diff options
1083 files changed, 65607 insertions, 73991 deletions
diff --git a/.clang-tidy b/.clang-tidy index b7888a1fcf..28115ae0b1 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -35,6 +35,7 @@ Checks: > -modernize-macro-to-enum, -readability-avoid-nested-conditional-operator, -readability-else-after-return, + -readability-enum-initial-value, -readability-function-size, -readability-isolate-declaration, @@ -56,6 +57,7 @@ Checks: > -readability-function-cognitive-complexity, -readability-identifier-length, -readability-magic-numbers, + -readability-math-missing-parentheses, -readability-redundant-declaration, Conflicts with our header generation scripts, -readability-suspicious-call-argument, @@ -65,6 +67,7 @@ Checks: > -cert-dcl51-cpp, -cert-exp42-c, -cert-flp37-c, + -cert-int09-c, -cert-msc24-c, -cert-msc33-c, -cppcoreguidelines-avoid-magic-numbers, diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 578a776b32..ce0dbd40de 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,5 +1,5 @@ name: Bug Report -description: Report a problem in Neovim +description: Report a problem in Nvim labels: [bug] body: @@ -43,7 +43,7 @@ body: - type: input attributes: - label: "Neovim version (nvim -v)" + label: "Nvim version (nvim -v)" placeholder: "0.6.0 commit db1b0ee3b30f" validations: required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index f25732f90d..a7d569514b 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: false contact_links: - name: Question - url: https://vi.stackexchange.com/ - about: Ask questions about configuration and usage of Neovim + url: https://github.com/neovim/neovim/discussions + about: Ask about configuration and usage of Nvim diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 711d70c589..49bd8158bf 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,5 +1,5 @@ name: Feature request -description: Request an enhancement for Neovim +description: Request an enhancement for Nvim labels: [enhancement] body: diff --git a/.github/ISSUE_TEMPLATE/lsp_bug_report.yml b/.github/ISSUE_TEMPLATE/lsp_bug_report.yml index 0e2111923d..277fabca5e 100644 --- a/.github/ISSUE_TEMPLATE/lsp_bug_report.yml +++ b/.github/ISSUE_TEMPLATE/lsp_bug_report.yml @@ -1,5 +1,6 @@ name: Language server (LSP) client bug -description: Report an issue with Neovim LSP +description: Report an issue with Nvim LSP +title: "LSP: " labels: [bug, lsp] body: @@ -59,7 +60,7 @@ body: - type: input attributes: - label: "Neovim version (nvim -v)" + label: "Nvim version (nvim -v)" placeholder: "0.6.0 commit db1b0ee3b30f" validations: required: true diff --git a/.github/scripts/install_deps.sh b/.github/scripts/install_deps.sh index 66f418eb10..b7d723e690 100755 --- a/.github/scripts/install_deps.sh +++ b/.github/scripts/install_deps.sh @@ -16,7 +16,7 @@ if [[ $os == Linux ]]; then if [[ $CC == clang ]]; then DEFAULT_CLANG_VERSION=$(echo | clang -dM -E - | grep __clang_major | awk '{print $3}') - CLANG_VERSION=18 + CLANG_VERSION=20 if ((DEFAULT_CLANG_VERSION >= CLANG_VERSION)); then echo "Default clang version is $DEFAULT_CLANG_VERSION, which equal or larger than wanted version $CLANG_VERSION. Aborting!" exit 1 @@ -30,10 +30,10 @@ if [[ $os == Linux ]]; then fi if [[ -n $TEST ]]; then - sudo apt-get install -y locales-all cpanminus attr libattr1-dev gdb fswatch + sudo apt-get install -y locales-all cpanminus attr libattr1-dev gdb inotify-tools # Use default CC to avoid compilation problems when installing Python modules - CC=cc python3 -m pip -q install --user --upgrade pynvim + CC=cc python3 -m pip -q install --user --upgrade --break-system-packages pynvim fi elif [[ $os == Darwin ]]; then brew update --quiet diff --git a/.github/scripts/labeler_configuration.yml b/.github/scripts/labeler_configuration.yml index ea670d1dd0..cf3b8f802b 100644 --- a/.github/scripts/labeler_configuration.yml +++ b/.github/scripts/labeler_configuration.yml @@ -2,6 +2,10 @@ build: - changed-files: - any-glob-to-any-file: [ CMakeLists.txt, "**/CMakeLists.txt", "**/Makefile", "**/*.cmake", cmake.deps/**/* ] +checkhealth: + - changed-files: + - any-glob-to-any-file: [ "**/health.lua" ] + ci: - changed-files: - any-glob-to-any-file: [ .github/actions/**, .github/workflows/**, .github/scripts/** ] @@ -14,6 +18,14 @@ column: - changed-files: - any-glob-to-any-file: [ src/nvim/sign* ] +comment: + - changed-files: + - any-glob-to-any-file: [ runtime/lua/vim/_comment.lua ] + +defaults: + - changed-files: + - any-glob-to-any-file: [ runtime/lua/vim/_defaults.lua ] + diagnostic: - changed-files: - any-glob-to-any-file: [ runtime/lua/vim/diagnostic.lua ] @@ -34,6 +46,10 @@ filetype: - changed-files: - any-glob-to-any-file: [ runtime/lua/vim/filetype.lua, runtime/lua/vim/filetype/detect.lua ] +filesystem: + - changed-files: + - any-glob-to-any-file: [ runtime/lua/vim/fs.lua ] + folds: - changed-files: - any-glob-to-any-file: [ src/nvim/fold* ] @@ -46,6 +62,10 @@ mouse: - changed-files: - any-glob-to-any-file: [ src/nvim/mouse* ] +netrw: + - changed-files: + - any-glob-to-any-file: [ runtime/autoload/netrw.vim, runtime/plugin/netrwPlugin.vim ] + snippet: - changed-files: - any-glob-to-any-file: [ runtime/lua/vim/snippet.lua ] diff --git a/.github/scripts/reviewers_add.js b/.github/scripts/reviewers_add.js index a7e0d2e47b..50195497af 100644 --- a/.github/scripts/reviewers_add.js +++ b/.github/scripts/reviewers_add.js @@ -23,6 +23,10 @@ module.exports = async ({ github, context }) => { reviewers.add("lewis6991"); } + if (labels.includes("comment")) { + reviewers.add("echasnovski"); + } + if (labels.includes("defaults")) { reviewers.add("gpanders"); } @@ -43,7 +47,7 @@ module.exports = async ({ github, context }) => { reviewers.add("gpanders"); } - if (labels.includes("extmarks")) { + if (labels.includes("marks")) { reviewers.add("bfredl"); } @@ -52,11 +56,19 @@ module.exports = async ({ github, context }) => { reviewers.add("gpanders"); } + if (labels.includes("inccommand")) { + reviewers.add("famiu"); + } + if (labels.includes("lsp")) { reviewers.add("MariaSolOs"); reviewers.add("mfussenegger"); } + if (labels.includes("netrw")) { + reviewers.add("justinmk"); + } + if (labels.includes("options")) { reviewers.add("famiu"); } diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 9fbe837106..25a52c4757 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -12,25 +12,35 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + + - uses: actions/create-github-app-token@v1 + id: app-token + with: + app-id: ${{ vars.BACKPORT_APP }} + private-key: ${{ secrets.BACKPORT_KEY }} + - name: Create backport PR id: backport - uses: korthout/backport-action@v2 + uses: korthout/backport-action@v3 with: pull_title: "${pull_title}" label_pattern: "^ci:backport ([^ ]+)$" - # https://github.com/korthout/backport-action/pull/399 - experimental: > - { - "detect_merge_method": true - } + github_token: ${{ steps.app-token.outputs.token }} - - if: ${{steps.backport.outputs.was_successful == 'true'}} + - name: Create failed backport label + if: ${{ steps.backport.outputs.was_successful == 'false' }} uses: actions/github-script@v7 with: script: | github.rest.issues.addLabels({ - issue_number: ${{steps.backport.outputs.created_pull_numbers}}, + issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, - labels: ['target:release'] + labels: ['needs:backport'] }) + + - name: Enable automerge + if: ${{ steps.backport.outputs.was_successful == 'true' }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh pr merge --rebase --auto ${{ steps.backport.outputs.created_pull_numbers }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a2316f3f0f..ab313729b9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,13 +21,28 @@ env: INSTALL_PREFIX: ${{ github.workspace }}/nvim-install jobs: + wasmtime: + strategy: + fail-fast: false + matrix: + test: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.test }} + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/setup + - run: | + cmake -S cmake.deps --preset ci -D ENABLE_WASMTIME=ON + cmake --build .deps + cmake --preset ci -D ENABLE_WASMTIME=ON + cmake --build build + old-cmake: name: Test oldest supported cmake runs-on: ubuntu-latest timeout-minutes: 15 env: - CMAKE_URL: 'https://cmake.org/files/v3.13/cmake-3.13.0-Linux-x86_64.sh' - CMAKE_VERSION: '3.13.0' + CMAKE_URL: 'https://cmake.org/files/v3.16/cmake-3.16.0-Linux-x86_64.sh' + CMAKE_VERSION: '3.16.0' steps: - uses: actions/checkout@v4 - uses: ./.github/actions/setup diff --git a/.github/workflows/build_dummy.yml b/.github/workflows/build_dummy.yml new file mode 100644 index 0000000000..b499ba7fa2 --- /dev/null +++ b/.github/workflows/build_dummy.yml @@ -0,0 +1,33 @@ +name: build_dummy +on: + pull_request: + branches: + - 'master' + - 'release-[0-9]+.[0-9]+' + # This needs to be an exact complement of `paths` in the build.yml workflow. + # This is required to bypass required checks since a required job is always + # needed to run. + paths-ignore: + - '**.cmake' + - '**/CMakeLists.txt' + - '**/CMakePresets.json' + - 'cmake.*/**' + - '.github/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + old-cmake: + name: Test oldest supported cmake + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - run: echo "success" + + use-existing-src: + name: Test USE_EXISTING_SRC_DIR=ON builds with no network access + runs-on: ubuntu-latest + steps: + - run: echo "success" diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index c91f2945fb..f132404382 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -2,13 +2,6 @@ name: docs on: pull_request: types: [opened, synchronize, reopened, ready_for_review] - paths: - - 'src/nvim/api/*.[ch]' - - 'src/nvim/eval.lua' - - 'runtime/lua/**.lua' - - 'runtime/doc/**' - - 'scripts/gen_vimdoc.py' - - 'scripts/gen_help_html.lua' jobs: docs: runs-on: ubuntu-latest diff --git a/.github/workflows/labeler_pr.yml b/.github/workflows/labeler_pr.yml index 8fd93bfb6d..5d402c3c03 100644 --- a/.github/workflows/labeler_pr.yml +++ b/.github/workflows/labeler_pr.yml @@ -33,8 +33,25 @@ jobs: - name: "Extract if the PR is a breaking change and add it as label" run: gh pr edit "$PR_NUMBER" --add-label "$(echo "$PR_TITLE" | sed -E 's|[[:alpha:]]+(\(.*\))?!:.*|breaking-change|')" || true - request-reviewer: + target-release: needs: ["changed-files", "type-scope"] + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - if: startsWith(github.base_ref, 'release') + uses: actions/github-script@v7 + with: + script: | + github.rest.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: ['target:release'] + }) + + request-reviewer: + needs: ["changed-files", "type-scope", "target-release"] permissions: pull-requests: write uses: ./.github/workflows/reviewers_add.yml diff --git a/.github/workflows/lintcommit.yml b/.github/workflows/lintcommit.yml index 3d140532cd..49dc7f3e66 100644 --- a/.github/workflows/lintcommit.yml +++ b/.github/workflows/lintcommit.yml @@ -1,4 +1,4 @@ -name: "lintcommit" +name: lintcommit on: pull_request: types: [opened, synchronize, reopened, ready_for_review] diff --git a/.github/workflows/lintcommit_dummy.yml b/.github/workflows/lintcommit_dummy.yml new file mode 100644 index 0000000000..e4a0c4af2d --- /dev/null +++ b/.github/workflows/lintcommit_dummy.yml @@ -0,0 +1,16 @@ +# Dummy workflow of lintcommit.yml. lintcommit is a required check, but it's +# only designed to work on master. Since required checks are always required to +# run, we can essentially "skip" the lintcommit on release branches with this +# dummy check that automatically passes. +name: lintcommit_dummy +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + branches: + - 'release-[0-9]+.[0-9]+' +jobs: + lint-commits: + runs-on: ubuntu-latest + if: github.event.pull_request.draft == false + steps: + - run: echo "success" diff --git a/.github/workflows/notes.md b/.github/workflows/notes.md index f67a098687..25f4a5fb32 100644 --- a/.github/workflows/notes.md +++ b/.github/workflows/notes.md @@ -18,6 +18,8 @@ ${NVIM_VERSION} 2. Run the MSI 3. Run `nvim.exe` on your CLI of choice +Note: On Windows "Server" you may need to [install vcruntime140.dll](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170). + ### macOS (x86_64) 1. Download **nvim-macos-x86_64.tar.gz** @@ -34,11 +36,10 @@ ${NVIM_VERSION} ### Linux (x64) -Minimum glibc version to run these releases is 2.31. People requiring releases -that work on older glibc versions can find them at -https://github.com/neovim/neovim-releases. +glibc 2.31 or newer is required. Or you may try the (unsupported) [builds for older glibc](https://github.com/neovim/neovim-releases). #### AppImage + 1. Download **nvim.appimage** 2. Run `chmod u+x nvim.appimage && ./nvim.appimage` - If your system does not have FUSE you can [extract the appimage](https://github.com/AppImage/AppImageKit/wiki/FUSE#type-2-appimage): diff --git a/.github/workflows/optional.yml b/.github/workflows/optional.yml index 742d51377f..540daccc56 100644 --- a/.github/workflows/optional.yml +++ b/.github/workflows/optional.yml @@ -11,7 +11,7 @@ concurrency: env: INSTALL_PREFIX: ${{ github.workspace }}/nvim-install # Double test timeout since it's running via qemu - TEST_TIMEOUT: 2400 + TEST_TIMEOUT: 3600 # TEST_FILE: test/functional/shada # TEST_FILTER: foo @@ -23,7 +23,7 @@ jobs: matrix: test: [functionaltest, oldtest] runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 90 steps: - run: docker run --rm --privileged multiarch/qemu-user-static:register --reset - uses: docker://multiarch/ubuntu-core:s390x-focal @@ -34,7 +34,7 @@ jobs: bash -c " apt-get -y update && - DEBIAN_FRONTEND=noninteractive apt-get -y install build-essential cmake curl gettext ninja-build locales-all cpanminus git attr libattr1-dev && + time DEBIAN_FRONTEND=noninteractive apt-get -y install build-essential cmake curl gettext ninja-build locales-all cpanminus git attr libattr1-dev xdg-utils && useradd --create-home qemuci && chown -R qemuci. . && runuser -u qemuci -- git clone --depth=1 https://github.com/neovim/neovim.git && diff --git a/.github/workflows/reviewers_add.yml b/.github/workflows/reviewers_add.yml index b116bca29b..90b473c754 100644 --- a/.github/workflows/reviewers_add.yml +++ b/.github/workflows/reviewers_add.yml @@ -5,7 +5,7 @@ on: workflow_call: jobs: request-reviewer: - if: github.event.pull_request.state == 'open' && github.event.pull_request.draft == false + if: github.event.pull_request.state == 'open' && github.event.pull_request.draft == false && !endsWith(github.actor, '[bot]') runs-on: ubuntu-latest permissions: pull-requests: write diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d0ee18ab73..522692b30a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,8 +8,6 @@ on: branches: - 'master' - 'release-[0-9]+.[0-9]+' - paths-ignore: - - 'contrib/**' workflow_dispatch: concurrency: @@ -30,7 +28,7 @@ env: jobs: lint: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 10 env: CC: clang @@ -80,7 +78,7 @@ jobs: run: cmake --build build --target lintc-uncrustify clang-analyzer: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 20 env: CC: clang @@ -95,18 +93,23 @@ jobs: - run: cmake --build build --target clang-analyzer posix: - name: ${{ matrix.build.runner }} ${{ matrix.build.flavor }} ${{ matrix.build.cc }} ${{ matrix.test }} + name: ${{ matrix.build.os }} ${{ matrix.build.flavor }} ${{ matrix.build.cc }} ${{ matrix.test }} strategy: fail-fast: false matrix: + # The `os` field is not needed to differentiate between the different + # matrix builds. It is needed to not change the required checks (which + # uses jobs names) each time we bump the runner version. It may be + # possible to remove if we e.g. start using `-latest` runner versions + # or if github introduces a wildcard for required checks in the future. build: [ - { runner: ubuntu-22.04, flavor: asan, cc: clang, flags: -D ENABLE_ASAN_UBSAN=ON }, - { runner: ubuntu-22.04, flavor: tsan, cc: clang, flags: -D ENABLE_TSAN=ON }, - { runner: ubuntu-22.04, cc: gcc }, - { runner: macos-12, cc: clang, flags: -D CMAKE_FIND_FRAMEWORK=NEVER, deps_flags: -D CMAKE_FIND_FRAMEWORK=NEVER }, - { runner: macos-14, cc: clang, flags: -D CMAKE_FIND_FRAMEWORK=NEVER, deps_flags: -D CMAKE_FIND_FRAMEWORK=NEVER }, - { runner: ubuntu-22.04, flavor: puc-lua, cc: gcc, deps_flags: -D USE_BUNDLED_LUAJIT=OFF -D USE_BUNDLED_LUA=ON, flags: -D PREFER_LUA=ON }, + { runner: ubuntu-24.04, os: ubuntu, flavor: asan, cc: clang, flags: -D ENABLE_ASAN_UBSAN=ON }, + { runner: ubuntu-24.04, os: ubuntu, flavor: tsan, cc: clang, flags: -D ENABLE_TSAN=ON }, + { runner: ubuntu-24.04, os: ubuntu, cc: gcc }, + { runner: macos-12, os: macos, flavor: 12, cc: clang, flags: -D CMAKE_FIND_FRAMEWORK=NEVER, deps_flags: -D CMAKE_FIND_FRAMEWORK=NEVER }, + { runner: macos-15, os: macos, cc: clang, flags: -D CMAKE_FIND_FRAMEWORK=NEVER, deps_flags: -D CMAKE_FIND_FRAMEWORK=NEVER }, + { runner: ubuntu-24.04, os: ubuntu, flavor: puc-lua, cc: gcc, deps_flags: -D USE_BUNDLED_LUAJIT=OFF -D USE_BUNDLED_LUA=ON, flags: -D PREFER_LUA=ON }, ] test: [unittest, functionaltest, oldtest] exclude: @@ -199,7 +202,7 @@ jobs: # single-config generators so it's nice to have a small sanity check for # multi-config. build-types: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 10 env: CC: gcc @@ -225,7 +228,7 @@ jobs: run: cmake --build build --config MinSizeRel with-external-deps: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 10 env: CC: gcc @@ -238,8 +241,6 @@ jobs: sudo add-apt-repository ppa:neovim-ppa/stable sudo apt-get install -y \ libluajit-5.1-dev \ - libmsgpack-dev \ - libtermkey-dev \ libunibilium-dev \ libuv1-dev \ lua-filesystem \ @@ -247,7 +248,6 @@ jobs: luajit \ lua-luv-dev # libtree-sitter-dev \ - # libvterm-dev # Remove comments from packages once we start using these external # dependencies. diff --git a/.github/workflows/test_windows.yml b/.github/workflows/test_windows.yml index d92993a08c..db7ad93f55 100644 --- a/.github/workflows/test_windows.yml +++ b/.github/workflows/test_windows.yml @@ -60,6 +60,7 @@ jobs: uses: msys2/setup-msys2@v2 with: update: true + install: unzip pacboy: >- make:p gcc:p diffutils:p release: false diff --git a/.github/workflows/vim_patches.yml b/.github/workflows/vim_patches.yml index f4251336c7..b0be01089f 100644 --- a/.github/workflows/vim_patches.yml +++ b/.github/workflows/vim_patches.yml @@ -50,6 +50,6 @@ jobs: if: ${{ steps.update-version.outputs.NEW_PATCHES != 0 }} run: | git add -u - git commit -m 'docs: update version.c [skip ci]' + git commit -m 'docs: update version.c' git push --force https://${GITHUB_ACTOR}:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY} ${VERSION_BRANCH} gh pr create --draft --fill --label vim-patch --base ${GITHUB_REF#refs/heads/} --head ${VERSION_BRANCH} || true diff --git a/.luacheckrc b/.luacheckrc index d54c61e9e7..4d4d656b4b 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -42,6 +42,7 @@ globals = { } exclude_files = { + 'test/_meta.lua', 'test/functional/fixtures/lua/syntax_error.lua', 'runtime/lua/vim/treesitter/_meta.lua', 'runtime/lua/vim/_meta/vimfn.lua', @@ -18,6 +18,7 @@ Eisuke Kawashima <e-kwsm@users.noreply.github.com> E Kawashima ElPiloto <luis.r.piloto@gmail.com> Luis Piloto Eliseo MartiÌnez <eliseomarmol@gmail.com> Eliseo MartÃnez Fabian Viöl <f.vioel@googlemail.com> Fabian +Famiu Haque <famiuhaque@proton.me> <famiuhaque@protonmail.com> Florian Walch <florian@fwalch.com> <fwalch@users.noreply.github.com> Gabriel Cruz <gabs.oficial98@gmail.com> <LTKills@users.noreply.github.com> Gaelan Steele <gbs@canishe.com> Gaelan @@ -12,7 +12,6 @@ - To build on Windows, see the [Building on Windows](#building-on-windows) section. _MSVC (Visual Studio) is recommended._ 4. `sudo make install` - Default install location is `/usr/local` - - On Debian/Ubuntu, instead of installing files directly with `sudo make install`, you can run `cd build && cpack -G DEB && sudo dpkg -i nvim-linux64.deb` to build DEB-package and install it. This should help ensuring the clean removal of installed files. **Notes**: - From the repository's root directory, running `make` will download and build all the needed dependencies and put the `nvim` executable in `build/bin`. @@ -84,7 +83,7 @@ make deps - Right-click _CMakeLists.txt → Delete Cache_. - Right-click _CMakeLists.txt → Generate Cache_. - If you see an "access violation" from `ntdll`, you can ignore it and continue. -4. If you set an error like `msgpackc.dll not found`, try the `nvim.exe (Install)` target. Then switch back to `nvim.exe (bin\nvim.exe)`. +4. If you see an error like `uv.dll not found`, try the `nvim.exe (Install)` target. Then switch back to `nvim.exe (bin\nvim.exe)`. ### Windows / MSVC PowerShell @@ -240,7 +239,7 @@ cmake --build build ### How to build without "bundled" dependencies 1. Manually install the dependencies: - - libuv libluv libvterm luajit lua-lpeg lua-mpack msgpack-c tree-sitter tree-sitter-bash tree-sitter-c tree-sitter-lua tree-sitter-markdown tree-sitter-python tree-sitter-query tree-sitter-vim tree-sitter-vimdoc unibilium + - libuv libluv libutf8proc luajit lua-lpeg tree-sitter tree-sitter-c tree-sitter-lua tree-sitter-markdown tree-sitter-query tree-sitter-vim tree-sitter-vimdoc unibilium 2. Run CMake: ```sh cmake -B build -G Ninja -D CMAKE_BUILD_TYPE=RelWithDebInfo @@ -248,7 +247,7 @@ cmake --build build ``` If all the dependencies are not available in the package, you can use only some of the bundled dependencies as follows (example of using `ninja`): ```sh - cmake -S cmake.deps -B .deps -G Ninja -D CMAKE_BUILD_TYPE=RelWithDebInfo -DUSE_BUNDLED=OFF -DUSE_BUNDLED_LIBVTERM=ON -DUSE_BUNDLED_TS=ON + cmake -S cmake.deps -B .deps -G Ninja -D CMAKE_BUILD_TYPE=RelWithDebInfo -DUSE_BUNDLED=OFF -DUSE_BUNDLED_TS=ON cmake --build .deps cmake -B build -G Ninja -D CMAKE_BUILD_TYPE=RelWithDebInfo cmake --build build @@ -260,8 +259,8 @@ cmake --build build #### Debian 10 (Buster) example: ```sh -sudo apt install luajit libluajit-5.1-dev lua-mpack lua-lpeg libunibilium-dev libmsgpack-dev -cmake -S cmake.deps -B .deps -G Ninja -D CMAKE_BUILD_TYPE=RelWithDebInfo -DUSE_BUNDLED=OFF -DUSE_BUNDLED_LIBUV=ON -DUSE_BUNDLED_LUV=ON -DUSE_BUNDLED_LIBVTERM=ON -DUSE_BUNDLED_TS=ON +sudo apt install luajit libluajit-5.1-dev lua-lpeg libunibilium-dev +cmake -S cmake.deps -B .deps -G Ninja -D CMAKE_BUILD_TYPE=RelWithDebInfo -DUSE_BUNDLED=OFF -DUSE_BUNDLED_LIBUV=ON -DUSE_BUNDLED_LUV=ON -DUSE_BUNDLED_TS=ON -DUSE_BUNDLED_UTF8PROC=ON cmake --build .deps cmake -B build -G Ninja -D CMAKE_BUILD_TYPE=RelWithDebInfo cmake --build build @@ -275,7 +274,7 @@ cmake --build build ``` - Example of using a package with some dependencies: ``` - make BUNDLED_CMAKE_FLAG="-DUSE_BUNDLED=OFF -DUSE_BUNDLED_LUV=ON -DUSE_BUNDLED_TS=ON -DUSE_BUNDLED_LIBVTERM=ON -DUSE_BUNDLED_LIBUV=ON" + make BUNDLED_CMAKE_FLAG="-DUSE_BUNDLED=OFF -DUSE_BUNDLED_LUV=ON -DUSE_BUNDLED_TS=ON -DUSE_BUNDLED_LIBUV=ON" ``` ## Build prerequisites @@ -283,8 +282,9 @@ cmake --build build General requirements (see [#1469](https://github.com/neovim/neovim/issues/1469#issuecomment-63058312)): - Clang or GCC version 4.9+ -- CMake version 3.13+, built with TLS/SSL support - - Optional: Get the latest CMake from an [installer](https://github.com/Kitware/CMake/releases) or the [Python package](https://pypi.org/project/cmake/) (`pip install cmake`) +- CMake version 3.16+, built with TLS/SSL support + - Optional: Get the latest CMake from https://cmake.org/download/ + - Provides a shell script which works on most Linux systems. After running it, ensure the resulting `cmake` binary is in your $PATH so the the Nvim build will find it. Platform-specific requirements are listed below. @@ -365,13 +365,16 @@ and replacing `neovim-unwrapped` with `neovim-dev`: nix-shell '<nixpkgs>' -A neovim-dev ``` -Neovim contains a Nix flake in the `contrib` folder, with 3 packages: +A flake for Neovim is hosted at [nix-community/neovim-nightly-overlay](https://github.com/nix-community/neovim-nightly-overlay/), with 3 packages: - `neovim` to run the nightly - `neovim-debug` to run the package with debug symbols - `neovim-developer` to get all the tools to develop on `neovim` -Thus you can run Neovim nightly with `nix run github:neovim/neovim?dir=contrib`. -Similarly to develop on Neovim: `nix develop github:neovim/neovim?dir=contrib#neovim-developer`. +Thus you can run Neovim nightly with `nix run github:nix-community/neovim-nightly-overlay`. +Similarly to develop on Neovim: `nix run github:nix-community/neovim-nightly-overlay#neovim-developer`. + +To use a specific version of Neovim, you can pass `--override-input neovim-src .` to use your current directory, +or a specific SHA1 like `--override-input neovim-src github:neovim/neovim/89dc8f8f4e754e70cbe1624f030fb61bded41bc2`. ### FreeBSD diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c0f8483ea..0100146274 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,14 +4,10 @@ # - pitfalls: https://izzys.casa/2019/02/everything-you-never-wanted-to-know-about-cmake/ # - troubleshooting: # - variable_watch https://cmake.org/cmake/help/latest/command/variable_watch.html +# - verbose output: cmake --build build --verbose # Version should match the tested CMAKE_URL in .github/workflows/build.yml. -cmake_minimum_required(VERSION 3.13) - -# Can be removed once minimum version is at least 3.15 -if(POLICY CMP0092) - cmake_policy(SET CMP0092 NEW) -endif() +cmake_minimum_required(VERSION 3.16) project(nvim C) @@ -40,6 +36,12 @@ include(PreventInTreeBuilds) include(Util) #------------------------------------------------------------------------------- +# User settings +#------------------------------------------------------------------------------- + +set(DEPS_IGNORE_SHA FALSE) + +#------------------------------------------------------------------------------- # Variables #------------------------------------------------------------------------------- set(FUNCS_DATA ${PROJECT_BINARY_DIR}/funcs_data.mpack) @@ -47,9 +49,6 @@ set(TOUCHES_DIR ${PROJECT_BINARY_DIR}/touches) file(GLOB DOCFILES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/runtime/doc/*.txt) -set_directory_properties(PROPERTIES - EP_PREFIX "${DEPS_BUILD_DIR}") - if(NOT CI_BUILD) set(CMAKE_INSTALL_MESSAGE NEVER) endif() @@ -127,6 +126,7 @@ else() option(ENABLE_LTO "enable link time optimization" ON) endif() option(ENABLE_LIBINTL "enable libintl" ON) +option(ENABLE_WASMTIME "enable wasmtime" OFF) message(STATUS "CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}") @@ -146,9 +146,9 @@ set(NVIM_VERSION_PATCH 0) set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers # API level -set(NVIM_API_LEVEL 12) # Bump this after any API change. +set(NVIM_API_LEVEL 13) # Bump this after any API/stdlib change. set(NVIM_API_LEVEL_COMPAT 0) # Adjust this after a _breaking_ API change. -set(NVIM_API_PRERELEASE false) +set(NVIM_API_PRERELEASE true) # Build-type: RelWithDebInfo # /Og means something different in MSVC @@ -241,7 +241,7 @@ add_glob_target( GLOB_DIRS runtime scripts src test GLOB_PAT *.lua TOUCH_STRATEGY PER_DIR) -add_dependencies(lintlua-luacheck lua-dev-deps) +add_dependencies(lintlua-luacheck lua_dev_deps) add_glob_target( TARGET lintlua-stylua @@ -300,26 +300,25 @@ if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) add_subdirectory(cmake.packaging) endif() +get_externalproject_options(uncrustify ${DEPS_IGNORE_SHA}) ExternalProject_Add(uncrustify - URL https://github.com/uncrustify/uncrustify/archive/uncrustify-0.79.0.tar.gz - URL_HASH SHA256=e7afaeabf636b7f0ce4e3e9747b95f7bd939613a8db49579755dddf44fedca5f DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/uncrustify CMAKE_ARGS ${DEPS_CMAKE_ARGS} + -D CMAKE_RUNTIME_OUTPUT_DIRECTORY=${DEPS_BIN_DIR} EXCLUDE_FROM_ALL TRUE - DOWNLOAD_NO_PROGRESS TRUE) + ${EXTERNALPROJECT_OPTIONS}) option(USE_BUNDLED_BUSTED "Use bundled busted" ON) if(USE_BUNDLED_BUSTED) - ExternalProject_Add(lua-dev-deps - URL https://github.com/neovim/deps/raw/5a1f71cceb24990a0b15fd9a472a5f549f019248/opt/lua-dev-deps.tar.gz - URL_HASH SHA256=27db2495f5eddc7fc191701ec9b291486853530c6125609d3197d03481e8d5a2 - DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/lua-dev-deps + get_externalproject_options(lua_dev_deps ${DEPS_IGNORE_SHA}) + ExternalProject_Add(lua_dev_deps + DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/lua_dev_deps SOURCE_DIR ${DEPS_SHARE_DIR} CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" EXCLUDE_FROM_ALL TRUE - DOWNLOAD_NO_PROGRESS TRUE) + ${EXTERNALPROJECT_OPTIONS}) else() - add_custom_target(lua-dev-deps) + add_custom_target(lua_dev_deps) endif() diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d080f3079e..f40d4c54b7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -42,10 +42,10 @@ Developer guidelines make distclean make # Nvim build system uses ninja automatically, if available. ``` -- Install `ccache` for faster rebuilds of Nvim. Nvim will use it automatically - if it's found. To disable caching use: +- Install `ccache` or `sccache` for faster rebuilds of Nvim. Nvim will use one + of these automatically if it's found. To disable caching use: ```bash - CCACHE_DISABLE=true make + cmake -B build -D CACHE_PRG=OFF ``` Pull requests (PRs) diff --git a/INSTALL.md b/INSTALL.md index 056a5acb04..509213fffc 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -55,12 +55,12 @@ Several Neovim GUIs are available from scoop (extras): [scoop.sh/#/apps?q=neovim 1. Choose a package (**nvim-winXX.zip**) from the [releases page](https://github.com/neovim/neovim/releases). 2. Unzip the package. Any location is fine, administrator privileges are _not_ required. - `$VIMRUNTIME` will be set to that location automatically. -3. Double-click `nvim-qt.exe`. +3. Run `nvim.exe` from a terminal. **Optional** steps: - Add the `bin` folder (e.g. `C:\Program Files\nvim\bin`) to your PATH. - - This makes it easy to run `nvim` and `nvim-qt` from anywhere. + - This makes it easy to run `nvim` from anywhere. - If `:set spell` does not work, create the `C:/Users/foo/AppData/Local/nvim/site/spell` folder. You can then copy your spell files over (for English, located [here](https://github.com/vim/vim/blob/master/runtime/spell/en.utf-8.spl) and @@ -112,7 +112,7 @@ sudo rm -rf /opt/nvim sudo tar -C /opt -xzf nvim-linux64.tar.gz ``` -After this step add this to `~/.bashrc`: +Then add this to your shell config (`~/.bashrc`, `~/.zshrc`, ...): export PATH="$PATH:/opt/nvim-linux64/bin" @@ -129,7 +129,7 @@ To expose nvim globally: mkdir -p /opt/nvim mv nvim.appimage /opt/nvim/nvim -And the following line to `~/.bashrc`: +And the following line to your shell config (`~/.bashrc`, `~/.zshrc`, ...): export PATH="$PATH:/opt/nvim/" @@ -204,7 +204,7 @@ You can also get nightly builds of git master from the [Copr automated build sys dnf copr enable agriffis/neovim-nightly dnf install -y neovim python3-neovim -See the [blog post](https://arongriffis.com/2019/03/02/neovim-nightly-builds) for information on how these are built. +See the [blog post](https://arongriffis.com/2019-03-02-neovim-nightly-builds) for information on how these are built. ### Flatpak diff --git a/MAINTAIN.md b/MAINTAIN.md index f7f0c5769c..5d046926c2 100644 --- a/MAINTAIN.md +++ b/MAINTAIN.md @@ -129,8 +129,6 @@ Some can be auto-bumped by `scripts/bump_deps.lua`. * [gettext](https://ftp.gnu.org/pub/gnu/gettext/) * [libiconv](https://ftp.gnu.org/pub/gnu/libiconv) * [libuv](https://github.com/libuv/libuv) -* [libvterm](https://www.leonerd.org.uk/code/libvterm/) - * Downloading from the original source is unreliable, so we use our [mirror](https://github.com/neovim/libvterm) instead. * [lua-compat](https://github.com/keplerproject/lua-compat-5.3) * [tree-sitter](https://github.com/tree-sitter/tree-sitter) * [unibilium](https://github.com/neovim/unibilium) @@ -146,6 +144,8 @@ These dependencies are "vendored" (inlined), we must update the sources manually * `src/xdiff/`: [xdiff](https://github.com/git/git/tree/master/xdiff) * `src/cjson/`: [lua-cjson](https://github.com/openresty/lua-cjson) * `src/klib/`: [Klib](https://github.com/attractivechaos/klib) +* `src/vterm/`: [libvterm](https://www.leonerd.org.uk/code/libvterm/), + [mirror](https://github.com/neovim/libvterm) * `runtime/lua/vim/inspect.lua`: [inspect.lua](https://github.com/kikito/inspect.lua) * `src/nvim/tui/terminfo_defs.h`: terminfo definitions * Run `scripts/update_terminfo.sh` to update these definitions. @@ -160,7 +160,6 @@ These dependencies are "vendored" (inlined), we must update the sources manually * Needs to be updated when LPeg is updated. * `src/bit.c`: only for PUC lua: port of `require'bit'` from luajit https://bitop.luajit.org/ * `runtime/lua/coxpcall.lua`: coxpcall (only needed for PUC lua, builtin to luajit) -* `src/termkey`: [libtermkey](https://github.com/neovim/libtermkey) Other dependencies -------------------------- @@ -170,6 +169,9 @@ Other dependencies * https://github.com/nvim-winget * Org secrets/tokens: * `CODECOV_TOKEN` + * `BACKPORT_KEY` +* Org/repo variables: + * `BACKPORT_APP` * Domain names (held in https://namecheap.com): * neovim.org * neovim.io @@ -185,10 +187,10 @@ Refactoring Refactoring Vim structurally and aesthetically is an important goal of Neovim. But there are some modules that should not be changed significantly, because -they are maintained Vim, at present. Until someone takes "ownership" of these -modules, the cost of any significant changes (including style or structural -changes that re-arrange the code) to these modules outweighs the benefit. The -modules are: +they are maintained by Vim, at present. Until someone takes "ownership" of +these modules, the cost of any significant changes (including style or +structural changes that re-arrange the code) to these modules outweighs the +benefit. The modules are: - `regexp.c` - `indent_c.c` @@ -211,12 +213,12 @@ https://github.com/neovim/neovim-backup * For special-purpose jobs where the runner version doesn't really matter, prefer `-latest` tags so we don't need to manually bump the versions. An example of a special-purpose workflow is `labeler_pr.yml`. - * For our testing job `test.yml`, prefer to use the latest stable (i.e. - non-beta) version explicitly. Avoid using the `-latest` tags here as it - makes it difficult to determine from an unrelated PR if a failure is due - to the PR itself or due to GitHub bumping the `-latest` tag without our - knowledge. There's also a high risk that automatically bumping the CI - versions will fail due to manual work being required from experience. + * For our testing job `test.yml`, prefer to use the latest version + explicitly. Avoid using the `-latest` tags here as it makes it difficult + to determine from an unrelated PR if a failure is due to the PR itself or + due to GitHub bumping the `-latest` tag without our knowledge. There's + also a high risk that automatically bumping the CI versions will fail due + to manual work being required from experience. * For our release job, which is `release.yml`, prefer to use the oldest stable (i.e. non-deprecated) versions available. The reason is that we're trying to produce images that work in the broadest number of environments, @@ -1,3 +1,25 @@ +ifeq ($(OS),Windows_NT) + SHELL := powershell.exe + .SHELLFLAGS := -NoProfile -NoLogo + MKDIR := @$$null = new-item -itemtype directory -force + TOUCH := @$$null = new-item -force + RM := remove-item -force + CMAKE := cmake + CMAKE_GENERATOR := Ninja + define rmdir + if (Test-Path $1) { remove-item -recurse $1 } + endef +else + MKDIR := mkdir -p + TOUCH := touch + RM := rm -rf + CMAKE := $(shell (command -v cmake3 || command -v cmake || echo cmake)) + CMAKE_GENERATOR ?= "$(shell (command -v ninja > /dev/null 2>&1 && echo "Ninja") || echo "Unix Makefiles")" + define rmdir + rm -rf $1 + endef +endif + MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) MAKEFILE_DIR := $(dir $(MAKEFILE_PATH)) @@ -9,7 +31,6 @@ filter-true = $(strip $(filter-out 1 on ON true TRUE,$1)) all: nvim -CMAKE ?= $(shell (command -v cmake3 || echo cmake)) CMAKE_FLAGS := -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) # Extra CMake flags which extend the default set CMAKE_EXTRA_FLAGS ?= @@ -37,21 +58,11 @@ else checkprefix: ; endif -CMAKE_GENERATOR ?= $(shell (command -v ninja > /dev/null 2>&1 && echo "Ninja") || \ - echo "Unix Makefiles") -DEPS_BUILD_DIR ?= .deps +DEPS_BUILD_DIR ?= ".deps" ifneq (1,$(words [$(DEPS_BUILD_DIR)])) $(error DEPS_BUILD_DIR must not contain whitespace) endif -ifeq (,$(BUILD_TOOL)) - ifeq (Ninja,$(CMAKE_GENERATOR)) - BUILD_TOOL = ninja - else - BUILD_TOOL = $(MAKE) - endif -endif - DEPS_CMAKE_FLAGS ?= USE_BUNDLED ?= @@ -61,7 +72,7 @@ endif ifneq (,$(findstring functionaltest-lua,$(MAKECMDGOALS))) BUNDLED_LUA_CMAKE_FLAG := -DUSE_BUNDLED_LUA=ON - $(shell [ -x $(DEPS_BUILD_DIR)/usr/bin/lua ] || rm build/.ran-*) + $(shell [ -x $(DEPS_BUILD_DIR)/usr/bin/lua ] || $(RM) build/.ran-*) endif # For use where we want to make sure only a single job is run. This does issue @@ -69,34 +80,33 @@ endif SINGLE_MAKE = export MAKEFLAGS= ; $(MAKE) nvim: build/.ran-cmake deps - $(BUILD_TOOL) -C build + $(CMAKE) --build build libnvim: build/.ran-cmake deps - $(BUILD_TOOL) -C build libnvim + $(CMAKE) --build build --target libnvim cmake: - touch CMakeLists.txt + $(TOUCH) CMakeLists.txt $(MAKE) build/.ran-cmake build/.ran-cmake: | deps - $(CMAKE) -B build -G '$(CMAKE_GENERATOR)' $(CMAKE_FLAGS) $(CMAKE_EXTRA_FLAGS) $(MAKEFILE_DIR) - touch $@ + $(CMAKE) -B build -G $(CMAKE_GENERATOR) $(CMAKE_FLAGS) $(CMAKE_EXTRA_FLAGS) $(MAKEFILE_DIR) + $(TOUCH) $@ deps: | build/.ran-deps-cmake ifeq ($(call filter-true,$(USE_BUNDLED)),) - $(BUILD_TOOL) -C $(DEPS_BUILD_DIR) + $(CMAKE) --build $(DEPS_BUILD_DIR) endif ifeq ($(call filter-true,$(USE_BUNDLED)),) $(DEPS_BUILD_DIR): - mkdir -p "$@" + $(MKDIR) $@ build/.ran-deps-cmake:: $(DEPS_BUILD_DIR) - $(CMAKE) -S $(MAKEFILE_DIR)/cmake.deps -B $(DEPS_BUILD_DIR) -G '$(CMAKE_GENERATOR)' \ - $(BUNDLED_CMAKE_FLAG) $(BUNDLED_LUA_CMAKE_FLAG) $(DEPS_CMAKE_FLAGS) + $(CMAKE) -S $(MAKEFILE_DIR)/cmake.deps -B $(DEPS_BUILD_DIR) -G $(CMAKE_GENERATOR) $(BUNDLED_CMAKE_FLAG) $(BUNDLED_LUA_CMAKE_FLAG) $(DEPS_CMAKE_FLAGS) endif build/.ran-deps-cmake:: - mkdir -p build - touch $@ + $(MKDIR) build + $(TOUCH) "$@" # TODO: cmake 3.2+ add_custom_target() has a USES_TERMINAL flag. oldtest: | nvim @@ -113,7 +123,7 @@ test/old/testdir/%.vim: phony_force nvim $(SINGLE_MAKE) -C test/old/testdir NVIM_PRG=$(NVIM_PRG) SCRIPTS= $(MAKEOVERRIDES) $(patsubst test/old/testdir/%.vim,%,$@) functionaltest-lua: | nvim - $(BUILD_TOOL) -C build functionaltest + $(CMAKE) --build build --target functionaltest FORMAT=formatc formatlua format LINT=lintlua lintsh lintc clang-analyzer lintcommit lintdoc lint @@ -135,16 +145,19 @@ iwyu: build/.ran-cmake $(CMAKE) --build build clean: - test -d build && $(BUILD_TOOL) -C build clean || true +ifneq ($(wildcard build),) + $(CMAKE) --build build --target clean +endif $(MAKE) -C test/old/testdir clean $(MAKE) -C runtime/indent clean distclean: - rm -rf $(DEPS_BUILD_DIR) build + $(call rmdir, $(DEPS_BUILD_DIR)) + $(call rmdir, build) $(MAKE) clean install: checkprefix nvim - $(BUILD_TOOL) -C build install + $(CMAKE) --install build appimage: bash scripts/genappimage.sh @@ -155,14 +168,4 @@ appimage: appimage-%: bash scripts/genappimage.sh $* -# Generic pattern rules, allowing for `make build/bin/nvim` etc. -# Does not work with "Unix Makefiles". -ifeq ($(CMAKE_GENERATOR),Ninja) -build/%: phony_force - $(BUILD_TOOL) -C build $(patsubst build/%,%,$@) - -$(DEPS_BUILD_DIR)/%: phony_force - $(BUILD_TOOL) -C $(DEPS_BUILD_DIR) $(patsubst $(DEPS_BUILD_DIR)/%,%,$@) -endif - .PHONY: test clean distclean nvim libnvim cmake deps install appimage checkprefix benchmark $(FORMAT) $(LINT) $(TEST) @@ -27,7 +27,7 @@ Features - [API access](https://github.com/neovim/neovim/wiki/Related-projects#api-clients) from any language including C/C++, C#, Clojure, D, Elixir, Go, Haskell, Java/Kotlin, JavaScript/Node.js, Julia, Lisp, Lua, Perl, Python, Racket, Ruby, Rust -- Embedded, scriptable [terminal emulator](https://neovim.io/doc/user/nvim_terminal_emulator.html) +- Embedded, scriptable [terminal emulator](https://neovim.io/doc/user/terminal.html) - Asynchronous [job control](https://github.com/neovim/neovim/pull/2247) - [Shared data (shada)](https://github.com/neovim/neovim/pull/2506) among multiple editor instances - [XDG base directories](https://github.com/neovim/neovim/pull/3470) support diff --git a/cmake.config/CMakeLists.txt b/cmake.config/CMakeLists.txt index 3171f9e88c..aac8c4c27b 100644 --- a/cmake.config/CMakeLists.txt +++ b/cmake.config/CMakeLists.txt @@ -173,9 +173,7 @@ function(append_target_expression) ${ARGN}) set(TARGET_EXPRESSION "$<TARGET_PROPERTY:nvim_bin,${ARG_PROPERTY}>") - if(${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.15) - set(TARGET_EXPRESSION "$<REMOVE_DUPLICATES:${TARGET_EXPRESSION}>") - endif() + set(TARGET_EXPRESSION "$<REMOVE_DUPLICATES:${TARGET_EXPRESSION}>") set(TARGET_EXPRESSION "${ARG_PREFIX}$<JOIN:${TARGET_EXPRESSION}, ${ARG_PREFIX}>") set(VERSION_STRING "${VERSION_STRING} ${TARGET_EXPRESSION} " PARENT_SCOPE) diff --git a/cmake.deps/CMakeLists.txt b/cmake.deps/CMakeLists.txt index 4853a1ab14..394c50a3b5 100644 --- a/cmake.deps/CMakeLists.txt +++ b/cmake.deps/CMakeLists.txt @@ -1,5 +1,5 @@ # This is not meant to be included by the top-level. -cmake_minimum_required (VERSION 3.13) +cmake_minimum_required(VERSION 3.16) project(NVIM_DEPS C) if(POLICY CMP0135) @@ -27,16 +27,16 @@ set(DEPS_IGNORE_SHA FALSE) option(USE_BUNDLED "Use bundled dependencies." ON) option(USE_BUNDLED_LIBUV "Use the bundled libuv." ${USE_BUNDLED}) -option(USE_BUNDLED_LIBVTERM "Use the bundled libvterm." ${USE_BUNDLED}) option(USE_BUNDLED_LPEG "Use the bundled lpeg." ${USE_BUNDLED}) # PUC Lua is only used for tests, unless explicitly requested. option(USE_BUNDLED_LUA "Use the bundled version of lua." OFF) option(USE_BUNDLED_LUAJIT "Use the bundled version of luajit." ${USE_BUNDLED}) option(USE_BUNDLED_LUV "Use the bundled version of luv." ${USE_BUNDLED}) -option(USE_BUNDLED_MSGPACK "Use the bundled msgpack." ${USE_BUNDLED}) option(USE_BUNDLED_TS "Use the bundled treesitter runtime." ${USE_BUNDLED}) option(USE_BUNDLED_TS_PARSERS "Use the bundled treesitter parsers." ${USE_BUNDLED}) option(USE_BUNDLED_UNIBILIUM "Use the bundled unibilium." ${USE_BUNDLED}) +option(USE_BUNDLED_UTF8PROC "Use the bundled utf8proc library." ${USE_BUNDLED}) + if(USE_BUNDLED AND MSVC) option(USE_BUNDLED_GETTEXT "Use the bundled version of gettext." ON) option(USE_BUNDLED_LIBICONV "Use the bundled version of libiconv." ON) @@ -45,6 +45,19 @@ else() option(USE_BUNDLED_LIBICONV "Use the bundled version of libiconv." OFF) endif() +option(ENABLE_WASMTIME "Use treesitter with wasmtime support." OFF) +if(ENABLE_WASMTIME) + if(USE_BUNDLED) + option(USE_BUNDLED_WASMTIME "Use the bundled wasmtime." ON) + else() + option(USE_BUNDLED_WASMTIME "Use the bundled wasmtime." OFF) + endif() +endif() +if(NOT ENABLE_WASMTIME AND USE_BUNDLED_WASMTIME) + message(FATAL_ERROR "ENABLE_WASMTIME is set to OFF while USE_BUNDLED_WASMTIME is set to ON.\ + You need set ENABLE_WASMTIME to ON if you want to use wasmtime.") +endif() + option(USE_EXISTING_SRC_DIR "Skip download of deps sources in case of existing source directory." OFF) set_default_buildtype(Release) @@ -74,25 +87,6 @@ if(APPLE) message(STATUS "Using deployment target ${CMAKE_OSX_DEPLOYMENT_TARGET}") endif() -set_directory_properties(PROPERTIES - EP_PREFIX "${DEPS_BUILD_DIR}" - CMAKE_CONFIGURE_DEPENDS deps.txt) - -file(READ deps.txt DEPENDENCIES) -STRING(REGEX REPLACE "\n" ";" DEPENDENCIES "${DEPENDENCIES}") -foreach(dep ${DEPENDENCIES}) - STRING(REGEX REPLACE " " ";" dep "${dep}") - list(GET dep 0 name) - list(GET dep 1 value) - if(NOT ${name}) - # _URL variables must NOT be set when USE_EXISTING_SRC_DIR is set, - # otherwise ExternalProject will try to re-download the sources. - if(NOT USE_EXISTING_SRC_DIR) - set(${name} ${value}) - endif() - endif() -endforeach() - if(USE_BUNDLED_LUAJIT) set(LUA_ENGINE LuaJit) elseif(USE_BUNDLED_LUA) @@ -115,18 +109,10 @@ if(USE_BUNDLED_UNIBILIUM) include(BuildUnibilium) endif() -if(USE_BUNDLED_LIBVTERM) - include(BuildLibvterm) -endif() - if(USE_BUNDLED_LIBUV) include(BuildLibuv) endif() -if(USE_BUNDLED_MSGPACK) - include(BuildMsgpack) -endif() - if(USE_BUNDLED_LUAJIT) include(BuildLuajit) endif() @@ -155,10 +141,18 @@ if(USE_BUNDLED_TS_PARSERS) include(BuildTreesitterParsers) endif() +if(USE_BUNDLED_WASMTIME) + include(BuildWasmtime) +endif() + if(USE_BUNDLED_TS) include(BuildTreesitter) endif() +if(USE_BUNDLED_UTF8PROC) + include(BuildUTF8proc) +endif() + if(WIN32) include(GetBinaryDeps) diff --git a/cmake.deps/CMakePresets.json b/cmake.deps/CMakePresets.json index f399dad217..fdec38372c 100644 --- a/cmake.deps/CMakePresets.json +++ b/cmake.deps/CMakePresets.json @@ -16,8 +16,9 @@ "description": "Build neovim with external deps on ubuntu", "cacheVariables": { "USE_BUNDLED":"OFF", - "USE_BUNDLED_LIBVTERM":"ON", - "USE_BUNDLED_TS":"ON" + "USE_BUNDLED_TS":"ON", + "USE_BUNDLED_UTF8PROC":"ON", + "ENABLE_WASMTIME":"OFF" }, "inherits": ["base"] } diff --git a/cmake.deps/cmake/BuildLibvterm.cmake b/cmake.deps/cmake/BuildLibvterm.cmake deleted file mode 100644 index 3415d8debe..0000000000 --- a/cmake.deps/cmake/BuildLibvterm.cmake +++ /dev/null @@ -1,8 +0,0 @@ -get_externalproject_options(libvterm ${DEPS_IGNORE_SHA}) -ExternalProject_Add(libvterm - DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/libvterm - PATCH_COMMAND ${CMAKE_COMMAND} -E copy - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/LibvtermCMakeLists.txt - ${DEPS_BUILD_DIR}/src/libvterm/CMakeLists.txt - CMAKE_ARGS ${DEPS_CMAKE_ARGS} - ${EXTERNALPROJECT_OPTIONS}) diff --git a/cmake.deps/cmake/BuildMsgpack.cmake b/cmake.deps/cmake/BuildMsgpack.cmake deleted file mode 100644 index 8f82dab140..0000000000 --- a/cmake.deps/cmake/BuildMsgpack.cmake +++ /dev/null @@ -1,7 +0,0 @@ -get_externalproject_options(msgpack ${DEPS_IGNORE_SHA}) -ExternalProject_Add(msgpack - DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/msgpack - CMAKE_ARGS ${DEPS_CMAKE_ARGS} - -D MSGPACK_BUILD_TESTS=OFF - -D MSGPACK_BUILD_EXAMPLES=OFF - ${EXTERNALPROJECT_OPTIONS}) diff --git a/cmake.deps/cmake/BuildTreesitter.cmake b/cmake.deps/cmake/BuildTreesitter.cmake index 7eb98163b9..f5962c8037 100644 --- a/cmake.deps/cmake/BuildTreesitter.cmake +++ b/cmake.deps/cmake/BuildTreesitter.cmake @@ -1,8 +1,14 @@ +if(ENABLE_WASMTIME) + set(TREESITTER_ARGS -D TREE_SITTER_FEATURE_WASM=ON) +endif() + get_externalproject_options(treesitter ${DEPS_IGNORE_SHA}) ExternalProject_Add(treesitter DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/treesitter - PATCH_COMMAND ${CMAKE_COMMAND} -E copy - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/TreesitterCMakeLists.txt - ${DEPS_BUILD_DIR}/src/treesitter/CMakeLists.txt - CMAKE_ARGS ${DEPS_CMAKE_ARGS} + SOURCE_SUBDIR lib + CMAKE_ARGS ${DEPS_CMAKE_ARGS} ${TREESITTER_ARGS} ${EXTERNALPROJECT_OPTIONS}) + +if(USE_BUNDLED_WASMTIME) + add_dependencies(treesitter wasmtime) +endif() diff --git a/cmake.deps/cmake/BuildTreesitterParsers.cmake b/cmake.deps/cmake/BuildTreesitterParsers.cmake index 837d075d20..060447e6fe 100644 --- a/cmake.deps/cmake/BuildTreesitterParsers.cmake +++ b/cmake.deps/cmake/BuildTreesitterParsers.cmake @@ -28,7 +28,7 @@ function(BuildTSParser) ${EXTERNALPROJECT_OPTIONS}) endfunction() -foreach(lang c lua vim vimdoc query python bash) +foreach(lang c lua vim vimdoc query) BuildTSParser(LANG ${lang}) endforeach() BuildTSParser(LANG markdown CMAKE_FILE MarkdownParserCMakeLists.txt) diff --git a/cmake.deps/cmake/BuildUTF8proc.cmake b/cmake.deps/cmake/BuildUTF8proc.cmake new file mode 100644 index 0000000000..9445e615f0 --- /dev/null +++ b/cmake.deps/cmake/BuildUTF8proc.cmake @@ -0,0 +1,5 @@ +get_externalproject_options(utf8proc ${DEPS_IGNORE_SHA}) +ExternalProject_Add(utf8proc + DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/utf8proc + CMAKE_ARGS ${DEPS_CMAKE_ARGS} + ${EXTERNALPROJECT_OPTIONS}) diff --git a/cmake.deps/cmake/BuildWasmtime.cmake b/cmake.deps/cmake/BuildWasmtime.cmake new file mode 100644 index 0000000000..d3c51ebdc7 --- /dev/null +++ b/cmake.deps/cmake/BuildWasmtime.cmake @@ -0,0 +1,11 @@ +# wasmtime is a chungus -- optimize _extra hard_ to keep nvim svelte +get_externalproject_options(wasmtime ${DEPS_IGNORE_SHA}) +ExternalProject_Add(wasmtime + DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/wasmtime + SOURCE_SUBDIR crates/c-api + CMAKE_ARGS ${DEPS_CMAKE_ARGS} + -D WASMTIME_FASTEST_RUNTIME=ON # build with full LTO + -D WASMTIME_DISABLE_ALL_FEATURES=ON # don't need all that crap... + -D WASMTIME_FEATURE_CRANELIFT=ON # ...except this one (compiles wasm to platform code) + USES_TERMINAL_BUILD TRUE + ${EXTERNALPROJECT_OPTIONS}) diff --git a/cmake.deps/cmake/GettextCMakeLists.txt b/cmake.deps/cmake/GettextCMakeLists.txt index c36f3aada5..722420e830 100644 --- a/cmake.deps/cmake/GettextCMakeLists.txt +++ b/cmake.deps/cmake/GettextCMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.13) +cmake_minimum_required(VERSION 3.16) project(gettext C) add_compile_options(-w) diff --git a/cmake.deps/cmake/LibiconvCMakeLists.txt b/cmake.deps/cmake/LibiconvCMakeLists.txt index e62b479b6b..9181314883 100644 --- a/cmake.deps/cmake/LibiconvCMakeLists.txt +++ b/cmake.deps/cmake/LibiconvCMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.13) +cmake_minimum_required(VERSION 3.16) project(libiconv C) add_compile_options(-w) diff --git a/cmake.deps/cmake/LibvtermCMakeLists.txt b/cmake.deps/cmake/LibvtermCMakeLists.txt deleted file mode 100644 index c197523786..0000000000 --- a/cmake.deps/cmake/LibvtermCMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -cmake_minimum_required(VERSION 3.13) -project(libvterm C) - -add_compile_options(-w) - -include(GNUInstallDirs) - -include_directories(${CMAKE_SOURCE_DIR}/include) -include_directories(${CMAKE_BINARY_DIR}) - -file(GLOB VTERM_SOURCES ${CMAKE_SOURCE_DIR}/src/*.c) -add_library(vterm ${VTERM_SOURCES}) -install(TARGETS vterm ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - -install(FILES include/vterm.h include/vterm_keycodes.h - DESTINATION include) - -if(NOT WIN32) - file(GLOB BIN_SOURCES ${CMAKE_SOURCE_DIR}/bin/*.c) - foreach(EXE_C ${BIN_SOURCES}) - get_filename_component(target_name ${EXE_C} NAME_WE) - add_executable(${target_name} ${EXE_C}) - target_link_libraries(${target_name} vterm) - install(TARGETS ${target_name} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) - endforeach() -endif() - -# vim: set ft=cmake: diff --git a/cmake.deps/cmake/LpegCMakeLists.txt b/cmake.deps/cmake/LpegCMakeLists.txt index 4dcf3a1b77..ac1da8c062 100644 --- a/cmake.deps/cmake/LpegCMakeLists.txt +++ b/cmake.deps/cmake/LpegCMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.13) +cmake_minimum_required(VERSION 3.16) project (lpeg C) include(GNUInstallDirs) diff --git a/cmake.deps/cmake/MarkdownParserCMakeLists.txt b/cmake.deps/cmake/MarkdownParserCMakeLists.txt index 981bf4dfd7..504acb74a5 100644 --- a/cmake.deps/cmake/MarkdownParserCMakeLists.txt +++ b/cmake.deps/cmake/MarkdownParserCMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.13) +cmake_minimum_required(VERSION 3.16) project(${PARSERLANG} C) add_compile_options(-w) diff --git a/cmake.deps/cmake/TreesitterCMakeLists.txt b/cmake.deps/cmake/TreesitterCMakeLists.txt deleted file mode 100644 index 71174bfe5b..0000000000 --- a/cmake.deps/cmake/TreesitterCMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -cmake_minimum_required(VERSION 3.13) -project(treesitter C) - -add_compile_options(-w) - -add_library(tree-sitter lib/src/lib.c) -target_include_directories(tree-sitter - PRIVATE lib/src lib/include) - -install(FILES - lib/include/tree_sitter/api.h - DESTINATION include/tree_sitter) - -include(GNUInstallDirs) -install(TARGETS tree-sitter DESTINATION ${CMAKE_INSTALL_LIBDIR}) - -# vim: set ft=cmake: diff --git a/cmake.deps/cmake/TreesitterParserCMakeLists.txt b/cmake.deps/cmake/TreesitterParserCMakeLists.txt index 0d4bbf0508..08b942a0ff 100644 --- a/cmake.deps/cmake/TreesitterParserCMakeLists.txt +++ b/cmake.deps/cmake/TreesitterParserCMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.13) +cmake_minimum_required(VERSION 3.16) project(parser C) add_compile_options(-w) diff --git a/cmake.deps/deps.txt b/cmake.deps/deps.txt index 6b72ed5b52..7acb7523b0 100644 --- a/cmake.deps/deps.txt +++ b/cmake.deps/deps.txt @@ -1,20 +1,14 @@ -LIBUV_URL https://github.com/libuv/libuv/archive/v1.48.0.tar.gz -LIBUV_SHA256 8c253adb0f800926a6cbd1c6576abae0bc8eb86a4f891049b72f9e5b7dc58f33 +LIBUV_URL https://github.com/libuv/libuv/archive/v1.49.0.tar.gz +LIBUV_SHA256 a10656a0865e2cff7a1b523fa47d0f5a9c65be963157301f814d1cc5dbd4dc1d -MSGPACK_URL https://github.com/msgpack/msgpack-c/archive/c-6.0.1.tar.gz -MSGPACK_SHA256 58d5fe49d0ee2b374d60a61aabf8028b2c92004e6f11bff04e74b639fc8ad541 - -LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/75e92777988017fe47c5eb290998021bbf972d1f.tar.gz -LUAJIT_SHA256 0f69288190024d732c67645e40ed5b137d67aa950fedf0f44a9ad0f3dba6d5d2 +LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/97813fb924edf822455f91a5fbbdfdb349e5984f.tar.gz +LUAJIT_SHA256 cbf1647acbd340c62b9c342dae43290762efa1b26d8bf8457f143fabf8ed86c7 LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333 -UNIBILIUM_URL https://github.com/neovim/unibilium/archive/d72c3598e7ac5d1ebf86ee268b8b4ed95c0fa628.tar.gz -UNIBILIUM_SHA256 9c4747c862ab5e3076dcf8fa8f0ea7a6b50f20ec5905618b9536655596797487 - -LIBVTERM_URL https://github.com/neovim/libvterm/archive/0a15c6e983b0db7ef8276e0792414a805d01bdaf.tar.gz -LIBVTERM_SHA256 c4683e7a2d71c04781fd0ab7719a94202800e97a9e091514c16983bb732b0fa7 +UNIBILIUM_URL https://github.com/neovim/unibilium/archive/v2.1.2.tar.gz +UNIBILIUM_SHA256 370ecb07fbbc20d91d1b350c55f1c806b06bf86797e164081ccc977fc9b3af7a LUV_URL https://github.com/luvit/luv/releases/download/1.48.0-2/luv-1.48.0-2.tar.gz LUV_SHA256 2c3a1ddfebb4f6550293a40ee789f7122e97647eede51511f57203de48c03b7a @@ -41,21 +35,28 @@ GETTEXT_SHA256 66415634c6e8c3fa8b71362879ec7575e27da43da562c798a8a2f223e6e47f5c LIBICONV_URL https://github.com/neovim/deps/raw/b9bf36eb31f27e8136d907da38fa23518927737e/opt/libiconv-1.17.tar.gz LIBICONV_SHA256 8f74213b56238c85a50a5329f77e06198771e70dd9a739779f4c02f65d971313 -TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.21.0.tar.gz -TREESITTER_C_SHA256 6f0f5d1b71cf8ffd8a37fb638c6022fa1245bd630150b538547d52128ce0ea7e -TREESITTER_LUA_URL https://github.com/tree-sitter-grammars/tree-sitter-lua/archive/v0.1.0.tar.gz -TREESITTER_LUA_SHA256 230cfcbfa74ed1f7b8149e9a1f34c2efc4c589a71fe0f5dc8560622f8020d722 +UTF8PROC_URL https://github.com/JuliaStrings/utf8proc/archive/3de4596fbe28956855df2ecb3c11c0bbc3535838.tar.gz +UTF8PROC_SHA256 fb4a16bb659b58afb7f921fcc8928d0b3c1fcab135366c8a4f9ca7de1b1cfada + +TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.23.0.tar.gz +TREESITTER_C_SHA256 ee58c925e2e507c23d735aad46bf7fb0af31ca06d6f4f41bc008216d9232b0cb +TREESITTER_LUA_URL https://github.com/tree-sitter-grammars/tree-sitter-lua/archive/v0.2.0.tar.gz +TREESITTER_LUA_SHA256 6c41227cd0a59047b19d31f0031d4d901f08bfd78d6fc7f55c89e5b8374c794e TREESITTER_VIM_URL https://github.com/neovim/tree-sitter-vim/archive/v0.4.0.tar.gz TREESITTER_VIM_SHA256 9f856f8b4a10ab43348550fa2d3cb2846ae3d8e60f45887200549c051c66f9d5 -TREESITTER_VIMDOC_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v2.5.1.tar.gz -TREESITTER_VIMDOC_SHA256 063645096504b21603585507c41c6d8718ff3c11b2150c5bfc31e8f3ee9afea3 -TREESITTER_QUERY_URL https://github.com/tree-sitter-grammars/tree-sitter-query/archive/v0.3.0.tar.gz -TREESITTER_QUERY_SHA256 f878ff37abcb83250e31a6569e997546f3dbab74dcb26683cb2d613f7568cfc0 -TREESITTER_PYTHON_URL https://github.com/tree-sitter/tree-sitter-python/archive/v0.21.0.tar.gz -TREESITTER_PYTHON_SHA256 720304a603271fa89e4430a14d6a81a023d6d7d1171b1533e49c0ab44f1e1c13 -TREESITTER_BASH_URL https://github.com/tree-sitter/tree-sitter-bash/archive/v0.21.0.tar.gz -TREESITTER_BASH_SHA256 f0515efda839cfede851adb24ac154227fbc0dfb60c6c11595ecfa9087d43ceb -TREESITTER_MARKDOWN_URL https://github.com/MDeiml/tree-sitter-markdown/archive/v0.2.3.tar.gz -TREESITTER_MARKDOWN_SHA256 4909d6023643f1afc3ab219585d4035b7403f3a17849782ab803c5f73c8a31d5 -TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.22.6.tar.gz -TREESITTER_SHA256 e2b687f74358ab6404730b7fb1a1ced7ddb3780202d37595ecd7b20a8f41861f +TREESITTER_VIMDOC_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v3.0.0.tar.gz +TREESITTER_VIMDOC_SHA256 a639bf92bf57bfa1cdc90ca16af27bfaf26a9779064776dd4be34c1ef1453f6c +TREESITTER_QUERY_URL https://github.com/tree-sitter-grammars/tree-sitter-query/archive/v0.4.0.tar.gz +TREESITTER_QUERY_SHA256 d3a423ab66dc62b2969625e280116678a8a22582b5ff087795222108db2f6a6e +TREESITTER_MARKDOWN_URL https://github.com/tree-sitter-grammars/tree-sitter-markdown/archive/v0.3.2.tar.gz +TREESITTER_MARKDOWN_SHA256 5dac48a6d971eb545aab665d59a18180d21963afc781bbf40f9077c06cb82ae5 +TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.24.1.tar.gz +TREESITTER_SHA256 7adb5bb3b3c2c4f4fdc980a9a13df8fbf3526a82b5c37dd9cf2ed29de56a4683 + +WASMTIME_URL https://github.com/bytecodealliance/wasmtime/archive/v25.0.1.tar.gz +WASMTIME_SHA256 0e816ee247eda6c35fca20dfaeac50c2cbb0df60d305b722fa2be9eced5b95da + +UNCRUSTIFY_URL https://github.com/uncrustify/uncrustify/archive/uncrustify-0.79.0.tar.gz +UNCRUSTIFY_SHA256 e7afaeabf636b7f0ce4e3e9747b95f7bd939613a8db49579755dddf44fedca5f +LUA_DEV_DEPS_URL https://github.com/neovim/deps/raw/5a1f71cceb24990a0b15fd9a472a5f549f019248/opt/lua-dev-deps.tar.gz +LUA_DEV_DEPS_SHA256 27db2495f5eddc7fc191701ec9b291486853530c6125609d3197d03481e8d5a2 diff --git a/cmake.packaging/CMakeLists.txt b/cmake.packaging/CMakeLists.txt index 645215ec92..8c158c39dc 100644 --- a/cmake.packaging/CMakeLists.txt +++ b/cmake.packaging/CMakeLists.txt @@ -38,6 +38,11 @@ if(WIN32) # Create start menu and desktop shortcuts set(CPACK_WIX_PROGRAM_MENU_FOLDER "${CPACK_PACKAGE_NAME}") set(CPACK_PACKAGE_EXECUTABLES "nvim" "Neovim") + set(CPACK_WIX_INSTALL_SCOPE "perMachine") + + set(CPACK_WIX_UI_REF "WixUI_CustomInstallDir") + list(APPEND CPACK_WIX_EXTRA_SOURCES ${CMAKE_CURRENT_LIST_DIR}/WixUI_CustomInstallDir.wxs) + list(APPEND CPACK_WIX_EXTRA_SOURCES ${CMAKE_CURRENT_LIST_DIR}/CustomInstallDirDlg.wxs) # We use a wix patch to add further options to the installer. # See: https://cmake.org/cmake/help/v3.7/module/CPackWIX.html#variable:CPACK_WIX_PATCH_FILE diff --git a/cmake.packaging/CustomInstallDirDlg.wxs b/cmake.packaging/CustomInstallDirDlg.wxs new file mode 100644 index 0000000000..73864cec0b --- /dev/null +++ b/cmake.packaging/CustomInstallDirDlg.wxs @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> + + +<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> + <Fragment> + <UI> + <Dialog Id="CustomInstallDirDlg" Width="370" Height="270" Title="!(loc.InstallDirDlg_Title)"> + <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="!(loc.WixUINext)" /> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="!(loc.WixUIBack)" /> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="!(loc.WixUICancel)"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + + <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes" Text="!(loc.InstallDirDlgDescription)" /> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes" Text="!(loc.InstallDirDlgTitle)" /> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="!(loc.InstallDirDlgBannerBitmap)" /> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" /> + + <Control Id="Note" Type="Text" X="20" Y="45" Width="290" Height="45" NoPrefix="yes"> + <Text>Note: besides its installation folder, [ProductName] stores configuration, data, and logs in standard locations. These can be further configured by the $NVIM_APPNAME environment variable. Also, the "base" (root) directories conform to the XDG Base Directory Specification. For more information see:</Text> + </Control> + <Control Id="Link1" Type="Hyperlink" X="20" Y="90" Width="290" Height="15"> + <Text><![CDATA[<a href="https://neovim.io/doc/user/starting.html#standard-path">https://neovim.io/doc/user/starting.html#standard-path</a>]]></Text> + </Control> + <Control Id="Link2" Type="Hyperlink" X="20" Y="105" Width="290" Height="15"> + <Text><![CDATA[<a href="https://neovim.io/doc/user/starting.html#base-directories">https://neovim.io/doc/user/starting.html#base-directories</a>]]></Text> + </Control> + <Control Id="Link3" Type="Hyperlink" X="20" Y="120" Width="290" Height="15"> + <Text><![CDATA[<a href="https://neovim.io/doc/user/starting.html#%24NVIM_APPNAME">https://neovim.io/doc/user/starting.html#$NVIM_APPNAME</a>]]></Text> + </Control> + <Control Id="FolderLabel" Type="Hyperlink" X="20" Y="135" Width="290" Height="15"> + <Text>Install [ProductName] to:</Text> + </Control> + <Control Id="Folder" Type="PathEdit" X="20" Y="150" Width="320" Height="18" Property="WIXUI_INSTALLDIR" Indirect="yes" /> + <Control Id="ChangeFolder" Type="PushButton" X="20" Y="180" Width="56" Height="17" Text="!(loc.InstallDirDlgChange)" /> + </Dialog> + </UI> + </Fragment> +</Wix> diff --git a/cmake.packaging/WixPatch.xml b/cmake.packaging/WixPatch.xml index 1196f4f335..89c47753ce 100644 --- a/cmake.packaging/WixPatch.xml +++ b/cmake.packaging/WixPatch.xml @@ -6,7 +6,7 @@ Name='PATH' Action='set' Permanent='no' - System='no' + System='yes' Part='last' Value='[INSTALL_ROOT]bin' /> diff --git a/cmake.packaging/WixUI_CustomInstallDir.wxs b/cmake.packaging/WixUI_CustomInstallDir.wxs new file mode 100644 index 0000000000..8015758771 --- /dev/null +++ b/cmake.packaging/WixUI_CustomInstallDir.wxs @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> + + + +<!-- +First-time install dialog sequence: + - WixUI_WelcomeDlg + - WixUI_LicenseAgreementDlg + - WixUI_InstallDirDlg + - WixUI_VerifyReadyDlg + - WixUI_DiskCostDlg + +Maintenance dialog sequence: + - WixUI_MaintenanceWelcomeDlg + - WixUI_MaintenanceTypeDlg + - WixUI_InstallDirDlg + - WixUI_VerifyReadyDlg + +Patch dialog sequence: + - WixUI_WelcomeDlg + - WixUI_VerifyReadyDlg + +--> + +<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> + <Fragment> + <UI Id="WixUI_CustomInstallDir"> + <TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" /> + <TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" /> + <TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" /> + + <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" /> + <Property Id="WixUI_Mode" Value="InstallDir" /> + + <DialogRef Id="BrowseDlg" /> + <DialogRef Id="DiskCostDlg" /> + <DialogRef Id="ErrorDlg" /> + <DialogRef Id="FatalError" /> + <DialogRef Id="FilesInUse" /> + <DialogRef Id="MsiRMFilesInUse" /> + <DialogRef Id="PrepareDlg" /> + <DialogRef Id="ProgressDlg" /> + <DialogRef Id="ResumeDlg" /> + <DialogRef Id="UserExit" /> + + <Publish Dialog="BrowseDlg" Control="OK" Event="DoAction" Value="WixUIValidatePath" Order="3">1</Publish> + <Publish Dialog="BrowseDlg" Control="OK" Event="SpawnDialog" Value="InvalidDirDlg" Order="4"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish> + + <Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish> + + <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="LicenseAgreementDlg">NOT Installed</Publish> + <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">Installed AND PATCH</Publish> + + <Publish Dialog="LicenseAgreementDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg">1</Publish> + <Publish Dialog="LicenseAgreementDlg" Control="Next" Event="NewDialog" Value="CustomInstallDirDlg">LicenseAccepted = "1"</Publish> + + <Publish Dialog="CustomInstallDirDlg" Control="Back" Event="NewDialog" Value="LicenseAgreementDlg">1</Publish> + <Publish Dialog="CustomInstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish> + <Publish Dialog="CustomInstallDirDlg" Control="Next" Event="DoAction" Value="WixUIValidatePath" Order="2">NOT WIXUI_DONTVALIDATEPATH</Publish> + <Publish Dialog="CustomInstallDirDlg" Control="Next" Event="SpawnDialog" Value="InvalidDirDlg" Order="3"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish> + <Publish Dialog="CustomInstallDirDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="4">WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1"</Publish> + <Publish Dialog="CustomInstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish> + <Publish Dialog="CustomInstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="2">1</Publish> + + <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="CustomInstallDirDlg" Order="1">NOT Installed</Publish> + <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="2">Installed AND NOT PATCH</Publish> + <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2">Installed AND PATCH</Publish> + + <Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish> + + <Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish> + <Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish> + <Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish> + + <Property Id="ARPNOMODIFY" Value="1" /> + </UI> + + <UIRef Id="WixUI_Common" /> + </Fragment> +</Wix> diff --git a/cmake/Deps.cmake b/cmake/Deps.cmake index 413e3a08a9..519826654f 100644 --- a/cmake/Deps.cmake +++ b/cmake/Deps.cmake @@ -18,11 +18,6 @@ if(APPLE) list(APPEND DEPS_CMAKE_ARGS -D CMAKE_FIND_FRAMEWORK=${CMAKE_FIND_FRAMEWORK}) endif() -# Can be removed once minimum version is at least 3.15 -if(POLICY CMP0092) - list(APPEND DEPS_CMAKE_ARGS -D CMAKE_POLICY_DEFAULT_CMP0092=NEW) -endif() - find_program(CACHE_PRG NAMES ccache sccache) if(CACHE_PRG) set(CMAKE_C_COMPILER_LAUNCHER ${CMAKE_COMMAND} -E env CCACHE_SLOPPINESS=pch_defines,time_macros ${CACHE_PRG}) @@ -58,6 +53,32 @@ if(CMAKE_OSX_SYSROOT) set(DEPS_C_COMPILER "${DEPS_C_COMPILER} -isysroot${CMAKE_OSX_SYSROOT}") endif() +get_filename_component(rootdir ${PROJECT_SOURCE_DIR} NAME) +if(${rootdir} MATCHES "cmake.deps") + set(depsfile ${PROJECT_SOURCE_DIR}/deps.txt) +else() + set(depsfile ${PROJECT_SOURCE_DIR}/cmake.deps/deps.txt) +endif() + +set_directory_properties(PROPERTIES + EP_PREFIX "${DEPS_BUILD_DIR}" + CMAKE_CONFIGURE_DEPENDS ${depsfile}) + +file(READ ${depsfile} DEPENDENCIES) +STRING(REGEX REPLACE "\n" ";" DEPENDENCIES "${DEPENDENCIES}") +foreach(dep ${DEPENDENCIES}) + STRING(REGEX REPLACE " " ";" dep "${dep}") + list(GET dep 0 name) + list(GET dep 1 value) + if(NOT ${name}) + # _URL variables must NOT be set when USE_EXISTING_SRC_DIR is set, + # otherwise ExternalProject will try to re-download the sources. + if(NOT USE_EXISTING_SRC_DIR) + set(${name} ${value}) + endif() + endif() +endforeach() + function(get_externalproject_options name DEPS_IGNORE_SHA) string(TOUPPER ${name} name_allcaps) set(url ${${name_allcaps}_URL}) diff --git a/cmake/FindLibvterm.cmake b/cmake/FindLibvterm.cmake deleted file mode 100644 index 68c2646d47..0000000000 --- a/cmake/FindLibvterm.cmake +++ /dev/null @@ -1,31 +0,0 @@ -find_path2(LIBVTERM_INCLUDE_DIR vterm.h) -find_library2(LIBVTERM_LIBRARY vterm) - -if(LIBVTERM_INCLUDE_DIR AND EXISTS "${LIBVTERM_INCLUDE_DIR}/vterm.h") - file(STRINGS ${LIBVTERM_INCLUDE_DIR}/vterm.h VTERM_VERSION_MAJOR REGEX "#define VTERM_VERSION_MAJOR") - string(REGEX MATCH "[0-9]+" VTERM_VERSION_MAJOR ${VTERM_VERSION_MAJOR}) - - file(STRINGS ${LIBVTERM_INCLUDE_DIR}/vterm.h VTERM_VERSION_MINOR REGEX "#define VTERM_VERSION_MINOR") - string(REGEX MATCH "[0-9]+" VTERM_VERSION_MINOR ${VTERM_VERSION_MINOR}) - - file(STRINGS ${LIBVTERM_INCLUDE_DIR}/vterm.h VTERM_VERSION_PATCH REGEX "#define VTERM_VERSION_PATCH") - - # The following is needed to give a coherent error for versions 0.3.2 and - # smaller. - if(VTERM_VERSION_PATCH) - string(REGEX MATCH "[0-9]+" VTERM_VERSION_PATCH ${VTERM_VERSION_PATCH}) - string(PREPEND VTERM_VERSION_PATCH ".") - endif() - - set(VTERM_VERSION ${VTERM_VERSION_MAJOR}.${VTERM_VERSION_MINOR}${VTERM_VERSION_PATCH}) -endif() - -find_package_handle_standard_args(Libvterm - REQUIRED_VARS LIBVTERM_INCLUDE_DIR LIBVTERM_LIBRARY - VERSION_VAR VTERM_VERSION) - -add_library(libvterm INTERFACE) -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/FindMsgpack.cmake b/cmake/FindMsgpack.cmake deleted file mode 100644 index 9ef18122ab..0000000000 --- a/cmake/FindMsgpack.cmake +++ /dev/null @@ -1,24 +0,0 @@ -find_path2(MSGPACK_INCLUDE_DIR msgpack/version_master.h) - -if(MSGPACK_INCLUDE_DIR) - file(READ ${MSGPACK_INCLUDE_DIR}/msgpack/version_master.h msgpack_version_h) - string(REGEX REPLACE ".*MSGPACK_VERSION_MAJOR +([0-9]+).*" "\\1" MSGPACK_VERSION_MAJOR "${msgpack_version_h}") - string(REGEX REPLACE ".*MSGPACK_VERSION_MINOR +([0-9]+).*" "\\1" MSGPACK_VERSION_MINOR "${msgpack_version_h}") - string(REGEX REPLACE ".*MSGPACK_VERSION_REVISION +([0-9]+).*" "\\1" MSGPACK_VERSION_REVISION "${msgpack_version_h}") - set(MSGPACK_VERSION_STRING "${MSGPACK_VERSION_MAJOR}.${MSGPACK_VERSION_MINOR}.${MSGPACK_VERSION_REVISION}") -else() - set(MSGPACK_VERSION_STRING) -endif() - -find_library2(MSGPACK_LIBRARY NAMES msgpackc msgpack msgpackc_import msgpack-c - NAMES_PER_DIR) - -mark_as_advanced(MSGPACK_INCLUDE_DIR MSGPACK_LIBRARY) - -find_package_handle_standard_args(Msgpack - REQUIRED_VARS MSGPACK_LIBRARY MSGPACK_INCLUDE_DIR - VERSION_VAR MSGPACK_VERSION_STRING) - -add_library(msgpack INTERFACE) -target_include_directories(msgpack SYSTEM BEFORE INTERFACE ${MSGPACK_INCLUDE_DIR}) -target_link_libraries(msgpack INTERFACE ${MSGPACK_LIBRARY}) diff --git a/cmake/FindUTF8proc.cmake b/cmake/FindUTF8proc.cmake new file mode 100644 index 0000000000..2183f35d34 --- /dev/null +++ b/cmake/FindUTF8proc.cmake @@ -0,0 +1,12 @@ +find_path2(UTF8PROC_INCLUDE_DIR utf8proc.h) +find_library2(UTF8PROC_LIBRARY NAMES utf8proc utf8proc_static) +find_package_handle_standard_args(UTF8proc DEFAULT_MSG + UTF8PROC_LIBRARY UTF8PROC_INCLUDE_DIR) +mark_as_advanced(UTF8PROC_LIBRARY UTF8PROC_INCLUDE_DIR) + +add_library(utf8proc INTERFACE) +target_include_directories(utf8proc SYSTEM BEFORE INTERFACE ${UTF8PROC_INCLUDE_DIR}) +target_link_libraries(utf8proc INTERFACE ${UTF8PROC_LIBRARY}) + +#TODO(dundargoc): this is a hack that should ideally be hardcoded into the utf8proc project via configure_command +target_compile_definitions(utf8proc INTERFACE "UTF8PROC_STATIC") diff --git a/cmake/FindWasmtime.cmake b/cmake/FindWasmtime.cmake new file mode 100644 index 0000000000..e6315748b4 --- /dev/null +++ b/cmake/FindWasmtime.cmake @@ -0,0 +1,22 @@ +find_path2(WASMTIME_INCLUDE_DIR wasmtime.h) +find_library2(WASMTIME_LIBRARY wasmtime) + +if(WASMTIME_INCLUDE_DIR AND EXISTS "${WASMTIME_INCLUDE_DIR}/wasmtime.h") + file(STRINGS ${WASMTIME_INCLUDE_DIR}/wasmtime.h WASMTIME_VERSION REGEX "#define WASMTIME_VERSION") + string(REGEX MATCH "[0-9]+\.[0-9]\.[0-9]" WASMTIME_VERSION ${WASMTIME_VERSION}) +endif() + +find_package_handle_standard_args(Wasmtime + REQUIRED_VARS WASMTIME_INCLUDE_DIR WASMTIME_LIBRARY + VERSION_VAR WASMTIME_VERSION) + +add_library(wasmtime INTERFACE) +target_include_directories(wasmtime SYSTEM BEFORE INTERFACE ${WASMTIME_INCLUDE_DIR}) +target_link_libraries(wasmtime INTERFACE ${WASMTIME_LIBRARY}) + +if(MSVC) + target_compile_options(wasmtime INTERFACE -DWASM_API_EXTERN= -DWASI_API_EXTERN=) + target_link_libraries(wasmtime INTERFACE ws2_32 advapi32 userenv ntdll shell32 ole32 bcrypt) +endif() + +mark_as_advanced(WASMTIME_INCLUDE_DIR WASMTIME_LIBRARY) diff --git a/contrib/local.mk.example b/contrib/local.mk.example index 58474a3750..718bf9f2a3 100644 --- a/contrib/local.mk.example +++ b/contrib/local.mk.example @@ -45,13 +45,12 @@ # DEPS_CMAKE_FLAGS += -DUSE_BUNDLED_GETTEXT=OFF # DEPS_CMAKE_FLAGS += -DUSE_BUNDLED_LIBICONV=OFF # DEPS_CMAKE_FLAGS += -DUSE_BUNDLED_LIBUV=OFF -# DEPS_CMAKE_FLAGS += -DUSE_BUNDLED_LIBVTERM=OFF # DEPS_CMAKE_FLAGS += -DUSE_BUNDLED_LUAJIT=OFF # DEPS_CMAKE_FLAGS += -DUSE_BUNDLED_LUV=OFF -# DEPS_CMAKE_FLAGS += -DUSE_BUNDLED_MSGPACK=OFF # DEPS_CMAKE_FLAGS += -DUSE_BUNDLED_TS=OFF # DEPS_CMAKE_FLAGS += -DUSE_BUNDLED_TS_PARSERS=OFF # DEPS_CMAKE_FLAGS += -DUSE_BUNDLED_UNIBILIUM=OFF +# DEPS_CMAKE_FLAGS += -DUSE_BUNDLED_UTF8PROC=OFF # # Or disable all bundled dependencies at once. # diff --git a/contrib/minimal.lua b/contrib/minimal.lua index 2391e12f68..cb4b7f8673 100644 --- a/contrib/minimal.lua +++ b/contrib/minimal.lua @@ -2,7 +2,8 @@ for name, url in pairs { -- ADD PLUGINS _NECESSARY_ TO REPRODUCE THE ISSUE, e.g: - -- some_plugin = 'https://github.com/author/plugin.nvim' + -- 'https://github.com/author1/plugin1', + -- 'https://github.com/author2/plugin2', } do local install_path = vim.fn.fnamemodify('nvim_issue/' .. name, ':p') if vim.fn.isdirectory(install_path) == 0 then diff --git a/runtime/autoload/dist/vim.vim b/runtime/autoload/dist/vim.vim index 021244c93b..bb858c5732 100644 --- a/runtime/autoload/dist/vim.vim +++ b/runtime/autoload/dist/vim.vim @@ -18,6 +18,9 @@ endif if !has('vim9script') function dist#vim#IsSafeExecutable(filetype, executable) let cwd = getcwd() + if empty(exepath(a:executable)) + return v:false + endif return get(g:, a:filetype .. '_exec', get(g:, 'plugin_exec', 0)) && \ (fnamemodify(exepath(a:executable), ':p:h') !=# cwd \ || (split($PATH, has('win32') ? ';' : ':')->index(cwd) != -1 && diff --git a/runtime/autoload/hare.vim b/runtime/autoload/hare.vim new file mode 100644 index 0000000000..c4581fccf9 --- /dev/null +++ b/runtime/autoload/hare.vim @@ -0,0 +1,26 @@ +" Vim autoload file. +" Language: Hare +" Maintainer: Amelia Clarke <selene@perilune.dev> +" Last Updated: 2024-05-10 +" Upstream: https://git.sr.ht/~sircmpwn/hare.vim + +" Attempt to find the directory for a given Hare module. +function hare#FindModule(str) + let path = substitute(trim(a:str, ':', 2), '::', '/', 'g') + let dir = finddir(path) + while !empty(path) && empty(dir) + let path = substitute(path, '/\?\h\w*$', '', '') + let dir = finddir(path) + endwhile + return dir +endfunction + +" Return the value of HAREPATH if it exists. Otherwise use a reasonable default. +function hare#GetPath() + if empty($HAREPATH) + return '/usr/src/hare/stdlib,/usr/src/hare/third-party' + endif + return substitute($HAREPATH, ':', ',', 'g') +endfunction + +" vim: et sts=2 sw=2 ts=8 diff --git a/runtime/autoload/hcl.vim b/runtime/autoload/hcl.vim new file mode 100644 index 0000000000..2215fc8f27 --- /dev/null +++ b/runtime/autoload/hcl.vim @@ -0,0 +1,40 @@ +" Language: HCL +" Maintainer: Gregory Anders +" Last Change: 2024-09-03 +" Based on: https://github.com/hashivim/vim-terraform + +function! hcl#indentexpr(lnum) + " Beginning of the file should have no indent + if a:lnum == 0 + return 0 + endif + + " Usual case is to continue at the same indent as the previous non-blank line. + let prevlnum = prevnonblank(a:lnum-1) + let thisindent = indent(prevlnum) + + " If that previous line is a non-comment ending in [ { (, increase the + " indent level. + let prevline = getline(prevlnum) + if prevline !~# '^\s*\(#\|//\)' && prevline =~# '[\[{\(]\s*$' + let thisindent += &shiftwidth + endif + + " If the current line ends a block, decrease the indent level. + let thisline = getline(a:lnum) + if thisline =~# '^\s*[\)}\]]' + let thisindent -= &shiftwidth + endif + + " If the previous line starts a block comment /*, increase by one + if prevline =~# '/\*' + let thisindent += 1 + endif + + " If the previous line ends a block comment */, decrease by one + if prevline =~# '\*/' + let thisindent -= 1 + endif + + return thisindent +endfunction diff --git a/runtime/autoload/javaformat.vim b/runtime/autoload/javaformat.vim new file mode 100644 index 0000000000..4d7d32cf19 --- /dev/null +++ b/runtime/autoload/javaformat.vim @@ -0,0 +1,92 @@ +" Vim formatting plugin file +" Language: Java +" Maintainer: Aliaksei Budavei <0x000c70 AT gmail DOT com> +" Repository: https://github.com/zzzyxwvut/java-vim.git +" Last Change: 2024 Sep 26 + +" Documented in ":help ft-java-plugin". +if &cp || exists("g:loaded_javaformat") || exists("g:java_ignore_javadoc") || exists("g:java_ignore_markdown") + finish +endif + +let g:loaded_javaformat = 1 + +"""" STRIVE TO REMAIN COMPATIBLE FOR AT LEAST VIM 7.0. + +function! javaformat#RemoveCommonMarkdownWhitespace() abort + if mode() != 'n' + return 0 + endif + + let pattern = '\(^\s*///\)\(\s*\)\(.*\)' + + " E121 for v:numbermax before v8.2.2388. + " E15 for expr-<< before v8.2.5003. + let common = 0x7fffffff + let comments = [] + + for n in range(v:lnum, (v:lnum + v:count - 1)) + let parts = matchlist(getline(n), pattern) + let whitespace = get(parts, 2, '') + let nonwhitespace = get(parts, 3, '') + + if !empty(whitespace) + let common = min([common, strlen(whitespace)]) + elseif !empty(nonwhitespace) || empty(parts) + " No whitespace prefix or not a Markdown comment. + return 0 + endif + + call add(comments, [whitespace, parts[1], nonwhitespace]) + endfor + + let cursor = v:lnum + + for line in comments + call setline(cursor, join(line[1 :], strpart(line[0], common))) + let cursor += 1 + endfor + + return 0 +endfunction + +" See ":help vim9-mix". +if !has("vim9script") + finish +endif + +def! g:javaformat#RemoveCommonMarkdownWhitespace(): number + if mode() != 'n' + return 0 + endif + + const pattern: string = '\(^\s*///\)\(\s*\)\(.*\)' + var common: number = v:numbermax + var comments: list<list<string>> = [] + + for n in range(v:lnum, (v:lnum + v:count - 1)) + const parts: list<string> = matchlist(getline(n), pattern) + const whitespace: string = get(parts, 2, '') + const nonwhitespace: string = get(parts, 3, '') + + if !empty(whitespace) + common = min([common, strlen(whitespace)]) + elseif !empty(nonwhitespace) || empty(parts) + # No whitespace prefix or not a Markdown comment. + return 0 + endif + + add(comments, [whitespace, parts[1], nonwhitespace]) + endfor + + var cursor: number = v:lnum + + for line in comments + setline(cursor, join(line[1 :], strpart(line[0], common))) + cursor += 1 + endfor + + return 0 +enddef + +" vim: fdm=syntax sw=4 ts=8 noet sta diff --git a/runtime/autoload/msgpack.vim b/runtime/autoload/msgpack.vim index 18dcd1e6a6..fb438def4f 100644 --- a/runtime/autoload/msgpack.vim +++ b/runtime/autoload/msgpack.vim @@ -361,7 +361,7 @@ endfunction let s:MSGPACK_STANDARD_TYPES = { \type(0): 'integer', \type(0.0): 'float', - \type(''): 'binary', + \type(''): 'string', \type([]): 'array', \type({}): 'map', \type(v:true): 'boolean', @@ -412,9 +412,15 @@ endfunction "" " Dump |msgpack-special-dict| that represents a string. If any additional " parameter is given then it dumps binary string. -function s:msgpack_dump_string(v, ...) abort - let ret = [a:0 ? '"' : '="'] - for v in a:v._VAL +function s:msgpack_dump_string(v) abort + if type(a:v) == type({}) + let val = a:v + else + let val = {'_VAL': split(a:v, "\n", 1)} + end + + let ret = ['"'] + for v in val._VAL call add( \ret, \substitute( @@ -427,16 +433,6 @@ function s:msgpack_dump_string(v, ...) abort endfunction "" -" Dump binary string. -function s:msgpack_dump_binary(v) abort - if type(a:v) == type({}) - return s:msgpack_dump_string(a:v, 1) - else - return s:msgpack_dump_string({'_VAL': split(a:v, "\n", 1)}, 1) - endif -endfunction - -"" " Dump array value. function s:msgpack_dump_array(v) abort let val = type(a:v) == type({}) ? a:v._VAL : a:v @@ -449,7 +445,7 @@ function s:msgpack_dump_map(v) abort let ret = ['{'] if msgpack#special_type(a:v) is 0 for [k, v] in items(a:v) - let ret += [s:msgpack_dump_string({'_VAL': split(k, "\n", 1)}), + let ret += [s:msgpack_dump_string({'_VAL': split(k, "\n")}), \': ', \msgpack#string(v), \', '] @@ -479,7 +475,7 @@ endfunction " Dump extension value. function s:msgpack_dump_ext(v) abort return printf('+(%i)%s', a:v._VAL[0], - \s:msgpack_dump_string({'_VAL': a:v._VAL[1]}, 1)) + \s:msgpack_dump_string({'_VAL': a:v._VAL[1]})) endfunction "" @@ -619,9 +615,7 @@ function msgpack#eval(s, special_objs) abort throw '"-invalid:Invalid string: ' . s endif call add(expr, '{''_TYPE'': v:msgpack_types.') - if empty(match[1]) - call add(expr, 'binary') - elseif match[1] is# '=' + if empty(match[1]) || match[1] is# '=' call add(expr, 'string') else call add(expr, 'ext') @@ -772,7 +766,7 @@ function msgpack#equal(a, b) let a = aspecial is 0 ? a:a : a:a._VAL let b = bspecial is 0 ? a:b : a:b._VAL return msgpack#equal(a, b) - elseif atype is# 'binary' + elseif atype is# 'string' let a = (aspecial is 0 ? split(a:a, "\n", 1) : a:a._VAL) let b = (bspecial is 0 ? split(a:b, "\n", 1) : a:b._VAL) return a ==# b @@ -787,13 +781,17 @@ function msgpack#equal(a, b) " Non-special mapping cannot have non-string keys return 0 endif - if (empty(k._VAL) - \|| k._VAL ==# [""] - \|| !empty(filter(copy(k._VAL), 'stridx(v:val, "\n") != -1'))) - " Non-special mapping cannot have zero byte in key or an empty key - return 0 + if type(k) == type({}) + if (empty(k._VAL) + \|| k._VAL ==# [""] + \|| !empty(filter(copy(k._VAL), 'stridx(v:val, "\n") != -1'))) + " Non-special mapping cannot have zero byte in key or an empty key + return 0 + endif + let kstr = join(k._VAL, "\n") + else + let kstr = k endif - let kstr = join(k._VAL, "\n") if !has_key(akeys, kstr) " Protects from both missing and duplicate keys return 0 diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim index ae602c5be6..a96364fb4b 100644 --- a/runtime/autoload/netrw.vim +++ b/runtime/autoload/netrw.vim @@ -3,7 +3,7 @@ " Maintainer: This runtime file is looking for a new maintainer. " Date: May 03, 2023 " Version: 173a -" Last Change: +" Last Change: {{{1 " 2023 Nov 21 by Vim Project: ignore wildignore when expanding $COMSPEC (v173a) " 2023 Nov 22 by Vim Project: fix handling of very long filename on longlist style (v173a) " 2024 Feb 19 by Vim Project: (announce adoption) @@ -12,6 +12,21 @@ " 2024 May 08 by Vim Project: cleanup legacy Win9X checks " 2024 May 09 by Vim Project: remove hard-coded private.ppk " 2024 May 10 by Vim Project: recursively delete directories by default +" 2024 May 13 by Vim Project: prefer scp over pscp +" 2024 Jun 04 by Vim Project: set bufhidden if buffer changed, nohidden is set and buffer shall be switched (#14915) +" 2024 Jun 13 by Vim Project: glob() on Windows fails when a directory name contains [] (#14952) +" 2024 Jun 23 by Vim Project: save ad restore registers when liststyle = WIDELIST (#15077, #15114) +" 2024 Jul 22 by Vim Project: avoid endless recursion (#15318) +" 2024 Jul 23 by Vim Project: escape filename before trying to delete it (#15330) +" 2024 Jul 30 by Vim Project: handle mark-copy to same target directory (#12112) +" 2024 Aug 02 by Vim Project: honor g:netrw_alt{o,v} for :{S,H,V}explore (#15417) +" 2024 Aug 15 by Vim Project: style changes, prevent E121 (#15501) +" 2024 Aug 22 by Vim Project: fix mf-selection highlight (#15551) +" 2024 Aug 22 by Vim Project: adjust echo output of mx command (#15550) +" 2024 Sep 15 by Vim Project: more strict confirmation dialog (#15680) +" 2024 Sep 19 by Vim Project: mf-selection highlight uses wrong pattern (#15700) +" 2024 Sep 21 by Vim Project: remove extraneous closing bracket (#15718) +" }}} " Former Maintainer: Charles E Campbell " GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim " Copyright: Copyright (C) 2016 Charles E. Campbell {{{1 @@ -54,11 +69,6 @@ if exists("s:needspatches") endif let g:loaded_netrw = "v173" -if !exists("s:NOTE") - let s:NOTE = 0 - let s:WARNING = 1 - let s:ERROR = 2 -endif let s:keepcpo= &cpo setl cpo&vim @@ -96,7 +106,7 @@ fun! netrw#ErrorMsg(level,msg,errnum) endif " call Decho("level=".level,'~'.expand("<slnum>")) - if g:netrw_use_errorwindow == 2 && (v:version > 802 || (v:version == 802 && has("patch486"))) + if g:netrw_use_errorwindow == 2 && exists("*popup_atcursor") " use popup window if type(a:msg) == 3 let msg = [level]+a:msg @@ -212,6 +222,11 @@ if !exists("s:LONGLIST") call s:NetrwInit("s:MAXLIST" ,4) endif +let s:NOTE = 0 +let s:WARNING = 1 +let s:ERROR = 2 +call s:NetrwInit("g:netrw_errorlvl", s:NOTE) + " --------------------------------------------------------------------- " Default option values: {{{2 let g:netrw_localcopycmdopt = "" @@ -337,7 +352,6 @@ call s:NetrwInit("s:didstarstar",0) call s:NetrwInit("g:netrw_dirhistcnt" , 0) call s:NetrwInit("g:netrw_decompress" , '{ ".gz" : "gunzip", ".bz2" : "bunzip2", ".zip" : "unzip", ".tar" : "tar -xf", ".xz" : "unxz" }') call s:NetrwInit("g:netrw_dirhistmax" , 10) -call s:NetrwInit("g:netrw_errorlvl" , s:NOTE) call s:NetrwInit("g:netrw_fastbrowse" , 1) call s:NetrwInit("g:netrw_ftp_browse_reject", '^total\s\+\d\+$\|^Trying\s\+\d\+.*$\|^KERBEROS_V\d rejected\|^Security extensions not\|No such file\|: connect to address [0-9a-fA-F:]*: No route to host$') if !exists("g:netrw_ftp_list_cmd") @@ -688,12 +702,11 @@ fun! netrw#Explore(indx,dosplit,style,...) \ ((isdirectory(s:NetrwFile(a:1))))? 'is a directory' : 'is not a directory', \ '~'.expand("<slnum>")) if a:1 =~ "\\\s" && !filereadable(s:NetrwFile(a:1)) && !isdirectory(s:NetrwFile(a:1)) -" call Decho("re-trying Explore with <".substitute(a:1,'\\\(\s\)','\1','g').">",'~'.expand("<slnum>")) - call netrw#Explore(a:indx,a:dosplit,a:style,substitute(a:1,'\\\(\s\)','\1','g')) -" call Dret("netrw#Explore : returning from retry") - return -" else " Decho -" call Decho("retry not needed",'~'.expand("<slnum>")) + let a1 = substitute(a:1, '\\\(\s\)', '\1', 'g') + if a1 != a:1 + call netrw#Explore(a:indx, a:dosplit, a:style, a1) + return + endif endif endif @@ -704,7 +717,6 @@ fun! netrw#Explore(indx,dosplit,style,...) " -or- file has been modified AND file not hidden when abandoned " -or- Texplore used if a:dosplit || (&modified && &hidden == 0 && &bufhidden != "hide") || a:style == 6 -" call Decho("case dosplit=".a:dosplit." modified=".&modified." a:style=".a:style.": dosplit or file has been modified",'~'.expand("<slnum>")) call s:SaveWinVars() let winsz= g:netrw_winsize if a:indx > 0 @@ -712,57 +724,41 @@ fun! netrw#Explore(indx,dosplit,style,...) endif if a:style == 0 " Explore, Sexplore -" call Decho("style=0: Explore or Sexplore",'~'.expand("<slnum>")) let winsz= (winsz > 0)? (winsz*winheight(0))/100 : -winsz if winsz == 0|let winsz= ""|endif - exe "noswapfile ".winsz."wincmd s" -" call Decho("exe noswapfile ".winsz."wincmd s",'~'.expand("<slnum>")) + exe "noswapfile ".(g:netrw_alto ? "below " : "above ").winsz."wincmd s" - elseif a:style == 1 "Explore!, Sexplore! -" call Decho("style=1: Explore! or Sexplore!",'~'.expand("<slnum>")) + elseif a:style == 1 " Explore!, Sexplore! let winsz= (winsz > 0)? (winsz*winwidth(0))/100 : -winsz if winsz == 0|let winsz= ""|endif - exe "keepalt noswapfile ".winsz."wincmd v" -" call Decho("exe keepalt noswapfile ".winsz."wincmd v",'~'.expand("<slnum>")) + exe "keepalt noswapfile ".(g:netrw_altv ? "rightbelow " : "leftabove ").winsz."wincmd v" elseif a:style == 2 " Hexplore -" call Decho("style=2: Hexplore",'~'.expand("<slnum>")) let winsz= (winsz > 0)? (winsz*winheight(0))/100 : -winsz if winsz == 0|let winsz= ""|endif - exe "keepalt noswapfile bel ".winsz."wincmd s" -" call Decho("exe keepalt noswapfile bel ".winsz."wincmd s",'~'.expand("<slnum>")) + exe "keepalt noswapfile ".(g:netrw_alto ? "below " : "above ").winsz."wincmd s" elseif a:style == 3 " Hexplore! -" call Decho("style=3: Hexplore!",'~'.expand("<slnum>")) let winsz= (winsz > 0)? (winsz*winheight(0))/100 : -winsz if winsz == 0|let winsz= ""|endif - exe "keepalt noswapfile abo ".winsz."wincmd s" -" call Decho("exe keepalt noswapfile abo ".winsz."wincmd s",'~'.expand("<slnum>")) + exe "keepalt noswapfile ".(!g:netrw_alto ? "below " : "above ").winsz."wincmd s" elseif a:style == 4 " Vexplore -" call Decho("style=4: Vexplore",'~'.expand("<slnum>")) let winsz= (winsz > 0)? (winsz*winwidth(0))/100 : -winsz if winsz == 0|let winsz= ""|endif - exe "keepalt noswapfile lefta ".winsz."wincmd v" -" call Decho("exe keepalt noswapfile lefta ".winsz."wincmd v",'~'.expand("<slnum>")) + exe "keepalt noswapfile ".(g:netrw_altv ? "rightbelow " : "leftabove ").winsz."wincmd v" elseif a:style == 5 " Vexplore! -" call Decho("style=5: Vexplore!",'~'.expand("<slnum>")) let winsz= (winsz > 0)? (winsz*winwidth(0))/100 : -winsz if winsz == 0|let winsz= ""|endif - exe "keepalt noswapfile rightb ".winsz."wincmd v" -" call Decho("exe keepalt noswapfile rightb ".winsz."wincmd v",'~'.expand("<slnum>")) + exe "keepalt noswapfile ".(!g:netrw_altv ? "rightbelow " : "leftabove ").winsz."wincmd v" elseif a:style == 6 " Texplore call s:SaveBufVars() -" call Decho("style = 6: Texplore",'~'.expand("<slnum>")) exe "keepalt tabnew ".fnameescape(curdir) -" call Decho("exe keepalt tabnew ".fnameescape(curdir),'~'.expand("<slnum>")) call s:RestoreBufVars() endif call s:RestoreWinVars() -" else " Decho -" call Decho("case a:dosplit=".a:dosplit." AND modified=".&modified." AND a:style=".a:style." is not 6",'~'.expand("<slnum>")) endif NetrwKeepj norm! 0 @@ -4188,7 +4184,7 @@ fun! s:NetrwGetBuffer(islocal,dirname) endif " call Decho(" NetrwTreeListing: bufnum#".bufnum,'~'.expand("<slnum>")) if !bufexists(bufnum) - call remove(s:netrwbuf,"NetrwTreeListing"]) + call remove(s:netrwbuf,"NetrwTreeListing") let bufnum= -1 endif elseif bufnr("NetrwTreeListing") != -1 @@ -4446,7 +4442,15 @@ fun! s:NetrwGetWord() call cursor(line("."),filestart+1) NetrwKeepj norm! ma endif - let rega= @a + + let dict={} + " save the unnamed register and register 0-9 and a + let dict.a=[getreg('a'), getregtype('a')] + for i in range(0, 9) + let dict[i] = [getreg(i), getregtype(i)] + endfor + let dict.unnamed = [getreg(''), getregtype('')] + let eofname= filestart + b:netrw_cpf + 1 if eofname <= col("$") call cursor(line("."),filestart+b:netrw_cpf+1) @@ -4454,8 +4458,10 @@ fun! s:NetrwGetWord() else NetrwKeepj norm! "ay$ endif + let dirname = @a - let @a = rega + call s:RestoreRegister(dict) + " call Decho("2: dirname<".dirname.">",'~'.expand("<slnum>")) let dirname= substitute(dirname,'\s\+$','','e') " call Decho("3: dirname<".dirname.">",'~'.expand("<slnum>")) @@ -5523,13 +5529,12 @@ endfun " --------------------------------------------------------------------- " netrw#BrowseXVis: used by gx in visual mode to select a file for browsing {{{2 fun! netrw#BrowseXVis() -" call Dfunc("netrw#BrowseXVis()") - let akeep = @a + let dict={} + let dict.a=[getreg('a'), getregtype('a')] norm! gv"ay let gxfile= @a - let @a = akeep + call s:RestoreRegister(dict) call netrw#BrowseX(gxfile,netrw#CheckIfRemote(gxfile)) -" call Dret("netrw#BrowseXVis") endfun " --------------------------------------------------------------------- @@ -5681,6 +5686,9 @@ fun! s:NetrwEditFile(cmd,opt,fname) exe "NetrwKeepj keepalt ".a:opt." ".a:cmd." ".fnameescape(a:fname) else " call Decho("exe NetrwKeepj ".a:opt." ".a:cmd." ".fnameescape(a:fname)) + if a:cmd =~# 'e\%[new]!' && !&hidden && getbufvar(bufname('%'), '&modified', 0) + call setbufvar(bufname('%'), '&bufhidden', 'hide') + endif exe "NetrwKeepj ".a:opt." ".a:cmd." ".fnameescape(a:fname) endif " call Dret("s:NetrwEditFile") @@ -5751,16 +5759,20 @@ fun! s:NetrwGlob(direntry,expr,pare) let filelist= w:netrw_treedict[a:direntry] endif let w:netrw_liststyle= keep_liststyle - elseif v:version > 704 || (v:version == 704 && has("patch656")) - let filelist= glob(s:ComposePath(fnameescape(a:direntry),a:expr),0,1,1) - if a:pare - let filelist= map(filelist,'substitute(v:val, "^.*/", "", "")') - endif else - let filelist= glob(s:ComposePath(fnameescape(a:direntry),a:expr),0,1) - if a:pare - let filelist= map(filelist,'substitute(v:val, "^.*/", "", "")') - endif + let path= s:ComposePath(fnameescape(a:direntry),a:expr) + if has("win32") + " escape [ so it is not detected as wildcard character, see :h wildcard + let path= substitute(path, '[', '[[]', 'g') + endif + if v:version > 704 || (v:version == 704 && has("patch656")) + let filelist= glob(path,0,1,1) + else + let filelist= glob(path,0,1) + endif + if a:pare + let filelist= map(filelist,'substitute(v:val, "^.*/", "", "")') + endif endif " call Dret("s:NetrwGlob ".string(filelist)) return filelist @@ -6817,11 +6829,7 @@ fun! s:NetrwMarkFile(islocal,fname) let ykeep = @@ let curbufnr= bufnr("%") - if a:fname =~ '^\a' - let leader= '\<' - else - let leader= '' - endif + let leader= '\%(^\|\s\)\zs' if a:fname =~ '\a$' let trailer = '\>[@=|\/\*]\=\ze\%( \|\t\|$\)' else @@ -7084,7 +7092,7 @@ fun! s:NetrwMarkFileCopy(islocal,...) endif " copy marked files while within the same directory (ie. allow renaming) - if simplify(s:netrwmftgt) == simplify(b:netrw_curdir) + if s:StripTrailingSlash(simplify(s:netrwmftgt)) == s:StripTrailingSlash(simplify(b:netrw_curdir)) if len(s:netrwmarkfilelist_{bufnr('%')}) == 1 " only one marked file " call Decho("case: only one marked file",'~'.expand("<slnum>")) @@ -7161,7 +7169,7 @@ fun! s:NetrwMarkFileCopy(islocal,...) " call Decho("system(".copycmd." '".args."' '".tgt."')",'~'.expand("<slnum>")) call system(copycmd.g:netrw_localcopycmdopt." '".args."' '".tgt."'") if v:shell_error != 0 - if exists("b:netrw_curdir") && b:netrw_curdir != getcwd() && !g:netrw_keepdir + if exists("b:netrw_curdir") && b:netrw_curdir != getcwd() && g:netrw_keepdir call netrw#ErrorMsg(s:ERROR,"copy failed; perhaps due to vim's current directory<".getcwd()."> not matching netrw's (".b:netrw_curdir.") (see :help netrw-cd)",101) else call netrw#ErrorMsg(s:ERROR,"tried using g:netrw_localcopycmd<".g:netrw_localcopycmd.">; it doesn't work!",80) @@ -7430,7 +7438,13 @@ fun! s:NetrwMarkFileExe(islocal,enbloc) NetrwKeepj call netrw#ErrorMsg(s:ERROR,"command<".xcmd."> failed, aborting",54) break else - echo ret + if ret !=# '' + echo "\n" + " skip trailing new line + echo ret[0:-2] + else + echo ret + endif endif endfor @@ -9669,7 +9683,13 @@ fun! s:NetrwWideListing() " fpl: filenames per line " fpc: filenames per column setl ma noro - let keepa= @a + let dict={} + " save the unnamed register and register 0-9 and a + let dict.a=[getreg('a'), getregtype('a')] + for i in range(0, 9) + let dict[i] = [getreg(i), getregtype(i)] + endfor + let dict.unnamed = [getreg(''), getregtype('')] " call Decho("setl ma noro",'~'.expand("<slnum>")) let b:netrw_cpf= 0 if line("$") >= w:netrw_bannercnt @@ -9677,7 +9697,8 @@ fun! s:NetrwWideListing() exe 'sil NetrwKeepj '.w:netrw_bannercnt.',$g/^./if virtcol("$") > b:netrw_cpf|let b:netrw_cpf= virtcol("$")|endif' NetrwKeepj call histdel("/",-1) else - let @a= keepa + " restore stored registers + call s:RestoreRegister(dict) " call Dret("NetrwWideListing") return endif @@ -9719,7 +9740,7 @@ fun! s:NetrwWideListing() exe 'nno <buffer> <silent> b :call search(''^.\\|\s\s\zs\S'',''bW'')'."\<cr>" " call Decho("NetrwWideListing) setl noma nomod ro",'~'.expand("<slnum>")) exe "setl ".g:netrw_bufsettings - let @a= keepa + call s:RestoreRegister(dict) " call Decho("ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>")) " call Dret("NetrwWideListing") return @@ -9731,7 +9752,6 @@ fun! s:NetrwWideListing() sil! nunmap <buffer> b endif endif - endfun " --------------------------------------------------------------------- @@ -10052,7 +10072,8 @@ fun! s:SetupNetrwStatusLine(statline) endif " set up User9 highlighting as needed - let keepa= @a + let dict={} + let dict.a=[getreg('a'), getregtype('a')] redir @a try hi User9 @@ -10064,7 +10085,7 @@ fun! s:SetupNetrwStatusLine(statline) endif endtry redir END - let @a= keepa + call s:RestoreRegister(dict) endif " set up status line (may use User9 highlighting) @@ -11257,7 +11278,7 @@ fun! s:NetrwLocalRm(path) range let ok= s:NetrwLocalRmFile(a:path,fname,all) if ok =~# 'q\%[uit]' || ok == "no" break - elseif ok =~# 'a\%[ll]' + elseif ok =~# '^a\%[ll]$' let all= 1 endif endfor @@ -11286,7 +11307,7 @@ fun! s:NetrwLocalRm(path) range let ok= s:NetrwLocalRmFile(a:path,curword,all) if ok =~# 'q\%[uit]' || ok == "no" break - elseif ok =~# 'a\%[ll]' + elseif ok =~# '^a\%[ll]$' let all= 1 endif let ctr= ctr + 1 @@ -11315,7 +11336,7 @@ fun! s:NetrwLocalRmFile(path,fname,all) let all= a:all let ok = "" NetrwKeepj norm! 0 - let rmfile= s:NetrwFile(s:ComposePath(a:path,a:fname)) + let rmfile= s:NetrwFile(s:ComposePath(a:path,escape(a:fname, '\\'))) " call Decho("rmfile<".rmfile.">",'~'.expand("<slnum>")) if rmfile !~ '^"' && (rmfile =~ '@$' || rmfile !~ '[\/]$') @@ -11324,7 +11345,7 @@ fun! s:NetrwLocalRmFile(path,fname,all) if !all echohl Statement call inputsave() - let ok= input("Confirm deletion of file<".rmfile."> ","[{y(es)},n(o),a(ll),q(uit)] ") + let ok= input("Confirm deletion of file <".rmfile."> ","[{y(es)},n(o),a(ll),q(uit)] ") call inputrestore() echohl NONE if ok == "" @@ -11333,12 +11354,12 @@ fun! s:NetrwLocalRmFile(path,fname,all) " call Decho("response: ok<".ok.">",'~'.expand("<slnum>")) let ok= substitute(ok,'\[{y(es)},n(o),a(ll),q(uit)]\s*','','e') " call Decho("response: ok<".ok."> (after sub)",'~'.expand("<slnum>")) - if ok =~# 'a\%[ll]' + if ok =~# '^a\%[ll]$' let all= 1 endif endif - if all || ok =~# 'y\%[es]' || ok == "" + if all || ok =~# '^y\%[es]$' || ok == "" let ret= s:NetrwDelete(rmfile) " call Decho("errcode=".v:shell_error." ret=".ret,'~'.expand("<slnum>")) endif @@ -11348,19 +11369,19 @@ fun! s:NetrwLocalRmFile(path,fname,all) if !all echohl Statement call inputsave() - let ok= input("Confirm *recursive* deletion of directory<".rmfile."> ","[{y(es)},n(o),a(ll),q(uit)] ") + let ok= input("Confirm *recursive* deletion of directory <".rmfile."> ","[{y(es)},n(o),a(ll),q(uit)] ") call inputrestore() let ok= substitute(ok,'\[{y(es)},n(o),a(ll),q(uit)]\s*','','e') if ok == "" let ok="no" endif - if ok =~# 'a\%[ll]' + if ok =~# '^a\%[ll]$' let all= 1 endif endif let rmfile= substitute(rmfile,'[\/]$','','e') - if all || ok =~# 'y\%[es]' || ok == "" + if all || ok =~# '^y\%[es]$' || ok == "" if delete(rmfile,"rf") call netrw#ErrorMsg(s:ERROR,"unable to delete directory <".rmfile.">!",103) endif @@ -11508,6 +11529,13 @@ fun! netrw#WinPath(path) endfun " --------------------------------------------------------------------- +" s:StripTrailingSlash: removes trailing slashes from a path {{{2 +fun! s:StripTrailingSlash(path) + " remove trailing slash + return substitute(a:path, '[/\\]$', '', 'g') +endfun + +" --------------------------------------------------------------------- " s:NetrwBadd: adds marked files to buffer list or vice versa {{{2 " cb : bl2mf=0 add marked files to buffer list " cB : bl2mf=1 use bufferlist to mark files @@ -11874,6 +11902,16 @@ fun! s:RestoreCursorline() " call Dret("s:RestoreCursorline : restored cul=".&l:cursorline." cuc=".&l:cursorcolumn) endfun +" s:RestoreRegister: restores all registers given in the dict {{{2 +fun! s:RestoreRegister(dict) + for [key, val] in items(a:dict) + if key == 'unnamed' + let key = '' + endif + call setreg(key, val[0], val[1]) + endfor +endfun + " --------------------------------------------------------------------- " s:NetrwDelete: Deletes a file. {{{2 " Uses Steve Hall's idea to insure that Windows paths stay @@ -12681,54 +12719,3 @@ unlet s:keepcpo " Modelines: {{{1 " =============== " vim:ts=8 fdm=marker -" doing autoload/netrw.vim version v172g ~57 -" varname<g:netrw_dirhistcnt> value=0 ~1 -" varname<s:THINLIST> value=0 ~1 -" varname<s:LONGLIST> value=1 ~1 -" varname<s:WIDELIST> value=2 ~1 -" varname<s:TREELIST> value=3 ~1 -" varname<s:MAXLIST> value=4 ~1 -" varname<g:netrw_use_errorwindow> value=2 ~1 -" varname<g:netrw_http_xcmd> value=-q -O ~1 -" varname<g:netrw_http_put_cmd> value=curl -T ~1 -" varname<g:netrw_keepj> value=keepj ~1 -" varname<g:netrw_rcp_cmd> value=rcp ~1 -" varname<g:netrw_rsync_cmd> value=rsync ~1 -" varname<g:netrw_rsync_sep> value=/ ~1 -" varname<g:netrw_scp_cmd> value=scp -q ~1 -" varname<g:netrw_sftp_cmd> value=sftp ~1 -" varname<g:netrw_ssh_cmd> value=ssh ~1 -" varname<g:netrw_alto> value=0 ~1 -" varname<g:netrw_altv> value=1 ~1 -" varname<g:netrw_banner> value=1 ~1 -" varname<g:netrw_browse_split> value=0 ~1 -" varname<g:netrw_bufsettings> value=noma nomod nonu nobl nowrap ro nornu ~1 -" varname<g:netrw_chgwin> value=-1 ~1 -" varname<g:netrw_clipboard> value=1 ~1 -" varname<g:netrw_compress> value=gzip ~1 -" varname<g:netrw_ctags> value=ctags ~1 -" varname<g:netrw_cursor> value=2 ~1 -" (netrw) COMBAK: cuc=0 cul=0 initialization of s:netrw_cu[cl] -" varname<g:netrw_cygdrive> value=/cygdrive ~1 -" varname<s:didstarstar> value=0 ~1 -" varname<g:netrw_dirhistcnt> value=0 ~1 -" varname<g:netrw_decompress> value={ ".gz" : "gunzip", ".bz2" : "bunzip2", ".zip" : "unzip", ".tar" : "tar -xf", ".xz" : "unxz" } ~1 -" varname<g:netrw_dirhistmax> value=10 ~1 -" varname<g:netrw_errorlvl> value=0 ~1 -" varname<g:netrw_fastbrowse> value=1 ~1 -" varname<g:netrw_ftp_browse_reject> value=^total\s\+\d\+$\|^Trying\s\+\d\+.*$\|^KERBEROS_V\d rejected\|^Security extensions not\|No such file\|: connect to address [0-9a-fA-F:]*: No route to host$ ~1 -" varname<g:netrw_ftpmode> value=binary ~1 -" varname<g:netrw_hide> value=1 ~1 -" varname<g:netrw_keepdir> value=1 ~1 -" varname<g:netrw_list_hide> value= ~1 -" varname<g:netrw_localmkdir> value=mkdir ~1 -" varname<g:netrw_remote_mkdir> value=mkdir ~1 -" varname<g:netrw_liststyle> value=0 ~1 -" varname<g:netrw_markfileesc> value=*./[\~ ~1 -" varname<g:netrw_maxfilenamelen> value=32 ~1 -" varname<g:netrw_menu> value=1 ~1 -" varname<g:netrw_mkdir_cmd> value=ssh USEPORT HOSTNAME mkdir ~1 -" varname<g:netrw_mousemaps> value=1 ~1 -" varname<g:netrw_retmap> value=0 ~1 -" varname<g:netrw_chgperm> value=chmod PERM FILENAME ~1 -" varname<g:netrw_preview> value=0 ~1 diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim index 82e0953196..58d3d4550f 100644 --- a/runtime/autoload/provider/clipboard.vim +++ b/runtime/autoload/provider/clipboard.vim @@ -140,6 +140,18 @@ function! provider#clipboard#Executable() abort let s:copy['*'] = s:copy['+'] let s:paste['*'] = s:paste['+'] return 'win32yank' + elseif executable('putclip') && executable('getclip') + let s:copy['+'] = ['putclip'] + let s:paste['+'] = ['getclip'] + let s:copy['*'] = s:copy['+'] + let s:paste['*'] = s:paste['+'] + return 'putclip' + elseif executable('clip') && executable('powershell') + let s:copy['+'] = ['clip'] + let s:paste['+'] = ['powershell', '-NoProfile', '-NoLogo', '-Command', 'Get-Clipboard'] + let s:copy['*'] = s:copy['+'] + let s:paste['*'] = s:paste['+'] + return 'clip' elseif executable('termux-clipboard-set') let s:copy['+'] = ['termux-clipboard-set'] let s:paste['+'] = ['termux-clipboard-get'] diff --git a/runtime/autoload/shada.vim b/runtime/autoload/shada.vim index ae718ad2e7..4753973196 100644 --- a/runtime/autoload/shada.vim +++ b/runtime/autoload/shada.vim @@ -230,7 +230,7 @@ function s:shada_check_type(type, val) abort return 0 elseif a:type is# 'bin' " Binary string without zero bytes - if type isnot# 'binary' + if type isnot# 'string' return 'Expected binary string' elseif (type(a:val) == type({}) \&& !empty(filter(copy(a:val._VAL), 'stridx(v:val, "\n") != -1'))) @@ -247,7 +247,7 @@ function s:shada_check_type(type, val) abort if type isnot# 'array' return 'Expected array value' elseif !empty(filter(copy(type(a:val) == type({}) ? a:val._VAL : a:val), - \'msgpack#type(v:val) isnot# "binary"')) + \'msgpack#type(v:val) isnot# "string"')) return 'Expected array of binary strings' else for element in (type(a:val) == type({}) ? a:val._VAL : a:val) diff --git a/runtime/autoload/typst.vim b/runtime/autoload/typst.vim new file mode 100644 index 0000000000..55edd23928 --- /dev/null +++ b/runtime/autoload/typst.vim @@ -0,0 +1,50 @@ +" Language: Typst +" Maintainer: Gregory Anders +" Last Change: 2024-07-14 +" Based on: https://github.com/kaarmu/typst.vim + +function! typst#indentexpr() abort + let l:lnum = v:lnum + let s:sw = shiftwidth() + + let [l:plnum, l:pline] = s:get_prev_nonblank(l:lnum - 1) + if l:plnum == 0 | return 0 | endif + + let l:line = getline(l:lnum) + let l:ind = indent(l:plnum) + + let l:synname = synIDattr(synID(l:lnum, 1, 1), 'name') + + " Use last indent for block comments + if l:synname == 'typstCommentBlock' + return l:ind + endif + + if l:pline =~ '\v[{[(]\s*$' + let l:ind += s:sw + endif + + if l:line =~ '\v^\s*[}\])]' + let l:ind -= s:sw + endif + + return l:ind +endfunction + +" Gets the previous non-blank line that is not a comment. +function! s:get_prev_nonblank(lnum) abort + let l:lnum = prevnonblank(a:lnum) + let l:line = getline(l:lnum) + + while l:lnum > 0 && l:line =~ '^\s*//' + let l:lnum = prevnonblank(l:lnum - 1) + let l:line = getline(l:lnum) + endwhile + + return [l:lnum, s:remove_comments(l:line)] +endfunction + +" Removes comments from the given line. +function! s:remove_comments(line) abort + return substitute(a:line, '\s*//.*', '', '') +endfunction diff --git a/runtime/autoload/zip.vim b/runtime/autoload/zip.vim index c0034f8a7a..172de98d36 100644 --- a/runtime/autoload/zip.vim +++ b/runtime/autoload/zip.vim @@ -1,36 +1,38 @@ " zip.vim: Handles browsing zipfiles -" AUTOLOAD PORTION -" Date: Mar 12, 2023 -" Version: 33 +" AUTOLOAD PORTION +" Date: 2024 Aug 21 +" Version: 34 " Maintainer: This runtime file is looking for a new maintainer. " Former Maintainer: Charles E Campbell +" Last Change: +" 2024 Jun 16 by Vim Project: handle whitespace on Windows properly (#14998) +" 2024 Jul 23 by Vim Project: fix 'x' command +" 2024 Jul 24 by Vim Project: use delete() function +" 2024 Jul 30 by Vim Project: fix opening remote zipfile +" 2024 Aug 04 by Vim Project: escape '[' in name of file to be extracted +" 2024 Aug 05 by Vim Project: workaround for the FreeBSD's unzip +" 2024 Aug 05 by Vim Project: clean-up and make it work with shellslash on Windows +" 2024 Aug 18 by Vim Project: correctly handle special globbing chars +" 2024 Aug 21 by Vim Project: simplify condition to detect MS-Windows " License: Vim License (see vim's :help license) -" Copyright: Copyright (C) 2005-2019 Charles E. Campbell {{{1 -" Permission is hereby granted to use and distribute this code, -" with or without modifications, provided that this copyright -" notice is copied with it. Like anything else that's free, -" zip.vim and zipPlugin.vim are provided *as is* and comes with -" no warranty of any kind, either expressed or implied. By using -" this plugin, you agree that in no event will the copyright -" holder be liable for any damages resulting from the use -" of this software. -"redraw!|call DechoSep()|call inputsave()|call input("Press <cr> to continue")|call inputrestore() +" Copyright: Copyright (C) 2005-2019 Charles E. Campbell {{{1 +" Permission is hereby granted to use and distribute this code, +" with or without modifications, provided that this copyright +" notice is copied with it. Like anything else that's free, +" zip.vim and zipPlugin.vim are provided *as is* and comes with +" no warranty of any kind, either expressed or implied. By using +" this plugin, you agree that in no event will the copyright +" holder be liable for any damages resulting from the use +" of this software. " --------------------------------------------------------------------- " Load Once: {{{1 if &cp || exists("g:loaded_zip") finish endif -let g:loaded_zip= "v33" -if v:version < 702 - echohl WarningMsg - echo "***warning*** this version of zip needs vim 7.2 or later" - echohl Normal - finish -endif +let g:loaded_zip= "v34" let s:keepcpo= &cpo set cpo&vim -"DechoTabOn let s:zipfile_escape = ' ?&;\' let s:ERROR = 2 @@ -58,8 +60,27 @@ if !exists("g:zip_extractcmd") let g:zip_extractcmd= g:zip_unzipcmd endif +" --------------------------------------------------------------------- +" required early +" s:Mess: {{{2 +fun! s:Mess(group, msg) + redraw! + exe "echohl " . a:group + echomsg a:msg + echohl Normal +endfun + +if v:version < 702 + call s:Mess('WarningMsg', "***warning*** this version of zip needs vim 7.2 or later") + finish +endif +" sanity checks +if !executable(g:zip_unzipcmd) + call s:Mess('Error', "***error*** (zip#Browse) unzip not available on your system") + finish +endif if !dist#vim#IsSafeExecutable('zip', g:zip_unzipcmd) - echoerr "Warning: NOT executing " .. g:zip_unzipcmd .. " from current directory!" + call s:Mess('Error', "Warning: NOT executing " .. g:zip_unzipcmd .. " from current directory!") finish endif @@ -70,47 +91,28 @@ endif " --------------------------------------------------------------------- " zip#Browse: {{{2 fun! zip#Browse(zipfile) -" call Dfunc("zip#Browse(zipfile<".a:zipfile.">)") - " sanity check: insure that the zipfile has "PK" as its first two letters - " (zipped files have a leading PK as a "magic cookie") - if !filereadable(a:zipfile) || readfile(a:zipfile, "", 1)[0] !~ '^PK' - exe "noswapfile noautocmd noswapfile e ".fnameescape(a:zipfile) -" call Dret("zip#Browse : not a zipfile<".a:zipfile.">") + " sanity check: ensure that the zipfile has "PK" as its first two letters + " (zip files have a leading PK as a "magic cookie") + if filereadable(a:zipfile) && readblob(a:zipfile, 0, 2) != 0z50.4B + exe "noswapfile noautocmd e " .. fnameescape(a:zipfile) return -" else " Decho -" call Decho("zip#Browse: a:zipfile<".a:zipfile."> passed PK test - it's a zip file") endif - let repkeep= &report - set report=10 + let dict = s:SetSaneOpts() + defer s:RestoreOpts(dict) " sanity checks - if !exists("*fnameescape") - if &verbose > 1 - echoerr "the zip plugin is not available (your vim doesn't support fnameescape())" - endif - return - endif if !executable(g:zip_unzipcmd) - redraw! - echohl Error | echo "***error*** (zip#Browse) unzip not available on your system" -" call inputsave()|call input("Press <cr> to continue")|call inputrestore() - let &report= repkeep -" call Dret("zip#Browse") + call s:Mess('Error', "***error*** (zip#Browse) unzip not available on your system") return endif if !filereadable(a:zipfile) if a:zipfile !~# '^\a\+://' " if it's an url, don't complain, let url-handlers such as vim do its thing - redraw! - echohl Error | echo "***error*** (zip#Browse) File not readable<".a:zipfile.">" | echohl None -" call inputsave()|call input("Press <cr> to continue")|call inputrestore() + call s:Mess('Error', "***error*** (zip#Browse) File not readable <".a:zipfile.">") endif - let &report= repkeep -" call Dret("zip#Browse : file<".a:zipfile."> not readable") return endif -" call Decho("passed sanity checks") if &ma != 1 set ma endif @@ -135,19 +137,15 @@ fun! zip#Browse(zipfile) \ '" Select a file with cursor and press ENTER']) keepj $ -" call Decho("exe silent r! ".g:zip_unzipcmd." -l -- ".s:Escape(a:zipfile,1)) - exe "keepj sil! r! ".g:zip_unzipcmd." -Z -1 -- ".s:Escape(a:zipfile,1) + exe $"keepj sil r! {g:zip_unzipcmd} -Z1 -- {s:Escape(a:zipfile, 1)}" if v:shell_error != 0 - redraw! - echohl WarningMsg | echo "***warning*** (zip#Browse) ".fnameescape(a:zipfile)." is not a zip file" | echohl None -" call inputsave()|call input("Press <cr> to continue")|call inputrestore() + call s:Mess('WarningMsg', "***warning*** (zip#Browse) ".fnameescape(a:zipfile)." is not a zip file") keepj sil! %d let eikeep= &ei set ei=BufReadCmd,FileReadCmd exe "keepj r ".fnameescape(a:zipfile) let &ei= eikeep keepj 1d -" call Dret("zip#Browse") return endif @@ -159,64 +157,46 @@ fun! zip#Browse(zipfile) noremap <silent> <buffer> <leftmouse> <leftmouse>:call <SID>ZipBrowseSelect()<cr> endif - let &report= repkeep -" call Dret("zip#Browse") endfun " --------------------------------------------------------------------- " ZipBrowseSelect: {{{2 fun! s:ZipBrowseSelect() - " call Dfunc("ZipBrowseSelect() zipfile<".((exists("b:zipfile"))? b:zipfile : "n/a")."> curfile<".expand("%").">") - let repkeep= &report - set report=10 + let dict = s:SetSaneOpts() + defer s:RestoreOpts(dict) let fname= getline(".") if !exists("b:zipfile") -" call Dret("ZipBrowseSelect : b:zipfile doesn't exist!") return endif " sanity check if fname =~ '^"' - let &report= repkeep -" call Dret("ZipBrowseSelect") return endif if fname =~ '/$' - redraw! - echohl Error | echo "***error*** (zip#Browse) Please specify a file, not a directory" | echohl None -" call inputsave()|call input("Press <cr> to continue")|call inputrestore() - let &report= repkeep -" call Dret("ZipBrowseSelect") + call s:Mess('Error', "***error*** (zip#Browse) Please specify a file, not a directory") return endif -" call Decho("fname<".fname.">") - " get zipfile to the new-window let zipfile = b:zipfile let curfile = expand("%") -" call Decho("zipfile<".zipfile.">") -" call Decho("curfile<".curfile.">") noswapfile new if !exists("g:zip_nomax") || g:zip_nomax == 0 wincmd _ endif let s:zipfile_{winnr()}= curfile -" call Decho("exe e ".fnameescape("zipfile://".zipfile.'::'.fname)) exe "noswapfile e ".fnameescape("zipfile://".zipfile.'::'.fname) filetype detect - let &report= repkeep -" call Dret("ZipBrowseSelect : s:zipfile_".winnr()."<".s:zipfile_{winnr()}.">") endfun " --------------------------------------------------------------------- " zip#Read: {{{2 fun! zip#Read(fname,mode) -" call Dfunc("zip#Read(fname<".a:fname.">,mode=".a:mode.")") - let repkeep= &report - set report=10 + let dict = s:SetSaneOpts() + defer s:RestoreOpts(dict) if has("unix") let zipfile = substitute(a:fname,'zipfile://\(.\{-}\)::[^\\].*$','\1','') @@ -224,28 +204,20 @@ fun! zip#Read(fname,mode) else let zipfile = substitute(a:fname,'^.\{-}zipfile://\(.\{-}\)::[^\\].*$','\1','') let fname = substitute(a:fname,'^.\{-}zipfile://.\{-}::\([^\\].*\)$','\1','') - let fname = substitute(fname, '[', '[[]', 'g') endif -" call Decho("zipfile<".zipfile.">") -" call Decho("fname <".fname.">") + let fname = fname->substitute('[', '[[]', 'g')->escape('?*\\') " sanity check if !executable(substitute(g:zip_unzipcmd,'\s\+.*$','','')) - redraw! - echohl Error | echo "***error*** (zip#Read) sorry, your system doesn't appear to have the ".g:zip_unzipcmd." program" | echohl None -" call inputsave()|call input("Press <cr> to continue")|call inputrestore() - let &report= repkeep -" call Dret("zip#Write") + call s:Mess('Error', "***error*** (zip#Read) sorry, your system doesn't appear to have the ".g:zip_unzipcmd." program") return endif " the following code does much the same thing as - " exe "keepj sil! r! ".g:zip_unzipcmd." -p -- ".s:Escape(zipfile,1)." ".s:Escape(fnameescape(fname),1) + " exe "keepj sil! r! ".g:zip_unzipcmd." -p -- ".s:Escape(zipfile,1)." ".s:Escape(fname,1) " but allows zipfile://... entries in quickfix lists let temp = tempname() -" call Decho("using temp file<".temp.">") let fn = expand('%:p') - exe "sil! !".g:zip_unzipcmd." -p -- ".s:Escape(zipfile,1)." ".s:Escape(fnameescape(fname),1).' > '.temp -" call Decho("exe sil! !".g:zip_unzipcmd." -p -- ".s:Escape(zipfile,1)." ".s:Escape(fnameescape(fname),1).' > '.temp) + exe "sil !".g:zip_unzipcmd." -p -- ".s:Escape(zipfile,1)." ".s:Escape(fname,1).' > '.temp sil exe 'keepalt file '.temp sil keepj e! sil exe 'keepalt file '.fnameescape(fn) @@ -254,62 +226,44 @@ fun! zip#Read(fname,mode) filetype detect " cleanup - " keepj 0d " used to be needed for the ...r! ... method set nomod - let &report= repkeep -" call Dret("zip#Read") endfun " --------------------------------------------------------------------- " zip#Write: {{{2 fun! zip#Write(fname) -" call Dfunc("zip#Write(fname<".a:fname.">) zipfile_".winnr()."<".s:zipfile_{winnr()}.">") - let repkeep= &report - set report=10 + let dict = s:SetSaneOpts() + defer s:RestoreOpts(dict) " sanity checks if !executable(substitute(g:zip_zipcmd,'\s\+.*$','','')) - redraw! - echohl Error | echo "***error*** (zip#Write) sorry, your system doesn't appear to have the ".g:zip_zipcmd." program" | echohl None -" call inputsave()|call input("Press <cr> to continue")|call inputrestore() - let &report= repkeep -" call Dret("zip#Write") + call s:Mess('Error', "***error*** (zip#Write) sorry, your system doesn't appear to have the ".g:zip_zipcmd." program") return endif if !exists("*mkdir") - redraw! - echohl Error | echo "***error*** (zip#Write) sorry, mkdir() doesn't work on your system" | echohl None -" call inputsave()|call input("Press <cr> to continue")|call inputrestore() - let &report= repkeep -" call Dret("zip#Write") + call s:Mess('Error', "***error*** (zip#Write) sorry, mkdir() doesn't work on your system") return endif let curdir= getcwd() let tmpdir= tempname() -" call Decho("orig tempname<".tmpdir.">") if tmpdir =~ '\.' let tmpdir= substitute(tmpdir,'\.[^.]*$','','e') endif -" call Decho("tmpdir<".tmpdir.">") call mkdir(tmpdir,"p") " attempt to change to the indicated directory if s:ChgDir(tmpdir,s:ERROR,"(zip#Write) cannot cd to temporary directory") - let &report= repkeep -" call Dret("zip#Write") return endif -" call Decho("current directory now: ".getcwd()) " place temporary files under .../_ZIPVIM_/ if isdirectory("_ZIPVIM_") - call s:Rmdir("_ZIPVIM_") + call delete("_ZIPVIM_", "rf") endif call mkdir("_ZIPVIM_") cd _ZIPVIM_ -" call Decho("current directory now: ".getcwd()) if has("unix") let zipfile = substitute(a:fname,'zipfile://\(.\{-}\)::[^\\].*$','\1','') @@ -318,21 +272,17 @@ fun! zip#Write(fname) let zipfile = substitute(a:fname,'^.\{-}zipfile://\(.\{-}\)::[^\\].*$','\1','') let fname = substitute(a:fname,'^.\{-}zipfile://.\{-}::\([^\\].*\)$','\1','') endif -" call Decho("zipfile<".zipfile.">") -" call Decho("fname <".fname.">") if fname =~ '/' let dirpath = substitute(fname,'/[^/]\+$','','e') if has("win32unix") && executable("cygpath") let dirpath = substitute(system("cygpath ".s:Escape(dirpath,0)),'\n','','e') endif -" call Decho("mkdir(dirpath<".dirpath.">,p)") call mkdir(dirpath,"p") endif if zipfile !~ '/' let zipfile= curdir.'/'.zipfile endif -" call Decho("zipfile<".zipfile."> fname<".fname.">") exe "w! ".fnameescape(fname) if has("win32unix") && executable("cygpath") @@ -343,17 +293,13 @@ fun! zip#Write(fname) let fname = substitute(fname, '[', '[[]', 'g') endif -" call Decho(g:zip_zipcmd." -u ".s:Escape(fnamemodify(zipfile,":p"),0)." ".s:Escape(fname,0)) call system(g:zip_zipcmd." -u ".s:Escape(fnamemodify(zipfile,":p"),0)." ".s:Escape(fname,0)) if v:shell_error != 0 - redraw! - echohl Error | echo "***error*** (zip#Write) sorry, unable to update ".zipfile." with ".fname | echohl None -" call inputsave()|call input("Press <cr> to continue")|call inputrestore() + call s:Mess('Error', "***error*** (zip#Write) sorry, unable to update ".zipfile." with ".fname) elseif s:zipfile_{winnr()} =~ '^\a\+://' " support writing zipfiles across a network let netzipfile= s:zipfile_{winnr()} -" call Decho("handle writing <".zipfile."> across network as <".netzipfile.">") 1split|enew let binkeep= &binary let eikeep = &ei @@ -365,64 +311,63 @@ fun! zip#Write(fname) q! unlet s:zipfile_{winnr()} endif - + " cleanup and restore current directory cd .. - call s:Rmdir("_ZIPVIM_") + call delete("_ZIPVIM_", "rf") call s:ChgDir(curdir,s:WARNING,"(zip#Write) unable to return to ".curdir."!") - call s:Rmdir(tmpdir) + call delete(tmpdir, "rf") setlocal nomod - let &report= repkeep -" call Dret("zip#Write") endfun " --------------------------------------------------------------------- " zip#Extract: extract a file from a zip archive {{{2 fun! zip#Extract() -" call Dfunc("zip#Extract()") - let repkeep= &report - set report=10 + let dict = s:SetSaneOpts() + defer s:RestoreOpts(dict) let fname= getline(".") -" call Decho("fname<".fname.">") " sanity check if fname =~ '^"' - let &report= repkeep -" call Dret("zip#Extract") return endif if fname =~ '/$' - redraw! - echohl Error | echo "***error*** (zip#Extract) Please specify a file, not a directory" | echohl None - let &report= repkeep -" call Dret("zip#Extract") + call s:Mess('Error', "***error*** (zip#Extract) Please specify a file, not a directory") return endif + if filereadable(fname) + call s:Mess('Error', "***error*** (zip#Extract) <" .. fname .."> already exists in directory, not overwriting!") + return + endif + let target = fname->substitute('\[', '[[]', 'g') + if &shell =~ 'cmd' && has("win32") + let target = target + \ ->substitute('[?*]', '[&]', 'g') + \ ->substitute('[\\]', '?', 'g') + \ ->shellescape() + " there cannot be a file name with '\' in its name, unzip replaces it by _ + let fname = fname->substitute('[\\?*]', '_', 'g') + else + let target = target->escape('*?\\')->shellescape() + endif " extract the file mentioned under the cursor -" call Decho("system(".g:zip_extractcmd." ".shellescape(b:zipfile)." ".shellescape(shell).")") - call system(g:zip_extractcmd." ".shellescape(b:zipfile)." ".shellescape(shell)) -" call Decho("zipfile<".b:zipfile.">") + call system($"{g:zip_extractcmd} -o {shellescape(b:zipfile)} {target}") if v:shell_error != 0 - echohl Error | echo "***error*** ".g:zip_extractcmd." ".b:zipfile." ".fname.": failed!" | echohl NONE + call s:Mess('Error', "***error*** ".g:zip_extractcmd." ".b:zipfile." ".fname.": failed!") elseif !filereadable(fname) - echohl Error | echo "***error*** attempted to extract ".fname." but it doesn't appear to be present!" + call s:Mess('Error', "***error*** attempted to extract ".fname." but it doesn't appear to be present!") else - echo "***note*** successfully extracted ".fname + echomsg "***note*** successfully extracted ".fname endif - " restore option - let &report= repkeep - -" call Dret("zip#Extract") endfun " --------------------------------------------------------------------- " s:Escape: {{{2 fun! s:Escape(fname,isfilt) -" call Dfunc("QuoteFileDir(fname<".a:fname."> isfilt=".a:isfilt.")") if exists("*shellescape") if a:isfilt let qnameq= shellescape(a:fname,1) @@ -432,45 +377,48 @@ fun! s:Escape(fname,isfilt) else let qnameq= g:zip_shq.escape(a:fname,g:zip_shq).g:zip_shq endif -" call Dret("QuoteFileDir <".qnameq.">") return qnameq endfun " --------------------------------------------------------------------- -" ChgDir: {{{2 +" s:ChgDir: {{{2 fun! s:ChgDir(newdir,errlvl,errmsg) -" call Dfunc("ChgDir(newdir<".a:newdir."> errlvl=".a:errlvl." errmsg<".a:errmsg.">)") - try exe "cd ".fnameescape(a:newdir) catch /^Vim\%((\a\+)\)\=:E344/ redraw! if a:errlvl == s:NOTE - echo "***note*** ".a:errmsg + echomsg "***note*** ".a:errmsg elseif a:errlvl == s:WARNING - echohl WarningMsg | echo "***warning*** ".a:errmsg | echohl NONE + call s:Mess("WarningMsg", "***warning*** ".a:errmsg) elseif a:errlvl == s:ERROR - echohl Error | echo "***error*** ".a:errmsg | echohl NONE + call s:Mess("Error", "***error*** ".a:errmsg) endif -" call inputsave()|call input("Press <cr> to continue")|call inputrestore() -" call Dret("ChgDir 1") return 1 endtry -" call Dret("ChgDir 0") return 0 endfun " --------------------------------------------------------------------- -" s:Rmdir: {{{2 -fun! s:Rmdir(fname) -" call Dfunc("Rmdir(fname<".a:fname.">)") - if (has("win32") || has("win95") || has("win64") || has("win16")) && &shell !~? 'sh$' - call system("rmdir /S/Q ".s:Escape(a:fname,0)) - else - call system("/bin/rm -rf ".s:Escape(a:fname,0)) - endif -" call Dret("Rmdir") +" s:SetSaneOpts: {{{2 +fun! s:SetSaneOpts() + let dict = {} + let dict.report = &report + let dict.shellslash = &shellslash + + let &report = 10 + let &shellslash = 0 + + return dict +endfun + +" --------------------------------------------------------------------- +" s:RestoreOpts: {{{2 +fun! s:RestoreOpts(dict) + for [key, val] in items(a:dict) + exe $"let &{key} = {val}" + endfor endfun " ------------------------------------------------------------------------ diff --git a/runtime/colors/blue.vim b/runtime/colors/blue.vim index d6931e4c71..9ee878e103 100644 --- a/runtime/colors/blue.vim +++ b/runtime/colors/blue.vim @@ -4,7 +4,7 @@ " Maintainer: Original maintainer Steven Vertigan <steven@vertigan.wattle.id.au> " Website: https://github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Mon 08 Jan 2024 09:42:49 AM AEDT +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -27,9 +27,11 @@ hi Normal guifg=#ffd700 guibg=#000087 gui=NONE cterm=NONE hi CursorLine guifg=NONE guibg=#005faf gui=NONE cterm=NONE hi Pmenu guifg=#ffffff guibg=#008787 gui=NONE cterm=NONE hi PmenuSel guifg=#008787 guibg=#ffffff gui=NONE cterm=NONE +hi PmenuMatch guifg=#ffd700 guibg=#008787 gui=NONE cterm=NONE +hi PmenuMatchSel guifg=#ff7f50 guibg=#ffffff gui=NONE cterm=NONE hi QuickFixLine guifg=#000000 guibg=#d787d7 gui=NONE cterm=NONE hi ColorColumn guifg=NONE guibg=#870087 gui=NONE cterm=NONE -hi Conceal guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE +hi Conceal guifg=#008787 guibg=NONE gui=NONE cterm=NONE hi Cursor guifg=#000000 guibg=#00ff00 gui=NONE cterm=NONE hi CursorColumn guifg=NONE guibg=#005faf gui=NONE cterm=NONE hi CursorIM guifg=#000000 guibg=#ffd700 gui=NONE cterm=NONE @@ -137,9 +139,11 @@ if s:t_Co >= 256 hi CursorLine ctermfg=NONE ctermbg=25 cterm=NONE hi Pmenu ctermfg=231 ctermbg=30 cterm=NONE hi PmenuSel ctermfg=30 ctermbg=231 cterm=NONE + hi PmenuMatch ctermfg=220 ctermbg=30 cterm=NONE + hi PmenuMatchSel ctermfg=209 ctermbg=231 cterm=NONE hi QuickFixLine ctermfg=16 ctermbg=176 cterm=NONE hi ColorColumn ctermfg=NONE ctermbg=90 cterm=NONE - hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE + hi Conceal ctermfg=30 ctermbg=NONE cterm=NONE hi Cursor ctermfg=16 ctermbg=46 cterm=NONE hi CursorColumn ctermfg=NONE ctermbg=25 cterm=NONE hi CursorIM ctermfg=16 ctermbg=220 cterm=NONE @@ -250,9 +254,11 @@ if s:t_Co >= 16 hi CursorLine ctermfg=NONE ctermbg=NONE cterm=underline hi Pmenu ctermfg=black ctermbg=darkcyan cterm=NONE hi PmenuSel ctermfg=black ctermbg=white cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=darkcyan cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=white cterm=bold hi QuickFixLine ctermfg=black ctermbg=magenta cterm=NONE hi ColorColumn ctermfg=NONE ctermbg=darkmagenta cterm=NONE - hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE + hi Conceal ctermfg=darkcyan ctermbg=NONE cterm=NONE hi Cursor ctermfg=black ctermbg=green cterm=NONE hi CursorColumn ctermfg=NONE ctermbg=blue cterm=NONE hi CursorIM ctermfg=black ctermbg=yellow cterm=NONE @@ -363,6 +369,8 @@ if s:t_Co >= 8 hi CursorLine ctermfg=NONE ctermbg=NONE cterm=underline hi Pmenu ctermfg=black ctermbg=cyan cterm=NONE hi PmenuSel ctermfg=black ctermbg=gray cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=cyan cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=gray cterm=bold hi QuickFixLine ctermfg=black ctermbg=magenta cterm=NONE hi ColorColumn ctermfg=NONE ctermbg=magenta cterm=NONE hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE diff --git a/runtime/colors/darkblue.vim b/runtime/colors/darkblue.vim index 471b8561fb..9451e397e5 100644 --- a/runtime/colors/darkblue.vim +++ b/runtime/colors/darkblue.vim @@ -4,7 +4,7 @@ " Maintainer: Original author Bohdan Vlasyuk <bohdan@vstu.edu.ua> " Website: https://github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Mon 08 Jan 2024 09:43:03 AM AEDT +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -73,7 +73,7 @@ hi! link CurSearch Search hi! link MessageWindow Pmenu hi! link PopupNotification Todo hi Normal guifg=#c0c0c0 guibg=#000040 gui=NONE cterm=NONE -hi Conceal guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE +hi Conceal guifg=#008b8b guibg=NONE gui=NONE cterm=NONE hi ColorColumn guifg=#c0c0c0 guibg=#8b0000 gui=NONE cterm=NONE hi Cursor guifg=#000000 guibg=#ffff60 gui=NONE cterm=NONE hi QuickFixLine guifg=#000000 guibg=#ff80ff gui=NONE cterm=NONE @@ -90,6 +90,8 @@ hi Pmenu guifg=#ffffff guibg=#0030ff gui=NONE cterm=NONE hi PmenuSbar guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuSel guifg=#0030ff guibg=#ffffff gui=NONE cterm=NONE hi PmenuThumb guifg=NONE guibg=#ffffff gui=NONE cterm=NONE +hi PmenuMatch guifg=#ff80ff guibg=#0030ff gui=NONE cterm=NONE +hi PmenuMatchSel guifg=#ff00ff guibg=#ffffff gui=NONE cterm=NONE hi Question guifg=#90f020 guibg=NONE gui=NONE cterm=NONE hi SignColumn guifg=#808080 guibg=NONE gui=NONE cterm=NONE hi SpecialKey guifg=#008b8b guibg=NONE gui=NONE cterm=NONE @@ -181,7 +183,7 @@ if s:t_Co >= 256 hi! link MessageWindow Pmenu hi! link PopupNotification Todo hi Normal ctermfg=252 ctermbg=17 cterm=NONE - hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE + hi Conceal ctermfg=30 ctermbg=NONE cterm=NONE hi ColorColumn ctermfg=252 ctermbg=88 cterm=NONE hi Cursor ctermfg=16 ctermbg=227 cterm=NONE hi QuickFixLine ctermfg=16 ctermbg=213 cterm=NONE @@ -198,6 +200,8 @@ if s:t_Co >= 256 hi PmenuSbar ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuSel ctermfg=27 ctermbg=231 cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=231 cterm=NONE + hi PmenuMatch ctermfg=213 ctermbg=27 cterm=NONE + hi PmenuMatchSel ctermfg=201 ctermbg=231 cterm=NONE hi Question ctermfg=118 ctermbg=NONE cterm=NONE hi SignColumn ctermfg=102 ctermbg=NONE cterm=NONE hi SpecialKey ctermfg=30 ctermbg=NONE cterm=NONE @@ -243,7 +247,7 @@ endif if s:t_Co >= 16 hi Normal ctermfg=grey ctermbg=black cterm=NONE - hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE + hi Conceal ctermfg=darkcyan ctermbg=NONE cterm=NONE hi ColorColumn ctermfg=grey ctermbg=darkred cterm=NONE hi Cursor ctermfg=black ctermbg=yellow cterm=NONE hi QuickFixLine ctermfg=black ctermbg=magenta cterm=NONE @@ -260,6 +264,8 @@ if s:t_Co >= 16 hi PmenuSbar ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuSel ctermfg=blue ctermbg=white cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=white cterm=NONE + hi PmenuMatch ctermfg=magenta ctermbg=blue cterm=NONE + hi PmenuMatchSel ctermfg=darkmagenta ctermbg=white cterm=NONE hi Question ctermfg=green ctermbg=NONE cterm=NONE hi SignColumn ctermfg=darkgrey ctermbg=NONE cterm=NONE hi SpecialKey ctermfg=darkcyan ctermbg=NONE cterm=NONE @@ -323,6 +329,8 @@ if s:t_Co >= 8 hi PmenuSbar ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuSel ctermfg=blue ctermbg=grey cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=grey cterm=NONE + hi PmenuMatch ctermfg=grey ctermbg=blue cterm=bold + hi PmenuMatchSel ctermfg=blue ctermbg=grey cterm=bold hi Question ctermfg=darkgreen ctermbg=NONE cterm=bold hi Search ctermfg=darkcyan ctermbg=blue cterm=NONE hi SignColumn ctermfg=grey ctermbg=NONE cterm=NONE diff --git a/runtime/colors/delek.vim b/runtime/colors/delek.vim index 1919526760..35d4934f5c 100644 --- a/runtime/colors/delek.vim +++ b/runtime/colors/delek.vim @@ -4,7 +4,7 @@ " Maintainer: Original maintainer David Schweikert <david@schweikert.ch> " Website: https://github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Fri 15 Dec 2023 20:05:34 +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -43,6 +43,8 @@ hi Pmenu guifg=#000000 guibg=#add8e6 gui=NONE cterm=NONE hi PmenuSel guifg=#ffffff guibg=#00008b gui=NONE cterm=NONE hi PmenuSbar guifg=NONE guibg=#ffffff gui=NONE cterm=NONE hi PmenuThumb guifg=NONE guibg=#008b8b gui=NONE cterm=NONE +hi PmenuMatch guifg=#cd00cd guibg=#add8e6 gui=NONE cterm=NONE +hi PmenuMatchSel guifg=#ff87ff guibg=#00008b gui=NONE cterm=NONE hi TabLine guifg=#000000 guibg=#e4e4e4 gui=NONE cterm=NONE hi TabLineFill guifg=NONE guibg=#bcbcbc gui=NONE cterm=NONE hi TabLineSel guifg=#000000 guibg=#ffffff gui=bold cterm=bold @@ -50,6 +52,7 @@ hi ToolbarLine guifg=NONE guibg=#e4e4e4 gui=NONE cterm=NONE hi ToolbarButton guifg=#ffffff guibg=#bcbcbc gui=bold cterm=bold hi NonText guifg=#bcbcbc guibg=NONE gui=NONE cterm=NONE hi SpecialKey guifg=#bcbcbc guibg=NONE gui=NONE cterm=NONE +hi Conceal guifg=#bcbcbc guibg=NONE gui=NONE cterm=NONE hi Folded guifg=#00008b guibg=#e4e4e4 gui=NONE cterm=NONE hi Visual guifg=#000000 guibg=#d0d0d0 gui=NONE cterm=NONE hi VisualNOS guifg=NONE guibg=#ee0000 gui=NONE cterm=NONE @@ -87,7 +90,6 @@ hi PreProc guifg=#cd00cd guibg=NONE gui=NONE cterm=NONE hi Type guifg=#0000ff guibg=NONE gui=bold cterm=bold hi Special guifg=#ff1493 guibg=NONE gui=NONE cterm=NONE hi Directory guifg=#008b8b guibg=NONE gui=bold cterm=bold -hi Conceal guifg=#ee0000 guibg=NONE gui=NONE cterm=NONE hi Ignore guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi Title guifg=#cd00cd guibg=NONE gui=bold cterm=bold hi CursorLine guifg=NONE guibg=#e4e4e4 gui=NONE cterm=NONE @@ -117,6 +119,8 @@ if s:t_Co >= 256 hi PmenuSel ctermfg=231 ctermbg=18 cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=231 cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=30 cterm=NONE + hi PmenuMatch ctermfg=164 ctermbg=152 cterm=NONE + hi PmenuMatchSel ctermfg=213 ctermbg=18 cterm=NONE hi TabLine ctermfg=16 ctermbg=254 cterm=NONE hi TabLineFill ctermfg=NONE ctermbg=250 cterm=NONE hi TabLineSel ctermfg=16 ctermbg=231 cterm=bold @@ -124,6 +128,7 @@ if s:t_Co >= 256 hi ToolbarButton ctermfg=231 ctermbg=250 cterm=bold hi NonText ctermfg=250 ctermbg=NONE cterm=NONE hi SpecialKey ctermfg=250 ctermbg=NONE cterm=NONE + hi Conceal ctermfg=250 ctermbg=NONE cterm=NONE hi Folded ctermfg=18 ctermbg=254 cterm=NONE hi Visual ctermfg=16 ctermbg=252 cterm=NONE hi VisualNOS ctermfg=NONE ctermbg=196 cterm=NONE @@ -161,7 +166,6 @@ if s:t_Co >= 256 hi Type ctermfg=21 ctermbg=NONE cterm=bold hi Special ctermfg=198 ctermbg=NONE cterm=NONE hi Directory ctermfg=30 ctermbg=NONE cterm=bold - hi Conceal ctermfg=196 ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi Title ctermfg=164 ctermbg=NONE cterm=bold hi CursorLine ctermfg=NONE ctermbg=254 cterm=NONE @@ -185,6 +189,8 @@ if s:t_Co >= 16 hi PmenuSel ctermfg=white ctermbg=darkblue cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=white cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=darkcyan cterm=NONE + hi PmenuMatch ctermfg=darkmagenta ctermbg=grey cterm=NONE + hi PmenuMatchSel ctermfg=magenta ctermbg=darkblue cterm=NONE hi TabLine ctermfg=black ctermbg=grey cterm=NONE hi TabLineFill ctermfg=NONE ctermbg=darkgrey cterm=NONE hi TabLineSel ctermfg=black ctermbg=white cterm=bold @@ -192,6 +198,7 @@ if s:t_Co >= 16 hi ToolbarButton ctermfg=white ctermbg=darkgrey cterm=bold hi NonText ctermfg=darkgrey ctermbg=NONE cterm=NONE hi SpecialKey ctermfg=darkgrey ctermbg=NONE cterm=NONE + hi Conceal ctermfg=darkgrey ctermbg=NONE cterm=NONE hi Folded ctermfg=darkblue ctermbg=grey cterm=NONE hi Visual ctermfg=black ctermbg=darkgrey cterm=NONE hi VisualNOS ctermfg=NONE ctermbg=darkred cterm=NONE @@ -229,7 +236,6 @@ if s:t_Co >= 16 hi Type ctermfg=blue ctermbg=NONE cterm=bold hi Special ctermfg=magenta ctermbg=NONE cterm=NONE hi Directory ctermfg=darkcyan ctermbg=NONE cterm=bold - hi Conceal ctermfg=darkred ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi Title ctermfg=darkmagenta ctermbg=NONE cterm=bold hi CursorLine ctermfg=NONE ctermbg=NONE cterm=underline @@ -254,6 +260,8 @@ if s:t_Co >= 8 hi PmenuSel ctermfg=black ctermbg=darkyellow cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=darkgreen cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=darkcyan cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkyellow cterm=bold hi TabLine ctermfg=gray ctermbg=black cterm=NONE hi TabLineFill ctermfg=NONE ctermbg=black cterm=NONE hi TabLineSel ctermfg=black ctermbg=gray cterm=NONE @@ -261,6 +269,7 @@ if s:t_Co >= 8 hi ToolbarButton ctermfg=black ctermbg=gray cterm=bold,reverse hi NonText ctermfg=darkblue ctermbg=NONE cterm=NONE hi SpecialKey ctermfg=darkblue ctermbg=NONE cterm=NONE + hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE hi Folded ctermfg=darkyellow ctermbg=NONE cterm=NONE hi Visual ctermfg=NONE ctermbg=NONE cterm=reverse hi VisualNOS ctermfg=NONE ctermbg=NONE cterm=underline @@ -296,7 +305,6 @@ if s:t_Co >= 8 hi Type ctermfg=darkblue ctermbg=NONE cterm=NONE hi Special ctermfg=darkmagenta ctermbg=NONE cterm=bold hi Directory ctermfg=darkcyan ctermbg=NONE cterm=bold - hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi Title ctermfg=darkmagenta ctermbg=NONE cterm=bold hi DiffAdd ctermfg=white ctermbg=darkgreen cterm=NONE @@ -403,6 +411,7 @@ endif " Color: darkmagenta #870087 18 darkmagenta " Color: darkcyan #008787 30 darkcyan " Color: gray #878787 102 gray +" Color: magenta #ff87ff 213 magenta " Term colors: bg0 statement constant preproc identifier type special bg1 " Term colors: comment statement constant preproc identifier type special fg0 " Color: bgDiffA #5F875F 65 darkgreen diff --git a/runtime/colors/desert.vim b/runtime/colors/desert.vim index 453e966899..07ef937ab6 100644 --- a/runtime/colors/desert.vim +++ b/runtime/colors/desert.vim @@ -4,7 +4,7 @@ " Maintainer: Original maintainer Hans Fugal <hans@fugal.net> " Website: https://github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Fri 15 Dec 2023 20:05:34 +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -42,6 +42,8 @@ hi Pmenu guifg=#ffffff guibg=#666666 gui=NONE cterm=NONE hi PmenuSel guifg=#333333 guibg=#f0e68c gui=NONE cterm=NONE hi PmenuSbar guifg=NONE guibg=#333333 gui=NONE cterm=NONE hi PmenuThumb guifg=NONE guibg=#c2bfa5 gui=NONE cterm=NONE +hi PmenuMatch guifg=#ffa0a0 guibg=#666666 gui=NONE cterm=NONE +hi PmenuMatchSel guifg=#cd5c5c guibg=#f0e68c gui=NONE cterm=NONE hi TabLine guifg=#333333 guibg=#c2bfa5 gui=NONE cterm=NONE hi TabLineFill guifg=NONE guibg=#c2bfa5 gui=NONE cterm=NONE hi TabLineSel guifg=#333333 guibg=#f0e68c gui=NONE cterm=NONE @@ -116,6 +118,8 @@ if s:t_Co >= 256 hi PmenuSel ctermfg=236 ctermbg=186 cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=236 cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=144 cterm=NONE + hi PmenuMatch ctermfg=217 ctermbg=241 cterm=NONE + hi PmenuMatchSel ctermfg=167 ctermbg=186 cterm=NONE hi TabLine ctermfg=236 ctermbg=144 cterm=NONE hi TabLineFill ctermfg=NONE ctermbg=144 cterm=NONE hi TabLineSel ctermfg=236 ctermbg=186 cterm=NONE @@ -182,6 +186,8 @@ if s:t_Co >= 16 hi PmenuSel ctermfg=black ctermbg=yellow cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=black cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=white cterm=NONE + hi PmenuMatch ctermfg=NONE ctermbg=darkgrey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=yellow cterm=bold hi TabLine ctermfg=black ctermbg=grey cterm=NONE hi TabLineFill ctermfg=NONE ctermbg=white cterm=NONE hi TabLineSel ctermfg=white ctermbg=black cterm=NONE @@ -248,6 +254,8 @@ if s:t_Co >= 8 hi PmenuSel ctermfg=black ctermbg=darkyellow cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=black cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=grey cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=darkcyan cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkyellow cterm=bold hi TabLine ctermfg=black ctermbg=grey cterm=NONE hi TabLineFill ctermfg=NONE ctermbg=grey cterm=NONE hi TabLineSel ctermfg=grey ctermbg=black cterm=NONE diff --git a/runtime/colors/elflord.vim b/runtime/colors/elflord.vim index 001368861f..355e161a46 100644 --- a/runtime/colors/elflord.vim +++ b/runtime/colors/elflord.vim @@ -3,7 +3,7 @@ " Maintainer: original maintainer Ron Aaron <ron@ronware.org> " Website: https://www.github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Fri 15 Dec 2023 20:05:35 +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -77,6 +77,8 @@ hi Pmenu guifg=#ffffff guibg=#444444 gui=NONE cterm=NONE hi PmenuSbar guifg=NONE guibg=#bebebe gui=NONE cterm=NONE hi PmenuSel guifg=#000000 guibg=#00cdcd gui=NONE cterm=NONE hi PmenuThumb guifg=NONE guibg=#ffffff gui=NONE cterm=NONE +hi PmenuMatch guifg=#ff00ff guibg=#444444 gui=bold cterm=bold +hi PmenuMatchSel guifg=#ff00ff guibg=#00cdcd gui=bold cterm=bold hi Question guifg=#00ff00 guibg=NONE gui=bold cterm=bold hi Search guifg=#000000 guibg=#ffff00 gui=NONE cterm=NONE hi SignColumn guifg=#00ffff guibg=NONE gui=NONE cterm=NONE @@ -145,6 +147,8 @@ if s:t_Co >= 256 hi PmenuSbar ctermfg=NONE ctermbg=250 cterm=NONE hi PmenuSel ctermfg=16 ctermbg=44 cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=231 cterm=NONE + hi PmenuMatch ctermfg=201 ctermbg=238 cterm=bold + hi PmenuMatchSel ctermfg=201 ctermbg=44 cterm=bold hi Question ctermfg=46 ctermbg=NONE cterm=bold hi Search ctermfg=16 ctermbg=226 cterm=NONE hi SignColumn ctermfg=51 ctermbg=NONE cterm=NONE @@ -216,6 +220,8 @@ if s:t_Co >= 16 hi PmenuSbar ctermfg=NONE ctermbg=grey cterm=NONE hi PmenuSel ctermfg=black ctermbg=darkcyan cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=white cterm=NONE + hi PmenuMatch ctermfg=magenta ctermbg=darkgrey cterm=bold + hi PmenuMatchSel ctermfg=magenta ctermbg=darkcyan cterm=bold hi Question ctermfg=green ctermbg=NONE cterm=bold hi Search ctermfg=black ctermbg=yellow cterm=NONE hi SignColumn ctermfg=cyan ctermbg=NONE cterm=NONE @@ -286,6 +292,8 @@ if s:t_Co >= 8 hi PmenuSbar ctermfg=grey ctermbg=grey cterm=NONE hi PmenuSel ctermfg=black ctermbg=darkcyan cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=darkcyan cterm=NONE + hi PmenuMatch ctermfg=grey ctermbg=NONE cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkcyan cterm=bold hi Question ctermfg=darkgreen ctermbg=NONE cterm=NONE hi Search ctermfg=black ctermbg=darkyellow cterm=NONE hi SignColumn ctermfg=darkcyan ctermbg=NONE cterm=NONE diff --git a/runtime/colors/evening.vim b/runtime/colors/evening.vim index 1abdd8006f..d5e081337a 100644 --- a/runtime/colors/evening.vim +++ b/runtime/colors/evening.vim @@ -4,7 +4,7 @@ " Maintainer: Original maintainer Steven Vertigan <steven@vertigan.wattle.id.au> " Website: https://github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Mon 08 Jan 2024 09:43:27 AM AEDT +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -80,6 +80,8 @@ hi StatusLine guifg=#333333 guibg=#ffffff gui=bold cterm=bold hi StatusLineNC guifg=#333333 guibg=#d3d3d3 gui=NONE cterm=NONE hi TabLineSel guifg=#333333 guibg=#ffffff gui=bold cterm=bold hi TabLine guifg=#333333 guibg=#d3d3d3 gui=NONE cterm=NONE +hi PmenuMatch guifg=#ff80ff guibg=#4d4d4d gui=NONE cterm=NONE +hi PmenuMatchSel guifg=#8b008b guibg=#bebebe gui=NONE cterm=NONE hi Pmenu guifg=#ffffff guibg=#4d4d4d gui=NONE cterm=NONE hi PmenuSbar guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuSel guifg=#000000 guibg=#bebebe gui=NONE cterm=NONE @@ -89,7 +91,7 @@ hi Cursor guifg=#000000 guibg=#00ff00 gui=NONE cterm=NONE hi Error guifg=#ff0000 guibg=#ffffff gui=reverse cterm=reverse hi ErrorMsg guifg=#ffffff guibg=#ff0000 gui=NONE cterm=NONE hi LineNr guifg=#ffff00 guibg=NONE gui=NONE cterm=NONE -hi Conceal guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE +hi Conceal guifg=#666666 guibg=NONE gui=NONE cterm=NONE hi FoldColumn guifg=#add8e6 guibg=NONE gui=NONE cterm=NONE hi Folded guifg=#00008b guibg=#d3d3d3 gui=bold cterm=bold hi IncSearch guifg=#00ff00 guibg=NONE gui=reverse cterm=reverse @@ -188,6 +190,8 @@ if s:t_Co >= 256 hi StatusLineNC ctermfg=236 ctermbg=252 cterm=NONE hi TabLineSel ctermfg=236 ctermbg=231 cterm=bold hi TabLine ctermfg=236 ctermbg=252 cterm=NONE + hi PmenuMatch ctermfg=201 ctermbg=239 cterm=NONE + hi PmenuMatchSel ctermfg=90 ctermbg=250 cterm=NONE hi Pmenu ctermfg=231 ctermbg=239 cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuSel ctermfg=16 ctermbg=250 cterm=NONE @@ -197,7 +201,7 @@ if s:t_Co >= 256 hi Error ctermfg=196 ctermbg=231 cterm=reverse hi ErrorMsg ctermfg=231 ctermbg=196 cterm=NONE hi LineNr ctermfg=226 ctermbg=NONE cterm=NONE - hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE + hi Conceal ctermfg=241 ctermbg=NONE cterm=NONE hi FoldColumn ctermfg=153 ctermbg=NONE cterm=NONE hi Folded ctermfg=18 ctermbg=252 cterm=bold hi IncSearch ctermfg=46 ctermbg=NONE cterm=reverse @@ -299,6 +303,8 @@ if s:t_Co >= 16 hi StatusLineNC ctermfg=black ctermbg=gray cterm=NONE hi TabLineSel ctermfg=black ctermbg=white cterm=NONE hi TabLine ctermfg=black ctermbg=gray cterm=NONE + hi PmenuMatch ctermfg=white ctermbg=darkgray cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=gray cterm=bold hi Pmenu ctermfg=white ctermbg=darkgray cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuSel ctermfg=black ctermbg=gray cterm=NONE @@ -308,7 +314,7 @@ if s:t_Co >= 16 hi Error ctermfg=red ctermbg=white cterm=reverse hi ErrorMsg ctermfg=white ctermbg=red cterm=NONE hi LineNr ctermfg=darkyellow ctermbg=NONE cterm=NONE - hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE + hi Conceal ctermfg=darkgray ctermbg=NONE cterm=NONE hi FoldColumn ctermfg=lightblue ctermbg=NONE cterm=NONE hi Folded ctermfg=darkblue ctermbg=gray cterm=bold hi IncSearch ctermfg=green ctermbg=NONE cterm=reverse @@ -366,6 +372,8 @@ if s:t_Co >= 8 hi PmenuSbar ctermfg=NONE ctermbg=gray cterm=NONE hi PmenuSel ctermfg=black ctermbg=gray cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=black cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=darkcyan cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=gray cterm=bold hi QuickFixLine ctermfg=gray ctermbg=darkmagenta cterm=NONE hi Error ctermfg=red ctermbg=gray cterm=reverse hi ErrorMsg ctermfg=gray ctermbg=red cterm=NONE diff --git a/runtime/colors/habamax.vim b/runtime/colors/habamax.vim index 66f40ab56a..4b4c95e050 100644 --- a/runtime/colors/habamax.vim +++ b/runtime/colors/habamax.vim @@ -4,7 +4,7 @@ " Maintainer: Maxim Kim <habamax@gmail.com> " Website: https://github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Mon 08 Jan 2024 09:39:53 AM AEDT +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -17,7 +17,7 @@ let g:colors_name = 'habamax' let s:t_Co = &t_Co if (has('termguicolors') && &termguicolors) || has('gui_running') - let g:terminal_ansi_colors = ['#1c1c1c', '#d75f5f', '#87af87', '#afaf87', '#5f87af', '#af87af', '#5f8787', '#9e9e9e', '#767676', '#d7875f', '#afd7af', '#d7d787', '#87afd7', '#d7afd7', '#87afaf', '#bcbcbc'] + let g:terminal_ansi_colors = ['#1c1c1c', '#af5f5f', '#5faf5f', '#af875f', '#5f87af', '#af87af', '#5f8787', '#9e9e9e', '#767676', '#d75f87', '#87d787', '#d7af87', '#5fafd7', '#d787d7', '#87afaf', '#bcbcbc'] " Nvim uses g:terminal_color_{0-15} instead for i in range(g:terminal_ansi_colors->len()) let g:terminal_color_{i} = g:terminal_ansi_colors[i] @@ -27,7 +27,6 @@ hi! link Terminal Normal hi! link StatuslineTerm Statusline hi! link StatuslineTermNC StatuslineNC hi! link MessageWindow Pmenu -hi! link PopupNotification Todo hi! link javaScriptFunction Statement hi! link javaScriptIdentifier Statement hi! link sqlKeyword Statement @@ -39,7 +38,6 @@ hi! link vimOper Normal hi! link vimSep Normal hi! link vimParenSep Normal hi! link vimCommentString Comment -hi! link gitCommitSummary Title hi! link markdownUrl String hi Normal guifg=#bcbcbc guibg=#1c1c1c gui=NONE cterm=NONE hi Statusline guifg=#1c1c1c guibg=#9e9e9e gui=NONE cterm=NONE @@ -47,11 +45,11 @@ hi StatuslineNC guifg=#1c1c1c guibg=#767676 gui=NONE cterm=NONE hi VertSplit guifg=#767676 guibg=#767676 gui=NONE cterm=NONE hi TabLine guifg=#1c1c1c guibg=#767676 gui=NONE cterm=NONE hi TabLineFill guifg=#1c1c1c guibg=#767676 gui=NONE cterm=NONE -hi TabLineSel guifg=NONE guibg=NONE gui=bold ctermfg=NONE ctermbg=NONE cterm=bold +hi TabLineSel guifg=#1c1c1c guibg=#9e9e9e gui=bold cterm=bold hi ToolbarLine guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE -hi ToolbarButton guifg=#9e9e9e guibg=#1c1c1c gui=bold,reverse cterm=bold,reverse +hi ToolbarButton guifg=#767676 guibg=#1c1c1c gui=bold,reverse cterm=bold,reverse hi QuickFixLine guifg=#1c1c1c guibg=#5f87af gui=NONE cterm=NONE -hi CursorLineNr guifg=#ffaf5f guibg=NONE gui=bold cterm=bold +hi CursorLineNr guifg=#dadada guibg=NONE gui=bold cterm=bold hi LineNr guifg=#585858 guibg=NONE gui=NONE cterm=NONE hi LineNrAbove guifg=#585858 guibg=NONE gui=NONE cterm=NONE hi LineNrBelow guifg=#585858 guibg=NONE gui=NONE cterm=NONE @@ -59,71 +57,71 @@ hi NonText guifg=#585858 guibg=NONE gui=NONE cterm=NONE hi EndOfBuffer guifg=#585858 guibg=NONE gui=NONE cterm=NONE hi SpecialKey guifg=#585858 guibg=NONE gui=NONE cterm=NONE hi FoldColumn guifg=#585858 guibg=NONE gui=NONE cterm=NONE -hi Visual guifg=#1c1c1c guibg=#87afaf gui=NONE cterm=NONE +hi Visual guifg=#87afaf guibg=#1c1c1c gui=reverse cterm=reverse hi VisualNOS guifg=#1c1c1c guibg=#5f8787 gui=NONE cterm=NONE hi Pmenu guifg=NONE guibg=#3a3a3a gui=NONE cterm=NONE hi PmenuThumb guifg=NONE guibg=#767676 gui=NONE cterm=NONE hi PmenuSbar guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE -hi PmenuSel guifg=#1c1c1c guibg=#afaf87 gui=NONE cterm=NONE -hi PmenuKind guifg=#d7875f guibg=#3a3a3a gui=NONE cterm=NONE -hi PmenuKindSel guifg=#d75f5f guibg=#afaf87 gui=NONE cterm=NONE +hi PmenuSel guifg=NONE guibg=#585858 gui=NONE cterm=NONE +hi PmenuKind guifg=#5f8787 guibg=#3a3a3a gui=NONE cterm=NONE +hi PmenuKindSel guifg=#5f8787 guibg=#585858 gui=NONE cterm=NONE hi PmenuExtra guifg=#767676 guibg=#3a3a3a gui=NONE cterm=NONE -hi PmenuExtraSel guifg=#1c1c1c guibg=#afaf87 gui=NONE cterm=NONE +hi PmenuExtraSel guifg=#9e9e9e guibg=#585858 gui=NONE cterm=NONE +hi PmenuMatch guifg=#ffaf5f guibg=#3a3a3a gui=NONE cterm=NONE +hi PmenuMatchSel guifg=#ffaf5f guibg=#585858 gui=NONE cterm=NONE hi SignColumn guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE -hi Error guifg=#d75f5f guibg=#1c1c1c gui=reverse cterm=reverse -hi ErrorMsg guifg=#d75f5f guibg=#1c1c1c gui=reverse cterm=reverse -hi ModeMsg guifg=#1c1c1c guibg=#d7d787 gui=NONE cterm=NONE -hi MoreMsg guifg=#87af87 guibg=NONE gui=NONE cterm=NONE -hi Question guifg=#afaf87 guibg=NONE gui=NONE cterm=NONE -hi WarningMsg guifg=#d7875f guibg=NONE gui=NONE cterm=NONE -hi Todo guifg=#d7d787 guibg=#1c1c1c gui=reverse cterm=reverse +hi Error guifg=#af5f5f guibg=#1c1c1c gui=reverse cterm=reverse +hi ErrorMsg guifg=#af5f5f guibg=#1c1c1c gui=reverse cterm=reverse +hi ModeMsg guifg=NONE guibg=NONE gui=bold ctermfg=NONE ctermbg=NONE cterm=bold +hi MoreMsg guifg=#5faf5f guibg=NONE gui=NONE cterm=NONE +hi Question guifg=#d7af87 guibg=NONE gui=NONE cterm=NONE +hi WarningMsg guifg=#d75f87 guibg=NONE gui=NONE cterm=NONE +hi Todo guifg=#dadada guibg=NONE gui=bold cterm=bold hi MatchParen guifg=#ff00af guibg=NONE gui=bold cterm=bold -hi Search guifg=#1c1c1c guibg=#87af87 gui=NONE cterm=NONE -hi IncSearch guifg=#1c1c1c guibg=#ffaf5f gui=NONE cterm=NONE -hi CurSearch guifg=#1c1c1c guibg=#afaf87 gui=NONE cterm=NONE -hi WildMenu guifg=#1c1c1c guibg=#d7d787 gui=NONE cterm=NONE +hi Search guifg=#5fafd7 guibg=#1c1c1c gui=reverse cterm=reverse +hi IncSearch guifg=#ffaf5f guibg=#1c1c1c gui=reverse cterm=reverse +hi CurSearch guifg=#ffaf5f guibg=#1c1c1c gui=reverse cterm=reverse +hi WildMenu guifg=#1c1c1c guibg=#d7af87 gui=bold cterm=bold hi debugPC guifg=#1c1c1c guibg=#5f87af gui=NONE cterm=NONE -hi debugBreakpoint guifg=#1c1c1c guibg=#d7875f gui=NONE cterm=NONE -hi Cursor guifg=#1c1c1c guibg=#ffaf5f gui=NONE cterm=NONE +hi debugBreakpoint guifg=#1c1c1c guibg=#d75f87 gui=NONE cterm=NONE +hi Cursor guifg=#000000 guibg=#dadada gui=NONE cterm=NONE hi lCursor guifg=#1c1c1c guibg=#5fff00 gui=NONE cterm=NONE hi CursorLine guifg=NONE guibg=#303030 gui=NONE cterm=NONE hi CursorColumn guifg=NONE guibg=#303030 gui=NONE cterm=NONE hi Folded guifg=#9e9e9e guibg=#262626 gui=NONE cterm=NONE hi ColorColumn guifg=NONE guibg=#3a3a3a gui=NONE cterm=NONE hi SpellBad guifg=NONE guibg=NONE guisp=#d75f5f gui=undercurl ctermfg=NONE ctermbg=NONE cterm=underline -hi SpellCap guifg=NONE guibg=NONE guisp=#5f87af gui=undercurl ctermfg=NONE ctermbg=NONE cterm=underline -hi SpellLocal guifg=NONE guibg=NONE guisp=#87af87 gui=undercurl ctermfg=NONE ctermbg=NONE cterm=underline -hi SpellRare guifg=NONE guibg=NONE guisp=#d7afd7 gui=undercurl ctermfg=NONE ctermbg=NONE cterm=underline +hi SpellCap guifg=NONE guibg=NONE guisp=#ffaf5f gui=undercurl ctermfg=NONE ctermbg=NONE cterm=underline +hi SpellLocal guifg=NONE guibg=NONE guisp=#5fd75f gui=undercurl ctermfg=NONE ctermbg=NONE cterm=underline +hi SpellRare guifg=NONE guibg=NONE guisp=#d787d7 gui=undercurl ctermfg=NONE ctermbg=NONE cterm=underline hi Comment guifg=#767676 guibg=NONE gui=NONE cterm=NONE -hi Constant guifg=#d7875f guibg=NONE gui=NONE cterm=NONE -hi String guifg=#87af87 guibg=NONE gui=NONE cterm=NONE -hi Character guifg=#afd7af guibg=NONE gui=NONE cterm=NONE +hi Constant guifg=#d75f87 guibg=NONE gui=NONE cterm=NONE +hi String guifg=#5faf5f guibg=NONE gui=NONE cterm=NONE +hi Character guifg=#87d787 guibg=NONE gui=NONE cterm=NONE hi Identifier guifg=#87afaf guibg=NONE gui=NONE cterm=NONE hi Statement guifg=#af87af guibg=NONE gui=NONE cterm=NONE -hi PreProc guifg=#afaf87 guibg=NONE gui=NONE cterm=NONE -hi Type guifg=#87afd7 guibg=NONE gui=NONE cterm=NONE +hi PreProc guifg=#af875f guibg=NONE gui=NONE cterm=NONE +hi Type guifg=#5f87af guibg=NONE gui=NONE cterm=NONE hi Special guifg=#5f8787 guibg=NONE gui=NONE cterm=NONE hi Underlined guifg=NONE guibg=NONE gui=underline ctermfg=NONE ctermbg=NONE cterm=underline -hi Title guifg=#d7d787 guibg=NONE gui=bold cterm=bold +hi Title guifg=NONE guibg=NONE gui=bold ctermfg=NONE ctermbg=NONE cterm=bold hi Directory guifg=#87afaf guibg=NONE gui=bold cterm=bold -hi Conceal guifg=#767676 guibg=NONE gui=NONE cterm=NONE +hi Conceal guifg=#585858 guibg=NONE gui=NONE cterm=NONE hi Ignore guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi Debug guifg=#5f8787 guibg=NONE gui=NONE cterm=NONE -hi DiffAdd guifg=#dadada guibg=#5f875f gui=NONE cterm=NONE -hi DiffDelete guifg=#af875f guibg=NONE gui=NONE cterm=NONE -hi Added guifg=#87af87 guibg=NONE gui=NONE cterm=NONE -hi Changed guifg=#5f8787 guibg=NONE gui=NONE cterm=NONE +hi DiffAdd guifg=#5faf5f guibg=NONE gui=reverse cterm=reverse +hi DiffChange guifg=#5f87af guibg=NONE gui=reverse cterm=reverse +hi DiffText guifg=#af87af guibg=NONE gui=reverse cterm=reverse +hi DiffDelete guifg=#af5f5f guibg=NONE gui=reverse cterm=reverse +hi Added guifg=#5fd75f guibg=NONE gui=NONE cterm=NONE +hi Changed guifg=#ffaf5f guibg=NONE gui=NONE cterm=NONE hi Removed guifg=#d75f5f guibg=NONE gui=NONE cterm=NONE -hi diffSubname guifg=#af87af guibg=NONE gui=NONE cterm=NONE -hi DiffText guifg=#dadada guibg=#878787 gui=NONE cterm=NONE -hi DiffChange guifg=#bcbcbc guibg=#5f5f5f gui=NONE cterm=NONE if s:t_Co >= 256 hi! link Terminal Normal hi! link StatuslineTerm Statusline hi! link StatuslineTermNC StatuslineNC hi! link MessageWindow Pmenu - hi! link PopupNotification Todo hi! link javaScriptFunction Statement hi! link javaScriptIdentifier Statement hi! link sqlKeyword Statement @@ -135,7 +133,6 @@ if s:t_Co >= 256 hi! link vimSep Normal hi! link vimParenSep Normal hi! link vimCommentString Comment - hi! link gitCommitSummary Title hi! link markdownUrl String hi Normal ctermfg=250 ctermbg=234 cterm=NONE hi Statusline ctermfg=234 ctermbg=247 cterm=NONE @@ -143,11 +140,11 @@ if s:t_Co >= 256 hi VertSplit ctermfg=243 ctermbg=243 cterm=NONE hi TabLine ctermfg=234 ctermbg=243 cterm=NONE hi TabLineFill ctermfg=234 ctermbg=243 cterm=NONE - hi TabLineSel ctermfg=NONE ctermbg=NONE cterm=bold + hi TabLineSel ctermfg=234 ctermbg=247 cterm=bold hi ToolbarLine ctermfg=NONE ctermbg=NONE cterm=NONE - hi ToolbarButton ctermfg=247 ctermbg=234 cterm=bold,reverse + hi ToolbarButton ctermfg=243 ctermbg=234 cterm=bold,reverse hi QuickFixLine ctermfg=234 ctermbg=67 cterm=NONE - hi CursorLineNr ctermfg=215 ctermbg=NONE cterm=bold + hi CursorLineNr ctermfg=253 ctermbg=NONE cterm=bold hi LineNr ctermfg=240 ctermbg=NONE cterm=NONE hi LineNrAbove ctermfg=240 ctermbg=NONE cterm=NONE hi LineNrBelow ctermfg=240 ctermbg=NONE cterm=NONE @@ -155,62 +152,63 @@ if s:t_Co >= 256 hi EndOfBuffer ctermfg=240 ctermbg=NONE cterm=NONE hi SpecialKey ctermfg=240 ctermbg=NONE cterm=NONE hi FoldColumn ctermfg=240 ctermbg=NONE cterm=NONE - hi Visual ctermfg=234 ctermbg=109 cterm=NONE + hi Visual ctermfg=109 ctermbg=234 cterm=reverse hi VisualNOS ctermfg=234 ctermbg=66 cterm=NONE hi Pmenu ctermfg=NONE ctermbg=237 cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=243 cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=NONE cterm=NONE - hi PmenuSel ctermfg=234 ctermbg=144 cterm=NONE - hi PmenuKind ctermfg=173 ctermbg=237 cterm=NONE - hi PmenuKindSel ctermfg=167 ctermbg=144 cterm=NONE + hi PmenuSel ctermfg=NONE ctermbg=240 cterm=NONE + hi PmenuKind ctermfg=66 ctermbg=237 cterm=NONE + hi PmenuKindSel ctermfg=66 ctermbg=240 cterm=NONE hi PmenuExtra ctermfg=243 ctermbg=237 cterm=NONE - hi PmenuExtraSel ctermfg=234 ctermbg=144 cterm=NONE + hi PmenuExtraSel ctermfg=247 ctermbg=240 cterm=NONE + hi PmenuMatch ctermfg=215 ctermbg=237 cterm=NONE + hi PmenuMatchSel ctermfg=215 ctermbg=240 cterm=NONE hi SignColumn ctermfg=NONE ctermbg=NONE cterm=NONE - hi Error ctermfg=167 ctermbg=234 cterm=reverse - hi ErrorMsg ctermfg=167 ctermbg=234 cterm=reverse - hi ModeMsg ctermfg=234 ctermbg=186 cterm=NONE - hi MoreMsg ctermfg=108 ctermbg=NONE cterm=NONE - hi Question ctermfg=144 ctermbg=NONE cterm=NONE - hi WarningMsg ctermfg=173 ctermbg=NONE cterm=NONE - hi Todo ctermfg=186 ctermbg=234 cterm=reverse + hi Error ctermfg=131 ctermbg=234 cterm=reverse + hi ErrorMsg ctermfg=131 ctermbg=234 cterm=reverse + hi ModeMsg ctermfg=NONE ctermbg=NONE cterm=bold + hi MoreMsg ctermfg=71 ctermbg=NONE cterm=NONE + hi Question ctermfg=180 ctermbg=NONE cterm=NONE + hi WarningMsg ctermfg=168 ctermbg=NONE cterm=NONE + hi Todo ctermfg=253 ctermbg=NONE cterm=bold hi MatchParen ctermfg=199 ctermbg=NONE cterm=bold - hi Search ctermfg=234 ctermbg=108 cterm=NONE - hi IncSearch ctermfg=234 ctermbg=215 cterm=NONE - hi CurSearch ctermfg=234 ctermbg=144 cterm=NONE - hi WildMenu ctermfg=234 ctermbg=186 cterm=NONE + hi Search ctermfg=74 ctermbg=234 cterm=reverse + hi IncSearch ctermfg=215 ctermbg=234 cterm=reverse + hi CurSearch ctermfg=215 ctermbg=234 cterm=reverse + hi WildMenu ctermfg=234 ctermbg=180 cterm=bold hi debugPC ctermfg=234 ctermbg=67 cterm=NONE - hi debugBreakpoint ctermfg=234 ctermbg=173 cterm=NONE + hi debugBreakpoint ctermfg=234 ctermbg=168 cterm=NONE hi CursorLine ctermfg=NONE ctermbg=236 cterm=NONE hi CursorColumn ctermfg=NONE ctermbg=236 cterm=NONE hi Folded ctermfg=247 ctermbg=235 cterm=NONE hi ColorColumn ctermfg=NONE ctermbg=237 cterm=NONE hi SpellBad ctermfg=167 ctermbg=NONE cterm=underline - hi SpellCap ctermfg=67 ctermbg=NONE cterm=underline - hi SpellLocal ctermfg=108 ctermbg=NONE cterm=underline - hi SpellRare ctermfg=182 ctermbg=NONE cterm=underline + hi SpellCap ctermfg=215 ctermbg=NONE cterm=underline + hi SpellLocal ctermfg=77 ctermbg=NONE cterm=underline + hi SpellRare ctermfg=176 ctermbg=NONE cterm=underline hi Comment ctermfg=243 ctermbg=NONE cterm=NONE - hi Constant ctermfg=173 ctermbg=NONE cterm=NONE - hi String ctermfg=108 ctermbg=NONE cterm=NONE - hi Character ctermfg=151 ctermbg=NONE cterm=NONE + hi Constant ctermfg=168 ctermbg=NONE cterm=NONE + hi String ctermfg=71 ctermbg=NONE cterm=NONE + hi Character ctermfg=114 ctermbg=NONE cterm=NONE hi Identifier ctermfg=109 ctermbg=NONE cterm=NONE hi Statement ctermfg=139 ctermbg=NONE cterm=NONE - hi PreProc ctermfg=144 ctermbg=NONE cterm=NONE - hi Type ctermfg=110 ctermbg=NONE cterm=NONE + hi PreProc ctermfg=137 ctermbg=NONE cterm=NONE + hi Type ctermfg=67 ctermbg=NONE cterm=NONE hi Special ctermfg=66 ctermbg=NONE cterm=NONE hi Underlined ctermfg=NONE ctermbg=NONE cterm=underline - hi Title ctermfg=186 ctermbg=NONE cterm=bold + hi Title ctermfg=NONE ctermbg=NONE cterm=bold hi Directory ctermfg=109 ctermbg=NONE cterm=bold - hi Conceal ctermfg=243 ctermbg=NONE cterm=NONE + hi Conceal ctermfg=240 ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi Debug ctermfg=66 ctermbg=NONE cterm=NONE - hi DiffAdd ctermfg=253 ctermbg=65 cterm=NONE - hi DiffDelete ctermfg=137 ctermbg=NONE cterm=NONE - hi Added ctermfg=108 ctermbg=NONE cterm=NONE - hi Changed ctermfg=66 ctermbg=NONE cterm=NONE + hi DiffAdd ctermfg=71 ctermbg=NONE cterm=reverse + hi DiffChange ctermfg=67 ctermbg=NONE cterm=reverse + hi DiffText ctermfg=139 ctermbg=NONE cterm=reverse + hi DiffDelete ctermfg=131 ctermbg=NONE cterm=reverse + hi Added ctermfg=77 ctermbg=NONE cterm=NONE + hi Changed ctermfg=215 ctermbg=NONE cterm=NONE hi Removed ctermfg=167 ctermbg=NONE cterm=NONE - hi diffSubname ctermfg=139 ctermbg=NONE cterm=NONE - hi DiffText ctermfg=253 ctermbg=102 cterm=NONE - hi DiffChange ctermfg=250 ctermbg=59 cterm=NONE unlet s:t_Co finish endif @@ -222,11 +220,11 @@ if s:t_Co >= 16 hi VertSplit ctermfg=darkgray ctermbg=darkgray cterm=NONE hi TabLine ctermfg=black ctermbg=darkgray cterm=NONE hi TabLineFill ctermfg=black ctermbg=darkgray cterm=NONE - hi TabLineSel ctermfg=NONE ctermbg=NONE cterm=bold + hi TabLineSel ctermfg=black ctermbg=gray cterm=bold hi ToolbarLine ctermfg=NONE ctermbg=NONE cterm=NONE - hi ToolbarButton ctermfg=gray ctermbg=black cterm=bold,reverse - hi QuickFixLine ctermfg=black ctermbg=blue cterm=NONE - hi CursorLineNr ctermfg=red ctermbg=NONE cterm=bold + hi ToolbarButton ctermfg=darkgray ctermbg=black cterm=bold,reverse + hi QuickFixLine ctermfg=black ctermbg=darkblue cterm=NONE + hi CursorLineNr ctermfg=white ctermbg=NONE cterm=bold hi LineNr ctermfg=darkgrey ctermbg=NONE cterm=NONE hi LineNrAbove ctermfg=darkgrey ctermbg=NONE cterm=NONE hi LineNrBelow ctermfg=darkgrey ctermbg=NONE cterm=NONE @@ -234,7 +232,7 @@ if s:t_Co >= 16 hi EndOfBuffer ctermfg=darkgrey ctermbg=NONE cterm=NONE hi SpecialKey ctermfg=darkgrey ctermbg=NONE cterm=NONE hi FoldColumn ctermfg=darkgrey ctermbg=NONE cterm=NONE - hi Visual ctermfg=black ctermbg=cyan cterm=NONE + hi Visual ctermfg=cyan ctermbg=black cterm=reverse hi VisualNOS ctermfg=black ctermbg=darkcyan cterm=NONE hi Pmenu ctermfg=black ctermbg=gray cterm=NONE hi PmenuThumb ctermfg=gray ctermbg=black cterm=NONE @@ -244,27 +242,29 @@ if s:t_Co >= 16 hi PmenuKindSel ctermfg=darkred ctermbg=darkyellow cterm=NONE hi PmenuExtra ctermfg=darkgray ctermbg=gray cterm=NONE hi PmenuExtraSel ctermfg=black ctermbg=darkyellow cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=gray cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkyellow cterm=bold hi SignColumn ctermfg=NONE ctermbg=NONE cterm=NONE hi Error ctermfg=darkred ctermbg=black cterm=reverse hi ErrorMsg ctermfg=darkred ctermbg=black cterm=reverse - hi ModeMsg ctermfg=black ctermbg=yellow cterm=NONE + hi ModeMsg ctermfg=NONE ctermbg=NONE cterm=bold hi MoreMsg ctermfg=darkgreen ctermbg=NONE cterm=NONE - hi Question ctermfg=darkyellow ctermbg=NONE cterm=NONE + hi Question ctermfg=yellow ctermbg=NONE cterm=NONE hi WarningMsg ctermfg=red ctermbg=NONE cterm=NONE - hi Todo ctermfg=yellow ctermbg=black cterm=reverse + hi Todo ctermfg=white ctermbg=NONE cterm=bold hi MatchParen ctermfg=magenta ctermbg=NONE cterm=bold - hi Search ctermfg=black ctermbg=darkgreen cterm=NONE - hi IncSearch ctermfg=black ctermbg=red cterm=NONE - hi CurSearch ctermfg=black ctermbg=darkyellow cterm=NONE - hi WildMenu ctermfg=black ctermbg=yellow cterm=NONE - hi debugPC ctermfg=black ctermbg=blue cterm=NONE + hi Search ctermfg=blue ctermbg=black cterm=reverse + hi IncSearch ctermfg=red ctermbg=black cterm=reverse + hi CurSearch ctermfg=red ctermbg=black cterm=reverse + hi WildMenu ctermfg=black ctermbg=yellow cterm=bold + hi debugPC ctermfg=black ctermbg=darkblue cterm=NONE hi debugBreakpoint ctermfg=black ctermbg=red cterm=NONE hi CursorLine ctermfg=NONE ctermbg=NONE cterm=underline hi CursorColumn ctermfg=black ctermbg=darkyellow cterm=NONE hi Folded ctermfg=black ctermbg=darkyellow cterm=NONE hi ColorColumn ctermfg=black ctermbg=darkyellow cterm=NONE hi SpellBad ctermfg=darkred ctermbg=NONE cterm=underline - hi SpellCap ctermfg=blue ctermbg=NONE cterm=underline + hi SpellCap ctermfg=darkyellow ctermbg=NONE cterm=underline hi SpellLocal ctermfg=darkgreen ctermbg=NONE cterm=underline hi SpellRare ctermfg=magenta ctermbg=NONE cterm=underline hi Comment ctermfg=darkgray ctermbg=NONE cterm=NONE @@ -274,22 +274,21 @@ if s:t_Co >= 16 hi Identifier ctermfg=cyan ctermbg=NONE cterm=NONE hi Statement ctermfg=darkmagenta ctermbg=NONE cterm=NONE hi PreProc ctermfg=darkyellow ctermbg=NONE cterm=NONE - hi Type ctermfg=blue ctermbg=NONE cterm=NONE + hi Type ctermfg=darkblue ctermbg=NONE cterm=NONE hi Special ctermfg=darkcyan ctermbg=NONE cterm=NONE hi Underlined ctermfg=NONE ctermbg=NONE cterm=underline - hi Title ctermfg=yellow ctermbg=NONE cterm=bold + hi Title ctermfg=NONE ctermbg=NONE cterm=bold hi Directory ctermfg=cyan ctermbg=NONE cterm=bold - hi Conceal ctermfg=darkgray ctermbg=NONE cterm=NONE + hi Conceal ctermfg=darkgrey ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi Debug ctermfg=darkcyan ctermbg=NONE cterm=NONE - hi DiffAdd ctermfg=white ctermbg=darkgreen cterm=NONE - hi DiffDelete ctermfg=darkyellow ctermbg=NONE cterm=NONE + hi DiffAdd ctermfg=darkgreen ctermbg=NONE cterm=reverse + hi DiffChange ctermfg=darkblue ctermbg=NONE cterm=reverse + hi DiffText ctermfg=darkmagenta ctermbg=NONE cterm=reverse + hi DiffDelete ctermfg=darkred ctermbg=NONE cterm=reverse hi Added ctermfg=darkgreen ctermbg=NONE cterm=NONE - hi Changed ctermfg=darkcyan ctermbg=NONE cterm=NONE + hi Changed ctermfg=darkyellow ctermbg=NONE cterm=NONE hi Removed ctermfg=darkred ctermbg=NONE cterm=NONE - hi diffSubname ctermfg=darkmagenta ctermbg=NONE cterm=NONE - hi DiffText ctermfg=white ctermbg=lightgrey cterm=NONE - hi DiffChange ctermfg=white ctermbg=darkgray cterm=NONE unlet s:t_Co finish endif @@ -298,13 +297,13 @@ if s:t_Co >= 8 hi Normal ctermfg=gray ctermbg=black cterm=NONE hi Statusline ctermfg=gray ctermbg=black cterm=bold,reverse hi StatuslineNC ctermfg=gray ctermbg=black cterm=reverse - hi VertSplit ctermfg=gray ctermbg=black cterm=reverse + hi VertSplit ctermfg=gray ctermbg=gray cterm=NONE hi TabLine ctermfg=black ctermbg=gray cterm=NONE - hi TabLineFill ctermfg=black ctermbg=gray cterm=NONE - hi TabLineSel ctermfg=NONE ctermbg=NONE cterm=NONE + hi TabLineFill ctermfg=gray ctermbg=gray cterm=NONE + hi TabLineSel ctermfg=black ctermbg=gray cterm=bold hi ToolbarLine ctermfg=NONE ctermbg=NONE cterm=NONE - hi ToolbarButton ctermfg=gray ctermbg=black cterm=bold,reverse - hi QuickFixLine ctermfg=black ctermbg=blue cterm=NONE + hi ToolbarButton ctermfg=gray ctermbg=black cterm=reverse + hi QuickFixLine ctermfg=black ctermbg=darkblue cterm=NONE hi CursorLineNr ctermfg=darkyellow ctermbg=NONE cterm=bold hi LineNr ctermfg=gray ctermbg=NONE cterm=bold hi LineNrAbove ctermfg=gray ctermbg=NONE cterm=bold @@ -323,52 +322,53 @@ if s:t_Co >= 8 hi PmenuKindSel ctermfg=darkred ctermbg=darkyellow cterm=NONE hi PmenuExtra ctermfg=black ctermbg=gray cterm=NONE hi PmenuExtraSel ctermfg=black ctermbg=darkyellow cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=gray cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkyellow cterm=bold hi SignColumn ctermfg=NONE ctermbg=NONE cterm=NONE hi Error ctermfg=darkred ctermbg=gray cterm=bold,reverse hi ErrorMsg ctermfg=darkred ctermbg=gray cterm=bold,reverse - hi ModeMsg ctermfg=black ctermbg=darkyellow cterm=NONE + hi ModeMsg ctermfg=NONE ctermbg=NONE cterm=bold hi MoreMsg ctermfg=darkgreen ctermbg=NONE cterm=NONE hi Question ctermfg=darkyellow ctermbg=NONE cterm=NONE hi WarningMsg ctermfg=darkred ctermbg=NONE cterm=NONE - hi Todo ctermfg=darkyellow ctermbg=black cterm=reverse + hi Todo ctermfg=gray ctermbg=NONE cterm=bold hi MatchParen ctermfg=magenta ctermbg=NONE cterm=bold - hi Search ctermfg=black ctermbg=darkgreen cterm=NONE + hi Search ctermfg=black ctermbg=darkblue cterm=NONE hi IncSearch ctermfg=black ctermbg=darkyellow cterm=NONE hi CurSearch ctermfg=black ctermbg=darkyellow cterm=NONE hi WildMenu ctermfg=black ctermbg=darkyellow cterm=NONE - hi debugPC ctermfg=black ctermbg=blue cterm=NONE + hi debugPC ctermfg=black ctermbg=darkblue cterm=NONE hi debugBreakpoint ctermfg=black ctermbg=darkcyan cterm=NONE hi CursorLine ctermfg=NONE ctermbg=NONE cterm=underline hi CursorColumn ctermfg=black ctermbg=darkyellow cterm=NONE hi Folded ctermfg=black ctermbg=darkyellow cterm=NONE hi ColorColumn ctermfg=black ctermbg=darkyellow cterm=NONE hi SpellBad ctermfg=darkred ctermbg=gray cterm=reverse - hi SpellCap ctermfg=blue ctermbg=gray cterm=reverse + hi SpellCap ctermfg=darkblue ctermbg=gray cterm=reverse hi SpellLocal ctermfg=darkgreen ctermbg=black cterm=reverse hi SpellRare ctermfg=darkmagenta ctermbg=gray cterm=reverse hi Comment ctermfg=gray ctermbg=NONE cterm=bold - hi Constant ctermfg=darkgreen ctermbg=NONE cterm=NONE + hi Constant ctermfg=darkred ctermbg=NONE cterm=NONE hi String ctermfg=darkgreen ctermbg=NONE cterm=NONE hi Character ctermfg=darkgreen ctermbg=NONE cterm=NONE hi Identifier ctermfg=gray ctermbg=NONE cterm=NONE hi Statement ctermfg=darkmagenta ctermbg=NONE cterm=NONE hi PreProc ctermfg=darkyellow ctermbg=NONE cterm=NONE - hi Type ctermfg=blue ctermbg=NONE cterm=NONE + hi Type ctermfg=darkblue ctermbg=NONE cterm=NONE hi Special ctermfg=darkcyan ctermbg=NONE cterm=NONE hi Underlined ctermfg=NONE ctermbg=NONE cterm=underline - hi Title ctermfg=darkyellow ctermbg=NONE cterm=bold + hi Title ctermfg=NONE ctermbg=NONE cterm=bold hi Directory ctermfg=darkcyan ctermbg=NONE cterm=bold hi Conceal ctermfg=gray ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi Debug ctermfg=darkcyan ctermbg=NONE cterm=NONE - hi DiffAdd ctermfg=white ctermbg=darkgreen cterm=NONE - hi DiffDelete ctermfg=darkyellow ctermbg=NONE cterm=NONE + hi DiffAdd ctermfg=darkgreen ctermbg=NONE cterm=reverse + hi DiffChange ctermfg=darkblue ctermbg=NONE cterm=reverse + hi DiffText ctermfg=darkmagenta ctermbg=NONE cterm=reverse + hi DiffDelete ctermfg=darkred ctermbg=NONE cterm=reverse hi Added ctermfg=darkgreen ctermbg=NONE cterm=NONE - hi Changed ctermfg=darkcyan ctermbg=NONE cterm=NONE + hi Changed ctermfg=darkyellow ctermbg=NONE cterm=NONE hi Removed ctermfg=darkred ctermbg=NONE cterm=NONE - hi diffSubname ctermfg=darkmagenta ctermbg=NONE cterm=NONE - hi DiffText ctermfg=white ctermbg=black cterm=bold,reverse - hi DiffChange ctermfg=black ctermbg=white cterm=NONE unlet s:t_Co finish endif @@ -442,36 +442,39 @@ if s:t_Co >= 0 endif " Background: dark -" Color: color00 #1C1C1C 234 black +" Color: color00 #1c1c1c 234 black " Color: color08 #767676 243 darkgray -" Color: color01 #D75F5F 167 darkred -" Color: color09 #D7875F 173 red -" Color: color02 #87AF87 108 darkgreen -" Color: color10 #AFD7AF 151 green -" Color: color03 #AFAF87 144 darkyellow -" Color: color11 #D7D787 186 yellow -" Color: color04 #5F87AF 67 blue -" Color: color12 #87AFD7 110 blue -" Color: color05 #AF87AF 139 darkmagenta -" Color: color13 #D7AFD7 182 magenta -" Color: color06 #5F8787 66 darkcyan -" Color: color14 #87AFAF 109 cyan -" Color: color07 #9E9E9E 247 gray -" Color: color15 #BCBCBC 250 white +" Color: color01 #af5f5f 131 darkred +" Color: color09 #d75f87 168 red +" Color: color02 #5faf5f 71 darkgreen +" Color: color10 #87d787 114 green +" Color: color03 #af875f 137 darkyellow +" Color: color11 #d7af87 180 yellow +" Color: color04 #5f87af 67 darkblue +" Color: color12 #5fafd7 74 blue +" Color: color05 #af87af 139 darkmagenta +" Color: color13 #d787d7 176 magenta +" Color: color06 #5f8787 66 darkcyan +" Color: color14 #87afaf 109 cyan +" Color: color07 #9e9e9e 247 gray +" Color: color15 #bcbcbc 250 white " Color: colorLine #303030 236 darkgrey " Color: colorB #3a3a3a 237 darkgrey " Color: colorF #262626 235 darkgrey " Color: colorNonT #585858 240 darkgrey -" Color: colorC #FFAF5F 215 red -" Color: colorlC #5FFF00 82 green -" Color: colorV #1F3F5F 109 cyan +" Color: colorC #ffaf5f 215 red +" Color: colorlC #5fff00 82 green +" Color: colorV #1f3f5f 109 cyan " Color: colorMP #ff00af 199 magenta -" Color: diffAdd #5f875f 65 darkgreen -" Color: diffDelete #af875f 137 darkyellow -" Color: diffChange #5f5f5f 59 darkgray -" Color: diffText #878787 102 lightgrey +" Color: diffAdd #5faf5f 71 darkgreen +" Color: diffDelete #af5f5f 131 darkred +" Color: diffChange #5f87af 67 darkblue +" Color: diffText #af87af 139 darkmagenta " Color: black #000000 16 black " Color: white #dadada 253 white +" Color: Added #5fd75f 77 darkgreen +" Color: Changed #ffaf5f 215 darkyellow +" Color: Removed #d75f5f 167 darkred " Term colors: color00 color01 color02 color03 color04 color05 color06 color07 " Term colors: color08 color09 color10 color11 color12 color13 color14 color15 " vim: et ts=8 sw=2 sts=2 diff --git a/runtime/colors/industry.vim b/runtime/colors/industry.vim index 449bf3b676..6e66a4a791 100644 --- a/runtime/colors/industry.vim +++ b/runtime/colors/industry.vim @@ -4,7 +4,7 @@ " Maintainer: Original maintainer Shian Lee. " Website: https://github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Fri 15 Dec 2023 20:05:36 +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -34,6 +34,8 @@ hi Pmenu guifg=#dadada guibg=#444444 gui=NONE cterm=NONE hi PmenuSel guifg=#000000 guibg=#ffff00 gui=NONE cterm=NONE hi PmenuSbar guifg=NONE guibg=#000000 gui=NONE cterm=NONE hi PmenuThumb guifg=NONE guibg=#6c6c6c gui=NONE cterm=NONE +hi PmenuMatch guifg=#ff00ff guibg=#444444 gui=NONE cterm=NONE +hi PmenuMatchSel guifg=#ff00ff guibg=#ffff00 gui=NONE cterm=NONE hi TabLine guifg=#dadada guibg=#444444 gui=NONE cterm=NONE hi TabLineFill guifg=NONE guibg=#6c6c6c gui=NONE cterm=NONE hi TabLineSel guifg=#ffffff guibg=#000000 gui=bold cterm=bold @@ -108,6 +110,8 @@ if s:t_Co >= 256 hi PmenuSel ctermfg=16 ctermbg=226 cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=16 cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=242 cterm=NONE + hi PmenuMatch ctermfg=201 ctermbg=238 cterm=NONE + hi PmenuMatchSel ctermfg=201 ctermbg=226 cterm=NONE hi TabLine ctermfg=253 ctermbg=238 cterm=NONE hi TabLineFill ctermfg=NONE ctermbg=242 cterm=NONE hi TabLineSel ctermfg=231 ctermbg=16 cterm=bold @@ -185,6 +189,8 @@ if s:t_Co >= 16 hi PmenuSel ctermfg=black ctermbg=yellow cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=black cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=grey cterm=NONE + hi PmenuMatch ctermfg=white ctermbg=darkgrey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=yellow cterm=bold hi TabLine ctermfg=white ctermbg=darkgrey cterm=NONE hi TabLineFill ctermfg=NONE ctermbg=grey cterm=NONE hi TabLineSel ctermfg=white ctermbg=black cterm=bold @@ -262,6 +268,8 @@ if s:t_Co >= 8 hi PmenuSel ctermfg=black ctermbg=darkyellow cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=black cterm=NONE hi PmenuThumb ctermfg=black ctermbg=darkyellow cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=grey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkyellow cterm=bold hi TabLine ctermfg=black ctermbg=grey cterm=NONE hi TabLineFill ctermfg=NONE ctermbg=grey cterm=NONE hi TabLineSel ctermfg=grey ctermbg=black cterm=NONE diff --git a/runtime/colors/koehler.vim b/runtime/colors/koehler.vim index 8a63f91a94..953c6a67fa 100644 --- a/runtime/colors/koehler.vim +++ b/runtime/colors/koehler.vim @@ -3,7 +3,7 @@ " Maintainer: original maintainer Ron Aaron <ron@ronware.org> " Website: https://www.github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Fri 15 Dec 2023 20:05:36 +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -67,7 +67,7 @@ hi CursorLine guifg=NONE guibg=#555555 gui=NONE cterm=NONE hi CursorLineNr guifg=#ffff00 guibg=NONE gui=bold cterm=bold hi Folded guifg=#00cdcd guibg=#666666 gui=NONE cterm=NONE hi QuickFixLine guifg=#000000 guibg=#ffff00 gui=NONE cterm=NONE -hi Conceal guifg=#e5e5e5 guibg=#a9a9a9 gui=NONE cterm=NONE +hi Conceal guifg=#666666 guibg=NONE gui=NONE cterm=NONE hi Cursor guifg=#000000 guibg=#00ff00 gui=NONE cterm=NONE hi Directory guifg=#cc8000 guibg=NONE gui=NONE cterm=NONE hi EndOfBuffer guifg=#cd0000 guibg=NONE gui=bold cterm=bold @@ -82,6 +82,8 @@ hi Pmenu guifg=#ffffff guibg=#444444 gui=NONE cterm=NONE hi PmenuSbar guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuSel guifg=#000000 guibg=#00cdcd gui=NONE cterm=NONE hi PmenuThumb guifg=NONE guibg=#ffffff gui=NONE cterm=NONE +hi PmenuMatch guifg=#ff00ff guibg=#444444 gui=NONE cterm=NONE +hi PmenuMatchSel guifg=#ff0000 guibg=#00cdcd gui=NONE cterm=NONE hi Question guifg=#5c5cff guibg=NONE gui=bold cterm=bold hi Search guifg=#ffffff guibg=#ff0000 gui=NONE cterm=NONE hi SignColumn guifg=#00ffff guibg=NONE gui=NONE cterm=NONE @@ -128,7 +130,7 @@ if s:t_Co >= 256 hi CursorLineNr ctermfg=226 ctermbg=NONE cterm=bold hi Folded ctermfg=44 ctermbg=59 cterm=NONE hi QuickFixLine ctermfg=16 ctermbg=226 cterm=NONE - hi Conceal ctermfg=254 ctermbg=145 cterm=NONE + hi Conceal ctermfg=59 ctermbg=NONE cterm=NONE hi Cursor ctermfg=16 ctermbg=46 cterm=NONE hi Directory ctermfg=172 ctermbg=NONE cterm=NONE hi EndOfBuffer ctermfg=160 ctermbg=NONE cterm=bold @@ -143,6 +145,8 @@ if s:t_Co >= 256 hi PmenuSbar ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuSel ctermfg=16 ctermbg=44 cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=231 cterm=NONE + hi PmenuMatch ctermfg=201 ctermbg=238 cterm=NONE + hi PmenuMatchSel ctermfg=196 ctermbg=44 cterm=NONE hi Question ctermfg=63 ctermbg=NONE cterm=bold hi Search ctermfg=231 ctermbg=196 cterm=NONE hi SignColumn ctermfg=51 ctermbg=NONE cterm=NONE @@ -192,7 +196,7 @@ if s:t_Co >= 16 hi CursorLine ctermfg=NONE ctermbg=NONE cterm=underline hi Folded ctermfg=darkblue ctermbg=NONE cterm=NONE hi QuickFixLine ctermfg=black ctermbg=yellow cterm=NONE - hi Conceal ctermfg=grey ctermbg=grey cterm=NONE + hi Conceal ctermfg=darkgrey ctermbg=NONE cterm=NONE hi Cursor ctermfg=black ctermbg=green cterm=NONE hi Directory ctermfg=darkyellow ctermbg=NONE cterm=NONE hi EndOfBuffer ctermfg=darkred ctermbg=NONE cterm=bold @@ -207,6 +211,8 @@ if s:t_Co >= 16 hi PmenuSbar ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuSel ctermfg=black ctermbg=darkcyan cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=white cterm=NONE + hi PmenuMatch ctermfg=white ctermbg=darkgrey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkcyan cterm=bold hi Question ctermfg=blue ctermbg=NONE cterm=bold hi Search ctermfg=white ctermbg=red cterm=NONE hi SignColumn ctermfg=cyan ctermbg=NONE cterm=NONE @@ -270,6 +276,8 @@ if s:t_Co >= 8 hi PmenuSbar ctermfg=NONE ctermbg=grey cterm=NONE hi PmenuSel ctermfg=black ctermbg=darkcyan cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=darkcyan cterm=NONE + hi PmenuMatch ctermfg=grey ctermbg=darkgrey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkcyan cterm=bold hi Question ctermfg=darkblue ctermbg=NONE cterm=bold hi Search ctermfg=grey ctermbg=darkred cterm=NONE hi SignColumn ctermfg=darkcyan ctermbg=NONE cterm=NONE diff --git a/runtime/colors/lunaperche.vim b/runtime/colors/lunaperche.vim index 62538468dc..75d25e2a23 100644 --- a/runtime/colors/lunaperche.vim +++ b/runtime/colors/lunaperche.vim @@ -4,7 +4,7 @@ " Maintainer: Maxim Kim <habamax@gmail.com> " Website: https://www.github.com/vim/colorschemes " License: Vim License (see `:help license`) -" Last Updated: Mon 08 Jan 2024 09:41:03 AM AEDT +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -125,6 +125,8 @@ if &background ==# 'dark' hi PmenuKindSel guifg=#ff5f5f guibg=#4e4e4e gui=NONE cterm=NONE hi PmenuExtra guifg=#767676 guibg=#303030 gui=NONE cterm=NONE hi PmenuExtraSel guifg=#767676 guibg=#4e4e4e gui=NONE cterm=NONE + hi PmenuMatch guifg=#d787d7 guibg=#303030 gui=NONE cterm=NONE + hi PmenuMatchSel guifg=#d787d7 guibg=#4e4e4e gui=NONE cterm=NONE hi SignColumn guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi Error guifg=#ffffff guibg=#ff5f5f gui=NONE cterm=NONE hi ErrorMsg guifg=#ffffff guibg=#ff5f5f gui=NONE cterm=NONE @@ -163,7 +165,7 @@ if &background ==# 'dark' hi Underlined guifg=NONE guibg=NONE gui=underline ctermfg=NONE ctermbg=NONE cterm=underline hi Title guifg=NONE guibg=NONE gui=bold ctermfg=NONE ctermbg=NONE cterm=bold hi Directory guifg=#5fafff guibg=NONE gui=bold cterm=bold - hi Conceal guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE + hi Conceal guifg=#585858 guibg=NONE gui=NONE cterm=NONE hi Ignore guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi DiffAdd guifg=#c6c6c6 guibg=#875f87 gui=NONE cterm=NONE hi DiffChange guifg=#c6c6c6 guibg=#5f5f5f gui=NONE cterm=NONE @@ -220,6 +222,8 @@ else hi PmenuKindSel guifg=#af0000 guibg=#c6c6c6 gui=NONE cterm=NONE hi PmenuExtra guifg=#767676 guibg=#e4e4e4 gui=NONE cterm=NONE hi PmenuExtraSel guifg=#767676 guibg=#c6c6c6 gui=NONE cterm=NONE + hi PmenuMatch guifg=#af00af guibg=#e4e4e4 gui=NONE cterm=NONE + hi PmenuMatchSel guifg=#af00af guibg=#c6c6c6 gui=NONE cterm=NONE hi SignColumn guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi Error guifg=#ffffff guibg=#d70000 gui=NONE cterm=NONE hi ErrorMsg guifg=#ffffff guibg=#d70000 gui=NONE cterm=NONE @@ -258,7 +262,7 @@ else hi Underlined guifg=NONE guibg=NONE gui=underline ctermfg=NONE ctermbg=NONE cterm=underline hi Title guifg=NONE guibg=NONE gui=bold ctermfg=NONE ctermbg=NONE cterm=bold hi Directory guifg=#005fd7 guibg=NONE gui=bold cterm=bold - hi Conceal guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE + hi Conceal guifg=#9e9e9e guibg=NONE gui=NONE cterm=NONE hi Ignore guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi DiffAdd guifg=#000000 guibg=#d7afd7 gui=NONE cterm=NONE hi DiffChange guifg=#000000 guibg=#d0d0d0 gui=NONE cterm=NONE @@ -390,6 +394,8 @@ if s:t_Co >= 256 hi PmenuKindSel ctermfg=203 ctermbg=239 cterm=NONE hi PmenuExtra ctermfg=243 ctermbg=236 cterm=NONE hi PmenuExtraSel ctermfg=243 ctermbg=239 cterm=NONE + hi PmenuMatch ctermfg=176 ctermbg=236 cterm=NONE + hi PmenuMatchSel ctermfg=176 ctermbg=239 cterm=NONE hi SignColumn ctermfg=NONE ctermbg=NONE cterm=NONE hi Error ctermfg=231 ctermbg=203 cterm=NONE hi ErrorMsg ctermfg=231 ctermbg=203 cterm=NONE @@ -426,7 +432,7 @@ if s:t_Co >= 256 hi Underlined ctermfg=NONE ctermbg=NONE cterm=underline hi Title ctermfg=NONE ctermbg=NONE cterm=bold hi Directory ctermfg=75 ctermbg=NONE cterm=bold - hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE + hi Conceal ctermfg=240 ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi DiffAdd ctermfg=251 ctermbg=96 cterm=NONE hi DiffChange ctermfg=251 ctermbg=59 cterm=NONE @@ -476,6 +482,8 @@ if s:t_Co >= 256 hi PmenuKindSel ctermfg=124 ctermbg=251 cterm=NONE hi PmenuExtra ctermfg=243 ctermbg=254 cterm=NONE hi PmenuExtraSel ctermfg=243 ctermbg=251 cterm=NONE + hi PmenuMatch ctermfg=127 ctermbg=254 cterm=NONE + hi PmenuMatchSel ctermfg=127 ctermbg=251 cterm=NONE hi SignColumn ctermfg=NONE ctermbg=NONE cterm=NONE hi Error ctermfg=231 ctermbg=160 cterm=NONE hi ErrorMsg ctermfg=231 ctermbg=160 cterm=NONE @@ -512,7 +520,7 @@ if s:t_Co >= 256 hi Underlined ctermfg=NONE ctermbg=NONE cterm=underline hi Title ctermfg=NONE ctermbg=NONE cterm=bold hi Directory ctermfg=26 ctermbg=NONE cterm=bold - hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE + hi Conceal ctermfg=247 ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi DiffAdd ctermfg=16 ctermbg=182 cterm=NONE hi DiffChange ctermfg=16 ctermbg=252 cterm=NONE @@ -568,6 +576,8 @@ if s:t_Co >= 16 hi PmenuKindSel ctermfg=darkred ctermbg=darkcyan cterm=NONE hi PmenuExtra ctermfg=black ctermbg=grey cterm=NONE hi PmenuExtraSel ctermfg=black ctermbg=darkcyan cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=grey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkcyan cterm=bold hi SignColumn ctermfg=NONE ctermbg=NONE cterm=NONE hi Error ctermfg=white ctermbg=red cterm=NONE hi ErrorMsg ctermfg=white ctermbg=red cterm=NONE @@ -603,7 +613,7 @@ if s:t_Co >= 16 hi Underlined ctermfg=NONE ctermbg=NONE cterm=underline hi Title ctermfg=NONE ctermbg=NONE cterm=bold hi Directory ctermfg=blue ctermbg=NONE cterm=bold - hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE + hi Conceal ctermfg=grey ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi DiffAdd ctermfg=white ctermbg=darkmagenta cterm=NONE hi DiffChange ctermfg=white ctermbg=darkgreen cterm=NONE @@ -689,7 +699,7 @@ if s:t_Co >= 16 hi Underlined ctermfg=NONE ctermbg=NONE cterm=underline hi Title ctermfg=NONE ctermbg=NONE cterm=bold hi Directory ctermfg=darkblue ctermbg=NONE cterm=bold - hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE + hi Conceal ctermfg=darkgrey ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi DiffAdd ctermfg=black ctermbg=darkmagenta cterm=NONE hi DiffChange ctermfg=black ctermbg=lightgray cterm=NONE @@ -745,6 +755,8 @@ if s:t_Co >= 8 hi PmenuKindSel ctermfg=darkred ctermbg=darkcyan cterm=NONE hi PmenuExtra ctermfg=black ctermbg=grey cterm=NONE hi PmenuExtraSel ctermfg=black ctermbg=darkcyan cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=grey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkcyan cterm=bold hi SignColumn ctermfg=NONE ctermbg=NONE cterm=NONE hi Error ctermfg=grey ctermbg=darkred cterm=NONE hi ErrorMsg ctermfg=grey ctermbg=darkred cterm=NONE diff --git a/runtime/colors/morning.vim b/runtime/colors/morning.vim index 12f1efe9a6..82a3d6d97d 100644 --- a/runtime/colors/morning.vim +++ b/runtime/colors/morning.vim @@ -4,7 +4,7 @@ " Maintainer: Original maintainer Bram Moolenaar <Bram@vim.org> " Website: https://github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Fri 15 Dec 2023 20:05:37 +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -47,6 +47,8 @@ hi Pmenu guifg=#000000 guibg=#b2b2b2 gui=NONE cterm=NONE hi PmenuSel guifg=#000000 guibg=#ffff00 gui=NONE cterm=NONE hi PmenuSbar guifg=NONE guibg=#e4e4e4 gui=NONE cterm=NONE hi PmenuThumb guifg=NONE guibg=#000000 gui=NONE cterm=NONE +hi PmenuMatch guifg=#a52a2a guibg=#b2b2b2 gui=NONE cterm=NONE +hi PmenuMatchSel guifg=#a52a2a guibg=#ffff00 gui=NONE cterm=NONE hi TabLine guifg=#000000 guibg=#bcbcbc gui=underline cterm=underline hi TabLineFill guifg=NONE guibg=NONE gui=reverse ctermfg=NONE ctermbg=NONE cterm=reverse hi TabLineSel guifg=#000000 guibg=#e4e4e4 gui=bold cterm=bold @@ -87,7 +89,7 @@ hi Type guifg=#2e8b57 guibg=NONE gui=bold cterm=bold hi Special guifg=#6a5acd guibg=NONE gui=NONE cterm=NONE hi Ignore guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi Directory guifg=#008787 guibg=NONE gui=bold cterm=bold -hi Conceal guifg=#0000ff guibg=NONE gui=NONE cterm=NONE +hi Conceal guifg=#878787 guibg=NONE gui=NONE cterm=NONE hi Title guifg=#a52a2a guibg=NONE gui=bold cterm=bold hi DiffAdd guifg=#ffffff guibg=#5f875f gui=NONE cterm=NONE hi DiffChange guifg=#ffffff guibg=#5f87af gui=NONE cterm=NONE @@ -119,6 +121,8 @@ if s:t_Co >= 256 hi PmenuSel ctermfg=16 ctermbg=226 cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=254 cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=16 cterm=NONE + hi PmenuMatch ctermfg=124 ctermbg=249 cterm=NONE + hi PmenuMatchSel ctermfg=124 ctermbg=226 cterm=NONE hi TabLine ctermfg=16 ctermbg=250 cterm=underline hi TabLineFill ctermfg=NONE ctermbg=NONE cterm=reverse hi TabLineSel ctermfg=16 ctermbg=254 cterm=bold @@ -159,7 +163,7 @@ if s:t_Co >= 256 hi Special ctermfg=62 ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi Directory ctermfg=30 ctermbg=NONE cterm=bold - hi Conceal ctermfg=21 ctermbg=NONE cterm=NONE + hi Conceal ctermfg=102 ctermbg=NONE cterm=NONE hi Title ctermfg=124 ctermbg=NONE cterm=bold hi DiffAdd ctermfg=231 ctermbg=65 cterm=NONE hi DiffChange ctermfg=231 ctermbg=67 cterm=NONE @@ -184,6 +188,8 @@ if s:t_Co >= 16 hi PmenuSel ctermfg=black ctermbg=yellow cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=grey cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=black cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=white cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=yellow cterm=bold hi TabLine ctermfg=black ctermbg=white cterm=underline hi TabLineFill ctermfg=NONE ctermbg=NONE cterm=reverse hi TabLineSel ctermfg=black ctermbg=grey cterm=bold @@ -224,7 +230,7 @@ if s:t_Co >= 16 hi Special ctermfg=darkblue ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi Directory ctermfg=darkcyan ctermbg=NONE cterm=bold - hi Conceal ctermfg=blue ctermbg=NONE cterm=NONE + hi Conceal ctermfg=gray ctermbg=NONE cterm=NONE hi Title ctermfg=darkred ctermbg=NONE cterm=bold hi DiffAdd ctermfg=white ctermbg=darkgreen cterm=NONE hi DiffChange ctermfg=white ctermbg=blue cterm=NONE @@ -249,6 +255,8 @@ if s:t_Co >= 8 hi PmenuSel ctermfg=black ctermbg=darkyellow cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=darkgreen cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=darkcyan cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkyellow cterm=bold hi TabLine ctermfg=gray ctermbg=black cterm=NONE hi TabLineFill ctermfg=NONE ctermbg=NONE cterm=reverse hi TabLineSel ctermfg=black ctermbg=gray cterm=NONE diff --git a/runtime/colors/murphy.vim b/runtime/colors/murphy.vim index c1612fbc0e..f38c8259dd 100644 --- a/runtime/colors/murphy.vim +++ b/runtime/colors/murphy.vim @@ -4,7 +4,7 @@ " Maintainer: Original maintainer Ron Aaron <ron@ronware.org>. " Website: https://github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Mon 08 Jan 2024 09:50:15 AM AEDT +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -43,6 +43,8 @@ hi Pmenu guifg=#ffffff guibg=#444444 gui=NONE cterm=NONE hi PmenuSel guifg=#000000 guibg=#ffff00 gui=NONE cterm=NONE hi PmenuSbar guifg=NONE guibg=#303030 gui=NONE cterm=NONE hi PmenuThumb guifg=NONE guibg=#bcbcbc gui=NONE cterm=NONE +hi PmenuMatch guifg=#ff00ff guibg=#444444 gui=NONE cterm=NONE +hi PmenuMatchSel guifg=#ff00ff guibg=#ffff00 gui=NONE cterm=NONE hi TabLineFill guifg=NONE guibg=#303030 gui=NONE cterm=NONE hi TabLine guifg=#87ff87 guibg=#444444 gui=NONE cterm=NONE hi TabLineSel guifg=#ffffff guibg=#000000 gui=NONE cterm=NONE @@ -116,6 +118,8 @@ if s:t_Co >= 256 hi PmenuSel ctermfg=16 ctermbg=226 cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=236 cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=250 cterm=NONE + hi PmenuMatch ctermfg=201 ctermbg=238 cterm=NONE + hi PmenuMatchSel ctermfg=201 ctermbg=226 cterm=NONE hi TabLineFill ctermfg=NONE ctermbg=236 cterm=NONE hi TabLine ctermfg=120 ctermbg=238 cterm=NONE hi TabLineSel ctermfg=231 ctermbg=16 cterm=NONE @@ -181,6 +185,8 @@ if s:t_Co >= 16 hi PmenuSel ctermfg=black ctermbg=yellow cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=black cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=grey cterm=NONE + hi PmenuMatch ctermfg=white ctermbg=darkgrey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=yellow cterm=bold hi TabLineFill ctermfg=NONE ctermbg=grey cterm=NONE hi TabLine ctermfg=green ctermbg=darkgrey cterm=NONE hi TabLineSel ctermfg=white ctermbg=black cterm=NONE @@ -246,6 +252,8 @@ if s:t_Co >= 8 hi PmenuSel ctermfg=black ctermbg=darkyellow cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=black cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=grey cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=darkcyan cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkyellow cterm=bold hi TabLineFill ctermfg=NONE ctermbg=grey cterm=NONE hi TabLine ctermfg=grey ctermbg=black cterm=reverse hi TabLineSel ctermfg=grey ctermbg=black cterm=NONE diff --git a/runtime/colors/pablo.vim b/runtime/colors/pablo.vim index f53739bc6d..de585adfe2 100644 --- a/runtime/colors/pablo.vim +++ b/runtime/colors/pablo.vim @@ -3,7 +3,7 @@ " Maintainer: Original maintainerRon Aaron <ron@ronware.org> " Website: https://github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Fri 15 Dec 2023 20:05:38 +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -42,7 +42,7 @@ hi Underlined guifg=#80a0ff guibg=NONE gui=underline cterm=underline hi Ignore guifg=#000000 guibg=#000000 gui=NONE cterm=NONE hi Error guifg=#ffffff guibg=#ff0000 gui=NONE cterm=NONE hi Todo guifg=#000000 guibg=#c0c000 gui=NONE cterm=NONE -hi Conceal guifg=#e5e5e5 guibg=#a9a9a9 gui=NONE cterm=NONE +hi Conceal guifg=#666666 guibg=NONE gui=NONE cterm=NONE hi Cursor guifg=#000000 guibg=#ffffff gui=NONE cterm=NONE hi lCursor guifg=#000000 guibg=#ffffff gui=NONE cterm=NONE hi CursorIM guifg=NONE guibg=fg gui=NONE cterm=NONE @@ -85,6 +85,8 @@ hi TabLineFill guifg=NONE guibg=#000000 gui=reverse cterm=reverse hi TabLineSel guifg=#ffffff guibg=#000000 gui=bold cterm=bold hi ToolbarLine guifg=NONE guibg=#000000 gui=NONE cterm=NONE hi ToolbarButton guifg=#000000 guibg=#e5e5e5 gui=bold cterm=bold +hi PmenuMatch guifg=#ff00ff guibg=#303030 gui=NONE cterm=NONE +hi PmenuMatchSel guifg=#ff00ff guibg=#e5e5e5 gui=NONE cterm=NONE hi Pmenu guifg=fg guibg=#303030 gui=NONE cterm=NONE hi PmenuSbar guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuSel guifg=#000000 guibg=#e5e5e5 gui=NONE cterm=NONE @@ -115,7 +117,7 @@ if s:t_Co >= 256 hi Ignore ctermfg=16 ctermbg=16 cterm=NONE hi Error ctermfg=231 ctermbg=196 cterm=NONE hi Todo ctermfg=16 ctermbg=142 cterm=NONE - hi Conceal ctermfg=254 ctermbg=248 cterm=NONE + hi Conceal ctermfg=241 ctermbg=NONE cterm=NONE hi Cursor ctermfg=16 ctermbg=231 cterm=NONE hi lCursor ctermfg=16 ctermbg=231 cterm=NONE hi CursorIM ctermfg=NONE ctermbg=fg cterm=NONE @@ -158,6 +160,8 @@ if s:t_Co >= 256 hi TabLineSel ctermfg=231 ctermbg=16 cterm=bold hi ToolbarLine ctermfg=NONE ctermbg=16 cterm=NONE hi ToolbarButton ctermfg=16 ctermbg=254 cterm=bold + hi PmenuMatch ctermfg=201 ctermbg=236 cterm=NONE + hi PmenuMatchSel ctermfg=201 ctermbg=254 cterm=NONE hi Pmenu ctermfg=fg ctermbg=236 cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuSel ctermfg=16 ctermbg=254 cterm=NONE @@ -183,7 +187,7 @@ if s:t_Co >= 16 hi Ignore ctermfg=black ctermbg=black cterm=NONE hi Error ctermfg=white ctermbg=red cterm=NONE hi Todo ctermfg=black ctermbg=darkyellow cterm=NONE - hi Conceal ctermfg=grey ctermbg=grey cterm=NONE + hi Conceal ctermfg=darkgrey ctermbg=NONE cterm=NONE hi Cursor ctermfg=black ctermbg=white cterm=NONE hi lCursor ctermfg=black ctermbg=white cterm=NONE hi CursorIM ctermfg=NONE ctermbg=fg cterm=NONE @@ -226,6 +230,8 @@ if s:t_Co >= 16 hi TabLineSel ctermfg=white ctermbg=black cterm=bold hi ToolbarLine ctermfg=NONE ctermbg=black cterm=NONE hi ToolbarButton ctermfg=black ctermbg=grey cterm=bold + hi PmenuMatch ctermfg=fg ctermbg=darkgrey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=grey cterm=bold hi Pmenu ctermfg=fg ctermbg=darkgrey cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuSel ctermfg=black ctermbg=grey cterm=NONE @@ -250,6 +256,8 @@ if s:t_Co >= 8 hi PmenuSel ctermfg=black ctermbg=darkyellow cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=black cterm=NONE hi PmenuThumb ctermfg=black ctermbg=darkyellow cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=grey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkyellow cterm=bold hi TabLine ctermfg=black ctermbg=grey cterm=NONE hi TabLineFill ctermfg=NONE ctermbg=grey cterm=NONE hi TabLineSel ctermfg=grey ctermbg=black cterm=NONE diff --git a/runtime/colors/peachpuff.vim b/runtime/colors/peachpuff.vim index f4c1e21697..91c98119b3 100644 --- a/runtime/colors/peachpuff.vim +++ b/runtime/colors/peachpuff.vim @@ -4,7 +4,7 @@ " Maintainer: Original maintainer David Ne\v{c}as (Yeti) <yeti@physics.muni.cz> " Website: https://github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Fri 15 Dec 2023 20:05:39 +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -44,9 +44,11 @@ hi StatusLineTerm guifg=#ffffff guibg=#2e8b57 gui=bold cterm=bold hi StatusLineTermNC guifg=#ffdab9 guibg=#008b8b gui=bold cterm=bold hi VertSplit guifg=#ffdab9 guibg=#737373 gui=NONE cterm=NONE hi Pmenu guifg=#000000 guibg=#ffaf87 gui=NONE cterm=NONE -hi PmenuSel guifg=#000000 guibg=#f5c195 gui=bold cterm=bold hi PmenuSbar guifg=NONE guibg=#ffdab9 gui=NONE cterm=NONE hi PmenuThumb guifg=NONE guibg=#737373 gui=NONE cterm=NONE +hi PmenuSel guifg=#000000 guibg=#f5c195 gui=bold cterm=bold +hi PmenuMatch guifg=#a52a2a guibg=#ffaf87 gui=NONE cterm=NONE +hi PmenuMatchSel guifg=#a52a2a guibg=#f5c195 gui=bold cterm=bold hi TabLine guifg=#ffdab9 guibg=#737373 gui=underline cterm=underline hi TabLineFill guifg=NONE guibg=NONE gui=reverse ctermfg=NONE ctermbg=NONE cterm=reverse hi TabLineSel guifg=#000000 guibg=#ffdab9 gui=bold cterm=bold @@ -86,7 +88,7 @@ hi PreProc guifg=#cd00cd guibg=NONE gui=NONE cterm=NONE hi Type guifg=#2e8b57 guibg=NONE gui=bold cterm=bold hi Special guifg=#6a5acd guibg=NONE gui=NONE cterm=NONE hi Directory guifg=#008b8b guibg=NONE gui=bold cterm=bold -hi Conceal guifg=#406090 guibg=NONE gui=NONE cterm=NONE +hi Conceal guifg=#737373 guibg=NONE gui=NONE cterm=NONE hi Ignore guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi Title guifg=#cd00cd guibg=NONE gui=bold cterm=bold hi DiffAdd guifg=#ffffff guibg=#5f875f gui=NONE cterm=NONE @@ -116,9 +118,11 @@ if s:t_Co >= 256 hi StatusLineTermNC ctermfg=223 ctermbg=30 cterm=bold hi VertSplit ctermfg=223 ctermbg=243 cterm=NONE hi Pmenu ctermfg=16 ctermbg=216 cterm=NONE - hi PmenuSel ctermfg=16 ctermbg=180 cterm=bold hi PmenuSbar ctermfg=NONE ctermbg=223 cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=243 cterm=NONE + hi PmenuSel ctermfg=16 ctermbg=180 cterm=bold + hi PmenuMatch ctermfg=124 ctermbg=216 cterm=NONE + hi PmenuMatchSel ctermfg=124 ctermbg=180 cterm=bold hi TabLine ctermfg=223 ctermbg=243 cterm=underline hi TabLineFill ctermfg=NONE ctermbg=NONE cterm=reverse hi TabLineSel ctermfg=16 ctermbg=223 cterm=bold @@ -158,7 +162,7 @@ if s:t_Co >= 256 hi Type ctermfg=29 ctermbg=NONE cterm=bold hi Special ctermfg=62 ctermbg=NONE cterm=NONE hi Directory ctermfg=30 ctermbg=NONE cterm=bold - hi Conceal ctermfg=25 ctermbg=NONE cterm=NONE + hi Conceal ctermfg=243 ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi Title ctermfg=164 ctermbg=NONE cterm=bold hi DiffAdd ctermfg=231 ctermbg=65 cterm=NONE @@ -183,9 +187,11 @@ if s:t_Co >= 16 hi StatusLineTermNC ctermfg=white ctermbg=darkcyan cterm=bold hi VertSplit ctermfg=white ctermbg=darkgrey cterm=NONE hi Pmenu ctermfg=black ctermbg=grey cterm=NONE - hi PmenuSel ctermfg=black ctermbg=yellow cterm=bold hi PmenuSbar ctermfg=NONE ctermbg=white cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=darkgrey cterm=NONE + hi PmenuSel ctermfg=black ctermbg=yellow cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=grey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=yellow cterm=bold hi TabLine ctermfg=white ctermbg=darkgrey cterm=underline hi TabLineFill ctermfg=NONE ctermbg=NONE cterm=reverse hi TabLineSel ctermfg=black ctermbg=white cterm=bold @@ -253,6 +259,8 @@ if s:t_Co >= 8 hi PmenuSel ctermfg=black ctermbg=darkyellow cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=darkgreen cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=darkcyan cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkyellow cterm=bold hi TabLine ctermfg=gray ctermbg=black cterm=NONE hi TabLineFill ctermfg=NONE ctermbg=NONE cterm=reverse hi TabLineSel ctermfg=black ctermbg=white cterm=NONE diff --git a/runtime/colors/quiet.vim b/runtime/colors/quiet.vim index d7f8582888..bcf2eced16 100644 --- a/runtime/colors/quiet.vim +++ b/runtime/colors/quiet.vim @@ -4,7 +4,7 @@ " Maintainer: Maxence Weynans <neutaaaaan@gmail.com> " Website: https://github.com/vim/colorschemes " License: Vim License (see `:help license`)` -" Last Updated: Fri 15 Dec 2023 20:05:39 +" Last Change: 2024 Aug 05 " Generated by Colortemplate v2.2.3 @@ -14,6 +14,9 @@ let g:colors_name = 'quiet' let s:t_Co = &t_Co +hi! link Added Normal +hi! link Changed Normal +hi! link Removed Normal hi! link Terminal Normal hi! link StatusLineTerm StatusLine hi! link StatusLineTermNC StatusLineNC @@ -79,10 +82,12 @@ if &background ==# 'dark' hi MoreMsg guifg=#dadada guibg=NONE gui=NONE cterm=NONE hi NonText guifg=#707070 guibg=NONE gui=NONE cterm=NONE hi Pmenu guifg=#000000 guibg=#a8a8a8 gui=NONE cterm=NONE + hi PmenuMatch guifg=#d7005f guibg=#a8a8a8 gui=NONE cterm=NONE hi PmenuExtra guifg=#000000 guibg=#a8a8a8 gui=NONE cterm=NONE hi PmenuKind guifg=#000000 guibg=#a8a8a8 gui=bold cterm=bold hi PmenuSbar guifg=#707070 guibg=#585858 gui=NONE cterm=NONE hi PmenuSel guifg=#000000 guibg=#dadada gui=NONE cterm=NONE + hi PmenuMatchSel guifg=#d7005f guibg=#dadada gui=bold cterm=bold hi PmenuExtraSel guifg=#000000 guibg=#dadada gui=NONE cterm=NONE hi PmenuKindSel guifg=#000000 guibg=#dadada gui=bold cterm=bold hi PmenuThumb guifg=#dadada guibg=#dadada gui=NONE cterm=NONE @@ -153,10 +158,12 @@ else hi MoreMsg guifg=#000000 guibg=NONE gui=NONE cterm=NONE hi NonText guifg=#626262 guibg=NONE gui=NONE cterm=NONE hi Pmenu guifg=#000000 guibg=#a8a8a8 gui=NONE cterm=NONE + hi PmenuMatch guifg=#d70000 guibg=#a8a8a8 gui=NONE cterm=NONE hi PmenuExtra guifg=#000000 guibg=#a8a8a8 gui=NONE cterm=NONE hi PmenuKind guifg=#000000 guibg=#a8a8a8 gui=bold cterm=bold hi PmenuSbar guifg=#000000 guibg=#e4e4e4 gui=NONE cterm=NONE hi PmenuSel guifg=#d7d7d7 guibg=#000000 gui=NONE cterm=NONE + hi PmenuMatchSel guifg=#d70000 guibg=#000000 gui=bold cterm=bold hi PmenuExtraSel guifg=#d7d7d7 guibg=#000000 gui=NONE cterm=NONE hi PmenuKindSel guifg=#d7d7d7 guibg=#000000 gui=bold cterm=bold hi PmenuThumb guifg=#000000 guibg=#000000 gui=NONE cterm=NONE @@ -222,10 +229,12 @@ if s:t_Co >= 256 hi MoreMsg ctermfg=253 ctermbg=NONE cterm=NONE hi NonText ctermfg=242 ctermbg=NONE cterm=NONE hi Pmenu ctermfg=16 ctermbg=248 cterm=NONE + hi PmenuMatch ctermfg=161 ctermbg=248 cterm=NONE hi PmenuExtra ctermfg=16 ctermbg=248 cterm=NONE hi PmenuKind ctermfg=16 ctermbg=248 cterm=bold hi PmenuSbar ctermfg=242 ctermbg=240 cterm=NONE hi PmenuSel ctermfg=16 ctermbg=253 cterm=NONE + hi PmenuMatchSel ctermfg=161 ctermbg=253 cterm=bold hi PmenuExtraSel ctermfg=16 ctermbg=253 cterm=NONE hi PmenuKindSel ctermfg=16 ctermbg=253 cterm=bold hi PmenuThumb ctermfg=253 ctermbg=253 cterm=NONE @@ -289,10 +298,12 @@ if s:t_Co >= 256 hi MoreMsg ctermfg=16 ctermbg=NONE cterm=NONE hi NonText ctermfg=241 ctermbg=NONE cterm=NONE hi Pmenu ctermfg=16 ctermbg=248 cterm=NONE + hi PmenuMatch ctermfg=160 ctermbg=248 cterm=NONE hi PmenuExtra ctermfg=16 ctermbg=248 cterm=NONE hi PmenuKind ctermfg=16 ctermbg=248 cterm=bold hi PmenuSbar ctermfg=16 ctermbg=254 cterm=NONE hi PmenuSel ctermfg=188 ctermbg=16 cterm=NONE + hi PmenuMatchSel ctermfg=160 ctermbg=16 cterm=bold hi PmenuExtraSel ctermfg=188 ctermbg=16 cterm=NONE hi PmenuKindSel ctermfg=188 ctermbg=16 cterm=bold hi PmenuThumb ctermfg=16 ctermbg=16 cterm=NONE @@ -368,9 +379,11 @@ if s:t_Co >= 16 hi ModeMsg ctermfg=NONE ctermbg=NONE cterm=bold hi MoreMsg ctermfg=NONE ctermbg=NONE cterm=NONE hi Pmenu ctermfg=NONE ctermbg=NONE cterm=reverse + hi PmenuMatch ctermfg=NONE ctermbg=darkred cterm=reverse hi PmenuExtra ctermfg=NONE ctermbg=NONE cterm=reverse hi PmenuKind ctermfg=NONE ctermbg=NONE cterm=bold,reverse hi PmenuSel ctermfg=NONE ctermbg=NONE cterm=bold + hi PmenuMatchSel ctermfg=darkred ctermbg=NONE cterm=bold hi PmenuExtraSel ctermfg=NONE ctermbg=NONE cterm=bold hi PmenuKindSel ctermfg=NONE ctermbg=NONE cterm=bold hi PmenuThumb ctermfg=NONE ctermbg=NONE cterm=NONE @@ -434,9 +447,11 @@ if s:t_Co >= 16 hi ModeMsg ctermfg=NONE ctermbg=NONE cterm=bold hi MoreMsg ctermfg=NONE ctermbg=NONE cterm=NONE hi Pmenu ctermfg=NONE ctermbg=NONE cterm=reverse + hi PmenuMatch ctermfg=NONE ctermbg=darkred cterm=reverse hi PmenuExtra ctermfg=NONE ctermbg=NONE cterm=reverse hi PmenuKind ctermfg=NONE ctermbg=NONE cterm=bold,reverse hi PmenuSel ctermfg=NONE ctermbg=NONE cterm=bold + hi PmenuMatchSel ctermfg=darkred ctermbg=NONE cterm=bold hi PmenuExtraSel ctermfg=NONE ctermbg=NONE cterm=bold hi PmenuKindSel ctermfg=NONE ctermbg=NONE cterm=bold hi PmenuThumb ctermfg=NONE ctermbg=NONE cterm=NONE @@ -507,9 +522,11 @@ if s:t_Co >= 8 hi ModeMsg ctermfg=NONE ctermbg=NONE cterm=bold hi MoreMsg ctermfg=NONE ctermbg=NONE cterm=NONE hi Pmenu ctermfg=NONE ctermbg=NONE cterm=reverse + hi PmenuMatch ctermfg=NONE ctermbg=darkred cterm=reverse hi PmenuExtra ctermfg=NONE ctermbg=NONE cterm=reverse hi PmenuKind ctermfg=NONE ctermbg=NONE cterm=bold,reverse hi PmenuSel ctermfg=NONE ctermbg=NONE cterm=bold + hi PmenuMatchSel ctermfg=darkred ctermbg=NONE cterm=bold hi PmenuExtraSel ctermfg=NONE ctermbg=NONE cterm=bold hi PmenuKindSel ctermfg=NONE ctermbg=NONE cterm=bold hi PmenuThumb ctermfg=NONE ctermbg=NONE cterm=NONE @@ -573,9 +590,11 @@ if s:t_Co >= 8 hi ModeMsg ctermfg=NONE ctermbg=NONE cterm=bold hi MoreMsg ctermfg=NONE ctermbg=NONE cterm=NONE hi Pmenu ctermfg=NONE ctermbg=NONE cterm=reverse + hi PmenuMatch ctermfg=NONE ctermbg=darkred cterm=reverse hi PmenuExtra ctermfg=NONE ctermbg=NONE cterm=reverse hi PmenuKind ctermfg=NONE ctermbg=NONE cterm=bold,reverse hi PmenuSel ctermfg=NONE ctermbg=NONE cterm=bold + hi PmenuMatchSel ctermfg=darkred ctermbg=NONE cterm=bold hi PmenuExtraSel ctermfg=NONE ctermbg=NONE cterm=bold hi PmenuKindSel ctermfg=NONE ctermbg=NONE cterm=bold hi PmenuThumb ctermfg=NONE ctermbg=NONE cterm=NONE diff --git a/runtime/colors/retrobox.vim b/runtime/colors/retrobox.vim index b4a194d885..a89bf0557e 100644 --- a/runtime/colors/retrobox.vim +++ b/runtime/colors/retrobox.vim @@ -4,7 +4,7 @@ " Maintainer: Maxim Kim <habamax@gmail.com>, ported from gruvbox8 of Lifepillar <lifepillar@lifepillar.me> " Website: https://www.github.com/vim/colorschemes " License: Vim License (see `:help license`) -" Last Updated: Fri 15 Dec 2023 20:05:40 +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -22,7 +22,8 @@ hi! link Tag Special hi! link lCursor Cursor hi! link MessageWindow PMenu hi! link PopupNotification Todo -hi! link CurSearch Search +hi! link CurSearch IncSearch +hi! link Terminal Normal if &background ==# 'dark' if (has('termguicolors') && &termguicolors) || has('gui_running') @@ -33,7 +34,7 @@ if &background ==# 'dark' endfor endif hi Normal guifg=#ebdbb2 guibg=#1c1c1c gui=NONE cterm=NONE - hi CursorLineNr guifg=#fabd2f guibg=#303030 gui=NONE cterm=NONE + hi CursorLineNr guifg=#fabd2f guibg=#1c1c1c gui=bold cterm=bold hi FoldColumn guifg=#928374 guibg=#1c1c1c gui=NONE cterm=NONE hi SignColumn guifg=#928374 guibg=#1c1c1c gui=NONE cterm=NONE hi VertSplit guifg=#303030 guibg=#1c1c1c gui=NONE cterm=NONE @@ -54,6 +55,8 @@ if &background ==# 'dark' hi PmenuKindSel guifg=#fb4934 guibg=#83a598 gui=NONE cterm=NONE hi PmenuExtra guifg=#a89984 guibg=#3c3836 gui=NONE cterm=NONE hi PmenuExtraSel guifg=#303030 guibg=#83a598 gui=NONE cterm=NONE + hi PmenuMatch guifg=#b16286 guibg=#3c3836 gui=NONE cterm=NONE + hi PmenuMatchSel guifg=#b16286 guibg=#83a598 gui=bold cterm=bold hi SpecialKey guifg=#928374 guibg=NONE gui=NONE cterm=NONE hi StatusLine guifg=#504945 guibg=#ebdbb2 gui=bold,reverse cterm=bold,reverse hi StatusLineNC guifg=#3c3836 guibg=#a89984 gui=reverse cterm=reverse @@ -65,7 +68,7 @@ if &background ==# 'dark' hi Visual guifg=#1c1c1c guibg=#83a598 gui=NONE cterm=NONE hi WildMenu guifg=#83a598 guibg=#504945 gui=bold cterm=bold hi EndOfBuffer guifg=#504945 guibg=NONE gui=NONE cterm=NONE - hi Conceal guifg=#83a598 guibg=NONE gui=NONE cterm=NONE + hi Conceal guifg=#504945 guibg=NONE gui=NONE cterm=NONE hi Cursor guifg=#1c1c1c guibg=#fbf1c7 gui=NONE cterm=NONE hi DiffAdd guifg=#b8bb26 guibg=#1c1c1c gui=reverse cterm=reverse hi DiffChange guifg=#8ec07c guibg=#1c1c1c gui=reverse cterm=reverse @@ -128,7 +131,7 @@ else endfor endif hi Normal guifg=#3c3836 guibg=#fbf1c7 gui=NONE cterm=NONE - hi CursorLineNr guifg=#b57614 guibg=#e5d4b1 gui=NONE cterm=NONE + hi CursorLineNr guifg=#b57614 guibg=#fbf1c7 gui=bold cterm=bold hi FoldColumn guifg=#928374 guibg=#fbf1c7 gui=NONE cterm=NONE hi SignColumn guifg=#3c3836 guibg=#fbf1c7 gui=NONE cterm=NONE hi VertSplit guifg=#bdae93 guibg=#fbf1c7 gui=NONE cterm=NONE @@ -149,6 +152,8 @@ else hi PmenuKindSel guifg=#9d0006 guibg=#076678 gui=NONE cterm=NONE hi PmenuExtra guifg=#7c6f64 guibg=#e5d4b1 gui=NONE cterm=NONE hi PmenuExtraSel guifg=#bdae93 guibg=#076678 gui=NONE cterm=NONE + hi PmenuMatch guifg=#8f3f71 guibg=#e5d4b1 gui=NONE cterm=NONE + hi PmenuMatchSel guifg=#d3869b guibg=#076678 gui=bold cterm=bold hi SpecialKey guifg=#928374 guibg=NONE gui=NONE cterm=NONE hi StatusLine guifg=#bdae93 guibg=#3c3836 gui=bold,reverse cterm=bold,reverse hi StatusLineNC guifg=#ebdbb2 guibg=#3c3836 gui=reverse cterm=reverse @@ -160,7 +165,7 @@ else hi Visual guifg=#fbf1c7 guibg=#076678 gui=NONE cterm=NONE hi WildMenu guifg=#076678 guibg=#e5d4b1 gui=bold cterm=bold hi EndOfBuffer guifg=#e5d4b1 guibg=NONE gui=NONE cterm=NONE - hi Conceal guifg=#076678 guibg=NONE gui=NONE cterm=NONE + hi Conceal guifg=#a89984 guibg=NONE gui=NONE cterm=NONE hi Cursor guifg=#fbf1c7 guibg=#282828 gui=NONE cterm=NONE hi DiffAdd guifg=#79740e guibg=#fbf1c7 gui=reverse cterm=reverse hi DiffChange guifg=#427b58 guibg=#fbf1c7 gui=reverse cterm=reverse @@ -218,7 +223,7 @@ endif if s:t_Co >= 256 if &background ==# 'dark' hi Normal ctermfg=187 ctermbg=234 cterm=NONE - hi CursorLineNr ctermfg=214 ctermbg=236 cterm=NONE + hi CursorLineNr ctermfg=214 ctermbg=234 cterm=bold hi FoldColumn ctermfg=102 ctermbg=234 cterm=NONE hi SignColumn ctermfg=102 ctermbg=234 cterm=NONE hi VertSplit ctermfg=236 ctermbg=234 cterm=NONE @@ -239,6 +244,8 @@ if s:t_Co >= 256 hi PmenuKindSel ctermfg=203 ctermbg=109 cterm=NONE hi PmenuExtra ctermfg=102 ctermbg=237 cterm=NONE hi PmenuExtraSel ctermfg=236 ctermbg=109 cterm=NONE + hi PmenuMatch ctermfg=132 ctermbg=237 cterm=NONE + hi PmenuMatchSel ctermfg=132 ctermbg=109 cterm=bold hi SpecialKey ctermfg=102 ctermbg=NONE cterm=NONE hi StatusLine ctermfg=239 ctermbg=187 cterm=bold,reverse hi StatusLineNC ctermfg=237 ctermbg=102 cterm=reverse @@ -250,7 +257,7 @@ if s:t_Co >= 256 hi Visual ctermfg=234 ctermbg=109 cterm=NONE hi WildMenu ctermfg=109 ctermbg=239 cterm=bold hi EndOfBuffer ctermfg=239 ctermbg=NONE cterm=NONE - hi Conceal ctermfg=109 ctermbg=NONE cterm=NONE + hi Conceal ctermfg=239 ctermbg=NONE cterm=NONE hi Cursor ctermfg=234 ctermbg=230 cterm=NONE hi DiffAdd ctermfg=142 ctermbg=234 cterm=reverse hi DiffChange ctermfg=107 ctermbg=234 cterm=reverse @@ -306,7 +313,7 @@ if s:t_Co >= 256 else " Light background hi Normal ctermfg=237 ctermbg=230 cterm=NONE - hi CursorLineNr ctermfg=172 ctermbg=188 cterm=NONE + hi CursorLineNr ctermfg=172 ctermbg=230 cterm=bold hi FoldColumn ctermfg=102 ctermbg=230 cterm=NONE hi SignColumn ctermfg=237 ctermbg=230 cterm=NONE hi VertSplit ctermfg=144 ctermbg=230 cterm=NONE @@ -327,6 +334,8 @@ if s:t_Co >= 256 hi PmenuKindSel ctermfg=124 ctermbg=23 cterm=NONE hi PmenuExtra ctermfg=243 ctermbg=188 cterm=NONE hi PmenuExtraSel ctermfg=144 ctermbg=23 cterm=NONE + hi PmenuMatch ctermfg=126 ctermbg=188 cterm=NONE + hi PmenuMatchSel ctermfg=175 ctermbg=23 cterm=bold hi SpecialKey ctermfg=102 ctermbg=NONE cterm=NONE hi StatusLine ctermfg=144 ctermbg=237 cterm=bold,reverse hi StatusLineNC ctermfg=187 ctermbg=237 cterm=reverse @@ -338,7 +347,7 @@ if s:t_Co >= 256 hi Visual ctermfg=230 ctermbg=23 cterm=NONE hi WildMenu ctermfg=23 ctermbg=188 cterm=bold hi EndOfBuffer ctermfg=188 ctermbg=NONE cterm=NONE - hi Conceal ctermfg=23 ctermbg=NONE cterm=NONE + hi Conceal ctermfg=137 ctermbg=NONE cterm=NONE hi Cursor ctermfg=230 ctermbg=235 cterm=NONE hi DiffAdd ctermfg=64 ctermbg=230 cterm=reverse hi DiffChange ctermfg=29 ctermbg=230 cterm=reverse @@ -418,6 +427,8 @@ if s:t_Co >= 16 hi PmenuKindSel ctermfg=DarkRed ctermbg=Blue cterm=NONE hi PmenuExtra ctermfg=gray ctermbg=DarkGray cterm=NONE hi PmenuExtraSel ctermfg=Black ctermbg=Blue cterm=NONE + hi PmenuMatch ctermfg=White ctermbg=DarkGray cterm=bold + hi PmenuMatchSel ctermfg=Black ctermbg=Blue cterm=bold hi SignColumn ctermfg=DarkGray ctermbg=NONE cterm=NONE hi SpecialKey ctermfg=DarkGray ctermbg=NONE cterm=NONE hi StatusLine ctermfg=gray ctermbg=Black cterm=bold,reverse @@ -431,7 +442,7 @@ if s:t_Co >= 16 hi Visual ctermfg=Black ctermbg=Blue cterm=NONE hi WildMenu ctermfg=White ctermbg=Black cterm=bold hi EndOfBuffer ctermfg=DarkGray ctermbg=NONE cterm=NONE - hi Conceal ctermfg=Blue ctermbg=NONE cterm=NONE + hi Conceal ctermfg=DarkGray ctermbg=NONE cterm=NONE hi Cursor ctermfg=Black ctermbg=White cterm=NONE hi DiffAdd ctermfg=Green ctermbg=Black cterm=reverse hi DiffChange ctermfg=Cyan ctermbg=Black cterm=reverse @@ -506,6 +517,8 @@ if s:t_Co >= 16 hi PmenuKindSel ctermfg=DarkRed ctermbg=Blue cterm=NONE hi PmenuExtra ctermfg=DarkGray ctermbg=Grey cterm=NONE hi PmenuExtraSel ctermfg=White ctermbg=Blue cterm=NONE + hi PmenuMatch ctermfg=Black ctermbg=Grey cterm=bold + hi PmenuMatchSel ctermfg=White ctermbg=Blue cterm=bold hi SignColumn ctermfg=Grey ctermbg=NONE cterm=NONE hi SpecialKey ctermfg=Grey ctermbg=NONE cterm=NONE hi StatusLine ctermfg=DarkGray ctermbg=White cterm=bold,reverse @@ -519,7 +532,7 @@ if s:t_Co >= 16 hi Visual ctermfg=White ctermbg=Blue cterm=NONE hi WildMenu ctermfg=Black ctermbg=White cterm=bold hi EndOfBuffer ctermfg=Grey ctermbg=NONE cterm=NONE - hi Conceal ctermfg=Blue ctermbg=NONE cterm=NONE + hi Conceal ctermfg=Grey ctermbg=NONE cterm=NONE hi Cursor ctermfg=White ctermbg=DarkGray cterm=NONE hi DiffAdd ctermfg=Green ctermbg=White cterm=reverse hi DiffChange ctermfg=Cyan ctermbg=White cterm=reverse @@ -599,6 +612,8 @@ if s:t_Co >= 8 hi PmenuKindSel ctermfg=Red ctermbg=Blue cterm=NONE hi PmenuExtra ctermfg=DarkGray ctermbg=White cterm=NONE hi PmenuExtraSel ctermfg=DarkGray ctermbg=Blue cterm=NONE + hi PmenuMatch ctermfg=DarkGray ctermbg=White cterm=bold + hi PmenuMatchSel ctermfg=Black ctermbg=Blue cterm=bold hi SignColumn ctermfg=gray ctermbg=NONE cterm=NONE hi SpecialKey ctermfg=gray ctermbg=NONE cterm=NONE hi StatusLine ctermfg=gray ctermbg=Black cterm=bold,reverse @@ -612,7 +627,7 @@ if s:t_Co >= 8 hi Visual ctermfg=Black ctermbg=Blue cterm=NONE hi WildMenu ctermfg=Blue ctermbg=DarkGray cterm=bold hi EndOfBuffer ctermfg=NONE ctermbg=NONE cterm=NONE - hi Conceal ctermfg=Blue ctermbg=NONE cterm=NONE + hi Conceal ctermfg=DarkGray ctermbg=NONE cterm=NONE hi Cursor ctermfg=Black ctermbg=White cterm=NONE hi DiffAdd ctermfg=Green ctermbg=Black cterm=reverse hi DiffChange ctermfg=Cyan ctermbg=Black cterm=reverse @@ -687,6 +702,8 @@ if s:t_Co >= 8 hi PmenuKindSel ctermfg=Red ctermbg=Blue cterm=NONE hi PmenuExtra ctermfg=Grey ctermbg=Black cterm=NONE hi PmenuExtraSel ctermfg=Grey ctermbg=Blue cterm=NONE + hi PmenuMatch ctermfg=Grey ctermbg=Black cterm=bold + hi PmenuMatchSel ctermfg=White ctermbg=Blue cterm=bold hi SignColumn ctermfg=Black ctermbg=NONE cterm=NONE hi SpecialKey ctermfg=Black ctermbg=NONE cterm=NONE hi StatusLine ctermfg=Black ctermbg=White cterm=bold,reverse @@ -700,7 +717,7 @@ if s:t_Co >= 8 hi Visual ctermfg=White ctermbg=Blue cterm=NONE hi WildMenu ctermfg=Blue ctermbg=Grey cterm=bold hi EndOfBuffer ctermfg=NONE ctermbg=NONE cterm=NONE - hi Conceal ctermfg=Blue ctermbg=NONE cterm=NONE + hi Conceal ctermfg=Grey ctermbg=NONE cterm=NONE hi Cursor ctermfg=White ctermbg=DarkGray cterm=NONE hi DiffAdd ctermfg=Green ctermbg=White cterm=reverse hi DiffChange ctermfg=Cyan ctermbg=White cterm=reverse @@ -861,7 +878,7 @@ endif " Color: bg1 #ebdbb2 187 Grey " Color: bg2 #e5d4b1 188 Grey " Color: bg3 #bdae93 144 -" Color: bg4 #a89984 137 +" Color: bg4 #a89984 137 Grey " Color: bg5 #ebe1b7 229 Grey " Color: bg6 #ffffd7 231 Grey " Color: fg0 #282828 235 DarkGray @@ -875,6 +892,7 @@ endif " Color: yellow #b57614 172 Yellow " Color: blue #076678 23 Blue " Color: purple #8f3f71 126 Magenta +" Color: lightpurple #d3869b 175 Magenta " Color: aqua #427b58 29 Cyan " Color: orange #ff5f00 202 Magenta " Term colors: fg1 neutralred neutralgreen neutralyellow neutralblue neutralpurple neutralaqua fg4 diff --git a/runtime/colors/ron.vim b/runtime/colors/ron.vim index 4d55f9978f..f847ff3dd4 100644 --- a/runtime/colors/ron.vim +++ b/runtime/colors/ron.vim @@ -3,7 +3,7 @@ " Maintainer: original maintainer Ron Aaron <ron@ronware.org> " Website: https://www.github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Fri 15 Dec 2023 20:05:41 +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -63,7 +63,7 @@ hi CursorColumn guifg=NONE guibg=#666666 gui=NONE cterm=NONE hi CursorLine guifg=NONE guibg=#666666 gui=NONE cterm=NONE hi CursorLineNr guifg=#ffff00 guibg=NONE gui=bold cterm=NONE hi QuickFixLine guifg=#000000 guibg=#00cdcd gui=NONE cterm=NONE -hi Conceal guifg=#e5e5e5 guibg=#a9a9a9 gui=NONE cterm=NONE +hi Conceal guifg=#666666 guibg=NONE gui=NONE cterm=NONE hi Cursor guifg=#ffffff guibg=#60a060 gui=NONE cterm=NONE hi Directory guifg=#00ffff guibg=NONE gui=NONE cterm=NONE hi EndOfBuffer guifg=#ffff00 guibg=#303030 gui=NONE cterm=NONE @@ -80,6 +80,8 @@ hi Pmenu guifg=#ffffff guibg=#444444 gui=NONE cterm=NONE hi PmenuSbar guifg=NONE guibg=#000000 gui=NONE cterm=NONE hi PmenuSel guifg=#000000 guibg=#00cdcd gui=NONE cterm=NONE hi PmenuThumb guifg=NONE guibg=#e5e5e5 gui=NONE cterm=NONE +hi PmenuMatch guifg=#ff00ff guibg=#444444 gui=NONE cterm=NONE +hi PmenuMatchSel guifg=#ff00ff guibg=#00cdcd gui=NONE cterm=NONE hi Question guifg=#00ff00 guibg=#000000 gui=bold cterm=NONE hi Search guifg=#000000 guibg=#a9a9a9 gui=bold cterm=NONE hi SignColumn guifg=#00ffff guibg=NONE gui=NONE cterm=NONE @@ -128,7 +130,7 @@ if s:t_Co >= 256 hi CursorLine ctermfg=NONE ctermbg=59 cterm=NONE hi CursorLineNr ctermfg=226 ctermbg=NONE cterm=NONE hi QuickFixLine ctermfg=16 ctermbg=44 cterm=NONE - hi Conceal ctermfg=254 ctermbg=145 cterm=NONE + hi Conceal ctermfg=59 ctermbg=NONE cterm=NONE hi Cursor ctermfg=231 ctermbg=71 cterm=NONE hi Directory ctermfg=51 ctermbg=NONE cterm=NONE hi EndOfBuffer ctermfg=226 ctermbg=236 cterm=NONE @@ -145,6 +147,8 @@ if s:t_Co >= 256 hi PmenuSbar ctermfg=NONE ctermbg=16 cterm=NONE hi PmenuSel ctermfg=16 ctermbg=44 cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=254 cterm=NONE + hi PmenuMatch ctermfg=201 ctermbg=238 cterm=NONE + hi PmenuMatchSel ctermfg=201 ctermbg=44 cterm=NONE hi Question ctermfg=46 ctermbg=16 cterm=NONE hi Search ctermfg=16 ctermbg=145 cterm=NONE hi SignColumn ctermfg=51 ctermbg=NONE cterm=NONE @@ -196,7 +200,7 @@ if s:t_Co >= 16 hi CursorLine ctermfg=NONE ctermbg=NONE cterm=underline hi CursorLineNr ctermfg=yellow ctermbg=NONE cterm=underline hi QuickFixLine ctermfg=black ctermbg=darkcyan cterm=NONE - hi Conceal ctermfg=grey ctermbg=grey cterm=NONE + hi Conceal ctermfg=darkgrey ctermbg=NONE cterm=NONE hi Cursor ctermfg=white ctermbg=green cterm=NONE hi Directory ctermfg=cyan ctermbg=NONE cterm=NONE hi EndOfBuffer ctermfg=yellow ctermbg=darkgrey cterm=NONE @@ -213,6 +217,8 @@ if s:t_Co >= 16 hi PmenuSbar ctermfg=NONE ctermbg=black cterm=NONE hi PmenuSel ctermfg=black ctermbg=darkcyan cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=grey cterm=NONE + hi PmenuMatch ctermfg=white ctermbg=darkgrey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkcyan cterm=bold hi Question ctermfg=green ctermbg=black cterm=NONE hi Search ctermfg=black ctermbg=grey cterm=NONE hi SignColumn ctermfg=cyan ctermbg=NONE cterm=NONE @@ -280,6 +286,8 @@ if s:t_Co >= 8 hi PmenuSbar ctermfg=NONE ctermbg=black cterm=NONE hi PmenuSel ctermfg=black ctermbg=darkcyan cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=grey cterm=NONE + hi PmenuMatch ctermfg=grey ctermbg=darkgrey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkcyan cterm=bold hi Question ctermfg=darkgreen ctermbg=black cterm=bold hi Search ctermfg=black ctermbg=grey cterm=NONE hi SignColumn ctermfg=darkcyan ctermbg=NONE cterm=NONE diff --git a/runtime/colors/shine.vim b/runtime/colors/shine.vim index b4a8793589..f3697c9ad6 100644 --- a/runtime/colors/shine.vim +++ b/runtime/colors/shine.vim @@ -4,7 +4,7 @@ " Maintainer: Original maintainer is Yasuhiro Matsumoto <mattn@mail.goo.ne.jp> " Website: https://github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Fri 15 Dec 2023 20:05:41 +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -50,6 +50,8 @@ hi Pmenu guifg=#000000 guibg=#a8a8a8 gui=NONE cterm=NONE hi PmenuSel guifg=#000000 guibg=#ffff60 gui=NONE cterm=NONE hi PmenuSbar guifg=#ffffff guibg=#ffffff gui=NONE cterm=NONE hi PmenuThumb guifg=#767676 guibg=#767676 gui=NONE cterm=NONE +hi PmenuMatch guifg=#ff0000 guibg=#a8a8a8 gui=NONE cterm=NONE +hi PmenuMatchSel guifg=#ff0000 guibg=#ffff60 gui=NONE cterm=NONE hi TabLine guifg=#000000 guibg=#dadada gui=underline cterm=underline hi TabLineFill guifg=NONE guibg=NONE gui=reverse ctermfg=NONE ctermbg=NONE cterm=reverse hi TabLineSel guifg=#000000 guibg=#ffffff gui=bold cterm=bold @@ -84,7 +86,7 @@ hi Statement guifg=#2e8b57 guibg=NONE gui=bold cterm=bold hi Type guifg=#2e8b57 guibg=NONE gui=bold cterm=bold hi Comment guifg=#a8a8a8 guibg=NONE gui=bold cterm=NONE hi StorageClass guifg=#ff0000 guibg=NONE gui=bold cterm=bold -hi Conceal guifg=#dadada guibg=#767676 gui=NONE cterm=NONE +hi Conceal guifg=#add8e6 guibg=NONE gui=NONE cterm=NONE hi Identifier guifg=#008b8b guibg=NONE gui=NONE cterm=NONE hi Constant guifg=#a07070 guibg=NONE gui=NONE cterm=NONE hi Number guifg=#a07070 guibg=NONE gui=bold cterm=bold @@ -128,6 +130,8 @@ if s:t_Co >= 256 hi PmenuSel ctermfg=16 ctermbg=228 cterm=NONE hi PmenuSbar ctermfg=231 ctermbg=231 cterm=NONE hi PmenuThumb ctermfg=243 ctermbg=243 cterm=NONE + hi PmenuMatch ctermfg=196 ctermbg=248 cterm=NONE + hi PmenuMatchSel ctermfg=196 ctermbg=228 cterm=NONE hi TabLine ctermfg=16 ctermbg=253 cterm=underline hi TabLineFill ctermfg=NONE ctermbg=NONE cterm=reverse hi TabLineSel ctermfg=16 ctermbg=231 cterm=bold @@ -162,7 +166,7 @@ if s:t_Co >= 256 hi Type ctermfg=29 ctermbg=NONE cterm=bold hi Comment ctermfg=248 ctermbg=NONE cterm=NONE hi StorageClass ctermfg=196 ctermbg=NONE cterm=bold - hi Conceal ctermfg=253 ctermbg=243 cterm=NONE + hi Conceal ctermfg=153 ctermbg=NONE cterm=NONE hi Identifier ctermfg=30 ctermbg=NONE cterm=NONE hi Constant ctermfg=95 ctermbg=NONE cterm=NONE hi Number ctermfg=95 ctermbg=NONE cterm=bold @@ -197,6 +201,8 @@ if s:t_Co >= 16 hi PmenuSel ctermfg=black ctermbg=yellow cterm=NONE hi PmenuSbar ctermfg=white ctermbg=white cterm=NONE hi PmenuThumb ctermfg=darkgrey ctermbg=darkgrey cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=darkgrey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=yellow cterm=bold hi TabLine ctermfg=black ctermbg=grey cterm=underline hi TabLineFill ctermfg=NONE ctermbg=NONE cterm=reverse hi TabLineSel ctermfg=black ctermbg=white cterm=bold @@ -231,7 +237,7 @@ if s:t_Co >= 16 hi Type ctermfg=darkgreen ctermbg=NONE cterm=bold hi Comment ctermfg=darkgrey ctermbg=NONE cterm=NONE hi StorageClass ctermfg=red ctermbg=NONE cterm=bold - hi Conceal ctermfg=grey ctermbg=darkgrey cterm=NONE + hi Conceal ctermfg=blue ctermbg=NONE cterm=NONE hi Identifier ctermfg=darkcyan ctermbg=NONE cterm=NONE hi Constant ctermfg=darkred ctermbg=NONE cterm=NONE hi Number ctermfg=darkred ctermbg=NONE cterm=bold @@ -266,6 +272,8 @@ if s:t_Co >= 8 hi PmenuSel ctermfg=black ctermbg=darkyellow cterm=NONE hi PmenuSbar ctermfg=grey ctermbg=grey cterm=NONE hi PmenuThumb ctermfg=black ctermbg=black cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=darkcyan cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkyellow cterm=bold hi TabLine ctermfg=black ctermbg=grey cterm=reverse hi TabLineFill ctermfg=NONE ctermbg=NONE cterm=reverse hi TabLineSel ctermfg=grey ctermbg=black cterm=reverse diff --git a/runtime/colors/slate.vim b/runtime/colors/slate.vim index aab6208b26..c9ce78946b 100644 --- a/runtime/colors/slate.vim +++ b/runtime/colors/slate.vim @@ -4,7 +4,7 @@ " Maintainer: Original maintainer Ralph Amissah <ralph@amissah.com> " Website: https://github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Fri 15 Dec 2023 20:05:41 +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -38,10 +38,12 @@ hi StatusLineNC guifg=#666666 guibg=#afaf87 gui=NONE cterm=NONE hi StatusLineTerm guifg=#000000 guibg=#afaf87 gui=NONE cterm=NONE hi StatusLineTermNC guifg=#666666 guibg=#afaf87 gui=NONE cterm=NONE hi VertSplit guifg=#666666 guibg=#afaf87 gui=NONE cterm=NONE -hi PmenuSel guifg=#262626 guibg=#d7d787 gui=NONE cterm=NONE hi Pmenu guifg=NONE guibg=#4a4a4a gui=NONE cterm=NONE +hi PmenuSel guifg=#262626 guibg=#d7d787 gui=NONE cterm=NONE hi PmenuSbar guifg=NONE guibg=#262626 gui=NONE cterm=NONE hi PmenuThumb guifg=NONE guibg=#ffd700 gui=NONE cterm=NONE +hi PmenuMatch guifg=#d7875f guibg=#4a4a4a gui=NONE cterm=NONE +hi PmenuMatchSel guifg=#d7875f guibg=#d7d787 gui=NONE cterm=NONE hi TabLineSel guifg=#000000 guibg=#afaf87 gui=NONE cterm=NONE hi TabLine guifg=#666666 guibg=#333333 gui=NONE cterm=NONE hi TabLineFill guifg=#ff8787 guibg=#333333 gui=NONE cterm=NONE @@ -115,10 +117,12 @@ if s:t_Co >= 256 hi StatusLineTerm ctermfg=16 ctermbg=144 cterm=NONE hi StatusLineTermNC ctermfg=241 ctermbg=144 cterm=NONE hi VertSplit ctermfg=241 ctermbg=144 cterm=NONE - hi PmenuSel ctermfg=235 ctermbg=186 cterm=NONE hi Pmenu ctermfg=NONE ctermbg=239 cterm=NONE + hi PmenuSel ctermfg=235 ctermbg=186 cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=235 cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=220 cterm=NONE + hi PmenuMatch ctermfg=173 ctermbg=239 cterm=NONE + hi PmenuMatchSel ctermfg=173 ctermbg=186 cterm=NONE hi TabLineSel ctermfg=16 ctermbg=144 cterm=NONE hi TabLine ctermfg=241 ctermbg=236 cterm=NONE hi TabLineFill ctermfg=210 ctermbg=236 cterm=NONE @@ -185,10 +189,12 @@ if s:t_Co >= 16 hi StatusLineTerm ctermfg=white ctermbg=black cterm=bold,reverse hi StatusLineTermNC ctermfg=black ctermbg=grey cterm=NONE hi VertSplit ctermfg=darkgrey ctermbg=grey cterm=NONE - hi PmenuSel ctermfg=black ctermbg=darkyellow cterm=NONE hi Pmenu ctermfg=NONE ctermbg=darkgrey cterm=NONE + hi PmenuSel ctermfg=black ctermbg=darkmagenta cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=black cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=yellow cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=darkgrey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkmagenta cterm=bold hi TabLineSel ctermfg=black ctermbg=darkyellow cterm=NONE hi TabLine ctermfg=grey ctermbg=darkgrey cterm=NONE hi TabLineFill ctermfg=cyan ctermbg=darkgrey cterm=NONE @@ -255,10 +261,12 @@ if s:t_Co >= 8 hi StatusLineTerm ctermfg=grey ctermbg=black cterm=bold,reverse hi StatusLineTermNC ctermfg=grey ctermbg=black cterm=reverse hi VertSplit ctermfg=grey ctermbg=black cterm=reverse - hi PmenuSel ctermfg=black ctermbg=darkyellow cterm=NONE hi Pmenu ctermfg=black ctermbg=darkcyan cterm=NONE + hi PmenuSel ctermfg=black ctermbg=darkyellow cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=black cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=darkyellow cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=darkcyan cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkyellow cterm=bold hi TabLineSel ctermfg=black ctermbg=darkyellow cterm=NONE hi TabLine ctermfg=grey ctermbg=black cterm=reverse hi TabLineFill ctermfg=grey ctermbg=black cterm=reverse diff --git a/runtime/colors/sorbet.vim b/runtime/colors/sorbet.vim index e4ef42469c..bd4fb7baf7 100644 --- a/runtime/colors/sorbet.vim +++ b/runtime/colors/sorbet.vim @@ -4,7 +4,7 @@ " Maintainer: Maxence Weynans <neutaaaaan@gmail.com> " Website: https://github.com/vim/colorschemes " License: Vim License (see `:help license`)` -" Last Updated: Fri 15 Dec 2023 20:05:42 +" Last Change: 2024 Aug 05 " Generated by Colortemplate v2.2.3 @@ -56,6 +56,9 @@ if (has('termguicolors') && &termguicolors) || has('gui_running') endfor endif hi Normal guifg=#dadada guibg=#161821 gui=NONE cterm=NONE +hi Added guifg=#87d75f guibg=NONE gui=NONE cterm=NONE +hi Changed guifg=#87afd7 guibg=NONE gui=NONE cterm=NONE +hi Removed guifg=#d75f5f guibg=NONE gui=NONE cterm=NONE hi ColorColumn guifg=NONE guibg=#262831 gui=NONE cterm=NONE hi Conceal guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi CurSearch guifg=#ff5fff guibg=#000000 gui=reverse cterm=reverse @@ -78,10 +81,12 @@ hi ModeMsg guifg=#dadada guibg=NONE gui=bold cterm=bold hi MoreMsg guifg=#dadada guibg=NONE gui=NONE cterm=NONE hi NonText guifg=#707070 guibg=NONE gui=NONE cterm=NONE hi Pmenu guifg=#000000 guibg=#a6a8b1 gui=NONE cterm=NONE +hi PmenuMatch guifg=#d7005f guibg=#a6a8b1 gui=NONE cterm=NONE hi PmenuExtra guifg=#000000 guibg=#a6a8b1 gui=NONE cterm=NONE hi PmenuKind guifg=#000000 guibg=#a6a8b1 gui=bold cterm=bold hi PmenuSbar guifg=#707070 guibg=#5f5f87 gui=NONE cterm=NONE hi PmenuSel guifg=#000000 guibg=#d7d7ff gui=NONE cterm=NONE +hi PmenuMatchSel guifg=#d7005f guibg=#d7d7ff gui=bold cterm=bold hi PmenuExtraSel guifg=#000000 guibg=#d7d7ff gui=NONE cterm=NONE hi PmenuKindSel guifg=#000000 guibg=#d7d7ff gui=bold cterm=bold hi PmenuThumb guifg=#dadada guibg=#d7d7ff gui=NONE cterm=NONE @@ -120,11 +125,13 @@ hi Underlined guifg=#dadada guibg=NONE gui=underline cterm=underline hi CursorIM guifg=#000000 guibg=#afff00 gui=NONE cterm=NONE hi ToolbarLine guifg=NONE guibg=#000000 gui=NONE cterm=NONE hi ToolbarButton guifg=#dadada guibg=#000000 gui=bold cterm=bold -hi DiffRemoved guifg=#d75f5f guibg=NONE gui=NONE cterm=NONE hi debugBreakpoint guifg=#8787af guibg=#000000 gui=bold,reverse cterm=bold,reverse if s:t_Co >= 256 hi Normal ctermfg=253 ctermbg=233 cterm=NONE + hi Added ctermfg=113 ctermbg=NONE cterm=NONE + hi Changed ctermfg=110 ctermbg=NONE cterm=NONE + hi Removed ctermfg=167 ctermbg=NONE cterm=NONE hi ColorColumn ctermfg=NONE ctermbg=235 cterm=NONE hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE hi CurSearch ctermfg=207 ctermbg=16 cterm=reverse @@ -147,10 +154,12 @@ if s:t_Co >= 256 hi MoreMsg ctermfg=253 ctermbg=NONE cterm=NONE hi NonText ctermfg=242 ctermbg=NONE cterm=NONE hi Pmenu ctermfg=16 ctermbg=248 cterm=NONE + hi PmenuMatch ctermfg=161 ctermbg=248 cterm=NONE hi PmenuExtra ctermfg=16 ctermbg=248 cterm=NONE hi PmenuKind ctermfg=16 ctermbg=248 cterm=bold hi PmenuSbar ctermfg=242 ctermbg=60 cterm=NONE hi PmenuSel ctermfg=16 ctermbg=189 cterm=NONE + hi PmenuMatchSel ctermfg=161 ctermbg=189 cterm=bold hi PmenuExtraSel ctermfg=16 ctermbg=189 cterm=NONE hi PmenuKindSel ctermfg=16 ctermbg=189 cterm=bold hi PmenuThumb ctermfg=253 ctermbg=189 cterm=NONE @@ -189,7 +198,6 @@ if s:t_Co >= 256 hi CursorIM ctermfg=16 ctermbg=154 cterm=NONE hi ToolbarLine ctermfg=NONE ctermbg=16 cterm=NONE hi ToolbarButton ctermfg=253 ctermbg=16 cterm=bold - hi DiffRemoved ctermfg=167 ctermbg=NONE cterm=NONE hi debugBreakpoint ctermfg=103 ctermbg=16 cterm=bold,reverse unlet s:t_Co finish @@ -209,6 +217,9 @@ if s:t_Co >= 16 hi TabLine ctermfg=darkgrey ctermbg=NONE cterm=reverse hi VertSplit ctermfg=darkgrey ctermbg=NONE cterm=NONE hi Normal ctermfg=NONE ctermbg=NONE cterm=NONE + hi Added ctermfg=darkgreen ctermbg=NONE cterm=NONE + hi Changed ctermfg=darkblue ctermbg=NONE cterm=NONE + hi Removed ctermfg=darkred ctermbg=NONE cterm=NONE hi ColorColumn ctermfg=NONE ctermbg=NONE cterm=reverse hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE hi Cursor ctermfg=NONE ctermbg=NONE cterm=reverse @@ -225,9 +236,11 @@ if s:t_Co >= 16 hi ModeMsg ctermfg=NONE ctermbg=NONE cterm=bold hi MoreMsg ctermfg=NONE ctermbg=NONE cterm=NONE hi Pmenu ctermfg=NONE ctermbg=NONE cterm=reverse + hi PmenuMatch ctermfg=NONE ctermbg=darkred cterm=reverse hi PmenuExtra ctermfg=NONE ctermbg=NONE cterm=reverse hi PmenuKind ctermfg=NONE ctermbg=NONE cterm=bold,reverse hi PmenuSel ctermfg=NONE ctermbg=NONE cterm=bold + hi PmenuMatchSel ctermfg=darkred ctermbg=NONE cterm=bold hi PmenuExtraSel ctermfg=NONE ctermbg=NONE cterm=bold hi PmenuKindSel ctermfg=NONE ctermbg=NONE cterm=bold hi PmenuThumb ctermfg=NONE ctermbg=NONE cterm=NONE @@ -261,7 +274,6 @@ if s:t_Co >= 16 hi CursorIM ctermfg=NONE ctermbg=NONE cterm=NONE hi ToolbarLine ctermfg=NONE ctermbg=NONE cterm=reverse hi ToolbarButton ctermfg=NONE ctermbg=NONE cterm=bold,reverse - hi DiffRemoved ctermfg=darkred ctermbg=NONE cterm=NONE hi debugBreakpoint ctermfg=NONE ctermbg=NONE cterm=bold,reverse unlet s:t_Co finish @@ -281,6 +293,9 @@ if s:t_Co >= 8 hi TabLine ctermfg=NONE ctermbg=NONE cterm=bold,underline hi VertSplit ctermfg=NONE ctermbg=NONE cterm=NONE hi Normal ctermfg=NONE ctermbg=NONE cterm=NONE + hi Added ctermfg=darkgreen ctermbg=NONE cterm=NONE + hi Changed ctermfg=darkblue ctermbg=NONE cterm=NONE + hi Removed ctermfg=darkred ctermbg=NONE cterm=NONE hi ColorColumn ctermfg=NONE ctermbg=NONE cterm=reverse hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE hi Cursor ctermfg=NONE ctermbg=NONE cterm=reverse @@ -297,9 +312,11 @@ if s:t_Co >= 8 hi ModeMsg ctermfg=NONE ctermbg=NONE cterm=bold hi MoreMsg ctermfg=NONE ctermbg=NONE cterm=NONE hi Pmenu ctermfg=NONE ctermbg=NONE cterm=reverse + hi PmenuMatch ctermfg=NONE ctermbg=darkred cterm=reverse hi PmenuExtra ctermfg=NONE ctermbg=NONE cterm=reverse hi PmenuKind ctermfg=NONE ctermbg=NONE cterm=bold,reverse hi PmenuSel ctermfg=NONE ctermbg=NONE cterm=bold + hi PmenuMatchSel ctermfg=darkred ctermbg=NONE cterm=bold hi PmenuExtraSel ctermfg=NONE ctermbg=NONE cterm=bold hi PmenuKindSel ctermfg=NONE ctermbg=NONE cterm=bold hi PmenuThumb ctermfg=NONE ctermbg=NONE cterm=NONE @@ -333,7 +350,6 @@ if s:t_Co >= 8 hi CursorIM ctermfg=NONE ctermbg=NONE cterm=NONE hi ToolbarLine ctermfg=NONE ctermbg=NONE cterm=reverse hi ToolbarButton ctermfg=NONE ctermbg=NONE cterm=bold,reverse - hi DiffRemoved ctermfg=darkred ctermbg=NONE cterm=NONE hi debugBreakpoint ctermfg=NONE ctermbg=NONE cterm=bold,reverse unlet s:t_Co finish diff --git a/runtime/colors/torte.vim b/runtime/colors/torte.vim index 36da28e596..7271188f0d 100644 --- a/runtime/colors/torte.vim +++ b/runtime/colors/torte.vim @@ -4,7 +4,7 @@ " Maintainer: Original maintainer Thorsten Maerz <info@netztorte.de> " Website: https://github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Fri 15 Dec 2023 20:05:42 +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -53,7 +53,7 @@ hi CursorLineNr guifg=#ffff00 guibg=#666666 gui=NONE cterm=NONE hi SignColumn guifg=#00ffff guibg=NONE gui=NONE cterm=NONE hi FoldColumn guifg=#00ffff guibg=NONE gui=NONE cterm=NONE hi ColorColumn guifg=#cccccc guibg=#8b0000 gui=NONE cterm=NONE -hi Conceal guifg=#e5e5e5 guibg=#a9a9a9 gui=NONE cterm=NONE +hi Conceal guifg=#666666 guibg=NONE gui=NONE cterm=NONE hi Cursor guifg=#000000 guibg=#00ff00 gui=bold cterm=NONE hi lCursor guifg=#000000 guibg=#e5e5e5 gui=NONE cterm=NONE hi CursorIM guifg=NONE guibg=fg gui=NONE cterm=NONE @@ -86,6 +86,8 @@ hi TabLineFill guifg=NONE guibg=#000000 gui=reverse cterm=reverse hi TabLineSel guifg=#cccccc guibg=#000000 gui=bold cterm=bold hi ToolbarLine guifg=NONE guibg=#000000 gui=NONE cterm=NONE hi ToolbarButton guifg=#000000 guibg=#e5e5e5 gui=bold cterm=bold +hi PmenuMatch guifg=#ff00ff guibg=#303030 gui=NONE cterm=NONE +hi PmenuMatchSel guifg=#ff00ff guibg=#ffff00 gui=NONE cterm=NONE hi Pmenu guifg=fg guibg=#303030 gui=NONE cterm=NONE hi PmenuSbar guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuSel guifg=#000000 guibg=#ffff00 gui=NONE cterm=NONE @@ -126,7 +128,7 @@ if s:t_Co >= 256 hi SignColumn ctermfg=51 ctermbg=NONE cterm=NONE hi FoldColumn ctermfg=51 ctermbg=NONE cterm=NONE hi ColorColumn ctermfg=251 ctermbg=88 cterm=NONE - hi Conceal ctermfg=254 ctermbg=248 cterm=NONE + hi Conceal ctermfg=242 ctermbg=NONE cterm=NONE hi Cursor ctermfg=16 ctermbg=46 cterm=NONE hi lCursor ctermfg=16 ctermbg=254 cterm=NONE hi CursorIM ctermfg=NONE ctermbg=fg cterm=NONE @@ -159,6 +161,8 @@ if s:t_Co >= 256 hi TabLineSel ctermfg=251 ctermbg=16 cterm=bold hi ToolbarLine ctermfg=NONE ctermbg=16 cterm=NONE hi ToolbarButton ctermfg=16 ctermbg=254 cterm=bold + hi PmenuMatch ctermfg=201 ctermbg=236 cterm=NONE + hi PmenuMatchSel ctermfg=201 ctermbg=226 cterm=NONE hi Pmenu ctermfg=fg ctermbg=236 cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuSel ctermfg=16 ctermbg=226 cterm=NONE @@ -192,7 +196,7 @@ if s:t_Co >= 16 hi SignColumn ctermfg=cyan ctermbg=NONE cterm=NONE hi FoldColumn ctermfg=cyan ctermbg=NONE cterm=NONE hi ColorColumn ctermfg=white ctermbg=darkred cterm=NONE - hi Conceal ctermfg=grey ctermbg=grey cterm=NONE + hi Conceal ctermfg=grey ctermbg=NONE cterm=NONE hi Cursor ctermfg=black ctermbg=green cterm=NONE hi lCursor ctermfg=black ctermbg=grey cterm=NONE hi CursorIM ctermfg=NONE ctermbg=fg cterm=NONE @@ -225,6 +229,8 @@ if s:t_Co >= 16 hi TabLineSel ctermfg=white ctermbg=black cterm=bold hi ToolbarLine ctermfg=NONE ctermbg=black cterm=NONE hi ToolbarButton ctermfg=black ctermbg=grey cterm=bold + hi PmenuMatch ctermfg=fg ctermbg=darkgrey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=yellow cterm=bold hi Pmenu ctermfg=fg ctermbg=darkgrey cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuSel ctermfg=black ctermbg=yellow cterm=NONE @@ -292,6 +298,8 @@ if s:t_Co >= 8 hi PmenuSbar ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuSel ctermfg=black ctermbg=darkyellow cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=darkmagenta cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=darkcyan cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkyellow cterm=bold hi DiffAdd ctermfg=white ctermbg=darkgreen cterm=NONE hi DiffChange ctermfg=white ctermbg=darkblue cterm=NONE hi DiffText ctermfg=black ctermbg=grey cterm=NONE diff --git a/runtime/colors/vim.lua b/runtime/colors/vim.lua index 7231418f5f..5b9309ab38 100644 --- a/runtime/colors/vim.lua +++ b/runtime/colors/vim.lua @@ -56,6 +56,8 @@ hi('CursorLineFold', { link = 'FoldColumn' }) hi('CurSearch', { link = 'Search' }) hi('PmenuKind', { link = 'Pmenu' }) hi('PmenuKindSel', { link = 'PmenuSel' }) +hi('PmenuMatch', { link = 'Pmenu' }) +hi('PmenuMatchSel', { link = 'PmenuSel' }) hi('PmenuExtra', { link = 'Pmenu' }) hi('PmenuExtraSel', { link = 'PmenuSel' }) hi('Substitute', { link = 'Search' }) @@ -209,81 +211,85 @@ hi('@lsp.type.variable', { link = 'Identifier' }) if vim.o.background == 'light' then -- Default colors only used with a light background. - hi('ColorColumn', { bg = 'LightRed', ctermbg = 'LightRed' }) - hi('CursorColumn', { bg = 'Grey90', ctermbg = 'LightGrey' }) - hi('CursorLine', { bg = 'Grey90', cterm = { underline = true } }) - hi('CursorLineNr', { fg = 'Brown', bold = true, ctermfg = 'Brown', cterm = { underline = true } }) - hi('DiffAdd', { bg = 'LightBlue', ctermbg = 'LightBlue' }) - hi('DiffChange', { bg = 'LightMagenta', ctermbg = 'LightMagenta' }) - hi('DiffDelete', { fg = 'Blue', bg = 'LightCyan', bold = true, ctermfg = 'Blue', ctermbg = 'LightCyan' }) - hi('Directory', { fg = 'Blue', ctermfg = 'DarkBlue' }) - hi('FoldColumn', { fg = 'DarkBlue', bg = 'Grey', ctermfg = 'DarkBlue', ctermbg = 'Grey' }) - hi('Folded', { fg = 'DarkBlue', bg = 'LightGrey', ctermfg = 'DarkBlue', ctermbg = 'Grey' }) - hi('LineNr', { fg = 'Brown', ctermfg = 'Brown' }) - hi('MatchParen', { bg = 'Cyan', ctermbg = 'Cyan' }) - hi('MoreMsg', { fg = 'SeaGreen', bold = true, ctermfg = 'DarkGreen' }) - hi('Pmenu', { bg = 'LightMagenta', ctermfg = 'Black', ctermbg = 'LightMagenta' }) - hi('PmenuSel', { bg = 'Grey', ctermfg = 'Black', ctermbg = 'LightGrey' }) - hi('PmenuThumb', { bg = 'Black', ctermbg = 'Black' }) - hi('Question', { fg = 'SeaGreen', bold = true, ctermfg = 'DarkGreen' }) - hi('Search', { bg = 'Yellow', ctermbg = 'Yellow' }) - hi('SignColumn', { fg = 'DarkBlue', bg = 'Grey', ctermfg = 'DarkBlue', ctermbg = 'Grey' }) - hi('SpecialKey', { fg = 'Blue', ctermfg = 'DarkBlue' }) - hi('SpellBad', { sp = 'Red', undercurl = true, ctermbg = 'LightRed' }) - hi('SpellCap', { sp = 'Blue', undercurl = true, ctermbg = 'LightBlue' }) - hi('SpellLocal', { sp = 'DarkCyan', undercurl = true, ctermbg = 'Cyan' }) - hi('SpellRare', { sp = 'Magenta', undercurl = true, ctermbg = 'LightMagenta' }) - hi('TabLine', { bg = 'LightGrey', underline = true, ctermfg = 'Black', ctermbg = 'LightGrey', cterm = { underline = true } }) - hi('Title', { fg = 'Magenta', bold = true, ctermfg = 'DarkMagenta' }) - hi('Visual', { fg = 'Black', bg = 'LightGrey', ctermfg = 'Black', ctermbg = 'Grey' }) - hi('WarningMsg', { fg = 'Red', ctermfg = 'DarkRed' }) - hi('Comment', { fg = 'Blue', ctermfg = 'DarkBlue' }) - hi('Constant', { fg = 'Magenta', ctermfg = 'DarkRed' }) - hi('Special', { fg = '#6a5acd', ctermfg = 'DarkMagenta' }) - hi('Identifier', { fg = 'DarkCyan', ctermfg = 'DarkCyan' }) - hi('Statement', { fg = 'Brown', bold = true, ctermfg = 'Brown' }) - hi('PreProc', { fg = '#6a0dad', ctermfg = 'DarkMagenta' }) - hi('Type', { fg = 'SeaGreen', bold = true, ctermfg = 'DarkGreen' }) - hi('Underlined', { fg = 'SlateBlue', underline = true, ctermfg = 'DarkMagenta', cterm = { underline = true } }) - hi('Ignore', { ctermfg = 'White' }) + hi('ColorColumn', { bg = 'LightRed', ctermbg = 'LightRed' }) + hi('CursorColumn', { bg = 'Grey90', ctermbg = 'LightGrey' }) + hi('CursorLine', { bg = 'Grey90', cterm = { underline = true } }) + hi('CursorLineNr', { fg = 'Brown', bold = true, ctermfg = 'Brown', cterm = { underline = true } }) + hi('DiffAdd', { bg = 'LightBlue', ctermbg = 'LightBlue' }) + hi('DiffChange', { bg = 'LightMagenta', ctermbg = 'LightMagenta' }) + hi('DiffDelete', { fg = 'Blue', bg = 'LightCyan', bold = true, ctermfg = 'Blue', ctermbg = 'LightCyan' }) + hi('Directory', { fg = 'Blue', ctermfg = 'DarkBlue' }) + hi('FoldColumn', { fg = 'DarkBlue', bg = 'Grey', ctermfg = 'DarkBlue', ctermbg = 'Grey' }) + hi('Folded', { fg = 'DarkBlue', bg = 'LightGrey', ctermfg = 'DarkBlue', ctermbg = 'Grey' }) + hi('LineNr', { fg = 'Brown', ctermfg = 'Brown' }) + hi('MatchParen', { bg = 'Cyan', ctermbg = 'Cyan' }) + hi('MoreMsg', { fg = 'SeaGreen', bold = true, ctermfg = 'DarkGreen' }) + hi('Pmenu', { bg = 'LightMagenta', ctermfg = 'Black', ctermbg = 'LightMagenta' }) + hi('PmenuSel', { bg = 'Grey', ctermfg = 'Black', ctermbg = 'LightGrey' }) + hi('PmenuThumb', { bg = 'Black', ctermbg = 'Black' }) + hi('Question', { fg = 'SeaGreen', bold = true, ctermfg = 'DarkGreen' }) + hi('Search', { bg = 'Yellow', ctermbg = 'Yellow' }) + hi('SignColumn', { fg = 'DarkBlue', bg = 'Grey', ctermfg = 'DarkBlue', ctermbg = 'Grey' }) + hi('SpecialKey', { fg = 'Blue', ctermfg = 'DarkBlue' }) + hi('SpellBad', { sp = 'Red', undercurl = true, ctermbg = 'LightRed' }) + hi('SpellCap', { sp = 'Blue', undercurl = true, ctermbg = 'LightBlue' }) + hi('SpellLocal', { sp = 'DarkCyan', undercurl = true, ctermbg = 'Cyan' }) + hi('SpellRare', { sp = 'Magenta', undercurl = true, ctermbg = 'LightMagenta' }) + hi('StatusLineTerm', { fg = 'White', bg = 'DarkGreen', bold = true, ctermfg = 'White', ctermbg = 'DarkGreen', cterm = { bold = true } }) + hi('StatusLineTermNC', { fg = 'White', bg = 'DarkGreen', ctermfg = 'White', ctermbg = 'DarkGreen' }) + hi('TabLine', { bg = 'LightGrey', underline = true, ctermfg = 'Black', ctermbg = 'LightGrey', cterm = { underline = true } }) + hi('Title', { fg = 'Magenta', bold = true, ctermfg = 'DarkMagenta' }) + hi('Visual', { fg = 'Black', bg = 'LightGrey', ctermfg = 'Black', ctermbg = 'Grey' }) + hi('WarningMsg', { fg = 'Red', ctermfg = 'DarkRed' }) + hi('Comment', { fg = 'Blue', ctermfg = 'DarkBlue' }) + hi('Constant', { fg = 'Magenta', ctermfg = 'DarkRed' }) + hi('Special', { fg = '#6a5acd', ctermfg = 'DarkMagenta' }) + hi('Identifier', { fg = 'DarkCyan', ctermfg = 'DarkCyan' }) + hi('Statement', { fg = 'Brown', bold = true, ctermfg = 'Brown' }) + hi('PreProc', { fg = '#6a0dad', ctermfg = 'DarkMagenta' }) + hi('Type', { fg = 'SeaGreen', bold = true, ctermfg = 'DarkGreen' }) + hi('Underlined', { fg = 'SlateBlue', underline = true, ctermfg = 'DarkMagenta', cterm = { underline = true } }) + hi('Ignore', { ctermfg = 'White' }) else -- Default colors only used with a dark background. - hi('ColorColumn', { bg = 'DarkRed', ctermbg = 'DarkRed' }) - hi('CursorColumn', { bg = 'Grey40', ctermbg = 'DarkGrey' }) - hi('CursorLine', { bg = 'Grey40', cterm = { underline = true } }) - hi('CursorLineNr', { fg = 'Yellow', bold = true, ctermfg = 'Yellow', cterm = { underline = true } }) - hi('DiffAdd', { bg = 'DarkBlue', ctermbg = 'DarkBlue' }) - hi('DiffChange', { bg = 'DarkMagenta', ctermbg = 'DarkMagenta' }) - hi('DiffDelete', { fg = 'Blue', bg = 'DarkCyan', bold = true, ctermfg = 'Blue', ctermbg = 'DarkCyan' }) - hi('Directory', { fg = 'Cyan', ctermfg = 'LightCyan' }) - hi('FoldColumn', { fg = 'Cyan', bg = 'Grey', ctermfg = 'Cyan', ctermbg = 'DarkGrey' }) - hi('Folded', { fg = 'Cyan', bg = 'DarkGrey', ctermfg = 'Cyan', ctermbg = 'DarkGrey' }) - hi('LineNr', { fg = 'Yellow', ctermfg = 'Yellow' }) - hi('MatchParen', { bg = 'DarkCyan', ctermbg = 'DarkCyan' }) - hi('MoreMsg', { fg = 'SeaGreen', bold = true, ctermfg = 'LightGreen' }) - hi('Pmenu', { bg = 'Magenta', ctermfg = 'Black', ctermbg = 'Magenta' }) - hi('PmenuSel', { bg = 'DarkGrey', ctermfg = 'DarkGrey', ctermbg = 'Black' }) - hi('PmenuThumb', { bg = 'White', ctermbg = 'White' }) - hi('Question', { fg = 'Green', bold = true, ctermfg = 'LightGreen' }) - hi('Search', { fg = 'Black', bg = 'Yellow', ctermfg = 'Black', ctermbg = 'Yellow' }) - hi('SignColumn', { fg = 'Cyan', bg = 'Grey', ctermfg = 'Cyan', ctermbg = 'DarkGrey' }) - hi('SpecialKey', { fg = 'Cyan', ctermfg = 'LightBlue' }) - hi('SpellBad', { sp = 'Red', undercurl = true, ctermbg = 'Red' }) - hi('SpellCap', { sp = 'Blue', undercurl = true, ctermbg = 'Blue' }) - hi('SpellLocal', { sp = 'Cyan', undercurl = true, ctermbg = 'Cyan' }) - hi('SpellRare', { sp = 'Magenta', undercurl = true, ctermbg = 'Magenta' }) - hi('TabLine', { bg = 'DarkGrey', underline = true, ctermfg = 'White', ctermbg = 'DarkGrey', cterm = { underline = true } }) - hi('Title', { fg = 'Magenta', bold = true, ctermfg = 'LightMagenta' }) - hi('Visual', { fg = 'LightGrey', bg = '#575757', ctermfg = 'Black', ctermbg = 'Grey' }) - hi('WarningMsg', { fg = 'Red', ctermfg = 'LightRed' }) - hi('Comment', { fg = '#80a0ff', ctermfg = 'Cyan' }) - hi('Constant', { fg = '#ffa0a0', ctermfg = 'Magenta' }) - hi('Special', { fg = 'Orange', ctermfg = 'LightRed' }) - hi('Identifier', { fg = '#40ffff', ctermfg = 'Cyan', cterm = { bold = true } }) - hi('Statement', { fg = '#ffff60', bold = true, ctermfg = 'Yellow' }) - hi('PreProc', { fg = '#ff80ff', ctermfg = 'LightBlue' }) - hi('Type', { fg = '#60ff60', bold = true, ctermfg = 'LightGreen' }) - hi('Underlined', { fg = '#80a0ff', underline = true, ctermfg = 'LightBlue', cterm = { underline = true } }) - hi('Ignore', { ctermfg = 'Black' }) + hi('ColorColumn', { bg = 'DarkRed', ctermbg = 'DarkRed' }) + hi('CursorColumn', { bg = 'Grey40', ctermbg = 'DarkGrey' }) + hi('CursorLine', { bg = 'Grey40', cterm = { underline = true } }) + hi('CursorLineNr', { fg = 'Yellow', bold = true, ctermfg = 'Yellow', cterm = { underline = true } }) + hi('DiffAdd', { bg = 'DarkBlue', ctermbg = 'DarkBlue' }) + hi('DiffChange', { bg = 'DarkMagenta', ctermbg = 'DarkMagenta' }) + hi('DiffDelete', { fg = 'Blue', bg = 'DarkCyan', bold = true, ctermfg = 'Blue', ctermbg = 'DarkCyan' }) + hi('Directory', { fg = 'Cyan', ctermfg = 'LightCyan' }) + hi('FoldColumn', { fg = 'Cyan', bg = 'Grey', ctermfg = 'Cyan', ctermbg = 'DarkGrey' }) + hi('Folded', { fg = 'Cyan', bg = 'DarkGrey', ctermfg = 'Cyan', ctermbg = 'DarkGrey' }) + hi('LineNr', { fg = 'Yellow', ctermfg = 'Yellow' }) + hi('MatchParen', { bg = 'DarkCyan', ctermbg = 'DarkCyan' }) + hi('MoreMsg', { fg = 'SeaGreen', bold = true, ctermfg = 'LightGreen' }) + hi('Pmenu', { bg = 'Magenta', ctermfg = 'Black', ctermbg = 'Magenta' }) + hi('PmenuSel', { bg = 'DarkGrey', ctermfg = 'DarkGrey', ctermbg = 'Black' }) + hi('PmenuThumb', { bg = 'White', ctermbg = 'White' }) + hi('Question', { fg = 'Green', bold = true, ctermfg = 'LightGreen' }) + hi('Search', { fg = 'Black', bg = 'Yellow', ctermfg = 'Black', ctermbg = 'Yellow' }) + hi('SignColumn', { fg = 'Cyan', bg = 'Grey', ctermfg = 'Cyan', ctermbg = 'DarkGrey' }) + hi('SpecialKey', { fg = 'Cyan', ctermfg = 'LightBlue' }) + hi('SpellBad', { sp = 'Red', undercurl = true, ctermbg = 'Red' }) + hi('SpellCap', { sp = 'Blue', undercurl = true, ctermbg = 'Blue' }) + hi('SpellLocal', { sp = 'Cyan', undercurl = true, ctermbg = 'Cyan' }) + hi('SpellRare', { sp = 'Magenta', undercurl = true, ctermbg = 'Magenta' }) + hi('StatusLineTerm', { fg = 'Black', bg = 'LightGreen', bold = true, ctermfg = 'Black', ctermbg = 'LightGreen', cterm = { bold = true } }) + hi('StatusLineTermNC', { fg = 'Black', bg = 'LightGreen', ctermfg = 'Black', ctermbg = 'LightGreen' }) + hi('TabLine', { bg = 'DarkGrey', underline = true, ctermfg = 'White', ctermbg = 'DarkGrey', cterm = { underline = true } }) + hi('Title', { fg = 'Magenta', bold = true, ctermfg = 'LightMagenta' }) + hi('Visual', { fg = 'LightGrey', bg = '#575757', ctermfg = 'Black', ctermbg = 'Grey' }) + hi('WarningMsg', { fg = 'Red', ctermfg = 'LightRed' }) + hi('Comment', { fg = '#80a0ff', ctermfg = 'Cyan' }) + hi('Constant', { fg = '#ffa0a0', ctermfg = 'Magenta' }) + hi('Special', { fg = 'Orange', ctermfg = 'LightRed' }) + hi('Identifier', { fg = '#40ffff', ctermfg = 'Cyan', cterm = { bold = true } }) + hi('Statement', { fg = '#ffff60', bold = true, ctermfg = 'Yellow' }) + hi('PreProc', { fg = '#ff80ff', ctermfg = 'LightBlue' }) + hi('Type', { fg = '#60ff60', bold = true, ctermfg = 'LightGreen' }) + hi('Underlined', { fg = '#80a0ff', underline = true, ctermfg = 'LightBlue', cterm = { underline = true } }) + hi('Ignore', { ctermfg = 'Black' }) end --stylua: ignore end diff --git a/runtime/colors/wildcharm.vim b/runtime/colors/wildcharm.vim index c47a66d148..47ca5a1408 100644 --- a/runtime/colors/wildcharm.vim +++ b/runtime/colors/wildcharm.vim @@ -4,7 +4,7 @@ " Maintainer: Maxim Kim <habamax@gmail.com> " Website: https://github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Mon 08 Jan 2024 09:40:36 AM AEDT +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -31,14 +31,14 @@ if &background ==# 'dark' endfor endif hi Normal guifg=#d0d0d0 guibg=#000000 gui=NONE cterm=NONE - hi Statusline guifg=#d0d0d0 guibg=#000000 gui=reverse cterm=reverse + hi Statusline guifg=#9e9e9e guibg=#000000 gui=bold,reverse cterm=bold,reverse hi StatuslineNC guifg=#767676 guibg=#000000 gui=reverse cterm=reverse - hi VertSplit guifg=#767676 guibg=#767676 gui=NONE cterm=NONE - hi TabLine guifg=#000000 guibg=#d0d0d0 gui=NONE cterm=NONE - hi TabLineFill guifg=NONE guibg=#767676 gui=NONE cterm=NONE - hi TabLineSel guifg=#ffffff guibg=#000000 gui=NONE cterm=NONE + hi VertSplit guifg=#767676 guibg=NONE gui=NONE cterm=NONE + hi TabLine guifg=#000000 guibg=#767676 gui=NONE cterm=NONE + hi TabLineFill guifg=NONE guibg=#000000 gui=NONE cterm=NONE + hi TabLineSel guifg=#000000 guibg=#9e9e9e gui=bold cterm=bold hi ToolbarLine guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE - hi ToolbarButton guifg=#000000 guibg=#ffffff gui=NONE cterm=NONE + hi ToolbarButton guifg=#000000 guibg=#d0d0d0 gui=NONE cterm=NONE hi QuickFixLine guifg=#000000 guibg=#ff87ff gui=NONE cterm=NONE hi CursorLineNr guifg=#ffffff guibg=NONE gui=bold cterm=bold hi LineNr guifg=#585858 guibg=NONE gui=NONE cterm=NONE @@ -48,13 +48,15 @@ if &background ==# 'dark' hi EndOfBuffer guifg=#585858 guibg=NONE gui=NONE cterm=NONE hi EndOfBuffer guifg=#767676 guibg=NONE gui=NONE cterm=NONE hi Pmenu guifg=#d0d0d0 guibg=#303030 gui=NONE cterm=NONE - hi PmenuSel guifg=#000000 guibg=#ffaf00 gui=NONE cterm=NONE + hi PmenuSel guifg=#d0d0d0 guibg=#585858 gui=NONE cterm=NONE hi PmenuThumb guifg=NONE guibg=#d0d0d0 gui=NONE cterm=NONE hi PmenuSbar guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuKind guifg=#ff5f87 guibg=#303030 gui=NONE cterm=NONE - hi PmenuKindSel guifg=#d7005f guibg=#ffaf00 gui=NONE cterm=NONE + hi PmenuKindSel guifg=#ff5f87 guibg=#585858 gui=NONE cterm=NONE hi PmenuExtra guifg=#767676 guibg=#303030 gui=NONE cterm=NONE - hi PmenuExtraSel guifg=#000000 guibg=#ffaf00 gui=NONE cterm=NONE + hi PmenuExtraSel guifg=#767676 guibg=#585858 gui=NONE cterm=NONE + hi PmenuMatch guifg=#d787d7 guibg=#303030 gui=NONE cterm=NONE + hi PmenuMatchSel guifg=#d787d7 guibg=#585858 gui=NONE cterm=NONE hi SignColumn guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi Error guifg=#d7005f guibg=#ffffff gui=reverse cterm=reverse hi ErrorMsg guifg=#d7005f guibg=#ffffff gui=reverse cterm=reverse @@ -70,7 +72,7 @@ if &background ==# 'dark' hi debugBreakpoint guifg=#00afaf guibg=NONE gui=reverse cterm=reverse hi Cursor guifg=#000000 guibg=#ffffff gui=NONE cterm=NONE hi lCursor guifg=#000000 guibg=#ff5fff gui=NONE cterm=NONE - hi Visual guifg=#0087d7 guibg=#000000 gui=reverse cterm=reverse + hi Visual guifg=#5fd7ff guibg=#000000 gui=reverse cterm=reverse hi VisualNOS guifg=#000000 guibg=#00afff gui=NONE cterm=NONE hi CursorLine guifg=NONE guibg=#262626 gui=NONE cterm=NONE hi CursorColumn guifg=NONE guibg=#262626 gui=NONE cterm=NONE @@ -92,7 +94,7 @@ if &background ==# 'dark' hi Underlined guifg=NONE guibg=NONE gui=underline ctermfg=NONE ctermbg=NONE cterm=underline hi Title guifg=NONE guibg=NONE gui=bold ctermfg=NONE ctermbg=NONE cterm=bold hi Directory guifg=#00afff guibg=NONE gui=bold cterm=bold - hi Conceal guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE + hi Conceal guifg=#585858 guibg=NONE gui=NONE cterm=NONE hi Ignore guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi DiffAdd guifg=#afffaf guibg=#5f875f gui=NONE cterm=NONE hi DiffChange guifg=#d0d0d0 guibg=#5f5f5f gui=NONE cterm=NONE @@ -111,14 +113,14 @@ else endfor endif hi Normal guifg=#000000 guibg=#ffffff gui=NONE cterm=NONE - hi Statusline guifg=#ffffff guibg=#5f5f5f gui=NONE cterm=NONE + hi Statusline guifg=#ffffff guibg=#5f5f5f gui=bold cterm=bold hi StatuslineNC guifg=#000000 guibg=#d0d0d0 gui=NONE cterm=NONE - hi VertSplit guifg=#d0d0d0 guibg=#d0d0d0 gui=NONE cterm=NONE + hi VertSplit guifg=#5f5f5f guibg=NONE gui=NONE cterm=NONE hi TabLine guifg=#000000 guibg=#d0d0d0 gui=NONE cterm=NONE - hi TabLineFill guifg=NONE guibg=#808080 gui=NONE cterm=NONE - hi TabLineSel guifg=#ffffff guibg=#000000 gui=reverse cterm=reverse + hi TabLineFill guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE + hi TabLineSel guifg=#5f5f5f guibg=#ffffff gui=bold,reverse cterm=bold,reverse hi ToolbarLine guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE - hi ToolbarButton guifg=#ffffff guibg=#000000 gui=NONE cterm=NONE + hi ToolbarButton guifg=#ffffff guibg=#5f5f5f gui=NONE cterm=NONE hi QuickFixLine guifg=#ffffff guibg=#870087 gui=NONE cterm=NONE hi CursorLineNr guifg=#000000 guibg=NONE gui=bold cterm=bold hi LineNr guifg=#b2b2b2 guibg=NONE gui=NONE cterm=NONE @@ -127,13 +129,15 @@ else hi EndOfBuffer guifg=#b2b2b2 guibg=NONE gui=NONE cterm=NONE hi SpecialKey guifg=#b2b2b2 guibg=NONE gui=NONE cterm=NONE hi Pmenu guifg=#000000 guibg=#e4e4e4 gui=NONE cterm=NONE - hi PmenuSel guifg=#ffffff guibg=#d78700 gui=NONE cterm=NONE + hi PmenuSel guifg=#000000 guibg=#b2b2b2 gui=NONE cterm=NONE hi PmenuThumb guifg=NONE guibg=#808080 gui=NONE cterm=NONE hi PmenuSbar guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuKind guifg=#d70000 guibg=#e4e4e4 gui=NONE cterm=NONE - hi PmenuKindSel guifg=#af0000 guibg=#d78700 gui=NONE cterm=NONE + hi PmenuKindSel guifg=#d70000 guibg=#b2b2b2 gui=NONE cterm=NONE hi PmenuExtra guifg=#808080 guibg=#e4e4e4 gui=NONE cterm=NONE - hi PmenuExtraSel guifg=#ffffff guibg=#d78700 gui=NONE cterm=NONE + hi PmenuExtraSel guifg=#808080 guibg=#b2b2b2 gui=NONE cterm=NONE + hi PmenuMatch guifg=#870087 guibg=#e4e4e4 gui=NONE cterm=NONE + hi PmenuMatchSel guifg=#870087 guibg=#b2b2b2 gui=NONE cterm=NONE hi SignColumn guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi Error guifg=#d70000 guibg=#ffffff gui=reverse cterm=reverse hi ErrorMsg guifg=#d70000 guibg=#ffffff gui=reverse cterm=reverse @@ -141,7 +145,7 @@ else hi MoreMsg guifg=#008700 guibg=NONE gui=NONE cterm=NONE hi Question guifg=#870087 guibg=NONE gui=NONE cterm=NONE hi WarningMsg guifg=#af5f00 guibg=NONE gui=NONE cterm=NONE - hi Todo guifg=#8700ff guibg=#ffffff gui=reverse cterm=reverse + hi Todo guifg=#5f00d7 guibg=#ffffff gui=reverse cterm=reverse hi Search guifg=#ffffff guibg=#008700 gui=NONE cterm=NONE hi IncSearch guifg=#ffffff guibg=#d78700 gui=NONE cterm=NONE hi WildMenu guifg=#ffffff guibg=#d78700 gui=NONE cterm=NONE @@ -167,11 +171,11 @@ else hi Statement guifg=#005faf guibg=NONE gui=NONE cterm=NONE hi Type guifg=#af5f00 guibg=NONE gui=NONE cterm=NONE hi PreProc guifg=#008787 guibg=NONE gui=NONE cterm=NONE - hi Special guifg=#8700ff guibg=NONE gui=NONE cterm=NONE + hi Special guifg=#5f00d7 guibg=NONE gui=NONE cterm=NONE hi Underlined guifg=NONE guibg=NONE gui=underline ctermfg=NONE ctermbg=NONE cterm=underline hi Title guifg=NONE guibg=NONE gui=bold ctermfg=NONE ctermbg=NONE cterm=bold hi Directory guifg=#005faf guibg=NONE gui=bold cterm=bold - hi Conceal guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE + hi Conceal guifg=#b2b2b2 guibg=NONE gui=NONE cterm=NONE hi Ignore guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi DiffAdd guifg=#005f00 guibg=#afd7af gui=NONE cterm=NONE hi DiffChange guifg=#262626 guibg=#dadada gui=NONE cterm=NONE @@ -193,14 +197,14 @@ if s:t_Co >= 256 hi! link CurSearch IncSearch if &background ==# 'dark' hi Normal ctermfg=252 ctermbg=16 cterm=NONE - hi Statusline ctermfg=252 ctermbg=16 cterm=reverse + hi Statusline ctermfg=247 ctermbg=16 cterm=bold,reverse hi StatuslineNC ctermfg=243 ctermbg=16 cterm=reverse - hi VertSplit ctermfg=243 ctermbg=243 cterm=NONE - hi TabLine ctermfg=16 ctermbg=252 cterm=NONE - hi TabLineFill ctermfg=NONE ctermbg=243 cterm=NONE - hi TabLineSel ctermfg=231 ctermbg=16 cterm=NONE + hi VertSplit ctermfg=243 ctermbg=NONE cterm=NONE + hi TabLine ctermfg=16 ctermbg=243 cterm=NONE + hi TabLineFill ctermfg=NONE ctermbg=16 cterm=NONE + hi TabLineSel ctermfg=16 ctermbg=247 cterm=bold hi ToolbarLine ctermfg=NONE ctermbg=NONE cterm=NONE - hi ToolbarButton ctermfg=16 ctermbg=231 cterm=NONE + hi ToolbarButton ctermfg=16 ctermbg=252 cterm=NONE hi QuickFixLine ctermfg=16 ctermbg=213 cterm=NONE hi CursorLineNr ctermfg=231 ctermbg=NONE cterm=bold hi LineNr ctermfg=240 ctermbg=NONE cterm=NONE @@ -210,13 +214,15 @@ if s:t_Co >= 256 hi EndOfBuffer ctermfg=240 ctermbg=NONE cterm=NONE hi EndOfBuffer ctermfg=243 ctermbg=NONE cterm=NONE hi Pmenu ctermfg=252 ctermbg=236 cterm=NONE - hi PmenuSel ctermfg=16 ctermbg=214 cterm=NONE + hi PmenuSel ctermfg=252 ctermbg=240 cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=252 cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuKind ctermfg=204 ctermbg=236 cterm=NONE - hi PmenuKindSel ctermfg=161 ctermbg=214 cterm=NONE + hi PmenuKindSel ctermfg=204 ctermbg=240 cterm=NONE hi PmenuExtra ctermfg=243 ctermbg=236 cterm=NONE - hi PmenuExtraSel ctermfg=16 ctermbg=214 cterm=NONE + hi PmenuExtraSel ctermfg=243 ctermbg=240 cterm=NONE + hi PmenuMatch ctermfg=176 ctermbg=236 cterm=NONE + hi PmenuMatchSel ctermfg=176 ctermbg=240 cterm=NONE hi SignColumn ctermfg=NONE ctermbg=NONE cterm=NONE hi Error ctermfg=161 ctermbg=231 cterm=reverse hi ErrorMsg ctermfg=161 ctermbg=231 cterm=reverse @@ -230,17 +236,17 @@ if s:t_Co >= 256 hi WildMenu ctermfg=16 ctermbg=214 cterm=NONE hi debugPC ctermfg=32 ctermbg=NONE cterm=reverse hi debugBreakpoint ctermfg=37 ctermbg=NONE cterm=reverse - hi Visual ctermfg=32 ctermbg=16 cterm=reverse + hi Visual ctermfg=81 ctermbg=16 cterm=reverse hi VisualNOS ctermfg=16 ctermbg=39 cterm=NONE hi CursorLine ctermfg=NONE ctermbg=235 cterm=NONE hi CursorColumn ctermfg=NONE ctermbg=235 cterm=NONE hi Folded ctermfg=243 ctermbg=236 cterm=NONE hi ColorColumn ctermfg=NONE ctermbg=236 cterm=NONE hi MatchParen ctermfg=199 ctermbg=NONE cterm=bold - hi SpellBad ctermfg=161 ctermbg=231 cterm=reverse - hi SpellCap ctermfg=37 ctermbg=16 cterm=reverse - hi SpellLocal ctermfg=41 ctermbg=16 cterm=reverse - hi SpellRare ctermfg=213 ctermbg=16 cterm=reverse + hi SpellBad ctermfg=161 ctermbg=NONE cterm=underline + hi SpellCap ctermfg=37 ctermbg=NONE cterm=underline + hi SpellLocal ctermfg=41 ctermbg=NONE cterm=underline + hi SpellRare ctermfg=213 ctermbg=NONE cterm=underline hi Comment ctermfg=243 ctermbg=NONE cterm=NONE hi Constant ctermfg=204 ctermbg=NONE cterm=NONE hi String ctermfg=41 ctermbg=NONE cterm=NONE @@ -252,7 +258,7 @@ if s:t_Co >= 256 hi Underlined ctermfg=NONE ctermbg=NONE cterm=underline hi Title ctermfg=NONE ctermbg=NONE cterm=bold hi Directory ctermfg=39 ctermbg=NONE cterm=bold - hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE + hi Conceal ctermfg=240 ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi DiffAdd ctermfg=157 ctermbg=65 cterm=NONE hi DiffChange ctermfg=252 ctermbg=59 cterm=NONE @@ -264,14 +270,14 @@ if s:t_Co >= 256 else " Light background hi Normal ctermfg=16 ctermbg=231 cterm=NONE - hi Statusline ctermfg=231 ctermbg=59 cterm=NONE + hi Statusline ctermfg=231 ctermbg=59 cterm=bold hi StatuslineNC ctermfg=16 ctermbg=252 cterm=NONE - hi VertSplit ctermfg=252 ctermbg=252 cterm=NONE + hi VertSplit ctermfg=59 ctermbg=NONE cterm=NONE hi TabLine ctermfg=16 ctermbg=252 cterm=NONE - hi TabLineFill ctermfg=NONE ctermbg=240 cterm=NONE - hi TabLineSel ctermfg=231 ctermbg=16 cterm=reverse + hi TabLineFill ctermfg=NONE ctermbg=NONE cterm=NONE + hi TabLineSel ctermfg=59 ctermbg=231 cterm=bold,reverse hi ToolbarLine ctermfg=NONE ctermbg=NONE cterm=NONE - hi ToolbarButton ctermfg=231 ctermbg=16 cterm=NONE + hi ToolbarButton ctermfg=231 ctermbg=59 cterm=NONE hi QuickFixLine ctermfg=231 ctermbg=90 cterm=NONE hi CursorLineNr ctermfg=16 ctermbg=NONE cterm=bold hi LineNr ctermfg=249 ctermbg=NONE cterm=NONE @@ -280,13 +286,15 @@ if s:t_Co >= 256 hi EndOfBuffer ctermfg=249 ctermbg=NONE cterm=NONE hi SpecialKey ctermfg=249 ctermbg=NONE cterm=NONE hi Pmenu ctermfg=16 ctermbg=254 cterm=NONE - hi PmenuSel ctermfg=231 ctermbg=172 cterm=NONE + hi PmenuSel ctermfg=16 ctermbg=249 cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=240 cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=NONE cterm=NONE hi PmenuKind ctermfg=160 ctermbg=254 cterm=NONE - hi PmenuKindSel ctermfg=124 ctermbg=172 cterm=NONE + hi PmenuKindSel ctermfg=160 ctermbg=249 cterm=NONE hi PmenuExtra ctermfg=240 ctermbg=254 cterm=NONE - hi PmenuExtraSel ctermfg=231 ctermbg=172 cterm=NONE + hi PmenuExtraSel ctermfg=240 ctermbg=249 cterm=NONE + hi PmenuMatch ctermfg=90 ctermbg=254 cterm=NONE + hi PmenuMatchSel ctermfg=90 ctermbg=249 cterm=NONE hi SignColumn ctermfg=NONE ctermbg=NONE cterm=NONE hi Error ctermfg=160 ctermbg=231 cterm=reverse hi ErrorMsg ctermfg=160 ctermbg=231 cterm=reverse @@ -294,7 +302,7 @@ if s:t_Co >= 256 hi MoreMsg ctermfg=28 ctermbg=NONE cterm=NONE hi Question ctermfg=90 ctermbg=NONE cterm=NONE hi WarningMsg ctermfg=130 ctermbg=NONE cterm=NONE - hi Todo ctermfg=93 ctermbg=231 cterm=reverse + hi Todo ctermfg=56 ctermbg=231 cterm=reverse hi Search ctermfg=231 ctermbg=28 cterm=NONE hi IncSearch ctermfg=231 ctermbg=172 cterm=NONE hi WildMenu ctermfg=231 ctermbg=172 cterm=NONE @@ -307,10 +315,10 @@ if s:t_Co >= 256 hi Folded ctermfg=240 ctermbg=254 cterm=NONE hi ColorColumn ctermfg=NONE ctermbg=254 cterm=NONE hi MatchParen ctermfg=199 ctermbg=NONE cterm=bold - hi SpellBad ctermfg=160 ctermbg=231 cterm=reverse - hi SpellCap ctermfg=30 ctermbg=231 cterm=reverse - hi SpellLocal ctermfg=28 ctermbg=231 cterm=reverse - hi SpellRare ctermfg=127 ctermbg=231 cterm=reverse + hi SpellBad ctermfg=160 ctermbg=NONE cterm=underline + hi SpellCap ctermfg=30 ctermbg=NONE cterm=underline + hi SpellLocal ctermfg=28 ctermbg=NONE cterm=underline + hi SpellRare ctermfg=127 ctermbg=NONE cterm=underline hi Comment ctermfg=245 ctermbg=NONE cterm=NONE hi Constant ctermfg=124 ctermbg=NONE cterm=NONE hi String ctermfg=28 ctermbg=NONE cterm=NONE @@ -318,11 +326,11 @@ if s:t_Co >= 256 hi Statement ctermfg=25 ctermbg=NONE cterm=NONE hi Type ctermfg=130 ctermbg=NONE cterm=NONE hi PreProc ctermfg=30 ctermbg=NONE cterm=NONE - hi Special ctermfg=93 ctermbg=NONE cterm=NONE + hi Special ctermfg=56 ctermbg=NONE cterm=NONE hi Underlined ctermfg=NONE ctermbg=NONE cterm=underline hi Title ctermfg=NONE ctermbg=NONE cterm=bold hi Directory ctermfg=25 ctermbg=NONE cterm=bold - hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE + hi Conceal ctermfg=249 ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi DiffAdd ctermfg=22 ctermbg=151 cterm=NONE hi DiffChange ctermfg=235 ctermbg=253 cterm=NONE @@ -339,14 +347,14 @@ endif if s:t_Co >= 16 if &background ==# 'dark' hi Normal ctermfg=grey ctermbg=black cterm=NONE - hi Statusline ctermfg=grey ctermbg=black cterm=reverse + hi Statusline ctermfg=grey ctermbg=black cterm=bold,reverse hi StatuslineNC ctermfg=darkgrey ctermbg=black cterm=reverse - hi VertSplit ctermfg=darkgrey ctermbg=darkgrey cterm=NONE - hi TabLine ctermfg=black ctermbg=grey cterm=NONE - hi TabLineFill ctermfg=NONE ctermbg=darkgrey cterm=NONE - hi TabLineSel ctermfg=white ctermbg=black cterm=NONE + hi VertSplit ctermfg=darkgrey ctermbg=NONE cterm=NONE + hi TabLine ctermfg=black ctermbg=darkgrey cterm=NONE + hi TabLineFill ctermfg=NONE ctermbg=black cterm=NONE + hi TabLineSel ctermfg=black ctermbg=grey cterm=bold hi ToolbarLine ctermfg=NONE ctermbg=NONE cterm=NONE - hi ToolbarButton ctermfg=black ctermbg=white cterm=NONE + hi ToolbarButton ctermfg=black ctermbg=grey cterm=NONE hi QuickFixLine ctermfg=black ctermbg=magenta cterm=NONE hi CursorLineNr ctermfg=white ctermbg=NONE cterm=bold hi LineNr ctermfg=grey ctermbg=NONE cterm=NONE @@ -362,6 +370,8 @@ if s:t_Co >= 16 hi PmenuKindSel ctermfg=darkred ctermbg=darkyellow cterm=NONE hi PmenuExtra ctermfg=darkgrey ctermbg=grey cterm=NONE hi PmenuExtraSel ctermfg=black ctermbg=darkyellow cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=grey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkyellow cterm=bold hi SignColumn ctermfg=NONE ctermbg=NONE cterm=NONE hi Error ctermfg=darkred ctermbg=white cterm=reverse hi ErrorMsg ctermfg=darkred ctermbg=white cterm=reverse @@ -375,17 +385,17 @@ if s:t_Co >= 16 hi WildMenu ctermfg=black ctermbg=yellow cterm=NONE hi debugPC ctermfg=darkblue ctermbg=NONE cterm=reverse hi debugBreakpoint ctermfg=darkcyan ctermbg=NONE cterm=reverse - hi Visual ctermfg=darkblue ctermbg=black cterm=reverse + hi Visual ctermfg=cyan ctermbg=black cterm=reverse hi VisualNOS ctermfg=black ctermbg=blue cterm=NONE hi CursorLine ctermfg=NONE ctermbg=NONE cterm=underline hi CursorColumn ctermfg=black ctermbg=yellow cterm=NONE hi Folded ctermfg=black ctermbg=NONE cterm=bold hi ColorColumn ctermfg=black ctermbg=darkyellow cterm=NONE hi MatchParen ctermfg=NONE ctermbg=NONE cterm=bold,underline - hi SpellBad ctermfg=darkred ctermbg=white cterm=reverse - hi SpellCap ctermfg=darkcyan ctermbg=black cterm=reverse - hi SpellLocal ctermfg=green ctermbg=black cterm=reverse - hi SpellRare ctermfg=magenta ctermbg=black cterm=reverse + hi SpellBad ctermfg=darkred ctermbg=NONE cterm=underline + hi SpellCap ctermfg=darkcyan ctermbg=NONE cterm=underline + hi SpellLocal ctermfg=green ctermbg=NONE cterm=underline + hi SpellRare ctermfg=magenta ctermbg=NONE cterm=underline hi Comment ctermfg=darkgrey ctermbg=NONE cterm=NONE hi Constant ctermfg=red ctermbg=NONE cterm=NONE hi String ctermfg=green ctermbg=NONE cterm=NONE @@ -397,7 +407,7 @@ if s:t_Co >= 16 hi Underlined ctermfg=NONE ctermbg=NONE cterm=underline hi Title ctermfg=NONE ctermbg=NONE cterm=bold hi Directory ctermfg=blue ctermbg=NONE cterm=bold - hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE + hi Conceal ctermfg=grey ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi DiffAdd ctermfg=black ctermbg=darkgreen cterm=NONE hi DiffChange ctermfg=black ctermbg=lightgray cterm=NONE @@ -409,14 +419,14 @@ if s:t_Co >= 16 else " Light background hi Normal ctermfg=black ctermbg=white cterm=NONE - hi Statusline ctermfg=white ctermbg=darkgrey cterm=NONE + hi Statusline ctermfg=white ctermbg=darkgrey cterm=bold hi StatuslineNC ctermfg=black ctermbg=lightgrey cterm=NONE - hi VertSplit ctermfg=lightgrey ctermbg=lightgrey cterm=NONE + hi VertSplit ctermfg=darkgrey ctermbg=NONE cterm=NONE hi TabLine ctermfg=black ctermbg=lightgrey cterm=NONE - hi TabLineFill ctermfg=NONE ctermbg=darkgrey cterm=NONE - hi TabLineSel ctermfg=white ctermbg=black cterm=reverse + hi TabLineFill ctermfg=NONE ctermbg=NONE cterm=NONE + hi TabLineSel ctermfg=darkgrey ctermbg=white cterm=bold,reverse hi ToolbarLine ctermfg=NONE ctermbg=NONE cterm=NONE - hi ToolbarButton ctermfg=white ctermbg=black cterm=NONE + hi ToolbarButton ctermfg=white ctermbg=darkgrey cterm=NONE hi QuickFixLine ctermfg=white ctermbg=darkmagenta cterm=NONE hi CursorLineNr ctermfg=black ctermbg=NONE cterm=bold hi LineNr ctermfg=darkgrey ctermbg=NONE cterm=NONE @@ -432,6 +442,8 @@ if s:t_Co >= 16 hi PmenuKindSel ctermfg=darkred ctermbg=darkyellow cterm=NONE hi PmenuExtra ctermfg=darkgrey ctermbg=grey cterm=NONE hi PmenuExtraSel ctermfg=black ctermbg=darkyellow cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=grey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkyellow cterm=bold hi SignColumn ctermfg=NONE ctermbg=NONE cterm=NONE hi Error ctermfg=red ctermbg=white cterm=reverse hi ErrorMsg ctermfg=red ctermbg=white cterm=reverse @@ -439,7 +451,7 @@ if s:t_Co >= 16 hi MoreMsg ctermfg=darkgreen ctermbg=NONE cterm=NONE hi Question ctermfg=darkmagenta ctermbg=NONE cterm=NONE hi WarningMsg ctermfg=darkyellow ctermbg=NONE cterm=NONE - hi Todo ctermfg=darkred ctermbg=white cterm=reverse + hi Todo ctermfg=blue ctermbg=white cterm=reverse hi Search ctermfg=white ctermbg=darkgreen cterm=NONE hi IncSearch ctermfg=white ctermbg=yellow cterm=NONE hi WildMenu ctermfg=white ctermbg=yellow cterm=NONE @@ -452,10 +464,10 @@ if s:t_Co >= 16 hi Folded ctermfg=black ctermbg=NONE cterm=bold hi ColorColumn ctermfg=black ctermbg=darkyellow cterm=NONE hi MatchParen ctermfg=NONE ctermbg=NONE cterm=bold,underline - hi SpellBad ctermfg=red ctermbg=white cterm=reverse - hi SpellCap ctermfg=darkcyan ctermbg=white cterm=reverse - hi SpellLocal ctermfg=darkgreen ctermbg=white cterm=reverse - hi SpellRare ctermfg=magenta ctermbg=white cterm=reverse + hi SpellBad ctermfg=red ctermbg=NONE cterm=underline + hi SpellCap ctermfg=darkcyan ctermbg=NONE cterm=underline + hi SpellLocal ctermfg=darkgreen ctermbg=NONE cterm=underline + hi SpellRare ctermfg=magenta ctermbg=NONE cterm=underline hi Comment ctermfg=darkgrey ctermbg=NONE cterm=NONE hi Constant ctermfg=darkred ctermbg=NONE cterm=NONE hi String ctermfg=darkgreen ctermbg=NONE cterm=NONE @@ -463,11 +475,11 @@ if s:t_Co >= 16 hi Statement ctermfg=darkblue ctermbg=NONE cterm=NONE hi Type ctermfg=darkyellow ctermbg=NONE cterm=NONE hi PreProc ctermfg=darkcyan ctermbg=NONE cterm=NONE - hi Special ctermfg=darkred ctermbg=NONE cterm=NONE + hi Special ctermfg=blue ctermbg=NONE cterm=NONE hi Underlined ctermfg=NONE ctermbg=NONE cterm=underline hi Title ctermfg=NONE ctermbg=NONE cterm=bold hi Directory ctermfg=darkblue ctermbg=NONE cterm=bold - hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE + hi Conceal ctermfg=darkgrey ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi DiffAdd ctermfg=black ctermbg=darkgreen cterm=NONE hi DiffChange ctermfg=black ctermbg=lightgray cterm=NONE @@ -486,10 +498,10 @@ if s:t_Co >= 8 hi Normal ctermfg=grey ctermbg=black cterm=NONE hi Statusline ctermfg=grey ctermbg=black cterm=bold,reverse hi StatuslineNC ctermfg=black ctermbg=grey cterm=NONE - hi VertSplit ctermfg=grey ctermbg=grey cterm=NONE - hi TabLine ctermfg=grey ctermbg=black cterm=reverse - hi TabLineFill ctermfg=NONE ctermbg=grey cterm=NONE - hi TabLineSel ctermfg=grey ctermbg=black cterm=NONE + hi VertSplit ctermfg=grey ctermbg=NONE cterm=NONE + hi TabLine ctermfg=grey ctermbg=black cterm=NONE + hi TabLineFill ctermfg=grey ctermbg=NONE cterm=NONE + hi TabLineSel ctermfg=grey ctermbg=black cterm=bold,reverse hi ToolbarLine ctermfg=NONE ctermbg=NONE cterm=NONE hi ToolbarButton ctermfg=grey ctermbg=black cterm=bold,reverse hi QuickFixLine ctermfg=black ctermbg=darkmagenta cterm=NONE @@ -507,6 +519,8 @@ if s:t_Co >= 8 hi PmenuKindSel ctermfg=darkred ctermbg=darkyellow cterm=NONE hi PmenuExtra ctermfg=black ctermbg=grey cterm=NONE hi PmenuExtraSel ctermfg=black ctermbg=darkyellow cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=grey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkyellow cterm=bold hi SignColumn ctermfg=NONE ctermbg=NONE cterm=NONE hi Error ctermfg=grey ctermbg=darkred cterm=NONE hi ErrorMsg ctermfg=grey ctermbg=darkred cterm=NONE @@ -553,10 +567,10 @@ if s:t_Co >= 8 hi Normal ctermfg=black ctermbg=grey cterm=NONE hi Statusline ctermfg=grey ctermbg=black cterm=bold hi StatuslineNC ctermfg=grey ctermbg=darkgrey cterm=NONE - hi VertSplit ctermfg=black ctermbg=black cterm=NONE - hi TabLine ctermfg=black ctermbg=grey cterm=reverse - hi TabLineFill ctermfg=NONE ctermbg=darkgrey cterm=NONE - hi TabLineSel ctermfg=black ctermbg=grey cterm=NONE + hi VertSplit ctermfg=black ctermbg=NONE cterm=NONE + hi TabLine ctermfg=black ctermbg=grey cterm=NONE + hi TabLineFill ctermfg=NONE ctermbg=NONE cterm=NONE + hi TabLineSel ctermfg=grey ctermbg=black cterm=bold hi ToolbarLine ctermfg=NONE ctermbg=NONE cterm=NONE hi ToolbarButton ctermfg=grey ctermbg=black cterm=bold hi QuickFixLine ctermfg=black ctermbg=darkmagenta cterm=NONE @@ -574,6 +588,8 @@ if s:t_Co >= 8 hi PmenuKindSel ctermfg=darkred ctermbg=darkyellow cterm=NONE hi PmenuExtra ctermfg=grey ctermbg=black cterm=NONE hi PmenuExtraSel ctermfg=black ctermbg=darkyellow cterm=NONE + hi PmenuMatch ctermfg=grey ctermbg=black cterm=bold + hi PmenuMatchSel ctermfg=NONE ctermbg=darkyellow cterm=bold hi SignColumn ctermfg=NONE ctermbg=NONE cterm=NONE hi Error ctermfg=white ctermbg=darkred cterm=NONE hi ErrorMsg ctermfg=white ctermbg=darkred cterm=NONE @@ -581,7 +597,7 @@ if s:t_Co >= 8 hi MoreMsg ctermfg=darkgreen ctermbg=NONE cterm=NONE hi Question ctermfg=darkmagenta ctermbg=NONE cterm=NONE hi WarningMsg ctermfg=darkyellow ctermbg=NONE cterm=NONE - hi Todo ctermfg=darkred ctermbg=black cterm=reverse + hi Todo ctermfg=blue ctermbg=black cterm=reverse hi Search ctermfg=darkgreen ctermbg=black cterm=reverse hi IncSearch ctermfg=darkyellow ctermbg=black cterm=reverse hi WildMenu ctermfg=black ctermbg=darkyellow cterm=NONE @@ -715,6 +731,8 @@ endif " Color: colorlC #ff5fff 207 magenta " Color: colorDim #878787 102 grey " Color: colorMP #ff00af 199 magenta +" Color: colorV #5fd7ff 81 cyan +" Color: colorSt #9e9e9e 247 grey " Color: diffAdd #5f875f 65 darkgreen " Color: diffAddFg #afffaf 157 black " Color: diffDelete #875f5f 95 darkred @@ -742,7 +760,7 @@ endif " Color: color14 #00afaf 37 cyan " Color: color07 #8a8a8a 245 grey " Color: color15 #ffffff 231 white -" Color: color16 #8700ff 93 darkred +" Color: color16 #5f00d7 56 blue " Color: colorCm #8a8a8a 245 darkgrey " Color: colorLine #EEEEEE 255 grey " Color: colorB #E4E4E4 254 grey @@ -750,7 +768,7 @@ endif " Color: colorTab #d0d0d0 252 lightgrey " Color: colorC #000000 16 black " Color: colorlC #FF00FF 201 magenta -" Color: colorV #5F87AF 67 darkblue +" Color: colorV #0087af 31 darkcyan " Color: colorDim #626262 241 darkgrey " Color: colorSt #5f5f5f 59 darkgrey " Color: colorMP #ff00af 199 magenta diff --git a/runtime/colors/zaibatsu.vim b/runtime/colors/zaibatsu.vim index 726843345b..90c6104afe 100644 --- a/runtime/colors/zaibatsu.vim +++ b/runtime/colors/zaibatsu.vim @@ -4,7 +4,7 @@ " Maintainer: Romain Lafourcade <romainlafourcade@gmail.com> " Website: https://github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Fri 15 Dec 2023 20:05:43 +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -40,6 +40,8 @@ hi PmenuExtra guifg=#878092 guibg=#ffffff gui=NONE cterm=NONE hi! link PmenuExtraSel PmenuSel hi PmenuKind guifg=#878092 guibg=#ffffff gui=NONE cterm=NONE hi! link PmenuKindSel PmenuSel +hi PmenuMatch guifg=#d700ff guibg=#ffffff gui=NONE cterm=NONE +hi PmenuMatchSel guifg=#d700ff guibg=#afafff gui=NONE cterm=NONE hi ColorColumn guifg=NONE guibg=#510039 gui=NONE cterm=NONE hi CursorLine guifg=NONE guibg=#362b49 gui=NONE cterm=NONE hi CursorColumn guifg=NONE guibg=#362b49 gui=NONE cterm=NONE @@ -143,6 +145,8 @@ if s:t_Co >= 256 hi! link PmenuExtraSel PmenuSel hi PmenuKind ctermfg=103 ctermbg=231 cterm=NONE hi! link PmenuKindSel PmenuSel + hi PmenuMatch ctermfg=165 ctermbg=231 cterm=NONE + hi PmenuMatchSel ctermfg=165 ctermbg=147 cterm=NONE hi ColorColumn ctermfg=NONE ctermbg=52 cterm=NONE hi CursorLine ctermfg=NONE ctermbg=237 cterm=NONE hi CursorColumn ctermfg=NONE ctermbg=237 cterm=NONE @@ -249,6 +253,8 @@ if s:t_Co >= 16 hi! link PmenuExtraSel PmenuSel hi PmenuKind ctermfg=darkgray ctermbg=white cterm=NONE hi! link PmenuKindSel PmenuSel + hi PmenuMatch ctermfg=black ctermbg=white cterm=bold + hi PmenuMatchSel ctermfg=white ctermbg=blue cterm=bold hi ColorColumn ctermfg=white ctermbg=darkred cterm=NONE hi CursorLine ctermfg=NONE ctermbg=NONE cterm=underline hi CursorColumn ctermfg=NONE ctermbg=blue cterm=NONE @@ -355,6 +361,8 @@ if s:t_Co >= 8 hi! link PmenuExtraSel PmenuSel hi! link PmenuKind Pmenu hi! link PmenuKindSel PmenuSel + hi PmenuMatch ctermfg=black ctermbg=white cterm=bold + hi PmenuMatchSel ctermfg=white ctermbg=blue cterm=bold hi ColorColumn ctermfg=white ctermbg=darkred cterm=NONE hi CursorLine ctermfg=NONE ctermbg=NONE cterm=underline hi CursorColumn ctermfg=NONE ctermbg=blue cterm=NONE diff --git a/runtime/colors/zellner.vim b/runtime/colors/zellner.vim index 37f012e92d..7781ca9ab8 100644 --- a/runtime/colors/zellner.vim +++ b/runtime/colors/zellner.vim @@ -4,7 +4,7 @@ " Maintainer: Original maintainer Ron Aaron <ron@ronware.org> " Website: https://github.com/vim/colorschemes " License: Same as Vim -" Last Updated: Fri 15 Dec 2023 20:05:44 +" Last Change: 2024 Aug 15 " Generated by Colortemplate v2.2.3 @@ -47,6 +47,8 @@ hi Pmenu guifg=#000000 guibg=#dadada gui=NONE cterm=NONE hi PmenuSel guifg=#000000 guibg=#ffff00 gui=NONE cterm=NONE hi PmenuSbar guifg=NONE guibg=#ffffff gui=NONE cterm=NONE hi PmenuThumb guifg=NONE guibg=#a9a9a9 gui=NONE cterm=NONE +hi PmenuMatch guifg=#a52a2a guibg=#dadada gui=NONE cterm=NONE +hi PmenuMatchSel guifg=#a52a2a guibg=#ffff00 gui=NONE cterm=NONE hi TabLine guifg=#000000 guibg=#a9a9a9 gui=underline cterm=underline hi TabLineFill guifg=NONE guibg=NONE gui=reverse ctermfg=NONE ctermbg=NONE cterm=reverse hi TabLineSel guifg=#000000 guibg=#ffffff gui=bold cterm=bold @@ -87,7 +89,7 @@ hi Type guifg=#0000ff guibg=NONE gui=NONE cterm=NONE hi Special guifg=#ff00ff guibg=NONE gui=NONE cterm=NONE hi Tag guifg=#006400 guibg=NONE gui=NONE cterm=NONE hi Directory guifg=#0000ff guibg=NONE gui=bold cterm=bold -hi Conceal guifg=#ff0000 guibg=NONE gui=NONE cterm=NONE +hi Conceal guifg=#a9a9a9 guibg=NONE gui=NONE cterm=NONE hi Ignore guifg=NONE guibg=NONE gui=NONE ctermfg=NONE ctermbg=NONE cterm=NONE hi Title guifg=#a020f0 guibg=NONE gui=bold cterm=bold hi DiffAdd guifg=#ffffff guibg=#5f875f gui=NONE cterm=NONE @@ -120,6 +122,8 @@ if s:t_Co >= 256 hi PmenuSel ctermfg=16 ctermbg=226 cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=231 cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=248 cterm=NONE + hi PmenuMatch ctermfg=124 ctermbg=253 cterm=NONE + hi PmenuMatchSel ctermfg=124 ctermbg=226 cterm=NONE hi TabLine ctermfg=16 ctermbg=248 cterm=underline hi TabLineFill ctermfg=NONE ctermbg=NONE cterm=reverse hi TabLineSel ctermfg=16 ctermbg=231 cterm=bold @@ -160,7 +164,7 @@ if s:t_Co >= 256 hi Special ctermfg=201 ctermbg=NONE cterm=NONE hi Tag ctermfg=22 ctermbg=NONE cterm=NONE hi Directory ctermfg=21 ctermbg=NONE cterm=bold - hi Conceal ctermfg=196 ctermbg=NONE cterm=NONE + hi Conceal ctermfg=248 ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi Title ctermfg=129 ctermbg=NONE cterm=bold hi DiffAdd ctermfg=231 ctermbg=65 cterm=NONE @@ -188,6 +192,8 @@ if s:t_Co >= 16 hi PmenuSel ctermfg=black ctermbg=yellow cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=white cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=darkgrey cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=grey cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=yellow cterm=bold hi TabLine ctermfg=black ctermbg=grey cterm=underline hi TabLineFill ctermfg=NONE ctermbg=NONE cterm=reverse hi TabLineSel ctermfg=black ctermbg=white cterm=bold @@ -228,7 +234,7 @@ if s:t_Co >= 16 hi Special ctermfg=magenta ctermbg=NONE cterm=NONE hi Tag ctermfg=darkgreen ctermbg=NONE cterm=NONE hi Directory ctermfg=blue ctermbg=NONE cterm=bold - hi Conceal ctermfg=red ctermbg=NONE cterm=NONE + hi Conceal ctermfg=grey ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi Title ctermfg=darkmagenta ctermbg=NONE cterm=bold hi DiffAdd ctermfg=white ctermbg=darkgreen cterm=NONE @@ -256,6 +262,8 @@ if s:t_Co >= 8 hi PmenuSel ctermfg=black ctermbg=darkyellow cterm=NONE hi PmenuSbar ctermfg=NONE ctermbg=black cterm=NONE hi PmenuThumb ctermfg=NONE ctermbg=darkmagenta cterm=NONE + hi PmenuMatch ctermfg=black ctermbg=darkcyan cterm=bold + hi PmenuMatchSel ctermfg=black ctermbg=darkyellow cterm=bold hi TabLine ctermfg=black ctermbg=gray cterm=reverse hi TabLineFill ctermfg=NONE ctermbg=NONE cterm=reverse hi TabLineSel ctermfg=gray ctermbg=black cterm=bold,reverse @@ -293,7 +301,7 @@ if s:t_Co >= 8 hi Type ctermfg=darkblue ctermbg=NONE cterm=bold hi Special ctermfg=darkgreen ctermbg=NONE cterm=NONE hi Directory ctermfg=darkblue ctermbg=NONE cterm=bold - hi Conceal ctermfg=darkred ctermbg=NONE cterm=NONE + hi Conceal ctermfg=NONE ctermbg=NONE cterm=NONE hi Ignore ctermfg=NONE ctermbg=NONE cterm=NONE hi Title ctermfg=darkmagenta ctermbg=NONE cterm=bold hi DiffAdd ctermfg=white ctermbg=darkgreen cterm=NONE diff --git a/runtime/compiler/README.txt b/runtime/compiler/README.txt index dccf4a9762..327d0a7fde 100644 --- a/runtime/compiler/README.txt +++ b/runtime/compiler/README.txt @@ -4,6 +4,8 @@ They are used with the ":compiler" command. These scripts usually set options, for example 'errorformat'. See ":help write-compiler-plugin". +To undo the effect of a compiler plugin, use the make compiler plugin. + If you want to write your own compiler plugin, have a look at the other files for how to do it, the format is simple. diff --git a/runtime/compiler/cppcheck.vim b/runtime/compiler/cppcheck.vim new file mode 100644 index 0000000000..ed7c46e90f --- /dev/null +++ b/runtime/compiler/cppcheck.vim @@ -0,0 +1,40 @@ +" vim compiler file +" Compiler: cppcheck (C++ static checker) +" Maintainer: Vincent B. (twinside@free.fr) +" Last Change: 2024 Oct 4 by @Konfekt + +if exists("cppcheck") + finish +endif +let current_compiler = "cppcheck" + +let s:cpo_save = &cpo +set cpo-=C + +if !exists('g:c_cppcheck_params') + let g:c_cppcheck_params = '--verbose --force --inline-suppr' + \ ..' '..'--enable=warning,style,performance,portability,information,missingInclude' + \ ..' '..(executable('getconf') ? '-j' .. systemlist('getconf _NPROCESSORS_ONLN')[0] : '') + let s:undo_compiler = 'unlet! g:c_cppcheck_params' +endif + +let &l:makeprg = 'cppcheck --quiet' + \ ..' --template="{file}:{line}:{column}: {severity}: [{id}] {message} {callstack}"' + \ ..' '..get(b:, 'c_cppcheck_params', + \ g:c_cppcheck_params..' '..(&filetype ==# 'cpp' ? ' --language=c++' : '')) + \ ..' '..get(b:, 'c_cppcheck_includes', get(g:, 'c_cppcheck_includes', + \ (filereadable('compile_commands.json') ? '--project=compile_commands.json' : + \ (empty(&path) ? '' : '-I')..join(map(filter(split(&path, ','), 'isdirectory(v:val)'),'shellescape(v:val)'), ' -I')))) +silent CompilerSet makeprg + +CompilerSet errorformat= + \%f:%l:%c:\ %tarning:\ %m, + \%f:%l:%c:\ %trror:\ %m, + \%f:%l:%c:\ %tnformation:\ %m, + \%f:%l:%c:\ %m, + \%.%#\ :\ [%f:%l]\ %m + +exe get(s:, 'undo_compiler', '') + +let &cpo = s:cpo_save +unlet s:cpo_save diff --git a/runtime/compiler/groff.vim b/runtime/compiler/groff.vim new file mode 100644 index 0000000000..640146d6a1 --- /dev/null +++ b/runtime/compiler/groff.vim @@ -0,0 +1,45 @@ +" Vim compiler file +" Compiler: Groff +" Maintainer: Konfekt +" Last Change: 2024 Sep 8 +" +" Expects output file extension, say `:make html` or `:make pdf`. +" Supported devices as of Sept 2024 are: (x)html, pdf, ps, dvi, lj4, lbp ... +" Adjust command-line flags, language, encoding by buffer-local/global variables +" groff_compiler_args, groff_compiler_lang, and groff_compiler_encoding, +" which default to '', &spelllang and 'utf8'. + +if exists("current_compiler") + finish +endif + +let s:keepcpo = &cpo +set cpo&vim + +let current_compiler = 'groff' + +silent! function s:groff_compiler_lang() + let lang = get(b:, 'groff_compiler_lang', + \ &spell ? matchstr(&spelllang, '^\a\a') : '') + if lang ==# 'en' | let lang = '' | endif + return empty(lang) ? '' : '-m'..lang +endfunction + +" Requires output format (= device) to be set by user after :make. +execute 'CompilerSet makeprg=groff'..escape( + \ ' '..s:groff_compiler_lang().. + \ ' -K'..get(b:, 'groff_compiler_encoding', get(g:, 'groff_compiler_encoding', 'utf8')).. + \ ' '..get(b:, 'groff_compiler_args', get(g:, 'groff_compiler_args', '')).. + \ ' -mom -T$* -- %:S > %:r:S.$*', ' ') +" From Gavin Freeborn's https://github.com/Gavinok/vim-troff under Vim License +" https://github.com/Gavinok/vim-troff/blob/91017b1423caa80aba541c997909a4f810edd275/compiler/troff.vim#L39 +CompilerSet errorformat=%o:<standard\ input>\ (%f):%l:%m, + \%o:\ <standard\ input>\ (%f):%l:%m, + \%o:%f:%l:%m, + \%o:\ %f:%l:%m, + \%f:%l:\ macro\ %trror:%m, + \%f:%l:%m, + \%W%tarning:\ file\ '%f'\\,\ around\ line\ %l:,%Z%m + +let &cpo = s:keepcpo +unlet s:keepcpo diff --git a/runtime/compiler/hare.vim b/runtime/compiler/hare.vim index c98bbb9c63..33edb3a281 100644 --- a/runtime/compiler/hare.vim +++ b/runtime/compiler/hare.vim @@ -1,28 +1,29 @@ -" Vim compiler file -" Compiler: Hare Compiler -" Maintainer: Amelia Clarke <me@rsaihe.dev> -" Last Change: 2022-09-21 -" 2024 Apr 05 by The Vim Project (removed :CompilerSet definition) +" Vim compiler file. +" Compiler: Hare +" Maintainer: Amelia Clarke <selene@perilune.dev> +" Last Change: 2024-05-23 +" Upstream: https://git.sr.ht/~sircmpwn/hare.vim -if exists("g:current_compiler") +if exists('current_compiler') finish endif -let g:current_compiler = "hare" +let current_compiler = 'hare' let s:cpo_save = &cpo set cpo&vim -if filereadable("Makefile") || filereadable("makefile") +if filereadable('Makefile') || filereadable('makefile') CompilerSet makeprg=make else CompilerSet makeprg=hare\ build endif CompilerSet errorformat= - \Error\ %f:%l:%c:\ %m, - \Syntax\ error:\ %.%#\ at\ %f:%l:%c\\,\ %m, + \%f:%l:%c:\ syntax\ error:\ %m, + \%f:%l:%c:\ error:\ %m, \%-G%.%# let &cpo = s:cpo_save unlet s:cpo_save -" vim: tabstop=2 shiftwidth=2 expandtab + +" vim: et sts=2 sw=2 ts=8 diff --git a/runtime/compiler/javac.vim b/runtime/compiler/javac.vim index f5fe84124f..9bd4cdf270 100644 --- a/runtime/compiler/javac.vim +++ b/runtime/compiler/javac.vim @@ -1,7 +1,7 @@ " Vim compiler file " Compiler: Java Development Kit Compiler " Maintainer: Doug Kearns <dougkearns@gmail.com> -" Last Change: 2024 Apr 03 +" Last Change: 2024 Jun 14 if exists("current_compiler") finish @@ -11,7 +11,12 @@ let current_compiler = "javac" let s:cpo_save = &cpo set cpo&vim -CompilerSet makeprg=javac +if exists("g:javac_makeprg_params") + execute $'CompilerSet makeprg=javac\ {escape(g:javac_makeprg_params, ' \|"')}' +else + CompilerSet makeprg=javac +endif + CompilerSet errorformat=%E%f:%l:\ error:\ %m, \%W%f:%l:\ warning:\ %m, \%-Z%p^, diff --git a/runtime/compiler/make.vim b/runtime/compiler/make.vim new file mode 100644 index 0000000000..748251bf8e --- /dev/null +++ b/runtime/compiler/make.vim @@ -0,0 +1,13 @@ +" Vim compiler plugin +" +" Maintainer: The Vim Project <https://github.com/vim/vim> +" Last Change: 2024 Sep 10 +" Original Author: Konfekt +" +" This compiler plugin is used to reset previously set compiler options. + +if exists("g:current_compiler") | unlet g:current_compiler | endif +if exists("b:current_compiler") | unlet b:current_compiler | endif + +CompilerSet makeprg& +CompilerSet errorformat& diff --git a/runtime/compiler/pandoc.vim b/runtime/compiler/pandoc.vim index 6c151930c5..6c15e104c3 100644 --- a/runtime/compiler/pandoc.vim +++ b/runtime/compiler/pandoc.vim @@ -1,9 +1,12 @@ " Vim compiler file " Compiler: Pandoc " Maintainer: Konfekt +" Last Change: 2024 Sep 8 " " Expects output file extension, say `:make html` or `:make pdf`. " Passes additional arguments to pandoc, say `:make html --self-contained`. +" Adjust command-line flags by buffer-local/global variable +" b/g:pandoc_compiler_args which defaults to empty. if exists("current_compiler") finish @@ -25,31 +28,36 @@ let s:supported_filetypes = silent! function s:PandocFiletype(filetype) abort let ft = a:filetype - if ft ==# 'pandoc' - return 'markdown' - elseif ft ==# 'tex' - return 'latex' - elseif ft ==# 'xml' - " Pandoc does not support XML as a generic input format, but it does support - " EndNote XML and Jats XML out of which the latter seems more universal. - return 'jats' - elseif ft ==# 'text' || empty(ft) - return 'markdown' - elseif index(s:supported_filetypes, &ft) >= 0 - return ft + + if ft ==# 'pandoc' | return 'markdown' + elseif ft ==# 'tex' | return 'latex' + " Pandoc does not support XML as a generic input format, but it does support + " EndNote XML and Jats XML out of which the latter seems more universal. + elseif ft ==# 'xml' | return 'jats' + elseif ft ==# 'text' || empty(ft) | return 'markdown' + elseif index(s:supported_filetypes, &ft) >= 0 | return ft else - echomsg 'Unsupported filetype: ' . ft . ', falling back to Markdown as input format!' + echomsg 'Unsupported filetype: '..ft..', falling back to Markdown as input format!' return 'markdown' endif endfunction -execute 'CompilerSet makeprg=pandoc\ --standalone' . - \ '\ --metadata\ title=%:t:r:S' . - \ '\ --metadata\ lang=' . matchstr(&spelllang, '^\a\a') . - \ '\ --from=' . s:PandocFiletype(&filetype) . - \ '\ ' . escape(get(b:, 'pandoc_compiler_args', get(g:, 'pandoc_compiler_args', '')), ' ') . - \ '\ --output\ %:r:S.$*\ %:S' - -CompilerSet errorformat="%f",\ line\ %l:\ %m + +silent! function s:PandocLang() + let lang = get(b:, 'pandoc_compiler_lang', + \ &spell ? matchstr(&spelllang, '^\a\a') : '') + if lang ==# 'en' | let lang = '' | endif + return empty(lang) ? '' : '--metadata lang='..lang +endfunction + +execute 'CompilerSet makeprg=pandoc'..escape( + \ ' --standalone'.. + \ (s:PandocFiletype(&filetype) ==# 'markdown' && (getline(1) =~# '^%\s\+\S\+' || (search('^title:\s+\S+', 'cnw') > 0)) ? + \ '' : ' --metadata title=%:t:r:S').. + \ ' '..s:PandocLang().. + \ ' --from='..s:PandocFiletype(&filetype).. + \ ' '..get(b:, 'pandoc_compiler_args', get(g:, 'pandoc_compiler_args', '')).. + \ ' --output %:r:S.$* -- %:S', ' ') +CompilerSet errorformat=\"%f\",\ line\ %l:\ %m let &cpo = s:keepcpo unlet s:keepcpo diff --git a/runtime/compiler/typst.vim b/runtime/compiler/typst.vim new file mode 100644 index 0000000000..33e55818e9 --- /dev/null +++ b/runtime/compiler/typst.vim @@ -0,0 +1,15 @@ +" Vim compiler file +" Language: Typst +" Maintainer: Gregory Anders +" Last Change: 2024-07-14 +" Based on: https://github.com/kaarmu/typst.vim + +if exists('current_compiler') + finish +endif +let current_compiler = get(g:, 'typst_cmd', 'typst') + +" With `--diagnostic-format` we can use the default errorformat +let s:makeprg = [current_compiler, 'compile', '--diagnostic-format', 'short', '%:S'] + +execute 'CompilerSet makeprg=' . join(s:makeprg, '\ ') diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 2aa147770d..dee0324a5b 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -42,9 +42,9 @@ The RPC API is like a more powerful version of Vim's "clientserver" feature. CONNECTING *rpc-connecting* See |channel-intro| for various ways to open a channel. Channel-opening -functions take an `rpc` key in the options dictionary. RPC channels can also -be opened by other processes connecting to TCP/IP sockets or named pipes -listened to by Nvim. +functions take an `rpc` key in the options dict. RPC channels can also be +opened by other processes connecting to TCP/IP sockets or named pipes listened +to by Nvim. Nvim creates a default RPC socket at |startup|, given by |v:servername|. To start with a TCP/IP socket instead, use |--listen| with a TCP-style address: > @@ -108,9 +108,9 @@ Basic types ~ Integer (signed 64-bit integer) int64_t Float (IEEE 754 double precision) double String {char* data, size_t size} struct - Array - Dictionary (msgpack: map) - Object + Array kvec + Dict (msgpack: map) kvec + Object any of the above < Note: - Empty Array is accepted as a valid Dictionary parameter. @@ -708,12 +708,12 @@ nvim_eval_statusline({str}, {opts}) *nvim_eval_statusline()* line number instead of statusline. Return: ~ - Dictionary containing statusline information, with these keys: + Dict containing statusline information, with these keys: • str: (string) Characters that will be displayed on the statusline. • width: (number) Display width of the statusline. • highlights: Array containing highlight information of the statusline. Only included when the "highlights" key in {opts} is - true. Each element of the array is a |Dictionary| with these keys: + true. Each element of the array is a |Dict| with these keys: • start: (number) Byte index (0-based) of first character that uses the highlight. • group: (string) Name of highlight group. @@ -763,7 +763,7 @@ nvim_feedkeys({keys}, {mode}, {escape_ks}) *nvim_feedkeys()* nvim_get_api_info() *nvim_get_api_info()* Returns a 2-tuple (Array), where item 0 is the current channel id and item - 1 is the |api-metadata| map (Dictionary). + 1 is the |api-metadata| map (Dict). Attributes: ~ |api-fast| @@ -779,7 +779,7 @@ nvim_get_chan_info({chan}) *nvim_get_chan_info()* • {chan} channel_id, or 0 for current channel Return: ~ - Dictionary describing a channel, with these keys: + Channel info dict with these keys: • "id" Channel id. • "argv" (optional) Job arguments list. • "stream" Stream underlying the channel. @@ -792,11 +792,11 @@ nvim_get_chan_info({chan}) *nvim_get_chan_info()* • "terminal" |terminal| instance interprets ASCII sequences. • "rpc" |RPC| communication on the channel is active. • "pty" (optional) Name of pseudoterminal. On a POSIX system this is a - device path like "/dev/pts/1". If the name is unknown, the key will - still be present if a pty is used (e.g. for conpty on Windows). - • "buffer" (optional) Buffer with connected |terminal| instance. + device path like "/dev/pts/1". If unknown, the key will still be + present if a pty is used (e.g. for conpty on Windows). + • "buffer" (optional) Buffer connected to |terminal| instance. • "client" (optional) Info about the peer (client on the other end of - the RPC channel), if provided by it via |nvim_set_client_info()|. + the RPC channel), which it provided via |nvim_set_client_info()|. nvim_get_color_by_name({name}) *nvim_get_color_by_name()* Returns the 24-bit RGB value of a |nvim_get_color_map()| color name or @@ -939,7 +939,7 @@ nvim_get_mode() *nvim_get_mode()* |api-fast| Return: ~ - Dictionary { "mode": String, "blocking": Boolean } + Dict { "mode": String, "blocking": Boolean } nvim_get_proc({pid}) *nvim_get_proc()* Gets info describing process `pid`. @@ -954,11 +954,11 @@ nvim_get_proc_children({pid}) *nvim_get_proc_children()* Array of child process ids, empty if process not found. nvim_get_runtime_file({name}, {all}) *nvim_get_runtime_file()* - Find files in runtime directories + Finds files in runtime directories, in 'runtimepath' order. "name" can contain wildcards. For example - nvim_get_runtime_file("colors/*.vim", true) will return all color scheme - files. Always use forward slashes (/) in the search pattern for + `nvim_get_runtime_file("colors/*.{vim,lua}", true)` will return all color + scheme files. Always use forward slashes (/) in the search pattern for subdirectories regardless of platform. It is not an error to not find any files. An empty array is returned then. @@ -996,6 +996,9 @@ nvim_input({keys}) *nvim_input()* input buffer and the call is non-blocking (input is processed asynchronously by the eventloop). + To input blocks of text, |nvim_paste()| is much faster and should be + preferred. + On execution error: does not fail, but updates v:errmsg. Note: ~ @@ -1148,21 +1151,35 @@ nvim_out_write({str}) *nvim_out_write()* • {str} Message nvim_paste({data}, {crlf}, {phase}) *nvim_paste()* - Pastes at cursor, in any mode. + Pastes at cursor (in any mode), and sets "redo" so dot (|.|) will repeat + the input. UIs call this to implement "paste", but it's also intended for + use by scripts to input large, dot-repeatable blocks of text (as opposed + to |nvim_input()| which is subject to mappings/events and is thus much + slower). - Invokes the `vim.paste` handler, which handles each mode appropriately. - Sets redo/undo. Faster than |nvim_input()|. Lines break at LF ("\n"). + Invokes the |vim.paste()| handler, which handles each mode appropriately. Errors ('nomodifiable', `vim.paste()` failure, …) are reflected in `err` but do not affect the return value (which is strictly decided by - `vim.paste()`). On error, subsequent calls are ignored ("drained") until - the next paste is initiated (phase 1 or -1). + `vim.paste()`). On error or cancel, subsequent calls are ignored + ("drained") until the next paste is initiated (phase 1 or -1). + + Useful in mappings and scripts to insert multiline text. Example: >lua + vim.keymap.set('n', 'x', function() + vim.api.nvim_paste([[ + line1 + line2 + line3 + ]], false, -1) + end, { buffer = true }) +< Attributes: ~ not allowed when |textlock| is active Parameters: ~ - • {data} Multiline input. May be binary (containing NUL bytes). + • {data} Multiline input. Lines break at LF ("\n"). May be binary + (containing NUL bytes). • {crlf} Also break lines at CR and CRLF. • {phase} -1: paste in a single call (i.e. without streaming). To "stream" a paste, call `nvim_paste` sequentially with these @@ -1173,10 +1190,11 @@ nvim_paste({data}, {crlf}, {phase}) *nvim_paste()* Return: ~ • true: Client may continue pasting. - • false: Client must cancel the paste. + • false: Client should cancel the paste. nvim_put({lines}, {type}, {after}, {follow}) *nvim_put()* - Puts text at cursor, in any mode. + Puts text at cursor, in any mode. For dot-repeatable input, use + |nvim_paste()|. Compare |:put| and |p| which are always linewise. @@ -1249,8 +1267,7 @@ nvim_set_client_info({name}, {version}, {type}, {methods}, {attributes}) Parameters: ~ • {name} Short name for the connected client - • {version} Dictionary describing the version, with these (optional) - keys: + • {version} Dict describing the version, with these (optional) keys: • "major" major version (defaults to 0 if not set, for no release yet) • "minor" minor version @@ -1285,6 +1302,7 @@ nvim_set_client_info({name}, {version}, {type}, {methods}, {attributes}) inclusive. • {attributes} Arbitrary string:string map of informal client properties. Suggested keys: + • "pid": Process id. • "website": Client homepage URL (e.g. GitHub repository) • "license": License description ("Apache 2", "GPLv3", @@ -1474,7 +1492,7 @@ nvim__complete_set({index}, {opts}) *nvim__complete_set()* • info: (string) info text. Return: ~ - Dictionary containing these keys: + Dict containing these keys: • winid: (number) floating window id • bufnr: (number) buffer id in floating window @@ -1516,14 +1534,14 @@ nvim__id_array({arr}) *nvim__id_array()* Return: ~ its argument. -nvim__id_dictionary({dct}) *nvim__id_dictionary()* - Returns dictionary given as argument. +nvim__id_dict({dct}) *nvim__id_dict()* + Returns dict given as argument. This API function is used for testing. One should not rely on its presence in plugins. Parameters: ~ - • {dct} Dictionary to return. + • {dct} Dict to return. Return: ~ its argument. @@ -1594,7 +1612,7 @@ nvim_call_dict_function({dict}, {fn}, {args}) On execution error: fails with Vimscript error, updates v:errmsg. Parameters: ~ - • {dict} Dictionary, or String evaluating to a Vimscript |self| dict + • {dict} Dict, or String evaluating to a Vimscript |self| dict • {fn} Name of the function defined on the Vimscript dict • {args} Function arguments packed in an Array @@ -1628,7 +1646,7 @@ nvim_command({command}) *nvim_command()* • {command} Ex command string nvim_eval({expr}) *nvim_eval()* - Evaluates a Vimscript |expression|. Dictionaries and Lists are recursively + Evaluates a Vimscript |expression|. Dicts and Lists are recursively expanded. On execution error: fails with Vimscript error, updates v:errmsg. @@ -1655,7 +1673,7 @@ nvim_exec2({src}, {opts}) *nvim_exec2()* return all (non-error, non-shell |:!|) output. Return: ~ - Dictionary containing information about execution, with these keys: + Dict containing information about execution, with these keys: • output: (string|nil) Output if `opts.output` is true. See also: ~ @@ -1692,9 +1710,9 @@ nvim_parse_expression({expr}, {flags}, {highlight}) region [start_col, end_col)). Return: ~ - • AST: top-level dictionary with these keys: - • "error": Dictionary with error, present only if parser saw some - error. Contains the following keys: + • AST: top-level dict with these keys: + • "error": Dict with error, present only if parser saw some error. + Contains the following keys: • "message": String, error message in printf format, translated. Must contain exactly one "%.*s". • "arg": String, error message argument. @@ -1702,7 +1720,7 @@ nvim_parse_expression({expr}, {flags}, {highlight}) that should be equal to the length of expr string. ("Successfully parsed" here means "participated in AST creation", not "till the first error".) - • "ast": AST, either nil or a dictionary with these keys: + • "ast": AST, either nil or a dict with these keys: • "type": node type, one of the value names from ExprASTNodeType stringified without "kExprNode" prefix. • "start": a pair `[line, column]` describing where node is @@ -1778,8 +1796,8 @@ nvim_buf_get_commands({buffer}, {opts}) *nvim_buf_get_commands()* nvim_cmd({cmd}, {opts}) *nvim_cmd()* Executes an Ex command. - Unlike |nvim_command()| this command takes a structured Dictionary instead - of a String. This allows for easier construction and manipulation of an Ex + Unlike |nvim_command()| this command takes a structured Dict instead of a + String. This allows for easier construction and manipulation of an Ex command. This also allows for things such as having spaces inside a command argument, expanding filenames in a command that otherwise doesn't expand filenames, etc. Command arguments may also be Number, Boolean or @@ -1793,8 +1811,8 @@ nvim_cmd({cmd}, {opts}) *nvim_cmd()* On execution error: fails with Vimscript error, updates v:errmsg. Parameters: ~ - • {cmd} Command to execute. Must be a Dictionary that can contain the - same values as the return value of |nvim_parse_cmd()| except + • {cmd} Command to execute. Must be a Dict that can contain the same + values as the return value of |nvim_parse_cmd()| except "addr", "nargs" and "nextcmd" which are ignored if provided. All values except for "cmd" are optional. • {opts} Optional parameters. @@ -1896,7 +1914,7 @@ nvim_parse_cmd({str}, {opts}) *nvim_parse_cmd()* • {opts} Optional parameters. Reserved for future use. Return: ~ - Dictionary containing command information, with these keys: + Dict containing command information, with these keys: • cmd: (string) Command name. • range: (array) (optional) Command range (<line1> <line2>). Omitted if command doesn't accept a range. Otherwise, has no elements if no @@ -1913,15 +1931,15 @@ nvim_parse_cmd({str}, {opts}) *nvim_parse_cmd()* • nargs: (string) Value of |:command-nargs|. • nextcmd: (string) Next command if there are multiple commands separated by a |:bar|. Empty if there isn't a next command. - • magic: (dictionary) Which characters have special meaning in the - command arguments. + • magic: (dict) Which characters have special meaning in the command + arguments. • file: (boolean) The command expands filenames. Which means characters such as "%", "#" and wildcards are expanded. • bar: (boolean) The "|" character is treated as a command separator and the double quote character (") is treated as the start of a comment. - • mods: (dictionary) |:command-modifiers|. - • filter: (dictionary) |:filter|. + • mods: (dict) |:command-modifiers|. + • filter: (dict) |:filter|. • pattern: (string) Filter pattern. Empty string if there is no filter. • force: (boolean) Whether filter is inverted or not. @@ -1958,11 +1976,11 @@ Options Functions *api-options* nvim_get_all_options_info() *nvim_get_all_options_info()* Gets the option information for all options. - The dictionary has the full option names as keys and option metadata - dictionaries as detailed at |nvim_get_option_info2()|. + The dict has the full option names as keys and option metadata dicts as + detailed at |nvim_get_option_info2()|. Return: ~ - dictionary of all options + dict of all options See also: ~ • |nvim_get_commands()| @@ -1970,7 +1988,7 @@ nvim_get_all_options_info() *nvim_get_all_options_info()* nvim_get_option_info2({name}, {opts}) *nvim_get_option_info2()* Gets the option information for one option from arbitrary buffer or window - Resulting dictionary has keys: + Resulting dict has keys: • name: Name of the option (like 'filetype') • shortname: Shortened name of the option (like 'ft') • type: type of option ("string", "number" or "boolean") @@ -2138,14 +2156,14 @@ nvim_buf_attach({buffer}, {send_buffer}, {opts}) *nvim_buf_attach()* • |api-buffer-updates-lua| nvim_buf_call({buffer}, {fun}) *nvim_buf_call()* - call a function with buffer as temporary current buffer + Call a function with buffer as temporary current buffer. This temporarily switches current buffer to "buffer". If the current - window already shows "buffer", the window is not switched If a window - inside the current tabpage (including a float) already shows the buffer - One of these windows will be set as current window temporarily. Otherwise - a temporary scratch window (called the "autocmd window" for historical - reasons) will be used. + window already shows "buffer", the window is not switched. If a window + inside the current tabpage (including a float) already shows the buffer, + then one of these windows will be set as current window temporarily. + Otherwise a temporary scratch window (called the "autocmd window" for + historical reasons) will be used. This is useful e.g. to call Vimscript functions that only work with the current buffer/window currently, like |termopen()|. @@ -2460,10 +2478,11 @@ nvim_buf_set_text({buffer}, {start_row}, {start_col}, {end_row}, {end_col}, `start_row = end_row = row` and `start_col = end_col = col`. To delete the text in a range, use `replacement = {}`. - Prefer |nvim_buf_set_lines()| if you are only adding or deleting entire - lines. - - Prefer |nvim_put()| if you want to insert text at the cursor position. + Note: ~ + • Prefer |nvim_buf_set_lines()| (for performance) to add or delete + entire lines. + • Prefer |nvim_paste()| or |nvim_put()| to insert (instead of replace) + text at cursor. Attributes: ~ not allowed when |textlock| is active @@ -2476,10 +2495,6 @@ nvim_buf_set_text({buffer}, {start_row}, {start_col}, {end_row}, {end_col}, • {end_col} Ending column (byte offset) on last line, exclusive • {replacement} Array of lines to use as replacement - See also: ~ - • |nvim_buf_set_lines()| - • |nvim_put()| - nvim_buf_set_var({buffer}, {name}, {value}) *nvim_buf_set_var()* Sets a buffer-scoped (b:) variable @@ -2758,8 +2773,6 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {opts}) • url: A URL to associate with this extmark. In the TUI, the OSC 8 control sequence is used to generate a clickable hyperlink to this URL. - • scoped: boolean (EXPERIMENTAL) enables "scoping" for the - extmark. See |nvim__win_add_ns()| Return: ~ Id of the created/updated extmark @@ -2802,7 +2815,7 @@ nvim_set_decoration_provider({ns_id}, {opts}) Note: this function should not be called often. Rather, the callbacks themselves can be used to throttle unneeded callbacks. the `on_start` callback can return `false` to disable the provider until the next redraw. - Similarly, return `false` in `on_win` will skip the `on_lines` calls for + Similarly, return `false` in `on_win` will skip the `on_line` calls for that window (but any extmarks set in `on_win` will still be used). A plugin managing multiple sources of decoration should ideally only set one provider, and merge the sources internally. You can use multiple `ns_id` @@ -2811,10 +2824,10 @@ nvim_set_decoration_provider({ns_id}, {opts}) Note: doing anything other than setting extmarks is considered experimental. Doing things like changing options are not explicitly forbidden, but is likely to have unexpected consequences (such as 100% CPU - consumption). doing `vim.rpcnotify` should be OK, but `vim.rpcrequest` is + consumption). Doing `vim.rpcnotify` should be OK, but `vim.rpcrequest` is quite dubious for the moment. - Note: It is not allowed to remove or update extmarks in 'on_line' + Note: It is not allowed to remove or update extmarks in `on_line` callbacks. Attributes: ~ @@ -2831,7 +2844,7 @@ nvim_set_decoration_provider({ns_id}, {opts}) ["buf", bufnr, tick] < • on_win: called when starting to redraw a specific window. > - ["win", winid, bufnr, topline, botline] + ["win", winid, bufnr, toprow, botrow] < • on_line: called for each buffer line being redrawn. (The interaction with fold lines is subject to change) > @@ -2841,41 +2854,26 @@ nvim_set_decoration_provider({ns_id}, {opts}) ["end", tick] < -nvim__win_add_ns({window}, {ns_id}) *nvim__win_add_ns()* +nvim__ns_get({ns_id}) *nvim__ns_get()* EXPERIMENTAL: this API will change in the future. - Scopes a namespace to the a window, so extmarks in the namespace will be - active only in the given window. + Get the properties for namespace Parameters: ~ - • {window} Window handle, or 0 for current window - • {ns_id} Namespace + • {ns_id} Namespace Return: ~ - true if the namespace was added, else false + Map defining the namespace properties, see |nvim__ns_set()| -nvim__win_del_ns({window}, {ns_id}) *nvim__win_del_ns()* +nvim__ns_set({ns_id}, {opts}) *nvim__ns_set()* EXPERIMENTAL: this API will change in the future. - Unscopes a namespace (un-binds it from the given scope). + Set some properties for namespace Parameters: ~ - • {window} Window handle, or 0 for current window - • {ns_id} the namespace to remove - - Return: ~ - true if the namespace was removed, else false - -nvim__win_get_ns({window}) *nvim__win_get_ns()* - EXPERIMENTAL: this API will change in the future. - - Gets the namespace scopes for a given window. - - Parameters: ~ - • {window} Window handle, or 0 for current window - - Return: ~ - a list of namespaces ids + • {ns_id} Namespace + • {opts} Optional parameters to set: + • wins: a list of windows to be scoped in ============================================================================== @@ -3097,7 +3095,7 @@ nvim_win_text_height({window}, {opts}) *nvim_win_text_height()* omitted include the whole line. Return: ~ - Dictionary containing text height information, with these keys: + Dict containing text height information, with these keys: • all: The total number of screen lines occupied by the range. • fill: The number of diff filler or virtual lines among them. @@ -3259,13 +3257,15 @@ nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()* < • title: Title (optional) in window border, string or list. List should consist of `[text, highlight]` tuples. If - string, the default highlight group is `FloatTitle`. + string, or a tuple lacks a highlight, the default + highlight group is `FloatTitle`. • title_pos: Title position. Must be set with `title` option. Value can be one of "left", "center", or "right". Default is `"left"`. • footer: Footer (optional) in window border, string or list. List should consist of `[text, highlight]` tuples. - If string, the default highlight group is `FloatFooter`. + If string, or a tuple lacks a highlight, the default + highlight group is `FloatFooter`. • footer_pos: Footer position. Must be set with `footer` option. Value can be one of "left", "center", or "right". Default is `"left"`. @@ -3419,7 +3419,7 @@ nvim_create_augroup({name}, {opts}) *nvim_create_augroup()* Parameters: ~ • {name} String: The name of the group - • {opts} Dictionary Parameters + • {opts} Dict Parameters • clear (bool) optional: defaults to true. Clear existing commands if the group already exists |autocmd-groups|. @@ -3538,7 +3538,7 @@ nvim_exec_autocmds({event}, {opts}) *nvim_exec_autocmds()* Parameters: ~ • {event} (String|Array) The event or events to execute - • {opts} Dictionary of autocommand options: + • {opts} Dict of autocommand options: • group (string|integer) optional: the autocommand group name or id to match against. |autocmd-groups|. • pattern (string|array) optional: defaults to "*" @@ -3574,7 +3574,7 @@ nvim_get_autocmds({opts}) *nvim_get_autocmds()* autocommands that match any combination of them. Parameters: ~ - • {opts} Dictionary with at least one of the following: + • {opts} Dict with at least one of the following: • group (string|integer): the autocommand group name or id to match against. • event (string|array): event or events to match against diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index ca816851dd..8e5e2628de 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -522,6 +522,11 @@ CursorMoved After the cursor was moved in Normal or Visual Careful: This is triggered very often, don't do anything that the user does not expect or that is slow. + *CursorMovedC* +CursorMovedC After the cursor was moved in the command + line. Be careful not to mess up the command + line, it may cause Vim to lock up. + <afile> expands to the |cmdline-char|. *CursorMovedI* CursorMovedI After the cursor was moved in Insert mode. Not triggered when the popup menu is visible. diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index ff7d5f9ce8..4c726f86d2 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -25,6 +25,12 @@ abs({expr}) *abs()* echo abs(-4) < 4 + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`number`) + acos({expr}) *acos()* Return the arc cosine of {expr} measured in radians, as a |Float| in the range of [0, pi]. @@ -38,6 +44,12 @@ acos({expr}) *acos()* echo acos(-0.5) < 2.094395 + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`number`) + add({object}, {expr}) *add()* Append the item {expr} to |List| or |Blob| {object}. Returns the resulting |List| or |Blob|. Examples: >vim @@ -49,6 +61,14 @@ add({object}, {expr}) *add()* Use |insert()| to add an item at another position. Returns 1 if {object} is not a |List| or a |Blob|. + Parameters: ~ + • {object} (`any`) + • {expr} (`any`) + + Return: ~ + (`any`) Resulting |List| or |Blob|, or 1 if {object} is not + a |List| or a |Blob|. + and({expr}, {expr}) *and()* Bitwise AND on the two arguments. The arguments are converted to a number. A List, Dict or Float argument causes an error. @@ -57,6 +77,13 @@ and({expr}, {expr}) *and()* let flag = and(bits, 0x80) < + Parameters: ~ + • {expr} (`number`) + • {expr1} (`number`) + + Return: ~ + (`integer`) + api_info() *api_info()* Returns Dictionary of |api-metadata|. @@ -64,6 +91,9 @@ api_info() *api_info()* lua vim.print(vim.fn.api_info()) < + Return: ~ + (`table`) + append({lnum}, {text}) *append()* When {text} is a |List|: Append each item of the |List| as a text line below line {lnum} in the current buffer. @@ -79,6 +109,13 @@ append({lnum}, {text}) *append()* let failed = append(0, ["Chapter 1", "the beginning"]) < + Parameters: ~ + • {lnum} (`integer`) + • {text} (`string|string[]`) + + Return: ~ + (`0|1`) + appendbufline({buf}, {lnum}, {text}) *appendbufline()* Like |append()| but append the text in buffer {expr}. @@ -100,6 +137,14 @@ appendbufline({buf}, {lnum}, {text}) *appendbufline()* < However, when {text} is an empty list then no error is given for an invalid {lnum}, since {lnum} isn't actually used. + Parameters: ~ + • {buf} (`integer|string`) + • {lnum} (`integer`) + • {text} (`string`) + + Return: ~ + (`0|1`) + argc([{winid}]) *argc()* The result is the number of files in the argument list. See |arglist|. @@ -110,10 +155,19 @@ argc([{winid}]) *argc()* list is used: either the window number or the window ID. Returns -1 if the {winid} argument is invalid. + Parameters: ~ + • {winid} (`integer?`) + + Return: ~ + (`integer`) + argidx() *argidx()* The result is the current index in the argument list. 0 is the first file. argc() - 1 is the last one. See |arglist|. + Return: ~ + (`integer`) + arglistid([{winnr} [, {tabnr}]]) *arglistid()* Return the argument list ID. This is a number which identifies the argument list being used. Zero is used for the @@ -126,6 +180,13 @@ arglistid([{winnr} [, {tabnr}]]) *arglistid()* page. {winnr} can be the window number or the |window-ID|. + Parameters: ~ + • {winnr} (`integer?`) + • {tabnr} (`integer?`) + + Return: ~ + (`integer`) + argv([{nr} [, {winid}]]) *argv()* The result is the {nr}th file in the argument list. See |arglist|. "argv(0)" is the first one. Example: >vim @@ -145,6 +206,13 @@ argv([{nr} [, {winid}]]) *argv()* the argument list. Returns an empty List if the {winid} argument is invalid. + Parameters: ~ + • {nr} (`integer?`) + • {winid} (`integer?`) + + Return: ~ + (`string|string[]`) + asin({expr}) *asin()* Return the arc sine of {expr} measured in radians, as a |Float| in the range of [-pi/2, pi/2]. @@ -158,27 +226,48 @@ asin({expr}) *asin()* echo asin(-0.5) < -0.523599 + Parameters: ~ + • {expr} (`any`) + + Return: ~ + (`number`) + assert_beeps({cmd}) *assert_beeps()* Run {cmd} and add an error message to |v:errors| if it does NOT produce a beep or visual bell. Also see |assert_fails()|, |assert_nobeep()| and |assert-return|. + Parameters: ~ + • {cmd} (`string`) + + Return: ~ + (`0|1`) + assert_equal({expected}, {actual} [, {msg}]) *assert_equal()* When {expected} and {actual} are not equal an error message is added to |v:errors| and 1 is returned. Otherwise zero is returned. |assert-return| The error is in the form "Expected {expected} but got - {actual}". When {msg} is present it is prefixed to that. + {actual}". When {msg} is present it is prefixed to that, + along with the location of the assert when run from a script. There is no automatic conversion, the String "4" is different from the Number 4. And the number 4 is different from the Float 4.0. The value of 'ignorecase' is not used here, case always matters. Example: >vim - assert_equal('foo', 'bar') -< Will result in a string to be added to |v:errors|: - test.vim line 12: Expected 'foo' but got 'bar' ~ + call assert_equal('foo', 'bar', 'baz') +< Will add the following to |v:errors|: + test.vim line 12: baz: Expected 'foo' but got 'bar' ~ + + Parameters: ~ + • {expected} (`any`) + • {actual} (`any`) + • {msg} (`any?`) + + Return: ~ + (`0|1`) assert_equalfile({fname-one}, {fname-two}) *assert_equalfile()* When the files {fname-one} and {fname-two} do not contain @@ -187,6 +276,13 @@ assert_equalfile({fname-one}, {fname-two}) *assert_equalfile()* When {fname-one} or {fname-two} does not exist the error will mention that. + Parameters: ~ + • {fname-one} (`string`) + • {fname-two} (`string`) + + Return: ~ + (`0|1`) + assert_exception({error} [, {msg}]) *assert_exception()* When v:exception does not contain the string {error} an error message is added to |v:errors|. Also see |assert-return|. @@ -201,6 +297,13 @@ assert_exception({error} [, {msg}]) *assert_exception()* endtry < + Parameters: ~ + • {error} (`any`) + • {msg} (`any?`) + + Return: ~ + (`0|1`) + *assert_fails()* assert_fails({cmd} [, {error} [, {msg} [, {lnum} [, {context}]]]]) Run {cmd} and add an error message to |v:errors| if it does @@ -210,25 +313,25 @@ assert_fails({cmd} [, {error} [, {msg} [, {lnum} [, {context}]]]]) When {error} is a string it must be found literally in the first reported error. Most often this will be the error code, including the colon, e.g. "E123:". >vim - assert_fails('bad cmd', 'E987:') + call assert_fails('bad cmd', 'E987:') < When {error} is a |List| with one or two strings, these are used as patterns. The first pattern is matched against the first reported error: >vim - assert_fails('cmd', ['E987:.*expected bool']) + call assert_fails('cmd', ['E987:.*expected bool']) < The second pattern, if present, is matched against the last reported error. To only match the last error use an empty string for the first error: >vim - assert_fails('cmd', ['', 'E987:']) + call assert_fails('cmd', ['', 'E987:']) < If {msg} is empty then it is not used. Do this to get the default message when passing the {lnum} argument. - + *E1115* When {lnum} is present and not negative, and the {error} argument is present and matches, then this is compared with the line number at which the error was reported. That can be the line number in a function or in a script. - + *E1116* When {context} is present it is used as a pattern and matched against the context (script name or function name) where {lnum} is located in. @@ -236,16 +339,34 @@ assert_fails({cmd} [, {error} [, {msg} [, {lnum} [, {context}]]]]) Note that beeping is not considered an error, and some failing commands only beep. Use |assert_beeps()| for those. + Parameters: ~ + • {cmd} (`string`) + • {error} (`any?`) + • {msg} (`any?`) + • {lnum} (`integer?`) + • {context} (`any?`) + + Return: ~ + (`0|1`) + assert_false({actual} [, {msg}]) *assert_false()* When {actual} is not false an error message is added to |v:errors|, like with |assert_equal()|. The error is in the form "Expected False but got {actual}". - When {msg} is present it is prepended to that. + When {msg} is present it is prefixed to that, along with the + location of the assert when run from a script. Also see |assert-return|. A value is false when it is zero. When {actual} is not a number the assert fails. + Parameters: ~ + • {actual} (`any`) + • {msg} (`any?`) + + Return: ~ + (`0|1`) + assert_inrange({lower}, {upper}, {actual} [, {msg}]) *assert_inrange()* This asserts number and |Float| values. When {actual} is lower than {lower} or higher than {upper} an error message is added @@ -254,11 +375,21 @@ assert_inrange({lower}, {upper}, {actual} [, {msg}]) *assert_inrange()* but got {actual}". When {msg} is present it is prefixed to that. + Parameters: ~ + • {lower} (`number`) + • {upper} (`number`) + • {actual} (`number`) + • {msg} (`string?`) + + Return: ~ + (`0|1`) + assert_match({pattern}, {actual} [, {msg}]) *assert_match()* When {pattern} does not match {actual} an error message is added to |v:errors|. Also see |assert-return|. The error is in the form "Pattern {pattern} does not match - {actual}". When {msg} is present it is prefixed to that. + {actual}". When {msg} is present it is prefixed to that, + along with the location of the assert when run from a script. {pattern} is used as with |expr-=~|: The matching is always done like 'magic' was set and 'cpoptions' is empty, no matter what @@ -269,36 +400,80 @@ assert_match({pattern}, {actual} [, {msg}]) *assert_match()* Use both to match the whole text. Example: >vim - assert_match('^f.*o$', 'foobar') + call assert_match('^f.*o$', 'foobar') < Will result in a string to be added to |v:errors|: test.vim line 12: Pattern '^f.*o$' does not match 'foobar' ~ + Parameters: ~ + • {pattern} (`string`) + • {actual} (`string`) + • {msg} (`string?`) + + Return: ~ + (`0|1`) + assert_nobeep({cmd}) *assert_nobeep()* Run {cmd} and add an error message to |v:errors| if it produces a beep or visual bell. Also see |assert_beeps()|. + Parameters: ~ + • {cmd} (`string`) + + Return: ~ + (`0|1`) + assert_notequal({expected}, {actual} [, {msg}]) *assert_notequal()* The opposite of `assert_equal()`: add an error message to |v:errors| when {expected} and {actual} are equal. Also see |assert-return|. + Parameters: ~ + • {expected} (`any`) + • {actual} (`any`) + • {msg} (`any?`) + + Return: ~ + (`0|1`) + assert_notmatch({pattern}, {actual} [, {msg}]) *assert_notmatch()* The opposite of `assert_match()`: add an error message to |v:errors| when {pattern} matches {actual}. Also see |assert-return|. + Parameters: ~ + • {pattern} (`string`) + • {actual} (`string`) + • {msg} (`string?`) + + Return: ~ + (`0|1`) + assert_report({msg}) *assert_report()* Report a test failure directly, using String {msg}. Always returns one. + Parameters: ~ + • {msg} (`string`) + + Return: ~ + (`0|1`) + assert_true({actual} [, {msg}]) *assert_true()* When {actual} is not true an error message is added to |v:errors|, like with |assert_equal()|. Also see |assert-return|. A value is |TRUE| when it is a non-zero number or |v:true|. When {actual} is not a number or |v:true| the assert fails. - When {msg} is given it precedes the default message. + When {msg} is given it is prefixed to the default message, + along with the location of the assert when run from a script. + + Parameters: ~ + • {actual} (`any`) + • {msg} (`string?`) + + Return: ~ + (`0|1`) atan({expr}) *atan()* Return the principal value of the arc tangent of {expr}, in @@ -311,6 +486,12 @@ atan({expr}) *atan()* echo atan(-4.01) < -1.326405 + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`number`) + atan2({expr1}, {expr2}) *atan2()* Return the arc tangent of {expr1} / {expr2}, measured in radians, as a |Float| in the range [-pi, pi]. @@ -323,6 +504,13 @@ atan2({expr1}, {expr2}) *atan2()* echo atan2(1, -1) < 2.356194 + Parameters: ~ + • {expr1} (`number`) + • {expr2} (`number`) + + Return: ~ + (`number`) + blob2list({blob}) *blob2list()* Return a List containing the number value of each byte in Blob {blob}. Examples: >vim @@ -331,6 +519,12 @@ blob2list({blob}) *blob2list()* < Returns an empty List on error. |list2blob()| does the opposite. + Parameters: ~ + • {blob} (`any`) + + Return: ~ + (`any[]`) + browse({save}, {title}, {initdir}, {default}) *browse()* Put up a file requester. This only works when "has("browse")" returns |TRUE| (only in some GUI versions). @@ -342,6 +536,15 @@ browse({save}, {title}, {initdir}, {default}) *browse()* An empty string is returned when the "Cancel" button is hit, something went wrong, or browsing is not possible. + Parameters: ~ + • {save} (`any`) + • {title} (`string`) + • {initdir} (`string`) + • {default} (`string`) + + Return: ~ + (`0|1`) + browsedir({title}, {initdir}) *browsedir()* Put up a directory requester. This only works when "has("browse")" returns |TRUE| (only in some GUI versions). @@ -354,6 +557,13 @@ browsedir({title}, {initdir}) *browsedir()* When the "Cancel" button is hit, something went wrong, or browsing is not possible, an empty string is returned. + Parameters: ~ + • {title} (`string`) + • {initdir} (`string`) + + Return: ~ + (`0|1`) + bufadd({name}) *bufadd()* Add a buffer to the buffer list with name {name} (must be a String). @@ -368,6 +578,12 @@ bufadd({name}) *bufadd()* call setbufline(bufnr, 1, ['some', 'text']) < Returns 0 on error. + Parameters: ~ + • {name} (`string`) + + Return: ~ + (`integer`) + bufexists({buf}) *bufexists()* The result is a Number, which is |TRUE| if a buffer called {buf} exists. @@ -390,11 +606,23 @@ bufexists({buf}) *bufexists()* Use "bufexists(0)" to test for the existence of an alternate file name. + Parameters: ~ + • {buf} (`any`) + + Return: ~ + (`0|1`) + buflisted({buf}) *buflisted()* The result is a Number, which is |TRUE| if a buffer called {buf} exists and is listed (has the 'buflisted' option set). The {buf} argument is used like with |bufexists()|. + Parameters: ~ + • {buf} (`any`) + + Return: ~ + (`0|1`) + bufload({buf}) *bufload()* Ensure the buffer {buf} is loaded. When the buffer name refers to an existing file then the file is read. Otherwise @@ -405,11 +633,20 @@ bufload({buf}) *bufload()* there will be no dialog, the buffer will be loaded anyway. The {buf} argument is used like with |bufexists()|. + Parameters: ~ + • {buf} (`any`) + bufloaded({buf}) *bufloaded()* The result is a Number, which is |TRUE| if a buffer called {buf} exists and is loaded (shown in a window or hidden). The {buf} argument is used like with |bufexists()|. + Parameters: ~ + • {buf} (`any`) + + Return: ~ + (`0|1`) + bufname([{buf}]) *bufname()* The result is the name of a buffer. Mostly as it is displayed by the `:ls` command, but not using special names such as @@ -441,6 +678,12 @@ bufname([{buf}]) *bufname()* echo bufname("file2") " name of buffer where "file2" matches. < + Parameters: ~ + • {buf} (`integer|string?`) + + Return: ~ + (`string`) + bufnr([{buf} [, {create}]]) *bufnr()* The result is the number of a buffer, as it is displayed by the `:ls` command. For the use of {buf}, see |bufname()| @@ -455,6 +698,13 @@ bufnr([{buf} [, {create}]]) *bufnr()* number necessarily exist, because ":bwipeout" may have removed them. Use bufexists() to test for the existence of a buffer. + Parameters: ~ + • {buf} (`integer|string?`) + • {create} (`any?`) + + Return: ~ + (`integer`) + bufwinid({buf}) *bufwinid()* The result is a Number, which is the |window-ID| of the first window associated with buffer {buf}. For the use of {buf}, @@ -466,6 +716,12 @@ bufwinid({buf}) *bufwinid()* Only deals with the current tab page. See |win_findbuf()| for finding more. + Parameters: ~ + • {buf} (`any`) + + Return: ~ + (`integer`) + bufwinnr({buf}) *bufwinnr()* Like |bufwinid()| but return the window number instead of the |window-ID|. @@ -477,6 +733,12 @@ bufwinnr({buf}) *bufwinnr()* < The number can be used with |CTRL-W_w| and ":wincmd w" |:wincmd|. + Parameters: ~ + • {buf} (`any`) + + Return: ~ + (`integer`) + byte2line({byte}) *byte2line()* Return the line number that contains the character at byte count {byte} in the current buffer. This includes the @@ -487,6 +749,12 @@ byte2line({byte}) *byte2line()* Returns -1 if the {byte} value is invalid. + Parameters: ~ + • {byte} (`any`) + + Return: ~ + (`integer`) + byteidx({expr}, {nr} [, {utf16}]) *byteidx()* Return byte index of the {nr}th character in the String {expr}. Use zero for the first character, it then returns @@ -523,6 +791,14 @@ byteidx({expr}, {nr} [, {utf16}]) *byteidx()* echo byteidx('a😊😊', 3, 1) " returns 5 < + Parameters: ~ + • {expr} (`any`) + • {nr} (`integer`) + • {utf16} (`any?`) + + Return: ~ + (`integer`) + byteidxcomp({expr}, {nr} [, {utf16}]) *byteidxcomp()* Like byteidx(), except that a composing character is counted as a separate character. Example: >vim @@ -534,6 +810,14 @@ byteidxcomp({expr}, {nr} [, {utf16}]) *byteidxcomp()* character is 3 bytes), the second echo results in 1 ('e' is one byte). + Parameters: ~ + • {expr} (`any`) + • {nr} (`integer`) + • {utf16} (`any?`) + + Return: ~ + (`integer`) + call({func}, {arglist} [, {dict}]) *call()* *E699* Call function {func} with the items in |List| {arglist} as arguments. @@ -543,6 +827,14 @@ call({func}, {arglist} [, {dict}]) *call()* *E69 {dict} is for functions with the "dict" attribute. It will be used to set the local variable "self". |Dictionary-function| + Parameters: ~ + • {func} (`any`) + • {arglist} (`any`) + • {dict} (`any?`) + + Return: ~ + (`any`) + ceil({expr}) *ceil()* Return the smallest integral value greater than or equal to {expr} as a |Float| (round up). @@ -557,6 +849,12 @@ ceil({expr}) *ceil()* Returns 0.0 if {expr} is not a |Float| or a |Number|. + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`number`) + chanclose({id} [, {stream}]) *chanclose()* Close a channel or a specific stream associated with it. For a job, {stream} can be one of "stdin", "stdout", @@ -567,6 +865,13 @@ chanclose({id} [, {stream}]) *chanclose()* For a socket, there is only one stream, and {stream} should be omitted. + Parameters: ~ + • {id} (`integer`) + • {stream} (`string?`) + + Return: ~ + (`0|1`) + changenr() *changenr()* Return the number of the most recent change. This is the same number as what is displayed with |:undolist| and can be used @@ -576,6 +881,9 @@ changenr() *changenr()* one less than the number of the undone change. Returns 0 if the undo list is empty. + Return: ~ + (`integer`) + chansend({id}, {data}) *chansend()* Send data to channel {id}. For a job, it writes it to the stdin of the process. For the stdio channel |channel-stdio|, @@ -594,6 +902,13 @@ chansend({id}, {data}) *chansend()* was created with `"rpc":v:true` then the channel expects RPC messages, use |rpcnotify()| and |rpcrequest()| instead. + Parameters: ~ + • {id} (`number`) + • {data} (`string|string[]`) + + Return: ~ + (`0|1`) + char2nr({string} [, {utf8}]) *char2nr()* Return Number value of the first char in {string}. Examples: >vim @@ -609,6 +924,13 @@ char2nr({string} [, {utf8}]) *char2nr()* Returns 0 if {string} is not a |String|. + Parameters: ~ + • {string} (`string`) + • {utf8} (`any?`) + + Return: ~ + (`0|1`) + charclass({string}) *charclass()* Return the character class of the first character in {string}. The character class is one of: @@ -620,6 +942,12 @@ charclass({string}) *charclass()* The class is used in patterns and word motions. Returns 0 if {string} is not a |String|. + Parameters: ~ + • {string} (`string`) + + Return: ~ + (`0|1|2|3|'other'`) + charcol({expr} [, {winid}]) *charcol()* Same as |col()| but returns the character index of the column position given with {expr} instead of the byte position. @@ -628,6 +956,14 @@ charcol({expr} [, {winid}]) *charcol()* With the cursor on '세' in line 5 with text "여보세요": >vim echo charcol('.') " returns 3 echo col('.') " returns 7 +< + + Parameters: ~ + • {expr} (`string|integer[]`) + • {winid} (`integer?`) + + Return: ~ + (`integer`) charidx({string}, {idx} [, {countcc} [, {utf16}]]) *charidx()* Return the character index of the byte at {idx} in {string}. @@ -663,6 +999,15 @@ charidx({string}, {idx} [, {countcc} [, {utf16}]]) *charidx()* echo charidx('a😊😊', 4, 0, 1) " returns 2 < + Parameters: ~ + • {string} (`string`) + • {idx} (`integer`) + • {countcc} (`boolean?`) + • {utf16} (`boolean?`) + + Return: ~ + (`integer`) + chdir({dir}) *chdir()* Change the current working directory to {dir}. The scope of the directory change depends on the directory of the current @@ -684,6 +1029,13 @@ chdir({dir}) *chdir()* " ... do some work call chdir(save_dir) endif +< + + Parameters: ~ + • {dir} (`string`) + + Return: ~ + (`string`) cindent({lnum}) *cindent()* Get the amount of indent for line {lnum} according the C @@ -693,41 +1045,50 @@ cindent({lnum}) *cindent()* When {lnum} is invalid -1 is returned. See |C-indenting|. + Parameters: ~ + • {lnum} (`integer`) + + Return: ~ + (`integer`) + clearmatches([{win}]) *clearmatches()* Clears all matches previously defined for the current window by |matchadd()| and the |:match| commands. If {win} is specified, use the window with this number or window ID instead of the current window. + Parameters: ~ + • {win} (`integer?`) + col({expr} [, {winid}]) *col()* The result is a Number, which is the byte index of the column - position given with {expr}. The accepted positions are: - . the cursor position - $ the end of the cursor line (the result is the - number of bytes in the cursor line plus one) - 'x position of mark x (if the mark is not set, 0 is - returned) - v In Visual mode: the start of the Visual area (the - cursor is the end). When not in Visual mode - returns the cursor position. Differs from |'<| in - that it's updated right away. + position given with {expr}. + For accepted positions see |getpos()|. + When {expr} is "$", it means the end of the cursor line, so + the result is the number of bytes in the cursor line plus one. Additionally {expr} can be [lnum, col]: a |List| with the line and column number. Most useful when the column is "$", to get the last column of a specific line. When "lnum" or "col" is out of range then col() returns zero. + With the optional {winid} argument the values are obtained for that window instead of the current window. + To get the line number use |line()|. To get both use |getpos()|. + For the screen column position use |virtcol()|. For the character position use |charcol()|. + Note that only marks in the current file can be used. + Examples: >vim echo col(".") " column of cursor echo col("$") " length of cursor line plus one echo col("'t") " column of mark t echo col("'" .. markname) " column of mark markname -< The first column is 1. Returns 0 if {expr} is invalid or when +< + The first column is 1. Returns 0 if {expr} is invalid or when the window with ID {winid} is not found. For an uppercase mark the column may actually be in another buffer. @@ -736,6 +1097,14 @@ col({expr} [, {winid}]) *col()* line. Also, when using a <Cmd> mapping the cursor isn't moved, this can be used to obtain the column in Insert mode: >vim imap <F2> <Cmd>echo col(".").."\n"<CR> +< + + Parameters: ~ + • {expr} (`string|integer[]`) + • {winid} (`integer?`) + + Return: ~ + (`integer`) complete({startcol}, {matches}) *complete()* *E785* Set the matches for Insert mode completion. @@ -767,6 +1136,10 @@ complete({startcol}, {matches}) *complete()* *E78 < This isn't very useful, but it shows how it works. Note that an empty string is returned to avoid a zero being inserted. + Parameters: ~ + • {startcol} (`integer`) + • {matches} (`any[]`) + complete_add({expr}) *complete_add()* Add {expr} to the list of matches. Only to be used by the function specified with the 'completefunc' option. @@ -776,6 +1149,12 @@ complete_add({expr}) *complete_add()* See |complete-functions| for an explanation of {expr}. It is the same as one item in the list that 'omnifunc' would return. + Parameters: ~ + • {expr} (`any`) + + Return: ~ + (`0|1|2`) + complete_check() *complete_check()* Check for a key typed while looking for completion matches. This is to be used when looking for matches takes some time. @@ -784,6 +1163,9 @@ complete_check() *complete_check()* Only to be used by the function specified with the 'completefunc' option. + Return: ~ + (`0|1`) + complete_info([{what}]) *complete_info()* Returns a |Dictionary| with information about Insert mode completion. See |ins-completion|. @@ -843,6 +1225,13 @@ complete_info([{what}]) *complete_info()* call complete_info(['mode']) " Get only 'mode' and 'pum_visible' call complete_info(['mode', 'pum_visible']) +< + + Parameters: ~ + • {what} (`any[]?`) + + Return: ~ + (`table`) confirm({msg} [, {choices} [, {default} [, {type}]]]) *confirm()* confirm() offers the user a dialog, from which a choice can be @@ -896,6 +1285,15 @@ confirm({msg} [, {choices} [, {default} [, {type}]]]) *confirm()* don't fit, a vertical layout is used anyway. For some systems the horizontal layout is always used. + Parameters: ~ + • {msg} (`string`) + • {choices} (`string?`) + • {default} (`integer?`) + • {type} (`string?`) + + Return: ~ + (`integer`) + copy({expr}) *copy()* Make a copy of {expr}. For Numbers and Strings this isn't different from using {expr} directly. @@ -906,6 +1304,12 @@ copy({expr}) *copy()* A |Dictionary| is copied in a similar way as a |List|. Also see |deepcopy()|. + Parameters: ~ + • {expr} (`any`) + + Return: ~ + (`any`) + cos({expr}) *cos()* Return the cosine of {expr}, measured in radians, as a |Float|. {expr} must evaluate to a |Float| or a |Number|. @@ -916,6 +1320,12 @@ cos({expr}) *cos()* echo cos(-4.01) < -0.646043 + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`number`) + cosh({expr}) *cosh()* Return the hyperbolic cosine of {expr} as a |Float| in the range [1, inf]. @@ -927,6 +1337,12 @@ cosh({expr}) *cosh()* echo cosh(-0.5) < -1.127626 + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`number`) + count({comp}, {expr} [, {ic} [, {start}]]) *count()* *E706* Return the number of times an item with value {expr} appears in |String|, |List| or |Dictionary| {comp}. @@ -940,15 +1356,33 @@ count({comp}, {expr} [, {ic} [, {start}]]) *count()* *E70 occurrences of {expr} is returned. Zero is returned when {expr} is an empty string. + Parameters: ~ + • {comp} (`string|table|any[]`) + • {expr} (`any`) + • {ic} (`boolean?`) + • {start} (`integer?`) + + Return: ~ + (`integer`) + ctxget([{index}]) *ctxget()* Returns a |Dictionary| representing the |context| at {index} from the top of the |context-stack| (see |context-dict|). If {index} is not given, it is assumed to be 0 (i.e.: top). + Parameters: ~ + • {index} (`integer?`) + + Return: ~ + (`table`) + ctxpop() *ctxpop()* Pops and restores the |context| at the top of the |context-stack|. + Return: ~ + (`any`) + ctxpush([{types}]) *ctxpush()* Pushes the current editor state (|context|) on the |context-stack|. @@ -956,15 +1390,31 @@ ctxpush([{types}]) *ctxpush()* which |context-types| to include in the pushed context. Otherwise, all context types are included. + Parameters: ~ + • {types} (`string[]?`) + + Return: ~ + (`any`) + ctxset({context} [, {index}]) *ctxset()* Sets the |context| at {index} from the top of the |context-stack| to that represented by {context}. {context} is a Dictionary with context data (|context-dict|). If {index} is not given, it is assumed to be 0 (i.e.: top). + Parameters: ~ + • {context} (`table`) + • {index} (`integer?`) + + Return: ~ + (`any`) + ctxsize() *ctxsize()* Returns the size of the |context-stack|. + Return: ~ + (`any`) + cursor({lnum}, {col} [, {off}]) *cursor()* cursor({list}) Positions the cursor at the column (byte count) {col} in the @@ -998,6 +1448,12 @@ cursor({list}) position within a <Tab> or after the last character. Returns 0 when the position could be set, -1 otherwise. + Parameters: ~ + • {list} (`integer[]`) + + Return: ~ + (`any`) + debugbreak({pid}) *debugbreak()* Specifically used to interrupt a program being debugged. It will cause process {pid} to get a SIGTRAP. Behavior for other @@ -1007,6 +1463,12 @@ debugbreak({pid}) *debugbreak()* Returns |TRUE| if successfully interrupted the program. Otherwise returns |FALSE|. + Parameters: ~ + • {pid} (`integer`) + + Return: ~ + (`any`) + deepcopy({expr} [, {noref}]) *deepcopy()* *E698* Make a copy of {expr}. For Numbers and Strings this isn't different from using {expr} directly. @@ -1027,6 +1489,13 @@ deepcopy({expr} [, {noref}]) *deepcopy()* *E69 {noref} set to 1 will fail. Also see |copy()|. + Parameters: ~ + • {expr} (`any`) + • {noref} (`boolean?`) + + Return: ~ + (`any`) + delete({fname} [, {flags}]) *delete()* Without {flags} or with {flags} empty: Deletes the file by the name {fname}. @@ -1046,6 +1515,13 @@ delete({fname} [, {flags}]) *delete()* operation was successful and -1/true when the deletion failed or partly failed. + Parameters: ~ + • {fname} (`string`) + • {flags} (`string?`) + + Return: ~ + (`integer`) + deletebufline({buf}, {first} [, {last}]) *deletebufline()* Delete lines {first} to {last} (inclusive) from buffer {buf}. If {last} is omitted then delete line {first} only. @@ -1060,6 +1536,14 @@ deletebufline({buf}, {first} [, {last}]) *deletebufline()* when using |line()| this refers to the current buffer. Use "$" to refer to the last line in buffer {buf}. + Parameters: ~ + • {buf} (`integer|string`) + • {first} (`integer|string`) + • {last} (`integer|string?`) + + Return: ~ + (`any`) + dictwatcheradd({dict}, {pattern}, {callback}) *dictwatcheradd()* Adds a watcher to a dictionary. A dictionary watcher is identified by three components: @@ -1100,11 +1584,27 @@ dictwatcheradd({dict}, {pattern}, {callback}) *dictwatcheradd()* This function can be used by plugins to implement options with validation and parsing logic. + Parameters: ~ + • {dict} (`table`) + • {pattern} (`string`) + • {callback} (`function`) + + Return: ~ + (`any`) + dictwatcherdel({dict}, {pattern}, {callback}) *dictwatcherdel()* Removes a watcher added with |dictwatcheradd()|. All three arguments must match the ones passed to |dictwatcheradd()| in order for the watcher to be successfully deleted. + Parameters: ~ + • {dict} (`any`) + • {pattern} (`string`) + • {callback} (`function`) + + Return: ~ + (`any`) + did_filetype() *did_filetype()* Returns |TRUE| when autocommands are being executed and the FileType event has been triggered at least once. Can be used @@ -1117,6 +1617,9 @@ did_filetype() *did_filetype()* editing another buffer to set 'filetype' and load a syntax file. + Return: ~ + (`any`) + diff_filler({lnum}) *diff_filler()* Returns the number of filler lines above line {lnum}. These are the lines that were inserted at this point in @@ -1126,6 +1629,12 @@ diff_filler({lnum}) *diff_filler()* line, "'m" mark m, etc. Returns 0 if the current window is not in diff mode. + Parameters: ~ + • {lnum} (`integer`) + + Return: ~ + (`any`) + diff_hlID({lnum}, {col}) *diff_hlID()* Returns the highlight ID for diff mode at line {lnum} column {col} (byte index). When the current line does not have a @@ -1137,6 +1646,13 @@ diff_hlID({lnum}, {col}) *diff_hlID()* The highlight ID can be used with |synIDattr()| to obtain syntax information about the highlighting. + Parameters: ~ + • {lnum} (`integer`) + • {col} (`integer`) + + Return: ~ + (`any`) + digraph_get({chars}) *digraph_get()* *E1214* Return the digraph of {chars}. This should be a string with exactly two characters. If {chars} are not just two @@ -1154,6 +1670,12 @@ digraph_get({chars}) *digraph_get()* *E121 echo digraph_get('aa') " Returns 'ã‚' < + Parameters: ~ + • {chars} (`string`) + + Return: ~ + (`any`) + digraph_getlist([{listall}]) *digraph_getlist()* Return a list of digraphs. If the {listall} argument is given and it is TRUE, return all digraphs, including the default @@ -1169,6 +1691,12 @@ digraph_getlist([{listall}]) *digraph_getlist()* echo digraph_getlist(1) < + Parameters: ~ + • {listall} (`boolean?`) + + Return: ~ + (`any`) + digraph_set({chars}, {digraph}) *digraph_set()* Add digraph {chars} to the list. {chars} must be a string with two characters. {digraph} is a string with one UTF-8 @@ -1186,9 +1714,13 @@ digraph_set({chars}, {digraph}) *digraph_set()* Example: >vim call digraph_set(' ', 'ã‚') < - Can be used as a |method|: >vim - GetString()->digraph_set('ã‚') -< + + Parameters: ~ + • {chars} (`string`) + • {digraph} (`string`) + + Return: ~ + (`any`) digraph_setlist({digraphlist}) *digraph_setlist()* Similar to |digraph_set()| but this function can add multiple @@ -1205,9 +1737,11 @@ digraph_setlist({digraphlist}) *digraph_setlist()* < Except that the function returns after the first error, following digraphs will not be added. - Can be used as a |method|: >vim - GetList()->digraph_setlist() -< + Parameters: ~ + • {digraphlist} (`table<integer,string[]>`) + + Return: ~ + (`any`) empty({expr}) *empty()* Return the Number 1 if {expr} is empty, zero otherwise. @@ -1218,6 +1752,12 @@ empty({expr}) *empty()* - |v:false| and |v:null| are empty, |v:true| is not. - A |Blob| is empty when its length is zero. + Parameters: ~ + • {expr} (`any`) + + Return: ~ + (`any`) + environ() *environ()* Return all of environment variables as dictionary. You can check if an environment variable exists like this: >vim @@ -1227,6 +1767,9 @@ environ() *environ()* echo index(keys(environ()), 'HOME', 0, 1) != -1 < + Return: ~ + (`any`) + escape({string}, {chars}) *escape()* Escape the characters in {chars} that occur in {string} with a backslash. Example: >vim @@ -1235,6 +1778,13 @@ escape({string}, {chars}) *escape()* c:\\program\ files\\vim < Also see |shellescape()| and |fnameescape()|. + Parameters: ~ + • {string} (`string`) + • {chars} (`string`) + + Return: ~ + (`any`) + eval({string}) *eval()* Evaluate {string} and return the result. Especially useful to turn the result of |string()| back into the original value. @@ -1242,34 +1792,56 @@ eval({string}) *eval()* of them. Also works for |Funcref|s that refer to existing functions. + Parameters: ~ + • {string} (`string`) + + Return: ~ + (`any`) + eventhandler() *eventhandler()* Returns 1 when inside an event handler. That is that Vim got interrupted while waiting for the user to type a character, e.g., when dropping a file on Vim. This means interactive commands cannot be used. Otherwise zero is returned. + Return: ~ + (`any`) + executable({expr}) *executable()* This function checks if an executable with the name {expr} exists. {expr} must be the name of the program without any arguments. + executable() uses the value of $PATH and/or the normal - searchpath for programs. *PATHEXT* + searchpath for programs. + *PATHEXT* On MS-Windows the ".exe", ".bat", etc. can optionally be included. Then the extensions in $PATHEXT are tried. Thus if "foo.exe" does not exist, "foo.exe.bat" can be found. If - $PATHEXT is not set then ".exe;.com;.bat;.cmd" is used. A dot + $PATHEXT is not set then ".com;.exe;.bat;.cmd" is used. A dot by itself can be used in $PATHEXT to try using the name without an extension. When 'shell' looks like a Unix shell, then the name is also tried without adding an extension. On MS-Windows it only checks if the file exists and is not a directory, not if it's really executable. - On Windows an executable in the same directory as Vim is - always found (it is added to $PATH at |startup|). + On MS-Windows an executable in the same directory as the Vim + executable is always found (it's added to $PATH at |startup|). + *NoDefaultCurrentDirectoryInExePath* + On MS-Windows an executable in Vim's current working directory + is also normally found, but this can be disabled by setting + the $NoDefaultCurrentDirectoryInExePath environment variable. + The result is a Number: 1 exists 0 does not exist |exepath()| can be used to get the full path of an executable. + Parameters: ~ + • {expr} (`string`) + + Return: ~ + (`0|1`) + execute({command} [, {silent}]) *execute()* Execute {command} and capture its output. If {command} is a |String|, returns {command} output. @@ -1298,12 +1870,25 @@ execute({command} [, {silent}]) *execute()* To execute a command in another window than the current one use `win_execute()`. + Parameters: ~ + • {command} (`string|string[]`) + • {silent} (`''|'silent'|'silent!'?`) + + Return: ~ + (`string`) + exepath({expr}) *exepath()* Returns the full path of {expr} if it is an executable and given as a (partial or full) path or is found in $PATH. Returns empty string otherwise. If {expr} starts with "./" the |current-directory| is used. + Parameters: ~ + • {expr} (`string`) + + Return: ~ + (`string`) + exists({expr}) *exists()* The result is a Number, which is |TRUE| if {expr} is defined, zero otherwise. @@ -1393,6 +1978,12 @@ exists({expr}) *exists()* < This doesn't check for existence of the "bufcount" variable, but gets the value of "bufcount", and checks if that exists. + Parameters: ~ + • {expr} (`string`) + + Return: ~ + (`0|1`) + exp({expr}) *exp()* Return the exponential of {expr} as a |Float| in the range [0, inf]. @@ -1404,6 +1995,12 @@ exp({expr}) *exp()* echo exp(-1) < 0.367879 + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`any`) + expand({string} [, {nosuf} [, {list}]]) *expand()* Expand wildcards and the following special keywords in {string}. 'wildignorecase' applies. @@ -1495,6 +2092,14 @@ expand({string} [, {nosuf} [, {list}]]) *expand()* See |glob()| for finding existing files. See |system()| for getting the raw output of an external command. + Parameters: ~ + • {string} (`string`) + • {nosuf} (`boolean?`) + • {list} (`nil|false?`) + + Return: ~ + (`string`) + expandcmd({string} [, {options}]) *expandcmd()* Expand special items in String {string} like what is done for an Ex command such as `:edit`. This expands special keywords, @@ -1519,6 +2124,13 @@ expandcmd({string} [, {options}]) *expandcmd()* echo expandcmd('make %<.o', {'errmsg': v:true}) < + Parameters: ~ + • {string} (`string`) + • {options} (`table?`) + + Return: ~ + (`any`) + extend({expr1}, {expr2} [, {expr3}]) *extend()* {expr1} and {expr2} must be both |Lists| or both |Dictionaries|. @@ -1555,11 +2167,27 @@ extend({expr1}, {expr2} [, {expr3}]) *extend()* fails. Returns {expr1}. Returns 0 on error. + Parameters: ~ + • {expr1} (`table`) + • {expr2} (`table`) + • {expr3} (`table?`) + + Return: ~ + (`any`) + extendnew({expr1}, {expr2} [, {expr3}]) *extendnew()* Like |extend()| but instead of adding items to {expr1} a new List or Dictionary is created and returned. {expr1} remains unchanged. + Parameters: ~ + • {expr1} (`table`) + • {expr2} (`table`) + • {expr3} (`table?`) + + Return: ~ + (`any`) + feedkeys({string} [, {mode}]) *feedkeys()* Characters in {string} are queued for processing as if they come from a mapping or were typed by the user. @@ -1606,6 +2234,29 @@ feedkeys({string} [, {mode}]) *feedkeys()* Return value is always 0. + Parameters: ~ + • {string} (`string`) + • {mode} (`string?`) + + Return: ~ + (`any`) + +filecopy({from}, {to}) *filecopy()* + Copy the file pointed to by the name {from} to {to}. The + result is a Number, which is |TRUE| if the file was copied + successfully, and |FALSE| when it failed. + If a file with name {to} already exists, it will fail. + Note that it does not handle directories (yet). + + This function is not available in the |sandbox|. + + Parameters: ~ + • {from} (`string`) + • {to} (`string`) + + Return: ~ + (`0|1`) + filereadable({file}) *filereadable()* The result is a Number, which is |TRUE| when a file with the name {file} exists, and can be read. If {file} doesn't exist, @@ -1623,12 +2274,24 @@ filereadable({file}) *filereadable()* 1 < + Parameters: ~ + • {file} (`string`) + + Return: ~ + (`0|1`) + filewritable({file}) *filewritable()* The result is a Number, which is 1 when a file with the name {file} exists, and can be written. If {file} doesn't exist, or is not writable, the result is 0. If {file} is a directory, and we can write to it, the result is 2. + Parameters: ~ + • {file} (`string`) + + Return: ~ + (`0|1`) + filter({expr1}, {expr2}) *filter()* {expr1} must be a |List|, |String|, |Blob| or |Dictionary|. For each item in {expr1} evaluate {expr2} and when the result @@ -1682,6 +2345,13 @@ filter({expr1}, {expr2}) *filter()* When {expr2} is a Funcref errors inside a function are ignored, unless it was defined with the "abort" flag. + Parameters: ~ + • {expr1} (`string|table`) + • {expr2} (`string|function`) + + Return: ~ + (`any`) + finddir({name} [, {path} [, {count}]]) *finddir()* Find directory {name} in {path}. Supports both downwards and upwards recursive directory searches. See |file-searching| @@ -1700,6 +2370,14 @@ finddir({name} [, {path} [, {count}]]) *finddir()* This is quite similar to the ex-command `:find`. + Parameters: ~ + • {name} (`string`) + • {path} (`string?`) + • {count} (`integer?`) + + Return: ~ + (`any`) + findfile({name} [, {path} [, {count}]]) *findfile()* Just like |finddir()|, but find a file instead of a directory. Uses 'suffixesadd'. @@ -1708,6 +2386,14 @@ findfile({name} [, {path} [, {count}]]) *findfile()* < Searches from the directory of the current file upwards until it finds the file "tags.vim". + Parameters: ~ + • {name} (`string`) + • {path} (`string?`) + • {count} (`any?`) + + Return: ~ + (`any`) + flatten({list} [, {maxdepth}]) *flatten()* Flatten {list} up to {maxdepth} levels. Without {maxdepth} the result is a |List| without nesting, as if {maxdepth} is @@ -1727,9 +2413,23 @@ flatten({list} [, {maxdepth}]) *flatten()* echo flatten([1, [2, [3, 4]], 5], 1) < [1, 2, [3, 4], 5] + Parameters: ~ + • {list} (`any[]`) + • {maxdepth} (`integer?`) + + Return: ~ + (`any[]|0`) + flattennew({list} [, {maxdepth}]) *flattennew()* Like |flatten()| but first make a copy of {list}. + Parameters: ~ + • {list} (`any[]`) + • {maxdepth} (`integer?`) + + Return: ~ + (`any[]|0`) + float2nr({expr}) *float2nr()* Convert {expr} to a Number by omitting the part after the decimal point. @@ -1752,6 +2452,12 @@ float2nr({expr}) *float2nr()* echo float2nr(1.0e-100) < 0 + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`any`) + floor({expr}) *floor()* Return the largest integral value less than or equal to {expr} as a |Float| (round down). @@ -1765,6 +2471,12 @@ floor({expr}) *floor()* echo floor(4.0) < 4.0 + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`any`) + fmod({expr1}, {expr2}) *fmod()* Return the remainder of {expr1} / {expr2}, even if the division is not representable. Returns {expr1} - i * {expr2} @@ -1781,6 +2493,13 @@ fmod({expr1}, {expr2}) *fmod()* echo fmod(-12.33, 1.22) < -0.13 + Parameters: ~ + • {expr1} (`number`) + • {expr2} (`number`) + + Return: ~ + (`any`) + fnameescape({string}) *fnameescape()* Escape {string} for use as file name command argument. All characters that have a special meaning, such as `'%'` and `'|'` @@ -1798,6 +2517,12 @@ fnameescape({string}) *fnameescape()* edit \+some\ str\%nge\|name < + Parameters: ~ + • {string} (`string`) + + Return: ~ + (`string`) + fnamemodify({fname}, {mods}) *fnamemodify()* Modify file name {fname} according to {mods}. {mods} is a string of characters like it is used for file names on the @@ -1815,6 +2540,13 @@ fnamemodify({fname}, {mods}) *fnamemodify()* Note: Environment variables don't work in {fname}, use |expand()| first then. + Parameters: ~ + • {fname} (`string`) + • {mods} (`string`) + + Return: ~ + (`string`) + foldclosed({lnum}) *foldclosed()* The result is a Number. If the line {lnum} is in a closed fold, the result is the number of the first line in that fold. @@ -1822,6 +2554,12 @@ foldclosed({lnum}) *foldclosed()* {lnum} is used like with |getline()|. Thus "." is the current line, "'m" mark m, etc. + Parameters: ~ + • {lnum} (`integer`) + + Return: ~ + (`integer`) + foldclosedend({lnum}) *foldclosedend()* The result is a Number. If the line {lnum} is in a closed fold, the result is the number of the last line in that fold. @@ -1829,6 +2567,12 @@ foldclosedend({lnum}) *foldclosedend()* {lnum} is used like with |getline()|. Thus "." is the current line, "'m" mark m, etc. + Parameters: ~ + • {lnum} (`integer`) + + Return: ~ + (`integer`) + foldlevel({lnum}) *foldlevel()* The result is a Number, which is the foldlevel of line {lnum} in the current buffer. For nested folds the deepest level is @@ -1841,6 +2585,12 @@ foldlevel({lnum}) *foldlevel()* {lnum} is used like with |getline()|. Thus "." is the current line, "'m" mark m, etc. + Parameters: ~ + • {lnum} (`integer`) + + Return: ~ + (`integer`) + foldtext() *foldtext()* Returns a String, to be displayed for a closed fold. This is the default function used for the 'foldtext' option and should @@ -1858,6 +2608,9 @@ foldtext() *foldtext()* setting. Returns an empty string when there is no fold. + Return: ~ + (`string`) + foldtextresult({lnum}) *foldtextresult()* Returns the text that is displayed for the closed fold at line {lnum}. Evaluates 'foldtext' in the appropriate context. @@ -1867,6 +2620,12 @@ foldtextresult({lnum}) *foldtextresult()* line, "'m" mark m, etc. Useful when exporting folded text, e.g., to HTML. + Parameters: ~ + • {lnum} (`integer`) + + Return: ~ + (`string`) + foreach({expr1}, {expr2}) *foreach()* {expr1} must be a |List|, |String|, |Blob| or |Dictionary|. For each item in {expr1} execute {expr2}. {expr1} is not @@ -1902,6 +2661,13 @@ foreach({expr1}, {expr2}) *foreach()* When {expr2} is a Funcref errors inside a function are ignored, unless it was defined with the "abort" flag. + Parameters: ~ + • {expr1} (`string|table`) + • {expr2} (`string|function`) + + Return: ~ + (`any`) + fullcommand({name}) *fullcommand()* Get the full command name from a short abbreviated command name; see |20.2| for details on command abbreviations. @@ -1914,6 +2680,12 @@ fullcommand({name}) *fullcommand()* For example `fullcommand('s')`, `fullcommand('sub')`, `fullcommand(':%substitute')` all return "substitute". + Parameters: ~ + • {name} (`string`) + + Return: ~ + (`string`) + funcref({name} [, {arglist}] [, {dict}]) *funcref()* Just like |function()|, but the returned Funcref will lookup the function by reference, not by name. This matters when the @@ -1926,6 +2698,14 @@ funcref({name} [, {arglist}] [, {dict}]) *funcref()* instead). {name} cannot be a builtin function. Returns 0 on error. + Parameters: ~ + • {name} (`string`) + • {arglist} (`any?`) + • {dict} (`any?`) + + Return: ~ + (`any`) + function({name} [, {arglist}] [, {dict}]) *function()* *partial* *E700* *E923* Return a |Funcref| variable that refers to function {name}. {name} can be the name of a user defined function or an @@ -2008,6 +2788,14 @@ function({name} [, {arglist}] [, {dict}]) *function()* *partial* *E700* < Returns 0 on error. + Parameters: ~ + • {name} (`string`) + • {arglist} (`any?`) + • {dict} (`any?`) + + Return: ~ + (`any`) + garbagecollect([{atexit}]) *garbagecollect()* Cleanup unused |Lists| and |Dictionaries| that have circular references. @@ -2028,17 +2816,39 @@ garbagecollect([{atexit}]) *garbagecollect()* it's safe to perform. This is when waiting for the user to type a character. -get({list}, {idx} [, {default}]) *get()* + Parameters: ~ + • {atexit} (`boolean?`) + + Return: ~ + (`any`) + +get({list}, {idx} [, {default}]) *get()* *get()-list* Get item {idx} from |List| {list}. When this item is not available return {default}. Return zero when {default} is omitted. -get({blob}, {idx} [, {default}]) + Parameters: ~ + • {list} (`any[]`) + • {idx} (`integer`) + • {default} (`any?`) + + Return: ~ + (`any`) + +get({blob}, {idx} [, {default}]) *get()-blob* Get byte {idx} from |Blob| {blob}. When this byte is not available return {default}. Return -1 when {default} is omitted. -get({dict}, {key} [, {default}]) + Parameters: ~ + • {blob} (`string`) + • {idx} (`integer`) + • {default} (`any?`) + + Return: ~ + (`any`) + +get({dict}, {key} [, {default}]) *get()-dict* Get item with key {key} from |Dictionary| {dict}. When this item is not available return {default}. Return zero when {default} is omitted. Useful example: >vim @@ -2046,15 +2856,43 @@ get({dict}, {key} [, {default}]) < This gets the value of g:var_name if it exists, and uses "default" when it does not exist. -get({func}, {what}) - Get item {what} from Funcref {func}. Possible values for + Parameters: ~ + • {dict} (`table<string,any>`) + • {key} (`string`) + • {default} (`any?`) + + Return: ~ + (`any`) + +get({func}, {what}) *get()-func* + Get item {what} from |Funcref| {func}. Possible values for {what} are: - "name" The function name - "func" The function - "dict" The dictionary - "args" The list with arguments + "name" The function name + "func" The function + "dict" The dictionary + "args" The list with arguments + "arity" A dictionary with information about the number of + arguments accepted by the function (minus the + {arglist}) with the following fields: + required the number of positional arguments + optional the number of optional arguments, + in addition to the required ones + varargs |TRUE| if the function accepts a + variable number of arguments |...| + + Note: There is no error, if the {arglist} of + the Funcref contains more arguments than the + Funcref expects, it's not validated. + Returns zero on error. + Parameters: ~ + • {func} (`function`) + • {what} (`string`) + + Return: ~ + (`any`) + getbufinfo([{buf}]) *getbufinfo()* getbufinfo([{dict}]) Get information about buffers as a List of Dictionaries. @@ -2124,6 +2962,12 @@ getbufinfo([{dict}]) getbufvar({bufnr}, '&option_name') < + Parameters: ~ + • {dict} (`vim.fn.getbufinfo.dict?`) + + Return: ~ + (`vim.fn.getbufinfo.ret.item[]`) + getbufline({buf}, {lnum} [, {end}]) *getbufline()* Return a |List| with the lines starting from {lnum} to {end} (inclusive) in the buffer {buf}. If {end} is omitted, a @@ -2148,11 +2992,27 @@ getbufline({buf}, {lnum} [, {end}]) *getbufline()* Example: >vim let lines = getbufline(bufnr("myfile"), 1, "$") +< + + Parameters: ~ + • {buf} (`integer|string`) + • {lnum} (`integer`) + • {end_} (`integer?`) + + Return: ~ + (`any`) getbufoneline({buf}, {lnum}) *getbufoneline()* Just like `getbufline()` but only get one line and return it as a string. + Parameters: ~ + • {buf} (`integer|string`) + • {lnum} (`integer`) + + Return: ~ + (`string`) + getbufvar({buf}, {varname} [, {def}]) *getbufvar()* The result is the value of option or local buffer variable {varname} in buffer {buf}. Note that the name without "b:" @@ -2174,12 +3034,23 @@ getbufvar({buf}, {varname} [, {def}]) *getbufvar()* let bufmodified = getbufvar(1, "&mod") echo "todo myvar = " .. getbufvar("todo", "myvar") + Parameters: ~ + • {buf} (`integer|string`) + • {varname} (`string`) + • {def} (`any?`) + + Return: ~ + (`any`) + getcellwidths() *getcellwidths()* Returns a |List| of cell widths of character ranges overridden by |setcellwidths()|. The format is equal to the argument of |setcellwidths()|. If no character ranges have their cell widths overridden, an empty List is returned. + Return: ~ + (`any`) + getchangelist([{buf}]) *getchangelist()* Returns the |changelist| for the buffer {buf}. For the use of {buf}, see |bufname()| above. If buffer {buf} doesn't @@ -2196,6 +3067,12 @@ getchangelist([{buf}]) *getchangelist()* position refers to the position in the list. For other buffers, it is set to the length of the list. + Parameters: ~ + • {buf} (`integer|string?`) + + Return: ~ + (`table[]`) + getchar([{expr}]) *getchar()* Get a single character from the user or input stream. If {expr} is omitted, wait until a character is available. @@ -2261,6 +3138,12 @@ getchar([{expr}]) *getchar()* endfunction < + Parameters: ~ + • {expr} (`0|1?`) + + Return: ~ + (`integer`) + getcharmod() *getcharmod()* The result is a Number which is the state of the modifiers for the last obtained character with getchar() or in another way. @@ -2277,6 +3160,9 @@ getcharmod() *getcharmod()* character itself are obtained. Thus Shift-a results in "A" without a modifier. Returns 0 if no modifiers are used. + Return: ~ + (`integer`) + getcharpos({expr}) *getcharpos()* Get the position for String {expr}. Same as |getpos()| but the column number in the returned List is a character index @@ -2291,6 +3177,12 @@ getcharpos({expr}) *getcharpos()* getpos('.') returns [0, 5, 7, 0] < + Parameters: ~ + • {expr} (`string`) + + Return: ~ + (`integer[]`) + getcharsearch() *getcharsearch()* Return the current character search information as a {dict} with the following entries: @@ -2311,6 +3203,9 @@ getcharsearch() *getcharsearch()* nnoremap <expr> , getcharsearch().forward ? ',' : ';' < Also see |setcharsearch()|. + Return: ~ + (`table`) + getcharstr([{expr}]) *getcharstr()* Get a single character from the user or input stream as a string. @@ -2323,34 +3218,60 @@ getcharstr([{expr}]) *getcharstr()* Otherwise this works like |getchar()|, except that a number result is converted to a string. + Parameters: ~ + • {expr} (`0|1?`) + + Return: ~ + (`string`) + getcmdcompltype() *getcmdcompltype()* Return the type of the current command-line completion. Only works when the command line is being edited, thus requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. See |:command-completion| for the return string. - Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()| and - |setcmdline()|. + Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, + |getcmdprompt()| and |setcmdline()|. Returns an empty string when completion is not defined. + Return: ~ + (`string`) + getcmdline() *getcmdline()* - Return the current command-line. Only works when the command - line is being edited, thus requires use of |c_CTRL-\_e| or - |c_CTRL-R_=|. + Return the current command-line input. Only works when the + command line is being edited, thus requires use of + |c_CTRL-\_e| or |c_CTRL-R_=|. Example: >vim cmap <F7> <C-\>eescape(getcmdline(), ' \')<CR> -< Also see |getcmdtype()|, |getcmdpos()|, |setcmdpos()| and - |setcmdline()|. +< Also see |getcmdtype()|, |getcmdpos()|, |setcmdpos()|, + |getcmdprompt()| and |setcmdline()|. Returns an empty string when entering a password or using |inputsecret()|. + Return: ~ + (`string`) + getcmdpos() *getcmdpos()* Return the position of the cursor in the command line as a byte count. The first column is 1. Only works when editing the command line, thus requires use of |c_CTRL-\_e| or |c_CTRL-R_=| or an expression mapping. Returns 0 otherwise. - Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()| and - |setcmdline()|. + Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, + |getcmdprompt()| and |setcmdline()|. + + Return: ~ + (`integer`) + +getcmdprompt() *getcmdprompt()* + Return the current command-line prompt when using functions + like |input()| or |confirm()|. + Only works when the command line is being edited, thus + requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. + Also see |getcmdtype()|, |getcmdline()|, |getcmdpos()|, + |setcmdpos()| and |setcmdline()|. + + Return: ~ + (`string`) getcmdscreenpos() *getcmdscreenpos()* Return the screen position of the cursor in the command line @@ -2362,6 +3283,9 @@ getcmdscreenpos() *getcmdscreenpos()* Also see |getcmdpos()|, |setcmdpos()|, |getcmdline()| and |setcmdline()|. + Return: ~ + (`any`) + getcmdtype() *getcmdtype()* Return the current command-line type. Possible return values are: @@ -2377,11 +3301,17 @@ getcmdtype() *getcmdtype()* Returns an empty string otherwise. Also see |getcmdpos()|, |setcmdpos()| and |getcmdline()|. + Return: ~ + (`':'|'>'|'/'|'?'|'@'|'-'|'='`) + getcmdwintype() *getcmdwintype()* Return the current |command-line-window| type. Possible return values are the same as |getcmdtype()|. Returns an empty string when not in the command-line window. + Return: ~ + (`':'|'>'|'/'|'?'|'@'|'-'|'='`) + getcompletion({pat}, {type} [, {filtered}]) *getcompletion()* Return a list of command-line completion matches. The String {type} argument specifies what for. The following completion @@ -2399,6 +3329,7 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()* customlist,{func} custom completion, defined via {func} diff_buffer |:diffget| and |:diffput| completion dir directory names + dir_in_path directory names in |'cdpath'| environment environment variable names event autocommand events expression Vim expression @@ -2451,6 +3382,14 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()* If there are no matches, an empty list is returned. An invalid value for {type} produces an error. + Parameters: ~ + • {pat} (`string`) + • {type} (`string`) + • {filtered} (`boolean?`) + + Return: ~ + (`string[]`) + getcurpos([{winid}]) *getcurpos()* Get the position of the cursor. This is like getpos('.'), but includes an extra "curswant" item in the list: @@ -2476,6 +3415,12 @@ getcurpos([{winid}]) *getcurpos()* < Note that this only works within the window. See |winrestview()| for restoring more state. + Parameters: ~ + • {winid} (`integer?`) + + Return: ~ + (`any`) + getcursorcharpos([{winid}]) *getcursorcharpos()* Same as |getcurpos()| but the column number in the returned List is a character index instead of a byte index. @@ -2486,6 +3431,12 @@ getcursorcharpos([{winid}]) *getcursorcharpos()* getcurpos() " returns [0, 3, 4, 0, 3] < + Parameters: ~ + • {winid} (`integer?`) + + Return: ~ + (`any`) + getcwd([{winnr} [, {tabnr}]]) *getcwd()* With no arguments, returns the name of the effective |current-directory|. With {winnr} or {tabnr} the working @@ -2502,6 +3453,13 @@ getcwd([{winnr} [, {tabnr}]]) *getcwd()* directory is returned. Throw error if the arguments are invalid. |E5000| |E5001| |E5002| + Parameters: ~ + • {winnr} (`integer?`) + • {tabnr} (`integer?`) + + Return: ~ + (`string`) + getenv({name}) *getenv()* Return the value of environment variable {name}. The {name} argument is a string, without a leading '$'. Example: >vim @@ -2511,6 +3469,12 @@ getenv({name}) *getenv()* is different from a variable set to an empty string. See also |expr-env|. + Parameters: ~ + • {name} (`string`) + + Return: ~ + (`string`) + getfontname([{name}]) *getfontname()* Without an argument returns the name of the normal font being used. Like what is used for the Normal highlight group @@ -2523,6 +3487,12 @@ getfontname([{name}]) *getfontname()* gvimrc file. Use the |GUIEnter| autocommand to use this function just after the GUI has started. + Parameters: ~ + • {name} (`string?`) + + Return: ~ + (`string`) + getfperm({fname}) *getfperm()* The result is a String, which is the read, write, and execute permissions of the given file {fname}. @@ -2540,6 +3510,12 @@ getfperm({fname}) *getfperm()* For setting permissions use |setfperm()|. + Parameters: ~ + • {fname} (`string`) + + Return: ~ + (`string`) + getfsize({fname}) *getfsize()* The result is a Number, which is the size in bytes of the given file {fname}. @@ -2548,6 +3524,12 @@ getfsize({fname}) *getfsize()* If the size of {fname} is too big to fit in a Number then -2 is returned. + Parameters: ~ + • {fname} (`string`) + + Return: ~ + (`integer`) + getftime({fname}) *getftime()* The result is a Number, which is the last modification time of the given file {fname}. The value is measured as seconds @@ -2555,6 +3537,12 @@ getftime({fname}) *getftime()* |localtime()| and |strftime()|. If the file {fname} can't be found -1 is returned. + Parameters: ~ + • {fname} (`string`) + + Return: ~ + (`integer`) + getftype({fname}) *getftype()* The result is a String, which is a description of the kind of file of the given file {fname}. @@ -2575,6 +3563,12 @@ getftype({fname}) *getftype()* systems that support it. On some systems only "dir" and "file" are returned. + Parameters: ~ + • {fname} (`string`) + + Return: ~ + (`'file'|'dir'|'link'|'bdev'|'cdev'|'socket'|'fifo'|'other'`) + getjumplist([{winnr} [, {tabnr}]]) *getjumplist()* Returns the |jumplist| for the specified window. @@ -2595,6 +3589,13 @@ getjumplist([{winnr} [, {tabnr}]]) *getjumplist()* filename filename if available lnum line number + Parameters: ~ + • {winnr} (`integer?`) + • {tabnr} (`integer?`) + + Return: ~ + (`vim.fn.getjumplist.ret`) + getline({lnum} [, {end}]) *getline()* Without {end} the result is a String, which is line {lnum} from the current buffer. Example: >vim @@ -2620,6 +3621,13 @@ getline({lnum} [, {end}]) *getline()* < To get lines from another buffer see |getbufline()| and |getbufoneline()| + Parameters: ~ + • {lnum} (`integer|string`) + • {end_} (`nil|false?`) + + Return: ~ + (`string`) + getloclist({nr} [, {what}]) *getloclist()* Returns a |List| with all the entries in the location list for window {nr}. {nr} can be the window number or the |window-ID|. @@ -2652,6 +3660,13 @@ getloclist({nr} [, {what}]) *getloclist()* echo getloclist(5, {'filewinid': 0}) < + Parameters: ~ + • {nr} (`integer`) + • {what} (`table?`) + + Return: ~ + (`any`) + getmarklist([{buf}]) *getmarklist()* Without the {buf} argument returns a |List| with information about all the global marks. |mark| @@ -2671,6 +3686,12 @@ getmarklist([{buf}]) *getmarklist()* Refer to |getpos()| for getting information about a specific mark. + Parameters: ~ + • {buf} (`integer??`) + + Return: ~ + (`vim.fn.getmarklist.ret.item[]`) + getmatches([{win}]) *getmatches()* Returns a |List| with all matches previously defined for the current window by |matchadd()| and the |:match| commands. @@ -2703,6 +3724,12 @@ getmatches([{win}]) *getmatches()* unlet m < + Parameters: ~ + • {win} (`integer?`) + + Return: ~ + (`any`) + getmousepos() *getmousepos()* Returns a |Dictionary| with the last known position of the mouse. This can be used in a mapping for a mouse click. The @@ -2734,14 +3761,45 @@ getmousepos() *getmousepos()* When using |getchar()| the Vim variables |v:mouse_lnum|, |v:mouse_col| and |v:mouse_winid| also provide these values. + Return: ~ + (`vim.fn.getmousepos.ret`) + getpid() *getpid()* Return a Number which is the process ID of the Vim process. This is a unique number, until Vim exits. + Return: ~ + (`integer`) + getpos({expr}) *getpos()* - Get the position for String {expr}. For possible values of - {expr} see |line()|. For getting the cursor position see - |getcurpos()|. + Get the position for String {expr}. + The accepted values for {expr} are: + . The cursor position. + $ The last line in the current buffer. + 'x Position of mark x (if the mark is not set, 0 is + returned for all values). + w0 First line visible in current window (one if the + display isn't updated, e.g. in silent Ex mode). + w$ Last line visible in current window (this is one + less than "w0" if no lines are visible). + v When not in Visual mode, returns the cursor + position. In Visual mode, returns the other end + of the Visual area. A good way to think about + this is that in Visual mode "v" and "." complement + each other. While "." refers to the cursor + position, "v" refers to where |v_o| would move the + cursor. As a result, you can use "v" and "." + together to work on all of a selection in + characterwise Visual mode. If the cursor is at + the end of a characterwise Visual area, "v" refers + to the start of the same Visual area. And if the + cursor is at the start of a characterwise Visual + area, "v" refers to the end of the same Visual + area. "v" differs from |'<| and |'>| in that it's + updated right away. + Note that a mark in another file can be used. The line number + then applies to another buffer. + The result is a |List| with four numbers: [bufnum, lnum, col, off] "bufnum" is zero, unless a mark like '0 or 'A is used, then it @@ -2752,20 +3810,31 @@ getpos({expr}) *getpos()* it is the offset in screen columns from the start of the character. E.g., a position within a <Tab> or after the last character. - Note that for '< and '> Visual mode matters: when it is "V" - (visual line mode) the column of '< is zero and the column of - '> is a large number equal to |v:maxcol|. + + For getting the cursor position see |getcurpos()|. The column number in the returned List is the byte position within the line. To get the character position in the line, use |getcharpos()|. + + Note that for '< and '> Visual mode matters: when it is "V" + (visual line mode) the column of '< is zero and the column of + '> is a large number equal to |v:maxcol|. A very large column number equal to |v:maxcol| can be returned, in which case it means "after the end of the line". If {expr} is invalid, returns a list with all zeros. + This can be used to save and restore the position of a mark: >vim let save_a_mark = getpos("'a") " ... call setpos("'a", save_a_mark) -< Also see |getcharpos()|, |getcurpos()| and |setpos()|. +< + Also see |getcharpos()|, |getcurpos()| and |setpos()|. + + Parameters: ~ + • {expr} (`string`) + + Return: ~ + (`integer[]`) getqflist([{what}]) *getqflist()* Returns a |List| with all the current quickfix errors. Each @@ -2871,6 +3940,12 @@ getqflist([{what}]) *getqflist()* echo getqflist({'lines' : ["F1:10:L10"]}) < + Parameters: ~ + • {what} (`table?`) + + Return: ~ + (`any`) + getreg([{regname} [, 1 [, {list}]]]) *getreg()* The result is a String, which is the contents of register {regname}. Example: >vim @@ -2894,6 +3969,13 @@ getreg([{regname} [, 1 [, {list}]]]) *getreg()* If {regname} is not specified, |v:register| is used. + Parameters: ~ + • {regname} (`string?`) + • {list} (`nil|false?`) + + Return: ~ + (`string`) + getreginfo([{regname}]) *getreginfo()* Returns detailed information about register {regname} as a Dictionary with the following entries: @@ -2918,6 +4000,12 @@ getreginfo([{regname}]) *getreginfo()* If {regname} is not specified, |v:register| is used. The returned Dictionary can be passed to |setreg()|. + Parameters: ~ + • {regname} (`string?`) + + Return: ~ + (`table`) + getregion({pos1}, {pos2} [, {opts}]) *getregion()* Returns the list of strings from {pos1} to {pos2} from a buffer. @@ -2930,14 +4018,14 @@ getregion({pos1}, {pos2} [, {opts}]) *getregion()* The optional argument {opts} is a Dict and supports the following items: - type Specify the region's selection type - (default: "v"): - "v" for |charwise| mode - "V" for |linewise| mode - "<CTRL-V>" for |blockwise-visual| mode + type Specify the region's selection type. + See |getregtype()| for possible values, + except that the width can be omitted + and an empty string cannot be used. + (default: "v") exclusive If |TRUE|, use exclusive selection - for the end position + for the end position. (default: follow 'selection') You can get the last selection type by |visualmode()|. @@ -2963,12 +4051,20 @@ getregion({pos1}, {pos2} [, {opts}]) *getregion()* difference if the buffer is displayed in a window with different 'virtualedit' or 'list' values. - Examples: > - :xnoremap <CR> + Examples: >vim + xnoremap <CR> \ <Cmd>echom getregion( \ getpos('v'), getpos('.'), #{ type: mode() })<CR> < + Parameters: ~ + • {pos1} (`table`) + • {pos2} (`table`) + • {opts} (`table?`) + + Return: ~ + (`string[]`) + getregionpos({pos1}, {pos2} [, {opts}]) *getregionpos()* Same as |getregion()|, but returns a list of positions describing the buffer text segments bound by {pos1} and @@ -3001,6 +4097,14 @@ getregionpos({pos1}, {pos2} [, {opts}]) *getregionpos()* value of 0 is used for both positions. (default: |FALSE|) + Parameters: ~ + • {pos1} (`table`) + • {pos2} (`table`) + • {opts} (`table?`) + + Return: ~ + (`integer[][][]`) + getregtype([{regname}]) *getregtype()* The result is a String, which is type of register {regname}. The value will be one of: @@ -3012,6 +4116,12 @@ getregtype([{regname}]) *getregtype()* The {regname} argument is a string. If {regname} is not specified, |v:register| is used. + Parameters: ~ + • {regname} (`string?`) + + Return: ~ + (`string`) + getscriptinfo([{opts}]) *getscriptinfo()* Returns a |List| with information about all the sourced Vim scripts in the order they were sourced, like what @@ -3049,6 +4159,12 @@ getscriptinfo([{opts}]) *getscriptinfo()* echo getscriptinfo({'sid': 15})[0].variables < + Parameters: ~ + • {opts} (`table?`) + + Return: ~ + (`vim.fn.getscriptinfo.ret[]`) + gettabinfo([{tabnr}]) *gettabinfo()* If {tabnr} is not specified, then information about all the tab pages is returned as a |List|. Each List item is a @@ -3062,6 +4178,12 @@ gettabinfo([{tabnr}]) *gettabinfo()* tabpage-local variables windows List of |window-ID|s in the tab page. + Parameters: ~ + • {tabnr} (`integer?`) + + Return: ~ + (`any`) + gettabvar({tabnr}, {varname} [, {def}]) *gettabvar()* Get the value of a tab-local variable {varname} in tab page {tabnr}. |t:var| @@ -3072,6 +4194,14 @@ gettabvar({tabnr}, {varname} [, {def}]) *gettabvar()* When the tab or variable doesn't exist {def} or an empty string is returned, there is no error message. + Parameters: ~ + • {tabnr} (`integer`) + • {varname} (`string`) + • {def} (`any?`) + + Return: ~ + (`any`) + gettabwinvar({tabnr}, {winnr}, {varname} [, {def}]) *gettabwinvar()* Get the value of window-local variable {varname} in window {winnr} in tab page {tabnr}. @@ -3099,6 +4229,15 @@ gettabwinvar({tabnr}, {winnr}, {varname} [, {def}]) *gettabwinvar()* gettabwinvar({tabnr}, {winnr}, '&') < + Parameters: ~ + • {tabnr} (`integer`) + • {winnr} (`integer`) + • {varname} (`string`) + • {def} (`any?`) + + Return: ~ + (`any`) + gettagstack([{winnr}]) *gettagstack()* The result is a Dict, which is the tag stack of window {winnr}. {winnr} can be the window number or the |window-ID|. @@ -3127,6 +4266,12 @@ gettagstack([{winnr}]) *gettagstack()* See |tagstack| for more information about the tag stack. + Parameters: ~ + • {winnr} (`integer?`) + + Return: ~ + (`any`) + gettext({text}) *gettext()* Translate String {text} if possible. This is mainly for use in the distributed Vim scripts. When @@ -3138,6 +4283,12 @@ gettext({text}) *gettext()* xgettext does not understand escaping in single quoted strings. + Parameters: ~ + • {text} (`string`) + + Return: ~ + (`any`) + getwininfo([{winid}]) *getwininfo()* Returns information about windows as a |List| with Dictionaries. @@ -3172,6 +4323,12 @@ getwininfo([{winid}]) *getwininfo()* winrow topmost screen line of the window; "row" from |win_screenpos()| + Parameters: ~ + • {winid} (`integer?`) + + Return: ~ + (`vim.fn.getwininfo.ret.item[]`) + getwinpos([{timeout}]) *getwinpos()* The result is a |List| with two numbers, the result of |getwinposx()| and |getwinposy()| combined: @@ -3193,24 +4350,44 @@ getwinpos([{timeout}]) *getwinpos()* endwhile < + Parameters: ~ + • {timeout} (`integer?`) + + Return: ~ + (`any`) + getwinposx() *getwinposx()* The result is a Number, which is the X coordinate in pixels of the left hand side of the GUI Vim window. The result will be -1 if the information is not available. The value can be used with `:winpos`. + Return: ~ + (`integer`) + getwinposy() *getwinposy()* The result is a Number, which is the Y coordinate in pixels of the top of the GUI Vim window. The result will be -1 if the information is not available. The value can be used with `:winpos`. + Return: ~ + (`integer`) + getwinvar({winnr}, {varname} [, {def}]) *getwinvar()* Like |gettabwinvar()| for the current tabpage. Examples: >vim let list_is_on = getwinvar(2, '&list') echo "myvar = " .. getwinvar(1, 'myvar') + Parameters: ~ + • {winnr} (`integer`) + • {varname} (`string`) + • {def} (`any?`) + + Return: ~ + (`any`) + glob({expr} [, {nosuf} [, {list} [, {alllinks}]]]) *glob()* Expand the file wildcards in {expr}. See |wildcards| for the use of special characters. @@ -3247,6 +4424,15 @@ glob({expr} [, {nosuf} [, {list} [, {alllinks}]]]) *glob()* See |expand()| for expanding special Vim variables. See |system()| for getting the raw output of an external command. + Parameters: ~ + • {expr} (`string`) + • {nosuf} (`boolean?`) + • {list} (`boolean?`) + • {alllinks} (`boolean?`) + + Return: ~ + (`any`) + glob2regpat({string}) *glob2regpat()* Convert a file pattern, as used by glob(), into a search pattern. The result can be used to match with a string that @@ -3263,6 +4449,12 @@ glob2regpat({string}) *glob2regpat()* Note that the result depends on the system. On MS-Windows a backslash usually means a path separator. + Parameters: ~ + • {string} (`string`) + + Return: ~ + (`any`) + globpath({path}, {expr} [, {nosuf} [, {list} [, {allinks}]]]) *globpath()* Perform glob() for String {expr} on all directories in {path} and concatenate the results. Example: >vim @@ -3298,6 +4490,16 @@ globpath({path}, {expr} [, {nosuf} [, {list} [, {allinks}]]]) *globpath()* < Upwards search and limiting the depth of "**" is not supported, thus using 'path' will not always work properly. + Parameters: ~ + • {path} (`string`) + • {expr} (`string`) + • {nosuf} (`boolean?`) + • {list} (`boolean?`) + • {allinks} (`boolean?`) + + Return: ~ + (`any`) + has({feature}) *has()* Returns 1 if {feature} is supported, 0 otherwise. The {feature} argument is a feature name like "nvim-0.2.1" or @@ -3366,11 +4568,24 @@ has({feature}) *has()* endif < + Parameters: ~ + • {feature} (`string`) + + Return: ~ + (`0|1`) + has_key({dict}, {key}) *has_key()* The result is a Number, which is TRUE if |Dictionary| {dict} has an entry with key {key}. FALSE otherwise. The {key} argument is a string. + Parameters: ~ + • {dict} (`table`) + • {key} (`string`) + + Return: ~ + (`0|1`) + haslocaldir([{winnr} [, {tabnr}]]) *haslocaldir()* The result is a Number, which is 1 when the window has set a local path via |:lcd| or when {winnr} is -1 and the tabpage @@ -3388,6 +4603,13 @@ haslocaldir([{winnr} [, {tabnr}]]) *haslocaldir()* If {winnr} is -1 it is ignored, only the tab is resolved. Throw error if the arguments are invalid. |E5000| |E5001| |E5002| + Parameters: ~ + • {winnr} (`integer?`) + • {tabnr} (`integer?`) + + Return: ~ + (`0|1`) + hasmapto({what} [, {mode} [, {abbr}]]) *hasmapto()* The result is a Number, which is TRUE if there is a mapping that contains {what} in somewhere in the rhs (what it is @@ -3419,6 +4641,14 @@ hasmapto({what} [, {mode} [, {abbr}]]) *hasmapto()* < This installs the mapping to "\ABCdoit" only if there isn't already a mapping to "\ABCdoit". + Parameters: ~ + • {what} (`any`) + • {mode} (`string?`) + • {abbr} (`boolean?`) + + Return: ~ + (`0|1`) + histadd({history}, {item}) *histadd()* Add the String {item} to the history {history} which can be one of: *hist-names* @@ -3440,6 +4670,13 @@ histadd({history}, {item}) *histadd()* let date=input("Enter date: ") < This function is not available in the |sandbox|. + Parameters: ~ + • {history} (`string`) + • {item} (`any`) + + Return: ~ + (`0|1`) + histdel({history} [, {item}]) *histdel()* Clear {history}, i.e. delete all its entries. See |hist-names| for the possible values of {history}. @@ -3473,6 +4710,13 @@ histdel({history} [, {item}]) *histdel()* let @/ = histget("search", -1) < + Parameters: ~ + • {history} (`string`) + • {item} (`any?`) + + Return: ~ + (`0|1`) + histget({history} [, {index}]) *histget()* The result is a String, the entry with Number {index} from {history}. See |hist-names| for the possible values of @@ -3489,6 +4733,13 @@ histget({history} [, {index}]) *histget()* command -nargs=1 H execute histget("cmd", 0+<args>) < + Parameters: ~ + • {history} (`string`) + • {index} (`integer|string?`) + + Return: ~ + (`string`) + histnr({history}) *histnr()* The result is the Number of the current entry in {history}. See |hist-names| for the possible values of {history}. @@ -3496,6 +4747,13 @@ histnr({history}) *histnr()* Example: >vim let inp_index = histnr("expr") +< + + Parameters: ~ + • {history} (`string`) + + Return: ~ + (`integer`) hlID({name}) *hlID()* The result is a Number, which is the ID of the highlight group @@ -3507,6 +4765,12 @@ hlID({name}) *hlID()* echo synIDattr(synIDtrans(hlID("Comment")), "bg") < + Parameters: ~ + • {name} (`string`) + + Return: ~ + (`integer`) + hlexists({name}) *hlexists()* The result is a Number, which is TRUE if a highlight group called {name} exists. This is when the group has been @@ -3514,11 +4778,20 @@ hlexists({name}) *hlexists()* been defined for it, it may also have been used for a syntax item. + Parameters: ~ + • {name} (`string`) + + Return: ~ + (`0|1`) + hostname() *hostname()* The result is a String, which is the name of the machine on which Vim is currently running. Machine names greater than 256 characters long are truncated. + Return: ~ + (`string`) + iconv({string}, {from}, {to}) *iconv()* The result is a String, which is the text {string} converted from encoding {from} to encoding {to}. @@ -3531,6 +4804,14 @@ iconv({string}, {from}, {to}) *iconv()* from/to UCS-2 is automatically changed to use UTF-8. You cannot use UCS-2 in a string anyway, because of the NUL bytes. + Parameters: ~ + • {string} (`string`) + • {from} (`string`) + • {to} (`string`) + + Return: ~ + (`any`) + id({expr}) *id()* Returns a |String| which is a unique identifier of the container type (|List|, |Dict|, |Blob| and |Partial|). It is @@ -3539,7 +4820,7 @@ id({expr}) *id()* Note that `v:_null_string`, `v:_null_list`, `v:_null_dict` and `v:_null_blob` have the same `id()` with different types because they are internally represented as NULL pointers. - `id()` returns a hexadecimal representanion of the pointers to + `id()` returns a hexadecimal representation of the pointers to the containers (i.e. like `0x994a40`), same as `printf("%p", {expr})`, but it is advised against counting on the exact format of the return value. @@ -3548,6 +4829,12 @@ id({expr}) *id()* will not be equal to some other `id()`: new containers may reuse identifiers of the garbage-collected ones. + Parameters: ~ + • {expr} (`any`) + + Return: ~ + (`any`) + indent({lnum}) *indent()* The result is a Number, which is indent of line {lnum} in the current buffer. The indent is counted in spaces, the value @@ -3555,6 +4842,12 @@ indent({lnum}) *indent()* |getline()|. When {lnum} is invalid -1 is returned. + Parameters: ~ + • {lnum} (`integer|string`) + + Return: ~ + (`integer`) + index({object}, {expr} [, {start} [, {ic}]]) *index()* Find {expr} in {object} and return its index. See |indexof()| for using a lambda to select the item. @@ -3581,6 +4874,16 @@ index({object}, {expr} [, {start} [, {ic}]]) *index()* if index(numbers, 123) >= 0 " ... endif +< + + Parameters: ~ + • {object} (`any`) + • {expr} (`any`) + • {start} (`integer?`) + • {ic} (`boolean?`) + + Return: ~ + (`any`) indexof({object}, {expr} [, {opts}]) *indexof()* Returns the index of an item in {object} where {expr} is @@ -3619,9 +4922,26 @@ indexof({object}, {expr} [, {opts}]) *indexof()* echo indexof(l, "v:val.n == 20") echo indexof(l, {i, v -> v.n == 30}) echo indexof(l, "v:val.n == 20", #{startidx: 1}) +< + + Parameters: ~ + • {object} (`any`) + • {expr} (`any`) + • {opts} (`table?`) + + Return: ~ + (`any`) input({prompt} [, {text} [, {completion}]]) *input()* + Parameters: ~ + • {prompt} (`string`) + • {text} (`string?`) + • {completion} (`string?`) + + Return: ~ + (`any`) + input({opts}) The result is a String, which is whatever the user typed on the command-line. The {prompt} argument is either a prompt @@ -3731,6 +5051,13 @@ input({opts}) let g:Foo = input("enter search pattern: ") call inputrestore() endfunction +< + + Parameters: ~ + • {opts} (`table`) + + Return: ~ + (`any`) inputlist({textlist}) *inputlist()* {textlist} must be a |List| of strings. This |List| is @@ -3749,12 +5076,21 @@ inputlist({textlist}) *inputlist()* let color = inputlist(['Select color:', '1. red', \ '2. green', '3. blue']) + Parameters: ~ + • {textlist} (`string[]`) + + Return: ~ + (`any`) + inputrestore() *inputrestore()* Restore typeahead that was saved with a previous |inputsave()|. Should be called the same number of times inputsave() is called. Calling it more often is harmless though. Returns TRUE when there is nothing to restore, FALSE otherwise. + Return: ~ + (`any`) + inputsave() *inputsave()* Preserve typeahead (also from mappings) and clear it, so that a following prompt gets input from the user. Should be @@ -3763,6 +5099,9 @@ inputsave() *inputsave()* many inputrestore() calls. Returns TRUE when out of memory, FALSE otherwise. + Return: ~ + (`any`) + inputsecret({prompt} [, {text}]) *inputsecret()* This function acts much like the |input()| function with but two exceptions: @@ -3774,6 +5113,13 @@ inputsecret({prompt} [, {text}]) *inputsecret()* typed on the command-line in response to the issued prompt. NOTE: Command-line completion is not supported. + Parameters: ~ + • {prompt} (`string`) + • {text} (`string?`) + + Return: ~ + (`any`) + insert({object}, {item} [, {idx}]) *insert()* When {object} is a |List| or a |Blob| insert {item} at the start of it. @@ -3791,6 +5137,14 @@ insert({object}, {item} [, {idx}]) *insert()* Note that when {item} is a |List| it is inserted as a single item. Use |extend()| to concatenate |Lists|. + Parameters: ~ + • {object} (`any`) + • {item} (`any`) + • {idx} (`integer?`) + + Return: ~ + (`any`) + interrupt() *interrupt()* Interrupt script execution. It works more or less like the user typing CTRL-C, most commands won't execute and control @@ -3805,18 +5159,54 @@ interrupt() *interrupt()* au BufWritePre * call s:check_typoname(expand('<amatch>')) < + Return: ~ + (`any`) + invert({expr}) *invert()* Bitwise invert. The argument is converted to a number. A List, Dict or Float argument causes an error. Example: >vim let bits = invert(bits) < + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`any`) + +isabsolutepath({path}) *isabsolutepath()* + The result is a Number, which is |TRUE| when {path} is an + absolute path. + On Unix, a path is considered absolute when it starts with '/'. + On MS-Windows, it is considered absolute when it starts with an + optional drive prefix and is followed by a '\' or '/'. UNC paths + are always absolute. + Example: >vim + echo isabsolutepath('/usr/share/') " 1 + echo isabsolutepath('./foobar') " 0 + echo isabsolutepath('C:\Windows') " 1 + echo isabsolutepath('foobar') " 0 + echo isabsolutepath('\\remote\file') " 1 +< + + Parameters: ~ + • {path} (`string`) + + Return: ~ + (`0|1`) + isdirectory({directory}) *isdirectory()* The result is a Number, which is |TRUE| when a directory with the name {directory} exists. If {directory} doesn't exist, or isn't a directory, the result is |FALSE|. {directory} is any expression, which is used as a String. + Parameters: ~ + • {directory} (`string`) + + Return: ~ + (`0|1`) + isinf({expr}) *isinf()* Return 1 if {expr} is a positive infinity, or -1 a negative infinity, otherwise 0. >vim @@ -3825,6 +5215,12 @@ isinf({expr}) *isinf()* echo isinf(-1.0 / 0.0) < -1 + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`1|0|-1`) + islocked({expr}) *islocked()* *E786* The result is a Number, which is |TRUE| when {expr} is the name of a locked variable. @@ -3839,11 +5235,23 @@ islocked({expr}) *islocked()* *E78 < When {expr} is a variable that does not exist you get an error message. Use |exists()| to check for existence. + Parameters: ~ + • {expr} (`any`) + + Return: ~ + (`0|1`) + isnan({expr}) *isnan()* Return |TRUE| if {expr} is a float with value NaN. >vim echo isnan(0.0 / 0.0) < 1 + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`0|1`) + items({dict}) *items()* Return a |List| with all the key-value pairs of {dict}. Each |List| item is a list with two items: the key of a {dict} @@ -3853,15 +5261,39 @@ items({dict}) *items()* for [key, value] in items(mydict) echo key .. ': ' .. value endfor +< + A List or a String argument is also supported. In these + cases, items() returns a List with the index and the value at + the index. + + Parameters: ~ + • {dict} (`any`) + + Return: ~ + (`any`) jobpid({job}) *jobpid()* Return the PID (process id) of |job-id| {job}. + Parameters: ~ + • {job} (`integer`) + + Return: ~ + (`integer`) + jobresize({job}, {width}, {height}) *jobresize()* Resize the pseudo terminal window of |job-id| {job} to {width} columns and {height} rows. Fails if the job was not started with `"pty":v:true`. + Parameters: ~ + • {job} (`integer`) + • {width} (`integer`) + • {height} (`integer`) + + Return: ~ + (`any`) + jobstart({cmd} [, {opts}]) *jobstart()* Note: Prefer |vim.system()| in Lua (unless using the `pty` option). @@ -3948,6 +5380,13 @@ jobstart({cmd} [, {opts}]) *jobstart()* - -1 if {cmd}[0] is not executable. See also |job-control|, |channel|, |msgpack-rpc|. + Parameters: ~ + • {cmd} (`string|string[]`) + • {opts} (`table?`) + + Return: ~ + (`any`) + jobstop({id}) *jobstop()* Stop |job-id| {id} by sending SIGTERM to the job process. If the process does not terminate after a timeout then SIGKILL @@ -3958,6 +5397,12 @@ jobstop({id}) *jobstop()* Returns 1 for valid job id, 0 for invalid id, including jobs have exited or stopped. + Parameters: ~ + • {id} (`integer`) + + Return: ~ + (`any`) + jobwait({jobs} [, {timeout}]) *jobwait()* Waits for jobs and their |on_exit| handlers to complete. @@ -3979,6 +5424,13 @@ jobwait({jobs} [, {timeout}]) *jobwait()* -2 if the job was interrupted (by |CTRL-C|) -3 if the job-id is invalid + Parameters: ~ + • {jobs} (`integer[]`) + • {timeout} (`integer?`) + + Return: ~ + (`any`) + join({list} [, {sep}]) *join()* Join the items in {list} together into one String. When {sep} is specified it is put in between the items. If @@ -3990,6 +5442,13 @@ join({list} [, {sep}]) *join()* converted into a string like with |string()|. The opposite function is |split()|. + Parameters: ~ + • {list} (`any[]`) + • {sep} (`string?`) + + Return: ~ + (`any`) + json_decode({expr}) *json_decode()* Convert {expr} from JSON object. Accepts |readfile()|-style list as the input, as well as regular string. May output any @@ -4005,6 +5464,12 @@ json_decode({expr}) *json_decode()* recommended and the only one required to be supported. Non-UTF-8 characters are an error. + Parameters: ~ + • {expr} (`any`) + + Return: ~ + (`any`) + json_encode({expr}) *json_encode()* Convert {expr} into a JSON string. Accepts |msgpack-special-dict| as the input. Will not convert @@ -4017,10 +5482,22 @@ json_encode({expr}) *json_encode()* or special escapes like "\t", other are dumped as-is. |Blob|s are converted to arrays of the individual bytes. + Parameters: ~ + • {expr} (`any`) + + Return: ~ + (`any`) + keys({dict}) *keys()* Return a |List| with all the keys of {dict}. The |List| is in arbitrary order. Also see |items()| and |values()|. + Parameters: ~ + • {dict} (`table`) + + Return: ~ + (`any`) + keytrans({string}) *keytrans()* Turn the internal byte representation of keys into a form that can be used for |:map|. E.g. >vim @@ -4028,6 +5505,12 @@ keytrans({string}) *keytrans()* echo keytrans(xx) < <C-Home> + Parameters: ~ + • {string} (`string`) + + Return: ~ + (`any`) + len({expr}) *len()* *E701* The result is a Number, which is the length of the argument. When {expr} is a String or a Number the length in bytes is @@ -4039,6 +5522,12 @@ len({expr}) *len()* *E70 |Dictionary| is returned. Otherwise an error is given and returns zero. + Parameters: ~ + • {expr} (`any`) + + Return: ~ + (`any`) + libcall({libname}, {funcname}, {argument}) *libcall()* *E364* *E368* Call function {funcname} in the run-time library {libname} with single argument {argument}. @@ -4081,6 +5570,14 @@ libcall({libname}, {funcname}, {argument}) *libcall()* *E364* *E Examples: >vim echo libcall("libc.so", "getenv", "HOME") + Parameters: ~ + • {libname} (`string`) + • {funcname} (`string`) + • {argument} (`any`) + + Return: ~ + (`any`) + libcallnr({libname}, {funcname}, {argument}) *libcallnr()* Just like |libcall()|, but used for a function that returns an int instead of a string. @@ -4090,29 +5587,25 @@ libcallnr({libname}, {funcname}, {argument}) *libcallnr()* call libcallnr("libc.so", "sleep", 10) < + Parameters: ~ + • {libname} (`string`) + • {funcname} (`string`) + • {argument} (`any`) + + Return: ~ + (`any`) + line({expr} [, {winid}]) *line()* - The result is a Number, which is the line number of the file - position given with {expr}. The {expr} argument is a string. - The accepted positions are: - . the cursor position - $ the last line in the current buffer - 'x position of mark x (if the mark is not set, 0 is - returned) - w0 first line visible in current window (one if the - display isn't updated, e.g. in silent Ex mode) - w$ last line visible in current window (this is one - less than "w0" if no lines are visible) - v In Visual mode: the start of the Visual area (the - cursor is the end). When not in Visual mode - returns the cursor position. Differs from |'<| in - that it's updated right away. - Note that a mark in another file can be used. The line number - then applies to another buffer. + See |getpos()| for accepted positions. + To get the column number use |col()|. To get both use |getpos()|. + With the optional {winid} argument the values are obtained for that window instead of the current window. + Returns 0 for invalid values of {expr} and {winid}. + Examples: >vim echo line(".") " line number of the cursor echo line(".", winid) " idem, in window "winid" @@ -4122,6 +5615,13 @@ line({expr} [, {winid}]) *line()* To jump to the last known position when opening a file see |last-position-jump|. + Parameters: ~ + • {expr} (`string|integer[]`) + • {winid} (`integer?`) + + Return: ~ + (`integer`) + line2byte({lnum}) *line2byte()* Return the byte count from the start of the buffer for line {lnum}. This includes the end-of-line character, depending on @@ -4135,6 +5635,12 @@ line2byte({lnum}) *line2byte()* |getline()|. When {lnum} is invalid -1 is returned. Also see |byte2line()|, |go| and |:goto|. + Parameters: ~ + • {lnum} (`integer`) + + Return: ~ + (`integer`) + lispindent({lnum}) *lispindent()* Get the amount of indent for line {lnum} according the lisp indenting rules, as with 'lisp'. @@ -4142,6 +5648,12 @@ lispindent({lnum}) *lispindent()* relevant. {lnum} is used just like in |getline()|. When {lnum} is invalid, -1 is returned. + Parameters: ~ + • {lnum} (`integer`) + + Return: ~ + (`any`) + list2blob({list}) *list2blob()* Return a Blob concatenating all the number values in {list}. Examples: >vim @@ -4152,6 +5664,12 @@ list2blob({list}) *list2blob()* |blob2list()| does the opposite. + Parameters: ~ + • {list} (`any[]`) + + Return: ~ + (`any`) + list2str({list} [, {utf8}]) *list2str()* Convert each number in {list} to a character string can concatenate them all. Examples: >vim @@ -4168,10 +5686,20 @@ list2str({list} [, {utf8}]) *list2str()* < Returns an empty string on error. + Parameters: ~ + • {list} (`any[]`) + • {utf8} (`boolean?`) + + Return: ~ + (`any`) + localtime() *localtime()* Return the current time, measured as seconds since 1st Jan 1970. See also |strftime()|, |strptime()| and |getftime()|. + Return: ~ + (`any`) + log({expr}) *log()* Return the natural logarithm (base e) of {expr} as a |Float|. {expr} must evaluate to a |Float| or a |Number| in the range @@ -4183,6 +5711,12 @@ log({expr}) *log()* echo log(exp(5)) < 5.0 + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`any`) + log10({expr}) *log10()* Return the logarithm of Float {expr} to base 10 as a |Float|. {expr} must evaluate to a |Float| or a |Number|. @@ -4193,10 +5727,23 @@ log10({expr}) *log10()* echo log10(0.01) < -2.0 + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`any`) + luaeval({expr} [, {expr}]) *luaeval()* Evaluate Lua expression {expr} and return its result converted to Vim data structures. See |lua-eval| for more details. + Parameters: ~ + • {expr} (`string`) + • {expr1} (`any[]?`) + + Return: ~ + (`any`) + map({expr1}, {expr2}) *map()* {expr1} must be a |List|, |String|, |Blob| or |Dictionary|. When {expr1} is a |List|| or |Dictionary|, replace each @@ -4251,6 +5798,13 @@ map({expr1}, {expr2}) *map()* When {expr2} is a Funcref errors inside a function are ignored, unless it was defined with the "abort" flag. + Parameters: ~ + • {expr1} (`string|table|any[]`) + • {expr2} (`string|function`) + + Return: ~ + (`any`) + maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()* When {dict} is omitted or zero: Return the rhs of mapping {name} in mode {mode}. The returned String has special @@ -4290,6 +5844,7 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()* "lhsrawalt" The {lhs} of the mapping as raw bytes, alternate form, only present when it differs from "lhsraw" "rhs" The {rhs} of the mapping as typed. + "callback" Lua function, if RHS was defined as such. "silent" 1 for a |:map-silent| mapping, else 0. "noremap" 1 if the {rhs} of the mapping is not remappable. "script" 1 if mapping was defined with <script>. @@ -4322,6 +5877,16 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()* This function can be used to map a key even when it's already mapped, and have it do the original mapping too. Sketch: >vim exe 'nnoremap <Tab> ==' .. maparg('<Tab>', 'n') +< + + Parameters: ~ + • {name} (`string`) + • {mode} (`string?`) + • {abbr} (`boolean?`) + • {dict} (`false?`) + + Return: ~ + (`string`) mapcheck({name} [, {mode} [, {abbr}]]) *mapcheck()* Check if there is a mapping that matches with {name} in mode @@ -4356,6 +5921,14 @@ mapcheck({name} [, {mode} [, {abbr}]]) *mapcheck()* < This avoids adding the "_vv" mapping when there already is a mapping for "_v" or for "_vvv". + Parameters: ~ + • {name} (`string`) + • {mode} (`string?`) + • {abbr} (`boolean?`) + + Return: ~ + (`any`) + maplist([{abbr}]) *maplist()* Returns a |List| of all mappings. Each List item is a |Dict|, the same as what is returned by |maparg()|, see @@ -4386,6 +5959,13 @@ maplist([{abbr}]) *maplist()* \ {_, m -> m.lhs == 'xyzzy'})[0].mode_bits ounmap xyzzy echo printf("Operator-pending mode bit: 0x%x", op_bit) +< + + Parameters: ~ + • {abbr} (`0|1?`) + + Return: ~ + (`table[]`) mapnew({expr1}, {expr2}) *mapnew()* Like |map()| but instead of replacing items in {expr1} a new @@ -4393,6 +5973,13 @@ mapnew({expr1}, {expr2}) *mapnew()* unchanged. Items can still be changed by {expr2}, if you don't want that use |deepcopy()| first. + Parameters: ~ + • {expr1} (`any`) + • {expr2} (`any`) + + Return: ~ + (`any`) + mapset({mode}, {abbr}, {dict}) *mapset()* mapset({dict}) Restore a mapping from a dictionary, possibly returned by @@ -4429,6 +6016,13 @@ mapset({dict}) for d in save_maps call mapset(d) endfor +< + + Parameters: ~ + • {dict} (`boolean`) + + Return: ~ + (`any`) match({expr}, {pat} [, {start} [, {count}]]) *match()* When {expr} is a |List| then this returns the index of the @@ -4493,6 +6087,15 @@ match({expr}, {pat} [, {start} [, {count}]]) *match()* zero matches at the start instead of a number of matches further down in the text. + Parameters: ~ + • {expr} (`string|any[]`) + • {pat} (`string`) + • {start} (`integer?`) + • {count} (`integer?`) + + Return: ~ + (`any`) + *matchadd()* *E798* *E799* *E801* *E957* matchadd({group}, {pattern} [, {priority} [, {id} [, {dict}]]]) Defines a pattern to be highlighted in the current window (a @@ -4552,13 +6155,23 @@ matchadd({group}, {pattern} [, {priority} [, {id} [, {dict}]]]) available from |getmatches()|. All matches can be deleted in one operation by |clearmatches()|. + Parameters: ~ + • {group} (`integer|string`) + • {pattern} (`string`) + • {priority} (`integer?`) + • {id} (`integer?`) + • {dict} (`string?`) + + Return: ~ + (`any`) + matchaddpos({group}, {pos} [, {priority} [, {id} [, {dict}]]]) *matchaddpos()* Same as |matchadd()|, but requires a list of positions {pos} instead of a pattern. This command is faster than |matchadd()| - because it does not require to handle regular expressions and - sets buffer line boundaries to redraw screen. It is supposed - to be used when fast match additions and deletions are - required, for example to highlight matching parentheses. + because it does not handle regular expressions and it sets + buffer line boundaries to redraw screen. It is supposed to be + used when fast match additions and deletions are required, for + example to highlight matching parentheses. *E5030* *E5031* {pos} is a list of positions. Each position can be one of these: @@ -4589,6 +6202,16 @@ matchaddpos({group}, {pos} [, {priority} [, {id} [, {dict}]]]) *matchaddpos()* < Matches added by |matchaddpos()| are returned by |getmatches()|. + Parameters: ~ + • {group} (`integer|string`) + • {pos} (`any[]`) + • {priority} (`integer?`) + • {id} (`integer?`) + • {dict} (`string?`) + + Return: ~ + (`any`) + matcharg({nr}) *matcharg()* Selects the {nr} match item, as set with a |:match|, |:2match| or |:3match| command. @@ -4601,6 +6224,12 @@ matcharg({nr}) *matcharg()* Highlighting matches using the |:match| commands are limited to three matches. |matchadd()| does not have this limitation. + Parameters: ~ + • {nr} (`integer`) + + Return: ~ + (`any`) + matchbufline({buf}, {pat}, {lnum}, {end}, [, {dict}]) *matchbufline()* Returns the |List| of matches in lines from {lnum} to {end} in buffer {buf} where {pat} matches. @@ -4629,22 +6258,32 @@ matchbufline({buf}, {pat}, {lnum}, {end}, [, {dict}]) *matchbufline()* Examples: >vim " Assuming line 3 in buffer 5 contains "a" - :echo matchbufline(5, '\<\k\+\>', 3, 3) - [{'lnum': 3, 'byteidx': 0, 'text': 'a'}] + echo matchbufline(5, '\<\k\+\>', 3, 3) +< `[{'lnum': 3, 'byteidx': 0, 'text': 'a'}]` >vim " Assuming line 4 in buffer 10 contains "tik tok" - :echo matchbufline(10, '\<\k\+\>', 1, 4) - [{'lnum': 4, 'byteidx': 0, 'text': 'tik'}, {'lnum': 4, 'byteidx': 4, 'text': 'tok'}] -< + echo matchbufline(10, '\<\k\+\>', 1, 4) +< `[{'lnum': 4, 'byteidx': 0, 'text': 'tik'}, {'lnum': 4, 'byteidx': 4, 'text': 'tok'}]` + If {submatch} is present and is v:true, then submatches like "\1", "\2", etc. are also returned. Example: >vim " Assuming line 2 in buffer 2 contains "acd" - :echo matchbufline(2, '\(a\)\?\(b\)\?\(c\)\?\(.*\)', 2, 2 + echo matchbufline(2, '\(a\)\?\(b\)\?\(c\)\?\(.*\)', 2, 2 \ {'submatches': v:true}) - [{'lnum': 2, 'byteidx': 0, 'text': 'acd', 'submatches': ['a', '', 'c', 'd', '', '', '', '', '']}] -< The "submatches" List always contains 9 items. If a submatch +< `[{'lnum': 2, 'byteidx': 0, 'text': 'acd', 'submatches': ['a', '', 'c', 'd', '', '', '', '', '']}]` + The "submatches" List always contains 9 items. If a submatch is not found, then an empty string is returned for that submatch. + Parameters: ~ + • {buf} (`string|integer`) + • {pat} (`string`) + • {lnum} (`string|integer`) + • {end_} (`string|integer`) + • {dict} (`table?`) + + Return: ~ + (`any`) + matchdelete({id} [, {win}]) *matchdelete()* *E802* *E803* Deletes a match with ID {id} previously defined by |matchadd()| or one of the |:match| commands. Returns 0 if successful, @@ -4653,6 +6292,13 @@ matchdelete({id} [, {win}]) *matchdelete()* *E802* *E If {win} is specified, use the window with this number or window ID instead of the current window. + Parameters: ~ + • {id} (`integer`) + • {win} (`integer?`) + + Return: ~ + (`any`) + matchend({expr}, {pat} [, {start} [, {count}]]) *matchend()* Same as |match()|, but return the index of first character after the match. Example: >vim @@ -4672,6 +6318,15 @@ matchend({expr}, {pat} [, {start} [, {count}]]) *matchend()* < result is "-1". When {expr} is a |List| the result is equal to |match()|. + Parameters: ~ + • {expr} (`any`) + • {pat} (`string`) + • {start} (`integer?`) + • {count} (`integer?`) + + Return: ~ + (`any`) + matchfuzzy({list}, {str} [, {dict}]) *matchfuzzy()* If {list} is a list of strings, then returns a |List| with all the strings in {list} that fuzzy match {str}. The strings in @@ -4735,6 +6390,14 @@ matchfuzzy({list}, {str} [, {dict}]) *matchfuzzy()* \ {'matchseq': 1}) < results in `['two one']`. + Parameters: ~ + • {list} (`any[]`) + • {str} (`string`) + • {dict} (`string?`) + + Return: ~ + (`any`) + matchfuzzypos({list}, {str} [, {dict}]) *matchfuzzypos()* Same as |matchfuzzy()|, but returns the list of matched strings, the list of character positions where characters @@ -4757,6 +6420,14 @@ matchfuzzypos({list}, {str} [, {dict}]) *matchfuzzypos()* \ ->matchfuzzypos('ll', {'key' : 'text'}) < results in `[[{"id": 10, "text": "hello"}], [[2, 3]], [127]]` + Parameters: ~ + • {list} (`any[]`) + • {str} (`string`) + • {dict} (`string?`) + + Return: ~ + (`any`) + matchlist({expr}, {pat} [, {start} [, {count}]]) *matchlist()* Same as |match()|, but return a |List|. The first item in the list is the matched string, same as what matchstr() would @@ -4769,6 +6440,15 @@ matchlist({expr}, {pat} [, {start} [, {count}]]) *matchlist()* You can pass in a List, but that is not very useful. + Parameters: ~ + • {expr} (`any`) + • {pat} (`string`) + • {start} (`integer?`) + • {count} (`integer?`) + + Return: ~ + (`any`) + matchstr({expr}, {pat} [, {start} [, {count}]]) *matchstr()* Same as |match()|, but return the matched string. Example: >vim echo matchstr("testing", "ing") @@ -4782,6 +6462,15 @@ matchstr({expr}, {pat} [, {start} [, {count}]]) *matchstr()* When {expr} is a |List| then the matching item is returned. The type isn't changed, it's not necessarily a String. + Parameters: ~ + • {expr} (`any`) + • {pat} (`string`) + • {start} (`integer?`) + • {count} (`integer?`) + + Return: ~ + (`any`) + matchstrlist({list}, {pat} [, {dict}]) *matchstrlist()* Returns the |List| of matches in {list} where {pat} matches. {list} is a |List| of strings. {pat} is matched against each @@ -4801,20 +6490,28 @@ matchstrlist({list}, {pat} [, {dict}]) *matchstrlist()* option settings on the pattern. Example: >vim - :echo matchstrlist(['tik tok'], '\<\k\+\>') - [{'idx': 0, 'byteidx': 0, 'text': 'tik'}, {'idx': 0, 'byteidx': 4, 'text': 'tok'}] - :echo matchstrlist(['a', 'b'], '\<\k\+\>') - [{'idx': 0, 'byteidx': 0, 'text': 'a'}, {'idx': 1, 'byteidx': 0, 'text': 'b'}] -< + echo matchstrlist(['tik tok'], '\<\k\+\>') +< `[{'idx': 0, 'byteidx': 0, 'text': 'tik'}, {'idx': 0, 'byteidx': 4, 'text': 'tok'}]` >vim + echo matchstrlist(['a', 'b'], '\<\k\+\>') +< `[{'idx': 0, 'byteidx': 0, 'text': 'a'}, {'idx': 1, 'byteidx': 0, 'text': 'b'}]` + If "submatches" is present and is v:true, then submatches like "\1", "\2", etc. are also returned. Example: >vim - :echo matchstrlist(['acd'], '\(a\)\?\(b\)\?\(c\)\?\(.*\)', + echo matchstrlist(['acd'], '\(a\)\?\(b\)\?\(c\)\?\(.*\)', \ #{submatches: v:true}) - [{'idx': 0, 'byteidx': 0, 'text': 'acd', 'submatches': ['a', '', 'c', 'd', '', '', '', '', '']}] -< The "submatches" List always contains 9 items. If a submatch +< `[{'idx': 0, 'byteidx': 0, 'text': 'acd', 'submatches': ['a', '', 'c', 'd', '', '', '', '', '']}]` + The "submatches" List always contains 9 items. If a submatch is not found, then an empty string is returned for that submatch. + Parameters: ~ + • {list} (`string[]`) + • {pat} (`string`) + • {dict} (`table?`) + + Return: ~ + (`any`) + matchstrpos({expr}, {pat} [, {start} [, {count}]]) *matchstrpos()* Same as |matchstr()|, but return the matched string, the start position and the end position of the match. Example: >vim @@ -4833,6 +6530,15 @@ matchstrpos({expr}, {pat} [, {start} [, {count}]]) *matchstrpos()* < result is ["x", 1, 2, 3]. The type isn't changed, it's not necessarily a String. + Parameters: ~ + • {expr} (`any`) + • {pat} (`string`) + • {start} (`integer?`) + • {count} (`integer?`) + + Return: ~ + (`any`) + max({expr}) *max()* Return the maximum value of all items in {expr}. Example: >vim echo max([apples, pears, oranges]) @@ -4843,6 +6549,12 @@ max({expr}) *max()* items in {expr} cannot be used as a Number this results in an error. An empty |List| or |Dictionary| results in zero. + Parameters: ~ + • {expr} (`any`) + + Return: ~ + (`any`) + menu_get({path} [, {modes}]) *menu_get()* Returns a |List| of |Dictionaries| describing |menus| (defined by |:menu|, |:amenu|, …), including |hidden-menus|. @@ -4889,6 +6601,13 @@ menu_get({path} [, {modes}]) *menu_get()* } ] < + Parameters: ~ + • {path} (`string`) + • {modes} (`string?`) + + Return: ~ + (`any`) + menu_info({name} [, {mode}]) *menu_info()* Return information about the specified menu {name} in mode {mode}. The menu name should be specified without the @@ -4960,6 +6679,13 @@ menu_info({name} [, {mode}]) *menu_info()* endfor < + Parameters: ~ + • {name} (`string`) + • {mode} (`string?`) + + Return: ~ + (`any`) + min({expr}) *min()* Return the minimum value of all items in {expr}. Example: >vim echo min([apples, pears, oranges]) @@ -4970,23 +6696,26 @@ min({expr}) *min()* items in {expr} cannot be used as a Number this results in an error. An empty |List| or |Dictionary| results in zero. + Parameters: ~ + • {expr} (`any`) + + Return: ~ + (`any`) + mkdir({name} [, {flags} [, {prot}]]) *mkdir()* *E739* Create directory {name}. When {flags} is present it must be a string. An empty string has no effect. - If {flags} contains "p" then intermediate directories are - created as necessary. + {flags} can contain these character flags: + "p" intermediate directories will be created as necessary + "D" {name} will be deleted at the end of the current + function, but not recursively |:defer| + "R" {name} will be deleted recursively at the end of the + current function |:defer| - If {flags} contains "D" then {name} is deleted at the end of - the current function, as with: >vim - defer delete({name}, 'd') -< - If {flags} contains "R" then {name} is deleted recursively at - the end of the current function, as with: >vim - defer delete({name}, 'rf') -< Note that when {name} has more than one part and "p" is used + Note that when {name} has more than one part and "p" is used some directories may already exist. Only the first one that is created and what it contains is scheduled to be deleted. E.g. when using: >vim @@ -5013,6 +6742,14 @@ mkdir({name} [, {flags} [, {prot}]]) *mkdir()* *E73 successful or FALSE if the directory creation failed or partly failed. + Parameters: ~ + • {name} (`string`) + • {flags} (`string?`) + • {prot} (`string?`) + + Return: ~ + (`any`) + mode([{expr}]) *mode()* Return a string that indicates the current mode. If {expr} is supplied and it evaluates to a non-zero Number or @@ -5067,6 +6804,12 @@ mode([{expr}]) *mode()* the leading character(s). Also see |visualmode()|. + Parameters: ~ + • {expr} (`any?`) + + Return: ~ + (`any`) + msgpackdump({list} [, {type}]) *msgpackdump()* Convert a list of Vimscript objects to msgpack. Returned value is a |readfile()|-style list. When {type} contains "B", a |Blob| is @@ -5086,6 +6829,13 @@ msgpackdump({list} [, {type}]) *msgpackdump()* 4. Other strings and |Blob|s are always dumped as BIN strings. 5. Points 3. and 4. do not apply to |msgpack-special-dict|s. + Parameters: ~ + • {list} (`any`) + • {type} (`any?`) + + Return: ~ + (`any`) + msgpackparse({data}) *msgpackparse()* Convert a |readfile()|-style list or a |Blob| to a list of Vimscript objects. @@ -5137,12 +6887,7 @@ msgpackparse({data}) *msgpackparse()* C parser does not support such values. float |Float|. This value cannot possibly appear in |msgpackparse()| output. - string |readfile()|-style list of strings. This value will - appear in |msgpackparse()| output if string contains - zero byte or if string is a mapping key and mapping is - being represented as special dictionary for other - reasons. - binary |String|, or |Blob| if binary string contains zero + string |String|, or |Blob| if binary string contains zero byte. This value cannot appear in |msgpackparse()| output since blobs were introduced. array |List|. This value cannot appear in |msgpackparse()| @@ -5159,6 +6904,12 @@ msgpackparse({data}) *msgpackparse()* representing extension type. Second is |readfile()|-style list of strings. + Parameters: ~ + • {data} (`any`) + + Return: ~ + (`any`) + nextnonblank({lnum}) *nextnonblank()* Return the line number of the first line at or below {lnum} that is not blank. Example: >vim @@ -5168,6 +6919,12 @@ nextnonblank({lnum}) *nextnonblank()* {lnum} is used like with |getline()|. See also |prevnonblank()|. + Parameters: ~ + • {lnum} (`integer`) + + Return: ~ + (`any`) + nr2char({expr} [, {utf8}]) *nr2char()* Return a string with a single character, which has the number value {expr}. Examples: >vim @@ -5183,6 +6940,13 @@ nr2char({expr} [, {utf8}]) *nr2char()* characters. nr2char(0) is a real NUL and terminates the string, thus results in an empty string. + Parameters: ~ + • {expr} (`integer`) + • {utf8} (`boolean?`) + + Return: ~ + (`any`) + nvim_...({...}) *nvim_...()* *E5555* *eval-api* Call nvim |api| functions. The type checking of arguments will be stricter than for most other builtins. For instance, @@ -5194,6 +6958,12 @@ nvim_...({...}) *nvim_...()* *E5555* *eval- also take the numerical value 0 to indicate the current (focused) object. + Parameters: ~ + • {...} (`any`) + + Return: ~ + (`any`) + or({expr}, {expr}) *or()* Bitwise OR on the two arguments. The arguments are converted to a number. A List, Dict or Float argument causes an error. @@ -5206,6 +6976,13 @@ or({expr}, {expr}) *or()* to separate commands. In many places it would not be clear if "|" is an operator or a command separator. + Parameters: ~ + • {expr} (`number`) + • {expr1} (`number`) + + Return: ~ + (`any`) + pathshorten({path} [, {len}]) *pathshorten()* Shorten directory names in the path {path} and return the result. The tail, the file name, is kept as-is. The other @@ -5220,6 +6997,13 @@ pathshorten({path} [, {len}]) *pathshorten()* It doesn't matter if the path exists or not. Returns an empty string on error. + Parameters: ~ + • {path} (`string`) + • {len} (`integer?`) + + Return: ~ + (`any`) + perleval({expr}) *perleval()* Evaluate |perl| expression {expr} and return its result converted to Vim data structures. @@ -5235,6 +7019,12 @@ perleval({expr}) *perleval()* echo perleval('[1 .. 4]') < [1, 2, 3, 4] + Parameters: ~ + • {expr} (`any`) + + Return: ~ + (`any`) + pow({x}, {y}) *pow()* Return the power of {x} to the exponent {y} as a |Float|. {x} and {y} must evaluate to a |Float| or a |Number|. @@ -5247,6 +7037,13 @@ pow({x}, {y}) *pow()* echo pow(32, 0.20) < 2.0 + Parameters: ~ + • {x} (`number`) + • {y} (`number`) + + Return: ~ + (`any`) + prevnonblank({lnum}) *prevnonblank()* Return the line number of the first line at or above {lnum} that is not blank. Example: >vim @@ -5256,6 +7053,12 @@ prevnonblank({lnum}) *prevnonblank()* {lnum} is used like with |getline()|. Also see |nextnonblank()|. + Parameters: ~ + • {lnum} (`integer`) + + Return: ~ + (`any`) + printf({fmt}, {expr1} ...) *printf()* Return a String with {fmt}, where "%" items are replaced by the formatted form of their respective arguments. Example: >vim @@ -5579,6 +7382,13 @@ printf({fmt}, {expr1} ...) *printf()* into this, copying the exact format string and parameters that were used. + Parameters: ~ + • {fmt} (`string`) + • {expr1} (`any?`) + + Return: ~ + (`string`) + prompt_getprompt({buf}) *prompt_getprompt()* Returns the effective prompt text for buffer {buf}. {buf} can be a buffer name or number. See |prompt-buffer|. @@ -5586,6 +7396,12 @@ prompt_getprompt({buf}) *prompt_getprompt()* If the buffer doesn't exist or isn't a prompt buffer, an empty string is returned. + Parameters: ~ + • {buf} (`integer|string`) + + Return: ~ + (`any`) + prompt_setcallback({buf}, {expr}) *prompt_setcallback()* Set prompt callback for buffer {buf} to {expr}. When {expr} is an empty string the callback is removed. This has only @@ -5618,6 +7434,13 @@ prompt_setcallback({buf}, {expr}) *prompt_setcallback()* endfunc call prompt_setcallback(bufnr(), function('s:TextEntered')) + Parameters: ~ + • {buf} (`integer|string`) + • {expr} (`string|function`) + + Return: ~ + (`any`) + prompt_setinterrupt({buf}, {expr}) *prompt_setinterrupt()* Set a callback for buffer {buf} to {expr}. When {expr} is an empty string the callback is removed. This has only effect if @@ -5627,6 +7450,13 @@ prompt_setinterrupt({buf}, {expr}) *prompt_setinterrupt()* mode. Without setting a callback Vim will exit Insert mode, as in any buffer. + Parameters: ~ + • {buf} (`integer|string`) + • {expr} (`string|function`) + + Return: ~ + (`any`) + prompt_setprompt({buf}, {text}) *prompt_setprompt()* Set prompt for buffer {buf} to {text}. You most likely want {text} to end in a space. @@ -5635,6 +7465,13 @@ prompt_setprompt({buf}, {text}) *prompt_setprompt()* call prompt_setprompt(bufnr(''), 'command: ') < + Parameters: ~ + • {buf} (`integer|string`) + • {text} (`string`) + + Return: ~ + (`any`) + pum_getpos() *pum_getpos()* If the popup menu (see |ins-completion-menu|) is not visible, returns an empty |Dictionary|, otherwise, returns a @@ -5648,12 +7485,18 @@ pum_getpos() *pum_getpos()* The values are the same as in |v:event| during |CompleteChanged|. + Return: ~ + (`any`) + pumvisible() *pumvisible()* Returns non-zero when the popup menu is visible, zero otherwise. See |ins-completion-menu|. This can be used to avoid some things that would remove the popup menu. + Return: ~ + (`any`) + py3eval({expr}) *py3eval()* Evaluate Python expression {expr} and return its result converted to Vim data structures. @@ -5664,6 +7507,12 @@ py3eval({expr}) *py3eval()* Dictionaries are represented as Vim |Dictionary| type with keys converted to strings. + Parameters: ~ + • {expr} (`any`) + + Return: ~ + (`any`) + pyeval({expr}) *pyeval()* *E858* *E859* Evaluate Python expression {expr} and return its result converted to Vim data structures. @@ -5673,12 +7522,24 @@ pyeval({expr}) *pyeval()* *E858* *E Dictionaries are represented as Vim |Dictionary| type, non-string keys result in error. + Parameters: ~ + • {expr} (`any`) + + Return: ~ + (`any`) + pyxeval({expr}) *pyxeval()* Evaluate Python expression {expr} and return its result converted to Vim data structures. Uses Python 2 or 3, see |python_x| and 'pyxversion'. See also: |pyeval()|, |py3eval()| + Parameters: ~ + • {expr} (`any`) + + Return: ~ + (`any`) + rand([{expr}]) *rand()* Return a pseudo-random Number generated with an xoshiro128** algorithm using seed {expr}. The returned number is 32 bits, @@ -5695,6 +7556,12 @@ rand([{expr}]) *rand()* echo rand(seed) % 16 " random number 0 - 15 < + Parameters: ~ + • {expr} (`number?`) + + Return: ~ + (`any`) + range({expr} [, {max} [, {stride}]]) *range()* *E726* *E727* Returns a |List| with Numbers: - If only {expr} is specified: [0, 1, ..., {expr} - 1] @@ -5714,6 +7581,14 @@ range({expr} [, {max} [, {stride}]]) *range()* *E726* *E echo range(2, 0) " error! < + Parameters: ~ + • {expr} (`any`) + • {max} (`integer?`) + • {stride} (`integer?`) + + Return: ~ + (`any`) + readblob({fname} [, {offset} [, {size}]]) *readblob()* Read file {fname} in binary mode and return a |Blob|. If {offset} is specified, read the file from the specified @@ -5738,6 +7613,14 @@ readblob({fname} [, {offset} [, {size}]]) *readblob()* is truncated. Also see |readfile()| and |writefile()|. + Parameters: ~ + • {fname} (`string`) + • {offset} (`integer?`) + • {size} (`integer?`) + + Return: ~ + (`any`) + readdir({directory} [, {expr}]) *readdir()* Return a list with file and directory names in {directory}. You can also use |glob()| if you don't need to do complicated @@ -5768,6 +7651,13 @@ readdir({directory} [, {expr}]) *readdir()* < Returns an empty List on error. + Parameters: ~ + • {directory} (`string`) + • {expr} (`integer?`) + + Return: ~ + (`any`) + readfile({fname} [, {type} [, {max}]]) *readfile()* Read file {fname} and return a |List|, each line of the file as an item. Lines are broken at NL characters. Macintosh @@ -5801,6 +7691,14 @@ readfile({fname} [, {type} [, {max}]]) *readfile()* the result is an empty list. Also see |writefile()|. + Parameters: ~ + • {fname} (`string`) + • {type} (`string?`) + • {max} (`integer?`) + + Return: ~ + (`any`) + reduce({object}, {func} [, {initial}]) *reduce()* *E998* {func} is called for every item in {object}, which can be a |String|, |List| or a |Blob|. {func} is called with two @@ -5819,20 +7717,37 @@ reduce({object}, {func} [, {initial}]) *reduce()* *E99 echo reduce('xyz', { acc, val -> acc .. ',' .. val }) < + Parameters: ~ + • {object} (`any`) + • {func} (`function`) + • {initial} (`any?`) + + Return: ~ + (`any`) + reg_executing() *reg_executing()* Returns the single letter name of the register being executed. Returns an empty string when no register is being executed. See |@|. + Return: ~ + (`any`) + reg_recorded() *reg_recorded()* Returns the single letter name of the last recorded register. Returns an empty string when nothing was recorded yet. See |q| and |Q|. + Return: ~ + (`any`) + reg_recording() *reg_recording()* Returns the single letter name of the register being recorded. Returns an empty string when not recording. See |q|. + Return: ~ + (`any`) + reltime() *reltime()* reltime({start}) reltime({start}, {end}) @@ -5855,6 +7770,13 @@ reltime({start}, {end}) Note: |localtime()| returns the current (non-relative) time. + Parameters: ~ + • {start} (`any?`) + • {end_} (`any?`) + + Return: ~ + (`any`) + reltimefloat({time}) *reltimefloat()* Return a Float that represents the time value of {time}. Unit of time is seconds. @@ -5866,6 +7788,12 @@ reltimefloat({time}) *reltimefloat()* Also see |profiling|. If there is an error an empty string is returned + Parameters: ~ + • {time} (`any`) + + Return: ~ + (`any`) + reltimestr({time}) *reltimestr()* Return a String that represents the time value of {time}. This is the number of seconds, a dot and the number of @@ -5880,6 +7808,12 @@ reltimestr({time}) *reltimestr()* < Also see |profiling|. If there is an error an empty string is returned + Parameters: ~ + • {time} (`any`) + + Return: ~ + (`any`) + remove({list}, {idx}) *remove()* remove({list}, {idx}, {end}) Without {end}: Remove the item at {idx} from |List| {list} and @@ -5896,6 +7830,14 @@ remove({list}, {idx}, {end}) < Use |delete()| to remove a file. + Parameters: ~ + • {list} (`any[]`) + • {idx} (`integer`) + • {end_} (`integer?`) + + Return: ~ + (`any`) + remove({blob}, {idx}) remove({blob}, {idx}, {end}) Without {end}: Remove the byte at {idx} from |Blob| {blob} and @@ -5910,6 +7852,14 @@ remove({blob}, {idx}, {end}) call remove(mylist, 0, 9) < + Parameters: ~ + • {blob} (`any`) + • {idx} (`integer`) + • {end_} (`integer?`) + + Return: ~ + (`any`) + remove({dict}, {key}) Remove the entry from {dict} with key {key} and return it. Example: >vim @@ -5917,6 +7867,13 @@ remove({dict}, {key}) < If there is no {key} in {dict} this is an error. Returns zero on error. + Parameters: ~ + • {dict} (`any`) + • {key} (`string`) + + Return: ~ + (`any`) + rename({from}, {to}) *rename()* Rename the file by the name {from} to the name {to}. This should also work to move files across file systems. The @@ -5925,6 +7882,13 @@ rename({from}, {to}) *rename()* NOTE: If {to} exists it is overwritten without warning. This function is not available in the |sandbox|. + Parameters: ~ + • {from} (`string`) + • {to} (`string`) + + Return: ~ + (`any`) + repeat({expr}, {count}) *repeat()* Repeat {expr} {count} times and return the concatenated result. Example: >vim @@ -5935,6 +7899,13 @@ repeat({expr}, {count}) *repeat()* let longlist = repeat(['a', 'b'], 3) < Results in ['a', 'b', 'a', 'b', 'a', 'b']. + Parameters: ~ + • {expr} (`any`) + • {count} (`integer`) + + Return: ~ + (`any`) + resolve({filename}) *resolve()* *E655* On MS-Windows, when {filename} is a shortcut (a .lnk file), returns the path the shortcut points to in a simplified form. @@ -5948,6 +7919,12 @@ resolve({filename}) *resolve()* *E65 current directory (provided the result is still a relative path name) and also keeps a trailing path separator. + Parameters: ~ + • {filename} (`string`) + + Return: ~ + (`any`) + reverse({object}) *reverse()* Reverse the order of items in {object}. {object} can be a |List|, a |Blob| or a |String|. For a List and a Blob the @@ -5959,6 +7936,12 @@ reverse({object}) *reverse()* let revlist = reverse(copy(mylist)) < + Parameters: ~ + • {object} (`any`) + + Return: ~ + (`any`) + round({expr}) *round()* Round off {expr} to the nearest integral value and return it as a |Float|. If {expr} lies halfway between two integral @@ -5973,6 +7956,12 @@ round({expr}) *round()* echo round(-4.5) < -5.0 + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`any`) + rpcnotify({channel}, {event} [, {args}...]) *rpcnotify()* Sends {event} to {channel} via |RPC| and returns immediately. If {channel} is 0, the event is broadcast to all channels. @@ -5980,6 +7969,14 @@ rpcnotify({channel}, {event} [, {args}...]) *rpcnotify()* au VimLeave call rpcnotify(0, "leaving") < + Parameters: ~ + • {channel} (`integer`) + • {event} (`string`) + • {args} (`any?`) + + Return: ~ + (`any`) + rpcrequest({channel}, {method} [, {args}...]) *rpcrequest()* Sends a request to {channel} to invoke {method} via |RPC| and blocks until a response is received. @@ -5987,12 +7984,13 @@ rpcrequest({channel}, {method} [, {args}...]) *rpcrequest()* let result = rpcrequest(rpc_chan, "func", 1, 2, 3) < -rpcstart({prog} [, {argv}]) *rpcstart()* - Deprecated. Replace >vim - let id = rpcstart('prog', ['arg1', 'arg2']) -< with >vim - let id = jobstart(['prog', 'arg1', 'arg2'], {'rpc': v:true}) -< + Parameters: ~ + • {channel} (`integer`) + • {method} (`string`) + • {args} (`any?`) + + Return: ~ + (`any`) rubyeval({expr}) *rubyeval()* Evaluate Ruby expression {expr} and return its result @@ -6004,12 +8002,25 @@ rubyeval({expr}) *rubyeval()* Other objects are represented as strings resulted from their "Object#to_s" method. + Parameters: ~ + • {expr} (`any`) + + Return: ~ + (`any`) + screenattr({row}, {col}) *screenattr()* Like |screenchar()|, but return the attribute. This is a rather arbitrary number that can only be used to compare to the attribute at other positions. Returns -1 when row or col is out of range. + Parameters: ~ + • {row} (`integer`) + • {col} (`integer`) + + Return: ~ + (`any`) + screenchar({row}, {col}) *screenchar()* The result is a Number, which is the character at position [row, col] on the screen. This works for every possible @@ -6020,6 +8031,13 @@ screenchar({row}, {col}) *screenchar()* This is mainly to be used for testing. Returns -1 when row or col is out of range. + Parameters: ~ + • {row} (`integer`) + • {col} (`integer`) + + Return: ~ + (`any`) + screenchars({row}, {col}) *screenchars()* The result is a |List| of Numbers. The first number is the same as what |screenchar()| returns. Further numbers are @@ -6027,6 +8045,13 @@ screenchars({row}, {col}) *screenchars()* This is mainly to be used for testing. Returns an empty List when row or col is out of range. + Parameters: ~ + • {row} (`integer`) + • {col} (`integer`) + + Return: ~ + (`any`) + screencol() *screencol()* The result is a Number, which is the current screen column of the cursor. The leftmost column has number 1. @@ -6039,9 +8064,12 @@ screencol() *screencol()* the following mappings: >vim nnoremap <expr> GG ":echom " .. screencol() .. "\n" nnoremap <silent> GG :echom screencol()<CR> - noremap GG <Cmd>echom screencol()<Cr> + noremap GG <Cmd>echom screencol()<CR> < + Return: ~ + (`any`) + screenpos({winid}, {lnum}, {col}) *screenpos()* The result is a Dict with the screen position of the text character in window {winid} at buffer line {lnum} and column @@ -6066,6 +8094,14 @@ screenpos({winid}, {lnum}, {col}) *screenpos()* first character is returned, {col} is not used. Returns an empty Dict if {winid} is invalid. + Parameters: ~ + • {winid} (`integer`) + • {lnum} (`integer`) + • {col} (`integer`) + + Return: ~ + (`any`) + screenrow() *screenrow()* The result is a Number, which is the current screen row of the cursor. The top line has number one. @@ -6074,6 +8110,9 @@ screenrow() *screenrow()* Note: Same restrictions as with |screencol()|. + Return: ~ + (`any`) + screenstring({row}, {col}) *screenstring()* The result is a String that contains the base character and any composing characters at position [row, col] on the screen. @@ -6082,6 +8121,13 @@ screenstring({row}, {col}) *screenstring()* This is mainly to be used for testing. Returns an empty String when row or col is out of range. + Parameters: ~ + • {row} (`integer`) + • {col} (`integer`) + + Return: ~ + (`any`) + search({pattern} [, {flags} [, {stopline} [, {timeout} [, {skip}]]]]) *search()* Search for regexp pattern {pattern}. The search starts at the cursor position (you can use |cursor()| to set it). @@ -6137,6 +8183,9 @@ search({pattern} [, {flags} [, {stopline} [, {timeout} [, {skip}]]]]) *search()* The value must not be negative. A zero value is like not giving the argument. + Note: the timeout is only considered when searching, not + while evaluating the {skip} expression. + If the {skip} expression is given it is evaluated with the cursor positioned on the start of a match. If it evaluates to non-zero this match is skipped. This can be used, for @@ -6184,6 +8233,16 @@ search({pattern} [, {flags} [, {stopline} [, {timeout} [, {skip}]]]]) *search()* without the 'e' flag if the cursor is on the "f" of "if". The 'n' flag tells the function not to move the cursor. + Parameters: ~ + • {pattern} (`string`) + • {flags} (`string?`) + • {stopline} (`integer?`) + • {timeout} (`integer?`) + • {skip} (`string|function?`) + + Return: ~ + (`any`) + searchcount([{options}]) *searchcount()* Get or update the last search count, like what is displayed without the "S" flag in 'shortmess'. This works even if @@ -6305,6 +8364,12 @@ searchcount([{options}]) *searchcount()* value. see |cursor()|, |getpos()| (default: cursor's position) + Parameters: ~ + • {options} (`table?`) + + Return: ~ + (`any`) + searchdecl({name} [, {global} [, {thisblock}]]) *searchdecl()* Search for the declaration of {name}. @@ -6324,6 +8389,14 @@ searchdecl({name} [, {global} [, {thisblock}]]) *searchdecl()* endif < + Parameters: ~ + • {name} (`string`) + • {global} (`boolean?`) + • {thisblock} (`boolean?`) + + Return: ~ + (`any`) + *searchpair()* searchpair({start}, {middle}, {end} [, {flags} [, {skip} [, {stopline} [, {timeout}]]]]) Search for the match of a nested start-end pair. This can be @@ -6410,6 +8483,18 @@ searchpair({start}, {middle}, {end} [, {flags} [, {skip} [, {stopline} [, {timeo \ 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string"') < + Parameters: ~ + • {start} (`string`) + • {middle} (`string`) + • {end_} (`string`) + • {flags} (`string?`) + • {skip} (`string|function?`) + • {stopline} (`integer?`) + • {timeout} (`integer?`) + + Return: ~ + (`integer`) + *searchpairpos()* searchpairpos({start}, {middle}, {end} [, {flags} [, {skip} [, {stopline} [, {timeout}]]]]) Same as |searchpair()|, but returns a |List| with the line and @@ -6422,6 +8507,18 @@ searchpairpos({start}, {middle}, {end} [, {flags} [, {skip} [, {stopline} [, {ti < See |match-parens| for a bigger and more useful example. + Parameters: ~ + • {start} (`string`) + • {middle} (`string`) + • {end_} (`string`) + • {flags} (`string?`) + • {skip} (`string|function?`) + • {stopline} (`integer?`) + • {timeout} (`integer?`) + + Return: ~ + (`[integer, integer]`) + *searchpos()* searchpos({pattern} [, {flags} [, {stopline} [, {timeout} [, {skip}]]]]) Same as |search()|, but returns a |List| with the line and @@ -6438,6 +8535,16 @@ searchpos({pattern} [, {flags} [, {stopline} [, {timeout} [, {skip}]]]]) < In this example "submatch" is 2 when a lowercase letter is found |/\l|, 3 when an uppercase letter is found |/\u|. + Parameters: ~ + • {pattern} (`string`) + • {flags} (`string?`) + • {stopline} (`integer?`) + • {timeout} (`integer?`) + • {skip} (`string|function?`) + + Return: ~ + (`any`) + serverlist() *serverlist()* Returns a list of server addresses, or empty if all servers were stopped. |serverstart()| |serverstop()| @@ -6445,6 +8552,9 @@ serverlist() *serverlist()* echo serverlist() < + Return: ~ + (`any`) + serverstart([{address}]) *serverstart()* Opens a socket or named pipe at {address} and listens for |RPC| messages. Clients can send |API| commands to the @@ -6479,12 +8589,24 @@ serverstart([{address}]) *serverstart()* echo serverstart('::1:12345') < + Parameters: ~ + • {address} (`string?`) + + Return: ~ + (`any`) + serverstop({address}) *serverstop()* Closes the pipe or socket at {address}. Returns TRUE if {address} is valid, else FALSE. If |v:servername| is stopped it is set to the next available address in |serverlist()|. + Parameters: ~ + • {address} (`string`) + + Return: ~ + (`any`) + setbufline({buf}, {lnum}, {text}) *setbufline()* Set line {lnum} to {text} in buffer {buf}. This works like |setline()| for the specified buffer. @@ -6510,6 +8632,14 @@ setbufline({buf}, {lnum}, {text}) *setbufline()* If {buf} is not a valid buffer or {lnum} is not valid, an error message is given. + Parameters: ~ + • {buf} (`integer|string`) + • {lnum} (`integer`) + • {text} (`string|string[]`) + + Return: ~ + (`any`) + setbufvar({buf}, {varname}, {val}) *setbufvar()* Set option or local variable {varname} in buffer {buf} to {val}. @@ -6524,6 +8654,14 @@ setbufvar({buf}, {varname}, {val}) *setbufvar()* call setbufvar("todo", "myvar", "foobar") < This function is not available in the |sandbox|. + Parameters: ~ + • {buf} (`integer|string`) + • {varname} (`string`) + • {val} (`any`) + + Return: ~ + (`any`) + setcellwidths({list}) *setcellwidths()* Specify overrides for cell widths of character ranges. This tells Vim how wide characters are when displayed in the @@ -6552,12 +8690,18 @@ setcellwidths({list}) *setcellwidths()* To clear the overrides pass an empty {list}: >vim call setcellwidths([]) -< You can use the script $VIMRUNTIME/tools/emoji_list.vim to see +< You can use the script $VIMRUNTIME/tools/emoji_list.lua to see the effect for known emoji characters. Move the cursor through the text to check if the cell widths of your terminal match with what Vim knows about each emoji. If it doesn't look right you need to adjust the {list} argument. + Parameters: ~ + • {list} (`any[]`) + + Return: ~ + (`any`) + setcharpos({expr}, {list}) *setcharpos()* Same as |setpos()| but uses the specified column number as the character index instead of the byte index in the line. @@ -6569,6 +8713,13 @@ setcharpos({expr}, {list}) *setcharpos()* call setpos('.', [0, 8, 4, 0]) < positions the cursor on the second character 'ë³´'. + Parameters: ~ + • {expr} (`string`) + • {list} (`integer[]`) + + Return: ~ + (`any`) + setcharsearch({dict}) *setcharsearch()* Set the current character search information to {dict}, which contains one or more of the following entries: @@ -6589,6 +8740,12 @@ setcharsearch({dict}) *setcharsearch()* call setcharsearch(prevsearch) < Also see |getcharsearch()|. + Parameters: ~ + • {dict} (`string`) + + Return: ~ + (`any`) + setcmdline({str} [, {pos}]) *setcmdline()* Set the command line to {str} and set the cursor position to {pos}. @@ -6596,6 +8753,13 @@ setcmdline({str} [, {pos}]) *setcmdline()* Returns 0 when successful, 1 when not editing the command line. + Parameters: ~ + • {str} (`string`) + • {pos} (`integer?`) + + Return: ~ + (`any`) + setcmdpos({pos}) *setcmdpos()* Set the cursor position in the command line to byte position {pos}. The first position is 1. @@ -6611,6 +8775,12 @@ setcmdpos({pos}) *setcmdpos()* Returns 0 when successful, 1 when not editing the command line. + Parameters: ~ + • {pos} (`integer`) + + Return: ~ + (`any`) + setcursorcharpos({lnum}, {col} [, {off}]) *setcursorcharpos()* setcursorcharpos({list}) Same as |cursor()| but uses the specified column number as the @@ -6623,6 +8793,12 @@ setcursorcharpos({list}) call cursor(4, 3) < positions the cursor on the first character 'ì—¬'. + Parameters: ~ + • {list} (`integer[]`) + + Return: ~ + (`any`) + setenv({name}, {val}) *setenv()* Set environment variable {name} to {val}. Example: >vim call setenv('HOME', '/home/myhome') @@ -6630,6 +8806,13 @@ setenv({name}, {val}) *setenv()* < When {val} is |v:null| the environment variable is deleted. See also |expr-env|. + Parameters: ~ + • {name} (`string`) + • {val} (`string`) + + Return: ~ + (`any`) + setfperm({fname}, {mode}) *setfperm()* *chmod* Set the file permissions for {fname} to {mode}. {mode} must be a string with 9 characters. It is of the form @@ -6647,6 +8830,13 @@ setfperm({fname}, {mode}) *setfperm()* *chmo To read permissions see |getfperm()|. + Parameters: ~ + • {fname} (`string`) + • {mode} (`string`) + + Return: ~ + (`any`) + setline({lnum}, {text}) *setline()* Set line {lnum} of the current buffer to {text}. To insert lines use |append()|. To set lines in another buffer use @@ -6675,6 +8865,13 @@ setline({lnum}, {text}) *setline()* < Note: The '[ and '] marks are not set. + Parameters: ~ + • {lnum} (`integer`) + • {text} (`any`) + + Return: ~ + (`any`) + setloclist({nr}, {list} [, {action} [, {what}]]) *setloclist()* Create or replace or add to the location list for window {nr}. {nr} can be the window number or the |window-ID|. @@ -6691,6 +8888,15 @@ setloclist({nr}, {list} [, {action} [, {what}]]) *setloclist()* only the items listed in {what} are set. Refer to |setqflist()| for the list of supported keys in {what}. + Parameters: ~ + • {nr} (`integer`) + • {list} (`any`) + • {action} (`string?`) + • {what} (`table?`) + + Return: ~ + (`any`) + setmatches({list} [, {win}]) *setmatches()* Restores a list of matches saved by |getmatches()| for the current window. Returns 0 if successful, otherwise -1. All @@ -6699,6 +8905,13 @@ setmatches({list} [, {win}]) *setmatches()* If {win} is specified, use the window with this number or window ID instead of the current window. + Parameters: ~ + • {list} (`any`) + • {win} (`integer?`) + + Return: ~ + (`any`) + setpos({expr}, {list}) *setpos()* Set the position for String {expr}. Possible values: . the cursor @@ -6748,6 +8961,13 @@ setpos({expr}, {list}) *setpos()* also set the preferred column. Also see the "curswant" key in |winrestview()|. + Parameters: ~ + • {expr} (`string`) + • {list} (`integer[]`) + + Return: ~ + (`any`) + setqflist({list} [, {action} [, {what}]]) *setqflist()* Create or replace or add to the quickfix list. @@ -6862,6 +9082,14 @@ setqflist({list} [, {action} [, {what}]]) *setqflist()* independent of the 'errorformat' setting. Use a command like `:cc 1` to jump to the first position. + Parameters: ~ + • {list} (`any[]`) + • {action} (`string?`) + • {what} (`table?`) + + Return: ~ + (`any`) + setreg({regname}, {value} [, {options}]) *setreg()* Set the register {regname} to {value}. If {regname} is "" or "@", the unnamed register '"' is used. @@ -6918,6 +9146,14 @@ setreg({regname}, {value} [, {options}]) *setreg()* nothing: >vim call setreg('a', '', 'al') + Parameters: ~ + • {regname} (`string`) + • {value} (`any`) + • {options} (`string?`) + + Return: ~ + (`any`) + settabvar({tabnr}, {varname}, {val}) *settabvar()* Set tab-local variable {varname} to {val} in tab page {tabnr}. |t:var| @@ -6926,6 +9162,14 @@ settabvar({tabnr}, {varname}, {val}) *settabvar()* Tabs are numbered starting with one. This function is not available in the |sandbox|. + Parameters: ~ + • {tabnr} (`integer`) + • {varname} (`string`) + • {val} (`any`) + + Return: ~ + (`any`) + settabwinvar({tabnr}, {winnr}, {varname}, {val}) *settabwinvar()* Set option or local variable {varname} in window {winnr} to {val}. @@ -6942,6 +9186,15 @@ settabwinvar({tabnr}, {winnr}, {varname}, {val}) *settabwinvar()* call settabwinvar(3, 2, "myvar", "foobar") < This function is not available in the |sandbox|. + Parameters: ~ + • {tabnr} (`integer`) + • {winnr} (`integer`) + • {varname} (`string`) + • {val} (`any`) + + Return: ~ + (`any`) + settagstack({nr}, {dict} [, {action}]) *settagstack()* Modify the tag stack of the window {nr} using {dict}. {nr} can be the window number or the |window-ID|. @@ -6976,16 +9229,38 @@ settagstack({nr}, {dict} [, {action}]) *settagstack()* unlet stack < + Parameters: ~ + • {nr} (`integer`) + • {dict} (`any`) + • {action} (`string?`) + + Return: ~ + (`any`) + setwinvar({nr}, {varname}, {val}) *setwinvar()* Like |settabwinvar()| for the current tab page. Examples: >vim call setwinvar(1, "&list", 0) call setwinvar(2, "myvar", "foobar") + Parameters: ~ + • {nr} (`integer`) + • {varname} (`string`) + • {val} (`any`) + + Return: ~ + (`any`) + sha256({string}) *sha256()* Returns a String with 64 hex characters, which is the SHA256 checksum of {string}. + Parameters: ~ + • {string} (`string`) + + Return: ~ + (`any`) + shellescape({string} [, {special}]) *shellescape()* Escape {string} for use as a shell command argument. @@ -7018,6 +9293,13 @@ shellescape({string} [, {special}]) *shellescape()* call system("chmod +w -- " .. shellescape(expand("%"))) < See also |::S|. + Parameters: ~ + • {string} (`string`) + • {special} (`boolean?`) + + Return: ~ + (`any`) + shiftwidth([{col}]) *shiftwidth()* Returns the effective value of 'shiftwidth'. This is the 'shiftwidth' value unless it is zero, in which case it is the @@ -7039,6 +9321,12 @@ shiftwidth([{col}]) *shiftwidth()* 'vartabstop' feature. If no {col} argument is given, column 1 will be assumed. + Parameters: ~ + • {col} (`integer?`) + + Return: ~ + (`integer`) + sign_define({name} [, {dict}]) *sign_define()* sign_define({list}) Define a new sign named {name} or modify the attributes of an @@ -7053,6 +9341,7 @@ sign_define({list}) icon full path to the bitmap file for the sign. linehl highlight group used for the whole line the sign is placed in. + priority default priority value of the sign numhl highlight group used for the line number where the sign is placed. text text that is displayed when there is no icon @@ -7086,6 +9375,12 @@ sign_define({list}) \ ]) < + Parameters: ~ + • {list} (`vim.fn.sign_define.dict[]`) + + Return: ~ + (`(0|-1)[]`) + sign_getdefined([{name}]) *sign_getdefined()* Get a list of defined signs and their attributes. This is similar to the |:sign-list| command. @@ -7100,6 +9395,7 @@ sign_getdefined([{name}]) *sign_getdefined()* linehl highlight group used for the whole line the sign is placed in; not present if not set. name name of the sign + priority default priority value of the sign numhl highlight group used for the line number where the sign is placed; not present if not set. text text that is displayed when there is no icon @@ -7122,6 +9418,12 @@ sign_getdefined([{name}]) *sign_getdefined()* echo sign_getdefined("mySign") < + Parameters: ~ + • {name} (`string?`) + + Return: ~ + (`vim.fn.sign_getdefined.ret.item[]`) + sign_getplaced([{buf} [, {dict}]]) *sign_getplaced()* Return a list of signs placed in a buffer or all the buffers. This is similar to the |:sign-place-list| command. @@ -7183,6 +9485,13 @@ sign_getplaced([{buf} [, {dict}]]) *sign_getplaced()* echo sign_getplaced() < + Parameters: ~ + • {buf} (`integer|string?`) + • {dict} (`vim.fn.sign_getplaced.dict?`) + + Return: ~ + (`vim.fn.sign_getplaced.ret.item[]`) + sign_jump({id}, {group}, {buf}) *sign_jump()* Open the buffer {buf} or jump to the window that contains {buf} and position the cursor at sign {id} in group {group}. @@ -7199,6 +9508,14 @@ sign_jump({id}, {group}, {buf}) *sign_jump()* call sign_jump(10, '', '') < + Parameters: ~ + • {id} (`integer`) + • {group} (`string`) + • {buf} (`integer|string`) + + Return: ~ + (`integer`) + sign_place({id}, {group}, {name}, {buf} [, {dict}]) *sign_place()* Place the sign defined as {name} at line {lnum} in file or buffer {buf} and assign {id} and {group} to sign. This is @@ -7248,6 +9565,16 @@ sign_place({id}, {group}, {name}, {buf} [, {dict}]) *sign_place()* \ {'lnum' : 40, 'priority' : 90}) < + Parameters: ~ + • {id} (`integer`) + • {group} (`string`) + • {name} (`string`) + • {buf} (`integer|string`) + • {dict} (`vim.fn.sign_place.dict?`) + + Return: ~ + (`integer`) + sign_placelist({list}) *sign_placelist()* Place one or more signs. This is similar to the |sign_place()| function. The {list} argument specifies the @@ -7272,7 +9599,8 @@ sign_placelist({list}) *sign_placelist()* priority Priority of the sign. When multiple signs are placed on a line, the sign with the highest priority is used. If not specified, the - default value of 10 is used. See + default value of 10 is used, unless specified + otherwise by the sign definition. See |sign-priority| for more information. If {id} refers to an existing sign, then the existing sign is @@ -7307,6 +9635,12 @@ sign_placelist({list}) *sign_placelist()* \ ]) < + Parameters: ~ + • {list} (`vim.fn.sign_placelist.list.item[]`) + + Return: ~ + (`integer[]`) + sign_undefine([{name}]) *sign_undefine()* sign_undefine({list}) Deletes a previously defined sign {name}. This is similar to @@ -7331,6 +9665,12 @@ sign_undefine({list}) call sign_undefine() < + Parameters: ~ + • {list} (`string[]?`) + + Return: ~ + (`integer[]`) + sign_unplace({group} [, {dict}]) *sign_unplace()* Remove a previously placed sign in one or more buffers. This is similar to the |:sign-unplace| command. @@ -7373,6 +9713,13 @@ sign_unplace({group} [, {dict}]) *sign_unplace()* " Remove all the placed signs from all the buffers call sign_unplace('*') + Parameters: ~ + • {group} (`string`) + • {dict} (`vim.fn.sign_unplace.dict?`) + + Return: ~ + (`0|-1`) + sign_unplacelist({list}) *sign_unplacelist()* Remove previously placed signs from one or more buffers. This is similar to the |sign_unplace()| function. @@ -7402,6 +9749,12 @@ sign_unplacelist({list}) *sign_unplacelist()* \ ]) < + Parameters: ~ + • {list} (`vim.fn.sign_unplacelist.list.item`) + + Return: ~ + (`(0|-1)[]`) + simplify({filename}) *simplify()* Simplify the file name as much as possible without changing the meaning. Shortcuts (on MS-Windows) or symbolic links (on @@ -7419,6 +9772,12 @@ simplify({filename}) *simplify()* directory. In order to resolve all the involved symbolic links before simplifying the path name, use |resolve()|. + Parameters: ~ + • {filename} (`string`) + + Return: ~ + (`any`) + sin({expr}) *sin()* Return the sine of {expr}, measured in radians, as a |Float|. {expr} must evaluate to a |Float| or a |Number|. @@ -7429,6 +9788,12 @@ sin({expr}) *sin()* echo sin(-4.01) < 0.763301 + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`any`) + sinh({expr}) *sinh()* Return the hyperbolic sine of {expr} as a |Float| in the range [-inf, inf]. @@ -7440,6 +9805,12 @@ sinh({expr}) *sinh()* echo sinh(-0.9) < -1.026517 + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`any`) + slice({expr}, {start} [, {end}]) *slice()* Similar to using a |slice| "expr[start : end]", but "end" is used exclusive. And for a string the indexes are used as @@ -7450,6 +9821,14 @@ slice({expr}, {start} [, {end}]) *slice()* When {end} is -1 the last item is omitted. Returns an empty value if {start} or {end} are invalid. + Parameters: ~ + • {expr} (`any`) + • {start} (`integer`) + • {end_} (`integer?`) + + Return: ~ + (`any`) + sockconnect({mode}, {address} [, {opts}]) *sockconnect()* Connect a socket to an address. If {mode} is "pipe" then {address} should be the path of a local domain socket (on @@ -7475,6 +9854,14 @@ sockconnect({mode}, {address} [, {opts}]) *sockconnect()* - The channel ID on success (greater than zero) - 0 on invalid arguments or connection failure. + Parameters: ~ + • {mode} (`string`) + • {address} (`string`) + • {opts} (`table?`) + + Return: ~ + (`any`) + sort({list} [, {how} [, {dict}]]) *sort()* *E702* Sort the items in {list} in-place. Returns {list}. @@ -7548,6 +9935,14 @@ sort({list} [, {how} [, {dict}]]) *sort()* *E70 eval mylist->sort({i1, i2 -> i1 - i2}) < + Parameters: ~ + • {list} (`any`) + • {how} (`string|function?`) + • {dict} (`any?`) + + Return: ~ + (`any`) + soundfold({word}) *soundfold()* Return the sound-folded equivalent of {word}. Uses the first language in 'spelllang' for the current window that supports @@ -7556,6 +9951,12 @@ soundfold({word}) *soundfold()* This can be used for making spelling suggestions. Note that the method can be quite slow. + Parameters: ~ + • {word} (`string`) + + Return: ~ + (`any`) + spellbadword([{sentence}]) *spellbadword()* Without argument: The result is the badly spelled word under or after the cursor. The cursor is moved to the start of the @@ -7580,6 +9981,12 @@ spellbadword([{sentence}]) *spellbadword()* The spelling information for the current window and the value of 'spelllang' are used. + Parameters: ~ + • {sentence} (`string?`) + + Return: ~ + (`any`) + spellsuggest({word} [, {max} [, {capital}]]) *spellsuggest()* Return a |List| with spelling suggestions to replace {word}. When {max} is given up to this number of suggestions are @@ -7601,10 +10008,18 @@ spellsuggest({word} [, {max} [, {capital}]]) *spellsuggest()* The spelling information for the current window is used. The values of 'spelllang' and 'spellsuggest' are used. + Parameters: ~ + • {word} (`string`) + • {max} (`integer?`) + • {capital} (`boolean?`) + + Return: ~ + (`any`) + split({string} [, {pattern} [, {keepempty}]]) *split()* Make a |List| out of {string}. When {pattern} is omitted or - empty each white-separated sequence of characters becomes an - item. + empty each white space separated sequence of characters + becomes an item. Otherwise the string is split where {pattern} matches, removing the matched characters. 'ignorecase' is not used here, add \c to ignore case. |/\c| @@ -7626,6 +10041,14 @@ split({string} [, {pattern} [, {keepempty}]]) *split()* let items = split(line, ':', 1) < The opposite function is |join()|. + Parameters: ~ + • {string} (`string`) + • {pattern} (`string?`) + • {keepempty} (`boolean?`) + + Return: ~ + (`any`) + sqrt({expr}) *sqrt()* Return the non-negative square root of Float {expr} as a |Float|. @@ -7639,6 +10062,12 @@ sqrt({expr}) *sqrt()* < str2float("nan") NaN may be different, it depends on system libraries. + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`any`) + srand([{expr}]) *srand()* Initialize seed used by |rand()|: - If {expr} is not given, seed values are initialized by @@ -7654,6 +10083,12 @@ srand([{expr}]) *srand()* echo rand(seed) < + Parameters: ~ + • {expr} (`number?`) + + Return: ~ + (`any`) + state([{what}]) *state()* Return a string which contains characters indicating the current state. Mostly useful in callbacks that want to do @@ -7684,6 +10119,12 @@ state([{what}]) *state()* recursiveness up to "ccc") s screen has scrolled for messages + Parameters: ~ + • {what} (`string?`) + + Return: ~ + (`any`) + stdioopen({opts}) *stdioopen()* With |--headless| this opens stdin and stdout as a |channel|. May be called only once. See |channel-stdio|. stderr is not @@ -7705,6 +10146,12 @@ stdioopen({opts}) *stdioopen()* - |channel-id| on success (value is always 1) - 0 on invalid arguments + Parameters: ~ + • {opts} (`table`) + + Return: ~ + (`any`) + stdpath({what}) *stdpath()* *E6100* Returns |standard-path| locations of various default files and directories. @@ -7727,6 +10174,13 @@ stdpath({what}) *stdpath()* *E610 echo stdpath("config") < + Parameters: ~ + • {what} + (`'cache'|'config'|'config_dirs'|'data'|'data_dirs'|'log'|'run'|'state'`) + + Return: ~ + (`string|string[]`) + str2float({string} [, {quoted}]) *str2float()* Convert String {string} to a Float. This mostly works the same as when using a floating point number in an expression, @@ -7746,6 +10200,13 @@ str2float({string} [, {quoted}]) *str2float()* < Returns 0.0 if the conversion fails. + Parameters: ~ + • {string} (`string`) + • {quoted} (`boolean?`) + + Return: ~ + (`any`) + str2list({string} [, {utf8}]) *str2list()* Return a list containing the number values which represent each character in String {string}. Examples: >vim @@ -7758,6 +10219,13 @@ str2list({string} [, {utf8}]) *str2list()* With UTF-8 composing characters are handled properly: >vim echo str2list("aÌ") " returns [97, 769] + Parameters: ~ + • {string} (`string`) + • {utf8} (`boolean?`) + + Return: ~ + (`any`) + str2nr({string} [, {base}]) *str2nr()* Convert string {string} to a number. {base} is the conversion base, it can be 2, 8, 10 or 16. @@ -7777,6 +10245,13 @@ str2nr({string} [, {base}]) *str2nr()* Returns 0 if {string} is empty or on error. + Parameters: ~ + • {string} (`string`) + • {base} (`integer?`) + + Return: ~ + (`any`) + strcharlen({string}) *strcharlen()* The result is a Number, which is the number of characters in String {string}. Composing characters are ignored. @@ -7787,6 +10262,12 @@ strcharlen({string}) *strcharlen()* Also see |strlen()|, |strdisplaywidth()| and |strwidth()|. + Parameters: ~ + • {string} (`string`) + + Return: ~ + (`any`) + strcharpart({src}, {start} [, {len} [, {skipcc}]]) *strcharpart()* Like |strpart()| but using character index and length instead of byte index and length. @@ -7802,6 +10283,15 @@ strcharpart({src}, {start} [, {len} [, {skipcc}]]) *strcharpart()* Returns an empty string on error. + Parameters: ~ + • {src} (`string`) + • {start} (`integer`) + • {len} (`integer?`) + • {skipcc} (`boolean?`) + + Return: ~ + (`any`) + strchars({string} [, {skipcc}]) *strchars()* The result is a Number, which is the number of characters in String {string}. @@ -7831,6 +10321,13 @@ strchars({string} [, {skipcc}]) *strchars()* endif < + Parameters: ~ + • {string} (`string`) + • {skipcc} (`boolean?`) + + Return: ~ + (`integer`) + strdisplaywidth({string} [, {col}]) *strdisplaywidth()* The result is a Number, which is the number of display cells String {string} occupies on the screen when it starts at {col} @@ -7845,6 +10342,13 @@ strdisplaywidth({string} [, {col}]) *strdisplaywidth()* Returns zero on error. Also see |strlen()|, |strwidth()| and |strchars()|. + Parameters: ~ + • {string} (`string`) + • {col} (`integer?`) + + Return: ~ + (`integer`) + strftime({format} [, {time}]) *strftime()* The result is a String, which is a formatted date and time, as specified by the {format} string. The given {time} is used, @@ -7862,6 +10366,13 @@ strftime({format} [, {time}]) *strftime()* echo strftime("%c", getftime("file.c")) " Show mod time of file.c. + Parameters: ~ + • {format} (`string`) + • {time} (`number?`) + + Return: ~ + (`string`) + strgetchar({str}, {index}) *strgetchar()* Get a Number corresponding to the character at {index} in {str}. This uses a zero-based character index, not a byte @@ -7871,6 +10382,13 @@ strgetchar({str}, {index}) *strgetchar()* Returns -1 if {index} is invalid. Also see |strcharpart()| and |strchars()|. + Parameters: ~ + • {str} (`string`) + • {index} (`integer`) + + Return: ~ + (`integer`) + stridx({haystack}, {needle} [, {start}]) *stridx()* The result is a Number, which gives the byte index in {haystack} of the first occurrence of the String {needle}. @@ -7890,6 +10408,14 @@ stridx({haystack}, {needle} [, {start}]) *stridx()* stridx() works similar to the C function strstr(). When used with a single character it works similar to strchr(). + Parameters: ~ + • {haystack} (`string`) + • {needle} (`string`) + • {start} (`integer?`) + + Return: ~ + (`integer`) + string({expr}) *string()* Return {expr} converted to a String. If {expr} is a Number, Float, String, Blob or a composition of them, then the result @@ -7914,6 +10440,12 @@ string({expr}) *string()* method. Use |msgpackdump()| or |json_encode()| if you need to share data with other applications. + Parameters: ~ + • {expr} (`any`) + + Return: ~ + (`string`) + strlen({string}) *strlen()* The result is a Number, which is the length of the String {string} in bytes. @@ -7923,6 +10455,12 @@ strlen({string}) *strlen()* |strchars()|. Also see |len()|, |strdisplaywidth()| and |strwidth()|. + Parameters: ~ + • {string} (`string`) + + Return: ~ + (`integer`) + strpart({src}, {start} [, {len} [, {chars}]]) *strpart()* The result is a String, which is part of {src}, starting from byte {start}, with the byte length {len}. @@ -7948,6 +10486,15 @@ strpart({src}, {start} [, {len} [, {chars}]]) *strpart()* < Returns an empty string on error. + Parameters: ~ + • {src} (`string`) + • {start} (`integer`) + • {len} (`integer?`) + • {chars} (`0|1?`) + + Return: ~ + (`string`) + strptime({format}, {timestring}) *strptime()* The result is a Number, which is a unix timestamp representing the date and time in {timestring}, which is expected to match @@ -7972,6 +10519,13 @@ strptime({format}, {timestring}) *strptime()* echo strftime("%c", strptime("%Y%m%d%H%M%S", "19970427115355") + 3600) < Sun Apr 27 12:53:55 1997 + Parameters: ~ + • {format} (`string`) + • {timestring} (`string`) + + Return: ~ + (`integer`) + strridx({haystack}, {needle} [, {start}]) *strridx()* The result is a Number, which gives the byte index in {haystack} of the last occurrence of the String {needle}. @@ -7990,6 +10544,14 @@ strridx({haystack}, {needle} [, {start}]) *strridx()* When used with a single character it works similar to the C function strrchr(). + Parameters: ~ + • {haystack} (`string`) + • {needle} (`string`) + • {start} (`integer?`) + + Return: ~ + (`integer`) + strtrans({string}) *strtrans()* The result is a String, which is {string} with all unprintable characters translated into printable characters |'isprint'|. @@ -8000,6 +10562,12 @@ strtrans({string}) *strtrans()* Returns an empty string on error. + Parameters: ~ + • {string} (`string`) + + Return: ~ + (`string`) + strutf16len({string} [, {countcc}]) *strutf16len()* The result is a Number, which is the number of UTF-16 code units in String {string} (after converting it to UTF-16). @@ -8020,6 +10588,13 @@ strutf16len({string} [, {countcc}]) *strutf16len()* echo strutf16len('ąÌ', v:true) " returns 3 < + Parameters: ~ + • {string} (`string`) + • {countcc} (`0|1?`) + + Return: ~ + (`integer`) + strwidth({string}) *strwidth()* The result is a Number, which is the number of display cells String {string} occupies. A Tab character is counted as one @@ -8029,6 +10604,12 @@ strwidth({string}) *strwidth()* Returns zero on error. Also see |strlen()|, |strdisplaywidth()| and |strchars()|. + Parameters: ~ + • {string} (`string`) + + Return: ~ + (`integer`) + submatch({nr} [, {list}]) *submatch()* *E935* Only for an expression in a |:substitute| command or substitute() function. @@ -8057,6 +10638,13 @@ submatch({nr} [, {list}]) *submatch()* *E93 < This finds the first number in the line and adds one to it. A line break is included as a newline character. + Parameters: ~ + • {nr} (`integer`) + • {list} (`nil?`) + + Return: ~ + (`string`) + substitute({string}, {pat}, {sub}, {flags}) *substitute()* The result is a String, which is a copy of {string}, in which the first match of {pat} is replaced with {sub}. @@ -8100,6 +10688,15 @@ substitute({string}, {pat}, {sub}, {flags}) *substitute()* < Returns an empty string on error. + Parameters: ~ + • {string} (`string`) + • {pat} (`string`) + • {sub} (`string`) + • {flags} (`string`) + + Return: ~ + (`string`) + swapfilelist() *swapfilelist()* Returns a list of swap file names, like what "vim -r" shows. See the |-r| command argument. The 'directory' option is used @@ -8111,6 +10708,9 @@ swapfilelist() *swapfilelist()* let swapfiles = swapfilelist() let &directory = save_dir + Return: ~ + (`string[]`) + swapinfo({fname}) *swapinfo()* The result is a dictionary, which holds information about the swapfile {fname}. The available fields are: @@ -8129,6 +10729,12 @@ swapinfo({fname}) *swapinfo()* Not a swap file: does not contain correct block ID Magic number mismatch: Info in first block is invalid + Parameters: ~ + • {fname} (`string`) + + Return: ~ + (`any`) + swapname({buf}) *swapname()* The result is the swap file path of the buffer {buf}. For the use of {buf}, see |bufname()| above. @@ -8136,6 +10742,12 @@ swapname({buf}) *swapname()* |:swapname| (unless there is no swap file). If buffer {buf} has no swap file, returns an empty string. + Parameters: ~ + • {buf} (`integer|string`) + + Return: ~ + (`string`) + synID({lnum}, {col}, {trans}) *synID()* The result is a Number, which is the syntax ID at the position {lnum} and {col} in the current window. @@ -8162,6 +10774,14 @@ synID({lnum}, {col}, {trans}) *synID()* echo synIDattr(synID(line("."), col("."), 1), "name") < + Parameters: ~ + • {lnum} (`integer`) + • {col} (`integer`) + • {trans} (`0|1`) + + Return: ~ + (`integer`) + synIDattr({synID}, {what} [, {mode}]) *synIDattr()* The result is a String, which is the {what} attribute of syntax ID {synID}. This can be used to obtain information @@ -8208,6 +10828,14 @@ synIDattr({synID}, {what} [, {mode}]) *synIDattr()* echo synID(line("."), col("."), 1)->synIDtrans()->synIDattr("fg") < + Parameters: ~ + • {synID} (`integer`) + • {what} (`string`) + • {mode} (`string?`) + + Return: ~ + (`string`) + synIDtrans({synID}) *synIDtrans()* The result is a Number, which is the translated syntax ID of {synID}. This is the syntax group ID of what is being used to @@ -8216,6 +10844,12 @@ synIDtrans({synID}) *synIDtrans()* Returns zero on error. + Parameters: ~ + • {synID} (`integer`) + + Return: ~ + (`integer`) + synconcealed({lnum}, {col}) *synconcealed()* The result is a |List| with currently three items: 1. The first item in the list is 0 if the character at the @@ -8245,6 +10879,13 @@ synconcealed({lnum}, {col}) *synconcealed()* since syntax and matching highlighting are two different mechanisms |syntax-vs-match|. + Parameters: ~ + • {lnum} (`integer`) + • {col} (`integer`) + + Return: ~ + (`[integer, string, integer]`) + synstack({lnum}, {col}) *synstack()* Return a |List|, which is the stack of syntax items at the position {lnum} and {col} in the current window. {lnum} is @@ -8264,6 +10905,13 @@ synstack({lnum}, {col}) *synstack()* character in a line and the first column in an empty line are valid positions. + Parameters: ~ + • {lnum} (`integer`) + • {col} (`integer`) + + Return: ~ + (`integer[]`) + system({cmd} [, {input}]) *system()* *E677* Note: Prefer |vim.system()| in Lua. @@ -8313,6 +10961,13 @@ system({cmd} [, {input}]) *system()* *E67 < Unlike ":!cmd" there is no automatic check for changed files. Use |:checktime| to force a check. + Parameters: ~ + • {cmd} (`string|string[]`) + • {input} (`string|string[]|integer?`) + + Return: ~ + (`string`) + systemlist({cmd} [, {input} [, {keepempty}]]) *systemlist()* Same as |system()|, but returns a |List| with lines (parts of output separated by NL) with NULs transformed into NLs. Output @@ -8327,6 +10982,14 @@ systemlist({cmd} [, {input} [, {keepempty}]]) *systemlist()* < Returns an empty string on error. + Parameters: ~ + • {cmd} (`string|string[]`) + • {input} (`string|string[]|integer?`) + • {keepempty} (`integer?`) + + Return: ~ + (`string[]`) + tabpagebuflist([{arg}]) *tabpagebuflist()* The result is a |List|, where each item is the number of the buffer associated with each window in the current tab page. @@ -8340,6 +11003,12 @@ tabpagebuflist([{arg}]) *tabpagebuflist()* endfor < Note that a buffer may appear in more than one window. + Parameters: ~ + • {arg} (`integer?`) + + Return: ~ + (`any`) + tabpagenr([{arg}]) *tabpagenr()* The result is a Number, which is the number of the current tab page. The first tab page has number 1. @@ -8354,6 +11023,12 @@ tabpagenr([{arg}]) *tabpagenr()* Returns zero on error. + Parameters: ~ + • {arg} (`'$'|'#'?`) + + Return: ~ + (`integer`) + tabpagewinnr({tabarg} [, {arg}]) *tabpagewinnr()* Like |winnr()| but for tab page {tabarg}. {tabarg} specifies the number of tab page to be used. @@ -8367,10 +11042,20 @@ tabpagewinnr({tabarg} [, {arg}]) *tabpagewinnr()* tabpagewinnr(4, '$') " number of windows in tab page 4 < When {tabarg} is invalid zero is returned. + Parameters: ~ + • {tabarg} (`integer`) + • {arg} (`'$'|'#'?`) + + Return: ~ + (`integer`) + tagfiles() *tagfiles()* Returns a |List| with the file names used to search for tags for the current buffer. This is the 'tags' option expanded. + Return: ~ + (`string[]`) + taglist({expr} [, {filename}]) *taglist()* Returns a |List| of tags matching the regular expression {expr}. @@ -8414,6 +11099,13 @@ taglist({expr} [, {filename}]) *taglist()* located by Vim. Refer to |tags-file-format| for the format of the tags file generated by the different ctags tools. + Parameters: ~ + • {expr} (`any`) + • {filename} (`string?`) + + Return: ~ + (`any`) + tan({expr}) *tan()* Return the tangent of {expr}, measured in radians, as a |Float| in the range [-inf, inf]. @@ -8425,6 +11117,12 @@ tan({expr}) *tan()* echo tan(-4.01) < -1.181502 + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`number`) + tanh({expr}) *tanh()* Return the hyperbolic tangent of {expr} as a |Float| in the range [-1, 1]. @@ -8436,6 +11134,12 @@ tanh({expr}) *tanh()* echo tanh(-1) < -0.761594 + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`number`) + tempname() *tempname()* Generates a (non-existent) filename located in the Nvim root |tempdir|. Scripts can use the filename as a temporary file. @@ -8444,6 +11148,9 @@ tempname() *tempname()* exe "redir > " .. tmpfile < + Return: ~ + (`string`) + termopen({cmd} [, {opts}]) *termopen()* Spawns {cmd} in a new pseudo-terminal session connected to the current (unmodified) buffer. Parameters and behavior @@ -8459,11 +11166,21 @@ termopen({cmd} [, {opts}]) *termopen()* except $TERM is set to "xterm-256color". Full behavior is described in |terminal|. + Parameters: ~ + • {cmd} (`string|string[]`) + • {opts} (`table?`) + + Return: ~ + (`any`) + test_garbagecollect_now() *test_garbagecollect_now()* Like |garbagecollect()|, but executed right away. This must only be called directly to avoid any structure to exist internally, and |v:testing| must have been set before calling - any function. + any function. *E1142* + + Return: ~ + (`any`) timer_info([{id}]) *timer_info()* Return a list with information about timers. @@ -8480,6 +11197,12 @@ timer_info([{id}]) *timer_info()* -1 means forever "callback" the callback + Parameters: ~ + • {id} (`integer?`) + + Return: ~ + (`any`) + timer_pause({timer}, {paused}) *timer_pause()* Pause or unpause a timer. A paused timer does not invoke its callback when its time expires. Unpausing a timer may cause @@ -8493,6 +11216,13 @@ timer_pause({timer}, {paused}) *timer_pause()* String, then the timer is paused, otherwise it is unpaused. See |non-zero-arg|. + Parameters: ~ + • {timer} (`integer`) + • {paused} (`boolean`) + + Return: ~ + (`any`) + timer_start({time}, {callback} [, {options}]) *timer_start()* *timer* Create a timer and return the timer ID. @@ -8523,26 +11253,55 @@ timer_start({time}, {callback} [, {options}]) *timer_start()* *time \ {'repeat': 3}) < This invokes MyHandler() three times at 500 msec intervals. + Parameters: ~ + • {time} (`number`) + • {callback} (`string|function`) + • {options} (`table?`) + + Return: ~ + (`any`) + timer_stop({timer}) *timer_stop()* Stop a timer. The timer callback will no longer be invoked. {timer} is an ID returned by timer_start(), thus it must be a Number. If {timer} does not exist there is no error. + Parameters: ~ + • {timer} (`integer`) + + Return: ~ + (`any`) + timer_stopall() *timer_stopall()* Stop all timers. The timer callbacks will no longer be invoked. Useful if some timers is misbehaving. If there are no timers there is no error. + Return: ~ + (`any`) + tolower({expr}) *tolower()* The result is a copy of the String given, with all uppercase characters turned into lowercase (just like applying |gu| to the string). Returns an empty string on error. + Parameters: ~ + • {expr} (`string`) + + Return: ~ + (`string`) + toupper({expr}) *toupper()* The result is a copy of the String given, with all lowercase characters turned into uppercase (just like applying |gU| to the string). Returns an empty string on error. + Parameters: ~ + • {expr} (`string`) + + Return: ~ + (`string`) + tr({src}, {fromstr}, {tostr}) *tr()* The result is a copy of the {src} string with all characters which appear in {fromstr} replaced by the character in that @@ -8559,6 +11318,14 @@ tr({src}, {fromstr}, {tostr}) *tr()* echo tr("<blob>", "<>", "{}") < returns "{blob}" + Parameters: ~ + • {src} (`string`) + • {fromstr} (`string`) + • {tostr} (`string`) + + Return: ~ + (`string`) + trim({text} [, {mask} [, {dir}]]) *trim()* Return {text} as a String where any character in {mask} is removed from the beginning and/or end of {text}. @@ -8587,6 +11354,14 @@ trim({text} [, {mask} [, {dir}]]) *trim()* echo trim(" vim ", " ", 2) < returns " vim" + Parameters: ~ + • {text} (`string`) + • {mask} (`string?`) + • {dir} (`0|1|2?`) + + Return: ~ + (`string`) + trunc({expr}) *trunc()* Return the largest integral value with magnitude less than or equal to {expr} as a |Float| (truncate towards zero). @@ -8600,6 +11375,12 @@ trunc({expr}) *trunc()* echo trunc(4.0) < 4.0 + Parameters: ~ + • {expr} (`number`) + + Return: ~ + (`integer`) + type({expr}) *type()* The result is a Number representing the type of {expr}. Instead of using the number directly, it is better to use the @@ -8626,6 +11407,13 @@ type({expr}) *type()* if myvar is v:null | endif < To check if the v:t_ variables exist use this: >vim if exists('v:t_number') | endif +< + + Parameters: ~ + • {expr} (`any`) + + Return: ~ + (`integer`) undofile({name}) *undofile()* Return the name of the undo file that would be used for a file @@ -8638,6 +11426,12 @@ undofile({name}) *undofile()* buffer without a file name will not write an undo file. Useful in combination with |:wundo| and |:rundo|. + Parameters: ~ + • {name} (`string`) + + Return: ~ + (`string`) + undotree([{buf}]) *undotree()* Return the current state of the undo tree for the current buffer, or for a specific buffer if {buf} is given. The @@ -8682,6 +11476,12 @@ undotree([{buf}]) *undotree()* blocks. Each item may again have an "alt" item. + Parameters: ~ + • {buf} (`integer|string?`) + + Return: ~ + (`vim.fn.undotree.ret`) + uniq({list} [, {func} [, {dict}]]) *uniq()* *E882* Remove second and succeeding copies of repeated adjacent {list} items in-place. Returns {list}. If you want a list @@ -8692,6 +11492,14 @@ uniq({list} [, {func} [, {dict}]]) *uniq()* *E88 Returns zero if {list} is not a |List|. + Parameters: ~ + • {list} (`any`) + • {func} (`any?`) + • {dict} (`any?`) + + Return: ~ + (`any[]|0`) + utf16idx({string}, {idx} [, {countcc} [, {charidx}]]) *utf16idx()* Same as |charidx()| but returns the UTF-16 code unit index of the byte at {idx} in {string} (after converting it to UTF-16). @@ -8720,11 +11528,26 @@ utf16idx({string}, {idx} [, {countcc} [, {charidx}]]) *utf16idx()* echo utf16idx('a😊😊', 9) " returns -1 < + Parameters: ~ + • {string} (`string`) + • {idx} (`integer`) + • {countcc} (`boolean?`) + • {charidx} (`boolean?`) + + Return: ~ + (`integer`) + values({dict}) *values()* Return a |List| with all the values of {dict}. The |List| is in arbitrary order. Also see |items()| and |keys()|. Returns zero if {dict} is not a |Dict|. + Parameters: ~ + • {dict} (`any`) + + Return: ~ + (`any`) + virtcol({expr} [, {list} [, {winid}]]) *virtcol()* The result is a Number, which is the screen column of the file position given with {expr}. That is, the last screen position @@ -8735,7 +11558,9 @@ virtcol({expr} [, {list} [, {winid}]]) *virtcol()* set to 8, it returns 8. |conceal| is ignored. For the byte position use |col()|. - For the use of {expr} see |col()|. + For the use of {expr} see |getpos()| and |col()|. + When {expr} is "$", it means the end of the cursor line, so + the result is the number of cells in the cursor line plus one. When 'virtualedit' is used {expr} can be [lnum, col, off], where "off" is the offset in screen columns from the start of @@ -8745,18 +11570,6 @@ virtcol({expr} [, {list} [, {winid}]]) *virtcol()* beyond the end of the line can be returned. Also see |'virtualedit'| - The accepted positions are: - . the cursor position - $ the end of the cursor line (the result is the - number of displayed characters in the cursor line - plus one) - 'x position of mark x (if the mark is not set, 0 is - returned) - v In Visual mode: the start of the Visual area (the - cursor is the end). When not in Visual mode - returns the cursor position. Differs from |'<| in - that it's updated right away. - If {list} is present and non-zero then virtcol() returns a List with the first and last screen position occupied by the character. @@ -8775,10 +11588,21 @@ virtcol({expr} [, {list} [, {winid}]]) *virtcol()* " With text " there", with 't at 'h': echo virtcol("'t") " returns 6 -< The first column is 1. 0 or [0, 0] is returned for an error. +< + The first column is 1. 0 or [0, 0] is returned for an error. + A more advanced example that echoes the maximum length of all lines: >vim echo max(map(range(1, line('$')), "virtcol([v:val, '$'])")) +< + + Parameters: ~ + • {expr} (`string|integer[]`) + • {list} (`boolean?`) + • {winid} (`integer?`) + + Return: ~ + (`any`) virtcol2col({winid}, {lnum}, {col}) *virtcol2col()* The result is a Number, which is the byte index of the @@ -8802,6 +11626,14 @@ virtcol2col({winid}, {lnum}, {col}) *virtcol2col()* See also |screenpos()|, |virtcol()| and |col()|. + Parameters: ~ + • {winid} (`integer`) + • {lnum} (`integer`) + • {col} (`integer`) + + Return: ~ + (`any`) + visualmode([{expr}]) *visualmode()* The result is a String, which describes the last Visual mode used in the current buffer. Initially it returns an empty @@ -8820,6 +11652,12 @@ visualmode([{expr}]) *visualmode()* a non-empty String, then the Visual mode will be cleared and the old value is returned. See |non-zero-arg|. + Parameters: ~ + • {expr} (`boolean?`) + + Return: ~ + (`any`) + wait({timeout}, {condition} [, {interval}]) *wait()* Waits until {condition} evaluates to |TRUE|, where {condition} is a |Funcref| or |string| containing an expression. @@ -8836,6 +11674,14 @@ wait({timeout}, {condition} [, {interval}]) *wait()* -2 if the function was interrupted (by |CTRL-C|) -3 if an error occurred + Parameters: ~ + • {timeout} (`integer`) + • {condition} (`any`) + • {interval} (`number?`) + + Return: ~ + (`any`) + wildmenumode() *wildmenumode()* Returns |TRUE| when the wildmenu is active and |FALSE| otherwise. See 'wildmenu' and 'wildmode'. @@ -8847,6 +11693,9 @@ wildmenumode() *wildmenumode()* < (Note, this needs the 'wildcharm' option set appropriately). + Return: ~ + (`any`) + win_execute({id}, {command} [, {silent}]) *win_execute()* Like `execute()` but in the context of window {id}. The window will temporarily be made the current window, @@ -8861,10 +11710,24 @@ win_execute({id}, {command} [, {silent}]) *win_execute()* When window {id} does not exist then no error is given and an empty string is returned. + Parameters: ~ + • {id} (`integer`) + • {command} (`string`) + • {silent} (`boolean?`) + + Return: ~ + (`any`) + win_findbuf({bufnr}) *win_findbuf()* Returns a |List| with |window-ID|s for windows that contain buffer {bufnr}. When there is none the list is empty. + Parameters: ~ + • {bufnr} (`integer`) + + Return: ~ + (`integer[]`) + win_getid([{win} [, {tab}]]) *win_getid()* Get the |window-ID| for the specified window. When {win} is missing use the current window. @@ -8874,6 +11737,13 @@ win_getid([{win} [, {tab}]]) *win_getid()* number {tab}. The first tab has number one. Return zero if the window cannot be found. + Parameters: ~ + • {win} (`integer?`) + • {tab} (`integer?`) + + Return: ~ + (`integer`) + win_gettype([{nr}]) *win_gettype()* Return the type of the window: "autocmd" autocommand window. Temporary window @@ -8892,20 +11762,44 @@ win_gettype([{nr}]) *win_gettype()* Also see the 'buftype' option. + Parameters: ~ + • {nr} (`integer?`) + + Return: ~ + (`'autocmd'|'command'|''|'loclist'|'popup'|'preview'|'quickfix'|'unknown'`) + win_gotoid({expr}) *win_gotoid()* Go to window with ID {expr}. This may also change the current tabpage. Return TRUE if successful, FALSE if the window cannot be found. + Parameters: ~ + • {expr} (`integer`) + + Return: ~ + (`0|1`) + win_id2tabwin({expr}) *win_id2tabwin()* Return a list with the tab number and window number of window with ID {expr}: [tabnr, winnr]. Return [0, 0] if the window cannot be found. + Parameters: ~ + • {expr} (`integer`) + + Return: ~ + (`any`) + win_id2win({expr}) *win_id2win()* Return the window number of window with ID {expr}. Return 0 if the window cannot be found in the current tabpage. + Parameters: ~ + • {expr} (`integer`) + + Return: ~ + (`any`) + win_move_separator({nr}, {offset}) *win_move_separator()* Move window {nr}'s vertical separator (i.e., the right border) by {offset} columns, as if being dragged by the mouse. {nr} @@ -8921,6 +11815,13 @@ win_move_separator({nr}, {offset}) *win_move_separator()* window, since it has no separator on the right. Only works for the current tab page. *E1308* + Parameters: ~ + • {nr} (`integer`) + • {offset} (`integer`) + + Return: ~ + (`any`) + win_move_statusline({nr}, {offset}) *win_move_statusline()* Move window {nr}'s status line (i.e., the bottom border) by {offset} rows, as if being dragged by the mouse. {nr} can be a @@ -8933,6 +11834,13 @@ win_move_statusline({nr}, {offset}) *win_move_statusline()* be found and FALSE otherwise. Only works for the current tab page. + Parameters: ~ + • {nr} (`integer`) + • {offset} (`integer`) + + Return: ~ + (`any`) + win_screenpos({nr}) *win_screenpos()* Return the screen position of window {nr} as a list with two numbers: [row, col]. The first window always has position @@ -8941,6 +11849,12 @@ win_screenpos({nr}) *win_screenpos()* for the current window. Returns [0, 0] if the window cannot be found. + Parameters: ~ + • {nr} (`integer`) + + Return: ~ + (`any`) + win_splitmove({nr}, {target} [, {options}]) *win_splitmove()* Temporarily switch to window {target}, then move window {nr} to a new split adjacent to {target}. @@ -8961,6 +11875,14 @@ win_splitmove({nr}, {target} [, {options}]) *win_splitmove()* present, the values of 'splitbelow' and 'splitright' are used. + Parameters: ~ + • {nr} (`integer`) + • {target} (`integer`) + • {options} (`table?`) + + Return: ~ + (`any`) + winbufnr({nr}) *winbufnr()* The result is a Number, which is the number of the buffer associated with window {nr}. {nr} can be the window number or @@ -8972,17 +11894,29 @@ winbufnr({nr}) *winbufnr()* echo "The file in the current window is " .. bufname(winbufnr(0)) < + Parameters: ~ + • {nr} (`integer`) + + Return: ~ + (`integer`) + wincol() *wincol()* The result is a Number, which is the virtual column of the cursor in the window. This is counting screen cells from the left side of the window. The leftmost column is one. + Return: ~ + (`integer`) + windowsversion() *windowsversion()* The result is a String. For MS-Windows it indicates the OS version. E.g, Windows 10 is "10.0", Windows 8 is "6.2", Windows XP is "5.1". For non-MS-Windows systems the result is an empty string. + Return: ~ + (`string`) + winheight({nr}) *winheight()* The result is a Number, which is the height of window {nr}. {nr} can be the window number or the |window-ID|. @@ -8992,6 +11926,13 @@ winheight({nr}) *winheight()* This excludes any window toolbar line. Examples: >vim echo "The current window has " .. winheight(0) .. " lines." +< + + Parameters: ~ + • {nr} (`integer`) + + Return: ~ + (`integer`) winlayout([{tabnr}]) *winlayout()* The result is a nested List containing the layout of windows @@ -9030,6 +11971,12 @@ winlayout([{tabnr}]) *winlayout()* ['leaf', 1001]]], ['leaf', 1000]]] < + Parameters: ~ + • {tabnr} (`integer?`) + + Return: ~ + (`any`) + winline() *winline()* The result is a Number, which is the screen line of the cursor in the window. This is counting screen lines from the top of @@ -9037,6 +11984,9 @@ winline() *winline()* If the cursor was moved the view on the file will be updated first, this may cause a scroll. + Return: ~ + (`integer`) + winnr([{arg}]) *winnr()* The result is a Number, which is the number of the current window. The top window has number 1. @@ -9067,6 +12017,13 @@ winnr([{arg}]) *winnr()* let window_count = winnr('$') let prev_window = winnr('#') let wnum = winnr('3k') +< + + Parameters: ~ + • {arg} (`string|integer?`) + + Return: ~ + (`any`) winrestcmd() *winrestcmd()* Returns a sequence of |:resize| commands that should restore @@ -9079,6 +12036,9 @@ winrestcmd() *winrestcmd()* exe cmd < + Return: ~ + (`any`) + winrestview({dict}) *winrestview()* Uses the |Dictionary| returned by |winsaveview()| to restore the view of the current window. @@ -9095,6 +12055,12 @@ winrestview({dict}) *winrestview()* If you have changed the values the result is unpredictable. If the window size changed the result won't be the same. + Parameters: ~ + • {dict} (`vim.fn.winrestview.dict`) + + Return: ~ + (`any`) + winsaveview() *winsaveview()* Returns a |Dictionary| that contains information to restore the view of the current window. Use |winrestview()| to @@ -9122,6 +12088,9 @@ winsaveview() *winsaveview()* skipcol columns skipped Note that no option values are saved. + Return: ~ + (`vim.fn.winsaveview.ret`) + winwidth({nr}) *winwidth()* The result is a Number, which is the width of window {nr}. {nr} can be the window number or the |window-ID|. @@ -9136,6 +12105,12 @@ winwidth({nr}) *winwidth()* < For getting the terminal or screen size, see the 'columns' option. + Parameters: ~ + • {nr} (`integer`) + + Return: ~ + (`any`) + wordcount() *wordcount()* The result is a dictionary of byte/chars/word statistics for the current buffer. This is the same info as provided by @@ -9157,6 +12132,9 @@ wordcount() *wordcount()* visual_words Number of words visually selected (only in Visual mode) + Return: ~ + (`any`) + writefile({object}, {fname} [, {flags}]) *writefile()* When {object} is a |List| write it to file {fname}. Each list item is separated with a NL. Each list item must be a String @@ -9202,6 +12180,15 @@ writefile({object}, {fname} [, {flags}]) *writefile()* To copy a file byte for byte: >vim let fl = readfile("foo", "b") call writefile(fl, "foocopy", "b") +< + + Parameters: ~ + • {object} (`any`) + • {fname} (`string`) + • {flags} (`string?`) + + Return: ~ + (`any`) xor({expr}, {expr}) *xor()* Bitwise XOR on the two arguments. The arguments are converted @@ -9211,6 +12198,13 @@ xor({expr}, {expr}) *xor()* let bits = xor(bits, 0x80) < + Parameters: ~ + • {expr} (`number`) + • {expr1} (`number`) + + Return: ~ + (`any`) + ============================================================================== 2. Matching a pattern in a String *string-match* diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt index 9ff16165d7..928b834600 100644 --- a/runtime/doc/change.txt +++ b/runtime/doc/change.txt @@ -1227,13 +1227,13 @@ Vim fills these registers with text from yank and delete commands. Numbered register 0 contains the text from the most recent yank command, unless the command specified another register with ["x]. Numbered register 1 contains the text deleted by the most recent delete or -change command, unless the command specified another register or the text is -less than one line (the small delete register is used then). An exception is -made for the delete operator with these movement commands: |%|, |(|, |)|, |`|, -|/|, |?|, |n|, |N|, |{| and |}|. Register "1 is always used then (this is Vi -compatible). The "- register is used as well if the delete is within a line. -Note that these characters may be mapped. E.g. |%| is mapped by the matchit -plugin. +change command (even when the command specified another register), unless the +text is less than one line (the small delete register is used then). An +exception is made for the delete operator with these movement commands: |%|, +|(|, |)|, |`|, |/|, |?|, |n|, |N|, |{| and |}|. +Register "1 is always used then (this is Vi compatible). The "- register is +used as well if the delete is within a line. Note that these characters may be +mapped. E.g. |%| is mapped by the matchit plugin. With each successive deletion or change, Vim shifts the previous contents of register 1 into register 2, 2 into 3, and so forth, losing the previous contents of register 9. diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt index f306067a9c..7967e2ce1a 100644 --- a/runtime/doc/cmdline.txt +++ b/runtime/doc/cmdline.txt @@ -348,7 +348,8 @@ terminals) :keepp[atterns] {command} *:keepp* *:keeppatterns* Execute {command}, without adding anything to the search - history + history and, in case of |:s| or |:&|, without modifying the + last substitute pattern or substitute string. ============================================================================== 2. Command-line completion *cmdline-completion* @@ -448,13 +449,13 @@ The 'wildignorecase' option can be set to ignore case in filenames. For completing other texts (e.g. command names), the 'ignorecase' option is used instead (fuzzy matching always ignores case, however). -If you like tcsh's autolist completion, you can use this mapping: +If you like tcsh's autolist completion, you can use this mapping: > :cnoremap X <C-L><C-D> (Where X is the command key to use, <C-L> is CTRL-L and <C-D> is CTRL-D) This will find the longest match and then list all matching files. If you like tcsh's autolist completion, you can use the 'wildmode' option to -emulate it. For example, this mimics autolist=ambiguous: +emulate it. For example, this mimics autolist=ambiguous: > :set wildmode=longest,list This will find the longest match with the first 'wildchar', then list all matching files with the next. diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt index 646ba72bd8..72d2faca02 100644 --- a/runtime/doc/deprecated.txt +++ b/runtime/doc/deprecated.txt @@ -19,6 +19,22 @@ API - nvim_subscribe() Plugins must maintain their own "multicast" channels list. - nvim_unsubscribe() Plugins must maintain their own "multicast" channels list. +LUA +- vim.region() Use |getregionpos()| instead. + +DIAGNOSTICS +- *vim.diagnostic.goto_next()* Use |vim.diagnostic.jump()| with `{count=1, float=true}` instead. +- *vim.diagnostic.goto_prev()* Use |vim.diagnostic.jump()| with `{count=-1, float=true}` instead. +- *vim.diagnostic.get_next_pos()* + Use the "lnum" and "col" fields from the return value of + |vim.diagnostic.get_next()| instead. +- *vim.diagnostic.get_prev_pos()* + Use the "lnum" and "col" fields from the return value of + |vim.diagnostic.get_prev()| instead. +- The "win_id" parameter used by various functions is deprecated in favor of + "winid" |winid| +- The "cursor_position" parameter of |vim.diagnostic.JumpOpts| is renamed to + "pos" ------------------------------------------------------------------------------ DEPRECATED IN 0.10 *deprecated-0.10* @@ -157,6 +173,7 @@ FUNCTIONS - *jobclose()* Obsolete name for |chanclose()| - *jobsend()* Obsolete name for |chansend()| - *last_buffer_nr()* Obsolete name for bufnr("$"). +- *rpcstart()* Use |jobstart()| with `{'rpc': v:true}` instead. - *rpcstop()* Use |jobstop()| instead to stop any job, or `chanclose(id, "rpc")` to close RPC communication without stopping the job. Use chanclose(id) to close @@ -202,9 +219,6 @@ internally and are no longer exposed as part of the API. Instead, use - *vim.lsp.diagnostic.set_underline()* - *vim.lsp.diagnostic.set_virtual_text()* -Configuring |diagnostic-signs| with |:sign-define| or |sign_define()| is no -longer supported. Use the "signs" key of |vim.diagnostic.config()| instead. - LSP FUNCTIONS - *vim.lsp.buf.server_ready()* Use |LspAttach| instead, depending on your use-case. "Server ready" is not diff --git a/runtime/doc/dev_arch.txt b/runtime/doc/dev_arch.txt new file mode 100644 index 0000000000..1cb3b9ad67 --- /dev/null +++ b/runtime/doc/dev_arch.txt @@ -0,0 +1,59 @@ +*dev_arch.txt* Nvim + + + NVIM REFERENCE MANUAL + + +How to develop Nvim, explanation of modules and subsystems *dev-arch* + +The top of each major module has (or should have) an overview in a comment at +the top of its file. The purpose of this document is to give: + +1. an overview of how it all fits together +2. how-to guides for common tasks such as: + - deprecating public functions + - adding a new public (API) function + - adding a new public (UI) event +3. TODO: move src/nvim/README.md into this doc. + + Type |gO| to see the table of contents. + +============================================================================== +Data structures + +Use `kvec.h` for most lists. When you absolutely need a linked list, use +`lib/queue_defs.h` which defines an "intrusive" linked list. + +============================================================================== +UI events + +The source files most directly involved with UI events are: +1. `src/nvim/ui.*`: calls handler functions of registered UI structs (independent from msgpack-rpc) +2. `src/nvim/api/ui.*`: forwards messages over msgpack-rpc to remote UIs. + +UI events are defined in `src/nvim/api/ui_events.in.h` , this file is not +compiled directly, rather it parsed by +`src/nvim/generators/gen_api_ui_events.lua` which autogenerates wrapper +functions used by the source files above. It also generates metadata +accessible as `api_info().ui_events`. + +See commit d3a8e9217f39c59dd7762bd22a76b8bd03ca85ff for an example of adding +a new UI event. + +UI events are deferred to UIs, which implies a deepcopy of the UI event data. + +Remember to bump NVIM_API_LEVEL if it wasn't already during this development +cycle. + +Other references: +* |msgpack-rpc| +* |ui| +* https://github.com/neovim/neovim/pull/3246 +* https://github.com/neovim/neovim/pull/18375 +* https://github.com/neovim/neovim/pull/21605 + + + +============================================================================== + +vim:tw=78:ts=8:sw=4:et:ft=help:norl: diff --git a/runtime/doc/dev_style.txt b/runtime/doc/dev_style.txt index 6c805963a9..32f7279704 100644 --- a/runtime/doc/dev_style.txt +++ b/runtime/doc/dev_style.txt @@ -95,9 +95,9 @@ variable is and what it was initialized to. In particular, initialization should be used instead of declaration and assignment, e.g. >c int i; - i = f(); // BAD: initialization separate from declaration. + i = f(); // âŒ: initialization separate from declaration. - int j = g(); // GOOD: declaration has initialization. + int j = g(); // ✅: declaration has initialization. Initialization ~ @@ -107,16 +107,13 @@ but each initialization should be done on a separate line. >c int i; - int j; // GOOD - - int i, j; // GOOD: multiple declarations, no initialization. - + int j; // ✅ + int i, j; // ✅: multiple declarations, no initialization. int i = 0; - int j = 0; // GOOD: one initialization per line. - - int i = 0, j; // BAD: multiple declarations with initialization. + int j = 0; // ✅: one initialization per line. - int i = 0, j = 0; // BAD: multiple declarations with initialization. + int i = 0, j; // âŒ: multiple declarations with initialization. + int i = 0, j = 0; // âŒ: multiple declarations with initialization. ============================================================================== Nvim-Specific Magic @@ -152,10 +149,10 @@ Postincrement and Postdecrement ~ Use postfix form (`i++`) in statements. >c for (int i = 0; i < 3; i++) { } - int j = ++i; // OK: ++i is used as an expression. + int j = ++i; // ✅: ++i is used as an expression. for (int i = 0; i < 3; ++i) { } - ++i; // BAD: ++i is used as a statement. + ++i; // âŒ: ++i is used as a statement. Use of const ~ @@ -217,7 +214,7 @@ Booleans ~ Use `bool` to represent boolean values. >c - int loaded = 1; // BAD: loaded should have type bool. + int loaded = 1; // âŒ: loaded should have type bool. Conditions ~ @@ -382,7 +379,7 @@ Filenames should be all lowercase and can include underscores (`_`). Use underscores to separate words. Examples of acceptable file names: > my_useful_file.c - getline_fix.c // OK: getline refers to the glibc function. + getline_fix.c // ✅: getline refers to the glibc function. C files should end in `.c` and header files should end in `.h`. @@ -415,10 +412,10 @@ instance: `my_exciting_local_variable`. For example: >c - string table_name; // OK: uses underscore. - string tablename; // OK: all lowercase. + string table_name; // ✅: uses underscore. + string tablename; // ✅: all lowercase. - string tableName; // BAD: mixed case. + string tableName; // âŒ: mixed case. < Struct Variables ~ diff --git a/runtime/doc/dev_tools.txt b/runtime/doc/dev_tools.txt index 52513db31d..efc6ce277a 100644 --- a/runtime/doc/dev_tools.txt +++ b/runtime/doc/dev_tools.txt @@ -7,7 +7,9 @@ Tools and techniques for developing Nvim *dev-tools* The following advice is helpful when working on or debugging issues with Nvim -itself. See also |debug.txt| for advice that applies to Vim. +itself. + +TODO: merge |debug.txt| into here. Type |gO| to see the table of contents. diff --git a/runtime/doc/dev_vimpatch.txt b/runtime/doc/dev_vimpatch.txt index d6e4ced054..5119613b55 100644 --- a/runtime/doc/dev_vimpatch.txt +++ b/runtime/doc/dev_vimpatch.txt @@ -139,7 +139,6 @@ TYPES OF "NOT APPLICABLE" VIM PATCHES ~ - NA files: `src/gui_*`, `src/gvim_*`, `src/GvimExt/*`, `src/testdir/test_gui*` - `balloon` changes: Nvim does not support balloon feature - NA files: `src/beval_*`, `src/testdir/test_balloon_*` -- libvterm changes: Nvim does not vendor libvterm in `src/`. - Screendump tests from `test_popupwin.vim`, `test_popupwin_textprop.vim`: https://github.com/neovim/neovim/pull/12741#issuecomment-704677141 - json changes: incompatible API https://github.com/neovim/neovim/pull/4131 @@ -204,6 +203,8 @@ information. mb_ptr2char utf_ptr2char mb_head_off utf_head_off mb_tail_off utf_cp_bounds + mb_strnicmp2 utf_strnicmp + MB_STRNICMP2 utf_strnicmp mb_lefthalve grid_lefthalve mb_fix_col grid_fix_col utf_off2cells grid_off2cells @@ -302,4 +303,58 @@ used in new documentation: - `{Only when compiled with ...}`: the vast majority of features have been made non-optional (see https://github.com/neovim/neovim/wiki/Introduction) +============================================================================== +FILETYPE DETECTION *dev-vimpatch-filetype* + +Nvim's filetype detection behavior matches Vim, but is implemented as part of +|vim.filetype| (see `$VIMRUNTIME/lua/vim/filetype.lua`). The logic is encoded in +three tables, listed in order of precedence (the first match is returned): +1. `filename` for literal full path or basename lookup; +2. `pattern` for matching filenames or paths against |lua-patterns|, optimized + for fast lookup; +3. `extension` for literal extension lookup. + +Logic that requires checking file contents or buffer variables is implemented +in `$VIMRUNTIME/lua/vim/filetype/detect.lua`. + +When porting filetype patches from Vim, keep the following in mind: + +Prefer explicit filenames or extensions over patterns, especially for case +insensitive matches (see https://github.com/neovim/neovim/pull/29800): > + "*[mM]akefile" regex -> "makefile", "Makefile" filenames + "*.js\c" regex -> "js", "jS", "Js", "jS" extensions + +Pattern matching has several differences: +- It is done using explicit Lua patterns without implicit anchoring instead + of Vim regexes: > + "*/debian/changelog" -> "/debian/changelog$" + "*/bind/db.*" -> "/bind/db%." +< +- Filetype patterns are grouped by their parent pattern to improve matching + performance: If the parent pattern does not match, skip testing all child + patterns. Note that unlike leaf patterns, parent patterns do not have + special matching behaviour if they contain a `/`. + + When adding a new filetype with pattern matching, consider the following: + - If there is already a group with appropriate parent pattern, use it. + - If there can be a fast and specific enough pattern to group at least 3 + filetype patterns, add it as a separate grouped entry. + + New parent patterns should be + - fast: rule of thumb is that it should be a short explicit string + (i.e. no quantifiers or character sets); + - specific: rules of thumb, in order: + - full directory name (e.g., `"/etc/"`, `"/log/"`); + - part of a rare enough directory name (e.g., `"/conf"`, `"git/"`); + - string rarely used in real full paths (e.g., `"nginx"`). + + Example: + - Filetype pattern: `".*/etc/a2ps/.*%.cfg"` + - Good parents: `"/etc/"` or `"%.cfg$"` + - Bad parents: `"%."` (fast but not specific) or `"/a2ps/.*%."` (specific + but slow) + + When modifying an existing regular pattern, make sure that it still fits its + group. + vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt index d7837dc2fe..a61c569a67 100644 --- a/runtime/doc/develop.txt +++ b/runtime/doc/develop.txt @@ -7,8 +7,8 @@ Development of Nvim *development* *dev* This reference describes design constraints and guidelines, for developing -Nvim applications or Nvim itself. -Architecture and internal concepts are covered in src/nvim/README.md +Nvim applications or Nvim itself. See |dev-arch| for discussion of Nvim's +architecture and internal concepts. Nvim is free and open source. Everybody is encouraged to contribute. https://github.com/neovim/neovim/blob/master/CONTRIBUTING.md @@ -138,15 +138,15 @@ DOCUMENTATION *dev-doc* - Write docstrings (as opposed to inline comments) with present tense ("Gets"), not imperative ("Get"). This tends to reduce ambiguity and improve clarity by describing "What" instead of "How". > - GOOD: + ✅ OK: /// Gets a highlight definition. - BAD: + ⌠NO: /// Get a highlight definition. - Avoid starting docstrings with "The" or "A" unless needed to avoid ambiguity. This is a visual aid and reduces noise. > - GOOD: + ✅ OK: /// @param dirname Path fragment before `pend` - BAD: + ⌠NO: /// @param dirname The path fragment before `pend` - Vim differences: - Do not prefix help tags with "nvim-". Use |vim_diff.txt| to catalog @@ -247,6 +247,10 @@ Docstring format: - References are written as `[tag]` - Use ``` for code samples. Code samples can be annotated as `vim` or `lua` +- Use `@since <api-level>` to note the |api-level| when the function became + "stable". If `<api-level>` is greater than the current stable release (or + 0), it is marked as "experimental". + - See scripts/util.lua for the mapping of api-level to Nvim version. - Use `@nodoc` to prevent documentation generation. - Use `@inlinedoc` to inline `@class` blocks into `@param` blocks. E.g. >lua @@ -271,7 +275,7 @@ Docstring format: - {somefield}? (integer) Documentation for some field < -- Files which has `@meta` are only used for typing and documentation. +- Files declared as `@meta` are only used for typing and documentation (similar to "*.d.ts" typescript files). Example: the help for |vim.paste()| is generated from a docstring decorating vim.paste in runtime/lua/vim/_editor.lua like this: > @@ -288,6 +292,7 @@ vim.paste in runtime/lua/vim/_editor.lua like this: > --- end)() --- ``` --- + --- @since 12 --- @see |paste| --- --- @param lines ... @@ -307,19 +312,36 @@ See also |dev-naming|. easier to inspect and print, and inherently compatible with all Lua plugins. (This guideline doesn't apply to opaque, non-data objects like `vim.cmd`.) - stdlib functions should follow these common patterns: - - accept iterable instead of table - - exception: in some cases iterable doesn't make sense, e.g. spair() sorts - the input by definition, so there is no reason for it to accept an - iterable, because the input needs to be "reified"; it can't operate on - a "stream". - - return iterable instead of table - - mimic the pairs() or ipairs() interface if the function is intended to be - used in a "for" loop. - - when a result-or-error interface is needed, return `result|nil, nil|errmsg`: > - ---@return Foo|nil # Result object, or nil if not found. - ---@return nil|string # Error message on failure, or nil on success. -< - - Examples: |vim.ui.open()| |io.open()| |luv-error-handling| + - Return |lua-result-or-message| (`any|nil,nil|string`) to communicate + failure, or choose from |dev-error-patterns| when appropriate. + - Accept iterable instead of only table. + - Note: in some cases iterable doesn't make sense, e.g. spair() sorts the + input by definition, so there is no reason for it to accept an iterable, + because the input needs to be "reified"; it can't operate on a "stream". + - Return an iterable (generator) instead of table, if possible. + - Mimic the pairs() or ipairs() interface if the function is intended for + use in a |for-in| loop. + + *dev-error-patterns* +To communicate failure to a consumer, choose from these patterns (in order of +preference): +1. `retval, errmsg` + - When failure is normal, or when it is practical for the consumer to + continue (fallback) in some other way. See |lua-result-or-message|. +2. optional result, no errormsg + - Special case of 1. When there is only a single case of "doesn't exist" + (e.g. cache lookup, dict lookup). +3. `error("no luck")` + - For invalid state ("must not happen"), when failure is exceptional, or at + a low level where the consumers are unlikely to handle it in a meaningful + way. Advantage is that propagation happens for free and it's harder to + accidentally swallow errors. (E.g. using + `uv_handle/pipe:write()` without checking return values is common.) +4. `on_error` parameter + - For async and "visitors" traversing a graph, where many errors may be + collected while work continues. +5. `vim.notify` (sometimes with optional `opts.silent` (async, visitors ^)) + - High-level / application-level messages. End-user invokes these directly. *dev-patterns* Interface conventions ~ @@ -329,13 +351,20 @@ Where possible, these patterns apply to _both_ Lua and the API: - When accepting a buffer id, etc., 0 means "current buffer", nil means "all buffers". Likewise for window id, tabpage id, etc. - Examples: |vim.lsp.codelens.clear()| |vim.diagnostic.enable()| -- Any function signature that accepts a callback function should define the - callback as the LAST parameter, if possible. This improves readability of - calls by placing the less "noisy" arguments near the start. > - GOOD: - filter(table, opts, function() … end) - BAD: - filter(function() … end, table, opts) +- Any function signature that accepts a callback (example: |table.foreach()|) + should place it as the LAST parameter (after opts), if possible (or ALWAYS + for "continuation callbacks"—functions called exactly once). + - Improves readability by placing the less "noisy" arguments near the start. + - Consistent with luv. + - Useful for future async lib which transforms functions of the form + `function(<args>, cb(<ret)>))` => `function(<args>) -> <ret>`. + - Example: >lua + -- ✅ OK: + filter(…, opts, function() … end) + -- ⌠NO: + filter(function() … end, …, opts) + -- ⌠NO: + filter(…, function() … end, opts) - "Enable" ("toggle") interface and behavior: - `enable(…, nil)` and `enable(…, {buf=nil})` are synonyms and control the the "global" enablement of a feature. @@ -566,10 +595,10 @@ a good name: it's idiomatic and unambiguous. If the package is named "neovim", it confuses users, and complicates documentation and discussions. Examples of API-client package names: -- GOOD: nvim-racket -- GOOD: pynvim -- BAD: python-client -- BAD: neovim_ +- ✅ OK: nvim-racket +- ✅ OK: pynvim +- ⌠NO: python-client +- ⌠NO: neovim_ API client implementation guidelines ~ diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt index 36616b9a0d..342947595e 100644 --- a/runtime/doc/diagnostic.txt +++ b/runtime/doc/diagnostic.txt @@ -363,7 +363,6 @@ Lua module: vim.diagnostic *diagnostic-api* • {message} (`string`) The diagnostic text • {source}? (`string`) The source of the diagnostic • {code}? (`string|integer`) The diagnostic code - • {_tags}? (`{ deprecated: boolean, unnecessary: boolean}`) • {user_data}? (`any`) arbitrary data plugins can add • {namespace}? (`integer`) @@ -378,28 +377,38 @@ Lua module: vim.diagnostic *diagnostic-api* • {severity}? (`vim.diagnostic.SeverityFilter`) See |diagnostic-severity|. -*vim.diagnostic.GotoOpts* +*vim.diagnostic.JumpOpts* Extends: |vim.diagnostic.GetOpts| - Configuration table with the following keys: + Configuration table with the keys listed below. Some parameters can have + their default values changed with |vim.diagnostic.config()|. Fields: ~ - • {cursor_position}? (`{[1]:integer,[2]:integer}`, default: current cursor position) - Cursor position as a `(row, col)` tuple. See - |nvim_win_get_cursor()|. - • {wrap}? (`boolean`, default: `true`) Whether to loop - around file or not. Similar to 'wrapscan'. - • {severity}? (`vim.diagnostic.SeverityFilter`) See - |diagnostic-severity|. - • {float}? (`boolean|vim.diagnostic.Opts.Float`, default: - `true`) If `true`, call - |vim.diagnostic.open_float()| after moving. If a - table, pass the table as the {opts} parameter to - |vim.diagnostic.open_float()|. Unless overridden, - the float will show diagnostics at the new cursor - position (as if "cursor" were passed to the - "scope" option). - • {win_id}? (`integer`, default: `0`) Window ID + • {diagnostic}? (`vim.Diagnostic`) The diagnostic to jump to. Mutually + exclusive with {count}, {namespace}, and {severity}. + See |vim.Diagnostic|. + • {count}? (`integer`) The number of diagnostics to move by, + starting from {pos}. A positive integer moves forward + by {count} diagnostics, while a negative integer moves + backward by {count} diagnostics. Mutually exclusive + with {diagnostic}. + • {pos}? (`[integer,integer]`) Cursor position as a `(row, col)` + tuple. See |nvim_win_get_cursor()|. Used to find the + nearest diagnostic when {count} is used. Only used when + {count} is non-nil. Default is the current cursor + position. + • {wrap}? (`boolean`, default: `true`) Whether to loop around + file or not. Similar to 'wrapscan'. + • {severity}? (`vim.diagnostic.SeverityFilter`) See + |diagnostic-severity|. + • {float}? (`boolean|vim.diagnostic.Opts.Float`, default: `false`) + If `true`, call |vim.diagnostic.open_float()| after + moving. If a table, pass the table as the {opts} + parameter to |vim.diagnostic.open_float()|. Unless + overridden, the float will show diagnostics at the new + cursor position (as if "cursor" were passed to the + "scope" option). + • {winid}? (`integer`, default: `0`) Window ID *vim.diagnostic.NS* @@ -410,7 +419,7 @@ Lua module: vim.diagnostic *diagnostic-api* • {disabled}? (`boolean`) *vim.diagnostic.Opts* - Each of the configuration options below accepts one of the following: + Many of the configuration options below accept one of the following: • `false`: Disable this feature • `true`: Enable this feature, use default settings. • `table`: Enable this feature with overrides. Use an empty table to use @@ -441,6 +450,9 @@ Lua module: vim.diagnostic *diagnostic-api* displayed before lower severities (e.g. ERROR is displayed before WARN). Options: • {reverse}? (boolean) Reverse sort order + • {jump}? (`vim.diagnostic.Opts.Jump`) Default values for + |vim.diagnostic.jump()|. See + |vim.diagnostic.Opts.Jump|. *vim.diagnostic.Opts.Float* @@ -454,18 +466,18 @@ Lua module: vim.diagnostic *diagnostic-api* current cursor position (`cursor`). Shorthand versions are also accepted (`c` for `cursor`, `l` for `line`, `b` for `buffer`). - • {pos}? (`integer|{[1]:integer,[2]:integer}`) If {scope} is - "line" or "cursor", use this position rather than - the cursor position. If a number, interpreted as a - line number; otherwise, a (row, col) tuple. + • {pos}? (`integer|[integer,integer]`) If {scope} is "line" + or "cursor", use this position rather than the + cursor position. If a number, interpreted as a line + number; otherwise, a (row, col) tuple. • {severity_sort}? (`boolean|{reverse?:boolean}`, default: `false`) Sort diagnostics by severity. Overrides the setting from |vim.diagnostic.config()|. • {severity}? (`vim.diagnostic.SeverityFilter`) See |diagnostic-severity|. Overrides the setting from |vim.diagnostic.config()|. - • {header}? (`string|{[1]:string,[2]:any}`) String to use as the - header for the floating window. If a table, it is + • {header}? (`string|[string,any]`) String to use as the header + for the floating window. If a table, it is interpreted as a `[text, hl_group]` tuple. Overrides the setting from |vim.diagnostic.config()|. • {source}? (`boolean|'if_many'`) Include the diagnostic source @@ -500,6 +512,17 @@ Lua module: vim.diagnostic *diagnostic-api* • {focus_id}? (`string`) • {border}? (`string`) see |nvim_open_win()|. +*vim.diagnostic.Opts.Jump* + + Fields: ~ + • {float}? (`boolean|vim.diagnostic.Opts.Float`, default: false) + Default value of the {float} parameter of + |vim.diagnostic.jump()|. + • {wrap}? (`boolean`, default: true) Default value of the {wrap} + parameter of |vim.diagnostic.jump()|. + • {severity}? (`vim.diagnostic.SeverityFilter`) Default value of the + {severity} parameter of |vim.diagnostic.jump()|. + *vim.diagnostic.Opts.Signs* Fields: ~ @@ -568,8 +591,7 @@ Lua module: vim.diagnostic *diagnostic-api* < • {hl_mode}? (`'replace'|'combine'|'blend'`) See |nvim_buf_set_extmark()|. - • {virt_text}? (`{[1]:string,[2]:any}[]`) See - |nvim_buf_set_extmark()|. + • {virt_text}? (`[string,any][]`) See |nvim_buf_set_extmark()|. • {virt_text_pos}? (`'eol'|'overlay'|'right_align'|'inline'`) See |nvim_buf_set_extmark()|. • {virt_text_win_col}? (`integer`) See |nvim_buf_set_extmark()|. @@ -678,52 +700,20 @@ get_next({opts}) *vim.diagnostic.get_next()* Get the next diagnostic closest to the cursor position. Parameters: ~ - • {opts} (`vim.diagnostic.GotoOpts?`) See |vim.diagnostic.GotoOpts|. + • {opts} (`vim.diagnostic.JumpOpts?`) See |vim.diagnostic.JumpOpts|. Return: ~ (`vim.Diagnostic?`) Next diagnostic. See |vim.Diagnostic|. -get_next_pos({opts}) *vim.diagnostic.get_next_pos()* - Return the position of the next diagnostic in the current buffer. - - Parameters: ~ - • {opts} (`vim.diagnostic.GotoOpts?`) See |vim.diagnostic.GotoOpts|. - - Return: ~ - (`table|false`) Next diagnostic position as a `(row, col)` tuple or - false if no next diagnostic. - get_prev({opts}) *vim.diagnostic.get_prev()* Get the previous diagnostic closest to the cursor position. Parameters: ~ - • {opts} (`vim.diagnostic.GotoOpts?`) See |vim.diagnostic.GotoOpts|. + • {opts} (`vim.diagnostic.JumpOpts?`) See |vim.diagnostic.JumpOpts|. Return: ~ (`vim.Diagnostic?`) Previous diagnostic. See |vim.Diagnostic|. -get_prev_pos({opts}) *vim.diagnostic.get_prev_pos()* - Return the position of the previous diagnostic in the current buffer. - - Parameters: ~ - • {opts} (`vim.diagnostic.GotoOpts?`) See |vim.diagnostic.GotoOpts|. - - Return: ~ - (`table|false`) Previous diagnostic position as a `(row, col)` tuple - or `false` if there is no prior diagnostic. - -goto_next({opts}) *vim.diagnostic.goto_next()* - Move to the next diagnostic. - - Parameters: ~ - • {opts} (`vim.diagnostic.GotoOpts?`) See |vim.diagnostic.GotoOpts|. - -goto_prev({opts}) *vim.diagnostic.goto_prev()* - Move to the previous diagnostic in the current buffer. - - Parameters: ~ - • {opts} (`vim.diagnostic.GotoOpts?`) See |vim.diagnostic.GotoOpts|. - hide({namespace}, {bufnr}) *vim.diagnostic.hide()* Hide currently displayed diagnostics. @@ -743,6 +733,9 @@ hide({namespace}, {bufnr}) *vim.diagnostic.hide()* is_enabled({filter}) *vim.diagnostic.is_enabled()* Check whether diagnostics are enabled. + Attributes: ~ + Since: 0.10.0 + Parameters: ~ • {filter} (`table?`) Optional filters |kwargs|, or `nil` for all. • {ns_id}? (`integer`) Diagnostic namespace, or `nil` for @@ -753,6 +746,16 @@ is_enabled({filter}) *vim.diagnostic.is_enabled()* Return: ~ (`boolean`) +jump({opts}) *vim.diagnostic.jump()* + Move to a diagnostic. + + Parameters: ~ + • {opts} (`vim.diagnostic.JumpOpts`) See |vim.diagnostic.JumpOpts|. + + Return: ~ + (`vim.Diagnostic?`) The diagnostic that was moved to. See + |vim.Diagnostic|. + *vim.diagnostic.match()* match({str}, {pat}, {groups}, {severity_map}, {defaults}) Parse a diagnostic from a string. @@ -792,7 +795,7 @@ open_float({opts}) *vim.diagnostic.open_float()* Return (multiple): ~ (`integer?`) float_bufnr - (`integer?`) win_id + (`integer?`) winid reset({namespace}, {bufnr}) *vim.diagnostic.reset()* Remove all diagnostics from the given namespace. @@ -831,7 +834,7 @@ setloclist({opts}) *vim.diagnostic.setloclist()* after setting. • {title}? (`string`) Title of the location list. Defaults to "Diagnostics". - • {severity}? (`vim.diagnostic.Severity`) See + • {severity}? (`vim.diagnostic.SeverityFilter`) See |diagnostic-severity|. setqflist({opts}) *vim.diagnostic.setqflist()* @@ -845,7 +848,7 @@ setqflist({opts}) *vim.diagnostic.setqflist()* after setting. • {title}? (`string`) Title of quickfix list. Defaults to "Diagnostics". - • {severity}? (`vim.diagnostic.Severity`) See + • {severity}? (`vim.diagnostic.SeverityFilter`) See |diagnostic-severity|. *vim.diagnostic.show()* diff --git a/runtime/doc/diff.txt b/runtime/doc/diff.txt index 2f174a404e..c9de54342e 100644 --- a/runtime/doc/diff.txt +++ b/runtime/doc/diff.txt @@ -369,6 +369,9 @@ Additionally, 'diffexpr' should take care of "icase" and "iwhite" in the 'diffopt' option. 'diffexpr' cannot change the value of 'lines' and 'columns'. +The advantage of using a function call without arguments is that it is faster, +see |expr-option-function|. + Example (this does almost the same as 'diffexpr' being empty): > set diffexpr=MyDiff() @@ -434,6 +437,9 @@ will have the same effect. These variables are set to the file names used: v:fname_diff patch file v:fname_out resulting patched file +The advantage of using a function call without arguments is that it is faster, +see |expr-option-function|. + Example (this does the same as 'patchexpr' being empty): > set patchexpr=MyPatch() diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt index 662d89895d..0008713025 100644 --- a/runtime/doc/editing.txt +++ b/runtime/doc/editing.txt @@ -646,7 +646,7 @@ list of the current window. Also see |++opt| and |+cmd|. :[count]arga[dd] {name} .. *:arga* *:argadd* *E479* -:[count]arga[dd] +:[count]arga[dd] *E1156* Add the {name}s to the argument list. When {name} is omitted add the current buffer name to the argument list. @@ -714,7 +714,7 @@ list of the current window. omitted the current entry is used. Also see |++opt| and |+cmd|. -:[count]n[ext] [++opt] [+cmd] *:n* *:ne* *:next* *E165* *E163* +:[count]n[ext] [++opt] [+cmd] *:n* *:ne* *:next* *]a* *E165* *E163* Edit [count] next file. This fails when changes have been made and Vim does not want to |abandon| the current buffer. Also see |++opt| and |+cmd|. @@ -740,10 +740,10 @@ list of the current window. any changes to the buffer. Also see |++opt| and |+cmd|. -:[count]prev[ious] [count] [++opt] [+cmd] *:prev* *:previous* +:[count]prev[ious] [count] [++opt] [+cmd] *:prev* *:previous* *[a* Same as :Next. Also see |++opt| and |+cmd|. - *:rew* *:rewind* + *:rew* *:rewind* *[A* :rew[ind] [++opt] [+cmd] Start editing the first file in the argument list. This fails when changes have been made and Vim does @@ -759,7 +759,7 @@ list of the current window. :fir[st][!] [++opt] [+cmd] Other name for ":rewind". - *:la* *:last* + *:la* *:last* *]A* :la[st] [++opt] [+cmd] Start editing the last file in the argument list. This fails when changes have been made and Vim does @@ -1623,7 +1623,7 @@ There are three different types of searching: stop-directories are appended to the path (for the 'path' option) or to the filename (for the 'tags' option) with a ';'. If you want several stop-directories separate them with ';'. If you want no stop-directory - ("search upward till the root directory) just use ';'. > + ("search upward till the root directory") just use ';'. > /usr/include/sys;/usr < will search in: > /usr/include/sys @@ -1636,7 +1636,7 @@ There are three different types of searching: If Vim's current path is /u/user_x/work/release and you do > :set path=include;/u/user_x -< and then search for a file with |gf| the file is searched in: > +< and then search for a file with |gf| the file is searched in: > /u/user_x/work/release/include /u/user_x/work/include /u/user_x/include @@ -1648,7 +1648,7 @@ There are three different types of searching: 3) Combined up/downward search: If Vim's current path is /u/user_x/work/release and you do > set path=**;/u/user_x -< and then search for a file with |gf| the file is searched in: > +< and then search for a file with |gf| the file is searched in: > /u/user_x/work/release/** /u/user_x/work/** /u/user_x/** @@ -1660,10 +1660,10 @@ There are three different types of searching: In the above example you might want to set path to: > :set path=**,/u/user_x/** -< This searches: - /u/user_x/work/release/** ~ - /u/user_x/** ~ - This searches the same directories, but in a different order. +< This searches: > + /u/user_x/work/release/** + /u/user_x/** +< This searches the same directories, but in a different order. Note that completion for ":find", ":sfind", and ":tabfind" commands do not currently work with 'path' items that contain a URL or use the double star diff --git a/runtime/doc/editorconfig.txt b/runtime/doc/editorconfig.txt index 0b20c77801..eef14ed51c 100644 --- a/runtime/doc/editorconfig.txt +++ b/runtime/doc/editorconfig.txt @@ -78,6 +78,10 @@ root *editorconfig.root* directories. This property must be at the top-level of the `.editorconfig` file (i.e. it must not be within a glob section). +spelling_language *editorconfig.spelling_language* + A code of the format ss or ss-TT, where ss is an ISO 639 language code and + TT is an ISO 3166 territory identifier. Sets the 'spelllang' option. + tab_width *editorconfig.tab_width* The display size of a single tab character. Sets the 'tabstop' option. diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 7b4dba5a50..e0c45503cc 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -894,6 +894,9 @@ Example: > All expressions within one level are parsed from left to right. +Expression nesting is limited to 1000 levels deep (300 when build with MSVC) +to avoid running out of stack and crashing. *E1169* + ------------------------------------------------------------------------------ expr1 *expr1* *ternary* *falsy-operator* *??* *E109* @@ -2166,9 +2169,10 @@ text... let lconst[0] = 2 " Error! let lconst[1][0] = 'b' " OK < *E995* - |:const| does not allow to for changing a variable. > + It is an error to specify an existing variable with + |:const|. > :let x = 1 - :const x = 2 " Error! + :const x = 1 " Error! < *E996* Note that environment variables, option values and register values cannot be used here, since they cannot @@ -2186,7 +2190,7 @@ text... :lockvar v :let v = 'asdf' " fails! :unlet v " works -< *E741* *E940* +< *E741* *E940* *E1122* If you try to change a locked variable you get an error message: "E741: Value is locked: {name}". If you try to lock or unlock a built-in variable you diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt index 5eae78744c..a577b0c5fb 100644 --- a/runtime/doc/filetype.txt +++ b/runtime/doc/filetype.txt @@ -147,6 +147,7 @@ variables can be used to overrule the filetype used for certain extensions: `*.csh` g:filetype_csh |ft-csh-syntax| `*.dat` g:filetype_dat `*.def` g:filetype_def + `*.dsp` g:filetype_dsp `*.f` g:filetype_f |ft-forth-syntax| `*.frm` g:filetype_frm |ft-form-syntax| `*.fs` g:filetype_fs |ft-forth-syntax| @@ -585,6 +586,17 @@ any #lang directive overrides, use the following command: > let g:freebasic_lang = "fblite" +GDSCRIPT *ft-gdscript-plugin* + +By default the following options are set, based on Godot official docs: > + + setlocal noexpandtab softtabstop=0 shiftwidth=0 + +To disable this behavior, set the following variable in your vimrc: > + + let g:gdscript_recommended_style = 0 + + GIT COMMIT *ft-gitcommit-plugin* One command, :DiffGitCached, is provided to show a diff of the current commit @@ -592,6 +604,17 @@ in the preview window. It is equivalent to calling "git diff --cached" plus any arguments given to the command. +GO *ft-go-plugin* + +By default the following options are set, based on Golang official docs: > + + setlocal noexpandtab softtabstop=0 shiftwidth=0 + +To disable this behavior, set the following variable in your vimrc: > + + let g:go_recommended_style = 0 + + GPROF *ft-gprof-plugin* The gprof filetype plugin defines a mapping <C-]> to jump from a function @@ -602,6 +625,12 @@ The mapping can be disabled with: > let g:no_gprof_maps = 1 +HARE *ft-hare* + +Since the text for this plugin is rather long it has been put in a separate +file: |ft_hare.txt|. + + JAVA *ft-java-plugin* Whenever the variable "g:ftplugin_java_source_path" is defined and its value @@ -632,6 +661,27 @@ Remember to manually trigger the |FileType| event from a buffer with a Java file loaded in it each time after assigning a new value to the variable: > doautocmd FileType < +Markdown documentation comments may contain common runs of vertical leading +whitespace following the comment marks (`///`) for aesthetic reasons; however, +some horizontal runs of leading whitespace are significant in Markdown because +they denote code blocks etc. For convenience, a 'formatexpr' function is +provided for the |gq| operator. As long as neither "g:java_ignore_javadoc" +nor "g:java_ignore_markdown" is defined, the reformatting of Markdown comments +can be enabled on demand with: > + setlocal formatexpr=g:javaformat#RemoveCommonMarkdownWhitespace() +< +Or for Vim versions less than `7.4.265`, with: > + setlocal formatexpr=javaformat#RemoveCommonMarkdownWhitespace() +< +This function accepts a range of lines, removes a common run of vertical +leading whitespace, and rewrites the lines of the range. Depending on the +author's layout style and the comment contents, which lines to select for +reformatting can vary from the whole comment to only some portion of it. +To enable the recognition of Markdown comments each time after removing +"g:java_ignore_markdown" or "g:java_ignore_javadoc", remember to manually +re-source "javaformat.vim" for Vim versions greater than `8.2.1397`: > + runtime autoload/javaformat.vim +< MAIL *ft-mail-plugin* @@ -984,6 +1034,10 @@ You can change the default by defining the variable g:tex_flavor to the format let g:tex_flavor = "latex" Currently no other formats are recognized. +TYPST *ft-typst-plugin* + + *g:typst_conceal* +When |TRUE| the Typst filetype plugin will set the 'conceallevel' option to 2. VIM *ft-vim-plugin* diff --git a/runtime/doc/fold.txt b/runtime/doc/fold.txt index 8f7393f5e3..b844e0ed85 100644 --- a/runtime/doc/fold.txt +++ b/runtime/doc/fold.txt @@ -69,8 +69,6 @@ method. The value of the 'foldexpr' option is evaluated to get the foldlevel of a line. Examples: This will create a fold for all consecutive lines that start with a tab: > :set foldexpr=getline(v:lnum)[0]==\"\\t\" -This will call a function to compute the fold level: > - :set foldexpr=MyFoldLevel(v:lnum) This will make a fold out of paragraphs separated by blank lines: > :set foldexpr=getline(v:lnum)=~'^\\s*$'&&getline(v:lnum+1)=~'\\S'?'<1':1 This does the same: > @@ -79,6 +77,10 @@ This does the same: > Note that backslashes must be used to escape characters that ":set" handles differently (space, backslash, double quote, etc., see |option-backslash|). +The most efficient is to call a function without arguments: > + :set foldexpr=MyFoldLevel() +The function must use v:lnum. See |expr-option-function|. + These are the conditions with which the expression is evaluated: - The current buffer and window are set for the line. - The variable "v:lnum" is set to the line number. diff --git a/runtime/doc/ft_ada.txt b/runtime/doc/ft_ada.txt index a9302cde97..337a4cba6a 100644 --- a/runtime/doc/ft_ada.txt +++ b/runtime/doc/ft_ada.txt @@ -48,14 +48,12 @@ ctermfg=White often shows well). There are several options you can select in this Ada mode. See |ft-ada-options| for a complete list. -To enable them, assign a value to the option. For example, to turn one on: - > - > let g:ada_standard_types = 1 - -To disable them use ":unlet". Example: -> - > unlet g:ada_standard_types - +To enable them, assign a value to the option. For example, to turn one on: > + let g:ada_standard_types = 1 +< +To disable them use ":unlet". Example: > + unlet g:ada_standard_types +< You can just use ":" and type these into the command line to set these temporarily before loading an Ada file. You can make these option settings permanent by adding the "let" command(s), without a colon, to your |init.vim| @@ -158,10 +156,9 @@ several versions available which differ in the licence terms used. The GNAT compiler plug-in will perform a compile on pressing <F7> and then immediately shows the result. You can set the project file to be used by -setting: - > - > call g:gnat.Set_Project_File ('my_project.gpr') - +setting: > + call g:gnat.Set_Project_File ('my_project.gpr') +< Setting a project file will also create a Vim session (|views-sessions|) so - like with the GPS - opened files, window positions etc. will be remembered separately for all projects. diff --git a/runtime/doc/ft_hare.txt b/runtime/doc/ft_hare.txt new file mode 100644 index 0000000000..937c5e0961 --- /dev/null +++ b/runtime/doc/ft_hare.txt @@ -0,0 +1,77 @@ +*ft_hare.txt* Support for the Hare programming language + +============================================================================== +CONTENTS *hare* + +1. Introduction |hare-intro| +2. Filetype plugin |hare-plugin| +3. Settings |hare-settings| + +============================================================================== +INTRODUCTION *hare-intro* + +This plugin provides syntax highlighting, indentation, and other functionality +for the Hare programming language. Support is also provided for README files +inside Hare modules, but this must be enabled by setting |g:filetype_haredoc|. + +============================================================================== +FILETYPE PLUGIN *hare-plugin* + +This plugin automatically sets the value of 'path' to include the contents of +the HAREPATH environment variable, allowing commands such as |gf| to directly +open standard library or third-party modules. If HAREPATH is not set, it +defaults to the recommended paths for most Unix-like filesystems, namely +/usr/src/hare/stdlib and /usr/src/hare/third-party. + +============================================================================== +SETTINGS *hare-settings* + +This plugin provides a small number of variables that you can define in your +vimrc to configure its behavior. + + *g:filetype_haredoc* +This plugin is able to automatically detect Hare modules and set the "haredoc" +filetype for any README files. As the recursive directory search used as a +heuristic has a minor performance impact, this feature is disabled by default +and must be specifically opted into: > + let g:filetype_haredoc = 1 +< +See |g:haredoc_search_depth| for ways to tweak the searching behavior. + + *g:hare_recommended_style* +The following options are set by default, in accordance with the official Hare +style guide: > + setlocal noexpandtab + setlocal shiftwidth=0 + setlocal softtabstop=0 + setlocal tabstop=8 + setlocal textwidth=80 +< +To disable this behavior: > + let g:hare_recommended_style = 0 +< + *g:hare_space_error* +By default, trailing whitespace and tabs preceded by space characters are +highlighted as errors. This is automatically turned off when in insert mode. +To disable this highlighting completely: > + let g:hare_space_error = 0 +< + *g:haredoc_search_depth* +By default, when |g:filetype_haredoc| is enabled, only the current directory +and its immediate subdirectories are searched for Hare files. The maximum +search depth may be adjusted with: > + let g:haredoc_search_depth = 2 +< + Value Effect~ + 0 Only search the current directory. + 1 Search the current directory and immediate + subdirectories. + 2 Search the current directory and two levels of + subdirectories. + +The maximum search depth can be set to any integer, but using values higher +than 2 is not recommended, and will likely provide no tangible benefit in most +situations. + +============================================================================== + vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/ft_sql.txt b/runtime/doc/ft_sql.txt index 241fa4bd74..1dbac66db0 100644 --- a/runtime/doc/ft_sql.txt +++ b/runtime/doc/ft_sql.txt @@ -293,7 +293,7 @@ loaded by Vim: > ftplugin/sql.vim syntax/sqlinformix.vim indent/sql.vim -> +< Notice indent/sqlinformix.sql was not loaded. There is no indent file for Informix, Vim loads the default files if the specified files does not exist. @@ -349,7 +349,7 @@ The defaults static maps are: > The use of "<C-C>" can be user chosen by using the following in your |init.vim| as it may not work properly on all platforms: > let g:ftplugin_sql_omni_key = '<C-C>' -> +< The static maps (which are based on the syntax highlight groups) follow this format: > imap <buffer> <C-C>k <C-\><C-O>:call sqlcomplete#Map('sqlKeyword')<CR><C-X><C-O> @@ -664,7 +664,7 @@ your |init.vim|: > filetype is changed temporarily to SQL, the sqlcompletion plugin will cache the syntax groups listed in the List specified in this option. -> + ------------------------------------------------------------------------------ 4.5 SQL Maps *sql-completion-maps* diff --git a/runtime/doc/gui.txt b/runtime/doc/gui.txt index a64d722177..9ab5bf4e1e 100644 --- a/runtime/doc/gui.txt +++ b/runtime/doc/gui.txt @@ -6,14 +6,38 @@ Nvim Graphical User Interface *gui* *GUI* +Any client that supports the Nvim |ui-protocol| can be used as a UI for Nvim. +And multiple UIs can connect to the same Nvim instance! The terms "UI" and +"GUI" are often used interchangeably because all Nvim UI clients have the same +potential capabilities; the "TUI" refers to a UI client that outputs to your +terminal, whereas a "GUI" outputs directly to the OS graphics system. + +Except where noted, this document describes UI capabilities available to both +TUI and GUI (assuming the UI supports the given feature). See |TUI| for notes +specific to the terminal UI. Help tags with the "gui-" prefix refer to UI +features, whereas help tags with the "ui-" prefix refer to the |ui-protocol|. + +Nvim provides a default, builtin UI (the |TUI|), but there are many other +(third-party) GUIs that you can use instead: + +- Firenvim (Nvim in your web browser!) https://github.com/glacambre/firenvim +- vscode-neovim (Nvim in VSCode!) https://github.com/vscode-neovim/vscode-neovim +- Neovide https://neovide.dev/ +- Goneovim https://github.com/akiyosi/goneovim +- Nvy https://github.com/RMichelsen/Nvy +- Neovim-Qt (Qt5) https://github.com/equalsraf/neovim-qt +- VimR (macOS) https://github.com/qvacua/vimr +- Others https://github.com/neovim/neovim/wiki/Related-projects#gui + Type |gO| to see the table of contents. ============================================================================== -Starting the GUI *gui-start* *E229* *E233* +Starting the GUI *gui-config* *gui-start* *ginit.vim* *gui-init* *gvimrc* *$MYGVIMRC* For GUI-specific configuration Nvim provides the |UIEnter| event. This -happens after other |initialization|s, like reading your vimrc file. +happens after other |initialization|s, or whenever a UI attaches (multiple UIs +can connect to any Nvim instance). Example: this sets "g:gui" to the value of the UI's "rgb" field: > :autocmd UIEnter * let g:gui = filter(nvim_list_uis(),{k,v-> v.chan==v:event.chan})[0].rgb @@ -221,7 +245,7 @@ is right aligned, and the "O" is underlined, to indicate it is the shortcut. *:am* *:amenu* *:an* *:anoremenu* The ":amenu" command can be used to define menu entries for all modes at once, -expect for Terminal mode. To make the command work correctly, a character is +except for Terminal mode. To make the command work correctly, a character is automatically inserted for some modes: mode inserted appended ~ Normal nothing nothing @@ -444,6 +468,10 @@ when the right mouse button is pressed, if 'mousemodel' is set to popup or popup_setpos. The default "PopUp" menu is: >vim + anoremenu PopUp.Go\ to\ definition <Cmd>lua vim.lsp.buf.definition()<CR> + amenu PopUp.Open\ in\ web\ browser gx + anoremenu PopUp.Inspect <Cmd>Inspect<CR> + anoremenu PopUp.-1- <Nop> vnoremenu PopUp.Cut "+x vnoremenu PopUp.Copy "+y anoremenu PopUp.Paste "+gP @@ -452,8 +480,7 @@ The default "PopUp" menu is: >vim nnoremenu PopUp.Select\ All ggVG vnoremenu PopUp.Select\ All gg0oG$ inoremenu PopUp.Select\ All <C-Home><C-O>VG - anoremenu PopUp.Inspect <Cmd>Inspect<CR> - anoremenu PopUp.-1- <Nop> + anoremenu PopUp.-2- <Nop> anoremenu PopUp.How-to\ disable\ mouse <Cmd>help disable-mouse<CR> < @@ -548,7 +575,7 @@ name and all existing submenus below it are affected. Examples for Menus *menu-examples* -Here is an example on how to add menu items with menu's! You can add a menu +Here is an example on how to add menu items with menus! You can add a menu item for the keyword under the cursor. The register "z" is used. > :nmenu Words.Add\ Var wb"zye:menu! Words.<C-R>z <C-R>z<CR> @@ -612,9 +639,6 @@ a menu item - you don't need to do a :tunmenu as well. You can cause a menu to popup at the cursor. This behaves similarly to the PopUp menus except that any menu tree can be popped up. -This command is for backwards compatibility, using it is discouraged, because -it behaves in a strange way. - *:popup* *:popu* :popu[p] {name} Popup the menu {name}. The menu named must have at least one subentry, but need not diff --git a/runtime/doc/health.txt b/runtime/doc/health.txt index e879f11351..cb70961b55 100644 --- a/runtime/doc/health.txt +++ b/runtime/doc/health.txt @@ -7,10 +7,10 @@ Type |gO| to see the table of contents. ============================================================================== -Checkhealth *health* +Checkhealth *vim.health* *health* -health.vim is a minimal framework to help users troubleshoot configuration and +vim.health is a minimal framework to help users troubleshoot configuration and any other environment conditions that a plugin might care about. Nvim ships with healthchecks for configuration, performance, python support, ruby support, clipboard support, and more. @@ -49,7 +49,7 @@ Commands *health-commands* :checkhealth vim* < -Create a healthcheck *health-dev* *vim.health* +Create a healthcheck *health-dev* Healthchecks are functions that check the user environment, configuration, or any other prerequisites that a plugin cares about. Nvim ships with diff --git a/runtime/doc/help.txt b/runtime/doc/help.txt index 43f80101ed..fd8bfd644f 100644 --- a/runtime/doc/help.txt +++ b/runtime/doc/help.txt @@ -127,6 +127,7 @@ PROGRAMMING LANGUAGE SUPPORT |filetype| Settings for specific types of files |quickfix| Commands for a quick edit-compile-fix cycle |ft_ada.txt| Ada filetype plugin +|ft_hare.txt| Filetype plugin for Hare |ft_ps1.txt| PowerShell filetype plugin |ft_raku.txt| Raku filetype plugin |ft_rust.txt| Rust filetype plugin @@ -168,6 +169,7 @@ VERSIONS DEVELOPING NVIM |dev| Development of Nvim +|dev-arch| Internal architecture, modules, data structures |dev-style| Development style guidelines |dev-theme| Design guidelines (colorschemes etc.) |dev-tools| Tools and techniques for developing Nvim @@ -187,7 +189,7 @@ Local additions ~ *local-additions* ------------------------------------------------------------------------------ -*bars* Bars example +Bars example *bars* Now that you've jumped here with CTRL-] or a double mouse click, you can use CTRL-T, CTRL-O, g<RightMouse>, or <C-RightMouse> to go back to where you were. @@ -199,5 +201,5 @@ You can use CTRL-] on any word (even if it is not within "|") and Nvim will try to find help for it. Especially for options in single quotes, e.g. 'hlsearch'. ------------------------------------------------------------------------------- + vim:tw=78:isk=!-~,^*,^\|,^\":ts=8:noet:ft=help:norl: diff --git a/runtime/doc/indent.txt b/runtime/doc/indent.txt index a890d531ac..f97ae24068 100644 --- a/runtime/doc/indent.txt +++ b/runtime/doc/indent.txt @@ -116,7 +116,7 @@ If you really want to reindent when you type 'o', 'O', 'e', '0', '<', '>', "<!>", respectively, for those keys. For an emacs-style indent mode where lines aren't indented every time you -press <Enter> but only if you press <Tab>, I suggest: +press <Enter> but only if you press <Tab>, I suggest: > :set cinkeys=0{,0},:,0#,!<Tab>,!^F You might also want to switch off 'autoindent' then. diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt index 79f10b33f1..9ee75ea950 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -196,10 +196,12 @@ tag char note action in Normal mode ~ |<Tab>| <Tab> 1 go to N newer entry in jump list |CTRL-I| CTRL-I 1 same as <Tab> |<NL>| <NL> 1 same as "j" +|<S-NL>| <S-NL> 1 same as CTRL-F |CTRL-J| CTRL-J 1 same as "j" CTRL-K not used |CTRL-L| CTRL-L redraw screen |<CR>| <CR> 1 cursor to the first CHAR N lines lower +|<S-CR>| <S-CR> 1 same as CTRL-F |CTRL-M| CTRL-M 1 same as <CR> |CTRL-N| CTRL-N 1 same as "j" |CTRL-O| CTRL-O 1 go to N older entry in jump list @@ -272,9 +274,11 @@ tag char note action in Normal mode ~ |star| * 1 search forward for the Nth occurrence of the ident under the cursor |+| + 1 same as <CR> +|<S-Plus>| <S-+> 1 same as CTRL-F |,| , 1 repeat latest f, t, F or T in opposite direction N times |-| - 1 cursor to the first CHAR N lines higher +|<S-Minus>| <S--> 1 same as CTRL-B |.| . 2 repeat last change with count replaced with N |/| /{pattern}<CR> 1 search forward for the Nth occurrence of @@ -366,7 +370,7 @@ tag char note action in Normal mode ~ or start of putted text |`]| `] 1 cursor to the end of last operated text or end of putted text -|``| `` 1 cursor to the position before latest jump +|``| "``" 1 cursor to the position before latest jump |`{| `{ 1 cursor to the start of the current paragraph |`}| `} 1 cursor to the end of the current paragraph |a| a 2 append text after the cursor N times @@ -397,7 +401,7 @@ tag char note action in Normal mode ~ |q| q{0-9a-zA-Z"} record typed characters into named register {0-9a-zA-Z"} (uppercase to append) |q| q (while recording) stops recording -|Q| Q replay last recorded macro +|Q| Q 2 replay last recorded register |q:| q: edit : command-line in command-line window |q/| q/ edit / command-line in command-line window |q?| q? edit ? command-line in command-line window @@ -736,7 +740,7 @@ tag char note action in Normal mode ~ search pattern and Visually select it |gP| ["x]gP 2 put the text [from register x] before the cursor N times, leave the cursor after it -|gQ| gQ switch to "Ex" mode with Vim editing +|gQ| gQ switch to "Ex" mode with Vim editing |gR| gR 2 enter Virtual Replace mode |gT| gT go to the previous tab page |gU| gU{motion} 2 make Nmove text uppercase @@ -923,7 +927,6 @@ tag command note action in Visual mode ~ |v_O| O move horizontally to other corner of area |v_P| P replace highlighted area with register contents; registers are unchanged - Q does not start Ex mode |v_R| R 2 delete the highlighted lines and start insert |v_S| S 2 delete the highlighted lines and start @@ -1136,7 +1139,7 @@ tag command action ~ |:!!| :!! repeat last ":!" command |:#| :# same as ":number" |:&| :& repeat last ":substitute" -|:star| :* use the last Visual area, like :'<,'> +|:star| :* use the last Visual area, like ":'<,'>" |:<| :< shift lines one 'shiftwidth' left |:=| := print the last line number |:>| :> shift lines one 'shiftwidth' right diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt index 91b0d41f1c..d7cbb7c78e 100644 --- a/runtime/doc/insert.txt +++ b/runtime/doc/insert.txt @@ -1177,6 +1177,18 @@ items: user_data custom data which is associated with the item and available in |v:completed_item|; it can be any type; defaults to an empty string + hl_group an additional highlight group whose attributes are + combined with |hl-PmenuSel| and |hl-Pmenu| or + |hl-PmenuMatchSel| and |hl-PmenuMatch| highlight + attributes in the popup menu to apply cterm and gui + properties (with higher priority) like strikethrough + to the completion items + kind_hlgroup an additional highlight group specifically for setting + the highlight attributes of the completion kind. When + this field is present, it will override the + |hl-PmenuKind| highlight group, allowing for the + customization of ctermfg and guifg properties for the + completion kind All of these except "icase", "equal", "dup" and "empty" must be a string. If an item does not meet these requirements then an error message is given and @@ -1927,11 +1939,16 @@ These two commands will keep on asking for lines, until you type a line containing only a ".". Watch out for lines starting with a backslash, see |line-continuation|. -When in Ex mode (see |-e|) a backslash at the end of the line can be used to -insert a NUL character. To be able to have a line ending in a backslash use -two backslashes. This means that the number of backslashes is halved, but -only at the end of the line. - +Text typed after a "|" command separator is used first. So the following +command in ex mode: > + :a|one + two + . + :visual +appends the following text, after the cursor line: > + one + two +< NOTE: These commands cannot be used with |:global| or |:vglobal|. ":append" and ":insert" don't work properly in between ":if" and ":endif", ":for" and ":endfor", ":while" and ":endwhile". diff --git a/runtime/doc/intro.txt b/runtime/doc/intro.txt index 4c757cc1f6..41846f8eed 100644 --- a/runtime/doc/intro.txt +++ b/runtime/doc/intro.txt @@ -688,7 +688,7 @@ The current mode is "-- INSERT --" or "-- REPLACE --", see |'showmode'|. The command characters are those that you typed but were not used yet. If you have a slow terminal you can switch off the status messages to speed -up editing: +up editing: > :set nosc noru nosm If there is an error, an error message will be shown for at least one second diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index 50fffca497..419f583c36 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -34,16 +34,16 @@ Follow these steps to get LSP features: vim.api.nvim_create_autocmd('FileType', { -- This handler will fire when the buffer's 'filetype' is "python" pattern = 'python', - callback = function(ev) + callback = function(args) vim.lsp.start({ name = 'my-server-name', cmd = {'name-of-language-server-executable', '--option', 'arg1', 'arg2'}, -- Set the "root directory" to the parent directory of the file in the - -- current buffer (`ev.buf`) that contains either a "setup.py" or a + -- current buffer (`args.buf`) that contains either a "setup.py" or a -- "pyproject.toml" file. Files that share a root directory will reuse -- the connection to the same LSP server. - root_dir = vim.fs.root(ev.buf, {'setup.py', 'pyproject.toml'}), + root_dir = vim.fs.root(args.buf, {'setup.py', 'pyproject.toml'}), }) end, }) @@ -86,18 +86,21 @@ To override or delete any of the above defaults, set or unset the options on |LspAttach|: >lua vim.api.nvim_create_autocmd('LspAttach', { - callback = function(ev) - vim.bo[ev.buf].formatexpr = nil - vim.bo[ev.buf].omnifunc = nil - vim.keymap.del('n', 'K', { buffer = ev.buf }) + callback = function(args) + -- Unset 'formatexpr' + vim.bo[args.buf].formatexpr = nil + -- Unset 'omnifunc' + vim.bo[args.buf].omnifunc = nil + -- Unmap K + vim.keymap.del('n', 'K', { buffer = args.buf }) end, }) < *lsp-config* -To use other LSP features, set keymaps on |LspAttach|. Not all language -servers provide the same capabilities. To ensure you only set keymaps if the -language server supports a feature, guard keymaps behind capability checks. -Example: >lua +To use other LSP features, set keymaps and other buffer options on +|LspAttach|. Not all language servers provide the same capabilities. Use +capability checks to ensure you only use features supported by the language +server. Example: >lua vim.api.nvim_create_autocmd('LspAttach', { callback = function(args) @@ -105,6 +108,21 @@ Example: >lua if client.supports_method('textDocument/implementation') then -- Create a keymap for vim.lsp.buf.implementation end + + if client.supports_method('textDocument/completion') then + -- Enable auto-completion + vim.lsp.completion.enable(true, client.id, args.buf, {autotrigger = true}) + end + + if client.supports_method('textDocument/formatting') then + -- Format the current buffer on save + vim.api.nvim_create_autocmd('BufWritePre', { + buffer = args.buf, + callback = function() + vim.lsp.buf.format({bufnr = args.buf, id = client.id}) + end, + }) + end end, }) < @@ -191,6 +209,7 @@ won't run if your server doesn't support them. - textDocument/prepareTypeHierarchy - textDocument/publishDiagnostics - textDocument/rangeFormatting +- textDocument/rangesFormatting - textDocument/references - textDocument/rename - textDocument/semanticTokens/full @@ -220,26 +239,26 @@ Each response handler has this signature: > function(err, result, ctx, config) < Parameters: ~ - - {err} (table|nil) Error info dict, or `nil` if the request - completed. - - {result} (Result | Params | nil) `result` key of the |lsp-response| or - `nil` if the request failed. - - {ctx} (table) Table of calling state associated with the - handler, with these keys: - - {method} (string) |lsp-method| name. - - {client_id} (number) |vim.lsp.Client| identifier. - - {bufnr} (Buffer) Buffer handle. - - {params} (table|nil) Request parameters table. - - {version} (number) Document version at time of - request. Handlers can compare this to the - current document version to check if the - response is "stale". See also |b:changedtick|. - - {config} (table) Handler-defined configuration table, which allows - users to customize handler behavior. - For an example, see: - |vim.lsp.diagnostic.on_publish_diagnostics()| - To configure a particular |lsp-handler|, see: - |lsp-handler-configuration| + • {err} (`table|nil`) Error info dict, or `nil` if the request + completed. + • {result} (`Result|Params|nil`) `result` key of the |lsp-response| or + `nil` if the request failed. + • {ctx} (`table`) Table of calling state associated with the + handler, with these keys: + • {method} (`string`) |lsp-method| name. + • {client_id} (`number`) |vim.lsp.Client| identifier. + • {bufnr} (`Buffer`) Buffer handle. + • {params} (`table|nil`) Request parameters table. + • {version} (`number`) Document version at time of + request. Handlers can compare this to the + current document version to check if the + response is "stale". See also |b:changedtick|. + • {config} (`table`) Handler-defined configuration table, which allows + users to customize handler behavior. + For an example, see: + |vim.lsp.diagnostic.on_publish_diagnostics()| + To configure a particular |lsp-handler|, see: + |lsp-handler-configuration| Returns: ~ Two values `result, err` where `err` is shaped like an RPC error: > @@ -302,7 +321,7 @@ To configure the behavior of a builtin |lsp-handler|, the convenient method } < Some handlers do not have an explicitly named handler function (such as - ||vim.lsp.diagnostic.on_publish_diagnostics()|). To override these, first + |vim.lsp.diagnostic.on_publish_diagnostics()|). To override these, first create a reference to the existing handler: >lua local on_references = vim.lsp.handlers["textDocument/references"] @@ -508,32 +527,25 @@ EVENTS *lsp-events* LspAttach *LspAttach* After an LSP client attaches to a buffer. The |autocmd-pattern| is the name of the buffer. When used from Lua, the client ID is passed to the - callback in the "data" table. Example: >lua - - vim.api.nvim_create_autocmd("LspAttach", { - callback = function(args) - local bufnr = args.buf - local client = vim.lsp.get_client_by_id(args.data.client_id) - if client.server_capabilities.completionProvider then - vim.bo[bufnr].omnifunc = "v:lua.vim.lsp.omnifunc" - end - if client.server_capabilities.definitionProvider then - vim.bo[bufnr].tagfunc = "v:lua.vim.lsp.tagfunc" - end - end, - }) -< + callback in the "data" table. See |lsp-config| for an example. LspDetach *LspDetach* Just before an LSP client detaches from a buffer. The |autocmd-pattern| is the name of the buffer. When used from Lua, the client ID is passed to the callback in the "data" table. Example: >lua - vim.api.nvim_create_autocmd("LspDetach", { + vim.api.nvim_create_autocmd('LspDetach', { callback = function(args) + -- Get the detaching client local client = vim.lsp.get_client_by_id(args.data.client_id) - -- Do something with the client - vim.cmd("setlocal tagfunc< omnifunc<") + + -- Remove the autocommand to format the buffer on save, if it exists + if client.supports_method('textDocument/formatting') then + vim.api.nvim_clear_autocmds({ + event = 'BufWritePre', + buffer = args.buf, + }) + end end, }) < @@ -750,7 +762,7 @@ formatexpr({opts}) *vim.lsp.formatexpr()* function. Currently only supports a single client. This can be set via - `setlocal formatexpr=v:lua.vim.lsp.formatexpr()` but will typically or in + `setlocal formatexpr=v:lua.vim.lsp.formatexpr()` or (more typically) in `on_attach` via `vim.bo[bufnr].formatexpr = 'v:lua.vim.lsp.formatexpr(#{timeout_ms:250})'`. @@ -874,13 +886,13 @@ start({config}, {opts}) *vim.lsp.start()* • {config} (`vim.lsp.ClientConfig`) Configuration for the server. See |vim.lsp.ClientConfig|. • {opts} (`table?`) Optional keyword arguments - • {reuse_client} + • {reuse_client}? (`fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean`) Predicate used to decide if a client should be re-used. Used on all running clients. The default implementation re-uses a client if name and root_dir matches. - • {bufnr} (`integer`) Buffer handle to attach to if starting - or re-using a client (0 for current). + • {bufnr}? (`integer`) Buffer handle to attach to if + starting or re-using a client (0 for current). • {silent}? (`boolean`) Suppress error reporting if the LSP server fails to start (default false). @@ -996,7 +1008,7 @@ Lua module: vim.lsp.client *lsp-client* if the client supports workspace folders. It can be `null` if the client supports workspace folders but none are configured. - • {root_dir} (`string`) + • {root_dir} (`string?`) • {attached_buffers} (`table<integer,true>`) • {commands} (`table<string,fun(command: lsp.Command, ctx: table)>`) Table of command name to function which is @@ -1043,7 +1055,7 @@ Lua module: vim.lsp.client *lsp-client* `client.cancel_request(request_id)` to cancel the request. • {request_sync} (`fun(method: string, params: table?, timeout_ms: integer?, bufnr: integer): {err: lsp.ResponseError?, result:any}?, string?`) - err # a dictionary, where + err # a dict • {notify} (`fun(method: string, params: table?): boolean`) Sends a notification to an LSP server. Returns: a boolean to indicate if the @@ -1371,15 +1383,22 @@ format({opts}) *vim.lsp.buf.format()* (client.id) matching this field. • {name}? (`string`) Restrict formatting to the client with name (client.name) matching this field. - • {range}? (`{start:integer[],end:integer[]}`, default: - current selection in visual mode, `nil` in other modes, - formatting the full buffer) Range to format. Table must - contain `start` and `end` keys with {row,col} tuples using - (1,0) indexing. + • {range}? + (`{start:[integer,integer],end:[integer, integer]}|{start:[integer,integer],end:[integer,integer]}[]`, + default: current selection in visual mode, `nil` in other + modes, formatting the full buffer) Range to format. Table + must contain `start` and `end` keys with {row,col} tuples + using (1,0) indexing. Can also be a list of tables that + contain `start` and `end` keys as described above, in which + case `textDocument/rangesFormatting` support is required. hover() *vim.lsp.buf.hover()* Displays hover information about the symbol under the cursor in a floating - window. Calling the function twice will jump into the floating window. + window. The window will be dismissed on cursor move. Calling the function + twice will jump into the floating window (thus by default, "KK" will open + the hover window and focus it). In the floating window, all commands and + mappings are available as usual, except that "q" dismisses the window. You + can scroll the contents the same as you would any other buffer. implementation({opts}) *vim.lsp.buf.implementation()* Lists all the implementations for the symbol under the cursor in the @@ -1468,6 +1487,15 @@ workspace_symbol({query}, {opts}) *vim.lsp.buf.workspace_symbol()* ============================================================================== Lua module: vim.lsp.diagnostic *lsp-diagnostic* +from({diagnostics}) *vim.lsp.diagnostic.from()* + Converts the input `vim.Diagnostic`s to LSP diagnostics. + + Parameters: ~ + • {diagnostics} (`vim.Diagnostic[]`) + + Return: ~ + (`lsp.Diagnostic[]`) + *vim.lsp.diagnostic.get_namespace()* get_namespace({client_id}, {is_pull}) Get the diagnostic namespace associated with an LSP client @@ -1605,6 +1633,34 @@ save({lenses}, {bufnr}, {client_id}) *vim.lsp.codelens.save()* ============================================================================== +Lua module: vim.lsp.completion *lsp-completion* + +*vim.lsp.completion.BufferOpts* + + Fields: ~ + • {autotrigger}? (`boolean`) Whether to trigger completion + automatically. Default: false + • {convert}? (`fun(item: lsp.CompletionItem): table`) Transforms an + LSP CompletionItem to |complete-items|. + + + *vim.lsp.completion.enable()* +enable({enable}, {client_id}, {bufnr}, {opts}) + Enables or disables completions from the given language client in the + given buffer. + + Parameters: ~ + • {enable} (`boolean`) True to enable, false to disable + • {client_id} (`integer`) Client ID + • {bufnr} (`integer`) Buffer handle, or 0 for the current buffer + • {opts} (`vim.lsp.completion.BufferOpts?`) See + |vim.lsp.completion.BufferOpts|. + +trigger() *vim.lsp.completion.trigger()* + Trigger LSP completion in the current buffer. + + +============================================================================== Lua module: vim.lsp.inlay_hint *lsp-inlay_hint* enable({enable}, {filter}) *vim.lsp.inlay_hint.enable()* @@ -1614,6 +1670,9 @@ enable({enable}, {filter}) *vim.lsp.inlay_hint.enable()* vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled()) < + Attributes: ~ + Since: 0.10.0 + Parameters: ~ • {enable} (`boolean?`) true/nil to enable, false to disable • {filter} (`table?`) Optional filters |kwargs|, or `nil` for all. @@ -1638,6 +1697,9 @@ get({filter}) *vim.lsp.inlay_hint.get()* }) < + Attributes: ~ + Since: 0.10.0 + Parameters: ~ • {filter} (`table?`) Optional filters |kwargs|: • {bufnr} (`integer?`) @@ -1652,8 +1714,11 @@ get({filter}) *vim.lsp.inlay_hint.get()* is_enabled({filter}) *vim.lsp.inlay_hint.is_enabled()* Query whether inlay hint is enabled in the {filter}ed scope + Attributes: ~ + Since: 0.10.0 + Parameters: ~ - • {filter} (`table`) Optional filters |kwargs|, or `nil` for all. + • {filter} (`table?`) Optional filters |kwargs|, or `nil` for all. • {bufnr} (`integer?`) Buffer number, or 0 for current buffer, or nil for all. @@ -1806,8 +1871,8 @@ apply_text_document_edit({text_document_edit}, {index}, {offset_encoding}) document. Parameters: ~ - • {text_document_edit} (`table`) a `TextDocumentEdit` object - • {index} (`integer`) Optional index of the edit, if from + • {text_document_edit} (`lsp.TextDocumentEdit`) + • {index} (`integer?`) Optional index of the edit, if from a list of edits (or nil, if not from a list) • {offset_encoding} (`string?`) @@ -1819,7 +1884,7 @@ apply_text_edits({text_edits}, {bufnr}, {offset_encoding}) Applies a list of text edits to a buffer. Parameters: ~ - • {text_edits} (`table`) list of `TextEdit` objects + • {text_edits} (`lsp.TextEdit[]`) • {bufnr} (`integer`) Buffer id • {offset_encoding} (`string`) utf-8|utf-16|utf-32 @@ -1831,7 +1896,7 @@ apply_workspace_edit({workspace_edit}, {offset_encoding}) Applies a `WorkspaceEdit`. Parameters: ~ - • {workspace_edit} (`table`) `WorkspaceEdit` + • {workspace_edit} (`lsp.WorkspaceEdit`) • {offset_encoding} (`string`) utf-8|utf-16|utf-32 (required) See also: ~ @@ -1849,8 +1914,7 @@ buf_highlight_references({bufnr}, {references}, {offset_encoding}) Parameters: ~ • {bufnr} (`integer`) Buffer id - • {references} (`table`) List of `DocumentHighlight` objects to - highlight + • {references} (`lsp.DocumentHighlight[]`) objects to highlight • {offset_encoding} (`string`) One of "utf-8", "utf-16", "utf-32". See also: ~ @@ -1884,8 +1948,8 @@ convert_input_to_markdown_lines({input}, {contents}) Parameters: ~ • {input} (`lsp.MarkedString|lsp.MarkedString[]|lsp.MarkupContent`) - • {contents} (`table?`) List of strings to extend with converted lines. - Defaults to {}. + • {contents} (`string[]?`) List of strings to extend with converted + lines. Defaults to {}. Return: ~ (`string[]`) extended with lines of converted markdown. @@ -1898,15 +1962,16 @@ convert_signature_help_to_markdown_lines({signature_help}, {ft}, {triggers}) Converts `textDocument/signatureHelp` response to markdown lines. Parameters: ~ - • {signature_help} (`table`) Response of `textDocument/SignatureHelp` + • {signature_help} (`lsp.SignatureHelp`) Response of + `textDocument/SignatureHelp` • {ft} (`string?`) filetype that will be use as the `lang` for the label markdown code block • {triggers} (`table?`) list of trigger characters from the lsp server. used to better determine parameter offsets Return (multiple): ~ - (`table?`) table list of lines of converted markdown. - (`table?`) table of active hl + (`string[]?`) table list of lines of converted markdown. + (`number[]?`) table of active hl See also: ~ • https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp @@ -1928,7 +1993,7 @@ jump_to_location({location}, {offset_encoding}, {reuse_win}) Jumps to a location. Parameters: ~ - • {location} (`table`) (`Location`|`LocationLink`) + • {location} (`lsp.Location|lsp.LocationLink`) • {offset_encoding} (`string?`) utf-8|utf-16|utf-32 • {reuse_win} (`boolean?`) Jump to existing window if buffer is already open. @@ -1957,7 +2022,9 @@ locations_to_items({locations}, {offset_encoding}) (`table[]`) A list of objects with the following fields: • {filename} (`string`) • {lnum} (`integer`) 1-indexed line number + • {end_lnum} (`integer`) 1-indexed end line number • {col} (`integer`) 1-indexed column + • {end_col} (`integer`) 1-indexed end column • {text} (`string`) • {user_data} (`lsp.Location|lsp.LocationLink`) @@ -1993,7 +2060,8 @@ make_formatting_params({options}) cursor position. Parameters: ~ - • {options} (`table?`) with valid `FormattingOptions` entries + • {options} (`lsp.FormattingOptions?`) with valid `FormattingOptions` + entries Return: ~ (`lsp.DocumentFormattingParams`) object @@ -2033,7 +2101,7 @@ make_position_params({window}, {offset_encoding}) `window` Return: ~ - (`table`) `TextDocumentPositionParams` object + (`lsp.TextDocumentPositionParams`) See also: ~ • https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams @@ -2064,7 +2132,7 @@ make_text_document_params({bufnr}) • {bufnr} (`integer?`) Buffer handle, defaults to current Return: ~ - (`table`) `TextDocumentIdentifier` + (`lsp.TextDocumentIdentifier`) See also: ~ • https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier @@ -2074,8 +2142,11 @@ make_workspace_params({added}, {removed}) Create the workspace params Parameters: ~ - • {added} (`table`) - • {removed} (`table`) + • {added} (`lsp.WorkspaceFolder[]`) + • {removed} (`lsp.WorkspaceFolder[]`) + + Return: ~ + (`lsp.WorkspaceFoldersChangeEvent`) *vim.lsp.util.open_floating_preview()* open_floating_preview({contents}, {syntax}, {opts}) @@ -2119,7 +2190,7 @@ preview_location({location}, {opts}) *vim.lsp.util.preview_location()* definition) Parameters: ~ - • {location} (`table`) a single `Location` or `LocationLink` + • {location} (`lsp.Location|lsp.LocationLink`) • {opts} (`table`) Return (multiple): ~ @@ -2149,7 +2220,7 @@ show_document({location}, {offset_encoding}, {opts}) Shows document and optionally jumps to the location. Parameters: ~ - • {location} (`table`) (`Location`|`LocationLink`) + • {location} (`lsp.Location|lsp.LocationLink`) • {offset_encoding} (`string?`) utf-8|utf-16|utf-32 • {opts} (`table?`) options • reuse_win (boolean) Jump to existing window if @@ -2174,7 +2245,7 @@ stylize_markdown({bufnr}, {contents}, {opts}) Parameters: ~ • {bufnr} (`integer`) - • {contents} (`table`) of lines to show in window + • {contents} (`string[]`) of lines to show in window • {opts} (`table`) with optional fields • height of floating window • width of floating window @@ -2191,7 +2262,7 @@ symbols_to_items({symbols}, {bufnr}) *vim.lsp.util.symbols_to_items()* Parameters: ~ • {symbols} (`table`) DocumentSymbol[] or SymbolInformation[] - • {bufnr} (`integer`) + • {bufnr} (`integer?`) ============================================================================== @@ -2238,7 +2309,7 @@ Lua module: vim.lsp.rpc *lsp-rpc* *vim.lsp.rpc.PublicClient* Fields: ~ - • {request} (`fun(method: string, params: table?, callback: fun(err: lsp.ResponseError?, result: any), notify_reply_callback: fun(integer)?):boolean,integer?`) + • {request} (`fun(method: string, params: table?, callback: fun(err: lsp.ResponseError?, result: any), notify_reply_callback: fun(message_id: integer)?):boolean,integer?`) see |vim.lsp.rpc.request()| • {notify} (`fun(method: string, params: any):boolean`) see |vim.lsp.rpc.notify()| diff --git a/runtime/doc/lua-guide.txt b/runtime/doc/lua-guide.txt index e8757a1859..5f06d51f42 100644 --- a/runtime/doc/lua-guide.txt +++ b/runtime/doc/lua-guide.txt @@ -225,7 +225,6 @@ Vimscript are automatically converted: end vim.fn.jobstart('ls', { on_stdout = print_stdout }) - print(vim.fn.printf('Hello from %s', 'Lua')) < This works for both |builtin-functions| and |user-function|s. diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 3d8453c5a2..396f24a1aa 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -28,17 +28,18 @@ You can also run Lua scripts from your shell using the |-l| argument: > nvim -l foo.lua [args...] < *lua-compat* -Lua 5.1 is the permanent interface for Nvim Lua. Plugins need only consider -Lua 5.1, not worry about forward-compatibility with future Lua versions. If -Nvim ever ships with Lua 5.4+, a Lua 5.1 compatibility shim will be provided -so that old plugins continue to work transparently. +Lua 5.1 is the permanent interface for Nvim Lua. Plugins should target Lua 5.1 +as specified in |luaref|; later versions (which are essentially different, +incompatible, dialects) are not supported. This includes extensions such as +`goto` that some Lua 5.1 interpreters like LuaJIT may support. *lua-luajit* -On supported platforms, Nvim is built with LuaJIT, which provides extra -functionality (compared to PUC Lua) such as "bit" and various utilities (see -|lua-profile|). Lua code in |init.lua| and plugins can assume its presence on -many platforms, but for maximum compatibility should check the `jit` global -variable: >lua +While Nvim officially only requires Lua 5.1 support, it should be built with +LuaJIT or a compatible fork on supported platforms for performance reasons. +LuaJIT also comes with useful extensions such as `ffi`, |lua-profile|, and +enhanced standard library functions; these cannot be assumed to be available, +and Lua code in |init.lua| or plugins should check the `jit` global variable +before using them: >lua if jit then -- code for luajit else @@ -46,11 +47,12 @@ variable: >lua end < *lua-bit* -The LuaJIT "bit" extension module is _always_ available: when built with PUC -Lua, Nvim includes a fallback implementation which provides `require("bit")`. +One exception is the LuaJIT `bit` extension, which is always available: when +built with PUC Lua, Nvim includes a fallback implementation which provides +`require("bit")`. *lua-profile* -To profile Lua code (with LuaJIT-enabled Nvim), the basic steps are: >lua +If Nvim is built with LuaJIT, Lua code can be profiled via >lua -- Start a profiling session: require('jit.p').start('ri1', '/tmp/profile') @@ -59,13 +61,13 @@ To profile Lua code (with LuaJIT-enabled Nvim), the basic steps are: >lua -- Stop the session. Profile is written to /tmp/profile. require('jit.p').stop() -See https://luajit.org/ext_profiler.html or the "p.lua" source for details: > +See https://luajit.org/ext_profiler.html or the `p.lua` source for details: > :lua vim.cmd.edit(package.searchpath('jit.p', package.path)) ============================================================================== LUA CONCEPTS AND IDIOMS *lua-concepts* -Lua is very simple: this means that, while there are some quirks, once you +Lua is very simple, and _consistent_: while there are some quirks, once you internalize those quirks, everything works the same everywhere. Scopes (closures) in particular are very consistent, unlike JavaScript or most other languages. @@ -83,6 +85,36 @@ https://www.lua.org/doc/cacm2018.pdf - Stackful coroutines enable cooperative multithreading, generators, and versatile control for both Lua and its host (Nvim). + *lua-error-handling* +Lua functions may throw |lua-errors| for exceptional (unexpected) failures, +which you can handle with |pcall()|. + *lua-result-or-message* +When failure is normal and expected, it's idiomatic to return `nil` which +signals to the caller that failure is not "exceptional" and must be handled. +This "result-or-message" pattern is expressed as the multi-value return type +`any|nil,nil|string`, or in LuaLS notation: > + + ---@return any|nil # result on success, nil on failure. + ---@return nil|string # nil on success, error message on failure. +< +Examples of the "result-or-message" pattern: +- |vim.ui.open()| +- |io.open()| +- |luv-error-handling| + +When a caller can't proceed on failure, it's idiomatic to `assert()` the +"result-or-message" result: >lua + + local value = assert(fn()) + +Guidance: use the "result-or-message" pattern for... +- Functions where failure is expected, especially when communicating with the + external world. E.g. HTTP requests or LSP requests often fail because of + server problems, even if the caller did everything right. +- Functions that return a value, e.g. Foo:new(). +- When there is a list of known error codes which can be returned as a third + value (like |luv-error-handling|). +< *iterator* An iterator is just a function that can be called repeatedly to get the "next" value of a collection (or any other |iterable|). This interface is expected by @@ -350,16 +382,14 @@ Example: >vim < *lua-table-ambiguous* Lua tables are used as both dictionaries and lists, so it is impossible to -determine whether empty table is meant to be empty list or empty dictionary. -Additionally Lua does not have integer numbers. To distinguish between these -cases there is the following agreement: +decide whether empty table is a list or a dict. Also Lua does not have integer +numbers. To disambiguate these cases, we define: *lua-list* -0. Empty table is empty list. -1. Table with N consecutive integer indices starting from 1 and ending with - N is considered a list. See also |list-iterator|. +0. Empty table is a list. Use |vim.empty_dict()| to represent empty dict. +1. Table with N consecutive (no `nil` values, aka "holes") integer keys 1…N is + a list. See also |list-iterator|. *lua-dict* -2. Table with string keys, none of which contains NUL byte, is considered to - be a dictionary. +2. Table with string keys, none of which contains NUL byte, is a dict. 3. Table with string keys, at least one of which contains NUL byte, is also considered to be a dictionary, but this time it is converted to a |msgpack-special-map|. @@ -543,16 +573,19 @@ Example: File-change detection *watch-file* vim.api.nvim_command( "command! -nargs=1 Watch call luaeval('watch_file(_A)', expand('<args>'))") < - *fswatch-limitations* -When on Linux and using fswatch, you may need to increase the maximum number -of `inotify` watches and queued events as the default limit can be too low. To -increase the limit, run: >sh - sysctl fs.inotify.max_user_watches=100000 - sysctl fs.inotify.max_queued_events=100000 + *inotify-limitations* +When on Linux you may need to increase the maximum number of `inotify` watches +and queued events as the default limit can be too low. To increase the limit, +run: >sh + sysctl fs.inotify.max_user_watches=494462 < -This will increase the limit to 100000 watches and queued events. These lines +This will increase the limit to 494462 watches and queued events. These lines can be added to `/etc/sysctl.conf` to make the changes persistent. +Note that each watch is a structure in the Kernel, thus available memory is +also a bottleneck for using inotify. In fact, a watch can take up to 1KB of +space. This means a million watches could result in 1GB of extra RAM usage. + Example: TCP echo-server *tcp-server* 1. Save this code to a file. 2. Execute it with ":luafile %". @@ -646,8 +679,8 @@ vim.highlight.range({bufnr}, {ns}, {higroup}, {start}, {finish}, {opts}) • {finish} (`integer[]|string`) End of region as a (line, column) tuple or string accepted by |getpos()| • {opts} (`table?`) A table with the following fields: - • {regtype}? (`string`, default: `'charwise'`) Type of - range. See |setreg()| + • {regtype}? (`string`, default: `'v'` i.e. charwise) Type + of range. See |getregtype()| • {inclusive}? (`boolean`, default: `false`) Indicates whether the range is end-inclusive • {priority}? (`integer`, default: @@ -680,47 +713,47 @@ vim.diff({a}, {b}, {opts}) *vim.diff()* Parameters: ~ • {a} (`string`) First string to compare • {b} (`string`) Second string to compare - • {opts} (`table`) Optional parameters: - • {on_hunk} - (`fun(start_a: integer, count_a: integer, start_b: integer, count_b: integer): integer`) + • {opts} (`table?`) Optional parameters: + • {on_hunk}? + (`fun(start_a: integer, count_a: integer, start_b: integer, count_b: integer): integer?`) Invoked for each hunk in the diff. Return a negative number to cancel the callback for any remaining hunks. Arguments: • `start_a` (`integer`): Start line of hunk in {a}. • `count_a` (`integer`): Hunk size in {a}. • `start_b` (`integer`): Start line of hunk in {b}. • `count_b` (`integer`): Hunk size in {b}. - • {result_type} (`'unified'|'indices'`, default: `'unified'`) + • {result_type}? (`'unified'|'indices'`, default: `'unified'`) Form of the returned diff: • `unified`: String in unified format. • `indices`: Array of hunk locations. Note: This option is ignored if `on_hunk` is used. - • {linematch} (`boolean|integer`) Run linematch on the + • {linematch}? (`boolean|integer`) Run linematch on the resulting hunks from xdiff. When integer, only hunks upto this size in lines are run through linematch. Requires `result_type = indices`, ignored otherwise. - • {algorithm} (`'myers'|'minimal'|'patience'|'histogram'`, + • {algorithm}? (`'myers'|'minimal'|'patience'|'histogram'`, default: `'myers'`) Diff algorithm to use. Values: • `myers`: the default algorithm • `minimal`: spend extra time to generate the smallest possible diff • `patience`: patience diff algorithm • `histogram`: histogram diff algorithm - • {ctxlen} (`integer`) Context length - • {interhunkctxlen} (`integer`) Inter hunk context length - • {ignore_whitespace} (`boolean`) Ignore whitespace - • {ignore_whitespace_change} (`boolean`) Ignore whitespace + • {ctxlen}? (`integer`) Context length + • {interhunkctxlen}? (`integer`) Inter hunk context length + • {ignore_whitespace}? (`boolean`) Ignore whitespace + • {ignore_whitespace_change}? (`boolean`) Ignore whitespace change - • {ignore_whitespace_change_at_eol} (`boolean`) Ignore + • {ignore_whitespace_change_at_eol}? (`boolean`) Ignore whitespace change at end-of-line. - • {ignore_cr_at_eol} (`boolean`) Ignore carriage return at + • {ignore_cr_at_eol}? (`boolean`) Ignore carriage return at end-of-line - • {ignore_blank_lines} (`boolean`) Ignore blank lines - • {indent_heuristic} (`boolean`) Use the indent heuristic for + • {ignore_blank_lines}? (`boolean`) Ignore blank lines + • {indent_heuristic}? (`boolean`) Use the indent heuristic for the internal diff library. Return: ~ - (`string|integer[]`) See {opts.result_type}. `nil` if {opts.on_hunk} - is given. + (`string|integer[][]?`) See {opts.result_type}. `nil` if + {opts.on_hunk} is given. ============================================================================== @@ -834,8 +867,8 @@ vim.spell.check({str}) *vim.spell.check()* • {str} (`string`) Return: ~ - (`{[1]: string, [2]: 'bad'|'rare'|'local'|'caps', [3]: integer}[]`) - List of tuples with three items: + (`[string, 'bad'|'rare'|'local'|'caps', integer][]`) List of tuples + with three items: • The badly spelled word. • The type of the spelling error: "bad" spelling mistake "rare" rare word "local" word only valid in another region "caps" word should @@ -981,6 +1014,9 @@ vim.str_byteindex({str}, {index}, {use_utf16}) *vim.str_byteindex()* • {index} (`integer`) • {use_utf16} (`boolean?`) + Return: ~ + (`integer`) + vim.str_utf_end({str}, {index}) *vim.str_utf_end()* Gets the distance (in bytes) from the last byte of the codepoint (character) that {index} points to. @@ -1067,7 +1103,9 @@ vim.stricmp({a}, {b}) *vim.stricmp()* lesser than {b}, respectively. vim.ui_attach({ns}, {options}, {callback}) *vim.ui_attach()* - Attach to ui events, similar to |nvim_ui_attach()| but receive events as + WARNING: This feature is experimental/unstable. + + Attach to |ui-events|, similar to |nvim_ui_attach()| but receive events as Lua callback. Can be used to implement screen elements like popupmenu or message handling in Lua. @@ -1660,8 +1698,11 @@ vim.on_key({fn}, {ns_id}) *vim.on_key()* callbacks if on_key() is called without arguments. vim.paste({lines}, {phase}) *vim.paste()* - Paste handler, invoked by |nvim_paste()| when a conforming UI (such as the - |TUI|) pastes text into the editor. + Paste handler, invoked by |nvim_paste()|. + + Note: This is provided only as a "hook", don't call it directly; call + |nvim_paste()| instead, which arranges redo (dot-repeat) and invokes + `vim.paste`. Example: To remove ANSI color codes when pasting: >lua vim.paste = (function(overridden) @@ -1670,7 +1711,7 @@ vim.paste({lines}, {phase}) *vim.paste()* -- Scrub ANSI color codes from paste input. lines[i] = line:gsub('\27%[[0-9;mK]+', '') end - overridden(lines, phase) + return overridden(lines, phase) end end)(vim.paste) < @@ -1708,30 +1749,6 @@ vim.print({...}) *vim.print()* • |vim.inspect()| • |:=| - *vim.region()* -vim.region({bufnr}, {pos1}, {pos2}, {regtype}, {inclusive}) - Gets a dict of line segment ("chunk") positions for the region from `pos1` - to `pos2`. - - Input and output positions are byte positions, (0,0)-indexed. "End of - line" column position (for example, |linewise| visual selection) is - returned as |v:maxcol| (big number). - - Parameters: ~ - • {bufnr} (`integer`) Buffer number, or 0 for current buffer - • {pos1} (`integer[]|string`) Start of region as a (line, column) - tuple or |getpos()|-compatible string - • {pos2} (`integer[]|string`) End of region as a (line, column) - tuple or |getpos()|-compatible string - • {regtype} (`string`) |setreg()|-style selection type - • {inclusive} (`boolean`) Controls whether the ending column is - inclusive (see also 'selection'). - - Return: ~ - (`table`) region Dict of the form `{linenr = {startcol,endcol}}`. - `endcol` is exclusive, and whole lines are returned as - `{startcol,endcol} = {0,-1}`. - vim.schedule_wrap({fn}) *vim.schedule_wrap()* Returns a function which calls {fn} via |vim.schedule()|. @@ -1841,6 +1858,9 @@ vim.inspect_pos({bufnr}, {row}, {col}, {filter}) *vim.inspect_pos()* Can also be pretty-printed with `:Inspect!`. *:Inspect!* + Attributes: ~ + Since: 0.9.0 + Parameters: ~ • {bufnr} (`integer?`) defaults to the current buffer • {row} (`integer?`) row to inspect, 0-based. Defaults to the row of @@ -1874,6 +1894,9 @@ vim.show_pos({bufnr}, {row}, {col}, {filter}) *vim.show_pos()* Can also be shown with `:Inspect`. *:Inspect* + Attributes: ~ + Since: 0.9.0 + Parameters: ~ • {bufnr} (`integer?`) defaults to the current buffer • {row} (`integer?`) row to inspect, 0-based. Defaults to the row of @@ -2248,6 +2271,12 @@ vim.tbl_count({t}) *vim.tbl_count()* vim.tbl_deep_extend({behavior}, {...}) *vim.tbl_deep_extend()* Merges recursively two or more tables. + Only values that are empty tables or tables that are not |lua-list|s + (indexed by consecutive integers starting from 1) are merged recursively. + This is useful for merging nested tables like default and user + configurations where lists should be treated as literals (i.e., are + overwritten instead of merged). + Parameters: ~ • {behavior} (`'error'|'keep'|'force'`) Decides what to do if a key is found in more than one map: @@ -2366,7 +2395,26 @@ vim.trim({s}) *vim.trim()* • https://www.lua.org/pil/20.2.html vim.validate({opt}) *vim.validate()* - Validates a parameter specification (types and values). Specs are + Validate function arguments. + + This function has two valid forms: + 1. vim.validate(name: str, value: any, type: string, optional?: bool) + 2. vim.validate(spec: table) + + Form 1 validates that argument {name} with value {value} has the type + {type}. {type} must be a value returned by |lua-type()|. If {optional} is + true, then {value} may be null. This form is significantly faster and + should be preferred for simple cases. + + Example: >lua + function vim.startswith(s, prefix) + vim.validate('s', s, 'string') + vim.validate('prefix', prefix, 'string') + ... + end +< + + Form 2 validates a parameter specification (types and values). Specs are evaluated in alphanumeric order, until the first failure. Usage example: >lua @@ -2421,11 +2469,15 @@ vim.validate({opt}) *vim.validate()* Lua module: vim.loader *vim.loader* vim.loader.disable() *vim.loader.disable()* + WARNING: This feature is experimental/unstable. + Disables the experimental Lua module loader: • removes the loaders • adds the default Nvim loader vim.loader.enable() *vim.loader.enable()* + WARNING: This feature is experimental/unstable. + Enables the experimental Lua module loader: • overrides loadfile • adds the Lua loader using the byte-compilation cache @@ -2433,6 +2485,8 @@ vim.loader.enable() *vim.loader.enable()* • removes the default Nvim loader vim.loader.find({modname}, {opts}) *vim.loader.find()* + WARNING: This feature is experimental/unstable. + Finds Lua modules for the given module name. Parameters: ~ @@ -2458,6 +2512,8 @@ vim.loader.find({modname}, {opts}) *vim.loader.find()* returned for `modname="*"` vim.loader.reset({path}) *vim.loader.reset()* + WARNING: This feature is experimental/unstable. + Resets the cache for the path, or all the paths if path is nil. Parameters: ~ @@ -2552,7 +2608,7 @@ vim.ui.input({opts}, {on_confirm}) *vim.ui.input()* typed (it might be an empty string if nothing was entered), or `nil` if the user aborted the dialog. -vim.ui.open({path}) *vim.ui.open()* +vim.ui.open({path}, {opt}) *vim.ui.open()* Opens `path` with the system default handler (macOS `open`, Windows `explorer.exe`, Linux `xdg-open`, …), or returns (but does not show) an error message on failure. @@ -2563,6 +2619,8 @@ vim.ui.open({path}) *vim.ui.open()* -- Asynchronous. vim.ui.open("https://neovim.io/") vim.ui.open("~/path/to/file") + -- Use the "osurl" command to handle the path or URL. + vim.ui.open("gh#neovim/neovim!29490", { cmd = { 'osurl' } }) -- Synchronous (wait until the process exits). local cmd, err = vim.ui.open("$VIMRUNTIME") if cmd then @@ -2572,6 +2630,8 @@ vim.ui.open({path}) *vim.ui.open()* Parameters: ~ • {path} (`string`) Path or URL to open + • {opt} (`{ cmd?: string[] }?`) Options + • cmd string[]|nil Command used to open the path or URL. Return (multiple): ~ (`vim.SystemObj?`) Command object, or nil if not found. @@ -2671,7 +2731,7 @@ vim.filetype.add({filetypes}) *vim.filetype.add()* ['.*/etc/foo/.*%.conf'] = { 'dosini', { priority = 10 } }, -- A pattern containing an environment variable ['${XDG_CONFIG_HOME}/foo/git'] = 'git', - ['README.(%a+)$'] = function(path, bufnr, ext) + ['.*README.(%a+)'] = function(path, bufnr, ext) if ext == 'md' then return 'markdown' elseif ext == 'rst' then @@ -2723,6 +2783,9 @@ vim.filetype.get_option({filetype}, {option}) means |ftplugin| and |FileType| autocommands are only triggered once and may not reflect later changes. + Attributes: ~ + Since: 0.9.0 + Parameters: ~ • {filetype} (`string`) Filetype • {option} (`string`) Option name @@ -2803,24 +2866,24 @@ vim.keymap.del({modes}, {lhs}, {opts}) *vim.keymap.del()* • |vim.keymap.set()| vim.keymap.set({mode}, {lhs}, {rhs}, {opts}) *vim.keymap.set()* - Adds a new |mapping|. Examples: >lua - -- Map to a Lua function: - vim.keymap.set('n', 'lhs', function() print("real lua function") end) - -- Map to multiple modes: - vim.keymap.set({'n', 'v'}, '<leader>lr', vim.lsp.buf.references, { buffer = true }) - -- Buffer-local mapping: - vim.keymap.set('n', '<leader>w', "<cmd>w<cr>", { silent = true, buffer = 5 }) - -- Expr mapping: + Defines a |mapping| of |keycodes| to a function or keycodes. + + Examples: >lua + -- Map "x" to a Lua function: + vim.keymap.set('n', 'x', function() print("real lua function") end) + -- Map "<leader>x" to multiple modes for the current buffer: + vim.keymap.set({'n', 'v'}, '<leader>x', vim.lsp.buf.references, { buffer = true }) + -- Map <Tab> to an expression (|:map-<expr>|): vim.keymap.set('i', '<Tab>', function() return vim.fn.pumvisible() == 1 and "<C-n>" or "<Tab>" end, { expr = true }) - -- <Plug> mapping: + -- Map "[%%" to a <Plug> mapping: vim.keymap.set('n', '[%%', '<Plug>(MatchitNormalMultiBackward)') < Parameters: ~ - • {mode} (`string|string[]`) Mode short-name, see |nvim_set_keymap()|. - Can also be list of modes to create mapping on multiple modes. + • {mode} (`string|string[]`) Mode "short-name" (see + |nvim_set_keymap()|), or a list thereof. • {lhs} (`string`) Left-hand side |{lhs}| of the mapping. • {rhs} (`string|function`) Right-hand side |{rhs}| of the mapping, can be a Lua function. @@ -2847,6 +2910,9 @@ Lua module: vim.fs *vim.fs* vim.fs.basename({file}) *vim.fs.basename()* Return the basename of the given path + Attributes: ~ + Since: 0.8.0 + Parameters: ~ • {file} (`string?`) Path @@ -2856,6 +2922,9 @@ vim.fs.basename({file}) *vim.fs.basename()* vim.fs.dir({path}, {opts}) *vim.fs.dir()* Return an iterator over the items located in {path} + Attributes: ~ + Since: 0.8.0 + Parameters: ~ • {path} (`string`) An absolute or relative path to the directory to iterate over. The path is first normalized @@ -2875,6 +2944,9 @@ vim.fs.dir({path}, {opts}) *vim.fs.dir()* vim.fs.dirname({file}) *vim.fs.dirname()* Return the parent directory of the given path + Attributes: ~ + Since: 0.8.0 + Parameters: ~ • {file} (`string?`) Path @@ -2907,6 +2979,9 @@ vim.fs.find({names}, {opts}) *vim.fs.find()* end, {limit = math.huge, type = 'file'}) < + Attributes: ~ + Since: 0.8.0 + Parameters: ~ • {names} (`string|string[]|fun(name: string, path: string): boolean`) Names of the items to find. Must be base names, paths and @@ -2938,6 +3013,9 @@ vim.fs.joinpath({...}) *vim.fs.joinpath()* Concatenate directories and/or file paths into a single path with normalization (e.g., `"foo/"` and `"bar"` get joined to `"foo/bar"`) + Attributes: ~ + Since: 0.10.0 + Parameters: ~ • {...} (`string`) @@ -2974,6 +3052,9 @@ vim.fs.normalize({path}, {opts}) *vim.fs.normalize()* [[\\?\UNC\server\share\foo\..\..\..\bar]] => "//?/UNC/server/share/bar" < + Attributes: ~ + Since: 0.8.0 + Parameters: ~ • {path} (`string`) Path to normalize • {opts} (`table?`) A table with the following fields: @@ -3002,6 +3083,9 @@ vim.fs.parents({start}) *vim.fs.parents()* end < + Attributes: ~ + Since: 0.8.0 + Parameters: ~ • {start} (`string`) Initial path. @@ -3010,6 +3094,18 @@ vim.fs.parents({start}) *vim.fs.parents()* (`nil`) (`string?`) +vim.fs.rm({path}, {opts}) *vim.fs.rm()* + WARNING: This feature is experimental/unstable. + + Remove files or directories + + Parameters: ~ + • {path} (`string`) Path to remove + • {opts} (`table?`) A table with the following fields: + • {recursive}? (`boolean`) Remove directories and their + contents recursively + • {force}? (`boolean`) Ignore nonexistent files and arguments + vim.fs.root({source}, {marker}) *vim.fs.root()* Find the first parent directory containing a specific "marker", relative to a file path or buffer. @@ -3030,6 +3126,9 @@ vim.fs.root({source}, {marker}) *vim.fs.root()* end) < + Attributes: ~ + Since: 0.10.0 + Parameters: ~ • {source} (`integer|string`) Buffer number (0 for current buffer) or file path (absolute or relative to the |current-directory|) @@ -3089,7 +3188,7 @@ In addition, its regex-like interface is available as |vim.re| -Pattern:match({subject}, {init}) *Pattern:match()* +Pattern:match({subject}, {init}, {...}) *Pattern:match()* Matches the given `pattern` against the `subject` string. If the match succeeds, returns the index in the subject of the first character after the match, or the captured values (if the pattern captured any value). An @@ -3112,9 +3211,10 @@ Pattern:match({subject}, {init}) *Pattern:match()* Parameters: ~ • {subject} (`string`) • {init} (`integer?`) + • {...} (`any`) Return: ~ - (`integer|vim.lpeg.Capture?`) + (`any`) ... vim.lpeg.B({pattern}) *vim.lpeg.B()* Returns a pattern that matches only if the input string at the current @@ -3124,7 +3224,7 @@ vim.lpeg.B({pattern}) *vim.lpeg.B()* or failure. Parameters: ~ - • {pattern} (`vim.lpeg.Pattern`) + • {pattern} (`vim.lpeg.Pattern|string|integer|boolean|table`) Return: ~ (`vim.lpeg.Pattern`) @@ -3148,7 +3248,7 @@ vim.lpeg.C({patt}) *vim.lpeg.C()* < Parameters: ~ - • {patt} (`vim.lpeg.Pattern`) + • {patt} (`vim.lpeg.Pattern|string|integer|boolean|table|function`) Return: ~ (`vim.lpeg.Capture`) @@ -3199,11 +3299,11 @@ vim.lpeg.Cf({patt}, {func}) *vim.lpeg.Cf()* This capture assumes that `patt` should produce at least one capture with at least one value (of any type), which becomes the initial value of an accumulator. (If you need a specific initial value, you may prefix a - constant captureto `patt`.) For each subsequent capture, LPeg calls `func` - with this accumulator as the first argument and all values produced by the - capture as extra arguments; the first result from this call becomes the - new value for the accumulator. The final value of the accumulator becomes - the captured value. + constant capture to `patt`.) For each subsequent capture, LPeg calls + `func` with this accumulator as the first argument and all values produced + by the capture as extra arguments; the first result from this call becomes + the new value for the accumulator. The final value of the accumulator + becomes the captured value. Example: >lua local number = lpeg.R('09') ^ 1 / tonumber @@ -3214,7 +3314,7 @@ vim.lpeg.Cf({patt}, {func}) *vim.lpeg.Cf()* < Parameters: ~ - • {patt} (`vim.lpeg.Pattern`) + • {patt} (`vim.lpeg.Pattern|string|integer|boolean|table|function`) • {func} (`fun(acc, newvalue)`) Return: ~ @@ -3226,7 +3326,7 @@ vim.lpeg.Cg({patt}, {name}) *vim.lpeg.Cg()* with the given name (which can be any non-nil Lua value). Parameters: ~ - • {patt} (`vim.lpeg.Pattern`) + • {patt} (`vim.lpeg.Pattern|string|integer|boolean|table|function`) • {name} (`string?`) Return: ~ @@ -3249,8 +3349,9 @@ vim.lpeg.Cmt({patt}, {fn}) *vim.lpeg.Cmt()* function become the values produced by the capture. Parameters: ~ - • {patt} (`vim.lpeg.Pattern`) - • {fn} (`function`) + • {patt} (`vim.lpeg.Pattern|string|integer|boolean|table|function`) + • {fn} (`fun(s: string, i: integer, ...: any)`) (position: + boolean|integer, ...: any) Return: ~ (`vim.lpeg.Capture`) @@ -3289,7 +3390,7 @@ vim.lpeg.Cs({patt}) *vim.lpeg.Cs()* < Parameters: ~ - • {patt} (`vim.lpeg.Pattern`) + • {patt} (`vim.lpeg.Pattern|string|integer|boolean|table|function`) Return: ~ (`vim.lpeg.Capture`) @@ -3302,7 +3403,7 @@ vim.lpeg.Ct({patt}) *vim.lpeg.Ct()* the group name as its key. The captured value is only the table. Parameters: ~ - • {patt} (`vim.lpeg.Pattern|''`) + • {patt} (`vim.lpeg.Pattern|string|integer|boolean|table|function`) Return: ~ (`vim.lpeg.Capture`) @@ -3337,7 +3438,7 @@ vim.lpeg.locale({tab}) *vim.lpeg.locale()* Return: ~ (`vim.lpeg.Locale`) -vim.lpeg.match({pattern}, {subject}, {init}) *vim.lpeg.match()* +vim.lpeg.match({pattern}, {subject}, {init}, {...}) *vim.lpeg.match()* Matches the given `pattern` against the `subject` string. If the match succeeds, returns the index in the subject of the first character after the match, or the captured values (if the pattern captured any value). An @@ -3358,12 +3459,13 @@ vim.lpeg.match({pattern}, {subject}, {init}) *vim.lpeg.match()* < Parameters: ~ - • {pattern} (`vim.lpeg.Pattern`) + • {pattern} (`vim.lpeg.Pattern|string|integer|boolean|table|function`) • {subject} (`string`) • {init} (`integer?`) + • {...} (`any`) Return: ~ - (`integer|vim.lpeg.Capture?`) + (`any`) ... vim.lpeg.P({value}) *vim.lpeg.P()* Converts the given value into a proper pattern. The following rules are @@ -3457,7 +3559,7 @@ vim.lpeg.V({v}) *vim.lpeg.V()* < Parameters: ~ - • {v} (`string|integer`) + • {v} (`boolean|string|number|function|table|thread|userdata|lightuserdata`) Return: ~ (`vim.lpeg.Pattern`) @@ -3550,10 +3652,10 @@ within a single line. *regex:match_line()* regex:match_line({bufnr}, {line_idx}, {start}, {end_}) - Match line {line_idx} (zero-based) in buffer {bufnr}. If {start} and {end} - are supplied, match only this byte index range. Otherwise see - |regex:match_str()|. If {start} is used, then the returned byte indices - will be relative {start}. + Matches line at `line_idx` (zero-based) in buffer `bufnr`. Match is + restricted to byte index range `start` and `end_` if given, otherwise see + |regex:match_str()|. Returned byte indices are relative to `start` if + given. Parameters: ~ • {bufnr} (`integer`) @@ -3561,19 +3663,28 @@ regex:match_line({bufnr}, {line_idx}, {start}, {end_}) • {start} (`integer?`) • {end_} (`integer?`) + Return (multiple): ~ + (`integer?`) match start (byte index) relative to `start`, or `nil` if + no match + (`integer?`) match end (byte index) relative to `start`, or `nil` if + no match + regex:match_str({str}) *regex:match_str()* - Match the string against the regex. If the string should match the regex - precisely, surround the regex with `^` and `$`. If there was a match, the - byte indices for the beginning and end of the match are returned. When - there is no match, `nil` is returned. Because any integer is "truthy", - `regex:match_str()` can be directly used as a condition in an - if-statement. + Matches string `str` against this regex. To match the string precisely, + surround the regex with "^" and "$". Returns the byte indices for the + start and end of the match, or `nil` if there is no match. Because any + integer is "truthy", `regex:match_str()` can be directly used as a + condition in an if-statement. Parameters: ~ • {str} (`string`) + Return (multiple): ~ + (`integer?`) match start (byte index), or `nil` if no match + (`integer?`) match end (byte index), or `nil` if no match + vim.regex({re}) *vim.regex()* - Parse the Vim regex {re} and return a regex object. Regexes are "magic" + Parses the Vim regex `re` and returns a regex object. Regexes are "magic" and case-sensitive by default, regardless of 'magic' and 'ignorecase'. They can be controlled with flags, see |/magic| and |/ignorecase|. @@ -3592,6 +3703,9 @@ vim.secure.read({path}) *vim.secure.read()* be trusted. The user's choice is persisted in a trust database at $XDG_STATE_HOME/nvim/trust. + Attributes: ~ + Since: 0.9.0 + Parameters: ~ • {path} (`string`) Path to a file to read. @@ -3607,6 +3721,9 @@ vim.secure.trust({opts}) *vim.secure.trust()* The trust database is located at |$XDG_STATE_HOME|/nvim/trust. + Attributes: ~ + Since: 0.9.0 + Parameters: ~ • {opts} (`table`) A table with the following fields: • {action} (`'allow'|'deny'|'remove'`) - `'allow'` to add a @@ -3698,6 +3815,9 @@ vim.version.cmp({v1}, {v2}) *vim.version.cmp()* • Per semver, build metadata is ignored when comparing two otherwise-equivalent versions. + Attributes: ~ + Since: 0.9.0 + Parameters: ~ • {v1} (`vim.Version|number[]|string`) Version object. • {v2} (`vim.Version|number[]|string`) Version to compare with `v1`. @@ -3709,6 +3829,9 @@ vim.version.eq({v1}, {v2}) *vim.version.eq()* Returns `true` if the given versions are equal. See |vim.version.cmp()| for usage. + Attributes: ~ + Since: 0.9.0 + Parameters: ~ • {v1} (`vim.Version|number[]|string`) • {v2} (`vim.Version|number[]|string`) @@ -3719,6 +3842,9 @@ vim.version.eq({v1}, {v2}) *vim.version.eq()* vim.version.ge({v1}, {v2}) *vim.version.ge()* Returns `true` if `v1 >= v2`. See |vim.version.cmp()| for usage. + Attributes: ~ + Since: 0.10.0 + Parameters: ~ • {v1} (`vim.Version|number[]|string`) • {v2} (`vim.Version|number[]|string`) @@ -3729,6 +3855,9 @@ vim.version.ge({v1}, {v2}) *vim.version.ge()* vim.version.gt({v1}, {v2}) *vim.version.gt()* Returns `true` if `v1 > v2`. See |vim.version.cmp()| for usage. + Attributes: ~ + Since: 0.9.0 + Parameters: ~ • {v1} (`vim.Version|number[]|string`) • {v2} (`vim.Version|number[]|string`) @@ -3748,6 +3877,9 @@ vim.version.last({versions}) *vim.version.last()* vim.version.le({v1}, {v2}) *vim.version.le()* Returns `true` if `v1 <= v2`. See |vim.version.cmp()| for usage. + Attributes: ~ + Since: 0.10.0 + Parameters: ~ • {v1} (`vim.Version|number[]|string`) • {v2} (`vim.Version|number[]|string`) @@ -3758,6 +3890,9 @@ vim.version.le({v1}, {v2}) *vim.version.le()* vim.version.lt({v1}, {v2}) *vim.version.lt()* Returns `true` if `v1 < v2`. See |vim.version.cmp()| for usage. + Attributes: ~ + Since: 0.9.0 + Parameters: ~ • {v1} (`vim.Version|number[]|string`) • {v2} (`vim.Version|number[]|string`) @@ -3772,6 +3907,9 @@ vim.version.parse({version}, {opts}) *vim.version.parse()* { major = 1, minor = 0, patch = 1, prerelease = "rc1", build = "build.2" } < + Attributes: ~ + Since: 0.9.0 + Parameters: ~ • {version} (`string`) Version string to parse. • {opts} (`table?`) Optional keyword arguments: @@ -3812,6 +3950,9 @@ vim.version.range({spec}) *vim.version.range()* print(vim.version.ge({1,0,3}, r.from) and vim.version.lt({1,0,3}, r.to)) < + Attributes: ~ + Since: 0.9.0 + Parameters: ~ • {spec} (`string`) Version range "spec" @@ -3833,10 +3974,12 @@ argument into an *Iter* object with methods (such as |Iter:filter()| and chained to create iterator "pipelines": the output of each pipeline stage is input to the next stage. The first stage depends on the type passed to `vim.iter()`: -• List tables (arrays, |lua-list|) yield only the value of each element. - • Holes (nil values) are allowed. +• Lists or arrays (|lua-list|) yield only the value of each element. + • Holes (nil values) are allowed (but discarded). + • Use pairs() to treat array/list tables as dicts (preserve holes and + non-contiguous integer keys): `vim.iter(pairs(…))`. • Use |Iter:enumerate()| to also pass the index to the next stage. - • Or initialize with ipairs(): `vim.iter(ipairs(…))`. + • Or initialize with ipairs(): `vim.iter(ipairs(…))`. • Non-list tables (|lua-dict|) yield both the key and value of each element. • Function |iterator|s yield all values returned by the underlying function. • Tables with a |__call()| metamethod are treated as function iterators. @@ -4084,10 +4227,10 @@ Iter:map({f}) *Iter:map()* < Parameters: ~ - • {f} (`fun(...):any`) Mapping function. Takes all values returned from - the previous stage in the pipeline as arguments and returns one - or more new values, which are used in the next pipeline stage. - Nil return values are filtered from the output. + • {f} (`fun(...):...:any`) Mapping function. Takes all values returned + from the previous stage in the pipeline as arguments and returns + one or more new values, which are used in the next pipeline + stage. Nil return values are filtered from the output. Return: ~ (`Iter`) @@ -4332,7 +4475,7 @@ vim.snippet.active({filter}) *vim.snippet.active()* You can use this function to navigate a snippet as follows: >lua vim.keymap.set({ 'i', 's' }, '<Tab>', function() if vim.snippet.active({ direction = 1 }) then - return '<cmd>lua vim.snippet.jump(1)<cr>' + return '<Cmd>lua vim.snippet.jump(1)<CR>' else return '<Tab>' end @@ -4366,7 +4509,7 @@ vim.snippet.jump({direction}) *vim.snippet.jump()* For example, map `<Tab>` to jump while a snippet is active: >lua vim.keymap.set({ 'i', 's' }, '<Tab>', function() if vim.snippet.active({ direction = 1 }) then - return '<cmd>lua vim.snippet.jump(1)<cr>' + return '<Cmd>lua vim.snippet.jump(1)<CR>' else return '<Tab>' end @@ -4390,8 +4533,9 @@ vim.text.hexdecode({enc}) *vim.text.hexdecode()* Parameters: ~ • {enc} (`string`) String to decode - Return: ~ - (`string`) Decoded string + Return (multiple): ~ + (`string?`) Decoded string + (`string?`) Error message, if any vim.text.hexencode({str}) *vim.text.hexencode()* Hex encode a string. @@ -4407,7 +4551,7 @@ vim.text.hexencode({str}) *vim.text.hexencode()* Lua module: tohtml *vim.tohtml* -:TOhtml {file} *:TOhtml* +:[range]TOhtml {file} *:TOhtml* Converts the buffer shown in the current window to HTML, opens the generated HTML in a new split window, and saves its contents to {file}. If {file} is not given, a temporary file (created by |tempname()|) is used. @@ -4429,6 +4573,8 @@ tohtml.tohtml({winid}, {opt}) *tohtml.tohtml.tohtml()* • {width}? (`integer`, default: 'textwidth' if non-zero or window width otherwise) Width used for items which are either right aligned or repeat a character infinitely. + • {range}? (`integer[]`, default: entire buffer) Range of + rows to use. Return: ~ (`string[]`) diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt index 9ec34d5d52..7fd1f3bfbb 100644 --- a/runtime/doc/map.txt +++ b/runtime/doc/map.txt @@ -354,7 +354,8 @@ Note: *E1255* *E1136* <Cmd> commands must terminate, that is, they must be followed by <CR> in the -{rhs} of the mapping definition. |Command-line| mode is never entered. +{rhs} of the mapping definition. |Command-line| mode is never entered. To use +a literal <CR> in the {rhs}, use |<lt>|. 1.3 MAPPING AND MODES *:map-modes* @@ -1380,12 +1381,14 @@ completion can be enabled: -complete=arglist file names in argument list -complete=augroup autocmd groups + -complete=breakpoint |:breakadd| suboptions -complete=buffer buffer names - -complete=behave :behave suboptions -complete=color color schemes -complete=command Ex command (and arguments) -complete=compiler compilers + -complete=diff_buffer diff buffer names -complete=dir directory names + -complete=dir_in_path directory names in |'cdpath'| -complete=environment environment variable names -complete=event autocommand events -complete=expression Vim expression @@ -1395,7 +1398,7 @@ completion can be enabled: -complete=function function name -complete=help help subjects -complete=highlight highlight groups - -complete=history :history suboptions + -complete=history |:history| suboptions -complete=keymap keyboard mappings -complete=locale locale names (as output of locale -a) -complete=lua Lua expression |:lua| @@ -1405,6 +1408,8 @@ completion can be enabled: -complete=messages |:messages| suboptions -complete=option options -complete=packadd optional package |pack-add| names + -complete=runtime file and directory names in |'runtimepath'| + -complete=scriptnames sourced script names -complete=shellcmd Shell command -complete=sign |:sign| suboptions -complete=syntax syntax file names |'syntax'| @@ -1679,7 +1684,7 @@ The valid escape sequences are nothing. Supported modifiers are |:aboveleft|, |:belowright|, |:botright|, |:browse|, |:confirm|, |:hide|, |:horizontal|, |:keepalt|, |:keepjumps|, |:keepmarks|, |:keeppatterns|, - |:leftabove|, |:lockmarks|, |:noautocmd|, |:noswapfile| + |:leftabove|, |:lockmarks|, |:noautocmd|, |:noswapfile|, |:rightbelow|, |:sandbox|, |:silent|, |:tab|, |:topleft|, |:unsilent|, |:verbose|, and |:vertical|. Note that |:filter| is not supported. diff --git a/runtime/doc/mbyte.txt b/runtime/doc/mbyte.txt index 0a7e0baad3..47fd4f3343 100644 --- a/runtime/doc/mbyte.txt +++ b/runtime/doc/mbyte.txt @@ -646,6 +646,12 @@ widespread as file format. A composing or combining character is used to change the meaning of the character before it. The combining characters are drawn on top of the preceding character. + +Nvim largely follows the definition of extended grapheme clusters in UAX#29 +in the Unicode standard, with some modifications: An ascii char will always +start a new cluster. In addition 'arabicshape' enables the combining of some +arabic letters, when they are shaped to be displayed together in a single cell. + Too big combined characters cannot be displayed, but they can still be inspected using the |g8| and |ga| commands described below. When editing text a composing character is mostly considered part of the @@ -686,7 +692,7 @@ You might want to select the font used for the menus. Unfortunately this doesn't always work. See the system specific remarks below, and 'langmenu'. -USING UTF-8 IN X-Windows *utf-8-in-xwindows* +USING UTF-8 IN X-WINDOWS *utf-8-in-xwindows* You need to specify a font to be used. For double-wide characters another font is required, which is exactly twice as wide. There are three ways to do diff --git a/runtime/doc/message.txt b/runtime/doc/message.txt index afe64300e7..ac151811c2 100644 --- a/runtime/doc/message.txt +++ b/runtime/doc/message.txt @@ -690,6 +690,7 @@ Ex command or function was given an invalid argument. Or |jobstart()| or *E488* > Trailing characters + Trailing characters: {text} An argument was given to an Ex command that does not permit one. Or the argument has invalid characters and has not been recognized. @@ -756,7 +757,7 @@ src/ex_cmds.lua. Update the lookup table by re-running the build. > This is an (incomplete) overview of various messages that Vim gives: *hit-enter* *press-enter* *hit-return* - *press-return* *hit-enter-prompt* + *press-return* *hit-enter-prompt* > Press ENTER or type command to continue diff --git a/runtime/doc/motion.txt b/runtime/doc/motion.txt index e80969c583..48e13d795e 100644 --- a/runtime/doc/motion.txt +++ b/runtime/doc/motion.txt @@ -60,10 +60,12 @@ When doubling the operator it operates on a line. When using a count, before or after the first character, that many lines are operated upon. Thus `3dd` deletes three lines. A count before and after the first character is multiplied, thus `2y3y` yanks six lines. - + *operator-resulting-pos* After applying the operator the cursor is mostly left at the start of the text that was operated upon. For example, "yfe" doesn't move the cursor, but "yFe" moves the cursor leftwards to the "e" where the yank started. +The 'startofline' option applies only to the "d", "<<", "==" and ">>" linewise +operations. *linewise* *charwise* *characterwise* The operator either affects whole lines, or the characters between the start @@ -162,9 +164,9 @@ h or *h* CTRL-H or *CTRL-H* *<BS>* <BS> [count] characters to the left. |exclusive| motion. Note: If you prefer <BS> to delete a character, use - the mapping: + the mapping: > :map CTRL-V<BS> X - (to enter "CTRL-V<BS>" type the CTRL-V key, followed +< (to enter "CTRL-V<BS>" type the CTRL-V key, followed by the <BS> key) l or *l* @@ -342,6 +344,7 @@ gg Goto line [count], default first line, on the first *:[range]* :[range] Set the cursor on the last line number in [range]. + In Ex mode, print the lines in [range]. [range] can also be just one line number, e.g., ":1" or ":'m". In contrast with |G| this command does not modify the @@ -354,11 +357,11 @@ gg Goto line [count], default first line, on the first See also 'startofline' option. :[range]go[to] [count] *:go* *:goto* *go* -[count]go Go to [count] byte in the buffer. Default [count] is - one, start of the file. When giving [range], the - last number in it used as the byte count. End-of-line - characters are counted depending on the current - 'fileformat' setting. +[count]go Go to [count] byte in the buffer. |exclusive| motion. + Default [count] is one, start of the file. When + giving [range], the last number in it used as the byte + count. End-of-line characters are counted depending + on the current 'fileformat' setting. Also see the |line2byte()| function, and the 'o' option in 'statusline'. diff --git a/runtime/doc/news-0.10.txt b/runtime/doc/news-0.10.txt index 8a0e7e92e7..a5ded1ca22 100644 --- a/runtime/doc/news-0.10.txt +++ b/runtime/doc/news-0.10.txt @@ -155,8 +155,6 @@ The following new features were added. • |nvim_input_mouse()| supports mouse buttons "x1" and "x2". • Added "force_crlf" option field in |nvim_open_term()|. • Added |nvim_tabpage_set_win()| to set the current window of a tabpage. - • |nvim__win_add_ns()| can bind a |namespace| to a window-local scope(s). - • Extmarks opt-in to this scoping via the `scoped` flag of |nvim_buf_set_extmark()|. • Mapping APIs now support abbreviations when mode short-name has suffix "a". • Floating windows can now show footer with new `footer` and `footer_pos` config fields. Uses |hl-FloatFooter| by default. @@ -307,7 +305,7 @@ The following new features were added. a predicate function that is checked for each value. (Use |vim.list_contains()| for checking list-like tables (integer keys without gaps) for literal values.) - • |vim.region()| can use a string accepted by |getpos()| as position. + • vim.region() can use a string accepted by |getpos()| as position. • Options: • 'winfixbuf' keeps a window focused onto a specific buffer @@ -349,8 +347,8 @@ The following new features were added. |default-autocmds| • Treesitter: - • Bundled parsers and queries (highlight, folds) for Markdown, Python, and - Bash. + • Bundled parser and queries (highlight, folds) for Markdown (used for LSP + hover). • |:InspectTree| shows root nodes. • |:InspectTree| now supports |folding|. • |:InspectTree| shows node ranges in 0-based instead of 1-based indexing. diff --git a/runtime/doc/news-0.9.txt b/runtime/doc/news-0.9.txt index 7905d6c3e3..3b078cf2cd 100644 --- a/runtime/doc/news-0.9.txt +++ b/runtime/doc/news-0.9.txt @@ -92,7 +92,7 @@ The following new APIs or features were added. showing a text representation of the nodes in a language tree for the current buffer. -• |'statuscolumn'| option to customize the area to the side of a window, +• 'statuscolumn' option to customize the area to the side of a window, normally containing the fold, sign and number columns. This new option follows the 'statusline' syntax and can be used to transform the line numbers, create mouse click callbacks for |signs|, introduce a custom margin or separator etc. @@ -129,15 +129,17 @@ The following new APIs or features were added. • When using Nvim inside tmux 3.2 or later, the default clipboard provider will now copy to the system clipboard. |provider-clipboard| -• |'showcmdloc'| option to display the 'showcmd' information in the - status line or tab line. A new %S statusline item is available to place - the 'showcmd' text in a custom 'statusline'. Useful for when |'cmdheight'| - is set to 0. +• 'showcmdloc' option to display the 'showcmd' information in the status + line or tab line. A new %S statusline item is available to place the + 'showcmd' text in a custom 'statusline'. Useful for when 'cmdheight' is set + to 0. -• |'splitkeep'| option to control the scroll behavior of horizontal splits. +• 'splitkeep' option to control the scroll behavior of horizontal splits. -• |'diffopt'| now includes a `linematch` option to enable a second-stage diff - on individual hunks to provide much more accurate diffs. This option is also +• 'wildoptions' flag "fuzzy" enables |fuzzy-matching| during |cmdline-completion|. + +• 'diffopt' now includes a `linematch` option to enable a second-stage diff on + individual hunks to provide much more accurate diffs. This option is also available to |vim.diff()| See https://github.com/neovim/neovim/pull/14537. @@ -235,7 +237,7 @@ The following changes to existing APIs or features add new behavior. relative to the mouse. Note that the mouse doesn't update frequently without setting `vim.o.mousemoveevent = true` -• |nvim_eval_statusline()| supports evaluating the |'statuscolumn'| through a +• |nvim_eval_statusline()| supports evaluating the 'statuscolumn' through a new `opts` field: `use_statuscol_lnum`. • |nvim_buf_get_extmarks()| now accepts a -1 `ns_id` to request extmarks from diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 708e127136..ed5bd973be 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -18,6 +18,10 @@ BREAKING CHANGES IN HEAD *news-breaking-dev* The following changes to UNRELEASED features were made during the development cycle (Nvim HEAD, the "master" branch). +OPTIONS + +• 'jumpoptions' flag "unload" has been renamed to "clean". + ============================================================================== BREAKING CHANGES *news-breaking* @@ -25,20 +29,40 @@ These changes may require adaptations in your config or plugins. API +• Improved API "meta" docstrings and :help documentation. • `vim.rpcnotify(0)` and `rpcnotify(0)` broadcast to ALL channels. Previously they would "multicast" only to subscribed channels (controlled by `nvim_subscribe()`). Plugins and clients that want "multicast" behavior must now maintain their own list of channels. • In the future, |vim.rpcnotify()| may accept a list of channels, if there is demand for this use-case. +• "Dictionary" was renamed to "Dict" internally and in the RPC |api-metadata|. + This is not expected to break clients because there are no known clients + that actually use the `return_type` field or the parameter type names + reported by |--api-info| or |nvim_get_api_info()|. +• Renamed `nvim__id_dictionary` (unsupported/experimental API) to + `nvim__id_dict`. DEFAULTS -• TODO +• |]d-default| and |[d-default| accept a count. +• |[D-default| and |]D-default| jump to the first and last diagnostic in the + current buffer, respectively. + +DIAGNOSTICS + +• |vim.diagnostic.config()| accepts a "jump" table to specify defaults for + |vim.diagnostic.jump()|. EDITOR -• The order in which signs are placed was changed. Higher priority signs will now appear left of lower priority signs. +• The order in which signs are placed was changed. Higher priority signs will + now appear left of lower priority signs. +• |hl-CurSearch| now behaves the same as Vim and no longer updates on every + cursor movement. +• Moving in the buffer list using |:bnext| and similar commands behaves as + documented and skips help buffers if run from a non-help buffer, otherwise + it moves to another help buffer. EVENTS @@ -46,15 +70,26 @@ EVENTS LSP -• TODO +• Improved rendering of LSP hover docs. |K-lsp-default| +• |vim.lsp.completion.enable()| gained the `convert` callback which enables + customizing the transformation of an LSP CompletionItem to |complete-items|. +• |vim.lsp.diagnostic.from()| can be used to convert a list of + |vim.Diagnostic| objects into their LSP diagnostic representation. LUA -• TODO +• API functions now consistently return an empty dictionary as + |vim.empty_dict()|. Earlier, a |lua-special-tbl| was sometimes used. +• Command-line completions for: `vim.g`, `vim.t`, `vim.w`, `vim.b`, `vim.v`, + `vim.o`, `vim.wo`, `vim.bo`, `vim.opt`, `vim.opt_local`, `vim.opt_global`, + and `vim.fn`. OPTIONS -• TODO +• The 'statuscolumn' `%l` item can now be used as a number column segment that + changes according to related options. It takes care of alignment, 'number', + 'relativenumber' and 'signcolumn' set to "number". The now redundant `%r` item + is no longer treated specially for 'statuscolumn'. PLUGINS @@ -62,12 +97,28 @@ PLUGINS TREESITTER -• TODO +• |Query:iter_matches()| correctly returns all matching nodes in a match + instead of only the last node. This means that the returned table maps + capture IDs to a list of nodes that need to be iterated over. For + backwards compatibility, an option `all=false` (only return the last + matching node) is provided that will be removed in a future release. +• |vim.treesitter.language.get_filetypes()| always includes the {language} + argument in addition to explicitly registered filetypes. +• |vim.treesitter.language.get_lang()| falls back to the {filetype} argument + if no languages are explicitly registered. +• |vim.treesitter.language.add()| returns `true` if a parser was loaded + successfully and `nil,errmsg` otherwise instead of throwing an error. TUI • TODO +VIMSCRIPT + +• |v:msgpack_types| has the type "binary" removed. |msgpackparse()| no longer + treats BIN, STR and FIXSTR as separate types. Any of these is returned as a + string if possible, or a |blob| if the value contained embedded NUL:s. + ============================================================================== NEW FEATURES *news-features* @@ -75,35 +126,67 @@ The following new features were added. API -• TODO +• |nvim__ns_set()| can set properties for a namespace DEFAULTS -• Keymaps: - - |grn| in Normal mode maps to |vim.lsp.buf.rename()| - - |grr| in Normal mode maps to |vim.lsp.buf.references()| - - |gra| in Normal and Visual mode maps to |vim.lsp.buf.code_action()| - - CTRL-S in Insert mode maps to |vim.lsp.buf.signature_help()| +• Highlighting: + • Improved styling of :checkhealth and :help buffers. + +• Mappings: + • |grn| in Normal mode maps to |vim.lsp.buf.rename()| + • |grr| in Normal mode maps to |vim.lsp.buf.references()| + • |gra| in Normal and Visual mode maps to |vim.lsp.buf.code_action()| + • CTRL-S in Insert mode maps to |vim.lsp.buf.signature_help()| + • Mouse |popup-menu| includes an "Open in web browser" item when you right-click + on a URL. + • Mouse |popup-menu| includes a "Go to definition" item when LSP is active + in the buffer. + • Mappings inspired by Tim Pope's vim-unimpaired: + • |[q|, |]q|, |[Q|, |]Q|, |[CTRL-Q|, |]CTRL-Q| navigate through the |quickfix| list + • |[l|, |]l|, |[L|, |]L|, |[CTRL-L|, |]CTRL-L| navigate through the |location-list| + • |[t|, |]t|, |[T|, |]T|, |[CTRL-T|, |]CTRL-T| navigate through the |tag-matchlist| + • |[a|, |]a|, |[A|, |]A| navigate through the |argument-list| + • |[b|, |]b|, |[B|, |]B| navigate through the |buffer-list| + +• Snippet: + • `<Tab>` in Insert and Select mode maps to `vim.snippet.jump({ direction = 1 })` + when a snippet is active and jumpable forwards. + • `<S-Tab>` in Insert and Select mode maps to `vim.snippet.jump({ direction = -1 })` + when a snippet is active and jumpable backwards. EDITOR -• TODO +• Improved |paste| handling for redo (dot-repeat) and macros (|recording|): + • Redoing a large paste is significantly faster and ignores 'autoindent'. + • Replaying a macro with |@| also replays pasted text. +• On Windows, filename arguments on the command-line prefixed with "~\" or + "~/" are now expanded to the user's profile directory, not a relative path + to a literal "~" directory. +• |hl-PmenuMatch| and |hl-PmenuMatchSel| show matched text in completion popup. EVENTS -• TODO +• |CompleteDone| now sets the `reason` key in `v:event` which specifies the reason + for completion being done. LSP -• TODO +• Completion side effects (including snippet expansion, execution of commands + and application of additional text edits) is now built-in. +• |vim.lsp.util.locations_to_items()| sets `end_col` and `end_lnum` fields. +• |vim.lsp.buf.format()| now supports passing a list of ranges + via the `range` parameter (this requires support for the + `textDocument/rangesFormatting` request). LUA -• TODO +• |vim.fs.rm()| can delete files and directories. OPTIONS -• TODO +• 'completeopt' flag "fuzzy" enables |fuzzy-matching| during |ins-completion|. +• 'tabclose' controls which tab page to focus when closing a tab page. PERFORMANCE @@ -111,38 +194,65 @@ PERFORMANCE PLUGINS -• TODO +• EditorConfig + • spelling_language property is now supported. STARTUP -• TODO +• Nvim will fail if the |--listen| or |$NVIM_LISTEN_ADDRESS| address is + invalid, instead of silently skipping an invalid address. TERMINAL -• TODO +• The |terminal| now understands the OSC 52 escape sequence to write to the + system clipboard (copy). Querying with OSC 52 (paste) is not supported. +• |hl-StatusLineTerm| and |hl-StatusLineTermNC| define highlights for the + status line in |terminal| windows. +• The terminal buffer now supports reflow (wrapped lines adapt when the buffer + is resized horizontally). Note: Lines that are not visible and kept in + 'scrollback' are not reflown. +• The |terminal| now supports OSC 8 escape sequences and will display + hyperlinks in supporting host terminals. TREESITTER -• TODO +• |LanguageTree:node_for_range()| gets anonymous and named nodes for a range +• |vim.treesitter.get_node()| now takes an option `include_anonymous`, default + false, which allows it to return anonymous nodes as well as named nodes. TUI -• TODO +• The builtin UI declares info |nvim_set_client_info()| on its channel. See + |startup-tui|. To see the current UI info, try this: > + :lua =vim.api.nvim_get_chan_info(vim.api.nvim_list_uis()[1].chan) +• |log| messages written by the builtin UI client (TUI, |--remote-ui|) are + now prefixed with "ui" instead of "?". UI -• TODO - - -• |CompleteDone| now sets the `reason` key in `v:event` which specifies the reason - for completion being done. +• |vim.ui.open()| (by default bound to |gx|) accepts an `opt.cmd` parameter + which controls the tool used to open the given path or URL. If you want to + globally set this, you can override vim.ui.open using the same approach + described at |vim.paste()|. ============================================================================== CHANGED FEATURES *news-changed* These existing features changed their behavior. -• N/A +• 'scrollbind' now works properly with buffers that contain virtual lines. + + Scrollbind works by aligning to a target top line of each window in a tab + page. Previously this was done by calculating the difference between the old + top line and the target top line, and scrolling by that amount. Now the + top lines are calculated using screen line numbers which take virtual lines + into account. + +• The implementation of grapheme clusters (or combining chars |mbyte-combining|) + was upgraded to closely follow extended grapheme clusters as defined by UAX#29 + in the unicode standard. Noteworthily, this enables proper display of many + more emoji characters than before, including those encoded with multiple + emoji codepoints combined with ZWJ (zero width joiner) codepoints. ============================================================================== REMOVED FEATURES *news-removed* diff --git a/runtime/doc/nvim.txt b/runtime/doc/nvim.txt index ef407922da..f8eba3f7f8 100644 --- a/runtime/doc/nvim.txt +++ b/runtime/doc/nvim.txt @@ -4,7 +4,7 @@ NVIM REFERENCE MANUAL -Nvim *nvim* *nvim-intro* +Nvim *neovim* *nvim* *nvim-intro* Nvim is based on Vim by Bram Moolenaar. diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 5570e62ab8..6dd062124b 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -58,7 +58,8 @@ achieve special effects. These options come in three forms: :se[t] {option}:{value} Set string or number option to {value}. For numeric options the value can be given in decimal, - hex (preceded with 0x) or octal (preceded with '0'). + hex (preceded with 0x) or octal (preceded with '0' or + '0o'). The old value can be inserted by typing 'wildchar' (by default this is a <Tab>). Many string options with fixed syntax also support completing known values. @@ -332,13 +333,14 @@ between string and number-based options. options which are different from the default. For buffer-local and window-local options: - Command global value local value ~ - :set option=value set set - :setlocal option=value - set -:setglobal option=value set - - :set option? - display - :setlocal option? - display -:setglobal option? display - + Command global value local value condition ~ + :set option=value set set + :setlocal option=value - set +:setglobal option=value set - + :set option? - display local value is set + :set option? display - local value is not set + :setlocal option? - display +:setglobal option? display - Global options with a local value *global-local* @@ -383,15 +385,37 @@ the name, e.g. "<lambda>123". Examples: set opfunc=function('MyOpFunc') set opfunc=funcref('MyOpFunc') set opfunc={a\ ->\ MyOpFunc(a)} - " set using a funcref variable + +Set to a script-local function: > + set opfunc=s:MyLocalFunc + set opfunc=<SID>MyLocalFunc + +Set using a funcref variable: > let Fn = function('MyTagFunc') let &tagfunc = Fn - " set using a lambda expression + +Set using a lambda expression: > let &tagfunc = {t -> MyTagFunc(t)} - " set using a variable with lambda expression + +Set using a variable with lambda expression: > let L = {a, b, c -> MyTagFunc(a, b , c)} let &tagfunc = L -< + +Calling a function in an expr option *expr-option-function* + +The value of a few options, such as 'foldexpr', is an expression that is +evaluated to get a value. The evaluation can have quite a bit of overhead. +One way to minimize the overhead, and also to keep the option value very +simple, is to define a function and set the option to call it without +arguments. A |v:lua-call| can also be used. Example: >vim + lua << EOF + function _G.MyFoldFunc() + -- ... compute fold level for line v:lnum + return level + end + EOF + set foldexpr=v:lua.MyFoldFunc() + Setting the filetype @@ -1092,7 +1116,7 @@ A jump table for the options with a short description can be found at |Q_op|. applying 'breakindent', even if the resulting text should normally be narrower. This prevents text indented almost to the right window border - occupying lot of vertical space when broken. + occupying lots of vertical space when broken. (default: 20) shift:{n} After applying 'breakindent', the wrapped line's beginning will be shifted by the given number of @@ -1106,9 +1130,9 @@ A jump table for the options with a short description can be found at |Q_op|. list:{n} Adds an additional indent for lines that match a numbered or bulleted list (using the 'formatlistpat' setting). - list:-1 Uses the length of a match with 'formatlistpat' - for indentation. (default: 0) + list:-1 Uses the width of a match with 'formatlistpat' for + indentation. column:{n} Indent at column {n}. Will overrule the other sub-options. Note: an additional indent may be added for the 'showbreak' setting. @@ -1252,9 +1276,10 @@ A jump table for the options with a short description can be found at |Q_op|. The key used in Command-line Mode to open the command-line window. Only non-printable keys are allowed. The key can be specified as a single character, but it is difficult to - type. The preferred way is to use the <> notation. Examples: >vim - exe "set cedit=\<C-Y>" - exe "set cedit=\<Esc>" + type. The preferred way is to use |key-notation| (e.g. <Up>, <C-F>) or + a letter preceded with a caret (e.g. `^F` is CTRL-F). Examples: >vim + set cedit=^Y + set cedit=<Esc> < |Nvi| also has this option, but it only uses the first character. See |cmdwin|. @@ -1298,6 +1323,17 @@ A jump table for the options with a short description can be found at |Q_op|. v:fname_in name of the input file v:fname_out name of the output file Note that v:fname_in and v:fname_out will never be the same. + + The advantage of using a function call without arguments is that it is + faster, see |expr-option-function|. + + If the 'charconvert' expression starts with s: or |<SID>|, then it is + replaced with the script ID (|local-function|). Example: >vim + set charconvert=s:MyConvert() + set charconvert=<SID>SomeConvert() +< Otherwise the expression is evaluated in the context of the script + where the option was set, thus script-local items are available. + This option cannot be set from a |modeline| or in the |sandbox|, for security reasons. @@ -1388,11 +1424,10 @@ A jump table for the options with a short description can be found at |Q_op|. used. The command-line will cover the last line of the screen when shown. - WARNING: `cmdheight=0` is considered experimental. Expect some - unwanted behaviour. Some 'shortmess' flags and similar - mechanism might fail to take effect, causing unwanted hit-enter - prompts. Some informative messages, both from Nvim itself and - plugins, will not be displayed. + WARNING: `cmdheight=0` is EXPERIMENTAL. Expect some unwanted behaviour. + Some 'shortmess' flags and similar mechanism might fail to take effect, + causing unwanted hit-enter prompts. Some informative messages, both + from Nvim itself and plugins, will not be displayed. *'cmdwinheight'* *'cwh'* 'cmdwinheight' 'cwh' number (default 7) @@ -1442,8 +1477,8 @@ A jump table for the options with a short description can be found at |Q_op|. 'commentstring' 'cms' string (default "") local to buffer A template for a comment. The "%s" in the value is replaced with the - comment text. For example, C uses "/*%s*/". Used for |commenting| and to - add markers for folding, see |fold-marker|. + comment text, and should be padded with a space when possible. + Used for |commenting| and to add markers for folding, see |fold-marker|. *'complete'* *'cpt'* *E535* 'complete' 'cpt' string (default ".,w,b,u,t") @@ -1493,9 +1528,19 @@ A jump table for the options with a short description can be found at |Q_op|. This option cannot be set from a |modeline| or in the |sandbox|, for security reasons. + *'completeitemalign'* *'cia'* +'completeitemalign' 'cia' string (default "abbr,kind,menu") + global + A comma-separated list of |complete-items| that controls the alignment + and display order of items in the popup menu during Insert mode + completion. The supported values are abbr, kind, and menu. These + options allow to customize how the completion items are shown in the + popup menu. Note: must always contain those three values in any + order. + *'completeopt'* *'cot'* 'completeopt' 'cot' string (default "menu,preview") - global + global or local to buffer |global-local| A comma-separated list of options for Insert mode completion |ins-completion|. The supported values are: @@ -1517,6 +1562,10 @@ A jump table for the options with a short description can be found at |Q_op|. completion in the preview window. Only works in combination with "menu" or "menuone". + popup Show extra information about the currently selected + completion in a popup window. Only works in combination + with "menu" or "menuone". Overrides "preview". + noinsert Do not insert any text for a match until the user selects a match from the menu. Only works in combination with "menu" or "menuone". No effect if "longest" is present. @@ -1525,9 +1574,13 @@ A jump table for the options with a short description can be found at |Q_op|. select one from the menu. Only works in combination with "menu" or "menuone". - popup Show extra information about the currently selected - completion in a popup window. Only works in combination - with "menu" or "menuone". Overrides "preview". + fuzzy Enable |fuzzy-matching| for completion candidates. This + allows for more flexible and intuitive matching, where + characters can be skipped and matches can be found even + if the exact sequence is not typed. Only makes a + difference how completion candidates are reduced from the + list of alternatives, but not how the candidates are + collected (using different completion types). *'completeslash'* *'csl'* 'completeslash' 'csl' string (default "") @@ -2175,9 +2228,12 @@ A jump table for the options with a short description can be found at |Q_op|. global When on all Unicode emoji characters are considered to be full width. This excludes "text emoji" characters, which are normally displayed as - single width. Unfortunately there is no good specification for this - and it has been determined on trial-and-error basis. Use the - |setcellwidths()| function to change the behavior. + single width. However, such "text emoji" are treated as full-width + emoji if they are followed by the U+FE0F variant selector. + + Unfortunately there is no good specification for this and it has been + determined on trial-and-error basis. Use the |setcellwidths()| + function to change the behavior. *'encoding'* *'enc'* 'encoding' 'enc' string (default "utf-8") @@ -2483,14 +2539,14 @@ A jump table for the options with a short description can be found at |Q_op|. /* vim: set filetype=idl : */ < |FileType| |filetypes| When a dot appears in the value then this separates two filetype - names. Example: >c + names, it should therefore not be used for a filetype. Example: >c /* vim: set filetype=c.doxygen : */ < This will use the "c" filetype first, then the "doxygen" filetype. This works both for filetype plugins and for syntax files. More than one dot may appear. This option is not copied to another buffer, independent of the 's' or 'S' flag in 'cpoptions'. - Only normal file name characters can be used, `/\*?[|<>` are illegal. + Only alphanumeric characters, '-' and '_' can be used. *'fillchars'* *'fcs'* 'fillchars' 'fcs' string (default "") @@ -2749,6 +2805,9 @@ A jump table for the options with a short description can be found at |Q_op|. < This will invoke the mylang#Format() function in the autoload/mylang.vim file in 'runtimepath'. |autoload| + The advantage of using a function call without arguments is that it is + faster, see |expr-option-function|. + The expression is also evaluated when 'textwidth' is set and adding text beyond that limit. This happens under the same conditions as when internal formatting is used. Make sure the cursor is kept in the @@ -3384,11 +3443,14 @@ A jump table for the options with a short description can be found at |Q_op|. If the expression starts with s: or |<SID>|, then it is replaced with the script ID (|local-function|). Example: >vim - setlocal includeexpr=s:MyIncludeExpr(v:fname) - setlocal includeexpr=<SID>SomeIncludeExpr(v:fname) + setlocal includeexpr=s:MyIncludeExpr() + setlocal includeexpr=<SID>SomeIncludeExpr() < Otherwise, the expression is evaluated in the context of the script where the option was set, thus script-local items are available. + It is more efficient if the value is just a function call without + arguments, see |expr-option-function|. + The expression will be evaluated in the |sandbox| when set from a modeline, see |sandbox-option|. This option cannot be set in a modeline when 'modelineexpr' is off. @@ -3439,7 +3501,7 @@ A jump table for the options with a short description can be found at |Q_op|. in Insert mode as specified with the 'indentkeys' option. When this option is not empty, it overrules the 'cindent' and 'smartindent' indenting. When 'lisp' is set, this option is - is only used when 'lispoptions' contains "expr:1". + only used when 'lispoptions' contains "expr:1". The expression is evaluated with |v:lnum| set to the line number for which the indent is to be computed. The cursor is also in this line when the expression is evaluated (but it may be moved around). @@ -3451,6 +3513,9 @@ A jump table for the options with a short description can be found at |Q_op|. < Otherwise, the expression is evaluated in the context of the script where the option was set, thus script-local items are available. + The advantage of using a function call without arguments is that it is + faster, see |expr-option-function|. + The expression must return the number of spaces worth of indent. It can return "-1" to keep the current indent (this means 'autoindent' is used for the indent). @@ -3611,7 +3676,7 @@ A jump table for the options with a short description can be found at |Q_op|. Otherwise only one space is inserted. *'jumpoptions'* *'jop'* -'jumpoptions' 'jop' string (default "") +'jumpoptions' 'jop' string (default "clean") global List of words that change the behavior of the |jumplist|. stack Make the jumplist behave like the tagstack. @@ -3624,6 +3689,9 @@ A jump table for the options with a short description can be found at |Q_op|. |alternate-file| or using |mark-motions| try to restore the |mark-view| in which the action occurred. + clean Remove unloaded buffers from the jumplist. + EXPERIMENTAL: this flag may change in the future. + *'keymap'* *'kmp'* 'keymap' 'kmp' string (default "") local to buffer @@ -3631,7 +3699,7 @@ A jump table for the options with a short description can be found at |Q_op|. Setting this option to a valid keymap name has the side effect of setting 'iminsert' to one, so that the keymap becomes effective. 'imsearch' is also set to one, unless it was -1 - Only normal file name characters can be used, `/\*?[|<>` are illegal. + Only alphanumeric characters, '.', '-' and '_' can be used. *'keymodel'* *'km'* 'keymodel' 'km' string (default "") @@ -3688,7 +3756,7 @@ A jump table for the options with a short description can be found at |Q_op|. part can be in one of two forms: 1. A list of pairs. Each pair is a "from" character immediately followed by the "to" character. Examples: "aA", "aAbBcC". - 2. A list of "from" characters, a semi-colon and a list of "to" + 2. A list of "from" characters, a semicolon and a list of "to" characters. Example: "abc;ABC" Example: "aA,fgh;FGH,cCdDeE" Special characters need to be preceded with a backslash. These are @@ -3756,7 +3824,7 @@ A jump table for the options with a short description can be found at |Q_op|. update use |:redraw|. This may occasionally cause display errors. It is only meant to be set temporarily when performing an operation where redrawing may cause - flickering or cause a slow down. + flickering or cause a slowdown. *'linebreak'* *'lbr'* *'nolinebreak'* *'nolbr'* 'linebreak' 'lbr' boolean (default off) @@ -3834,6 +3902,9 @@ A jump table for the options with a short description can be found at |Q_op|. between tabs and spaces and for trailing blanks. Further changed by the 'listchars' option. + When 'listchars' does not contain "tab" field, tabs are shown as "^I" + or "<09>", like how unprintable characters are displayed. + The cursor is displayed at the start of the space a Tab character occupies, not at the end as usual in Normal mode. To get this cursor position while displaying Tabs with spaces, use: >vim @@ -4416,6 +4487,20 @@ A jump table for the options with a short description can be found at |Q_op|. (without "unsigned" it would become "9-2019"). Using CTRL-X on "0" or CTRL-A on "18446744073709551615" (2^64 - 1) has no effect, overflow is prevented. + blank If included, treat numbers as signed or unsigned based on + preceding whitespace. If a number with a leading dash has its + dash immediately preceded by a non-whitespace character (i.e., + not a tab or a " "), the negative sign won't be considered as + part of the number. For example: + Using CTRL-A on "14" in "Carbon-14" results in "Carbon-15" + (without "blank" it would become "Carbon-13"). + Using CTRL-X on "8" in "Carbon -8" results in "Carbon -9" + (because -8 is preceded by whitespace. If "unsigned" was + set, it would result in "Carbon -7"). + If this format is included, overflow is prevented as if + "unsigned" were set. If both this format and "unsigned" are + included, "unsigned" will take precedence. + Numbers which simply begin with a digit in the range 1-9 are always considered decimal. This also happens for numbers that are not recognized as octal or hex. @@ -4582,7 +4667,7 @@ A jump table for the options with a short description can be found at |Q_op|. set path+= < To use an environment variable, you probably need to replace the separator. Here is an example to append $INCL, in which directory - names are separated with a semi-colon: >vim + names are separated with a semicolon: >vim let &path = &path .. "," .. substitute($INCL, ';', ',', 'g') < Replace the ';' with a ':' or whatever separator is used. Note that this doesn't work when $INCL contains a comma or white space. @@ -4960,6 +5045,9 @@ A jump table for the options with a short description can be found at |Q_op|. Minimum is 1, maximum is 100000. Only in |terminal| buffers. + Note: Lines that are not visible and kept in scrollback are not + reflown when the terminal buffer is resized horizontally. + *'scrollbind'* *'scb'* *'noscrollbind'* *'noscb'* 'scrollbind' 'scb' boolean (default off) local to window @@ -5442,7 +5530,7 @@ A jump table for the options with a short description can be found at |Q_op|. 'shortmess' 'shm' string (default "ltToOCF") global This option helps to avoid all the |hit-enter| prompts caused by file - messages, for example with CTRL-G, and to avoid some other messages. + messages, for example with CTRL-G, and to avoid some other messages. It is a list of flags: flag meaning when present ~ l use "999L, 888B" instead of "999 lines, 888 bytes" *shm-l* @@ -5459,8 +5547,8 @@ A jump table for the options with a short description can be found at |Q_op|. message; also for quickfix message (e.g., ":cn") s don't give "search hit BOTTOM, continuing at TOP" or *shm-s* "search hit TOP, continuing at BOTTOM" messages; when using - the search count do not show "W" after the count message (see - S below) + the search count do not show "W" before the count message + (see |shm-S| below) t truncate file message at the start if it is too long *shm-t* to fit on the command-line, "<" will appear in the left most column; ignored in Ex mode @@ -5482,7 +5570,11 @@ A jump table for the options with a short description can be found at |Q_op|. `:silent` was used for the command; note that this also affects messages from 'autoread' reloading S do not show search count message when searching, e.g. *shm-S* - "[1/5]" + "[1/5]". When the "S" flag is not present (e.g. search count + is shown), the "search hit BOTTOM, continuing at TOP" and + "search hit TOP, continuing at BOTTOM" messages are only + indicated by a "W" (Mnemonic: Wrapped) letter before the + search count statistics. This gives you the opportunity to avoid that a change between buffers requires you to hit <Enter>, but still gives as useful a message as @@ -5847,7 +5939,7 @@ A jump table for the options with a short description can be found at |Q_op|. minus two. timeout:{millisec} Limit the time searching for suggestions to - {millisec} milli seconds. Applies to the following + {millisec} milliseconds. Applies to the following methods. When omitted the limit is 5000. When negative there is no limit. @@ -5867,9 +5959,11 @@ A jump table for the options with a short description can be found at |Q_op|. The file is used for all languages. expr:{expr} Evaluate expression {expr}. Use a function to avoid - trouble with spaces. |v:val| holds the badly spelled - word. The expression must evaluate to a List of - Lists, each with a suggestion and a score. + trouble with spaces. Best is to call a function + without arguments, see |expr-option-function|. + |v:val| holds the badly spelled word. The expression + must evaluate to a List of Lists, each with a + suggestion and a score. Example: [['the', 33], ['that', 44]] ~ Set 'verbose' and use |z=| to see the scores that the @@ -5921,7 +6015,8 @@ A jump table for the options with a short description can be found at |Q_op|. non-blank of the line. When off the cursor is kept in the same column (if possible). This applies to the commands: - CTRL-D, CTRL-U, CTRL-B, CTRL-F, "G", "H", "M", "L", "gg" - - "d", "<<" and ">>" with a linewise operator + - "d", "<<", "==" and ">>" with a linewise operator + (|operator-resulting-pos|) - "%" with a count - buffer changing commands (CTRL-^, :bnext, :bNext, etc.) - Ex commands that only have a line number, e.g., ":25" or ":+". @@ -5931,7 +6026,6 @@ A jump table for the options with a short description can be found at |Q_op|. *'statuscolumn'* *'stc'* 'statuscolumn' 'stc' string (default "") local to window - EXPERIMENTAL When non-empty, this option determines the content of the area to the side of a window, normally containing the fold, sign and number columns. The format of this option is like that of 'statusline'. @@ -5939,8 +6033,7 @@ A jump table for the options with a short description can be found at |Q_op|. Some of the items from the 'statusline' format are different for 'statuscolumn': - %l line number of currently drawn line - %r relative line number of currently drawn line + %l line number column for currently drawn line %s sign column for currently drawn line %C fold column for currently drawn line @@ -5967,11 +6060,8 @@ A jump table for the options with a short description can be found at |Q_op|. handler should be written with this in mind. Examples: >vim - " Relative number with bar separator and click handlers: - set statuscolumn=%@SignCb@%s%=%T%@NumCb@%r│%T - - " Right aligned relative cursor line number: - let &stc='%=%{v:relnum?v:relnum:v:lnum} ' + " Line number with bar separator and click handlers: + set statuscolumn=%@SignCb@%s%=%T%@NumCb@%l│%T " Line numbers in hexadecimal for non wrapped part of lines: let &stc='%=%{v:virtnum>0?"":printf("%x",v:lnum)} ' @@ -6313,7 +6403,20 @@ A jump table for the options with a short description can be found at |Q_op|. Syntax autocommand event is triggered with the value as argument. This option is not copied to another buffer, independent of the 's' or 'S' flag in 'cpoptions'. - Only normal file name characters can be used, `/\*?[|<>` are illegal. + Only alphanumeric characters, '.', '-' and '_' can be used. + + *'tabclose'* *'tcl'* +'tabclose' 'tcl' string (default "") + global + This option controls the behavior when closing tab pages (e.g., using + |:tabclose|). When empty Vim goes to the next (right) tab page. + + Possible values (comma-separated list): + left If included, go to the previous tab page instead of + the next one. + uselast If included, go to the previously used tab page if + possible. This option takes precedence over the + others. *'tabline'* *'tal'* 'tabline' 'tal' string (default "") @@ -6621,7 +6724,7 @@ A jump table for the options with a short description can be found at |Q_op|. global When on, the title of the window will be set to the value of 'titlestring' (if it is not empty), or to: - filename [+=-] (path) - NVIM + filename [+=-] (path) - Nvim Where: filename the name of the file being edited - indicates the file cannot be modified, 'ma' off @@ -6629,7 +6732,7 @@ A jump table for the options with a short description can be found at |Q_op|. = indicates the file is read-only =+ indicates the file is read-only and modified (path) is the path of the file being edited - - NVIM the server name |v:servername| or "NVIM" + - Nvim the server name |v:servername| or "Nvim" *'titlelen'* 'titlelen' number (default 85) @@ -7022,7 +7125,12 @@ A jump table for the options with a short description can be found at |Q_op|. Some keys will not work, such as CTRL-C, <CR> and Enter. <Esc> can be used, but hitting it twice in a row will still exit command-line as a failsafe measure. - Although 'wc' is a number option, you can set it to a special key: >vim + Although 'wc' is a number option, it can be specified as a number, a + single character, a |key-notation| (e.g. <Up>, <C-F>) or a letter + preceded with a caret (e.g. `^F` is CTRL-F): >vim + :set wc=27 + :set wc=X + :set wc=^I set wc=<Tab> < diff --git a/runtime/doc/pattern.txt b/runtime/doc/pattern.txt index 1ef182127c..8ec02276cc 100644 --- a/runtime/doc/pattern.txt +++ b/runtime/doc/pattern.txt @@ -141,13 +141,17 @@ CTRL-C Interrupt current (search) command. executing autocommands |autocmd-searchpat|. Same thing for when invoking a user function. + While typing the search pattern the current match will be shown if the 'incsearch' option is on. Remember that you still have to finish the search command with <CR> to actually position the cursor at the displayed match. Or use <Esc> to abandon the search. + *nohlsearch-auto* All matches for the last used search pattern will be highlighted if you set -the 'hlsearch' option. This can be suspended with the |:nohlsearch| command. +the 'hlsearch' option. This can be suspended with the |:nohlsearch| command +or auto suspended with nohlsearch plugin. See |nohlsearch-install|. + When 'shortmess' does not include the "S" flag, Vim will automatically show an index, on which the cursor is. This can look like this: > @@ -1494,5 +1498,7 @@ the matching positions and the fuzzy match scores. The "f" flag of `:vimgrep` enables fuzzy matching. +To enable fuzzy matching for |ins-completion|, add the "fuzzy" value to the +'completeopt' option. vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/pi_netrw.txt b/runtime/doc/pi_netrw.txt index 81acd9cf7e..0652fb27e7 100644 --- a/runtime/doc/pi_netrw.txt +++ b/runtime/doc/pi_netrw.txt @@ -3858,7 +3858,7 @@ netrw: netrw-safe guioptions Nov 15, 2021 * removed netrw_localrm and netrw_localrmdir references - Aug 18, 2022 * (Miguel Barro) improving compatability with + Aug 18, 2022 * (Miguel Barro) improving compatibility with powershell v171: Oct 09, 2020 * included code in s:NetrwOptionsSafe() to allow |'bh'| to be set to delete when diff --git a/runtime/doc/provider.txt b/runtime/doc/provider.txt index a39f4bc5d7..f1b0daee76 100644 --- a/runtime/doc/provider.txt +++ b/runtime/doc/provider.txt @@ -194,6 +194,8 @@ registers. Nvim looks for these clipboard tools, in order of priority: - lemonade (for SSH) https://github.com/pocke/lemonade - doitclient (for SSH) https://www.chiark.greenend.org.uk/~sgtatham/doit/ - win32yank (Windows) + - putclip, getclip (Windows) https://cygwin.com/packages/summary/cygutils.html + - clip, powershell (Windows) https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/clip - termux (via termux-clipboard-set, termux-clipboard-set) - tmux (if $TMUX is set) @@ -248,8 +250,8 @@ For Windows WSL, try this g:clipboard definition: \ '*': 'clip.exe', \ }, \ 'paste': { - \ '+': 'powershell.exe -c [Console]::Out.Write($(Get-Clipboard -Raw).tostring().replace("`r", ""))', - \ '*': 'powershell.exe -c [Console]::Out.Write($(Get-Clipboard -Raw).tostring().replace("`r", ""))', + \ '+': 'powershell.exe -NoLogo -NoProfile -c [Console]::Out.Write($(Get-Clipboard -Raw).tostring().replace("`r", ""))', + \ '*': 'powershell.exe -NoLogo -NoProfile -c [Console]::Out.Write($(Get-Clipboard -Raw).tostring().replace("`r", ""))', \ }, \ 'cache_enabled': 0, \ } diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt index 5d3c0cbdc2..63109bdaf3 100644 --- a/runtime/doc/quickfix.txt +++ b/runtime/doc/quickfix.txt @@ -91,24 +91,24 @@ processing a quickfix or location list command, it will be aborted. :ll[!] [nr] Same as ":cc", except the location list for the :[nr]ll[!] current window is used instead of the quickfix list. - *:cn* *:cne* *:cnext* *E553* + *:cn* *:cne* *:cnext* *E553* *]q* :[count]cn[ext][!] Display the [count] next error in the list that includes a file name. If there are no file names at all, go to the [count] next error. See |:cc| for [!] and 'switchbuf'. - *:lne* *:lnext* + *:lne* *:lnext* *]l* :[count]lne[xt][!] Same as ":cnext", except the location list for the current window is used instead of the quickfix list. -:[count]cN[ext][!] *:cp* *:cprevious* *:cprev* *:cN* *:cNext* +:[count]cN[ext][!] *:cp* *:cprevious* *:cprev* *:cN* *:cNext* *[q* :[count]cp[revious][!] Display the [count] previous error in the list that includes a file name. If there are no file names at all, go to the [count] previous error. See |:cc| for [!] and 'switchbuf'. -:[count]lN[ext][!] *:lp* *:lprevious* *:lprev* *:lN* *:lNext* +:[count]lN[ext][!] *:lp* *:lprevious* *:lprev* *:lN* *:lNext* *[l* :[count]lp[revious][!] Same as ":cNext" and ":cprevious", except the location list for the current window is used instead of the quickfix list. @@ -171,18 +171,18 @@ processing a quickfix or location list command, it will be aborted. :[count]laf[ter] Same as ":cafter", except the location list for the current window is used instead of the quickfix list. - *:cnf* *:cnfile* + *:cnf* *:cnfile* *]CTRL-Q* :[count]cnf[ile][!] Display the first error in the [count] next file in the list that includes a file name. If there are no file names at all or if there is no next file, go to the [count] next error. See |:cc| for [!] and 'switchbuf'. - *:lnf* *:lnfile* + *:lnf* *:lnfile* *]CTRL-L* :[count]lnf[ile][!] Same as ":cnfile", except the location list for the current window is used instead of the quickfix list. -:[count]cNf[ile][!] *:cpf* *:cpfile* *:cNf* *:cNfile* +:[count]cNf[ile][!] *:cpf* *:cpfile* *:cNf* *:cNfile* *[CTRL-Q* :[count]cpf[ile][!] Display the last error in the [count] previous file in the list that includes a file name. If there are no file names at all or if there is no next file, go to @@ -190,16 +190,16 @@ processing a quickfix or location list command, it will be aborted. 'switchbuf'. -:[count]lNf[ile][!] *:lpf* *:lpfile* *:lNf* *:lNfile* +:[count]lNf[ile][!] *:lpf* *:lpfile* *:lNf* *:lNfile* *[CTRL-L* :[count]lpf[ile][!] Same as ":cNfile" and ":cpfile", except the location list for the current window is used instead of the quickfix list. - *:crewind* *:cr* + *:crewind* *:cr* *[Q* :cr[ewind][!] [nr] Display error [nr]. If [nr] is omitted, the FIRST error is displayed. See |:cc|. - *:lrewind* *:lr* + *:lrewind* *:lr* *[L* :lr[ewind][!] [nr] Same as ":crewind", except the location list for the current window is used instead of the quickfix list. @@ -209,11 +209,11 @@ processing a quickfix or location list command, it will be aborted. *:lfirst* *:lfir* :lfir[st][!] [nr] Same as ":lrewind". - *:clast* *:cla* + *:clast* *:cla* *]Q* :cla[st][!] [nr] Display error [nr]. If [nr] is omitted, the LAST error is displayed. See |:cc|. - *:llast* *:lla* + *:llast* *:lla* *]L* :lla[st][!] [nr] Same as ":clast", except the location list for the current window is used instead of the quickfix list. @@ -994,7 +994,7 @@ Another option is using 'makeencoding'. ============================================================================== 5. Using :vimgrep and :grep *grep* *lid* -Vim has two ways to find matches for a pattern: Internal and external. The +Vim has two ways to find matches for a pattern: internal and external. The advantage of the internal grep is that it works on all systems and uses the powerful Vim search patterns. An external grep program can be used when the Vim grep does not do what you want. @@ -1023,7 +1023,7 @@ commands can be combined to create a NewGrep command: > command! -nargs=+ NewGrep execute 'silent grep! <args>' | copen 42 -5.1 using Vim's internal grep +5.1 Using Vim's internal grep *:vim* *:vimgrep* *E682* *E683* :vim[grep][!] /{pattern}/[g][j][f] {file} ... @@ -1080,8 +1080,8 @@ commands can be combined to create a NewGrep command: > :vim[grep][!] {pattern} {file} ... Like above, but instead of enclosing the pattern in a - non-ID character use a white-separated pattern. The - pattern must start with an ID character. + non-ID character use a white space separated pattern. + The pattern must start with an ID character. Example: > :vimgrep Error *.c < @@ -1262,6 +1262,33 @@ not "b:current_compiler". What the command actually does is the following: For writing a compiler plugin, see |write-compiler-plugin|. +Use the |compiler-make| plugin to undo the effect of a compiler plugin. + +CPPCHECK *quickfix-cppcheck* *compiler-cppcheck* + +Use g/b:`c_cppcheck_params` to set cppcheck parameters. The global +settings by default include + +- `--verbose`: Enables verbose output. +- `--force`: Forces checking of all configurations. +- `--inline-suppr`: Allows inline suppressions. +- `--enable=...`: Enables specific checks like warnings, style, performance, + portability, information, and missing includes. +- `-j`: Utilizes multiple processors if available, determined by the + `getconf` command if available (requires omitting the unusedFunction check) + +For C++ files (`filetype == 'cpp'`), the `--language=c++` option is added to +ensure Cppcheck treats the file as C++. + +If compile_commands.json is present in the current directory, it is added as a +`--project` parameter to the command line. Otherwise, by default the +directories in &path are passed as include directories. These can be set by +g/b:`c_cppcheck_includes` as a list of `-I` flags. Tim Pope's vim-apathy +plug-in [0] can expand &path. To also append the folders in a git repo use > + + let &l:path = join(systemlist('git ls-tree -d --name-only -r HEAD'), ',') + +[0] https://github.com/tpope/vim-apathy DOTNET *compiler-dotnet* @@ -1277,7 +1304,6 @@ Example: limit output to only display errors, and suppress the project name: > let dotnet_show_project_file = v:false compiler dotnet < - GCC *quickfix-gcc* *compiler-gcc* There's one variable you can set for the GCC compiler: @@ -1288,6 +1314,31 @@ g:compiler_gcc_ignore_unmatched_lines commands run from make are generating false positives. +JAVAC *compiler-javac* + +Commonly used compiler options can be added to 'makeprg' by setting the +g:javac_makeprg_params variable. For example: > + let g:javac_makeprg_params = "-Xlint:all -encoding utf-8" +< +GNU MAKE *compiler-make* + +Since the default make program is "make", the compiler plugin for make, +:compiler make, will reset the 'makeprg' and 'errorformat' option to +the default values and unlet any variables that may have been set by a +previous compiler plugin. + +GROFF *quickfix-groff* *compiler-groff* + +The GROFF compiler plugin uses the mom macro set (documented in the groff_mom +manpage) as input and expects that the output file type extension is passed to +make, say :make html or :make pdf. + +Additional arguments can be passed to groff by setting them in +`b:groff_compiler_args` or `g:groff_compiler_args`. The `language` argument +passed to groff is set using 'spelllang'; it can be overridden by setting +`b:groff_compiler_lang`. The default encoding is `UTF-8` and can be changed +by setting `b:groff_compiler_encoding` or `g:groff_compiler_encoding`. + PANDOC *quickfix-pandoc* *compiler-pandoc* The Pandoc compiler plugin expects that an output file type extension is @@ -1296,7 +1347,13 @@ passed to make, say :make html or :make pdf. Additional arguments can be passed to pandoc: - either by appending them to make, say `:make html --self-contained` . -- or setting them in `b:pandoc_compiler_args` or `g:pandoc_compiler_args` +- or setting them in `b:pandoc_compiler_args` or `g:pandoc_compiler_args`. + +The `--from` argument is an educated guess using the buffer file type; +it can be overridden by setting `b:pandoc_compiler_from`. +The `--metadata lang` argument is set using 'spelllang'; +If `--from=markdown` is assumed and no title set in a title header or +YAML block, then the filename (without extension) is used as the title. PERL *quickfix-perl* *compiler-perl* @@ -1365,6 +1422,17 @@ shells and OSes and also does not allow to use other available TeX options, if any. If your TeX doesn't support "-interaction=nonstopmode", please report it with different means to express \nonstopmode from the command line. +TYPST COMPILER *compiler-typst* + +Vim includes a compiler plugin for Typst files. This compiler is enabled +automatically in Typst buffers by the Typst filetype plugin |ft-typst-plugin|. +Run |:make| to compile the current Typst file. + + *g:typst_cmd* +By default Vim will use "typst" as the command to run the Typst compiler. This +can be changed by setting the |g:typst_cmd| variable: > + let g:typst_cmd = "/path/to/other/command" + ============================================================================= 7. The error format *error-file-format* diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt index c0d00d16cb..d77750b485 100644 --- a/runtime/doc/quickref.txt +++ b/runtime/doc/quickref.txt @@ -886,6 +886,7 @@ Short explanation of each option: *option-list* 'switchbuf' 'swb' sets behavior when switching to another buffer 'synmaxcol' 'smc' maximum column to find syntax items 'syntax' 'syn' syntax to be loaded for current buffer +'tabclose' 'tcl' which tab page to focus when closing a tab 'tabline' 'tal' custom format for the console tab pages line 'tabpagemax' 'tpm' maximum number of tab pages for |-p| and "tab all" 'tabstop' 'ts' number of spaces that <Tab> in file uses @@ -898,6 +899,7 @@ Short explanation of each option: *option-list* 'tagstack' 'tgst' push tags onto the tag stack 'term' name of the terminal 'termbidi' 'tbidi' terminal takes care of bi-directionality +'termguicolors' 'tgc' enable 24-bit RGB color in the TUI 'textwidth' 'tw' maximum width of text that is being inserted 'thesaurus' 'tsr' list of thesaurus files for keyword completion 'thesaurusfunc' 'tsrfu' function to be used for thesaurus completion diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt index 2263b20d1a..521d690d93 100644 --- a/runtime/doc/repeat.txt +++ b/runtime/doc/repeat.txt @@ -96,9 +96,9 @@ where the cursor was before the global command). The global command sets both the last used search pattern and the last used substitute pattern (this is vi compatible). This makes it easy to globally -replace a string: +replace a string: > :g/pat/s//PAT/g -This replaces all occurrences of "pat" with "PAT". The same can be done with: +This replaces all occurrences of "pat" with "PAT". The same can be done with: > :%s/pat/PAT/g Which is two characters shorter! @@ -447,7 +447,7 @@ Example: the lines > \:%, \n:>, \fb:- -are interpreted as if they were given in one line: +are interpreted as if they were given in one line: > :set comments=sr:/*,mb:*,el:*/,://,b:#,:%,n:>,fb:- All leading whitespace characters in the line before a backslash are ignored. @@ -540,7 +540,7 @@ the runtime path. Example: > Using a package and loading automatically ~ Let's assume your Nvim files are in "~/.local/share/nvim/site" and you want to -add a package from a zip archive "/tmp/foopack.zip": +add a package from a zip archive "/tmp/foopack.zip": > % mkdir -p ~/.local/share/nvim/site/pack/foo % cd ~/.local/share/nvim/site/pack/foo % unzip /tmp/foopack.zip @@ -589,7 +589,7 @@ If the package has an "after" directory, that directory is added to the end of Using a single plugin and loading it automatically ~ If you don't have a package but a single plugin, you need to create the extra -directory level: +directory level: > % mkdir -p ~/.local/share/nvim/site/pack/foo/start/foobar % cd ~/.local/share/nvim/site/pack/foo/start/foobar % unzip /tmp/someplugin.zip diff --git a/runtime/doc/scroll.txt b/runtime/doc/scroll.txt index 29d6177213..8b727a86fb 100644 --- a/runtime/doc/scroll.txt +++ b/runtime/doc/scroll.txt @@ -43,6 +43,8 @@ CTRL-D Scroll window Downwards in the buffer. The number of <S-Down> or *<S-Down>* *<kPageDown>* <PageDown> or *<PageDown>* *CTRL-F* +<S-CR> or *<S-CR>* *<S-NL>* +<S-+> or *SHIFT-+* *<S-Plus>* CTRL-F Scroll window [count] pages Forwards (downwards) in the buffer. See also 'startofline' option. When there is only one window the 'window' option @@ -80,6 +82,7 @@ CTRL-U Scroll window Upwards in the buffer. The number of <S-Up> or *<S-Up>* *<kPageUp>* <PageUp> or *<PageUp>* *CTRL-B* +<S--> or *<S-Minus>* *SHIFT-MINUS* CTRL-B Scroll window [count] pages Backwards (upwards) in the buffer. See also 'startofline' option. When there is only one window the 'window' option diff --git a/runtime/doc/sign.txt b/runtime/doc/sign.txt index 6fa260be40..9d74f1f376 100644 --- a/runtime/doc/sign.txt +++ b/runtime/doc/sign.txt @@ -67,15 +67,13 @@ sign group allows Vim plugins to use unique signs without interfering with other plugins using signs. *sign-priority* -Each placed sign is assigned a priority value. When multiple signs are placed -on the same line, the attributes of the sign with the highest priority is used -independently of the sign group. The default priority for a sign is 10. The -priority is assigned at the time of placing a sign. - -When multiple signs that each have an icon or text are present, signs are -ordered with increasing priority from left to right, up until the maximum -width set in 'signcolumn'. Lower priority signs that do not fit are hidden. -Highest priority signs with highlight attributes are always shown. +Each placed sign is assigned a priority value independently of the sign group. +The default priority for a sign is 10, this value can be changed for different +signs by specifying a different value at definition time. When multiple signs +that each have an icon or text are placed on the same line, signs are ordered +with decreasing priority from left to right, up until the maximum width set in +'signcolumn'. Low priority signs that do not fit are hidden. Highest priority +signs with highlight attributes are always shown. When the line on which the sign is placed is deleted, the sign is removed along with it. @@ -116,6 +114,9 @@ See |sign_define()| for the equivalent Vim script function. toolkit supports ~ Win32 .bmp, .ico, .cur + priority={prio} + Default priority for the sign, see |sign-priority|. + linehl={group} Highlighting group used for the whole line the sign is placed in. Most useful is defining a background color. @@ -186,11 +187,11 @@ See |sign_place()| for the equivalent Vim script function. By default, the sign is placed in the global sign group. - By default, the sign is assigned a default priority of 10. To - assign a different priority value, use "priority={prio}" to - specify a value. The priority is used to determine the sign - that is displayed when multiple signs are placed on the same - line. + By default, the sign is assigned a default priority of 10, + unless specified otherwise by the sign definition. To assign a + different priority value, use "priority={prio}" to specify a + value. The priority is used to determine the sign that is + displayed when multiple signs are placed on the same line. Examples: > :sign place 5 line=3 name=sign1 file=a.py diff --git a/runtime/doc/spell.txt b/runtime/doc/spell.txt index 269d52352d..a13bf079e8 100644 --- a/runtime/doc/spell.txt +++ b/runtime/doc/spell.txt @@ -776,7 +776,7 @@ them before the Vim word list is made. The tools for this can be found in the The format for the affix and word list files is based on what Myspell uses (the spell checker of Mozilla and OpenOffice.org). A description can be found here: - https://lingucomponent.openoffice.org/affix.readme ~ + https://lingucomponent.openoffice.org/affix.readme Note that affixes are case sensitive, this isn't obvious from the description. Vim supports quite a few extras. They are described below |spell-affix-vim|. diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index fb8ed0344b..3b0fa2b371 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -422,6 +422,10 @@ argument. Start |RPC| server on pipe or TCP address {addr}. Sets the primary listen address |v:servername| to {addr}. |serverstart()| + To start the server on-demand with systemd, use a systemd + socket unit and associated service unit running: > + systemd-socket-proxyd --exit-idle-time +< ============================================================================== Initialization *initialization* *startup* diff --git a/runtime/doc/support.txt b/runtime/doc/support.txt index 5b8b32fa16..0ddf037fba 100644 --- a/runtime/doc/support.txt +++ b/runtime/doc/support.txt @@ -12,9 +12,9 @@ Support *support* Supported platforms *supported-platforms* `System` `Tier` `Versions` `Tested versions` -Linux 1 >= 2.6.32, glibc >= 2.12 Ubuntu 22.04 +Linux 1 >= 2.6.32, glibc >= 2.12 Ubuntu 24.04 macOS (Intel) 1 >= 11 macOS 12 -macOS (M1) 2 >= 11 macOS 14 +macOS (M1) 1 >= 11 macOS 15 Windows 64-bit 1 >= Windows 10 Version 1809 Windows Server 2022 FreeBSD 1 >= 10 FreeBSD 13 OpenBSD 2 >= 7 @@ -25,13 +25,16 @@ Note: Windows 10 "Version 1809" or later is required for |:terminal|. To check your Windows version, run the "winver" command and look for "Version xxxx" (NOT "OS Build"). +Note: On Windows "Server" you may need to install vcruntime140.dll: +https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170 + Support types ~ * Tier 1: Officially supported and tested with CI. Any contributed patch - MUST NOT break such systems. + MUST NOT break support for such platforms. -* Tier 2: Officially supported, but not necessarily tested with CI. These - systems are maintained to the best of our ability, without being a top +* Tier 2: Officially supported, but not necessarily tested with CI. Support + for these platforms are maintained by best effort, without being a top priority. * Tier 3: Not tested and no guarantees, and not all features may work. @@ -47,7 +50,8 @@ Common Some common notes when adding support for new platforms: -Cmake is the only supported build system. The platform must be buildable with cmake. +CMake is the only supported build system. Nvim must be buildable on the +platform with CMake. All functionality related to the new platform must be implemented in its own file inside `src/nvim/os` unless it's already done in a common file, in which diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index 7893822a66..219be92c58 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -152,8 +152,7 @@ add a few items or change the highlighting, follow these steps: 1. Create your user directory from 'runtimepath', see above. 2. Create a directory in there called "after/syntax". For Unix: > - mkdir ~/.config/nvim/after - mkdir ~/.config/nvim/after/syntax + mkdir -p ~/.config/nvim/after/syntax 3. Write a Vim script that contains the commands you want to use. For example, to change the colors for the C syntax: > @@ -466,14 +465,14 @@ ASTRO *astro.vim* *ft-astro-syntax* Configuration The following variables control certain syntax highlighting features. -You can add them to your .vimrc: > +You can add them to your .vimrc. + +To enable TypeScript and TSX for ".astro" files (default "disable"): > let g:astro_typescript = "enable" < -Enables TypeScript and TSX for ".astro" files. Default Value: "disable" > +To enable Stylus for ".astro" files (default "disable"): > let g:astro_stylus = "enable" < -Enables Stylus for ".astro" files. Default Value: "disable" - NOTE: You need to install an external plugin to support stylus in astro files. @@ -489,6 +488,25 @@ For Visual Basic use: > :let g:filetype_asa = "aspvbs" :let g:filetype_asp = "aspvbs" +ASYMPTOTE *asy.vim* *ft-asy-syntax* + +By default, only basic Asymptote keywords are highlighted. To highlight +extended geometry keywords: > + + :let g:asy_syn_plain = 1 + +and for highlighting keywords related to 3D constructions: > + + :let g:asy_syn_three = 1 + +By default, Asymptote-defined colors (e.g: lightblue) are highlighted. To +highlight TeX-defined colors (e.g: BlueViolet) use: > + + :let g:asy_syn_texcolors = 1 + +or for Xorg colors (e.g: AliceBlue): > + + :let g:asy_syn_x11colors = 1 BAAN *baan.vim* *baan-syntax* @@ -752,6 +770,21 @@ will be classified as tcsh, UNLESS the "filetype_csh" variable exists. If the "filetype_csh" variable exists, the filetype will be set to the value of the variable. +CSV *ft-csv-syntax* + +If you change the delimiter of a CSV file, its syntax highlighting will no +longer match the changed file content. You will need to unlet the following +variable: > + + :unlet b:csv_delimiter + +And afterwards save and reload the file: > + + :w + :e + +Now the syntax engine should determine the newly changed CSV delimiter. + CYNLIB *cynlib.vim* *ft-cynlib-syntax* @@ -1402,6 +1435,10 @@ You can also disable this rendering by adding the following line to your vimrc file: > :let html_no_rendering=1 +By default Vim synchronises the syntax to 250 lines before the first displayed +line. This can be configured using: > + :let html_minlines = 500 +< HTML comments are rather special (see an HTML reference document for the details), and the syntax coloring scheme will highlight all errors. However, if you prefer to use the wrong style (starts with <!-- and @@ -1437,7 +1474,7 @@ Note: Syntax folding might slow down syntax highlighting significantly, especially for large files. -HTML/OS (by Aestiva) *htmlos.vim* *ft-htmlos-syntax* +HTML/OS (BY AESTIVA) *htmlos.vim* *ft-htmlos-syntax* The coloring scheme for HTML/OS works as follows: @@ -1521,102 +1558,172 @@ idlsyntax_showerror_soft Use softer colours by default for errors JAVA *java.vim* *ft-java-syntax* -The java.vim syntax highlighting file offers several options: +The java.vim syntax highlighting file offers several options. -In Java 1.0.2 it was never possible to have braces inside parens, so this was -flagged as an error. Since Java 1.1 this is possible (with anonymous -classes), and therefore is no longer marked as an error. If you prefer the -old way, put the following line into your vim startup file: > - :let java_mark_braces_in_parens_as_errors=1 +In Java 1.0.2, it was never possible to have braces inside parens, so this was +flagged as an error. Since Java 1.1, this is possible (with anonymous +classes); and, therefore, is no longer marked as an error. If you prefer the +old way, put the following line into your Vim startup file: > + :let g:java_mark_braces_in_parens_as_errors = 1 -All identifiers in java.lang.* are always visible in all classes. To -highlight them use: > - :let java_highlight_java_lang_ids=1 +All (exported) public types declared in `java.lang` are always automatically +imported and available as simple names. To highlight them, use: > + :let g:java_highlight_java_lang_ids = 1 -You can also highlight identifiers of most standard Java packages if you -download the javaid.vim script at https://www.fleiner.com/vim/download.html. -If you prefer to only highlight identifiers of a certain package, say java.io -use the following: > - :let java_highlight_java_io=1 +You can also highlight types of most standard Java packages if you download +the javaid.vim script at https://www.fleiner.com/vim/download.html. If you +prefer to only highlight types of a certain package, say `java.io`, use the +following: > + :let g:java_highlight_java_io = 1 Check the javaid.vim file for a list of all the packages that are supported. -Function names are not highlighted, as the way to find functions depends on -how you write Java code. The syntax file knows two possible ways to highlight -functions: - -If you write function declarations that are consistently indented by either -a tab, or a space . . . or eight space character(s), you may want to set > - :let java_highlight_functions="indent" - :let java_highlight_functions="indent1" - :let java_highlight_functions="indent2" - :let java_highlight_functions="indent3" - :let java_highlight_functions="indent4" - :let java_highlight_functions="indent5" - :let java_highlight_functions="indent6" - :let java_highlight_functions="indent7" - :let java_highlight_functions="indent8" +Headers of indented function declarations can be highlighted (along with parts +of lambda expressions and method reference expressions), but it depends on how +you write Java code. Two formats are recognized: + +1) If you write function declarations that are consistently indented by either +a tab, or a space . . . or eight space character(s), you may want to set one +of > + :let g:java_highlight_functions = "indent" + :let g:java_highlight_functions = "indent1" + :let g:java_highlight_functions = "indent2" + :let g:java_highlight_functions = "indent3" + :let g:java_highlight_functions = "indent4" + :let g:java_highlight_functions = "indent5" + :let g:java_highlight_functions = "indent6" + :let g:java_highlight_functions = "indent7" + :let g:java_highlight_functions = "indent8" Note that in terms of 'shiftwidth', this is the leftmost step of indentation. -However, if you follow the Java guidelines about how functions and classes are -supposed to be named (with respect to upper- and lowercase) and there is any -amount of indentation, you may want to set > - :let java_highlight_functions="style" -If neither setting does work for you, but you would still want function -declarations to be highlighted, create your own definitions by changing the -definitions in java.vim or by creating your own java.vim that includes the -original one and then adds the code to highlight functions. - -In Java 1.1 the functions System.out.println() and System.err.println() should -only be used for debugging. Therefore it is possible to highlight debugging -statements differently. To do this you must add the following definition in -your startup file: > - :let java_highlight_debug=1 -The result will be that those statements are highlighted as 'Special' -characters. If you prefer to have them highlighted differently you must define -new highlightings for the following groups.: - Debug, DebugSpecial, DebugString, DebugBoolean, DebugType -which are used for the statement itself, special characters used in debug -strings, strings, boolean constants and types (this, super) respectively. I -have opted to choose another background for those statements. + +2) However, if you follow the Java guidelines about how functions and types +are supposed to be named (with respect to upper- and lowercase) and there is +any amount of indentation, you may want to set > + :let g:java_highlight_functions = "style" + +In addition, you can combine any value of "g:java_highlight_functions" with > + :let g:java_highlight_signature = 1 +to have the name of a function with its parameter list parens distinctly +highlighted from its type parameters, return type, and formal parameters; and +to have the parameter list parens of a lambda expression with its arrow +distinctly highlighted from its formal parameters or identifiers. + +If neither setting does work for you, but you would still want headers of +function declarations to be highlighted, modify the current syntax definitions +or compose new ones. + +Higher-order function types can be hard to parse by eye, so uniformly toning +down some of their components may be of value. Provided that such type names +conform to the Java naming guidelines, you may arrange it with > + :let g:java_highlight_generics = 1 + +In Java 1.1, the functions `System.out.println()` and `System.err.println()` +should only be used for debugging. Consider adding the following definition +in your startup file: > + :let g:java_highlight_debug = 1 +to have the bulk of those statements colored as + `*Debug` debugging statements, +and to make some of their own items further grouped and linked: + `*Special` as DebugSpecial, + `*String` as DebugString, + `*Boolean` as DebugBoolean, + `*Type` as DebugType, +which are used for special characters appearing in strings, strings proper, +boolean literals, and special instance references (`super`, `this`, `null`), +respectively. Javadoc is a program that takes special comments out of Java program files and creates HTML pages. The standard configuration will highlight this HTML code -similarly to HTML files (see |html.vim|). You can even add Javascript -and CSS inside this code (see below). There are four differences however: - 1. The title (all characters up to the first '.' which is followed by - some white space or up to the first '@') is colored differently (to change - the color change the group CommentTitle). - 2. The text is colored as 'Comment'. - 3. HTML comments are colored as 'Special' - 4. The special Javadoc tags (@see, @param, ...) are highlighted as specials - and the argument (for @see, @param, @exception) as Function. -To turn this feature off add the following line to your startup file: > - :let java_ignore_javadoc=1 - -If you use the special Javadoc comment highlighting described above you -can also turn on special highlighting for Javascript, visual basic -scripts and embedded CSS (stylesheets). This makes only sense if you -actually have Javadoc comments that include either Javascript or embedded -CSS. The options to use are > - :let java_javascript=1 - :let java_css=1 - :let java_vb=1 - -In order to highlight nested parens with different colors define colors -for javaParen, javaParen1 and javaParen2, for example with > +similarly to HTML files (see |html.vim|). You can even add JavaScript and CSS +inside this code (see below). The HTML rendering and the Markdown rendering +diverge as follows: + 1. The first sentence (all characters up to the first period `.`, which is + followed by a whitespace character or a line terminator, or up to the + first block tag, e.g. `@param`, `@return`) is colored as + *SpecialComment special comments. + 2. The text is colored as + `*Comment` comments. + 3. HTML comments are colored as + `*Special` special symbols. + 4. The standard Javadoc tags (`@code`, `@see`, etc.) are colored as + `*Special` special symbols + and some of their arguments are colored as + `*Function` function names. +To turn this feature off for both HTML and Markdown, add the following line to +your startup file: > + :let g:java_ignore_javadoc = 1 +Alternatively, only suppress HTML comments or Markdown comments: > + :let g:java_ignore_html = 1 + :let g:java_ignore_markdown = 1 +See |ft-java-plugin| for additional support available for Markdown comments. + +If you use the special Javadoc comment highlighting described above, you can +also turn on special highlighting for JavaScript, Visual Basic scripts, and +embedded CSS (stylesheets). This only makes sense if any of these languages +actually appear in Javadoc comments. The variables to use are > + :let g:java_javascript = 1 + :let g:java_css = 1 + :let g:java_vb = 1 +Note that these three variables are maintained in the HTML syntax file. + +Numbers and strings can be recognized in non-Javadoc comments with > + :let g:java_comment_strings = 1 + +When 'foldmethod' is set to "syntax", blocks of code and multi-line comments +will be folded. No text is usually written in the first line of a multi-line +comment, making folded contents of Javadoc comments less informative with the +default 'foldtext' value; you may opt for showing the contents of a second +line for any comments written in this way, and showing the contents of a first +line otherwise, with > + :let g:java_foldtext_show_first_or_second_line = 1 + +Trailing whitespace characters or a run of space characters before a tab +character can be marked as an error with > + :let g:java_space_errors = 1 +but either kind of an error can be suppressed by also defining one of > + :let g:java_no_trail_space_error = 1 + :let g:java_no_tab_space_error = 1 + +In order to highlight nested parens with different colors, define colors for +`javaParen`, `javaParen1`, and `javaParen2`. For example, > :hi link javaParen Comment or > :hi javaParen ctermfg=blue guifg=#0000ff +Certain modifiers are incompatible with each other, e.g. `abstract` and +`final`: > + :syn list javaConceptKind +and can be differently highlighted as a group than other modifiers with > + :hi link javaConceptKind NonText + If you notice highlighting errors while scrolling backwards, which are fixed -when redrawing with CTRL-L, try setting the "java_minlines" internal variable -to a larger number: > - :let java_minlines = 50 +when redrawing with CTRL-L, try setting the "g:java_minlines" variable to +a larger number: > + :let g:java_minlines = 50 This will make the syntax synchronization start 50 lines before the first displayed line. The default value is 10. The disadvantage of using a larger number is that redrawing can become slow. +Significant changes to the Java platform are gradually introduced in the form +of JDK Enhancement Proposals (JEPs) that can be implemented for a release and +offered as its preview features. It may take several JEPs and a few release +cycles for such a feature to become either integrated into the platform or +withdrawn from this effort. To cater for early adopters, there is optional +support in Vim for syntax related preview features that are implemented. You +can request it by specifying a list of preview feature numbers as follows: > + :let g:java_syntax_previews = [455, 476] + +The supported JEP numbers are to be drawn from this table: + `430`: String Templates [JDK 21] + `455`: Primitive types in Patterns, instanceof, and switch + `476`: Module Import Declarations + +Note that as soon as the particular preview feature will have been integrated +into the Java platform, its entry will be removed from the table and related +optionality will be discontinued. + -JSON *json.vim* *ft-json-syntax* +JSON *json.vim* *ft-json-syntax* *g:vim_json_conceal* + *g:vim_json_warnings* The json syntax file provides syntax highlighting with conceal support by default. To disable concealment: > @@ -1759,7 +1866,7 @@ By default mail.vim synchronises syntax to 100 lines before the first displayed line. If you have a slow machine, and generally deal with emails with short headers, you can change this to a smaller value: > - :let mail_minlines = 30 + :let mail_minlines = 30 MAKE *make.vim* *ft-make-syntax* @@ -1770,6 +1877,16 @@ feature off by using: > :let make_no_commands = 1 +Comments are also highlighted by default. You can turn this off by using: > + + :let make_no_comments = 1 + +Microsoft Makefile handles variable expansion and comments differently +(backslashes are not used for escape). If you see any wrong highlights +because of this, you can try this: > + + :let make_microsoft = 1 + MAPLE *maple.vim* *ft-maple-syntax* @@ -1796,7 +1913,8 @@ $VIMRUNTIME/syntax/syntax.vim). mv_finance mv_logic mv_powseries -MARKDOWN *ft-markdown-syntax* +MARKDOWN *ft-markdown-syntax* *g:markdown_minlines* + *g:markdown_fenced_languages* *g:markdown_syntax_conceal* If you have long regions there might be wrong highlighting. At the cost of slowing down displaying, you can have the engine look further back to sync on @@ -1821,6 +1939,17 @@ have the following in your vimrc: > let filetype_m = "mma" +MEDIAWIKI *ft-mediawiki-syntax* + +By default, syntax highlighting includes basic HTML tags like style and +headers |html.vim|. For strict Mediawiki syntax highlighting: > + + let g:html_no_rendering = 1 + +If HTML highlighting is desired, terminal-based text formatting such as bold +and italic is possible by: > + + let g:html_style_rendering = 1 MODULA2 *modula2.vim* *ft-modula2-syntax* @@ -2034,9 +2163,9 @@ PANDOC *ft-pandoc-syntax* By default, markdown files will be detected as filetype "markdown". Alternatively, you may want them to be detected as filetype "pandoc" instead. -To do so, set the following: > +To do so, set the *g:filetype_md* var: > - :let g:markdown_md = 'pandoc' + :let g:filetype_md = 'pandoc' The pandoc syntax plugin uses |conceal| for pretty highlighting. Default is 1 > @@ -2575,6 +2704,13 @@ To highlight R code in knitr chunk headers, add to your |vimrc|: > let rrst_syn_hl_chunk = 1 +RASI *rasi.vim* *ft-rasi-syntax* + +Rasi stands for Rofi Advanced Style Information. It is used by the program +rofi to style the rendering of the search window. The language is heavily +inspired by CSS stylesheet. Files with the following extensions are recognized +as rasi files: .rasi. + READLINE *readline.vim* *ft-readline-syntax* The readline library is primarily used by the BASH shell, which adds quite a @@ -3289,6 +3425,28 @@ set "tf_minlines" to the value you desire. Example: > :let tf_minlines = your choice < +TYPESCRIPT *typescript.vim* *ft-typescript-syntax* + *typescriptreact.vim* *ft-typescriptreact-syntax* + +There is one option to control the TypeScript syntax highlighting. + + *g:typescript_host_keyword* +When this variable is set to 1, host-specific APIs such as `addEventListener` +are highlighted. To disable set it to zero in your .vimrc: > + + let g:typescript_host_keyword = 0 +< +The default value is 1. + +TYPST *ft-typst-syntax* + + *g:typst_embedded_languages* +Typst files can embed syntax highlighting for other languages by setting the +|g:typst_embedded_languages| variable. This variable is a list of language +names whose syntax definitions will be included in Typst files. Example: > + + let g:typst_embedded_languages = ['python', 'r'] + VIM *vim.vim* *ft-vim-syntax* *g:vimsyn_minlines* *g:vimsyn_maxlines* There is a trade-off between more accurate syntax highlighting versus screen @@ -3307,23 +3465,31 @@ The g:vimsyn_embed option allows users to select what, if any, types of embedded script highlighting they wish to have. > g:vimsyn_embed == 0 : disable (don't embed any scripts) - g:vimsyn_embed == 'lpPr' : support embedded lua, perl, python and ruby + g:vimsyn_embed == 'lpPr' : support embedded Lua, Perl, Python and Ruby < This option is disabled by default. *g:vimsyn_folding* - -Some folding is now supported with syntax/vim.vim: > +Some folding is now supported with when 'foldmethod' is set to "syntax": > g:vimsyn_folding == 0 or doesn't exist: no syntax-based folding g:vimsyn_folding =~ 'a' : augroups g:vimsyn_folding =~ 'f' : fold functions g:vimsyn_folding =~ 'h' : fold heredocs - g:vimsyn_folding =~ 'l' : fold lua script - g:vimsyn_folding =~ 'p' : fold perl script - g:vimsyn_folding =~ 'P' : fold python script - g:vimsyn_folding =~ 'r' : fold ruby script + g:vimsyn_folding =~ 'l' : fold Lua script + g:vimsyn_folding =~ 'p' : fold Perl script + g:vimsyn_folding =~ 'P' : fold Python script + g:vimsyn_folding =~ 'r' : fold Ruby script < - *g:vimsyn_noerror* + +By default, g:vimsyn_folding is unset. Concatenate the indicated characters +to support folding of multiple syntax constructs (e.g., +g:vimsyn_folding = "fh" will enable folding of both functions and heredocs). + + *g:vimsyn_comment_strings* +By default, strings are highlighted inside comments. This may be disabled by +setting g:vimsyn_comment_strings to false. + + *g:vimsyn_noerror* Not all error highlighting that syntax/vim.vim does may be correct; Vim script is a difficult language to highlight correctly. A way to suppress error highlighting is to put the following line in your |vimrc|: > @@ -4527,7 +4693,7 @@ matches, nextgroup, etc. But there are a few differences: line (or group of continued lines). - When a match with a sync pattern is found, the rest of the line (or group of continued lines) is searched for another match. The last match is used. - This is used when a line can contain both the start end the end of a region + This is used when a line can contain both the start and the end of a region (e.g., in a C-comment like `/* this */`, the last "*/" is used). There are two ways how a match with a sync pattern can be used: @@ -4926,11 +5092,13 @@ guisp={color-name} *guisp* All values are hexadecimal, range from "00" to "ff". Examples: > :highlight Comment guifg=#11f0c3 guibg=#ff00ff < -blend={integer} *highlight-blend* +blend={integer} *highlight-blend* *opacity* Override the blend level for a highlight group within the popupmenu or floating windows. Only takes effect if 'pumblend' or 'winblend' is set for the menu or window. See the help at the respective option. + See also the "blend" flag of |nvim_buf_set_extmark()|. + *highlight-groups* *highlight-default* These are the builtin highlighting groups. Note that the highlighting depends on the value of 'background'. You can see the current settings with the @@ -4941,8 +5109,9 @@ ColorColumn Used for the columns set with 'colorcolumn'. Conceal Placeholder characters substituted for concealed text (see 'conceallevel'). *hl-CurSearch* -CurSearch Used for highlighting a search pattern under the cursor - (see 'hlsearch'). +CurSearch Current match for the last search pattern (see 'hlsearch'). + Note: This is correct after a search, but may get outdated if + changes are made or the screen is redrawn. *hl-Cursor* *hl-lCursor* Cursor Character under the cursor. lCursor Character under the cursor when |language-mapping| @@ -4986,7 +5155,6 @@ IncSearch 'incsearch' highlighting; also used for the text replaced with ":s///c". *hl-Substitute* Substitute |:substitute| replacement text highlighting. - *hl-LineNr* LineNr Line number for ":number" and ":#" commands, and when 'number' or 'relativenumber' option is set. @@ -5006,7 +5174,6 @@ CursorLineSign Like SignColumn when 'cursorline' is set for the cursor line. *hl-MatchParen* MatchParen Character under the cursor or just before it, if it is a paired bracket, and its match. |pi_paren.txt| - *hl-ModeMsg* ModeMsg 'showmode' message (e.g., "-- INSERT --"). *hl-MsgArea* @@ -5048,11 +5215,15 @@ PmenuExtraSel Popup menu: Selected item "extra text". PmenuSbar Popup menu: Scrollbar. *hl-PmenuThumb* PmenuThumb Popup menu: Thumb of the scrollbar. + *hl-PmenuMatch* +PmenuMatch Popup menu: Matched text in normal item. + *hl-PmenuMatchSel* +PmenuMatchSel Popup menu: Matched text in selected item. *hl-Question* Question |hit-enter| prompt and yes/no questions. *hl-QuickFixLine* QuickFixLine Current |quickfix| item in the quickfix window. Combined with - |hl-CursorLine| when the cursor is there. + |hl-CursorLine| when the cursor is there. *hl-Search* Search Last search pattern highlighting (see 'hlsearch'). Also used for similar items that need to stand out. @@ -5079,6 +5250,11 @@ SpellRare Word that is recognized by the spellchecker as one that is StatusLine Status line of current window. *hl-StatusLineNC* StatusLineNC Status lines of not-current windows. + *hl-StatusLineTerm* +StatusLineTerm Status line of |terminal| window. + *hl-StatusLineTermNC* +StatusLineTermNC + Status line of non-current |terminal| windows. *hl-TabLine* TabLine Tab pages line, not active tab page label. *hl-TabLineFill* diff --git a/runtime/doc/tabpage.txt b/runtime/doc/tabpage.txt index 2f50e31ee5..7bfa36e8ab 100644 --- a/runtime/doc/tabpage.txt +++ b/runtime/doc/tabpage.txt @@ -135,7 +135,8 @@ something else. :tabclose $ " close the last tab page :tabclose # " close the last accessed tab page -When a tab is closed the next tab page will become the current one. +When a tab is closed the next tab page will become the current one. This +behaviour can be customized using the 'tabclose' option. *:tabo* *:tabonly* :tabo[nly][!] Close all other tab pages. diff --git a/runtime/doc/tagsrch.txt b/runtime/doc/tagsrch.txt index ef1654d365..d5e165a870 100644 --- a/runtime/doc/tagsrch.txt +++ b/runtime/doc/tagsrch.txt @@ -274,25 +274,25 @@ g CTRL-] Like CTRL-], but use ":tjump" instead of ":tag". {Visual}g CTRL-] Same as "g CTRL-]", but use the highlighted text as the identifier. - *:tn* *:tnext* + *:tn* *:tnext* *]t* :[count]tn[ext][!] Jump to [count] next matching tag (default 1). See |tag-!| for [!]. - *:tp* *:tprevious* + *:tp* *:tprevious* *[t* :[count]tp[revious][!] Jump to [count] previous matching tag (default 1). See |tag-!| for [!]. *:tN* *:tNext* :[count]tN[ext][!] Same as ":tprevious". - *:tr* *:trewind* + *:tr* *:trewind* *[T* :[count]tr[ewind][!] Jump to first matching tag. If [count] is given, jump to [count]th matching tag. See |tag-!| for [!]. *:tf* *:tfirst* :[count]tf[irst][!] Same as ":trewind". - *:tl* *:tlast* + *:tl* *:tlast* *]T* :tl[ast][!] Jump to last matching tag. See |tag-!| for [!]. *:lt* *:ltag* @@ -335,10 +335,10 @@ the same as above, with a "p" prepended. :ptj[ump][!] [name] Does ":tjump[!] [name]" and shows the new tag in a "Preview" window. See |:ptag| for more info. - *:ptn* *:ptnext* + *:ptn* *:ptnext* *]CTRL-T* :[count]ptn[ext][!] ":tnext" in the preview window. See |:ptag|. - *:ptp* *:ptprevious* + *:ptp* *:ptprevious* *[CTRL-T* :[count]ptp[revious][!] ":tprevious" in the preview window. See |:ptag|. *:ptN* *:ptNext* @@ -565,12 +565,12 @@ ctags). {term} ;" The two characters semicolon and double quote. This is interpreted by Vi as the start of a comment, which makes the following be ignored. This is for backwards compatibility - with Vi, it ignores the following fields. Example: + with Vi, it ignores the following fields. Example: > APP file /^static int APP;$/;" v - When {tagaddress} is not a line number or search pattern, then +< When {tagaddress} is not a line number or search pattern, then {term} must be `|;"`. Here the bar ends the command (excluding the bar) and `;"` is used to have Vi ignore the rest of the - line. Example: + line. Example: > APP file.c call cursor(3, 4)|;" v {field} .. A list of optional fields. Each field has the form: @@ -588,7 +588,9 @@ ctags). There is one field that doesn't have a ':'. This is the kind of the tag. It is handled like it was preceded with "kind:". - See the documentation of ctags for the kinds it produces. + In the above example, this was "kind:v" (typically variable). + See the documentation of ctags for the kinds it produces, with + ctags you can use `ctags --list-kinds` . The only other field currently recognized by Vim is "file:" (with an empty value). It is used for a static tag. @@ -633,14 +635,14 @@ If the command is a normal search command (it starts and ends with "/" or The direction of the search is forward for "/", backward for "?". Note that 'wrapscan' does not matter, the whole file is always searched. - If the search fails, another try is done ignoring case. If that fails too, - a search is done for: + a search is done for: > "^tagname[ \t]*(" - (the tag with '^' prepended and "[ \t]*(" appended). When using function +< (the tag with '^' prepended and "[ \t]*(" appended). When using function names, this will find the function name when it is in column 0. This will help when the arguments to the function have changed since the tags file was - made. If this search also fails another search is done with: + made. If this search also fails another search is done with: > "^[#a-zA-Z_].*\<tagname[ \t]*(" - This means: A line starting with '#' or an identifier and containing the tag +< This means: A line starting with '#' or an identifier and containing the tag followed by white space and a '('. This will find macro names and function names with a type prepended. @@ -781,15 +783,15 @@ CTRL-W i Open a new window, with the cursor on the first line count'th matching line is displayed. *[d-default* - Mapped to |vim.diagnostic.goto_prev()| by default. - |default-mappings| + Jumps to the previous diagnostic in the current buffer + by default. |vim.diagnostic.jump()| |default-mappings| *]d* ]d like "[d", but start at the current cursor position. *]d-default* - Mapped to |vim.diagnostic.goto_next()| by default. - |default-mappings| + Jumps to the next diagnostic in the current buffer by + default. |vim.diagnostic.jump()| |default-mappings| *:ds* *:dsearch* :[range]ds[earch][!] [count] [/]string[/] @@ -803,9 +805,17 @@ CTRL-W i Open a new window, with the cursor on the first line displayed for the found lines. The search starts from the beginning of the file. + *[D-default* + Jumps to the first diagnostic in the current buffer by + default. |vim.diagnostic.jump()| |default-mappings| + *]D* ]D like "[D", but start at the current cursor position. + *]D-default* + Jumps to the last diagnostic in the current buffer by + default. |vim.diagnostic.jump()| |default-mappings| + *:dli* *:dlist* :[range]dli[st][!] [/]string[/] Like `[D` and `]D`, but search in [range] lines diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/terminal.txt index a6ebc7e958..9c47e6de7d 100644 --- a/runtime/doc/nvim_terminal_emulator.txt +++ b/runtime/doc/terminal.txt @@ -1,4 +1,4 @@ -*terminal_emulator.txt* Nvim +*terminal.txt* Nvim NVIM REFERENCE MANUAL by Thiago de Arruda @@ -164,7 +164,22 @@ directory indicated in the request. >lua To try it out, select the above code and source it with `:'<,'>lua`, then run this command in a :terminal buffer: > - printf "\033]7;file://./foo/bar\033\\" + printf "\033]7;file://./foo/bar\033\\" + +OSC 52: write to system clipboard *terminal-osc52* + +Applications in the :terminal buffer can write to the system clipboard by +emitting an OSC 52 sequence. Example: > + + printf '\033]52;;%s\033\\' "$(echo -n 'Hello world' | base64)" + +Nvim uses the configured |clipboard| provider to write to the system +clipboard. Reading from the system clipboard with OSC 52 is not supported, as +this would allow any arbitrary program in the :terminal to read the user's +clipboard. + +OSC 52 sequences sent from the :terminal buffer do not emit a |TermRequest| +event. The event is handled directly by Nvim and is not forwarded to plugins. ============================================================================== Status Variables *terminal-status* @@ -186,7 +201,7 @@ Example: >vim Use |jobwait()| to check if the terminal job has finished: >vim let running = jobwait([&channel], 0)[0] == -1 - +< ============================================================================== :Termdebug plugin *terminal-debug* @@ -198,6 +213,8 @@ Starting ~ *termdebug-starting* Load the plugin with this command: >vim packadd termdebug +When loading the plugin from the |vimrc| file, add the "!" attribute: >vim + packadd! termdebug < *:Termdebug* To start debugging use `:Termdebug` or `:TermdebugCommand` followed by the command name, for example: >vim @@ -447,6 +464,9 @@ If there is no g:termdebug_config you can use: >vim let g:termdebug_use_prompt = 1 < Mappings ~ +The termdebug plugin enables a few default mappings. All those mappings +are reset to their original values once the termdebug session concludes. + *termdebug_map_K* *termdebug-mappings* The K key is normally mapped to |:Evaluate| unless a buffer local (|:map-local|) mapping to K already exists. If you do not want this use: >vim diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt index 0b84bb60d4..35192cc43d 100644 --- a/runtime/doc/treesitter.txt +++ b/runtime/doc/treesitter.txt @@ -49,151 +49,13 @@ treesitter parser for buffers with filetype `svg` or `xslt`, use: >lua vim.treesitter.language.register('xml', { 'svg', 'xslt' }) < + *treesitter-parsers-wasm* -============================================================================== -TREESITTER TREES *treesitter-tree* - *TSTree* - -A "treesitter tree" represents the parsed contents of a buffer, which can be -used to perform further analysis. It is a |userdata| reference to an object -held by the treesitter library. - -An instance `TSTree` of a treesitter tree supports the following methods. - -TSTree:root() *TSTree:root()* - Return the root node of this tree. - -TSTree:copy() *TSTree:copy()* - Returns a copy of the `TSTree`. - -============================================================================== -TREESITTER NODES *treesitter-node* - *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 |userdata| reference to an object held by the treesitter library. - -An instance `TSNode` of a treesitter node supports the following methods. - -TSNode:parent() *TSNode:parent()* - Get the node's immediate parent. - Prefer |TSNode:child_containing_descendant()| - for iterating over the node's ancestors. - -TSNode:next_sibling() *TSNode:next_sibling()* - Get the node's next sibling. - -TSNode:prev_sibling() *TSNode:prev_sibling()* - Get the node's previous sibling. - -TSNode:next_named_sibling() *TSNode:next_named_sibling()* - Get the node's next 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 - they are named or not. - Returns the child node plus the eventual field name corresponding to this - child node. - -TSNode:field({name}) *TSNode:field()* - Returns a table of the nodes corresponding to the {name} field. - -TSNode:child_count() *TSNode:child_count()* - Get the node's number of children. - -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()* - Get the node's number of named children. - -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:child_containing_descendant({descendant}) *TSNode:child_containing_descendant()* - Get the node's child that contains {descendant}. - -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_()* - Get the node's end position. Return three values: the row, column and - total byte count (all zero-based). - -TSNode:range({include_bytes}) *TSNode:range()* - Get the range of the node. - - Return four or six values: - - start row - - start column - - start byte (if {include_bytes} is `true`) - - end row - - end column - - end byte (if {include_bytes} is `true`) - -TSNode:type() *TSNode:type()* - Get the node's type as a string. - -TSNode:symbol() *TSNode:symbol()* - Get the node's type as a numerical id. - -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()* - Check if the node is missing. Missing nodes are inserted by the parser in - order to recover from certain kinds of syntax errors. - -TSNode:extra() *TSNode:extra()* - Check if the node is extra. Extra nodes represent things like comments, - which are not required by the grammar but can appear anywhere. - -TSNode:has_changes() *TSNode:has_changes()* - Check if a syntax node has been edited. - -TSNode:has_error() *TSNode:has_error()* - Check if the node is a syntax error or contains any syntax errors. - -TSNode:sexpr() *TSNode:sexpr()* - Get an S-expression representing the node as a string. - -TSNode:id() *TSNode:id()* - Get a unique identifier for the node inside its own tree. - - No guarantees are made about this identifier's internal representation, - except for being a primitive Lua type with value equality (so not a - table). Presently it is a (non-printable) string. - - Note: The `id` is not guaranteed to be unique for nodes from different - trees. - -TSNode:tree() *TSNode:tree()* - Get the |TSTree| of the node. - *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}) - Get the smallest named node within this node that spans the given range of - (row, column) positions - *TSNode:equal()* -TSNode:equal({node}) - Check if {node} refers to the same node within the same tree. +If Nvim is built with `ENABLE_WASMTIME`, then wasm parsers can also be +loaded: >lua - *TSNode:byte_length()* -TSNode:byte_length() - Return the number of bytes spanned by this node. + vim.treesitter.language.add('python', { path = "/path/to/python.wasm" }) +< ============================================================================== TREESITTER QUERIES *treesitter-query* @@ -335,7 +197,7 @@ TREESITTER QUERY DIRECTIVES *treesitter-directives* Treesitter directives store metadata for a node or match and perform side effects. For example, the `set!` directive sets metadata on the match or node: >query - ((identifier) @foo (#set! "type" "parameter")) + ((identifier) @foo (#set! type "parameter")) < The following directives are built in: @@ -350,13 +212,14 @@ The following directives are built in: {value} Examples: >query - ((identifier) @foo (#set! @foo "kind" "parameter")) - ((node1) @left (node2) @right (#set! "type" "pair")) - ((codeblock) @markup.raw.block (#set! "priority" 90)) + ((identifier) @foo (#set! @foo kind "parameter")) + ((node1) @left (node2) @right (#set! type "pair")) + ((codeblock) @markup.raw.block (#set! priority 90)) < `offset!` *treesitter-directive-offset!* Takes the range of the captured node and applies an offset. This will - set a new `Range4` object for the captured node with `capture_id` as + set a new range in the form of a list like { {start_row}, {start_col}, + {end_row}, {end_col} } for the captured node with `capture_id` as `metadata[capture_id].range`. Useful for |treesitter-language-injections|. Parameters: ~ @@ -540,9 +403,9 @@ the exact definition): @keyword.coroutine keywords related to coroutines (e.g. `go` in Go, `async/await` in Python) @keyword.function keywords that define a function (e.g. `func` in Go, `def` in Python) @keyword.operator operators that are English words (e.g. `and`, `or`) -@keyword.import keywords for including modules (e.g. `import`, `from` in Python) -@keyword.type keywords defining composite types (e.g. `struct`, `enum`) -@keyword.modifier keywords defining type modifiers (e.g. `const`, `static`, `public`) +@keyword.import keywords for including or exporting modules (e.g. `import`, `from` in Python) +@keyword.type keywords describing namespaces and composite types (e.g. `struct`, `enum`) +@keyword.modifier keywords modifying other constructs (e.g. `const`, `static`, `public`) @keyword.repeat keywords related to loops (e.g. `for`, `while`) @keyword.return keywords like `return` and `yield` @keyword.debug keywords related to debugging @@ -598,7 +461,7 @@ the exact definition): @diff.delta changed text (for diff files) @tag XML-style tag names (e.g. in XML, HTML, etc.) -@tag.builtin XML-style tag names (e.g. HTML5 tags) +@tag.builtin builtin tag names (e.g. HTML5 tags) @tag.attribute XML-style tag attributes @tag.delimiter XML-style tag delimiters @@ -636,7 +499,7 @@ higher than treesitter. It is also possible to change the priority of an individual query pattern manually by setting its `"priority"` metadata attribute: >query - ((super_important_node) @superimportant (#set! "priority" 105)) + ((super_important_node) @superimportant (#set! priority 105)) < ============================================================================== @@ -711,6 +574,278 @@ The earliest parser ABI version that is supported by the bundled treesitter library. ============================================================================== +TREESITTER TREES *treesitter-tree* *TSTree* + +A "treesitter tree" represents the parsed contents of a buffer, which can be +used to perform further analysis. It is a |userdata| reference to an object +held by the treesitter library. + +An instance `TSTree` of a treesitter tree supports the following methods. + + +TSTree:copy() *TSTree:copy()* + Returns a copy of the `TSTree`. + + Return: ~ + (`TSTree`) + +TSTree:root() *TSTree:root()* + Return the root node of this tree. + + Return: ~ + (`TSNode`) + + +============================================================================== +TREESITTER NODES *treesitter-node* *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 +|userdata| reference to an object held by the treesitter library. + +An instance `TSNode` of a treesitter node supports the following methods. + + +TSNode:byte_length() *TSNode:byte_length()* + Return the number of bytes spanned by this node. + + Return: ~ + (`integer`) + +TSNode:child({index}) *TSNode:child()* + Get the node's child at the given {index}, where zero represents the first + child. + + Parameters: ~ + • {index} (`integer`) + + Return: ~ + (`TSNode?`) + + *TSNode:child_containing_descendant()* +TSNode:child_containing_descendant({descendant}) + Get the node's child that contains {descendant}. + + Parameters: ~ + • {descendant} (`TSNode`) + + Return: ~ + (`TSNode?`) + +TSNode:child_count() *TSNode:child_count()* + Get the node's number of children. + + Return: ~ + (`integer`) + + *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 + + Parameters: ~ + • {start_row} (`integer`) + • {start_col} (`integer`) + • {end_row} (`integer`) + • {end_col} (`integer`) + + Return: ~ + (`TSNode?`) + +TSNode:end_() *TSNode:end_()* + Get the node's end position. Return three values: the row, column and + total byte count (all zero-based). + + Return (multiple): ~ + (`integer`) + (`integer`) + (`integer`) + +TSNode:equal({node}) *TSNode:equal()* + Check if {node} refers to the same node within the same tree. + + Parameters: ~ + • {node} (`TSNode`) + + Return: ~ + (`boolean`) + +TSNode:extra() *TSNode:extra()* + Check if the node is extra. Extra nodes represent things like comments, + which are not required by the grammar but can appear anywhere. + + Return: ~ + (`boolean`) + +TSNode:field({name}) *TSNode:field()* + Returns a table of the nodes corresponding to the {name} field. + + Parameters: ~ + • {name} (`string`) + + Return: ~ + (`TSNode[]`) + +TSNode:has_changes() *TSNode:has_changes()* + Check if a syntax node has been edited. + + Return: ~ + (`boolean`) + +TSNode:has_error() *TSNode:has_error()* + Check if the node is a syntax error or contains any syntax errors. + + Return: ~ + (`boolean`) + +TSNode:id() *TSNode:id()* + Get a unique identifier for the node inside its own tree. + + No guarantees are made about this identifier's internal representation, + except for being a primitive Lua type with value equality (so not a + table). Presently it is a (non-printable) string. + + Note: The `id` is not guaranteed to be unique for nodes from different + trees. + + Return: ~ + (`string`) + +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. + + Return: ~ + (`fun(): TSNode, string`) + +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. + + Return: ~ + (`boolean`) + +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. + + Return: ~ + (`boolean`) + +TSNode:named_child({index}) *TSNode:named_child()* + Get the node's named child at the given {index}, where zero represents the + first named child. + + Parameters: ~ + • {index} (`integer`) + + Return: ~ + (`TSNode?`) + +TSNode:named_child_count() *TSNode:named_child_count()* + Get the node's number of named children. + + Return: ~ + (`integer`) + + *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 + + Parameters: ~ + • {start_row} (`integer`) + • {start_col} (`integer`) + • {end_row} (`integer`) + • {end_col} (`integer`) + + Return: ~ + (`TSNode?`) + +TSNode:next_named_sibling() *TSNode:next_named_sibling()* + Get the node's next named sibling. + + Return: ~ + (`TSNode?`) + +TSNode:next_sibling() *TSNode:next_sibling()* + Get the node's next sibling. + + Return: ~ + (`TSNode?`) + +TSNode:parent() *TSNode:parent()* + Get the node's immediate parent. Prefer + |TSNode:child_containing_descendant()| for iterating over the node's + ancestors. + + Return: ~ + (`TSNode?`) + +TSNode:prev_named_sibling() *TSNode:prev_named_sibling()* + Get the node's previous named sibling. + + Return: ~ + (`TSNode?`) + +TSNode:prev_sibling() *TSNode:prev_sibling()* + Get the node's previous sibling. + + Return: ~ + (`TSNode?`) + +TSNode:range({include_bytes}) *TSNode:range()* + Get the range of the node. + + Return four or six values: + • start row + • start column + • start byte (if {include_bytes} is `true`) + • end row + • end column + • end byte (if {include_bytes} is `true`) + + Parameters: ~ + • {include_bytes} (`boolean?`) + +TSNode:sexpr() *TSNode:sexpr()* + Get an S-expression representing the node as a string. + + Return: ~ + (`string`) + +TSNode:start() *TSNode:start()* + Get the node's start position. Return three values: the row, column and + total byte count (all zero-based). + + Return (multiple): ~ + (`integer`) + (`integer`) + (`integer`) + +TSNode:symbol() *TSNode:symbol()* + Get the node's type as a numerical id. + + Return: ~ + (`integer`) + +TSNode:tree() *TSNode:tree()* + Get the |TSTree| of the node. + + Return: ~ + (`TSTree`) + +TSNode:type() *TSNode:type()* + Get the node's type as a string. + + Return: ~ + (`string`) + + +============================================================================== Lua module: vim.treesitter *lua-treesitter-core* foldexpr({lnum}) *vim.treesitter.foldexpr()* @@ -719,6 +854,9 @@ foldexpr({lnum}) *vim.treesitter.foldexpr()* vim.wo.foldexpr = 'v:lua.vim.treesitter.foldexpr()' < + Attributes: ~ + Since: 0.9.0 + Parameters: ~ • {lnum} (`integer?`) Line number to calculate fold level for @@ -749,7 +887,7 @@ get_captures_at_pos({bufnr}, {row}, {col}) • {col} (`integer`) Position column Return: ~ - (`{capture: string, lang: string, metadata: table}[]`) + (`{capture: string, lang: string, metadata: vim.treesitter.query.TSMetadata}[]`) get_node({opts}) *vim.treesitter.get_node()* Returns the smallest named node at the given position @@ -764,13 +902,15 @@ get_node({opts}) *vim.treesitter.get_node()* • {opts} (`table?`) Optional keyword arguments: • {bufnr} (`integer?`) Buffer number (nil or 0 for current buffer) - • {pos} (`{ [1]: integer, [2]: integer }?`) 0-indexed (row, - col) tuple. Defaults to cursor position in the current - window. Required if {bufnr} is not the current buffer + • {pos} (`[integer, integer]?`) 0-indexed (row, col) tuple. + Defaults to cursor position in the current window. Required + if {bufnr} is not the current buffer • {lang} (`string?`) Parser language. (default: from buffer filetype) • {ignore_injections} (`boolean?`) Ignore injected languages (default true) + • {include_anonymous} (`boolean?`) Include anonymous nodes + (default false) Return: ~ (`TSNode?`) Node at the given position @@ -808,6 +948,11 @@ get_parser({bufnr}, {lang}, {opts}) *vim.treesitter.get_parser()* If needed, this will create the parser. + If no parser can be created, an error is thrown. Set `opts.error = false` + to suppress this and return nil (and an error message) instead. WARNING: + This behavior will become default in Nvim 0.12 and the option will be + removed. + Parameters: ~ • {bufnr} (`integer?`) Buffer the parser should be tied to (default: current buffer) @@ -815,8 +960,9 @@ get_parser({bufnr}, {lang}, {opts}) *vim.treesitter.get_parser()* filetype) • {opts} (`table?`) Options to pass to the created language tree - Return: ~ - (`vim.treesitter.LanguageTree`) object to use for parsing + Return (multiple): ~ + (`vim.treesitter.LanguageTree?`) object to use for parsing + (`string?`) error message, if applicable get_range({node}, {source}, {metadata}) *vim.treesitter.get_range()* Get the range of a |TSNode|. Can also supply {source} and {metadata} to @@ -829,7 +975,13 @@ get_range({node}, {source}, {metadata}) *vim.treesitter.get_range()* • {metadata} (`vim.treesitter.query.TSMetadata?`) Return: ~ - (`Range6`) + (`table`) A table with the following fields: + • {[1]} (`integer`) start row + • {[2]} (`integer`) start column + • {[3]} (`integer`) start bytes + • {[4]} (`integer`) end row + • {[5]} (`integer`) end column + • {[6]} (`integer`) end bytes *vim.treesitter.get_string_parser()* get_string_parser({str}, {lang}, {opts}) @@ -854,6 +1006,9 @@ inspect_tree({opts}) *vim.treesitter.inspect_tree()* Can also be shown with `:InspectTree`. *:InspectTree* + Attributes: ~ + Since: 0.9.0 + Parameters: ~ • {opts} (`table?`) Optional options table with the following possible keys: @@ -942,19 +1097,29 @@ add({lang}, {opts}) *vim.treesitter.language.add()* Load parser with name {lang} Parsers are searched in the `parser` runtime directory, or the provided - {path} + {path}. Can be used to check for available parsers before enabling + treesitter features, e.g., >lua + if vim.treesitter.language.add('markdown') then + vim.treesitter.start(bufnr, 'markdown') + end +< Parameters: ~ • {lang} (`string`) Name of the parser (alphanumerical and `_` only) • {opts} (`table?`) Options: - • {filetype}? (`string|string[]`, default: {lang}) Default - filetype the parser should be associated with. • {path}? (`string`) Optional path the parser is located at • {symbol_name}? (`string`) Internal symbol name for the language to load + Return (multiple): ~ + (`boolean?`) True if parser is loaded + (`string?`) Error if parser cannot be loaded + get_filetypes({lang}) *vim.treesitter.language.get_filetypes()* - Get the filetypes associated with the parser named {lang}. + Returns the filetypes for which a parser named {lang} is used. + + The list includes {lang} itself plus all filetypes registered via + |vim.treesitter.language.register()|. Parameters: ~ • {lang} (`string`) Name of parser @@ -963,6 +1128,11 @@ get_filetypes({lang}) *vim.treesitter.language.get_filetypes()* (`string[]`) filetypes get_lang({filetype}) *vim.treesitter.language.get_lang()* + Returns the language name to be used when loading a parser for {filetype}. + + If no language has been explicitly registered via + |vim.treesitter.language.register()|, default to {filetype}. For composite + filetypes like `html.glimmer`, only the main filetype is returned. Parameters: ~ • {filetype} (`string`) @@ -1007,7 +1177,7 @@ add_directive({name}, {handler}, {opts}) Parameters: ~ • {name} (`string`) Name of the directive, without leading # - • {handler} (`fun(match: table<integer,TSNode[]>, pattern: integer, source: integer|string, predicate: any[], metadata: table)`) + • {handler} (`fun(match: table<integer,TSNode[]>, pattern: integer, source: integer|string, predicate: any[], metadata: vim.treesitter.query.TSMetadata)`) • match: A table mapping capture IDs to a list of captured nodes • pattern: the index of the matching pattern in the query @@ -1020,9 +1190,8 @@ add_directive({name}, {handler}, {opts}) the same name • {all}? (`boolean`) Use the correct implementation of the match table where capture IDs map to a list of nodes - instead of a single node. Defaults to false (for backward - compatibility). This option will eventually become the - default and removed. + instead of a single node. Defaults to true. This option + will be removed in a future release. *vim.treesitter.query.add_predicate()* add_predicate({name}, {handler}, {opts}) @@ -1030,17 +1199,16 @@ add_predicate({name}, {handler}, {opts}) Parameters: ~ • {name} (`string`) Name of the predicate, without leading # - • {handler} (`fun(match: table<integer,TSNode[]>, pattern: integer, source: integer|string, predicate: any[], metadata: table)`) + • {handler} (`fun(match: table<integer,TSNode[]>, pattern: integer, source: integer|string, predicate: any[], metadata: vim.treesitter.query.TSMetadata)`) • see |vim.treesitter.query.add_directive()| for argument meanings - • {opts} (`table`) A table with the following fields: + • {opts} (`table?`) A table with the following fields: • {force}? (`boolean`) Override an existing predicate of the same name • {all}? (`boolean`) Use the correct implementation of the match table where capture IDs map to a list of nodes - instead of a single node. Defaults to false (for backward - compatibility). This option will eventually become the - default and removed. + instead of a single node. Defaults to true. This option + will be removed in a future release. edit({lang}) *vim.treesitter.query.edit()* Opens a live editor to query the buffer you started from. @@ -1200,14 +1368,8 @@ Query:iter_matches({node}, {source}, {start}, {stop}, {opts}) indices to a list of nodes, and metadata from any directives processing the match. - WARNING: Set `all=true` to ensure all matching nodes in a match are - returned, otherwise only the last node in a match is returned, breaking - captures involving quantifiers such as `(comment)+ @comment`. The default - option `all=false` is only provided for backward compatibility and will be - removed after Nvim 0.10. - Example: >lua - for pattern, match, metadata in cquery:iter_matches(tree:root(), bufnr, 0, -1, { all = true }) do + for pattern, match, metadata in cquery:iter_matches(tree:root(), bufnr, 0, -1) do for id, nodes in pairs(match) do local name = query.captures[id] for _, node in ipairs(nodes) do @@ -1232,16 +1394,15 @@ Query:iter_matches({node}, {source}, {start}, {stop}, {opts}) start depth for each match. This is used to prevent traversing too deep into a tree. • match_limit (integer) Set the maximum number of - in-progress matches (Default: 256). - • all (boolean) When set, the returned match table maps - capture IDs to a list of nodes. Older versions of - iter_matches incorrectly mapped capture IDs to a single - node, which is incorrect behavior. This option will - eventually become the default and removed. + in-progress matches (Default: 256). all (boolean) When + `false` (default `true`), the returned table maps capture + IDs to a single (last) node instead of the full list of + matching nodes. This option is only for backward + compatibility and will be removed in a future release. Return: ~ - (`fun(): integer, table<integer, TSNode[]>, table`) pattern id, match, - metadata + (`fun(): integer, table<integer, TSNode[]>, vim.treesitter.query.TSMetadata`) + pattern id, match, metadata set({lang}, {query_name}, {text}) *vim.treesitter.query.set()* Sets the runtime query named {query_name} for {lang} @@ -1296,7 +1457,11 @@ LanguageTree:contains({range}) *LanguageTree:contains()* Determines whether {range} is contained in the |LanguageTree|. Parameters: ~ - • {range} (`Range4`) `{ start_line, start_col, end_line, end_col }` + • {range} (`table`) A table with the following fields: + • {[1]} (`integer`) start row + • {[2]} (`integer`) start column + • {[3]} (`integer`) end row + • {[4]} (`integer`) end column Return: ~ (`boolean`) @@ -1320,7 +1485,9 @@ LanguageTree:for_each_tree({fn}) *LanguageTree:for_each_tree()* LanguageTree:included_regions() *LanguageTree:included_regions()* Gets the set of included regions managed by this LanguageTree. This can be different from the regions set by injection query, because a partial - |LanguageTree:parse()| drops the regions outside the requested range. + |LanguageTree:parse()| drops the regions outside the requested range. Each + list represents a range in the form of { {start_row}, {start_col}, + {start_bytes}, {end_row}, {end_col}, {end_bytes} }. Return: ~ (`table<integer, Range6[]>`) @@ -1355,7 +1522,11 @@ LanguageTree:language_for_range({range}) Gets the appropriate language that contains {range}. Parameters: ~ - • {range} (`Range4`) `{ start_line, start_col, end_line, end_col }` + • {range} (`table`) A table with the following fields: + • {[1]} (`integer`) start row + • {[2]} (`integer`) start column + • {[3]} (`integer`) end row + • {[4]} (`integer`) end column Return: ~ (`vim.treesitter.LanguageTree`) tree Managing {range} @@ -1365,7 +1536,28 @@ LanguageTree:named_node_for_range({range}, {opts}) Gets the smallest named node that contains {range}. Parameters: ~ - • {range} (`Range4`) `{ start_line, start_col, end_line, end_col }` + • {range} (`table`) A table with the following fields: + • {[1]} (`integer`) start row + • {[2]} (`integer`) start column + • {[3]} (`integer`) end row + • {[4]} (`integer`) end column + • {opts} (`table?`) A table with the following fields: + • {ignore_injections}? (`boolean`, default: `true`) Ignore + injected languages + + Return: ~ + (`TSNode?`) + + *LanguageTree:node_for_range()* +LanguageTree:node_for_range({range}, {opts}) + Gets the smallest node that contains {range}. + + Parameters: ~ + • {range} (`table`) A table with the following fields: + • {[1]} (`integer`) start row + • {[2]} (`integer`) start column + • {[3]} (`integer`) end row + • {[4]} (`integer`) end column • {opts} (`table?`) A table with the following fields: • {ignore_injections}? (`boolean`, default: `true`) Ignore injected languages @@ -1426,7 +1618,11 @@ LanguageTree:tree_for_range({range}, {opts}) Gets the tree that contains {range}. Parameters: ~ - • {range} (`Range4`) `{ start_line, start_col, end_line, end_col }` + • {range} (`table`) A table with the following fields: + • {[1]} (`integer`) start row + • {[2]} (`integer`) start column + • {[3]} (`integer`) end row + • {[4]} (`integer`) end column • {opts} (`table?`) A table with the following fields: • {ignore_injections}? (`boolean`, default: `true`) Ignore injected languages diff --git a/runtime/doc/term.txt b/runtime/doc/tui.txt index 8ef8675d13..9493f91b1e 100644 --- a/runtime/doc/term.txt +++ b/runtime/doc/tui.txt @@ -1,4 +1,4 @@ -*term.txt* Nvim +*tui.txt* Nvim NVIM REFERENCE MANUAL @@ -6,28 +6,45 @@ Terminal UI *TUI* *tui* -Nvim uses a list of terminal capabilities to display its user interface -(except in |--embed| and |--headless| modes). If that information is wrong, -the screen may be messed up or keys may not be recognized. +By default when you run `nvim` (without |--embed| or |--headless|) it starts +the builtin "terminal UI" (TUI). This default UI is optional: you can run Nvim +as a "headless" server, or you can use a |GUI|. Type |gO| to see the table of contents. ============================================================================== -Startup *startup-terminal* +Startup *startup-tui* *startup-terminal* + +Nvim has a client-server architecture: by default when you run `nvim`, this +starts the builtin UI client, which starts a `nvim --embed` server (child) +process that the UI client connects to. After attaching to the server, the UI +client calls |nvim_set_client_info()| (as recommended for all UIs |dev-ui|) +and sets these fields on its channel: > + + client = { + attributes = { + license = 'Apache 2', + pid = …, + website = 'https://neovim.io', + }, + name = 'nvim-tui', + type = 'ui', + version = { … }, + } Nvim guesses the terminal type when it starts (except in |--embed| and |--headless| modes). The |$TERM| environment variable is the primary hint that determines the terminal type. *terminfo* *E557* *E558* *E559* -The terminfo database is used if available. - -The Unibilium library (used by Nvim to read terminfo) allows you to override -the system terminfo with one in $HOME/.terminfo/ directory, in part or in -whole. - -Building your own terminfo is usually as simple as running this as -a non-superuser: +To display its user interface, Nvim reads a list of "terminal capabilities" +from the system terminfo database (or builtin defaults if terminfo is not +found). If that information is wrong, the screen may be messed up or keys may +not be recognized. + +The Unibilium library (used to read terminfo) allows you to override the +system terminfo with one in the "$HOME/.terminfo/" directory. Building your +own terminfo is usually as simple as running this: > curl -LO https://invisible-island.net/datafiles/current/terminfo.src.gz gunzip terminfo.src.gz @@ -41,6 +58,7 @@ or sub-optimal behavior will result (scrolling quirks, wrong colors, etc.). $TERM is also important because it is forwarded by SSH to the remote session, unlike most other environment variables. +> For this terminal Set $TERM to |builtin-terms| ------------------------------------------------------------------------- anything libvte-based vte, vte-256color Y @@ -61,6 +79,7 @@ unlike most other environment variables. Windows/VTP console vtpcon Y Windows/legacy console win32con Y xterm or compatible xterm, xterm-256color Y +< *builtin-terms* *builtin_terms* If a |terminfo| database is not available or there is no entry for the current @@ -126,27 +145,27 @@ extended keys a.k.a. "modifyOtherKeys" or "CSI u") can also be parsed. For example, when running Nvim in tmux, this makes Nvim leave Insert mode and go to the window below: > - tmux send-keys 'Escape' [ 2 7 u 'C-W' j + tmux send-keys 'Escape' [ 2 7 u 'C-W' j Where `'Escape' [ 2 7 u` is an unambiguous "CSI u" sequence for the <Esc> key. The kitty keyboard protocol https://sw.kovidgoyal.net/kitty/keyboard-protocol/ is partially supported, including keypad keys in Unicode Private Use Area. For example, this sequence is recognized by Nvim as <C-kEnter>: > - CSI 57414 ; 5 u + CSI 57414 ; 5 u and can be used differently from <C-CR> in mappings. *tui-modifyOtherKeys* *tui-csiu* At startup Nvim will query your terminal to see if it supports the "CSI u" encoding by writing the sequence > - CSI ? u CSI c + CSI ? u CSI c If your terminal emulator responds with > - CSI ? <flags> u + CSI ? <flags> u this means your terminal supports the "CSI u" encoding and Nvim will tell your terminal to enable it by writing the sequence > - CSI > 1 u + CSI > 1 u If your terminal does not support "CSI u" then Nvim will instead enable the "modifyOtherKeys" encoding by writing the sequence > - CSI > 4 ; 2 m + CSI > 4 ; 2 m When Nvim exits cleanly it will send the corresponding sequence to disable the special key encoding. If Nvim does not exit cleanly then your terminal @@ -215,9 +234,9 @@ are not in terminfo you must add them by setting "terminal-overrides" in See the tmux(1) manual page for the details of how and what to do in the tmux configuration file. It will look something like: >bash - set -ga terminal-overrides '*:Ss=\E[%p1%d q:Se=\E[ q' -<or (alas!) for Konsole 18.07.70 or older, something more complex like: >bash - set -ga terminal-overrides 'xterm*:\E]50;CursorShape=%?%p1%{3}%<%t%{0}%e%{1}%;%d\007' + set -ga terminal-overrides '*:Ss=\E[%p1%d q:Se=\E[ q' +or (alas!) for Konsole 18.07.70 or older, something more complex like: >bash + set -ga terminal-overrides 'xterm*:\E]50;CursorShape=%?%p1%{3}%<%t%{0}%e%{1}%;%d\007' < ============================================================================== Window size *window-size* @@ -250,12 +269,11 @@ number of lines that Vim uses with the command "z{height}<CR>". If the characters from the terminal are arriving with more than 1 second between them you might want to set the 'timeout' and/or 'ttimeout' option. -See the "Options" chapter |options|. If you are using a color terminal that is slow when displaying lines beyond the end of a buffer, this is because Nvim is drawing the whitespace twice, in two sets of colours and attributes. To prevent this, use this command: >vim - hi NonText cterm=NONE ctermfg=NONE + hi NonText cterm=NONE ctermfg=NONE This draws the spaces with the default colours and attributes, which allows the second pass of drawing to be optimized away. Note: Although in theory the colours of whitespace are immaterial, in practice they change the colours of @@ -268,57 +286,65 @@ Using the mouse *mouse-using* *mouse-mode-table* *mouse-overview* Overview of what the mouse buttons do, when 'mousemodel' is "extend": -Normal Mode: -event position selection change action ~ - cursor window ~ -<LeftMouse> yes end yes -<C-LeftMouse> yes end yes "CTRL-]" (2) -<S-LeftMouse> yes no change yes "*" (2) *<S-LeftMouse>* -<LeftDrag> yes start or extend (1) no *<LeftDrag>* -<LeftRelease> yes start or extend (1) no -<MiddleMouse> yes if not active no put -<MiddleMouse> yes if active no yank and put -<RightMouse> yes start or extend yes -<A-RightMouse> yes start or extend blockw. yes *<A-RightMouse>* -<S-RightMouse> yes no change yes "#" (2) *<S-RightMouse>* -<C-RightMouse> no no change no "CTRL-T" -<RightDrag> yes extend no *<RightDrag>* -<RightRelease> yes extend no *<RightRelease>* - -Insert or Replace Mode: -event position selection change action ~ - cursor window ~ -<LeftMouse> yes (cannot be active) yes -<C-LeftMouse> yes (cannot be active) yes "CTRL-O^]" (2) -<S-LeftMouse> yes (cannot be active) yes "CTRL-O*" (2) -<LeftDrag> yes start or extend (1) no like CTRL-O (1) -<LeftRelease> yes start or extend (1) no like CTRL-O (1) -<MiddleMouse> no (cannot be active) no put register -<RightMouse> yes start or extend yes like CTRL-O -<A-RightMouse> yes start or extend blockw. yes -<S-RightMouse> yes (cannot be active) yes "CTRL-O#" (2) -<C-RightMouse> no (cannot be active) no "CTRL-O CTRL-T" - -In a help window: -event position selection change action ~ - cursor window ~ -<2-LeftMouse> yes (cannot be active) no "^]" (jump to help tag) + *<S-LeftMouse>* *<A-RightMouse>* *<S-RightMouse>* *<RightDrag>* + *<RightRelease>* *<LeftDrag>* +Normal Mode: > + event position selection change action + cursor window + --------------------------------------------------------------------------- + <LeftMouse> yes end yes + <C-LeftMouse> yes end yes "CTRL-]" (2) + <S-LeftMouse> yes no change yes "*" (2) + <LeftDrag> yes start or extend (1) no + <LeftRelease> yes start or extend (1) no + <MiddleMouse> yes if not active no put + <MiddleMouse> yes if active no yank and put + <RightMouse> yes start or extend yes + <A-RightMouse> yes start or extend blockw. yes + <S-RightMouse> yes no change yes "#" (2) + <C-RightMouse> no no change no "CTRL-T" + <RightDrag> yes extend no + <RightRelease> yes extend no + +Insert or Replace Mode: > + event position selection change action + cursor window + --------------------------------------------------------------------------- + <LeftMouse> yes (cannot be active) yes + <C-LeftMouse> yes (cannot be active) yes "CTRL-O^]" (2) + <S-LeftMouse> yes (cannot be active) yes "CTRL-O*" (2) + <LeftDrag> yes start or extend (1) no like CTRL-O (1) + <LeftRelease> yes start or extend (1) no like CTRL-O (1) + <MiddleMouse> no (cannot be active) no put register + <RightMouse> yes start or extend yes like CTRL-O + <A-RightMouse> yes start or extend blockw. yes + <S-RightMouse> yes (cannot be active) yes "CTRL-O#" (2) + <C-RightMouse> no (cannot be active) no "CTRL-O CTRL-T" + +In a help window: > + event position selection change action + cursor window + --------------------------------------------------------------------------- + <2-LeftMouse> yes (cannot be active) no "^]" (jump to help tag) When 'mousemodel' is "popup", these are different: -Normal Mode: -event position selection change action ~ - cursor window ~ -<S-LeftMouse> yes start or extend (1) no -<A-LeftMouse> yes start or extend blockw. no *<A-LeftMouse>* -<RightMouse> no popup menu no - -Insert or Replace Mode: -event position selection change action ~ - cursor window ~ -<S-LeftMouse> yes start or extend (1) no like CTRL-O (1) -<A-LeftMouse> yes start or extend blockw. no -<RightMouse> no popup menu no + *<A-LeftMouse>* +Normal Mode: > + event position selection change action + cursor window + --------------------------------------------------------------------------- + <S-LeftMouse> yes start or extend (1) no + <A-LeftMouse> yes start/extend blockw no + <RightMouse> no popup menu no + +Insert or Replace Mode: > + event position selection change action + cursor window + --------------------------------------------------------------------------- + <S-LeftMouse> yes start or extend (1) no like CTRL-O (1) + <A-LeftMouse> yes start/extend blockw no + <RightMouse> no popup menu no (1) only if mouse pointer moved since press (2) only if click is in same buffer @@ -348,16 +374,20 @@ key pressed causes the Visual area to become blockwise. When 'mousemodel' is work on systems where the window manager consumes the mouse events when the alt key is pressed (it may move the window). - *double-click* + *double-click* *<2-LeftMouse>* *<3-LeftMouse>* *<4-LeftMouse>* Double, triple and quadruple clicks are supported when the GUI is active, for Win32 and for an xterm. For selecting text, extra clicks extend the -selection: - click select ~ - double word or % match *<2-LeftMouse>* - triple line *<3-LeftMouse>* - quadruple rectangular block *<4-LeftMouse>* +selection: > + + click select + --------------------------------- + double word or % match + triple line + quadruple rectangular block + Exception: In a Help window a double click jumps to help for the word that is clicked on. + A double click on a word selects that word. 'iskeyword' is used to specify which characters are included in a word. A double click on a character that has a match selects until that match (like using "v%"). If the match is @@ -365,7 +395,7 @@ an #if/#else/#endif block, the selection becomes linewise. For MS-Windows and xterm the time for double clicking can be set with the 'mousetime' option. For the other systems this time is defined outside of Vim. An example, for using a double click to jump to the tag under the cursor: >vim - :map <2-LeftMouse> :exe "tag " .. expand("<cword>")<CR> + :map <2-LeftMouse> :exe "tag " .. expand("<cword>")<CR> Dragging the mouse with a double click (button-down, button-up, button-down and then drag) will result in whole words to be selected. This continues @@ -379,59 +409,62 @@ temporarily. When Visual or Select mode ends, it returns to Insert mode. This is like using CTRL-O in Insert mode. Select mode is used when the 'selectmode' option contains "mouse". - *<MiddleRelease>* *<MiddleDrag>* -Mouse clicks can be mapped. The codes for mouse clicks are: - code mouse button normal action ~ - <LeftMouse> left pressed set cursor position - <LeftDrag> left moved while pressed extend selection - <LeftRelease> left released set selection end - <MiddleMouse> middle pressed paste text at cursor position - <MiddleDrag> middle moved while pressed - - <MiddleRelease> middle released - - <RightMouse> right pressed extend selection - <RightDrag> right moved while pressed extend selection - <RightRelease> right released set selection end - <X1Mouse> X1 button pressed - *X1Mouse* - <X1Drag> X1 moved while pressed - *X1Drag* - <X1Release> X1 button release - *X1Release* - <X2Mouse> X2 button pressed - *X2Mouse* - <X2Drag> X2 moved while pressed - *X2Drag* - <X2Release> X2 button release - *X2Release* + *X1Mouse* *X1Drag* *X1Release* + *X2Mouse* *X2Drag* *X2Release* + *<MiddleRelease>* *<MiddleDrag>* +Mouse clicks can be mapped. The codes for mouse clicks are: > + code mouse button normal action + --------------------------------------------------------------------------- + <LeftMouse> left pressed set cursor position + <LeftDrag> left moved while pressed extend selection + <LeftRelease> left released set selection end + <MiddleMouse> middle pressed paste text at cursor position + <MiddleDrag> middle moved while pressed - + <MiddleRelease> middle released - + <RightMouse> right pressed extend selection + <RightDrag> right moved while pressed extend selection + <RightRelease> right released set selection end + <X1Mouse> X1 button pressed - + <X1Drag> X1 moved while pressed - + <X1Release> X1 button release - + <X2Mouse> X2 button pressed - + <X2Drag> X2 moved while pressed - + <X2Release> X2 button release - The X1 and X2 buttons refer to the extra buttons found on some mice. The 'Microsoft Explorer' mouse has these buttons available to the right thumb. Currently X1 and X2 only work on Win32 and X11 environments. Examples: >vim - :noremap <MiddleMouse> <LeftMouse><MiddleMouse> + :noremap <MiddleMouse> <LeftMouse><MiddleMouse> Paste at the position of the middle mouse button click (otherwise the paste would be done at the cursor position). >vim - :noremap <LeftRelease> <LeftRelease>y + :noremap <LeftRelease> <LeftRelease>y Immediately yank the selection, when using Visual mode. Note the use of ":noremap" instead of "map" to avoid a recursive mapping. >vim - :map <X1Mouse> <C-O> - :map <X2Mouse> <C-I> + :map <X1Mouse> <C-O> + :map <X2Mouse> <C-I> Map the X1 and X2 buttons to go forwards and backwards in the jump list, see |CTRL-O| and |CTRL-I|. *mouse-swap-buttons* To swap the meaning of the left and right mouse buttons: >vim - :noremap <LeftMouse> <RightMouse> - :noremap <LeftDrag> <RightDrag> - :noremap <LeftRelease> <RightRelease> - :noremap <RightMouse> <LeftMouse> - :noremap <RightDrag> <LeftDrag> - :noremap <RightRelease> <LeftRelease> - :noremap g<LeftMouse> <C-RightMouse> - :noremap g<RightMouse> <C-LeftMouse> - :noremap! <LeftMouse> <RightMouse> - :noremap! <LeftDrag> <RightDrag> - :noremap! <LeftRelease> <RightRelease> - :noremap! <RightMouse> <LeftMouse> - :noremap! <RightDrag> <LeftDrag> - :noremap! <RightRelease> <LeftRelease> + :noremap <LeftMouse> <RightMouse> + :noremap <LeftDrag> <RightDrag> + :noremap <LeftRelease> <RightRelease> + :noremap <RightMouse> <LeftMouse> + :noremap <RightDrag> <LeftDrag> + :noremap <RightRelease> <LeftRelease> + :noremap g<LeftMouse> <C-RightMouse> + :noremap g<RightMouse> <C-LeftMouse> + :noremap! <LeftMouse> <RightMouse> + :noremap! <LeftDrag> <RightDrag> + :noremap! <LeftRelease> <RightRelease> + :noremap! <RightMouse> <LeftMouse> + :noremap! <RightDrag> <LeftDrag> + :noremap! <RightRelease> <LeftRelease> < - vim:tw=78:ts=8:ft=help:norl: + vim:et:sw=2:tw=78:ts=8:ft=help:norl: diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt index 1f5132bd30..d37cdfb9df 100644 --- a/runtime/doc/ui.txt +++ b/runtime/doc/ui.txt @@ -9,7 +9,7 @@ Nvim UI protocol *UI* *ui* Type |gO| to see the table of contents. ============================================================================== -UI Events *ui-events* +UI Events *ui-protocol* *ui-events* UIs can be implemented as external client processes communicating with Nvim over the RPC API. The default UI model is a terminal-like grid with a single, @@ -398,8 +398,8 @@ numerical highlight ids to the actual attributes. `grid` will not be used anymore and the UI can free any data associated with it. -["grid_cursor_goto", grid, row, column] ~ - Makes `grid` the current grid and `row, column` the cursor position on this +["grid_cursor_goto", grid, row, col] ~ + Makes `grid` the current grid and `row, col` the cursor position on this grid. This event will be sent at most once in a `redraw` batch and indicates the visible cursor position. @@ -610,7 +610,7 @@ tabs. size). If the window was previously hidden, it should now be shown again. -["win_float_pos", grid, win, anchor, anchor_grid, anchor_row, anchor_col, focusable] ~ +["win_float_pos", grid, win, anchor, anchor_grid, anchor_row, anchor_col, focusable, zindex] ~ Display or reconfigure floating window `win`. The window should be displayed above another grid `anchor_grid` at the specified position `anchor_row` and `anchor_col`. For the meaning of `anchor` and more diff --git a/runtime/doc/undo.txt b/runtime/doc/undo.txt index 3fcc196250..b3a49dbb7e 100644 --- a/runtime/doc/undo.txt +++ b/runtime/doc/undo.txt @@ -165,13 +165,13 @@ This is explained in the user manual: |usr_32.txt|. g- Go to older text state. With a count repeat that many times. *:ea* *:earlier* -:earlier {count} Go to older text state {count} times. -:earlier {N}s Go to older text state about {N} seconds before. -:earlier {N}m Go to older text state about {N} minutes before. -:earlier {N}h Go to older text state about {N} hours before. -:earlier {N}d Go to older text state about {N} days before. +:ea[rlier] {count} Go to older text state {count} times. +:ea[rlier] {N}s Go to older text state about {N} seconds before. +:ea[rlier] {N}m Go to older text state about {N} minutes before. +:ea[rlier] {N}h Go to older text state about {N} hours before. +:ea[rlier] {N}d Go to older text state about {N} days before. -:earlier {N}f Go to older text state {N} file writes before. +:ea[rlier] {N}f Go to older text state {N} file writes before. When changes were made since the last write ":earlier 1f" will revert the text to the state when it was written. Otherwise it will go to the write @@ -184,13 +184,13 @@ g- Go to older text state. With a count repeat that many g+ Go to newer text state. With a count repeat that many times. *:lat* *:later* -:later {count} Go to newer text state {count} times. -:later {N}s Go to newer text state about {N} seconds later. -:later {N}m Go to newer text state about {N} minutes later. -:later {N}h Go to newer text state about {N} hours later. -:later {N}d Go to newer text state about {N} days later. +:lat[er] {count} Go to newer text state {count} times. +:lat[er] {N}s Go to newer text state about {N} seconds later. +:lat[er] {N}m Go to newer text state about {N} minutes later. +:lat[er] {N}h Go to newer text state about {N} hours later. +:lat[er] {N}d Go to newer text state about {N} days later. -:later {N}f Go to newer text state {N} file writes later. +:lat[er] {N}f Go to newer text state {N} file writes later. When at the state of the last file write, ":later 1f" will go to the newest text state. diff --git a/runtime/doc/usr_05.txt b/runtime/doc/usr_05.txt index 076a50c582..698d1207d3 100644 --- a/runtime/doc/usr_05.txt +++ b/runtime/doc/usr_05.txt @@ -120,7 +120,7 @@ This switches on three very clever mechanisms: *restore-cursor* *last-position-jump* > augroup RestoreCursor autocmd! - autocmd BufRead * autocmd FileType <buffer> ++once + autocmd BufReadPre * autocmd FileType <buffer> ++once \ let s:line = line("'\"") \ | if s:line >= 1 && s:line <= line("$") && &filetype !~# 'commit' \ && index(['xxd', 'gitrebase'], &filetype) == -1 @@ -234,6 +234,22 @@ an archive or as a repository. For an archive you can follow these steps: Here "fancytext" is the name of the package, it can be anything else. + +Adding nohlsearch package *nohlsearch-install* + +Load the plugin with this command: > + packadd nohlsearch +< +Automatically execute |:nohlsearch| after 'updatetime' or getting into +|Insert| mode. +Thus assuming default updatetime, hlsearch would be suspended/turned off after +4 seconds of idle time. + +To disable the effect of the plugin after it has been loaded: > + au! nohlsearch +< + + More information about packages can be found here: |packages|. ============================================================================== diff --git a/runtime/doc/usr_21.txt b/runtime/doc/usr_21.txt index 4ae72bbe84..8671f04ba2 100644 --- a/runtime/doc/usr_21.txt +++ b/runtime/doc/usr_21.txt @@ -303,21 +303,21 @@ use, and save this in a session. Then you can go back to this layout whenever you want. For example, this is a nice layout to use: > - +----------------------------------------+ - | VIM - main help file | - | | - |Move around: Use the cursor keys, or "h| - |help.txt================================| - |explorer | | - |dir |~ | - |dir |~ | - |file |~ | - |file |~ | - |file |~ | - |file |~ | - |~/=========|[No File]===================| - | | - +----------------------------------------+ + +----------------------------------------+ + | VIM - main help file | + | | + |Move around: Use the cursor keys, or "h| + |help.txt================================| + |explorer | | + |dir |~ | + |dir |~ | + |file |~ | + |file |~ | + |file |~ | + |file |~ | + |~/=========|[No File]===================| + | | + +----------------------------------------+ < This has a help window at the top, so that you can read this text. The narrow vertical window on the left contains a file explorer. This is a Vim plugin @@ -448,9 +448,9 @@ trust the files you are editing: > :set nomodeline -Use this format for the modeline: +Use this format for the modeline: > - any-text vim:set {option}={value} ... : any-text ~ + any-text vim:set {option}={value} ... : any-text The "any-text" indicates that you can put any text before and after the part that Vim will use. This allows making it look like a comment, like what was @@ -462,9 +462,9 @@ using something like "gvim:" will not work. typing the ":set" command, except that you need to insert a backslash before a colon (otherwise it would be seen as the end of the modeline). -Another example: +Another example: > - // vim:set textwidth=72 dir=c\:\tmp: use c:\tmp here ~ + // vim:set textwidth=72 dir=c\:\tmp: use c:\tmp here There is an extra backslash before the first colon, so that it's included in the ":set" command. The text after the second colon is ignored, thus a remark diff --git a/runtime/doc/usr_29.txt b/runtime/doc/usr_29.txt index dd8598a3a0..eb20f7b6f2 100644 --- a/runtime/doc/usr_29.txt +++ b/runtime/doc/usr_29.txt @@ -34,7 +34,7 @@ following command: > "ctags" is a separate program. Most Unix systems already have it installed. If you do not have it yet, you can find Universal ctags at: - https://ctags.io ~ + https://ctags.io Universal ctags is preferred, Exuberant ctags is no longer being developed. @@ -87,7 +87,7 @@ The ":tags" command shows the list of tags that you traversed through: 1 1 write_line 8 write_block.c ~ 2 1 write_char 7 write_line.c ~ > ~ -> +< Now to go back. The CTRL-T command goes to the preceding tag. In the example above you get back to the "write_line" function, in the call to "write_char". This command takes a count argument that indicates how many tags to jump diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt index ab2eecdfaf..8c7ed875cf 100644 --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -836,6 +836,7 @@ System functions and manipulation of files: getfperm() get the permissions of a file setfperm() set the permissions of a file getftype() get the kind of a file + isabsolutepath() check if a path is absolute isdirectory() check if a directory exists getfsize() get the size of a file getcwd() get the current working directory @@ -855,6 +856,7 @@ System functions and manipulation of files: readblob() read a file into a Blob readdir() get a List of file names in a directory writefile() write a List of lines or Blob into a file + filecopy() copy a file {from} to {to} Date and Time: *date-functions* *time-functions* getftime() get last modification time of a file @@ -906,7 +908,8 @@ Buffers, windows and the argument list: Command line: *command-line-functions* getcmdcompltype() get the type of the current command line completion - getcmdline() get the current command line + getcmdline() get the current command line input + getcmdprompt() get the current command line prompt getcmdpos() get position of the cursor in the command line getcmdscreenpos() get screen position of the cursor in the command line diff --git a/runtime/doc/usr_toc.txt b/runtime/doc/usr_toc.txt index dd0d5784f5..d1770ddcd5 100644 --- a/runtime/doc/usr_toc.txt +++ b/runtime/doc/usr_toc.txt @@ -2,12 +2,12 @@ VIM USER MANUAL - by Bram Moolenaar - Table Of Contents *user-manual* + Table Of Contents *user-manual* *usr* ============================================================================== Overview -Getting Started +Getting Started ~ |usr_01.txt| About the manuals |usr_02.txt| The first steps in Vim |usr_03.txt| Moving around @@ -21,7 +21,7 @@ Getting Started |usr_11.txt| Recovering from a crash |usr_12.txt| Clever tricks -Editing Effectively +Editing Effectively ~ |usr_20.txt| Typing command-line commands quickly |usr_21.txt| Go away and come back |usr_22.txt| Finding the file to edit @@ -36,7 +36,7 @@ Editing Effectively |usr_31.txt| Exploiting the GUI |usr_32.txt| The undo tree -Tuning Vim +Tuning Vim ~ |usr_40.txt| Make new commands |usr_41.txt| Write a Vim script |usr_42.txt| Add new menus @@ -45,7 +45,7 @@ Tuning Vim |usr_45.txt| Select your language (locale) -Reference manual +Reference manual ~ |reference_toc| More detailed information for all commands The user manual is online: diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt index 0287271d4c..33da539c66 100644 --- a/runtime/doc/various.txt +++ b/runtime/doc/various.txt @@ -28,8 +28,8 @@ CTRL-L Clears and redraws the screen. The redraw may happen :redr[aw][!] Redraws pending screen updates now, or the entire screen if "!" is included. To CLEAR the screen use |:mode| or |CTRL-L|. - Useful to update the screen during a script or - function (or a mapping if 'lazyredraw' set). + It can be used to redraw the screen in a script + or function (or a mapping if |'lazyredraw'| is set). See also |nvim__redraw()|. *:redraws* *:redrawstatus* @@ -78,10 +78,9 @@ ga Print the ascii value of the character under the If the character can be inserted as a digraph, also output the two characters that can be used to create the character: - <ö> 246, Hex 00f6, Oct 366, Digr o: ~ + <ö> 246, Hex 00f6, Oct 366, Digr o: ~ This shows you can type CTRL-K o : to insert ö. - *g8* g8 Print the hex values of the bytes used in the character under the cursor, assuming it is in |UTF-8| @@ -140,12 +139,18 @@ gx Opens the current filepath or URL (decided by :[range]# [count] [flags] synonym for :number. - *:#!* + *:#!* *vim-shebang* :#!{anything} Ignored, so that you can start a Vim script with: > #!vim -S - echo "this is a Vim script" - quit + let mylogbook='$HOME/logbook.md' + exe $':e {mylogbook}' + $ + put ='## ' .. strftime('%d. %b %Y') + norm! o < + Make that script executable and run it to create a + new diary entry. + *:z* *E144* :[range]z[+-^.=][count] Display several lines of text surrounding the line specified with [range], or around the current line @@ -209,7 +214,7 @@ gx Opens the current filepath or URL (decided by This implies that an insert command must be completed (to start Insert mode, see |:startinsert|). A ":" command must be completed as well. And you can't use - "Q" or "gQ" to start Ex mode. + "gQ" to start Ex mode. The display is not updated while ":normal" is busy. diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index 5d894bb5e1..e069678b30 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -62,11 +62,12 @@ Defaults *nvim-defaults* - 'isfname' does not include ":" (on Windows). Drive letters are handled correctly without it. (Use |gF| for filepaths suffixed with ":line:col"). - 'joinspaces' is disabled +- 'jumpoptions' defaults to "clean" - 'langnoremap' is enabled - 'langremap' is disabled - 'laststatus' defaults to 2 (statusline is always shown) - 'listchars' defaults to "tab:> ,trail:-,nbsp:+" -- 'mouse' defaults to "nvi" +- 'mouse' defaults to "nvi", see |default-mouse| for details - 'mousemodel' defaults to "popup_setpos" - 'nrformats' defaults to "bin,hex" - 'path' defaults to ".,,". The C ftplugin adds "/usr/include" if it exists. @@ -100,28 +101,35 @@ Defaults *nvim-defaults* DEFAULT MOUSE *default-mouse* *disable-mouse* -By default the mouse is enabled, and <RightMouse> opens a |popup-menu| with -standard actions ("Cut", "Copy", "Paste", …). Mouse is NOT enabled in -|command-mode| or the |more-prompt|, so you can temporarily disable it just by -typing ":". +By default the mouse is enabled. This means |scroll-mouse-wheel| will scroll +the window instead of moving the cursor; <LeftMouse> click places the cursor; +and <RightMouse> click opens the default |popup-menu| with standard actions. + +Mouse is NOT enabled in |Cmdline-mode| or the |more-prompt|, so you can +temporarily disable it just by typing ":". Or if you want to partially or +fully disable the mouse or popup-menu, do any of the following: -If you don't like this you can disable the mouse in your |config| using any of -the following: - Disable mouse completely by unsetting the 'mouse' option: >vim set mouse= -- Pressing <RightMouse> extends selection instead of showing popup-menu: >vim +- Change the 'mousemodel', so <RightMouse> extends selection instead of + showing the popup-menu: >vim set mousemodel=extend -- Pressing <A-LeftMouse> releases mouse until the cursor moves: >vim +- Map <A-LeftMouse> so that it temporarily disables mouse until the cursor + moves: >vim nnoremap <A-LeftMouse> <Cmd> \ set mouse=<Bar> \ echo 'mouse OFF until next cursor-move'<Bar> \ autocmd CursorMoved * ++once set mouse&<Bar> \ echo 'mouse ON'<CR> < -To remove the "How-to disable mouse" menu item and the separator above it: >vim +To remove the default popup-menu without disabling mouse: >vim + aunmenu PopUp + autocmd! nvim_popupmenu + +To remove only the "How-to disable mouse" menu item (and its separator): >vim aunmenu PopUp.How-to\ disable\ mouse - aunmenu PopUp.-1- -< + aunmenu PopUp.-2- + DEFAULT MAPPINGS *default-mappings* Nvim creates the following default mappings at |startup|. You can disable any @@ -145,7 +153,14 @@ of these in your config by simply removing the mapping, e.g. ":unmap Y". - <C-S> |i_CTRL-S| - ]d |]d-default| - [d |[d-default| +- [D |[D-default| +- ]D |]D-default| - <C-W>d |CTRL-W_d-default| +- |[q|, |]q|, |[Q|, |]Q|, |[CTRL-Q|, |]CTRL-Q| +- |[l|, |]l|, |[L|, |]L|, |[CTRL-L|, |]CTRL-L| +- |[t|, |]t|, |[T|, |]T|, |[CTRL-T|, |]CTRL-T| +- |[a|, |]a|, |[A|, |]A| +- |[b|, |]b|, |[B|, |]B| - Nvim LSP client defaults |lsp-defaults| - K |K-lsp-default| @@ -164,6 +179,14 @@ nvim_terminal: when 'background' is "light". While this may not reflect the actual foreground/background color, it permits 'background' to be retained for a nested Nvim instance running in the terminal emulator. +- TermOpen: Sets default options for |terminal| buffers: + - 'nomodifiable' + - 'undolevels' set to -1 + - 'textwidth' set to 0 + - 'nowrap' + - 'nolist' + - 'winhighlight' uses |hl-StatusLineTerm| and |hl-StatusLineTermNC| in + place of |hl-StatusLine| and |hl-StatusLineNC| nvim_cmdwin: - CmdwinEnter: Limits syntax sync to maxlines=1 in the |cmdwin|. @@ -330,7 +353,9 @@ string options work. - 'guicursor' works in the terminal (TUI) - 'inccommand' shows interactive results for |:substitute|-like commands and |:command-preview| commands -- 'jumpoptions' "view" tries to restore the |mark-view| when moving through +- 'jumpoptions' + - "view" tries to restore |mark-view| when moving through the jumplist. + - "clean" removes unloaded buffers from the jumplist. - the |jumplist|, |changelist|, |alternate-file| or using |mark-motions|. - 'laststatus' global statusline support - 'mousescroll' amount to scroll by when scrolling with a mouse @@ -529,13 +554,13 @@ Functions: Highlight groups: - |hl-ColorColumn|, |hl-CursorColumn| are lower priority than most other groups -- |hl-CurSearch| highlights match under cursor instead of last match found - using |n| or |N| - |hl-CursorLine| is low-priority unless foreground color is set - |hl-VertSplit| superseded by |hl-WinSeparator| - Highlight groups names are allowed to contain `@` characters. - It is an error to define a highlight group with a name that doesn't match the regexp `[a-zA-Z0-9_.@-]*` (see |group-name|). +- |hl-StatusLineTerm| |hl-StatusLineTermNC| are implemented as 'winhighlight' + window-local highlights which are set by the default |TermOpen| handler. Macro (|recording|) behavior: - Replay of a macro recorded during :lmap produces the same actions as when it @@ -663,17 +688,6 @@ Events: - *SafeStateAgain* - *SigUSR1* Use |Signal| to detect `SIGUSR1` signal instead. -Highlight groups: -- *hl-StatusLineTerm* *hl-StatusLineTermNC* are unnecessary because Nvim - supports 'winhighlight' window-local highlights. For example, to mimic Vim's - StatusLineTerm: >vim - hi StatusLineTerm ctermfg=black ctermbg=green - hi StatusLineTermNC ctermfg=green - autocmd TermOpen,WinEnter * if &buftype=='terminal' - \|setlocal winhighlight=StatusLine:StatusLineTerm,StatusLineNC:StatusLineTermNC - \|else|setlocal winhighlight=|endif -< - Options: - *'aleph'* *'al'* - antialias diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt index 4791e73929..5729dd0874 100644 --- a/runtime/doc/windows.txt +++ b/runtime/doc/windows.txt @@ -53,11 +53,27 @@ active yes yes 'a' hidden no yes 'h' inactive no no ' ' -Note: All CTRL-W commands can also be executed with |:wincmd|, for those -places where a Normal mode command can't be used or is inconvenient. + *buffer-reuse* +Each buffer has a unique number and the number will not change within a Vim +session. The |bufnr()| and |bufname()| functions can be used to convert +between a buffer name and the buffer number. There is one exception: if a new +empty buffer is created and it is not modified, the buffer will be re-used +when loading another file into that buffer. This also means the buffer number +will not change. The main Vim window can hold several split windows. There are also tab pages |tab-page|, each of which can hold multiple windows. + + *focusable* +If a window is focusable, it is part of the "navigation stack", that is, +editor commands such as :windo, |CTRL-W|, etc., will consider the window as +one that can be made the "current window". A non-focusable window will be +skipped by such commands (though it can be explicitly focused by +|nvim_set_current_win()|). + +Windows (especially floating windows) can have many other |api-win_config| +properties such as "hide" and "fixed" which also affect behavior. + *window-ID* *winid* *windowid* Each window has a unique identifier called the window ID. This identifier will not change within a Vim session. The |win_getid()| and |win_id2tabwin()| @@ -69,9 +85,6 @@ across tabs. For most functions that take a window ID or a window number, the window number only applies to the current tab, while the window ID can refer to a window in any tab. -Each buffer has a unique number and the number will not change within a Vim -session. The |bufnr()| and |bufname()| functions can be used to convert -between a buffer name and the buffer number. ============================================================================== 2. Starting Vim *windows-starting* @@ -423,18 +436,19 @@ CTRL-W l Move cursor to Nth window right of current one. Uses the cursor position to select between alternatives. CTRL-W w *CTRL-W_w* *CTRL-W_CTRL-W* -CTRL-W CTRL-W Without count: move cursor to window below/right of the - current one. If there is no window below or right, go to - top-left window. - With count: go to Nth window (windows are numbered from - top-left to bottom-right). To obtain the window number see - |bufwinnr()| and |winnr()|. When N is larger than the number - of windows go to the last window. +CTRL-W CTRL-W Without count: move cursor to the |focusable| window + below/right of the current one. If there is no (focusable) + window below or right, go to top-left window. With count: go + to Nth window (windows are numbered from top-left to + bottom-right). To obtain the window number see |bufwinnr()| + and |winnr()|. When N is larger than the number of windows go + to the last window. *CTRL-W_W* -CTRL-W W Without count: move cursor to window above/left of current - one. If there is no window above or left, go to bottom-right - window. With count: go to Nth window, like with CTRL-W w. +CTRL-W W Without count: move cursor to the |focusable| window + above/left of current one. If there is no window above or + left, go to bottom-right window. With count: go to Nth + window, like with CTRL-W w. CTRL-W t *CTRL-W_t* *CTRL-W_CTRL-T* CTRL-W CTRL-T Move cursor to top-left window. @@ -468,6 +482,10 @@ These commands can also be executed with ":wincmd": :exe nr .. "wincmd w" < This goes to window "nr". +Note: All CTRL-W commands can also be executed with |:wincmd|, for those +places where a Normal mode command can't be used or is inconvenient (e.g. +in a browser-based terminal). + ============================================================================== 5. Moving windows around *window-moving* @@ -787,9 +805,9 @@ can also get to them with the buffer list commands, like ":bnext". 8. Do a command in all buffers or windows *list-repeat* *:windo* -:[range]windo {cmd} Execute {cmd} in each window or if [range] is given - only in windows for which the window number lies in - the [range]. It works like doing this: > +:[range]windo {cmd} Execute {cmd} in each |focusable| window, or only for + windows in a given [range] of window numbers. It works + like doing this: > CTRL-W t :{cmd} CTRL-W w @@ -1175,11 +1193,12 @@ list of buffers. |unlisted-buffer| :bw[ipeout][!] N1 N2 ... Like |:bdelete|, but really delete the buffer. Everything related to the buffer is lost. All marks in this buffer - become invalid, option settings are lost, etc. Don't use this + become invalid, option settings are lost, the jumplist and + tagstack data will be purged, etc. Don't use this unless you know what you are doing. Examples: > - :.+,$bwipeout " wipe out all buffers after the current - " one - :%bwipeout " wipe out all buffers + :.+,$bwipeout " wipe out all buffers after the current + " one + :%bwipeout " wipe out all buffers < :[N]bun[load][!] *:bun* *:bunload* *E515* :bun[load][!] [N] @@ -1242,7 +1261,7 @@ list of buffers. |unlisted-buffer| :w foobar | sp # < Also see |+cmd|. -:[N]bn[ext][!] [+cmd] [N] *:bn* *:bnext* *E87* +:[N]bn[ext][!] [+cmd] [N] *:bn* *:bnext* *[b* *E87* Go to [N]th next buffer in buffer list. [N] defaults to one. Wraps around the end of the buffer list. See |:buffer-!| for [!]. @@ -1260,7 +1279,7 @@ list of buffers. |unlisted-buffer| Wraps around the end of the buffer list. Uses 'switchbuf' Also see |+cmd|. -:[N]bN[ext][!] [+cmd] [N] *:bN* *:bNext* *:bp* *:bprevious* *E88* +:[N]bN[ext][!] [+cmd] [N] *:bN* *:bNext* *:bp* *:bprevious* *]b* *E88* :[N]bp[revious][!] [+cmd] [N] Go to [N]th previous buffer in buffer list. [N] defaults to one. Wraps around the start of the buffer list. @@ -1274,7 +1293,7 @@ list of buffers. |unlisted-buffer| Uses 'switchbuf'. Also see |+cmd|. -:br[ewind][!] [+cmd] *:br* *:bre* *:brewind* +:br[ewind][!] [+cmd] *:br* *:bre* *:brewind* *[B* Go to first buffer in buffer list. If the buffer list is empty, go to the first unlisted buffer. See |:buffer-!| for [!]. @@ -1292,7 +1311,7 @@ list of buffers. |unlisted-buffer| :sbf[irst] [+cmd] *:sbf* *:sbfirst* Same as ":sbrewind". -:bl[ast][!] [+cmd] *:bl* *:blast* +:bl[ast][!] [+cmd] *:bl* *:blast* *]B* Go to last buffer in buffer list. If the buffer list is empty, go to the last unlisted buffer. See |:buffer-!| for [!]. diff --git a/runtime/filetype.lua b/runtime/filetype.lua index 4880ed55ef..797033da06 100644 --- a/runtime/filetype.lua +++ b/runtime/filetype.lua @@ -21,7 +21,7 @@ vim.api.nvim_create_autocmd({ 'BufRead', 'BufNewFile', 'StdinReadPost' }, { -- Generic configuration file used as fallback ft = require('vim.filetype.detect').conf(args.file, args.buf) if ft then - vim.api.nvim_buf_call(args.buf, function() + vim._with({ buf = args.buf }, function() vim.api.nvim_cmd({ cmd = 'setf', args = { 'FALLBACK', ft } }, {}) end) end @@ -32,22 +32,13 @@ vim.api.nvim_create_autocmd({ 'BufRead', 'BufNewFile', 'StdinReadPost' }, { on_detect(args.buf) end - vim.api.nvim_buf_call(args.buf, function() + vim._with({ buf = args.buf }, function() vim.api.nvim_cmd({ cmd = 'setf', args = { ft } }, {}) end) end end, }) --- These *must* be sourced after the autocommand above is created -if not vim.g.did_load_ftdetect then - vim.cmd([[ - augroup filetypedetect - runtime! ftdetect/*.{vim,lua} - augroup END - ]]) -end - -- Set up the autocmd for user scripts.vim vim.api.nvim_create_autocmd({ 'BufRead', 'BufNewFile' }, { group = 'filetypedetect', @@ -62,3 +53,10 @@ vim.api.nvim_create_autocmd('StdinReadPost', { if not vim.g.ft_ignore_pat then vim.g.ft_ignore_pat = '\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$' end + +-- These *must* be sourced after the autocommands above are created +vim.cmd([[ + augroup filetypedetect + runtime! ftdetect/*.{vim,lua} + augroup END +]]) diff --git a/runtime/ftplugin/abaqus.vim b/runtime/ftplugin/abaqus.vim index c16e7b032e..d4bb6fe777 100644 --- a/runtime/ftplugin/abaqus.vim +++ b/runtime/ftplugin/abaqus.vim @@ -3,6 +3,7 @@ " Maintainer: Carl Osterwisch <costerwi@gmail.com> " Last Change: 2022 Oct 08 " 2024 Jan 14 by Vim Project (browsefilter) +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') " Only do this when not done yet for this buffer if exists("b:did_ftplugin") | finish | endif @@ -27,7 +28,7 @@ setlocal isfname-=, " Define format of comment lines (see 'formatoptions' for uses) setlocal comments=:** -setlocal commentstring=**%s +setlocal commentstring=**\ %s " Definitions start with a * and assign a NAME, NSET, or ELSET " Used in [d ^wd and other commands diff --git a/runtime/ftplugin/antlr4.vim b/runtime/ftplugin/antlr4.vim new file mode 100644 index 0000000000..610d5284fb --- /dev/null +++ b/runtime/ftplugin/antlr4.vim @@ -0,0 +1,14 @@ +" Vim filetype plugin +" Language: ANTLR4, ANother Tool for Language Recognition v4 <www.antlr.org> +" Maintainer: Yinzuo Jiang <jiangyinzuo@foxmail.com> +" Last Change: 2024 July 09 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// +setlocal commentstring=//\ %s + +let b:undo_ftplugin = 'setl com< cms<' diff --git a/runtime/ftplugin/arduino.lua b/runtime/ftplugin/arduino.lua new file mode 100644 index 0000000000..89ab42ef54 --- /dev/null +++ b/runtime/ftplugin/arduino.lua @@ -0,0 +1,3 @@ +vim.bo.commentstring = '// %s' + +vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<' diff --git a/runtime/ftplugin/arduino.vim b/runtime/ftplugin/arduino.vim index dae3dd83d3..60b11dab1a 100644 --- a/runtime/ftplugin/arduino.vim +++ b/runtime/ftplugin/arduino.vim @@ -3,6 +3,7 @@ " Maintainer: The Vim Project <https://github.com/vim/vim> " Ken Takata <https://github.com/k-takata> " Last Change: 2024 Apr 12 +" 2024 Jun 02 by Riley Bruins <ribru17@gmail.com> ('commentstring') " " Most of the part was copied from c.vim. @@ -32,7 +33,7 @@ setlocal fo-=t fo+=croql " These options have the right value as default, but the user may have " overruled that. -setlocal commentstring& define& include& +setlocal commentstring=/*\ %s\ */ define& include& " Set completion with CTRL-X CTRL-O to autoloaded function. if exists('&ofu') diff --git a/runtime/ftplugin/asm.vim b/runtime/ftplugin/asm.vim index 0ae1610394..4482b90d0b 100644 --- a/runtime/ftplugin/asm.vim +++ b/runtime/ftplugin/asm.vim @@ -4,13 +4,14 @@ " Last Change: 2020 May 23 " 2023 Aug 28 by Vim Project (undo_ftplugin) " 2024 Apr 09 by Vim Project (add Matchit support) +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") | finish | endif let b:did_ftplugin = 1 setl include=^\\s*%\\s*include setl comments=:;,s1:/*,mb:*,ex:*/,:// -setl commentstring=;%s +setl commentstring=;\ %s let b:undo_ftplugin = "setl commentstring< comments< include<" diff --git a/runtime/ftplugin/astro.vim b/runtime/ftplugin/astro.vim index 0b0e03447b..5d35ba9624 100644 --- a/runtime/ftplugin/astro.vim +++ b/runtime/ftplugin/astro.vim @@ -2,6 +2,7 @@ " Language: Astro " Maintainer: Romain Lafourcade <romainlafourcade@gmail.com> " Last Change: 2024 Apr 21 +" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") finish @@ -25,17 +26,17 @@ function! s:AstroComments() abort \ || s:IdentifyScope('^\s*<script', '^\s*<\/script>') " ECMAScript comments setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// - setlocal commentstring=//%s + setlocal commentstring=//\ %s elseif s:IdentifyScope('^\s*<style', '^\s*<\/style>') " CSS comments setlocal comments=s1:/*,mb:*,ex:*/ - setlocal commentstring=/*%s*/ + setlocal commentstring=/*\ %s\ */ else " HTML comments setlocal comments=s:<!--,m:\ \ \ \ ,e:--> - setlocal commentstring=<!--%s--> + setlocal commentstring=<!--\ %s\ --> endif endfunction diff --git a/runtime/ftplugin/asy.vim b/runtime/ftplugin/asy.vim new file mode 100644 index 0000000000..76bd69d202 --- /dev/null +++ b/runtime/ftplugin/asy.vim @@ -0,0 +1,14 @@ +" Vim filetype plugin +" Language: Asymptote +" Maintainer: AvidSeeker <avidseeker7@protonmail.com> +" Last Change: 2024 Jul 13 +" + +if exists("b:did_ftplugin") + finish +endif +let g:did_ftplugin = 1 + +setlocal commentstring=/*\ %s\ */ + +let b:undo_ftplugin = "setl commentstring<" diff --git a/runtime/ftplugin/autohotkey.vim b/runtime/ftplugin/autohotkey.vim new file mode 100644 index 0000000000..9cb4fd7fdf --- /dev/null +++ b/runtime/ftplugin/autohotkey.vim @@ -0,0 +1,16 @@ +" Vim filetype plugin file +" Language: AutoHotkey +" Maintainer: Peter Aronoff <peteraronoff@fastmail.com> +" Last Changed: 2024 Jul 25 + +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin = 1 + +setlocal comments=:; +setlocal commentstring=;\ %s + +let b:undo_ftplugin = "setlocal comments< commentstring<" + +" vim: nowrap sw=2 sts=2 ts=8 noet: diff --git a/runtime/ftplugin/bindzone.vim b/runtime/ftplugin/bindzone.vim new file mode 100644 index 0000000000..f9e5f4ba3c --- /dev/null +++ b/runtime/ftplugin/bindzone.vim @@ -0,0 +1,16 @@ +" Vim filetype plugin file +" Language: bind zone file +" Maintainer: This runtime file is looking for a new maintainer. +" Last Change: 2024 Jul 06 + +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin=1 + +setlocal comments=b:; +setlocal commentstring=;\ %s +setlocal formatoptions-=t +setlocal formatoptions+=crq + +let b:undo_ftplugin = "setlocal com< cms< fo<" diff --git a/runtime/ftplugin/bitbake.vim b/runtime/ftplugin/bitbake.vim index 99fe334627..4d50a7feb7 100644 --- a/runtime/ftplugin/bitbake.vim +++ b/runtime/ftplugin/bitbake.vim @@ -3,13 +3,14 @@ " Maintainer: Gregory Anders <greg@gpanders.com> " Repository: https://github.com/openembedded/bitbake " Latest Revision: 2022-07-23 +" 2024-05-23 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") finish endif let b:did_ftplugin = 1 -setlocal commentstring=#%s +setlocal commentstring=#\ %s setlocal comments=:# setlocal suffixesadd=.bb,.bbclass diff --git a/runtime/ftplugin/c.lua b/runtime/ftplugin/c.lua index 0ddbf09470..09e286201b 100644 --- a/runtime/ftplugin/c.lua +++ b/runtime/ftplugin/c.lua @@ -1,5 +1,5 @@ -- These are the default option values in Vim, but not in Nvim, so must be set explicitly. -vim.bo.commentstring = '/*%s*/' +vim.bo.commentstring = '// %s' vim.bo.define = '^\\s*#\\s*define' vim.bo.include = '^\\s*#\\s*include' @@ -11,4 +11,4 @@ if vim.fn.isdirectory('/usr/include') == 1 then ]]) end -vim.b.undo_ftplugin = vim.b.undo_ftplugin .. '|setl path<' +vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring< define< include< path<' diff --git a/runtime/ftplugin/c.vim b/runtime/ftplugin/c.vim index 716b454675..8b2b784eb4 100644 --- a/runtime/ftplugin/c.vim +++ b/runtime/ftplugin/c.vim @@ -2,6 +2,7 @@ " Language: C " Maintainer: The Vim Project <https://github.com/vim/vim> " Last Change: 2023 Aug 22 +" 2024 Jun 02 by Riley Bruins <ribru17@gmail.com> ('commentstring') " Former Maintainer: Bram Moolenaar <Bram@vim.org> " Only do this when not done yet for this buffer @@ -24,7 +25,7 @@ setlocal fo-=t fo+=croql " These options have the right value as default, but the user may have " overruled that. -setlocal commentstring& define& include& +setlocal commentstring=/*\ %s\ */ define& include& " Set completion with CTRL-X CTRL-O to autoloaded function. if exists('&ofu') diff --git a/runtime/ftplugin/cabal.vim b/runtime/ftplugin/cabal.vim new file mode 100644 index 0000000000..5ccfa1df70 --- /dev/null +++ b/runtime/ftplugin/cabal.vim @@ -0,0 +1,13 @@ +" Vim filetype plugin file +" Language: Haskell Cabal Build file +" Maintainer: Riley Bruins <ribru17@gmail.com> +" Last Change: 2024 Jul 06 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +setl comments=:-- commentstring=--\ %s + +let b:undo_ftplugin = 'setl com< cms<' diff --git a/runtime/ftplugin/calendar.vim b/runtime/ftplugin/calendar.vim index f454ba1dc8..c4e683acf6 100644 --- a/runtime/ftplugin/calendar.vim +++ b/runtime/ftplugin/calendar.vim @@ -2,6 +2,7 @@ " Language: calendar(1) input file " Previous Maintainer: Nikolai Weibull <now@bitwi.se> " Latest Revision: 2008-07-09 +" 2024-06-02 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") finish @@ -13,7 +14,7 @@ set cpo&vim let b:undo_ftplugin = "setl com< cms< inc< fo<" -setlocal comments=s1:/*,mb:*,ex:*/ commentstring& include& +setlocal comments=s1:/*,mb:*,ex:*/ commentstring=/*\ %s\ */ include& setlocal formatoptions-=t formatoptions+=croql let &cpo = s:cpo_save diff --git a/runtime/ftplugin/calender.lua b/runtime/ftplugin/calender.lua deleted file mode 100644 index b4e68148f5..0000000000 --- a/runtime/ftplugin/calender.lua +++ /dev/null @@ -1 +0,0 @@ -vim.bo.commentstring = '/*%s*/' diff --git a/runtime/ftplugin/cedar.vim b/runtime/ftplugin/cedar.vim new file mode 100644 index 0000000000..74a1903b46 --- /dev/null +++ b/runtime/ftplugin/cedar.vim @@ -0,0 +1,13 @@ +" Vim filetype plugin +" Language: Cedar +" Maintainer: Riley Bruins <ribru17@gmail.com> +" Last Change: 2024 Jul 4 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +setl comments=:// commentstring=//\ %s + +let b:undo_ftplugin = 'setl com< cms<' diff --git a/runtime/ftplugin/cgdbrc.vim b/runtime/ftplugin/cgdbrc.vim index 46cf135c5c..99f9702d26 100644 --- a/runtime/ftplugin/cgdbrc.vim +++ b/runtime/ftplugin/cgdbrc.vim @@ -3,6 +3,7 @@ " Maintainer: Wu, Zhenyu <wuzhenyu@ustc.edu> " Documentation: https://cgdb.github.io/docs/Configuring-CGDB.html " Latest Revision: 2024-04-09 +" 2024-05-23 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists('b:did_ftplugin') finish @@ -14,7 +15,7 @@ set cpoptions&vim let b:undo_ftplugin = 'setl com< cms<' -setlocal commentstring=#%s +setlocal commentstring=#\ %s setlocal comments=:# let &cpoptions = s:save_cpoptions diff --git a/runtime/ftplugin/ch.lua b/runtime/ftplugin/ch.lua new file mode 100644 index 0000000000..89ab42ef54 --- /dev/null +++ b/runtime/ftplugin/ch.lua @@ -0,0 +1,3 @@ +vim.bo.commentstring = '// %s' + +vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<' diff --git a/runtime/ftplugin/chicken.vim b/runtime/ftplugin/chicken.vim index 84d45bae1e..b12b264f6e 100644 --- a/runtime/ftplugin/chicken.vim +++ b/runtime/ftplugin/chicken.vim @@ -1,12 +1,12 @@ " CHICKEN-specific Vim customizations -" Last Change: 2018-03-05 -" Author: Evan Hanson <evhan@foldling.org> -" Maintainer: Evan Hanson <evhan@foldling.org> -" Repository: https://git.foldling.org/vim-scheme.git -" URL: https://foldling.org/vim/ftplugin/chicken.vim -" Notes: These are supplemental settings, to be loaded after the core -" Scheme ftplugin file (ftplugin/scheme.vim). Enable it by setting -" b:is_chicken=1 and filetype=scheme. +" Last Change: 2024 Jun 21 +" Author: Evan Hanson <evhan@foldling.org> +" Maintainer: Evan Hanson <evhan@foldling.org> +" Repository: https://git.foldling.org/vim-scheme.git +" URL: https://foldling.org/vim/ftplugin/chicken.vim +" Notes: These are supplemental settings, to be loaded after the +" core Scheme ftplugin file (ftplugin/scheme.vim). Enable +" it by setting b:is_chicken=1 and filetype=scheme. if !exists('b:did_scheme_ftplugin') finish diff --git a/runtime/ftplugin/cmakecache.vim b/runtime/ftplugin/cmakecache.vim new file mode 100644 index 0000000000..6753cd284a --- /dev/null +++ b/runtime/ftplugin/cmakecache.vim @@ -0,0 +1,13 @@ +" Vim filetype plugin +" Language: cmakecache - CMakeCache.txt files generated by CMake +" Maintainer: Riley Bruins <ribru17@gmail.com> +" Last Change: 2024 Jul 06 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +setl comments=:#,:// commentstring=//\ %s + +let b:undo_ftplugin = 'setl com< cms<' diff --git a/runtime/ftplugin/context.vim b/runtime/ftplugin/context.vim index 37f7240d7b..ed6b5fa672 100644 --- a/runtime/ftplugin/context.vim +++ b/runtime/ftplugin/context.vim @@ -12,10 +12,6 @@ let b:did_ftplugin = 1 let s:cpo_save = &cpo set cpo&vim -if !exists('current_compiler') - compiler context -endif - let b:undo_ftplugin = "setl com< cms< def< inc< sua< fo< ofu<" setlocal comments=b:%D,b:%C,b:%M,:% commentstring=%\ %s formatoptions+=tjcroql2 @@ -108,6 +104,12 @@ if get(g:, 'context_mappings', 1) endif endif +if !exists('current_compiler') + let b:undo_ftplugin ..= "| compiler make" + compiler context +endif + +let b:undo_ftplugin ..= "| sil! delc -buffer ConTeXt | sil! delc -buffer ConTeXtLog | sil! delc -buffer ConTeXtJobStatus | sil! delc -buffer ConTeXtStopJobs" " Commands for asynchronous typesetting command! -buffer -nargs=? -complete=file ConTeXt call context#typeset(<q-args>) command! -nargs=0 ConTeXtJobStatus call context#job_status() diff --git a/runtime/ftplugin/cpp.vim b/runtime/ftplugin/cpp.vim index d4931a2533..73768bc592 100644 --- a/runtime/ftplugin/cpp.vim +++ b/runtime/ftplugin/cpp.vim @@ -1,7 +1,7 @@ " Vim filetype plugin file " Language: C++ " Maintainer: The Vim Project <https://github.com/vim/vim> -" Last Change: 2023 Aug 10 +" Last Change: 2024 Jun 06 " Former Maintainer: Bram Moolenaar <Bram@vim.org> " Only do this when not done yet for this buffer @@ -10,7 +10,12 @@ if exists("b:did_ftplugin") endif " Behaves mostly just like C -runtime! ftplugin/c.{vim,lua} ftplugin/c_*.{vim,lua} ftplugin/c/*.{vim,lua} +" XXX: "[.]" in the first pattern makes it a wildcard on Windows +runtime! ftplugin/c[.]{vim,lua} ftplugin/c_*.{vim,lua} ftplugin/c/*.{vim,lua} + +" Change 'commentstring' to "C++ style"/"mono-line" comments +setlocal commentstring=//\ %s +let b:undo_ftplugin ..= ' | setl commentstring<' " C++ uses templates with <things> " Disabled, because it gives an error for typing an unmatched ">". diff --git a/runtime/ftplugin/cs.lua b/runtime/ftplugin/cs.lua index b4e68148f5..89ab42ef54 100644 --- a/runtime/ftplugin/cs.lua +++ b/runtime/ftplugin/cs.lua @@ -1 +1,3 @@ -vim.bo.commentstring = '/*%s*/' +vim.bo.commentstring = '// %s' + +vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<' diff --git a/runtime/ftplugin/csh.vim b/runtime/ftplugin/csh.vim index a22bee3279..74666b9680 100644 --- a/runtime/ftplugin/csh.vim +++ b/runtime/ftplugin/csh.vim @@ -4,6 +4,7 @@ " Previous Maintainer: Dan Sharp " Contributor: Johannes Zellner <johannes@zellner.org> " Last Change: 2024 Jan 14 +" 2024 May 23 by Riley Bruins ('commentstring') if exists("b:did_ftplugin") finish @@ -14,7 +15,7 @@ let s:save_cpo = &cpo set cpo-=C setlocal comments=:# -setlocal commentstring=#%s +setlocal commentstring=#\ %s setlocal formatoptions-=t setlocal formatoptions+=crql diff --git a/runtime/ftplugin/css.lua b/runtime/ftplugin/css.lua deleted file mode 100644 index b4e68148f5..0000000000 --- a/runtime/ftplugin/css.lua +++ /dev/null @@ -1 +0,0 @@ -vim.bo.commentstring = '/*%s*/' diff --git a/runtime/ftplugin/css.vim b/runtime/ftplugin/css.vim index ece2def4ee..778a9e12d6 100644 --- a/runtime/ftplugin/css.vim +++ b/runtime/ftplugin/css.vim @@ -3,6 +3,7 @@ " Maintainer: Doug Kearns <dougkearns@gmail.com> " Previous Maintainer: Nikolai Weibull <now@bitwi.se> " Last Change: 2020 Dec 21 +" 2024 Jun 02 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") finish @@ -14,7 +15,7 @@ set cpo&vim let b:undo_ftplugin = "setl com< cms< inc< fo< ofu< isk<" -setlocal comments=s1:/*,mb:*,ex:*/ commentstring& +setlocal comments=s1:/*,mb:*,ex:*/ commentstring=/*\ %s\ */ setlocal formatoptions-=t formatoptions+=croql setlocal omnifunc=csscomplete#CompleteCSS setlocal iskeyword+=- diff --git a/runtime/ftplugin/csv.vim b/runtime/ftplugin/csv.vim new file mode 100644 index 0000000000..60412ee527 --- /dev/null +++ b/runtime/ftplugin/csv.vim @@ -0,0 +1,22 @@ +" Maintainer: Maxim Kim <habamax@gmail.com> +" Converted from vim9script +" Last Update: 2024-06-18 + +if !exists("b:csv_delimiter") + " detect delimiter + let s:delimiters = ",;\t|" + + let s:max = 0 + for s:d in s:delimiters + let s:count = getline(1)->split(s:d)->len() + getline(2)->split(s:d)->len() + if s:count > s:max + let s:max = s:count + let b:csv_delimiter = s:d + endif + endfor +endif + +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin = 1 diff --git a/runtime/ftplugin/cuda.vim b/runtime/ftplugin/cuda.vim new file mode 100644 index 0000000000..91d722b649 --- /dev/null +++ b/runtime/ftplugin/cuda.vim @@ -0,0 +1,11 @@ +" Vim filetype plugin +" Language: CUDA +" Maintainer: Riley Bruins <ribru17@gmail.com> +" Last Change: 2024 Jul 29 + +if exists('b:did_ftplugin') + finish +endif + +" Behaves mostly just like C++ +runtime! ftplugin/cpp.vim diff --git a/runtime/ftplugin/d.lua b/runtime/ftplugin/d.lua index b4e68148f5..89ab42ef54 100644 --- a/runtime/ftplugin/d.lua +++ b/runtime/ftplugin/d.lua @@ -1 +1,3 @@ -vim.bo.commentstring = '/*%s*/' +vim.bo.commentstring = '// %s' + +vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<' diff --git a/runtime/ftplugin/deb822sources.vim b/runtime/ftplugin/deb822sources.vim index 4936f42bf9..31c81b1a5d 100644 --- a/runtime/ftplugin/deb822sources.vim +++ b/runtime/ftplugin/deb822sources.vim @@ -1,6 +1,6 @@ " Language: Debian sources.list " Maintainer: Debian Vim Maintainers <team+vim@tracker.debian.org> -" Last Change: 2024 Mar 20 +" Last Change: 2024 May 25 " License: Vim License " URL: https://salsa.debian.org/vim-team/vim-debian/blob/main/ftplugin/deb822sources.vim @@ -10,7 +10,7 @@ endif let b:did_ftplugin=1 setlocal comments=:# -setlocal commentstring=#%s +setlocal commentstring=#\ %s setlocal formatoptions-=t let b:undo_ftplugin = 'setlocal comments< commentstring< formatoptions<' diff --git a/runtime/ftplugin/debcontrol.vim b/runtime/ftplugin/debcontrol.vim index bb710e597c..5b8292ba6e 100644 --- a/runtime/ftplugin/debcontrol.vim +++ b/runtime/ftplugin/debcontrol.vim @@ -2,7 +2,7 @@ " Language: Debian control files " Maintainer: Debian Vim Maintainers " Former Maintainer: Pierre Habouzit <madcoder@debian.org> -" Last Change: 2023 Jan 16 +" Last Change: 2024 May 25 " URL: https://salsa.debian.org/vim-team/vim-debian/blob/main/ftplugin/debcontrol.vim " Do these settings once per buffer @@ -19,8 +19,11 @@ if exists('g:debcontrol_fold_enable') endif setlocal textwidth=0 +setlocal comments=:# +setlocal commentstring=#\ %s + " Clean unloading -let b:undo_ftplugin = 'setlocal tw< foldmethod< foldexpr< foldtext<' +let b:undo_ftplugin = 'setlocal tw< foldmethod< foldexpr< foldtext< comments< commentstring<' " }}}1 diff --git a/runtime/ftplugin/debsources.vim b/runtime/ftplugin/debsources.vim index cbb4fafd22..2c5ea3599f 100644 --- a/runtime/ftplugin/debsources.vim +++ b/runtime/ftplugin/debsources.vim @@ -1,6 +1,6 @@ " Language: Debian sources.list " Maintainer: Debian Vim Maintainers <team+vim@tracker.debian.org> -" Last Change: 2023 Aug 30 +" Last Change: 2024 May 25 " License: Vim License " URL: https://salsa.debian.org/vim-team/vim-debian/blob/main/ftplugin/debsources.vim @@ -10,7 +10,7 @@ endif let b:did_ftplugin=1 setlocal comments=:# -setlocal commentstring=#%s +setlocal commentstring=#\ %s setlocal formatoptions-=t let b:undo_ftplugin = 'setlocal comments< commentstring< formatoptions<' diff --git a/runtime/ftplugin/desktop.vim b/runtime/ftplugin/desktop.vim index bd6fd7097c..d15afd24b9 100644 --- a/runtime/ftplugin/desktop.vim +++ b/runtime/ftplugin/desktop.vim @@ -2,6 +2,7 @@ " Language: XDG desktop entry " Maintainer: Eisuke Kawashima ( e.kawaschima+vim AT gmail.com ) " Last Change: 2022-07-26 +" 2024-05-24 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists('b:did_ftplugin') finish @@ -9,5 +10,5 @@ endif let b:did_ftplugin = v:true setl comments=:# -setl commentstring=#%s +setl commentstring=#\ %s let b:undo_ftplugin = 'setl com< cms<' diff --git a/runtime/ftplugin/dot.lua b/runtime/ftplugin/dot.lua new file mode 100644 index 0000000000..89ab42ef54 --- /dev/null +++ b/runtime/ftplugin/dot.lua @@ -0,0 +1,3 @@ +vim.bo.commentstring = '// %s' + +vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<' diff --git a/runtime/ftplugin/dtd.vim b/runtime/ftplugin/dtd.vim index bea8c5c18a..f97014814b 100644 --- a/runtime/ftplugin/dtd.vim +++ b/runtime/ftplugin/dtd.vim @@ -6,6 +6,7 @@ " Former maintainer: Dan Sharp " Last Change: 2009 Jan 20 " 2024 Jan 14 by Vim Project (browsefilter) +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") | finish | endif let b:did_ftplugin = 1 @@ -15,7 +16,7 @@ let b:did_ftplugin = 1 let s:save_cpo = &cpo set cpo-=C -setlocal commentstring=<!--%s--> +setlocal commentstring=<!--\ %s\ --> setlocal comments=s:<!--,m:\ \ \ \ \ ,e:--> setlocal formatoptions-=t diff --git a/runtime/ftplugin/dtrace.vim b/runtime/ftplugin/dtrace.vim index 9288097f7f..a276b310a3 100644 --- a/runtime/ftplugin/dtrace.vim +++ b/runtime/ftplugin/dtrace.vim @@ -1,6 +1,7 @@ " Language: D script as described in "Solaris Dynamic Tracing Guide", " http://docs.sun.com/app/docs/doc/817-6223 " Last Change: 2008/03/20 +" 2024/05/23 by Riley Bruins <ribru17@gmail.com ('commentstring') " Version: 1.2 " Maintainer: Nicolas Weber <nicolasweber@gmx.de> @@ -26,8 +27,8 @@ setlocal fo-=t fo+=croql setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/ " dtrace uses /* */ comments. Set this explicitly, just in case the user -" changed this (/*%s*/ is the default) -setlocal commentstring=/*%s*/ +" changed this (/*\ %s\ */ is the default) +setlocal commentstring=/*\ %s\ */ setlocal iskeyword+=@,$ diff --git a/runtime/ftplugin/dts.vim b/runtime/ftplugin/dts.vim index 42e38338b7..346ff94704 100644 --- a/runtime/ftplugin/dts.vim +++ b/runtime/ftplugin/dts.vim @@ -2,6 +2,7 @@ " Language: dts/dtsi (device tree files) " Maintainer: Wu, Zhenyu <wuzhenyu@ustc.edu> " Latest Revision: 2024 Apr 12 +" 2024 Jun 02 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists('b:did_ftplugin') finish @@ -12,5 +13,5 @@ let b:undo_ftplugin = 'setl inc< cms< com<' setlocal include=^\\%(#include\\\|/include/\\) " same as C -setlocal commentstring& +setlocal commentstring=/*\ %s\ */ setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:///,:// diff --git a/runtime/ftplugin/editorconfig.vim b/runtime/ftplugin/editorconfig.vim new file mode 100644 index 0000000000..6d437351eb --- /dev/null +++ b/runtime/ftplugin/editorconfig.vim @@ -0,0 +1,13 @@ +" Vim filetype plugin +" Language: EditorConfig +" Maintainer: Riley Bruins <ribru17@gmail.com> +" Last Change: 2024 Jul 06 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +setl comments=:#,:; commentstring=#\ %s + +let b:undo_ftplugin = 'setl com< cms<' diff --git a/runtime/ftplugin/erlang.vim b/runtime/ftplugin/erlang.vim index 1cb57f4c85..5a3ab717d9 100644 --- a/runtime/ftplugin/erlang.vim +++ b/runtime/ftplugin/erlang.vim @@ -6,7 +6,8 @@ " Eduardo Lopez (http://github.com/tapichu) " Arvid Bjurklint (http://github.com/slarwise) " PaweÅ‚ Zacharek (http://github.com/subc2) -" Last Update: 2023-Dec-20 +" Riley Bruins (http://github.com/ribru17) ('commentstring') +" Last Update: 2024 May 23 " License: Vim license " URL: https://github.com/vim-erlang/vim-erlang-runtime @@ -27,7 +28,7 @@ if get(g:, 'erlang_folding', 0) endif setlocal comments=:%%%,:%%,:% -setlocal commentstring=%%s +setlocal commentstring=%\ %s setlocal formatoptions+=ro diff --git a/runtime/ftplugin/eruby.vim b/runtime/ftplugin/eruby.vim index b5c4665d24..b3e074aa20 100644 --- a/runtime/ftplugin/eruby.vim +++ b/runtime/ftplugin/eruby.vim @@ -5,6 +5,7 @@ " Release Coordinator: Doug Kearns <dougkearns@gmail.com> " Last Change: 2022 May 15 " 2024 Jan 14 by Vim Project (browsefilter) +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') " Only do this when not done yet for this buffer if exists("b:did_ftplugin") @@ -125,7 +126,7 @@ if exists("loaded_matchit") endif " TODO: comments= -setlocal commentstring=<%#%s%> +setlocal commentstring=<%#\ %s\ %> let b:undo_ftplugin = "setl cms< " . \ " | unlet! b:browsefilter b:match_words | " . b:undo_ftplugin diff --git a/runtime/ftplugin/faust.lua b/runtime/ftplugin/faust.lua new file mode 100644 index 0000000000..89ab42ef54 --- /dev/null +++ b/runtime/ftplugin/faust.lua @@ -0,0 +1,3 @@ +vim.bo.commentstring = '// %s' + +vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<' diff --git a/runtime/ftplugin/fennel.vim b/runtime/ftplugin/fennel.vim index 93cf366726..2a9623faff 100644 --- a/runtime/ftplugin/fennel.vim +++ b/runtime/ftplugin/fennel.vim @@ -2,13 +2,14 @@ " Language: Fennel " Maintainer: Gregory Anders <greg[NOSPAM]@gpanders.com> " Last Update: 2023 Jun 9 +" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists('b:did_ftplugin') finish endif let b:did_ftplugin = 1 -setlocal commentstring=;%s +setlocal commentstring=;\ %s setlocal comments=:;;,:; setlocal formatoptions-=t setlocal suffixesadd=.fnl diff --git a/runtime/ftplugin/fish.vim b/runtime/ftplugin/fish.vim index f06ad3a0bf..55d7ea8dd9 100644 --- a/runtime/ftplugin/fish.vim +++ b/runtime/ftplugin/fish.vim @@ -4,6 +4,7 @@ " Repository: https://github.com/nickeb96/fish.vim " Last Change: February 1, 2023 " 2023 Aug 28 by Vim Project (undo_ftplugin) +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") finish @@ -12,7 +13,7 @@ let b:did_ftplugin = 1 setlocal iskeyword=@,48-57,_,192-255,-,. setlocal comments=:# -setlocal commentstring=#%s +setlocal commentstring=#\ %s setlocal formatoptions+=crjq let b:undo_ftplugin = "setl cms< com< fo< isk<" diff --git a/runtime/ftplugin/fortran.vim b/runtime/ftplugin/fortran.vim index 3c325818d3..19a4c1e62b 100644 --- a/runtime/ftplugin/fortran.vim +++ b/runtime/ftplugin/fortran.vim @@ -11,6 +11,7 @@ " Doug Kearns, and Fritz Reese. " Last Change: 2023 Dec 22 " 2024 Jan 14 by Vim Project (browsefilter) +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') " Only do these settings when not done yet for this buffer if exists("b:did_ftplugin") @@ -89,7 +90,7 @@ else endif " Set commentstring for foldmethod=marker -setlocal cms=!%s +setlocal cms=!\ %s " Tabs are not a good idea in Fortran so the default is to expand tabs if !exists("fortran_have_tabs") diff --git a/runtime/ftplugin/fstab.vim b/runtime/ftplugin/fstab.vim index 99805322cd..0e7ffda498 100644 --- a/runtime/ftplugin/fstab.vim +++ b/runtime/ftplugin/fstab.vim @@ -3,6 +3,7 @@ " Maintainer: Radu Dineiu <radu.dineiu@gmail.com> " URL: https://raw.github.com/rid9/vim-fstab/master/ftplugin/fstab.vim " Last Change: 2021 Jan 02 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') " Version: 1.0 " " Credits: @@ -13,7 +14,7 @@ if exists("b:did_ftplugin") endif let b:did_ftplugin = 1 -setlocal commentstring=#%s +setlocal commentstring=#\ %s let b:undo_ftplugin = "setlocal commentstring<" " vim: ts=8 ft=vim diff --git a/runtime/ftplugin/gdb.vim b/runtime/ftplugin/gdb.vim index 7c10633be4..af88a04d54 100644 --- a/runtime/ftplugin/gdb.vim +++ b/runtime/ftplugin/gdb.vim @@ -3,11 +3,12 @@ " Maintainer: Michaël Peeters <NOSPAMm.vim@noekeon.org> " Last Changed: 2017-10-26 " 2024-04-10: - add Matchit support (by Vim Project) +" 2024-04-23: - add space to commentstring (by Riley Bruins) ('commentstring') if exists("b:did_ftplugin") | finish | endif let b:did_ftplugin = 1 -setlocal commentstring=#%s +setlocal commentstring=#\ %s setlocal include=^\\s*source " Undo the stuff we changed. diff --git a/runtime/ftplugin/gdscript.vim b/runtime/ftplugin/gdscript.vim index 692afdd0ea..8869c9a019 100644 --- a/runtime/ftplugin/gdscript.vim +++ b/runtime/ftplugin/gdscript.vim @@ -25,6 +25,11 @@ setlocal commentstring=#\ %s setlocal foldignore= setlocal foldexpr=s:GDScriptFoldLevel() +if get(g:, 'gdscript_recommended_style', 1) + setlocal noexpandtab tabstop=4 softtabstop=0 shiftwidth=0 + let b:undo_ftplugin ..= ' | setlocal expandtab< tabstop< softtabstop< shiftwidth<' +endif + function s:GDScriptFoldLevel() abort let line = getline(v:lnum) diff --git a/runtime/ftplugin/glsl.lua b/runtime/ftplugin/glsl.lua new file mode 100644 index 0000000000..89ab42ef54 --- /dev/null +++ b/runtime/ftplugin/glsl.lua @@ -0,0 +1,3 @@ +vim.bo.commentstring = '// %s' + +vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<' diff --git a/runtime/ftplugin/go.vim b/runtime/ftplugin/go.vim index 61dc1a13b7..75f78cfa4b 100644 --- a/runtime/ftplugin/go.vim +++ b/runtime/ftplugin/go.vim @@ -2,6 +2,7 @@ " Language: Go " Maintainer: David Barnett (https://github.com/google/vim-ft-go) " Last Change: 2014 Aug 16 +" 2024 Jul 16 by Vim Project (add recommended indent style) if exists('b:did_ftplugin') finish @@ -15,4 +16,9 @@ setlocal commentstring=//\ %s let b:undo_ftplugin = 'setl fo< com< cms<' +if get(g:, 'go_recommended_style', 1) + setlocal noexpandtab softtabstop=0 shiftwidth=0 + let b:undo_ftplugin ..= ' | setl et< sts< sw<' +endif + " vim: sw=2 sts=2 et diff --git a/runtime/ftplugin/goaccess.vim b/runtime/ftplugin/goaccess.vim new file mode 100644 index 0000000000..fb557300c9 --- /dev/null +++ b/runtime/ftplugin/goaccess.vim @@ -0,0 +1,14 @@ +" Vim filetype plugin +" Language: GoAccess configuration +" Maintainer: Adam Monsen <haircut@gmail.com> +" Last Change: 2024 Aug 1 + +if exists('b:did_ftplugin') + finish +endif + +let b:did_ftplugin = 1 + +setl comments=:# commentstring=#\ %s + +let b:undo_ftplugin = 'setl com< cms<' diff --git a/runtime/ftplugin/gomod.vim b/runtime/ftplugin/gomod.vim new file mode 100644 index 0000000000..554c948eb0 --- /dev/null +++ b/runtime/ftplugin/gomod.vim @@ -0,0 +1,16 @@ +" Vim filetype plugin file +" Language: go module file +" Maintainer: YU YUK KUEN <yukkuen.yu719@gmail.com> +" Last Change: 2024-06-21 +" 2024 Jul 16 by Vim Project (noexpandtab) + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +setlocal noexpandtab +setlocal formatoptions-=t formatoptions-=c +setlocal commentstring=//\ %s + +let b:undo_ftplugin = 'setl et< fo< cms<' diff --git a/runtime/ftplugin/gpg.vim b/runtime/ftplugin/gpg.vim index 7fb4f47ed8..bb4e0c9a19 100644 --- a/runtime/ftplugin/gpg.vim +++ b/runtime/ftplugin/gpg.vim @@ -1,7 +1,7 @@ " Vim filetype plugin file " Language: gpg(1) configuration file " Previous Maintainer: Nikolai Weibull <now@bitwi.se> -" Latest Revision: 2023-10-07 +" Latest Revision: 2024-09-19 (simplify keywordprg #15696) if exists("b:did_ftplugin") finish @@ -15,20 +15,12 @@ let b:undo_ftplugin = "setl com< cms< fo<" setlocal comments=:# commentstring=#\ %s formatoptions-=t formatoptions+=croql -if has('unix') && executable('less') - if !has('gui_running') - command -buffer -nargs=1 GpgKeywordPrg - \ silent exe '!' . 'LESS= MANPAGER="less --pattern=''^\s+--' . <q-args> . '\b'' --hilite-search" man ' . 'gpg' | - \ redraw! - elseif has('terminal') - command -buffer -nargs=1 GpgKeywordPrg - \ silent exe ':term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+--' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'gpg' - endif - if exists(':GpgKeywordPrg') == 2 - setlocal iskeyword+=- - setlocal keywordprg=:GpgKeywordPrg - let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer GpgKeywordPrg' - endif +if has('unix') && executable('less') && exists(':terminal') == 2 + command -buffer -nargs=1 GpgKeywordPrg + \ silent exe ':term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+--' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'gpg' + setlocal iskeyword+=- + setlocal keywordprg=:GpgKeywordPrg + let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer GpgKeywordPrg' endif let &cpo = s:cpo_save diff --git a/runtime/ftplugin/groovy.vim b/runtime/ftplugin/groovy.vim index cc7d6e35eb..a2e2b2f93e 100644 --- a/runtime/ftplugin/groovy.vim +++ b/runtime/ftplugin/groovy.vim @@ -2,6 +2,7 @@ " Language: groovy " Maintainer: Justin M. Keyes <justinkz@gmail.com> " Last Change: 2016 May 22 +" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists('b:did_ftplugin') finish @@ -13,7 +14,7 @@ set cpo-=C let b:undo_ftplugin = 'setlocal commentstring<' -setlocal commentstring=//%s +setlocal commentstring=//\ %s let &cpo = s:cpo_save unlet s:cpo_save diff --git a/runtime/ftplugin/hamster.vim b/runtime/ftplugin/hamster.vim index 5446e72286..904f267fdc 100644 --- a/runtime/ftplugin/hamster.vim +++ b/runtime/ftplugin/hamster.vim @@ -3,6 +3,7 @@ " Version: 2.0.6.0 " Maintainer: David Fishburn <dfishburn dot vim at gmail dot com> " Last Change: 2021 Jan 19 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') " Only do this when not done yet for this buffer if exists("b:did_ftplugin") @@ -31,7 +32,7 @@ if &tw == 0 endif " Comments start with a double quote -setlocal commentstring=#%s +setlocal commentstring=#\ %s " Move around functions. noremap <silent><buffer> [[ :call search('^\s*sub\>', "bW")<CR> diff --git a/runtime/ftplugin/hare.vim b/runtime/ftplugin/hare.vim index 0200ba5913..6c61c818d1 100644 --- a/runtime/ftplugin/hare.vim +++ b/runtime/ftplugin/hare.vim @@ -1,35 +1,61 @@ -" Vim filetype plugin -" Language: Hare -" Maintainer: Amelia Clarke <me@rsaihe.dev> -" Previous Maintainer: Drew DeVault <sir@cmpwn.com> -" Last Updated: 2022-09-28 -" 2023 Aug 28 by Vim Project (undo_ftplugin) +" Vim filetype plugin. +" Language: Hare +" Maintainer: Amelia Clarke <selene@perilune.dev> +" Last Updated: 2024 Oct 04 +" Upstream: https://git.sr.ht/~sircmpwn/hare.vim if exists('b:did_ftplugin') finish endif let b:did_ftplugin = 1 -" Formatting settings. -setlocal formatoptions-=t formatoptions+=croql/ +let s:cpo_save = &cpo +set cpo&vim -" Miscellaneous. +" Formatting settings. setlocal comments=:// setlocal commentstring=//\ %s +setlocal formatlistpat=^\ \\?-\ +setlocal formatoptions+=croqnlj/ formatoptions-=t + +" Search for Hare modules. +setlocal include=^\\s*use\\> +setlocal includeexpr=hare#FindModule(v:fname) +setlocal isfname+=: setlocal suffixesadd=.ha -let b:undo_ftplugin = "setl cms< com< fo< sua<" +" Add HAREPATH to the default search paths. +setlocal path-=/usr/include,, +let &l:path .= ',' .. hare#GetPath() .. ',,' + +let b:undo_ftplugin = 'setl cms< com< flp< fo< inc< inex< isf< pa< sua< mp<' -" Hare recommended style. -if get(g:, "hare_recommended_style", 1) +" Follow the Hare style guide by default. +if get(g:, 'hare_recommended_style', 1) setlocal noexpandtab - setlocal shiftwidth=8 + setlocal shiftwidth=0 setlocal softtabstop=0 setlocal tabstop=8 setlocal textwidth=80 - let b:undo_ftplugin ..= " | setl et< sts< sw< ts< tw<" + let b:undo_ftplugin .= ' et< sts< sw< ts< tw<' +endif + +augroup hare.vim + autocmd! + + " Highlight whitespace errors by default. + if get(g:, 'hare_space_error', 1) + autocmd InsertEnter * hi link hareSpaceError NONE + autocmd InsertLeave * hi link hareSpaceError Error + endif +augroup END + +if !exists('current_compiler') + let b:undo_ftplugin .= "| compiler make" + compiler hare endif -compiler hare +let &cpo = s:cpo_save +unlet s:cpo_save -" vim: et sw=2 sts=2 ts=8 +" vim: et sts=2 sw=2 ts=8 diff --git a/runtime/ftplugin/haredoc.vim b/runtime/ftplugin/haredoc.vim new file mode 100644 index 0000000000..69030b47ba --- /dev/null +++ b/runtime/ftplugin/haredoc.vim @@ -0,0 +1,44 @@ +" Vim filetype plugin. +" Language: Haredoc (Hare documentation format) +" Maintainer: Amelia Clarke <selene@perilune.dev> +" Last Updated: 2024-05-02 +" Upstream: https://git.sr.ht/~selene/hare.vim + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +let s:cpo_save = &cpo +set cpo&vim + +" Formatting settings. +setlocal comments=:\ +setlocal formatlistpat=^\ \\?-\ +setlocal formatoptions+=tnlj formatoptions-=c formatoptions-=q + +" Search for Hare modules. +setlocal includeexpr=hare#FindModule(v:fname) +setlocal isfname+=: +setlocal suffixesadd=.ha + +" Add HAREPATH to the default search paths. +setlocal path-=/usr/include,, +let &l:path .= ',' .. hare#GetPath() .. ',,' + +let b:undo_ftplugin = 'setl com< flp< fo< inex< isf< pa< sua<' + +" Follow the Hare style guide by default. +if get(g:, 'hare_recommended_style', 1) + setlocal noexpandtab + setlocal shiftwidth=0 + setlocal softtabstop=0 + setlocal tabstop=8 + setlocal textwidth=80 + let b:undo_ftplugin .= ' et< sts< sw< ts< tw<' +endif + +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim: et sts=2 sw=2 ts=8 diff --git a/runtime/ftplugin/hcl.vim b/runtime/ftplugin/hcl.vim new file mode 100644 index 0000000000..c47a0378d0 --- /dev/null +++ b/runtime/ftplugin/hcl.vim @@ -0,0 +1,10 @@ +" Vim filetype plugin +" Language: HCL +" Maintainer: Gregory Anders +" Last Change: 2024-09-03 + +if exists('b:did_ftplugin') + finish +endif + +runtime! ftplugin/terraform.vim diff --git a/runtime/ftplugin/help.lua b/runtime/ftplugin/help.lua index 67c417b1be..8d991be0e4 100644 --- a/runtime/ftplugin/help.lua +++ b/runtime/ftplugin/help.lua @@ -1,7 +1,7 @@ -- use treesitter over syntax (for highlighted code blocks) vim.treesitter.start() --- add custom highlights for list in `:h highlight-groups` +-- Add custom highlights for list in `:h highlight-groups`. local bufname = vim.fs.normalize(vim.api.nvim_buf_get_name(0)) if vim.endswith(bufname, '/doc/syntax.txt') then require('vim.vimhelp').highlight_groups({ @@ -26,3 +26,10 @@ elseif vim.endswith(bufname, '/doc/lsp.txt') then { start = [[\*lsp-semantic-highlight\*]], stop = '^======', match = '^@[%w%p]+' }, }) end + +vim.keymap.set('n', 'gO', function() + require('vim.vimhelp').show_toc() +end, { buffer = 0, silent = true }) + +vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n exe "nunmap <buffer> gO"' +vim.b.undo_ftplugin = vim.b.undo_ftplugin .. ' | call v:lua.vim.treesitter.stop()' diff --git a/runtime/ftplugin/help.vim b/runtime/ftplugin/help.vim index a188e45cb4..833baf5d8f 100644 --- a/runtime/ftplugin/help.vim +++ b/runtime/ftplugin/help.vim @@ -21,77 +21,5 @@ endif " Prefer Vim help instead of manpages. setlocal keywordprg=:help -if !exists('g:no_plugin_maps') - function! s:show_toc() abort - let bufname = bufname('%') - let info = getloclist(0, {'winid': 1}) - if !empty(info) && getwinvar(info.winid, 'qf_toc') ==# bufname - lopen - return - endif - - let toc = [] - let lnum = 2 - let last_line = line('$') - 1 - let last_added = 0 - let has_section = 0 - let has_sub_section = 0 - - while lnum && lnum <= last_line - let level = 0 - let add_text = '' - let text = getline(lnum) - - if text =~# '^=\+$' && lnum + 1 < last_line - " A de-facto section heading. Other headings are inferred. - let has_section = 1 - let has_sub_section = 0 - let lnum = nextnonblank(lnum + 1) - let text = getline(lnum) - let add_text = text - while add_text =~# '\*[^*]\+\*\s*$' - let add_text = matchstr(add_text, '.*\ze\*[^*]\+\*\s*$') - endwhile - elseif text =~# '^[A-Z0-9][-A-ZA-Z0-9 .][-A-Z0-9 .():]*\%([ \t]\+\*.\+\*\)\?$' - " Any line that's yelling is important. - let has_sub_section = 1 - let level = has_section - let add_text = matchstr(text, '.\{-}\ze\s*\%([ \t]\+\*.\+\*\)\?$') - elseif text =~# '\~$' - \ && matchstr(text, '^\s*\zs.\{-}\ze\s*\~$') !~# '\t\|\s\{2,}' - \ && getline(lnum - 1) =~# '^\s*<\?$\|^\s*\*.*\*$' - \ && getline(lnum + 1) =~# '^\s*>\?$\|^\s*\*.*\*$' - " These lines could be headers or code examples. We only want the - " ones that have subsequent lines at the same indent or more. - let l = nextnonblank(lnum + 1) - if getline(l) =~# '\*[^*]\+\*$' - " Ignore tag lines - let l = nextnonblank(l + 1) - endif - - if indent(lnum) <= indent(l) - let level = has_section + has_sub_section - let add_text = matchstr(text, '\S.\{-}\ze\s\=\~$') - endif - endif - - let add_text = substitute(add_text, '\s\+$', '', 'g') - if !empty(add_text) && last_added != lnum - let last_added = lnum - call add(toc, {'bufnr': bufnr('%'), 'lnum': lnum, - \ 'text': repeat("\u00a0\u00a0", level) . add_text}) - endif - let lnum = nextnonblank(lnum + 1) - endwhile - - call setloclist(0, toc, ' ') - call setloclist(0, [], 'a', {'title': 'Help TOC'}) - lopen - let w:qf_toc = bufname - endfunction - - nnoremap <silent><buffer> gO :call <sid>show_toc()<cr> -endif - let &cpo = s:cpo_save unlet s:cpo_save diff --git a/runtime/ftplugin/hlsplaylist.vim b/runtime/ftplugin/hlsplaylist.vim new file mode 100644 index 0000000000..879a04f0f9 --- /dev/null +++ b/runtime/ftplugin/hlsplaylist.vim @@ -0,0 +1,37 @@ +" Vim filetype plugin +" Language: HLS/M3U Playlist +" Maintainer: AvidSeeker <avidseeker7@protonmail.com> +" Last Change: 2024 Jul 07 +" + +if exists("b:did_ftplugin") + finish +endif +let g:did_ftplugin = 1 + +setlocal commentstring=#%s + +let b:undo_ftplugin = "setl commentstring<" + +function! M3UFold() abort + let line = getline(v:lnum) + if line =~# '^#EXTGRP' + return ">1" + endif + return "=" +endfunction + +function! M3UFoldText() abort + let start_line = getline(v:foldstart) + let title = substitute(start_line, '^#EXTGRP:*', '', '') + let foldsize = (v:foldend - v:foldstart + 1) + let linecount = '['.foldsize.' lines]' + return title.' '.linecount +endfunction + +if has("folding") + setlocal foldexpr=M3UFold() + setlocal foldmethod=expr + setlocal foldtext=M3UFoldText() + let b:undo_ftplugin .= "|setl foldexpr< foldmethod< foldtext<" +endif diff --git a/runtime/ftplugin/html.vim b/runtime/ftplugin/html.vim index 3aa60a873e..5495f859de 100644 --- a/runtime/ftplugin/html.vim +++ b/runtime/ftplugin/html.vim @@ -3,6 +3,7 @@ " Maintainer: Doug Kearns <dougkearns@gmail.com> " Previous Maintainer: Dan Sharp " Last Change: 2024 Jan 14 +" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") finish @@ -13,7 +14,7 @@ let s:save_cpo = &cpo set cpo-=C setlocal matchpairs+=<:> -setlocal commentstring=<!--%s--> +setlocal commentstring=<!--\ %s\ --> setlocal comments=s:<!--,m:\ \ \ \ ,e:--> let b:undo_ftplugin = "setlocal comments< commentstring< matchpairs<" diff --git a/runtime/ftplugin/htmlangular.vim b/runtime/ftplugin/htmlangular.vim new file mode 100644 index 0000000000..b114372442 --- /dev/null +++ b/runtime/ftplugin/htmlangular.vim @@ -0,0 +1,12 @@ +" Vim filetype plugin file +" Language: Angular HTML Template +" Maintainer: Dennis van den Berg <dennis@vdberg.dev> +" Last Change: 2024 Jul 9 + +" Only use this filetype plugin when no other was loaded. +if exists("b:did_ftplugin") + finish +endif + +" source the HTML ftplugin +runtime! ftplugin/html.vim diff --git a/runtime/ftplugin/http.vim b/runtime/ftplugin/http.vim new file mode 100644 index 0000000000..ca5055011b --- /dev/null +++ b/runtime/ftplugin/http.vim @@ -0,0 +1,13 @@ +" Vim filetype plugin +" Language: HTTP +" Maintainer: Riley Bruins <ribru17@gmail.com> +" Last Change: 2024 Sep 28 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +setl comments=:# commentstring=#\ %s + +let b:undo_ftplugin = 'setl com< cms<' diff --git a/runtime/ftplugin/indent.lua b/runtime/ftplugin/indent.lua index b4e68148f5..89ab42ef54 100644 --- a/runtime/ftplugin/indent.lua +++ b/runtime/ftplugin/indent.lua @@ -1 +1,3 @@ -vim.bo.commentstring = '/*%s*/' +vim.bo.commentstring = '// %s' + +vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<' diff --git a/runtime/ftplugin/indent.vim b/runtime/ftplugin/indent.vim index 64a650ad7b..32208d38d8 100644 --- a/runtime/ftplugin/indent.vim +++ b/runtime/ftplugin/indent.vim @@ -3,6 +3,7 @@ " Maintainer: Doug Kearns <dougkearns@gmail.com> " Previous Maintainer: Nikolai Weibull <now@bitwi.se> " Latest Revision: 2008-07-09 +" 2024-06-02 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") finish @@ -14,7 +15,7 @@ set cpo&vim let b:undo_ftplugin = "setl com< cms< fo<" -setlocal comments=s1:/*,mb:*,ex:*/ commentstring& +setlocal comments=s1:/*,mb:*,ex:*/ commentstring=/*\ %s\ */ setlocal formatoptions-=t formatoptions+=croql let &cpo = s:cpo_save diff --git a/runtime/ftplugin/initex.vim b/runtime/ftplugin/initex.vim index 0ee3e8d899..71049df6bd 100644 --- a/runtime/ftplugin/initex.vim +++ b/runtime/ftplugin/initex.vim @@ -3,6 +3,7 @@ " Maintainer: Benji Fisher, Ph.D. <benji@member.AMS.org> " Version: 1.0 " Last Change: Wed 19 Apr 2006 +" Last Change: Thu 23 May 2024 by Riley Bruins <ribru17@gmail.com> ('commentstring') " Only do this when not done yet for this buffer. if exists("b:did_ftplugin") @@ -23,7 +24,7 @@ setlocal com=sO:%\ -,mO:%\ \ ,eO:%%,:% " Set 'commentstring' to recognize the % comment character: " (Thanks to Ajit Thakkar.) -setlocal cms=%%s +setlocal cms=%\ %s " Allow "[d" to be used to find a macro definition: let &l:define='\\\([egx]\|char\|mathchar\|count\|dimen\|muskip\|skip\|toks\)\=' diff --git a/runtime/ftplugin/java.vim b/runtime/ftplugin/java.vim index fa2b61075f..55b358374f 100644 --- a/runtime/ftplugin/java.vim +++ b/runtime/ftplugin/java.vim @@ -3,17 +3,29 @@ " Maintainer: Aliaksei Budavei <0x000c70 AT gmail DOT com> " Former Maintainer: Dan Sharp " Repository: https://github.com/zzzyxwvut/java-vim.git -" Last Change: 2024 Apr 18 +" Last Change: 2024 Sep 26 " 2024 Jan 14 by Vim Project (browsefilter) - -if exists("b:did_ftplugin") | finish | endif -let b:did_ftplugin = 1 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') " Make sure the continuation lines below do not cause problems in " compatibility mode. let s:save_cpo = &cpo set cpo-=C +if (exists("g:java_ignore_javadoc") || exists("g:java_ignore_markdown")) && + \ exists("*javaformat#RemoveCommonMarkdownWhitespace") + delfunction javaformat#RemoveCommonMarkdownWhitespace + unlet! g:loaded_javaformat +endif + +if exists("b:did_ftplugin") + let &cpo = s:save_cpo + unlet s:save_cpo + finish +endif + +let b:did_ftplugin = 1 + " For filename completion, prefer the .java extension over the .class " extension. set suffixes+=.class @@ -26,6 +38,8 @@ setlocal suffixesadd=.java " Clean up in case this file is sourced again. unlet! s:zip_func_upgradable +"""" STRIVE TO REMAIN COMPATIBLE FOR AT LEAST VIM 7.0. + " Documented in ":help ft-java-plugin". if exists("g:ftplugin_java_source_path") && \ type(g:ftplugin_java_source_path) == type("") @@ -58,10 +72,11 @@ endif " and insert the comment leader when hitting <CR> or using "o". setlocal formatoptions-=t formatoptions+=croql -" Set 'comments' to format dashed lists in comments. Behaves just like C. -setlocal comments& comments^=sO:*\ -,mO:*\ \ ,exO:*/ +" Set 'comments' to format Markdown Javadoc comments and dashed lists +" in other multi-line comments (it behaves just like C). +setlocal comments& comments^=:///,sO:*\ -,mO:*\ \ ,exO:*/ -setlocal commentstring=//%s +setlocal commentstring=//\ %s " Change the :browse e filter to primarily show Java-related files. if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter") @@ -102,3 +117,4 @@ endif " Restore the saved compatibility options. let &cpo = s:save_cpo unlet s:save_cpo +" vim: fdm=syntax sw=4 ts=8 noet sta diff --git a/runtime/ftplugin/javacc.vim b/runtime/ftplugin/javacc.vim new file mode 100644 index 0000000000..780c68b0f9 --- /dev/null +++ b/runtime/ftplugin/javacc.vim @@ -0,0 +1,20 @@ +" Vim filetype plugin +" Language: JavaCC +" Maintainer: Riley Bruins <ribru17@gmail.com> +" Last Change: 2024 Jul 06 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +" Set 'formatoptions' to break comment lines but not other lines, +" and insert the comment leader when hitting <CR> or using "o". +setlocal formatoptions-=t formatoptions+=croql + +" Set 'comments' to format dashed lists in comments. Behaves just like C. +setlocal comments& comments^=sO:*\ -,mO:*\ \ ,exO:*/ + +setlocal commentstring=//\ %s + +let b:undo_ftplugin = 'setl fo< com< cms<' diff --git a/runtime/ftplugin/javascript.vim b/runtime/ftplugin/javascript.vim index 2633954903..455b794cf0 100644 --- a/runtime/ftplugin/javascript.vim +++ b/runtime/ftplugin/javascript.vim @@ -3,6 +3,7 @@ " Maintainer: Doug Kearns <dougkearns@gmail.com> " Contributor: Romain Lafourcade <romainlafourcade@gmail.com> " Last Change: 2024 Jan 14 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") finish @@ -24,7 +25,7 @@ endif " Set 'comments' to format dashed lists in comments. setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// -setlocal commentstring=//%s +setlocal commentstring=//\ %s " Change the :browse e filter to primarily show JavaScript-related files. if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter") diff --git a/runtime/ftplugin/jq.vim b/runtime/ftplugin/jq.vim index 88958e80dd..307fbdb62d 100644 --- a/runtime/ftplugin/jq.vim +++ b/runtime/ftplugin/jq.vim @@ -2,6 +2,8 @@ " Language: jq " Maintainer: Vito <vito.blog@gmail.com> " Last Change: 2024 Apr 29 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') +" 2024 Oct 04 by Konfekt (unset compiler) " Upstream: https://github.com/vito-c/jq.vim if exists('b:did_ftplugin') @@ -10,7 +12,12 @@ endif let b:did_ftplugin = 1 setlocal include=^\\s*\\%(import\\\|include\\) -setlocal commentstring=#%s -compiler jq +setlocal commentstring=#\ %s let b:undo_ftplugin = 'setl commentstring< include<' + +if !exists('current_compiler') + let b:undo_ftplugin ..= "| compiler make" + compiler jq +endif + diff --git a/runtime/ftplugin/jsonc.vim b/runtime/ftplugin/jsonc.vim index e47a75f574..ec3268492c 100644 --- a/runtime/ftplugin/jsonc.vim +++ b/runtime/ftplugin/jsonc.vim @@ -5,6 +5,7 @@ " https://github.com/kevinoid/vim-jsonc " License: MIT " Last Change: 2021 Nov 22 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') runtime! ftplugin/json.vim @@ -15,7 +16,7 @@ else endif " Set comment (formatting) related options. {{{1 -setlocal commentstring=//%s comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// +setlocal commentstring=//\ %s comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// " Let Vim know how to disable the plug-in. let b:undo_ftplugin = 'setlocal commentstring< comments<' diff --git a/runtime/ftplugin/kdl.vim b/runtime/ftplugin/kdl.vim new file mode 100644 index 0000000000..c9a1d8b185 --- /dev/null +++ b/runtime/ftplugin/kdl.vim @@ -0,0 +1,17 @@ +" Vim filetype plugin +" Language: KDL +" Author: Aram Drevekenin <aram@poor.dev> +" Maintainer: Yinzuo Jiang <jiangyinzuo@foxmail.com> +" Last Change: 2024-06-10 + +if exists("b:did_ftplugin") + finish +endif + +let b:did_ftplugin = 1 + +setlocal comments=:// +setlocal commentstring=//\ %s +setlocal formatoptions-=t + +let b:undo_ftplugin = 'setlocal comments< commentstring< formatoptions<' diff --git a/runtime/ftplugin/kivy.vim b/runtime/ftplugin/kivy.vim new file mode 100644 index 0000000000..e19d832bf3 --- /dev/null +++ b/runtime/ftplugin/kivy.vim @@ -0,0 +1,13 @@ +" Vim filetype plugin +" Language: Kivy +" Maintainer: Riley Bruins <ribru17@gmail.com> +" Last Change: 2024 Jul 06 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +setl commentstring=#\ %s + +let b:undo_ftplugin = 'setl cms<' diff --git a/runtime/ftplugin/lc.vim b/runtime/ftplugin/lc.vim new file mode 100644 index 0000000000..e818f1aecb --- /dev/null +++ b/runtime/ftplugin/lc.vim @@ -0,0 +1,13 @@ +" Vim filetype plugin +" Language: Elsa +" Maintainer: Riley Bruins <ribru17@gmail.com> +" Last Change: 2024 May 25 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +setl comments=:-- commentstring=--\ %s + +let b:undo_ftplugin = 'setl com< cms<' diff --git a/runtime/ftplugin/ld.vim b/runtime/ftplugin/ld.vim index 1ab80d533c..9cc70bd94d 100644 --- a/runtime/ftplugin/ld.vim +++ b/runtime/ftplugin/ld.vim @@ -1,7 +1,8 @@ " Vim filetype plugin file " Language: ld(1) script " Previous Maintainer: Nikolai Weibull <now@bitwi.se> -" Latest Revision: 2008-07-09 +" Latest Revision: 2008 Jul 09 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") finish @@ -13,7 +14,7 @@ set cpo&vim let b:undo_ftplugin = "setl com< cms< inc< fo<" -setlocal comments=s1:/*,mb:*,ex:*/ commentstring=/*%s*/ include=^\\s*INCLUDE +setlocal comments=s1:/*,mb:*,ex:*/ commentstring=/*\ %s\ */ include=^\\s*INCLUDE setlocal formatoptions-=t formatoptions+=croql let &cpo = s:cpo_save diff --git a/runtime/ftplugin/ldapconf.vim b/runtime/ftplugin/ldapconf.vim new file mode 100644 index 0000000000..70557160e8 --- /dev/null +++ b/runtime/ftplugin/ldapconf.vim @@ -0,0 +1,13 @@ +" Vim filetype plugin +" Language: ldap.conf(5) configuration file. +" Maintainer: Riley Bruins <ribru17@gmail.com> +" Last Change: 2024 Jul 06 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +setl comments=:# commentstring=#\ %s + +let b:undo_ftplugin = 'setl com< cms<' diff --git a/runtime/ftplugin/lex.vim b/runtime/ftplugin/lex.vim new file mode 100644 index 0000000000..c6c47fedf0 --- /dev/null +++ b/runtime/ftplugin/lex.vim @@ -0,0 +1,14 @@ +" Vim filetype plugin +" Language: Lex and Flex +" Maintainer: Riley Bruins <ribru17@gmail.com> +" Last Change: 2024 Jul 06 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// +setlocal commentstring=//\ %s + +let b:undo_ftplugin = 'setl com< cms<' diff --git a/runtime/ftplugin/liquid.vim b/runtime/ftplugin/liquid.vim index f24ec4cbb2..dbd8abe457 100644 --- a/runtime/ftplugin/liquid.vim +++ b/runtime/ftplugin/liquid.vim @@ -2,6 +2,7 @@ " Language: Liquid " Maintainer: Tim Pope <vimNOSPAM@tpope.org> " Last Change: 2022 Mar 15 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists('b:did_ftplugin') finish @@ -56,6 +57,6 @@ if exists('loaded_matchit') let b:match_words .= '\<\%(if\w*\|unless\|case\)\>:\<\%(elsif\|else\|when\)\>:\<end\%(if\w*\|unless\|case\)\>,\<\%(for\|tablerow\)\>:\%({%\s*\)\@<=empty\>:\<end\%(for\|tablerow\)\>,\<\(capture\|comment\|highlight\)\>:\<end\1\>' endif -setlocal commentstring={%\ comment\ %}%s{%\ endcomment\ %} +setlocal commentstring={%\ comment\ %}\ %s\ {%\ endcomment\ %} let b:undo_ftplugin .= 'setl cms< | unlet! b:browsefilter b:match_words' diff --git a/runtime/ftplugin/lisp.vim b/runtime/ftplugin/lisp.vim index db3ac96631..fe3c6fe996 100644 --- a/runtime/ftplugin/lisp.vim +++ b/runtime/ftplugin/lisp.vim @@ -5,6 +5,7 @@ " Original author: Dorai Sitaram <ds26@gte.com> " Original URL: http://www.ccs.neu.edu/~dorai/vimplugins/vimplugins.html " Last Change: Mar 10, 2021 +" May 23, 2024 by Riley Bruins <ribru17@gmail.com> ('commentstring') " Only do this when not done yet for this buffer if exists("b:did_ftplugin") @@ -19,6 +20,6 @@ setl define=^\\s*(def\\k* setl formatoptions-=t setl iskeyword+=+,-,*,/,%,<,=,>,:,$,?,!,@-@,94 setl lisp -setl commentstring=;%s +setl commentstring=;\ %s let b:undo_ftplugin = "setlocal comments< define< formatoptions< iskeyword< lisp< commentstring<" diff --git a/runtime/ftplugin/lua.lua b/runtime/ftplugin/lua.lua index 98f218e36e..75deb6b190 100644 --- a/runtime/ftplugin/lua.lua +++ b/runtime/ftplugin/lua.lua @@ -1,2 +1,4 @@ -- use treesitter over syntax vim.treesitter.start() + +vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n call v:lua.vim.treesitter.stop()' diff --git a/runtime/ftplugin/man.vim b/runtime/ftplugin/man.vim index fdeaae4c3f..37667477f3 100644 --- a/runtime/ftplugin/man.vim +++ b/runtime/ftplugin/man.vim @@ -8,14 +8,16 @@ let b:did_ftplugin = 1 setlocal noexpandtab tabstop=8 softtabstop=8 shiftwidth=8 setlocal wrap breakindent linebreak +setlocal colorcolumn=0 nolist " Parentheses and '-' for references like `git-ls-files(1)`; '@' for systemd " pages; ':' for Perl and C++ pages. Here, I intentionally omit the locale " specific characters matched by `@`. setlocal iskeyword=@-@,:,a-z,A-Z,48-57,_,.,-,(,) -setlocal nonumber norelativenumber -setlocal foldcolumn=0 colorcolumn=0 nolist nofoldenable +" man page content is likely preformatted for the terminal width, so +" narrowing display by any additional columns leads to Embarrassing Line Wrap +setlocal nonumber norelativenumber foldcolumn=0 signcolumn=auto setlocal tagfunc=v:lua.require'man'.goto_tag @@ -35,6 +37,8 @@ if get(g:, 'ft_man_folding_enable', 0) setlocal foldenable setlocal foldmethod=indent setlocal foldnestmax=1 +else + setlocal nofoldenable endif let b:undo_ftplugin = '' diff --git a/runtime/ftplugin/markdown.vim b/runtime/ftplugin/markdown.vim index 022dd0d601..d4ee5ac242 100644 --- a/runtime/ftplugin/markdown.vim +++ b/runtime/ftplugin/markdown.vim @@ -2,6 +2,7 @@ " Language: Markdown " Maintainer: Tim Pope <https://github.com/tpope/vim-markdown> " Last Change: 2023 Dec 28 +" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") finish @@ -12,7 +13,7 @@ runtime! ftplugin/html.vim ftplugin/html_*.vim ftplugin/html/*.vim let s:keepcpo= &cpo set cpo&vim -setlocal comments=fb:*,fb:-,fb:+,n:> commentstring=<!--%s--> +setlocal comments=fb:*,fb:-,fb:+,n:> commentstring=<!--\ %s\ --> setlocal formatoptions+=tcqln formatoptions-=r formatoptions-=o setlocal formatlistpat=^\\s*\\d\\+\\.\\s\\+\\\|^\\s*[-*+]\\s\\+\\\|^\\[^\\ze[^\\]]\\+\\]:\\&^.\\{4\\} diff --git a/runtime/ftplugin/mediawiki.vim b/runtime/ftplugin/mediawiki.vim new file mode 100644 index 0000000000..4618246106 --- /dev/null +++ b/runtime/ftplugin/mediawiki.vim @@ -0,0 +1,42 @@ +" Language: MediaWiki +" Maintainer: Avid Seeker <avidseeker7@protonmail.com> +" Home: http://en.wikipedia.org/wiki/Wikipedia:Text_editor_support#Vim +" Last Change: 2024 Jul 14 +" Credits: chikamichi +" + +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin = 1 + +" Many MediaWiki wikis prefer line breaks only at the end of paragraphs +" (like in a text processor), which results in long, wrapping lines. +setlocal wrap linebreak +setlocal textwidth=0 + +setlocal formatoptions-=tc formatoptions+=l formatoptions+=roq +setlocal matchpairs+=<:> + +" Treat lists, indented text and tables as comment lines and continue with the +" same formatting in the next line (i.e. insert the comment leader) when hitting +" <CR> or using "o". +setlocal comments=n:#,n:*,n:\:,s:{\|,m:\|,ex:\|},s:<!--,m:\ \ \ \ ,e:--> +setlocal commentstring=<!--\ %s\ --> + +" match HTML tags (taken directly from $VIM/ftplugin/html.vim) +if exists("loaded_matchit") + let b:match_ignorecase=0 + let b:match_skip = 's:Comment' + let b:match_words = '<:>,' . + \ '<\@<=[ou]l\>[^>]*\%(>\|$\):<\@<=li\>:<\@<=/[ou]l>,' . + \ '<\@<=dl\>[^>]*\%(>\|$\):<\@<=d[td]\>:<\@<=/dl>,' . + \ '<\@<=\([^/][^ \t>]*\)[^>]*\%(>\|$\):<\@<=/\1>' +endif + +" Enable folding based on ==sections== +setlocal foldexpr=getline(v:lnum)=~'^\\(=\\+\\)[^=]\\+\\1\\(\\s*<!--.*-->\\)\\=\\s*$'?\">\".(len(matchstr(getline(v:lnum),'^=\\+'))-1):\"=\" +setlocal foldmethod=expr + +let b:undo_ftplugin = "setl commentstring< comments< formatoptions< foldexpr< foldmethod<" +let b:undo_ftplugin += " matchpairs< linebreak< wrap< textwidth<" diff --git a/runtime/ftplugin/mermaid.vim b/runtime/ftplugin/mermaid.vim index fe84ab37cf..5547ad3e1f 100644 --- a/runtime/ftplugin/mermaid.vim +++ b/runtime/ftplugin/mermaid.vim @@ -2,6 +2,7 @@ " Language: Mermaid " Maintainer: Craig MacEachern <https://github.com/craigmac/vim-mermaid> " Last Change: 2022 Oct 13 +" 2024 Jul 18 by Vim Project (adjust comments) if exists("b:did_ftplugin") finish @@ -16,9 +17,9 @@ setlocal shiftwidth=2 setlocal softtabstop=-1 setlocal tabstop=4 +setlocal comments=:%% +setlocal commentstring=%%\ %s " TODO: comments, formatlist stuff, based on what? -setlocal comments=b:#,fb:- -setlocal commentstring=#\ %s setlocal formatoptions+=tcqln formatoptions-=r formatoptions-=o setlocal formatlistpat=^\\s*\\d\\+\\.\\s\\+\\\|^\\s*[-*+]\\s\\+\\\|^\\[^\\ze[^\\]]\\+\\]:\\&^.\\{4\\} diff --git a/runtime/ftplugin/mma.vim b/runtime/ftplugin/mma.vim index ce4cee18ae..91a8111bcb 100644 --- a/runtime/ftplugin/mma.vim +++ b/runtime/ftplugin/mma.vim @@ -1,7 +1,8 @@ " Vim filetype plugin file " Language: Mathematica " Maintainer: Ian Ford <ianf@wolfram.com> -" Last Change: 22 January 2019 +" Last Change: 2019 Jan 22 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') " Only do this when not done yet for this buffer if exists("b:did_ftplugin") @@ -13,4 +14,4 @@ let b:did_ftplugin = 1 let b:undo_ftplugin = "setlocal commentstring<" -setlocal commentstring=\(*%s*\) +setlocal commentstring=\(*\ %s\ *\) diff --git a/runtime/ftplugin/modconf.vim b/runtime/ftplugin/modconf.vim index 22d18a9aad..68ce69a446 100644 --- a/runtime/ftplugin/modconf.vim +++ b/runtime/ftplugin/modconf.vim @@ -1,7 +1,8 @@ " Vim filetype plugin file " Language: modules.conf(5) configuration file +" Maintainer: This runtime file is looking for a new maintainer. " Previous Maintainer: Nikolai Weibull <now@bitwi.se> -" Latest Revision: 2023-10-07 +" Latest Revision: 2024-09-20 (remove erroneous endif) if exists("b:did_ftplugin") finish @@ -16,20 +17,12 @@ let b:undo_ftplugin = "setl com< cms< inc< fo<" setlocal comments=:# commentstring=#\ %s include=^\\s*include setlocal formatoptions-=t formatoptions+=croql -if has('unix') && executable('less') - if !has('gui_running') - command -buffer -nargs=1 ModconfKeywordPrg - \ silent exe '!' . 'LESS= MANPAGER="less --pattern=''^\s{,8}' . <q-args> . '\b'' --hilite-search" man ' . 'modprobe.d' | - \ redraw! - elseif has('terminal') - command -buffer -nargs=1 ModconfKeywordPrg - \ silent exe ':term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s{,8}' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'modprobe.d' - endif - if exists(':ModconfKeywordPrg') == 2 - setlocal iskeyword+=- - setlocal keywordprg=:ModconfKeywordPrg - let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer ModconfKeywordPrg' - endif +if has('unix') && executable('less') && exists(':terminal') == 2 + command -buffer -nargs=1 ModconfKeywordPrg + \ silent exe ':term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s{,8}' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'modprobe.d' + setlocal iskeyword+=- + setlocal keywordprg=:ModconfKeywordPrg + let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer ModconfKeywordPrg' endif let &cpo = s:cpo_save diff --git a/runtime/ftplugin/modula2.vim b/runtime/ftplugin/modula2.vim index 9c1acc276a..306688da05 100644 --- a/runtime/ftplugin/modula2.vim +++ b/runtime/ftplugin/modula2.vim @@ -2,6 +2,7 @@ " Language: Modula-2 " Maintainer: Doug Kearns <dougkearns@gmail.com> " Last Change: 2024 Jan 14 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") finish @@ -17,7 +18,7 @@ if s:dialect ==# "r10" setlocal comments=s:(*,m:\ ,e:*),:! setlocal commentstring=!\ %s else - setlocal commentstring=(*%s*) + setlocal commentstring=(*\ %s\ *) setlocal comments=s:(*,m:\ ,e:*) endif setlocal formatoptions-=t formatoptions+=croql diff --git a/runtime/ftplugin/modula3.vim b/runtime/ftplugin/modula3.vim index 45dd7ca01c..f899d1d103 100644 --- a/runtime/ftplugin/modula3.vim +++ b/runtime/ftplugin/modula3.vim @@ -2,6 +2,7 @@ " Language: Modula-3 " Maintainer: Doug Kearns <dougkearns@gmail.com> " Last Change: 2024 Jan 14 +" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") finish @@ -12,7 +13,7 @@ let s:cpo_save = &cpo set cpo&vim setlocal comments=s0:(*,mb:\ ,ex:*) -setlocal commentstring=(*%s*) +setlocal commentstring=(*\ %s\ *) setlocal formatoptions-=t formatoptions+=croql setlocal suffixesadd+=.m3 setlocal formatprg=m3pp diff --git a/runtime/ftplugin/mojo.vim b/runtime/ftplugin/mojo.vim new file mode 100644 index 0000000000..ff50229934 --- /dev/null +++ b/runtime/ftplugin/mojo.vim @@ -0,0 +1,41 @@ +" Vim filetype plugin +" Language: Mojo +" Maintainer: Riley Bruins <ribru17@gmail.com> +" Last Change: 2024 Jul 07 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +setlocal include=^\\s*\\(from\\\|import\\) +setlocal define=^\\s*\\(\\(async\\s\\+\\)\\?def\\\|class\\) + +" For imports with leading .., append / and replace additional .s with ../ +let b:grandparent_match = '^\(.\.\)\(\.*\)' +let b:grandparent_sub = '\=submatch(1)."/".repeat("../",strlen(submatch(2)))' + +" For imports with a single leading ., replace it with ./ +let b:parent_match = '^\.\(\.\)\@!' +let b:parent_sub = './' + +" Replace any . sandwiched between word characters with / +let b:child_match = '\(\w\)\.\(\w\)' +let b:child_sub = '\1/\2' + +setlocal includeexpr=substitute(substitute(substitute( + \v:fname, + \b:grandparent_match,b:grandparent_sub,''), + \b:parent_match,b:parent_sub,''), + \b:child_match,b:child_sub,'g') + +setlocal suffixesadd=.mojo +setlocal comments=b:#,fb:- +setlocal commentstring=#\ %s + +let b:undo_ftplugin = 'setlocal include<' + \ . '|setlocal define<' + \ . '|setlocal includeexpr<' + \ . '|setlocal suffixesadd<' + \ . '|setlocal comments<' + \ . '|setlocal commentstring<' diff --git a/runtime/ftplugin/muttrc.vim b/runtime/ftplugin/muttrc.vim index c9f6df31d0..7df61580bf 100644 --- a/runtime/ftplugin/muttrc.vim +++ b/runtime/ftplugin/muttrc.vim @@ -1,7 +1,7 @@ " Vim filetype plugin file " Language: mutt RC File " Previous Maintainer: Nikolai Weibull <now@bitwi.se> -" Latest Revision: 2023-10-07 +" Latest Revision: 2024-09-19 (simplify keywordprg #15696) if exists("b:did_ftplugin") finish @@ -18,20 +18,12 @@ setlocal formatoptions-=t formatoptions+=croql let &l:include = '^\s*source\>' -if has('unix') && executable('less') - if !has('gui_running') - command -buffer -nargs=1 MuttrcKeywordPrg - \ silent exe '!' . 'LESS= MANPAGER="less --pattern=''^\s+' . <q-args> . '\b'' --hilite-search" man ' . 'muttrc' | - \ redraw! - elseif has('terminal') - command -buffer -nargs=1 MuttrcKeywordPrg - \ silent exe 'term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'muttrc' - endif - if exists(':MuttrcKeywordPrg') == 2 - setlocal iskeyword+=- - setlocal keywordprg=:MuttrcKeywordPrg - let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer MuttrcKeywordPrg' - endif +if has('unix') && executable('less') && exists(':terminal') == 2 + command -buffer -nargs=1 MuttrcKeywordPrg + \ silent exe 'term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'muttrc' + setlocal iskeyword+=- + setlocal keywordprg=:MuttrcKeywordPrg + let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer MuttrcKeywordPrg' endif let &cpo = s:cpo_save diff --git a/runtime/ftplugin/mysql.vim b/runtime/ftplugin/mysql.vim new file mode 100644 index 0000000000..232df8c5a3 --- /dev/null +++ b/runtime/ftplugin/mysql.vim @@ -0,0 +1,9 @@ +" Vim filetype plugin +" Language: MySQL +" Maintainer: Riley Bruins <ribru17@gmail.com> +" Last Change: 2024 Aug 12 +if exists("b:did_ftplugin") + finish +endif + +runtime ftplugin/sql.vim diff --git a/runtime/ftplugin/nroff.vim b/runtime/ftplugin/nroff.vim index cf62d02daa..ed0b32f5f3 100644 --- a/runtime/ftplugin/nroff.vim +++ b/runtime/ftplugin/nroff.vim @@ -2,15 +2,15 @@ " Language: roff(7) " Maintainer: Aman Verma " Homepage: https://github.com/a-vrma/vim-nroff-ftplugin -" Previous Maintainer: Chris Spiegel <cspiegel@gmail.com> -" Last Change: 2020 Nov 21 +" Previous Maintainer: Chris Spiegel <cspiegel@gmail.com> +" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") finish endif let b:did_ftplugin = 1 -setlocal commentstring=.\\\"%s +setlocal commentstring=.\\\"\ %s setlocal comments=:.\\\" setlocal sections+=Sh diff --git a/runtime/ftplugin/nu.vim b/runtime/ftplugin/nu.vim new file mode 100644 index 0000000000..9efbc3b099 --- /dev/null +++ b/runtime/ftplugin/nu.vim @@ -0,0 +1,13 @@ +" Vim filetype plugin +" Language: Nu +" Maintainer: Marc Jakobi <marc@jakobi.dev> +" Last Change: 2024 Aug 31 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +setlocal commentstring=#\ %s + +let b:undo_ftplugin = 'setl com<' diff --git a/runtime/ftplugin/objc.lua b/runtime/ftplugin/objc.lua new file mode 100644 index 0000000000..89ab42ef54 --- /dev/null +++ b/runtime/ftplugin/objc.lua @@ -0,0 +1,3 @@ +vim.bo.commentstring = '// %s' + +vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<' diff --git a/runtime/ftplugin/objcpp.vim b/runtime/ftplugin/objcpp.vim new file mode 100644 index 0000000000..ffba685c7d --- /dev/null +++ b/runtime/ftplugin/objcpp.vim @@ -0,0 +1 @@ +runtime! ftplugin/objc.vim diff --git a/runtime/ftplugin/obse.vim b/runtime/ftplugin/obse.vim index 6d865f05ee..bf5076f41f 100644 --- a/runtime/ftplugin/obse.vim +++ b/runtime/ftplugin/obse.vim @@ -2,8 +2,9 @@ " Language: Oblivion Language (obl) " Original Creator: Kat <katisntgood@gmail.com> " Maintainer: Kat <katisntgood@gmail.com> -" Created: August 08, 2021 -" Last Change: 13 November 2022 +" Created: 2021 Aug 08 +" Last Change: 2022 Nov 13 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") finish @@ -20,7 +21,7 @@ noremap <script> <buffer> <silent> ]] <nop> noremap <script> <buffer> <silent> [] <nop> noremap <script> <buffer> <silent> ][ <nop> -setlocal commentstring=;%s +setlocal commentstring=;\ %s setlocal comments=:; function s:NextSection(type, backwards, visual) diff --git a/runtime/ftplugin/ocaml.vim b/runtime/ftplugin/ocaml.vim index 20172c9b32..8b88d8d001 100644 --- a/runtime/ftplugin/ocaml.vim +++ b/runtime/ftplugin/ocaml.vim @@ -5,12 +5,14 @@ " Pierre Vittet <pierre-vittet@pvittet.com> " Stefano Zacchiroli <zack@bononia.it> " Vincent Aravantinos <firstname.name@imag.fr> +" Riley Bruins <ribru17@gmail.com> ('commentstring') " URL: https://github.com/ocaml/vim-ocaml " Last Change: " 2013 Oct 27 - Added commentstring (MM) " 2013 Jul 26 - load default compiler settings (MM) " 2013 Jul 24 - removed superfluous efm-setting (MM) " 2013 Jul 22 - applied fixes supplied by Hirotaka Hamada (MM) +" 2024 May 23 - added space in commentstring (RB) if exists("b:did_ftplugin") finish @@ -40,7 +42,7 @@ set cpo&vim " Comment string setlocal comments=sr:(*\ ,mb:\ ,ex:*) setlocal comments^=sr:(**,mb:\ \ ,ex:*) -setlocal commentstring=(*%s*) +setlocal commentstring=(*\ %s\ *) " Add mappings, unless the user didn't want this. if !exists("no_plugin_maps") && !exists("no_ocaml_maps") diff --git a/runtime/ftplugin/odin.vim b/runtime/ftplugin/odin.vim index c50fea65a3..ca534bb30c 100644 --- a/runtime/ftplugin/odin.vim +++ b/runtime/ftplugin/odin.vim @@ -2,7 +2,8 @@ " Language: Odin " Maintainer: Maxim Kim <habamax@gmail.com> " Website: https://github.com/habamax/vim-odin -" Last Change: 2024-01-15 +" Last Change: 2024 Jan 15 +" 2024-May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') " " This file has been manually translated from Vim9 script. @@ -19,7 +20,7 @@ let b:undo_ftplugin = 'setlocal commentstring<' \ .. '| setlocal suffixesadd<' setlocal suffixesadd=.odin -setlocal commentstring=//%s +setlocal commentstring=//\ %s setlocal comments=s1:/*,mb:*,ex:*/,:// let &cpo = s:cpo_save diff --git a/runtime/ftplugin/openvpn.vim b/runtime/ftplugin/openvpn.vim index 56c0f25b39..9cd7b7ad1a 100644 --- a/runtime/ftplugin/openvpn.vim +++ b/runtime/ftplugin/openvpn.vim @@ -2,6 +2,7 @@ " Language: OpenVPN " Maintainer: ObserverOfTime <chronobserver@disroot.org> " Last Change: 2022 Oct 16 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists('b:did_ftplugin') finish @@ -9,6 +10,6 @@ endif let b:did_ftplugin = 1 setlocal iskeyword+=-,.,/ -setlocal comments=:#,:; commentstring=#%s +setlocal comments=:#,:; commentstring=#\ %s let b:undo_ftplugin = 'setl isk< com< cms<' diff --git a/runtime/ftplugin/pascal.vim b/runtime/ftplugin/pascal.vim index 9abd7dd382..7c800c4fbd 100644 --- a/runtime/ftplugin/pascal.vim +++ b/runtime/ftplugin/pascal.vim @@ -3,6 +3,7 @@ " Maintainer: Doug Kearns <dougkearns@gmail.com> " Previous Maintainer: Dan Sharp " Last Change: 2024 Jan 14 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") | finish | endif let b:did_ftplugin = 1 @@ -11,7 +12,7 @@ let s:cpo_save = &cpo set cpo&vim set comments=s:(*,m:\ ,e:*),s:{,m:\ ,e:} -set commentstring={%s} +set commentstring={\ %s\ } if exists("pascal_delphi") set comments+=:/// diff --git a/runtime/ftplugin/pdf.vim b/runtime/ftplugin/pdf.vim index 1ed99117d6..96c77c870a 100644 --- a/runtime/ftplugin/pdf.vim +++ b/runtime/ftplugin/pdf.vim @@ -2,13 +2,14 @@ " Language: PDF " Maintainer: Tim Pope <vimNOSPAM@tpope.info> " Last Change: 2007 Dec 16 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") finish endif let b:did_ftplugin = 1 -setlocal commentstring=%%s +setlocal commentstring=%\ %s setlocal comments=:% let b:undo_ftplugin = "setlocal cms< com< | unlet! b:match_words" diff --git a/runtime/ftplugin/perl.vim b/runtime/ftplugin/perl.vim index 8c6a80eb4f..03368a7af3 100644 --- a/runtime/ftplugin/perl.vim +++ b/runtime/ftplugin/perl.vim @@ -8,6 +8,7 @@ " 2023 Sep 07 by Vim Project (safety check: don't execute perl " from current directory) " 2024 Jan 14 by Vim Project (browsefilter) +" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") | finish | endif let b:did_ftplugin = 1 @@ -22,7 +23,7 @@ setlocal formatoptions+=crqol setlocal keywordprg=perldoc\ -f setlocal comments=:# -setlocal commentstring=#%s +setlocal commentstring=#\ %s " Provided by Ned Konz <ned at bike-nomad dot com> "--------------------------------------------- diff --git a/runtime/ftplugin/php.vim b/runtime/ftplugin/php.vim index f03f14512a..e124961ba1 100644 --- a/runtime/ftplugin/php.vim +++ b/runtime/ftplugin/php.vim @@ -3,6 +3,7 @@ " Maintainer: Doug Kearns <dougkearns@gmail.com> " Previous Maintainer: Dan Sharp " Last Change: 2024 Jan 14 +" Last Change: 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") finish @@ -44,7 +45,7 @@ if exists("b:match_skip") endif setlocal comments=s1:/*,mb:*,ex:*/,://,:# -setlocal commentstring=/*%s*/ +setlocal commentstring=/*\ %s\ */ setlocal formatoptions+=l formatoptions-=t if get(g:, "php_autocomment", 1) diff --git a/runtime/ftplugin/ps1.vim b/runtime/ftplugin/ps1.vim index d6ab01016b..e09bbf86dc 100644 --- a/runtime/ftplugin/ps1.vim +++ b/runtime/ftplugin/ps1.vim @@ -3,6 +3,8 @@ " URL: https://github.com/PProvost/vim-ps1 " Last Change: 2021 Apr 02 " 2024 Jan 14 by Vim Project (browsefilter) +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') +" 2024 Sep 19 by Konfekt (simplify keywordprg #15696) " Only do this when not done yet for this buffer if exists("b:did_ftplugin") | finish | endif @@ -14,7 +16,7 @@ let s:cpo_save = &cpo set cpo&vim setlocal tw=0 -setlocal commentstring=#%s +setlocal commentstring=#\ %s setlocal formatoptions=tcqro " Enable autocompletion of hyphenated PowerShell commands, " e.g. Get-Content or Get-ADUser @@ -34,6 +36,10 @@ if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter") endif endif +" Undo the stuff we changed +let b:undo_ftplugin = "setlocal tw< cms< fo< iskeyword<" . + \ " | unlet! b:browsefilter" + " Look up keywords by Get-Help: " check for PowerShell Core in Windows, Linux or MacOS if executable('pwsh') | let s:pwsh_cmd = 'pwsh' @@ -44,21 +50,14 @@ elseif executable('powershell.exe') | let s:pwsh_cmd = 'powershell.exe' endif if exists('s:pwsh_cmd') - if !has('gui_running') && executable('less') && - \ !(exists('$ConEmuBuild') && &term =~? '^xterm') - " For exclusion of ConEmu, see https://github.com/Maximus5/ConEmu/issues/2048 - command! -buffer -nargs=1 GetHelp silent exe '!' . s:pwsh_cmd . ' -NoLogo -NoProfile -NonInteractive -ExecutionPolicy RemoteSigned -Command Get-Help -Full "<args>" | ' . (has('unix') ? 'LESS= less' : 'less') | redraw! - elseif has('terminal') + if exists(':terminal') == 2 command! -buffer -nargs=1 GetHelp silent exe 'term ' . s:pwsh_cmd . ' -NoLogo -NoProfile -NonInteractive -ExecutionPolicy RemoteSigned -Command Get-Help -Full "<args>"' . (executable('less') ? ' | less' : '') else command! -buffer -nargs=1 GetHelp echo system(s:pwsh_cmd . ' -NoLogo -NoProfile -NonInteractive -ExecutionPolicy RemoteSigned -Command Get-Help -Full <args>') endif + setlocal keywordprg=:GetHelp + let b:undo_ftplugin ..= " | setl kp< | sil! delc -buffer GetHelp" endif -setlocal keywordprg=:GetHelp - -" Undo the stuff we changed -let b:undo_ftplugin = "setlocal tw< cms< fo< iskeyword< keywordprg<" . - \ " | unlet! b:browsefilter" let &cpo = s:cpo_save unlet s:cpo_save diff --git a/runtime/ftplugin/ps1xml.vim b/runtime/ftplugin/ps1xml.vim index 17bb181f37..0052de19ce 100644 --- a/runtime/ftplugin/ps1xml.vim +++ b/runtime/ftplugin/ps1xml.vim @@ -3,6 +3,7 @@ " URL: https://github.com/PProvost/vim-ps1 " Last Change: 2021 Apr 02 " 2024 Jan 14 by Vim Project (browsefilter) +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') " Only do this when not done yet for this buffer if exists("b:did_ftplugin") | finish | endif @@ -14,7 +15,7 @@ let s:cpo_save = &cpo set cpo&vim setlocal tw=0 -setlocal commentstring=#%s +setlocal commentstring=#\ %s setlocal formatoptions=tcqro " Change the browse dialog on Win32 and GTK to show mainly PowerShell-related files diff --git a/runtime/ftplugin/qml.vim b/runtime/ftplugin/qml.vim index aa05c11bf9..53df11c6b8 100644 --- a/runtime/ftplugin/qml.vim +++ b/runtime/ftplugin/qml.vim @@ -3,6 +3,7 @@ " Maintainer: Chase Knowlden <haroldknowlden@gmail.com> " Last Change: 2023 Aug 16 " 2023 Aug 23 by Vim Project (browsefilter) +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists( 'b:did_ftplugin' ) finish @@ -28,7 +29,7 @@ endif " Set 'comments' to format dashed lists in comments. setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// -setlocal commentstring=//%s +setlocal commentstring=//\ %s setlocal formatoptions-=t setlocal formatoptions+=croql diff --git a/runtime/ftplugin/query.lua b/runtime/ftplugin/query.lua index c75dc30430..32d615c65c 100644 --- a/runtime/ftplugin/query.lua +++ b/runtime/ftplugin/query.lua @@ -1,6 +1,6 @@ -- Neovim filetype plugin file -- Language: Treesitter query --- Last Change: 2023 Aug 23 +-- Last Change: 2024 Jul 03 if vim.b.did_ftplugin == 1 then return @@ -32,4 +32,7 @@ if not vim.b.disable_query_linter and #query_lint_on > 0 then end -- it's a lisp! -vim.cmd([[ runtime! ftplugin/lisp.vim ]]) +vim.cmd([[runtime! ftplugin/lisp.vim]]) + +vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl omnifunc< iskeyword<' +vim.b.undo_ftplugin = vim.b.undo_ftplugin .. ' | call v:lua.vim.treesitter.stop()' diff --git a/runtime/ftplugin/racket.vim b/runtime/ftplugin/racket.vim index 84f5422140..7bfd87ddc3 100644 --- a/runtime/ftplugin/racket.vim +++ b/runtime/ftplugin/racket.vim @@ -3,8 +3,7 @@ " Maintainer: D. Ben Knoble <ben.knoble+github@gmail.com> " Previous Maintainer: Will Langstroth <will@langstroth.com> " URL: https://github.com/benknoble/vim-racket -" Last Change: 2022 Aug 29 -" 2024 Jan 14 by Vim Project (browsefilter) +" Last Change: 2024 May 28 if exists("b:did_ftplugin") finish @@ -21,7 +20,7 @@ setlocal iskeyword=@,!,#-',*-:,<-Z,a-z,~,_,94 setlocal comments=:;;;;,:;;;,:;;,:; setlocal formatoptions+=r -"setlocal commentstring=;;%s +"setlocal commentstring=;;\ %s setlocal commentstring=#\|\ %s\ \|# setlocal formatprg=raco\ fmt diff --git a/runtime/ftplugin/raku.vim b/runtime/ftplugin/raku.vim index 941222bd38..f57427e323 100644 --- a/runtime/ftplugin/raku.vim +++ b/runtime/ftplugin/raku.vim @@ -1,10 +1,11 @@ " Vim filetype plugin file -" Language: Raku -" Maintainer: vim-perl <vim-perl@googlegroups.com> -" Homepage: https://github.com/Raku/vim-raku +" Language: Raku +" Maintainer: vim-perl <vim-perl@googlegroups.com> +" Homepage: https://github.com/Raku/vim-raku " Bugs/requests: https://github.com/Raku/vim-raku/issues -" Last Change: 2021-04-16 -" Contributors: Hinrik Örn Sigurðsson <hinrik.sig@gmail.com> +" Last Change: 2021 Apr 16 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') +" Contributors: Hinrik Örn Sigurðsson <hinrik.sig@gmail.com> " " Based on ftplugin/perl.vim by Dan Sharp <dwsharp at hotmail dot com> @@ -21,7 +22,7 @@ setlocal formatoptions+=crqol setlocal keywordprg=p6doc setlocal comments=:#\|,:#=,:# -setlocal commentstring=#%s +setlocal commentstring=#\ %s " Provided by Ned Konz <ned at bike-nomad dot com> "--------------------------------------------- diff --git a/runtime/ftplugin/rasi.vim b/runtime/ftplugin/rasi.vim new file mode 100644 index 0000000000..5f8ce862df --- /dev/null +++ b/runtime/ftplugin/rasi.vim @@ -0,0 +1,25 @@ +" Vim filetype plugin file +" Language: RASI +" Maintainer: Pierrick Guillaume <pierguill@gmail.com> +" Last Change: 2024 May 21 + +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin = 1 + +let s:cpo_save = &cpo +set cpo&vim + +let b:undo_ftplugin = "setl com< cms< isk< inc<" + +setlocal comments=s1:/*,mb:*,ex:*/ +setlocal commentstring=//\ %s +setlocal iskeyword+=- + +let &l:include = '^\s*@import\s\+\%(url(\)\=' + +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim: ts=8 diff --git a/runtime/ftplugin/readline.vim b/runtime/ftplugin/readline.vim index f5934ce2c0..77fab2a611 100644 --- a/runtime/ftplugin/readline.vim +++ b/runtime/ftplugin/readline.vim @@ -2,7 +2,7 @@ " Language: readline(3) configuration file " Maintainer: Doug Kearns <dougkearns@gmail.com> " Previous Maintainer: Nikolai Weibull <now@bitwi.se> -" Last Change: 2023 Aug 22 +" Last Change: 2024 Sep 19 (simplify keywordprg #15696) if exists("b:did_ftplugin") finish @@ -34,20 +34,12 @@ if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter") let b:undo_ftplugin ..= " | unlet! b:browsefilter" endif -if has('unix') && executable('less') - if !has('gui_running') - command -buffer -nargs=1 ReadlineKeywordPrg - \ silent exe '!' . 'LESS= MANPAGER="less --pattern=''^\s+' . <q-args> . '\b'' --hilite-search" man ' . '3 readline' | - \ redraw! - elseif has('terminal') - command -buffer -nargs=1 ReadlineKeywordPrg - \ silent exe 'term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . '3 readline' - endif - if exists(':ReadlineKeywordPrg') == 2 - setlocal iskeyword+=- - setlocal keywordprg=:ReadlineKeywordPrg - let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer ReadlineKeywordPrg' - endif +if has('unix') && executable('less') && exists(':terminal') == 2 + command -buffer -nargs=1 ReadlineKeywordPrg + \ silent exe 'term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . '3 readline' + setlocal iskeyword+=- + setlocal keywordprg=:ReadlineKeywordPrg + let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer ReadlineKeywordPrg' endif let &cpo = s:cpo_save diff --git a/runtime/ftplugin/requirements.vim b/runtime/ftplugin/requirements.vim index fcfc1ac269..babf33795c 100644 --- a/runtime/ftplugin/requirements.vim +++ b/runtime/ftplugin/requirements.vim @@ -36,7 +36,11 @@ let b:undo_ftplugin = "setl iskeyword< commentstring<" " pip options contain "-" setlocal iskeyword+=- setlocal commentstring=#\ %s -compiler pip_compile + +if !exists('current_compiler') + let b:undo_ftplugin ..= "| compiler make" + compiler pip_compile +endif let &cpoptions = s:save_cpoptions unlet s:save_cpoptions diff --git a/runtime/ftplugin/rmd.vim b/runtime/ftplugin/rmd.vim index a537017aad..2390ab1cb9 100644 --- a/runtime/ftplugin/rmd.vim +++ b/runtime/ftplugin/rmd.vim @@ -3,7 +3,9 @@ " Maintainer: This runtime file is looking for a new maintainer. " Former Maintainer: Jakson Alves de Aquino <jalvesaq@gmail.com> " Former Repository: https://github.com/jalvesaq/R-Vim-runtime -" Last Change: 2024 Feb 28 by Vim Project +" Last Change: +" 2024 Feb 28 by Vim Project +" 2024 Sep 23 by Vim Project: properly restore fex option " Original work by Alex Zvoleff (adjusted from R help for rmd by Michel Kuhlmann) " Only do this when not yet done for this buffer @@ -74,9 +76,9 @@ if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter") endif if exists('b:undo_ftplugin') - let b:undo_ftplugin .= " | setl cms< com< fo< flp< isk< | unlet! b:browsefilter" + let b:undo_ftplugin .= " | setl cms< com< fo< flp< isk< fex< | unlet! b:browsefilter" else - let b:undo_ftplugin = "setl cms< com< fo< flp< isk< | unlet! b:browsefilter" + let b:undo_ftplugin = "setl cms< com< fo< flp< isk< fex< | unlet! b:browsefilter" endif let &cpo = s:cpo_save diff --git a/runtime/ftplugin/rrst.vim b/runtime/ftplugin/rrst.vim index d088f98224..73ebb75fea 100644 --- a/runtime/ftplugin/rrst.vim +++ b/runtime/ftplugin/rrst.vim @@ -3,7 +3,9 @@ " Maintainer: This runtime file is looking for a new maintainer. " Former Maintainer: Jakson Alves de Aquino <jalvesaq@gmail.com> " Former Repository: https://github.com/jalvesaq/R-Vim-runtime -" Last Change: 2024 Feb 28 by Vim Project +" Last Change: +" 2024 Feb 28 by Vim Project +" 2024 Sep 23 by Vim Project: properly restore fex option " Original work by Alex Zvoleff " Only do this when not yet done for this buffer @@ -48,9 +50,9 @@ if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter") endif if exists('b:undo_ftplugin') - let b:undo_ftplugin .= " | setl cms< com< fo< flp< isk< | unlet! b:browsefilter" + let b:undo_ftplugin .= " | setl cms< com< fo< flp< isk< fex< | unlet! b:browsefilter" else - let b:undo_ftplugin = "setl cms< com< fo< flp< isk< | unlet! b:browsefilter" + let b:undo_ftplugin = "setl cms< com< fo< flp< isk< fex< | unlet! b:browsefilter" endif let &cpo = s:cpo_save diff --git a/runtime/ftplugin/rust.vim b/runtime/ftplugin/rust.vim index fb15b444d0..3e2741f919 100644 --- a/runtime/ftplugin/rust.vim +++ b/runtime/ftplugin/rust.vim @@ -1,7 +1,8 @@ -" Language: Rust -" Description: Vim ftplugin for Rust -" Maintainer: Chris Morgan <me@chrismorgan.info> -" Last Change: 2024-03-17 +" Language: Rust +" Description: Vim ftplugin for Rust +" Maintainer: Chris Morgan <me@chrismorgan.info> +" Last Change: 2024 Mar 17 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com ('commentstring') " For bugs, patches and license go to https://github.com/rust-lang/rust.vim if exists("b:did_ftplugin") @@ -36,7 +37,7 @@ if get(g:, 'rust_bang_comment_leader', 0) else setlocal comments=s0:/*!,ex:*/,s1:/*,mb:*,ex:*/,:///,://!,:// endif -setlocal commentstring=//%s +setlocal commentstring=//\ %s setlocal formatoptions-=t formatoptions+=croqnl " j was only added in 7.3.541, so stop complaints about its nonexistence silent! setlocal formatoptions+=j @@ -147,6 +148,7 @@ endif " Cleanup {{{1 let b:undo_ftplugin = " + \ compiler make | \ setlocal formatoptions< comments< commentstring< include< includeexpr< suffixesadd< \|if exists('b:rust_set_style') \|setlocal tabstop< shiftwidth< softtabstop< expandtab< textwidth< diff --git a/runtime/ftplugin/scdoc.vim b/runtime/ftplugin/scdoc.vim index 552c865baa..8225e437a8 100644 --- a/runtime/ftplugin/scdoc.vim +++ b/runtime/ftplugin/scdoc.vim @@ -1,7 +1,8 @@ " scdoc filetype plugin -" Maintainer: Gregory Anders <contact@gpanders.com> -" Last Updated: 2022-05-09 -" Upstream: https://github.com/gpanders/vim-scdoc +" Maintainer: Gregory Anders <contact@gpanders.com> +" Last Updated: 2022 May 09 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') +" Upstream: https://github.com/gpanders/vim-scdoc " Only do this when not done yet for this buffer if exists('b:did_ftplugin') @@ -12,7 +13,7 @@ endif let b:did_ftplugin = 1 setlocal comments=b:; -setlocal commentstring=;%s +setlocal commentstring=;\ %s setlocal formatoptions+=t setlocal noexpandtab setlocal shiftwidth=0 diff --git a/runtime/ftplugin/scheme.vim b/runtime/ftplugin/scheme.vim index 04655bc136..63e578199d 100644 --- a/runtime/ftplugin/scheme.vim +++ b/runtime/ftplugin/scheme.vim @@ -1,11 +1,12 @@ " Vim filetype plugin file -" Language: Scheme (R7RS) -" Last Change: 2019-11-19 -" Author: Evan Hanson <evhan@foldling.org> -" Maintainer: Evan Hanson <evhan@foldling.org> +" Language: Scheme (R7RS) +" Last Change: 2024 Jun 21 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') +" Author: Evan Hanson <evhan@foldling.org> +" Maintainer: Evan Hanson <evhan@foldling.org> " Previous Maintainer: Sergey Khorev <sergey.khorev@gmail.com> -" Repository: https://git.foldling.org/vim-scheme.git -" URL: https://foldling.org/vim/ftplugin/scheme.vim +" Repository: https://git.foldling.org/vim-scheme.git +" URL: https://foldling.org/vim/ftplugin/scheme.vim if exists('b:did_ftplugin') finish @@ -16,14 +17,16 @@ set cpo&vim setl lisp setl comments=:;;;;,:;;;,:;;,:;,sr:#\|,mb:\|,ex:\|# -setl commentstring=;%s +setl commentstring=;\ %s setl define=^\\s*(def\\k* setl iskeyword=33,35-39,42-43,45-58,60-90,94,95,97-122,126 +setl formatoptions-=t -let b:undo_ftplugin = 'setl lisp< comments< commentstring< define< iskeyword<' +let b:undo_ftplugin = 'setl lisp< comments< commentstring< define< iskeyword< formatoptions<' setl lispwords+=case setl lispwords+=define +setl lispwords+=define-library setl lispwords+=define-record-type setl lispwords+=define-syntax setl lispwords+=define-values diff --git a/runtime/ftplugin/sh.vim b/runtime/ftplugin/sh.vim index c47aa520e9..4c7695dcc6 100644 --- a/runtime/ftplugin/sh.vim +++ b/runtime/ftplugin/sh.vim @@ -4,7 +4,7 @@ " Previous Maintainer: Dan Sharp " Contributor: Enno Nagel <ennonagel+vim@gmail.com> " Eisuke Kawashima -" Last Change: 2024 May 06 by Vim Project (MANPAGER=) +" Last Change: 2024 Sep 19 by Vim Project (compiler shellcheck) if exists("b:did_ftplugin") finish @@ -45,15 +45,18 @@ if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter") endif if get(b:, "is_bash", 0) - if !has("gui_running") && executable("less") - command! -buffer -nargs=1 ShKeywordPrg silent exe '!bash -c "{ help "<args>" 2>/dev/null || MANPAGER= man "<args>"; } | LESS= less"' | redraw! - elseif has("terminal") + if exists(':terminal') == 2 command! -buffer -nargs=1 ShKeywordPrg silent exe ':term bash -c "help "<args>" 2>/dev/null || man "<args>""' else command! -buffer -nargs=1 ShKeywordPrg echo system('bash -c "help <args>" 2>/dev/null || MANPAGER= man "<args>"') endif setlocal keywordprg=:ShKeywordPrg let b:undo_ftplugin ..= " | setl kp< | sil! delc -buffer ShKeywordPrg" + + if !exists('current_compiler') + compiler shellcheck + endif + let b:undo_ftplugin .= ' | compiler make' endif let &cpo = s:save_cpo diff --git a/runtime/ftplugin/snakemake.vim b/runtime/ftplugin/snakemake.vim new file mode 100644 index 0000000000..ab90ca10b5 --- /dev/null +++ b/runtime/ftplugin/snakemake.vim @@ -0,0 +1,13 @@ +" Vim filetype plugin +" Language: snakemake +" Maintainer: Riley Bruins <ribru17@gmail.com> +" Last Change: 2024 Jun 13 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +setl comments=:# commentstring=#\ %s + +let b:undo_ftplugin = 'setl com< cms<' diff --git a/runtime/ftplugin/spec.vim b/runtime/ftplugin/spec.vim index 9040e19ce1..fa125be52c 100644 --- a/runtime/ftplugin/spec.vim +++ b/runtime/ftplugin/spec.vim @@ -2,8 +2,9 @@ " Filename: spec.vim " Maintainer: Igor Gnatenko i.gnatenko.brain@gmail.com " Former Maintainer: Gustavo Niemeyer <niemeyer@conectiva.com> (until March 2014) -" Last Change: Mon Jun 01 21:15 MSK 2015 Igor Gnatenko -" Update by Zdenek Dohnal, 2022 May 17 +" Last Change: 2015 Jun 01 +" Update by Zdenek Dohnal, 2022 May 17 +" 2024 Sep 10 by Vim Project: add epoch support for spec changelog, #15537 if exists("b:did_ftplugin") finish @@ -66,9 +67,11 @@ if !exists("*s:SpecChangelog") endif let line = 0 let name = "" + let epoch = "" let ver = "" let rel = "" let nameline = -1 + let epochline = -1 let verline = -1 let relline = -1 let chgline = -1 @@ -77,6 +80,9 @@ if !exists("*s:SpecChangelog") if name == "" && linestr =~? '^Name:' let nameline = line let name = substitute(strpart(linestr,5), '^[ ]*\([^ ]\+\)[ ]*$','\1','') + elseif epoch == "" && linestr =~? '^Epoch:' + let epochline = line + let epoch = substitute(strpart(linestr,6), '^[ ]*\([^ ]\+\)[ ]*$','\1','') elseif ver == "" && linestr =~? '^Version:' let verline = line let ver = substitute(strpart(linestr,8), '^[ ]*\([^ ]\+\)[ ]*$','\1','') @@ -93,6 +99,7 @@ if !exists("*s:SpecChangelog") if nameline != -1 && verline != -1 && relline != -1 let include_release_info = exists("g:spec_chglog_release_info") let name = s:ParseRpmVars(name, nameline) + let epoch = s:ParseRpmVars(epoch, epochline) let ver = s:ParseRpmVars(ver, verline) let rel = s:ParseRpmVars(rel, relline) else @@ -117,6 +124,9 @@ if !exists("*s:SpecChangelog") if chgline != -1 let tmptime = v:lc_time language time C + if strlen(epoch) + let ver = epoch.":".ver + endif let parsed_format = "* ".strftime(format)." - ".ver."-".rel execute "language time" tmptime let release_info = "+ ".name."-".ver."-".rel diff --git a/runtime/ftplugin/sql.vim b/runtime/ftplugin/sql.vim index 61b7e67255..3b56acd674 100644 --- a/runtime/ftplugin/sql.vim +++ b/runtime/ftplugin/sql.vim @@ -3,8 +3,9 @@ " Version: 12.0 " Maintainer: David Fishburn <dfishburn dot vim at gmail dot com> " Last Change: 2017 Mar 07 -" 2024 Jan 14 by Vim Project (browsefilter) -" 2024 May 18 by Vim Project (set comment options) +" 2024 Jan 14 by Vim Project: browsefilter +" 2024 May 18 by Vim Project: set comment options +" 2024 Aug 14 by Vim Project: remove redundant code " Download: http://vim.sourceforge.net/script.php?script_id=454 " For more details please use: @@ -92,13 +93,19 @@ " Only do this when not done yet for this buffer " This ftplugin can be used with other ftplugins. So ensure loading " happens if all elements of this plugin have not yet loaded. -if exists("b:did_ftplugin") && exists("b:current_ftplugin") && b:current_ftplugin == 'sql' +if exists("b:did_ftplugin") finish endif +" Don't load another plugin for this buffer +let b:did_ftplugin = 1 + let s:save_cpo = &cpo set cpo&vim +let b:undo_ftplugin = "setl comments< commentstring< formatoptions< define< omnifunc<" . + \ " | unlet! b:browsefilter b:match_words" + " Disable autowrapping for code, but enable for comments " t Auto-wrap text using textwidth " c Auto-wrap comments using textwidth, inserting the current comment @@ -263,19 +270,6 @@ elseif exists("g:sql_type_default") endif endif -" If the above runtime command succeeded, do not load the default settings -" as they should have already been loaded from a previous run. -if exists("b:did_ftplugin") && exists("b:current_ftplugin") && b:current_ftplugin == 'sql' - finish -endif - -let b:undo_ftplugin = "setl comments< commentstring< formatoptions< define< omnifunc<" . - \ " | unlet! b:browsefilter b:match_words" - -" Don't load another plugin for this buffer -let b:did_ftplugin = 1 -let b:current_ftplugin = 'sql' - " Win32 and GTK can filter files in the browse dialog if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter") let b:browsefilter = "SQL Files (*.sql)\t*.sql\n" diff --git a/runtime/ftplugin/squirrel.vim b/runtime/ftplugin/squirrel.vim new file mode 100644 index 0000000000..559be88001 --- /dev/null +++ b/runtime/ftplugin/squirrel.vim @@ -0,0 +1,17 @@ +" Vim filetype plugin +" Language: Squirrel +" Maintainer: Riley Bruins <ribru17@gmail.com> +" Last Change: 2024 Jul 06 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +" Set 'comments' to format dashed lists in comments. +" Also include ///, used for Doxygen. +setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:///,:// + +setlocal commentstring=//\ %s + +let b:undo_ftplugin = 'setl com< cms<' diff --git a/runtime/ftplugin/sshconfig.vim b/runtime/ftplugin/sshconfig.vim index 4a054da52f..1cc4e609b0 100644 --- a/runtime/ftplugin/sshconfig.vim +++ b/runtime/ftplugin/sshconfig.vim @@ -1,7 +1,8 @@ " Vim filetype plugin file -" Language: OpenSSH client configuration file -" Previous Maintainer: Nikolai Weibull <now@bitwi.se> -" Latest Revision: 2023-10-07 +" Language: OpenSSH client configuration file +" Maintainer: This runtime file is looking for a new maintainer. +" Previous Maintainer: Nikolai Weibull <now@bitwi.se> +" Latest Revision: 2024-09-19 (simplify keywordprg #15696) if exists("b:did_ftplugin") finish @@ -14,20 +15,12 @@ set cpo&vim setlocal comments=:# commentstring=#\ %s formatoptions-=t formatoptions+=croql let b:undo_ftplugin = 'setlocal com< cms< fo<' -if has('unix') && executable('less') - if !has('gui_running') - command -buffer -nargs=1 SshconfigKeywordPrg - \ silent exe '!' . 'LESS= MANPAGER="less --pattern=''^\s+' . <q-args> . '$'' --hilite-search" man ' . 'ssh_config' | - \ redraw! - elseif has('terminal') - command -buffer -nargs=1 SshconfigKeywordPrg - \ silent exe 'term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+' . <q-args> . '$', '\') . ''' --hilite-search" man ' . 'ssh_config' - endif - if exists(':SshconfigKeywordPrg') == 2 - setlocal iskeyword+=- - setlocal keywordprg=:SshconfigKeywordPrg - let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer SshconfigKeywordPrg' - endif +if has('unix') && executable('less') && exists(':terminal') == 2 + command -buffer -nargs=1 SshconfigKeywordPrg + \ silent exe 'term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s+' . <q-args> . '$', '\') . ''' --hilite-search" man ' . 'ssh_config' + setlocal iskeyword+=- + setlocal keywordprg=:SshconfigKeywordPrg + let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer SshconfigKeywordPrg' endif let &cpo = s:cpo_save diff --git a/runtime/ftplugin/stata.lua b/runtime/ftplugin/stata.lua new file mode 100644 index 0000000000..89ab42ef54 --- /dev/null +++ b/runtime/ftplugin/stata.lua @@ -0,0 +1,3 @@ +vim.bo.commentstring = '// %s' + +vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<' diff --git a/runtime/ftplugin/sudoers.vim b/runtime/ftplugin/sudoers.vim index 81ce7906a9..e87fedaa01 100644 --- a/runtime/ftplugin/sudoers.vim +++ b/runtime/ftplugin/sudoers.vim @@ -1,7 +1,8 @@ " Vim filetype plugin file -" Language: sudoers(5) configuration files -" Previous Maintainer: Nikolai Weibull <now@bitwi.se> -" Latest Revision: 2023-10-07 +" Language: sudoers(5) configuration files +" Maintainer: This runtime file is looking for a new maintainer. +" Previous Maintainer: Nikolai Weibull <now@bitwi.se> +" Latest Revision: 2024-09-19 (simplify keywordprg #15696) if exists("b:did_ftplugin") finish @@ -15,20 +16,12 @@ let b:undo_ftplugin = "setl com< cms< fo<" setlocal comments=:# commentstring=#\ %s formatoptions-=t formatoptions+=croql -if has('unix') && executable('less') - if !has('gui_running') - command -buffer -nargs=1 SudoersKeywordPrg - \ silent exe '!' . 'LESS= MANPAGER="less --pattern=''\b' . <q-args> . '\b'' --hilite-search" man ' . 'sudoers' | - \ redraw! - elseif has('terminal') - command -buffer -nargs=1 SudoersKeywordPrg - \ silent exe ':term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('\b' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'sudoers' - endif - if exists(':SudoersKeywordPrg') == 2 - setlocal iskeyword+=- - setlocal keywordprg=:SudoersKeywordPrg - let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer SudoersKeywordPrg' - endif +if has('unix') && executable('less') && exists(':terminal') == 2 + command -buffer -nargs=1 SudoersKeywordPrg + \ silent exe ':term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('\b' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'sudoers' + setlocal iskeyword+=- + setlocal keywordprg=:SudoersKeywordPrg + let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer SudoersKeywordPrg' endif let &cpo = s:cpo_save diff --git a/runtime/ftplugin/supercollider.lua b/runtime/ftplugin/supercollider.lua new file mode 100644 index 0000000000..89ab42ef54 --- /dev/null +++ b/runtime/ftplugin/supercollider.lua @@ -0,0 +1,3 @@ +vim.bo.commentstring = '// %s' + +vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<' diff --git a/runtime/ftplugin/svelte.vim b/runtime/ftplugin/svelte.vim new file mode 100644 index 0000000000..e0ec4e0ae3 --- /dev/null +++ b/runtime/ftplugin/svelte.vim @@ -0,0 +1,13 @@ +" Vim filetype plugin +" Language: svelte +" Maintainer: Igor Lacerda <igorlafarsi@gmail.com> +" Last Change: 2024 Jun 09 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +setl commentstring=<!--\ %s\ --> + +let b:undo_ftplugin = 'setl cms<' diff --git a/runtime/ftplugin/swift.lua b/runtime/ftplugin/swift.lua new file mode 100644 index 0000000000..89ab42ef54 --- /dev/null +++ b/runtime/ftplugin/swift.lua @@ -0,0 +1,3 @@ +vim.bo.commentstring = '// %s' + +vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<' diff --git a/runtime/ftplugin/systemd.vim b/runtime/ftplugin/systemd.vim index 8bcacdd381..1b1d242029 100644 --- a/runtime/ftplugin/systemd.vim +++ b/runtime/ftplugin/systemd.vim @@ -1,37 +1,30 @@ " Vim filetype plugin file " Language: systemd.unit(5) " Keyword Lookup Support: Enno Nagel <enno.nagel+vim@gmail.com> -" Latest Revision: 2023-10-07 +" Latest Revision: 2024-10-02 (small fixes to &keywordprg) -if !exists('b:did_ftplugin') - " Looks a lot like dosini files. - runtime! ftplugin/dosini.vim +if exists("b:did_ftplugin") + finish endif +" Looks a lot like dosini files. +runtime! ftplugin/dosini.vim -if has('unix') && executable('less') - if !has('gui_running') - command -buffer -nargs=1 SystemdKeywordPrg silent exe '!' . KeywordLookup_systemd(<q-args>) | redraw! - elseif has('terminal') - command -buffer -nargs=1 SystemdKeywordPrg silent exe 'term ' . KeywordLookup_systemd(<q-args>) - endif - if exists(':SystemdKeywordPrg') == 2 - if !exists('*KeywordLookup_systemd') - function KeywordLookup_systemd(keyword) abort - let matches = matchlist(getline(search('\v^\s*\[\s*.+\s*\]\s*$', 'nbWz')), '\v^\s*\[\s*(\k+).*\]\s*$') - if len(matches) > 1 - let section = matches[1] - return 'LESS= MANPAGER="less --pattern=''(^|,)\s+' . a:keyword . '=$'' --hilite-search" man ' . 'systemd.' . section - else - return 'LESS= MANPAGER="less --pattern=''(^|,)\s+' . a:keyword . '=$'' --hilite-search" man ' . 'systemd' - endif - endfunction - endif - setlocal iskeyword+=- - setlocal keywordprg=:SystemdKeywordPrg - if !exists('b:undo_ftplugin') || empty(b:undo_ftplugin) - let b:undo_ftplugin = 'setlocal keywordprg< iskeyword<' +if has('unix') && executable('less') && exists(':terminal') == 2 + command! -buffer -nargs=1 SystemdKeywordPrg silent exe 'term ++close ' KeywordLookup_systemd(<q-args>) + silent! function KeywordLookup_systemd(keyword) abort + let matches = matchlist(getline(search('\v^\s*\[\s*.+\s*\]\s*$', 'nbWz')), '\v^\s*\[\s*(\k+).*\]\s*$') + if len(matches) > 1 + let section = matches[1] + return 'env LESS= MANPAGER="less --pattern=''(^|,)\\s+' . a:keyword . '=$'' --hilite-search" man ' . 'systemd.' . section else - let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer SystemdKeywordPrg' + return 'env LESS= MANPAGER="less --pattern=''(^|,)\\s+' . a:keyword . '=$'' --hilite-search" man ' . 'systemd' endif + endfunction + setlocal iskeyword+=- + setlocal keywordprg=:SystemdKeywordPrg + if !exists('b:undo_ftplugin') || empty(b:undo_ftplugin) + let b:undo_ftplugin = 'setlocal keywordprg< iskeyword< | sil! delc -buffer SystemdKeywordPrg' + else + let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer SystemdKeywordPrg' endif endif diff --git a/runtime/ftplugin/tcl.vim b/runtime/ftplugin/tcl.vim index fa900096c0..214d9c256d 100644 --- a/runtime/ftplugin/tcl.vim +++ b/runtime/ftplugin/tcl.vim @@ -3,6 +3,7 @@ " Maintainer: Robert L Hicks <sigzero@gmail.com> " Latest Revision: 2009-05-01 " 2024 Jan 14 by Vim Project (browsefilter) +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") finish @@ -15,7 +16,7 @@ let s:cpo_save = &cpo set cpo-=C setlocal comments=:# -setlocal commentstring=#%s +setlocal commentstring=#\ %s setlocal formatoptions+=croql " Change the browse dialog on Windows to show mainly Tcl-related files diff --git a/runtime/ftplugin/terraform.vim b/runtime/ftplugin/terraform.vim new file mode 100644 index 0000000000..b03cab3638 --- /dev/null +++ b/runtime/ftplugin/terraform.vim @@ -0,0 +1,14 @@ +" Vim filetype plugin +" Language: terraform +" Maintainer: Janno Tjarks (janno.tjarks@mailbox.org) +" Last Change: 2024 Jul 3 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +setlocal commentstring=#\ %s +setlocal comments=://,:# + +let b:undo_ftplugin = "setlocal commentstring< comments<" diff --git a/runtime/ftplugin/tf.vim b/runtime/ftplugin/tf.vim new file mode 100644 index 0000000000..1571d5e508 --- /dev/null +++ b/runtime/ftplugin/tf.vim @@ -0,0 +1,13 @@ +" Vim filetype plugin +" Language: tf (TinyFugue) +" Maintainer: Riley Bruins <ribru17@gmail.com> +" Last Change: 2024 Jul 06 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +setl comments=:#,:; commentstring=;\ %s + +let b:undo_ftplugin = 'setl com< cms<' diff --git a/runtime/ftplugin/thrift.vim b/runtime/ftplugin/thrift.vim new file mode 100644 index 0000000000..dd18e19948 --- /dev/null +++ b/runtime/ftplugin/thrift.vim @@ -0,0 +1,17 @@ +" Vim filetype plugin file +" Language: Apache Thrift +" Maintainer: Yinzuo Jiang <jiangyinzuo@foxmail.com> +" Last Change: 2024/07/29 + +if exists("b:did_ftplugin") + finish +endif + +let b:did_ftplugin = 1 + +" Thrift supports shell-style, C-style multi-line as well as single-line Java/C++ style comments. +" Reference: https://diwakergupta.github.io/thrift-missing-guide/#_language_reference +setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:///,://,b:# +setlocal commentstring=//\ %s + +let b:undo_ftplugin = 'setl comments< commentstring<' diff --git a/runtime/ftplugin/typescript.vim b/runtime/ftplugin/typescript.vim index 680521df31..fb5f4e135f 100644 --- a/runtime/ftplugin/typescript.vim +++ b/runtime/ftplugin/typescript.vim @@ -2,6 +2,7 @@ " Language: TypeScript " Maintainer: Doug Kearns <dougkearns@gmail.com> " Last Change: 2024 Jan 14 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") finish @@ -18,7 +19,7 @@ setlocal formatoptions-=t formatoptions+=croql " Set 'comments' to format dashed lists in comments. setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// -setlocal commentstring=//%s +setlocal commentstring=//\ %s setlocal suffixesadd+=.ts,.d.ts,.tsx,.js,.jsx,.cjs,.mjs diff --git a/runtime/ftplugin/typst.vim b/runtime/ftplugin/typst.vim index c2d7811ace..895fc688d9 100644 --- a/runtime/ftplugin/typst.vim +++ b/runtime/ftplugin/typst.vim @@ -1,14 +1,27 @@ -" Vim filetype plugin -" Language: typst -" Maintainer: Riley Bruins <ribru17@gmail.com> -" Last Change: 2024 May 19 +" Vim filetype plugin file +" Language: Typst +" Maintainer: Gregory Anders +" Last Change: 2024 Oct 04 +" Based on: https://github.com/kaarmu/typst.vim if exists('b:did_ftplugin') finish endif let b:did_ftplugin = 1 -setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// setlocal commentstring=//\ %s +setlocal comments=s1:/*,mb:*,ex:*/,:// +setlocal formatoptions+=croq +setlocal suffixesadd=.typ -let b:undo_ftplugin = 'setl com< cms<' +let b:undo_ftplugin = 'setl cms< com< fo< sua<' + +if get(g:, 'typst_conceal', 0) + setlocal conceallevel=2 + let b:undo_ftplugin .= ' cole<' +endif + +if !exists('current_compiler') + compiler typst + let b:undo_ftplugin ..= "| compiler make" +endif diff --git a/runtime/ftplugin/udevrules.vim b/runtime/ftplugin/udevrules.vim index ec365f04c2..e6c7f113c2 100644 --- a/runtime/ftplugin/udevrules.vim +++ b/runtime/ftplugin/udevrules.vim @@ -1,7 +1,8 @@ " Vim filetype plugin file -" Language: udev(8) rules file -" Previous Maintainer: Nikolai Weibull <now@bitwi.se> -" Latest Revision: 2023-10-07 +" Language: udev(8) rules file +" Maintainer: This runtime file is looking for a new maintainer. +" Previous Maintainer: Nikolai Weibull <now@bitwi.se> +" Latest Revision: 2024-09-19 (simplify keywordprg #15696) if exists("b:did_ftplugin") finish @@ -15,20 +16,12 @@ let b:undo_ftplugin = "setl com< cms< fo<" setlocal comments=:# commentstring=#\ %s formatoptions-=t formatoptions+=croql -if has('unix') && executable('less') - if !has('gui_running') - command -buffer -nargs=1 UdevrulesKeywordPrg - \ silent exe '!' . 'LESS= MANPAGER="less --pattern=''^\s{,8}' . <q-args> . '\b'' --hilite-search" man ' . 'udev' | - \ redraw! - elseif has('terminal') - command -buffer -nargs=1 UdevrulesKeywordPrg - \ silent exe ':term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s{,8}' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'udev' - endif - if exists(':UdevrulesKeywordPrg') == 2 - setlocal iskeyword+=- - setlocal keywordprg=:UdevrulesKeywordPrg - let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer UdevrulesKeywordPrg' - endif +if has('unix') && executable('less') && exists(':terminal') == 2 + command -buffer -nargs=1 UdevrulesKeywordPrg + \ silent exe ':term ' . 'env LESS= MANPAGER="less --pattern=''' . escape('^\s{,8}' . <q-args> . '\b', '\') . ''' --hilite-search" man ' . 'udev' + setlocal iskeyword+=- + setlocal keywordprg=:UdevrulesKeywordPrg + let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword< | sil! delc -buffer UdevrulesKeywordPrg' endif let &cpo = s:cpo_save diff --git a/runtime/ftplugin/vim.vim b/runtime/ftplugin/vim.vim index 5c99df7f5a..b5e8e693f6 100644 --- a/runtime/ftplugin/vim.vim +++ b/runtime/ftplugin/vim.vim @@ -2,6 +2,7 @@ " Language: Vim " Maintainer: Doug Kearns <dougkearns@gmail.com> " Last Change: 2024 Apr 13 +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') " Former Maintainer: Bram Moolenaar <Bram@vim.org> " Only do this when not done yet for this buffer @@ -51,7 +52,7 @@ setlocal keywordprg=:help " Comments starts with # in Vim9 script. We have to guess which one to use. if "\n" .. getline(1, 32)->join("\n") =~# '\n\s*vim9\%[script]\>' - setlocal commentstring=#%s + setlocal commentstring=#\ %s else setlocal commentstring=\"%s endif @@ -66,9 +67,6 @@ if &tw == 0 setlocal tw=78 endif -" Prefer Vim help instead of manpages. -setlocal keywordprg=:help - if !exists("no_plugin_maps") && !exists("no_vim_maps") let b:did_add_maps = 1 diff --git a/runtime/ftplugin/wat.vim b/runtime/ftplugin/wat.vim index 35d2d6a322..ad1140bbb5 100644 --- a/runtime/ftplugin/wat.vim +++ b/runtime/ftplugin/wat.vim @@ -2,6 +2,7 @@ " Language: WebAssembly " Maintainer: rhysd <lin90162@yahoo.co.jp> " Last Change: Nov 14, 2023 +" May 24, 2024 by Riley Bruins <ribru17@gmail.com> ('commentstring') " For bugs, patches and license go to https://github.com/rhysd/vim-wasm if exists("b:did_ftplugin") @@ -10,7 +11,7 @@ endif let b:did_ftplugin = 1 setlocal comments=s:(;,e:;),:;; -setlocal commentstring=(;%s;) +setlocal commentstring=(;\ %s\ ;) setlocal formatoptions-=t setlocal iskeyword+=$,.,/ diff --git a/runtime/ftplugin/xdefaults.lua b/runtime/ftplugin/xdefaults.lua deleted file mode 100644 index b4e68148f5..0000000000 --- a/runtime/ftplugin/xdefaults.lua +++ /dev/null @@ -1 +0,0 @@ -vim.bo.commentstring = '/*%s*/' diff --git a/runtime/ftplugin/xdefaults.vim b/runtime/ftplugin/xdefaults.vim index c1aff70176..26c7516f8e 100644 --- a/runtime/ftplugin/xdefaults.vim +++ b/runtime/ftplugin/xdefaults.vim @@ -1,7 +1,8 @@ " Vim filetype plugin file -" Language: X resources files like ~/.Xdefaults (xrdb) -" Previous Maintainer: Nikolai Weibull <now@bitwi.se> -" Latest Revision: 2008-07-09 +" Language: X resources files like ~/.Xdefaults (xrdb) +" Previous Maintainer: Nikolai Weibull <now@bitwi.se> +" Latest Revision: 2008 Jul 09 +" 2024 Jun 03 by Riley Bruins <ribru17@gmail.com> ('commentstring') if exists("b:did_ftplugin") finish @@ -13,7 +14,7 @@ set cpo&vim let b:undo_ftplugin = "setl com< cms< inc< fo<" -setlocal comments=s1:/*,mb:*,ex:*/,:! commentstring& inc& +setlocal comments=s1:/*,mb:*,ex:*/,:! commentstring=!\ %s inc& setlocal formatoptions-=t formatoptions+=croql let &cpo = s:cpo_save diff --git a/runtime/ftplugin/xml.vim b/runtime/ftplugin/xml.vim index b81c3980d2..83c528eff2 100644 --- a/runtime/ftplugin/xml.vim +++ b/runtime/ftplugin/xml.vim @@ -3,6 +3,7 @@ " Maintainer: Christian Brabandt <cb@256bit.org> " Last Changed: Dec 07th, 2018 " 2024 Jan 14 by Vim Project (browsefilter) +" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring') " Repository: https://github.com/chrisbra/vim-xml-ftplugin " Previous Maintainer: Dan Sharp " URL: http://dwsharp.users.sourceforge.net/vim/ftplugin @@ -15,7 +16,7 @@ let b:did_ftplugin = 1 let s:save_cpo = &cpo set cpo&vim -setlocal commentstring=<!--%s--> +setlocal commentstring=<!--\ %s\ --> " Remove the middlepart from the comments section, as this causes problems: " https://groups.google.com/d/msg/vim_dev/x4GT-nqa0Kg/jvtRnEbtAnMJ setlocal comments=s:<!--,e:--> diff --git a/runtime/ftplugin/xs.lua b/runtime/ftplugin/xs.lua new file mode 100644 index 0000000000..89ab42ef54 --- /dev/null +++ b/runtime/ftplugin/xs.lua @@ -0,0 +1,3 @@ +vim.bo.commentstring = '// %s' + +vim.b.undo_ftplugin = (vim.b.undo_ftplugin or '') .. '\n setl commentstring<' diff --git a/runtime/ftplugin/yacc.vim b/runtime/ftplugin/yacc.vim new file mode 100644 index 0000000000..d95e1ee600 --- /dev/null +++ b/runtime/ftplugin/yacc.vim @@ -0,0 +1,16 @@ +" Vim filetype plugin +" Language: Yacc +" Maintainer: Riley Bruins <ribru17@gmail.com> +" Last Change: 2024 Jul 06 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +" Set 'comments' to format dashed lists in comments. +" Also include ///, used for Doxygen. +setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:///,:// +setlocal commentstring=//\ %s + +let b:undo_ftplugin = 'setl com< cms<' diff --git a/runtime/ftplugin/yaml.vim b/runtime/ftplugin/yaml.vim index 8bfc45e4c8..4e12350c22 100644 --- a/runtime/ftplugin/yaml.vim +++ b/runtime/ftplugin/yaml.vim @@ -1,7 +1,7 @@ " Vim filetype plugin file " Language: YAML (YAML Ain't Markup Language) " Previous Maintainer: Nikolai Weibull <now@bitwi.se> (inactive) -" Last Change: 2020 Mar 02 +" Last Change: 2024 Oct 04 if exists("b:did_ftplugin") finish @@ -18,7 +18,10 @@ setlocal formatoptions-=t formatoptions+=croql " rime input method engine uses `*.custom.yaml` as its config files if expand('%:r:e') ==# 'custom' - compiler rime_deployer + if !exists('current_compiler') + compiler rime_deployer + let b:undo_ftplugin ..= "| compiler make" + endif setlocal include=__include:\\s* let b:undo_ftplugin ..= " inc<" endif diff --git a/runtime/ftplugin/zig.vim b/runtime/ftplugin/zig.vim index ea229b6a49..ea584ed086 100644 --- a/runtime/ftplugin/zig.vim +++ b/runtime/ftplugin/zig.vim @@ -1,7 +1,7 @@ " Vim filetype plugin file " Language: Zig " Maintainer: Mathias Lindgren <math.lindgren@gmail.com> -" Last Change: 2024 May 21 +" Last Change: 2024 Oct 04 " Based on: https://github.com/ziglang/zig.vim if exists("b:did_ftplugin") @@ -13,8 +13,6 @@ let b:did_ftplugin = 1 let s:cpo_save = &cpo set cpo&vim -compiler zig_build - " Match Zig builtin fns setlocal iskeyword+=@-@ setlocal formatoptions-=t formatoptions+=croql @@ -47,6 +45,11 @@ if exists('g:zig_std_dir') let b:undo_ftplugin .= ' | setl pa<' endif +if !exists('current_compiler') + compiler zig_build + let b:undo_ftplugin .= "| compiler make" +endif + let &cpo = s:cpo_save unlet s:cpo_save " vim: tabstop=8 shiftwidth=4 softtabstop=4 expandtab diff --git a/runtime/ftplugin/zsh.vim b/runtime/ftplugin/zsh.vim index aee890024f..5d4f4fe256 100644 --- a/runtime/ftplugin/zsh.vim +++ b/runtime/ftplugin/zsh.vim @@ -2,7 +2,7 @@ " Language: Zsh shell script " Maintainer: Christian Brabandt <cb@256bit.org> " Previous Maintainer: Nikolai Weibull <now@bitwi.se> -" Latest Revision: 2024 May 06 by Vim Project (MANPAGER=) +" Latest Revision: 2024 Sep 19 " License: Vim (see :h license) " Repository: https://github.com/chrisbra/vim-zsh @@ -19,18 +19,18 @@ setlocal comments=:# commentstring=#\ %s formatoptions-=t formatoptions+=croql let b:undo_ftplugin = "setl com< cms< fo< " if executable('zsh') && &shell !~# '/\%(nologin\|false\)$' - if !has('gui_running') && executable('less') - command! -buffer -nargs=1 ZshKeywordPrg silent exe '!MANPAGER= zsh -c "autoload -Uz run-help; run-help <args> 2>/dev/null | LESS= less"' | redraw! - elseif has('terminal') + if exists(':terminal') == 2 command! -buffer -nargs=1 ZshKeywordPrg silent exe ':term zsh -c "autoload -Uz run-help; run-help <args>"' else command! -buffer -nargs=1 ZshKeywordPrg echo system('MANPAGER= zsh -c "autoload -Uz run-help; run-help <args> 2>/dev/null"') endif + setlocal keywordprg=:ZshKeywordPrg + let b:undo_ftplugin .= '| setl keywordprg< | sil! delc -buffer ZshKeywordPrg' + if !exists('current_compiler') compiler zsh endif - setlocal keywordprg=:ZshKeywordPrg - let b:undo_ftplugin .= 'keywordprg< | sil! delc -buffer ZshKeywordPrg' + let b:undo_ftplugin .= ' | compiler make' endif let b:match_words = '\<if\>:\<elif\>:\<else\>:\<fi\>' diff --git a/runtime/indent/asm.vim b/runtime/indent/asm.vim deleted file mode 100644 index 054612b9d6..0000000000 --- a/runtime/indent/asm.vim +++ /dev/null @@ -1,29 +0,0 @@ -" Vim indent file -" Language: asm -" Maintainer: Philip Jones <philj56@gmail.com> -" Upstream: https://github.com/philj56/vim-asm-indent -" Last Change: 2017-Jul-01 -" 2024 Apr 25 by Vim Project (undo_indent) - -if exists("b:did_indent") - finish -endif -let b:did_indent = 1 - -setlocal indentexpr=s:getAsmIndent() -setlocal indentkeys=<:>,!^F,o,O - -let b:undo_indent = "setlocal indentexpr< indentkeys<" - -function! s:getAsmIndent() - let line = getline(v:lnum) - let ind = shiftwidth() - - " If the line is a label (starts with ':' terminated keyword), - " then don't indent - if line =~ '^\s*\k\+:' - let ind = 0 - endif - - return ind -endfunction diff --git a/runtime/indent/glsl.vim b/runtime/indent/glsl.vim new file mode 100644 index 0000000000..4ebee60656 --- /dev/null +++ b/runtime/indent/glsl.vim @@ -0,0 +1,14 @@ +" Language: OpenGL Shading Language +" Maintainer: Gregory Anders <greg@gpanders.com> +" Last Modified: 2024 Jul 21 +" Upstream: https://github.com/tikhomirov/vim-glsl + +if exists('b:did_indent') + finish +endif +let b:did_indent = 1 + +setlocal autoindent cindent +setlocal cinoptions& + +let b:undo_indent = 'setl ai< ci< cino<' diff --git a/runtime/indent/hare.vim b/runtime/indent/hare.vim index 0a9d8dafd8..1b51d1e80a 100644 --- a/runtime/indent/hare.vim +++ b/runtime/indent/hare.vim @@ -1,19 +1,16 @@ " Vim indent file -" Language: Hare -" Maintainer: Amelia Clarke <me@rsaihe.dev> -" Last Change: 2022 Sep 22 -" 2023 Aug 28 by Vim Project (undo_indent) +" Language: Hare +" Maintainer: Amelia Clarke <selene@perilune.dev> +" Last Change: 2024-04-14 +" Upstream: https://git.sr.ht/~sircmpwn/hare.vim -if exists("b:did_indent") +if exists('b:did_indent') finish endif let b:did_indent = 1 -if !has("cindent") || !has("eval") - finish -endif - -setlocal cindent +let s:cpo_save = &cpo +set cpo&vim " L0 -> don't deindent labels " (s -> use one indent after a trailing ( @@ -41,7 +38,11 @@ setlocal cinwords=if,else,for,switch,match setlocal indentexpr=GetHareIndent() -let b:undo_indent = "setl cin< cino< cinw< inde< indk<" +let b:undo_indent = 'setl cino< cinw< inde< indk<' + +if exists('*GetHareIndent()') + finish +endif function! FloorCindent(lnum) return cindent(a:lnum) / shiftwidth() * shiftwidth() @@ -122,7 +123,8 @@ function! GetHareIndent() " Indent the body of a case. " If the previous line ended in a semicolon and the line before that was a " case, don't do any special indenting. - if prevline =~# '\v;\s*(//.*)?$' && prevprevline =~# '\v\=\>\s*(//.*)?$' && line !~# '\v^\s*}' + if prevline =~# '\v;\s*(//.*)?$' && prevprevline =~# '\v\=\>\s*(//.*)?$' + \ && line !~# '\v^\s*}' return indent(prevlnum) endif @@ -138,4 +140,7 @@ function! GetHareIndent() return l:indent endfunction -" vim: tabstop=2 shiftwidth=2 expandtab +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim: et sw=2 sts=2 ts=8 diff --git a/runtime/indent/hcl.vim b/runtime/indent/hcl.vim new file mode 100644 index 0000000000..b13d2c5649 --- /dev/null +++ b/runtime/indent/hcl.vim @@ -0,0 +1,16 @@ +" Vim indent file +" Language: HCL +" Maintainer: Gregory Anders +" Upstream: https://github.com/hashivim/vim-terraform +" Last Change: 2024-09-03 + +if exists('b:did_indent') + finish +endif +let b:did_indent = 1 + +setlocal autoindent shiftwidth=2 tabstop=2 softtabstop=2 expandtab +setlocal indentexpr=hcl#indentexpr(v:lnum) +setlocal indentkeys+=<:>,0=},0=) + +let b:undo_indent = 'setlocal ai< sw< ts< sts< et< inde< indk<' diff --git a/runtime/indent/kdl.vim b/runtime/indent/kdl.vim new file mode 100644 index 0000000000..b0a6bd90d9 --- /dev/null +++ b/runtime/indent/kdl.vim @@ -0,0 +1,30 @@ +" Vim indent file +" Language: KDL +" Author: Aram Drevekenin <aram@poor.dev> +" Maintainer: Yinzuo Jiang <jiangyinzuo@foxmail.com> +" Last Change: 2024-06-16 + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal indentexpr=KdlIndent() +let b:undo_indent = "setlocal indentexpr<" + +function! KdlIndent(...) + let line = substitute(getline(v:lnum), '//.*$', '', '') + let previousNum = prevnonblank(v:lnum - 1) + let previous = substitute(getline(previousNum), '//.*$', '', '') + + let l:indent = indent(previousNum) + if previous =~ "{" && previous !~ "}" + let l:indent += shiftwidth() + endif + if line =~ "}" && line !~ "{" + let l:indent -= shiftwidth() + endif + return l:indent +endfunction +" vim: sw=2 sts=2 et diff --git a/runtime/indent/lua.vim b/runtime/indent/lua.vim index 35b08d4037..ce6cfe18cd 100644 --- a/runtime/indent/lua.vim +++ b/runtime/indent/lua.vim @@ -4,6 +4,7 @@ " First Author: Max Ischenko <mfi 'at' ukr.net> " Last Change: 2017 Jun 13 " 2022 Sep 07: b:undo_indent added by Doug Kearns +" 2024 Jul 27: by Vim project: match '(', ')' in function GetLuaIndentIntern() " Only load this indent file when no other was loaded. if exists("b:did_indent") @@ -46,12 +47,12 @@ function! GetLuaIndentIntern() endif " Add a 'shiftwidth' after lines that start a block: - " 'function', 'if', 'for', 'while', 'repeat', 'else', 'elseif', '{' + " 'function', 'if', 'for', 'while', 'repeat', 'else', 'elseif', '{', '(' let ind = indent(prevlnum) let prevline = getline(prevlnum) let midx = match(prevline, '^\s*\%(if\>\|for\>\|while\>\|repeat\>\|else\>\|elseif\>\|do\>\|then\>\)') if midx == -1 - let midx = match(prevline, '{\s*\%(--\%([^[].*\)\?\)\?$') + let midx = match(prevline, '\%({\|(\)\s*\%(--\%([^[].*\)\?\)\?$') if midx == -1 let midx = match(prevline, '\<function\>\s*\%(\k\|[.:]\)\{-}\s*(') endif @@ -65,9 +66,9 @@ function! GetLuaIndentIntern() endif endif - " Subtract a 'shiftwidth' on end, else, elseif, until and '}' + " Subtract a 'shiftwidth' on end, else, elseif, until, '}' and ')' " This is the part that requires 'indentkeys'. - let midx = match(getline(v:lnum), '^\s*\%(end\>\|else\>\|elseif\>\|until\>\|}\)') + let midx = match(getline(v:lnum), '^\s*\%(end\>\|else\>\|elseif\>\|until\>\|}\|)\)') if midx != -1 && synIDattr(synID(v:lnum, midx + 1, 1), "name") != "luaComment" let ind = ind - shiftwidth() endif diff --git a/runtime/indent/mojo.vim b/runtime/indent/mojo.vim new file mode 100644 index 0000000000..9b6a7d4c58 --- /dev/null +++ b/runtime/indent/mojo.vim @@ -0,0 +1,6 @@ +" Vim indent file +" Language: Mojo +" Maintainer: Riley Bruins <ribru17@gmail.com> +" Last Change: 2024 Jul 07 + +runtime! indent/python.vim diff --git a/runtime/indent/ocaml.vim b/runtime/indent/ocaml.vim index c9beb8be0b..d137796e3d 100644 --- a/runtime/indent/ocaml.vim +++ b/runtime/indent/ocaml.vim @@ -4,8 +4,7 @@ " Mike Leary <leary@nwlink.com> " Markus Mottl <markus.mottl@gmail.com> " URL: https://github.com/ocaml/vim-ocaml -" Last Change: 2023 Aug 28 - Add undo_indent (Vim Project) -" 2017 Jun 13 +" Last Change: 2017 Jun 13 " 2005 Jun 25 - Fixed multiple bugs due to 'else\nreturn ind' working " 2005 May 09 - Added an option to not indent OCaml-indents specially (MM) " 2013 June - commented textwidth (Marc Weber) @@ -36,6 +35,7 @@ if !exists("no_ocaml_comments") setlocal comments=sr:(*\ ,mb:\ ,ex:*) setlocal comments^=sr:(**,mb:\ \ ,ex:*) setlocal fo=cqort + let b:undo_indent .= " | setl com< fo<" endif endif diff --git a/runtime/indent/proto.vim b/runtime/indent/proto.vim new file mode 100644 index 0000000000..743f14094b --- /dev/null +++ b/runtime/indent/proto.vim @@ -0,0 +1,19 @@ +" Vim indent file +" Language: Protobuf +" Maintainer: David Pedersen <limero@me.com> +" Last Change: 2024 Aug 07 + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +" Protobuf is like indenting C +setlocal cindent +setlocal expandtab +setlocal shiftwidth=2 + +let b:undo_indent = "setlocal cindent< expandtab< shiftwidth<" + +" vim: sw=2 sts=2 et diff --git a/runtime/indent/query.lua b/runtime/indent/query.lua index 3261376d87..c5b4f1f03d 100644 --- a/runtime/indent/query.lua +++ b/runtime/indent/query.lua @@ -1,6 +1,6 @@ -- Neovim indent file -- Language: Treesitter query --- Last Change: 2022 Mar 29 +-- Last Change: 2024 Jul 03 -- it's a lisp! -vim.cmd([[ runtime! indent/lisp.vim ]]) +vim.cmd([[runtime! indent/lisp.vim]]) diff --git a/runtime/indent/rust.vim b/runtime/indent/rust.vim index 7c055ec739..a96650d419 100644 --- a/runtime/indent/rust.vim +++ b/runtime/indent/rust.vim @@ -2,7 +2,10 @@ " Language: Rust " Author: Chris Morgan <me@chrismorgan.info> " Last Change: 2023-09-11 +" 2024 Jul 04 by Vim Project: use shiftwidth() instead of hard-coding shifted values (#15138) + " For bugs, patches and license go to https://github.com/rust-lang/rust.vim +" Note: upstream seems umaintained: https://github.com/rust-lang/rust.vim/issues/502 " Only load this indent file when no other was loaded. if exists("b:did_indent") @@ -179,7 +182,7 @@ function GetRustIndent(lnum) " A standalone 'where' adds a shift. let l:standalone_prevline_where = prevline =~# '\V\^\s\*where\s\*\$' if l:standalone_prevline_where - return indent(prevlinenum) + 4 + return indent(prevlinenum) + shiftwidth() endif " Handle where clauses nicely: subsequent values should line up nicely. @@ -197,7 +200,7 @@ function GetRustIndent(lnum) let l:scope_start = searchpair('{\|(', '', '}\|)', 'nbW', \ 's:is_string_comment(line("."), col("."))') if l:scope_start != 0 && l:scope_start < a:lnum - return indent(l:scope_start) + 4 + return indent(l:scope_start) + shiftwidth() endif endif @@ -268,7 +271,7 @@ function GetRustIndent(lnum) " It's the closing line, dedent it return 0 else - return &shiftwidth + return shiftwidth() endif endif endif diff --git a/runtime/indent/scheme.vim b/runtime/indent/scheme.vim index 496da3267d..888659b1de 100644 --- a/runtime/indent/scheme.vim +++ b/runtime/indent/scheme.vim @@ -1,9 +1,10 @@ " Vim indent file -" Language: Scheme -" Last Change: 2018 Jan 31 -" Maintainer: Evan Hanson <evhan@foldling.org> +" Language: Scheme +" Last Change: 2024 Jun 21 +" Maintainer: Evan Hanson <evhan@foldling.org> " Previous Maintainer: Sergey Khorev <sergey.khorev@gmail.com> -" URL: https://foldling.org/vim/indent/scheme.vim +" Repository: https://git.foldling.org/vim-scheme.git +" URL: https://foldling.org/vim/indent/scheme.vim " Only load this indent file when no other was loaded. if exists("b:did_indent") diff --git a/runtime/indent/terraform.vim b/runtime/indent/terraform.vim new file mode 100644 index 0000000000..d62813d6a2 --- /dev/null +++ b/runtime/indent/terraform.vim @@ -0,0 +1,11 @@ +" Vim indent file +" Language: Terraform +" Maintainer: Gregory Anders +" Upstream: https://github.com/hashivim/vim-terraform +" Last Change: 2024-09-03 + +if exists('b:did_indent') + finish +endif + +runtime! indent/hcl.vim diff --git a/runtime/indent/testdir/lua.in b/runtime/indent/testdir/lua.in new file mode 100644 index 0000000000..c8f5d2bb8d --- /dev/null +++ b/runtime/indent/testdir/lua.in @@ -0,0 +1,19 @@ +-- vim: set ft=lua sw=2 noet: + +-- START_INDENT +function foo(a, b, c, d) + return { a, b, c, d } +end + +local a = foo( +1, +2, +"longxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", +4 +) + +local b = { +1, + 2, +} +-- END_INDENT diff --git a/runtime/indent/testdir/lua.ok b/runtime/indent/testdir/lua.ok new file mode 100644 index 0000000000..95f9873beb --- /dev/null +++ b/runtime/indent/testdir/lua.ok @@ -0,0 +1,19 @@ +-- vim: set ft=lua sw=2 noet: + +-- START_INDENT +function foo(a, b, c, d) + return { a, b, c, d } +end + +local a = foo( + 1, + 2, + "longxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + 4 +) + +local b = { + 1, + 2, +} +-- END_INDENT diff --git a/runtime/indent/testdir/thrift.in b/runtime/indent/testdir/thrift.in new file mode 100644 index 0000000000..7490dc8d30 --- /dev/null +++ b/runtime/indent/testdir/thrift.in @@ -0,0 +1,38 @@ +// vim: set ft=thrift sw=4 et: + +# START_INDENT +namespace cpp foo +namespace java com.foo.thrift + +include "Status.thrift" + +// These are supporting structs for JniFrontend.java, which serves as the glue +// between our C++ execution environment and the Java frontend. + +struct TSetSessionParams { + 1: required string user +} + +struct TAuthenticateParams { + 1: required string user + 2: required string passwd + 3: optional string host +4: optional string db_name + 5: optional list<string> table_names; +} + +/* { + * xxxx + * } + */ +// TColumnDesc +struct TColumnDesc { + // { +4: optional string tableName +5: optional string columnDefault + // Let FE control the type, which makes it easier to modify and display complex types +6: optional string columnTypeStr // deprecated +7: optional string dataType + // } +} +# END_INDENT diff --git a/runtime/indent/testdir/thrift.ok b/runtime/indent/testdir/thrift.ok new file mode 100644 index 0000000000..9e2a48242b --- /dev/null +++ b/runtime/indent/testdir/thrift.ok @@ -0,0 +1,38 @@ +// vim: set ft=thrift sw=4 et: + +# START_INDENT +namespace cpp foo +namespace java com.foo.thrift + +include "Status.thrift" + +// These are supporting structs for JniFrontend.java, which serves as the glue +// between our C++ execution environment and the Java frontend. + +struct TSetSessionParams { + 1: required string user +} + +struct TAuthenticateParams { + 1: required string user + 2: required string passwd + 3: optional string host + 4: optional string db_name + 5: optional list<string> table_names; +} + +/* { + * xxxx + * } + */ +// TColumnDesc +struct TColumnDesc { + // { + 4: optional string tableName + 5: optional string columnDefault + // Let FE control the type, which makes it easier to modify and display complex types + 6: optional string columnTypeStr // deprecated + 7: optional string dataType + // } +} +# END_INDENT diff --git a/runtime/indent/thrift.vim b/runtime/indent/thrift.vim new file mode 100644 index 0000000000..e0860e12a2 --- /dev/null +++ b/runtime/indent/thrift.vim @@ -0,0 +1,74 @@ +" Vim indent file +" Language: Apache Thrift +" Maintainer: Yinzuo Jiang <jiangyinzuo@foxmail.com> +" Last Change: 2024/07/29 + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal cindent +setlocal indentexpr=GetThriftIndent() + +let b:undo_indent = "set cindent< indentexpr<" + +" Only define the function once. +if exists("*GetThriftIndent") + finish +endif + +let s:keepcpo= &cpo +set cpo&vim + +function! SkipThriftBlanksAndComments(startline) + let lnum = a:startline + while lnum > 1 + let lnum = prevnonblank(lnum) + if getline(lnum) =~ '\*/\s*$' + while getline(lnum) !~ '/\*' && lnum > 1 + let lnum = lnum - 1 + endwhile + if getline(lnum) =~ '^\s*/\*' + let lnum = lnum - 1 + else + break + endif + elseif getline(lnum) =~ '^\s*\(//\|#\)' + let lnum = lnum - 1 + else + break + endif + endwhile + return lnum +endfunction + +function GetThriftIndent() + " Thrift is just like C; use the built-in C indenting and then correct a few + " specific cases. + let theIndent = cindent(v:lnum) + + " If we're in the middle of a comment then just trust cindent + if getline(v:lnum) =~ '^\s*\*' + return theIndent + endif + + let line = substitute(getline(v:lnum), '\(//\|#\).*$', '', '') + let previousNum = SkipThriftBlanksAndComments(v:lnum - 1) + let previous = substitute(getline(previousNum), '\(//\|#\).*$', '', '') + + let l:indent = indent(previousNum) + if previous =~ "{" && previous !~ "}" + let l:indent += shiftwidth() + endif + if line =~ "}" && line !~ "{" + let l:indent -= shiftwidth() + endif + return l:indent +endfunction + +let &cpo = s:keepcpo +unlet s:keepcpo + +" vim: sw=2 sts=2 et diff --git a/runtime/indent/typst.vim b/runtime/indent/typst.vim new file mode 100644 index 0000000000..6aaa04a53a --- /dev/null +++ b/runtime/indent/typst.vim @@ -0,0 +1,18 @@ +" Vim indent file +" Language: Typst +" Maintainer: Gregory Anders <greg@gpanders.com> +" Last Change: 2024-07-14 +" Based on: https://github.com/kaarmu/typst.vim + +if exists('b:did_indent') + finish +endif +let b:did_indent = 1 + +setlocal expandtab +setlocal softtabstop=2 +setlocal shiftwidth=2 +setlocal autoindent +setlocal indentexpr=typst#indentexpr() + +let b:undo_indent = 'setl et< sts< sw< ai< inde<' diff --git a/runtime/indent/yaml.vim b/runtime/indent/yaml.vim index e5daf9f219..c38712745d 100644 --- a/runtime/indent/yaml.vim +++ b/runtime/indent/yaml.vim @@ -3,7 +3,8 @@ " Maintainer: Nikolai Pavlov <zyx.vim@gmail.com> " Last Updates: Lukas Reineke, "lacygoill" " Last Change: 2022 Jun 17 -" 2024 Feb 29 disable mulitline indent by default (The Vim project) +" 2024 Feb 29 by Vim project: disable mulitline indent by default +" 2024 Aug 14 by Vim project: fix re-indenting when commenting out lines " Only load this indent file when no other was loaded. if exists('b:did_indent') @@ -13,7 +14,7 @@ endif let b:did_indent = 1 setlocal indentexpr=GetYAMLIndent(v:lnum) -setlocal indentkeys=!^F,o,O,0#,0},0],<:>,0- +setlocal indentkeys=!^F,o,O,0},0],<:>,0- setlocal nosmartindent let b:undo_indent = 'setlocal indentexpr< indentkeys< smartindent<' diff --git a/runtime/keymap/georgian-qwerty.vim b/runtime/keymap/georgian-qwerty.vim new file mode 100644 index 0000000000..df18729f06 --- /dev/null +++ b/runtime/keymap/georgian-qwerty.vim @@ -0,0 +1,51 @@ +" Vim keymap file for Georgian (Mkhedruli) layout +" Maintainer: Mishiko Okropiridze <misho.okropiridze@gmail.com> +" Last changed: 2024-06-14 + + +let b:keymap_name = "ge" + +loadkeymap +a რ+A რ+b ბ +c ც +C ჩ +d დ +e ე +E ე +f ფ +F ფ +g გ +G გ +h ჰ +H ჵ +i ი +I ი +j ჯ +J ჟ +k კ +l ლ +m მ +n ნ +o რ+p პ +q ქ +Q ქ +r რ+R ღ +s ს +S შ +t ტ +T თ +u უ +v ვ +V ვ +w წ +W რ+x ხ +X ხ +y ყ +Y ყ +z ზ +Z ძ diff --git a/runtime/lua/editorconfig.lua b/runtime/lua/editorconfig.lua index dcd7425c29..e65d267a70 100644 --- a/runtime/lua/editorconfig.lua +++ b/runtime/lua/editorconfig.lua @@ -190,6 +190,27 @@ function properties.insert_final_newline(bufnr, val) end end +--- A code of the format ss or ss-TT, where ss is an ISO 639 language code and TT is an ISO 3166 territory identifier. +--- Sets the 'spelllang' option. +function properties.spelling_language(bufnr, val) + local error_msg = + 'spelling_language must be of the format ss or ss-TT, where ss is an ISO 639 language code and TT is an ISO 3166 territory identifier.' + + assert(val:len() == 2 or val:len() == 5, error_msg) + + local language_code = val:sub(1, 2):lower() + assert(language_code:match('%l%l'), error_msg) + if val:len() == 2 then + vim.bo[bufnr].spelllang = language_code + else + assert(val:sub(3, 3) == '-', error_msg) + + local territory_code = val:sub(4, 5):lower() + assert(territory_code:match('%l%l'), error_msg) + vim.bo[bufnr].spelllang = language_code .. '_' .. territory_code + end +end + --- @private --- Modified version of [glob2regpat()] that does not match path separators on `*`. --- diff --git a/runtime/lua/man.lua b/runtime/lua/man.lua index 02e841030f..fce8f89be8 100644 --- a/runtime/lua/man.lua +++ b/runtime/lua/man.lua @@ -35,7 +35,7 @@ local function highlight_line(line, linenr) ---@type string[] local chars = {} local prev_char = '' - local overstrike, escape = false, false + local overstrike, escape, osc8 = false, false, false ---@type table<integer,{attr:integer,start:integer,final:integer}> local hls = {} -- Store highlight groups as { attr, start, final } @@ -139,6 +139,12 @@ local function highlight_line(line, linenr) prev_char = '' byte = byte + #char chars[#chars + 1] = char + elseif osc8 then + -- eat characters until String Terminator or bell + if (prev_char == '\027' and char == '\\') or char == '\a' then + osc8 = false + end + prev_char = char elseif escape then -- Use prev_char to store the escape sequence prev_char = prev_char .. char @@ -157,8 +163,11 @@ local function highlight_line(line, linenr) add_attr_hl(match + 0) -- coerce to number end escape = false - elseif not prev_char:match('^%[[\032-\063]*$') then - -- Stop looking if this isn't a partial CSI sequence + elseif prev_char == ']8;' then + osc8 = true + escape = false + elseif not prev_char:match('^[][][\032-\063]*$') then + -- Stop looking if this isn't a partial CSI or OSC sequence escape = false end elseif char == '\027' then @@ -470,7 +479,13 @@ local function put_page(page) -- XXX: nroff justifies text by filling it with whitespace. That interacts -- badly with our use of $MANWIDTH=999. Hack around this by using a fixed -- size for those whitespace regions. - vim.cmd([[silent! keeppatterns keepjumps %s/\s\{199,}/\=repeat(' ', 10)/g]]) + -- Use try/catch to avoid setting v:errmsg. + vim.cmd([[ + try + keeppatterns keepjumps %s/\s\{199,}/\=repeat(' ', 10)/g + catch + endtry + ]]) vim.cmd('1') -- Move cursor to first line highlight_man_page() set_options() @@ -708,7 +723,7 @@ function M.open_page(count, smods, args) end sect, name = extract_sect_and_name_path(path) - local buf = fn.bufnr() + local buf = api.nvim_get_current_buf() local save_tfu = vim.bo[buf].tagfunc vim.bo[buf].tagfunc = "v:lua.require'man'.goto_tag" @@ -724,7 +739,9 @@ function M.open_page(count, smods, args) end end) - vim.bo[buf].tagfunc = save_tfu + if api.nvim_buf_is_valid(buf) then + vim.bo[buf].tagfunc = save_tfu + end if not ok then error(ret) diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index 505de720ba..ed42b28725 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -1,6 +1,6 @@ --- @brief ---<pre>help ----:TOhtml {file} *:TOhtml* +---:[range]TOhtml {file} *:TOhtml* ---Converts the buffer shown in the current window to HTML, opens the generated ---HTML in a new split window, and saves its contents to {file}. If {file} is not ---given, a temporary file (created by |tempname()|) is used. @@ -40,13 +40,14 @@ --- @field winid integer --- @field bufnr integer --- @field width integer ---- @field buflen integer +--- @field start integer +--- @field end_ integer --- @class (private) vim.tohtml.styletable --- @field [integer] vim.tohtml.line (integer: (1-index, exclusive)) --- @class (private) vim.tohtml.line ---- @field virt_lines {[integer]:{[1]:string,[2]:integer}[]} +--- @field virt_lines {[integer]:[string,integer][]} --- @field pre_text string[][] --- @field hide? boolean --- @field [integer] vim.tohtml.cell? (integer: (1-index, exclusive)) @@ -57,6 +58,24 @@ --- @field [3] any[][] virt_text --- @field [4] any[][] overlay_text +--- @type string[] +local notifications = {} + +---@param msg string +local function notify(msg) + if #notifications == 0 then + vim.schedule(function() + if #notifications > 1 then + vim.notify(('TOhtml: %s (+ %d more warnings)'):format(notifications[1], #notifications - 1)) + elseif #notifications == 1 then + vim.notify('TOhtml: ' .. notifications[1]) + end + notifications = {} + end) + end + table.insert(notifications, msg) +end + local HIDE_ID = -1 -- stylua: ignore start local cterm_8_to_hex={ @@ -168,6 +187,8 @@ local background_color_cache = nil --- @type string? local foreground_color_cache = nil +local len = vim.api.nvim_strwidth + --- @see https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands --- @param color "background"|"foreground"|integer --- @return string? @@ -215,7 +236,7 @@ local function cterm_to_hex(colorstr) if hex then cterm_color_cache[color] = hex else - vim.notify_once("Info(TOhtml): Couldn't get terminal colors, using fallback") + notify("Couldn't get terminal colors, using fallback") local t_Co = tonumber(vim.api.nvim_eval('&t_Co')) if t_Co <= 8 then cterm_color_cache = cterm_8_to_hex @@ -241,7 +262,7 @@ local function get_background_color() end local hex = try_query_terminal_color('background') if not hex or not hex:match('#%x%x%x%x%x%x') then - vim.notify_once("Info(TOhtml): Couldn't get terminal background colors, using fallback") + notify("Couldn't get terminal background colors, using fallback") hex = vim.o.background == 'light' and '#ffffff' or '#000000' end background_color_cache = hex @@ -259,7 +280,7 @@ local function get_foreground_color() end local hex = try_query_terminal_color('foreground') if not hex or not hex:match('#%x%x%x%x%x%x') then - vim.notify_once("Info(TOhtml): Couldn't get terminal foreground colors, using fallback") + notify("Couldn't get terminal foreground colors, using fallback") hex = vim.o.background == 'light' and '#000000' or '#ffffff' end foreground_color_cache = hex @@ -292,9 +313,12 @@ local function style_line_insert_virt_text(style_line, col, val) end --- @param state vim.tohtml.state ---- @param hl string|integer|nil +--- @param hl string|integer|string[]|integer[]? --- @return nil|integer local function register_hl(state, hl) + if type(hl) == 'table' then + hl = hl[#hl] + end if type(hl) == 'nil' then return elseif type(hl) == 'string' then @@ -370,7 +394,7 @@ end --- @param state vim.tohtml.state local function styletable_syntax(state) - for row = 1, state.buflen do + for row = state.start, state.end_ do local prev_id = 0 local prev_col = nil for col = 1, #vim.fn.getline(row) + 1 do @@ -390,7 +414,7 @@ end --- @param state vim.tohtml.state local function styletable_diff(state) local styletable = state.style - for row = 1, state.buflen do + for row = state.start, state.end_ do local style_line = styletable[row] local filler = vim.fn.diff_filler(row) if filler ~= 0 then @@ -400,7 +424,7 @@ local function styletable_diff(state) { { fill:rep(state.width), register_hl(state, 'DiffDelete') } } ) end - if row == state.buflen + 1 then + if row == state.end_ + 1 then break end local prev_id = 0 @@ -442,7 +466,9 @@ local function styletable_treesitter(state) if not query then return end - for capture, node, metadata in query:iter_captures(root, buf_highlighter.bufnr, 0, state.buflen) do + for capture, node, metadata in + query:iter_captures(root, buf_highlighter.bufnr, state.start - 1, state.end_) + do local srow, scol, erow, ecol = node:range() --- @diagnostic disable-next-line: invisible local c = q._query.captures[capture] @@ -458,7 +484,7 @@ local function styletable_treesitter(state) end --- @param state vim.tohtml.state ---- @param extmark {[1]:integer,[2]:integer,[3]:integer,[4]:vim.api.keyset.set_extmark|any} +--- @param extmark [integer, integer, integer, vim.api.keyset.set_extmark|any] --- @param namespaces table<integer,string> local function _styletable_extmarks_highlight(state, extmark, namespaces) if not extmark[4].hl_group then @@ -467,7 +493,7 @@ local function _styletable_extmarks_highlight(state, extmark, namespaces) ---TODO(altermo) LSP semantic tokens (and some other extmarks) are only ---generated in visible lines, and not in the whole buffer. if (namespaces[extmark[4].ns_id] or ''):find('vim_lsp_semantic_tokens') then - vim.notify_once('Info(TOhtml): lsp semantic tokens are not supported, HTML may be incorrect') + notify('lsp semantic tokens are not supported, HTML may be incorrect') return end local srow, scol, erow, ecol = @@ -480,18 +506,28 @@ local function _styletable_extmarks_highlight(state, extmark, namespaces) end --- @param state vim.tohtml.state ---- @param extmark {[1]:integer,[2]:integer,[3]:integer,[4]:vim.api.keyset.set_extmark|any} -local function _styletable_extmarks_virt_text(state, extmark) +--- @param extmark [integer, integer, integer, vim.api.keyset.set_extmark|any] +--- @param namespaces table<integer,string> +local function _styletable_extmarks_virt_text(state, extmark, namespaces) if not extmark[4].virt_text then return end + ---TODO(altermo) LSP semantic tokens (and some other extmarks) are only + ---generated in visible lines, and not in the whole buffer. + if (namespaces[extmark[4].ns_id] or ''):find('vim_lsp_inlayhint') then + notify('lsp inlay hints are not supported, HTML may be incorrect') + return + end local styletable = state.style --- @type integer,integer local row, col = extmark[2], extmark[3] if - extmark[4].virt_text_pos == 'inline' - or extmark[4].virt_text_pos == 'eol' - or extmark[4].virt_text_pos == 'overlay' + row < vim.api.nvim_buf_line_count(state.bufnr) + and ( + extmark[4].virt_text_pos == 'inline' + or extmark[4].virt_text_pos == 'eol' + or extmark[4].virt_text_pos == 'overlay' + ) then if extmark[4].virt_text_pos == 'eol' then style_line_insert_virt_text(styletable[row + 1], #vim.fn.getline(row + 1) + 1, { ' ' }) @@ -510,7 +546,7 @@ local function _styletable_extmarks_virt_text(state, extmark) else style_line_insert_virt_text(styletable[row + 1], col + 1, { i[1], hlid }) end - virt_text_len = virt_text_len + #i[1] + virt_text_len = virt_text_len + len(i[1]) end if extmark[4].virt_text_pos == 'overlay' then styletable_insert_range(state, row + 1, col + 1, row + 1, col + virt_text_len + 1, HIDE_ID) @@ -521,17 +557,15 @@ local function _styletable_extmarks_virt_text(state, extmark) hl_mode = 'blend', hl_group = 'combine', } - for opt, val in ipairs(not_supported) do + for opt, val in pairs(not_supported) do if extmark[4][opt] == val then - vim.notify_once( - ('Info(TOhtml): extmark.%s="%s" is not supported, HTML may be incorrect'):format(opt, val) - ) + notify(('extmark.%s="%s" is not supported, HTML may be incorrect'):format(opt, val)) end end end --- @param state vim.tohtml.state ---- @param extmark {[1]:integer,[2]:integer,[3]:integer,[4]:vim.api.keyset.set_extmark|any} +--- @param extmark [integer, integer, integer, vim.api.keyset.set_extmark|any] local function _styletable_extmarks_virt_lines(state, extmark) ---TODO(altermo) if the fold start is equal to virt_line start then the fold hides the virt_line if not extmark[4].virt_lines then @@ -552,7 +586,7 @@ local function _styletable_extmarks_virt_lines(state, extmark) end --- @param state vim.tohtml.state ---- @param extmark {[1]:integer,[2]:integer,[3]:integer,[4]:vim.api.keyset.set_extmark|any} +--- @param extmark [integer, integer, integer, vim.api.keyset.set_extmark|any] local function _styletable_extmarks_conceal(state, extmark) if not extmark[4].conceal or state.opt.conceallevel == 0 then return @@ -586,7 +620,7 @@ local function styletable_extmarks(state) _styletable_extmarks_conceal(state, v) end for _, v in ipairs(extmarks) do - _styletable_extmarks_virt_text(state, v) + _styletable_extmarks_virt_text(state, v, namespaces) end for _, v in ipairs(extmarks) do _styletable_extmarks_virt_lines(state, v) @@ -597,7 +631,7 @@ end local function styletable_folds(state) local styletable = state.style local has_folded = false - for row = 1, state.buflen do + for row = state.start, state.end_ do if vim.fn.foldclosed(row) > 0 then has_folded = true styletable[row].hide = true @@ -611,18 +645,16 @@ local function styletable_folds(state) end end if has_folded and type(({ pcall(vim.api.nvim_eval, vim.o.foldtext) })[2]) == 'table' then - vim.notify_once( - 'Info(TOhtml): foldtext returning a table is half supported, HTML may be incorrect' - ) + notify('foldtext returning a table with highlights is not supported, HTML may be incorrect') end end --- @param state vim.tohtml.state local function styletable_conceal(state) local bufnr = state.bufnr - vim.api.nvim_buf_call(bufnr, function() - for row = 1, state.buflen do - --- @type table<integer,{[1]:integer,[2]:integer,[3]:string}> + vim._with({ buf = bufnr }, function() + for row = state.start, state.end_ do + --- @type table<integer,[integer,integer,string]> local conceals = {} local line_len_exclusive = #vim.fn.getline(row) + 1 for col = 1, line_len_exclusive do @@ -738,8 +770,8 @@ local function styletable_statuscolumn(state) if foldcolumn:match('^auto') then local max = tonumber(foldcolumn:match('^%w-:(%d)')) or 1 local maxfold = 0 - vim.api.nvim_buf_call(state.bufnr, function() - for row = 1, vim.api.nvim_buf_line_count(state.bufnr) do + vim._with({ buf = state.bufnr }, function() + for row = state.start, state.end_ do local foldlevel = vim.fn.foldlevel(row) if foldlevel > maxfold then maxfold = foldlevel @@ -754,12 +786,12 @@ local function styletable_statuscolumn(state) --- @type table<integer,any> local statuses = {} - for row = 1, state.buflen do + for row = state.start, state.end_ do local status = vim.api.nvim_eval_statusline( statuscolumn, { winid = state.winid, use_statuscol_lnum = row, highlights = true } ) - local width = vim.api.nvim_strwidth(status.str) + local width = len(status.str) if width > minwidth then minwidth = width end @@ -774,7 +806,7 @@ local function styletable_statuscolumn(state) for k, v in ipairs(hls) do local text = str:sub(v.start + 1, hls[k + 1] and hls[k + 1].start or nil) if k == #hls then - text = text .. (' '):rep(minwidth - vim.api.nvim_strwidth(str)) + text = text .. (' '):rep(minwidth - len(str)) end if text ~= '' then local hlid = register_hl(state, v.group) @@ -794,7 +826,6 @@ local function styletable_listchars(state) local function utf8_sub(str, i, j) return vim.fn.strcharpart(str, i - 1, j and j - i + 1 or nil) end - local len = vim.api.nvim_strwidth --- @type table<string,string> local listchars = vim.opt_local.listchars:get() local ids = setmetatable({}, { @@ -805,7 +836,7 @@ local function styletable_listchars(state) }) if listchars.eol then - for row = 1, state.buflen do + for row = state.start, state.end_ do local style_line = state.style[row] style_line_insert_overlay_char( style_line, @@ -972,6 +1003,7 @@ local function extend_style(out, state) --TODO(altermo) use local namespace (instead of global 0) local fg = vim.fn.synIDattr(hlid, 'fg#') local bg = vim.fn.synIDattr(hlid, 'bg#') + local sp = vim.fn.synIDattr(hlid, 'sp#') local decor_line = {} if vim.fn.synIDattr(hlid, 'underline') ~= '' then table.insert(decor_line, 'underline') @@ -989,6 +1021,8 @@ local function extend_style(out, state) ['font-weight'] = vim.fn.synIDattr(hlid, 'bold') ~= '' and 'bold' or nil, ['text-decoration-line'] = not vim.tbl_isempty(decor_line) and table.concat(decor_line, ' ') or nil, + -- TODO(ribru17): fallback to displayed text color if sp not set + ['text-decoration-color'] = sp ~= '' and cterm_to_hex(sp) or nil, --TODO(altermo) if strikethrough and undercurl then the strikethrough becomes wavy ['text-decoration-style'] = vim.fn.synIDattr(hlid, 'undercurl') ~= '' and 'wavy' or nil, } @@ -1099,16 +1133,22 @@ end local function extend_pre(out, state) local styletable = state.style table.insert(out, '<pre>') + local out_start = #out local hide_count = 0 --- @type integer[] local stack = {} + local before = '' + local after = '' local function loop(row) + local inside = row <= state.end_ and row >= state.start local style_line = styletable[row] if style_line.hide and (styletable[row - 1] or {}).hide then return end - _extend_virt_lines(out, state, row) + if inside then + _extend_virt_lines(out, state, row) + end --Possible improvement (altermo): --Instead of looping over all the buffer characters per line, --why not loop over all the style_line cells, @@ -1118,8 +1158,16 @@ local function extend_pre(out, state) end local line = vim.api.nvim_buf_get_lines(state.bufnr, row - 1, row, false)[1] or '' local s = '' - s = s .. _pre_text_to_html(state, row) - for col = 1, #line + 1 do + if inside then + s = s .. _pre_text_to_html(state, row) + end + local true_line_len = #line + 1 + for k in pairs(style_line) do + if type(k) == 'number' and k > true_line_len then + true_line_len = k + end + end + for col = 1, true_line_len do local cell = style_line[col] --- @type table? local char @@ -1159,18 +1207,18 @@ local function extend_pre(out, state) end end - if cell[3] then + if cell[3] and inside then s = s .. _virt_text_to_html(state, cell) end char = cell[4][#cell[4]] end - if col == #line + 1 and not char then + if col == true_line_len and not char then break end - if hide_count == 0 then + if hide_count == 0 and inside then s = s .. _char_to_html( state, @@ -1179,12 +1227,20 @@ local function extend_pre(out, state) ) end end - table.insert(out, s) + if row > state.end_ + 1 then + after = after .. s + elseif row < state.start then + before = s .. before + else + table.insert(out, s) + end end - for row = 1, state.buflen + 1 do + for row = 1, vim.api.nvim_buf_line_count(state.bufnr) + 1 do loop(row) end + out[out_start] = out[out_start] .. before + out[#out] = out[#out] .. after assert(#stack == 0, 'an open HTML tag was never closed') table.insert(out, '</pre>') end @@ -1216,6 +1272,7 @@ local function global_state_to_state(winid, global_state) if not width or width < 1 then width = vim.api.nvim_win_get_width(winid) end + local range = opt.range or { 1, vim.api.nvim_buf_line_count(bufnr) } local state = setmetatable({ winid = winid == 0 and vim.api.nvim_get_current_win() or winid, opt = vim.wo[winid], @@ -1223,7 +1280,8 @@ local function global_state_to_state(winid, global_state) bufnr = bufnr, tabstop = (' '):rep(vim.bo[bufnr].tabstop), width = width, - buflen = vim.api.nvim_buf_line_count(bufnr), + start = range[1], + end_ = range[2], }, { __index = global_state }) return state --[[@as vim.tohtml.state]] end @@ -1235,9 +1293,25 @@ local function opt_to_global_state(opt, title) local fonts = {} if opt.font then fonts = type(opt.font) == 'string' and { opt.font } or opt.font --[[@as (string[])]] + for i, v in pairs(fonts) do + fonts[i] = ('"%s"'):format(v) + end elseif vim.o.guifont:match('^[^:]+') then - table.insert(fonts, vim.o.guifont:match('^[^:]+')) + -- Example: + -- Input: "Font,Escape\,comma, Ignore space after comma" + -- Output: { "Font","Escape,comma","Ignore space after comma" } + local prev = '' + for name in vim.gsplit(vim.o.guifont:match('^[^:]+'), ',', { trimempty = true }) do + if vim.endswith(name, '\\') then + prev = prev .. vim.trim(name:sub(1, -2) .. ',') + elseif vim.trim(name) ~= '' then + table.insert(fonts, ('"%s%s"'):format(prev, vim.trim(name))) + prev = '' + end + end end + -- Generic family names (monospace here) must not be quoted + -- because the browser recognizes them as font families. table.insert(fonts, 'monospace') --- @type vim.tohtml.state.global local state = { @@ -1266,7 +1340,7 @@ local styletable_funcs = { --- @param state vim.tohtml.state local function state_generate_style(state) - vim.api.nvim_win_call(state.winid, function() + vim._with({ win = state.winid }, function() for _, fn in ipairs(styletable_funcs) do --- @type string? local cond @@ -1282,35 +1356,22 @@ local function state_generate_style(state) end) end ---- @param winid integer[]|integer +--- @param winid integer --- @param opt? vim.tohtml.opt --- @return string[] local function win_to_html(winid, opt) - if type(winid) == 'number' then - winid = { winid } - end - --- @cast winid integer[] - assert(#winid > 0, 'no window specified') opt = opt or {} - local title = table.concat( - vim.tbl_map(vim.api.nvim_buf_get_name, vim.tbl_map(vim.api.nvim_win_get_buf, winid)), - ',' - ) + local title = vim.api.nvim_buf_get_name(vim.api.nvim_win_get_buf(winid)) + local global_state = opt_to_global_state(opt, title) - --- @type vim.tohtml.state[] - local states = {} - for _, i in ipairs(winid) do - local state = global_state_to_state(i, global_state) - state_generate_style(state) - table.insert(states, state) - end + local state = global_state_to_state(winid, global_state) + state_generate_style(state) + local html = {} extend_html(html, function() extend_head(html, global_state) extend_body(html, function() - for _, state in ipairs(states) do - extend_pre(html, state) - end + extend_pre(html, state) end) end) return html @@ -1337,6 +1398,10 @@ local M = {} --- infinitely. --- (default: 'textwidth' if non-zero or window width otherwise) --- @field width? integer +--- +--- Range of rows to use. +--- (default: entire buffer) +--- @field range? integer[] --- Converts the buffer shown in the window {winid} to HTML and returns the output as a list of string. --- @param winid? integer Window to convert (defaults to current window) diff --git a/runtime/lua/vim/_comment.lua b/runtime/lua/vim/_comment.lua index 044cd69716..de7f62632c 100644 --- a/runtime/lua/vim/_comment.lua +++ b/runtime/lua/vim/_comment.lua @@ -9,8 +9,8 @@ local function get_commentstring(ref_position) local buf_cs = vim.bo.commentstring - local has_ts_parser, ts_parser = pcall(vim.treesitter.get_parser) - if not has_ts_parser then + local ts_parser = vim.treesitter.get_parser(0, '', { error = false }) + if not ts_parser then return buf_cs end @@ -194,14 +194,9 @@ local function toggle_lines(line_start, line_end, ref_position) -- - Debatable for highlighting in text area (like LSP semantic tokens). -- Mostly because it causes flicker as highlighting is preserved during -- comment toggling. - package.loaded['vim._comment']._lines = vim.tbl_map(f, lines) - local lua_cmd = string.format( - 'vim.api.nvim_buf_set_lines(0, %d, %d, false, package.loaded["vim._comment"]._lines)', - line_start - 1, - line_end - ) - vim.cmd.lua({ lua_cmd, mods = { lockmarks = true } }) - package.loaded['vim._comment']._lines = nil + vim._with({ lockmarks = true }, function() + vim.api.nvim_buf_set_lines(0, line_start - 1, line_end, false, vim.tbl_map(f, lines)) + end) end --- Operator which toggles user-supplied range of lines diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua index 5b964b84a0..6cad1dbca9 100644 --- a/runtime/lua/vim/_defaults.lua +++ b/runtime/lua/vim/_defaults.lua @@ -85,13 +85,13 @@ do vim.keymap.set( 'x', 'Q', - "mode() == 'V' ? ':normal! @<C-R>=reg_recorded()<CR><CR>' : 'Q'", + "mode() ==# 'V' ? ':normal! @<C-R>=reg_recorded()<CR><CR>' : 'Q'", { silent = true, expr = true, desc = ':help v_Q-default' } ) vim.keymap.set( 'x', '@', - "mode() == 'V' ? ':normal! @'.getcharstr().'<CR>' : '@'", + "mode() ==# 'V' ? ':normal! @'.getcharstr().'<CR>' : '@'", { silent = true, expr = true, desc = ':help v_@-default' } ) @@ -113,9 +113,11 @@ do local gx_desc = 'Opens filepath or URI under cursor with the system handler (file explorer, web browser, …)' vim.keymap.set({ 'n' }, 'gx', function() - local err = do_open(require('vim.ui')._get_url()) - if err then - vim.notify(err, vim.log.levels.ERROR) + for _, url in ipairs(require('vim.ui')._get_urls()) do + local err = do_open(url) + if err then + vim.notify(err, vim.log.levels.ERROR) + end end end, { desc = gx_desc }) vim.keymap.set({ 'x' }, 'gx', function() @@ -180,12 +182,20 @@ do --- See |[d-default|, |]d-default|, and |CTRL-W_d-default|. do vim.keymap.set('n', ']d', function() - vim.diagnostic.goto_next({ float = false }) - end, { desc = 'Jump to the next diagnostic' }) + vim.diagnostic.jump({ count = vim.v.count1 }) + end, { desc = 'Jump to the next diagnostic in the current buffer' }) vim.keymap.set('n', '[d', function() - vim.diagnostic.goto_prev({ float = false }) - end, { desc = 'Jump to the previous diagnostic' }) + vim.diagnostic.jump({ count = -vim.v.count1 }) + end, { desc = 'Jump to the previous diagnostic in the current buffer' }) + + vim.keymap.set('n', ']D', function() + vim.diagnostic.jump({ count = math.huge, wrap = false }) + end, { desc = 'Jump to the last diagnostic in the current buffer' }) + + vim.keymap.set('n', '[D', function() + vim.diagnostic.jump({ count = -math.huge, wrap = false }) + end, { desc = 'Jump to the first diagnostic in the current buffer' }) vim.keymap.set('n', '<C-W>d', function() vim.diagnostic.open_float() @@ -198,13 +208,187 @@ do { remap = true, desc = 'Show diagnostics under the cursor' } ) end + + --- vim-unimpaired style mappings. See: https://github.com/tpope/vim-unimpaired + do + -- Quickfix mappings + vim.keymap.set('n', '[q', function() + vim.cmd.cprevious({ count = vim.v.count1 }) + end, { + desc = ':cprevious', + }) + + vim.keymap.set('n', ']q', function() + vim.cmd.cnext({ count = vim.v.count1 }) + end, { + desc = ':cnext', + }) + + vim.keymap.set('n', '[Q', function() + vim.cmd.crewind({ count = vim.v.count ~= 0 and vim.v.count or nil }) + end, { + desc = ':crewind', + }) + + vim.keymap.set('n', ']Q', function() + vim.cmd.clast({ count = vim.v.count ~= 0 and vim.v.count or nil }) + end, { + desc = ':clast', + }) + + vim.keymap.set('n', '[<C-Q>', function() + vim.cmd.cpfile({ count = vim.v.count1 }) + end, { + desc = ':cpfile', + }) + + vim.keymap.set('n', ']<C-Q>', function() + vim.cmd.cnfile({ count = vim.v.count1 }) + end, { + desc = ':cnfile', + }) + + -- Location list mappings + vim.keymap.set('n', '[l', function() + vim.cmd.lprevious({ count = vim.v.count1 }) + end, { + desc = ':lprevious', + }) + + vim.keymap.set('n', ']l', function() + vim.cmd.lnext({ count = vim.v.count1 }) + end, { + desc = ':lnext', + }) + + vim.keymap.set('n', '[L', function() + vim.cmd.lrewind({ count = vim.v.count ~= 0 and vim.v.count or nil }) + end, { + desc = ':lrewind', + }) + + vim.keymap.set('n', ']L', function() + vim.cmd.llast({ count = vim.v.count ~= 0 and vim.v.count or nil }) + end, { + desc = ':llast', + }) + + vim.keymap.set('n', '[<C-L>', function() + vim.cmd.lpfile({ count = vim.v.count1 }) + end, { + desc = ':lpfile', + }) + + vim.keymap.set('n', ']<C-L>', function() + vim.cmd.lnfile({ count = vim.v.count1 }) + end, { + desc = ':lnfile', + }) + + -- Argument list + vim.keymap.set('n', '[a', function() + vim.cmd.previous({ count = vim.v.count1 }) + end, { + desc = ':previous', + }) + + vim.keymap.set('n', ']a', function() + -- count doesn't work with :next, must use range. See #30641. + vim.cmd.next({ range = { vim.v.count1 } }) + end, { + desc = ':next', + }) + + vim.keymap.set('n', '[A', function() + if vim.v.count ~= 0 then + vim.cmd.argument({ count = vim.v.count }) + else + vim.cmd.rewind() + end + end, { + desc = ':rewind', + }) + + vim.keymap.set('n', ']A', function() + if vim.v.count ~= 0 then + vim.cmd.argument({ count = vim.v.count }) + else + vim.cmd.last() + end + end, { + desc = ':last', + }) + + -- Tags + vim.keymap.set('n', '[t', function() + -- count doesn't work with :tprevious, must use range. See #30641. + vim.cmd.tprevious({ range = { vim.v.count1 } }) + end, { desc = ':tprevious' }) + + vim.keymap.set('n', ']t', function() + -- count doesn't work with :tnext, must use range. See #30641. + vim.cmd.tnext({ range = { vim.v.count1 } }) + end, { desc = ':tnext' }) + + vim.keymap.set('n', '[T', function() + -- count doesn't work with :trewind, must use range. See #30641. + vim.cmd.trewind({ range = vim.v.count ~= 0 and { vim.v.count } or nil }) + end, { desc = ':trewind' }) + + vim.keymap.set('n', ']T', function() + -- :tlast does not accept a count, so use :trewind if count given + if vim.v.count ~= 0 then + vim.cmd.trewind({ range = { vim.v.count } }) + else + vim.cmd.tlast() + end + end, { desc = ':tlast' }) + + vim.keymap.set('n', '[<C-T>', function() + -- count doesn't work with :ptprevious, must use range. See #30641. + vim.cmd.ptprevious({ range = { vim.v.count1 } }) + end, { desc = ' :ptprevious' }) + + vim.keymap.set('n', ']<C-T>', function() + -- count doesn't work with :ptnext, must use range. See #30641. + vim.cmd.ptnext({ range = { vim.v.count1 } }) + end, { desc = ':ptnext' }) + + -- Buffers + vim.keymap.set('n', '[b', function() + vim.cmd.bprevious({ count = vim.v.count1 }) + end, { desc = ':bprevious' }) + + vim.keymap.set('n', ']b', function() + vim.cmd.bnext({ count = vim.v.count1 }) + end, { desc = ':bnext' }) + + vim.keymap.set('n', '[B', function() + if vim.v.count ~= 0 then + vim.cmd.buffer({ count = vim.v.count }) + else + vim.cmd.brewind() + end + end, { desc = ':brewind' }) + + vim.keymap.set('n', ']B', function() + if vim.v.count ~= 0 then + vim.cmd.buffer({ count = vim.v.count }) + else + vim.cmd.blast() + end + end, { desc = ':blast' }) + end end --- Default menus do --- Right click popup menu - -- TODO VimScript, no l10n vim.cmd([[ + anoremenu PopUp.Go\ to\ definition <Cmd>lua vim.lsp.buf.definition()<CR> + amenu PopUp.Open\ in\ web\ browser gx + anoremenu PopUp.Inspect <Cmd>Inspect<CR> + anoremenu PopUp.-1- <Nop> vnoremenu PopUp.Cut "+x vnoremenu PopUp.Copy "+y anoremenu PopUp.Paste "+gP @@ -213,10 +397,36 @@ do nnoremenu PopUp.Select\ All ggVG vnoremenu PopUp.Select\ All gg0oG$ inoremenu PopUp.Select\ All <C-Home><C-O>VG - anoremenu PopUp.Inspect <Cmd>Inspect<CR> - anoremenu PopUp.-1- <Nop> + anoremenu PopUp.-2- <Nop> anoremenu PopUp.How-to\ disable\ mouse <Cmd>help disable-mouse<CR> ]]) + + local function enable_ctx_menu(ctx) + vim.cmd([[ + amenu disable PopUp.Go\ to\ definition + amenu disable PopUp.Open\ in\ web\ browser + ]]) + + if ctx == 'url' then + vim.cmd([[amenu enable PopUp.Open\ in\ web\ browser]]) + elseif ctx == 'lsp' then + vim.cmd([[anoremenu enable PopUp.Go\ to\ definition]]) + end + end + + local nvim_popupmenu_augroup = vim.api.nvim_create_augroup('nvim_popupmenu', {}) + vim.api.nvim_create_autocmd('MenuPopup', { + pattern = '*', + group = nvim_popupmenu_augroup, + desc = 'Mouse popup menu', + -- nested = true, + callback = function() + local urls = require('vim.ui')._get_urls() + local url = vim.startswith(urls[1], 'http') + local ctx = url and 'url' or (vim.lsp.get_clients({ bufnr = 0 })[1] and 'lsp' or nil) + enable_ctx_menu(ctx) + end, + }) end --- Default autocommands. See |default-autocmds| @@ -274,6 +484,26 @@ do end, }) + vim.api.nvim_create_autocmd('TermOpen', { + group = nvim_terminal_augroup, + desc = 'Default settings for :terminal buffers', + callback = function() + vim.bo.modifiable = false + vim.bo.undolevels = -1 + vim.bo.scrollback = vim.o.scrollback < 0 and 10000 or math.max(1, vim.o.scrollback) + vim.bo.textwidth = 0 + vim.wo[0][0].wrap = false + vim.wo[0][0].list = false + + -- This is gross. Proper list options support when? + local winhl = vim.o.winhighlight + if winhl ~= '' then + winhl = winhl .. ',' + end + vim.wo[0][0].winhighlight = winhl .. 'StatusLine:StatusLineTerm,StatusLineNC:StatusLineTermNC' + end, + }) + vim.api.nvim_create_autocmd('CmdwinEnter', { pattern = '[:>]', desc = 'Limit syntax sync to maxlines=1 in the command window', @@ -462,10 +692,14 @@ do --- response indicates that it does support truecolor enable 'termguicolors', --- but only if the user has not already disabled it. do - if tty.rgb then - -- The TUI was able to determine truecolor support + local colorterm = os.getenv('COLORTERM') + if tty.rgb or colorterm == 'truecolor' or colorterm == '24bit' then + -- The TUI was able to determine truecolor support or $COLORTERM explicitly indicates + -- truecolor support setoption('termguicolors', true) - else + elseif colorterm == nil or colorterm == '' then + -- Neither the TUI nor $COLORTERM indicate that truecolor is supported, so query the + -- terminal local caps = {} ---@type table<string, boolean> require('vim.termcap').query({ 'Tc', 'RGB', 'setrgbf', 'setrgbb' }, function(cap, found) if not found then diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 5e9be509c8..2e829578a7 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -1,17 +1,19 @@ -- Nvim-Lua stdlib: the `vim` module (:help lua-stdlib) -- --- Lua code lives in one of three places: --- 1. runtime/lua/vim/ (the runtime): For "nice to have" features, e.g. the --- `inspect` and `lpeg` modules. --- 2. runtime/lua/vim/shared.lua: pure Lua functions which always --- are available. Used in the test runner, as well as worker threads --- and processes launched from Nvim. --- 3. runtime/lua/vim/_editor.lua: Code which directly interacts with --- the Nvim editor state. Only available in the main thread. +-- Lua code lives in one of four places: +-- 1. Plugins! Not everything needs to live on "vim.*". Plugins are the correct model for +-- non-essential features which the user may want to disable or replace with a third-party +-- plugin. Examples: "editorconfig", "comment". +-- - "opt-out": runtime/plugin/*.lua +-- - "opt-in": runtime/pack/dist/opt/ +-- 2. runtime/lua/vim/ (the runtime): Lazy-loaded modules. Examples: `inspect`, `lpeg`. +-- 3. runtime/lua/vim/shared.lua: pure Lua functions which always are available. Used in the test +-- runner, as well as worker threads and processes launched from Nvim. +-- 4. runtime/lua/vim/_editor.lua: Eager-loaded code which directly interacts with the Nvim +-- editor state. Only available in the main thread. -- --- Guideline: "If in doubt, put it in the runtime". --- --- Most functions should live directly in `vim.`, not in submodules. +-- The top level "vim.*" namespace is for fundamental Lua and editor features. Use submodules for +-- everything else (but avoid excessive "nesting"), or plugins (see above). -- -- Compatibility with Vim's `if_lua` is explicitly a non-goal. -- @@ -19,9 +21,7 @@ -- - https://github.com/luafun/luafun -- - https://github.com/rxi/lume -- - http://leafo.net/lapis/reference/utilities.html --- - https://github.com/torch/paths -- - https://github.com/bakpakin/Fennel (pretty print, repl) --- - https://github.com/howl-editor/howl/tree/master/lib/howl/util -- These are for loading runtime modules lazily since they aren't available in -- the nvim binary as specified in executor.c @@ -208,8 +208,10 @@ vim.inspect = vim.inspect do local tdots, tick, got_line1, undo_started, trailing_nl = 0, 0, false, false, false - --- Paste handler, invoked by |nvim_paste()| when a conforming UI - --- (such as the |TUI|) pastes text into the editor. + --- Paste handler, invoked by |nvim_paste()|. + --- + --- Note: This is provided only as a "hook", don't call it directly; call |nvim_paste()| instead, + --- which arranges redo (dot-repeat) and invokes `vim.paste`. --- --- Example: To remove ANSI color codes when pasting: --- @@ -220,7 +222,7 @@ do --- -- Scrub ANSI color codes from paste input. --- lines[i] = line:gsub('\27%[[0-9;mK]+', '') --- end - --- overridden(lines, phase) + --- return overridden(lines, phase) --- end --- end)(vim.paste) --- ``` @@ -494,6 +496,7 @@ do vim.t = make_dict_accessor('t') end +--- @deprecated --- Gets a dict of line segment ("chunk") positions for the region from `pos1` to `pos2`. --- --- Input and output positions are byte positions, (0,0)-indexed. "End of line" column @@ -507,6 +510,8 @@ end ---@return table region Dict of the form `{linenr = {startcol,endcol}}`. `endcol` is exclusive, and ---whole lines are returned as `{startcol,endcol} = {0,-1}`. function vim.region(bufnr, pos1, pos2, regtype, inclusive) + vim.deprecate('vim.region', 'vim.fn.getregionpos()', '0.13') + if not vim.api.nvim_buf_is_loaded(bufnr) then vim.fn.bufload(bufnr) end @@ -605,10 +610,9 @@ end --- Displays a notification to the user. --- ---- This function can be overridden by plugins to display notifications using a ---- custom provider (such as the system notification provider). By default, +--- This function can be overridden by plugins to display notifications using +--- a custom provider (such as the system notification provider). By default, --- writes to |:messages|. ---- ---@param msg string Content of the notification to show to the user. ---@param level integer|nil One of the values from |vim.log.levels|. ---@param opts table|nil Optional parameters. Unused by default. @@ -783,7 +787,7 @@ function vim._expand_pat(pat, env) if mt and type(mt.__index) == 'table' then field = rawget(mt.__index, key) elseif final_env == vim and (vim._submodules[key] or vim._extra[key]) then - field = vim[key] + field = vim[key] --- @type any end end final_env = field @@ -794,14 +798,24 @@ function vim._expand_pat(pat, env) end local keys = {} --- @type table<string,true> + --- @param obj table<any,any> local function insert_keys(obj) for k, _ in pairs(obj) do - if type(k) == 'string' and string.sub(k, 1, string.len(match_part)) == match_part then + if + type(k) == 'string' + and string.sub(k, 1, string.len(match_part)) == match_part + and k:match('^[_%w]+$') ~= nil -- filter out invalid identifiers for field, e.g. 'foo#bar' + then keys[k] = true end end end + ---@param acc table<string,any> + local function _fold_to_map(acc, k, v) + acc[k] = (v or true) + return acc + end if type(final_env) == 'table' then insert_keys(final_env) @@ -810,11 +824,61 @@ function vim._expand_pat(pat, env) if mt and type(mt.__index) == 'table' then insert_keys(mt.__index) end + if final_env == vim then insert_keys(vim._submodules) insert_keys(vim._extra) end + -- Completion for dict accessors (special vim variables and vim.fn) + if mt and vim.tbl_contains({ vim.g, vim.t, vim.w, vim.b, vim.v, vim.fn }, final_env) then + local prefix, type = unpack( + vim.fn == final_env and { '', 'function' } + or vim.g == final_env and { 'g:', 'var' } + or vim.t == final_env and { 't:', 'var' } + or vim.w == final_env and { 'w:', 'var' } + or vim.b == final_env and { 'b:', 'var' } + or vim.v == final_env and { 'v:', 'var' } + or { nil, nil } + ) + assert(prefix, "Can't resolve final_env") + local vars = vim.fn.getcompletion(prefix .. match_part, type) --- @type string[] + insert_keys(vim + .iter(vars) + :map(function(s) ---@param s string + s = s:gsub('[()]+$', '') -- strip '(' and ')' for function completions + return s:sub(#prefix + 1) -- strip the prefix, e.g., 'g:foo' => 'foo' + end) + :fold({}, _fold_to_map)) + end + + -- Completion for option accessors (full names only) + if + mt + and vim.tbl_contains( + { vim.o, vim.go, vim.bo, vim.wo, vim.opt, vim.opt_local, vim.opt_global }, + final_env + ) + then + --- @type fun(option_name: string, option: vim.api.keyset.get_option_info): boolean + local filter = function(_, _) + return true + end + if vim.bo == final_env then + filter = function(_, option) + return option.scope == 'buf' + end + elseif vim.wo == final_env then + filter = function(_, option) + return option.scope == 'win' + end + end + + --- @type table<string, vim.api.keyset.get_option_info> + local options = vim.api.nvim_get_all_options_info() + insert_keys(vim.iter(options):filter(filter):fold({}, _fold_to_map)) + end + keys = vim.tbl_keys(keys) table.sort(keys) diff --git a/runtime/lua/vim/_inspector.lua b/runtime/lua/vim/_inspector.lua index f5d1640c82..fccf4b8dbe 100644 --- a/runtime/lua/vim/_inspector.lua +++ b/runtime/lua/vim/_inspector.lua @@ -27,6 +27,7 @@ local defaults = { --- ---Can also be pretty-printed with `:Inspect!`. [:Inspect!]() --- +---@since 11 ---@param bufnr? integer defaults to the current buffer ---@param row? integer row to inspect, 0-based. Defaults to the row of the current cursor ---@param col? integer col to inspect, 0-based. Defaults to the col of the current cursor @@ -84,7 +85,7 @@ function vim.inspect_pos(bufnr, row, col, filter) -- syntax if filter.syntax and vim.api.nvim_buf_is_valid(bufnr) then - vim.api.nvim_buf_call(bufnr, function() + vim._with({ buf = bufnr }, function() for _, i1 in ipairs(vim.fn.synstack(row + 1, col + 1)) do results.syntax[#results.syntax + 1] = resolve_hl({ hl_group = vim.fn.synIDattr(i1, 'name') }) @@ -145,6 +146,7 @@ end --- ---Can also be shown with `:Inspect`. [:Inspect]() --- +---@since 11 ---@param bufnr? integer defaults to the current buffer ---@param row? integer row to inspect, 0-based. Defaults to the row of the current cursor ---@param col? integer col to inspect, 0-based. Defaults to the col of the current cursor diff --git a/runtime/lua/vim/_meta.lua b/runtime/lua/vim/_meta.lua index 731dd5b923..c9f207cb20 100644 --- a/runtime/lua/vim/_meta.lua +++ b/runtime/lua/vim/_meta.lua @@ -34,3 +34,5 @@ vim.uri_from_fname = uri.uri_from_fname vim.uri_from_bufnr = uri.uri_from_bufnr vim.uri_to_fname = uri.uri_to_fname vim.uri_to_bufnr = uri.uri_to_bufnr + +vim.provider = require('vim.provider') diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua index 6edf2a5a96..c66b295d3a 100644 --- a/runtime/lua/vim/_meta/api.lua +++ b/runtime/lua/vim/_meta/api.lua @@ -20,14 +20,15 @@ function vim.api.nvim__buf_stats(buffer) end --- @private --- EXPERIMENTAL: this API may change in the future. --- ---- Sets info for the completion item at the given index. If the info text was ---- shown in a window, returns the window and buffer ids, or empty dict if not ---- shown. +--- Sets info for the completion item at the given index. If the info text was shown in a window, +--- returns the window and buffer ids, or empty dict if not shown. --- --- @param index integer Completion candidate index --- @param opts vim.api.keyset.complete_set Optional parameters. ---- • info: (string) info text. ---- @return table<string,any> +--- - info: (string) info text. +--- @return table<string,any> # Dict containing these keys: +--- - winid: (number) floating window id +--- - bufnr: (number) buffer id in floating window function vim.api.nvim__complete_set(index, opts) end --- @private @@ -40,7 +41,7 @@ function vim.api.nvim__get_lib_dir() end --- @param pat any[] pattern of files to search for --- @param all boolean whether to return all matches or only the first --- @param opts vim.api.keyset.runtime is_lua: only search Lua subdirs ---- @return string[] +--- @return string[] # list of absolute paths to the found files function vim.api.nvim__get_runtime(pat, all, opts) end --- @private @@ -50,7 +51,7 @@ function vim.api.nvim__get_runtime(pat, all, opts) end --- in plugins. --- --- @param obj any Object to return. ---- @return any +--- @return any # its argument. function vim.api.nvim__id(obj) end --- @private @@ -60,18 +61,18 @@ function vim.api.nvim__id(obj) end --- in plugins. --- --- @param arr any[] Array to return. ---- @return any[] +--- @return any[] # its argument. function vim.api.nvim__id_array(arr) end --- @private ---- Returns dictionary given as argument. +--- Returns dict given as argument. --- --- This API function is used for testing. One should not rely on its presence --- in plugins. --- ---- @param dct table<string,any> Dictionary to return. ---- @return table<string,any> -function vim.api.nvim__id_dictionary(dct) end +--- @param dct table<string,any> Dict to return. +--- @return table<string,any> # its argument. +function vim.api.nvim__id_dict(dct) end --- @private --- Returns floating-point value given as argument. @@ -80,13 +81,11 @@ function vim.api.nvim__id_dictionary(dct) end --- in plugins. --- --- @param flt number Value to return. ---- @return number +--- @return number # its argument. function vim.api.nvim__id_float(flt) end --- @private ---- NB: if your UI doesn't use hlstate, this will not return hlstate first ---- time. ---- +--- NB: if your UI doesn't use hlstate, this will not return hlstate first time. --- @param grid integer --- @param row integer --- @param col integer @@ -94,35 +93,55 @@ function vim.api.nvim__id_float(flt) end function vim.api.nvim__inspect_cell(grid, row, col) end --- @private ---- For testing. The condition in schar_cache_clear_if_full is hard to reach, ---- so this function can be used to force a cache clear in a test. ---- +--- For testing. The condition in schar_cache_clear_if_full is hard to +--- reach, so this function can be used to force a cache clear in a test. function vim.api.nvim__invalidate_glyph_cache() end --- @private +--- EXPERIMENTAL: this API will change in the future. +--- +--- Get the properties for namespace +--- +--- @param ns_id integer Namespace +--- @return vim.api.keyset.ns_opts # Map defining the namespace properties, see |nvim__ns_set()| +function vim.api.nvim__ns_get(ns_id) end + +--- @private +--- EXPERIMENTAL: this API will change in the future. +--- +--- Set some properties for namespace +--- +--- @param ns_id integer Namespace +--- @param opts vim.api.keyset.ns_opts Optional parameters to set: +--- - wins: a list of windows to be scoped in +function vim.api.nvim__ns_set(ns_id, opts) end + +--- @private --- EXPERIMENTAL: this API may change in the future. --- --- Instruct Nvim to redraw various components. --- +--- +--- @see `:help :redraw` --- @param opts vim.api.keyset.redraw Optional parameters. ---- • win: Target a specific `window-ID` as described below. ---- • buf: Target a specific buffer number as described below. ---- • flush: Update the screen with pending updates. ---- • valid: When present mark `win`, `buf`, or all windows for ---- redraw. When `true`, only redraw changed lines (useful for ---- decoration providers). When `false`, forcefully redraw. ---- • range: Redraw a range in `buf`, the buffer in `win` or the ---- current buffer (useful for decoration providers). Expects a ---- tuple `[first, last]` with the first and last line number of ---- the range, 0-based end-exclusive `api-indexing`. ---- • cursor: Immediately update cursor position on the screen in ---- `win` or the current window. ---- • statuscolumn: Redraw the 'statuscolumn' in `buf`, `win` or ---- all windows. ---- • statusline: Redraw the 'statusline' in `buf`, `win` or all ---- windows. ---- • winbar: Redraw the 'winbar' in `buf`, `win` or all windows. ---- • tabline: Redraw the 'tabline'. +--- - win: Target a specific `window-ID` as described below. +--- - buf: Target a specific buffer number as described below. +--- - flush: Update the screen with pending updates. +--- - valid: When present mark `win`, `buf`, or all windows for +--- redraw. When `true`, only redraw changed lines (useful for +--- decoration providers). When `false`, forcefully redraw. +--- - range: Redraw a range in `buf`, the buffer in `win` or the +--- current buffer (useful for decoration providers). Expects a +--- tuple `[first, last]` with the first and last line number +--- of the range, 0-based end-exclusive `api-indexing`. +--- - cursor: Immediately update cursor position on the screen in +--- `win` or the current window. +--- - statuscolumn: Redraw the 'statuscolumn' in `buf`, `win` or +--- all windows. +--- - statusline: Redraw the 'statusline' in `buf`, `win` or all +--- windows. +--- - winbar: Redraw the 'winbar' in `buf`, `win` or all windows. +--- - tabline: Redraw the 'tabline'. function vim.api.nvim__redraw(opts) end --- @private @@ -136,7 +155,7 @@ function vim.api.nvim__screenshot(path) end --- @private --- Gets internal stats. --- ---- @return table<string,any> +--- @return table<string,any> # Map of various internal stats. function vim.api.nvim__stats() end --- @private @@ -144,50 +163,20 @@ function vim.api.nvim__stats() end --- @return any function vim.api.nvim__unpack(str) end ---- @private ---- EXPERIMENTAL: this API will change in the future. ---- ---- Scopes a namespace to the a window, so extmarks in the namespace will be ---- active only in the given window. ---- ---- @param window integer Window handle, or 0 for current window ---- @param ns_id integer Namespace ---- @return boolean -function vim.api.nvim__win_add_ns(window, ns_id) end - ---- @private ---- EXPERIMENTAL: this API will change in the future. ---- ---- Unscopes a namespace (un-binds it from the given scope). ---- ---- @param window integer Window handle, or 0 for current window ---- @param ns_id integer the namespace to remove ---- @return boolean -function vim.api.nvim__win_del_ns(window, ns_id) end - ---- @private ---- EXPERIMENTAL: this API will change in the future. ---- ---- Gets the namespace scopes for a given window. ---- ---- @param window integer Window handle, or 0 for current window ---- @return integer[] -function vim.api.nvim__win_get_ns(window) end - --- Adds a highlight to buffer. --- ---- Useful for plugins that dynamically generate highlights to a buffer (like ---- a semantic highlighter or linter). The function adds a single highlight to ---- a buffer. Unlike `matchaddpos()` highlights follow changes to line ---- numbering (as lines are inserted/removed above the highlighted line), like ---- signs and marks do. +--- Useful for plugins that dynamically generate highlights to a buffer +--- (like a semantic highlighter or linter). The function adds a single +--- highlight to a buffer. Unlike `matchaddpos()` highlights follow changes to +--- line numbering (as lines are inserted/removed above the highlighted line), +--- like signs and marks do. --- --- Namespaces are used for batch deletion/updating of a set of highlights. To ---- create a namespace, use `nvim_create_namespace()` which returns a ---- namespace id. Pass it in to this function as `ns_id` to add highlights to ---- the namespace. All highlights in the same namespace can then be cleared ---- with single call to `nvim_buf_clear_namespace()`. If the highlight never ---- will be deleted by an API call, pass `ns_id = -1`. +--- create a namespace, use `nvim_create_namespace()` which returns a namespace +--- id. Pass it in to this function as `ns_id` to add highlights to the +--- namespace. All highlights in the same namespace can then be cleared with +--- single call to `nvim_buf_clear_namespace()`. If the highlight never will be +--- deleted by an API call, pass `ns_id = -1`. --- --- As a shorthand, `ns_id = 0` can be used to create a new namespace for the --- highlight, the allocated id is then returned. If `hl_group` is the empty @@ -200,98 +189,100 @@ function vim.api.nvim__win_get_ns(window) end --- @param hl_group string Name of the highlight group to use --- @param line integer Line to highlight (zero-indexed) --- @param col_start integer Start of (byte-indexed) column range to highlight ---- @param col_end integer End of (byte-indexed) column range to highlight, or -1 to ---- highlight to end of line ---- @return integer +--- @param col_end integer End of (byte-indexed) column range to highlight, +--- or -1 to highlight to end of line +--- @return integer # The ns_id that was used function vim.api.nvim_buf_add_highlight(buffer, ns_id, hl_group, line, col_start, col_end) end --- Activates buffer-update events on a channel, or as Lua callbacks. --- ---- Example (Lua): capture buffer updates in a global `events` variable (use ---- "vim.print(events)" to see its contents): +--- Example (Lua): capture buffer updates in a global `events` variable +--- (use "vim.print(events)" to see its contents): --- --- ```lua ---- events = {} ---- vim.api.nvim_buf_attach(0, false, { ---- on_lines = function(...) ---- table.insert(events, {...}) ---- end, ---- }) +--- events = {} +--- vim.api.nvim_buf_attach(0, false, { +--- on_lines = function(...) +--- table.insert(events, {...}) +--- end, +--- }) --- ``` --- --- +--- @see vim.api.nvim_buf_detach +--- @see `:help api-buffer-updates-lua` --- @param buffer integer Buffer handle, or 0 for current buffer --- @param send_buffer boolean True if the initial notification should contain the ---- whole buffer: first notification will be ---- `nvim_buf_lines_event`. Else the first notification ---- will be `nvim_buf_changedtick_event`. Not for Lua ---- callbacks. +--- whole buffer: first notification will be `nvim_buf_lines_event`. +--- Else the first notification will be `nvim_buf_changedtick_event`. +--- Not for Lua callbacks. --- @param opts vim.api.keyset.buf_attach Optional parameters. ---- • on_lines: Lua callback invoked on change. Return a truthy ---- value (not `false` or `nil`) to detach. Args: ---- • the string "lines" ---- • buffer handle ---- • b:changedtick ---- • first line that changed (zero-indexed) ---- • last line that was changed ---- • last line in the updated range ---- • byte count of previous contents ---- • deleted_codepoints (if `utf_sizes` is true) ---- • deleted_codeunits (if `utf_sizes` is true) ---- • on_bytes: Lua callback invoked on change. This callback ---- receives more granular information about the change compared ---- to on_lines. Return a truthy value (not `false` or `nil`) to ---- detach. Args: ---- • the string "bytes" ---- • buffer handle ---- • b:changedtick ---- • start row of the changed text (zero-indexed) ---- • start column of the changed text ---- • byte offset of the changed text (from the start of the ---- buffer) ---- • old end row of the changed text (offset from start row) ---- • old end column of the changed text (if old end row = 0, ---- offset from start column) ---- • old end byte length of the changed text ---- • new end row of the changed text (offset from start row) ---- • new end column of the changed text (if new end row = 0, ---- offset from start column) ---- • new end byte length of the changed text ---- • on_changedtick: Lua callback invoked on changedtick ---- increment without text change. Args: ---- • the string "changedtick" ---- • buffer handle ---- • b:changedtick ---- • on_detach: Lua callback invoked on detach. Args: ---- • the string "detach" ---- • buffer handle ---- • on_reload: Lua callback invoked on reload. The entire buffer ---- content should be considered changed. Args: ---- • the string "reload" ---- • buffer handle ---- • utf_sizes: include UTF-32 and UTF-16 size of the replaced ---- region, as args to `on_lines`. ---- • preview: also attach to command preview (i.e. 'inccommand') ---- events. ---- @return boolean +--- - on_lines: Lua callback invoked on change. +--- Return a truthy value (not `false` or `nil`) to detach. Args: +--- - the string "lines" +--- - buffer handle +--- - b:changedtick +--- - first line that changed (zero-indexed) +--- - last line that was changed +--- - last line in the updated range +--- - byte count of previous contents +--- - deleted_codepoints (if `utf_sizes` is true) +--- - deleted_codeunits (if `utf_sizes` is true) +--- - on_bytes: Lua callback invoked on change. +--- This callback receives more granular information about the +--- change compared to on_lines. +--- Return a truthy value (not `false` or `nil`) to detach. Args: +--- - the string "bytes" +--- - buffer handle +--- - b:changedtick +--- - start row of the changed text (zero-indexed) +--- - start column of the changed text +--- - byte offset of the changed text (from the start of +--- the buffer) +--- - old end row of the changed text (offset from start row) +--- - old end column of the changed text +--- (if old end row = 0, offset from start column) +--- - old end byte length of the changed text +--- - new end row of the changed text (offset from start row) +--- - new end column of the changed text +--- (if new end row = 0, offset from start column) +--- - new end byte length of the changed text +--- - on_changedtick: Lua callback invoked on changedtick +--- increment without text change. Args: +--- - the string "changedtick" +--- - buffer handle +--- - b:changedtick +--- - on_detach: Lua callback invoked on detach. Args: +--- - the string "detach" +--- - buffer handle +--- - on_reload: Lua callback invoked on reload. The entire buffer +--- content should be considered changed. Args: +--- - the string "reload" +--- - buffer handle +--- - utf_sizes: include UTF-32 and UTF-16 size of the replaced +--- region, as args to `on_lines`. +--- - preview: also attach to command preview (i.e. 'inccommand') +--- events. +--- @return boolean # False if attach failed (invalid parameter, or buffer isn't loaded); +--- otherwise True. TODO: LUA_API_NO_EVAL function vim.api.nvim_buf_attach(buffer, send_buffer, opts) end ---- call a function with buffer as temporary current buffer +--- Call a function with buffer as temporary current buffer. --- ---- This temporarily switches current buffer to "buffer". If the current ---- window already shows "buffer", the window is not switched If a window ---- inside the current tabpage (including a float) already shows the buffer ---- One of these windows will be set as current window temporarily. Otherwise ---- a temporary scratch window (called the "autocmd window" for historical ---- reasons) will be used. +--- This temporarily switches current buffer to "buffer". +--- If the current window already shows "buffer", the window is not switched. +--- If a window inside the current tabpage (including a float) already shows the +--- buffer, then one of these windows will be set as current window temporarily. +--- Otherwise a temporary scratch window (called the "autocmd window" for +--- historical reasons) will be used. --- --- This is useful e.g. to call Vimscript functions that only work with the --- current buffer/window currently, like `termopen()`. --- --- @param buffer integer Buffer handle, or 0 for current buffer --- @param fun function Function to call inside the buffer (currently Lua callable ---- only) ---- @return any +--- only) +--- @return any # Return value of function. function vim.api.nvim_buf_call(buffer, fun) end --- @deprecated @@ -301,21 +292,22 @@ function vim.api.nvim_buf_call(buffer, fun) end --- @param line_end integer function vim.api.nvim_buf_clear_highlight(buffer, ns_id, line_start, line_end) end ---- Clears `namespace`d objects (highlights, `extmarks`, virtual text) from a ---- region. +--- Clears `namespace`d objects (highlights, `extmarks`, virtual text) from +--- a region. --- ---- Lines are 0-indexed. `api-indexing` To clear the namespace in the entire +--- Lines are 0-indexed. `api-indexing` To clear the namespace in the entire --- buffer, specify line_start=0 and line_end=-1. --- --- @param buffer integer Buffer handle, or 0 for current buffer --- @param ns_id integer Namespace to clear, or -1 to clear all namespaces. --- @param line_start integer Start of range of lines to clear --- @param line_end integer End of range of lines to clear (exclusive) or -1 to clear ---- to end of buffer. +--- to end of buffer. function vim.api.nvim_buf_clear_namespace(buffer, ns_id, line_start, line_end) end --- Creates a buffer-local command `user-commands`. --- +--- @see vim.api.nvim_create_user_command --- @param buffer integer Buffer handle, or 0 for current buffer. --- @param name string --- @param command any @@ -327,11 +319,13 @@ function vim.api.nvim_buf_create_user_command(buffer, name, command, opts) end --- @param buffer integer Buffer handle, or 0 for current buffer --- @param ns_id integer Namespace id from `nvim_create_namespace()` --- @param id integer Extmark id ---- @return boolean +--- @return boolean # true if the extmark was found, else false function vim.api.nvim_buf_del_extmark(buffer, ns_id, id) end --- Unmaps a buffer-local `mapping` for the given mode. --- +--- +--- @see vim.api.nvim_del_keymap --- @param buffer integer Buffer handle, or 0 for current buffer --- @param mode string --- @param lhs string @@ -339,9 +333,15 @@ function vim.api.nvim_buf_del_keymap(buffer, mode, lhs) end --- Deletes a named mark in the buffer. See `mark-motions`. --- +--- Note: +--- only deletes marks set in the buffer, if the mark is not set +--- in the buffer it will return false. +--- +--- @see vim.api.nvim_buf_set_mark +--- @see vim.api.nvim_del_mark --- @param buffer integer Buffer to set the mark on --- @param name string Mark name ---- @return boolean +--- @return boolean # true if the mark was deleted, else false. function vim.api.nvim_buf_del_mark(buffer, name) end --- Delete a buffer-local user-defined command. @@ -363,21 +363,21 @@ function vim.api.nvim_buf_del_var(buffer, name) end --- --- @param buffer integer Buffer handle, or 0 for current buffer --- @param opts vim.api.keyset.buf_delete Optional parameters. Keys: ---- • force: Force deletion and ignore unsaved changes. ---- • unload: Unloaded only, do not delete. See `:bunload` +--- - force: Force deletion and ignore unsaved changes. +--- - unload: Unloaded only, do not delete. See `:bunload` function vim.api.nvim_buf_delete(buffer, opts) end --- Gets a changed tick of a buffer --- --- @param buffer integer Buffer handle, or 0 for current buffer ---- @return integer +--- @return integer # `b:changedtick` value. function vim.api.nvim_buf_get_changedtick(buffer) end --- Gets a map of buffer-local `user-commands`. --- --- @param buffer integer Buffer handle, or 0 for current buffer --- @param opts vim.api.keyset.get_commands Optional parameters. Currently not used. ---- @return table<string,any> +--- @return table<string,any> # Map of maps describing commands. function vim.api.nvim_buf_get_commands(buffer, opts) end --- Gets the position (0-indexed) of an `extmark`. @@ -386,10 +386,10 @@ function vim.api.nvim_buf_get_commands(buffer, opts) end --- @param ns_id integer Namespace id from `nvim_create_namespace()` --- @param id integer Extmark id --- @param opts vim.api.keyset.get_extmark Optional parameters. Keys: ---- • details: Whether to include the details dict ---- • hl_name: Whether to include highlight group name instead of ---- id, true if omitted ---- @return vim.api.keyset.get_extmark_item +--- - details: Whether to include the details dict +--- - hl_name: Whether to include highlight group name instead of id, true if omitted +--- @return vim.api.keyset.get_extmark_item_by_id # 0-indexed (row, col) tuple or empty list () if extmark id was +--- absent function vim.api.nvim_buf_get_extmark_by_id(buffer, ns_id, id, opts) end --- Gets `extmarks` in "traversal order" from a `charwise` region defined by @@ -400,70 +400,67 @@ function vim.api.nvim_buf_get_extmark_by_id(buffer, ns_id, id, opts) end --- respectively, thus the following are equivalent: --- --- ```lua ---- vim.api.nvim_buf_get_extmarks(0, my_ns, 0, -1, {}) ---- vim.api.nvim_buf_get_extmarks(0, my_ns, {0,0}, {-1,-1}, {}) +--- vim.api.nvim_buf_get_extmarks(0, my_ns, 0, -1, {}) +--- vim.api.nvim_buf_get_extmarks(0, my_ns, {0,0}, {-1,-1}, {}) --- ``` --- ---- If `end` is less than `start`, traversal works backwards. (Useful with ---- `limit`, to get the first marks prior to a given position.) +--- If `end` is less than `start`, traversal works backwards. (Useful +--- with `limit`, to get the first marks prior to a given position.) --- --- Note: when using extmark ranges (marks with a end_row/end_col position) ---- the `overlap` option might be useful. Otherwise only the start position of ---- an extmark will be considered. +--- the `overlap` option might be useful. Otherwise only the start position +--- of an extmark will be considered. --- ---- Note: legacy signs placed through the `:sign` commands are implemented as ---- extmarks and will show up here. Their details array will contain a +--- Note: legacy signs placed through the `:sign` commands are implemented +--- as extmarks and will show up here. Their details array will contain a --- `sign_name` field. --- --- Example: --- --- ```lua ---- local api = vim.api ---- local pos = api.nvim_win_get_cursor(0) ---- local ns = api.nvim_create_namespace('my-plugin') ---- -- Create new extmark at line 1, column 1. ---- local m1 = api.nvim_buf_set_extmark(0, ns, 0, 0, {}) ---- -- Create new extmark at line 3, column 1. ---- local m2 = api.nvim_buf_set_extmark(0, ns, 2, 0, {}) ---- -- Get extmarks only from line 3. ---- local ms = api.nvim_buf_get_extmarks(0, ns, {2,0}, {2,0}, {}) ---- -- Get all marks in this buffer + namespace. ---- local all = api.nvim_buf_get_extmarks(0, ns, 0, -1, {}) ---- vim.print(ms) +--- local api = vim.api +--- local pos = api.nvim_win_get_cursor(0) +--- local ns = api.nvim_create_namespace('my-plugin') +--- -- Create new extmark at line 1, column 1. +--- local m1 = api.nvim_buf_set_extmark(0, ns, 0, 0, {}) +--- -- Create new extmark at line 3, column 1. +--- local m2 = api.nvim_buf_set_extmark(0, ns, 2, 0, {}) +--- -- Get extmarks only from line 3. +--- local ms = api.nvim_buf_get_extmarks(0, ns, {2,0}, {2,0}, {}) +--- -- Get all marks in this buffer + namespace. +--- local all = api.nvim_buf_get_extmarks(0, ns, 0, -1, {}) +--- vim.print(ms) --- ``` --- ---- --- @param buffer integer Buffer handle, or 0 for current buffer ---- @param ns_id integer Namespace id from `nvim_create_namespace()` or -1 for all ---- namespaces +--- @param ns_id integer Namespace id from `nvim_create_namespace()` or -1 for all namespaces --- @param start any Start of range: a 0-indexed (row, col) or valid extmark id ---- (whose position defines the bound). `api-indexing` +--- (whose position defines the bound). `api-indexing` --- @param end_ any End of range (inclusive): a 0-indexed (row, col) or valid ---- extmark id (whose position defines the bound). `api-indexing` +--- extmark id (whose position defines the bound). `api-indexing` --- @param opts vim.api.keyset.get_extmarks Optional parameters. Keys: ---- • limit: Maximum number of marks to return ---- • details: Whether to include the details dict ---- • hl_name: Whether to include highlight group name instead of ---- id, true if omitted ---- • overlap: Also include marks which overlap the range, even if ---- their start position is less than `start` ---- • type: Filter marks by type: "highlight", "sign", "virt_text" ---- and "virt_lines" ---- @return vim.api.keyset.get_extmark_item[] +--- - limit: Maximum number of marks to return +--- - details: Whether to include the details dict +--- - hl_name: Whether to include highlight group name instead of id, true if omitted +--- - overlap: Also include marks which overlap the range, even if +--- their start position is less than `start` +--- - type: Filter marks by type: "highlight", "sign", "virt_text" and "virt_lines" +--- @return vim.api.keyset.get_extmark_item[] # List of `[extmark_id, row, col]` tuples in "traversal order". function vim.api.nvim_buf_get_extmarks(buffer, ns_id, start, end_, opts) end --- Gets a list of buffer-local `mapping` definitions. --- --- @param buffer integer Buffer handle, or 0 for current buffer --- @param mode string Mode short-name ("n", "i", "v", ...) ---- @return vim.api.keyset.keymap[] +--- @return vim.api.keyset.keymap[] # Array of |maparg()|-like dictionaries describing mappings. +--- The "buffer" key holds the associated buffer handle. function vim.api.nvim_buf_get_keymap(buffer, mode) end --- Gets a line-range from the buffer. --- ---- Indexing is zero-based, end-exclusive. Negative indices are interpreted as ---- length+1+index: -1 refers to the index past the end. So to get the last ---- element use start=-2 and end=-1. +--- Indexing is zero-based, end-exclusive. Negative indices are interpreted +--- as length+1+index: -1 refers to the index past the end. So to get the +--- last element use start=-2 and end=-1. --- --- Out-of-bounds indices are clamped to the nearest valid value, unless --- `strict_indexing` is set. @@ -472,24 +469,27 @@ function vim.api.nvim_buf_get_keymap(buffer, mode) end --- @param start integer First line index --- @param end_ integer Last line index, exclusive --- @param strict_indexing boolean Whether out-of-bounds should be an error. ---- @return string[] +--- @return string[] # Array of lines, or empty array for unloaded buffer. function vim.api.nvim_buf_get_lines(buffer, start, end_, strict_indexing) end --- Returns a `(row,col)` tuple representing the position of the named mark. ---- "End of line" column position is returned as `v:maxcol` (big number). See ---- `mark-motions`. +--- "End of line" column position is returned as `v:maxcol` (big number). +--- See `mark-motions`. --- --- Marks are (1,0)-indexed. `api-indexing` --- +--- @see vim.api.nvim_buf_set_mark +--- @see vim.api.nvim_buf_del_mark --- @param buffer integer Buffer handle, or 0 for current buffer --- @param name string Mark name ---- @return integer[] +--- @return integer[] # (row, col) tuple, (0, 0) if the mark is not set, or is an +--- uppercase/file mark set in another buffer. function vim.api.nvim_buf_get_mark(buffer, name) end --- Gets the full file name for the buffer --- --- @param buffer integer Buffer handle, or 0 for current buffer ---- @return string +--- @return string # Buffer name function vim.api.nvim_buf_get_name(buffer) end --- @deprecated @@ -504,12 +504,12 @@ function vim.api.nvim_buf_get_number(buffer) end --- last line gives the total byte-count of the buffer. A final EOL byte is --- counted if it would be written, see 'eol'. --- ---- Unlike `line2byte()`, throws error for out-of-bounds indexing. Returns -1 ---- for unloaded buffer. +--- Unlike `line2byte()`, throws error for out-of-bounds indexing. +--- Returns -1 for unloaded buffer. --- --- @param buffer integer Buffer handle, or 0 for current buffer --- @param index integer Line index ---- @return integer +--- @return integer # Integer byte offset, or -1 for unloaded buffer. function vim.api.nvim_buf_get_offset(buffer, index) end --- @deprecated @@ -534,49 +534,54 @@ function vim.api.nvim_buf_get_option(buffer, name) end --- @param end_row integer Last line index, inclusive --- @param end_col integer Ending column (byte offset) on last line, exclusive --- @param opts vim.api.keyset.empty Optional parameters. Currently unused. ---- @return string[] +--- @return string[] # Array of lines, or empty array for unloaded buffer. function vim.api.nvim_buf_get_text(buffer, start_row, start_col, end_row, end_col, opts) end --- Gets a buffer-scoped (b:) variable. --- --- @param buffer integer Buffer handle, or 0 for current buffer --- @param name string Variable name ---- @return any +--- @return any # Variable value function vim.api.nvim_buf_get_var(buffer, name) end --- Checks if a buffer is valid and loaded. See `api-buffer` for more info --- about unloaded buffers. --- --- @param buffer integer Buffer handle, or 0 for current buffer ---- @return boolean +--- @return boolean # true if the buffer is valid and loaded, false otherwise. function vim.api.nvim_buf_is_loaded(buffer) end --- Checks if a buffer is valid. --- +--- Note: +--- Even if a buffer is valid it may have been unloaded. See |api-buffer| +--- for more info about unloaded buffers. +--- +--- --- @param buffer integer Buffer handle, or 0 for current buffer ---- @return boolean +--- @return boolean # true if the buffer is valid, false otherwise. function vim.api.nvim_buf_is_valid(buffer) end --- Returns the number of lines in the given buffer. --- --- @param buffer integer Buffer handle, or 0 for current buffer ---- @return integer +--- @return integer # Line count, or 0 for unloaded buffer. |api-buffer| function vim.api.nvim_buf_line_count(buffer) end --- Creates or updates an `extmark`. --- ---- By default a new extmark is created when no id is passed in, but it is ---- also possible to create a new mark by passing in a previously unused id or ---- move an existing mark by passing in its id. The caller must then keep ---- track of existing and unused ids itself. (Useful over RPC, to avoid ---- waiting for the return value.) +--- By default a new extmark is created when no id is passed in, but it is also +--- possible to create a new mark by passing in a previously unused id or move +--- an existing mark by passing in its id. The caller must then keep track of +--- existing and unused ids itself. (Useful over RPC, to avoid waiting for the +--- return value.) --- ---- Using the optional arguments, it is possible to use this to highlight a ---- range of text, and also to associate virtual text to the mark. +--- Using the optional arguments, it is possible to use this to highlight +--- a range of text, and also to associate virtual text to the mark. --- ---- If present, the position defined by `end_col` and `end_row` should be ---- after the start position in order for the extmark to cover a range. An ---- earlier end position is not an error, but then it behaves like an empty +--- If present, the position defined by `end_col` and `end_row` should be after +--- the start position in order for the extmark to cover a range. +--- An earlier end position is not an error, but then it behaves like an empty --- range (no highlighting). --- --- @param buffer integer Buffer handle, or 0 for current buffer @@ -584,115 +589,122 @@ function vim.api.nvim_buf_line_count(buffer) end --- @param line integer Line where to place the mark, 0-based. `api-indexing` --- @param col integer Column where to place the mark, 0-based. `api-indexing` --- @param opts vim.api.keyset.set_extmark Optional parameters. ---- • id : id of the extmark to edit. ---- • end_row : ending line of the mark, 0-based inclusive. ---- • end_col : ending col of the mark, 0-based exclusive. ---- • hl_group : name of the highlight group used to highlight ---- this mark. ---- • hl_eol : when true, for a multiline highlight covering the ---- EOL of a line, continue the highlight for the rest of the ---- screen line (just like for diff and cursorline highlight). ---- • virt_text : virtual text to link to this mark. A list of ---- `[text, highlight]` tuples, each representing a text chunk ---- with specified highlight. `highlight` element can either be ---- a single highlight group, or an array of multiple highlight ---- groups that will be stacked (highest priority last). A ---- highlight group can be supplied either as a string or as an ---- integer, the latter which can be obtained using ---- `nvim_get_hl_id_by_name()`. ---- • virt_text_pos : position of virtual text. Possible values: ---- • "eol": right after eol character (default). ---- • "overlay": display over the specified column, without ---- shifting the underlying text. ---- • "right_align": display right aligned in the window. ---- • "inline": display at the specified column, and shift the ---- buffer text to the right as needed. ---- • virt_text_win_col : position the virtual text at a fixed ---- window column (starting from the first text column of the ---- screen line) instead of "virt_text_pos". ---- • virt_text_hide : hide the virtual text when the background ---- text is selected or hidden because of scrolling with ---- 'nowrap' or 'smoothscroll'. Currently only affects "overlay" ---- virt_text. ---- • virt_text_repeat_linebreak : repeat the virtual text on ---- wrapped lines. ---- • hl_mode : control how highlights are combined with the ---- highlights of the text. Currently only affects virt_text ---- highlights, but might affect `hl_group` in later versions. ---- • "replace": only show the virt_text color. This is the ---- default. ---- • "combine": combine with background text color. ---- • "blend": blend with background text color. Not supported ---- for "inline" virt_text. ---- • virt_lines : virtual lines to add next to this mark This ---- should be an array over lines, where each line in turn is an ---- array over `[text, highlight]` tuples. In general, buffer ---- and window options do not affect the display of the text. In ---- particular 'wrap' and 'linebreak' options do not take ---- effect, so the number of extra screen lines will always ---- match the size of the array. However the 'tabstop' buffer ---- option is still used for hard tabs. By default lines are ---- placed below the buffer line containing the mark. ---- • virt_lines_above: place virtual lines above instead. ---- • virt_lines_leftcol: Place extmarks in the leftmost column of ---- the window, bypassing sign and number columns. ---- • ephemeral : for use with `nvim_set_decoration_provider()` ---- callbacks. The mark will only be used for the current redraw ---- cycle, and not be permantently stored in the buffer. ---- • right_gravity : boolean that indicates the direction the ---- extmark will be shifted in when new text is inserted (true ---- for right, false for left). Defaults to true. ---- • end_right_gravity : boolean that indicates the direction the ---- extmark end position (if it exists) will be shifted in when ---- new text is inserted (true for right, false for left). ---- Defaults to false. ---- • undo_restore : Restore the exact position of the mark if ---- text around the mark was deleted and then restored by undo. ---- Defaults to true. ---- • invalidate : boolean that indicates whether to hide the ---- extmark if the entirety of its range is deleted. For hidden ---- marks, an "invalid" key is added to the "details" array of ---- `nvim_buf_get_extmarks()` and family. If "undo_restore" is ---- false, the extmark is deleted instead. ---- • priority: a priority value for the highlight group, sign ---- attribute or virtual text. For virtual text, item with ---- highest priority is drawn last. For example treesitter ---- highlighting uses a value of 100. ---- • strict: boolean that indicates extmark should not be placed ---- if the line or column value is past the end of the buffer or ---- end of the line respectively. Defaults to true. ---- • sign_text: string of length 1-2 used to display in the sign ---- column. ---- • sign_hl_group: name of the highlight group used to highlight ---- the sign column text. ---- • number_hl_group: name of the highlight group used to ---- highlight the number column. ---- • line_hl_group: name of the highlight group used to highlight ---- the whole line. ---- • cursorline_hl_group: name of the highlight group used to ---- highlight the sign column text when the cursor is on the ---- same line as the mark and 'cursorline' is enabled. ---- • conceal: string which should be either empty or a single ---- character. Enable concealing similar to `:syn-conceal`. When ---- a character is supplied it is used as `:syn-cchar`. ---- "hl_group" is used as highlight for the cchar if provided, ---- otherwise it defaults to `hl-Conceal`. ---- • spell: boolean indicating that spell checking should be ---- performed within this extmark ---- • ui_watched: boolean that indicates the mark should be drawn ---- by a UI. When set, the UI will receive win_extmark events. ---- Note: the mark is positioned by virt_text attributes. Can be ---- used together with virt_text. ---- • url: A URL to associate with this extmark. In the TUI, the ---- OSC 8 control sequence is used to generate a clickable ---- hyperlink to this URL. ---- • scoped: boolean (EXPERIMENTAL) enables "scoping" for the ---- extmark. See `nvim__win_add_ns()` ---- @return integer +--- - id : id of the extmark to edit. +--- - end_row : ending line of the mark, 0-based inclusive. +--- - end_col : ending col of the mark, 0-based exclusive. +--- - hl_group : name of the highlight group used to highlight +--- this mark. +--- - hl_eol : when true, for a multiline highlight covering the +--- EOL of a line, continue the highlight for the rest +--- of the screen line (just like for diff and +--- cursorline highlight). +--- - virt_text : virtual text to link to this mark. +--- A list of `[text, highlight]` tuples, each representing a +--- text chunk with specified highlight. `highlight` element +--- can either be a single highlight group, or an array of +--- multiple highlight groups that will be stacked +--- (highest priority last). A highlight group can be supplied +--- either as a string or as an integer, the latter which +--- can be obtained using `nvim_get_hl_id_by_name()`. +--- - virt_text_pos : position of virtual text. Possible values: +--- - "eol": right after eol character (default). +--- - "overlay": display over the specified column, without +--- shifting the underlying text. +--- - "right_align": display right aligned in the window. +--- - "inline": display at the specified column, and +--- shift the buffer text to the right as needed. +--- - virt_text_win_col : position the virtual text at a fixed +--- window column (starting from the first +--- text column of the screen line) instead +--- of "virt_text_pos". +--- - virt_text_hide : hide the virtual text when the background +--- text is selected or hidden because of +--- scrolling with 'nowrap' or 'smoothscroll'. +--- Currently only affects "overlay" virt_text. +--- - virt_text_repeat_linebreak : repeat the virtual text on +--- wrapped lines. +--- - hl_mode : control how highlights are combined with the +--- highlights of the text. Currently only affects +--- virt_text highlights, but might affect `hl_group` +--- in later versions. +--- - "replace": only show the virt_text color. This is the default. +--- - "combine": combine with background text color. +--- - "blend": blend with background text color. +--- Not supported for "inline" virt_text. +--- +--- - virt_lines : virtual lines to add next to this mark +--- This should be an array over lines, where each line in +--- turn is an array over `[text, highlight]` tuples. In +--- general, buffer and window options do not affect the +--- display of the text. In particular 'wrap' +--- and 'linebreak' options do not take effect, so +--- the number of extra screen lines will always match +--- the size of the array. However the 'tabstop' buffer +--- option is still used for hard tabs. By default lines are +--- placed below the buffer line containing the mark. +--- +--- - virt_lines_above: place virtual lines above instead. +--- - virt_lines_leftcol: Place extmarks in the leftmost +--- column of the window, bypassing +--- sign and number columns. +--- +--- - ephemeral : for use with `nvim_set_decoration_provider()` +--- callbacks. The mark will only be used for the current +--- redraw cycle, and not be permantently stored in the +--- buffer. +--- - right_gravity : boolean that indicates the direction +--- the extmark will be shifted in when new text is inserted +--- (true for right, false for left). Defaults to true. +--- - end_right_gravity : boolean that indicates the direction +--- the extmark end position (if it exists) will be shifted +--- in when new text is inserted (true for right, false +--- for left). Defaults to false. +--- - undo_restore : Restore the exact position of the mark +--- if text around the mark was deleted and then restored by undo. +--- Defaults to true. +--- - invalidate : boolean that indicates whether to hide the +--- extmark if the entirety of its range is deleted. For +--- hidden marks, an "invalid" key is added to the "details" +--- array of `nvim_buf_get_extmarks()` and family. If +--- "undo_restore" is false, the extmark is deleted instead. +--- - priority: a priority value for the highlight group, sign +--- attribute or virtual text. For virtual text, item with +--- highest priority is drawn last. For example treesitter +--- highlighting uses a value of 100. +--- - strict: boolean that indicates extmark should not be placed +--- if the line or column value is past the end of the +--- buffer or end of the line respectively. Defaults to true. +--- - sign_text: string of length 1-2 used to display in the +--- sign column. +--- - sign_hl_group: name of the highlight group used to +--- highlight the sign column text. +--- - number_hl_group: name of the highlight group used to +--- highlight the number column. +--- - line_hl_group: name of the highlight group used to +--- highlight the whole line. +--- - cursorline_hl_group: name of the highlight group used to +--- highlight the sign column text when the cursor is on +--- the same line as the mark and 'cursorline' is enabled. +--- - conceal: string which should be either empty or a single +--- character. Enable concealing similar to `:syn-conceal`. +--- When a character is supplied it is used as `:syn-cchar`. +--- "hl_group" is used as highlight for the cchar if provided, +--- otherwise it defaults to `hl-Conceal`. +--- - spell: boolean indicating that spell checking should be +--- performed within this extmark +--- - ui_watched: boolean that indicates the mark should be drawn +--- by a UI. When set, the UI will receive win_extmark events. +--- Note: the mark is positioned by virt_text attributes. Can be +--- used together with virt_text. +--- - url: A URL to associate with this extmark. In the TUI, the OSC 8 control +--- sequence is used to generate a clickable hyperlink to this URL. +--- @return integer # Id of the created/updated extmark function vim.api.nvim_buf_set_extmark(buffer, ns_id, line, col, opts) end --- Sets a buffer-local `mapping` for the given mode. --- +--- +--- @see vim.api.nvim_set_keymap --- @param buffer integer Buffer handle, or 0 for current buffer --- @param mode string --- @param lhs string @@ -702,9 +714,9 @@ function vim.api.nvim_buf_set_keymap(buffer, mode, lhs, rhs, opts) end --- Sets (replaces) a line-range in the buffer. --- ---- Indexing is zero-based, end-exclusive. Negative indices are interpreted as ---- length+1+index: -1 refers to the index past the end. So to change or ---- delete the last element use start=-2 and end=-1. +--- Indexing is zero-based, end-exclusive. Negative indices are interpreted +--- as length+1+index: -1 refers to the index past the end. So to change +--- or delete the last element use start=-2 and end=-1. --- --- To insert lines at a given index, set `start` and `end` to the same index. --- To delete a range of lines, set `replacement` to an empty array. @@ -712,6 +724,8 @@ function vim.api.nvim_buf_set_keymap(buffer, mode, lhs, rhs, opts) end --- Out-of-bounds indices are clamped to the nearest valid value, unless --- `strict_indexing` is set. --- +--- +--- @see vim.api.nvim_buf_set_text --- @param buffer integer Buffer handle, or 0 for current buffer --- @param start integer First line index --- @param end_ integer Last line index, exclusive @@ -724,12 +738,18 @@ function vim.api.nvim_buf_set_lines(buffer, start, end_, strict_indexing, replac --- --- Marks are (1,0)-indexed. `api-indexing` --- +--- Note: +--- Passing 0 as line deletes the mark +--- +--- +--- @see vim.api.nvim_buf_del_mark +--- @see vim.api.nvim_buf_get_mark --- @param buffer integer Buffer to set the mark on --- @param name string Mark name --- @param line integer Line number --- @param col integer Column/row number --- @param opts vim.api.keyset.empty Optional parameters. Reserved for future use. ---- @return boolean +--- @return boolean # true if the mark was set, else false. function vim.api.nvim_buf_set_mark(buffer, name, line, col, opts) end --- Sets the full file name for a buffer, like `:file_f` @@ -746,21 +766,21 @@ function vim.api.nvim_buf_set_option(buffer, name, value) end --- Sets (replaces) a range in the buffer --- ---- This is recommended over `nvim_buf_set_lines()` when only modifying parts ---- of a line, as extmarks will be preserved on non-modified parts of the ---- touched lines. +--- This is recommended over `nvim_buf_set_lines()` when only modifying parts of +--- a line, as extmarks will be preserved on non-modified parts of the touched +--- lines. --- --- Indexing is zero-based. Row indices are end-inclusive, and column indices --- are end-exclusive. --- ---- To insert text at a given `(row, column)` location, use ---- `start_row = end_row = row` and `start_col = end_col = col`. To delete the ---- text in a range, use `replacement = {}`. +--- To insert text at a given `(row, column)` location, use `start_row = end_row +--- = row` and `start_col = end_col = col`. To delete the text in a range, use +--- `replacement = {}`. --- ---- Prefer `nvim_buf_set_lines()` if you are only adding or deleting entire ---- lines. +--- Note: +--- Prefer |nvim_buf_set_lines()| (for performance) to add or delete entire lines. +--- Prefer |nvim_paste()| or |nvim_put()| to insert (instead of replace) text at cursor. --- ---- Prefer `nvim_put()` if you want to insert text at the cursor position. --- --- @param buffer integer Buffer handle, or 0 for current buffer --- @param start_row integer First line index @@ -790,10 +810,10 @@ function vim.api.nvim_buf_set_virtual_text(buffer, src_id, line, chunks, opts) e --- --- On execution error: fails with Vimscript error, updates v:errmsg. --- ---- @param dict any Dictionary, or String evaluating to a Vimscript `self` dict +--- @param dict any Dict, or String evaluating to a Vimscript `self` dict --- @param fn string Name of the function defined on the Vimscript dict --- @param args any[] Function arguments packed in an Array ---- @return any +--- @return any # Result of the function call function vim.api.nvim_call_dict_function(dict, fn, args) end --- Calls a Vimscript function with the given arguments. @@ -802,85 +822,83 @@ function vim.api.nvim_call_dict_function(dict, fn, args) end --- --- @param fn string Function to call --- @param args any[] Function arguments packed in an Array ---- @return any +--- @return any # Result of the function call function vim.api.nvim_call_function(fn, args) end ---- Send data to channel `id`. For a job, it writes it to the stdin of the ---- process. For the stdio channel `channel-stdio`, it writes to Nvim's ---- stdout. For an internal terminal instance (`nvim_open_term()`) it writes ---- directly to terminal output. See `channel-bytes` for more information. +--- Send data to channel `id`. For a job, it writes it to the +--- stdin of the process. For the stdio channel `channel-stdio`, +--- it writes to Nvim's stdout. For an internal terminal instance +--- (`nvim_open_term()`) it writes directly to terminal output. +--- See `channel-bytes` for more information. --- ---- This function writes raw data, not RPC messages. If the channel was ---- created with `rpc=true` then the channel expects RPC messages, use ---- `vim.rpcnotify()` and `vim.rpcrequest()` instead. +--- This function writes raw data, not RPC messages. If the channel +--- was created with `rpc=true` then the channel expects RPC +--- messages, use `vim.rpcnotify()` and `vim.rpcrequest()` instead. --- --- @param chan integer id of the channel --- @param data string data to write. 8-bit clean: can contain NUL bytes. function vim.api.nvim_chan_send(chan, data) end ---- Clears all autocommands selected by {opts}. To delete autocmds see ---- `nvim_del_autocmd()`. +--- Clears all autocommands selected by {opts}. To delete autocmds see `nvim_del_autocmd()`. --- --- @param opts vim.api.keyset.clear_autocmds Parameters ---- • event: (string|table) Examples: ---- • event: "pat1" ---- • event: { "pat1" } ---- • event: { "pat1", "pat2", "pat3" } ---- • pattern: (string|table) ---- • pattern or patterns to match exactly. ---- • For example, if you have `*.py` as that pattern for the ---- autocmd, you must pass `*.py` exactly to clear it. ---- `test.py` will not match the pattern. ---- • defaults to clearing all patterns. ---- • NOTE: Cannot be used with {buffer} ---- • buffer: (bufnr) ---- • clear only `autocmd-buflocal` autocommands. ---- • NOTE: Cannot be used with {pattern} ---- • group: (string|int) The augroup name or id. ---- • NOTE: If not passed, will only delete autocmds not in any ---- group. +--- - event: (string|table) +--- Examples: +--- - event: "pat1" +--- - event: { "pat1" } +--- - event: { "pat1", "pat2", "pat3" } +--- - pattern: (string|table) +--- - pattern or patterns to match exactly. +--- - For example, if you have `*.py` as that pattern for the autocmd, +--- you must pass `*.py` exactly to clear it. `test.py` will not +--- match the pattern. +--- - defaults to clearing all patterns. +--- - NOTE: Cannot be used with {buffer} +--- - buffer: (bufnr) +--- - clear only `autocmd-buflocal` autocommands. +--- - NOTE: Cannot be used with {pattern} +--- - group: (string|int) The augroup name or id. +--- - NOTE: If not passed, will only delete autocmds *not* in any group. function vim.api.nvim_clear_autocmds(opts) end --- Executes an Ex command. --- ---- Unlike `nvim_command()` this command takes a structured Dictionary instead ---- of a String. This allows for easier construction and manipulation of an Ex ---- command. This also allows for things such as having spaces inside a ---- command argument, expanding filenames in a command that otherwise doesn't ---- expand filenames, etc. Command arguments may also be Number, Boolean or ---- String. +--- Unlike `nvim_command()` this command takes a structured Dict instead of a String. This +--- allows for easier construction and manipulation of an Ex command. This also allows for things +--- such as having spaces inside a command argument, expanding filenames in a command that otherwise +--- doesn't expand filenames, etc. Command arguments may also be Number, Boolean or String. --- ---- The first argument may also be used instead of count for commands that ---- support it in order to make their usage simpler with `vim.cmd()`. For ---- example, instead of `vim.cmd.bdelete{ count = 2 }`, you may do ---- `vim.cmd.bdelete(2)`. +--- The first argument may also be used instead of count for commands that support it in order to +--- make their usage simpler with `vim.cmd()`. For example, instead of +--- `vim.cmd.bdelete{ count = 2 }`, you may do `vim.cmd.bdelete(2)`. --- --- On execution error: fails with Vimscript error, updates v:errmsg. --- ---- @param cmd vim.api.keyset.cmd Command to execute. Must be a Dictionary that can contain the ---- same values as the return value of `nvim_parse_cmd()` except ---- "addr", "nargs" and "nextcmd" which are ignored if provided. ---- All values except for "cmd" are optional. +--- +--- @see vim.api.nvim_exec2 +--- @see vim.api.nvim_command +--- @param cmd vim.api.keyset.cmd Command to execute. Must be a Dict that can contain the same values as +--- the return value of `nvim_parse_cmd()` except "addr", "nargs" and "nextcmd" +--- which are ignored if provided. All values except for "cmd" are optional. --- @param opts vim.api.keyset.cmd_opts Optional parameters. ---- • output: (boolean, default false) Whether to return command ---- output. ---- @return string +--- - output: (boolean, default false) Whether to return command output. +--- @return string # Command output (non-error, non-shell |:!|) if `output` is true, else empty string. function vim.api.nvim_cmd(cmd, opts) end --- Executes an Ex command. --- --- On execution error: fails with Vimscript error, updates v:errmsg. --- ---- Prefer using `nvim_cmd()` or `nvim_exec2()` over this. To evaluate ---- multiple lines of Vim script or an Ex command directly, use ---- `nvim_exec2()`. To construct an Ex command using a structured format and ---- then execute it, use `nvim_cmd()`. To modify an Ex command before ---- evaluating it, use `nvim_parse_cmd()` in conjunction with `nvim_cmd()`. +--- Prefer using `nvim_cmd()` or `nvim_exec2()` over this. To evaluate multiple lines of Vim script +--- or an Ex command directly, use `nvim_exec2()`. To construct an Ex command using a structured +--- format and then execute it, use `nvim_cmd()`. To modify an Ex command before evaluating it, use +--- `nvim_parse_cmd()` in conjunction with `nvim_cmd()`. --- --- @param command string Ex command string function vim.api.nvim_command(command) end --- @deprecated +--- @see vim.api.nvim_exec2 --- @param command string --- @return string function vim.api.nvim_command_output(command) end @@ -890,106 +908,99 @@ function vim.api.nvim_command_output(command) end --- To get an existing group id, do: --- --- ```lua ---- local id = vim.api.nvim_create_augroup("MyGroup", { ---- clear = false ---- }) +--- local id = vim.api.nvim_create_augroup("MyGroup", { +--- clear = false +--- }) --- ``` --- ---- +--- @see `:help autocmd-groups` --- @param name string String: The name of the group ---- @param opts vim.api.keyset.create_augroup Dictionary Parameters ---- • clear (bool) optional: defaults to true. Clear existing ---- commands if the group already exists `autocmd-groups`. ---- @return integer +--- @param opts vim.api.keyset.create_augroup Dict Parameters +--- - clear (bool) optional: defaults to true. Clear existing +--- commands if the group already exists `autocmd-groups`. +--- @return integer # Integer id of the created group. function vim.api.nvim_create_augroup(name, opts) end ---- Creates an `autocommand` event handler, defined by `callback` (Lua ---- function or Vimscript function name string) or `command` (Ex command ---- string). +--- Creates an `autocommand` event handler, defined by `callback` (Lua function or Vimscript +--- function _name_ string) or `command` (Ex command string). --- --- Example using Lua callback: --- --- ```lua ---- vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, { ---- pattern = {"*.c", "*.h"}, ---- callback = function(ev) ---- print(string.format('event fired: %s', vim.inspect(ev))) ---- end ---- }) +--- vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, { +--- pattern = {"*.c", "*.h"}, +--- callback = function(ev) +--- print(string.format('event fired: %s', vim.inspect(ev))) +--- end +--- }) --- ``` --- --- Example using an Ex command as the handler: --- --- ```lua ---- vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, { ---- pattern = {"*.c", "*.h"}, ---- command = "echo 'Entering a C or C++ file'", ---- }) +--- vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, { +--- pattern = {"*.c", "*.h"}, +--- command = "echo 'Entering a C or C++ file'", +--- }) --- ``` --- ---- Note: `pattern` is NOT automatically expanded (unlike with `:autocmd`), ---- thus names like "$HOME" and "~" must be expanded explicitly: +--- Note: `pattern` is NOT automatically expanded (unlike with `:autocmd`), thus names like "$HOME" +--- and "~" must be expanded explicitly: --- --- ```lua ---- pattern = vim.fn.expand("~") .. "/some/path/*.py" +--- pattern = vim.fn.expand("~") .. "/some/path/*.py" --- ``` --- ---- ---- @param event any (string|array) Event(s) that will trigger the handler ---- (`callback` or `command`). +--- @see `:help autocommand` +--- @see vim.api.nvim_del_autocmd +--- @param event any (string|array) Event(s) that will trigger the handler (`callback` or `command`). --- @param opts vim.api.keyset.create_autocmd Options dict: ---- • group (string|integer) optional: autocommand group name or ---- id to match against. ---- • pattern (string|array) optional: pattern(s) to match ---- literally `autocmd-pattern`. ---- • buffer (integer) optional: buffer number for buffer-local ---- autocommands `autocmd-buflocal`. Cannot be used with ---- {pattern}. ---- • desc (string) optional: description (for documentation and ---- troubleshooting). ---- • callback (function|string) optional: Lua function (or ---- Vimscript function name, if string) called when the event(s) ---- is triggered. Lua callback can return a truthy value (not ---- `false` or `nil`) to delete the autocommand. Receives one ---- argument, a table with these keys: *event-args* ---- • id: (number) autocommand id ---- • event: (string) name of the triggered event ---- `autocmd-events` ---- • group: (number|nil) autocommand group id, if any ---- • match: (string) expanded value of <amatch> ---- • buf: (number) expanded value of <abuf> ---- • file: (string) expanded value of <afile> ---- • data: (any) arbitrary data passed from ---- `nvim_exec_autocmds()` *event-data* ---- • command (string) optional: Vim command to execute on event. ---- Cannot be used with {callback} ---- • once (boolean) optional: defaults to false. Run the ---- autocommand only once `autocmd-once`. ---- • nested (boolean) optional: defaults to false. Run nested ---- autocommands `autocmd-nested`. ---- @return integer +--- - group (string|integer) optional: autocommand group name or id to match against. +--- - pattern (string|array) optional: pattern(s) to match literally `autocmd-pattern`. +--- - buffer (integer) optional: buffer number for buffer-local autocommands +--- `autocmd-buflocal`. Cannot be used with {pattern}. +--- - desc (string) optional: description (for documentation and troubleshooting). +--- - callback (function|string) optional: Lua function (or Vimscript function name, if +--- string) called when the event(s) is triggered. Lua callback can return a truthy +--- value (not `false` or `nil`) to delete the autocommand. Receives one argument, +--- a table with these keys: [event-args]() +--- - id: (number) autocommand id +--- - event: (string) name of the triggered event `autocmd-events` +--- - group: (number|nil) autocommand group id, if any +--- - match: (string) expanded value of [<amatch>] +--- - buf: (number) expanded value of [<abuf>] +--- - file: (string) expanded value of [<afile>] +--- - data: (any) arbitrary data passed from [nvim_exec_autocmds()] [event-data]() +--- - command (string) optional: Vim command to execute on event. Cannot be used with +--- {callback} +--- - once (boolean) optional: defaults to false. Run the autocommand +--- only once `autocmd-once`. +--- - nested (boolean) optional: defaults to false. Run nested +--- autocommands `autocmd-nested`. +--- @return integer # Autocommand id (number) function vim.api.nvim_create_autocmd(event, opts) end --- Creates a new, empty, unnamed buffer. --- +--- @see buf_open_scratch --- @param listed boolean Sets 'buflisted' --- @param scratch boolean Creates a "throwaway" `scratch-buffer` for temporary work ---- (always 'nomodified'). Also sets 'nomodeline' on the ---- buffer. ---- @return integer +--- (always 'nomodified'). Also sets 'nomodeline' on the buffer. +--- @return integer # Buffer handle, or 0 on error +--- function vim.api.nvim_create_buf(listed, scratch) end ---- Creates a new namespace or gets an existing one. *namespace* +--- Creates a new namespace or gets an existing one. [namespace]() --- --- Namespaces are used for buffer highlights and virtual text, see --- `nvim_buf_add_highlight()` and `nvim_buf_set_extmark()`. --- --- Namespaces can be named or anonymous. If `name` matches an existing ---- namespace, the associated id is returned. If `name` is an empty string a ---- new, anonymous namespace is created. +--- namespace, the associated id is returned. If `name` is an empty string +--- a new, anonymous namespace is created. --- --- @param name string Namespace name or empty string ---- @return integer +--- @return integer # Namespace id function vim.api.nvim_create_namespace(name) end --- Creates a global `user-commands` command. @@ -999,70 +1010,57 @@ function vim.api.nvim_create_namespace(name) end --- Example: --- --- ```vim ---- :call nvim_create_user_command('SayHello', 'echo "Hello world!"', {'bang': v:true}) ---- :SayHello ---- Hello world! +--- :call nvim_create_user_command('SayHello', 'echo "Hello world!"', {'bang': v:true}) +--- :SayHello +--- Hello world! --- ``` --- ---- ---- @param name string Name of the new user command. Must begin with an uppercase ---- letter. ---- @param command any Replacement command to execute when this user command is ---- executed. When called from Lua, the command can also be a ---- Lua function. The function is called with a single table ---- argument that contains the following keys: ---- • name: (string) Command name ---- • args: (string) The args passed to the command, if any ---- <args> ---- • fargs: (table) The args split by unescaped whitespace ---- (when more than one argument is allowed), if any <f-args> ---- • nargs: (string) Number of arguments `:command-nargs` ---- • bang: (boolean) "true" if the command was executed with a ---- ! modifier <bang> ---- • line1: (number) The starting line of the command range ---- <line1> ---- • line2: (number) The final line of the command range ---- <line2> ---- • range: (number) The number of items in the command range: ---- 0, 1, or 2 <range> ---- • count: (number) Any count supplied <count> ---- • reg: (string) The optional register, if specified <reg> ---- • mods: (string) Command modifiers, if any <mods> ---- • smods: (table) Command modifiers in a structured format. ---- Has the same structure as the "mods" key of ---- `nvim_parse_cmd()`. +--- @param name string Name of the new user command. Must begin with an uppercase letter. +--- @param command any Replacement command to execute when this user command is executed. When called +--- from Lua, the command can also be a Lua function. The function is called with a +--- single table argument that contains the following keys: +--- - name: (string) Command name +--- - args: (string) The args passed to the command, if any [<args>] +--- - fargs: (table) The args split by unescaped whitespace (when more than one +--- argument is allowed), if any [<f-args>] +--- - nargs: (string) Number of arguments `:command-nargs` +--- - bang: (boolean) "true" if the command was executed with a ! modifier [<bang>] +--- - line1: (number) The starting line of the command range [<line1>] +--- - line2: (number) The final line of the command range [<line2>] +--- - range: (number) The number of items in the command range: 0, 1, or 2 [<range>] +--- - count: (number) Any count supplied [<count>] +--- - reg: (string) The optional register, if specified [<reg>] +--- - mods: (string) Command modifiers, if any [<mods>] +--- - smods: (table) Command modifiers in a structured format. Has the same +--- structure as the "mods" key of `nvim_parse_cmd()`. --- @param opts vim.api.keyset.user_command Optional `command-attributes`. ---- • Set boolean attributes such as `:command-bang` or ---- `:command-bar` to true (but not `:command-buffer`, use ---- `nvim_buf_create_user_command()` instead). ---- • "complete" `:command-complete` also accepts a Lua function ---- which works like `:command-completion-customlist`. ---- • Other parameters: ---- • desc: (string) Used for listing the command when a Lua ---- function is used for {command}. ---- • force: (boolean, default true) Override any previous ---- definition. ---- • preview: (function) Preview callback for 'inccommand' ---- `:command-preview` +--- - Set boolean attributes such as `:command-bang` or `:command-bar` to true (but +--- not `:command-buffer`, use `nvim_buf_create_user_command()` instead). +--- - "complete" `:command-complete` also accepts a Lua function which works like +--- `:command-completion-customlist`. +--- - Other parameters: +--- - desc: (string) Used for listing the command when a Lua function is used for +--- {command}. +--- - force: (boolean, default true) Override any previous definition. +--- - preview: (function) Preview callback for 'inccommand' `:command-preview` function vim.api.nvim_create_user_command(name, command, opts) end --- Delete an autocommand group by id. --- --- To get a group id one can use `nvim_get_autocmds()`. --- ---- NOTE: behavior differs from `:augroup-delete`. When deleting a group, ---- autocommands contained in this group will also be deleted and cleared. ---- This group will no longer exist. ---- +--- NOTE: behavior differs from `:augroup-delete`. When deleting a group, autocommands contained in +--- this group will also be deleted and cleared. This group will no longer exist. +--- @see vim.api.nvim_del_augroup_by_name +--- @see vim.api.nvim_create_augroup --- @param id integer Integer The id of the group. function vim.api.nvim_del_augroup_by_id(id) end --- Delete an autocommand group by name. --- ---- NOTE: behavior differs from `:augroup-delete`. When deleting a group, ---- autocommands contained in this group will also be deleted and cleared. ---- This group will no longer exist. ---- +--- NOTE: behavior differs from `:augroup-delete`. When deleting a group, autocommands contained in +--- this group will also be deleted and cleared. This group will no longer exist. +--- @see `:help autocmd-groups` --- @param name string String The name of the group. function vim.api.nvim_del_augroup_by_name(name) end @@ -1079,14 +1077,20 @@ function vim.api.nvim_del_current_line() end --- --- To unmap a buffer-local mapping, use `nvim_buf_del_keymap()`. --- +--- @see vim.api.nvim_set_keymap --- @param mode string --- @param lhs string function vim.api.nvim_del_keymap(mode, lhs) end --- Deletes an uppercase/file named mark. See `mark-motions`. --- +--- Note: +--- Lowercase name (or other buffer-local mark) is an error. +--- +--- @see vim.api.nvim_buf_del_mark +--- @see vim.api.nvim_get_mark --- @param name string Mark name ---- @return boolean +--- @return boolean # true if the mark was deleted, else false. function vim.api.nvim_del_mark(name) end --- Delete a user-defined command. @@ -1102,14 +1106,13 @@ function vim.api.nvim_del_var(name) end --- Echo a message. --- --- @param chunks any[] A list of `[text, hl_group]` arrays, each representing a ---- text chunk with specified highlight. `hl_group` element can ---- be omitted for no highlight. +--- text chunk with specified highlight. `hl_group` element +--- can be omitted for no highlight. --- @param history boolean if true, add to `message-history`. --- @param opts vim.api.keyset.echo_opts Optional parameters. ---- • verbose: Message was printed as a result of 'verbose' option ---- if Nvim was invoked with -V3log_file, the message will be ---- redirected to the log_file and suppressed from direct ---- output. +--- - verbose: Message was printed as a result of 'verbose' option +--- if Nvim was invoked with -V3log_file, the message will be +--- redirected to the log_file and suppressed from direct output. function vim.api.nvim_echo(chunks, history, opts) end --- Writes a message to the Vim error buffer. Does not append "\n", the @@ -1121,39 +1124,43 @@ function vim.api.nvim_err_write(str) end --- Writes a message to the Vim error buffer. Appends "\n", so the buffer is --- flushed (and displayed). --- +--- @see vim.api.nvim_err_write --- @param str string Message function vim.api.nvim_err_writeln(str) end ---- Evaluates a Vimscript `expression`. Dictionaries and Lists are recursively ---- expanded. +--- Evaluates a Vimscript `expression`. Dicts and Lists are recursively expanded. --- --- On execution error: fails with Vimscript error, updates v:errmsg. --- --- @param expr string Vimscript expression string ---- @return any +--- @return any # Evaluation result or expanded object function vim.api.nvim_eval(expr) end --- Evaluates statusline string. --- --- @param str string Statusline string (see 'statusline'). --- @param opts vim.api.keyset.eval_statusline Optional parameters. ---- • winid: (number) `window-ID` of the window to use as context ---- for statusline. ---- • maxwidth: (number) Maximum width of statusline. ---- • fillchar: (string) Character to fill blank spaces in the ---- statusline (see 'fillchars'). Treated as single-width even ---- if it isn't. ---- • highlights: (boolean) Return highlight information. ---- • use_winbar: (boolean) Evaluate winbar instead of statusline. ---- • use_tabline: (boolean) Evaluate tabline instead of ---- statusline. When true, {winid} is ignored. Mutually ---- exclusive with {use_winbar}. ---- • use_statuscol_lnum: (number) Evaluate statuscolumn for this ---- line number instead of statusline. ---- @return table<string,any> +--- - winid: (number) `window-ID` of the window to use as context for statusline. +--- - maxwidth: (number) Maximum width of statusline. +--- - fillchar: (string) Character to fill blank spaces in the statusline (see +--- 'fillchars'). Treated as single-width even if it isn't. +--- - highlights: (boolean) Return highlight information. +--- - use_winbar: (boolean) Evaluate winbar instead of statusline. +--- - use_tabline: (boolean) Evaluate tabline instead of statusline. When true, {winid} +--- is ignored. Mutually exclusive with {use_winbar}. +--- - use_statuscol_lnum: (number) Evaluate statuscolumn for this line number instead of statusline. +--- @return table<string,any> # Dict containing statusline information, with these keys: +--- - str: (string) Characters that will be displayed on the statusline. +--- - width: (number) Display width of the statusline. +--- - highlights: Array containing highlight information of the statusline. Only included when +--- the "highlights" key in {opts} is true. Each element of the array is a +--- |Dict| with these keys: +--- - start: (number) Byte index (0-based) of first character that uses the highlight. +--- - group: (string) Name of highlight group. function vim.api.nvim_eval_statusline(str, opts) end --- @deprecated +--- @see vim.api.nvim_exec2 --- @param src string --- @param output boolean --- @return string @@ -1162,33 +1169,38 @@ function vim.api.nvim_exec(src, output) end --- Executes Vimscript (multiline block of Ex commands), like anonymous --- `:source`. --- ---- Unlike `nvim_command()` this function supports heredocs, script-scope ---- (s:), etc. +--- Unlike `nvim_command()` this function supports heredocs, script-scope (s:), +--- etc. --- --- On execution error: fails with Vimscript error, updates v:errmsg. --- +--- +--- @see `:help execute()` +--- @see vim.api.nvim_command +--- @see vim.api.nvim_cmd --- @param src string Vimscript code --- @param opts vim.api.keyset.exec_opts Optional parameters. ---- • output: (boolean, default false) Whether to capture and ---- return all (non-error, non-shell `:!`) output. ---- @return table<string,any> +--- - output: (boolean, default false) Whether to capture and return +--- all (non-error, non-shell `:!`) output. +--- @return table<string,any> # Dict containing information about execution, with these keys: +--- - output: (string|nil) Output if `opts.output` is true. function vim.api.nvim_exec2(src, opts) end ---- Execute all autocommands for {event} that match the corresponding {opts} ---- `autocmd-execute`. ---- +--- Execute all autocommands for {event} that match the corresponding +--- {opts} `autocmd-execute`. +--- @see `:help :doautocmd` --- @param event any (String|Array) The event or events to execute ---- @param opts vim.api.keyset.exec_autocmds Dictionary of autocommand options: ---- • group (string|integer) optional: the autocommand group name ---- or id to match against. `autocmd-groups`. ---- • pattern (string|array) optional: defaults to "*" ---- `autocmd-pattern`. Cannot be used with {buffer}. ---- • buffer (integer) optional: buffer number `autocmd-buflocal`. ---- Cannot be used with {pattern}. ---- • modeline (bool) optional: defaults to true. Process the ---- modeline after the autocommands <nomodeline>. ---- • data (any): arbitrary data to send to the autocommand ---- callback. See `nvim_create_autocmd()` for details. +--- @param opts vim.api.keyset.exec_autocmds Dict of autocommand options: +--- - group (string|integer) optional: the autocommand group name or +--- id to match against. `autocmd-groups`. +--- - pattern (string|array) optional: defaults to "*" `autocmd-pattern`. Cannot be used +--- with {buffer}. +--- - buffer (integer) optional: buffer number `autocmd-buflocal`. Cannot be used with +--- {pattern}. +--- - modeline (bool) optional: defaults to true. Process the +--- modeline after the autocommands [<nomodeline>]. +--- - data (any): arbitrary data to send to the autocommand callback. See +--- `nvim_create_autocmd()` for details. function vim.api.nvim_exec_autocmds(event, opts) end --- Sends input-keys to Nvim, subject to various quirks controlled by `mode` @@ -1196,31 +1208,34 @@ function vim.api.nvim_exec_autocmds(event, opts) end --- --- On execution error: does not fail, but updates v:errmsg. --- ---- To input sequences like <C-o> use `nvim_replace_termcodes()` (typically +--- To input sequences like [<C-o>] use `nvim_replace_termcodes()` (typically --- with escape_ks=false) to replace `keycodes`, then pass the result to --- nvim_feedkeys(). --- --- Example: --- --- ```vim ---- :let key = nvim_replace_termcodes("<C-o>", v:true, v:false, v:true) ---- :call nvim_feedkeys(key, 'n', v:false) +--- :let key = nvim_replace_termcodes("<C-o>", v:true, v:false, v:true) +--- :call nvim_feedkeys(key, 'n', v:false) --- ``` --- ---- +--- @see feedkeys() +--- @see vim_strsave_escape_ks --- @param keys string to be typed --- @param mode string behavior flags, see `feedkeys()` ---- @param escape_ks boolean If true, escape K_SPECIAL bytes in `keys`. This should be ---- false if you already used `nvim_replace_termcodes()`, and ---- true otherwise. +--- @param escape_ks boolean If true, escape K_SPECIAL bytes in `keys`. +--- This should be false if you already used +--- `nvim_replace_termcodes()`, and true otherwise. function vim.api.nvim_feedkeys(keys, mode, escape_ks) end --- Gets the option information for all options. --- ---- The dictionary has the full option names as keys and option metadata ---- dictionaries as detailed at `nvim_get_option_info2()`. +--- The dict has the full option names as keys and option metadata dicts as detailed at +--- `nvim_get_option_info2()`. --- ---- @return table<string,any> +--- +--- @see vim.api.nvim_get_commands +--- @return table<string,any> # dict of all options function vim.api.nvim_get_all_options_info() end --- Get all autocommands that match the corresponding {opts}. @@ -1228,39 +1243,68 @@ function vim.api.nvim_get_all_options_info() end --- These examples will get autocommands matching ALL the given criteria: --- --- ```lua ---- -- Matches all criteria ---- autocommands = vim.api.nvim_get_autocmds({ ---- group = "MyGroup", ---- event = {"BufEnter", "BufWinEnter"}, ---- pattern = {"*.c", "*.h"} ---- }) ---- ---- -- All commands from one group ---- autocommands = vim.api.nvim_get_autocmds({ ---- group = "MyGroup", ---- }) +--- -- Matches all criteria +--- autocommands = vim.api.nvim_get_autocmds({ +--- group = "MyGroup", +--- event = {"BufEnter", "BufWinEnter"}, +--- pattern = {"*.c", "*.h"} +--- }) +--- +--- -- All commands from one group +--- autocommands = vim.api.nvim_get_autocmds({ +--- group = "MyGroup", +--- }) --- ``` --- ---- NOTE: When multiple patterns or events are provided, it will find all the ---- autocommands that match any combination of them. ---- ---- @param opts vim.api.keyset.get_autocmds Dictionary with at least one of the following: ---- • group (string|integer): the autocommand group name or id to ---- match against. ---- • event (string|array): event or events to match against ---- `autocmd-events`. ---- • pattern (string|array): pattern or patterns to match against ---- `autocmd-pattern`. Cannot be used with {buffer} ---- • buffer: Buffer number or list of buffer numbers for buffer ---- local autocommands `autocmd-buflocal`. Cannot be used with ---- {pattern} ---- @return vim.api.keyset.get_autocmds.ret[] +--- NOTE: When multiple patterns or events are provided, it will find all the autocommands that +--- match any combination of them. +--- +--- @param opts vim.api.keyset.get_autocmds Dict with at least one of the following: +--- - group (string|integer): the autocommand group name or id to match against. +--- - event (string|array): event or events to match against `autocmd-events`. +--- - pattern (string|array): pattern or patterns to match against `autocmd-pattern`. +--- Cannot be used with {buffer} +--- - buffer: Buffer number or list of buffer numbers for buffer local autocommands +--- `autocmd-buflocal`. Cannot be used with {pattern} +--- @return vim.api.keyset.get_autocmds.ret[] # Array of autocommands matching the criteria, with each item +--- containing the following fields: +--- - id (number): the autocommand id (only when defined with the API). +--- - group (integer): the autocommand group id. +--- - group_name (string): the autocommand group name. +--- - desc (string): the autocommand description. +--- - event (string): the autocommand event. +--- - command (string): the autocommand command. Note: this will be empty if a callback is set. +--- - callback (function|string|nil): Lua function or name of a Vim script function +--- which is executed when this autocommand is triggered. +--- - once (boolean): whether the autocommand is only run once. +--- - pattern (string): the autocommand pattern. +--- If the autocommand is buffer local |autocmd-buffer-local|: +--- - buflocal (boolean): true if the autocommand is buffer local. +--- - buffer (number): the buffer number. function vim.api.nvim_get_autocmds(opts) end --- Gets information about a channel. --- --- @param chan integer channel_id, or 0 for current channel ---- @return table<string,any> +--- @return table<string,any> # Channel info dict with these keys: +--- - "id" Channel id. +--- - "argv" (optional) Job arguments list. +--- - "stream" Stream underlying the channel. +--- - "stdio" stdin and stdout of this Nvim instance +--- - "stderr" stderr of this Nvim instance +--- - "socket" TCP/IP socket or named pipe +--- - "job" Job with communication over its stdio. +--- - "mode" How data received on the channel is interpreted. +--- - "bytes" Send and receive raw bytes. +--- - "terminal" |terminal| instance interprets ASCII sequences. +--- - "rpc" |RPC| communication on the channel is active. +--- - "pty" (optional) Name of pseudoterminal. On a POSIX system this is a device path like +--- "/dev/pts/1". If unknown, the key will still be present if a pty is used (e.g. +--- for conpty on Windows). +--- - "buffer" (optional) Buffer connected to |terminal| instance. +--- - "client" (optional) Info about the peer (client on the other end of the RPC channel), +--- which it provided via |nvim_set_client_info()|. +--- function vim.api.nvim_get_chan_info(chan) end --- Returns the 24-bit RGB value of a `nvim_get_color_map()` color name or @@ -1269,13 +1313,12 @@ function vim.api.nvim_get_chan_info(chan) end --- Example: --- --- ```vim ---- :echo nvim_get_color_by_name("Pink") ---- :echo nvim_get_color_by_name("#cbcbcb") +--- :echo nvim_get_color_by_name("Pink") +--- :echo nvim_get_color_by_name("#cbcbcb") --- ``` --- ---- --- @param name string Color name or "#rrggbb" string ---- @return integer +--- @return integer # 24-bit RGB value, or -1 for invalid argument. function vim.api.nvim_get_color_by_name(name) end --- Returns a map of color names and RGB values. @@ -1283,67 +1326,75 @@ function vim.api.nvim_get_color_by_name(name) end --- Keys are color names (e.g. "Aqua") and values are 24-bit RGB color values --- (e.g. 65535). --- ---- @return table<string,integer> +--- @return table<string,integer> # Map of color names and RGB values. function vim.api.nvim_get_color_map() end --- Gets a map of global (non-buffer-local) Ex commands. --- --- Currently only `user-commands` are supported, not builtin Ex commands. --- ---- @param opts vim.api.keyset.get_commands Optional parameters. Currently only supports {"builtin":false} ---- @return table<string,any> +--- +--- @see vim.api.nvim_get_all_options_info +--- @param opts vim.api.keyset.get_commands Optional parameters. Currently only supports +--- {"builtin":false} +--- @return table<string,any> # Map of maps describing commands. function vim.api.nvim_get_commands(opts) end --- Gets a map of the current editor state. --- --- @param opts vim.api.keyset.context Optional parameters. ---- • types: List of `context-types` ("regs", "jumps", "bufs", ---- "gvars", …) to gather, or empty for "all". ---- @return table<string,any> +--- - types: List of `context-types` ("regs", "jumps", "bufs", +--- "gvars", …) to gather, or empty for "all". +--- @return table<string,any> # map of global |context|. function vim.api.nvim_get_context(opts) end --- Gets the current buffer. --- ---- @return integer +--- @return integer # Buffer handle function vim.api.nvim_get_current_buf() end --- Gets the current line. --- ---- @return string +--- @return string # Current line string function vim.api.nvim_get_current_line() end --- Gets the current tabpage. --- ---- @return integer +--- @return integer # Tabpage handle function vim.api.nvim_get_current_tabpage() end --- Gets the current window. --- ---- @return integer +--- @return integer # Window handle function vim.api.nvim_get_current_win() end --- Gets all or specific highlight groups in a namespace. --- ---- @param ns_id integer Get highlight groups for namespace ns_id ---- `nvim_get_namespaces()`. Use 0 to get global highlight groups ---- `:highlight`. +--- Note: +--- When the `link` attribute is defined in the highlight definition +--- map, other attributes will not be taking effect (see |:hi-link|). +--- +--- +--- @param ns_id integer Get highlight groups for namespace ns_id `nvim_get_namespaces()`. +--- Use 0 to get global highlight groups `:highlight`. --- @param opts vim.api.keyset.get_highlight Options dict: ---- • name: (string) Get a highlight definition by name. ---- • id: (integer) Get a highlight definition by id. ---- • link: (boolean, default true) Show linked group name instead ---- of effective definition `:hi-link`. ---- • create: (boolean, default true) When highlight group doesn't ---- exist create it. ---- @return vim.api.keyset.hl_info +--- - name: (string) Get a highlight definition by name. +--- - id: (integer) Get a highlight definition by id. +--- - link: (boolean, default true) Show linked group name instead of effective definition `:hi-link`. +--- - create: (boolean, default true) When highlight group doesn't exist create it. +--- @return vim.api.keyset.get_hl_info # Highlight groups as a map from group name to a highlight definition map as in |nvim_set_hl()|, +--- or only a single highlight definition map if requested by name or id. function vim.api.nvim_get_hl(ns_id, opts) end --- @deprecated +--- @see vim.api.nvim_get_hl_by_name --- @param hl_id integer --- @param rgb boolean --- @return table<string,any> function vim.api.nvim_get_hl_by_id(hl_id, rgb) end --- @deprecated +--- @see vim.api.nvim_get_hl_by_id --- @param name string --- @param rgb boolean --- @return table<string,any> @@ -1352,7 +1403,6 @@ function vim.api.nvim_get_hl_by_name(name, rgb) end --- Gets a highlight group by name --- --- similar to `hlID()`, but allocates a new ID if not present. ---- --- @param name string --- @return integer function vim.api.nvim_get_hl_id_by_name(name) end @@ -1360,39 +1410,46 @@ function vim.api.nvim_get_hl_id_by_name(name) end --- Gets the active highlight namespace. --- --- @param opts vim.api.keyset.get_ns Optional parameters ---- • winid: (number) `window-ID` for retrieving a window's ---- highlight namespace. A value of -1 is returned when ---- `nvim_win_set_hl_ns()` has not been called for the window ---- (or was called with a namespace of -1). ---- @return integer +--- - winid: (number) `window-ID` for retrieving a window's highlight +--- namespace. A value of -1 is returned when `nvim_win_set_hl_ns()` +--- has not been called for the window (or was called with a namespace +--- of -1). +--- @return integer # Namespace id, or -1 function vim.api.nvim_get_hl_ns(opts) end --- Gets a list of global (non-buffer-local) `mapping` definitions. --- --- @param mode string Mode short-name ("n", "i", "v", ...) ---- @return vim.api.keyset.keymap[] +--- @return vim.api.keyset.keymap[] # Array of |maparg()|-like dictionaries describing mappings. +--- The "buffer" key is always zero. function vim.api.nvim_get_keymap(mode) end --- Returns a `(row, col, buffer, buffername)` tuple representing the position ---- of the uppercase/file named mark. "End of line" column position is ---- returned as `v:maxcol` (big number). See `mark-motions`. +--- of the uppercase/file named mark. "End of line" column position is returned +--- as `v:maxcol` (big number). See `mark-motions`. --- --- Marks are (1,0)-indexed. `api-indexing` --- +--- Note: +--- Lowercase name (or other buffer-local mark) is an error. +--- +--- @see vim.api.nvim_buf_set_mark +--- @see vim.api.nvim_del_mark --- @param name string Mark name --- @param opts vim.api.keyset.empty Optional parameters. Reserved for future use. ---- @return vim.api.keyset.get_mark +--- @return vim.api.keyset.get_mark # 4-tuple (row, col, buffer, buffername), (0, 0, 0, '') if the mark is +--- not set. function vim.api.nvim_get_mark(name, opts) end ---- Gets the current mode. `mode()` "blocking" is true if Nvim is waiting for ---- input. +--- Gets the current mode. `mode()` +--- "blocking" is true if Nvim is waiting for input. --- ---- @return vim.api.keyset.get_mode +--- @return vim.api.keyset.get_mode # Dict { "mode": String, "blocking": Boolean } function vim.api.nvim_get_mode() end --- Gets existing, non-anonymous `namespace`s. --- ---- @return table<string,integer> +--- @return table<string,integer> # dict that maps from names to namespace ids. function vim.api.nvim_get_namespaces() end --- @deprecated @@ -1407,100 +1464,113 @@ function vim.api.nvim_get_option_info(name) end --- Gets the option information for one option from arbitrary buffer or window --- ---- Resulting dictionary has keys: ---- • name: Name of the option (like 'filetype') ---- • shortname: Shortened name of the option (like 'ft') ---- • type: type of option ("string", "number" or "boolean") ---- • default: The default value for the option ---- • was_set: Whether the option was set. ---- • last_set_sid: Last set script id (if any) ---- • last_set_linenr: line number where option was set ---- • last_set_chan: Channel where option was set (0 for local) ---- • scope: one of "global", "win", or "buf" ---- • global_local: whether win or buf option has a global value ---- • commalist: List of comma separated values ---- • flaglist: List of single char flags ---- ---- When {scope} is not provided, the last set information applies to the ---- local value in the current buffer or window if it is available, otherwise ---- the global value information is returned. This behavior can be disabled by +--- Resulting dict has keys: +--- - name: Name of the option (like 'filetype') +--- - shortname: Shortened name of the option (like 'ft') +--- - type: type of option ("string", "number" or "boolean") +--- - default: The default value for the option +--- - was_set: Whether the option was set. +--- +--- - last_set_sid: Last set script id (if any) +--- - last_set_linenr: line number where option was set +--- - last_set_chan: Channel where option was set (0 for local) +--- +--- - scope: one of "global", "win", or "buf" +--- - global_local: whether win or buf option has a global value +--- +--- - commalist: List of comma separated values +--- - flaglist: List of single char flags +--- +--- When {scope} is not provided, the last set information applies to the local +--- value in the current buffer or window if it is available, otherwise the +--- global value information is returned. This behavior can be disabled by --- explicitly specifying {scope} in the {opts} table. --- --- @param name string Option name --- @param opts vim.api.keyset.option Optional parameters ---- • scope: One of "global" or "local". Analogous to `:setglobal` ---- and `:setlocal`, respectively. ---- • win: `window-ID`. Used for getting window local options. ---- • buf: Buffer number. Used for getting buffer local options. ---- Implies {scope} is "local". ---- @return vim.api.keyset.get_option_info +--- - scope: One of "global" or "local". Analogous to +--- `:setglobal` and `:setlocal`, respectively. +--- - win: `window-ID`. Used for getting window local options. +--- - buf: Buffer number. Used for getting buffer local options. +--- Implies {scope} is "local". +--- @return vim.api.keyset.get_option_info # Option Information function vim.api.nvim_get_option_info2(name, opts) end --- Gets the value of an option. The behavior of this function matches that of --- `:set`: the local value of an option is returned if it exists; otherwise, ---- the global value is returned. Local values always correspond to the ---- current buffer or window, unless "buf" or "win" is set in {opts}. +--- the global value is returned. Local values always correspond to the current +--- buffer or window, unless "buf" or "win" is set in {opts}. --- --- @param name string Option name --- @param opts vim.api.keyset.option Optional parameters ---- • scope: One of "global" or "local". Analogous to `:setglobal` ---- and `:setlocal`, respectively. ---- • win: `window-ID`. Used for getting window local options. ---- • buf: Buffer number. Used for getting buffer local options. ---- Implies {scope} is "local". ---- • filetype: `filetype`. Used to get the default option for a ---- specific filetype. Cannot be used with any other option. ---- Note: this will trigger `ftplugin` and all `FileType` ---- autocommands for the corresponding filetype. ---- @return any +--- - scope: One of "global" or "local". Analogous to +--- `:setglobal` and `:setlocal`, respectively. +--- - win: `window-ID`. Used for getting window local options. +--- - buf: Buffer number. Used for getting buffer local options. +--- Implies {scope} is "local". +--- - filetype: `filetype`. Used to get the default option for a +--- specific filetype. Cannot be used with any other option. +--- Note: this will trigger `ftplugin` and all `FileType` +--- autocommands for the corresponding filetype. +--- @return any # Option value function vim.api.nvim_get_option_value(name, opts) end --- Gets info describing process `pid`. --- --- @param pid integer ---- @return any +--- @return any # Map of process properties, or NIL if process not found. function vim.api.nvim_get_proc(pid) end --- Gets the immediate children of process `pid`. --- --- @param pid integer ---- @return any[] +--- @return any[] # Array of child process ids, empty if process not found. function vim.api.nvim_get_proc_children(pid) end ---- Find files in runtime directories +--- Finds files in runtime directories, in 'runtimepath' order. --- --- "name" can contain wildcards. For example ---- nvim_get_runtime_file("colors/*.vim", true) will return all color scheme ---- files. Always use forward slashes (/) in the search pattern for +--- `nvim_get_runtime_file("colors/*.{vim,lua}", true)` will return all color +--- scheme files. Always use forward slashes (/) in the search pattern for --- subdirectories regardless of platform. --- --- It is not an error to not find any files. An empty array is returned then. --- --- @param name string pattern of files to search for --- @param all boolean whether to return all matches or only the first ---- @return string[] +--- @return string[] # list of absolute paths to the found files function vim.api.nvim_get_runtime_file(name, all) end --- Gets a global (g:) variable. --- --- @param name string Variable name ---- @return any +--- @return any # Variable value function vim.api.nvim_get_var(name) end --- Gets a v: variable. --- --- @param name string Variable name ---- @return any +--- @return any # Variable value function vim.api.nvim_get_vvar(name) end ---- Queues raw user-input. Unlike `nvim_feedkeys()`, this uses a low-level ---- input buffer and the call is non-blocking (input is processed ---- asynchronously by the eventloop). +--- Queues raw user-input. Unlike `nvim_feedkeys()`, this uses a low-level input buffer and the call +--- is non-blocking (input is processed asynchronously by the eventloop). +--- +--- To input blocks of text, `nvim_paste()` is much faster and should be preferred. --- --- On execution error: does not fail, but updates v:errmsg. --- +--- Note: +--- |keycodes| like [<CR>] are translated, so "<" is special. +--- To input a literal "<", send [<LT>]. +--- +--- For mouse events use |nvim_input_mouse()|. The pseudokey form +--- `<LeftMouse><col,row>` is deprecated since |api-level| 6. +--- +--- --- @param keys string to be typed ---- @return integer +--- @return integer # Number of bytes actually written (can be fewer than +--- requested if the buffer becomes full). function vim.api.nvim_input(keys) end --- Send mouse event from GUI. @@ -1508,15 +1578,22 @@ function vim.api.nvim_input(keys) end --- Non-blocking: does not wait on any result, but queues the event to be --- processed soon by the event loop. --- ---- @param button string Mouse button: one of "left", "right", "middle", "wheel", ---- "move", "x1", "x2". ---- @param action string For ordinary buttons, one of "press", "drag", "release". For ---- the wheel, one of "up", "down", "left", "right". Ignored for ---- "move". ---- @param modifier string String of modifiers each represented by a single char. The ---- same specifiers are used as for a key press, except that ---- the "-" separator is optional, so "C-A-", "c-a" and "CA" ---- can all be used to specify Ctrl+Alt+click. +--- Note: +--- Currently this doesn't support "scripting" multiple mouse events +--- by calling it multiple times in a loop: the intermediate mouse +--- positions will be ignored. It should be used to implement real-time +--- mouse input in a GUI. The deprecated pseudokey form +--- (`<LeftMouse><col,row>`) of |nvim_input()| has the same limitation. +--- +--- +--- @param button string Mouse button: one of "left", "right", "middle", "wheel", "move", +--- "x1", "x2". +--- @param action string For ordinary buttons, one of "press", "drag", "release". +--- For the wheel, one of "up", "down", "left", "right". Ignored for "move". +--- @param modifier string String of modifiers each represented by a single char. +--- The same specifiers are used as for a key press, except +--- that the "-" separator is optional, so "C-A-", "c-a" +--- and "CA" can all be used to specify Ctrl+Alt+click. --- @param grid integer Grid number if the client uses `ui-multigrid`, else 0. --- @param row integer Mouse row-position (zero-based, like redraw events) --- @param col integer Mouse column-position (zero-based, like redraw events) @@ -1524,35 +1601,41 @@ function vim.api.nvim_input_mouse(button, action, modifier, grid, row, col) end --- Gets the current list of buffer handles --- ---- Includes unlisted (unloaded/deleted) buffers, like `:ls!`. Use ---- `nvim_buf_is_loaded()` to check if a buffer is loaded. +--- Includes unlisted (unloaded/deleted) buffers, like `:ls!`. +--- Use `nvim_buf_is_loaded()` to check if a buffer is loaded. --- ---- @return integer[] +--- @return integer[] # List of buffer handles function vim.api.nvim_list_bufs() end --- Get information about all open channels. --- ---- @return any[] +--- @return any[] # Array of Dictionaries, each describing a channel with +--- the format specified at |nvim_get_chan_info()|. function vim.api.nvim_list_chans() end --- Gets the paths contained in `runtime-search-path`. --- ---- @return string[] +--- @return string[] # List of paths function vim.api.nvim_list_runtime_paths() end --- Gets the current list of tabpage handles. --- ---- @return integer[] +--- @return integer[] # List of tabpage handles function vim.api.nvim_list_tabpages() end --- Gets a list of dictionaries representing attached UIs. --- ---- @return any[] +--- @return any[] # Array of UI dictionaries, each with these keys: +--- - "height" Requested height of the UI +--- - "width" Requested width of the UI +--- - "rgb" true if the UI uses RGB colors (false implies |cterm-colors|) +--- - "ext_..." Requested UI extensions, see |ui-option| +--- - "chan" |channel-id| of remote UI function vim.api.nvim_list_uis() end --- Gets the current list of window handles. --- ---- @return integer[] +--- @return integer[] # List of window handles function vim.api.nvim_list_wins() end --- Sets the current editor state from the given `context` map. @@ -1575,210 +1658,194 @@ function vim.api.nvim_notify(msg, log_level, opts) end --- Open a terminal instance in a buffer --- --- By default (and currently the only option) the terminal will not be ---- connected to an external process. Instead, input send on the channel will ---- be echoed directly by the terminal. This is useful to display ANSI ---- terminal sequences returned as part of a rpc message, or similar. +--- connected to an external process. Instead, input send on the channel +--- will be echoed directly by the terminal. This is useful to display +--- ANSI terminal sequences returned as part of a rpc message, or similar. --- --- Note: to directly initiate the terminal using the right size, display the --- buffer in a configured window before calling this. For instance, for a --- floating display, first create an empty buffer using `nvim_create_buf()`, ---- then display it using `nvim_open_win()`, and then call this function. Then ---- `nvim_chan_send()` can be called immediately to process sequences in a ---- virtual terminal having the intended size. +--- then display it using `nvim_open_win()`, and then call this function. +--- Then `nvim_chan_send()` can be called immediately to process sequences +--- in a virtual terminal having the intended size. --- --- @param buffer integer the buffer to use (expected to be empty) --- @param opts vim.api.keyset.open_term Optional parameters. ---- • on_input: Lua callback for input sent, i e keypresses in ---- terminal mode. Note: keypresses are sent raw as they would ---- be to the pty master end. For instance, a carriage return is ---- sent as a "\r", not as a "\n". `textlock` applies. It is ---- possible to call `nvim_chan_send()` directly in the callback ---- however. `["input", term, bufnr, data]` ---- • force_crlf: (boolean, default true) Convert "\n" to "\r\n". ---- @return integer +--- - on_input: Lua callback for input sent, i e keypresses in terminal +--- mode. Note: keypresses are sent raw as they would be to the pty +--- master end. For instance, a carriage return is sent +--- as a "\r", not as a "\n". `textlock` applies. It is possible +--- to call `nvim_chan_send()` directly in the callback however. +--- `["input", term, bufnr, data]` +--- - force_crlf: (boolean, default true) Convert "\n" to "\r\n". +--- @return integer # Channel id, or 0 on error function vim.api.nvim_open_term(buffer, opts) end --- Opens a new split window, or a floating window if `relative` is specified, --- or an external window (managed by the UI) if `external` is specified. --- --- Floats are windows that are drawn above the split layout, at some anchor ---- position in some other window. Floats can be drawn internally or by ---- external GUI with the `ui-multigrid` extension. External windows are only ---- supported with multigrid GUIs, and are displayed as separate top-level ---- windows. +--- position in some other window. Floats can be drawn internally or by external +--- GUI with the `ui-multigrid` extension. External windows are only supported +--- with multigrid GUIs, and are displayed as separate top-level windows. --- --- For a general overview of floats, see `api-floatwin`. --- --- The `width` and `height` of the new window must be specified when opening --- a floating window, but are optional for normal windows. --- ---- If `relative` and `external` are omitted, a normal "split" window is ---- created. The `win` property determines which window will be split. If no ---- `win` is provided or `win == 0`, a window will be created adjacent to the ---- current window. If -1 is provided, a top-level split will be created. ---- `vertical` and `split` are only valid for normal windows, and are used to ---- control split direction. For `vertical`, the exact direction is determined ---- by `'splitright'` and `'splitbelow'`. Split windows cannot have ---- `bufpos`/`row`/`col`/`border`/`title`/`footer` properties. +--- If `relative` and `external` are omitted, a normal "split" window is created. +--- The `win` property determines which window will be split. If no `win` is +--- provided or `win == 0`, a window will be created adjacent to the current window. +--- If -1 is provided, a top-level split will be created. `vertical` and `split` are +--- only valid for normal windows, and are used to control split direction. For `vertical`, +--- the exact direction is determined by `'splitright'` and `'splitbelow'`. +--- Split windows cannot have `bufpos`/`row`/`col`/`border`/`title`/`footer` +--- properties. --- --- With relative=editor (row=0,col=0) refers to the top-left corner of the --- screen-grid and (row=Lines-1,col=Columns-1) refers to the bottom-right --- corner. Fractional values are allowed, but the builtin implementation --- (used by non-multigrid UIs) will always round down to nearest integer. --- ---- Out-of-bounds values, and configurations that make the float not fit ---- inside the main editor, are allowed. The builtin implementation truncates ---- values so floats are fully within the main screen grid. External GUIs ---- could let floats hover outside of the main window like a tooltip, but this ---- should not be used to specify arbitrary WM screen positions. +--- Out-of-bounds values, and configurations that make the float not fit inside +--- the main editor, are allowed. The builtin implementation truncates values +--- so floats are fully within the main screen grid. External GUIs +--- could let floats hover outside of the main window like a tooltip, but +--- this should not be used to specify arbitrary WM screen positions. --- --- Example (Lua): window-relative float --- --- ```lua ---- vim.api.nvim_open_win(0, false, ---- {relative='win', row=3, col=3, width=12, height=3}) +--- vim.api.nvim_open_win(0, false, +--- {relative='win', row=3, col=3, width=12, height=3}) --- ``` --- --- Example (Lua): buffer-relative float (travels as buffer is scrolled) --- --- ```lua ---- vim.api.nvim_open_win(0, false, ---- {relative='win', width=12, height=3, bufpos={100,10}}) +--- vim.api.nvim_open_win(0, false, +--- {relative='win', width=12, height=3, bufpos={100,10}}) --- ``` --- --- Example (Lua): vertical split left of the current window --- --- ```lua ---- vim.api.nvim_open_win(0, false, { ---- split = 'left', ---- win = 0 ---- }) +--- vim.api.nvim_open_win(0, false, { +--- split = 'left', +--- win = 0 +--- }) --- ``` --- ---- --- @param buffer integer Buffer to display, or 0 for current buffer --- @param enter boolean Enter the window (make it the current window) --- @param config vim.api.keyset.win_config Map defining the window configuration. Keys: ---- • relative: Sets the window layout to "floating", placed at ---- (row,col) coordinates relative to: ---- • "editor" The global editor grid ---- • "win" Window given by the `win` field, or current ---- window. ---- • "cursor" Cursor position in current window. ---- • "mouse" Mouse position ---- • win: `window-ID` window to split, or relative window when ---- creating a float (relative="win"). ---- • anchor: Decides which corner of the float to place at ---- (row,col): ---- • "NW" northwest (default) ---- • "NE" northeast ---- • "SW" southwest ---- • "SE" southeast ---- • width: Window width (in character cells). Minimum of 1. ---- • height: Window height (in character cells). Minimum of 1. ---- • bufpos: Places float relative to buffer text (only when ---- relative="win"). Takes a tuple of zero-indexed ---- `[line, column]`. `row` and `col` if given are applied ---- relative to this position, else they default to: ---- • `row=1` and `col=0` if `anchor` is "NW" or "NE" ---- • `row=0` and `col=0` if `anchor` is "SW" or "SE" (thus ---- like a tooltip near the buffer text). ---- • row: Row position in units of "screen cell height", may be ---- fractional. ---- • col: Column position in units of "screen cell width", may ---- be fractional. ---- • focusable: Enable focus by user actions (wincmds, mouse ---- events). Defaults to true. Non-focusable windows can be ---- entered by `nvim_set_current_win()`. ---- • external: GUI should display the window as an external ---- top-level window. Currently accepts no other positioning ---- configuration together with this. ---- • zindex: Stacking order. floats with higher `zindex` go on ---- top on floats with lower indices. Must be larger than ---- zero. The following screen elements have hard-coded ---- z-indices: ---- • 100: insert completion popupmenu ---- • 200: message scrollback ---- • 250: cmdline completion popupmenu (when ---- wildoptions+=pum) The default value for floats are 50. ---- In general, values below 100 are recommended, unless ---- there is a good reason to overshadow builtin elements. ---- • style: (optional) Configure the appearance of the window. ---- Currently only supports one value: ---- • "minimal" Nvim will display the window with many UI ---- options disabled. This is useful when displaying a ---- temporary float where the text should not be edited. ---- Disables 'number', 'relativenumber', 'cursorline', ---- 'cursorcolumn', 'foldcolumn', 'spell' and 'list' ---- options. 'signcolumn' is changed to `auto` and ---- 'colorcolumn' is cleared. 'statuscolumn' is changed to ---- empty. The end-of-buffer region is hidden by setting ---- `eob` flag of 'fillchars' to a space char, and clearing ---- the `hl-EndOfBuffer` region in 'winhighlight'. ---- • border: Style of (optional) window border. This can either ---- be a string or an array. The string values are ---- • "none": No border (default). ---- • "single": A single line box. ---- • "double": A double line box. ---- • "rounded": Like "single", but with rounded corners ---- ("â•" etc.). ---- • "solid": Adds padding by a single whitespace cell. ---- • "shadow": A drop shadow effect by blending with the ---- background. ---- • If it is an array, it should have a length of eight or ---- any divisor of eight. The array will specify the eight ---- chars building up the border in a clockwise fashion ---- starting with the top-left corner. As an example, the ---- double box style could be specified as: ---- ``` ---- [ "â•”", "â•" ,"â•—", "â•‘", "â•", "â•", "╚", "â•‘" ]. ---- ``` ---- ---- If the number of chars are less than eight, they will be ---- repeated. Thus an ASCII border could be specified as ---- ``` ---- [ "/", "-", \"\\\\\", "|" ], ---- ``` ---- ---- or all chars the same as ---- ``` ---- [ "x" ]. ---- ``` ---- ---- An empty string can be used to turn off a specific border, ---- for instance, ---- ``` ---- [ "", "", "", ">", "", "", "", "<" ] ---- ``` ---- ---- will only make vertical borders but not horizontal ones. ---- By default, `FloatBorder` highlight is used, which links ---- to `WinSeparator` when not defined. It could also be ---- specified by character: ---- ``` ---- [ ["+", "MyCorner"], ["x", "MyBorder"] ]. ---- ``` ---- ---- • title: Title (optional) in window border, string or list. ---- List should consist of `[text, highlight]` tuples. If ---- string, the default highlight group is `FloatTitle`. ---- • title_pos: Title position. Must be set with `title` ---- option. Value can be one of "left", "center", or "right". ---- Default is `"left"`. ---- • footer: Footer (optional) in window border, string or ---- list. List should consist of `[text, highlight]` tuples. ---- If string, the default highlight group is `FloatFooter`. ---- • footer_pos: Footer position. Must be set with `footer` ---- option. Value can be one of "left", "center", or "right". ---- Default is `"left"`. ---- • noautocmd: If true then all autocommands are blocked for ---- the duration of the call. ---- • fixed: If true when anchor is NW or SW, the float window ---- would be kept fixed even if the window would be truncated. ---- • hide: If true the floating window will be hidden. ---- • vertical: Split vertically `:vertical`. ---- • split: Split direction: "left", "right", "above", "below". ---- @return integer +--- - relative: Sets the window layout to "floating", placed at (row,col) +--- coordinates relative to: +--- - "editor" The global editor grid +--- - "win" Window given by the `win` field, or current window. +--- - "cursor" Cursor position in current window. +--- - "mouse" Mouse position +--- - win: `window-ID` window to split, or relative window when creating a +--- float (relative="win"). +--- - anchor: Decides which corner of the float to place at (row,col): +--- - "NW" northwest (default) +--- - "NE" northeast +--- - "SW" southwest +--- - "SE" southeast +--- - width: Window width (in character cells). Minimum of 1. +--- - height: Window height (in character cells). Minimum of 1. +--- - bufpos: Places float relative to buffer text (only when +--- relative="win"). Takes a tuple of zero-indexed `[line, column]`. +--- `row` and `col` if given are applied relative to this +--- position, else they default to: +--- - `row=1` and `col=0` if `anchor` is "NW" or "NE" +--- - `row=0` and `col=0` if `anchor` is "SW" or "SE" +--- (thus like a tooltip near the buffer text). +--- - row: Row position in units of "screen cell height", may be fractional. +--- - col: Column position in units of "screen cell width", may be +--- fractional. +--- - focusable: Enable focus by user actions (wincmds, mouse events). +--- Defaults to true. Non-focusable windows can be entered by +--- `nvim_set_current_win()`. +--- - external: GUI should display the window as an external +--- top-level window. Currently accepts no other positioning +--- configuration together with this. +--- - zindex: Stacking order. floats with higher `zindex` go on top on +--- floats with lower indices. Must be larger than zero. The +--- following screen elements have hard-coded z-indices: +--- - 100: insert completion popupmenu +--- - 200: message scrollback +--- - 250: cmdline completion popupmenu (when wildoptions+=pum) +--- The default value for floats are 50. In general, values below 100 are +--- recommended, unless there is a good reason to overshadow builtin +--- elements. +--- - style: (optional) Configure the appearance of the window. Currently +--- only supports one value: +--- - "minimal" Nvim will display the window with many UI options +--- disabled. This is useful when displaying a temporary +--- float where the text should not be edited. Disables +--- 'number', 'relativenumber', 'cursorline', 'cursorcolumn', +--- 'foldcolumn', 'spell' and 'list' options. 'signcolumn' +--- is changed to `auto` and 'colorcolumn' is cleared. +--- 'statuscolumn' is changed to empty. The end-of-buffer +--- region is hidden by setting `eob` flag of +--- 'fillchars' to a space char, and clearing the +--- `hl-EndOfBuffer` region in 'winhighlight'. +--- - border: Style of (optional) window border. This can either be a string +--- or an array. The string values are +--- - "none": No border (default). +--- - "single": A single line box. +--- - "double": A double line box. +--- - "rounded": Like "single", but with rounded corners ("â•" etc.). +--- - "solid": Adds padding by a single whitespace cell. +--- - "shadow": A drop shadow effect by blending with the background. +--- - If it is an array, it should have a length of eight or any divisor of +--- eight. The array will specify the eight chars building up the border +--- in a clockwise fashion starting with the top-left corner. As an +--- example, the double box style could be specified as: +--- ``` +--- [ "â•”", "â•" ,"â•—", "â•‘", "â•", "â•", "╚", "â•‘" ]. +--- ``` +--- If the number of chars are less than eight, they will be repeated. Thus +--- an ASCII border could be specified as +--- ``` +--- [ "/", "-", \"\\\\\", "|" ], +--- ``` +--- or all chars the same as +--- ``` +--- [ "x" ]. +--- ``` +--- An empty string can be used to turn off a specific border, for instance, +--- ``` +--- [ "", "", "", ">", "", "", "", "<" ] +--- ``` +--- will only make vertical borders but not horizontal ones. +--- By default, `FloatBorder` highlight is used, which links to `WinSeparator` +--- when not defined. It could also be specified by character: +--- ``` +--- [ ["+", "MyCorner"], ["x", "MyBorder"] ]. +--- ``` +--- - title: Title (optional) in window border, string or list. +--- List should consist of `[text, highlight]` tuples. +--- If string, or a tuple lacks a highlight, the default highlight group is `FloatTitle`. +--- - title_pos: Title position. Must be set with `title` option. +--- Value can be one of "left", "center", or "right". +--- Default is `"left"`. +--- - footer: Footer (optional) in window border, string or list. +--- List should consist of `[text, highlight]` tuples. +--- If string, or a tuple lacks a highlight, the default highlight group is `FloatFooter`. +--- - footer_pos: Footer position. Must be set with `footer` option. +--- Value can be one of "left", "center", or "right". +--- Default is `"left"`. +--- - noautocmd: If true then all autocommands are blocked for the duration of +--- the call. +--- - fixed: If true when anchor is NW or SW, the float window +--- would be kept fixed even if the window would be truncated. +--- - hide: If true the floating window will be hidden. +--- - vertical: Split vertically `:vertical`. +--- - split: Split direction: "left", "right", "above", "below". +--- @return integer # Window handle, or 0 on error function vim.api.nvim_open_win(buffer, enter, config) end --- Writes a message to the Vim output buffer. Does not append "\n", the @@ -1793,92 +1860,207 @@ function vim.api.nvim_out_write(str) end --- --- @param str string Command line string to parse. Cannot contain "\n". --- @param opts vim.api.keyset.empty Optional parameters. Reserved for future use. ---- @return vim.api.keyset.parse_cmd +--- @return vim.api.keyset.parse_cmd # Dict containing command information, with these keys: +--- - cmd: (string) Command name. +--- - range: (array) (optional) Command range ([<line1>] [<line2>]). +--- Omitted if command doesn't accept a range. +--- Otherwise, has no elements if no range was specified, one element if +--- only a single range item was specified, or two elements if both range +--- items were specified. +--- - count: (number) (optional) Command [<count>]. +--- Omitted if command cannot take a count. +--- - reg: (string) (optional) Command [<register>]. +--- Omitted if command cannot take a register. +--- - bang: (boolean) Whether command contains a [<bang>] (!) modifier. +--- - args: (array) Command arguments. +--- - addr: (string) Value of |:command-addr|. Uses short name or "line" for -addr=lines. +--- - nargs: (string) Value of |:command-nargs|. +--- - nextcmd: (string) Next command if there are multiple commands separated by a |:bar|. +--- Empty if there isn't a next command. +--- - magic: (dict) Which characters have special meaning in the command arguments. +--- - file: (boolean) The command expands filenames. Which means characters such as "%", +--- "#" and wildcards are expanded. +--- - bar: (boolean) The "|" character is treated as a command separator and the double +--- quote character (") is treated as the start of a comment. +--- - mods: (dict) |:command-modifiers|. +--- - filter: (dict) |:filter|. +--- - pattern: (string) Filter pattern. Empty string if there is no filter. +--- - force: (boolean) Whether filter is inverted or not. +--- - silent: (boolean) |:silent|. +--- - emsg_silent: (boolean) |:silent!|. +--- - unsilent: (boolean) |:unsilent|. +--- - sandbox: (boolean) |:sandbox|. +--- - noautocmd: (boolean) |:noautocmd|. +--- - browse: (boolean) |:browse|. +--- - confirm: (boolean) |:confirm|. +--- - hide: (boolean) |:hide|. +--- - horizontal: (boolean) |:horizontal|. +--- - keepalt: (boolean) |:keepalt|. +--- - keepjumps: (boolean) |:keepjumps|. +--- - keepmarks: (boolean) |:keepmarks|. +--- - keeppatterns: (boolean) |:keeppatterns|. +--- - lockmarks: (boolean) |:lockmarks|. +--- - noswapfile: (boolean) |:noswapfile|. +--- - tab: (integer) |:tab|. -1 when omitted. +--- - verbose: (integer) |:verbose|. -1 when omitted. +--- - vertical: (boolean) |:vertical|. +--- - split: (string) Split modifier string, is an empty string when there's no split +--- modifier. If there is a split modifier it can be one of: +--- - "aboveleft": |:aboveleft|. +--- - "belowright": |:belowright|. +--- - "topleft": |:topleft|. +--- - "botright": |:botright|. function vim.api.nvim_parse_cmd(str, opts) end --- Parse a Vimscript expression. --- --- @param expr string Expression to parse. Always treated as a single line. --- @param flags string Flags: ---- • "m" if multiple expressions in a row are allowed (only the ---- first one will be parsed), ---- • "E" if EOC tokens are not allowed (determines whether they ---- will stop parsing process or be recognized as an ---- operator/space, though also yielding an error). ---- • "l" when needing to start parsing with lvalues for ":let" ---- or ":for". Common flag sets: ---- • "m" to parse like for `":echo"`. ---- • "E" to parse like for `"<C-r>="`. ---- • empty string for ":call". ---- • "lm" to parse for ":let". ---- @param highlight boolean If true, return value will also include "highlight" key ---- containing array of 4-tuples (arrays) (Integer, Integer, ---- Integer, String), where first three numbers define the ---- highlighted region and represent line, starting column ---- and ending column (latter exclusive: one should highlight ---- region [start_col, end_col)). ---- @return table<string,any> +--- - "m" if multiple expressions in a row are allowed (only +--- the first one will be parsed), +--- - "E" if EOC tokens are not allowed (determines whether +--- they will stop parsing process or be recognized as an +--- operator/space, though also yielding an error). +--- - "l" when needing to start parsing with lvalues for +--- ":let" or ":for". +--- Common flag sets: +--- - "m" to parse like for `":echo"`. +--- - "E" to parse like for `"<C-r>="`. +--- - empty string for ":call". +--- - "lm" to parse for ":let". +--- @param highlight boolean If true, return value will also include "highlight" +--- key containing array of 4-tuples (arrays) (Integer, +--- Integer, Integer, String), where first three numbers +--- define the highlighted region and represent line, +--- starting column and ending column (latter exclusive: +--- one should highlight region [start_col, end_col)). +--- @return table<string,any> # +--- - AST: top-level dict with these keys: +--- - "error": Dict with error, present only if parser saw some +--- error. Contains the following keys: +--- - "message": String, error message in printf format, translated. +--- Must contain exactly one "%.*s". +--- - "arg": String, error message argument. +--- - "len": Amount of bytes successfully parsed. With flags equal to "" +--- that should be equal to the length of expr string. +--- ("Successfully parsed" here means "participated in AST +--- creation", not "till the first error".) +--- - "ast": AST, either nil or a dict with these keys: +--- - "type": node type, one of the value names from ExprASTNodeType +--- stringified without "kExprNode" prefix. +--- - "start": a pair `[line, column]` describing where node is "started" +--- where "line" is always 0 (will not be 0 if you will be +--- using this API on e.g. ":let", but that is not +--- present yet). Both elements are Integers. +--- - "len": “length†of the node. This and "start" are there for +--- debugging purposes primary (debugging parser and providing +--- debug information). +--- - "children": a list of nodes described in top/"ast". There always +--- is zero, one or two children, key will not be present +--- if node has no children. Maximum number of children +--- may be found in node_maxchildren array. +--- - Local values (present only for certain nodes): +--- - "scope": a single Integer, specifies scope for "Option" and +--- "PlainIdentifier" nodes. For "Option" it is one of +--- ExprOptScope values, for "PlainIdentifier" it is one of +--- ExprVarScope values. +--- - "ident": identifier (without scope, if any), present for "Option", +--- "PlainIdentifier", "PlainKey" and "Environment" nodes. +--- - "name": Integer, register name (one character) or -1. Only present +--- for "Register" nodes. +--- - "cmp_type": String, comparison type, one of the value names from +--- ExprComparisonType, stringified without "kExprCmp" +--- prefix. Only present for "Comparison" nodes. +--- - "ccs_strategy": String, case comparison strategy, one of the +--- value names from ExprCaseCompareStrategy, +--- stringified without "kCCStrategy" prefix. Only +--- present for "Comparison" nodes. +--- - "augmentation": String, augmentation type for "Assignment" nodes. +--- Is either an empty string, "Add", "Subtract" or +--- "Concat" for "=", "+=", "-=" or ".=" respectively. +--- - "invert": Boolean, true if result of comparison needs to be +--- inverted. Only present for "Comparison" nodes. +--- - "ivalue": Integer, integer value for "Integer" nodes. +--- - "fvalue": Float, floating-point value for "Float" nodes. +--- - "svalue": String, value for "SingleQuotedString" and +--- "DoubleQuotedString" nodes. function vim.api.nvim_parse_expression(expr, flags, highlight) end ---- Pastes at cursor, in any mode. +--- Pastes at cursor (in any mode), and sets "redo" so dot (`.`) will repeat the input. UIs call +--- this to implement "paste", but it's also intended for use by scripts to input large, +--- dot-repeatable blocks of text (as opposed to `nvim_input()` which is subject to mappings/events +--- and is thus much slower). +--- +--- Invokes the `vim.paste()` handler, which handles each mode appropriately. --- ---- Invokes the `vim.paste` handler, which handles each mode appropriately. ---- Sets redo/undo. Faster than `nvim_input()`. Lines break at LF ("\n"). +--- Errors ('nomodifiable', `vim.paste()` failure, …) are reflected in `err` but do not affect the +--- return value (which is strictly decided by `vim.paste()`). On error or cancel, subsequent calls +--- are ignored ("drained") until the next paste is initiated (phase 1 or -1). --- ---- Errors ('nomodifiable', `vim.paste()` failure, …) are reflected in `err` ---- but do not affect the return value (which is strictly decided by ---- `vim.paste()`). On error, subsequent calls are ignored ("drained") until ---- the next paste is initiated (phase 1 or -1). +--- Useful in mappings and scripts to insert multiline text. Example: --- ---- @param data string Multiline input. May be binary (containing NUL bytes). +--- ```lua +--- vim.keymap.set('n', 'x', function() +--- vim.api.nvim_paste([[ +--- line1 +--- line2 +--- line3 +--- ]], false, -1) +--- end, { buffer = true }) +--- ``` +--- +--- @param data string Multiline input. Lines break at LF ("\n"). May be binary (containing NUL bytes). --- @param crlf boolean Also break lines at CR and CRLF. ---- @param phase integer -1: paste in a single call (i.e. without streaming). To ---- "stream" a paste, call `nvim_paste` sequentially with these ---- `phase` values: ---- • 1: starts the paste (exactly once) ---- • 2: continues the paste (zero or more times) ---- • 3: ends the paste (exactly once) ---- @return boolean +--- @param phase integer -1: paste in a single call (i.e. without streaming). +--- To "stream" a paste, call `nvim_paste` sequentially with +--- these `phase` values: +--- - 1: starts the paste (exactly once) +--- - 2: continues the paste (zero or more times) +--- - 3: ends the paste (exactly once) +--- @return boolean # +--- - true: Client may continue pasting. +--- - false: Client should cancel the paste. function vim.api.nvim_paste(data, crlf, phase) end ---- Puts text at cursor, in any mode. +--- Puts text at cursor, in any mode. For dot-repeatable input, use `nvim_paste()`. --- --- Compare `:put` and `p` which are always linewise. --- --- @param lines string[] `readfile()`-style list of lines. `channel-lines` --- @param type string Edit behavior: any `getregtype()` result, or: ---- • "b" `blockwise-visual` mode (may include width, e.g. "b3") ---- • "c" `charwise` mode ---- • "l" `linewise` mode ---- • "" guess by contents, see `setreg()` +--- - "b" `blockwise-visual` mode (may include width, e.g. "b3") +--- - "c" `charwise` mode +--- - "l" `linewise` mode +--- - "" guess by contents, see `setreg()` --- @param after boolean If true insert after cursor (like `p`), or before (like `P`). --- @param follow boolean If true place cursor at end of inserted text. function vim.api.nvim_put(lines, type, after, follow) end ---- Replaces terminal codes and `keycodes` (<CR>, <Esc>, ...) in a string with +--- Replaces terminal codes and `keycodes` ([<CR>], [<Esc>], ...) in a string with --- the internal representation. --- +--- @see replace_termcodes +--- @see cpoptions --- @param str string String to be converted. --- @param from_part boolean Legacy Vim parameter. Usually true. ---- @param do_lt boolean Also translate <lt>. Ignored if `special` is false. ---- @param special boolean Replace `keycodes`, e.g. <CR> becomes a "\r" char. +--- @param do_lt boolean Also translate [<lt>]. Ignored if `special` is false. +--- @param special boolean Replace `keycodes`, e.g. [<CR>] becomes a "\r" char. --- @return string function vim.api.nvim_replace_termcodes(str, from_part, do_lt, special) end --- Selects an item in the completion popup menu. --- --- If neither `ins-completion` nor `cmdline-completion` popup menu is active ---- this API call is silently ignored. Useful for an external UI using ---- `ui-popupmenu` to control the popup menu with the mouse. Can also be used ---- in a mapping; use <Cmd> `:map-cmd` or a Lua mapping to ensure the mapping +--- this API call is silently ignored. +--- Useful for an external UI using `ui-popupmenu` to control the popup menu with the mouse. +--- Can also be used in a mapping; use [<Cmd>] `:map-cmd` or a Lua mapping to ensure the mapping --- doesn't end completion mode. --- ---- @param item integer Index (zero-based) of the item to select. Value of -1 selects ---- nothing and restores the original text. ---- @param insert boolean For `ins-completion`, whether the selection should be ---- inserted in the buffer. Ignored for `cmdline-completion`. ---- @param finish boolean Finish the completion and dismiss the popup menu. Implies ---- {insert}. +--- @param item integer Index (zero-based) of the item to select. Value of -1 selects nothing +--- and restores the original text. +--- @param insert boolean For `ins-completion`, whether the selection should be inserted in the buffer. +--- Ignored for `cmdline-completion`. +--- @param finish boolean Finish the completion and dismiss the popup menu. Implies {insert}. --- @param opts vim.api.keyset.empty Optional parameters. Reserved for future use. function vim.api.nvim_select_popupmenu_item(item, insert, finish, opts) end @@ -1909,111 +2091,118 @@ function vim.api.nvim_set_current_win(window) end --- Set or change decoration provider for a `namespace` --- ---- This is a very general purpose interface for having Lua callbacks being ---- triggered during the redraw code. +--- This is a very general purpose interface for having Lua callbacks +--- being triggered during the redraw code. --- ---- The expected usage is to set `extmarks` for the currently redrawn buffer. ---- `nvim_buf_set_extmark()` can be called to add marks on a per-window or ---- per-lines basis. Use the `ephemeral` key to only use the mark for the ---- current screen redraw (the callback will be called again for the next ---- redraw). +--- The expected usage is to set `extmarks` for the currently +--- redrawn buffer. `nvim_buf_set_extmark()` can be called to add marks +--- on a per-window or per-lines basis. Use the `ephemeral` key to only +--- use the mark for the current screen redraw (the callback will be called +--- again for the next redraw). --- --- Note: this function should not be called often. Rather, the callbacks --- themselves can be used to throttle unneeded callbacks. the `on_start` --- callback can return `false` to disable the provider until the next redraw. ---- Similarly, return `false` in `on_win` will skip the `on_lines` calls for ---- that window (but any extmarks set in `on_win` will still be used). A ---- plugin managing multiple sources of decoration should ideally only set one ---- provider, and merge the sources internally. You can use multiple `ns_id` +--- Similarly, return `false` in `on_win` will skip the `on_line` calls +--- for that window (but any extmarks set in `on_win` will still be used). +--- A plugin managing multiple sources of decoration should ideally only set +--- one provider, and merge the sources internally. You can use multiple `ns_id` --- for the extmarks set/modified inside the callback anyway. --- ---- Note: doing anything other than setting extmarks is considered ---- experimental. Doing things like changing options are not explicitly ---- forbidden, but is likely to have unexpected consequences (such as 100% CPU ---- consumption). doing `vim.rpcnotify` should be OK, but `vim.rpcrequest` is ---- quite dubious for the moment. +--- Note: doing anything other than setting extmarks is considered experimental. +--- Doing things like changing options are not explicitly forbidden, but is +--- likely to have unexpected consequences (such as 100% CPU consumption). +--- Doing `vim.rpcnotify` should be OK, but `vim.rpcrequest` is quite dubious +--- for the moment. --- ---- Note: It is not allowed to remove or update extmarks in 'on_line' ---- callbacks. +--- Note: It is not allowed to remove or update extmarks in `on_line` callbacks. --- --- @param ns_id integer Namespace id from `nvim_create_namespace()` --- @param opts vim.api.keyset.set_decoration_provider Table of callbacks: ---- • on_start: called first on each screen redraw ---- ``` ---- ["start", tick] ---- ``` +--- - on_start: called first on each screen redraw +--- ``` +--- ["start", tick] +--- ``` +--- - on_buf: called for each buffer being redrawn (before +--- window callbacks) +--- ``` +--- ["buf", bufnr, tick] +--- ``` +--- - on_win: called when starting to redraw a specific window. +--- ``` +--- ["win", winid, bufnr, toprow, botrow] +--- ``` +--- - on_line: called for each buffer line being redrawn. +--- (The interaction with fold lines is subject to change) +--- ``` +--- ["line", winid, bufnr, row] +--- ``` +--- - on_end: called at the end of a redraw cycle +--- ``` +--- ["end", tick] +--- ``` +function vim.api.nvim_set_decoration_provider(ns_id, opts) end + +--- Sets a highlight group. --- ---- • on_buf: called for each buffer being redrawn (before window ---- callbacks) ---- ``` ---- ["buf", bufnr, tick] ---- ``` +--- Note: +--- Unlike the `:highlight` command which can update a highlight group, +--- this function completely replaces the definition. For example: +--- `nvim_set_hl(0, 'Visual', {})` will clear the highlight group +--- 'Visual'. --- ---- • on_win: called when starting to redraw a specific window. ---- ``` ---- ["win", winid, bufnr, topline, botline] ---- ``` +--- The fg and bg keys also accept the string values `"fg"` or `"bg"` +--- which act as aliases to the corresponding foreground and background +--- values of the Normal group. If the Normal group has not been defined, +--- using these values results in an error. --- ---- • on_line: called for each buffer line being redrawn. (The ---- interaction with fold lines is subject to change) ---- ``` ---- ["line", winid, bufnr, row] ---- ``` --- ---- • on_end: called at the end of a redraw cycle ---- ``` ---- ["end", tick] ---- ``` -function vim.api.nvim_set_decoration_provider(ns_id, opts) end - ---- Sets a highlight group. +--- If `link` is used in combination with other attributes; only the +--- `link` will take effect (see |:hi-link|). +--- --- --- @param ns_id integer Namespace id for this highlight `nvim_create_namespace()`. ---- Use 0 to set a highlight group globally `:highlight`. ---- Highlights from non-global namespaces are not active by ---- default, use `nvim_set_hl_ns()` or `nvim_win_set_hl_ns()` to ---- activate them. +--- Use 0 to set a highlight group globally `:highlight`. +--- Highlights from non-global namespaces are not active by default, use +--- `nvim_set_hl_ns()` or `nvim_win_set_hl_ns()` to activate them. --- @param name string Highlight group name, e.g. "ErrorMsg" --- @param val vim.api.keyset.highlight Highlight definition map, accepts the following keys: ---- • fg: color name or "#RRGGBB", see note. ---- • bg: color name or "#RRGGBB", see note. ---- • sp: color name or "#RRGGBB" ---- • blend: integer between 0 and 100 ---- • bold: boolean ---- • standout: boolean ---- • underline: boolean ---- • undercurl: boolean ---- • underdouble: boolean ---- • underdotted: boolean ---- • underdashed: boolean ---- • strikethrough: boolean ---- • italic: boolean ---- • reverse: boolean ---- • nocombine: boolean ---- • link: name of another highlight group to link to, see ---- `:hi-link`. ---- • default: Don't override existing definition `:hi-default` ---- • ctermfg: Sets foreground of cterm color `ctermfg` ---- • ctermbg: Sets background of cterm color `ctermbg` ---- • cterm: cterm attribute map, like `highlight-args`. If not ---- set, cterm attributes will match those from the attribute map ---- documented above. ---- • force: if true force update the highlight group when it ---- exists. +--- - fg: color name or "#RRGGBB", see note. +--- - bg: color name or "#RRGGBB", see note. +--- - sp: color name or "#RRGGBB" +--- - blend: integer between 0 and 100 +--- - bold: boolean +--- - standout: boolean +--- - underline: boolean +--- - undercurl: boolean +--- - underdouble: boolean +--- - underdotted: boolean +--- - underdashed: boolean +--- - strikethrough: boolean +--- - italic: boolean +--- - reverse: boolean +--- - nocombine: boolean +--- - link: name of another highlight group to link to, see `:hi-link`. +--- - default: Don't override existing definition `:hi-default` +--- - ctermfg: Sets foreground of cterm color `ctermfg` +--- - ctermbg: Sets background of cterm color `ctermbg` +--- - cterm: cterm attribute map, like `highlight-args`. If not set, +--- cterm attributes will match those from the attribute map +--- documented above. +--- - force: if true force update the highlight group when it exists. function vim.api.nvim_set_hl(ns_id, name, val) end ---- Set active namespace for highlights defined with `nvim_set_hl()`. This can ---- be set for a single window, see `nvim_win_set_hl_ns()`. +--- Set active namespace for highlights defined with `nvim_set_hl()`. This can be set for +--- a single window, see `nvim_win_set_hl_ns()`. --- --- @param ns_id integer the namespace to use function vim.api.nvim_set_hl_ns(ns_id) end ---- Set active namespace for highlights defined with `nvim_set_hl()` while ---- redrawing. +--- Set active namespace for highlights defined with `nvim_set_hl()` while redrawing. --- --- This function meant to be called while redrawing, primarily from ---- `nvim_set_decoration_provider()` on_win and on_line callbacks, which are ---- allowed to change the namespace during a redraw cycle. +--- `nvim_set_decoration_provider()` on_win and on_line callbacks, which +--- are allowed to change the namespace during a redraw cycle. --- --- @param ns_id integer the namespace to activate function vim.api.nvim_set_hl_ns_fast(ns_id) end @@ -2022,37 +2211,34 @@ function vim.api.nvim_set_hl_ns_fast(ns_id) end --- --- To set a buffer-local mapping, use `nvim_buf_set_keymap()`. --- ---- Unlike `:map`, leading/trailing whitespace is accepted as part of the ---- {lhs} or {rhs}. Empty {rhs} is <Nop>. `keycodes` are replaced as usual. +--- Unlike `:map`, leading/trailing whitespace is accepted as part of the {lhs} or {rhs}. +--- Empty {rhs} is [<Nop>]. `keycodes` are replaced as usual. --- --- Example: --- --- ```vim ---- call nvim_set_keymap('n', ' <NL>', '', {'nowait': v:true}) +--- call nvim_set_keymap('n', ' <NL>', '', {'nowait': v:true}) --- ``` --- --- is equivalent to: --- --- ```vim ---- nmap <nowait> <Space><NL> <Nop> +--- nmap <nowait> <Space><NL> <Nop> --- ``` --- ---- --- @param mode string Mode short-name (map command prefix: "n", "i", "v", "x", …) ---- or "!" for `:map!`, or empty string for `:map`. "ia", "ca" or ---- "!a" for abbreviation in Insert mode, Cmdline mode, or both, ---- respectively +--- or "!" for `:map!`, or empty string for `:map`. +--- "ia", "ca" or "!a" for abbreviation in Insert mode, Cmdline mode, or both, respectively --- @param lhs string Left-hand-side `{lhs}` of the mapping. --- @param rhs string Right-hand-side `{rhs}` of the mapping. ---- @param opts vim.api.keyset.keymap Optional parameters map: Accepts all `:map-arguments` as keys ---- except <buffer>, values are booleans (default false). Also: ---- • "noremap" disables `recursive_mapping`, like `:noremap` ---- • "desc" human-readable description. ---- • "callback" Lua function called in place of {rhs}. ---- • "replace_keycodes" (boolean) When "expr" is true, replace ---- keycodes in the resulting string (see ---- `nvim_replace_termcodes()`). Returning nil from the Lua ---- "callback" is equivalent to returning an empty string. +--- @param opts vim.api.keyset.keymap Optional parameters map: Accepts all `:map-arguments` as keys except [<buffer>], +--- values are booleans (default false). Also: +--- - "noremap" disables `recursive_mapping`, like `:noremap` +--- - "desc" human-readable description. +--- - "callback" Lua function called in place of {rhs}. +--- - "replace_keycodes" (boolean) When "expr" is true, replace keycodes in the +--- resulting string (see `nvim_replace_termcodes()`). Returning nil from the Lua +--- "callback" is equivalent to returning an empty string. function vim.api.nvim_set_keymap(mode, lhs, rhs, opts) end --- @deprecated @@ -2069,10 +2255,10 @@ function vim.api.nvim_set_option(name, value) end --- @param name string Option name --- @param value any New option value --- @param opts vim.api.keyset.option Optional parameters ---- • scope: One of "global" or "local". Analogous to `:setglobal` ---- and `:setlocal`, respectively. ---- • win: `window-ID`. Used for setting window local option. ---- • buf: Buffer number. Used for setting buffer local option. +--- - scope: One of "global" or "local". Analogous to +--- `:setglobal` and `:setlocal`, respectively. +--- - win: `window-ID`. Used for setting window local option. +--- - buf: Buffer number. Used for setting buffer local option. function vim.api.nvim_set_option_value(name, value, opts) end --- Sets a global (g:) variable. @@ -2087,11 +2273,11 @@ function vim.api.nvim_set_var(name, value) end --- @param value any Variable value function vim.api.nvim_set_vvar(name, value) end ---- Calculates the number of display cells occupied by `text`. Control ---- characters including <Tab> count as one cell. +--- Calculates the number of display cells occupied by `text`. +--- Control characters including [<Tab>] count as one cell. --- --- @param text string Some text ---- @return integer +--- @return integer # Number of cells function vim.api.nvim_strwidth(text) end --- Removes a tab-scoped (t:) variable @@ -2103,32 +2289,32 @@ function vim.api.nvim_tabpage_del_var(tabpage, name) end --- Gets the tabpage number --- --- @param tabpage integer Tabpage handle, or 0 for current tabpage ---- @return integer +--- @return integer # Tabpage number function vim.api.nvim_tabpage_get_number(tabpage) end --- Gets a tab-scoped (t:) variable --- --- @param tabpage integer Tabpage handle, or 0 for current tabpage --- @param name string Variable name ---- @return any +--- @return any # Variable value function vim.api.nvim_tabpage_get_var(tabpage, name) end --- Gets the current window in a tabpage --- --- @param tabpage integer Tabpage handle, or 0 for current tabpage ---- @return integer +--- @return integer # Window handle function vim.api.nvim_tabpage_get_win(tabpage) end --- Checks if a tabpage is valid --- --- @param tabpage integer Tabpage handle, or 0 for current tabpage ---- @return boolean +--- @return boolean # true if the tabpage is valid, false otherwise function vim.api.nvim_tabpage_is_valid(tabpage) end --- Gets the windows in a tabpage --- --- @param tabpage integer Tabpage handle, or 0 for current tabpage ---- @return integer[] +--- @return integer[] # List of windows in `tabpage` function vim.api.nvim_tabpage_list_wins(tabpage) end --- Sets a tab-scoped (t:) variable @@ -2146,18 +2332,21 @@ function vim.api.nvim_tabpage_set_win(tabpage, win) end --- Calls a function with window as temporary current window. --- +--- +--- @see `:help win_execute()` +--- @see vim.api.nvim_buf_call --- @param window integer Window handle, or 0 for current window --- @param fun function Function to call inside the window (currently Lua callable ---- only) ---- @return any +--- only) +--- @return any # Return value of function. function vim.api.nvim_win_call(window, fun) end --- Closes the window (like `:close` with a `window-ID`). --- --- @param window integer Window handle, or 0 for current window --- @param force boolean Behave like `:close!` The last window of a buffer with ---- unwritten changes can be closed. The buffer will become ---- hidden, even if 'hidden' is not set. +--- unwritten changes can be closed. The buffer will become +--- hidden, even if 'hidden' is not set. function vim.api.nvim_win_close(window, force) end --- Removes a window-scoped (w:) variable @@ -2169,7 +2358,7 @@ function vim.api.nvim_win_del_var(window, name) end --- Gets the current buffer in a window --- --- @param window integer Window handle, or 0 for current window ---- @return integer +--- @return integer # Buffer handle function vim.api.nvim_win_get_buf(window) end --- Gets window configuration. @@ -2179,27 +2368,29 @@ function vim.api.nvim_win_get_buf(window) end --- `relative` is empty for normal windows. --- --- @param window integer Window handle, or 0 for current window ---- @return vim.api.keyset.win_config +--- @return vim.api.keyset.win_config # Map defining the window configuration, see |nvim_open_win()| function vim.api.nvim_win_get_config(window) end --- Gets the (1,0)-indexed, buffer-relative cursor position for a given window --- (different windows showing the same buffer have independent cursor --- positions). `api-indexing` --- +--- +--- @see `:help getcurpos()` --- @param window integer Window handle, or 0 for current window ---- @return integer[] +--- @return integer[] # (row, col) tuple function vim.api.nvim_win_get_cursor(window) end --- Gets the window height --- --- @param window integer Window handle, or 0 for current window ---- @return integer +--- @return integer # Height as a count of rows function vim.api.nvim_win_get_height(window) end --- Gets the window number --- --- @param window integer Window handle, or 0 for current window ---- @return integer +--- @return integer # Window number function vim.api.nvim_win_get_number(window) end --- @deprecated @@ -2211,34 +2402,34 @@ function vim.api.nvim_win_get_option(window, name) end --- Gets the window position in display cells. First position is zero. --- --- @param window integer Window handle, or 0 for current window ---- @return integer[] +--- @return integer[] # (row, col) tuple with the window position function vim.api.nvim_win_get_position(window) end --- Gets the window tabpage --- --- @param window integer Window handle, or 0 for current window ---- @return integer +--- @return integer # Tabpage that contains the window function vim.api.nvim_win_get_tabpage(window) end --- Gets a window-scoped (w:) variable --- --- @param window integer Window handle, or 0 for current window --- @param name string Variable name ---- @return any +--- @return any # Variable value function vim.api.nvim_win_get_var(window, name) end --- Gets the window width --- --- @param window integer Window handle, or 0 for current window ---- @return integer +--- @return integer # Width as a count of columns function vim.api.nvim_win_get_width(window) end --- Closes the window and hide the buffer it contains (like `:hide` with a --- `window-ID`). --- ---- Like `:hide` the buffer becomes hidden unless another window is editing ---- it, or 'bufhidden' is `unload`, `delete` or `wipe` as opposed to `:close` ---- or `nvim_win_close()`, which will close the buffer. +--- Like `:hide` the buffer becomes hidden unless another window is editing it, +--- or 'bufhidden' is `unload`, `delete` or `wipe` as opposed to `:close` or +--- `nvim_win_close()`, which will close the buffer. --- --- @param window integer Window handle, or 0 for current window function vim.api.nvim_win_hide(window) end @@ -2246,7 +2437,7 @@ function vim.api.nvim_win_hide(window) end --- Checks if a window is valid --- --- @param window integer Window handle, or 0 for current window ---- @return boolean +--- @return boolean # true if the window is valid, false otherwise function vim.api.nvim_win_is_valid(window) end --- Sets the current buffer in a window, without side effects @@ -2261,12 +2452,15 @@ function vim.api.nvim_win_set_buf(window, buffer) end --- When reconfiguring a window, absent option keys will not be changed. --- `row`/`col` and `relative` must be reconfigured together. --- +--- +--- @see vim.api.nvim_open_win --- @param window integer Window handle, or 0 for current window ---- @param config vim.api.keyset.win_config Map defining the window configuration, see `nvim_open_win()` +--- @param config vim.api.keyset.win_config Map defining the window configuration, +--- see `nvim_open_win()` function vim.api.nvim_win_set_config(window, config) end ---- Sets the (1,0)-indexed cursor position in the window. `api-indexing` This ---- scrolls the window even if it is not the current one. +--- Sets the (1,0)-indexed cursor position in the window. `api-indexing` +--- This scrolls the window even if it is not the current one. --- --- @param window integer Window handle, or 0 for current window --- @param pos integer[] (row, col) tuple representing the new position @@ -2278,9 +2472,9 @@ function vim.api.nvim_win_set_cursor(window, pos) end --- @param height integer Height as a count of rows function vim.api.nvim_win_set_height(window, height) end ---- Set highlight namespace for a window. This will use highlights defined ---- with `nvim_set_hl()` for this namespace, but fall back to global ---- highlights (ns=0) when missing. +--- Set highlight namespace for a window. This will use highlights defined with +--- `nvim_set_hl()` for this namespace, but fall back to global highlights (ns=0) when +--- missing. --- --- This takes precedence over the 'winhighlight' option. --- @@ -2308,28 +2502,32 @@ function vim.api.nvim_win_set_var(window, name, value) end --- @param width integer Width as a count of columns function vim.api.nvim_win_set_width(window, width) end ---- Computes the number of screen lines occupied by a range of text in a given ---- window. Works for off-screen text and takes folds into account. +--- Computes the number of screen lines occupied by a range of text in a given window. +--- Works for off-screen text and takes folds into account. --- ---- Diff filler or virtual lines above a line are counted as a part of that ---- line, unless the line is on "start_row" and "start_vcol" is specified. +--- Diff filler or virtual lines above a line are counted as a part of that line, +--- unless the line is on "start_row" and "start_vcol" is specified. --- ---- Diff filler or virtual lines below the last buffer line are counted in the ---- result when "end_row" is omitted. +--- Diff filler or virtual lines below the last buffer line are counted in the result +--- when "end_row" is omitted. --- --- Line indexing is similar to `nvim_buf_get_text()`. --- +--- @see `:help virtcol()` for text width. --- @param window integer Window handle, or 0 for current window. --- @param opts vim.api.keyset.win_text_height Optional parameters: ---- • start_row: Starting line index, 0-based inclusive. When ---- omitted start at the very top. ---- • end_row: Ending line index, 0-based inclusive. When omitted ---- end at the very bottom. ---- • start_vcol: Starting virtual column index on "start_row", ---- 0-based inclusive, rounded down to full screen lines. When ---- omitted include the whole line. ---- • end_vcol: Ending virtual column index on "end_row", 0-based ---- exclusive, rounded up to full screen lines. When omitted ---- include the whole line. ---- @return table<string,any> +--- - start_row: Starting line index, 0-based inclusive. +--- When omitted start at the very top. +--- - end_row: Ending line index, 0-based inclusive. +--- When omitted end at the very bottom. +--- - start_vcol: Starting virtual column index on "start_row", +--- 0-based inclusive, rounded down to full screen lines. +--- When omitted include the whole line. +--- - end_vcol: Ending virtual column index on "end_row", +--- 0-based exclusive, rounded up to full screen lines. +--- When omitted include the whole line. +--- @return table<string,any> # Dict containing text height information, with these keys: +--- - all: The total number of screen lines occupied by the range. +--- - fill: The number of diff filler or virtual lines among them. +--- function vim.api.nvim_win_text_height(window, opts) end diff --git a/runtime/lua/vim/_meta/api_keysets.lua b/runtime/lua/vim/_meta/api_keysets.lua index f7cd92a3b2..2fe5c32faf 100644 --- a/runtime/lua/vim/_meta/api_keysets.lua +++ b/runtime/lua/vim/_meta/api_keysets.lua @@ -197,6 +197,9 @@ error('Cannot require a meta file') --- @field desc? string --- @field replace_keycodes? boolean +--- @class vim.api.keyset.ns_opts +--- @field wins? any[] + --- @class vim.api.keyset.open_term --- @field on_input? function --- @field force_crlf? boolean diff --git a/runtime/lua/vim/_meta/api_keysets_extra.lua b/runtime/lua/vim/_meta/api_keysets_extra.lua index 76b56b04e7..81bce50746 100644 --- a/runtime/lua/vim/_meta/api_keysets_extra.lua +++ b/runtime/lua/vim/_meta/api_keysets_extra.lua @@ -23,16 +23,16 @@ error('Cannot require a meta file') --- @field conceal? boolean --- @field spell? boolean --- @field ui_watched? boolean ---- @field url? boolean +--- @field url? string --- @field hl_mode? string --- ---- @field virt_text? {[1]: string, [2]: string}[] +--- @field virt_text? [string, string][] --- @field virt_text_hide? boolean --- @field virt_text_repeat_linebreak? boolean --- @field virt_text_win_col? integer --- @field virt_text_pos? string --- ---- @field virt_lines? {[1]: string, [2]: string}[][] +--- @field virt_lines? [string, string][][] --- @field virt_lines_above? boolean --- @field virt_lines_leftcol? boolean --- @@ -43,11 +43,17 @@ error('Cannot require a meta file') --- @field line_hl_group? string --- @field cursorline_hl_group? string ---- @class vim.api.keyset.get_extmark_item +--- @class vim.api.keyset.get_extmark_item_by_id --- @field [1] integer row --- @field [2] integer col --- @field [3] vim.api.keyset.extmark_details? +--- @class vim.api.keyset.get_extmark_item +--- @field [1] integer extmark_id +--- @field [2] integer row +--- @field [3] integer col +--- @field [4] vim.api.keyset.extmark_details? + --- @class vim.api.keyset.get_mark --- @field [1] integer row --- @field [2] integer col @@ -96,20 +102,29 @@ error('Cannot require a meta file') --- @field strikethrough? true --- @field altfont? true --- @field nocombine? true - ---- @class vim.api.keyset.hl_info.cterm : vim.api.keyset.hl_info.base --- @field ctermfg? integer --- @field ctermbg? integer + +--- @class vim.api.keyset.hl_info.cterm : vim.api.keyset.hl_info.base --- @field foreground? integer --- @field background? integer ---- @class vim.api.keyset.hl_info : vim.api.keyset.hl_info.base +--- @class vim.api.keyset.get_hl_info : vim.api.keyset.hl_info.base --- @field fg? integer --- @field bg? integer --- @field sp? integer --- @field default? true +--- @field blend? integer +--- @field cterm? vim.api.keyset.hl_info.cterm + +--- @class vim.api.keyset.set_hl_info : vim.api.keyset.hl_info.base +--- @field fg? integer|string +--- @field bg? integer|string +--- @field sp? integer|string +--- @field default? true --- @field link? string --- @field blend? integer +--- @field force? true --- @field cterm? vim.api.keyset.hl_info.cterm --- @class vim.api.keyset.get_mode diff --git a/runtime/lua/vim/_meta/builtin.lua b/runtime/lua/vim/_meta/builtin.lua index 75737bd040..13bd1c1294 100644 --- a/runtime/lua/vim/_meta/builtin.lua +++ b/runtime/lua/vim/_meta/builtin.lua @@ -121,6 +121,7 @@ function vim.stricmp(a, b) end --- @param str string --- @param index integer --- @param use_utf16? boolean +--- @return integer function vim.str_byteindex(str, index, use_utf16) end --- Gets a list of the starting byte positions of each UTF-8 codepoint in the given string. @@ -181,8 +182,8 @@ function vim.str_utf_end(str, index) end --- that sequence. --- @param str string --- @param index? integer ---- @return integer UTF-32 index ---- @return integer UTF-16 index +--- @return integer # UTF-32 index +--- @return integer # UTF-16 index function vim.str_utfindex(str, index) end --- The result is a String, which is the text {str} converted from @@ -247,7 +248,7 @@ function vim.schedule(fn) end --- - If {callback} errors, the error is raised. function vim.wait(time, callback, interval, fast_only) end ---- Attach to ui events, similar to |nvim_ui_attach()| but receive events +--- Attach to |ui-events|, similar to |nvim_ui_attach()| but receive events --- as Lua callback. Can be used to implement screen elements like --- popupmenu or message handling in Lua. --- @@ -281,6 +282,8 @@ function vim.wait(time, callback, interval, fast_only) end --- end) --- ``` --- +--- @since 0 +--- --- @param ns integer --- @param options table<string, any> --- @param callback fun() diff --git a/runtime/lua/vim/_meta/builtin_types.lua b/runtime/lua/vim/_meta/builtin_types.lua index 9f0d2e7038..aca6649957 100644 --- a/runtime/lua/vim/_meta/builtin_types.lua +++ b/runtime/lua/vim/_meta/builtin_types.lua @@ -25,7 +25,7 @@ --- @field variables table<string,any> --- @field windows integer[] ---- @alias vim.fn.getjumplist.ret {[1]: vim.fn.getjumplist.ret.item[], [2]: integer} +--- @alias vim.fn.getjumplist.ret [vim.fn.getjumplist.ret.item[], integer] --- @class vim.fn.getjumplist.ret.item --- @field bufnr integer @@ -34,6 +34,11 @@ --- @field filename? string --- @field lnum integer +--- @class vim.fn.getmarklist.ret.item +--- @field mark string +--- @field pos [integer, integer, integer, integer] +--- @field file string + --- @class vim.fn.getmousepos.ret --- @field screenrow integer --- @field screencol integer @@ -135,3 +140,69 @@ --- @field sid string --- @field variables? table<string, any> --- @field version 1 + +--- @class vim.fn.undotree.entry +--- +--- Undo sequence number. Same as what appears in +--- \|:undolist|. +--- @field seq integer +--- +--- Timestamp when the change happened. Use +--- \|strftime()| to convert to something readable. +--- @field time integer +--- +--- Only appears in the item that is the last one +--- that was added. This marks the last change +--- and where further changes will be added. +--- @field newhead? integer +--- +--- Only appears in the item that is the last one +--- that was undone. This marks the current +--- position in the undo tree, the block that will +--- be used by a redo command. When nothing was +--- undone after the last change this item will +--- not appear anywhere. +--- @field curhead? integer +--- +--- Only appears on the last block before a file +--- write. The number is the write count. The +--- first write has number 1, the last one the +--- "save_last" mentioned above. +--- @field save integer +--- +--- Alternate entry. This is again a List of undo +--- blocks. Each item may again have an "alt" +--- item. +--- @field alt vim.fn.undotree.entry[] + +--- @class vim.fn.undotree.ret +--- +--- The highest undo sequence number used. +--- @field seq_last integer +--- +--- The sequence number of the current position in +--- the undo tree. This differs from "seq_last" +--- when some changes were undone. +--- @field seq_cur integer +--- +--- Time last used for |:earlier| and related +--- commands. Use |strftime()| to convert to +--- something readable. +--- @field time_cur integer +--- +--- Number of the last file write. Zero when no +--- write yet. +--- @field save_last integer +--- +--- Number of the current position in the undo +--- tree. +--- @field save_cur integer +--- +--- Non-zero when the last undo block was synced. +--- This happens when waiting from input from the +--- user. See |undo-blocks|. +--- @field synced integer +--- +--- A list of dictionaries with information about +--- undo blocks. +--- @field entries vim.fn.undotree.entry[] diff --git a/runtime/lua/vim/_meta/diff.lua b/runtime/lua/vim/_meta/diff.lua index 617bc87f59..4803ed4775 100644 --- a/runtime/lua/vim/_meta/diff.lua +++ b/runtime/lua/vim/_meta/diff.lua @@ -11,19 +11,19 @@ --- - `count_a` (`integer`): Hunk size in {a}. --- - `start_b` (`integer`): Start line of hunk in {b}. --- - `count_b` (`integer`): Hunk size in {b}. ---- @field on_hunk fun(start_a: integer, count_a: integer, start_b: integer, count_b: integer): integer +--- @field on_hunk? fun(start_a: integer, count_a: integer, start_b: integer, count_b: integer): integer? --- --- Form of the returned diff: --- - `unified`: String in unified format. --- - `indices`: Array of hunk locations. --- Note: This option is ignored if `on_hunk` is used. --- (default: `'unified'`) ---- @field result_type 'unified'|'indices' +--- @field result_type? 'unified'|'indices' --- --- Run linematch on the resulting hunks from xdiff. When integer, only hunks --- upto this size in lines are run through linematch. --- Requires `result_type = indices`, ignored otherwise. ---- @field linematch boolean|integer +--- @field linematch? boolean|integer --- --- Diff algorithm to use. Values: --- - `myers`: the default algorithm @@ -31,15 +31,15 @@ --- - `patience`: patience diff algorithm --- - `histogram`: histogram diff algorithm --- (default: `'myers'`) ---- @field algorithm 'myers'|'minimal'|'patience'|'histogram' ---- @field ctxlen integer Context length ---- @field interhunkctxlen integer Inter hunk context length ---- @field ignore_whitespace boolean Ignore whitespace ---- @field ignore_whitespace_change boolean Ignore whitespace change ---- @field ignore_whitespace_change_at_eol boolean Ignore whitespace change at end-of-line. ---- @field ignore_cr_at_eol boolean Ignore carriage return at end-of-line ---- @field ignore_blank_lines boolean Ignore blank lines ---- @field indent_heuristic boolean Use the indent heuristic for the internal diff library. +--- @field algorithm? 'myers'|'minimal'|'patience'|'histogram' +--- @field ctxlen? integer Context length +--- @field interhunkctxlen? integer Inter hunk context length +--- @field ignore_whitespace? boolean Ignore whitespace +--- @field ignore_whitespace_change? boolean Ignore whitespace change +--- @field ignore_whitespace_change_at_eol? boolean Ignore whitespace change at end-of-line. +--- @field ignore_cr_at_eol? boolean Ignore carriage return at end-of-line +--- @field ignore_blank_lines? boolean Ignore blank lines +--- @field indent_heuristic? boolean Use the indent heuristic for the internal diff library. -- luacheck: no unused args @@ -65,7 +65,7 @@ --- ---@param a string First string to compare ---@param b string Second string to compare ----@param opts vim.diff.Opts +---@param opts? vim.diff.Opts ---@return string|integer[][]? --- See {opts.result_type}. `nil` if {opts.on_hunk} is given. function vim.diff(a, b, opts) end diff --git a/runtime/lua/vim/_meta/lpeg.lua b/runtime/lua/vim/_meta/lpeg.lua index 73b3375c82..d354de95df 100644 --- a/runtime/lua/vim/_meta/lpeg.lua +++ b/runtime/lua/vim/_meta/lpeg.lua @@ -2,7 +2,7 @@ error('Cannot require a meta file') -- These types were taken from https://github.com/LuaCATS/lpeg --- (based on revision e6789e28e5b91a4a277a2a03081d708c403a3e34) +-- (based on revision 33f4ff5343a64cf613a0634d70092fbc2b64291b) -- with types being renamed to include the vim namespace and with some descriptions made less verbose. --- @brief <pre>help @@ -22,17 +22,18 @@ vim.lpeg = {} --- @nodoc --- @class vim.lpeg.Pattern +--- @operator len: vim.lpeg.Pattern --- @operator unm: vim.lpeg.Pattern --- @operator add(vim.lpeg.Pattern): vim.lpeg.Pattern --- @operator sub(vim.lpeg.Pattern): vim.lpeg.Pattern --- @operator mul(vim.lpeg.Pattern): vim.lpeg.Pattern --- @operator mul(vim.lpeg.Capture): vim.lpeg.Pattern --- @operator div(string): vim.lpeg.Capture ---- @operator div(number): vim.lpeg.Capture +--- @operator div(integer): vim.lpeg.Capture --- @operator div(table): vim.lpeg.Capture --- @operator div(function): vim.lpeg.Capture ---- @operator pow(number): vim.lpeg.Pattern ---- @operator mod(function): nil +--- @operator pow(integer): vim.lpeg.Pattern +--- @operator mod(function): vim.lpeg.Capture local Pattern = {} --- @alias vim.lpeg.Capture vim.lpeg.Pattern @@ -55,11 +56,12 @@ local Pattern = {} --- assert(pattern:match('1 hello') == nil) --- ``` --- ---- @param pattern vim.lpeg.Pattern +--- @param pattern vim.lpeg.Pattern|string|integer|boolean|table|function --- @param subject string --- @param init? integer ---- @return integer|vim.lpeg.Capture|nil -function vim.lpeg.match(pattern, subject, init) end +--- @param ... any +--- @return any ... +function vim.lpeg.match(pattern, subject, init, ...) end --- Matches the given `pattern` against the `subject` string. If the match succeeds, returns the --- index in the subject of the first character after the match, or the captured values (if the @@ -81,8 +83,9 @@ function vim.lpeg.match(pattern, subject, init) end --- --- @param subject string --- @param init? integer ---- @return integer|vim.lpeg.Capture|nil -function Pattern:match(subject, init) end +--- @param ... any +--- @return any ... +function Pattern:match(subject, init, ...) end --- Returns the string `"pattern"` if the given value is a pattern, otherwise `nil`. --- @@ -123,7 +126,7 @@ function vim.lpeg.P(value) end --- Pattern `patt` must match only strings with some fixed length, and it cannot contain captures. --- Like the `and` predicate, this pattern never consumes any input, independently of success or failure. --- ---- @param pattern vim.lpeg.Pattern +--- @param pattern vim.lpeg.Pattern|string|integer|boolean|table --- @return vim.lpeg.Pattern function vim.lpeg.B(pattern) end @@ -163,7 +166,7 @@ function vim.lpeg.S(string) end --- assert(b:match('(') == nil) --- ``` --- ---- @param v string|integer +--- @param v boolean|string|number|function|table|thread|userdata|lightuserdata --- @return vim.lpeg.Pattern function vim.lpeg.V(v) end @@ -227,7 +230,7 @@ function vim.lpeg.locale(tab) end --- assert(c == 'c') --- ``` --- ---- @param patt vim.lpeg.Pattern +--- @param patt vim.lpeg.Pattern|string|integer|boolean|table|function --- @return vim.lpeg.Capture function vim.lpeg.C(patt) end @@ -258,7 +261,7 @@ function vim.lpeg.Cc(...) end --- `func(...func(func(C1, C2), C3)...,Cn)`, that is, it will fold (or accumulate, or reduce) the captures from --- `patt` using function `func`. This capture assumes that `patt` should produce at least one capture with at --- least one value (of any type), which becomes the initial value of an accumulator. (If you need a specific ---- initial value, you may prefix a constant captureto `patt`.) For each subsequent capture, LPeg calls `func` +--- initial value, you may prefix a constant capture to `patt`.) For each subsequent capture, LPeg calls `func` --- with this accumulator as the first argument and all values produced by the capture as extra arguments; --- the first result from this call becomes the new value for the accumulator. The final value of the accumulator --- becomes the captured value. @@ -273,7 +276,7 @@ function vim.lpeg.Cc(...) end --- assert(sum:match('10,30,43') == 83) --- ``` --- ---- @param patt vim.lpeg.Pattern +--- @param patt vim.lpeg.Pattern|string|integer|boolean|table|function --- @param func fun(acc, newvalue) --- @return vim.lpeg.Capture function vim.lpeg.Cf(patt, func) end @@ -282,7 +285,7 @@ function vim.lpeg.Cf(patt, func) end --- The group may be anonymous (if no name is given) or named with the given name (which --- can be any non-nil Lua value). --- ---- @param patt vim.lpeg.Pattern +--- @param patt vim.lpeg.Pattern|string|integer|boolean|table|function --- @param name? string --- @return vim.lpeg.Capture function vim.lpeg.Cg(patt, name) end @@ -320,7 +323,7 @@ function vim.lpeg.Cp() end --- assert(gsub('Hello, xxx!', 'xxx', 'World') == 'Hello, World!') --- ``` --- ---- @param patt vim.lpeg.Pattern +--- @param patt vim.lpeg.Pattern|string|integer|boolean|table|function --- @return vim.lpeg.Capture function vim.lpeg.Cs(patt) end @@ -329,7 +332,7 @@ function vim.lpeg.Cs(patt) end --- Moreover, for each named capture group created by `patt`, the first value of the group is put into --- the table with the group name as its key. The captured value is only the table. --- ---- @param patt vim.lpeg.Pattern|'' +--- @param patt vim.lpeg.Pattern|string|integer|boolean|table|function --- @return vim.lpeg.Capture function vim.lpeg.Ct(patt) end @@ -343,7 +346,7 @@ function vim.lpeg.Ct(patt) end --- (so, to return true is equivalent to return `i`). If the call returns `false`, `nil`, or no value, the match fails. --- Any extra values returned by the function become the values produced by the capture. --- ---- @param patt vim.lpeg.Pattern ---- @param fn function +--- @param patt vim.lpeg.Pattern|string|integer|boolean|table|function +--- @param fn fun(s: string, i: integer, ...: any): (position: boolean|integer, ...: any) --- @return vim.lpeg.Capture function vim.lpeg.Cmt(patt, fn) end diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index 428b7c4d4f..ce3ff4f861 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -544,7 +544,7 @@ vim.wo.bri = vim.wo.breakindent --- applying 'breakindent', even if the resulting --- text should normally be narrower. This prevents --- text indented almost to the right window border ---- occupying lot of vertical space when broken. +--- occupying lots of vertical space when broken. --- (default: 20) --- shift:{n} After applying 'breakindent', the wrapped line's --- beginning will be shifted by the given number of @@ -558,9 +558,9 @@ vim.wo.bri = vim.wo.breakindent --- list:{n} Adds an additional indent for lines that match a --- numbered or bulleted list (using the --- 'formatlistpat' setting). ---- list:-1 Uses the length of a match with 'formatlistpat' ---- for indentation. --- (default: 0) +--- list:-1 Uses the width of a match with 'formatlistpat' for +--- indentation. --- column:{n} Indent at column {n}. Will overrule the other --- sub-options. Note: an additional indent may be --- added for the 'showbreak' setting. @@ -731,11 +731,12 @@ vim.go.cd = vim.go.cdpath --- The key used in Command-line Mode to open the command-line window. --- Only non-printable keys are allowed. --- The key can be specified as a single character, but it is difficult to ---- type. The preferred way is to use the <> notation. Examples: +--- type. The preferred way is to use `key-notation` (e.g. <Up>, <C-F>) or +--- a letter preceded with a caret (e.g. `^F` is CTRL-F). Examples: --- --- ```vim ---- exe "set cedit=\\<C-Y>" ---- exe "set cedit=\\<Esc>" +--- set cedit=^Y +--- set cedit=<Esc> --- ``` --- `Nvi` also has this option, but it only uses the first character. --- See `cmdwin`. @@ -785,6 +786,20 @@ vim.bo.channel = vim.o.channel --- v:fname_in name of the input file --- v:fname_out name of the output file --- Note that v:fname_in and v:fname_out will never be the same. +--- +--- The advantage of using a function call without arguments is that it is +--- faster, see `expr-option-function`. +--- +--- If the 'charconvert' expression starts with s: or `<SID>`, then it is +--- replaced with the script ID (`local-function`). Example: +--- +--- ```vim +--- set charconvert=s:MyConvert() +--- set charconvert=<SID>SomeConvert() +--- ``` +--- Otherwise the expression is evaluated in the context of the script +--- where the option was set, thus script-local items are available. +--- --- This option cannot be set from a `modeline` or in the `sandbox`, for --- security reasons. --- @@ -899,11 +914,10 @@ vim.go.cb = vim.go.clipboard --- used. The command-line will cover the last line of the screen when --- shown. --- ---- WARNING: `cmdheight=0` is considered experimental. Expect some ---- unwanted behaviour. Some 'shortmess' flags and similar ---- mechanism might fail to take effect, causing unwanted hit-enter ---- prompts. Some informative messages, both from Nvim itself and ---- plugins, will not be displayed. +--- WARNING: `cmdheight=0` is EXPERIMENTAL. Expect some unwanted behaviour. +--- Some 'shortmess' flags and similar mechanism might fail to take effect, +--- causing unwanted hit-enter prompts. Some informative messages, both +--- from Nvim itself and plugins, will not be displayed. --- --- @type integer vim.o.cmdheight = 1 @@ -974,8 +988,8 @@ vim.bo.comments = vim.o.comments vim.bo.com = vim.bo.comments --- A template for a comment. The "%s" in the value is replaced with the ---- comment text. For example, C uses "/*%s*/". Used for `commenting` and to ---- add markers for folding, see `fold-marker`. +--- comment text, and should be padded with a space when possible. +--- Used for `commenting` and to add markers for folding, see `fold-marker`. --- --- @type string vim.o.commentstring = "" @@ -1040,6 +1054,19 @@ vim.o.cfu = vim.o.completefunc vim.bo.completefunc = vim.o.completefunc vim.bo.cfu = vim.bo.completefunc +--- A comma-separated list of `complete-items` that controls the alignment +--- and display order of items in the popup menu during Insert mode +--- completion. The supported values are abbr, kind, and menu. These +--- options allow to customize how the completion items are shown in the +--- popup menu. Note: must always contain those three values in any +--- order. +--- +--- @type string +vim.o.completeitemalign = "abbr,kind,menu" +vim.o.cia = vim.o.completeitemalign +vim.go.completeitemalign = vim.o.completeitemalign +vim.go.cia = vim.go.completeitemalign + --- A comma-separated list of options for Insert mode completion --- `ins-completion`. The supported values are: --- @@ -1061,6 +1088,10 @@ vim.bo.cfu = vim.bo.completefunc --- completion in the preview window. Only works in --- combination with "menu" or "menuone". --- +--- popup Show extra information about the currently selected +--- completion in a popup window. Only works in combination +--- with "menu" or "menuone". Overrides "preview". +--- --- noinsert Do not insert any text for a match until the user selects --- a match from the menu. Only works in combination with --- "menu" or "menuone". No effect if "longest" is present. @@ -1069,13 +1100,19 @@ vim.bo.cfu = vim.bo.completefunc --- select one from the menu. Only works in combination with --- "menu" or "menuone". --- ---- popup Show extra information about the currently selected ---- completion in a popup window. Only works in combination ---- with "menu" or "menuone". Overrides "preview". +--- fuzzy Enable `fuzzy-matching` for completion candidates. This +--- allows for more flexible and intuitive matching, where +--- characters can be skipped and matches can be found even +--- if the exact sequence is not typed. Only makes a +--- difference how completion candidates are reduced from the +--- list of alternatives, but not how the candidates are +--- collected (using different completion types). --- --- @type string vim.o.completeopt = "menu,preview" vim.o.cot = vim.o.completeopt +vim.bo.completeopt = vim.o.completeopt +vim.bo.cot = vim.bo.completeopt vim.go.completeopt = vim.o.completeopt vim.go.cot = vim.go.completeopt @@ -1805,9 +1842,12 @@ vim.go.ead = vim.go.eadirection --- When on all Unicode emoji characters are considered to be full width. --- This excludes "text emoji" characters, which are normally displayed as ---- single width. Unfortunately there is no good specification for this ---- and it has been determined on trial-and-error basis. Use the ---- `setcellwidths()` function to change the behavior. +--- single width. However, such "text emoji" are treated as full-width +--- emoji if they are followed by the U+FE0F variant selector. +--- +--- Unfortunately there is no good specification for this and it has been +--- determined on trial-and-error basis. Use the `setcellwidths()` +--- function to change the behavior. --- --- @type boolean vim.o.emoji = true @@ -2177,7 +2217,7 @@ vim.go.fic = vim.go.fileignorecase --- ``` --- `FileType` `filetypes` --- When a dot appears in the value then this separates two filetype ---- names. Example: >c +--- names, it should therefore not be used for a filetype. Example: >c --- /* vim: set filetype=c.doxygen : */ --- ``` --- This will use the "c" filetype first, then the "doxygen" filetype. @@ -2185,7 +2225,7 @@ vim.go.fic = vim.go.fileignorecase --- one dot may appear. --- This option is not copied to another buffer, independent of the 's' or --- 'S' flag in 'cpoptions'. ---- Only normal file name characters can be used, `/\*?[|<>` are illegal. +--- Only alphanumeric characters, '-' and '_' can be used. --- --- @type string vim.o.filetype = "" @@ -2500,6 +2540,9 @@ vim.wo.fdt = vim.wo.foldtext --- This will invoke the mylang#Format() function in the --- autoload/mylang.vim file in 'runtimepath'. `autoload` --- +--- The advantage of using a function call without arguments is that it is +--- faster, see `expr-option-function`. +--- --- The expression is also evaluated when 'textwidth' is set and adding --- text beyond that limit. This happens under the same conditions as --- when internal formatting is used. Make sure the cursor is kept in the @@ -3265,12 +3308,15 @@ vim.go.inc = vim.go.include --- the script ID (`local-function`). Example: --- --- ```vim ---- setlocal includeexpr=s:MyIncludeExpr(v:fname) ---- setlocal includeexpr=<SID>SomeIncludeExpr(v:fname) +--- setlocal includeexpr=s:MyIncludeExpr() +--- setlocal includeexpr=<SID>SomeIncludeExpr() --- ``` --- Otherwise, the expression is evaluated in the context of the script --- where the option was set, thus script-local items are available. --- +--- It is more efficient if the value is just a function call without +--- arguments, see `expr-option-function`. +--- --- The expression will be evaluated in the `sandbox` when set from a --- modeline, see `sandbox-option`. --- This option cannot be set in a modeline when 'modelineexpr' is off. @@ -3330,7 +3376,7 @@ vim.go.is = vim.go.incsearch --- in Insert mode as specified with the 'indentkeys' option. --- When this option is not empty, it overrules the 'cindent' and --- 'smartindent' indenting. When 'lisp' is set, this option is ---- is only used when 'lispoptions' contains "expr:1". +--- only used when 'lispoptions' contains "expr:1". --- The expression is evaluated with `v:lnum` set to the line number for --- which the indent is to be computed. The cursor is also in this line --- when the expression is evaluated (but it may be moved around). @@ -3345,6 +3391,9 @@ vim.go.is = vim.go.incsearch --- Otherwise, the expression is evaluated in the context of the script --- where the option was set, thus script-local items are available. --- +--- The advantage of using a function call without arguments is that it is +--- faster, see `expr-option-function`. +--- --- The expression must return the number of spaces worth of indent. It --- can return "-1" to keep the current indent (this means 'autoindent' is --- used for the indent). @@ -3541,8 +3590,11 @@ vim.go.js = vim.go.joinspaces --- |alternate-file` or using `mark-motions` try to --- restore the `mark-view` in which the action occurred. --- +--- clean Remove unloaded buffers from the jumplist. +--- EXPERIMENTAL: this flag may change in the future. +--- --- @type string -vim.o.jumpoptions = "" +vim.o.jumpoptions = "clean" vim.o.jop = vim.o.jumpoptions vim.go.jumpoptions = vim.o.jumpoptions vim.go.jop = vim.go.jumpoptions @@ -3551,7 +3603,7 @@ vim.go.jop = vim.go.jumpoptions --- Setting this option to a valid keymap name has the side effect of --- setting 'iminsert' to one, so that the keymap becomes effective. --- 'imsearch' is also set to one, unless it was -1 ---- Only normal file name characters can be used, `/\*?[|<>` are illegal. +--- Only alphanumeric characters, '.', '-' and '_' can be used. --- --- @type string vim.o.keymap = "" @@ -3628,7 +3680,7 @@ vim.go.kp = vim.go.keywordprg --- part can be in one of two forms: --- 1. A list of pairs. Each pair is a "from" character immediately --- followed by the "to" character. Examples: "aA", "aAbBcC". ---- 2. A list of "from" characters, a semi-colon and a list of "to" +--- 2. A list of "from" characters, a semicolon and a list of "to" --- characters. Example: "abc;ABC" --- Example: "aA,fgh;FGH,cCdDeE" --- Special characters need to be preceded with a backslash. These are @@ -3720,7 +3772,7 @@ vim.go.ls = vim.go.laststatus --- update use `:redraw`. --- This may occasionally cause display errors. It is only meant to be set --- temporarily when performing an operation where redrawing may cause ---- flickering or cause a slow down. +--- flickering or cause a slowdown. --- --- @type boolean vim.o.lazyredraw = false @@ -3820,6 +3872,9 @@ vim.go.lw = vim.go.lispwords --- between tabs and spaces and for trailing blanks. Further changed by --- the 'listchars' option. --- +--- When 'listchars' does not contain "tab" field, tabs are shown as "^I" +--- or "<09>", like how unprintable characters are displayed. +--- --- The cursor is displayed at the start of the space a Tab character --- occupies, not at the end as usual in Normal mode. To get this cursor --- position while displaying Tabs with spaces, use: @@ -4533,6 +4588,20 @@ vim.go.mouset = vim.go.mousetime --- (without "unsigned" it would become "9-2019"). --- Using CTRL-X on "0" or CTRL-A on "18446744073709551615" --- (2^64 - 1) has no effect, overflow is prevented. +--- blank If included, treat numbers as signed or unsigned based on +--- preceding whitespace. If a number with a leading dash has its +--- dash immediately preceded by a non-whitespace character (i.e., +--- not a tab or a " "), the negative sign won't be considered as +--- part of the number. For example: +--- Using CTRL-A on "14" in "Carbon-14" results in "Carbon-15" +--- (without "blank" it would become "Carbon-13"). +--- Using CTRL-X on "8" in "Carbon -8" results in "Carbon -9" +--- (because -8 is preceded by whitespace. If "unsigned" was +--- set, it would result in "Carbon -7"). +--- If this format is included, overflow is prevented as if +--- "unsigned" were set. If both this format and "unsigned" are +--- included, "unsigned" will take precedence. +--- --- Numbers which simply begin with a digit in the range 1-9 are always --- considered decimal. This also happens for numbers that are not --- recognized as octal or hex. @@ -4757,7 +4826,7 @@ vim.go.pm = vim.go.patchmode --- ``` --- To use an environment variable, you probably need to replace the --- separator. Here is an example to append $INCL, in which directory ---- names are separated with a semi-colon: +--- names are separated with a semicolon: --- --- ```vim --- let &path = &path .. "," .. substitute($INCL, ';', ',', 'g') @@ -5200,6 +5269,9 @@ vim.wo.scr = vim.wo.scroll --- Minimum is 1, maximum is 100000. --- Only in `terminal` buffers. --- +--- Note: Lines that are not visible and kept in scrollback are not +--- reflown when the terminal buffer is resized horizontally. +--- --- @type integer vim.o.scrollback = -1 vim.o.scbk = vim.o.scrollback @@ -5764,7 +5836,7 @@ vim.bo.shiftwidth = vim.o.shiftwidth vim.bo.sw = vim.bo.shiftwidth --- This option helps to avoid all the `hit-enter` prompts caused by file ---- messages, for example with CTRL-G, and to avoid some other messages. +--- messages, for example with CTRL-G, and to avoid some other messages. --- It is a list of flags: --- flag meaning when present ~ --- l use "999L, 888B" instead of "999 lines, 888 bytes" *shm-l* @@ -5781,8 +5853,8 @@ vim.bo.sw = vim.bo.shiftwidth --- message; also for quickfix message (e.g., ":cn") --- s don't give "search hit BOTTOM, continuing at TOP" or *shm-s* --- "search hit TOP, continuing at BOTTOM" messages; when using ---- the search count do not show "W" after the count message (see ---- S below) +--- the search count do not show "W" before the count message +--- (see `shm-S` below) --- t truncate file message at the start if it is too long *shm-t* --- to fit on the command-line, "<" will appear in the left most --- column; ignored in Ex mode @@ -5804,7 +5876,11 @@ vim.bo.sw = vim.bo.shiftwidth --- `:silent` was used for the command; note that this also --- affects messages from 'autoread' reloading --- S do not show search count message when searching, e.g. *shm-S* ---- "[1/5]" +--- "[1/5]". When the "S" flag is not present (e.g. search count +--- is shown), the "search hit BOTTOM, continuing at TOP" and +--- "search hit TOP, continuing at BOTTOM" messages are only +--- indicated by a "W" (Mnemonic: Wrapped) letter before the +--- search count statistics. --- --- This gives you the opportunity to avoid that a change between buffers --- requires you to hit <Enter>, but still gives as useful a message as @@ -6249,7 +6325,7 @@ vim.bo.spo = vim.bo.spelloptions --- minus two. --- --- timeout:{millisec} Limit the time searching for suggestions to ---- {millisec} milli seconds. Applies to the following +--- {millisec} milliseconds. Applies to the following --- methods. When omitted the limit is 5000. When --- negative there is no limit. --- @@ -6269,9 +6345,11 @@ vim.bo.spo = vim.bo.spelloptions --- The file is used for all languages. --- --- expr:{expr} Evaluate expression {expr}. Use a function to avoid ---- trouble with spaces. `v:val` holds the badly spelled ---- word. The expression must evaluate to a List of ---- Lists, each with a suggestion and a score. +--- trouble with spaces. Best is to call a function +--- without arguments, see `expr-option-function|. +--- |v:val` holds the badly spelled word. The expression +--- must evaluate to a List of Lists, each with a +--- suggestion and a score. --- Example: --- [['the', 33], ['that', 44]] ~ --- Set 'verbose' and use `z=` to see the scores that the @@ -6338,7 +6416,8 @@ vim.go.spr = vim.go.splitright --- non-blank of the line. When off the cursor is kept in the same column --- (if possible). This applies to the commands: --- - CTRL-D, CTRL-U, CTRL-B, CTRL-F, "G", "H", "M", "L", "gg" ---- - "d", "<<" and ">>" with a linewise operator +--- - "d", "<<", "==" and ">>" with a linewise operator +--- (`operator-resulting-pos`) --- - "%" with a count --- - buffer changing commands (CTRL-^, :bnext, :bNext, etc.) --- - Ex commands that only have a line number, e.g., ":25" or ":+". @@ -6351,7 +6430,6 @@ vim.o.sol = vim.o.startofline vim.go.startofline = vim.o.startofline vim.go.sol = vim.go.startofline ---- EXPERIMENTAL --- When non-empty, this option determines the content of the area to the --- side of a window, normally containing the fold, sign and number columns. --- The format of this option is like that of 'statusline'. @@ -6359,8 +6437,7 @@ vim.go.sol = vim.go.startofline --- Some of the items from the 'statusline' format are different for --- 'statuscolumn': --- ---- %l line number of currently drawn line ---- %r relative line number of currently drawn line +--- %l line number column for currently drawn line --- %s sign column for currently drawn line --- %C fold column for currently drawn line --- @@ -6389,11 +6466,8 @@ vim.go.sol = vim.go.startofline --- Examples: --- --- ```vim ---- " Relative number with bar separator and click handlers: ---- set statuscolumn=%@SignCb@%s%=%T%@NumCb@%r│%T ---- ---- " Right aligned relative cursor line number: ---- let &stc='%=%{v:relnum?v:relnum:v:lnum} ' +--- " Line number with bar separator and click handlers: +--- set statuscolumn=%@SignCb@%s%=%T%@NumCb@%l│%T --- --- " Line numbers in hexadecimal for non wrapped part of lines: --- let &stc='%=%{v:virtnum>0?"":printf("%x",v:lnum)} ' @@ -6799,7 +6873,7 @@ vim.bo.smc = vim.bo.synmaxcol --- Syntax autocommand event is triggered with the value as argument. --- This option is not copied to another buffer, independent of the 's' or --- 'S' flag in 'cpoptions'. ---- Only normal file name characters can be used, `/\*?[|<>` are illegal. +--- Only alphanumeric characters, '.', '-' and '_' can be used. --- --- @type string vim.o.syntax = "" @@ -6807,6 +6881,22 @@ vim.o.syn = vim.o.syntax vim.bo.syntax = vim.o.syntax vim.bo.syn = vim.bo.syntax +--- This option controls the behavior when closing tab pages (e.g., using +--- `:tabclose`). When empty Vim goes to the next (right) tab page. +--- +--- Possible values (comma-separated list): +--- left If included, go to the previous tab page instead of +--- the next one. +--- uselast If included, go to the previously used tab page if +--- possible. This option takes precedence over the +--- others. +--- +--- @type string +vim.o.tabclose = "" +vim.o.tcl = vim.o.tabclose +vim.go.tabclose = vim.o.tabclose +vim.go.tcl = vim.go.tabclose + --- When non-empty, this option determines the content of the tab pages --- line at the top of the Vim window. When empty Vim will use a default --- tab pages line. See `setting-tabline` for more info. @@ -7178,7 +7268,7 @@ vim.go.tm = vim.go.timeoutlen --- When on, the title of the window will be set to the value of --- 'titlestring' (if it is not empty), or to: ---- filename [+=-] (path) - NVIM +--- filename [+=-] (path) - Nvim --- Where: --- filename the name of the file being edited --- - indicates the file cannot be modified, 'ma' off @@ -7186,7 +7276,7 @@ vim.go.tm = vim.go.timeoutlen --- = indicates the file is read-only --- =+ indicates the file is read-only and modified --- (path) is the path of the file being edited ---- - NVIM the server name `v:servername` or "NVIM" +--- - Nvim the server name `v:servername` or "Nvim" --- --- @type boolean vim.o.title = false @@ -7607,9 +7697,14 @@ vim.go.ww = vim.go.whichwrap --- Some keys will not work, such as CTRL-C, <CR> and Enter. --- <Esc> can be used, but hitting it twice in a row will still exit --- command-line as a failsafe measure. ---- Although 'wc' is a number option, you can set it to a special key: +--- Although 'wc' is a number option, it can be specified as a number, a +--- single character, a `key-notation` (e.g. <Up>, <C-F>) or a letter +--- preceded with a caret (e.g. `^F` is CTRL-F): --- --- ```vim +--- :set wc=27 +--- :set wc=X +--- :set wc=^I --- set wc=<Tab> --- ``` --- diff --git a/runtime/lua/vim/_meta/regex.lua b/runtime/lua/vim/_meta/regex.lua index 595ad96319..9c9cd7d29b 100644 --- a/runtime/lua/vim/_meta/regex.lua +++ b/runtime/lua/vim/_meta/regex.lua @@ -5,9 +5,9 @@ --- @brief Vim regexes can be used directly from Lua. Currently they only allow --- matching within a single line. ---- Parse the Vim regex {re} and return a regex object. Regexes are "magic" ---- and case-sensitive by default, regardless of 'magic' and 'ignorecase'. ---- They can be controlled with flags, see |/magic| and |/ignorecase|. +--- Parses the Vim regex `re` and returns a regex object. Regexes are "magic" and case-sensitive by +--- default, regardless of 'magic' and 'ignorecase'. They can be controlled with flags, see |/magic| +--- and |/ignorecase|. --- @param re string --- @return vim.regex function vim.regex(re) end @@ -16,20 +16,22 @@ function vim.regex(re) end --- @class vim.regex local regex = {} -- luacheck: no unused ---- Match the string against the regex. If the string should match the regex ---- precisely, surround the regex with `^` and `$`. If there was a match, the ---- byte indices for the beginning and end of the match are returned. When ---- there is no match, `nil` is returned. Because any integer is "truthy", ---- `regex:match_str()` can be directly used as a condition in an if-statement. +--- Matches string `str` against this regex. To match the string precisely, surround the regex with +--- "^" and "$". Returns the byte indices for the start and end of the match, or `nil` if there is +--- no match. Because any integer is "truthy", `regex:match_str()` can be directly used as +--- a condition in an if-statement. --- @param str string +--- @return integer? # match start (byte index), or `nil` if no match +--- @return integer? # match end (byte index), or `nil` if no match function regex:match_str(str) end ---- Match line {line_idx} (zero-based) in buffer {bufnr}. If {start} and {end} ---- are supplied, match only this byte index range. Otherwise see ---- |regex:match_str()|. If {start} is used, then the returned byte indices ---- will be relative {start}. +--- Matches line at `line_idx` (zero-based) in buffer `bufnr`. Match is restricted to byte index +--- range `start` and `end_` if given, otherwise see |regex:match_str()|. Returned byte indices are +--- relative to `start` if given. --- @param bufnr integer --- @param line_idx integer --- @param start? integer --- @param end_? integer +--- @return integer? # match start (byte index) relative to `start`, or `nil` if no match +--- @return integer? # match end (byte index) relative to `start`, or `nil` if no match function regex:match_line(bufnr, line_idx, start, end_) end diff --git a/runtime/lua/vim/_meta/spell.lua b/runtime/lua/vim/_meta/spell.lua index c636db3b53..b4e3bf6ca4 100644 --- a/runtime/lua/vim/_meta/spell.lua +++ b/runtime/lua/vim/_meta/spell.lua @@ -20,7 +20,7 @@ --- ``` --- --- @param str string ---- @return {[1]: string, [2]: 'bad'|'rare'|'local'|'caps', [3]: integer}[] +--- @return [string, 'bad'|'rare'|'local'|'caps', integer][] --- List of tuples with three items: --- - The badly spelled word. --- - The type of the spelling error: diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index f4daacfb7d..3f6deba092 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -15,7 +15,7 @@ error('Cannot require a meta file') --- echo abs(-4) --- < 4 --- ---- @param expr any +--- @param expr number --- @return number function vim.fn.abs(expr) end @@ -31,7 +31,7 @@ function vim.fn.abs(expr) end --- echo acos(-0.5) --- < 2.094395 --- ---- @param expr any +--- @param expr number --- @return number function vim.fn.acos(expr) end @@ -47,7 +47,7 @@ function vim.fn.acos(expr) end --- --- @param object any --- @param expr any ---- @return any +--- @return any # Resulting |List| or |Blob|, or 1 if {object} is not a |List| or a |Blob|. function vim.fn.add(object, expr) end --- Bitwise AND on the two arguments. The arguments are converted @@ -57,8 +57,8 @@ function vim.fn.add(object, expr) end --- let flag = and(bits, 0x80) --- < --- ---- @param expr any ---- @param expr1 any +--- @param expr number +--- @param expr1 number --- @return integer vim.fn['and'] = function(expr, expr1) end @@ -86,7 +86,7 @@ function vim.fn.api_info() end --- < --- --- @param lnum integer ---- @param text any +--- @param text string|string[] --- @return 0|1 function vim.fn.append(lnum, text) end @@ -110,7 +110,7 @@ function vim.fn.append(lnum, text) end --- <However, when {text} is an empty list then no error is given --- for an invalid {lnum}, since {lnum} isn't actually used. --- ---- @param buf any +--- @param buf integer|string --- @param lnum integer --- @param text string --- @return 0|1 @@ -195,7 +195,7 @@ function vim.fn.asin(expr) end --- Also see |assert_fails()|, |assert_nobeep()| and --- |assert-return|. --- ---- @param cmd any +--- @param cmd string --- @return 0|1 function vim.fn.assert_beeps(cmd) end @@ -203,16 +203,17 @@ function vim.fn.assert_beeps(cmd) end --- added to |v:errors| and 1 is returned. Otherwise zero is --- returned. |assert-return| --- The error is in the form "Expected {expected} but got ---- {actual}". When {msg} is present it is prefixed to that. +--- {actual}". When {msg} is present it is prefixed to that, +--- along with the location of the assert when run from a script. --- --- There is no automatic conversion, the String "4" is different --- from the Number 4. And the number 4 is different from the --- Float 4.0. The value of 'ignorecase' is not used here, case --- always matters. --- Example: >vim ---- assert_equal('foo', 'bar') ---- <Will result in a string to be added to |v:errors|: ---- test.vim line 12: Expected 'foo' but got 'bar' ~ +--- call assert_equal('foo', 'bar', 'baz') +--- <Will add the following to |v:errors|: +--- test.vim line 12: baz: Expected 'foo' but got 'bar' ~ --- --- @param expected any --- @param actual any @@ -226,8 +227,10 @@ function vim.fn.assert_equal(expected, actual, msg) end --- When {fname-one} or {fname-two} does not exist the error will --- mention that. --- +--- @param fname-one string +--- @param fname-two string --- @return 0|1 -function vim.fn.assert_equalfile() end +function vim.fn.assert_equalfile(fname-one, fname-two) end --- When v:exception does not contain the string {error} an error --- message is added to |v:errors|. Also see |assert-return|. @@ -254,25 +257,25 @@ function vim.fn.assert_exception(error, msg) end --- When {error} is a string it must be found literally in the --- first reported error. Most often this will be the error code, --- including the colon, e.g. "E123:". >vim ---- assert_fails('bad cmd', 'E987:') +--- call assert_fails('bad cmd', 'E987:') --- < --- When {error} is a |List| with one or two strings, these are --- used as patterns. The first pattern is matched against the --- first reported error: >vim ---- assert_fails('cmd', ['E987:.*expected bool']) +--- call assert_fails('cmd', ['E987:.*expected bool']) --- <The second pattern, if present, is matched against the last --- reported error. To only match the last error use an empty --- string for the first error: >vim ---- assert_fails('cmd', ['', 'E987:']) +--- call assert_fails('cmd', ['', 'E987:']) --- < --- If {msg} is empty then it is not used. Do this to get the --- default message when passing the {lnum} argument. ---- +--- *E1115* --- When {lnum} is present and not negative, and the {error} --- argument is present and matches, then this is compared with --- the line number at which the error was reported. That can be --- the line number in a function or in a script. ---- +--- *E1116* --- When {context} is present it is used as a pattern and matched --- against the context (script name or function name) where --- {lnum} is located in. @@ -280,7 +283,7 @@ function vim.fn.assert_exception(error, msg) end --- Note that beeping is not considered an error, and some failing --- commands only beep. Use |assert_beeps()| for those. --- ---- @param cmd any +--- @param cmd string --- @param error? any --- @param msg? any --- @param lnum? integer @@ -291,7 +294,8 @@ function vim.fn.assert_fails(cmd, error, msg, lnum, context) end --- When {actual} is not false an error message is added to --- |v:errors|, like with |assert_equal()|. --- The error is in the form "Expected False but got {actual}". ---- When {msg} is present it is prepended to that. +--- When {msg} is present it is prefixed to that, along with the +--- location of the assert when run from a script. --- Also see |assert-return|. --- --- A value is false when it is zero. When {actual} is not a @@ -309,17 +313,18 @@ function vim.fn.assert_false(actual, msg) end --- but got {actual}". When {msg} is present it is prefixed to --- that. --- ---- @param lower any ---- @param upper any ---- @param actual any ---- @param msg? any +--- @param lower number +--- @param upper number +--- @param actual number +--- @param msg? string --- @return 0|1 function vim.fn.assert_inrange(lower, upper, actual, msg) end --- When {pattern} does not match {actual} an error message is --- added to |v:errors|. Also see |assert-return|. --- The error is in the form "Pattern {pattern} does not match ---- {actual}". When {msg} is present it is prefixed to that. +--- {actual}". When {msg} is present it is prefixed to that, +--- along with the location of the assert when run from a script. --- --- {pattern} is used as with |expr-=~|: The matching is always done --- like 'magic' was set and 'cpoptions' is empty, no matter what @@ -330,13 +335,13 @@ function vim.fn.assert_inrange(lower, upper, actual, msg) end --- Use both to match the whole text. --- --- Example: >vim ---- assert_match('^f.*o$', 'foobar') +--- call assert_match('^f.*o$', 'foobar') --- <Will result in a string to be added to |v:errors|: --- test.vim line 12: Pattern '^f.*o$' does not match 'foobar' ~ --- ---- @param pattern any ---- @param actual any ---- @param msg? any +--- @param pattern string +--- @param actual string +--- @param msg? string --- @return 0|1 function vim.fn.assert_match(pattern, actual, msg) end @@ -344,7 +349,7 @@ function vim.fn.assert_match(pattern, actual, msg) end --- produces a beep or visual bell. --- Also see |assert_beeps()|. --- ---- @param cmd any +--- @param cmd string --- @return 0|1 function vim.fn.assert_nobeep(cmd) end @@ -362,16 +367,16 @@ function vim.fn.assert_notequal(expected, actual, msg) end --- |v:errors| when {pattern} matches {actual}. --- Also see |assert-return|. --- ---- @param pattern any ---- @param actual any ---- @param msg? any +--- @param pattern string +--- @param actual string +--- @param msg? string --- @return 0|1 function vim.fn.assert_notmatch(pattern, actual, msg) end --- Report a test failure directly, using String {msg}. --- Always returns one. --- ---- @param msg any +--- @param msg string --- @return 0|1 function vim.fn.assert_report(msg) end @@ -380,10 +385,11 @@ function vim.fn.assert_report(msg) end --- Also see |assert-return|. --- A value is |TRUE| when it is a non-zero number or |v:true|. --- When {actual} is not a number or |v:true| the assert fails. ---- When {msg} is given it precedes the default message. +--- When {msg} is given it is prefixed to the default message, +--- along with the location of the assert when run from a script. --- --- @param actual any ---- @param msg? any +--- @param msg? string --- @return 0|1 function vim.fn.assert_true(actual, msg) end @@ -397,7 +403,7 @@ function vim.fn.assert_true(actual, msg) end --- echo atan(-4.01) --- < -1.326405 --- ---- @param expr any +--- @param expr number --- @return number function vim.fn.atan(expr) end @@ -412,8 +418,8 @@ function vim.fn.atan(expr) end --- echo atan2(1, -1) --- < 2.356194 --- ---- @param expr1 any ---- @param expr2 any +--- @param expr1 number +--- @param expr2 number --- @return number function vim.fn.atan2(expr1, expr2) end @@ -439,9 +445,9 @@ function vim.fn.blob2list(blob) end --- something went wrong, or browsing is not possible. --- --- @param save any ---- @param title any ---- @param initdir any ---- @param default any +--- @param title string +--- @param initdir string +--- @param default string --- @return 0|1 function vim.fn.browse(save, title, initdir, default) end @@ -456,8 +462,8 @@ function vim.fn.browse(save, title, initdir, default) end --- When the "Cancel" button is hit, something went wrong, or --- browsing is not possible, an empty string is returned. --- ---- @param title any ---- @param initdir any +--- @param title string +--- @param initdir string --- @return 0|1 function vim.fn.browsedir(title, initdir) end @@ -729,7 +735,7 @@ function vim.fn.call(func, arglist, dict) end --- --- Returns 0.0 if {expr} is not a |Float| or a |Number|. --- ---- @param expr any +--- @param expr number --- @return number function vim.fn.ceil(expr) end @@ -742,8 +748,8 @@ function vim.fn.ceil(expr) end --- For a socket, there is only one stream, and {stream} should be --- omitted. --- ---- @param id any ---- @param stream? any +--- @param id integer +--- @param stream? string --- @return 0|1 function vim.fn.chanclose(id, stream) end @@ -775,8 +781,8 @@ function vim.fn.changenr() end --- was created with `"rpc":v:true` then the channel expects RPC --- messages, use |rpcnotify()| and |rpcrequest()| instead. --- ---- @param id any ---- @param data any +--- @param id number +--- @param data string|string[] --- @return 0|1 function vim.fn.chansend(id, data) end @@ -820,8 +826,9 @@ function vim.fn.charclass(string) end --- With the cursor on '세' in line 5 with text "여보세요": >vim --- echo charcol('.') " returns 3 --- echo col('.') " returns 7 +--- < --- ---- @param expr any +--- @param expr string|integer[] --- @param winid? integer --- @return integer function vim.fn.charcol(expr, winid) end @@ -861,8 +868,8 @@ function vim.fn.charcol(expr, winid) end --- --- @param string string --- @param idx integer ---- @param countcc? any ---- @param utf16? any +--- @param countcc? boolean +--- @param utf16? boolean --- @return integer function vim.fn.charidx(string, idx, countcc, utf16) end @@ -886,6 +893,7 @@ function vim.fn.charidx(string, idx, countcc, utf16) end --- " ... do some work --- call chdir(save_dir) --- endif +--- < --- --- @param dir string --- @return string @@ -907,37 +915,37 @@ function vim.fn.cindent(lnum) end --- If {win} is specified, use the window with this number or --- window ID instead of the current window. --- ---- @param win? any +--- @param win? integer function vim.fn.clearmatches(win) end --- The result is a Number, which is the byte index of the column ---- position given with {expr}. The accepted positions are: ---- . the cursor position ---- $ the end of the cursor line (the result is the ---- number of bytes in the cursor line plus one) ---- 'x position of mark x (if the mark is not set, 0 is ---- returned) ---- v In Visual mode: the start of the Visual area (the ---- cursor is the end). When not in Visual mode ---- returns the cursor position. Differs from |'<| in ---- that it's updated right away. +--- position given with {expr}. +--- For accepted positions see |getpos()|. +--- When {expr} is "$", it means the end of the cursor line, so +--- the result is the number of bytes in the cursor line plus one. --- Additionally {expr} can be [lnum, col]: a |List| with the line --- and column number. Most useful when the column is "$", to get --- the last column of a specific line. When "lnum" or "col" is --- out of range then col() returns zero. +--- --- With the optional {winid} argument the values are obtained for --- that window instead of the current window. +--- --- To get the line number use |line()|. To get both use --- |getpos()|. +--- --- For the screen column position use |virtcol()|. For the --- character position use |charcol()|. +--- --- Note that only marks in the current file can be used. +--- --- Examples: >vim --- echo col(".") " column of cursor --- echo col("$") " length of cursor line plus one --- echo col("'t") " column of mark t --- echo col("'" .. markname) " column of mark markname ---- <The first column is 1. Returns 0 if {expr} is invalid or when +--- < +--- The first column is 1. Returns 0 if {expr} is invalid or when --- the window with ID {winid} is not found. --- For an uppercase mark the column may actually be in another --- buffer. @@ -946,8 +954,9 @@ function vim.fn.clearmatches(win) end --- line. Also, when using a <Cmd> mapping the cursor isn't --- moved, this can be used to obtain the column in Insert mode: >vim --- imap <F2> <Cmd>echo col(".").."\n"<CR> +--- < --- ---- @param expr any +--- @param expr string|integer[] --- @param winid? integer --- @return integer function vim.fn.col(expr, winid) end @@ -981,8 +990,8 @@ function vim.fn.col(expr, winid) end --- <This isn't very useful, but it shows how it works. Note that --- an empty string is returned to avoid a zero being inserted. --- ---- @param startcol any ---- @param matches any +--- @param startcol integer +--- @param matches any[] function vim.fn.complete(startcol, matches) end --- Add {expr} to the list of matches. Only to be used by the @@ -1065,8 +1074,9 @@ function vim.fn.complete_check() end --- call complete_info(['mode']) --- " Get only 'mode' and 'pum_visible' --- call complete_info(['mode', 'pum_visible']) +--- < --- ---- @param what? any +--- @param what? any[] --- @return table function vim.fn.complete_info(what) end @@ -1121,10 +1131,10 @@ function vim.fn.complete_info(what) end --- don't fit, a vertical layout is used anyway. For some systems --- the horizontal layout is always used. --- ---- @param msg any ---- @param choices? any ---- @param default? any ---- @param type? any +--- @param msg string +--- @param choices? string +--- @param default? integer +--- @param type? string --- @return integer function vim.fn.confirm(msg, choices, default, type) end @@ -1150,7 +1160,7 @@ function vim.fn.copy(expr) end --- echo cos(-4.01) --- < -0.646043 --- ---- @param expr any +--- @param expr number --- @return number function vim.fn.cos(expr) end @@ -1164,7 +1174,7 @@ function vim.fn.cos(expr) end --- echo cosh(-0.5) --- < -1.127626 --- ---- @param expr any +--- @param expr number --- @return number function vim.fn.cosh(expr) end @@ -1180,10 +1190,10 @@ function vim.fn.cosh(expr) end --- occurrences of {expr} is returned. Zero is returned when --- {expr} is an empty string. --- ---- @param comp any +--- @param comp string|table|any[] --- @param expr any ---- @param ic? any ---- @param start? any +--- @param ic? boolean +--- @param start? integer --- @return integer function vim.fn.count(comp, expr, ic, start) end @@ -1191,7 +1201,7 @@ function vim.fn.count(comp, expr, ic, start) end --- from the top of the |context-stack| (see |context-dict|). --- If {index} is not given, it is assumed to be 0 (i.e.: top). --- ---- @param index? any +--- @param index? integer --- @return table function vim.fn.ctxget(index) end @@ -1207,7 +1217,7 @@ function vim.fn.ctxpop() end --- which |context-types| to include in the pushed context. --- Otherwise, all context types are included. --- ---- @param types? any +--- @param types? string[] --- @return any function vim.fn.ctxpush(types) end @@ -1216,8 +1226,8 @@ function vim.fn.ctxpush(types) end --- {context} is a Dictionary with context data (|context-dict|). --- If {index} is not given, it is assumed to be 0 (i.e.: top). --- ---- @param context any ---- @param index? any +--- @param context table +--- @param index? integer --- @return any function vim.fn.ctxset(context, index) end @@ -1228,7 +1238,7 @@ function vim.fn.ctxsize() end --- @param lnum integer --- @param col? integer ---- @param off? any +--- @param off? integer --- @return any function vim.fn.cursor(lnum, col, off) end @@ -1263,7 +1273,7 @@ function vim.fn.cursor(lnum, col, off) end --- position within a <Tab> or after the last character. --- Returns 0 when the position could be set, -1 otherwise. --- ---- @param list any +--- @param list integer[] --- @return any function vim.fn.cursor(list) end @@ -1275,7 +1285,7 @@ function vim.fn.cursor(list) end --- Returns |TRUE| if successfully interrupted the program. --- Otherwise returns |FALSE|. --- ---- @param pid any +--- @param pid integer --- @return any function vim.fn.debugbreak(pid) end @@ -1299,7 +1309,7 @@ function vim.fn.debugbreak(pid) end --- Also see |copy()|. --- --- @param expr any ---- @param noref? any +--- @param noref? boolean --- @return any function vim.fn.deepcopy(expr, noref) end @@ -1339,9 +1349,9 @@ function vim.fn.delete(fname, flags) end --- when using |line()| this refers to the current buffer. Use "$" --- to refer to the last line in buffer {buf}. --- ---- @param buf any ---- @param first any ---- @param last? any +--- @param buf integer|string +--- @param first integer|string +--- @param last? integer|string --- @return any function vim.fn.deletebufline(buf, first, last) end @@ -1384,9 +1394,9 @@ function vim.fn.deletebufline(buf, first, last) end --- This function can be used by plugins to implement options with --- validation and parsing logic. --- ---- @param dict any ---- @param pattern any ---- @param callback any +--- @param dict table +--- @param pattern string +--- @param callback function --- @return any function vim.fn.dictwatcheradd(dict, pattern, callback) end @@ -1395,8 +1405,8 @@ function vim.fn.dictwatcheradd(dict, pattern, callback) end --- order for the watcher to be successfully deleted. --- --- @param dict any ---- @param pattern any ---- @param callback any +--- @param pattern string +--- @param callback function --- @return any function vim.fn.dictwatcherdel(dict, pattern, callback) end @@ -1457,7 +1467,7 @@ function vim.fn.diff_hlID(lnum, col) end --- echo digraph_get('aa') " Returns 'ã‚' --- < --- ---- @param chars any +--- @param chars string --- @return any function vim.fn.digraph_get(chars) end @@ -1475,7 +1485,7 @@ function vim.fn.digraph_get(chars) end --- echo digraph_getlist(1) --- < --- ---- @param listall? any +--- @param listall? boolean --- @return any function vim.fn.digraph_getlist(listall) end @@ -1495,12 +1505,9 @@ function vim.fn.digraph_getlist(listall) end --- Example: >vim --- call digraph_set(' ', 'ã‚') --- < ---- Can be used as a |method|: >vim ---- GetString()->digraph_set('ã‚') ---- < --- ---- @param chars any ---- @param digraph any +--- @param chars string +--- @param digraph string --- @return any function vim.fn.digraph_set(chars, digraph) end @@ -1518,11 +1525,7 @@ function vim.fn.digraph_set(chars, digraph) end --- <Except that the function returns after the first error, --- following digraphs will not be added. --- ---- Can be used as a |method|: >vim ---- GetList()->digraph_setlist() ---- < ---- ---- @param digraphlist any +--- @param digraphlist table<integer,string[]> --- @return any function vim.fn.digraph_setlist(digraphlist) end @@ -1557,7 +1560,7 @@ function vim.fn.environ() end --- <Also see |shellescape()| and |fnameescape()|. --- --- @param string string ---- @param chars any +--- @param chars string --- @return any function vim.fn.escape(string, chars) end @@ -1582,25 +1585,32 @@ function vim.fn.eventhandler() end --- This function checks if an executable with the name {expr} --- exists. {expr} must be the name of the program without any --- arguments. +--- --- executable() uses the value of $PATH and/or the normal ---- searchpath for programs. *PATHEXT* +--- searchpath for programs. +--- *PATHEXT* --- On MS-Windows the ".exe", ".bat", etc. can optionally be --- included. Then the extensions in $PATHEXT are tried. Thus if --- "foo.exe" does not exist, "foo.exe.bat" can be found. If ---- $PATHEXT is not set then ".exe;.com;.bat;.cmd" is used. A dot +--- $PATHEXT is not set then ".com;.exe;.bat;.cmd" is used. A dot --- by itself can be used in $PATHEXT to try using the name --- without an extension. When 'shell' looks like a Unix shell, --- then the name is also tried without adding an extension. --- On MS-Windows it only checks if the file exists and is not a --- directory, not if it's really executable. ---- On Windows an executable in the same directory as Vim is ---- always found (it is added to $PATH at |startup|). +--- On MS-Windows an executable in the same directory as the Vim +--- executable is always found (it's added to $PATH at |startup|). +--- *NoDefaultCurrentDirectoryInExePath* +--- On MS-Windows an executable in Vim's current working directory +--- is also normally found, but this can be disabled by setting +--- the $NoDefaultCurrentDirectoryInExePath environment variable. +--- --- The result is a Number: --- 1 exists --- 0 does not exist --- |exepath()| can be used to get the full path of an executable. --- ---- @param expr any +--- @param expr string --- @return 0|1 function vim.fn.executable(expr) end @@ -1641,8 +1651,8 @@ function vim.fn.execute(command, silent) end --- Returns empty string otherwise. --- If {expr} starts with "./" the |current-directory| is used. --- ---- @param expr any ---- @return any +--- @param expr string +--- @return string function vim.fn.exepath(expr) end --- The result is a Number, which is |TRUE| if {expr} is @@ -1733,7 +1743,7 @@ function vim.fn.exepath(expr) end --- <This doesn't check for existence of the "bufcount" variable, --- but gets the value of "bufcount", and checks if that exists. --- ---- @param expr any +--- @param expr string --- @return 0|1 function vim.fn.exists(expr) end @@ -1747,7 +1757,7 @@ function vim.fn.exists(expr) end --- echo exp(-1) --- < 0.367879 --- ---- @param expr any +--- @param expr number --- @return any function vim.fn.exp(expr) end @@ -1916,9 +1926,9 @@ function vim.fn.expandcmd(string, options) end --- fails. --- Returns {expr1}. Returns 0 on error. --- ---- @param expr1 any ---- @param expr2 any ---- @param expr3? any +--- @param expr1 table +--- @param expr2 table +--- @param expr3? table --- @return any function vim.fn.extend(expr1, expr2, expr3) end @@ -1926,9 +1936,9 @@ function vim.fn.extend(expr1, expr2, expr3) end --- List or Dictionary is created and returned. {expr1} remains --- unchanged. --- ---- @param expr1 any ---- @param expr2 any ---- @param expr3? any +--- @param expr1 table +--- @param expr2 table +--- @param expr3? table --- @return any function vim.fn.extendnew(expr1, expr2, expr3) end @@ -1989,6 +1999,19 @@ function vim.fn.feedkeys(string, mode) end --- @return any function vim.fn.file_readable(file) end +--- Copy the file pointed to by the name {from} to {to}. The +--- result is a Number, which is |TRUE| if the file was copied +--- successfully, and |FALSE| when it failed. +--- If a file with name {to} already exists, it will fail. +--- Note that it does not handle directories (yet). +--- +--- This function is not available in the |sandbox|. +--- +--- @param from string +--- @param to string +--- @return 0|1 +function vim.fn.filecopy(from, to) end + --- The result is a Number, which is |TRUE| when a file with the --- name {file} exists, and can be read. If {file} doesn't exist, --- or is a directory, the result is |FALSE|. {file} is any @@ -2070,8 +2093,8 @@ function vim.fn.filewritable(file) end --- When {expr2} is a Funcref errors inside a function are ignored, --- unless it was defined with the "abort" flag. --- ---- @param expr1 any ---- @param expr2 any +--- @param expr1 string|table +--- @param expr2 string|function --- @return any function vim.fn.filter(expr1, expr2) end @@ -2094,7 +2117,7 @@ function vim.fn.filter(expr1, expr2) end --- --- @param name string --- @param path? string ---- @param count? any +--- @param count? integer --- @return any function vim.fn.finddir(name, path, count) end @@ -2129,15 +2152,15 @@ function vim.fn.findfile(name, path, count) end --- echo flatten([1, [2, [3, 4]], 5], 1) --- < [1, 2, [3, 4], 5] --- ---- @param list any ---- @param maxdepth? any +--- @param list any[] +--- @param maxdepth? integer --- @return any[]|0 function vim.fn.flatten(list, maxdepth) end --- Like |flatten()| but first make a copy of {list}. --- ---- @param list any ---- @param maxdepth? any +--- @param list any[] +--- @param maxdepth? integer --- @return any[]|0 function vim.fn.flattennew(list, maxdepth) end @@ -2162,7 +2185,7 @@ function vim.fn.flattennew(list, maxdepth) end --- echo float2nr(1.0e-100) --- < 0 --- ---- @param expr any +--- @param expr number --- @return any function vim.fn.float2nr(expr) end @@ -2178,7 +2201,7 @@ function vim.fn.float2nr(expr) end --- echo floor(4.0) --- < 4.0 --- ---- @param expr any +--- @param expr number --- @return any function vim.fn.floor(expr) end @@ -2197,8 +2220,8 @@ function vim.fn.floor(expr) end --- echo fmod(-12.33, 1.22) --- < -0.13 --- ---- @param expr1 any ---- @param expr2 any +--- @param expr1 number +--- @param expr2 number --- @return any function vim.fn.fmod(expr1, expr2) end @@ -2343,8 +2366,8 @@ function vim.fn.foldtextresult(lnum) end --- When {expr2} is a Funcref errors inside a function are ignored, --- unless it was defined with the "abort" flag. --- ---- @param expr1 any ---- @param expr2 any +--- @param expr1 string|table +--- @param expr2 string|function --- @return any function vim.fn.foreach(expr1, expr2) end @@ -2486,7 +2509,7 @@ vim.fn['function'] = function(name, arglist, dict) end --- it's safe to perform. This is when waiting for the user to --- type a character. --- ---- @param atexit? any +--- @param atexit? boolean --- @return any function vim.fn.garbagecollect(atexit) end @@ -2523,12 +2546,25 @@ function vim.fn.get(blob, idx, default) end --- @return any function vim.fn.get(dict, key, default) end ---- Get item {what} from Funcref {func}. Possible values for +--- Get item {what} from |Funcref| {func}. Possible values for --- {what} are: ---- "name" The function name ---- "func" The function ---- "dict" The dictionary ---- "args" The list with arguments +--- "name" The function name +--- "func" The function +--- "dict" The dictionary +--- "args" The list with arguments +--- "arity" A dictionary with information about the number of +--- arguments accepted by the function (minus the +--- {arglist}) with the following fields: +--- required the number of positional arguments +--- optional the number of optional arguments, +--- in addition to the required ones +--- varargs |TRUE| if the function accepts a +--- variable number of arguments |...| +--- +--- Note: There is no error, if the {arglist} of +--- the Funcref contains more arguments than the +--- Funcref expects, it's not validated. +--- --- Returns zero on error. --- --- @param func function @@ -2634,8 +2670,9 @@ function vim.fn.getbufinfo(dict) end --- --- Example: >vim --- let lines = getbufline(bufnr("myfile"), 1, "$") +--- < --- ---- @param buf any +--- @param buf integer|string --- @param lnum integer --- @param end_? integer --- @return any @@ -2669,7 +2706,7 @@ function vim.fn.getbufoneline(buf, lnum) end --- let bufmodified = getbufvar(1, "&mod") --- echo "todo myvar = " .. getbufvar("todo", "myvar") --- ---- @param buf any +--- @param buf integer|string --- @param varname string --- @param def? any --- @return any @@ -2766,8 +2803,9 @@ function vim.fn.getchangelist(buf) end --- endfunction --- < --- +--- @param expr? 0|1 --- @return integer -function vim.fn.getchar() end +function vim.fn.getchar(expr) end --- The result is a Number which is the state of the modifiers for --- the last obtained character with getchar() or in another way. @@ -2800,7 +2838,7 @@ function vim.fn.getcharmod() end --- getpos('.') returns [0, 5, 7, 0] --- < --- ---- @param expr any +--- @param expr string --- @return integer[] function vim.fn.getcharpos(expr) end @@ -2823,7 +2861,7 @@ function vim.fn.getcharpos(expr) end --- nnoremap <expr> , getcharsearch().forward ? ',' : ';' --- <Also see |setcharsearch()|. --- ---- @return table[] +--- @return table function vim.fn.getcharsearch() end --- Get a single character from the user or input stream as a @@ -2837,27 +2875,28 @@ function vim.fn.getcharsearch() end --- Otherwise this works like |getchar()|, except that a number --- result is converted to a string. --- +--- @param expr? 0|1 --- @return string -function vim.fn.getcharstr() end +function vim.fn.getcharstr(expr) end --- Return the type of the current command-line completion. --- Only works when the command line is being edited, thus --- requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. --- See |:command-completion| for the return string. ---- Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()| and ---- |setcmdline()|. +--- Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, +--- |getcmdprompt()| and |setcmdline()|. --- Returns an empty string when completion is not defined. --- --- @return string function vim.fn.getcmdcompltype() end ---- Return the current command-line. Only works when the command ---- line is being edited, thus requires use of |c_CTRL-\_e| or ---- |c_CTRL-R_=|. +--- Return the current command-line input. Only works when the +--- command line is being edited, thus requires use of +--- |c_CTRL-\_e| or |c_CTRL-R_=|. --- Example: >vim --- cmap <F7> <C-\>eescape(getcmdline(), ' \')<CR> ---- <Also see |getcmdtype()|, |getcmdpos()|, |setcmdpos()| and ---- |setcmdline()|. +--- <Also see |getcmdtype()|, |getcmdpos()|, |setcmdpos()|, +--- |getcmdprompt()| and |setcmdline()|. --- Returns an empty string when entering a password or using --- |inputsecret()|. --- @@ -2869,12 +2908,22 @@ function vim.fn.getcmdline() end --- Only works when editing the command line, thus requires use of --- |c_CTRL-\_e| or |c_CTRL-R_=| or an expression mapping. --- Returns 0 otherwise. ---- Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()| and ---- |setcmdline()|. +--- Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, +--- |getcmdprompt()| and |setcmdline()|. --- --- @return integer function vim.fn.getcmdpos() end +--- Return the current command-line prompt when using functions +--- like |input()| or |confirm()|. +--- Only works when the command line is being edited, thus +--- requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. +--- Also see |getcmdtype()|, |getcmdline()|, |getcmdpos()|, +--- |setcmdpos()| and |setcmdline()|. +--- +--- @return string +function vim.fn.getcmdprompt() end + --- Return the screen position of the cursor in the command line --- as a byte count. The first column is 1. --- Instead of |getcmdpos()|, it adds the prompt position. @@ -2927,6 +2976,7 @@ function vim.fn.getcmdwintype() end --- customlist,{func} custom completion, defined via {func} --- diff_buffer |:diffget| and |:diffput| completion --- dir directory names +--- dir_in_path directory names in |'cdpath'| --- environment environment variable names --- event autocommand events --- expression Vim expression @@ -2979,9 +3029,9 @@ function vim.fn.getcmdwintype() end --- If there are no matches, an empty list is returned. An --- invalid value for {type} produces an error. --- ---- @param pat any ---- @param type any ---- @param filtered? any +--- @param pat string +--- @param type string +--- @param filtered? boolean --- @return string[] function vim.fn.getcompletion(pat, type, filtered) end @@ -3227,7 +3277,7 @@ function vim.fn.getline(lnum, end_) end --- < --- --- @param nr integer ---- @param what? any +--- @param what? table --- @return any function vim.fn.getloclist(nr, what) end @@ -3249,8 +3299,8 @@ function vim.fn.getloclist(nr, what) end --- Refer to |getpos()| for getting information about a specific --- mark. --- ---- @param buf? any ---- @return any +--- @param buf? integer? +--- @return vim.fn.getmarklist.ret.item[] function vim.fn.getmarklist(buf) end --- Returns a |List| with all matches previously defined for the @@ -3284,7 +3334,7 @@ function vim.fn.getmarklist(buf) end --- unlet m --- < --- ---- @param win? any +--- @param win? integer --- @return any function vim.fn.getmatches(win) end @@ -3327,9 +3377,34 @@ function vim.fn.getmousepos() end --- @return integer function vim.fn.getpid() end ---- Get the position for String {expr}. For possible values of ---- {expr} see |line()|. For getting the cursor position see ---- |getcurpos()|. +--- Get the position for String {expr}. +--- The accepted values for {expr} are: +--- . The cursor position. +--- $ The last line in the current buffer. +--- 'x Position of mark x (if the mark is not set, 0 is +--- returned for all values). +--- w0 First line visible in current window (one if the +--- display isn't updated, e.g. in silent Ex mode). +--- w$ Last line visible in current window (this is one +--- less than "w0" if no lines are visible). +--- v When not in Visual mode, returns the cursor +--- position. In Visual mode, returns the other end +--- of the Visual area. A good way to think about +--- this is that in Visual mode "v" and "." complement +--- each other. While "." refers to the cursor +--- position, "v" refers to where |v_o| would move the +--- cursor. As a result, you can use "v" and "." +--- together to work on all of a selection in +--- characterwise Visual mode. If the cursor is at +--- the end of a characterwise Visual area, "v" refers +--- to the start of the same Visual area. And if the +--- cursor is at the start of a characterwise Visual +--- area, "v" refers to the end of the same Visual +--- area. "v" differs from |'<| and |'>| in that it's +--- updated right away. +--- Note that a mark in another file can be used. The line number +--- then applies to another buffer. +--- --- The result is a |List| with four numbers: --- [bufnum, lnum, col, off] --- "bufnum" is zero, unless a mark like '0 or 'A is used, then it @@ -3340,20 +3415,25 @@ function vim.fn.getpid() end --- it is the offset in screen columns from the start of the --- character. E.g., a position within a <Tab> or after the last --- character. ---- Note that for '< and '> Visual mode matters: when it is "V" ---- (visual line mode) the column of '< is zero and the column of ---- '> is a large number equal to |v:maxcol|. +--- +--- For getting the cursor position see |getcurpos()|. --- The column number in the returned List is the byte position --- within the line. To get the character position in the line, --- use |getcharpos()|. +--- +--- Note that for '< and '> Visual mode matters: when it is "V" +--- (visual line mode) the column of '< is zero and the column of +--- '> is a large number equal to |v:maxcol|. --- A very large column number equal to |v:maxcol| can be returned, --- in which case it means "after the end of the line". --- If {expr} is invalid, returns a list with all zeros. +--- --- This can be used to save and restore the position of a mark: >vim --- let save_a_mark = getpos("'a") --- " ... --- call setpos("'a", save_a_mark) ---- <Also see |getcharpos()|, |getcurpos()| and |setpos()|. +--- < +--- Also see |getcharpos()|, |getcurpos()| and |setpos()|. --- --- @param expr string --- @return integer[] @@ -3462,7 +3542,7 @@ function vim.fn.getpos(expr) end --- echo getqflist({'lines' : ["F1:10:L10"]}) --- < --- ---- @param what? any +--- @param what? table --- @return any function vim.fn.getqflist(what) end @@ -3536,14 +3616,14 @@ function vim.fn.getreginfo(regname) end --- The optional argument {opts} is a Dict and supports the --- following items: --- ---- type Specify the region's selection type ---- (default: "v"): ---- "v" for |charwise| mode ---- "V" for |linewise| mode ---- "<CTRL-V>" for |blockwise-visual| mode +--- type Specify the region's selection type. +--- See |getregtype()| for possible values, +--- except that the width can be omitted +--- and an empty string cannot be used. +--- (default: "v") --- --- exclusive If |TRUE|, use exclusive selection ---- for the end position +--- for the end position. --- (default: follow 'selection') --- --- You can get the last selection type by |visualmode()|. @@ -3569,8 +3649,8 @@ function vim.fn.getreginfo(regname) end --- difference if the buffer is displayed in a window with --- different 'virtualedit' or 'list' values. --- ---- Examples: > ---- :xnoremap <CR> +--- Examples: >vim +--- xnoremap <CR> --- \ <Cmd>echom getregion( --- \ getpos('v'), getpos('.'), #{ type: mode() })<CR> --- < @@ -3777,7 +3857,7 @@ function vim.fn.gettagstack(winnr) end --- xgettext does not understand escaping in single quoted --- strings. --- ---- @param text any +--- @param text string --- @return any function vim.fn.gettext(text) end @@ -3904,10 +3984,10 @@ function vim.fn.getwinvar(winnr, varname, def) end --- See |expand()| for expanding special Vim variables. See --- |system()| for getting the raw output of an external command. --- ---- @param expr any +--- @param expr string --- @param nosuf? boolean ---- @param list? any ---- @param alllinks? any +--- @param list? boolean +--- @param alllinks? boolean --- @return any function vim.fn.glob(expr, nosuf, list, alllinks) end @@ -3965,10 +4045,10 @@ function vim.fn.glob2regpat(string) end --- supported, thus using 'path' will not always work properly. --- --- @param path string ---- @param expr any +--- @param expr string --- @param nosuf? boolean ---- @param list? any ---- @param allinks? any +--- @param list? boolean +--- @param allinks? boolean --- @return any function vim.fn.globpath(path, expr, nosuf, list, allinks) end @@ -4039,7 +4119,7 @@ function vim.fn.globpath(path, expr, nosuf, list, allinks) end --- endif --- < --- ---- @param feature any +--- @param feature string --- @return 0|1 function vim.fn.has(feature) end @@ -4047,8 +4127,8 @@ function vim.fn.has(feature) end --- has an entry with key {key}. FALSE otherwise. The {key} --- argument is a string. --- ---- @param dict any ---- @param key any +--- @param dict table +--- @param key string --- @return 0|1 function vim.fn.has_key(dict, key) end @@ -4105,7 +4185,7 @@ function vim.fn.haslocaldir(winnr, tabnr) end --- --- @param what any --- @param mode? string ---- @param abbr? any +--- @param abbr? boolean --- @return 0|1 function vim.fn.hasmapto(what, mode, abbr) end @@ -4143,7 +4223,7 @@ function vim.fn.highlight_exists(name) end --- let date=input("Enter date: ") --- <This function is not available in the |sandbox|. --- ---- @param history any +--- @param history string --- @param item any --- @return 0|1 function vim.fn.histadd(history, item) end @@ -4180,7 +4260,7 @@ function vim.fn.histadd(history, item) end --- let \@/ = histget("search", -1) --- < --- ---- @param history any +--- @param history string --- @param item? any --- @return 0|1 function vim.fn.histdel(history, item) end @@ -4200,8 +4280,8 @@ function vim.fn.histdel(history, item) end --- command -nargs=1 H execute histget("cmd", 0+<args>) --- < --- ---- @param history any ---- @param index? any +--- @param history string +--- @param index? integer|string --- @return string function vim.fn.histget(history, index) end @@ -4211,8 +4291,9 @@ function vim.fn.histget(history, index) end --- --- Example: >vim --- let inp_index = histnr("expr") +--- < --- ---- @param history any +--- @param history string --- @return integer function vim.fn.histnr(history) end @@ -4258,8 +4339,8 @@ function vim.fn.hostname() end --- cannot use UCS-2 in a string anyway, because of the NUL bytes. --- --- @param string string ---- @param from any ---- @param to any +--- @param from string +--- @param to string --- @return any function vim.fn.iconv(string, from, to) end @@ -4270,7 +4351,7 @@ function vim.fn.iconv(string, from, to) end --- Note that `v:_null_string`, `v:_null_list`, `v:_null_dict` and --- `v:_null_blob` have the same `id()` with different types --- because they are internally represented as NULL pointers. ---- `id()` returns a hexadecimal representanion of the pointers to +--- `id()` returns a hexadecimal representation of the pointers to --- the containers (i.e. like `0x994a40`), same as `printf("%p", --- {expr})`, but it is advised against counting on the exact --- format of the return value. @@ -4318,11 +4399,12 @@ function vim.fn.indent(lnum) end --- if index(numbers, 123) >= 0 --- " ... --- endif +--- < --- --- @param object any --- @param expr any ---- @param start? any ---- @param ic? any +--- @param start? integer +--- @param ic? boolean --- @return any function vim.fn.index(object, expr, start, ic) end @@ -4362,6 +4444,7 @@ function vim.fn.index(object, expr, start, ic) end --- echo indexof(l, "v:val.n == 20") --- echo indexof(l, {i, v -> v.n == 30}) --- echo indexof(l, "v:val.n == 20", #{startidx: 1}) +--- < --- --- @param object any --- @param expr any @@ -4370,9 +4453,9 @@ function vim.fn.index(object, expr, start, ic) end function vim.fn.indexof(object, expr, opts) end --- ---- @param prompt any ---- @param text? any ---- @param completion? any +--- @param prompt string +--- @param text? string +--- @param completion? string --- @return any function vim.fn.input(prompt, text, completion) end @@ -4484,6 +4567,7 @@ function vim.fn.input(prompt, text, completion) end --- let g:Foo = input("enter search pattern: ") --- call inputrestore() --- endfunction +--- < --- --- @param opts table --- @return any @@ -4512,7 +4596,7 @@ function vim.fn.inputdialog(...) end --- let color = inputlist(['Select color:', '1. red', --- \ '2. green', '3. blue']) --- ---- @param textlist any +--- @param textlist string[] --- @return any function vim.fn.inputlist(textlist) end @@ -4544,8 +4628,8 @@ function vim.fn.inputsave() end --- typed on the command-line in response to the issued prompt. --- NOTE: Command-line completion is not supported. --- ---- @param prompt any ---- @param text? any +--- @param prompt string +--- @param text? string --- @return any function vim.fn.inputsecret(prompt, text) end @@ -4592,16 +4676,34 @@ function vim.fn.interrupt() end --- let bits = invert(bits) --- < --- ---- @param expr any +--- @param expr number --- @return any function vim.fn.invert(expr) end +--- The result is a Number, which is |TRUE| when {path} is an +--- absolute path. +--- On Unix, a path is considered absolute when it starts with '/'. +--- On MS-Windows, it is considered absolute when it starts with an +--- optional drive prefix and is followed by a '\' or '/'. UNC paths +--- are always absolute. +--- Example: >vim +--- echo isabsolutepath('/usr/share/') " 1 +--- echo isabsolutepath('./foobar') " 0 +--- echo isabsolutepath('C:\Windows') " 1 +--- echo isabsolutepath('foobar') " 0 +--- echo isabsolutepath('\\remote\file') " 1 +--- < +--- +--- @param path string +--- @return 0|1 +function vim.fn.isabsolutepath(path) end + --- The result is a Number, which is |TRUE| when a directory --- with the name {directory} exists. If {directory} doesn't --- exist, or isn't a directory, the result is |FALSE|. {directory} --- is any expression, which is used as a String. --- ---- @param directory any +--- @param directory string --- @return 0|1 function vim.fn.isdirectory(directory) end @@ -4612,7 +4714,7 @@ function vim.fn.isdirectory(directory) end --- echo isinf(-1.0 / 0.0) --- < -1 --- ---- @param expr any +--- @param expr number --- @return 1|0|-1 function vim.fn.isinf(expr) end @@ -4637,7 +4739,7 @@ function vim.fn.islocked(expr) end --- echo isnan(0.0 / 0.0) --- < 1 --- ---- @param expr any +--- @param expr number --- @return 0|1 function vim.fn.isnan(expr) end @@ -4649,6 +4751,10 @@ function vim.fn.isnan(expr) end --- for [key, value] in items(mydict) --- echo key .. ': ' .. value --- endfor +--- < +--- A List or a String argument is also supported. In these +--- cases, items() returns a List with the index and the value at +--- the index. --- --- @param dict any --- @return any @@ -4663,7 +4769,7 @@ function vim.fn.jobclose(...) end --- Return the PID (process id) of |job-id| {job}. --- ---- @param job any +--- @param job integer --- @return integer function vim.fn.jobpid(job) end @@ -4671,7 +4777,7 @@ function vim.fn.jobpid(job) end --- columns and {height} rows. --- Fails if the job was not started with `"pty":v:true`. --- ---- @param job any +--- @param job integer --- @param width integer --- @param height integer --- @return any @@ -4769,7 +4875,7 @@ function vim.fn.jobsend(...) end --- - -1 if {cmd}[0] is not executable. --- See also |job-control|, |channel|, |msgpack-rpc|. --- ---- @param cmd any +--- @param cmd string|string[] --- @param opts? table --- @return any function vim.fn.jobstart(cmd, opts) end @@ -4783,7 +4889,7 @@ function vim.fn.jobstart(cmd, opts) end --- Returns 1 for valid job id, 0 for invalid id, including jobs have --- exited or stopped. --- ---- @param id any +--- @param id integer --- @return any function vim.fn.jobstop(id) end @@ -4807,7 +4913,7 @@ function vim.fn.jobstop(id) end --- -2 if the job was interrupted (by |CTRL-C|) --- -3 if the job-id is invalid --- ---- @param jobs any +--- @param jobs integer[] --- @param timeout? integer --- @return any function vim.fn.jobwait(jobs, timeout) end @@ -4822,8 +4928,8 @@ function vim.fn.jobwait(jobs, timeout) end --- converted into a string like with |string()|. --- The opposite function is |split()|. --- ---- @param list any ---- @param sep? any +--- @param list any[] +--- @param sep? string --- @return any function vim.fn.join(list, sep) end @@ -4863,7 +4969,7 @@ function vim.fn.json_encode(expr) end --- Return a |List| with all the keys of {dict}. The |List| is in --- arbitrary order. Also see |items()| and |values()|. --- ---- @param dict any +--- @param dict table --- @return any function vim.fn.keys(dict) end @@ -4958,28 +5064,16 @@ function vim.fn.libcall(libname, funcname, argument) end --- @return any function vim.fn.libcallnr(libname, funcname, argument) end ---- The result is a Number, which is the line number of the file ---- position given with {expr}. The {expr} argument is a string. ---- The accepted positions are: ---- . the cursor position ---- $ the last line in the current buffer ---- 'x position of mark x (if the mark is not set, 0 is ---- returned) ---- w0 first line visible in current window (one if the ---- display isn't updated, e.g. in silent Ex mode) ---- w$ last line visible in current window (this is one ---- less than "w0" if no lines are visible) ---- v In Visual mode: the start of the Visual area (the ---- cursor is the end). When not in Visual mode ---- returns the cursor position. Differs from |'<| in ---- that it's updated right away. ---- Note that a mark in another file can be used. The line number ---- then applies to another buffer. +--- See |getpos()| for accepted positions. +--- --- To get the column number use |col()|. To get both use --- |getpos()|. +--- --- With the optional {winid} argument the values are obtained for --- that window instead of the current window. +--- --- Returns 0 for invalid values of {expr} and {winid}. +--- --- Examples: >vim --- echo line(".") " line number of the cursor --- echo line(".", winid) " idem, in window "winid" @@ -4989,7 +5083,7 @@ function vim.fn.libcallnr(libname, funcname, argument) end --- To jump to the last known position when opening a file see --- |last-position-jump|. --- ---- @param expr any +--- @param expr string|integer[] --- @param winid? integer --- @return integer function vim.fn.line(expr, winid) end @@ -5029,7 +5123,7 @@ function vim.fn.lispindent(lnum) end --- --- |blob2list()| does the opposite. --- ---- @param list any +--- @param list any[] --- @return any function vim.fn.list2blob(list) end @@ -5048,8 +5142,8 @@ function vim.fn.list2blob(list) end --- < --- Returns an empty string on error. --- ---- @param list any ---- @param utf8? any +--- @param list any[] +--- @param utf8? boolean --- @return any function vim.fn.list2str(list, utf8) end @@ -5069,7 +5163,7 @@ function vim.fn.localtime() end --- echo log(exp(5)) --- < 5.0 --- ---- @param expr any +--- @param expr number --- @return any function vim.fn.log(expr) end @@ -5082,7 +5176,7 @@ function vim.fn.log(expr) end --- echo log10(0.01) --- < -2.0 --- ---- @param expr any +--- @param expr number --- @return any function vim.fn.log10(expr) end @@ -5139,8 +5233,8 @@ function vim.fn.log10(expr) end --- When {expr2} is a Funcref errors inside a function are ignored, --- unless it was defined with the "abort" flag. --- ---- @param expr1 any ---- @param expr2 any +--- @param expr1 string|table|any[] +--- @param expr2 string|function --- @return any function vim.fn.map(expr1, expr2) end @@ -5182,6 +5276,7 @@ function vim.fn.map(expr1, expr2) end --- "lhsrawalt" The {lhs} of the mapping as raw bytes, alternate --- form, only present when it differs from "lhsraw" --- "rhs" The {rhs} of the mapping as typed. +--- "callback" Lua function, if RHS was defined as such. --- "silent" 1 for a |:map-silent| mapping, else 0. --- "noremap" 1 if the {rhs} of the mapping is not remappable. --- "script" 1 if mapping was defined with <script>. @@ -5214,6 +5309,7 @@ function vim.fn.map(expr1, expr2) end --- This function can be used to map a key even when it's already --- mapped, and have it do the original mapping too. Sketch: >vim --- exe 'nnoremap <Tab> ==' .. maparg('<Tab>', 'n') +--- < --- --- @param name string --- @param mode? string @@ -5263,7 +5359,7 @@ function vim.fn.maparg(name, mode, abbr, dict) end --- --- @param name string --- @param mode? string ---- @param abbr? any +--- @param abbr? boolean --- @return any function vim.fn.mapcheck(name, mode, abbr) end @@ -5296,9 +5392,11 @@ function vim.fn.mapcheck(name, mode, abbr) end --- \ {_, m -> m.lhs == 'xyzzy'})[0].mode_bits --- ounmap xyzzy --- echo printf("Operator-pending mode bit: 0x%x", op_bit) +--- < --- ---- @return any -function vim.fn.maplist() end +--- @param abbr? 0|1 +--- @return table[] +function vim.fn.maplist(abbr) end --- Like |map()| but instead of replacing items in {expr1} a new --- List or Dictionary is created and returned. {expr1} remains @@ -5311,8 +5409,8 @@ function vim.fn.maplist() end function vim.fn.mapnew(expr1, expr2) end --- @param mode string ---- @param abbr? any ---- @param dict? any +--- @param abbr? boolean +--- @param dict? boolean --- @return any function vim.fn.mapset(mode, abbr, dict) end @@ -5350,8 +5448,9 @@ function vim.fn.mapset(mode, abbr, dict) end --- for d in save_maps --- call mapset(d) --- endfor +--- < --- ---- @param dict any +--- @param dict boolean --- @return any function vim.fn.mapset(dict) end @@ -5417,10 +5516,10 @@ function vim.fn.mapset(dict) end --- zero matches at the start instead of a number of matches --- further down in the text. --- ---- @param expr any ---- @param pat any ---- @param start? any ---- @param count? any +--- @param expr string|any[] +--- @param pat string +--- @param start? integer +--- @param count? integer --- @return any function vim.fn.match(expr, pat, start, count) end @@ -5481,20 +5580,20 @@ function vim.fn.match(expr, pat, start, count) end --- available from |getmatches()|. All matches can be deleted in --- one operation by |clearmatches()|. --- ---- @param group any ---- @param pattern any ---- @param priority? any ---- @param id? any ---- @param dict? any +--- @param group integer|string +--- @param pattern string +--- @param priority? integer +--- @param id? integer +--- @param dict? string --- @return any function vim.fn.matchadd(group, pattern, priority, id, dict) end --- Same as |matchadd()|, but requires a list of positions {pos} --- instead of a pattern. This command is faster than |matchadd()| ---- because it does not require to handle regular expressions and ---- sets buffer line boundaries to redraw screen. It is supposed ---- to be used when fast match additions and deletions are ---- required, for example to highlight matching parentheses. +--- because it does not handle regular expressions and it sets +--- buffer line boundaries to redraw screen. It is supposed to be +--- used when fast match additions and deletions are required, for +--- example to highlight matching parentheses. --- *E5030* *E5031* --- {pos} is a list of positions. Each position can be one of --- these: @@ -5525,11 +5624,11 @@ function vim.fn.matchadd(group, pattern, priority, id, dict) end --- <Matches added by |matchaddpos()| are returned by --- |getmatches()|. --- ---- @param group any ---- @param pos any ---- @param priority? any ---- @param id? any ---- @param dict? any +--- @param group integer|string +--- @param pos any[] +--- @param priority? integer +--- @param id? integer +--- @param dict? string --- @return any function vim.fn.matchaddpos(group, pos, priority, id, dict) end @@ -5575,19 +5674,19 @@ function vim.fn.matcharg(nr) end --- --- Examples: >vim --- " Assuming line 3 in buffer 5 contains "a" ---- :echo matchbufline(5, '\<\k\+\>', 3, 3) ---- [{'lnum': 3, 'byteidx': 0, 'text': 'a'}] +--- echo matchbufline(5, '\<\k\+\>', 3, 3) +--- < `[{'lnum': 3, 'byteidx': 0, 'text': 'a'}]` >vim --- " Assuming line 4 in buffer 10 contains "tik tok" ---- :echo matchbufline(10, '\<\k\+\>', 1, 4) ---- [{'lnum': 4, 'byteidx': 0, 'text': 'tik'}, {'lnum': 4, 'byteidx': 4, 'text': 'tok'}] ---- < +--- echo matchbufline(10, '\<\k\+\>', 1, 4) +--- < `[{'lnum': 4, 'byteidx': 0, 'text': 'tik'}, {'lnum': 4, 'byteidx': 4, 'text': 'tok'}]` +--- --- If {submatch} is present and is v:true, then submatches like --- "\1", "\2", etc. are also returned. Example: >vim --- " Assuming line 2 in buffer 2 contains "acd" ---- :echo matchbufline(2, '\(a\)\?\(b\)\?\(c\)\?\(.*\)', 2, 2 +--- echo matchbufline(2, '\(a\)\?\(b\)\?\(c\)\?\(.*\)', 2, 2 --- \ {'submatches': v:true}) ---- [{'lnum': 2, 'byteidx': 0, 'text': 'acd', 'submatches': ['a', '', 'c', 'd', '', '', '', '', '']}] ---- <The "submatches" List always contains 9 items. If a submatch +--- < `[{'lnum': 2, 'byteidx': 0, 'text': 'acd', 'submatches': ['a', '', 'c', 'd', '', '', '', '', '']}]` +--- The "submatches" List always contains 9 items. If a submatch --- is not found, then an empty string is returned for that --- submatch. --- @@ -5606,8 +5705,8 @@ function vim.fn.matchbufline(buf, pat, lnum, end_, dict) end --- If {win} is specified, use the window with this number or --- window ID instead of the current window. --- ---- @param id any ---- @param win? any +--- @param id integer +--- @param win? integer --- @return any function vim.fn.matchdelete(id, win) end @@ -5630,9 +5729,9 @@ function vim.fn.matchdelete(id, win) end --- When {expr} is a |List| the result is equal to |match()|. --- --- @param expr any ---- @param pat any ---- @param start? any ---- @param count? any +--- @param pat string +--- @param start? integer +--- @param count? integer --- @return any function vim.fn.matchend(expr, pat, start, count) end @@ -5698,9 +5797,9 @@ function vim.fn.matchend(expr, pat, start, count) end --- \ {'matchseq': 1}) --- <results in `['two one']`. --- ---- @param list any ---- @param str any ---- @param dict? any +--- @param list any[] +--- @param str string +--- @param dict? string --- @return any function vim.fn.matchfuzzy(list, str, dict) end @@ -5725,9 +5824,9 @@ function vim.fn.matchfuzzy(list, str, dict) end --- \ ->matchfuzzypos('ll', {'key' : 'text'}) --- <results in `[[{"id": 10, "text": "hello"}], [[2, 3]], [127]]` --- ---- @param list any ---- @param str any ---- @param dict? any +--- @param list any[] +--- @param str string +--- @param dict? string --- @return any function vim.fn.matchfuzzypos(list, str, dict) end @@ -5743,9 +5842,9 @@ function vim.fn.matchfuzzypos(list, str, dict) end --- You can pass in a List, but that is not very useful. --- --- @param expr any ---- @param pat any ---- @param start? any ---- @param count? any +--- @param pat string +--- @param start? integer +--- @param count? integer --- @return any function vim.fn.matchlist(expr, pat, start, count) end @@ -5762,9 +5861,9 @@ function vim.fn.matchlist(expr, pat, start, count) end --- The type isn't changed, it's not necessarily a String. --- --- @param expr any ---- @param pat any ---- @param start? any ---- @param count? any +--- @param pat string +--- @param start? integer +--- @param count? integer --- @return any function vim.fn.matchstr(expr, pat, start, count) end @@ -5786,17 +5885,17 @@ function vim.fn.matchstr(expr, pat, start, count) end --- option settings on the pattern. --- --- Example: >vim ---- :echo matchstrlist(['tik tok'], '\<\k\+\>') ---- [{'idx': 0, 'byteidx': 0, 'text': 'tik'}, {'idx': 0, 'byteidx': 4, 'text': 'tok'}] ---- :echo matchstrlist(['a', 'b'], '\<\k\+\>') ---- [{'idx': 0, 'byteidx': 0, 'text': 'a'}, {'idx': 1, 'byteidx': 0, 'text': 'b'}] ---- < +--- echo matchstrlist(['tik tok'], '\<\k\+\>') +--- < `[{'idx': 0, 'byteidx': 0, 'text': 'tik'}, {'idx': 0, 'byteidx': 4, 'text': 'tok'}]` >vim +--- echo matchstrlist(['a', 'b'], '\<\k\+\>') +--- < `[{'idx': 0, 'byteidx': 0, 'text': 'a'}, {'idx': 1, 'byteidx': 0, 'text': 'b'}]` +--- --- If "submatches" is present and is v:true, then submatches like --- "\1", "\2", etc. are also returned. Example: >vim ---- :echo matchstrlist(['acd'], '\(a\)\?\(b\)\?\(c\)\?\(.*\)', +--- echo matchstrlist(['acd'], '\(a\)\?\(b\)\?\(c\)\?\(.*\)', --- \ #{submatches: v:true}) ---- [{'idx': 0, 'byteidx': 0, 'text': 'acd', 'submatches': ['a', '', 'c', 'd', '', '', '', '', '']}] ---- <The "submatches" List always contains 9 items. If a submatch +--- < `[{'idx': 0, 'byteidx': 0, 'text': 'acd', 'submatches': ['a', '', 'c', 'd', '', '', '', '', '']}]` +--- The "submatches" List always contains 9 items. If a submatch --- is not found, then an empty string is returned for that --- submatch. --- @@ -5824,9 +5923,9 @@ function vim.fn.matchstrlist(list, pat, dict) end --- The type isn't changed, it's not necessarily a String. --- --- @param expr any ---- @param pat any ---- @param start? any ---- @param count? any +--- @param pat string +--- @param start? integer +--- @param count? integer --- @return any function vim.fn.matchstrpos(expr, pat, start, count) end @@ -5889,7 +5988,7 @@ function vim.fn.max(expr) end --- < --- --- @param path string ---- @param modes? any +--- @param modes? string --- @return any function vim.fn.menu_get(path, modes) end @@ -5986,17 +6085,14 @@ function vim.fn.min(expr) end --- When {flags} is present it must be a string. An empty string --- has no effect. --- ---- If {flags} contains "p" then intermediate directories are ---- created as necessary. +--- {flags} can contain these character flags: +--- "p" intermediate directories will be created as necessary +--- "D" {name} will be deleted at the end of the current +--- function, but not recursively |:defer| +--- "R" {name} will be deleted recursively at the end of the +--- current function |:defer| --- ---- If {flags} contains "D" then {name} is deleted at the end of ---- the current function, as with: >vim ---- defer delete({name}, 'd') ---- < ---- If {flags} contains "R" then {name} is deleted recursively at ---- the end of the current function, as with: >vim ---- defer delete({name}, 'rf') ---- <Note that when {name} has more than one part and "p" is used +--- Note that when {name} has more than one part and "p" is used --- some directories may already exist. Only the first one that --- is created and what it contains is scheduled to be deleted. --- E.g. when using: >vim @@ -6025,7 +6121,7 @@ function vim.fn.min(expr) end --- --- @param name string --- @param flags? string ---- @param prot? any +--- @param prot? string --- @return any function vim.fn.mkdir(name, flags, prot) end @@ -6159,12 +6255,7 @@ function vim.fn.msgpackdump(list, type) end --- C parser does not support such values. --- float |Float|. This value cannot possibly appear in --- |msgpackparse()| output. ---- string |readfile()|-style list of strings. This value will ---- appear in |msgpackparse()| output if string contains ---- zero byte or if string is a mapping key and mapping is ---- being represented as special dictionary for other ---- reasons. ---- binary |String|, or |Blob| if binary string contains zero +--- string |String|, or |Blob| if binary string contains zero --- byte. This value cannot appear in |msgpackparse()| --- output since blobs were introduced. --- array |List|. This value cannot appear in |msgpackparse()| @@ -6211,8 +6302,8 @@ function vim.fn.nextnonblank(lnum) end --- characters. nr2char(0) is a real NUL and terminates the --- string, thus results in an empty string. --- ---- @param expr any ---- @param utf8? any +--- @param expr integer +--- @param utf8? boolean --- @return any function vim.fn.nr2char(expr, utf8) end @@ -6227,8 +6318,8 @@ function vim.fn.nr2char(expr, utf8) end --- to separate commands. In many places it would not be clear if --- "|" is an operator or a command separator. --- ---- @param expr any ---- @param expr1 any +--- @param expr number +--- @param expr1 number --- @return any vim.fn['or'] = function(expr, expr1) end @@ -6246,7 +6337,7 @@ vim.fn['or'] = function(expr, expr1) end --- Returns an empty string on error. --- --- @param path string ---- @param len? any +--- @param len? integer --- @return any function vim.fn.pathshorten(path, len) end @@ -6279,8 +6370,8 @@ function vim.fn.perleval(expr) end --- echo pow(32, 0.20) --- < 2.0 --- ---- @param x any ---- @param y any +--- @param x number +--- @param y number --- @return any function vim.fn.pow(x, y) end @@ -6618,7 +6709,7 @@ function vim.fn.prevnonblank(lnum) end --- into this, copying the exact format string and parameters that --- were used. --- ---- @param fmt any +--- @param fmt string --- @param expr1? any --- @return string function vim.fn.printf(fmt, expr1) end @@ -6629,7 +6720,7 @@ function vim.fn.printf(fmt, expr1) end --- If the buffer doesn't exist or isn't a prompt buffer, an empty --- string is returned. --- ---- @param buf any +--- @param buf integer|string --- @return any function vim.fn.prompt_getprompt(buf) end @@ -6664,8 +6755,8 @@ function vim.fn.prompt_getprompt(buf) end --- endfunc --- call prompt_setcallback(bufnr(), function('s:TextEntered')) --- ---- @param buf any ---- @param expr any +--- @param buf integer|string +--- @param expr string|function --- @return any function vim.fn.prompt_setcallback(buf, expr) end @@ -6677,8 +6768,8 @@ function vim.fn.prompt_setcallback(buf, expr) end --- mode. Without setting a callback Vim will exit Insert mode, --- as in any buffer. --- ---- @param buf any ---- @param expr any +--- @param buf integer|string +--- @param expr string|function --- @return any function vim.fn.prompt_setinterrupt(buf, expr) end @@ -6689,8 +6780,8 @@ function vim.fn.prompt_setinterrupt(buf, expr) end --- call prompt_setprompt(bufnr(''), 'command: ') --- < --- ---- @param buf any ---- @param text any +--- @param buf integer|string +--- @param text string --- @return any function vim.fn.prompt_setprompt(buf, text) end @@ -6766,7 +6857,7 @@ function vim.fn.pyxeval(expr) end --- echo rand(seed) % 16 " random number 0 - 15 --- < --- ---- @param expr? any +--- @param expr? number --- @return any function vim.fn.rand(expr) end @@ -6789,8 +6880,8 @@ function vim.fn.rand(expr) end --- < --- --- @param expr any ---- @param max? any ---- @param stride? any +--- @param max? integer +--- @param stride? integer --- @return any function vim.fn.range(expr, max, stride) end @@ -6818,8 +6909,8 @@ function vim.fn.range(expr, max, stride) end --- Also see |readfile()| and |writefile()|. --- --- @param fname string ---- @param offset? any ---- @param size? any +--- @param offset? integer +--- @param size? integer --- @return any function vim.fn.readblob(fname, offset, size) end @@ -6852,8 +6943,8 @@ function vim.fn.readblob(fname, offset, size) end --- < --- Returns an empty List on error. --- ---- @param directory any ---- @param expr? any +--- @param directory string +--- @param expr? integer --- @return any function vim.fn.readdir(directory, expr) end @@ -6890,8 +6981,8 @@ function vim.fn.readdir(directory, expr) end --- Also see |writefile()|. --- --- @param fname string ---- @param type? any ---- @param max? any +--- @param type? string +--- @param max? integer --- @return any function vim.fn.readfile(fname, type, max) end @@ -6913,7 +7004,7 @@ function vim.fn.readfile(fname, type, max) end --- < --- --- @param object any ---- @param func any +--- @param func function --- @param initial? any --- @return any function vim.fn.reduce(object, func, initial) end @@ -7019,9 +7110,9 @@ function vim.fn.remove(list, idx) end --- < --- Use |delete()| to remove a file. --- ---- @param list any +--- @param list any[] --- @param idx integer ---- @param end_? any +--- @param end_? integer --- @return any function vim.fn.remove(list, idx, end_) end @@ -7044,7 +7135,7 @@ function vim.fn.remove(blob, idx) end --- --- @param blob any --- @param idx integer ---- @param end_? any +--- @param end_? integer --- @return any function vim.fn.remove(blob, idx, end_) end @@ -7055,7 +7146,7 @@ function vim.fn.remove(blob, idx, end_) end --- Returns zero on error. --- --- @param dict any ---- @param key any +--- @param key string --- @return any function vim.fn.remove(dict, key) end @@ -7066,8 +7157,8 @@ function vim.fn.remove(dict, key) end --- NOTE: If {to} exists it is overwritten without warning. --- This function is not available in the |sandbox|. --- ---- @param from any ---- @param to any +--- @param from string +--- @param to string --- @return any function vim.fn.rename(from, to) end @@ -7081,7 +7172,7 @@ function vim.fn.rename(from, to) end --- <Results in ['a', 'b', 'a', 'b', 'a', 'b']. --- --- @param expr any ---- @param count any +--- @param count integer --- @return any vim.fn['repeat'] = function(expr, count) end @@ -7097,7 +7188,7 @@ vim.fn['repeat'] = function(expr, count) end --- current directory (provided the result is still a relative --- path name) and also keeps a trailing path separator. --- ---- @param filename any +--- @param filename string --- @return any function vim.fn.resolve(filename) end @@ -7128,7 +7219,7 @@ function vim.fn.reverse(object) end --- echo round(-4.5) --- < -5.0 --- ---- @param expr any +--- @param expr number --- @return any function vim.fn.round(expr) end @@ -7138,8 +7229,8 @@ function vim.fn.round(expr) end --- au VimLeave call rpcnotify(0, "leaving") --- < --- ---- @param channel any ---- @param event any +--- @param channel integer +--- @param event string --- @param args? any --- @return any function vim.fn.rpcnotify(channel, event, args) end @@ -7150,19 +7241,20 @@ function vim.fn.rpcnotify(channel, event, args) end --- let result = rpcrequest(rpc_chan, "func", 1, 2, 3) --- < --- ---- @param channel any ---- @param method any +--- @param channel integer +--- @param method string --- @param args? any --- @return any function vim.fn.rpcrequest(channel, method, args) end +--- @deprecated --- Deprecated. Replace >vim --- let id = rpcstart('prog', ['arg1', 'arg2']) --- <with >vim --- let id = jobstart(['prog', 'arg1', 'arg2'], {'rpc': v:true}) --- < --- ---- @param prog any +--- @param prog string --- @param argv? any --- @return any function vim.fn.rpcstart(prog, argv) end @@ -7195,7 +7287,7 @@ function vim.fn.rubyeval(expr) end --- attribute at other positions. --- Returns -1 when row or col is out of range. --- ---- @param row any +--- @param row integer --- @param col integer --- @return any function vim.fn.screenattr(row, col) end @@ -7209,7 +7301,7 @@ function vim.fn.screenattr(row, col) end --- This is mainly to be used for testing. --- Returns -1 when row or col is out of range. --- ---- @param row any +--- @param row integer --- @param col integer --- @return any function vim.fn.screenchar(row, col) end @@ -7220,7 +7312,7 @@ function vim.fn.screenchar(row, col) end --- This is mainly to be used for testing. --- Returns an empty List when row or col is out of range. --- ---- @param row any +--- @param row integer --- @param col integer --- @return any function vim.fn.screenchars(row, col) end @@ -7236,7 +7328,7 @@ function vim.fn.screenchars(row, col) end --- the following mappings: >vim --- nnoremap <expr> GG ":echom " .. screencol() .. "\n" --- nnoremap <silent> GG :echom screencol()<CR> ---- noremap GG <Cmd>echom screencol()<Cr> +--- noremap GG <Cmd>echom screencol()<CR> --- < --- --- @return any @@ -7288,7 +7380,7 @@ function vim.fn.screenrow() end --- This is mainly to be used for testing. --- Returns an empty String when row or col is out of range. --- ---- @param row any +--- @param row integer --- @param col integer --- @return any function vim.fn.screenstring(row, col) end @@ -7347,6 +7439,9 @@ function vim.fn.screenstring(row, col) end --- The value must not be negative. A zero value is like not --- giving the argument. --- +--- Note: the timeout is only considered when searching, not +--- while evaluating the {skip} expression. +--- --- If the {skip} expression is given it is evaluated with the --- cursor positioned on the start of a match. If it evaluates to --- non-zero this match is skipped. This can be used, for @@ -7394,11 +7489,11 @@ function vim.fn.screenstring(row, col) end --- without the 'e' flag if the cursor is on the "f" of "if". --- The 'n' flag tells the function not to move the cursor. --- ---- @param pattern any +--- @param pattern string --- @param flags? string ---- @param stopline? any +--- @param stopline? integer --- @param timeout? integer ---- @param skip? any +--- @param skip? string|function --- @return any function vim.fn.search(pattern, flags, stopline, timeout, skip) end @@ -7545,8 +7640,8 @@ function vim.fn.searchcount(options) end --- < --- --- @param name string ---- @param global? any ---- @param thisblock? any +--- @param global? boolean +--- @param thisblock? boolean --- @return any function vim.fn.searchdecl(name, global, thisblock) end @@ -7634,8 +7729,15 @@ function vim.fn.searchdecl(name, global, thisblock) end --- \ 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string"') --- < --- ---- @return any -function vim.fn.searchpair() end +--- @param start string +--- @param middle string +--- @param end_ string +--- @param flags? string +--- @param skip? string|function +--- @param stopline? integer +--- @param timeout? integer +--- @return integer +function vim.fn.searchpair(start, middle, end_, flags, skip, stopline, timeout) end --- Same as |searchpair()|, but returns a |List| with the line and --- column position of the match. The first element of the |List| @@ -7647,8 +7749,15 @@ function vim.fn.searchpair() end --- < --- See |match-parens| for a bigger and more useful example. --- ---- @return any -function vim.fn.searchpairpos() end +--- @param start string +--- @param middle string +--- @param end_ string +--- @param flags? string +--- @param skip? string|function +--- @param stopline? integer +--- @param timeout? integer +--- @return [integer, integer] +function vim.fn.searchpairpos(start, middle, end_, flags, skip, stopline, timeout) end --- Same as |search()|, but returns a |List| with the line and --- column position of the match. The first element of the |List| @@ -7664,11 +7773,11 @@ function vim.fn.searchpairpos() end --- <In this example "submatch" is 2 when a lowercase letter is --- found |/\l|, 3 when an uppercase letter is found |/\u|. --- ---- @param pattern any +--- @param pattern string --- @param flags? string ---- @param stopline? any +--- @param stopline? integer --- @param timeout? integer ---- @param skip? any +--- @param skip? string|function --- @return any function vim.fn.searchpos(pattern, flags, stopline, timeout, skip) end @@ -7714,7 +7823,7 @@ function vim.fn.serverlist() end --- echo serverstart('::1:12345') --- < --- ---- @param address? any +--- @param address? string --- @return any function vim.fn.serverstart(address) end @@ -7723,7 +7832,7 @@ function vim.fn.serverstart(address) end --- If |v:servername| is stopped it is set to the next available --- address in |serverlist()|. --- ---- @param address any +--- @param address string --- @return any function vim.fn.serverstop(address) end @@ -7751,9 +7860,9 @@ function vim.fn.serverstop(address) end --- If {buf} is not a valid buffer or {lnum} is not valid, an --- error message is given. --- ---- @param buf any +--- @param buf integer|string --- @param lnum integer ---- @param text any +--- @param text string|string[] --- @return any function vim.fn.setbufline(buf, lnum, text) end @@ -7770,7 +7879,7 @@ function vim.fn.setbufline(buf, lnum, text) end --- call setbufvar("todo", "myvar", "foobar") --- <This function is not available in the |sandbox|. --- ---- @param buf any +--- @param buf integer|string --- @param varname string --- @param val any --- @return any @@ -7803,13 +7912,13 @@ function vim.fn.setbufvar(buf, varname, val) end --- To clear the overrides pass an empty {list}: >vim --- call setcellwidths([]) --- ---- <You can use the script $VIMRUNTIME/tools/emoji_list.vim to see +--- <You can use the script $VIMRUNTIME/tools/emoji_list.lua to see --- the effect for known emoji characters. Move the cursor --- through the text to check if the cell widths of your terminal --- match with what Vim knows about each emoji. If it doesn't --- look right you need to adjust the {list} argument. --- ---- @param list any +--- @param list any[] --- @return any function vim.fn.setcellwidths(list) end @@ -7823,8 +7932,8 @@ function vim.fn.setcellwidths(list) end --- call setpos('.', [0, 8, 4, 0]) --- <positions the cursor on the second character 'ë³´'. --- ---- @param expr any ---- @param list any +--- @param expr string +--- @param list integer[] --- @return any function vim.fn.setcharpos(expr, list) end @@ -7847,7 +7956,7 @@ function vim.fn.setcharpos(expr, list) end --- call setcharsearch(prevsearch) --- <Also see |getcharsearch()|. --- ---- @param dict any +--- @param dict string --- @return any function vim.fn.setcharsearch(dict) end @@ -7857,8 +7966,8 @@ function vim.fn.setcharsearch(dict) end --- Returns 0 when successful, 1 when not editing the command --- line. --- ---- @param str any ---- @param pos? any +--- @param str string +--- @param pos? integer --- @return any function vim.fn.setcmdline(str, pos) end @@ -7876,13 +7985,13 @@ function vim.fn.setcmdline(str, pos) end --- Returns 0 when successful, 1 when not editing the command --- line. --- ---- @param pos any +--- @param pos integer --- @return any function vim.fn.setcmdpos(pos) end --- @param lnum integer --- @param col? integer ---- @param off? any +--- @param off? integer --- @return any function vim.fn.setcursorcharpos(lnum, col, off) end @@ -7896,7 +8005,7 @@ function vim.fn.setcursorcharpos(lnum, col, off) end --- call cursor(4, 3) --- <positions the cursor on the first character 'ì—¬'. --- ---- @param list any +--- @param list integer[] --- @return any function vim.fn.setcursorcharpos(list) end @@ -7907,7 +8016,7 @@ function vim.fn.setcursorcharpos(list) end --- See also |expr-env|. --- --- @param name string ---- @param val any +--- @param val string --- @return any function vim.fn.setenv(name, val) end @@ -7981,8 +8090,8 @@ function vim.fn.setline(lnum, text) end --- --- @param nr integer --- @param list any ---- @param action? any ---- @param what? any +--- @param action? string +--- @param what? table --- @return any function vim.fn.setloclist(nr, list, action, what) end @@ -7994,7 +8103,7 @@ function vim.fn.setloclist(nr, list, action, what) end --- window ID instead of the current window. --- --- @param list any ---- @param win? any +--- @param win? integer --- @return any function vim.fn.setmatches(list, win) end @@ -8046,8 +8155,8 @@ function vim.fn.setmatches(list, win) end --- also set the preferred column. Also see the "curswant" key in --- |winrestview()|. --- ---- @param expr any ---- @param list any +--- @param expr string +--- @param list integer[] --- @return any function vim.fn.setpos(expr, list) end @@ -8164,9 +8273,9 @@ function vim.fn.setpos(expr, list) end --- independent of the 'errorformat' setting. Use a command like --- `:cc 1` to jump to the first position. --- ---- @param list any ---- @param action? any ---- @param what? any +--- @param list any[] +--- @param action? string +--- @param what? table --- @return any function vim.fn.setqflist(list, action, what) end @@ -8301,7 +8410,7 @@ function vim.fn.settabwinvar(tabnr, winnr, varname, val) end --- --- @param nr integer --- @param dict any ---- @param action? any +--- @param action? string --- @return any function vim.fn.settagstack(nr, dict, action) end @@ -8355,7 +8464,7 @@ function vim.fn.sha256(string) end --- <See also |::S|. --- --- @param string string ---- @param special? any +--- @param special? boolean --- @return any function vim.fn.shellescape(string, special) end @@ -8400,6 +8509,7 @@ function vim.fn.sign_define(name, dict) end --- icon full path to the bitmap file for the sign. --- linehl highlight group used for the whole line the --- sign is placed in. +--- priority default priority value of the sign --- numhl highlight group used for the line number where --- the sign is placed. --- text text that is displayed when there is no icon @@ -8450,6 +8560,7 @@ function vim.fn.sign_define(list) end --- linehl highlight group used for the whole line the --- sign is placed in; not present if not set. --- name name of the sign +--- priority default priority value of the sign --- numhl highlight group used for the line number where --- the sign is placed; not present if not set. --- text text that is displayed when there is no icon @@ -8536,7 +8647,7 @@ function vim.fn.sign_getdefined(name) end --- echo sign_getplaced() --- < --- ---- @param buf? any +--- @param buf? integer|string --- @param dict? vim.fn.sign_getplaced.dict --- @return vim.fn.sign_getplaced.ret.item[] function vim.fn.sign_getplaced(buf, dict) end @@ -8610,10 +8721,10 @@ function vim.fn.sign_jump(id, group, buf) end --- \ {'lnum' : 40, 'priority' : 90}) --- < --- ---- @param id any ---- @param group any +--- @param id integer +--- @param group string --- @param name string ---- @param buf any +--- @param buf integer|string --- @param dict? vim.fn.sign_place.dict --- @return integer function vim.fn.sign_place(id, group, name, buf, dict) end @@ -8641,7 +8752,8 @@ function vim.fn.sign_place(id, group, name, buf, dict) end --- priority Priority of the sign. When multiple signs are --- placed on a line, the sign with the highest --- priority is used. If not specified, the ---- default value of 10 is used. See +--- default value of 10 is used, unless specified +--- otherwise by the sign definition. See --- |sign-priority| for more information. --- --- If {id} refers to an existing sign, then the existing sign is @@ -8804,7 +8916,7 @@ function vim.fn.sign_unplacelist(list) end --- directory. In order to resolve all the involved symbolic --- links before simplifying the path name, use |resolve()|. --- ---- @param filename any +--- @param filename string --- @return any function vim.fn.simplify(filename) end @@ -8817,7 +8929,7 @@ function vim.fn.simplify(filename) end --- echo sin(-4.01) --- < 0.763301 --- ---- @param expr any +--- @param expr number --- @return any function vim.fn.sin(expr) end @@ -8831,7 +8943,7 @@ function vim.fn.sin(expr) end --- echo sinh(-0.9) --- < -1.026517 --- ---- @param expr any +--- @param expr number --- @return any function vim.fn.sinh(expr) end @@ -8845,8 +8957,8 @@ function vim.fn.sinh(expr) end --- Returns an empty value if {start} or {end} are invalid. --- --- @param expr any ---- @param start any ---- @param end_? any +--- @param start integer +--- @param end_? integer --- @return any function vim.fn.slice(expr, start, end_) end @@ -8875,7 +8987,7 @@ function vim.fn.slice(expr, start, end_) end --- - 0 on invalid arguments or connection failure. --- --- @param mode string ---- @param address any +--- @param address string --- @param opts? table --- @return any function vim.fn.sockconnect(mode, address, opts) end @@ -8953,7 +9065,7 @@ function vim.fn.sockconnect(mode, address, opts) end --- < --- --- @param list any ---- @param how? any +--- @param how? string|function --- @param dict? any --- @return any function vim.fn.sort(list, how, dict) end @@ -8965,7 +9077,7 @@ function vim.fn.sort(list, how, dict) end --- This can be used for making spelling suggestions. Note that --- the method can be quite slow. --- ---- @param word any +--- @param word string --- @return any function vim.fn.soundfold(word) end @@ -8992,7 +9104,7 @@ function vim.fn.soundfold(word) end --- The spelling information for the current window and the value --- of 'spelllang' are used. --- ---- @param sentence? any +--- @param sentence? string --- @return any function vim.fn.spellbadword(sentence) end @@ -9016,15 +9128,15 @@ function vim.fn.spellbadword(sentence) end --- The spelling information for the current window is used. The --- values of 'spelllang' and 'spellsuggest' are used. --- ---- @param word any ---- @param max? any ---- @param capital? any +--- @param word string +--- @param max? integer +--- @param capital? boolean --- @return any function vim.fn.spellsuggest(word, max, capital) end --- Make a |List| out of {string}. When {pattern} is omitted or ---- empty each white-separated sequence of characters becomes an ---- item. +--- empty each white space separated sequence of characters +--- becomes an item. --- Otherwise the string is split where {pattern} matches, --- removing the matched characters. 'ignorecase' is not used --- here, add \c to ignore case. |/\c| @@ -9047,8 +9159,8 @@ function vim.fn.spellsuggest(word, max, capital) end --- <The opposite function is |join()|. --- --- @param string string ---- @param pattern? any ---- @param keepempty? any +--- @param pattern? string +--- @param keepempty? boolean --- @return any function vim.fn.split(string, pattern, keepempty) end @@ -9064,7 +9176,7 @@ function vim.fn.split(string, pattern, keepempty) end --- < str2float("nan") --- NaN may be different, it depends on system libraries. --- ---- @param expr any +--- @param expr number --- @return any function vim.fn.sqrt(expr) end @@ -9082,7 +9194,7 @@ function vim.fn.sqrt(expr) end --- echo rand(seed) --- < --- ---- @param expr? any +--- @param expr? number --- @return any function vim.fn.srand(expr) end @@ -9187,7 +9299,7 @@ function vim.fn.stdpath(what) end --- Returns 0.0 if the conversion fails. --- --- @param string string ---- @param quoted? any +--- @param quoted? boolean --- @return any function vim.fn.str2float(string, quoted) end @@ -9203,7 +9315,7 @@ function vim.fn.str2float(string, quoted) end --- echo str2list("aÌ") " returns [97, 769] --- --- @param string string ---- @param utf8? any +--- @param utf8? boolean --- @return any function vim.fn.str2list(string, utf8) end @@ -9226,7 +9338,7 @@ function vim.fn.str2list(string, utf8) end --- Returns 0 if {string} is empty or on error. --- --- @param string string ---- @param base? any +--- @param base? integer --- @return any function vim.fn.str2nr(string, base) end @@ -9257,10 +9369,10 @@ function vim.fn.strcharlen(string) end --- --- Returns an empty string on error. --- ---- @param src any ---- @param start any ---- @param len? any ---- @param skipcc? any +--- @param src string +--- @param start integer +--- @param len? integer +--- @param skipcc? boolean --- @return any function vim.fn.strcharpart(src, start, len, skipcc) end @@ -9293,7 +9405,7 @@ function vim.fn.strcharpart(src, start, len, skipcc) end --- < --- --- @param string string ---- @param skipcc? any +--- @param skipcc? boolean --- @return integer function vim.fn.strchars(string, skipcc) end @@ -9331,8 +9443,8 @@ function vim.fn.strdisplaywidth(string, col) end --- echo strftime("%c", getftime("file.c")) --- " Show mod time of file.c. --- ---- @param format any ---- @param time? any +--- @param format string +--- @param time? number --- @return string function vim.fn.strftime(format, time) end @@ -9796,7 +9908,7 @@ function vim.fn.synIDtrans(synID) end --- --- @param lnum integer --- @param col integer ---- @return {[1]: integer, [2]: string, [3]: integer} +--- @return [integer, string, integer] function vim.fn.synconcealed(lnum, col) end --- Return a |List|, which is the stack of syntax items at the @@ -9906,7 +10018,7 @@ function vim.fn.systemlist(cmd, input, keepempty) end --- endfor --- <Note that a buffer may appear in more than one window. --- ---- @param arg? any +--- @param arg? integer --- @return any function vim.fn.tabpagebuflist(arg) end @@ -10049,7 +10161,7 @@ function vim.fn.tempname() end --- except $TERM is set to "xterm-256color". Full behavior is --- described in |terminal|. --- ---- @param cmd any +--- @param cmd string|string[] --- @param opts? table --- @return any function vim.fn.termopen(cmd, opts) end @@ -10068,7 +10180,7 @@ function vim.fn.termopen(cmd, opts) end --- -1 means forever --- "callback" the callback --- ---- @param id? any +--- @param id? integer --- @return any function vim.fn.timer_info(id) end @@ -10084,8 +10196,8 @@ function vim.fn.timer_info(id) end --- String, then the timer is paused, otherwise it is unpaused. --- See |non-zero-arg|. --- ---- @param timer any ---- @param paused any +--- @param timer integer +--- @param paused boolean --- @return any function vim.fn.timer_pause(timer, paused) end @@ -10118,8 +10230,8 @@ function vim.fn.timer_pause(timer, paused) end --- \ {'repeat': 3}) --- <This invokes MyHandler() three times at 500 msec intervals. --- ---- @param time any ---- @param callback any +--- @param time number +--- @param callback string|function --- @param options? table --- @return any function vim.fn.timer_start(time, callback, options) end @@ -10128,7 +10240,7 @@ function vim.fn.timer_start(time, callback, options) end --- {timer} is an ID returned by timer_start(), thus it must be a --- Number. If {timer} does not exist there is no error. --- ---- @param timer any +--- @param timer integer --- @return any function vim.fn.timer_stop(timer) end @@ -10143,7 +10255,7 @@ function vim.fn.timer_stopall() end --- characters turned into lowercase (just like applying |gu| to --- the string). Returns an empty string on error. --- ---- @param expr any +--- @param expr string --- @return string function vim.fn.tolower(expr) end @@ -10151,7 +10263,7 @@ function vim.fn.tolower(expr) end --- characters turned into uppercase (just like applying |gU| to --- the string). Returns an empty string on error. --- ---- @param expr any +--- @param expr string --- @return string function vim.fn.toupper(expr) end @@ -10203,7 +10315,7 @@ function vim.fn.tr(src, fromstr, tostr) end --- echo trim(" vim ", " ", 2) --- <returns " vim" --- ---- @param text any +--- @param text string --- @param mask? string --- @param dir? 0|1|2 --- @return string @@ -10221,7 +10333,7 @@ function vim.fn.trim(text, mask, dir) end --- echo trunc(4.0) --- < 4.0 --- ---- @param expr any +--- @param expr number --- @return integer function vim.fn.trunc(expr) end @@ -10250,6 +10362,7 @@ function vim.fn.trunc(expr) end --- if myvar is v:null | endif --- <To check if the v:t_ variables exist use this: >vim --- if exists('v:t_number') | endif +--- < --- --- @param expr any --- @return integer @@ -10313,7 +10426,7 @@ function vim.fn.undofile(name) end --- item. --- --- @param buf? integer|string ---- @return any +--- @return vim.fn.undotree.ret function vim.fn.undotree(buf) end --- Remove second and succeeding copies of repeated adjacent @@ -10360,8 +10473,8 @@ function vim.fn.uniq(list, func, dict) end --- --- @param string string --- @param idx integer ---- @param countcc? any ---- @param charidx? any +--- @param countcc? boolean +--- @param charidx? boolean --- @return integer function vim.fn.utf16idx(string, idx, countcc, charidx) end @@ -10382,7 +10495,9 @@ function vim.fn.values(dict) end --- set to 8, it returns 8. |conceal| is ignored. --- For the byte position use |col()|. --- ---- For the use of {expr} see |col()|. +--- For the use of {expr} see |getpos()| and |col()|. +--- When {expr} is "$", it means the end of the cursor line, so +--- the result is the number of cells in the cursor line plus one. --- --- When 'virtualedit' is used {expr} can be [lnum, col, off], --- where "off" is the offset in screen columns from the start of @@ -10392,18 +10507,6 @@ function vim.fn.values(dict) end --- beyond the end of the line can be returned. Also see --- |'virtualedit'| --- ---- The accepted positions are: ---- . the cursor position ---- $ the end of the cursor line (the result is the ---- number of displayed characters in the cursor line ---- plus one) ---- 'x position of mark x (if the mark is not set, 0 is ---- returned) ---- v In Visual mode: the start of the Visual area (the ---- cursor is the end). When not in Visual mode ---- returns the cursor position. Differs from |'<| in ---- that it's updated right away. ---- --- If {list} is present and non-zero then virtcol() returns a --- List with the first and last screen position occupied by the --- character. @@ -10422,13 +10525,16 @@ function vim.fn.values(dict) end --- " With text " there", with 't at 'h': --- --- echo virtcol("'t") " returns 6 ---- <The first column is 1. 0 or [0, 0] is returned for an error. +--- < +--- The first column is 1. 0 or [0, 0] is returned for an error. +--- --- A more advanced example that echoes the maximum length of --- all lines: >vim --- echo max(map(range(1, line('$')), "virtcol([v:val, '$'])")) +--- < --- ---- @param expr any ---- @param list? any +--- @param expr string|integer[] +--- @param list? boolean --- @param winid? integer --- @return any function vim.fn.virtcol(expr, list, winid) end @@ -10477,7 +10583,7 @@ function vim.fn.virtcol2col(winid, lnum, col) end --- a non-empty String, then the Visual mode will be cleared and --- the old value is returned. See |non-zero-arg|. --- ---- @param expr? any +--- @param expr? boolean --- @return any function vim.fn.visualmode(expr) end @@ -10498,7 +10604,7 @@ function vim.fn.visualmode(expr) end --- --- @param timeout integer --- @param condition any ---- @param interval? any +--- @param interval? number --- @return any function vim.fn.wait(timeout, condition, interval) end @@ -10528,8 +10634,8 @@ function vim.fn.wildmenumode() end --- When window {id} does not exist then no error is given and --- an empty string is returned. --- ---- @param id any ---- @param command any +--- @param id integer +--- @param command string --- @param silent? boolean --- @return any function vim.fn.win_execute(id, command, silent) end @@ -10537,7 +10643,7 @@ function vim.fn.win_execute(id, command, silent) end --- Returns a |List| with |window-ID|s for windows that contain --- buffer {bufnr}. When there is none the list is empty. --- ---- @param bufnr any +--- @param bufnr integer --- @return integer[] function vim.fn.win_findbuf(bufnr) end @@ -10549,8 +10655,8 @@ function vim.fn.win_findbuf(bufnr) end --- number {tab}. The first tab has number one. --- Return zero if the window cannot be found. --- ---- @param win? any ---- @param tab? any +--- @param win? integer +--- @param tab? integer --- @return integer function vim.fn.win_getid(win, tab) end @@ -10579,7 +10685,7 @@ function vim.fn.win_gettype(nr) end --- tabpage. --- Return TRUE if successful, FALSE if the window cannot be found. --- ---- @param expr any +--- @param expr integer --- @return 0|1 function vim.fn.win_gotoid(expr) end @@ -10587,14 +10693,14 @@ function vim.fn.win_gotoid(expr) end --- with ID {expr}: [tabnr, winnr]. --- Return [0, 0] if the window cannot be found. --- ---- @param expr any +--- @param expr integer --- @return any function vim.fn.win_id2tabwin(expr) end --- Return the window number of window with ID {expr}. --- Return 0 if the window cannot be found in the current tabpage. --- ---- @param expr any +--- @param expr integer --- @return any function vim.fn.win_id2win(expr) end @@ -10613,7 +10719,7 @@ function vim.fn.win_id2win(expr) end --- Only works for the current tab page. *E1308* --- --- @param nr integer ---- @param offset any +--- @param offset integer --- @return any function vim.fn.win_move_separator(nr, offset) end @@ -10629,7 +10735,7 @@ function vim.fn.win_move_separator(nr, offset) end --- Only works for the current tab page. --- --- @param nr integer ---- @param offset any +--- @param offset integer --- @return any function vim.fn.win_move_statusline(nr, offset) end @@ -10664,7 +10770,7 @@ function vim.fn.win_screenpos(nr) end --- 'splitright' are used. --- --- @param nr integer ---- @param target any +--- @param target integer --- @param options? table --- @return any function vim.fn.win_splitmove(nr, target, options) end @@ -10706,6 +10812,7 @@ function vim.fn.windowsversion() end --- This excludes any window toolbar line. --- Examples: >vim --- echo "The current window has " .. winheight(0) .. " lines." +--- < --- --- @param nr integer --- @return integer @@ -10789,8 +10896,9 @@ function vim.fn.winline() end --- let window_count = winnr('$') --- let prev_window = winnr('#') --- let wnum = winnr('3k') +--- < --- ---- @param arg? any +--- @param arg? string|integer --- @return any function vim.fn.winnr(arg) end @@ -10939,6 +11047,7 @@ function vim.fn.wordcount() end --- To copy a file byte for byte: >vim --- let fl = readfile("foo", "b") --- call writefile(fl, "foocopy", "b") +--- < --- --- @param object any --- @param fname string @@ -10953,7 +11062,7 @@ function vim.fn.writefile(object, fname, flags) end --- let bits = xor(bits, 0x80) --- < --- ---- @param expr any ---- @param expr1 any +--- @param expr number +--- @param expr1 number --- @return any function vim.fn.xor(expr, expr1) end diff --git a/runtime/lua/vim/_options.lua b/runtime/lua/vim/_options.lua index b41e298dd7..a61fa61256 100644 --- a/runtime/lua/vim/_options.lua +++ b/runtime/lua/vim/_options.lua @@ -95,7 +95,6 @@ local api = vim.api -- TODO(tjdevries): Improve option metadata so that this doesn't have to be hardcoded. --- Can be done in a separate PR. local key_value_options = { fillchars = true, fcs = true, @@ -175,6 +174,11 @@ local function new_buf_opt_accessor(bufnr) end local function new_win_opt_accessor(winid, bufnr) + -- TODO(lewis6991): allow passing both buf and win to nvim_get_option_value + if bufnr ~= nil and bufnr ~= 0 then + error('only bufnr=0 is supported') + end + return setmetatable({}, { __index = function(_, k) if bufnr == nil and type(k) == 'number' then @@ -185,11 +189,6 @@ local function new_win_opt_accessor(winid, bufnr) end end - if bufnr ~= nil and bufnr ~= 0 then - error('only bufnr=0 is supported') - end - - -- TODO(lewis6991): allow passing both buf and win to nvim_get_option_value return api.nvim_get_option_value(k, { scope = bufnr and 'local' or nil, win = winid or 0, @@ -197,7 +196,6 @@ local function new_win_opt_accessor(winid, bufnr) end, __newindex = function(_, k, v) - -- TODO(lewis6991): allow passing both buf and win to nvim_set_option_value return api.nvim_set_option_value(k, v, { scope = bufnr and 'local' or nil, win = winid or 0, diff --git a/runtime/lua/vim/_watch.lua b/runtime/lua/vim/_watch.lua index 02b3f536c2..11f6742941 100644 --- a/runtime/lua/vim/_watch.lua +++ b/runtime/lua/vim/_watch.lua @@ -30,6 +30,8 @@ M.FileChangeType = { --- @class vim._watch.watch.Opts : vim._watch.Opts --- @field uvflags? uv.fs_event_start.flags +--- Decides if `path` should be skipped. +--- --- @param path string --- @param opts? vim._watch.Opts local function skip(path, opts) @@ -69,7 +71,7 @@ function M.watch(path, opts, callback) local uvflags = opts and opts.uvflags or {} local handle = assert(uv.new_fs_event()) - local _, start_err = handle:start(path, uvflags, function(err, filename, events) + local _, start_err, start_errname = handle:start(path, uvflags, function(err, filename, events) assert(not err, err) local fullpath = path if filename then @@ -96,7 +98,15 @@ function M.watch(path, opts, callback) callback(fullpath, change_type) end) - assert(not start_err, start_err) + if start_err then + if start_errname == 'ENOENT' then + -- Server may send "workspace/didChangeWatchedFiles" with nonexistent `baseUri` path. + -- This is mostly a placeholder until we have `nvim_log` API. + vim.notify_once(('watch.watch: %s'):format(start_err), vim.log.levels.INFO) + end + -- TODO(justinmk): log important errors once we have `nvim_log` API. + return function() end + end return function() local _, stop_err = handle:stop() @@ -193,7 +203,18 @@ function M.watchdirs(path, opts, callback) local root_handle = assert(uv.new_fs_event()) handles[path] = root_handle - root_handle:start(path, {}, create_on_change(path)) + local _, start_err, start_errname = root_handle:start(path, {}, create_on_change(path)) + + if start_err then + if start_errname == 'ENOENT' then + -- Server may send "workspace/didChangeWatchedFiles" with nonexistent `baseUri` path. + -- This is mostly a placeholder until we have `nvim_log` API. + vim.notify_once(('watch.watchdirs: %s'):format(start_err), vim.log.levels.INFO) + end + -- TODO(justinmk): log important errors once we have `nvim_log` API. + + -- Continue. vim.fs.dir() will return nothing, so the code below is harmless. + end --- "640K ought to be enough for anyone" --- Who has folders this deep? @@ -227,11 +248,12 @@ end --- @param data string --- @param opts vim._watch.Opts? --- @param callback vim._watch.Callback -local function fswatch_output_handler(data, opts, callback) +local function on_inotifywait_output(data, opts, callback) local d = vim.split(data, '%s+') -- only consider the last reported event - local fullpath, event = d[1], d[#d] + local path, event, file = d[1], d[2], d[#d] + local fullpath = vim.fs.joinpath(path, file) if skip(fullpath, opts) then return @@ -240,20 +262,16 @@ local function fswatch_output_handler(data, opts, callback) --- @type integer local change_type - if event == 'Created' then + if event == 'CREATE' then change_type = M.FileChangeType.Created - elseif event == 'Removed' then + elseif event == 'DELETE' then change_type = M.FileChangeType.Deleted - elseif event == 'Updated' then + elseif event == 'MODIFY' then change_type = M.FileChangeType.Changed - elseif event == 'Renamed' then - local _, staterr, staterrname = uv.fs_stat(fullpath) - if staterrname == 'ENOENT' then - change_type = M.FileChangeType.Deleted - else - assert(not staterr, staterr) - change_type = M.FileChangeType.Created - end + elseif event == 'MOVED_FROM' then + change_type = M.FileChangeType.Deleted + elseif event == 'MOVED_TO' then + change_type = M.FileChangeType.Created end if change_type then @@ -265,24 +283,22 @@ end --- @param opts vim._watch.Opts? --- @param callback vim._watch.Callback Callback for new events --- @return fun() cancel Stops the watcher -function M.fswatch(path, opts, callback) - -- debounce isn't the same as latency but close enough - local latency = 0.5 -- seconds - if opts and opts.debounce then - latency = opts.debounce / 1000 - end - +function M.inotify(path, opts, callback) local obj = vim.system({ - 'fswatch', - '--event=Created', - '--event=Removed', - '--event=Updated', - '--event=Renamed', - '--event-flags', + 'inotifywait', + '--quiet', -- suppress startup messages + '--no-dereference', -- don't follow symlinks + '--monitor', -- keep listening for events forever '--recursive', - '--latency=' .. tostring(latency), - '--exclude', - '/.git/', + '--event', + 'create', + '--event', + 'delete', + '--event', + 'modify', + '--event', + 'move', + string.format('@%s/.git', path), -- ignore git directory path, }, { stderr = function(err, data) @@ -292,11 +308,11 @@ function M.fswatch(path, opts, callback) if data and #vim.trim(data) > 0 then vim.schedule(function() - if vim.fn.has('linux') == 1 and vim.startswith(data, 'Event queue overflow') then - data = 'inotify(7) limit reached, see :h fswatch-limitations for more info.' + if vim.fn.has('linux') == 1 and vim.startswith(data, 'Failed to watch') then + data = 'inotify(7) limit reached, see :h inotify-limitations for more info.' end - vim.notify('fswatch: ' .. data, vim.log.levels.ERROR) + vim.notify('inotify: ' .. data, vim.log.levels.ERROR) end) end end, @@ -306,7 +322,7 @@ function M.fswatch(path, opts, callback) end for line in vim.gsplit(data or '', '\n', { plain = true, trimempty = true }) do - fswatch_output_handler(line, opts, callback) + on_inotifywait_output(line, opts, callback) end end, -- --latency is locale dependent but tostring() isn't and will always have '.' as decimal point. diff --git a/runtime/lua/vim/deprecated/health.lua b/runtime/lua/vim/deprecated/health.lua index 0f6b1f578c..eed889d90a 100644 --- a/runtime/lua/vim/deprecated/health.lua +++ b/runtime/lua/vim/deprecated/health.lua @@ -1,7 +1,7 @@ local M = {} local health = vim.health -local deprecated = {} +local deprecated = {} ---@type [string, table, string][] function M.check() if next(deprecated) == nil then diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index 348204abb7..ef00a1fa51 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -42,7 +42,7 @@ local M = {} --- --- @field namespace? integer ---- Each of the configuration options below accepts one of the following: +--- Many of the configuration options below accept one of the following: --- - `false`: Disable this feature --- - `true`: Enable this feature, use default settings. --- - `table`: Enable this feature with overrides. Use an empty table to use default values. @@ -78,6 +78,9 @@ local M = {} --- - {reverse}? (boolean) Reverse sort order --- (default: `false`) --- @field severity_sort? boolean|{reverse?:boolean} +--- +--- Default values for |vim.diagnostic.jump()|. See |vim.diagnostic.Opts.Jump|. +--- @field jump? vim.diagnostic.Opts.Jump --- @class (private) vim.diagnostic.OptsResolved --- @field float vim.diagnostic.Opts.Float @@ -105,7 +108,7 @@ local M = {} --- If {scope} is "line" or "cursor", use this position rather than the cursor --- position. If a number, interpreted as a line number; otherwise, a --- (row, col) tuple. ---- @field pos? integer|{[1]:integer,[2]:integer} +--- @field pos? integer|[integer,integer] --- --- Sort diagnostics by severity. --- Overrides the setting from |vim.diagnostic.config()|. @@ -119,7 +122,7 @@ local M = {} --- String to use as the header for the floating window. If a table, it is --- interpreted as a `[text, hl_group]` tuple. --- Overrides the setting from |vim.diagnostic.config()|. ---- @field header? string|{[1]:string,[2]:any} +--- @field header? string|[string,any] --- --- Include the diagnostic source in the message. --- Use "if_many" to only show sources if there is more than one source of @@ -200,7 +203,7 @@ local M = {} --- @field hl_mode? 'replace'|'combine'|'blend' --- --- See |nvim_buf_set_extmark()|. ---- @field virt_text? {[1]:string,[2]:any}[] +--- @field virt_text? [string,any][] --- --- See |nvim_buf_set_extmark()|. --- @field virt_text_pos? 'eol'|'overlay'|'right_align'|'inline' @@ -241,6 +244,22 @@ local M = {} --- whole line the sign is placed in. --- @field linehl? table<vim.diagnostic.Severity,string> +--- @class vim.diagnostic.Opts.Jump +--- +--- Default value of the {float} parameter of |vim.diagnostic.jump()|. +--- (default: false) +--- @field float? boolean|vim.diagnostic.Opts.Float +--- +--- Default value of the {wrap} parameter of |vim.diagnostic.jump()|. +--- (default: true) +--- @field wrap? boolean +--- +--- Default value of the {severity} parameter of |vim.diagnostic.jump()|. +--- @field severity? vim.diagnostic.SeverityFilter +--- +--- Default value of the {_highest} parameter of |vim.diagnostic.jump()|. +--- @field package _highest? boolean + -- TODO: inherit from `vim.diagnostic.Opts`, implement its fields. --- Optional filters |kwargs|, or `nil` for all. --- @class vim.diagnostic.Filter @@ -284,6 +303,13 @@ local global_diagnostic_options = { float = true, update_in_insert = false, severity_sort = false, + jump = { + -- Do not show floating window + float = false, + + -- Wrap around buffer + wrap = true, + }, } --- @class (private) vim.diagnostic.Handler @@ -835,21 +861,36 @@ local function filter_highest(diagnostics) end end ---- @param position {[1]: integer, [2]: integer} --- @param search_forward boolean ---- @param bufnr integer ---- @param opts vim.diagnostic.GotoOpts ---- @param namespace integer[]|integer +--- @param opts vim.diagnostic.JumpOpts? --- @return vim.Diagnostic? -local function next_diagnostic(position, search_forward, bufnr, opts, namespace) +local function next_diagnostic(search_forward, opts) + opts = opts or {} + + -- Support deprecated win_id alias + if opts.win_id then + vim.deprecate('opts.win_id', 'opts.winid', '0.13') + opts.winid = opts.win_id + opts.win_id = nil + end + + -- Support deprecated cursor_position alias + if opts.cursor_position then + vim.deprecate('opts.cursor_position', 'opts.pos', '0.13') + opts.pos = opts.cursor_position + opts.cursor_position = nil + end + + local winid = opts.winid or api.nvim_get_current_win() + local bufnr = api.nvim_win_get_buf(winid) + local position = opts.pos or api.nvim_win_get_cursor(winid) + + -- Adjust row to be 0-indexed position[1] = position[1] - 1 - bufnr = get_bufnr(bufnr) - local wrap = if_nil(opts.wrap, true) - local get_opts = vim.deepcopy(opts) - get_opts.namespace = get_opts.namespace or namespace + local wrap = if_nil(opts.wrap, true) - local diagnostics = get_diagnostics(bufnr, get_opts, true) + local diagnostics = get_diagnostics(bufnr, opts, true) if opts._highest then filter_highest(diagnostics) @@ -902,32 +943,40 @@ local function next_diagnostic(position, search_forward, bufnr, opts, namespace) end end ---- @param opts vim.diagnostic.GotoOpts? ---- @param pos {[1]:integer,[2]:integer}|false -local function diagnostic_move_pos(opts, pos) - opts = opts or {} - - local float = if_nil(opts.float, true) - local win_id = opts.win_id or api.nvim_get_current_win() - - if not pos then +--- Move the cursor to the given diagnostic. +--- +--- @param diagnostic vim.Diagnostic? +--- @param opts vim.diagnostic.JumpOpts? +local function goto_diagnostic(diagnostic, opts) + if not diagnostic then api.nvim_echo({ { 'No more valid diagnostics to move to', 'WarningMsg' } }, true, {}) return end - api.nvim_win_call(win_id, function() + opts = opts or {} + + -- Support deprecated win_id alias + if opts.win_id then + vim.deprecate('opts.win_id', 'opts.winid', '0.13') + opts.winid = opts.win_id + opts.win_id = nil + end + + local winid = opts.winid or api.nvim_get_current_win() + + vim._with({ win = winid }, function() -- Save position in the window's jumplist vim.cmd("normal! m'") - api.nvim_win_set_cursor(win_id, { pos[1] + 1, pos[2] }) + api.nvim_win_set_cursor(winid, { diagnostic.lnum + 1, diagnostic.col }) -- Open folds under the cursor vim.cmd('normal! zv') end) - if float then - local float_opts = type(float) == 'table' and float or {} + if opts.float then + local float_opts = type(opts.float) == 'table' and opts.float or {} vim.schedule(function() M.open_float(vim.tbl_extend('keep', float_opts, { - bufnr = api.nvim_win_get_buf(win_id), + bufnr = api.nvim_win_get_buf(winid), scope = 'cursor', focus = false, })) @@ -1114,24 +1163,24 @@ end --- Get the previous diagnostic closest to the cursor position. --- ----@param opts? vim.diagnostic.GotoOpts +---@param opts? vim.diagnostic.JumpOpts ---@return vim.Diagnostic? : Previous diagnostic function M.get_prev(opts) - opts = opts or {} - - local win_id = opts.win_id or api.nvim_get_current_win() - local bufnr = api.nvim_win_get_buf(win_id) - local cursor_position = opts.cursor_position or api.nvim_win_get_cursor(win_id) - - return next_diagnostic(cursor_position, false, bufnr, opts, opts.namespace) + return next_diagnostic(false, opts) end --- Return the position of the previous diagnostic in the current buffer. --- ----@param opts? vim.diagnostic.GotoOpts +---@param opts? vim.diagnostic.JumpOpts ---@return table|false: Previous diagnostic position as a `(row, col)` tuple --- or `false` if there is no prior diagnostic. +---@deprecated function M.get_prev_pos(opts) + vim.deprecate( + 'vim.diagnostic.get_prev_pos()', + 'access the lnum and col fields from get_prev() instead', + '0.13' + ) local prev = M.get_prev(opts) if not prev then return false @@ -1141,31 +1190,35 @@ function M.get_prev_pos(opts) end --- Move to the previous diagnostic in the current buffer. ----@param opts? vim.diagnostic.GotoOpts +---@param opts? vim.diagnostic.JumpOpts +---@deprecated function M.goto_prev(opts) - return diagnostic_move_pos(opts, M.get_prev_pos(opts)) + vim.deprecate('vim.diagnostic.goto_prev()', 'vim.diagnostic.jump()', '0.13') + opts = opts or {} + opts.float = if_nil(opts.float, true) + goto_diagnostic(M.get_prev(opts), opts) end --- Get the next diagnostic closest to the cursor position. --- ----@param opts? vim.diagnostic.GotoOpts +---@param opts? vim.diagnostic.JumpOpts ---@return vim.Diagnostic? : Next diagnostic function M.get_next(opts) - opts = opts or {} - - local win_id = opts.win_id or api.nvim_get_current_win() - local bufnr = api.nvim_win_get_buf(win_id) - local cursor_position = opts.cursor_position or api.nvim_win_get_cursor(win_id) - - return next_diagnostic(cursor_position, true, bufnr, opts, opts.namespace) + return next_diagnostic(true, opts) end --- Return the position of the next diagnostic in the current buffer. --- ----@param opts? vim.diagnostic.GotoOpts +---@param opts? vim.diagnostic.JumpOpts ---@return table|false : Next diagnostic position as a `(row, col)` tuple or false if no next --- diagnostic. +---@deprecated function M.get_next_pos(opts) + vim.deprecate( + 'vim.diagnostic.get_next_pos()', + 'access the lnum and col fields from get_next() instead', + '0.13' + ) local next = M.get_next(opts) if not next then return false @@ -1186,13 +1239,23 @@ end --- See |diagnostic-severity|. --- @field severity? vim.diagnostic.SeverityFilter ---- Configuration table with the following keys: ---- @class vim.diagnostic.GotoOpts : vim.diagnostic.GetOpts +--- Configuration table with the keys listed below. Some parameters can have their default values +--- changed with |vim.diagnostic.config()|. +--- @class vim.diagnostic.JumpOpts : vim.diagnostic.GetOpts +--- +--- The diagnostic to jump to. Mutually exclusive with {count}, {namespace}, +--- and {severity}. +--- @field diagnostic? vim.Diagnostic --- ---- Cursor position as a `(row, col)` tuple. ---- See |nvim_win_get_cursor()|. ---- (default: current cursor position) ---- @field cursor_position? {[1]:integer,[2]:integer} +--- The number of diagnostics to move by, starting from {pos}. A positive +--- integer moves forward by {count} diagnostics, while a negative integer moves +--- backward by {count} diagnostics. Mutually exclusive with {diagnostic}. +--- @field count? integer +--- +--- Cursor position as a `(row, col)` tuple. See |nvim_win_get_cursor()|. Used +--- to find the nearest diagnostic when {count} is used. Only used when {count} +--- is non-nil. Default is the current cursor position. +--- @field pos? [integer,integer] --- --- Whether to loop around file or not. Similar to 'wrapscan'. --- (default: `true`) @@ -1209,18 +1272,78 @@ end --- If a table, pass the table as the {opts} parameter to |vim.diagnostic.open_float()|. --- Unless overridden, the float will show diagnostics at the new cursor --- position (as if "cursor" were passed to the "scope" option). ---- (default: `true`) +--- (default: `false`) --- @field float? boolean|vim.diagnostic.Opts.Float --- --- Window ID --- (default: `0`) ---- @field win_id? integer +--- @field winid? integer + +--- Move to a diagnostic. +--- +--- @param opts vim.diagnostic.JumpOpts +--- @return vim.Diagnostic? # The diagnostic that was moved to. +function M.jump(opts) + vim.validate('opts', opts, 'table') + + -- One of "diagnostic" or "count" must be provided + assert( + opts.diagnostic or opts.count, + 'One of "diagnostic" or "count" must be specified in the options to vim.diagnostic.jump()' + ) + + -- Apply configuration options from vim.diagnostic.config() + opts = vim.tbl_deep_extend('keep', opts, global_diagnostic_options.jump) + + if opts.diagnostic then + goto_diagnostic(opts.diagnostic, opts) + return opts.diagnostic + end + + local count = opts.count + if count == 0 then + return nil + end + + -- Support deprecated cursor_position alias + if opts.cursor_position then + vim.deprecate('opts.cursor_position', 'opts.pos', '0.13') + opts.pos = opts.cursor_position + opts.cursor_position = nil + end + + local diag = nil + while count ~= 0 do + local next = next_diagnostic(count > 0, opts) + if not next then + break + end + + -- Update cursor position + opts.pos = { next.lnum + 1, next.col } + + if count > 0 then + count = count - 1 + else + count = count + 1 + end + diag = next + end + + goto_diagnostic(diag, opts) + + return diag +end --- Move to the next diagnostic. --- ----@param opts? vim.diagnostic.GotoOpts +---@param opts? vim.diagnostic.JumpOpts +---@deprecated function M.goto_next(opts) - diagnostic_move_pos(opts, M.get_next_pos(opts)) + vim.deprecate('vim.diagnostic.goto_next()', 'vim.diagnostic.jump()', '0.13') + opts = opts or {} + opts.float = if_nil(opts.float, true) + goto_diagnostic(M.get_next(opts), opts) end M.handlers.signs = { @@ -1239,6 +1362,10 @@ M.handlers.signs = { bufnr = get_bufnr(bufnr) opts = opts or {} + if not api.nvim_buf_is_loaded(bufnr) then + return + end + if opts.signs and opts.signs.severity then diagnostics = filter_by_severity(opts.signs.severity, diagnostics) end @@ -1321,8 +1448,10 @@ M.handlers.signs = { local numhl = opts.signs.numhl or {} local linehl = opts.signs.linehl or {} + local line_count = api.nvim_buf_line_count(bufnr) + for _, diagnostic in ipairs(diagnostics) do - if api.nvim_buf_is_loaded(diagnostic.bufnr) then + if diagnostic.lnum <= line_count then api.nvim_buf_set_extmark(bufnr, ns.user_data.sign_ns, diagnostic.lnum, 0, { sign_text = text[diagnostic.severity] or text[M.severity[diagnostic.severity]] or 'U', sign_hl_group = sign_highlight_map[diagnostic.severity], @@ -1688,7 +1817,7 @@ end --- ---@param opts vim.diagnostic.Opts.Float? ---@return integer? float_bufnr ----@return integer? win_id +---@return integer? winid function M.open_float(opts, ...) -- Support old (bufnr, opts) signature local bufnr --- @type integer? @@ -1739,16 +1868,19 @@ function M.open_float(opts, ...) if scope == 'line' then --- @param d vim.Diagnostic diagnostics = vim.tbl_filter(function(d) - return lnum >= d.lnum and lnum <= d.end_lnum + return lnum >= d.lnum + and lnum <= d.end_lnum + and (d.lnum == d.end_lnum or lnum ~= d.end_lnum or d.end_col ~= 0) end, diagnostics) elseif scope == 'cursor' then - -- LSP servers can send diagnostics with `end_col` past the length of the line + -- If `col` is past the end of the line, show if the cursor is on the last char in the line local line_length = #api.nvim_buf_get_lines(bufnr, lnum, lnum + 1, true)[1] --- @param d vim.Diagnostic diagnostics = vim.tbl_filter(function(d) - return d.lnum == lnum - and math.min(d.col, line_length - 1) <= col - and (d.end_col >= col or d.end_lnum > lnum) + return lnum >= d.lnum + and lnum <= d.end_lnum + and (lnum ~= d.lnum or col >= math.min(d.col, line_length - 1)) + and ((d.lnum == d.end_lnum and d.col == d.end_col) or lnum ~= d.end_lnum or col < d.end_col) end, diagnostics) end @@ -1946,7 +2078,7 @@ end --- @field title? string --- --- See |diagnostic-severity|. ---- @field severity? vim.diagnostic.Severity +--- @field severity? vim.diagnostic.SeverityFilter --- Add all diagnostics to the quickfix list. --- @@ -1974,7 +2106,7 @@ end --- @field title? string --- --- See |diagnostic-severity|. ---- @field severity? vim.diagnostic.Severity +--- @field severity? vim.diagnostic.SeverityFilter --- Add buffer diagnostics to the location list. --- diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index d1fdd0aa16..d3910e26eb 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -4,12 +4,13 @@ local fn = vim.fn local M = {} --- @alias vim.filetype.mapfn fun(path:string,bufnr:integer, ...):string?, fun(b:integer)? ---- @alias vim.filetype.maptbl {[1]:string|vim.filetype.mapfn, [2]:{priority:integer}} +--- @alias vim.filetype.mapopts { parent: string, priority: number } +--- @alias vim.filetype.maptbl [string|vim.filetype.mapfn, vim.filetype.mapopts] --- @alias vim.filetype.mapping.value string|vim.filetype.mapfn|vim.filetype.maptbl --- @alias vim.filetype.mapping table<string,vim.filetype.mapping.value> --- @param ft string|vim.filetype.mapfn ---- @param opts? {priority:integer} +--- @param opts? vim.filetype.mapopts --- @return vim.filetype.maptbl local function starsetf(ft, opts) return { @@ -26,6 +27,9 @@ local function starsetf(ft, opts) end end, { + -- Allow setting "parent" to be reused in closures, but don't have default as it will be + -- assigned later from grouping + parent = opts and opts.parent, -- Starset matches should have lowest priority by default priority = (opts and opts.priority) or -math.huge, }, @@ -144,6 +148,9 @@ end local function detect_noext(path, bufnr) local root = fn.fnamemodify(path, ':r') + if root == path then + return + end return M.match({ buf = bufnr, filename = root }) end @@ -170,9 +177,15 @@ end -- luacheck: push no unused args -- luacheck: push ignore 122 --- Filetypes based on file extension +-- Filetype detection logic is encoded in three tables: +-- 1. `extension` for literal extension lookup +-- 2. `filename` for literal full path or basename lookup; +-- 3. `pattern` for matching filenames or paths against Lua patterns, +-- optimized for fast lookup. +-- See `:h dev-vimpatch-filetype` for guidance when porting Vim filetype patches. + ---@diagnostic disable: unused-local ---- @type vim.filetype.mapping +---@type vim.filetype.mapping local extension = { -- BEGIN EXTENSION ['8th'] = '8th', @@ -190,6 +203,7 @@ local extension = { aidl = 'aidl', aml = 'aml', run = 'ampl', + g4 = 'antlr4', scpt = 'applescript', ino = 'arduino', pde = 'arduino', @@ -203,12 +217,17 @@ local extension = { return 'aspvbs' end, asm = detect.asm, + s = detect.asm, + S = detect.asm, + a = detect.asm, + A = detect.asm, lst = detect.asm, mac = detect.asm, asn1 = 'asn', asn = 'asn', asp = detect.asp, astro = 'astro', + asy = 'asy', atl = 'atlas', as = 'atlas', zed = 'authzed', @@ -232,6 +251,7 @@ local extension = { db = detect.bindzone, bicep = 'bicep', bicepparam = 'bicep', + zone = 'bindzone', bb = 'bitbake', bbappend = 'bitbake', bbclass = 'bitbake', @@ -257,10 +277,14 @@ local extension = { cdc = 'cdc', cdl = 'cdl', toc = detect_line1('\\contentsline', 'tex', 'cdrtoc'), + cedar = 'cedar', cfc = 'cf', cfm = 'cf', cfi = 'cf', hgrc = 'cfg', + cfg = detect.cfg, + Cfg = detect.cfg, + CFG = detect.cfg, chf = 'ch', chai = 'chaiscript', ch = detect.change, @@ -281,7 +305,6 @@ local extension = { cook = 'cook', cmake = 'cmake', cmod = 'cmod', - lib = 'cobol', cob = 'cobol', cbl = 'cobol', atg = 'coco', @@ -344,6 +367,9 @@ local extension = { dart = 'dart', drt = 'dart', ds = 'datascript', + dat = detect.dat, + Dat = detect.dat, + DAT = detect.dat, dcd = 'dcd', decl = detect.decl, dec = detect.decl, @@ -366,6 +392,9 @@ local extension = { gv = 'dot', drac = 'dracula', drc = 'dracula', + lvs = 'dracula', + lpe = 'dracula', + dsp = detect.dsp, dtd = 'dtd', d = detect.dtrace, dts = 'dts', @@ -417,6 +446,7 @@ local extension = { fal = 'falcon', fan = 'fan', fwt = 'fan', + lib = 'faust', fnl = 'fennel', m4gl = 'fgl', ['4gl'] = 'fgl', @@ -468,8 +498,21 @@ local extension = { gmi = 'gemtext', gemini = 'gemtext', gift = 'gift', + prettierignore = 'gitignore', gleam = 'gleam', + vert = 'glsl', + tesc = 'glsl', + tese = 'glsl', glsl = 'glsl', + geom = 'glsl', + frag = 'glsl', + comp = 'glsl', + rgen = 'glsl', + rmiss = 'glsl', + rchit = 'glsl', + rahit = 'glsl', + rint = 'glsl', + rcall = 'glsl', gn = 'gn', gni = 'gn', gnuplot = 'gnuplot', @@ -535,6 +578,7 @@ local extension = { stm = detect.html, htt = 'httest', htb = 'httest', + http = 'http', hurl = 'hurl', hw = detect.hw, module = detect.hw, @@ -572,6 +616,7 @@ local extension = { jsx = 'javascriptreact', clp = 'jess', jgr = 'jgraph', + jinja = 'jinja', jjdescription = 'jj', j73 = 'jovial', jov = 'jovial', @@ -582,6 +627,7 @@ local extension = { json = 'json', jsonp = 'json', geojson = 'json', + mcmeta = 'json', webmanifest = 'json', ipynb = 'json', ['jupyterlab-settings'] = 'json', @@ -606,6 +652,9 @@ local extension = { kts = 'kotlin', kt = 'kotlin', ktm = 'kotlin', + sub = 'krl', + Sub = 'krl', + SUB = 'krl', ks = 'kscript', k = 'kwt', ACE = 'lace', @@ -639,6 +688,9 @@ local extension = { lt = 'lite', lite = 'lite', livemd = 'livebook', + log = detect.log, + Log = detect.log, + LOG = detect.log, lgt = 'logtalk', lotos = 'lotos', lot = detect_line1('\\contentsline', 'tex', 'lotos'), @@ -664,9 +716,8 @@ local extension = { return not (path:find('html%.m4$') or path:find('fvwm2rc')) and 'm4' or nil end, eml = 'mail', - mk = 'make', - mak = 'make', - dsp = 'make', + mk = detect.make, + mak = detect.make, page = 'mallard', map = 'map', mws = 'maple', @@ -679,7 +730,6 @@ local extension = { markdown = detect.markdown, mdown = detect.markdown, mhtml = 'mason', - comp = 'mason', mason = 'mason', master = 'master', mas = 'master', @@ -689,6 +739,8 @@ local extension = { dm3 = 'maxima', dmt = 'maxima', wxm = 'maxima', + mw = 'mediawiki', + wiki = 'mediawiki', mel = 'mel', mmd = 'mermaid', mmdc = 'mermaid', @@ -702,9 +754,17 @@ local extension = { mixal = 'mix', mm = detect.mm, nb = 'mma', + wl = 'mma', mmp = 'mmp', mms = detect.mms, + mod = detect.mod, + Mod = detect.mod, + MOD = detect.mod, DEF = 'modula2', + m3 = 'modula3', + i3 = 'modula3', + mg = 'modula3', + ig = 'modula3', lm3 = 'modula3', mojo = 'mojo', ['🔥'] = 'mojo', -- 🙄 @@ -729,6 +789,14 @@ local extension = { n1ql = 'n1ql', nql = 'n1ql', nanorc = 'nanorc', + NSA = 'natural', + NSC = 'natural', + NSG = 'natural', + NSL = 'natural', + NSM = 'natural', + NSN = 'natural', + NSP = 'natural', + NSS = 'natural', ncf = 'ncf', nginx = 'nginx', nim = 'nim', @@ -738,6 +806,15 @@ local extension = { nix = 'nix', norg = 'norg', nqc = 'nqc', + ['1'] = detect.nroff, + ['2'] = detect.nroff, + ['3'] = detect.nroff, + ['4'] = detect.nroff, + ['5'] = detect.nroff, + ['6'] = detect.nroff, + ['7'] = detect.nroff, + ['8'] = detect.nroff, + ['9'] = detect.nroff, roff = 'nroff', tmac = 'nroff', man = 'nroff', @@ -769,6 +846,14 @@ local extension = { ['or'] = 'openroad', scad = 'openscad', ovpn = 'openvpn', + opl = 'opl', + opL = 'opl', + oPl = 'opl', + oPL = 'opl', + Opl = 'opl', + OpL = 'opl', + OPl = 'opl', + OPL = 'opl', ora = 'ora', org = 'org', org_archive = 'org', @@ -800,6 +885,16 @@ local extension = { ctp = 'php', php = 'php', phpt = 'php', + php0 = 'php', + php1 = 'php', + php2 = 'php', + php3 = 'php', + php4 = 'php', + php5 = 'php', + php6 = 'php', + php7 = 'php', + php8 = 'php', + php9 = 'php', phtml = 'php', theme = 'php', pike = 'pike', @@ -832,6 +927,9 @@ local extension = { it = 'ppwiz', ih = 'ppwiz', action = 'privoxy', + prg = detect.prg, + Prg = detect.prg, + PRG = detect.prg, pc = 'proc', pdb = 'prolog', pml = 'promela', @@ -873,6 +971,19 @@ local extension = { t6 = 'raku', p6 = 'raku', raml = 'raml', + sysx = 'rapid', + sysX = 'rapid', + Sysx = 'rapid', + SysX = 'rapid', + SYSX = 'rapid', + SYSx = 'rapid', + modx = 'rapid', + modX = 'rapid', + Modx = 'rapid', + ModX = 'rapid', + MODX = 'rapid', + MODx = 'rapid', + rasi = 'rasi', rbs = 'rbs', rego = 'rego', rem = 'remind', @@ -929,6 +1040,7 @@ local extension = { rake = 'ruby', rs = 'rust', sage = 'sage', + sls = 'salt', sas = 'sas', sass = 'sass', sa = 'sather', @@ -952,6 +1064,7 @@ local extension = { ebuild = detect.bash, eclass = detect.bash, env = detect.sh, + envrc = detect.sh, ksh = detect.ksh, sh = detect.sh, mdd = 'sh', @@ -984,6 +1097,7 @@ local extension = { smt = 'smith', smithy = 'smithy', sml = 'sml', + smk = 'snakemake', spt = 'snobol4', sno = 'snobol4', sln = 'solution', @@ -1006,6 +1120,9 @@ local extension = { sqi = 'sqr', sqr = 'sqr', nut = 'squirrel', + src = detect.src, + Src = detect.src, + SRC = detect.src, s28 = 'srec', s37 = 'srec', srec = 'srec', @@ -1030,8 +1147,12 @@ local extension = { svelte = 'svelte', svg = 'svg', swift = 'swift', + swiftinterface = 'swift', swig = 'swig', swg = 'swig', + sys = detect.sys, + Sys = detect.sys, + SYS = detect.sys, svh = 'systemverilog', sv = 'systemverilog', cmm = 'trace32', @@ -1060,6 +1181,7 @@ local extension = { nls = 'tex', thm = 'tex', eps_tex = 'tex', + pdf_tex = 'tex', pygtex = 'tex', pygstyle = 'tex', clo = 'tex', @@ -1153,6 +1275,8 @@ local extension = { wbt = 'winbatch', wit = 'wit', wml = 'wml', + wsf = 'wsh', + wsc = 'wsh', wsml = 'wsml', ad = 'xdefaults', xhtml = 'xhtml', @@ -1206,6 +1330,8 @@ local extension = { z8a = 'z8a', zig = 'zig', zon = 'zig', + ziggy = 'ziggy', + ['ziggy-schema'] = 'ziggy_schema', zu = 'zimbu', zut = 'zimbutempl', zs = 'zserio', @@ -1261,8 +1387,7 @@ local extension = { ['dpkg-new'] = detect_noext, ['in'] = function(path, bufnr) if vim.fs.basename(path) ~= 'configure.in' then - local root = fn.fnamemodify(path, ':r') - return M.match({ buf = bufnr, filename = root }) + return detect_noext(path, bufnr) end end, new = detect_noext, @@ -1275,7 +1400,7 @@ local extension = { -- END EXTENSION } ---- @type vim.filetype.mapping +---@type vim.filetype.mapping local filename = { -- BEGIN FILENAME ['a2psrc'] = 'a2ps', @@ -1290,7 +1415,17 @@ local filename = { ['/.aptitude/config'] = 'aptconf', ['=tagging-method'] = 'arch', ['.arch-inventory'] = 'arch', + ['makefile.am'] = 'automake', + ['Makefile.am'] = 'automake', ['GNUmakefile.am'] = 'automake', + ['.bash_aliases'] = detect.bash, + ['.bash-aliases'] = detect.bash, + ['.bash_history'] = detect.bash, + ['.bash-history'] = detect.bash, + ['.bash_logout'] = detect.bash, + ['.bash-logout'] = detect.bash, + ['.bash_profile'] = detect.bash, + ['.bash-profile'] = detect.bash, ['named.root'] = 'bindzone', WORKSPACE = 'bzl', ['WORKSPACE.bzlmod'] = 'bzl', @@ -1373,6 +1508,7 @@ local filename = { jbuild = 'dune', ['dune-workspace'] = 'dune', ['dune-project'] = 'dune', + ['dune-file'] = 'dune', Earthfile = 'earthfile', ['.editorconfig'] = 'editorconfig', ['elinks.conf'] = 'elinks', @@ -1409,6 +1545,7 @@ local filename = { gnashpluginrc = 'gnash', gnashrc = 'gnash', ['.gnuplot_history'] = 'gnuplot', + ['goaccess.conf'] = 'goaccess', ['go.sum'] = 'gosum', ['go.work.sum'] = 'gosum', ['go.work'] = 'gowork', @@ -1445,11 +1582,15 @@ local filename = { ['ipf.conf'] = 'ipfilter', ['ipf6.conf'] = 'ipfilter', ['ipf.rules'] = 'ipfilter', + ['.bun_repl_history'] = 'javascript', ['.node_repl_history'] = 'javascript', + ['deno_history.txt'] = 'javascript', ['Pipfile.lock'] = 'json', ['.firebaserc'] = 'json', ['.prettierrc'] = 'json', ['.stylelintrc'] = 'json', + ['.lintstagedrc'] = 'json', + ['deno.lock'] = 'json', ['flake.lock'] = 'json', ['.babelrc'] = 'jsonc', ['.eslintrc'] = 'jsonc', @@ -1461,9 +1602,14 @@ local filename = { ['.swrc'] = 'jsonc', ['.vsconfig'] = 'jsonc', ['.justfile'] = 'just', + ['justfile'] = 'just', + ['Justfile'] = 'just', Kconfig = 'kconfig', ['Kconfig.debug'] = 'kconfig', ['Config.in'] = 'kconfig', + ['ldaprc'] = 'ldapconf', + ['.ldaprc'] = 'ldapconf', + ['ldap.conf'] = 'ldapconf', ['lftp.conf'] = 'lftp', ['.lftprc'] = 'lftp', ['/.libao'] = 'libao', @@ -1509,6 +1655,8 @@ local filename = { mrxvtrc = 'mrxvtrc', ['.mrxvtrc'] = 'mrxvtrc', ['.msmtprc'] = 'msmtp', + ['Muttngrc'] = 'muttrc', + ['Muttrc'] = 'muttrc', ['.mysql_history'] = 'mysql', ['/etc/nanorc'] = 'nanorc', Neomuttrc = 'neomuttrc', @@ -1520,6 +1668,7 @@ local filename = { ['octave.conf'] = 'octave', ['.ondirrc'] = 'ondir', opam = 'opam', + ['opam.locked'] = 'opam', ['pacman.log'] = 'pacmanlog', ['/etc/pam.conf'] = 'pamconf', ['pam_env.conf'] = 'pamenv', @@ -1532,6 +1681,9 @@ local filename = { ['/etc/shadow-'] = 'passwd', ['/etc/shadow'] = 'passwd', ['/etc/passwd.edit'] = 'passwd', + ['.gitolite.rc'] = 'perl', + ['gitolite.rc'] = 'perl', + ['example.gitolite.rc'] = 'perl', ['latexmkrc'] = 'perl', ['.latexmkrc'] = 'perl', ['pf.conf'] = 'pf', @@ -1587,6 +1739,10 @@ local filename = { irbrc = 'ruby', ['.irb_history'] = 'ruby', irb_history = 'ruby', + ['rakefile'] = 'ruby', + ['Rakefile'] = 'ruby', + ['rantfile'] = 'ruby', + ['Rantfile'] = 'ruby', Vagrantfile = 'ruby', ['smb.conf'] = 'samba', screenrc = 'screen', @@ -1597,6 +1753,8 @@ local filename = { ['/etc/serial.conf'] = 'setserial', ['/etc/udev/cdsymlinks.conf'] = 'sh', ['.ash_history'] = 'sh', + ['.devscripts'] = 'sh', + ['devscripts.conf'] = 'sh', ['makepkg.conf'] = 'sh', ['.makepkg.conf'] = 'sh', ['user-dirs.dirs'] = 'sh', @@ -1618,6 +1776,7 @@ local filename = { ['/etc/slp.spi'] = 'slpspi', ['.slrnrc'] = 'slrnrc', ['sendmail.cf'] = 'sm', + Snakefile = 'snakemake', ['.sqlite_history'] = 'sql', ['squid.conf'] = 'squid', ['ssh_config'] = 'sshconfig', @@ -1637,7 +1796,7 @@ local filename = { ['.xsdbcmdhistory'] = 'tcl', ['texmf.cnf'] = 'texmf', COPYING = 'text', - README = 'text', + README = detect_seq(detect.haredoc, 'text'), LICENSE = 'text', AUTHORS = 'text', tfrc = 'tf', @@ -1703,528 +1862,568 @@ local filename = { } -- Re-use closures as much as possible -local detect_apache = starsetf('apache') -local detect_muttrc = starsetf('muttrc') -local detect_neomuttrc = starsetf('neomuttrc') +local detect_apache_diretc = starsetf('apache', { parent = '/etc/' }) +local detect_apache_dotconf = starsetf('apache', { parent = '%.conf' }) +local detect_muttrc = starsetf('muttrc', { parent = 'utt' }) +local detect_neomuttrc = starsetf('neomuttrc', { parent = 'utt' }) +local detect_xkb = starsetf('xkb', { parent = '/usr/' }) ---- @type vim.filetype.mapping +---@type table<string,vim.filetype.mapping> local pattern = { -- BEGIN PATTERN - ['.*/etc/a2ps/.*%.cfg'] = 'a2ps', - ['.*/etc/a2ps%.cfg'] = 'a2ps', - ['.*/usr/share/alsa/alsa%.conf'] = 'alsaconf', - ['.*/etc/asound%.conf'] = 'alsaconf', - ['.*/etc/apache2/sites%-.*/.*%.com'] = 'apache', - ['.*/etc/httpd/.*%.conf'] = 'apache', - ['.*/etc/apache2/.*%.conf.*'] = detect_apache, - ['.*/etc/apache2/conf%..*/.*'] = detect_apache, - ['.*/etc/apache2/mods%-.*/.*'] = detect_apache, - ['.*/etc/apache2/sites%-.*/.*'] = detect_apache, - ['access%.conf.*'] = detect_apache, - ['apache%.conf.*'] = detect_apache, - ['apache2%.conf.*'] = detect_apache, - ['httpd%.conf.*'] = detect_apache, - ['srm%.conf.*'] = detect_apache, - ['.*/etc/httpd/conf%..*/.*'] = detect_apache, - ['.*/etc/httpd/conf%.d/.*%.conf.*'] = detect_apache, - ['.*/etc/httpd/mods%-.*/.*'] = detect_apache, - ['.*/etc/httpd/sites%-.*/.*'] = detect_apache, - ['.*/etc/proftpd/.*%.conf.*'] = starsetf('apachestyle'), - ['.*/etc/proftpd/conf%..*/.*'] = starsetf('apachestyle'), - ['proftpd%.conf.*'] = starsetf('apachestyle'), - ['.*asterisk/.*%.conf.*'] = starsetf('asterisk'), - ['.*asterisk.*/.*voicemail%.conf.*'] = starsetf('asteriskvm'), - ['.*/%.aptitude/config'] = 'aptconf', - ['.*%.[aA]'] = detect.asm, - ['.*%.[sS]'] = detect.asm, - ['[mM]akefile%.am'] = 'automake', - ['.*/bind/db%..*'] = starsetf('bindzone'), - ['.*/named/db%..*'] = starsetf('bindzone'), - ['.*/build/conf/.*%.conf'] = 'bitbake', - ['.*/meta/conf/.*%.conf'] = 'bitbake', - ['.*/meta%-.*/conf/.*%.conf'] = 'bitbake', - ['.*%.blade%.php'] = 'blade', - ['bzr_log%..*'] = 'bzr', - ['.*enlightenment/.*%.cfg'] = 'c', - ['.*/%.cabal/config'] = 'cabalconfig', - ['.*/cabal/config'] = 'cabalconfig', - ['cabal%.project%..*'] = starsetf('cabalproject'), - ['.*/%.calendar/.*'] = starsetf('calendar'), - ['.*/share/calendar/.*/calendar%..*'] = starsetf('calendar'), - ['.*/share/calendar/calendar%..*'] = starsetf('calendar'), - ['sgml%.catalog.*'] = starsetf('catalog'), - ['.*/etc/defaults/cdrdao'] = 'cdrdaoconf', - ['.*/etc/cdrdao%.conf'] = 'cdrdaoconf', - ['.*/etc/default/cdrdao'] = 'cdrdaoconf', - ['.*hgrc'] = 'cfg', - ['.*%.[Cc][Ff][Gg]'] = { - detect.cfg, - -- Decrease priority to avoid conflicts with more specific patterns - -- such as '.*/etc/a2ps/.*%.cfg', '.*enlightenment/.*%.cfg', etc. - { priority = -1 }, + ['/debian/'] = { + ['/debian/changelog$'] = 'debchangelog', + ['/debian/control$'] = 'debcontrol', + ['/debian/copyright$'] = 'debcopyright', + ['/debian/patches/'] = detect.dep3patch, + }, + ['/etc/'] = { + ['/etc/a2ps/.*%.cfg$'] = 'a2ps', + ['/etc/a2ps%.cfg$'] = 'a2ps', + ['/etc/asound%.conf$'] = 'alsaconf', + ['/etc/apache2/sites%-.*/.*%.com$'] = 'apache', + ['/etc/httpd/.*%.conf$'] = 'apache', + ['/etc/apache2/.*%.conf'] = detect_apache_diretc, + ['/etc/apache2/conf%..*/'] = detect_apache_diretc, + ['/etc/apache2/mods%-.*/'] = detect_apache_diretc, + ['/etc/apache2/sites%-.*/'] = detect_apache_diretc, + ['/etc/httpd/conf%..*/'] = detect_apache_diretc, + ['/etc/httpd/conf%.d/.*%.conf'] = detect_apache_diretc, + ['/etc/httpd/mods%-.*/'] = detect_apache_diretc, + ['/etc/httpd/sites%-.*/'] = detect_apache_diretc, + ['/etc/proftpd/.*%.conf'] = starsetf('apachestyle'), + ['/etc/proftpd/conf%..*/'] = starsetf('apachestyle'), + ['/etc/cdrdao%.conf$'] = 'cdrdaoconf', + ['/etc/default/cdrdao$'] = 'cdrdaoconf', + ['/etc/defaults/cdrdao$'] = 'cdrdaoconf', + ['/etc/translate%-shell$'] = 'clojure', + ['/etc/hostname%.'] = starsetf('config'), + ['/etc/cron%.d/'] = starsetf('crontab'), + ['/etc/apt/sources%.list%.d/.*%.sources$'] = 'deb822sources', + ['/etc/apt/sources%.list%.d/.*%.list$'] = 'debsources', + ['/etc/apt/sources%.list$'] = 'debsources', + ['/etc/DIR_COLORS$'] = 'dircolors', + ['/etc/dnsmasq%.conf$'] = 'dnsmasq', + ['/etc/dnsmasq%.d/'] = starsetf('dnsmasq'), + ['/etc/yum%.conf$'] = 'dosini', + ['/etc/yum%.repos%.d/'] = starsetf('dosini'), + ['/etc/gitconfig%.d/'] = starsetf('gitconfig'), + ['/etc/gitconfig$'] = 'gitconfig', + ['/etc/gitattributes$'] = 'gitattributes', + ['/etc/group$'] = 'group', + ['/etc/group%-$'] = 'group', + ['/etc/group%.edit$'] = 'group', + ['/etc/gshadow%-$'] = 'group', + ['/etc/gshadow%.edit$'] = 'group', + ['/etc/gshadow$'] = 'group', + ['/etc/grub%.conf$'] = 'grub', + ['/etc/host%.conf$'] = 'hostconf', + ['/etc/hosts%.allow$'] = 'hostsaccess', + ['/etc/hosts%.deny$'] = 'hostsaccess', + ['/etc/initng/.*/.*%.i$'] = 'initng', + ['/etc/libao%.conf$'] = 'libao', + ['/etc/.*limits%.conf$'] = 'limits', + ['/etc/.*limits%.d/.*%.conf$'] = 'limits', + ['/etc/limits$'] = 'limits', + ['/etc/logcheck/.*%.d.*/'] = starsetf('logcheck'), + ['/etc/login%.access$'] = 'loginaccess', + ['/etc/login%.defs$'] = 'logindefs', + ['/etc/aliases$'] = 'mailaliases', + ['/etc/mail/aliases$'] = 'mailaliases', + ['/etc/man%.conf$'] = 'manconf', + ['/etc/conf%.modules$'] = 'modconf', + ['/etc/modprobe%.'] = starsetf('modconf'), + ['/etc/modules%.conf$'] = 'modconf', + ['/etc/modules$'] = 'modconf', + ['/etc/modutils/'] = starsetf(function(path, bufnr) + if fn.executable(fn.expand(path)) ~= 1 then + return 'modconf' + end + end), + ['/etc/Muttrc%.d/'] = starsetf('muttrc'), + ['/etc/nanorc$'] = 'nanorc', + ['/etc/nginx/'] = 'nginx', + ['/etc/pam%.conf$'] = 'pamconf', + ['/etc/pam%.d/'] = starsetf('pamconf'), + ['/etc/passwd%-$'] = 'passwd', + ['/etc/shadow$'] = 'passwd', + ['/etc/shadow%.edit$'] = 'passwd', + ['/etc/passwd$'] = 'passwd', + ['/etc/passwd%.edit$'] = 'passwd', + ['/etc/shadow%-$'] = 'passwd', + ['/etc/pinforc$'] = 'pinfo', + ['/etc/protocols$'] = 'protocols', + ['/etc/sensors%.d/[^.]'] = starsetf('sensors'), + ['/etc/sensors%.conf$'] = 'sensors', + ['/etc/sensors3%.conf$'] = 'sensors', + ['/etc/services$'] = 'services', + ['/etc/serial%.conf$'] = 'setserial', + ['/etc/udev/cdsymlinks%.conf$'] = 'sh', + ['/etc/profile$'] = detect.sh, + ['/etc/slp%.conf$'] = 'slpconf', + ['/etc/slp%.reg$'] = 'slpreg', + ['/etc/slp%.spi$'] = 'slpspi', + ['/etc/sudoers%.d/'] = starsetf('sudoers'), + ['/etc/ssh/ssh_config%.d/.*%.conf$'] = 'sshconfig', + ['/etc/ssh/sshd_config%.d/.*%.conf$'] = 'sshdconfig', + ['/etc/sudoers$'] = 'sudoers', + ['/etc/sysctl%.conf$'] = 'sysctl', + ['/etc/sysctl%.d/.*%.conf$'] = 'sysctl', + ['/etc/systemd/.*%.conf%.d/.*%.conf$'] = 'systemd', + ['/etc/systemd/system/.*%.d/.*%.conf$'] = 'systemd', + ['/etc/systemd/system/.*%.d/%.#'] = 'systemd', + ['/etc/systemd/system/%.#'] = 'systemd', + ['/etc/config/'] = starsetf(detect.uci), + ['/etc/udev/udev%.conf$'] = 'udevconf', + ['/etc/udev/permissions%.d/.*%.permissions$'] = 'udevperm', + ['/etc/updatedb%.conf$'] = 'updatedb', + ['/etc/init/.*%.conf$'] = 'upstart', + ['/etc/init/.*%.override$'] = 'upstart', + ['/etc/xinetd%.conf$'] = 'xinetd', + ['/etc/xinetd%.d/'] = starsetf('xinetd'), + ['/etc/blkid%.tab%.old$'] = 'xml', + ['/etc/blkid%.tab$'] = 'xml', + ['/etc/xdg/menus/.*%.menu$'] = 'xml', + ['/etc/zprofile$'] = 'zsh', }, - ['[cC]hange[lL]og.*'] = starsetf(detect.changelog), - ['.*%.%.ch'] = 'chill', - ['.*/etc/translate%-shell'] = 'clojure', - ['.*%.cmake%.in'] = 'cmake', - -- */cmus/rc and */.cmus/rc - ['.*/%.?cmus/rc'] = 'cmusrc', - -- */cmus/*.theme and */.cmus/*.theme - ['.*/%.?cmus/.*%.theme'] = 'cmusrc', - ['.*/%.cmus/autosave'] = 'cmusrc', - ['.*/%.cmus/command%-history'] = 'cmusrc', - ['.*/etc/hostname%..*'] = starsetf('config'), - ['crontab%..*'] = starsetf('crontab'), - ['.*/etc/cron%.d/.*'] = starsetf('crontab'), - ['%.cshrc.*'] = detect.csh, - ['%.login.*'] = detect.csh, - ['cvs%d+'] = 'cvs', - ['.*%.[Dd][Aa][Tt]'] = detect.dat, - ['.*/debian/patches/.*'] = detect.dep3patch, - ['.*/etc/dnsmasq%.d/.*'] = starsetf('dnsmasq'), - ['Containerfile%..*'] = starsetf('dockerfile'), - ['Dockerfile%..*'] = starsetf('dockerfile'), - ['.*/etc/yum%.repos%.d/.*'] = starsetf('dosini'), - ['drac%..*'] = starsetf('dracula'), - ['.*/debian/changelog'] = 'debchangelog', - ['.*/debian/control'] = 'debcontrol', - ['.*/debian/copyright'] = 'debcopyright', - ['.*/etc/apt/sources%.list%.d/.*%.list'] = 'debsources', - ['.*/etc/apt/sources%.list'] = 'debsources', - ['.*/etc/apt/sources%.list%.d/.*%.sources'] = 'deb822sources', - ['.*%.directory'] = 'desktop', - ['.*%.desktop'] = 'desktop', - ['dictd.*%.conf'] = 'dictdconf', - ['.*/etc/DIR_COLORS'] = 'dircolors', - ['.*/etc/dnsmasq%.conf'] = 'dnsmasq', - ['php%.ini%-.*'] = 'dosini', - ['.*/%.aws/config'] = 'confini', - ['.*/%.aws/credentials'] = 'confini', - ['.*/etc/yum%.conf'] = 'dosini', - ['.*/lxqt/.*%.conf'] = 'dosini', - ['.*/screengrab/.*%.conf'] = 'dosini', - ['.*/bpython/config'] = 'dosini', - ['.*/mypy/config'] = 'dosini', - ['.*/flatpak/repo/config'] = 'dosini', - ['.*lvs'] = 'dracula', - ['.*lpe'] = 'dracula', - ['.*/dtrace/.*%.d'] = 'dtrace', - ['.*esmtprc'] = 'esmtprc', - ['.*Eterm/.*%.cfg'] = 'eterm', - ['.*s6.*/up'] = 'execline', - ['.*s6.*/down'] = 'execline', - ['.*s6.*/run'] = 'execline', - ['.*s6.*/finish'] = 'execline', - ['s6%-.*'] = 'execline', - ['[a-zA-Z0-9].*Dict'] = detect.foam, - ['[a-zA-Z0-9].*Dict%..*'] = detect.foam, - ['[a-zA-Z].*Properties'] = detect.foam, - ['[a-zA-Z].*Properties%..*'] = detect.foam, - ['.*Transport%..*'] = detect.foam, - ['.*/constant/g'] = detect.foam, - ['.*/0/.*'] = detect.foam, - ['.*/0%.orig/.*'] = detect.foam, - ['.*/%.fvwm/.*'] = starsetf('fvwm'), - ['.*fvwmrc.*'] = starsetf(detect.fvwm_v1), - ['.*fvwm95.*%.hook'] = starsetf(detect.fvwm_v1), - ['.*fvwm2rc.*'] = starsetf(detect.fvwm_v2), - ['.*/tmp/lltmp.*'] = starsetf('gedcom'), - ['.*/etc/gitconfig%.d/.*'] = starsetf('gitconfig'), - ['.*/gitolite%-admin/conf/.*'] = starsetf('gitolite'), - ['tmac%..*'] = starsetf('nroff'), - ['.*/%.gitconfig%.d/.*'] = starsetf('gitconfig'), - ['.*%.git/.*'] = { - detect.git, - -- Decrease priority to run after simple pattern checks - { priority = -1 }, + ['/log/'] = { + ['/log/auth%.crit$'] = 'messages', + ['/log/auth%.err$'] = 'messages', + ['/log/auth%.info$'] = 'messages', + ['/log/auth%.log$'] = 'messages', + ['/log/auth%.notice$'] = 'messages', + ['/log/auth%.warn$'] = 'messages', + ['/log/auth$'] = 'messages', + ['/log/cron%.crit$'] = 'messages', + ['/log/cron%.err$'] = 'messages', + ['/log/cron%.info$'] = 'messages', + ['/log/cron%.log$'] = 'messages', + ['/log/cron%.notice$'] = 'messages', + ['/log/cron%.warn$'] = 'messages', + ['/log/cron$'] = 'messages', + ['/log/daemon%.crit$'] = 'messages', + ['/log/daemon%.err$'] = 'messages', + ['/log/daemon%.info$'] = 'messages', + ['/log/daemon%.log$'] = 'messages', + ['/log/daemon%.notice$'] = 'messages', + ['/log/daemon%.warn$'] = 'messages', + ['/log/daemon$'] = 'messages', + ['/log/debug%.crit$'] = 'messages', + ['/log/debug%.err$'] = 'messages', + ['/log/debug%.info$'] = 'messages', + ['/log/debug%.log$'] = 'messages', + ['/log/debug%.notice$'] = 'messages', + ['/log/debug%.warn$'] = 'messages', + ['/log/debug$'] = 'messages', + ['/log/kern%.crit$'] = 'messages', + ['/log/kern%.err$'] = 'messages', + ['/log/kern%.info$'] = 'messages', + ['/log/kern%.log$'] = 'messages', + ['/log/kern%.notice$'] = 'messages', + ['/log/kern%.warn$'] = 'messages', + ['/log/kern$'] = 'messages', + ['/log/lpr%.crit$'] = 'messages', + ['/log/lpr%.err$'] = 'messages', + ['/log/lpr%.info$'] = 'messages', + ['/log/lpr%.log$'] = 'messages', + ['/log/lpr%.notice$'] = 'messages', + ['/log/lpr%.warn$'] = 'messages', + ['/log/lpr$'] = 'messages', + ['/log/mail%.crit$'] = 'messages', + ['/log/mail%.err$'] = 'messages', + ['/log/mail%.info$'] = 'messages', + ['/log/mail%.log$'] = 'messages', + ['/log/mail%.notice$'] = 'messages', + ['/log/mail%.warn$'] = 'messages', + ['/log/mail$'] = 'messages', + ['/log/messages%.crit$'] = 'messages', + ['/log/messages%.err$'] = 'messages', + ['/log/messages%.info$'] = 'messages', + ['/log/messages%.log$'] = 'messages', + ['/log/messages%.notice$'] = 'messages', + ['/log/messages%.warn$'] = 'messages', + ['/log/messages$'] = 'messages', + ['/log/news/news%.crit$'] = 'messages', + ['/log/news/news%.err$'] = 'messages', + ['/log/news/news%.info$'] = 'messages', + ['/log/news/news%.log$'] = 'messages', + ['/log/news/news%.notice$'] = 'messages', + ['/log/news/news%.warn$'] = 'messages', + ['/log/news/news$'] = 'messages', + ['/log/syslog%.crit$'] = 'messages', + ['/log/syslog%.err$'] = 'messages', + ['/log/syslog%.info$'] = 'messages', + ['/log/syslog%.log$'] = 'messages', + ['/log/syslog%.notice$'] = 'messages', + ['/log/syslog%.warn$'] = 'messages', + ['/log/syslog$'] = 'messages', + ['/log/user%.crit$'] = 'messages', + ['/log/user%.err$'] = 'messages', + ['/log/user%.info$'] = 'messages', + ['/log/user%.log$'] = 'messages', + ['/log/user%.notice$'] = 'messages', + ['/log/user%.warn$'] = 'messages', + ['/log/user$'] = 'messages', + }, + ['/systemd/'] = { + ['/%.config/systemd/user/%.#'] = 'systemd', + ['/%.config/systemd/user/.*%.d/%.#'] = 'systemd', + ['/%.config/systemd/user/.*%.d/.*%.conf$'] = 'systemd', + ['/systemd/.*%.automount$'] = 'systemd', + ['/systemd/.*%.dnssd$'] = 'systemd', + ['/systemd/.*%.link$'] = 'systemd', + ['/systemd/.*%.mount$'] = 'systemd', + ['/systemd/.*%.netdev$'] = 'systemd', + ['/systemd/.*%.network$'] = 'systemd', + ['/systemd/.*%.nspawn$'] = 'systemd', + ['/systemd/.*%.path$'] = 'systemd', + ['/systemd/.*%.service$'] = 'systemd', + ['/systemd/.*%.slice$'] = 'systemd', + ['/systemd/.*%.socket$'] = 'systemd', + ['/systemd/.*%.swap$'] = 'systemd', + ['/systemd/.*%.target$'] = 'systemd', + ['/systemd/.*%.timer$'] = 'systemd', + }, + ['/usr/'] = { + ['/usr/share/alsa/alsa%.conf$'] = 'alsaconf', + ['/usr/.*/gnupg/options%.skel$'] = 'gpg', + ['/usr/share/upstart/.*%.conf$'] = 'upstart', + ['/usr/share/upstart/.*%.override$'] = 'upstart', + ['/usr/share/X11/xkb/compat/'] = detect_xkb, + ['/usr/share/X11/xkb/geometry/'] = detect_xkb, + ['/usr/share/X11/xkb/keycodes/'] = detect_xkb, + ['/usr/share/X11/xkb/symbols/'] = detect_xkb, + ['/usr/share/X11/xkb/types/'] = detect_xkb, + }, + ['/var/'] = { + ['/var/backups/group%.bak$'] = 'group', + ['/var/backups/gshadow%.bak$'] = 'group', + ['/var/backups/passwd%.bak$'] = 'passwd', + ['/var/backups/shadow%.bak$'] = 'passwd', + }, + ['/conf'] = { + ['/%.aptitude/config$'] = 'aptconf', + ['/build/conf/.*%.conf$'] = 'bitbake', + ['/meta%-.*/conf/.*%.conf$'] = 'bitbake', + ['/meta/conf/.*%.conf$'] = 'bitbake', + ['/%.cabal/config$'] = 'cabalconfig', + ['/cabal/config$'] = 'cabalconfig', + ['/%.aws/config$'] = 'confini', + ['/bpython/config$'] = 'dosini', + ['/flatpak/repo/config$'] = 'dosini', + ['/mypy/config$'] = 'dosini', + ['^${HOME}/%.config/notmuch/.*/config$'] = 'dosini', + ['^${XDG_CONFIG_HOME}/notmuch/.*/config$'] = 'dosini', + ['^${XDG_CONFIG_HOME}/git/config$'] = 'gitconfig', + ['%.git/config%.worktree$'] = 'gitconfig', + ['%.git/config$'] = 'gitconfig', + ['%.git/modules/.*/config$'] = 'gitconfig', + ['%.git/modules/config$'] = 'gitconfig', + ['%.git/worktrees/.*/config%.worktree$'] = 'gitconfig', + ['/%.config/git/config$'] = 'gitconfig', + ['/gitolite%-admin/conf/'] = starsetf('gitolite'), + ['/%.i3/config$'] = 'i3config', + ['/i3/config$'] = 'i3config', + ['/supertux2/config$'] = 'lisp', + ['/%.mplayer/config$'] = 'mplayerconf', + ['/neofetch/config%.conf$'] = 'sh', + ['/%.ssh/config$'] = 'sshconfig', + ['/%.sway/config$'] = 'swayconfig', + ['/sway/config$'] = 'swayconfig', + ['/%.cargo/config$'] = 'toml', + ['/%.bundle/config$'] = 'yaml', + }, + ['/%.'] = { + ['/%.aws/credentials$'] = 'confini', + ['/%.gitconfig%.d/'] = starsetf('gitconfig'), + ['/%.gnupg/gpg%.conf$'] = 'gpg', + ['/%.gnupg/options$'] = 'gpg', + ['/%.icewm/menu$'] = 'icemenu', + ['/%.libao$'] = 'libao', + ['/%.pinforc$'] = 'pinfo', + ['/%.cargo/credentials$'] = 'toml', + ['/%.init/.*%.override$'] = 'upstart', + }, + ['calendar/'] = { + ['/%.calendar/'] = starsetf('calendar'), + ['/share/calendar/.*/calendar%.'] = starsetf('calendar'), + ['/share/calendar/calendar%.'] = starsetf('calendar'), + }, + ['cmus/'] = { + -- */cmus/*.theme and */.cmus/*.theme + ['/%.?cmus/.*%.theme$'] = 'cmusrc', + -- */cmus/rc and */.cmus/rc + ['/%.?cmus/rc$'] = 'cmusrc', + ['/%.cmus/autosave$'] = 'cmusrc', + ['/%.cmus/command%-history$'] = 'cmusrc', + }, + ['git/'] = { + ['%.git/'] = { + detect.git, + -- Decrease priority to run after simple pattern checks + { priority = -1 }, + }, + ['^${XDG_CONFIG_HOME}/git/attributes$'] = 'gitattributes', + ['%.git/info/attributes$'] = 'gitattributes', + ['/%.config/git/attributes$'] = 'gitattributes', + ['^${XDG_CONFIG_HOME}/git/ignore$'] = 'gitignore', + ['%.git/info/exclude$'] = 'gitignore', + ['/%.config/git/ignore$'] = 'gitignore', + }, + ['%.cfg'] = { + ['enlightenment/.*%.cfg$'] = 'c', + ['Eterm/.*%.cfg$'] = 'eterm', + ['baseq[2-3]/.*%.cfg$'] = 'quake', + ['id1/.*%.cfg$'] = 'quake', + ['quake[1-3]/.*%.cfg$'] = 'quake', + ['/tex/latex/.*%.cfg$'] = 'tex', + }, + ['%.conf'] = { + ['^proftpd%.conf'] = starsetf('apachestyle'), + ['^access%.conf'] = detect_apache_dotconf, + ['^apache%.conf'] = detect_apache_dotconf, + ['^apache2%.conf'] = detect_apache_dotconf, + ['^httpd%.conf'] = detect_apache_dotconf, + ['^srm%.conf'] = detect_apache_dotconf, + ['asterisk/.*%.conf'] = starsetf('asterisk'), + ['asterisk.*/.*voicemail%.conf'] = starsetf('asteriskvm'), + ['^dictd.*%.conf$'] = 'dictdconf', + ['/lxqt/.*%.conf$'] = 'dosini', + ['/screengrab/.*%.conf$'] = 'dosini', + ['^${GNUPGHOME}/gpg%.conf$'] = 'gpg', + ['/boot/grub/grub%.conf$'] = 'grub', + ['^lilo%.conf'] = starsetf('lilo'), + ['^named.*%.conf$'] = 'named', + ['^rndc.*%.conf$'] = 'named', + ['/openvpn/.*/.*%.conf$'] = 'openvpn', + ['/%.ssh/.*%.conf$'] = 'sshconfig', + ['^%.?tmux.*%.conf$'] = 'tmux', + ['^%.?tmux.*%.conf'] = { 'tmux', { priority = -1 } }, + ['/%.config/upstart/.*%.conf$'] = 'upstart', + ['/%.config/upstart/.*%.override$'] = 'upstart', + ['/%.init/.*%.conf$'] = 'upstart', + ['/xorg%.conf%.d/.*%.conf$'] = detect.xfree86_v4, + }, + ['sst%.meta'] = { + ['%.%-sst%.meta$'] = 'sisu', + ['%._sst%.meta$'] = 'sisu', + ['%.sst%.meta$'] = 'sisu', + }, + ['file'] = { + ['^Containerfile%.'] = starsetf('dockerfile'), + ['^Dockerfile%.'] = starsetf('dockerfile'), + ['[mM]akefile$'] = detect.make, + ['^[mM]akefile'] = starsetf('make'), + ['^[rR]akefile'] = starsetf('ruby'), + ['^%.profile'] = detect.sh, + }, + ['fvwm'] = { + ['/%.fvwm/'] = starsetf('fvwm'), + ['fvwmrc'] = starsetf(detect.fvwm_v1), + ['fvwm95.*%.hook$'] = starsetf(detect.fvwm_v1), + ['fvwm2rc'] = starsetf(detect.fvwm_v2), + }, + ['nginx'] = { + ['/nginx/.*%.conf$'] = 'nginx', + ['/usr/local/nginx/conf/'] = 'nginx', + ['nginx%.conf$'] = 'nginx', + ['^nginx.*%.conf$'] = 'nginx', + }, + ['require'] = { + ['%-requirements%.txt$'] = 'requirements', + ['^requirements/.*%.txt$'] = 'requirements', + ['^requires/.*%.txt$'] = 'requirements', + }, + ['s6'] = { + ['s6.*/down$'] = 'execline', + ['s6.*/finish$'] = 'execline', + ['s6.*/run$'] = 'execline', + ['s6.*/up$'] = 'execline', + ['^s6%-'] = 'execline', + }, + ['utt'] = { + ['^mutt%-.*%-%w+$'] = 'mail', + ['^mutt' .. string.rep('[%w_-]', 6) .. '$'] = 'mail', + ['^muttng%-.*%-%w+$'] = 'mail', + ['^neomutt%-.*%-%w+$'] = 'mail', + ['^neomutt' .. string.rep('[%w_-]', 6) .. '$'] = 'mail', + -- muttngrc* and .muttngrc* + ['^%.?muttngrc'] = detect_muttrc, + -- muttrc* and .muttrc* + ['^%.?muttrc'] = detect_muttrc, + ['/%.mutt/muttrc'] = detect_muttrc, + ['/%.muttng/muttngrc'] = detect_muttrc, + ['/%.muttng/muttrc'] = detect_muttrc, + ['^Muttngrc'] = detect_muttrc, + ['^Muttrc'] = detect_muttrc, + -- neomuttrc* and .neomuttrc* + ['^%.?neomuttrc'] = detect_neomuttrc, + ['/%.neomutt/neomuttrc'] = detect_neomuttrc, + ['^Neomuttrc'] = detect_neomuttrc, + }, + ['^%.'] = { + ['^%.cshrc'] = detect.csh, + ['^%.login'] = detect.csh, + ['^%.notmuch%-config%.'] = 'dosini', + ['^%.gitsendemail%.msg%.......$'] = 'gitsendemail', + ['^%.kshrc'] = detect.ksh, + ['^%.article%.%d+$'] = 'mail', + ['^%.letter%.%d+$'] = 'mail', + ['^%.reminders'] = starsetf('remind'), + ['^%.tcshrc'] = detect.tcsh, + ['^%.zcompdump'] = starsetf('zsh'), + }, + ['proj%.user$'] = { + ['%.csproj%.user$'] = 'xml', + ['%.fsproj%.user$'] = 'xml', + ['%.vbproj%.user$'] = 'xml', + }, + [''] = { + ['^bash%-fc[%-%.]'] = detect.bash, + ['/bind/db%.'] = starsetf('bindzone'), + ['/named/db%.'] = starsetf('bindzone'), + ['%.blade%.php$'] = 'blade', + ['^bzr_log%.'] = 'bzr', + ['^cabal%.project%.'] = starsetf('cabalproject'), + ['^sgml%.catalog'] = starsetf('catalog'), + ['hgrc$'] = 'cfg', + ['^[cC]hange[lL]og'] = starsetf(detect.changelog), + ['%.%.ch$'] = 'chill', + ['%.cmake%.in$'] = 'cmake', + ['^crontab%.'] = starsetf('crontab'), + ['^cvs%d+$'] = 'cvs', + ['^php%.ini%-'] = 'dosini', + ['^drac%.'] = starsetf('dracula'), + ['/dtrace/.*%.d$'] = 'dtrace', + ['esmtprc$'] = 'esmtprc', + ['/0%.orig/'] = detect.foam, + ['/0/'] = detect.foam, + ['/constant/g$'] = detect.foam, + ['Transport%.'] = detect.foam, + ['^[a-zA-Z0-9].*Dict%.'] = detect.foam, + ['^[a-zA-Z0-9].*Dict$'] = detect.foam, + ['^[a-zA-Z].*Properties%.'] = detect.foam, + ['^[a-zA-Z].*Properties$'] = detect.foam, + ['/tmp/lltmp'] = starsetf('gedcom'), + ['^gkrellmrc_.$'] = 'gkrellmrc', + ['^${GNUPGHOME}/options$'] = 'gpg', + ['/boot/grub/menu%.lst$'] = 'grub', + -- gtkrc* and .gtkrc* + ['^%.?gtkrc'] = starsetf('gtkrc'), + ['^${VIMRUNTIME}/doc/.*%.txt$'] = 'help', + ['^hg%-editor%-.*%.txt$'] = 'hgcommit', + ['%.html%.m4$'] = 'htmlm4', + ['^JAM.*%.'] = starsetf('jam'), + ['^Prl.*%.'] = starsetf('jam'), + ['%.properties_..$'] = 'jproperties', + ['%.properties_.._..$'] = 'jproperties', + ['%.properties_.._.._'] = starsetf('jproperties'), + ['^org%.eclipse%..*%.prefs$'] = 'jproperties', + ['^[jt]sconfig.*%.json$'] = 'jsonc', + ['^Config%.in%.'] = starsetf('kconfig'), + ['^Kconfig%.'] = starsetf('kconfig'), + ['/ldscripts/'] = 'ld', + ['lftp/rc$'] = 'lftp', + ['/LiteStep/.*/.*%.rc$'] = 'litestep', + ['^/tmp/SLRN[0-9A-Z.]+$'] = 'mail', + ['^ae%d+%.txt$'] = 'mail', + ['^pico%.%d+$'] = 'mail', + ['^reportbug%-'] = starsetf('mail'), + ['^snd%.%d+$'] = 'mail', + ['^rndc.*%.key$'] = 'named', + ['^tmac%.'] = starsetf('nroff'), + ['%.ml%.cppo$'] = 'ocaml', + ['%.mli%.cppo$'] = 'ocaml', + ['/octave/history$'] = 'octave', + ['%.opam%.locked$'] = 'opam', + ['%.opam%.template$'] = 'opam', + ['printcap'] = starsetf(function(path, bufnr) + return require('vim.filetype.detect').printcap('print') + end), + ['/queries/.*%.scm$'] = 'query', -- treesitter queries (Neovim only) + [',v$'] = 'rcs', + ['^svn%-commit.*%.tmp$'] = 'svn', + ['%.swift%.gyb$'] = 'swiftgyb', + ['termcap'] = starsetf(function(path, bufnr) + return require('vim.filetype.detect').printcap('term') + end), + ['%.t%.html$'] = 'tilde', + ['%.vhdl_[0-9]'] = starsetf('vhdl'), + ['vimrc'] = starsetf('vim'), + ['/Xresources/'] = starsetf('xdefaults'), + ['/app%-defaults/'] = starsetf('xdefaults'), + ['^Xresources'] = starsetf('xdefaults'), + -- Increase priority to run before the pattern below + ['^XF86Config%-4'] = starsetf(detect.xfree86_v4, { priority = -math.huge + 1 }), + ['^XF86Config'] = starsetf(detect.xfree86_v3), + ['Xmodmap$'] = 'xmodmap', + ['xmodmap'] = starsetf('xmodmap'), + -- .zlog* and zlog* + ['^%.?zlog'] = starsetf('zsh'), + -- .zsh* and zsh* + ['^%.?zsh'] = starsetf('zsh'), + -- Ignored extension + ['~$'] = function(path, bufnr) + local short = path:gsub('~+$', '', 1) + if path ~= short and short ~= '' then + return M.match({ buf = bufnr, filename = fn.fnameescape(short) }) + end + end, }, - ['.*%.git/modules/.*/config'] = 'gitconfig', - ['.*%.git/modules/config'] = 'gitconfig', - ['.*%.git/config'] = 'gitconfig', - ['.*/etc/gitconfig'] = 'gitconfig', - ['.*/%.config/git/config'] = 'gitconfig', - ['.*%.git/config%.worktree'] = 'gitconfig', - ['.*%.git/worktrees/.*/config%.worktree'] = 'gitconfig', - ['${XDG_CONFIG_HOME}/git/config'] = 'gitconfig', - ['.*%.git/info/attributes'] = 'gitattributes', - ['.*/etc/gitattributes'] = 'gitattributes', - ['.*/%.config/git/attributes'] = 'gitattributes', - ['${XDG_CONFIG_HOME}/git/attributes'] = 'gitattributes', - ['.*%.git/info/exclude'] = 'gitignore', - ['.*/%.config/git/ignore'] = 'gitignore', - ['${XDG_CONFIG_HOME}/git/ignore'] = 'gitignore', - ['%.gitsendemail%.msg%.......'] = 'gitsendemail', - ['gkrellmrc_.'] = 'gkrellmrc', - ['.*/usr/.*/gnupg/options%.skel'] = 'gpg', - ['.*/%.gnupg/options'] = 'gpg', - ['.*/%.gnupg/gpg%.conf'] = 'gpg', - ['${GNUPGHOME}/options'] = 'gpg', - ['${GNUPGHOME}/gpg%.conf'] = 'gpg', - ['.*/etc/group'] = 'group', - ['.*/etc/gshadow'] = 'group', - ['.*/etc/group%.edit'] = 'group', - ['.*/var/backups/gshadow%.bak'] = 'group', - ['.*/etc/group%-'] = 'group', - ['.*/etc/gshadow%-'] = 'group', - ['.*/var/backups/group%.bak'] = 'group', - ['.*/etc/gshadow%.edit'] = 'group', - ['.*/boot/grub/grub%.conf'] = 'grub', - ['.*/boot/grub/menu%.lst'] = 'grub', - ['.*/etc/grub%.conf'] = 'grub', - -- gtkrc* and .gtkrc* - ['%.?gtkrc.*'] = starsetf('gtkrc'), - ['${VIMRUNTIME}/doc/.*%.txt'] = 'help', - ['hg%-editor%-.*%.txt'] = 'hgcommit', - ['.*/etc/host%.conf'] = 'hostconf', - ['.*/etc/hosts%.deny'] = 'hostsaccess', - ['.*/etc/hosts%.allow'] = 'hostsaccess', - ['.*%.html%.m4'] = 'htmlm4', - ['.*/%.i3/config'] = 'i3config', - ['.*/i3/config'] = 'i3config', - ['.*/%.icewm/menu'] = 'icemenu', - ['.*/etc/initng/.*/.*%.i'] = 'initng', - ['JAM.*%..*'] = starsetf('jam'), - ['Prl.*%..*'] = starsetf('jam'), - ['.*%.properties_..'] = 'jproperties', - ['.*%.properties_.._..'] = 'jproperties', - ['org%.eclipse%..*%.prefs'] = 'jproperties', - ['.*%.properties_.._.._.*'] = starsetf('jproperties'), - ['[jt]sconfig.*%.json'] = 'jsonc', - ['[jJ]ustfile'] = 'just', - ['Kconfig%..*'] = starsetf('kconfig'), - ['Config%.in%..*'] = starsetf('kconfig'), - ['.*%.[Ss][Uu][Bb]'] = 'krl', - ['lilo%.conf.*'] = starsetf('lilo'), - ['.*/etc/logcheck/.*%.d.*/.*'] = starsetf('logcheck'), - ['.*/ldscripts/.*'] = 'ld', - ['.*lftp/rc'] = 'lftp', - ['.*/%.libao'] = 'libao', - ['.*/etc/libao%.conf'] = 'libao', - ['.*/etc/.*limits%.conf'] = 'limits', - ['.*/etc/limits'] = 'limits', - ['.*/etc/.*limits%.d/.*%.conf'] = 'limits', - ['.*/supertux2/config'] = 'lisp', - ['.*/LiteStep/.*/.*%.rc'] = 'litestep', - ['.*/etc/login%.access'] = 'loginaccess', - ['.*/etc/login%.defs'] = 'logindefs', - ['%.letter%.%d+'] = 'mail', - ['%.article%.%d+'] = 'mail', - ['/tmp/SLRN[0-9A-Z.]+'] = 'mail', - ['ae%d+%.txt'] = 'mail', - ['pico%.%d+'] = 'mail', - ['mutt%-.*%-%w+'] = 'mail', - ['muttng%-.*%-%w+'] = 'mail', - ['neomutt%-.*%-%w+'] = 'mail', - ['mutt' .. string.rep('[%w_-]', 6)] = 'mail', - ['neomutt' .. string.rep('[%w_-]', 6)] = 'mail', - ['snd%.%d+'] = 'mail', - ['reportbug%-.*'] = starsetf('mail'), - ['.*/etc/mail/aliases'] = 'mailaliases', - ['.*/etc/aliases'] = 'mailaliases', - ['.*[mM]akefile'] = 'make', - ['[mM]akefile.*'] = starsetf('make'), - ['.*/etc/man%.conf'] = 'manconf', - ['.*/log/auth'] = 'messages', - ['.*/log/cron'] = 'messages', - ['.*/log/daemon'] = 'messages', - ['.*/log/debug'] = 'messages', - ['.*/log/kern'] = 'messages', - ['.*/log/lpr'] = 'messages', - ['.*/log/mail'] = 'messages', - ['.*/log/messages'] = 'messages', - ['.*/log/news/news'] = 'messages', - ['.*/log/syslog'] = 'messages', - ['.*/log/user'] = 'messages', - ['.*/log/auth%.log'] = 'messages', - ['.*/log/cron%.log'] = 'messages', - ['.*/log/daemon%.log'] = 'messages', - ['.*/log/debug%.log'] = 'messages', - ['.*/log/kern%.log'] = 'messages', - ['.*/log/lpr%.log'] = 'messages', - ['.*/log/mail%.log'] = 'messages', - ['.*/log/messages%.log'] = 'messages', - ['.*/log/news/news%.log'] = 'messages', - ['.*/log/syslog%.log'] = 'messages', - ['.*/log/user%.log'] = 'messages', - ['.*/log/auth%.err'] = 'messages', - ['.*/log/cron%.err'] = 'messages', - ['.*/log/daemon%.err'] = 'messages', - ['.*/log/debug%.err'] = 'messages', - ['.*/log/kern%.err'] = 'messages', - ['.*/log/lpr%.err'] = 'messages', - ['.*/log/mail%.err'] = 'messages', - ['.*/log/messages%.err'] = 'messages', - ['.*/log/news/news%.err'] = 'messages', - ['.*/log/syslog%.err'] = 'messages', - ['.*/log/user%.err'] = 'messages', - ['.*/log/auth%.info'] = 'messages', - ['.*/log/cron%.info'] = 'messages', - ['.*/log/daemon%.info'] = 'messages', - ['.*/log/debug%.info'] = 'messages', - ['.*/log/kern%.info'] = 'messages', - ['.*/log/lpr%.info'] = 'messages', - ['.*/log/mail%.info'] = 'messages', - ['.*/log/messages%.info'] = 'messages', - ['.*/log/news/news%.info'] = 'messages', - ['.*/log/syslog%.info'] = 'messages', - ['.*/log/user%.info'] = 'messages', - ['.*/log/auth%.warn'] = 'messages', - ['.*/log/cron%.warn'] = 'messages', - ['.*/log/daemon%.warn'] = 'messages', - ['.*/log/debug%.warn'] = 'messages', - ['.*/log/kern%.warn'] = 'messages', - ['.*/log/lpr%.warn'] = 'messages', - ['.*/log/mail%.warn'] = 'messages', - ['.*/log/messages%.warn'] = 'messages', - ['.*/log/news/news%.warn'] = 'messages', - ['.*/log/syslog%.warn'] = 'messages', - ['.*/log/user%.warn'] = 'messages', - ['.*/log/auth%.crit'] = 'messages', - ['.*/log/cron%.crit'] = 'messages', - ['.*/log/daemon%.crit'] = 'messages', - ['.*/log/debug%.crit'] = 'messages', - ['.*/log/kern%.crit'] = 'messages', - ['.*/log/lpr%.crit'] = 'messages', - ['.*/log/mail%.crit'] = 'messages', - ['.*/log/messages%.crit'] = 'messages', - ['.*/log/news/news%.crit'] = 'messages', - ['.*/log/syslog%.crit'] = 'messages', - ['.*/log/user%.crit'] = 'messages', - ['.*/log/auth%.notice'] = 'messages', - ['.*/log/cron%.notice'] = 'messages', - ['.*/log/daemon%.notice'] = 'messages', - ['.*/log/debug%.notice'] = 'messages', - ['.*/log/kern%.notice'] = 'messages', - ['.*/log/lpr%.notice'] = 'messages', - ['.*/log/mail%.notice'] = 'messages', - ['.*/log/messages%.notice'] = 'messages', - ['.*/log/news/news%.notice'] = 'messages', - ['.*/log/syslog%.notice'] = 'messages', - ['.*/log/user%.notice'] = 'messages', - ['.*%.[Mm][Oo][Dd]'] = detect.mod, - ['.*/etc/modules%.conf'] = 'modconf', - ['.*/etc/conf%.modules'] = 'modconf', - ['.*/etc/modules'] = 'modconf', - ['.*/etc/modprobe%..*'] = starsetf('modconf'), - ['.*/etc/modutils/.*'] = starsetf(function(path, bufnr) - if fn.executable(fn.expand(path)) ~= 1 then - return 'modconf' - end - end), - ['.*%.[mi][3g]'] = 'modula3', - ['Muttrc'] = 'muttrc', - ['Muttngrc'] = 'muttrc', - ['.*/etc/Muttrc%.d/.*'] = starsetf('muttrc'), - ['.*/%.mplayer/config'] = 'mplayerconf', - ['Muttrc.*'] = detect_muttrc, - ['Muttngrc.*'] = detect_muttrc, - -- muttrc* and .muttrc* - ['%.?muttrc.*'] = detect_muttrc, - -- muttngrc* and .muttngrc* - ['%.?muttngrc.*'] = detect_muttrc, - ['.*/%.mutt/muttrc.*'] = detect_muttrc, - ['.*/%.muttng/muttrc.*'] = detect_muttrc, - ['.*/%.muttng/muttngrc.*'] = detect_muttrc, - ['rndc.*%.conf'] = 'named', - ['rndc.*%.key'] = 'named', - ['named.*%.conf'] = 'named', - ['.*/etc/nanorc'] = 'nanorc', - ['.*%.NS[ACGLMNPS]'] = 'natural', - ['Neomuttrc.*'] = detect_neomuttrc, - -- neomuttrc* and .neomuttrc* - ['%.?neomuttrc.*'] = detect_neomuttrc, - ['.*/%.neomutt/neomuttrc.*'] = detect_neomuttrc, - ['nginx.*%.conf'] = 'nginx', - ['.*/etc/nginx/.*'] = 'nginx', - ['.*nginx%.conf'] = 'nginx', - ['.*/nginx/.*%.conf'] = 'nginx', - ['.*/usr/local/nginx/conf/.*'] = 'nginx', - ['.*%.[1-9]'] = detect.nroff, - ['.*%.ml%.cppo'] = 'ocaml', - ['.*%.mli%.cppo'] = 'ocaml', - ['.*/octave/history'] = 'octave', - ['.*%.opam%.template'] = 'opam', - ['.*/openvpn/.*/.*%.conf'] = 'openvpn', - ['.*%.[Oo][Pp][Ll]'] = 'opl', - ['.*/etc/pam%.conf'] = 'pamconf', - ['.*/etc/pam%.d/.*'] = starsetf('pamconf'), - ['.*/etc/passwd%-'] = 'passwd', - ['.*/etc/shadow'] = 'passwd', - ['.*/etc/shadow%.edit'] = 'passwd', - ['.*/var/backups/shadow%.bak'] = 'passwd', - ['.*/var/backups/passwd%.bak'] = 'passwd', - ['.*/etc/passwd'] = 'passwd', - ['.*/etc/passwd%.edit'] = 'passwd', - ['.*/etc/shadow%-'] = 'passwd', - ['%.?gitolite%.rc'] = 'perl', - ['example%.gitolite%.rc'] = 'perl', - ['.*%.php%d'] = 'php', - ['.*/%.pinforc'] = 'pinfo', - ['.*/etc/pinforc'] = 'pinfo', - ['.*%.[Pp][Rr][Gg]'] = detect.prg, - ['.*/etc/protocols'] = 'protocols', - ['.*printcap.*'] = starsetf(function(path, bufnr) - return require('vim.filetype.detect').printcap('print') - end), - ['.*baseq[2-3]/.*%.cfg'] = 'quake', - ['.*quake[1-3]/.*%.cfg'] = 'quake', - ['.*id1/.*%.cfg'] = 'quake', - ['.*/queries/.*%.scm'] = 'query', -- treesitter queries (Neovim only) - ['.*,v'] = 'rcs', - ['%.reminders.*'] = starsetf('remind'), - ['.*%-requirements%.txt'] = 'requirements', - ['requirements/.*%.txt'] = 'requirements', - ['requires/.*%.txt'] = 'requirements', - ['[rR]akefile.*'] = starsetf('ruby'), - ['[rR]antfile'] = 'ruby', - ['[rR]akefile'] = 'ruby', - ['.*/etc/sensors%.d/[^.].*'] = starsetf('sensors'), - ['.*/etc/sensors%.conf'] = 'sensors', - ['.*/etc/sensors3%.conf'] = 'sensors', - ['.*/etc/services'] = 'services', - ['.*/etc/serial%.conf'] = 'setserial', - ['.*/etc/udev/cdsymlinks%.conf'] = 'sh', - ['.*/neofetch/config%.conf'] = 'sh', - ['%.bash[_%-]aliases'] = detect.bash, - ['%.bash[_%-]history'] = detect.bash, - ['%.bash[_%-]logout'] = detect.bash, - ['%.bash[_%-]profile'] = detect.bash, - ['%.kshrc.*'] = detect.ksh, - ['%.profile.*'] = detect.sh, - ['.*/etc/profile'] = detect.sh, - ['bash%-fc[%-%.].*'] = detect.bash, - ['%.tcshrc.*'] = detect.tcsh, - ['.*/etc/sudoers%.d/.*'] = starsetf('sudoers'), - ['.*%._sst%.meta'] = 'sisu', - ['.*%.%-sst%.meta'] = 'sisu', - ['.*%.sst%.meta'] = 'sisu', - ['.*/etc/slp%.conf'] = 'slpconf', - ['.*/etc/slp%.reg'] = 'slpreg', - ['.*/etc/slp%.spi'] = 'slpspi', - ['.*/etc/ssh/ssh_config%.d/.*%.conf'] = 'sshconfig', - ['.*/%.ssh/config'] = 'sshconfig', - ['.*/%.ssh/.*%.conf'] = 'sshconfig', - ['.*/etc/ssh/sshd_config%.d/.*%.conf'] = 'sshdconfig', - ['.*%.[Ss][Rr][Cc]'] = detect.src, - ['.*/etc/sudoers'] = 'sudoers', - ['svn%-commit.*%.tmp'] = 'svn', - ['.*/sway/config'] = 'swayconfig', - ['.*/%.sway/config'] = 'swayconfig', - ['.*%.swift%.gyb'] = 'swiftgyb', - ['.*%.[Ss][Yy][Ss]'] = detect.sys, - ['.*/etc/sysctl%.conf'] = 'sysctl', - ['.*/etc/sysctl%.d/.*%.conf'] = 'sysctl', - ['.*/systemd/.*%.automount'] = 'systemd', - ['.*/systemd/.*%.dnssd'] = 'systemd', - ['.*/systemd/.*%.link'] = 'systemd', - ['.*/systemd/.*%.mount'] = 'systemd', - ['.*/systemd/.*%.netdev'] = 'systemd', - ['.*/systemd/.*%.network'] = 'systemd', - ['.*/systemd/.*%.nspawn'] = 'systemd', - ['.*/systemd/.*%.path'] = 'systemd', - ['.*/systemd/.*%.service'] = 'systemd', - ['.*/systemd/.*%.slice'] = 'systemd', - ['.*/systemd/.*%.socket'] = 'systemd', - ['.*/systemd/.*%.swap'] = 'systemd', - ['.*/systemd/.*%.target'] = 'systemd', - ['.*/systemd/.*%.timer'] = 'systemd', - ['.*/etc/systemd/.*%.conf%.d/.*%.conf'] = 'systemd', - ['.*/%.config/systemd/user/.*%.d/.*%.conf'] = 'systemd', - ['.*/etc/systemd/system/.*%.d/.*%.conf'] = 'systemd', - ['.*/etc/systemd/system/.*%.d/%.#.*'] = 'systemd', - ['.*/etc/systemd/system/%.#.*'] = 'systemd', - ['.*/%.config/systemd/user/.*%.d/%.#.*'] = 'systemd', - ['.*/%.config/systemd/user/%.#.*'] = 'systemd', - ['.*termcap.*'] = starsetf(function(path, bufnr) - return require('vim.filetype.detect').printcap('term') - end), - ['.*/tex/latex/.*%.cfg'] = 'tex', - ['.*%.t%.html'] = 'tilde', - ['%.?tmux.*%.conf'] = 'tmux', - ['%.?tmux.*%.conf.*'] = { 'tmux', { priority = -1 } }, - ['.*/%.cargo/config'] = 'toml', - ['.*/%.cargo/credentials'] = 'toml', - ['.*/etc/udev/udev%.conf'] = 'udevconf', - ['.*/etc/udev/permissions%.d/.*%.permissions'] = 'udevperm', - ['.*/etc/updatedb%.conf'] = 'updatedb', - ['.*/%.init/.*%.override'] = 'upstart', - ['.*/usr/share/upstart/.*%.conf'] = 'upstart', - ['.*/%.config/upstart/.*%.override'] = 'upstart', - ['.*/etc/init/.*%.conf'] = 'upstart', - ['.*/etc/init/.*%.override'] = 'upstart', - ['.*/%.config/upstart/.*%.conf'] = 'upstart', - ['.*/%.init/.*%.conf'] = 'upstart', - ['.*/usr/share/upstart/.*%.override'] = 'upstart', - ['.*%.[Ll][Oo][Gg]'] = detect.log, - ['.*/etc/config/.*'] = starsetf(detect.uci), - ['.*%.vhdl_[0-9].*'] = starsetf('vhdl'), - ['.*%.ws[fc]'] = 'wsh', - ['.*/Xresources/.*'] = starsetf('xdefaults'), - ['.*/app%-defaults/.*'] = starsetf('xdefaults'), - ['.*/etc/xinetd%.conf'] = 'xinetd', - ['.*/usr/share/X11/xkb/compat/.*'] = starsetf('xkb'), - ['.*/usr/share/X11/xkb/geometry/.*'] = starsetf('xkb'), - ['.*/usr/share/X11/xkb/keycodes/.*'] = starsetf('xkb'), - ['.*/usr/share/X11/xkb/symbols/.*'] = starsetf('xkb'), - ['.*/usr/share/X11/xkb/types/.*'] = starsetf('xkb'), - ['.*/etc/blkid%.tab'] = 'xml', - ['.*/etc/blkid%.tab%.old'] = 'xml', - ['.*%.vbproj%.user'] = 'xml', - ['.*%.fsproj%.user'] = 'xml', - ['.*%.csproj%.user'] = 'xml', - ['.*/etc/xdg/menus/.*%.menu'] = 'xml', - ['.*Xmodmap'] = 'xmodmap', - ['.*/etc/zprofile'] = 'zsh', - ['.*vimrc.*'] = starsetf('vim'), - ['Xresources.*'] = starsetf('xdefaults'), - ['.*/etc/xinetd%.d/.*'] = starsetf('xinetd'), - ['.*xmodmap.*'] = starsetf('xmodmap'), - ['.*/xorg%.conf%.d/.*%.conf'] = detect.xfree86_v4, - -- Increase priority to run before the pattern below - ['XF86Config%-4.*'] = starsetf(detect.xfree86_v4, { priority = -math.huge + 1 }), - ['XF86Config.*'] = starsetf(detect.xfree86_v3), - ['.*/%.bundle/config'] = 'yaml', - ['%.zcompdump.*'] = starsetf('zsh'), - -- .zlog* and zlog* - ['%.?zlog.*'] = starsetf('zsh'), - -- .zsh* and zsh* - ['%.?zsh.*'] = starsetf('zsh'), - -- Ignored extension - ['.*~'] = function(path, bufnr) - local short = path:gsub('~+$', '', 1) - if path ~= short and short ~= '' then - return M.match({ buf = bufnr, filename = fn.fnameescape(short) }) - end - end, -- END PATTERN } -- luacheck: pop -- luacheck: pop ---- @param t vim.filetype.mapping +--- Lookup table/cache for patterns +--- @alias vim.filetype.pattern_cache { has_env: boolean, has_slash: boolean } +--- @type table<string,vim.filetype.pattern_cache> +local pattern_lookup = {} + +local function compare_by_priority(a, b) + return a[next(a)][2].priority > b[next(b)][2].priority +end + +--- @param pat string +--- @return { has_env: boolean, has_slash: boolean } +local function parse_pattern(pat) + return { has_env = pat:find('%$%b{}') ~= nil, has_slash = pat:find('/') ~= nil } +end + +--- @param t table<string,vim.filetype.mapping> +--- @return vim.filetype.mapping[] --- @return vim.filetype.mapping[] local function sort_by_priority(t) - local sorted = {} --- @type vim.filetype.mapping[] - for k, v in pairs(t) do - local ft = type(v) == 'table' and v[1] or v - assert( - type(ft) == 'string' or type(ft) == 'function', - 'Expected string or function for filetype' - ) - - local opts = (type(v) == 'table' and type(v[2]) == 'table') and v[2] or {} - if not opts.priority then - opts.priority = 0 + -- Separate patterns with non-negative and negative priority because they + -- will be processed separately + local pos = {} --- @type vim.filetype.mapping[] + local neg = {} --- @type vim.filetype.mapping[] + for parent, ft_map in pairs(t) do + pattern_lookup[parent] = pattern_lookup[parent] or parse_pattern(parent) + for pat, maptbl in pairs(ft_map) do + local ft = type(maptbl) == 'table' and maptbl[1] or maptbl + assert( + type(ft) == 'string' or type(ft) == 'function', + 'Expected string or function for filetype' + ) + + -- Parse pattern for common data and cache it once + pattern_lookup[pat] = pattern_lookup[pat] or parse_pattern(pat) + + local opts = (type(maptbl) == 'table' and type(maptbl[2]) == 'table') and maptbl[2] or {} + opts.parent = opts.parent or parent + opts.priority = opts.priority or 0 + + table.insert(opts.priority >= 0 and pos or neg, { [pat] = { ft, opts } }) end - table.insert(sorted, { [k] = { ft, opts } }) end - table.sort(sorted, function(a, b) - return a[next(a)][2].priority > b[next(b)][2].priority - end) - return sorted + + table.sort(pos, compare_by_priority) + table.sort(neg, compare_by_priority) + return pos, neg end -local pattern_sorted = sort_by_priority(pattern) +local pattern_sorted_pos, pattern_sorted_neg = sort_by_priority(pattern) --- @param path string --- @param as_pattern? true @@ -2302,7 +2501,7 @@ end --- ['.*/etc/foo/.*%.conf'] = { 'dosini', { priority = 10 } }, --- -- A pattern containing an environment variable --- ['${XDG_CONFIG_HOME}/foo/git'] = 'git', ---- ['README.(%a+)$'] = function(path, bufnr, ext) +--- ['.*README.(%a+)'] = function(path, bufnr, ext) --- if ext == 'md' then --- return 'markdown' --- elseif ext == 'rst' then @@ -2344,11 +2543,16 @@ function M.add(filetypes) end for k, v in pairs(filetypes.pattern or {}) do - pattern[normalize_path(k, true)] = v + -- Add to "match all" parent pattern (might be better to optimize later or document + -- supplying `opts.parent` directly) + -- User patterns are assumed to be implicitly anchored (as in Vim) + pattern['']['^' .. normalize_path(k, true) .. '$'] = v end if filetypes.pattern then - pattern_sorted = sort_by_priority(pattern) + -- TODO: full resorting might be expensive with a lot of separate `vim.filetype.add()` calls. + -- Consider inserting new patterns precisely into already sorted lists of built-in patterns. + pattern_sorted_pos, pattern_sorted_neg = sort_by_priority(pattern) end end @@ -2392,46 +2596,81 @@ local function dispatch(ft, path, bufnr, ...) return ft0, on_detect end ---- Lookup table/cache for patterns that contain an environment variable pattern, e.g. ${SOME_VAR}. ---- @type table<string,boolean> -local expand_env_lookup = {} +--- @param pat string +--- @return boolean +--- @return string +local function expand_envvar_pattern(pat) + local some_env_missing = false + local expanded = pat:gsub('%${(%S-)}', function(env) + local val = vim.env[env] --- @type string? + some_env_missing = some_env_missing or val == nil + return vim.pesc(val or '') + end) + return some_env_missing, expanded +end --- @param name string --- @param path string --- @param tail string --- @param pat string ---- @return string|false? -local function match_pattern(name, path, tail, pat) - if expand_env_lookup[pat] == nil then - expand_env_lookup[pat] = pat:find('%${') ~= nil - end - if expand_env_lookup[pat] then - local return_early --- @type true? - --- @type string - pat = pat:gsub('%${(%S-)}', function(env) - -- If an environment variable is present in the pattern but not set, there is no match - if not vim.env[env] then - return_early = true - return nil - end - return vim.pesc(vim.env[env]) - end) - if return_early then - return false +--- @param try_all_candidates boolean +--- @return string? +local function match_pattern(name, path, tail, pat, try_all_candidates) + local pat_cache = pattern_lookup[pat] + local has_slash = pat_cache.has_slash + + if pat_cache.has_env then + local some_env_missing, expanded = expand_envvar_pattern(pat) + -- If any environment variable is present in the pattern but not set, there is no match + if some_env_missing then + return nil end + pat, has_slash = expanded, expanded:find('/') ~= nil end - -- If the pattern contains a / match against the full path, otherwise just the tail - local fullpat = '^' .. pat .. '$' + -- Try all possible candidates to make parent patterns not depend on slash presence + if try_all_candidates then + return (path:match(pat) or name:match(pat) or tail:match(pat)) + end - if pat:find('/') then + -- If the pattern contains a / match against the full path, otherwise just the tail + if has_slash then -- Similar to |autocmd-pattern|, if the pattern contains a '/' then check for a match against -- both the short file name (as typed) and the full file name (after expanding to full path -- and resolving symlinks) - return (name:match(fullpat) or path:match(fullpat)) + return (name:match(pat) or path:match(pat)) end - return (tail:match(fullpat)) + return (tail:match(pat)) +end + +--- @param name string +--- @param path string +--- @param tail string +--- @param pattern_sorted vim.filetype.mapping[] +--- @param parent_matches table<string,boolean> +--- @param bufnr integer? +local function match_pattern_sorted(name, path, tail, pattern_sorted, parent_matches, bufnr) + for i = 1, #pattern_sorted do + local pat, ft_data = next(pattern_sorted[i]) + + local parent = ft_data[2].parent + local parent_is_matched = parent_matches[parent] + if parent_is_matched == nil then + parent_matches[parent] = match_pattern(name, path, tail, parent, true) ~= nil + parent_is_matched = parent_matches[parent] + end + + if parent_is_matched then + local matches = match_pattern(name, path, tail, pat, false) + if matches then + local ft, on_detect = dispatch(ft_data[1], path, bufnr, matches) + if ft then + return ft, on_detect + end + end + end + end end --- @class vim.filetype.match.args @@ -2527,23 +2766,12 @@ function M.match(args) 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 - 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 + -- Cache match results of all parent patterns to improve performance + local parent_matches = {} + ft, on_detect = + match_pattern_sorted(name, path, tail, pattern_sorted_pos, parent_matches, bufnr) + if ft then + return ft, on_detect end -- Next, check file extension @@ -2556,18 +2784,10 @@ function M.match(args) end -- 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 - end - end + ft, on_detect = + match_pattern_sorted(name, path, tail, pattern_sorted_neg, parent_matches, bufnr) + if ft then + return ft, on_detect end end @@ -2583,20 +2803,24 @@ function M.match(args) contents = M._getlines(bufnr) end end - -- If name is nil, catch any errors from the contents filetype detection function. - -- 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, on_detect = pcall( - require('vim.filetype.detect').match_contents, - contents, - name, - function(ext) - return dispatch(extension[ext], name, bufnr) + + -- Match based solely on content only if there is any content (for performance) + if not (#contents == 1 and contents[1] == '') then + -- If name is nil, catch any errors from the contents filetype detection function. + -- 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, on_detect = pcall( + require('vim.filetype.detect').match_contents, + contents, + name, + function(ext) + return dispatch(extension[ext], name, bufnr) + end + ) + if ok then + return ft, on_detect end - ) - if ok then - return ft, on_detect end end end @@ -2615,6 +2839,7 @@ end --- Note: this uses |nvim_get_option_value()| but caches the result. --- This means |ftplugin| and |FileType| autocommands are only --- triggered once and may not reflect later changes. +--- @since 11 --- @param filetype string Filetype --- @param option string Option name --- @return string|boolean|integer: Option value diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index ba86d8de5a..1cc81b177f 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -450,7 +450,7 @@ local function modula2(bufnr) return 'modula2', function(b) - vim.api.nvim_buf_call(b, function() + vim._with({ buf = b }, function() fn['modula2#SetDialect'](dialect, extension) end) end @@ -472,6 +472,41 @@ function M.def(_, bufnr) end --- @type vim.filetype.mapfn +function M.dsp(path, bufnr) + if vim.g.filetype_dsp then + return vim.g.filetype_dsp + end + + -- Test the filename + local file_name = fn.fnamemodify(path, ':t') + if file_name:find('^[mM]akefile.*$') then + return 'make' + end + + -- Test the file contents + for _, line in ipairs(getlines(bufnr, 1, 200)) do + if + findany(line, { + -- Check for comment style + [[#.*]], + -- Check for common lines + [[^.*Microsoft Developer Studio Project File.*$]], + [[^!MESSAGE This is not a valid makefile\..+$]], + -- Check for keywords + [[^!(IF,ELSEIF,ENDIF).*$]], + -- Check for common assignments + [[^SOURCE=.*$]], + }) + then + return 'make' + end + end + + -- Otherwise, assume we have a Faust file + return 'faust' +end + +--- @type vim.filetype.mapfn function M.e(_, bufnr) if vim.g.filetype_euphoria then return vim.g.filetype_euphoria @@ -594,7 +629,7 @@ function M.frm(_, bufnr) end --- @type vim.filetype.mapfn -function M.fvwm_1(_, _) +function M.fvwm_v1(_, _) return 'fvwm', function(bufnr) vim.b[bufnr].fvwm_version = 1 end @@ -650,13 +685,58 @@ function M.header(_, bufnr) end end +--- Recursively search for Hare source files in a directory and any +--- subdirectories, up to a given depth. +--- @param dir string +--- @param depth number +--- @return boolean +local function is_hare_module(dir, depth) + depth = math.max(depth, 0) + for name, _ in vim.fs.dir(dir, { depth = depth + 1 }) do + if name:find('%.ha$') then + return true + end + end + return false +end + +--- @type vim.filetype.mapfn +function M.haredoc(path, _) + if vim.g.filetype_haredoc then + if is_hare_module(vim.fs.dirname(path), vim.g.haredoc_search_depth or 1) then + return 'haredoc' + end + end +end + --- @type vim.filetype.mapfn function M.html(_, bufnr) - for _, line in ipairs(getlines(bufnr, 1, 10)) do - if matchregex(line, [[\<DTD\s\+XHTML\s]]) then + -- Disabled for the reasons mentioned here: + -- https://github.com/vim/vim/pull/13594#issuecomment-1834465890 + -- local filename = fn.fnamemodify(path, ':t') + -- if filename:find('%.component%.html$') then + -- return 'htmlangular' + -- end + + for _, line in ipairs(getlines(bufnr, 1, 40)) do + if + matchregex( + line, + [[@\(if\|for\|defer\|switch\)\|\*\(ngIf\|ngFor\|ngSwitch\|ngTemplateOutlet\)\|ng-template\|ng-content\|{{.*}}]] + ) + then + return 'htmlangular' + elseif matchregex(line, [[\<DTD\s\+XHTML\s]]) then return 'xhtml' - elseif matchregex(line, [[\c{%\s*\(extends\|block\|load\)\>\|{#\s\+]]) then + elseif + matchregex( + line, + [[\c{%\s*\(autoescape\|block\|comment\|csrf_token\|cycle\|debug\|extends\|filter\|firstof\|for\|if\|ifchanged\|include\|load\|lorem\|now\|query_string\|regroup\|resetcycle\|spaceless\|templatetag\|url\|verbatim\|widthratio\|with\)\>\|{#\s\+]] + ) + then return 'htmldjango' + elseif findany(line, { '<extend', '<super>' }) then + return 'superhtml' end end return 'html' @@ -894,6 +974,24 @@ local function m4(contents) end end +--- Check if it is a Microsoft Makefile +--- @type vim.filetype.mapfn +function M.make(_, bufnr) + vim.b.make_microsoft = nil + for _, line in ipairs(getlines(bufnr, 1, 1000)) do + if matchregex(line, [[\c^\s*!\s*\(ifn\=\(def\)\=\|include\|message\|error\)\>]]) then + vim.b.make_microsoft = 1 + break + elseif + matchregex(line, [[^ *ifn\=\(eq\|def\)\>]]) + or findany(line, { '^ *[-s]?%s', '^ *%w+%s*[!?:+]=' }) + then + break + end + end + return 'make' +end + --- @type vim.filetype.mapfn function M.markdown(_, _) return vim.g.filetype_md or 'markdown' @@ -1038,6 +1136,8 @@ function M.perl(path, bufnr) end end +local prolog_patterns = { '^%s*:%-', '^%s*%%+%s', '^%s*%%+$', '^%s*/%*', '%.%s*$' } + --- @type vim.filetype.mapfn function M.pl(_, bufnr) if vim.g.filetype_pl then @@ -1046,11 +1146,7 @@ function M.pl(_, bufnr) -- Recognize Prolog by specific text in the first non-empty line; -- require a blank after the '%' because Perl uses "%list" and "%translate" local line = nextnonblank(bufnr, 1) - if - line and line:find(':%-') - or matchregex(line, [[\c\<prolog\>]]) - or findany(line, { '^%s*%%+%s', '^%s*%%+$', '^%s*/%*' }) - then + if line and matchregex(line, [[\c\<prolog\>]]) or findany(line, prolog_patterns) then return 'prolog' else return 'perl' @@ -1154,11 +1250,7 @@ function M.proto(_, bufnr) -- Recognize Prolog by specific text in the first non-empty line; -- require a blank after the '%' because Perl uses "%list" and "%translate" local line = nextnonblank(bufnr, 1) - if - line and line:find(':%-') - or matchregex(line, [[\c\<prolog\>]]) - or findany(line, { '^%s*%%+%s', '^%s*%%+$', '^%s*/%*' }) - then + if line and matchregex(line, [[\c\<prolog\>]]) or findany(line, prolog_patterns) then return 'prolog' end end @@ -1331,7 +1423,7 @@ end function M.sgml(_, bufnr) local lines = table.concat(getlines(bufnr, 1, 5)) if lines:find('linuxdoc') then - return 'smgllnx' + return 'sgmllnx' elseif lines:find('<!DOCTYPE.*DocBook') then return 'docbk', function(b) @@ -1533,7 +1625,7 @@ function M.tex(path, bufnr) end end --- Determine if a *.tf file is TF mud client or terraform +-- Determine if a *.tf file is TF (TinyFugue) mud client or terraform --- @type vim.filetype.mapfn function M.tf(_, bufnr) for _, line in ipairs(getlines(bufnr)) do @@ -1759,6 +1851,7 @@ local patterns_hashbang = { ['^janet\\>'] = { 'janet', { vim_regex = true } }, ['^dart\\>'] = { 'dart', { vim_regex = true } }, ['^execlineb\\>'] = { 'execline', { vim_regex = true } }, + ['^vim\\>'] = { 'vim', { vim_regex = true } }, } ---@private diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua index b05220ee2c..ccddf826f7 100644 --- a/runtime/lua/vim/fs.lua +++ b/runtime/lua/vim/fs.lua @@ -1,6 +1,10 @@ +local uv = vim.uv + local M = {} -local iswin = vim.uv.os_uname().sysname == 'Windows_NT' +-- Can't use `has('win32')` because the `nvim -ll` test runner doesn't support `vim.fn` yet. +local sysname = uv.os_uname().sysname:lower() +local iswin = not not (sysname:find('windows') or sysname:find('mingw')) local os_sep = iswin and '\\' or '/' --- Iterate over all the parents of the given path. @@ -21,6 +25,7 @@ local os_sep = iswin and '\\' or '/' --- end --- ``` --- +---@since 10 ---@param start (string) Initial path. ---@return fun(_, dir: string): string? # Iterator ---@return nil @@ -40,6 +45,7 @@ end --- Return the parent directory of the given path --- +---@since 10 ---@generic T : string|nil ---@param file T Path ---@return T Parent directory of {file} @@ -69,6 +75,7 @@ end --- Return the basename of the given path --- +---@since 10 ---@generic T : string|nil ---@param file T Path ---@return T Basename of {file} @@ -89,6 +96,7 @@ end --- Concatenate directories and/or file paths into a single path with normalization --- (e.g., `"foo/"` and `"bar"` get joined to `"foo/bar"`) --- +---@since 12 ---@param ... string ---@return string function M.joinpath(...) @@ -99,6 +107,7 @@ end --- Return an iterator over the items located in {path} --- +---@since 10 ---@param path (string) An absolute or relative path to the directory to iterate --- over. The path is first normalized |vim.fs.normalize()|. --- @param opts table|nil Optional keyword arguments: @@ -122,12 +131,12 @@ function M.dir(path, opts) path = M.normalize(path) if not opts.depth or opts.depth == 1 then - local fs = vim.uv.fs_scandir(path) + local fs = uv.fs_scandir(path) return function() if not fs then return end - return vim.uv.fs_scandir_next(fs) + return uv.fs_scandir_next(fs) end end @@ -138,9 +147,9 @@ function M.dir(path, opts) --- @type string, integer local dir0, level = unpack(table.remove(dirs, 1)) local dir = level == 1 and dir0 or M.joinpath(path, dir0) - local fs = vim.uv.fs_scandir(dir) + local fs = uv.fs_scandir(dir) while fs do - local name, t = vim.uv.fs_scandir_next(fs) + local name, t = uv.fs_scandir_next(fs) if not name then break end @@ -210,6 +219,7 @@ end --- end, {limit = math.huge, type = 'file'}) --- ``` --- +---@since 10 ---@param names (string|string[]|fun(name: string, path: string): boolean) Names of the items to find. --- Must be base names, paths and globs are not supported when {names} is a string or a table. --- If {names} is a function, it is called for each traversed item with args: @@ -234,7 +244,7 @@ function M.find(names, opts) names = { names } end - local path = opts.path or assert(vim.uv.cwd()) + local path = opts.path or assert(uv.cwd()) local stop = opts.stop local limit = opts.limit or 1 @@ -265,7 +275,7 @@ function M.find(names, opts) local t = {} --- @type string[] for _, name in ipairs(names) do local f = M.joinpath(p, name) - local stat = vim.uv.fs_stat(f) + local stat = uv.fs_stat(f) if stat and (not opts.type or opts.type == stat.type) then t[#t + 1] = f end @@ -349,6 +359,7 @@ end --- end) --- ``` --- +--- @since 12 --- @param source integer|string Buffer number (0 for current buffer) or file path (absolute or --- relative to the |current-directory|) to begin the search from. --- @param marker (string|string[]|fun(name: string, path: string): boolean) A marker, or list @@ -365,7 +376,7 @@ function M.root(source, marker) path = source elseif type(source) == 'number' then if vim.bo[source].buftype ~= '' then - path = assert(vim.uv.cwd()) + path = assert(uv.cwd()) else path = vim.api.nvim_buf_get_name(source) end @@ -528,6 +539,7 @@ end --- [[\\?\UNC\server\share\foo\..\..\..\bar]] => "//?/UNC/server/share/bar" --- ``` --- +---@since 10 ---@param path (string) Path to normalize ---@param opts? vim.fs.normalize.Opts ---@return (string) : Normalized path @@ -552,7 +564,7 @@ function M.normalize(path, opts) -- Expand ~ to users home directory if vim.startswith(path, '~') then - local home = vim.uv.os_homedir() or '~' + local home = uv.os_homedir() or '~' if home:sub(-1) == os_sep_local then home = home:sub(1, -2) end @@ -561,7 +573,7 @@ function M.normalize(path, opts) -- Expand environment variables if `opts.expand_env` isn't `false` if opts.expand_env == nil or opts.expand_env then - path = path:gsub('%$([%w_]+)', vim.uv.os_getenv) + path = path:gsub('%$([%w_]+)', uv.os_getenv) end if win then @@ -609,4 +621,56 @@ function M.normalize(path, opts) return path end +--- @param path string Path to remove +--- @param ty string type of path +--- @param recursive? boolean +--- @param force? boolean +local function rm(path, ty, recursive, force) + --- @diagnostic disable-next-line:no-unknown + local rm_fn + + if ty == 'directory' then + if recursive then + for file, fty in vim.fs.dir(path) do + rm(M.joinpath(path, file), fty, true, force) + end + elseif not force then + error(string.format('%s is a directory', path)) + end + + rm_fn = uv.fs_rmdir + else + rm_fn = uv.fs_unlink + end + + local ret, err, errnm = rm_fn(path) + if ret == nil and (not force or errnm ~= 'ENOENT') then + error(err) + end +end + +--- @class vim.fs.rm.Opts +--- @inlinedoc +--- +--- Remove directories and their contents recursively +--- @field recursive? boolean +--- +--- Ignore nonexistent files and arguments +--- @field force? boolean + +--- Remove files or directories +--- @since 13 +--- @param path string Path to remove +--- @param opts? vim.fs.rm.Opts +function M.rm(path, opts) + opts = opts or {} + + local stat, err, errnm = uv.fs_stat(path) + if stat then + rm(path, stat.type, opts.recursive, opts.force) + elseif not opts.force or errnm ~= 'ENOENT' then + error(err) + end +end + return M diff --git a/runtime/lua/vim/glob.lua b/runtime/lua/vim/glob.lua index ad4a915a94..22073b15c8 100644 --- a/runtime/lua/vim/glob.lua +++ b/runtime/lua/vim/glob.lua @@ -1,6 +1,6 @@ local lpeg = vim.lpeg local P, S, V, R, B = lpeg.P, lpeg.S, lpeg.V, lpeg.R, lpeg.B -local C, Cc, Ct, Cf = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cf +local C, Cc, Ct, Cf, Cmt = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cf, lpeg.Cmt local M = {} @@ -29,8 +29,10 @@ function M.to_lpeg(pattern) return patt end - local function add(acc, a) - return acc + a + local function condlist(conds, after) + return vim.iter(conds):fold(P(false), function(acc, cond) + return acc + cond * after + end) end local function mul(acc, m) @@ -45,13 +47,22 @@ function M.to_lpeg(pattern) return (-after * P(1)) ^ 0 * after end + -- luacheck: push ignore s + local function cut(s, idx, match) + return idx, match + end + -- luacheck: pop + local p = P({ 'Pattern', Pattern = V('Elem') ^ -1 * V('End'), - Elem = Cf( - (V('DStar') + V('Star') + V('Ques') + V('Class') + V('CondList') + V('Literal')) - * (V('Elem') + V('End')), - mul + Elem = Cmt( + Cf( + (V('DStar') + V('Star') + V('Ques') + V('Class') + V('CondList') + V('Literal')) + * (V('Elem') + V('End')), + mul + ), + cut ), DStar = (B(pathsep) + -B(P(1))) * P('**') @@ -63,15 +74,14 @@ function M.to_lpeg(pattern) * C(P('!') ^ -1) * Ct(Ct(C(P(1)) * P('-') * C(P(1) - P(']'))) ^ 1 * P(']')) / class, - CondList = P('{') * Cf(V('Cond') * (P(',') * V('Cond')) ^ 0, add) * P('}'), + CondList = P('{') * Ct(V('Cond') * (P(',') * V('Cond')) ^ 0) * P('}') * V('Pattern') / condlist, -- TODO: '*' inside a {} condition is interpreted literally but should probably have the same -- wildcard semantics it usually has. -- Fixing this is non-trivial because '*' should match non-greedily up to "the rest of the -- pattern" which in all other cases is the entire succeeding part of the pattern, but at the end of a {} -- condition means "everything after the {}" where several other options separated by ',' may -- exist in between that should not be matched by '*'. - Cond = Cf((V('Ques') + V('Class') + V('CondList') + (V('Literal') - S(',}'))) ^ 1, mul) - + Cc(P(0)), + Cond = Cmt(Cf((V('Ques') + V('Class') + V('Literal') - S(',}')) ^ 1, mul), cut) + Cc(P(0)), Literal = P(1) / P, End = P(-1) * Cc(P(-1)), }) diff --git a/runtime/lua/vim/health.lua b/runtime/lua/vim/health.lua index f40f04a064..52a7a13966 100644 --- a/runtime/lua/vim/health.lua +++ b/runtime/lua/vim/health.lua @@ -1,6 +1,6 @@ --- @brief ---<pre>help ---- health.vim is a minimal framework to help users troubleshoot configuration and +--- vim.health is a minimal framework to help users troubleshoot configuration and --- any other environment conditions that a plugin might care about. Nvim ships --- with healthchecks for configuration, performance, python support, ruby --- support, clipboard support, and more. @@ -39,7 +39,7 @@ --- :checkhealth vim* --- < --- ---- Create a healthcheck *health-dev* *vim.health* +--- Create a healthcheck *health-dev* --- --- Healthchecks are functions that check the user environment, configuration, or --- any other prerequisites that a plugin cares about. Nvim ships with @@ -104,10 +104,10 @@ local function filepath_to_healthcheck(path) local subpath = path:gsub('.*lua/', '') if vim.fs.basename(subpath) == 'health.lua' then -- */health.lua - name = assert(vim.fs.dirname(subpath)) + name = vim.fs.dirname(subpath) else -- */health/init.lua - name = assert(vim.fs.dirname(assert(vim.fs.dirname(subpath)))) + name = vim.fs.dirname(vim.fs.dirname(subpath)) end name = name:gsub('/', '.') @@ -275,114 +275,6 @@ function M.error(msg, ...) collect_output(input) end -function M._provider_disabled(provider) - local loaded_var = 'loaded_' .. provider .. '_provider' - local v = vim.g[loaded_var] - if v == 0 then - M.info('Disabled (' .. loaded_var .. '=' .. v .. ').') - return true - end - return false -end - --- Handler for s:system() function. -local function system_handler(self, _, data, event) - if event == 'stderr' then - if self.add_stderr_to_output then - self.output = self.output .. table.concat(data, '') - else - self.stderr = self.stderr .. table.concat(data, '') - end - elseif event == 'stdout' then - self.output = self.output .. table.concat(data, '') - end -end - --- Attempts to construct a shell command from an args list. --- Only for display, to help users debug a failed command. -local function shellify(cmd) - if type(cmd) ~= 'table' then - return cmd - end - local escaped = {} - for i, v in ipairs(cmd) do - if v:match('[^A-Za-z_/.-]') then - escaped[i] = vim.fn.shellescape(v) - else - escaped[i] = v - end - end - return table.concat(escaped, ' ') -end - -function M._cmd_ok(cmd) - local out = vim.fn.system(cmd) - return vim.v.shell_error == 0, out -end - ---- Run a system command and timeout after 30 seconds. ---- ---- @param cmd table List of command arguments to execute ---- @param args? table Optional arguments: ---- - stdin (string): Data to write to the job's stdin ---- - stderr (boolean): Append stderr to stdout ---- - ignore_error (boolean): If true, ignore error output ---- - timeout (number): Number of seconds to wait before timing out (default 30) -function M._system(cmd, args) - args = args or {} - local stdin = args.stdin or '' - local stderr = vim.F.if_nil(args.stderr, false) - local ignore_error = vim.F.if_nil(args.ignore_error, false) - - local shell_error_code = 0 - local opts = { - add_stderr_to_output = stderr, - output = '', - stderr = '', - on_stdout = system_handler, - on_stderr = system_handler, - on_exit = function(_, data) - shell_error_code = data - end, - } - local jobid = vim.fn.jobstart(cmd, opts) - - if jobid < 1 then - local message = - string.format('Command error (job=%d): %s (in %s)', jobid, shellify(cmd), vim.uv.cwd()) - error(message) - return opts.output, 1 - end - - if stdin:find('^%s$') then - vim.fn.chansend(jobid, stdin) - end - - local res = vim.fn.jobwait({ jobid }, vim.F.if_nil(args.timeout, 30) * 1000) - if res[1] == -1 then - error('Command timed out: ' .. shellify(cmd)) - vim.fn.jobstop(jobid) - elseif shell_error_code ~= 0 and not ignore_error then - local emsg = string.format( - 'Command error (job=%d, exit code %d): %s (in %s)', - jobid, - shell_error_code, - shellify(cmd), - vim.uv.cwd() - ) - if opts.output:find('%S') then - emsg = string.format('%s\noutput: %s', emsg, opts.output) - end - if opts.stderr:find('%S') then - emsg = string.format('%s\nstderr: %s', emsg, opts.stderr) - end - error(emsg) - end - - -- return opts.output - return vim.trim(vim.fn.system(cmd)), shell_error_code -end - local path2name = function(path) if path:match('%.lua$') then -- Lua: transform "../lua/vim/lsp/health.lua" into "vim.lsp" @@ -393,8 +285,8 @@ local path2name = function(path) -- Remove everything up to the last /lua/ folder path = path:gsub('^.*/lua/', '') - -- Remove the filename (health.lua) - path = vim.fs.dirname(path) + -- Remove the filename (health.lua) or (health/init.lua) + path = vim.fs.dirname(path:gsub('/init%.lua$', '')) -- Change slashes to dots path = path:gsub('/', '.') @@ -409,11 +301,13 @@ end local PATTERNS = { '/autoload/health/*.vim', '/lua/**/**/health.lua', '/lua/**/**/health/init.lua' } --- :checkhealth completion function used by cmdexpand.c get_healthcheck_names() M._complete = function() - local unique = vim + local unique = vim ---@type table<string,boolean> + ---@param pattern string .iter(vim.tbl_map(function(pattern) return vim.tbl_map(path2name, vim.api.nvim_get_runtime_file(pattern, true)) end, PATTERNS)) :flatten() + ---@param t table<string,boolean> :fold({}, function(t, name) t[name] = true -- Remove duplicates return t @@ -472,7 +366,7 @@ function M._check(mods, plugin_names) vim.fn.call(func, {}) else local f = assert(loadstring(func)) - local ok, output = pcall(f) + local ok, output = pcall(f) ---@type boolean, string if not ok then M.error( string.format('Failed to run healthcheck for "%s" plugin. Exception:\n%s\n', name, output) @@ -485,7 +379,14 @@ function M._check(mods, plugin_names) s_output = {} M.error('The healthcheck report for "' .. name .. '" plugin is empty.') end - local header = { string.rep('=', 78), name .. ': ' .. func, '' } + + local header = { + string.rep('=', 78), + -- Example: `foo.health: [ …] require("foo.health").check()` + ('%s: %s%s'):format(name, (' '):rep(76 - name:len() - func:len()), func), + '', + } + -- remove empty line after header from report_start if s_output[1] == '' then local tmp = {} ---@type string[] @@ -499,7 +400,7 @@ function M._check(mods, plugin_names) end s_output[#s_output + 1] = '' s_output = vim.list_extend(header, s_output) - vim.fn.append('$', s_output) + vim.fn.append(vim.fn.line('$'), s_output) vim.cmd.redraw() end diff --git a/runtime/lua/vim/health/health.lua b/runtime/lua/vim/health/health.lua index 5bc03199ee..d226f35f9a 100644 --- a/runtime/lua/vim/health/health.lua +++ b/runtime/lua/vim/health/health.lua @@ -11,10 +11,14 @@ local function check_runtime() health.start('Runtime') -- Files from an old installation. local bad_files = { - ['plugin/health.vim'] = false, ['autoload/health/nvim.vim'] = false, ['autoload/health/provider.vim'] = false, ['autoload/man.vim'] = false, + ['lua/provider/node/health.lua'] = false, + ['lua/provider/perl/health.lua'] = false, + ['lua/provider/python/health.lua'] = false, + ['lua/provider/ruby/health.lua'] = false, + ['plugin/health.vim'] = false, ['plugin/man.vim'] = false, ['queries/help/highlights.scm'] = false, ['queries/help/injections.scm'] = false, @@ -39,7 +43,7 @@ local function check_runtime() 'Found old files in $VIMRUNTIME (this can cause weird behavior):\n%s', bad_files_msg ), - { 'Delete the $VIMRUNTIME directory (or uninstall Nvim), then reinstall Nvim.' } + { 'Delete the $VIMRUNTIME directory, then reinstall Nvim.' } ) end end @@ -50,11 +54,11 @@ local function check_config() local init_lua = vim.fn.stdpath('config') .. '/init.lua' local init_vim = vim.fn.stdpath('config') .. '/init.vim' - local vimrc = vim.env.MYVIMRC and vim.fn.expand(vim.env.MYVIMRC) or init_lua + local vimrc = vim.env.MYVIMRC and vim.fs.normalize(vim.env.MYVIMRC) or init_lua if vim.fn.filereadable(vimrc) == 0 and vim.fn.filereadable(init_vim) == 0 then ok = false - local has_vim = vim.fn.filereadable(vim.fn.expand('~/.vimrc')) == 1 + local has_vim = vim.fn.filereadable(vim.fs.normalize('~/.vimrc')) == 1 health.warn( ('%s user config file: %s'):format( -1 == vim.fn.getfsize(vimrc) and 'Missing' or 'Unreadable', @@ -114,7 +118,7 @@ local function check_config() ) shadafile = ( vim.o.shadafile == '' - and (shadafile == '' and vim.fn.stdpath('state') .. '/shada/main.shada' or vim.fn.expand( + and (shadafile == '' and vim.fn.stdpath('state') .. '/shada/main.shada' or vim.fs.normalize( shadafile )) or (vim.o.shadafile == 'NONE' and '' or vim.o.shadafile) @@ -239,6 +243,7 @@ local function check_tmux() return end + ---@param option string local get_tmux_option = function(option) local cmd = 'tmux show-option -qvg ' .. option -- try global scope local out = vim.fn.system(vim.fn.split(cmd)) @@ -378,7 +383,7 @@ local function check_terminal() 'SSH_TTY', }) do if vim.env[env_var] then - health.info(vim.fn.printf('$%s="%s"', env_var, vim.env[env_var])) + health.info(string.format('$%s="%s"', env_var, vim.env[env_var])) end end end diff --git a/runtime/lua/vim/highlight.lua b/runtime/lua/vim/highlight.lua index f278bd357f..a8d88db372 100644 --- a/runtime/lua/vim/highlight.lua +++ b/runtime/lua/vim/highlight.lua @@ -20,8 +20,8 @@ M.priorities = { --- @class vim.highlight.range.Opts --- @inlinedoc --- ---- Type of range. See [setreg()] ---- (default: `'charwise'`) +--- Type of range. See [getregtype()] +--- (default: `'v'` i.e. charwise) --- @field regtype? string --- --- Indicates whether the range is end-inclusive @@ -31,8 +31,6 @@ M.priorities = { --- Indicates priority of highlight --- (default: `vim.highlight.priorities.user`) --- @field priority? integer ---- ---- @field package _scoped? boolean --- Apply highlight group to range of text. --- @@ -47,25 +45,72 @@ function M.range(bufnr, ns, higroup, start, finish, opts) local regtype = opts.regtype or 'v' local inclusive = opts.inclusive or false local priority = opts.priority or M.priorities.user - local scoped = opts._scoped or false - - -- TODO: in case of 'v', 'V' (not block), this should calculate equivalent - -- bounds (row, col, end_row, end_col) as multiline regions are natively - -- supported now - local region = vim.region(bufnr, start, finish, regtype, inclusive) - for linenr, cols in pairs(region) do - local end_row - if cols[2] == -1 then - end_row = linenr + 1 - cols[2] = 0 + + local v_maxcol = vim.v.maxcol + + local pos1 = type(start) == 'string' and vim.fn.getpos(start) + or { + bufnr, + start[1] + 1, + start[2] ~= -1 and start[2] ~= v_maxcol and start[2] + 1 or v_maxcol, + 0, + } + local pos2 = type(finish) == 'string' and vim.fn.getpos(finish) + or { + bufnr, + finish[1] + 1, + finish[2] ~= -1 and start[2] ~= v_maxcol and finish[2] + 1 or v_maxcol, + 0, + } + + local buf_line_count = vim.api.nvim_buf_line_count(bufnr) + pos1[2] = math.min(pos1[2], buf_line_count) + pos2[2] = math.min(pos2[2], buf_line_count) + + if pos1[2] <= 0 or pos1[3] <= 0 or pos2[2] <= 0 or pos2[3] <= 0 then + return + end + + vim._with({ buf = bufnr }, function() + if pos1[3] ~= v_maxcol then + local max_col1 = vim.fn.col({ pos1[2], '$' }) + pos1[3] = math.min(pos1[3], max_col1) + end + if pos2[3] ~= v_maxcol then + local max_col2 = vim.fn.col({ pos2[2], '$' }) + pos2[3] = math.min(pos2[3], max_col2) end - api.nvim_buf_set_extmark(bufnr, ns, linenr, cols[1], { + end) + + local region = vim.fn.getregionpos(pos1, pos2, { + type = regtype, + exclusive = not inclusive, + eol = true, + }) + -- For non-blockwise selection, use a single extmark. + if regtype == 'v' or regtype == 'V' then + region = { { region[1][1], region[#region][2] } } + if + regtype == 'V' + or region[1][2][2] == pos1[2] and pos1[3] == v_maxcol + or region[1][2][2] == pos2[2] and pos2[3] == v_maxcol + then + region[1][2][2] = region[1][2][2] + 1 + region[1][2][3] = 0 + end + end + + for _, res in ipairs(region) do + local start_row = res[1][2] - 1 + local start_col = res[1][3] - 1 + local end_row = res[2][2] - 1 + local end_col = res[2][3] + api.nvim_buf_set_extmark(bufnr, ns, start_row, start_col, { hl_group = higroup, end_row = end_row, - end_col = cols[2], + end_col = end_col, priority = priority, strict = false, - scoped = scoped, }) end end @@ -129,19 +174,18 @@ function M.on_yank(opts) yank_cancel() end - vim.api.nvim__win_add_ns(winid, yank_ns) + vim.api.nvim__ns_set(yank_ns, { wins = { winid } }) M.range(bufnr, yank_ns, higroup, "'[", "']", { regtype = event.regtype, inclusive = event.inclusive, priority = opts.priority or M.priorities.user, - _scoped = true, }) yank_cancel = function() yank_timer = nil yank_cancel = nil pcall(vim.api.nvim_buf_clear_namespace, bufnr, yank_ns, 0, -1) - pcall(vim.api.nvim__win_del_ns, winid, yank_ns) + pcall(vim.api.nvim__ns_set, { wins = {} }) end yank_timer = vim.defer_fn(yank_cancel, timeout) diff --git a/runtime/lua/vim/iter.lua b/runtime/lua/vim/iter.lua index 1093759efe..4bbcaf16db 100644 --- a/runtime/lua/vim/iter.lua +++ b/runtime/lua/vim/iter.lua @@ -6,10 +6,12 @@ --- of each pipeline stage is input to the next stage. The first stage depends on the type passed to --- `vim.iter()`: --- ---- - List tables (arrays, |lua-list|) yield only the value of each element. ---- - Holes (nil values) are allowed. +--- - Lists or arrays (|lua-list|) yield only the value of each element. +--- - Holes (nil values) are allowed (but discarded). +--- - Use pairs() to treat array/list tables as dicts (preserve holes and non-contiguous integer +--- keys): `vim.iter(pairs(…))`. --- - Use |Iter:enumerate()| to also pass the index to the next stage. ---- - Or initialize with ipairs(): `vim.iter(ipairs(…))`. +--- - Or initialize with ipairs(): `vim.iter(ipairs(…))`. --- - Non-list tables (|lua-dict|) yield both the key and value of each element. --- - Function |iterator|s yield all values returned by the underlying function. --- - Tables with a |__call()| metamethod are treated as function iterators. @@ -276,7 +278,7 @@ end --- -- { 6, 12 } --- ``` --- ----@param f fun(...):any Mapping function. Takes all values returned from +---@param f fun(...):...:any Mapping function. Takes all values returned from --- the previous stage in the pipeline as arguments --- and returns one or more new values, which are used --- in the next pipeline stage. Nil return values @@ -1034,7 +1036,7 @@ function Iter.new(src, ...) if type(k) ~= 'number' or k <= 0 or math.floor(k) ~= k then return Iter.new(pairs(src)) end - t[#t + 1] = v + t[#t + 1] = v -- Coerce to list-like table. end return ArrayIter.new(t) end diff --git a/runtime/lua/vim/keymap.lua b/runtime/lua/vim/keymap.lua index ec00c56c7a..50ca0d2d0e 100644 --- a/runtime/lua/vim/keymap.lua +++ b/runtime/lua/vim/keymap.lua @@ -15,30 +15,28 @@ local keymap = {} --- (Default: `false`) --- @field remap? boolean ---- Adds a new |mapping|. +--- Defines a |mapping| of |keycodes| to a function or keycodes. +--- --- Examples: --- --- ```lua ---- -- Map to a Lua function: ---- vim.keymap.set('n', 'lhs', function() print("real lua function") end) ---- -- Map to multiple modes: ---- vim.keymap.set({'n', 'v'}, '<leader>lr', vim.lsp.buf.references, { buffer = true }) ---- -- Buffer-local mapping: ---- vim.keymap.set('n', '<leader>w', "<cmd>w<cr>", { silent = true, buffer = 5 }) ---- -- Expr mapping: +--- -- Map "x" to a Lua function: +--- vim.keymap.set('n', 'x', function() print("real lua function") end) +--- -- Map "<leader>x" to multiple modes for the current buffer: +--- vim.keymap.set({'n', 'v'}, '<leader>x', vim.lsp.buf.references, { buffer = true }) +--- -- Map <Tab> to an expression (|:map-<expr>|): --- vim.keymap.set('i', '<Tab>', function() --- return vim.fn.pumvisible() == 1 and "<C-n>" or "<Tab>" --- end, { expr = true }) ---- -- <Plug> mapping: +--- -- Map "[%%" to a <Plug> mapping: --- vim.keymap.set('n', '[%%', '<Plug>(MatchitNormalMultiBackward)') --- ``` --- ----@param mode string|string[] Mode short-name, see |nvim_set_keymap()|. ---- Can also be list of modes to create mapping on multiple modes. +---@param mode string|string[] Mode "short-name" (see |nvim_set_keymap()|), or a list thereof. ---@param lhs string Left-hand side |{lhs}| of the mapping. ---@param rhs string|function Right-hand side |{rhs}| of the mapping, can be a Lua function. ---- ---@param opts? vim.keymap.set.Opts +--- ---@see |nvim_set_keymap()| ---@see |maparg()| ---@see |mapcheck()| diff --git a/runtime/lua/vim/loader.lua b/runtime/lua/vim/loader.lua index ea77a22416..e86d33bf53 100644 --- a/runtime/lua/vim/loader.lua +++ b/runtime/lua/vim/loader.lua @@ -200,7 +200,7 @@ function Loader.loader(modname) return chunk or error(err) end Loader._hashes = nil - return '\ncache_loader: module ' .. modname .. ' not found' + return ("\n\tcache_loader: module '%s' not found"):format(modname) end --- The `package.loaders` loader for libs @@ -208,8 +208,7 @@ end ---@return string|function ---@private function Loader.loader_lib(modname) - local sysname = uv.os_uname().sysname:lower() or '' - local is_win = sysname:find('win', 1, true) and not sysname:find('darwin', 1, true) + local is_win = vim.fn.has('win32') == 1 local ret = M.find(modname, { patterns = is_win and { '.dll' } or { '.so' } })[1] if ret then -- Making function name in Lua 5.1 (see src/loadlib.c:mkfuncname) is @@ -222,7 +221,7 @@ function Loader.loader_lib(modname) local chunk, err = package.loadlib(ret.modpath, 'luaopen_' .. funcname:gsub('%.', '_')) return chunk or error(err) end - return '\ncache_loader_lib: module ' .. modname .. ' not found' + return ("\n\tcache_loader_lib: module '%s' not found"):format(modname) end --- `loadfile` using the cache @@ -290,6 +289,9 @@ function Loader.load(modpath, opts) end --- Finds Lua modules for the given module name. +--- +--- @since 0 +--- ---@param modname string Module name, or `"*"` to find the top-level modules instead ---@param opts? vim.loader.find.Opts Options for finding a module: ---@return vim.loader.ModuleInfo[] @@ -378,8 +380,10 @@ function M.find(modname, opts) return results end ---- Resets the cache for the path, or all the paths ---- if path is nil. +--- Resets the cache for the path, or all the paths if path is nil. +--- +--- @since 0 +--- ---@param path string? path to reset function M.reset(path) if path then @@ -399,6 +403,8 @@ end --- * adds the Lua loader using the byte-compilation cache --- * adds the libs loader --- * removes the default Nvim loader +--- +--- @since 0 function M.enable() if M.enabled then return @@ -422,6 +428,8 @@ end --- Disables the experimental Lua module loader: --- * removes the loaders --- * adds the default Nvim loader +--- +--- @since 0 function M.disable() if not M.enabled then return diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 1592fd3151..60677554ce 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -3,7 +3,6 @@ local validate = vim.validate local lsp = vim._defer_require('vim.lsp', { _changetracking = ..., --- @module 'vim.lsp._changetracking' - _completion = ..., --- @module 'vim.lsp._completion' _dynamic = ..., --- @module 'vim.lsp._dynamic' _snippet_grammar = ..., --- @module 'vim.lsp._snippet_grammar' _tagfunc = ..., --- @module 'vim.lsp._tagfunc' @@ -11,6 +10,7 @@ local lsp = vim._defer_require('vim.lsp', { buf = ..., --- @module 'vim.lsp.buf' client = ..., --- @module 'vim.lsp.client' codelens = ..., --- @module 'vim.lsp.codelens' + completion = ..., --- @module 'vim.lsp.completion' diagnostic = ..., --- @module 'vim.lsp.diagnostic' handlers = ..., --- @module 'vim.lsp.handlers' inlay_hint = ..., --- @module 'vim.lsp.inlay_hint' @@ -33,43 +33,50 @@ lsp.rpc_response_error = lsp.rpc.rpc_response_error -- maps request name to the required server_capability in the client. lsp._request_name_to_capability = { - [ms.textDocument_hover] = { 'hoverProvider' }, - [ms.textDocument_signatureHelp] = { 'signatureHelpProvider' }, - [ms.textDocument_definition] = { 'definitionProvider' }, - [ms.textDocument_implementation] = { 'implementationProvider' }, - [ms.textDocument_declaration] = { 'declarationProvider' }, - [ms.textDocument_typeDefinition] = { 'typeDefinitionProvider' }, - [ms.textDocument_documentSymbol] = { 'documentSymbolProvider' }, - [ms.textDocument_prepareCallHierarchy] = { 'callHierarchyProvider' }, [ms.callHierarchy_incomingCalls] = { 'callHierarchyProvider' }, [ms.callHierarchy_outgoingCalls] = { 'callHierarchyProvider' }, - [ms.textDocument_prepareTypeHierarchy] = { 'typeHierarchyProvider' }, - [ms.typeHierarchy_subtypes] = { 'typeHierarchyProvider' }, - [ms.typeHierarchy_supertypes] = { 'typeHierarchyProvider' }, - [ms.textDocument_rename] = { 'renameProvider' }, - [ms.textDocument_prepareRename] = { 'renameProvider', 'prepareProvider' }, + [ms.codeAction_resolve] = { 'codeActionProvider', 'resolveProvider' }, + [ms.codeLens_resolve] = { 'codeLensProvider', 'resolveProvider' }, + [ms.documentLink_resolve] = { 'documentLinkProvider', 'resolveProvider' }, + [ms.inlayHint_resolve] = { 'inlayHintProvider', 'resolveProvider' }, [ms.textDocument_codeAction] = { 'codeActionProvider' }, [ms.textDocument_codeLens] = { 'codeLensProvider' }, - [ms.codeLens_resolve] = { 'codeLensProvider', 'resolveProvider' }, - [ms.codeAction_resolve] = { 'codeActionProvider', 'resolveProvider' }, - [ms.workspace_executeCommand] = { 'executeCommandProvider' }, - [ms.workspace_symbol] = { 'workspaceSymbolProvider' }, - [ms.textDocument_references] = { 'referencesProvider' }, - [ms.textDocument_rangeFormatting] = { 'documentRangeFormattingProvider' }, - [ms.textDocument_formatting] = { 'documentFormattingProvider' }, [ms.textDocument_completion] = { 'completionProvider' }, - [ms.textDocument_documentHighlight] = { 'documentHighlightProvider' }, - [ms.textDocument_semanticTokens_full] = { 'semanticTokensProvider' }, - [ms.textDocument_semanticTokens_full_delta] = { 'semanticTokensProvider' }, - [ms.textDocument_inlayHint] = { 'inlayHintProvider' }, + [ms.textDocument_declaration] = { 'declarationProvider' }, + [ms.textDocument_definition] = { 'definitionProvider' }, [ms.textDocument_diagnostic] = { 'diagnosticProvider' }, - [ms.inlayHint_resolve] = { 'inlayHintProvider', 'resolveProvider' }, - [ms.textDocument_documentLink] = { 'documentLinkProvider' }, - [ms.documentLink_resolve] = { 'documentLinkProvider', 'resolveProvider' }, [ms.textDocument_didClose] = { 'textDocumentSync', 'openClose' }, [ms.textDocument_didOpen] = { 'textDocumentSync', 'openClose' }, - [ms.textDocument_willSave] = { 'textDocumentSync', 'willSave' }, + [ms.textDocument_documentColor] = { 'colorProvider' }, + [ms.textDocument_documentHighlight] = { 'documentHighlightProvider' }, + [ms.textDocument_documentLink] = { 'documentLinkProvider' }, + [ms.textDocument_documentSymbol] = { 'documentSymbolProvider' }, + [ms.textDocument_formatting] = { 'documentFormattingProvider' }, + [ms.textDocument_hover] = { 'hoverProvider' }, + [ms.textDocument_implementation] = { 'implementationProvider' }, + [ms.textDocument_inlayHint] = { 'inlayHintProvider' }, + [ms.textDocument_inlineValue] = { 'inlineValueProvider' }, + [ms.textDocument_linkedEditingRange] = { 'linkedEditingRangeProvider' }, + [ms.textDocument_moniker] = { 'monikerProvider' }, + [ms.textDocument_onTypeFormatting] = { 'documentOnTypeFormattingProvider' }, + [ms.textDocument_prepareCallHierarchy] = { 'callHierarchyProvider' }, + [ms.textDocument_prepareRename] = { 'renameProvider', 'prepareProvider' }, + [ms.textDocument_prepareTypeHierarchy] = { 'typeHierarchyProvider' }, + [ms.textDocument_rangeFormatting] = { 'documentRangeFormattingProvider' }, + [ms.textDocument_rangesFormatting] = { 'documentRangeFormattingProvider', 'rangesSupport' }, + [ms.textDocument_references] = { 'referencesProvider' }, + [ms.textDocument_rename] = { 'renameProvider' }, + [ms.textDocument_selectionRange] = { 'selectionRangeProvider' }, + [ms.textDocument_semanticTokens_full] = { 'semanticTokensProvider' }, + [ms.textDocument_semanticTokens_full_delta] = { 'semanticTokensProvider' }, + [ms.textDocument_signatureHelp] = { 'signatureHelpProvider' }, + [ms.textDocument_typeDefinition] = { 'typeDefinitionProvider' }, [ms.textDocument_willSaveWaitUntil] = { 'textDocumentSync', 'willSaveWaitUntil' }, + [ms.textDocument_willSave] = { 'textDocumentSync', 'willSave' }, + [ms.typeHierarchy_subtypes] = { 'typeHierarchyProvider' }, + [ms.typeHierarchy_supertypes] = { 'typeHierarchyProvider' }, + [ms.workspace_executeCommand] = { 'executeCommandProvider' }, + [ms.workspace_symbol] = { 'workspaceSymbolProvider' }, } -- TODO improve handling of scratch buffers with LSP attached. @@ -201,10 +208,10 @@ end --- Predicate used to decide if a client should be re-used. Used on all --- running clients. The default implementation re-uses a client if name and --- root_dir matches. ---- @field reuse_client fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean +--- @field reuse_client? fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean --- --- Buffer handle to attach to if starting or re-using a client (0 for current). ---- @field bufnr integer +--- @field bufnr? integer --- --- Suppress error reporting if the LSP server fails to start (default false). --- @field silent? boolean @@ -351,7 +358,7 @@ function lsp._set_defaults(client, bufnr) then vim.bo[bufnr].formatexpr = 'v:lua.vim.lsp.formatexpr()' end - api.nvim_buf_call(bufnr, function() + vim._with({ buf = bufnr }, function() if client.supports_method(ms.textDocument_hover) and is_empty_or_default(bufnr, 'keywordprg') @@ -377,9 +384,9 @@ local function reset_defaults(bufnr) if vim.bo[bufnr].formatexpr == 'v:lua.vim.lsp.formatexpr()' then vim.bo[bufnr].formatexpr = nil end - api.nvim_buf_call(bufnr, function() + vim._with({ buf = bufnr }, function() local keymap = vim.fn.maparg('K', 'n', false, true) - if keymap and keymap.callback == vim.lsp.buf.hover then + if keymap and keymap.callback == vim.lsp.buf.hover and keymap.buffer == 1 then vim.keymap.del('n', 'K', { buffer = bufnr }) end end) @@ -391,9 +398,9 @@ end local function on_client_exit(code, signal, client_id) local client = all_clients[client_id] - for bufnr in pairs(client.attached_buffers) do - vim.schedule(function() - if client and client.attached_buffers[bufnr] then + vim.schedule(function() + for bufnr in pairs(client.attached_buffers) do + if client and client.attached_buffers[bufnr] and api.nvim_buf_is_valid(bufnr) then api.nvim_exec_autocmds('LspDetach', { buffer = bufnr, modeline = false, @@ -401,15 +408,16 @@ local function on_client_exit(code, signal, client_id) }) end - local namespace = vim.lsp.diagnostic.get_namespace(client_id) - vim.diagnostic.reset(namespace, bufnr) client.attached_buffers[bufnr] = nil if #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 then reset_defaults(bufnr) end - end) - end + end + + local namespace = vim.lsp.diagnostic.get_namespace(client_id) + vim.diagnostic.reset(namespace) + end) local name = client.name or 'unknown' @@ -519,7 +527,6 @@ local function buf_detach_client(bufnr, client) end client.attached_buffers[bufnr] = nil - util.buf_versions[bufnr] = nil local namespace = lsp.diagnostic.get_namespace(client.id) vim.diagnostic.reset(namespace, bufnr) @@ -577,7 +584,8 @@ local function buf_attach(bufnr) api.nvim_buf_attach(bufnr, false, { on_lines = function(_, _, changedtick, firstline, lastline, new_lastline) if #lsp.get_clients({ bufnr = bufnr }) == 0 then - return true -- detach + -- detach if there are no clients + return #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 end util.buf_versions[bufnr] = changedtick changetracking.send_changes(bufnr, firstline, lastline, new_lastline) @@ -603,6 +611,7 @@ local function buf_attach(bufnr) buf_detach_client(bufnr, client) end attached_buffers[bufnr] = nil + util.buf_versions[bufnr] = nil end, -- TODO if we know all of the potential clients ahead of time, then we @@ -852,17 +861,20 @@ api.nvim_create_autocmd('VimLeavePre', { ---@param params table|nil Parameters to send to the server ---@param handler? lsp.Handler See |lsp-handler| --- If nil, follows resolution strategy defined in |lsp-handler-configuration| ---- +---@param on_unsupported? fun() +--- The function to call when the buffer has no clients that support the given method. +--- Defaults to an `ERROR` level notification. ---@return table<integer, integer> client_request_ids Map of client-id:request-id pairs ---for all successful requests. ---@return function _cancel_all_requests Function which can be used to ---cancel all the requests. You could instead ---iterate all clients and call their `cancel_request()` methods. -function lsp.buf_request(bufnr, method, params, handler) +function lsp.buf_request(bufnr, method, params, handler, on_unsupported) validate({ bufnr = { bufnr, 'n', true }, method = { method, 's' }, handler = { handler, 'f', true }, + on_unsupported = { on_unsupported, 'f', true }, }) bufnr = resolve_bufnr(bufnr) @@ -884,7 +896,11 @@ function lsp.buf_request(bufnr, method, params, handler) -- if has client but no clients support the given method, notify the user if next(clients) and not method_supported then - vim.notify(lsp._unsupported_method(method), vim.log.levels.ERROR) + if on_unsupported == nil then + vim.notify(lsp._unsupported_method(method), vim.log.levels.ERROR) + else + on_unsupported() + end vim.cmd.redraw() return {}, function() end end @@ -1002,8 +1018,7 @@ end --- - findstart=0: column where the completion starts, or -2 or -3 --- - findstart=1: list of matches (actually just calls |complete()|) function lsp.omnifunc(findstart, base) - log.debug('omnifunc.findstart', { findstart = findstart, base = base }) - return vim.lsp._completion.omnifunc(findstart, base) + return vim.lsp.completion._omnifunc(findstart, base) end --- @class vim.lsp.formatexpr.Opts @@ -1016,7 +1031,7 @@ end --- Provides an interface between the built-in client and a `formatexpr` function. --- --- Currently only supports a single client. This can be set via ---- `setlocal formatexpr=v:lua.vim.lsp.formatexpr()` but will typically or in `on_attach` +--- `setlocal formatexpr=v:lua.vim.lsp.formatexpr()` or (more typically) in `on_attach` --- via `vim.bo[bufnr].formatexpr = 'v:lua.vim.lsp.formatexpr(#{timeout_ms:250})'`. --- ---@param opts? vim.lsp.formatexpr.Opts diff --git a/runtime/lua/vim/lsp/_completion.lua b/runtime/lua/vim/lsp/_completion.lua deleted file mode 100644 index a169f96565..0000000000 --- a/runtime/lua/vim/lsp/_completion.lua +++ /dev/null @@ -1,276 +0,0 @@ -local M = {} -local api = vim.api -local lsp = vim.lsp -local protocol = lsp.protocol -local ms = protocol.Methods - ---- @alias vim.lsp.CompletionResult lsp.CompletionList | lsp.CompletionItem[] - --- TODO(mariasolos): Remove this declaration once we figure out a better way to handle --- literal/anonymous types (see https://github.com/neovim/neovim/pull/27542/files#r1495259331). ---- @class lsp.ItemDefaults ---- @field editRange lsp.Range | { insert: lsp.Range, replace: lsp.Range } | nil ---- @field insertTextFormat lsp.InsertTextFormat? ---- @field insertTextMode lsp.InsertTextMode? ---- @field data any - ----@param input string unparsed snippet ----@return string parsed snippet -local function parse_snippet(input) - local ok, parsed = pcall(function() - return vim.lsp._snippet_grammar.parse(input) - end) - return ok and tostring(parsed) or input -end - ---- Returns text that should be inserted when selecting completion item. The ---- precedence is as follows: textEdit.newText > insertText > label ---- ---- See https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion ---- ----@param item lsp.CompletionItem ----@return string -local function get_completion_word(item) - if item.textEdit ~= nil and item.textEdit.newText ~= nil and item.textEdit.newText ~= '' then - if item.insertTextFormat == protocol.InsertTextFormat.PlainText then - return item.textEdit.newText - else - return parse_snippet(item.textEdit.newText) - end - elseif item.insertText ~= nil and item.insertText ~= '' then - if item.insertTextFormat == protocol.InsertTextFormat.PlainText then - return item.insertText - else - return parse_snippet(item.insertText) - end - end - return item.label -end - ---- Applies the given defaults to the completion item, modifying it in place. ---- ---- @param item lsp.CompletionItem ---- @param defaults lsp.ItemDefaults? -local function apply_defaults(item, defaults) - if not defaults then - return - end - - item.insertTextFormat = item.insertTextFormat or defaults.insertTextFormat - item.insertTextMode = item.insertTextMode or defaults.insertTextMode - item.data = item.data or defaults.data - if defaults.editRange then - local textEdit = item.textEdit or {} - item.textEdit = textEdit - textEdit.newText = textEdit.newText or item.textEditText or item.insertText - if defaults.editRange.start then - textEdit.range = textEdit.range or defaults.editRange - elseif defaults.editRange.insert then - textEdit.insert = defaults.editRange.insert - textEdit.replace = defaults.editRange.replace - end - end -end - ----@param result vim.lsp.CompletionResult ----@return lsp.CompletionItem[] -local function get_items(result) - if result.items then - for _, item in ipairs(result.items) do - ---@diagnostic disable-next-line: param-type-mismatch - apply_defaults(item, result.itemDefaults) - end - return result.items - else - return result - end -end - ---- Turns the result of a `textDocument/completion` request into vim-compatible ---- |complete-items|. ---- ----@param result vim.lsp.CompletionResult Result of `textDocument/completion` ----@param prefix string prefix to filter the completion items ----@return table[] ----@see complete-items -function M._lsp_to_complete_items(result, prefix) - local items = get_items(result) - if vim.tbl_isempty(items) then - return {} - end - - local function matches_prefix(item) - return vim.startswith(get_completion_word(item), prefix) - end - - items = vim.tbl_filter(matches_prefix, items) --[[@as lsp.CompletionItem[]|]] - table.sort(items, function(a, b) - return (a.sortText or a.label) < (b.sortText or b.label) - end) - - local matches = {} - for _, item in ipairs(items) do - local info = '' - local documentation = item.documentation - if documentation then - if type(documentation) == 'string' and documentation ~= '' then - info = documentation - elseif type(documentation) == 'table' and type(documentation.value) == 'string' then - info = documentation.value - else - vim.notify( - ('invalid documentation value %s'):format(vim.inspect(documentation)), - vim.log.levels.WARN - ) - end - end - local word = get_completion_word(item) - table.insert(matches, { - word = word, - abbr = item.label, - kind = protocol.CompletionItemKind[item.kind] or 'Unknown', - menu = item.detail or '', - info = #info > 0 and info or nil, - icase = 1, - dup = 1, - empty = 1, - user_data = { - nvim = { - lsp = { - completion_item = item, - }, - }, - }, - }) - end - return matches -end - ----@param lnum integer 0-indexed ----@param items lsp.CompletionItem[] -local function adjust_start_col(lnum, line, items, encoding) - local min_start_char = nil - for _, item in pairs(items) do - if item.textEdit and item.textEdit.range.start.line == lnum then - if min_start_char and min_start_char ~= item.textEdit.range.start.character then - return nil - end - min_start_char = item.textEdit.range.start.character - end - end - if min_start_char then - return vim.lsp.util._str_byteindex_enc(line, min_start_char, encoding) - else - return nil - end -end - ----@private ----@param line string line content ----@param lnum integer 0-indexed line number ----@param client_start_boundary integer 0-indexed word boundary ----@param server_start_boundary? integer 0-indexed word boundary, based on textEdit.range.start.character ----@param result vim.lsp.CompletionResult ----@param encoding string ----@return table[] matches ----@return integer? server_start_boundary -function M._convert_results( - line, - lnum, - cursor_col, - client_start_boundary, - server_start_boundary, - result, - encoding -) - -- Completion response items may be relative to a position different than `client_start_boundary`. - -- Concrete example, with lua-language-server: - -- - -- require('plenary.asy| - -- â–² â–² â–² - -- │ │ └── cursor_pos: 20 - -- │ └────── client_start_boundary: 17 - -- └────────────── textEdit.range.start.character: 9 - -- .newText = 'plenary.async' - -- ^^^ - -- prefix (We'd remove everything not starting with `asy`, - -- so we'd eliminate the `plenary.async` result - -- - -- `adjust_start_col` is used to prefer the language server boundary. - -- - local candidates = get_items(result) - local curstartbyte = adjust_start_col(lnum, line, candidates, encoding) - if server_start_boundary == nil then - server_start_boundary = curstartbyte - elseif curstartbyte ~= nil and curstartbyte ~= server_start_boundary then - server_start_boundary = client_start_boundary - end - local prefix = line:sub((server_start_boundary or client_start_boundary) + 1, cursor_col) - local matches = M._lsp_to_complete_items(result, prefix) - return matches, server_start_boundary -end - ----@param findstart integer 0 or 1, decides behavior ----@param base integer findstart=0, text to match against ----@return integer|table Decided by {findstart}: ---- - findstart=0: column where the completion starts, or -2 or -3 ---- - findstart=1: list of matches (actually just calls |complete()|) -function M.omnifunc(findstart, base) - assert(base) -- silence luals - local bufnr = api.nvim_get_current_buf() - local clients = lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_completion }) - local remaining = #clients - if remaining == 0 then - return findstart == 1 and -1 or {} - end - - local win = api.nvim_get_current_win() - local cursor = api.nvim_win_get_cursor(win) - local lnum = cursor[1] - 1 - local cursor_col = cursor[2] - local line = api.nvim_get_current_line() - local line_to_cursor = line:sub(1, cursor_col) - local client_start_boundary = vim.fn.match(line_to_cursor, '\\k*$') --[[@as integer]] - local server_start_boundary = nil - local items = {} - - local function on_done() - local mode = api.nvim_get_mode()['mode'] - if mode == 'i' or mode == 'ic' then - vim.fn.complete((server_start_boundary or client_start_boundary) + 1, items) - end - end - - local util = vim.lsp.util - for _, client in ipairs(clients) do - local params = util.make_position_params(win, client.offset_encoding) - client.request(ms.textDocument_completion, params, function(err, result) - if err then - vim.lsp.log.warn(err.message) - end - if result and vim.fn.mode() == 'i' then - local matches - matches, server_start_boundary = M._convert_results( - line, - lnum, - cursor_col, - client_start_boundary, - server_start_boundary, - result, - client.offset_encoding - ) - vim.list_extend(items, matches) - end - remaining = remaining - 1 - if remaining == 0 then - vim.schedule(on_done) - end - end, bufnr) - end - - -- Return -2 to signal that we should continue completion so that we can - -- async complete. - return -2 -end - -return M diff --git a/runtime/lua/vim/lsp/_dynamic.lua b/runtime/lua/vim/lsp/_dynamic.lua index 819b03a63a..27113c0e74 100644 --- a/runtime/lua/vim/lsp/_dynamic.lua +++ b/runtime/lua/vim/lsp/_dynamic.lua @@ -24,7 +24,6 @@ function M:supports_registration(method) end --- @param registrations lsp.Registration[] ---- @package function M:register(registrations) -- remove duplicates self:unregister(registrations) @@ -38,7 +37,6 @@ function M:register(registrations) end --- @param unregisterations lsp.Unregistration[] ---- @package function M:unregister(unregisterations) for _, unreg in ipairs(unregisterations) do local method = unreg.method @@ -58,7 +56,6 @@ end --- @param method string --- @param opts? {bufnr: integer?} --- @return lsp.Registration? (table|nil) the registration if found ---- @package function M:get(method, opts) opts = opts or {} opts.bufnr = opts.bufnr or vim.api.nvim_get_current_buf() @@ -78,7 +75,6 @@ end --- @param method string --- @param opts? {bufnr: integer?} ---- @package function M:supports(method, opts) return self:get(method, opts) ~= nil end diff --git a/runtime/lua/vim/lsp/_meta/protocol.lua b/runtime/lua/vim/lsp/_meta/protocol.lua index 9a11972007..d83c40a09f 100644 --- a/runtime/lua/vim/lsp/_meta/protocol.lua +++ b/runtime/lua/vim/lsp/_meta/protocol.lua @@ -134,7 +134,7 @@ error('Cannot require a meta file') ---The zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line. ---@field endCharacter? uinteger --- ----Describes the kind of the folding range such as `comment' or 'region'. The kind +---Describes the kind of the folding range such as 'comment' or 'region'. The kind ---is used to categorize folding ranges and used by commands like 'Fold all comments'. ---See {@link FoldingRangeKind} for an enumeration of standardized kinds. ---@field kind? lsp.FoldingRangeKind @@ -681,6 +681,11 @@ error('Cannot require a meta file') ---of a notebook cell. ---@field cellTextDocuments lsp.TextDocumentItem[] +---Registration options specific to a notebook. +--- +---@since 3.17.0 +---@class lsp.NotebookDocumentSyncRegistrationOptions: lsp.NotebookDocumentSyncOptions, lsp.StaticRegistrationOptions + ---The params sent in a change notebook document notification. --- ---@since 3.17.0 @@ -789,7 +794,7 @@ error('Cannot require a meta file') ---Information about the server. --- ---@since 3.15.0 ----@field serverInfo? lsp._anonym1.serverInfo +---@field serverInfo? lsp.ServerInfo ---The data type of the ResponseError if the ---initialize request fails. @@ -1115,7 +1120,7 @@ error('Cannot require a meta file') ---capability. --- ---@since 3.17.0 ----@field itemDefaults? lsp._anonym2.itemDefaults +---@field itemDefaults? lsp.CompletionItemDefaults --- ---The completion items. ---@field items lsp.CompletionItem[] @@ -1171,7 +1176,7 @@ error('Cannot require a meta file') --- ---If `null`, no parameter of the signature is active (for example a named ---argument that does not match any declared parameters). This is only valid ----since 3.18.0 and if the client specifies the client capability +---if the client specifies the client capability ---`textDocument.signatureHelp.noActiveParameterSupport === true` --- ---If omitted or the value lies outside the range of @@ -1307,6 +1312,12 @@ error('Cannot require a meta file') ---Title of the command, like `save`. ---@field title string --- +---An optional tooltip. +--- +---@since 3.18.0 +---@proposed +---@field tooltip? string +--- ---The identifier of the actual command handler. ---@field command string --- @@ -1355,7 +1366,7 @@ error('Cannot require a meta file') --- error message with `reason` in the editor. --- ---@since 3.16.0 ----@field disabled? lsp._anonym4.disabled +---@field disabled? lsp.CodeActionDisabled --- ---The workspace edit this code action performs. ---@field edit? lsp.WorkspaceEdit @@ -1379,6 +1390,12 @@ error('Cannot require a meta file') --- ---A query string to filter symbols by. Clients may send an empty ---string here to request all symbols. +--- +---The `query`-parameter should be interpreted in a *relaxed way* as editors +---will apply their own highlighting and scoring on the results. A good rule +---of thumb is to match case-insensitive and to simply check that the +---characters of *query* appear in their order in a candidate symbol. +---Servers shouldn't use prefix, substring, or similar strict matching. ---@field query string ---A special workspace symbol that supports locations without a range. @@ -1393,7 +1410,7 @@ error('Cannot require a meta file') ---capability `workspace.symbol.resolveSupport`. --- ---See SymbolInformation#location for more details. ----@field location lsp.Location|lsp._anonym5.location +---@field location lsp.Location|lsp.LocationUriOnly --- ---A data entry field that is preserved on a workspace symbol between a ---workspace symbol request and a workspace symbol resolve request. @@ -1566,6 +1583,12 @@ error('Cannot require a meta file') --- ---The edits to apply. ---@field edit lsp.WorkspaceEdit +--- +---Additional data about the edit. +--- +---@since 3.18.0 +---@proposed +---@field metadata? lsp.WorkspaceEditMetadata ---The result returned from the apply workspace edit request. --- @@ -1650,7 +1673,7 @@ error('Cannot require a meta file') ---@class lsp.SetTraceParams --- ----@field value lsp.TraceValues +---@field value lsp.TraceValue ---@class lsp.LogTraceParams --- @@ -1848,10 +1871,10 @@ error('Cannot require a meta file') --- ---Server supports providing semantic tokens for a specific range ---of a document. ----@field range? boolean|lsp._anonym6.range +---@field range? boolean|lsp._anonym1.range --- ---Server supports providing semantic tokens for a full document. ----@field full? boolean|lsp._anonym7.full +---@field full? boolean|lsp.SemanticTokensFullDelta ---@since 3.16.0 ---@class lsp.SemanticTokensEdit @@ -1888,7 +1911,10 @@ error('Cannot require a meta file') --- ---@since 3.16.0 - support for AnnotatedTextEdit. This is guarded using a ---client capability. ----@field edits (lsp.TextEdit|lsp.AnnotatedTextEdit)[] +--- +---@since 3.18.0 - support for SnippetTextEdit. This is guarded using a +---client capability. +---@field edits (lsp.TextEdit|lsp.AnnotatedTextEdit|lsp.SnippetTextEdit)[] ---Create file operation. ---@class lsp.CreateFile: lsp.ResourceOperation @@ -2235,7 +2261,7 @@ error('Cannot require a meta file') ---@field uri lsp.DocumentUri --- ---The text document's language identifier. ----@field languageId string +---@field languageId lsp.LanguageKind --- ---The version number of this document (it will increase after each ---change, including undo/redo). @@ -2244,6 +2270,28 @@ error('Cannot require a meta file') ---The content of the opened text document. ---@field text string +---Options specific to a notebook plus its cells +---to be synced to the server. +--- +---If a selector provides a notebook document +---filter but no cell selector all cells of a +---matching notebook document will be synced. +--- +---If a selector provides no notebook document +---filter but only a cell selector all notebook +---document that contain at least one matching +---cell will be synced. +--- +---@since 3.17.0 +---@class lsp.NotebookDocumentSyncOptions +--- +---The notebooks to be synced +---@field notebookSelector (lsp.NotebookDocumentFilterWithNotebook|lsp.NotebookDocumentFilterWithCells)[] +--- +---Whether save notification should be forwarded to +---the server. Will only be honored if mode === `notebook`. +---@field save? boolean + ---A versioned notebook document identifier. --- ---@since 3.17.0 @@ -2266,7 +2314,7 @@ error('Cannot require a meta file') ---@field metadata? lsp.LSPObject --- ---Changes to cells ----@field cells? lsp._anonym8.cells +---@field cells? lsp.NotebookDocumentCellChanges ---A literal to identify a notebook document in the client. --- @@ -2348,7 +2396,7 @@ error('Cannot require a meta file') ---Information about the client --- ---@since 3.15.0 ----@field clientInfo? lsp._anonym11.clientInfo +---@field clientInfo? lsp.ClientInfo --- ---The locale the client is currently showing the user interface ---in. This must not necessarily be the locale of the operating @@ -2380,7 +2428,7 @@ error('Cannot require a meta file') ---@field initializationOptions? lsp.LSPAny --- ---The initial trace setting. If omitted trace is disabled ('off'). ----@field trace? lsp.TraceValues +---@field trace? lsp.TraceValue ---@class lsp.WorkspaceFoldersInitializeParams --- @@ -2534,18 +2582,24 @@ error('Cannot require a meta file') ---@proposed ---@field inlineCompletionProvider? boolean|lsp.InlineCompletionOptions --- ----Text document specific server capabilities. ---- ----@since 3.18.0 ----@proposed ----@field textDocument? lsp._anonym12.textDocument ---- ---Workspace specific server capabilities. ----@field workspace? lsp._anonym14.workspace +---@field workspace? lsp.WorkspaceOptions --- ---Experimental server capabilities. ---@field experimental? lsp.LSPAny +---Information about the server +--- +---@since 3.15.0 +---@since 3.18.0 ServerInfo type name added. +---@class lsp.ServerInfo +--- +---The name of the server as defined by the server. +---@field name string +--- +---The server's version as defined by the server. +---@field version? string + ---A text document identifier to denote a specific version of a text document. ---@class lsp.VersionedTextDocumentIdentifier: lsp.TextDocumentIdentifier --- @@ -2586,8 +2640,9 @@ error('Cannot require a meta file') ---The range at which the message applies ---@field range lsp.Range --- ----The diagnostic's severity. Can be omitted. If omitted it is up to the ----client to interpret diagnostics as error, warning, info or hint. +---The diagnostic's severity. To avoid interpretation mismatches when a +---server is used with different clients it is highly recommended that servers +---always provide a severity value. ---@field severity? lsp.DiagnosticSeverity --- ---The diagnostic's code, which usually appear in the user interface. @@ -2604,10 +2659,8 @@ error('Cannot require a meta file') ---appears in the user interface. ---@field source? string --- ----The diagnostic's message. It usually appears in the user interface. ---- ----@since 3.18.0 - support for `MarkupContent`. This is guarded by the client capability `textDocument.diagnostic.markupMessageSupport`. ----@field message string|lsp.MarkupContent +---The diagnostic's message. It usually appears in the user interface +---@field message string --- ---Additional metadata about the diagnostic. --- @@ -2661,6 +2714,46 @@ error('Cannot require a meta file') ---The range if the replace is requested. ---@field replace lsp.Range +---In many cases the items of an actual completion result share the same +---value for properties like `commitCharacters` or the range of a text +---edit. A completion list can therefore define item defaults which will +---be used if a completion item itself doesn't specify the value. +--- +---If a completion list specifies a default value and a completion item +---also specifies a corresponding value the one from the item is used. +--- +---Servers are only allowed to return default values if the client +---signals support for this via the `completionList.itemDefaults` +---capability. +--- +---@since 3.17.0 +---@class lsp.CompletionItemDefaults +--- +---A default commit character set. +--- +---@since 3.17.0 +---@field commitCharacters? string[] +--- +---A default edit range. +--- +---@since 3.17.0 +---@field editRange? lsp.Range|lsp.EditRangeWithInsertReplace +--- +---A default insert text format. +--- +---@since 3.17.0 +---@field insertTextFormat? lsp.InsertTextFormat +--- +---A default insert text mode. +--- +---@since 3.17.0 +---@field insertTextMode? lsp.InsertTextMode +--- +---A default data value. +--- +---@since 3.17.0 +---@field data? lsp.LSPAny + ---Completion options. ---@class lsp.CompletionOptions: lsp.WorkDoneProgressOptions --- @@ -2692,7 +2785,7 @@ error('Cannot require a meta file') ---capabilities. --- ---@since 3.17.0 ----@field completionItem? lsp._anonym15.completionItem +---@field completionItem? lsp.ServerCompletionItemOptions ---Hover options. ---@class lsp.HoverOptions: lsp.WorkDoneProgressOptions @@ -2742,7 +2835,7 @@ error('Cannot require a meta file') --- ---If `null`, no parameter of the signature is active (for example a named ---argument that does not match any declared parameters). This is only valid ----since 3.18.0 and if the client specifies the client capability +---if the client specifies the client capability ---`textDocument.signatureHelp.noActiveParameterSupport === true` --- ---If provided (or `null`), this is used in place of @@ -2819,8 +2912,6 @@ error('Cannot require a meta file') ---errors are currently presented to the user for the given range. There is no guarantee ---that these accurately reflect the error state of the resource. The primary parameter ---to compute code actions is the provided range. ---- ----Note that the client should check the `textDocument.diagnostic.markupMessageSupport` server capability before sending diagnostics with markup messages to a server. ---@field diagnostics lsp.Diagnostic[] --- ---Requested kind of actions to return. @@ -2834,6 +2925,16 @@ error('Cannot require a meta file') ---@since 3.17.0 ---@field triggerKind? lsp.CodeActionTriggerKind +---Captures why the code action is currently disabled. +--- +---@since 3.18.0 +---@class lsp.CodeActionDisabled +--- +---Human readable description of why the code action is currently disabled. +--- +---This is displayed in the code actions UI. +---@field reason string + ---Provider options for a {@link CodeActionRequest}. ---@class lsp.CodeActionOptions: lsp.WorkDoneProgressOptions --- @@ -2843,12 +2944,36 @@ error('Cannot require a meta file') ---may list out every specific kind they provide. ---@field codeActionKinds? lsp.CodeActionKind[] --- +---Static documentation for a class of code actions. +--- +---Documentation from the provider should be shown in the code actions menu if either: +--- +---- Code actions of `kind` are requested by the editor. In this case, the editor will show the documentation that +--- most closely matches the requested code action kind. For example, if a provider has documentation for +--- both `Refactor` and `RefactorExtract`, when the user requests code actions for `RefactorExtract`, +--- the editor will use the documentation for `RefactorExtract` instead of the documentation for `Refactor`. +--- +---- Any code actions of `kind` are returned by the provider. +--- +---At most one documentation entry should be shown per provider. +--- +---@since 3.18.0 +---@proposed +---@field documentation? lsp.CodeActionKindDocumentation[] +--- ---The server provides support to resolve additional ---information for a code action. --- ---@since 3.16.0 ---@field resolveProvider? boolean +---Location with only uri and does not include range. +--- +---@since 3.18.0 +---@class lsp.LocationUriOnly +--- +---@field uri lsp.DocumentUri + ---Server capabilities for a {@link WorkspaceSymbolRequest}. ---@class lsp.WorkspaceSymbolOptions: lsp.WorkDoneProgressOptions --- @@ -2923,12 +3048,33 @@ error('Cannot require a meta file') ---@since version 3.12.0 ---@field prepareProvider? boolean +---@since 3.18.0 +---@class lsp.PrepareRenamePlaceholder +--- +---@field range lsp.Range +--- +---@field placeholder string + +---@since 3.18.0 +---@class lsp.PrepareRenameDefaultBehavior +--- +---@field defaultBehavior boolean + ---The server capabilities of a {@link ExecuteCommandRequest}. ---@class lsp.ExecuteCommandOptions: lsp.WorkDoneProgressOptions --- ---The commands to be executed on the server ---@field commands string[] +---Additional data about a workspace edit. +--- +---@since 3.18.0 +---@proposed +---@class lsp.WorkspaceEditMetadata +--- +---Signal to the editor that this edit is a refactoring. +---@field isRefactoring? boolean + ---@since 3.16.0 ---@class lsp.SemanticTokensLegend --- @@ -2938,6 +3084,14 @@ error('Cannot require a meta file') ---The token modifiers a server uses. ---@field tokenModifiers string[] +---Semantic tokens options to support deltas for full documents +--- +---@since 3.18.0 +---@class lsp.SemanticTokensFullDelta +--- +---The server supports deltas for full documents. +---@field delta? boolean + ---A text document identifier to optionally denote a specific version of a text document. ---@class lsp.OptionalVersionedTextDocumentIdentifier: lsp.TextDocumentIdentifier --- @@ -2956,6 +3110,21 @@ error('Cannot require a meta file') ---The actual identifier of the change annotation ---@field annotationId lsp.ChangeAnnotationIdentifier +---An interactive text edit. +--- +---@since 3.18.0 +---@proposed +---@class lsp.SnippetTextEdit +--- +---The range of the text document to be manipulated. +---@field range lsp.Range +--- +---The snippet to be inserted. +---@field snippet lsp.StringValue +--- +---The actual identifier of the snippet edit. +---@field annotationId? lsp.ChangeAnnotationIdentifier + ---A generic resource operation. ---@class lsp.ResourceOperation --- @@ -3066,20 +3235,43 @@ error('Cannot require a meta file') ---if supported by the client. ---@field executionSummary? lsp.ExecutionSummary ----A change describing how to move a `NotebookCell` ----array from state S to S'. +---@since 3.18.0 +---@class lsp.NotebookDocumentFilterWithNotebook --- ----@since 3.17.0 ----@class lsp.NotebookCellArrayChange +---The notebook to be synced If a string +---value is provided it matches against the +---notebook type. '*' matches every notebook. +---@field notebook string|lsp.NotebookDocumentFilter --- ----The start oftest of the cell that changed. ----@field start uinteger +---The cells of the matching notebook to be synced. +---@field cells? lsp.NotebookCellLanguage[] + +---@since 3.18.0 +---@class lsp.NotebookDocumentFilterWithCells --- ----The deleted cells ----@field deleteCount uinteger +---The notebook to be synced If a string +---value is provided it matches against the +---notebook type. '*' matches every notebook. +---@field notebook? string|lsp.NotebookDocumentFilter --- ----The new cells, if any ----@field cells? lsp.NotebookCell[] +---The cells of the matching notebook to be synced. +---@field cells lsp.NotebookCellLanguage[] + +---Cell changes to a notebook document. +--- +---@since 3.18.0 +---@class lsp.NotebookDocumentCellChanges +--- +---Changes to the cell structure to add or +---remove cells. +---@field structure? lsp.NotebookDocumentCellChangeStructure +--- +---Changes to notebook cells properties like its +---kind, execution summary or metadata. +---@field data? lsp.NotebookCell[] +--- +---Changes to the text content of notebook cells. +---@field textContent? lsp.NotebookDocumentCellContentChanges[] ---Describes the currently selected completion item. --- @@ -3093,6 +3285,18 @@ error('Cannot require a meta file') ---The text the range will be replaced with if this completion is accepted. ---@field text string +---Information about the client +--- +---@since 3.15.0 +---@since 3.18.0 ClientInfo type name added. +---@class lsp.ClientInfo +--- +---The name of the client as defined by the client. +---@field name string +--- +---The client's version as defined by the client. +---@field version? string + ---Defines the capabilities provided by the client. ---@class lsp.ClientCapabilities --- @@ -3140,69 +3344,40 @@ error('Cannot require a meta file') ---sent. ---@field save? boolean|lsp.SaveOptions ----Options specific to a notebook plus its cells ----to be synced to the server. +---Defines workspace specific capabilities of the server. --- ----If a selector provides a notebook document ----filter but no cell selector all cells of a ----matching notebook document will be synced. +---@since 3.18.0 +---@class lsp.WorkspaceOptions --- ----If a selector provides no notebook document ----filter but only a cell selector all notebook ----document that contain at least one matching ----cell will be synced. +---The server supports workspace folder. --- ----@since 3.17.0 ----@class lsp.NotebookDocumentSyncOptions +---@since 3.6.0 +---@field workspaceFolders? lsp.WorkspaceFoldersServerCapabilities --- ----The notebooks to be synced ----@field notebookSelector (lsp._anonym16.notebookSelector|lsp._anonym18.notebookSelector)[] +---The server is interested in notifications/requests for operations on files. --- ----Whether save notification should be forwarded to ----the server. Will only be honored if mode === `notebook`. ----@field save? boolean +---@since 3.16.0 +---@field fileOperations? lsp.FileOperationOptions ----Registration options specific to a notebook. +---@since 3.18.0 +---@class lsp.TextDocumentContentChangePartial --- ----@since 3.17.0 ----@class lsp.NotebookDocumentSyncRegistrationOptions: lsp.NotebookDocumentSyncOptions, lsp.StaticRegistrationOptions - ----@class lsp.WorkspaceFoldersServerCapabilities +---The range of the document that changed. +---@field range lsp.Range --- ----The server has support for workspace folders ----@field supported? boolean +---The optional length of the range that got replaced. --- ----Whether the server wants to receive workspace folder ----change notifications. +---@deprecated use range instead. +---@field rangeLength? uinteger --- ----If a string is provided the string is treated as an ID ----under which the notification is registered on the client ----side. The ID can be used to unregister for these events ----using the `client/unregisterCapability` request. ----@field changeNotifications? string|boolean +---The new text for the provided range. +---@field text string ----Options for notifications/requests for user operations on files. ---- ----@since 3.16.0 ----@class lsp.FileOperationOptions ---- ----The server is interested in receiving didCreateFiles notifications. ----@field didCreate? lsp.FileOperationRegistrationOptions ---- ----The server is interested in receiving willCreateFiles requests. ----@field willCreate? lsp.FileOperationRegistrationOptions ---- ----The server is interested in receiving didRenameFiles notifications. ----@field didRename? lsp.FileOperationRegistrationOptions ---- ----The server is interested in receiving willRenameFiles requests. ----@field willRename? lsp.FileOperationRegistrationOptions ---- ----The server is interested in receiving didDeleteFiles file notifications. ----@field didDelete? lsp.FileOperationRegistrationOptions +---@since 3.18.0 +---@class lsp.TextDocumentContentChangeWholeDocument --- ----The server is interested in receiving willDeleteFiles file requests. ----@field willDelete? lsp.FileOperationRegistrationOptions +---The new text of the whole document. +---@field text string ---Structure to capture a description for an error code. --- @@ -3223,6 +3398,33 @@ error('Cannot require a meta file') ---The message of this related diagnostic information. ---@field message string +---Edit range variant that includes ranges for insert and replace operations. +--- +---@since 3.18.0 +---@class lsp.EditRangeWithInsertReplace +--- +---@field insert lsp.Range +--- +---@field replace lsp.Range + +---@since 3.18.0 +---@class lsp.ServerCompletionItemOptions +--- +---The server has support for completion item label +---details (see also `CompletionItemLabelDetails`) when +---receiving a completion item in a resolve call. +--- +---@since 3.17.0 +---@field labelDetailsSupport? boolean + +---@since 3.18.0 +---@deprecated use MarkupContent instead. +---@class lsp.MarkedStringWithLanguage +--- +---@field language string +--- +---@field value string + ---Represents a parameter of a callable-signature. A parameter can ---have a label and a doc-comment. ---@class lsp.ParameterInformation @@ -3233,14 +3435,36 @@ error('Cannot require a meta file') ---signature label. (see SignatureInformation.label). The offsets are based on a UTF-16 ---string representation as `Position` and `Range` does. --- +---To avoid ambiguities a server should use the [start, end] offset value instead of using +---a substring. Whether a client support this is controlled via `labelOffsetSupport` client +---capability. +--- ---*Note*: a label of type string should be a substring of its containing signature label. ---Its intended use case is to highlight the parameter label part in the `SignatureInformation.label`. ----@field label string|{ [1]: uinteger, [2]: uinteger } +---@field label string|[uinteger, uinteger] --- ---The human-readable doc-comment of this parameter. Will be shown ---in the UI but can be omitted. ---@field documentation? string|lsp.MarkupContent +---Documentation for a class of code actions. +--- +---@since 3.18.0 +---@proposed +---@class lsp.CodeActionKindDocumentation +--- +---The kind of the code action being documented. +--- +---If the kind is generic, such as `CodeActionKind.Refactor`, the documentation will be shown whenever any +---refactorings are returned. If the kind if more specific, such as `CodeActionKind.RefactorExtract`, the +---documentation will only be shown when extract refactoring code actions are returned. +---@field kind lsp.CodeActionKind +--- +---Command that is ued to display the documentation to the user. +--- +---The title of this documentation code action is taken from {@linkcode Command.title} +---@field command lsp.Command + ---A notebook cell text document filter denotes a cell text ---document by different properties. --- @@ -3278,6 +3502,34 @@ error('Cannot require a meta file') ---not if known by the client. ---@field success? boolean +---@since 3.18.0 +---@class lsp.NotebookCellLanguage +--- +---@field language string + +---Structural changes to cells in a notebook document. +--- +---@since 3.18.0 +---@class lsp.NotebookDocumentCellChangeStructure +--- +---The change to the cell array. +---@field array lsp.NotebookCellArrayChange +--- +---Additional opened cell text documents. +---@field didOpen? lsp.TextDocumentItem[] +--- +---Additional closed cell text documents. +---@field didClose? lsp.TextDocumentIdentifier[] + +---Content changes to a cell in a notebook document. +--- +---@since 3.18.0 +---@class lsp.NotebookDocumentCellContentChanges +--- +---@field document lsp.VersionedTextDocumentIdentifier +--- +---@field changes lsp.TextDocumentContentChangeEvent[] + ---Workspace specific client capabilities. ---@class lsp.WorkspaceClientCapabilities --- @@ -3524,7 +3776,7 @@ error('Cannot require a meta file') ---anymore since the information is outdated). --- ---@since 3.17.0 ----@field staleRequestSupport? lsp._anonym20.staleRequestSupport +---@field staleRequestSupport? lsp.StaleRequestSupportOptions --- ---Client capabilities specific to regular expressions. --- @@ -3556,6 +3808,43 @@ error('Cannot require a meta file') ---@since 3.17.0 ---@field positionEncodings? lsp.PositionEncodingKind[] +---@class lsp.WorkspaceFoldersServerCapabilities +--- +---The server has support for workspace folders +---@field supported? boolean +--- +---Whether the server wants to receive workspace folder +---change notifications. +--- +---If a string is provided the string is treated as an ID +---under which the notification is registered on the client +---side. The ID can be used to unregister for these events +---using the `client/unregisterCapability` request. +---@field changeNotifications? string|boolean + +---Options for notifications/requests for user operations on files. +--- +---@since 3.16.0 +---@class lsp.FileOperationOptions +--- +---The server is interested in receiving didCreateFiles notifications. +---@field didCreate? lsp.FileOperationRegistrationOptions +--- +---The server is interested in receiving willCreateFiles requests. +---@field willCreate? lsp.FileOperationRegistrationOptions +--- +---The server is interested in receiving didRenameFiles notifications. +---@field didRename? lsp.FileOperationRegistrationOptions +--- +---The server is interested in receiving willRenameFiles requests. +---@field willRename? lsp.FileOperationRegistrationOptions +--- +---The server is interested in receiving didDeleteFiles file notifications. +---@field didDelete? lsp.FileOperationRegistrationOptions +--- +---The server is interested in receiving willDeleteFiles file requests. +---@field willDelete? lsp.FileOperationRegistrationOptions + ---A relative pattern is a helper to construct glob patterns that are matched ---relatively to a base URI. The common value for a `baseUri` is a workspace ---folder root, but it can be another absolute URI as well. @@ -3570,6 +3859,111 @@ error('Cannot require a meta file') ---The actual glob pattern; ---@field pattern lsp.Pattern +---A document filter where `language` is required field. +--- +---@since 3.18.0 +---@class lsp.TextDocumentFilterLanguage +--- +---A language id, like `typescript`. +---@field language string +--- +---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. +---@field scheme? string +--- +---A glob pattern, like **/*.{ts,js}. See TextDocumentFilter for examples. +--- +---@since 3.18.0 - support for relative patterns. +---@field pattern? lsp.GlobPattern + +---A document filter where `scheme` is required field. +--- +---@since 3.18.0 +---@class lsp.TextDocumentFilterScheme +--- +---A language id, like `typescript`. +---@field language? string +--- +---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. +---@field scheme string +--- +---A glob pattern, like **/*.{ts,js}. See TextDocumentFilter for examples. +--- +---@since 3.18.0 - support for relative patterns. +---@field pattern? lsp.GlobPattern + +---A document filter where `pattern` is required field. +--- +---@since 3.18.0 +---@class lsp.TextDocumentFilterPattern +--- +---A language id, like `typescript`. +---@field language? string +--- +---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. +---@field scheme? string +--- +---A glob pattern, like **/*.{ts,js}. See TextDocumentFilter for examples. +--- +---@since 3.18.0 - support for relative patterns. +---@field pattern lsp.GlobPattern + +---A notebook document filter where `notebookType` is required field. +--- +---@since 3.18.0 +---@class lsp.NotebookDocumentFilterNotebookType +--- +---The type of the enclosing notebook. +---@field notebookType string +--- +---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. +---@field scheme? string +--- +---A glob pattern. +---@field pattern? lsp.GlobPattern + +---A notebook document filter where `scheme` is required field. +--- +---@since 3.18.0 +---@class lsp.NotebookDocumentFilterScheme +--- +---The type of the enclosing notebook. +---@field notebookType? string +--- +---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. +---@field scheme string +--- +---A glob pattern. +---@field pattern? lsp.GlobPattern + +---A notebook document filter where `pattern` is required field. +--- +---@since 3.18.0 +---@class lsp.NotebookDocumentFilterPattern +--- +---The type of the enclosing notebook. +---@field notebookType? string +--- +---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. +---@field scheme? string +--- +---A glob pattern. +---@field pattern lsp.GlobPattern + +---A change describing how to move a `NotebookCell` +---array from state S to S'. +--- +---@since 3.17.0 +---@class lsp.NotebookCellArrayChange +--- +---The start oftest of the cell that changed. +---@field start uinteger +--- +---The deleted cells +---@field deleteCount uinteger +--- +---The new cells, if any +---@field cells? lsp.NotebookCell[] + ---@class lsp.WorkspaceEditClientCapabilities --- ---The client supports versioned document changes in `WorkspaceEdit`s @@ -3600,7 +3994,19 @@ error('Cannot require a meta file') ---create file, rename file and delete file changes. --- ---@since 3.16.0 ----@field changeAnnotationSupport? lsp._anonym21.changeAnnotationSupport +---@field changeAnnotationSupport? lsp.ChangeAnnotationsSupportOptions +--- +---Whether the client supports `WorkspaceEditMetadata` in `WorkspaceEdit`s. +--- +---@since 3.18.0 +---@proposed +---@field metadataSupport? boolean +--- +---Whether the client supports snippets as text edits. +--- +---@since 3.18.0 +---@proposed +---@field snippetEditSupport? boolean ---@class lsp.DidChangeConfigurationClientCapabilities --- @@ -3627,20 +4033,20 @@ error('Cannot require a meta file') ---@field dynamicRegistration? boolean --- ---Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. ----@field symbolKind? lsp._anonym22.symbolKind +---@field symbolKind? lsp.ClientSymbolKindOptions --- ---The client supports tags on `SymbolInformation`. ---Clients supporting tags have to handle unknown tags gracefully. --- ---@since 3.16.0 ----@field tagSupport? lsp._anonym23.tagSupport +---@field tagSupport? lsp.ClientSymbolTagOptions --- ---The client support partial workspace symbols. The client will send the ---request `workspaceSymbol/resolve` to the server to resolve additional ---properties. --- ---@since 3.17.0 ----@field resolveSupport? lsp._anonym24.resolveSupport +---@field resolveSupport? lsp.ClientSymbolResolveOptions ---The client capabilities of a {@link ExecuteCommandRequest}. ---@class lsp.ExecuteCommandClientCapabilities @@ -3785,9 +4191,9 @@ error('Cannot require a meta file') --- ---The client supports the following `CompletionItem` specific ---capabilities. ----@field completionItem? lsp._anonym25.completionItem +---@field completionItem? lsp.ClientCompletionItemOptions --- ----@field completionItemKind? lsp._anonym29.completionItemKind +---@field completionItemKind? lsp.ClientCompletionItemOptionsKind --- ---Defines how the client handles whitespace and indentation ---when accepting a completion item that uses multi line @@ -3804,7 +4210,7 @@ error('Cannot require a meta file') ---capabilities. --- ---@since 3.17.0 ----@field completionList? lsp._anonym30.completionList +---@field completionList? lsp.CompletionListCapabilities ---@class lsp.HoverClientCapabilities --- @@ -3823,7 +4229,7 @@ error('Cannot require a meta file') --- ---The client supports the following `SignatureInformation` ---specific properties. ----@field signatureInformation? lsp._anonym31.signatureInformation +---@field signatureInformation? lsp.ClientSignatureInformationOptions --- ---The client supports to send additional context information for a ---`textDocument/signatureHelp` request. A client that opts into @@ -3901,7 +4307,7 @@ error('Cannot require a meta file') --- ---Specific capabilities for the `SymbolKind` in the ---`textDocument/documentSymbol` request. ----@field symbolKind? lsp._anonym33.symbolKind +---@field symbolKind? lsp.ClientSymbolKindOptions --- ---The client supports hierarchical document symbols. ---@field hierarchicalDocumentSymbolSupport? boolean @@ -3911,7 +4317,7 @@ error('Cannot require a meta file') ---Clients supporting tags have to handle unknown tags gracefully. --- ---@since 3.16.0 ----@field tagSupport? lsp._anonym34.tagSupport +---@field tagSupport? lsp.ClientSymbolTagOptions --- ---The client supports an additional label presented in the UI when ---registering a document symbol provider. @@ -3930,7 +4336,7 @@ error('Cannot require a meta file') ---set the request can only return `Command` literals. --- ---@since 3.8.0 ----@field codeActionLiteralSupport? lsp._anonym35.codeActionLiteralSupport +---@field codeActionLiteralSupport? lsp.ClientCodeActionLiteralOptions --- ---Whether code action supports the `isPreferred` property. --- @@ -3953,7 +4359,7 @@ error('Cannot require a meta file') ---properties via a separate `codeAction/resolve` request. --- ---@since 3.16.0 ----@field resolveSupport? lsp._anonym37.resolveSupport +---@field resolveSupport? lsp.ClientCodeActionResolveOptions --- ---Whether the client honors the change annotations in ---text edits and resource operations returned via the @@ -3963,12 +4369,25 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@field honorsChangeAnnotations? boolean +--- +---Whether the client supports documentation for a class of +---code actions. +--- +---@since 3.18.0 +---@proposed +---@field documentationSupport? boolean ---The client capabilities of a {@link CodeLensRequest}. ---@class lsp.CodeLensClientCapabilities --- ---Whether code lens supports dynamic registration. ---@field dynamicRegistration? boolean +--- +---Whether the client supports resolving additional code lens +---properties via a separate `codeLens/resolve` request. +--- +---@since 3.18.0 +---@field resolveSupport? lsp.ClientCodeLensResolveOptions ---The client capabilities of a {@link DocumentLinkRequest}. ---@class lsp.DocumentLinkClientCapabilities @@ -4061,12 +4480,12 @@ error('Cannot require a meta file') ---Specific options for the folding range kind. --- ---@since 3.17.0 ----@field foldingRangeKind? lsp._anonym38.foldingRangeKind +---@field foldingRangeKind? lsp.ClientFoldingRangeKindOptions --- ---Specific options for the folding range. --- ---@since 3.17.0 ----@field foldingRange? lsp._anonym39.foldingRange +---@field foldingRange? lsp.ClientFoldingRangeOptions ---@class lsp.SelectionRangeClientCapabilities --- @@ -4076,34 +4495,13 @@ error('Cannot require a meta file') ---@field dynamicRegistration? boolean ---The publish diagnostic client capabilities. ----@class lsp.PublishDiagnosticsClientCapabilities ---- ----Whether the clients accepts diagnostics with related information. ----@field relatedInformation? boolean ---- ----Client supports the tag property to provide meta data about a diagnostic. ----Clients supporting tags have to handle unknown tags gracefully. ---- ----@since 3.15.0 ----@field tagSupport? lsp._anonym40.tagSupport +---@class lsp.PublishDiagnosticsClientCapabilities: lsp.DiagnosticsCapabilities --- ---Whether the client interprets the version property of the ---`textDocument/publishDiagnostics` notification's parameter. --- ---@since 3.15.0 ---@field versionSupport? boolean ---- ----Client supports a codeDescription property ---- ----@since 3.16.0 ----@field codeDescriptionSupport? boolean ---- ----Whether code action supports the `data` property which is ----preserved between a `textDocument/publishDiagnostics` and ----`textDocument/codeAction` request. ---- ----@since 3.16.0 ----@field dataSupport? boolean ---@since 3.16.0 ---@class lsp.CallHierarchyClientCapabilities @@ -4129,7 +4527,7 @@ error('Cannot require a meta file') ---`request.range` are both set to true but the server only provides a ---range provider the client might not render a minimap correctly or might ---even decide to not show any semantic tokens at all. ----@field requests lsp._anonym41.requests +---@field requests lsp.ClientSemanticTokensRequestOptions --- ---The token types that the client supports. ---@field tokenTypes string[] @@ -4212,12 +4610,12 @@ error('Cannot require a meta file') --- ---Indicates which properties a client can resolve lazily on an inlay ---hint. ----@field resolveSupport? lsp._anonym44.resolveSupport +---@field resolveSupport? lsp.ClientInlayHintResolveOptions ---Client capabilities specific to diagnostic pull requests. --- ---@since 3.17.0 ----@class lsp.DiagnosticClientCapabilities +---@class lsp.DiagnosticClientCapabilities: lsp.DiagnosticsCapabilities --- ---Whether implementation supports dynamic registration. If this is set to `true` ---the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` @@ -4226,9 +4624,6 @@ error('Cannot require a meta file') --- ---Whether the clients supports related documents for document diagnostic pulls. ---@field relatedDocumentSupport? boolean ---- ----Whether the client supports `MarkupContent` in diagnostic messages. ----@field markupMessageSupport? boolean ---Client capabilities specific to inline completions. --- @@ -4257,7 +4652,7 @@ error('Cannot require a meta file') ---@class lsp.ShowMessageRequestClientCapabilities --- ---Capabilities specific to the `MessageActionItem` type. ----@field messageActionItem? lsp._anonym45.messageActionItem +---@field messageActionItem? lsp.ClientShowMessageActionItemOptions ---Client capabilities for the showDocument request. --- @@ -4268,13 +4663,24 @@ error('Cannot require a meta file') ---request. ---@field support boolean +---@since 3.18.0 +---@class lsp.StaleRequestSupportOptions +--- +---The client will actively cancel the request. +---@field cancel boolean +--- +---The list of requests for which the client +---will retry the request if it receives a +---response with error code `ContentModified` +---@field retryOnContentModified string[] + ---Client capabilities specific to regular expressions. --- ---@since 3.16.0 ---@class lsp.RegularExpressionsClientCapabilities --- ---The engine's name. ----@field engine string +---@field engine lsp.RegularExpressionEngineKind --- ---The engine's version. ---@field version? string @@ -4296,6 +4702,285 @@ error('Cannot require a meta file') ---@since 3.17.0 ---@field allowedTags? string[] +---@since 3.18.0 +---@class lsp.ChangeAnnotationsSupportOptions +--- +---Whether the client groups edits with equal labels into tree nodes, +---for instance all edits labelled with "Changes in Strings" would +---be a tree node. +---@field groupsOnLabel? boolean + +---@since 3.18.0 +---@class lsp.ClientSymbolKindOptions +--- +---The symbol kind values the client supports. When this +---property exists the client also guarantees that it will +---handle values outside its set gracefully and falls back +---to a default value when unknown. +--- +---If this property is not present the client only supports +---the symbol kinds from `File` to `Array` as defined in +---the initial version of the protocol. +---@field valueSet? lsp.SymbolKind[] + +---@since 3.18.0 +---@class lsp.ClientSymbolTagOptions +--- +---The tags supported by the client. +---@field valueSet lsp.SymbolTag[] + +---@since 3.18.0 +---@class lsp.ClientSymbolResolveOptions +--- +---The properties that a client can resolve lazily. Usually +---`location.range` +---@field properties string[] + +---@since 3.18.0 +---@class lsp.ClientCompletionItemOptions +--- +---Client supports snippets as insert text. +--- +---A snippet can define tab stops and placeholders with `$1`, `$2` +---and `${3:foo}`. `$0` defines the final tab stop, it defaults to +---the end of the snippet. Placeholders with equal identifiers are linked, +---that is typing in one will update others too. +---@field snippetSupport? boolean +--- +---Client supports commit characters on a completion item. +---@field commitCharactersSupport? boolean +--- +---Client supports the following content formats for the documentation +---property. The order describes the preferred format of the client. +---@field documentationFormat? lsp.MarkupKind[] +--- +---Client supports the deprecated property on a completion item. +---@field deprecatedSupport? boolean +--- +---Client supports the preselect property on a completion item. +---@field preselectSupport? boolean +--- +---Client supports the tag property on a completion item. Clients supporting +---tags have to handle unknown tags gracefully. Clients especially need to +---preserve unknown tags when sending a completion item back to the server in +---a resolve call. +--- +---@since 3.15.0 +---@field tagSupport? lsp.CompletionItemTagOptions +--- +---Client support insert replace edit to control different behavior if a +---completion item is inserted in the text or should replace text. +--- +---@since 3.16.0 +---@field insertReplaceSupport? boolean +--- +---Indicates which properties a client can resolve lazily on a completion +---item. Before version 3.16.0 only the predefined properties `documentation` +---and `details` could be resolved lazily. +--- +---@since 3.16.0 +---@field resolveSupport? lsp.ClientCompletionItemResolveOptions +--- +---The client supports the `insertTextMode` property on +---a completion item to override the whitespace handling mode +---as defined by the client (see `insertTextMode`). +--- +---@since 3.16.0 +---@field insertTextModeSupport? lsp.ClientCompletionItemInsertTextModeOptions +--- +---The client has support for completion item label +---details (see also `CompletionItemLabelDetails`). +--- +---@since 3.17.0 +---@field labelDetailsSupport? boolean + +---@since 3.18.0 +---@class lsp.ClientCompletionItemOptionsKind +--- +---The completion item kind values the client supports. When this +---property exists the client also guarantees that it will +---handle values outside its set gracefully and falls back +---to a default value when unknown. +--- +---If this property is not present the client only supports +---the completion items kinds from `Text` to `Reference` as defined in +---the initial version of the protocol. +---@field valueSet? lsp.CompletionItemKind[] + +---The client supports the following `CompletionList` specific +---capabilities. +--- +---@since 3.17.0 +---@class lsp.CompletionListCapabilities +--- +---The client supports the following itemDefaults on +---a completion list. +--- +---The value lists the supported property names of the +---`CompletionList.itemDefaults` object. If omitted +---no properties are supported. +--- +---@since 3.17.0 +---@field itemDefaults? string[] + +---@since 3.18.0 +---@class lsp.ClientSignatureInformationOptions +--- +---Client supports the following content formats for the documentation +---property. The order describes the preferred format of the client. +---@field documentationFormat? lsp.MarkupKind[] +--- +---Client capabilities specific to parameter information. +---@field parameterInformation? lsp.ClientSignatureParameterInformationOptions +--- +---The client supports the `activeParameter` property on `SignatureInformation` +---literal. +--- +---@since 3.16.0 +---@field activeParameterSupport? boolean +--- +---The client supports the `activeParameter` property on +---`SignatureHelp`/`SignatureInformation` being set to `null` to +---indicate that no parameter should be active. +--- +---@since 3.18.0 +---@proposed +---@field noActiveParameterSupport? boolean + +---@since 3.18.0 +---@class lsp.ClientCodeActionLiteralOptions +--- +---The code action kind is support with the following value +---set. +---@field codeActionKind lsp.ClientCodeActionKindOptions + +---@since 3.18.0 +---@class lsp.ClientCodeActionResolveOptions +--- +---The properties that a client can resolve lazily. +---@field properties string[] + +---@since 3.18.0 +---@class lsp.ClientCodeLensResolveOptions +--- +---The properties that a client can resolve lazily. +---@field properties string[] + +---@since 3.18.0 +---@class lsp.ClientFoldingRangeKindOptions +--- +---The folding range kind values the client supports. When this +---property exists the client also guarantees that it will +---handle values outside its set gracefully and falls back +---to a default value when unknown. +---@field valueSet? lsp.FoldingRangeKind[] + +---@since 3.18.0 +---@class lsp.ClientFoldingRangeOptions +--- +---If set, the client signals that it supports setting collapsedText on +---folding ranges to display custom labels instead of the default text. +--- +---@since 3.17.0 +---@field collapsedText? boolean + +---General diagnostics capabilities for pull and push model. +---@class lsp.DiagnosticsCapabilities +--- +---Whether the clients accepts diagnostics with related information. +---@field relatedInformation? boolean +--- +---Client supports the tag property to provide meta data about a diagnostic. +---Clients supporting tags have to handle unknown tags gracefully. +--- +---@since 3.15.0 +---@field tagSupport? lsp.ClientDiagnosticsTagOptions +--- +---Client supports a codeDescription property +--- +---@since 3.16.0 +---@field codeDescriptionSupport? boolean +--- +---Whether code action supports the `data` property which is +---preserved between a `textDocument/publishDiagnostics` and +---`textDocument/codeAction` request. +--- +---@since 3.16.0 +---@field dataSupport? boolean + +---@since 3.18.0 +---@class lsp.ClientSemanticTokensRequestOptions +--- +---The client will send the `textDocument/semanticTokens/range` request if +---the server provides a corresponding handler. +---@field range? boolean|lsp._anonym2.range +--- +---The client will send the `textDocument/semanticTokens/full` request if +---the server provides a corresponding handler. +---@field full? boolean|lsp.ClientSemanticTokensRequestFullDelta + +---@since 3.18.0 +---@class lsp.ClientInlayHintResolveOptions +--- +---The properties that a client can resolve lazily. +---@field properties string[] + +---@since 3.18.0 +---@class lsp.ClientShowMessageActionItemOptions +--- +---Whether the client supports additional attributes which +---are preserved and send back to the server in the +---request's response. +---@field additionalPropertiesSupport? boolean + +---@since 3.18.0 +---@class lsp.CompletionItemTagOptions +--- +---The tags supported by the client. +---@field valueSet lsp.CompletionItemTag[] + +---@since 3.18.0 +---@class lsp.ClientCompletionItemResolveOptions +--- +---The properties that a client can resolve lazily. +---@field properties string[] + +---@since 3.18.0 +---@class lsp.ClientCompletionItemInsertTextModeOptions +--- +---@field valueSet lsp.InsertTextMode[] + +---@since 3.18.0 +---@class lsp.ClientSignatureParameterInformationOptions +--- +---The client supports processing label offsets instead of a +---simple label string. +--- +---@since 3.14.0 +---@field labelOffsetSupport? boolean + +---@since 3.18.0 +---@class lsp.ClientCodeActionKindOptions +--- +---The code action kind values the client supports. When this +---property exists the client also guarantees that it will +---handle values outside its set gracefully and falls back +---to a default value when unknown. +---@field valueSet lsp.CodeActionKind[] + +---@since 3.18.0 +---@class lsp.ClientDiagnosticsTagOptions +--- +---The tags supported by the client. +---@field valueSet lsp.DiagnosticTag[] + +---@since 3.18.0 +---@class lsp.ClientSemanticTokensRequestFullDelta +--- +---The client will send the `textDocument/semanticTokens/full/delta` request if +---the server provides a corresponding handler. +---@field delta? boolean + ---A set of predefined token types. This set is not fixed ---an clients can specify additional token types via the ---corresponding client capabilities. @@ -4325,6 +5010,7 @@ error('Cannot require a meta file') ---| "regexp" # regexp ---| "operator" # operator ---| "decorator" # decorator +---| "label" # label ---A set of predefined token modifiers. This set is not fixed ---an clients can specify additional token types via the @@ -4515,12 +5201,14 @@ error('Cannot require a meta file') ---| "refactor" # Refactor ---| "refactor.extract" # RefactorExtract ---| "refactor.inline" # RefactorInline +---| "refactor.move" # RefactorMove ---| "refactor.rewrite" # RefactorRewrite ---| "source" # Source ---| "source.organizeImports" # SourceOrganizeImports ---| "source.fixAll" # SourceFixAll +---| "notebook" # Notebook ----@alias lsp.TraceValues +---@alias lsp.TraceValue ---| "off" # Off ---| "messages" # Messages ---| "verbose" # Verbose @@ -4534,13 +5222,79 @@ error('Cannot require a meta file') ---| "plaintext" # PlainText ---| "markdown" # Markdown +---Predefined Language kinds +---@since 3.18.0 +---@proposed +---@alias lsp.LanguageKind +---| "abap" # ABAP +---| "bat" # WindowsBat +---| "bibtex" # BibTeX +---| "clojure" # Clojure +---| "coffeescript" # Coffeescript +---| "c" # C +---| "cpp" # CPP +---| "csharp" # CSharp +---| "css" # CSS +---| "d" # D +---| "pascal" # Delphi +---| "diff" # Diff +---| "dart" # Dart +---| "dockerfile" # Dockerfile +---| "elixir" # Elixir +---| "erlang" # Erlang +---| "fsharp" # FSharp +---| "git-commit" # GitCommit +---| "rebase" # GitRebase +---| "go" # Go +---| "groovy" # Groovy +---| "handlebars" # Handlebars +---| "haskell" # Haskell +---| "html" # HTML +---| "ini" # Ini +---| "java" # Java +---| "javascript" # JavaScript +---| "javascriptreact" # JavaScriptReact +---| "json" # JSON +---| "latex" # LaTeX +---| "less" # Less +---| "lua" # Lua +---| "makefile" # Makefile +---| "markdown" # Markdown +---| "objective-c" # ObjectiveC +---| "objective-cpp" # ObjectiveCPP +---| "pascal" # Pascal +---| "perl" # Perl +---| "perl6" # Perl6 +---| "php" # PHP +---| "powershell" # Powershell +---| "jade" # Pug +---| "python" # Python +---| "r" # R +---| "razor" # Razor +---| "ruby" # Ruby +---| "rust" # Rust +---| "scss" # SCSS +---| "sass" # SASS +---| "scala" # Scala +---| "shaderlab" # ShaderLab +---| "shellscript" # ShellScript +---| "sql" # SQL +---| "swift" # Swift +---| "typescript" # TypeScript +---| "typescriptreact" # TypeScriptReact +---| "tex" # TeX +---| "vb" # VisualBasic +---| "xml" # XML +---| "xsl" # XSL +---| "yaml" # YAML + ---Describes how an {@link InlineCompletionItemProvider inline completion provider} was triggered. --- ---@since 3.18.0 ---@proposed ---@alias lsp.InlineCompletionTriggerKind ----| 0 # Invoked ----| 1 # Automatic +---| 1 # Invoked +---| 2 # Automatic ---A set of predefined position encoding kinds. --- @@ -4684,7 +5438,7 @@ error('Cannot require a meta file') ---@since 3.17.0 ---@alias lsp.DocumentDiagnosticReport lsp.RelatedFullDocumentDiagnosticReport|lsp.RelatedUnchangedDocumentDiagnosticReport ----@alias lsp.PrepareRenameResult lsp.Range|lsp._anonym46.PrepareRenameResult|lsp._anonym47.PrepareRenameResult +---@alias lsp.PrepareRenameResult lsp.Range|lsp.PrepareRenamePlaceholder|lsp.PrepareRenameDefaultBehavior ---A document selector is the combination of one or many document filters. --- @@ -4705,7 +5459,7 @@ error('Cannot require a meta file') ---An event describing a change to a text document. If only a text is provided ---it is considered to be the full content of the document. ----@alias lsp.TextDocumentContentChangeEvent lsp._anonym48.TextDocumentContentChangeEvent|lsp._anonym49.TextDocumentContentChangeEvent +---@alias lsp.TextDocumentContentChangeEvent lsp.TextDocumentContentChangePartial|lsp.TextDocumentContentChangeWholeDocument ---MarkedString can be used to render human readable text. It is either a markdown string ---or a code-block that provides a language and a code snippet. The language identifier @@ -4719,7 +5473,7 @@ error('Cannot require a meta file') --- ---Note that markdown strings will be sanitized - that means html will be escaped. ---@deprecated use MarkupContent instead. ----@alias lsp.MarkedString string|lsp._anonym50.MarkedString +---@alias lsp.MarkedString string|lsp.MarkedStringWithLanguage ---A document filter describes a top level text document or ---a notebook cell document. @@ -4752,14 +5506,14 @@ error('Cannot require a meta file') ---\@sample A language filter that applies to all package.json paths: `{ language: 'json', pattern: '**package.json' }` --- ---@since 3.17.0 ----@alias lsp.TextDocumentFilter lsp._anonym51.TextDocumentFilter|lsp._anonym52.TextDocumentFilter|lsp._anonym53.TextDocumentFilter +---@alias lsp.TextDocumentFilter lsp.TextDocumentFilterLanguage|lsp.TextDocumentFilterScheme|lsp.TextDocumentFilterPattern ---A notebook document filter denotes a notebook document by ---different properties. The properties will be match ---against the notebook's URI (same as with documents) --- ---@since 3.17.0 ----@alias lsp.NotebookDocumentFilter lsp._anonym54.NotebookDocumentFilter|lsp._anonym55.NotebookDocumentFilter|lsp._anonym56.NotebookDocumentFilter +---@alias lsp.NotebookDocumentFilter lsp.NotebookDocumentFilterNotebookType|lsp.NotebookDocumentFilterScheme|lsp.NotebookDocumentFilterPattern ---The glob pattern to watch relative to the base path. Glob patterns can have the following syntax: ---- `*` to match one or more characters in a path segment @@ -4772,512 +5526,8 @@ error('Cannot require a meta file') ---@since 3.17.0 ---@alias lsp.Pattern string ----@class lsp._anonym1.serverInfo ---- ----The name of the server as defined by the server. ----@field name string ---- ----The server's version as defined by the server. ----@field version? string - ----@class lsp._anonym3.itemDefaults.editRange ---- ----@field insert lsp.Range ---- ----@field replace lsp.Range - ----@class lsp._anonym2.itemDefaults ---- ----A default commit character set. ---- ----@since 3.17.0 ----@field commitCharacters? string[] ---- ----A default edit range. ---- ----@since 3.17.0 ----@field editRange? lsp.Range|lsp._anonym3.itemDefaults.editRange ---- ----A default insert text format. ---- ----@since 3.17.0 ----@field insertTextFormat? lsp.InsertTextFormat ---- ----A default insert text mode. ---- ----@since 3.17.0 ----@field insertTextMode? lsp.InsertTextMode ---- ----A default data value. ---- ----@since 3.17.0 ----@field data? lsp.LSPAny - ----@class lsp._anonym4.disabled ---- ----Human readable description of why the code action is currently disabled. ---- ----This is displayed in the code actions UI. ----@field reason string - ----@class lsp._anonym5.location ---- ----@field uri lsp.DocumentUri - ----@class lsp._anonym6.range - ----@class lsp._anonym7.full ---- ----The server supports deltas for full documents. ----@field delta? boolean - ----@class lsp._anonym9.cells.structure ---- ----The change to the cell array. ----@field array lsp.NotebookCellArrayChange ---- ----Additional opened cell text documents. ----@field didOpen? lsp.TextDocumentItem[] ---- ----Additional closed cell text documents. ----@field didClose? lsp.TextDocumentIdentifier[] - ----@class lsp._anonym10.cells.textContent ---- ----@field document lsp.VersionedTextDocumentIdentifier ---- ----@field changes lsp.TextDocumentContentChangeEvent[] - ----@class lsp._anonym8.cells ---- ----Changes to the cell structure to add or ----remove cells. ----@field structure? lsp._anonym9.cells.structure ---- ----Changes to notebook cells properties like its ----kind, execution summary or metadata. ----@field data? lsp.NotebookCell[] ---- ----Changes to the text content of notebook cells. ----@field textContent? lsp._anonym10.cells.textContent[] - ----@class lsp._anonym11.clientInfo ---- ----The name of the client as defined by the client. ----@field name string ---- ----The client's version as defined by the client. ----@field version? string - ----@class lsp._anonym13.textDocument.diagnostic ---- ----Whether the server supports `MarkupContent` in diagnostic messages. ----@field markupMessageSupport? boolean - ----@class lsp._anonym12.textDocument ---- ----Capabilities specific to the diagnostic pull model. ---- ----@since 3.18.0 ----@field diagnostic? lsp._anonym13.textDocument.diagnostic - ----@class lsp._anonym14.workspace ---- ----The server supports workspace folder. ---- ----@since 3.6.0 ----@field workspaceFolders? lsp.WorkspaceFoldersServerCapabilities ---- ----The server is interested in notifications/requests for operations on files. ---- ----@since 3.16.0 ----@field fileOperations? lsp.FileOperationOptions - ----@class lsp._anonym15.completionItem ---- ----The server has support for completion item label ----details (see also `CompletionItemLabelDetails`) when ----receiving a completion item in a resolve call. ---- ----@since 3.17.0 ----@field labelDetailsSupport? boolean - ----@class lsp._anonym17.notebookSelector.cells ---- ----@field language string - ----@class lsp._anonym16.notebookSelector ---- ----The notebook to be synced If a string ----value is provided it matches against the ----notebook type. '*' matches every notebook. ----@field notebook string|lsp.NotebookDocumentFilter ---- ----The cells of the matching notebook to be synced. ----@field cells? lsp._anonym17.notebookSelector.cells[] - ----@class lsp._anonym19.notebookSelector.cells ---- ----@field language string - ----@class lsp._anonym18.notebookSelector ---- ----The notebook to be synced If a string ----value is provided it matches against the ----notebook type. '*' matches every notebook. ----@field notebook? string|lsp.NotebookDocumentFilter ---- ----The cells of the matching notebook to be synced. ----@field cells lsp._anonym19.notebookSelector.cells[] - ----@class lsp._anonym20.staleRequestSupport ---- ----The client will actively cancel the request. ----@field cancel boolean ---- ----The list of requests for which the client ----will retry the request if it receives a ----response with error code `ContentModified` ----@field retryOnContentModified string[] - ----@class lsp._anonym21.changeAnnotationSupport ---- ----Whether the client groups edits with equal labels into tree nodes, ----for instance all edits labelled with "Changes in Strings" would ----be a tree node. ----@field groupsOnLabel? boolean +---@alias lsp.RegularExpressionEngineKind string ----@class lsp._anonym22.symbolKind ---- ----The symbol kind values the client supports. When this ----property exists the client also guarantees that it will ----handle values outside its set gracefully and falls back ----to a default value when unknown. ---- ----If this property is not present the client only supports ----the symbol kinds from `File` to `Array` as defined in ----the initial version of the protocol. ----@field valueSet? lsp.SymbolKind[] +---@class lsp._anonym1.range ----@class lsp._anonym23.tagSupport ---- ----The tags supported by the client. ----@field valueSet lsp.SymbolTag[] - ----@class lsp._anonym24.resolveSupport ---- ----The properties that a client can resolve lazily. Usually ----`location.range` ----@field properties string[] - ----@class lsp._anonym26.completionItem.tagSupport ---- ----The tags supported by the client. ----@field valueSet lsp.CompletionItemTag[] - ----@class lsp._anonym27.completionItem.resolveSupport ---- ----The properties that a client can resolve lazily. ----@field properties string[] - ----@class lsp._anonym28.completionItem.insertTextModeSupport ---- ----@field valueSet lsp.InsertTextMode[] - ----@class lsp._anonym25.completionItem ---- ----Client supports snippets as insert text. ---- ----A snippet can define tab stops and placeholders with `$1`, `$2` ----and `${3:foo}`. `$0` defines the final tab stop, it defaults to ----the end of the snippet. Placeholders with equal identifiers are linked, ----that is typing in one will update others too. ----@field snippetSupport? boolean ---- ----Client supports commit characters on a completion item. ----@field commitCharactersSupport? boolean ---- ----Client supports the following content formats for the documentation ----property. The order describes the preferred format of the client. ----@field documentationFormat? lsp.MarkupKind[] ---- ----Client supports the deprecated property on a completion item. ----@field deprecatedSupport? boolean ---- ----Client supports the preselect property on a completion item. ----@field preselectSupport? boolean ---- ----Client supports the tag property on a completion item. Clients supporting ----tags have to handle unknown tags gracefully. Clients especially need to ----preserve unknown tags when sending a completion item back to the server in ----a resolve call. ---- ----@since 3.15.0 ----@field tagSupport? lsp._anonym26.completionItem.tagSupport ---- ----Client support insert replace edit to control different behavior if a ----completion item is inserted in the text or should replace text. ---- ----@since 3.16.0 ----@field insertReplaceSupport? boolean ---- ----Indicates which properties a client can resolve lazily on a completion ----item. Before version 3.16.0 only the predefined properties `documentation` ----and `details` could be resolved lazily. ---- ----@since 3.16.0 ----@field resolveSupport? lsp._anonym27.completionItem.resolveSupport ---- ----The client supports the `insertTextMode` property on ----a completion item to override the whitespace handling mode ----as defined by the client (see `insertTextMode`). ---- ----@since 3.16.0 ----@field insertTextModeSupport? lsp._anonym28.completionItem.insertTextModeSupport ---- ----The client has support for completion item label ----details (see also `CompletionItemLabelDetails`). ---- ----@since 3.17.0 ----@field labelDetailsSupport? boolean - ----@class lsp._anonym29.completionItemKind ---- ----The completion item kind values the client supports. When this ----property exists the client also guarantees that it will ----handle values outside its set gracefully and falls back ----to a default value when unknown. ---- ----If this property is not present the client only supports ----the completion items kinds from `Text` to `Reference` as defined in ----the initial version of the protocol. ----@field valueSet? lsp.CompletionItemKind[] - ----@class lsp._anonym30.completionList ---- ----The client supports the following itemDefaults on ----a completion list. ---- ----The value lists the supported property names of the ----`CompletionList.itemDefaults` object. If omitted ----no properties are supported. ---- ----@since 3.17.0 ----@field itemDefaults? string[] - ----@class lsp._anonym32.signatureInformation.parameterInformation ---- ----The client supports processing label offsets instead of a ----simple label string. ---- ----@since 3.14.0 ----@field labelOffsetSupport? boolean - ----@class lsp._anonym31.signatureInformation ---- ----Client supports the following content formats for the documentation ----property. The order describes the preferred format of the client. ----@field documentationFormat? lsp.MarkupKind[] ---- ----Client capabilities specific to parameter information. ----@field parameterInformation? lsp._anonym32.signatureInformation.parameterInformation ---- ----The client supports the `activeParameter` property on `SignatureInformation` ----literal. ---- ----@since 3.16.0 ----@field activeParameterSupport? boolean ---- ----The client supports the `activeParameter` property on ----`SignatureInformation` being set to `null` to indicate that no ----parameter should be active. ---- ----@since 3.18.0 ----@field noActiveParameterSupport? boolean - ----@class lsp._anonym33.symbolKind ---- ----The symbol kind values the client supports. When this ----property exists the client also guarantees that it will ----handle values outside its set gracefully and falls back ----to a default value when unknown. ---- ----If this property is not present the client only supports ----the symbol kinds from `File` to `Array` as defined in ----the initial version of the protocol. ----@field valueSet? lsp.SymbolKind[] - ----@class lsp._anonym34.tagSupport ---- ----The tags supported by the client. ----@field valueSet lsp.SymbolTag[] - ----@class lsp._anonym36.codeActionLiteralSupport.codeActionKind ---- ----The code action kind values the client supports. When this ----property exists the client also guarantees that it will ----handle values outside its set gracefully and falls back ----to a default value when unknown. ----@field valueSet lsp.CodeActionKind[] - ----@class lsp._anonym35.codeActionLiteralSupport ---- ----The code action kind is support with the following value ----set. ----@field codeActionKind lsp._anonym36.codeActionLiteralSupport.codeActionKind - ----@class lsp._anonym37.resolveSupport ---- ----The properties that a client can resolve lazily. ----@field properties string[] - ----@class lsp._anonym38.foldingRangeKind ---- ----The folding range kind values the client supports. When this ----property exists the client also guarantees that it will ----handle values outside its set gracefully and falls back ----to a default value when unknown. ----@field valueSet? lsp.FoldingRangeKind[] - ----@class lsp._anonym39.foldingRange ---- ----If set, the client signals that it supports setting collapsedText on ----folding ranges to display custom labels instead of the default text. ---- ----@since 3.17.0 ----@field collapsedText? boolean - ----@class lsp._anonym40.tagSupport ---- ----The tags supported by the client. ----@field valueSet lsp.DiagnosticTag[] - ----@class lsp._anonym42.requests.range - ----@class lsp._anonym43.requests.full ---- ----The client will send the `textDocument/semanticTokens/full/delta` request if ----the server provides a corresponding handler. ----@field delta? boolean - ----@class lsp._anonym41.requests ---- ----The client will send the `textDocument/semanticTokens/range` request if ----the server provides a corresponding handler. ----@field range? boolean|lsp._anonym42.requests.range ---- ----The client will send the `textDocument/semanticTokens/full` request if ----the server provides a corresponding handler. ----@field full? boolean|lsp._anonym43.requests.full - ----@class lsp._anonym44.resolveSupport ---- ----The properties that a client can resolve lazily. ----@field properties string[] - ----@class lsp._anonym45.messageActionItem ---- ----Whether the client supports additional attributes which ----are preserved and send back to the server in the ----request's response. ----@field additionalPropertiesSupport? boolean - ----@class lsp._anonym46.PrepareRenameResult ---- ----@field range lsp.Range ---- ----@field placeholder string - ----@class lsp._anonym47.PrepareRenameResult ---- ----@field defaultBehavior boolean - ----@class lsp._anonym48.TextDocumentContentChangeEvent ---- ----The range of the document that changed. ----@field range lsp.Range ---- ----The optional length of the range that got replaced. ---- ----@deprecated use range instead. ----@field rangeLength? uinteger ---- ----The new text for the provided range. ----@field text string - ----@class lsp._anonym49.TextDocumentContentChangeEvent ---- ----The new text of the whole document. ----@field text string - ----@class lsp._anonym50.MarkedString ---- ----@field language string ---- ----@field value string - ----@class lsp._anonym51.TextDocumentFilter ---- ----A language id, like `typescript`. ----@field language string ---- ----A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ----@field scheme? string ---- ----A glob pattern, like **/*.{ts,js}. See TextDocumentFilter for examples. ----@field pattern? string - ----@class lsp._anonym52.TextDocumentFilter ---- ----A language id, like `typescript`. ----@field language? string ---- ----A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ----@field scheme string ---- ----A glob pattern, like **/*.{ts,js}. See TextDocumentFilter for examples. ----@field pattern? string - ----@class lsp._anonym53.TextDocumentFilter ---- ----A language id, like `typescript`. ----@field language? string ---- ----A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ----@field scheme? string ---- ----A glob pattern, like **/*.{ts,js}. See TextDocumentFilter for examples. ----@field pattern string - ----@class lsp._anonym54.NotebookDocumentFilter ---- ----The type of the enclosing notebook. ----@field notebookType string ---- ----A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ----@field scheme? string ---- ----A glob pattern. ----@field pattern? string - ----@class lsp._anonym55.NotebookDocumentFilter ---- ----The type of the enclosing notebook. ----@field notebookType? string ---- ----A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ----@field scheme string ---- ----A glob pattern. ----@field pattern? string - ----@class lsp._anonym56.NotebookDocumentFilter ---- ----The type of the enclosing notebook. ----@field notebookType? string ---- ----A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ----@field scheme? string ---- ----A glob pattern. ----@field pattern string +---@class lsp._anonym2.range diff --git a/runtime/lua/vim/lsp/_watchfiles.lua b/runtime/lua/vim/lsp/_watchfiles.lua index 49328fbe9b..98e9818bcd 100644 --- a/runtime/lua/vim/lsp/_watchfiles.lua +++ b/runtime/lua/vim/lsp/_watchfiles.lua @@ -9,8 +9,8 @@ local M = {} if vim.fn.has('win32') == 1 or vim.fn.has('mac') == 1 then M._watchfunc = watch.watch -elseif vim.fn.executable('fswatch') == 1 then - M._watchfunc = watch.fswatch +elseif vim.fn.executable('inotifywait') == 1 then + M._watchfunc = watch.inotify else M._watchfunc = watch.watchdirs end diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 49833eaeec..301c1f0cb6 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -29,7 +29,12 @@ local function request(method, params, handler) end --- Displays hover information about the symbol under the cursor in a floating ---- window. Calling the function twice will jump into the floating window. +--- window. The window will be dismissed on cursor move. +--- Calling the function twice will jump into the floating window +--- (thus by default, "KK" will open the hover window and focus it). +--- In the floating window, all commands and mappings are available as usual, +--- except that "q" dismisses the window. +--- You can scroll the contents the same as you would any other buffer. function M.hover() local params = util.make_position_params() request(ms.textDocument_hover, params) @@ -135,7 +140,7 @@ end ---@param mode "v"|"V" ---@return table {start={row,col}, end={row,col}} using (1, 0) indexing local function range_from_selection(bufnr, mode) - -- TODO: Use `vim.region()` instead https://github.com/neovim/neovim/pull/13896 + -- TODO: Use `vim.fn.getregionpos()` instead. -- [bufnum, lnum, col, off]; both row and column 1-indexed local start = vim.fn.getpos('v') @@ -205,9 +210,11 @@ end --- Range to format. --- Table must contain `start` and `end` keys with {row,col} tuples using --- (1,0) indexing. +--- Can also be a list of tables that contain `start` and `end` keys as described above, +--- in which case `textDocument/rangesFormatting` support is required. --- (Default: current selection in visual mode, `nil` in other modes, --- formatting the full buffer) ---- @field range? {start:integer[],end:integer[]} +--- @field range? {start:[integer,integer],end:[integer, integer]}|{start:[integer,integer],end:[integer,integer]}[] --- Formats a buffer using the attached (and optionally filtered) language --- server clients. @@ -218,10 +225,20 @@ function M.format(opts) local bufnr = opts.bufnr or api.nvim_get_current_buf() local mode = api.nvim_get_mode().mode local range = opts.range + -- Try to use visual selection if no range is given if not range and mode == 'v' or mode == 'V' then range = range_from_selection(bufnr, mode) end - local method = range and ms.textDocument_rangeFormatting or ms.textDocument_formatting + + local passed_multiple_ranges = (range and #range ~= 0 and type(range[1]) == 'table') + local method ---@type string + if passed_multiple_ranges then + method = ms.textDocument_rangesFormatting + elseif range then + method = ms.textDocument_rangeFormatting + else + method = ms.textDocument_formatting + end local clients = vim.lsp.get_clients({ id = opts.id, @@ -241,10 +258,14 @@ function M.format(opts) --- @param params lsp.DocumentFormattingParams --- @return lsp.DocumentFormattingParams local function set_range(client, params) - if range then - local range_params = - util.make_given_range_params(range.start, range['end'], bufnr, client.offset_encoding) - params.range = range_params.range + local to_lsp_range = function(r) ---@return lsp.DocumentRangeFormattingParams|lsp.DocumentRangesFormattingParams + return util.make_given_range_params(r.start, r['end'], bufnr, client.offset_encoding).range + end + + if passed_multiple_ranges then + params.ranges = vim.tbl_map(to_lsp_range, range) + elseif range then + params.range = to_lsp_range(range) end return params end @@ -431,11 +452,9 @@ function M.document_symbol(opts) request_with_opts(ms.textDocument_documentSymbol, params, opts) end ---- @param call_hierarchy_items lsp.CallHierarchyItem[]? +--- @param call_hierarchy_items lsp.CallHierarchyItem[] +--- @return lsp.CallHierarchyItem? local function pick_call_hierarchy_item(call_hierarchy_items) - if not call_hierarchy_items then - return - end if #call_hierarchy_items == 1 then return call_hierarchy_items[1] end @@ -448,7 +467,7 @@ local function pick_call_hierarchy_item(call_hierarchy_items) if choice < 1 or choice > #items then return end - return choice + return call_hierarchy_items[choice] end --- @param method string @@ -460,7 +479,7 @@ local function call_hierarchy(method) vim.notify(err.message, vim.log.levels.WARN) return end - if not result then + if not result or vim.tbl_isempty(result) then vim.notify('No item resolved', vim.log.levels.WARN) return end @@ -836,14 +855,10 @@ function M.code_action(opts) if opts.diagnostics or opts.only then opts = { options = opts } end - local context = opts.context or {} + local context = opts.context and vim.deepcopy(opts.context) or {} if not context.triggerKind then context.triggerKind = vim.lsp.protocol.CodeActionTriggerKind.Invoked end - if not context.diagnostics then - local bufnr = api.nvim_get_current_buf() - context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics(bufnr) - end local mode = api.nvim_get_mode().mode local bufnr = api.nvim_get_current_buf() local win = api.nvim_get_current_win() @@ -885,7 +900,23 @@ function M.code_action(opts) else params = util.make_range_params(win, client.offset_encoding) end - params.context = context + if context.diagnostics then + params.context = context + else + local ns_push = vim.lsp.diagnostic.get_namespace(client.id, false) + local ns_pull = vim.lsp.diagnostic.get_namespace(client.id, true) + local diagnostics = {} + local lnum = api.nvim_win_get_cursor(0)[1] - 1 + vim.list_extend(diagnostics, vim.diagnostic.get(bufnr, { namespace = ns_pull, lnum = lnum })) + vim.list_extend(diagnostics, vim.diagnostic.get(bufnr, { namespace = ns_push, lnum = lnum })) + params.context = vim.tbl_extend('force', context, { + ---@diagnostic disable-next-line: no-unknown + diagnostics = vim.tbl_map(function(d) + return d.user_data.lsp + end, diagnostics), + }) + end + client.request(ms.textDocument_codeAction, params, on_result, bufnr) end end diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 4beb7fefda..e3c82f4169 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -182,7 +182,7 @@ local validate = vim.validate --- It can be `null` if the client supports workspace folders but none are --- configured. --- @field workspace_folders lsp.WorkspaceFolder[]? ---- @field root_dir string +--- @field root_dir string? --- --- @field attached_buffers table<integer,true> --- @@ -233,11 +233,11 @@ local validate = vim.validate --- --- Sends a request to the server and synchronously waits for the response. --- This is a wrapper around {client.request} ---- Returns: { err=err, result=result }, a dictionary, where `err` and `result` +--- Returns: { err=err, result=result }, a dict, where `err` and `result` --- come from the |lsp-handler|. On timeout, cancel or error, returns `(nil, --- err)` where `err` is a string describing the failure reason. If the request --- was unsuccessful returns `nil`. ---- @field request_sync fun(method: string, params: table?, timeout_ms: integer?, bufnr: integer): {err: lsp.ResponseError|nil, result:any}|nil, string|nil err # a dictionary, where +--- @field request_sync fun(method: string, params: table?, timeout_ms: integer?, bufnr: integer): {err: lsp.ResponseError|nil, result:any}|nil, string|nil err # a dict --- --- Sends a notification to an LSP server. --- Returns: a boolean to indicate if the notification was successful. If @@ -436,7 +436,7 @@ local function ensure_list(x) return { x } end ---- @package +--- @nodoc --- @param config vim.lsp.ClientConfig --- @return vim.lsp.Client? function Client.create(config) @@ -470,7 +470,6 @@ function Client.create(config) _on_exit_cbs = ensure_list(config.on_exit), _on_attach_cbs = ensure_list(config.on_attach), _on_error_cb = config.on_error, - _root_dir = config.root_dir, _trace = get_trace(config.trace), --- Contains $/progress report messages. @@ -536,7 +535,7 @@ function Client:_run_callbacks(cbs, error_id, ...) end end ---- @package +--- @nodoc function Client:initialize() local config = self.config @@ -657,7 +656,7 @@ end --- @param method string LSP method name. --- @param params? table LSP request params. --- @param handler? lsp.Handler Response |lsp-handler| for this method. ---- @param bufnr? integer Buffer handle (0 for current). +--- @param bufnr integer Buffer handle (0 for current). --- @return boolean status, integer? request_id {status} is a bool indicating --- whether the request was successful. If it is `false`, then it will --- always be `false` (the client has shutdown). If it was @@ -739,7 +738,7 @@ end --- @param timeout_ms (integer|nil) Maximum time in milliseconds to wait for --- a result. Defaults to 1000 --- @param bufnr (integer) Buffer handle (0 for current). ---- @return {err: lsp.ResponseError|nil, result:any}|nil, string|nil err # a dictionary, where +--- @return {err: lsp.ResponseError|nil, result:any}|nil, string|nil err # a dict, where --- `err` and `result` come from the |lsp-handler|. --- On timeout, cancel or error, returns `(nil, err)` where `err` is a --- string describing the failure reason. If the request was unsuccessful @@ -862,14 +861,14 @@ function Client:_is_stopped() return self.rpc.is_closing() end ---- @package --- Execute a lsp command, either via client command function (if available) --- or via workspace/executeCommand (if supported by the server) --- --- @param command lsp.Command --- @param context? {bufnr: integer} --- @param handler? lsp.Handler only called if a server command -function Client:_exec_cmd(command, context, handler) +--- @param on_unsupported? function handler invoked when the command is not supported by the client. +function Client:_exec_cmd(command, context, handler, on_unsupported) context = vim.deepcopy(context or {}, true) --[[@as lsp.HandlerContext]] context.bufnr = context.bufnr or api.nvim_get_current_buf() context.client_id = self.id @@ -883,14 +882,18 @@ function Client:_exec_cmd(command, context, handler) local command_provider = self.server_capabilities.executeCommandProvider local commands = type(command_provider) == 'table' and command_provider.commands or {} if not vim.list_contains(commands, cmdname) then - vim.notify_once( - string.format( - 'Language server `%s` does not support command `%s`. This command may require a client extension.', - self.name, - cmdname - ), - vim.log.levels.WARN - ) + if on_unsupported then + on_unsupported() + else + vim.notify_once( + string.format( + 'Language server `%s` does not support command `%s`. This command may require a client extension.', + self.name, + cmdname + ), + vim.log.levels.WARN + ) + end return end -- Not using command directly to exclude extra properties, @@ -902,7 +905,6 @@ function Client:_exec_cmd(command, context, handler) self.request(ms.workspace_executeCommand, params, handler, context.bufnr) end ---- @package --- Default handler for the 'textDocument/didOpen' LSP notification. --- --- @param bufnr integer Number of the buffer, or 0 for current @@ -914,18 +916,16 @@ function Client:_text_document_did_open_handler(bufnr) if not api.nvim_buf_is_loaded(bufnr) then return end - local filetype = vim.bo[bufnr].filetype - local params = { + local filetype = vim.bo[bufnr].filetype + self.notify(ms.textDocument_didOpen, { textDocument = { - version = 0, + version = lsp.util.buf_versions[bufnr], uri = vim.uri_from_bufnr(bufnr), languageId = self.get_language_id(bufnr, filetype), text = lsp._buf_get_full_text(bufnr), }, - } - self.notify(ms.textDocument_didOpen, params) - lsp.util.buf_versions[bufnr] = params.textDocument.version + }) -- Next chance we get, we should re-do the diagnostics vim.schedule(function() @@ -938,7 +938,6 @@ function Client:_text_document_did_open_handler(bufnr) end) end ---- @package --- Runs the on_attach function from the client's config if it was defined. --- @param bufnr integer Buffer number function Client:_on_attach(bufnr) @@ -1061,7 +1060,6 @@ function Client:_on_exit(code, signal) ) end ---- @package --- Add a directory to the workspace folders. --- @param dir string? function Client:_add_workspace_folder(dir) @@ -1084,7 +1082,6 @@ function Client:_add_workspace_folder(dir) vim.list_extend(self.workspace_folders, wf) end ---- @package --- Remove a directory to the workspace folders. --- @param dir string? function Client:_remove_workspace_folder(dir) diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua index c85bb6aa32..c1b6bfb28c 100644 --- a/runtime/lua/vim/lsp/codelens.lua +++ b/runtime/lua/vim/lsp/codelens.lua @@ -307,7 +307,13 @@ function M.refresh(opts) } active_refreshes[buf] = true - local request_ids = vim.lsp.buf_request(buf, ms.textDocument_codeLens, params, M.on_codelens) + local request_ids = vim.lsp.buf_request( + buf, + ms.textDocument_codeLens, + params, + M.on_codelens, + function() end + ) if vim.tbl_isempty(request_ids) then active_refreshes[buf] = nil end diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua new file mode 100644 index 0000000000..71ea2df100 --- /dev/null +++ b/runtime/lua/vim/lsp/completion.lua @@ -0,0 +1,754 @@ +local M = {} + +local api = vim.api +local lsp = vim.lsp +local protocol = lsp.protocol +local ms = protocol.Methods + +local rtt_ms = 50 +local ns_to_ms = 0.000001 + +--- @alias vim.lsp.CompletionResult lsp.CompletionList | lsp.CompletionItem[] + +-- TODO(mariasolos): Remove this declaration once we figure out a better way to handle +-- literal/anonymous types (see https://github.com/neovim/neovim/pull/27542/files#r1495259331). +--- @nodoc +--- @class lsp.ItemDefaults +--- @field editRange lsp.Range | { insert: lsp.Range, replace: lsp.Range } | nil +--- @field insertTextFormat lsp.InsertTextFormat? +--- @field insertTextMode lsp.InsertTextMode? +--- @field data any + +--- @nodoc +--- @class vim.lsp.completion.BufHandle +--- @field clients table<integer, vim.lsp.Client> +--- @field triggers table<string, vim.lsp.Client[]> +--- @field convert? fun(item: lsp.CompletionItem): table + +--- @type table<integer, vim.lsp.completion.BufHandle> +local buf_handles = {} + +--- @nodoc +--- @class vim.lsp.completion.Context +local Context = { + cursor = nil, --- @type [integer, integer]? + last_request_time = nil, --- @type integer? + pending_requests = {}, --- @type function[] + isIncomplete = false, +} + +--- @nodoc +function Context:cancel_pending() + for _, cancel in ipairs(self.pending_requests) do + cancel() + end + + self.pending_requests = {} +end + +--- @nodoc +function Context:reset() + -- Note that the cursor isn't reset here, it needs to survive a `CompleteDone` event. + self.isIncomplete = false + self.last_request_time = nil + self:cancel_pending() +end + +--- @type uv.uv_timer_t? +local completion_timer = nil + +--- @return uv.uv_timer_t +local function new_timer() + return assert(vim.uv.new_timer()) +end + +local function reset_timer() + if completion_timer then + completion_timer:stop() + completion_timer:close() + end + + completion_timer = nil +end + +--- @param window integer +--- @param warmup integer +--- @return fun(sample: number): number +local function exp_avg(window, warmup) + local count = 0 + local sum = 0 + local value = 0 + + return function(sample) + if count < warmup then + count = count + 1 + sum = sum + sample + value = sum / count + else + local factor = 2.0 / (window + 1) + value = value * (1 - factor) + sample * factor + end + return value + end +end +local compute_new_average = exp_avg(10, 10) + +--- @return number +local function next_debounce() + if not Context.last_request_time then + return rtt_ms + end + + local ms_since_request = (vim.uv.hrtime() - Context.last_request_time) * ns_to_ms + return math.max((ms_since_request - rtt_ms) * -1, 0) +end + +--- @param input string Unparsed snippet +--- @return string # Parsed snippet if successful, else returns its input +local function parse_snippet(input) + local ok, parsed = pcall(function() + return lsp._snippet_grammar.parse(input) + end) + return ok and tostring(parsed) or input +end + +--- @param item lsp.CompletionItem +--- @param suffix? string +local function apply_snippet(item, suffix) + if item.textEdit then + vim.snippet.expand(item.textEdit.newText .. suffix) + elseif item.insertText then + vim.snippet.expand(item.insertText .. suffix) + end +end + +--- Returns text that should be inserted when a selecting completion item. The +--- precedence is as follows: textEdit.newText > insertText > label +--- +--- See https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion +--- +--- @param item lsp.CompletionItem +--- @return string +local function get_completion_word(item) + if item.insertTextFormat == protocol.InsertTextFormat.Snippet then + if item.textEdit then + -- Use label instead of text if text has different starting characters. + -- label is used as abbr (=displayed), but word is used for filtering + -- This is required for things like postfix completion. + -- E.g. in lua: + -- + -- local f = {} + -- f@| + -- â–² + -- └─ cursor + -- + -- item.textEdit.newText: table.insert(f, $0) + -- label: insert + -- + -- Typing `i` would remove the candidate because newText starts with `t`. + local text = parse_snippet(item.insertText or item.textEdit.newText) + return #text < #item.label and vim.fn.matchstr(text, '\\k*') or item.label + elseif item.insertText and item.insertText ~= '' then + return parse_snippet(item.insertText) + else + return item.label + end + elseif item.textEdit then + local word = item.textEdit.newText + return word:match('^(%S*)') or word + elseif item.insertText and item.insertText ~= '' then + return item.insertText + end + return item.label +end + +--- Applies the given defaults to the completion item, modifying it in place. +--- +--- @param item lsp.CompletionItem +--- @param defaults lsp.ItemDefaults? +local function apply_defaults(item, defaults) + if not defaults then + return + end + + item.insertTextFormat = item.insertTextFormat or defaults.insertTextFormat + item.insertTextMode = item.insertTextMode or defaults.insertTextMode + item.data = item.data or defaults.data + if defaults.editRange then + local textEdit = item.textEdit or {} + item.textEdit = textEdit + textEdit.newText = textEdit.newText or item.textEditText or item.insertText or item.label + if defaults.editRange.start then + textEdit.range = textEdit.range or defaults.editRange + elseif defaults.editRange.insert then + textEdit.insert = defaults.editRange.insert + textEdit.replace = defaults.editRange.replace + end + end +end + +--- @param result vim.lsp.CompletionResult +--- @return lsp.CompletionItem[] +local function get_items(result) + if result.items then + -- When we have a list, apply the defaults and return an array of items. + for _, item in ipairs(result.items) do + ---@diagnostic disable-next-line: param-type-mismatch + apply_defaults(item, result.itemDefaults) + end + return result.items + else + -- Else just return the items as they are. + return result + end +end + +---@param item lsp.CompletionItem +---@return string +local function get_doc(item) + local doc = item.documentation + if not doc then + return '' + end + if type(doc) == 'string' then + return doc + end + if type(doc) == 'table' and type(doc.value) == 'string' then + return doc.value + end + + vim.notify('invalid documentation value: ' .. vim.inspect(doc), vim.log.levels.WARN) + return '' +end + +--- Turns the result of a `textDocument/completion` request into vim-compatible +--- |complete-items|. +--- +--- @private +--- @param result vim.lsp.CompletionResult Result of `textDocument/completion` +--- @param prefix string prefix to filter the completion items +--- @param client_id integer? Client ID +--- @return table[] +--- @see complete-items +function M._lsp_to_complete_items(result, prefix, client_id) + local items = get_items(result) + if vim.tbl_isempty(items) then + return {} + end + + ---@type fun(item: lsp.CompletionItem):boolean + local matches + if not prefix:find('%w') then + matches = function(_) + return true + end + else + ---@param item lsp.CompletionItem + matches = function(item) + local text = item.filterText or item.label + return next(vim.fn.matchfuzzy({ text }, prefix)) ~= nil + end + end + + local candidates = {} + local bufnr = api.nvim_get_current_buf() + local user_convert = vim.tbl_get(buf_handles, bufnr, 'convert') + for _, item in ipairs(items) do + if matches(item) then + local word = get_completion_word(item) + local hl_group = '' + if + item.deprecated + or vim.list_contains((item.tags or {}), protocol.CompletionTag.Deprecated) + then + hl_group = 'DiagnosticDeprecated' + end + local completion_item = { + word = word, + abbr = item.label, + kind = protocol.CompletionItemKind[item.kind] or 'Unknown', + menu = item.detail or '', + info = get_doc(item), + icase = 1, + dup = 1, + empty = 1, + hl_group = hl_group, + user_data = { + nvim = { + lsp = { + completion_item = item, + client_id = client_id, + }, + }, + }, + } + if user_convert then + completion_item = vim.tbl_extend('keep', user_convert(item), completion_item) + end + table.insert(candidates, completion_item) + end + end + ---@diagnostic disable-next-line: no-unknown + table.sort(candidates, function(a, b) + ---@type lsp.CompletionItem + local itema = a.user_data.nvim.lsp.completion_item + ---@type lsp.CompletionItem + local itemb = b.user_data.nvim.lsp.completion_item + return (itema.sortText or itema.label) < (itemb.sortText or itemb.label) + end) + + return candidates +end + +--- @param lnum integer 0-indexed +--- @param line string +--- @param items lsp.CompletionItem[] +--- @param encoding string +--- @return integer? +local function adjust_start_col(lnum, line, items, encoding) + local min_start_char = nil + for _, item in pairs(items) do + if item.textEdit and item.textEdit.range.start.line == lnum then + if min_start_char and min_start_char ~= item.textEdit.range.start.character then + return nil + end + min_start_char = item.textEdit.range.start.character + end + end + if min_start_char then + return lsp.util._str_byteindex_enc(line, min_start_char, encoding) + else + return nil + end +end + +--- @private +--- @param line string line content +--- @param lnum integer 0-indexed line number +--- @param cursor_col integer +--- @param client_id integer client ID +--- @param client_start_boundary integer 0-indexed word boundary +--- @param server_start_boundary? integer 0-indexed word boundary, based on textEdit.range.start.character +--- @param result vim.lsp.CompletionResult +--- @param encoding string +--- @return table[] matches +--- @return integer? server_start_boundary +function M._convert_results( + line, + lnum, + cursor_col, + client_id, + client_start_boundary, + server_start_boundary, + result, + encoding +) + -- Completion response items may be relative to a position different than `client_start_boundary`. + -- Concrete example, with lua-language-server: + -- + -- require('plenary.asy| + -- â–² â–² â–² + -- │ │ └── cursor_pos: 20 + -- │ └────── client_start_boundary: 17 + -- └────────────── textEdit.range.start.character: 9 + -- .newText = 'plenary.async' + -- ^^^ + -- prefix (We'd remove everything not starting with `asy`, + -- so we'd eliminate the `plenary.async` result + -- + -- `adjust_start_col` is used to prefer the language server boundary. + -- + local candidates = get_items(result) + local curstartbyte = adjust_start_col(lnum, line, candidates, encoding) + if server_start_boundary == nil then + server_start_boundary = curstartbyte + elseif curstartbyte ~= nil and curstartbyte ~= server_start_boundary then + server_start_boundary = client_start_boundary + end + local prefix = line:sub((server_start_boundary or client_start_boundary) + 1, cursor_col) + local matches = M._lsp_to_complete_items(result, prefix, client_id) + return matches, server_start_boundary +end + +--- @param clients table<integer, vim.lsp.Client> # keys != client_id +--- @param bufnr integer +--- @param win integer +--- @param callback fun(responses: table<integer, { err: lsp.ResponseError, result: vim.lsp.CompletionResult }>) +--- @return function # Cancellation function +local function request(clients, bufnr, win, callback) + local responses = {} --- @type table<integer, { err: lsp.ResponseError, result: any }> + local request_ids = {} --- @type table<integer, integer> + local remaining_requests = vim.tbl_count(clients) + + for _, client in pairs(clients) do + local client_id = client.id + local params = lsp.util.make_position_params(win, client.offset_encoding) + local ok, request_id = client.request(ms.textDocument_completion, params, function(err, result) + responses[client_id] = { err = err, result = result } + remaining_requests = remaining_requests - 1 + if remaining_requests == 0 then + callback(responses) + end + end, bufnr) + + if ok then + request_ids[client_id] = request_id + end + end + + return function() + for client_id, request_id in pairs(request_ids) do + local client = lsp.get_client_by_id(client_id) + if client then + client.cancel_request(request_id) + end + end + end +end + +local function trigger(bufnr, clients) + reset_timer() + Context:cancel_pending() + + if tonumber(vim.fn.pumvisible()) == 1 and not Context.isIncomplete then + return + end + + local win = api.nvim_get_current_win() + local cursor_row, cursor_col = unpack(api.nvim_win_get_cursor(win)) --- @type integer, integer + local line = api.nvim_get_current_line() + local line_to_cursor = line:sub(1, cursor_col) + local word_boundary = vim.fn.match(line_to_cursor, '\\k*$') + local start_time = vim.uv.hrtime() + Context.last_request_time = start_time + + local cancel_request = request(clients, bufnr, win, function(responses) + local end_time = vim.uv.hrtime() + rtt_ms = compute_new_average((end_time - start_time) * ns_to_ms) + + Context.pending_requests = {} + Context.isIncomplete = false + + local row_changed = api.nvim_win_get_cursor(win)[1] ~= cursor_row + local mode = api.nvim_get_mode().mode + if row_changed or not (mode == 'i' or mode == 'ic') then + return + end + + local matches = {} + local server_start_boundary --- @type integer? + for client_id, response in pairs(responses) do + if response.err then + vim.notify_once(response.err.message, vim.log.levels.warn) + end + + local result = response.result + if result then + Context.isIncomplete = Context.isIncomplete or result.isIncomplete + local client = lsp.get_client_by_id(client_id) + local encoding = client and client.offset_encoding or 'utf-16' + local client_matches + client_matches, server_start_boundary = M._convert_results( + line, + cursor_row - 1, + cursor_col, + client_id, + word_boundary, + nil, + result, + encoding + ) + vim.list_extend(matches, client_matches) + end + end + local start_col = (server_start_boundary or word_boundary) + 1 + vim.fn.complete(start_col, matches) + end) + + table.insert(Context.pending_requests, cancel_request) +end + +--- @param handle vim.lsp.completion.BufHandle +local function on_insert_char_pre(handle) + if tonumber(vim.fn.pumvisible()) == 1 then + if Context.isIncomplete then + reset_timer() + + local debounce_ms = next_debounce() + if debounce_ms == 0 then + vim.schedule(M.trigger) + else + completion_timer = new_timer() + completion_timer:start(debounce_ms, 0, vim.schedule_wrap(M.trigger)) + end + end + + return + end + + local char = api.nvim_get_vvar('char') + if not completion_timer and handle.triggers[char] then + completion_timer = assert(vim.uv.new_timer()) + completion_timer:start(25, 0, function() + reset_timer() + vim.schedule(M.trigger) + end) + end +end + +local function on_insert_leave() + reset_timer() + Context.cursor = nil + Context:reset() +end + +local function on_complete_done() + local completed_item = api.nvim_get_vvar('completed_item') + if not completed_item or not completed_item.user_data or not completed_item.user_data.nvim then + Context:reset() + return + end + + local cursor_row, cursor_col = unpack(api.nvim_win_get_cursor(0)) --- @type integer, integer + cursor_row = cursor_row - 1 + local completion_item = completed_item.user_data.nvim.lsp.completion_item --- @type lsp.CompletionItem + local client_id = completed_item.user_data.nvim.lsp.client_id --- @type integer + if not completion_item or not client_id then + Context:reset() + return + end + + local bufnr = api.nvim_get_current_buf() + local expand_snippet = completion_item.insertTextFormat == protocol.InsertTextFormat.Snippet + and (completion_item.textEdit ~= nil or completion_item.insertText ~= nil) + + Context:reset() + + local client = lsp.get_client_by_id(client_id) + if not client then + return + end + + local offset_encoding = client.offset_encoding or 'utf-16' + local resolve_provider = (client.server_capabilities.completionProvider or {}).resolveProvider + + local function clear_word() + if not expand_snippet then + return nil + end + + -- Remove the already inserted word. + local start_char = cursor_col - #completed_item.word + local line = api.nvim_buf_get_lines(bufnr, cursor_row, cursor_row + 1, true)[1] + api.nvim_buf_set_text(bufnr, cursor_row, start_char, cursor_row, #line, { '' }) + return line:sub(cursor_col + 1) + end + + --- @param suffix? string + local function apply_snippet_and_command(suffix) + if expand_snippet then + apply_snippet(completion_item, suffix) + end + + local command = completion_item.command + if command then + client:_exec_cmd(command, { bufnr = bufnr }, nil, function() + vim.lsp.log.warn( + string.format( + 'Language server `%s` does not support command `%s`. This command may require a client extension.', + client.name, + command.command + ) + ) + end) + end + end + + if completion_item.additionalTextEdits and next(completion_item.additionalTextEdits) then + local suffix = clear_word() + lsp.util.apply_text_edits(completion_item.additionalTextEdits, bufnr, offset_encoding) + apply_snippet_and_command(suffix) + elseif resolve_provider and type(completion_item) == 'table' then + local changedtick = vim.b[bufnr].changedtick + + --- @param result lsp.CompletionItem + client.request(ms.completionItem_resolve, completion_item, function(err, result) + if changedtick ~= vim.b[bufnr].changedtick then + return + end + + local suffix = clear_word() + if err then + vim.notify_once(err.message, vim.log.levels.WARN) + elseif result and result.additionalTextEdits then + lsp.util.apply_text_edits(result.additionalTextEdits, bufnr, offset_encoding) + if result.command then + completion_item.command = result.command + end + end + + apply_snippet_and_command(suffix) + end, bufnr) + else + local suffix = clear_word() + apply_snippet_and_command(suffix) + end +end + +--- @class vim.lsp.completion.BufferOpts +--- @field autotrigger? boolean Whether to trigger completion automatically. Default: false +--- @field convert? fun(item: lsp.CompletionItem): table Transforms an LSP CompletionItem to |complete-items|. + +---@param client_id integer +---@param bufnr integer +---@param opts vim.lsp.completion.BufferOpts +local function enable_completions(client_id, bufnr, opts) + local buf_handle = buf_handles[bufnr] + if not buf_handle then + buf_handle = { clients = {}, triggers = {}, convert = opts.convert } + buf_handles[bufnr] = buf_handle + + -- Attach to buffer events. + api.nvim_buf_attach(bufnr, false, { + on_detach = function(_, buf) + buf_handles[buf] = nil + end, + on_reload = function(_, buf) + M.enable(true, client_id, buf, opts) + end, + }) + + -- Set up autocommands. + local group = + api.nvim_create_augroup(string.format('vim/lsp/completion-%d', bufnr), { clear = true }) + api.nvim_create_autocmd('CompleteDone', { + group = group, + buffer = bufnr, + callback = function() + local reason = api.nvim_get_vvar('event').reason --- @type string + if reason == 'accept' then + on_complete_done() + end + end, + }) + if opts.autotrigger then + api.nvim_create_autocmd('InsertCharPre', { + group = group, + buffer = bufnr, + callback = function() + on_insert_char_pre(buf_handles[bufnr]) + end, + }) + api.nvim_create_autocmd('InsertLeave', { + group = group, + buffer = bufnr, + callback = on_insert_leave, + }) + end + end + + if not buf_handle.clients[client_id] then + local client = lsp.get_client_by_id(client_id) + assert(client, 'invalid client ID') + + -- Add the new client to the buffer's clients. + buf_handle.clients[client_id] = client + + -- Add the new client to the clients that should be triggered by its trigger characters. + --- @type string[] + local triggers = vim.tbl_get( + client.server_capabilities, + 'completionProvider', + 'triggerCharacters' + ) or {} + for _, char in ipairs(triggers) do + local clients_for_trigger = buf_handle.triggers[char] + if not clients_for_trigger then + clients_for_trigger = {} + buf_handle.triggers[char] = clients_for_trigger + end + local client_exists = vim.iter(clients_for_trigger):any(function(c) + return c.id == client_id + end) + if not client_exists then + table.insert(clients_for_trigger, client) + end + end + end +end + +--- @param client_id integer +--- @param bufnr integer +local function disable_completions(client_id, bufnr) + local handle = buf_handles[bufnr] + if not handle then + return + end + + handle.clients[client_id] = nil + if not next(handle.clients) then + buf_handles[bufnr] = nil + api.nvim_del_augroup_by_name(string.format('vim/lsp/completion-%d', bufnr)) + else + for char, clients in pairs(handle.triggers) do + --- @param c vim.lsp.Client + handle.triggers[char] = vim.tbl_filter(function(c) + return c.id ~= client_id + end, clients) + end + end +end + +--- Enables or disables completions from the given language client in the given buffer. +--- +--- @param enable boolean True to enable, false to disable +--- @param client_id integer Client ID +--- @param bufnr integer Buffer handle, or 0 for the current buffer +--- @param opts? vim.lsp.completion.BufferOpts +function M.enable(enable, client_id, bufnr, opts) + bufnr = (bufnr == 0 and api.nvim_get_current_buf()) or bufnr + + if enable then + enable_completions(client_id, bufnr, opts or {}) + else + disable_completions(client_id, bufnr) + end +end + +--- Trigger LSP completion in the current buffer. +function M.trigger() + local bufnr = api.nvim_get_current_buf() + local clients = (buf_handles[bufnr] or {}).clients or {} + trigger(bufnr, clients) +end + +--- Implements 'omnifunc' compatible LSP completion. +--- +--- @see |complete-functions| +--- @see |complete-items| +--- @see |CompleteDone| +--- +--- @param findstart integer 0 or 1, decides behavior +--- @param base integer findstart=0, text to match against +--- +--- @return integer|table Decided by {findstart}: +--- - findstart=0: column where the completion starts, or -2 or -3 +--- - findstart=1: list of matches (actually just calls |complete()|) +function M._omnifunc(findstart, base) + vim.lsp.log.debug('omnifunc.findstart', { findstart = findstart, base = base }) + assert(base) -- silence luals + local bufnr = api.nvim_get_current_buf() + local clients = lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_completion }) + local remaining = #clients + if remaining == 0 then + return findstart == 1 and -1 or {} + end + + trigger(bufnr, clients) + + -- Return -2 to signal that we should continue completion so that we can + -- async complete. + return -2 +end + +return M diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 08cea13548..c10312484b 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -110,6 +110,14 @@ local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id) return vim.tbl_map(function(diagnostic) local start = diagnostic.range.start local _end = diagnostic.range['end'] + local message = diagnostic.message + if type(message) ~= 'string' then + vim.notify_once( + string.format('Unsupported Markup message from LSP client %d', client_id), + vim.lsp.log_levels.ERROR + ) + message = diagnostic.message.value + end --- @type vim.Diagnostic return { lnum = start.line, @@ -117,18 +125,12 @@ local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id) end_lnum = _end.line, end_col = line_byte_from_position(buf_lines, _end.line, _end.character, offset_encoding), severity = severity_lsp_to_vim(diagnostic.severity), - message = diagnostic.message, + message = message, source = diagnostic.source, code = diagnostic.code, _tags = tags_lsp_to_vim(diagnostic, client_id), user_data = { - lsp = { - -- usage of user_data.lsp.code is deprecated in favor of the top-level code field - code = diagnostic.code, - codeDescription = diagnostic.codeDescription, - relatedInformation = diagnostic.relatedInformation, - data = diagnostic.data, - }, + lsp = diagnostic, }, } end, diagnostics) @@ -151,14 +153,18 @@ local function tags_vim_to_lsp(diagnostic) return tags end +--- Converts the input `vim.Diagnostic`s to LSP diagnostics. --- @param diagnostics vim.Diagnostic[] --- @return lsp.Diagnostic[] -local function diagnostic_vim_to_lsp(diagnostics) +function M.from(diagnostics) ---@param diagnostic vim.Diagnostic ---@return lsp.Diagnostic return vim.tbl_map(function(diagnostic) - return vim.tbl_extend('keep', { - -- "keep" the below fields over any duplicate fields in diagnostic.user_data.lsp + local user_data = diagnostic.user_data or {} + if user_data.lsp then + return user_data.lsp + end + return { range = { start = { line = diagnostic.lnum, @@ -174,7 +180,7 @@ local function diagnostic_vim_to_lsp(diagnostics) source = diagnostic.source, code = diagnostic.code, tags = tags_vim_to_lsp(diagnostic), - }, diagnostic.user_data and (diagnostic.user_data.lsp or {}) or {}) + } end, diagnostics) end @@ -366,6 +372,7 @@ end --- Structured: { [1] = {...}, [5] = {.... } } ---@private function M.get_line_diagnostics(bufnr, line_nr, opts, client_id) + vim.deprecate('vim.lsp.diagnostic.get_line_diagnostics', 'vim.diagnostic.get', '0.12') convert_severity(opts) local diag_opts = {} --- @type vim.diagnostic.GetOpts @@ -379,7 +386,7 @@ function M.get_line_diagnostics(bufnr, line_nr, opts, client_id) diag_opts.lnum = line_nr or (api.nvim_win_get_cursor(0)[1] - 1) - return diagnostic_vim_to_lsp(vim.diagnostic.get(bufnr, diag_opts)) + return M.from(vim.diagnostic.get(bufnr, diag_opts)) end --- Clear diagnostics from pull based clients diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index f9d394642c..44548fec92 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -3,7 +3,7 @@ local protocol = require('vim.lsp.protocol') local ms = protocol.Methods local util = require('vim.lsp.util') local api = vim.api -local completion = require('vim.lsp._completion') +local completion = require('vim.lsp.completion') --- @type table<string,lsp.Handler> local M = {} @@ -646,6 +646,7 @@ M[ms.window_showMessage] = function(_, result, ctx, _) if message_type == protocol.MessageType.Error then err_message('LSP[', client_name, '] ', message) else + --- @type string local message_type_name = protocol.MessageType[message_type] api.nvim_out_write(string.format('LSP[%s][%s] %s\n', client_name, message_type_name, message)) end diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua index a79ae76eb9..18066a84db 100644 --- a/runtime/lua/vim/lsp/health.lua +++ b/runtime/lua/vim/lsp/health.lua @@ -33,16 +33,25 @@ local function check_active_clients() local clients = vim.lsp.get_clients() if next(clients) then for _, client in pairs(clients) do - local attached_to = table.concat(vim.tbl_keys(client.attached_buffers or {}), ',') - report_info( + local cmd ---@type string + if type(client.config.cmd) == 'table' then + cmd = table.concat(client.config.cmd --[[@as table]], ' ') + elseif type(client.config.cmd) == 'function' then + cmd = tostring(client.config.cmd) + end + report_info(table.concat({ + string.format('%s (id: %d)', client.name, client.id), string.format( - '%s (id=%s, root_dir=%s, attached_to=[%s])', - client.name, - client.id, - vim.fn.fnamemodify(client.root_dir, ':~'), - attached_to - ) - ) + ' Root directory: %s', + client.root_dir and vim.fn.fnamemodify(client.root_dir, ':~') or nil + ), + string.format(' Command: %s', cmd), + string.format(' Settings: %s', vim.inspect(client.settings, { newline = '\n ' })), + string.format( + ' Attached buffers: %s', + vim.iter(pairs(client.attached_buffers)):map(tostring):join(', ') + ), + }, '\n')) end else report_info('No active clients') @@ -50,7 +59,7 @@ local function check_active_clients() end local function check_watcher() - vim.health.start('vim.lsp: File watcher') + vim.health.start('vim.lsp: File Watcher') -- Only run the check if file watching has been enabled by a client. local clients = vim.lsp.get_clients() @@ -81,8 +90,8 @@ local function check_watcher() watchfunc_name = 'libuv-watch' elseif watchfunc == vim._watch.watchdirs then watchfunc_name = 'libuv-watchdirs' - elseif watchfunc == vim._watch.fswatch then - watchfunc_name = 'fswatch' + elseif watchfunc == vim._watch.inotifywait then + watchfunc_name = 'inotifywait' else local nm = debug.getinfo(watchfunc, 'S').source watchfunc_name = string.format('Custom (%s)', nm) @@ -90,7 +99,63 @@ local function check_watcher() report_info('File watch backend: ' .. watchfunc_name) if watchfunc_name == 'libuv-watchdirs' then - report_warn('libuv-watchdirs has known performance issues. Consider installing fswatch.') + report_warn('libuv-watchdirs has known performance issues. Consider installing inotify-tools.') + end +end + +local function check_position_encodings() + vim.health.start('vim.lsp: Position Encodings') + local clients = vim.lsp.get_clients() + if next(clients) then + local position_encodings = {} ---@type table<integer, table<string, integer[]>> + for _, client in pairs(clients) do + for bufnr in pairs(client.attached_buffers) do + if not position_encodings[bufnr] then + position_encodings[bufnr] = {} + end + if not position_encodings[bufnr][client.offset_encoding] then + position_encodings[bufnr][client.offset_encoding] = {} + end + table.insert(position_encodings[bufnr][client.offset_encoding], client.id) + end + end + + -- Check if any buffers are attached to multiple clients with different position encodings + local buffers = {} ---@type integer[] + for bufnr, encodings in pairs(position_encodings) do + local list = {} ---@type string[] + for k in pairs(encodings) do + list[#list + 1] = k + end + + if #list > 1 then + buffers[#buffers + 1] = bufnr + end + end + + if #buffers > 0 then + local lines = + { 'Found buffers attached to multiple clients with different position encodings.' } + for _, bufnr in ipairs(buffers) do + local encodings = position_encodings[bufnr] + local parts = {} + for encoding, client_ids in pairs(encodings) do + table.insert( + parts, + string.format('%s (client id(s): %s)', encoding:upper(), table.concat(client_ids, ', ')) + ) + end + table.insert(lines, string.format('- Buffer %d: %s', bufnr, table.concat(parts, ', '))) + end + report_warn( + table.concat(lines, '\n'), + 'Use the positionEncodings client capability to ensure all clients use the same position encoding' + ) + else + report_info('No buffers contain mixed position encodings') + end + else + report_info('No active clients') end end @@ -99,6 +164,7 @@ function M.check() check_log() check_active_clients() check_watcher() + check_position_encodings() end return M diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua index f98496456b..61059180fe 100644 --- a/runtime/lua/vim/lsp/inlay_hint.lua +++ b/runtime/lua/vim/lsp/inlay_hint.lua @@ -43,17 +43,16 @@ function M.on_inlayhint(err, result, ctx, _) return end local bufnr = assert(ctx.bufnr) - if util.buf_versions[bufnr] ~= ctx.version then + if + util.buf_versions[bufnr] ~= ctx.version + or not result + or not api.nvim_buf_is_loaded(bufnr) + or not bufstates[bufnr].enabled + then return end local client_id = ctx.client_id - if not result then - return - end local bufstate = bufstates[bufnr] - if not bufstate.enabled then - return - end if not (bufstate.client_hints and bufstate.version) then bufstate.client_hints = vim.defaulttable() bufstate.version = ctx.version @@ -77,12 +76,7 @@ function M.on_inlayhint(err, result, ctx, _) local col = position.character if col > 0 then local line = lines[position.line + 1] or '' - local ok, convert_result - ok, convert_result = pcall(util._str_byteindex_enc, line, col, client.offset_encoding) - if ok then - return convert_result - end - return math.min(#line, col) + return util._str_byteindex_enc(line, col, client.offset_encoding) end return col end @@ -336,6 +330,8 @@ api.nvim_set_decoration_provider(namespace, { for lnum = topline, botline do if bufstate.applied[lnum] ~= bufstate.version then api.nvim_buf_clear_namespace(bufnr, namespace, lnum, lnum + 1) + + local hint_virtual_texts = {} --- @type table<integer, [string, string?][]> for _, lnum_hints in pairs(client_hints) do local hints = lnum_hints[lnum] or {} for _, hint in pairs(hints) do @@ -348,7 +344,7 @@ api.nvim_set_decoration_provider(namespace, { text = text .. part.value end end - local vt = {} --- @type {[1]: string, [2]: string?}[] + local vt = hint_virtual_texts[hint.position.character] or {} if hint.paddingLeft then vt[#vt + 1] = { ' ' } end @@ -356,13 +352,18 @@ api.nvim_set_decoration_provider(namespace, { if hint.paddingRight then vt[#vt + 1] = { ' ' } end - api.nvim_buf_set_extmark(bufnr, namespace, lnum, hint.position.character, { - virt_text_pos = 'inline', - ephemeral = false, - virt_text = vt, - }) + hint_virtual_texts[hint.position.character] = vt end end + + for pos, vt in pairs(hint_virtual_texts) do + api.nvim_buf_set_extmark(bufnr, namespace, lnum, pos, { + virt_text_pos = 'inline', + ephemeral = false, + virt_text = vt, + }) + end + bufstate.applied[lnum] = bufstate.version end end @@ -370,7 +371,7 @@ api.nvim_set_decoration_provider(namespace, { }) --- Query whether inlay hint is enabled in the {filter}ed scope ---- @param filter vim.lsp.inlay_hint.enable.Filter +--- @param filter? vim.lsp.inlay_hint.enable.Filter --- @return boolean --- @since 12 function M.is_enabled(filter) diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua index 9f2bd71158..4f177b47fd 100644 --- a/runtime/lua/vim/lsp/log.lua +++ b/runtime/lua/vim/lsp/log.lua @@ -9,7 +9,7 @@ local log_levels = vim.log.levels --- Can be used to lookup the number from the name or the name from the number. --- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" --- Level numbers begin with "TRACE" at 0 ---- @type table<string|integer, string|integer> +--- @type table<string,integer> | table<integer, string> --- @nodoc log.levels = vim.deepcopy(log_levels) @@ -19,7 +19,7 @@ local current_log_level = log_levels.WARN local log_date_format = '%F %H:%M:%S' local function format_func(arg) - return vim.inspect(arg, { newline = '' }) + return vim.inspect(arg, { newline = ' ', indent = '' }) end local function notify(msg, level) diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 419c2ff644..1699fff0c1 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -12,9 +12,6 @@ end local sysname = vim.uv.os_uname().sysname --- Protocol for the Microsoft Language Server Protocol (mslsp) -local protocol = {} - local constants = { --- @enum lsp.DiagnosticSeverity DiagnosticSeverity = { @@ -46,6 +43,8 @@ local constants = { Info = 3, -- A log message. Log = 4, + -- A debug message. + Debug = 5, }, -- The file event type. @@ -100,6 +99,13 @@ local constants = { TriggerForIncompleteCompletions = 3, }, + -- Completion item tags are extra annotations that tweak the rendering of a + -- completion item + CompletionTag = { + -- Render a completion as obsolete, usually using a strike-out. + Deprecated = 1, + }, + -- A document highlight kind. DocumentHighlightKind = { -- A textual occurrence. @@ -308,326 +314,18 @@ local constants = { }, } -for k1, v1 in pairs(constants) do - local tbl = vim.deepcopy(v1, true) - for _, k2 in ipairs(vim.tbl_keys(tbl)) do - local v2 = tbl[k2] - tbl[v2] = k2 +-- Protocol for the Microsoft Language Server Protocol (mslsp) +local protocol = {} + +--- @diagnostic disable:no-unknown +for k1, v1 in pairs(vim.deepcopy(constants, true)) do + for _, k2 in ipairs(vim.tbl_keys(v1)) do + local v2 = v1[k2] + v1[v2] = k2 end - protocol[k1] = tbl + protocol[k1] = v1 end - ---[=[ ---Text document specific client capabilities. -export interface TextDocumentClientCapabilities { - synchronization?: { - --Whether text document synchronization supports dynamic registration. - dynamicRegistration?: boolean; - --The client supports sending will save notifications. - willSave?: boolean; - --The client supports sending a will save request and - --waits for a response providing text edits which will - --be applied to the document before it is saved. - willSaveWaitUntil?: boolean; - --The client supports did save notifications. - didSave?: boolean; - } - --Capabilities specific to the `textDocument/completion` - completion?: { - --Whether completion supports dynamic registration. - dynamicRegistration?: boolean; - --The client supports the following `CompletionItem` specific - --capabilities. - completionItem?: { - --The client supports snippets as insert text. - -- - --A snippet can define tab stops and placeholders with `$1`, `$2` - --and `${3:foo}`. `$0` defines the final tab stop, it defaults to - --the end of the snippet. Placeholders with equal identifiers are linked, - --that is typing in one will update others too. - snippetSupport?: boolean; - --The client supports commit characters on a completion item. - commitCharactersSupport?: boolean - --The client supports the following content formats for the documentation - --property. The order describes the preferred format of the client. - documentationFormat?: MarkupKind[]; - --The client supports the deprecated property on a completion item. - deprecatedSupport?: boolean; - --The client supports the preselect property on a completion item. - preselectSupport?: boolean; - } - completionItemKind?: { - --The completion item kind values the client supports. When this - --property exists the client also guarantees that it will - --handle values outside its set gracefully and falls back - --to a default value when unknown. - -- - --If this property is not present the client only supports - --the completion items kinds from `Text` to `Reference` as defined in - --the initial version of the protocol. - valueSet?: CompletionItemKind[]; - }, - --The client supports to send additional context information for a - --`textDocument/completion` request. - contextSupport?: boolean; - }; - --Capabilities specific to the `textDocument/hover` - hover?: { - --Whether hover supports dynamic registration. - dynamicRegistration?: boolean; - --The client supports the follow content formats for the content - --property. The order describes the preferred format of the client. - contentFormat?: MarkupKind[]; - }; - --Capabilities specific to the `textDocument/signatureHelp` - signatureHelp?: { - --Whether signature help supports dynamic registration. - dynamicRegistration?: boolean; - --The client supports the following `SignatureInformation` - --specific properties. - signatureInformation?: { - --The client supports the follow content formats for the documentation - --property. The order describes the preferred format of the client. - documentationFormat?: MarkupKind[]; - --Client capabilities specific to parameter information. - parameterInformation?: { - --The client supports processing label offsets instead of a - --simple label string. - -- - --Since 3.14.0 - labelOffsetSupport?: boolean; - } - }; - }; - --Capabilities specific to the `textDocument/references` - references?: { - --Whether references supports dynamic registration. - dynamicRegistration?: boolean; - }; - --Capabilities specific to the `textDocument/documentHighlight` - documentHighlight?: { - --Whether document highlight supports dynamic registration. - dynamicRegistration?: boolean; - }; - --Capabilities specific to the `textDocument/documentSymbol` - documentSymbol?: { - --Whether document symbol supports dynamic registration. - dynamicRegistration?: boolean; - --Specific capabilities for the `SymbolKind`. - symbolKind?: { - --The symbol kind values the client supports. When this - --property exists the client also guarantees that it will - --handle values outside its set gracefully and falls back - --to a default value when unknown. - -- - --If this property is not present the client only supports - --the symbol kinds from `File` to `Array` as defined in - --the initial version of the protocol. - valueSet?: SymbolKind[]; - } - --The client supports hierarchical document symbols. - hierarchicalDocumentSymbolSupport?: boolean; - }; - --Capabilities specific to the `textDocument/formatting` - formatting?: { - --Whether formatting supports dynamic registration. - dynamicRegistration?: boolean; - }; - --Capabilities specific to the `textDocument/rangeFormatting` - rangeFormatting?: { - --Whether range formatting supports dynamic registration. - dynamicRegistration?: boolean; - }; - --Capabilities specific to the `textDocument/onTypeFormatting` - onTypeFormatting?: { - --Whether on type formatting supports dynamic registration. - dynamicRegistration?: boolean; - }; - --Capabilities specific to the `textDocument/declaration` - declaration?: { - --Whether declaration supports dynamic registration. If this is set to `true` - --the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` - --return value for the corresponding server capability as well. - dynamicRegistration?: boolean; - --The client supports additional metadata in the form of declaration links. - -- - --Since 3.14.0 - linkSupport?: boolean; - }; - --Capabilities specific to the `textDocument/definition`. - -- - --Since 3.14.0 - definition?: { - --Whether definition supports dynamic registration. - dynamicRegistration?: boolean; - --The client supports additional metadata in the form of definition links. - linkSupport?: boolean; - }; - --Capabilities specific to the `textDocument/typeDefinition` - -- - --Since 3.6.0 - typeDefinition?: { - --Whether typeDefinition supports dynamic registration. If this is set to `true` - --the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` - --return value for the corresponding server capability as well. - dynamicRegistration?: boolean; - --The client supports additional metadata in the form of definition links. - -- - --Since 3.14.0 - linkSupport?: boolean; - }; - --Capabilities specific to the `textDocument/implementation`. - -- - --Since 3.6.0 - implementation?: { - --Whether implementation supports dynamic registration. If this is set to `true` - --the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` - --return value for the corresponding server capability as well. - dynamicRegistration?: boolean; - --The client supports additional metadata in the form of definition links. - -- - --Since 3.14.0 - linkSupport?: boolean; - }; - --Capabilities specific to the `textDocument/codeAction` - codeAction?: { - --Whether code action supports dynamic registration. - dynamicRegistration?: boolean; - --The client support code action literals as a valid - --response of the `textDocument/codeAction` request. - -- - --Since 3.8.0 - codeActionLiteralSupport?: { - --The code action kind is support with the following value - --set. - codeActionKind: { - --The code action kind values the client supports. When this - --property exists the client also guarantees that it will - --handle values outside its set gracefully and falls back - --to a default value when unknown. - valueSet: CodeActionKind[]; - }; - }; - }; - --Capabilities specific to the `textDocument/codeLens` - codeLens?: { - --Whether code lens supports dynamic registration. - dynamicRegistration?: boolean; - }; - --Capabilities specific to the `textDocument/documentLink` - documentLink?: { - --Whether document link supports dynamic registration. - dynamicRegistration?: boolean; - }; - --Capabilities specific to the `textDocument/documentColor` and the - --`textDocument/colorPresentation` request. - -- - --Since 3.6.0 - colorProvider?: { - --Whether colorProvider supports dynamic registration. If this is set to `true` - --the client supports the new `(ColorProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)` - --return value for the corresponding server capability as well. - dynamicRegistration?: boolean; - } - --Capabilities specific to the `textDocument/rename` - rename?: { - --Whether rename supports dynamic registration. - dynamicRegistration?: boolean; - --The client supports testing for validity of rename operations - --before execution. - prepareSupport?: boolean; - }; - --Capabilities specific to `textDocument/publishDiagnostics`. - publishDiagnostics?: { - --Whether the clients accepts diagnostics with related information. - relatedInformation?: boolean; - --Client supports the tag property to provide meta data about a diagnostic. - --Clients supporting tags have to handle unknown tags gracefully. - --Since 3.15.0 - tagSupport?: { - --The tags supported by this client - valueSet: DiagnosticTag[]; - }; - }; - --Capabilities specific to `textDocument/foldingRange` requests. - -- - --Since 3.10.0 - foldingRange?: { - --Whether implementation supports dynamic registration for folding range providers. If this is set to `true` - --the client supports the new `(FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)` - --return value for the corresponding server capability as well. - dynamicRegistration?: boolean; - --The maximum number of folding ranges that the client prefers to receive per document. The value serves as a - --hint, servers are free to follow the limit. - rangeLimit?: number; - --If set, the client signals that it only supports folding complete lines. If set, client will - --ignore specified `startCharacter` and `endCharacter` properties in a FoldingRange. - lineFoldingOnly?: boolean; - }; -} ---]=] - ---[=[ ---Workspace specific client capabilities. -export interface WorkspaceClientCapabilities { - --The client supports applying batch edits to the workspace by supporting - --the request 'workspace/applyEdit' - applyEdit?: boolean; - --Capabilities specific to `WorkspaceEdit`s - workspaceEdit?: { - --The client supports versioned document changes in `WorkspaceEdit`s - documentChanges?: boolean; - --The resource operations the client supports. Clients should at least - --support 'create', 'rename' and 'delete' files and folders. - resourceOperations?: ResourceOperationKind[]; - --The failure handling strategy of a client if applying the workspace edit - --fails. - failureHandling?: FailureHandlingKind; - }; - --Capabilities specific to the `workspace/didChangeConfiguration` notification. - didChangeConfiguration?: { - --Did change configuration notification supports dynamic registration. - dynamicRegistration?: boolean; - }; - --Capabilities specific to the `workspace/didChangeWatchedFiles` notification. - didChangeWatchedFiles?: { - --Did change watched files notification supports dynamic registration. Please note - --that the current protocol doesn't support static configuration for file changes - --from the server side. - dynamicRegistration?: boolean; - }; - --Capabilities specific to the `workspace/symbol` request. - symbol?: { - --Symbol request supports dynamic registration. - dynamicRegistration?: boolean; - --Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. - symbolKind?: { - --The symbol kind values the client supports. When this - --property exists the client also guarantees that it will - --handle values outside its set gracefully and falls back - --to a default value when unknown. - -- - --If this property is not present the client only supports - --the symbol kinds from `File` to `Array` as defined in - --the initial version of the protocol. - valueSet?: SymbolKind[]; - } - }; - --Capabilities specific to the `workspace/executeCommand` request. - executeCommand?: { - --Execute command supports dynamic registration. - dynamicRegistration?: boolean; - }; - --The client has support for workspace folders. - -- - --Since 3.6.0 - workspaceFolders?: boolean; - --The client supports `workspace/configuration` requests. - -- - --Since 3.6.0 - configuration?: boolean; -} ---]=] +--- @diagnostic enable:no-unknown --- Gets a new ClientCapabilities object describing the LSP client --- capabilities. @@ -729,23 +427,35 @@ function protocol.make_client_capabilities() properties = { 'edit' }, }, }, + codeLens = { + dynamicRegistration = false, + resolveSupport = { + properties = { 'command' }, + }, + }, formatting = { dynamicRegistration = true, }, rangeFormatting = { dynamicRegistration = true, + rangesSupport = true, }, completion = { dynamicRegistration = false, completionItem = { - -- Until we can actually expand snippet, move cursor and allow for true snippet experience, - -- this should be disabled out of the box. - -- However, users can turn this back on if they have a snippet plugin. - snippetSupport = false, + snippetSupport = true, commitCharactersSupport = false, preselectSupport = false, - deprecatedSupport = false, + deprecatedSupport = true, documentationFormat = { constants.MarkupKind.Markdown, constants.MarkupKind.PlainText }, + resolveSupport = { + properties = { + 'additionalTextEdits', + }, + }, + tagSupport = { + valueSet = get_value_set(constants.CompletionTag), + }, }, completionItemKind = { valueSet = get_value_set(constants.CompletionItemKind), @@ -852,7 +562,7 @@ function protocol.make_client_capabilities() workDoneProgress = true, showMessage = { messageActionItem = { - additionalPropertiesSupport = false, + additionalPropertiesSupport = true, }, }, showDocument = { @@ -905,9 +615,10 @@ function protocol.resolve_capabilities(server_capabilities) end -- Generated by gen_lsp.lua, keep at end of file. ---- LSP method names. --- +---@enum vim.lsp.protocol.Methods ---@see https://microsoft.github.io/language-server-protocol/specification/#metaModel +--- LSP method names. protocol.Methods = { --- A request to resolve the incoming calls for a given `CallHierarchyItem`. --- @since 3.16.0 @@ -1170,14 +881,14 @@ protocol.Methods = { --- symbol's location. --- @since 3.17.0 workspaceSymbol_resolve = 'workspaceSymbol/resolve', - --- A request sent from the server to the client to modify certain resources. + --- A request sent from the server to the client to modified certain resources. workspace_applyEdit = 'workspace/applyEdit', --- A request to refresh all code actions --- @since 3.16.0 workspace_codeLens_refresh = 'workspace/codeLens/refresh', --- The 'workspace/configuration' request is sent from the server to the client to fetch a certain --- configuration setting. - --- This pull model replaces the old push model where the client signaled configuration change via an + --- This pull model replaces the old push model were the client signaled configuration change via an --- event. If the server still needs to react to configuration changes (since the server caches the --- result of `workspace/configuration` requests) the server should register for an empty configuration --- change event and empty the cache if such an event is received. @@ -1210,7 +921,7 @@ protocol.Methods = { --- files were renamed from within the client. --- @since 3.16.0 workspace_didRenameFiles = 'workspace/didRenameFiles', - --- A request sent from the client to the server to execute a command. The request might return + --- A request send from the client to the server to execute a command. The request might return --- a workspace edit which the client will apply to the workspace. workspace_executeCommand = 'workspace/executeCommand', --- @since 3.18.0 @@ -1248,14 +959,5 @@ protocol.Methods = { --- The `workspace/workspaceFolders` is sent from the server to the client to fetch the open workspace folders. workspace_workspaceFolders = 'workspace/workspaceFolders', } -local function freeze(t) - return setmetatable({}, { - __index = t, - __newindex = function() - error('cannot modify immutable table') - end, - }) -end -protocol.Methods = freeze(protocol.Methods) return protocol diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index 3c63a12da2..e79dbd2db3 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -3,7 +3,7 @@ local log = require('vim.lsp.log') local protocol = require('vim.lsp.protocol') local validate, schedule, schedule_wrap = vim.validate, vim.schedule, vim.schedule_wrap -local is_win = uv.os_uname().version:find('Windows') +local is_win = vim.fn.has('win32') == 1 --- Checks whether a given path exists and is a directory. ---@param filename string path to check @@ -140,7 +140,7 @@ local client_errors = { SERVER_RESULT_CALLBACK_ERROR = 7, } ---- @type table<string|integer, string|integer> +--- @type table<string,integer> | table<integer,string> --- @nodoc M.client_errors = vim.deepcopy(client_errors) for k, v in pairs(client_errors) do @@ -407,7 +407,9 @@ function Client:handle_body(body) end log.debug('rpc.receive', decoded) - if type(decoded.method) == 'string' and decoded.id then + if type(decoded) ~= 'table' then + self:on_error(M.client_errors.INVALID_SERVER_MESSAGE, decoded) + elseif type(decoded.method) == 'string' and decoded.id then local err --- @type lsp.ResponseError|nil -- Schedule here so that the users functions don't trigger an error and -- we can still use the result. @@ -502,7 +504,7 @@ function Client:handle_body(body) if decoded.error then decoded.error = setmetatable(decoded.error, { __tostring = M.format_rpc_error, - }) --- @type table + }) end self:try_call( M.client_errors.SERVER_RESULT_CALLBACK_ERROR, @@ -548,7 +550,7 @@ local function new_client(dispatchers, transport) end ---@class vim.lsp.rpc.PublicClient ----@field request fun(method: string, params: table?, callback: fun(err: lsp.ResponseError|nil, result: any), notify_reply_callback: fun(integer)|nil):boolean,integer? see |vim.lsp.rpc.request()| +---@field request fun(method: string, params: table?, callback: fun(err: lsp.ResponseError|nil, result: any), notify_reply_callback: fun(message_id: integer)|nil):boolean,integer? see |vim.lsp.rpc.request()| ---@field notify fun(method: string, params: any):boolean see |vim.lsp.rpc.notify()| ---@field is_closing fun(): boolean ---@field terminate fun() @@ -701,7 +703,9 @@ function M.connect(host_or_path, port) if port == nil then handle:connect(host_or_path, on_connect) else - handle:connect(host_or_path, port, on_connect) + local info = uv.getaddrinfo(host_or_path, nil) + local resolved_host = info and info[1] and info[1].addr or host_or_path + handle:connect(resolved_host, port, on_connect) end return public_client(client) diff --git a/runtime/lua/vim/lsp/semantic_tokens.lua b/runtime/lua/vim/lsp/semantic_tokens.lua index ef2502b12e..8182457dd0 100644 --- a/runtime/lua/vim/lsp/semantic_tokens.lua +++ b/runtime/lua/vim/lsp/semantic_tokens.lua @@ -140,12 +140,7 @@ local function tokens_to_ranges(data, bufnr, client, request) local function _get_byte_pos(col) if col > 0 then local buf_line = lines[line + 1] or '' - local ok, result - ok, result = pcall(util._str_byteindex_enc, buf_line, col, client.offset_encoding) - if ok then - return result - end - return math.min(#buf_line, col) + return util._str_byteindex_enc(buf_line, col, client.offset_encoding) end return col end @@ -197,12 +192,6 @@ function STHighlighter.new(bufnr) highlighter:send_request() end end, - on_detach = function(_, buf) - local highlighter = STHighlighter.active[buf] - if highlighter then - highlighter:destroy() - end - end, }) api.nvim_create_autocmd({ 'BufWinEnter', 'InsertLeave' }, { @@ -418,7 +407,7 @@ end function STHighlighter:on_win(topline, botline) for client_id, state in pairs(self.client_state) do local current_result = state.current_result - if current_result.version and current_result.version == util.buf_versions[self.bufnr] then + if current_result.version == util.buf_versions[self.bufnr] then if not current_result.namespace_cleared then api.nvim_buf_clear_namespace(self.bufnr, state.namespace, 0, -1) current_result.namespace_cleared = true @@ -779,7 +768,6 @@ function M.highlight_token(token, bufnr, client_id, hl_group, opts) }) end ---- @package --- |lsp-handler| for the method `workspace/semanticTokens/refresh` --- --- Refresh requests are sent by the server to indicate a project-wide change diff --git a/runtime/lua/vim/lsp/sync.lua b/runtime/lua/vim/lsp/sync.lua index 936579e003..bdfe8d51b8 100644 --- a/runtime/lua/vim/lsp/sync.lua +++ b/runtime/lua/vim/lsp/sync.lua @@ -212,7 +212,8 @@ end ---@param lastline integer ---@param new_lastline integer ---@param offset_encoding string ----@return vim.lsp.sync.Range, vim.lsp.sync.Range +---@return vim.lsp.sync.Range prev_end_range +---@return vim.lsp.sync.Range curr_end_range local function compute_end_range( prev_lines, curr_lines, @@ -222,6 +223,16 @@ local function compute_end_range( new_lastline, offset_encoding ) + -- A special case for the following `firstline == new_lastline` case where lines are deleted. + -- Even if the buffer has become empty, nvim behaves as if it has an empty line with eol. + if #curr_lines == 1 and curr_lines[1] == '' then + local prev_line = prev_lines[lastline - 1] + return { + line_idx = lastline - 1, + byte_idx = #prev_line + 1, + char_idx = compute_line_length(prev_line, offset_encoding) + 1, + }, { line_idx = 1, byte_idx = 1, char_idx = 1 } + end -- If firstline == new_lastline, the first change occurred on a line that was deleted. -- In this case, the last_byte... if firstline == new_lastline then diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 5a229a1169..882ec22ca6 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -99,9 +99,26 @@ local function get_border_size(opts) return { height = height, width = width } end -local function split_lines(value) - value = string.gsub(value, '\r\n?', '\n') - return split(value, '\n', { plain = true, trimempty = true }) +--- Splits string at newlines, optionally removing unwanted blank lines. +--- +--- @param s string Multiline string +--- @param no_blank boolean? Drop blank lines for each @param/@return (except one empty line +--- separating each). Workaround for https://github.com/LuaLS/lua-language-server/issues/2333 +local function split_lines(s, no_blank) + s = string.gsub(s, '\r\n?', '\n') + local lines = {} + local in_desc = true -- Main description block, before seeing any @foo. + for line in vim.gsplit(s, '\n', { plain = true, trimempty = true }) do + local start_annotation = not not line:find('^ ?%@.?[pr]') + in_desc = (not start_annotation) and in_desc or false + if start_annotation and no_blank and not (lines[#lines] or ''):find('^%s*$') then + table.insert(lines, '') -- Separate each @foo with a blank line. + end + if in_desc or not no_blank or not line:find('^%s*$') then + table.insert(lines, line) + end + end + return lines end local function create_window_without_focus() @@ -116,9 +133,10 @@ end --- Convenience wrapper around vim.str_utfindex ---@param line string line to be indexed ---@param index integer|nil byte index (utf-8), or `nil` for length ----@param encoding string|nil utf-8|utf-16|utf-32|nil defaults to utf-16 +---@param encoding 'utf-8'|'utf-16'|'utf-32'|nil defaults to utf-16 ---@return integer `encoding` index of `index` in `line` function M._str_utfindex_enc(line, index, encoding) + local len32, len16 = vim.str_utfindex(line) if not encoding then encoding = 'utf-16' end @@ -129,9 +147,15 @@ function M._str_utfindex_enc(line, index, encoding) return #line end elseif encoding == 'utf-16' then + if not index or index > len16 then + return len16 + end local _, col16 = vim.str_utfindex(line, index) return col16 elseif encoding == 'utf-32' then + if not index or index > len32 then + return len32 + end local col32, _ = vim.str_utfindex(line, index) return col32 else @@ -147,6 +171,12 @@ end ---@param encoding string utf-8|utf-16|utf-32| defaults to utf-16 ---@return integer byte (utf-8) index of `encoding` index `index` in `line` function M._str_byteindex_enc(line, index, encoding) + local len = #line + if index > len then + -- LSP spec: if character > line length, default to the line length. + -- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position + return len + end if not encoding then encoding = 'utf-16' end @@ -154,7 +184,7 @@ function M._str_byteindex_enc(line, index, encoding) if index then return index else - return #line + return len end elseif encoding == 'utf-16' then return vim.str_byteindex(line, index, true) @@ -165,19 +195,16 @@ function M._str_byteindex_enc(line, index, encoding) end end -local _str_utfindex_enc = M._str_utfindex_enc -local _str_byteindex_enc = M._str_byteindex_enc - --- Replaces text in a range with new text. --- --- CAUTION: Changes in-place! --- ---@deprecated ----@param lines (table) Original list of strings ----@param A (table) Start position; a 2-tuple of {line,col} numbers ----@param B (table) End position; a 2-tuple of {line,col} numbers ----@param new_lines (table) list of strings to replace the original ----@return table The modified {lines} object +---@param lines string[] Original list of strings +---@param A [integer, integer] Start position; a 2-tuple of {line,col} numbers +---@param B [integer, integer] End position; a 2-tuple {line,col} numbers +---@param new_lines string[] list of strings to replace the original +---@return string[] The modified {lines} object function M.set_lines(lines, A, B, new_lines) vim.deprecate('vim.lsp.util.set_lines()', 'nil', '0.12') -- 0-indexing to 1-indexing @@ -238,6 +265,7 @@ end ---@param rows integer[] zero-indexed line numbers ---@return table<integer, string>|string a table mapping rows to lines local function get_lines(bufnr, rows) + --- @type integer[] rows = type(rows) == 'table' and rows or { rows } -- This is needed for bufload and bufloaded @@ -246,7 +274,7 @@ local function get_lines(bufnr, rows) end local function buf_lines() - local lines = {} + local lines = {} --- @type table<integer,string> for _, row in ipairs(rows) do lines[row] = (api.nvim_buf_get_lines(bufnr, row, row + 1, false) or { '' })[1] end @@ -268,17 +296,20 @@ local function get_lines(bufnr, rows) end local filename = api.nvim_buf_get_name(bufnr) + if vim.fn.isdirectory(filename) ~= 0 then + return {} + end -- get the data from the file local fd = uv.fs_open(filename, 'r', 438) if not fd then return '' end - local stat = uv.fs_fstat(fd) - local data = uv.fs_read(fd, stat.size, 0) + local stat = assert(uv.fs_fstat(fd)) + local data = assert(uv.fs_read(fd, stat.size, 0)) uv.fs_close(fd) - local lines = {} -- rows we need to retrieve + local lines = {} --- @type table<integer,true|string> rows we need to retrieve local need = 0 -- keep track of how many unique rows we need for _, row in pairs(rows) do if not lines[row] then @@ -307,7 +338,7 @@ local function get_lines(bufnr, rows) lines[i] = '' end end - return lines + return lines --[[@as table<integer,string>]] end --- Gets the zero-indexed line from the given buffer. @@ -322,7 +353,8 @@ local function get_line(bufnr, row) end --- Position is a https://microsoft.github.io/language-server-protocol/specifications/specification-current/#position ----@param offset_encoding string|nil utf-8|utf-16|utf-32 +---@param position lsp.Position +---@param offset_encoding? string utf-8|utf-16|utf-32 ---@return integer local function get_line_byte_from_position(bufnr, position, offset_encoding) -- LSP's line and characters are 0-indexed @@ -332,18 +364,13 @@ local function get_line_byte_from_position(bufnr, position, offset_encoding) -- character if col > 0 then local line = get_line(bufnr, position.line) or '' - local ok, result - ok, result = pcall(_str_byteindex_enc, line, col, offset_encoding) - if ok then - return result - end - return math.min(#line, col) + return M._str_byteindex_enc(line, col, offset_encoding or 'utf-16') end return col end --- Applies a list of text edits to a buffer. ----@param text_edits table list of `TextEdit` objects +---@param text_edits lsp.TextEdit[] ---@param bufnr integer Buffer id ---@param offset_encoding string utf-8|utf-16|utf-32 ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit @@ -366,6 +393,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) -- Fix reversed range and indexing each text_edits local index = 0 + --- @param text_edit lsp.TextEdit text_edits = vim.tbl_map(function(text_edit) index = index + 1 text_edit._index = index @@ -383,6 +411,9 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) end, text_edits) -- Sort text_edits + ---@param a lsp.TextEdit | { _index: integer } + ---@param b lsp.TextEdit | { _index: integer } + ---@return boolean table.sort(text_edits, function(a, b) if a.range.start.line ~= b.range.start.line then return a.range.start.line > b.range.start.line @@ -390,13 +421,11 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) if a.range.start.character ~= b.range.start.character then return a.range.start.character > b.range.start.character end - if a._index ~= b._index then - return a._index > b._index - end + return a._index > b._index end) -- save and restore local marks since they get deleted by nvim_buf_set_lines - local marks = {} + local marks = {} --- @type table<string,[integer,integer]> for _, m in pairs(vim.fn.getmarklist(bufnr)) do if m.mark:match("^'[a-z]$") then marks[m.mark:sub(2, 2)] = { m.pos[2], m.pos[3] - 1 } -- api-indexed @@ -432,14 +461,15 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) e.end_col = last_line_len has_eol_text_edit = true else - -- If the replacement is over the end of a line (i.e. e.end_col is out of bounds and the + -- If the replacement is over the end of a line (i.e. e.end_col is equal to the line length and the -- replacement text ends with a newline We can likely assume that the replacement is assumed -- to be meant to replace the newline with another newline and we need to make sure this -- doesn't add an extra empty line. E.g. when the last line to be replaced contains a '\r' -- in the file some servers (clangd on windows) will include that character in the line -- while nvim_buf_set_text doesn't count it as part of the line. if - e.end_col > last_line_len + e.end_col >= last_line_len + and text_edit.range['end'].character > e.end_col and #text_edit.newText > 0 and string.sub(text_edit.newText, -1) == '\n' then @@ -481,8 +511,8 @@ end --- Applies a `TextDocumentEdit`, which is a list of changes to a single --- document. --- ----@param text_document_edit table: a `TextDocumentEdit` object ----@param index integer: Optional index of the edit, if from a list of edits (or nil, if not from a list) +---@param text_document_edit lsp.TextDocumentEdit +---@param index? integer: Optional index of the edit, if from a list of edits (or nil, if not from a list) ---@param offset_encoding? string ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit function M.apply_text_document_edit(text_document_edit, index, offset_encoding) @@ -509,7 +539,6 @@ function M.apply_text_document_edit(text_document_edit, index, offset_encoding) and ( text_document.version and text_document.version > 0 - and M.buf_versions[bufnr] and M.buf_versions[bufnr] > text_document.version ) then @@ -534,6 +563,7 @@ local function path_under_prefix(path, prefix) end --- Get list of buffers whose filename matches the given path prefix (normalized full path) +---@param prefix string ---@return integer[] local function get_bufs_with_prefix(prefix) prefix = path_components(prefix) @@ -616,7 +646,7 @@ function M.rename(old_fname, new_fname, opts) buf_rename[b] = { from = old_bname, to = new_bname } end - local newdir = assert(vim.fs.dirname(new_fname)) + local newdir = vim.fs.dirname(new_fname) vim.fn.mkdir(newdir, 'p') local ok, err = os.rename(old_fname_full, new_fname) @@ -625,7 +655,7 @@ function M.rename(old_fname, new_fname, opts) local old_undofile = vim.fn.undofile(old_fname_full) if uv.fs_stat(old_undofile) ~= nil then local new_undofile = vim.fn.undofile(new_fname) - vim.fn.mkdir(assert(vim.fs.dirname(new_undofile)), 'p') + vim.fn.mkdir(vim.fs.dirname(new_undofile), 'p') os.rename(old_undofile, new_undofile) end @@ -633,7 +663,7 @@ function M.rename(old_fname, new_fname, opts) -- Rename with :saveas. This does two things: -- * Unset BF_WRITE_MASK, so that users don't get E13 when they do :write. -- * Send didClose and didOpen via textDocument/didSave handler. - api.nvim_buf_call(b, function() + vim._with({ buf = b }, function() vim.cmd('keepalt saveas! ' .. vim.fn.fnameescape(rename.to)) end) -- Delete the new buffer with the old name created by :saveas. nvim_buf_delete and @@ -642,6 +672,7 @@ function M.rename(old_fname, new_fname, opts) end end +--- @param change lsp.CreateFile local function create_file(change) local opts = change.options or {} -- from spec: Overwrite wins over `ignoreIfExists` @@ -656,29 +687,21 @@ local function create_file(change) vim.fn.bufadd(fname) end +--- @param change lsp.DeleteFile local function delete_file(change) local opts = change.options or {} local fname = vim.uri_to_fname(change.uri) - local stat = uv.fs_stat(fname) - if opts.ignoreIfNotExists and not stat then - return - end - assert(stat, 'Cannot delete not existing file or folder ' .. fname) - local flags - if stat and stat.type == 'directory' then - flags = opts.recursive and 'rf' or 'd' - else - flags = '' - end local bufnr = vim.fn.bufadd(fname) - local result = tonumber(vim.fn.delete(fname, flags)) - assert(result == 0, 'Could not delete file: ' .. fname .. ', stat: ' .. vim.inspect(stat)) + vim.fs.rm(fname, { + force = opts.ignoreIfNotExists, + recursive = opts.recursive, + }) api.nvim_buf_delete(bufnr, { force = true }) end --- Applies a `WorkspaceEdit`. --- ----@param workspace_edit table `WorkspaceEdit` +---@param workspace_edit lsp.WorkspaceEdit ---@param offset_encoding string utf-8|utf-16|utf-32 (required) ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit function M.apply_workspace_edit(workspace_edit, offset_encoding) @@ -724,21 +747,21 @@ end --- Note that if the input is of type `MarkupContent` and its kind is `plaintext`, --- then the corresponding value is returned without further modifications. --- ----@param input (lsp.MarkedString | lsp.MarkedString[] | lsp.MarkupContent) ----@param contents (table|nil) List of strings to extend with converted lines. Defaults to {}. +---@param input lsp.MarkedString|lsp.MarkedString[]|lsp.MarkupContent +---@param contents string[]|nil List of strings to extend with converted lines. Defaults to {}. ---@return string[] extended with lines of converted markdown. ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover function M.convert_input_to_markdown_lines(input, contents) contents = contents or {} -- MarkedString variation 1 if type(input) == 'string' then - list_extend(contents, split_lines(input)) + list_extend(contents, split_lines(input, true)) else assert(type(input) == 'table', 'Expected a table for LSP input') -- MarkupContent if input.kind then local value = input.value or '' - list_extend(contents, split_lines(value)) + list_extend(contents, split_lines(value, true)) -- MarkupString variation 2 elseif input.language then table.insert(contents, '```' .. input.language) @@ -760,11 +783,11 @@ end --- Converts `textDocument/signatureHelp` response to markdown lines. --- ----@param signature_help table Response of `textDocument/SignatureHelp` +---@param signature_help lsp.SignatureHelp Response of `textDocument/SignatureHelp` ---@param ft string|nil filetype that will be use as the `lang` for the label markdown code block ---@param triggers table|nil list of trigger characters from the lsp server. used to better determine parameter offsets ----@return table|nil table list of lines of converted markdown. ----@return table|nil table of active hl +---@return string[]|nil table list of lines of converted markdown. +---@return number[]|nil table of active hl ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers) if not signature_help.signatures then @@ -961,7 +984,7 @@ end --- Shows document and optionally jumps to the location. --- ----@param location table (`Location`|`LocationLink`) +---@param location lsp.Location|lsp.LocationLink ---@param offset_encoding string|nil utf-8|utf-16|utf-32 ---@param opts table|nil options --- - reuse_win (boolean) Jump to existing window if buffer is already open. @@ -1007,7 +1030,7 @@ function M.show_document(location, offset_encoding, opts) local row = range.start.line local col = get_line_byte_from_position(bufnr, range.start, offset_encoding) api.nvim_win_set_cursor(win, { row + 1, col }) - api.nvim_win_call(win, function() + vim._with({ win = win }, function() -- Open folds under the cursor vim.cmd('normal! zv') end) @@ -1018,7 +1041,7 @@ end --- Jumps to a location. --- ----@param location table (`Location`|`LocationLink`) +---@param location lsp.Location|lsp.LocationLink ---@param offset_encoding string|nil utf-8|utf-16|utf-32 ---@param reuse_win boolean|nil Jump to existing window if buffer is already open. ---@return boolean `true` if the jump succeeded @@ -1039,7 +1062,7 @@ end --- - for Location, range is shown (e.g., function definition) --- - for LocationLink, targetRange is shown (e.g., body of function definition) --- ----@param location table a single `Location` or `LocationLink` +---@param location lsp.Location|lsp.LocationLink ---@param opts table ---@return integer|nil buffer id of float window ---@return integer|nil window id of float window @@ -1155,7 +1178,7 @@ end --- If you want to open a popup with fancy markdown, use `open_floating_preview` instead --- ---@param bufnr integer ----@param contents table of lines to show in window +---@param contents string[] of lines to show in window ---@param opts table with optional fields --- - height of floating window --- - width of floating window @@ -1327,7 +1350,7 @@ function M.stylize_markdown(bufnr, contents, opts) end -- needs to run in the buffer for the regions to work - api.nvim_buf_call(bufnr, function() + vim._with({ buf = bufnr }, function() -- we need to apply lsp_markdown regions speperately, since otherwise -- markdown regions can "bleed" through the other syntax regions -- and mess up the formatting @@ -1438,7 +1461,7 @@ end --- Computes size of float needed to show contents (with optional wrapping) --- ---@param contents table of lines to show in window ----@param opts table with optional fields +---@param opts? table with optional fields --- - height of floating window --- - width of floating window --- - wrap_at character to wrap at for computing height @@ -1630,10 +1653,9 @@ function M.open_floating_preview(contents, syntax, opts) if do_stylize then vim.wo[floating_winnr].conceallevel = 2 end - -- disable folding - vim.wo[floating_winnr].foldenable = false - -- soft wrapping - vim.wo[floating_winnr].wrap = opts.wrap + vim.wo[floating_winnr].foldenable = false -- Disable folding. + vim.wo[floating_winnr].wrap = opts.wrap -- Soft wrapping. + vim.wo[floating_winnr].breakindent = true -- Slightly better list presentation. vim.bo[floating_bufnr].modifiable = false vim.bo[floating_bufnr].bufhidden = 'wipe' @@ -1670,7 +1692,7 @@ do --[[ References ]] --- Shows a list of document highlights for a certain buffer. --- ---@param bufnr integer Buffer id - ---@param references table List of `DocumentHighlight` objects to highlight + ---@param references lsp.DocumentHighlight[] objects to highlight ---@param offset_encoding string One of "utf-8", "utf-16", "utf-32". ---@see https://microsoft.github.io/language-server-protocol/specification/#textDocumentContentChangeEvent function M.buf_highlight_references(bufnr, references, offset_encoding) @@ -1721,7 +1743,9 @@ end) ---@inlinedoc ---@field filename string ---@field lnum integer 1-indexed line number +---@field end_lnum integer 1-indexed end line number ---@field col integer 1-indexed column +---@field end_col integer 1-indexed end column ---@field text string ---@field user_data lsp.Location|lsp.LocationLink @@ -1748,7 +1772,7 @@ function M.locations_to_items(locations, offset_encoding) end local items = {} - ---@type table<string, {start: lsp.Position, location: lsp.Location|lsp.LocationLink}[]> + ---@type table<string, {start: lsp.Position, end: lsp.Position, location: lsp.Location|lsp.LocationLink}[]> local grouped = setmetatable({}, { __index = function(t, k) local v = {} @@ -1760,7 +1784,7 @@ function M.locations_to_items(locations, offset_encoding) -- locations may be Location or LocationLink local uri = d.uri or d.targetUri local range = d.range or d.targetSelectionRange - table.insert(grouped[uri], { start = range.start, location = d }) + table.insert(grouped[uri], { start = range.start, ['end'] = range['end'], location = d }) end ---@type string[] @@ -1775,6 +1799,9 @@ function M.locations_to_items(locations, offset_encoding) local line_numbers = {} for _, temp in ipairs(rows) do table.insert(line_numbers, temp.start.line) + if temp.start.line ~= temp['end'].line then + table.insert(line_numbers, temp['end'].line) + end end -- get all the lines for this uri @@ -1782,13 +1809,20 @@ function M.locations_to_items(locations, offset_encoding) for _, temp in ipairs(rows) do local pos = temp.start + local end_pos = temp['end'] local row = pos.line + local end_row = end_pos.line local line = lines[row] or '' + local end_line = lines[end_row] or '' local col = M._str_byteindex_enc(line, pos.character, offset_encoding) + local end_col = M._str_byteindex_enc(end_line, end_pos.character, offset_encoding) + table.insert(items, { filename = filename, lnum = row + 1, + end_lnum = end_row + 1, col = col + 1, + end_col = end_col + 1, text = line, user_data = temp.location, }) @@ -1807,7 +1841,7 @@ end --- Converts symbols to quickfix list items. --- ---@param symbols table DocumentSymbol[] or SymbolInformation[] ----@param bufnr integer +---@param bufnr? integer function M.symbols_to_items(symbols, bufnr) local function _symbols_to_items(_symbols, _items, _bufnr) for _, symbol in ipairs(_symbols) do @@ -1874,7 +1908,7 @@ end --- CAUTION: Modifies the input in-place! --- ---@deprecated ----@param lines table list of lines +---@param lines string[] list of lines ---@return string filetype or "markdown" if it was unchanged. function M.try_trim_markdown_code_blocks(lines) vim.deprecate('vim.lsp.util.try_trim_markdown_code_blocks()', 'nil', '0.12') @@ -1899,7 +1933,7 @@ function M.try_trim_markdown_code_blocks(lines) end ---@param window integer|nil: window handle or 0 for current, defaults to current ----@param offset_encoding string utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window` +---@param offset_encoding? string utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window` local function make_position_param(window, offset_encoding) window = window or 0 local buf = api.nvim_win_get_buf(window) @@ -1911,7 +1945,7 @@ local function make_position_param(window, offset_encoding) return { line = 0, character = 0 } end - col = _str_utfindex_enc(line, col, offset_encoding) + col = M._str_utfindex_enc(line, col, offset_encoding) return { line = row, character = col } end @@ -1920,7 +1954,7 @@ end --- ---@param window integer|nil: window handle or 0 for current, defaults to current ---@param offset_encoding string|nil utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window` ----@return table `TextDocumentPositionParams` object +---@return lsp.TextDocumentPositionParams ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams function M.make_position_params(window, offset_encoding) window = window or 0 @@ -1933,7 +1967,7 @@ function M.make_position_params(window, offset_encoding) end --- Utility function for getting the encoding of the first LSP client on the given buffer. ----@param bufnr (integer) buffer handle or 0 for current, defaults to current +---@param bufnr integer buffer handle or 0 for current, defaults to current ---@return string encoding first client if there is one, nil otherwise function M._get_offset_encoding(bufnr) validate({ @@ -2034,15 +2068,16 @@ end --- Creates a `TextDocumentIdentifier` object for the current buffer. --- ---@param bufnr integer|nil: Buffer handle, defaults to current ----@return table `TextDocumentIdentifier` +---@return lsp.TextDocumentIdentifier ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier function M.make_text_document_params(bufnr) return { uri = vim.uri_from_bufnr(bufnr or 0) } end --- Create the workspace params ----@param added table ----@param removed table +---@param added lsp.WorkspaceFolder[] +---@param removed lsp.WorkspaceFolder[] +---@return lsp.WorkspaceFoldersChangeEvent function M.make_workspace_params(added, removed) return { event = { added = added, removed = removed } } end @@ -2050,8 +2085,8 @@ end --- Returns indentation size. --- ---@see 'shiftwidth' ----@param bufnr (integer|nil): Buffer handle, defaults to current ----@return (integer) indentation size +---@param bufnr integer|nil: Buffer handle, defaults to current +---@return integer indentation size function M.get_effective_tabstop(bufnr) validate({ bufnr = { bufnr, 'n', true } }) local bo = bufnr and vim.bo[bufnr] or vim.bo @@ -2061,7 +2096,7 @@ end --- Creates a `DocumentFormattingParams` object for the current buffer and cursor position. --- ----@param options table|nil with valid `FormattingOptions` entries +---@param options lsp.FormattingOptions|nil with valid `FormattingOptions` entries ---@return lsp.DocumentFormattingParams object ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting function M.make_formatting_params(options) @@ -2092,11 +2127,7 @@ function M.character_offset(buf, row, col, offset_encoding) ) offset_encoding = vim.lsp.get_clients({ bufnr = buf })[1].offset_encoding end - -- If the col is past the EOL, use the line length. - if col > #line then - return _str_utfindex_enc(line, nil, offset_encoding) - end - return _str_utfindex_enc(line, col, offset_encoding) + return M._str_utfindex_enc(line, col, offset_encoding) end --- Helper function to return nested values in language server settings @@ -2203,6 +2234,11 @@ end M._get_line_byte_from_position = get_line_byte_from_position ---@nodoc -M.buf_versions = {} ---@type table<integer,integer> +---@type table<integer,integer> +M.buf_versions = setmetatable({}, { + __index = function(t, bufnr) + return rawget(t, bufnr) or 0 + end, +}) return M diff --git a/runtime/lua/vim/provider/health.lua b/runtime/lua/vim/provider/health.lua index 63e0da448a..47c2080e3c 100644 --- a/runtime/lua/vim/provider/health.lua +++ b/runtime/lua/vim/provider/health.lua @@ -1,8 +1,114 @@ local health = vim.health -local iswin = vim.uv.os_uname().sysname == 'Windows_NT' +local iswin = vim.fn.has('win32') == 1 local M = {} +local function cmd_ok(cmd) + local out = vim.fn.system(cmd) + return vim.v.shell_error == 0, out +end + +-- Attempts to construct a shell command from an args list. +-- Only for display, to help users debug a failed command. +local function shellify(cmd) + if type(cmd) ~= 'table' then + return cmd + end + local escaped = {} + for i, v in ipairs(cmd) do + if v:match('[^A-Za-z_/.-]') then + escaped[i] = vim.fn.shellescape(v) + else + escaped[i] = v + end + end + return table.concat(escaped, ' ') +end + +-- Handler for s:system() function. +local function system_handler(self, _, data, event) + if event == 'stderr' then + if self.add_stderr_to_output then + self.output = self.output .. table.concat(data, '') + else + self.stderr = self.stderr .. table.concat(data, '') + end + elseif event == 'stdout' then + self.output = self.output .. table.concat(data, '') + end +end + +--- @param cmd table List of command arguments to execute +--- @param args? table Optional arguments: +--- - stdin (string): Data to write to the job's stdin +--- - stderr (boolean): Append stderr to stdout +--- - ignore_error (boolean): If true, ignore error output +--- - timeout (number): Number of seconds to wait before timing out (default 30) +local function system(cmd, args) + args = args or {} + local stdin = args.stdin or '' + local stderr = vim.F.if_nil(args.stderr, false) + local ignore_error = vim.F.if_nil(args.ignore_error, false) + + local shell_error_code = 0 + local opts = { + add_stderr_to_output = stderr, + output = '', + stderr = '', + on_stdout = system_handler, + on_stderr = system_handler, + on_exit = function(_, data) + shell_error_code = data + end, + } + local jobid = vim.fn.jobstart(cmd, opts) + + if jobid < 1 then + local message = + string.format('Command error (job=%d): %s (in %s)', jobid, shellify(cmd), vim.uv.cwd()) + error(message) + return opts.output, 1 + end + + if stdin:find('^%s$') then + vim.fn.chansend(jobid, stdin) + end + + local res = vim.fn.jobwait({ jobid }, vim.F.if_nil(args.timeout, 30) * 1000) + if res[1] == -1 then + error('Command timed out: ' .. shellify(cmd)) + vim.fn.jobstop(jobid) + elseif shell_error_code ~= 0 and not ignore_error then + local emsg = string.format( + 'Command error (job=%d, exit code %d): %s (in %s)', + jobid, + shell_error_code, + shellify(cmd), + vim.uv.cwd() + ) + if opts.output:find('%S') then + emsg = string.format('%s\noutput: %s', emsg, opts.output) + end + if opts.stderr:find('%S') then + emsg = string.format('%s\nstderr: %s', emsg, opts.stderr) + end + error(emsg) + end + + return vim.trim(vim.fn.system(cmd)), shell_error_code +end + +---@param provider string +local function provider_disabled(provider) + local loaded_var = 'loaded_' .. provider .. '_provider' + local v = vim.g[loaded_var] + if v == 0 then + health.info('Disabled (' .. loaded_var .. '=' .. v .. ').') + return true + end + return false +end + local function clipboard() health.start('Clipboard (optional)') @@ -10,7 +116,7 @@ local function clipboard() os.getenv('TMUX') and vim.fn.executable('tmux') == 1 and vim.fn.executable('pbpaste') == 1 - and not health._cmd_ok('pbpaste') + and not cmd_ok('pbpaste') then local tmux_version = string.match(vim.fn.system('tmux -V'), '%d+%.%d+') local advice = { @@ -20,9 +126,9 @@ local function clipboard() health.error('pbcopy does not work with tmux version: ' .. tmux_version, advice) end - local clipboard_tool = vim.fn['provider#clipboard#Executable']() + local clipboard_tool = vim.fn['provider#clipboard#Executable']() ---@type string if vim.g.clipboard ~= nil and clipboard_tool == '' then - local error_message = vim.fn['provider#clipboard#Error']() + local error_message = vim.fn['provider#clipboard#Error']() ---@type string health.error( error_message, "Use the example in :help g:clipboard as a template, or don't set g:clipboard at all." @@ -40,7 +146,7 @@ end local function node() health.start('Node.js provider (optional)') - if health._provider_disabled('node') then + if provider_disabled('node') then return end @@ -60,7 +166,7 @@ local function node() end -- local node_v = vim.fn.split(system({'node', '-v'}), "\n")[1] or '' - local ok, node_v = health._cmd_ok({ 'node', '-v' }) + local ok, node_v = cmd_ok({ 'node', '-v' }) health.info('Node.js: ' .. node_v) if not ok or vim.version.lt(node_v, '6.0.0') then health.warn('Nvim node.js host does not support Node ' .. node_v) @@ -73,7 +179,7 @@ local function node() ) end - local node_detect_table = vim.fn['provider#node#Detect']() + local node_detect_table = vim.fn['provider#node#Detect']() ---@type string[] local host = node_detect_table[1] if host:find('^%s*$') then health.warn('Missing "neovim" npm (or yarn, pnpm) package.', { @@ -97,7 +203,7 @@ local function node() iswin and 'cmd /c ' .. manager .. ' info neovim --json' or manager .. ' info neovim --json' ) local latest_npm - ok, latest_npm = health._cmd_ok(vim.split(latest_npm_cmd, ' ')) + ok, latest_npm = cmd_ok(vim.split(latest_npm_cmd, ' ')) if not ok or latest_npm:find('^%s$') then health.error( 'Failed to run: ' .. latest_npm_cmd, @@ -115,7 +221,7 @@ local function node() local current_npm_cmd = { 'node', host, '--version' } local current_npm - ok, current_npm = health._cmd_ok(current_npm_cmd) + ok, current_npm = cmd_ok(current_npm_cmd) if not ok then health.error( 'Failed to run: ' .. table.concat(current_npm_cmd, ' '), @@ -143,7 +249,7 @@ end local function perl() health.start('Perl provider (optional)') - if health._provider_disabled('perl') then + if provider_disabled('perl') then return end @@ -162,7 +268,7 @@ local function perl() -- we cannot use cpanm that is on the path, as it may not be for the perl -- set with g:perl_host_prog - local ok = health._cmd_ok({ perl_exec, '-W', '-MApp::cpanminus', '-e', '' }) + local ok = cmd_ok({ perl_exec, '-W', '-MApp::cpanminus', '-e', '' }) if not ok then return { perl_exec, '"App::cpanminus" module is not installed' } end @@ -174,7 +280,7 @@ local function perl() 'my $app = App::cpanminus::script->new; $app->parse_options ("--info", "-q", "Neovim::Ext"); exit $app->doit', } local latest_cpan - ok, latest_cpan = health._cmd_ok(latest_cpan_cmd) + ok, latest_cpan = cmd_ok(latest_cpan_cmd) if not ok or latest_cpan:find('^%s*$') then health.error( 'Failed to run: ' .. table.concat(latest_cpan_cmd, ' '), @@ -184,7 +290,7 @@ local function perl() elseif latest_cpan[1] == '!' then local cpanm_errs = vim.split(latest_cpan, '!') if cpanm_errs[1]:find("Can't write to ") then - local advice = {} + local advice = {} ---@type string[] for i = 2, #cpanm_errs do advice[#advice + 1] = cpanm_errs[i] end @@ -197,7 +303,7 @@ local function perl() return end end - latest_cpan = vim.fn.matchstr(latest_cpan, [[\(\.\?\d\)\+]]) + latest_cpan = tostring(vim.fn.matchstr(latest_cpan, [[\(\.\?\d\)\+]])) if latest_cpan:find('^%s*$') then health.error('Cannot parse version number from cpanm output: ' .. latest_cpan) return @@ -205,7 +311,7 @@ local function perl() local current_cpan_cmd = { perl_exec, '-W', '-MNeovim::Ext', '-e', 'print $Neovim::Ext::VERSION' } local current_cpan - ok, current_cpan = health._cmd_ok(current_cpan_cmd) + ok, current_cpan = cmd_ok(current_cpan_cmd) if not ok then health.error( 'Failed to run: ' .. table.concat(current_cpan_cmd, ' '), @@ -243,9 +349,11 @@ local function python_exepath(invocation) return vim.fs.normalize(vim.trim(p.stdout)) end --- Check if pyenv is available and a valid pyenv root can be found, then return --- their respective paths. If either of those is invalid, return two empty --- strings, effectively ignoring pyenv. +--- Check if pyenv is available and a valid pyenv root can be found, then return +--- their respective paths. If either of those is invalid, return two empty +--- strings, effectively ignoring pyenv. +--- +--- @return [string, string] local function check_for_pyenv() local pyenv_path = vim.fn.resolve(vim.fn.exepath('pyenv')) @@ -258,7 +366,17 @@ local function check_for_pyenv() local pyenv_root = vim.fn.resolve(os.getenv('PYENV_ROOT') or '') if pyenv_root == '' then - pyenv_root = vim.fn.system({ pyenv_path, 'root' }) + local p = vim.system({ pyenv_path, 'root' }):wait() + if p.code ~= 0 then + local message = string.format( + 'pyenv: Failed to infer the root of pyenv by running `%s root` : %s. Ignoring pyenv for all following checks.', + pyenv_path, + p.stderr + ) + health.warn(message) + return { '', '' } + end + pyenv_root = vim.trim(p.stdout) health.info('pyenv: $PYENV_ROOT is not set. Infer from `pyenv root`.') end @@ -288,24 +406,29 @@ local function check_bin(bin) return true end --- Fetch the contents of a URL. +--- Fetch the contents of a URL. +--- +--- @param url string local function download(url) local has_curl = vim.fn.executable('curl') == 1 if has_curl and vim.fn.system({ 'curl', '-V' }):find('Protocols:.*https') then - local out, rc = health._system({ 'curl', '-sL', url }, { stderr = true, ignore_error = true }) + local out, rc = system({ 'curl', '-sL', url }, { stderr = true, ignore_error = true }) if rc ~= 0 then return 'curl error with ' .. url .. ': ' .. rc else return out end elseif vim.fn.executable('python') == 1 then - local script = "try:\n\ - from urllib.request import urlopen\n\ - except ImportError:\n\ - from urllib2 import urlopen\n\ - response = urlopen('" .. url .. "')\n\ - print(response.read().decode('utf8'))\n" - local out, rc = health._system({ 'python', '-c', script }) + local script = ([[ +try: + from urllib.request import urlopen +except ImportError: + from urllib2 import urlopen + +response = urlopen('%s') +print(response.read().decode('utf8')) +]]):format(url) + local out, rc = system({ 'python', '-c', script }) if out == '' and rc ~= 0 then return 'python urllib.request error: ' .. rc else @@ -323,25 +446,24 @@ local function download(url) return message end --- Get the latest Nvim Python client (pynvim) version from PyPI. +--- Get the latest Nvim Python client (pynvim) version from PyPI. local function latest_pypi_version() local pypi_version = 'unable to get pypi response' local pypi_response = download('https://pypi.python.org/pypi/pynvim/json') if pypi_response ~= '' then local pcall_ok, output = pcall(vim.fn.json_decode, pypi_response) - local pypi_data - if pcall_ok then - pypi_data = output - else + if not pcall_ok then return 'error: ' .. pypi_response end + local pypi_data = output local pypi_element = pypi_data['info'] or {} pypi_version = pypi_element['version'] or 'unable to parse' end return pypi_version end +--- @param s string local function is_bad_response(s) local lower = s:lower() return vim.startswith(lower, 'unable') @@ -349,20 +471,22 @@ local function is_bad_response(s) or vim.startswith(lower, 'outdated') end --- Get version information using the specified interpreter. The interpreter is --- used directly in case breaking changes were introduced since the last time --- Nvim's Python client was updated. --- --- Returns: { --- {python executable version}, --- {current nvim version}, --- {current pypi nvim status}, --- {installed version status} --- } +--- Get version information using the specified interpreter. The interpreter is +--- used directly in case breaking changes were introduced since the last time +--- Nvim's Python client was updated. +--- +--- @param python string +--- +--- Returns: { +--- {python executable version}, +--- {current nvim version}, +--- {current pypi nvim status}, +--- {installed version status} +--- } local function version_info(python) local pypi_version = latest_pypi_version() - local python_version, rc = health._system({ + local python_version, rc = system({ python, '-c', 'import sys; print(".".join(str(x) for x in sys.version_info[:3]))', @@ -373,7 +497,7 @@ local function version_info(python) end local nvim_path - nvim_path, rc = health._system({ + nvim_path, rc = system({ python, '-c', 'import sys; sys.path = [p for p in sys.path if p != ""]; import neovim; print(neovim.__file__)', @@ -398,7 +522,7 @@ local function version_info(python) -- Try to get neovim.VERSION (added in 0.1.11dev). local nvim_version - nvim_version, rc = health._system({ + nvim_version, rc = system({ python, '-c', 'from neovim import VERSION as v; print("{}.{}.{}{}".format(v.major, v.minor, v.patch, v.prerelease))', @@ -406,9 +530,9 @@ local function version_info(python) if rc ~= 0 or nvim_version == '' then nvim_version = 'unable to find pynvim module version' local base = vim.fs.basename(nvim_path) - local metas = vim.fn.glob(base .. '-*/METADATA', 1, 1) - vim.list_extend(metas, vim.fn.glob(base .. '-*/PKG-INFO', 1, 1)) - vim.list_extend(metas, vim.fn.glob(base .. '.egg-info/PKG-INFO', 1, 1)) + local metas = vim.fn.glob(base .. '-*/METADATA', true, 1) + vim.list_extend(metas, vim.fn.glob(base .. '-*/PKG-INFO', true, 1)) + vim.list_extend(metas, vim.fn.glob(base .. '.egg-info/PKG-INFO', true, 1)) metas = table.sort(metas, compare) if metas and next(metas) ~= nil then @@ -438,14 +562,13 @@ end local function python() health.start('Python 3 provider (optional)') - local pyname = 'python3' ---@type string? local python_exe = '' local virtual_env = os.getenv('VIRTUAL_ENV') local venv = virtual_env and vim.fn.resolve(virtual_env) or '' - local host_prog_var = pyname .. '_host_prog' - local python_multiple = {} + local host_prog_var = 'python3_host_prog' + local python_multiple = {} ---@type string[] - if health._provider_disabled(pyname) then + if provider_disabled('python3') then return end @@ -458,8 +581,7 @@ local function python() health.info(message) end - local pythonx_warnings - pyname, pythonx_warnings = vim.provider.python.detect_by_module('neovim') + local pyname, pythonx_warnings = vim.provider.python.detect_by_module('neovim') if not pyname then health.warn( @@ -487,7 +609,7 @@ local function python() end if pyenv ~= '' then - python_exe = health._system({ pyenv, 'which', pyname }, { stderr = true }) + python_exe = system({ pyenv, 'which', pyname }, { stderr = true }) if python_exe == '' then health.warn('pyenv could not find ' .. pyname .. '.') end @@ -547,12 +669,7 @@ local function python() ) health.warn('pyenv is not set up optimally.', advice) elseif venv ~= '' then - local venv_root - if pyenv_root ~= '' then - venv_root = pyenv_root - else - venv_root = vim.fs.dirname(venv) - end + local venv_root = pyenv_root ~= '' and pyenv_root or vim.fs.dirname(venv) if vim.startswith(vim.fn.resolve(python_exe), venv_root .. '/') then local advice = string.format( @@ -637,9 +754,9 @@ local function python() health.ok('no $VIRTUAL_ENV') return end - local errors = {} + local errors = {} ---@type string[] -- Keep hints as dict keys in order to discard duplicates. - local hints = {} + local hints = {} ---@type table<string, boolean> -- The virtualenv should contain some Python executables, and those -- executables should be first both on Nvim's $PATH and the $PATH of -- subshells launched from Nvim. @@ -647,7 +764,7 @@ local function python() local venv_bins = vim.fn.glob(string.format('%s/%s/python*', virtual_env, bin_dir), true, true) venv_bins = vim.tbl_filter(function(v) -- XXX: Remove irrelevant executables found in bin/. - return not v:match('python%-config') + return not v:match('python.*%-config') end, venv_bins) if vim.tbl_count(venv_bins) > 0 then for _, venv_bin in pairs(venv_bins) do @@ -710,9 +827,7 @@ local function python() health.info(msg) health.info( 'Python version: ' - .. health._system( - 'python -c "import platform, sys; sys.stdout.write(platform.python_version())"' - ) + .. system('python -c "import platform, sys; sys.stdout.write(platform.python_version())"') ) health.ok('$VIRTUAL_ENV provides :!python.') end @@ -721,7 +836,7 @@ end local function ruby() health.start('Ruby provider (optional)') - if health._provider_disabled('ruby') then + if provider_disabled('ruby') then return end @@ -732,7 +847,7 @@ local function ruby() ) return end - health.info('Ruby: ' .. health._system({ 'ruby', '-v' })) + health.info('Ruby: ' .. system({ 'ruby', '-v' })) local host, _ = vim.provider.ruby.detect() if (not host) or host:find('^%s*$') then @@ -748,7 +863,7 @@ local function ruby() health.info('Host: ' .. host) local latest_gem_cmd = (iswin and 'cmd /c gem list -ra "^^neovim$"' or 'gem list -ra ^neovim$') - local ok, latest_gem = health._cmd_ok(vim.split(latest_gem_cmd, ' ')) + local ok, latest_gem = cmd_ok(vim.split(latest_gem_cmd, ' ')) if not ok or latest_gem:find('^%s*$') then health.error( 'Failed to run: ' .. latest_gem_cmd, @@ -761,7 +876,7 @@ local function ruby() local current_gem_cmd = { host, '--version' } local current_gem - ok, current_gem = health._cmd_ok(current_gem_cmd) + ok, current_gem = cmd_ok(current_gem_cmd) if not ok then health.error( 'Failed to run: ' .. table.concat(current_gem_cmd, ' '), diff --git a/runtime/lua/vim/secure.lua b/runtime/lua/vim/secure.lua index 41a3d3ba25..266725cce2 100644 --- a/runtime/lua/vim/secure.lua +++ b/runtime/lua/vim/secure.lua @@ -41,6 +41,7 @@ end --- trusted. The user's choice is persisted in a trust database at --- $XDG_STATE_HOME/nvim/trust. --- +---@since 11 ---@see |:trust| --- ---@param path (string) Path to a file to read. @@ -126,6 +127,7 @@ end --- --- The trust database is located at |$XDG_STATE_HOME|/nvim/trust. --- +---@since 11 ---@param opts vim.trust.opts ---@return boolean success true if operation was successful ---@return string msg full path if operation was successful, else error message diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index e9e4326057..4d06cdd77d 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -214,7 +214,7 @@ end ---@param t table<T, any> (table) Table ---@return T[] : List of keys function vim.tbl_keys(t) - vim.validate({ t = { t, 't' } }) + vim.validate('t', t, 'table') --- @cast t table<any,any> local keys = {} @@ -231,7 +231,7 @@ end ---@param t table<any, T> (table) Table ---@return T[] : List of values function vim.tbl_values(t) - vim.validate({ t = { t, 't' } }) + vim.validate('t', t, 'table') local values = {} for _, v in @@ -332,7 +332,7 @@ end ---@param value any Value to compare ---@return boolean `true` if `t` contains `value` function vim.list_contains(t, value) - vim.validate({ t = { t, 't' } }) + vim.validate('t', t, 'table') --- @cast t table<any,any> for _, v in ipairs(t) do @@ -350,41 +350,32 @@ end ---@param t table Table to check ---@return boolean `true` if `t` is empty function vim.tbl_isempty(t) - vim.validate({ t = { t, 't' } }) + vim.validate('t', t, 'table') return next(t) == nil end ---- We only merge empty tables or tables that are not an array (indexed by integers) +--- We only merge empty tables or tables that are not list-like (indexed by consecutive integers +--- starting from 1) local function can_merge(v) - return type(v) == 'table' and (vim.tbl_isempty(v) or not vim.isarray(v)) + return type(v) == 'table' and (vim.tbl_isempty(v) or not vim.islist(v)) end -local function tbl_extend(behavior, deep_extend, ...) - if behavior ~= 'error' and behavior ~= 'keep' and behavior ~= 'force' then - error('invalid "behavior": ' .. tostring(behavior)) - end - - if select('#', ...) < 2 then - error( - 'wrong number of arguments (given ' - .. tostring(1 + select('#', ...)) - .. ', expected at least 3)' - ) - end - +--- Recursive worker for tbl_extend +--- @param behavior 'error'|'keep'|'force' +--- @param deep_extend boolean +--- @param ... table<any,any> +local function tbl_extend_rec(behavior, deep_extend, ...) local ret = {} --- @type table<any,any> if vim._empty_dict_mt ~= nil and getmetatable(select(1, ...)) == vim._empty_dict_mt then ret = vim.empty_dict() end for i = 1, select('#', ...) do - local tbl = select(i, ...) - vim.validate({ ['after the second argument'] = { tbl, 't' } }) - --- @cast tbl table<any,any> + local tbl = select(i, ...) --[[@as table<any,any>]] if tbl then for k, v in pairs(tbl) do if deep_extend and can_merge(v) and can_merge(ret[k]) then - ret[k] = tbl_extend(behavior, true, ret[k], v) + ret[k] = tbl_extend_rec(behavior, true, ret[k], v) elseif behavior ~= 'force' and ret[k] ~= nil then if behavior == 'error' then error('key found in more than one map: ' .. k) @@ -395,9 +386,31 @@ local function tbl_extend(behavior, deep_extend, ...) end end end + return ret end +--- @param behavior 'error'|'keep'|'force' +--- @param deep_extend boolean +--- @param ... table<any,any> +local function tbl_extend(behavior, deep_extend, ...) + if behavior ~= 'error' and behavior ~= 'keep' and behavior ~= 'force' then + error('invalid "behavior": ' .. tostring(behavior)) + end + + local nargs = select('#', ...) + + if nargs < 2 then + error(('wrong number of arguments (given %d, expected at least 3)'):format(1 + nargs)) + end + + for i = 1, nargs do + vim.validate('after the second argument', select(i, ...), 'table') + end + + return tbl_extend_rec(behavior, deep_extend, ...) +end + --- Merges two or more tables. --- ---@see |extend()| @@ -414,6 +427,11 @@ end --- Merges recursively two or more tables. --- +--- Only values that are empty tables or tables that are not |lua-list|s (indexed by consecutive +--- integers starting from 1) are merged recursively. This is useful for merging nested tables +--- like default and user configurations where lists should be treated as literals (i.e., are +--- overwritten instead of merged). +--- ---@see |vim.tbl_extend()| --- ---@generic T1: table @@ -580,7 +598,7 @@ end ---@return fun(table: table<K, V>, index?: K):K, V # |for-in| iterator over sorted keys and their values ---@return T function vim.spairs(t) - assert(type(t) == 'table', ('expected table, got %s'):format(type(t))) + vim.validate('t', t, 'table') --- @cast t table<any,any> -- collect the keys @@ -691,7 +709,7 @@ end ---@param t table Table ---@return integer : Number of non-nil values in table function vim.tbl_count(t) - vim.validate({ t = { t, 't' } }) + vim.validate('t', t, 'table') --- @cast t table<any,any> local count = 0 @@ -723,7 +741,7 @@ end ---@param s string String to trim ---@return string String with whitespace removed from its beginning and end function vim.trim(s) - vim.validate({ s = { s, 's' } }) + vim.validate('s', s, 'string') return s:match('^%s*(.*%S)') or '' end @@ -733,7 +751,7 @@ end ---@param s string String to escape ---@return string %-escaped pattern string function vim.pesc(s) - vim.validate({ s = { s, 's' } }) + vim.validate('s', s, 'string') return (s:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', '%%%1')) end @@ -743,7 +761,8 @@ end ---@param prefix string Prefix to match ---@return boolean `true` if `prefix` is a prefix of `s` function vim.startswith(s, prefix) - vim.validate({ s = { s, 's' }, prefix = { prefix, 's' } }) + vim.validate('s', s, 'string') + vim.validate('prefix', prefix, 'string') return s:sub(1, #prefix) == prefix end @@ -753,7 +772,8 @@ end ---@param suffix string Suffix to match ---@return boolean `true` if `suffix` is a suffix of `s` function vim.endswith(s, suffix) - vim.validate({ s = { s, 's' }, suffix = { suffix, 's' } }) + vim.validate('s', s, 'string') + vim.validate('suffix', suffix, 'string') return #suffix == 0 or s:sub(-#suffix) == suffix end @@ -787,7 +807,7 @@ do } --- @nodoc - --- @class vim.validate.Spec {[1]: any, [2]: string|string[], [3]: boolean } + --- @class vim.validate.Spec [any, string|string[], boolean] --- @field [1] any Argument value --- @field [2] string|string[]|fun(v:any):boolean, string? Type name, or callable --- @field [3]? boolean @@ -877,8 +897,30 @@ do return true end - --- Validates a parameter specification (types and values). Specs are evaluated in alphanumeric - --- order, until the first failure. + --- Validate function arguments. + --- + --- This function has two valid forms: + --- + --- 1. vim.validate(name: str, value: any, type: string, optional?: bool) + --- 2. vim.validate(spec: table) + --- + --- Form 1 validates that argument {name} with value {value} has the type + --- {type}. {type} must be a value returned by |lua-type()|. If {optional} is + --- true, then {value} may be null. This form is significantly faster and + --- should be preferred for simple cases. + --- + --- Example: + --- + --- ```lua + --- function vim.startswith(s, prefix) + --- vim.validate('s', s, 'string') + --- vim.validate('prefix', prefix, 'string') + --- ... + --- end + --- ``` + --- + --- Form 2 validates a parameter specification (types and values). Specs are + --- evaluated in alphanumeric order, until the first failure. --- --- Usage example: --- @@ -930,8 +972,32 @@ do --- only if the argument is valid. Can optionally return an additional --- informative error message as the second returned value. --- - msg: (optional) error string if validation fails - function vim.validate(opt) - local ok, err_msg = is_valid(opt) + --- @overload fun(name: string, val: any, expected: string, optional?: boolean) + function vim.validate(opt, ...) + local ok = false + local err_msg ---@type string? + local narg = select('#', ...) + if narg == 0 then + ok, err_msg = is_valid(opt) + elseif narg >= 2 then + -- Overloaded signature for fast/simple cases + local name = opt --[[@as string]] + local v, expected, optional = ... ---@type string, string, boolean? + local actual = type(v) + + ok = (actual == expected) or (v == nil and optional == true) + if not ok then + err_msg = ('%s: expected %s, got %s%s'):format( + name, + expected, + actual, + v and (' (%s)'):format(v) or '' + ) + end + else + error('invalid arguments') + end + if not ok then error(err_msg, 2) end @@ -949,7 +1015,7 @@ function vim.is_callable(f) if m == nil then return false end - return type(m.__call) == 'function' + return type(rawget(m, '__call')) == 'function' end --- Creates a table whose missing keys are provided by {createfn} (like Python's "defaultdict"). @@ -1091,4 +1157,165 @@ function vim._defer_require(root, mod) }) end +--- @nodoc +--- @class vim.context.mods +--- @field bo? table<string, any> +--- @field buf? integer +--- @field emsg_silent? boolean +--- @field env? table<string, any> +--- @field go? table<string, any> +--- @field hide? boolean +--- @field keepalt? boolean +--- @field keepjumps? boolean +--- @field keepmarks? boolean +--- @field keeppatterns? boolean +--- @field lockmarks? boolean +--- @field noautocmd? boolean +--- @field o? table<string, any> +--- @field sandbox? boolean +--- @field silent? boolean +--- @field unsilent? boolean +--- @field win? integer +--- @field wo? table<string, any> + +--- @nodoc +--- @class vim.context.state +--- @field bo? table<string, any> +--- @field env? table<string, any> +--- @field go? table<string, any> +--- @field wo? table<string, any> + +local scope_map = { buf = 'bo', global = 'go', win = 'wo' } +local scope_order = { 'o', 'wo', 'bo', 'go', 'env' } +local state_restore_order = { 'bo', 'wo', 'go', 'env' } + +--- Gets data about current state, enough to properly restore specified options/env/etc. +--- @param context vim.context.mods +--- @return vim.context.state +local get_context_state = function(context) + local res = { bo = {}, env = {}, go = {}, wo = {} } + + -- Use specific order from possibly most to least intrusive + for _, scope in ipairs(scope_order) do + for name, _ in pairs(context[scope] or {}) do + local sc = scope == 'o' and scope_map[vim.api.nvim_get_option_info2(name, {}).scope] or scope + + -- Do not override already set state and fall back to `vim.NIL` for + -- state `nil` values (which still needs restoring later) + res[sc][name] = res[sc][name] or vim[sc][name] or vim.NIL + + -- Always track global option value to properly restore later. + -- This matters for at least `o` and `wo` (which might set either/both + -- local and global option values). + if sc ~= 'env' then + res.go[name] = res.go[name] or vim.go[name] + end + end + end + + return res +end + +--- Executes function `f` with the given context specification. +--- +--- Notes: +--- - Context `{ buf = buf }` has no guarantees about current window when +--- inside context. +--- - Context `{ buf = buf, win = win }` is yet not allowed, but this seems +--- to be an implementation detail. +--- - There should be no way to revert currently set `context.sandbox = true` +--- (like with nested `vim._with()` calls). Otherwise it kind of breaks the +--- whole purpose of sandbox execution. +--- - Saving and restoring option contexts (`bo`, `go`, `o`, `wo`) trigger +--- `OptionSet` events. This is an implementation issue because not doing it +--- seems to mean using either 'eventignore' option or extra nesting with +--- `{ noautocmd = true }` (which itself is a wrapper for 'eventignore'). +--- As `{ go = { eventignore = '...' } }` is a valid context which should be +--- properly set and restored, this is not a good approach. +--- Not triggering `OptionSet` seems to be a good idea, though. So probably +--- only moving context save and restore to lower level might resolve this. +--- +--- @param context vim.context.mods +--- @param f function +--- @return any +function vim._with(context, f) + vim.validate('context', context, 'table') + vim.validate('f', f, 'function') + + vim.validate('context.bo', context.bo, 'table', true) + vim.validate('context.buf', context.buf, 'number', true) + vim.validate('context.emsg_silent', context.emsg_silent, 'boolean', true) + vim.validate('context.env', context.env, 'table', true) + vim.validate('context.go', context.go, 'table', true) + vim.validate('context.hide', context.hide, 'boolean', true) + vim.validate('context.keepalt', context.keepalt, 'boolean', true) + vim.validate('context.keepjumps', context.keepjumps, 'boolean', true) + vim.validate('context.keepmarks', context.keepmarks, 'boolean', true) + vim.validate('context.keeppatterns', context.keeppatterns, 'boolean', true) + vim.validate('context.lockmarks', context.lockmarks, 'boolean', true) + vim.validate('context.noautocmd', context.noautocmd, 'boolean', true) + vim.validate('context.o', context.o, 'table', true) + vim.validate('context.sandbox', context.sandbox, 'boolean', true) + vim.validate('context.silent', context.silent, 'boolean', true) + vim.validate('context.unsilent', context.unsilent, 'boolean', true) + vim.validate('context.win', context.win, 'number', true) + vim.validate('context.wo', context.wo, 'table', true) + + -- Check buffer exists + if context.buf then + if not vim.api.nvim_buf_is_valid(context.buf) then + error('Invalid buffer id: ' .. context.buf) + end + end + + -- Check window exists + if context.win then + if not vim.api.nvim_win_is_valid(context.win) then + error('Invalid window id: ' .. context.win) + end + -- TODO: Maybe allow it? + if context.buf and vim.api.nvim_win_get_buf(context.win) ~= context.buf then + error('Can not set both `buf` and `win` context.') + end + end + + -- Decorate so that save-set-restore options is done in correct window-buffer + local callback = function() + -- Cache current values to be changed by context + -- Abort early in case of bad context value + local ok, state = pcall(get_context_state, context) + if not ok then + error(state, 0) + end + + -- Apply some parts of the context in specific order + -- NOTE: triggers `OptionSet` event + for _, scope in ipairs(scope_order) do + for name, context_value in pairs(context[scope] or {}) do + vim[scope][name] = context_value + end + end + + -- Execute + local res = { pcall(f) } + + -- Restore relevant cached values in specific order, global scope last + -- NOTE: triggers `OptionSet` event + for _, scope in ipairs(state_restore_order) do + for name, cached_value in pairs(state[scope]) do + vim[scope][name] = cached_value + end + end + + -- Return + if not res[1] then + error(res[2], 0) + end + table.remove(res, 1) + return unpack(res, 1, table.maxn(res)) + end + + return vim._with_c(context, callback) +end + return vim diff --git a/runtime/lua/vim/snippet.lua b/runtime/lua/vim/snippet.lua index 3d8f73f362..af7e3c6d33 100644 --- a/runtime/lua/vim/snippet.lua +++ b/runtime/lua/vim/snippet.lua @@ -2,6 +2,8 @@ local G = vim.lsp._snippet_grammar local snippet_group = vim.api.nvim_create_augroup('vim/snippet', {}) local snippet_ns = vim.api.nvim_create_namespace('vim/snippet') local hl_group = 'SnippetTabstop' +local jump_forward_key = '<tab>' +local jump_backward_key = '<s-tab>' --- Returns the 0-based cursor position. --- @@ -182,6 +184,8 @@ end --- @field extmark_id integer --- @field tabstops table<integer, vim.snippet.Tabstop[]> --- @field current_tabstop vim.snippet.Tabstop +--- @field tab_keymaps { i: table<string, any>?, s: table<string, any>? } +--- @field shift_tab_keymaps { i: table<string, any>?, s: table<string, any>? } local Session = {} --- Creates a new snippet session in the current buffer. @@ -197,6 +201,8 @@ function Session.new(bufnr, snippet_extmark, tabstop_data) extmark_id = snippet_extmark, tabstops = {}, current_tabstop = Tabstop.new(0, bufnr, { 0, 0, 0, 0 }), + tab_keymaps = { i = nil, s = nil }, + shift_tab_keymaps = { i = nil, s = nil }, }, { __index = Session }) -- Create the tabstops. @@ -207,9 +213,64 @@ function Session.new(bufnr, snippet_extmark, tabstop_data) end end + self:set_keymaps() + return self end +--- Sets the snippet navigation keymaps. +--- +--- @package +function Session:set_keymaps() + local function maparg(key, mode) + local map = vim.fn.maparg(key, mode, false, true) --[[ @as table ]] + if not vim.tbl_isempty(map) and map.buffer == 1 then + return map + else + return nil + end + end + + local function set(jump_key, direction) + vim.keymap.set({ 'i', 's' }, jump_key, function() + return vim.snippet.active({ direction = direction }) + and '<cmd>lua vim.snippet.jump(' .. direction .. ')<cr>' + or jump_key + end, { expr = true, silent = true, buffer = self.bufnr }) + end + + self.tab_keymaps = { + i = maparg(jump_forward_key, 'i'), + s = maparg(jump_forward_key, 's'), + } + self.shift_tab_keymaps = { + i = maparg(jump_backward_key, 'i'), + s = maparg(jump_backward_key, 's'), + } + set(jump_forward_key, 1) + set(jump_backward_key, -1) +end + +--- Restores/deletes the keymaps used for snippet navigation. +--- +--- @package +function Session:restore_keymaps() + local function restore(keymap, lhs, mode) + if keymap then + vim._with({ buf = self.bufnr }, function() + vim.fn.mapset(keymap) + end) + else + vim.api.nvim_buf_del_keymap(self.bufnr, mode, lhs) + end + end + + restore(self.tab_keymaps.i, jump_forward_key, 'i') + restore(self.tab_keymaps.s, jump_forward_key, 's') + restore(self.shift_tab_keymaps.i, jump_backward_key, 'i') + restore(self.shift_tab_keymaps.s, jump_backward_key, 's') +end + --- Returns the destination tabstop index when jumping in the given direction. --- --- @package @@ -315,7 +376,7 @@ local function select_tabstop(tabstop) move_cursor_to(range[1] + 1, range[2] + 1) feedkeys('v') move_cursor_to(range[3] + 1, range[4]) - feedkeys('o<c-g>') + feedkeys('o<c-g><c-r>_') end end @@ -395,6 +456,15 @@ local function setup_autocmds(bufnr) end end, }) + + vim.api.nvim_create_autocmd('BufLeave', { + group = snippet_group, + desc = 'Stop the snippet session when leaving the buffer', + buffer = bufnr, + callback = function() + M.stop() + end, + }) end --- Expands the given snippet text. @@ -444,7 +514,7 @@ function M.expand(input) local snippet_lines = text_to_lines(snippet_text) -- Get the base indentation based on the current line and the last line of the snippet. if #snippet_lines > 0 then - base_indent = base_indent .. (snippet_lines[#snippet_lines]:match('(^%s*)%S') or '') --- @type string + base_indent = base_indent .. (snippet_lines[#snippet_lines]:match('(^%s+)%S') or '') --- @type string end local shiftwidth = vim.fn.shiftwidth() @@ -539,7 +609,7 @@ end --- ```lua --- vim.keymap.set({ 'i', 's' }, '<Tab>', function() --- if vim.snippet.active({ direction = 1 }) then ---- return '<cmd>lua vim.snippet.jump(1)<cr>' +--- return '<Cmd>lua vim.snippet.jump(1)<CR>' --- else --- return '<Tab>' --- end @@ -591,7 +661,7 @@ end --- ```lua --- vim.keymap.set({ 'i', 's' }, '<Tab>', function() --- if vim.snippet.active({ direction = 1 }) then ---- return '<cmd>lua vim.snippet.jump(1)<cr>' +--- return '<Cmd>lua vim.snippet.jump(1)<CR>' --- else --- return '<Tab>' --- end @@ -619,6 +689,8 @@ function M.stop() return end + M._session:restore_keymaps() + vim.api.nvim_clear_autocmds({ group = snippet_group, buffer = M._session.bufnr }) vim.api.nvim_buf_clear_namespace(M._session.bufnr, snippet_ns, 0, -1) diff --git a/runtime/lua/vim/text.lua b/runtime/lua/vim/text.lua index bc90d490aa..d45c8021c6 100644 --- a/runtime/lua/vim/text.lua +++ b/runtime/lua/vim/text.lua @@ -7,10 +7,9 @@ local M = {} --- @param str string String to encode --- @return string : Hex encoded string function M.hexencode(str) - local bytes = { str:byte(1, #str) } local enc = {} ---@type string[] - for i = 1, #bytes do - enc[i] = string.format('%02X', bytes[i]) + for i = 1, #str do + enc[i] = string.format('%02X', str:byte(i, i + 1)) end return table.concat(enc) end @@ -18,15 +17,19 @@ end --- Hex decode a string. --- --- @param enc string String to decode ---- @return string : Decoded string +--- @return string? : Decoded string +--- @return string? : Error message, if any function M.hexdecode(enc) - assert(#enc % 2 == 0, 'string must have an even number of hex characters') + if #enc % 2 ~= 0 then + return nil, 'string must have an even number of hex characters' + end + local str = {} ---@type string[] for i = 1, #enc, 2 do local n = assert(tonumber(enc:sub(i, i + 1), 16)) str[#str + 1] = string.char(n) end - return table.concat(str) + return table.concat(str), nil end return M diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index db544c1ab1..ed7d31e1f7 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -76,36 +76,48 @@ end --- --- If needed, this will create the parser. --- +--- If no parser can be created, an error is thrown. Set `opts.error = false` to suppress this and +--- return nil (and an error message) instead. WARNING: This behavior will become default in Nvim +--- 0.12 and the option will be removed. +--- ---@param bufnr (integer|nil) Buffer the parser should be tied to (default: current buffer) ---@param lang (string|nil) Language of this parser (default: from buffer filetype) ---@param opts (table|nil) Options to pass to the created language tree --- ----@return vim.treesitter.LanguageTree object to use for parsing +---@return vim.treesitter.LanguageTree? object to use for parsing +---@return string? error message, if applicable function M.get_parser(bufnr, lang, opts) opts = opts or {} + local should_error = opts.error == nil or opts.error if bufnr == nil or bufnr == 0 then bufnr = api.nvim_get_current_buf() end if not valid_lang(lang) then - lang = M.language.get_lang(vim.bo[bufnr].filetype) or vim.bo[bufnr].filetype + lang = M.language.get_lang(vim.bo[bufnr].filetype) end if not valid_lang(lang) then if not parsers[bufnr] then - error( - string.format( - 'There is no parser available for buffer %d and one could not be' - .. ' created because lang could not be determined. Either pass lang' - .. ' or set the buffer filetype', - bufnr - ) - ) + local err_msg = + string.format('Parser not found for buffer %s: language could not be determined', bufnr) + if should_error then + error(err_msg) + end + return nil, err_msg end elseif parsers[bufnr] == nil or parsers[bufnr]:lang() ~= lang then - assert(lang, 'lang should be valid') - parsers[bufnr] = M._create_parser(bufnr, lang, opts) + local parser = vim.F.npcall(M._create_parser, bufnr, lang, opts) + if not parser then + local err_msg = + string.format('Parser could not be created for buffer %s and language "%s"', bufnr, lang) + if should_error then + error(err_msg) + end + return nil, err_msg + end + parsers[bufnr] = parser end parsers[bufnr]:register_cbs(opts.buf_attach_cbs) @@ -140,16 +152,8 @@ function M.is_ancestor(dest, source) return false end - local current = source ---@type TSNode? - while current ~= nil do - if current == dest then - return true - end - - current = current:parent() - end - - return false + -- child_containing_descendant returns nil if dest is a direct parent + return source:parent() == dest or dest:child_containing_descendant(source) ~= nil end --- Returns the node's range or an unpacked range table @@ -257,7 +261,7 @@ end ---@param row integer Position row ---@param col integer Position column --- ----@return {capture: string, lang: string, metadata: table}[] +---@return {capture: string, lang: string, metadata: vim.treesitter.query.TSMetadata}[] function M.get_captures_at_pos(bufnr, row, col) if bufnr == 0 then bufnr = api.nvim_get_current_buf() @@ -335,13 +339,16 @@ end --- --- 0-indexed (row, col) tuple. Defaults to cursor position in the --- current window. Required if {bufnr} is not the current buffer ---- @field pos { [1]: integer, [2]: integer }? +--- @field pos [integer, integer]? --- --- Parser language. (default: from buffer filetype) --- @field lang string? --- --- Ignore injected languages (default true) --- @field ignore_injections boolean? +--- +--- Include anonymous nodes (default false) +--- @field include_anonymous boolean? --- Returns the smallest named node at the given position --- @@ -383,11 +390,14 @@ function M.get_node(opts) local ts_range = { row, col, row, col } - local root_lang_tree = M.get_parser(bufnr, opts.lang) + local root_lang_tree = M.get_parser(bufnr, opts.lang, { error = false }) if not root_lang_tree then return end + if opts.include_anonymous then + return root_lang_tree:node_for_range(ts_range, opts) + end return root_lang_tree:named_node_for_range(ts_range, opts) end @@ -413,7 +423,7 @@ end ---@param lang (string|nil) Language of the parser (default: from buffer filetype) function M.start(bufnr, lang) bufnr = bufnr or api.nvim_get_current_buf() - local parser = M.get_parser(bufnr, lang) + local parser = assert(M.get_parser(bufnr, lang, { error = false })) M.highlighter.new(parser) end @@ -437,6 +447,7 @@ end --- --- Can also be shown with `:InspectTree`. [:InspectTree]() --- +---@since 11 ---@param opts table|nil Optional options table with the following possible keys: --- - lang (string|nil): The language of the source buffer. If omitted, detect --- from the filetype of the source buffer. @@ -460,6 +471,7 @@ end --- vim.wo.foldexpr = 'v:lua.vim.treesitter.foldexpr()' --- ``` --- +---@since 11 ---@param lnum integer|nil Line number to calculate fold level for ---@return string function M.foldexpr(lnum) diff --git a/runtime/lua/vim/treesitter/_fold.lua b/runtime/lua/vim/treesitter/_fold.lua index eecf1ad6b1..7237d2e7d4 100644 --- a/runtime/lua/vim/treesitter/_fold.lua +++ b/runtime/lua/vim/treesitter/_fold.lua @@ -87,7 +87,7 @@ end ---@param srow integer ---@param erow integer 0-indexed, exclusive function FoldInfo:add_range(srow, erow) - list_insert(self.levels, srow + 1, erow, '=') + list_insert(self.levels, srow + 1, erow, -1) list_insert(self.levels0, srow + 1, erow, -1) end @@ -114,7 +114,7 @@ local function compute_folds_levels(bufnr, info, srow, erow, parse_injections) srow = srow or 0 erow = erow or api.nvim_buf_line_count(bufnr) - local parser = ts.get_parser(bufnr) + local parser = assert(ts.get_parser(bufnr, nil, { error = false })) parser:parse(parse_injections and { srow, erow } or nil) @@ -131,24 +131,18 @@ local function compute_folds_levels(bufnr, info, srow, erow, parse_injections) -- Collect folds starting from srow - 1, because we should first subtract the folds that end at -- srow - 1 from the level of srow - 1 to get accurate level of srow. - for _, match, metadata in - query:iter_matches(tree:root(), bufnr, math.max(srow - 1, 0), erow, { all = true }) - do + for _, match, metadata in query:iter_matches(tree:root(), bufnr, math.max(srow - 1, 0), erow) do for id, nodes in pairs(match) do if query.captures[id] == 'fold' then local range = ts.get_range(nodes[1], bufnr, metadata[id]) local start, _, stop, stop_col = Range.unpack4(range) - for i = 2, #nodes, 1 do - local node_range = ts.get_range(nodes[i], bufnr, metadata[id]) - local node_start, _, node_stop, node_stop_col = Range.unpack4(node_range) - if node_start < start then - start = node_start - end - if node_stop > stop then - stop = node_stop - stop_col = node_stop_col - end + if #nodes > 1 then + -- assumes nodes are ordered by range + local end_range = ts.get_range(nodes[#nodes], bufnr, metadata[id]) + local _, _, end_stop, end_stop_col = Range.unpack4(end_range) + stop = end_stop + stop_col = end_stop_col end if stop_col == 0 then @@ -268,6 +262,15 @@ end ---@package function FoldInfo:do_foldupdate(bufnr) + -- InsertLeave is not executed when <C-C> is used for exiting the insert mode, leaving + -- do_foldupdate untouched. If another execution of foldupdate consumes foldupdate_range, the + -- InsertLeave do_foldupdate gets nil foldupdate_range. In that case, skip the update. This is + -- correct because the update that consumed the range must have incorporated the range that + -- InsertLeave meant to update. + if not self.foldupdate_range then + return + end + local srow, erow = self.foldupdate_range[1], self.foldupdate_range[2] self.foldupdate_range = nil for _, win in ipairs(vim.fn.win_findbuf(bufnr)) do @@ -383,14 +386,13 @@ local function on_bytes(bufnr, foldinfo, start_row, start_col, old_row, old_col, end end ----@package ---@param lnum integer|nil ---@return string function M.foldexpr(lnum) lnum = lnum or vim.v.lnum local bufnr = api.nvim_get_current_buf() - local parser = vim.F.npcall(ts.get_parser, bufnr) + local parser = ts.get_parser(bufnr, nil, { error = false }) if not parser then return '0' end diff --git a/runtime/lua/vim/treesitter/_meta.lua b/runtime/lua/vim/treesitter/_meta.lua deleted file mode 100644 index 177699a207..0000000000 --- a/runtime/lua/vim/treesitter/_meta.lua +++ /dev/null @@ -1,113 +0,0 @@ ----@meta -error('Cannot require a meta file') - ----@class TSNode: userdata ----@field id fun(self: TSNode): string ----@field tree fun(self: TSNode): TSTree ----@field range fun(self: TSNode, include_bytes: false?): integer, integer, integer, integer ----@field range fun(self: TSNode, include_bytes: true): integer, integer, 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 extra fun(self: TSNode): boolean ----@field child_count fun(self: TSNode): integer ----@field named_child_count fun(self: TSNode): integer ----@field child fun(self: TSNode, index: integer): TSNode? ----@field named_child fun(self: TSNode, index: integer): TSNode? ----@field descendant_for_range fun(self: TSNode, start_row: integer, start_col: integer, end_row: integer, end_col: integer): TSNode? ----@field named_descendant_for_range fun(self: TSNode, start_row: integer, start_col: integer, end_row: integer, end_col: integer): TSNode? ----@field parent fun(self: TSNode): TSNode? ----@field child_containing_descendant fun(self: TSNode, descendant: 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_changes fun(self: TSNode): boolean ----@field has_error fun(self: TSNode): boolean ----@field sexpr fun(self: TSNode): string ----@field equal fun(self: TSNode, other: TSNode): boolean ----@field iter_children fun(self: TSNode): fun(): TSNode, string ----@field field fun(self: TSNode, name: string): TSNode[] ----@field byte_length fun(self: TSNode): integer -local TSNode = {} - ----@alias TSLoggerCallback fun(logtype: 'parse'|'lex', msg: string) - ----@class TSParser: userdata ----@field parse fun(self: TSParser, tree: TSTree?, source: integer|string, include_bytes: boolean): TSTree, (Range4|Range6)[] ----@field reset fun(self: TSParser) ----@field included_ranges fun(self: TSParser, include_bytes: boolean?): integer[] ----@field set_included_ranges fun(self: TSParser, ranges: (Range6|TSNode)[]) ----@field set_timeout fun(self: TSParser, timeout: integer) ----@field timeout fun(self: TSParser): integer ----@field _set_logger fun(self: TSParser, lex: boolean, parse: boolean, cb: TSLoggerCallback) ----@field _logger fun(self: TSParser): TSLoggerCallback - ----@class TSTree: userdata ----@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 ----@field included_ranges fun(self: TSTree, include_bytes: true): Range6[] ----@field included_ranges fun(self: TSTree, include_bytes: false): Range4[] - ----@class TSQuery: userdata ----@field inspect fun(self: TSQuery): TSQueryInfo - ----@class (exact) TSQueryInfo ----@field captures string[] ----@field patterns table<integer, (integer|string)[][]> - ---- @param lang string -vim._ts_inspect_language = function(lang) end - ----@return integer -vim._ts_get_language_version = function() end - ---- @param path string ---- @param lang string ---- @param symbol_name? string -vim._ts_add_language = function(path, lang, symbol_name) end - ----@return integer -vim._ts_get_minimum_language_version = function() end - ----@param lang string Language to use for the query ----@param query string Query string in s-expr syntax ----@return TSQuery -vim._ts_parse_query = function(lang, query) end - ----@param lang string ----@return TSParser -vim._create_ts_parser = function(lang) end - ---- @class TSQueryMatch: userdata ---- @field captures fun(self: TSQueryMatch): table<integer,TSNode[]> -local TSQueryMatch = {} - ---- @return integer match_id ---- @return integer pattern_index -function TSQueryMatch:info() end - ---- @class TSQueryCursor: userdata ---- @field remove_match fun(self: TSQueryCursor, id: integer) -local TSQueryCursor = {} - ---- @return integer capture ---- @return TSNode captured_node ---- @return TSQueryMatch match -function TSQueryCursor:next_capture() end - ---- @return TSQueryMatch match -function TSQueryCursor:next_match() end - ---- @param node TSNode ---- @param query TSQuery ---- @param start integer? ---- @param stop integer? ---- @param opts? { max_start_depth?: integer, match_limit?: integer} ---- @return TSQueryCursor -function vim._create_ts_querycursor(node, query, start, stop, opts) end diff --git a/runtime/lua/vim/treesitter/_meta/misc.lua b/runtime/lua/vim/treesitter/_meta/misc.lua new file mode 100644 index 0000000000..33701ef254 --- /dev/null +++ b/runtime/lua/vim/treesitter/_meta/misc.lua @@ -0,0 +1,78 @@ +---@meta +-- luacheck: no unused args +error('Cannot require a meta file') + +---@alias TSLoggerCallback fun(logtype: 'parse'|'lex', msg: string) + +---@class TSParser: userdata +---@field parse fun(self: TSParser, tree: TSTree?, source: integer|string, include_bytes: boolean): TSTree, (Range4|Range6)[] +---@field reset fun(self: TSParser) +---@field included_ranges fun(self: TSParser, include_bytes: boolean?): integer[] +---@field set_included_ranges fun(self: TSParser, ranges: (Range6|TSNode)[]) +---@field set_timeout fun(self: TSParser, timeout: integer) +---@field timeout fun(self: TSParser): integer +---@field _set_logger fun(self: TSParser, lex: boolean, parse: boolean, cb: TSLoggerCallback) +---@field _logger fun(self: TSParser): TSLoggerCallback + +---@class TSQuery: userdata +---@field inspect fun(self: TSQuery): TSQueryInfo + +---@class (exact) TSQueryInfo +---@field captures string[] +---@field patterns table<integer, (integer|string)[][]> + +--- @param lang string +--- @return table +vim._ts_inspect_language = function(lang) end + +---@return integer +vim._ts_get_language_version = function() end + +--- @param path string +--- @param lang string +--- @param symbol_name? string +vim._ts_add_language_from_object = function(path, lang, symbol_name) end + +--- @param path string +--- @param lang string +vim._ts_add_language_from_wasm = function(path, lang) end + +---@return integer +vim._ts_get_minimum_language_version = function() end + +---@param lang string Language to use for the query +---@param query string Query string in s-expr syntax +---@return TSQuery +vim._ts_parse_query = function(lang, query) end + +---@param lang string +---@return TSParser +vim._create_ts_parser = function(lang) end + +--- @class TSQueryMatch: userdata +--- @field captures fun(self: TSQueryMatch): table<integer,TSNode[]> +local TSQueryMatch = {} -- luacheck: no unused + +--- @return integer match_id +--- @return integer pattern_index +function TSQueryMatch:info() end + +--- @class TSQueryCursor: userdata +--- @field remove_match fun(self: TSQueryCursor, id: integer) +local TSQueryCursor = {} -- luacheck: no unused + +--- @return integer capture +--- @return TSNode captured_node +--- @return TSQueryMatch match +function TSQueryCursor:next_capture() end + +--- @return TSQueryMatch match +function TSQueryCursor:next_match() end + +--- @param node TSNode +--- @param query TSQuery +--- @param start integer? +--- @param stop integer? +--- @param opts? { max_start_depth?: integer, match_limit?: integer} +--- @return TSQueryCursor +function vim._create_ts_querycursor(node, query, start, stop, opts) end diff --git a/runtime/lua/vim/treesitter/_meta/tsnode.lua b/runtime/lua/vim/treesitter/_meta/tsnode.lua new file mode 100644 index 0000000000..acc9f8d24e --- /dev/null +++ b/runtime/lua/vim/treesitter/_meta/tsnode.lua @@ -0,0 +1,185 @@ +---@meta +-- luacheck: no unused args +error('Cannot require a meta file') + +--- @brief 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 |userdata| reference to an +--- object held by the treesitter library. +--- +--- An instance `TSNode` of a treesitter node supports the following methods. + +---@nodoc +---@class TSNode: userdata +---@field named_children fun(self: TSNode): TSNode[] +---@field __has_ancestor fun(self: TSNode, node_types: string[]): boolean +local TSNode = {} -- luacheck: no unused + +--- Get the node's immediate parent. +--- Prefer |TSNode:child_containing_descendant()| +--- for iterating over the node's ancestors. +--- @return TSNode? +function TSNode:parent() end + +--- Get the node's next sibling. +--- @return TSNode? +function TSNode:next_sibling() end + +--- Get the node's previous sibling. +--- @return TSNode? +function TSNode:prev_sibling() end + +--- Get the node's next named sibling. +--- @return TSNode? +function TSNode:next_named_sibling() end + +--- Get the node's previous named sibling. +--- @return TSNode? +function TSNode:prev_named_sibling() end + +--- 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. +--- @return fun(): TSNode, string +function TSNode:iter_children() end + +--- Returns a table of the nodes corresponding to the {name} field. +--- @param name string +--- @return TSNode[] +function TSNode:field(name) end + +--- Get the node's number of children. +--- @return integer +function TSNode:child_count() end + +--- Get the node's child at the given {index}, where zero represents the first +--- child. +--- @param index integer +--- @return TSNode? +function TSNode:child(index) end + +--- Get the node's number of named children. +--- @return integer +function TSNode:named_child_count() end + +--- Get the node's named child at the given {index}, where zero represents the +--- first named child. +--- @param index integer +--- @return TSNode? +function TSNode:named_child(index) end + +--- Get the node's child that contains {descendant}. +--- @param descendant TSNode +--- @return TSNode? +function TSNode:child_containing_descendant(descendant) end + +--- Get the node's start position. Return three values: the row, column and +--- total byte count (all zero-based). +--- @return integer, integer, integer +function TSNode:start() end + +--- Get the node's end position. Return three values: the row, column and +--- total byte count (all zero-based). +--- @return integer, integer, integer +function TSNode:end_() end + +--- Get the range of the node. +--- +--- Return four or six values: +--- +--- - start row +--- - start column +--- - start byte (if {include_bytes} is `true`) +--- - end row +--- - end column +--- - end byte (if {include_bytes} is `true`) +--- @param include_bytes boolean? +function TSNode:range(include_bytes) end + +--- @nodoc +--- @param include_bytes false? +--- @return integer, integer, integer, integer +function TSNode:range(include_bytes) end + +--- @nodoc +--- @param include_bytes true +--- @return integer, integer, integer, integer, integer, integer +function TSNode:range(include_bytes) end + +--- Get the node's type as a string. +--- @return string +function TSNode:type() end + +--- Get the node's type as a numerical id. +--- @return integer +function TSNode:symbol() end + +--- 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. +--- @return boolean +function TSNode:named() end + +--- Check if the node is missing. Missing nodes are inserted by the parser in +--- order to recover from certain kinds of syntax errors. +--- @return boolean +function TSNode:missing() end + +--- Check if the node is extra. Extra nodes represent things like comments, +--- which are not required by the grammar but can appear anywhere. +--- @return boolean +function TSNode:extra() end + +--- Check if a syntax node has been edited. +--- @return boolean +function TSNode:has_changes() end + +--- Check if the node is a syntax error or contains any syntax errors. +--- @return boolean +function TSNode:has_error() end + +--- Get an S-expression representing the node as a string. +--- @return string +function TSNode:sexpr() end + +--- Get a unique identifier for the node inside its own tree. +--- +--- No guarantees are made about this identifier's internal representation, +--- except for being a primitive Lua type with value equality (so not a +--- table). Presently it is a (non-printable) string. +--- +--- Note: The `id` is not guaranteed to be unique for nodes from different +--- trees. +--- @return string +function TSNode:id() end + +--- Get the |TSTree| of the node. +--- @return TSTree +function TSNode:tree() end + +--- Get the smallest node within this node that spans the given range of (row, +--- column) positions +--- @param start_row integer +--- @param start_col integer +--- @param end_row integer +--- @param end_col integer +--- @return TSNode? +function TSNode:descendant_for_range(start_row, start_col, end_row, end_col) end + +--- Get the smallest named node within this node that spans the given range of +--- (row, column) positions +--- @param start_row integer +--- @param start_col integer +--- @param end_row integer +--- @param end_col integer +--- @return TSNode? +function TSNode:named_descendant_for_range(start_row, start_col, end_row, end_col) end + +--- Check if {node} refers to the same node within the same tree. +--- @param node TSNode +--- @return boolean +function TSNode:equal(node) end + +--- Return the number of bytes spanned by this node. +--- @return integer +function TSNode:byte_length() end diff --git a/runtime/lua/vim/treesitter/_meta/tstree.lua b/runtime/lua/vim/treesitter/_meta/tstree.lua new file mode 100644 index 0000000000..24cb60040e --- /dev/null +++ b/runtime/lua/vim/treesitter/_meta/tstree.lua @@ -0,0 +1,44 @@ +---@meta +-- luacheck: no unused args +error('Cannot require a meta file') + +--- @brief A "treesitter tree" represents the parsed contents of a buffer, which can be +--- used to perform further analysis. It is a |userdata| reference to an object +--- held by the treesitter library. +--- +--- An instance `TSTree` of a treesitter tree supports the following methods. + +---@nodoc +---@class TSTree: userdata +local TSTree = {} -- luacheck: no unused + +--- Return the root node of this tree. +---@return TSNode +function TSTree:root() end + +-- stylua: ignore +---@param start_byte integer +---@param end_byte_old integer +---@param end_byte_new integer +---@param start_row integer +---@param start_col integer +---@param end_row_old integer +---@param end_col_old integer +---@param end_row_new integer +---@param end_col_new integer +---@nodoc +function TSTree:edit(start_byte, end_byte_old, end_byte_new, start_row, start_col, end_row_old, end_col_old, end_row_new, end_col_new) end + +--- Returns a copy of the `TSTree`. +---@return TSTree +function TSTree:copy() end + +---@param include_bytes true +---@return Range6[] +---@nodoc +function TSTree:included_ranges(include_bytes) end + +---@param include_bytes false +---@return Range4[] +---@nodoc +function TSTree:included_ranges(include_bytes) end diff --git a/runtime/lua/vim/treesitter/_query_linter.lua b/runtime/lua/vim/treesitter/_query_linter.lua index 12b4cbc7b9..c5e4b86e1e 100644 --- a/runtime/lua/vim/treesitter/_query_linter.lua +++ b/runtime/lua/vim/treesitter/_query_linter.lua @@ -40,7 +40,8 @@ end local function guess_query_lang(buf) local filename = api.nvim_buf_get_name(buf) if filename ~= '' then - return vim.F.npcall(vim.fn.fnamemodify, filename, ':p:h:t') + local resolved_filename = vim.F.npcall(vim.fn.fnamemodify, filename, ':p:h:t') + return resolved_filename and vim.treesitter.language.get_lang(resolved_filename) end end @@ -64,7 +65,7 @@ local function normalize_opts(buf, opts) end local lint_query = [[;; query - (program [(named_node) (list) (grouping)] @toplevel) + (program [(named_node) (anonymous_node) (list) (grouping)] @toplevel) (named_node name: _ @node.named) (anonymous_node @@ -170,17 +171,17 @@ function M.lint(buf, opts) --- @type (table|nil) local parser_info = vim.F.npcall(vim.treesitter.language.inspect, lang) + local lang_context = { + lang = lang, + parser_info = parser_info, + is_first_lang = i == 1, + } - local parser = vim.treesitter.get_parser(buf) + local parser = assert(vim.treesitter.get_parser(buf, nil, { error = false })) parser:parse() parser:for_each_tree(function(tree, ltree) if ltree:lang() == 'query' then - for _, match, _ in query:iter_matches(tree:root(), buf, 0, -1, { all = true }) do - local lang_context = { - lang = lang, - parser_info = parser_info, - is_first_lang = i == 1, - } + for _, match, _ in query:iter_matches(tree:root(), buf, 0, -1) do lint_match(buf, match, query, lang_context, diagnostics) end end @@ -240,7 +241,7 @@ function M.omnifunc(findstart, base) end end for _, s in pairs(parser_info.symbols) do - local text = s[2] and s[1] or '"' .. s[1]:gsub([[\]], [[\\]]) .. '"' ---@type string + local text = s[2] and s[1] or string.format('%q', s[1]):gsub('\n', 'n') ---@type string if text:find(base, 1, true) then table.insert(items, text) end diff --git a/runtime/lua/vim/treesitter/_range.lua b/runtime/lua/vim/treesitter/_range.lua index 8d727c3c52..82ab8517aa 100644 --- a/runtime/lua/vim/treesitter/_range.lua +++ b/runtime/lua/vim/treesitter/_range.lua @@ -3,16 +3,19 @@ local api = vim.api local M = {} ---@class Range2 +---@inlinedoc ---@field [1] integer start row ---@field [2] integer end row ---@class Range4 +---@inlinedoc ---@field [1] integer start row ---@field [2] integer start column ---@field [3] integer end row ---@field [4] integer end column ---@class Range6 +---@inlinedoc ---@field [1] integer start row ---@field [2] integer start column ---@field [3] integer start bytes @@ -150,6 +153,7 @@ function M.contains(r1, r2) return true end +--- @private --- @param source integer|string --- @param index integer --- @return integer diff --git a/runtime/lua/vim/treesitter/dev.lua b/runtime/lua/vim/treesitter/dev.lua index 5c91f101c0..90c3720b80 100644 --- a/runtime/lua/vim/treesitter/dev.lua +++ b/runtime/lua/vim/treesitter/dev.lua @@ -76,10 +76,14 @@ end --- ---@package function TSTreeView:new(bufnr, lang) - local ok, parser = pcall(vim.treesitter.get_parser, bufnr or 0, lang) - if not ok then - local err = parser --[[ @as string ]] - return nil, 'No parser available for the given buffer:\n' .. err + local parser = vim.treesitter.get_parser(bufnr or 0, lang, { error = false }) + if not parser then + return nil, + string.format( + 'Failed to create TSTreeView for buffer %s: no parser for lang "%s"', + bufnr, + lang + ) end -- For each child tree (injected language), find the root of the tree and locate the node within @@ -154,7 +158,8 @@ end ---@param w integer ---@param b integer -local function set_dev_properties(w, b) +---@param opts nil|{ indent?: integer } +local function set_dev_options(w, b, opts) vim.wo[w].scrolloff = 5 vim.wo[w].wrap = false vim.wo[w].foldmethod = 'expr' @@ -165,6 +170,12 @@ local function set_dev_properties(w, b) vim.bo[b].buftype = 'nofile' vim.bo[b].bufhidden = 'wipe' vim.bo[b].filetype = 'query' + vim.bo[b].swapfile = false + + opts = opts or {} + if opts.indent then + vim.bo[b].shiftwidth = opts.indent + end end --- Updates the cursor position in the inspector to match the node under the cursor. @@ -174,7 +185,7 @@ end --- @param source_buf integer --- @param inspect_buf integer --- @param inspect_win integer ---- @param pos? { [1]: integer, [2]: integer } +--- @param pos? [integer, integer] local function set_inspector_cursor(treeview, lang, source_buf, inspect_buf, inspect_win, pos) api.nvim_buf_clear_namespace(inspect_buf, treeview.ns, 0, -1) @@ -183,6 +194,7 @@ local function set_inspector_cursor(treeview, lang, source_buf, inspect_buf, ins lang = lang, pos = pos, ignore_injections = false, + include_anonymous = treeview.opts.anon, }) if not cursor_node then return @@ -220,14 +232,13 @@ function TSTreeView:draw(bufnr) local text ---@type string if item.node:named() then - if item.field then - text = string.format('%s: (%s', item.field, item.node:type()) - else - text = string.format('(%s', item.node:type()) - end + text = string.format('(%s', item.node:type()) else text = string.format('%q', item.node:type()):gsub('\n', 'n') end + if item.field then + text = string.format('%s: %s', item.field, text) + end local next = self:get(i + 1) if not next or next.depth <= item.depth then @@ -325,7 +336,10 @@ function M.inspect_tree(opts) opts = opts or {} + -- source buffer local buf = api.nvim_get_current_buf() + + -- window id for source buffer local win = api.nvim_get_current_win() local treeview = assert(TSTreeView:new(buf, opts.lang)) @@ -334,12 +348,14 @@ function M.inspect_tree(opts) close_win(vim.b[buf].dev_inspect) end + -- window id for tree buffer local w = opts.winid if not w then vim.cmd(opts.command or '60vnew') w = api.nvim_get_current_win() end + -- tree buffer local b = opts.bufnr if b then api.nvim_win_set_buf(w, b) @@ -350,7 +366,7 @@ function M.inspect_tree(opts) vim.b[buf].dev_inspect = w vim.b[b].dev_base = win -- base window handle vim.b[b].disable_query_linter = true - set_dev_properties(w, b) + set_dev_options(w, b, { indent = treeview.opts.indent }) local title --- @type string? local opts_title = opts.title @@ -375,6 +391,12 @@ function M.inspect_tree(opts) callback = function() local row = api.nvim_win_get_cursor(w)[1] local lnum, col = treeview:get(row).node:start() + + -- update source window if original was closed + if not api.nvim_win_is_valid(win) then + win = vim.fn.win_findbuf(buf)[1] + end + api.nvim_set_current_win(win) api.nvim_win_set_cursor(win, { lnum + 1, col }) end, @@ -432,6 +454,7 @@ function M.inspect_tree(opts) return true end + w = api.nvim_get_current_win() api.nvim_buf_clear_namespace(buf, treeview.ns, 0, -1) local row = api.nvim_win_get_cursor(w)[1] local lnum, col, end_lnum, end_col = treeview:get(row).node:range() @@ -441,6 +464,11 @@ function M.inspect_tree(opts) hl_group = 'Visual', }) + -- update source window if original was closed + if not api.nvim_win_is_valid(win) then + win = vim.fn.win_findbuf(buf)[1] + end + local topline, botline = vim.fn.line('w0', win), vim.fn.line('w$', win) -- Move the cursor if highlighted range is completely out of view @@ -506,7 +534,10 @@ function M.inspect_tree(opts) buffer = buf, once = true, callback = function() - close_win(w) + -- close all tree windows + for _, window in pairs(vim.fn.win_findbuf(b)) do + close_win(window) + end end, }) end @@ -519,7 +550,7 @@ local edit_ns = api.nvim_create_namespace('treesitter/dev-edit') local function update_editor_highlights(query_win, base_win, lang) local base_buf = api.nvim_win_get_buf(base_win) local query_buf = api.nvim_win_get_buf(query_win) - local parser = vim.treesitter.get_parser(base_buf, lang) + local parser = assert(vim.treesitter.get_parser(base_buf, lang, { error = false })) api.nvim_buf_clear_namespace(base_buf, edit_ns, 0, -1) local query_content = table.concat(api.nvim_buf_get_lines(query_buf, 0, -1, false), '\n') @@ -554,6 +585,8 @@ end --- @private --- @param lang? string language to open the query editor for. +--- @return boolean? `true` on success, `nil` on failure +--- @return string? error message, if applicable function M.edit_query(lang) local buf = api.nvim_get_current_buf() local win = api.nvim_get_current_win() @@ -576,9 +609,10 @@ function M.edit_query(lang) end vim.cmd(cmd) - local ok, parser = pcall(vim.treesitter.get_parser, buf, lang) - if not ok then - return nil, 'No parser available for the given buffer' + local parser = vim.treesitter.get_parser(buf, lang, { error = false }) + if not parser then + return nil, + string.format('Failed to show query editor for buffer %s: no parser for lang "%s"', buf, lang) end lang = parser:lang() @@ -587,7 +621,7 @@ function M.edit_query(lang) vim.b[buf].dev_edit = query_win vim.bo[query_buf].omnifunc = 'v:lua.vim.treesitter.query.omnifunc' - set_dev_properties(query_win, query_buf) + set_dev_options(query_win, query_buf) -- Note that omnifunc guesses the language based on the containing folder, -- so we add the parser's language to the buffer's name so that omnifunc @@ -652,6 +686,8 @@ function M.edit_query(lang) }) vim.cmd('normal! G') vim.cmd.startinsert() + + return true end return M diff --git a/runtime/lua/vim/treesitter/health.lua b/runtime/lua/vim/treesitter/health.lua index ed3616ef46..637f9ea543 100644 --- a/runtime/lua/vim/treesitter/health.lua +++ b/runtime/lua/vim/treesitter/health.lua @@ -28,6 +28,9 @@ function M.check() ) end end + + local can_wasm = vim._ts_add_language_from_wasm ~= nil + health.info(string.format('Can load WASM parsers: %s', tostring(can_wasm))) end return M diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index d2f986b874..a94c408f4e 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -47,7 +47,7 @@ function TSHighlighterQuery:get_hl_from_capture(capture) return self.hl_cache[capture] end ----@package +---@nodoc function TSHighlighterQuery:query() return self._query end @@ -75,7 +75,7 @@ local TSHighlighter = { TSHighlighter.__index = TSHighlighter ----@package +---@nodoc --- --- Creates a highlighter for `tree`. --- @@ -139,11 +139,14 @@ function TSHighlighter.new(tree, opts) -- but use synload.vim rather than syntax.vim to not enable -- syntax FileType autocmds. Later on we should integrate with the -- `:syntax` and `set syntax=...` machinery properly. + -- Still need to ensure that syntaxset augroup exists, so that calling :destroy() + -- immediately afterwards will not error. if vim.g.syntax_on ~= 1 then vim.cmd.runtime({ 'syntax/synload.vim', bang = true }) + vim.api.nvim_create_augroup('syntaxset', { clear = false }) end - api.nvim_buf_call(self.bufnr, function() + vim._with({ buf = self.bufnr }, function() vim.opt_local.spelloptions:append('noplainbuffer') end) @@ -232,7 +235,7 @@ function TSHighlighter:on_changedtree(changes) end --- Gets the query used for @param lang ----@package +---@nodoc ---@param lang string Language used by the highlighter. ---@return vim.treesitter.highlighter.Query function TSHighlighter:get_query(lang) @@ -377,11 +380,15 @@ function TSHighlighter._on_spell_nav(_, _, buf, srow, _, erow, _) return end + -- Do not affect potentially populated highlight state. Here we just want a temporary + -- empty state so the C code can detect whether the region should be spell checked. + local highlight_states = self._highlight_states self:prepare_highlight_states(srow, erow) for row = srow, erow do on_line_impl(self, buf, row, true) end + self._highlight_states = highlight_states end ---@private diff --git a/runtime/lua/vim/treesitter/language.lua b/runtime/lua/vim/treesitter/language.lua index d0a74daa6c..9f7807e036 100644 --- a/runtime/lua/vim/treesitter/language.lua +++ b/runtime/lua/vim/treesitter/language.lua @@ -7,11 +7,15 @@ local ft_to_lang = { help = 'vimdoc', } ---- Get the filetypes associated with the parser named {lang}. +--- Returns the filetypes for which a parser named {lang} is used. +--- +--- The list includes {lang} itself plus all filetypes registered via +--- |vim.treesitter.language.register()|. +--- --- @param lang string Name of parser --- @return string[] filetypes function M.get_filetypes(lang) - local r = {} ---@type string[] + local r = { lang } ---@type string[] for ft, p in pairs(ft_to_lang) do if p == lang then r[#r + 1] = ft @@ -20,6 +24,12 @@ function M.get_filetypes(lang) return r end +--- Returns the language name to be used when loading a parser for {filetype}. +--- +--- If no language has been explicitly registered via |vim.treesitter.language.register()|, +--- default to {filetype}. For composite filetypes like `html.glimmer`, only the main filetype is +--- returned. +--- --- @param filetype string --- @return string|nil function M.get_lang(filetype) @@ -29,9 +39,9 @@ function M.get_lang(filetype) if ft_to_lang[filetype] then return ft_to_lang[filetype] end - -- support subfiletypes like html.glimmer + -- for subfiletypes like html.glimmer use only "main" filetype filetype = vim.split(filetype, '.', { plain = true })[1] - return ft_to_lang[filetype] + return ft_to_lang[filetype] or filetype end ---@deprecated @@ -52,17 +62,27 @@ function M.require_language(lang, path, silent, symbol_name) return installed end - M.add(lang, opts) - return true + return M.add(lang, opts) +end + +--- Load wasm or native parser (wrapper) +--- todo(clason): move to C +--- +---@param path string Path of parser library +---@param lang string Language name +---@param symbol_name? string Internal symbol name for the language to load (default lang) +---@return boolean? True if parser is loaded +local function loadparser(path, lang, symbol_name) + if vim.endswith(path, '.wasm') then + return vim._ts_add_language_from_wasm and vim._ts_add_language_from_wasm(path, lang) + else + return vim._ts_add_language_from_object(path, lang, symbol_name) + end end ---@class vim.treesitter.language.add.Opts ---@inlinedoc --- ----Default filetype the parser should be associated with. ----(Default: {lang}) ----@field filetype? string|string[] ---- ---Optional path the parser is located at ---@field path? string --- @@ -71,46 +91,52 @@ end --- Load parser with name {lang} --- ---- Parsers are searched in the `parser` runtime directory, or the provided {path} +--- Parsers are searched in the `parser` runtime directory, or the provided {path}. +--- Can be used to check for available parsers before enabling treesitter features, e.g., +--- ```lua +--- if vim.treesitter.language.add('markdown') then +--- vim.treesitter.start(bufnr, 'markdown') +--- end +--- ``` --- ---@param lang string Name of the parser (alphanumerical and `_` only) ---@param opts? vim.treesitter.language.add.Opts Options: +---@return boolean? True if parser is loaded +---@return string? Error if parser cannot be loaded function M.add(lang, opts) opts = opts or {} local path = opts.path - local filetype = opts.filetype or lang local symbol_name = opts.symbol_name vim.validate({ lang = { lang, 'string' }, path = { path, 'string', true }, symbol_name = { symbol_name, 'string', true }, - filetype = { filetype, { 'string', 'table' }, true }, }) -- parser names are assumed to be lowercase (consistent behavior on case-insensitive file systems) lang = lang:lower() if vim._ts_has_language(lang) then - M.register(lang, filetype) - return + return true end if path == nil then + -- allow only safe language names when looking for libraries to load if not (lang and lang:match('[%w_]+') == lang) then - error("'" .. lang .. "' is not a valid language name") + return nil, string.format('Invalid language name "%s"', lang) end local fname = 'parser/' .. lang .. '.*' local paths = api.nvim_get_runtime_file(fname, false) if #paths == 0 then - error("no parser for '" .. lang .. "' language, see :help treesitter-parsers") + return nil, string.format('No parser for language "%s"', lang) end path = paths[1] end - vim._ts_add_language(path, lang, symbol_name) - M.register(lang, filetype) + return loadparser(path, lang, symbol_name) or nil, + string.format('Cannot load parser %s for language "%s"', path, lang) end --- @param x string|string[] diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index b0812123b9..fd68c2b910 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -98,9 +98,9 @@ local LanguageTree = {} LanguageTree.__index = LanguageTree ---- @package +--- @nodoc --- ---- |LanguageTree| contains a tree of parsers: the root treesitter parser for {lang} and any +--- LanguageTree contains a tree of parsers: the root treesitter parser for {lang} and any --- "injected" language parsers, which themselves may inject other languages, recursively. --- ---@param source (integer|string) Buffer or text string to parse @@ -108,7 +108,7 @@ LanguageTree.__index = LanguageTree ---@param opts vim.treesitter.LanguageTree.new.Opts? ---@return vim.treesitter.LanguageTree parser object function LanguageTree.new(source, lang, opts) - language.add(lang) + assert(language.add(lang)) opts = opts or {} if source == 0 then @@ -638,6 +638,8 @@ end ---Gets the set of included regions managed by this LanguageTree. This can be different from the ---regions set by injection query, because a partial |LanguageTree:parse()| drops the regions ---outside the requested range. +---Each list represents a range in the form of +---{ {start_row}, {start_col}, {start_bytes}, {end_row}, {end_col}, {end_bytes} }. ---@return table<integer, Range6[]> function LanguageTree:included_regions() if self._regions then @@ -732,7 +734,7 @@ local function add_injection(t, tree_index, pattern, lang, combined, ranges) table.insert(t[tree_index][lang][pattern].regions, ranges) end --- TODO(clason): replace by refactored `ts.has_parser` API (without registering) +-- TODO(clason): replace by refactored `ts.has_parser` API (without side effects) --- The result of this function is cached to prevent nvim_get_runtime_file from being --- called too often --- @param lang string parser name @@ -831,13 +833,7 @@ function LanguageTree:_get_injections() local start_line, _, end_line, _ = root_node:range() for pattern, match, metadata in - self._injection_query:iter_matches( - root_node, - self._source, - start_line, - end_line + 1, - { all = true } - ) + self._injection_query:iter_matches(root_node, self._source, start_line, end_line + 1) do local lang, combined, ranges = self:_get_injection(match, metadata) if lang then @@ -951,7 +947,7 @@ function LanguageTree:_edit( end end ----@package +---@nodoc ---@param bufnr integer ---@param changed_tick integer ---@param start_row integer @@ -1023,12 +1019,12 @@ function LanguageTree:_on_bytes( ) end ----@package +---@nodoc function LanguageTree:_on_reload() self:invalidate(true) end ----@package +---@nodoc function LanguageTree:_on_detach(...) self:invalidate(true) self:_do_callback('detach', ...) @@ -1087,7 +1083,7 @@ end --- Determines whether {range} is contained in the |LanguageTree|. --- ----@param range Range4 `{ start_line, start_col, end_line, end_col }` +---@param range Range4 ---@return boolean function LanguageTree:contains(range) for _, tree in pairs(self._trees) do @@ -1108,7 +1104,7 @@ end --- Gets the tree that contains {range}. --- ----@param range Range4 `{ start_line, start_col, end_line, end_col }` +---@param range Range4 ---@param opts? vim.treesitter.LanguageTree.tree_for_range.Opts ---@return TSTree? function LanguageTree:tree_for_range(range, opts) @@ -1133,9 +1129,21 @@ function LanguageTree:tree_for_range(range, opts) return nil end +--- Gets the smallest node that contains {range}. +--- +---@param range Range4 +---@param opts? vim.treesitter.LanguageTree.tree_for_range.Opts +---@return TSNode? +function LanguageTree:node_for_range(range, opts) + local tree = self:tree_for_range(range, opts) + if tree then + return tree:root():descendant_for_range(unpack(range)) + end +end + --- Gets the smallest named node that contains {range}. --- ----@param range Range4 `{ start_line, start_col, end_line, end_col }` +---@param range Range4 ---@param opts? vim.treesitter.LanguageTree.tree_for_range.Opts ---@return TSNode? function LanguageTree:named_node_for_range(range, opts) @@ -1147,7 +1155,7 @@ end --- Gets the appropriate language that contains {range}. --- ----@param range Range4 `{ start_line, start_col, end_line, end_col }` +---@param range Range4 ---@return vim.treesitter.LanguageTree tree Managing {range} function LanguageTree:language_for_range(range) for _, child in pairs(self._children) do diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index ef5c2143a7..4614967799 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -247,8 +247,7 @@ end) --- ---@see [vim.treesitter.query.get()] M.parse = memoize('concat-2', function(lang, query) - language.add(lang) - + assert(language.add(lang)) local ts_query = vim._ts_parse_query(lang, query) return Query.new(lang, ts_query) end) @@ -487,8 +486,8 @@ predicate_handlers['any-vim-match?'] = predicate_handlers['any-match?'] ---@class vim.treesitter.query.TSMetadata ---@field range? Range ---@field conceal? string ----@field [integer] vim.treesitter.query.TSMetadata ----@field [string] integer|string +---@field [integer]? vim.treesitter.query.TSMetadata +---@field [string]? integer|string ---@alias TSDirective fun(match: table<integer,TSNode[]>, _, _, predicate: (string|integer)[], metadata: vim.treesitter.query.TSMetadata) @@ -620,16 +619,16 @@ local directive_handlers = { --- @field force? boolean --- --- Use the correct implementation of the match table where capture IDs map to ---- a list of nodes instead of a single node. Defaults to false (for backward ---- compatibility). This option will eventually become the default and removed. +--- a list of nodes instead of a single node. Defaults to true. This option will +--- be removed in a future release. --- @field all? boolean --- Adds a new predicate to be used in queries --- ---@param name string Name of the predicate, without leading # ----@param handler fun(match: table<integer,TSNode[]>, pattern: integer, source: integer|string, predicate: any[], metadata: table) +---@param handler fun(match: table<integer,TSNode[]>, pattern: integer, source: integer|string, predicate: any[], metadata: vim.treesitter.query.TSMetadata) --- - see |vim.treesitter.query.add_directive()| for argument meanings ----@param opts vim.treesitter.query.add_predicate.Opts +---@param opts? vim.treesitter.query.add_predicate.Opts function M.add_predicate(name, handler, opts) -- Backward compatibility: old signature had "force" as boolean argument if type(opts) == 'boolean' then @@ -642,7 +641,7 @@ function M.add_predicate(name, handler, opts) error(string.format('Overriding existing predicate %s', name)) end - if opts.all then + if opts.all ~= false then predicate_handlers[name] = handler else --- @param match table<integer, TSNode[]> @@ -667,7 +666,7 @@ end --- metadata table `metadata[capture_id].key = value` --- ---@param name string Name of the directive, without leading # ----@param handler fun(match: table<integer,TSNode[]>, pattern: integer, source: integer|string, predicate: any[], metadata: table) +---@param handler fun(match: table<integer,TSNode[]>, pattern: integer, source: integer|string, predicate: any[], metadata: vim.treesitter.query.TSMetadata) --- - match: A table mapping capture IDs to a list of captured nodes --- - pattern: the index of the matching pattern in the query file --- - predicate: list of strings containing the full directive being called, e.g. @@ -894,16 +893,10 @@ end --- index of the pattern in the query, a table mapping capture indices to a list --- of nodes, and metadata from any directives processing the match. --- ---- WARNING: Set `all=true` to ensure all matching nodes in a match are ---- returned, otherwise only the last node in a match is returned, breaking captures ---- involving quantifiers such as `(comment)+ @comment`. The default option ---- `all=false` is only provided for backward compatibility and will be removed ---- after Nvim 0.10. ---- --- Example: --- --- ```lua ---- for pattern, match, metadata in cquery:iter_matches(tree:root(), bufnr, 0, -1, { all = true }) do +--- for pattern, match, metadata in cquery:iter_matches(tree:root(), bufnr, 0, -1) do --- for id, nodes in pairs(match) do --- local name = query.captures[id] --- for _, node in ipairs(nodes) do @@ -925,11 +918,11 @@ end --- - max_start_depth (integer) if non-zero, sets the maximum start depth --- for each match. This is used to prevent traversing too deep into a tree. --- - match_limit (integer) Set the maximum number of in-progress matches (Default: 256). ---- - all (boolean) When set, the returned match table maps capture IDs to a list of nodes. ---- Older versions of iter_matches incorrectly mapped capture IDs to a single node, which is ---- incorrect behavior. This option will eventually become the default and removed. +--- - all (boolean) When `false` (default `true`), the returned table maps capture IDs to a single +--- (last) node instead of the full list of matching nodes. This option is only for backward +--- compatibility and will be removed in a future release. --- ----@return (fun(): integer, table<integer, TSNode[]>, table): pattern id, match, metadata +---@return (fun(): integer, table<integer, TSNode[]>, vim.treesitter.query.TSMetadata): pattern id, match, metadata function Query:iter_matches(node, source, start, stop, opts) opts = opts or {} opts.match_limit = opts.match_limit or 256 @@ -960,10 +953,10 @@ function Query:iter_matches(node, source, start, stop, opts) local captures = match:captures() - if not opts.all then + if opts.all == false then -- Convert the match table into the old buggy version for backward - -- compatibility. This is slow. Plugin authors, if you're reading this, set the "all" - -- option! + -- compatibility. This is slow, but we only do it when the caller explicitly opted into it by + -- setting `all` to `false`. local old_match = {} ---@type table<integer, TSNode> for k, v in pairs(captures or {}) do old_match[k] = v[#v] @@ -1034,7 +1027,7 @@ end --- --- @param lang? string language to open the query editor for. If omitted, inferred from the current buffer's filetype. function M.edit(lang) - vim.treesitter.dev.edit_query(lang) + assert(vim.treesitter.dev.edit_query(lang)) end return M diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index 99b9b78e2a..532decf5e9 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -117,6 +117,8 @@ end --- -- Asynchronous. --- vim.ui.open("https://neovim.io/") --- vim.ui.open("~/path/to/file") +--- -- Use the "osurl" command to handle the path or URL. +--- vim.ui.open("gh#neovim/neovim!29490", { cmd = { 'osurl' } }) --- -- Synchronous (wait until the process exits). --- local cmd, err = vim.ui.open("$VIMRUNTIME") --- if cmd then @@ -125,23 +127,29 @@ end --- ``` --- ---@param path string Path or URL to open +---@param opt? { cmd?: string[] } Options +--- - cmd string[]|nil Command used to open the path or URL. --- ---@return vim.SystemObj|nil # Command object, or nil if not found. ---@return nil|string # Error message on failure, or nil on success. --- ---@see |vim.system()| -function M.open(path) +function M.open(path, opt) vim.validate({ path = { path, 'string' }, }) local is_uri = path:match('%w+:') if not is_uri then - path = vim.fn.expand(path) + path = vim.fs.normalize(path) end - local cmd --- @type string[] + opt = opt or {} + local cmd ---@type string[] + local job_opt = { text = true, detach = true } --- @type vim.SystemOpts - if vim.fn.has('mac') == 1 then + if opt.cmd then + cmd = vim.list_extend(opt.cmd --[[@as string[] ]], { path }) + elseif vim.fn.has('mac') == 1 then cmd = { 'open', path } elseif vim.fn.has('win32') == 1 then if vim.fn.executable('rundll32') == 1 then @@ -149,37 +157,79 @@ function M.open(path) else return nil, 'vim.ui.open: rundll32 not found' end + elseif vim.fn.executable('xdg-open') == 1 then + cmd = { 'xdg-open', path } + job_opt.stdout = false + job_opt.stderr = false elseif vim.fn.executable('wslview') == 1 then cmd = { 'wslview', path } elseif vim.fn.executable('explorer.exe') == 1 then cmd = { 'explorer.exe', path } - elseif vim.fn.executable('xdg-open') == 1 then - cmd = { 'xdg-open', path } else return nil, 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open)' end - return vim.system(cmd, { text = true, detach = true }), nil + return vim.system(cmd, job_opt), nil end ---- Gets the URL at cursor, if any. -function M._get_url() - if vim.bo.filetype == 'markdown' then - local range = vim.api.nvim_win_get_cursor(0) - vim.treesitter.get_parser():parse(range) - -- marking the node as `markdown_inline` is required. Setting it to `markdown` does not - -- work. - local current_node = vim.treesitter.get_node { lang = 'markdown_inline' } - while current_node do - local type = current_node:type() - if type == 'inline_link' or type == 'image' then - local child = assert(current_node:named_child(1)) - return vim.treesitter.get_node_text(child, 0) +--- Returns all URLs at cursor, if any. +--- @return string[] +function M._get_urls() + local urls = {} ---@type string[] + + local bufnr = vim.api.nvim_get_current_buf() + local cursor = vim.api.nvim_win_get_cursor(0) + local row = cursor[1] - 1 + local col = cursor[2] + local extmarks = vim.api.nvim_buf_get_extmarks(bufnr, -1, { row, col }, { row, col }, { + details = true, + type = 'highlight', + overlap = true, + }) + for _, v in ipairs(extmarks) do + local details = v[4] + if details and details.url then + urls[#urls + 1] = details.url + end + end + + local highlighter = vim.treesitter.highlighter.active[bufnr] + if highlighter then + local range = { row, col, row, col } + local ltree = highlighter.tree:language_for_range(range) + local lang = ltree:lang() + local query = vim.treesitter.query.get(lang, 'highlights') + if query then + local tree = assert(ltree:tree_for_range(range)) + for _, match, metadata in query:iter_matches(tree:root(), bufnr, row, row + 1) do + for id, nodes in pairs(match) do + for _, node in ipairs(nodes) do + if vim.treesitter.node_contains(node, range) then + local url = metadata[id] and metadata[id].url + if url and match[url] then + for _, n in ipairs(match[url]) do + urls[#urls + 1] = + vim.treesitter.get_node_text(n, bufnr, { metadata = metadata[url] }) + end + end + end + end + end end - current_node = current_node:parent() end end - return vim.fn.expand('<cfile>') + + if #urls == 0 then + -- If all else fails, use the filename under the cursor + table.insert( + urls, + vim._with({ go = { isfname = vim.o.isfname .. ',@-@' } }, function() + return vim.fn.expand('<cfile>') + end) + ) + end + + return urls end return M diff --git a/runtime/lua/vim/version.lua b/runtime/lua/vim/version.lua index 0b149700b5..d64ef98d2d 100644 --- a/runtime/lua/vim/version.lua +++ b/runtime/lua/vim/version.lua @@ -174,6 +174,10 @@ function M._version(version, strict) -- Adapted from https://github.com/folke/la version = version:match('%d[^ ]*') end + if version == nil then + return nil + end + local prerel = version:match('%-([^+]*)') local prerel_strict = version:match('%-([0-9A-Za-z-]*)') if @@ -272,6 +276,7 @@ end --- ``` --- --- @see # https://github.com/npm/node-semver#ranges +--- @since 11 --- --- @param spec string Version range "spec" --- @return vim.VersionRange? @@ -371,6 +376,7 @@ end --- ``` --- --- @note Per semver, build metadata is ignored when comparing two otherwise-equivalent versions. +--- @since 11 --- ---@param v1 vim.Version|number[]|string Version object. ---@param v2 vim.Version|number[]|string Version to compare with `v1`. @@ -388,6 +394,7 @@ function M.cmp(v1, v2) end ---Returns `true` if the given versions are equal. See |vim.version.cmp()| for usage. +---@since 11 ---@param v1 vim.Version|number[]|string ---@param v2 vim.Version|number[]|string ---@return boolean @@ -396,6 +403,7 @@ function M.eq(v1, v2) end ---Returns `true` if `v1 <= v2`. See |vim.version.cmp()| for usage. +---@since 12 ---@param v1 vim.Version|number[]|string ---@param v2 vim.Version|number[]|string ---@return boolean @@ -404,6 +412,7 @@ function M.le(v1, v2) end ---Returns `true` if `v1 < v2`. See |vim.version.cmp()| for usage. +---@since 11 ---@param v1 vim.Version|number[]|string ---@param v2 vim.Version|number[]|string ---@return boolean @@ -412,6 +421,7 @@ function M.lt(v1, v2) end ---Returns `true` if `v1 >= v2`. See |vim.version.cmp()| for usage. +---@since 12 ---@param v1 vim.Version|number[]|string ---@param v2 vim.Version|number[]|string ---@return boolean @@ -420,6 +430,7 @@ function M.ge(v1, v2) end ---Returns `true` if `v1 > v2`. See |vim.version.cmp()| for usage. +---@since 11 ---@param v1 vim.Version|number[]|string ---@param v2 vim.Version|number[]|string ---@return boolean @@ -434,7 +445,8 @@ end --- { major = 1, minor = 0, patch = 1, prerelease = "rc1", build = "build.2" } --- ``` --- ---- @see # https://semver.org/spec/v2.0.0.html +---@see # https://semver.org/spec/v2.0.0.html +---@since 11 --- ---@param version string Version string to parse. ---@param opts table|nil Optional keyword arguments: diff --git a/runtime/lua/vim/vimhelp.lua b/runtime/lua/vim/vimhelp.lua index 4af6866d48..5579cc0174 100644 --- a/runtime/lua/vim/vimhelp.lua +++ b/runtime/lua/vim/vimhelp.lua @@ -30,4 +30,42 @@ function M.highlight_groups(patterns) vim.fn.setpos('.', save_cursor) end +--- Show a table of contents for the help buffer in a loclist +function M.show_toc() + local bufnr = vim.api.nvim_get_current_buf() + local parser = assert(vim.treesitter.get_parser(bufnr, 'vimdoc', { error = false })) + local query = vim.treesitter.query.parse( + parser:lang(), + [[ + (h1 (heading) @h1) + (h2 (heading) @h2) + (h3 (heading) @h3) + (column_heading (heading) @h4) + ]] + ) + local root = parser:parse()[1]:root() + local headings = {} + for id, node, _, _ in query:iter_captures(root, bufnr) do + local text = vim.treesitter.get_node_text(node, bufnr) + local capture = query.captures[id] + local row, col = node:start() + -- only column_headings at col 1 are headings, otherwise it's code examples + local is_code = (capture == 'h4' and col > 0) + -- ignore tabular material + local is_table = (capture == 'h4' and (text:find('\t') or text:find(' '))) + -- ignore tag-only headings + local is_tag = node:child_count() == 1 and node:child(0):type() == 'tag' + if not (is_code or is_table or is_tag) then + table.insert(headings, { + bufnr = bufnr, + lnum = row + 1, + text = (capture == 'h3' or capture == 'h4') and '  ' .. text or text, + }) + end + end + vim.fn.setloclist(0, headings, ' ') + vim.fn.setloclist(0, {}, 'a', { title = 'Help TOC' }) + vim.cmd.lopen() +end + return M diff --git a/runtime/nvim.desktop b/runtime/nvim.desktop index 224353c6ad..f9feae926d 100644 --- a/runtime/nvim.desktop +++ b/runtime/nvim.desktop @@ -4,6 +4,7 @@ GenericName=Text Editor GenericName[ckb]=دەستکاریکەری دەق GenericName[de]=Texteditor GenericName[fr]=Éditeur de texte +GenericName[pl]=Edytor tekstu GenericName[ru]=ТекÑтовый редактор GenericName[sr]=Едитор текÑÑ‚ GenericName[tr]=Metin Düzenleyici diff --git a/runtime/optwin.vim b/runtime/optwin.vim index 5b5b33e4ad..da70ff1afe 100644 --- a/runtime/optwin.vim +++ b/runtime/optwin.vim @@ -1,7 +1,7 @@ " These commands create the option window. " " Maintainer: The Vim Project <https://github.com/vim/vim> -" Last Change: 2023 Aug 31 +" Last Change: 2024 Jul 12 " Former Maintainer: Bram Moolenaar <Bram@vim.org> " If there already is an option window, jump to that one. @@ -507,6 +507,8 @@ endif call <SID>Header(gettext("multiple tab pages")) call <SID>AddOption("showtabline", gettext("0, 1 or 2; when to use a tab pages line")) call append("$", " \tset stal=" . &stal) +call <SID>AddOption("tabclose", gettext("behaviour when closing tab pages: left, uselast or empty")) +call append("$", " \tset tcl=" . &tcl) call <SID>AddOption("tabpagemax", gettext("maximum number of tab pages to open for -p and \"tab all\"")) call append("$", " \tset tpm=" . &tpm) call <SID>AddOption("tabline", gettext("custom tab pages line")) @@ -723,7 +725,9 @@ if has("insert_expand") call append("$", "\t" .. s:local_to_buffer) call <SID>OptionL("cpt") call <SID>AddOption("completeopt", gettext("whether to use a popup menu for Insert mode completion")) - call <SID>OptionG("cot", &cot) + call <SID>OptionL("cot") + call <SID>AddOption("completeitemalign", gettext("popup menu item align order")) + call <SID>OptionG("cia", &cia) call <SID>AddOption("pumheight", gettext("maximum height of the popup menu")) call <SID>OptionG("ph", &ph) call <SID>AddOption("pumwidth", gettext("minimum width of the popup menu")) diff --git a/runtime/pack/dist/opt/nohlsearch/plugin/nohlsearch.vim b/runtime/pack/dist/opt/nohlsearch/plugin/nohlsearch.vim new file mode 100644 index 0000000000..a2d766e41a --- /dev/null +++ b/runtime/pack/dist/opt/nohlsearch/plugin/nohlsearch.vim @@ -0,0 +1,20 @@ +" nohlsearch.vim: Auto turn off hlsearch +" Last Change: 2024-07-31 +" Maintainer: Maxim Kim <habamax@gmail.com> +" +" turn off hlsearch after: +" - doing nothing for 'updatetime' +" - getting into insert mode + +if exists('g:loaded_nohlsearch') + finish +endif +let g:loaded_nohlsearch = 1 + +augroup nohlsearch + au! + noremap <Plug>(nohlsearch) <cmd>nohlsearch<cr> + noremap! <Plug>(nohlsearch) <cmd>nohlsearch<cr> + au CursorHold * call feedkeys("\<Plug>(nohlsearch)", 'm') + au InsertEnter * call feedkeys("\<Plug>(nohlsearch)", 'm') +augroup END diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim index f78a082cb7..9412a821e8 100644 --- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim +++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim @@ -44,8 +44,13 @@ " - job_info && term_getjob -> nvim_get_chan_info " - balloon -> vim.lsp.util.open_floating_preview +func s:Echoerr(msg) + echohl ErrorMsg | echom $'[termdebug] {a:msg}' | echohl None +endfunc + " In case this gets sourced twice. if exists(':Termdebug') + call s:Echoerr('Termdebug already loaded.') finish endif @@ -67,8 +72,8 @@ command -nargs=+ -complete=file -bang TermdebugCommand call s:StartDebugCommand( let s:pc_id = 12 let s:asm_id = 13 let s:break_id = 14 " breakpoint number is added to this -let s:stopped = 1 -let s:running = 0 +let s:stopped = v:true +let s:running = v:false let s:parsing_disasm_msg = 0 let s:asm_lines = [] @@ -86,9 +91,9 @@ endfunction func s:Highlight(init, old, new) let default = a:init ? 'default ' : '' if a:new ==# 'light' && a:old !=# 'light' - exe "hi " . default . "debugPC term=reverse ctermbg=lightblue guibg=lightblue" + exe $"hi {default}debugPC term=reverse ctermbg=lightblue guibg=lightblue" elseif a:new ==# 'dark' && a:old !=# 'dark' - exe "hi " . default . "debugPC term=reverse ctermbg=darkblue guibg=darkblue" + exe $"hi {default}debugPC term=reverse ctermbg=darkblue guibg=darkblue" endif endfunc @@ -121,10 +126,6 @@ func s:GetCommand() return type(cmd) == v:t_list ? copy(cmd) : [cmd] endfunc -func s:Echoerr(msg) - echohl ErrorMsg | echom '[termdebug] ' .. a:msg | echohl None -endfunc - func s:StartDebug(bang, ...) " First argument is the command to debug, second core file or process ID. call s:StartDebug_internal({'gdb_args': a:000, 'bang': a:bang}) @@ -142,16 +143,16 @@ func s:StartDebug_internal(dict) endif let gdbcmd = s:GetCommand() if !executable(gdbcmd[0]) - call s:Echoerr('Cannot execute debugger program "' .. gdbcmd[0] .. '"') + call s:Echoerr($'Cannot execute debugger program "{gdbcmd[0]}"') return endif let s:ptywin = 0 let s:pid = 0 let s:asmwin = 0 - let s:asmbuf = 0 + let s:asmbufnr = 0 let s:varwin = 0 - let s:varbuf = 0 + let s:varbufnr = 0 if exists('#User#TermdebugStartPre') doauto <nomodeline> User TermdebugStartPre @@ -167,8 +168,8 @@ func s:StartDebug_internal(dict) let b:save_signcolumn = &signcolumn let s:signcolumn_buflist = [bufnr()] - let s:save_columns = 0 - let s:allleft = 0 + let s:saved_columns = 0 + let s:allleft = v:false let wide = 0 if exists('g:termdebug_config') let wide = get(g:termdebug_config, 'wide', 0) @@ -177,15 +178,15 @@ func s:StartDebug_internal(dict) endif if wide > 0 if &columns < wide - let s:save_columns = &columns + let s:saved_columns = &columns let &columns = wide " If we make the Vim window wider, use the whole left half for the debug " windows. - let s:allleft = 1 + let s:allleft = v:true endif - let s:vertical = 1 + let s:vertical = v:true else - let s:vertical = 0 + let s:vertical = v:false endif " Override using a terminal window by setting g:termdebug_use_prompt to 1. @@ -226,24 +227,25 @@ endfunc " Use when debugger didn't start or ended. func s:CloseBuffers() - exe 'bwipe! ' . s:ptybuf - if s:asmbuf > 0 && bufexists(s:asmbuf) - exe 'bwipe! ' . s:asmbuf + exe $'bwipe! {s:ptybufnr}' + if s:asmbufnr > 0 && bufexists(s:asmbufnr) + exe $'bwipe! {s:asmbufnr}' endif - if s:varbuf > 0 && bufexists(s:varbuf) - exe 'bwipe! ' . s:varbuf + if s:varbufnr > 0 && bufexists(s:varbufnr) + exe $'bwipe! {s:varbufnr}' endif - let s:running = 0 + let s:running = v:false unlet! s:gdbwin endfunc -func s:CheckGdbRunning() +func s:IsGdbStarted() if !s:gdb_running - call s:Echoerr(string(s:GetCommand()[0]) . ' exited unexpectedly') + let cmd_name = string(s:GetCommand()[0]) + call s:Echoerr($'{cmd_name} exited unexpectedly') call s:CloseBuffers() - return '' + return v:false endif - return 'ok' + return v:true endfunc " Open a terminal window without a job, to run the debugged program in. @@ -258,13 +260,13 @@ func s:StartDebug_term(dict) return endif let pty_job_info = nvim_get_chan_info(s:pty_job_id) - let s:ptybuf = pty_job_info['buffer'] + let s:ptybufnr = pty_job_info['buffer'] let pty = pty_job_info['pty'] let s:ptywin = win_getid() if s:vertical " Assuming the source code window will get a signcolumn, use two more " columns for that, thus one less for the terminal window. - exe (&columns / 2 - 1) . "wincmd |" + exe $":{(&columns / 2 - 1)}wincmd |" if s:allleft " use the whole left column wincmd H @@ -279,11 +281,11 @@ func s:StartDebug_term(dict) " hide terminal buffer if s:comm_job_id == 0 call s:Echoerr('Invalid argument (or job table is full) while opening communication terminal window') - exe 'bwipe! ' . s:ptybuf + exe 'bwipe! ' . s:ptybufnr return elseif s:comm_job_id == -1 call s:Echoerr('Failed to open the communication terminal window') - exe 'bwipe! ' . s:ptybuf + exe $'bwipe! {s:ptybufnr}' return endif let comm_job_info = nvim_get_chan_info(s:comm_job_id) @@ -320,11 +322,11 @@ func s:StartDebug_term(dict) let gdb_cmd += gdb_args execute 'new' - " call ch_log('executing "' . join(gdb_cmd) . '"') + " call ch_log($'executing "{join(gdb_cmd)}"') let s:gdb_job_id = termopen(gdb_cmd, {'on_exit': function('s:EndTermDebug')}) if s:gdb_job_id == 0 call s:Echoerr('Invalid argument (or job table is full) while opening gdb terminal window') - exe 'bwipe! ' . s:ptybuf + exe 'bwipe! ' . s:ptybufnr return elseif s:gdb_job_id == -1 call s:Echoerr('Failed to open the gdb terminal window') @@ -334,18 +336,18 @@ func s:StartDebug_term(dict) let s:gdb_running = v:true let s:starting = v:true let gdb_job_info = nvim_get_chan_info(s:gdb_job_id) - let s:gdbbuf = gdb_job_info['buffer'] + let s:gdbbufnr = gdb_job_info['buffer'] let s:gdbwin = win_getid() " Wait for the "startupdone" message before sending any commands. let try_count = 0 while 1 - if s:CheckGdbRunning() != 'ok' + if !s:IsGdbStarted() return endif for lnum in range(1, 200) - if get(getbufline(s:gdbbuf, lnum), 0, '') =~ 'startupdone' + if get(getbufline(s:gdbbufnr, lnum), 0, '') =~ 'startupdone' let try_count = 9999 break endif @@ -359,26 +361,26 @@ func s:StartDebug_term(dict) endwhile " Set arguments to be run. - if len(proc_args) - call chansend(s:gdb_job_id, 'server set args ' . join(proc_args) . "\r") + if !empty(proc_args) + call chansend(s:gdb_job_id, $"server set args {join(proc_args)}\r") endif " Connect gdb to the communication pty, using the GDB/MI interface. " Prefix "server" to avoid adding this to the history. - call chansend(s:gdb_job_id, 'server new-ui mi ' . commpty . "\r") + call chansend(s:gdb_job_id, $"server new-ui mi {commpty}\r") " Wait for the response to show up, users may not notice the error and wonder " why the debugger doesn't work. let try_count = 0 while 1 - if s:CheckGdbRunning() != 'ok' + if !s:IsGdbStarted() return endif let response = '' for lnum in range(1, 200) - let line1 = get(getbufline(s:gdbbuf, lnum), 0, '') - let line2 = get(getbufline(s:gdbbuf, lnum + 1), 0, '') + let line1 = get(getbufline(s:gdbbufnr, lnum), 0, '') + let line2 = get(getbufline(s:gdbbufnr, lnum + 1), 0, '') if line1 =~ 'new-ui mi ' " response can be in the same line or the next line let response = line1 . line2 @@ -444,7 +446,7 @@ func s:StartDebug_prompt(dict) if s:vertical " Assuming the source code window will get a signcolumn, use two more " columns for that, thus one less for the terminal window. - exe (&columns / 2 - 1) . "wincmd |" + exe $":{(&columns / 2 - 1)}wincmd |" endif let gdb_args = get(a:dict, 'gdb_args', []) @@ -465,14 +467,14 @@ func s:StartDebug_prompt(dict) " Adding arguments requested by the user let gdb_cmd += gdb_args - " call ch_log('executing "' . join(gdb_cmd) . '"') + " call ch_log($'executing "{join(gdb_cmd)}"') let s:gdbjob = jobstart(gdb_cmd, { \ 'on_exit': function('s:EndPromptDebug'), \ 'on_stdout': function('s:JobOutCallback', {'last_line': '', 'real_cb': function('s:GdbOutCallback')}), \ }) if s:gdbjob == 0 call s:Echoerr('Invalid argument (or job table is full) while starting gdb job') - exe 'bwipe! ' . s:ptybuf + exe $'bwipe! {s:ptybufnr}' return elseif s:gdbjob == -1 call s:Echoerr('Failed to start the gdb job') @@ -481,7 +483,7 @@ func s:StartDebug_prompt(dict) endif exe $'au BufUnload <buffer={s:promptbuf}> ++once call jobstop(s:gdbjob)' - let s:ptybuf = 0 + let s:ptybufnr = 0 if has('win32') " MS-Windows: run in a new console window for maximum compatibility call s:SendCommand('set new-console on') @@ -498,26 +500,26 @@ func s:StartDebug_prompt(dict) return endif let pty_job_info = nvim_get_chan_info(s:pty_job_id) - let s:ptybuf = pty_job_info['buffer'] + let s:ptybufnr = pty_job_info['buffer'] let pty = pty_job_info['pty'] let s:ptywin = win_getid() - call s:SendCommand('tty ' . pty) + call s:SendCommand($'tty {pty}') " Since GDB runs in a prompt window, the environment has not been set to " match a terminal window, need to do that now. call s:SendCommand('set env TERM = xterm-color') - call s:SendCommand('set env ROWS = ' . winheight(s:ptywin)) - call s:SendCommand('set env LINES = ' . winheight(s:ptywin)) - call s:SendCommand('set env COLUMNS = ' . winwidth(s:ptywin)) - call s:SendCommand('set env COLORS = ' . &t_Co) - call s:SendCommand('set env VIM_TERMINAL = ' . v:version) + call s:SendCommand($'set env ROWS = {winheight(s:ptywin)}') + call s:SendCommand($'set env LINES = {winheight(s:ptywin)}') + call s:SendCommand($'set env COLUMNS = {winwidth(s:ptywin)}') + call s:SendCommand($'set env COLORS = {&t_Co}') + call s:SendCommand($'set env VIM_TERMINAL = {v:version}') endif call s:SendCommand('set print pretty on') call s:SendCommand('set breakpoint pending on') " Set arguments to be run - if len(proc_args) - call s:SendCommand('set args ' . join(proc_args)) + if !empty(proc_args) + call s:SendCommand($'set args {join(proc_args)}') endif call s:StartDebugCommon(a:dict) @@ -563,18 +565,18 @@ endfunc " Send a command to gdb. "cmd" is the string without line terminator. func s:SendCommand(cmd) - "call ch_log('sending to gdb: ' . a:cmd) + " call ch_log($'sending to gdb: {a:cmd}') if s:way == 'prompt' - call chansend(s:gdbjob, a:cmd . "\n") + call chansend(s:gdbjob, $"{a:cmd}\n") else - call chansend(s:comm_job_id, a:cmd . "\r") + call chansend(s:comm_job_id, $"{a:cmd}\r") endif endfunc " This is global so that a user can create their mappings with this. func TermDebugSendCommand(cmd) if s:way == 'prompt' - call chansend(s:gdbjob, a:cmd . "\n") + call chansend(s:gdbjob, $"{a:cmd}\n") else let do_continue = 0 if !s:stopped @@ -589,7 +591,7 @@ func TermDebugSendCommand(cmd) sleep 10m endif " TODO: should we prepend CTRL-U to clear the command? - call chansend(s:gdb_job_id, a:cmd . "\r") + call chansend(s:gdb_job_id, $"{a:cmd}\r") if do_continue Continue endif @@ -602,11 +604,11 @@ endfunc func s:SendResumingCommand(cmd) if s:stopped " reset s:stopped here, it may take a bit of time before we get a response - let s:stopped = 0 + let s:stopped = v:false " call ch_log('assume that program is running after this command') call s:SendCommand(a:cmd) " else - " call ch_log('dropping command, program is running: ' . a:cmd) + " call ch_log($'dropping command, program is running: {a:cmd}') endif endfunc @@ -651,7 +653,7 @@ endfunc " Function called when gdb outputs text. func s:GdbOutCallback(job_id, msgs, event) - "call ch_log('received from gdb: ' . a:text) + " call ch_log($'received from gdb: {a:text}') let comm_msgs = [] let lines = [] @@ -710,7 +712,7 @@ endfunc " - change \\ to \ func s:DecodeMessage(quotedText, literal) if a:quotedText[0] != '"' - call s:Echoerr('DecodeMessage(): missing quote in ' . a:quotedText) + call s:Echoerr($'DecodeMessage(): missing quote in {a:quotedText}') return endif let msg = a:quotedText @@ -776,23 +778,23 @@ endfunc func s:EndDebugCommon() let curwinid = win_getid() - if exists('s:ptybuf') && s:ptybuf - exe 'bwipe! ' . s:ptybuf + if exists('s:ptybufnr') && s:ptybufnr + exe $'bwipe! {s:ptybufnr}' endif - if s:asmbuf > 0 && bufexists(s:asmbuf) - exe 'bwipe! ' . s:asmbuf + if s:asmbufnr > 0 && bufexists(s:asmbufnr) + exe $'bwipe! {s:asmbufnr}' endif - if s:varbuf > 0 && bufexists(s:varbuf) - exe 'bwipe! ' . s:varbuf + if s:varbufnr > 0 && bufexists(s:varbufnr) + exe $'bwipe! {s:varbufnr}' endif - let s:running = 0 + let s:running = v:false " Restore 'signcolumn' in all buffers for which it was set. call win_gotoid(s:sourcewin) let was_buf = bufnr() for bufnr in s:signcolumn_buflist if bufexists(bufnr) - exe bufnr .. "buf" + exe $":{bufnr}buf" if exists('b:save_signcolumn') let &signcolumn = b:save_signcolumn unlet b:save_signcolumn @@ -800,15 +802,15 @@ func s:EndDebugCommon() endif endfor if bufexists(was_buf) - exe was_buf .. "buf" + exe $":{was_buf}buf" endif call s:DeleteCommands() call win_gotoid(curwinid) - if s:save_columns > 0 - let &columns = s:save_columns + if s:saved_columns > 0 + let &columns = s:saved_columns endif if exists('#User#TermdebugStopPost') @@ -824,7 +826,7 @@ func s:EndPromptDebug(job_id, exit_code, event) endif if bufexists(s:promptbuf) - exe 'bwipe! ' . s:promptbuf + exe $'bwipe! {s:promptbuf}' endif call s:EndDebugCommon() @@ -853,7 +855,7 @@ func s:HandleDisasmMsg(msg) set nomodified set filetype=asm - let lnum = search('^' . s:asm_addr) + let lnum = search($'^{s:asm_addr}') if lnum != 0 call sign_unplace('TermDebug', #{id: s:asm_id}) call sign_place(s:asm_id, 'TermDebug', 'debugPC', '%', #{lnum: lnum}) @@ -915,11 +917,8 @@ func s:HandleVariablesMsg(msg) silent! %delete _ let spaceBuffer = 20 - call setline(1, 'Type' . - \ repeat(' ', 16) . - \ 'Name' . - \ repeat(' ', 16) . - \ 'Value') + let spaces = repeat(' ', 16) + call setline(1, $'Type{spaces}Name{spaces}Value') let cnt = 1 let capture = '{name=".\{-}",\%(arg=".\{-}",\)\{0,1\}type=".\{-}"\%(,value=".\{-}"\)\{0,1\}}' let varinfo = matchstr(a:msg, capture, 0, cnt) @@ -1027,8 +1026,8 @@ func s:InstallCommands() let map = g:termdebug_map_K endif if map - let s:k_map_saved = maparg('K', 'n', 0, 1) - if !empty(s:k_map_saved) && !s:k_map_saved.buffer || empty(s:k_map_saved) + let s:saved_K_map = maparg('K', 'n', 0, 1) + if !empty(s:saved_K_map) && !s:saved_K_map.buffer || empty(s:saved_K_map) nnoremap K :Evaluate<CR> endif endif @@ -1038,8 +1037,8 @@ func s:InstallCommands() let map = get(g:termdebug_config, 'map_plus', 1) endif if map - let s:plus_map_saved = maparg('+', 'n', 0, 1) - if !empty(s:plus_map_saved) && !s:plus_map_saved.buffer || empty(s:plus_map_saved) + let s:saved_plus_map = maparg('+', 'n', 0, 1) + if !empty(s:saved_plus_map) && !s:saved_plus_map.buffer || empty(s:saved_plus_map) nnoremap <expr> + $'<Cmd>{v:count1}Up<CR>' endif endif @@ -1049,8 +1048,8 @@ func s:InstallCommands() let map = get(g:termdebug_config, 'map_minus', 1) endif if map - let s:minus_map_saved = maparg('-', 'n', 0, 1) - if !empty(s:minus_map_saved) && !s:minus_map_saved.buffer || empty(s:minus_map_saved) + let s:saved_minus_map = maparg('-', 'n', 0, 1) + if !empty(s:saved_minus_map) && !s:saved_minus_map.buffer || empty(s:saved_minus_map) nnoremap <expr> - $'<Cmd>{v:count1}Down<CR>' endif endif @@ -1118,32 +1117,32 @@ func s:DeleteCommands() delcommand Var delcommand Winbar - if exists('s:k_map_saved') - if !empty(s:k_map_saved) && !s:k_map_saved.buffer + if exists('s:saved_K_map') + if !empty(s:saved_K_map) && !s:saved_K_map.buffer nunmap K - call mapset(s:k_map_saved) - elseif empty(s:k_map_saved) + call mapset(s:saved_K_map) + elseif empty(s:saved_K_map) nunmap K endif - unlet s:k_map_saved + unlet s:saved_K_map endif - if exists('s:plus_map_saved') - if !empty(s:plus_map_saved) && !s:plus_map_saved.buffer + if exists('s:saved_plus_map') + if !empty(s:saved_plus_map) && !s:saved_plus_map.buffer nunmap + - call mapset(s:plus_map_saved) - elseif empty(s:plus_map_saved) + call mapset(s:saved_plus_map) + elseif empty(s:saved_plus_map) nunmap + endif - unlet s:plus_map_saved + unlet s:saved_plus_map endif - if exists('s:minus_map_saved') - if !empty(s:minus_map_saved) && !s:minus_map_saved.buffer + if exists('s:saved_minus_map') + if !empty(s:saved_minus_map) && !s:saved_minus_map.buffer nunmap - - call mapset(s:minus_map_saved) - elseif empty(s:minus_map_saved) + call mapset(s:saved_minus_map) + elseif empty(s:saved_minus_map) nunmap - endif - unlet s:minus_map_saved + unlet s:saved_minus_map endif if has('menu') @@ -1182,16 +1181,21 @@ func s:DeleteCommands() let s:BreakpointSigns = [] endfunc +func s:QuoteArg(x) + " Find all the occurrences of " and \ and escape them and double quote + " the resulting string. + return printf('"%s"', a:x->substitute('[\\"]', '\\&', 'g')) +endfunc + " :Until - Execute until past a specified position or current line func s:Until(at) if s:stopped " reset s:stopped here, it may take a bit of time before we get a response - let s:stopped = 0 + let s:stopped = v:false " call ch_log('assume that program is running after this command') " Use the fname:lnum format - let at = empty(a:at) ? - \ fnameescape(expand('%:p')) . ':' . line('.') : a:at - call s:SendCommand('-exec-until ' . at) + let at = empty(a:at) ? s:QuoteArg($"{expand('%:p')}:{line('.')}") : a:at + call s:SendCommand($'-exec-until {at}') " else " call ch_log('dropping command, program is running: exec-until') endif @@ -1209,12 +1213,11 @@ func s:SetBreakpoint(at, tbreak=v:false) endif " Use the fname:lnum format, older gdb can't handle --source. - let at = empty(a:at) ? - \ fnameescape(expand('%:p')) . ':' . line('.') : a:at + let at = empty(a:at) ? s:QuoteArg($"{expand('%:p')}:{line('.')}") : a:at if a:tbreak - let cmd = '-break-insert -t ' . at + let cmd = $'-break-insert -t {at}' else - let cmd = '-break-insert ' . at + let cmd = $'-break-insert {at}' endif call s:SendCommand(cmd) if do_continue @@ -1233,7 +1236,7 @@ func s:ClearBreakpoint() for id in s:breakpoint_locations[bploc] if has_key(s:breakpoints, id) " Assume this always works, the reply is simply "^done". - call s:SendCommand('-break-delete ' . id) + call s:SendCommand($'-break-delete {id}') for subid in keys(s:breakpoints[id]) call sign_unplace('TermDebug', \ #{id: s:Breakpoint2SignNumber(id, subid)}) @@ -1250,18 +1253,18 @@ func s:ClearBreakpoint() if empty(s:breakpoint_locations[bploc]) unlet s:breakpoint_locations[bploc] endif - echomsg 'Breakpoint ' . id . ' cleared from line ' . lnum . '.' + echomsg $'Breakpoint {nr} cleared from line {lnum}.' else - call s:Echoerr('Internal error trying to remove breakpoint at line ' . lnum . '!') + call s:Echoerr($'Internal error trying to remove breakpoint at line {lnum}!') endif else - echomsg 'No breakpoint to remove at line ' . lnum . '.' + echomsg $'No breakpoint to remove at line {lnum}.' endif endfunc func s:Run(args) if a:args != '' - call s:SendResumingCommand('-exec-arguments ' . a:args) + call s:SendResumingCommand($'-exec-arguments {a:args}') endif call s:SendResumingCommand('-exec-run') endfunc @@ -1275,13 +1278,13 @@ func s:Frame(arg) " already parsed and allows for more formats if a:arg =~ '^\d\+$' || a:arg == '' " specify frame by number - call s:SendCommand('-interpreter-exec mi "frame ' . a:arg .'"') + call s:SendCommand($'-interpreter-exec mi "frame {a:arg}"') elseif a:arg =~ '^0x[0-9a-fA-F]\+$' " specify frame by stack address - call s:SendCommand('-interpreter-exec mi "frame address ' . a:arg .'"') + call s:SendCommand($'-interpreter-exec mi "frame address {a:arg}"') else " specify frame by function name - call s:SendCommand('-interpreter-exec mi "frame function ' . a:arg .'"') + call s:SendCommand($'-interpreter-exec mi "frame function {a:arg}"') endif endfunc @@ -1307,10 +1310,10 @@ func s:SendEval(expr) endif " encoding expression to prevent bad errors - let expr = a:expr - let expr = substitute(expr, '\\', '\\\\', 'g') - let expr = substitute(expr, '"', '\\"', 'g') - call s:SendCommand('-data-evaluate-expression "' . expr . '"') + let expr_escaped = a:expr + \ ->substitute('\\', '\\\\', 'g') + \ ->substitute('"', '\\"', 'g') + call s:SendCommand($'-data-evaluate-expression "{expr_escaped}"') let s:evalexpr = exprLHS endfunc @@ -1322,9 +1325,9 @@ func s:Evaluate(range, arg) return endif let expr = s:GetEvaluationExpression(a:range, a:arg) - let s:evalFromBalloonExpr = 1 + let s:evalFromBalloonExpr = v:true let s:evalFromBalloonExprResult = '' - let s:ignoreEvalError = 0 + let s:ignoreEvalError = v:false call s:SendEval(expr) endfunc @@ -1343,12 +1346,12 @@ func s:GetEvaluationExpression(range, arg) let expr = s:CleanupExpr(@v) call setpos('.', pos) call setreg('v', reg, regt) - let s:evalFromBalloonExpr = 1 + let s:evalFromBalloonExpr = v:true else " no evaluation provided: get from C-expression under cursor " TODO: allow filetype specific lookup #9057 let expr = expand('<cexpr>') - let s:evalFromBalloonExpr = 1 + let s:evalFromBalloonExpr = v:true endif return expr endfunc @@ -1376,8 +1379,8 @@ func s:CleanupExpr(expr) return expr endfunc -let s:ignoreEvalError = 0 -let s:evalFromBalloonExpr = 0 +let s:ignoreEvalError = v:false +let s:evalFromBalloonExpr = v:false let s:evalFromBalloonExprResult = '' let s:eval_float_win_id = -1 @@ -1400,9 +1403,9 @@ func s:HandleEvaluate(msg) \ ->substitute('
', '\1', '') if s:evalFromBalloonExpr if s:evalFromBalloonExprResult == '' - let s:evalFromBalloonExprResult = s:evalexpr . ': ' . value + let s:evalFromBalloonExprResult = $'{s:evalexpr}: {value}' else - let s:evalFromBalloonExprResult .= ' = ' . value + let s:evalFromBalloonExprResult ..= $' = {value}' endif " NEOVIM: " - Result pretty-printing is not implemented. Vim prettifies the result @@ -1414,13 +1417,13 @@ func s:HandleEvaluate(msg) " first message. let s:eval_float_win_id = luaeval('select(2, vim.lsp.util.open_floating_preview(_A))', [s:evalFromBalloonExprResult]) else - echomsg '"' . s:evalexpr . '": ' . value + echomsg $'"{s:evalexpr}": {value}' endif if s:evalexpr[0] != '*' && value =~ '^0x' && value != '0x0' && value !~ '"$' " Looks like a pointer, also display what it points to. - let s:ignoreEvalError = 1 - call s:SendEval('*' . s:evalexpr) + let s:ignoreEvalError = v:true + call s:SendEval($'*{s:evalexpr}') endif endfunc @@ -1428,8 +1431,8 @@ endfunc func s:HandleError(msg) if s:ignoreEvalError " Result of s:SendEval() failed, ignore. - let s:ignoreEvalError = 0 - let s:evalFromBalloonExpr = 0 + let s:ignoreEvalError = v:false + let s:evalFromBalloonExpr = v:false return endif let msgVal = substitute(a:msg, '.*msg="\(.*\)"', '\1', '') @@ -1471,7 +1474,7 @@ func s:GotoAsmwinOrCreateIt() " 60 is approx spaceBuffer * 3 if winwidth(0) > (78 + 60) let mdf = 'vert' - exe mdf .. ' ' .. 60 .. 'new' + exe $'{mdf} :60new' else exe 'rightbelow new' endif @@ -1489,23 +1492,23 @@ func s:GotoAsmwinOrCreateIt() setlocal signcolumn=no setlocal modifiable - if s:asmbuf > 0 && bufexists(s:asmbuf) - exe 'buffer' . s:asmbuf + if s:asmbufnr > 0 && bufexists(s:asmbufnr) + exe $'buffer {s:asmbufnr}' elseif empty(glob('Termdebug-asm-listing')) silent file Termdebug-asm-listing - let s:asmbuf = bufnr('Termdebug-asm-listing') + let s:asmbufnr = bufnr('Termdebug-asm-listing') else call s:Echoerr("You have a file/folder named 'Termdebug-asm-listing'. \ Please exit and rename it because Termdebug may not work as expected.") endif if mdf != 'vert' && s:GetDisasmWindowHeight() > 0 - exe 'resize ' .. s:GetDisasmWindowHeight() + exe $'resize {s:GetDisasmWindowHeight()}' endif endif if s:asm_addr != '' - let lnum = search('^' . s:asm_addr) + let lnum = search($'^{s:asm_addr}') if lnum == 0 if s:stopped call s:SendCommand('disassemble $pc') @@ -1544,7 +1547,7 @@ func s:GotoVariableswinOrCreateIt() " 60 is approx spaceBuffer * 3 if winwidth(0) > (78 + 60) let mdf = 'vert' - exe mdf .. ' ' .. 60 .. 'new' + exe $'{mdf} :60new' else exe 'rightbelow new' endif @@ -1561,18 +1564,18 @@ func s:GotoVariableswinOrCreateIt() setlocal signcolumn=no setlocal modifiable - if s:varbuf > 0 && bufexists(s:varbuf) - exe 'buffer' . s:varbuf + if s:varbufnr > 0 && bufexists(s:varbufnr) + exe $'buffer {s:varbufnr}' elseif empty(glob('Termdebug-variables-listing')) silent file Termdebug-variables-listing - let s:varbuf = bufnr('Termdebug-variables-listing') + let s:varbufnr = bufnr('Termdebug-variables-listing') else call s:Echoerr("You have a file/folder named 'Termdebug-variables-listing'. \ Please exit and rename it because Termdebug may not work as expected.") endif if mdf != 'vert' && s:GetVariablesWindowHeight() > 0 - exe 'resize ' .. s:GetVariablesWindowHeight() + exe $'resize {s:GetVariablesWindowHeight()}' endif endif @@ -1588,14 +1591,14 @@ func s:HandleCursor(msg) if a:msg =~ '^\*stopped' "call ch_log('program stopped') - let s:stopped = 1 + let s:stopped = v:true if a:msg =~ '^\*stopped,reason="exited-normally"' - let s:running = 0 + let s:running = v:false endif elseif a:msg =~ '^\*running' "call ch_log('program running') - let s:stopped = 0 - let s:running = 1 + let s:stopped = v:false + let s:running = v:true endif if a:msg =~ 'fullname=' @@ -1611,7 +1614,7 @@ func s:HandleCursor(msg) let curwinid = win_getid() if win_gotoid(s:asmwin) - let lnum = search('^' . s:asm_addr) + let lnum = search($'^{s:asm_addr}') if lnum == 0 call s:SendCommand('disassemble $pc') else @@ -1633,7 +1636,7 @@ func s:HandleCursor(msg) if lnum =~ '^[0-9]*$' call s:GotoSourcewinOrCreateIt() if expand('%:p') != fnamemodify(fname, ':p') - echomsg 'different fname: "' .. expand('%:p') .. '" vs "' .. fnamemodify(fname, ':p') .. '"' + echomsg $"different fname: '{expand('%:p')}' vs '{fnamemodify(fname, ':p')}'" augroup Termdebug " Always open a file read-only instead of showing the ATTENTION " prompt, since it is unlikely we want to edit the file. @@ -1645,17 +1648,17 @@ func s:HandleCursor(msg) augroup END if &modified " TODO: find existing window - exe 'split ' . fnameescape(fname) + exe $'split {fnameescape(fname)}' let s:sourcewin = win_getid() call s:InstallWinbar(0) else - exe 'edit ' . fnameescape(fname) + exe $'edit {fnameescape(fname)}' endif augroup Termdebug au! SwapExists augroup END endif - exe lnum + exe $":{lnum}" normal! zv call sign_unplace('TermDebug', #{id: s:pc_id}) call sign_place(s:pc_id, 'TermDebug', 'debugPC', fname, @@ -1694,7 +1697,7 @@ func s:CreateBreakpoint(id, subid, enabled) let label = 'F+' endif endif - call sign_define('debugBreakpoint' .. nr, + call sign_define($'debugBreakpoint{nr}', \ #{text: slice(label, 0, 2), \ texthl: hiName}) endif @@ -1712,7 +1715,7 @@ func s:HandleNewBreakpoint(msg, modifiedFlag) if a:msg =~ 'pending=' let nr = substitute(a:msg, '.*number=\"\([0-9.]*\)\".*', '\1', '') let target = substitute(a:msg, '.*pending=\"\([^"]*\)\".*', '\1', '') - echomsg 'Breakpoint ' . nr . ' (' . target . ') pending.' + echomsg $'Breakpoint {nr} ({target}) pending.' endif return endif @@ -1757,9 +1760,9 @@ func s:HandleNewBreakpoint(msg, modifiedFlag) if bufloaded(fname) call s:PlaceSign(id, subid, entry) - let posMsg = ' at line ' . lnum . '.' + let posMsg = $' at line {lnum}.' else - let posMsg = ' in ' . fname . ' at line ' . lnum . '.' + let posMsg = $' in {fname} at line {lnum}.' endif if !a:modifiedFlag let actionTaken = 'created' @@ -1768,14 +1771,14 @@ func s:HandleNewBreakpoint(msg, modifiedFlag) else let actionTaken = 'enabled' endif - echomsg 'Breakpoint ' . nr . ' ' . actionTaken . posMsg + echom $'Breakpoint {nr} {actionTaken}{posMsg}' endfor endfunc func s:PlaceSign(id, subid, entry) let nr = printf('%d.%d', a:id, a:subid) call sign_place(s:Breakpoint2SignNumber(a:id, a:subid), 'TermDebug', - \ 'debugBreakpoint' .. nr, a:entry['fname'], + \ $'debugBreakpoint{nr}', a:entry['fname'], \ #{lnum: a:entry['lnum'], priority: 110}) let a:entry['placed'] = 1 endfunc @@ -1796,7 +1799,7 @@ func s:HandleBreakpointDelete(msg) endif endfor unlet s:breakpoints[id] - echomsg 'Breakpoint ' . id . ' cleared.' + echomsg $'Breakpoint {id} cleared.' endif endfunc @@ -1808,7 +1811,7 @@ func s:HandleProgramRun(msg) return endif let s:pid = nr - "call ch_log('Detected process ID: ' . s:pid) + " call ch_log($'Detected process ID: {s:pid}') endfunc " Handle a BufRead autocommand event: place any signs. diff --git a/runtime/plugin/matchparen.vim b/runtime/plugin/matchparen.vim index 6c061c9fb8..2899612dce 100644 --- a/runtime/plugin/matchparen.vim +++ b/runtime/plugin/matchparen.vim @@ -60,12 +60,8 @@ func s:Highlight_Matching_Pair() let before = 0 let text = getline(c_lnum) - let matches = matchlist(text, '\(.\)\=\%'.c_col.'c\(.\=\)') - if empty(matches) - let [c_before, c] = ['', ''] - else - let [c_before, c] = matches[1:2] - endif + let c_before = text->strpart(0, c_col - 1)->slice(-1) + let c = text->strpart(c_col - 1)->slice(0, 1) let plist = split(&matchpairs, '.\zs[:,]') let i = index(plist, c) if i < 0 diff --git a/runtime/plugin/tohtml.lua b/runtime/plugin/tohtml.lua index 79f2794a40..0cb4562938 100644 --- a/runtime/plugin/tohtml.lua +++ b/runtime/plugin/tohtml.lua @@ -5,8 +5,8 @@ vim.g.loaded_2html_plugin = true vim.api.nvim_create_user_command('TOhtml', function(args) local outfile = args.args ~= '' and args.args or vim.fn.tempname() .. '.html' - local html = require('tohtml').tohtml() + local html = require('tohtml').tohtml(0, { range = { args.line1, args.line2 } }) vim.fn.writefile(html, outfile) vim.cmd.split(outfile) vim.bo.filetype = 'html' -end, { bar = true, nargs = '?' }) +end, { bar = true, nargs = '?', range = '%' }) diff --git a/runtime/queries/bash/folds.scm b/runtime/queries/bash/folds.scm deleted file mode 100644 index 766dbe598b..0000000000 --- a/runtime/queries/bash/folds.scm +++ /dev/null @@ -1,9 +0,0 @@ -[ - (function_definition) - (if_statement) - (case_statement) - (for_statement) - (while_statement) - (c_style_for_statement) - (heredoc_redirect) -] @fold diff --git a/runtime/queries/bash/highlights.scm b/runtime/queries/bash/highlights.scm deleted file mode 100644 index feb0e038ea..0000000000 --- a/runtime/queries/bash/highlights.scm +++ /dev/null @@ -1,232 +0,0 @@ -[ - "(" - ")" - "{" - "}" - "[" - "]" - "[[" - "]]" - "((" - "))" -] @punctuation.bracket - -[ - ";" - ";;" - ";&" - ";;&" - "&" -] @punctuation.delimiter - -[ - ">" - ">>" - "<" - "<<" - "&&" - "|" - "|&" - "||" - "=" - "+=" - "=~" - "==" - "!=" - "&>" - "&>>" - "<&" - ">&" - ">|" - "<&-" - ">&-" - "<<-" - "<<<" - ".." - "!" -] @operator - -; Do *not* spell check strings since they typically have some sort of -; interpolation in them, or, are typically used for things like filenames, URLs, -; flags and file content. -[ - (string) - (raw_string) - (ansi_c_string) - (heredoc_body) -] @string - -[ - (heredoc_start) - (heredoc_end) -] @label - -(variable_assignment - (word) @string) - -(command - argument: "$" @string) ; bare dollar - -(concatenation - (word) @string) - -[ - "if" - "then" - "else" - "elif" - "fi" - "case" - "in" - "esac" -] @keyword.conditional - -[ - "for" - "do" - "done" - "select" - "until" - "while" -] @keyword.repeat - -[ - "declare" - "typeset" - "export" - "readonly" - "local" - "unset" - "unsetenv" -] @keyword - -"function" @keyword.function - -(special_variable_name) @constant - -; trap -l -((word) @constant.builtin - (#any-of? @constant.builtin - "SIGHUP" "SIGINT" "SIGQUIT" "SIGILL" "SIGTRAP" "SIGABRT" "SIGBUS" "SIGFPE" "SIGKILL" "SIGUSR1" - "SIGSEGV" "SIGUSR2" "SIGPIPE" "SIGALRM" "SIGTERM" "SIGSTKFLT" "SIGCHLD" "SIGCONT" "SIGSTOP" - "SIGTSTP" "SIGTTIN" "SIGTTOU" "SIGURG" "SIGXCPU" "SIGXFSZ" "SIGVTALRM" "SIGPROF" "SIGWINCH" - "SIGIO" "SIGPWR" "SIGSYS" "SIGRTMIN" "SIGRTMIN+1" "SIGRTMIN+2" "SIGRTMIN+3" "SIGRTMIN+4" - "SIGRTMIN+5" "SIGRTMIN+6" "SIGRTMIN+7" "SIGRTMIN+8" "SIGRTMIN+9" "SIGRTMIN+10" "SIGRTMIN+11" - "SIGRTMIN+12" "SIGRTMIN+13" "SIGRTMIN+14" "SIGRTMIN+15" "SIGRTMAX-14" "SIGRTMAX-13" - "SIGRTMAX-12" "SIGRTMAX-11" "SIGRTMAX-10" "SIGRTMAX-9" "SIGRTMAX-8" "SIGRTMAX-7" "SIGRTMAX-6" - "SIGRTMAX-5" "SIGRTMAX-4" "SIGRTMAX-3" "SIGRTMAX-2" "SIGRTMAX-1" "SIGRTMAX")) - -((word) @boolean - (#any-of? @boolean "true" "false")) - -(comment) @comment @spell - -(test_operator) @operator - -(command_substitution - "$(" @punctuation.special - ")" @punctuation.special) - -(process_substitution - [ - "<(" - ">(" - ] @punctuation.special - ")" @punctuation.special) - -(arithmetic_expansion - [ - "$((" - "((" - ] @punctuation.special - "))" @punctuation.special) - -(arithmetic_expansion - "," @punctuation.delimiter) - -(ternary_expression - [ - "?" - ":" - ] @keyword.conditional.ternary) - -(binary_expression - operator: _ @operator) - -(unary_expression - operator: _ @operator) - -(postfix_expression - operator: _ @operator) - -(function_definition - name: (word) @function) - -(command_name - (word) @function.call) - -(command_name - (word) @function.builtin - (#any-of? @function.builtin - "alias" "bg" "bind" "break" "builtin" "caller" "cd" "command" "compgen" "complete" "compopt" - "continue" "coproc" "dirs" "disown" "echo" "enable" "eval" "exec" "exit" "fc" "fg" "getopts" - "hash" "help" "history" "jobs" "kill" "let" "logout" "mapfile" "popd" "printf" "pushd" "pwd" - "read" "readarray" "return" "set" "shift" "shopt" "source" "suspend" "test" "time" "times" - "trap" "type" "typeset" "ulimit" "umask" "unalias" "wait")) - -(command - argument: [ - (word) @variable.parameter - (concatenation - (word) @variable.parameter) - ]) - -(number) @number - -((word) @number - (#lua-match? @number "^[0-9]+$")) - -(file_redirect - destination: (word) @variable.parameter) - -(file_descriptor) @operator - -(simple_expansion - "$" @punctuation.special) @none - -(expansion - "${" @punctuation.special - "}" @punctuation.special) @none - -(expansion - operator: _ @punctuation.special) - -(expansion - "@" - . - operator: _ @character.special) - -((expansion - (subscript - index: (word) @character.special)) - (#any-of? @character.special "@" "*")) - -"``" @punctuation.special - -(variable_name) @variable - -((variable_name) @constant - (#lua-match? @constant "^[A-Z][A-Z_0-9]*$")) - -(case_item - value: (word) @variable.parameter) - -[ - (regex) - (extglob_pattern) -] @string.regexp - -((program - . - (comment) @keyword.directive @nospell) - (#lua-match? @keyword.directive "^#!/")) diff --git a/runtime/queries/bash/injections.scm b/runtime/queries/bash/injections.scm deleted file mode 100644 index 427b414958..0000000000 --- a/runtime/queries/bash/injections.scm +++ /dev/null @@ -1,3 +0,0 @@ -(heredoc_redirect - (heredoc_body) @injection.content - (heredoc_end) @injection.language) diff --git a/runtime/queries/c/highlights.scm b/runtime/queries/c/highlights.scm index 170937c8f8..eba272d5c9 100644 --- a/runtime/queries/c/highlights.scm +++ b/runtime/queries/c/highlights.scm @@ -1,6 +1,6 @@ ; Lower priority to prefer @variable.parameter when identifier appears in parameter_declaration. ((identifier) @variable - (#set! "priority" 95)) + (#set! priority 95)) (preproc_def (preproc_arg) @variable) diff --git a/runtime/queries/lua/highlights.scm b/runtime/queries/lua/highlights.scm index 0c8f07f290..01c280f2d5 100644 --- a/runtime/queries/lua/highlights.scm +++ b/runtime/queries/lua/highlights.scm @@ -162,7 +162,7 @@ ; Tables (field - name: (identifier) @variable.member) + name: (identifier) @property) (dot_index_expression field: (identifier) @variable.member) diff --git a/runtime/queries/markdown/highlights.scm b/runtime/queries/markdown/highlights.scm index 4b445e02f3..a12669ca2b 100644 --- a/runtime/queries/markdown/highlights.scm +++ b/runtime/queries/markdown/highlights.scm @@ -8,28 +8,22 @@ (setext_h2_underline) @markup.heading.2) (atx_heading - (atx_h1_marker) @markup.heading.1 - (inline) @markup.heading.1) + (atx_h1_marker)) @markup.heading.1 (atx_heading - (atx_h2_marker) @markup.heading.2 - (inline) @markup.heading.2) + (atx_h2_marker)) @markup.heading.2 (atx_heading - (atx_h3_marker) @markup.heading.3 - (inline) @markup.heading.3) + (atx_h3_marker)) @markup.heading.3 (atx_heading - (atx_h4_marker) @markup.heading.4 - (inline) @markup.heading.4) + (atx_h4_marker)) @markup.heading.4 (atx_heading - (atx_h5_marker) @markup.heading.5 - (inline) @markup.heading.5) + (atx_h5_marker)) @markup.heading.5 (atx_heading - (atx_h6_marker) @markup.heading.6 - (inline) @markup.heading.6) + (atx_h6_marker)) @markup.heading.6 (info_string) @label @@ -51,7 +45,7 @@ (indented_code_block) @markup.raw.block ((fenced_code_block) @markup.raw.block - (#set! "priority" 90)) + (#set! priority 90)) (fenced_code_block (fenced_code_block_delimiter) @markup.raw.block @@ -109,13 +103,13 @@ (task_list_marker_checked) @markup.list.checked ((block_quote) @markup.quote - (#set! "priority" 90)) + (#set! priority 90)) ([ (plus_metadata) (minus_metadata) ] @keyword.directive - (#set! "priority" 90)) + (#set! priority 90)) [ (block_continuation) diff --git a/runtime/queries/markdown_inline/highlights.scm b/runtime/queries/markdown_inline/highlights.scm index 233ab411cd..148ef0fad0 100644 --- a/runtime/queries/markdown_inline/highlights.scm +++ b/runtime/queries/markdown_inline/highlights.scm @@ -43,7 +43,12 @@ (inline_link (link_text) @_label (link_destination) @_url - (#set! @_label "url" @_url)) + (#set! @_label url @_url)) + +(image + (image_description) @_label + (link_destination) @_url + (#set! @_label url @_url)) ; Conceal image links (image @@ -85,12 +90,22 @@ [ (link_destination) (uri_autolink) + (email_autolink) ] @markup.link.url @nospell +((link_destination) @_url + (#set! @_url url @_url)) + +((uri_autolink) @_url + (#offset! @_url 0 1 0 -1) + (#set! @_url url @_url)) + +(entity_reference) @nospell + ; Replace common HTML entities. ((entity_reference) @character.special (#eq? @character.special " ") - (#set! conceal "")) + (#set! conceal " ")) ((entity_reference) @character.special (#eq? @character.special "<") diff --git a/runtime/queries/python/folds.scm b/runtime/queries/python/folds.scm deleted file mode 100644 index ecb9352d78..0000000000 --- a/runtime/queries/python/folds.scm +++ /dev/null @@ -1,28 +0,0 @@ -[ - (function_definition) - (class_definition) - (while_statement) - (for_statement) - (if_statement) - (with_statement) - (try_statement) - (match_statement) - (import_from_statement) - (parameters) - (argument_list) - (parenthesized_expression) - (generator_expression) - (list_comprehension) - (set_comprehension) - (dictionary_comprehension) - (tuple) - (list) - (set) - (dictionary) - (string) -] @fold - -[ - (import_statement) - (import_from_statement) -]+ @fold diff --git a/runtime/queries/python/highlights.scm b/runtime/queries/python/highlights.scm deleted file mode 100644 index 5e5a2a88de..0000000000 --- a/runtime/queries/python/highlights.scm +++ /dev/null @@ -1,457 +0,0 @@ -; From tree-sitter-python licensed under MIT License -; Copyright (c) 2016 Max Brunsfeld -; Variables -(identifier) @variable - -; Reset highlighting in f-string interpolations -(interpolation) @none - -; Identifier naming conventions -((identifier) @type - (#lua-match? @type "^[A-Z].*[a-z]")) - -((identifier) @constant - (#lua-match? @constant "^[A-Z][A-Z_0-9]*$")) - -((identifier) @constant.builtin - (#lua-match? @constant.builtin "^__[a-zA-Z0-9_]*__$")) - -((identifier) @constant.builtin - (#any-of? @constant.builtin - ; https://docs.python.org/3/library/constants.html - "NotImplemented" "Ellipsis" "quit" "exit" "copyright" "credits" "license")) - -"_" @constant.builtin ; match wildcard - -((attribute - attribute: (identifier) @variable.member) - (#lua-match? @variable.member "^[%l_].*$")) - -((assignment - left: (identifier) @type.definition - (type - (identifier) @_annotation)) - (#eq? @_annotation "TypeAlias")) - -((assignment - left: (identifier) @type.definition - right: (call - function: (identifier) @_func)) - (#any-of? @_func "TypeVar" "NewType")) - -; Function calls -(call - function: (identifier) @function.call) - -(call - function: (attribute - attribute: (identifier) @function.method.call)) - -((call - function: (identifier) @constructor) - (#lua-match? @constructor "^%u")) - -((call - function: (attribute - attribute: (identifier) @constructor)) - (#lua-match? @constructor "^%u")) - -; Decorators -((decorator - "@" @attribute) - (#set! "priority" 101)) - -(decorator - (identifier) @attribute) - -(decorator - (attribute - attribute: (identifier) @attribute)) - -(decorator - (call - (identifier) @attribute)) - -(decorator - (call - (attribute - attribute: (identifier) @attribute))) - -((decorator - (identifier) @attribute.builtin) - (#any-of? @attribute.builtin "classmethod" "property" "staticmethod")) - -; Builtin functions -((call - function: (identifier) @function.builtin) - (#any-of? @function.builtin - "abs" "all" "any" "ascii" "bin" "bool" "breakpoint" "bytearray" "bytes" "callable" "chr" - "classmethod" "compile" "complex" "delattr" "dict" "dir" "divmod" "enumerate" "eval" "exec" - "filter" "float" "format" "frozenset" "getattr" "globals" "hasattr" "hash" "help" "hex" "id" - "input" "int" "isinstance" "issubclass" "iter" "len" "list" "locals" "map" "max" "memoryview" - "min" "next" "object" "oct" "open" "ord" "pow" "print" "property" "range" "repr" "reversed" - "round" "set" "setattr" "slice" "sorted" "staticmethod" "str" "sum" "super" "tuple" "type" - "vars" "zip" "__import__")) - -; Function definitions -(function_definition - name: (identifier) @function) - -(type - (identifier) @type) - -(type - (subscript - (identifier) @type)) ; type subscript: Tuple[int] - -((call - function: (identifier) @_isinstance - arguments: (argument_list - (_) - (identifier) @type)) - (#eq? @_isinstance "isinstance")) - -; Normal parameters -(parameters - (identifier) @variable.parameter) - -; Lambda parameters -(lambda_parameters - (identifier) @variable.parameter) - -(lambda_parameters - (tuple_pattern - (identifier) @variable.parameter)) - -; Default parameters -(keyword_argument - name: (identifier) @variable.parameter) - -; Naming parameters on call-site -(default_parameter - name: (identifier) @variable.parameter) - -(typed_parameter - (identifier) @variable.parameter) - -(typed_default_parameter - name: (identifier) @variable.parameter) - -; Variadic parameters *args, **kwargs -(parameters - (list_splat_pattern ; *args - (identifier) @variable.parameter)) - -(parameters - (dictionary_splat_pattern ; **kwargs - (identifier) @variable.parameter)) - -; Typed variadic parameters -(parameters - (typed_parameter - (list_splat_pattern ; *args: type - (identifier) @variable.parameter))) - -(parameters - (typed_parameter - (dictionary_splat_pattern ; *kwargs: type - (identifier) @variable.parameter))) - -; Lambda parameters -(lambda_parameters - (list_splat_pattern - (identifier) @variable.parameter)) - -(lambda_parameters - (dictionary_splat_pattern - (identifier) @variable.parameter)) - -; Literals -(none) @constant.builtin - -[ - (true) - (false) -] @boolean - -((identifier) @variable.builtin - (#eq? @variable.builtin "self")) - -((identifier) @variable.builtin - (#eq? @variable.builtin "cls")) - -(integer) @number - -(float) @number.float - -(comment) @comment @spell - -((module - . - (comment) @keyword.directive @nospell) - (#lua-match? @keyword.directive "^#!/")) - -(string) @string - -[ - (escape_sequence) - (escape_interpolation) -] @string.escape - -; doc-strings -(module - . - (comment)* - . - (expression_statement - (string) @string.documentation)) - -(class_definition - body: (block - . - (expression_statement - (string) @string.documentation))) - -(function_definition - body: (block - . - (expression_statement - (string) @string.documentation))) - -(module - . - (comment)* - . - (expression_statement - (string - (string_content) @spell))) - -(class_definition - body: (block - . - (expression_statement - (string - (string_content) @spell)))) - -(function_definition - body: (block - . - (expression_statement - (string - (string_content) @spell)))) - -; Tokens -[ - "-" - "-=" - ":=" - "!=" - "*" - "**" - "**=" - "*=" - "/" - "//" - "//=" - "/=" - "&" - "&=" - "%" - "%=" - "^" - "^=" - "+" - "+=" - "<" - "<<" - "<<=" - "<=" - "<>" - "=" - "==" - ">" - ">=" - ">>" - ">>=" - "@" - "@=" - "|" - "|=" - "~" - "->" -] @operator - -; Keywords -[ - "and" - "in" - "is" - "not" - "or" - "is not" - "not in" - "del" -] @keyword.operator - -[ - "def" - "lambda" -] @keyword.function - -[ - "assert" - "exec" - "global" - "nonlocal" - "pass" - "print" - "with" - "as" -] @keyword - -[ - "type" - "class" -] @keyword.type - -[ - "async" - "await" -] @keyword.coroutine - -[ - "return" - "yield" -] @keyword.return - -(yield - "from" @keyword.return) - -(future_import_statement - "from" @keyword.import - "__future__" @constant.builtin) - -(import_from_statement - "from" @keyword.import) - -"import" @keyword.import - -(aliased_import - "as" @keyword.import) - -[ - "if" - "elif" - "else" - "match" - "case" -] @keyword.conditional - -[ - "for" - "while" - "break" - "continue" -] @keyword.repeat - -[ - "try" - "except" - "except*" - "raise" - "finally" -] @keyword.exception - -(raise_statement - "from" @keyword.exception) - -(try_statement - (else_clause - "else" @keyword.exception)) - -[ - "(" - ")" - "[" - "]" - "{" - "}" -] @punctuation.bracket - -(interpolation - "{" @punctuation.special - "}" @punctuation.special) - -(type_conversion) @function.macro - -[ - "," - "." - ":" - ";" - (ellipsis) -] @punctuation.delimiter - -; Class definitions -(class_definition - name: (identifier) @type) - -(class_definition - body: (block - (function_definition - name: (identifier) @function.method))) - -(class_definition - superclasses: (argument_list - (identifier) @type)) - -((class_definition - body: (block - (expression_statement - (assignment - left: (identifier) @variable.member)))) - (#lua-match? @variable.member "^[%l_].*$")) - -((class_definition - body: (block - (expression_statement - (assignment - left: (_ - (identifier) @variable.member))))) - (#lua-match? @variable.member "^[%l_].*$")) - -((class_definition - (block - (function_definition - name: (identifier) @constructor))) - (#any-of? @constructor "__new__" "__init__")) - -((identifier) @type.builtin - (#any-of? @type.builtin - ; https://docs.python.org/3/library/exceptions.html - "BaseException" "Exception" "ArithmeticError" "BufferError" "LookupError" "AssertionError" - "AttributeError" "EOFError" "FloatingPointError" "GeneratorExit" "ImportError" - "ModuleNotFoundError" "IndexError" "KeyError" "KeyboardInterrupt" "MemoryError" "NameError" - "NotImplementedError" "OSError" "OverflowError" "RecursionError" "ReferenceError" "RuntimeError" - "StopIteration" "StopAsyncIteration" "SyntaxError" "IndentationError" "TabError" "SystemError" - "SystemExit" "TypeError" "UnboundLocalError" "UnicodeError" "UnicodeEncodeError" - "UnicodeDecodeError" "UnicodeTranslateError" "ValueError" "ZeroDivisionError" "EnvironmentError" - "IOError" "WindowsError" "BlockingIOError" "ChildProcessError" "ConnectionError" - "BrokenPipeError" "ConnectionAbortedError" "ConnectionRefusedError" "ConnectionResetError" - "FileExistsError" "FileNotFoundError" "InterruptedError" "IsADirectoryError" - "NotADirectoryError" "PermissionError" "ProcessLookupError" "TimeoutError" "Warning" - "UserWarning" "DeprecationWarning" "PendingDeprecationWarning" "SyntaxWarning" "RuntimeWarning" - "FutureWarning" "ImportWarning" "UnicodeWarning" "BytesWarning" "ResourceWarning" - ; https://docs.python.org/3/library/stdtypes.html - "bool" "int" "float" "complex" "list" "tuple" "range" "str" "bytes" "bytearray" "memoryview" - "set" "frozenset" "dict" "type" "object")) - -; Regex from the `re` module -(call - function: (attribute - object: (identifier) @_re) - arguments: (argument_list - . - (string - (string_content) @string.regexp)) - (#eq? @_re "re")) diff --git a/runtime/queries/query/highlights.scm b/runtime/queries/query/highlights.scm index 210d03dc33..e459b44602 100644 --- a/runtime/queries/query/highlights.scm +++ b/runtime/queries/query/highlights.scm @@ -5,9 +5,6 @@ (capture (identifier) @type) -(anonymous_node - (identifier) @string) - (predicate name: (identifier) @function.call) @@ -15,7 +12,7 @@ name: (identifier) @variable) (field_definition - name: (identifier) @property) + name: (identifier) @variable.member) (negated_field "!" @operator @@ -36,7 +33,10 @@ ")" ] @punctuation.bracket -":" @punctuation.delimiter +[ + ":" + "/" +] @punctuation.delimiter [ "@" @@ -69,6 +69,15 @@ ((predicate name: (identifier) @_name parameters: (parameters + . + (capture)? + . + (identifier) @property)) + (#eq? @_name "set")) + +((predicate + name: (identifier) @_name + parameters: (parameters (string "\"" @string "\"" @string) @string.regexp)) diff --git a/runtime/queries/vimdoc/highlights.scm b/runtime/queries/vimdoc/highlights.scm index 70a3a2f206..1f809c2f60 100644 --- a/runtime/queries/vimdoc/highlights.scm +++ b/runtime/queries/vimdoc/highlights.scm @@ -1,13 +1,19 @@ -(h1) @markup.heading.1 +(h1 + (delimiter) @markup.heading.1.delimiter + (heading) @markup.heading.1) -(h2) @markup.heading.2 +(h2 + (delimiter) @markup.heading.2.delimiter + (heading) @markup.heading.2) -(h3) @markup.heading.3 +(h3 + (heading) @markup.heading.3) -(column_heading) @markup.heading.4 +(column_heading + (heading) @markup.heading.4) (column_heading - "~" @markup.heading.4 + (delimiter) @markup.heading.4 (#set! conceal "")) (tag @@ -35,7 +41,7 @@ text: (_) @markup.raw) ((codeblock) @markup.raw.block - (#set! "priority" 90)) + (#set! priority 90)) (codeblock ">" @markup.raw @@ -53,7 +59,8 @@ (keycode) @string.special -(url) @string.special.url +((url) @string.special.url + (#set! @string.special.url url @string.special.url)) (modeline) @keyword.directive diff --git a/runtime/syntax/antlr4.vim b/runtime/syntax/antlr4.vim new file mode 100644 index 0000000000..33cc865ccc --- /dev/null +++ b/runtime/syntax/antlr4.vim @@ -0,0 +1,30 @@ +" Vim syntax file +" Language: ANTLR4, ANother Tool for Language Recognition v4 <www.antlr.org> +" Maintainer: Yinzuo Jiang <jiangyinzuo@foxmail.com> +" Last Change: 2024 July 09 + +" quit when a syntax file was already loaded +if exists("b:current_syntax") + finish +endif + +" Keywords. See https://github.com/antlr/antlr4/blob/4.13.1/doc/lexicon.md +syn keyword antlr4Include import +" https://github.com/antlr/antlr4/blob/4.13.1/doc/options.md +" https://github.com/antlr/antlr4/blob/4.13.1/doc/grammars.md +syn keyword antlr4Structure fragment lexer parser grammar options channels tokens mode +syn keyword antlr4Statement returns locals +syn keyword antlr4Exceptions throws catch finally + +" Comments. +syn keyword antlr4Todo contained TODO FIXME XXX NOTE +syn region antlr4Comment start="//" end="$" contains=antlr4Todo,@Spell +syn region antlr4Comment start="/\*" end="\*/" contains=antlr4Todo,@Spell + +hi def link antlr4Include Include +hi def link antlr4Structure Structure +hi def link antlr4Statement Statement +hi def link antlr4Exceptions Structure +hi def link antlr4Comment Comment + +let b:current_syntax = "antlr4" diff --git a/runtime/syntax/asy.vim b/runtime/syntax/asy.vim new file mode 100644 index 0000000000..ed2bf712f5 --- /dev/null +++ b/runtime/syntax/asy.vim @@ -0,0 +1,243 @@ +" Vim syntax file +" Language: Asymptote +" Maintainer: Avid Seeker <avidseeker7@protonmail.com> +" Andy Hammerlindl +" Last Change: 2022 Jan 05 + +" Hacked together from Bram Moolenaar's C syntax file, and Claudio Fleiner's +" Java syntax file. + +if exists("b:current_syntax") + finish +endif + +" useful C/C++/Java keywords +syn keyword asyStatement break return continue unravel +syn keyword asyConditional if else +syn keyword asyRepeat while for do +syn keyword asyExternal access from import include +syn keyword asyOperator new operator + +" basic asymptote keywords +syn keyword asyConstant VERSION +syn keyword asyConstant true false default infinity inf nan +syn keyword asyConstant null nullframe nullpath nullpen +syn keyword asyConstant intMin intMax realMin realMax +syn keyword asyConstant realEpsilon realDigits +syn keyword asyPathSpec and cycle controls tension atleast curl +syn keyword asyStorageClass static public restricted private explicit +syn keyword asyStructure struct typedef +syn keyword asyType void bool bool3 int real string file +syn keyword asyType pair triple transform guide path pen frame +syn keyword asyType picture + +" module specific keywords +if exists("asy_syn_plain") + syn keyword asyConstant currentpicture currentpen defaultpen + syn keyword asyConstant inch inches cm mm bp pt up down right left + syn keyword asyConstant E NE N NW W SW S SE + syn keyword asyConstant ENE NNE NNW WNW WSW SSW SSE ESE + syn keyword asyConstant I pi twopi + syn keyword asyConstant CCW CW + syn keyword asyConstant undefined sqrtEpsilon Align mantissaBits + syn keyword asyConstant identity zeroTransform invert + syn keyword asyConstant stdin stdout + syn keyword asyConstant unitsquare unitcircle circleprecision + syn keyword asyConstant solid dotted Dotted dashed dashdotted + syn keyword asyConstant longdashed longdashdotted + syn keyword asyConstant squarecap roundcap extendcap + syn keyword asyConstant miterjoin roundjoin beveljoin + syn keyword asyConstant zerowinding evenodd basealign nobasealign + syn keyword asyConstant black white gray red green blue Cyan Magenta + syn keyword asyConstant Yellow Black cyan magenta yellow palered + syn keyword asyConstant palegreen paleblue palecyan palemagenta + syn keyword asyConstant paleyellow palegray lightred lightgreen + syn keyword asyConstant lightblue lightcyan lightmagenta lightyellow + syn keyword asyConstant lightgray mediumred mediumgreen mediumblue + syn keyword asyConstant mediumcyan mediummagenta mediumyellow + syn keyword asyConstant mediumgray heavyred heavygreen heavyblue + syn keyword asyConstant heavycyan heavymagenta lightolive heavygray + syn keyword asyConstant deepred deepgreen deepblue deepcyan + syn keyword asyConstant deepmagenta deepyellow deepgray darkred + syn keyword asyConstant darkgreen darkblue darkcyan darkmagenta + syn keyword asyConstant darkolive darkgray orange fuchsia chartreuse + syn keyword asyConstant springgreen purple royalblue salmon brown + syn keyword asyConstant olive darkbrown pink palegrey lightgrey + syn keyword asyConstant mediumgrey grey heavygrey deepgrey darkgrey + + if exists("asy_syn_texcolors") + syn keyword asyConstant GreenYellow Yellow Goldenrod Dandelion + syn keyword asyConstant Apricot Peach Melon YellowOrange Orange + syn keyword asyConstant BurntOrange Bittersweet RedOrange Mahogany + syn keyword asyConstant Maroon BrickRed Red OrangeRed RubineRed + syn keyword asyConstant WildStrawberry Salmon CarnationPink Magenta + syn keyword asyConstant VioletRed Rhodamine Mulberry RedViolet + syn keyword asyConstant Fuchsia Lavender Thistle Orchid DarkOrchid + syn keyword asyConstant Purple Plum Violet RoyalPurple BlueViolet + syn keyword asyConstant Periwinkle CadetBlue CornflowerBlue + syn keyword asyConstant MidnightBlue NavyBlue RoyalBlue Blue + syn keyword asyConstant Cerulean Cyan ProcessBlue SkyBlue Turquoise + syn keyword asyConstant TealBlue Aquamarine BlueGreen Emerald + syn keyword asyConstant JungleGreen SeaGreen Green ForestGreen + syn keyword asyConstant PineGreen LimeGreen YellowGreen SpringGreen + syn keyword asyConstant OliveGreen RawSienna Sepia Brown Tan Gray + syn keyword asyConstant Black White + endif + + if exists("asy_syn_x11colors") + syn keyword asyConstant AliceBlue AntiqueWhite Aqua Aquamarine Azure + syn keyword asyConstant Beige Bisque Black BlanchedAlmond Blue + syn keyword asyConstant BlueViolet Brown BurlyWood CadetBlue + syn keyword asyConstant Chartreuse Chocolate Coral CornflowerBlue + syn keyword asyConstant Cornsilk Crimson Cyan DarkBlue DarkCyan + syn keyword asyConstant DarkGoldenrod DarkGray DarkGreen DarkKhaki + syn keyword asyConstant DarkMagenta DarkOliveGreen DarkOrange + syn keyword asyConstant DarkOrchid DarkRed DarkSalmon DarkSeaGreen + syn keyword asyConstant DarkSlateBlue DarkSlateGray DarkTurquoise + syn keyword asyConstant DarkViolet DeepPink DeepSkyBlue DimGray + syn keyword asyConstant DodgerBlue FireBrick FloralWhite ForestGreen + syn keyword asyConstant Fuchsia Gainsboro GhostWhite Gold Goldenrod + syn keyword asyConstant Gray Green GreenYellow Honeydew HotPink + syn keyword asyConstant IndianRed Indigo Ivory Khaki Lavender + syn keyword asyConstant LavenderBlush LawnGreen LemonChiffon + syn keyword asyConstant LightBlue LightCoral LightCyan + syn keyword asyConstant LightGoldenrodYellow LightGreen LightGrey + syn keyword asyConstant LightPink LightSalmon LightSeaGreen + syn keyword asyConstant LightSkyBlue LightSlateGray LightSteelBlue + syn keyword asyConstant LightYellow Lime LimeGreen Linen Magenta + syn keyword asyConstant Maroon MediumAquamarine MediumBlue + syn keyword asyConstant MediumOrchid MediumPurple MediumSeaGreen + syn keyword asyConstant MediumSlateBlue MediumSpringGreen + syn keyword asyConstant MediumTurquoise MediumVioletRed MidnightBlue + syn keyword asyConstant MintCream MistyRose Moccasin NavajoWhite + syn keyword asyConstant Navy OldLace Olive OliveDrab Orange + syn keyword asyConstant OrangeRed Orchid PaleGoldenrod PaleGreen + syn keyword asyConstant PaleTurquoise PaleVioletRed PapayaWhip + syn keyword asyConstant PeachPuff Peru Pink Plum PowderBlue Purple + syn keyword asyConstant Red RosyBrown RoyalBlue SaddleBrown Salmon + syn keyword asyConstant SandyBrown SeaGreen Seashell Sienna Silver + syn keyword asyConstant SkyBlue SlateBlue SlateGray Snow SpringGreen + syn keyword asyConstant SteelBlue Tan Teal Thistle Tomato Turquoise + syn keyword asyConstant Violet Wheat White WhiteSmoke Yellow + syn keyword asyConstant YellowGreen + endif + + if exists("asy_syn_three") + syn keyword asyType path3 guide3 transform3 + syn keyword asyType projection light material patch surface tube + syn keyword asyConstant currentprojection currentlight defaultrender + syn keyword asyConstant identity4 O X Y Z + syn keyword asyConstant nolight nullpens + syn keyword asyConstant unitsphere unithemisphere unitplane octant1 + syn keyword asyConstant unitcone unitsolidcone unitcube unitcylinder + syn keyword asyConstant unitdisk unittube + endif +endif + + +" string constants +syn region asyCString start=+'+ end=+'+ skip=+\\\\\|\\'+ contains=asyCSpecial +syn match asyCSpecial display contained +\\\(['"?\\abfnrtv]\|\o\{1,3}\)+ +syn match asyCSpecial display contained +\\\(x[0-9A-F]\{1,2\}\|$\)+ +" double quoted strings only special character is \" +syn region asyString start=+"+ end=+"+ skip=+\\\\\|\\"+ contains=asySpecial +syn match asySpecial display contained +\(\\\)\@1<!\(\\\\\)*\zs\\"+ + + +" number constants +syn match asyNumbers display transparent "\<\d\|\.\d" + \ contains=asyNumber,asyNumberError +syn match asyNumber display contained "\d*\.\=\d*\(e[-+]\=\d\+\)\=" +" highlight number constants with two '.' or with '.' after an 'e' +syn match asyNumberError display contained "\d*\.\(\d\|e[-+]\=\)*\.[0-9.]*" +syn match asyNumberError display contained "\d*e[-+]\=\d*\.[0-9.]*" +syn match asyNumberError display contained "\d*e[-+]\=\(e[-+]\=\)*\.[0-9.]*" + + +" comments and comment strings +syn keyword asyTodo contained TODO FIXME XXX +syn sync ccomment asyComment minlines=15 +if exists("asy_comment_strings") + " A comment can contain asyString, asyCString, and asyNumber. But a "*/" + " inside a asy*String in a asyComment DOES end the comment! So we need to + " use a special type of asy*String: asyComment*String, which also ends on + " "*/", and sees a "*" at the start of the line as comment again. + " Unfortunately this doesn't very well work for // type of comments :-( + syn match asyCommentSkip contained "^\s*\*\($\|\s\+\)" + syn region asyCommentString contained start=+"+ skip=+\\\\\|\\"+ end=+"+ + \ end=+\*/+me=s-1 + \ contains=asySpecial,asyCommentSkip + syn region asyCommentCString contained start=+'+ skip=+\\\\\|\\'+ end=+'+ + \ end=+\*/+me=s-1 + \ contains=asyCSpecial,asyCommentSkip + syn region asyCommentLString contained start=+"+ skip=+\\\\\|\\"+ end=+"+ + \ end="$" contains=asySpecial + syn region asyCommentLCString contained start=+'+ skip=+\\\\\|\\'+ end=+'+ + \ end="$" contains=asyCSpecial + syn region asyCommentL start="//" skip="\\$" end="$" keepend + \ contains=asyTodo,asyCommentLString, + \ asyCommentLCString,asyNumbers + syn region asyComment matchgroup=asyComment start="/\*" end="\*/" + \ contains=asyTodo,asyCommentStartError, + \ asyCommentString,asyCommentCString,asyNumbers +else + syn region asyCommentL start="//" skip="\\$" end="$" keepend + \ contains=asyTodo + syn region asyComment matchgroup=asyComment start="/\*" end="\*/" + \ contains=asyTodo,asyCommentStartError +endif + +" highlight common errors when starting/ending C comments +syn match asyCommentError display "\*/" +syn match asyCommentStartError display "/\*"me=e-1 contained + + +" delimiter matching errors +syn region asyCurly transparent start='{' end='}' + \ contains=TOP,asyCurlyError +syn region asyBrack transparent start='\[' end='\]' matchgroup=asyError + \ end=';' contains=TOP,asyBrackError +syn region asyParen transparent start='(' end=')' matchgroup=asyError + \ end=';' contains=TOP,asyParenError +syn match asyCurlyError display '}' +syn match asyBrackError display '\]' +syn match asyParenError display ')' +" for (;;) constructs are exceptions that allow ; inside parenthesis +syn region asyParen transparent matchgroup=asyParen + \ start='\(for\s*\)\@<=(' end=')' + \ contains=TOP,asyParenError + +" Define the default highlighting. +hi def link asyCommentL asyComment +hi def link asyConditional Conditional +hi def link asyRepeat Repeat +hi def link asyNumber Number +hi def link asyNumberError asyError +hi def link asyCurlyError asyError +hi def link asyBracketError asyError +hi def link asyParenError asyError +hi def link asyCommentError asyError +hi def link asyCommentStartError asyError +hi def link asyOperator Operator +hi def link asyStructure Structure +hi def link asyStorageClass StorageClass +hi def link asyExternal Include +hi def link asyDefine Macro +hi def link asyError Error +hi def link asyStatement Statement +hi def link asyType Type +hi def link asyConstant Constant +hi def link asyCommentString asyString +hi def link asyCommentCString asyString +hi def link asyCommentLString asyString +hi def link asyCommentLCString asyString +hi def link asyCommentSkip asyComment +hi def link asyString String +hi def link asyCString String +hi def link asyComment Comment +hi def link asySpecial SpecialChar +hi def link asyCSpecial SpecialChar +hi def link asyTodo Todo +hi def link asyPathSpec Statement + +let b:current_syntax = "asy" diff --git a/runtime/syntax/checkhealth.vim b/runtime/syntax/checkhealth.vim index 2fd0aed601..a4f6e016cb 100644 --- a/runtime/syntax/checkhealth.vim +++ b/runtime/syntax/checkhealth.vim @@ -14,7 +14,9 @@ syn case match syn keyword DiagnosticError ERROR[:] syn keyword DiagnosticWarn WARNING[:] syn keyword DiagnosticOk OK[:] -syn match helpSectionDelim "^======*\n.*$" -syn match healthHeadingChar "=" conceal cchar=─ contained containedin=helpSectionDelim +" Note: hs=e starts higlighting on the title line (instead of the "===" line). +syn match helpSectionDelim /^======*\n.*$/hs=e +highlight helpSectionDelim gui=reverse cterm=reverse +syn match healthHeadingChar "=" conceal cchar= contained containedin=helpSectionDelim let b:current_syntax = "checkhealth" diff --git a/runtime/syntax/chicken.vim b/runtime/syntax/chicken.vim index f53d872e74..958fc1f361 100644 --- a/runtime/syntax/chicken.vim +++ b/runtime/syntax/chicken.vim @@ -1,13 +1,13 @@ " Vim syntax file -" Language: Scheme (CHICKEN) -" Last Change: 2021 Oct 01 -" Author: Evan Hanson <evhan@foldling.org> -" Maintainer: Evan Hanson <evhan@foldling.org> -" Repository: https://git.foldling.org/vim-scheme.git -" URL: https://foldling.org/vim/syntax/chicken.vim -" Notes: This is supplemental syntax, to be loaded after the core Scheme -" syntax file (syntax/scheme.vim). Enable it by setting b:is_chicken=1 -" and filetype=scheme. +" Language: Scheme (CHICKEN) +" Last Change: 2024 Jun 21 +" Author: Evan Hanson <evhan@foldling.org> +" Maintainer: Evan Hanson <evhan@foldling.org> +" Repository: https://git.foldling.org/vim-scheme.git +" URL: https://foldling.org/vim/syntax/chicken.vim +" Notes: This is supplemental syntax, to be loaded after the core +" Scheme syntax file (syntax/scheme.vim). Enable it by +" setting b:is_chicken=1 and filetype=scheme. " Only to be used on top of the Scheme syntax. if !exists('b:did_scheme_syntax') diff --git a/runtime/syntax/csv.vim b/runtime/syntax/csv.vim new file mode 100644 index 0000000000..6295c3e29a --- /dev/null +++ b/runtime/syntax/csv.vim @@ -0,0 +1,38 @@ +" Maintainer: Maxim Kim <habamax@gmail.com> +" Converted from vim9script +" Last Update: 2024-06-18 + +if exists("b:current_syntax") + finish +endif + +let s:delimiter = get(b:, "csv_delimiter", ",") + +" generate bunch of following syntaxes: +" syntax match csvCol8 /.\{-}\(,\|$\)/ nextgroup=escCsvCol0,csvCol0 +" syntax region escCsvCol8 start=/ *"\([^"]*""\)*[^"]*/ end=/" *\(,\|$\)/ nextgroup=escCsvCol0,csvCol0 +for s:col in range(8, 0, -1) + let s:ncol = (s:col == 8 ? 0 : s:col + 1) + exe $'syntax match csvCol{s:col}' .. ' /.\{-}\(' .. s:delimiter .. '\|$\)/ nextgroup=escCsvCol' .. s:ncol .. ',csvCol' .. s:ncol + exe $'syntax region escCsvCol{s:col}' .. ' start=/ *"\([^"]*""\)*[^"]*/ end=/" *\(' .. s:delimiter .. '\|$\)/ nextgroup=escCsvCol' .. s:ncol .. ',csvCol' .. s:ncol +endfor + +hi def link csvCol1 Statement +hi def link csvCol2 Constant +hi def link csvCol3 Type +hi def link csvCol4 PreProc +hi def link csvCol5 Identifier +hi def link csvCol6 Special +hi def link csvCol7 String +hi def link csvCol8 Comment + +hi def link escCsvCol1 csvCol1 +hi def link escCsvCol2 csvCol2 +hi def link escCsvCol3 csvCol3 +hi def link escCsvCol4 csvCol4 +hi def link escCsvCol5 csvCol5 +hi def link escCsvCol6 csvCol6 +hi def link escCsvCol7 csvCol7 +hi def link escCsvCol8 csvCol8 + +let b:current_syntax = "csv" diff --git a/runtime/syntax/deb822sources.vim b/runtime/syntax/deb822sources.vim index f7d337fce9..ec45605905 100644 --- a/runtime/syntax/deb822sources.vim +++ b/runtime/syntax/deb822sources.vim @@ -40,7 +40,7 @@ syn match deb822sourcesUri '\(https\?://\|ftp://\|[rs]sh://\|debtorre syn region deb822sourcesStrictField matchgroup=deb822sourcesEntryField start="^\%(Types\|URIs\|Suites\|Components\): *" end="$" contains=deb822sourcesType,deb822sourcesUri,deb822sourcesSupportedSuites,deb822sourcesUnsupportedSuites,deb822sourcesFreeComponent,deb822sourcesNonFreeComponent oneline syn region deb822sourcesField matchgroup=deb822sourcesOptionField start="^\%(Signed-By\|Check-Valid-Until\|Valid-Until-Min\|Valid-Until-Max\|Date-Max-Future\|InRelease-Path\): *" end="$" oneline syn region deb822sourcesField matchgroup=deb822sourcesMultiValueOptionField start="^\%(Architectures\|Languages\|Targets\)\%(-Add\|-Remove\)\?: *" end="$" oneline -syn region deb822sourcesStrictField matchgroup=deb822sourcesBooleanOptionField start="^\%(PDiffs\|Allow-Insecure\|Allow-Weak\|Allow-Downgrade-To-Insecure\|Trusted\|Check-Date\): *" end="$" contains=deb822sourcesYesNo oneline +syn region deb822sourcesStrictField matchgroup=deb822sourcesBooleanOptionField start="^\%(PDiffs\|Allow-Insecure\|Allow-Weak\|Allow-Downgrade-To-Insecure\|Trusted\|Check-Date\|Enabled\): *" end="$" contains=deb822sourcesYesNo oneline syn region deb822sourcesStrictField matchgroup=deb822sourcesForceBooleanOptionField start="^\%(By-Hash\): *" end="$" contains=deb822sourcesForce,deb822sourcesYesNo oneline hi def link deb822sourcesField Default diff --git a/runtime/syntax/debcopyright.vim b/runtime/syntax/debcopyright.vim index 6f76b5c868..cb9e8965de 100644 --- a/runtime/syntax/debcopyright.vim +++ b/runtime/syntax/debcopyright.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: Debian copyright file " Maintainer: Debian Vim Maintainers -" Last Change: 2023 Jan 16 +" Last Change: 2024 Jul 28 " URL: https://salsa.debian.org/vim-team/vim-debian/blob/main/syntax/debcopyright.vim " Standard syntax initialization @@ -15,7 +15,7 @@ set cpo&vim syn case match syn match debcopyrightUrl "\vhttps?://[[:alnum:]][-[:alnum:]]*[[:alnum:]]?(\.[[:alnum:]][-[:alnum:]]*[[:alnum:]]?)*\.[[:alpha:]][-[:alnum:]]*[[:alpha:]]?(:\d+)?(/[^[:space:]]*)?$" -syn match debcopyrightKey "^\%(Format\|Upstream-Name\|Upstream-Contact\|Disclaimer\|Source\|Comment\|Files\|Copyright\|License\|Files-Excluded\%(-[-a-zA-Z0-9]\+\)\=\): *" +syn match debcopyrightKey "^\%(Format\|Upstream-Name\|Upstream-Contact\|Disclaimer\|Source\|Comment\|Files\|Copyright\|License\|Files-\%(Excluded\|Included\)\%(-[-a-zA-Z0-9]\+\)\=\): *" syn match debcopyrightEmail "[_=[:alnum:]\.+-]\+@[[:alnum:]\./\-]\+" syn match debcopyrightEmail "<.\{-}>" syn match debcopyrightComment "^#.*$" contains=@Spell diff --git a/runtime/syntax/dockerfile.vim b/runtime/syntax/dockerfile.vim index ce52e697cd..6ec71fcdb6 100644 --- a/runtime/syntax/dockerfile.vim +++ b/runtime/syntax/dockerfile.vim @@ -1,6 +1,6 @@ " dockerfile.vim - Syntax highlighting for Dockerfiles " Maintainer: Honza Pokorny <https://honza.ca> -" Last Change: 2020 Feb 11 +" Last Change: 2024 Jul 03 " License: BSD " https://docs.docker.com/engine/reference/builder/ @@ -34,7 +34,7 @@ syntax region dockerfileJSON contained keepend start=/\v\[/ skip=/\v\\\_./ end syntax region dockerfileShell contained keepend start=/\v/ skip=/\v\\\_./ end=/\v$/ contains=@Shell syntax region dockerfileValue contained keepend start=/\v/ skip=/\v\\\_./ end=/\v$/ contains=dockerfileString -syntax region dockerfileComment start=/\v^\s*#/ end=/\v$/ +syntax region dockerfileComment start=/\v^\s*#/ end=/\v$/ contains=@Spell set commentstring=#\ %s hi def link dockerfileString String diff --git a/runtime/syntax/dosbatch.vim b/runtime/syntax/dosbatch.vim index 55601996ad..0c3e99be3b 100644 --- a/runtime/syntax/dosbatch.vim +++ b/runtime/syntax/dosbatch.vim @@ -3,6 +3,7 @@ " Maintainer: Mike Williams <mrmrdubya@gmail.com> " Filenames: *.bat " Last Change: 3rd February 2024 +" 2024 Aug 14 by Vim Project: improve syntax (#15453) " " Options Flags: " dosbatch_cmdextversion - 1 = Windows NT, 2 = Windows 2000 [default] @@ -45,7 +46,7 @@ syn match dosbatchString "\<echo\([^)>|]\|\^\@<=[)>|]\)*"lc=4 contains=dosbatchV syn match dosbatchEchoOperator "\<echo\s\+\(on\|off\)\s*$"lc=4 " For embedded commands -syn match dosbatchCmd "(\s*'[^']*'"lc=1 contains=dosbatchString,dosbatchVariable,dosBatchArgument,@dosbatchNumber,dosbatchImplicit,dosbatchStatement,dosbatchConditional,dosbatchRepeat,dosbatchOperator +syn match dosbatchCmd "(\s*'[^']*'"lc=1 contains=dosbatchString,dosbatchVariable,dosBatchArgument,@dosbatchNumber,dosbatchImplicit,dosbatchStatement,dosbatchConditional,dosbatchRepeat,dosbatchOperator,dosbatchIfOperator " Numbers - surround with ws to not include in dir and filenames syn match dosbatchInteger "[[:space:]=(/:,!~-]\d\+"lc=1 @@ -74,7 +75,7 @@ syn match dosbatchSet "\s\h\w*[+-]\==\{-1}" contains=dosbatchIdentifier,dosbatc " Args to bat files and for loops, etc syn match dosbatchArgument "%\(\d\|\*\)" -syn match dosbatchArgument "%[a-z]\>" +syn match dosbatchArgument "%%[a-z]\>" if dosbatch_cmdextversion == 1 syn match dosbatchArgument "%\~[fdpnxs]\+\(\($PATH:\)\=[a-z]\|\d\)\>" else @@ -102,9 +103,11 @@ else syn match dosbatchColonCommentErr contained "\s*:\s*:.*$" endif syn match dosbatchColonCommentErr contained "\s*:\s*:[^)]*\(\(\n\s*\)\?)\)\@=" -syn region dosbatchCodeBlock transparent start=+(+ end=+)+ contains=dosbatchString,dosbatchVariable,dosBatchArgument,@dosbatchNumber,dosbatchImplicit,dosbatchStatement,dosbatchConditional,dosbatchRepeat,dosbatchOperator,@dosbatchCodeBlockComment,dosbatchColonCommentErr,dosbatchCodeBlock +syn region dosbatchCodeBlock transparent start=+(+ end=+)+ contains=dosbatchString,dosbatchVariable,dosBatchArgument,@dosbatchNumber,dosbatchImplicit,dosbatchStatement,dosbatchConditional,dosbatchRepeat,dosbatchOperator,dosbatchIfOperator,@dosbatchCodeBlockComment,dosbatchColonCommentErr,dosbatchCodeBlock syn match dosbatchCodeBlockErr ")" +syn sync match dosbatchSyncCodeBlock grouphere NONE "^)\s*$" + syn keyword dosbatchImplicit append assoc at attrib break cacls cd chcp chdir syn keyword dosbatchImplicit chkdsk chkntfs cls cmd color comp compact convert copy syn keyword dosbatchImplicit date del dir diskcomp diskcopy doskey echo endlocal diff --git a/runtime/syntax/dosini.vim b/runtime/syntax/dosini.vim index 66e17ec9af..e8212b6d2e 100644 --- a/runtime/syntax/dosini.vim +++ b/runtime/syntax/dosini.vim @@ -1,12 +1,12 @@ " Vim syntax file " Language: Configuration File (ini file) for MSDOS/MS Windows -" Version: 2.3 +" Version: 2.4 " Original Author: Sean M. McKee <mckee@misslink.net> " Previous Maintainer: Nima Talebi <nima@it.net.au> " Current Maintainer: Hong Xu <hong@topbug.net> " Homepage: http://www.vim.org/scripts/script.php?script_id=3747 " Repository: https://github.com/xuhdev/syntax-dosini.vim -" Last Change: 2023 Aug 20 +" Last Change: 2024 Sept 08 " quit when a syntax file was already loaded @@ -27,7 +27,7 @@ syn match dosiniNumber "=\zs\s*\d\+\s*$" syn match dosiniNumber "=\zs\s*\d*\.\d\+\s*$" syn match dosiniNumber "=\zs\s*\d\+e[+-]\=\d\+\s*$" syn region dosiniHeader start="^\s*\[" end="\]" -syn match dosiniComment "^[#;].*$" +syn match dosiniComment "^[#;].*$" contains=@Spell syn region dosiniSection start="\s*\[.*\]" end="\ze\s*\[.*\]" fold \ contains=dosiniLabel,dosiniValue,dosiniNumber,dosiniHeader,dosiniComment diff --git a/runtime/syntax/dune.vim b/runtime/syntax/dune.vim index b4254057c0..3cfb47fbee 100644 --- a/runtime/syntax/dune.vim +++ b/runtime/syntax/dune.vim @@ -4,6 +4,7 @@ " Anton Kochkov <anton.kochkov@gmail.com> " URL: https://github.com/ocaml/vim-ocaml " Last Change: +" 2023 Nov 24 - Add end-of-line strings (Samuel Hym) " 2019 Feb 27 - Add newer keywords to the syntax (Simon Cruanes) " 2018 May 8 - Check current_syntax (Kawahara Satoru) " 2018 Mar 29 - Extend jbuild syntax with more keywords (Petter A. Urkedal) @@ -38,6 +39,8 @@ syn keyword lispFunc ignore-stdout ignore-stderr ignore-outputs syn keyword lispFunc with-stdout-to with-stderr-to with-outputs-to syn keyword lispFunc write-file system bash +syn region lispString start=+"\\[>|]+ end=+$+ contains=@Spell + syn cluster lispBaseListCluster add=duneVar syn match duneVar '\${[@<^]}' containedin=lispSymbol syn match duneVar '\${\k\+\(:\k\+\)\?}' containedin=lispSymbol diff --git a/runtime/syntax/fstab.vim b/runtime/syntax/fstab.vim index 91150bc37b..64d5bee3d0 100644 --- a/runtime/syntax/fstab.vim +++ b/runtime/syntax/fstab.vim @@ -2,8 +2,8 @@ " Language: fstab file " Maintainer: Radu Dineiu <radu.dineiu@gmail.com> " URL: https://raw.github.com/rid9/vim-fstab/master/syntax/fstab.vim -" Last Change: 2023 Feb 19 -" Version: 1.6.3 +" Last Change: 2024 Jul 11 +" Version: 1.6.4 " " Credits: " David Necas (Yeti) <yeti@physics.muni.cz> @@ -35,7 +35,7 @@ syn match fsOperator /[,=:#]/ " Device syn cluster fsDeviceCluster contains=fsOperator,fsDeviceKeyword,fsDeviceError syn match fsDeviceError /\%([^a-zA-Z0-9_\/#@:\.-]\|^\w\{-}\ze\W\)/ contained -syn keyword fsDeviceKeyword contained none proc linproc tmpfs devpts devtmpfs sysfs usbfs +syn keyword fsDeviceKeyword contained none proc linproc tmpfs devpts devtmpfs sysfs usbfs tracefs overlay syn keyword fsDeviceKeyword contained LABEL nextgroup=fsDeviceLabel syn keyword fsDeviceKeyword contained UUID nextgroup=fsDeviceUUID syn keyword fsDeviceKeyword contained PARTLABEL nextgroup=fsDevicePARTLABEL @@ -56,7 +56,7 @@ syn keyword fsMountPointKeyword contained none swap " Type syn cluster fsTypeCluster contains=fsTypeKeyword,fsTypeUnknown syn match fsTypeUnknown /\s\+\zs\w\+/ contained -syn keyword fsTypeKeyword contained adfs ados affs anon_inodefs atfs audiofs auto autofs bdev befs bfs btrfs binfmt_misc cd9660 ceph cfs cgroup cifs coda coherent configfs cpuset cramfs debugfs devfs devpts devtmpfs dlmfs e2compr ecryptfs efivarfs efs erofs exfat ext2 ext2fs ext3 ext4 f2fs fdesc ffs filecore fuse fuseblk fusectl gfs2 hfs hfsplus hpfs hugetlbfs iso9660 jffs jffs2 jfs kernfs lfs linprocfs mfs minix mqueue msdos ncpfs nfs nfs4 nfsd nilfs2 none ntfs ntfs3 null nwfs ocfs2 omfs overlay ovlfs pipefs portal proc procfs pstore ptyfs pvfs2 qnx4 qnx6 reiserfs ramfs romfs rpc_pipefs securityfs shm smbfs spufs squashfs sockfs sshfs std subfs swap sysfs sysv tcfs tmpfs ubifs udf ufs umap umsdos union usbfs userfs v9fs vfat virtiofs vs3fs vxfs wrapfs wvfs xenfs xenix xfs zisofs zonefs +syn keyword fsTypeKeyword contained adfs ados affs anon_inodefs atfs audiofs auto autofs bdev befs bfs btrfs binfmt_misc cd9660 ceph cfs cgroup cifs coda coherent configfs cpuset cramfs debugfs devfs devpts devtmpfs dlmfs e2compr ecryptfs efivarfs efs erofs exfat ext2 ext2fs ext3 ext4 f2fs fdesc ffs filecore fuse fuseblk fusectl gfs2 hfs hfsplus hpfs hugetlbfs iso9660 jffs jffs2 jfs kernfs lfs linprocfs mfs minix mqueue msdos ncpfs nfs nfs4 nfsd nilfs2 none ntfs ntfs3 null nwfs ocfs2 omfs overlay ovlfs pipefs portal proc procfs pstore ptyfs pvfs2 qnx4 qnx6 reiserfs ramfs romfs rpc_pipefs securityfs shm smbfs spufs squashfs sockfs sshfs std subfs swap sysfs sysv tcfs tmpfs tracefs ubifs udf ufs umap umsdos union usbfs userfs v9fs vfat virtiofs vs3fs vxfs wrapfs wvfs xenfs xenix xfs zisofs zonefs " Options " ------- @@ -80,10 +80,10 @@ syn match fsOptionsKeywords contained /\<x-systemd\.\%(device-bound\|automount\| syn match fsOptionsKeywords contained /\<x-initrd\.mount/ syn match fsOptionsKeywords contained /\<cache=/ nextgroup=fsOptionsCache -syn keyword fsOptionsCache yes no none strict loose fscache mmap +syn keyword fsOptionsCache contained yes no none strict loose fscache mmap syn match fsOptionsKeywords contained /\<dax=/ nextgroup=fsOptionsDax -syn keyword fsOptionsDax inode never always +syn keyword fsOptionsDax contained inode never always syn match fsOptionsKeywords contained /\<errors=/ nextgroup=fsOptionsErrors syn keyword fsOptionsErrors contained continue panic withdraw remount-ro recover zone-ro zone-offline repair @@ -288,8 +288,15 @@ syn match fsOptionsKeywords contained /\<\%(atime_quantum\|preferred_slot\|local syn keyword fsOptionsKeywords contained strictatime inode64 " Options: overlay +syn match fsOptionsKeywords contained /\<\%(index\|uuid\|nfs_export\|metacopy\)=/ nextgroup=fsOptionsOverlayBool +syn keyword fsOptionsOverlayBool contained on off +syn match fsOptionsKeywords contained /\<\%(lowerdir\|upperdir\|workdir\)=/ nextgroup=fsOptionsOverlayDir +syn match fsOptionsOverlayDir contained /[^,[:space:]]*/ syn match fsOptionsKeywords contained /\<redirect_dir=/ nextgroup=fsOptionsOverlayRedirectDir syn keyword fsOptionsOverlayRedirectDir contained on follow off nofollow +syn match fsOptionsKeywords contained /\<xino=/ nextgroup=fsOptionsOverlayXino +syn keyword fsOptionsOverlayXino contained on off auto +syn keyword fsOptionsKeywords contained userxattr volatile " Options: proc syn match fsOptionsKeywords contained /\<\%(hidepid\|subset\)=/ nextgroup=fsOptionsString @@ -462,7 +469,10 @@ hi def link fsOptionsNumberOctal Number hi def link fsOptionsNumberSigned Number hi def link fsOptionsOcfs2Coherency String hi def link fsOptionsOcfs2ResvLevel Number +hi def link fsOptionsOverlayBool Boolean +hi def link fsOptionsOverlayDir String hi def link fsOptionsOverlayRedirectDir String +hi def link fsOptionsOverlayXino String hi def link fsOptionsQnx4Bitmap String hi def link fsOptionsQnx6Hold String hi def link fsOptionsQnx6Sync String diff --git a/runtime/syntax/glsl.vim b/runtime/syntax/glsl.vim new file mode 100644 index 0000000000..06ffcba625 --- /dev/null +++ b/runtime/syntax/glsl.vim @@ -0,0 +1,752 @@ +" Language: OpenGL Shading Language +" Maintainer: Gregory Anders <greg@gpanders.com> +" Last Modified: 2024 Jul 21 +" Upstream: https://github.com/tikhomirov/vim-glsl + +if exists('b:current_syntax') + finish +endif + +" Statements +syn keyword glslConditional if else switch case default +syn keyword glslRepeat for while do +syn keyword glslStatement discard return break continue + +" Comments +syn keyword glslTodo contained TODO FIXME XXX NOTE +syn region glslCommentL start="//" skip="\\$" end="$" keepend contains=glslTodo,@Spell +syn region glslComment matchgroup=glslCommentStart start="/\*" end="\*/" extend contains=glslTodo,@Spell + +" Preprocessor +syn region glslPreCondit start="^\s*#\s*\(if\|ifdef\|ifndef\|else\|elif\|endif\)" skip="\\$" end="$" keepend +syn region glslDefine start="^\s*#\s*\(define\|undef\)" skip="\\$" end="$" keepend +syn keyword glslTokenConcat ## +syn keyword glslPredefinedMacro __LINE__ __FILE__ __VERSION__ GL_ES +syn region glslPreProc start="^\s*#\s*\(error\|pragma\|extension\|version\|line\)" skip="\\$" end="$" keepend +syn region glslInclude start="^\s*#\s*include" skip="\\$" end="$" keepend + +" Folding Blocks +syn region glslCurlyBlock start="{" end="}" transparent fold +syn region glslParenBlock start="(" end=")" transparent fold + +" Boolean Constants +syn keyword glslBoolean true false + +" Integer Numbers +syn match glslDecimalInt display "\<\(0\|[1-9]\d*\)[uU]\?" +syn match glslOctalInt display "\<0\o\+[uU]\?" +syn match glslHexInt display "\<0[xX]\x\+[uU]\?" + +" Float Numbers +syn match glslFloat display "\<\d\+\.\([eE][+-]\=\d\+\)\=\(lf\|LF\|f\|F\)\=" +syn match glslFloat display "\<\.\d\+\([eE][+-]\=\d\+\)\=\(lf\|LF\|f\|F\)\=" +syn match glslFloat display "\<\d\+[eE][+-]\=\d\+\(lf\|LF\|f\|F\)\=" +syn match glslFloat display "\<\d\+\.\d\+\([eE][+-]\=\d\+\)\=\(lf\|LF\|f\|F\)\=" + +" Swizzles +syn match glslSwizzle display /\.[xyzw]\{1,4\}\>/ +syn match glslSwizzle display /\.[rgba]\{1,4\}\>/ +syn match glslSwizzle display /\.[stpq]\{1,4\}\>/ + +" Structure +syn keyword glslStructure struct nextgroup=glslIdentifier skipwhite skipempty + +syn match glslIdentifier contains=glslIdentifierPrime "\%([a-zA-Z_]\)\%([a-zA-Z0-9_]\)*" display contained + +" Types +syn keyword glslType accelerationStructureEXT +syn keyword glslType atomic_uint +syn keyword glslType bool +syn keyword glslType bvec2 +syn keyword glslType bvec3 +syn keyword glslType bvec4 +syn keyword glslType dmat2 +syn keyword glslType dmat2x2 +syn keyword glslType dmat2x3 +syn keyword glslType dmat2x4 +syn keyword glslType dmat3 +syn keyword glslType dmat3x2 +syn keyword glslType dmat3x3 +syn keyword glslType dmat3x4 +syn keyword glslType dmat4 +syn keyword glslType dmat4x2 +syn keyword glslType dmat4x3 +syn keyword glslType dmat4x4 +syn keyword glslType double +syn keyword glslType dvec2 +syn keyword glslType dvec3 +syn keyword glslType dvec4 +syn keyword glslType float +syn keyword glslType iimage1D +syn keyword glslType iimage1DArray +syn keyword glslType iimage2D +syn keyword glslType iimage2DArray +syn keyword glslType iimage2DMS +syn keyword glslType iimage2DMSArray +syn keyword glslType iimage2DRect +syn keyword glslType iimage3D +syn keyword glslType iimageBuffer +syn keyword glslType iimageCube +syn keyword glslType iimageCubeArray +syn keyword glslType image1D +syn keyword glslType image1DArray +syn keyword glslType image2D +syn keyword glslType image2DArray +syn keyword glslType image2DMS +syn keyword glslType image2DMSArray +syn keyword glslType image2DRect +syn keyword glslType image3D +syn keyword glslType imageBuffer +syn keyword glslType imageCube +syn keyword glslType imageCubeArray +syn keyword glslType int +syn keyword glslType isampler1D +syn keyword glslType isampler1DArray +syn keyword glslType isampler2D +syn keyword glslType isampler2DArray +syn keyword glslType isampler2DMS +syn keyword glslType isampler2DMSArray +syn keyword glslType isampler2DRect +syn keyword glslType isampler3D +syn keyword glslType isamplerBuffer +syn keyword glslType isamplerCube +syn keyword glslType isamplerCubeArray +syn keyword glslType ivec2 +syn keyword glslType ivec3 +syn keyword glslType ivec4 +syn keyword glslType mat2 +syn keyword glslType mat2x2 +syn keyword glslType mat2x3 +syn keyword glslType mat2x4 +syn keyword glslType mat3 +syn keyword glslType mat3x2 +syn keyword glslType mat3x3 +syn keyword glslType mat3x4 +syn keyword glslType mat4 +syn keyword glslType mat4x2 +syn keyword glslType mat4x3 +syn keyword glslType mat4x4 +syn keyword glslType rayQueryEXT +syn keyword glslType sampler1D +syn keyword glslType sampler1DArray +syn keyword glslType sampler1DArrayShadow +syn keyword glslType sampler1DShadow +syn keyword glslType sampler2D +syn keyword glslType sampler2DArray +syn keyword glslType sampler2DArrayShadow +syn keyword glslType sampler2DMS +syn keyword glslType sampler2DMSArray +syn keyword glslType sampler2DRect +syn keyword glslType sampler2DRectShadow +syn keyword glslType sampler2DShadow +syn keyword glslType sampler3D +syn keyword glslType samplerBuffer +syn keyword glslType samplerCube +syn keyword glslType samplerCubeArray +syn keyword glslType samplerCubeArrayShadow +syn keyword glslType samplerCubeShadow +syn keyword glslType uimage1D +syn keyword glslType uimage1DArray +syn keyword glslType uimage2D +syn keyword glslType uimage2DArray +syn keyword glslType uimage2DMS +syn keyword glslType uimage2DMSArray +syn keyword glslType uimage2DRect +syn keyword glslType uimage3D +syn keyword glslType uimageBuffer +syn keyword glslType uimageCube +syn keyword glslType uimageCubeArray +syn keyword glslType uint +syn keyword glslType usampler1D +syn keyword glslType usampler1DArray +syn keyword glslType usampler2D +syn keyword glslType usampler2DArray +syn keyword glslType usampler2DMS +syn keyword glslType usampler2DMSArray +syn keyword glslType usampler2DRect +syn keyword glslType usampler3D +syn keyword glslType usamplerBuffer +syn keyword glslType usamplerCube +syn keyword glslType usamplerCubeArray +syn keyword glslType uvec2 +syn keyword glslType uvec3 +syn keyword glslType uvec4 +syn keyword glslType vec2 +syn keyword glslType vec3 +syn keyword glslType vec4 +syn keyword glslType void + +" Qualifiers +syn keyword glslQualifier align +syn keyword glslQualifier attribute +syn keyword glslQualifier binding +syn keyword glslQualifier buffer +syn keyword glslQualifier callableDataEXT +syn keyword glslQualifier callableDataInEXT +syn keyword glslQualifier ccw +syn keyword glslQualifier centroid +syn keyword glslQualifier centroid varying +syn keyword glslQualifier coherent +syn keyword glslQualifier column_major +syn keyword glslQualifier const +syn keyword glslQualifier cw +syn keyword glslQualifier depth_any +syn keyword glslQualifier depth_greater +syn keyword glslQualifier depth_less +syn keyword glslQualifier depth_unchanged +syn keyword glslQualifier early_fragment_tests +syn keyword glslQualifier equal_spacing +syn keyword glslQualifier flat +syn keyword glslQualifier fractional_even_spacing +syn keyword glslQualifier fractional_odd_spacing +syn keyword glslQualifier highp +syn keyword glslQualifier hitAttributeEXT +syn keyword glslQualifier in +syn keyword glslQualifier index +syn keyword glslQualifier inout +syn keyword glslQualifier invariant +syn keyword glslQualifier invocations +syn keyword glslQualifier isolines +syn keyword glslQualifier layout +syn keyword glslQualifier line_strip +syn keyword glslQualifier lines +syn keyword glslQualifier lines_adjacency +syn keyword glslQualifier local_size_x +syn keyword glslQualifier local_size_y +syn keyword glslQualifier local_size_z +syn keyword glslQualifier location +syn keyword glslQualifier lowp +syn keyword glslQualifier max_vertices +syn keyword glslQualifier mediump +syn keyword glslQualifier nonuniformEXT +syn keyword glslQualifier noperspective +syn keyword glslQualifier offset +syn keyword glslQualifier origin_upper_left +syn keyword glslQualifier out +syn keyword glslQualifier packed +syn keyword glslQualifier patch +syn keyword glslQualifier pixel_center_integer +syn keyword glslQualifier point_mode +syn keyword glslQualifier points +syn keyword glslQualifier precise +syn keyword glslQualifier precision +syn keyword glslQualifier quads +syn keyword glslQualifier r11f_g11f_b10f +syn keyword glslQualifier r16 +syn keyword glslQualifier r16_snorm +syn keyword glslQualifier r16f +syn keyword glslQualifier r16i +syn keyword glslQualifier r16ui +syn keyword glslQualifier r32f +syn keyword glslQualifier r32i +syn keyword glslQualifier r32ui +syn keyword glslQualifier r8 +syn keyword glslQualifier r8_snorm +syn keyword glslQualifier r8i +syn keyword glslQualifier r8ui +syn keyword glslQualifier rayPayloadEXT +syn keyword glslQualifier rayPayloadInEXT +syn keyword glslQualifier readonly +syn keyword glslQualifier restrict +syn keyword glslQualifier rg16 +syn keyword glslQualifier rg16_snorm +syn keyword glslQualifier rg16f +syn keyword glslQualifier rg16i +syn keyword glslQualifier rg16ui +syn keyword glslQualifier rg32f +syn keyword glslQualifier rg32i +syn keyword glslQualifier rg32ui +syn keyword glslQualifier rg8 +syn keyword glslQualifier rg8_snorm +syn keyword glslQualifier rg8i +syn keyword glslQualifier rg8ui +syn keyword glslQualifier rgb10_a2 +syn keyword glslQualifier rgb10_a2ui +syn keyword glslQualifier rgba16 +syn keyword glslQualifier rgba16_snorm +syn keyword glslQualifier rgba16f +syn keyword glslQualifier rgba16i +syn keyword glslQualifier rgba16ui +syn keyword glslQualifier rgba32f +syn keyword glslQualifier rgba32i +syn keyword glslQualifier rgba32ui +syn keyword glslQualifier rgba8 +syn keyword glslQualifier rgba8_snorm +syn keyword glslQualifier rgba8i +syn keyword glslQualifier rgba8ui +syn keyword glslQualifier row_major +syn keyword glslQualifier sample +syn keyword glslQualifier shaderRecordEXT +syn keyword glslQualifier shared +syn keyword glslQualifier smooth +syn keyword glslQualifier std140 +syn keyword glslQualifier std430 +syn keyword glslQualifier stream +syn keyword glslQualifier triangle_strip +syn keyword glslQualifier triangles +syn keyword glslQualifier triangles_adjacency +syn keyword glslQualifier uniform +syn keyword glslQualifier varying +syn keyword glslQualifier vertices +syn keyword glslQualifier volatile +syn keyword glslQualifier writeonly +syn keyword glslQualifier xfb_buffer +syn keyword glslQualifier xfb_offset +syn keyword glslQualifier xfb_stride + +" Built-in Constants +syn keyword glslBuiltinConstant gl_CullDistance +syn keyword glslBuiltinConstant gl_HitKindBackFacingTriangleEXT +syn keyword glslBuiltinConstant gl_HitKindFrontFacingTriangleEXT +syn keyword glslBuiltinConstant gl_MaxAtomicCounterBindings +syn keyword glslBuiltinConstant gl_MaxAtomicCounterBufferSize +syn keyword glslBuiltinConstant gl_MaxClipDistances +syn keyword glslBuiltinConstant gl_MaxClipPlanes +syn keyword glslBuiltinConstant gl_MaxCombinedAtomicCounterBuffers +syn keyword glslBuiltinConstant gl_MaxCombinedAtomicCounters +syn keyword glslBuiltinConstant gl_MaxCombinedClipAndCullDistances +syn keyword glslBuiltinConstant gl_MaxCombinedImageUniforms +syn keyword glslBuiltinConstant gl_MaxCombinedImageUnitsAndFragmentOutputs +syn keyword glslBuiltinConstant gl_MaxCombinedShaderOutputResources +syn keyword glslBuiltinConstant gl_MaxCombinedTextureImageUnits +syn keyword glslBuiltinConstant gl_MaxComputeAtomicCounterBuffers +syn keyword glslBuiltinConstant gl_MaxComputeAtomicCounters +syn keyword glslBuiltinConstant gl_MaxComputeImageUniforms +syn keyword glslBuiltinConstant gl_MaxComputeTextureImageUnits +syn keyword glslBuiltinConstant gl_MaxComputeUniformComponents +syn keyword glslBuiltinConstant gl_MaxComputeWorkGroupCount +syn keyword glslBuiltinConstant gl_MaxComputeWorkGroupSize +syn keyword glslBuiltinConstant gl_MaxCullDistances +syn keyword glslBuiltinConstant gl_MaxDrawBuffers +syn keyword glslBuiltinConstant gl_MaxFragmentAtomicCounterBuffers +syn keyword glslBuiltinConstant gl_MaxFragmentAtomicCounters +syn keyword glslBuiltinConstant gl_MaxFragmentImageUniforms +syn keyword glslBuiltinConstant gl_MaxFragmentInputComponents +syn keyword glslBuiltinConstant gl_MaxFragmentInputVectors +syn keyword glslBuiltinConstant gl_MaxFragmentUniformComponents +syn keyword glslBuiltinConstant gl_MaxFragmentUniformVectors +syn keyword glslBuiltinConstant gl_MaxGeometryAtomicCounterBuffers +syn keyword glslBuiltinConstant gl_MaxGeometryAtomicCounters +syn keyword glslBuiltinConstant gl_MaxGeometryImageUniforms +syn keyword glslBuiltinConstant gl_MaxGeometryInputComponents +syn keyword glslBuiltinConstant gl_MaxGeometryOutputComponents +syn keyword glslBuiltinConstant gl_MaxGeometryOutputVertices +syn keyword glslBuiltinConstant gl_MaxGeometryTextureImageUnits +syn keyword glslBuiltinConstant gl_MaxGeometryTotalOutputComponents +syn keyword glslBuiltinConstant gl_MaxGeometryUniformComponents +syn keyword glslBuiltinConstant gl_MaxGeometryVaryingComponents +syn keyword glslBuiltinConstant gl_MaxImageSamples +syn keyword glslBuiltinConstant gl_MaxImageUnits +syn keyword glslBuiltinConstant gl_MaxLights +syn keyword glslBuiltinConstant gl_MaxPatchVertices +syn keyword glslBuiltinConstant gl_MaxProgramTexelOffset +syn keyword glslBuiltinConstant gl_MaxSamples +syn keyword glslBuiltinConstant gl_MaxTessControlAtomicCounterBuffers +syn keyword glslBuiltinConstant gl_MaxTessControlAtomicCounters +syn keyword glslBuiltinConstant gl_MaxTessControlImageUniforms +syn keyword glslBuiltinConstant gl_MaxTessControlInputComponents +syn keyword glslBuiltinConstant gl_MaxTessControlOutputComponents +syn keyword glslBuiltinConstant gl_MaxTessControlTextureImageUnits +syn keyword glslBuiltinConstant gl_MaxTessControlTotalOutputComponents +syn keyword glslBuiltinConstant gl_MaxTessControlUniformComponents +syn keyword glslBuiltinConstant gl_MaxTessEvaluationAtomicCounterBuffers +syn keyword glslBuiltinConstant gl_MaxTessEvaluationAtomicCounters +syn keyword glslBuiltinConstant gl_MaxTessEvaluationImageUniforms +syn keyword glslBuiltinConstant gl_MaxTessEvaluationInputComponents +syn keyword glslBuiltinConstant gl_MaxTessEvaluationOutputComponents +syn keyword glslBuiltinConstant gl_MaxTessEvaluationTextureImageUnits +syn keyword glslBuiltinConstant gl_MaxTessEvaluationUniformComponents +syn keyword glslBuiltinConstant gl_MaxTessGenLevel +syn keyword glslBuiltinConstant gl_MaxTessPatchComponents +syn keyword glslBuiltinConstant gl_MaxTextureCoords +syn keyword glslBuiltinConstant gl_MaxTextureImageUnits +syn keyword glslBuiltinConstant gl_MaxTextureUnits +syn keyword glslBuiltinConstant gl_MaxTransformFeedbackBuffers +syn keyword glslBuiltinConstant gl_MaxTransformFeedbackInterleavedComponents +syn keyword glslBuiltinConstant gl_MaxVaryingComponents +syn keyword glslBuiltinConstant gl_MaxVaryingFloats +syn keyword glslBuiltinConstant gl_MaxVaryingVectors +syn keyword glslBuiltinConstant gl_MaxVertexAtomicCounterBuffers +syn keyword glslBuiltinConstant gl_MaxVertexAtomicCounters +syn keyword glslBuiltinConstant gl_MaxVertexAttribs +syn keyword glslBuiltinConstant gl_MaxVertexImageUniforms +syn keyword glslBuiltinConstant gl_MaxVertexOutputComponents +syn keyword glslBuiltinConstant gl_MaxVertexOutputVectors +syn keyword glslBuiltinConstant gl_MaxVertexTextureImageUnits +syn keyword glslBuiltinConstant gl_MaxVertexUniformComponents +syn keyword glslBuiltinConstant gl_MaxVertexUniformVectors +syn keyword glslBuiltinConstant gl_MaxViewports +syn keyword glslBuiltinConstant gl_MinProgramTexelOffset +syn keyword glslBuiltinConstant gl_RayFlagsCullBackFacingTrianglesEXT +syn keyword glslBuiltinConstant gl_RayFlagsCullFrontFacingTrianglesEXT +syn keyword glslBuiltinConstant gl_RayFlagsCullNoOpaqueEXT +syn keyword glslBuiltinConstant gl_RayFlagsCullOpaqueEXT +syn keyword glslBuiltinConstant gl_RayFlagsNoOpaqueEXT +syn keyword glslBuiltinConstant gl_RayFlagsNoneEXT +syn keyword glslBuiltinConstant gl_RayFlagsOpaqueEXT +syn keyword glslBuiltinConstant gl_RayFlagsSkipClosestHitShaderEXT +syn keyword glslBuiltinConstant gl_RayFlagsTerminateOnFirstHitEXT +syn keyword glslBuiltinConstant gl_RayQueryCandidateIntersectionAABBEXT +syn keyword glslBuiltinConstant gl_RayQueryCandidateIntersectionTriangleEXT +syn keyword glslBuiltinConstant gl_RayQueryCommittedIntersectionGeneratedEXT +syn keyword glslBuiltinConstant gl_RayQueryCommittedIntersectionNoneEXT +syn keyword glslBuiltinConstant gl_RayQueryCommittedIntersectionTriangleEXT + +" Built-in Variables +syn keyword glslBuiltinVariable gl_BackColor +syn keyword glslBuiltinVariable gl_BackLightModelProduct +syn keyword glslBuiltinVariable gl_BackLightProduct +syn keyword glslBuiltinVariable gl_BackLightProduct +syn keyword glslBuiltinVariable gl_BackMaterial +syn keyword glslBuiltinVariable gl_BackSecondaryColor +syn keyword glslBuiltinVariable gl_ClipDistance +syn keyword glslBuiltinVariable gl_ClipPlane +syn keyword glslBuiltinVariable gl_ClipVertex +syn keyword glslBuiltinVariable gl_Color +syn keyword glslBuiltinVariable gl_DepthRange +syn keyword glslBuiltinVariable gl_EyePlaneQ +syn keyword glslBuiltinVariable gl_EyePlaneR +syn keyword glslBuiltinVariable gl_EyePlaneS +syn keyword glslBuiltinVariable gl_EyePlaneT +syn keyword glslBuiltinVariable gl_Fog +syn keyword glslBuiltinVariable gl_FogCoord +syn keyword glslBuiltinVariable gl_FogFragCoord +syn keyword glslBuiltinVariable gl_FragColor +syn keyword glslBuiltinVariable gl_FragCoord +syn keyword glslBuiltinVariable gl_FragData +syn keyword glslBuiltinVariable gl_FragDepth +syn keyword glslBuiltinVariable gl_FrontColor +syn keyword glslBuiltinVariable gl_FrontFacing +syn keyword glslBuiltinVariable gl_FrontLightModelProduct +syn keyword glslBuiltinVariable gl_FrontLightProduct +syn keyword glslBuiltinVariable gl_FrontMaterial +syn keyword glslBuiltinVariable gl_FrontSecondaryColor +syn keyword glslBuiltinVariable gl_GeometryIndexEXT +syn keyword glslBuiltinVariable gl_GlobalInvocationID +syn keyword glslBuiltinVariable gl_HelperInvocation +syn keyword glslBuiltinVariable gl_HitKindEXT +syn keyword glslBuiltinVariable gl_HitTEXT +syn keyword glslBuiltinVariable gl_IncomingRayFlagsEXT +syn keyword glslBuiltinVariable gl_InstanceCustomIndexEXT +syn keyword glslBuiltinVariable gl_InstanceID +syn keyword glslBuiltinVariable gl_InstanceID +syn keyword glslBuiltinVariable gl_InvocationID +syn keyword glslBuiltinVariable gl_LaunchIDEXT +syn keyword glslBuiltinVariable gl_LaunchSizeEXT +syn keyword glslBuiltinVariable gl_Layer +syn keyword glslBuiltinVariable gl_LightModel +syn keyword glslBuiltinVariable gl_LightSource +syn keyword glslBuiltinVariable gl_LocalInvocationID +syn keyword glslBuiltinVariable gl_LocalInvocationIndex +syn keyword glslBuiltinVariable gl_ModelViewMatrix +syn keyword glslBuiltinVariable gl_ModelViewMatrixInverse +syn keyword glslBuiltinVariable gl_ModelViewMatrixInverseTranspose +syn keyword glslBuiltinVariable gl_ModelViewMatrixTranspose +syn keyword glslBuiltinVariable gl_ModelViewProjectionMatrix +syn keyword glslBuiltinVariable gl_ModelViewProjectionMatrixInverse +syn keyword glslBuiltinVariable gl_ModelViewProjectionMatrixInverseTranspose +syn keyword glslBuiltinVariable gl_ModelViewProjectionMatrixTranspose +syn keyword glslBuiltinVariable gl_MultiTexCoord0 +syn keyword glslBuiltinVariable gl_MultiTexCoord1 +syn keyword glslBuiltinVariable gl_MultiTexCoord2 +syn keyword glslBuiltinVariable gl_MultiTexCoord3 +syn keyword glslBuiltinVariable gl_MultiTexCoord4 +syn keyword glslBuiltinVariable gl_MultiTexCoord5 +syn keyword glslBuiltinVariable gl_MultiTexCoord6 +syn keyword glslBuiltinVariable gl_MultiTexCoord7 +syn keyword glslBuiltinVariable gl_Normal +syn keyword glslBuiltinVariable gl_NormalMatrix +syn keyword glslBuiltinVariable gl_NormalScale +syn keyword glslBuiltinVariable gl_NumSamples +syn keyword glslBuiltinVariable gl_NumWorkGroups +syn keyword glslBuiltinVariable gl_ObjectPlaneQ +syn keyword glslBuiltinVariable gl_ObjectPlaneR +syn keyword glslBuiltinVariable gl_ObjectPlaneS +syn keyword glslBuiltinVariable gl_ObjectPlaneT +syn keyword glslBuiltinVariable gl_ObjectRayDirectionEXT +syn keyword glslBuiltinVariable gl_ObjectRayOriginEXT +syn keyword glslBuiltinVariable gl_ObjectToWorld3x4EXT +syn keyword glslBuiltinVariable gl_ObjectToWorldEXT +syn keyword glslBuiltinVariable gl_PatchVerticesIn +syn keyword glslBuiltinVariable gl_Point +syn keyword glslBuiltinVariable gl_PointCoord +syn keyword glslBuiltinVariable gl_PointSize +syn keyword glslBuiltinVariable gl_Position +syn keyword glslBuiltinVariable gl_PrimitiveID +syn keyword glslBuiltinVariable gl_PrimitiveID +syn keyword glslBuiltinVariable gl_PrimitiveIDIn +syn keyword glslBuiltinVariable gl_ProjectionMatrix +syn keyword glslBuiltinVariable gl_ProjectionMatrixInverse +syn keyword glslBuiltinVariable gl_ProjectionMatrixInverseTranspose +syn keyword glslBuiltinVariable gl_ProjectionMatrixTranspose +syn keyword glslBuiltinVariable gl_RayTmaxEXT +syn keyword glslBuiltinVariable gl_RayTminEXT +syn keyword glslBuiltinVariable gl_SampleID +syn keyword glslBuiltinVariable gl_SampleMask +syn keyword glslBuiltinVariable gl_SampleMaskIn +syn keyword glslBuiltinVariable gl_SamplePosition +syn keyword glslBuiltinVariable gl_SecondaryColor +syn keyword glslBuiltinVariable gl_TessCoord +syn keyword glslBuiltinVariable gl_TessLevelInner +syn keyword glslBuiltinVariable gl_TessLevelOuter +syn keyword glslBuiltinVariable gl_TexCoord +syn keyword glslBuiltinVariable gl_TextureEnvColor +syn keyword glslBuiltinVariable gl_TextureMatrix +syn keyword glslBuiltinVariable gl_TextureMatrixInverse +syn keyword glslBuiltinVariable gl_TextureMatrixInverseTranspose +syn keyword glslBuiltinVariable gl_TextureMatrixTranspose +syn keyword glslBuiltinVariable gl_Vertex +syn keyword glslBuiltinVariable gl_VertexID +syn keyword glslBuiltinVariable gl_VertexIndex +syn keyword glslBuiltinVariable gl_ViewportIndex +syn keyword glslBuiltinVariable gl_WorkGroupID +syn keyword glslBuiltinVariable gl_WorkGroupSize +syn keyword glslBuiltinVariable gl_WorldRayDirectionEXT +syn keyword glslBuiltinVariable gl_WorldRayOriginEXT +syn keyword glslBuiltinVariable gl_WorldToObject3x4EXT +syn keyword glslBuiltinVariable gl_WorldToObjectEXT +syn keyword glslBuiltinVariable gl_in +syn keyword glslBuiltinVariable gl_out + +" Built-in Functions +syn keyword glslBuiltinFunction EmitStreamVertex +syn keyword glslBuiltinFunction EmitVertex +syn keyword glslBuiltinFunction EndPrimitive +syn keyword glslBuiltinFunction EndStreamPrimitive +syn keyword glslBuiltinFunction abs +syn keyword glslBuiltinFunction acos +syn keyword glslBuiltinFunction acosh +syn keyword glslBuiltinFunction all +syn keyword glslBuiltinFunction any +syn keyword glslBuiltinFunction asin +syn keyword glslBuiltinFunction asinh +syn keyword glslBuiltinFunction atan +syn keyword glslBuiltinFunction atanh +syn keyword glslBuiltinFunction atomicAdd +syn keyword glslBuiltinFunction atomicAnd +syn keyword glslBuiltinFunction atomicCompSwap +syn keyword glslBuiltinFunction atomicCounter +syn keyword glslBuiltinFunction atomicCounterDecrement +syn keyword glslBuiltinFunction atomicCounterIncrement +syn keyword glslBuiltinFunction atomicExchange +syn keyword glslBuiltinFunction atomicMax +syn keyword glslBuiltinFunction atomicMin +syn keyword glslBuiltinFunction atomicOr +syn keyword glslBuiltinFunction atomicXor +syn keyword glslBuiltinFunction barrier +syn keyword glslBuiltinFunction bitCount +syn keyword glslBuiltinFunction bitfieldExtract +syn keyword glslBuiltinFunction bitfieldInsert +syn keyword glslBuiltinFunction bitfieldReverse +syn keyword glslBuiltinFunction ceil +syn keyword glslBuiltinFunction clamp +syn keyword glslBuiltinFunction cos +syn keyword glslBuiltinFunction cosh +syn keyword glslBuiltinFunction cross +syn keyword glslBuiltinFunction dFdx +syn keyword glslBuiltinFunction dFdxCoarse +syn keyword glslBuiltinFunction dFdxFine +syn keyword glslBuiltinFunction dFdy +syn keyword glslBuiltinFunction dFdyCoarse +syn keyword glslBuiltinFunction dFdyFine +syn keyword glslBuiltinFunction degrees +syn keyword glslBuiltinFunction determinant +syn keyword glslBuiltinFunction distance +syn keyword glslBuiltinFunction dot +syn keyword glslBuiltinFunction equal +syn keyword glslBuiltinFunction executeCallableEXT +syn keyword glslBuiltinFunction exp +syn keyword glslBuiltinFunction exp2 +syn keyword glslBuiltinFunction faceforward +syn keyword glslBuiltinFunction findLSB +syn keyword glslBuiltinFunction findMSB +syn keyword glslBuiltinFunction floatBitsToInt +syn keyword glslBuiltinFunction floatBitsToUint +syn keyword glslBuiltinFunction floor +syn keyword glslBuiltinFunction fma +syn keyword glslBuiltinFunction fract +syn keyword glslBuiltinFunction frexp +syn keyword glslBuiltinFunction ftransform +syn keyword glslBuiltinFunction fwidth +syn keyword glslBuiltinFunction fwidthCoarse +syn keyword glslBuiltinFunction fwidthFine +syn keyword glslBuiltinFunction greaterThan +syn keyword glslBuiltinFunction greaterThanEqual +syn keyword glslBuiltinFunction groupMemoryBarrier +syn keyword glslBuiltinFunction ignoreIntersectionEXT +syn keyword glslBuiltinFunction imageAtomicAdd +syn keyword glslBuiltinFunction imageAtomicAnd +syn keyword glslBuiltinFunction imageAtomicCompSwap +syn keyword glslBuiltinFunction imageAtomicExchange +syn keyword glslBuiltinFunction imageAtomicMax +syn keyword glslBuiltinFunction imageAtomicMin +syn keyword glslBuiltinFunction imageAtomicOr +syn keyword glslBuiltinFunction imageAtomicXor +syn keyword glslBuiltinFunction imageLoad +syn keyword glslBuiltinFunction imageSize +syn keyword glslBuiltinFunction imageStore +syn keyword glslBuiltinFunction imulExtended +syn keyword glslBuiltinFunction intBitsToFloat +syn keyword glslBuiltinFunction interpolateAtCentroid +syn keyword glslBuiltinFunction interpolateAtOffset +syn keyword glslBuiltinFunction interpolateAtSample +syn keyword glslBuiltinFunction inverse +syn keyword glslBuiltinFunction inversesqrt +syn keyword glslBuiltinFunction isinf +syn keyword glslBuiltinFunction isnan +syn keyword glslBuiltinFunction ldexp +syn keyword glslBuiltinFunction length +syn keyword glslBuiltinFunction lessThan +syn keyword glslBuiltinFunction lessThanEqual +syn keyword glslBuiltinFunction log +syn keyword glslBuiltinFunction log2 +syn keyword glslBuiltinFunction matrixCompMult +syn keyword glslBuiltinFunction max +syn keyword glslBuiltinFunction memoryBarrier +syn keyword glslBuiltinFunction memoryBarrierAtomicCounter +syn keyword glslBuiltinFunction memoryBarrierBuffer +syn keyword glslBuiltinFunction memoryBarrierImage +syn keyword glslBuiltinFunction memoryBarrierShared +syn keyword glslBuiltinFunction min +syn keyword glslBuiltinFunction mix +syn keyword glslBuiltinFunction mod +syn keyword glslBuiltinFunction modf +syn keyword glslBuiltinFunction noise1 +syn keyword glslBuiltinFunction noise2 +syn keyword glslBuiltinFunction noise3 +syn keyword glslBuiltinFunction noise4 +syn keyword glslBuiltinFunction normalize +syn keyword glslBuiltinFunction not +syn keyword glslBuiltinFunction notEqual +syn keyword glslBuiltinFunction outerProduct +syn keyword glslBuiltinFunction packDouble2x32 +syn keyword glslBuiltinFunction packHalf2x16 +syn keyword glslBuiltinFunction packSnorm2x16 +syn keyword glslBuiltinFunction packSnorm4x8 +syn keyword glslBuiltinFunction packUnorm2x16 +syn keyword glslBuiltinFunction packUnorm4x8 +syn keyword glslBuiltinFunction pow +syn keyword glslBuiltinFunction radians +syn keyword glslBuiltinFunction rayQueryConfirmIntersectionEXT +syn keyword glslBuiltinFunction rayQueryGenerateIntersectionEXT +syn keyword glslBuiltinFunction rayQueryGetIntersectionBarycentricsEXT +syn keyword glslBuiltinFunction rayQueryGetIntersectionCandidateAABBOpaqueEXT +syn keyword glslBuiltinFunction rayQueryGetIntersectionFrontFaceEXT +syn keyword glslBuiltinFunction rayQueryGetIntersectionGeometryIndexEXT +syn keyword glslBuiltinFunction rayQueryGetIntersectionInstanceCustomIndexEXT +syn keyword glslBuiltinFunction rayQueryGetIntersectionInstanceIdEXT +syn keyword glslBuiltinFunction rayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetEXT +syn keyword glslBuiltinFunction rayQueryGetIntersectionObjectRayDirectionEXT +syn keyword glslBuiltinFunction rayQueryGetIntersectionObjectRayOriginEXT +syn keyword glslBuiltinFunction rayQueryGetIntersectionObjectToWorldEXT +syn keyword glslBuiltinFunction rayQueryGetIntersectionPrimitiveIndexEXT +syn keyword glslBuiltinFunction rayQueryGetIntersectionTEXT +syn keyword glslBuiltinFunction rayQueryGetIntersectionTypeEXT +syn keyword glslBuiltinFunction rayQueryGetIntersectionWorldToObjectEXT +syn keyword glslBuiltinFunction rayQueryGetRayFlagsEXT +syn keyword glslBuiltinFunction rayQueryGetRayTMinEXT +syn keyword glslBuiltinFunction rayQueryGetWorldRayDirectionEXT +syn keyword glslBuiltinFunction rayQueryGetWorldRayOriginEXT +syn keyword glslBuiltinFunction rayQueryInitializeEXT +syn keyword glslBuiltinFunction rayQueryProceedEXT +syn keyword glslBuiltinFunction rayQueryTerminateEXT +syn keyword glslBuiltinFunction reflect +syn keyword glslBuiltinFunction refract +syn keyword glslBuiltinFunction reportIntersectionEXT +syn keyword glslBuiltinFunction round +syn keyword glslBuiltinFunction roundEven +syn keyword glslBuiltinFunction shadow1D +syn keyword glslBuiltinFunction shadow1DLod +syn keyword glslBuiltinFunction shadow1DProj +syn keyword glslBuiltinFunction shadow1DProjLod +syn keyword glslBuiltinFunction shadow2D +syn keyword glslBuiltinFunction shadow2DLod +syn keyword glslBuiltinFunction shadow2DProj +syn keyword glslBuiltinFunction shadow2DProjLod +syn keyword glslBuiltinFunction sign +syn keyword glslBuiltinFunction sin +syn keyword glslBuiltinFunction sinh +syn keyword glslBuiltinFunction smoothstep +syn keyword glslBuiltinFunction sqrt +syn keyword glslBuiltinFunction step +syn keyword glslBuiltinFunction tan +syn keyword glslBuiltinFunction tanh +syn keyword glslBuiltinFunction terminateRayEXT +syn keyword glslBuiltinFunction texelFetch +syn keyword glslBuiltinFunction texelFetchOffset +syn keyword glslBuiltinFunction texture +syn keyword glslBuiltinFunction texture1D +syn keyword glslBuiltinFunction texture1DLod +syn keyword glslBuiltinFunction texture1DProj +syn keyword glslBuiltinFunction texture1DProjLod +syn keyword glslBuiltinFunction texture2D +syn keyword glslBuiltinFunction texture2DLod +syn keyword glslBuiltinFunction texture2DProj +syn keyword glslBuiltinFunction texture2DProjLod +syn keyword glslBuiltinFunction texture3D +syn keyword glslBuiltinFunction texture3DLod +syn keyword glslBuiltinFunction texture3DProj +syn keyword glslBuiltinFunction texture3DProjLod +syn keyword glslBuiltinFunction textureCube +syn keyword glslBuiltinFunction textureCubeLod +syn keyword glslBuiltinFunction textureGather +syn keyword glslBuiltinFunction textureGatherOffset +syn keyword glslBuiltinFunction textureGatherOffsets +syn keyword glslBuiltinFunction textureGrad +syn keyword glslBuiltinFunction textureGradOffset +syn keyword glslBuiltinFunction textureLod +syn keyword glslBuiltinFunction textureLodOffset +syn keyword glslBuiltinFunction textureOffset +syn keyword glslBuiltinFunction textureProj +syn keyword glslBuiltinFunction textureProjGrad +syn keyword glslBuiltinFunction textureProjGradOffset +syn keyword glslBuiltinFunction textureProjLod +syn keyword glslBuiltinFunction textureProjLodOffset +syn keyword glslBuiltinFunction textureProjOffset +syn keyword glslBuiltinFunction textureQueryLevels +syn keyword glslBuiltinFunction textureQueryLod +syn keyword glslBuiltinFunction textureSize +syn keyword glslBuiltinFunction traceRayEXT +syn keyword glslBuiltinFunction transpose +syn keyword glslBuiltinFunction trunc +syn keyword glslBuiltinFunction uaddCarry +syn keyword glslBuiltinFunction uintBitsToFloat +syn keyword glslBuiltinFunction umulExtended +syn keyword glslBuiltinFunction unpackDouble2x32 +syn keyword glslBuiltinFunction unpackHalf2x16 +syn keyword glslBuiltinFunction unpackSnorm2x16 +syn keyword glslBuiltinFunction unpackSnorm4x8 +syn keyword glslBuiltinFunction unpackUnorm2x16 +syn keyword glslBuiltinFunction unpackUnorm4x8 +syn keyword glslBuiltinFunction usubBorrow + +hi def link glslConditional Conditional +hi def link glslRepeat Repeat +hi def link glslStatement Statement +hi def link glslTodo Todo +hi def link glslCommentL glslComment +hi def link glslCommentStart glslComment +hi def link glslComment Comment +hi def link glslPreCondit PreCondit +hi def link glslDefine Define +hi def link glslTokenConcat glslPreProc +hi def link glslPredefinedMacro Macro +hi def link glslPreProc PreProc +hi def link glslInclude Include +hi def link glslBoolean Boolean +hi def link glslDecimalInt glslInteger +hi def link glslOctalInt glslInteger +hi def link glslHexInt glslInteger +hi def link glslInteger Number +hi def link glslFloat Float +hi def link glslIdentifierPrime glslIdentifier +hi def link glslIdentifier Identifier +hi def link glslStructure Structure +hi def link glslType Type +hi def link glslQualifier StorageClass +hi def link glslBuiltinConstant Constant +hi def link glslBuiltinFunction Function +hi def link glslBuiltinVariable Identifier +hi def link glslSwizzle Identifier + +let b:current_syntax = 'glsl' diff --git a/runtime/syntax/goaccess.vim b/runtime/syntax/goaccess.vim new file mode 100644 index 0000000000..4ca8f6d921 --- /dev/null +++ b/runtime/syntax/goaccess.vim @@ -0,0 +1,34 @@ +" Vim syntax file +" Language: GoAccess configuration +" Maintainer: Adam Monsen <haircut@gmail.com> +" Last Change: 2024 Aug 1 +" Remark: see https://goaccess.io/man#configuration +" +" The GoAccess configuration file syntax is line-separated settings. Settings +" are space-separated key value pairs. Comments are any line starting with a +" hash mark. +" Example: https://github.com/allinurl/goaccess/blob/master/config/goaccess.conf +" +" This syntax definition supports todo/fixme highlighting in comments, and +" special (Keyword) highlighting if a setting's value is 'true' or 'false'. +" +" TODO: a value is required, so use extreme highlighting (e.g. bright red +" background) if a setting is missing a value. + +if exists("b:current_syntax") + finish +endif + +syn match goaccessSettingName '^[a-z-]\+' nextgroup=goaccessSettingValue +syn match goaccessSettingValue '\s\+.\+$' contains=goaccessKeyword +syn match goaccessComment "^#.*$" contains=goaccessTodo,@Spell +syn keyword goaccessTodo TODO FIXME contained +syn keyword goaccessKeyword true false contained + +hi def link goaccessSettingName Type +hi def link goaccessSettingValue String +hi def link goaccessComment Comment +hi def link goaccessTodo Todo +hi def link goaccessKeyword Keyword + +let b:current_syntax = "goaccess" diff --git a/runtime/syntax/hare.vim b/runtime/syntax/hare.vim index 07cf33fb11..4c7ae92486 100644 --- a/runtime/syntax/hare.vim +++ b/runtime/syntax/hare.vim @@ -1,119 +1,142 @@ -" PRELUDE {{{1 -" Vim syntax file -" Language: Hare -" Maintainer: Amelia Clarke <me@rsaihe.dev> -" Last Change: 2022-09-21 +" Vim syntax file. +" Language: Hare +" Maintainer: Amelia Clarke <selene@perilune.dev> +" Last Change: 2024-05-10 +" Upstream: https://git.sr.ht/~sircmpwn/hare.vim -if exists("b:current_syntax") +if exists('b:current_syntax') finish endif -let b:current_syntax = "hare" +syn include @haredoc syntax/haredoc.vim +let b:current_syntax = 'hare' -" SYNTAX {{{1 +" Syntax {{{1 syn case match +syn iskeyword @,48-57,@-@,_ -" KEYWORDS {{{2 -syn keyword hareConditional if else match switch +" Keywords {{{2 +syn keyword hareConditional else if match switch +syn keyword hareDefine def +syn keyword hareInclude use syn keyword hareKeyword break continue return yield +syn keyword hareKeyword case +syn keyword hareKeyword const let syn keyword hareKeyword defer +syn keyword hareKeyword export static syn keyword hareKeyword fn -syn keyword hareKeyword let -syn keyword hareLabel case syn keyword hareOperator as is syn keyword hareRepeat for -syn keyword hareStorageClass const def export nullable static -syn keyword hareStructure enum struct union syn keyword hareTypedef type -" C ABI. -syn keyword hareKeyword vastart vaarg vaend - -" BUILTINS {{{2 -syn keyword hareBuiltin abort +" Attributes. +syn keyword hareAttribute @fini @init @test +syn keyword hareAttribute @offset @packed +syn keyword hareAttribute @symbol +syn keyword hareAttribute @threadlocal + +" Builtins. +syn keyword hareBuiltin abort assert +syn keyword hareBuiltin align len offset syn keyword hareBuiltin alloc free syn keyword hareBuiltin append delete insert -syn keyword hareBuiltin assert -syn keyword hareBuiltin len offset +syn keyword hareBuiltin vaarg vaend vastart -" TYPES {{{2 +" Types {{{2 syn keyword hareType bool -syn keyword hareType char str +syn keyword hareType done syn keyword hareType f32 f64 -syn keyword hareType u8 u16 u32 u64 i8 i16 i32 i64 -syn keyword hareType uint int -syn keyword hareType rune +syn keyword hareType i8 i16 i32 i64 int +syn keyword hareType never +syn keyword hareType opaque +syn keyword hareType rune str +syn keyword hareType u8 u16 u32 u64 uint syn keyword hareType uintptr +syn keyword hareType valist syn keyword hareType void -" C ABI. -syn keyword hareType valist +" Other types. +syn keyword hareStorageClass nullable +syn keyword hareStructure enum struct union -" LITERALS {{{2 -syn keyword hareBoolean true false -syn keyword hareNull null - -" Number literals. -syn match hareNumber "\v(\.@1<!|\.\.)\zs<\d+([Ee][+-]?\d+)?(z|[iu](8|16|32|64)?)?>" display -syn match hareNumber "\v(\.@1<!|\.\.)\zs<0b[01]+(z|[iu](8|16|32|64)?)?>" display -syn match hareNumber "\v(\.@1<!|\.\.)\zs<0o\o+(z|[iu](8|16|32|64)?)?>" display -syn match hareNumber "\v(\.@1<!|\.\.)\zs<0x\x+(z|[iu](8|16|32|64)?)?>" display - -" Floating-point number literals. -syn match hareFloat "\v<\d+\.\d+([Ee][+-]?\d+)?(f32|f64)?>" display -syn match hareFloat "\v<\d+([Ee][+-]?\d+)?(f32|f64)>" display - -" String and rune literals. -syn match hareEscape "\\[\\'"0abfnrtv]" contained display -syn match hareEscape "\v\\(x\x{2}|u\x{4}|U\x{8})" contained display -syn match hareFormat "\v\{\d*(\%\d*|(:[ 0+-]?\d*(\.\d+)?[Xbox]?))?}" contained display -syn match hareFormat "\({{\|}}\)" contained display -syn region hareRune start="'" end="'\|$" skip="\\'" contains=hareEscape display extend -syn region hareString start=+"+ end=+"\|$+ skip=+\\"+ contains=hareEscape,hareFormat display extend -syn region hareString start="`" end="`\|$" contains=hareFormat display - -" MISCELLANEOUS {{{2 -syn keyword hareTodo FIXME TODO XXX contained +" Literals {{{2 +syn keyword hareBoolean false true +syn keyword hareConstant null -" Attributes. -syn match hareAttribute "@[a-z]*" +" Integer literals. +syn match hareNumber '\v<%(0|[1-9]%(_?\d)*)%([Ee]\+?\d+)?%([iu]%(8|16|32|64)?|z)?>' display +syn match hareNumber '\v<0b[01]%(_?[01])*%([iu]%(8|16|32|64)?|z)?>' display +syn match hareNumber '\v<0o\o%(_?\o)*%([iu]%(8|16|32|64)?|z)?>' display +syn match hareNumber '\v<0x\x%(_?\x)*%([iu]%(8|16|32|64)?|z)?>' display -" Blocks. -syn region hareBlock start="{" end="}" fold transparent +" Floating-point literals. +syn match hareFloat '\v<%(0|[1-9]%(_?\d)*)\.\d%(_?\d)*%([Ee][+-]?\d+)?%(f32|f64)?>' display +syn match hareFloat '\v<%(0|[1-9]%(_?\d)*)%([Ee][+-]?\d+)?%(f32|f64)>' display +syn match hareFloat '\v<0x\x%(_?\x)*%(\.\x%(_?\x)*)?[Pp][+-]?\d+%(f32|f64)?>' display + +" Rune and string literals. +syn region hareRune start="'" skip="\\'" end="'" contains=hareEscape +syn region hareString start='"' skip='\\"' end='"' contains=hareEscape,hareFormat +syn region hareString start='`' end='`' contains=hareFormat + +" Escape sequences. +syn match hareEscape '\\[0abfnrtv\\'"]' contained +syn match hareEscape '\v\\%(x\x{2}|u\x{4}|U\x{8})' contained display + +" Format sequences. +syn match hareFormat '\v\{\d*%(:%(\.?\d+|[ +\-=Xbefgox]|F[.2ESUs]|_%(.|\\%([0abfnrtv\\'"]|x\x{2}|u\x{4}|U\x{8})))*)?}' contained contains=hareEscape display +syn match hareFormat '{\d*%\d*}' contained display +syn match hareFormat '{{\|}}' contained display + +" Miscellaneous {{{2 " Comments. -syn region hareComment start="//" end="$" contains=hareCommentDoc,hareTodo,@Spell display keepend -syn region hareCommentDoc start="\[\[" end="]]\|\ze\_s" contained display +syn region hareComment start='//' end='$' contains=hareTodo,@haredoc,@Spell display +syn keyword hareTodo FIXME TODO XXX contained + +" Identifiers. +syn match hareDelimiter '::' display +syn match hareName '\<\h\w*\>' nextgroup=@harePostfix skipempty skipwhite transparent -" The size keyword can be either a builtin or a type. -syn match hareBuiltin "\v<size>\ze(\_s*//.*\_$)*\_s*\(" contains=hareComment -syn match hareType "\v<size>((\_s*//.*\_$)*\_s*\()@!" contains=hareComment +" Labels. +syn match hareLabel ':\h\w*\>' display -" Trailing whitespace. -syn match hareSpaceError "\v\s+$" display excludenl -syn match hareSpaceError "\v\zs +\ze\t" display +" Match `size` as a type unless it is followed by an open paren. +syn match hareType '\<size\>' display +syn match hareBuiltin '\<size\ze(' display -" Use statement. -syn region hareUse start="\v^\s*\zsuse>" end=";" contains=hareComment display +" Postfix expressions. +syn cluster harePostfix contains=hareErrorTest,hareField,hareIndex,hareParens +syn match hareErrorTest '!=\@!' contained nextgroup=@harePostfix skipempty skipwhite +syn match hareErrorTest '?' nextgroup=@harePostfix skipempty skipwhite +syn match hareField '\.\w*\>'hs=s+1 contained contains=hareNumber nextgroup=@harePostfix skipempty skipwhite +syn region hareIndex start='\[' end=']' contained nextgroup=@harePostfix skipempty skipwhite transparent +syn region hareParens start='(' end=')' nextgroup=@harePostfix skipempty skipwhite transparent -syn match hareErrorAssertion "\v(^([^/]|//@!)*\)\_s*)@<=!\=@!" -syn match hareQuestionMark "?" +" Whitespace errors. +syn match hareSpaceError '^ \+\ze\t' display +syn match hareSpaceError excludenl '\s\+$' containedin=ALL display -" DEFAULT HIGHLIGHTING {{{1 -hi def link hareAttribute Keyword +" Folding {{{3 +syn region hareBlock start='{' end='}' fold transparent + +" Default highlighting {{{1 +hi def link hareAttribute PreProc hi def link hareBoolean Boolean -hi def link hareBuiltin Function +hi def link hareBuiltin Operator hi def link hareComment Comment -hi def link hareCommentDoc SpecialComment hi def link hareConditional Conditional +hi def link hareConstant Constant +hi def link hareDefine Define +hi def link hareDelimiter Delimiter +hi def link hareErrorTest Special hi def link hareEscape SpecialChar hi def link hareFloat Float hi def link hareFormat SpecialChar +hi def link hareInclude Include hi def link hareKeyword Keyword -hi def link hareLabel Label -hi def link hareNull Constant +hi def link hareLabel Special hi def link hareNumber Number hi def link hareOperator Operator -hi def link hareQuestionMark Special hi def link hareRepeat Repeat hi def link hareRune Character hi def link hareStorageClass StorageClass @@ -122,12 +145,13 @@ hi def link hareStructure Structure hi def link hareTodo Todo hi def link hareType Type hi def link hareTypedef Typedef -hi def link hareUse PreProc -hi def link hareSpaceError Error -autocmd InsertEnter * hi link hareSpaceError NONE -autocmd InsertLeave * hi link hareSpaceError Error +" Highlight embedded haredoc references. +hi! def link haredocRefValid SpecialComment -hi def hareErrorAssertion ctermfg=red cterm=bold guifg=red gui=bold +" Highlight whitespace errors by default. +if get(g:, 'hare_space_error', 1) + hi def link hareSpaceError Error +endif -" vim: tabstop=8 shiftwidth=2 expandtab +" vim: et sts=2 sw=2 ts=8 diff --git a/runtime/syntax/haredoc.vim b/runtime/syntax/haredoc.vim new file mode 100644 index 0000000000..09c99c1d56 --- /dev/null +++ b/runtime/syntax/haredoc.vim @@ -0,0 +1,32 @@ +" Vim syntax file. +" Language: Haredoc (Hare documentation format) +" Maintainer: Amelia Clarke <selene@perilune.dev> +" Last Change: 2024-05-10 +" Upstream: https://git.sr.ht/~selene/hare.vim + +if exists('b:current_syntax') + finish +endif +let b:current_syntax = 'haredoc' + +" Syntax {{{1 +syn case match +syn iskeyword @,48-57,_ + +" Code samples. +syn region haredocCodeSample excludenl start='\t\zs' end='$' contains=@NoSpell display + +" References to other declarations and modules. +syn region haredocRef start='\[\[' end=']]' contains=haredocRefValid,@NoSpell display keepend oneline +syn match haredocRefValid '\v\[\[\h\w*%(::\h\w*)*%(::)?]]' contained contains=@NoSpell display + +" Miscellaneous. +syn keyword haredocTodo FIXME TODO XXX + +" Default highlighting {{{1 +hi def link haredocCodeSample Comment +hi def link haredocRef Error +hi def link haredocRefValid Special +hi def link haredocTodo Todo + +" vim: et sts=2 sw=2 ts=8 diff --git a/runtime/syntax/hcl.vim b/runtime/syntax/hcl.vim new file mode 100644 index 0000000000..5e9349ab38 --- /dev/null +++ b/runtime/syntax/hcl.vim @@ -0,0 +1,66 @@ +" Vim syntax file +" Language: HCL +" Maintainer: Gregory Anders +" Upstream: https://github.com/hashivim/vim-terraform +" Last Change: 2024-09-03 + +if exists('b:current_syntax') + finish +endif + +syn iskeyword a-z,A-Z,48-57,_,- + +syn case match + +" A block is introduced by a type, some number of labels - which are either +" strings or identifiers - and an opening curly brace. Match the type. +syn match hclBlockType /^\s*\zs\K\k*\ze\s\+\(\("\K\k*"\|\K\k*\)\s\+\)*{/ + +" An attribute name is an identifier followed by an equals sign. +syn match hclAttributeAssignment /\(\K\k*\.\)*\K\k*\s\+=\s/ contains=hclAttributeName +syn match hclAttributeName /\<\K\k*\>/ contained + +syn keyword hclValueBool true false + +syn keyword hclTodo contained TODO FIXME XXX BUG +syn region hclComment start="/\*" end="\*/" contains=hclTodo,@Spell +syn region hclComment start="#" end="$" contains=hclTodo,@Spell +syn region hclComment start="//" end="$" contains=hclTodo,@Spell + +""" misc. +syn match hclValueDec "\<[0-9]\+\([kKmMgG]b\?\)\?\>" +syn match hclValueHexaDec "\<0x[0-9a-f]\+\([kKmMgG]b\?\)\?\>" +syn match hclBraces "[\[\]]" + +""" skip \" and \\ in strings. +syn region hclValueString start=/"/ skip=/\\\\\|\\"/ end=/"/ contains=hclStringInterp +syn region hclStringInterp matchgroup=hclBraces start=/\(^\|[^$]\)\$\zs{/ end=/}/ contained contains=ALLBUT,hclAttributeName +syn region hclHereDocText start=/<<-\?\z([a-z0-9A-Z]\+\)/ end=/^\s*\z1/ contains=hclStringInterp + +"" Functions. +syn match hclFunction "[a-z0-9]\+(\@=" + +""" HCL2 +syn keyword hclRepeat for in +syn keyword hclConditional if +syn keyword hclValueNull null + +" enable block folding +syn region hclBlockBody matchgroup=hclBraces start="{" end="}" fold transparent + +hi def link hclComment Comment +hi def link hclTodo Todo +hi def link hclBraces Delimiter +hi def link hclAttributeName Identifier +hi def link hclBlockType Type +hi def link hclValueBool Boolean +hi def link hclValueDec Number +hi def link hclValueHexaDec Number +hi def link hclValueString String +hi def link hclHereDocText String +hi def link hclFunction Function +hi def link hclRepeat Repeat +hi def link hclConditional Conditional +hi def link hclValueNull Constant + +let b:current_syntax = 'hcl' diff --git a/runtime/syntax/help.vim b/runtime/syntax/help.vim index fced5e7dd1..fd128bb0b5 100644 --- a/runtime/syntax/help.vim +++ b/runtime/syntax/help.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: Vim help file " Maintainer: The Vim Project <https://github.com/vim/vim> -" Last Change: 2023 Aug 10 +" Last Change: 2024 Oct 05 " Former Maintainer: Bram Moolenaar <Bram@vim.org> " Quit when a (custom) syntax file was already loaded @@ -15,7 +15,7 @@ set cpo&vim syn match helpHeadline "^[A-Z.][-A-Z0-9 .,()_']*?\=\ze\(\s\+\*\|$\)" syn match helpSectionDelim "^===.*===$" syn match helpSectionDelim "^---.*--$" -" Neovim: support language annotation in codeblocks +" Nvim: support language annotation in codeblocks if has("conceal") syn region helpExample matchgroup=helpIgnore start=" >[a-z0-9]*$" start="^>[a-z0-9]*$" end="^[^ \t]"me=e-1 end="^<" concealends else @@ -60,10 +60,14 @@ syn match helpSpecial "\<N\.\s"me=e-2 syn match helpSpecial "(N\>"ms=s+1 syn match helpSpecial "\[N]" -" avoid highlighting N N in help.txt +" avoid highlighting N N in quickref.txt syn match helpSpecial "N N"he=s+1 syn match helpSpecial "Nth"me=e-2 syn match helpSpecial "N-1"me=e-2 +" highlighting N of cinoptions-values in indent.txt +syn match helpSpecial "^\t-\?\zsNs\?\s"me=s+1 +" highlighting N of cinoptions-values in indent.txt +syn match helpSpecial "^\t[>enf{}^L:=lbghNEpti+cC/(uUwWkmMjJ)*#P]N\s"ms=s+2,me=e-1 syn match helpSpecial "{[-_a-zA-Z0-9'"*+/:%#=[\]<>.,]\+}" syn match helpSpecial "\s\[[-a-z^A-Z0-9_]\{2,}]"ms=s+1 syn match helpSpecial "<[-a-zA-Z0-9_]\+>" diff --git a/runtime/syntax/hollywood.vim b/runtime/syntax/hollywood.vim index 7846d5230f..16df9fa736 100644 --- a/runtime/syntax/hollywood.vim +++ b/runtime/syntax/hollywood.vim @@ -2,7 +2,7 @@ " Language: Hollywood 10.0 " Maintainer: Ola Söder <rolfkopman@gmail.com> " First Author: Tom Crecelius <holly@net-eclipse.net> -" Last Change: 2023 Mar 22 +" Last Change: 2024 Jun 20 " Highlighting Issues: " Depending on your colour schema, Strings or Comments might be highlighted in " a way, you don't like. If so, try one of the following settings after @@ -30,7 +30,7 @@ let s:cpo_save = &cpo set cpo&vim if !exists("hw_version") - let hw_version = 9 + let hw_version = 10 let hw_subversion = 0 elseif !exists("hw_subversion") let hw_subversion = 0 @@ -54,9 +54,9 @@ syn match hwError "\<\%(If\|End\|Else\|ElseIf\|Then\|Until\|In\|EndIf\|EndSwitc syn region hwFunctionBlock transparent matchgroup=hwFunction start="\<Function\>" end="\<EndFunction\>" contains=ALLBUT,hwTodo,hwSpecial,hwElseIf,hwElse,hwIn,hwStep,hwFallThrough,hwLineStatement " If .. Then -syn region hwIfThen transparent matchgroup=hwCond start="\<If\>" end="\<Then\>\{-}"me=e-4 skipwhite skipempty +syn region hwIfThen transparent matchgroup=hwCond start="\<If\>" end="\<Then\>\{-}"me=e-4 oneline skipwhite skipempty " Then ... Else -syn region hwThenElse transparent matchgroup=hwCond start="\<Then\>" end="$" end="\<Else\>" contains=ALLBUT,hwTodo,hwSpecial,hwIn,hwStep,hwLineStatement,hwIfEndIf,hwElseEndif,hwIfThen,hwThenElse skipwhite skipempty +syn region hwThenElse transparent matchgroup=hwCond start="\<Then\>" end="$" end="\<Else\>" contains=hwFunction,hwUserFunction,hwElseIf,hwStatement,hwConstant containedin=hwIfThen oneline skipwhite skipempty " If .. EndIf syn region hwIfEndIf transparent matchgroup=hwCond start="\<If\>\(\(.\{-}Then.\{-}\)\@!\)" end="\<EndIf\>" contains=ALLBUT,hwTodo,hwSpecial,hwIn,hwStep,hwLineStatement skipwhite skipempty @@ -98,6 +98,12 @@ syn region hwForTo transparent matchgroup=hwRepeat start="\<For\>" end="\<To\>"m " To .. Next syn region hwToNext transparent matchgroup=hwRepeat start="\<To\>" end="\<Next\>" contains=ALLBUT,hwTodo,hwSpecial,hwElseIf,hwElse,hwIn,hwLineStatement skipwhite skipempty +" For .. In +syn region hwForIn transparent matchgroup=hwRepeat start="\<For\>\(\(.\{-}To.\{-}\)\@!\)" end="\<In\>"me=e-2, skipwhite skipempty nextgroup=hwInNext + +" In .. Next +syn region hwInNext transparent matchgroup=hwRepeat start="\<In\>" end="\<Next\>" contains=ALLBUT,hwTodo,hwSpecial,hwElseIf,hwElse,hwLineStatement skipwhite skipempty + syn keyword hwStep contained Step syn keyword hwIn contained In @@ -116,7 +122,7 @@ syn match hwConstant "#\<\%(ACTIVEWINDOW\|ADF_ANIM\|ADF_FX\|ADF_MOVEOBJECT\|ALL\ syn keyword hwFunction Abs ACos ActivateDisplay Add AddArcToPath AddBoxToPath AddCircleToPath AddEllipseToPath AddFontPath AddIconImage AddMove AddStr AddTab AddTextToPath AllocConsoleColor AllocMem AllocMemFromPointer AllocMemFromVirtualFile AppendPath ApplyPatch Arc ArcDistortBrush ARGB ArrayToStr Asc ASin Assert AsyncDrawFrame ATan ATan2 BarrelDistortBrush Base64Str Beep BeepConsole BeginAnimStream BeginDoubleBuffer BeginRefresh BGPicToBrush BinStr BitClear BitComplement BitSet BitTest BitXor Blue BlurBrush Box BreakEventHandler BreakWhileMouseOn BrushToBGPic BrushToGray BrushToMonochrome BrushToPenArray BrushToRGBArray ByteAsc ByteChr ByteLen ByteOffset ByteStrStr ByteVal CallJavaMethod CancelAsyncDraw CancelAsyncOperation CanonizePath Cast Ceil ChangeApplicationIcon ChangeBrushTransparency ChangeDirectory ChangeDisplayMode ChangeDisplaySize ChangeInterval CharcoalBrush CharOffset CharWidth CheckEvent CheckEvents Chr Circle ClearClipboard ClearConsole ClearConsoleStyle ClearEvents ClearInterval ClearMove ClearObjectData ClearPath ClearScreen ClearSerialQueue ClearTimeout CloseAmigaGuide CloseAnim CloseAudio CloseCatalog CloseConnection CloseConsole CloseDirectory CloseDisplay CloseFile CloseFont CloseMusic ClosePath CloseResourceMonitor CloseSerialPort CloseServer CloseUDPObject CloseVideo Cls CollectGarbage Collision ColorRequest CompareDates CompareStr CompressFile Concat ConfigureJoystick ConsolePrint ConsolePrintChr ConsolePrintNR ConsolePrompt ContinueAsyncOperation ContrastBrush ContrastPalette ConvertStr ConvertToBrush CopyAnim CopyBGPic CopyBrush CopyConsoleWindow CopyFile CopyLayer CopyMem CopyObjectData CopyPalette CopyPath CopyPens CopySample CopySprite CopyTable CopyTextObject Cos CountDirectoryEntries CountJoysticks CountStr CRC32 CRC32Str CreateAnim CreateBGPic CreateBorderBrush CreateBrush CreateButton CreateClipRegion CreateConsoleWindow CreateCoroutine CreateDisplay CreateFont CreateGradientBGPic CreateGradientBrush CreateIcon CreateKeyDown CreateLayer CreateList CreateMenu CreateMusic CreatePalette CreatePointer CreatePort CreateRainbowBGPic CreateRexxPort CreateSample CreateServer CreateShadowBrush CreateShortcut CreateSprite CreateTextObject CreateTexturedBGPic CreateTexturedBrush CreateUDPObject CropBrush CtrlCQuit CurveTo CyclePalette DateToTimestamp DateToUTC DebugOutput DebugPrint DebugPrintNR DebugPrompt DebugStr DebugVal DecomposeConsoleChr DecompressFile DecreasePointer DefineVirtualFile DefineVirtualFileFromString Deg DeleteAlphaChannel DeleteButton DeleteConsoleChr DeleteConsoleLine DeleteFile DeleteMask DeletePrefs DeselectMenuItem DeserializeTable DirectoryItems DisableAdvancedConsole DisableButton DisableEvent DisableEventHandler DisableLayers DisableLineHook DisableMenuItem DisablePlugin DisablePrecalculation DisableVWait DisplayAnimFrame DisplayBGPic DisplayBGPicPart DisplayBGPicPartFX DisplayBrush DisplayBrushFX DisplayBrushPart DisplaySprite DisplayTextObject DisplayTextObjectFX DisplayTransitionFX DisplayVideoFrame Div DoMove DownloadFile DrawConsoleBorder DrawConsoleBox DrawConsoleHLine DrawConsoleVLine DrawPath DumpButtons DumpLayers DumpMem DumpVideo DumpVideoTime EdgeBrush Ellipse EmbossBrush EmptyStr EnableAdvancedConsole EnableButton EnableEvent EnableEventHandler EnableLayers EnableLineHook EnableMenuItem EnablePlugin EnablePrecalculation EnableVWait End EndDoubleBuffer EndianSwap EndRefresh EndSelect EndsWith Eof EraseConsole Error EscapeQuit Eval Execute Exists ExitOnError Exp ExtendBrush ExtractPalette FileAttributes FileLength FileLines FilePart FilePos FileRequest FileSize FileToString FillMem FillMusicBuffer FindStr FinishAnimStream FinishAsyncDraw FlashConsole Flip FlipBrush FlipSprite FloodFill Floor FlushFile FlushMusicBuffer FlushSerialPort FontRequest ForcePathUse ForceSound ForceVideoDriver ForceVideoMode ForEach ForEachI FormatConsoleLine FormatDate FormatNumber FormatStr Frac FreeAnim FreeBGPic FreeBrush FreeClipRegion FreeConsoleColor FreeConsoleWindow FreeDisplay FreeEventCache FreeGlyphCache FreeIcon FreeLayers FreeMem FreeMenu FreeModule FreePalette FreePath FreePointer FreeSample FreeSprite FreeTextObject FrExp FullPath GammaBrush GammaPalette GCInfo GetAllocConsoleColor GetAnimFrame GetApplicationInfo GetApplicationList GetAsset GetAttribute GetAvailableFonts GetBaudRate GetBestPen GetBrushLink GetBrushPen GetBulletColor GetCatalogString GetChannels GetCharMaps GetClipboard GetCommandLine GetConnectionIP GetConnectionPort GetConnectionProtocol GetConsoleBackground GetConsoleChr GetConsoleColor GetConsoleControlChr GetConsoleCursor GetConsoleOrigin GetConsoleSize GetConsoleStr GetConsoleStyle GetConsoleWindow GetConstant GetCoroutineStatus GetCountryInfo GetCurrentDirectory GetCurrentPoint GetDash GetDataBits GetDate GetDateNum GetDefaultAdapter GetDefaultEncoding GetDefaultLoader GetDirectoryEntry GetDisplayModes GetDTR GetEnv GetErrorName GetEventCode GetFileArgument GetFileAttributes GetFillRule GetFillStyle GetFlowControl GetFontColor GetFontStyle GetFormStyle GetFPSLimit GetFreePen GetFrontScreen GetHostName GetIconProperties GetItem GetKerningPair GetLanguageInfo GetLastError GetLayerAtPos GetLayerGroupMembers GetLayerGroups GetLayerPen GetLayerStyle GetLineCap GetLineJoin GetLineWidth GetLocaleInfo GetLocalInterfaces GetLocalIP GetLocalPort GetLocalProtocol GetMACAddress GetMemoryInfo GetMemPointer GetMemString GetMetaTable GetMiterLimit GetMonitors GetObjectData GetObjects GetObjectType GetPalettePen GetParity GetPathExtents GetPatternPosition GetPen GetPlugins GetProgramDirectory GetProgramInfo GetPubScreens GetRandomColor GetRandomFX GetRawArguments GetRealColor GetRTS GetSampleData GetSerializeMode GetShortcutPath GetSongPosition GetStartDirectory GetStopBits GetSystemCountry GetSystemInfo GetSystemLanguage GetTempFileName GetTime GetTimer GetTimestamp GetTimeZone GetType GetVersion GetVideoFrame GetVolumeInfo GetVolumeName GetWeekday Gosub Goto GrabDesktop Green GroupLayer HasItem HaveConsole HaveFreeChannel HaveItem HaveObject HaveObjectData HavePlugin HaveVolume HexStr HideConsoleCursor HideDisplay HideKeyboard HideLayer HideLayerFX HidePointer HideScreen Hypot IgnoreCase IIf ImageRequest IncreasePointer InitConsoleColor InKeyStr InsertConsoleChr InsertConsoleLine InsertConsoleStr InsertItem InsertLayer InsertSample InsertStr InstallEventHandler Int Intersection InvertAlphaChannel InvertBrush InvertMask InvertPalette IPairs IsAbsolutePath IsAlNum IsAlpha IsAnim IsAnimPlaying IsBrushEmpty IsChannelPlaying IsCntrl IsDigit IsDirectory IsFinite IsGraph IsInf IsKeyDown IsLeftMouse IsLower IsMenuItemDisabled IsMenuItemSelected IsMidMouse IsModule IsMusic IsMusicPlaying IsNan IsNil IsOnline IsPathEmpty IsPicture IsPrint IsPunct IsRightMouse IsSample IsSamplePlaying IsSound IsSpace IsTableEmpty IsUnicode IsUpper IsVideo IsVideoPlaying IsXDigit JoyAxisX JoyAxisY JoyAxisZ JoyButton JoyDir JoyFire Label JoyHat LayerExists LayerGroupExists LayerToBack LayerToFront Ld LdExp LeftMouseQuit LeftStr LegacyControl Limit Line LineTo ListItems ListRequest Ln LoadAnim LoadAnimFrame LoadBGPic LoadBrush LoadIcon LoadModule LoadPalette LoadPlugin LoadPrefs LoadSample LoadSprite Locate Log LowerStr MakeButton MakeConsoleChr MakeDate MakeDirectory MakeHostPath MatchPattern Matrix2D Max MD5 MD5Str MemToTable MergeLayers MidStr Min MixBrush MixRGB MixSample Mod ModifyAnimFrames ModifyButton ModifyKeyDown ModifyLayerFrames ModulateBrush ModulatePalette MonitorDirectory MouseX MouseY MoveAnim MoveBrush MoveConsoleWindow MoveDisplay MoveFile MoveLayer MovePointer MoveSprite MoveTextObject MoveTo Mul NearlyEqual NextDirectoryEntry NextFrame NextItem NormalizePath NPrint OilPaintBrush OpenAmigaGuide OpenAnim OpenAudio OpenCatalog OpenConnection OpenConsole OpenDirectory OpenDisplay OpenFile OpenFont OpenMusic OpenResourceMonitor OpenSerialPort OpenURL OpenVideo Pack PadNum Pairs PaletteToGray ParseDate PathItems PathPart PathRequest PathToBrush PatternFindStr PatternFindStrDirect PatternFindStrShort PatternReplaceStr PauseLayer PauseModule PauseMusic PauseTimer PauseVideo Peek PeekClipboard PenArrayToBrush PerformSelector PermissionRequest PerspectiveDistortBrush Pi PixelateBrush PlayAnim PlayAnimDisk PlayLayer PlayModule PlayMusic PlaySample PlaySubsong PlayVideo Plot Poke PolarDistortBrush PollSerialQueue Polygon PopupMenu Pow Print QuantizeBrush Rad RaiseOnError RasterizeBrush RawDiv RawEqual RawGet RawSet ReadBrushPixel ReadByte ReadBytes ReadChr ReadConsoleKey ReadConsoleStr ReadDirectory ReadFloat ReadFunction ReadInt ReadLine ReadMem ReadPen ReadPixel ReadRegistryKey ReadSerialData ReadShort ReadString ReadTable ReceiveData ReceiveUDPData Red ReduceAlphaChannel RefreshConsole RefreshDisplay RefreshLayer RelCurveTo RelLineTo RelMoveTo RemapBrush RemoveBrushPalette RemoveButton RemoveIconImage RemoveItem RemoveKeyDown RemoveLayer RemoveLayerFX RemoveLayers RemoveSprite RemoveSprites Rename RenderLayer RepeatStr ReplaceColors ReplaceStr ResetKeyStates ResetTabs ResetTimer ResolveHostName ResumeCoroutine ResumeLayer ResumeModule ResumeMusic ResumeTimer ResumeVideo ReverseFindStr ReverseStr RewindDirectory RGB RGBArrayToBrush RightStr Rnd RndF RndStrong Rol Ror RotateBrush RotateLayer RotateTextObject Round Rt Run RunCallback RunRexxScript Sar SaveAnim SaveBrush SaveIcon SavePalette SavePrefs SaveSample SaveSnapshot ScaleAnim ScaleBGPic ScaleBrush ScaleLayer ScaleSprite ScaleTextObject ScrollConsole Seek SeekLayer SeekMusic SeekVideo SelectAlphaChannel SelectAnim SelectBGPic SelectBrush SelectConsoleWindow SelectDisplay SelectLayer SelectMask SelectMenuItem SelectPalette SendApplicationMessage SendData SendMessage SendRexxCommand SendUDPData SepiaToneBrush SerializeTable SetAllocConsoleColor SetAlphaIntensity SetAnimFrameDelay SetAttribute SetBaudRate SetBorderPen SetBrushDepth SetBrushPalette SetBrushPen SetBrushTransparency SetBrushTransparentPen SetBulletColor SetBulletPen SetChannelVolume SetClipboard SetClipRegion SetConsoleBackground SetConsoleColor SetConsoleCursor SetConsoleOptions SetConsoleStyle SetConsoleTitle SetCycleTable SetDash SetDataBits SetDefaultAdapter SetDefaultEncoding SetDefaultLoader SetDepth SetDisplayAttributes SetDitherMode SetDrawPen SetDrawTagsDefault SetDTR SetEnv SetEventTimeout SetFileAttributes SetFileEncoding SetFillRule SetFillStyle SetFlowControl SetFont SetFontColor SetFontStyle SetFormStyle SetFPSLimit SetGradientPalette SetIconProperties SetInterval SetIOMode SetLayerAnchor SetLayerBorder SetLayerDepth SetLayerFilter SetLayerLight SetLayerName SetLayerPalette SetLayerPen SetLayerShadow SetLayerStyle SetLayerTint SetLayerTransparency SetLayerTransparentPen SetLayerVolume SetLayerZPos SetLineCap SetLineJoin SetLineWidth SetListItems SetMargins SetMaskMode SetMasterVolume SetMetaTable SetMiterLimit SetMusicVolume SetNetworkProtocol SetNetworkTimeout SetObjectData SetPalette SetPaletteDepth SetPaletteMode SetPalettePen SetPaletteTransparentPen SetPanning SetParity SetPen SetPitch SetPointer SetRTS SetScreenTitle SetSerializeMode SetSerializeOptions SetShadowPen SetSpriteZPos SetStandardIconImage SetStandardPalette SetStopBits SetSubtitle SetTimeout SetTimerElapse SetTitle SetTransparentPen SetTransparentThreshold SetTrayIcon SetVarType SetVectorEngine SetVideoPosition SetVideoSize SetVideoVolume SetVolume SetWBIcon Sgn SharpenBrush Shl ShowConsoleCursor ShowDisplay ShowKeyboard ShowLayer ShowLayerFX ShowNotification ShowPointer ShowRinghioMessage ShowScreen ShowToast Shr Sin Sleep SolarizeBrush SolarizePalette Sort SplitStr Sqrt StartConsoleColorMode StartPath StartSubPath StartsWith StartTimer StopAnim StopChannel StopLayer StopModule StopMusic StopSample StopTimer StopVideo StringRequest StringToFile StripStr StrLen StrStr StrToArray Sub SwapLayers SwirlBrush SystemRequest TableItems TableToMem Tan TextExtent TextHeight TextOut TextWidth TimerElapsed TimestampToDate TintBrush TintPalette ToHostName ToIP ToNumber ToString TouchConsoleWindow ToUserData TransformBox TransformBrush TransformLayer TransformPoint TransformTextObject TranslateLayer TranslatePath TrimBrush TrimStr UndefineVirtualStringFile Undo UndoFX UngroupLayer UnleftStr UnmidStr Unpack UnrightStr UnsetEnv UploadFile UpperStr Usage UseCarriageReturn UseFont UTCToDate Val ValidateDate ValidateStr Vibrate VWait Wait WaitAnimEnd WaitEvent WaitKeyDown WaitLeftMouse WaitMidMouse WaitMusicEnd WaitPatternPosition WaitRightMouse WaitSampleEnd WaitSongPosition WaitTimer WaterRippleBrush WhileKeyDown WhileMouseDown WhileMouseOn WhileRightMouseDown Wrap WriteAnimFrame WriteBrushPixel WriteByte WriteBytes WriteChr WriteFloat WriteFunction WriteInt WriteLine WriteMem WritePen WriteRegistryKey WriteSerialData WriteShort WriteString WriteTable YieldCoroutine " user-defined constants -syn match hwUserConstant "#\<\u\+\>" +syn match hwUserConstant "#\<\(\u\|_\|-\|\d\)\+\>\$\?" " user-defined functions syn match hwUserFunction "\<p_\w\{-1,}\>("me=e-1 diff --git a/runtime/syntax/html.vim b/runtime/syntax/html.vim index c975ae8620..ca7c7f1cdd 100644 --- a/runtime/syntax/html.vim +++ b/runtime/syntax/html.vim @@ -4,6 +4,7 @@ " Previous Maintainers: Jorge Maldonado Ventura <jorgesumle@freakspot.net> " Claudio Fleiner <claudio@fleiner.com> " Last Change: 2023 Nov 28 +" 2024 Jul 30 by Vim Project: increase syn-sync-minlines to 250 " See :help html.vim for some comments and a description of the options @@ -191,7 +192,7 @@ syn keyword htmlArg contained step title translate typemustmatch syn match htmlArg contained "\<data-\h\%(\w\|[-.]\)*\%(\_s*=\)\@=" " special characters -syn match htmlSpecialChar "&#\=[0-9A-Za-z]\{1,8};" +syn match htmlSpecialChar "&#\=[0-9A-Za-z]\{1,32};" " Comments (the real ones or the old netscape ones) if exists("html_wrong_comments") @@ -320,7 +321,7 @@ if main_syntax == "html" syn sync match htmlHighlight groupthere NONE "<[/a-zA-Z]" syn sync match htmlHighlight groupthere javaScript "<script" syn sync match htmlHighlightSkip "^.*['\"].*$" - syn sync minlines=10 + exe "syn sync minlines=" . get(g:, 'html_minlines', 250) endif " Folding diff --git a/runtime/syntax/htmlangular.vim b/runtime/syntax/htmlangular.vim new file mode 100644 index 0000000000..021e61f9b1 --- /dev/null +++ b/runtime/syntax/htmlangular.vim @@ -0,0 +1,18 @@ +" Vim syntax file +" Language: Angular HTML template +" Maintainer: Dennis van den Berg <dennis@vdberg.dev> +" Last Change: 2024 Aug 22 + +" quit when a syntax file was already loaded +if exists("b:current_syntax") + finish +endif + +if !exists("main_syntax") + let main_syntax = 'html' +endif + +runtime! syntax/html.vim +unlet b:current_syntax + +let b:current_syntax = "htmlangular" diff --git a/runtime/syntax/i3config.vim b/runtime/syntax/i3config.vim index f4d789e418..c95cb879ad 100644 --- a/runtime/syntax/i3config.vim +++ b/runtime/syntax/i3config.vim @@ -2,8 +2,8 @@ " Language: i3 config file " Original Author: Josef Litos (JosefLitos/i3config.vim) " Maintainer: Quentin Hibon (github user hiqua) -" Version: 1.2.3 -" Last Change: 2024-05-23 +" Version: 1.2.4 +" Last Change: 2024-05-24 " References: " http://i3wm.org/docs/userguide.html#configuring @@ -67,7 +67,7 @@ syn keyword i3ConfigBindKeyword bindsym bindcode contained skipwhite nextgroup=i syn region i3ConfigModeBlock matchgroup=i3ConfigKeyword start=/mode\ze\( --pango_markup\)\? \([^'" {]\+\|'[^']\+'\|".\+"\)\s\+{$/ end=/^}\zs$/ contained contains=i3ConfigShParam,@i3ConfigStrVar,i3ConfigBindKeyword,i3ConfigComment,i3ConfigParen fold keepend extend " 4.7 Floating modifier -syn match i3ConfigKeyword /^floating_modifier [$0-9A-Za-z]*$/ contains=i3ConfigVariable,i3ConfigBindModkey +syn match i3ConfigKeyword /floating_modifier [$A-Z][0-9A-Za-z]*$/ contained contains=i3ConfigVariable,i3ConfigBindModkey " 4.8 Floating window size syn keyword i3ConfigSizeSpecial x contained diff --git a/runtime/syntax/idlang.vim b/runtime/syntax/idlang.vim index 14e976ce05..f7bfcb203a 100644 --- a/runtime/syntax/idlang.vim +++ b/runtime/syntax/idlang.vim @@ -1,7 +1,8 @@ " Interactive Data Language syntax file (IDL, too [:-)] " Maintainer: Aleksandar Jelenak <ajelenak AT yahoo.com> -" Last change: 2011 Apr 11 -" Created by: Hermann Rochholz <Hermann.Rochholz AT gmx.de> +" Created By: Hermann Rochholz <Hermann.Rochholz AT gmx.de> +" Last Change: 2011 Apr 11 +" 2024 Sep 10 by Vim Project: update syntax script, #15419 " Remove any old syntax stuff hanging around " quit when a syntax file was already loaded @@ -16,7 +17,7 @@ syn match idlangStatement "^\s*function\s" syn keyword idlangStatement return continue mod do break syn keyword idlangStatement compile_opt forward_function goto syn keyword idlangStatement begin common end of -syn keyword idlangStatement inherits on_ioerror begin +syn keyword idlangStatement inherits on_error on_ioerror begin syn keyword idlangConditional if else then for while case switch syn keyword idlangConditional endcase endelse endfor endswitch @@ -82,7 +83,7 @@ syn keyword idlangRoutine CALL_EXTERNAL CALL_FUNCTION CALL_METHOD syn keyword idlangRoutine CALL_PROCEDURE CATCH CD CEIL CHEBYSHEV CHECK_MATH syn keyword idlangRoutine CHISQR_CVF CHISQR_PDF CHOLDC CHOLSOL CINDGEN syn keyword idlangRoutine CIR_3PNT CLOSE CLUST_WTS CLUSTER COLOR_CONVERT -syn keyword idlangRoutine COLOR_QUAN COLORMAP_APPLICABLE COMFIT COMMON +syn keyword idlangRoutine COLOR_QUAN COLORMAP_APPLICABLE COMFIT syn keyword idlangRoutine COMPLEX COMPLEXARR COMPLEXROUND syn keyword idlangRoutine COMPUTE_MESH_NORMALS COND CONGRID CONJ syn keyword idlangRoutine CONSTRAINED_MIN CONTOUR CONVERT_COORD CONVOL @@ -98,7 +99,7 @@ syn keyword idlangRoutine CW_PALETTE_EDITOR_GET CW_PALETTE_EDITOR_SET syn keyword idlangRoutine CW_PDMENU CW_RGBSLIDER CW_TMPL CW_ZOOM DBLARR syn keyword idlangRoutine DCINDGEN DCOMPLEX DCOMPLEXARR DEFINE_KEY DEFROI syn keyword idlangRoutine DEFSYSV DELETE_SYMBOL DELLOG DELVAR DERIV DERIVSIG -syn keyword idlangRoutine DETERM DEVICE DFPMIN DIALOG_MESSAGE +syn keyword idlangRoutine DETERM DEVICE DFPMIN DIAG_MATRIX DIALOG_MESSAGE syn keyword idlangRoutine DIALOG_PICKFILE DIALOG_PRINTERSETUP syn keyword idlangRoutine DIALOG_PRINTJOB DIALOG_READ_IMAGE syn keyword idlangRoutine DIALOG_WRITE_IMAGE DIGITAL_FILTER DILATE DINDGEN @@ -155,7 +156,7 @@ syn keyword idlangRoutine MPEG_PUT MPEG_SAVE MSG_CAT_CLOSE MSG_CAT_COMPILE syn keyword idlangRoutine MSG_CAT_OPEN MULTI N_ELEMENTS N_PARAMS N_TAGS syn keyword idlangRoutine NEWTON NORM OBJ_CLASS OBJ_DESTROY OBJ_ISA OBJ_NEW syn keyword idlangRoutine OBJ_VALID OBJARR ON_ERROR ON_IOERROR ONLINE_HELP -syn keyword idlangRoutine OPEN OPENR OPENW OPLOT OPLOTERR P_CORRELATE +syn keyword idlangRoutine OPEN OPENR OPENW OPENU OPLOT OPLOTERR P_CORRELATE syn keyword idlangRoutine PARTICLE_TRACE PCOMP PLOT PLOT_3DBOX PLOT_FIELD syn keyword idlangRoutine PLOTERR PLOTS PNT_LINE POINT_LUN POLAR_CONTOUR syn keyword idlangRoutine POLAR_SURFACE POLY POLY_2D POLY_AREA POLY_FIT diff --git a/runtime/syntax/indent.vim b/runtime/syntax/indent.vim index b2a1a0c85f..921a0a8ad0 100644 --- a/runtime/syntax/indent.vim +++ b/runtime/syntax/indent.vim @@ -2,7 +2,7 @@ " Language: indent(1) configuration file " Maintainer: Doug Kearns <dougkearns@gmail.com> " Previous Maintainer: Nikolai Weibull <now@bitwi.se> -" Last Change: 2021 Nov 17 +" Last Change: 2024 Sep 29 " indent_is_bsd: If exists, will change somewhat to match BSD implementation " " TODO: is the deny-all (a la lilo.vim nice or no?)... @@ -34,7 +34,7 @@ endif syn match indentOptions '-\%(bli\|c\%([bl]i\|[dip]\)\=\|di\=\|ip\=\|lc\=\|pp\=i\|sbi\|ts\|-\%(brace-indent\|comment-indentation\|case-brace-indentation\|declaration-comment-column\|continuation-indentation\|case-indentation\|else-endif-column\|line-comments-indentation\|declaration-indentation\|indent-level\|parameter-indentation\|line-length\|comment-line-length\|paren-indentation\|preprocessor-indentation\|struct-brace-indentation\|tab-size\)\)' \ nextgroup=indentNumber skipwhite skipempty -syn match indentNumber display contained '\d\+\>' +syn match indentNumber display contained '-\=\d\+\>' syn match indentOptions '-T' \ nextgroup=indentIdent skipwhite skipempty diff --git a/runtime/syntax/java.vim b/runtime/syntax/java.vim index 9867b147c2..307fc26349 100644 --- a/runtime/syntax/java.vim +++ b/runtime/syntax/java.vim @@ -3,18 +3,33 @@ " Maintainer: Aliaksei Budavei <0x000c70 AT gmail DOT com> " Former Maintainer: Claudio Fleiner <claudio@fleiner.com> " Repository: https://github.com/zzzyxwvut/java-vim.git -" Last Change: 2024 May 10 +" Last Change: 2024 Oct 03 -" Please check :help java.vim for comments on some of the options available. +" Please check ":help java.vim" for comments on some of the options +" available. -" quit when a syntax file was already loaded -if !exists("main_syntax") - if exists("b:current_syntax") - finish +" Do not aggregate syntax items from circular inclusion. +if exists("b:current_syntax") + finish +endif + +if exists("g:main_syntax") + " Reject attendant circularity for every :syn-included syntax file, + " but ACCEPT FAILURE when "g:main_syntax" is set to "java". + if g:main_syntax == 'html' + if !exists("g:java_ignore_html") + let g:java_ignore_html = 1 + let s:clear_java_ignore_html = 1 + endif + elseif g:main_syntax == 'markdown' + if !exists("g:java_ignore_markdown") + let g:java_ignore_markdown = 1 + let s:clear_java_ignore_markdown = 1 + endif endif - " we define it here so that included files can test for it - let main_syntax='java' - syn region javaFold start="{" end="}" transparent fold +else + " Allow syntax files that include this file test for its inclusion. + let g:main_syntax = 'java' endif let s:cpo_save = &cpo @@ -31,6 +46,10 @@ function! s:ff.RightConstant(x, y) abort return a:y endfunction +function! s:ff.IsRequestedPreviewFeature(n) abort + return exists("g:java_syntax_previews") && index(g:java_syntax_previews, a:n) + 1 +endfunction + if !exists("*s:ReportOnce") function s:ReportOnce(message) abort echomsg 'syntax/java.vim: ' . a:message @@ -40,6 +59,28 @@ else endfunction endif +if exists("g:java_foldtext_show_first_or_second_line") + function! s:LazyPrefix(prefix, dashes, count) abort + return empty(a:prefix) + \ ? printf('+-%s%3d lines: ', a:dashes, a:count) + \ : a:prefix + endfunction + + function! JavaSyntaxFoldTextExpr() abort + " Piggyback on NGETTEXT. + let summary = foldtext() + return getline(v:foldstart) !~ '/\*\+\s*$' + \ ? summary + \ : s:LazyPrefix(matchstr(summary, '^+-\+\s*\d\+\s.\{-1,}:\s'), + \ v:folddashes, + \ (v:foldend - v:foldstart + 1)) . + \ getline(v:foldstart + 1) + endfunction + + " E120 for "fdt=s:JavaSyntaxFoldTextExpr()" before v8.2.3900. + setlocal foldtext=JavaSyntaxFoldTextExpr() +endif + " Admit the ASCII dollar sign to keyword characters (JLS-17, §3.8): try exec 'syntax iskeyword ' . &l:iskeyword . ',$' @@ -54,7 +95,6 @@ syn match javaError "<<<\|\.\.\|=>\|||=\|&&=\|\*\/" " use separate name so that it can be deleted in javacc.vim syn match javaError2 "#\|=<" -hi def link javaError2 javaError " Keywords (JLS-17, §3.9): syn keyword javaExternal native package @@ -68,6 +108,13 @@ syn keyword javaTypedef this super syn keyword javaOperator new instanceof syn match javaOperator "\<var\>\%(\s*(\)\@!" +if s:ff.IsRequestedPreviewFeature(476) + " Module imports can be used in any source file. + syn match javaExternal "\<import\s\+module\>" contains=javaModuleImport + syn keyword javaModuleImport contained module + hi def link javaModuleImport Statement +endif + " Since the yield statement, which could take a parenthesised operand, " and _qualified_ yield methods get along within the switch block " (JLS-17, §3.8), it seems futile to make a region definition for this @@ -76,18 +123,18 @@ syn match javaOperator "\<var\>\%(\s*(\)\@!" " if necessary, on the line before that (h: \@<=), trying to match " neither a method reference nor a qualified method invocation. try - syn match javaOperator "\%(\%(::\|\.\)[[:space:]\n]*\)\@80<!\<yield\>" + syn match javaOperator "\%(\%(::\|\.\)[[:space:]\n]*\)\@80<!\<yield\>" let s:ff.Peek = s:ff.LeftConstant catch /\<E59:/ call s:ReportOnce(v:exception) - syn match javaOperator "\%(\%(::\|\.\)[[:space:]\n]*\)\@<!\<yield\>" + syn match javaOperator "\%(\%(::\|\.\)[[:space:]\n]*\)\@<!\<yield\>" let s:ff.Peek = s:ff.RightConstant endtry syn keyword javaType boolean char byte short int long float double syn keyword javaType void syn keyword javaStatement return -syn keyword javaStorageClass static synchronized transient volatile strictfp serializable +syn keyword javaStorageClass static synchronized transient volatile strictfp syn keyword javaExceptions throw try catch finally syn keyword javaAssert assert syn keyword javaMethodDecl throws @@ -99,9 +146,10 @@ syn match javaClassDecl "\<record\>\%(\s*(\)\@!" syn match javaClassDecl "^class\>" syn match javaClassDecl "[^.]\s*\<class\>"ms=s+1 syn match javaAnnotation "@\%(\K\k*\.\)*\K\k*\>" +syn region javaAnnotation transparent matchgroup=javaAnnotationStart start=/@\%(\K\k*\.\)*\K\k*(/ end=/)/ skip=/\/\*.\{-}\*\/\|\/\/.*$/ contains=javaAnnotation,javaParenT,javaBlock,javaString,javaBoolean,javaNumber,javaTypedef,javaComment,javaLineComment syn match javaClassDecl "@interface\>" syn keyword javaBranch break continue nextgroup=javaUserLabelRef skipwhite -syn match javaUserLabelRef "\k\+" contained +syn match javaUserLabelRef contained "\k\+" syn match javaVarArg "\.\.\." syn keyword javaScopeDecl public protected private syn keyword javaConceptKind abstract final @@ -109,15 +157,6 @@ syn match javaConceptKind "\<non-sealed\>" syn match javaConceptKind "\<sealed\>\%(\s*(\)\@!" syn match javaConceptKind "\<default\>\%(\s*\%(:\|->\)\)\@!" -" Note that a "module-info" file will be recognised with an arbitrary -" file extension (or no extension at all) so that more than one such -" declaration for the same Java module can be maintained for modular -" testing in a project without attendant confusion for IDEs, with the -" ".java\=" extension used for a production version and an arbitrary -" extension used for a testing version. -let s:module_info_cur_buf = fnamemodify(bufname("%"), ":t") =~ '^module-info\%(\.class\>\)\@!' -lockvar s:module_info_cur_buf - if !(v:version < 704) " Request the new regexp engine for [:upper:] and [:lower:]. let [s:ff.Engine, s:ff.UpperCase, s:ff.LowerCase] = repeat([s:ff.LeftConstant], 3) @@ -127,17 +166,68 @@ else let [s:ff.Engine, s:ff.UpperCase, s:ff.LowerCase] = repeat([s:ff.RightConstant], 3) endif -" Java modules (since Java 9, for "module-info.java" file). -if s:module_info_cur_buf +if exists("g:java_highlight_signature") + let [s:ff.PeekTo, s:ff.PeekFrom, s:ff.GroupArgs] = repeat([s:ff.LeftConstant], 3) +else + let [s:ff.PeekTo, s:ff.PeekFrom, s:ff.GroupArgs] = repeat([s:ff.RightConstant], 3) +endif + +let s:with_html = !exists("g:java_ignore_html") +let s:with_markdown = !exists("g:java_ignore_markdown") +lockvar s:with_html s:with_markdown + +" Java module declarations (JLS-17, §7.7). +" +" Note that a "module-info" file will be recognised with an arbitrary +" file extension (or no extension at all) so that more than one such +" declaration for the same Java module can be maintained for modular +" testing in a project without attendant confusion for IDEs, with the +" ".java\=" extension used for a production version and an arbitrary +" extension used for a testing version. +if fnamemodify(bufname("%"), ":t") =~ '^module-info\>\%(\.class\>\)\@!' syn keyword javaModuleStorageClass module transitive syn keyword javaModuleStmt open requires exports opens uses provides syn keyword javaModuleExternal to with + hi def link javaModuleStorageClass StorageClass + hi def link javaModuleStmt Statement + hi def link javaModuleExternal Include + + if !exists("g:java_ignore_javadoc") && (s:with_html || s:with_markdown) && g:main_syntax != 'jsp' + syn match javaDocProvidesTag contained "@provides\_s\+\S\+" contains=javaDocParam + syn match javaDocUsesTag contained "@uses\_s\+\S\+" contains=javaDocParam + hi def link javaDocProvidesTag Special + hi def link javaDocUsesTag Special + endif +endif + +" Fancy parameterised types (JLS-17, §4.5). +" +" Note that false positives may elsewhere occur whenever an identifier +" is butted against a less-than operator. Cf. (X<Y) and (X < Y). +if exists("g:java_highlight_generics") + syn keyword javaWildcardBound contained extends super + + " Parameterised types are delegated to javaGenerics (s:ctx.gsg) and + " are not matched with javaTypeArgument. + exec 'syn match javaTypeArgument contained "' . s:ff.Engine('\%#=2', '') . '?\|\%(\<\%(b\%(oolean\|yte\)\|char\|short\|int\|long\|float\|double\)\[\]\|\%(\<\K\k*\>\.\)*\<' . s:ff.UpperCase('[$_[:upper:]]', '[^a-z0-9]') . '\k*\>\)\%(\[\]\)*"' + + for s:ctx in [{'dsg': 'javaDimExpr', 'gsg': 'javaGenerics', 'ghg': 'javaGenericsC1', 'csg': 'javaGenericsX', 'c': ''}, + \ {'dsg': 'javaDimExprX', 'gsg': 'javaGenericsX', 'ghg': 'javaGenericsC2', 'csg': 'javaGenerics', 'c': ' contained'}] + " Consider array creation expressions of reifiable types. + exec 'syn region ' . s:ctx.dsg . ' contained transparent matchgroup=' . s:ctx.ghg . ' start="\[" end="\]" nextgroup=' . s:ctx.dsg . ' skipwhite skipnl' + exec 'syn region ' . s:ctx.gsg . s:ctx.c . ' transparent matchgroup=' . s:ctx.ghg . ' start=/' . s:ff.Engine('\%#=2', '') . '\%(\<\K\k*\>\.\)*\<' . s:ff.UpperCase('[$_[:upper:]]', '[^a-z0-9]') . '\k*\><\%([[:space:]\n]*\%([?@]\|\<\%(b\%(oolean\|yte\)\|char\|short\|int\|long\|float\|double\)\[\]\|\%(\<\K\k*\>\.\)*\<' . s:ff.UpperCase('[$_[:upper:]]', '[^a-z0-9]') . '\k*\>\)\)\@=/ end=/>/ contains=' . s:ctx.csg . ',javaAnnotation,javaTypeArgument,javaWildcardBound,javaType,@javaClasses nextgroup=' . s:ctx.dsg . ' skipwhite skipnl' + endfor + + unlet s:ctx + hi def link javaWildcardBound Question + hi def link javaGenericsC1 Function + hi def link javaGenericsC2 Type endif -if exists("java_highlight_java_lang_ids") - let java_highlight_all=1 +if exists("g:java_highlight_java_lang_ids") + let g:java_highlight_all = 1 endif -if exists("java_highlight_all") || exists("java_highlight_java") || exists("java_highlight_java_lang") +if exists("g:java_highlight_all") || exists("g:java_highlight_java") || exists("g:java_highlight_java_lang") " java.lang.* " " The keywords of javaR_JavaLang, javaC_JavaLang, javaE_JavaLang, @@ -163,9 +253,15 @@ if exists("java_highlight_all") || exists("java_highlight_java") || exists("ja exec 'syn match javaC_JavaLang "\%(\<ModuleLayer\.\)\@' . s:ff.Peek('12', '') . '<=\<Controller\>"' exec 'syn match javaC_JavaLang "\%(\<Runtime\.\)\@' . s:ff.Peek('8', '') . '<=\<Version\>"' exec 'syn match javaC_JavaLang "\%(\<System\.\)\@' . s:ff.Peek('7', '') . '<=\<LoggerFinder\>"' - exec 'syn match javaC_JavaLang "\%(\<Enum\.\)\@' . s:ff.Peek('5', '') . '<=\<EnumDesc\>"' - syn keyword javaC_JavaLang Boolean Character Class ClassLoader Compiler Double Float Integer Long Math Number Object Process Runtime SecurityManager String StringBuffer Thread ThreadGroup Byte Short Void InheritableThreadLocal Package RuntimePermission ThreadLocal StrictMath StackTraceElement Enum ProcessBuilder StringBuilder ClassValue Module ModuleLayer StackWalker Record + syn keyword javaC_JavaLang Boolean Character ClassLoader Compiler Double Float Integer Long Math Number Object Process Runtime SecurityManager String StringBuffer Thread ThreadGroup Byte Short Void Package RuntimePermission StrictMath StackTraceElement ProcessBuilder StringBuilder Module ModuleLayer StackWalker Record syn match javaC_JavaLang "\<System\>" " See javaDebug. + + if !exists("g:java_highlight_generics") + " The non-interface parameterised names of java.lang members. + exec 'syn match javaC_JavaLang "\%(\<Enum\.\)\@' . s:ff.Peek('5', '') . '<=\<EnumDesc\>"' + syn keyword javaC_JavaLang Class InheritableThreadLocal ThreadLocal Enum ClassValue + endif + " As of JDK 21, java.lang.Compiler is no more (deprecated in JDK 9). syn keyword javaLangDeprecated Compiler syn cluster javaClasses add=javaC_JavaLang @@ -181,55 +277,68 @@ if exists("java_highlight_all") || exists("java_highlight_java") || exists("ja hi def link javaC_Java javaC_ hi def link javaE_Java javaE_ hi def link javaX_Java javaX_ - hi def link javaX_ javaExceptions - hi def link javaR_ javaExceptions - hi def link javaE_ javaExceptions - hi def link javaC_ javaConstant - - syn keyword javaLangObject clone equals finalize getClass hashCode - syn keyword javaLangObject notify notifyAll toString wait - hi def link javaLangObject javaConstant + hi def link javaX_ javaExceptions + hi def link javaR_ javaExceptions + hi def link javaE_ javaExceptions + hi def link javaC_ javaConstant + + syn keyword javaLangObject getClass notify notifyAll wait + + " Lower the syntax priority of overridable java.lang.Object method + " names for zero-width matching (define g:java_highlight_signature + " and see their base declarations for java.lang.Object): + syn match javaLangObject "\<clone\>" + syn match javaLangObject "\<equals\>" + syn match javaLangObject "\<finalize\>" + syn match javaLangObject "\<hashCode\>" + syn match javaLangObject "\<toString\>" + hi def link javaLangObject javaConstant endif if filereadable(expand("<sfile>:p:h") . "/javaid.vim") source <sfile>:p:h/javaid.vim endif -if exists("java_space_errors") - if !exists("java_no_trail_space_error") - syn match javaSpaceError "\s\+$" +if exists("g:java_space_errors") + if !exists("g:java_no_trail_space_error") + syn match javaSpaceError "\s\+$" endif - if !exists("java_no_tab_space_error") - syn match javaSpaceError " \+\t"me=e-1 + if !exists("g:java_no_tab_space_error") + syn match javaSpaceError " \+\t"me=e-1 endif + hi def link javaSpaceError Error +endif + +exec 'syn match javaUserLabel "^\s*\<\K\k*\>\%(\<default\>\)\@' . s:ff.Peek('7', '') . '<!\s*::\@!"he=e-1' + +if s:ff.IsRequestedPreviewFeature(455) + syn region javaLabelRegion transparent matchgroup=javaLabel start="\<case\>" matchgroup=NONE end=":\|->" contains=javaBoolean,javaNumber,javaCharacter,javaString,javaConstant,@javaClasses,javaGenerics,javaType,javaLabelDefault,javaLabelVarType,javaLabelWhenClause +else + syn region javaLabelRegion transparent matchgroup=javaLabel start="\<case\>" matchgroup=NONE end=":\|->" contains=javaLabelCastType,javaLabelNumber,javaCharacter,javaString,javaConstant,@javaClasses,javaGenerics,javaLabelDefault,javaLabelVarType,javaLabelWhenClause + syn keyword javaLabelCastType contained char byte short int + syn match javaLabelNumber contained "\<0\>[lL]\@!" + syn match javaLabelNumber contained "\<\%(0\%([xX]\x\%(_*\x\)*\|_*\o\%(_*\o\)*\|[bB][01]\%(_*[01]\)*\)\|[1-9]\%(_*\d\)*\)\>[lL]\@!" + hi def link javaLabelCastType javaType + hi def link javaLabelNumber javaNumber endif -exec 'syn match javaUserLabel "^\s*\<\K\k*\>\%(\<default\>\)\@' . s:ff.Peek('7', '') . '<!\s*:"he=e-1' -syn region javaLabelRegion transparent matchgroup=javaLabel start="\<case\>" matchgroup=NONE end=":\|->" contains=javaLabelCastType,javaLabelNumber,javaCharacter,javaString,javaConstant,@javaClasses,javaLabelDefault,javaLabelVarType,javaLabelWhenClause syn region javaLabelRegion transparent matchgroup=javaLabel start="\<default\>\%(\s*\%(:\|->\)\)\@=" matchgroup=NONE end=":\|->" oneline " Consider grouped _default_ _case_ labels, i.e. " case null, default -> " case null: default: syn keyword javaLabelDefault contained default syn keyword javaLabelVarType contained var -syn keyword javaLabelCastType contained char byte short int " Allow for the contingency of the enclosing region not being able to " _keep_ its _end_, e.g. case ':':. -syn region javaLabelWhenClause contained transparent matchgroup=javaLabel start="\<when\>" matchgroup=NONE end=":"me=e-1 end="->"me=e-2 contains=TOP,javaExternal -syn match javaLabelNumber contained "\<0\>[lL]\@!" -syn match javaLabelNumber contained "\<\%(0\%([xX]\x\%(_*\x\)*\|_*\o\%(_*\o\)*\|[bB][01]\%(_*[01]\)*\)\|[1-9]\%(_*\d\)*\)\>[lL]\@!" -hi def link javaLabelDefault javaLabel -hi def link javaLabelVarType javaOperator -hi def link javaLabelNumber javaNumber -hi def link javaLabelCastType javaType +syn region javaLabelWhenClause contained transparent matchgroup=javaLabel start="\<when\>" matchgroup=NONE end=":"me=e-1 end="->"me=e-2 contains=TOP,javaExternal,javaLambdaDef " Comments -syn keyword javaTodo contained TODO FIXME XXX +syn keyword javaTodo contained TODO FIXME XXX -if exists("java_comment_strings") - syn region javaCommentString contained start=+"+ end=+"+ end=+$+ end=+\*/+me=s-1,he=s-1 contains=javaSpecial,javaCommentStar,javaSpecialChar,@Spell - syn region javaCommentString contained start=+"""[ \t\x0c\r]*$+hs=e+1 end=+"""+he=s-1 contains=javaSpecial,javaCommentStar,javaSpecialChar,@Spell,javaSpecialError,javaTextBlockError - syn region javaComment2String contained start=+"+ end=+$\|"+ contains=javaSpecial,javaSpecialChar,@Spell +if exists("g:java_comment_strings") + syn region javaCommentString contained start=+"+ end=+"+ end=+$+ end=+\*/+me=s-1,he=s-1 contains=javaSpecial,javaCommentStar,javaSpecialChar,@Spell + syn region javaCommentString contained start=+"""[ \t\x0c\r]*$+hs=e+1 end=+"""+he=s-1 contains=javaSpecial,javaCommentStar,javaSpecialChar,@Spell,javaSpecialError,javaTextBlockError + syn region javaComment2String contained start=+"+ end=+$\|"+ contains=javaSpecial,javaSpecialChar,@Spell syn match javaCommentCharacter contained "'\\[^']\{1,6\}'" contains=javaSpecialChar syn match javaCommentCharacter contained "'\\''" contains=javaSpecialChar syn match javaCommentCharacter contained "'[^\\]'" @@ -237,27 +346,65 @@ if exists("java_comment_strings") syn cluster javaCommentSpecial2 add=javaComment2String,javaCommentCharacter,javaNumber,javaStrTempl endif -syn region javaComment matchgroup=javaCommentStart start="/\*" end="\*/" contains=@javaCommentSpecial,javaTodo,javaCommentError,javaSpaceError,@Spell -syn match javaCommentStar contained "^\s*\*[^/]"me=e-1 -syn match javaCommentStar contained "^\s*\*$" +syn region javaComment matchgroup=javaCommentStart start="/\*" end="\*/" contains=@javaCommentSpecial,javaTodo,javaCommentError,javaSpaceError,@Spell fold +syn match javaCommentStar contained "^\s*\*[^/]"me=e-1 +syn match javaCommentStar contained "^\s*\*$" syn match javaLineComment "//.*" contains=@javaCommentSpecial2,javaTodo,javaCommentMarkupTag,javaSpaceError,@Spell syn match javaCommentMarkupTag contained "@\%(end\|highlight\|link\|replace\|start\)\>" nextgroup=javaCommentMarkupTagAttr,javaSpaceError skipwhite syn match javaCommentMarkupTagAttr contained "\<region\>" nextgroup=javaCommentMarkupTagAttr,javaSpaceError skipwhite -exec 'syn region javaCommentMarkupTagAttr contained transparent matchgroup=htmlArg start=/\<\%(re\%(gex\|gion\|placement\)\|substring\|t\%(arget\|ype\)\)\%(\s*=\)\@=/ matchgroup=htmlString end=/\%(=\s*\)\@' . s:ff.Peek('80', '') . '<=\%("[^"]\+"\|' . "\x27[^\x27]\\+\x27" . '\|\%([.-]\|\k\)\+\)/ nextgroup=javaCommentMarkupTagAttr,javaSpaceError skipwhite oneline' -hi def link javaCommentMarkupTagAttr htmlArg -hi def link javaCommentString javaString -hi def link javaComment2String javaString -hi def link javaCommentCharacter javaCharacter +exec 'syn region javaCommentMarkupTagAttr contained transparent matchgroup=javaHtmlArg start=/\<\%(re\%(gex\|gion\|placement\)\|substring\|t\%(arget\|ype\)\)\%(\s*=\)\@=/ matchgroup=javaHtmlString end=/\%(=\s*\)\@' . s:ff.Peek('80', '') . '<=\%("[^"]\+"\|' . "\x27[^\x27]\\+\x27" . '\|\%([.-]\|\k\)\+\)/ nextgroup=javaCommentMarkupTagAttr,javaSpaceError skipwhite oneline' syn match javaCommentError contained "/\*"me=e-1 display -hi def link javaCommentError javaError -hi def link javaCommentStart javaComment -if !exists("java_ignore_javadoc") && main_syntax != 'jsp' +if !exists("g:java_ignore_javadoc") && (s:with_html || s:with_markdown) && g:main_syntax != 'jsp' + " The overridable "html*" and "markdown*" default links must be + " defined _before_ the inclusion of the same default links from + " "html.vim" and "markdown.vim". + if s:with_html || s:with_markdown + hi def link htmlComment Special + hi def link htmlCommentPart Special + hi def link htmlArg Type + hi def link htmlString String + endif + + if s:with_markdown + hi def link markdownCode Special + hi def link markdownCodeBlock Special + hi def link markdownCodeDelimiter Special + hi def link markdownLinkDelimiter Comment + endif + syntax case ignore + " Note that javaDocSeeTag is valid in HTML and Markdown. + let s:ff.WithMarkdown = s:ff.RightConstant + " Include HTML syntax coloring for Javadoc comments. - syntax include @javaHtml syntax/html.vim - unlet b:current_syntax + if s:with_html + try + syntax include @javaHtml syntax/html.vim + finally + unlet! b:current_syntax + endtry + endif + + " Include Markdown syntax coloring (v7.2.437) for Javadoc comments. + if s:with_markdown + try + syntax include @javaMarkdown syntax/markdown.vim + let s:ff.WithMarkdown = s:ff.LeftConstant + catch /\<E48[45]:/ + call s:ReportOnce(v:exception) + unlockvar s:with_markdown + let s:with_markdown = 0 + lockvar s:with_markdown + hi clear markdownCode + hi clear markdownCodeBlock + hi clear markdownCodeDelimiter + hi clear markdownLinkDelimiter + finally + unlet! b:current_syntax + endtry + endif " HTML enables spell checking for all text that is not in a syntax " item (:syntax spell toplevel); instead, limit spell checking to @@ -268,100 +415,275 @@ if !exists("java_ignore_javadoc") && main_syntax != 'jsp' call s:ReportOnce(v:exception) endtry - syn region javaDocComment start="/\*\*" end="\*/" keepend contains=javaCommentTitle,@javaHtml,javaDocTags,javaDocSeeTag,javaDocCodeTag,javaDocSnippetTag,javaTodo,javaCommentError,javaSpaceError,@Spell - exec 'syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*" matchgroup=javaCommentTitle end="\.$" end="\.[ \t\r]\@=" end="\%(^\s*\**\s*\)\@' . s:ff.Peek('80', '') . '<=@"me=s-2,he=s-1 end="\*/"me=s-1,he=s-1 contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,javaDocTags,javaDocSeeTag,javaDocCodeTag,javaDocSnippetTag' - syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*\s*\r\=\n\=\s*\**\s*\%({@return\>\)\@=" matchgroup=javaCommentTitle end="}\%(\s*\.*\)*" contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,javaDocTags,javaDocSeeTag,javaDocCodeTag,javaDocSnippetTag - syn region javaDocTags contained start="{@\%(li\%(teral\|nk\%(plain\)\=\)\|inherit[Dd]oc\|doc[rR]oot\|value\)\>" end="}" - syn match javaDocTags contained "@\%(param\|exception\|throws\|since\)\s\+\S\+" contains=javaDocParam - syn match javaDocParam contained "\s\S\+" - syn match javaDocTags contained "@\%(version\|author\|return\|deprecated\|serial\%(Field\|Data\)\=\)\>" - syn region javaDocSeeTag contained matchgroup=javaDocTags start="@see\s\+" matchgroup=NONE end="\_."re=e-1 contains=javaDocSeeTagParam - syn match javaDocSeeTagParam contained @"\_[^"]\+"\|<a\s\+\_.\{-}</a>\|\%(\k\|\.\)*\%(#\k\+\%((\_[^)]*)\)\=\)\=@ contains=@javaHtml extend + if s:with_markdown + syn region javaMarkdownComment start="///" skip="^\s*///.*$" end="^" keepend contains=javaMarkdownCommentTitle,javaMarkdownShortcutLink,@javaMarkdown,@javaDocTags,javaTodo,@Spell nextgroup=javaMarkdownCommentTitle fold + syn match javaMarkdownCommentMask contained "^\s*///" + exec 'syn region javaMarkdownCommentTitle contained matchgroup=javaMarkdownComment start="\%(///.*\r\=\n\s*\)\@' . s:ff.Peek('80', '') . '<!///" matchgroup=javaMarkdownCommentTitle end="\.$" end="\.[ \t\r]\@=" end="\n\%(\s*///\s*$\)\@=" end="\%(^\s*///\s*\)\@' . s:ff.Peek('80', '') . '<=@"me=s-2,he=s-1 contains=javaMarkdownShortcutLink,@javaMarkdown,javaMarkdownCommentMask,javaTodo,@Spell,@javaDocTags' + exec 'syn region javaMarkdownCommentTitle contained matchgroup=javaMarkdownComment start="\%(///.*\r\=\n\s*\)\@' . s:ff.Peek('80', '') . '<!///\s*\%({@return\>\)\@=" matchgroup=javaMarkdownCommentTitle end="}\%(\s*\.*\)*" contains=javaMarkdownShortcutLink,@javaMarkdown,javaMarkdownCommentMask,javaTodo,@Spell,@javaDocTags,javaTitleSkipBlock' + exec 'syn region javaMarkdownCommentTitle contained matchgroup=javaMarkdownComment start="\%(///.*\r\=\n\s*\)\@' . s:ff.Peek('80', '') . '<!///\s*\%({@summary\>\)\@=" matchgroup=javaMarkdownCommentTitle end="}" contains=javaMarkdownShortcutLink,@javaMarkdown,javaMarkdownCommentMask,javaTodo,@Spell,@javaDocTags,javaTitleSkipBlock' + + syn clear markdownId markdownLineStart markdownH1 markdownH2 markdownHeadingRule markdownRule markdownCode markdownCodeBlock markdownIdDeclaration + " REDEFINE THE MARKDOWN ITEMS ANCHORED WITH "^", OBSERVING THE + " DEFINITION ORDER. + syn match markdownLineStart contained "^\s*///\s*[<@]\@!" contains=@markdownBlock,javaMarkdownCommentTitle,javaMarkdownCommentMask nextgroup=@markdownBlock,htmlSpecialChar + " See https://spec.commonmark.org/0.31.2/#setext-headings. + syn match markdownH1 contained "^\s*/// \{,3}.\+\r\=\n\s*/// \{,3}=\+\s*$" contains=@markdownInline,markdownHeadingRule,markdownAutomaticLink,javaMarkdownCommentMask + syn match markdownH2 contained "^\s*/// \{,3}.\+\r\=\n\s*/// \{,3}-\+\s*$" contains=@markdownInline,markdownHeadingRule,markdownAutomaticLink,javaMarkdownCommentMask + " See https://spec.commonmark.org/0.31.2/#atx-headings. + syn region markdownH1 contained matchgroup=markdownH1Delimiter start=" \{,3}#\s" end="#*\s*$" keepend contains=@markdownInline,markdownAutomaticLink oneline + syn region markdownH2 contained matchgroup=markdownH2Delimiter start=" \{,3}##\s" end="#*\s*$" keepend contains=@markdownInline,markdownAutomaticLink oneline + syn match markdownHeadingRule contained "^\s*/// \{,3}[=-]\+\s*$" contains=javaMarkdownCommentMask + " See https://spec.commonmark.org/0.31.2/#thematic-breaks. + syn match markdownRule contained "^\s*/// \{,3}\*\s*\*\%(\s*\*\)\+\s*$" contains=javaMarkdownCommentMask + syn match markdownRule contained "^\s*/// \{,3}_\s*_\%(\s*_\)\+\s*$" contains=javaMarkdownCommentMask + syn match markdownRule contained "^\s*/// \{,3}-\s*-\%(\s*-\)\+\s*$" contains=javaMarkdownCommentMask + " See https://spec.commonmark.org/0.31.2/#indented-code-blocks. + syn region markdownCodeBlock contained start="^\s*///\%( \{4,}\|\t\)" end="^\ze\s*///\%(\s*$\| \{,3}\S\)" keepend contains=javaMarkdownCommentMask + " See https://spec.commonmark.org/0.31.2/#code-spans. + syn region markdownCode contained matchgroup=markdownCodeDelimiter start="\z(`\+\) \=" end=" \=\z1" keepend contains=markdownLineStart,javaMarkdownCommentMask + " See https://spec.commonmark.org/0.31.2/#fenced-code-blocks. + syn region markdownCodeBlock contained start="^\s*/// \{,3}\z(```\+\)\%(.\{-}[^`]`\)\@!" end="^\s*/// \{,3}\z1`*" keepend contains=javaMarkdownCommentMask + syn region markdownCodeBlock contained start="^\s*/// \{,3}\z(\~\~\~\+\)" end="^\s*/// \{,3}\z1\~*" keepend contains=javaMarkdownCommentMask + " See https://spec.commonmark.org/0.31.2/#link-reference-definitions. + syn region markdownIdDeclaration contained matchgroup=markdownLinkDelimiter start="^\s*/// \{,3\}!\=\[" end="\]:" keepend contains=javaMarkdownCommentMask nextgroup=markdownUrl oneline skipwhite + " See https://spec.commonmark.org/0.31.2/#link-label. + syn region markdownId contained matchgroup=markdownIdDelimiter start="\[\%([\t ]\]\)\@!" end="\]" contains=javaMarkdownSkipBrackets,javaMarkdownCommentMask + " Note that escaped brackets can be unbalanced. + syn match javaMarkdownSkipBrackets contained transparent "\\\[\|\\\]" + " See https://spec.commonmark.org/0.31.2/#shortcut-reference-link. + syn region javaMarkdownShortcutLink contained matchgroup=markdownLinkTextDelimiter start="!\=\[^\@!\%(\_[^][]*\%(\[\_[^][]*\]\_[^][]*\)*]\%([[(]\)\@!\)\@=" end="\]\%([[(]\)\@!" contains=@markdownInline,markdownLineStart,javaMarkdownSkipBrackets,javaMarkdownCommentMask nextgroup=markdownLink,markdownId skipwhite + + for s:name in ['markdownFootnoteDefinition', 'markdownFootnote'] + if hlexists(s:name) + exec 'syn clear ' . s:name + endif + endfor + + unlet s:name + + " COMBAK: Footnotes are recognised by "markdown.vim", but are not + " in CommonMark. See https://pandoc.org/MANUAL.html#footnotes. +""""syn match markdownFootnoteDefinition contained "^\s*///\s*\[^[^\]]\+\]:" contains=javaMarkdownCommentMask + + hi def link javaMarkdownComment Comment + hi def link javaMarkdownCommentMask javaMarkdownComment + hi def link javaMarkdownCommentTitle SpecialComment + hi def link javaMarkdownShortcutLink htmlLink + endif + + if s:with_html + syn region javaDocComment start="/\*\*" end="\*/" keepend contains=javaCommentTitle,@javaHtml,@javaDocTags,javaTodo,javaCommentError,javaSpaceError,@Spell fold + exec 'syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*" matchgroup=javaCommentTitle end="\.$" end="\.[ \t\r]\@=" end="\%(^\s*\**\s*\)\@' . s:ff.Peek('80', '') . '<=@"me=s-2,he=s-1 end="\*/"me=s-1,he=s-1 contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,@javaDocTags' + syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*\s*\r\=\n\=\s*\**\s*\%({@return\>\)\@=" matchgroup=javaCommentTitle end="}\%(\s*\.*\)*" contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,@javaDocTags,javaTitleSkipBlock + syn region javaCommentTitle contained matchgroup=javaDocComment start="/\*\*\s*\r\=\n\=\s*\**\s*\%({@summary\>\)\@=" matchgroup=javaCommentTitle end="}" contains=@javaHtml,javaCommentStar,javaTodo,javaCommentError,javaSpaceError,@Spell,@javaDocTags,javaTitleSkipBlock + hi def link javaDocComment Comment + hi def link javaCommentTitle SpecialComment + endif + + " The members of javaDocTags are sub-grouped according to the Java + " version of their introduction, and sub-group members in turn are + " arranged in alphabetical order, so that future newer members can + " be pre-sorted and appended without disturbing the current member + " placement. + " Since they only have significance in javaCommentTitle, neither + " javaDocSummaryTag nor javaDocReturnTitleTag are defined. + syn cluster javaDocTags contains=javaDocAuthorTag,javaDocDeprecatedTag,javaDocExceptionTag,javaDocParamTag,javaDocReturnTag,javaDocSeeTag,javaDocVersionTag,javaDocSinceTag,javaDocLinkTag,javaDocSerialTag,javaDocSerialDataTag,javaDocSerialFieldTag,javaDocThrowsTag,javaDocDocRootTag,javaDocInheritDocTag,javaDocLinkplainTag,javaDocValueTag,javaDocCodeTag,javaDocLiteralTag,javaDocHiddenTag,javaDocIndexTag,javaDocProvidesTag,javaDocUsesTag,javaDocSystemPropertyTag,javaDocSnippetTag,javaDocSpecTag + + " Anticipate non-standard inline tags in {@return} and {@summary}. + syn region javaTitleSkipBlock contained transparent start="{\%(@\%(return\|summary\)\>\)\@!" end="}" + syn match javaDocDocRootTag contained "{@docRoot}" + syn match javaDocInheritDocTag contained "{@inheritDoc}" + syn region javaIndexSkipBlock contained transparent start="{\%(@index\>\)\@!" end="}" contains=javaIndexSkipBlock,javaDocIndexTag + syn region javaDocIndexTag contained start="{@index\>" end="}" contains=javaDocIndexTag,javaIndexSkipBlock + syn region javaLinkSkipBlock contained transparent start="{\%(@link\>\)\@!" end="}" contains=javaLinkSkipBlock,javaDocLinkTag + syn region javaDocLinkTag contained start="{@link\>" end="}" contains=javaDocLinkTag,javaLinkSkipBlock + syn region javaLinkplainSkipBlock contained transparent start="{\%(@linkplain\>\)\@!" end="}" contains=javaLinkplainSkipBlock,javaDocLinkplainTag + syn region javaDocLinkplainTag contained start="{@linkplain\>" end="}" contains=javaDocLinkplainTag,javaLinkplainSkipBlock + syn region javaLiteralSkipBlock contained transparent start="{\%(@literal\>\)\@!" end="}" contains=javaLiteralSkipBlock,javaDocLiteralTag + syn region javaDocLiteralTag contained start="{@literal\>" end="}" contains=javaDocLiteralTag,javaLiteralSkipBlock + syn region javaSystemPropertySkipBlock contained transparent start="{\%(@systemProperty\>\)\@!" end="}" contains=javaSystemPropertySkipBlock,javaDocSystemPropertyTag + syn region javaDocSystemPropertyTag contained start="{@systemProperty\>" end="}" contains=javaDocSystemPropertyTag,javaSystemPropertySkipBlock + syn region javaValueSkipBlock contained transparent start="{\%(@value\>\)\@!" end="}" contains=javaValueSkipBlock,javaDocValueTag + syn region javaDocValueTag contained start="{@value\>" end="}" contains=javaDocValueTag,javaValueSkipBlock + + syn match javaDocParam contained "\s\zs\S\+" + syn match javaDocExceptionTag contained "@exception\s\+\S\+" contains=javaDocParam + syn match javaDocParamTag contained "@param\s\+\S\+" contains=javaDocParam + syn match javaDocSinceTag contained "@since\s\+\S\+" contains=javaDocParam + syn match javaDocThrowsTag contained "@throws\s\+\S\+" contains=javaDocParam + syn match javaDocSpecTag contained "@spec\_s\+\S\+\ze\_s\+\S\+" contains=javaDocParam + + syn match javaDocAuthorTag contained "@author\>" + syn match javaDocDeprecatedTag contained "@deprecated\>" + syn match javaDocHiddenTag contained "@hidden\>" + syn match javaDocReturnTag contained "@return\>" + syn match javaDocSerialTag contained "@serial\>" + syn match javaDocSerialDataTag contained "@serialData\>" + syn match javaDocSerialFieldTag contained "@serialField\>" + syn match javaDocVersionTag contained "@version\>" + + syn match javaDocSeeTag contained "@see\>\s*" nextgroup=javaDocSeeTag1,javaDocSeeTag2,javaDocSeeTag3,javaDocSeeTag4,javaDocSeeTagStar,javaDocSeeTagSlash skipwhite skipempty + + if s:with_html + syn match javaDocSeeTagStar contained "^\s*\*\+\%(\s*{\=@\|/\|$\)\@!" nextgroup=javaDocSeeTag1,javaDocSeeTag2,javaDocSeeTag3,javaDocSeeTag4 skipwhite skipempty + hi def link javaDocSeeTagStar javaDocComment + endif + + if s:with_markdown + syn match javaDocSeeTagSlash contained "^\s*///\%(\s*{\=@\|$\)\@!" nextgroup=javaDocSeeTag1,javaDocSeeTag2,javaDocSeeTag3,javaDocSeeTag4 skipwhite skipempty + hi def link javaDocSeeTagSlash javaMarkdownComment + endif + + syn match javaDocSeeTag1 contained @"\_[^"]\+"@ + syn match javaDocSeeTag2 contained @<a\s\+\_.\{-}</a>@ contains=@javaHtml extend + exec 'syn match javaDocSeeTag3 contained @[' . s:ff.WithMarkdown('[', '') . '"< \t]\@!\%(\k\|[/.]\)*\%(##\=\k\+\%((\_[^)]*)\)\=\)\=@ nextgroup=javaDocSeeTag3Label skipwhite skipempty' + syn match javaDocSeeTag3Label contained @\k\%(\k\+\s*\)*$@ + + " COMBAK: No support for type javaDocSeeTag2 in Markdown. +""if s:with_markdown +"" syn match javaDocSeeTag4 contained @\[.\+\]\s\=\%(\[.\+\]\|(.\+)\)@ contains=@javaMarkdown extend +"" hi def link javaDocSeeTag4 Special +""endif + syn region javaCodeSkipBlock contained transparent start="{\%(@code\>\)\@!" end="}" contains=javaCodeSkipBlock,javaDocCodeTag syn region javaDocCodeTag contained start="{@code\>" end="}" contains=javaDocCodeTag,javaCodeSkipBlock - exec 'syn region javaDocSnippetTagAttr contained transparent matchgroup=htmlArg start=/\<\%(class\|file\|id\|lang\|region\)\%(\s*=\)\@=/ matchgroup=htmlString end=/:$/ end=/\%(=\s*\)\@' . s:ff.Peek('80', '') . '<=\%("[^"]\+"\|' . "\x27[^\x27]\\+\x27" . '\|\%([.\\/-]\|\k\)\+\)/ nextgroup=javaDocSnippetTagAttr skipwhite skipnl' + + exec 'syn region javaDocSnippetTagAttr contained transparent matchgroup=javaHtmlArg start=/\<\%(class\|file\|id\|lang\|region\)\%(\s*=\)\@=/ matchgroup=javaHtmlString end=/:$/ end=/\%(=\s*\)\@' . s:ff.Peek('80', '') . '<=\%("[^"]\+"\|' . "\x27[^\x27]\\+\x27" . '\|\%([.\\/-]\|\k\)\+\)/ nextgroup=javaDocSnippetTagAttr skipwhite skipnl' syn region javaSnippetSkipBlock contained transparent start="{\%(@snippet\>\)\@!" end="}" contains=javaSnippetSkipBlock,javaDocSnippetTag,javaCommentMarkupTag syn region javaDocSnippetTag contained start="{@snippet\>" end="}" contains=javaDocSnippetTag,javaSnippetSkipBlock,javaDocSnippetTagAttr,javaCommentMarkupTag syntax case match + hi def link javaDocParam Function + + hi def link javaDocAuthorTag Special + hi def link javaDocCodeTag Special + hi def link javaDocDeprecatedTag Special + hi def link javaDocDocRootTag Special + hi def link javaDocExceptionTag Special + hi def link javaDocHiddenTag Special + hi def link javaDocIndexTag Special + hi def link javaDocInheritDocTag Special + hi def link javaDocLinkTag Special + hi def link javaDocLinkplainTag Special + hi def link javaDocLiteralTag Special + hi def link javaDocParamTag Special + hi def link javaDocReturnTag Special + hi def link javaDocSeeTag Special + hi def link javaDocSeeTag1 String + hi def link javaDocSeeTag2 Special + hi def link javaDocSeeTag3 Function + hi def link javaDocSerialTag Special + hi def link javaDocSerialDataTag Special + hi def link javaDocSerialFieldTag Special + hi def link javaDocSinceTag Special + hi def link javaDocSnippetTag Special + hi def link javaDocSpecTag Special + hi def link javaDocSystemPropertyTag Special + hi def link javaDocThrowsTag Special + hi def link javaDocValueTag Special + hi def link javaDocVersionTag Special endif " match the special comment /**/ -syn match javaComment "/\*\*/" +syn match javaComment "/\*\*/" " Strings and constants -syn match javaSpecialError contained "\\." +syn match javaSpecialError contained "\\." syn match javaSpecialCharError contained "[^']" " Escape Sequences (JLS-17, §3.10.7): -syn match javaSpecialChar contained "\\\%(u\x\x\x\x\|[0-3]\o\o\|\o\o\=\|[bstnfr"'\\]\)" +syn match javaSpecialChar contained "\\\%(u\x\x\x\x\|[0-3]\o\o\|\o\o\=\|[bstnfr"'\\]\)" syn region javaString start=+"+ end=+"+ end=+$+ contains=javaSpecialChar,javaSpecialError,@Spell syn region javaString start=+"""[ \t\x0c\r]*$+hs=e+1 end=+"""+he=s-1 contains=javaSpecialChar,javaSpecialError,javaTextBlockError,@Spell syn match javaTextBlockError +"""\s*"""+ -syn region javaStrTemplEmbExp contained matchgroup=javaStrTempl start="\\{" end="}" contains=TOP -exec 'syn region javaStrTempl start=+\%(\.[[:space:]\n]*\)\@' . s:ff.Peek('80', '') . '<="+ end=+"+ contains=javaStrTemplEmbExp,javaSpecialChar,javaSpecialError,@Spell' -exec 'syn region javaStrTempl start=+\%(\.[[:space:]\n]*\)\@' . s:ff.Peek('80', '') . '<="""[ \t\x0c\r]*$+hs=e+1 end=+"""+he=s-1 contains=javaStrTemplEmbExp,javaSpecialChar,javaSpecialError,javaTextBlockError,@Spell' -syn match javaCharacter "'[^']*'" contains=javaSpecialChar,javaSpecialCharError -syn match javaCharacter "'\\''" contains=javaSpecialChar -syn match javaCharacter "'[^\\]'" + +if s:ff.IsRequestedPreviewFeature(430) + syn region javaStrTemplEmbExp contained matchgroup=javaStrTempl start="\\{" end="}" contains=TOP + exec 'syn region javaStrTempl start=+\%(\.[[:space:]\n]*\)\@' . s:ff.Peek('80', '') . '<="+ end=+"+ contains=javaStrTemplEmbExp,javaSpecialChar,javaSpecialError,@Spell' + exec 'syn region javaStrTempl start=+\%(\.[[:space:]\n]*\)\@' . s:ff.Peek('80', '') . '<="""[ \t\x0c\r]*$+hs=e+1 end=+"""+he=s-1 contains=javaStrTemplEmbExp,javaSpecialChar,javaSpecialError,javaTextBlockError,@Spell' + hi def link javaStrTempl Macro +endif + +syn match javaCharacter "'[^']*'" contains=javaSpecialChar,javaSpecialCharError +syn match javaCharacter "'\\''" contains=javaSpecialChar +syn match javaCharacter "'[^\\]'" " Integer literals (JLS-17, §3.10.1): -syn keyword javaNumber 0 0l 0L -syn match javaNumber "\<\%(0\%([xX]\x\%(_*\x\)*\|_*\o\%(_*\o\)*\|[bB][01]\%(_*[01]\)*\)\|[1-9]\%(_*\d\)*\)[lL]\=\>" +syn keyword javaNumber 0 0l 0L +syn match javaNumber "\<\%(0\%([xX]\x\%(_*\x\)*\|_*\o\%(_*\o\)*\|[bB][01]\%(_*[01]\)*\)\|[1-9]\%(_*\d\)*\)[lL]\=\>" " Decimal floating-point literals (JLS-17, §3.10.2): " Against "\<\d\+\>\.": -syn match javaNumber "\<\d\%(_*\d\)*\." -syn match javaNumber "\%(\<\d\%(_*\d\)*\.\%(\d\%(_*\d\)*\)\=\|\.\d\%(_*\d\)*\)\%([eE][-+]\=\d\%(_*\d\)*\)\=[fFdD]\=\>" -syn match javaNumber "\<\d\%(_*\d\)*[eE][-+]\=\d\%(_*\d\)*[fFdD]\=\>" -syn match javaNumber "\<\d\%(_*\d\)*\%([eE][-+]\=\d\%(_*\d\)*\)\=[fFdD]\>" +syn match javaNumber "\<\d\%(_*\d\)*\." +syn match javaNumber "\%(\<\d\%(_*\d\)*\.\%(\d\%(_*\d\)*\)\=\|\.\d\%(_*\d\)*\)\%([eE][-+]\=\d\%(_*\d\)*\)\=[fFdD]\=\>" +syn match javaNumber "\<\d\%(_*\d\)*[eE][-+]\=\d\%(_*\d\)*[fFdD]\=\>" +syn match javaNumber "\<\d\%(_*\d\)*\%([eE][-+]\=\d\%(_*\d\)*\)\=[fFdD]\>" " Hexadecimal floating-point literals (JLS-17, §3.10.2): -syn match javaNumber "\<0[xX]\%(\x\%(_*\x\)*\.\=\|\%(\x\%(_*\x\)*\)\=\.\x\%(_*\x\)*\)[pP][-+]\=\d\%(_*\d\)*[fFdD]\=\>" +syn match javaNumber "\<0[xX]\%(\x\%(_*\x\)*\.\=\|\%(\x\%(_*\x\)*\)\=\.\x\%(_*\x\)*\)[pP][-+]\=\d\%(_*\d\)*[fFdD]\=\>" " Unicode characters syn match javaSpecial "\\u\x\x\x\x" " Method declarations (JLS-17, §8.4.3, §8.4.4, §9.4). -if exists("java_highlight_functions") - syn cluster javaFuncParams contains=javaAnnotation,@javaClasses,javaType,javaVarArg,javaComment,javaLineComment +if exists("g:java_highlight_functions") + syn cluster javaFuncParams contains=javaAnnotation,@javaClasses,javaGenerics,javaType,javaVarArg,javaComment,javaLineComment - if java_highlight_functions =~# '^indent[1-8]\=$' - let s:last = java_highlight_functions[-1 :] - let s:indent = s:last != 't' ? repeat("\x20", s:last) : "\t" + if exists("g:java_highlight_signature") + syn cluster javaFuncParams add=javaParamModifier + hi def link javaFuncDefStart javaFuncDef + else syn cluster javaFuncParams add=javaScopeDecl,javaConceptKind,javaStorageClass,javaExternal + endif + + if g:java_highlight_functions =~# '^indent[1-8]\=$' + let s:last = g:java_highlight_functions[-1 :] + let s:indent = s:last != 't' ? repeat("\x20", s:last) : "\t" " Try to not match other type members, initialiser blocks, enum " constants (JLS-17, §8.9.1), and constructors (JLS-17, §8.1.7): " at any _conventional_ indentation, skip over all fields with " "[^=]*", all records with "\<record\s", and let the "*Skip*" " definitions take care of constructor declarations and enum - " constants (with no support for @Foo(value = "bar")). - exec 'syn region javaFuncDef start=+^' . s:indent . '\%(<[^>]\+>\+\s\+\|\%(\%(@\%(\K\k*\.\)*\K\k*\>\)\s\+\)\+\)\=\%(\<\K\k*\>\.\)*\K\k*\>[^=]*\%(\<record\)\@' . s:ff.Peek('6', '') . '<!\s\K\k*\s*(+ end=+)+ contains=@javaFuncParams' + " constants (with no support for @Foo(value = "bar")). Also, + " reject inlined declarations with "[^{]" for signature. + exec 'syn region javaFuncDef ' . s:ff.GroupArgs('transparent matchgroup=javaFuncDefStart', '') . ' start=/' . s:ff.PeekTo('\%(', '') . '^' . s:indent . '\%(<[^>]\+>\+\s\+\|\%(\%(@\%(\K\k*\.\)*\K\k*\>\)\s\+\)\+\)\=\%(\<\K\k*\>\.\)*\K\k*\>[^={]*\%(\<record\)\@' . s:ff.Peek('6', '') . '<!\s' . s:ff.PeekFrom('\)\@' . s:ff.Peek('80', '') . '<=', '') . '\K\k*\s*(/ end=/)/ contains=@javaFuncParams' " As long as package-private constructors cannot be matched with " javaFuncDef, do not look with javaConstructorSkipDeclarator for " them. - exec 'syn match javaConstructorSkipDeclarator transparent +^' . s:indent . '\%(\%(@\%(\K\k*\.\)*\K\k*\>\)\s\+\)*p\%(ublic\|rotected\|rivate\)\s\+\%(<[^>]\+>\+\s\+\)\=\K\k*\s*\ze(+ contains=javaAnnotation,javaScopeDecl' - exec 'syn match javaEnumSkipArgumentativeConstant transparent +^' . s:indent . '\%(\%(@\%(\K\k*\.\)*\K\k*\>\)\s\+\)*\K\k*\s*\ze(+ contains=javaAnnotation' + exec 'syn match javaConstructorSkipDeclarator transparent /^' . s:indent . '\%(\%(@\%(\K\k*\.\)*\K\k*\>\)\s\+\)*p\%(ublic\|rotected\|rivate\)\s\+\%(<[^>]\+>\+\s\+\)\=\K\k*\s*\ze(/ contains=javaAnnotation,javaScopeDecl,javaClassDecl,javaTypedef,javaGenerics' + " With a zero-width span for signature applicable on demand to + " javaFuncDef, make related adjustments: + " (1) Claim all enum constants of a line as a unit. + exec 'syn match javaEnumSkipConstant contained transparent /^' . s:indent . '\%(\%(\%(@\%(\K\k*\.\)*\K\k*\>\)\s\+\)*\K\k*\s*\%((.*)\)\=\s*[,;({]\s*\)\+/ contains=@javaEnumConstants' + " (2) Define a syntax group for top level enumerations and tell + " apart their constants from method declarations. + exec 'syn region javaTopEnumDeclaration transparent start=/\%(^\%(\%(@\%(\K\k*\.\)*\K\k*\>\)\s\+\)*\%(p\%(ublic\|rotected\|rivate\)\s\+\)\=\%(strictfp\s\+\)\=\<enum\_s\+\)\@' . s:ff.Peek('80', '') . '<=\K\k*\%(\_s\+implements\_s.\+\)\=\_s*{/ end=/}/ contains=@javaTop,javaEnumSkipConstant' + " (3) Define a base variant of javaParenT without using @javaTop + " in order to not include javaFuncDef. + syn region javaParenE transparent matchgroup=javaParen start="(" end=")" contains=@javaEnumConstants,javaInParen + syn region javaParenE transparent matchgroup=javaParen start="\[" end="\]" contains=@javaEnumConstants + syn cluster javaEnumConstants contains=TOP,javaTopEnumDeclaration,javaFuncDef,javaParenT unlet s:indent s:last else " This is the "style" variant (:help ft-java-syntax). - syn cluster javaFuncParams add=javaScopeDecl,javaConceptKind,javaStorageClass,javaExternal " Match arbitrarily indented camelCasedName method declarations. " Match: [@É] [abstract] [<α, β>] Τʬ[<γ>][[][]] μÊÊ(/* ... */); - exec 'syn region javaFuncDef start=/' . s:ff.Engine('\%#=2', '') . '^\s\+\%(\%(@\%(\K\k*\.\)*\K\k*\>\)\s\+\)*\%(p\%(ublic\|rotected\|rivate\)\s\+\)\=\%(\%(abstract\|default\)\s\+\|\%(\%(final\|\%(native\|strictfp\)\|s\%(tatic\|ynchronized\)\)\s\+\)*\)\=\%(<.*[[:space:]-]\@' . s:ff.Peek('1', '') . '<!>\s\+\)\=\%(void\|\%(b\%(oolean\|yte\)\|char\|short\|int\|long\|float\|double\|\%(\<\K\k*\>\.\)*\<' . s:ff.UpperCase('[$_[:upper:]]', '[^a-z0-9]') . '\k*\>\%(<[^(){}]*[[:space:]-]\@' . s:ff.Peek('1', '') . '<!>\)\=\)\%(\[\]\)*\)\s\+\<' . s:ff.LowerCase('[$_[:lower:]]', '[^A-Z0-9]') . '\k*\>\s*(/ end=/)/ skip=/\/\*.\{-}\*\/\|\/\/.*$/ contains=@javaFuncParams' + exec 'syn region javaFuncDef ' . s:ff.GroupArgs('transparent matchgroup=javaFuncDefStart', '') . ' start=/' . s:ff.Engine('\%#=2', '') . s:ff.PeekTo('\%(', '') . '^\s\+\%(\%(@\%(\K\k*\.\)*\K\k*\>\)\s\+\)*\%(p\%(ublic\|rotected\|rivate\)\s\+\)\=\%(\%(abstract\|default\)\s\+\|\%(\%(final\|\%(native\|strictfp\)\|s\%(tatic\|ynchronized\)\)\s\+\)*\)\=\%(<.*[[:space:]-]\@' . s:ff.Peek('1', '') . '<!>\s\+\)\=\%(void\|\%(b\%(oolean\|yte\)\|char\|short\|int\|long\|float\|double\|\%(\<\K\k*\>\.\)*\<' . s:ff.UpperCase('[$_[:upper:]]', '[^a-z0-9]') . '\k*\>\%(<[^(){}]*[[:space:]-]\@' . s:ff.Peek('1', '') . '<!>\)\=\)\%(\[\]\)*\)\s\+' . s:ff.PeekFrom('\)\@' . s:ff.Peek('80', '') . '<=', '') . '\<' . s:ff.LowerCase('[$_[:lower:]]', '[^A-Z0-9]') . '\k*\>\s*(/ end=/)/ skip=/\/\*.\{-}\*\/\|\/\/.*$/ contains=@javaFuncParams' endif - - exec 'syn match javaLambdaDef "\<\K\k*\>\%(\<default\>\)\@' . s:ff.Peek('7', '') . '<!\s*->"' - syn match javaBraces "[{}]" endif -if exists("java_highlight_debug") +if exists("g:java_highlight_debug") " Strings and constants syn match javaDebugSpecial contained "\\\%(u\x\x\x\x\|[0-3]\o\o\|\o\o\=\|[bstnfr"'\\]\)" - syn region javaDebugString contained start=+"+ end=+"+ contains=javaDebugSpecial + syn region javaDebugString contained start=+"+ end=+"+ contains=javaDebugSpecial syn region javaDebugString contained start=+"""[ \t\x0c\r]*$+hs=e+1 end=+"""+he=s-1 contains=javaDebugSpecial,javaDebugTextBlockError - " The highlight groups of java{StrTempl,Debug{,Paren,StrTempl}}\, - " share one colour by default. Do not conflate unrelated parens. - syn region javaDebugStrTemplEmbExp contained matchgroup=javaDebugStrTempl start="\\{" end="}" contains=javaComment,javaLineComment,javaDebug\%(Paren\)\@!.* - exec 'syn region javaDebugStrTempl contained start=+\%(\.[[:space:]\n]*\)\@' . s:ff.Peek('80', '') . '<="+ end=+"+ contains=javaDebugStrTemplEmbExp,javaDebugSpecial' - exec 'syn region javaDebugStrTempl contained start=+\%(\.[[:space:]\n]*\)\@' . s:ff.Peek('80', '') . '<="""[ \t\x0c\r]*$+hs=e+1 end=+"""+he=s-1 contains=javaDebugStrTemplEmbExp,javaDebugSpecial,javaDebugTextBlockError' + + if s:ff.IsRequestedPreviewFeature(430) + " The highlight groups of java{StrTempl,Debug{,Paren,StrTempl}}\, + " share one colour by default. Do not conflate unrelated parens. + syn region javaDebugStrTemplEmbExp contained matchgroup=javaDebugStrTempl start="\\{" end="}" contains=javaComment,javaLineComment,javaDebug\%(Paren\)\@!.* + exec 'syn region javaDebugStrTempl contained start=+\%(\.[[:space:]\n]*\)\@' . s:ff.Peek('80', '') . '<="+ end=+"+ contains=javaDebugStrTemplEmbExp,javaDebugSpecial' + exec 'syn region javaDebugStrTempl contained start=+\%(\.[[:space:]\n]*\)\@' . s:ff.Peek('80', '') . '<="""[ \t\x0c\r]*$+hs=e+1 end=+"""+he=s-1 contains=javaDebugStrTemplEmbExp,javaDebugSpecial,javaDebugTextBlockError' + hi def link javaDebugStrTempl Macro + endif + syn match javaDebugTextBlockError contained +"""\s*"""+ syn match javaDebugCharacter contained "'[^\\]'" syn match javaDebugSpecialCharacter contained "'\\.'" @@ -375,7 +697,7 @@ if exists("java_highlight_debug") syn match javaDebugNumber contained "\<0[xX]\%(\x\%(_*\x\)*\.\=\|\%(\x\%(_*\x\)*\)\=\.\x\%(_*\x\)*\)[pP][-+]\=\d\%(_*\d\)*[fFdD]\=\>" syn keyword javaDebugBoolean contained true false syn keyword javaDebugType contained null this super - syn region javaDebugParen start=+(+ end=+)+ contained contains=javaDebug.*,javaDebugParen + syn region javaDebugParen contained start=+(+ end=+)+ contains=javaDebug.*,javaDebugParen " To make this work, define the highlighting for these groups. syn match javaDebug "\<System\.\%(out\|err\)\.print\%(ln\)\=\s*("me=e-1 contains=javaDebug.* nextgroup=javaDebugParen @@ -385,53 +707,88 @@ if exists("java_highlight_debug") " FIXME: What API do "trace*" belong to? " syn match javaDebug "\<trace[SL]\=\s*("me=e-1 contains=javaDebug.* nextgroup=javaDebugParen - hi def link javaDebug Debug - hi def link javaDebugString DebugString - hi def link javaDebugStrTempl Macro - hi def link javaDebugTextBlockError Error - hi def link javaDebugType DebugType - hi def link javaDebugBoolean DebugBoolean - hi def link javaDebugNumber Debug - hi def link javaDebugSpecial DebugSpecial - hi def link javaDebugSpecialCharacter DebugSpecial - hi def link javaDebugCharacter DebugString - hi def link javaDebugParen Debug - - hi def link DebugString String - hi def link DebugSpecial Special - hi def link DebugBoolean Boolean - hi def link DebugType Type + hi def link javaDebug Debug + hi def link javaDebugString DebugString + hi def link javaDebugTextBlockError Error + hi def link javaDebugType DebugType + hi def link javaDebugBoolean DebugBoolean + hi def link javaDebugNumber Debug + hi def link javaDebugSpecial DebugSpecial + hi def link javaDebugSpecialCharacter DebugSpecial + hi def link javaDebugCharacter DebugString + hi def link javaDebugParen Debug + + hi def link DebugString String + hi def link DebugSpecial Special + hi def link DebugBoolean Boolean + hi def link DebugType Type endif -if exists("java_mark_braces_in_parens_as_errors") - syn match javaInParen contained "[{}]" - hi def link javaInParen javaError +" Try not to fold top-level-type bodies under assumption that there is +" but one such body. +exec 'syn region javaBlock transparent start="\%(^\|^\S[^:]\+\)\@' . s:ff.Peek('120', '') . '<!{" end="}" fold' + +if exists("g:java_mark_braces_in_parens_as_errors") + syn match javaInParen contained "[{}]" + hi def link javaInParen javaError endif " catch errors caused by wrong parenthesis -syn region javaParenT transparent matchgroup=javaParen start="(" end=")" contains=@javaTop,javaParenT1 -syn region javaParenT1 transparent matchgroup=javaParen1 start="(" end=")" contains=@javaTop,javaParenT2 contained -syn region javaParenT2 transparent matchgroup=javaParen2 start="(" end=")" contains=@javaTop,javaParenT contained -syn match javaParenError ")" +syn region javaParenT transparent matchgroup=javaParen start="(" end=")" contains=@javaTop,javaInParen,javaParenT1 +syn region javaParenT1 contained transparent matchgroup=javaParen1 start="(" end=")" contains=@javaTop,javaInParen,javaParenT2 +syn region javaParenT2 contained transparent matchgroup=javaParen2 start="(" end=")" contains=@javaTop,javaInParen,javaParenT +syn match javaParenError ")" " catch errors caused by wrong square parenthesis -syn region javaParenT transparent matchgroup=javaParen start="\[" end="\]" contains=@javaTop,javaParenT1 -syn region javaParenT1 transparent matchgroup=javaParen1 start="\[" end="\]" contains=@javaTop,javaParenT2 contained -syn region javaParenT2 transparent matchgroup=javaParen2 start="\[" end="\]" contains=@javaTop,javaParenT contained -syn match javaParenError "\]" - -hi def link javaParenError javaError +syn region javaParenT transparent matchgroup=javaParen start="\[" end="\]" contains=@javaTop,javaParenT1 +syn region javaParenT1 contained transparent matchgroup=javaParen1 start="\[" end="\]" contains=@javaTop,javaParenT2 +syn region javaParenT2 contained transparent matchgroup=javaParen2 start="\[" end="\]" contains=@javaTop,javaParenT +syn match javaParenError "\]" + +" Lambda expressions (JLS-17, §15.27) and method reference expressions +" (JLS-17, §15.13). +if exists("g:java_highlight_functions") + syn match javaMethodRef ":::\@!" + + if exists("g:java_highlight_signature") + let s:ff.LambdaDef = s:ff.LeftConstant + else + let s:ff.LambdaDef = s:ff.RightConstant + endif -if exists("java_highlight_functions") " Make ()-matching definitions after the parenthesis error catcher. - exec 'syn match javaLambdaDef "\k\@' . s:ff.Peek('4', '') . '<!(\%(\k\|[[:space:]<>?\[\]@,.]\)*)\s*->"' + " + " Note that here and elsewhere a single-line token is used for \z, + " with other tokens repeated as necessary, to overcome the lack of + " support for multi-line matching with \z. + " + " Match: ([@A [@B ...] final] var a[, var b, ...]) -> + " | ([@A [@B ...] final] T[<α>][[][]] a[, T b, ...]) -> + " There is no recognition of expressions interspersed with comments + " or of expressions whose parameterised parameter types are written + " across multiple lines. + exec 'syn ' . s:ff.LambdaDef('region javaLambdaDef transparent matchgroup=javaLambdaDefStart start=/', 'match javaLambdaDef "') . '\k\@' . s:ff.Peek('4', '') . '<!(' . s:ff.LambdaDef('\%(', '') . '[[:space:]\n]*\%(\%(@\%(\K\k*\.\)*\K\k*\>\%((\_.\{-1,})\)\{-,1}[[:space:]\n]\+\)*\%(final[[:space:]\n]\+\)\=\%(\<\K\k*\>\.\)*\<\K\k*\>\%(<[^(){}]*[[:space:]-]\@' . s:ff.Peek('1', '') . '<!>\)\=\%(\%(\%(\[\]\)\+\|\.\.\.\)\)\=[[:space:]\n]\+\<\K\k*\>\%(\[\]\)*\%(,[[:space:]\n]*\)\=\)\+)[[:space:]\n]*' . s:ff.LambdaDef('\z(->\)\)\@=/ end=/)[[:space:]\n]*\z1/', '->"') . ' contains=javaAnnotation,javaParamModifier,javaLambdaVarType,javaType,@javaClasses,javaGenerics,javaVarArg' + " Match: () -> + " | (a[, b, ...]) -> + exec 'syn ' . s:ff.LambdaDef('region javaLambdaDef transparent matchgroup=javaLambdaDefStart start=/', 'match javaLambdaDef "') . '\k\@' . s:ff.Peek('4', '') . '<!(' . s:ff.LambdaDef('\%(', '') . '[[:space:]\n]*\%(\<\K\k*\>\%(,[[:space:]\n]*\)\=\)*)[[:space:]\n]*' . s:ff.LambdaDef('\z(->\)\)\@=/ end=/)[[:space:]\n]*\z1/', '->"') + " Match: a -> + exec 'syn ' . s:ff.LambdaDef('region javaLambdaDef transparent start=/', 'match javaLambdaDef "') . '\<\K\k*\>\%(\<default\>\)\@' . s:ff.Peek('7', '') . '<!' . s:ff.LambdaDef('\%([[:space:]\n]*\z(->\)\)\@=/ matchgroup=javaLambdaDefStart end=/\z1/', '[[:space:]\n]*->"') + + syn keyword javaParamModifier contained final + syn keyword javaLambdaVarType contained var + hi def link javaParamModifier javaConceptKind + hi def link javaLambdaVarType javaOperator + hi def link javaLambdaDef javaFuncDef + hi def link javaLambdaDefStart javaFuncDef + hi def link javaMethodRef javaFuncDef + hi def link javaFuncDef Function endif " The @javaTop cluster comprises non-contained Java syntax groups. " Note that the syntax file "aidl.vim" relies on its availability. -syn cluster javaTop contains=TOP,javaDocComment,javaFold,javaParenError,javaParenT +syn cluster javaTop contains=TOP,javaTopEnumDeclaration -if !exists("java_minlines") - let java_minlines = 10 +if !exists("g:java_minlines") + let g:java_minlines = 10 endif " Note that variations of a /*/ balanced comment, e.g., /*/*/, /*//*/, @@ -440,17 +797,11 @@ endif " to make synchronisation start further towards file's beginning by " bumping up g:java_minlines or issuing ':syntax sync fromstart' or " preferring &foldmethod set to 'syntax'. -exec "syn sync ccomment javaComment minlines=" . java_minlines +exec "syn sync ccomment javaComment minlines=" . g:java_minlines " The default highlighting. -hi def link javaLambdaDef Function -hi def link javaFuncDef Function hi def link javaVarArg Function -hi def link javaBraces Function hi def link javaBranch Conditional -hi def link javaUserLabelRef javaUserLabel -hi def link javaLabel Label -hi def link javaUserLabel Label hi def link javaConditional Conditional hi def link javaRepeat Repeat hi def link javaExceptions Exception @@ -459,60 +810,91 @@ hi def link javaStorageClass StorageClass hi def link javaMethodDecl javaStorageClass hi def link javaClassDecl javaStorageClass hi def link javaScopeDecl javaStorageClass -hi def link javaConceptKind NonText +hi def link javaConceptKind javaStorageClass -hi def link javaBoolean Boolean -hi def link javaSpecial Special +hi def link javaBoolean Boolean +hi def link javaSpecial Special hi def link javaSpecialError Error hi def link javaSpecialCharError Error hi def link javaString String -hi def link javaStrTempl Macro hi def link javaCharacter Character hi def link javaSpecialChar SpecialChar hi def link javaNumber Number hi def link javaError Error +hi def link javaError2 javaError hi def link javaTextBlockError Error +hi def link javaParenError javaError hi def link javaStatement Statement hi def link javaOperator Operator -hi def link javaComment Comment -hi def link javaDocComment Comment -hi def link javaLineComment Comment hi def link javaConstant Constant -hi def link javaTypedef Typedef +hi def link javaTypedef Typedef hi def link javaTodo Todo hi def link javaAnnotation PreProc +hi def link javaAnnotationStart javaAnnotation +hi def link javaType Type +hi def link javaExternal Include + +hi def link javaUserLabel Label +hi def link javaUserLabelRef javaUserLabel +hi def link javaLabel Label +hi def link javaLabelDefault javaLabel +hi def link javaLabelVarType javaOperator -hi def link javaCommentTitle SpecialComment -hi def link javaDocTags Special -hi def link javaDocCodeTag Special -hi def link javaDocSnippetTag Special -hi def link javaDocParam Function -hi def link javaDocSeeTagParam Function +hi def link javaComment Comment hi def link javaCommentStar javaComment +hi def link javaLineComment Comment +hi def link javaCommentMarkupTagAttr javaHtmlArg +hi def link javaCommentString javaString +hi def link javaComment2String javaString +hi def link javaCommentCharacter javaCharacter +hi def link javaCommentError javaError +hi def link javaCommentStart javaComment -hi def link javaType Type -hi def link javaExternal Include +hi def link javaHtmlArg Type +hi def link javaHtmlString String -hi def link htmlComment Special -hi def link htmlCommentPart Special -hi def link htmlArg Type -hi def link htmlString String -hi def link javaSpaceError Error +let b:current_syntax = "java" -if s:module_info_cur_buf - hi def link javaModuleStorageClass StorageClass - hi def link javaModuleStmt Statement - hi def link javaModuleExternal Include +if g:main_syntax == 'java' + unlet g:main_syntax endif -let b:current_syntax = "java" +if exists("s:clear_java_ignore_html") + unlet! s:clear_java_ignore_html g:java_ignore_html +endif -if main_syntax == 'java' - unlet main_syntax +if exists("s:clear_java_ignore_markdown") + unlet! s:clear_java_ignore_markdown g:java_ignore_markdown endif let b:spell_options = "contained" let &cpo = s:cpo_save -unlet s:module_info_cur_buf s:ff s:cpo_save +unlet s:cpo_save s:ff s:with_html s:with_markdown -" vim: sw=2 ts=8 noet sta +" See ":help vim9-mix". +if !has("vim9script") + finish +endif + +if exists("g:java_foldtext_show_first_or_second_line") + def! s:LazyPrefix(prefix: string, dashes: string, count: number): string + return empty(prefix) + ? printf('+-%s%3d lines: ', dashes, count) + : prefix + enddef + + def! s:JavaSyntaxFoldTextExpr(): string + # Piggyback on NGETTEXT. + const summary: string = foldtext() + return getline(v:foldstart) !~ '/\*\+\s*$' + ? summary + : LazyPrefix(matchstr(summary, '^+-\+\s*\d\+\s.\{-1,}:\s'), + v:folddashes, + (v:foldend - v:foldstart + 1)) .. + getline(v:foldstart + 1) + enddef + + setlocal foldtext=s:JavaSyntaxFoldTextExpr() + delfunction! g:JavaSyntaxFoldTextExpr +endif +" vim: fdm=syntax sw=2 ts=8 noet sta diff --git a/runtime/syntax/javascript.vim b/runtime/syntax/javascript.vim index e3b4cdf703..c73f5d7097 100644 --- a/runtime/syntax/javascript.vim +++ b/runtime/syntax/javascript.vim @@ -10,6 +10,7 @@ " Last Change: 2022 Jun 09 " 2013 Jun 12: adjusted javaScriptRegexpString (Kevin Locke) " 2018 Apr 14: adjusted javaScriptRegexpString (LongJohnCoder) +" 2024 Aug 14: fix a few stylistic issues (#15480) " tuning parameters: " unlet javaScript_fold @@ -59,14 +60,15 @@ syn keyword javaScriptType Array Boolean Date Function Number Object String Reg syn keyword javaScriptStatement return with await yield syn keyword javaScriptBoolean true false syn keyword javaScriptNull null undefined -syn keyword javaScriptIdentifier arguments this var let +syn keyword javaScriptIdentifier arguments this syn keyword javaScriptLabel case default syn keyword javaScriptException try catch finally throw syn keyword javaScriptMessage alert confirm prompt status syn keyword javaScriptGlobal self window top parent syn keyword javaScriptMember document event location syn keyword javaScriptDeprecated escape unescape -syn keyword javaScriptReserved abstract boolean byte char class const debugger double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile async +syn keyword javaScriptReserved abstract boolean byte char class const debugger double enum export extends final float from goto implements import int interface let long native package private protected public short super synchronized throws transient var volatile async +syn keyword javaScriptModifier static syn cluster javaScriptEmbededExpr contains=javaScriptBoolean,javaScriptNull,javaScriptIdentifier,javaScriptStringD,javaScriptStringS,javaScriptStringT @@ -110,7 +112,7 @@ hi def link javaScriptBranch Conditional hi def link javaScriptOperator Operator hi def link javaScriptType Type hi def link javaScriptStatement Statement -hi def link javaScriptFunction Function +hi def link javaScriptFunction Keyword hi def link javaScriptBraces Function hi def link javaScriptError Error hi def link javaScrParenError javaScriptError @@ -126,6 +128,7 @@ hi def link javaScriptGlobal Keyword hi def link javaScriptMember Keyword hi def link javaScriptDeprecated Exception hi def link javaScriptReserved Keyword +hi def link javaScriptModifier StorageClass hi def link javaScriptDebug Debug hi def link javaScriptConstant Label hi def link javaScriptEmbed Special diff --git a/runtime/syntax/jinja.vim b/runtime/syntax/jinja.vim new file mode 100644 index 0000000000..6000855ff7 --- /dev/null +++ b/runtime/syntax/jinja.vim @@ -0,0 +1,86 @@ +" Vim syntax file +" Language: Jinja +" Maintainer: Gregory Anders +" Upstream: https://gitlab.com/HiPhish/jinja.vim + +if exists('b:current_syntax') + finish +endif + +syntax case match +syntax sync fromstart + +" Jinja template built-in tags and parameters (without filter, macro, is and raw, they +" have special threatment) +syn keyword jinjaStatement containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained and if else in not or recursive as import + +syn keyword jinjaStatement containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained is filter skipwhite nextgroup=jinjaFilter +syn keyword jinjaStatement containedin=jinjaTagBlock contained macro skipwhite nextgroup=jinjaFunction +syn keyword jinjaStatement containedin=jinjaTagBlock contained block skipwhite nextgroup=jinjaBlockName + +" Variable Names +syn match jinjaVariable containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained /[a-zA-Z_][a-zA-Z0-9_]*/ +syn keyword jinjaSpecial containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained false true none False True None loop super caller varargs kwargs + +" Filters +syn match jinjaOperator "|" containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained skipwhite nextgroup=jinjaFilter +syn match jinjaFilter contained /[a-zA-Z_][a-zA-Z0-9_]*/ +syn match jinjaFunction contained /[a-zA-Z_][a-zA-Z0-9_]*/ +syn match jinjaBlockName contained /[a-zA-Z_][a-zA-Z0-9_]*/ + +" Jinja template constants +syn region jinjaString containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained start=/"/ skip=/\(\\\)\@<!\(\(\\\\\)\@>\)*\\"/ end=/"/ +syn region jinjaString containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained start=/'/ skip=/\(\\\)\@<!\(\(\\\\\)\@>\)*\\'/ end=/'/ +syn match jinjaNumber containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained /[0-9]\+\(\.[0-9]\+\)\?/ + +" Operators +syn match jinjaOperator containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained /[+\-*\/<>=!,:]/ +syn match jinjaPunctuation containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained /[()\[\]]/ +syn match jinjaOperator containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained /\./ nextgroup=jinjaAttribute +syn match jinjaAttribute contained /[a-zA-Z_][a-zA-Z0-9_]*/ + +" Jinja template tag and variable blocks +syn region jinjaNested matchgroup=jinjaOperator start="(" end=")" transparent display containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained +syn region jinjaNested matchgroup=jinjaOperator start="\[" end="\]" transparent display containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained +syn region jinjaNested matchgroup=jinjaOperator start="{" end="}" transparent display containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained +syn region jinjaTagBlock matchgroup=jinjaTagDelim start=/{%-\?/ end=/-\?%}/ containedin=ALLBUT,jinjaTagBlock,jinjaVarBlock,jinjaRaw,jinjaString,jinjaNested,jinjaComment + +syn region jinjaVarBlock matchgroup=jinjaVarDelim start=/{{-\?/ end=/-\?}}/ containedin=ALLBUT,jinjaTagBlock,jinjaVarBlock,jinjaRaw,jinjaString,jinjaNested,jinjaComment + +" Jinja template 'raw' tag +syn region jinjaRaw matchgroup=jinjaRawDelim start="{%\s*raw\s*%}" end="{%\s*endraw\s*%}" containedin=ALLBUT,jinjaTagBlock,jinjaVarBlock,jinjaString,jinjaComment + +" Jinja comments +syn region jinjaComment matchgroup=jinjaCommentDelim start="{#" end="#}" containedin=ALLBUT,jinjaTagBlock,jinjaVarBlock,jinjaString + +" Block start keywords. A bit tricker. We only highlight at the start of a +" tag block and only if the name is not followed by a comma or equals sign +" which usually means that we have to deal with an assignment. +syn match jinjaStatement containedin=jinjaTagBlock contained /\({%-\?\s*\)\@<=\<[a-zA-Z_][a-zA-Z0-9_]*\>\(\s*[,=]\)\@!/ + +" and context modifiers +syn match jinjaStatement containedin=jinjaTagBlock contained /\<with\(out\)\?\s\+context\>/ + +hi def link jinjaPunctuation jinjaOperator +hi def link jinjaAttribute jinjaVariable +hi def link jinjaFunction jinjaFilter + +hi def link jinjaTagDelim jinjaTagBlock +hi def link jinjaVarDelim jinjaVarBlock +hi def link jinjaCommentDelim jinjaComment +hi def link jinjaRawDelim jinja + +hi def link jinjaSpecial Special +hi def link jinjaOperator Normal +hi def link jinjaRaw Normal +hi def link jinjaTagBlock PreProc +hi def link jinjaVarBlock PreProc +hi def link jinjaStatement Statement +hi def link jinjaFilter Function +hi def link jinjaBlockName Function +hi def link jinjaVariable Identifier +hi def link jinjaString Constant +hi def link jinjaNumber Constant +hi def link jinjaComment Comment + +let b:current_syntax = 'jinja' diff --git a/runtime/syntax/kconfig.vim b/runtime/syntax/kconfig.vim index c7a305b73c..0aecc00060 100644 --- a/runtime/syntax/kconfig.vim +++ b/runtime/syntax/kconfig.vim @@ -1,7 +1,7 @@ " Vim syntax file " Maintainer: Christian Brabandt <cb@256bit.org> " Previous Maintainer: Nikolai Weibull <now@bitwi.se> -" Latest Revision: 2015-05-29 +" Latest Revision: 2024-07-19 " License: Vim (see :h license) " Repository: https://github.com/chrisbra/vim-kconfig @@ -715,8 +715,6 @@ syn region kconfigHelpText \ skip='^$' \ end='^\z1\@!' -syn sync match kconfigSyncHelp grouphere kconfigHelpText 'help\|---help---' - hi def link kconfigTodo Todo hi def link kconfigComment Comment hi def link kconfigKeyword Keyword diff --git a/runtime/syntax/kdl.vim b/runtime/syntax/kdl.vim new file mode 100644 index 0000000000..97e8f93b61 --- /dev/null +++ b/runtime/syntax/kdl.vim @@ -0,0 +1,48 @@ +" Vim syntax file +" Language: KDL +" Maintainer: Aram Drevekenin <aram@poor.dev> +" Maintainer: Yinzuo Jiang <jiangyinzuo@foxmail.com> +" Latest Revision: 2024-06-16 + +" quit when a syntax file was already loaded +if exists("b:current_syntax") + finish +endif + +syn match kdlNode '\v(\w|-|\=)' display +syn match kdlBool '\v(true|false)' display + +syn keyword kdlTodo contained TODO FIXME XXX NOTE +syn region kdlComment start="//" end="$" contains=kdlTodo,@Spell +syn region kdlComment start="/\*" end="\*/" contains=kdlTodo,@Spell + +" Regular int like number with - + or nothing in front +syn match kdlNumber '\d\+' +syn match kdlNumber '[-+]\d\+' + +" Floating point number with decimal no E or e (+,-) +syn match kdlNumber '\d\+\.\d*' contained display +syn match kdlNumber '[-+]\d\+\.\d*' contained display + +" Floating point like number with E and no decimal point (+,-) +syn match kdlNumber '[-+]\=\d[[:digit:]]*[eE][\-+]\=\d\+' contained display +syn match kdlNumber '\d[[:digit:]]*[eE][\-+]\=\d\+' contained display + +" Floating point like number with E and decimal point (+,-) +syn match kdlNumber '[-+]\=\d[[:digit:]]*\.\d*[eE][\-+]\=\d\+' contained display +syn match kdlNumber '\d[[:digit:]]*\.\d*[eE][\-+]\=\d\+' contained display + +syn region kdlString start='"' end='"' skip='\\\\\|\\"' display + +syn region kdlChildren start="{" end="}" contains=kdlString,kdlNumber,kdlNode,kdlBool,kdlComment + +hi def link kdlTodo Todo +hi def link kdlComment Comment +hi def link kdlNode Statement +hi def link kdlBool Boolean +hi def link kdlString String +hi def link kdlNumber Number + +let b:current_syntax = "kdl" + +" vim: sw=2 sts=2 et diff --git a/runtime/syntax/kivy.vim b/runtime/syntax/kivy.vim index b145503478..d4bccfc147 100644 --- a/runtime/syntax/kivy.vim +++ b/runtime/syntax/kivy.vim @@ -1,9 +1,9 @@ " Vim syntax file " Language: Kivy -" Maintainer: Corey Prophitt <prophitt.corey@gmail.com> -" Last Change: May 29th, 2014 +" Maintainer: Corey Prophitt <corey@prophitt.me> +" Last Change: Jul 31st, 2024 " Version: 1 -" URL: http://kivy.org/ +" URL: https://kivy.org/ if exists("b:current_syntax") finish @@ -13,11 +13,11 @@ endif syn include @pyth $VIMRUNTIME/syntax/python.vim " Kivy language rules can be found here -" http://kivy.org/docs/guide/lang.html +" https://kivy.org/doc/stable/guide/lang.html " Define Kivy syntax syn match kivyPreProc /#:.*/ -syn match kivyComment /#.*/ +syn match kivyComment /#[^:].*/ syn match kivyRule /<\I\i*\(,\s*\I\i*\)*>:/ syn match kivyAttribute /\<\I\i*\>/ nextgroup=kivyValue diff --git a/runtime/syntax/lc.vim b/runtime/syntax/lc.vim index a334529385..1991c1b582 100644 --- a/runtime/syntax/lc.vim +++ b/runtime/syntax/lc.vim @@ -2,6 +2,7 @@ " Language: Elsa " Maintainer: Miles Glapa-Grossklag <miles@glapa-grossklag.com> " Last Change: 2023-01-29 +" 2024 May 25 by Riley Bruins <ribru17@gmail.com> (move 'commentstring' to ftplugin) if exists('b:current_syntax') finish @@ -13,7 +14,6 @@ syntax match elsaKeyword "\v:" highlight link elsaKeyword Keyword " Comments -setlocal commentstring=--%s syntax match elsaComment "\v--.*$" highlight link elsaComment Comment diff --git a/runtime/syntax/logindefs.vim b/runtime/syntax/logindefs.vim index 8cb4295eda..51fa19992c 100644 --- a/runtime/syntax/logindefs.vim +++ b/runtime/syntax/logindefs.vim @@ -1,7 +1,8 @@ -" Vim syntax file +" Vim syntax file for login.defs(5) " Language: login.defs(5) configuration file " Previous Maintainer: Nikolai Weibull <now@bitwi.se> " Latest Revision: 2010-11-29 +" 2024 Jul 12 by Vim Project: Update keywords if exists("b:current_syntax") finish @@ -35,6 +36,8 @@ syn keyword logindefsBooleanKeyword contained \ CREATE_HOME \ DEFAULT_HOME \ FAILLOG_ENAB + \ FORCE_SHADOW + \ GRANT_AUX_GROUP_SUBIDS \ LASTLOG_ENAB \ LOG_OK_LOGINS \ LOG_UNKFAIL_ENAB @@ -54,15 +57,20 @@ syn keyword logindefsBoolean contained yes no syn keyword logindefsEncryptKeyword contained \ ENCRYPT_METHOD + \ HMAC_CRYPTO_ALGO \ nextgroup=logindefsEncryptMethod skipwhite syn keyword logindefsEncryptMethod contained + \ BCRYPT \ DES \ MD5 \ SHA256 \ SHA512 + \ YESCRYPT syn keyword logindefsNumberKeyword contained + \ BCRYPT_MAX_ROUNDS + \ BCRYPT_MIN_ROUNDS \ ERASECHAR \ FAIL_DELAY \ GID_MAX @@ -79,6 +87,12 @@ syn keyword logindefsNumberKeyword contained \ PASS_MIN_LEN \ SHA_CRYPT_MAX_ROUNDS \ SHA_CRYPT_MIN_ROUNDS + \ SUB_GID_COUNT + \ SUB_GID_MAX + \ SUB_GID_MIN + \ SUB_UID_COUNT + \ SUB_UID_MAX + \ SUB_UID_MIN \ SYS_GID_MAX \ SYS_GID_MIN \ SYS_UID_MAX @@ -86,9 +100,15 @@ syn keyword logindefsNumberKeyword contained \ UID_MAX \ UID_MIN \ ULIMIT - \ UMASK + \ YESCRYPT_COST_FACTOR \ nextgroup=@logindefsNumber skipwhite +syn keyword logindefsNumberKeyword contained + \ HOME_MODE + \ TTYPERM + \ UMASK + \ nextgroup=logindefsOctal,logindefsOctalError skipwhite + syn cluster logindefsNumber contains= \ logindefsDecimal, \ logindefsHex, @@ -114,6 +134,7 @@ syn keyword logindefsPathKeyword contained \ MAIL_DIR \ MAIL_FILE \ NOLOGINS_FILE + \ NONEXISTENT \ SULOG_FILE \ TTYTYPE_FILE \ nextgroup=logindefsPath skipwhite @@ -138,9 +159,9 @@ syn keyword logindefsStringKeyword contained \ ENV_HZ \ ENV_TZ \ LOGIN_STRING + \ PREVENT_NO_AUTH \ SU_NAME \ TTYGROUP - \ TTYPERM \ USERDEL_CMD \ nextgroup=logindefsString skipwhite diff --git a/runtime/syntax/lyrics.vim b/runtime/syntax/lyrics.vim index 42a288b51b..fd127988f2 100644 --- a/runtime/syntax/lyrics.vim +++ b/runtime/syntax/lyrics.vim @@ -2,7 +2,7 @@ " Language: LyRiCs " Maintainer: ObserverOfTime <chronobserver@disroot.org> " Filenames: *.lrc -" Last Change: 2022 Sep 18 +" Last Change: 2024 Sep 20 if exists('b:current_syntax') finish @@ -23,7 +23,7 @@ syn match lrcTagName contained nextgroup=lrcTagValue syn match lrcTagValue /:\zs.\+\ze\]/ contained " Lyrics -syn match lrcLyricTime /^\s*\[\d\d:\d\d\.\d\d\]/ +syn match lrcLyricTime /^\s*\(\[\d\d:\d\d\.\d\d\]\)\+/ \ contains=lrcNumber nextgroup=lrcLyricLine syn match lrcLyricLine /.*$/ contained contains=lrcWordTime,@Spell syn match lrcWordTime /<\d\d:\d\d\.\d\d>/ contained contains=lrcNumber,@NoSpell diff --git a/runtime/syntax/make.vim b/runtime/syntax/make.vim index b4573044ca..d3ddf78291 100644 --- a/runtime/syntax/make.vim +++ b/runtime/syntax/make.vim @@ -28,8 +28,13 @@ syn match makePreCondit "^!\s*\(cmdswitches\|error\|message\|include\|if\|ifdef\ syn case match " identifiers -syn region makeIdent start="\$(" skip="\\)\|\\\\" end=")" contains=makeStatement,makeIdent -syn region makeIdent start="\${" skip="\\}\|\\\\" end="}" contains=makeStatement,makeIdent +if exists("b:make_microsoft") || exists("make_microsoft") + syn region makeIdent start="\$(" end=")" contains=makeStatement,makeIdent + syn region makeIdent start="\${" end="}" contains=makeStatement,makeIdent +else + syn region makeIdent start="\$(" skip="\\)\|\\\\" end=")" contains=makeStatement,makeIdent + syn region makeIdent start="\${" skip="\\}\|\\\\" end="}" contains=makeStatement,makeIdent +endif syn match makeIdent "\$\$\w*" syn match makeIdent "\$[^({]" syn match makeIdent "^ *[^:#= \t]*\s*[:+?!*]="me=e-2 @@ -78,11 +83,13 @@ syn match makeOverride "^ *override\>" syn match makeStatement contained "(\(abspath\|addprefix\|addsuffix\|and\|basename\|call\|dir\|error\|eval\|file\|filter-out\|filter\|findstring\|firstword\|flavor\|foreach\|guile\|if\|info\|join\|lastword\|notdir\|or\|origin\|patsubst\|realpath\|shell\|sort\|strip\|subst\|suffix\|value\|warning\|wildcard\|word\|wordlist\|words\)\>"ms=s+1 " Comment -if exists("make_microsoft") - syn match makeComment "#.*" contains=@Spell,makeTodo -elseif !exists("make_no_comments") - syn region makeComment start="#" end="^$" end="[^\\]$" keepend contains=@Spell,makeTodo - syn match makeComment "#$" contains=@Spell +if !exists("make_no_comments") + if exists("b:make_microsoft") || exists("make_microsoft") + syn match makeComment "#.*" contains=@Spell,makeTodo + else + syn region makeComment start="#" end="^$" end="[^\\]$" keepend contains=@Spell,makeTodo + syn match makeComment "#$" contains=@Spell + endif endif syn keyword makeTodo TODO FIXME XXX contained diff --git a/runtime/syntax/mediawiki.vim b/runtime/syntax/mediawiki.vim new file mode 100644 index 0000000000..8ac30b93db --- /dev/null +++ b/runtime/syntax/mediawiki.vim @@ -0,0 +1,292 @@ +" mediawiki.vim (formerly named Wikipedia.vim) +" +" Vim syntax file +" Language: MediaWiki +" Maintainer: Avid Seeker <avidseeker7@protonmail.com> +" Home: http://en.wikipedia.org/wiki/Wikipedia:Text_editor_support#Vim +" Last Change: 2024 Jul 14 +" Credits: [[User:Unforgettableid]] [[User:Aepd87]], [[User:Danny373]], [[User:Ingo Karkat]], et al. +" +" Published on Wikipedia in 2003-04 and declared authorless. +" +" Based on the HTML syntax file. Probably too closely based, in fact. +" There may well be name collisions everywhere, but ignorance is bliss, +" so they say. +" + +if exists("b:current_syntax") + finish +endif + +syntax case ignore +syntax spell toplevel + +" Mark illegal characters +sy match htmlError "[<>&]" + +" Tags +sy region htmlString contained start=+"+ end=+"+ contains=htmlSpecialChar,@htmlPreproc +sy region htmlString contained start=+'+ end=+'+ contains=htmlSpecialChar,@htmlPreproc +sy match htmlValue contained "=[\t ]*[^'" \t>][^ \t>]*"hs=s+1 contains=@htmlPreproc +sy region htmlEndTag start=+</+ end=+>+ contains=htmlTagN,htmlTagError +sy region htmlTag start=+<[^/]+ end=+>+ contains=htmlTagN,htmlString,htmlArg,htmlValue,htmlTagError,htmlEvent,htmlCssDefinition,@htmlPreproc,@htmlArgCluster +sy match htmlTagN contained +<\s*[-a-zA-Z0-9]\++hs=s+1 contains=htmlTagName,htmlSpecialTagName,@htmlTagNameCluster +sy match htmlTagN contained +</\s*[-a-zA-Z0-9]\++hs=s+2 contains=htmlTagName,htmlSpecialTagName,@htmlTagNameCluster +sy match htmlTagError contained "[^>]<"ms=s+1 + +" Allowed HTML tag names +sy keyword htmlTagName contained big blockquote br caption center cite code +sy keyword htmlTagName contained dd del div dl dt font hr ins li +sy keyword htmlTagName contained ol p pre rb rp rt ruby s small span strike sub +sy keyword htmlTagName contained sup table td th tr tt ul var +sy match htmlTagName contained "\<\(b\|i\|u\|h[1-6]\|em\|strong\)\>" +" Allowed Wiki tag names +sy keyword htmlTagName contained math nowiki references source syntaxhighlight + +" Allowed arg names +sy keyword htmlArg contained align lang dir width height nowrap bgcolor clear +sy keyword htmlArg contained noshade cite datetime size face color type start +sy keyword htmlArg contained value compact summary border frame rules +sy keyword htmlArg contained cellspacing cellpadding valign char charoff +sy keyword htmlArg contained colgroup col span abbr axis headers scope rowspan +sy keyword htmlArg contained colspan id class name style title + +" Special characters +sy match htmlSpecialChar "&#\=[0-9A-Za-z]\{1,8};" + +" Comments +sy region htmlComment start=+<!+ end=+>+ contains=htmlCommentPart,htmlCommentError +sy match htmlCommentError contained "[^><!]" +sy region htmlCommentPart contained start=+--+ end=+--\s*+ contains=@htmlPreProc +sy region htmlComment start=+<!DOCTYPE+ keepend end=+>+ + +if !exists("html_no_rendering") + sy cluster htmlTop contains=@Spell,htmlTag,htmlEndTag,htmlSpecialChar,htmlPreProc,htmlComment,htmlLink,@htmlPreproc + + sy region htmlBold start="<b\>" end="</b>"me=e-4 contains=@htmlTop,htmlBoldUnderline,htmlBoldItalic + sy region htmlBold start="<strong\>" end="</strong>"me=e-9 contains=@htmlTop,htmlBoldUnderline,htmlBoldItalic + sy region htmlBoldUnderline contained start="<u\>" end="</u>"me=e-4 contains=@htmlTop,htmlBoldUnderlineItalic + sy region htmlBoldItalic contained start="<i\>" end="</i>"me=e-4 contains=@htmlTop,htmlBoldItalicUnderline + sy region htmlBoldItalic contained start="<em\>" end="</em>"me=e-5 contains=@htmlTop,htmlBoldItalicUnderline + sy region htmlBoldUnderlineItalic contained start="<i\>" end="</i>"me=e-4 contains=@htmlTop + sy region htmlBoldUnderlineItalic contained start="<em\>" end="</em>"me=e-5 contains=@htmlTop + sy region htmlBoldItalicUnderline contained start="<u\>" end="</u>"me=e-4 contains=@htmlTop,htmlBoldUnderlineItalic + + sy region htmlUnderline start="<u\>" end="</u>"me=e-4 contains=@htmlTop,htmlUnderlineBold,htmlUnderlineItalic + sy region htmlUnderlineBold contained start="<b\>" end="</b>"me=e-4 contains=@htmlTop,htmlUnderlineBoldItalic + sy region htmlUnderlineBold contained start="<strong\>" end="</strong>"me=e-9 contains=@htmlTop,htmlUnderlineBoldItalic + sy region htmlUnderlineItalic contained start="<i\>" end="</i>"me=e-4 contains=@htmlTop,htmlUnderlineItalicBold + sy region htmlUnderlineItalic contained start="<em\>" end="</em>"me=e-5 contains=@htmlTop,htmlUnderlineItalicBold + sy region htmlUnderlineItalicBold contained start="<b\>" end="</b>"me=e-4 contains=@htmlTop + sy region htmlUnderlineItalicBold contained start="<strong\>" end="</strong>"me=e-9 contains=@htmlTop + sy region htmlUnderlineBoldItalic contained start="<i\>" end="</i>"me=e-4 contains=@htmlTop + sy region htmlUnderlineBoldItalic contained start="<em\>" end="</em>"me=e-5 contains=@htmlTop + + sy region htmlItalic start="<i\>" end="</i>"me=e-4 contains=@htmlTop,htmlItalicBold,htmlItalicUnderline + sy region htmlItalic start="<em\>" end="</em>"me=e-5 contains=@htmlTop + sy region htmlItalicBold contained start="<b\>" end="</b>"me=e-4 contains=@htmlTop,htmlItalicBoldUnderline + sy region htmlItalicBold contained start="<strong\>" end="</strong>"me=e-9 contains=@htmlTop,htmlItalicBoldUnderline + sy region htmlItalicBoldUnderline contained start="<u\>" end="</u>"me=e-4 contains=@htmlTop + sy region htmlItalicUnderline contained start="<u\>" end="</u>"me=e-4 contains=@htmlTop,htmlItalicUnderlineBold + sy region htmlItalicUnderlineBold contained start="<b\>" end="</b>"me=e-4 contains=@htmlTop + sy region htmlItalicUnderlineBold contained start="<strong\>" end="</strong>"me=e-9 contains=@htmlTop + + sy region htmlH1 start="<h1\>" end="</h1>"me=e-5 contains=@htmlTop + sy region htmlH2 start="<h2\>" end="</h2>"me=e-5 contains=@htmlTop + sy region htmlH3 start="<h3\>" end="</h3>"me=e-5 contains=@htmlTop + sy region htmlH4 start="<h4\>" end="</h4>"me=e-5 contains=@htmlTop + sy region htmlH5 start="<h5\>" end="</h5>"me=e-5 contains=@htmlTop + sy region htmlH6 start="<h6\>" end="</h6>"me=e-5 contains=@htmlTop +endif + + +" No htmlTop and wikiPre inside HTML preformatted areas, because +" MediaWiki renders everything in there literally (HTML tags and +" entities, too): <pre> tags work as the combination of <nowiki> and +" the standard HTML <pre> tag: the content will preformatted, and it +" will not be parsed, but shown as in the wikitext source. +" +" With wikiPre, indented lines would be rendered differently from +" unindented lines. +sy match htmlPreTag /<pre\>[^>]*>/ contains=htmlTag +sy match htmlPreEndTag /<\/pre>/ contains=htmlEndTag +sy match wikiNowikiTag /<nowiki>/ contains=htmlTag +sy match wikiNowikiEndTag /<\/nowiki>/ contains=htmlEndTag +sy match wikiSourceTag /<source\s\+[^>]\+>/ contains=htmlTag +sy match wikiSourceEndTag /<\/source>/ contains=htmlEndTag +sy match wikiSyntaxHLTag /<syntaxhighlight\s\+[^>]\+>/ contains=htmlTag +sy match wikiSyntaxHLEndTag /<\/syntaxhighlight>/ contains=htmlEndTag + +" Note: Cannot use 'start="<pre>"rs=e', so still have the <pre> tag +" highlighted correctly via separate sy-match. Unfortunately, this will +" also highlight <pre> tags inside the preformatted region. +sy region htmlPre start="<pre\>[^>]*>" end="<\/pre>"me=e-6 contains=htmlPreTag +sy region wikiNowiki start="<nowiki>" end="<\/nowiki>"me=e-9 contains=wikiNowikiTag +sy region wikiSource start="<source\s\+[^>]\+>" keepend end="<\/source>"me=e-9 contains=wikiSourceTag +sy region wikiSyntaxHL start="<syntaxhighlight\s\+[^>]\+>" keepend end="<\/syntaxhighlight>"me=e-18 contains=wikiSyntaxHLTag + +sy include @TeX syntax/tex.vim +unlet b:current_syntax +sy region wikiTeX matchgroup=htmlTag start="<math>" end="<\/math>" contains=@texMathZoneGroup,wikiNowiki,wikiNowikiEndTag +sy region wikiRef matchgroup=htmlTag start="<ref>" end="<\/ref>" contains=wikiNowiki,wikiNowikiEndTag + +sy cluster wikiText contains=wikiLink,wikiTemplate,wikiNowiki,wikiNowikiEndTag,wikiItalic,wikiBold,wikiBoldAndItalic + +" Tables +sy cluster wikiTableFormat contains=wikiTemplate,htmlString,htmlArg,htmlValue +sy region wikiTable matchgroup=wikiTableSeparator start="{|" end="|}" contains=wikiTableHeaderLine,wikiTableCaptionLine,wikiTableNewRow,wikiTableHeadingCell,wikiTableNormalCell,@wikiText +sy match wikiTableSeparator /^!/ contained +sy match wikiTableSeparator /^|/ contained +sy match wikiTableSeparator /^|[+-]/ contained +sy match wikiTableSeparator /||/ contained +sy match wikiTableSeparator /!!/ contained +sy match wikiTableFormatEnd /[!|]/ contained +sy match wikiTableHeadingCell /\(^!\|!!\)\([^!|]*|\)\?.*/ contains=wikiTableSeparator,@wikiText,wikiTableHeadingFormat +" Require at least one '=' in the format, to avoid spurious matches (e.g. +" the | in [[foo|bar]] might be taken as the final |, indicating the beginning +" of the cell). The same is done for wikiTableNormalFormat below. +sy match wikiTableHeadingFormat /\%(^!\|!!\)[^!|]\+=[^!|]\+\([!|]\)\(\1\)\@!/me=e-1 contains=@wikiTableFormat,wikiTableSeparator nextgroup=wikiTableFormatEnd +sy match wikiTableNormalCell /\(^|\|||\)\([^|]*|\)\?.*/ contains=wikiTableSeparator,@wikiText,wikiTableNormalFormat +sy match wikiTableNormalFormat /\(^|\|||\)[^|]\+=[^|]\+||\@!/me=e-1 contains=@wikiTableFormat,wikiTableSeparator nextgroup=wikiTableFormatEnd +sy match wikiTableHeaderLine /\(^{|\)\@<=.*$/ contained contains=@wikiTableFormat +sy match wikiTableCaptionLine /^|+.*$/ contained contains=wikiTableSeparator,@wikiText +sy match wikiTableNewRow /^|-.*$/ contained contains=wikiTableSeparator,@wikiTableFormat + +sy cluster wikiTop contains=@Spell,wikiLink,wikiNowiki,wikiNowikiEndTag + +sy region wikiItalic start=+'\@<!'''\@!+ end=+''+ oneline contains=@wikiTop,wikiItalicBold +sy region wikiBold start=+'''+ end=+'''+ oneline contains=@wikiTop,wikiBoldItalic +sy region wikiBoldAndItalic start=+'''''+ end=+'''''+ oneline contains=@wikiTop + +sy region wikiBoldItalic contained start=+'\@<!'''\@!+ end=+''+ oneline contains=@wikiTop +sy region wikiItalicBold contained start=+'''+ end=+'''+ oneline contains=@wikiTop + +sy region wikiH1 start="^=" end="=" oneline contains=@wikiTop +sy region wikiH2 start="^==" end="==" oneline contains=@wikiTop +sy region wikiH3 start="^===" end="===" oneline contains=@wikiTop +sy region wikiH4 start="^====" end="====" oneline contains=@wikiTop +sy region wikiH5 start="^=====" end="=====" oneline contains=@wikiTop +sy region wikiH6 start="^======" end="======" oneline contains=@wikiTop + +sy region wikiLink start="\[\[" end="\]\]\(s\|'s\|es\|ing\|\)" oneline contains=wikiLink,wikiNowiki,wikiNowikiEndTag + +sy region wikiLink start="https\?://" end="\W*\_s"me=s-1 oneline +sy region wikiLink start="\[http:" end="\]" oneline contains=wikiNowiki,wikiNowikiEndTag +sy region wikiLink start="\[https:" end="\]" oneline contains=wikiNowiki,wikiNowikiEndTag +sy region wikiLink start="\[ftp:" end="\]" oneline contains=wikiNowiki,wikiNowikiEndTag +sy region wikiLink start="\[gopher:" end="\]" oneline contains=wikiNowiki,wikiNowikiEndTag +sy region wikiLink start="\[news:" end="\]" oneline contains=wikiNowiki,wikiNowikiEndTag +sy region wikiLink start="\[mailto:" end="\]" oneline contains=wikiNowiki,wikiNowikiEndTag + +sy match wikiTemplateName /{{[^{|}<>\[\]]\+/hs=s+2 contained +sy region wikiTemplate start="{{" end="}}" keepend extend contains=wikiNowiki,wikiNowikiEndTag,wikiTemplateName,wikiTemplateParam,wikiTemplate,wikiLink +sy region wikiTemplateParam start="{{{\s*\d" end="}}}" extend contains=wikiTemplateName + +sy match wikiParaFormatChar /^[\:|\*|;|#]\+/ +sy match wikiParaFormatChar /^-----*/ +sy match wikiPre /^\ .*$/ contains=wikiNowiki,wikiNowikiEndTag + +" HTML highlighting + +hi def link htmlTag Function +hi def link htmlEndTag Identifier +hi def link htmlArg Type +hi def link htmlTagName htmlStatement +hi def link htmlSpecialTagName Exception +hi def link htmlValue String +hi def link htmlSpecialChar Special + +if !exists("html_no_rendering") + hi def link htmlTitle Title + hi def link htmlH1 htmlTitle + hi def link htmlH2 htmlTitle + hi def link htmlH3 htmlTitle + hi def link htmlH4 htmlTitle + hi def link htmlH5 htmlTitle + hi def link htmlH6 htmlTitle + + hi def link htmlPreProc PreProc + hi def link htmlHead htmlPreProc + hi def link htmlPreProcAttrName htmlPreProc + hi def link htmlPreStmt htmlPreProc + + hi def link htmlSpecial Special + hi def link htmlCssDefinition htmlSpecial + hi def link htmlEvent htmlSpecial + hi def link htmlSpecialChar htmlSpecial + + hi def link htmlComment Comment + hi def link htmlCommentPart htmlComment + hi def link htmlCssStyleComment htmlComment + + hi def link htmlString String + hi def link htmlPreAttr htmlString + hi def link htmlValue htmlString + + hi def link htmlError Error + hi def link htmlBadArg htmlError + hi def link htmlBadTag htmlError + hi def link htmlCommentError htmlError + hi def link htmlPreError htmlError + hi def link htmlPreProcAttrError htmlError + hi def link htmlTagError htmlError + + hi def link htmlStatement Statement + + hi def link htmlConstant Constant + + hi def link htmlBoldItalicUnderline htmlBoldUnderlineItalic + hi def link htmlUnderlineItalicBold htmlBoldUnderlineItalic + hi def link htmlUnderlineBoldItalic htmlBoldUnderlineItalic + hi def link htmlItalicBoldUnderline htmlBoldUnderlineItalic + hi def link htmlItalicUnderlineBold htmlBoldUnderlineItalic + + hi def link htmlItalicBold htmlBoldItalic + hi def link htmlItalicUnderline htmlUnderlineItalic + hi def link htmlUnderlineBold htmlBoldUnderline + + hi def link htmlLink Underlined + + if !exists("html_style_rendering") + hi def htmlBold term=bold cterm=bold gui=bold + hi def htmlBoldUnderline term=bold,underline cterm=bold,underline gui=bold,underline + hi def htmlBoldItalic term=bold,italic cterm=bold,italic gui=bold,italic + hi def htmlBoldUnderlineItalic term=bold,italic,underline cterm=bold,italic,underline gui=bold,italic,underline + hi def htmlUnderline term=underline cterm=underline gui=underline + hi def htmlUnderlineItalic term=italic,underline cterm=italic,underline gui=italic,underline + hi def htmlItalic term=italic cterm=italic gui=italic + endif +endif + +" Wiki highlighting + +hi def link wikiItalic htmlItalic +hi def link wikiBold htmlBold +hi def link wikiBoldItalic htmlBoldItalic +hi def link wikiItalicBold htmlBoldItalic +hi def link wikiBoldAndItalic htmlBoldItalic + +hi def link wikiH1 htmlTitle +hi def link wikiH2 htmlTitle +hi def link wikiH3 htmlTitle +hi def link wikiH4 htmlTitle +hi def link wikiH5 htmlTitle +hi def link wikiH6 htmlTitle + +hi def link wikiLink htmlLink +hi def link wikiTemplate htmlSpecial +hi def link wikiTemplateParam htmlSpecial +hi def link wikiTemplateName Type +hi def link wikiParaFormatChar htmlSpecial +hi def link wikiPre htmlConstant +hi def link wikiRef htmlComment + +hi def link htmlPre wikiPre +hi def link wikiSource wikiPre +hi def link wikiSyntaxHL wikiPre + +hi def link wikiTableSeparator Statement +hi def link wikiTableFormatEnd wikiTableSeparator +hi def link wikiTableHeadingCell htmlBold + +let b:current_syntax = "mediawiki" diff --git a/runtime/syntax/mma.vim b/runtime/syntax/mma.vim index d2f22e9be5..802cbe5538 100644 --- a/runtime/syntax/mma.vim +++ b/runtime/syntax/mma.vim @@ -2,6 +2,7 @@ " Language: Mathematica " Maintainer: steve layland <layland@wolfram.com> " Last Change: 2012 Feb 03 by Thilo Six +" 2024 May 24 by Riley Bruins <ribru17@gmail.com> (remove 'commentstring') " Source: http://members.wri.com/layland/vim/syntax/mma.vim " http://vim.sourceforge.net/scripts/script.php?script_id=1273 " Id: $Id: mma.vim,v 1.4 2006/04/14 20:40:38 vimboss Exp $ @@ -248,7 +249,6 @@ syntax match mmaBoring "[(){}]" contained "syntax region mmaRegion start="(\*\+[^<]*<!--[^>]*\*\+)" end="--> \*)" containedin=ALLBUT,@mmaStrings transparent fold keepend " show fold text -set commentstring='(*%s*)' "set foldtext=MmaFoldText() "function MmaFoldText() diff --git a/runtime/syntax/mysql.vim b/runtime/syntax/mysql.vim index 8bd7b6459a..49b53313c9 100644 --- a/runtime/syntax/mysql.vim +++ b/runtime/syntax/mysql.vim @@ -1,10 +1,13 @@ " Vim syntax file " Language: mysql " Maintainer: Kenneth J. Pronovici <pronovic@ieee.org> -" Last Change: $LastChangedDate: 2016-04-11 10:31:04 -0500 (Mon, 11 Apr 2016) $ " Filenames: *.mysql -" URL: ftp://cedar-solutions.com/software/mysql.vim -" Note: The definitions below are taken from the mysql user manual as of April 2002, for version 3.23 +" URL: ftp://cedar-solutions.com/software/mysql.vim (https://github.com/pronovic/vim-syntax/blob/master/mysql.vim) +" Note: The definitions below are taken from the mysql user manual as of April 2002, for version 3.23 and have been updated +" in July 2024 with the docs for version 8.4 +" Last Change: 2016 Apr 11 +" 2024-07-21: update MySQL functions as of MySQL 8.4 (by Vim Project) +" " quit when a syntax file was already loaded if exists("b:current_syntax") @@ -92,23 +95,23 @@ syn keyword mysqlType tinytext mediumtext longtext text syn keyword mysqlType tinyblob mediumblob longblob blob syn region mysqlType start="float\W" end="."me=s-1 syn region mysqlType start="float$" end="."me=s-1 -syn region mysqlType start="float(" end=")" contains=mysqlNumber,mysqlVariable +syn region mysqlType start="\<float(" end=")" contains=mysqlNumber,mysqlVariable syn region mysqlType start="double\W" end="."me=s-1 syn region mysqlType start="double$" end="."me=s-1 -syn region mysqlType start="double(" end=")" contains=mysqlNumber,mysqlVariable +syn region mysqlType start="\<double(" end=")" contains=mysqlNumber,mysqlVariable syn region mysqlType start="double precision\W" end="."me=s-1 syn region mysqlType start="double precision$" end="."me=s-1 syn region mysqlType start="double precision(" end=")" contains=mysqlNumber,mysqlVariable syn region mysqlType start="real\W" end="."me=s-1 syn region mysqlType start="real$" end="."me=s-1 -syn region mysqlType start="real(" end=")" contains=mysqlNumber,mysqlVariable -syn region mysqlType start="numeric(" end=")" contains=mysqlNumber,mysqlVariable +syn region mysqlType start="\<real(" end=")" contains=mysqlNumber,mysqlVariable +syn region mysqlType start="\<numeric(" end=")" contains=mysqlNumber,mysqlVariable syn region mysqlType start="dec\W" end="."me=s-1 syn region mysqlType start="dec$" end="."me=s-1 -syn region mysqlType start="dec(" end=")" contains=mysqlNumber,mysqlVariable +syn region mysqlType start="\<dec(" end=")" contains=mysqlNumber,mysqlVariable syn region mysqlType start="decimal\W" end="."me=s-1 syn region mysqlType start="decimal$" end="."me=s-1 -syn region mysqlType start="decimal(" end=")" contains=mysqlNumber,mysqlVariable +syn region mysqlType start="\<decimal(" end=")" contains=mysqlNumber,mysqlVariable syn region mysqlType start="\Wtimestamp\W" end="."me=s-1 syn region mysqlType start="\Wtimestamp$" end="."me=s-1 syn region mysqlType start="\Wtimestamp(" end=")" contains=mysqlNumber,mysqlVariable @@ -117,25 +120,42 @@ syn region mysqlType start="^timestamp$" end="."me=s-1 syn region mysqlType start="^timestamp(" end=")" contains=mysqlNumber,mysqlVariable syn region mysqlType start="\Wyear(" end=")" contains=mysqlNumber,mysqlVariable syn region mysqlType start="^year(" end=")" contains=mysqlNumber,mysqlVariable -syn region mysqlType start="char(" end=")" contains=mysqlNumber,mysqlVariable -syn region mysqlType start="varchar(" end=")" contains=mysqlNumber,mysqlVariable -syn region mysqlType start="enum(" end=")" contains=mysqlString,mysqlVariable +syn region mysqlType start="\<char(" end=")" contains=mysqlNumber,mysqlVariable +syn region mysqlType start="\<varchar(" end=")" contains=mysqlNumber,mysqlVariable +syn region mysqlType start="\<enum(" end=")" contains=mysqlString,mysqlVariable syn region mysqlType start="\Wset(" end=")" contains=mysqlString,mysqlVariable syn region mysqlType start="^set(" end=")" contains=mysqlString,mysqlVariable " Logical, string and numeric operators syn keyword mysqlOperator between not and or is in like regexp rlike binary exists -syn region mysqlOperator start="isnull(" end=")" contains=ALL -syn region mysqlOperator start="coalesce(" end=")" contains=ALL -syn region mysqlOperator start="interval(" end=")" contains=ALL +syn region mysqlOperatorFunction start="\<isnull(" end=")" contains=ALL +syn region mysqlOperatorFunction start="\<coalesce(" end=")" contains=ALL +syn region mysqlOperatorFunction start="\<interval(" end=")" contains=ALL -" Control flow functions -syn keyword mysqlFlow case when then else end -syn region mysqlFlow start="ifnull(" end=")" contains=ALL -syn region mysqlFlow start="nullif(" end=")" contains=ALL -syn region mysqlFlow start="if(" end=")" contains=ALL +" Flow control functions +" https://docs.oracle.com/cd/E17952_01/mysql-8.4-en/flow-control-functions.html +syn keyword mysqlFlowLabel case when then else end +syn region mysqlFlowFunction start="\<ifnull(" end=")" contains=ALL +syn region mysqlFlowFunction start="\<nullif(" end=")" contains=ALL +syn region mysqlFlowFunction start="\<if(" end=")" contains=ALL -" General Functions +" Window functions +" https://docs.oracle.com/cd/E17952_01/mysql-8.4-en/window-functions-usage.html +syn keyword mysqlWindowKeyword over partition window +" https://docs.oracle.com/cd/E17952_01/mysql-8.4-en/window-function-descriptions.html +syn region mysqlWindowFunction start="\<cume_dist(" end=")" contains=ALL +syn region mysqlWindowFunction start="\<dense_rank(" end=")" contains=ALL +syn region mysqlWindowFunction start="\<first_value(" end=")" contains=ALL +syn region mysqlWindowFunction start="\<lag(" end=")" contains=ALL +syn region mysqlWindowFunction start="\<last_value(" end=")" contains=ALL +syn region mysqlWindowFunction start="\<lead(" end=")" contains=ALL +syn region mysqlWindowFunction start="\<nth_value(" end=")" contains=ALL +syn region mysqlWindowFunction start="\<ntile(" end=")" contains=ALL +syn region mysqlWindowFunction start="\<percent_rank(" end=")" contains=ALL +syn region mysqlWindowFunction start="\<rank(" end=")" contains=ALL +syn region mysqlWindowFunction start="\<row_number(" end=")" contains=ALL + +" General functions " " I'm leery of just defining keywords for functions, since according to the MySQL manual: " @@ -147,140 +167,144 @@ syn region mysqlFlow start="if(" end=")" contains=ALL " region to define them, not just a keyword. This will probably cause the syntax file " to load more slowly, but at least it will be 'correct'. -syn region mysqlFunction start="abs(" end=")" contains=ALL -syn region mysqlFunction start="acos(" end=")" contains=ALL -syn region mysqlFunction start="adddate(" end=")" contains=ALL -syn region mysqlFunction start="ascii(" end=")" contains=ALL -syn region mysqlFunction start="asin(" end=")" contains=ALL -syn region mysqlFunction start="atan(" end=")" contains=ALL -syn region mysqlFunction start="atan2(" end=")" contains=ALL -syn region mysqlFunction start="avg(" end=")" contains=ALL -syn region mysqlFunction start="benchmark(" end=")" contains=ALL -syn region mysqlFunction start="bin(" end=")" contains=ALL -syn region mysqlFunction start="bit_and(" end=")" contains=ALL -syn region mysqlFunction start="bit_count(" end=")" contains=ALL -syn region mysqlFunction start="bit_or(" end=")" contains=ALL -syn region mysqlFunction start="ceiling(" end=")" contains=ALL -syn region mysqlFunction start="character_length(" end=")" contains=ALL -syn region mysqlFunction start="char_length(" end=")" contains=ALL -syn region mysqlFunction start="concat(" end=")" contains=ALL -syn region mysqlFunction start="concat_ws(" end=")" contains=ALL -syn region mysqlFunction start="connection_id(" end=")" contains=ALL -syn region mysqlFunction start="conv(" end=")" contains=ALL -syn region mysqlFunction start="cos(" end=")" contains=ALL -syn region mysqlFunction start="cot(" end=")" contains=ALL -syn region mysqlFunction start="count(" end=")" contains=ALL -syn region mysqlFunction start="curdate(" end=")" contains=ALL -syn region mysqlFunction start="curtime(" end=")" contains=ALL -syn region mysqlFunction start="date_add(" end=")" contains=ALL -syn region mysqlFunction start="date_format(" end=")" contains=ALL -syn region mysqlFunction start="date_sub(" end=")" contains=ALL -syn region mysqlFunction start="dayname(" end=")" contains=ALL -syn region mysqlFunction start="dayofmonth(" end=")" contains=ALL -syn region mysqlFunction start="dayofweek(" end=")" contains=ALL -syn region mysqlFunction start="dayofyear(" end=")" contains=ALL -syn region mysqlFunction start="decode(" end=")" contains=ALL -syn region mysqlFunction start="degrees(" end=")" contains=ALL -syn region mysqlFunction start="elt(" end=")" contains=ALL -syn region mysqlFunction start="encode(" end=")" contains=ALL -syn region mysqlFunction start="encrypt(" end=")" contains=ALL -syn region mysqlFunction start="exp(" end=")" contains=ALL -syn region mysqlFunction start="export_set(" end=")" contains=ALL -syn region mysqlFunction start="extract(" end=")" contains=ALL -syn region mysqlFunction start="field(" end=")" contains=ALL -syn region mysqlFunction start="find_in_set(" end=")" contains=ALL -syn region mysqlFunction start="floor(" end=")" contains=ALL -syn region mysqlFunction start="format(" end=")" contains=ALL -syn region mysqlFunction start="from_days(" end=")" contains=ALL -syn region mysqlFunction start="from_unixtime(" end=")" contains=ALL -syn region mysqlFunction start="get_lock(" end=")" contains=ALL -syn region mysqlFunction start="greatest(" end=")" contains=ALL -syn region mysqlFunction start="group_unique_users(" end=")" contains=ALL -syn region mysqlFunction start="hex(" end=")" contains=ALL -syn region mysqlFunction start="inet_aton(" end=")" contains=ALL -syn region mysqlFunction start="inet_ntoa(" end=")" contains=ALL -syn region mysqlFunction start="instr(" end=")" contains=ALL -syn region mysqlFunction start="lcase(" end=")" contains=ALL -syn region mysqlFunction start="least(" end=")" contains=ALL -syn region mysqlFunction start="length(" end=")" contains=ALL -syn region mysqlFunction start="load_file(" end=")" contains=ALL -syn region mysqlFunction start="locate(" end=")" contains=ALL -syn region mysqlFunction start="log(" end=")" contains=ALL -syn region mysqlFunction start="log10(" end=")" contains=ALL -syn region mysqlFunction start="lower(" end=")" contains=ALL -syn region mysqlFunction start="lpad(" end=")" contains=ALL -syn region mysqlFunction start="ltrim(" end=")" contains=ALL -syn region mysqlFunction start="make_set(" end=")" contains=ALL -syn region mysqlFunction start="master_pos_wait(" end=")" contains=ALL -syn region mysqlFunction start="max(" end=")" contains=ALL -syn region mysqlFunction start="md5(" end=")" contains=ALL -syn region mysqlFunction start="mid(" end=")" contains=ALL -syn region mysqlFunction start="min(" end=")" contains=ALL -syn region mysqlFunction start="mod(" end=")" contains=ALL -syn region mysqlFunction start="monthname(" end=")" contains=ALL -syn region mysqlFunction start="now(" end=")" contains=ALL -syn region mysqlFunction start="oct(" end=")" contains=ALL -syn region mysqlFunction start="octet_length(" end=")" contains=ALL -syn region mysqlFunction start="ord(" end=")" contains=ALL -syn region mysqlFunction start="period_add(" end=")" contains=ALL -syn region mysqlFunction start="period_diff(" end=")" contains=ALL -syn region mysqlFunction start="pi(" end=")" contains=ALL -syn region mysqlFunction start="position(" end=")" contains=ALL -syn region mysqlFunction start="pow(" end=")" contains=ALL -syn region mysqlFunction start="power(" end=")" contains=ALL -syn region mysqlFunction start="quarter(" end=")" contains=ALL -syn region mysqlFunction start="radians(" end=")" contains=ALL -syn region mysqlFunction start="rand(" end=")" contains=ALL -syn region mysqlFunction start="release_lock(" end=")" contains=ALL -syn region mysqlFunction start="repeat(" end=")" contains=ALL -syn region mysqlFunction start="reverse(" end=")" contains=ALL -syn region mysqlFunction start="round(" end=")" contains=ALL -syn region mysqlFunction start="rpad(" end=")" contains=ALL -syn region mysqlFunction start="rtrim(" end=")" contains=ALL -syn region mysqlFunction start="sec_to_time(" end=")" contains=ALL -syn region mysqlFunction start="session_user(" end=")" contains=ALL -syn region mysqlFunction start="sign(" end=")" contains=ALL -syn region mysqlFunction start="sin(" end=")" contains=ALL -syn region mysqlFunction start="soundex(" end=")" contains=ALL -syn region mysqlFunction start="space(" end=")" contains=ALL -syn region mysqlFunction start="sqrt(" end=")" contains=ALL -syn region mysqlFunction start="std(" end=")" contains=ALL -syn region mysqlFunction start="stddev(" end=")" contains=ALL -syn region mysqlFunction start="strcmp(" end=")" contains=ALL -syn region mysqlFunction start="subdate(" end=")" contains=ALL -syn region mysqlFunction start="substring(" end=")" contains=ALL -syn region mysqlFunction start="substring_index(" end=")" contains=ALL -syn region mysqlFunction start="subtime(" end=")" contains=ALL -syn region mysqlFunction start="sum(" end=")" contains=ALL -syn region mysqlFunction start="sysdate(" end=")" contains=ALL -syn region mysqlFunction start="system_user(" end=")" contains=ALL -syn region mysqlFunction start="tan(" end=")" contains=ALL -syn region mysqlFunction start="time_format(" end=")" contains=ALL -syn region mysqlFunction start="time_to_sec(" end=")" contains=ALL -syn region mysqlFunction start="to_days(" end=")" contains=ALL -syn region mysqlFunction start="trim(" end=")" contains=ALL -syn region mysqlFunction start="ucase(" end=")" contains=ALL -syn region mysqlFunction start="unique_users(" end=")" contains=ALL -syn region mysqlFunction start="unix_timestamp(" end=")" contains=ALL -syn region mysqlFunction start="upper(" end=")" contains=ALL -syn region mysqlFunction start="user(" end=")" contains=ALL -syn region mysqlFunction start="version(" end=")" contains=ALL -syn region mysqlFunction start="week(" end=")" contains=ALL -syn region mysqlFunction start="weekday(" end=")" contains=ALL -syn region mysqlFunction start="yearweek(" end=")" contains=ALL +syn region mysqlFunction start="\<abs(" end=")" contains=ALL +syn region mysqlFunction start="\<acos(" end=")" contains=ALL +syn region mysqlFunction start="\<adddate(" end=")" contains=ALL +syn region mysqlFunction start="\<ascii(" end=")" contains=ALL +syn region mysqlFunction start="\<asin(" end=")" contains=ALL +syn region mysqlFunction start="\<atan(" end=")" contains=ALL +syn region mysqlFunction start="\<atan2(" end=")" contains=ALL +syn region mysqlFunction start="\<avg(" end=")" contains=ALL +syn region mysqlFunction start="\<benchmark(" end=")" contains=ALL +syn region mysqlFunction start="\<bin(" end=")" contains=ALL +syn region mysqlFunction start="\<bit_and(" end=")" contains=ALL +syn region mysqlFunction start="\<bit_count(" end=")" contains=ALL +syn region mysqlFunction start="\<bit_or(" end=")" contains=ALL +syn region mysqlFunction start="\<ceiling(" end=")" contains=ALL +syn region mysqlFunction start="\<character_length(" end=")" contains=ALL +syn region mysqlFunction start="\<char_length(" end=")" contains=ALL +syn region mysqlFunction start="\<concat(" end=")" contains=ALL +syn region mysqlFunction start="\<concat_ws(" end=")" contains=ALL +syn region mysqlFunction start="\<connection_id(" end=")" contains=ALL +syn region mysqlFunction start="\<conv(" end=")" contains=ALL +syn region mysqlFunction start="\<cos(" end=")" contains=ALL +syn region mysqlFunction start="\<cot(" end=")" contains=ALL +syn region mysqlFunction start="\<count(" end=")" contains=ALL +syn region mysqlFunction start="\<curdate(" end=")" contains=ALL +syn region mysqlFunction start="\<curtime(" end=")" contains=ALL +syn region mysqlFunction start="\<date_add(" end=")" contains=ALL +syn region mysqlFunction start="\<date_format(" end=")" contains=ALL +syn region mysqlFunction start="\<date_sub(" end=")" contains=ALL +syn region mysqlFunction start="\<dayname(" end=")" contains=ALL +syn region mysqlFunction start="\<dayofmonth(" end=")" contains=ALL +syn region mysqlFunction start="\<dayofweek(" end=")" contains=ALL +syn region mysqlFunction start="\<dayofyear(" end=")" contains=ALL +syn region mysqlFunction start="\<decode(" end=")" contains=ALL +syn region mysqlFunction start="\<degrees(" end=")" contains=ALL +syn region mysqlFunction start="\<elt(" end=")" contains=ALL +syn region mysqlFunction start="\<encode(" end=")" contains=ALL +syn region mysqlFunction start="\<encrypt(" end=")" contains=ALL +syn region mysqlFunction start="\<exp(" end=")" contains=ALL +syn region mysqlFunction start="\<export_set(" end=")" contains=ALL +syn region mysqlFunction start="\<extract(" end=")" contains=ALL +syn region mysqlFunction start="\<field(" end=")" contains=ALL +syn region mysqlFunction start="\<find_in_set(" end=")" contains=ALL +syn region mysqlFunction start="\<floor(" end=")" contains=ALL +syn region mysqlFunction start="\<format(" end=")" contains=ALL +syn region mysqlFunction start="\<from_days(" end=")" contains=ALL +syn region mysqlFunction start="\<from_unixtime(" end=")" contains=ALL +syn region mysqlFunction start="\<get_lock(" end=")" contains=ALL +syn region mysqlFunction start="\<greatest(" end=")" contains=ALL +syn region mysqlFunction start="\<group_unique_users(" end=")" contains=ALL +syn region mysqlFunction start="\<hex(" end=")" contains=ALL +syn region mysqlFunction start="\<inet_aton(" end=")" contains=ALL +syn region mysqlFunction start="\<inet_ntoa(" end=")" contains=ALL +syn region mysqlFunction start="\<instr(" end=")" contains=ALL +syn region mysqlFunction start="\<lcase(" end=")" contains=ALL +syn region mysqlFunction start="\<least(" end=")" contains=ALL +syn region mysqlFunction start="\<length(" end=")" contains=ALL +syn region mysqlFunction start="\<load_file(" end=")" contains=ALL +syn region mysqlFunction start="\<locate(" end=")" contains=ALL +syn region mysqlFunction start="\<log(" end=")" contains=ALL +syn region mysqlFunction start="\<log10(" end=")" contains=ALL +syn region mysqlFunction start="\<lower(" end=")" contains=ALL +syn region mysqlFunction start="\<lpad(" end=")" contains=ALL +syn region mysqlFunction start="\<ltrim(" end=")" contains=ALL +syn region mysqlFunction start="\<make_set(" end=")" contains=ALL +syn region mysqlFunction start="\<master_pos_wait(" end=")" contains=ALL +syn region mysqlFunction start="\<max(" end=")" contains=ALL +syn region mysqlFunction start="\<md5(" end=")" contains=ALL +syn region mysqlFunction start="\<mid(" end=")" contains=ALL +syn region mysqlFunction start="\<min(" end=")" contains=ALL +syn region mysqlFunction start="\<mod(" end=")" contains=ALL +syn region mysqlFunction start="\<monthname(" end=")" contains=ALL +syn region mysqlFunction start="\<now(" end=")" contains=ALL +syn region mysqlFunction start="\<oct(" end=")" contains=ALL +syn region mysqlFunction start="\<octet_length(" end=")" contains=ALL +syn region mysqlFunction start="\<ord(" end=")" contains=ALL +syn region mysqlFunction start="\<period_add(" end=")" contains=ALL +syn region mysqlFunction start="\<period_diff(" end=")" contains=ALL +syn region mysqlFunction start="\<pi(" end=")" contains=ALL +syn region mysqlFunction start="\<position(" end=")" contains=ALL +syn region mysqlFunction start="\<pow(" end=")" contains=ALL +syn region mysqlFunction start="\<power(" end=")" contains=ALL +syn region mysqlFunction start="\<quarter(" end=")" contains=ALL +syn region mysqlFunction start="\<radians(" end=")" contains=ALL +syn region mysqlFunction start="\<rand(" end=")" contains=ALL +syn region mysqlFunction start="\<release_lock(" end=")" contains=ALL +syn region mysqlFunction start="\<repeat(" end=")" contains=ALL +syn region mysqlFunction start="\<reverse(" end=")" contains=ALL +syn region mysqlFunction start="\<round(" end=")" contains=ALL +syn region mysqlFunction start="\<rpad(" end=")" contains=ALL +syn region mysqlFunction start="\<rtrim(" end=")" contains=ALL +syn region mysqlFunction start="\<sec_to_time(" end=")" contains=ALL +syn region mysqlFunction start="\<session_user(" end=")" contains=ALL +syn region mysqlFunction start="\<sign(" end=")" contains=ALL +syn region mysqlFunction start="\<sin(" end=")" contains=ALL +syn region mysqlFunction start="\<soundex(" end=")" contains=ALL +syn region mysqlFunction start="\<space(" end=")" contains=ALL +syn region mysqlFunction start="\<sqrt(" end=")" contains=ALL +syn region mysqlFunction start="\<std(" end=")" contains=ALL +syn region mysqlFunction start="\<stddev(" end=")" contains=ALL +syn region mysqlFunction start="\<strcmp(" end=")" contains=ALL +syn region mysqlFunction start="\<subdate(" end=")" contains=ALL +syn region mysqlFunction start="\<substring(" end=")" contains=ALL +syn region mysqlFunction start="\<substring_index(" end=")" contains=ALL +syn region mysqlFunction start="\<subtime(" end=")" contains=ALL +syn region mysqlFunction start="\<sum(" end=")" contains=ALL +syn region mysqlFunction start="\<sysdate(" end=")" contains=ALL +syn region mysqlFunction start="\<system_user(" end=")" contains=ALL +syn region mysqlFunction start="\<tan(" end=")" contains=ALL +syn region mysqlFunction start="\<time_format(" end=")" contains=ALL +syn region mysqlFunction start="\<time_to_sec(" end=")" contains=ALL +syn region mysqlFunction start="\<to_days(" end=")" contains=ALL +syn region mysqlFunction start="\<trim(" end=")" contains=ALL +syn region mysqlFunction start="\<ucase(" end=")" contains=ALL +syn region mysqlFunction start="\<unique_users(" end=")" contains=ALL +syn region mysqlFunction start="\<unix_timestamp(" end=")" contains=ALL +syn region mysqlFunction start="\<upper(" end=")" contains=ALL +syn region mysqlFunction start="\<user(" end=")" contains=ALL +syn region mysqlFunction start="\<version(" end=")" contains=ALL +syn region mysqlFunction start="\<week(" end=")" contains=ALL +syn region mysqlFunction start="\<weekday(" end=")" contains=ALL +syn region mysqlFunction start="\<yearweek(" end=")" contains=ALL " Define the default highlighting. " Only when an item doesn't have highlighting yet -hi def link mysqlKeyword Statement +hi def link mysqlKeyword Keyword hi def link mysqlSpecial Special hi def link mysqlString String hi def link mysqlNumber Number hi def link mysqlVariable Identifier hi def link mysqlComment Comment hi def link mysqlType Type -hi def link mysqlOperator Statement -hi def link mysqlFlow Statement +hi def link mysqlOperator Operator +hi def link mysqlOperatorFunction Function +hi def link mysqlFlowFunction Function +hi def link mysqlFlowLabel Label +hi def link mysqlWindowFunction Function +hi def link mysqlWindowKeyword Keyword hi def link mysqlFunction Function diff --git a/runtime/syntax/ocaml.vim b/runtime/syntax/ocaml.vim index af3efd3dab..04ba39203d 100644 --- a/runtime/syntax/ocaml.vim +++ b/runtime/syntax/ocaml.vim @@ -6,6 +6,7 @@ " Issac Trotts <ijtrotts@ucdavis.edu> " URL: https://github.com/ocaml/vim-ocaml " Last Change: +" 2019 Nov 05 - Accurate type highlighting (Maëlan) " 2018 Nov 08 - Improved highlighting of operators (Maëlan) " 2018 Apr 22 - Improved support for PPX (Andrey Popp) " 2018 Mar 16 - Remove raise, lnot and not from keywords (Étienne Millon, "copy") @@ -38,25 +39,18 @@ syn case match " Access to the method of an object syn match ocamlMethod "#" -" Script headers highlighted like comments -syn match ocamlComment "^#!.*" contains=@Spell - " Scripting directives syn match ocamlScript "^#\<\(quit\|labels\|warnings\|warn_error\|directory\|remove_directory\|cd\|load\|load_rec\|use\|mod_use\|install_printer\|remove_printer\|require\|list\|ppx\|principal\|predicates\|rectypes\|thread\|trace\|untrace\|untrace_all\|print_depth\|print_length\|camlp4o\|camlp4r\|topfind_log\|topfind_verbose\)\>" " lowercase identifier - the standard way to match syn match ocamlLCIdentifier /\<\(\l\|_\)\(\w\|'\)*\>/ -syn match ocamlKeyChar "|" - " Errors syn match ocamlBraceErr "}" syn match ocamlBrackErr "\]" syn match ocamlParenErr ")" syn match ocamlArrErr "|]" -syn match ocamlCommentErr "\*)" - syn match ocamlCountErr "\<downto\>" syn match ocamlCountErr "\<to\>" @@ -75,19 +69,22 @@ else syn match ocamlEndErr "\<end\>" endif -" Some convenient clusters -syn cluster ocamlAllErrs contains=ocamlBraceErr,ocamlBrackErr,ocamlParenErr,ocamlCommentErr,ocamlCountErr,ocamlDoErr,ocamlDoneErr,ocamlEndErr,ocamlThenErr +" These keywords are only expected nested in constructions that are handled by +" the type linter, so outside of type contexts we highlight them as errors: +syn match ocamlKwErr "\<\(mutable\|nonrec\|of\|private\)\>" -syn cluster ocamlAENoParen contains=ocamlBraceErr,ocamlBrackErr,ocamlCommentErr,ocamlCountErr,ocamlDoErr,ocamlDoneErr,ocamlEndErr,ocamlThenErr +" Some convenient clusters +syn cluster ocamlAllErrs contains=@ocamlAENoParen,ocamlParenErr +syn cluster ocamlAENoParen contains=ocamlBraceErr,ocamlBrackErr,ocamlCountErr,ocamlDoErr,ocamlDoneErr,ocamlEndErr,ocamlThenErr,ocamlKwErr -syn cluster ocamlContained contains=ocamlTodo,ocamlPreDef,ocamlModParam,ocamlModParam1,ocamlMPRestr,ocamlMPRestr1,ocamlMPRestr2,ocamlMPRestr3,ocamlModRHS,ocamlFuncWith,ocamlFuncStruct,ocamlModTypeRestr,ocamlModTRWith,ocamlWith,ocamlWithRest,ocamlModType,ocamlFullMod,ocamlVal +syn cluster ocamlContained contains=ocamlTodo,ocamlPreDef,ocamlModParam,ocamlModParam1,ocamlModTypePre,ocamlModRHS,ocamlFuncWith,ocamlModTypeRestr,ocamlModTRWith,ocamlWith,ocamlWithRest,ocamlFullMod,ocamlVal " Enclosing delimiters -syn region ocamlEncl transparent matchgroup=ocamlKeyword start="(" matchgroup=ocamlKeyword end=")" contains=ALLBUT,@ocamlContained,ocamlParenErr -syn region ocamlEncl transparent matchgroup=ocamlKeyword start="{" matchgroup=ocamlKeyword end="}" contains=ALLBUT,@ocamlContained,ocamlBraceErr -syn region ocamlEncl transparent matchgroup=ocamlKeyword start="\[" matchgroup=ocamlKeyword end="\]" contains=ALLBUT,@ocamlContained,ocamlBrackErr -syn region ocamlEncl transparent matchgroup=ocamlKeyword start="\[|" matchgroup=ocamlKeyword end="|\]" contains=ALLBUT,@ocamlContained,ocamlArrErr +syn region ocamlNone transparent matchgroup=ocamlEncl start="(" matchgroup=ocamlEncl end=")" contains=ALLBUT,@ocamlContained,ocamlParenErr +syn region ocamlNone transparent matchgroup=ocamlEncl start="{" matchgroup=ocamlEncl end="}" contains=ALLBUT,@ocamlContained,ocamlBraceErr +syn region ocamlNone transparent matchgroup=ocamlEncl start="\[" matchgroup=ocamlEncl end="\]" contains=ALLBUT,@ocamlContained,ocamlBrackErr +syn region ocamlNone transparent matchgroup=ocamlEncl start="\[|" matchgroup=ocamlEncl end="|\]" contains=ALLBUT,@ocamlContained,ocamlArrErr " Comments @@ -124,10 +121,6 @@ syn region ocamlPpx matchgroup=ocamlPpxEncl start="\[@\{1,3\}" contains=TOP end= "" Modules -" "sig" -syn region ocamlSig matchgroup=ocamlSigEncl start="\<sig\>" matchgroup=ocamlSigEncl end="\<end\>" contains=ALLBUT,@ocamlContained,ocamlEndErr,ocamlModule -syn region ocamlModSpec matchgroup=ocamlKeyword start="\<module\>" matchgroup=ocamlModule end="\<\u\(\w\|'\)*\>" contained contains=@ocamlAllErrs,ocamlComment skipwhite skipempty nextgroup=ocamlModTRWith,ocamlMPRestr - " "open" syn match ocamlKeyword "\<open\>" skipwhite skipempty nextgroup=ocamlFullMod @@ -135,51 +128,66 @@ syn match ocamlKeyword "\<open\>" skipwhite skipempty nextgroup=ocamlFullMod syn match ocamlKeyword "\<include\>" skipwhite skipempty nextgroup=ocamlModParam,ocamlFullMod " "module" - somewhat complicated stuff ;-) -syn region ocamlModule matchgroup=ocamlKeyword start="\<module\>" matchgroup=ocamlModule end="\<\u\(\w\|'\)*\>" contains=@ocamlAllErrs,ocamlComment skipwhite skipempty nextgroup=ocamlPreDef -syn region ocamlPreDef start="."me=e-1 matchgroup=ocamlKeyword end="\l\|=\|)"me=e-1 contained contains=@ocamlAllErrs,ocamlComment,ocamlModParam,ocamlGenMod,ocamlModTypeRestr,ocamlModTRWith nextgroup=ocamlModPreRHS -syn region ocamlModParam start="([^*]" end=")" contained contains=ocamlGenMod,ocamlModParam1,ocamlSig,ocamlVal +" 2022-10: please document it? +syn region ocamlModule matchgroup=ocamlKeyword start="\<module\>" matchgroup=ocamlModule end="\<_\|\u\(\w\|'\)*\>" contains=@ocamlAllErrs,ocamlComment skipwhite skipempty nextgroup=ocamlPreDef +syn region ocamlPreDef start="."me=e-1 end="[a-z:=)]\@=" contained contains=@ocamlAllErrs,ocamlComment,ocamlModParam,ocamlGenMod,ocamlModTypeRestr nextgroup=ocamlModTypePre,ocamlModPreRHS +syn region ocamlModParam start="(\*\@!" end=")" contained contains=ocamlGenMod,ocamlModParam,ocamlModParam1,ocamlSig,ocamlVal syn match ocamlModParam1 "\<\u\(\w\|'\)*\>" contained skipwhite skipempty syn match ocamlGenMod "()" contained skipwhite skipempty -syn region ocamlMPRestr start=":" end="."me=e-1 contained contains=@ocamlComment skipwhite skipempty nextgroup=ocamlMPRestr1,ocamlMPRestr2,ocamlMPRestr3 -syn region ocamlMPRestr1 matchgroup=ocamlSigEncl start="\ssig\s\=" matchgroup=ocamlSigEncl end="\<end\>" contained contains=ALLBUT,@ocamlContained,ocamlEndErr,ocamlModule -syn region ocamlMPRestr2 start="\sfunctor\(\s\|(\)\="me=e-1 matchgroup=ocamlKeyword end="->" contained contains=@ocamlAllErrs,ocamlComment,ocamlModParam,ocamlGenMod skipwhite skipempty nextgroup=ocamlFuncWith,ocamlMPRestr2 -syn match ocamlMPRestr3 "\w\(\w\|'\)*\( *\. *\w\(\w\|'\)*\)*" contained +syn match ocamlModTypePre ":" contained skipwhite skipempty nextgroup=ocamlModTRWith,ocamlSig,ocamlFunctor,ocamlModTypeRestr,ocamlModTypeOf +syn match ocamlModTypeRestr "\<\w\(\w\|'\)*\( *\. *\w\(\w\|'\)*\)*\>" contained + syn match ocamlModPreRHS "=" contained skipwhite skipempty nextgroup=ocamlModParam,ocamlFullMod syn keyword ocamlKeyword val -syn region ocamlVal matchgroup=ocamlKeyword start="\<val\>" matchgroup=ocamlLCIdentifier end="\<\l\(\w\|'\)*\>" contains=@ocamlAllErrs,ocamlComment,ocamlFullMod skipwhite skipempty nextgroup=ocamlMPRestr +syn region ocamlVal matchgroup=ocamlKeyword start="\<val\>" matchgroup=ocamlLCIdentifier end="\<\l\(\w\|'\)*\>" contains=@ocamlAllErrs,ocamlComment,ocamlFullMod skipwhite skipempty nextgroup=ocamlModTypePre syn region ocamlModRHS start="." end=". *\w\|([^*]"me=e-2 contained contains=ocamlComment skipwhite skipempty nextgroup=ocamlModParam,ocamlFullMod syn match ocamlFullMod "\<\u\(\w\|'\)*\( *\. *\u\(\w\|'\)*\)*" contained skipwhite skipempty nextgroup=ocamlFuncWith -syn region ocamlFuncWith start="([^*)]"me=e-1 end=")" contained contains=ocamlComment,ocamlWith,ocamlFuncStruct skipwhite skipempty nextgroup=ocamlFuncWith -syn region ocamlFuncStruct matchgroup=ocamlStructEncl start="[^a-zA-Z]struct\>"hs=s+1 matchgroup=ocamlStructEncl end="\<end\>" contains=ALLBUT,@ocamlContained,ocamlEndErr +syn region ocamlFuncWith start="([*)]\@!" end=")" contained contains=ocamlComment,ocamlWith,ocamlStruct skipwhite skipempty nextgroup=ocamlFuncWith -syn match ocamlModTypeRestr "\<\w\(\w\|'\)*\( *\. *\w\(\w\|'\)*\)*\>" contained -syn region ocamlModTRWith start=":\s*("hs=s+1 end=")" contained contains=@ocamlAENoParen,ocamlWith +syn region ocamlModTRWith start="(\*\@!" end=")" contained contains=@ocamlAENoParen,ocamlWith syn match ocamlWith "\<\(\u\(\w\|'\)* *\. *\)*\w\(\w\|'\)*\>" contained skipwhite skipempty nextgroup=ocamlWithRest syn region ocamlWithRest start="[^)]" end=")"me=e-1 contained contains=ALLBUT,@ocamlContained " "struct" syn region ocamlStruct matchgroup=ocamlStructEncl start="\<\(module\s\+\)\=struct\>" matchgroup=ocamlStructEncl end="\<end\>" contains=ALLBUT,@ocamlContained,ocamlEndErr +" "sig" +syn region ocamlSig matchgroup=ocamlSigEncl start="\<sig\>" matchgroup=ocamlSigEncl end="\<end\>" contains=ALLBUT,@ocamlContained,ocamlEndErr + +" "functor" +syn region ocamlFunctor start="\<functor\>" matchgroup=ocamlKeyword end="->" contains=@ocamlAllErrs,ocamlComment,ocamlModParam,ocamlGenMod skipwhite skipempty nextgroup=ocamlStruct,ocamlSig,ocamlFuncWith,ocamlFunctor + " "module type" -syn region ocamlKeyword start="\<module\>\s*\<type\>\(\s*\<of\>\)\=" matchgroup=ocamlModule end="\<\w\(\w\|'\)*\>" contains=ocamlComment skipwhite skipempty nextgroup=ocamlMTDef +syn region ocamlModTypeOf start="\<module\s\+type\(\s\+of\)\=\>" matchgroup=ocamlModule end="\<\w\(\w\|'\)*\>" contains=ocamlComment skipwhite skipempty nextgroup=ocamlMTDef syn match ocamlMTDef "=\s*\w\(\w\|'\)*\>"hs=s+1,me=s+1 skipwhite skipempty nextgroup=ocamlFullMod " Quoted strings syn region ocamlString matchgroup=ocamlQuotedStringDelim start="{\z\([a-z_]*\)|" end="|\z1}" contains=@Spell +syn region ocamlString matchgroup=ocamlQuotedStringDelim start="{%[a-z_]\+\(\.[a-z_]\+\)\?\( \z\([a-z_]\+\)\)\?|" end="|\z1}" contains=@Spell syn keyword ocamlKeyword and as assert class -syn keyword ocamlKeyword constraint else -syn keyword ocamlKeyword exception external fun - +syn keyword ocamlKeyword else +syn keyword ocamlKeyword external syn keyword ocamlKeyword in inherit initializer syn keyword ocamlKeyword lazy let match -syn keyword ocamlKeyword method mutable new nonrec of -syn keyword ocamlKeyword parser private rec -syn keyword ocamlKeyword try type +syn keyword ocamlKeyword method new +syn keyword ocamlKeyword parser rec +syn keyword ocamlKeyword try syn keyword ocamlKeyword virtual when while with +" Keywords which are handled by the type linter: +" as (within a type equation) +" constraint exception mutable nonrec of private type + +" The `fun` keyword has special treatment because of the syntax `fun … : t -> e` +" where `->` ends the type context rather than being part of it; to handle that, +" we blacklist the ocamlTypeAnnot matchgroup, and we plug ocamlFunTypeAnnot +" instead (later in this file, by using containedin=ocamlFun): +syn region ocamlFun matchgroup=ocamlKeyword start='\<fun\>' matchgroup=ocamlArrow end='->' +\ contains=ALLBUT,@ocamlContained,ocamlArrow,ocamlInfixOp,ocamlTypeAnnot + if exists("ocaml_revised") syn keyword ocamlKeyword do value syn keyword ocamlBoolean True False @@ -188,14 +196,10 @@ else syn keyword ocamlBoolean true false endif -syn keyword ocamlType array bool char exn float format format4 -syn keyword ocamlType int int32 int64 lazy_t list nativeint option -syn keyword ocamlType bytes string unit - -syn match ocamlConstructor "(\s*)" -syn match ocamlConstructor "\[\s*\]" -syn match ocamlConstructor "\[|\s*>|]" -syn match ocamlConstructor "\[<\s*>\]" +syn match ocamlEmptyConstructor "(\s*)" +syn match ocamlEmptyConstructor "\[\s*\]" +syn match ocamlEmptyConstructor "\[|\s*>|]" +syn match ocamlEmptyConstructor "\[<\s*>\]" syn match ocamlConstructor "\u\(\w\|'\)*\>" " Polymorphic variants @@ -210,26 +214,24 @@ syn match ocamlCharErr "'\\\d\d'\|'\\\d'" syn match ocamlCharErr "'\\[^\'ntbr]'" syn region ocamlString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=@Spell -syn match ocamlTopStop ";;" - syn match ocamlAnyVar "\<_\>" -syn match ocamlKeyChar "|[^\]]"me=e-1 +syn match ocamlKeyChar "|]\@!" syn match ocamlKeyChar ";" syn match ocamlKeyChar "\~" syn match ocamlKeyChar "?" +" NOTE: for correct precedence, the rule for ";;" must come after that for ";" +syn match ocamlTopStop ";;" + "" Operators " The grammar of operators is found there: " https://caml.inria.fr/pub/docs/manual-ocaml/names.html#operator-name " https://caml.inria.fr/pub/docs/manual-ocaml/extn.html#s:ext-ops " https://caml.inria.fr/pub/docs/manual-ocaml/extn.html#s:index-operators -" =, *, < and > are both operator names and keywords, we let the user choose how -" to display them (has to be declared before regular infix operators): +" = is both an operator name and a keyword, we let the user choose how +" to display it (has to be declared before regular infix operators): syn match ocamlEqual "=" -syn match ocamlStar "*" -syn match ocamlAngle "<" -syn match ocamlAngle ">" " Custom indexing operators: syn region ocamlIndexing matchgroup=ocamlIndexingOp \ start="\.[~?!:|&$%=>@^/*+-][~?!.:|&$%<=>@^*/+-]*\_s*(" @@ -248,8 +250,8 @@ syn match ocamlExtensionOp "#[#~?!.:|&$%<=>@^*/+-]\+" " Infix and prefix operators: syn match ocamlPrefixOp "![~?!.:|&$%<=>@^*/+-]*" syn match ocamlPrefixOp "[~?][~?!.:|&$%<=>@^*/+-]\+" -syn match ocamlInfixOp "[&$%@^/+-][~?!.:|&$%<=>@^*/+-]*" -syn match ocamlInfixOp "[|<=>*][~?!.:|&$%<=>@^*/+-]\+" +syn match ocamlInfixOp "[&$%<>@^*/+-][~?!.:|&$%<=>@^*/+-]*" +syn match ocamlInfixOp "[|=][~?!.:|&$%<=>@^*/+-]\+" syn match ocamlInfixOp "#[~?!.:|&$%<=>@^*/+-]\+#\@!" syn match ocamlInfixOp "!=[~?!.:|&$%<=>@^*/+-]\@!" syn keyword ocamlInfixOpKeyword asr land lor lsl lsr lxor mod or @@ -266,6 +268,9 @@ else syn match ocamlKeyChar "<-[~?!.:|&$%<=>@^*/+-]\@!" endif +" Script shebang (has to be declared after operators) +syn match ocamlShebang "\%1l^#!.*$" + syn match ocamlNumber "-\=\<\d\(_\|\d\)*[l|L|n]\?\>" syn match ocamlNumber "-\=\<0[x|X]\(\x\|_\)\+[l|L|n]\?\>" syn match ocamlNumber "-\=\<0[o|O]\(\o\|_\)\+[l|L|n]\?\>" @@ -273,10 +278,264 @@ syn match ocamlNumber "-\=\<0[b|B]\([01]\|_\)\+[l|L|n]\?\>" syn match ocamlFloat "-\=\<\d\(_\|\d\)*\.\?\(_\|\d\)*\([eE][-+]\=\d\(_\|\d\)*\)\=\>" " Labels -syn match ocamlLabel "\~\(\l\|_\)\(\w\|'\)*"lc=1 -syn match ocamlLabel "?\(\l\|_\)\(\w\|'\)*"lc=1 +syn match ocamlLabel "[~?]\(\l\|_\)\(\w\|'\)*:\?" syn region ocamlLabel transparent matchgroup=ocamlLabel start="[~?](\(\l\|_\)\(\w\|'\)*"lc=2 end=")"me=e-1 contains=ALLBUT,@ocamlContained,ocamlParenErr +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +"" Type contexts + +" How we recognize type contexts is explained in `type-linter-notes.md` +" and a test suite is found in `type-linter-test.ml`. +" +" ocamlTypeExpr is the cluster of things that can make up a type expression +" (in a loose sense, e.g. the “as†keyword and universal quantification are +" included). Regions containing a type expression use it like this: +" +" contains=@ocamlTypeExpr,... +" +" ocamlTypeContained is the cluster of things that can be found in a type +" expression or a type definition. It is not expected to be used in any region, +" it exists solely for throwing things in it that should not pollute the main +" linter. +" +" Both clusters are filled in incrementally. Every match group that is not to be +" found at the main level must be declared as “contained†and added to either +" ocamlTypeExpr or ocamlTypeContained. +" +" In these clusters we don’t put generic things that can also be found elswhere, +" i.e. ocamlComment and ocamlPpx, because everything that is in these clusters +" is also put in ocamlContained and thus ignored by the main linter. + +"syn cluster ocamlTypeExpr contains= +syn cluster ocamlTypeContained contains=@ocamlTypeExpr +syn cluster ocamlContained add=@ocamlTypeContained + +" We’ll use a “catch-all†highlighting group to show as error anything that is +" not matched more specifically; we don’t want spaces to be reported as errors +" (different background color), so we just catch them here: +syn cluster ocamlTypeExpr add=ocamlTypeBlank +syn match ocamlTypeBlank contained "\_s\+" +hi link ocamlTypeBlank NONE + +" NOTE: Carefully avoid catching "(*" here. +syn cluster ocamlTypeExpr add=ocamlTypeParen +syn region ocamlTypeParen contained transparent +\ matchgroup=ocamlEncl start="(\*\@!" +\ matchgroup=ocamlEncl end=")" +\ contains=@ocamlTypeExpr,ocamlComment,ocamlPpx + +syn cluster ocamlTypeExpr add=ocamlTypeKeyChar,ocamlTypeAs +syn match ocamlTypeKeyChar contained "->" +syn match ocamlTypeKeyChar contained "\*" +syn match ocamlTypeKeyChar contained "#" +syn match ocamlTypeKeyChar contained "," +syn match ocamlTypeKeyChar contained "\." +syn keyword ocamlTypeAs contained as +hi link ocamlTypeAs ocamlKeyword + +syn cluster ocamlTypeExpr add=ocamlTypeVariance +syn match ocamlTypeVariance contained "[-+!]\ze *\('\|\<_\>\)" +syn match ocamlTypeVariance contained "[-+] *!\+\ze *\('\|\<_\>\)" +syn match ocamlTypeVariance contained "! *[-+]\+\ze *\('\|\<_\>\)" + +syn cluster ocamlTypeContained add=ocamlTypeEq +syn match ocamlTypeEq contained "[+:]\?=" +hi link ocamlTypeEq ocamlKeyChar + +syn cluster ocamlTypeExpr add=ocamlTypeVar,ocamlTypeConstr,ocamlTypeAnyVar,ocamlTypeBuiltin +syn match ocamlTypeVar contained "'\(\l\|_\)\(\w\|'\)*\>" +syn match ocamlTypeConstr contained "\<\(\l\|_\)\(\w\|'\)*\>" +" NOTE: for correct precedence, the rule for the wildcard (ocamlTypeAnyVar) +" must come after the rule for type constructors (ocamlTypeConstr). +syn match ocamlTypeAnyVar contained "\<_\>" +" NOTE: For correct precedence, these builtin names must occur after the rule +" for type constructors (ocamlTypeConstr) but before the rule for non-optional +" labeled arguments (ocamlTypeLabel). For the latter to take precedence over +" these builtin names, we use “syn match†here instead of “syn keywordâ€. +syn match ocamlTypeBuiltin contained "\<array\>" +syn match ocamlTypeBuiltin contained "\<bool\>" +syn match ocamlTypeBuiltin contained "\<bytes\>" +syn match ocamlTypeBuiltin contained "\<char\>" +syn match ocamlTypeBuiltin contained "\<exn\>" +syn match ocamlTypeBuiltin contained "\<float\>" +syn match ocamlTypeBuiltin contained "\<format\>" +syn match ocamlTypeBuiltin contained "\<format4\>" +syn match ocamlTypeBuiltin contained "\<format6\>" +syn match ocamlTypeBuiltin contained "\<in_channel\>" +syn match ocamlTypeBuiltin contained "\<int\>" +syn match ocamlTypeBuiltin contained "\<int32\>" +syn match ocamlTypeBuiltin contained "\<int64\>" +syn match ocamlTypeBuiltin contained "\<lazy_t\>" +syn match ocamlTypeBuiltin contained "\<list\>" +syn match ocamlTypeBuiltin contained "\<nativeint\>" +syn match ocamlTypeBuiltin contained "\<option\>" +syn match ocamlTypeBuiltin contained "\<out_channel\>" +syn match ocamlTypeBuiltin contained "\<ref\>" +syn match ocamlTypeBuiltin contained "\<result\>" +syn match ocamlTypeBuiltin contained "\<scanner\>" +syn match ocamlTypeBuiltin contained "\<string\>" +syn match ocamlTypeBuiltin contained "\<unit\>" + +syn cluster ocamlTypeExpr add=ocamlTypeLabel +syn match ocamlTypeLabel contained "?\?\(\l\|_\)\(\w\|'\)*\_s*:[>=]\@!" +hi link ocamlTypeLabel ocamlLabel + +" Object type +syn cluster ocamlTypeExpr add=ocamlTypeObject +syn region ocamlTypeObject contained +\ matchgroup=ocamlEncl start="<" +\ matchgroup=ocamlEncl end=">" +\ contains=ocamlTypeObjectDots,ocamlLCIdentifier,ocamlTypeObjectAnnot,ocamlTypeBlank,ocamlComment,ocamlPpx +hi link ocamlTypeObject ocamlTypeCatchAll +syn cluster ocamlTypeContained add=ocamlTypeObjectDots +syn match ocamlTypeObjectDots contained "\.\." +hi link ocamlTypeObjectDots ocamlKeyChar +syn cluster ocamlTypeContained add=ocamlTypeObjectAnnot +syn region ocamlTypeObjectAnnot contained +\ matchgroup=ocamlKeyChar start=":" +\ matchgroup=ocamlKeyChar end=";\|>\@=" +\ contains=@ocamlTypeExpr,ocamlComment,ocamlPpx +hi link ocamlTypeObjectAnnot ocamlTypeCatchAll + +" Record type definition +syn cluster ocamlTypeContained add=ocamlTypeRecordDecl +syn region ocamlTypeRecordDecl contained +\ matchgroup=ocamlEncl start="{" +\ matchgroup=ocamlEncl end="}" +\ contains=ocamlTypeMutable,ocamlLCIdentifier,ocamlTypeRecordAnnot,ocamlTypeBlank,ocamlComment,ocamlPpx +hi link ocamlTypeRecordDecl ocamlTypeCatchAll +syn cluster ocamlTypeContained add=ocamlTypeMutable +syn keyword ocamlTypeMutable contained mutable +hi link ocamlTypeMutable ocamlKeyword +syn cluster ocamlTypeContained add=ocamlTypeRecordAnnot +syn region ocamlTypeRecordAnnot contained +\ matchgroup=ocamlKeyChar start=":" +\ matchgroup=ocamlKeyChar end=";\|}\@=" +\ contains=@ocamlTypeExpr,ocamlComment,ocamlPpx +hi link ocamlTypeRecordAnnot ocamlTypeCatchAll + +" Polymorphic variant types +" NOTE: Carefully avoid catching "[@" here. +syn cluster ocamlTypeExpr add=ocamlTypeVariant +syn region ocamlTypeVariant contained +\ matchgroup=ocamlEncl start="\[>" start="\[<" start="\[@\@!" +\ matchgroup=ocamlEncl end="\]" +\ contains=ocamlTypeVariantKeyChar,ocamlTypeVariantConstr,ocamlTypeVariantAnnot,ocamlTypeBlank,ocamlComment,ocamlPpx +hi link ocamlTypeVariant ocamlTypeCatchAll +syn cluster ocamlTypeContained add=ocamlTypeVariantKeyChar +syn match ocamlTypeVariantKeyChar contained "|" +syn match ocamlTypeVariantKeyChar contained ">" +hi link ocamlTypeVariantKeyChar ocamlKeyChar +syn cluster ocamlTypeContained add=ocamlTypeVariantConstr +syn match ocamlTypeVariantConstr contained "`\w\(\w\|'\)*\>" +hi link ocamlTypeVariantConstr ocamlConstructor +syn cluster ocamlTypeContained add=ocamlTypeVariantAnnot +syn region ocamlTypeVariantAnnot contained +\ matchgroup=ocamlKeyword start="\<of\>" +\ matchgroup=ocamlKeyChar end="|\|>\|\]\@=" +\ contains=@ocamlTypeExpr,ocamlTypeAmp,ocamlComment,ocamlPpx +hi link ocamlTypeVariantAnnot ocamlTypeCatchAll +syn cluster ocamlTypeContained add=ocamlTypeAmp +syn match ocamlTypeAmp contained "&" +hi link ocamlTypeAmp ocamlTypeKeyChar + +" Sum type definition +syn cluster ocamlTypeContained add=ocamlTypeSumDecl +syn region ocamlTypeSumDecl contained +\ matchgroup=ocamlTypeSumBar start="|" +\ matchgroup=ocamlTypeSumConstr start="\<\u\(\w\|'\)*\>" +\ matchgroup=ocamlTypeSumConstr start="\<false\>" start="\<true\>" +\ matchgroup=ocamlTypeSumConstr start="(\_s*)" start="\[\_s*]" start="(\_s*::\_s*)" +\ matchgroup=NONE end="\(\<type\>\|\<exception\>\|\<val\>\|\<module\>\|\<class\>\|\<method\>\|\<constraint\>\|\<inherit\>\|\<object\>\|\<struct\>\|\<open\>\|\<include\>\|\<let\>\|\<external\>\|\<in\>\|\<end\>\|)\|]\|}\|;\|;;\|=\)\@=" +\ matchgroup=NONE end="\(\<and\>\)\@=" +\ contains=ocamlTypeSumBar,ocamlTypeSumConstr,ocamlTypeSumAnnot,ocamlTypeBlank,ocamlComment,ocamlPpx +hi link ocamlTypeSumDecl ocamlTypeCatchAll +syn cluster ocamlTypeContained add=ocamlTypeSumBar +syn match ocamlTypeSumBar contained "|" +hi link ocamlTypeSumBar ocamlKeyChar +syn cluster ocamlTypeContained add=ocamlTypeSumConstr +syn match ocamlTypeSumConstr contained "\<\u\(\w\|'\)*\>" +syn match ocamlTypeSumConstr contained "\<false\>" +syn match ocamlTypeSumConstr contained "\<true\>" +syn match ocamlTypeSumConstr contained "(\_s*)" +syn match ocamlTypeSumConstr contained "\[\_s*]" +syn match ocamlTypeSumConstr contained "(\_s*::\_s*)" +hi link ocamlTypeSumConstr ocamlConstructor +syn cluster ocamlTypeContained add=ocamlTypeSumAnnot +syn region ocamlTypeSumAnnot contained +\ matchgroup=ocamlKeyword start="\<of\>" +\ matchgroup=ocamlKeyChar start=":" +\ matchgroup=NONE end="|\@=" +\ matchgroup=NONE end="\(\<type\>\|\<exception\>\|\<val\>\|\<module\>\|\<class\>\|\<method\>\|\<constraint\>\|\<inherit\>\|\<object\>\|\<struct\>\|\<open\>\|\<include\>\|\<let\>\|\<external\>\|\<in\>\|\<end\>\|)\|]\|}\|;\|;;\)\@=" +\ matchgroup=NONE end="\(\<and\>\)\@=" +\ contains=@ocamlTypeExpr,ocamlTypeRecordDecl,ocamlComment,ocamlPpx +hi link ocamlTypeSumAnnot ocamlTypeCatchAll + +" Type context opened by “type†(type definition), “constraint†(type +" constraint) and “exception†(exception definition) +syn region ocamlTypeDef +\ matchgroup=ocamlKeyword start="\<type\>\(\_s\+\<nonrec\>\)\?\|\<constraint\>\|\<exception\>" +\ matchgroup=NONE end="\(\<type\>\|\<exception\>\|\<val\>\|\<module\>\|\<class\>\|\<method\>\|\<constraint\>\|\<inherit\>\|\<object\>\|\<struct\>\|\<open\>\|\<include\>\|\<let\>\|\<external\>\|\<in\>\|\<end\>\|)\|]\|}\|;\|;;\)\@=" +\ contains=@ocamlTypeExpr,ocamlTypeEq,ocamlTypePrivate,ocamlTypeDefDots,ocamlTypeRecordDecl,ocamlTypeSumDecl,ocamlTypeDefAnd,ocamlComment,ocamlPpx +hi link ocamlTypeDef ocamlTypeCatchAll +syn cluster ocamlTypeContained add=ocamlTypePrivate +syn keyword ocamlTypePrivate contained private +hi link ocamlTypePrivate ocamlKeyword +syn cluster ocamlTypeContained add=ocamlTypeDefAnd +syn keyword ocamlTypeDefAnd contained and +hi link ocamlTypeDefAnd ocamlKeyword +syn cluster ocamlTypeContained add=ocamlTypeDefDots +syn match ocamlTypeDefDots contained "\.\." +hi link ocamlTypeDefDots ocamlKeyChar + +" When "exception" is preceded by "with", "|" or "(", that’s not an exception +" definition but an exception pattern; we simply highlight the keyword without +" starting a type context. +" NOTE: These rules must occur after that for "exception". +syn match ocamlKeyword "\<with\_s\+exception\>"lc=4 +syn match ocamlKeyword "|\_s*exception\>"lc=1 +syn match ocamlKeyword "(\_s*exception\>"lc=1 + +" Type context opened by “:†(countless kinds of type annotations) and “:>†+" (type coercions) +syn region ocamlTypeAnnot matchgroup=ocamlKeyChar start=":\(>\|\_s*type\>\|[>:=]\@!\)" +\ matchgroup=NONE end="\(\<type\>\|\<exception\>\|\<val\>\|\<module\>\|\<class\>\|\<method\>\|\<constraint\>\|\<inherit\>\|\<object\>\|\<struct\>\|\<open\>\|\<include\>\|\<let\>\|\<external\>\|\<in\>\|\<end\>\|)\|]\|}\|;\|;;\)\@=" +\ matchgroup=NONE end="\(;\|}\)\@=" +\ matchgroup=NONE end="\(=\|:>\)\@=" +\ contains=@ocamlTypeExpr,ocamlComment,ocamlPpx +hi link ocamlTypeAnnot ocamlTypeCatchAll + +" Type annotation that gives the return type of a `fun` keyword +" (the type context is ended by `->`) +syn cluster ocamlTypeContained add=ocamlFunTypeAnnot +syn region ocamlFunTypeAnnot contained containedin=ocamlFun +\ matchgroup=ocamlKeyChar start=":" +\ matchgroup=NONE end="\(->\)\@=" +\ contains=@ocamlTypeExpr,ocamlComment,ocamlPpx +hi link ocamlFunTypeAnnot ocamlTypeCatchAll + +" Module paths (including functors) in types. +" NOTE: This rule must occur after the rule for ocamlTypeSumDecl as it must take +" precedence over it (otherwise the module name would be mistakenly highlighted +" as a constructor). +" NOTE: Carefully avoid catching "(*" here. +syn cluster ocamlTypeExpr add=ocamlTypeModPath +syn match ocamlTypeModPath contained "\<\u\(\w\|'\)*\_s*\." +syn region ocamlTypeModPath contained transparent +\ matchgroup=ocamlModPath start="\<\u\(\w\|'\)*\_s*(\*\@!" +\ matchgroup=ocamlModPath end=")\_s*\." +\ contains=ocamlTypeDotlessModPath,ocamlTypeBlank,ocamlComment,ocamlPpx +hi link ocamlTypeModPath ocamlModPath +syn cluster ocamlTypeContained add=ocamlTypeDotlessModPath +syn match ocamlTypeDotlessModPath contained "\<\u\(\w\|'\)*\_s*\.\?" +syn region ocamlTypeDotlessModPath contained transparent +\ matchgroup=ocamlModPath start="\<\u\(\w\|'\)*\_s*(\*\@!" +\ matchgroup=ocamlModPath end=")\_s*\.\?" +\ contains=ocamlTypeDotlessModPath,ocamlTypeBlank,ocamlComment,ocamlPpx +hi link ocamlTypeDotlessModPath ocamlTypeModPath + +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" " Synchronization syn sync minlines=50 @@ -306,27 +565,25 @@ hi def link ocamlBrackErr Error hi def link ocamlParenErr Error hi def link ocamlArrErr Error -hi def link ocamlCommentErr Error - hi def link ocamlCountErr Error hi def link ocamlDoErr Error hi def link ocamlDoneErr Error hi def link ocamlEndErr Error hi def link ocamlThenErr Error +hi def link ocamlKwErr Error hi def link ocamlCharErr Error hi def link ocamlErr Error hi def link ocamlComment Comment +hi def link ocamlShebang ocamlComment hi def link ocamlModPath Include hi def link ocamlObject Include hi def link ocamlModule Include hi def link ocamlModParam1 Include hi def link ocamlGenMod Include -hi def link ocamlModType Include -hi def link ocamlMPRestr3 Include hi def link ocamlFullMod Include hi def link ocamlFuncWith Include hi def link ocamlModParam Include @@ -339,10 +596,13 @@ hi def link ocamlStructEncl ocamlModule hi def link ocamlScript Include hi def link ocamlConstructor Constant +hi def link ocamlEmptyConstructor ocamlConstructor hi def link ocamlVal Keyword +hi def link ocamlModTypePre Keyword hi def link ocamlModPreRHS Keyword -hi def link ocamlMPRestr2 Keyword +hi def link ocamlFunctor Keyword +hi def link ocamlModTypeOf Keyword hi def link ocamlKeyword Keyword hi def link ocamlMethod Include hi def link ocamlArrow Keyword @@ -352,8 +612,6 @@ hi def link ocamlTopStop Keyword hi def link ocamlRefAssign ocamlKeyChar hi def link ocamlEqual ocamlKeyChar -hi def link ocamlStar ocamlInfixOp -hi def link ocamlAngle ocamlInfixOp hi def link ocamlCons ocamlInfixOp hi def link ocamlPrefixOp ocamlOperator @@ -377,7 +635,24 @@ hi def link ocamlQuotedStringDelim Identifier hi def link ocamlLabel Identifier -hi def link ocamlType Type +" Type linting groups that the user can customize: +" - ocamlTypeCatchAll: anything in a type context that is not caught by more +" specific rules (in principle, this should only match syntax errors) +" - ocamlTypeConstr: type constructors +" - ocamlTypeBuiltin: builtin type constructors (like int or list) +" - ocamlTypeVar: type variables ('a) +" - ocamlTypeAnyVar: wildcard (_) +" - ocamlTypeVariance: variance and injectivity indications (+'a, !'a) +" - ocamlTypeKeyChar: symbols such as -> and * +" Default values below mimick the behavior before the type linter was +" implemented, but now we can do better. :-) +hi def link ocamlTypeCatchAll Error +hi def link ocamlTypeConstr NONE +hi def link ocamlTypeBuiltin Type +hi def link ocamlTypeVar NONE +hi def link ocamlTypeAnyVar NONE +hi def link ocamlTypeVariance ocamlKeyChar +hi def link ocamlTypeKeyChar ocamlKeyChar hi def link ocamlTodo Todo diff --git a/runtime/syntax/opam.vim b/runtime/syntax/opam.vim index 9ac1d41ce7..da296627e5 100644 --- a/runtime/syntax/opam.vim +++ b/runtime/syntax/opam.vim @@ -1,5 +1,5 @@ " Vim syntax file -" Language: OPAM - OCaml package manager +" Language: opam - OCaml package manager " Maintainer: Markus Mottl <markus.mottl@gmail.com> " URL: https://github.com/ocaml/vim-ocaml " Last Change: @@ -11,20 +11,55 @@ endif " need %{vars}% " env: [[CAML_LD_LIBRARY_PATH = "%{lib}%/stublibs"]] -syn keyword opamKeyword1 remove depends pin-depends depopts conflicts env packages patches version maintainer tags license homepage authors doc install author available name depexts substs synopsis description -syn match opamKeyword2 "\v(bug-reports|post-messages|ocaml-version|opam-version|dev-repo|build-test|build-doc|build)" +syn iskeyword a-z,A-Z,- +syn keyword opamKeyword1 author +syn keyword opamKeyword1 authors +syn keyword opamKeyword1 available +syn keyword opamKeyword1 bug-reports +syn keyword opamKeyword1 build +syn keyword opamKeyword1 build-env +syn keyword opamKeyword1 conflict-class +syn keyword opamKeyword1 conflicts +syn keyword opamKeyword1 depends +syn keyword opamKeyword1 depexts +syn keyword opamKeyword1 depopts +syn keyword opamKeyword1 description +syn keyword opamKeyword1 dev-repo +syn keyword opamKeyword1 doc +syn keyword opamKeyword1 extra-files +syn keyword opamKeyword1 features +syn keyword opamKeyword1 flags +syn keyword opamKeyword1 homepage +syn keyword opamKeyword1 install +syn keyword opamKeyword1 libraries +syn keyword opamKeyword1 license +syn keyword opamKeyword1 maintainer +syn keyword opamKeyword1 messages +syn keyword opamKeyword1 name +syn keyword opamKeyword1 opam-version +syn keyword opamKeyword1 patches +syn keyword opamKeyword1 pin-depends +syn keyword opamKeyword1 post-messages +syn keyword opamKeyword1 remove +syn keyword opamKeyword1 run-test +syn keyword opamKeyword1 setenv +syn keyword opamKeyword1 substs +syn keyword opamKeyword1 synopsis +syn keyword opamKeyword1 syntax +syn keyword opamKeyword1 tags +syn keyword opamKeyword1 version syn keyword opamTodo FIXME NOTE NOTES TODO XXX contained syn match opamComment "#.*$" contains=opamTodo,@Spell syn match opamOperator ">\|<\|=\|<=\|>=" -syn region opamInterpolate start=/%{/ end=/}%/ contained -syn region opamString start=/"/ end=/"/ contains=opamInterpolate -syn region opamSeq start=/\[/ end=/\]/ contains=ALLBUT,opamKeyword1,opamKeyword2 -syn region opamExp start=/{/ end=/}/ contains=ALLBUT,opamKeyword1,opamKeyword2 +syn match opamUnclosedInterpolate "%{[^ "]*" contained +syn match opamInterpolate "%{[^ "]\+}%" contained +syn region opamString start=/"/ end=/"/ contains=opamInterpolate,OpamUnclosedInterpolate +syn region opamSeq start=/\[/ end=/\]/ contains=ALLBUT,opamKeyword1 +syn region opamExp start=/{/ end=/}/ contains=ALLBUT,opamKeyword1 hi link opamKeyword1 Keyword -hi link opamKeyword2 Keyword hi link opamString String hi link opamExp Function @@ -32,6 +67,7 @@ hi link opamSeq Statement hi link opamOperator Operator hi link opamComment Comment hi link opamInterpolate Identifier +hi link opamUnclosedInterpolate Error let b:current_syntax = "opam" diff --git a/runtime/syntax/progress.vim b/runtime/syntax/progress.vim index 5e7cfef299..4b8f61287c 100644 --- a/runtime/syntax/progress.vim +++ b/runtime/syntax/progress.vim @@ -3,13 +3,13 @@ " Filename extensions: *.p (collides with Pascal), " *.i (collides with assembler) " *.w (collides with cweb) -" Maintainer: Philip Uren <philuSPAXY@ieee.org> Remove SPAXY spam block +" Maintainer: Daniel Smith <daniel@rdnlsmith.com> +" Previous Maintainer: Philip Uren <philuSPAXY@ieee.org> Remove SPAXY spam block " Contributors: Matthew Stickney <mtstickneySPAXY@gmail.com> " Chris Ruprecht <chrisSPAXY@ruprecht.org> " Mikhail Kuperblum <mikhailSPAXY@whasup.com> " John Florian <jflorianSPAXY@voyager.net> -" Version: 13 -" Last Change: Nov 11 2012 +" Last Change: Jul 23 2024 " quit when a syntax file was already loaded if exists("b:current_syntax") @@ -116,8 +116,10 @@ syn match ProgressShowTab "\t" " If you don't like white space on the end of lines, uncomment this: " syn match ProgressSpaceError "\s\+$" -syn region ProgressComment start="/\*" end="\*/" contains=ProgressComment,ProgressTodo,ProgressDebug,@Spell -syn region ProgressInclude start="^[ ]*[{]" end="[}]" contains=ProgressPreProc,ProgressOperator,ProgressString,ProgressComment +syn region ProgressBlockComment start="/\*" end="\*/" contains=ProgressBlockComment,ProgressTodo,ProgressDebug,@Spell +syn match ProgressLineComment "//.*$" contains=ProgressTodo,ProgressDebug,@Spell +syn cluster ProgressComment contains=ProgressBlockComment,ProgressLineComment +syn region ProgressInclude start="^[ ]*[{]" end="[}]" contains=ProgressPreProc,ProgressOperator,ProgressString,@ProgressComment syn region ProgressPreProc start="&" end="\>" contained " This next line works reasonably well. @@ -281,6 +283,8 @@ syn sync lines=800 hi def link ProgressByte Number hi def link ProgressCase Repeat hi def link ProgressComment Comment +hi def link ProgressBlockComment ProgressComment +hi def link ProgressLineComment ProgressComment hi def link ProgressConditional Conditional hi def link ProgressDebug Debug hi def link ProgressDo Repeat diff --git a/runtime/syntax/query.lua b/runtime/syntax/query.lua index 1e129dbeff..2dfe29f69b 100644 --- a/runtime/syntax/query.lua +++ b/runtime/syntax/query.lua @@ -1,6 +1,6 @@ -- Neovim syntax file -- Language: Treesitter query --- Last Change: 2022 Apr 13 +-- Last Change: 2024 Jul 03 -- it's a lisp! -vim.cmd([[ runtime! syntax/lisp.vim ]]) +vim.cmd([[runtime! syntax/lisp.vim]]) diff --git a/runtime/syntax/rasi.vim b/runtime/syntax/rasi.vim new file mode 100644 index 0000000000..40c3393fc5 --- /dev/null +++ b/runtime/syntax/rasi.vim @@ -0,0 +1,298 @@ +" Vim syntax file +" Language: rasi (Rofi Advanced Style Information) +" Maintainer: Pierrick Guillaume <pierguill@gmail.com> +" Last Change: 2024 May 21 +" +" Syntax support for rasi config file + +" This file is based on syntax defined in rofi-theme man page +" https://man.archlinux.org/man/community/rofi/rofi-theme.5.en + +if exists('b:current_syntax') + finish +endif +let b:current_syntax = 'rasi' + +" String {{{ +syn region rasiString start=+"+ skip=+\\"+ end=+"+ oneline contained +syn match rasiCharacter +L\='[^\\]'+ contained + +syn cluster rasiPropertyVals add=rasiString,rasiCharacter +" }}} + +" Integer/Real {{{ +syn match rasiNumber display contained '[+-]\?\d\+\(\.\d\+\)\?' + +syn cluster rasiPropertyVals add=rasiNumber +" }}} + +" Boolean {{{ +syn keyword rasiBool contained true false + +syn cluster rasiPropertyVals add=rasiBool +" }}} + +" Image {{{ +syn match rasiInvImage display contained 'url([^)]*)' +syn keyword rasiImageK contained url linear-gradient + +syn match rasiImage display contained transparent 'url(\s*"\([^"]\|\\"\)\+"\(\s*,\s*\(none\|both\|width\|height\)\)\?\s*)' contains=rasiImageScale,rasiString,rasiImageK +syn keyword rasiImageScale contained none both width height + +syn match rasiImage display contained transparent 'linear-gradient(\s*\(\(top\|left\|right\|bottom\)\s*,\s*\)\?[^,)]\+\s*\(,\s*[^,)]\+\s*\)\+)' contains=rasiImageDirection,@rasiColors,rasiImageK +syn keyword rasiImageDirection contained top left right bottom + +syn match rasiImage display contained transparent 'linear-gradient(\s*\d\+\(rad\|grad\|deg\)\s*,\s*[^,)]\+\s*\(,\s*[^,)]\+\s*\)\+)' contains=rasiImageUnit,@rasiColor,@rasiInvColor,rasiNumber,rasiImageK +syn match rasiImageUnit display contained '\(rad\|grad\|deg\)\>' + +syn cluster rasiPropertyVals add=rasiInvImage,rasiImage +" }}} + +" Reference {{{ +syn match rasiReference display contained '@[a-zA-Z0-9-]\+' + +syn keyword rasiVarReferenceK contained var + +syn match rasiInvVarReference display contained 'var([^)]*)' +syn match rasiVarReference display contained transparent 'var(\s*[a-zA-Z0-9-]\+\s*,\s*\(\a\+\s*([^)]*)\)\?[^),]*)' contains=rasiVarReferenceK,rasiPropertyIdRef,@rasiPropertyVals +syn match rasiPropertyIdRef display contained '\a[a-zA-Z0-9-]*' + +syn cluster rasiPropertyVals add=rasiReference,rasiInvVarReference,rasiVarReference +" }}} + +" Env variable {{{ +syn match rasiInvEnv display contained '${[^}]*}' +syn match rasiEnv display contained '${\w\+}'hs=s+2,he=e-1 + +syn keyword rasiEnvVarK contained env + +syn match rasiInvEnvVar display contained 'env([^)]*)' +syn match rasiEnvVar display contained transparent 'env(\s*\w\+\s*,\s*\(\a\+([^)]*)\)\?[^),]*)' contains=rasiEnvVarK,rasiEnvRef,@rasiPropertyVals +syn match rasiEnvRef display contained '\a\w*' + +syn cluster rasiPropertyVals add=rasiEnv,rasiInvEnv,rasiInvEnvVar,rasiEnvVar +" }}} + +" Color {{{ +syn keyword rasiColorK contained rgb[a] hsl[a] hwb[a] cmyk + +syn match rasiHexColor display contained '#\x\{3,4}' +syn match rasiHexColor display contained '#\x\{6}' +syn match rasiHexColor display contained '#\x\{8}' +syn match rasiInvHexColor display contained '#\x\{5}\X'he=e-1,me=e-1 +syn match rasiInvHexColor display contained '#\x\{7}\X'he=e-1,me=e-1 + +syn match rasiInvRGBColor display contained 'rgb\(a\)\?([^)]*)' +syn match rasiRGBColor display contained transparent 'rgb\(a\)\?(\s*\d\+\s*\(%\)\?\s*,\(\s*\d\+\s*\(%\)\?\s*\){2}\(,\s*\(\d\(\.\d*\)\?\|\d\{,3}%\)\s*\)\?)' contains=rasiColorK,rasiNumber,rasiDistance + +syn match rasiInvHSLColor display contained 'h\(sl\|wb\)\(a\)\?([^)]*)' +syn match rasiHSLColor display contained transparent 'h\(sl\|wb\)\(a\)\?(\s*\d\+\(\.\d*\)\?\(deg\|rad\|grad\|turn\)\?\s*\(,\s*\(\d\(\.\d*\)\?\|\d\{,3}%\)\s*\)\{2,3})' contains=rasiColorK,rasiNumber,rasiDistance + + +"this matches doesn't works properly (too long ?) +syn match rasiInvCMYKColor display contained 'cmyk([^)]*)' +syn match rasiCMYKColor display contained transparent 'cmyk(\s*\(\d\(\.\d*\)\?\|\d\{,3}%\)\s*\(,\s*\(\d\(\.\d*\)\?\|\d\{,3}%\)\s*\)\{3,4})' contains=rasiColorK,rasiNumber,rasiDistance + +syn case ignore +syn keyword rasiNamedColor contained + \ AliceBlue AntiqueWhite Aqua Aquamarine Azure Beige Bisque Black BlanchedAlmond Blue + \ BlueViolet Brown BurlyWood CadetBlue Chartreuse Chocolate Coral CornflowerBlue Cornsilk + \ Crimson Cyan DarkBlue DarkCyan DarkGoldenRod DarkGray DarkGrey DarkGreen DarkKhaki DarkMagenta + \ DarkOliveGreen DarkOrange DarkOrchid DarkRed DarkSalmon DarkSeaGreen Dark SlateBlue + \ DarkSlateGray DarkSlateGrey DarkTurquoise DarkViolet DeepPink DeepSkyBlue DimGray DimGrey + \ DodgerBlue FireBrick FloralWhite ForestGreen Fuchsia Gainsboro GhostWhite Gold GoldenRod + \ Gray Grey Green GreenYellow HoneyDew HotPink IndianRed Indigo Ivory Khaki Lavender + \ LavenderBlush LawnGreen LemonChiffon LightBlue LightCoral LightCyan LightGoldenRodYellow + \ LightGray LightGrey LightGreen LightPink LightSalmon LightSeaGreen LightSkyBlue LightSlateGray + \ LightSlateGrey LightSteelBlue LightYellow Lime LimeGreen Linen Magenta Maroon MediumAquaMarine + \ MediumBlue MediumOrchid MediumPurple MediumSeaGreen MediumSlateBlue MediumSpringGreen + \ MediumTurquoise MediumVioletRed MidnightBlue MintCream MistyRose Moccasin NavajoWhite Navy + \ OldLace Olive OliveDrab Orange OrangeRed Orchid PaleGoldenRod PaleGreen PaleTurquoise + \ PaleVioletRed PapayaWhip PeachPuff Peru Pink Plum PowderBlue Purple RebeccaPurple Red + \ RosyBrown RoyalBlue SaddleBrown Salmon SandyBrown SeaGreen SeaShell Sienna Silver SkyBlue + \ SlateBlue SlateGray SlateGrey Snow SpringGreen SteelBlue Tan Teal Thistle Tomato Turquoise + \ Violet Wheat White WhiteSmoke Yellow YellowGreen transparent[] "uses `[]` to escape keyword + +syn cluster rasiColors add=rasiHexColor,rasiRGBColor,rasiHSLColor,rasiCMYKColor,rasiNamedColor +syn cluster rasiColors add=rasiInvHexColor,rasiInvRGBColor,rasiInvHSLColor,rasiInvCMYKColor + +syn cluster rasiPropertyVals add=@rasiColors +" }}} + +" Text-Style {{{ +syn keyword rasiTextStyle contained bold italic underline strikethrough none + +syn cluster rasiPropertyVals add=rasiTextStyle +" }}} + +" Line-Style {{{ +syn keyword rasiLineStyle contained dash solid + +syn cluster rasiPropertyVals add=rasiLineStyle +" }}} + +" Distance {{{ +syn match rasiDistanceUnit display contained '\(px\|em\|ch\|%\|mm\)' + +syn match rasiInvDistance display contained '[+-]\?\d\+\.\d\+\(px\|mm\)' +syn match rasiDistance display contained transparent '[-+]\?\d\+\(px\|mm\)' contains=rasiDistanceUnit,rasiNumber +syn match rasiDistance display contained transparent '[+-]\?\d\+\(\.\d\+\)\?\(em\|ch\|%\)' contains=rasiDistanceUnit,rasiNumber + +syn keyword rasiDistanceCalc contained calc nextgroup=rasiDistanceCalcBody +syn region rasiDistanceCalcBody display contained start=+(+ end=+)+ contains=rasiDistanceCalcOp,rasiDistance,rasiInvDistance +syn match rasiDistanceCalcOp display contained '\(+\|-\|/\|\*\|%\|min\|max\)' + +syn cluster rasiPropertyVals add=rasiInvDistance,rasiDistance,rasiDistanceCalc +" }}} + +" Position {{{ +syn keyword rasiPosition contained center east north west south + +syn cluster rasiPropertyVals add=rasiPosition +" }}} + +" Orientation {{{ +syn keyword rasiOrientation contained horizontal vertical + +syn cluster rasiPropertyVals add=rasiOrientation +" }}} + +" Cursor {{{ +syn keyword rasiCursor contained default pointer text + +syn cluster rasiPropertyVals add=rasiCursor +" }}} + +" Keyword List {{{ +syn region rasiKeywordList contained start=+\[+ end=+\]+ contains=rasiPropertyIdRef + +syn cluster rasiPropertyVals add=rasiKeywordList +" }}} + +" Inherit {{{ +syn keyword rasiInherit contained inherit children + +syn cluster rasiPropertyVals add=rasiInherit +" }}} + +syn match rasiGlobalImport display '^\s*@\(import\|theme\)' nextgroup=rasiString skipwhite + +" Section {{{ +" syn region rasiSection transparent start='^[^{]\+{'me=e-1 end='}' contains=rasiSectionOpenning,rasiSectionContent +syn match rasiSectionOpenning transparent '^[^{]\+{'me=e-1 contains=rasiGlobalSection,rasiWidgetName,rasiGlobalMedia nextgroup=rasiThemeSectionContent +" syn match rasiThemeInnerSectionOpenning transparent '^[^:${]\+{'me=e-1 contains=rasiWidgetName nextgroup=rasiThemeInnerSectionContent contained + +syn match rasiGlobalMedia display contained '^\s*@media' nextgroup=rasiInvMediaBody,rasiMediaBody skipwhite +syn match rasiInvMediaBody display contained '([^)]*)' +syn match rasiMediaBody display contained '(\s*[a-z-]\+\s*:\s*\d\+\(px\|mm\)\?\s*)' contains=rasiMediaK,rasiNumber,rasiDistance +syn keyword rasiMediaK contained min-width max-width min-height max-height min-aspect-ratio max-aspect-ratio monitor-id + +syn match rasiGlobalSection display contained '^*' +syn match rasiWidgetName display contained '[a-zA-Z0-9-]\+' nextgroup=rasiVisibleMod skipwhite + +syn keyword rasiVisibleMod contained normal selected alternate nextgroup=rasiVisibleMod,rasiStateWrapper skipwhite +syn match rasiStateWrapper display contained transparent '\.\(normal\|active\|urgent\)' contains=rasiState +syn keyword rasiState contained normal active urgent + + +syn region rasiThemeSectionContent transparent start="{" end="}" contains=rasiProperty,rasiComment,rasiCommentL,rasiSectionOpenning contained +" syn region rasiThemeInnerSectionContent transparent start="{" end="}" contains=rasiProperty,rasiComment,rasiCommentL,rasiThemeInnerSectionOpenning contained + +syn match rasiProperty transparent '^\s*\S\+\s*:.*;\s*$' keepend contained contains=rasiPropertyId,rasiInvPropertyId,rasiPropertyVal,rasiComment,rasiCommentL +syn match rasiInvPropertyId '^\([^:]\&[^/]\{2}\)*:'me=e-1 contained +syn match rasiPropertyId '^\s*[0-9a-zA-Z-]\+\s*:'me=e-1 contained +syn match rasiInvPropertyVal ':[^;];\s*\S\+\s*$'ms=s+1,hs=s+1 +syn match rasiPropertyVal ':\s*[^;]\+;\s*$'ms=s+1,hs=s+1 contained contains=@rasiPropertyVals +" }}} + +" Comment {{{ +syn cluster rasiCommentGroup contains=rasiTodo,rasiBadContinuation + +syn region rasiCommentL start="//" skip="\\$" end="$" keepend contains=@rasiCommentGroup,@Spell +syn region rasiComment start="/\*" end="\*/" contains=@rasiCommentGroup,rasiCommentStartError,@Spell fold extend + +syn match rasiCommentError display '\*/' + +syn keyword rasiTodo contained TODO FIXME XXX NOTE + +if exists("rasi_minlines") + let b:rasi_minlines = rasi_minlines +else + let b:rasi_minlines = 50 +endif +exec "syn sync ccomment rasiComment minlines=" . b:rasi_minlines +" }}} + + + +" Highlighting: {{{ +hi def link rasiError Error + +hi def link rasiTodo Todo +hi def link rasiComment Comment +hi def link rasiCommentStart rasiComment +hi def link rasiCommentL rasiComment +hi def link rasiCommentError rasiError + +hi def link rasiString String +hi def link rasiNumber Number +hi def link rasiBool Boolean + +hi def link rasiImageK Function +hi def link rasiImageScale Keyword +hi def link rasiImageDirection Keyword +hi def link rasiImageUnit Type +hi def link rasiInvImage rasiError + +hi def link rasiHexColor Number +hi def link rasiColorK Function +hi def link rasiNamedColor Number +hi def link rasiInvColor rasiError +hi def link rasiInvHexColor rasiInvColor +hi def link rasiInvRGBColor rasiInvColor +hi def link rasiInvHSLColor rasiInvColor +hi def link rasiInvCMYKColor rasiInvColor + +hi def link rasiTextStyle Keyword +hi def link rasiLineStyle Keyword + +hi def link rasiDistanceUnit Type +hi def link rasiDistanceCalc Function +hi def link rasiDistanceCalcOp Operator +hi def link rasiInvDistance rasiError + +hi def link rasiPosition Keyword +hi def link rasiOrientation Keyword +hi def link rasiCursor Keyword + +hi def link rasiReference Identifier +hi def link rasiPropertyIdRef Identifier +hi def link rasiVarReferenceK Function +hi def link rasiInvVarReference rasiError + +hi def link rasiEnv Identifier +hi def link rasiEnvRef Identifier +hi def link rasiEnvVarK Function +hi def link rasiInvEnv rasiError +hi def link rasiInvEnvVar rasiError + +hi def link rasiWidgetName StorageClass +hi def link rasiGlobalSection StorageClass +hi def link rasiVisibleMod Type +hi def link rasiState Tag + +hi def link rasiInherit Identifier + +hi def link rasiGlobalImport Include + +hi def link rasiGlobalMedia Preproc +hi def link rasiMediaK Keyword +hi def link rasiInvMediaBody rasiError + +hi def link rasiPropertyId Identifier +hi def link rasiInvProperty rasiError +hi def link rasiInvPropertyId rasiError +hi def link rasiInvPropertyVal rasiError +" }}} + +" vim:ts=8 diff --git a/runtime/syntax/salt.vim b/runtime/syntax/salt.vim new file mode 100644 index 0000000000..fdbce2f677 --- /dev/null +++ b/runtime/syntax/salt.vim @@ -0,0 +1,16 @@ +" Vim syntax file +" Maintainer: Gregory Anders +" Last Changed: 2024-09-16 + +if exists('b:current_syntax') + finish +endif + +" Salt state files are just YAML with embedded Jinja +runtime! syntax/yaml.vim +unlet! b:current_syntax + +runtime! syntax/jinja.vim +unlet! b:current_syntax + +let b:current_syntax = 'salt' diff --git a/runtime/syntax/scheme.vim b/runtime/syntax/scheme.vim index c4454fc57c..59b0cc5b18 100644 --- a/runtime/syntax/scheme.vim +++ b/runtime/syntax/scheme.vim @@ -1,12 +1,12 @@ " Vim syntax file -" Language: Scheme (R7RS) -" Last Change: 2021-01-03 -" Author: Evan Hanson <evhan@foldling.org> -" Maintainer: Evan Hanson <evhan@foldling.org> -" Previous Author: Dirk van Deun <dirk@igwe.vub.ac.be> +" Language: Scheme (R7RS) +" Last Change: 2024 Jun 21 +" Author: Evan Hanson <evhan@foldling.org> +" Maintainer: Evan Hanson <evhan@foldling.org> +" Previous Author: Dirk van Deun <dirk@igwe.vub.ac.be> " Previous Maintainer: Sergey Khorev <sergey.khorev@gmail.com> -" Repository: https://git.foldling.org/vim-scheme.git -" URL: https://foldling.org/vim/syntax/scheme.vim +" Repository: https://git.foldling.org/vim-scheme.git +" URL: https://foldling.org/vim/syntax/scheme.vim if exists('b:current_syntax') finish @@ -50,9 +50,11 @@ syn match schemeBoolean /#f\(alse\)\?/ syn match schemeCharacter /#\\.[^ `'\t\n\[\]()]*/ syn match schemeCharacter /#\\x[0-9a-fA-F]\+/ -syn match schemeComment /;.*$/ contains=@Spell +syn match schemeComment /;.*$/ contains=schemeTodo,@Spell -syn region schemeMultilineComment start=/#|/ end=/|#/ contains=schemeMultilineComment,@Spell +syn region schemeMultilineComment start=/#|/ end=/|#/ contains=schemeTodo,schemeMultilineComment,@Spell + +syn match schemeTodo /\c\<\(todo\|xxx\|fixme\|note\):\?\>/ contained syn region schemeForm matchgroup=schemeParentheses start="(" end=")" contains=ALLBUT,schemeUnquote,schemeDatumCommentForm,@schemeImportCluster syn region schemeForm matchgroup=schemeParentheses start="\[" end="\]" contains=ALLBUT,schemeUnquote,schemeDatumCommentForm,@schemeImportCluster @@ -427,6 +429,7 @@ syn keyword schemeFunction write-string syn keyword schemeFunction write-u8 syn keyword schemeFunction zero? +hi def link schemeTodo Todo hi def link schemeBoolean Boolean hi def link schemeCharacter Character hi def link schemeComment Comment diff --git a/runtime/syntax/sdc.vim b/runtime/syntax/sdc.vim index dbfa35eeb6..ae2aae5f07 100644 --- a/runtime/syntax/sdc.vim +++ b/runtime/syntax/sdc.vim @@ -1,9 +1,10 @@ " Vim syntax file " Language: SDC - Synopsys Design Constraints " Maintainer: Maurizio Tranchero - maurizio.tranchero@gmail.com -" Last Change: Thu Mar 25 17:35:16 CET 2009 " Credits: based on TCL Vim syntax file " Version: 0.3 +" Last Change: Thu Mar 25 17:35:16 CET 2009 +" 2024 Jul 17 by Vim Project (update to SDC 2.1) " Quit when a syntax file was already loaded if exists("b:current_syntax") @@ -13,16 +14,48 @@ endif " Read the TCL syntax to start with runtime! syntax/tcl.vim -" SDC-specific keywords +" TCL extension related to SDC and available from some vendors +" (not defined in SDC standard!) syn keyword sdcCollections foreach_in_collection -syn keyword sdcObjectsQuery get_clocks get_ports syn keyword sdcObjectsInfo get_point_info get_node_info get_path_info syn keyword sdcObjectsInfo get_timing_paths set_attribute -syn keyword sdcConstraints set_false_path + +" SDC rev. 2.1 specific keywords +syn keyword sdcObjectsQuery get_clocks get_ports get_cells +syn keyword sdcObjectsQuery get_pins get_nets all_inputs +syn keyword sdcObjectsQuery all_outputs all_registers all_clocks +syn keyword sdcObjectsQuery get_libs get_lib_cells get_lib_pins + +syn keyword sdcConstraints set_false_path set_clock_groups set_sense +syn keyword sdcConstraints set_propagated_clock set_clock_gating_check +syn keyword sdcConstraints set_ideal_latency set_ideal_network +syn keyword sdcConstraints set_ideal_transistion set_max_time_borrow +syn keyword sdcConstraints set_data_check group_path set_max_transition +syn keyword sdcConstraints set_max_fanout set_driving_cell +syn keyword sdcConstraints set_port_fanout_number set_multi_cycle_path +syn keyword sdcConstraints set_disable_timing set_min_pulse_width + syn keyword sdcNonIdealities set_min_delay set_max_delay syn keyword sdcNonIdealities set_input_delay set_output_delay syn keyword sdcNonIdealities set_load set_min_capacitance set_max_capacitance +syn keyword sdcNonIdealities set_clock_latency set_clock_transition set_clock_uncertainty +syn keyword sdcNonIdealities set_resistance set_timing_derate set_drive +syn keyword sdcNonIdealities set_input_transition set_fanout_load + syn keyword sdcCreateOperations create_clock create_timing_netlist update_timing_netlist +syn keyword sdcCreateOperations create_generated_clock + +syn keyword sdcPowerArea set_max_area create_voltage_area +syn keyword sdcPowerArea set_level_shifter_threshold set_max_dynamic_power +syn keyword sdcPowerArea set_level_shifter_strategy set_max_leakage_power + +syn keyword sdcModeConfig set_case_analysis set_logic_dc +syn keyword sdcModeConfig set_logic_zero set_logic_one + +syn keyword sdcMiscCommmands sdc_version set_wire_load_selection_group +syn keyword sdcMiscCommmands set_units set_wire_load_mode set_wire_load_model +syn keyword sdcMiscCommmands set_wire_load_min_block_size set_operating_conditions +syn keyword sdcMiscCommmands current_design " command flags highlighting syn match sdcFlags "[[:space:]]-[[:alpha:]_]*\>" @@ -31,9 +64,12 @@ syn match sdcFlags "[[:space:]]-[[:alpha:]_]*\>" hi def link sdcCollections Repeat hi def link sdcObjectsInfo Operator hi def link sdcCreateOperations Operator -hi def link sdcObjectsQuery Operator +hi def link sdcObjectsQuery Function hi def link sdcConstraints Operator hi def link sdcNonIdealities Operator +hi def link sdcPowerArea Operator +hi def link sdcModeConfig Operator +hi def link sdcMiscCommmands Operator hi def link sdcFlags Special let b:current_syntax = "sdc" diff --git a/runtime/syntax/shared/debversions.vim b/runtime/syntax/shared/debversions.vim index e18eca96b1..56f18b969a 100644 --- a/runtime/syntax/shared/debversions.vim +++ b/runtime/syntax/shared/debversions.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: Debian version information " Maintainer: Debian Vim Maintainers -" Last Change: 2024 Apr 27 +" Last Change: 2024 May 25 " URL: https://salsa.debian.org/vim-team/vim-debian/blob/main/syntax/shared/debversions.vim let s:cpo = &cpo @@ -11,7 +11,7 @@ let g:debSharedSupportedVersions = [ \ 'oldstable', 'stable', 'testing', 'unstable', 'experimental', 'sid', 'rc-buggy', \ 'bullseye', 'bookworm', 'trixie', 'forky', \ - \ 'trusty', 'xenial', 'bionic', 'focal', 'jammy', 'mantic', 'noble', 'oracular', + \ 'focal', 'jammy', 'mantic', 'noble', 'oracular', \ 'devel' \ ] let g:debSharedUnsupportedVersions = [ @@ -22,8 +22,9 @@ let g:debSharedUnsupportedVersions = [ \ 'warty', 'hoary', 'breezy', 'dapper', 'edgy', 'feisty', \ 'gutsy', 'hardy', 'intrepid', 'jaunty', 'karmic', 'lucid', \ 'maverick', 'natty', 'oneiric', 'precise', 'quantal', 'raring', 'saucy', - \ 'utopic', 'vivid', 'wily', 'yakkety', 'zesty', 'artful', 'cosmic', - \ 'disco', 'eoan', 'hirsute', 'impish', 'kinetic', 'lunar', 'groovy' + \ 'trusty', 'utopic', 'vivid', 'wily', 'xenial', 'yakkety', 'zesty', + \ 'artful', 'bionic', 'cosmic', 'disco', 'eoan', 'hirsute', + \ 'impish', 'kinetic', 'lunar', 'groovy' \ ] let &cpo=s:cpo diff --git a/runtime/syntax/shared/typescriptcommon.vim b/runtime/syntax/shared/typescriptcommon.vim index d06525115e..3af79a38fb 100644 --- a/runtime/syntax/shared/typescriptcommon.vim +++ b/runtime/syntax/shared/typescriptcommon.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: TypeScript and TypeScriptReact " Maintainer: Herrington Darkholme -" Last Change: 2023 Aug 24 +" Last Change: 2024 May 24 " Based On: Herrington Darkholme's yats.vim " Changes: See https://github.com/HerringtonDarkholme/yats.vim " Credits: See yats.vim on github @@ -49,13 +49,13 @@ syntax match typescriptProp contained /\K\k*!\?/ \ nextgroup=@afterIdentifier \ skipwhite skipempty -syntax region typescriptIndexExpr contained matchgroup=typescriptProperty start=/\[/rs=s+1 end=/]/he=e-1 contains=@typescriptValue nextgroup=@typescriptSymbols,typescriptDotNotation,typescriptFuncCallArg skipwhite skipempty +syntax region typescriptIndexExpr contained matchgroup=typescriptProperty start=/\[/ end=/]/ contains=@typescriptValue,typescriptCastKeyword nextgroup=@typescriptSymbols,typescriptDotNotation,typescriptFuncCallArg skipwhite skipempty syntax match typescriptDotNotation /\.\|?\.\|!\./ nextgroup=typescriptProp skipnl syntax match typescriptDotStyleNotation /\.style\./ nextgroup=typescriptDOMStyle transparent " syntax match typescriptFuncCall contained /[a-zA-Z]\k*\ze(/ nextgroup=typescriptFuncCallArg syntax region typescriptParenExp matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptComments,@typescriptValue,typescriptCastKeyword nextgroup=@typescriptSymbols skipwhite skipempty -syntax region typescriptFuncCallArg contained matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptValue,@typescriptComments nextgroup=@typescriptSymbols,typescriptDotNotation skipwhite skipempty skipnl +syntax region typescriptFuncCallArg contained matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptValue,@typescriptComments,typescriptCastKeyword nextgroup=@typescriptSymbols,typescriptDotNotation skipwhite skipempty skipnl syntax region typescriptEventFuncCallArg contained matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptEventExpression syntax region typescriptEventString contained start=/\z(["']\)/ skip=/\\\\\|\\\z1\|\\\n/ end=/\z1\|$/ contains=typescriptASCII,@events @@ -116,20 +116,33 @@ syntax match typescriptASCII contained /\\\d\d\d/ syntax region typescriptTemplateSubstitution matchgroup=typescriptTemplateSB \ start=/\${/ end=/}/ - \ contains=@typescriptValue + \ contains=@typescriptValue,typescriptCastKeyword \ contained -syntax region typescriptString +syntax region typescriptString \ start=+\z(["']\)+ skip=+\\\%(\z1\|$\)+ end=+\z1+ end=+$+ \ contains=typescriptSpecial,@Spell + \ nextgroup=@typescriptSymbols + \ skipwhite skipempty \ extend syntax match typescriptSpecial contained "\v\\%(x\x\x|u%(\x{4}|\{\x{1,6}})|c\u|.)" -" From vim runtime -" <https://github.com/vim/vim/blob/master/runtime/syntax/javascript.vim#L48> -syntax region typescriptRegexpString start=+/[^/*]+me=e-1 skip=+\\\\\|\\/+ end=+/[gimuy]\{0,5\}\s*$+ end=+/[gimuy]\{0,5\}\s*[;.,)\]}:]+me=e-1 nextgroup=typescriptDotNotation oneline +" From pangloss/vim-javascript +" <https://github.com/pangloss/vim-javascript/blob/d6e137563c47fb59f26ed25d044c0c7532304f18/syntax/javascript.vim#L64-L72> +syntax region typescriptRegexpCharClass contained start=+\[+ skip=+\\.+ end=+\]+ contains=typescriptSpecial extend +syntax match typescriptRegexpBoundary contained "\v\c[$^]|\\b" +syntax match typescriptRegexpBackRef contained "\v\\[1-9]\d*" +syntax match typescriptRegexpQuantifier contained "\v[^\\]%([?*+]|\{\d+%(,\d*)?})\??"lc=1 +syntax match typescriptRegexpOr contained "|" +syntax match typescriptRegexpMod contained "\v\(\?[:=!>]"lc=1 +syntax region typescriptRegexpGroup contained start="[^\\]("lc=1 skip="\\.\|\[\(\\.\|[^]]\+\)\]" end=")" contains=typescriptRegexpCharClass,@typescriptRegexpSpecial keepend +syntax region typescriptRegexpString + \ start=+\%(\%(\<return\|\<typeof\|\_[^)\]'"[:blank:][:alnum:]_$]\)\s*\)\@<=/\ze[^*/]+ skip=+\\.\|\[[^]]\{1,}\]+ end=+/[gimyus]\{,6}+ + \ contains=typescriptRegexpCharClass,typescriptRegexpGroup,@typescriptRegexpSpecial + \ oneline keepend extend +syntax cluster typescriptRegexpSpecial contains=typescriptSpecial,typescriptRegexpBoundary,typescriptRegexpBackRef,typescriptRegexpQuantifier,typescriptRegexpOr,typescriptRegexpMod syntax region typescriptTemplate \ start=/`/ skip=/\\\\\|\\`\|\n/ end=/`\|$/ @@ -140,7 +153,7 @@ syntax region typescriptTemplate "Array syntax region typescriptArray matchgroup=typescriptBraces \ start=/\[/ end=/]/ - \ contains=@typescriptValue,@typescriptComments + \ contains=@typescriptValue,@typescriptComments,typescriptCastKeyword \ nextgroup=@typescriptSymbols,typescriptDotNotation \ skipwhite skipempty fold @@ -153,7 +166,7 @@ syntax match typescriptNumber /\<\%(\d[0-9_]*\%(\.\d[0-9_]*\)\=\|\.\d[0-9_]*\)\% syntax region typescriptObjectLiteral matchgroup=typescriptBraces \ start=/{/ end=/}/ - \ contains=@typescriptComments,typescriptObjectLabel,typescriptStringProperty,typescriptComputedPropertyName,typescriptObjectAsyncKeyword + \ contains=@typescriptComments,typescriptObjectLabel,typescriptStringProperty,typescriptComputedPropertyName,typescriptObjectAsyncKeyword,typescriptTernary,typescriptCastKeyword \ fold contained syntax keyword typescriptObjectAsyncKeyword async contained @@ -223,11 +236,11 @@ syntax match typescriptBinaryOp contained /\*\*=\?/ nextgroup=@typescriptValue syntax cluster typescriptSymbols contains=typescriptBinaryOp,typescriptKeywordOp,typescriptTernary,typescriptAssign,typescriptCastKeyword -" runtime syntax/basic/reserved.vim +" runtime syntax/ts-common/reserved.vim "Import syntax keyword typescriptImport from as syntax keyword typescriptImport import - \ nextgroup=typescriptImportType + \ nextgroup=typescriptImportType,typescriptTypeBlock,typescriptDefaultImportName \ skipwhite syntax keyword typescriptImportType type \ contained @@ -238,20 +251,11 @@ syntax match typescriptExportType /\<type\s*{\@=/ \ contained skipwhite skipempty skipnl syntax keyword typescriptModule namespace module -"this - -"JavaScript Prototype -syntax keyword typescriptPrototype prototype - \ nextgroup=@afterIdentifier -syntax keyword typescriptCastKeyword as +syntax keyword typescriptCastKeyword as satisfies \ nextgroup=@typescriptType \ skipwhite -"Program Keywords -syntax keyword typescriptIdentifier arguments this super - \ nextgroup=@afterIdentifier - syntax keyword typescriptVariable let var \ nextgroup=@typescriptVariableDeclarations \ skipwhite skipempty @@ -260,6 +264,10 @@ syntax keyword typescriptVariable const \ nextgroup=typescriptEnum,@typescriptVariableDeclarations \ skipwhite skipempty +syntax keyword typescriptUsing using + \ nextgroup=@typescriptVariableDeclarations + \ skipwhite skipempty + syntax region typescriptEnum matchgroup=typescriptEnumKeyword start=/enum / end=/\ze{/ \ nextgroup=typescriptBlock \ skipwhite @@ -272,7 +280,6 @@ syntax keyword typescriptOperator delete new typeof void syntax keyword typescriptForOperator contained in of syntax keyword typescriptBoolean true false nextgroup=@typescriptSymbols skipwhite skipempty -syntax keyword typescriptNull null undefined nextgroup=@typescriptSymbols skipwhite skipempty syntax keyword typescriptMessage alert confirm prompt status \ nextgroup=typescriptDotNotation,typescriptFuncCallArg syntax keyword typescriptGlobal self top parent @@ -290,10 +297,10 @@ syntax keyword typescriptCase case nextgroup=@typescriptPrimiti syntax keyword typescriptDefault default containedin=typescriptBlock nextgroup=@typescriptValue,typescriptClassKeyword,typescriptInterfaceKeyword skipwhite oneline syntax keyword typescriptStatementKeyword with syntax keyword typescriptStatementKeyword yield skipwhite nextgroup=@typescriptValue containedin=typescriptBlock -syntax keyword typescriptStatementKeyword return skipwhite contained nextgroup=@typescriptValue containedin=typescriptBlock syntax keyword typescriptTry try -syntax keyword typescriptExceptions catch throw finally +syntax keyword typescriptExceptions throw finally +syntax keyword typescriptExceptions catch nextgroup=typescriptCall skipwhite skipempty oneline syntax keyword typescriptDebugger debugger syntax keyword typescriptAsyncFor await nextgroup=typescriptLoopParen skipwhite skipempty contained @@ -321,6 +328,24 @@ syntax cluster typescriptAmbients contains= \ typescriptEnumKeyword,typescriptEnum, \ typescriptModule +syntax keyword typescriptIdentifier arguments nextgroup=@afterIdentifier +syntax match typescriptDefaultImportName /\v\h\k*( |,)/ + \ contained + \ nextgroup=typescriptTypeBlock + \ skipwhite skipempty + +syntax region typescriptTypeBlock + \ matchgroup=typescriptBraces + \ start=/{/ end=/}/ + \ contained + \ contains=typescriptIdentifierName,typescriptImportType + \ fold + +"Program Keywords +syntax keyword typescriptNull null undefined nextgroup=@typescriptSymbols skipwhite skipempty +syntax keyword typescriptIdentifier this super prototype nextgroup=@afterIdentifier +syntax keyword typescriptStatementKeyword return skipwhite contained nextgroup=@typescriptValue containedin=typescriptBlock + "Syntax coloring for Node.js shebang line syntax match shellbang "^#!.*node\>" syntax match shellbang "^#!.*iojs\>" @@ -536,7 +561,7 @@ syntax region typescriptGenericFunc matchgroup=typescriptTypeBrackets \ contained skipwhite skipnl syntax region typescriptFuncType matchgroup=typescriptParens - \ start=/(/ end=/)\s*=>/me=e-2 + \ start=/(\(\k\+:\|)\)\@=/ end=/)\s*=>/me=e-2 \ contains=@typescriptParameterList \ nextgroup=typescriptFuncTypeArrow \ contained skipwhite skipnl oneline @@ -546,7 +571,6 @@ syntax match typescriptFuncTypeArrow /=>/ \ containedin=typescriptFuncType \ contained skipwhite skipnl - syntax keyword typescriptConstructorType new \ nextgroup=@typescriptFunctionType \ contained skipwhite skipnl @@ -623,25 +647,24 @@ syntax keyword typescriptReadonlyArrayKeyword readonly " extension -if get(g:, 'yats_host_keyword', 1) - syntax keyword typescriptGlobal containedin=typescriptIdentifierName Function Boolean - " use of nextgroup Suggested by Doug Kearns +if get(g:, 'typescript_host_keyword', 1) + syntax keyword typescriptGlobal containedin=typescriptIdentifierName Function Boolean nextgroup=typescriptFuncCallArg syntax keyword typescriptGlobal containedin=typescriptIdentifierName Error EvalError nextgroup=typescriptFuncCallArg - syntax keyword typescriptGlobal containedin=typescriptIdentifierName InternalError - syntax keyword typescriptGlobal containedin=typescriptIdentifierName RangeError ReferenceError - syntax keyword typescriptGlobal containedin=typescriptIdentifierName StopIteration - syntax keyword typescriptGlobal containedin=typescriptIdentifierName SyntaxError TypeError - syntax keyword typescriptGlobal containedin=typescriptIdentifierName URIError Date - syntax keyword typescriptGlobal containedin=typescriptIdentifierName Float32Array - syntax keyword typescriptGlobal containedin=typescriptIdentifierName Float64Array - syntax keyword typescriptGlobal containedin=typescriptIdentifierName Int16Array Int32Array - syntax keyword typescriptGlobal containedin=typescriptIdentifierName Int8Array Uint16Array - syntax keyword typescriptGlobal containedin=typescriptIdentifierName Uint32Array Uint8Array - syntax keyword typescriptGlobal containedin=typescriptIdentifierName Uint8ClampedArray - syntax keyword typescriptGlobal containedin=typescriptIdentifierName ParallelArray - syntax keyword typescriptGlobal containedin=typescriptIdentifierName ArrayBuffer DataView - syntax keyword typescriptGlobal containedin=typescriptIdentifierName Iterator Generator - syntax keyword typescriptGlobal containedin=typescriptIdentifierName Reflect Proxy + syntax keyword typescriptGlobal containedin=typescriptIdentifierName InternalError nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName RangeError ReferenceError nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName StopIteration nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName SyntaxError TypeError nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName URIError Date nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName Float32Array nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName Float64Array nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName Int16Array Int32Array nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName Int8Array Uint16Array nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName Uint32Array Uint8Array nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName Uint8ClampedArray nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName ParallelArray nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName ArrayBuffer DataView nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName Iterator Generator nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName Reflect Proxy nextgroup=typescriptFuncCallArg syntax keyword typescriptGlobal containedin=typescriptIdentifierName arguments hi def link typescriptGlobal Structure syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName eval uneval nextgroup=typescriptFuncCallArg @@ -675,12 +698,12 @@ if get(g:, 'yats_host_keyword', 1) hi def link typescriptStringStaticMethod Keyword syntax keyword typescriptStringMethod contained anchor charAt charCodeAt codePointAt nextgroup=typescriptFuncCallArg syntax keyword typescriptStringMethod contained concat endsWith includes indexOf lastIndexOf nextgroup=typescriptFuncCallArg - syntax keyword typescriptStringMethod contained link localeCompare match normalize nextgroup=typescriptFuncCallArg - syntax keyword typescriptStringMethod contained padStart padEnd repeat replace search nextgroup=typescriptFuncCallArg + syntax keyword typescriptStringMethod contained link localeCompare match matchAll normalize nextgroup=typescriptFuncCallArg + syntax keyword typescriptStringMethod contained padStart padEnd repeat replace replaceAll search nextgroup=typescriptFuncCallArg syntax keyword typescriptStringMethod contained slice split startsWith substr substring nextgroup=typescriptFuncCallArg syntax keyword typescriptStringMethod contained toLocaleLowerCase toLocaleUpperCase nextgroup=typescriptFuncCallArg syntax keyword typescriptStringMethod contained toLowerCase toString toUpperCase trim nextgroup=typescriptFuncCallArg - syntax keyword typescriptStringMethod contained valueOf nextgroup=typescriptFuncCallArg + syntax keyword typescriptStringMethod contained trimEnd trimStart valueOf nextgroup=typescriptFuncCallArg syntax cluster props add=typescriptStringMethod hi def link typescriptStringMethod Keyword @@ -689,18 +712,18 @@ if get(g:, 'yats_host_keyword', 1) syntax keyword typescriptArrayStaticMethod contained from isArray of nextgroup=typescriptFuncCallArg hi def link typescriptArrayStaticMethod Keyword syntax keyword typescriptArrayMethod contained concat copyWithin entries every fill nextgroup=typescriptFuncCallArg - syntax keyword typescriptArrayMethod contained filter find findIndex forEach indexOf nextgroup=typescriptFuncCallArg - syntax keyword typescriptArrayMethod contained includes join keys lastIndexOf map nextgroup=typescriptFuncCallArg + syntax keyword typescriptArrayMethod contained filter find findIndex flat flatMap forEach nextgroup=typescriptFuncCallArg + syntax keyword typescriptArrayMethod contained includes indexOf join keys lastIndexOf map nextgroup=typescriptFuncCallArg syntax keyword typescriptArrayMethod contained pop push reduce reduceRight reverse nextgroup=typescriptFuncCallArg syntax keyword typescriptArrayMethod contained shift slice some sort splice toLocaleString nextgroup=typescriptFuncCallArg - syntax keyword typescriptArrayMethod contained toSource toString unshift nextgroup=typescriptFuncCallArg + syntax keyword typescriptArrayMethod contained toSource toString unshift values nextgroup=typescriptFuncCallArg syntax cluster props add=typescriptArrayMethod hi def link typescriptArrayMethod Keyword syntax keyword typescriptGlobal containedin=typescriptIdentifierName Object nextgroup=typescriptGlobalObjectDot,typescriptFuncCallArg syntax match typescriptGlobalObjectDot /\./ contained nextgroup=typescriptObjectStaticMethod,typescriptProp syntax keyword typescriptObjectStaticMethod contained create defineProperties defineProperty nextgroup=typescriptFuncCallArg - syntax keyword typescriptObjectStaticMethod contained entries freeze getOwnPropertyDescriptors nextgroup=typescriptFuncCallArg + syntax keyword typescriptObjectStaticMethod contained entries freeze fromEntries getOwnPropertyDescriptors nextgroup=typescriptFuncCallArg syntax keyword typescriptObjectStaticMethod contained getOwnPropertyDescriptor getOwnPropertyNames nextgroup=typescriptFuncCallArg syntax keyword typescriptObjectStaticMethod contained getOwnPropertySymbols getPrototypeOf nextgroup=typescriptFuncCallArg syntax keyword typescriptObjectStaticMethod contained is isExtensible isFrozen isSealed nextgroup=typescriptFuncCallArg @@ -715,7 +738,7 @@ if get(g:, 'yats_host_keyword', 1) syntax keyword typescriptGlobal containedin=typescriptIdentifierName Symbol nextgroup=typescriptGlobalSymbolDot,typescriptFuncCallArg syntax match typescriptGlobalSymbolDot /\./ contained nextgroup=typescriptSymbolStaticProp,typescriptSymbolStaticMethod,typescriptProp - syntax keyword typescriptSymbolStaticProp contained length iterator match replace + syntax keyword typescriptSymbolStaticProp contained description length iterator match matchAll replace syntax keyword typescriptSymbolStaticProp contained search split hasInstance isConcatSpreadable syntax keyword typescriptSymbolStaticProp contained unscopables species toPrimitive syntax keyword typescriptSymbolStaticProp contained toStringTag @@ -771,7 +794,7 @@ if get(g:, 'yats_host_keyword', 1) syntax match typescriptGlobalRegExpDot /\./ contained nextgroup=typescriptRegExpStaticProp,typescriptProp syntax keyword typescriptRegExpStaticProp contained lastIndex hi def link typescriptRegExpStaticProp Keyword - syntax keyword typescriptRegExpProp contained global ignoreCase multiline source sticky + syntax keyword typescriptRegExpProp contained dotAll global ignoreCase multiline source sticky syntax cluster props add=typescriptRegExpProp hi def link typescriptRegExpProp Keyword syntax keyword typescriptRegExpMethod contained exec test nextgroup=typescriptFuncCallArg @@ -805,7 +828,7 @@ if get(g:, 'yats_host_keyword', 1) syntax keyword typescriptGlobal containedin=typescriptIdentifierName Promise nextgroup=typescriptGlobalPromiseDot,typescriptFuncCallArg syntax match typescriptGlobalPromiseDot /\./ contained nextgroup=typescriptPromiseStaticMethod,typescriptProp - syntax keyword typescriptPromiseStaticMethod contained resolve reject all race nextgroup=typescriptFuncCallArg + syntax keyword typescriptPromiseStaticMethod contained all allSettled any race reject resolve nextgroup=typescriptFuncCallArg hi def link typescriptPromiseStaticMethod Keyword syntax keyword typescriptPromiseMethod contained then catch finally nextgroup=typescriptFuncCallArg syntax cluster props add=typescriptPromiseMethod @@ -1232,7 +1255,8 @@ if get(g:, 'yats_host_keyword', 1) syntax cluster props add=typescriptBOMHistoryMethod hi def link typescriptBOMHistoryMethod Keyword - syntax keyword typescriptGlobal containedin=typescriptIdentifierName console + syntax keyword typescriptGlobal containedin=typescriptIdentifierName console nextgroup=typescriptGlobalConsoleDot + syntax match typescriptGlobalConsoleDot /\./ contained nextgroup=typescriptConsoleMethod,typescriptProp syntax keyword typescriptConsoleMethod contained count dir error group groupCollapsed nextgroup=typescriptFuncCallArg syntax keyword typescriptConsoleMethod contained groupEnd info log time timeEnd trace nextgroup=typescriptFuncCallArg syntax keyword typescriptConsoleMethod contained warn nextgroup=typescriptFuncCallArg @@ -1735,8 +1759,6 @@ if get(g:, 'yats_host_keyword', 1) syntax keyword typescriptServiceWorkerEvent contained install activate fetch syntax cluster events add=typescriptServiceWorkerEvent hi def link typescriptServiceWorkerEvent Title - - endif " patch @@ -1764,6 +1786,7 @@ syntax cluster typescriptPropertyMemberDeclaration contains= \ typescriptClassStatic, \ typescriptAccessibilityModifier, \ typescriptReadonlyModifier, + \ typescriptAutoAccessor, \ typescriptMethodAccessor, \ @typescriptMembers " \ typescriptMemberVariableDeclaration @@ -1780,7 +1803,9 @@ syntax keyword typescriptClassStatic static syntax keyword typescriptAccessibilityModifier public private protected contained -syntax keyword typescriptReadonlyModifier readonly contained +syntax keyword typescriptReadonlyModifier readonly override contained + +syntax keyword typescriptAutoAccessor accessor contained syntax region typescriptStringMember contained \ start=/\z(["']\)/ skip=/\\\\\|\\\z1\|\\\n/ end=/\z1/ @@ -1789,7 +1814,7 @@ syntax region typescriptStringMember contained syntax region typescriptComputedMember contained matchgroup=typescriptProperty \ start=/\[/rs=s+1 end=/]/ - \ contains=@typescriptValue,typescriptMember,typescriptMappedIn + \ contains=@typescriptValue,typescriptMember,typescriptMappedIn,typescriptCastKeyword \ nextgroup=@memberNextGroup \ skipwhite skipempty @@ -1861,7 +1886,7 @@ syntax match typescriptInterfaceComma /,/ contained nextgroup=typescriptInterfac "Block VariableStatement EmptyStatement ExpressionStatement IfStatement IterationStatement ContinueStatement BreakStatement ReturnStatement WithStatement LabelledStatement SwitchStatement ThrowStatement TryStatement DebuggerStatement syntax cluster typescriptStatement - \ contains=typescriptBlock,typescriptVariable, + \ contains=typescriptBlock,typescriptVariable,typescriptUsing, \ @typescriptTopExpression,typescriptAssign, \ typescriptConditional,typescriptRepeat,typescriptBranch, \ typescriptLabel,typescriptStatementKeyword, @@ -1899,16 +1924,14 @@ syntax cluster typescriptValue syntax cluster typescriptEventExpression contains=typescriptArrowFuncDef,typescriptParenExp,@typescriptValue,typescriptRegexpString,@typescriptEventTypes,typescriptOperator,typescriptGlobal,jsxRegion syntax keyword typescriptAsyncFuncKeyword async - \ nextgroup=typescriptFuncKeyword,typescriptArrowFuncDef + \ nextgroup=typescriptFuncKeyword,typescriptArrowFuncDef,typescriptArrowFuncTypeParameter \ skipwhite syntax keyword typescriptAsyncFuncKeyword await - \ nextgroup=@typescriptValue + \ nextgroup=@typescriptValue,typescriptUsing \ skipwhite -syntax keyword typescriptFuncKeyword function - \ nextgroup=typescriptAsyncFunc,typescriptFuncName,@typescriptCallSignature - \ skipwhite skipempty +syntax keyword typescriptFuncKeyword function nextgroup=typescriptAsyncFunc,typescriptFuncName,@typescriptCallSignature skipwhite skipempty syntax match typescriptAsyncFunc contained /*/ \ nextgroup=typescriptFuncName,@typescriptCallSignature @@ -1918,39 +1941,33 @@ syntax match typescriptFuncName contained /\K\k*/ \ nextgroup=@typescriptCallSignature \ skipwhite -" destructuring ({ a: ee }) => -syntax match typescriptArrowFuncDef contained /(\(\s*\({\_[^}]*}\|\k\+\)\(:\_[^)]\)\?,\?\)\+)\s*=>/ - \ contains=typescriptArrowFuncArg,typescriptArrowFunc - \ nextgroup=@typescriptExpression,typescriptBlock - \ skipwhite skipempty - -" matches `(a) =>` or `([a]) =>` or -" `( -" a) =>` -syntax match typescriptArrowFuncDef contained /(\(\_s*[a-zA-Z\$_\[.]\_[^)]*\)*)\s*=>/ +syntax match typescriptArrowFuncDef contained /\K\k*\s*=>/ \ contains=typescriptArrowFuncArg,typescriptArrowFunc \ nextgroup=@typescriptExpression,typescriptBlock \ skipwhite skipempty -syntax match typescriptArrowFuncDef contained /\K\k*\s*=>/ - \ contains=typescriptArrowFuncArg,typescriptArrowFunc +syntax match typescriptArrowFuncDef contained /(\%(\_[^()]\+\|(\_[^()]*)\)*)\_s*=>/ + \ contains=typescriptArrowFuncArg,typescriptArrowFunc,@typescriptCallSignature \ nextgroup=@typescriptExpression,typescriptBlock \ skipwhite skipempty -" TODO: optimize this pattern -syntax region typescriptArrowFuncDef contained start=/(\_[^(^)]*):/ end=/=>/ - \ contains=typescriptArrowFuncArg,typescriptArrowFunc,typescriptTypeAnnotation +syntax region typescriptArrowFuncDef contained start=/(\%(\_[^()]\+\|(\_[^()]*)\)*):/ matchgroup=typescriptArrowFunc end=/=>/ + \ contains=typescriptArrowFuncArg,typescriptTypeAnnotation,@typescriptCallSignature \ nextgroup=@typescriptExpression,typescriptBlock \ skipwhite skipempty keepend +syntax region typescriptArrowFuncTypeParameter start=/</ end=/>/ + \ contains=@typescriptTypeParameterCluster + \ nextgroup=typescriptArrowFuncDef + \ contained skipwhite skipnl + syntax match typescriptArrowFunc /=>/ syntax match typescriptArrowFuncArg contained /\K\k*/ -syntax region typescriptArrowFuncArg contained start=/<\|(/ end=/\ze=>/ contains=@typescriptCallSignature syntax region typescriptReturnAnnotation contained start=/:/ end=/{/me=e-1 contains=@typescriptType nextgroup=typescriptBlock -syntax region typescriptFuncImpl contained start=/function\>/ end=/{/me=e-1 +syntax region typescriptFuncImpl contained start=/function\>/ end=/{\|;\|\n/me=e-1 \ contains=typescriptFuncKeyword \ nextgroup=typescriptBlock @@ -1970,7 +1987,7 @@ syntax match typescriptDecorator /@\([_$a-zA-Z][_$a-zA-Z0-9]*\.\)*[_$a-zA-Z][_$a \ nextgroup=typescriptFuncCallArg,typescriptTypeArguments \ contains=@_semantic,typescriptDotNotation -" Define the default highlighting. + hi def link typescriptReserved Error hi def link typescriptEndColons Exception @@ -2013,6 +2030,7 @@ hi def link typescriptDefault typescriptCase hi def link typescriptBranch Conditional hi def link typescriptIdentifier Structure hi def link typescriptVariable Identifier +hi def link typescriptUsing Identifier hi def link typescriptDestructureVariable PreProc hi def link typescriptEnumKeyword Identifier hi def link typescriptRepeat Repeat @@ -2050,16 +2068,13 @@ hi def link typescriptFuncKeyword Keyword hi def link typescriptAsyncFunc Keyword hi def link typescriptArrowFunc Type hi def link typescriptFuncName Function -hi def link typescriptFuncArg PreProc +hi def link typescriptFuncCallArg PreProc hi def link typescriptArrowFuncArg PreProc hi def link typescriptFuncComma Operator hi def link typescriptClassKeyword Keyword hi def link typescriptClassExtends Keyword -" hi def link typescriptClassName Function hi def link typescriptAbstract Special -" hi def link typescriptClassHeritage Function -" hi def link typescriptInterfaceHeritage Function hi def link typescriptClassStatic StorageClass hi def link typescriptReadonlyModifier Keyword hi def link typescriptInterfaceKeyword Keyword @@ -2077,6 +2092,7 @@ hi def link typescriptFuncTypeArrow Function hi def link typescriptConstructorType Function hi def link typescriptTypeQuery Keyword hi def link typescriptAccessibilityModifier Keyword +hi def link typescriptAutoAccessor Keyword hi def link typescriptOptionalMark PreProc hi def link typescriptFuncType Special hi def link typescriptMappedIn Special diff --git a/runtime/syntax/spec.vim b/runtime/syntax/spec.vim index 4cb3a343eb..730a0b8cc5 100644 --- a/runtime/syntax/spec.vim +++ b/runtime/syntax/spec.vim @@ -4,6 +4,7 @@ " Maintainer: Igor Gnatenko i.gnatenko.brain@gmail.com " Former Maintainer: Donovan Rebbechi elflord@panix.com (until March 2014) " Last Change: 2020 May 25 +" 2024 Sep 10 by Vim Project: add file triggers support, #15569 " quit when a syntax file was already loaded if exists("b:current_syntax") @@ -111,7 +112,7 @@ syn region specDescriptionArea matchgroup=specSection start='^%description' end= syn region specPackageArea matchgroup=specSection start='^%package' end='^%'me=e-1 contains=specPackageOpts,specPreAmble,specComment "%% Scripts Section %% -syn region specScriptArea matchgroup=specSection start='^%\(prep\|generate_buildrequires\|conf\|build\|install\|clean\|check\|pre\|postun\|preun\|post\|posttrans\)\>' skip='^%{\|^%\(define\|patch\d*\|configure\|GNUconfigure\|setup\|autosetup\|autopatch\|find_lang\|make_build\|makeinstall\|make_install\)\>' end='^%'me=e-1 contains=specSpecialVariables,specVariables,@specCommands,specVariables,shDo,shFor,shCaseEsac,specNoNumberHilite,specCommandOpts,shComment,shIf,specSpecialChar,specMacroIdentifier,specSectionMacroArea,specSectionMacroBracketArea,shOperator,shQuote1,shQuote2 +syn region specScriptArea matchgroup=specSection start='^%\(prep\|generate_buildrequires\|conf\|build\|install\|clean\|check\|pre\|postun\|preun\|post\|posttrans\|filetriggerin\|filetriggerun\|filetriggerpostun\|transfiletriggerin\|transfiletriggerun\|transfiletriggerpostun\)\>' skip='^%{\|^%\(define\|patch\d*\|configure\|GNUconfigure\|setup\|autosetup\|autopatch\|find_lang\|make_build\|makeinstall\|make_install\)\>' end='^%'me=e-1 contains=specSpecialVariables,specVariables,@specCommands,specVariables,shDo,shFor,shCaseEsac,specNoNumberHilite,specCommandOpts,shComment,shIf,specSpecialChar,specMacroIdentifier,specSectionMacroArea,specSectionMacroBracketArea,shOperator,shQuote1,shQuote2 "%% Changelog Section %% syn region specChangelogArea matchgroup=specSection start='^%changelog' end='^%'me=e-1 contains=specEmail,specURL,specWeekday,specMonth,specNumber,specComment,specLicense diff --git a/runtime/syntax/stylus.vim b/runtime/syntax/stylus.vim index fd0f33b65a..d8bf641e60 100644 --- a/runtime/syntax/stylus.vim +++ b/runtime/syntax/stylus.vim @@ -4,17 +4,7 @@ " Filenames: *.styl, *.stylus " Based On: Tim Pope (sass.vim) " Created: Dec 14, 2011 -" Modified: Apr 29, 2024 - -if main_syntax == "css" - syn sync minlines=10 -endif - -" let b:current_syntax = "css" -" -if main_syntax == 'css' - unlet main_syntax -endif +" Modified: May 28, 2024 syn case ignore diff --git a/runtime/syntax/sudoers.vim b/runtime/syntax/sudoers.vim index bf2d337d9e..4cdf598be0 100644 --- a/runtime/syntax/sudoers.vim +++ b/runtime/syntax/sudoers.vim @@ -2,9 +2,10 @@ " Language: sudoers(5) configuration files " Maintainer: Eisuke Kawashima ( e.kawaschima+vim AT gmail.com ) " Previous Maintainer: Nikolai Weibull <now@bitwi.se> -" Latest Revision: 2021 Mar 15 +" Latest Revision: 2024 Sep 02 " Recent Changes: Support for #include and #includedir. " Added many new options (Samuel D. Leslie) +" Update allowed Tag_Spec Runas_Spec syntax items if exists("b:current_syntax") finish @@ -22,7 +23,7 @@ syn match sudoersUserSpec '^' nextgroup=@sudoersUserInSpec skipwhite syn match sudoersSpecEquals contained '=' nextgroup=@sudoersCmndSpecList skipwhite -syn cluster sudoersCmndSpecList contains=sudoersUserRunasBegin,sudoersPASSWD,@sudoersCmndInSpec +syn cluster sudoersCmndSpecList contains=sudoersUserRunasBegin,sudoersTagSpec,@sudoersCmndInSpec syn keyword sudoersTodo contained TODO FIXME XXX NOTE @@ -92,10 +93,11 @@ syn cluster sudoersUserList contains=sudoersUserListComma,sudoersUserLis syn match sudoersUserSpecComma contained ',' nextgroup=@sudoersUserInSpec skipwhite skipnl syn cluster sudoersUserSpec contains=sudoersUserSpecComma,@sudoersHostInSpec -syn match sudoersUserRunasBegin contained '(' nextgroup=@sudoersUserInRunas skipwhite skipnl +syn match sudoersUserRunasBegin contained '(' nextgroup=@sudoersUserInRunas,sudoersUserRunasColon skipwhite skipnl syn match sudoersUserRunasComma contained ',' nextgroup=@sudoersUserInRunas skipwhite skipnl -syn match sudoersUserRunasEnd contained ')' nextgroup=sudoersPASSWD,@sudoersCmndInSpec skipwhite skipnl -syn cluster sudoersUserRunas contains=sudoersUserRunasComma,@sudoersUserInRunas,sudoersUserRunasEnd +syn match sudoersUserRunasColon contained ':' nextgroup=@sudoersUserInRunas skipwhite skipnl +syn match sudoersUserRunasEnd contained ')' nextgroup=sudoersTagSpec,@sudoersCmndInSpec skipwhite skipnl +syn cluster sudoersUserRunas contains=sudoersUserRunasComma,sudoersUserRunasColon,@sudoersUserInRunas,sudoersUserRunasEnd syn match sudoersHostAliasEquals contained '=' nextgroup=@sudoersHostInList skipwhite skipnl @@ -291,7 +293,7 @@ syn region sudoersStringValue contained start=+"+ skip=+\\"+ end=+"+ nextgroup syn match sudoersListValue contained '[^[:space:],:=\\]*\%(\\[[:space:],:=\\][^[:space:],:=\\]*\)*' nextgroup=sudoersParameterListComma skipwhite skipnl syn region sudoersListValue contained start=+"+ skip=+\\"+ end=+"+ nextgroup=sudoersParameterListComma skipwhite skipnl -syn match sudoersPASSWD contained '\%(NO\)\=PASSWD:' nextgroup=@sudoersCmndInSpec skipwhite +syn match sudoersTagSpec contained '\%(NO\)\=\%(EXEC\|FOLLOW\|LOG_\%(INPUT\|OUTPUT\)\|MAIL\|INTERCEPT\|PASSWD\|SETENV\):' nextgroup=sudoersTagSpec,@sudoersCmndInSpec skipwhite hi def link sudoersSpecEquals Operator hi def link sudoersTodo Todo @@ -345,6 +347,7 @@ hi def link sudoersUserListColon Delimiter hi def link sudoersUserSpecComma Delimiter hi def link sudoersUserRunasBegin Delimiter hi def link sudoersUserRunasComma Delimiter +hi def link sudoersUserRunasColon Delimiter hi def link sudoersUserRunasEnd Delimiter hi def link sudoersHostAliasEquals Operator hi def link sudoersHostListComma Delimiter @@ -381,7 +384,7 @@ hi def link sudoersListParameterEquals Operator hi def link sudoersIntegerValue Number hi def link sudoersStringValue String hi def link sudoersListValue String -hi def link sudoersPASSWD Special +hi def link sudoersTagSpec Special hi def link sudoersInclude Statement let b:current_syntax = "sudoers" diff --git a/runtime/syntax/swayconfig.vim b/runtime/syntax/swayconfig.vim index 401412adfd..d09d476a5a 100644 --- a/runtime/syntax/swayconfig.vim +++ b/runtime/syntax/swayconfig.vim @@ -2,8 +2,8 @@ " Language: sway config file " Original Author: Josef Litos (JosefLitos/i3config.vim) " Maintainer: James Eapen <james.eapen@vai.org> -" Version: 1.2.3 -" Last Change: 2024-05-23 +" Version: 1.2.4 +" Last Change: 2024-05-24 " References: " http://i3wm.org/docs/userguide.html#configuring @@ -34,12 +34,12 @@ syn region i3ConfigBindArgument start=/--input-device=['"]/ end=/\s/ contained c syn region i3ConfigBindCombo matchgroup=i3ConfigParen start=/{$/ end=/^\s*}$/ contained contains=i3ConfigBindArgument,i3ConfigBindCombo,i3ConfigComment fold keepend extend " hack for blocks with start outside parsing range -syn region swayConfigBlockOrphan start=/^\s\+\(--[a-z-]\+ \)*\([A-Z$][$a-zA-Z0-9_+]\+\|[a-z]\) [a-z[]/ skip=/\\$\|$\n^\s*}$/ end=/$/ contains=i3ConfigBindArgument,i3ConfigBindCombo,i3ConfigParen keepend extend +syn region swayConfigBlockOrphan start=/^\s\+\(--[a-z-]\+ \)*\([$A-Z][$0-9A-Za-z_+]\+\|[a-z]\) [a-z[]/ skip=/\\$\|$\n^\s*}$/ end=/$/ contains=i3ConfigBindArgument,i3ConfigBindCombo,i3ConfigParen keepend extend syn region i3ConfigExec start=/ {$/ end=/^\s*}$/ contained contains=i3ConfigExecAction,@i3ConfigSh,i3ConfigComment fold keepend extend syn keyword swayConfigFloatingModifierOpts normal inverse none contained -syn match i3ConfigKeyword /floating_modifier \(none\|[$a-zA-Z0-9+]\+ \(normal\|inverse\)\)$/ contained contains=i3ConfigVariable,i3ConfigBindModkey,swayConfigFloatingModifierOpts +syn match i3ConfigKeyword /floating_modifier \(none\|[$A-Z][0-9A-Za-z]\+ \(normal\|inverse\)\)$/ contained contains=i3ConfigVariable,i3ConfigBindModkey,swayConfigFloatingModifierOpts syn match swayConfigI3Param /--i3/ contains=i3ConfigShParam skipwhite nextgroup=i3ConfigEdgeOpts syn keyword i3ConfigKeyword hide_edge_borders contained skipwhite nextgroup=swayConfigI3Param,i3ConfigEdgeOpts @@ -71,7 +71,7 @@ syn keyword i3ConfigBindKeyword bindswitch contained skipwhite nextgroup=swayCon syn region swayConfigBlockOrphan start=/^\s\+\(lid\|tablet\):/ skip=/\\$\|$\n^\s*}$/ end=/$/ contains=swayConfigBindswitchArgument,swayConfigBindswitchType,i3ConfigParen keepend extend " Bindgesture -syn match swayConfigBindgestureArgument /--\(exact\|input-device=[:0-9a-zA-Z_/-]\+\|no-warn\) / contained nextgroup=swayConfigBindgestureArgument,swayConfigBindgestureCombo +syn match swayConfigBindgestureArgument /--\(exact\|input-device=[:0-9A-Za-z_/-]\+\|no-warn\) / contained nextgroup=swayConfigBindgestureArgument,swayConfigBindgestureCombo syn keyword swayConfigBindgestureType hold swipe pinch contained syn keyword swayConfigBindgestureDir up down left right inward outward clockwise counterclockwise contained syn match swayConfigBindgestureCombo /\(hold\(:[1-5]\)\?\|swipe\(:[3-5]\)\?\(:up\|:down\|:left\|:right\)\?\|pinch\(:[2-5]\)\?:\(+\?\(inward\|outward\|clockwise\|counterclockwise\|up\|down\|left\|right\)\)\+\) / contained contains=i3ConfigNumber,swayConfigBindgestureType,i3ConfigColonOperator,swayConfigBindgestureDir,i3ConfigBindModifier nextgroup=swayConfigBindgestureCombo,i3ConfigBind diff --git a/runtime/syntax/terraform.vim b/runtime/syntax/terraform.vim new file mode 100644 index 0000000000..559dc79568 --- /dev/null +++ b/runtime/syntax/terraform.vim @@ -0,0 +1,17 @@ +" Vim syntax file +" Language: Terraform +" Maintainer: Gregory Anders +" Upstream: https://github.com/hashivim/vim-terraform +" Last Change: 2024-09-03 + +if exists('b:current_syntax') + finish +endif + +runtime! syntax/hcl.vim + +syn keyword terraType string bool number object tuple list map set any + +hi def link terraType Type + +let b:current_syntax = 'terraform' diff --git a/runtime/syntax/thrift.vim b/runtime/syntax/thrift.vim new file mode 100644 index 0000000000..502e98852a --- /dev/null +++ b/runtime/syntax/thrift.vim @@ -0,0 +1,74 @@ +" Vim syntax file +" Language: Thrift +" Original Author: Martin Smith <martin@facebook.com> +" Maintainer: Yinzuo Jiang <jiangyinzuo@foxmail.com> +" Last Change: 2024/07/29 +" https://github.com/apache/thrift/blob/master/contrib/thrift.vim +" +" Licensed to the Apache Software Foundation (ASF) under one +" or more contributor license agreements. See the NOTICE file +" distributed with this work for additional information +" regarding copyright ownership. The ASF licenses this file +" to you under the Apache License, Version 2.0 (the +" "License"); you may not use this file except in compliance +" with the License. You may obtain a copy of the License at +" +" http://www.apache.org/licenses/LICENSE-2.0 +" +" Unless required by applicable law or agreed to in writing, +" software distributed under the License is distributed on an +" "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +" KIND, either express or implied. See the License for the +" specific language governing permissions and limitations +" under the License. +" + +if exists("b:current_syntax") + finish +endif + +" Todo +syn keyword thriftTodo TODO todo FIXME fixme XXX xxx contained + +" Comments +syn match thriftComment "#.*" contains=thriftTodo +syn region thriftComment start="/\*" end="\*/" contains=thriftTodo +syn match thriftComment "//.\{-}\(?>\|$\)\@=" + +" String +syn region thriftStringDouble matchgroup=None start=+"+ end=+"+ + +" Number +syn match thriftNumber "-\=\<\d\+\>" contained + +" Keywords +syn keyword thriftKeyword namespace +syn keyword thriftKeyword xsd_all xsd_optional xsd_nillable xsd_attrs +syn keyword thriftKeyword include cpp_include cpp_type const optional required +syn keyword thriftBasicTypes void bool byte i8 i16 i32 i64 double string binary +syn keyword thriftStructure map list set struct typedef exception enum throws union + +" Special +syn match thriftSpecial "\d\+:" + +" Structure +syn keyword thriftStructure service oneway extends +"async" { return tok_async; } +"exception" { return tok_xception; } +"extends" { return tok_extends; } +"throws" { return tok_throws; } +"service" { return tok_service; } +"enum" { return tok_enum; } +"const" { return tok_const; } + +hi def link thriftComment Comment +hi def link thriftKeyword Special +hi def link thriftBasicTypes Type +hi def link thriftStructure StorageClass +hi def link thriftTodo Todo +hi def link thriftString String +hi def link thriftNumber Number +hi def link thriftSpecial Special +hi def link thriftStructure Structure + +let b:current_syntax = "thrift" diff --git a/runtime/syntax/tmux.vim b/runtime/syntax/tmux.vim index 9766ed55d7..4b8454dd51 100644 --- a/runtime/syntax/tmux.vim +++ b/runtime/syntax/tmux.vim @@ -1,5 +1,5 @@ " Language: tmux(1) configuration file -" Version: 3.4 (git-608d1134) +" Version: 3.4 (git-3d8ead8a) " URL: https://github.com/ericpruitt/tmux.vim/ " Maintainer: Eric Pruitt <eric.pruitt@gmail.com> " License: 2-Clause BSD (http://opensource.org/licenses/BSD-2-Clause) @@ -28,7 +28,7 @@ syn match tmuxKey /\(C-\|M-\|\^\)\+\S\+/ display syn match tmuxNumber /\<\d\+\>/ display syn match tmuxFlags /\s-\a\+/ display syn match tmuxVariableExpansion /\$\({[A-Za-z_]\w*}\|[A-Za-z_]\w*\)/ display -syn match tmuxControl /\(^\|\s\)%\(if\|elif\|else\|endif\)\($\|\s\)/ display +syn match tmuxControl /\(^\|\s\)%\(if\|elif\|else\|endif\|hidden\)\($\|\s\)/ display syn match tmuxEscape /\\\(u\x\{4\}\|U\x\{8\}\|\o\{3\}\|[\\ernt$]\)/ display " Missing closing bracket. @@ -37,7 +37,7 @@ syn match tmuxInvalidVariableExpansion /\${[^}]*$/ display syn match tmuxInvalidVariableExpansion /\${[^A-Za-z_][^}]*}/ display syn match tmuxInvalidVariableExpansion /\$[^A-Za-z_{ \t]/ display " Contains invalid character. -syn match tmuxInvalidVariableExpansion /\${[^}]*[^A-Za-z0-9_][^}]*}/ display +syn match tmuxInvalidVariableExpansion /\${[^}]*[^A-Za-z0-9_}][^}]*}/ display syn region tmuxComment start=/#/ skip=/\\\@<!\\$/ end=/$/ contains=tmuxTodo,@Spell @@ -99,11 +99,11 @@ syn keyword tmuxOptions \ after-set-environment after-set-hook after-set-option after-show-environment \ after-show-messages after-show-options after-split-window after-unbind-key \ aggressive-resize alert-activity alert-bell alert-silence allow-passthrough -\ allow-rename alternate-screen assume-paste-time automatic-rename -\ automatic-rename-format backspace base-index bell-action buffer-limit -\ client-active client-attached client-detached client-focus-in +\ allow-rename allow-set-title alternate-screen assume-paste-time +\ automatic-rename automatic-rename-format backspace base-index bell-action +\ buffer-limit client-active client-attached client-detached client-focus-in \ client-focus-out client-resized client-session-changed clock-mode-color -\ clock-mode-colour clock-mode-style command-alias copy-command +\ clock-mode-colour clock-mode-style command-alias command-error copy-command \ copy-mode-current-match-style copy-mode-mark-style copy-mode-match-style \ cursor-color cursor-colour cursor-style default-command default-shell \ default-size default-terminal destroy-unattached detach-on-destroy diff --git a/runtime/syntax/tsv.vim b/runtime/syntax/tsv.vim new file mode 100644 index 0000000000..f0dd9f717d --- /dev/null +++ b/runtime/syntax/tsv.vim @@ -0,0 +1,12 @@ +" Vim filetype plugin file +" Language: Tab separated values (TSV) +" Last Change: 2024 Jul 16 +" This runtime file is looking for a new maintainer. + +if exists('b:current_syntax') + finish +endif + +let b:csv_delimiter = '\t' " enforce tab delimiter +runtime! syntax/csv.vim +let b:current_syntax = 'tsv' diff --git a/runtime/syntax/typescript.vim b/runtime/syntax/typescript.vim index 5389c21497..03520fd56a 100644 --- a/runtime/syntax/typescript.vim +++ b/runtime/syntax/typescript.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: TypeScript " Maintainer: Herrington Darkholme -" Last Change: 2023 Aug 13 +" Last Change: 2024 May 24 " Based On: Herrington Darkholme's yats.vim " Changes: Go to https://github.com/HerringtonDarkholme/yats.vim for recent changes. " Origin: https://github.com/othree/yajs diff --git a/runtime/syntax/typescriptreact.vim b/runtime/syntax/typescriptreact.vim index 1c510459f5..061ec4d81e 100644 --- a/runtime/syntax/typescriptreact.vim +++ b/runtime/syntax/typescriptreact.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: TypeScript with React (JSX) " Maintainer: The Vim Project <https://github.com/vim/vim> -" Last Change: 2023 Aug 13 +" Last Change: 2024 May 26 " Based On: Herrington Darkholme's yats.vim " Changes: See https://github.com/HerringtonDarkholme/yats.vim " Credits: See yats.vim on github @@ -118,13 +118,14 @@ syntax match tsxEqual +=+ display contained " <tag id="sample"> " s~~~~~~e -syntax region tsxString contained start=+"+ end=+"+ contains=tsxEntity,@Spell display +syntax region tsxString contained start=+"+ skip=+\\"+ end=+"+ contains=tsxEntity,@Spell display +syntax region tsxString contained start=+'+ skip=+\\'+ end=+'+ contains=tsxEntity,@Spell display " <tag key={this.props.key}> " s~~~~~~~~~~~~~~e syntax region tsxEscJs \ contained - \ contains=@typescriptValue,@tsxComment + \ contains=@typescriptValue,@tsxComment,typescriptObjectSpread \ matchgroup=typescriptBraces \ start=+{+ \ end=+}+ diff --git a/runtime/syntax/typst.vim b/runtime/syntax/typst.vim new file mode 100644 index 0000000000..82fdadb3d5 --- /dev/null +++ b/runtime/syntax/typst.vim @@ -0,0 +1,472 @@ +" Vim syntax file +" Language: Typst +" Maintainer: Gregory Anders <greg@gpanders.com> +" Last Change: 2024-07-14 +" Based on: https://github.com/kaarmu/typst.vim + +if exists('b:current_syntax') + finish +endif + +syntax sync fromstart +syntax spell toplevel + +" Common {{{1 +syntax cluster typstCommon + \ contains=@typstComment + +" Common > Comment {{{2 +syntax cluster typstComment + \ contains=typstCommentBlock,typstCommentLine +syntax match typstCommentBlock + \ #/\*\%(\_.\{-}\)\*/# + \ contains=typstCommentTodo,@Spell +syntax match typstCommentLine + \ #//.*# + \ contains=typstCommentTodo,@Spell +syntax keyword typstCommentTodo + \ contained + \ TODO FIXME XXX TBD + + +" Code {{{1 +syntax cluster typstCode + \ contains=@typstCommon + \ ,@typstCodeKeywords + \ ,@typstCodeConstants + \ ,@typstCodeIdentifiers + \ ,@typstCodeFunctions + \ ,@typstCodeParens + +" Code > Keywords {{{2 +syntax cluster typstCodeKeywords + \ contains=typstCodeConditional + \ ,typstCodeRepeat + \ ,typstCodeKeyword + \ ,typstCodeStatement +syntax keyword typstCodeConditional + \ contained + \ if else +syntax keyword typstCodeRepeat + \ contained + \ while for +syntax keyword typstCodeKeyword + \ contained + \ not in and or return +syntax region typstCodeStatement + \ contained + \ matchgroup=typstCodeStatementWord start=/\v(let|set|import|include)>/ + \ matchgroup=Noise end=/\v%(;|$)/ + \ contains=@typstCode +syntax region typstCodeStatement + \ contained + \ matchgroup=typstCodeStatementWord start=/show/ + \ matchgroup=Noise end=/\v%(:|$)/ keepend + \ contains=@typstCode + \ skipwhite nextgroup=@typstCode,typstCodeShowRocket +syntax match typstCodeShowRocket + \ contained + \ /.*=>/ + \ contains=@typstCode + \ skipwhite nextgroup=@typstCode + +" Code > Identifiers {{{2 +syntax cluster typstCodeIdentifiers + \ contains=typstCodeIdentifier + \ ,typstCodeFieldAccess +syntax match typstCodeIdentifier + \ contained + \ /\v\w\k*>(<%(let|set|show|import|include))@<![\.\[\(]@!/ +syntax match typstCodeFieldAccess + \ contained + \ /\v\w\k*>(<%(let|set|show|import|include))@<!\.[\[\(]@!/ + \ nextgroup=typstCodeFieldAccess,typstCodeFunction + +" Code > Functions {{{2 +syntax cluster typstCodeFunctions + \ contains=typstCodeFunction +syntax match typstCodeFunction + \ contained + \ /\v\w\k*>(<%(let|set|show|import|include))@<![\(\[]@=/ + \ nextgroup=typstCodeFunctionArgument +syntax match typstCodeFunctionArgument + \ contained + \ /\v%(%(\(.{-}\)|\[.{-}\]|\{.{-}\}))*/ transparent + \ contains=@typstCode + +" Code > Constants {{{2 +syntax cluster typstCodeConstants + \ contains=typstCodeConstant + \ ,typstCodeNumberInteger + \ ,typstCodeNumberFloat + \ ,typstCodeNumberLength + \ ,typstCodeNumberAngle + \ ,typstCodeNumberRatio + \ ,typstCodeNumberFraction + \ ,typstCodeString + \ ,typstCodeLabel +syntax match typstCodeConstant + \ contained + \ /\v<%(none|auto|true|false)-@!>/ +syntax match typstCodeNumberInteger + \ contained + \ /\v<\d+>/ + +syntax match typstCodeNumberFloat + \ contained + \ /\v<\d+\.\d*>/ +syntax match typstCodeNumberLength + \ contained + \ /\v<\d+(\.\d*)?(pt|mm|cm|in|em)>/ +syntax match typstCodeNumberAngle + \ contained + \ /\v<\d+(\.\d*)?(deg|rad)>/ +syntax match typstCodeNumberRatio + \ contained + \ /\v<\d+(\.\d*)?\%/ +syntax match typstCodeNumberFraction + \ contained + \ /\v<\d+(\.\d*)?fr>/ +syntax region typstCodeString + \ contained + \ start=/"/ skip=/\v\\\\|\\"/ end=/"/ + \ contains=@Spell +syntax match typstCodeLabel + \ contained + \ /\v\<\K%(\k*-*)*\>/ + +" Code > Parens {{{2 +syntax cluster typstCodeParens + \ contains=typstCodeParen + \ ,typstCodeBrace + \ ,typstCodeBracket + \ ,typstCodeDollar + \ ,typstMarkupRawInline + \ ,typstMarkupRawBlock +syntax region typstCodeParen + \ contained + \ matchgroup=Noise start=/(/ end=/)/ + \ contains=@typstCode +syntax region typstCodeBrace + \ contained + \ matchgroup=Noise start=/{/ end=/}/ + \ contains=@typstCode +syntax region typstCodeBracket + \ contained + \ matchgroup=Noise start=/\[/ end=/\]/ + \ contains=@typstMarkup +syntax region typstCodeDollar + \ contained + \ matchgroup=Number start=/\\\@<!\$/ end=/\\\@<!\$/ + \ contains=@typstMath + + +" Hashtag {{{1 +syntax cluster typstHashtag + \ contains=@typstHashtagKeywords + \ ,@typstHashtagConstants + \ ,@typstHashtagIdentifiers + \ ,@typstHashtagFunctions + \ ,@typstHashtagParens + +" Hashtag > Keywords {{{2 +syntax cluster typstHashtagKeywords + \ contains=typstHashtagConditional + \ ,typstHashtagRepeat + \ ,typstHashtagKeywords + \ ,typstHashtagStatement + +" syntax match typstHashtagControlFlowError +" \ /\v#%(if|while|for)>-@!.{-}$\_.{-}%(\{|\[|\()/ +syntax match typstHashtagControlFlow + \ /\v#%(if|while|for)>.{-}\ze%(\{|\[|\()/ + \ contains=typstHashtagConditional,typstHashtagRepeat + \ nextgroup=@typstCode +syntax region typstHashtagConditional + \ contained + \ start=/\v#if>/ end=/\v\ze(\{|\[)/ + \ contains=@typstCode +syntax region typstHashtagRepeat + \ contained + \ start=/\v#(while|for)>/ end=/\v\ze(\{|\[)/ + \ contains=@typstCode +syntax match typstHashtagKeyword + \ /\v#(return)>/ + \ skipwhite nextgroup=@typstCode +syntax region typstHashtagStatement + \ matchgroup=typstHashtagStatementWord start=/\v#(let|set|import|include)>/ + \ matchgroup=Noise end=/\v%(;|$)/ + \ contains=@typstCode +syntax region typstHashtagStatement + \ matchgroup=typstHashtagStatementWord start=/#show/ + \ matchgroup=Noise end=/\v%(:|$)/ keepend + \ contains=@typstCode + \ skipwhite nextgroup=@typstCode,typstCodeShowRocket + +" Hashtag > Constants {{{2 +syntax cluster typstHashtagConstants + \ contains=typstHashtagConstant +syntax match typstHashtagConstant + \ /\v#(none|auto|true|false)>/ + +" Hashtag > Identifiers {{{2 +syntax cluster typstHashtagIdentifiers + \ contains=typstHashtagIdentifier + \ ,typstHashtagFieldAccess +syntax match typstHashtagIdentifier + \ /\v#\w\k*>(<%(let|set|show|import|include))@<![\.\[\(]@!/ +syntax match typstHashtagFieldAccess + \ /\v#\w\k*>(<%(let|set|show|import|include))@<!\.[\[\(]@!/ + \ nextgroup=typstCodeFieldAccess,typstCodeFunction + +" Hashtag > Functions {{{2 +syntax cluster typstHashtagFunctions + \ contains=typstHashtagFunction +syntax match typstHashtagFunction + \ /\v#\w\k*>(<%(let|set|show|import|include))@<![\(\[]@=/ + \ nextgroup=typstCodeFunctionArgument + +" Hashtag > Parens {{{2 +syntax cluster typstHashtagParens + \ contains=typstHashtagParen + \ ,typstHashtagBrace + \ ,typstHashtagBracket + \ ,typstHashtagDollar +syntax region typstHashtagParen + \ matchgroup=Noise start=/#(/ end=/)/ + \ contains=@typstCode +syntax region typstHashtagBrace + \ matchgroup=Noise start=/#{/ end=/}/ + \ contains=@typstCode +syntax region typstHashtagBracket + \ matchgroup=Noise start=/#\[/ end=/\]/ + \ contains=@typstMarkup +syntax region typstHashtagDollar + \ matchgroup=Noise start=/#\$/ end=/\\\@<!\$/ + \ contains=@typstMath + + +" Markup {{{1 +syntax cluster typstMarkup + \ contains=@typstCommon + \ ,@Spell + \ ,@typstHashtag + \ ,@typstMarkupText + \ ,@typstMarkupParens + +" Markup > Text {{{2 +syntax cluster typstMarkupText + \ contains=typstMarkupRawInline + \ ,typstMarkupRawBlock + \ ,typstMarkupLabel + \ ,typstMarkupReference + \ ,typstMarkupUrl + \ ,typstMarkupHeading + \ ,typstMarkupBulletList + \ ,typstMarkupEnumList + \ ,typstMarkupTermList + \ ,typstMarkupBold + \ ,typstMarkupItalic + \ ,typstMarkupLinebreak + \ ,typstMarkupNonbreakingSpace + \ ,typstMarkupShy + \ ,typstMarkupDash + \ ,typstMarkupEllipsis + +" Raw Text +syntax match typstMarkupRawInline + \ /`.\{-}`/ +syntax region typstMarkupRawBlock + \ matchgroup=Macro start=/```\w*/ + \ matchgroup=Macro end=/```/ keepend +syntax region typstMarkupCodeBlockTypst + \ matchgroup=Macro start=/```typst/ + \ matchgroup=Macro end=/```/ contains=@typstCode keepend + \ concealends + +for s:name in get(g:, 'typst_embedded_languages', []) + let s:include = ['syntax include' + \ ,'@typstEmbedded_'..s:name + \ ,'syntax/'..s:name..'.vim'] + let s:rule = ['syn region' + \,s:name + \,'matchgroup=Macro' + \,'start=/```'..s:name..'\>/ end=/```/' + \,'contains=@typstEmbedded_'..s:name + \,'keepend' + \,'concealends'] + execute 'silent! ' .. join(s:include, ' ') + unlet! b:current_syntax + execute join(s:rule, ' ') +endfor + +" Label & Reference +syntax match typstMarkupLabel + \ /\v\<\K%(\k*-*)*\>/ +syntax match typstMarkupReference + \ /\v\@\K%(\k*-*)*/ + +" URL +syntax match typstMarkupUrl + \ #\v\w+://\S*# + +" Heading +syntax match typstMarkupHeading + \ /^\s*\zs=\{1,6}\s.*$/ + \ contains=typstMarkupLabel,@Spell + +" Lists +syntax match typstMarkupBulletList + \ /\v^\s*-\s+/ +syntax match typstMarkupEnumList + \ /\v^\s*(\+|\d+\.)\s+/ +syntax region typstMarkupTermList + \ oneline start=/\v^\s*\/\s/ end=/:/ + \ contains=@typstMarkup + +" Bold & Italic +syntax match typstMarkupBold + \ /\v(\w|\\)@1<!\*\S@=.{-}(\n.{-1,})*\S@1<=\\@1<!\*/ + \ contains=typstMarkupBoldRegion +syntax match typstMarkupItalic + \ /\v(\w|\\)@1<!_\S@=.{-}(\n.{-1,})*\S@1<=\\@1<!_/ + \ contains=typstMarkupItalicRegion +syntax match typstMarkupBoldItalic + \ contained + \ /\v(\w|\\)@1<![_\*]\S@=.{-}(\n.{-1,})*\S@1<=\\@1<!\2/ + \ contains=typstMarkupBoldRegion,typstMarkupItalicRegion +syntax region typstMarkupBoldRegion + \ contained + \ transparent matchgroup=typstMarkupBold + \ start=/\(^\|[^0-9a-zA-Z]\)\@<=\*/ end=/\*\($\|[^0-9a-zA-Z]\)\@=/ + \ concealends contains=typstMarkupBoldItalic,typstMarkupLabel,@Spell +syntax region typstMarkupItalicRegion + \ contained + \ transparent matchgroup=typstMarkupItalic + \ start=/\(^\|[^0-9a-zA-Z]\)\@<=_/ end=/_\($\|[^0-9a-zA-Z]\)\@=/ + \ concealends contains=typstMarkupBoldItalic,typstMarkupLabel,@Spell + +" Linebreak & Special Whitespace +syntax match typstMarkupLinebreak + \ /\\\\/ +syntax match typstMarkupNonbreakingSpace + \ /\~/ +syntax match typstMarkupShy + \ /-?/ + +" Special Symbols +syntax match typstMarkupDash + \ /-\{2,3}/ +syntax match typstMarkupEllipsis + \ /\.\.\./ + +" Markup > Parens {{{2 +syntax cluster typstMarkupParens + \ contains=typstMarkupBracket + \ ,typstMarkupDollar +syntax region typstMarkupBracket + \ matchgroup=Noise start=/\[/ end=/\]/ + \ contains=@typstMarkup +syntax region typstMarkupDollar + \ matchgroup=Special start=/\\\@<!\$/ end=/\\\@<!\$/ + \ contains=@typstMath + + +" Math {{{1 +syntax cluster typstMath + \ contains=@typstCommon + \ ,@typstHashtag + \ ,typstMathIdentifier + \ ,typstMathFunction + \ ,typstMathNumber + \ ,typstMathSymbol + \ ,typstMathBold + \ ,typstMathScripts + \ ,typstMathQuote + +syntax match typstMathIdentifier + \ /\a\a\+/ + \ contained +syntax match typstMathFunction + \ /\a\a\+\ze(/ + \ contained +syntax match typstMathNumber + \ /\<\d\+\>/ + \ contained +syntax region typstMathQuote + \ matchgroup=String start=/"/ skip=/\\"/ end=/"/ + \ contained + +" Math > Linked groups {{{2 +highlight default link typstMathIdentifier Identifier +highlight default link typstMathFunction Statement +highlight default link typstMathNumber Number +highlight default link typstMathSymbol Statement + +" Highlighting {{{1 + +" Highlighting > Linked groups {{{2 +highlight default link typstCommentBlock Comment +highlight default link typstCommentLine Comment +highlight default link typstCommentTodo Todo +highlight default link typstCodeConditional Conditional +highlight default link typstCodeRepeat Repeat +highlight default link typstCodeKeyword Keyword +highlight default link typstCodeConstant Constant +highlight default link typstCodeNumberInteger Number +highlight default link typstCodeNumberFloat Number +highlight default link typstCodeNumberLength Number +highlight default link typstCodeNumberAngle Number +highlight default link typstCodeNumberRatio Number +highlight default link typstCodeNumberFraction Number +highlight default link typstCodeString String +highlight default link typstCodeLabel Structure +highlight default link typstCodeStatementWord Statement +highlight default link typstCodeIdentifier Identifier +highlight default link typstCodeFieldAccess Identifier +highlight default link typstCodeFunction Function +highlight default link typstCodeParen Noise +highlight default link typstCodeBrace Noise +highlight default link typstCodeBracket Noise +highlight default link typstCodeDollar Noise +" highlight default link typstHashtagControlFlowError Error +highlight default link typstHashtagConditional Conditional +highlight default link typstHashtagRepeat Repeat +highlight default link typstHashtagKeyword Keyword +highlight default link typstHashtagConstant Constant +highlight default link typstHashtagStatementWord Statement +highlight default link typstHashtagIdentifier Identifier +highlight default link typstHashtagFieldAccess Identifier +highlight default link typstHashtagFunction Function +highlight default link typstHashtagParen Noise +highlight default link typstHashtagBrace Noise +highlight default link typstHashtagBracket Noise +highlight default link typstHashtagDollar Noise +highlight default link typstMarkupRawInline Macro +highlight default link typstMarkupRawBlock Macro +highlight default link typstMarkupLabel Structure +highlight default link typstMarkupReference Structure +highlight default link typstMarkupBulletList Structure +" highlight default link typstMarkupItalicError Error +" highlight default link typstMarkupBoldError Error +highlight default link typstMarkupEnumList Structure +highlight default link typstMarkupLinebreak Structure +highlight default link typstMarkupNonbreakingSpace Structure +highlight default link typstMarkupShy Structure +highlight default link typstMarkupDash Structure +highlight default link typstMarkupEllipsis Structure +highlight default link typstMarkupTermList Structure +highlight default link typstMarkupDollar Noise + +" Highlighting > Custom Styling {{{2 +highlight! Conceal ctermfg=NONE ctermbg=NONE guifg=NONE guibg=NONE + +highlight default typstMarkupHeading term=underline,bold cterm=underline,bold gui=underline,bold +highlight default typstMarkupUrl term=underline cterm=underline gui=underline +highlight default typstMarkupBold term=bold cterm=bold gui=bold +highlight default typstMarkupItalic term=italic cterm=italic gui=italic +highlight default typstMarkupBoldItalic term=bold,italic cterm=bold,italic gui=bold,italic + +let b:current_syntax = 'typst' + +" }}}1 diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim index 4fc640bab1..9073c6e7bf 100644 --- a/runtime/syntax/vim.vim +++ b/runtime/syntax/vim.vim @@ -36,8 +36,8 @@ syn keyword vimOnlyOption contained nobiosk nobioskey noconsk noconskey nocp noc " Invertible setting variants syn keyword vimOnlyOption contained invbiosk invbioskey invconsk invconskey invcp invcompatible invguipty invmacatsui invsn invshortname invta invtextauto invtx invtextmode invtf invttyfast invtbi invttybuiltin invwiv invweirdinvert " termcap codes (which can also be set) {{{2 -" GEN_SYN_VIM: vimOption term output code, START_STR='syn keyword vimOption contained', END_STR='' -syn keyword vimOption contained t_AB t_AF t_AU t_AL t_al t_bc t_BE t_BD t_cd t_ce t_Ce t_CF t_cl t_cm t_Co t_CS t_Cs t_cs t_CV t_da t_db t_DL t_dl t_ds t_Ds t_EC t_EI t_fs t_fd t_fe t_GP t_IE t_IS t_ke t_ks t_le t_mb t_md t_me t_mr t_ms t_nd t_op t_RF t_RB t_RC t_RI t_Ri t_RK t_RS t_RT t_RV t_Sb t_SC t_se t_Sf t_SH t_SI t_Si t_so t_SR t_sr t_ST t_Te t_te t_TE t_ti t_TI t_Ts t_ts t_u7 t_ue t_us t_Us t_ut t_vb t_ve t_vi t_VS t_vs t_WP t_WS t_XM t_xn t_xs t_ZH t_ZR t_8f t_8b t_8u +" GEN_SYN_VIM: vimOption term output code, START_STR='syn keyword vimOption contained', END_STR='skipwhite nextgroup=vimSetEqual,vimSetMod' +syn keyword vimOption contained t_AB t_AF t_AU t_AL t_al t_bc t_BE t_BD t_cd t_ce t_Ce t_CF t_cl t_cm t_Co t_CS t_Cs t_cs t_CV t_da t_db t_DL t_dl t_ds t_Ds t_EC t_EI t_fs t_fd t_fe t_GP t_IE t_IS t_ke t_ks t_le t_mb t_md t_me t_mr t_ms t_nd t_op t_RF t_RB t_RC t_RI t_Ri t_RK t_RS t_RT t_RV t_Sb t_SC t_se t_Sf t_SH t_SI t_Si t_so t_SR t_sr t_ST t_Te t_te t_TE t_ti t_TI t_Ts t_ts t_u7 t_ue t_us t_Us t_ut t_vb t_ve t_vi t_VS t_vs t_WP t_WS t_XM t_xn t_xs t_ZH t_ZR t_8f t_8b t_8u t_xo skipwhite nextgroup=vimSetEqual,vimSetMod " term key codes syn keyword vimOption contained t_F1 t_F2 t_F3 t_F4 t_F5 t_F6 t_F7 t_F8 t_F9 t_k1 t_K1 t_k2 t_k3 t_K3 t_k4 t_K4 t_k5 t_K5 t_k6 t_K6 t_k7 t_K7 t_k8 t_K8 t_k9 t_K9 t_KA t_kb t_kB t_KB t_KC t_kd t_kD t_KD t_KE t_KF t_KG t_kh t_KH t_kI t_KI t_KJ t_KK t_kl t_KL t_kN t_kP t_kr t_ku syn match vimTermOption contained "t_%1" @@ -60,15 +60,20 @@ syn case ignore syn keyword vimGroup contained Comment Constant String Character Number Boolean Float Identifier Function Statement Conditional Repeat Label Operator Keyword Exception PreProc Include Define Macro PreCondit Type StorageClass Structure Typedef Special SpecialChar Tag Delimiter SpecialComment Debug Underlined Ignore Error Todo " Default highlighting groups {{{2 -syn keyword vimHLGroup contained ErrorMsg IncSearch ModeMsg NonText StatusLine StatusLineNC EndOfBuffer VertSplit DiffText PmenuSbar TabLineSel TabLineFill Cursor lCursor QuickFixLine CursorLineSign CursorLineFold CurSearch PmenuKind PmenuKindSel PmenuExtra PmenuExtraSel Normal Directory LineNr CursorLineNr MoreMsg Question Search SpellBad SpellCap SpellRare SpellLocal PmenuThumb Pmenu PmenuSel SpecialKey Title WarningMsg WildMenu Folded FoldColumn SignColumn Visual DiffAdd DiffChange DiffDelete TabLine CursorColumn CursorLine ColorColumn Conceal MatchParen CursorIM LineNrAbove LineNrBelow -syn keyword vimOnlyHLGroup contained Menu Scrollbar StatusLineTerm StatusLineTermNC ToolbarButton ToolbarLine Tooltip VisualNOS +syn keyword vimHLGroup contained ErrorMsg IncSearch ModeMsg NonText StatusLine StatusLineNC EndOfBuffer VertSplit DiffText PmenuSbar TabLineSel TabLineFill Cursor lCursor QuickFixLine CursorLineSign CursorLineFold CurSearch PmenuKind PmenuKindSel PmenuMatch PmenuMatchSel PmenuExtra PmenuExtraSel Normal Directory LineNr CursorLineNr MoreMsg Question Search SpellBad SpellCap SpellRare SpellLocal PmenuThumb Pmenu PmenuSel SpecialKey Title WarningMsg WildMenu Folded FoldColumn SignColumn Visual DiffAdd DiffChange DiffDelete TabLine CursorColumn CursorLine ColorColumn MatchParen StatusLineTerm StatusLineTermNC CursorIM LineNrAbove LineNrBelow +syn match vimHLGroup contained "\<Conceal\>" +syn keyword vimOnlyHLGroup contained Menu Scrollbar ToolbarButton ToolbarLine Tooltip VisualNOS syn keyword nvimHLGroup contained FloatBorder FloatFooter FloatTitle MsgSeparator NormalFloat NormalNC Substitute TermCursor TermCursorNC VisualNC Whitespace WinBar WinBarNC WinSeparator "}}}2 syn case match " Special Vim Highlighting (not automatic) {{{1 -" Set up folding commands for this syntax highlighting file {{{2 +" Set up commands for this syntax highlighting file {{{2 + +com! -nargs=* Vim9 execute <q-args> s:vim9script ? "" : "contained" +com! -nargs=* VimL execute <q-args> s:vim9script ? "contained" : "" + if exists("g:vimsyn_folding") && g:vimsyn_folding =~# '[afhHlmpPrt]' if g:vimsyn_folding =~# 'a' com! -nargs=* VimFolda <args> fold @@ -151,6 +156,14 @@ else let s:vimsyn_maxlines= 60 endif +" Nulls {{{2 +" ===== +Vim9 syn keyword vim9Null null null_blob null_channel null_class null_dict null_function null_job null_list null_object null_partial null_string + +" Booleans {{{2 +" ======== +Vim9 syn keyword vim9Boolean true false + " Numbers {{{2 " ======= syn case ignore @@ -164,9 +177,11 @@ syn match vimNumber '\%(^\|\A\)\zs#\x\{6}' skipwhite nextgroup=vimGlobal,vimSub syn case match " All vimCommands are contained by vimIsCommand. {{{2 -syn cluster vimCmdList contains=vimAbb,vimAddress,vimAutoCmd,vimAugroup,vimBehave,vimDef,@vimEcho,vimEnddef,vimEndfunction,vimExecute,vimIsCommand,vimExtCmd,vimFor,vimFunction,vimGlobal,vimHighlight,vimLet,vimMap,vimMark,vimNotFunc,vimNorm,vimSet,vimSyntax,vimUnlet,vimUnmap,vimUserCmd,vimMenu,vimMenutranslate +syn cluster vimCmdList contains=vimAbb,vimAddress,vimAutoCmd,vimAugroup,vimBehave,vimCall,vimCatch,vimConst,vimDef,vimDelcommand,@vimEcho,vimEnddef,vimEndfunction,vimExecute,vimIsCommand,vimExtCmd,vimFor,vimFunction,vimFuncFold,vimGlobal,vimHighlight,vimLet,vimLoadkeymap,vimMap,vimMark,vimMatch,vimNotFunc,vimNorm,vimSet,vimSleep,vimSyntax,vimThrow,vimUnlet,vimUnmap,vimUserCmd,vimMenu,vimMenutranslate,@vim9CmdList +syn cluster vim9CmdList contains=vim9Const,vim9Final,vim9For,vim9Var syn match vimCmdSep "[:|]\+" skipwhite nextgroup=@vimCmdList,vimSubst1 syn match vimIsCommand "\<\%(\h\w*\|[23]mat\%[ch]\)\>" contains=vimCommand +syn match vimBang contained "!" syn match vimVar contained "\<\h[a-zA-Z0-9#_]*\>" syn match vimVar "\<[bwglstav]:\h[a-zA-Z0-9#_]*\>" syn match vimVar "\s\zs&\%([lg]:\)\=\a\+\>" @@ -175,7 +190,8 @@ syn match vimVar "\s\zs&t_k;" syn match vimFBVar contained "\<[bwglstav]:\h[a-zA-Z0-9#_]*\>" syn keyword vimCommand contained in -syn cluster vimExprList contains=vimEnvvar,vimFunc,vimFuncVar,vimNumber,vimOper,vimOperParen,vimLetRegister,vimString,vimVar +syn cluster vimExprList contains=vimEnvvar,vimFunc,vimNumber,vimOper,vimOperParen,vimLetRegister,vimString,vimVar,@vim9ExprList +syn cluster vim9ExprList contains=vim9Boolean,vim9Null " Insertions And Appends: insert append {{{2 " (buftype != nofile test avoids having append, change, insert show up in the command window) @@ -195,6 +211,15 @@ syn match vimBehave "\<be\%[have]\>" nextgroup=vimBehaveBang,vimBehaveModel,vi syn match vimBehaveBang contained "\a\@1<=!" nextgroup=vimBehaveModel skipwhite syn keyword vimBehaveModel contained mswin xterm +" Call {{{2 +" ==== +syn match vimCall "\<call\=\>" skipwhite nextgroup=vimFunc + +" Exception Handling {{{2 +syn keyword vimThrow th[row] skipwhite nextgroup=@vimExprList +syn keyword vimCatch cat[ch] skipwhite nextgroup=vimCatchPattern +syn region vimCatchPattern contained matchgroup=Delimiter start="\z([!#$%&'()*+,-./:;<=>?@[\]^_`{}~]\)" skip="\\\\\|\\\z1" end="\z1" contains=@vimSubstList oneline + " Filetypes {{{2 " ========= syn match vimFiletype "\<filet\%[ype]\(\s\+\I\i*\)*" skipwhite contains=vimFTCmd,vimFTOption,vimFTError @@ -224,8 +249,8 @@ syn keyword vimAugroupKey contained aug[roup] skipwhite nextgroup=vimAugroupBan " Operators: {{{2 " ========= -syn cluster vimOperGroup contains=vimEnvvar,vimFunc,vimFuncVar,vimOper,vimOperParen,vimNumber,vimString,vimRegister,@vimContinue,vim9Comment,vimVar -syn match vimOper "||\|&&\|[-+*/%.!]" skipwhite nextgroup=vimString,vimSpecFile +syn cluster vimOperGroup contains=vimEnvvar,vimFunc,vimFuncVar,vimOper,vimOperParen,vimNumber,vimString,vimRegister,@vimContinue,vim9Comment,vimVar,vimBoolean,vimNull +syn match vimOper "||\|&&\|[-+*/%.!]" skipwhite nextgroup=vimString,vimSpecFile syn match vimOper "\%#=1\(==\|!=\|>=\|<=\|=\~\|!\~\|>\|<\|=\|!\~#\)[?#]\{0,2}" skipwhite nextgroup=vimString,vimSpecFile syn match vimOper "\(\<is\|\<isnot\)[?#]\{0,2}\>" skipwhite nextgroup=vimString,vimSpecFile syn region vimOperParen matchgroup=vimParenSep start="(" end=")" contains=@vimOperGroup @@ -240,8 +265,8 @@ syn cluster vimFuncList contains=vimFuncBang,vimFunctionError,vimFuncKey,vimFunc syn cluster vimDefList contains=vimFuncBang,vimFunctionError,vimDefKey,vimFuncSID,Tag syn cluster vimFuncBodyCommon contains=@vimCmdList,vimCmplxRepeat,vimContinue,vimCtrlChar,vimDef,vimEnvvar,vimFBVar,vimFunc,vimFunction,vimLetHereDoc,vimNotation,vimNotFunc,vimNumber,vimOper,vimOperParen,vimRegister,vimSearch,vimSpecFile,vimString,vimSubst,vimFuncFold -syn cluster vimFuncBodyList contains=@vimFuncBodyCommon,vimComment,vimLineComment,vimFuncVar,vimInsert -syn cluster vimDefBodyList contains=@vimFuncBodyCommon,vim9Comment,vim9LineComment +syn cluster vimFuncBodyList contains=@vimFuncBodyCommon,vimComment,vimLineComment,vimFuncVar,vimInsert,vimConst,vimLet +syn cluster vimDefBodyList contains=@vimFuncBodyCommon,vim9Comment,vim9LineComment,vim9Const,vim9Final,vim9Var,vim9Null,vim9Boolean,vim9For syn region vimFuncPattern contained matchgroup=vimOper start="/" end="$" contains=@vimSubstList syn match vimFunction "\<fu\%[nction]\>" skipwhite nextgroup=vimCmdSep,vimComment,vimFuncPattern contains=vimFuncKey @@ -251,8 +276,8 @@ syn match vimFunction "\<fu\%[nction]\>!\=\s*\%(<[sS][iI][dD]>\|[sg]:\)\=\%(\i\| syn match vimDef "\<def\s\+new\%(\i\|{.\{-1,}}\)\+" contains=@vimDefList nextgroup=vimDefParams syn match vimDef "\<def\>!\=\s*\%(<[sS][iI][dD]>\|[sg]:\)\=\%(\i\|[#.]\|{.\{-1,}}\)\+" contains=@vimDefList nextgroup=vimDefParams -syn match vimFuncComment contained +".*+ skipwhite skipnl nextgroup=vimFuncBody,vimEndfunction -syn match vimDefComment contained "#.*" skipwhite skipnl nextgroup=vimDefBody,vimEnddef +syn match vimFuncComment contained +".*+ skipwhite skipempty nextgroup=vimFuncBody,vimEndfunction +syn match vimDefComment contained "#.*" skipwhite skipempty nextgroup=vimDefBody,vimEnddef syn match vimFuncBang contained "!" syn match vimFuncSID contained "\c<sid>" @@ -260,24 +285,24 @@ syn match vimFuncSID contained "\<[sg]:" syn keyword vimFuncKey contained fu[nction] syn keyword vimDefKey contained def -syn region vimFuncParams contained matchgroup=Delimiter start="(" skip=+\n\s*\\\|\n\s*"\\ + end=")" skipwhite skipnl nextgroup=vimFuncBody,vimFuncComment,vimEndfunction,vimFuncMod contains=vimFuncParam,@vimContinue -syn region vimDefParams contained matchgroup=Delimiter start="(" end=")" skipwhite skipnl nextgroup=vimDefBody,vimDefComment,vimEnddef,vimReturnType contains=vimDefParam,vim9Comment +syn region vimFuncParams contained matchgroup=Delimiter start="(" skip=+\n\s*\\\|\n\s*"\\ + end=")" skipwhite skipempty nextgroup=vimFuncBody,vimFuncComment,vimEndfunction,vimFuncMod,vim9CommentError contains=vimFuncParam,@vimContinue +syn region vimDefParams contained matchgroup=Delimiter start="(" end=")" skipwhite skipempty nextgroup=vimDefBody,vimDefComment,vimEnddef,vimReturnType,vimCommentError contains=vimDefParam,vim9Comment,vimFuncParamEquals syn match vimFuncParam contained "\<\h\w*\>\|\.\.\." skipwhite nextgroup=vimFuncParamEquals syn match vimDefParam contained "\<\h\w*\>" skipwhite nextgroup=vimParamType,vimFuncParamEquals -syn match vimFuncParamEquals contained "=" skipwhite nextgroup=@vimExprList -syn match vimFuncMod contained "\<\%(abort\|closure\|dict\|range\)\>" skipwhite skipnl nextgroup=vimFuncBody,vimFuncComment,vimEndfunction,vimFuncMod +syn match vimFuncParamEquals contained "=" skipwhite nextgroup=@vimExprList +syn match vimFuncMod contained "\<\%(abort\|closure\|dict\|range\)\>" skipwhite skipempty nextgroup=vimFuncBody,vimFuncComment,vimEndfunction,vimFuncMod,vim9CommentError -syn region vimFuncBody contained start="^" matchgroup=vimCommand end="\<endfu\%[nction]\>" contains=@vimFuncBodyList -syn region vimDefBody contained start="^" matchgroup=vimCommand end="\<enddef\>" contains=@vimDefBodyList +syn region vimFuncBody contained start="^." matchgroup=vimCmdSep start="|" matchgroup=vimCommand end="\<endfu\%[nction]\>" contains=@vimFuncBodyList skipwhite nextgroup=vimCmdSep,vimComment,vim9CommentError +syn region vimDefBody contained start="^." matchgroup=vimCmdSep start="|" matchgroup=vimCommand end="\<enddef\>" contains=@vimDefBodyList skipwhite nextgroup=vimCmdSep,vim9Comment,vimCommentError -syn match vimEndfunction "\<endf\%[unction]\>" -syn match vimEnddef "\<enddef\>" +syn match vimEndfunction "\<endf\%[unction]\>" skipwhite nextgroup=vimCmdSep,vimComment,vim9CommentError +syn match vimEnddef "\<enddef\>" skipwhite nextgroup=vimCmdSep,vim9Comment,vimCommentError if exists("g:vimsyn_folding") && g:vimsyn_folding =~# 'f' - syn region vimFuncFold start="^\s*:\=\s*fu\%[nction]\>!\=\s*\%(<[sS][iI][dD]>\|[sg]:\)\=\%(\i\|[#.]\|{.\{-1,}}\)\+\s*(" end="^\s*:\=\s*endf\%[unction]\>" contains=vimFunction fold keepend extend transparent - syn region vimFuncFold start="^\s*:\=\s*def\>!\=\s*\%(<[sS][iI][dD]>\|[sg]:\)\=\%(\i\|[#.]\)\+(" end="^\s*:\=\s*enddef\>" contains=vimDef fold keepend extend transparent - syn region vimFuncFold start="^\s*:\=\s*def\s\+new\i\+(" end="^\s*:\=\s*enddef\>" contains=vimDef fold keepend extend transparent + syn region vimFuncFold start="\<fu\%[nction]\>!\=\s*\%(<[sS][iI][dD]>\|[sg]:\)\=\%(\i\|[#.]\|{.\{-1,}}\)\+\s*(" end="\<endf\%[unction]\>" contains=vimFunction fold keepend extend transparent + syn region vimFuncFold start="\<def\>!\=\s*\%(<[sS][iI][dD]>\|[sg]:\)\=\%(\i\|[#.]\)\+(" end="\<enddef\>" contains=vimDef fold keepend extend transparent + syn region vimFuncFold start="\<def\s\+new\i\+(" end="\<enddef\>" contains=vimDef fold keepend extend transparent endif syn match vimFuncVar contained "a:\%(\K\k*\|\d\+\)\>" @@ -285,9 +310,9 @@ syn match vimFuncBlank contained "\s\+" " Types: {{{2 " ===== -" vimTypes : new for vim9 -syn region vimReturnType contained start=":\s" end="$" matchgroup=vim9Comment end="\ze#" skipwhite skipnl nextgroup=vimDefBody,vimDefComment,vimEnddef contains=vimTypeSep transparent -syn match vimParamType contained ":\s\+\a" skipwhite skipnl nextgroup=vimFuncParamEquals contains=vimTypeSep,@vimType + +syn region vimReturnType contained start=":\s" end="$" matchgroup=vim9Comment end="\ze[#"]" skipwhite skipempty nextgroup=vimDefBody,vimDefComment,vimEnddef,vimCommentError contains=vimTypeSep transparent +syn match vimParamType contained ":\s" skipwhite skipnl nextgroup=@vimType contains=vimTypeSep syn match vimTypeSep contained ":\s\@=" skipwhite nextgroup=@vimType syn keyword vimType contained any blob bool channel float job number string void @@ -314,7 +339,7 @@ else endif syn cluster vimKeymapLineComment contains=vim9\=KeymapLineComment -syn region vimKeymap matchgroup=vimCommand start="\<loadk\%[eymap]\>" end="\%$" contains=vimKeymapStart +syn region vimLoadkeymap matchgroup=vimCommand start="\<loadk\%[eymap]\>" end="\%$" contains=vimKeymapStart " Special Filenames, Modifiers, Extension Removal: {{{2 " =============================================== @@ -329,67 +354,73 @@ syn match vimSpecFileMod "\(:[phtre]\)\+" contained " User-Specified Commands: {{{2 " ======================= syn cluster vimUserCmdList contains=@vimCmdList,vimCmplxRepeat,@vimComment,vimCtrlChar,vimEscapeBrace,vimFunc,vimNotation,vimNumber,vimOper,vimRegister,vimSpecFile,vimString,vimSubst,vimSubstRep,vimSubstRange -syn keyword vimUserCommand contained com[mand] -syn match vimUserCmdName contained "\<\u\w*\>" nextgroup=vimUserCmdBlock skipwhite -syn match vimUserCmd "\<com\%[mand]!\=\>.*$" contains=vimUserAttrb,vimUserAttrbError,vimUserCommand,@vimUserCmdList,vimComFilter,vimCmdBlock,vimUserCmdName -syn match vimUserAttrbError contained "-\a\+\ze\s" -syn match vimUserAttrb contained "-nargs=[01*?+]" contains=vimUserAttrbKey,vimOper -syn match vimUserAttrb contained "-complete=" contains=vimUserAttrbKey,vimOper nextgroup=vimUserAttrbCmplt,vimUserCmdError -syn match vimUserAttrb contained "-range\(=%\|=\d\+\)\=" contains=vimNumber,vimOper,vimUserAttrbKey -syn match vimUserAttrb contained "-count\(=\d\+\)\=" contains=vimNumber,vimOper,vimUserAttrbKey -syn match vimUserAttrb contained "-bang\>" contains=vimOper,vimUserAttrbKey -syn match vimUserAttrb contained "-bar\>" contains=vimOper,vimUserAttrbKey -syn match vimUserAttrb contained "-buffer\>" contains=vimOper,vimUserAttrbKey -syn match vimUserAttrb contained "-register\>" contains=vimOper,vimUserAttrbKey +syn keyword vimUserCmdKey contained com[mand] +syn match vimUserCmdName contained "\<\u[[:alnum:]]*\>" skipwhite nextgroup=vimUserCmdBlock +syn match vimUserCmd "\<com\%[mand]\>!\=.*$" contains=vimUserCmdKey,vimBang,vimUserCmdAttr,vimUserCmdAttrError,vimUserCmdName,@vimUserCmdList,vimComFilter +syn match vimUserCmdAttrError contained "-\a\+\ze\%(\s\|=\)" +syn match vimUserCmdAttr contained "-addr=" contains=vimUserCmdAttrKey nextgroup=vimUserCmdAttrAddr +syn match vimUserCmdAttr contained "-bang\>" contains=vimUserCmdAttrKey +syn match vimUserCmdAttr contained "-bar\>" contains=vimUserCmdAttrKey +syn match vimUserCmdAttr contained "-buffer\>" contains=vimUserCmdAttrKey +syn match vimUserCmdAttr contained "-complete=" contains=vimUserCmdAttrKey nextgroup=vimUserCmdAttrCmplt,vimUserCmdError +syn match vimUserCmdAttr contained "-count\>" contains=vimUserCmdAttrKey +syn match vimUserCmdAttr contained "-count=" contains=vimUserCmdAttrKey nextgroup=vimNumber +syn match vimUserCmdAttr contained "-keepscript\>" contains=vimUserCmdAttrKey +syn match vimUserCmdAttr contained "-nargs=" contains=vimUserCmdAttrKey nextgroup=vimUserCmdAttrNargs +syn match vimUserCmdAttr contained "-range\>" contains=vimUserCmdAttrKey +syn match vimUserCmdAttr contained "-range=" contains=vimUserCmdAttrKey nextgroup=vimNumber,vimUserCmdAttrRange +syn match vimUserCmdAttr contained "-register\>" contains=vimUserCmdAttrKey + +syn match vimUserCmdAttrNargs contained "[01*?+]" +syn match vimUserCmdAttrRange contained "%" + if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_nousercmderror") syn match vimUserCmdError contained "\S\+\>" endif -syn case ignore -syn keyword vimUserAttrbKey contained bar ban[g] cou[nt] ra[nge] com[plete] n[args] re[gister] -" GEN_SYN_VIM: vimUserAttrbCmplt, START_STR='syn keyword vimUserAttrbCmplt contained', END_STR='' -syn keyword vimUserAttrbCmplt contained arglist augroup behave buffer color command compiler cscope diff_buffer dir environment event expression file file_in_path filetype function help highlight history keymap locale mapclear mapping menu messages syntax syntime option packadd runtime shellcmd sign tag tag_listfiles user var breakpoint scriptnames -syn keyword vimUserAttrbCmplt contained custom customlist nextgroup=vimUserAttrbCmpltFunc,vimUserCmdError -syn match vimUserAttrbCmpltFunc contained ",\%([sS]:\|<[sS][iI][dD]>\)\=\%(\h\w*\%([.#]\h\w*\)\+\|\h\w*\)"hs=s+1 nextgroup=vimUserCmdError +syn case ignore +syn keyword vimUserCmdAttrKey contained a[ddr] ban[g] bar bu[ffer] com[plete] cou[nt] k[eepscript] n[args] ra[nge] re[gister] +" GEN_SYN_VIM: vimUserCmdAttrCmplt, START_STR='syn keyword vimUserCmdAttrCmplt contained', END_STR='' +syn keyword vimUserCmdAttrCmplt contained arglist augroup behave breakpoint buffer color command compiler cscope diff_buffer dir dir_in_path environment event expression file file_in_path filetype function help highlight history keymap locale mapclear mapping menu messages option packadd runtime scriptnames shellcmd sign syntax syntime tag tag_listfiles user var +syn keyword vimUserCmdAttrCmplt contained custom customlist nextgroup=vimUserCmdAttrCmpltFunc,vimUserCmdError +syn match vimUserCmdAttrCmpltFunc contained ",\%([sS]:\|<[sS][iI][dD]>\)\=\%(\h\w*\%([.#]\h\w*\)\+\|\h\w*\)"hs=s+1 nextgroup=vimUserCmdError +" GEN_SYN_VIM: vimUserCmdAttrAddr, START_STR='syn keyword vimUserCmdAttrAddr contained', END_STR='' +syn keyword vimUserCmdAttrAddr contained arguments arg buffers buf lines line loaded_buffers load other quickfix qf tabs tab windows win +syn match vimUserCmdAttrAddr contained "?" syn case match -syn match vimUserAttrbCmplt contained "custom,\u\w*" syn region vimUserCmdBlock contained matchgroup=vimSep start="{" end="}" contains=@vimDefBodyList +syn match vimDelcommand "\<delc\%[ommand]\>" skipwhite nextgroup=vimDelcommandAttr +syn match vimDelcommandAttr contained "-buffer\>" + " Lower Priority Comments: after some vim commands... {{{2 " ======================= -syn region vimCommentString contained oneline start='\S\s\+"'ms=e end='"' +if get(g:, "vimsyn_comment_strings", 1) + syn region vimCommentString contained oneline start='\S\s\+"'ms=e end='"' extend +endif if s:vim9script - syn match vimComment excludenl +\s"[^\-:.%#=*].*$+lc=1 contains=@vimCommentGroup,vimCommentString contained - syn match vimComment +\<endif\s\+".*$+lc=5 contains=@vimCommentGroup,vimCommentString contained - syn match vimComment +\<else\s\+".*$+lc=4 contains=@vimCommentGroup,vimCommentString contained - " Vim9 comments - TODO: might be highlighted while they don't work - syn match vim9Comment excludenl +\s#[^{].*$+lc=1 contains=@vimCommentGroup,vimCommentString - syn match vim9Comment +\<endif\s\+#[^{].*$+lc=5 contains=@vimCommentGroup,vimCommentString - syn match vim9Comment +\<else\s\+#[^{].*$+lc=4 contains=@vimCommentGroup,vimCommentString - " Vim9 comment inside expression - " syn match vim9Comment +\s\zs#[^{].*$+ms=s+1 contains=@vimCommentGroup,vimCommentString - " syn match vim9Comment +^\s*#[^{].*$+ contains=@vimCommentGroup,vimCommentString - " syn match vim9Comment +^\s*#$+ contains=@vimCommentGroup,vimCommentString - syn cluster vimComment contains=vim9Comment else - syn match vimComment excludenl +\s"[^\-:.%#=*].*$+lc=1 contains=@vimCommentGroup,vimCommentString - syn match vimComment +\<endif\s\+".*$+lc=5 contains=@vimCommentGroup,vimCommentString - syn match vimComment +\<else\s\+".*$+lc=4 contains=@vimCommentGroup,vimCommentString - " Vim9 comments - TODO: might be highlighted while they don't work - syn match vim9Comment excludenl +\s#[^{].*$+lc=1 contains=@vimCommentGroup,vimCommentString contained - syn match vim9Comment +\<endif\s\+#[^{].*$+lc=5 contains=@vimCommentGroup,vimCommentString contained - syn match vim9Comment +\<else\s\+#[^{].*$+lc=4 contains=@vimCommentGroup,vimCommentString contained - " Vim9 comment inside expression - syn match vim9Comment +\s\zs#[^{].*$+ms=s+1 contains=@vimCommentGroup,vimCommentString contained - syn match vim9Comment +^\s*#[^{].*$+ contains=@vimCommentGroup,vimCommentString contained - syn match vim9Comment +^\s*#$+ contains=@vimCommentGroup,vimCommentString contained - syn cluster vimComment contains=vimComment endif +VimL syn match vimComment excludenl +\s"[^\-:.%#=*].*$+lc=1 contains=@vimCommentGroup,vimCommentString extend +VimL syn match vimComment +\<endif\s\+".*$+lc=5 contains=@vimCommentGroup,vimCommentString extend +VimL syn match vimComment +\<else\s\+".*$+lc=4 contains=@vimCommentGroup,vimCommentString extend +" Vim9 comments - TODO: might be highlighted while they don't work +Vim9 syn match vim9Comment excludenl +\s#[^{].*$+lc=1 contains=@vimCommentGroup,vimCommentString extend +Vim9 syn match vim9Comment +\<endif\s\+#[^{].*$+lc=5 contains=@vimCommentGroup,vimCommentString extend +Vim9 syn match vim9Comment +\<else\s\+#[^{].*$+lc=4 contains=@vimCommentGroup,vimCommentString extend +" Vim9 comment inside expression +Vim9 syn match vim9Comment +\s\zs#[^{].*$+ms=s+1 contains=@vimCommentGroup,vimCommentString contained extend +Vim9 syn match vim9Comment +^\s*#[^{].*$+ contains=@vimCommentGroup,vimCommentString contained extend +Vim9 syn match vim9Comment +^\s*#$+ contains=@vimCommentGroup,vimCommentString contained extend + +syn match vim9CommentError contained "#.*" +syn match vimCommentError contained +".*+ + " Environment Variables: {{{2 " ===================== syn match vimEnvvar "\$\I\i*" @@ -405,8 +436,8 @@ syn region vimPatSepZone oneline contained matchgroup=vimPatSepZ start="\\%\ syn region vimPatRegion contained transparent matchgroup=vimPatSepR start="\\[z%]\=(" end="\\)" contains=@vimSubstList oneline syn match vimNotPatSep contained "\\\\" syn cluster vimStringGroup contains=vimEscape,vimEscapeBrace,vimPatSep,vimNotPatSep,vimPatSepErr,vimPatSepZone,@Spell -syn region vimString oneline keepend start=+[^a-zA-Z>!\\@]"+lc=1 skip=+\\\\\|\\"+ matchgroup=vimStringEnd end=+"+ contains=@vimStringGroup -syn region vimString oneline keepend start=+[^a-zA-Z>!\\@]'+lc=1 end=+'+ +syn region vimString oneline keepend start=+[^a-zA-Z>!\\@]"+lc=1 skip=+\\\\\|\\"+ matchgroup=vimStringEnd end=+"+ contains=@vimStringGroup extend +syn region vimString oneline keepend start=+[^a-zA-Z>!\\@]'+lc=1 end=+'+ extend "syn region vimString oneline start="\s/\s*\A"lc=1 skip="\\\\\|\\+" end="/" contains=@vimStringGroup " see tst45.vim syn match vimString contained +"[^"]*\\$+ skipnl nextgroup=vimStringCont syn match vimStringCont contained +\(\\\\\|.\)\{-}[^\\]"+ @@ -416,23 +447,22 @@ syn match vimEscape contained "\\\o\{1,3}\|\\[xX]\x\{1,2}\|\\u\x\{1,4}\|\\U\x\{1 syn match vimEscape contained "\\<" contains=vimNotation syn match vimEscape contained "\\<\*[^>]*>\=>" -syn region vimString oneline start=+$'+ skip=+''+ end=+'+ contains=vimStringInterpolationBrace,vimStringInterpolationExpr -syn region vimString oneline start=+$"+ end=+"+ contains=@vimStringGroup,vimStringInterpolationBrace,vimStringInterpolationExpr +syn region vimString oneline start=+$'+ skip=+''+ end=+'+ contains=@vimStringInterpolation extend +syn region vimString oneline start=+$"+ end=+"+ contains=@vimStringGroup,@vimStringInterpolation extend syn region vimStringInterpolationExpr oneline contained matchgroup=vimSep start=+{+ end=+}+ contains=@vimExprList syn match vimStringInterpolationBrace contained "{{" syn match vimStringInterpolationBrace contained "}}" +syn cluster vimStringInterpolation contains=vimStringInterpolationExpr,vimStringInterpolationBrace " Substitutions: {{{2 " ============= syn cluster vimSubstList contains=vimPatSep,vimPatRegion,vimPatSepErr,vimSubstTwoBS,vimSubstRange,vimNotation syn cluster vimSubstRepList contains=vimSubstSubstr,vimSubstTwoBS,vimNotation syn cluster vimSubstList add=vimCollection -syn match vimSubst "^\s*\%(s\%[ubstitute]\|sm\%[agic]\|sno\%[magic]\)\>[\"#|]\@!" nextgroup=vimSubstPat -syn match vimSubst "^\s*\%(s\%[ubstitute]\|sm\%[agic]\|sno\%[magic]\)_\@=" nextgroup=vimSubstPat -syn match vimSubst "^\s*\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)\ze#.\{-}#.\{-}#" nextgroup=vimSubstPat -syn match vimSubst1 contained "\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)\>[\"#|]\@!" nextgroup=vimSubstPat -syn match vimSubst1 contained "\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)_\@=" nextgroup=vimSubstPat -syn match vimSubst1 contained "\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)\ze#.\{-}#.\{-}#" nextgroup=vimSubstPat +syn match vimSubst "^\s*\%(s\%[ubstitute]\|sm\%[agic]\|sno\%[magic]\)\>" skipwhite nextgroup=vimSubstPat +syn match vimSubst "^\s*\%(s\%[ubstitute]\|sm\%[agic]\|sno\%[magic]\)[_#]\@=" skipwhite nextgroup=vimSubstPat +syn match vimSubst1 contained "\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)\>" skipwhite nextgroup=vimSubstPat +syn match vimSubst1 contained "\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)[_#]\@=" skipwhite nextgroup=vimSubstPat " TODO: Vim9 illegal separators for abbreviated :s form are [-.:], :su\%[...] required " : # is allowed but "not recommended" (see :h pattern-delimiter) syn region vimSubstPat contained matchgroup=vimSubstDelim start="\z([!#$%&'()*+,-./:;<=>?@[\]^_`{}~]\)"rs=s+1 skip="\\\\\|\\\z1" end="\z1"re=e-1,me=e-1 contains=@vimSubstList nextgroup=vimSubstRep4 oneline @@ -445,13 +475,17 @@ syn match vimSubstTwoBS contained "\\\\" syn match vimSubstFlagErr contained "[^< \t\r|]\+" contains=vimSubstFlags syn match vimSubstFlags contained "[&cegiIlnpr#]\+" +" Vi compatibility +syn match vimSubstDelim contained "\\" +syn match vimSubstPat contained "\\\ze[/?&]" contains=vimSubstDelim nextgroup=vimSubstRep4 + " 'String': {{{2 syn match vimString "[^(,]'[^']\{-}\zs'" " Marks, Registers, Addresses, Filters: {{{2 syn match vimMark "'[a-zA-Z0-9]\ze[-+,!]" nextgroup=vimFilter,vimMarkNumber,vimSubst1 -syn match vimMark "'[<>]\ze[-+,!]" nextgroup=vimFilter,vimMarkNumber,vimSubst1 -syn match vimMark ",\zs'[<>]\ze" nextgroup=vimFilter,vimMarkNumber,vimSubst1 +syn match vimMark "'[[\]{}()<>]\ze[-+,!]" nextgroup=vimFilter,vimMarkNumber,vimSubst1 +syn match vimMark ",\zs'[[\]{}()<>]\ze" nextgroup=vimFilter,vimMarkNumber,vimSubst1 syn match vimMark "[!,:]\zs'[a-zA-Z0-9]" nextgroup=vimFilter,vimMarkNumber,vimSubst1 syn match vimMark "\<norm\%[al]\s\zs'[a-zA-Z0-9]" nextgroup=vimFilter,vimMarkNumber,vimSubst1 syn match vimMarkNumber "[-+]\d\+" contained contains=vimOper nextgroup=vimSubst1 @@ -478,28 +512,45 @@ syn match vimCmplxRepeat '[^a-zA-Z_/\\()]q[0-9a-zA-Z"]\>'lc=1 syn match vimCmplxRepeat '@[0-9a-z".=@:]\ze\($\|[^a-zA-Z]\>\)' " Set command and associated set-options (vimOptions) with comment {{{2 -syn region vimSet matchgroup=vimCommand start="\<\%(setl\%[ocal]\|setg\%[lobal]\|se\%[t]\)\>" skip="\%(\\\\\)*\\.\n\@!" end="$" end="|" matchgroup=vimNotation end="<[cC][rR]>" keepend contains=vimSetEqual,vimOption,vimErrSetting,@vimComment,vimSetString,vimSetMod -syn region vimSetEqual contained start="[=:]\|[-+^]=" skip="\\\\\|\\\s" end="[| \t]"me=e-1 end="$" contains=vimCtrlChar,vimSetSep,vimNotation,vimEnvvar -syn region vimSetString contained start=+="+hs=s+1 skip=+\\\\\|\\"+ end=+"+ contains=vimCtrlChar +syn match vimSet "\<\%(setl\%[ocal]\|setg\%[lobal]\|se\%[t]\)\>" skipwhite nextgroup=vimSetBang,vimSetRegion +syn region vimSetRegion contained start="\S" skip=+\\\\\|\\|\|\n\s*\\\|\n\s*["#]\\ + matchgroup=vimCmdSep end="|" end="$" matchgroup=vimNotation end="<[cC][rR]>" keepend contains=@vimComment,@vimContinue,vimErrSetting,vimOption,vimSetAll,vimSetTermcap +syn region vimSetEqual contained matchgroup=vimOper start="[=:]\|[-+^]=" skip=+\\\\\|\\|\|\\\s\|\n\s*\\\|\n\s*["#]\\ \|^\s*\\\|^\s*["#]\\ + matchgroup=vimCmdSep end="|" end="\ze\s" end="$" contains=@vimContinue,vimCtrlChar,vimEnvvar,vimNotation,vimSetSep +syn match vimSetBang contained "\a\@1<=!" skipwhite nextgroup=vimSetAll,vimSetTermcap +syn keyword vimSetAll contained all nextgroup=vimSetMod +syn keyword vimSetTermcap contained termcap +syn region vimSetString contained start=+="+hs=s+1 skip=+\\\\\|\\"+ end=+"+ contains=vimCtrlChar syn match vimSetSep contained "[,:]" -syn match vimSetMod contained "&vim\=\|[!&?<]\|all&" +syn match vimSetMod contained "\a\@1<=\%(&vim\=\|[!&?<]\)" -" Let: {{{2 -" === -syn keyword vimLet let skipwhite nextgroup=vimVar,vimFuncVar,vimLetHereDoc,vimLetRegister,vimVarList -syn keyword vimConst cons[t] skipwhite nextgroup=vimVar,vimLetHereDoc,vimVarList -syn region vimVarList contained start="\[" end="]" contains=vimVar,vimContinue +" Variable Declarations: {{{2 +" ===================== +VimL syn keyword vimLet let skipwhite nextgroup=vimVar,vimFuncVar,vimLetRegister,vimVarList +VimL syn keyword vimConst cons[t] skipwhite nextgroup=vimVar,vimVarList +syn region vimVarList contained start="\[" end="]" contains=vimVar,@vimContinue -syn keyword vimUnlet unl[et] skipwhite nextgroup=vimUnletBang,vimUnletVars +VimL syn keyword vimUnlet unl[et] skipwhite nextgroup=vimUnletBang,vimUnletVars syn match vimUnletBang contained "!" skipwhite nextgroup=vimUnletVars syn region vimUnletVars contained start="$\I\|\h" skip="\n\s*\\" end="$" end="|" contains=vimVar,vimEnvvar,vimContinue,vimString,vimNumber -VimFoldh syn region vimLetHereDoc matchgroup=vimLetHereDocStart start='=<<\s*\%(trim\s\+\%(eval\s\+\)\=\|eval\s\+\%(trim\s\+\)\=\)\=\z(\L\S*\)' matchgroup=vimLetHereDocStop end='^\s*\z1\s*$' extend -syn keyword vimLet var skipwhite nextgroup=vimVar,vimFuncVar,vimLetHereDoc +VimFoldh syn region vimLetHereDoc matchgroup=vimLetHereDocStart start='\%(^\z(\s*\)\S.*\)\@<==<<\s*trim\%(\s\+\)\@>\z(\L\S*\)' matchgroup=vimLetHereDocStop end='^\z1\=\z2$' extend +VimFoldh syn region vimLetHereDoc matchgroup=vimLetHereDocStart start='=<<\%(\s*\)\@>\z(\L\S*\)' matchgroup=vimLetHereDocStop end='^\z1$' extend +VimFoldh syn region vimLetHereDoc matchgroup=vimLetHereDocStart start='\%(^\z(\s*\)\S.*\)\@<==<<\s*\%(trim\s\+eval\|eval\s\+trim\)\%(\s\+\)\@>\z(\L\S*\)' matchgroup=vimLetHereDocStop end='^\z1\=\z2$' contains=@vimStringInterpolation extend +VimFoldh syn region vimLetHereDoc matchgroup=vimLetHereDocStart start='=<<\s*eval\%(\s\+\)\@>\z(\L\S*\)' matchgroup=vimLetHereDocStop end='^\z1$' contains=@vimStringInterpolation extend + +Vim9 syn keyword vim9Const const skipwhite nextgroup=vim9Variable,vim9VariableList +Vim9 syn keyword vim9Final final skipwhite nextgroup=vim9Variable,vim9VariableList +Vim9 syn keyword vim9Var var skipwhite nextgroup=vim9Variable,vim9VariableList + +syn match vim9Variable contained "\<\h\w*\>" skipwhite nextgroup=vimTypeSep,vimLetHereDoc +syn region vim9VariableList contained start="\[" end="]" contains=vim9Variable,@vimContinue " For: {{{2 " === -syn keyword vimFor for skipwhite nextgroup=vimVar,vimVarList +if s:vim9script + syn keyword vim9For for skipwhite nextgroup=vim9Variable,vim9VariableList +else + syn keyword vimFor for skipwhite nextgroup=vimVar,vimVarList +endif " Abbreviations: {{{2 " ============= @@ -543,15 +594,17 @@ syn region vimExecute matchgroup=vimCommand start="\<exe\%[cute]\>" skip=+\\|\|\ " Maps: {{{2 " ==== -syn match vimMap "\<map\>\ze\s*(\@!" skipwhite nextgroup=vimMapMod,vimMapLhs -syn match vimMap "\<map!" contains=vimMapBang skipwhite nextgroup=vimMapMod,vimMapLhs -" GEN_SYN_VIM: vimCommand map, START_STR='syn keyword vimMap', END_STR='skipwhite nextgroup=vimMapBang,vimMapMod,vimMapLhs' -syn keyword vimMap cm[ap] cno[remap] im[ap] ino[remap] lm[ap] ln[oremap] nm[ap] nn[oremap] no[remap] om[ap] ono[remap] smap snor[emap] tma[p] tno[remap] vm[ap] vn[oremap] xm[ap] xn[oremap] skipwhite nextgroup=vimMapBang,vimMapMod,vimMapLhs +" GEN_SYN_VIM: vimCommand map, START_STR='syn keyword vimMap', END_STR='skipwhite nextgroup=vimMapMod,vimMapLhs' +syn keyword vimMap cm[ap] cno[remap] im[ap] ino[remap] lm[ap] ln[oremap] nm[ap] nn[oremap] om[ap] ono[remap] smap snor[emap] tma[p] tno[remap] vm[ap] vn[oremap] xm[ap] xn[oremap] skipwhite nextgroup=vimMapMod,vimMapLhs +syn match vimMap "\<map\>" skipwhite nextgroup=vimMapBang,vimMapMod,vimMapLhs +syn keyword vimMap no[remap] skipwhite nextgroup=vimMapBang,vimMapMod,vimMapLhs " GEN_SYN_VIM: vimCommand mapclear, START_STR='syn keyword vimMap', END_STR='skipwhite nextgroup=vimMapMod' syn keyword vimMap cmapc[lear] imapc[lear] lmapc[lear] nmapc[lear] omapc[lear] smapc[lear] tmapc[lear] vmapc[lear] xmapc[lear] skipwhite nextgroup=vimMapMod -syn keyword vimMap mapc[lear] skipwhite nextgroup=vimMapBang,vimMapMod -" GEN_SYN_VIM: vimCommand unmap, START_STR='syn keyword vimUnmap', END_STR='skipwhite nextgroup=vimMapBang,vimMapMod,vimMapLhs' -syn keyword vimUnmap cu[nmap] iu[nmap] lu[nmap] nun[map] ou[nmap] sunm[ap] tunma[p] unm[ap] vu[nmap] xu[nmap] skipwhite nextgroup=vimMapBang,vimMapMod,vimMapLhs +syn keyword vimMap mapc[lear] skipwhite nextgroup=vimMapBang,vimMapMod +" GEN_SYN_VIM: vimCommand unmap, START_STR='syn keyword vimUnmap', END_STR='skipwhite nextgroup=vimMapMod,vimMapLhs' +syn keyword vimUnmap cu[nmap] iu[nmap] lu[nmap] nun[map] ou[nmap] sunm[ap] tunma[p] vu[nmap] xu[nmap] skipwhite nextgroup=vimMapMod,vimMapLhs +syn keyword vimUnmap unm[ap] skipwhite nextgroup=vimMapBang,vimMapMod,vimMapLhs + syn match vimMapLhs contained "\%(.\|\S\)\+" contains=vimCtrlChar,vimNotation skipwhite nextgroup=vimMapRhs syn match vimMapLhs contained "\%(.\|\S\)\+\ze\s*$" contains=vimCtrlChar,vimNotation skipwhite skipnl nextgroup=vimMapRhsContinue syn match vimMapBang contained "\a\@1<=!" skipwhite nextgroup=vimMapMod,vimMapLhs @@ -618,6 +671,8 @@ syn match vimFunc "\%(\%([sSgGbBwWtTlL]:\|<[sS][iI][dD]>\)\=\%(\w\ syn match vimUserFunc contained "\%(\%([sSgGbBwWtTlL]:\|<[sS][iI][dD]>\)\=\%(\w\+\.\)*\I[a-zA-Z0-9_.]*\)\|\<\u[a-zA-Z0-9.]*\>\|\<if\>" contains=vimNotation syn keyword vimFuncEcho contained ec ech echo +syn match vimMap "\<map\%(\s\+(\)\@=" skipwhite nextgroup=vimMapBang,vimMapMod,vimMapLhs + " User Command Highlighting: {{{2 syn match vimUsrCmd '^\s*\zs\u\%(\w*\)\@>\%([(#[]\|\s\+\%([-+*/%]\=\|\.\.\)=\)\@!' @@ -630,13 +685,28 @@ if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_novimfunctionerror") syn match vimBufnrWarn /\<bufnr\s*(\s*["']\.['"]\s*)/ endif -syn match vimNotFunc "\<if\>\|\<el\%[seif]\>\|\<retu\%[rn]\>\|\<while\>" skipwhite nextgroup=vimOper,vimOperParen,vimVar,vimFunc,vimNotation +syn match vimNotFunc "\<if\>\|\<el\%[seif]\>\|\<retu\%[rn]\>\|\<while\>" skipwhite nextgroup=@vimExprList,vimNotation + +" Match: {{{2 +" ===== +syn match vimMatch "\<[23]\=mat\%[ch]\>" skipwhite nextgroup=vimMatchGroup,vimMatchNone +syn match vimMatchGroup contained "[[:alnum:]._-]\+" skipwhite nextgroup=vimMatchPattern +syn case ignore +syn keyword vimMatchNone contained none +syn case match +syn region vimMatchPattern contained matchgroup=Delimiter start="\z([!#$%&'()*+,-./:;<=>?@[\]^_`{}~]\)" skip="\\\\\|\\\z1" end="\z1" contains=@vimSubstList oneline " Norm: {{{2 " ==== syn match vimNorm "\<norm\%[al]!\=" skipwhite nextgroup=vimNormCmds syn match vimNormCmds contained ".*$" +" Sleep: {{{2 +" ===== +syn keyword vimSleep sl[eep] skipwhite nextgroup=vimSleepBang,vimSleepArg +syn match vimSleepBang contained "\a\@1<=!" skipwhite nextgroup=vimSleepArg +syn match vimSleepArg contained "\<\%(\d\+\)\=m\=\>" + " Syntax: {{{2 "======= syn match vimGroupList contained "[^[:space:],]\+\%(\s*,\s*[^[:space:],]\+\)*" contains=vimGroupSpecial @@ -802,17 +872,20 @@ syn match vimCtrlChar "[--]" " Beginners - Patterns that involve ^ {{{2 " ========= -if s:vim9script - syn match vimLineComment +^[ \t:]*".*$+ contains=@vimCommentGroup,vimCommentString,vimCommentTitle contained - syn match vim9LineComment +^[ \t:]*#.*$+ contains=@vimCommentGroup,vimCommentString,vim9CommentTitle -else - syn match vimLineComment +^[ \t:]*".*$+ contains=@vimCommentGroup,vimCommentString,vimCommentTitle - syn match vim9LineComment +^[ \t:]*#.*$+ contains=@vimCommentGroup,vimCommentString,vim9CommentTitle contained -endif +Vim9 syn region vim9LineComment start=+^[ \t:]*\zs#.*$+ skip=+\n\s*\\\|\n\s*#\\ + end="$" contains=@vimCommentGroup,vimCommentString,vim9CommentTitle extend +VimL syn region vimLineComment start=+^[ \t:]*\zs".*$+ skip=+\n\s*\\\|\n\s*"\\ + end="$" contains=@vimCommentGroup,vimCommentString,vimCommentTitle extend + syn match vimCommentTitle '"\s*\%([sS]:\|\h\w*#\)\=\u\w*\(\s\+\u\w*\)*:'hs=s+1 contained contains=vimCommentTitleLeader,vimTodo,@vimCommentGroup syn match vim9CommentTitle '#\s*\%([sS]:\|\h\w*#\)\=\u\w*\(\s\+\u\w*\)*:'hs=s+1 contained contains=vim9CommentTitleLeader,vimTodo,@vimCommentGroup + +" allowed anywhere in the file +if !s:vim9script + syn match vimShebangError "^\s*\zs#!.*" display +endif +syn match vimShebang "\%^#!.*" display + syn match vimContinue "^\s*\zs\\" -syn match vimContinueComment '^\s*\zs["#]\\ .*' contained +syn match vimContinueComment '^\s*\zs["#]\\ .*' syn cluster vimContinue contains=vimContinue,vimContinueComment syn region vimString start="^\s*\\\z(['"]\)" skip='\\\\\|\\\z1' end="\z1" oneline keepend contains=@vimStringGroup,vimContinue syn match vimCommentTitleLeader '"\s\+'ms=s+1 contained @@ -845,12 +918,12 @@ endif " Allows users to specify the type of embedded script highlighting " they want: (perl/python/ruby/tcl support) " g:vimsyn_embed == 0 : don't embed any scripts -" g:vimsyn_embed =~# 'l' : embed lua -" g:vimsyn_embed =~# 'm' : embed mzscheme -" g:vimsyn_embed =~# 'p' : embed perl -" g:vimsyn_embed =~# 'P' : embed python -" g:vimsyn_embed =~# 'r' : embed ruby -" g:vimsyn_embed =~# 't' : embed tcl +" g:vimsyn_embed =~# 'l' : embed Lua +" g:vimsyn_embed =~# 'm' : embed MzScheme +" g:vimsyn_embed =~# 'p' : embed Perl +" g:vimsyn_embed =~# 'P' : embed Python +" g:vimsyn_embed =~# 'r' : embed Ruby +" g:vimsyn_embed =~# 't' : embed Tcl if !exists("g:vimsyn_embed") let g:vimsyn_embed = 'l' endif @@ -869,12 +942,16 @@ if g:vimsyn_embed =~# 'l' && filereadable(s:luapath) unlet! b:current_syntax syn cluster vimFuncBodyList add=vimLuaRegion exe "syn include @vimLuaScript ".s:luapath - VimFoldl syn region vimLuaRegion matchgroup=vimScriptDelim start=+lua\s*<<\s*\z(.*\)$+ end=+^\z1$+ contains=@vimLuaScript - VimFoldl syn region vimLuaRegion matchgroup=vimScriptDelim start=+lua\s*<<\s*$+ end=+\.$+ contains=@vimLuaScript + VimFoldl syn region vimLuaRegion matchgroup=vimScriptDelim start=+^\z(\s*\)lua\s*<<\s*trim\s\+\z(\S\+\)+ end=+^\z1\z2$+ contains=@vimLuaScript + VimFoldl syn region vimLuaRegion matchgroup=vimScriptDelim start=+lua\s*<<\s*\z(\S*\)+ end=+^\z1$+ contains=@vimLuaScript + VimFoldl syn region vimLuaRegion matchgroup=vimScriptDelim start=+^\z(\s*\)lua\s*<<\s*trim\s*$+ end=+^\z1\.$+ contains=@vimLuaScript + VimFoldl syn region vimLuaRegion matchgroup=vimScriptDelim start=+lua\s*<<\s*$+ end=+^\.$+ contains=@vimLuaScript syn cluster vimFuncBodyList add=vimLuaRegion else - syn region vimEmbedError start=+lua\s*<<\s*\z(.*\)$+ end=+^\z1$+ - syn region vimEmbedError start=+lua\s*<<\s*$+ end=+\.$+ + syn region vimEmbedError start=+^\z(\s*\)lua\s*<<\s*trim\s\+\z(\S\+\)+ end=+^\z1\z2$+ + syn region vimEmbedError start=+lua\s*<<\s*\z(\S*\)+ end=+^\z1$+ + syn region vimEmbedError start=+^\z(\s*\)lua\s*<<\s*trim\s\*$+ end=+^\z1\.$+ + syn region vimEmbedError start=+lua\s*<<\s*$+ end=+^\.$+ endif unlet s:luapath @@ -894,12 +971,16 @@ if g:vimsyn_embed =~# 'p' && filereadable(s:perlpath) let s:foldmethod = &l:foldmethod exe "syn include @vimPerlScript ".s:perlpath let &l:foldmethod = s:foldmethod - VimFoldp syn region vimPerlRegion matchgroup=vimScriptDelim start=+pe\%[rl]\s*<<\s*\z(\S*\)\ze\(\s*["#].*\)\=$+ end=+^\z1\ze\(\s*[#"].*\)\=$+ contains=@vimPerlScript - VimFoldp syn region vimPerlRegion matchgroup=vimScriptDelim start=+pe\%[rl]\s*<<\s*$+ end=+\.$+ contains=@vimPerlScript + VimFoldp syn region vimPerlRegion matchgroup=vimScriptDelim start=+^\z(\s*\)pe\%[rl]\s*<<\s*trim\s\+\z(\S\+\)+ end=+^\z1\z2$+ contains=@vimPerlScript + VimFoldp syn region vimPerlRegion matchgroup=vimScriptDelim start=+pe\%[rl]\s*<<\s*\z(\S*\)+ end=+^\z1$+ contains=@vimPerlScript + VimFoldp syn region vimPerlRegion matchgroup=vimScriptDelim start=+^\z(\s*\)pe\%[rl]\s*<<\s*trim\s*$+ end=+^\z1\.$+ contains=@vimPerlScript + VimFoldp syn region vimPerlRegion matchgroup=vimScriptDelim start=+pe\%[rl]\s*<<\s*$+ end=+\.$+ contains=@vimPerlScript syn cluster vimFuncBodyList add=vimPerlRegion else - syn region vimEmbedError start=+pe\%[rl]\s*<<\s*\z(.*\)$+ end=+^\z1$+ - syn region vimEmbedError start=+pe\%[rl]\s*<<\s*$+ end=+\.$+ + syn region vimEmbedError start=+^\z(\s*\)pe\%[rl]\s*<<\s*trim\s\+\z(\S\+\)+ end=+^\z1\z2$+ + syn region vimEmbedError start=+pe\%[rl]\s*<<\s*\z(\S*\)+ end=+^\z1$+ + syn region vimEmbedError start=+^\z(\s*\)pe\%[rl]\s*<<\s*trim\s\*$+ end=+^\z1\.$+ + syn region vimEmbedError start=+pe\%[rl]\s*<<\s*$+ end=+^\.$+ endif unlet s:perlpath @@ -919,12 +1000,16 @@ if g:vimsyn_embed =~# 'r' && filereadable(s:rubypath) let s:foldmethod = &l:foldmethod exe "syn include @vimRubyScript ".s:rubypath let &l:foldmethod = s:foldmethod - VimFoldr syn region vimRubyRegion matchgroup=vimScriptDelim start=+rub[y]\s*<<\s*\z(\S*\)\ze\(\s*#.*\)\=$+ end=+^\z1\ze\(\s*".*\)\=$+ contains=@vimRubyScript - syn region vimRubyRegion matchgroup=vimScriptDelim start=+rub[y]\s*<<\s*$+ end=+\.$+ contains=@vimRubyScript + VimFoldr syn region vimRubyRegion matchgroup=vimScriptDelim start=+^\z(\s*\)rub\%[y]\s*<<\s*trim\s\+\z(\S\+\)+ end=+^\z1\z2$+ contains=@vimRubyScript + VimFoldr syn region vimRubyRegion matchgroup=vimScriptDelim start=+rub\%[y]\s*<<\s*\z(\S*\)+ end=+^\z1$+ contains=@vimRubyScript + VimFoldr syn region vimRubyRegion matchgroup=vimScriptDelim start=+^\z(\s*\)rub\%[y]\s*<<\s*trim\s*$+ end=+^\z1\.$+ contains=@vimRubyScript + VimFoldr syn region vimRubyRegion matchgroup=vimScriptDelim start=+rub\%[y]\s*<<\s*$+ end=+\.$+ contains=@vimRubyScript syn cluster vimFuncBodyList add=vimRubyRegion else - syn region vimEmbedError start=+rub[y]\s*<<\s*\z(.*\)$+ end=+^\z1$+ - syn region vimEmbedError start=+rub[y]\s*<<\s*$+ end=+\.$+ + syn region vimEmbedError start=+^\z(\s*\)rub\%[y]\s*<<\s*trim\s\+\z(\S\+\)+ end=+^\z1\z2$+ + syn region vimEmbedError start=+rub\%[y]\s*<<\s*\z(\S.*\)+ end=+^\z1$+ + syn region vimEmbedError start=+^\z(\s*\)rub\%[y]\s*<<\s*trim\s\*$+ end=+^\z1\.$+ + syn region vimEmbedError start=+rub\%[y]\s*<<\s*$+ end=+^\.$+ endif unlet s:rubypath @@ -942,14 +1027,18 @@ if g:vimsyn_embed =~# 'P' && filereadable(s:pythonpath) unlet! b:current_syntax syn cluster vimFuncBodyList add=vimPythonRegion exe "syn include @vimPythonScript ".s:pythonpath - VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+py\%[thon][3x]\=\s*<<\s*\%(trim\s*\)\=\z(\S*\)\ze\(\s*#.*\)\=$+ end=+^\z1\ze\(\s*".*\)\=$+ contains=@vimPythonScript - VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+py\%[thon][3x]\=\s*<<\s*\%(trim\s*\)\=$+ end=+\.$+ contains=@vimPythonScript - VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+Py\%[thon]2or3\s*<<\s*\%(trim\s*\)\=\z(\S*\)\ze\(\s*#.*\)\=$+ end=+^\z1\ze\(\s*".*\)\=$+ contains=@vimPythonScript - VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+Py\%[thon]2or3\=\s*<<\s*\%(trim\s*\)\=$+ end=+\.$+ contains=@vimPythonScript + VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+^\z(\s*\)py\%[thon][3x]\=\s*<<\s*trim\s\+\z(\S\+\)+ end=+^\z1\z2$+ contains=@vimPythonScript + VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+py\%[thon][3x]\=\s*<<\s*\z(\S\+\)+ end=+^\z1$+ contains=@vimPythonScript + VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+^\z(\s*\)py\%[thon][3x]\=\s*<<\s*trim\s*$+ end=+^\z1\.$+ contains=@vimPythonScript + VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+py\%[thon][3x]\=\s*<<\s*$+ end=+^\.$+ contains=@vimPythonScript + VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+Py\%[thon]2or3\s*<<\s*\%(trim\s*\)\=\z(\S\+\)+ end=+^\z1$+ contains=@vimPythonScript + VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+Py\%[thon]2or3\s*<<\s*\%(trim\s*\)\=$+ end=+^\.$+ contains=@vimPythonScript syn cluster vimFuncBodyList add=vimPythonRegion else - syn region vimEmbedError start=+py\%[thon]3\=\s*<<\s*\z(.*\)$+ end=+^\z1$+ - syn region vimEmbedError start=+py\%[thon]3\=\s*<<\s*$+ end=+\.$+ + syn region vimEmbedError start=+^\z(\s*\)py\%[thon][3x]\=\s*<<\s*trim\s\+\z(\S\+\)+ end=+^\z1\z2$+ + syn region vimEmbedError start=+py\%[thon][3x]\=\s*<<\s*\z(\S\+\)+ end=+^\z1$+ + syn region vimEmbedError start=+^\z(\s*\)py\%[thon][3x]\=\s*<<\s*trim\s*$+ end=+^\z1\.$+ + syn region vimEmbedError start=+py\%[thon][3x]\=\s*<<\s*$+ end=+^\.$+ endif unlet s:pythonpath @@ -974,17 +1063,23 @@ if s:trytcl unlet! b:current_syntax syn cluster vimFuncBodyList add=vimTclRegion exe "syn include @vimTclScript ".s:tclpath - VimFoldt syn region vimTclRegion matchgroup=vimScriptDelim start=+tc[l]\=\s*<<\s*\z(.*\)$+ end=+^\z1$+ contains=@vimTclScript - VimFoldt syn region vimTclRegion matchgroup=vimScriptDelim start=+tc[l]\=\s*<<\s*$+ end=+\.$+ contains=@vimTclScript + VimFoldt syn region vimTclRegion matchgroup=vimScriptDelim start=+^\z(\s*\)tc\%[l]\s*<<\s*trim\s\+\z(\S\+\)+ end=+^\z1\z2$+ contains=@vimTclScript + VimFoldt syn region vimTclRegion matchgroup=vimScriptDelim start=+tc\%[l]\=\s*<<\s*\z(\S*\)+ end=+^\z1$+ contains=@vimTclScript + VimFoldt syn region vimTclRegion matchgroup=vimScriptDelim start=+^\z(\s*\)tc\%[l]\s*<<\s*trim\s*$+ end=+^\z1\.$+ contains=@vimTclScript + VimFoldt syn region vimTclRegion matchgroup=vimScriptDelim start=+tc\%[l]\=\s*<<\s*$+ end=+^\.$+ contains=@vimTclScript syn cluster vimFuncBodyList add=vimTclScript else - syn region vimEmbedError start=+tc[l]\=\s*<<\s*\z(.*\)$+ end=+^\z1$+ - syn region vimEmbedError start=+tc[l]\=\s*<<\s*$+ end=+\.$+ + syn region vimEmbedError start=+^\z(\s*\)tc\%[l]\s*<<\s*trim\s\+\z(\S\+\)+ end=+^\z1\z2$+ + syn region vimEmbedError start=+tc\%[l]\=\s*<<\s*\z(\S*\)+ end=+^\z1$+ + syn region vimEmbedError start=+^\z(\s*\)tc\%[l]\s*<<\s*trim\s\*$+ end=+^\z1\.$+ + syn region vimEmbedError start=+tc\%[l]\=\s*<<\s*$+ end=+^\.$+ endif unlet s:tclpath else - syn region vimEmbedError start=+tc[l]\=\s*<<\s*\z(.*\)$+ end=+^\z1$+ - syn region vimEmbedError start=+tc[l]\=\s*<<\s*$+ end=+\.$+ + syn region vimEmbedError start=+^\z(\s*\)tc\%[l]\s*<<\s*trim\s\+\z(\S\+\)+ end=+^\z1\z2$+ + syn region vimEmbedError start=+tc\%[l]\=\s*<<\s*\z(\S*\)+ end=+^\z1$+ + syn region vimEmbedError start=+^\z(\s*\)tc\%[l]\s*<<\s*trim\s\*$+ end=+^\z1\.$+ + syn region vimEmbedError start=+tc\%[l]\=\s*<<\s*$+ end=+^\.$+ endif unlet s:trytcl @@ -1005,12 +1100,16 @@ if g:vimsyn_embed =~# 'm' && filereadable(s:mzschemepath) exe "syn include @vimMzSchemeScript ".s:mzschemepath let &isk= s:iskKeep unlet s:iskKeep - VimFoldm syn region vimMzSchemeRegion matchgroup=vimScriptDelim start=+mz\%[scheme]\s*<<\s*\z(.*\)$+ end=+^\z1$+ contains=@vimMzSchemeScript - VimFoldm syn region vimMzSchemeRegion matchgroup=vimScriptDelim start=+mz\%[scheme]\s*<<\s*$+ end=+\.$+ contains=@vimMzSchemeScript + VimFoldm syn region vimMzSchemeRegion matchgroup=vimScriptDelim start=+^\z(\s*\)mz\%[scheme]\s*<<\s*trim\s\+\z(\S\+\)+ end=+^\z1\z2$+ contains=@vimMzSchemeScript + VimFoldm syn region vimMzSchemeRegion matchgroup=vimScriptDelim start=+mz\%[scheme]\s*<<\s*\z(\S*\)+ end=+^\z1$+ contains=@vimMzSchemeScript + VimFoldm syn region vimMzSchemeRegion matchgroup=vimScriptDelim start=+^\z(\s*\)mz\%[scheme]\s*<<\s*trim\s*$+ end=+^\z1\.$+ contains=@vimMzSchemeScript + VimFoldm syn region vimMzSchemeRegion matchgroup=vimScriptDelim start=+mz\%[scheme]\s*<<\s*$+ end=+^\.$+ contains=@vimMzSchemeScript syn cluster vimFuncBodyList add=vimMzSchemeRegion else - syn region vimEmbedError start=+mz\%[scheme]\s*<<\s*\z(.*\)$+ end=+^\z1$+ - syn region vimEmbedError start=+mz\%[scheme]\s*<<\s*$+ end=+\.$+ + syn region vimEmbedError start=+^\z(\s*\)mz\%[scheme]\s*<<\s*trim\s\+\z(\S\+\)+ end=+^\z1\z2$+ + syn region vimEmbedError start=+mz\%[scheme]\s*<<\s*\z(\S*\)+ end=+^\z1$+ + syn region vimEmbedError start=+^\z(\s*\)mz\%[scheme]\s*<<\s*trim\s\*$+ end=+^\z1\.$+ + syn region vimEmbedError start=+mz\%[scheme]\s*<<\s*$+ end=+^\.$+ endif unlet s:mzschemepath @@ -1041,13 +1140,13 @@ if !exists("skip_vim_syntax_inits") hi def link vimHiCtermError vimError hi def link vimHiKeyError vimError hi def link vimMapModErr vimError + hi def link vimShebangError vimError hi def link vimSubstFlagErr vimError hi def link vimSynCaseError vimError hi def link vimSynFoldMethodError vimError hi def link vimBufnrWarn vimWarn endif - hi def link vim9Vim9ScriptArg Special hi def link vimAbb vimCommand hi def link vimAddress vimMark hi def link vimAugroupBang vimBang @@ -1061,21 +1160,24 @@ if !exists("skip_vim_syntax_inits") hi def link vimBehaveModel vimBehave hi def link vimBehave vimCommand hi def link vimBracket Delimiter + hi def link vimCall vimCommand + hi def link vimCatch vimCommand hi def link vimCmplxRepeat SpecialChar hi def link vimCommand Statement hi def link vimComment Comment - hi def link vim9Comment Comment + hi def link vimCommentError vimError hi def link vimCommentString vimString hi def link vimCommentTitle PreProc - hi def link vim9CommentTitle PreProc hi def link vimCondHL vimCommand hi def link vimConst vimCommand hi def link vimContinue Special hi def link vimContinueComment vimComment hi def link vimCtrlChar SpecialChar - hi def link vimDefComment vimComment + hi def link vimDefComment vim9Comment hi def link vimDefKey vimCommand hi def link vimDefParam vimVar + hi def link vimDelcommand vimCommand + hi def link vimDelcommandAttr vimUserCmdAttr hi def link vimEcho vimCommand hi def link vimEchohlNone vimGroup hi def link vimEchohl vimCommand @@ -1135,13 +1237,15 @@ if !exists("skip_vim_syntax_inits") hi def link vimLetHereDocStop Special hi def link vimLetRegister Special hi def link vimLineComment vimComment - hi def link vim9LineComment vimComment hi def link vimMapBang vimBang hi def link vimMapModKey vimFuncSID hi def link vimMapMod vimBracket hi def link vimMap vimCommand hi def link vimMark Number hi def link vimMarkNumber vimNumber + hi def link vimMatch vimCommand + hi def link vimMatchGroup vimGroup + hi def link vimMatchNone vimGroup hi def link vimMenuBang vimBang hi def link vimMenuClear Special hi def link vimMenuMod vimMapMod @@ -1174,10 +1278,17 @@ if !exists("skip_vim_syntax_inits") hi def link vimSearchDelim Statement hi def link vimSearch vimString hi def link vimSep Delimiter + hi def link vimSet vimCommand + hi def link vimSetAll vimOption + hi def link vimSetBang vimBang hi def link vimSetMod vimOption - hi def link vimSetSep Statement + hi def link vimSetSep vimSep hi def link vimSetString vimString - hi def link vim9Vim9Script vimCommand + hi def link vimSetTermcap vimOption + hi def link vimShebang PreProc + hi def link vimSleep vimCommand + hi def link vimSleepArg Constant + hi def link vimSleepBang vimBang hi def link vimSpecFile Identifier hi def link vimSpecFileMod vimSpecFile hi def link vimSpecial Type @@ -1218,22 +1329,39 @@ if !exists("skip_vim_syntax_inits") hi def link vimSynReg Type hi def link vimSyntax vimCommand hi def link vimSynType vimSpecial + hi def link vimThrow vimCommand hi def link vimTodo Todo hi def link vimType Type hi def link vimUnlet vimCommand hi def link vimUnletBang vimBang hi def link vimUnmap vimMap - hi def link vimUserAttrbCmpltFunc Special - hi def link vimUserAttrbCmplt vimSpecial - hi def link vimUserAttrbKey vimOption - hi def link vimUserAttrb vimSpecial - hi def link vimUserAttrbError Error + hi def link vimUserCmdAttrAddr vimSpecial + hi def link vimUserCmdAttrCmplt vimSpecial + hi def link vimUserCmdAttrNargs vimSpecial + hi def link vimUserCmdAttrRange vimSpecial + hi def link vimUserCmdAttrKey vimUserCmdAttr + hi def link vimUserCmdAttr Special + hi def link vimUserCmdAttrError Error hi def link vimUserCmdError Error - hi def link vimUserCommand vimCommand + hi def link vimUserCmdKey vimCommand hi def link vimUserFunc Normal hi def link vimVar Identifier hi def link vimWarn WarningMsg + hi def link vim9Boolean Boolean + hi def link vim9Comment Comment + hi def link vim9CommentError vimError + hi def link vim9CommentTitle PreProc + hi def link vim9Const vimCommand + hi def link vim9Final vimCommand + hi def link vim9For vimCommand + hi def link vim9LineComment vimComment + hi def link vim9Null Constant + hi def link vim9Var vimCommand + hi def link vim9Variable vimVar + hi def link vim9Vim9Script vimCommand + hi def link vim9Vim9ScriptArg Special + hi def link nvimAutoEvent vimAutoEvent hi def link nvimHLGroup vimHLGroup endif @@ -1243,6 +1371,8 @@ let b:current_syntax = "vim" " --------------------------------------------------------------------- " Cleanup: {{{1 +delc Vim9 +delc VimL delc VimFolda delc VimFoldf delc VimFoldh diff --git a/runtime/syntax/yaml.vim b/runtime/syntax/yaml.vim index 6ec806a4cb..e992bc02e6 100644 --- a/runtime/syntax/yaml.vim +++ b/runtime/syntax/yaml.vim @@ -129,7 +129,7 @@ syn region yamlFlowCollection matchgroup=yamlFlowIndicator start='\[' end='\]' c execute 'syn match yamlPlainScalar /'.s:ns_plain_out.'/' execute 'syn match yamlPlainScalar contained /'.s:ns_plain_in.'/' -execute 'syn match yamlFlowMappingKey /'.s:ns_plain_in.'\%(\s\+'.s:ns_plain_in.'\)*\ze\s*:/ contained '. +execute 'syn match yamlFlowMappingKey /'.s:ns_plain_in.'\%(\s\+'.s:ns_plain_in.'\)*\ze\s*:\%(\s\|$\)/ contained '. \'nextgroup=yamlFlowMappingDelimiter skipwhite' syn match yamlFlowMappingKeyStart /?/ contained nextgroup=@yamlFlowNode skipwhite syn match yamlFlowMappingMerge /<<\ze\s*:/ contained nextgroup=yamlFlowMappingDelimiter skipwhite diff --git a/runtime/syntax/zathurarc.vim b/runtime/syntax/zathurarc.vim index 5e0526d02a..32997c2d2d 100644 --- a/runtime/syntax/zathurarc.vim +++ b/runtime/syntax/zathurarc.vim @@ -3,7 +3,7 @@ " Maintainer: Wu, Zhenyu <wuzhenyu@ustc.edu> " Documentation: https://pwmt.org/projects/zathura/documentation/ " Upstream: https://github.com/Freed-Wu/zathurarc.vim -" Latest Revision: 2024-04-02 +" Latest Revision: 2024-09-16 if exists('b:current_syntax') finish @@ -22,7 +22,7 @@ syntax region zathurarcString start=`'` skip=`\\'` end=`'` syntax keyword zathurarcMode normal fullscreen presentation index syntax keyword zathurarcBoolean true false syntax keyword zathurarcCommand include map set unmap -syntax keyword zathurarcOption abort-clear-search adjust-open advance-pages-per-row completion-bg completion-fg completion-group-bg completion-group-fg completion-highlight-bg completion-highlight-fg continuous-hist-save database dbus-raise-window dbus-service default-bg default-fg exec-command filemonitor first-page-column font guioptions highlight-active-color highlight-color highlight-fg highlight-transparency incremental-search index-active-bg index-active-fg index-bg index-fg inputbar-bg inputbar-fg link-hadjust link-zoom n-completion-items notification-bg notification-error-bg notification-error-fg notification-fg notification-warning-bg notification-warning-fg page-cache-size page-padding page-right-to-left page-thumbnail-size pages-per-row recolor recolor-darkcolor recolor-keephue recolor-lightcolor recolor-reverse-video render-loading render-loading-bg render-loading-fg sandbox scroll-full-overlap scroll-hstep scroll-page-aware scroll-step scroll-wrap search-hadjust selection-clipboard selection-notification show-directories show-hidden show-recent statusbar-basename statusbar-bg statusbar-fg statusbar-h-padding statusbar-home-tilde statusbar-page-percent statusbar-v-padding synctex synctex-editor-command vertical-center window-height window-icon window-icon-document window-title-basename window-title-home-tilde window-title-page window-width zoom-center zoom-max zoom-min zoom-step +syntax keyword zathurarcOption abort-clear-search adjust-open advance-pages-per-row completion-bg completion-fg completion-group-bg completion-group-fg completion-highlight-bg completion-highlight-fg continuous-hist-save database dbus-raise-window dbus-service default-bg default-fg double-click-follow exec-command filemonitor first-page-column font guioptions highlight-active-color highlight-color highlight-fg highlight-transparency incremental-search index-active-bg index-active-fg index-bg index-fg inputbar-bg inputbar-fg link-hadjust link-zoom n-completion-items notification-bg notification-error-bg notification-error-fg notification-fg notification-warning-bg notification-warning-fg page-cache-size page-padding page-right-to-left page-thumbnail-size pages-per-row recolor recolor-darkcolor recolor-keephue recolor-lightcolor recolor-reverse-video render-loading render-loading-bg render-loading-fg sandbox scroll-full-overlap scroll-hstep scroll-page-aware scroll-step scroll-wrap search-hadjust selection-clipboard selection-notification show-directories show-hidden show-recent statusbar-basename statusbar-bg statusbar-fg statusbar-h-padding statusbar-home-tilde statusbar-page-percent statusbar-v-padding synctex synctex-editor-command vertical-center window-height window-icon window-icon-document window-title-basename window-title-home-tilde window-title-page window-width zoom-center zoom-max zoom-min zoom-step highlight default link zathurarcComment Comment highlight default link zathurarcNumber Number diff --git a/runtime/tools/emoji_list.lua b/runtime/tools/emoji_list.lua new file mode 100644 index 0000000000..63bbbe4371 --- /dev/null +++ b/runtime/tools/emoji_list.lua @@ -0,0 +1,19 @@ +-- Script to fill the window with emoji characters, one per line. +-- Source this script: :source % + +if vim.bo.modified then + vim.cmd.new() +else + vim.cmd.enew() +end + +local lnum = 1 +for c = 0x100, 0x1ffff do + local cs = vim.fn.nr2char(c) + if vim.fn.charclass(cs) == 3 then + vim.fn.setline(lnum, string.format('|%s| %d', cs, vim.fn.strwidth(cs))) + lnum = lnum + 1 + end +end + +vim.bo.modified = false diff --git a/runtime/tools/emoji_list.vim b/runtime/tools/emoji_list.vim deleted file mode 100644 index c335b8c88f..0000000000 --- a/runtime/tools/emoji_list.vim +++ /dev/null @@ -1,21 +0,0 @@ -" Script to fill the window with emoji characters, one per line. -" Source this script: :source % - -if &modified - new -else - enew -endif - -lua << EOF - local lnum = 1 - for c = 0x100, 0x1ffff do - local cs = vim.fn.nr2char(c) - if vim.fn.charclass(cs) == 3 then - vim.fn.setline(lnum, '|' .. cs .. '| ' .. vim.fn.strwidth(cs)) - lnum = lnum + 1 - end - end -EOF - -set nomodified diff --git a/runtime/tutor/en/vim-01-beginner.tutor b/runtime/tutor/en/vim-01-beginner.tutor index 622eb7cc06..e6b81d63b9 100644 --- a/runtime/tutor/en/vim-01-beginner.tutor +++ b/runtime/tutor/en/vim-01-beginner.tutor @@ -888,7 +888,7 @@ NOTE: If you want to ignore case for just one search command, use [\c](/\c) Neovim has a comprehensive online help system. -To get started, try one of these three: +To get started, try one of these two: - press the `<F1>`{normal} key (if you have one) - type `:help`{vim} diff --git a/runtime/tutor/en/vim-01-beginner.tutor.json b/runtime/tutor/en/vim-01-beginner.tutor.json index 8f88a3897d..835f0f6782 100644 --- a/runtime/tutor/en/vim-01-beginner.tutor.json +++ b/runtime/tutor/en/vim-01-beginner.tutor.json @@ -11,13 +11,13 @@ "232": "Somebody typed the end of this line twice.", "271": -1, "290": "This line of words is cleaned up.", - "307": -1, - "308": -1, - "309": -1, - "310": -1, - "311": -1, - "312": -1, - "313": -1, + "307": "1) Roses are red,", + "308": "3) Violets are blue,", + "309": "6) Sugar is sweet", + "310": "7) And so are you.", + "311": "7) And so are you.", + "312": "7) And so are you.", + "313": "7) And so are you.", "333": "Fix the errors on this line and replace them with undo.", "379": -1, "380": -1, diff --git a/runtime/windows_icon.rc b/runtime/windows_icon.rc new file mode 100644 index 0000000000..87b79e9ea7 --- /dev/null +++ b/runtime/windows_icon.rc @@ -0,0 +1,4 @@ +// NOTE: this resource file *must* be in the same folder as the icon. +// Otherwise, absolute paths would need to be used. +// see https://learn.microsoft.com/en-us/windows/win32/menurc/icon-resource +NEOVIM_ICON ICON "neovim.ico" diff --git a/scripts/bump_deps.lua b/scripts/bump_deps.lua index c5294893e0..e332ef475f 100755 --- a/scripts/bump_deps.lua +++ b/scripts/bump_deps.lua @@ -81,6 +81,14 @@ local function get_dependency(dependency_name) repo = 'luvit/luv', symbol = 'LUV', }, + ['unibilium'] = { + repo = 'neovim/unibilium', + symbol = 'UNIBILIUM', + }, + ['utf8proc'] = { + repo = 'JuliaStrings/utf8proc', + symbol = 'UTF8PROC', + }, ['tree-sitter'] = { repo = 'tree-sitter/tree-sitter', symbol = 'TREESITTER', @@ -90,11 +98,11 @@ local function get_dependency(dependency_name) symbol = 'TREESITTER_C', }, ['tree-sitter-lua'] = { - repo = 'MunifTanjim/tree-sitter-lua', + repo = 'tree-sitter-grammars/tree-sitter-lua', symbol = 'TREESITTER_LUA', }, ['tree-sitter-vim'] = { - repo = 'neovim/tree-sitter-vim', + repo = 'tree-sitter-grammars/tree-sitter-vim', symbol = 'TREESITTER_VIM', }, ['tree-sitter-vimdoc'] = { @@ -102,9 +110,21 @@ local function get_dependency(dependency_name) symbol = 'TREESITTER_VIMDOC', }, ['tree-sitter-query'] = { - repo = 'nvim-treesitter/tree-sitter-query', + repo = 'tree-sitter-grammars/tree-sitter-query', symbol = 'TREESITTER_QUERY', }, + ['tree-sitter-markdown'] = { + repo = 'tree-sitter-grammars/tree-sitter-markdown', + symbol = 'TREESITTER_MARKDOWN', + }, + ['wasmtime'] = { + repo = 'bytecodealliance/wasmtime', + symbol = 'WASMTIME', + }, + ['uncrustify'] = { + repo = 'uncrustify/uncrustify', + symbol = 'UNCRUSTIFY', + }, } local dependency = dependency_table[dependency_name] if dependency == nil then diff --git a/scripts/gen_eval_files.lua b/scripts/gen_eval_files.lua index f1bba5c0a2..b9ea4e73f0 100755 --- a/scripts/gen_eval_files.lua +++ b/scripts/gen_eval_files.lua @@ -2,11 +2,15 @@ -- Generator for various vimdoc and Lua type files +local util = require('scripts.util') +local fmt = string.format + local DEP_API_METADATA = 'build/funcs_metadata.mpack' +local TEXT_WIDTH = 78 --- @class vim.api.metadata --- @field name string ---- @field parameters {[1]:string,[2]:string}[] +--- @field parameters [string,string][] --- @field return_type string --- @field deprecated_since integer --- @field eval boolean @@ -20,7 +24,7 @@ local DEP_API_METADATA = 'build/funcs_metadata.mpack' local LUA_API_RETURN_OVERRIDES = { nvim_buf_get_command = 'table<string,vim.api.keyset.command_info>', - nvim_buf_get_extmark_by_id = 'vim.api.keyset.get_extmark_item', + nvim_buf_get_extmark_by_id = 'vim.api.keyset.get_extmark_item_by_id', nvim_buf_get_extmarks = 'vim.api.keyset.get_extmark_item[]', nvim_buf_get_keymap = 'vim.api.keyset.keymap[]', nvim_get_autocmds = 'vim.api.keyset.get_autocmds.ret[]', @@ -29,11 +33,11 @@ local LUA_API_RETURN_OVERRIDES = { nvim_get_keymap = 'vim.api.keyset.keymap[]', nvim_get_mark = 'vim.api.keyset.get_mark', - -- Can also return table<string,vim.api.keyset.hl_info>, however we need to + -- Can also return table<string,vim.api.keyset.get_hl_info>, however we need to -- pick one to get some benefit. -- REVISIT lewrus01 (26/01/24): we can maybe add - -- @overload fun(ns: integer, {}): table<string,vim.api.keyset.hl_info> - nvim_get_hl = 'vim.api.keyset.hl_info', + -- @overload fun(ns: integer, {}): table<string,vim.api.keyset.get_hl_info> + nvim_get_hl = 'vim.api.keyset.get_hl_info', nvim_get_mode = 'vim.api.keyset.get_mode', nvim_get_namespaces = 'table<string,integer>', @@ -112,7 +116,7 @@ local API_TYPES = { String = 'string', Array = 'any[]', LuaRef = 'function', - Dictionary = 'table<string,any>', + Dict = 'table<string,any>', Float = 'number', HLGroupID = 'number|string', void = '', @@ -140,7 +144,7 @@ local function api_type(t) return 'vim.api.keyset.' .. d end - local d0 = t:match('^DictionaryOf%((.*)%)') + local d0 = t:match('^DictOf%((.*)%)') if d0 then return 'table<string,' .. api_type(d0) .. '>' end @@ -149,7 +153,7 @@ local function api_type(t) end --- @param f string ---- @param params {[1]:string,[2]:string}[]|true +--- @param params [string,string][]|true --- @return string local function render_fun_sig(f, params) local param_str --- @type string @@ -158,7 +162,7 @@ local function render_fun_sig(f, params) else param_str = table.concat( vim.tbl_map( - --- @param v {[1]:string,[2]:string} + --- @param v [string,string] --- @return string function(v) return v[1] @@ -170,16 +174,16 @@ local function render_fun_sig(f, params) end if LUA_KEYWORDS[f] then - return string.format("vim.fn['%s'] = function(%s) end", f, param_str) + return fmt("vim.fn['%s'] = function(%s) end", f, param_str) else - return string.format('function vim.fn.%s(%s) end', f, param_str) + return fmt('function vim.fn.%s(%s) end', f, param_str) end end --- Uniquify names --- Fix any names that are lua keywords ---- @param params {[1]:string,[2]:string,[3]:string}[] ---- @return {[1]:string,[2]:string,[3]:string}[] +--- @param params [string,string,string][] +--- @return [string,string,string][] local function process_params(params) local seen = {} --- @type table<string,true> local sfx = 1 @@ -199,14 +203,6 @@ local function process_params(params) return params end ---- @class vim.gen_vim_doc_fun ---- @field signature string ---- @field doc string[] ---- @field parameters_doc table<string,string> ---- @field return string[] ---- @field seealso string[] ---- @field annotations string[] - --- @return table<string, vim.EvalFn> local function get_api_meta() local ret = {} --- @type table<string, vim.EvalFn> @@ -245,7 +241,17 @@ local function get_api_meta() for _, fun in pairs(functions) do local deprecated = fun.deprecated_since ~= nil - local params = {} --- @type {[1]:string,[2]:string}[] + local notes = {} --- @type string[] + for _, note in ipairs(fun.notes or {}) do + notes[#notes + 1] = note.desc + end + + local sees = {} --- @type string[] + for _, see in ipairs(fun.see or {}) do + sees[#sees + 1] = see.desc + end + + local params = {} --- @type [string,string][] for _, p in ipairs(fun.params) do params[#params + 1] = { p.name, @@ -258,13 +264,15 @@ local function get_api_meta() signature = 'NA', name = fun.name, params = params, + notes = notes, + see = sees, returns = api_type(fun.returns[1].type), deprecated = deprecated, } if not deprecated then r.desc = fun.desc - r.return_desc = fun.returns[1].desc + r.returns_desc = fun.returns[1].desc end ret[fun.name] = r @@ -278,8 +286,19 @@ end --- Ensure code blocks have one empty line before the start fence and after the closing fence. --- --- @param x string +--- @param special string? +--- | 'see-api-meta' Normalize `@see` for API meta docstrings. --- @return string -local function norm_text(x) +local function norm_text(x, special) + if special == 'see-api-meta' then + -- Try to guess a symbol that actually works in @see. + -- "nvim_xx()" => "vim.api.nvim_xx" + x = x:gsub([=[%|?(nvim_[^.()| ]+)%(?%)?%|?]=], 'vim.api.%1') + -- TODO: Remove backticks when LuaLS resolves: https://github.com/LuaLS/lua-language-server/issues/2889 + -- "|foo|" => "`:help foo`" + x = x:gsub([=[|([^ ]+)|]=], '`:help %1`') + end + return ( x:gsub('|([^ ]+)|', '`%1`') :gsub('\n*>lua', '\n\n```lua') @@ -291,14 +310,13 @@ local function norm_text(x) ) end +--- Generates LuaLS docstring for an API function. --- @param _f string --- @param fun vim.EvalFn --- @param write fun(line: string) local function render_api_meta(_f, fun, write) write('') - local text_utils = require('scripts.text_utils') - if vim.startswith(fun.name, 'nvim__') then write('--- @private') end @@ -309,10 +327,18 @@ local function render_api_meta(_f, fun, write) local desc = fun.desc if desc then - desc = text_utils.md_to_vimdoc(desc, 0, 0, 74) - for _, l in ipairs(split(norm_text(desc))) do - write('--- ' .. l) - end + write(util.prefix_lines('--- ', norm_text(desc))) + end + + -- LuaLS doesn't support @note. Render @note items as a markdown list. + if fun.notes and #fun.notes > 0 then + write('--- Note:') + write(util.prefix_lines('--- ', table.concat(fun.notes, '\n'))) + write('---') + end + + for _, see in ipairs(fun.see or {}) do + write(util.prefix_lines('--- @see ', norm_text(see, 'see-api-meta'))) end local param_names = {} --- @type string[] @@ -322,8 +348,6 @@ local function render_api_meta(_f, fun, write) local pdesc = p[3] if pdesc then local s = '--- @param ' .. p[1] .. ' ' .. p[2] .. ' ' - local indent = #('@param ' .. p[1] .. ' ') - pdesc = text_utils.md_to_vimdoc(pdesc, #s, indent, 74, true) local pdesc_a = split(vim.trim(norm_text(pdesc))) write(s .. pdesc_a[1]) for i = 2, #pdesc_a do @@ -336,15 +360,15 @@ local function render_api_meta(_f, fun, write) write('--- @param ' .. p[1] .. ' ' .. p[2]) end end + if fun.returns ~= '' then - local ret_desc = fun.returns_desc and ' : ' .. fun.returns_desc or '' - ret_desc = text_utils.md_to_vimdoc(ret_desc, 0, 0, 74) + local ret_desc = fun.returns_desc and ' # ' .. fun.returns_desc or '' local ret = LUA_API_RETURN_OVERRIDES[fun.name] or fun.returns - write('--- @return ' .. ret .. ret_desc) + write(util.prefix_lines('--- ', '@return ' .. ret .. ret_desc)) end local param_str = table.concat(param_names, ', ') - write(string.format('function vim.api.%s(%s) end', fun.name, param_str)) + write(fmt('function vim.api.%s(%s) end', fun.name, param_str)) end --- @return table<string, vim.EvalFn> @@ -372,10 +396,14 @@ local function get_api_keysets_meta() return ret end +--- Generates LuaLS docstring for an API keyset. --- @param _f string --- @param fun vim.EvalFn --- @param write fun(line: string) local function render_api_keyset_meta(_f, fun, write) + if string.sub(fun.name, 1, 1) == '_' then + return -- not exported + end write('') write('--- @class vim.api.keyset.' .. fun.name) for _, p in ipairs(fun.params) do @@ -388,6 +416,7 @@ local function get_eval_meta() return require('src/nvim/eval').funcs end +--- Generates LuaLS docstring for a Vimscript "eval" function. --- @param f string --- @param fun vim.EvalFn --- @param write fun(line: string) @@ -397,7 +426,6 @@ local function render_eval_meta(f, fun, write) end local funname = fun.name or f - local params = process_params(fun.params) write('') @@ -421,25 +449,28 @@ local function render_eval_meta(f, fun, write) for i, param in ipairs(params) do local pname, ptype = param[1], param[2] local optional = (pname ~= '...' and i > req_args) and '?' or '' - write(string.format('--- @param %s%s %s', pname, optional, ptype)) + write(fmt('--- @param %s%s %s', pname, optional, ptype)) end if fun.returns ~= false then - write('--- @return ' .. (fun.returns or 'any')) + local ret_desc = fun.returns_desc and ' # ' .. fun.returns_desc or '' + write('--- @return ' .. (fun.returns or 'any') .. ret_desc) end write(render_fun_sig(funname, params)) end +--- Generates vimdoc heading for a Vimscript "eval" function signature. --- @param name string +--- @param name_tag boolean --- @param fun vim.EvalFn --- @param write fun(line: string) -local function render_sig_and_tag(name, fun, write) +local function render_sig_and_tag(name, name_tag, fun, write) if not fun.signature then return end - local tags = { '*' .. name .. '()*' } + local tags = name_tag and { '*' .. name .. '()*' } or {} if fun.tags then for _, t in ipairs(fun.tags) do @@ -447,6 +478,11 @@ local function render_sig_and_tag(name, fun, write) end end + if #tags == 0 then + write(fun.signature) + return + end + local tag = table.concat(tags, ' ') local siglen = #fun.signature local conceal_offset = 2 * (#tags - 1) @@ -456,32 +492,28 @@ local function render_sig_and_tag(name, fun, write) write(string.rep(' ', tag_pad_len) .. tag) write(fun.signature) else - write(string.format('%s%s%s', fun.signature, string.rep(' ', tag_pad_len - siglen), tag)) + write(fmt('%s%s%s', fun.signature, string.rep(' ', tag_pad_len - siglen), tag)) end end +--- Generates vimdoc for a Vimscript "eval" function. --- @param f string --- @param fun vim.EvalFn --- @param write fun(line: string) local function render_eval_doc(f, fun, write) - if fun.deprecated then - return - end - - if not fun.signature then + if fun.deprecated or not fun.signature then return end - if f:find('__%d+$') then - write(fun.signature) - else - render_sig_and_tag(fun.name or f, fun, write) - end + render_sig_and_tag(fun.name or f, not f:find('__%d+$'), fun, write) if not fun.desc then return end + local params = process_params(fun.params) + local req_args = type(fun.args) == 'table' and fun.args[1] or fun.args or 0 + local desc_l = split(vim.trim(fun.desc)) for _, l in ipairs(desc_l) do l = l:gsub('^ ', '') @@ -497,6 +529,26 @@ local function render_eval_doc(f, fun, write) if #desc_l > 0 and not desc_l[#desc_l]:match('^<?$') then write('') end + + if #params > 0 then + write(util.md_to_vimdoc('Parameters: ~', 16, 16, TEXT_WIDTH)) + for i, param in ipairs(params) do + local pname, ptype = param[1], param[2] + local optional = (pname ~= '...' and i > req_args) and '?' or '' + local s = fmt('- %-14s (`%s%s`)', fmt('{%s}', pname), ptype, optional) + write(util.md_to_vimdoc(s, 16, 18, TEXT_WIDTH)) + end + write('') + end + + if fun.returns ~= false then + write(util.md_to_vimdoc('Return: ~', 16, 16, TEXT_WIDTH)) + local ret = ('(`%s`)'):format((fun.returns or 'any')) + ret = ret .. (fun.returns_desc and ' ' .. fun.returns_desc or '') + ret = util.md_to_vimdoc(ret, 18, 18, TEXT_WIDTH) + write(ret) + write('') + end end --- @param d vim.option_defaults @@ -734,9 +786,9 @@ local function render_option_doc(_f, opt, write) local name_str --- @type string if opt.abbreviation then - name_str = string.format("'%s' '%s'", opt.full_name, opt.abbreviation) + name_str = fmt("'%s' '%s'", opt.full_name, opt.abbreviation) else - name_str = string.format("'%s'", opt.full_name) + name_str = fmt("'%s'", opt.full_name) end local otype = opt.type == 'boolean' and 'boolean' or opt.type @@ -744,13 +796,13 @@ local function render_option_doc(_f, opt, write) local v = render_option_default(opt.defaults, true) local pad = string.rep('\t', math.max(1, math.ceil((24 - #name_str) / 8))) if opt.defaults.doc then - local deflen = #string.format('%s%s%s (', name_str, pad, otype) + local deflen = #fmt('%s%s%s (', name_str, pad, otype) --- @type string v = v:gsub('\n', '\n' .. string.rep(' ', deflen - 2)) end - write(string.format('%s%s%s\t(default %s)', name_str, pad, otype, v)) + write(fmt('%s%s%s\t(default %s)', name_str, pad, otype, v)) else - write(string.format('%s\t%s', name_str, otype)) + write(fmt('%s\t%s', name_str, otype)) end write('\t\t\t' .. scope_to_doc(opt.scope) .. scope_more_doc(opt)) diff --git a/scripts/gen_help_html.lua b/scripts/gen_help_html.lua index cdfb85bde6..f6e799508b 100644 --- a/scripts/gen_help_html.lua +++ b/scripts/gen_help_html.lua @@ -1,6 +1,4 @@ --- Converts Vim :help files to HTML. Validates |tag| links and document syntax (parser errors). --- --- NOTE: :helptags checks for duplicate tags, whereas this script checks _links_ (to tags). +--- Converts Nvim :help files to HTML. Validates |tag| links and document syntax (parser errors). -- -- USAGE (For CI/local testing purposes): Simply `make lintdoc` or `scripts/lintdoc.lua`, which -- basically does the following: @@ -23,6 +21,8 @@ -- 1. nvim -V1 -es +"lua require('scripts.gen_help_html')._test()" +q -- -- NOTES: +-- * This script is used by the automation repo: https://github.com/neovim/doc +-- * :helptags checks for duplicate tags, whereas this script checks _links_ (to tags). -- * gen() and validate() are the primary (programmatic) entrypoints. validate() only exists -- because gen() is too slow (~1 min) to run in per-commit CI. -- * visit_node() is the core function used by gen() to traverse the document tree and produce HTML. @@ -68,6 +68,7 @@ local new_layout = { ['dev_theme.txt'] = true, ['dev_tools.txt'] = true, ['dev_vimpatch.txt'] = true, + ['editorconfig.txt'] = true, ['faq.txt'] = true, ['lua.txt'] = true, ['luaref.txt'] = true, @@ -76,10 +77,17 @@ local new_layout = { ['news-0.10.txt'] = true, ['nvim.txt'] = true, ['provider.txt'] = true, + ['tui.txt'] = true, ['ui.txt'] = true, ['vim_diff.txt'] = true, } +-- Map of new:old pages, to redirect renamed pages. +local redirects = { + ['tui'] = 'term', + ['terminal'] = 'nvim_terminal_emulator', +} + -- TODO: These known invalid |links| require an update to the relevant docs. local exclude_invalid = { ["'string'"] = 'eval.txt', @@ -212,6 +220,7 @@ local function is_noise(line, noise_lines) end --- Creates a github issue URL at neovim/tree-sitter-vimdoc with prefilled content. +--- @return string local function get_bug_url_vimdoc(fname, to_fname, sample_text) local this_url = string.format('https://neovim.io/doc/user/%s', vim.fs.basename(to_fname)) local bug_url = ( @@ -227,6 +236,7 @@ local function get_bug_url_vimdoc(fname, to_fname, sample_text) end --- Creates a github issue URL at neovim/neovim with prefilled content. +--- @return string local function get_bug_url_nvim(fname, to_fname, sample_text, token_name) local this_url = string.format('https://neovim.io/doc/user/%s', vim.fs.basename(to_fname)) local bug_url = ( @@ -255,7 +265,7 @@ local function get_helppage(f) return 'index.html' end - return (f:gsub('%.txt$', '.html')) + return (f:gsub('%.txt$', '')) .. '.html' end --- Counts leading spaces (tab=8) to decide the indent size of multiline text. @@ -490,7 +500,6 @@ local function visit_node(root, level, lang_tree, headings, opt, stats) or nil -- Parent kind (string). local parent = root:parent() and root:parent():type() or nil - local text = '' -- Gets leading whitespace of `node`. local function ws(node) node = node or root @@ -508,6 +517,7 @@ local function visit_node(root, level, lang_tree, headings, opt, stats) return string.format('%s%s', ws_, vim.treesitter.get_node_text(node, opt.buf)) end + local text = '' local trimmed ---@type string if root:named_child_count() == 0 or node_name == 'ERROR' then text = node_text() @@ -537,12 +547,17 @@ local function visit_node(root, level, lang_tree, headings, opt, stats) if is_noise(text, stats.noise_lines) then return '' -- Discard common "noise" lines. end - -- Remove "===" and tags from ToC text. - local hname = (node_text():gsub('%-%-%-%-+', ''):gsub('%=%=%=%=+', ''):gsub('%*.*%*', '')) + -- Remove tags from ToC text. + local heading_node = first(root, 'heading') + local hname = trim(node_text(heading_node):gsub('%*.*%*', '')) + if not heading_node or hname == '' then + return '' -- Spurious "===" or "---" in the help doc. + end + -- Use the first *tag* node as the heading anchor, if any. - local tagnode = first(root, 'tag') + local tagnode = first(heading_node, 'tag') -- Use the *tag* as the heading anchor id, if possible. - local tagname = tagnode and url_encode(node_text(tagnode:child(1), false)) + local tagname = tagnode and url_encode(trim(node_text(tagnode:child(1), false))) or to_heading_tag(hname) if node_name == 'h1' or #headings == 0 then ---@type nvim.gen_help_html.heading @@ -555,7 +570,9 @@ local function visit_node(root, level, lang_tree, headings, opt, stats) ) end local el = node_name == 'h1' and 'h2' or 'h3' - return ('<%s id="%s" class="help-heading">%s</%s>\n'):format(el, tagname, text, el) + return ('<%s id="%s" class="help-heading">%s</%s>\n'):format(el, tagname, trimmed, el) + elseif node_name == 'heading' then + return trimmed elseif node_name == 'column_heading' or node_name == 'column_name' then if root:has_error() then return text @@ -648,13 +665,13 @@ local function visit_node(root, level, lang_tree, headings, opt, stats) code = ('<pre>%s</pre>'):format(trim(trim_indent(text), 2)) end return code - elseif node_name == 'tag' then -- anchor + elseif node_name == 'tag' then -- anchor, h4 pseudo-heading if root:has_error() then return text end local in_heading = vim.list_contains({ 'h1', 'h2', 'h3' }, parent) - local cssclass = (not in_heading and get_indent(node_text()) > 8) and 'help-tag-right' - or 'help-tag' + local h4 = not in_heading and not next_ and get_indent(node_text()) > 8 -- h4 pseudo-heading + local cssclass = h4 and 'help-tag-right' or 'help-tag' local tagname = node_text(root:child(1), false) if vim.tbl_count(stats.first_tags) < 2 then -- Force the first 2 tags in the doc to be anchored at the main heading. @@ -694,8 +711,8 @@ local function visit_node(root, level, lang_tree, headings, opt, stats) -- End the <span> container for tags in a heading. return string.format('%s</span>', s) end - return s - elseif node_name == 'modeline' then + return s .. (h4 and '<br>' or '') -- HACK: <br> avoids h4 pseudo-heading mushing with text. + elseif node_name == 'delimiter' or node_name == 'modeline' then return '' elseif node_name == 'ERROR' then if ignore_parse_error(opt.fname, trimmed) then @@ -760,14 +777,21 @@ local function ensure_runtimepath() end end ---- Opens `fname` in a buffer and gets a treesitter parser for the buffer contents. +--- Opens `fname` (or `text`, if given) in a buffer and gets a treesitter parser for the buffer contents. --- ---- @param fname string help file to parse +--- @param fname string :help file to parse +--- @param text string? :help file contents --- @param parser_path string? path to non-default vimdoc.so --- @return vim.treesitter.LanguageTree, integer (lang_tree, bufnr) -local function parse_buf(fname, parser_path) +local function parse_buf(fname, text, parser_path) local buf ---@type integer - if type(fname) == 'string' then + if text then + vim.cmd('split new') -- Text contents. + vim.api.nvim_put(vim.split(text, '\n'), '', false, false) + vim.cmd('setfiletype help') + -- vim.treesitter.language.add('vimdoc') + buf = vim.api.nvim_get_current_buf() + elseif type(fname) == 'string' then vim.cmd('split ' .. vim.fn.fnameescape(fname)) -- Filename. buf = vim.api.nvim_get_current_buf() else @@ -779,7 +803,7 @@ local function parse_buf(fname, parser_path) if parser_path then vim.treesitter.language.add('vimdoc', { path = parser_path }) end - local lang_tree = vim.treesitter.get_parser(buf) + local lang_tree = assert(vim.treesitter.get_parser(buf, nil, { error = false })) return lang_tree, buf end @@ -794,7 +818,7 @@ local function validate_one(fname, parser_path) local stats = { parse_errors = {}, } - local lang_tree, buf = parse_buf(fname, parser_path) + local lang_tree, buf = parse_buf(fname, nil, parser_path) for _, tree in ipairs(lang_tree:trees()) do visit_validate(tree:root(), 0, tree, { buf = buf, fname = fname }, stats) end @@ -805,20 +829,21 @@ end --- Generates HTML from one :help file `fname` and writes the result to `to_fname`. --- ---- @param fname string Source :help file +--- @param fname string Source :help file. +--- @param text string|nil Source :help file contents, or nil to read `fname`. --- @param to_fname string Destination .html file --- @param old boolean Preformat paragraphs (for old :help files which are full of arbitrary whitespace) --- @param parser_path string? path to non-default vimdoc.so --- --- @return string html --- @return table stats -local function gen_one(fname, to_fname, old, commit, parser_path) +local function gen_one(fname, text, to_fname, old, commit, parser_path) local stats = { noise_lines = {}, parse_errors = {}, first_tags = {}, -- Track the first few tags in doc. } - local lang_tree, buf = parse_buf(fname, parser_path) + local lang_tree, buf = parse_buf(fname, text, parser_path) ---@type nvim.gen_help_html.heading[] local headings = {} -- Headings (for ToC). 2-dimensional: h1 contains h2/h3. local title = to_titlecase(basename_noext(fname)) @@ -1126,6 +1151,7 @@ local function gen_css(fname) margin-left: auto; margin-right: 0; float: right; + display: block; } .help-tag a, .help-tag-right a { @@ -1139,10 +1165,11 @@ local function gen_css(fname) font-size: smaller; } .help-heading { - overflow: hidden; - white-space: nowrap; + white-space: normal; display: flex; + flex-flow: row wrap; justify-content: space-between; + gap: 0 15px; } /* The (right-aligned) "tags" part of a section heading. */ .help-heading-tags { @@ -1177,8 +1204,7 @@ local function gen_css(fname) pre:last-child { margin-bottom: 0; } - pre:hover, - .help-heading:hover { + pre:hover { overflow: visible; } .generator-stats { @@ -1216,7 +1242,7 @@ end function M._test() tagmap = get_helptags('$VIMRUNTIME/doc') - helpfiles = get_helpfiles(vim.fn.expand('$VIMRUNTIME/doc')) + helpfiles = get_helpfiles(vim.fs.normalize('$VIMRUNTIME/doc')) ok(vim.tbl_count(tagmap) > 3000, '>3000', vim.tbl_count(tagmap)) ok( @@ -1278,7 +1304,7 @@ function M.gen(help_dir, to_dir, include, commit, parser_path) help_dir = { help_dir, function(d) - return vim.fn.isdirectory(vim.fn.expand(d)) == 1 + return vim.fn.isdirectory(vim.fs.normalize(d)) == 1 end, 'valid directory', }, @@ -1288,40 +1314,88 @@ function M.gen(help_dir, to_dir, include, commit, parser_path) parser_path = { parser_path, function(f) - return f == nil or vim.fn.filereadable(vim.fn.expand(f)) == 1 + return f == nil or vim.fn.filereadable(vim.fs.normalize(f)) == 1 end, 'valid vimdoc.{so,dll} filepath', }, } local err_count = 0 + local redirects_count = 0 ensure_runtimepath() - tagmap = get_helptags(vim.fn.expand(help_dir)) + tagmap = get_helptags(vim.fs.normalize(help_dir)) helpfiles = get_helpfiles(help_dir, include) - to_dir = vim.fn.expand(to_dir) - parser_path = parser_path and vim.fn.expand(parser_path) or nil + to_dir = vim.fs.normalize(to_dir) + parser_path = parser_path and vim.fs.normalize(parser_path) or nil - print(('output dir: %s'):format(to_dir)) + print(('output dir: %s\n\n'):format(to_dir)) vim.fn.mkdir(to_dir, 'p') gen_css(('%s/help.css'):format(to_dir)) for _, f in ipairs(helpfiles) do + -- "foo.txt" local helpfile = vim.fs.basename(f) + -- "to/dir/foo.html" local to_fname = ('%s/%s'):format(to_dir, get_helppage(helpfile)) - local html, stats = gen_one(f, to_fname, not new_layout[helpfile], commit or '?', parser_path) + local html, stats = + gen_one(f, nil, to_fname, not new_layout[helpfile], commit or '?', parser_path) tofile(to_fname, html) print( - ('generated (%-4s errors): %-15s => %s'):format( + ('generated (%-2s errors): %-15s => %s'):format( #stats.parse_errors, helpfile, vim.fs.basename(to_fname) ) ) + + -- Generate redirect pages for renamed help files. + local helpfile_tag = (helpfile:gsub('%.txt$', '')) + local redirect_from = redirects[helpfile_tag] + if redirect_from then + local redirect_text = ([[ +*%s* Nvim + +This document moved to: |%s| + +============================================================================== +This document moved to: |%s| + +This document moved to: |%s| + +============================================================================== + vim:tw=78:ts=8:ft=help:norl: + ]]):format( + redirect_from, + helpfile_tag, + helpfile_tag, + helpfile_tag, + helpfile_tag, + helpfile_tag + ) + local redirect_to = ('%s/%s'):format(to_dir, get_helppage(redirect_from)) + local redirect_html, _ = + gen_one(redirect_from, redirect_text, redirect_to, false, commit or '?', parser_path) + assert(redirect_html:find(helpfile_tag)) + tofile(redirect_to, redirect_html) + + print( + ('generated (redirect) : %-15s => %s'):format( + redirect_from .. '.txt', + vim.fs.basename(to_fname) + ) + ) + redirects_count = redirects_count + 1 + end + err_count = err_count + #stats.parse_errors end - print(('generated %d html pages'):format(#helpfiles)) + + print(('\ngenerated %d html pages'):format(#helpfiles + redirects_count)) print(('total errors: %d'):format(err_count)) - print(('invalid tags:\n%s'):format(vim.inspect(invalid_links))) + print(('invalid tags: %s'):format(vim.inspect(invalid_links))) + assert(#(include or {}) > 0 or redirects_count == vim.tbl_count(redirects)) -- sanity check + print(('redirects: %d'):format(redirects_count)) + print('\n') --- @type nvim.gen_help_html.gen_result return { @@ -1351,7 +1425,7 @@ function M.validate(help_dir, include, parser_path) help_dir = { help_dir, function(d) - return vim.fn.isdirectory(vim.fn.expand(d)) == 1 + return vim.fn.isdirectory(vim.fs.normalize(d)) == 1 end, 'valid directory', }, @@ -1359,7 +1433,7 @@ function M.validate(help_dir, include, parser_path) parser_path = { parser_path, function(f) - return f == nil or vim.fn.filereadable(vim.fn.expand(f)) == 1 + return f == nil or vim.fn.filereadable(vim.fs.normalize(f)) == 1 end, 'valid vimdoc.{so,dll} filepath', }, @@ -1367,12 +1441,12 @@ function M.validate(help_dir, include, parser_path) local err_count = 0 ---@type integer local files_to_errors = {} ---@type table<string, string[]> ensure_runtimepath() - tagmap = get_helptags(vim.fn.expand(help_dir)) + tagmap = get_helptags(vim.fs.normalize(help_dir)) helpfiles = get_helpfiles(help_dir, include) - parser_path = parser_path and vim.fn.expand(parser_path) or nil + parser_path = parser_path and vim.fs.normalize(parser_path) or nil for _, f in ipairs(helpfiles) do - local helpfile = assert(vim.fs.basename(f)) + local helpfile = vim.fs.basename(f) local rv = validate_one(f, parser_path) print(('validated (%-4s errors): %s'):format(#rv.parse_errors, helpfile)) if #rv.parse_errors > 0 then @@ -1404,7 +1478,7 @@ end --- --- @param help_dir? string e.g. '$VIMRUNTIME/doc' or './runtime/doc' function M.run_validate(help_dir) - help_dir = vim.fn.expand(help_dir or '$VIMRUNTIME/doc') + help_dir = vim.fs.normalize(help_dir or '$VIMRUNTIME/doc') print('doc path = ' .. vim.uv.fs_realpath(help_dir)) local rv = M.validate(help_dir) @@ -1430,16 +1504,14 @@ end --- :help files, we can be precise about the tolerances here. --- @param help_dir? string e.g. '$VIMRUNTIME/doc' or './runtime/doc' function M.test_gen(help_dir) - local tmpdir = assert(vim.fs.dirname(vim.fn.tempname())) - help_dir = vim.fn.expand(help_dir or '$VIMRUNTIME/doc') + local tmpdir = vim.fs.dirname(vim.fn.tempname()) + help_dir = vim.fs.normalize(help_dir or '$VIMRUNTIME/doc') print('doc path = ' .. vim.uv.fs_realpath(help_dir)) - local rv = M.gen( - help_dir, - tmpdir, - -- Because gen() is slow (~30s), this test is limited to a few files. - { 'help.txt', 'index.txt', 'nvim.txt' } - ) + -- Because gen() is slow (~30s), this test is limited to a few files. + local input = { 'help.txt', 'index.txt', 'nvim.txt' } + local rv = M.gen(help_dir, tmpdir, input) + eq(#input, #rv.helpfiles) eq(0, rv.err_count, 'parse errors in :help docs') eq({}, rv.invalid_links, 'invalid tags in :help docs') end diff --git a/scripts/gen_lsp.lua b/scripts/gen_lsp.lua index 04d19f22e6..c8dcf8c018 100644 --- a/scripts/gen_lsp.lua +++ b/scripts/gen_lsp.lua @@ -60,9 +60,10 @@ end local function gen_methods(protocol) local output = { '-- Generated by gen_lsp.lua, keep at end of file.', - '--- LSP method names.', '---', + '---@enum vim.lsp.protocol.Methods', '---@see https://microsoft.github.io/language-server-protocol/specification/#metaModel', + '--- LSP method names.', 'protocol.Methods = {', } local indent = (' '):rep(2) @@ -109,26 +110,8 @@ local function gen_methods(protocol) end end output[#output + 1] = '}' - output = vim.list_extend( - output, - vim.split( - [[ -local function freeze(t) - return setmetatable({}, { - __index = t, - __newindex = function() - error('cannot modify immutable table') - end, - }) -end -protocol.Methods = freeze(protocol.Methods) - -return protocol -]], - '\n', - { trimempty = true } - ) - ) + output[#output + 1] = '' + output[#output + 1] = 'return protocol' local fname = './runtime/lua/vim/lsp/protocol.lua' local bufnr = vim.fn.bufadd(fname) @@ -297,13 +280,13 @@ function M.gen(opt) -- TupleType elseif type.kind == 'tuple' then - local tuple = '{ ' - for i, value in ipairs(type.items) do - tuple = tuple .. '[' .. i .. ']: ' .. parse_type(value, prefix) .. ', ' + local tuple = '[' + for _, value in ipairs(type.items) do + tuple = tuple .. parse_type(value, prefix) .. ', ' end -- remove , at the end tuple = tuple:sub(0, -3) - return tuple .. ' }' + return tuple .. ']' end vim.print('WARNING: Unknown type ', type) diff --git a/scripts/gen_vimdoc.lua b/scripts/gen_vimdoc.lua index 9c6225efc3..8908097397 100755 --- a/scripts/gen_vimdoc.lua +++ b/scripts/gen_vimdoc.lua @@ -18,12 +18,12 @@ local luacats_parser = require('scripts.luacats_parser') local cdoc_parser = require('scripts.cdoc_parser') -local text_utils = require('scripts.text_utils') +local util = require('scripts.util') local fmt = string.format -local wrap = text_utils.wrap -local md_to_vimdoc = text_utils.md_to_vimdoc +local wrap = util.wrap +local md_to_vimdoc = util.md_to_vimdoc local TEXT_WIDTH = 78 local INDENTATION = 4 @@ -50,7 +50,7 @@ local INDENTATION = 4 --- For generated section names. --- @field section_fmt fun(name: string): string --- ---- @field helptag_fmt fun(name: string): string +--- @field helptag_fmt fun(name: string): string|string[] --- --- Per-function helptag. --- @field fn_helptag_fmt? fun(fun: nvim.luacats.parser.fun): string @@ -273,6 +273,7 @@ local config = { 'buf.lua', 'diagnostic.lua', 'codelens.lua', + 'completion.lua', 'inlay_hint.lua', 'tagfunc.lua', 'semantic_tokens.lua', @@ -318,6 +319,8 @@ local config = { treesitter = { filename = 'treesitter.txt', section_order = { + 'tstree.lua', + 'tsnode.lua', 'treesitter.lua', 'language.lua', 'query.lua', @@ -326,18 +329,27 @@ local config = { 'dev.lua', }, files = { + 'runtime/lua/vim/treesitter/_meta/', 'runtime/lua/vim/treesitter.lua', 'runtime/lua/vim/treesitter/', }, section_fmt = function(name) if name:lower() == 'treesitter' then return 'Lua module: vim.treesitter' + elseif name:lower() == 'tstree' then + return 'TREESITTER TREES' + elseif name:lower() == 'tsnode' then + return 'TREESITTER NODES' end return 'Lua module: vim.treesitter.' .. name:lower() end, helptag_fmt = function(name) if name:lower() == 'treesitter' then return 'lua-treesitter-core' + elseif name:lower() == 'tstree' then + return { 'treesitter-tree', 'TSTree' } + elseif name:lower() == 'tsnode' then + return { 'treesitter-node', 'TSNode' } end return 'lua-treesitter-' .. name:lower() end, @@ -372,8 +384,8 @@ local config = { section_fmt = function(_name) return 'Checkhealth' end, - helptag_fmt = function(name) - return name:lower() + helptag_fmt = function() + return { 'vim.health', 'health' } end, }, } @@ -420,8 +432,11 @@ local function render_type(ty, generics, default) end --- @param p nvim.luacats.parser.param|nvim.luacats.parser.field -local function should_render_param(p) - return not p.access and not contains(p.name, { '_', 'self' }) +local function should_render_field_or_param(p) + return not p.nodoc + and not p.access + and not contains(p.name, { '_', 'self' }) + and not vim.startswith(p.name, '_') end --- @param desc? string @@ -523,7 +538,7 @@ end local function render_fields_or_params(xs, generics, classes, exclude_types) local ret = {} --- @type string[] - xs = vim.tbl_filter(should_render_param, xs) + xs = vim.tbl_filter(should_render_field_or_param, xs) local indent = 0 for _, p in ipairs(xs) do @@ -715,19 +730,25 @@ local function render_fun(fun, classes, cfg) table.insert(ret, render_fun_header(fun, cfg)) table.insert(ret, '\n') - if fun.desc then - table.insert(ret, md_to_vimdoc(fun.desc, INDENTATION, INDENTATION, TEXT_WIDTH)) - end - if fun.since then - local since = tonumber(fun.since) + local since = assert(tonumber(fun.since), 'invalid @since on ' .. fun.name) local info = nvim_api_info() - if since and (since > info.level or since == info.level and info.prerelease) then - fun.notes = fun.notes or {} - table.insert(fun.notes, { desc = 'This API is pre-release (unstable).' }) + if since == 0 or (info.prerelease and since == info.level) then + -- Experimental = (since==0 or current prerelease) + local s = 'WARNING: This feature is experimental/unstable.' + table.insert(ret, md_to_vimdoc(s, INDENTATION, INDENTATION, TEXT_WIDTH)) + table.insert(ret, '\n') + else + local v = assert(util.version_level[since], 'invalid @since on ' .. fun.name) + fun.attrs = fun.attrs or {} + table.insert(fun.attrs, ('Since: %s'):format(v)) end end + if fun.desc then + table.insert(ret, md_to_vimdoc(fun.desc, INDENTATION, INDENTATION, TEXT_WIDTH)) + end + if fun.notes then table.insert(ret, '\n Note: ~\n') for _, p in ipairs(fun.notes) do @@ -813,7 +834,7 @@ local function get_script_path() end local script_path = get_script_path() -local base_dir = vim.fs.dirname(assert(vim.fs.dirname(script_path))) +local base_dir = vim.fs.dirname(vim.fs.dirname(script_path)) local function delete_lines_below(doc_file, tokenstr) local lines = {} --- @type string[] @@ -865,7 +886,11 @@ local function make_section(filename, cfg, section_docs, funs_txt) local sectname = cfg.section_name and cfg.section_name[filename] or mktitle(name) -- section tag: e.g., "*api-autocmd*" - local help_tag = '*' .. cfg.helptag_fmt(sectname) .. '*' + local help_labels = cfg.helptag_fmt(sectname) + if type(help_labels) == 'table' then + help_labels = table.concat(help_labels, '* *') + end + local help_tags = '*' .. help_labels .. '*' if funs_txt == '' and #section_docs == 0 then return @@ -874,7 +899,7 @@ local function make_section(filename, cfg, section_docs, funs_txt) return { name = sectname, title = cfg.section_fmt(sectname), - help_tag = help_tag, + help_tag = help_tags, funs_txt = funs_txt, doc = section_docs, } @@ -934,7 +959,7 @@ local function gen_target(cfg) expand_files(cfg.files) - --- @type table<string,{[1]:table<string,nvim.luacats.parser.class>, [2]: nvim.luacats.parser.fun[], [3]: string[]}> + --- @type table<string,[table<string,nvim.luacats.parser.class>, nvim.luacats.parser.fun[], string[]]> local file_results = {} --- @type table<string,nvim.luacats.parser.class> @@ -965,7 +990,7 @@ local function gen_target(cfg) end end -- FIXME: Using f_base will confuse `_meta/protocol.lua` with `protocol.lua` - local f_base = assert(vim.fs.basename(f)) + local f_base = vim.fs.basename(f) sections[f_base] = make_section(f_base, cfg, briefs_txt, funs_txt) end diff --git a/scripts/lintcommit.lua b/scripts/lintcommit.lua index 96f6304247..7cb57de901 100644 --- a/scripts/lintcommit.lua +++ b/scripts/lintcommit.lua @@ -41,12 +41,6 @@ end -- Returns nil if the given commit message is valid, or returns a string -- message explaining why it is invalid. local function validate_commit(commit_message) - -- Return nil if the commit message starts with "fixup" as it signifies it's - -- a work in progress and shouldn't be linted yet. - if vim.startswith(commit_message, 'fixup') then - return nil - end - local commit_split = vim.split(commit_message, ':', { plain = true }) -- Return nil if the type is vim-patch since most of the normal rules don't -- apply. @@ -74,11 +68,12 @@ local function validate_commit(commit_message) if after_idx > vim.tbl_count(commit_split) then return [[Commit message does not include colons.]] end - local after_colon = '' + local after_colon_split = {} while after_idx <= vim.tbl_count(commit_split) do - after_colon = after_colon .. commit_split[after_idx] + table.insert(after_colon_split, commit_split[after_idx]) after_idx = after_idx + 1 end + local after_colon = table.concat(after_colon_split, ':') -- Check if commit introduces a breaking change. if vim.endswith(before_colon, '!') then @@ -229,9 +224,9 @@ function M._test() ['vim-patch:8.2.3374: Pyret files are not recognized (#15642)'] = true, ['vim-patch:8.1.1195,8.2.{3417,3419}'] = true, ['revert: "ci: use continue-on-error instead of "|| true""'] = true, - ['fixup'] = true, - ['fixup: commit message'] = true, - ['fixup! commit message'] = true, + ['fixup'] = false, + ['fixup: commit message'] = false, + ['fixup! commit message'] = false, [':no type before colon 1'] = false, [' :no type before colon 2'] = false, [' :no type before colon 3'] = false, @@ -253,8 +248,10 @@ function M._test() ['unknown: using unknown type'] = false, ['feat: foo:bar'] = true, ['feat: :foo:bar'] = true, + ['feat: :Foo:Bar'] = true, ['feat(something): foo:bar'] = true, ['feat(something): :foo:bar'] = true, + ['feat(something): :Foo:Bar'] = true, ['feat(:grep): read from pipe'] = true, ['feat(:grep/:make): read from pipe'] = true, ['feat(:grep): foo:bar'] = true, diff --git a/scripts/luacats_grammar.lua b/scripts/luacats_grammar.lua index 29f3bda5aa..34c1470fea 100644 --- a/scripts/luacats_grammar.lua +++ b/scripts/luacats_grammar.lua @@ -4,7 +4,7 @@ LPEG grammar for LuaCATS local lpeg = vim.lpeg local P, R, S = lpeg.P, lpeg.R, lpeg.S -local Ct, Cg = lpeg.Ct, lpeg.Cg +local C, Ct, Cg = lpeg.C, lpeg.Ct, lpeg.Cg --- @param x vim.lpeg.Pattern local function rep(x) @@ -23,23 +23,20 @@ end local ws = rep1(S(' \t')) local fill = opt(ws) - local any = P(1) -- (consume one character) -local letter = R('az', 'AZ') + S('_$') +local letter = R('az', 'AZ') local num = R('09') -local ident = letter * rep(letter + num + S '-.') -local string_single = P "'" * rep(any - P "'") * P "'" -local string_double = P('"') * rep(any - P('"')) * P('"') - -local literal = (string_single + string_double + (opt(P('-')) * num) + P('false') + P('true')) -local lname = (ident + P('...')) * opt(P('?')) - ---- @param x string +--- @param x string | vim.lpeg.Pattern local function Pf(x) return fill * P(x) * fill end +--- @param x string | vim.lpeg.Pattern +local function Plf(x) + return fill * P(x) +end + --- @param x string local function Sf(x) return fill * S(x) * fill @@ -72,16 +69,6 @@ local v = setmetatable({}, { end, }) -local colon = Pf(':') -local opt_exact = opt(Cg(Pf('(exact)'), 'access')) -local access = P('private') + P('protected') + P('package') -local caccess = Cg(access, 'access') -local desc_delim = Sf '#:' + ws -local desc = Cg(rep(any), 'desc') -local opt_desc = opt(desc_delim * desc) -local cname = Cg(ident, 'name') -local opt_parent = opt(colon * Cg(ident, 'parent')) - --- @class nvim.luacats.Param --- @field kind 'param' --- @field name string @@ -135,21 +122,69 @@ local function annot(nm, pat) return Ct(Cg(P(nm), 'kind')) end +local colon = Pf(':') +local ellipsis = P('...') +local ident_first = P('_') + letter +local ident = ident_first * rep(ident_first + num) +local opt_ident = ident * opt(P('?')) +local ty_ident_sep = S('-._') +local ty_ident = ident * rep(ty_ident_sep * ident) +local string_single = P "'" * rep(any - P "'") * P "'" +local string_double = P('"') * rep(any - P('"')) * P('"') +local generic = P('`') * ty_ident * P('`') +local literal = string_single + string_double + (opt(P('-')) * rep1(num)) + P('false') + P('true') +local ty_prims = ty_ident + literal + generic + +local array_postfix = rep1(Plf('[]')) +local opt_postfix = rep1(Plf('?')) +local rep_array_opt_postfix = rep(array_postfix + opt_postfix) + +local typedef = P({ + 'typedef', + typedef = C(v.type), + + type = v.ty * rep_array_opt_postfix * rep(Pf('|') * v.ty * rep_array_opt_postfix), + ty = v.composite + paren(v.typedef), + composite = (v.types * array_postfix) + (v.types * opt_postfix) + v.types, + types = v.generics + v.kv_table + v.tuple + v.dict + v.table_literal + v.fun + ty_prims, + + tuple = Pf('[') * comma1(v.type) * Plf(']'), + dict = Pf('{') * comma1(Pf('[') * v.type * Pf(']') * colon * v.type) * Plf('}'), + kv_table = Pf('table') * Pf('<') * v.type * Pf(',') * v.type * Plf('>'), + table_literal = Pf('{') * comma1(opt_ident * Pf(':') * v.type) * Plf('}'), + fun_param = (opt_ident + ellipsis) * opt(colon * v.type), + fun_ret = v.type + (ellipsis * opt(colon * v.type)), + fun = Pf('fun') * paren(comma(v.fun_param)) * opt(Pf(':') * comma1(v.fun_ret)), + generics = P(ty_ident) * Pf('<') * comma1(v.type) * Plf('>'), +}) / function(match) + return vim.trim(match):gsub('^%((.*)%)$', '%1'):gsub('%?+', '?') +end + +local opt_exact = opt(Cg(Pf('(exact)'), 'access')) +local access = P('private') + P('protected') + P('package') +local caccess = Cg(access, 'access') +local desc_delim = Sf '#:' + ws +local desc = Cg(rep(any), 'desc') +local opt_desc = opt(desc_delim * desc) +local ty_name = Cg(ty_ident, 'name') +local opt_parent = opt(colon * Cg(ty_ident, 'parent')) +local lname = (ident + ellipsis) * opt(P('?')) + local grammar = P { rep1(P('@') * (v.ats + v.ext_ats)), ats = annot('param', Cg(lname, 'name') * ws * v.ctype * opt_desc) - + annot('return', comma1(Ct(v.ctype * opt(ws * cname))) * opt_desc) + + annot('return', comma1(Ct(v.ctype * opt(ws * (ty_name + Cg(ellipsis, 'name'))))) * opt_desc) + annot('type', comma1(Ct(v.ctype)) * opt_desc) - + annot('cast', cname * ws * opt(Sf('+-')) * v.ctype) - + annot('generic', cname * opt(colon * v.ctype)) - + annot('class', opt_exact * opt(paren(caccess)) * fill * cname * opt_parent) + + annot('cast', ty_name * ws * opt(Sf('+-')) * v.ctype) + + annot('generic', ty_name * opt(colon * v.ctype)) + + annot('class', opt_exact * opt(paren(caccess)) * fill * ty_name * opt_parent) + annot('field', opt(caccess * ws) * v.field_name * ws * v.ctype * opt_desc) - + annot('operator', cname * opt(paren(Cg(v.ltype, 'argtype'))) * colon * v.ctype) + + annot('operator', ty_name * opt(paren(Cg(v.ctype, 'argtype'))) * colon * v.ctype) + annot(access) + annot('deprecated') - + annot('alias', cname * opt(ws * v.ctype)) - + annot('enum', cname) + + annot('alias', ty_name * opt(ws * v.ctype)) + + annot('enum', ty_name) + annot('overload', v.ctype) + annot('see', opt(desc_delim) * desc) + annot('diagnostic', opt(desc_delim) * desc) @@ -165,21 +200,8 @@ local grammar = P { ), field_name = Cg(lname + (v.ty_index * opt(P('?'))), 'name'), - - ctype = parenOpt(Cg(v.ltype, 'type')), - ltype = parenOpt(v.ty_union), - - ty_union = v.ty_opt * rep(Pf('|') * v.ty_opt), - ty = v.ty_fun + ident + v.ty_table + literal + paren(v.ty) + v.ty_generic, - ty_param = Pf('<') * comma1(v.ltype) * fill * P('>'), - ty_opt = v.ty * opt(v.ty_param) * opt(P('[]')) * opt(P('?')), - ty_index = (Pf('[') * (v.ltype + ident + rep1(num)) * fill * P(']')), - table_key = v.ty_index + lname, - table_elem = v.table_key * colon * v.ltype, - ty_table = Pf('{') * comma1(v.table_elem) * fill * P('}'), - fun_param = lname * opt(colon * v.ltype), - ty_fun = Pf('fun') * paren(comma(lname * opt(colon * v.ltype))) * opt(colon * comma1(v.ltype)), - ty_generic = P('`') * letter * P('`'), + ty_index = C(Pf('[') * typedef * fill * P(']')), + ctype = Cg(typedef, 'type'), } return grammar --[[@as nvim.luacats.grammar]] diff --git a/scripts/luacats_parser.lua b/scripts/luacats_parser.lua index cb301b32e4..9a763e4d7b 100644 --- a/scripts/luacats_parser.lua +++ b/scripts/luacats_parser.lua @@ -46,6 +46,7 @@ local luacats_grammar = require('scripts.luacats_grammar') --- @field type string --- @field desc string --- @field access? 'private'|'package'|'protected' +--- @field nodoc? true --- @class nvim.luacats.parser.class --- @field kind 'class' @@ -252,9 +253,12 @@ end --- @return nvim.luacats.parser.field local function fun2field(fun) local parts = { 'fun(' } + + local params = {} ---@type string[] for _, p in ipairs(fun.params or {}) do - parts[#parts + 1] = string.format('%s: %s', p.name, p.type) + params[#params + 1] = string.format('%s: %s', p.name, p.type) end + parts[#parts + 1] = table.concat(params, ', ') parts[#parts + 1] = ')' if fun.returns then parts[#parts + 1] = ': ' @@ -270,6 +274,7 @@ local function fun2field(fun) type = table.concat(parts, ''), access = fun.access, desc = fun.desc, + nodoc = fun.nodoc, } end @@ -458,7 +463,7 @@ local function dump_uncommitted(filename, uncommitted) local out_path = 'luacats-uncommited/' .. filename:gsub('/', '%%') .. '.txt' if #uncommitted > 0 then print(string.format('Could not commit %d objects in %s', #uncommitted, filename)) - vim.fn.mkdir(assert(vim.fs.dirname(out_path)), 'p') + vim.fn.mkdir(vim.fs.dirname(out_path), 'p') local f = assert(io.open(out_path, 'w')) for i, x in ipairs(uncommitted) do f:write(i) diff --git a/scripts/text_utils.lua b/scripts/util.lua index 75b3bfedd5..5940221abe 100644 --- a/scripts/text_utils.lua +++ b/scripts/util.lua @@ -1,7 +1,9 @@ +-- TODO(justinmk): move most of this to `vim.text`. + local fmt = string.format ---- @class nvim.text_utils.MDNode ---- @field [integer] nvim.text_utils.MDNode +--- @class nvim.util.MDNode +--- @field [integer] nvim.util.MDNode --- @field type string --- @field text? string @@ -15,6 +17,24 @@ local function contains(t, xs) return vim.tbl_contains(xs, t) end +-- Map of api_level:version, by inspection of: +-- :lua= vim.mpack.decode(vim.fn.readfile('test/functional/fixtures/api_level_9.mpack','B')).version +M.version_level = { + [13] = '0.11.0', + [12] = '0.10.0', + [11] = '0.9.0', + [10] = '0.8.0', + [9] = '0.7.0', + [8] = '0.6.0', + [7] = '0.5.0', + [6] = '0.4.0', + [5] = '0.3.2', + [4] = '0.3.0', + [3] = '0.2.1', + [2] = '0.2.0', + [1] = '0.1.0', +} + --- @param txt string --- @param srow integer --- @param scol integer @@ -47,13 +67,13 @@ local function slice_text(txt, srow, scol, erow, ecol) end --- @param text string ---- @return nvim.text_utils.MDNode +--- @return nvim.util.MDNode local function parse_md_inline(text) local parser = vim.treesitter.languagetree.new(text, 'markdown_inline') local root = parser:parse(true)[1]:root() --- @param node TSNode - --- @return nvim.text_utils.MDNode? + --- @return nvim.util.MDNode? local function extract(node) local ntype = node:type() @@ -101,7 +121,7 @@ local function parse_md_inline(text) end --- @param text string ---- @return nvim.text_utils.MDNode +--- @return nvim.util.MDNode local function parse_md(text) local parser = vim.treesitter.languagetree.new(text, 'markdown', { injections = { markdown = '' }, @@ -119,7 +139,7 @@ local function parse_md(text) } --- @param node TSNode - --- @return nvim.text_utils.MDNode? + --- @return nvim.util.MDNode? local function extract(node) local ntype = node:type() @@ -153,6 +173,20 @@ local function parse_md(text) return extract(root) or {} end +--- Prefixes each line in `text`. +--- +--- Does not wrap, not important for "meta" files? (You probably want md_to_vimdoc instead.) +--- +--- @param text string +--- @param prefix_ string +function M.prefix_lines(prefix_, text) + local r = '' + for _, l in ipairs(vim.split(text, '\n', { plain = true })) do + r = r .. vim.trim(prefix_ .. l) .. '\n' + end + return r +end + --- @param x string --- @param start_indent integer --- @param indent integer @@ -179,7 +213,7 @@ function M.wrap(x, start_indent, indent, text_width) return (table.concat(parts):gsub('%s+\n', '\n'):gsub('\n+$', '')) end ---- @param node nvim.text_utils.MDNode +--- @param node nvim.util.MDNode --- @param start_indent integer --- @param indent integer --- @param text_width integer @@ -207,6 +241,8 @@ local function render_md(node, start_indent, indent, text_width, level, is_list) elseif ntype == 'shortcut_link' then if node[1].text:find('^<.*>$') then parts[#parts + 1] = node[1].text + elseif node[1].text:find('^%d+$') then + vim.list_extend(parts, { '[', node[1].text, ']' }) else vim.list_extend(parts, { '|', node[1].text, '|' }) end diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh index e8758c064f..bfa9f6d99c 100755 --- a/scripts/vim-patch.sh +++ b/scripts/vim-patch.sh @@ -156,7 +156,7 @@ assign_commit_details() { local munge_commit_line=true else # Interpret parameter as commit hash. - vim_version="${1:0:12}" + vim_version="${1:0:7}" vim_tag= vim_commit_ref="$vim_version" local munge_commit_line=false @@ -207,7 +207,7 @@ preprocess_patch() { 2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/runtime/\<\%('"${na_rt}"'\)\>@exe "norm! d/\\v(^diff)|%$\r"' +w +q "$file" # Remove unwanted Vim doc files. - local na_doc='channel\.txt\|if_cscop\.txt\|netbeans\.txt\|os_\w\+\.txt\|print\.txt\|term\.txt\|todo\.txt\|version\d\.txt\|vim9\.txt\|sponsor\.txt\|intro\.txt\|tags' + local na_doc='channel\.txt\|if_cscop\.txt\|netbeans\.txt\|os_\w\+\.txt\|print\.txt\|term\.txt\|todo\.txt\|vim9\.txt\|tags' 2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/runtime/doc/\<\%('"${na_doc}"'\)\>@exe "norm! d/\\v(^diff)|%$\r"' +w +q "$file" # Remove "Last change ..." changes in doc files. @@ -293,8 +293,12 @@ preprocess_patch() { LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/option\.h/\1\/option_vars.h/g' \ "$file" > "$file".tmp && mv "$file".tmp "$file" - # Rename terminal.txt to nvim_terminal_emulator.txt - LC_ALL=C sed -Ee 's/( [ab]\/runtime\/doc)\/terminal\.txt/\1\/nvim_terminal_emulator.txt/g' \ + # Rename version*.txt to news.txt + LC_ALL=C sed -Ee 's/( [ab]\/runtime\/doc)\/version[0-9]+\.txt/\1\/news.txt/g' \ + "$file" > "$file".tmp && mv "$file".tmp "$file" + + # Rename sponsor.txt to intro.txt + LC_ALL=C sed -Ee 's/( [ab]\/runtime\/doc)\/sponsor\.txt/\1\/intro.txt/g' \ "$file" > "$file".tmp && mv "$file".tmp "$file" # Rename test_urls.vim to check_urls.vim diff --git a/src/.valgrind.supp b/src/.valgrind.supp index cce22bd632..ee3687a6a4 100644 --- a/src/.valgrind.supp +++ b/src/.valgrind.supp @@ -10,7 +10,7 @@ Memcheck:Leak fun:malloc fun:uv_spawn - fun:libuv_process_spawn - fun:process_spawn + fun:libuv_proc_spawn + fun:proc_spawn fun:job_start } diff --git a/src/clint.py b/src/clint.py index 41058469b1..b57bbe354b 100755 --- a/src/clint.py +++ b/src/clint.py @@ -848,7 +848,7 @@ def CheckIncludes(filename, lines, error): or filename.endswith('.in.h') or FileInfo(filename).RelativePath() in { 'func_attr.h', - 'os/pty_process.h', + 'os/pty_proc.h', }): return @@ -869,7 +869,7 @@ def CheckIncludes(filename, lines, error): "src/nvim/msgpack_rpc/unpacker.h", "src/nvim/option.h", "src/nvim/os/pty_conpty_win.h", - "src/nvim/os/pty_process_win.h", + "src/nvim/os/pty_proc_win.h", ] skip_headers = [ @@ -880,6 +880,8 @@ def CheckIncludes(filename, lines, error): "mpack/object.h", "nvim/func_attr.h", "termkey/termkey.h", + "vterm/vterm.h", + "xdiff/xdiff.h", ] for i in check_includes_ignore: @@ -895,6 +897,7 @@ def CheckIncludes(filename, lines, error): if (not name.endswith('.h.generated.h') and not name.endswith('/defs.h') and not name.endswith('_defs.h') and + not name.endswith('h.inline.generated.h') and not name.endswith('_defs.generated.h') and not name.endswith('_enum.generated.h')): error(filename, i, 'build/include_defs', 5, @@ -1779,7 +1782,7 @@ def CheckSpacing(filename, clean_lines, linenum, error): r'(?<!\bPMap)' r'(?<!\bSet)' r'(?<!\bArrayOf)' - r'(?<!\bDictionaryOf)' + r'(?<!\bDictOf)' r'(?<!\bDict)' r'\((?:const )?(?:struct )?[a-zA-Z_]\w*(?: *\*(?:const)?)*\)' r' +' @@ -1995,7 +1998,7 @@ def CheckLanguage(filename, clean_lines, linenum, error): if match: error(filename, linenum, 'runtime/printf', 4, 'Use xstrlcpy, xmemcpyz or snprintf instead of %s' % match.group(1)) - match = Search(r'\b(STRNCAT|strncat|strcat|vim_strcat)\b', line) + match = Search(r'\b(STRNCAT|strncat|vim_strcat)\b', line) if match: error(filename, linenum, 'runtime/printf', 4, 'Use xstrlcat or snprintf instead of %s' % match.group(1)) diff --git a/src/klib/klist.h b/src/klib/klist.h deleted file mode 100644 index 4274c53919..0000000000 --- a/src/klib/klist.h +++ /dev/null @@ -1,144 +0,0 @@ -/* The MIT License - - Copyright (c) 2008-2009, by Attractive Chaos <attractor@live.co.uk> - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -#ifndef _AC_KLIST_H -#define _AC_KLIST_H - -#include <assert.h> -#include <stdlib.h> - -#include "nvim/func_attr.h" -#include "nvim/memory.h" - -#define KMEMPOOL_INIT(name, kmptype_t, kmpfree_f) \ - typedef struct { \ - size_t cnt, n, max; \ - kmptype_t **buf; \ - } kmp_##name##_t; \ - static inline kmp_##name##_t *kmp_init_##name(void) { \ - return (kmp_##name##_t *)xcalloc(1, sizeof(kmp_##name##_t)); \ - } \ - static inline void kmp_destroy_##name(kmp_##name##_t *mp) \ - REAL_FATTR_UNUSED; \ - static inline void kmp_destroy_##name(kmp_##name##_t *mp) { \ - size_t k; \ - for (k = 0; k < mp->n; k++) { \ - kmpfree_f(mp->buf[k]); XFREE_CLEAR(mp->buf[k]); \ - } \ - XFREE_CLEAR(mp->buf); XFREE_CLEAR(mp); \ - } \ - static inline kmptype_t *kmp_alloc_##name(kmp_##name##_t *mp) { \ - mp->cnt++; \ - if (mp->n == 0) { \ - return (kmptype_t *)xcalloc(1, sizeof(kmptype_t)); \ - } \ - return mp->buf[--mp->n]; \ - } \ - static inline void kmp_free_##name(kmp_##name##_t *mp, kmptype_t *p) { \ - mp->cnt--; \ - if (mp->n == mp->max) { \ - mp->max = mp->max ? (mp->max << 1) : 16; \ - mp->buf = (kmptype_t **)xrealloc(mp->buf, sizeof(kmptype_t *) * mp->max); \ - } \ - mp->buf[mp->n++] = p; \ - } - -#define kmempool_t(name) kmp_##name##_t -#define kmp_init(name) kmp_init_##name() -#define kmp_destroy(name, mp) kmp_destroy_##name(mp) -#define kmp_alloc(name, mp) kmp_alloc_##name(mp) -#define kmp_free(name, mp, p) kmp_free_##name(mp, p) - -#define KLIST_INIT(name, kltype_t, kmpfree_t) \ - struct __kl1_##name { \ - kltype_t data; \ - struct __kl1_##name *next; \ - }; \ - typedef struct __kl1_##name kl1_##name; \ - KMEMPOOL_INIT(name, kl1_##name, kmpfree_t) \ - typedef struct { \ - kl1_##name *head, *tail; \ - kmp_##name##_t *mp; \ - size_t size; \ - } kl_##name##_t; \ - static inline kl_##name##_t *kl_init_##name(void) { \ - kl_##name##_t *kl = (kl_##name##_t *)xcalloc(1, sizeof(kl_##name##_t)); \ - kl->mp = kmp_init(name); \ - kl->head = kl->tail = kmp_alloc(name, kl->mp); \ - kl->head->next = 0; \ - return kl; \ - } \ - static inline void kl_destroy_##name(kl_##name##_t *kl) \ - REAL_FATTR_UNUSED; \ - static inline void kl_destroy_##name(kl_##name##_t *kl) { \ - kl1_##name *p; \ - for (p = kl->head; p != kl->tail; p = p->next) { \ - kmp_free(name, kl->mp, p); \ - } \ - kmp_free(name, kl->mp, p); \ - kmp_destroy(name, kl->mp); \ - XFREE_CLEAR(kl); \ - } \ - static inline void kl_push_##name(kl_##name##_t *kl, kltype_t d) { \ - kl1_##name *q, *p = kmp_alloc(name, kl->mp); \ - q = kl->tail; p->next = 0; kl->tail->next = p; kl->tail = p; \ - kl->size++; \ - q->data = d; \ - } \ - static inline kltype_t kl_shift_at_##name(kl_##name##_t *kl, \ - kl1_##name **n) { \ - assert((*n)->next); \ - kl1_##name *p; \ - kl->size--; \ - p = *n; \ - *n = (*n)->next; \ - if (p == kl->head) { \ - kl->head = *n; \ - } \ - kltype_t d = p->data; \ - kmp_free(name, kl->mp, p); \ - return d; \ - } - -#define kliter_t(name) kl1_##name -#define klist_t(name) kl_##name##_t -#define kl_val(iter) ((iter)->data) -#define kl_next(iter) ((iter)->next) -#define kl_begin(kl) ((kl)->head) -#define kl_end(kl) ((kl)->tail) - -#define kl_init(name) kl_init_##name() -#define kl_destroy(name, kl) kl_destroy_##name(kl) -#define kl_push(name, kl, d) kl_push_##name(kl, d) -#define kl_shift_at(name, kl, node) kl_shift_at_##name(kl, node) -#define kl_shift(name, kl) kl_shift_at(name, kl, &kl->head) -#define kl_empty(kl) ((kl)->size == 0) -// Iteration macros. It's ok to modify the list while iterating as long as a -// `break` statement is executed before the next iteration. -#define kl_iter(name, kl, p) kl_iter_at(name, kl, p, NULL) -#define kl_iter_at(name, kl, p, h) \ - for (kl1_##name **p = h ? h : &kl->head; *p != kl->tail; p = &(*p)->next) - -#endif diff --git a/src/man/nvim.1 b/src/man/nvim.1 index 4dc099f98c..9b7680d011 100644 --- a/src/man/nvim.1 +++ b/src/man/nvim.1 @@ -387,10 +387,10 @@ features like .El .Sh FILES .Bl -tag -width "~/.config/nvim/init.vim" -.It Pa ~/.config/nvim/init.vim +.It Pa ~/.config/nvim/init.lua User-local .Nm -configuration file. +Lua configuration file. .It Pa ~/.config/nvim User-local .Nm diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 937cfaaa31..c2a358327a 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -30,19 +30,17 @@ target_link_libraries(main_lib INTERFACE ${LUV_LIBRARY}) find_package(Iconv REQUIRED) find_package(Libuv 1.28.0 REQUIRED) -find_package(Libvterm 0.3.3 REQUIRED) find_package(Lpeg REQUIRED) -find_package(Msgpack 1.0.0 REQUIRED) -find_package(Treesitter 0.22.6 REQUIRED) +find_package(Treesitter 0.23.0 REQUIRED) find_package(Unibilium 2.0 REQUIRED) +find_package(UTF8proc REQUIRED) target_link_libraries(main_lib INTERFACE iconv - libvterm lpeg - msgpack treesitter - unibilium) + unibilium + utf8proc) target_link_libraries(nlua0 PUBLIC lpeg) if(ENABLE_LIBINTL) @@ -50,7 +48,11 @@ if(ENABLE_LIBINTL) target_link_libraries(main_lib INTERFACE libintl) endif() -target_compile_definitions(main_lib INTERFACE HAVE_UNIBILIUM) +if(ENABLE_WASMTIME) + find_package(Wasmtime 25.0.1 EXACT REQUIRED) + target_link_libraries(main_lib INTERFACE wasmtime) + target_compile_definitions(nvim_bin PRIVATE HAVE_WASMTIME) +endif() # The unit test lib requires LuaJIT; it will be skipped if LuaJIT is missing. option(PREFER_LUA "Prefer Lua over LuaJIT in the nvim executable." OFF) @@ -149,7 +151,7 @@ if(UNIX) endif() if(CMAKE_SYSTEM_NAME MATCHES "Windows") - target_compile_definitions(main_lib INTERFACE _WIN32_WINNT=0x0602 MSWIN) + target_compile_definitions(main_lib INTERFACE _WIN32_WINNT=0x0602 MSWIN WIN32_LEAN_AND_MEAN) target_link_libraries(main_lib INTERFACE netapi32) elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin") target_link_libraries(nvim_bin PRIVATE "-framework CoreServices") @@ -294,7 +296,6 @@ set(GENERATOR_DIR ${CMAKE_CURRENT_LIST_DIR}/generators) set(GEN_EVAL_TOUCH ${TOUCHES_DIR}/gen_doc_eval) set(LUAJIT_RUNTIME_DIR ${DEPS_PREFIX}/share/luajit-2.1/jit) set(NVIM_RUNTIME_DIR ${PROJECT_SOURCE_DIR}/runtime) -set(UNICODE_DIR ${PROJECT_SOURCE_DIR}/src/unicode) # GENERATOR_DIR set(API_DISPATCH_GENERATOR ${GENERATOR_DIR}/gen_api_dispatch.lua) @@ -309,7 +310,6 @@ set(GENERATOR_PRELOAD ${GENERATOR_DIR}/preload.lua) set(HEADER_GENERATOR ${GENERATOR_DIR}/gen_declarations.lua) set(OPTIONS_ENUM_GENERATOR ${GENERATOR_DIR}/gen_options_enum.lua) set(OPTIONS_GENERATOR ${GENERATOR_DIR}/gen_options.lua) -set(UNICODE_TABLES_GENERATOR ${GENERATOR_DIR}/gen_unicode_tables.lua) # GENERATED_DIR and GENERATED_INCLUDES_DIR set(GENERATED_API_DISPATCH ${GENERATED_DIR}/api/private/dispatch_wrappers.generated.h) @@ -326,7 +326,6 @@ set(GENERATED_OPTIONS_MAP ${GENERATED_DIR}/options_map.generated.h) set(GENERATED_UI_EVENTS_CALL ${GENERATED_DIR}/ui_events_call.generated.h) set(GENERATED_UI_EVENTS_CLIENT ${GENERATED_DIR}/ui_events_client.generated.h) set(GENERATED_UI_EVENTS_REMOTE ${GENERATED_DIR}/ui_events_remote.generated.h) -set(GENERATED_UNICODE_TABLES ${GENERATED_DIR}/unicode_tables.generated.h) set(LUA_API_C_BINDINGS ${GENERATED_DIR}/lua_api_c_bindings.generated.h) set(VIM_MODULE_FILE ${GENERATED_DIR}/lua/vim_module.generated.h) @@ -343,7 +342,6 @@ set(LUA_LOADER_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/loader.lua) set(LUA_OPTIONS_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/_options.lua) set(LUA_SHARED_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/shared.lua) -file(GLOB UNICODE_FILES CONFIGURE_DEPENDS ${UNICODE_DIR}/*.txt) file(GLOB API_HEADERS CONFIGURE_DEPENDS api/*.h) list(REMOVE_ITEM API_HEADERS ${CMAKE_CURRENT_LIST_DIR}/api/ui_events.in.h) file(GLOB MSGPACK_RPC_HEADERS CONFIGURE_DEPENDS msgpack_rpc/*.h) @@ -363,8 +361,8 @@ file(MAKE_DIRECTORY ${TOUCHES_DIR} ${GENERATED_DIR} ${GENERATED_INCLUDES_DIR}) file(GLOB NVIM_SOURCES CONFIGURE_DEPENDS *.c) file(GLOB NVIM_HEADERS CONFIGURE_DEPENDS *.h) -file(GLOB EXTERNAL_SOURCES CONFIGURE_DEPENDS ../xdiff/*.c ../mpack/*.c ../cjson/*.c ../klib/*.c ../termkey/*.c) -file(GLOB EXTERNAL_HEADERS CONFIGURE_DEPENDS ../xdiff/*.h ../mpack/*.h ../cjson/*.h ../klib/*.h ../termkey/*.h) +file(GLOB EXTERNAL_SOURCES CONFIGURE_DEPENDS ../xdiff/*.c ../mpack/*.c ../cjson/*.c ../klib/*.c ../vterm/*.c) +file(GLOB EXTERNAL_HEADERS CONFIGURE_DEPENDS ../xdiff/*.h ../mpack/*.h ../cjson/*.h ../klib/*.h ../vterm/*.h) file(GLOB NLUA0_SOURCES CONFIGURE_DEPENDS ../mpack/*.c) @@ -375,6 +373,15 @@ if(PREFER_LUA) target_compile_definitions(main_lib INTERFACE NVIM_VENDOR_BIT) endif() +# Inlined external projects, we don't maintain it. #9306 +if(MSVC) + set_source_files_properties( + ${EXTERNAL_SOURCES} PROPERTIES COMPILE_OPTIONS "-wd4090;-wd4244;-wd4267") +else() + set_source_files_properties( + ${EXTERNAL_SOURCES} PROPERTIES COMPILE_OPTIONS "-Wno-conversion;-Wno-missing-noreturn;-Wno-missing-format-attribute;-Wno-double-promotion;-Wno-strict-prototypes;-Wno-misleading-indentation;-Wno-sign-compare;-Wno-implicit-fallthrough;-Wno-missing-prototypes;-Wno-missing-field-initializers") +endif() + list(APPEND NLUA0_SOURCES ${PROJECT_SOURCE_DIR}/src/nlua0.c) foreach(subdir @@ -383,9 +390,11 @@ foreach(subdir api/private msgpack_rpc tui + tui/termkey event eval lua + lib viml viml/parser ) @@ -403,34 +412,36 @@ endforeach() list(SORT NVIM_SOURCES) list(SORT NVIM_HEADERS) -list(APPEND LINT_NVIM_SOURCES ${NVIM_SOURCES} ${NVIM_HEADERS}) - foreach(sfile ${NVIM_SOURCES}) get_filename_component(f ${sfile} NAME) - if(WIN32 AND ${f} MATCHES "^(pty_process_unix.c)$") - list(APPEND to_remove ${sfile}) + if(WIN32 AND ${f} MATCHES "^(pty_proc_unix.c)$") + list(REMOVE_ITEM NVIM_SOURCES ${sfile}) endif() - if(NOT WIN32 AND ${f} MATCHES "^(pty_process_win.c)$") - list(APPEND to_remove ${sfile}) + if(NOT WIN32 AND ${f} MATCHES "^(pty_proc_win.c)$") + list(REMOVE_ITEM NVIM_SOURCES ${sfile}) endif() if(NOT WIN32 AND ${f} MATCHES "^(pty_conpty_win.c)$") - list(APPEND to_remove ${sfile}) + list(REMOVE_ITEM NVIM_SOURCES ${sfile}) endif() if(NOT WIN32 AND ${f} MATCHES "^(os_win_console.c)$") - list(APPEND to_remove ${sfile}) + list(REMOVE_ITEM NVIM_SOURCES ${sfile}) endif() endforeach() -list(REMOVE_ITEM NVIM_SOURCES ${to_remove}) +foreach(hfile ${NVIM_HEADERS}) + get_filename_component(f ${hfile} NAME) + if(WIN32 AND ${f} MATCHES "^(unix_defs.h)$") + list(REMOVE_ITEM NVIM_HEADERS ${hfile}) + endif() + if(WIN32 AND ${f} MATCHES "^(pty_proc_unix.h)$") + list(REMOVE_ITEM NVIM_HEADERS ${hfile}) + endif() + if(NOT WIN32 AND ${f} MATCHES "^(win_defs.h)$") + list(REMOVE_ITEM NVIM_HEADERS ${hfile}) + endif() +endforeach() -# xdiff, mpack, lua-cjson, termkey: inlined external project, we don't maintain it. #9306 -if(MSVC) - set_source_files_properties( - ${EXTERNAL_SOURCES} PROPERTIES COMPILE_OPTIONS "-wd4090;-wd4244;-wd4267") -else() - set_source_files_properties( - ${EXTERNAL_SOURCES} PROPERTIES COMPILE_OPTIONS "-Wno-conversion;-Wno-missing-noreturn;-Wno-missing-format-attribute;-Wno-double-promotion;-Wno-strict-prototypes;-Wno-misleading-indentation;-Wno-sign-compare;-Wno-implicit-fallthrough;-Wno-missing-prototypes;-Wno-missing-field-initializers") -endif() +list(APPEND LINT_NVIM_SOURCES ${NVIM_SOURCES} ${NVIM_HEADERS}) # Log level (NVIM_LOG_DEBUG in log.h) if(CI_BUILD) @@ -477,7 +488,6 @@ endif() if(MSVC) list(APPEND gen_cflags -wd4003) endif() -list(APPEND gen_cflags -O2) set(NVIM_VERSION_GIT_H ${PROJECT_BINARY_DIR}/cmake.config/auto/versiondef_git.h) add_custom_target(update_version_stamp @@ -507,6 +517,7 @@ set(LUA_GEN_DEPS ${GENERATOR_PRELOAD} $<TARGET_FILE:nlua0>) # NVIM_GENERATED_FOR_SOURCES: generated headers to be included in sources # These lists must be mutually exclusive. foreach(sfile ${NVIM_SOURCES} + ${NVIM_HEADERS} ${GENERATED_API_DISPATCH} "${GENERATED_UI_EVENTS_CALL}" "${GENERATED_UI_EVENTS_REMOTE}" @@ -519,18 +530,30 @@ foreach(sfile ${NVIM_SOURCES} endif() get_filename_component(f ${sfile} NAME) get_filename_component(r ${sfile} NAME_WE) + get_filename_component(ext ${sfile} EXT) if(NOT ${d} EQUAL ".") set(f "${d}/${f}") set(r "${d}/${r}") endif() - set(gf_c_h "${GENERATED_DIR}/${r}.c.generated.h") - set(gf_h_h "${GENERATED_INCLUDES_DIR}/${r}.h.generated.h") - set(gf_i "${GENERATED_DIR}/${r}.i") + if ("${ext}" STREQUAL ".c.h") + continue() # .c.h files are sussy baka, skip + elseif(${sfile} IN_LIST NVIM_HEADERS) + set(gf_basename "${r}.h.inline.generated.h") + set(gf_c_h "${GENERATED_INCLUDES_DIR}/${r}.h.inline.generated.h") + set(gf_h_h "SKIP") + set(gf_h_h_out "") + else() + set(gf_basename "${r}.c.generated.h") + set(gf_c_h "${GENERATED_DIR}/${r}.c.generated.h") + set(gf_h_h "${GENERATED_INCLUDES_DIR}/${r}.h.generated.h") + set(gf_h_h_out "${gf_h_h}") + endif() + set(gf_i "${GENERATED_DIR}/${f}.i") if(MSVC) set(PREPROC_OUTPUT /P /Fi${gf_i} /nologo) else() - set(PREPROC_OUTPUT -E -o ${gf_i}) + set(PREPROC_OUTPUT -w -E -o ${gf_i}) endif() set(depends "${HEADER_GENERATOR}" "${sfile}" "${LUA_GEN_DEPS}") @@ -539,26 +562,19 @@ foreach(sfile ${NVIM_SOURCES} list(APPEND depends update_version_stamp "${NVIM_VERSION_GIT_H}" "${NVIM_VERSION_DEF_H}") endif() add_custom_command( - OUTPUT "${gf_c_h}" "${gf_h_h}" + OUTPUT "${gf_c_h}" ${gf_h_h_out} COMMAND ${CMAKE_C_COMPILER} ${sfile} ${PREPROC_OUTPUT} ${gen_cflags} - COMMAND ${LUA_GEN} "${HEADER_GENERATOR}" "${sfile}" "${gf_c_h}" "${gf_h_h}" "${gf_i}" + COMMAND ${LUA_GEN} "${HEADER_GENERATOR}" "${sfile}" "${gf_c_h}" "${gf_h_h}" "${gf_i}" "${gf_basename}" DEPENDS ${depends}) list(APPEND NVIM_GENERATED_FOR_SOURCES "${gf_c_h}") - list(APPEND NVIM_GENERATED_FOR_HEADERS "${gf_h_h}") - if(${d} MATCHES "^api$" AND NOT ${f} MATCHES "^api/helpers.c$") - list(APPEND API_HEADERS ${gf_h_h}) + if (NOT ${sfile} IN_LIST NVIM_HEADERS) + list(APPEND NVIM_GENERATED_FOR_HEADERS "${gf_h_h}") + if(${d} MATCHES "^api$" AND NOT ${f} MATCHES "^api/helpers.c$") + list(APPEND API_HEADERS ${gf_h_h}) + endif() endif() endforeach() -add_custom_command(OUTPUT ${GENERATED_UNICODE_TABLES} - COMMAND ${LUA_PRG} ${UNICODE_TABLES_GENERATOR} - ${UNICODE_DIR} - ${GENERATED_UNICODE_TABLES} - DEPENDS - ${UNICODE_TABLES_GENERATOR} - ${UNICODE_FILES} -) - set(NVIM_VERSION_LUA ${PROJECT_BINARY_DIR}/nvim_version.lua) configure_file(${GENERATOR_DIR}/nvim_version.lua.in ${NVIM_VERSION_LUA}) @@ -650,7 +666,6 @@ list(APPEND NVIM_GENERATED_FOR_SOURCES "${GENERATED_EVENTS_NAMES_MAP}" "${GENERATED_OPTIONS}" "${GENERATED_OPTIONS_MAP}" - "${GENERATED_UNICODE_TABLES}" "${VIM_MODULE_FILE}" "${PROJECT_BINARY_DIR}/cmake.config/auto/pathdef.h" ) @@ -706,6 +721,12 @@ target_sources(main_lib INTERFACE ${EXTERNAL_SOURCES} ${EXTERNAL_HEADERS}) +if(WIN32) + # add windows resource file pointing to the neovim icon + # this makes the icon appear for the neovim exe and associated filetypes + target_sources(nvim_bin PRIVATE ${NVIM_RUNTIME_DIR}/windows_icon.rc) +endif() + target_sources(nlua0 PUBLIC ${NLUA0_SOURCES}) target_link_libraries(nvim_bin PRIVATE main_lib PUBLIC libuv) @@ -808,19 +829,19 @@ find_program(CLANG_TIDY_PRG clang-tidy) set(EXCLUDE_CLANG_TIDY typval_encode.c.h ui_events.in.h) if(WIN32) list(APPEND EXCLUDE_CLANG_TIDY - os/pty_process_unix.h + os/pty_proc_unix.h os/unix_defs.h) else() list(APPEND EXCLUDE_CLANG_TIDY os/win_defs.h - os/pty_process_win.h + os/pty_proc_win.h os/pty_conpty_win.h os/os_win_console.h) endif() add_glob_target( TARGET lintc-clang-tidy COMMAND ${CLANG_TIDY_PRG} - FILES ${NVIM_SOURCES} ${NVIM_HEADERS} + FILES ${LINT_NVIM_SOURCES} FLAGS --quiet EXCLUDE ${EXCLUDE_CLANG_TIDY}) @@ -833,7 +854,7 @@ endif() add_glob_target( TARGET clang-analyzer COMMAND ${CLANG_TIDY_PRG} - FILES ${NVIM_SOURCES} ${NVIM_HEADERS} + FILES ${LINT_NVIM_SOURCES} FLAGS --quiet --checks=' -*, @@ -841,8 +862,11 @@ add_glob_target( -clang-analyzer-core.NullDereference, -clang-analyzer-core.UndefinedBinaryOperatorResult, -clang-analyzer-core.uninitialized.Assign, + -clang-analyzer-optin.core.EnumCastOutOfRange, -clang-analyzer-optin.performance.Padding, -clang-analyzer-security.insecureAPI.strcpy, + -clang-analyzer-unix.StdCLibraryFunctions, + -clang-analyzer-unix.Stream, ${CLANG_ANALYZER_IGNORE} ' EXCLUDE ${EXCLUDE_CLANG_TIDY}) @@ -876,13 +900,13 @@ add_glob_target( TARGET lintc-uncrustify COMMAND ${UNCRUSTIFY_PRG} FLAGS -c ${UNCRUSTIFY_CONFIG} -q --check - FILES ${LINT_NVIM_SOURCES}) + FILES ${NVIM_SOURCES} ${NVIM_HEADERS}) add_glob_target( TARGET formatc COMMAND ${UNCRUSTIFY_PRG} FLAGS -c ${UNCRUSTIFY_CONFIG} --replace --no-backup - FILES ${LINT_NVIM_SOURCES}) + FILES ${NVIM_SOURCES} ${NVIM_HEADERS}) add_dependencies(lintc-uncrustify uncrustify_update_config) add_dependencies(formatc uncrustify_update_config) diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index ca8367b7ce..22932fd1a2 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -67,7 +67,7 @@ static int64_t next_autocmd_id = 1; /// NOTE: When multiple patterns or events are provided, it will find all the autocommands that /// match any combination of them. /// -/// @param opts Dictionary with at least one of the following: +/// @param opts Dict with at least one of the following: /// - group (string|integer): the autocommand group name or id to match against. /// - event (string|array): event or events to match against |autocmd-events|. /// - pattern (string|array): pattern or patterns to match against |autocmd-pattern|. @@ -270,7 +270,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Arena *arena, Error *err) } } - Dictionary autocmd_info = arena_dict(arena, 11); + Dict autocmd_info = arena_dict(arena, 11); if (ap->group != AUGROUP_DEFAULT) { PUT_C(autocmd_info, "group", INTEGER_OBJ(ap->group)); @@ -334,7 +334,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Arena *arena, Error *err) // PUT_C(autocmd_info, "sid", INTEGER_OBJ(ac->script_ctx.sc_sid)); // PUT_C(autocmd_info, "lnum", INTEGER_OBJ(ac->script_ctx.sc_lnum)); - kvi_push(autocmd_list, DICTIONARY_OBJ(autocmd_info)); + kvi_push(autocmd_list, DICT_OBJ(autocmd_info)); } } @@ -621,7 +621,7 @@ void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Arena *arena, Error *err) /// ``` /// /// @param name String: The name of the group -/// @param opts Dictionary Parameters +/// @param opts Dict Parameters /// - clear (bool) optional: defaults to true. Clear existing /// commands if the group already exists |autocmd-groups|. /// @return Integer id of the created group. @@ -686,7 +686,7 @@ void nvim_del_augroup_by_name(String name, Error *err) /// Execute all autocommands for {event} that match the corresponding /// {opts} |autocmd-execute|. /// @param event (String|Array) The event or events to execute -/// @param opts Dictionary of autocommand options: +/// @param opts Dict of autocommand options: /// - group (string|integer) optional: the autocommand group name or /// id to match against. |autocmd-groups|. /// - pattern (string|array) optional: defaults to "*" |autocmd-pattern|. Cannot be used diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 7e64808709..9480292d9a 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -462,12 +462,8 @@ end: /// = row` and `start_col = end_col = col`. To delete the text in a range, use /// `replacement = {}`. /// -/// Prefer |nvim_buf_set_lines()| if you are only adding or deleting entire lines. -/// -/// Prefer |nvim_put()| if you want to insert text at the cursor position. -/// -/// @see |nvim_buf_set_lines()| -/// @see |nvim_put()| +/// @note Prefer |nvim_buf_set_lines()| (for performance) to add or delete entire lines. +/// @note Prefer |nvim_paste()| or |nvim_put()| to insert (instead of replace) text at cursor. /// /// @param channel_id /// @param buffer Buffer handle, or 0 for current buffer @@ -866,7 +862,7 @@ Integer nvim_buf_get_changedtick(Buffer buffer, Error *err) /// @param[out] err Error details, if any /// @returns Array of |maparg()|-like dictionaries describing mappings. /// The "buffer" key holds the associated buffer handle. -ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Arena *arena, Error *err) +ArrayOf(Dict) nvim_buf_get_keymap(Buffer buffer, String mode, Arena *arena, Error *err) FUNC_API_SINCE(3) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -1183,12 +1179,12 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Arena *arena, return rv; } -/// call a function with buffer as temporary current buffer +/// Call a function with buffer as temporary current buffer. /// /// This temporarily switches current buffer to "buffer". -/// If the current window already shows "buffer", the window is not switched +/// If the current window already shows "buffer", the window is not switched. /// If a window inside the current tabpage (including a float) already shows the -/// buffer One of these windows will be set as current window temporarily. +/// buffer, then one of these windows will be set as current window temporarily. /// Otherwise a temporary scratch window (called the "autocmd window" for /// historical reasons) will be used. /// @@ -1221,14 +1217,14 @@ Object nvim_buf_call(Buffer buffer, LuaRef fun, Error *err) } /// @nodoc -Dictionary nvim__buf_stats(Buffer buffer, Arena *arena, Error *err) +Dict nvim__buf_stats(Buffer buffer, Arena *arena, Error *err) { buf_T *buf = find_buffer_by_handle(buffer, err); if (!buf) { - return (Dictionary)ARRAY_DICT_INIT; + return (Dict)ARRAY_DICT_INIT; } - Dictionary rv = arena_dict(arena, 7); + Dict rv = arena_dict(arena, 7); // Number of times the cached line was flushed. // This should generally not increase while editing the same // line in the same mode. @@ -1375,7 +1371,7 @@ static inline void init_line_array(lua_State *lstate, Array *a, size_t size, Are /// @param s String to push /// @param len Size of string /// @param idx 0-based index to place s (only used for Lua) -/// @param replace_nl Replace newlines ('\n') with null ('\0') +/// @param replace_nl Replace newlines ('\n') with null (NUL) static void push_linestr(lua_State *lstate, Array *a, const char *s, size_t len, int idx, bool replace_nl, Arena *arena) { @@ -1384,7 +1380,7 @@ static void push_linestr(lua_State *lstate, Array *a, const char *s, size_t len, if (s && replace_nl && strchr(s, '\n')) { // TODO(bfredl): could manage scratch space in the arena, for the NUL case char *tmp = xmemdupz(s, len); - strchrsub(tmp, '\n', '\0'); + strchrsub(tmp, '\n', NUL); lua_pushlstring(lstate, tmp, len); xfree(tmp); } else { @@ -1397,7 +1393,7 @@ static void push_linestr(lua_State *lstate, Array *a, const char *s, size_t len, str = CBUF_TO_ARENA_STR(arena, s, len); if (replace_nl) { // Vim represents NULs as NLs, but this may confuse clients. - strchrsub(str.data, '\n', '\0'); + strchrsub(str.data, '\n', NUL); } } diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 779e216c74..ab57d5c009 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -46,7 +46,7 @@ /// @param str Command line string to parse. Cannot contain "\n". /// @param opts Optional parameters. Reserved for future use. /// @param[out] err Error details, if any. -/// @return Dictionary containing command information, with these keys: +/// @return Dict containing command information, with these keys: /// - cmd: (string) Command name. /// - range: (array) (optional) Command range ([<line1>] [<line2>]). /// Omitted if command doesn't accept a range. @@ -63,13 +63,13 @@ /// - nargs: (string) Value of |:command-nargs|. /// - nextcmd: (string) Next command if there are multiple commands separated by a |:bar|. /// Empty if there isn't a next command. -/// - magic: (dictionary) Which characters have special meaning in the command arguments. +/// - magic: (dict) Which characters have special meaning in the command arguments. /// - file: (boolean) The command expands filenames. Which means characters such as "%", /// "#" and wildcards are expanded. /// - bar: (boolean) The "|" character is treated as a command separator and the double /// quote character (") is treated as the start of a comment. -/// - mods: (dictionary) |:command-modifiers|. -/// - filter: (dictionary) |:filter|. +/// - mods: (dict) |:command-modifiers|. +/// - filter: (dict) |:filter|. /// - pattern: (string) Filter pattern. Empty string if there is no filter. /// - force: (boolean) Whether filter is inverted or not. /// - silent: (boolean) |:silent|. @@ -193,7 +193,7 @@ Dict(cmd) nvim_parse_cmd(String str, Dict(empty) *opts, Arena *arena, Error *err } else { nargs[0] = '0'; } - nargs[1] = '\0'; + nargs[1] = NUL; PUT_KEY(result, cmd, nargs, CSTR_TO_ARENA_OBJ(arena, nargs)); char *addr; @@ -230,12 +230,12 @@ Dict(cmd) nvim_parse_cmd(String str, Dict(empty) *opts, Arena *arena, Error *err PUT_KEY(result, cmd, nextcmd, CSTR_AS_OBJ(ea.nextcmd)); // TODO(bfredl): nested keydict would be nice.. - Dictionary mods = arena_dict(arena, 20); + Dict mods = arena_dict(arena, 20); - Dictionary filter = arena_dict(arena, 2); + Dict filter = arena_dict(arena, 2); PUT_C(filter, "pattern", CSTR_TO_ARENA_OBJ(arena, cmdinfo.cmdmod.cmod_filter_pat)); PUT_C(filter, "force", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_filter_force)); - PUT_C(mods, "filter", DICTIONARY_OBJ(filter)); + PUT_C(mods, "filter", DICT_OBJ(filter)); PUT_C(mods, "silent", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_SILENT)); PUT_C(mods, "emsg_silent", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_ERRSILENT)); @@ -272,7 +272,7 @@ Dict(cmd) nvim_parse_cmd(String str, Dict(empty) *opts, Arena *arena, Error *err PUT_KEY(result, cmd, mods, mods); - Dictionary magic = arena_dict(arena, 2); + Dict magic = arena_dict(arena, 2); PUT_C(magic, "file", BOOLEAN_OBJ(cmdinfo.magic.file)); PUT_C(magic, "bar", BOOLEAN_OBJ(cmdinfo.magic.bar)); PUT_KEY(result, cmd, magic, magic); @@ -284,7 +284,7 @@ end: /// Executes an Ex command. /// -/// Unlike |nvim_command()| this command takes a structured Dictionary instead of a String. This +/// Unlike |nvim_command()| this command takes a structured Dict instead of a String. This /// allows for easier construction and manipulation of an Ex command. This also allows for things /// such as having spaces inside a command argument, expanding filenames in a command that otherwise /// doesn't expand filenames, etc. Command arguments may also be Number, Boolean or String. @@ -298,7 +298,7 @@ end: /// @see |nvim_exec2()| /// @see |nvim_command()| /// -/// @param cmd Command to execute. Must be a Dictionary that can contain the same values as +/// @param cmd Command to execute. Must be a Dict that can contain the same values as /// the return value of |nvim_parse_cmd()| except "addr", "nargs" and "nextcmd" /// which are ignored if provided. All values except for "cmd" are optional. /// @param opts Optional parameters. @@ -391,7 +391,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Arena case kObjectTypeBoolean: data_str = arena_alloc(arena, 2, false); data_str[0] = elem.data.boolean ? '1' : '0'; - data_str[1] = '\0'; + data_str[1] = NUL; ADD_C(args, CSTR_AS_OBJ(data_str)); break; case kObjectTypeBuffer: @@ -515,7 +515,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Arena if (HAS_KEY(cmd, cmd, magic)) { Dict(cmd_magic) magic[1] = KEYDICT_INIT; - if (!api_dict_to_keydict(magic, KeyDict_cmd_magic_get_field, cmd->magic, err)) { + if (!api_dict_to_keydict(magic, DictHash(cmd_magic), cmd->magic, err)) { goto end; } @@ -533,14 +533,14 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Arena if (HAS_KEY(cmd, cmd, mods)) { Dict(cmd_mods) mods[1] = KEYDICT_INIT; - if (!api_dict_to_keydict(mods, KeyDict_cmd_mods_get_field, cmd->mods, err)) { + if (!api_dict_to_keydict(mods, DictHash(cmd_mods), cmd->mods, err)) { goto end; } if (HAS_KEY(mods, cmd_mods, filter)) { Dict(cmd_mods_filter) filter[1] = KEYDICT_INIT; - if (!api_dict_to_keydict(&filter, KeyDict_cmd_mods_filter_get_field, + if (!api_dict_to_keydict(&filter, DictHash(cmd_mods_filter), mods->filter, err)) { goto end; } @@ -1166,7 +1166,7 @@ err: /// @param[out] err Error details, if any. /// /// @returns Map of maps describing commands. -Dictionary nvim_get_commands(Dict(get_commands) *opts, Arena *arena, Error *err) +Dict nvim_get_commands(Dict(get_commands) *opts, Arena *arena, Error *err) FUNC_API_SINCE(4) { return nvim_buf_get_commands(-1, opts, arena, err); @@ -1179,25 +1179,25 @@ Dictionary nvim_get_commands(Dict(get_commands) *opts, Arena *arena, Error *err) /// @param[out] err Error details, if any. /// /// @returns Map of maps describing commands. -Dictionary nvim_buf_get_commands(Buffer buffer, Dict(get_commands) *opts, Arena *arena, Error *err) +Dict nvim_buf_get_commands(Buffer buffer, Dict(get_commands) *opts, Arena *arena, Error *err) FUNC_API_SINCE(4) { bool global = (buffer == -1); if (ERROR_SET(err)) { - return (Dictionary)ARRAY_DICT_INIT; + return (Dict)ARRAY_DICT_INIT; } if (global) { if (opts->builtin) { api_set_error(err, kErrorTypeValidation, "builtin=true not implemented"); - return (Dictionary)ARRAY_DICT_INIT; + return (Dict)ARRAY_DICT_INIT; } return commands_array(NULL, arena); } buf_T *buf = find_buffer_by_handle(buffer, err); if (opts->builtin || !buf) { - return (Dictionary)ARRAY_DICT_INIT; + return (Dict)ARRAY_DICT_INIT; } return commands_array(buf, arena); } diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index af3bfe2c03..6376011106 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -170,7 +170,7 @@ Integer nvim_buf_set_virtual_text(Buffer buffer, Integer src_id, Integer line, A DecorInline decor = { .ext = true, .data.ext.vt = vt, .data.ext.sh_idx = DECOR_ID_INVALID }; extmark_set(buf, ns_id, NULL, (int)line, 0, -1, -1, decor, 0, true, - false, false, false, false, NULL); + false, false, false, NULL); return src_id; } @@ -183,11 +183,11 @@ Integer nvim_buf_set_virtual_text(Buffer buffer, Integer src_id, Integer line, A /// @param[out] err Error details, if any /// @return Highlight definition map /// @see nvim_get_hl_by_name -Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Arena *arena, Error *err) +Dict nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Arena *arena, Error *err) FUNC_API_SINCE(3) FUNC_API_DEPRECATED_SINCE(9) { - Dictionary dic = ARRAY_DICT_INIT; + Dict dic = ARRAY_DICT_INIT; VALIDATE_INT((syn_get_final_id((int)hl_id) != 0), "highlight id", hl_id, { return dic; }); @@ -204,11 +204,11 @@ Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Arena *arena, Error *er /// @param[out] err Error details, if any /// @return Highlight definition map /// @see nvim_get_hl_by_id -Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Arena *arena, Error *err) +Dict nvim_get_hl_by_name(String name, Boolean rgb, Arena *arena, Error *err) FUNC_API_SINCE(3) FUNC_API_DEPRECATED_SINCE(9) { - Dictionary result = ARRAY_DICT_INIT; + Dict result = ARRAY_DICT_INIT; int id = syn_name2id(name.data); VALIDATE_S((id != 0), "highlight name", name.data, { @@ -515,7 +515,7 @@ static int64_t convert_index(int64_t index) /// @param name Option name /// @param[out] err Error details, if any /// @return Option Information -Dictionary nvim_get_option_info(String name, Arena *arena, Error *err) +Dict nvim_get_option_info(String name, Arena *arena, Error *err) FUNC_API_SINCE(7) FUNC_API_DEPRECATED_SINCE(11) { diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 85cce45560..7786c30624 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -18,6 +18,7 @@ #include "nvim/decoration_provider.h" #include "nvim/drawscreen.h" #include "nvim/extmark.h" +#include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/highlight_group.h" #include "nvim/map_defs.h" @@ -41,6 +42,7 @@ void api_extmark_free_all_mem(void) xfree(name.data); }) map_destroy(String, &namespace_ids); + set_destroy(uint32_t, &namespace_localscope); } /// Creates a new namespace or gets an existing one. [namespace]() @@ -72,10 +74,10 @@ Integer nvim_create_namespace(String name) /// Gets existing, non-anonymous |namespace|s. /// /// @return dict that maps from names to namespace ids. -Dictionary nvim_get_namespaces(Arena *arena) +Dict nvim_get_namespaces(Arena *arena) FUNC_API_SINCE(5) { - Dictionary retval = arena_dict(arena, map_size(&namespace_ids)); + Dict retval = arena_dict(arena, map_size(&namespace_ids)); String name; handle_T id; @@ -156,7 +158,7 @@ static Array extmark_to_array(MTPair extmark, bool id, bool add_dict, bool hl_na if (add_dict) { // TODO(bfredl): coding the size like this is a bit fragile. // We want ArrayOf(Dict(set_extmark)) as the return type.. - Dictionary dict = arena_dict(arena, ARRAY_SIZE(set_extmark_table)); + Dict dict = arena_dict(arena, ARRAY_SIZE(set_extmark_table)); PUT_C(dict, "ns_id", INTEGER_OBJ((Integer)start.ns)); @@ -179,13 +181,9 @@ static Array extmark_to_array(MTPair extmark, bool id, bool add_dict, bool hl_na PUT_C(dict, "invalid", BOOLEAN_OBJ(true)); } - if (mt_scoped(start)) { - PUT_C(dict, "scoped", BOOLEAN_OBJ(true)); - } - decor_to_dict_legacy(&dict, mt_decor(start), hl_name, arena); - ADD_C(rv, DICTIONARY_OBJ(dict)); + ADD_C(rv, DICT_OBJ(dict)); } return rv; @@ -489,8 +487,6 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// used together with virt_text. /// - url: A URL to associate with this extmark. In the TUI, the OSC 8 control /// sequence is used to generate a clickable hyperlink to this URL. -/// - scoped: boolean (EXPERIMENTAL) enables "scoping" for the extmark. See -/// |nvim__win_add_ns()| /// /// @param[out] err Error details, if any /// @return Id of the created/updated extmark @@ -575,7 +571,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer String c = opts->conceal; if (c.size > 0) { int ch; - hl.conceal_char = utfc_ptr2schar_len(c.data, (int)c.size, &ch); + hl.conceal_char = utfc_ptr2schar(c.data, &ch); if (!hl.conceal_char || !vim_isprintc(ch)) { api_set_error(err, kErrorTypeValidation, "conceal char has to be printable"); goto error; @@ -691,6 +687,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer if (HAS_KEY(opts, set_extmark, url)) { url = string_to_cstr(opts->url); + has_hl = true; } if (opts->ui_watched) { @@ -749,11 +746,6 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } if (opts->ephemeral && decor_state.win && decor_state.win->w_buffer == buf) { - if (opts->scoped) { - api_set_error(err, kErrorTypeException, "not yet implemented"); - goto error; - } - int r = (int)line; int c = (int)col; if (line2 == -1) { @@ -767,13 +759,9 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer if (kv_size(virt_lines.data.virt_lines)) { decor_range_add_virt(&decor_state, r, c, line2, col2, decor_put_vt(virt_lines, NULL), true); } - if (url != NULL) { - DecorSignHighlight sh = DECOR_SIGN_HIGHLIGHT_INIT; - sh.url = url; - decor_range_add_sh(&decor_state, r, c, line2, col2, &sh, true, 0, 0); - } if (has_hl) { DecorSignHighlight sh = decor_sh_from_inline(hl); + sh.url = url; decor_range_add_sh(&decor_state, r, c, line2, col2, &sh, true, (uint32_t)ns_id, id); } } else { @@ -797,12 +785,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } uint32_t decor_indexed = DECOR_ID_INVALID; - if (url != NULL) { - DecorSignHighlight sh = DECOR_SIGN_HIGHLIGHT_INIT; - sh.url = url; - sh.next = decor_indexed; - decor_indexed = decor_put_sh(sh); - } + if (sign.flags & kSHIsSign) { sign.next = decor_indexed; decor_indexed = decor_put_sh(sign); @@ -815,9 +798,11 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } DecorInline decor = DECOR_INLINE_INIT; - if (decor_alloc || decor_indexed != DECOR_ID_INVALID || schar_high(hl.conceal_char)) { + if (decor_alloc || decor_indexed != DECOR_ID_INVALID || url != NULL + || schar_high(hl.conceal_char)) { if (has_hl) { DecorSignHighlight sh = decor_sh_from_inline(hl); + sh.url = url; sh.next = decor_indexed; decor_indexed = decor_put_sh(sh); } @@ -834,7 +819,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer extmark_set(buf, (uint32_t)ns_id, &id, (int)line, (colnr_T)col, line2, col2, decor, decor_flags, right_gravity, opts->end_right_gravity, !GET_BOOL_OR_TRUE(opts, set_extmark, undo_restore), - opts->invalidate, opts->scoped, err); + opts->invalidate, err); if (ERROR_SET(err)) { decor_free(decor); return 0; @@ -960,7 +945,7 @@ Integer nvim_buf_add_highlight(Buffer buffer, Integer ns_id, String hl_group, In decor.data.hl.hl_id = hl_id; extmark_set(buf, ns, NULL, (int)line, (colnr_T)col_start, end_line, (colnr_T)col_end, - decor, MT_FLAG_DECOR_HL, true, false, false, false, false, NULL); + decor, MT_FLAG_DECOR_HL, true, false, false, false, NULL); return ns_id; } @@ -1011,7 +996,7 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start, /// Note: this function should not be called often. Rather, the callbacks /// themselves can be used to throttle unneeded callbacks. the `on_start` /// callback can return `false` to disable the provider until the next redraw. -/// Similarly, return `false` in `on_win` will skip the `on_lines` calls +/// Similarly, return `false` in `on_win` will skip the `on_line` calls /// for that window (but any extmarks set in `on_win` will still be used). /// A plugin managing multiple sources of decoration should ideally only set /// one provider, and merge the sources internally. You can use multiple `ns_id` @@ -1020,10 +1005,10 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start, /// Note: doing anything other than setting extmarks is considered experimental. /// Doing things like changing options are not explicitly forbidden, but is /// likely to have unexpected consequences (such as 100% CPU consumption). -/// doing `vim.rpcnotify` should be OK, but `vim.rpcrequest` is quite dubious +/// Doing `vim.rpcnotify` should be OK, but `vim.rpcrequest` is quite dubious /// for the moment. /// -/// Note: It is not allowed to remove or update extmarks in 'on_line' callbacks. +/// Note: It is not allowed to remove or update extmarks in `on_line` callbacks. /// /// @param ns_id Namespace id from |nvim_create_namespace()| /// @param opts Table of callbacks: @@ -1038,7 +1023,7 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start, /// ``` /// - on_win: called when starting to redraw a specific window. /// ``` -/// ["win", winid, bufnr, topline, botline] +/// ["win", winid, bufnr, toprow, botrow] /// ``` /// - on_line: called for each buffer line being redrawn. /// (The interaction with fold lines is subject to change) @@ -1217,77 +1202,119 @@ String nvim__buf_debug_extmarks(Buffer buffer, Boolean keys, Boolean dot, Error /// EXPERIMENTAL: this API will change in the future. /// -/// Scopes a namespace to the a window, so extmarks in the namespace will be active only in the -/// given window. +/// Set some properties for namespace /// -/// @param window Window handle, or 0 for current window /// @param ns_id Namespace -/// @return true if the namespace was added, else false -Boolean nvim__win_add_ns(Window window, Integer ns_id, Error *err) +/// @param opts Optional parameters to set: +/// - wins: a list of windows to be scoped in +/// +void nvim__ns_set(Integer ns_id, Dict(ns_opts) *opts, Error *err) { - win_T *win = find_window_by_handle(window, err); - if (!win) { - return false; - } - VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, { - return false; + return; }); - set_put(uint32_t, &win->w_ns_set, (uint32_t)ns_id); + bool set_scoped = true; - if (map_has(uint32_t, win->w_buffer->b_extmark_ns, (uint32_t)ns_id)) { - changed_window_setting(win); - } + if (HAS_KEY(opts, ns_opts, wins)) { + if (opts->wins.size == 0) { + set_scoped = false; + } - return true; -} + Set(ptr_t) windows = SET_INIT; + for (size_t i = 0; i < opts->wins.size; i++) { + Integer win = opts->wins.items[i].data.integer; -/// EXPERIMENTAL: this API will change in the future. -/// -/// Gets the namespace scopes for a given window. -/// -/// @param window Window handle, or 0 for current window -/// @return a list of namespaces ids -ArrayOf(Integer) nvim__win_get_ns(Window window, Arena *arena, Error *err) -{ - win_T *win = find_window_by_handle(window, err); - if (!win) { - return (Array)ARRAY_DICT_INIT; + win_T *wp = find_window_by_handle((Window)win, err); + if (!wp) { + return; + } + + set_put(ptr_t, &windows, wp); + } + + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (set_has(ptr_t, &windows, wp) && !set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id)) { + set_put(uint32_t, &wp->w_ns_set, (uint32_t)ns_id); + + if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) { + changed_window_setting(wp); + } + } + + if (set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id) && !set_has(ptr_t, &windows, wp)) { + set_del(uint32_t, &wp->w_ns_set, (uint32_t)ns_id); + + if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) { + changed_window_setting(wp); + } + } + } + + set_destroy(ptr_t, &windows); } - Array rv = arena_array(arena, set_size(&win->w_ns_set)); - uint32_t i; - set_foreach(&win->w_ns_set, i, { - ADD_C(rv, INTEGER_OBJ((Integer)(i))); - }); + if (set_scoped && !set_has(uint32_t, &namespace_localscope, (uint32_t)ns_id)) { + set_put(uint32_t, &namespace_localscope, (uint32_t)ns_id); - return rv; + // When a namespace becomes scoped, any window which contains + // elements associated with namespace needs to be redrawn + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) { + changed_window_setting(wp); + } + } + } else if (!set_scoped && set_has(uint32_t, &namespace_localscope, (uint32_t)ns_id)) { + set_del(uint32_t, &namespace_localscope, (uint32_t)ns_id); + + // When a namespace becomes unscoped, any window which does not + // contain elements associated with namespace needs to be redrawn + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) { + changed_window_setting(wp); + } + } + } } /// EXPERIMENTAL: this API will change in the future. /// -/// Unscopes a namespace (un-binds it from the given scope). +/// Get the properties for namespace /// -/// @param window Window handle, or 0 for current window -/// @param ns_id the namespace to remove -/// @return true if the namespace was removed, else false -Boolean nvim__win_del_ns(Window window, Integer ns_id, Error *err) +/// @param ns_id Namespace +/// @return Map defining the namespace properties, see |nvim__ns_set()| +Dict(ns_opts) nvim__ns_get(Integer ns_id, Arena *arena, Error *err) { - win_T *win = find_window_by_handle(window, err); - if (!win) { - return false; + Dict(ns_opts) opts = KEYDICT_INIT; + + Array windows = ARRAY_DICT_INIT; + + PUT_KEY(opts, ns_opts, wins, windows); + + VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, { + return opts; + }); + + if (!set_has(uint32_t, &namespace_localscope, (uint32_t)ns_id)) { + return opts; } - if (!set_has(uint32_t, &win->w_ns_set, (uint32_t)ns_id)) { - return false; + size_t count = 0; + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id)) { + count++; + } } - set_del(uint32_t, &win->w_ns_set, (uint32_t)ns_id); + windows = arena_array(arena, count); - if (map_has(uint32_t, win->w_buffer->b_extmark_ns, (uint32_t)ns_id)) { - changed_window_setting(win); + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id)) { + ADD(windows, INTEGER_OBJ(wp->handle)); + } } - return true; + PUT_KEY(opts, ns_opts, wins, windows); + + return opts; } diff --git a/src/nvim/api/extmark.h b/src/nvim/api/extmark.h index 124feaabfb..af2d51c95c 100644 --- a/src/nvim/api/extmark.h +++ b/src/nvim/api/extmark.h @@ -4,14 +4,29 @@ #include "nvim/api/keysets_defs.h" // IWYU pragma: keep #include "nvim/api/private/defs.h" // IWYU pragma: keep +#include "nvim/buffer_defs.h" #include "nvim/decoration_defs.h" // IWYU pragma: keep #include "nvim/macros_defs.h" #include "nvim/map_defs.h" #include "nvim/types_defs.h" EXTERN Map(String, int) namespace_ids INIT( = MAP_INIT); +/// Non-global namespaces. A locally-scoped namespace may be "orphaned" if all +/// window(s) it was scoped to, are destroyed. Such orphans are tracked here to +/// avoid being mistaken as "global scope". +EXTERN Set(uint32_t) namespace_localscope INIT( = SET_INIT); EXTERN handle_T next_namespace_id INIT( = 1); +/// Returns true if the namespace is global or scoped in the given window. +static inline bool ns_in_win(uint32_t ns_id, win_T *wp) +{ + if (!set_has(uint32_t, &namespace_localscope, ns_id)) { + return true; + } + + return set_has(uint32_t, &wp->w_ns_set, ns_id); +} + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/extmark.h.generated.h" #endif diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h index 00d8aa8428..552612dd13 100644 --- a/src/nvim/api/keysets_defs.h +++ b/src/nvim/api/keysets_defs.h @@ -103,7 +103,7 @@ typedef struct { Object nargs; Object preview; Object range; - Boolean register_; + Boolean register_ DictKey(register); } Dict(user_command); typedef struct { @@ -170,7 +170,7 @@ typedef struct { Boolean reverse; Boolean altfont; Boolean nocombine; - Boolean default_; + Boolean default_ DictKey(default); Object cterm; Object foreground; Object fg; @@ -275,8 +275,8 @@ typedef struct { String reg; Boolean bang; Array args; - Dictionary magic; - Dictionary mods; + Dict magic; + Dict mods; Object nargs; Object addr; Object nextcmd; @@ -293,7 +293,7 @@ typedef struct { Boolean silent; Boolean emsg_silent; Boolean unsilent; - Dictionary filter; + Dict filter; Boolean sandbox; Boolean noautocmd; Boolean browse; @@ -387,3 +387,46 @@ typedef struct { Window win; Buffer buf; } Dict(redraw); + +typedef struct { + OptionalKeys is_set__ns_opts_; + Array wins; +} Dict(ns_opts); + +typedef struct { + OptionalKeys is_set___shada_search_pat_; + Boolean magic DictKey(sm); + Boolean smartcase DictKey(sc); + Boolean has_line_offset DictKey(sl); + Boolean place_cursor_at_end DictKey(se); + Boolean is_last_used DictKey(su); + Boolean is_substitute_pattern DictKey(ss); + Boolean highlighted DictKey(sh); + Boolean search_backward DictKey(sb); + Integer offset DictKey(so); + String pat DictKey(sp); +} Dict(_shada_search_pat); + +typedef struct { + OptionalKeys is_set___shada_mark_; + Integer n; + Integer l; + Integer c; + String f; +} Dict(_shada_mark); + +typedef struct { + OptionalKeys is_set___shada_register_; + StringArray rc; + Boolean ru; + Integer rt; + Integer n; + Integer rw; +} Dict(_shada_register); + +typedef struct { + OptionalKeys is_set___shada_buflist_item_; + Integer l; + Integer c; + String f; +} Dict(_shada_buflist_item); diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index d9bc0ccc92..1a0edd551e 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -54,6 +54,10 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex * } if (HAS_KEY_X(opts, buf)) { + VALIDATE(!(HAS_KEY_X(opts, scope) && *scope == OPT_GLOBAL), "%s", + "cannot use both global 'scope' and 'buf'", { + return FAIL; + }); *scope = OPT_LOCAL; *req_scope = kOptReqBuf; *from = find_buffer_by_handle(opts->buf, err); @@ -68,11 +72,6 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex * return FAIL; }); - VALIDATE((!HAS_KEY_X(opts, scope) || !HAS_KEY_X(opts, buf)), "%s", - "cannot use both 'scope' and 'buf'", { - return FAIL; - }); - VALIDATE((!HAS_KEY_X(opts, win) || !HAS_KEY_X(opts, buf)), "%s", "cannot use both 'buf' and 'win'", { return FAIL; @@ -257,13 +256,13 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict( /// Gets the option information for all options. /// -/// The dictionary has the full option names as keys and option metadata -/// dictionaries as detailed at |nvim_get_option_info2()|. +/// The dict has the full option names as keys and option metadata dicts as detailed at +/// |nvim_get_option_info2()|. /// /// @see |nvim_get_commands()| /// -/// @return dictionary of all options -Dictionary nvim_get_all_options_info(Arena *arena, Error *err) +/// @return dict of all options +Dict nvim_get_all_options_info(Arena *arena, Error *err) FUNC_API_SINCE(7) { return get_all_vimoptions(arena); @@ -271,7 +270,7 @@ Dictionary nvim_get_all_options_info(Arena *arena, Error *err) /// Gets the option information for one option from arbitrary buffer or window /// -/// Resulting dictionary has keys: +/// Resulting dict has keys: /// - name: Name of the option (like 'filetype') /// - shortname: Shortened name of the option (like 'ft') /// - type: type of option ("string", "number" or "boolean") @@ -302,7 +301,7 @@ Dictionary nvim_get_all_options_info(Arena *arena, Error *err) /// Implies {scope} is "local". /// @param[out] err Error details, if any /// @return Option Information -Dictionary nvim_get_option_info2(String name, Dict(option) *opts, Arena *arena, Error *err) +Dict nvim_get_option_info2(String name, Dict(option) *opts, Arena *arena, Error *err) FUNC_API_SINCE(11) { OptIndex opt_idx = 0; @@ -311,7 +310,7 @@ Dictionary nvim_get_option_info2(String name, Dict(option) *opts, Arena *arena, void *from = NULL; if (!validate_option_value_args(opts, name.data, &opt_idx, &scope, &req_scope, &from, NULL, err)) { - return (Dictionary)ARRAY_DICT_INIT; + return (Dict)ARRAY_DICT_INIT; } buf_T *buf = (req_scope == kOptReqBuf) ? (buf_T *)from : curbuf; diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index a78d78c057..59e7373f68 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -7,7 +7,9 @@ #include "nvim/api/private/converter.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/ascii_defs.h" #include "nvim/assert_defs.h" +#include "nvim/eval/decode.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" @@ -28,6 +30,7 @@ typedef struct { #endif #define TYPVAL_ENCODE_ALLOW_SPECIALS false +#define TYPVAL_ENCODE_CHECK_BEFORE #define TYPVAL_ENCODE_CONV_NIL(tv) \ kvi_push(edata->stack, NIL) @@ -91,8 +94,7 @@ static Object typval_cbuf_to_obj(EncodedData *edata, const char *data, size_t le kvi_push(edata->stack, ARRAY_OBJ(((Array) { .capacity = 0, .size = 0 }))) #define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ - kvi_push(edata->stack, \ - DICTIONARY_OBJ(((Dictionary) { .capacity = 0, .size = 0 }))) + kvi_push(edata->stack, DICT_OBJ(((Dict) { .capacity = 0, .size = 0 }))) static inline void typval_encode_list_start(EncodedData *const edata, const size_t len) FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL @@ -134,7 +136,7 @@ static inline void typval_encode_list_end(EncodedData *const edata) static inline void typval_encode_dict_start(EncodedData *const edata, const size_t len) FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL { - kvi_push(edata->stack, DICTIONARY_OBJ(arena_dict(edata->arena, len))); + kvi_push(edata->stack, DICT_OBJ(arena_dict(edata->arena, len))); } #define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) \ @@ -149,13 +151,13 @@ static inline void typval_encode_after_key(EncodedData *const edata) { Object key = kv_pop(edata->stack); Object *const dict = &kv_last(edata->stack); - assert(dict->type == kObjectTypeDictionary); - assert(dict->data.dictionary.size < dict->data.dictionary.capacity); + assert(dict->type == kObjectTypeDict); + assert(dict->data.dict.size < dict->data.dict.capacity); if (key.type == kObjectTypeString) { - dict->data.dictionary.items[dict->data.dictionary.size].key + dict->data.dict.items[dict->data.dict.size].key = key.data.string; } else { - dict->data.dictionary.items[dict->data.dictionary.size].key + dict->data.dict.items[dict->data.dict.size].key = STATIC_CSTR_AS_STRING("__INVALID_KEY__"); } } @@ -168,9 +170,9 @@ static inline void typval_encode_between_dict_items(EncodedData *const edata) { Object val = kv_pop(edata->stack); Object *const dict = &kv_last(edata->stack); - assert(dict->type == kObjectTypeDictionary); - assert(dict->data.dictionary.size < dict->data.dictionary.capacity); - dict->data.dictionary.items[dict->data.dictionary.size++].value = val; + assert(dict->type == kObjectTypeDict); + assert(dict->data.dict.size < dict->data.dict.capacity); + dict->data.dict.items[dict->data.dict.size++].value = val; } #define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict) \ @@ -182,7 +184,7 @@ static inline void typval_encode_dict_end(EncodedData *const edata) typval_encode_between_dict_items(edata); #ifndef NDEBUG const Object *const dict = &kv_last(edata->stack); - assert(dict->data.dictionary.size == dict->data.dictionary.capacity); + assert(dict->data.dict.size == dict->data.dict.capacity); #endif } @@ -217,6 +219,7 @@ static inline void typval_encode_dict_end(EncodedData *const edata) #undef TYPVAL_ENCODE_CONV_LIST_START #undef TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START #undef TYPVAL_ENCODE_CONV_EMPTY_DICT +#undef TYPVAL_ENCODE_CHECK_BEFORE #undef TYPVAL_ENCODE_CONV_NIL #undef TYPVAL_ENCODE_CONV_BOOL #undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER @@ -300,15 +303,11 @@ void object_to_vim_take_luaref(Object *obj, typval_T *tv, bool take_luaref, Erro tv->vval.v_float = obj->data.floating; break; - case kObjectTypeString: - tv->v_type = VAR_STRING; - if (obj->data.string.data == NULL) { - tv->vval.v_string = NULL; - } else { - tv->vval.v_string = xmemdupz(obj->data.string.data, - obj->data.string.size); - } + case kObjectTypeString: { + String s = obj->data.string; + *tv = decode_string(s.data, s.size, false, false); break; + } case kObjectTypeArray: { list_T *const list = tv_list_alloc((ptrdiff_t)obj->data.array.size); @@ -325,11 +324,11 @@ void object_to_vim_take_luaref(Object *obj, typval_T *tv, bool take_luaref, Erro break; } - case kObjectTypeDictionary: { + case kObjectTypeDict: { dict_T *const dict = tv_dict_alloc(); - for (uint32_t i = 0; i < obj->data.dictionary.size; i++) { - KeyValuePair *item = &obj->data.dictionary.items[i]; + for (uint32_t i = 0; i < obj->data.dict.size; i++) { + KeyValuePair *item = &obj->data.dict.items[i]; String key = item->key; dictitem_T *const di = tv_dict_item_alloc(key.data); object_to_vim_take_luaref(&item->value, &di->di_tv, take_luaref, err); diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index ca088d7a55..26d5ac09a8 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -5,7 +5,6 @@ #include <string.h> #include "klib/kvec.h" -#include "nvim/func_attr.h" #include "nvim/types_defs.h" #define ARRAY_DICT_INIT KV_INITIAL_VALUE @@ -18,8 +17,11 @@ #ifdef INCLUDE_GENERATED_DECLARATIONS # define ArrayOf(...) Array -# define DictionaryOf(...) Dictionary +# define DictOf(...) Dict # define Dict(name) KeyDict_##name +# define DictHash(name) KeyDict_##name##_get_field +# define DictKey(name) +# include "api/private/defs.h.inline.generated.h" #endif // Basic types @@ -47,15 +49,13 @@ typedef enum { /// Internal call from Lua code #define LUA_INTERNAL_CALL (VIML_INTERNAL_CALL + 1) -static inline bool is_internal_call(uint64_t channel_id) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST; - /// Check whether call is internal /// /// @param[in] channel_id Channel id. /// /// @return true if channel_id refers to internal channel. static inline bool is_internal_call(const uint64_t channel_id) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_CONST { return !!(channel_id & INTERNAL_CALL_MASK); } @@ -88,7 +88,9 @@ typedef struct object Object; typedef kvec_t(Object) Array; typedef struct key_value_pair KeyValuePair; -typedef kvec_t(KeyValuePair) Dictionary; +typedef kvec_t(KeyValuePair) Dict; + +typedef kvec_t(String) StringArray; typedef enum { kObjectTypeNil = 0, @@ -97,7 +99,7 @@ typedef enum { kObjectTypeFloat, kObjectTypeString, kObjectTypeArray, - kObjectTypeDictionary, + kObjectTypeDict, kObjectTypeLuaRef, // EXT types, cannot be split or reordered, see #EXT_OBJECT_TYPE_SHIFT kObjectTypeBuffer, @@ -105,6 +107,10 @@ typedef enum { kObjectTypeTabpage, } ObjectType; +typedef enum { + kUnpackTypeStringArray = -1, +} UnpackType; + /// Value by which objects represented as EXT type are shifted /// /// Subtracted when packing, added when unpacking. Used to allow moving @@ -121,7 +127,7 @@ struct object { Float floating; String string; Array array; - Dictionary dictionary; + Dict dict; LuaRef luaref; } data; }; @@ -142,7 +148,7 @@ typedef struct { typedef struct { char *str; size_t ptr_off; - ObjectType type; // kObjectTypeNil == untyped + int type; // ObjectType or UnpackType. kObjectTypeNil == untyped int opt_index; bool is_hlgroup; } KeySetLink; diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index a17e78cc31..e1fb4ed732 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -1,6 +1,5 @@ #include <assert.h> #include <limits.h> -#include <msgpack/unpack.h> #include <stdarg.h> #include <stdbool.h> #include <stddef.h> @@ -199,7 +198,7 @@ dictitem_T *dict_check_writable(dict_T *dict, String key, bool del, Error *err) api_set_error(err, kErrorTypeException, "Key is fixed: %s", key.data); } } else if (dict->dv_lock) { - api_set_error(err, kErrorTypeException, "Dictionary is locked"); + api_set_error(err, kErrorTypeException, "Dict is locked"); } else if (key.size == 0) { api_set_error(err, kErrorTypeValidation, "Key name is empty"); } else if (key.size > INT_MAX) { @@ -529,29 +528,19 @@ String buf_get_text(buf_T *buf, int64_t lnum, int64_t start_col, int64_t end_col start_col = start_col < 0 ? line_length + start_col + 1 : start_col; end_col = end_col < 0 ? line_length + end_col + 1 : end_col; - if (start_col >= MAXCOL || end_col >= MAXCOL) { - api_set_error(err, kErrorTypeValidation, "Column index is too high"); - return rv; - } + start_col = MIN(MAX(0, start_col), line_length); + end_col = MIN(MAX(0, end_col), line_length); if (start_col > end_col) { - api_set_error(err, kErrorTypeValidation, "start_col must be less than end_col"); - return rv; - } - - if (start_col >= line_length) { + api_set_error(err, kErrorTypeValidation, "start_col must be less than or equal to end_col"); return rv; } - return cstrn_as_string(&bufstr[start_col], (size_t)(end_col - start_col)); + return cbuf_as_string(bufstr + start_col, (size_t)(end_col - start_col)); } void api_free_string(String value) { - if (!value.data) { - return; - } - xfree(value.data); } @@ -562,9 +551,9 @@ Array arena_array(Arena *arena, size_t max_size) return arr; } -Dictionary arena_dict(Arena *arena, size_t max_size) +Dict arena_dict(Arena *arena, size_t max_size) { - Dictionary dict = ARRAY_DICT_INIT; + Dict dict = ARRAY_DICT_INIT; kv_fixsize_arena(arena, dict, max_size); return dict; } @@ -607,8 +596,8 @@ void api_free_object(Object value) api_free_array(value.data.array); break; - case kObjectTypeDictionary: - api_free_dictionary(value.data.dictionary); + case kObjectTypeDict: + api_free_dict(value.data.dict); break; case kObjectTypeLuaRef: @@ -626,7 +615,7 @@ void api_free_array(Array value) xfree(value.items); } -void api_free_dictionary(Dictionary value) +void api_free_dict(Dict value) { for (size_t i = 0; i < value.size; i++) { api_free_string(value.items[i].key); @@ -659,7 +648,7 @@ Object api_metadata(void) Arena arena = ARENA_EMPTY; Error err = ERROR_INIT; metadata = unpack((char *)packed_api_metadata, sizeof(packed_api_metadata), &arena, &err); - if (ERROR_SET(&err) || metadata.type != kObjectTypeDictionary) { + if (ERROR_SET(&err) || metadata.type != kObjectTypeDict) { abort(); } mem_for_metadata = arena_finish(&arena); @@ -695,9 +684,9 @@ Array copy_array(Array array, Arena *arena) return rv; } -Dictionary copy_dictionary(Dictionary dict, Arena *arena) +Dict copy_dict(Dict dict, Arena *arena) { - Dictionary rv = arena_dict(arena, dict.size); + Dict rv = arena_dict(arena, dict.size); for (size_t i = 0; i < dict.size; i++) { KeyValuePair item = dict.items[i]; PUT_C(rv, copy_string(item.key, arena).data, copy_object(item.value, arena)); @@ -724,8 +713,8 @@ Object copy_object(Object obj, Arena *arena) case kObjectTypeArray: return ARRAY_OBJ(copy_array(obj.data.array, arena)); - case kObjectTypeDictionary: - return DICTIONARY_OBJ(copy_dictionary(obj.data.dictionary, arena)); + case kObjectTypeDict: + return DICT_OBJ(copy_dict(obj.data.dict, arena)); case kObjectTypeLuaRef: return LUAREF_OBJ(api_new_luaref(obj.data.luaref)); @@ -779,7 +768,8 @@ int object_to_hl_id(Object obj, const char *what, Error *err) String str = obj.data.string; return str.size ? syn_check_group(str.data, str.size) : 0; } else if (obj.type == kObjectTypeInteger) { - return MAX((int)obj.data.integer, 0); + int id = (int)obj.data.integer; + return (1 <= id && id <= highlight_num_groups()) ? id : 0; } else { api_set_error(err, kErrorTypeValidation, "Invalid highlight: %s", what); return 0; @@ -801,7 +791,7 @@ char *api_typename(ObjectType t) return "String"; case kObjectTypeArray: return "Array"; - case kObjectTypeDictionary: + case kObjectTypeDict: return "Dict"; case kObjectTypeLuaRef: return "Function"; @@ -854,7 +844,7 @@ free_exit: } // see also nlua_pop_keydict for the lua specific implementation -bool api_dict_to_keydict(void *retval, FieldHashfn hashy, Dictionary dict, Error *err) +bool api_dict_to_keydict(void *retval, FieldHashfn hashy, Dict dict, Error *err) { for (size_t i = 0; i < dict.size; i++) { String k = dict.items[i].key; @@ -918,23 +908,25 @@ bool api_dict_to_keydict(void *retval, FieldHashfn hashy, Dictionary dict, Error return false; }); *(Array *)mem = value->data.array; - } else if (field->type == kObjectTypeDictionary) { - Dictionary *val = (Dictionary *)mem; + } else if (field->type == kObjectTypeDict) { + Dict *val = (Dict *)mem; // allow empty array as empty dict for lua (directly or via lua-client RPC) if (value->type == kObjectTypeArray && value->data.array.size == 0) { - *val = (Dictionary)ARRAY_DICT_INIT; - } else if (value->type == kObjectTypeDictionary) { - *val = value->data.dictionary; + *val = (Dict)ARRAY_DICT_INIT; + } else if (value->type == kObjectTypeDict) { + *val = value->data.dict; } else { - api_err_exp(err, field->str, api_typename(field->type), api_typename(value->type)); + api_err_exp(err, field->str, api_typename((ObjectType)field->type), + api_typename(value->type)); return false; } } else if (field->type == kObjectTypeBuffer || field->type == kObjectTypeWindow || field->type == kObjectTypeTabpage) { - if (value->type == kObjectTypeInteger || value->type == field->type) { + if (value->type == kObjectTypeInteger || value->type == (ObjectType)field->type) { *(handle_T *)mem = (handle_T)value->data.integer; } else { - api_err_exp(err, field->str, api_typename(field->type), api_typename(value->type)); + api_err_exp(err, field->str, api_typename((ObjectType)field->type), + api_typename(value->type)); return false; } } else if (field->type == kObjectTypeLuaRef) { @@ -949,9 +941,9 @@ bool api_dict_to_keydict(void *retval, FieldHashfn hashy, Dictionary dict, Error return true; } -Dictionary api_keydict_to_dict(void *value, KeySetLink *table, size_t max_size, Arena *arena) +Dict api_keydict_to_dict(void *value, KeySetLink *table, size_t max_size, Arena *arena) { - Dictionary rv = arena_dict(arena, max_size); + Dict rv = arena_dict(arena, max_size); for (size_t i = 0; table[i].str; i++) { KeySetLink *field = &table[i]; bool is_set = true; @@ -979,12 +971,12 @@ Dictionary api_keydict_to_dict(void *value, KeySetLink *table, size_t max_size, val = STRING_OBJ(*(String *)mem); } else if (field->type == kObjectTypeArray) { val = ARRAY_OBJ(*(Array *)mem); - } else if (field->type == kObjectTypeDictionary) { - val = DICTIONARY_OBJ(*(Dictionary *)mem); + } else if (field->type == kObjectTypeDict) { + val = DICT_OBJ(*(Dict *)mem); } else if (field->type == kObjectTypeBuffer || field->type == kObjectTypeWindow || field->type == kObjectTypeTabpage) { val.data.integer = *(handle_T *)mem; - val.type = field->type; + val.type = (ObjectType)field->type; } else if (field->type == kObjectTypeLuaRef) { // do nothing } else { @@ -1010,8 +1002,8 @@ void api_luarefs_free_object(Object value) api_luarefs_free_array(value.data.array); break; - case kObjectTypeDictionary: - api_luarefs_free_dict(value.data.dictionary); + case kObjectTypeDict: + api_luarefs_free_dict(value.data.dict); break; default: @@ -1027,8 +1019,8 @@ void api_luarefs_free_keydict(void *dict, KeySetLink *table) api_luarefs_free_object(*(Object *)mem); } else if (table[i].type == kObjectTypeLuaRef) { api_free_luaref(*(LuaRef *)mem); - } else if (table[i].type == kObjectTypeDictionary) { - api_luarefs_free_dict(*(Dictionary *)mem); + } else if (table[i].type == kObjectTypeDict) { + api_luarefs_free_dict(*(Dict *)mem); } } } @@ -1040,7 +1032,7 @@ void api_luarefs_free_array(Array value) } } -void api_luarefs_free_dict(Dictionary value) +void api_luarefs_free_dict(Dict value) { for (size_t i = 0; i < value.size; i++) { api_luarefs_free_object(value.items[i].value); diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 7eda8ffaf6..57932e067e 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -53,9 +53,9 @@ .type = kObjectTypeArray, \ .data.array = a }) -#define DICTIONARY_OBJ(d) ((Object) { \ - .type = kObjectTypeDictionary, \ - .data.dictionary = d }) +#define DICT_OBJ(d) ((Object) { \ + .type = kObjectTypeDict, \ + .data.dict = d }) #define LUAREF_OBJ(r) ((Object) { \ .type = kObjectTypeLuaRef, \ @@ -90,7 +90,7 @@ name.items = name##__items; \ #define MAXSIZE_TEMP_DICT(name, maxsize) \ - Dictionary name = ARRAY_DICT_INIT; \ + Dict name = ARRAY_DICT_INIT; \ KeyValuePair name##__items[maxsize]; \ name.capacity = maxsize; \ name.items = name##__items; \ @@ -121,7 +121,7 @@ typedef kvec_withinit_t(Object, 16) ArrayBuilder; #define api_init_tabpage #define api_init_object = NIL #define api_init_array = ARRAY_DICT_INIT -#define api_init_dictionary = ARRAY_DICT_INIT +#define api_init_dict = ARRAY_DICT_INIT #define KEYDICT_INIT { 0 } diff --git a/src/nvim/api/private/validate.c b/src/nvim/api/private/validate.c index e198c671eb..9fd7d3bfa6 100644 --- a/src/nvim/api/private/validate.c +++ b/src/nvim/api/private/validate.c @@ -17,7 +17,7 @@ void api_err_invalid(Error *err, const char *name, const char *val_s, int64_t va char *has_space = strchr(name, ' '); // No value. - if (val_s && val_s[0] == '\0') { + if (val_s && val_s[0] == NUL) { api_set_error(err, errtype, has_space ? "Invalid %s" : "Invalid '%s'", name); return; } diff --git a/src/nvim/api/private/validate.h b/src/nvim/api/private/validate.h index 2c1d1a241d..67af8adea8 100644 --- a/src/nvim/api/private/validate.h +++ b/src/nvim/api/private/validate.h @@ -42,7 +42,7 @@ #define VALIDATE_T(name, expected_t, actual_t, code) \ do { \ - STATIC_ASSERT(expected_t != kObjectTypeDictionary, "use VALIDATE_T_DICT"); \ + STATIC_ASSERT(expected_t != kObjectTypeDict, "use VALIDATE_T_DICT"); \ if (expected_t != actual_t) { \ api_err_exp(err, name, api_typename(expected_t), api_typename(actual_t)); \ code; \ @@ -52,7 +52,7 @@ /// Checks that `obj_` has type `expected_t`. #define VALIDATE_T2(obj_, expected_t, code) \ do { \ - STATIC_ASSERT(expected_t != kObjectTypeDictionary, "use VALIDATE_T_DICT"); \ + STATIC_ASSERT(expected_t != kObjectTypeDict, "use VALIDATE_T_DICT"); \ if ((obj_).type != expected_t) { \ api_err_exp(err, STR(obj_), api_typename(expected_t), api_typename((obj_).type)); \ code; \ @@ -62,11 +62,11 @@ /// Checks that `obj_` has Dict type. Also allows empty Array in a Lua context. #define VALIDATE_T_DICT(name, obj_, code) \ do { \ - if ((obj_).type != kObjectTypeDictionary \ + if ((obj_).type != kObjectTypeDict \ && !(channel_id == LUA_INTERNAL_CALL \ && (obj_).type == kObjectTypeArray \ && (obj_).data.array.size == 0)) { \ - api_err_exp(err, name, api_typename(kObjectTypeDictionary), api_typename((obj_).type)); \ + api_err_exp(err, name, api_typename(kObjectTypeDict), api_typename((obj_).type)); \ code; \ } \ } while (0) diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index fdf25c75d7..b09a9ed253 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -1,6 +1,5 @@ #include <assert.h> #include <inttypes.h> -#include <msgpack/pack.h> #include <stdbool.h> #include <stddef.h> #include <stdint.h> @@ -94,15 +93,15 @@ void remote_ui_free_all_mem(void) } #endif -/// Wait until ui has connected on stdio channel if only_stdio -/// is true, otherwise any channel. +/// Wait until UI has connected. +/// +/// @param only_stdio UI is expected to connect on stdio. void remote_ui_wait_for_attach(bool only_stdio) { if (only_stdio) { Channel *channel = find_channel(CHAN_STDIO); if (!channel) { - // this function should only be called in --embed mode, stdio channel - // can be assumed. + // `only_stdio` implies --embed mode, thus stdio channel can be assumed. abort(); } @@ -129,8 +128,7 @@ void remote_ui_wait_for_attach(bool only_stdio) /// @param height Requested screen rows /// @param options |ui-option| map /// @param[out] err Error details, if any -void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictionary options, - Error *err) +void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dict options, Error *err) FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY { if (map_has(uint64_t, &connected_uis, channel_id)) { @@ -688,8 +686,8 @@ void remote_ui_hl_attr_define(RemoteUI *ui, Integer id, HlAttrs rgb_attrs, HlAtt PUT_C(rgb, "url", CSTR_AS_OBJ(url)); } - ADD_C(args, DICTIONARY_OBJ(rgb)); - ADD_C(args, DICTIONARY_OBJ(cterm)); + ADD_C(args, DICT_OBJ(rgb)); + ADD_C(args, DICT_OBJ(cterm)); if (ui->ui_ext[kUIHlState]) { ADD_C(args, ARRAY_OBJ(info)); @@ -710,7 +708,7 @@ void remote_ui_highlight_set(RemoteUI *ui, int id) MAXSIZE_TEMP_DICT(dict, HLATTRS_DICT_SIZE); hlattrs2dict(&dict, NULL, syn_attr2entry(id), ui->rgb, false); MAXSIZE_TEMP_ARRAY(args, 1); - ADD_C(args, DICTIONARY_OBJ(dict)); + ADD_C(args, DICT_OBJ(dict)); push_call(ui, "highlight_set", args); } @@ -778,16 +776,26 @@ void remote_ui_raw_line(RemoteUI *ui, Integer grid, Integer row, Integer startco for (size_t i = 0; i < ncells; i++) { repeat++; if (i == ncells - 1 || attrs[i] != attrs[i + 1] || chunk[i] != chunk[i + 1]) { - if (UI_BUF_SIZE - BUF_POS(ui) < 2 * (1 + 2 + MAX_SCHAR_SIZE + 5 + 5) + 1 + if ( + // Close to overflowing the redraw buffer. Finish this event, flush, + // and start a new "grid_line" event at the current position. + // For simplicity leave place for the final "clear" element as well, + // hence the factor of 2 in the check. + UI_BUF_SIZE - BUF_POS(ui) < 2 * (1 + 2 + MAX_SCHAR_SIZE + 5 + 5) + 1 + // Also if there is a lot of packed cells, pass them off to the UI to + // let it start processing them. || ui->ncells_pending >= 500) { - // close to overflowing the redraw buffer. finish this event, - // flush, and start a new "grid_line" event at the current position. - // For simplicity leave place for the final "clear" element - // as well, hence the factor of 2 in the check. - // Also if there is a lot of packed cells, pass them of to the UI to - // let it start processing them + // If the last chunk was all spaces, add an empty clearing chunk, + // so it's clear that the last chunk wasn't a clearing chunk. + if (was_space) { + nelem++; + ui->ncells_pending += 1; + mpack_array(buf, 3); + mpack_str_small(buf, S_LEN(" ")); + mpack_uint(buf, (uint32_t)clearattr); + mpack_uint(buf, 0); + } mpack_w2(&lenpos, nelem); - // We only ever set the wrap field on the final "grid_line" event for the line. mpack_bool(buf, false); ui_flush_buf(ui); @@ -838,7 +846,7 @@ void remote_ui_raw_line(RemoteUI *ui, Integer grid, Integer row, Integer startco char sc_buf[MAX_SCHAR_SIZE]; schar_get(sc_buf, chunk[i]); remote_ui_put(ui, sc_buf); - if (utf_ambiguous_width(utf_ptr2char(sc_buf))) { + if (utf_ambiguous_width(sc_buf)) { ui->client_col = -1; // force cursor update } } @@ -911,11 +919,11 @@ static Array translate_contents(RemoteUI *ui, Array contents, Arena *arena) Array new_item = arena_array(arena, 2); int attr = (int)item.items[0].data.integer; if (attr) { - Dictionary rgb_attrs = arena_dict(arena, HLATTRS_DICT_SIZE); + Dict rgb_attrs = arena_dict(arena, HLATTRS_DICT_SIZE); hlattrs2dict(&rgb_attrs, NULL, syn_attr2entry(attr), ui->rgb, false); - ADD_C(new_item, DICTIONARY_OBJ(rgb_attrs)); + ADD_C(new_item, DICT_OBJ(rgb_attrs)); } else { - ADD_C(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT)); + ADD_C(new_item, DICT_OBJ((Dict)ARRAY_DICT_INIT)); } ADD_C(new_item, item.items[1]); ADD_C(new_contents, ARRAY_OBJ(new_item)); diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index fc780e1248..8c88a19147 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -28,6 +28,8 @@ #include "nvim/cursor.h" #include "nvim/decoration.h" #include "nvim/drawscreen.h" +#include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -68,7 +70,7 @@ #include "nvim/optionstr.h" #include "nvim/os/input.h" #include "nvim/os/os_defs.h" -#include "nvim/os/process.h" +#include "nvim/os/proc.h" #include "nvim/popupmenu.h" #include "nvim/pos_defs.h" #include "nvim/runtime.h" @@ -115,7 +117,7 @@ Integer nvim_get_hl_id_by_name(String name) /// @param[out] err Error details, if any. /// @return Highlight groups as a map from group name to a highlight definition map as in |nvim_set_hl()|, /// or only a single highlight definition map if requested by name or id. -Dictionary nvim_get_hl(Integer ns_id, Dict(get_highlight) *opts, Arena *arena, Error *err) +Dict nvim_get_hl(Integer ns_id, Dict(get_highlight) *opts, Arena *arena, Error *err) FUNC_API_SINCE(11) { return ns_get_hl_defs((NS)ns_id, opts, arena, err); @@ -313,7 +315,7 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks) keys_esc = keys.data; } if (lowlevel) { - input_enqueue_raw(cstr_as_string(keys_esc)); + input_enqueue_raw(keys_esc, strlen(keys_esc)); } else { ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE), insert ? 0 : typebuf.tb_len, !typed, false); @@ -342,9 +344,10 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks) } } -/// Queues raw user-input. Unlike |nvim_feedkeys()|, this uses a low-level -/// input buffer and the call is non-blocking (input is processed -/// asynchronously by the eventloop). +/// Queues raw user-input. Unlike |nvim_feedkeys()|, this uses a low-level input buffer and the call +/// is non-blocking (input is processed asynchronously by the eventloop). +/// +/// To input blocks of text, |nvim_paste()| is much faster and should be preferred. /// /// On execution error: does not fail, but updates v:errmsg. /// @@ -524,13 +527,13 @@ Object nvim_exec_lua(String code, Array args, Arena *arena, Error *err) /// @param log_level The log level /// @param opts Reserved for future use. /// @param[out] err Error details, if any -Object nvim_notify(String msg, Integer log_level, Dictionary opts, Arena *arena, Error *err) +Object nvim_notify(String msg, Integer log_level, Dict opts, Arena *arena, Error *err) FUNC_API_SINCE(7) { MAXSIZE_TEMP_ARRAY(args, 3); ADD_C(args, STRING_OBJ(msg)); ADD_C(args, INTEGER_OBJ(log_level)); - ADD_C(args, DICTIONARY_OBJ(opts)); + ADD_C(args, DICT_OBJ(opts)); return NLUA_EXEC_STATIC("return vim.notify(...)", args, kRetObject, arena, err); } @@ -571,10 +574,10 @@ typedef struct { Arena *arena; } RuntimeCookie; -/// Find files in runtime directories +/// Finds files in runtime directories, in 'runtimepath' order. /// /// "name" can contain wildcards. For example -/// nvim_get_runtime_file("colors/*.vim", true) will return all color +/// `nvim_get_runtime_file("colors/*.{vim,lua}", true)` will return all color /// scheme files. Always use forward slashes (/) in the search pattern for /// subdirectories regardless of platform. /// @@ -1210,17 +1213,30 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err) } } -/// Pastes at cursor, in any mode. +/// Pastes at cursor (in any mode), and sets "redo" so dot (|.|) will repeat the input. UIs call +/// this to implement "paste", but it's also intended for use by scripts to input large, +/// dot-repeatable blocks of text (as opposed to |nvim_input()| which is subject to mappings/events +/// and is thus much slower). +/// +/// Invokes the |vim.paste()| handler, which handles each mode appropriately. /// -/// Invokes the `vim.paste` handler, which handles each mode appropriately. -/// Sets redo/undo. Faster than |nvim_input()|. Lines break at LF ("\n"). +/// Errors ('nomodifiable', `vim.paste()` failure, …) are reflected in `err` but do not affect the +/// return value (which is strictly decided by `vim.paste()`). On error or cancel, subsequent calls +/// are ignored ("drained") until the next paste is initiated (phase 1 or -1). /// -/// Errors ('nomodifiable', `vim.paste()` failure, …) are reflected in `err` -/// but do not affect the return value (which is strictly decided by -/// `vim.paste()`). On error, subsequent calls are ignored ("drained") until -/// the next paste is initiated (phase 1 or -1). +/// Useful in mappings and scripts to insert multiline text. Example: +/// +/// ```lua +/// vim.keymap.set('n', 'x', function() +/// vim.api.nvim_paste([[ +/// line1 +/// line2 +/// line3 +/// ]], false, -1) +/// end, { buffer = true }) +/// ``` /// -/// @param data Multiline input. May be binary (containing NUL bytes). +/// @param data Multiline input. Lines break at LF ("\n"). May be binary (containing NUL bytes). /// @param crlf Also break lines at CR and CRLF. /// @param phase -1: paste in a single call (i.e. without streaming). /// To "stream" a paste, call `nvim_paste` sequentially with @@ -1231,20 +1247,20 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err) /// @param[out] err Error details, if any /// @return /// - true: Client may continue pasting. -/// - false: Client must cancel the paste. -Boolean nvim_paste(String data, Boolean crlf, Integer phase, Arena *arena, Error *err) +/// - false: Client should cancel the paste. +Boolean nvim_paste(uint64_t channel_id, String data, Boolean crlf, Integer phase, Arena *arena, + Error *err) FUNC_API_SINCE(6) FUNC_API_TEXTLOCK_ALLOW_CMDWIN { - static bool draining = false; - bool cancel = false; + static bool cancelled = false; VALIDATE_INT((phase >= -1 && phase <= 3), "phase", phase, { return false; }); if (phase == -1 || phase == 1) { // Start of paste-stream. - draining = false; - } else if (draining) { + cancelled = false; + } else if (cancelled) { // Skip remaining chunks. Report error only once per "stream". goto theend; } @@ -1253,40 +1269,29 @@ Boolean nvim_paste(String data, Boolean crlf, Integer phase, Arena *arena, Error ADD_C(args, ARRAY_OBJ(lines)); ADD_C(args, INTEGER_OBJ(phase)); Object rv = NLUA_EXEC_STATIC("return vim.paste(...)", args, kRetNilBool, arena, err); - if (ERROR_SET(err)) { - draining = true; - goto theend; + // vim.paste() decides if client should cancel. + if (ERROR_SET(err) || (rv.type == kObjectTypeBoolean && !rv.data.boolean)) { + cancelled = true; } - if (!(State & (MODE_CMDLINE | MODE_INSERT)) && (phase == -1 || phase == 1)) { - ResetRedobuff(); - AppendCharToRedobuff('a'); // Dot-repeat. - } - // vim.paste() decides if client should cancel. Errors do NOT cancel: we - // want to drain remaining chunks (rather than divert them to main input). - cancel = (rv.type == kObjectTypeBoolean && !rv.data.boolean); - if (!cancel && !(State & MODE_CMDLINE)) { // Dot-repeat. - for (size_t i = 0; i < lines.size; i++) { - String s = lines.items[i].data.string; - assert(s.size <= INT_MAX); - AppendToRedobuffLit(s.data, (int)s.size); - // readfile()-style: "\n" is indicated by presence of N+1 item. - if (i + 1 < lines.size) { - AppendCharToRedobuff(NL); - } - } + if (!cancelled && (phase == -1 || phase == 1)) { + paste_store(channel_id, kFalse, NULL_STRING, crlf); + } + if (!cancelled) { + paste_store(channel_id, kNone, data, crlf); } - if (!(State & (MODE_CMDLINE | MODE_INSERT)) && (phase == -1 || phase == 3)) { - AppendCharToRedobuff(ESC); // Dot-repeat. + if (phase == 3 || phase == (cancelled ? 2 : -1)) { + paste_store(channel_id, kTrue, NULL_STRING, crlf); } theend: - if (cancel || phase == -1 || phase == 3) { // End of paste-stream. - draining = false; + ; + bool retval = !cancelled; + if (phase == -1 || phase == 3) { // End of paste-stream. + cancelled = false; } - - return !cancel; + return retval; } -/// Puts text at cursor, in any mode. +/// Puts text at cursor, in any mode. For dot-repeatable input, use |nvim_paste()|. /// /// Compare |:put| and |p| which are always linewise. /// @@ -1359,10 +1364,10 @@ Integer nvim_get_color_by_name(String name) /// (e.g. 65535). /// /// @return Map of color names and RGB values. -Dictionary nvim_get_color_map(Arena *arena) +Dict nvim_get_color_map(Arena *arena) FUNC_API_SINCE(1) { - Dictionary colors = arena_dict(arena, ARRAY_SIZE(color_name_table)); + Dict colors = arena_dict(arena, ARRAY_SIZE(color_name_table)); for (int i = 0; color_name_table[i].name != NULL; i++) { PUT_C(colors, color_name_table[i].name, INTEGER_OBJ(color_name_table[i].color)); @@ -1378,7 +1383,7 @@ Dictionary nvim_get_color_map(Arena *arena) /// @param[out] err Error details, if any /// /// @return map of global |context|. -Dictionary nvim_get_context(Dict(context) *opts, Arena *arena, Error *err) +Dict nvim_get_context(Dict(context) *opts, Arena *arena, Error *err) FUNC_API_SINCE(6) { Array types = ARRAY_DICT_INIT; @@ -1405,7 +1410,7 @@ Dictionary nvim_get_context(Dict(context) *opts, Arena *arena, Error *err) int_types |= kCtxFuncs; } else { VALIDATE_S(false, "type", s, { - return (Dictionary)ARRAY_DICT_INIT; + return (Dict)ARRAY_DICT_INIT; }); } } @@ -1414,7 +1419,7 @@ Dictionary nvim_get_context(Dict(context) *opts, Arena *arena, Error *err) Context ctx = CONTEXT_INIT; ctx_save(&ctx, int_types); - Dictionary dict = ctx_to_dict(&ctx, arena); + Dict dict = ctx_to_dict(&ctx, arena); ctx_free(&ctx); return dict; } @@ -1422,7 +1427,7 @@ Dictionary nvim_get_context(Dict(context) *opts, Arena *arena, Error *err) /// Sets the current editor state from the given |context| map. /// /// @param dict |Context| map. -Object nvim_load_context(Dictionary dict, Error *err) +Object nvim_load_context(Dict dict, Error *err) FUNC_API_SINCE(6) { Context ctx = CONTEXT_INIT; @@ -1444,11 +1449,11 @@ Object nvim_load_context(Dictionary dict, Error *err) /// Gets the current mode. |mode()| /// "blocking" is true if Nvim is waiting for input. /// -/// @returns Dictionary { "mode": String, "blocking": Boolean } -Dictionary nvim_get_mode(Arena *arena) +/// @returns Dict { "mode": String, "blocking": Boolean } +Dict nvim_get_mode(Arena *arena) FUNC_API_SINCE(2) FUNC_API_FAST { - Dictionary rv = arena_dict(arena, 2); + Dict rv = arena_dict(arena, 2); char *modestr = arena_alloc(arena, MODE_MAX_LENGTH, false); get_mode(modestr); bool blocked = input_blocking(); @@ -1464,7 +1469,7 @@ Dictionary nvim_get_mode(Arena *arena) /// @param mode Mode short-name ("n", "i", "v", ...) /// @returns Array of |maparg()|-like dictionaries describing mappings. /// The "buffer" key is always zero. -ArrayOf(Dictionary) nvim_get_keymap(String mode, Arena *arena) +ArrayOf(Dict) nvim_get_keymap(String mode, Arena *arena) FUNC_API_SINCE(3) { return keymap_array(mode, NULL, arena); @@ -1523,7 +1528,7 @@ void nvim_del_keymap(uint64_t channel_id, String mode, String lhs, Error *err) } /// Returns a 2-tuple (Array), where item 0 is the current channel id and item -/// 1 is the |api-metadata| map (Dictionary). +/// 1 is the |api-metadata| map (Dict). /// /// @returns 2-tuple `[{channel-id}, {api-metadata}]` Array nvim_get_api_info(uint64_t channel_id, Arena *arena) @@ -1552,7 +1557,7 @@ Array nvim_get_api_info(uint64_t channel_id, Arena *arena) /// /// @param channel_id /// @param name Short name for the connected client -/// @param version Dictionary describing the version, with these +/// @param version Dict describing the version, with these /// (optional) keys: /// - "major" major version (defaults to 0 if not set, for no release yet) /// - "minor" minor version @@ -1584,14 +1589,15 @@ Array nvim_get_api_info(uint64_t channel_id, Arena *arena) /// /// @param attributes Arbitrary string:string map of informal client properties. /// Suggested keys: +/// - "pid": Process id. /// - "website": Client homepage URL (e.g. GitHub repository) /// - "license": License description ("Apache 2", "GPLv3", "MIT", …) /// - "logo": URI or path to image, preferably small logo or icon. /// .png or .svg format is preferred. /// /// @param[out] err Error details, if any -void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version, String type, - Dictionary methods, Dictionary attributes, Arena *arena, Error *err) +void nvim_set_client_info(uint64_t channel_id, String name, Dict version, String type, Dict methods, + Dict attributes, Arena *arena, Error *err) FUNC_API_SINCE(4) FUNC_API_REMOTE_ONLY { MAXSIZE_TEMP_DICT(info, 5); @@ -1605,7 +1611,7 @@ void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version, } } if (!has_major) { - Dictionary v = arena_dict(arena, version.size + 1); + Dict v = arena_dict(arena, version.size + 1); if (version.size) { memcpy(v.items, version.items, version.size * sizeof(v.items[0])); v.size = version.size; @@ -1613,19 +1619,19 @@ void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version, PUT_C(v, "major", INTEGER_OBJ(0)); version = v; } - PUT_C(info, "version", DICTIONARY_OBJ(version)); + PUT_C(info, "version", DICT_OBJ(version)); PUT_C(info, "type", STRING_OBJ(type)); - PUT_C(info, "methods", DICTIONARY_OBJ(methods)); - PUT_C(info, "attributes", DICTIONARY_OBJ(attributes)); + PUT_C(info, "methods", DICT_OBJ(methods)); + PUT_C(info, "attributes", DICT_OBJ(attributes)); - rpc_set_client_info(channel_id, copy_dictionary(info, NULL)); + rpc_set_client_info(channel_id, copy_dict(info, NULL)); } /// Gets information about a channel. /// /// @param chan channel_id, or 0 for current channel -/// @returns Dictionary describing a channel, with these keys: +/// @returns Channel info dict with these keys: /// - "id" Channel id. /// - "argv" (optional) Job arguments list. /// - "stream" Stream underlying the channel. @@ -1637,20 +1643,18 @@ void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version, /// - "bytes" Send and receive raw bytes. /// - "terminal" |terminal| instance interprets ASCII sequences. /// - "rpc" |RPC| communication on the channel is active. -/// - "pty" (optional) Name of pseudoterminal. On a POSIX system this -/// is a device path like "/dev/pts/1". If the name is unknown, -/// the key will still be present if a pty is used (e.g. for -/// conpty on Windows). -/// - "buffer" (optional) Buffer with connected |terminal| instance. -/// - "client" (optional) Info about the peer (client on the other end of -/// the RPC channel), if provided by it via -/// |nvim_set_client_info()|. -/// -Dictionary nvim_get_chan_info(uint64_t channel_id, Integer chan, Arena *arena, Error *err) +/// - "pty" (optional) Name of pseudoterminal. On a POSIX system this is a device path like +/// "/dev/pts/1". If unknown, the key will still be present if a pty is used (e.g. +/// for conpty on Windows). +/// - "buffer" (optional) Buffer connected to |terminal| instance. +/// - "client" (optional) Info about the peer (client on the other end of the RPC channel), +/// which it provided via |nvim_set_client_info()|. +/// +Dict nvim_get_chan_info(uint64_t channel_id, Integer chan, Arena *arena, Error *err) FUNC_API_SINCE(4) { if (chan < 0) { - return (Dictionary)ARRAY_DICT_INIT; + return (Dict)ARRAY_DICT_INIT; } if (chan == 0 && !is_internal_call(channel_id)) { @@ -1747,17 +1751,17 @@ Array nvim__id_array(Array arr, Arena *arena) return copy_array(arr, arena); } -/// Returns dictionary given as argument. +/// Returns dict given as argument. /// /// This API function is used for testing. One should not rely on its presence /// in plugins. /// -/// @param[in] dct Dictionary to return. +/// @param[in] dct Dict to return. /// /// @return its argument. -Dictionary nvim__id_dictionary(Dictionary dct, Arena *arena) +Dict nvim__id_dict(Dict dct, Arena *arena) { - return copy_dictionary(dct, arena); + return copy_dict(dct, arena); } /// Returns floating-point value given as argument. @@ -1776,9 +1780,9 @@ Float nvim__id_float(Float flt) /// Gets internal stats. /// /// @return Map of various internal stats. -Dictionary nvim__stats(Arena *arena) +Dict nvim__stats(Arena *arena) { - Dictionary rv = arena_dict(arena, 6); + Dict rv = arena_dict(arena, 6); PUT_C(rv, "fsync", INTEGER_OBJ(g_stats.fsync)); PUT_C(rv, "log_skip", INTEGER_OBJ(g_stats.log_skip)); PUT_C(rv, "lua_refcount", INTEGER_OBJ(nlua_get_global_ref_count())); @@ -1855,8 +1859,8 @@ Object nvim_get_proc(Integer pid, Arena *arena, Error *err) }); #ifdef MSWIN - rvobj = DICTIONARY_OBJ(os_proc_info((int)pid, arena)); - if (rvobj.data.dictionary.size == 0) { // Process not found. + rvobj = DICT_OBJ(os_proc_info((int)pid, arena)); + if (rvobj.data.dict.size == 0) { // Process not found. return NIL; } #else @@ -1866,7 +1870,7 @@ Object nvim_get_proc(Integer pid, Arena *arena, Error *err) Object o = NLUA_EXEC_STATIC("return vim._os_proc_info(...)", a, kRetObject, arena, err); if (o.type == kObjectTypeArray && o.data.array.size == 0) { return NIL; // Process not found. - } else if (o.type == kObjectTypeDictionary) { + } else if (o.type == kObjectTypeDict) { rvobj = o; } else if (!ERROR_SET(err)) { api_set_error(err, kErrorTypeException, @@ -1930,7 +1934,7 @@ Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Arena *arena, E schar_get(sc_buf, g->chars[off]); ADD_C(ret, CSTR_AS_OBJ(sc_buf)); int attr = g->attrs[off]; - ADD_C(ret, DICTIONARY_OBJ(hl_get_attr_by_id(attr, true, arena, err))); + ADD_C(ret, DICT_OBJ(hl_get_attr_by_id(attr, true, arena, err))); // will not work first time if (!highlight_use_hlstate()) { ADD_C(ret, ARRAY_OBJ(hl_inspect(attr, arena))); @@ -2073,18 +2077,18 @@ Array nvim_get_mark(String name, Dict(empty) *opts, Arena *arena, Error *err) /// - use_statuscol_lnum: (number) Evaluate statuscolumn for this line number instead of statusline. /// /// @param[out] err Error details, if any. -/// @return Dictionary containing statusline information, with these keys: +/// @return Dict containing statusline information, with these keys: /// - str: (string) Characters that will be displayed on the statusline. /// - width: (number) Display width of the statusline. /// - highlights: Array containing highlight information of the statusline. Only included when /// the "highlights" key in {opts} is true. Each element of the array is a -/// |Dictionary| with these keys: +/// |Dict| with these keys: /// - start: (number) Byte index (0-based) of first character that uses the highlight. /// - group: (string) Name of highlight group. -Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Arena *arena, Error *err) +Dict nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Arena *arena, Error *err) FUNC_API_SINCE(8) FUNC_API_FAST { - Dictionary result = ARRAY_DICT_INIT; + Dict result = ARRAY_DICT_INIT; int maxwidth; schar_T fillchar = 0; @@ -2210,18 +2214,18 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Arena * // If first character doesn't have a defined highlight, // add the default highlight at the beginning of the highlight list if (hltab->start == NULL || (hltab->start - buf) != 0) { - Dictionary hl_info = arena_dict(arena, 2); + Dict hl_info = arena_dict(arena, 2); const char *grpname = get_default_stl_hl(opts->use_tabline ? NULL : wp, opts->use_winbar, stc_hl_id); PUT_C(hl_info, "start", INTEGER_OBJ(0)); PUT_C(hl_info, "group", CSTR_AS_OBJ(grpname)); - ADD_C(hl_values, DICTIONARY_OBJ(hl_info)); + ADD_C(hl_values, DICT_OBJ(hl_info)); } for (stl_hlrec_t *sp = hltab; sp->start != NULL; sp++) { - Dictionary hl_info = arena_dict(arena, 2); + Dict hl_info = arena_dict(arena, 2); PUT_C(hl_info, "start", INTEGER_OBJ(sp->start - buf)); @@ -2235,7 +2239,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Arena * grpname = arena_memdupz(arena, user_group, strlen(user_group)); } PUT_C(hl_info, "group", CSTR_AS_OBJ(grpname)); - ADD_C(hl_values, DICTIONARY_OBJ(hl_info)); + ADD_C(hl_values, DICT_OBJ(hl_info)); } PUT_C(result, "highlights", ARRAY_OBJ(hl_values)); } @@ -2261,12 +2265,12 @@ void nvim_error_event(uint64_t channel_id, Integer lvl, String data) /// @param index Completion candidate index /// @param opts Optional parameters. /// - info: (string) info text. -/// @return Dictionary containing these keys: +/// @return Dict containing these keys: /// - winid: (number) floating window id /// - bufnr: (number) buffer id in floating window -Dictionary nvim__complete_set(Integer index, Dict(complete_set) *opts, Arena *arena) +Dict nvim__complete_set(Integer index, Dict(complete_set) *opts, Arena *arena) { - Dictionary rv = arena_dict(arena, 2); + Dict rv = arena_dict(arena, 2); if (HAS_KEY(opts, complete_set, info)) { win_T *wp = pum_set_info((int)index, opts->info.data); if (wp) { @@ -2354,8 +2358,8 @@ void nvim__redraw(Dict(redraw) *opts, Error *err) } } - int count = (win != NULL) + (buf != NULL); - VALIDATE(popcount(opts->is_set__redraw_) > count, "%s", "at least one action required", { + unsigned count = (win != NULL) + (buf != NULL); + VALIDATE(xpopcount(opts->is_set__redraw_) > count, "%s", "at least one action required", { return; }); @@ -2392,10 +2396,6 @@ void nvim__redraw(Dict(redraw) *opts, Error *err) redraw_buf_range_later(rbuf, first, last); } - if (opts->cursor) { - setcursor_mayforce(win ? win : curwin, true); - } - bool flush = opts->flush; if (opts->tabline) { // Flush later in case tabline was just hidden or shown for the first time. @@ -2422,11 +2422,22 @@ void nvim__redraw(Dict(redraw) *opts, Error *err) } } - // Flush pending screen updates if "flush" or "clear" is true, or when - // redrawing a status component may have changed the grid dimensions. + win_T *cwin = win ? win : curwin; + // Allow moving cursor to recently opened window and make sure it is drawn #28868. + if (opts->cursor && (!cwin->w_grid.target || !cwin->w_grid.target->valid)) { + flush = true; + } + + // Redraw pending screen updates when explicitly requested or when determined + // that it is necessary to properly draw other requested components. if (flush && !cmdpreview) { update_screen(); } + + if (opts->cursor) { + setcursor_mayforce(cwin, true); + } + ui_flush(); RedrawingDisabled = save_rd; diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index 477cbe2428..165cc93fbe 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -48,12 +48,12 @@ /// - output: (boolean, default false) Whether to capture and return /// all (non-error, non-shell |:!|) output. /// @param[out] err Error details (Vim error), if any -/// @return Dictionary containing information about execution, with these keys: +/// @return Dict containing information about execution, with these keys: /// - output: (string|nil) Output if `opts.output` is true. -Dictionary nvim_exec2(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error *err) +Dict nvim_exec2(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error *err) FUNC_API_SINCE(11) FUNC_API_RET_ALLOC { - Dictionary result = ARRAY_DICT_INIT; + Dict result = ARRAY_DICT_INIT; String output = exec_impl(channel_id, src, opts, err); if (ERROR_SET(err)) { @@ -109,7 +109,7 @@ String exec_impl(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error * // redir usually (except :echon) prepends a newline. if (s.data[0] == '\n') { memmove(s.data, s.data + 1, s.size - 1); - s.data[s.size - 1] = '\0'; + s.data[s.size - 1] = NUL; s.size = s.size - 1; } return s; // Caller will free the memory. @@ -140,8 +140,7 @@ void nvim_command(String command, Error *err) try_end(err); } -/// Evaluates a Vimscript |expression|. -/// Dictionaries and Lists are recursively expanded. +/// Evaluates a Vimscript |expression|. Dicts and Lists are recursively expanded. /// /// On execution error: fails with Vimscript error, updates v:errmsg. /// @@ -270,7 +269,7 @@ Object nvim_call_function(String fn, Array args, Arena *arena, Error *err) /// /// On execution error: fails with Vimscript error, updates v:errmsg. /// -/// @param dict Dictionary, or String evaluating to a Vimscript |self| dict +/// @param dict Dict, or String evaluating to a Vimscript |self| dict /// @param fn Name of the function defined on the Vimscript dict /// @param args Function arguments packed in an Array /// @param[out] err Error details, if any @@ -297,12 +296,11 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Arena *arena, // refcount of a dict. Not necessary for a RPC dict. mustfree = true; break; - case kObjectTypeDictionary: + case kObjectTypeDict: object_to_vim(dict, &rettv, err); break; default: - api_set_error(err, kErrorTypeValidation, - "dict argument type must be String or Dictionary"); + api_set_error(err, kErrorTypeValidation, "dict argument type must be String or Dict"); return rv; } dict_T *self_dict = rettv.vval.v_dict; @@ -311,7 +309,7 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Arena *arena, goto end; } - if (fn.data && fn.size > 0 && dict.type != kObjectTypeDictionary) { + if (fn.data && fn.size > 0 && dict.type != kObjectTypeDict) { dictitem_T *const di = tv_dict_find(self_dict, fn.data, (ptrdiff_t)fn.size); if (di == NULL) { api_set_error(err, kErrorTypeValidation, "Not found: %s", fn.data); @@ -377,8 +375,8 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack; /// one should highlight region [start_col, end_col)). /// /// @return -/// - AST: top-level dictionary with these keys: -/// - "error": Dictionary with error, present only if parser saw some +/// - AST: top-level dict with these keys: +/// - "error": Dict with error, present only if parser saw some /// error. Contains the following keys: /// - "message": String, error message in printf format, translated. /// Must contain exactly one "%.*s". @@ -387,7 +385,7 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack; /// that should be equal to the length of expr string. /// ("Successfully parsed" here means "participated in AST /// creation", not "till the first error".) -/// - "ast": AST, either nil or a dictionary with these keys: +/// - "ast": AST, either nil or a dict with these keys: /// - "type": node type, one of the value names from ExprASTNodeType /// stringified without "kExprNode" prefix. /// - "start": a pair `[line, column]` describing where node is "started" @@ -427,8 +425,7 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack; /// - "svalue": String, value for "SingleQuotedString" and /// "DoubleQuotedString" nodes. /// @param[out] err Error details, if any -Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, Arena *arena, - Error *err) +Dict nvim_parse_expression(String expr, String flags, Boolean highlight, Arena *arena, Error *err) FUNC_API_SINCE(4) FUNC_API_FAST { int pflags = 0; @@ -443,11 +440,11 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, A case NUL: api_set_error(err, kErrorTypeValidation, "Invalid flag: '\\0' (%u)", (unsigned)flags.data[i]); - return (Dictionary)ARRAY_DICT_INIT; + return (Dict)ARRAY_DICT_INIT; default: api_set_error(err, kErrorTypeValidation, "Invalid flag: '%c' (%u)", flags.data[i], (unsigned)flags.data[i]); - return (Dictionary)ARRAY_DICT_INIT; + return (Dict)ARRAY_DICT_INIT; } } ParserLine parser_lines[] = { @@ -471,15 +468,15 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, A + (size_t)highlight // "highlight" + 0); - Dictionary ret = arena_dict(arena, ret_size); + Dict ret = arena_dict(arena, ret_size); PUT_C(ret, "len", INTEGER_OBJ((Integer)(pstate.pos.line == 1 ? parser_lines[0].size : pstate.pos.col))); if (east.err.msg != NULL) { - Dictionary err_dict = arena_dict(arena, 2); + Dict err_dict = arena_dict(arena, 2); PUT_C(err_dict, "message", CSTR_TO_ARENA_OBJ(arena, east.err.msg)); PUT_C(err_dict, "arg", CBUF_TO_ARENA_OBJ(arena, east.err.arg, (size_t)east.err.arg_len)); - PUT_C(ret, "error", DICTIONARY_OBJ(err_dict)); + PUT_C(ret, "error", DICT_OBJ(err_dict)); } if (highlight) { Array hl = arena_array(arena, kv_size(colors)); @@ -530,10 +527,10 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, A || node->type == kExprNodeSingleQuotedString) // "svalue" + (node->type == kExprNodeAssignment) // "augmentation" + 0); - Dictionary ret_node = arena_dict(arena, items_size); - *cur_item.ret_node_p = DICTIONARY_OBJ(ret_node); + Dict ret_node = arena_dict(arena, items_size); + *cur_item.ret_node_p = DICT_OBJ(ret_node); } - Dictionary *ret_node = &cur_item.ret_node_p->data.dictionary; + Dict *ret_node = &cur_item.ret_node_p->data.dict; if (node->children != NULL) { const size_t num_children = 1 + (node->children->next != NULL); Array children_array = arena_array(arena, num_children); @@ -638,8 +635,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, A case kExprNodeMod: break; } - assert(cur_item.ret_node_p->data.dictionary.size - == cur_item.ret_node_p->data.dictionary.capacity); + assert(cur_item.ret_node_p->data.dict.size == cur_item.ret_node_p->data.dict.capacity); xfree(*cur_item.node_p); *cur_item.node_p = NULL; } diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 3a9986a7d1..f63fdc5381 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -17,6 +17,7 @@ #include "nvim/decoration.h" #include "nvim/decoration_defs.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval/window.h" #include "nvim/extmark_defs.h" #include "nvim/globals.h" @@ -189,13 +190,13 @@ /// ``` /// - title: Title (optional) in window border, string or list. /// List should consist of `[text, highlight]` tuples. -/// If string, the default highlight group is `FloatTitle`. +/// If string, or a tuple lacks a highlight, the default highlight group is `FloatTitle`. /// - title_pos: Title position. Must be set with `title` option. /// Value can be one of "left", "center", or "right". /// Default is `"left"`. /// - footer: Footer (optional) in window border, string or list. /// List should consist of `[text, highlight]` tuples. -/// If string, the default highlight group is `FloatFooter`. +/// If string, or a tuple lacks a highlight, the default highlight group is `FloatFooter`. /// - footer_pos: Footer position. Must be set with `footer` option. /// Value can be one of "left", "center", or "right". /// Default is `"left"`. @@ -447,7 +448,7 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) } } } - win->w_config = fconfig; + merge_win_config(&win->w_config, fconfig); // If there's no "vertical" or "split" set, or if "split" is unchanged, // then we can just change the size of the window. @@ -851,27 +852,16 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type, bool *is_present; VirtText *chunks; int *width; - int default_hl_id; switch (bordertext_type) { case kBorderTextTitle: - if (fconfig->title) { - clear_virttext(&fconfig->title_chunks); - } - is_present = &fconfig->title; chunks = &fconfig->title_chunks; width = &fconfig->title_width; - default_hl_id = syn_check_group(S_LEN("FloatTitle")); break; case kBorderTextFooter: - if (fconfig->footer) { - clear_virttext(&fconfig->footer_chunks); - } - is_present = &fconfig->footer; chunks = &fconfig->footer_chunks; width = &fconfig->footer_width; - default_hl_id = syn_check_group(S_LEN("FloatFooter")); break; } @@ -880,8 +870,9 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type, *is_present = false; return; } + kv_init(*chunks); kv_push(*chunks, ((VirtTextChunk){ .text = xstrdup(bordertext.data.string.data), - .hl_id = default_hl_id })); + .hl_id = -1 })); *width = (int)mb_string2cells(bordertext.data.string.data); *is_present = true; return; @@ -1040,7 +1031,7 @@ static void parse_border_style(Object style, WinConfig *fconfig, Error *err) static void generate_api_error(win_T *wp, const char *attribute, Error *err) { - if (wp->w_floating) { + if (wp != NULL && wp->w_floating) { api_set_error(err, kErrorTypeValidation, "Missing 'relative' field when reconfiguring floating window %d", wp->handle); @@ -1057,13 +1048,13 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco if (config->relative.size > 0) { if (!parse_float_relative(config->relative, &fconfig->relative)) { api_set_error(err, kErrorTypeValidation, "Invalid value of 'relative' key"); - return false; + goto fail; } if (config->relative.size > 0 && !(HAS_KEY_X(config, row) && HAS_KEY_X(config, col)) && !HAS_KEY_X(config, bufpos)) { api_set_error(err, kErrorTypeValidation, "'relative' requires 'row'/'col' or 'bufpos'"); - return false; + goto fail; } has_relative = true; @@ -1078,39 +1069,39 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco } else if (wp == NULL) { // new win api_set_error(err, kErrorTypeValidation, "Must specify 'relative' or 'external' when creating a float"); - return false; + goto fail; } } if (HAS_KEY_X(config, vertical)) { if (!is_split) { api_set_error(err, kErrorTypeValidation, "floating windows cannot have 'vertical'"); - return false; + goto fail; } } if (HAS_KEY_X(config, split)) { if (!is_split) { api_set_error(err, kErrorTypeValidation, "floating windows cannot have 'split'"); - return false; + goto fail; } if (!parse_config_split(config->split, &fconfig->split)) { api_set_error(err, kErrorTypeValidation, "Invalid value of 'split' key"); - return false; + goto fail; } } if (HAS_KEY_X(config, anchor)) { if (!parse_float_anchor(config->anchor, &fconfig->anchor)) { api_set_error(err, kErrorTypeValidation, "Invalid value of 'anchor' key"); - return false; + goto fail; } } if (HAS_KEY_X(config, row)) { if (!has_relative || is_split) { generate_api_error(wp, "row", err); - return false; + goto fail; } fconfig->row = config->row; } @@ -1118,7 +1109,7 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco if (HAS_KEY_X(config, col)) { if (!has_relative || is_split) { generate_api_error(wp, "col", err); - return false; + goto fail; } fconfig->col = config->col; } @@ -1126,11 +1117,11 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco if (HAS_KEY_X(config, bufpos)) { if (!has_relative || is_split) { generate_api_error(wp, "bufpos", err); - return false; + goto fail; } else { if (!parse_float_bufpos(config->bufpos, &fconfig->bufpos)) { api_set_error(err, kErrorTypeValidation, "Invalid value of 'bufpos' key"); - return false; + goto fail; } if (!HAS_KEY_X(config, row)) { @@ -1147,11 +1138,11 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco fconfig->width = (int)config->width; } else { api_set_error(err, kErrorTypeValidation, "'width' key must be a positive Integer"); - return false; + goto fail; } } else if (!reconf && !is_split) { api_set_error(err, kErrorTypeValidation, "Must specify 'width'"); - return false; + goto fail; } if (HAS_KEY_X(config, height)) { @@ -1159,23 +1150,23 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco fconfig->height = (int)config->height; } else { api_set_error(err, kErrorTypeValidation, "'height' key must be a positive Integer"); - return false; + goto fail; } } else if (!reconf && !is_split) { api_set_error(err, kErrorTypeValidation, "Must specify 'height'"); - return false; + goto fail; } if (relative_is_win || is_split) { if (reconf && relative_is_win) { win_T *target_win = find_window_by_handle(config->win, err); if (!target_win) { - return false; + goto fail; } if (target_win == wp) { api_set_error(err, kErrorTypeException, "floating window cannot be relative to itself"); - return false; + goto fail; } } fconfig->window = curwin->handle; @@ -1188,11 +1179,11 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco if (has_relative) { api_set_error(err, kErrorTypeValidation, "'win' key is only valid with relative='win' and relative=''"); - return false; + goto fail; } else if (!is_split) { api_set_error(err, kErrorTypeValidation, "non-float with 'win' requires at least 'split' or 'vertical'"); - return false; + goto fail; } } @@ -1201,11 +1192,11 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco if (has_relative && fconfig->external) { api_set_error(err, kErrorTypeValidation, "Only one of 'relative' and 'external' must be used"); - return false; + goto fail; } if (fconfig->external && !ui_has(kUIMultigrid)) { api_set_error(err, kErrorTypeValidation, "UI doesn't support external windows"); - return false; + goto fail; } } @@ -1216,78 +1207,78 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco if (HAS_KEY_X(config, zindex)) { if (is_split) { api_set_error(err, kErrorTypeValidation, "non-float cannot have 'zindex'"); - return false; + goto fail; } if (config->zindex > 0) { fconfig->zindex = (int)config->zindex; } else { api_set_error(err, kErrorTypeValidation, "'zindex' key must be a positive Integer"); - return false; + goto fail; } } if (HAS_KEY_X(config, title)) { if (is_split) { api_set_error(err, kErrorTypeValidation, "non-float cannot have 'title'"); - return false; + goto fail; } // title only work with border if (!HAS_KEY_X(config, border) && !fconfig->border) { api_set_error(err, kErrorTypeException, "title requires border to be set"); - return false; + goto fail; } parse_bordertext(config->title, kBorderTextTitle, fconfig, err); if (ERROR_SET(err)) { - return false; + goto fail; } // handles unset 'title_pos' same as empty string if (!parse_bordertext_pos(config->title_pos, kBorderTextTitle, fconfig, err)) { - return false; + goto fail; } } else { if (HAS_KEY_X(config, title_pos)) { api_set_error(err, kErrorTypeException, "title_pos requires title to be set"); - return false; + goto fail; } } if (HAS_KEY_X(config, footer)) { if (is_split) { api_set_error(err, kErrorTypeValidation, "non-float cannot have 'footer'"); - return false; + goto fail; } // footer only work with border if (!HAS_KEY_X(config, border) && !fconfig->border) { api_set_error(err, kErrorTypeException, "footer requires border to be set"); - return false; + goto fail; } parse_bordertext(config->footer, kBorderTextFooter, fconfig, err); if (ERROR_SET(err)) { - return false; + goto fail; } // handles unset 'footer_pos' same as empty string if (!parse_bordertext_pos(config->footer_pos, kBorderTextFooter, fconfig, err)) { - return false; + goto fail; } } else { if (HAS_KEY_X(config, footer_pos)) { api_set_error(err, kErrorTypeException, "footer_pos requires footer to be set"); - return false; + goto fail; } } if (HAS_KEY_X(config, border)) { if (is_split) { api_set_error(err, kErrorTypeValidation, "non-float cannot have 'border'"); - return false; + goto fail; } parse_border_style(config->border, fconfig, err); if (ERROR_SET(err)) { - return false; + goto fail; } } @@ -1298,14 +1289,14 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco fconfig->style = kWinStyleMinimal; } else { api_set_error(err, kErrorTypeValidation, "Invalid value of 'style' key"); - return false; + goto fail; } } if (HAS_KEY_X(config, noautocmd)) { if (wp) { api_set_error(err, kErrorTypeValidation, "'noautocmd' cannot be used with existing windows"); - return false; + goto fail; } fconfig->noautocmd = config->noautocmd; } @@ -1319,5 +1310,9 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco } return true; + +fail: + merge_win_config(fconfig, wp != NULL ? wp->w_config : WIN_CONFIG_INIT); + return false; #undef HAS_KEY_X } diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 54a19513db..5a4972ef23 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -13,6 +13,7 @@ #include "nvim/buffer_defs.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval/window.h" #include "nvim/ex_docmd.h" #include "nvim/gettext_defs.h" @@ -502,16 +503,15 @@ void nvim_win_set_hl_ns(Window window, Integer ns_id, Error *err) /// - end_vcol: Ending virtual column index on "end_row", /// 0-based exclusive, rounded up to full screen lines. /// When omitted include the whole line. -/// @return Dictionary containing text height information, with these keys: +/// @return Dict containing text height information, with these keys: /// - all: The total number of screen lines occupied by the range. /// - fill: The number of diff filler or virtual lines among them. /// /// @see |virtcol()| for text width. -Dictionary nvim_win_text_height(Window window, Dict(win_text_height) *opts, Arena *arena, - Error *err) +Dict nvim_win_text_height(Window window, Dict(win_text_height) *opts, Arena *arena, Error *err) FUNC_API_SINCE(12) { - Dictionary rv = arena_dict(arena, 2); + Dict rv = arena_dict(arena, 2); win_T *const win = find_window_by_handle(window, err); if (!win) { diff --git a/src/nvim/arglist.c b/src/nvim/arglist.c index 4d493c9d03..bb639edc07 100644 --- a/src/nvim/arglist.c +++ b/src/nvim/arglist.c @@ -13,6 +13,7 @@ #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" +#include "nvim/errors.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/window.h" @@ -202,6 +203,8 @@ void alist_set(alist_T *al, int count, char **files, int use_curbuf, int *fnum_l /// Add file "fname" to argument list "al". /// "fname" must have been allocated and "al" must have been checked for room. /// +/// May trigger Buf* autocommands +/// /// @param set_fnum 1: set buffer number; 2: re-use curbuf void alist_add(alist_T *al, char *fname, int set_fnum) { @@ -212,6 +215,7 @@ void alist_add(alist_T *al, char *fname, int set_fnum) return; } arglist_locked = true; + curwin->w_locked = true; #ifdef BACKSLASH_IN_FILENAME slash_adjust(fname); @@ -224,6 +228,7 @@ void alist_add(alist_T *al, char *fname, int set_fnum) al->al_ga.ga_len++; arglist_locked = false; + curwin->w_locked = false; } #if defined(BACKSLASH_IN_FILENAME) @@ -345,23 +350,20 @@ static void alist_add_list(int count, char **files, int after, bool will_edit) int old_argcount = ARGCOUNT; ga_grow(&ALIST(curwin)->al_ga, count); if (check_arglist_locked() != FAIL) { - if (after < 0) { - after = 0; - } - if (after > ARGCOUNT) { - after = ARGCOUNT; - } + after = MIN(MAX(after, 0), ARGCOUNT); if (after < ARGCOUNT) { memmove(&(ARGLIST[after + count]), &(ARGLIST[after]), (size_t)(ARGCOUNT - after) * sizeof(aentry_T)); } arglist_locked = true; + curwin->w_locked = true; for (int i = 0; i < count; i++) { const int flags = BLN_LISTED | (will_edit ? BLN_CURBUF : 0); ARGLIST[after + i].ae_fname = files[i]; ARGLIST[after + i].ae_fnum = buflist_add(files[i], flags); } arglist_locked = false; + curwin->w_locked = false; ALIST(curwin)->al_ga.ga_len += count; if (old_argcount > 0 && curwin->w_arg_idx >= after) { curwin->w_arg_idx += count; diff --git a/src/nvim/ascii_defs.h b/src/nvim/ascii_defs.h index 0cd7ccfec4..155a18fb95 100644 --- a/src/nvim/ascii_defs.h +++ b/src/nvim/ascii_defs.h @@ -2,9 +2,12 @@ #include <stdbool.h> -#include "nvim/func_attr.h" #include "nvim/os/os_defs.h" +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "ascii_defs.h.inline.generated.h" +#endif + // Definitions of various common control characters. #define CHAR_ORD(x) ((uint8_t)(x) < 'a' \ @@ -82,31 +85,24 @@ # define PATHSEPSTR "/" #endif -static inline bool ascii_iswhite(int c) - REAL_FATTR_CONST - REAL_FATTR_ALWAYS_INLINE; /// Checks if `c` is a space or tab character. /// /// @see {ascii_isdigit} static inline bool ascii_iswhite(int c) + FUNC_ATTR_CONST FUNC_ATTR_ALWAYS_INLINE { return c == ' ' || c == '\t'; } -static inline bool ascii_iswhite_or_nul(int c) - REAL_FATTR_CONST - REAL_FATTR_ALWAYS_INLINE; /// Checks if `c` is a space or tab character or NUL. /// /// @see {ascii_isdigit} static inline bool ascii_iswhite_or_nul(int c) + FUNC_ATTR_CONST FUNC_ATTR_ALWAYS_INLINE { return ascii_iswhite(c) || c == NUL; } -static inline bool ascii_isdigit(int c) - REAL_FATTR_CONST - REAL_FATTR_ALWAYS_INLINE; /// Check whether character is a decimal digit. /// /// Library isdigit() function is officially locale-dependent and, for @@ -117,64 +113,55 @@ static inline bool ascii_isdigit(int c) /// what may be used for some optimizations (e.g. simple `return /// isdigit_table[c];`). static inline bool ascii_isdigit(int c) + FUNC_ATTR_CONST FUNC_ATTR_ALWAYS_INLINE { return c >= '0' && c <= '9'; } -static inline bool ascii_isxdigit(int c) - REAL_FATTR_CONST - REAL_FATTR_ALWAYS_INLINE; /// Checks if `c` is a hexadecimal digit, that is, one of 0-9, a-f, A-F. /// /// @see {ascii_isdigit} static inline bool ascii_isxdigit(int c) + FUNC_ATTR_CONST FUNC_ATTR_ALWAYS_INLINE { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } -static inline bool ascii_isident(int c) - REAL_FATTR_CONST - REAL_FATTR_ALWAYS_INLINE; /// Checks if `c` is an “identifier†character /// /// That is, whether it is alphanumeric character or underscore. static inline bool ascii_isident(int c) + FUNC_ATTR_CONST FUNC_ATTR_ALWAYS_INLINE { return ASCII_ISALNUM(c) || c == '_'; } -static inline bool ascii_isbdigit(int c) - REAL_FATTR_CONST - REAL_FATTR_ALWAYS_INLINE; /// Checks if `c` is a binary digit, that is, 0-1. /// /// @see {ascii_isdigit} static inline bool ascii_isbdigit(int c) + FUNC_ATTR_CONST FUNC_ATTR_ALWAYS_INLINE { return (c == '0' || c == '1'); } -static inline bool ascii_isodigit(int c) - REAL_FATTR_CONST - REAL_FATTR_ALWAYS_INLINE; /// Checks if `c` is an octal digit, that is, 0-7. /// /// @see {ascii_isdigit} static inline bool ascii_isodigit(int c) + FUNC_ATTR_CONST FUNC_ATTR_ALWAYS_INLINE { return (c >= '0' && c <= '7'); } -static inline bool ascii_isspace(int c) - REAL_FATTR_CONST - REAL_FATTR_ALWAYS_INLINE; /// Checks if `c` is a white-space character, that is, /// one of \f, \n, \r, \t, \v. /// /// @see {ascii_isdigit} static inline bool ascii_isspace(int c) + FUNC_ATTR_CONST FUNC_ATTR_ALWAYS_INLINE { return (c >= 9 && c <= 13) || c == ' '; } diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua index 94c5080f8d..d509837de7 100644 --- a/src/nvim/auevents.lua +++ b/src/nvim/auevents.lua @@ -36,6 +36,7 @@ return { 'CursorHold', -- cursor in same position for a while 'CursorHoldI', -- idem, in Insert mode 'CursorMoved', -- cursor was moved + 'CursorMovedC', -- cursor was moved in Cmdline mode 'CursorMovedI', -- cursor was moved in Insert mode 'DiagnosticChanged', -- diagnostics in a buffer were modified 'DiffUpdated', -- diffs have been updated @@ -117,6 +118,7 @@ return { 'TextChangedP', -- text was modified in Insert mode(popup) 'TextChangedT', -- text was modified in Terminal mode 'TextYankPost', -- after a yank or delete was done (y, d, c) + 'TextPutPre', -- before a put was done (p, P) 'TextPutPost', -- after a put was done (p, P) 'UIEnter', -- after UI attaches 'UILeave', -- after UI detaches diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index c5d81d4cd2..5a4ade913d 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -15,6 +15,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/cursor.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" @@ -710,7 +711,7 @@ char *au_event_disable(char *what) if (*what == ',' && *p_ei == NUL) { STRCPY(new_ei, what + 1); } else { - STRCAT(new_ei, what); + strcat(new_ei, what); } set_option_direct(kOptEventignore, CSTR_AS_OPTVAL(new_ei), 0, SID_NONE); xfree(new_ei); @@ -1699,19 +1700,33 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force } else { sfname = xstrdup(fname); // Don't try expanding the following events. - if (event == EVENT_CMDLINECHANGED || event == EVENT_CMDLINEENTER - || event == EVENT_CMDLINELEAVE || event == EVENT_CMDUNDEFINED - || event == EVENT_CMDWINENTER || event == EVENT_CMDWINLEAVE - || event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE - || event == EVENT_DIRCHANGED || event == EVENT_DIRCHANGEDPRE - || event == EVENT_FILETYPE || event == EVENT_FUNCUNDEFINED - || event == EVENT_MENUPOPUP || event == EVENT_MODECHANGED - || event == EVENT_OPTIONSET || event == EVENT_QUICKFIXCMDPOST - || event == EVENT_QUICKFIXCMDPRE || event == EVENT_REMOTEREPLY - || event == EVENT_SIGNAL || event == EVENT_SPELLFILEMISSING - || event == EVENT_SYNTAX || event == EVENT_TABCLOSED - || event == EVENT_USER || event == EVENT_WINCLOSED - || event == EVENT_WINRESIZED || event == EVENT_WINSCROLLED) { + if (event == EVENT_CMDLINECHANGED + || event == EVENT_CMDLINEENTER + || event == EVENT_CMDLINELEAVE + || event == EVENT_CMDUNDEFINED + || event == EVENT_CURSORMOVEDC + || event == EVENT_CMDWINENTER + || event == EVENT_CMDWINLEAVE + || event == EVENT_COLORSCHEME + || event == EVENT_COLORSCHEMEPRE + || event == EVENT_DIRCHANGED + || event == EVENT_DIRCHANGEDPRE + || event == EVENT_FILETYPE + || event == EVENT_FUNCUNDEFINED + || event == EVENT_MENUPOPUP + || event == EVENT_MODECHANGED + || event == EVENT_OPTIONSET + || event == EVENT_QUICKFIXCMDPOST + || event == EVENT_QUICKFIXCMDPRE + || event == EVENT_REMOTEREPLY + || event == EVENT_SIGNAL + || event == EVENT_SPELLFILEMISSING + || event == EVENT_SYNTAX + || event == EVENT_TABCLOSED + || event == EVENT_USER + || event == EVENT_WINCLOSED + || event == EVENT_WINRESIZED + || event == EVENT_WINSCROLLED) { fname = xstrdup(fname); autocmd_fname_full = true; // don't expand it later } else { @@ -2037,7 +2052,7 @@ static bool call_autocmd_callback(const AutoCmd *ac, const AutoPatCmd *apc) } MAXSIZE_TEMP_ARRAY(args, 1); - ADD_C(args, DICTIONARY_OBJ(data)); + ADD_C(args, DICT_OBJ(data)); Object result = nlua_call_ref(callback.data.luaref, NULL, args, kRetNilBool, NULL, NULL); return LUARET_TRUTHY(result); diff --git a/src/nvim/base64.c b/src/nvim/base64.c index a645c64fe3..99d3c5a33e 100644 --- a/src/nvim/base64.c +++ b/src/nvim/base64.c @@ -4,6 +4,7 @@ #include <string.h> #include "auto/config.h" // IWYU pragma: keep +#include "nvim/ascii_defs.h" #include "nvim/base64.h" #include "nvim/memory.h" @@ -125,7 +126,7 @@ char *base64_encode(const char *src, size_t src_len) dest[out_i] = '='; } - dest[out_len] = '\0'; + dest[out_len] = NUL; return dest; } @@ -141,6 +142,7 @@ char *base64_encode(const char *src, size_t src_len) /// @param [out] out_lenp Returns the length of the decoded string /// @return Decoded string char *base64_decode(const char *src, size_t src_len, size_t *out_lenp) + FUNC_ATTR_NONNULL_ALL { assert(src != NULL); assert(out_lenp != NULL); diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 39d0d24d47..4a87cebfa7 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -43,6 +43,7 @@ #include "nvim/diff.h" #include "nvim/digraph.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/vars.h" @@ -477,6 +478,11 @@ static bool can_unload_buffer(buf_T *buf) return can_unload; } +bool buf_locked(buf_T *buf) +{ + return buf->b_locked || buf->b_locked_split; +} + /// Close the link to a buffer. /// /// @param win If not NULL, set b_last_cursor. @@ -698,6 +704,9 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i if (buf->b_nwindows > 0) { return false; } + FOR_ALL_TAB_WINDOWS(tp, wp) { + mark_forget_file(wp, buf->b_fnum); + } if (buf->b_sfname != buf->b_ffname) { XFREE_CLEAR(buf->b_sfname); } else { @@ -864,7 +873,7 @@ static void free_buffer(buf_T *buf) } unref_var_dict(buf->b_vars); aubuflocal_remove(buf); - tv_dict_unref(buf->additional_data); + xfree(buf->additional_data); xfree(buf->b_prompt_text); callback_free(&buf->b_prompt_callback); callback_free(&buf->b_prompt_interrupt); @@ -938,6 +947,21 @@ static void free_buffer_stuff(buf_T *buf, int free_flags) void goto_buffer(exarg_T *eap, int start, int dir, int count) { const int save_sea = swap_exists_action; + bool skip_help_buf; + + switch (eap->cmdidx) { + case CMD_bnext: + case CMD_sbnext: + case CMD_bNext: + case CMD_bprevious: + case CMD_sbNext: + case CMD_sbprevious: + skip_help_buf = true; + break; + default: + skip_help_buf = false; + break; + } bufref_T old_curbuf; set_bufref(&old_curbuf, curbuf); @@ -945,8 +969,9 @@ void goto_buffer(exarg_T *eap, int start, int dir, int count) if (swap_exists_action == SEA_NONE) { swap_exists_action = SEA_DIALOG; } - do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO, - start, dir, count, eap->forceit); + (void)do_buffer_ext(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO, start, dir, count, + (eap->forceit ? DOBUF_FORCEIT : 0) | + (skip_help_buf ? DOBUF_SKIPHELP : 0)); if (swap_exists_action == SEA_QUIT && *eap->cmd == 's') { cleanup_T cs; @@ -1183,32 +1208,6 @@ static int empty_curbuf(bool close_others, int forceit, int action) return retval; } -/// Remove every jump list entry referring to a given buffer. -/// This function will also adjust the current jump list index. -void buf_remove_from_jumplist(buf_T *deleted_buf) -{ - // Remove all jump list entries that match the deleted buffer. - for (int i = curwin->w_jumplistlen - 1; i >= 0; i--) { - buf_T *buf = buflist_findnr(curwin->w_jumplist[i].fmark.fnum); - - if (buf == deleted_buf) { - // Found an entry that we want to delete. - curwin->w_jumplistlen -= 1; - - // If the current jump list index behind the entry we want to - // delete, move it back by one. - if (curwin->w_jumplistidx > i && curwin->w_jumplistidx > 0) { - curwin->w_jumplistidx -= 1; - } - - // Actually remove the entry from the jump list. - for (int d = i; d < curwin->w_jumplistlen; d++) { - curwin->w_jumplist[d] = curwin->w_jumplist[d + 1]; - } - } - } -} - /// Implementation of the commands for the buffer list. /// /// action == DOBUF_GOTO go to specified buffer @@ -1224,10 +1223,10 @@ void buf_remove_from_jumplist(buf_T *deleted_buf) /// /// @param dir FORWARD or BACKWARD /// @param count buffer number or number of buffers -/// @param forceit true for :...! +/// @param flags see @ref dobuf_flags_value /// /// @return FAIL or OK. -int do_buffer(int action, int start, int dir, int count, int forceit) +static int do_buffer_ext(int action, int start, int dir, int count, int flags) { buf_T *buf; buf_T *bp; @@ -1268,19 +1267,14 @@ int do_buffer(int action, int start, int dir, int count, int forceit) if (bp == NULL) { bp = buf; } - if (dir == FORWARD) { - buf = buf->b_next; - if (buf == NULL) { - buf = firstbuf; - } - } else { - buf = buf->b_prev; - if (buf == NULL) { - buf = lastbuf; - } - } - // don't count unlisted buffers - if (unload || buf->b_p_bl) { + buf = dir == FORWARD ? (buf->b_next != NULL ? buf->b_next : firstbuf) + : (buf->b_prev != NULL ? buf->b_prev : lastbuf); + // Don't count unlisted buffers. + // Avoid non-help buffers if the starting point was a non-help buffer and + // vice-versa. + if (unload + || (buf->b_p_bl + && ((flags & DOBUF_SKIPHELP) == 0 || buf->b_help == bp->b_help))) { count--; bp = NULL; // use this buffer as new starting point } @@ -1306,7 +1300,9 @@ int do_buffer(int action, int start, int dir, int count, int forceit) return FAIL; } - if (action == DOBUF_GOTO && buf != curbuf && !check_can_set_curbuf_forceit(forceit)) { + if (action == DOBUF_GOTO + && buf != curbuf + && !check_can_set_curbuf_forceit((flags & DOBUF_FORCEIT) ? true : false)) { // disallow navigating to another buffer when 'winfixbuf' is applied return FAIL; } @@ -1332,7 +1328,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) return FAIL; } - if (!forceit && bufIsChanged(buf)) { + if ((flags & DOBUF_FORCEIT) == 0 && bufIsChanged(buf)) { if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) { dialog_changed(buf, false); if (!bufref_valid(&bufref)) { @@ -1352,7 +1348,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) } } - if (!forceit && buf->terminal && terminal_running(buf->terminal)) { + if (!(flags & DOBUF_FORCEIT) && buf->terminal && terminal_running(buf->terminal)) { if (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) { if (!dialog_close_terminal(buf)) { return FAIL; @@ -1363,6 +1359,8 @@ int do_buffer(int action, int start, int dir, int count, int forceit) } } + int buf_fnum = buf->b_fnum; + // When closing the current buffer stop Visual mode. if (buf == curbuf && VIsual_active) { end_visual_mode(); @@ -1378,7 +1376,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) } } if (bp == NULL && buf == curbuf) { - return empty_curbuf(true, forceit, action); + return empty_curbuf(true, (flags & DOBUF_FORCEIT), action); } // If the deleted buffer is the current one, close the current window @@ -1386,7 +1384,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) // When the autocommand window is involved win_close() may need to print an error message. // Repeat this so long as we end up in a window with this buffer. while (buf == curbuf - && !(curwin->w_closing || curwin->w_buffer->b_locked > 0) + && !(win_locked(curwin) || curwin->w_buffer->b_locked > 0) && (is_aucmd_win(lastwin) || !last_window(curwin))) { if (win_close(curwin, false, false) == FAIL) { break; @@ -1395,8 +1393,10 @@ int do_buffer(int action, int start, int dir, int count, int forceit) // If the buffer to be deleted is not the current one, delete it here. if (buf != curbuf) { - // Remove the buffer to be deleted from the jump list. - buf_remove_from_jumplist(buf); + if (jop_flags & JOP_CLEAN) { + // Remove the buffer to be deleted from the jump list. + mark_jumplist_forget_file(curwin, buf_fnum); + } close_windows(buf, false); @@ -1419,28 +1419,37 @@ int do_buffer(int action, int start, int dir, int count, int forceit) if (au_new_curbuf.br_buf != NULL && bufref_valid(&au_new_curbuf)) { buf = au_new_curbuf.br_buf; } else if (curwin->w_jumplistlen > 0) { - // Remove the current buffer from the jump list. - buf_remove_from_jumplist(curbuf); + if (jop_flags & JOP_CLEAN) { + // Remove the buffer from the jump list. + mark_jumplist_forget_file(curwin, buf_fnum); + } // It's possible that we removed all jump list entries, in that case we need to try another // approach if (curwin->w_jumplistlen > 0) { - // If the index is the same as the length, the current position was not yet added to the jump - // list. So we can safely go back to the last entry and search from there. - if (curwin->w_jumplistidx == curwin->w_jumplistlen) { - curwin->w_jumplistidx = curwin->w_jumplistlen - 1; - } - int jumpidx = curwin->w_jumplistidx; + if (jop_flags & JOP_CLEAN) { + // If the index is the same as the length, the current position was not yet added to the + // jump list. So we can safely go back to the last entry and search from there. + if (jumpidx == curwin->w_jumplistlen) { + jumpidx = curwin->w_jumplistidx = curwin->w_jumplistlen - 1; + } + } else { + jumpidx--; + if (jumpidx < 0) { + jumpidx = curwin->w_jumplistlen - 1; + } + } + forward = jumpidx; - do { + while ((jop_flags & JOP_CLEAN) || jumpidx != curwin->w_jumplistidx) { buf = buflist_findnr(curwin->w_jumplist[jumpidx].fmark.fnum); if (buf != NULL) { - // Skip unlisted bufs. Also skip a quickfix + // Skip current and unlisted bufs. Also skip a quickfix // buffer, it might be deleted soon. - if (!buf->b_p_bl || bt_quickfix(buf)) { + if (buf == curbuf || !buf->b_p_bl || bt_quickfix(buf)) { buf = NULL; } else if (buf->b_ml.ml_mfp == NULL) { // skip unloaded buf, but may keep it for later @@ -1451,8 +1460,10 @@ int do_buffer(int action, int start, int dir, int count, int forceit) } } if (buf != NULL) { // found a valid buffer: stop searching - curwin->w_jumplistidx = jumpidx; - update_jumplist = false; + if (jop_flags & JOP_CLEAN) { + curwin->w_jumplistidx = jumpidx; + update_jumplist = false; + } break; } // advance to older entry in jump list @@ -1465,7 +1476,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) if (jumpidx == forward) { // List exhausted for sure break; } - } while (jumpidx != curwin->w_jumplistidx); + } } } @@ -1490,11 +1501,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) bp = buf; } } - if (forward) { - buf = buf->b_next; - } else { - buf = buf->b_prev; - } + buf = forward ? buf->b_next : buf->b_prev; } } if (buf == NULL) { // No loaded buffer, use unloaded one @@ -1509,11 +1516,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) } } if (buf == NULL) { // Still no buffer, just take one - if (curbuf->b_next != NULL) { - buf = curbuf->b_next; - } else { - buf = curbuf->b_prev; - } + buf = curbuf->b_next != NULL ? curbuf->b_next : curbuf->b_prev; if (bt_quickfix(buf)) { buf = NULL; } @@ -1523,7 +1526,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) if (buf == NULL) { // Autocommands must have wiped out all other buffers. Only option // now is to make the current buffer empty. - return empty_curbuf(false, forceit, action); + return empty_curbuf(false, (flags & DOBUF_FORCEIT), action); } // make "buf" the current buffer @@ -1544,7 +1547,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) } // Check if the current buffer may be abandoned. - if (action == DOBUF_GOTO && !can_abandon(curbuf, forceit)) { + if (action == DOBUF_GOTO && !can_abandon(curbuf, (flags & DOBUF_FORCEIT))) { if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) { bufref_T bufref; set_bufref(&bufref, buf); @@ -1574,6 +1577,11 @@ int do_buffer(int action, int start, int dir, int count, int forceit) return OK; } +int do_buffer(int action, int start, int dir, int count, int forceit) +{ + return do_buffer_ext(action, start, dir, count, forceit ? DOBUF_FORCEIT : 0); +} + /// Set current buffer to "buf". Executes autocommands and closes current /// buffer. /// @@ -1659,11 +1667,7 @@ void set_curbuf(buf_T *buf, int action, bool update_jumplist) } // If the buffer is not valid but curwin->w_buffer is NULL we must // enter some buffer. Using the last one is hopefully OK. - if (!valid) { - enter_buffer(lastbuf); - } else { - enter_buffer(buf); - } + enter_buffer(valid ? buf : lastbuf); if (old_tw != curbuf->b_p_tw) { check_colorcolumn(curwin); } @@ -2076,6 +2080,7 @@ void free_buf_options(buf_T *buf, bool free_p_ff) clear_string_option(&buf->b_p_lop); clear_string_option(&buf->b_p_cinsd); clear_string_option(&buf->b_p_cinw); + clear_string_option(&buf->b_p_cot); clear_string_option(&buf->b_p_cpt); clear_string_option(&buf->b_p_cfu); callback_free(&buf->b_cfu_cb); @@ -2114,7 +2119,6 @@ int buflist_getfile(int n, linenr_T lnum, int options, int forceit) { win_T *wp = NULL; fmark_T *fm = NULL; - colnr_T col; buf_T *buf = buflist_findnr(n); if (buf == NULL) { @@ -2135,6 +2139,7 @@ int buflist_getfile(int n, linenr_T lnum, int options, int forceit) return FAIL; } + colnr_T col; bool restore_view = false; // altfpos may be changed by getfile(), get it now if (lnum == 0) { @@ -2270,11 +2275,7 @@ int buflist_findpat(const char *pattern, const char *pattern_end, bool unlisted, int match = -1; if (pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#')) { - if (*pattern == '%') { - match = curbuf->b_fnum; - } else { - match = curwin->w_alt_fnum; - } + match = *pattern == '%' ? curbuf->b_fnum : curwin->w_alt_fnum; buf_T *found_buf = buflist_findnr(match); if (diffmode && !(found_buf && diff_mode_buf(found_buf))) { match = -1; @@ -2885,9 +2886,7 @@ void buflist_list(exarg_T *eap) changed_char, NameBuff); - if (len > IOSIZE - 20) { - len = IOSIZE - 20; - } + len = MIN(len, IOSIZE - 20); // put "line 999" in column 40 or after the file name int i = 40 - vim_strsize(IObuff); @@ -2965,7 +2964,17 @@ int setfname(buf_T *buf, char *ffname_arg, char *sfname_arg, bool message) obuf = buflist_findname_file_id(ffname, &file_id, file_id_valid); } if (obuf != NULL && obuf != buf) { - if (obuf->b_ml.ml_mfp != NULL) { // it's loaded, fail + bool in_use = false; + + // during startup a window may use a buffer that is not loaded yet + FOR_ALL_TAB_WINDOWS(tab, win) { + if (win->w_buffer == obuf) { + in_use = true; + } + } + + // it's loaded or used in a window, fail + if (obuf->b_ml.ml_mfp != NULL || in_use) { if (message) { emsg(_("E95: Buffer with this name already exists")); } @@ -3191,8 +3200,6 @@ static bool buf_same_file_id(buf_T *buf, FileID *file_id) /// @param fullname when non-zero print full path void fileinfo(int fullname, int shorthelp, bool dont_truncate) { - char *name; - int n; char *p; char *buffer = xmalloc(IOSIZE); @@ -3208,11 +3215,9 @@ void fileinfo(int fullname, int shorthelp, bool dont_truncate) if (buf_spname(curbuf) != NULL) { xstrlcpy(p, buf_spname(curbuf), (size_t)(IOSIZE - (p - buffer))); } else { - if (!fullname && curbuf->b_fname != NULL) { - name = curbuf->b_fname; - } else { - name = curbuf->b_ffname; - } + char *name = (!fullname && curbuf->b_fname != NULL) + ? curbuf->b_fname + : curbuf->b_ffname; home_replace(shorthelp ? curbuf : NULL, name, p, (size_t)(IOSIZE - (p - buffer)), true); } @@ -3233,6 +3238,7 @@ void fileinfo(int fullname, int shorthelp, bool dont_truncate) || (curbuf->b_flags & BF_WRITE_MASK) || curbuf->b_p_ro) ? " " : ""); + int n; // With 32 bit longs and more than 21,474,836 lines multiplying by 100 // causes an overflow, thus for large numbers divide instead. if (curwin->w_cursor.lnum > 1000000) { @@ -3321,10 +3327,7 @@ void maketitle(void) if (p_title) { if (p_titlelen > 0) { - maxlen = (int)(p_titlelen * Columns / 100); - if (maxlen < 10) { - maxlen = 10; - } + maxlen = MAX((int)(p_titlelen * Columns / 100), 10); } if (*p_titlestring != NUL) { @@ -3340,7 +3343,7 @@ void maketitle(void) #define SPACE_FOR_FNAME (sizeof(buf) - 100) #define SPACE_FOR_DIR (sizeof(buf) - 20) -#define SPACE_FOR_ARGNR (sizeof(buf) - 10) // At least room for " - NVIM". +#define SPACE_FOR_ARGNR (sizeof(buf) - 10) // At least room for " - Nvim". char *buf_p = buf; if (curbuf->b_fname == NULL) { const size_t size = xstrlcpy(buf_p, _("[No Name]"), @@ -3414,7 +3417,7 @@ void maketitle(void) append_arg_number(curwin, buf_p, (int)(SPACE_FOR_ARGNR - (size_t)(buf_p - buf))); - xstrlcat(buf_p, " - NVIM", (sizeof(buf) - (size_t)(buf_p - buf))); + xstrlcat(buf_p, " - Nvim", (sizeof(buf) - (size_t)(buf_p - buf))); if (maxlen > 0) { // Make it shorter by removing a bit in the middle. @@ -3440,12 +3443,9 @@ void maketitle(void) icon_str = p_iconstring; } } else { - char *buf_p; - if (buf_spname(curbuf) != NULL) { - buf_p = buf_spname(curbuf); - } else { // use file name only in icon - buf_p = path_tail(curbuf->b_ffname); - } + char *buf_p = buf_spname(curbuf) != NULL + ? buf_spname(curbuf) + : path_tail(curbuf->b_ffname); // use file name only in icon *icon_str = NUL; // Truncate name at 100 bytes. int len = (int)strlen(buf_p); @@ -3610,23 +3610,18 @@ bool bt_prompt(buf_T *buf) /// Open a window for a number of buffers. void ex_buffer_all(exarg_T *eap) { - win_T *wp, *wpnext; + win_T *wpnext; int split_ret = OK; int open_wins = 0; - linenr_T count; // Maximum number of windows to open. - int all; // When true also load inactive buffers. int had_tab = cmdmod.cmod_tab; - if (eap->addr_count == 0) { // make as many windows as possible - count = 9999; - } else { - count = eap->line2; // make as many windows as specified - } - if (eap->cmdidx == CMD_unhide || eap->cmdidx == CMD_sunhide) { - all = false; - } else { - all = true; - } + // Maximum number of windows to open. + linenr_T count = eap->addr_count == 0 + ? 9999 // make as many windows as possible + : eap->line2; // make as many windows as specified + + // When true also load inactive buffers. + int all = eap->cmdidx != CMD_unhide && eap->cmdidx != CMD_sunhide; // Stop Visual mode, the cursor and "VIsual" may very well be invalid after // switching to another buffer. @@ -3642,7 +3637,7 @@ void ex_buffer_all(exarg_T *eap) while (true) { tabpage_T *tpnext = curtab->tp_next; // Try to close floating windows first - for (wp = lastwin->w_floating ? lastwin : firstwin; wp != NULL; wp = wpnext) { + for (win_T *wp = lastwin->w_floating ? lastwin : firstwin; wp != NULL; wp = wpnext) { wpnext = wp->w_floating ? wp->w_prev->w_floating ? wp->w_prev : firstwin : (wp->w_next == NULL || wp->w_next->w_floating) ? NULL : wp->w_next; @@ -3654,7 +3649,7 @@ void ex_buffer_all(exarg_T *eap) : wp->w_width != Columns) || (had_tab > 0 && wp != firstwin)) && !ONE_WINDOW - && !(wp->w_closing || wp->w_buffer->b_locked > 0) + && !(win_locked(curwin) || wp->w_buffer->b_locked > 0) && !is_aucmd_win(wp)) { if (win_close(wp, false, false) == FAIL) { break; @@ -3691,13 +3686,12 @@ void ex_buffer_all(exarg_T *eap) continue; } + win_T *wp; if (had_tab != 0) { // With the ":tab" modifier don't move the window. - if (buf->b_nwindows > 0) { - wp = lastwin; // buffer has a window, skip it - } else { - wp = NULL; - } + wp = buf->b_nwindows > 0 + ? lastwin // buffer has a window, skip it + : NULL; } else { // Check if this buffer already has a window for (wp = firstwin; wp != NULL; wp = wp->w_next) { @@ -3726,7 +3720,7 @@ void ex_buffer_all(exarg_T *eap) // Open the buffer in this window. swap_exists_action = SEA_DIALOG; - set_curbuf(buf, DOBUF_GOTO, false); + set_curbuf(buf, DOBUF_GOTO, !(jop_flags & JOP_CLEAN)); if (!bufref_valid(&bufref)) { // Autocommands deleted the buffer. swap_exists_action = SEA_NONE; @@ -3773,7 +3767,7 @@ void ex_buffer_all(exarg_T *eap) autocmd_no_leave--; // Close superfluous windows. - for (wp = lastwin; open_wins > count;) { + for (win_T *wp = lastwin; open_wins > count;) { bool r = (buf_hide(wp->w_buffer) || !bufIsChanged(wp->w_buffer) || autowrite(wp->w_buffer, false) == OK) && !is_aucmd_win(wp); if (!win_valid(wp)) { @@ -3841,7 +3835,6 @@ static int chk_modeline(linenr_T lnum, int flags) { char *s; char *e; - char *linecopy; // local copy of any modeline found intmax_t vers; int retval = OK; @@ -3886,6 +3879,7 @@ static int chk_modeline(linenr_T lnum, int flags) s++; } while (s[-1] != ':'); + char *linecopy; // local copy of any modeline found s = linecopy = xstrdup(s); // copy the line, it will change // prepare for emsg() @@ -4207,7 +4201,7 @@ int buf_open_scratch(handle_T bufnr, char *bufname) bool buf_is_empty(buf_T *buf) { - return buf->b_ml.ml_line_count == 1 && *ml_get_buf(buf, 1) == '\0'; + return buf->b_ml.ml_line_count == 1 && *ml_get_buf(buf, 1) == NUL; } /// Increment b:changedtick value diff --git a/src/nvim/buffer.h b/src/nvim/buffer.h index 4c5023d39a..2936c297fe 100644 --- a/src/nvim/buffer.h +++ b/src/nvim/buffer.h @@ -5,7 +5,6 @@ #include "nvim/buffer_defs.h" // IWYU pragma: keep #include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds_defs.h" // IWYU pragma: keep -#include "nvim/func_attr.h" #include "nvim/gettext_defs.h" // IWYU pragma: keep #include "nvim/macros_defs.h" #include "nvim/marktree_defs.h" @@ -39,7 +38,7 @@ enum bln_values { BLN_NOCURWIN = 128, ///< buffer is not associated with curwin }; -/// Values for action argument for do_buffer() +/// Values for action argument for do_buffer_ext() and close_buffer() enum dobuf_action_values { DOBUF_GOTO = 0, ///< go to specified buffer DOBUF_SPLIT = 1, ///< split window and go to specified buffer @@ -48,7 +47,7 @@ enum dobuf_action_values { DOBUF_WIPE = 4, ///< delete specified buffer(s) really }; -/// Values for start argument for do_buffer() +/// Values for start argument for do_buffer_ext() enum dobuf_start_values { DOBUF_CURRENT = 0, ///< "count" buffer from current buffer DOBUF_FIRST = 1, ///< "count" buffer from first buffer @@ -56,6 +55,13 @@ enum dobuf_start_values { DOBUF_MOD = 3, ///< "count" mod. buffer from current buffer }; +/// Values for flags argument of do_buffer_ext() +enum dobuf_flags_value { + DOBUF_FORCEIT = 1, ///< :cmd! + DOBUF_SKIPHELP = 4, ///< skip or keep help buffers depending on b_help of the + ///< starting buffer +}; + /// flags for buf_freeall() enum bfa_values { BFA_DEL = 1, ///< buffer is going to be deleted @@ -69,18 +75,17 @@ EXTERN char *msg_qflist INIT( = N_("[Quickfix List]")); #ifdef INCLUDE_GENERATED_DECLARATIONS # include "buffer.h.generated.h" +# include "buffer.h.inline.generated.h" #endif -static inline varnumber_T buf_get_changedtick(const buf_T *buf) - REAL_FATTR_NONNULL_ALL REAL_FATTR_ALWAYS_INLINE REAL_FATTR_PURE - REAL_FATTR_WARN_UNUSED_RESULT; - /// Get b:changedtick value /// /// Faster then querying b:. /// /// @param[in] buf Buffer to get b:changedtick from. static inline varnumber_T buf_get_changedtick(const buf_T *const buf) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_PURE + FUNC_ATTR_WARN_UNUSED_RESULT { return buf->changedtick_di.di_tv.vval.v_number; } diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 8f5f2c44f7..a68e841f3e 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -393,7 +393,7 @@ struct file_buffer { /// Change-identifier incremented for each change, including undo. /// - /// This is a dictionary item used to store b:changedtick. + /// This is a dict item used to store b:changedtick. ChangedtickDictItem changedtick_di; varnumber_T b_last_changedtick; // b:changedtick when TextChanged was @@ -533,6 +533,8 @@ struct file_buffer { char *b_p_cinsd; ///< 'cinscopedecls' char *b_p_com; ///< 'comments' char *b_p_cms; ///< 'commentstring' + char *b_p_cot; ///< 'completeopt' local value + unsigned b_cot_flags; ///< flags for 'completeopt' char *b_p_cpt; ///< 'complete' #ifdef BACKSLASH_IN_FILENAME char *b_p_csl; ///< 'completeslash' @@ -671,8 +673,8 @@ struct file_buffer { int b_bad_char; // "++bad=" argument when edit started or 0 int b_start_bomb; // 'bomb' when it was read - ScopeDictDictItem b_bufvar; ///< Variable for "b:" Dictionary. - dict_T *b_vars; ///< b: scope dictionary. + ScopeDictDictItem b_bufvar; ///< Variable for "b:" Dict. + dict_T *b_vars; ///< b: scope Dict. // When a buffer is created, it starts without a swap file. b_may_swap is // then set to indicate that a swap file may be opened later. It is reset @@ -711,7 +713,7 @@ struct file_buffer { Terminal *terminal; // Terminal instance associated with the buffer - dict_T *additional_data; // Additional data from shada file if any. + AdditionalData *additional_data; // Additional data from shada file if any. int b_mapped_ctrl_c; // modes where CTRL-C is mapped @@ -738,8 +740,6 @@ struct file_buffer { // The number for times the current line has been flushed in the memline. int flush_count; - - int b_diff_failed; // internal diff failed for this buffer }; // Stuff for diff mode. @@ -793,7 +793,7 @@ struct tabpage_S { int tp_diff_invalid; ///< list of diffs is outdated int tp_diff_update; ///< update diffs before redrawing frame_T *(tp_snapshot[SNAP_COUNT]); ///< window layout snapshots - ScopeDictDictItem tp_winvar; ///< Variable for "t:" Dictionary. + ScopeDictDictItem tp_winvar; ///< Variable for "t:" Dict. dict_T *tp_vars; ///< Internal variables, local to tab page. char *tp_localdir; ///< Absolute path of local cwd or NULL. char *tp_prevdir; ///< Previous directory. @@ -1046,8 +1046,7 @@ 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. + bool w_locked; ///< don't let autocommands close the window frame_T *w_frame; ///< frame containing this window @@ -1265,8 +1264,8 @@ struct window_S { int w_scbind_pos; - ScopeDictDictItem w_winvar; ///< Variable for "w:" dictionary. - dict_T *w_vars; ///< Dictionary with w: variables. + ScopeDictDictItem w_winvar; ///< Variable for "w:" dict. + dict_T *w_vars; ///< Dict with w: variables. // The w_prev_pcmark field is used to check whether we really did jump to // a new line after setting the w_pcmark. If not, then we revert to diff --git a/src/nvim/bufwrite.c b/src/nvim/bufwrite.c index 27de03954a..fa0a55e7b6 100644 --- a/src/nvim/bufwrite.c +++ b/src/nvim/bufwrite.c @@ -18,6 +18,7 @@ #include "nvim/bufwrite.h" #include "nvim/change.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds.h" @@ -260,11 +261,8 @@ static int buf_write_convert(struct bw_info *ip, char **bufp, int *lenp) ip->bw_restlen += *lenp; break; } - if (n > 1) { - c = (unsigned)utf_ptr2char((char *)ip->bw_rest); - } else { - c = ip->bw_rest[0]; - } + c = (n > 1) ? (unsigned)utf_ptr2char((char *)ip->bw_rest) + : ip->bw_rest[0]; if (n >= ip->bw_restlen) { n -= ip->bw_restlen; ip->bw_restlen = 0; @@ -288,11 +286,8 @@ static int buf_write_convert(struct bw_info *ip, char **bufp, int *lenp) (size_t)ip->bw_restlen); break; } - if (n > 1) { - c = (unsigned)utf_ptr2char(*bufp + wlen); - } else { - c = (uint8_t)(*bufp)[wlen]; - } + c = n > 1 ? (unsigned)utf_ptr2char(*bufp + wlen) + : (uint8_t)(*bufp)[wlen]; } if (ucs2bytes(c, &p, flags) && !ip->bw_conv_error) { @@ -820,10 +815,6 @@ static int buf_write_make_backup(char *fname, bool append, FileInfo *file_info_o // Isolate one directory name, using an entry in 'bdir'. size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ","); char *p = IObuff + dir_len; - bool trailing_pathseps = after_pathsep(IObuff, p) && p[-1] == p[-2]; - if (trailing_pathseps) { - IObuff[dir_len - 2] = NUL; - } if (*dirp == NUL && !os_isdir(IObuff)) { int ret; char *failed_dir; @@ -833,9 +824,9 @@ static int buf_write_make_backup(char *fname, bool append, FileInfo *file_info_o xfree(failed_dir); } } - if (trailing_pathseps) { + if (after_pathsep(IObuff, p) && p[-1] == p[-2]) { // Ends with '//', Use Full path - if ((p = make_percent_swname(IObuff, fname)) + if ((p = make_percent_swname(IObuff, p, fname)) != NULL) { *backupp = modname(p, backup_ext, no_prepend_dot); xfree(p); @@ -879,9 +870,7 @@ static int buf_write_make_backup(char *fname, bool append, FileInfo *file_info_o // Change one character, just before the extension. // char *wp = *backupp + strlen(*backupp) - 1 - strlen(backup_ext); - if (wp < *backupp) { // empty file name ??? - wp = *backupp; - } + wp = MAX(wp, *backupp); // empty file name ??? *wp = 'z'; while (*wp > 'a' && os_fileinfo(*backupp, &file_info_new)) { (*wp)--; @@ -962,10 +951,6 @@ nobackup: // Isolate one directory name and make the backup file name. size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ","); char *p = IObuff + dir_len; - bool trailing_pathseps = after_pathsep(IObuff, p) && p[-1] == p[-2]; - if (trailing_pathseps) { - IObuff[dir_len - 2] = NUL; - } if (*dirp == NUL && !os_isdir(IObuff)) { int ret; char *failed_dir; @@ -975,9 +960,9 @@ nobackup: xfree(failed_dir); } } - if (trailing_pathseps) { + if (after_pathsep(IObuff, p) && p[-1] == p[-2]) { // path ends with '//', use full path - if ((p = make_percent_swname(IObuff, fname)) + if ((p = make_percent_swname(IObuff, p, fname)) != NULL) { *backupp = modname(p, backup_ext, no_prepend_dot); xfree(p); @@ -1000,9 +985,7 @@ nobackup: // Change one character, just before the extension. if (!p_bk && os_path_exists(*backupp)) { p = *backupp + strlen(*backupp) - 1 - strlen(backup_ext); - if (p < *backupp) { // empty file name ??? - p = *backupp; - } + p = MAX(p, *backupp); // empty file name ??? *p = 'z'; while (*p > 'a' && os_path_exists(*backupp)) { (*p)--; @@ -1065,7 +1048,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en bool whole = (start == 1 && end == buf->b_ml.ml_line_count); bool write_undo_file = false; context_sha256_T sha_ctx; - unsigned bkc = get_bkc_value(buf); + unsigned bkc = get_bkc_flags(buf); if (fname == NULL || *fname == NUL) { // safety check return FAIL; @@ -1262,9 +1245,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en status_redraw_all(); // redraw status lines later } - if (end > buf->b_ml.ml_line_count) { - end = buf->b_ml.ml_line_count; - } + end = MIN(end, buf->b_ml.ml_line_count); if (buf->b_ml.ml_flags & ML_EMPTY) { start = end + 1; } diff --git a/src/nvim/change.c b/src/nvim/change.c index 05772d39e9..51a13b80e7 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -392,6 +392,10 @@ static void changed_common(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnum } } } + + if (wp == curwin && xtra != 0 && search_hl_has_cursor_lnum >= lnum) { + search_hl_has_cursor_lnum += xtra; + } } // Call update_screen() later, which checks out what needs to be redrawn, @@ -519,19 +523,13 @@ void changed_lines_redraw_buf(buf_T *buf, linenr_T lnum, linenr_T lnume, linenr_ { if (buf->b_mod_set) { // find the maximum area that must be redisplayed - if (lnum < buf->b_mod_top) { - buf->b_mod_top = lnum; - } + buf->b_mod_top = MIN(buf->b_mod_top, lnum); if (lnum < buf->b_mod_bot) { // adjust old bot position for xtra lines buf->b_mod_bot += xtra; - if (buf->b_mod_bot < lnum) { - buf->b_mod_bot = lnum; - } - } - if (lnume + xtra > buf->b_mod_bot) { - buf->b_mod_bot = lnume + xtra; + buf->b_mod_bot = MAX(buf->b_mod_bot, lnum); } + buf->b_mod_bot = MAX(buf->b_mod_bot, lnume + xtra); buf->b_mod_xlines += xtra; } else { // set the area that must be redisplayed @@ -758,10 +756,8 @@ void ins_char_bytes(char *buf, size_t charlen) // put back when BS is used. The bytes of a multi-byte character are // done the other way around, so that the first byte is popped off // first (it tells the byte length of the character). - replace_push(NUL); - for (size_t i = 0; i < oldlen; i++) { - i += (size_t)replace_push_mb(oldp + col + i) - 1; - } + replace_push_nul(); + replace_push(oldp + col, oldlen); } char *newp = xmalloc(linelen + newlen - oldlen); @@ -898,14 +894,15 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine) // delete the last combining character. if (p_deco && use_delcombine && utfc_ptr2len(oldp + col) >= count) { char *p0 = oldp + col; - if (utf_composinglike(p0, p0 + utf_ptr2len(p0))) { + GraphemeState state = GRAPHEME_STATE_INIT; + if (utf_composinglike(p0, p0 + utf_ptr2len(p0), &state)) { // Find the last composing char, there can be several. int n = col; do { col = n; count = utf_ptr2len(oldp + n); n += count; - } while (utf_composinglike(oldp + col, oldp + n)); + } while (utf_composinglike(oldp + col, oldp + n, &state)); fixpos = false; } } @@ -1138,12 +1135,10 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) // on the line onto the replace stack. We'll push any other characters // that might be replaced at the start of the next line (due to // autoindent etc) a bit later. - replace_push(NUL); // Call twice because BS over NL expects it - replace_push(NUL); + replace_push_nul(); // Call twice because BS over NL expects it + replace_push_nul(); p = saved_line + curwin->w_cursor.col; - while (*p != NUL) { - p += replace_push_mb(p); - } + replace_push(p, strlen(p)); saved_line[curwin->w_cursor.col] = NUL; } @@ -1692,13 +1687,13 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) // stack, preceded by a NUL, so they can be put back when a BS is // entered. if (REPLACE_NORMAL(State)) { - replace_push(NUL); // end of extra blanks + replace_push_nul(); // end of extra blanks } if (curbuf->b_p_ai || (flags & OPENLINE_DELSPACES)) { while ((*p_extra == ' ' || *p_extra == '\t') - && !utf_iscomposing(utf_ptr2char(p_extra + 1))) { + && !utf_iscomposing_first(utf_ptr2char(p_extra + 1))) { if (REPLACE_NORMAL(State)) { - replace_push(*p_extra); + replace_push(p_extra, 1); // always ascii, len = 1 } p_extra++; less_cols_off++; @@ -1723,12 +1718,12 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) // Below, set_indent(newindent, SIN_INSERT) will insert the // whitespace needed before the comment char. for (int i = 0; i < padding; i++) { - STRCAT(leader, " "); + strcat(leader, " "); less_cols--; newcol++; } } - STRCAT(leader, p_extra); + strcat(leader, p_extra); p_extra = leader; did_ai = true; // So truncating blanks works with comments less_cols -= lead_len; @@ -1795,7 +1790,7 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) // must be a NUL on the replace stack, for when it is deleted with BS if (REPLACE_NORMAL(State)) { for (colnr_T n = 0; n < curwin->w_cursor.col; n++) { - replace_push(NUL); + replace_push_nul(); } } newcol += curwin->w_cursor.col; @@ -1809,7 +1804,7 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) // must be a NUL on the replace stack, for when it is deleted with BS. if (REPLACE_NORMAL(State)) { while (lead_len-- > 0) { - replace_push(NUL); + replace_push_nul(); } } @@ -2258,9 +2253,7 @@ int get_last_leader_offset(char *line, char **flags) for (int off = (len2 > i ? i : len2); off > 0 && off + len1 > len2;) { off--; if (!strncmp(string + off, com_leader, (size_t)(len2 - off))) { - if (i - off < lower_check_bound) { - lower_check_bound = i - off; - } + lower_check_bound = MIN(lower_check_bound, i - off); } } } diff --git a/src/nvim/channel.c b/src/nvim/channel.c index 41635747f8..021fdd4b79 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -13,12 +13,13 @@ #include "nvim/autocmd_defs.h" #include "nvim/buffer_defs.h" #include "nvim/channel.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/typval.h" #include "nvim/event/loop.h" #include "nvim/event/multiqueue.h" -#include "nvim/event/process.h" +#include "nvim/event/proc.h" #include "nvim/event/rstream.h" #include "nvim/event/socket.h" #include "nvim/event/stream.h" @@ -38,8 +39,6 @@ #include "nvim/os/os_defs.h" #include "nvim/os/shell.h" #include "nvim/path.h" -#include "nvim/rbuffer.h" -#include "nvim/rbuffer_defs.h" #include "nvim/terminal.h" #include "nvim/types_defs.h" @@ -89,7 +88,7 @@ void channel_free_all_mem(void) bool channel_close(uint64_t id, ChannelPart part, const char **error) { Channel *chan; - Process *proc; + Proc *proc; const char *dummy; if (!error) { @@ -126,32 +125,32 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error) *error = e_invstream; return false; } - stream_may_close(&chan->stream.socket); + rstream_may_close(&chan->stream.socket); break; case kChannelStreamProc: proc = &chan->stream.proc; if (part == kChannelPartStdin || close_main) { - stream_may_close(&proc->in); + wstream_may_close(&proc->in); } if (part == kChannelPartStdout || close_main) { - stream_may_close(&proc->out); + rstream_may_close(&proc->out); } if (part == kChannelPartStderr || part == kChannelPartAll) { - stream_may_close(&proc->err); + rstream_may_close(&proc->err); } - if (proc->type == kProcessTypePty && part == kChannelPartAll) { - pty_process_close_master(&chan->stream.pty); + if (proc->type == kProcTypePty && part == kChannelPartAll) { + pty_proc_close_master(&chan->stream.pty); } break; case kChannelStreamStdio: if (part == kChannelPartStdin || close_main) { - stream_may_close(&chan->stream.stdio.in); + rstream_may_close(&chan->stream.stdio.in); } if (part == kChannelPartStdout || close_main) { - stream_may_close(&chan->stream.stdio.out); + wstream_may_close(&chan->stream.stdio.out); } if (part == kChannelPartStderr) { *error = e_invstream; @@ -240,11 +239,11 @@ void channel_create_event(Channel *chan, const char *ext_source) assert(chan->id <= VARNUMBER_MAX); Arena arena = ARENA_EMPTY; - Dictionary info = channel_info(chan->id, &arena); + Dict info = channel_info(chan->id, &arena); typval_T tv = TV_INITIAL_VALUE; // TODO(bfredl): do the conversion in one step. Also would be nice // to pretty print top level dict in defined order - object_to_vim(DICTIONARY_OBJ(info), &tv, NULL); + object_to_vim(DICT_OBJ(info), &tv, NULL); assert(tv.v_type == VAR_DICT); char *str = encode_tv2json(&tv, NULL); ILOG("new channel %" PRIu64 " (%s) : %s", chan->id, source, str); @@ -290,7 +289,7 @@ static void channel_destroy(Channel *chan) } if (chan->streamtype == kChannelStreamProc) { - process_free(&chan->stream.proc); + proc_free(&chan->stream.proc); } callback_reader_free(&chan->on_data); @@ -377,7 +376,7 @@ Channel *channel_job_start(char **argv, const char *exepath, CallbackReader on_s *status_out = 0; return NULL; } - chan->stream.pty = pty_process_init(&main_loop, chan); + chan->stream.pty = pty_proc_init(&main_loop, chan); if (pty_width > 0) { chan->stream.pty.width = pty_width; } @@ -385,22 +384,22 @@ Channel *channel_job_start(char **argv, const char *exepath, CallbackReader on_s chan->stream.pty.height = pty_height; } } else { - chan->stream.uv = libuv_process_init(&main_loop, chan); + chan->stream.uv = libuv_proc_init(&main_loop, chan); } - Process *proc = &chan->stream.proc; + Proc *proc = &chan->stream.proc; proc->argv = argv; proc->exepath = exepath; - proc->cb = channel_process_exit_cb; + proc->cb = channel_proc_exit_cb; proc->events = chan->events; proc->detach = detach; proc->cwd = cwd; proc->env = env; proc->overlapped = overlapped; - char *cmd = xstrdup(process_get_exepath(proc)); + char *cmd = xstrdup(proc_get_exepath(proc)); bool has_out, has_err; - if (proc->type == kProcessTypePty) { + if (proc->type == kProcTypePty) { has_out = true; has_err = false; } else { @@ -411,7 +410,7 @@ Channel *channel_job_start(char **argv, const char *exepath, CallbackReader on_s bool has_in = stdin_mode == kChannelStdinPipe; - int status = process_spawn(proc, has_in, has_out, has_err); + int status = proc_spawn(proc, has_in, has_out, has_err); if (status) { semsg(_(e_jobspawn), os_strerror(status), cmd); xfree(cmd); @@ -431,7 +430,7 @@ Channel *channel_job_start(char **argv, const char *exepath, CallbackReader on_s wstream_init(&proc->in, 0); } if (has_out) { - rstream_init(&proc->out, 0); + rstream_init(&proc->out); } if (rpc) { @@ -446,7 +445,7 @@ Channel *channel_job_start(char **argv, const char *exepath, CallbackReader on_s if (has_err) { callback_reader_start(&chan->on_stderr, "stderr"); - rstream_init(&proc->err, 0); + rstream_init(&proc->err); rstream_start(&proc->err, on_job_stderr, chan); } @@ -480,10 +479,10 @@ uint64_t channel_connect(bool tcp, const char *address, bool rpc, CallbackReader return 0; } - channel->stream.socket.internal_close_cb = close_cb; - channel->stream.socket.internal_data = channel; - wstream_init(&channel->stream.socket, 0); - rstream_init(&channel->stream.socket, 0); + channel->stream.socket.s.internal_close_cb = close_cb; + channel->stream.socket.s.internal_data = channel; + wstream_init(&channel->stream.socket.s, 0); + rstream_init(&channel->stream.socket); if (rpc) { rpc_start(channel); @@ -505,10 +504,10 @@ void channel_from_connection(SocketWatcher *watcher) { Channel *channel = channel_alloc(kChannelStreamSocket); socket_watcher_accept(watcher, &channel->stream.socket); - channel->stream.socket.internal_close_cb = close_cb; - channel->stream.socket.internal_data = channel; - wstream_init(&channel->stream.socket, 0); - rstream_init(&channel->stream.socket, 0); + channel->stream.socket.s.internal_close_cb = close_cb; + channel->stream.socket.s.internal_data = channel; + wstream_init(&channel->stream.socket.s, 0); + rstream_init(&channel->stream.socket); rpc_start(channel); channel_create_event(channel, watcher->addr); } @@ -553,7 +552,7 @@ uint64_t channel_from_stdio(bool rpc, CallbackReader on_output, const char **err dup2(STDERR_FILENO, STDIN_FILENO); } #endif - rstream_init_fd(&main_loop, &channel->stream.stdio.in, stdin_dup_fd, 0); + rstream_init_fd(&main_loop, &channel->stream.stdio.in, stdin_dup_fd); wstream_init_fd(&main_loop, &channel->stream.stdio.out, stdout_dup_fd, 0); if (rpc) { @@ -647,51 +646,38 @@ static inline list_T *buffer_to_tv_list(const char *const buf, const size_t len) return l; } -void on_channel_data(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof) +size_t on_channel_data(RStream *stream, const char *buf, size_t count, void *data, bool eof) { Channel *chan = data; - on_channel_output(stream, chan, buf, eof, &chan->on_data); + return on_channel_output(stream, chan, buf, count, eof, &chan->on_data); } -void on_job_stderr(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof) +size_t on_job_stderr(RStream *stream, const char *buf, size_t count, void *data, bool eof) { Channel *chan = data; - on_channel_output(stream, chan, buf, eof, &chan->on_stderr); + return on_channel_output(stream, chan, buf, count, eof, &chan->on_stderr); } -static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf, bool eof, - CallbackReader *reader) +static size_t on_channel_output(RStream *stream, Channel *chan, const char *buf, size_t count, + bool eof, CallbackReader *reader) { - size_t count; - char *output = rbuffer_read_ptr(buf, &count); - if (chan->term) { - if (!eof) { - char *p = output; - char *end = output + count; + if (count) { + const char *p = buf; + const char *end = buf + count; while (p < end) { // Don't pass incomplete UTF-8 sequences to libvterm. #16245 // Composing chars can be passed separately, so utf_ptr2len_len() is enough. int clen = utf_ptr2len_len(p, (int)(end - p)); if (clen > end - p) { - count = (size_t)(p - output); + count = (size_t)(p - buf); break; } p += clen; } } - terminal_receive(chan->term, output, count); - } - - if (count) { - rbuffer_consumed(buf, count); - } - // Move remaining data to start of buffer, so the buffer can never wrap around. - rbuffer_reset(buf); - - if (callback_reader_set(*reader)) { - ga_concat_len(&reader->buffer, output, count); + terminal_receive(chan->term, buf, count); } if (eof) { @@ -699,8 +685,11 @@ static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf, bool } if (callback_reader_set(*reader)) { + ga_concat_len(&reader->buffer, buf, count); schedule_channel_event(chan); } + + return count; } /// schedule the necessary callbacks to be invoked as a deferred event @@ -771,7 +760,7 @@ void channel_reader_callbacks(Channel *chan, CallbackReader *reader) } } -static void channel_process_exit_cb(Process *proc, int status, void *data) +static void channel_proc_exit_cb(Proc *proc, int status, void *data) { Channel *chan = data; if (chan->term) { @@ -858,13 +847,13 @@ static void term_write(const char *buf, size_t size, void *data) static void term_resize(uint16_t width, uint16_t height, void *data) { Channel *chan = data; - pty_process_resize(&chan->stream.pty, width, height); + pty_proc_resize(&chan->stream.pty, width, height); } static inline void term_delayed_free(void **argv) { Channel *chan = argv[0]; - if (chan->stream.proc.in.pending_reqs || chan->stream.proc.out.pending_reqs) { + if (chan->stream.proc.in.pending_reqs || chan->stream.proc.out.s.pending_reqs) { multiqueue_put(chan->events, term_delayed_free, chan); return; } @@ -878,7 +867,7 @@ static inline void term_delayed_free(void **argv) static void term_close(void *data) { Channel *chan = data; - process_stop(&chan->stream.proc); + proc_stop(&chan->stream.proc); multiqueue_put(chan->events, term_delayed_free, data); } @@ -899,9 +888,9 @@ static void set_info_event(void **argv) save_v_event_T save_v_event; dict_T *dict = get_v_event(&save_v_event); Arena arena = ARENA_EMPTY; - Dictionary info = channel_info(chan->id, &arena); + Dict info = channel_info(chan->id, &arena); typval_T retval; - object_to_vim(DICTIONARY_OBJ(info), &retval, NULL); + object_to_vim(DICT_OBJ(info), &retval, NULL); assert(retval.v_type == VAR_DICT); tv_dict_add_dict(dict, S_LEN("info"), retval.vval.v_dict); tv_dict_set_keys_readonly(dict); @@ -918,25 +907,25 @@ bool channel_job_running(uint64_t id) Channel *chan = find_channel(id); return (chan && chan->streamtype == kChannelStreamProc - && !process_is_stopped(&chan->stream.proc)); + && !proc_is_stopped(&chan->stream.proc)); } -Dictionary channel_info(uint64_t id, Arena *arena) +Dict channel_info(uint64_t id, Arena *arena) { Channel *chan = find_channel(id); if (!chan) { - return (Dictionary)ARRAY_DICT_INIT; + return (Dict)ARRAY_DICT_INIT; } - Dictionary info = arena_dict(arena, 8); + Dict info = arena_dict(arena, 8); PUT_C(info, "id", INTEGER_OBJ((Integer)chan->id)); const char *stream_desc, *mode_desc; switch (chan->streamtype) { case kChannelStreamProc: { stream_desc = "job"; - if (chan->stream.proc.type == kProcessTypePty) { - const char *name = pty_process_tty_name(&chan->stream.pty); + if (chan->stream.proc.type == kProcTypePty) { + const char *name = pty_proc_tty_name(&chan->stream.pty); PUT_C(info, "pty", CSTR_TO_ARENA_OBJ(arena, name)); } @@ -974,7 +963,7 @@ Dictionary channel_info(uint64_t id, Arena *arena) if (chan->is_rpc) { mode_desc = "rpc"; - PUT_C(info, "client", DICTIONARY_OBJ(chan->rpc.info)); + PUT_C(info, "client", DICT_OBJ(chan->rpc.info)); } else if (chan->term) { mode_desc = "terminal"; PUT_C(info, "buffer", BUFFER_OBJ(terminal_buf(chan->term))); @@ -1007,7 +996,7 @@ Array channel_all_info(Arena *arena) Array ret = arena_array(arena, ids.size); for (size_t i = 0; i < ids.size; i++) { - ADD_C(ret, DICTIONARY_OBJ(channel_info((uint64_t)ids.items[i], arena))); + ADD_C(ret, DICT_OBJ(channel_info((uint64_t)ids.items[i], arena))); } return ret; } diff --git a/src/nvim/channel.h b/src/nvim/channel.h index 35d369e513..2327216826 100644 --- a/src/nvim/channel.h +++ b/src/nvim/channel.h @@ -7,19 +7,13 @@ #include "nvim/channel_defs.h" // IWYU pragma: keep #include "nvim/eval/typval_defs.h" #include "nvim/event/defs.h" -#include "nvim/event/libuv_process.h" -#include "nvim/func_attr.h" +#include "nvim/event/libuv_proc.h" #include "nvim/macros_defs.h" #include "nvim/map_defs.h" #include "nvim/msgpack_rpc/channel_defs.h" -#include "nvim/os/pty_process.h" +#include "nvim/os/pty_proc.h" #include "nvim/types_defs.h" -static inline bool callback_reader_set(CallbackReader reader) -{ - return reader.cb.type != kCallbackNone || reader.self; -} - struct Channel { uint64_t id; size_t refcount; @@ -27,10 +21,10 @@ struct Channel { ChannelStreamType streamtype; union { - Process proc; - LibuvProcess uv; - PtyProcess pty; - Stream socket; + Proc proc; + LibuvProc uv; + PtyProc pty; + RStream socket; StdioPair stdio; StderrState err; InternalState internal; @@ -49,14 +43,20 @@ struct Channel { bool callback_scheduled; }; -EXTERN PMap(uint64_t) channels INIT( = MAP_INIT); - -EXTERN Callback on_print INIT( = CALLBACK_INIT); - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "channel.h.generated.h" +# include "channel.h.inline.generated.h" #endif +static inline bool callback_reader_set(CallbackReader reader) +{ + return reader.cb.type != kCallbackNone || reader.self; +} + +EXTERN PMap(uint64_t) channels INIT( = MAP_INIT); + +EXTERN Callback on_print INIT( = CALLBACK_INIT); + /// @returns Channel with the id or NULL if not found static inline Channel *find_channel(uint64_t id) { @@ -64,16 +64,14 @@ static inline Channel *find_channel(uint64_t id) } static inline Stream *channel_instream(Channel *chan) - REAL_FATTR_NONNULL_ALL; - -static inline Stream *channel_instream(Channel *chan) + FUNC_ATTR_NONNULL_ALL { switch (chan->streamtype) { case kChannelStreamProc: return &chan->stream.proc.in; case kChannelStreamSocket: - return &chan->stream.socket; + return &chan->stream.socket.s; case kChannelStreamStdio: return &chan->stream.stdio.out; @@ -85,10 +83,8 @@ static inline Stream *channel_instream(Channel *chan) abort(); } -static inline Stream *channel_outstream(Channel *chan) - REAL_FATTR_NONNULL_ALL; - -static inline Stream *channel_outstream(Channel *chan) +static inline RStream *channel_outstream(Channel *chan) + FUNC_ATTR_NONNULL_ALL { switch (chan->streamtype) { case kChannelStreamProc: diff --git a/src/nvim/channel_defs.h b/src/nvim/channel_defs.h index d4f1895420..2df6edea7a 100644 --- a/src/nvim/channel_defs.h +++ b/src/nvim/channel_defs.h @@ -30,7 +30,7 @@ typedef enum { } ChannelStdinMode; typedef struct { - Stream in; + RStream in; Stream out; } StdioPair; diff --git a/src/nvim/charset.c b/src/nvim/charset.c index c611d4cfd6..430f6b15fe 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1470,7 +1470,7 @@ start: *dst++ = *p++; } } - *dst = '\0'; + *dst = NUL; } } @@ -1492,6 +1492,6 @@ char *backslash_halve_save(const char *p) *dst++ = *p++; } } - *dst = '\0'; + *dst = NUL; return res; } diff --git a/src/nvim/charset.h b/src/nvim/charset.h index 62a38660a8..1407e21785 100644 --- a/src/nvim/charset.h +++ b/src/nvim/charset.h @@ -3,20 +3,9 @@ #include <stdbool.h> #include <stdint.h> -#include "nvim/func_attr.h" #include "nvim/option_vars.h" #include "nvim/strings.h" // IWYU pragma: keep -/// Return the folded-case equivalent of the given character -/// -/// @param[in] c Character to transform. -/// -/// @return Folded variant. -#define CH_FOLD(c) \ - utf_fold((sizeof(c) == sizeof(char)) \ - ? ((int)(uint8_t)(c)) \ - : ((int)(c))) - /// Flags for vim_str2nr() typedef enum { STR2NR_DEC = 0, @@ -41,15 +30,13 @@ typedef enum { #ifdef INCLUDE_GENERATED_DECLARATIONS # include "charset.h.generated.h" +# include "charset.h.inline.generated.h" #endif -static inline bool vim_isbreak(int c) - REAL_FATTR_CONST - REAL_FATTR_ALWAYS_INLINE; - /// Check if `c` is one of the characters in 'breakat'. /// Used very often if 'linebreak' is set static inline bool vim_isbreak(int c) + FUNC_ATTR_CONST FUNC_ATTR_ALWAYS_INLINE { return breakat_flags[(uint8_t)c]; } diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 808df44941..402a891099 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -19,6 +19,7 @@ #include "nvim/cmdexpand.h" #include "nvim/cmdhist.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" @@ -104,6 +105,7 @@ static bool cmdline_fuzzy_completion_supported(const expand_T *const xp) && xp->xp_context != EXPAND_COLORS && xp->xp_context != EXPAND_COMPILER && xp->xp_context != EXPAND_DIRECTORIES + && xp->xp_context != EXPAND_DIRS_IN_CDPATH && xp->xp_context != EXPAND_FILES && xp->xp_context != EXPAND_FILES_IN_PATH && xp->xp_context != EXPAND_FILETYPE @@ -158,7 +160,8 @@ static void wildescape(expand_T *xp, const char *str, int numfiles, char **files || xp->xp_context == EXPAND_FILES_IN_PATH || xp->xp_context == EXPAND_SHELLCMD || xp->xp_context == EXPAND_BUFFERS - || xp->xp_context == EXPAND_DIRECTORIES) { + || xp->xp_context == EXPAND_DIRECTORIES + || xp->xp_context == EXPAND_DIRS_IN_CDPATH) { // Insert a backslash into a file name before a space, \, %, # // and wildmatch characters, except '~'. for (int i = 0; i < numfiles; i++) { @@ -239,6 +242,9 @@ int nextwild(expand_T *xp, int type, int options, bool escape) if (xp->xp_numfiles == -1) { set_expand_context(xp); + if (xp->xp_context == EXPAND_LUA) { + nlua_expand_pat(xp); + } cmd_showtail = expand_showtail(xp); } @@ -285,12 +291,6 @@ int nextwild(expand_T *xp, int type, int options, bool escape) p2 = ExpandOne(xp, p1, xstrnsave(&ccline->cmdbuff[i], xp->xp_pattern_len), use_options, type); xfree(p1); - - // xp->xp_pattern might have been modified by ExpandOne (for example, - // in lua completion), so recompute the pattern index and length - i = (int)(xp->xp_pattern - ccline->cmdbuff); - xp->xp_pattern_len = (size_t)ccline->cmdpos - (size_t)i; - // Longest match: make sure it is not shorter, happens with :help. if (p2 != NULL && type == WILD_LONGEST) { int j; @@ -356,6 +356,7 @@ static int cmdline_pum_create(CmdlineInfo *ccline, expand_T *xp, char **matches, .pum_info = NULL, .pum_extra = NULL, .pum_kind = NULL, + .pum_user_hlattr = -1, }; } @@ -401,6 +402,20 @@ void cmdline_pum_cleanup(CmdlineInfo *cclp) wildmenu_cleanup(cclp); } +/// Returns the current cmdline completion pattern. +char *cmdline_compl_pattern(void) +{ + expand_T *xp = get_cmdline_info()->xpc; + return xp == NULL ? NULL : xp->xp_orig; +} + +/// Returns true if fuzzy cmdline completion is active, false otherwise. +bool cmdline_compl_is_fuzzy(void) +{ + expand_T *xp = get_cmdline_info()->xpc; + return xp != NULL && cmdline_fuzzy_completion_supported(xp); +} + /// Return the number of characters that should be skipped in the wildmenu /// These are backslashes used for escaping. Do show backslashes in help tags. static int skip_wildmenu_char(expand_T *xp, char *s) @@ -655,10 +670,7 @@ static char *get_next_or_prev_match(int mode, expand_T *xp) ht -= 2; } findex -= ht; - if (findex < 0) { - // few entries left, select the first entry - findex = 0; - } + findex = MAX(findex, 0); // few entries left, select the first entry } } else if (mode == WILD_PAGEDOWN) { if (findex == xp->xp_numfiles - 1) { @@ -686,18 +698,10 @@ static char *get_next_or_prev_match(int mode, expand_T *xp) // When wrapping around, return the original string, set findex to -1. if (findex < 0) { - if (xp->xp_orig == NULL) { - findex = xp->xp_numfiles - 1; - } else { - findex = -1; - } + findex = xp->xp_orig == NULL ? xp->xp_numfiles - 1 : -1; } if (findex >= xp->xp_numfiles) { - if (xp->xp_orig == NULL) { - findex = 0; - } else { - findex = -1; - } + findex = xp->xp_orig == NULL ? 0 : -1; } if (compl_match_array) { compl_selected = findex; @@ -1046,6 +1050,9 @@ int showmatches(expand_T *xp, bool wildmenu) if (xp->xp_numfiles == -1) { set_expand_context(xp); + if (xp->xp_context == EXPAND_LUA) { + nlua_expand_pat(xp); + } int i = expand_cmdline(xp, ccline->cmdbuff, ccline->cmdpos, &numMatches, &matches); showtail = expand_showtail(xp); @@ -1094,9 +1101,7 @@ int showmatches(expand_T *xp, bool wildmenu) } else { j = vim_strsize(SHOW_MATCH(i)); } - if (j > maxlen) { - maxlen = j; - } + maxlen = MAX(maxlen, j); } if (xp->xp_context == EXPAND_TAGS_LISTFILES) { @@ -1213,7 +1218,8 @@ char *addstar(char *fname, size_t len, int context) if (context != EXPAND_FILES && context != EXPAND_FILES_IN_PATH && context != EXPAND_SHELLCMD - && context != EXPAND_DIRECTORIES) { + && context != EXPAND_DIRECTORIES + && context != EXPAND_DIRS_IN_CDPATH) { // Matching will be done internally (on something other than files). // So we convert the file-matching-type wildcards into our kind for // use with vim_regcomp(). First work out how long it will be: @@ -1827,7 +1833,7 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expa case CMD_tcd: case CMD_tchdir: if (xp->xp_context == EXPAND_FILES) { - xp->xp_context = EXPAND_DIRECTORIES; + xp->xp_context = EXPAND_DIRS_IN_CDPATH; } break; case CMD_help: @@ -2491,6 +2497,8 @@ static int expand_files_and_dirs(expand_T *xp, char *pat, char ***matches, int * flags |= EW_FILE; } else if (xp->xp_context == EXPAND_FILES_IN_PATH) { flags |= (EW_FILE | EW_PATH); + } else if (xp->xp_context == EXPAND_DIRS_IN_CDPATH) { + flags = (flags | EW_DIR | EW_CDPATH) & ~EW_FILE; } else { flags = (flags | EW_DIR) & ~EW_FILE; } @@ -2703,7 +2711,8 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM if (xp->xp_context == EXPAND_FILES || xp->xp_context == EXPAND_DIRECTORIES - || xp->xp_context == EXPAND_FILES_IN_PATH) { + || xp->xp_context == EXPAND_FILES_IN_PATH + || xp->xp_context == EXPAND_DIRS_IN_CDPATH) { return expand_files_and_dirs(xp, pat, matches, numMatches, flags, options); } @@ -2782,8 +2791,7 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM } if (xp->xp_context == EXPAND_LUA) { - ILOG("PAT %s", pat); - return nlua_expand_pat(xp, pat, numMatches, matches); + return nlua_expand_get_matches(numMatches, matches); } if (!fuzzy) { @@ -3074,7 +3082,7 @@ static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T typval_T args[4]; const sctx_T save_current_sctx = current_sctx; - if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0' || xp->xp_line == NULL) { + if (xp->xp_arg == NULL || xp->xp_arg[0] == NUL || xp->xp_line == NULL) { return NULL; } @@ -3256,7 +3264,7 @@ void globpath(char *path, char *file, garray_T *ga, int expand_options, bool dir copy_option_part(&path, buf, MAXPATHL, ","); if (strlen(buf) + strlen(file) + 2 < MAXPATHL) { add_pathsep(buf); - STRCAT(buf, file); + strcat(buf, file); char **p; int num_p = 0; @@ -3595,7 +3603,11 @@ void f_getcompletion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } theend: - ; + if (xpc.xp_context == EXPAND_LUA) { + xpc.xp_col = (int)strlen(xpc.xp_line); + nlua_expand_pat(&xpc); + xpc.xp_pattern_len = strlen(xpc.xp_pattern); + } char *pat; if (cmdline_fuzzy_completion_supported(&xpc)) { // when fuzzy matching, don't modify the search string diff --git a/src/nvim/cmdexpand_defs.h b/src/nvim/cmdexpand_defs.h index c1fb85859c..3369790151 100644 --- a/src/nvim/cmdexpand_defs.h +++ b/src/nvim/cmdexpand_defs.h @@ -105,6 +105,7 @@ enum { EXPAND_SETTING_SUBTRACT, EXPAND_ARGOPT, EXPAND_KEYMAP, + EXPAND_DIRS_IN_CDPATH, EXPAND_CHECKHEALTH, EXPAND_LUA, }; diff --git a/src/nvim/cmdhist.c b/src/nvim/cmdhist.c index 983ab8b59b..47a4ffba9e 100644 --- a/src/nvim/cmdhist.c +++ b/src/nvim/cmdhist.c @@ -11,6 +11,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/cmdhist.h" +#include "nvim/errors.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" @@ -189,7 +190,7 @@ static inline void hist_free_entry(histentry_T *hisptr) FUNC_ATTR_NONNULL_ALL { xfree(hisptr->hisstr); - tv_list_unref(hisptr->additional_elements); + xfree(hisptr->additional_data); clear_hist_entry(hisptr); } @@ -236,7 +237,7 @@ static int in_history(int type, const char *str, int move_to_front, int sep) return false; } - list_T *const list = history[type][i].additional_elements; + AdditionalData *ad = history[type][i].additional_data; char *const save_hisstr = history[type][i].hisstr; while (i != hisidx[type]) { if (++i >= hislen) { @@ -245,11 +246,11 @@ static int in_history(int type, const char *str, int move_to_front, int sep) history[type][last_i] = history[type][i]; last_i = i; } - tv_list_unref(list); + xfree(ad); history[type][i].hisnum = ++hisnum[type]; history[type][i].hisstr = save_hisstr; history[type][i].timestamp = os_time(); - history[type][i].additional_elements = NULL; + history[type][i].additional_data = NULL; return true; } @@ -336,7 +337,7 @@ void add_to_history(int histype, const char *new_entry, size_t new_entrylen, boo // Store the separator after the NUL of the string. hisptr->hisstr = xstrnsave(new_entry, new_entrylen + 2); hisptr->timestamp = os_time(); - hisptr->additional_elements = NULL; + hisptr->additional_data = NULL; hisptr->hisstr[new_entrylen + 1] = (char)sep; hisptr->hisnum = ++hisnum[histype]; diff --git a/src/nvim/cmdhist.h b/src/nvim/cmdhist.h index 43be397cee..4df4b09e68 100644 --- a/src/nvim/cmdhist.h +++ b/src/nvim/cmdhist.h @@ -24,7 +24,7 @@ typedef struct { int hisnum; ///< Entry identifier number. char *hisstr; ///< Actual entry, separator char after the NUL. Timestamp timestamp; ///< Time when entry was added. - list_T *additional_elements; ///< Additional entries from ShaDa file. + AdditionalData *additional_data; ///< Additional entries from ShaDa file. } histentry_T; #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/context.c b/src/nvim/context.c index 95e2618f62..461b10a9d5 100644 --- a/src/nvim/context.c +++ b/src/nvim/context.c @@ -66,21 +66,11 @@ Context *ctx_get(size_t index) void ctx_free(Context *ctx) FUNC_ATTR_NONNULL_ALL { - if (ctx->regs.data) { - msgpack_sbuffer_destroy(&ctx->regs); - } - if (ctx->jumps.data) { - msgpack_sbuffer_destroy(&ctx->jumps); - } - if (ctx->bufs.data) { - msgpack_sbuffer_destroy(&ctx->bufs); - } - if (ctx->gvars.data) { - msgpack_sbuffer_destroy(&ctx->gvars); - } - if (ctx->funcs.items) { - api_free_array(ctx->funcs); - } + api_free_string(ctx->regs); + api_free_string(ctx->jumps); + api_free_string(ctx->bufs); + api_free_string(ctx->gvars); + api_free_array(ctx->funcs); } /// Saves the editor state to a context. @@ -98,19 +88,19 @@ void ctx_save(Context *ctx, const int flags) } if (flags & kCtxRegs) { - ctx_save_regs(ctx); + ctx->regs = shada_encode_regs(); } if (flags & kCtxJumps) { - ctx_save_jumps(ctx); + ctx->jumps = shada_encode_jumps(); } if (flags & kCtxBufs) { - ctx_save_bufs(ctx); + ctx->bufs = shada_encode_buflist(); } if (flags & kCtxGVars) { - ctx_save_gvars(ctx); + ctx->gvars = shada_encode_gvars(); } if (flags & kCtxFuncs) { @@ -173,33 +163,13 @@ bool ctx_restore(Context *ctx, const int flags) return true; } -/// Saves the global registers to a context. -/// -/// @param ctx Save to this context. -static inline void ctx_save_regs(Context *ctx) - FUNC_ATTR_NONNULL_ALL -{ - msgpack_sbuffer_init(&ctx->regs); - shada_encode_regs(&ctx->regs); -} - /// Restores the global registers from a context. /// /// @param ctx Restore from this context. static inline void ctx_restore_regs(Context *ctx) FUNC_ATTR_NONNULL_ALL { - shada_read_sbuf(&ctx->regs, kShaDaWantInfo | kShaDaForceit); -} - -/// Saves the jumplist to a context. -/// -/// @param ctx Save to this context. -static inline void ctx_save_jumps(Context *ctx) - FUNC_ATTR_NONNULL_ALL -{ - msgpack_sbuffer_init(&ctx->jumps); - shada_encode_jumps(&ctx->jumps); + shada_read_string(ctx->regs, kShaDaWantInfo | kShaDaForceit); } /// Restores the jumplist from a context. @@ -208,17 +178,7 @@ static inline void ctx_save_jumps(Context *ctx) static inline void ctx_restore_jumps(Context *ctx) FUNC_ATTR_NONNULL_ALL { - shada_read_sbuf(&ctx->jumps, kShaDaWantInfo | kShaDaForceit); -} - -/// Saves the buffer list to a context. -/// -/// @param ctx Save to this context. -static inline void ctx_save_bufs(Context *ctx) - FUNC_ATTR_NONNULL_ALL -{ - msgpack_sbuffer_init(&ctx->bufs); - shada_encode_buflist(&ctx->bufs); + shada_read_string(ctx->jumps, kShaDaWantInfo | kShaDaForceit); } /// Restores the buffer list from a context. @@ -227,17 +187,7 @@ static inline void ctx_save_bufs(Context *ctx) static inline void ctx_restore_bufs(Context *ctx) FUNC_ATTR_NONNULL_ALL { - shada_read_sbuf(&ctx->bufs, kShaDaWantInfo | kShaDaForceit); -} - -/// Saves global variables to a context. -/// -/// @param ctx Save to this context. -static inline void ctx_save_gvars(Context *ctx) - FUNC_ATTR_NONNULL_ALL -{ - msgpack_sbuffer_init(&ctx->gvars); - shada_encode_gvars(&ctx->gvars); + shada_read_string(ctx->bufs, kShaDaWantInfo | kShaDaForceit); } /// Restores global variables from a context. @@ -246,7 +196,7 @@ static inline void ctx_save_gvars(Context *ctx) static inline void ctx_restore_gvars(Context *ctx) FUNC_ATTR_NONNULL_ALL { - shada_read_sbuf(&ctx->gvars, kShaDaWantInfo | kShaDaForceit); + shada_read_string(ctx->gvars, kShaDaWantInfo | kShaDaForceit); } /// Saves functions to a context. @@ -291,41 +241,16 @@ static inline void ctx_restore_funcs(Context *ctx) } } -/// Convert msgpack_sbuffer to readfile()-style array. -/// -/// @param[in] sbuf msgpack_sbuffer to convert. -/// -/// @return readfile()-style array representation of "sbuf". -static inline Array sbuf_to_array(msgpack_sbuffer sbuf, Arena *arena) -{ - list_T *const list = tv_list_alloc(kListLenMayKnow); - tv_list_append_string(list, "", 0); - if (sbuf.size > 0) { - encode_list_write(list, sbuf.data, sbuf.size); - } - - typval_T list_tv = (typval_T) { - .v_lock = VAR_UNLOCKED, - .v_type = VAR_LIST, - .vval.v_list = list - }; - - Array array = vim_to_object(&list_tv, arena, false).data.array; - tv_clear(&list_tv); - return array; -} - -/// Convert readfile()-style array to msgpack_sbuffer. +/// Convert readfile()-style array to String /// /// @param[in] array readfile()-style array to convert. /// @param[out] err Error object. /// -/// @return msgpack_sbuffer with conversion result. -static inline msgpack_sbuffer array_to_sbuf(Array array, Error *err) +/// @return String with conversion result. +static inline String array_to_string(Array array, Error *err) FUNC_ATTR_NONNULL_ALL { - msgpack_sbuffer sbuf; - msgpack_sbuffer_init(&sbuf); + String sbuf = STRING_INIT; typval_T list_tv; object_to_vim(ARRAY_OBJ(array), &list_tv, err); @@ -335,41 +260,40 @@ static inline msgpack_sbuffer array_to_sbuf(Array array, Error *err) api_set_error(err, kErrorTypeException, "%s", "E474: Failed to convert list to msgpack string buffer"); } - sbuf.alloc = sbuf.size; tv_clear(&list_tv); return sbuf; } -/// Converts Context to Dictionary representation. +/// Converts Context to Dict representation. /// /// @param[in] ctx Context to convert. /// -/// @return Dictionary representing "ctx". -Dictionary ctx_to_dict(Context *ctx, Arena *arena) +/// @return Dict representing "ctx". +Dict ctx_to_dict(Context *ctx, Arena *arena) FUNC_ATTR_NONNULL_ALL { assert(ctx != NULL); - Dictionary rv = arena_dict(arena, 5); + Dict rv = arena_dict(arena, 5); - PUT_C(rv, "regs", ARRAY_OBJ(sbuf_to_array(ctx->regs, arena))); - PUT_C(rv, "jumps", ARRAY_OBJ(sbuf_to_array(ctx->jumps, arena))); - PUT_C(rv, "bufs", ARRAY_OBJ(sbuf_to_array(ctx->bufs, arena))); - PUT_C(rv, "gvars", ARRAY_OBJ(sbuf_to_array(ctx->gvars, arena))); + PUT_C(rv, "regs", ARRAY_OBJ(string_to_array(ctx->regs, false, arena))); + PUT_C(rv, "jumps", ARRAY_OBJ(string_to_array(ctx->jumps, false, arena))); + PUT_C(rv, "bufs", ARRAY_OBJ(string_to_array(ctx->bufs, false, arena))); + PUT_C(rv, "gvars", ARRAY_OBJ(string_to_array(ctx->gvars, false, arena))); PUT_C(rv, "funcs", ARRAY_OBJ(copy_array(ctx->funcs, arena))); return rv; } -/// Converts Dictionary representation of Context back to Context object. +/// Converts Dict representation of Context back to Context object. /// -/// @param[in] dict Context Dictionary representation. +/// @param[in] dict Context Dict representation. /// @param[out] ctx Context object to store conversion result into. /// @param[out] err Error object. /// /// @return types of included context items. -int ctx_from_dict(Dictionary dict, Context *ctx, Error *err) +int ctx_from_dict(Dict dict, Context *ctx, Error *err) FUNC_ATTR_NONNULL_ALL { assert(ctx != NULL); @@ -382,16 +306,16 @@ int ctx_from_dict(Dictionary dict, Context *ctx, Error *err) } if (strequal(item.key.data, "regs")) { types |= kCtxRegs; - ctx->regs = array_to_sbuf(item.value.data.array, err); + ctx->regs = array_to_string(item.value.data.array, err); } else if (strequal(item.key.data, "jumps")) { types |= kCtxJumps; - ctx->jumps = array_to_sbuf(item.value.data.array, err); + ctx->jumps = array_to_string(item.value.data.array, err); } else if (strequal(item.key.data, "bufs")) { types |= kCtxBufs; - ctx->bufs = array_to_sbuf(item.value.data.array, err); + ctx->bufs = array_to_string(item.value.data.array, err); } else if (strequal(item.key.data, "gvars")) { types |= kCtxGVars; - ctx->gvars = array_to_sbuf(item.value.data.array, err); + ctx->gvars = array_to_string(item.value.data.array, err); } else if (strequal(item.key.data, "funcs")) { types |= kCtxFuncs; ctx->funcs = copy_object(item.value, NULL).data.array; diff --git a/src/nvim/context.h b/src/nvim/context.h index 1c18a1af7c..4375030fbc 100644 --- a/src/nvim/context.h +++ b/src/nvim/context.h @@ -1,31 +1,24 @@ #pragma once -#include <msgpack/sbuffer.h> #include <stddef.h> #include "klib/kvec.h" #include "nvim/api/private/defs.h" typedef struct { - msgpack_sbuffer regs; ///< Registers. - msgpack_sbuffer jumps; ///< Jumplist. - msgpack_sbuffer bufs; ///< Buffer list. - msgpack_sbuffer gvars; ///< Global variables. + String regs; ///< Registers. + String jumps; ///< Jumplist. + String bufs; ///< Buffer list. + String gvars; ///< Global variables. Array funcs; ///< Functions. } Context; typedef kvec_t(Context) ContextVec; -#define MSGPACK_SBUFFER_INIT (msgpack_sbuffer) { \ - .size = 0, \ - .data = NULL, \ - .alloc = 0, \ -} - #define CONTEXT_INIT (Context) { \ - .regs = MSGPACK_SBUFFER_INIT, \ - .jumps = MSGPACK_SBUFFER_INIT, \ - .bufs = MSGPACK_SBUFFER_INIT, \ - .gvars = MSGPACK_SBUFFER_INIT, \ + .regs = STRING_INIT, \ + .jumps = STRING_INIT, \ + .bufs = STRING_INIT, \ + .gvars = STRING_INIT, \ .funcs = ARRAY_DICT_INIT, \ } diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c index 2e9e68843a..35afca2fe9 100644 --- a/src/nvim/cursor.c +++ b/src/nvim/cursor.c @@ -216,12 +216,7 @@ static int coladvance2(win_T *wp, pos_T *pos, bool addspaces, bool finetune, col } } - if (idx < 0) { - pos->col = 0; - } else { - pos->col = idx; - } - + pos->col = MAX(idx, 0); pos->coladd = 0; if (finetune) { @@ -310,15 +305,9 @@ linenr_T get_cursor_rel_lnum(win_T *wp, linenr_T lnum) /// This allows for the col to be on the NUL byte. void check_pos(buf_T *buf, pos_T *pos) { - if (pos->lnum > buf->b_ml.ml_line_count) { - pos->lnum = buf->b_ml.ml_line_count; - } - + pos->lnum = MIN(pos->lnum, buf->b_ml.ml_line_count); if (pos->col > 0) { - colnr_T len = ml_get_buf_len(buf, pos->lnum); - if (pos->col > len) { - pos->col = len; - } + pos->col = MIN(pos->col, ml_get_buf_len(buf, pos->lnum)); } } @@ -385,9 +374,7 @@ void check_cursor_col(win_T *win) int cs, ce; getvcol(win, &win->w_cursor, &cs, NULL, &ce); - if (win->w_cursor.coladd > ce - cs) { - win->w_cursor.coladd = ce - cs; - } + win->w_cursor.coladd = MIN(win->w_cursor.coladd, ce - cs); } } else { // avoid weird number when there is a miscalculation or overflow diff --git a/src/nvim/cursor_shape.c b/src/nvim/cursor_shape.c index 67bb34d4ea..1f11367618 100644 --- a/src/nvim/cursor_shape.c +++ b/src/nvim/cursor_shape.c @@ -57,7 +57,7 @@ Array mode_style_array(Arena *arena) for (int i = 0; i < SHAPE_IDX_COUNT; i++) { cursorentry_T *cur = &shape_table[i]; - Dictionary dic = arena_dict(arena, 3 + ((cur->used_for & SHAPE_CURSOR) ? 9 : 0)); + Dict dic = arena_dict(arena, 3 + ((cur->used_for & SHAPE_CURSOR) ? 9 : 0)); PUT_C(dic, "name", CSTR_AS_OBJ(cur->full_name)); PUT_C(dic, "short_name", CSTR_AS_OBJ(cur->name)); if (cur->used_for & SHAPE_MOUSE) { @@ -86,7 +86,7 @@ Array mode_style_array(Arena *arena) PUT_C(dic, "attr_id_lm", INTEGER_OBJ(cur->id_lm ? syn_id2attr(cur->id_lm) : 0)); } - ADD_C(all, DICTIONARY_OBJ(dic)); + ADD_C(all, DICT_OBJ(dic)); } return all; diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c index 7d87b61ce5..b71ff23f57 100644 --- a/src/nvim/debugger.c +++ b/src/nvim/debugger.c @@ -13,6 +13,7 @@ #include "nvim/cmdexpand_defs.h" #include "nvim/debugger.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index 303d0318b5..3633940b14 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -15,6 +15,7 @@ #include "nvim/drawscreen.h" #include "nvim/extmark.h" #include "nvim/fold.h" +#include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/grid_defs.h" #include "nvim/highlight.h" @@ -30,9 +31,6 @@ # include "decoration.c.generated.h" #endif -// TODO(bfredl): These should maybe be per-buffer, so that all resources -// associated with a buffer can be freed when the buffer is unloaded. -kvec_t(DecorSignHighlight) decor_items = KV_INITIAL_VALUE; uint32_t decor_freelist = UINT32_MAX; // Decorations might be requested to be deleted in a callback in the middle of redrawing. @@ -88,7 +86,7 @@ void bufhl_add_hl_pos_offset(buf_T *buf, int src_id, int hl_id, lpos_T pos_start extmark_set(buf, (uint32_t)src_id, NULL, (int)lnum - 1, hl_start, (int)lnum - 1 + end_off, hl_end, - decor, MT_FLAG_DECOR_HL, true, false, true, false, false, NULL); + decor, MT_FLAG_DECOR_HL, true, false, true, false, NULL); } } @@ -184,6 +182,21 @@ void buf_put_decor(buf_T *buf, DecorInline decor, int row, int row2) } } +/// When displaying signs in the 'number' column, if the width of the number +/// column is less than 2, then force recomputing the width after placing or +/// unplacing the first sign in "buf". +static void may_force_numberwidth_recompute(buf_T *buf, bool unplace) +{ + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (wp->w_buffer == buf + && wp->w_minscwidth == SCL_NUM + && (wp->w_p_nu || wp->w_p_rnu) + && (unplace || wp->w_nrwidth_width < 2)) { + wp->w_nrwidth_line_count = 0; + } + } +} + static int sign_add_id = 0; void buf_put_decor_sh(buf_T *buf, DecorSignHighlight *sh, int row1, int row2) { @@ -191,6 +204,7 @@ void buf_put_decor_sh(buf_T *buf, DecorSignHighlight *sh, int row1, int row2) sh->sign_add_id = sign_add_id++; if (sh->text[0]) { buf_signcols_count_range(buf, row1, row2, 1, kFalse); + may_force_numberwidth_recompute(buf, false); } } } @@ -218,6 +232,7 @@ void buf_remove_decor_sh(buf_T *buf, int row1, int row2, DecorSignHighlight *sh) if (buf_meta_total(buf, kMTMetaSignText)) { buf_signcols_count_range(buf, row1, row2, -1, kFalse); } else { + may_force_numberwidth_recompute(buf, true); buf->b_signcols.resized = true; buf->b_signcols.max = buf->b_signcols.count[0] = 0; } @@ -274,7 +289,7 @@ static void decor_free_inner(DecorVirtText *vt, uint32_t first_idx) while (idx != DECOR_ID_INVALID) { DecorSignHighlight *sh = &kv_A(decor_items, idx); if (sh->flags & kSHIsSign) { - xfree(sh->sign_name); + XFREE_CLEAR(sh->sign_name); } sh->flags = 0; if (sh->url != NULL) { @@ -580,11 +595,7 @@ int decor_redraw_col(win_T *wp, int col, int win_col, bool hidden, DecorState *s break; } - if (!mt_scoped_in_win(mark, wp)) { - goto next_mark; - } - - if (mt_invalid(mark) || mt_end(mark) || !mt_decor_any(mark)) { + if (mt_invalid(mark) || mt_end(mark) || !mt_decor_any(mark) || !ns_in_win(mark.ns, wp)) { goto next_mark; } @@ -728,8 +739,7 @@ void decor_redraw_signs(win_T *wp, buf_T *buf, int row, SignTextAttrs sattrs[], if (mark.pos.row != row) { break; } - if (!mt_end(mark) && !mt_invalid(mark) && mt_decor_sign(mark) - && mt_scoped_in_win(mark, wp)) { + if (!mt_invalid(mark) && !mt_end(mark) && mt_decor_sign(mark) && ns_in_win(mark.ns, wp)) { DecorSignHighlight *sh = decor_find_sign(mt_decor(mark)); num_text += (sh->text[0] != NUL); kv_push(signs, ((SignItem){ sh, mark.id })); @@ -877,8 +887,8 @@ bool decor_redraw_eol(win_T *wp, DecorState *state, int *eol_attr, int eol_col) static const uint32_t lines_filter[4] = {[kMTMetaLines] = kMTFilterSelect }; -/// @param has_fold whether line "lnum" has a fold, or kNone when not calculated yet -int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines, TriState has_fold) +/// @param apply_folds Only count virtual lines that are not in folds. +int decor_virt_lines(win_T *wp, int start_row, int end_row, VirtLines *lines, bool apply_folds) { buf_T *buf = wp->w_buffer; if (!buf_meta_total(buf, kMTMetaLines)) { @@ -887,34 +897,26 @@ int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines, TriState has_fo return 0; } - assert(lnum > 0); - bool below_fold = lnum > 1 && hasFolding(wp, lnum - 1, NULL, NULL); - if (has_fold == kNone) { - has_fold = hasFolding(wp, lnum, NULL, NULL); - } - - const int row = lnum - 1; - const int start_row = below_fold ? row : MAX(row - 1, 0); - const int end_row = has_fold ? row : row + 1; - if (start_row >= end_row) { - return 0; - } - MarkTreeIter itr[1] = { 0 }; - if (!marktree_itr_get_filter(buf->b_marktree, start_row, 0, end_row, 0, lines_filter, itr)) { + if (!marktree_itr_get_filter(buf->b_marktree, MAX(start_row - 1, 0), 0, end_row, 0, + lines_filter, itr)) { return 0; } + assert(start_row >= 0); + int virt_lines = 0; while (true) { MTKey mark = marktree_itr_current(itr); DecorVirtText *vt = mt_decor_virt(mark); - if (mt_scoped_in_win(mark, wp)) { + if (!mt_invalid(mark) && ns_in_win(mark.ns, wp)) { while (vt) { if (vt->flags & kVTIsLines) { bool above = vt->flags & kVTLinesAbove; - int draw_row = mark.pos.row + (above ? 0 : 1); - if (draw_row == row) { + int mrow = mark.pos.row; + int draw_row = mrow + (above ? 0 : 1); + if (draw_row >= start_row && draw_row < end_row + && (!apply_folds || !hasFolding(wp, mrow + 1, NULL, NULL))) { virt_lines += (int)kv_size(vt->data.virt_lines); if (lines) { kv_splice(*lines, vt->data.virt_lines); @@ -936,7 +938,7 @@ int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines, TriState has_fo /// This assumes maximum one entry of each kind, which will not always be the case. /// /// NB: assumes caller has allocated enough space in dict for all fields! -void decor_to_dict_legacy(Dictionary *dict, DecorInline decor, bool hl_name, Arena *arena) +void decor_to_dict_legacy(Dict *dict, DecorInline decor, bool hl_name, Arena *arena) { DecorSignHighlight sh_hl = DECOR_SIGN_HIGHLIGHT_INIT; DecorSignHighlight sh_sign = DECOR_SIGN_HIGHLIGHT_INIT; diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h index 86d4de79f0..1b595fb86f 100644 --- a/src/nvim/decoration.h +++ b/src/nvim/decoration.h @@ -77,6 +77,9 @@ typedef struct { } DecorState; EXTERN DecorState decor_state INIT( = { 0 }); +// TODO(bfredl): These should maybe be per-buffer, so that all resources +// associated with a buffer can be freed when the buffer is unloaded. +EXTERN kvec_t(DecorSignHighlight) decor_items INIT( = KV_INITIAL_VALUE); #ifdef INCLUDE_GENERATED_DECLARATIONS # include "decoration.h.generated.h" diff --git a/src/nvim/decoration_defs.h b/src/nvim/decoration_defs.h index c9475257b1..49dc4f9168 100644 --- a/src/nvim/decoration_defs.h +++ b/src/nvim/decoration_defs.h @@ -56,6 +56,7 @@ typedef struct { } DecorHighlightInline; #define DECOR_HIGHLIGHT_INLINE_INIT { 0, DECOR_PRIORITY_BASE, 0, 0 } + typedef struct { uint16_t flags; DecorPriority priority; diff --git a/src/nvim/diff.c b/src/nvim/diff.c index ea846b46ec..d22fb65827 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -26,6 +26,7 @@ #include "nvim/cursor.h" #include "nvim/diff.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" @@ -139,7 +140,7 @@ typedef enum { void diff_buf_delete(buf_T *buf) { FOR_ALL_TABS(tp) { - int i = diff_buf_idx_tp(buf, tp); + int i = diff_buf_idx(buf, tp); if (i != DB_COUNT) { tp->tp_diffbuf[i] = NULL; @@ -172,7 +173,7 @@ void diff_buf_adjust(win_T *win) } if (!found_win) { - int i = diff_buf_idx(win->w_buffer); + int i = diff_buf_idx(win->w_buffer, curtab); if (i != DB_COUNT) { curtab->tp_diffbuf[i] = NULL; curtab->tp_diff_invalid = true; @@ -195,7 +196,7 @@ void diff_buf_adjust(win_T *win) /// @param buf The buffer to add. void diff_buf_add(buf_T *buf) { - if (diff_buf_idx(buf) != DB_COUNT) { + if (diff_buf_idx(buf, curtab) != DB_COUNT) { // It's already there. return; } @@ -212,9 +213,7 @@ void diff_buf_add(buf_T *buf) semsg(_("E96: Cannot diff more than %" PRId64 " buffers"), (int64_t)DB_COUNT); } -/// /// Remove all buffers to make diffs for. -/// static void diff_buf_clear(void) { for (int i = 0; i < DB_COUNT; i++) { @@ -226,23 +225,13 @@ static void diff_buf_clear(void) } } -/// Find buffer "buf" in the list of diff buffers for the current tab page. -/// -/// @param buf The buffer to find. -/// -/// @return Its index or DB_COUNT if not found. -static int diff_buf_idx(buf_T *buf) -{ - return diff_buf_idx_tp(buf, curtab); -} - /// Find buffer "buf" in the list of diff buffers for tab page "tp". /// /// @param buf /// @param tp /// /// @return its index or DB_COUNT if not found. -static int diff_buf_idx_tp(buf_T *buf, tabpage_T *tp) +static int diff_buf_idx(buf_T *buf, tabpage_T *tp) { int idx; for (idx = 0; idx < DB_COUNT; idx++) { @@ -260,7 +249,7 @@ static int diff_buf_idx_tp(buf_T *buf, tabpage_T *tp) void diff_invalidate(buf_T *buf) { FOR_ALL_TABS(tp) { - int i = diff_buf_idx_tp(buf, tp); + int i = diff_buf_idx(buf, tp); if (i != DB_COUNT) { tp->tp_diff_invalid = true; if (tp == curtab) { @@ -281,7 +270,7 @@ void diff_mark_adjust(buf_T *buf, linenr_T line1, linenr_T line2, linenr_T amoun { // Handle all tab pages that use "buf" in a diff. FOR_ALL_TABS(tp) { - int idx = diff_buf_idx_tp(buf, tp); + int idx = diff_buf_idx(buf, tp); if (idx != DB_COUNT) { diff_mark_adjust_tp(tp, idx, line1, line2, amount, amount_after); } @@ -366,7 +355,6 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, linenr_T break; } - // // Check for these situations: // 1 2 3 // 1 2 3 @@ -696,7 +684,7 @@ void diff_redraw(bool dofold) if (((wp != curwin) && (wp->w_topfill > 0)) || (n > 0)) { if (wp->w_topfill > n) { - wp->w_topfill = (n < 0 ? 0 : n); + wp->w_topfill = MAX(n, 0); } else if ((n > 0) && (n > wp->w_topfill)) { wp->w_topfill = n; if (wp == curwin) { @@ -748,6 +736,12 @@ static void clear_diffout(diffout_T *dout) /// @return FAIL for failure. static int diff_write_buffer(buf_T *buf, mmfile_t *m, linenr_T start, linenr_T end) { + if (buf->b_ml.ml_flags & ML_EMPTY) { + m->ptr = NULL; + m->size = 0; + return OK; + } + size_t len = 0; if (end < 0) { @@ -758,20 +752,7 @@ static int diff_write_buffer(buf_T *buf, mmfile_t *m, linenr_T start, linenr_T e for (linenr_T lnum = start; lnum <= end; lnum++) { len += (size_t)ml_get_buf_len(buf, lnum) + 1; } - char *ptr = try_malloc(len); - if (ptr == NULL) { - // Allocating memory failed. This can happen, because we try to read - // the whole buffer text into memory. Set the failed flag, the diff - // will be retried with external diff. The flag is never reset. - buf->b_diff_failed = true; - if (p_verbose > 0) { - verbose_enter(); - smsg(0, _("Not enough memory to use internal diff for buffer \"%s\""), - buf->b_fname); - verbose_leave(); - } - return FAIL; - } + char *ptr = xmalloc(len); m->ptr = ptr; m->size = (int)len; @@ -834,7 +815,6 @@ static int diff_write(buf_T *buf, diffin_T *din) return r; } -/// /// Update the diffs for all buffers involved. /// /// @param dio @@ -854,34 +834,33 @@ static void diff_try_update(diffio_T *dio, int idx_orig, exarg_T *eap) || dio->dio_diff.dout_fname == NULL) { goto theend; } + // Check external diff is actually working. + if (check_external_diff(dio) == FAIL) { + goto theend; + } } - // Check external diff is actually working. - if (!dio->dio_internal && check_external_diff(dio) == FAIL) { - goto theend; - } - - buf_T *buf; - // :diffupdate! if (eap != NULL && eap->forceit) { for (int idx_new = idx_orig; idx_new < DB_COUNT; idx_new++) { - buf = curtab->tp_diffbuf[idx_new]; + buf_T *buf = curtab->tp_diffbuf[idx_new]; if (buf_valid(buf)) { buf_check_timestamp(buf); } } } - // Write the first buffer to a tempfile or mmfile_t. - buf = curtab->tp_diffbuf[idx_orig]; - if (diff_write(buf, &dio->dio_orig) == FAIL) { - goto theend; + { + // Write the first buffer to a tempfile or mmfile_t. + buf_T *buf = curtab->tp_diffbuf[idx_orig]; + if (diff_write(buf, &dio->dio_orig) == FAIL) { + goto theend; + } } // Make a difference between the first buffer and every other. for (int idx_new = idx_orig + 1; idx_new < DB_COUNT; idx_new++) { - buf = curtab->tp_diffbuf[idx_new]; + buf_T *buf = curtab->tp_diffbuf[idx_new]; if (buf == NULL || buf->b_ml.ml_mfp == NULL) { continue; // skip buffer that isn't loaded } @@ -908,32 +887,15 @@ theend: xfree(dio->dio_diff.dout_fname); } -/// /// Return true if the options are set to use the internal diff library. /// Note that if the internal diff failed for one of the buffers, the external /// diff will be used anyway. -/// int diff_internal(void) FUNC_ATTR_PURE { return (diff_flags & DIFF_INTERNAL) != 0 && *p_dex == NUL; } -/// -/// Return true if the internal diff failed for one of the diff buffers. -/// -static int diff_internal_failed(void) -{ - // Only need to do something when there is another buffer. - for (int idx = 0; idx < DB_COUNT; idx++) { - if (curtab->tp_diffbuf[idx] != NULL - && curtab->tp_diffbuf[idx]->b_diff_failed) { - return true; - } - } - return false; -} - /// Completely update the diffs for the buffers involved. /// /// When using the external "diff" command the buffers are written to a file, @@ -981,14 +943,9 @@ void ex_diffupdate(exarg_T *eap) // Only use the internal method if it did not fail for one of the buffers. diffio_T diffio; CLEAR_FIELD(diffio); - diffio.dio_internal = diff_internal() && !diff_internal_failed(); + diffio.dio_internal = diff_internal(); diff_try_update(&diffio, idx_orig, eap); - if (diffio.dio_internal && diff_internal_failed()) { - // Internal diff failed, use external diff instead. - CLEAR_FIELD(diffio); - diff_try_update(&diffio, idx_orig, eap); - } // force updating cursor position on screen curwin->w_valid_cursor.lnum = 0; @@ -1002,11 +959,9 @@ theend: } } -/// /// Do a quick test if "diff" really works. Otherwise it looks like there /// are no differences. Can't use the return value, it's non-zero when /// there are differences. -/// static int check_external_diff(diffio_T *diffio) { // May try twice, first with "-a" and then without. @@ -1032,10 +987,9 @@ static int check_external_diff(diffio_T *diffio) io_error = true; } fclose(fd); - fd = NULL; - if (diff_file(diffio) == OK) { - fd = os_fopen(diffio->dio_diff.dout_fname, "r"); - } + fd = diff_file(diffio) == OK + ? os_fopen(diffio->dio_diff.dout_fname, "r") + : NULL; if (fd == NULL) { io_error = true; @@ -1090,9 +1044,7 @@ static int check_external_diff(diffio_T *diffio) return OK; } -/// /// Invoke the xdiff function. -/// static int diff_file_internal(diffio_T *diffio) { xpparam_t param; @@ -1272,10 +1224,10 @@ void ex_diffpatch(exarg_T *eap) // Delete any .orig or .rej file created. STRCPY(buf, tmp_new); - STRCAT(buf, ".orig"); + strcat(buf, ".orig"); os_remove(buf); STRCPY(buf, tmp_new); - STRCAT(buf, ".rej"); + strcat(buf, ".rej"); os_remove(buf); // Only continue if the output file was created. @@ -1287,7 +1239,7 @@ void ex_diffpatch(exarg_T *eap) } else { if (curbuf->b_fname != NULL) { newname = xstrnsave(curbuf->b_fname, strlen(curbuf->b_fname) + 4); - STRCAT(newname, ".new"); + strcat(newname, ".new"); } // don't use a new tab page, each tab page has its own diffs @@ -1657,6 +1609,7 @@ static void process_hunk(diff_T **dpp, diff_T **dprevp, int idx_orig, int idx_ne for (int i = idx_orig; i < idx_new; i++) { if (curtab->tp_diffbuf[i] != NULL) { dp->df_lnum[i] -= off; + dp->df_count[i] += off; } } dp->df_lnum[idx_new] = hunk->lnum_new; @@ -1667,11 +1620,7 @@ static void process_hunk(diff_T **dpp, diff_T **dprevp, int idx_orig, int idx_ne dp->df_count[idx_new] = (linenr_T)hunk->count_new - off; } else { // second overlap of new block with existing block - dp->df_count[idx_new] += (linenr_T)hunk->count_new - (linenr_T)hunk->count_orig - + dpl->df_lnum[idx_orig] + - dpl->df_count[idx_orig] - - (dp->df_lnum[idx_orig] + - dp->df_count[idx_orig]); + dp->df_count[idx_new] += (linenr_T)hunk->count_new; } // Adjust the size of the block to include all the lines to the @@ -1680,11 +1629,8 @@ static void process_hunk(diff_T **dpp, diff_T **dprevp, int idx_orig, int idx_ne - (dpl->df_lnum[idx_orig] + dpl->df_count[idx_orig]); if (off < 0) { - // new change ends in existing block, adjust the end if not - // done already - if (*notsetp) { - dp->df_count[idx_new] += -off; - } + // new change ends in existing block, adjust the end + dp->df_count[idx_new] += -off; off = 0; } @@ -1812,9 +1758,7 @@ void diff_clear(tabpage_T *tp) tp->tp_first_diff = NULL; } -/// -/// return true if the options are set to use diff linematch -/// +/// Return true if the options are set to use diff linematch. bool diff_linematch(diff_T *dp) { if (!(diff_flags & DIFF_LINEMATCH)) { @@ -2061,7 +2005,7 @@ static void run_linematch_algorithm(diff_T *dp) { // define buffers for diff algorithm mmfile_t diffbufs_mm[DB_COUNT]; - const char *diffbufs[DB_COUNT]; + const mmfile_t *diffbufs[DB_COUNT]; int diff_length[DB_COUNT]; size_t ndiffs = 0; for (int i = 0; i < DB_COUNT; i++) { @@ -2071,9 +2015,7 @@ static void run_linematch_algorithm(diff_T *dp) diff_write_buffer(curtab->tp_diffbuf[i], &diffbufs_mm[ndiffs], dp->df_lnum[i], dp->df_lnum[i] + dp->df_count[i] - 1); - // we want to get the char* to the diff buffer that was just written - // we add it to the array of char*, diffbufs - diffbufs[ndiffs] = diffbufs_mm[ndiffs].ptr; + diffbufs[ndiffs] = &diffbufs_mm[ndiffs]; // keep track of the length of this diff block to pass it to the linematch // algorithm @@ -2132,7 +2074,7 @@ int diff_check_with_linestatus(win_T *wp, linenr_T lnum, int *linestatus) return 0; } - int idx = diff_buf_idx(buf); // index in tp_diffbuf[] for this buffer + int idx = diff_buf_idx(buf, curtab); // index in tp_diffbuf[] for this buffer if (idx == DB_COUNT) { // no diffs for buffer "buf" @@ -2156,7 +2098,11 @@ int diff_check_with_linestatus(win_T *wp, linenr_T lnum, int *linestatus) return 0; } - if (!dp->is_linematched && diff_linematch(dp)) { + // Don't run linematch when lnum is offscreen. + // Useful for scrollbind calculations which need to count all the filler lines + // above the screen. + if (lnum >= wp->w_topline && lnum < wp->w_botline + && !dp->is_linematched && diff_linematch(dp)) { run_linematch_algorithm(dp); } @@ -2349,7 +2295,7 @@ void diff_set_topline(win_T *fromwin, win_T *towin) buf_T *frombuf = fromwin->w_buffer; linenr_T lnum = fromwin->w_topline; - int fromidx = diff_buf_idx(frombuf); + int fromidx = diff_buf_idx(frombuf, curtab); if (fromidx == DB_COUNT) { // safety check return; @@ -2376,7 +2322,7 @@ void diff_set_topline(win_T *fromwin, win_T *towin) - (frombuf->b_ml.ml_line_count - lnum); } else { // Find index for "towin". - int toidx = diff_buf_idx(towin->w_buffer); + int toidx = diff_buf_idx(towin->w_buffer, curtab); if (toidx == DB_COUNT) { // safety check @@ -2621,7 +2567,7 @@ bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) // Make a copy of the line, the next ml_get() will invalidate it. char *line_org = xstrdup(ml_get_buf(wp->w_buffer, lnum)); - int idx = diff_buf_idx(wp->w_buffer); + int idx = diff_buf_idx(wp->w_buffer, curtab); if (idx == DB_COUNT) { // cannot happen xfree(line_org); @@ -2692,9 +2638,7 @@ bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) si_org -= utf_head_off(line_org, line_org + si_org); si_new -= utf_head_off(line_new, line_new + si_new); - if (*startp > si_org) { - *startp = si_org; - } + *startp = MIN(*startp, si_org); // Search for end of difference, if any. if ((line_org[si_org] != NUL) || (line_new[si_new] != NUL)) { @@ -2734,9 +2678,7 @@ bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) } } - if (*endp < ei_org) { - *endp = ei_org; - } + *endp = MAX(*endp, ei_org); } } } @@ -2847,7 +2789,7 @@ void ex_diffgetput(exarg_T *eap) int idx_other; // Find the current buffer in the list of diff buffers. - int idx_cur = diff_buf_idx(curbuf); + int idx_cur = diff_buf_idx(curbuf, curtab); if (idx_cur == DB_COUNT) { emsg(_("E99: Current buffer is not in diff mode")); return; @@ -2919,7 +2861,7 @@ void ex_diffgetput(exarg_T *eap) // nothing to do return; } - idx_other = diff_buf_idx(buf); + idx_other = diff_buf_idx(buf, curtab); if (idx_other == DB_COUNT) { semsg(_("E103: Buffer \"%s\" is not in diff mode"), eap->arg); @@ -2961,7 +2903,7 @@ void ex_diffgetput(exarg_T *eap) // everything up. if (!curbuf->b_changed) { change_warning(curbuf, 0); - if (diff_buf_idx(curbuf) != idx_to) { + if (diff_buf_idx(curbuf, curtab) != idx_to) { emsg(_("E787: Buffer changed unexpectedly")); goto theend; } @@ -3064,19 +3006,11 @@ static void diffgetput(const int addr_count, const int idx_cur, const int idx_fr // range ends above end of current/from diff block if (idx_cur == idx_from) { // :diffput - int i = dp->df_count[idx_cur] - start_skip - end_skip; - - if (count > i) { - count = i; - } + count = MIN(count, dp->df_count[idx_cur] - start_skip - end_skip); } else { // :diffget count -= end_skip; - end_skip = dp->df_count[idx_from] - start_skip - count; - - if (end_skip < 0) { - end_skip = 0; - } + end_skip = MAX(dp->df_count[idx_from] - start_skip - count, 0); } } else { end_skip = 0; @@ -3208,7 +3142,7 @@ bool diff_mode_buf(buf_T *buf) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) { FOR_ALL_TABS(tp) { - if (diff_buf_idx_tp(buf, tp) != DB_COUNT) { + if (diff_buf_idx(buf, tp) != DB_COUNT) { return true; } } @@ -3224,7 +3158,7 @@ bool diff_mode_buf(buf_T *buf) int diff_move_to(int dir, int count) { linenr_T lnum = curwin->w_cursor.lnum; - int idx = diff_buf_idx(curbuf); + int idx = diff_buf_idx(curbuf, curtab); if ((idx == DB_COUNT) || (curtab->tp_first_diff == NULL)) { return FAIL; } @@ -3262,9 +3196,7 @@ int diff_move_to(int dir, int count) } // don't end up past the end of the file - if (lnum > curbuf->b_ml.ml_line_count) { - lnum = curbuf->b_ml.ml_line_count; - } + lnum = MIN(lnum, curbuf->b_ml.ml_line_count); // When the cursor didn't move at all we fail. if (lnum == curwin->w_cursor.lnum) { @@ -3284,8 +3216,8 @@ static linenr_T diff_get_corresponding_line_int(buf_T *buf1, linenr_T lnum1) { linenr_T baseline = 0; - int idx1 = diff_buf_idx(buf1); - int idx2 = diff_buf_idx(curbuf); + int idx1 = diff_buf_idx(buf1, curtab); + int idx2 = diff_buf_idx(curbuf, curtab); if ((idx1 == DB_COUNT) || (idx2 == DB_COUNT) @@ -3310,10 +3242,7 @@ static linenr_T diff_get_corresponding_line_int(buf_T *buf1, linenr_T lnum1) if ((dp->df_lnum[idx1] + dp->df_count[idx1]) > lnum1) { // Inside the diffblock baseline = lnum1 - dp->df_lnum[idx1]; - - if (baseline > dp->df_count[idx2]) { - baseline = dp->df_count[idx2]; - } + baseline = MIN(baseline, dp->df_count[idx2]); return dp->df_lnum[idx2] + baseline; } @@ -3348,10 +3277,7 @@ linenr_T diff_get_corresponding_line(buf_T *buf1, linenr_T lnum1) linenr_T lnum = diff_get_corresponding_line_int(buf1, lnum1); // don't end up past the end of the file - if (lnum > curbuf->b_ml.ml_line_count) { - return curbuf->b_ml.ml_line_count; - } - return lnum; + return MIN(lnum, curbuf->b_ml.ml_line_count); } /// For line "lnum" in the current window find the equivalent lnum in window @@ -3360,7 +3286,7 @@ linenr_T diff_lnum_win(linenr_T lnum, win_T *wp) { diff_T *dp; - int idx = diff_buf_idx(curbuf); + int idx = diff_buf_idx(curbuf, curtab); if (idx == DB_COUNT) { // safety check @@ -3386,7 +3312,7 @@ linenr_T diff_lnum_win(linenr_T lnum, win_T *wp) } // Find index for "wp". - int i = diff_buf_idx(wp->w_buffer); + int i = diff_buf_idx(wp->w_buffer, curtab); if (i == DB_COUNT) { // safety check @@ -3394,10 +3320,7 @@ linenr_T diff_lnum_win(linenr_T lnum, win_T *wp) } linenr_T n = lnum + (dp->df_lnum[i] - dp->df_lnum[idx]); - if (n > dp->df_lnum[i] + dp->df_count[i]) { - n = dp->df_lnum[i] + dp->df_count[i]; - } - return n; + return MIN(n, dp->df_lnum[i] + dp->df_count[i]); } /// Handle an ED style diff line. diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c index a358a1723a..7413d33fe4 100644 --- a/src/nvim/digraph.c +++ b/src/nvim/digraph.c @@ -12,6 +12,7 @@ #include "nvim/charset.h" #include "nvim/digraph.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds_defs.h" @@ -1864,7 +1865,7 @@ static void printdigraph(const digr_T *dp, result_T *previous) p = buf; // add a space to draw a composing char on - if (utf_iscomposing(dp->result)) { + if (utf_iscomposing_first(dp->result)) { *p++ = ' '; } p += utf_char2bytes(dp->result, p); @@ -2197,7 +2198,7 @@ bool get_keymap_str(win_T *wp, char *fmt, char *buf, int len) curwin = wp; STRCPY(buf, "b:keymap_name"); // must be writable emsg_skip++; - char *s = p = eval_to_string(buf, false); + char *s = p = eval_to_string(buf, false, false); emsg_skip--; curbuf = old_curbuf; curwin = old_curwin; diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 07944081da..3b88dd2e90 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -170,28 +170,26 @@ static void margin_columns_win(win_T *wp, int *left_col, int *right_col) // cache previous calculations depending on w_virtcol static int saved_w_virtcol; static win_T *prev_wp; + static int prev_width1; + static int prev_width2; static int prev_left_col; static int prev_right_col; - static int prev_col_off; int cur_col_off = win_col_off(wp); - int width1; - int width2; + int width1 = wp->w_width_inner - cur_col_off; + int width2 = width1 + win_col_off2(wp); if (saved_w_virtcol == wp->w_virtcol && prev_wp == wp - && prev_col_off == cur_col_off) { + && prev_width1 == width1 && prev_width2 == width2) { *right_col = prev_right_col; *left_col = prev_left_col; return; } - width1 = wp->w_width_inner - cur_col_off; - width2 = width1 + win_col_off2(wp); - *left_col = 0; *right_col = width1; - if (wp->w_virtcol >= (colnr_T)width1) { + if (wp->w_virtcol >= (colnr_T)width1 && width2 > 0) { *right_col = width1 + ((wp->w_virtcol - width1) / width2 + 1) * width2; } if (wp->w_virtcol >= (colnr_T)width1 && width2 > 0) { @@ -202,8 +200,9 @@ static void margin_columns_win(win_T *wp, int *left_col, int *right_col) prev_left_col = *left_col; prev_right_col = *right_col; prev_wp = wp; + prev_width1 = width1; + prev_width2 = width2; saved_w_virtcol = wp->w_virtcol; - prev_col_off = cur_col_off; } /// Put a single char from an UTF-8 buffer into a line buffer. @@ -465,6 +464,7 @@ static void draw_sign(bool nrcol, win_T *wp, winlinevars_T *wlv, int sign_idx, i int fill = nrcol ? number_width(wp) + 1 : SIGN_WIDTH; draw_col_fill(wlv, schar_from_ascii(' '), fill, attr); int sign_pos = wlv->off - SIGN_WIDTH - (int)nrcol; + assert(sign_pos >= 0); linebuf_char[sign_pos] = sattr.text[0]; linebuf_char[sign_pos + 1] = sattr.text[1]; } else { @@ -586,12 +586,13 @@ static void draw_statuscol(win_T *wp, winlinevars_T *wlv, linenr_T lnum, int vir char buf[MAXPATHL]; // 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 - // potentially truncated width and rebuild before drawing anything. + // width of the status column by building with the largest possible line number. + // Add potentially truncated width and rebuild before drawing anything. if (wp->w_statuscol_line_count != wp->w_nrwidth_line_count) { wp->w_statuscol_line_count = wp->w_nrwidth_line_count; set_vim_var_nr(VV_VIRTNUM, 0); - int width = build_statuscol_str(wp, wp->w_nrwidth_line_count, 0, buf, stcp); + int width = build_statuscol_str(wp, wp->w_nrwidth_line_count, + wp->w_nrwidth_line_count, buf, stcp); if (width > stcp->width) { int addwidth = MIN(width - stcp->width, MAX_STCWIDTH - stcp->width); wp->w_nrwidth += addwidth; @@ -884,9 +885,7 @@ static int get_rightmost_vcol(win_T *wp, const int *color_cols) if (color_cols) { // determine rightmost colorcolumn to possibly draw for (int i = 0; color_cols[i] >= 0; i++) { - if (ret < color_cols[i]) { - ret = color_cols[i]; - } + ret = MAX(ret, color_cols[i]); } } @@ -1156,7 +1155,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s area_highlighting = true; } VirtLines virt_lines = KV_INITIAL_VALUE; - wlv.n_virt_lines = decor_virt_lines(wp, lnum, &virt_lines, has_fold); + wlv.n_virt_lines = decor_virt_lines(wp, lnum - 1, lnum, &virt_lines, true); wlv.filler_lines += wlv.n_virt_lines; if (lnum == wp->w_topline) { wlv.filler_lines = wp->w_topfill; @@ -1421,7 +1420,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s line = ml_get_buf(wp->w_buffer, lnum); ptr = line + linecol; - if (len == 0 || (int)wp->w_cursor.col > ptr - line) { + if (len == 0 || wp->w_cursor.col > linecol) { // no bad word found at line start, don't check until end of a // word spell_hlf = HLF_COUNT; @@ -1551,7 +1550,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s // When only updating the columns and that's done, stop here. if (col_rows > 0) { - wlv_put_linebuf(wp, &wlv, wlv.off, false, bg_attr, 0); + wlv_put_linebuf(wp, &wlv, MIN(wlv.off, grid->cols), false, bg_attr, 0); // Need to update more screen lines if: // - 'statuscolumn' needs to be drawn, or // - LineNrAbove or LineNrBelow is used, or @@ -1596,6 +1595,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s // hide virt_text on text hidden by 'nowrap' or 'smoothscroll' decor_redraw_col(wp, (colnr_T)(ptr - line) - 1, wlv.off, true, &decor_state); } + if (wlv.col >= grid->cols) { + wlv.col = wlv.off = grid->cols; + goto end_check; + } } if (cul_screenline && wlv.filler_todo <= 0 @@ -1822,7 +1825,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s // If a double-width char doesn't fit display a '>' in the last column. // Don't advance the pointer but put the character at the start of the next line. - if (wlv.col >= grid->cols - 1 && utf_char2cells(mb_c) == 2) { + if (wlv.col >= grid->cols - 1 && schar_cells(mb_schar) == 2) { mb_c = '>'; mb_l = 1; (void)mb_l; @@ -1918,7 +1921,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s // If a double-width char doesn't fit display a '>' in the // last column; the character is displayed at the start of the // next line. - if (wlv.col >= grid->cols - 1 && utf_char2cells(mb_c) == 2) { + if (wlv.col >= grid->cols - 1 && schar_cells(mb_schar) == 2) { mb_schar = schar_from_ascii('>'); mb_c = '>'; mb_l = 1; @@ -2389,6 +2392,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s || (decor_conceal && decor_state.conceal_char) || wp->w_p_cole == 1) && wp->w_p_cole != 3) { + if (schar_cells(mb_schar) > 1) { + // When the first char to be concealed is double-width, + // need to advance one more virtual column. + wlv.n_extra++; + } + // First time at this concealed item: display one // character. if (has_match_conc && match_conc) { @@ -2406,12 +2415,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s mb_schar = schar_from_ascii(' '); } - if (utf_char2cells(mb_c) > 1) { - // When the first char to be concealed is double-width, - // need to advance one more virtual column. - wlv.n_extra++; - } - mb_c = schar_get_first_codepoint(mb_schar); prev_syntax_id = syntax_seqnr; @@ -2480,7 +2483,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s && mb_schar != NUL) { mb_schar = wp->w_p_lcs_chars.prec; lcs_prec_todo = NUL; - if (utf_char2cells(mb_c) > 1) { + if (schar_cells(mb_schar) > 1) { // Double-width character being overwritten by the "precedes" // character, need to fill up half the character. wlv.sc_extra = schar_from_ascii(MB_FILLER_CHAR); @@ -2554,9 +2557,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s // Highlight 'cursorcolumn' & 'colorcolumn' past end of the line. // check if line ends before left margin - if (wlv.vcol < start_col + wlv.col - win_col_off(wp)) { - wlv.vcol = start_col + wlv.col - win_col_off(wp); - } + wlv.vcol = MAX(wlv.vcol, start_col + wlv.col - win_col_off(wp)); // Get rid of the boguscols now, we want to draw until the right // edge for 'cursorcolumn'. wlv.col -= wlv.boguscols; @@ -2650,13 +2651,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s conceal_cursor_used = conceal_cursor_line(curwin); } - // When the window is too narrow draw all "@" lines. - if (leftcols_width >= wp->w_grid.cols && is_wrapped) { - win_draw_end(wp, schar_from_ascii('@'), true, wlv.row, wp->w_grid.rows, HLF_AT); - set_empty_rows(wp, wlv.row); - wlv.row = endrow; - } - break; } @@ -2730,7 +2724,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s linebuf_vcol[wlv.off] = wlv.vcol; - if (utf_char2cells(mb_c) > 1) { + if (schar_cells(mb_schar) > 1) { // Need to fill two screen columns. wlv.off++; wlv.col++; @@ -2749,7 +2743,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s wlv.off++; wlv.col++; } else if (wp->w_p_cole > 0 && is_concealing) { - bool concealed_wide = utf_char2cells(mb_c) > 1; + bool concealed_wide = schar_cells(mb_schar) > 1; wlv.skip_cells--; wlv.vcol_off_co++; @@ -2844,10 +2838,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } } +end_check: // At end of screen line and there is more to come: Display the line // so far. If there is no more to display it is caught above. if (wlv.col >= grid->cols && (!has_foldtext || virt_line_offset >= 0) - && (*ptr != NUL + && (wlv.col <= leftcols_width + || *ptr != NUL || wlv.filler_todo > 0 || (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL && lcs_eol_todo) || (wlv.n_extra != 0 && (wlv.sc_extra != NUL || *wlv.p_extra != NUL)) diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index bda0ccc870..aa5c66465b 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -65,6 +65,7 @@ #include "nvim/autocmd.h" #include "nvim/autocmd_defs.h" #include "nvim/buffer.h" +#include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/cursor.h" @@ -394,18 +395,9 @@ void screen_resize(int width, int height) void check_screensize(void) { // Limit Rows and Columns to avoid an overflow in Rows * Columns. - if (Rows < min_rows()) { - // need room for one window and command line - Rows = min_rows(); - } else if (Rows > 1000) { - Rows = 1000; - } - - if (Columns < MIN_COLUMNS) { - Columns = MIN_COLUMNS; - } else if (Columns > 10000) { - Columns = 10000; - } + // need room for one window and command line + Rows = MIN(MAX(Rows, min_rows()), 1000); + Columns = MIN(MAX(Columns, MIN_COLUMNS), 10000); } /// Return true if redrawing should currently be done. @@ -715,14 +707,17 @@ void end_search_hl(void) screen_search_hl.rm.regprog = NULL; } -static void win_redr_bordertext(win_T *wp, VirtText vt, int col) +static void win_redr_bordertext(win_T *wp, VirtText vt, int col, BorderTextType bt) { for (size_t i = 0; i < kv_size(vt);) { - int attr = 0; + int attr = -1; char *text = next_virt_text_chunk(vt, &i, &attr); if (text == NULL) { break; } + if (attr == -1) { // No highlight specified. + attr = wp->w_ns_hl_attr[bt == kBorderTextTitle ? HLF_BTITLE : HLF_BFOOTER]; + } attr = hl_apply_winblend(wp, attr); col += grid_line_puts(col, text, -1, attr); } @@ -773,7 +768,7 @@ static void win_redr_border(win_T *wp) if (wp->w_config.title) { int title_col = win_get_bordertext_col(icol, wp->w_config.title_width, wp->w_config.title_pos); - win_redr_bordertext(wp, wp->w_config.title_chunks, title_col); + win_redr_bordertext(wp, wp->w_config.title_chunks, title_col, kBorderTextTitle); } if (adj[1]) { grid_line_put_schar(icol + adj[3], chars[2], attrs[2]); @@ -809,7 +804,7 @@ static void win_redr_border(win_T *wp) if (wp->w_config.footer) { int footer_col = win_get_bordertext_col(icol, wp->w_config.footer_width, wp->w_config.footer_pos); - win_redr_bordertext(wp, wp->w_config.footer_chunks, footer_col); + win_redr_bordertext(wp, wp->w_config.footer_chunks, footer_col, kBorderTextFooter); } if (adj[1]) { grid_line_put_schar(icol + adj[3], chars[4], attrs[4]); @@ -927,13 +922,7 @@ int showmode(void) msg_ext_clear(true); } - // Don't make non-flushed message part of the showmode and reset global - // variables before flushing to to avoid recursiveness. - bool draw_mode = redraw_mode; - bool clear_cmd = clear_cmdline; - redraw_cmdline = false; - redraw_mode = false; - clear_cmdline = false; + // Don't make non-flushed message part of the showmode. msg_ext_ui_flush(); msg_grid_validate(); @@ -956,8 +945,8 @@ int showmode(void) msg_check_for_delay(false); // if the cmdline is more than one line high, erase top lines - bool need_clear = clear_cmd; - if (clear_cmd && cmdline_row < Rows - 1) { + bool need_clear = clear_cmdline; + if (clear_cmdline && cmdline_row < Rows - 1) { msg_clr_cmdline(); // will reset clear_cmdline } @@ -998,12 +987,9 @@ int showmode(void) } if (edit_submode_extra != NULL) { msg_puts_attr(" ", attr); // Add a space in between. - int sub_attr; - if (edit_submode_highl < HLF_COUNT) { - sub_attr = win_hl_attr(curwin, (int)edit_submode_highl); - } else { - sub_attr = attr; - } + int sub_attr = edit_submode_highl < HLF_COUNT + ? win_hl_attr(curwin, (int)edit_submode_highl) + : attr; msg_puts_attr(edit_submode_extra, sub_attr); } } @@ -1079,7 +1065,7 @@ int showmode(void) } mode_displayed = true; - if (need_clear || clear_cmd || draw_mode) { + if (need_clear || clear_cmdline || redraw_mode) { msg_clr_eos(); } msg_didout = false; // overwrite this message @@ -1088,10 +1074,10 @@ int showmode(void) msg_no_more = false; lines_left = save_lines_left; need_wait_return = nwr_save; // never ask for hit-return for this - } else if (clear_cmd && msg_silent == 0) { + } else if (clear_cmdline && msg_silent == 0) { // Clear the whole command line. Will reset "clear_cmdline". msg_clr_cmdline(); - } else if (draw_mode) { + } else if (redraw_mode) { msg_pos_mode(); msg_clr_eos(); } @@ -1114,6 +1100,10 @@ int showmode(void) grid_line_flush(); } + redraw_cmdline = false; + redraw_mode = false; + clear_cmdline = false; + return length; } @@ -1544,6 +1534,7 @@ static void win_update(win_T *wp) // Force redraw when width of 'number' or 'relativenumber' column changes. if (wp->w_nrwidth != nrwidth_new) { type = UPD_NOT_VALID; + changed_line_abv_curs_win(wp); wp->w_nrwidth = nrwidth_new; } else { // Set mod_top to the first line that needs displaying because of @@ -1561,9 +1552,7 @@ static void win_update(win_T *wp) // in a pattern match. if (syntax_present(wp)) { mod_top -= buf->b_s.b_syn_sync_linebreaks; - if (mod_top < 1) { - mod_top = 1; - } + mod_top = MAX(mod_top, 1); } } if (mod_bot == 0 || mod_bot < buf->b_mod_bot) { @@ -1590,6 +1579,18 @@ static void win_update(win_T *wp) } } } + + if (search_hl_has_cursor_lnum > 0) { + // CurSearch was used last time, need to redraw the line with it to + // avoid having two matches highlighted with CurSearch. + if (mod_top == 0 || mod_top > search_hl_has_cursor_lnum) { + mod_top = search_hl_has_cursor_lnum; + } + if (mod_bot == 0 || mod_bot < search_hl_has_cursor_lnum + 1) { + mod_bot = search_hl_has_cursor_lnum + 1; + } + } + if (mod_top != 0 && hasAnyFolding(wp)) { // A change in a line can cause lines above it to become folded or // unfolded. Find the top most buffer line that may be affected. @@ -1620,17 +1621,13 @@ static void win_update(win_T *wp) } hasFolding(wp, mod_top, &mod_top, NULL); - if (mod_top > lnumt) { - mod_top = lnumt; - } + mod_top = MIN(mod_top, lnumt); // Now do the same for the bottom line (one above mod_bot). mod_bot--; hasFolding(wp, mod_bot, NULL, &mod_bot); mod_bot++; - if (mod_bot < lnumb) { - mod_bot = lnumb; - } + mod_bot = MAX(mod_bot, lnumb); } // When a change starts above w_topline and the end is below @@ -1648,6 +1645,7 @@ static void win_update(win_T *wp) wp->w_redraw_top = 0; // reset for next time wp->w_redraw_bot = 0; + search_hl_has_cursor_lnum = 0; // When only displaying the lines at the top, set top_end. Used when // window has scrolled down for msg_scrolled. @@ -1807,8 +1805,10 @@ static void win_update(win_T *wp) // Correct the first entry for filler lines at the top // when it won't get updated below. if (win_may_fill(wp) && bot_start > 0) { - wp->w_lines[0].wl_size = (uint16_t)(plines_win_nofill(wp, wp->w_topline, true) - + wp->w_topfill); + int n = plines_win_nofill(wp, wp->w_topline, false) + wp->w_topfill + - adjust_plines_for_skipcol(wp); + n = MIN(n, wp->w_height_inner); + wp->w_lines[0].wl_size = (uint16_t)n; } } } @@ -1849,18 +1849,8 @@ static void win_update(win_T *wp) to = curwin->w_cursor.lnum; } // redraw more when the cursor moved as well - if (wp->w_old_cursor_lnum < from) { - from = wp->w_old_cursor_lnum; - } - if (wp->w_old_cursor_lnum > to) { - to = wp->w_old_cursor_lnum; - } - if (wp->w_old_visual_lnum < from) { - from = wp->w_old_visual_lnum; - } - if (wp->w_old_visual_lnum > to) { - to = wp->w_old_visual_lnum; - } + from = MIN(MIN(from, wp->w_old_cursor_lnum), wp->w_old_visual_lnum); + to = MAX(MAX(to, wp->w_old_cursor_lnum), wp->w_old_visual_lnum); } else { // Find the line numbers that need to be updated: The lines // between the old cursor position and the current cursor @@ -1882,15 +1872,8 @@ static void win_update(win_T *wp) && wp->w_old_visual_lnum != 0) { from = wp->w_old_visual_lnum; } - if (wp->w_old_visual_lnum > to) { - to = wp->w_old_visual_lnum; - } - if (VIsual.lnum < from) { - from = VIsual.lnum; - } - if (VIsual.lnum > to) { - to = VIsual.lnum; - } + to = MAX(MAX(to, wp->w_old_visual_lnum), VIsual.lnum); + from = MIN(from, VIsual.lnum); } } @@ -1925,9 +1908,7 @@ static void win_update(win_T *wp) pos.col = (colnr_T)strlen(ml_get_buf(wp->w_buffer, pos.lnum)); getvvcol(wp, &pos, NULL, NULL, &t); - if (toc < t) { - toc = t; - } + toc = MAX(toc, t); } toc++; } else { @@ -1937,12 +1918,8 @@ static void win_update(win_T *wp) if (fromc != wp->w_old_cursor_fcol || toc != wp->w_old_cursor_lcol) { - if (from > VIsual.lnum) { - from = VIsual.lnum; - } - if (to < VIsual.lnum) { - to = VIsual.lnum; - } + from = MIN(from, VIsual.lnum); + to = MAX(to, VIsual.lnum); } wp->w_old_cursor_fcol = fromc; wp->w_old_cursor_lcol = toc; @@ -1959,19 +1936,13 @@ static void win_update(win_T *wp) } // There is no need to update lines above the top of the window. - if (from < wp->w_topline) { - from = wp->w_topline; - } + from = MAX(from, wp->w_topline); // If we know the value of w_botline, use it to restrict the update to // the lines that are visible in the window. if (wp->w_valid & VALID_BOTLINE) { - if (from >= wp->w_botline) { - from = wp->w_botline - 1; - } - if (to >= wp->w_botline) { - to = wp->w_botline - 1; - } + from = MIN(from, wp->w_botline - 1); + to = MIN(to, wp->w_botline - 1); } // Find the minimal part to be updated. @@ -2159,11 +2130,9 @@ static void win_update(win_T *wp) if (hasFolding(wp, l, NULL, &l)) { new_rows++; } else if (l == wp->w_topline) { - int n = plines_win_nofill(wp, l, false) + wp->w_topfill; - n -= adjust_plines_for_skipcol(wp); - if (n > wp->w_height_inner) { - n = wp->w_height_inner; - } + int n = plines_win_nofill(wp, l, false) + wp->w_topfill + - adjust_plines_for_skipcol(wp); + n = MIN(n, wp->w_height_inner); new_rows += n; } else { new_rows += plines_win(wp, l, true); @@ -2228,16 +2197,12 @@ static void win_update(win_T *wp) x += wp->w_lines[j++].wl_size; i++; } - if (bot_start > x) { - bot_start = x; - } + bot_start = MIN(bot_start, x); } else { // j > i // move entries in w_lines[] downwards j -= i; wp->w_lines_valid += (linenr_T)j; - if (wp->w_lines_valid > wp->w_grid.rows) { - wp->w_lines_valid = wp->w_grid.rows; - } + wp->w_lines_valid = MIN(wp->w_lines_valid, wp->w_grid.rows); for (i = wp->w_lines_valid; i - j >= idx; i--) { wp->w_lines[i] = wp->w_lines[i - j]; } @@ -2369,9 +2334,7 @@ redr_statuscol: wp->w_last_cursor_lnum_rnu = wp->w_p_rnu ? wp->w_cursor.lnum : 0; - if (idx > wp->w_lines_valid) { - wp->w_lines_valid = idx; - } + wp->w_lines_valid = MAX(wp->w_lines_valid, idx); // Let the syntax stuff know we stop parsing here. if (syntax_last_parsed != 0 && syntax_present(wp)) { @@ -2492,10 +2455,12 @@ redr_statuscol: recursive = true; curwin->w_valid &= ~VALID_TOPLINE; update_topline(curwin); // may invalidate w_botline again + // New redraw either due to updated topline or reset skipcol. if (must_redraw != 0) { // Don't update for changes in buffer again. int mod_set = curbuf->b_mod_set; curbuf->b_mod_set = false; + curs_columns(curwin, true); win_update(curwin); must_redraw = 0; curbuf->b_mod_set = mod_set; @@ -2586,10 +2551,7 @@ int compute_foldcolumn(win_T *wp, int col) int wmw = wp == curwin && p_wmw == 0 ? 1 : (int)p_wmw; int wwidth = wp->w_grid.cols; - if (fdc > wwidth - (col + wmw)) { - fdc = wwidth - (col + wmw); - } - return fdc; + return MIN(fdc, wwidth - (col + wmw)); } /// Return the width of the 'number' and 'relativenumber' column. @@ -2626,9 +2588,7 @@ int number_width(win_T *wp) } while (lnum > 0); // 'numberwidth' gives the minimal width plus one - if (n < wp->w_p_nuw - 1) { - n = (int)wp->w_p_nuw - 1; - } + n = MAX(n, (int)wp->w_p_nuw - 1); // If 'signcolumn' is set to 'number' and there is a sign to display, then // the minimal width for the number column is 2. @@ -2653,9 +2613,7 @@ void redraw_later(win_T *wp, int type) if (type >= UPD_NOT_VALID) { wp->w_lines_valid = 0; } - if (must_redraw < type) { // must_redraw is the maximum of all windows - must_redraw = type; - } + must_redraw = MAX(must_redraw, type); // must_redraw is the maximum of all windows } } @@ -2673,8 +2631,8 @@ void redraw_all_later(int type) /// or it is currently not allowed. void set_must_redraw(int type) { - if (!redraw_not_allowed && must_redraw < type) { - must_redraw = type; + if (!redraw_not_allowed) { + must_redraw = MAX(must_redraw, type); } } diff --git a/src/nvim/drawscreen.h b/src/nvim/drawscreen.h index f804345bca..36ba8099fd 100644 --- a/src/nvim/drawscreen.h +++ b/src/nvim/drawscreen.h @@ -25,7 +25,11 @@ EXTERN bool updating_screen INIT( = false); /// must_redraw to be set. EXTERN bool redraw_not_allowed INIT( = false); -EXTERN match_T screen_search_hl INIT( = { 0 }); ///< used for 'hlsearch' highlight matching +/// used for 'hlsearch' highlight matching +EXTERN match_T screen_search_hl INIT( = { 0 }); + +/// last lnum where CurSearch was displayed +EXTERN linenr_T search_hl_has_cursor_lnum INIT( = 0); #define W_ENDCOL(wp) ((wp)->w_wincol + (wp)->w_width) #define W_ENDROW(wp) ((wp)->w_winrow + (wp)->w_height) diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 220b92d099..f06dc124f0 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -18,6 +18,7 @@ #include "nvim/digraph.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds_defs.h" @@ -135,6 +136,8 @@ static TriState dont_sync_undo = kFalse; // CTRL-G U prevents syncing undo static linenr_T o_lnum = 0; +static kvec_t(char) replace_stack = KV_INITIAL_VALUE; + static void insert_enter(InsertState *s) { s->did_backspace = true; @@ -270,11 +273,7 @@ static void insert_enter(InsertState *s) if (restart_edit != 0 && stuff_empty()) { // After a paste we consider text typed to be part of the insert for // the pasted text. You can backspace over the pasted text too. - if (where_paste_started.lnum) { - arrow_used = false; - } else { - arrow_used = true; - } + arrow_used = where_paste_started.lnum == 0; restart_edit = 0; // If the cursor was after the end-of-line before the CTRL-O and it is @@ -467,13 +466,15 @@ static int insert_check(VimState *state) && !curwin->w_p_sms && !s->did_backspace && curwin->w_topline == s->old_topline - && curwin->w_topfill == s->old_topfill) { + && curwin->w_topfill == s->old_topfill + && s->count <= 1) { s->mincol = curwin->w_wcol; validate_cursor_col(curwin); if (curwin->w_wcol < s->mincol - tabstop_at(get_nolist_virtcol(), curbuf->b_p_ts, - curbuf->b_p_vts_array) + curbuf->b_p_vts_array, + false) && curwin->w_wrow == curwin->w_height_inner - 1 - get_scrolloff_value(curwin) && (curwin->w_cursor.lnum != curwin->w_topline || curwin->w_topfill > 0)) { @@ -488,11 +489,15 @@ static int insert_check(VimState *state) } // May need to adjust w_topline to show the cursor. - update_topline(curwin); + if (s->count <= 1) { + update_topline(curwin); + } s->did_backspace = false; - validate_cursor(curwin); // may set must_redraw + if (s->count <= 1) { + validate_cursor(curwin); // may set must_redraw + } // Redraw the display when no characters are waiting. // Also shows mode, ruler and positions cursor. @@ -506,7 +511,9 @@ static int insert_check(VimState *state) do_check_cursorbind(); } - update_curswant(); + if (s->count <= 1) { + update_curswant(); + } s->old_topline = curwin->w_topline; s->old_topfill = curwin->w_topfill; @@ -900,6 +907,10 @@ static int insert_handle_key(InsertState *s) case K_IGNORE: // Something mapped to nothing break; + case K_PASTE_START: + paste_repeat(1); + goto check_pum; + case K_EVENT: // some event state_handle_k_event(); // If CTRL-G U was used apply it to the next typed key. @@ -1539,9 +1550,7 @@ static void init_prompt(int cmdchar_todo) if (cmdchar_todo == 'A') { coladvance(curwin, MAXCOL); } - if (curwin->w_cursor.col < (colnr_T)strlen(prompt)) { - curwin->w_cursor.col = (colnr_T)strlen(prompt); - } + curwin->w_cursor.col = MAX(curwin->w_cursor.col, (colnr_T)strlen(prompt)); // Make sure the cursor is in a valid position. check_cursor(curwin); } @@ -1576,7 +1585,7 @@ void edit_unputchar(void) /// text. Only works when cursor is in the line that changes. void display_dollar(colnr_T col_arg) { - colnr_T col = col_arg < 0 ? 0 : col_arg; + colnr_T col = MAX(col_arg, 0); if (!redrawing()) { return; @@ -1615,9 +1624,8 @@ void undisplay_dollar(void) /// type == INDENT_SET set indent to "amount" /// /// @param round if true, round the indent to 'shiftwidth' (only with _INC and _Dec). -/// @param replaced replaced character, put on replace stack /// @param call_changed_bytes call changed_bytes() -void change_indent(int type, int amount, int round, int replaced, bool call_changed_bytes) +void change_indent(int type, int amount, int round, bool call_changed_bytes) { int insstart_less; // reduction for Insstart.col colnr_T orig_col = 0; // init for GCC @@ -1734,12 +1742,7 @@ void change_indent(int type, int amount, int round, int replaced, bool call_chan } curwin->w_p_list = save_p_list; - - if (new_cursor_col <= 0) { - curwin->w_cursor.col = 0; - } else { - curwin->w_cursor.col = (colnr_T)new_cursor_col; - } + curwin->w_cursor.col = MAX(0, (colnr_T)new_cursor_col); curwin->w_set_curswant = true; changed_cline_bef_curs(curwin); @@ -1769,12 +1772,8 @@ void change_indent(int type, int amount, int round, int replaced, bool call_chan replace_join(0); // remove a NUL from the replace stack start_col--; } - while (start_col < (int)curwin->w_cursor.col || replaced) { - replace_push(NUL); - if (replaced) { - replace_push(replaced); - replaced = NUL; - } + while (start_col < (int)curwin->w_cursor.col) { + replace_push_nul(); start_col++; } } @@ -2025,7 +2024,6 @@ static void insert_special(int c, int allow_modmask, int ctrlv) // '0' and '^' are special, because they can be followed by CTRL-D. #define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^') -/// /// "flags": INSCHAR_FORMAT - force formatting /// INSCHAR_CTRLV - char typed just after CTRL-V /// INSCHAR_NO_FEX - don't use 'formatexpr' @@ -2328,7 +2326,7 @@ int stop_arrow(void) static void stop_insert(pos_T *end_insert_pos, int esc, int nomove) { stop_redo_ins(); - replace_flush(); // abandon replace stack + kv_destroy(replace_stack); // abandon replace stack (reinitializes) // Save the inserted text for later redo with ^@ and CTRL-A. // Don't do it when "restart_edit" was set and nothing was inserted, @@ -2606,9 +2604,7 @@ void cursor_up_inner(win_T *wp, linenr_T n) hasFolding(wp, lnum, &lnum, NULL); } } - if (lnum < 1) { - lnum = 1; - } + lnum = MAX(lnum, 1); } else { lnum -= n; } @@ -2649,7 +2645,6 @@ void cursor_down_inner(win_T *wp, int n) // count each sequence of folded lines as one logical line while (n--) { - // Move to last line of fold, will fail if it's the end-of-file. if (hasFoldingWin(wp, lnum, NULL, &last, true, NULL)) { lnum = last + 1; } else { @@ -2659,9 +2654,7 @@ void cursor_down_inner(win_T *wp, int n) break; } } - if (lnum > line_count) { - lnum = line_count; - } + lnum = MIN(lnum, line_count); } else { lnum += (linenr_T)n; } @@ -2672,8 +2665,10 @@ void cursor_down_inner(win_T *wp, int n) /// @param upd_topline When true: update topline int cursor_down(int n, bool upd_topline) { - // This fails if the cursor is already in the last line. - if (n > 0 && curwin->w_cursor.lnum >= curwin->w_buffer->b_ml.ml_line_count) { + linenr_T lnum = curwin->w_cursor.lnum; + // This fails if the cursor is already in the last (folded) line. + hasFoldingWin(curwin, lnum, NULL, &lnum, true, NULL); + if (n > 0 && lnum >= curwin->w_buffer->b_ml.ml_line_count) { return FAIL; } cursor_down_inner(curwin, n); @@ -2808,55 +2803,51 @@ static bool echeck_abbr(int c) // that the NL replaced. The extra one stores the characters after the cursor // that were deleted (always white space). -static uint8_t *replace_stack = NULL; -static ssize_t replace_stack_nr = 0; // next entry in replace stack -static ssize_t replace_stack_len = 0; // max. number of entries - /// Push character that is replaced onto the replace stack. /// /// replace_offset is normally 0, in which case replace_push will add a new /// character at the end of the stack. If replace_offset is not 0, that many /// characters will be left on the stack above the newly inserted character. /// -/// @param c character that is replaced (NUL is none) -void replace_push(int c) +/// @param str character that is replaced (NUL is none) +/// @param len length of character in bytes +void replace_push(char *str, size_t len) { - if (replace_stack_nr < replace_offset) { // nothing to do + // TODO(bfredl): replace_offset is suss af, if we don't need it, this + // function is just kv_concat() :p + if (kv_size(replace_stack) < (size_t)replace_offset) { // nothing to do return; } - if (replace_stack_len <= replace_stack_nr) { - replace_stack_len += 50; - replace_stack = xrealloc(replace_stack, (size_t)replace_stack_len); - } - uint8_t *p = replace_stack + replace_stack_nr - replace_offset; + kv_ensure_space(replace_stack, len); + + char *p = replace_stack.items + kv_size(replace_stack) - replace_offset; if (replace_offset) { - memmove(p + 1, p, (size_t)replace_offset); + memmove(p + len, p, (size_t)replace_offset); } - *p = (uint8_t)c; - replace_stack_nr++; + memcpy(p, str, len); + kv_size(replace_stack) += len; } -/// Push a character onto the replace stack. Handles a multi-byte character in -/// reverse byte order, so that the first byte is popped off first. -/// -/// @return the number of bytes done (includes composing characters). -int replace_push_mb(char *p) +/// push NUL as separator between entries in the stack +void replace_push_nul(void) { - int l = utfc_ptr2len(p); - - for (int j = l - 1; j >= 0; j--) { - replace_push(p[j]); - } - return l; + replace_push("", 1); } -/// Pop one item from the replace stack. +/// Check top of replace stack, pop it if it was NUL +/// +/// when a non-NUL byte is found, use mb_replace_pop_ins() to +/// pop one complete multibyte character. /// -/// @return -1 if stack is empty, replaced character or NUL otherwise -static int replace_pop(void) +/// @return -1 if stack is empty, last byte of char or NUL otherwise +static int replace_pop_if_nul(void) { - return (replace_stack_nr == 0) ? -1 : (int)replace_stack[--replace_stack_nr]; + int ch = (kv_size(replace_stack)) ? (uint8_t)kv_A(replace_stack, kv_size(replace_stack) - 1) : -1; + if (ch == NUL) { + kv_size(replace_stack)--; + } + return ch; } /// Join the top two items on the replace stack. This removes to "off"'th NUL @@ -2865,11 +2856,11 @@ static int replace_pop(void) /// @param off offset for which NUL to remove static void replace_join(int off) { - for (ssize_t i = replace_stack_nr; --i >= 0;) { - if (replace_stack[i] == NUL && off-- <= 0) { - replace_stack_nr--; - memmove(replace_stack + i, replace_stack + i + 1, - (size_t)(replace_stack_nr - i)); + for (ssize_t i = (ssize_t)kv_size(replace_stack); --i >= 0;) { + if (kv_A(replace_stack, i) == NUL && off-- <= 0) { + kv_size(replace_stack)--; + memmove(&kv_A(replace_stack, i), &kv_A(replace_stack, i + 1), + (kv_size(replace_stack) - (size_t)i)); return; } } @@ -2879,70 +2870,25 @@ static void replace_join(int off) /// before the cursor. Can only be used in MODE_REPLACE or MODE_VREPLACE state. static void replace_pop_ins(void) { - int cc; int oldState = State; State = MODE_NORMAL; // don't want MODE_REPLACE here - while ((cc = replace_pop()) > 0) { - mb_replace_pop_ins(cc); + while ((replace_pop_if_nul()) > 0) { + mb_replace_pop_ins(); dec_cursor(); } State = oldState; } -// Insert bytes popped from the replace stack. "cc" is the first byte. If it -// indicates a multi-byte char, pop the other bytes too. -static void mb_replace_pop_ins(int cc) -{ - int n; - uint8_t buf[MB_MAXBYTES + 1]; - - if ((n = MB_BYTE2LEN(cc)) > 1) { - buf[0] = (uint8_t)cc; - for (int i = 1; i < n; i++) { - buf[i] = (uint8_t)replace_pop(); - } - ins_bytes_len((char *)buf, (size_t)n); - } else { - ins_char(cc); - } - - // Handle composing chars. - while (true) { - int c = replace_pop(); - if (c == -1) { // stack empty - break; - } - if ((n = MB_BYTE2LEN(c)) == 1) { - // Not a multi-byte char, put it back. - replace_push(c); - break; - } - - buf[0] = (uint8_t)c; - assert(n > 1); - for (int i = 1; i < n; i++) { - buf[i] = (uint8_t)replace_pop(); - } - if (utf_iscomposing(utf_ptr2char((char *)buf))) { - ins_bytes_len((char *)buf, (size_t)n); - } else { - // Not a composing char, put it back. - for (int i = n - 1; i >= 0; i--) { - replace_push(buf[i]); - } - break; - } - } -} - -// make the replace stack empty -// (called when exiting replace mode) -static void replace_flush(void) +/// Insert multibyte char popped from the replace stack. +/// +/// caller must already have checked the top of the stack is not NUL!! +static void mb_replace_pop_ins(void) { - XFREE_CLEAR(replace_stack); - replace_stack_len = 0; - replace_stack_nr = 0; + int len = utf_head_off(&kv_A(replace_stack, 0), + &kv_A(replace_stack, kv_size(replace_stack) - 1)) + 1; + kv_size(replace_stack) -= (size_t)len; + ins_bytes_len(&kv_A(replace_stack, kv_size(replace_stack)), (size_t)len); } // Handle doing a BS for one character. @@ -2957,7 +2903,7 @@ static void replace_do_bs(int limit_col) colnr_T start_vcol; const int l_State = State; - int cc = replace_pop(); + int cc = replace_pop_if_nul(); if (cc > 0) { int orig_len = 0; int orig_vcols = 0; @@ -2971,7 +2917,6 @@ static void replace_do_bs(int limit_col) if (l_State & VREPLACE_FLAG) { orig_len = get_cursor_pos_len(); } - replace_push(cc); replace_pop_ins(); if (l_State & VREPLACE_FLAG) { @@ -3630,9 +3575,9 @@ static void ins_shift(int c, int lastc) if (lastc == '^') { old_indent = get_indent(); // remember curr. indent } - change_indent(INDENT_SET, 0, true, 0, true); + change_indent(INDENT_SET, 0, true, true); } else { - change_indent(c == Ctrl_D ? INDENT_DEC : INDENT_INC, 0, true, 0, true); + change_indent(c == Ctrl_D ? INDENT_DEC : INDENT_INC, 0, true, true); } if (did_ai && *skipwhite(get_cursor_line_ptr()) != NUL) { @@ -3751,7 +3696,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) // cc >= 0: NL was replaced, put original characters back cc = -1; if (State & REPLACE_FLAG) { - cc = replace_pop(); // returns -1 if NL was inserted + cc = replace_pop_if_nul(); // returns -1 if NL was inserted } // In replace mode, in the line we started replacing, we only move the // cursor. @@ -3797,9 +3742,9 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) // restore characters (blanks) deleted after cursor while (cc > 0) { colnr_T save_col = curwin->w_cursor.col; - mb_replace_pop_ins(cc); + mb_replace_pop_ins(); curwin->w_cursor.col = save_col; - cc = replace_pop(); + cc = replace_pop_if_nul(); } // restore the characters that NL replaced replace_pop_ins(); @@ -3856,7 +3801,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) space_sci = sci; space_vcol = vcol; } - vcol += charsize_nowrap(curbuf, use_ts, vcol, sci.chr.value); + vcol += charsize_nowrap(curbuf, sci.ptr, use_ts, vcol, sci.chr.value); sci = utfc_next(sci); prev_space = cur_space; } @@ -3872,7 +3817,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) // Find the position to stop backspacing. // Use charsize_nowrap() so that virtual text and wrapping are ignored. while (true) { - int size = charsize_nowrap(curbuf, use_ts, space_vcol, space_sci.chr.value); + int size = charsize_nowrap(curbuf, space_sci.ptr, use_ts, space_vcol, space_sci.chr.value); if (space_vcol + size > want_vcol) { break; } @@ -3908,7 +3853,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) } else { ins_str(" "); if ((State & REPLACE_FLAG)) { - replace_push(NUL); + replace_push_nul(); } } } @@ -3943,7 +3888,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) bool has_composing = false; if (p_deco) { char *p0 = get_cursor_pos_ptr(); - has_composing = utf_composinglike(p0, p0 + utf_ptr2len(p0)); + has_composing = utf_composinglike(p0, p0 + utf_ptr2len(p0), NULL); } del_char(false); // If there are combining characters and 'delcombine' is set @@ -4318,7 +4263,7 @@ static bool ins_tab(void) } else { ins_str(" "); if (State & REPLACE_FLAG) { // no char replaced - replace_push(NUL); + replace_push_nul(); } } } @@ -4419,18 +4364,30 @@ static bool ins_tab(void) // Delete following spaces. int i = cursor->col - fpos.col; if (i > 0) { - STRMOVE(ptr, ptr + i); + if (!(State & VREPLACE_FLAG)) { + char *newp = xmalloc((size_t)(curbuf->b_ml.ml_line_len - i)); + ptrdiff_t col = ptr - curbuf->b_ml.ml_line_ptr; + if (col > 0) { + memmove(newp, ptr - col, (size_t)col); + } + memmove(newp + col, ptr + i, (size_t)(curbuf->b_ml.ml_line_len - col - i)); + if (curbuf->b_ml.ml_flags & (ML_LINE_DIRTY | ML_ALLOCATED)) { + xfree(curbuf->b_ml.ml_line_ptr); + } + curbuf->b_ml.ml_line_ptr = newp; + curbuf->b_ml.ml_line_len -= i; + curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY; + inserted_bytes(fpos.lnum, change_col, + cursor->col - change_col, fpos.col - change_col); + } else { + STRMOVE(ptr, ptr + i); + } // correct replace stack. if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) { for (temp = i; --temp >= 0;) { replace_join(repl_off); } } - if (!(State & VREPLACE_FLAG)) { - curbuf->b_ml.ml_line_len -= i; - inserted_bytes(fpos.lnum, change_col, - cursor->col - change_col, fpos.col - change_col); - } } cursor->col -= i; @@ -4473,7 +4430,7 @@ bool ins_eol(int c) // character under the cursor. Only push a NUL on the replace stack, // nothing to put back when the NL is deleted. if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) { - replace_push(NUL); + replace_push_nul(); } // In MODE_VREPLACE state, a NL replaces the rest of the line, and starts @@ -4674,7 +4631,7 @@ static void ins_try_si(int c) i = get_indent(); curwin->w_cursor = old_pos; if (State & VREPLACE_FLAG) { - change_indent(INDENT_SET, i, false, NUL, true); + change_indent(INDENT_SET, i, false, true); } else { set_indent(i, SIN_CHANGED); } @@ -4712,9 +4669,7 @@ static void ins_try_si(int c) } // Adjust ai_col, the char at this position can be deleted. - if (ai_col > curwin->w_cursor.col) { - ai_col = curwin->w_cursor.col; - } + ai_col = MIN(ai_col, curwin->w_cursor.col); } // Get the value that w_virtcol would have when 'list' is off. diff --git a/src/nvim/errors.h b/src/nvim/errors.h new file mode 100644 index 0000000000..39095db952 --- /dev/null +++ b/src/nvim/errors.h @@ -0,0 +1,193 @@ +#pragma once + +#include "nvim/gettext_defs.h" +#include "nvim/macros_defs.h" + +// +// Shared error messages. Excludes errors only used once and debugging messages. +// +// uncrustify:off +EXTERN const char e_abort[] INIT(= N_("E470: Command aborted")); +EXTERN const char e_afterinit[] INIT(= N_("E905: Cannot set this option after startup")); +EXTERN const char e_api_spawn_failed[] INIT(= N_("E903: Could not spawn API job")); +EXTERN const char e_argreq[] INIT(= N_("E471: Argument required")); +EXTERN const char e_backslash[] INIT(= N_("E10: \\ should be followed by /, ? or &")); +EXTERN const char e_cmdwin[] INIT(= N_("E11: Invalid in command-line window; <CR> executes, CTRL-C quits")); +EXTERN const char e_curdir[] INIT(= N_("E12: Command not allowed in secure mode in current dir or tag search")); +EXTERN const char e_invalid_buffer_name_str[] INIT(= N_("E158: Invalid buffer name: %s")); +EXTERN const char e_command_too_recursive[] INIT(= N_("E169: Command too recursive")); +EXTERN const char e_buffer_is_not_loaded[] INIT(= N_("E681: Buffer is not loaded")); +EXTERN const char e_endif[] INIT(= N_("E171: Missing :endif")); +EXTERN const char e_endtry[] INIT(= N_("E600: Missing :endtry")); +EXTERN const char e_endwhile[] INIT(= N_("E170: Missing :endwhile")); +EXTERN const char e_endfor[] INIT(= N_("E170: Missing :endfor")); +EXTERN const char e_while[] INIT(= N_("E588: :endwhile without :while")); +EXTERN const char e_for[] INIT(= N_("E588: :endfor without :for")); +EXTERN const char e_exists[] INIT(= N_("E13: File exists (add ! to override)")); +EXTERN const char e_failed[] INIT(= N_("E472: Command failed")); +EXTERN const char e_internal[] INIT(= N_("E473: Internal error")); +EXTERN const char e_intern2[] INIT(= N_("E685: Internal error: %s")); +EXTERN const char e_interr[] INIT(= N_("Interrupted")); +EXTERN const char e_invarg[] INIT(= N_("E474: Invalid argument")); +EXTERN const char e_invarg2[] INIT(= N_("E475: Invalid argument: %s")); +EXTERN const char e_invargval[] INIT(= N_("E475: Invalid value for argument %s")); +EXTERN const char e_invargNval[] INIT(= N_("E475: Invalid value for argument %s: %s")); +EXTERN const char e_duparg2[] INIT(= N_("E983: Duplicate argument: %s")); +EXTERN const char e_invexpr2[] INIT(= N_("E15: Invalid expression: \"%s\"")); +EXTERN const char e_invrange[] INIT(= N_("E16: Invalid range")); +EXTERN const char e_invcmd[] INIT(= N_("E476: Invalid command")); +EXTERN const char e_isadir2[] INIT(= N_("E17: \"%s\" is a directory")); +EXTERN const char e_no_spell[] INIT(= N_("E756: Spell checking is not possible")); +EXTERN const char e_invchan[] INIT(= N_("E900: Invalid channel id")); +EXTERN const char e_invchanjob[] INIT(= N_("E900: Invalid channel id: not a job")); +EXTERN const char e_jobtblfull[] INIT(= N_("E901: Job table is full")); +EXTERN const char e_jobspawn[] INIT(= N_("E903: Process failed to start: %s: \"%s\"")); +EXTERN const char e_channotpty[] INIT(= N_("E904: channel is not a pty")); +EXTERN const char e_stdiochan2[] INIT(= N_("E905: Couldn't open stdio channel: %s")); +EXTERN const char e_invstream[] INIT(= N_("E906: invalid stream for channel")); +EXTERN const char e_invstreamrpc[] INIT(= N_("E906: invalid stream for rpc channel, use 'rpc'")); +EXTERN const char e_streamkey[] INIT(= N_("E5210: dict key '%s' already set for buffered stream in channel %" PRIu64)); +EXTERN const char e_libcall[] INIT(= N_("E364: Library call failed for \"%s()\"")); +EXTERN const char e_fsync[] INIT(= N_("E667: Fsync failed: %s")); +EXTERN const char e_mkdir[] INIT(= N_("E739: Cannot create directory %s: %s")); +EXTERN const char e_markinval[] INIT(= N_("E19: Mark has invalid line number")); +EXTERN const char e_marknotset[] INIT(= N_("E20: Mark not set")); +EXTERN const char e_modifiable[] INIT(= N_("E21: Cannot make changes, 'modifiable' is off")); +EXTERN const char e_nesting[] INIT(= N_("E22: Scripts nested too deep")); +EXTERN const char e_noalt[] INIT(= N_("E23: No alternate file")); +EXTERN const char e_noabbr[] INIT(= N_("E24: No such abbreviation")); +EXTERN const char e_nobang[] INIT(= N_("E477: No ! allowed")); +EXTERN const char e_nogroup[] INIT(= N_("E28: No such highlight group name: %s")); +EXTERN const char e_noinstext[] INIT(= N_("E29: No inserted text yet")); +EXTERN const char e_nolastcmd[] INIT(= N_("E30: No previous command line")); +EXTERN const char e_nomap[] INIT(= N_("E31: No such mapping")); +EXTERN const char e_nomatch[] INIT(= N_("E479: No match")); +EXTERN const char e_nomatch2[] INIT(= N_("E480: No match: %s")); +EXTERN const char e_noname[] INIT(= N_("E32: No file name")); +EXTERN const char e_nopresub[] INIT(= N_("E33: No previous substitute regular expression")); +EXTERN const char e_noprev[] INIT(= N_("E34: No previous command")); +EXTERN const char e_noprevre[] INIT(= N_("E35: No previous regular expression")); +EXTERN const char e_norange[] INIT(= N_("E481: No range allowed")); +EXTERN const char e_noroom[] INIT(= N_("E36: Not enough room")); +EXTERN const char e_notmp[] INIT(= N_("E483: Can't get temp file name")); +EXTERN const char e_notopen[] INIT(= N_("E484: Can't open file %s")); +EXTERN const char e_notopen_2[] INIT(= N_("E484: Can't open file %s: %s")); +EXTERN const char e_notread[] INIT(= N_("E485: Can't read file %s")); +EXTERN const char e_null[] INIT(= N_("E38: Null argument")); +EXTERN const char e_number_exp[] INIT(= N_("E39: Number expected")); +EXTERN const char e_openerrf[] INIT(= N_("E40: Can't open errorfile %s")); +EXTERN const char e_outofmem[] INIT(= N_("E41: Out of memory!")); +EXTERN const char e_patnotf[] INIT(= N_("Pattern not found")); +EXTERN const char e_patnotf2[] INIT(= N_("E486: Pattern not found: %s")); +EXTERN const char e_positive[] INIT(= N_("E487: Argument must be positive")); +EXTERN const char e_prev_dir[] INIT(= N_("E459: Cannot go back to previous directory")); + +EXTERN const char e_no_errors[] INIT(= N_("E42: No Errors")); +EXTERN const char e_loclist[] INIT(= N_("E776: No location list")); +EXTERN const char e_re_damg[] INIT(= N_("E43: Damaged match string")); +EXTERN const char e_re_corr[] INIT(= N_("E44: Corrupted regexp program")); +EXTERN const char e_readonly[] INIT(= N_("E45: 'readonly' option is set (add ! to override)")); +EXTERN const char e_letwrong[] INIT(= N_("E734: Wrong variable type for %s=")); +EXTERN const char e_illvar[] INIT(= N_("E461: Illegal variable name: %s")); +EXTERN const char e_cannot_mod[] INIT(= N_("E995: Cannot modify existing variable")); +EXTERN const char e_readonlyvar[] INIT(= N_("E46: Cannot change read-only variable \"%.*s\"")); +EXTERN const char e_stringreq[] INIT(= N_("E928: String required")); +EXTERN const char e_dictreq[] INIT(= N_("E715: Dictionary required")); +EXTERN const char e_blobidx[] INIT(= N_("E979: Blob index out of range: %" PRId64)); +EXTERN const char e_invalblob[] INIT(= N_("E978: Invalid operation for Blob")); +EXTERN const char e_toomanyarg[] INIT(= N_("E118: Too many arguments for function: %s")); +EXTERN const char e_toofewarg[] INIT(= N_("E119: Not enough arguments for function: %s")); +EXTERN const char e_dictkey[] INIT(= N_("E716: Key not present in Dictionary: \"%s\"")); +EXTERN const char e_dictkey_len[] INIT(= N_("E716: Key not present in Dictionary: \"%.*s\"")); +EXTERN const char e_listreq[] INIT(= N_("E714: List required")); +EXTERN const char e_listblobreq[] INIT(= N_("E897: List or Blob required")); +EXTERN const char e_listdictarg[] INIT(= N_("E712: Argument of %s must be a List or Dictionary")); +EXTERN const char e_listdictblobarg[] INIT(= N_("E896: Argument of %s must be a List, Dictionary or Blob")); +EXTERN const char e_readerrf[] INIT(= N_("E47: Error while reading errorfile")); +EXTERN const char e_sandbox[] INIT(= N_("E48: Not allowed in sandbox")); +EXTERN const char e_secure[] INIT(= N_("E523: Not allowed here")); +EXTERN const char e_textlock[] INIT(= N_("E565: Not allowed to change text or change window")); +EXTERN const char e_screenmode[] INIT(= N_("E359: Screen mode setting not supported")); +EXTERN const char e_scroll[] INIT(= N_("E49: Invalid scroll size")); +EXTERN const char e_shellempty[] INIT(= N_("E91: 'shell' option is empty")); +EXTERN const char e_signdata[] INIT(= N_("E255: Couldn't read in sign data!")); +EXTERN const char e_swapclose[] INIT(= N_("E72: Close error on swap file")); +EXTERN const char e_toocompl[] INIT(= N_("E74: Command too complex")); +EXTERN const char e_longname[] INIT(= N_("E75: Name too long")); +EXTERN const char e_toomsbra[] INIT(= N_("E76: Too many [")); +EXTERN const char e_toomany[] INIT(= N_("E77: Too many file names")); +EXTERN const char e_trailing[] INIT(= N_("E488: Trailing characters")); +EXTERN const char e_trailing_arg[] INIT(= N_("E488: Trailing characters: %s")); +EXTERN const char e_umark[] INIT(= N_("E78: Unknown mark")); +EXTERN const char e_wildexpand[] INIT(= N_("E79: Cannot expand wildcards")); +EXTERN const char e_winheight[] INIT(= N_("E591: 'winheight' cannot be smaller than 'winminheight'")); +EXTERN const char e_winwidth[] INIT(= N_("E592: 'winwidth' cannot be smaller than 'winminwidth'")); +EXTERN const char e_write[] INIT(= N_("E80: Error while writing")); +EXTERN const char e_zerocount[] INIT(= N_("E939: Positive count required")); +EXTERN const char e_usingsid[] INIT(= N_("E81: Using <SID> not in a script context")); +EXTERN const char e_missingparen[] INIT(= N_("E107: Missing parentheses: %s")); +EXTERN const char e_empty_buffer[] INIT(= N_("E749: Empty buffer")); +EXTERN const char e_nobufnr[] INIT(= N_("E86: Buffer %" PRId64 " does not exist")); + +EXTERN const char e_str_not_inside_function[] INIT(= N_("E193: %s not inside a function")); + +EXTERN const char e_invalpat[] INIT(= N_("E682: Invalid search pattern or delimiter")); +EXTERN const char e_bufloaded[] INIT(= N_("E139: File is loaded in another buffer")); +EXTERN const char e_notset[] INIT(= N_("E764: Option '%s' is not set")); +EXTERN const char e_invalidreg[] INIT(= N_("E850: Invalid register name")); +EXTERN const char e_dirnotf[] INIT(= N_("E919: Directory not found in '%s': \"%s\"")); +EXTERN const char e_au_recursive[] INIT(= N_("E952: Autocommand caused recursive behavior")); +EXTERN const char e_menu_only_exists_in_another_mode[] +INIT(= N_("E328: Menu only exists in another mode")); +EXTERN const char e_autocmd_close[] INIT(= N_("E813: Cannot close autocmd window")); +EXTERN const char e_listarg[] INIT(= N_("E686: Argument of %s must be a List")); +EXTERN const char e_unsupportedoption[] INIT(= N_("E519: Option not supported")); +EXTERN const char e_fnametoolong[] INIT(= N_("E856: Filename too long")); +EXTERN const char e_using_float_as_string[] INIT(= N_("E806: Using a Float as a String")); +EXTERN const char e_cannot_edit_other_buf[] INIT(= N_("E788: Not allowed to edit another buffer now")); +EXTERN const char e_using_number_as_bool_nr[] INIT(= N_("E1023: Using a Number as a Bool: %d")); +EXTERN const char e_not_callable_type_str[] INIT(= N_("E1085: Not a callable type: %s")); +EXTERN const char e_auabort[] INIT(= N_("E855: Autocommands caused command to abort")); + +EXTERN const char e_api_error[] INIT(= N_("E5555: API call: %s")); + +EXTERN const char e_luv_api_disabled[] INIT(= N_("E5560: %s must not be called in a lua loop callback")); + +EXTERN const char e_floatonly[] INIT(= N_("E5601: Cannot close window, only floating window would remain")); +EXTERN const char e_floatexchange[] INIT(= N_("E5602: Cannot exchange or rotate float")); + +EXTERN const char e_cannot_define_autocommands_for_all_events[] INIT(= N_("E1155: Cannot define autocommands for ALL events")); + +EXTERN const char e_resulting_text_too_long[] INIT(= N_("E1240: Resulting text too long")); + +EXTERN const char e_line_number_out_of_range[] INIT(= N_("E1247: Line number out of range")); + +EXTERN const char e_highlight_group_name_invalid_char[] INIT(= N_("E5248: Invalid character in group name")); + +EXTERN const char e_highlight_group_name_too_long[] INIT(= N_("E1249: Highlight group name too long")); + +EXTERN const char e_invalid_column_number_nr[] INIT( = N_("E964: Invalid column number: %ld")); +EXTERN const char e_invalid_line_number_nr[] INIT(= N_("E966: Invalid line number: %ld")); + +EXTERN const char e_stray_closing_curly_str[] +INIT(= N_("E1278: Stray '}' without a matching '{': %s")); +EXTERN const char e_missing_close_curly_str[] +INIT(= N_("E1279: Missing '}': %s")); + +EXTERN const char e_val_too_large[] INIT(= N_("E1510: Value too large: %s")); + +EXTERN const char e_undobang_cannot_redo_or_move_branch[] +INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch")); + +EXTERN const char e_winfixbuf_cannot_go_to_buffer[] +INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled")); + +EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s")); + +EXTERN const char e_unknown_option2[] INIT(= N_("E355: Unknown option: %s")); + +EXTERN const char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM")); +EXTERN const char bot_top_msg[] INIT(= N_("search hit BOTTOM, continuing at TOP")); + +EXTERN const char line_msg[] INIT(= N_(" line ")); +// uncrustify:on diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 64883e69a2..8682139b32 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6,7 +6,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/stat.h> #include <uv.h> #include "auto/config.h" @@ -21,9 +20,9 @@ #include "nvim/channel.h" #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" -#include "nvim/cmdhist.h" #include "nvim/cursor.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/executor.h" @@ -33,18 +32,15 @@ #include "nvim/eval/vars.h" #include "nvim/event/loop.h" #include "nvim/event/multiqueue.h" -#include "nvim/event/process.h" +#include "nvim/event/proc.h" #include "nvim/event/time.h" #include "nvim/ex_cmds.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" -#include "nvim/ex_getln.h" #include "nvim/garray.h" #include "nvim/garray_defs.h" -#include "nvim/getchar.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" -#include "nvim/grid_defs.h" #include "nvim/hashtab.h" #include "nvim/highlight_group.h" #include "nvim/insexpand.h" @@ -66,14 +62,11 @@ #include "nvim/option.h" #include "nvim/option_vars.h" #include "nvim/optionstr.h" -#include "nvim/os/fileio.h" #include "nvim/os/fs.h" -#include "nvim/os/fs_defs.h" #include "nvim/os/lang.h" #include "nvim/os/os.h" #include "nvim/os/os_defs.h" #include "nvim/os/shell.h" -#include "nvim/os/stdpaths_defs.h" #include "nvim/path.h" #include "nvim/pos_defs.h" #include "nvim/profile.h" @@ -82,14 +75,9 @@ #include "nvim/regexp_defs.h" #include "nvim/runtime.h" #include "nvim/runtime_defs.h" -#include "nvim/search.h" #include "nvim/strings.h" #include "nvim/tag.h" #include "nvim/types_defs.h" -#include "nvim/ui.h" -#include "nvim/ui_compositor.h" -#include "nvim/ui_defs.h" -#include "nvim/usercmd.h" #include "nvim/version.h" #include "nvim/vim_defs.h" #include "nvim/window.h" @@ -106,7 +94,6 @@ static const char e_cannot_index_special_variable[] = N_("E909: Cannot index a special variable"); static const char *e_nowhitespace = N_("E274: No white space allowed before parenthesis"); -static const char *e_write2 = N_("E80: Error while writing: %s"); static const char e_cannot_index_a_funcref[] = N_("E695: Cannot index a Funcref"); static const char e_variable_nested_too_deep_for_making_copy[] @@ -121,6 +108,8 @@ static const char e_empty_function_name[] = N_("E1192: Empty function name"); static const char e_argument_of_str_must_be_list_string_dictionary_or_blob[] = N_("E1250: Argument of %s must be a List, String, Dictionary or Blob"); +static const char e_cannot_use_partial_here[] + = N_("E1265: Cannot use a partial here"); static char * const namespace_char = "abglstvw"; @@ -151,6 +140,12 @@ typedef struct { int fi_byte_idx; // byte index in fi_string } forinfo_T; +typedef enum { + GLV_FAIL, + GLV_OK, + GLV_STOP, +} glv_status_T; + // values for vv_flags: #define VV_COMPAT 1 // compatible, also used without "v:" #define VV_RO 2 // read-only @@ -330,7 +325,6 @@ static const char *const msgpack_type_names[] = { [kMPInteger] = "integer", [kMPFloat] = "float", [kMPString] = "string", - [kMPBinary] = "binary", [kMPArray] = "array", [kMPMap] = "map", [kMPExt] = "ext", @@ -341,7 +335,6 @@ const list_T *eval_msgpack_type_lists[] = { [kMPInteger] = NULL, [kMPFloat] = NULL, [kMPString] = NULL, - [kMPBinary] = NULL, [kMPArray] = NULL, [kMPMap] = NULL, [kMPExt] = NULL, @@ -696,7 +689,7 @@ int eval_charconvert(const char *const enc_from, const char *const enc_to, } bool err = false; - if (eval_to_bool(p_ccv, &err, NULL, false)) { + if (eval_to_bool(p_ccv, &err, NULL, false, true)) { err = true; } @@ -725,7 +718,7 @@ void eval_diff(const char *const origfile, const char *const newfile, const char } // errors are ignored - typval_T *tv = eval_expr(p_dex, NULL); + typval_T *tv = eval_expr_ext(p_dex, NULL, true); tv_free(tv); set_vim_var_string(VV_FNAME_IN, NULL, -1); @@ -747,7 +740,7 @@ void eval_patch(const char *const origfile, const char *const difffile, const ch } // errors are ignored - typval_T *tv = eval_expr(p_pex, NULL); + typval_T *tv = eval_expr_ext(p_pex, NULL, true); tv_free(tv); set_vim_var_string(VV_FNAME_IN, NULL, -1); @@ -776,7 +769,8 @@ void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, bool skip) /// @param skip only parse, don't execute /// /// @return true or false. -bool eval_to_bool(char *arg, bool *error, exarg_T *eap, bool skip) +bool eval_to_bool(char *arg, bool *error, exarg_T *eap, const bool skip, + const bool use_simple_function) { typval_T tv; bool retval = false; @@ -787,7 +781,9 @@ bool eval_to_bool(char *arg, bool *error, exarg_T *eap, bool skip) if (skip) { emsg_skip++; } - if (eval0(arg, &tv, eap, &evalarg) == FAIL) { + int r = use_simple_function ? eval0_simple_funccal(arg, &tv, eap, &evalarg) + : eval0(arg, &tv, eap, &evalarg); + if (r == FAIL) { *error = true; } else { *error = false; @@ -840,6 +836,80 @@ bool eval_expr_valid_arg(const typval_T *const tv) && (tv->v_type != VAR_STRING || (tv->vval.v_string != NULL && *tv->vval.v_string != NUL)); } +/// Evaluate a partial. +/// Pass arguments "argv[argc]". +/// Return the result in "rettv" and OK or FAIL. +static int eval_expr_partial(const typval_T *expr, typval_T *argv, int argc, typval_T *rettv) + FUNC_ATTR_NONNULL_ALL +{ + partial_T *const partial = expr->vval.v_partial; + if (partial == NULL) { + return FAIL; + } + + const char *const s = partial_name(partial); + if (s == NULL || *s == NUL) { + return FAIL; + } + + funcexe_T funcexe = FUNCEXE_INIT; + funcexe.fe_evaluate = true; + funcexe.fe_partial = partial; + if (call_func(s, -1, rettv, argc, argv, &funcexe) == FAIL) { + return FAIL; + } + + return OK; +} + +/// Evaluate an expression which is a function. +/// Pass arguments "argv[argc]". +/// Return the result in "rettv" and OK or FAIL. +static int eval_expr_func(const typval_T *expr, typval_T *argv, int argc, typval_T *rettv) + FUNC_ATTR_NONNULL_ALL +{ + char buf[NUMBUFLEN]; + const char *const s = (expr->v_type == VAR_FUNC + ? expr->vval.v_string + : tv_get_string_buf_chk(expr, buf)); + if (s == NULL || *s == NUL) { + return FAIL; + } + + funcexe_T funcexe = FUNCEXE_INIT; + funcexe.fe_evaluate = true; + if (call_func(s, -1, rettv, argc, argv, &funcexe) == FAIL) { + return FAIL; + } + + return OK; +} + +/// Evaluate an expression, which is a string. +/// Return the result in "rettv" and OK or FAIL. +static int eval_expr_string(const typval_T *expr, typval_T *rettv) + FUNC_ATTR_NONNULL_ALL +{ + char buf[NUMBUFLEN]; + char *s = (char *)tv_get_string_buf_chk(expr, buf); + if (s == NULL) { + return FAIL; + } + + s = skipwhite(s); + if (eval1_emsg(&s, rettv, NULL) == FAIL) { + return FAIL; + } + + if (*skipwhite(s) != NUL) { // check for trailing chars after expr + tv_clear(rettv); + semsg(_(e_invexpr2), s); + return FAIL; + } + + return OK; +} + /// Evaluate an expression, which can be a function, partial or string. /// Pass arguments "argv[argc]". /// Return the result in "rettv" and OK or FAIL. @@ -849,49 +919,14 @@ int eval_expr_typval(const typval_T *expr, bool want_func, typval_T *argv, int a typval_T *rettv) FUNC_ATTR_NONNULL_ALL { - char buf[NUMBUFLEN]; - funcexe_T funcexe = FUNCEXE_INIT; - if (expr->v_type == VAR_PARTIAL) { - partial_T *const partial = expr->vval.v_partial; - if (partial == NULL) { - return FAIL; - } - const char *const s = partial_name(partial); - if (s == NULL || *s == NUL) { - return FAIL; - } - funcexe.fe_evaluate = true; - funcexe.fe_partial = partial; - if (call_func(s, -1, rettv, argc, argv, &funcexe) == FAIL) { - return FAIL; - } + return eval_expr_partial(expr, argv, argc, rettv); } else if (expr->v_type == VAR_FUNC || want_func) { - const char *const s = (expr->v_type == VAR_FUNC - ? expr->vval.v_string - : tv_get_string_buf_chk(expr, buf)); - if (s == NULL || *s == NUL) { - return FAIL; - } - funcexe.fe_evaluate = true; - if (call_func(s, -1, rettv, argc, argv, &funcexe) == FAIL) { - return FAIL; - } + return eval_expr_func(expr, argv, argc, rettv); } else { - char *s = (char *)tv_get_string_buf_chk(expr, buf); - if (s == NULL) { - return FAIL; - } - s = skipwhite(s); - if (eval1_emsg(&s, rettv, NULL) == FAIL) { - return FAIL; - } - if (*skipwhite(s) != NUL) { // check for trailing chars after expr - tv_clear(rettv); - semsg(_(e_invexpr2), s); - return FAIL; - } + return eval_expr_string(expr, rettv); } + return OK; } @@ -996,14 +1031,17 @@ static char *typval2string(typval_T *tv, bool join_list) /// @param join_list when true convert a List into a sequence of lines. /// /// @return pointer to allocated memory, or NULL for failure. -char *eval_to_string_eap(char *arg, bool join_list, exarg_T *eap) +char *eval_to_string_eap(char *arg, const bool join_list, exarg_T *eap, + const bool use_simple_function) { typval_T tv; char *retval; evalarg_T evalarg; fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip); - if (eval0(arg, &tv, NULL, &evalarg) == FAIL) { + int r = use_simple_function ? eval0_simple_funccal(arg, &tv, NULL, &evalarg) + : eval0(arg, &tv, NULL, &evalarg); + if (r == FAIL) { retval = NULL; } else { retval = typval2string(&tv, join_list); @@ -1014,16 +1052,16 @@ char *eval_to_string_eap(char *arg, bool join_list, exarg_T *eap) return retval; } -char *eval_to_string(char *arg, bool join_list) +char *eval_to_string(char *arg, const bool join_list, const bool use_simple_function) { - return eval_to_string_eap(arg, join_list, NULL); + return eval_to_string_eap(arg, join_list, NULL, use_simple_function); } /// Call eval_to_string() without using current local variables and using /// textlock. /// /// @param use_sandbox when true, use the sandbox. -char *eval_to_string_safe(char *arg, const bool use_sandbox) +char *eval_to_string_safe(char *arg, const bool use_sandbox, const bool use_simple_function) { char *retval; funccal_entry_T funccal_entry; @@ -1033,7 +1071,7 @@ char *eval_to_string_safe(char *arg, const bool use_sandbox) sandbox++; } textlock++; - retval = eval_to_string(arg, false); + retval = eval_to_string(arg, false, use_simple_function); if (use_sandbox) { sandbox--; } @@ -1046,15 +1084,22 @@ char *eval_to_string_safe(char *arg, const bool use_sandbox) /// Evaluates "expr" silently. /// /// @return -1 for an error. -varnumber_T eval_to_number(char *expr) +varnumber_T eval_to_number(char *expr, const bool use_simple_function) { typval_T rettv; varnumber_T retval; char *p = skipwhite(expr); + int r = NOTDONE; emsg_off++; - if (eval1(&p, &rettv, &EVALARG_EVALUATE) == FAIL) { + if (use_simple_function) { + r = may_call_simple_func(expr, &rettv); + } + if (r == NOTDONE) { + r = eval1(&p, &rettv, &EVALARG_EVALUATE); + } + if (r == FAIL) { retval = -1; } else { retval = tv_get_number_chk(&rettv, NULL); @@ -1071,12 +1116,26 @@ varnumber_T eval_to_number(char *expr) /// NULL when there is an error. typval_T *eval_expr(char *arg, exarg_T *eap) { + return eval_expr_ext(arg, eap, false); +} + +static typval_T *eval_expr_ext(char *arg, exarg_T *eap, const bool use_simple_function) +{ typval_T *tv = xmalloc(sizeof(*tv)); evalarg_T evalarg; fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip); - if (eval0(arg, tv, eap, &evalarg) == FAIL) { + int r = NOTDONE; + + if (use_simple_function) { + r = eval0_simple_funccal(arg, tv, eap, &evalarg); + } + if (r == NOTDONE) { + r = eval0(arg, tv, eap, &evalarg); + } + + if (r == FAIL) { XFREE_CLEAR(tv); } @@ -1162,7 +1221,11 @@ list_T *eval_spell_expr(char *badword, char *expr) current_sctx = *ctx; } - if (eval1(&p, &rettv, &EVALARG_EVALUATE) == OK) { + int r = may_call_simple_func(p, &rettv); + if (r == NOTDONE) { + r = eval1(&p, &rettv, &EVALARG_EVALUATE); + } + if (r == OK) { if (rettv.v_type != VAR_LIST) { tv_clear(&rettv); } else { @@ -1303,7 +1366,7 @@ int eval_foldexpr(win_T *wp, int *cp) const sctx_T saved_sctx = current_sctx; const bool use_sandbox = was_set_insecurely(wp, kOptFoldexpr, OPT_LOCAL); - char *arg = wp->w_p_fde; + char *arg = skipwhite(wp->w_p_fde); current_sctx = wp->w_p_script_ctx[WV_FDE].script_ctx; emsg_off++; @@ -1315,7 +1378,9 @@ int eval_foldexpr(win_T *wp, int *cp) typval_T tv; varnumber_T retval; - if (eval0(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) { + // Evaluate the expression. If the expression is "FuncName()" call the + // function directly. + if (eval0_simple_funccal(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) { retval = 0; } else { // If the result is a number, just return the number. @@ -1361,7 +1426,7 @@ Object eval_foldtext(win_T *wp) typval_T tv; Object retval; - if (eval0(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) { + if (eval0_simple_funccal(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) { retval = STRING_OBJ(NULL_STRING); } else { if (tv.v_type == VAR_LIST) { @@ -1382,22 +1447,232 @@ Object eval_foldtext(win_T *wp) return retval; } +/// Find the end of a variable or function name. Unlike find_name_end() this +/// does not recognize magic braces. +/// When "use_namespace" is true recognize "b:", "s:", etc. +/// Return a pointer to just after the name. Equal to "arg" if there is no +/// valid name. +static const char *to_name_end(const char *arg, bool use_namespace) +{ + // Quick check for valid starting character. + if (!eval_isnamec1(*arg)) { + return arg; + } + + const char *p; + for (p = arg + 1; *p != NUL && eval_isnamec(*p); MB_PTR_ADV(p)) { + // Include a namespace such as "s:var" and "v:var". But "n:" is not + // and can be used in slice "[n:]". + if (*p == ':' && (p != arg + 1 + || !use_namespace + || vim_strchr("bgstvw", *arg) == NULL)) { + break; + } + } + return p; +} + +/// Get an Dict lval variable that can be assigned a value to: "name", +/// "name[expr]", "name[expr][expr]", "name.key", "name.key[expr]" etc. +/// "name" points to the start of the name. +/// If "rettv" is not NULL it points to the value to be assigned. +/// "unlet" is true for ":unlet": slightly different behavior when something is +/// wrong; must end in space or cmd separator. +/// +/// flags: +/// GLV_QUIET: do not give error messages +/// GLV_READ_ONLY: will not change the variable +/// GLV_NO_AUTOLOAD: do not use script autoloading +/// +/// The Dict is returned in 'lp'. Returns GLV_OK on success and GLV_FAIL on +/// failure. Returns GLV_STOP to stop processing the characters following +/// 'key_end'. +static glv_status_T get_lval_dict_item(lval_T *lp, char *name, char *key, int len, char **key_end, + typval_T *var1, int flags, bool unlet, typval_T *rettv) +{ + bool quiet = flags & GLV_QUIET; + char *p = *key_end; + + if (len == -1) { + // "[key]": get key from "var1" + key = (char *)tv_get_string(var1); // is number or string + } + lp->ll_list = NULL; + + // a NULL dict is equivalent with an empty dict + if (lp->ll_tv->vval.v_dict == NULL) { + lp->ll_tv->vval.v_dict = tv_dict_alloc(); + lp->ll_tv->vval.v_dict->dv_refcount++; + } + lp->ll_dict = lp->ll_tv->vval.v_dict; + + lp->ll_di = tv_dict_find(lp->ll_dict, key, len); + + // When assigning to a scope dictionary check that a function and + // variable name is valid (only variable name unless it is l: or + // g: dictionary). Disallow overwriting a builtin function. + if (rettv != NULL && lp->ll_dict->dv_scope != 0) { + char prevval; + if (len != -1) { + prevval = key[len]; + key[len] = NUL; + } else { + prevval = 0; // Avoid compiler warning. + } + bool wrong = ((lp->ll_dict->dv_scope == VAR_DEF_SCOPE + && tv_is_func(*rettv) + && var_wrong_func_name(key, lp->ll_di == NULL)) + || !valid_varname(key)); + if (len != -1) { + key[len] = prevval; + } + if (wrong) { + return GLV_FAIL; + } + } + + if (lp->ll_di != NULL && tv_is_luafunc(&lp->ll_di->di_tv) + && len == -1 && rettv == NULL) { + semsg(e_illvar, "v:['lua']"); + return GLV_FAIL; + } + + if (lp->ll_di == NULL) { + // Can't add "v:" or "a:" variable. + if (lp->ll_dict == &vimvardict + || &lp->ll_dict->dv_hashtab == get_funccal_args_ht()) { + semsg(_(e_illvar), name); + return GLV_FAIL; + } + + // Key does not exist in dict: may need to add it. + if (*p == '[' || *p == '.' || unlet) { + if (!quiet) { + semsg(_(e_dictkey), key); + } + return GLV_FAIL; + } + if (len == -1) { + lp->ll_newkey = xstrdup(key); + } else { + lp->ll_newkey = xmemdupz(key, (size_t)len); + } + *key_end = p; + return GLV_STOP; + // existing variable, need to check if it can be changed + } else if (!(flags & GLV_READ_ONLY) + && (var_check_ro(lp->ll_di->di_flags, name, (size_t)(p - name)) + || var_check_lock(lp->ll_di->di_flags, name, (size_t)(p - name)))) { + return GLV_FAIL; + } + + lp->ll_tv = &lp->ll_di->di_tv; + + return GLV_OK; +} + +/// Get an blob lval variable that can be assigned a value to: "name", +/// "na{me}", "name[expr]", "name[expr:expr]", "name[expr][expr]", etc. +/// +/// 'var1' specifies the starting blob index and 'var2' specifies the ending +/// blob index. If the first index is not specified in a range, then 'empty1' +/// is true. If 'quiet' is true, then error messages are not displayed for +/// invalid indexes. +/// +/// The blob is returned in 'lp'. Returns OK on success and FAIL on failure. +static int get_lval_blob(lval_T *lp, typval_T *var1, typval_T *var2, bool empty1, bool quiet) +{ + const int bloblen = tv_blob_len(lp->ll_tv->vval.v_blob); + + // Get the number and item for the only or first index of the List. + if (empty1) { + lp->ll_n1 = 0; + } else { + // Is number or string. + lp->ll_n1 = (int)tv_get_number(var1); + } + + if (tv_blob_check_index(bloblen, lp->ll_n1, quiet) == FAIL) { + return FAIL; + } + if (lp->ll_range && !lp->ll_empty2) { + lp->ll_n2 = (int)tv_get_number(var2); + if (tv_blob_check_range(bloblen, lp->ll_n1, lp->ll_n2, quiet) == FAIL) { + return FAIL; + } + } + + lp->ll_blob = lp->ll_tv->vval.v_blob; + lp->ll_tv = NULL; + + return OK; +} + +/// Get a List lval variable that can be assigned a value to: "name", +/// "na{me}", "name[expr]", "name[expr:expr]", "name[expr][expr]", etc. +/// +/// 'var1' specifies the starting List index and 'var2' specifies the ending +/// List index. If the first index is not specified in a range, then 'empty1' +/// is true. If 'quiet' is true, then error messages are not displayed for +/// invalid indexes. +/// +/// The List is returned in 'lp'. Returns OK on success and FAIL on failure. +static int get_lval_list(lval_T *lp, typval_T *var1, typval_T *var2, bool empty1, int flags, + bool quiet) +{ + // Get the number and item for the only or first index of the List. + if (empty1) { + lp->ll_n1 = 0; + } else { + // Is number or string. + lp->ll_n1 = (int)tv_get_number(var1); + } + + lp->ll_dict = NULL; + lp->ll_list = lp->ll_tv->vval.v_list; + lp->ll_li = tv_list_check_range_index_one(lp->ll_list, &lp->ll_n1, quiet); + if (lp->ll_li == NULL) { + return FAIL; + } + + // May need to find the item or absolute index for the second + // index of a range. + // When no index given: "lp->ll_empty2" is true. + // Otherwise "lp->ll_n2" is set to the second index. + if (lp->ll_range && !lp->ll_empty2) { + lp->ll_n2 = (int)tv_get_number(var2); // Is number or string. + if (tv_list_check_range_index_two(lp->ll_list, + &lp->ll_n1, lp->ll_li, + &lp->ll_n2, quiet) == FAIL) { + return FAIL; + } + } + + lp->ll_tv = TV_LIST_ITEM_TV(lp->ll_li); + + return OK; +} + /// Get the lval of a list/dict/blob subitem starting at "p". Loop /// until no more [idx] or .key is following. /// +/// If "rettv" is not NULL it points to the value to be assigned. +/// "unlet" is true for ":unlet". +/// /// @param[in] flags @see GetLvalFlags. /// /// @return A pointer to the character after the subscript on success or NULL on /// failure. static char *get_lval_subscript(lval_T *lp, char *p, char *name, typval_T *rettv, hashtab_T *ht, - dictitem_T *v, int unlet, int flags) + dictitem_T *v, bool unlet, int flags) { - int quiet = flags & GLV_QUIET; + bool quiet = flags & GLV_QUIET; typval_T var1; var1.v_type = VAR_UNKNOWN; typval_T var2; var2.v_type = VAR_UNKNOWN; bool empty1 = false; + int rc = FAIL; // Loop until no more [idx] or .key is following. while (*p == '[' || (*p == '.' && p[1] != '=' && p[1] != '.')) { @@ -1427,7 +1702,7 @@ static char *get_lval_subscript(lval_T *lp, char *p, char *name, typval_T *rettv if (!quiet) { emsg(_("E708: [:] must come last")); } - return NULL; + goto done; } int len = -1; @@ -1451,12 +1726,11 @@ static char *get_lval_subscript(lval_T *lp, char *p, char *name, typval_T *rettv } else { empty1 = false; if (eval1(&p, &var1, &EVALARG_EVALUATE) == FAIL) { // Recursive! - return NULL; + goto done; } if (!tv_check_str(&var1)) { // Not a number or string. - tv_clear(&var1); - return NULL; + goto done; } p = skipwhite(p); } @@ -1467,8 +1741,7 @@ static char *get_lval_subscript(lval_T *lp, char *p, char *name, typval_T *rettv if (!quiet) { emsg(_(e_cannot_slice_dictionary)); } - tv_clear(&var1); - return NULL; + goto done; } if (rettv != NULL && !(rettv->v_type == VAR_LIST && rettv->vval.v_list != NULL) @@ -1476,8 +1749,7 @@ static char *get_lval_subscript(lval_T *lp, char *p, char *name, typval_T *rettv if (!quiet) { emsg(_("E709: [:] requires a List or Blob value")); } - tv_clear(&var1); - return NULL; + goto done; } p = skipwhite(p + 1); if (*p == ']') { @@ -1486,14 +1758,11 @@ static char *get_lval_subscript(lval_T *lp, char *p, char *name, typval_T *rettv lp->ll_empty2 = false; // Recursive! if (eval1(&p, &var2, &EVALARG_EVALUATE) == FAIL) { - tv_clear(&var1); - return NULL; + goto done; } if (!tv_check_str(&var2)) { // Not a number or string. - tv_clear(&var1); - tv_clear(&var2); - return NULL; + goto done; } } lp->ll_range = true; @@ -1505,9 +1774,7 @@ static char *get_lval_subscript(lval_T *lp, char *p, char *name, typval_T *rettv if (!quiet) { emsg(_(e_missbrac)); } - tv_clear(&var1); - tv_clear(&var2); - return NULL; + goto done; } // Skip to past ']'. @@ -1515,142 +1782,37 @@ static char *get_lval_subscript(lval_T *lp, char *p, char *name, typval_T *rettv } if (lp->ll_tv->v_type == VAR_DICT) { - if (len == -1) { - // "[key]": get key from "var1" - key = (char *)tv_get_string(&var1); // is number or string - } - lp->ll_list = NULL; - lp->ll_dict = lp->ll_tv->vval.v_dict; - lp->ll_di = tv_dict_find(lp->ll_dict, key, len); - - // When assigning to a scope dictionary check that a function and - // variable name is valid (only variable name unless it is l: or - // g: dictionary). Disallow overwriting a builtin function. - if (rettv != NULL && lp->ll_dict->dv_scope != 0) { - char prevval; - if (len != -1) { - prevval = key[len]; - key[len] = NUL; - } else { - prevval = 0; // Avoid compiler warning. - } - bool wrong = ((lp->ll_dict->dv_scope == VAR_DEF_SCOPE - && tv_is_func(*rettv) - && var_wrong_func_name(key, lp->ll_di == NULL)) - || !valid_varname(key)); - if (len != -1) { - key[len] = prevval; - } - if (wrong) { - tv_clear(&var1); - return NULL; - } - } - - if (lp->ll_di != NULL && tv_is_luafunc(&lp->ll_di->di_tv) - && len == -1 && rettv == NULL) { - tv_clear(&var1); - semsg(e_illvar, "v:['lua']"); - return NULL; + glv_status_T glv_status = get_lval_dict_item(lp, name, key, len, &p, &var1, + flags, unlet, rettv); + if (glv_status == GLV_FAIL) { + goto done; } - - if (lp->ll_di == NULL) { - // Can't add "v:" or "a:" variable. - if (lp->ll_dict == &vimvardict - || &lp->ll_dict->dv_hashtab == get_funccal_args_ht()) { - semsg(_(e_illvar), name); - tv_clear(&var1); - return NULL; - } - - // Key does not exist in dict: may need to add it. - if (*p == '[' || *p == '.' || unlet) { - if (!quiet) { - semsg(_(e_dictkey), key); - } - tv_clear(&var1); - return NULL; - } - if (len == -1) { - lp->ll_newkey = xstrdup(key); - } else { - lp->ll_newkey = xmemdupz(key, (size_t)len); - } - tv_clear(&var1); + if (glv_status == GLV_STOP) { break; - // existing variable, need to check if it can be changed - } else if (!(flags & GLV_READ_ONLY) - && (var_check_ro(lp->ll_di->di_flags, name, (size_t)(p - name)) - || var_check_lock(lp->ll_di->di_flags, name, (size_t)(p - name)))) { - tv_clear(&var1); - return NULL; } - - tv_clear(&var1); - lp->ll_tv = &lp->ll_di->di_tv; } else if (lp->ll_tv->v_type == VAR_BLOB) { - // Get the number and item for the only or first index of the List. - if (empty1) { - lp->ll_n1 = 0; - } else { - // Is number or string. - lp->ll_n1 = (int)tv_get_number(&var1); + if (get_lval_blob(lp, &var1, &var2, empty1, quiet) == FAIL) { + goto done; } - tv_clear(&var1); - - const int bloblen = tv_blob_len(lp->ll_tv->vval.v_blob); - if (tv_blob_check_index(bloblen, lp->ll_n1, quiet) == FAIL) { - tv_clear(&var2); - return NULL; - } - if (lp->ll_range && !lp->ll_empty2) { - lp->ll_n2 = (int)tv_get_number(&var2); - tv_clear(&var2); - if (tv_blob_check_range(bloblen, lp->ll_n1, lp->ll_n2, quiet) == FAIL) { - return NULL; - } - } - lp->ll_blob = lp->ll_tv->vval.v_blob; - lp->ll_tv = NULL; break; } else { - // Get the number and item for the only or first index of the List. - if (empty1) { - lp->ll_n1 = 0; - } else { - // Is number or string. - lp->ll_n1 = (int)tv_get_number(&var1); - } - tv_clear(&var1); - - lp->ll_dict = NULL; - lp->ll_list = lp->ll_tv->vval.v_list; - lp->ll_li = tv_list_check_range_index_one(lp->ll_list, &lp->ll_n1, quiet); - if (lp->ll_li == NULL) { - tv_clear(&var2); - return NULL; - } - - // May need to find the item or absolute index for the second - // index of a range. - // When no index given: "lp->ll_empty2" is true. - // Otherwise "lp->ll_n2" is set to the second index. - if (lp->ll_range && !lp->ll_empty2) { - lp->ll_n2 = (int)tv_get_number(&var2); // Is number or string. - tv_clear(&var2); - if (tv_list_check_range_index_two(lp->ll_list, - &lp->ll_n1, lp->ll_li, - &lp->ll_n2, quiet) == FAIL) { - return NULL; - } + if (get_lval_list(lp, &var1, &var2, empty1, flags, quiet) == FAIL) { + goto done; } - - lp->ll_tv = TV_LIST_ITEM_TV(lp->ll_li); } + + tv_clear(&var1); + tv_clear(&var2); + var1.v_type = VAR_UNKNOWN; + var2.v_type = VAR_UNKNOWN; } + rc = OK; + +done: tv_clear(&var1); - return p; + tv_clear(&var2); + return rc == OK ? p : NULL; } /// Get an lvalue @@ -2381,9 +2543,10 @@ void clear_evalarg(evalarg_T *evalarg, exarg_T *eap) } } -/// The "evaluate" argument: When false, the argument is only parsed but not -/// executed. The function may return OK, but the rettv will be of type -/// VAR_UNKNOWN. The function still returns FAIL for a syntax error. +/// The "eval" functions have an "evalarg" argument: When NULL or +/// "evalarg->eval_flags" does not have EVAL_EVALUATE, then the argument is only +/// parsed but not executed. The functions may return OK, but the rettv will be +/// of type VAR_UNKNOWN. The functions still returns FAIL for a syntax error. /// Handle zero level expression. /// This calls eval1() and handles error message and nextcmd. @@ -2442,6 +2605,42 @@ int eval0(char *arg, typval_T *rettv, exarg_T *eap, evalarg_T *const evalarg) return ret; } +/// If "arg" is a simple function call without arguments then call it and return +/// the result. Otherwise return NOTDONE. +static int may_call_simple_func(const char *arg, typval_T *rettv) +{ + const char *parens = strstr(arg, "()"); + int r = NOTDONE; + + // If the expression is "FuncName()" then we can skip a lot of overhead. + if (parens != NULL && *skipwhite(parens + 2) == NUL) { + if (strnequal(arg, "v:lua.", 6)) { + const char *p = arg + 6; + if (p != parens && skip_luafunc_name(p) == parens) { + r = call_simple_luafunc(p, (size_t)(parens - p), rettv); + } + } else { + const char *p = strncmp(arg, "<SNR>", 5) == 0 ? skipdigits(arg + 5) : arg; + if (to_name_end(p, true) == parens) { + r = call_simple_func(arg, (size_t)(parens - arg), rettv); + } + } + } + return r; +} + +/// Handle zero level expression with optimization for a simple function call. +/// Same arguments and return value as eval0(). +static int eval0_simple_funccal(char *arg, typval_T *rettv, exarg_T *eap, evalarg_T *const evalarg) +{ + int r = may_call_simple_func(arg, rettv); + + if (r == NOTDONE) { + r = eval0(arg, rettv, eap, evalarg); + } + return r; +} + /// Handle top level expression: /// expr2 ? expr1 : expr1 /// expr2 ?? expr1 @@ -2832,6 +3031,93 @@ static int eval_addlist(typval_T *tv1, typval_T *tv2) return OK; } +/// Concatenate strings "tv1" and "tv2" and store the result in "tv1". +static int eval_concat_str(typval_T *tv1, typval_T *tv2) +{ + char buf1[NUMBUFLEN]; + char buf2[NUMBUFLEN]; + // s1 already checked + const char *const s1 = tv_get_string_buf(tv1, buf1); + const char *const s2 = tv_get_string_buf_chk(tv2, buf2); + if (s2 == NULL) { // Type error? + tv_clear(tv1); + tv_clear(tv2); + return FAIL; + } + + char *p = concat_str(s1, s2); + tv_clear(tv1); + tv1->v_type = VAR_STRING; + tv1->vval.v_string = p; + + return OK; +} + +/// Add or subtract numbers "tv1" and "tv2" and store the result in "tv1". +/// The numbers can be whole numbers or floats. +static int eval_addsub_number(typval_T *tv1, typval_T *tv2, int op) +{ + bool error = false; + varnumber_T n1, n2; + float_T f1 = 0; + float_T f2 = 0; + + if (tv1->v_type == VAR_FLOAT) { + f1 = tv1->vval.v_float; + n1 = 0; + } else { + n1 = tv_get_number_chk(tv1, &error); + if (error) { + // This can only happen for "list + non-list" or + // "blob + non-blob". For "non-list + ..." or + // "something - ...", we returned before evaluating the + // 2nd operand. + tv_clear(tv1); + tv_clear(tv2); + return FAIL; + } + if (tv2->v_type == VAR_FLOAT) { + f1 = (float_T)n1; + } + } + if (tv2->v_type == VAR_FLOAT) { + f2 = tv2->vval.v_float; + n2 = 0; + } else { + n2 = tv_get_number_chk(tv2, &error); + if (error) { + tv_clear(tv1); + tv_clear(tv2); + return FAIL; + } + if (tv1->v_type == VAR_FLOAT) { + f2 = (float_T)n2; + } + } + tv_clear(tv1); + + // If there is a float on either side the result is a float. + if (tv1->v_type == VAR_FLOAT || tv2->v_type == VAR_FLOAT) { + if (op == '+') { + f1 = f1 + f2; + } else { + f1 = f1 - f2; + } + tv1->v_type = VAR_FLOAT; + tv1->vval.v_float = f1; + } else { + if (op == '+') { + n1 = n1 + n2; + } else { + n1 = n1 - n2; + } + tv1->v_type = VAR_NUMBER; + tv1->vval.v_number = n1; + } + + return OK; +} + /// Handle fourth level expression: /// + number addition, concatenation of list or blob /// - number subtraction @@ -2887,20 +3173,9 @@ static int eval5(char **arg, typval_T *rettv, evalarg_T *const evalarg) if (evaluate) { // Compute the result. if (op == '.') { - char buf1[NUMBUFLEN]; - char buf2[NUMBUFLEN]; - // s1 already checked - const char *const s1 = tv_get_string_buf(rettv, buf1); - const char *const s2 = tv_get_string_buf_chk(&var2, buf2); - if (s2 == NULL) { // Type error? - tv_clear(rettv); - tv_clear(&var2); + if (eval_concat_str(rettv, &var2) == FAIL) { return FAIL; } - char *p = concat_str(s1, s2); - tv_clear(rettv); - rettv->v_type = VAR_STRING; - rettv->vval.v_string = p; } else if (op == '+' && rettv->v_type == VAR_BLOB && var2.v_type == VAR_BLOB) { eval_addblob(rettv, &var2); } else if (op == '+' && rettv->v_type == VAR_LIST && var2.v_type == VAR_LIST) { @@ -2908,62 +3183,8 @@ static int eval5(char **arg, typval_T *rettv, evalarg_T *const evalarg) return FAIL; } } else { - bool error = false; - varnumber_T n1, n2; - float_T f1 = 0; - float_T f2 = 0; - - if (rettv->v_type == VAR_FLOAT) { - f1 = rettv->vval.v_float; - n1 = 0; - } else { - n1 = tv_get_number_chk(rettv, &error); - if (error) { - // This can only happen for "list + non-list" or - // "blob + non-blob". For "non-list + ..." or - // "something - ...", we returned before evaluating the - // 2nd operand. - tv_clear(rettv); - tv_clear(&var2); - return FAIL; - } - if (var2.v_type == VAR_FLOAT) { - f1 = (float_T)n1; - } - } - if (var2.v_type == VAR_FLOAT) { - f2 = var2.vval.v_float; - n2 = 0; - } else { - n2 = tv_get_number_chk(&var2, &error); - if (error) { - tv_clear(rettv); - tv_clear(&var2); - return FAIL; - } - if (rettv->v_type == VAR_FLOAT) { - f2 = (float_T)n2; - } - } - tv_clear(rettv); - - // If there is a float on either side the result is a float. - if (rettv->v_type == VAR_FLOAT || var2.v_type == VAR_FLOAT) { - if (op == '+') { - f1 = f1 + f2; - } else { - f1 = f1 - f2; - } - rettv->v_type = VAR_FLOAT; - rettv->vval.v_float = f1; - } else { - if (op == '+') { - n1 = n1 + n2; - } else { - n1 = n1 - n2; - } - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = n1; + if (eval_addsub_number(rettv, &var2, op) == FAIL) { + return FAIL; } } tv_clear(&var2); @@ -2972,6 +3193,85 @@ static int eval5(char **arg, typval_T *rettv, evalarg_T *const evalarg) return OK; } +/// Multiply or divide or compute the modulo of numbers "tv1" and "tv2" and +/// store the result in "tv1". The numbers can be whole numbers or floats. +static int eval_multdiv_number(typval_T *tv1, typval_T *tv2, int op) + FUNC_ATTR_NO_SANITIZE_UNDEFINED +{ + varnumber_T n1, n2; + bool use_float = false; + + float_T f1 = 0; + float_T f2 = 0; + bool error = false; + if (tv1->v_type == VAR_FLOAT) { + f1 = tv1->vval.v_float; + use_float = true; + n1 = 0; + } else { + n1 = tv_get_number_chk(tv1, &error); + } + tv_clear(tv1); + if (error) { + tv_clear(tv2); + return FAIL; + } + + if (tv2->v_type == VAR_FLOAT) { + if (!use_float) { + f1 = (float_T)n1; + use_float = true; + } + f2 = tv2->vval.v_float; + n2 = 0; + } else { + n2 = tv_get_number_chk(tv2, &error); + tv_clear(tv2); + if (error) { + return FAIL; + } + if (use_float) { + f2 = (float_T)n2; + } + } + + // Compute the result. + // When either side is a float the result is a float. + if (use_float) { + if (op == '*') { + f1 = f1 * f2; + } else if (op == '/') { + // uncrustify:off + + // Division by zero triggers error from AddressSanitizer + f1 = (f2 == 0 ? ( +#ifdef NAN + f1 == 0 ? (float_T)NAN : +#endif + (f1 > 0 ? (float_T)INFINITY : (float_T)-INFINITY)) : f1 / f2); + + // uncrustify:on + } else { + emsg(_("E804: Cannot use '%' with Float")); + return FAIL; + } + tv1->v_type = VAR_FLOAT; + tv1->vval.v_float = f1; + } else { + if (op == '*') { + n1 = n1 * n2; + } else if (op == '/') { + n1 = num_divide(n1, n2); + } else { + n1 = num_modulus(n1, n2); + } + tv1->v_type = VAR_NUMBER; + tv1->vval.v_number = n1; + } + + return OK; +} + /// Handle fifth level expression: /// - * number multiplication /// - / number division @@ -2985,10 +3285,7 @@ static int eval5(char **arg, typval_T *rettv, evalarg_T *const evalarg) /// float /// @return OK or FAIL. static int eval6(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool want_string) - FUNC_ATTR_NO_SANITIZE_UNDEFINED { - bool use_float = false; - // Get the first variable. if (eval7(arg, rettv, evalarg, want_string) == FAIL) { return FAIL; @@ -3001,26 +3298,7 @@ static int eval6(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan break; } - varnumber_T n1, n2; - float_T f1 = 0; - float_T f2 = 0; - bool error = false; const bool evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE); - if (evaluate) { - if (rettv->v_type == VAR_FLOAT) { - f1 = rettv->vval.v_float; - use_float = true; - n1 = 0; - } else { - n1 = tv_get_number_chk(rettv, &error); - } - tv_clear(rettv); - if (error) { - return FAIL; - } - } else { - n1 = 0; - } // Get the second variable. *arg = skipwhite(*arg + 1); @@ -3030,56 +3308,9 @@ static int eval6(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan } if (evaluate) { - if (var2.v_type == VAR_FLOAT) { - if (!use_float) { - f1 = (float_T)n1; - use_float = true; - } - f2 = var2.vval.v_float; - n2 = 0; - } else { - n2 = tv_get_number_chk(&var2, &error); - tv_clear(&var2); - if (error) { - return FAIL; - } - if (use_float) { - f2 = (float_T)n2; - } - } - // Compute the result. - // When either side is a float the result is a float. - if (use_float) { - if (op == '*') { - f1 = f1 * f2; - } else if (op == '/') { - // uncrustify:off - - // Division by zero triggers error from AddressSanitizer - f1 = (f2 == 0 ? ( -#ifdef NAN - f1 == 0 ? (float_T)NAN : -#endif - (f1 > 0 ? (float_T)INFINITY : (float_T)-INFINITY)) : f1 / f2); - - // uncrustify:on - } else { - emsg(_("E804: Cannot use '%' with Float")); - return FAIL; - } - rettv->v_type = VAR_FLOAT; - rettv->vval.v_float = f1; - } else { - if (op == '*') { - n1 = n1 * n2; - } else if (op == '/') { - n1 = num_divide(n1, n2); - } else { - n1 = num_modulus(n1, n2); - } - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = n1; + if (eval_multdiv_number(rettv, &var2, op) == FAIL) { + return FAIL; } } } @@ -3183,14 +3414,9 @@ static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan ret = eval_list(arg, rettv, evalarg); break; - // Dictionary: #{key: val, key: val} + // Literal Dictionary: #{key: val, key: val} case '#': - if ((*arg)[1] == '{') { - (*arg)++; - ret = eval_dict(arg, rettv, evalarg, true); - } else { - ret = NOTDONE; - } + ret = eval_lit_dict(arg, rettv, evalarg); break; // Lambda: {arg, arg -> expr} @@ -3480,20 +3706,22 @@ static int eval_method(char **const arg, typval_T *const rettv, evalarg_T *const int len; char *name = *arg; char *lua_funcname = NULL; + char *alias = NULL; if (strnequal(name, "v:lua.", 6)) { lua_funcname = name + 6; *arg = (char *)skip_luafunc_name(lua_funcname); *arg = skipwhite(*arg); // to detect trailing whitespace later len = (int)(*arg - lua_funcname); } else { - char *alias; len = get_name_len((const char **)arg, &alias, evaluate, true); if (alias != NULL) { name = alias; } } - int ret; + char *tofree = NULL; + int ret = OK; + if (len <= 0) { if (verbose) { if (lua_funcname == NULL) { @@ -3504,25 +3732,79 @@ static int eval_method(char **const arg, typval_T *const rettv, evalarg_T *const } ret = FAIL; } else { - if (**arg != '(') { - if (verbose) { - semsg(_(e_missingparen), name); - } - ret = FAIL; - } else if (ascii_iswhite((*arg)[-1])) { - if (verbose) { - emsg(_(e_nowhitespace)); + *arg = skipwhite(*arg); + + // If there is no "(" immediately following, but there is further on, + // it can be "dict.Func()", "list[nr]", etc. + // Does not handle anything where "(" is part of the expression. + char *paren; + if (**arg != '(' && lua_funcname == NULL && alias == NULL + && (paren = vim_strchr(*arg, '(')) != NULL) { + *arg = name; + *paren = NUL; + typval_T ref; + ref.v_type = VAR_UNKNOWN; + if (eval7(arg, &ref, evalarg, false) == FAIL) { + *arg = name + len; + ret = FAIL; + } else if (*skipwhite(*arg) != NUL) { + if (verbose) { + semsg(_(e_trailing_arg), *arg); + } + ret = FAIL; + } else if (ref.v_type == VAR_FUNC && ref.vval.v_string != NULL) { + name = ref.vval.v_string; + ref.vval.v_string = NULL; + tofree = name; + len = (int)strlen(name); + } else if (ref.v_type == VAR_PARTIAL && ref.vval.v_partial != NULL) { + if (ref.vval.v_partial->pt_argc > 0 || ref.vval.v_partial->pt_dict != NULL) { + if (verbose) { + emsg(_(e_cannot_use_partial_here)); + } + ret = FAIL; + } else { + name = xstrdup(partial_name(ref.vval.v_partial)); + tofree = name; + if (name == NULL) { + ret = FAIL; + name = *arg; + } else { + len = (int)strlen(name); + } + } + } else { + if (verbose) { + semsg(_(e_not_callable_type_str), name); + } + ret = FAIL; } - ret = FAIL; - } else if (lua_funcname != NULL) { - if (evaluate) { - rettv->v_type = VAR_PARTIAL; - rettv->vval.v_partial = vvlua_partial; - rettv->vval.v_partial->pt_refcount++; + tv_clear(&ref); + *paren = '('; + } + + if (ret == OK) { + if (**arg != '(') { + if (verbose) { + semsg(_(e_missingparen), name); + } + ret = FAIL; + } else if (ascii_iswhite((*arg)[-1])) { + if (verbose) { + emsg(_(e_nowhitespace)); + } + ret = FAIL; + } else if (lua_funcname != NULL) { + if (evaluate) { + rettv->v_type = VAR_PARTIAL; + rettv->vval.v_partial = vvlua_partial; + rettv->vval.v_partial->pt_refcount++; + } + ret = call_func_rettv(arg, evalarg, rettv, evaluate, NULL, &base, lua_funcname); + } else { + ret = eval_func(arg, evalarg, name, len, rettv, + evaluate ? EVAL_EVALUATE : 0, &base); } - ret = call_func_rettv(arg, evalarg, rettv, evaluate, NULL, &base, lua_funcname); - } else { - ret = eval_func(arg, evalarg, name, len, rettv, evaluate ? EVAL_EVALUATE : 0, &base); } } @@ -3531,6 +3813,11 @@ static int eval_method(char **const arg, typval_T *const rettv, evalarg_T *const if (evaluate) { tv_clear(&base); } + xfree(tofree); + + if (alias != NULL) { + xfree(alias); + } return ret; } @@ -3669,7 +3956,7 @@ static int check_can_index(typval_T *rettv, bool evaluate, bool verbose) /// slice() function void f_slice(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - if (check_can_index(argvars, true, false) != OK) { + if (check_can_index(&argvars[0], true, false) != OK) { return; } @@ -4386,7 +4673,7 @@ bool func_equal(typval_T *tv1, typval_T *tv2, bool ic) if (d1 != d2) { return false; } - } else if (!tv_dict_equal(d1, d2, ic, true)) { + } else if (!tv_dict_equal(d1, d2, ic)) { return false; } @@ -4398,7 +4685,7 @@ bool func_equal(typval_T *tv1, typval_T *tv2, bool ic) } for (int i = 0; i < a1; i++) { if (!tv_equal(tv1->vval.v_partial->pt_argv + i, - tv2->vval.v_partial->pt_argv + i, ic, true)) { + tv2->vval.v_partial->pt_argv + i, ic)) { return false; } } @@ -4493,19 +4780,6 @@ bool garbage_collect(bool testing) FOR_ALL_BUFFERS(buf) { // buffer-local variables ABORTING(set_ref_in_item)(&buf->b_bufvar.di_tv, copyID, NULL, NULL); - // buffer marks (ShaDa additional data) - ABORTING(set_ref_in_fmark)(buf->b_last_cursor, copyID); - ABORTING(set_ref_in_fmark)(buf->b_last_insert, copyID); - ABORTING(set_ref_in_fmark)(buf->b_last_change, copyID); - for (size_t i = 0; i < NMARKS; i++) { - ABORTING(set_ref_in_fmark)(buf->b_namedm[i], copyID); - } - // buffer change list (ShaDa additional data) - for (int i = 0; i < buf->b_changelistlen; i++) { - ABORTING(set_ref_in_fmark)(buf->b_changelist[i], copyID); - } - // buffer ShaDa additional data - ABORTING(set_ref_dict)(buf->additional_data, copyID); // buffer callback functions ABORTING(set_ref_in_callback)(&buf->b_prompt_callback, copyID, NULL, NULL); @@ -4528,10 +4802,6 @@ bool garbage_collect(bool testing) FOR_ALL_TAB_WINDOWS(tp, wp) { // window-local variables ABORTING(set_ref_in_item)(&wp->w_winvar.di_tv, copyID, NULL, NULL); - // window jump list (ShaDa additional data) - for (int i = 0; i < wp->w_jumplistlen; i++) { - ABORTING(set_ref_in_fmark)(wp->w_jumplist[i].fmark, copyID); - } } // window-local variables in autocmd windows for (int i = 0; i < AUCMD_WIN_COUNT; i++) { @@ -4548,9 +4818,6 @@ bool garbage_collect(bool testing) char name = NUL; bool is_unnamed = false; reg_iter = op_global_reg_iter(reg_iter, &name, ®, &is_unnamed); - if (name != NUL) { - ABORTING(set_ref_dict)(reg.additional_data, copyID); - } } while (reg_iter != ITER_REGISTER_NULL); } @@ -4561,9 +4828,6 @@ bool garbage_collect(bool testing) xfmark_T fm; char name = NUL; mark_iter = mark_global_iter(mark_iter, &name, &fm); - if (name != NUL) { - ABORTING(set_ref_dict)(fm.fmark.additional_data, copyID); - } } while (mark_iter != NULL); } @@ -4605,36 +4869,6 @@ bool garbage_collect(bool testing) // v: vars ABORTING(set_ref_in_ht)(&vimvarht, copyID, NULL); - // history items (ShaDa additional elements) - if (p_hi) { - for (int i = 0; i < HIST_COUNT; i++) { - const void *iter = NULL; - do { - histentry_T hist; - iter = hist_iter(iter, (uint8_t)i, false, &hist); - if (hist.hisstr != NULL) { - ABORTING(set_ref_list)(hist.additional_elements, copyID); - } - } while (iter != NULL); - } - } - - // previously used search/substitute patterns (ShaDa additional data) - { - SearchPattern pat; - get_search_pattern(&pat); - ABORTING(set_ref_dict)(pat.additional_data, copyID); - get_substitute_pattern(&pat); - ABORTING(set_ref_dict)(pat.additional_data, copyID); - } - - // previously used replacement string - { - SubReplacementString sub; - sub_get_replacement(&sub); - ABORTING(set_ref_list)(sub.additional_elements, copyID); - } - ABORTING(set_ref_in_quickfix)(copyID); bool did_free = false; @@ -4916,52 +5150,6 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, list_stack return abort; } -/// Mark all lists and dicts referenced in given mark -/// -/// @return true if setting references failed somehow. -static inline bool set_ref_in_fmark(fmark_T fm, int copyID) - FUNC_ATTR_WARN_UNUSED_RESULT -{ - if (fm.additional_data != NULL - && fm.additional_data->dv_copyID != copyID) { - fm.additional_data->dv_copyID = copyID; - return set_ref_in_ht(&fm.additional_data->dv_hashtab, copyID, NULL); - } - return false; -} - -/// Mark all lists and dicts referenced in given list and the list itself -/// -/// @return true if setting references failed somehow. -static inline bool set_ref_list(list_T *list, int copyID) - FUNC_ATTR_WARN_UNUSED_RESULT -{ - if (list != NULL) { - typval_T tv = (typval_T) { - .v_type = VAR_LIST, - .vval = { .v_list = list } - }; - return set_ref_in_item(&tv, copyID, NULL, NULL); - } - return false; -} - -/// Mark all lists and dicts referenced in given dict and the dict itself -/// -/// @return true if setting references failed somehow. -static inline bool set_ref_dict(dict_T *dict, int copyID) - FUNC_ATTR_WARN_UNUSED_RESULT -{ - if (dict != NULL) { - typval_T tv = (typval_T) { - .v_type = VAR_DICT, - .vval = { .v_dict = dict } - }; - return set_ref_in_item(&tv, copyID, NULL, NULL); - } - return false; -} - /// Get the key for #{key: val} into "tv" and advance "arg". /// /// @return FAIL when there is no valid key. @@ -5093,6 +5281,24 @@ failret: return OK; } +/// Evaluate a literal dictionary: #{key: val, key: val} +/// "*arg" points to the "#". +/// On return, "*arg" points to the character after the Dict. +/// Return OK or FAIL. Returns NOTDONE for {expr}. +static int eval_lit_dict(char **arg, typval_T *rettv, evalarg_T *const evalarg) +{ + int ret = OK; + + if ((*arg)[1] == '{') { + (*arg)++; + ret = eval_dict(arg, rettv, evalarg, true); + } else { + ret = NOTDONE; + } + + return ret; +} + /// Convert the string to a floating point number /// /// This uses strtod(). setlocale(LC_NUMERIC, "C") has been used earlier to @@ -5569,317 +5775,6 @@ void f_foreach(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) filter_map(argvars, rettv, FILTERMAP_FOREACH); } -/// "function()" function -/// "funcref()" function -void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref) -{ - char *s; - char *name; - bool use_string = false; - partial_T *arg_pt = NULL; - char *trans_name = NULL; - - if (argvars[0].v_type == VAR_FUNC) { - // function(MyFunc, [arg], dict) - s = argvars[0].vval.v_string; - } else if (argvars[0].v_type == VAR_PARTIAL - && argvars[0].vval.v_partial != NULL) { - // function(dict.MyFunc, [arg]) - arg_pt = argvars[0].vval.v_partial; - s = partial_name(arg_pt); - // TODO(bfredl): do the entire nlua_is_table_from_lua dance - } else { - // function('MyFunc', [arg], dict) - s = (char *)tv_get_string(&argvars[0]); - use_string = true; - } - - if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref) { - name = s; - trans_name = save_function_name(&name, false, - TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL); - if (*name != NUL) { - s = NULL; - } - } - if (s == NULL || *s == NUL || (use_string && ascii_isdigit(*s)) - || (is_funcref && trans_name == NULL)) { - semsg(_(e_invarg2), (use_string ? tv_get_string(&argvars[0]) : s)); - // Don't check an autoload name for existence here. - } else if (trans_name != NULL - && (is_funcref - ? find_func(trans_name) == NULL - : !translated_function_exists(trans_name))) { - semsg(_("E700: Unknown function: %s"), s); - } else { - int dict_idx = 0; - int arg_idx = 0; - list_T *list = NULL; - if (strncmp(s, "s:", 2) == 0 || strncmp(s, "<SID>", 5) == 0) { - // Expand s: and <SID> into <SNR>nr_, so that the function can - // also be called from another script. Using trans_function_name() - // would also work, but some plugins depend on the name being - // printable text. - name = get_scriptlocal_funcname(s); - } else { - name = xstrdup(s); - } - - if (argvars[1].v_type != VAR_UNKNOWN) { - if (argvars[2].v_type != VAR_UNKNOWN) { - // function(name, [args], dict) - arg_idx = 1; - dict_idx = 2; - } else if (argvars[1].v_type == VAR_DICT) { - // function(name, dict) - dict_idx = 1; - } else { - // function(name, [args]) - arg_idx = 1; - } - if (dict_idx > 0) { - if (tv_check_for_dict_arg(argvars, dict_idx) == FAIL) { - xfree(name); - goto theend; - } - if (argvars[dict_idx].vval.v_dict == NULL) { - dict_idx = 0; - } - } - if (arg_idx > 0) { - if (argvars[arg_idx].v_type != VAR_LIST) { - emsg(_("E923: Second argument of function() must be " - "a list or a dict")); - xfree(name); - goto theend; - } - list = argvars[arg_idx].vval.v_list; - if (tv_list_len(list) == 0) { - arg_idx = 0; - } else if (tv_list_len(list) > MAX_FUNC_ARGS) { - emsg_funcname(e_toomanyarg, s); - xfree(name); - goto theend; - } - } - } - if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref) { - partial_T *const pt = xcalloc(1, sizeof(*pt)); - - // result is a VAR_PARTIAL - if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0)) { - const int arg_len = (arg_pt == NULL ? 0 : arg_pt->pt_argc); - const int lv_len = tv_list_len(list); - - pt->pt_argc = arg_len + lv_len; - pt->pt_argv = xmalloc(sizeof(pt->pt_argv[0]) * (size_t)pt->pt_argc); - int i = 0; - for (; i < arg_len; i++) { - tv_copy(&arg_pt->pt_argv[i], &pt->pt_argv[i]); - } - if (lv_len > 0) { - TV_LIST_ITER(list, li, { - tv_copy(TV_LIST_ITEM_TV(li), &pt->pt_argv[i++]); - }); - } - } - - // For "function(dict.func, [], dict)" and "func" is a partial - // use "dict". That is backwards compatible. - if (dict_idx > 0) { - // The dict is bound explicitly, pt_auto is false - pt->pt_dict = argvars[dict_idx].vval.v_dict; - (pt->pt_dict->dv_refcount)++; - } else if (arg_pt != NULL) { - // If the dict was bound automatically the result is also - // bound automatically. - pt->pt_dict = arg_pt->pt_dict; - pt->pt_auto = arg_pt->pt_auto; - if (pt->pt_dict != NULL) { - (pt->pt_dict->dv_refcount)++; - } - } - - pt->pt_refcount = 1; - if (arg_pt != NULL && arg_pt->pt_func != NULL) { - pt->pt_func = arg_pt->pt_func; - func_ptr_ref(pt->pt_func); - xfree(name); - } else if (is_funcref) { - pt->pt_func = find_func(trans_name); - func_ptr_ref(pt->pt_func); - xfree(name); - } else { - pt->pt_name = name; - func_ref(name); - } - - rettv->v_type = VAR_PARTIAL; - rettv->vval.v_partial = pt; - } else { - // result is a VAR_FUNC - rettv->v_type = VAR_FUNC; - rettv->vval.v_string = name; - func_ref(name); - } - } -theend: - xfree(trans_name); -} - -/// Get the line number from Vimscript object -/// -/// @note Unlike tv_get_lnum(), this one supports only "$" special string. -/// -/// @param[in] tv Object to get value from. Is expected to be a number or -/// a special string "$". -/// @param[in] buf Buffer to take last line number from in case tv is "$". May -/// be NULL, in this case "$" results in zero return. -/// -/// @return Line number or 0 in case of error. -linenr_T tv_get_lnum_buf(const typval_T *const tv, const buf_T *const buf) - FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT -{ - if (tv->v_type == VAR_STRING - && tv->vval.v_string != NULL - && tv->vval.v_string[0] == '$' - && tv->vval.v_string[1] == NUL - && buf != NULL) { - return buf->b_ml.ml_line_count; - } - return (linenr_T)tv_get_number_chk(tv, NULL); -} - -/// This function is used by f_input() and f_inputdialog() functions. The third -/// argument to f_input() specifies the type of completion to use at the -/// prompt. The third argument to f_inputdialog() specifies the value to return -/// when the user cancels the prompt. -void get_user_input(const typval_T *const argvars, typval_T *const rettv, const bool inputdialog, - const bool secret) - FUNC_ATTR_NONNULL_ALL -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - - const char *prompt; - const char *defstr = ""; - typval_T *cancelreturn = NULL; - typval_T cancelreturn_strarg2 = TV_INITIAL_VALUE; - const char *xp_name = NULL; - Callback input_callback = { .type = kCallbackNone }; - char prompt_buf[NUMBUFLEN]; - char defstr_buf[NUMBUFLEN]; - char cancelreturn_buf[NUMBUFLEN]; - char xp_name_buf[NUMBUFLEN]; - char def[1] = { 0 }; - if (argvars[0].v_type == VAR_DICT) { - if (argvars[1].v_type != VAR_UNKNOWN) { - emsg(_("E5050: {opts} must be the only argument")); - return; - } - dict_T *const dict = argvars[0].vval.v_dict; - prompt = tv_dict_get_string_buf_chk(dict, S_LEN("prompt"), prompt_buf, ""); - if (prompt == NULL) { - return; - } - defstr = tv_dict_get_string_buf_chk(dict, S_LEN("default"), defstr_buf, ""); - if (defstr == NULL) { - return; - } - dictitem_T *cancelreturn_di = tv_dict_find(dict, S_LEN("cancelreturn")); - if (cancelreturn_di != NULL) { - cancelreturn = &cancelreturn_di->di_tv; - } - xp_name = tv_dict_get_string_buf_chk(dict, S_LEN("completion"), - xp_name_buf, def); - if (xp_name == NULL) { // error - return; - } - if (xp_name == def) { // default to NULL - xp_name = NULL; - } - if (!tv_dict_get_callback(dict, S_LEN("highlight"), &input_callback)) { - return; - } - } else { - prompt = tv_get_string_buf_chk(&argvars[0], prompt_buf); - if (prompt == NULL) { - return; - } - if (argvars[1].v_type != VAR_UNKNOWN) { - defstr = tv_get_string_buf_chk(&argvars[1], defstr_buf); - if (defstr == NULL) { - return; - } - if (argvars[2].v_type != VAR_UNKNOWN) { - const char *const strarg2 = tv_get_string_buf_chk(&argvars[2], cancelreturn_buf); - if (strarg2 == NULL) { - return; - } - if (inputdialog) { - cancelreturn_strarg2.v_type = VAR_STRING; - cancelreturn_strarg2.vval.v_string = (char *)strarg2; - cancelreturn = &cancelreturn_strarg2; - } else { - xp_name = strarg2; - } - } - } - } - - int xp_type = EXPAND_NOTHING; - char *xp_arg = NULL; - if (xp_name != NULL) { - // input() with a third argument: completion - const int xp_namelen = (int)strlen(xp_name); - - uint32_t argt = 0; - if (parse_compl_arg(xp_name, xp_namelen, &xp_type, - &argt, &xp_arg) == FAIL) { - return; - } - } - - const bool cmd_silent_save = cmd_silent; - - cmd_silent = false; // Want to see the prompt. - // Only the part of the message after the last NL is considered as - // prompt for the command line, unlsess cmdline is externalized - const char *p = prompt; - if (!ui_has(kUICmdline)) { - const char *lastnl = strrchr(prompt, '\n'); - if (lastnl != NULL) { - p = lastnl + 1; - msg_start(); - msg_clr_eos(); - msg_puts_len(prompt, p - prompt, echo_attr); - msg_didout = false; - msg_starthere(); - } - } - cmdline_row = msg_row; - - stuffReadbuffSpec(defstr); - - const int save_ex_normal_busy = ex_normal_busy; - ex_normal_busy = 0; - rettv->vval.v_string = getcmdline_prompt(secret ? NUL : '@', p, echo_attr, xp_type, xp_arg, - input_callback); - ex_normal_busy = save_ex_normal_busy; - callback_free(&input_callback); - - if (rettv->vval.v_string == NULL && cancelreturn != NULL) { - tv_copy(cancelreturn, rettv); - } - - xfree(xp_arg); - - // Since the user typed this, no need to wait for return. - need_wait_return = false; - msg_didout = false; - cmd_silent = cmd_silent_save; -} - /// Builds a process argument vector from a Vimscript object (typval_T). /// /// @param[in] cmd_tv Vimscript object @@ -5948,56 +5843,6 @@ char **tv_to_argv(typval_T *cmd_tv, const char **cmd, bool *executable) return argv; } -void return_register(int regname, typval_T *rettv) -{ - char buf[2] = { (char)regname, 0 }; - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = xstrdup(buf); -} - -void screenchar_adjust(ScreenGrid **grid, int *row, int *col) -{ - // TODO(bfredl): this is a hack for legacy tests which use screenchar() - // to check printed messages on the screen (but not floats etc - // as these are not legacy features). If the compositor is refactored to - // have its own buffer, this should just read from it instead. - msg_scroll_flush(); - - *grid = ui_comp_get_grid_at_coord(*row, *col); - - // Make `row` and `col` relative to the grid - *row -= (*grid)->comp_row; - *col -= (*grid)->comp_col; -} - -/// "stdpath()" helper for list results -void get_xdg_var_list(const XDGVarType xdg, typval_T *rettv) - FUNC_ATTR_NONNULL_ALL -{ - list_T *const list = tv_list_alloc(kListLenShouldKnow); - rettv->v_type = VAR_LIST; - rettv->vval.v_list = list; - tv_list_ref(list); - char *const dirs = stdpaths_get_xdg_var(xdg); - if (dirs == NULL) { - return; - } - const void *iter = NULL; - const char *appname = get_appname(); - do { - size_t dir_len; - const char *dir; - iter = vim_env_iter(ENV_SEPCHAR, dirs, iter, &dir, &dir_len); - if (dir != NULL && dir_len > 0) { - char *dir_with_nvim = xmemdupz(dir, dir_len); - dir_with_nvim = concat_fnames_realloc(dir_with_nvim, appname, true); - tv_list_append_allocated_string(list, dir_with_nvim); - } - } while (iter != NULL); - xfree(dirs); -} - static list_T *string_to_list(const char *str, size_t len, const bool keepempty) { if (!keepempty && str[len - 1] == NL) { @@ -6417,149 +6262,6 @@ void timer_teardown(void) timer_stop_all(); } -/// Write "list" of strings to file "fd". -/// -/// @param fp File to write to. -/// @param[in] list List to write. -/// @param[in] binary Whether to write in binary mode. -/// -/// @return true in case of success, false otherwise. -bool write_list(FileDescriptor *const fp, const list_T *const list, const bool binary) - FUNC_ATTR_NONNULL_ARG(1) -{ - int error = 0; - TV_LIST_ITER_CONST(list, li, { - const char *const s = tv_get_string_chk(TV_LIST_ITEM_TV(li)); - if (s == NULL) { - return false; - } - const char *hunk_start = s; - for (const char *p = hunk_start;; p++) { - if (*p == NUL || *p == NL) { - if (p != hunk_start) { - const ptrdiff_t written = file_write(fp, hunk_start, - (size_t)(p - hunk_start)); - if (written < 0) { - error = (int)written; - goto write_list_error; - } - } - if (*p == NUL) { - break; - } else { - hunk_start = p + 1; - const ptrdiff_t written = file_write(fp, (char[]){ NUL }, 1); - if (written < 0) { - error = (int)written; - break; - } - } - } - } - if (!binary || TV_LIST_ITEM_NEXT(list, li) != NULL) { - const ptrdiff_t written = file_write(fp, "\n", 1); - if (written < 0) { - error = (int)written; - goto write_list_error; - } - } - }); - if ((error = file_flush(fp)) != 0) { - goto write_list_error; - } - return true; -write_list_error: - semsg(_(e_write2), os_strerror(error)); - return false; -} - -/// Write a blob to file with descriptor `fp`. -/// -/// @param[in] fp File to write to. -/// @param[in] blob Blob to write. -/// -/// @return true on success, or false on failure. -bool write_blob(FileDescriptor *const fp, const blob_T *const blob) - FUNC_ATTR_NONNULL_ARG(1) -{ - int error = 0; - const int len = tv_blob_len(blob); - if (len > 0) { - const ptrdiff_t written = file_write(fp, blob->bv_ga.ga_data, (size_t)len); - if (written < (ptrdiff_t)len) { - error = (int)written; - goto write_blob_error; - } - } - error = file_flush(fp); - if (error != 0) { - goto write_blob_error; - } - return true; -write_blob_error: - semsg(_(e_write2), os_strerror(error)); - return false; -} - -/// Read blob from file "fd". -/// Caller has allocated a blob in "rettv". -/// -/// @param[in] fd File to read from. -/// @param[in,out] rettv Blob to write to. -/// @param[in] offset Read the file from the specified offset. -/// @param[in] size Read the specified size, or -1 if no limit. -/// -/// @return OK on success, or FAIL on failure. -int read_blob(FILE *const fd, typval_T *rettv, off_T offset, off_T size_arg) - FUNC_ATTR_NONNULL_ALL -{ - blob_T *const blob = rettv->vval.v_blob; - FileInfo file_info; - if (!os_fileinfo_fd(fileno(fd), &file_info)) { - return FAIL; // can't read the file, error - } - - int whence; - off_T size = size_arg; - const off_T file_size = (off_T)os_fileinfo_size(&file_info); - if (offset >= 0) { - // The size defaults to the whole file. If a size is given it is - // limited to not go past the end of the file. - if (size == -1 || (size > file_size - offset && !S_ISCHR(file_info.stat.st_mode))) { - // size may become negative, checked below - size = (off_T)os_fileinfo_size(&file_info) - offset; - } - whence = SEEK_SET; - } else { - // limit the offset to not go before the start of the file - if (-offset > file_size && !S_ISCHR(file_info.stat.st_mode)) { - offset = -file_size; - } - // Size defaults to reading until the end of the file. - if (size == -1 || size > -offset) { - size = -offset; - } - whence = SEEK_END; - } - if (size <= 0) { - return OK; - } - if (offset != 0 && vim_fseek(fd, offset, whence) != 0) { - return OK; - } - - ga_grow(&blob->bv_ga, (int)size); - blob->bv_ga.ga_len = (int)size; - if (fread(blob->bv_ga.ga_data, 1, (size_t)blob->bv_ga.ga_len, fd) - < (size_t)blob->bv_ga.ga_len) { - // An empty blob is returned on error. - tv_blob_free(rettv->vval.v_blob); - rettv->vval.v_blob = NULL; - return FAIL; - } - return OK; -} - /// Saves a typval_T as a string. /// /// For lists or buffers, replaces NLs with NUL and separates items with NLs. @@ -7146,13 +6848,13 @@ static char *make_expanded_name(const char *in_start, char *expr_start, char *ex char c1 = *in_end; *in_end = NUL; - char *temp_result = eval_to_string(expr_start + 1, false); + char *temp_result = eval_to_string(expr_start + 1, false, false); if (temp_result != NULL) { retval = xmalloc(strlen(temp_result) + (size_t)(expr_start - in_start) + (size_t)(in_end - expr_end) + 1); STRCPY(retval, in_start); - STRCAT(retval, temp_result); - STRCAT(retval, expr_end + 1); + strcat(retval, temp_result); + strcat(retval, expr_end + 1); } xfree(temp_result); @@ -8201,6 +7903,12 @@ void ex_echohl(exarg_T *eap) echo_attr = syn_name2attr(eap->arg); } +/// Returns the :echo attribute +int get_echo_attr(void) +{ + return echo_attr; +} + /// ":execute expr1 ..." execute the result of an expression. /// ":echomsg expr1 ..." Print a message /// ":echoerr expr1 ..." Print an error @@ -8796,7 +8504,7 @@ Channel *find_job(uint64_t id, bool show_error) { Channel *data = find_channel(id); if (!data || data->streamtype != kChannelStreamProc - || process_is_stopped(&data->stream.proc)) { + || proc_is_stopped(&data->stream.proc)) { if (show_error) { if (data && data->streamtype != kChannelStreamProc) { emsg(_(e_invchanjob)); @@ -8907,7 +8615,7 @@ bool eval_has_provider(const char *feat, bool throw_if_fast) char name[32]; // Normalized: "python3_compiled" => "python3". snprintf(name, sizeof(name), "%s", feat); - strchrsub(name, '_', '\0'); // Chop any "_xx" suffix. + strchrsub(name, '_', NUL); // Chop any "_xx" suffix. char buf[256]; typval_T tv; @@ -9062,7 +8770,7 @@ int typval_compare(typval_T *typ1, typval_T *typ2, exprtype_T type, bool ic) return FAIL; } else { // Compare two Lists for being equal or unequal. - n1 = tv_list_equal(typ1->vval.v_list, typ2->vval.v_list, ic, false); + n1 = tv_list_equal(typ1->vval.v_list, typ2->vval.v_list, ic); if (type == EXPR_NEQUAL) { n1 = !n1; } @@ -9085,7 +8793,7 @@ int typval_compare(typval_T *typ1, typval_T *typ2, exprtype_T type, bool ic) return FAIL; } else { // Compare two Dictionaries for being equal or unequal. - n1 = tv_dict_equal(typ1->vval.v_dict, typ2->vval.v_dict, ic, false); + n1 = tv_dict_equal(typ1->vval.v_dict, typ2->vval.v_dict, ic); if (type == EXPR_NEQUAL) { n1 = !n1; } @@ -9106,14 +8814,14 @@ int typval_compare(typval_T *typ1, typval_T *typ2, exprtype_T type, bool ic) if (typ1->v_type == VAR_FUNC && typ2->v_type == VAR_FUNC) { // strings are considered the same if their value is // the same - n1 = tv_equal(typ1, typ2, ic, false); + n1 = tv_equal(typ1, typ2, ic); } else if (typ1->v_type == VAR_PARTIAL && typ2->v_type == VAR_PARTIAL) { n1 = typ1->vval.v_partial == typ2->vval.v_partial; } else { n1 = false; } } else { - n1 = tv_equal(typ1, typ2, ic, false); + n1 = tv_equal(typ1, typ2, ic); } if (type == EXPR_NEQUAL || type == EXPR_ISNOT) { n1 = !n1; diff --git a/src/nvim/eval.h b/src/nvim/eval.h index d83af70ef7..bb9b00abc7 100644 --- a/src/nvim/eval.h +++ b/src/nvim/eval.h @@ -61,7 +61,7 @@ typedef struct { bool ll_empty2; ///< Second index is empty: [i:]. int ll_n1; ///< First index for list. int ll_n2; ///< Second index for list range. - dict_T *ll_dict; ///< The Dictionary or NULL. + dict_T *ll_dict; ///< The Dict or NULL. dictitem_T *ll_di; ///< The dictitem or NULL. char *ll_newkey; ///< New key for Dict in allocated memory or NULL. blob_T *ll_blob; ///< The Blob or NULL. @@ -172,7 +172,7 @@ typedef enum { VV_MSGPACK_TYPES, VV__NULL_STRING, // String with NULL value. For test purposes only. VV__NULL_LIST, // List with NULL value. For test purposes only. - VV__NULL_DICT, // Dictionary with NULL value. For test purposes only. + VV__NULL_DICT, // Dict with NULL value. For test purposes only. VV__NULL_BLOB, // Blob with NULL value. For test purposes only. VV_LUA, VV_RELNUM, @@ -237,13 +237,6 @@ typedef enum { EXPR_ISNOT, ///< isnot } exprtype_T; -/// Type for dict_list function -typedef enum { - kDictListKeys, ///< List dictionary keys. - kDictListValues, ///< List dictionary values. - kDictListItems, ///< List dictionary contents: [keys, values]. -} DictListType; - // Used for checking if local variables or arguments used in a lambda. extern bool *eval_lavars_used; diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 7d4438ded6..50aaf9e03b 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -19,7 +19,9 @@ --- @field returns_desc? string --- @field signature? string --- @field desc? string ---- @field params {[1]:string, [2]:string, [3]:string}[] +--- @field params [string, string, string][] +--- @field notes? string[] +--- @field see? string[] --- @field lua? false Do not render type information --- @field tags? string[] Extra tags --- @field data? string Used by gen_eval.lua @@ -52,7 +54,7 @@ M.funcs = { ]=], name = 'abs', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, signature = 'abs({expr})', returns = 'number', }, @@ -75,7 +77,7 @@ M.funcs = { ]=], float_func = 'acos', name = 'acos', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, returns = 'number', signature = 'acos({expr})', }, @@ -97,6 +99,7 @@ M.funcs = { name = 'add', params = { { 'object', 'any' }, { 'expr', 'any' } }, returns = 'any', + returns_desc = [=[Resulting |List| or |Blob|, or 1 if {object} is not a |List| or a |Blob|.]=], signature = 'add({object}, {expr})', }, ['and'] = { @@ -111,7 +114,7 @@ M.funcs = { < ]=], name = 'and', - params = { { 'expr', 'any' }, { 'expr', 'any' } }, + params = { { 'expr', 'number' }, { 'expr', 'number' } }, returns = 'integer', signature = 'and({expr}, {expr})', }, @@ -149,7 +152,7 @@ M.funcs = { ]=], name = 'append', - params = { { 'lnum', 'integer' }, { 'text', 'any' } }, + params = { { 'lnum', 'integer' }, { 'text', 'string|string[]' } }, returns = '0|1', signature = 'append({lnum}, {text})', }, @@ -179,7 +182,7 @@ M.funcs = { ]=], name = 'appendbufline', - params = { { 'buf', 'any' }, { 'lnum', 'integer' }, { 'text', 'string' } }, + params = { { 'buf', 'integer|string' }, { 'lnum', 'integer' }, { 'text', 'string' } }, returns = '0|1', signature = 'appendbufline({buf}, {lnum}, {text})', }, @@ -289,7 +292,7 @@ M.funcs = { ]=], name = 'assert_beeps', - params = { { 'cmd', 'any' } }, + params = { { 'cmd', 'string' } }, returns = '0|1', signature = 'assert_beeps({cmd})', }, @@ -301,16 +304,17 @@ M.funcs = { added to |v:errors| and 1 is returned. Otherwise zero is returned. |assert-return| The error is in the form "Expected {expected} but got - {actual}". When {msg} is present it is prefixed to that. + {actual}". When {msg} is present it is prefixed to that, + along with the location of the assert when run from a script. There is no automatic conversion, the String "4" is different from the Number 4. And the number 4 is different from the Float 4.0. The value of 'ignorecase' is not used here, case always matters. Example: >vim - assert_equal('foo', 'bar') - <Will result in a string to be added to |v:errors|: - test.vim line 12: Expected 'foo' but got 'bar' ~ + call assert_equal('foo', 'bar', 'baz') + <Will add the following to |v:errors|: + test.vim line 12: baz: Expected 'foo' but got 'bar' ~ ]=], name = 'assert_equal', @@ -330,7 +334,7 @@ M.funcs = { ]=], name = 'assert_equalfile', - params = {}, + params = { { 'fname-one', 'string' }, { 'fname-two', 'string' } }, returns = '0|1', signature = 'assert_equalfile({fname-one}, {fname-two})', }, @@ -366,25 +370,25 @@ M.funcs = { When {error} is a string it must be found literally in the first reported error. Most often this will be the error code, including the colon, e.g. "E123:". >vim - assert_fails('bad cmd', 'E987:') + call assert_fails('bad cmd', 'E987:') < When {error} is a |List| with one or two strings, these are used as patterns. The first pattern is matched against the first reported error: >vim - assert_fails('cmd', ['E987:.*expected bool']) + call assert_fails('cmd', ['E987:.*expected bool']) <The second pattern, if present, is matched against the last reported error. To only match the last error use an empty string for the first error: >vim - assert_fails('cmd', ['', 'E987:']) + call assert_fails('cmd', ['', 'E987:']) < If {msg} is empty then it is not used. Do this to get the default message when passing the {lnum} argument. - + *E1115* When {lnum} is present and not negative, and the {error} argument is present and matches, then this is compared with the line number at which the error was reported. That can be the line number in a function or in a script. - + *E1116* When {context} is present it is used as a pattern and matched against the context (script name or function name) where {lnum} is located in. @@ -395,7 +399,7 @@ M.funcs = { ]=], name = 'assert_fails', params = { - { 'cmd', 'any' }, + { 'cmd', 'string' }, { 'error', 'any' }, { 'msg', 'any' }, { 'lnum', 'integer' }, @@ -411,7 +415,8 @@ M.funcs = { When {actual} is not false an error message is added to |v:errors|, like with |assert_equal()|. The error is in the form "Expected False but got {actual}". - When {msg} is present it is prepended to that. + When {msg} is present it is prefixed to that, along with the + location of the assert when run from a script. Also see |assert-return|. A value is false when it is zero. When {actual} is not a @@ -435,7 +440,12 @@ M.funcs = { that. ]=], name = 'assert_inrange', - params = { { 'lower', 'any' }, { 'upper', 'any' }, { 'actual', 'any' }, { 'msg', 'any' } }, + params = { + { 'lower', 'number' }, + { 'upper', 'number' }, + { 'actual', 'number' }, + { 'msg', 'string' }, + }, returns = '0|1', signature = 'assert_inrange({lower}, {upper}, {actual} [, {msg}])', }, @@ -446,7 +456,8 @@ M.funcs = { When {pattern} does not match {actual} an error message is added to |v:errors|. Also see |assert-return|. The error is in the form "Pattern {pattern} does not match - {actual}". When {msg} is present it is prefixed to that. + {actual}". When {msg} is present it is prefixed to that, + along with the location of the assert when run from a script. {pattern} is used as with |expr-=~|: The matching is always done like 'magic' was set and 'cpoptions' is empty, no matter what @@ -457,13 +468,13 @@ M.funcs = { Use both to match the whole text. Example: >vim - assert_match('^f.*o$', 'foobar') + call assert_match('^f.*o$', 'foobar') <Will result in a string to be added to |v:errors|: test.vim line 12: Pattern '^f.*o$' does not match 'foobar' ~ ]=], name = 'assert_match', - params = { { 'pattern', 'any' }, { 'actual', 'any' }, { 'msg', 'any' } }, + params = { { 'pattern', 'string' }, { 'actual', 'string' }, { 'msg', 'string' } }, returns = '0|1', signature = 'assert_match({pattern}, {actual} [, {msg}])', }, @@ -477,7 +488,7 @@ M.funcs = { ]=], name = 'assert_nobeep', - params = { { 'cmd', 'any' } }, + params = { { 'cmd', 'string' } }, returns = '0|1', signature = 'assert_nobeep({cmd})', }, @@ -505,7 +516,7 @@ M.funcs = { ]=], name = 'assert_notmatch', - params = { { 'pattern', 'any' }, { 'actual', 'any' }, { 'msg', 'any' } }, + params = { { 'pattern', 'string' }, { 'actual', 'string' }, { 'msg', 'string' } }, returns = '0|1', signature = 'assert_notmatch({pattern}, {actual} [, {msg}])', }, @@ -518,7 +529,7 @@ M.funcs = { ]=], name = 'assert_report', - params = { { 'msg', 'any' } }, + params = { { 'msg', 'string' } }, returns = '0|1', signature = 'assert_report({msg})', }, @@ -531,11 +542,12 @@ M.funcs = { Also see |assert-return|. A value is |TRUE| when it is a non-zero number or |v:true|. When {actual} is not a number or |v:true| the assert fails. - When {msg} is given it precedes the default message. + When {msg} is given it is prefixed to the default message, + along with the location of the assert when run from a script. ]=], name = 'assert_true', - params = { { 'actual', 'any' }, { 'msg', 'any' } }, + params = { { 'actual', 'any' }, { 'msg', 'string' } }, returns = '0|1', signature = 'assert_true({actual} [, {msg}])', }, @@ -556,7 +568,7 @@ M.funcs = { ]=], float_func = 'atan', name = 'atan', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, returns = 'number', signature = 'atan({expr})', }, @@ -577,7 +589,7 @@ M.funcs = { ]=], name = 'atan2', - params = { { 'expr1', 'any' }, { 'expr2', 'any' } }, + params = { { 'expr1', 'number' }, { 'expr2', 'number' } }, returns = 'number', signature = 'atan2({expr1}, {expr2})', }, @@ -612,7 +624,12 @@ M.funcs = { something went wrong, or browsing is not possible. ]=], name = 'browse', - params = { { 'save', 'any' }, { 'title', 'any' }, { 'initdir', 'any' }, { 'default', 'any' } }, + params = { + { 'save', 'any' }, + { 'title', 'string' }, + { 'initdir', 'string' }, + { 'default', 'string' }, + }, returns = '0|1', signature = 'browse({save}, {title}, {initdir}, {default})', }, @@ -631,7 +648,7 @@ M.funcs = { browsing is not possible, an empty string is returned. ]=], name = 'browsedir', - params = { { 'title', 'any' }, { 'initdir', 'any' } }, + params = { { 'title', 'string' }, { 'initdir', 'string' } }, returns = '0|1', signature = 'browsedir({title}, {initdir})', }, @@ -1000,7 +1017,7 @@ M.funcs = { ]=], float_func = 'ceil', name = 'ceil', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, returns = 'number', signature = 'ceil({expr})', }, @@ -1017,7 +1034,7 @@ M.funcs = { omitted. ]=], name = 'chanclose', - params = { { 'id', 'any' }, { 'stream', 'any' } }, + params = { { 'id', 'integer' }, { 'stream', 'string' } }, returns = '0|1', signature = 'chanclose({id} [, {stream}])', }, @@ -1057,7 +1074,7 @@ M.funcs = { messages, use |rpcnotify()| and |rpcrequest()| instead. ]=], name = 'chansend', - params = { { 'id', 'any' }, { 'data', 'any' } }, + params = { { 'id', 'number' }, { 'data', 'string|string[]' } }, returns = '0|1', signature = 'chansend({id}, {data})', }, @@ -1116,10 +1133,11 @@ M.funcs = { With the cursor on '세' in line 5 with text "여보세요": >vim echo charcol('.') " returns 3 echo col('.') " returns 7 + < ]=], name = 'charcol', - params = { { 'expr', 'any' }, { 'winid', 'integer' } }, + params = { { 'expr', 'string|integer[]' }, { 'winid', 'integer' } }, returns = 'integer', signature = 'charcol({expr} [, {winid}])', }, @@ -1164,8 +1182,8 @@ M.funcs = { params = { { 'string', 'string' }, { 'idx', 'integer' }, - { 'countcc', 'any' }, - { 'utf16', 'any' }, + { 'countcc', 'boolean' }, + { 'utf16', 'boolean' }, }, returns = 'integer', signature = 'charidx({string}, {idx} [, {countcc} [, {utf16}]])', @@ -1194,6 +1212,7 @@ M.funcs = { " ... do some work call chdir(save_dir) endif + < ]=], name = 'chdir', @@ -1229,7 +1248,7 @@ M.funcs = { ]=], name = 'clearmatches', - params = { { 'win', 'any' } }, + params = { { 'win', 'integer' } }, returns = false, signature = 'clearmatches([{win}])', }, @@ -1238,33 +1257,33 @@ M.funcs = { base = 1, desc = [=[ The result is a Number, which is the byte index of the column - position given with {expr}. The accepted positions are: - . the cursor position - $ the end of the cursor line (the result is the - number of bytes in the cursor line plus one) - 'x position of mark x (if the mark is not set, 0 is - returned) - v In Visual mode: the start of the Visual area (the - cursor is the end). When not in Visual mode - returns the cursor position. Differs from |'<| in - that it's updated right away. + position given with {expr}. + For accepted positions see |getpos()|. + When {expr} is "$", it means the end of the cursor line, so + the result is the number of bytes in the cursor line plus one. Additionally {expr} can be [lnum, col]: a |List| with the line and column number. Most useful when the column is "$", to get the last column of a specific line. When "lnum" or "col" is out of range then col() returns zero. + With the optional {winid} argument the values are obtained for that window instead of the current window. + To get the line number use |line()|. To get both use |getpos()|. + For the screen column position use |virtcol()|. For the character position use |charcol()|. + Note that only marks in the current file can be used. + Examples: >vim echo col(".") " column of cursor echo col("$") " length of cursor line plus one echo col("'t") " column of mark t echo col("'" .. markname) " column of mark markname - <The first column is 1. Returns 0 if {expr} is invalid or when + < + The first column is 1. Returns 0 if {expr} is invalid or when the window with ID {winid} is not found. For an uppercase mark the column may actually be in another buffer. @@ -1273,10 +1292,11 @@ M.funcs = { line. Also, when using a <Cmd> mapping the cursor isn't moved, this can be used to obtain the column in Insert mode: >vim imap <F2> <Cmd>echo col(".").."\n"<CR> + < ]=], name = 'col', - params = { { 'expr', 'any' }, { 'winid', 'integer' } }, + params = { { 'expr', 'string|integer[]' }, { 'winid', 'integer' } }, returns = 'integer', signature = 'col({expr} [, {winid}])', }, @@ -1315,7 +1335,7 @@ M.funcs = { ]=], name = 'complete', - params = { { 'startcol', 'any' }, { 'matches', 'any' } }, + params = { { 'startcol', 'integer' }, { 'matches', 'any[]' } }, returns = false, signature = 'complete({startcol}, {matches})', tags = { 'E785' }, @@ -1414,10 +1434,11 @@ M.funcs = { call complete_info(['mode']) " Get only 'mode' and 'pum_visible' call complete_info(['mode', 'pum_visible']) + < ]=], name = 'complete_info', - params = { { 'what', 'any' } }, + params = { { 'what', 'any[]' } }, returns = 'table', signature = 'complete_info([{what}])', }, @@ -1478,7 +1499,12 @@ M.funcs = { ]=], name = 'confirm', - params = { { 'msg', 'any' }, { 'choices', 'any' }, { 'default', 'any' }, { 'type', 'any' } }, + params = { + { 'msg', 'string' }, + { 'choices', 'string' }, + { 'default', 'integer' }, + { 'type', 'string' }, + }, returns = 'integer', signature = 'confirm({msg} [, {choices} [, {default} [, {type}]]])', }, @@ -1516,7 +1542,7 @@ M.funcs = { ]=], float_func = 'cos', name = 'cos', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, returns = 'number', signature = 'cos({expr})', }, @@ -1537,7 +1563,7 @@ M.funcs = { ]=], float_func = 'cosh', name = 'cosh', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, returns = 'number', signature = 'cosh({expr})', }, @@ -1560,7 +1586,12 @@ M.funcs = { ]=], name = 'count', - params = { { 'comp', 'any' }, { 'expr', 'any' }, { 'ic', 'any' }, { 'start', 'any' } }, + params = { + { 'comp', 'string|table|any[]' }, + { 'expr', 'any' }, + { 'ic', 'boolean' }, + { 'start', 'integer' }, + }, returns = 'integer', signature = 'count({comp}, {expr} [, {ic} [, {start}]])', }, @@ -1572,7 +1603,7 @@ M.funcs = { If {index} is not given, it is assumed to be 0 (i.e.: top). ]=], name = 'ctxget', - params = { { 'index', 'any' } }, + params = { { 'index', 'integer' } }, returns = 'table', signature = 'ctxget([{index}])', }, @@ -1595,7 +1626,7 @@ M.funcs = { Otherwise, all context types are included. ]=], name = 'ctxpush', - params = { { 'types', 'any' } }, + params = { { 'types', 'string[]' } }, signature = 'ctxpush([{types}])', }, ctxset = { @@ -1607,7 +1638,7 @@ M.funcs = { If {index} is not given, it is assumed to be 0 (i.e.: top). ]=], name = 'ctxset', - params = { { 'context', 'any' }, { 'index', 'any' } }, + params = { { 'context', 'table' }, { 'index', 'integer' } }, signature = 'ctxset({context} [, {index}])', }, ctxsize = { @@ -1622,7 +1653,7 @@ M.funcs = { args = { 1, 3 }, base = 1, name = 'cursor', - params = { { 'lnum', 'integer' }, { 'col', 'integer' }, { 'off', 'any' } }, + params = { { 'lnum', 'integer' }, { 'col', 'integer' }, { 'off', 'integer' } }, signature = 'cursor({lnum}, {col} [, {off}])', }, cursor__1 = { @@ -1662,7 +1693,7 @@ M.funcs = { ]=], name = 'cursor', - params = { { 'list', 'any' } }, + params = { { 'list', 'integer[]' } }, signature = 'cursor({list})', }, debugbreak = { @@ -1679,7 +1710,7 @@ M.funcs = { ]=], name = 'debugbreak', - params = { { 'pid', 'any' } }, + params = { { 'pid', 'integer' } }, signature = 'debugbreak({pid})', }, deepcopy = { @@ -1708,7 +1739,7 @@ M.funcs = { ]=], name = 'deepcopy', - params = { { 'expr', 'any' }, { 'noref', 'any' } }, + params = { { 'expr', 'any' }, { 'noref', 'boolean' } }, signature = 'deepcopy({expr} [, {noref}])', }, delete = { @@ -1758,7 +1789,11 @@ M.funcs = { ]=], name = 'deletebufline', - params = { { 'buf', 'any' }, { 'first', 'any' }, { 'last', 'any' } }, + params = { + { 'buf', 'integer|string' }, + { 'first', 'integer|string' }, + { 'last', 'integer|string' }, + }, signature = 'deletebufline({buf}, {first} [, {last}])', }, dictwatcheradd = { @@ -1804,7 +1839,7 @@ M.funcs = { validation and parsing logic. ]=], name = 'dictwatcheradd', - params = { { 'dict', 'any' }, { 'pattern', 'any' }, { 'callback', 'any' } }, + params = { { 'dict', 'table' }, { 'pattern', 'string' }, { 'callback', 'function' } }, signature = 'dictwatcheradd({dict}, {pattern}, {callback})', }, dictwatcherdel = { @@ -1815,7 +1850,7 @@ M.funcs = { order for the watcher to be successfully deleted. ]=], name = 'dictwatcherdel', - params = { { 'dict', 'any' }, { 'pattern', 'any' }, { 'callback', 'any' } }, + params = { { 'dict', 'any' }, { 'pattern', 'string' }, { 'callback', 'function' } }, signature = 'dictwatcherdel({dict}, {pattern}, {callback})', }, did_filetype = { @@ -1894,7 +1929,7 @@ M.funcs = { < ]=], name = 'digraph_get', - params = { { 'chars', 'any' } }, + params = { { 'chars', 'string' } }, signature = 'digraph_get({chars})', }, digraph_getlist = { @@ -1916,7 +1951,7 @@ M.funcs = { < ]=], name = 'digraph_getlist', - params = { { 'listall', 'any' } }, + params = { { 'listall', 'boolean' } }, signature = 'digraph_getlist([{listall}])', }, digraph_set = { @@ -1939,12 +1974,9 @@ M.funcs = { Example: >vim call digraph_set(' ', 'ã‚') < - Can be used as a |method|: >vim - GetString()->digraph_set('ã‚') - < ]=], name = 'digraph_set', - params = { { 'chars', 'any' }, { 'digraph', 'any' } }, + params = { { 'chars', 'string' }, { 'digraph', 'string' } }, signature = 'digraph_set({chars}, {digraph})', }, digraph_setlist = { @@ -1964,13 +1996,9 @@ M.funcs = { endfor <Except that the function returns after the first error, following digraphs will not be added. - - Can be used as a |method|: >vim - GetList()->digraph_setlist() - < ]=], name = 'digraph_setlist', - params = { { 'digraphlist', 'any' } }, + params = { { 'digraphlist', 'table<integer,string[]>' } }, signature = 'digraph_setlist({digraphlist})', }, empty = { @@ -2019,7 +2047,7 @@ M.funcs = { ]=], fast = true, name = 'escape', - params = { { 'string', 'string' }, { 'chars', 'any' } }, + params = { { 'string', 'string' }, { 'chars', 'string' } }, signature = 'escape({string}, {chars})', }, eval = { @@ -2055,19 +2083,26 @@ M.funcs = { This function checks if an executable with the name {expr} exists. {expr} must be the name of the program without any arguments. + executable() uses the value of $PATH and/or the normal - searchpath for programs. *PATHEXT* + searchpath for programs. + *PATHEXT* On MS-Windows the ".exe", ".bat", etc. can optionally be included. Then the extensions in $PATHEXT are tried. Thus if "foo.exe" does not exist, "foo.exe.bat" can be found. If - $PATHEXT is not set then ".exe;.com;.bat;.cmd" is used. A dot + $PATHEXT is not set then ".com;.exe;.bat;.cmd" is used. A dot by itself can be used in $PATHEXT to try using the name without an extension. When 'shell' looks like a Unix shell, then the name is also tried without adding an extension. On MS-Windows it only checks if the file exists and is not a directory, not if it's really executable. - On Windows an executable in the same directory as Vim is - always found (it is added to $PATH at |startup|). + On MS-Windows an executable in the same directory as the Vim + executable is always found (it's added to $PATH at |startup|). + *NoDefaultCurrentDirectoryInExePath* + On MS-Windows an executable in Vim's current working directory + is also normally found, but this can be disabled by setting + the $NoDefaultCurrentDirectoryInExePath environment variable. + The result is a Number: 1 exists 0 does not exist @@ -2076,7 +2111,7 @@ M.funcs = { ]=], fast = true, name = 'executable', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'string' } }, returns = '0|1', signature = 'executable({expr})', }, @@ -2131,8 +2166,9 @@ M.funcs = { ]=], name = 'exepath', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'string' } }, signature = 'exepath({expr})', + returns = 'string', }, exists = { args = 1, @@ -2228,7 +2264,7 @@ M.funcs = { ]=], name = 'exists', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'string' } }, returns = '0|1', signature = 'exists({expr})', }, @@ -2249,7 +2285,7 @@ M.funcs = { ]=], float_func = 'exp', name = 'exp', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, signature = 'exp({expr})', }, expand = { @@ -2435,7 +2471,7 @@ M.funcs = { ]=], name = 'extend', - params = { { 'expr1', 'any' }, { 'expr2', 'any' }, { 'expr3', 'any' } }, + params = { { 'expr1', 'table' }, { 'expr2', 'table' }, { 'expr3', 'table' } }, signature = 'extend({expr1}, {expr2} [, {expr3}])', }, extendnew = { @@ -2447,7 +2483,7 @@ M.funcs = { unchanged. ]=], name = 'extendnew', - params = { { 'expr1', 'any' }, { 'expr2', 'any' }, { 'expr3', 'any' } }, + params = { { 'expr1', 'table' }, { 'expr2', 'table' }, { 'expr3', 'table' } }, signature = 'extendnew({expr1}, {expr2} [, {expr3}])', }, feedkeys = { @@ -2516,6 +2552,23 @@ M.funcs = { params = { { 'file', 'string' } }, signature = 'file_readable({file})', }, + filecopy = { + args = 2, + base = 1, + desc = [[ + Copy the file pointed to by the name {from} to {to}. The + result is a Number, which is |TRUE| if the file was copied + successfully, and |FALSE| when it failed. + If a file with name {to} already exists, it will fail. + Note that it does not handle directories (yet). + + This function is not available in the |sandbox|. + ]], + name = 'filecopy', + params = { { 'from', 'string' }, { 'to', 'string' } }, + returns = '0|1', + signature = 'filecopy({from}, {to})', + }, filereadable = { args = 1, base = 1, @@ -2617,7 +2670,7 @@ M.funcs = { ]=], name = 'filter', - params = { { 'expr1', 'any' }, { 'expr2', 'any' } }, + params = { { 'expr1', 'string|table' }, { 'expr2', 'string|function' } }, signature = 'filter({expr1}, {expr2})', }, finddir = { @@ -2643,7 +2696,7 @@ M.funcs = { ]=], name = 'finddir', - params = { { 'name', 'string' }, { 'path', 'string' }, { 'count', 'any' } }, + params = { { 'name', 'string' }, { 'path', 'string' }, { 'count', 'integer' } }, signature = 'finddir({name} [, {path} [, {count}]])', }, findfile = { @@ -2686,7 +2739,7 @@ M.funcs = { ]=], name = 'flatten', - params = { { 'list', 'any' }, { 'maxdepth', 'any' } }, + params = { { 'list', 'any[]' }, { 'maxdepth', 'integer' } }, returns = 'any[]|0', signature = 'flatten({list} [, {maxdepth}])', }, @@ -2697,7 +2750,7 @@ M.funcs = { Like |flatten()| but first make a copy of {list}. ]=], name = 'flattennew', - params = { { 'list', 'any' }, { 'maxdepth', 'any' } }, + params = { { 'list', 'any[]' }, { 'maxdepth', 'integer' } }, returns = 'any[]|0', signature = 'flattennew({list} [, {maxdepth}])', }, @@ -2728,7 +2781,7 @@ M.funcs = { ]=], name = 'float2nr', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, signature = 'float2nr({expr})', }, floor = { @@ -2750,7 +2803,7 @@ M.funcs = { ]=], float_func = 'floor', name = 'floor', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, signature = 'floor({expr})', }, fmod = { @@ -2774,7 +2827,7 @@ M.funcs = { ]=], name = 'fmod', - params = { { 'expr1', 'any' }, { 'expr2', 'any' } }, + params = { { 'expr1', 'number' }, { 'expr2', 'number' } }, signature = 'fmod({expr1}, {expr2})', }, fnameescape = { @@ -2963,7 +3016,7 @@ M.funcs = { unless it was defined with the "abort" flag. ]=], name = 'foreach', - params = { { 'expr1', 'any' }, { 'expr2', 'any' } }, + params = { { 'expr1', 'string|table' }, { 'expr2', 'string|function' } }, signature = 'foreach({expr1}, {expr2})', }, foreground = { @@ -3126,7 +3179,7 @@ M.funcs = { type a character. ]=], name = 'garbagecollect', - params = { { 'atexit', 'any' } }, + params = { { 'atexit', 'boolean' } }, signature = 'garbagecollect([{atexit}])', }, get = { @@ -3140,6 +3193,7 @@ M.funcs = { name = 'get', params = { { 'list', 'any[]' }, { 'idx', 'integer' }, { 'default', 'any' } }, signature = 'get({list}, {idx} [, {default}])', + tags = { 'get()-list' }, }, get__1 = { args = { 2, 3 }, @@ -3152,6 +3206,7 @@ M.funcs = { name = 'get', params = { { 'blob', 'string' }, { 'idx', 'integer' }, { 'default', 'any' } }, signature = 'get({blob}, {idx} [, {default}])', + tags = { 'get()-blob' }, }, get__2 = { args = { 2, 3 }, @@ -3167,23 +3222,38 @@ M.funcs = { name = 'get', params = { { 'dict', 'table<string,any>' }, { 'key', 'string' }, { 'default', 'any' } }, signature = 'get({dict}, {key} [, {default}])', + tags = { 'get()-dict' }, }, get__3 = { args = { 2, 3 }, base = 1, desc = [=[ - Get item {what} from Funcref {func}. Possible values for + Get item {what} from |Funcref| {func}. Possible values for {what} are: - "name" The function name - "func" The function - "dict" The dictionary - "args" The list with arguments + "name" The function name + "func" The function + "dict" The dictionary + "args" The list with arguments + "arity" A dictionary with information about the number of + arguments accepted by the function (minus the + {arglist}) with the following fields: + required the number of positional arguments + optional the number of optional arguments, + in addition to the required ones + varargs |TRUE| if the function accepts a + variable number of arguments |...| + + Note: There is no error, if the {arglist} of + the Funcref contains more arguments than the + Funcref expects, it's not validated. + Returns zero on error. ]=], name = 'get', params = { { 'func', 'function' }, { 'what', 'string' } }, returns = 'any', signature = 'get({func}, {what})', + tags = { 'get()-func' }, }, getbufinfo = { args = { 0, 1 }, @@ -3296,10 +3366,11 @@ M.funcs = { Example: >vim let lines = getbufline(bufnr("myfile"), 1, "$") + < ]=], name = 'getbufline', - params = { { 'buf', 'any' }, { 'lnum', 'integer' }, { 'end', 'integer' } }, + params = { { 'buf', 'integer|string' }, { 'lnum', 'integer' }, { 'end', 'integer' } }, signature = 'getbufline({buf}, {lnum} [, {end}])', }, getbufoneline = { @@ -3340,7 +3411,7 @@ M.funcs = { ]=], name = 'getbufvar', - params = { { 'buf', 'any' }, { 'varname', 'string' }, { 'def', 'any' } }, + params = { { 'buf', 'integer|string' }, { 'varname', 'string' }, { 'def', 'any' } }, signature = 'getbufvar({buf}, {varname} [, {def}])', }, getcellwidths = { @@ -3447,7 +3518,7 @@ M.funcs = { < ]=], name = 'getchar', - params = {}, + params = { { 'expr', '0|1' } }, returns = 'integer', signature = 'getchar([{expr}])', }, @@ -3491,7 +3562,7 @@ M.funcs = { < ]=], name = 'getcharpos', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'string' } }, returns = 'integer[]', signature = 'getcharpos({expr})', }, @@ -3518,7 +3589,7 @@ M.funcs = { ]=], name = 'getcharsearch', params = {}, - returns = 'table[]', + returns = 'table', signature = 'getcharsearch()', }, getcharstr = { @@ -3536,7 +3607,7 @@ M.funcs = { result is converted to a string. ]=], name = 'getcharstr', - params = {}, + params = { { 'expr', '0|1' } }, returns = 'string', signature = 'getcharstr([{expr}])', }, @@ -3546,8 +3617,8 @@ M.funcs = { Only works when the command line is being edited, thus requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. See |:command-completion| for the return string. - Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()| and - |setcmdline()|. + Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, + |getcmdprompt()| and |setcmdline()|. Returns an empty string when completion is not defined. ]=], name = 'getcmdcompltype', @@ -3557,13 +3628,13 @@ M.funcs = { }, getcmdline = { desc = [=[ - Return the current command-line. Only works when the command - line is being edited, thus requires use of |c_CTRL-\_e| or - |c_CTRL-R_=|. + Return the current command-line input. Only works when the + command line is being edited, thus requires use of + |c_CTRL-\_e| or |c_CTRL-R_=|. Example: >vim cmap <F7> <C-\>eescape(getcmdline(), ' \')<CR> - <Also see |getcmdtype()|, |getcmdpos()|, |setcmdpos()| and - |setcmdline()|. + <Also see |getcmdtype()|, |getcmdpos()|, |setcmdpos()|, + |getcmdprompt()| and |setcmdline()|. Returns an empty string when entering a password or using |inputsecret()|. ]=], @@ -3579,14 +3650,28 @@ M.funcs = { Only works when editing the command line, thus requires use of |c_CTRL-\_e| or |c_CTRL-R_=| or an expression mapping. Returns 0 otherwise. - Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()| and - |setcmdline()|. + Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, + |getcmdprompt()| and |setcmdline()|. ]=], name = 'getcmdpos', params = {}, returns = 'integer', signature = 'getcmdpos()', }, + getcmdprompt = { + desc = [=[ + Return the current command-line prompt when using functions + like |input()| or |confirm()|. + Only works when the command line is being edited, thus + requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. + Also see |getcmdtype()|, |getcmdline()|, |getcmdpos()|, + |setcmdpos()| and |setcmdline()|. + ]=], + name = 'getcmdprompt', + params = {}, + returns = 'string', + signature = 'getcmdprompt()', + }, getcmdscreenpos = { desc = [=[ Return the screen position of the cursor in the command line @@ -3654,6 +3739,7 @@ M.funcs = { customlist,{func} custom completion, defined via {func} diff_buffer |:diffget| and |:diffput| completion dir directory names + dir_in_path directory names in |'cdpath'| environment environment variable names event autocommand events expression Vim expression @@ -3708,7 +3794,7 @@ M.funcs = { ]=], name = 'getcompletion', - params = { { 'pat', 'any' }, { 'type', 'any' }, { 'filtered', 'any' } }, + params = { { 'pat', 'string' }, { 'type', 'string' }, { 'filtered', 'boolean' } }, returns = 'string[]', signature = 'getcompletion({pat}, {type} [, {filtered}])', }, @@ -4019,7 +4105,7 @@ M.funcs = { < ]=], name = 'getloclist', - params = { { 'nr', 'integer' }, { 'what', 'any' } }, + params = { { 'nr', 'integer' }, { 'what', 'table' } }, signature = 'getloclist({nr} [, {what}])', }, getmarklist = { @@ -4046,8 +4132,9 @@ M.funcs = { ]=], name = 'getmarklist', - params = { { 'buf', 'any' } }, + params = { { 'buf', 'integer?' } }, signature = 'getmarklist([{buf}])', + returns = 'vim.fn.getmarklist.ret.item[]', }, getmatches = { args = { 0, 1 }, @@ -4084,7 +4171,7 @@ M.funcs = { < ]=], name = 'getmatches', - params = { { 'win', 'any' } }, + params = { { 'win', 'integer' } }, signature = 'getmatches([{win}])', }, getmousepos = { @@ -4139,9 +4226,34 @@ M.funcs = { args = 1, base = 1, desc = [=[ - Get the position for String {expr}. For possible values of - {expr} see |line()|. For getting the cursor position see - |getcurpos()|. + Get the position for String {expr}. + The accepted values for {expr} are: + . The cursor position. + $ The last line in the current buffer. + 'x Position of mark x (if the mark is not set, 0 is + returned for all values). + w0 First line visible in current window (one if the + display isn't updated, e.g. in silent Ex mode). + w$ Last line visible in current window (this is one + less than "w0" if no lines are visible). + v When not in Visual mode, returns the cursor + position. In Visual mode, returns the other end + of the Visual area. A good way to think about + this is that in Visual mode "v" and "." complement + each other. While "." refers to the cursor + position, "v" refers to where |v_o| would move the + cursor. As a result, you can use "v" and "." + together to work on all of a selection in + characterwise Visual mode. If the cursor is at + the end of a characterwise Visual area, "v" refers + to the start of the same Visual area. And if the + cursor is at the start of a characterwise Visual + area, "v" refers to the end of the same Visual + area. "v" differs from |'<| and |'>| in that it's + updated right away. + Note that a mark in another file can be used. The line number + then applies to another buffer. + The result is a |List| with four numbers: [bufnum, lnum, col, off] "bufnum" is zero, unless a mark like '0 or 'A is used, then it @@ -4152,20 +4264,25 @@ M.funcs = { it is the offset in screen columns from the start of the character. E.g., a position within a <Tab> or after the last character. - Note that for '< and '> Visual mode matters: when it is "V" - (visual line mode) the column of '< is zero and the column of - '> is a large number equal to |v:maxcol|. + + For getting the cursor position see |getcurpos()|. The column number in the returned List is the byte position within the line. To get the character position in the line, use |getcharpos()|. + + Note that for '< and '> Visual mode matters: when it is "V" + (visual line mode) the column of '< is zero and the column of + '> is a large number equal to |v:maxcol|. A very large column number equal to |v:maxcol| can be returned, in which case it means "after the end of the line". If {expr} is invalid, returns a list with all zeros. + This can be used to save and restore the position of a mark: >vim let save_a_mark = getpos("'a") " ... call setpos("'a", save_a_mark) - <Also see |getcharpos()|, |getcurpos()| and |setpos()|. + < + Also see |getcharpos()|, |getcurpos()| and |setpos()|. ]=], name = 'getpos', @@ -4280,7 +4397,7 @@ M.funcs = { < ]=], name = 'getqflist', - params = { { 'what', 'any' } }, + params = { { 'what', 'table' } }, signature = 'getqflist([{what}])', }, getreg = { @@ -4370,14 +4487,14 @@ M.funcs = { The optional argument {opts} is a Dict and supports the following items: - type Specify the region's selection type - (default: "v"): - "v" for |charwise| mode - "V" for |linewise| mode - "<CTRL-V>" for |blockwise-visual| mode + type Specify the region's selection type. + See |getregtype()| for possible values, + except that the width can be omitted + and an empty string cannot be used. + (default: "v") exclusive If |TRUE|, use exclusive selection - for the end position + for the end position. (default: follow 'selection') You can get the last selection type by |visualmode()|. @@ -4403,8 +4520,8 @@ M.funcs = { difference if the buffer is displayed in a window with different 'virtualedit' or 'list' values. - Examples: > - :xnoremap <CR> + Examples: >vim + xnoremap <CR> \ <Cmd>echom getregion( \ getpos('v'), getpos('.'), #{ type: mode() })<CR> < @@ -4647,7 +4764,7 @@ M.funcs = { strings. ]=], name = 'gettext', - params = { { 'text', 'any' } }, + params = { { 'text', 'string' } }, signature = 'gettext({text})', }, getwininfo = { @@ -4800,7 +4917,12 @@ M.funcs = { ]=], name = 'glob', - params = { { 'expr', 'any' }, { 'nosuf', 'boolean' }, { 'list', 'any' }, { 'alllinks', 'any' } }, + params = { + { 'expr', 'string' }, + { 'nosuf', 'boolean' }, + { 'list', 'boolean' }, + { 'alllinks', 'boolean' }, + }, signature = 'glob({expr} [, {nosuf} [, {list} [, {alllinks}]]])', }, glob2regpat = { @@ -4869,10 +4991,10 @@ M.funcs = { name = 'globpath', params = { { 'path', 'string' }, - { 'expr', 'any' }, + { 'expr', 'string' }, { 'nosuf', 'boolean' }, - { 'list', 'any' }, - { 'allinks', 'any' }, + { 'list', 'boolean' }, + { 'allinks', 'boolean' }, }, signature = 'globpath({path}, {expr} [, {nosuf} [, {list} [, {allinks}]]])', }, @@ -4948,7 +5070,7 @@ M.funcs = { ]=], fast = true, name = 'has', - params = { { 'feature', 'any' } }, + params = { { 'feature', 'string' } }, returns = '0|1', signature = 'has({feature})', }, @@ -4962,7 +5084,7 @@ M.funcs = { ]=], name = 'has_key', - params = { { 'dict', 'any' }, { 'key', 'any' } }, + params = { { 'dict', 'table' }, { 'key', 'string' } }, returns = '0|1', signature = 'has_key({dict}, {key})', }, @@ -5028,7 +5150,7 @@ M.funcs = { ]=], name = 'hasmapto', - params = { { 'what', 'any' }, { 'mode', 'string' }, { 'abbr', 'any' } }, + params = { { 'what', 'any' }, { 'mode', 'string' }, { 'abbr', 'boolean' } }, returns = '0|1', signature = 'hasmapto({what} [, {mode} [, {abbr}]])', }, @@ -5080,7 +5202,7 @@ M.funcs = { ]=], name = 'histadd', - params = { { 'history', 'any' }, { 'item', 'any' } }, + params = { { 'history', 'string' }, { 'item', 'any' } }, returns = '0|1', signature = 'histadd({history}, {item})', }, @@ -5121,7 +5243,7 @@ M.funcs = { < ]=], name = 'histdel', - params = { { 'history', 'any' }, { 'item', 'any' } }, + params = { { 'history', 'string' }, { 'item', 'any' } }, returns = '0|1', signature = 'histdel({history} [, {item}])', }, @@ -5145,7 +5267,7 @@ M.funcs = { < ]=], name = 'histget', - params = { { 'history', 'any' }, { 'index', 'any' } }, + params = { { 'history', 'string' }, { 'index', 'integer|string' } }, returns = 'string', signature = 'histget({history} [, {index}])', }, @@ -5159,10 +5281,11 @@ M.funcs = { Example: >vim let inp_index = histnr("expr") + < ]=], name = 'histnr', - params = { { 'history', 'any' } }, + params = { { 'history', 'string' } }, returns = 'integer', signature = 'histnr({history})', }, @@ -5230,7 +5353,7 @@ M.funcs = { ]=], fast = true, name = 'iconv', - params = { { 'string', 'string' }, { 'from', 'any' }, { 'to', 'any' } }, + params = { { 'string', 'string' }, { 'from', 'string' }, { 'to', 'string' } }, signature = 'iconv({string}, {from}, {to})', }, id = { @@ -5243,7 +5366,7 @@ M.funcs = { Note that `v:_null_string`, `v:_null_list`, `v:_null_dict` and `v:_null_blob` have the same `id()` with different types because they are internally represented as NULL pointers. - `id()` returns a hexadecimal representanion of the pointers to + `id()` returns a hexadecimal representation of the pointers to the containers (i.e. like `0x994a40`), same as `printf("%p", {expr})`, but it is advised against counting on the exact format of the return value. @@ -5301,10 +5424,11 @@ M.funcs = { if index(numbers, 123) >= 0 " ... endif + < ]=], name = 'index', - params = { { 'object', 'any' }, { 'expr', 'any' }, { 'start', 'any' }, { 'ic', 'any' } }, + params = { { 'object', 'any' }, { 'expr', 'any' }, { 'start', 'integer' }, { 'ic', 'boolean' } }, signature = 'index({object}, {expr} [, {start} [, {ic}]])', }, indexof = { @@ -5347,6 +5471,7 @@ M.funcs = { echo indexof(l, "v:val.n == 20") echo indexof(l, {i, v -> v.n == 30}) echo indexof(l, "v:val.n == 20", #{startidx: 1}) + < ]=], name = 'indexof', @@ -5358,7 +5483,7 @@ M.funcs = { base = 1, desc = '', name = 'input', - params = { { 'prompt', 'any' }, { 'text', 'any' }, { 'completion', 'any' } }, + params = { { 'prompt', 'string' }, { 'text', 'string' }, { 'completion', 'string' } }, signature = 'input({prompt} [, {text} [, {completion}]])', }, input__1 = { @@ -5473,6 +5598,7 @@ M.funcs = { let g:Foo = input("enter search pattern: ") call inputrestore() endfunction + < ]=], name = 'input', @@ -5511,7 +5637,7 @@ M.funcs = { ]=], name = 'inputlist', - params = { { 'textlist', 'any' } }, + params = { { 'textlist', 'string[]' } }, signature = 'inputlist({textlist})', }, inputrestore = { @@ -5554,7 +5680,7 @@ M.funcs = { ]=], name = 'inputsecret', - params = { { 'prompt', 'any' }, { 'text', 'any' } }, + params = { { 'prompt', 'string' }, { 'text', 'string' } }, signature = 'inputsecret({prompt} [, {text}])', }, insert = { @@ -5612,9 +5738,33 @@ M.funcs = { < ]=], name = 'invert', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, signature = 'invert({expr})', }, + isabsolutepath = { + args = 1, + base = 1, + desc = [=[ + The result is a Number, which is |TRUE| when {path} is an + absolute path. + On Unix, a path is considered absolute when it starts with '/'. + On MS-Windows, it is considered absolute when it starts with an + optional drive prefix and is followed by a '\' or '/'. UNC paths + are always absolute. + Example: >vim + echo isabsolutepath('/usr/share/') " 1 + echo isabsolutepath('./foobar') " 0 + echo isabsolutepath('C:\Windows') " 1 + echo isabsolutepath('foobar') " 0 + echo isabsolutepath('\\remote\file') " 1 + < + ]=], + fast = true, + name = 'isabsolutepath', + params = { { 'path', 'string' } }, + returns = '0|1', + signature = 'isabsolutepath({path})', + }, isdirectory = { args = 1, base = 1, @@ -5627,7 +5777,7 @@ M.funcs = { ]=], fast = true, name = 'isdirectory', - params = { { 'directory', 'any' } }, + params = { { 'directory', 'string' } }, returns = '0|1', signature = 'isdirectory({directory})', }, @@ -5644,7 +5794,7 @@ M.funcs = { ]=], name = 'isinf', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, returns = '1|0|-1', signature = 'isinf({expr})', }, @@ -5682,7 +5832,7 @@ M.funcs = { ]=], name = 'isnan', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, returns = '0|1', signature = 'isnan({expr})', }, @@ -5698,7 +5848,10 @@ M.funcs = { for [key, value] in items(mydict) echo key .. ': ' .. value endfor - + < + A List or a String argument is also supported. In these + cases, items() returns a List with the index and the value at + the index. ]=], name = 'items', params = { { 'dict', 'any' } }, @@ -5720,7 +5873,7 @@ M.funcs = { Return the PID (process id) of |job-id| {job}. ]=], name = 'jobpid', - params = { { 'job', 'any' } }, + params = { { 'job', 'integer' } }, returns = 'integer', signature = 'jobpid({job})', }, @@ -5732,7 +5885,7 @@ M.funcs = { Fails if the job was not started with `"pty":v:true`. ]=], name = 'jobresize', - params = { { 'job', 'any' }, { 'width', 'integer' }, { 'height', 'integer' } }, + params = { { 'job', 'integer' }, { 'width', 'integer' }, { 'height', 'integer' } }, signature = 'jobresize({job}, {width}, {height})', }, jobsend = { @@ -5834,7 +5987,7 @@ M.funcs = { See also |job-control|, |channel|, |msgpack-rpc|. ]=], name = 'jobstart', - params = { { 'cmd', 'any' }, { 'opts', 'table' } }, + params = { { 'cmd', 'string|string[]' }, { 'opts', 'table' } }, signature = 'jobstart({cmd} [, {opts}])', }, jobstop = { @@ -5850,7 +6003,7 @@ M.funcs = { exited or stopped. ]=], name = 'jobstop', - params = { { 'id', 'any' } }, + params = { { 'id', 'integer' } }, signature = 'jobstop({id})', }, jobwait = { @@ -5877,7 +6030,7 @@ M.funcs = { -3 if the job-id is invalid ]=], name = 'jobwait', - params = { { 'jobs', 'any' }, { 'timeout', 'integer' } }, + params = { { 'jobs', 'integer[]' }, { 'timeout', 'integer' } }, signature = 'jobwait({jobs} [, {timeout}])', }, join = { @@ -5896,7 +6049,7 @@ M.funcs = { ]=], name = 'join', - params = { { 'list', 'any' }, { 'sep', 'any' } }, + params = { { 'list', 'any[]' }, { 'sep', 'string' } }, signature = 'join({list} [, {sep}])', }, json_decode = { @@ -5951,7 +6104,7 @@ M.funcs = { ]=], name = 'keys', - params = { { 'dict', 'any' } }, + params = { { 'dict', 'table' } }, signature = 'keys({dict})', }, keytrans = { @@ -6068,28 +6221,16 @@ M.funcs = { args = { 1, 2 }, base = 1, desc = [=[ - The result is a Number, which is the line number of the file - position given with {expr}. The {expr} argument is a string. - The accepted positions are: - . the cursor position - $ the last line in the current buffer - 'x position of mark x (if the mark is not set, 0 is - returned) - w0 first line visible in current window (one if the - display isn't updated, e.g. in silent Ex mode) - w$ last line visible in current window (this is one - less than "w0" if no lines are visible) - v In Visual mode: the start of the Visual area (the - cursor is the end). When not in Visual mode - returns the cursor position. Differs from |'<| in - that it's updated right away. - Note that a mark in another file can be used. The line number - then applies to another buffer. + See |getpos()| for accepted positions. + To get the column number use |col()|. To get both use |getpos()|. + With the optional {winid} argument the values are obtained for that window instead of the current window. + Returns 0 for invalid values of {expr} and {winid}. + Examples: >vim echo line(".") " line number of the cursor echo line(".", winid) " idem, in window "winid" @@ -6101,7 +6242,7 @@ M.funcs = { ]=], name = 'line', - params = { { 'expr', 'any' }, { 'winid', 'integer' } }, + params = { { 'expr', 'string|integer[]' }, { 'winid', 'integer' } }, returns = 'integer', signature = 'line({expr} [, {winid}])', }, @@ -6157,7 +6298,7 @@ M.funcs = { ]=], name = 'list2blob', - params = { { 'list', 'any' } }, + params = { { 'list', 'any[]' } }, signature = 'list2blob({list})', }, list2str = { @@ -6181,7 +6322,7 @@ M.funcs = { ]=], name = 'list2str', - params = { { 'list', 'any' }, { 'utf8', 'any' } }, + params = { { 'list', 'any[]' }, { 'utf8', 'boolean' } }, signature = 'list2str({list} [, {utf8}])', }, localtime = { @@ -6210,7 +6351,7 @@ M.funcs = { ]=], float_func = 'log', name = 'log', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, signature = 'log({expr})', }, log10 = { @@ -6229,7 +6370,7 @@ M.funcs = { ]=], float_func = 'log10', name = 'log10', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, signature = 'log10({expr})', }, luaeval = { @@ -6242,7 +6383,7 @@ M.funcs = { ]=], lua = false, name = 'luaeval', - params = { { 'expr', 'any' }, { 'expr', 'any' } }, + params = { { 'expr', 'string' }, { 'expr', 'any[]' } }, signature = 'luaeval({expr} [, {expr}])', }, map = { @@ -6304,7 +6445,7 @@ M.funcs = { ]=], name = 'map', - params = { { 'expr1', 'any' }, { 'expr2', 'any' } }, + params = { { 'expr1', 'string|table|any[]' }, { 'expr2', 'string|function' } }, signature = 'map({expr1}, {expr2})', }, maparg = { @@ -6349,6 +6490,7 @@ M.funcs = { "lhsrawalt" The {lhs} of the mapping as raw bytes, alternate form, only present when it differs from "lhsraw" "rhs" The {rhs} of the mapping as typed. + "callback" Lua function, if RHS was defined as such. "silent" 1 for a |:map-silent| mapping, else 0. "noremap" 1 if the {rhs} of the mapping is not remappable. "script" 1 if mapping was defined with <script>. @@ -6381,6 +6523,7 @@ M.funcs = { This function can be used to map a key even when it's already mapped, and have it do the original mapping too. Sketch: >vim exe 'nnoremap <Tab> ==' .. maparg('<Tab>', 'n') + < ]=], name = 'maparg', @@ -6443,7 +6586,7 @@ M.funcs = { ]=], name = 'mapcheck', - params = { { 'name', 'string' }, { 'mode', 'string' }, { 'abbr', 'any' } }, + params = { { 'name', 'string' }, { 'mode', 'string' }, { 'abbr', 'boolean' } }, signature = 'mapcheck({name} [, {mode} [, {abbr}]])', }, maplist = { @@ -6478,9 +6621,11 @@ M.funcs = { \ {_, m -> m.lhs == 'xyzzy'})[0].mode_bits ounmap xyzzy echo printf("Operator-pending mode bit: 0x%x", op_bit) + < ]], name = 'maplist', - params = {}, + params = { { 'abbr', '0|1' } }, + returns = 'table[]', signature = 'maplist([{abbr}])', }, mapnew = { @@ -6500,7 +6645,7 @@ M.funcs = { args = { 1, 3 }, base = 1, name = 'mapset', - params = { { 'mode', 'string' }, { 'abbr', 'any' }, { 'dict', 'any' } }, + params = { { 'mode', 'string' }, { 'abbr', 'boolean' }, { 'dict', 'boolean' } }, signature = 'mapset({mode}, {abbr}, {dict})', }, mapset__1 = { @@ -6541,9 +6686,10 @@ M.funcs = { for d in save_maps call mapset(d) endfor + < ]=], name = 'mapset', - params = { { 'dict', 'any' } }, + params = { { 'dict', 'boolean' } }, signature = 'mapset({dict})', }, match = { @@ -6614,7 +6760,12 @@ M.funcs = { ]=], name = 'match', - params = { { 'expr', 'any' }, { 'pat', 'any' }, { 'start', 'any' }, { 'count', 'any' } }, + params = { + { 'expr', 'string|any[]' }, + { 'pat', 'string' }, + { 'start', 'integer' }, + { 'count', 'integer' }, + }, signature = 'match({expr}, {pat} [, {start} [, {count}]])', }, matchadd = { @@ -6681,11 +6832,11 @@ M.funcs = { ]=], name = 'matchadd', params = { - { 'group', 'any' }, - { 'pattern', 'any' }, - { 'priority', 'any' }, - { 'id', 'any' }, - { 'dict', 'any' }, + { 'group', 'integer|string' }, + { 'pattern', 'string' }, + { 'priority', 'integer' }, + { 'id', 'integer' }, + { 'dict', 'string' }, }, signature = 'matchadd({group}, {pattern} [, {priority} [, {id} [, {dict}]]])', tags = { 'E798', 'E799', 'E801', 'E957' }, @@ -6696,10 +6847,10 @@ M.funcs = { desc = [=[ Same as |matchadd()|, but requires a list of positions {pos} instead of a pattern. This command is faster than |matchadd()| - because it does not require to handle regular expressions and - sets buffer line boundaries to redraw screen. It is supposed - to be used when fast match additions and deletions are - required, for example to highlight matching parentheses. + because it does not handle regular expressions and it sets + buffer line boundaries to redraw screen. It is supposed to be + used when fast match additions and deletions are required, for + example to highlight matching parentheses. *E5030* *E5031* {pos} is a list of positions. Each position can be one of these: @@ -6733,11 +6884,11 @@ M.funcs = { ]=], name = 'matchaddpos', params = { - { 'group', 'any' }, - { 'pos', 'any' }, - { 'priority', 'any' }, - { 'id', 'any' }, - { 'dict', 'any' }, + { 'group', 'integer|string' }, + { 'pos', 'any[]' }, + { 'priority', 'integer' }, + { 'id', 'integer' }, + { 'dict', 'string' }, }, signature = 'matchaddpos({group}, {pos} [, {priority} [, {id} [, {dict}]]])', }, @@ -6792,19 +6943,19 @@ M.funcs = { Examples: >vim " Assuming line 3 in buffer 5 contains "a" - :echo matchbufline(5, '\<\k\+\>', 3, 3) - [{'lnum': 3, 'byteidx': 0, 'text': 'a'}] + echo matchbufline(5, '\<\k\+\>', 3, 3) + < `[{'lnum': 3, 'byteidx': 0, 'text': 'a'}]` >vim " Assuming line 4 in buffer 10 contains "tik tok" - :echo matchbufline(10, '\<\k\+\>', 1, 4) - [{'lnum': 4, 'byteidx': 0, 'text': 'tik'}, {'lnum': 4, 'byteidx': 4, 'text': 'tok'}] - < + echo matchbufline(10, '\<\k\+\>', 1, 4) + < `[{'lnum': 4, 'byteidx': 0, 'text': 'tik'}, {'lnum': 4, 'byteidx': 4, 'text': 'tok'}]` + If {submatch} is present and is v:true, then submatches like "\1", "\2", etc. are also returned. Example: >vim " Assuming line 2 in buffer 2 contains "acd" - :echo matchbufline(2, '\(a\)\?\(b\)\?\(c\)\?\(.*\)', 2, 2 + echo matchbufline(2, '\(a\)\?\(b\)\?\(c\)\?\(.*\)', 2, 2 \ {'submatches': v:true}) - [{'lnum': 2, 'byteidx': 0, 'text': 'acd', 'submatches': ['a', '', 'c', 'd', '', '', '', '', '']}] - <The "submatches" List always contains 9 items. If a submatch + < `[{'lnum': 2, 'byteidx': 0, 'text': 'acd', 'submatches': ['a', '', 'c', 'd', '', '', '', '', '']}]` + The "submatches" List always contains 9 items. If a submatch is not found, then an empty string is returned for that submatch. ]=], @@ -6831,7 +6982,7 @@ M.funcs = { ]=], name = 'matchdelete', - params = { { 'id', 'any' }, { 'win', 'any' } }, + params = { { 'id', 'integer' }, { 'win', 'integer' } }, signature = 'matchdelete({id} [, {win}])', tags = { 'E802', 'E803' }, }, @@ -6859,7 +7010,12 @@ M.funcs = { ]=], name = 'matchend', - params = { { 'expr', 'any' }, { 'pat', 'any' }, { 'start', 'any' }, { 'count', 'any' } }, + params = { + { 'expr', 'any' }, + { 'pat', 'string' }, + { 'start', 'integer' }, + { 'count', 'integer' }, + }, signature = 'matchend({expr}, {pat} [, {start} [, {count}]])', }, matchfuzzy = { @@ -6929,7 +7085,7 @@ M.funcs = { <results in `['two one']`. ]=], name = 'matchfuzzy', - params = { { 'list', 'any' }, { 'str', 'any' }, { 'dict', 'any' } }, + params = { { 'list', 'any[]' }, { 'str', 'string' }, { 'dict', 'string' } }, signature = 'matchfuzzy({list}, {str} [, {dict}])', }, matchfuzzypos = { @@ -6958,7 +7114,7 @@ M.funcs = { <results in `[[{"id": 10, "text": "hello"}], [[2, 3]], [127]]` ]=], name = 'matchfuzzypos', - params = { { 'list', 'any' }, { 'str', 'any' }, { 'dict', 'any' } }, + params = { { 'list', 'any[]' }, { 'str', 'string' }, { 'dict', 'string' } }, signature = 'matchfuzzypos({list}, {str} [, {dict}])', }, matchlist = { @@ -6978,7 +7134,12 @@ M.funcs = { ]=], name = 'matchlist', - params = { { 'expr', 'any' }, { 'pat', 'any' }, { 'start', 'any' }, { 'count', 'any' } }, + params = { + { 'expr', 'any' }, + { 'pat', 'string' }, + { 'start', 'integer' }, + { 'count', 'integer' }, + }, signature = 'matchlist({expr}, {pat} [, {start} [, {count}]])', }, matchstr = { @@ -6999,7 +7160,12 @@ M.funcs = { ]=], name = 'matchstr', - params = { { 'expr', 'any' }, { 'pat', 'any' }, { 'start', 'any' }, { 'count', 'any' } }, + params = { + { 'expr', 'any' }, + { 'pat', 'string' }, + { 'start', 'integer' }, + { 'count', 'integer' }, + }, signature = 'matchstr({expr}, {pat} [, {start} [, {count}]])', }, matchstrlist = { @@ -7024,17 +7190,17 @@ M.funcs = { option settings on the pattern. Example: >vim - :echo matchstrlist(['tik tok'], '\<\k\+\>') - [{'idx': 0, 'byteidx': 0, 'text': 'tik'}, {'idx': 0, 'byteidx': 4, 'text': 'tok'}] - :echo matchstrlist(['a', 'b'], '\<\k\+\>') - [{'idx': 0, 'byteidx': 0, 'text': 'a'}, {'idx': 1, 'byteidx': 0, 'text': 'b'}] - < + echo matchstrlist(['tik tok'], '\<\k\+\>') + < `[{'idx': 0, 'byteidx': 0, 'text': 'tik'}, {'idx': 0, 'byteidx': 4, 'text': 'tok'}]` >vim + echo matchstrlist(['a', 'b'], '\<\k\+\>') + < `[{'idx': 0, 'byteidx': 0, 'text': 'a'}, {'idx': 1, 'byteidx': 0, 'text': 'b'}]` + If "submatches" is present and is v:true, then submatches like "\1", "\2", etc. are also returned. Example: >vim - :echo matchstrlist(['acd'], '\(a\)\?\(b\)\?\(c\)\?\(.*\)', + echo matchstrlist(['acd'], '\(a\)\?\(b\)\?\(c\)\?\(.*\)', \ #{submatches: v:true}) - [{'idx': 0, 'byteidx': 0, 'text': 'acd', 'submatches': ['a', '', 'c', 'd', '', '', '', '', '']}] - <The "submatches" List always contains 9 items. If a submatch + < `[{'idx': 0, 'byteidx': 0, 'text': 'acd', 'submatches': ['a', '', 'c', 'd', '', '', '', '', '']}]` + The "submatches" List always contains 9 items. If a submatch is not found, then an empty string is returned for that submatch. ]=], @@ -7065,7 +7231,12 @@ M.funcs = { ]=], name = 'matchstrpos', - params = { { 'expr', 'any' }, { 'pat', 'any' }, { 'start', 'any' }, { 'count', 'any' } }, + params = { + { 'expr', 'any' }, + { 'pat', 'string' }, + { 'start', 'integer' }, + { 'count', 'integer' }, + }, signature = 'matchstrpos({expr}, {pat} [, {start} [, {count}]])', }, max = { @@ -7135,7 +7306,7 @@ M.funcs = { < ]=], name = 'menu_get', - params = { { 'path', 'string' }, { 'modes', 'any' } }, + params = { { 'path', 'string' }, { 'modes', 'string' } }, signature = 'menu_get({path} [, {modes}])', }, menu_info = { @@ -7243,17 +7414,14 @@ M.funcs = { When {flags} is present it must be a string. An empty string has no effect. - If {flags} contains "p" then intermediate directories are - created as necessary. + {flags} can contain these character flags: + "p" intermediate directories will be created as necessary + "D" {name} will be deleted at the end of the current + function, but not recursively |:defer| + "R" {name} will be deleted recursively at the end of the + current function |:defer| - If {flags} contains "D" then {name} is deleted at the end of - the current function, as with: >vim - defer delete({name}, 'd') - < - If {flags} contains "R" then {name} is deleted recursively at - the end of the current function, as with: >vim - defer delete({name}, 'rf') - <Note that when {name} has more than one part and "p" is used + Note that when {name} has more than one part and "p" is used some directories may already exist. Only the first one that is created and what it contains is scheduled to be deleted. E.g. when using: >vim @@ -7282,7 +7450,7 @@ M.funcs = { ]=], name = 'mkdir', - params = { { 'name', 'string' }, { 'flags', 'string' }, { 'prot', 'any' } }, + params = { { 'name', 'string' }, { 'flags', 'string' }, { 'prot', 'string' } }, signature = 'mkdir({name} [, {flags} [, {prot}]])', tags = { 'E739' }, }, @@ -7426,12 +7594,7 @@ M.funcs = { C parser does not support such values. float |Float|. This value cannot possibly appear in |msgpackparse()| output. - string |readfile()|-style list of strings. This value will - appear in |msgpackparse()| output if string contains - zero byte or if string is a mapping key and mapping is - being represented as special dictionary for other - reasons. - binary |String|, or |Blob| if binary string contains zero + string |String|, or |Blob| if binary string contains zero byte. This value cannot appear in |msgpackparse()| output since blobs were introduced. array |List|. This value cannot appear in |msgpackparse()| @@ -7489,7 +7652,7 @@ M.funcs = { ]=], name = 'nr2char', - params = { { 'expr', 'any' }, { 'utf8', 'any' } }, + params = { { 'expr', 'integer' }, { 'utf8', 'boolean' } }, signature = 'nr2char({expr} [, {utf8}])', }, nvim_api__ = { @@ -7528,7 +7691,7 @@ M.funcs = { "|" is an operator or a command separator. ]=], name = 'or', - params = { { 'expr', 'any' }, { 'expr', 'any' } }, + params = { { 'expr', 'number' }, { 'expr', 'number' } }, signature = 'or({expr}, {expr})', }, pathshorten = { @@ -7550,7 +7713,7 @@ M.funcs = { ]=], name = 'pathshorten', - params = { { 'path', 'string' }, { 'len', 'any' } }, + params = { { 'path', 'string' }, { 'len', 'integer' } }, signature = 'pathshorten({path} [, {len}])', }, perleval = { @@ -7593,7 +7756,7 @@ M.funcs = { ]=], name = 'pow', - params = { { 'x', 'any' }, { 'y', 'any' } }, + params = { { 'x', 'number' }, { 'y', 'number' } }, signature = 'pow({x}, {y})', }, prevnonblank = { @@ -7941,7 +8104,7 @@ M.funcs = { ]=], name = 'printf', - params = { { 'fmt', 'any' }, { 'expr1', 'any' } }, + params = { { 'fmt', 'string' }, { 'expr1', 'any' } }, signature = 'printf({fmt}, {expr1} ...)', returns = 'string', }, @@ -7957,7 +8120,7 @@ M.funcs = { ]=], name = 'prompt_getprompt', - params = { { 'buf', 'any' } }, + params = { { 'buf', 'integer|string' } }, signature = 'prompt_getprompt({buf})', }, prompt_setcallback = { @@ -7997,7 +8160,7 @@ M.funcs = { ]=], name = 'prompt_setcallback', - params = { { 'buf', 'any' }, { 'expr', 'any' } }, + params = { { 'buf', 'integer|string' }, { 'expr', 'string|function' } }, signature = 'prompt_setcallback({buf}, {expr})', }, prompt_setinterrupt = { @@ -8014,7 +8177,7 @@ M.funcs = { ]=], name = 'prompt_setinterrupt', - params = { { 'buf', 'any' }, { 'expr', 'any' } }, + params = { { 'buf', 'integer|string' }, { 'expr', 'string|function' } }, signature = 'prompt_setinterrupt({buf}, {expr})', }, prompt_setprompt = { @@ -8029,7 +8192,7 @@ M.funcs = { < ]=], name = 'prompt_setprompt', - params = { { 'buf', 'any' }, { 'text', 'any' } }, + params = { { 'buf', 'integer|string' }, { 'text', 'string' } }, signature = 'prompt_setprompt({buf}, {text})', }, pum_getpos = { @@ -8133,7 +8296,7 @@ M.funcs = { < ]=], name = 'rand', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, signature = 'rand([{expr}])', }, range = { @@ -8159,7 +8322,7 @@ M.funcs = { < ]=], name = 'range', - params = { { 'expr', 'any' }, { 'max', 'any' }, { 'stride', 'any' } }, + params = { { 'expr', 'any' }, { 'max', 'integer' }, { 'stride', 'integer' } }, signature = 'range({expr} [, {max} [, {stride}]])', tags = { 'E726', 'E727' }, }, @@ -8191,7 +8354,7 @@ M.funcs = { Also see |readfile()| and |writefile()|. ]=], name = 'readblob', - params = { { 'fname', 'string' }, { 'offset', 'any' }, { 'size', 'any' } }, + params = { { 'fname', 'string' }, { 'offset', 'integer' }, { 'size', 'integer' } }, signature = 'readblob({fname} [, {offset} [, {size}]])', }, readdir = { @@ -8229,7 +8392,7 @@ M.funcs = { ]=], name = 'readdir', - params = { { 'directory', 'any' }, { 'expr', 'any' } }, + params = { { 'directory', 'string' }, { 'expr', 'integer' } }, signature = 'readdir({directory} [, {expr}])', }, readfile = { @@ -8270,7 +8433,7 @@ M.funcs = { ]=], name = 'readfile', - params = { { 'fname', 'string' }, { 'type', 'any' }, { 'max', 'any' } }, + params = { { 'fname', 'string' }, { 'type', 'string' }, { 'max', 'integer' } }, signature = 'readfile({fname} [, {type} [, {max}]])', }, reduce = { @@ -8296,7 +8459,7 @@ M.funcs = { < ]=], name = 'reduce', - params = { { 'object', 'any' }, { 'func', 'any' }, { 'initial', 'any' } }, + params = { { 'object', 'any' }, { 'func', 'function' }, { 'initial', 'any' } }, signature = 'reduce({object}, {func} [, {initial}])', }, reg_executing = { @@ -8442,7 +8605,7 @@ M.funcs = { ]=], name = 'remove', - params = { { 'list', 'any' }, { 'idx', 'integer' }, { 'end', 'any' } }, + params = { { 'list', 'any[]' }, { 'idx', 'integer' }, { 'end', 'integer' } }, signature = 'remove({list}, {idx}, {end})', }, remove__2 = { @@ -8469,7 +8632,7 @@ M.funcs = { < ]=], name = 'remove', - params = { { 'blob', 'any' }, { 'idx', 'integer' }, { 'end', 'any' } }, + params = { { 'blob', 'any' }, { 'idx', 'integer' }, { 'end', 'integer' } }, signature = 'remove({blob}, {idx}, {end})', }, remove__4 = { @@ -8483,7 +8646,7 @@ M.funcs = { Returns zero on error. ]=], name = 'remove', - params = { { 'dict', 'any' }, { 'key', 'any' } }, + params = { { 'dict', 'any' }, { 'key', 'string' } }, signature = 'remove({dict}, {key})', }, rename = { @@ -8499,7 +8662,7 @@ M.funcs = { ]=], name = 'rename', - params = { { 'from', 'any' }, { 'to', 'any' } }, + params = { { 'from', 'string' }, { 'to', 'string' } }, signature = 'rename({from}, {to})', }, ['repeat'] = { @@ -8518,7 +8681,7 @@ M.funcs = { ]=], fast = true, name = 'repeat', - params = { { 'expr', 'any' }, { 'count', 'any' } }, + params = { { 'expr', 'any' }, { 'count', 'integer' } }, signature = 'repeat({expr}, {count})', }, resolve = { @@ -8541,7 +8704,7 @@ M.funcs = { ]=], fast = true, name = 'resolve', - params = { { 'filename', 'any' } }, + params = { { 'filename', 'string' } }, signature = 'resolve({filename})', }, reverse = { @@ -8582,7 +8745,7 @@ M.funcs = { ]=], float_func = 'round', name = 'round', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, signature = 'round({expr})', }, rpcnotify = { @@ -8595,7 +8758,7 @@ M.funcs = { < ]=], name = 'rpcnotify', - params = { { 'channel', 'any' }, { 'event', 'any' }, { 'args', 'any' } }, + params = { { 'channel', 'integer' }, { 'event', 'string' }, { 'args', 'any' } }, signature = 'rpcnotify({channel}, {event} [, {args}...])', }, rpcrequest = { @@ -8608,10 +8771,11 @@ M.funcs = { < ]=], name = 'rpcrequest', - params = { { 'channel', 'any' }, { 'method', 'any' }, { 'args', 'any' } }, + params = { { 'channel', 'integer' }, { 'method', 'string' }, { 'args', 'any' } }, signature = 'rpcrequest({channel}, {method} [, {args}...])', }, rpcstart = { + deprecated = true, args = { 1, 2 }, desc = [=[ Deprecated. Replace >vim @@ -8621,7 +8785,7 @@ M.funcs = { < ]=], name = 'rpcstart', - params = { { 'prog', 'any' }, { 'argv', 'any' } }, + params = { { 'prog', 'string' }, { 'argv', 'any' } }, signature = 'rpcstart({prog} [, {argv}])', }, rpcstop = { @@ -8665,7 +8829,7 @@ M.funcs = { ]=], name = 'screenattr', - params = { { 'row', 'any' }, { 'col', 'integer' } }, + params = { { 'row', 'integer' }, { 'col', 'integer' } }, signature = 'screenattr({row}, {col})', }, screenchar = { @@ -8683,7 +8847,7 @@ M.funcs = { ]=], name = 'screenchar', - params = { { 'row', 'any' }, { 'col', 'integer' } }, + params = { { 'row', 'integer' }, { 'col', 'integer' } }, signature = 'screenchar({row}, {col})', }, screenchars = { @@ -8698,7 +8862,7 @@ M.funcs = { ]=], name = 'screenchars', - params = { { 'row', 'any' }, { 'col', 'integer' } }, + params = { { 'row', 'integer' }, { 'col', 'integer' } }, signature = 'screenchars({row}, {col})', }, screencol = { @@ -8714,7 +8878,7 @@ M.funcs = { the following mappings: >vim nnoremap <expr> GG ":echom " .. screencol() .. "\n" nnoremap <silent> GG :echom screencol()<CR> - noremap GG <Cmd>echom screencol()<Cr> + noremap GG <Cmd>echom screencol()<CR> < ]=], name = 'screencol', @@ -8779,7 +8943,7 @@ M.funcs = { ]=], name = 'screenstring', - params = { { 'row', 'any' }, { 'col', 'integer' } }, + params = { { 'row', 'integer' }, { 'col', 'integer' } }, signature = 'screenstring({row}, {col})', }, search = { @@ -8840,6 +9004,9 @@ M.funcs = { The value must not be negative. A zero value is like not giving the argument. + Note: the timeout is only considered when searching, not + while evaluating the {skip} expression. + If the {skip} expression is given it is evaluated with the cursor positioned on the start of a match. If it evaluates to non-zero this match is skipped. This can be used, for @@ -8890,11 +9057,11 @@ M.funcs = { ]=], name = 'search', params = { - { 'pattern', 'any' }, + { 'pattern', 'string' }, { 'flags', 'string' }, - { 'stopline', 'any' }, + { 'stopline', 'integer' }, { 'timeout', 'integer' }, - { 'skip', 'any' }, + { 'skip', 'string|function' }, }, signature = 'search({pattern} [, {flags} [, {stopline} [, {timeout} [, {skip}]]]])', }, @@ -9050,7 +9217,7 @@ M.funcs = { < ]=], name = 'searchdecl', - params = { { 'name', 'string' }, { 'global', 'any' }, { 'thisblock', 'any' } }, + params = { { 'name', 'string' }, { 'global', 'boolean' }, { 'thisblock', 'boolean' } }, signature = 'searchdecl({name} [, {global} [, {thisblock}]])', }, searchpair = { @@ -9141,7 +9308,16 @@ M.funcs = { < ]=], name = 'searchpair', - params = {}, + params = { + { 'start', 'string' }, + { 'middle', 'string' }, + { 'end', 'string' }, + { 'flags', 'string' }, + { 'skip', 'string|function' }, + { 'stopline', 'integer' }, + { 'timeout', 'integer' }, + }, + returns = 'integer', signature = 'searchpair({start}, {middle}, {end} [, {flags} [, {skip} [, {stopline} [, {timeout}]]]])', }, searchpairpos = { @@ -9158,7 +9334,16 @@ M.funcs = { See |match-parens| for a bigger and more useful example. ]=], name = 'searchpairpos', - params = {}, + params = { + { 'start', 'string' }, + { 'middle', 'string' }, + { 'end', 'string' }, + { 'flags', 'string' }, + { 'skip', 'string|function' }, + { 'stopline', 'integer' }, + { 'timeout', 'integer' }, + }, + returns = '[integer, integer]', signature = 'searchpairpos({start}, {middle}, {end} [, {flags} [, {skip} [, {stopline} [, {timeout}]]]])', }, searchpos = { @@ -9182,11 +9367,11 @@ M.funcs = { ]=], name = 'searchpos', params = { - { 'pattern', 'any' }, + { 'pattern', 'string' }, { 'flags', 'string' }, - { 'stopline', 'any' }, + { 'stopline', 'integer' }, { 'timeout', 'integer' }, - { 'skip', 'any' }, + { 'skip', 'string|function' }, }, signature = 'searchpos({pattern} [, {flags} [, {stopline} [, {timeout} [, {skip}]]]])', }, @@ -9239,7 +9424,7 @@ M.funcs = { < ]=], name = 'serverstart', - params = { { 'address', 'any' } }, + params = { { 'address', 'string' } }, signature = 'serverstart([{address}])', }, serverstop = { @@ -9251,7 +9436,7 @@ M.funcs = { address in |serverlist()|. ]=], name = 'serverstop', - params = { { 'address', 'any' } }, + params = { { 'address', 'string' } }, signature = 'serverstop({address})', }, setbufline = { @@ -9284,7 +9469,7 @@ M.funcs = { ]=], name = 'setbufline', - params = { { 'buf', 'any' }, { 'lnum', 'integer' }, { 'text', 'any' } }, + params = { { 'buf', 'integer|string' }, { 'lnum', 'integer' }, { 'text', 'string|string[]' } }, signature = 'setbufline({buf}, {lnum}, {text})', }, setbufvar = { @@ -9306,7 +9491,7 @@ M.funcs = { ]=], name = 'setbufvar', - params = { { 'buf', 'any' }, { 'varname', 'string' }, { 'val', 'any' } }, + params = { { 'buf', 'integer|string' }, { 'varname', 'string' }, { 'val', 'any' } }, signature = 'setbufvar({buf}, {varname}, {val})', }, setcellwidths = { @@ -9340,14 +9525,14 @@ M.funcs = { To clear the overrides pass an empty {list}: >vim call setcellwidths([]) - <You can use the script $VIMRUNTIME/tools/emoji_list.vim to see + <You can use the script $VIMRUNTIME/tools/emoji_list.lua to see the effect for known emoji characters. Move the cursor through the text to check if the cell widths of your terminal match with what Vim knows about each emoji. If it doesn't look right you need to adjust the {list} argument. ]=], name = 'setcellwidths', - params = { { 'list', 'any' } }, + params = { { 'list', 'any[]' } }, signature = 'setcellwidths({list})', }, setcharpos = { @@ -9366,7 +9551,7 @@ M.funcs = { ]=], name = 'setcharpos', - params = { { 'expr', 'any' }, { 'list', 'any' } }, + params = { { 'expr', 'string' }, { 'list', 'integer[]' } }, signature = 'setcharpos({expr}, {list})', }, setcharsearch = { @@ -9394,7 +9579,7 @@ M.funcs = { ]=], name = 'setcharsearch', - params = { { 'dict', 'any' } }, + params = { { 'dict', 'string' } }, signature = 'setcharsearch({dict})', }, setcmdline = { @@ -9409,7 +9594,7 @@ M.funcs = { ]=], name = 'setcmdline', - params = { { 'str', 'any' }, { 'pos', 'any' } }, + params = { { 'str', 'string' }, { 'pos', 'integer' } }, signature = 'setcmdline({str} [, {pos}])', }, setcmdpos = { @@ -9432,14 +9617,14 @@ M.funcs = { ]=], name = 'setcmdpos', - params = { { 'pos', 'any' } }, + params = { { 'pos', 'integer' } }, signature = 'setcmdpos({pos})', }, setcursorcharpos = { args = { 1, 3 }, base = 1, name = 'setcursorcharpos', - params = { { 'lnum', 'integer' }, { 'col', 'integer' }, { 'off', 'any' } }, + params = { { 'lnum', 'integer' }, { 'col', 'integer' }, { 'off', 'integer' } }, signature = 'setcursorcharpos({lnum}, {col} [, {off}])', }, setcursorcharpos__1 = { @@ -9458,7 +9643,7 @@ M.funcs = { ]=], name = 'setcursorcharpos', - params = { { 'list', 'any' } }, + params = { { 'list', 'integer[]' } }, signature = 'setcursorcharpos({list})', }, setenv = { @@ -9473,7 +9658,7 @@ M.funcs = { ]=], name = 'setenv', - params = { { 'name', 'string' }, { 'val', 'any' } }, + params = { { 'name', 'string' }, { 'val', 'string' } }, signature = 'setenv({name}, {val})', }, setfperm = { @@ -9558,7 +9743,7 @@ M.funcs = { ]=], name = 'setloclist', - params = { { 'nr', 'integer' }, { 'list', 'any' }, { 'action', 'any' }, { 'what', 'any' } }, + params = { { 'nr', 'integer' }, { 'list', 'any' }, { 'action', 'string' }, { 'what', 'table' } }, signature = 'setloclist({nr}, {list} [, {action} [, {what}]])', }, setmatches = { @@ -9574,7 +9759,7 @@ M.funcs = { ]=], name = 'setmatches', - params = { { 'list', 'any' }, { 'win', 'any' } }, + params = { { 'list', 'any' }, { 'win', 'integer' } }, signature = 'setmatches({list} [, {win}])', }, setpos = { @@ -9631,7 +9816,7 @@ M.funcs = { ]=], name = 'setpos', - params = { { 'expr', 'any' }, { 'list', 'any' } }, + params = { { 'expr', 'string' }, { 'list', 'integer[]' } }, signature = 'setpos({expr}, {list})', }, setqflist = { @@ -9753,7 +9938,7 @@ M.funcs = { ]=], name = 'setqflist', - params = { { 'list', 'any' }, { 'action', 'any' }, { 'what', 'any' } }, + params = { { 'list', 'any[]' }, { 'action', 'string' }, { 'what', 'table' } }, signature = 'setqflist({list} [, {action} [, {what}]])', }, setreg = { @@ -9903,7 +10088,7 @@ M.funcs = { < ]=], name = 'settagstack', - params = { { 'nr', 'integer' }, { 'dict', 'any' }, { 'action', 'any' } }, + params = { { 'nr', 'integer' }, { 'dict', 'any' }, { 'action', 'string' } }, signature = 'settagstack({nr}, {dict} [, {action}])', }, setwinvar = { @@ -9969,7 +10154,7 @@ M.funcs = { ]=], name = 'shellescape', - params = { { 'string', 'string' }, { 'special', 'any' } }, + params = { { 'string', 'string' }, { 'special', 'boolean' } }, signature = 'shellescape({string} [, {special}])', }, shiftwidth = { @@ -10026,6 +10211,7 @@ M.funcs = { icon full path to the bitmap file for the sign. linehl highlight group used for the whole line the sign is placed in. + priority default priority value of the sign numhl highlight group used for the line number where the sign is placed. text text that is displayed when there is no icon @@ -10081,6 +10267,7 @@ M.funcs = { linehl highlight group used for the whole line the sign is placed in; not present if not set. name name of the sign + priority default priority value of the sign numhl highlight group used for the line number where the sign is placed; not present if not set. text text that is displayed when there is no icon @@ -10173,7 +10360,7 @@ M.funcs = { < ]=], name = 'sign_getplaced', - params = { { 'buf', 'any' }, { 'dict', 'vim.fn.sign_getplaced.dict' } }, + params = { { 'buf', 'integer|string' }, { 'dict', 'vim.fn.sign_getplaced.dict' } }, signature = 'sign_getplaced([{buf} [, {dict}]])', returns = 'vim.fn.sign_getplaced.ret.item[]', }, @@ -10255,10 +10442,10 @@ M.funcs = { ]=], name = 'sign_place', params = { - { 'id', 'any' }, - { 'group', 'any' }, + { 'id', 'integer' }, + { 'group', 'string' }, { 'name', 'string' }, - { 'buf', 'any' }, + { 'buf', 'integer|string' }, { 'dict', 'vim.fn.sign_place.dict' }, }, signature = 'sign_place({id}, {group}, {name}, {buf} [, {dict}])', @@ -10291,7 +10478,8 @@ M.funcs = { priority Priority of the sign. When multiple signs are placed on a line, the sign with the highest priority is used. If not specified, the - default value of 10 is used. See + default value of 10 is used, unless specified + otherwise by the sign definition. See |sign-priority| for more information. If {id} refers to an existing sign, then the existing sign is @@ -10480,7 +10668,7 @@ M.funcs = { ]=], name = 'simplify', - params = { { 'filename', 'any' } }, + params = { { 'filename', 'string' } }, signature = 'simplify({filename})', }, sin = { @@ -10499,7 +10687,7 @@ M.funcs = { ]=], float_func = 'sin', name = 'sin', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, signature = 'sin({expr})', }, sinh = { @@ -10519,7 +10707,7 @@ M.funcs = { ]=], float_func = 'sinh', name = 'sinh', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, signature = 'sinh({expr})', }, slice = { @@ -10537,7 +10725,7 @@ M.funcs = { ]=], name = 'slice', - params = { { 'expr', 'any' }, { 'start', 'any' }, { 'end', 'any' } }, + params = { { 'expr', 'any' }, { 'start', 'integer' }, { 'end', 'integer' } }, signature = 'slice({expr}, {start} [, {end}])', }, sockconnect = { @@ -10568,7 +10756,7 @@ M.funcs = { - 0 on invalid arguments or connection failure. ]=], name = 'sockconnect', - params = { { 'mode', 'string' }, { 'address', 'any' }, { 'opts', 'table' } }, + params = { { 'mode', 'string' }, { 'address', 'string' }, { 'opts', 'table' } }, signature = 'sockconnect({mode}, {address} [, {opts}])', }, sort = { @@ -10649,7 +10837,7 @@ M.funcs = { < ]=], name = 'sort', - params = { { 'list', 'any' }, { 'how', 'any' }, { 'dict', 'any' } }, + params = { { 'list', 'any' }, { 'how', 'string|function' }, { 'dict', 'any' } }, signature = 'sort({list} [, {how} [, {dict}]])', }, soundfold = { @@ -10665,7 +10853,7 @@ M.funcs = { ]=], name = 'soundfold', - params = { { 'word', 'any' } }, + params = { { 'word', 'string' } }, signature = 'soundfold({word})', }, spellbadword = { @@ -10697,7 +10885,7 @@ M.funcs = { ]=], name = 'spellbadword', - params = { { 'sentence', 'any' } }, + params = { { 'sentence', 'string' } }, signature = 'spellbadword([{sentence}])', }, spellsuggest = { @@ -10726,7 +10914,7 @@ M.funcs = { ]=], name = 'spellsuggest', - params = { { 'word', 'any' }, { 'max', 'any' }, { 'capital', 'any' } }, + params = { { 'word', 'string' }, { 'max', 'integer' }, { 'capital', 'boolean' } }, signature = 'spellsuggest({word} [, {max} [, {capital}]])', }, split = { @@ -10734,8 +10922,8 @@ M.funcs = { base = 1, desc = [=[ Make a |List| out of {string}. When {pattern} is omitted or - empty each white-separated sequence of characters becomes an - item. + empty each white space separated sequence of characters + becomes an item. Otherwise the string is split where {pattern} matches, removing the matched characters. 'ignorecase' is not used here, add \c to ignore case. |/\c| @@ -10759,7 +10947,7 @@ M.funcs = { ]=], name = 'split', - params = { { 'string', 'string' }, { 'pattern', 'any' }, { 'keepempty', 'any' } }, + params = { { 'string', 'string' }, { 'pattern', 'string' }, { 'keepempty', 'boolean' } }, signature = 'split({string} [, {pattern} [, {keepempty}]])', }, sqrt = { @@ -10781,7 +10969,7 @@ M.funcs = { ]=], float_func = 'sqrt', name = 'sqrt', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, signature = 'sqrt({expr})', }, srand = { @@ -10803,7 +10991,7 @@ M.funcs = { < ]=], name = 'srand', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, signature = 'srand([{expr}])', }, stdioopen = { @@ -10926,7 +11114,7 @@ M.funcs = { ]=], name = 'str2float', - params = { { 'string', 'string' }, { 'quoted', 'any' } }, + params = { { 'string', 'string' }, { 'quoted', 'boolean' } }, signature = 'str2float({string} [, {quoted}])', }, str2list = { @@ -10946,7 +11134,7 @@ M.funcs = { ]=], name = 'str2list', - params = { { 'string', 'string' }, { 'utf8', 'any' } }, + params = { { 'string', 'string' }, { 'utf8', 'boolean' } }, signature = 'str2list({string} [, {utf8}])', }, str2nr = { @@ -10973,7 +11161,7 @@ M.funcs = { ]=], name = 'str2nr', - params = { { 'string', 'string' }, { 'base', 'any' } }, + params = { { 'string', 'string' }, { 'base', 'integer' } }, signature = 'str2nr({string} [, {base}])', }, strcharlen = { @@ -11015,7 +11203,12 @@ M.funcs = { ]=], fast = true, name = 'strcharpart', - params = { { 'src', 'any' }, { 'start', 'any' }, { 'len', 'any' }, { 'skipcc', 'any' } }, + params = { + { 'src', 'string' }, + { 'start', 'integer' }, + { 'len', 'integer' }, + { 'skipcc', 'boolean' }, + }, signature = 'strcharpart({src}, {start} [, {len} [, {skipcc}]])', }, strchars = { @@ -11051,7 +11244,7 @@ M.funcs = { < ]=], name = 'strchars', - params = { { 'string', 'string' }, { 'skipcc', 'any' } }, + params = { { 'string', 'string' }, { 'skipcc', 'boolean' } }, returns = 'integer', signature = 'strchars({string} [, {skipcc}])', }, @@ -11100,7 +11293,7 @@ M.funcs = { ]=], name = 'strftime', - params = { { 'format', 'any' }, { 'time', 'any' } }, + params = { { 'format', 'string' }, { 'time', 'number' } }, returns = 'string', signature = 'strftime({format} [, {time}])', }, @@ -11671,7 +11864,7 @@ M.funcs = { ]=], name = 'synconcealed', params = { { 'lnum', 'integer' }, { 'col', 'integer' } }, - returns = '{[1]: integer, [2]: string, [3]: integer}', + returns = '[integer, string, integer]', signature = 'synconcealed({lnum}, {col})', }, synstack = { @@ -11809,7 +12002,7 @@ M.funcs = { ]=], name = 'tabpagebuflist', - params = { { 'arg', 'any' } }, + params = { { 'arg', 'integer' } }, signature = 'tabpagebuflist([{arg}])', }, tabpagenr = { @@ -11990,7 +12183,7 @@ M.funcs = { described in |terminal|. ]=], name = 'termopen', - params = { { 'cmd', 'any' }, { 'opts', 'table' } }, + params = { { 'cmd', 'string|string[]' }, { 'opts', 'table' } }, signature = 'termopen({cmd} [, {opts}])', }, test_garbagecollect_now = { @@ -11999,7 +12192,7 @@ M.funcs = { Like |garbagecollect()|, but executed right away. This must only be called directly to avoid any structure to exist internally, and |v:testing| must have been set before calling - any function. + any function. *E1142* ]=], params = {}, signature = 'test_garbagecollect_now()', @@ -12030,7 +12223,7 @@ M.funcs = { ]=], name = 'timer_info', - params = { { 'id', 'any' } }, + params = { { 'id', 'integer' } }, signature = 'timer_info([{id}])', }, timer_pause = { @@ -12051,7 +12244,7 @@ M.funcs = { ]=], name = 'timer_pause', - params = { { 'timer', 'any' }, { 'paused', 'any' } }, + params = { { 'timer', 'integer' }, { 'paused', 'boolean' } }, signature = 'timer_pause({timer}, {paused})', }, timer_start = { @@ -12090,7 +12283,7 @@ M.funcs = { ]=], name = 'timer_start', - params = { { 'time', 'any' }, { 'callback', 'any' }, { 'options', 'table' } }, + params = { { 'time', 'number' }, { 'callback', 'string|function' }, { 'options', 'table' } }, signature = 'timer_start({time}, {callback} [, {options}])', }, timer_stop = { @@ -12103,7 +12296,7 @@ M.funcs = { ]=], name = 'timer_stop', - params = { { 'timer', 'any' } }, + params = { { 'timer', 'integer' } }, signature = 'timer_stop({timer})', }, timer_stopall = { @@ -12128,7 +12321,7 @@ M.funcs = { ]=], fast = true, name = 'tolower', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'string' } }, returns = 'string', signature = 'tolower({expr})', }, @@ -12143,7 +12336,7 @@ M.funcs = { ]=], fast = true, name = 'toupper', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'string' } }, returns = 'string', signature = 'toupper({expr})', }, @@ -12205,7 +12398,7 @@ M.funcs = { ]=], name = 'trim', - params = { { 'text', 'any' }, { 'mask', 'string' }, { 'dir', '0|1|2' } }, + params = { { 'text', 'string' }, { 'mask', 'string' }, { 'dir', '0|1|2' } }, returns = 'string', signature = 'trim({text} [, {mask} [, {dir}]])', }, @@ -12228,7 +12421,7 @@ M.funcs = { ]=], float_func = 'trunc', name = 'trunc', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'number' } }, returns = 'integer', signature = 'trunc({expr})', }, @@ -12261,6 +12454,7 @@ M.funcs = { if myvar is v:null | endif <To check if the v:t_ variables exist use this: >vim if exists('v:t_number') | endif + < ]=], fast = true, @@ -12338,6 +12532,7 @@ M.funcs = { ]=], name = 'undotree', params = { { 'buf', 'integer|string' } }, + returns = 'vim.fn.undotree.ret', signature = 'undotree([{buf}])', }, uniq = { @@ -12395,8 +12590,8 @@ M.funcs = { params = { { 'string', 'string' }, { 'idx', 'integer' }, - { 'countcc', 'any' }, - { 'charidx', 'any' }, + { 'countcc', 'boolean' }, + { 'charidx', 'boolean' }, }, returns = 'integer', signature = 'utf16idx({string}, {idx} [, {countcc} [, {charidx}]])', @@ -12427,7 +12622,9 @@ M.funcs = { set to 8, it returns 8. |conceal| is ignored. For the byte position use |col()|. - For the use of {expr} see |col()|. + For the use of {expr} see |getpos()| and |col()|. + When {expr} is "$", it means the end of the cursor line, so + the result is the number of cells in the cursor line plus one. When 'virtualedit' is used {expr} can be [lnum, col, off], where "off" is the offset in screen columns from the start of @@ -12437,18 +12634,6 @@ M.funcs = { beyond the end of the line can be returned. Also see |'virtualedit'| - The accepted positions are: - . the cursor position - $ the end of the cursor line (the result is the - number of displayed characters in the cursor line - plus one) - 'x position of mark x (if the mark is not set, 0 is - returned) - v In Visual mode: the start of the Visual area (the - cursor is the end). When not in Visual mode - returns the cursor position. Differs from |'<| in - that it's updated right away. - If {list} is present and non-zero then virtcol() returns a List with the first and last screen position occupied by the character. @@ -12467,14 +12652,17 @@ M.funcs = { " With text " there", with 't at 'h': echo virtcol("'t") " returns 6 - <The first column is 1. 0 or [0, 0] is returned for an error. + < + The first column is 1. 0 or [0, 0] is returned for an error. + A more advanced example that echoes the maximum length of all lines: >vim echo max(map(range(1, line('$')), "virtcol([v:val, '$'])")) + < ]=], name = 'virtcol', - params = { { 'expr', 'any' }, { 'list', 'any' }, { 'winid', 'integer' } }, + params = { { 'expr', 'string|integer[]' }, { 'list', 'boolean' }, { 'winid', 'integer' } }, signature = 'virtcol({expr} [, {list} [, {winid}]])', }, virtcol2col = { @@ -12528,7 +12716,7 @@ M.funcs = { the old value is returned. See |non-zero-arg|. ]=], name = 'visualmode', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'boolean' } }, signature = 'visualmode([{expr}])', }, wait = { @@ -12550,7 +12738,7 @@ M.funcs = { -3 if an error occurred ]=], name = 'wait', - params = { { 'timeout', 'integer' }, { 'condition', 'any' }, { 'interval', 'any' } }, + params = { { 'timeout', 'integer' }, { 'condition', 'any' }, { 'interval', 'number' } }, signature = 'wait({timeout}, {condition} [, {interval}])', }, wildmenumode = { @@ -12588,7 +12776,7 @@ M.funcs = { ]=], name = 'win_execute', - params = { { 'id', 'any' }, { 'command', 'any' }, { 'silent', 'boolean' } }, + params = { { 'id', 'integer' }, { 'command', 'string' }, { 'silent', 'boolean' } }, signature = 'win_execute({id}, {command} [, {silent}])', }, win_findbuf = { @@ -12600,7 +12788,7 @@ M.funcs = { ]=], name = 'win_findbuf', - params = { { 'bufnr', 'any' } }, + params = { { 'bufnr', 'integer' } }, returns = 'integer[]', signature = 'win_findbuf({bufnr})', }, @@ -12618,7 +12806,7 @@ M.funcs = { ]=], name = 'win_getid', - params = { { 'win', 'any' }, { 'tab', 'any' } }, + params = { { 'win', 'integer' }, { 'tab', 'integer' } }, returns = 'integer', signature = 'win_getid([{win} [, {tab}]])', }, @@ -12659,7 +12847,7 @@ M.funcs = { ]=], name = 'win_gotoid', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'integer' } }, returns = '0|1', signature = 'win_gotoid({expr})', }, @@ -12673,7 +12861,7 @@ M.funcs = { ]=], name = 'win_id2tabwin', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'integer' } }, signature = 'win_id2tabwin({expr})', }, win_id2win = { @@ -12685,7 +12873,7 @@ M.funcs = { ]=], name = 'win_id2win', - params = { { 'expr', 'any' } }, + params = { { 'expr', 'integer' } }, signature = 'win_id2win({expr})', }, win_move_separator = { @@ -12708,7 +12896,7 @@ M.funcs = { ]=], name = 'win_move_separator', - params = { { 'nr', 'integer' }, { 'offset', 'any' } }, + params = { { 'nr', 'integer' }, { 'offset', 'integer' } }, signature = 'win_move_separator({nr}, {offset})', }, win_move_statusline = { @@ -12728,7 +12916,7 @@ M.funcs = { ]=], name = 'win_move_statusline', - params = { { 'nr', 'integer' }, { 'offset', 'any' } }, + params = { { 'nr', 'integer' }, { 'offset', 'integer' } }, signature = 'win_move_statusline({nr}, {offset})', }, win_screenpos = { @@ -12771,7 +12959,7 @@ M.funcs = { ]=], name = 'win_splitmove', - params = { { 'nr', 'integer' }, { 'target', 'any' }, { 'options', 'table' } }, + params = { { 'nr', 'integer' }, { 'target', 'integer' }, { 'options', 'table' } }, signature = 'win_splitmove({nr}, {target} [, {options}])', }, winbufnr = { @@ -12829,6 +13017,7 @@ M.funcs = { This excludes any window toolbar line. Examples: >vim echo "The current window has " .. winheight(0) .. " lines." + < ]=], name = 'winheight', @@ -12926,10 +13115,10 @@ M.funcs = { let window_count = winnr('$') let prev_window = winnr('#') let wnum = winnr('3k') - + < ]=], name = 'winnr', - params = { { 'arg', 'any' } }, + params = { { 'arg', 'string|integer' } }, signature = 'winnr([{arg}])', }, winrestcmd = { @@ -13101,6 +13290,7 @@ M.funcs = { To copy a file byte for byte: >vim let fl = readfile("foo", "b") call writefile(fl, "foocopy", "b") + < ]=], name = 'writefile', @@ -13119,7 +13309,7 @@ M.funcs = { < ]=], name = 'xor', - params = { { 'expr', 'any' }, { 'expr', 'any' } }, + params = { { 'expr', 'number' }, { 'expr', 'number' } }, signature = 'xor({expr}, {expr})', }, } diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c index d7df7bb150..afc2efddf6 100644 --- a/src/nvim/eval/decode.c +++ b/src/nvim/eval/decode.c @@ -1,5 +1,4 @@ #include <assert.h> -#include <msgpack/object.h> #include <stdbool.h> #include <stddef.h> #include <stdint.h> @@ -7,6 +6,7 @@ #include <string.h> #include "klib/kvec.h" +#include "mpack/object.h" #include "nvim/ascii_defs.h" #include "nvim/charset.h" #include "nvim/eval.h" @@ -247,45 +247,29 @@ list_T *decode_create_map_special_dict(typval_T *const ret_tv, const ptrdiff_t l /// /// @param[in] s String to decode. /// @param[in] len String length. -/// @param[in] hasnul Whether string has NUL byte, not or it was not yet -/// determined. -/// @param[in] binary Determines decode type if string has NUL bytes. -/// If true convert string to VAR_BLOB, otherwise to the -/// kMPString special type. +/// @param[in] force_blob whether string always should be decoded as a blob, +/// or only when embedded NUL bytes were present /// @param[in] s_allocated If true, then `s` was allocated and can be saved in /// a returned structure. If it is not saved there, it /// will be freed. /// /// @return Decoded string. -typval_T decode_string(const char *const s, const size_t len, const TriState hasnul, - const bool binary, const bool s_allocated) +typval_T decode_string(const char *const s, const size_t len, bool force_blob, + const bool s_allocated) FUNC_ATTR_WARN_UNUSED_RESULT { assert(s != NULL || len == 0); - const bool really_hasnul = (hasnul == kNone - ? ((s != NULL) && (memchr(s, NUL, len) != NULL)) - : (bool)hasnul); - if (really_hasnul) { + const bool use_blob = force_blob || ((s != NULL) && (memchr(s, NUL, len) != NULL)); + if (use_blob) { typval_T tv; tv.v_lock = VAR_UNLOCKED; - if (binary) { - tv_blob_alloc_ret(&tv); - ga_concat_len(&tv.vval.v_blob->bv_ga, s, len); + blob_T *b = tv_blob_alloc_ret(&tv); + if (s_allocated) { + b->bv_ga.ga_data = (void *)s; + b->bv_ga.ga_len = (int)len; + b->bv_ga.ga_maxlen = (int)len; } else { - list_T *const list = tv_list_alloc(kListLenMayKnow); - tv_list_ref(list); - create_special_dict(&tv, kMPString, - (typval_T){ .v_type = VAR_LIST, - .v_lock = VAR_UNLOCKED, - .vval = { .v_list = list } }); - const int elw_ret = encode_list_write((void *)list, s, len); - if (s_allocated) { - xfree((void *)s); - } - if (elw_ret == -1) { - tv_clear(&tv); - return (typval_T) { .v_type = VAR_UNKNOWN, .v_lock = VAR_UNLOCKED }; - } + ga_concat_len(&b->bv_ga, s, len); } return tv; } @@ -405,7 +389,6 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len, char *str = xmalloc(len + 1); int fst_in_pair = 0; char *str_end = str; - bool hasnul = false; #define PUT_FST_IN_PAIR(fst_in_pair, str_end) \ do { \ if ((fst_in_pair) != 0) { \ @@ -426,9 +409,6 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len, uvarnumber_T ch; vim_str2nr(ubuf, NULL, NULL, STR2NR_HEX | STR2NR_FORCE, NULL, &ch, 4, true, NULL); - if (ch == 0) { - hasnul = true; - } if (SURROGATE_HI_START <= ch && ch <= SURROGATE_HI_END) { PUT_FST_IN_PAIR(fst_in_pair, str_end); fst_in_pair = (int)ch; @@ -476,10 +456,7 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len, PUT_FST_IN_PAIR(fst_in_pair, str_end); #undef PUT_FST_IN_PAIR *str_end = NUL; - typval_T obj = decode_string(str, (size_t)(str_end - str), hasnul ? kTrue : kFalse, false, true); - if (obj.v_type == VAR_UNKNOWN) { - goto parse_json_string_fail; - } + typval_T obj = decode_string(str, (size_t)(str_end - str), false, true); POP(obj, obj.v_type != VAR_STRING); goto parse_json_string_ret; parse_json_string_fail: @@ -908,182 +885,250 @@ json_decode_string_ret: #undef DICT_LEN -/// Convert msgpack object to a Vimscript one -int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +static void positive_integer_to_special_typval(typval_T *rettv, uint64_t val) { - switch (mobj.type) { - case MSGPACK_OBJECT_NIL: + if (val <= VARNUMBER_MAX) { *rettv = (typval_T) { + .v_type = VAR_NUMBER, + .v_lock = VAR_UNLOCKED, + .vval = { .v_number = (varnumber_T)val }, + }; + } else { + list_T *const list = tv_list_alloc(4); + tv_list_ref(list); + create_special_dict(rettv, kMPInteger, ((typval_T) { + .v_type = VAR_LIST, + .v_lock = VAR_UNLOCKED, + .vval = { .v_list = list }, + })); + tv_list_append_number(list, 1); + tv_list_append_number(list, (varnumber_T)((val >> 62) & 0x3)); + tv_list_append_number(list, (varnumber_T)((val >> 31) & 0x7FFFFFFF)); + tv_list_append_number(list, (varnumber_T)(val & 0x7FFFFFFF)); + } +} + +static void typval_parse_enter(mpack_parser_t *parser, mpack_node_t *node) +{ + typval_T *result = NULL; + + mpack_node_t *parent = MPACK_PARENT_NODE(node); + if (parent) { + switch (parent->tok.type) { + case MPACK_TOKEN_ARRAY: { + list_T *list = parent->data[1].p; + result = tv_list_append_owned_tv(list, (typval_T) { .v_type = VAR_UNKNOWN }); + break; + } + case MPACK_TOKEN_MAP: { + typval_T(*items)[2] = parent->data[1].p; + result = &items[parent->pos][parent->key_visited]; + break; + } + + case MPACK_TOKEN_STR: + case MPACK_TOKEN_BIN: + case MPACK_TOKEN_EXT: + assert(node->tok.type == MPACK_TOKEN_CHUNK); + break; + + default: + abort(); + } + } else { + result = parser->data.p; + } + + // for types that are completed in typval_parse_exit + node->data[0].p = result; + node->data[1].p = NULL; // free on error if non-NULL + + switch (node->tok.type) { + case MPACK_TOKEN_NIL: + *result = (typval_T) { .v_type = VAR_SPECIAL, .v_lock = VAR_UNLOCKED, .vval = { .v_special = kSpecialVarNull }, }; break; - case MSGPACK_OBJECT_BOOLEAN: - *rettv = (typval_T) { + case MPACK_TOKEN_BOOLEAN: + *result = (typval_T) { .v_type = VAR_BOOL, .v_lock = VAR_UNLOCKED, .vval = { - .v_bool = mobj.via.boolean ? kBoolVarTrue : kBoolVarFalse + .v_bool = mpack_unpack_boolean(node->tok) ? kBoolVarTrue : kBoolVarFalse }, }; break; - case MSGPACK_OBJECT_POSITIVE_INTEGER: - if (mobj.via.u64 <= VARNUMBER_MAX) { - *rettv = (typval_T) { - .v_type = VAR_NUMBER, - .v_lock = VAR_UNLOCKED, - .vval = { .v_number = (varnumber_T)mobj.via.u64 }, - }; - } else { - list_T *const list = tv_list_alloc(4); - tv_list_ref(list); - create_special_dict(rettv, kMPInteger, ((typval_T) { - .v_type = VAR_LIST, - .v_lock = VAR_UNLOCKED, - .vval = { .v_list = list }, - })); - uint64_t n = mobj.via.u64; - tv_list_append_number(list, 1); - tv_list_append_number(list, (varnumber_T)((n >> 62) & 0x3)); - tv_list_append_number(list, (varnumber_T)((n >> 31) & 0x7FFFFFFF)); - tv_list_append_number(list, (varnumber_T)(n & 0x7FFFFFFF)); - } + case MPACK_TOKEN_SINT: { + *result = (typval_T) { + .v_type = VAR_NUMBER, + .v_lock = VAR_UNLOCKED, + .vval = { .v_number = mpack_unpack_sint(node->tok) }, + }; break; - case MSGPACK_OBJECT_NEGATIVE_INTEGER: - if (mobj.via.i64 >= VARNUMBER_MIN) { - *rettv = (typval_T) { - .v_type = VAR_NUMBER, - .v_lock = VAR_UNLOCKED, - .vval = { .v_number = (varnumber_T)mobj.via.i64 }, - }; - } else { - list_T *const list = tv_list_alloc(4); - tv_list_ref(list); - create_special_dict(rettv, kMPInteger, ((typval_T) { - .v_type = VAR_LIST, - .v_lock = VAR_UNLOCKED, - .vval = { .v_list = list }, - })); - uint64_t n = -((uint64_t)mobj.via.i64); - tv_list_append_number(list, -1); - tv_list_append_number(list, (varnumber_T)((n >> 62) & 0x3)); - tv_list_append_number(list, (varnumber_T)((n >> 31) & 0x7FFFFFFF)); - tv_list_append_number(list, (varnumber_T)(n & 0x7FFFFFFF)); - } + } + case MPACK_TOKEN_UINT: + positive_integer_to_special_typval(result, mpack_unpack_uint(node->tok)); break; - case MSGPACK_OBJECT_FLOAT32: - case MSGPACK_OBJECT_FLOAT64: - *rettv = (typval_T) { + case MPACK_TOKEN_FLOAT: + *result = (typval_T) { .v_type = VAR_FLOAT, .v_lock = VAR_UNLOCKED, - .vval = { .v_float = mobj.via.f64 }, + .vval = { .v_float = mpack_unpack_float(node->tok) }, }; break; - case MSGPACK_OBJECT_STR: - *rettv = decode_string(mobj.via.bin.ptr, mobj.via.bin.size, kTrue, false, - false); - if (rettv->v_type == VAR_UNKNOWN) { - return FAIL; - } + + case MPACK_TOKEN_BIN: + case MPACK_TOKEN_STR: + case MPACK_TOKEN_EXT: + // actually converted in typval_parse_exit after the data chunks + node->data[1].p = xmallocz(node->tok.length); break; - case MSGPACK_OBJECT_BIN: - *rettv = decode_string(mobj.via.bin.ptr, mobj.via.bin.size, kNone, true, - false); - if (rettv->v_type == VAR_UNKNOWN) { - return FAIL; - } + case MPACK_TOKEN_CHUNK: { + char *data = parent->data[1].p; + memcpy(data + parent->pos, + node->tok.data.chunk_ptr, node->tok.length); break; - case MSGPACK_OBJECT_ARRAY: { - list_T *const list = tv_list_alloc((ptrdiff_t)mobj.via.array.size); + } + + case MPACK_TOKEN_ARRAY: { + list_T *const list = tv_list_alloc((ptrdiff_t)node->tok.length); tv_list_ref(list); - *rettv = (typval_T) { + *result = (typval_T) { .v_type = VAR_LIST, .v_lock = VAR_UNLOCKED, .vval = { .v_list = list }, }; - for (size_t i = 0; i < mobj.via.array.size; i++) { - // Not populated yet, need to create list item to push. - tv_list_append_owned_tv(list, (typval_T) { .v_type = VAR_UNKNOWN }); - if (msgpack_to_vim(mobj.via.array.ptr[i], - TV_LIST_ITEM_TV(tv_list_last(list))) - == FAIL) { - return FAIL; - } + node->data[1].p = list; + break; + } + case MPACK_TOKEN_MAP: + // we don't know if this will be safe to convert to a typval dict yet + node->data[1].p = xmallocz(node->tok.length * 2 * sizeof(typval_T)); + break; + } +} + +/// Free node which was entered but never exited, due to a nested error +/// +/// Don't bother with typvals as these will be GC:d eventually +void typval_parser_error_free(mpack_parser_t *parser) +{ + for (uint32_t i = 0; i < parser->size; i++) { + mpack_node_t *node = &parser->items[i]; + switch (node->tok.type) { + case MPACK_TOKEN_BIN: + case MPACK_TOKEN_STR: + case MPACK_TOKEN_EXT: + case MPACK_TOKEN_MAP: + XFREE_CLEAR(node->data[1].p); + break; + default: + break; } + } +} + +static void typval_parse_exit(mpack_parser_t *parser, mpack_node_t *node) +{ + typval_T *result = node->data[0].p; + switch (node->tok.type) { + case MPACK_TOKEN_BIN: + case MPACK_TOKEN_STR: + *result = decode_string(node->data[1].p, node->tok.length, false, true); + node->data[1].p = NULL; break; + + case MPACK_TOKEN_EXT: { + list_T *const list = tv_list_alloc(2); + tv_list_ref(list); + tv_list_append_number(list, node->tok.data.ext_type); + list_T *const ext_val_list = tv_list_alloc(kListLenMayKnow); + tv_list_append_list(list, ext_val_list); + create_special_dict(result, kMPExt, ((typval_T) { .v_type = VAR_LIST, + .v_lock = VAR_UNLOCKED, + .vval = { .v_list = list } })); + // TODO(bfredl): why not use BLOB? + encode_list_write((void *)ext_val_list, node->data[1].p, node->tok.length); + XFREE_CLEAR(node->data[1].p); } - case MSGPACK_OBJECT_MAP: { - for (size_t i = 0; i < mobj.via.map.size; i++) { - if (mobj.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR - || mobj.via.map.ptr[i].key.via.str.size == 0 - || memchr(mobj.via.map.ptr[i].key.via.str.ptr, NUL, - mobj.via.map.ptr[i].key.via.str.size) != NULL) { + break; + + case MPACK_TOKEN_MAP: { + typval_T(*items)[2] = node->data[1].p; + for (size_t i = 0; i < node->tok.length; i++) { + typval_T *key = &items[i][0]; + if (key->v_type != VAR_STRING + || key->vval.v_string == NULL + || key->vval.v_string[0] == NUL) { goto msgpack_to_vim_generic_map; } } dict_T *const dict = tv_dict_alloc(); dict->dv_refcount++; - *rettv = (typval_T) { + *result = (typval_T) { .v_type = VAR_DICT, .v_lock = VAR_UNLOCKED, .vval = { .v_dict = dict }, }; - for (size_t i = 0; i < mobj.via.map.size; i++) { - dictitem_T *const di = xmallocz(offsetof(dictitem_T, di_key) - + mobj.via.map.ptr[i].key.via.str.size); - memcpy(&di->di_key[0], mobj.via.map.ptr[i].key.via.str.ptr, - mobj.via.map.ptr[i].key.via.str.size); + for (size_t i = 0; i < node->tok.length; i++) { + char *key = items[i][0].vval.v_string; + size_t keylen = strlen(key); + dictitem_T *const di = xmallocz(offsetof(dictitem_T, di_key) + keylen); + memcpy(&di->di_key[0], key, keylen); di->di_tv.v_type = VAR_UNKNOWN; if (tv_dict_add(dict, di) == FAIL) { // Duplicate key: fallback to generic map - tv_clear(rettv); + TV_DICT_ITER(dict, d, { + d->di_tv.v_type = VAR_SPECIAL; // don't free values in tv_clear(), they will be reused + d->di_tv.vval.v_special = kSpecialVarNull; + }); + tv_clear(result); xfree(di); goto msgpack_to_vim_generic_map; } - if (msgpack_to_vim(mobj.via.map.ptr[i].val, &di->di_tv) == FAIL) { - return FAIL; - } + di->di_tv = items[i][1]; + } + for (size_t i = 0; i < node->tok.length; i++) { + xfree(items[i][0].vval.v_string); } + XFREE_CLEAR(node->data[1].p); break; msgpack_to_vim_generic_map: {} - list_T *const list = decode_create_map_special_dict(rettv, (ptrdiff_t)mobj.via.map.size); - for (size_t i = 0; i < mobj.via.map.size; i++) { + list_T *const list = decode_create_map_special_dict(result, node->tok.length); + for (size_t i = 0; i < node->tok.length; i++) { list_T *const kv_pair = tv_list_alloc(2); tv_list_append_list(list, kv_pair); - typval_T key_tv = { .v_type = VAR_UNKNOWN }; - if (msgpack_to_vim(mobj.via.map.ptr[i].key, &key_tv) == FAIL) { - tv_clear(&key_tv); - return FAIL; - } - tv_list_append_owned_tv(kv_pair, key_tv); - - typval_T val_tv = { .v_type = VAR_UNKNOWN }; - if (msgpack_to_vim(mobj.via.map.ptr[i].val, &val_tv) == FAIL) { - tv_clear(&val_tv); - return FAIL; - } - tv_list_append_owned_tv(kv_pair, val_tv); + tv_list_append_owned_tv(kv_pair, items[i][0]); + tv_list_append_owned_tv(kv_pair, items[i][1]); } + XFREE_CLEAR(node->data[1].p); break; } - case MSGPACK_OBJECT_EXT: { - list_T *const list = tv_list_alloc(2); - tv_list_ref(list); - tv_list_append_number(list, mobj.via.ext.type); - list_T *const ext_val_list = tv_list_alloc(kListLenMayKnow); - tv_list_append_list(list, ext_val_list); - create_special_dict(rettv, kMPExt, ((typval_T) { .v_type = VAR_LIST, - .v_lock = VAR_UNLOCKED, - .vval = { .v_list = list } })); - if (encode_list_write((void *)ext_val_list, mobj.via.ext.ptr, - mobj.via.ext.size) == -1) { - return FAIL; - } + + default: + // other kinds are handled completely in typval_parse_enter break; } +} + +int mpack_parse_typval(mpack_parser_t *parser, const char **data, size_t *size) +{ + return mpack_parse(parser, data, size, typval_parse_enter, typval_parse_exit); +} + +int unpack_typval(const char **data, size_t *size, typval_T *ret) +{ + ret->v_type = VAR_UNKNOWN; + mpack_parser_t parser; + mpack_parser_init(&parser, 0); + parser.data.p = ret; + int status = mpack_parse_typval(&parser, data, size); + if (status != MPACK_OK) { + typval_parser_error_free(&parser); + tv_clear(ret); } - return OK; + return status; } diff --git a/src/nvim/eval/decode.h b/src/nvim/eval/decode.h index c0d10a469a..485cc65561 100644 --- a/src/nvim/eval/decode.h +++ b/src/nvim/eval/decode.h @@ -1,8 +1,8 @@ #pragma once -#include <msgpack.h> // IWYU pragma: keep #include <stddef.h> // IWYU pragma: keep +#include "mpack/object.h" #include "nvim/eval/typval_defs.h" // IWYU pragma: keep #include "nvim/types_defs.h" // IWYU pragma: keep diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index d35ac4eb7b..79f334601d 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -13,7 +13,7 @@ #include <string.h> #include "klib/kvec.h" -#include "msgpack/pack.h" +#include "nvim/api/private/helpers.h" #include "nvim/ascii_defs.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" @@ -28,6 +28,7 @@ #include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/message.h" +#include "nvim/msgpack_rpc/packer.h" #include "nvim/strings.h" #include "nvim/types_defs.h" #include "nvim/vim_defs.h" // For _() @@ -54,11 +55,11 @@ int encode_blob_write(void *const data, const char *const buf, const size_t len) } /// Msgpack callback for writing to readfile()-style list -int encode_list_write(void *const data, const char *const buf, const size_t len) +void encode_list_write(void *const data, const char *const buf, const size_t len) FUNC_ATTR_NONNULL_ARG(1) { if (len == 0) { - return 0; + return; } list_T *const list = (list_T *)data; const char *const end = buf + len; @@ -96,7 +97,6 @@ int encode_list_write(void *const data, const char *const buf, const size_t len) if (line_end == end) { tv_list_append_allocated_string(list, NULL); } - return 0; } /// Abort conversion to string after a recursion error. @@ -412,6 +412,8 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s #define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ ga_concat(gap, "{}") +#define TYPVAL_ENCODE_CHECK_BEFORE + #define TYPVAL_ENCODE_CONV_NIL(tv) \ ga_concat(gap, "v:null") @@ -536,6 +538,8 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s #undef TYPVAL_ENCODE_ALLOW_SPECIALS #define TYPVAL_ENCODE_ALLOW_SPECIALS true +#define TYPVAL_ENCODE_CHECK_BEFORE + #undef TYPVAL_ENCODE_CONV_NIL #define TYPVAL_ENCODE_CONV_NIL(tv) \ ga_concat(gap, "null") @@ -771,8 +775,7 @@ bool encode_check_json_key(const typval_T *const tv) const dictitem_T *val_di; if ((type_di = tv_dict_find(spdict, S_LEN("_TYPE"))) == NULL || type_di->di_tv.v_type != VAR_LIST - || (type_di->di_tv.vval.v_list != eval_msgpack_type_lists[kMPString] - && type_di->di_tv.vval.v_list != eval_msgpack_type_lists[kMPBinary]) + || type_di->di_tv.vval.v_list != eval_msgpack_type_lists[kMPString] || (val_di = tv_dict_find(spdict, S_LEN("_VAL"))) == NULL || val_di->di_tv.v_type != VAR_LIST) { return false; @@ -821,6 +824,7 @@ bool encode_check_json_key(const typval_T *const tv) #undef TYPVAL_ENCODE_CONV_LIST_START #undef TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START #undef TYPVAL_ENCODE_CONV_EMPTY_DICT +#undef TYPVAL_ENCODE_CHECK_BEFORE #undef TYPVAL_ENCODE_CONV_NIL #undef TYPVAL_ENCODE_CONV_BOOL #undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER @@ -855,7 +859,7 @@ char *encode_tv2string(typval_T *tv, size_t *len) if (len != NULL) { *len = (size_t)ga.ga_len; } - ga_append(&ga, '\0'); + ga_append(&ga, NUL); return (char *)ga.ga_data; } @@ -883,7 +887,7 @@ char *encode_tv2echo(typval_T *tv, size_t *len) if (len != NULL) { *len = (size_t)ga.ga_len; } - ga_append(&ga, '\0'); + ga_append(&ga, NUL); return (char *)ga.ga_data; } @@ -908,57 +912,27 @@ char *encode_tv2json(typval_T *tv, size_t *len) if (len != NULL) { *len = (size_t)ga.ga_len; } - ga_append(&ga, '\0'); + ga_append(&ga, NUL); return (char *)ga.ga_data; } #define TYPVAL_ENCODE_CONV_STRING(tv, buf, len) \ - do { \ - if ((buf) == NULL) { \ - msgpack_pack_bin(packer, 0); \ - } else { \ - const size_t len_ = (len); \ - msgpack_pack_bin(packer, len_); \ - msgpack_pack_bin_body(packer, buf, len_); \ - } \ - } while (0) + mpack_bin(cbuf_as_string(buf, (len)), packer); \ #define TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len) \ - do { \ - if ((buf) == NULL) { \ - msgpack_pack_str(packer, 0); \ - } else { \ - const size_t len_ = (len); \ - msgpack_pack_str(packer, len_); \ - msgpack_pack_str_body(packer, buf, len_); \ - } \ - } while (0) + mpack_str(cbuf_as_string(buf, (len)), packer); \ #define TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type) \ - do { \ - if ((buf) == NULL) { \ - msgpack_pack_ext(packer, 0, (int8_t)(type)); \ - } else { \ - const size_t len_ = (len); \ - msgpack_pack_ext(packer, len_, (int8_t)(type)); \ - msgpack_pack_ext_body(packer, buf, len_); \ - } \ - } while (0) + mpack_ext(buf, (len), (int8_t)(type), packer); \ #define TYPVAL_ENCODE_CONV_BLOB(tv, blob, len) \ - do { \ - const size_t len_ = (size_t)(len); \ - msgpack_pack_bin(packer, len_); \ - if (len_ > 0) { \ - msgpack_pack_bin_body(packer, (blob)->bv_ga.ga_data, len_); \ - } \ - } while (0) + mpack_bin(cbuf_as_string((blob) ? (blob)->bv_ga.ga_data : NULL, (size_t)(len)), packer); #define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \ - msgpack_pack_int64(packer, (int64_t)(num)) + mpack_integer(&packer->ptr, (Integer)(num)) #define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \ - msgpack_pack_double(packer, (double)(flt)) + mpack_float8(&packer->ptr, (double)(flt)) #define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ return conv_error(_("E5004: Error while dumping %s, %s: " \ @@ -970,33 +944,30 @@ char *encode_tv2json(typval_T *tv, size_t *len) #define TYPVAL_ENCODE_CONV_FUNC_END(tv) #define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \ - msgpack_pack_array(packer, 0) + mpack_array(&packer->ptr, 0) #define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \ - msgpack_pack_array(packer, (size_t)(len)) + mpack_array(&packer->ptr, (uint32_t)(len)) #define TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, mpsv) #define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ - msgpack_pack_map(packer, 0) + mpack_map(&packer->ptr, 0) + +#define TYPVAL_ENCODE_CHECK_BEFORE \ + mpack_check_buffer(packer) #define TYPVAL_ENCODE_CONV_NIL(tv) \ - msgpack_pack_nil(packer) + mpack_nil(&packer->ptr) #define TYPVAL_ENCODE_CONV_BOOL(tv, num) \ - do { \ - if (num) { \ - msgpack_pack_true(packer); \ - } else { \ - msgpack_pack_false(packer); \ - } \ - } while (0) + mpack_bool(&packer->ptr, (bool)num); \ #define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, num) \ - msgpack_pack_uint64(packer, (num)) + mpack_uint64(&packer->ptr, (num)) #define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) \ - msgpack_pack_map(packer, (size_t)(len)) + mpack_map(&packer->ptr, (uint32_t)(len)) #define TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(tv, dict, mpsv) @@ -1021,7 +992,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) #define TYPVAL_ENCODE_SCOPE #define TYPVAL_ENCODE_NAME msgpack -#define TYPVAL_ENCODE_FIRST_ARG_TYPE msgpack_packer *const +#define TYPVAL_ENCODE_FIRST_ARG_TYPE PackerBuffer *const #define TYPVAL_ENCODE_FIRST_ARG_NAME packer #include "nvim/eval/typval_encode.c.h" #undef TYPVAL_ENCODE_SCOPE @@ -1043,6 +1014,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) #undef TYPVAL_ENCODE_CONV_LIST_START #undef TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START #undef TYPVAL_ENCODE_CONV_EMPTY_DICT +#undef TYPVAL_ENCODE_CHECK_BEFORE #undef TYPVAL_ENCODE_CONV_NIL #undef TYPVAL_ENCODE_CONV_BOOL #undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER diff --git a/src/nvim/eval/encode.h b/src/nvim/eval/encode.h index 6d1c0b61c5..2bacc82b0d 100644 --- a/src/nvim/eval/encode.h +++ b/src/nvim/eval/encode.h @@ -1,10 +1,10 @@ #pragma once -#include <msgpack/pack.h> #include <string.h> #include "nvim/eval/typval_defs.h" #include "nvim/garray_defs.h" +#include "nvim/msgpack_rpc/packer_defs.h" /// Convert Vimscript value to msgpack string /// @@ -13,7 +13,7 @@ /// @param[in] objname Object name, used for error message. /// /// @return OK in case of success, FAIL otherwise. -int encode_vim_to_msgpack(msgpack_packer *packer, typval_T *tv, const char *objname); +int encode_vim_to_msgpack(PackerBuffer *packer, typval_T *tv, const char *objname); /// Convert Vimscript value to :echo output /// diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c index 1b8c057d7c..5b92f217d1 100644 --- a/src/nvim/eval/executor.c +++ b/src/nvim/eval/executor.c @@ -1,6 +1,7 @@ #include <inttypes.h> #include <stdlib.h> +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/executor.h" #include "nvim/eval/typval.h" @@ -20,6 +21,174 @@ char *e_list_index_out_of_range_nr = N_("E684: List index out of range: %" PRId64); +/// Handle "blob1 += blob2". +/// Returns OK or FAIL. +static int tv_op_blob(typval_T *tv1, const typval_T *tv2, const char *op) + FUNC_ATTR_NONNULL_ALL +{ + if (*op != '+' || tv2->v_type != VAR_BLOB) { + return FAIL; + } + + // Blob += Blob + if (tv2->vval.v_blob == NULL) { + return OK; + } + + if (tv1->vval.v_blob == NULL) { + tv1->vval.v_blob = tv2->vval.v_blob; + tv1->vval.v_blob->bv_refcount++; + return OK; + } + + blob_T *const b1 = tv1->vval.v_blob; + blob_T *const b2 = tv2->vval.v_blob; + const int len = tv_blob_len(b2); + + for (int i = 0; i < len; i++) { + ga_append(&b1->bv_ga, tv_blob_get(b2, i)); + } + + return OK; +} + +/// Handle "list1 += list2". +/// Returns OK or FAIL. +static int tv_op_list(typval_T *tv1, const typval_T *tv2, const char *op) + FUNC_ATTR_NONNULL_ALL +{ + if (*op != '+' || tv2->v_type != VAR_LIST) { + return FAIL; + } + + // List += List + if (tv2->vval.v_list == NULL) { + return OK; + } + + if (tv1->vval.v_list == NULL) { + tv1->vval.v_list = tv2->vval.v_list; + tv_list_ref(tv1->vval.v_list); + } else { + tv_list_extend(tv1->vval.v_list, tv2->vval.v_list, NULL); + } + + return OK; +} + +/// Handle number operations: +/// nr += nr , nr -= nr , nr *=nr , nr /= nr , nr %= nr +/// +/// Returns OK or FAIL. +static int tv_op_number(typval_T *tv1, const typval_T *tv2, const char *op) + FUNC_ATTR_NONNULL_ALL +{ + varnumber_T n = tv_get_number(tv1); + if (tv2->v_type == VAR_FLOAT) { + float_T f = (float_T)n; + if (*op == '%') { + return FAIL; + } + switch (*op) { + case '+': + f += tv2->vval.v_float; break; + case '-': + f -= tv2->vval.v_float; break; + case '*': + f *= tv2->vval.v_float; break; + case '/': + f /= tv2->vval.v_float; break; + } + tv_clear(tv1); + tv1->v_type = VAR_FLOAT; + tv1->vval.v_float = f; + } else { + switch (*op) { + case '+': + n += tv_get_number(tv2); break; + case '-': + n -= tv_get_number(tv2); break; + case '*': + n *= tv_get_number(tv2); break; + case '/': + n = num_divide(n, tv_get_number(tv2)); break; + case '%': + n = num_modulus(n, tv_get_number(tv2)); break; + } + tv_clear(tv1); + tv1->v_type = VAR_NUMBER; + tv1->vval.v_number = n; + } + + return OK; +} + +/// Handle "str1 .= str2" +/// Returns OK or FAIL. +static int tv_op_string(typval_T *tv1, const typval_T *tv2, const char *op) + FUNC_ATTR_NONNULL_ALL +{ + if (tv2->v_type == VAR_FLOAT) { + return FAIL; + } + + // str .= str + const char *tvs = tv_get_string(tv1); + char numbuf[NUMBUFLEN]; + char *const s = concat_str(tvs, tv_get_string_buf(tv2, numbuf)); + tv_clear(tv1); + tv1->v_type = VAR_STRING; + tv1->vval.v_string = s; + + return OK; +} + +/// Handle "tv1 += tv2", "tv1 -= tv2", "tv1 *= tv2", "tv1 /= tv2", "tv1 %= tv2" +/// and "tv1 .= tv2" +/// Returns OK or FAIL. +static int tv_op_nr_or_string(typval_T *tv1, const typval_T *tv2, const char *op) + FUNC_ATTR_NONNULL_ALL +{ + if (tv2->v_type == VAR_LIST) { + return FAIL; + } + + if (vim_strchr("+-*/%", (uint8_t)(*op)) != NULL) { + return tv_op_number(tv1, tv2, op); + } + + return tv_op_string(tv1, tv2, op); +} + +/// Handle "f1 += f2", "f1 -= f2", "f1 *= f2", "f1 /= f2". +/// Returns OK or FAIL. +static int tv_op_float(typval_T *tv1, const typval_T *tv2, const char *op) + FUNC_ATTR_NONNULL_ALL +{ + if (*op == '%' || *op == '.' + || (tv2->v_type != VAR_FLOAT + && tv2->v_type != VAR_NUMBER + && tv2->v_type != VAR_STRING)) { + return FAIL; + } + + const float_T f = (tv2->v_type == VAR_FLOAT + ? tv2->vval.v_float + : (float_T)tv_get_number(tv2)); + switch (*op) { + case '+': + tv1->vval.v_float += f; break; + case '-': + tv1->vval.v_float -= f; break; + case '*': + tv1->vval.v_float *= f; break; + case '/': + tv1->vval.v_float /= f; break; + } + + return OK; +} + /// Handle tv1 += tv2, -=, *=, /=, %=, .= /// /// @param[in,out] tv1 First operand, modified typval. @@ -28,125 +197,45 @@ char *e_list_index_out_of_range_nr /// /// @return OK or FAIL. int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, const char *const op) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NO_SANITIZE_UNDEFINED + FUNC_ATTR_NONNULL_ALL { - // Can't do anything with a Funcref, a Dict or special value on the right. - if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT - && tv2->v_type != VAR_BOOL && tv2->v_type != VAR_SPECIAL) { - switch (tv1->v_type) { - case VAR_DICT: - case VAR_FUNC: - case VAR_PARTIAL: - case VAR_BOOL: - case VAR_SPECIAL: - break; - case VAR_BLOB: - if (*op != '+' || tv2->v_type != VAR_BLOB) { - break; - } - // Blob += Blob - if (tv1->vval.v_blob != NULL && tv2->vval.v_blob != NULL) { - blob_T *const b1 = tv1->vval.v_blob; - blob_T *const b2 = tv2->vval.v_blob; - for (int i = 0; i < tv_blob_len(b2); i++) { - ga_append(&b1->bv_ga, tv_blob_get(b2, i)); - } - } - return OK; - case VAR_LIST: - if (*op != '+' || tv2->v_type != VAR_LIST) { - break; - } - // List += List - if (tv1->vval.v_list != NULL && tv2->vval.v_list != NULL) { - tv_list_extend(tv1->vval.v_list, tv2->vval.v_list, NULL); - } - return OK; - case VAR_NUMBER: - case VAR_STRING: - if (tv2->v_type == VAR_LIST) { - break; - } - if (vim_strchr("+-*/%", (uint8_t)(*op)) != NULL) { - // nr += nr or nr -= nr, nr *= nr, nr /= nr, nr %= nr - varnumber_T n = tv_get_number(tv1); - if (tv2->v_type == VAR_FLOAT) { - float_T f = (float_T)n; - - if (*op == '%') { - break; - } - switch (*op) { - case '+': - f += tv2->vval.v_float; break; - case '-': - f -= tv2->vval.v_float; break; - case '*': - f *= tv2->vval.v_float; break; - case '/': - f /= tv2->vval.v_float; break; - } - tv_clear(tv1); - tv1->v_type = VAR_FLOAT; - tv1->vval.v_float = f; - } else { - switch (*op) { - case '+': - n += tv_get_number(tv2); break; - case '-': - n -= tv_get_number(tv2); break; - case '*': - n *= tv_get_number(tv2); break; - case '/': - n = num_divide(n, tv_get_number(tv2)); break; - case '%': - n = num_modulus(n, tv_get_number(tv2)); break; - } - tv_clear(tv1); - tv1->v_type = VAR_NUMBER; - tv1->vval.v_number = n; - } - } else { - // str .= str - if (tv2->v_type == VAR_FLOAT) { - break; - } - const char *tvs = tv_get_string(tv1); - char numbuf[NUMBUFLEN]; - char *const s = - concat_str(tvs, tv_get_string_buf(tv2, numbuf)); - tv_clear(tv1); - tv1->v_type = VAR_STRING; - tv1->vval.v_string = s; - } - return OK; - case VAR_FLOAT: { - if (*op == '%' || *op == '.' - || (tv2->v_type != VAR_FLOAT - && tv2->v_type != VAR_NUMBER - && tv2->v_type != VAR_STRING)) { - break; - } - const float_T f = (tv2->v_type == VAR_FLOAT - ? tv2->vval.v_float - : (float_T)tv_get_number(tv2)); - switch (*op) { - case '+': - tv1->vval.v_float += f; break; - case '-': - tv1->vval.v_float -= f; break; - case '*': - tv1->vval.v_float *= f; break; - case '/': - tv1->vval.v_float /= f; break; - } - return OK; - } - case VAR_UNKNOWN: - abort(); - } + // Can't do anything with a Funcref or Dict on the right. + // v:true and friends only work with "..=". + if (tv2->v_type == VAR_FUNC || tv2->v_type == VAR_DICT + || ((tv2->v_type == VAR_BOOL || tv2->v_type == VAR_SPECIAL) && *op == '.')) { + semsg(_(e_letwrong), op); + return FAIL; + } + + int retval = FAIL; + + switch (tv1->v_type) { + case VAR_DICT: + case VAR_FUNC: + case VAR_PARTIAL: + case VAR_BOOL: + case VAR_SPECIAL: + break; + case VAR_BLOB: + retval = tv_op_blob(tv1, tv2, op); + break; + case VAR_LIST: + retval = tv_op_list(tv1, tv2, op); + break; + case VAR_NUMBER: + case VAR_STRING: + retval = tv_op_nr_or_string(tv1, tv2, op); + break; + case VAR_FLOAT: + retval = tv_op_float(tv1, tv2, op); + break; + case VAR_UNKNOWN: + abort(); + } + + if (retval != OK) { + semsg(_(e_letwrong), op); } - semsg(_(e_letwrong), op); - return FAIL; + return retval; } diff --git a/src/nvim/eval/fs.c b/src/nvim/eval/fs.c new file mode 100644 index 0000000000..f5b33c804e --- /dev/null +++ b/src/nvim/eval/fs.c @@ -0,0 +1,1492 @@ +// eval/fs.c: Filesystem related builtin functions + +#include <assert.h> +#include <limits.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> + +#include "auto/config.h" +#include "nvim/ascii_defs.h" +#include "nvim/buffer_defs.h" +#include "nvim/cmdexpand.h" +#include "nvim/cmdexpand_defs.h" +#include "nvim/errors.h" +#include "nvim/eval.h" +#include "nvim/eval/fs.h" +#include "nvim/eval/typval.h" +#include "nvim/eval/userfunc.h" +#include "nvim/eval/window.h" +#include "nvim/ex_cmds.h" +#include "nvim/ex_docmd.h" +#include "nvim/file_search.h" +#include "nvim/fileio.h" +#include "nvim/garray.h" +#include "nvim/garray_defs.h" +#include "nvim/gettext_defs.h" +#include "nvim/globals.h" +#include "nvim/macros_defs.h" +#include "nvim/memory.h" +#include "nvim/message.h" +#include "nvim/option_vars.h" +#include "nvim/os/fileio.h" +#include "nvim/os/fileio_defs.h" +#include "nvim/os/fs.h" +#include "nvim/os/fs_defs.h" +#include "nvim/os/os_defs.h" +#include "nvim/path.h" +#include "nvim/pos_defs.h" +#include "nvim/strings.h" +#include "nvim/types_defs.h" +#include "nvim/vim_defs.h" +#include "nvim/window.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "eval/fs.c.generated.h" +#endif + +static const char e_error_while_writing_str[] = N_("E80: Error while writing: %s"); + +/// "chdir(dir)" function +void f_chdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + + if (argvars[0].v_type != VAR_STRING) { + // Returning an empty string means it failed. + // No error message, for historic reasons. + return; + } + + // Return the current directory + char *cwd = xmalloc(MAXPATHL); + if (os_dirname(cwd, MAXPATHL) != FAIL) { +#ifdef BACKSLASH_IN_FILENAME + slash_adjust(cwd); +#endif + rettv->vval.v_string = xstrdup(cwd); + } + xfree(cwd); + + CdScope scope = kCdScopeGlobal; + if (curwin->w_localdir != NULL) { + scope = kCdScopeWindow; + } else if (curtab->tp_localdir != NULL) { + scope = kCdScopeTabpage; + } + + if (!changedir_func(argvars[0].vval.v_string, scope)) { + // Directory change failed + XFREE_CLEAR(rettv->vval.v_string); + } +} + +/// "delete()" function +void f_delete(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + rettv->vval.v_number = -1; + if (check_secure()) { + return; + } + + const char *const name = tv_get_string(&argvars[0]); + if (*name == NUL) { + emsg(_(e_invarg)); + return; + } + + char nbuf[NUMBUFLEN]; + const char *flags; + if (argvars[1].v_type != VAR_UNKNOWN) { + flags = tv_get_string_buf(&argvars[1], nbuf); + } else { + flags = ""; + } + + if (*flags == NUL) { + // delete a file + rettv->vval.v_number = os_remove(name) == 0 ? 0 : -1; + } else if (strcmp(flags, "d") == 0) { + // delete an empty directory + rettv->vval.v_number = os_rmdir(name) == 0 ? 0 : -1; + } else if (strcmp(flags, "rf") == 0) { + // delete a directory recursively + rettv->vval.v_number = delete_recursive(name); + } else { + semsg(_(e_invexpr2), flags); + } +} + +/// "executable()" function +void f_executable(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + if (tv_check_for_string_arg(argvars, 0) == FAIL) { + return; + } + + // Check in $PATH and also check directly if there is a directory name + rettv->vval.v_number = os_can_exe(tv_get_string(&argvars[0]), NULL, true); +} + +/// "exepath()" function +void f_exepath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + if (tv_check_for_nonempty_string_arg(argvars, 0) == FAIL) { + return; + } + + char *path = NULL; + + os_can_exe(tv_get_string(&argvars[0]), &path, true); + +#ifdef BACKSLASH_IN_FILENAME + if (path != NULL) { + slash_adjust(path); + } +#endif + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = path; +} + +/// "filecopy()" function +void f_filecopy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + rettv->vval.v_number = false; + + if (check_secure() + || tv_check_for_string_arg(argvars, 0) == FAIL + || tv_check_for_string_arg(argvars, 1) == FAIL) { + return; + } + + const char *from = tv_get_string(&argvars[0]); + + FileInfo from_info; + if (os_fileinfo_link(from, &from_info) + && (S_ISREG(from_info.stat.st_mode) || S_ISLNK(from_info.stat.st_mode))) { + rettv->vval.v_number + = vim_copyfile(tv_get_string(&argvars[0]), tv_get_string(&argvars[1])) == OK; + } +} + +/// "filereadable()" function +void f_filereadable(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + const char *const p = tv_get_string(&argvars[0]); + rettv->vval.v_number = (*p && !os_isdir(p) && os_file_is_readable(p)); +} + +/// @return 0 for not writable +/// 1 for writable file +/// 2 for a dir which we have rights to write into. +void f_filewritable(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + const char *filename = tv_get_string(&argvars[0]); + rettv->vval.v_number = os_file_is_writable(filename); +} + +static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what) +{ + char *fresult = NULL; + char *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; + int count = 1; + bool first = true; + bool error = false; + + rettv->vval.v_string = NULL; + rettv->v_type = VAR_STRING; + + const char *fname = tv_get_string(&argvars[0]); + + char pathbuf[NUMBUFLEN]; + if (argvars[1].v_type != VAR_UNKNOWN) { + const char *p = tv_get_string_buf_chk(&argvars[1], pathbuf); + if (p == NULL) { + error = true; + } else { + if (*p != NUL) { + path = (char *)p; + } + + if (argvars[2].v_type != VAR_UNKNOWN) { + count = (int)tv_get_number_chk(&argvars[2], &error); + } + } + } + + if (count < 0) { + tv_list_alloc_ret(rettv, kListLenUnknown); + } + + if (*fname != NUL && !error) { + char *file_to_find = NULL; + char *search_ctx = NULL; + + do { + if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST) { + xfree(fresult); + } + fresult = find_file_in_path_option(first ? (char *)fname : NULL, + first ? strlen(fname) : 0, + 0, first, path, + find_what, curbuf->b_ffname, + (find_what == FINDFILE_DIR + ? "" + : curbuf->b_p_sua), + &file_to_find, &search_ctx); + first = false; + + if (fresult != NULL && rettv->v_type == VAR_LIST) { + tv_list_append_string(rettv->vval.v_list, fresult, -1); + } + } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL); + + xfree(file_to_find); + vim_findfile_cleanup(search_ctx); + } + + if (rettv->v_type == VAR_STRING) { + rettv->vval.v_string = fresult; + } +} + +/// "finddir({fname}[, {path}[, {count}]])" function +void f_finddir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + findfilendir(argvars, rettv, FINDFILE_DIR); +} + +/// "findfile({fname}[, {path}[, {count}]])" function +void f_findfile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + findfilendir(argvars, rettv, FINDFILE_FILE); +} + +/// `getcwd([{win}[, {tab}]])` function +/// +/// Every scope not specified implies the currently selected scope object. +/// +/// @pre The arguments must be of type number. +/// @pre There may not be more than two arguments. +/// @pre An argument may not be -1 if preceding arguments are not all -1. +/// +/// @post The return value will be a string. +void f_getcwd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + // Possible scope of working directory to return. + CdScope scope = kCdScopeInvalid; + + // Numbers of the scope objects (window, tab) we want the working directory + // of. A `-1` means to skip this scope, a `0` means the current object. + int scope_number[] = { + [kCdScopeWindow] = 0, // Number of window to look at. + [kCdScopeTabpage] = 0, // Number of tab to look at. + }; + + char *cwd = NULL; // Current working directory to print + char *from = NULL; // The original string to copy + + tabpage_T *tp = curtab; // The tabpage to look at. + win_T *win = curwin; // The window to look at. + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + + // Pre-conditions and scope extraction together + for (int i = MIN_CD_SCOPE; i < MAX_CD_SCOPE; i++) { + // If there is no argument there are no more scopes after it, break out. + if (argvars[i].v_type == VAR_UNKNOWN) { + break; + } + if (argvars[i].v_type != VAR_NUMBER) { + emsg(_(e_invarg)); + return; + } + scope_number[i] = (int)argvars[i].vval.v_number; + // It is an error for the scope number to be less than `-1`. + if (scope_number[i] < -1) { + emsg(_(e_invarg)); + return; + } + // Use the narrowest scope the user requested + if (scope_number[i] >= 0 && scope == kCdScopeInvalid) { + // The scope is the current iteration step. + scope = i; + } else if (scope_number[i] < 0) { + scope = i + 1; + } + } + + // Find the tabpage by number + if (scope_number[kCdScopeTabpage] > 0) { + tp = find_tabpage(scope_number[kCdScopeTabpage]); + if (!tp) { + emsg(_("E5000: Cannot find tab number.")); + return; + } + } + + // Find the window in `tp` by number, `NULL` if none. + if (scope_number[kCdScopeWindow] >= 0) { + if (scope_number[kCdScopeTabpage] < 0) { + emsg(_("E5001: Higher scope cannot be -1 if lower scope is >= 0.")); + return; + } + + if (scope_number[kCdScopeWindow] > 0) { + win = find_win_by_nr(&argvars[0], tp); + if (!win) { + emsg(_("E5002: Cannot find window number.")); + return; + } + } + } + + cwd = xmalloc(MAXPATHL); + + switch (scope) { + case kCdScopeWindow: + assert(win); + from = win->w_localdir; + if (from) { + break; + } + FALLTHROUGH; + case kCdScopeTabpage: + assert(tp); + from = tp->tp_localdir; + if (from) { + break; + } + FALLTHROUGH; + case kCdScopeGlobal: + if (globaldir) { // `globaldir` is not always set. + from = globaldir; + break; + } + FALLTHROUGH; // In global directory, just need to get OS CWD. + case kCdScopeInvalid: // If called without any arguments, get OS CWD. + if (os_dirname(cwd, MAXPATHL) == FAIL) { + from = ""; // Return empty string on failure. + } + } + + if (from) { + xstrlcpy(cwd, from, MAXPATHL); + } + + rettv->vval.v_string = xstrdup(cwd); +#ifdef BACKSLASH_IN_FILENAME + slash_adjust(rettv->vval.v_string); +#endif + + xfree(cwd); +} + +/// "getfperm({fname})" function +void f_getfperm(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + char *perm = NULL; + char flags[] = "rwx"; + + const char *filename = tv_get_string(&argvars[0]); + int32_t file_perm = os_getperm(filename); + if (file_perm >= 0) { + perm = xstrdup("---------"); + for (int i = 0; i < 9; i++) { + if (file_perm & (1 << (8 - i))) { + perm[i] = flags[i % 3]; + } + } + } + rettv->v_type = VAR_STRING; + rettv->vval.v_string = perm; +} + +/// "getfsize({fname})" function +void f_getfsize(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + const char *fname = tv_get_string(&argvars[0]); + + rettv->v_type = VAR_NUMBER; + + FileInfo file_info; + if (os_fileinfo(fname, &file_info)) { + uint64_t filesize = os_fileinfo_size(&file_info); + if (os_isdir(fname)) { + rettv->vval.v_number = 0; + } else { + rettv->vval.v_number = (varnumber_T)filesize; + + // non-perfect check for overflow + if ((uint64_t)rettv->vval.v_number != filesize) { + rettv->vval.v_number = -2; + } + } + } else { + rettv->vval.v_number = -1; + } +} + +/// "getftime({fname})" function +void f_getftime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + const char *fname = tv_get_string(&argvars[0]); + + FileInfo file_info; + if (os_fileinfo(fname, &file_info)) { + rettv->vval.v_number = (varnumber_T)file_info.stat.st_mtim.tv_sec; + } else { + rettv->vval.v_number = -1; + } +} + +/// "getftype({fname})" function +void f_getftype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + char *type = NULL; + char *t; + + const char *fname = tv_get_string(&argvars[0]); + + rettv->v_type = VAR_STRING; + FileInfo file_info; + if (os_fileinfo_link(fname, &file_info)) { + uint64_t mode = file_info.stat.st_mode; + if (S_ISREG(mode)) { + t = "file"; + } else if (S_ISDIR(mode)) { + t = "dir"; + } else if (S_ISLNK(mode)) { + t = "link"; + } else if (S_ISBLK(mode)) { + t = "bdev"; + } else if (S_ISCHR(mode)) { + t = "cdev"; + } else if (S_ISFIFO(mode)) { + t = "fifo"; + } else if (S_ISSOCK(mode)) { + t = "socket"; + } else { + t = "other"; + } + type = xstrdup(t); + } + rettv->vval.v_string = type; +} + +/// "glob()" function +void f_glob(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + int options = WILD_SILENT|WILD_USE_NL; + expand_T xpc; + bool error = false; + + // When the optional second argument is non-zero, don't remove matches + // for 'wildignore' and don't put matches for 'suffixes' at the end. + rettv->v_type = VAR_STRING; + if (argvars[1].v_type != VAR_UNKNOWN) { + if (tv_get_number_chk(&argvars[1], &error)) { + options |= WILD_KEEP_ALL; + } + if (argvars[2].v_type != VAR_UNKNOWN) { + if (tv_get_number_chk(&argvars[2], &error)) { + tv_list_set_ret(rettv, NULL); + } + if (argvars[3].v_type != VAR_UNKNOWN + && tv_get_number_chk(&argvars[3], &error)) { + options |= WILD_ALLLINKS; + } + } + } + if (!error) { + ExpandInit(&xpc); + xpc.xp_context = EXPAND_FILES; + if (p_wic) { + options += WILD_ICASE; + } + if (rettv->v_type == VAR_STRING) { + rettv->vval.v_string = ExpandOne(&xpc, (char *) + tv_get_string(&argvars[0]), NULL, options, + WILD_ALL); + } else { + ExpandOne(&xpc, (char *)tv_get_string(&argvars[0]), NULL, options, + WILD_ALL_KEEP); + tv_list_alloc_ret(rettv, xpc.xp_numfiles); + for (int i = 0; i < xpc.xp_numfiles; i++) { + tv_list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); + } + ExpandCleanup(&xpc); + } + } else { + rettv->vval.v_string = NULL; + } +} + +/// "globpath()" function +void f_globpath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + int flags = WILD_IGNORE_COMPLETESLASH; // Flags for globpath. + bool error = false; + + // Return a string, or a list if the optional third argument is non-zero. + rettv->v_type = VAR_STRING; + + if (argvars[2].v_type != VAR_UNKNOWN) { + // When the optional second argument is non-zero, don't remove matches + // for 'wildignore' and don't put matches for 'suffixes' at the end. + if (tv_get_number_chk(&argvars[2], &error)) { + flags |= WILD_KEEP_ALL; + } + + if (argvars[3].v_type != VAR_UNKNOWN) { + if (tv_get_number_chk(&argvars[3], &error)) { + tv_list_set_ret(rettv, NULL); + } + if (argvars[4].v_type != VAR_UNKNOWN + && tv_get_number_chk(&argvars[4], &error)) { + flags |= WILD_ALLLINKS; + } + } + } + + char buf1[NUMBUFLEN]; + const char *const file = tv_get_string_buf_chk(&argvars[1], buf1); + if (file != NULL && !error) { + garray_T ga; + ga_init(&ga, (int)sizeof(char *), 10); + globpath((char *)tv_get_string(&argvars[0]), (char *)file, &ga, flags, false); + + if (rettv->v_type == VAR_STRING) { + rettv->vval.v_string = ga_concat_strings_sep(&ga, "\n"); + } else { + tv_list_alloc_ret(rettv, ga.ga_len); + for (int i = 0; i < ga.ga_len; i++) { + tv_list_append_string(rettv->vval.v_list, + ((const char **)(ga.ga_data))[i], -1); + } + } + + ga_clear_strings(&ga); + } else { + rettv->vval.v_string = NULL; + } +} + +/// "glob2regpat()" function +void f_glob2regpat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + const char *const pat = tv_get_string_chk(&argvars[0]); // NULL on type error + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = pat == NULL ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, false); +} + +/// `haslocaldir([{win}[, {tab}]])` function +/// +/// Returns `1` if the scope object has a local directory, `0` otherwise. If a +/// scope object is not specified the current one is implied. This function +/// share a lot of code with `f_getcwd`. +/// +/// @pre The arguments must be of type number. +/// @pre There may not be more than two arguments. +/// @pre An argument may not be -1 if preceding arguments are not all -1. +/// +/// @post The return value will be either the number `1` or `0`. +void f_haslocaldir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + // Possible scope of working directory to return. + CdScope scope = kCdScopeInvalid; + + // Numbers of the scope objects (window, tab) we want the working directory + // of. A `-1` means to skip this scope, a `0` means the current object. + int scope_number[] = { + [kCdScopeWindow] = 0, // Number of window to look at. + [kCdScopeTabpage] = 0, // Number of tab to look at. + }; + + tabpage_T *tp = curtab; // The tabpage to look at. + win_T *win = curwin; // The window to look at. + + rettv->v_type = VAR_NUMBER; + rettv->vval.v_number = 0; + + // Pre-conditions and scope extraction together + for (int i = MIN_CD_SCOPE; i < MAX_CD_SCOPE; i++) { + if (argvars[i].v_type == VAR_UNKNOWN) { + break; + } + if (argvars[i].v_type != VAR_NUMBER) { + emsg(_(e_invarg)); + return; + } + scope_number[i] = (int)argvars[i].vval.v_number; + if (scope_number[i] < -1) { + emsg(_(e_invarg)); + return; + } + // Use the narrowest scope the user requested + if (scope_number[i] >= 0 && scope == kCdScopeInvalid) { + // The scope is the current iteration step. + scope = i; + } else if (scope_number[i] < 0) { + scope = i + 1; + } + } + + // If the user didn't specify anything, default to window scope + if (scope == kCdScopeInvalid) { + scope = MIN_CD_SCOPE; + } + + // Find the tabpage by number + if (scope_number[kCdScopeTabpage] > 0) { + tp = find_tabpage(scope_number[kCdScopeTabpage]); + if (!tp) { + emsg(_("E5000: Cannot find tab number.")); + return; + } + } + + // Find the window in `tp` by number, `NULL` if none. + if (scope_number[kCdScopeWindow] >= 0) { + if (scope_number[kCdScopeTabpage] < 0) { + emsg(_("E5001: Higher scope cannot be -1 if lower scope is >= 0.")); + return; + } + + if (scope_number[kCdScopeWindow] > 0) { + win = find_win_by_nr(&argvars[0], tp); + if (!win) { + emsg(_("E5002: Cannot find window number.")); + return; + } + } + } + + switch (scope) { + case kCdScopeWindow: + assert(win); + rettv->vval.v_number = win->w_localdir ? 1 : 0; + break; + case kCdScopeTabpage: + assert(tp); + rettv->vval.v_number = tp->tp_localdir ? 1 : 0; + break; + case kCdScopeGlobal: + // The global scope never has a local directory + break; + case kCdScopeInvalid: + // We should never get here + abort(); + } +} + +/// "isabsolutepath()" function +void f_isabsolutepath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + rettv->vval.v_number = path_is_absolute(tv_get_string(&argvars[0])); +} + +/// "isdirectory()" function +void f_isdirectory(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + rettv->vval.v_number = os_isdir(tv_get_string(&argvars[0])); +} + +/// "mkdir()" function +void f_mkdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + int prot = 0755; + + rettv->vval.v_number = FAIL; + if (check_secure()) { + return; + } + + char buf[NUMBUFLEN]; + const char *const dir = tv_get_string_buf(&argvars[0], buf); + if (*dir == NUL) { + return; + } + + if (*path_tail(dir) == NUL) { + // Remove trailing slashes. + *path_tail_with_sep((char *)dir) = NUL; + } + + bool defer = false; + bool defer_recurse = false; + char *created = NULL; + if (argvars[1].v_type != VAR_UNKNOWN) { + if (argvars[2].v_type != VAR_UNKNOWN) { + prot = (int)tv_get_number_chk(&argvars[2], NULL); + if (prot == -1) { + return; + } + } + const char *arg2 = tv_get_string(&argvars[1]); + defer = vim_strchr(arg2, 'D') != NULL; + defer_recurse = vim_strchr(arg2, 'R') != NULL; + if ((defer || defer_recurse) && !can_add_defer()) { + return; + } + + if (vim_strchr(arg2, 'p') != NULL) { + char *failed_dir; + int ret = os_mkdir_recurse(dir, prot, &failed_dir, + defer || defer_recurse ? &created : NULL); + if (ret != 0) { + semsg(_(e_mkdir), failed_dir, os_strerror(ret)); + xfree(failed_dir); + rettv->vval.v_number = FAIL; + return; + } + rettv->vval.v_number = OK; + } + } + if (rettv->vval.v_number == FAIL) { + rettv->vval.v_number = vim_mkdir_emsg(dir, prot); + } + + // Handle "D" and "R": deferred deletion of the created directory. + if (rettv->vval.v_number == OK + && created == NULL && (defer || defer_recurse)) { + created = FullName_save(dir, false); + } + if (created != NULL) { + typval_T tv[2]; + tv[0].v_type = VAR_STRING; + tv[0].v_lock = VAR_UNLOCKED; + tv[0].vval.v_string = created; + tv[1].v_type = VAR_STRING; + tv[1].v_lock = VAR_UNLOCKED; + tv[1].vval.v_string = xstrdup(defer_recurse ? "rf" : "d"); + add_defer("delete", 2, tv); + } +} + +/// "pathshorten()" function +void f_pathshorten(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + int trim_len = 1; + + if (argvars[1].v_type != VAR_UNKNOWN) { + trim_len = (int)tv_get_number(&argvars[1]); + if (trim_len < 1) { + trim_len = 1; + } + } + + rettv->v_type = VAR_STRING; + const char *p = tv_get_string_chk(&argvars[0]); + if (p == NULL) { + rettv->vval.v_string = NULL; + } else { + rettv->vval.v_string = xstrdup(p); + shorten_dir_len(rettv->vval.v_string, trim_len); + } +} + +/// Evaluate "expr" (= "context") for readdir(). +static varnumber_T readdir_checkitem(void *context, const char *name) + FUNC_ATTR_NONNULL_ALL +{ + typval_T *expr = (typval_T *)context; + typval_T argv[2]; + varnumber_T retval = 0; + bool error = false; + + if (expr->v_type == VAR_UNKNOWN) { + return 1; + } + + typval_T save_val; + prepare_vimvar(VV_VAL, &save_val); + set_vim_var_string(VV_VAL, name, -1); + argv[0].v_type = VAR_STRING; + argv[0].vval.v_string = (char *)name; + + typval_T rettv; + if (eval_expr_typval(expr, false, argv, 1, &rettv) == FAIL) { + goto theend; + } + + retval = tv_get_number_chk(&rettv, &error); + if (error) { + retval = -1; + } + + tv_clear(&rettv); + +theend: + set_vim_var_string(VV_VAL, NULL, 0); + restore_vimvar(VV_VAL, &save_val); + return retval; +} + +/// "readdir()" function +void f_readdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + tv_list_alloc_ret(rettv, kListLenUnknown); + + const char *path = tv_get_string(&argvars[0]); + typval_T *expr = &argvars[1]; + garray_T ga; + int ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem); + if (ret == OK && ga.ga_len > 0) { + for (int i = 0; i < ga.ga_len; i++) { + const char *p = ((const char **)ga.ga_data)[i]; + tv_list_append_string(rettv->vval.v_list, p, -1); + } + } + ga_clear_strings(&ga); +} + +/// Read blob from file "fd". +/// Caller has allocated a blob in "rettv". +/// +/// @param[in] fd File to read from. +/// @param[in,out] rettv Blob to write to. +/// @param[in] offset Read the file from the specified offset. +/// @param[in] size Read the specified size, or -1 if no limit. +/// +/// @return OK on success, or FAIL on failure. +static int read_blob(FILE *const fd, typval_T *rettv, off_T offset, off_T size_arg) + FUNC_ATTR_NONNULL_ALL +{ + blob_T *const blob = rettv->vval.v_blob; + FileInfo file_info; + if (!os_fileinfo_fd(fileno(fd), &file_info)) { + return FAIL; // can't read the file, error + } + + int whence; + off_T size = size_arg; + const off_T file_size = (off_T)os_fileinfo_size(&file_info); + if (offset >= 0) { + // The size defaults to the whole file. If a size is given it is + // limited to not go past the end of the file. + if (size == -1 || (size > file_size - offset && !S_ISCHR(file_info.stat.st_mode))) { + // size may become negative, checked below + size = (off_T)os_fileinfo_size(&file_info) - offset; + } + whence = SEEK_SET; + } else { + // limit the offset to not go before the start of the file + if (-offset > file_size && !S_ISCHR(file_info.stat.st_mode)) { + offset = -file_size; + } + // Size defaults to reading until the end of the file. + if (size == -1 || size > -offset) { + size = -offset; + } + whence = SEEK_END; + } + if (size <= 0) { + return OK; + } + if (offset != 0 && vim_fseek(fd, offset, whence) != 0) { + return OK; + } + + ga_grow(&blob->bv_ga, (int)size); + blob->bv_ga.ga_len = (int)size; + if (fread(blob->bv_ga.ga_data, 1, (size_t)blob->bv_ga.ga_len, fd) + < (size_t)blob->bv_ga.ga_len) { + // An empty blob is returned on error. + tv_blob_free(rettv->vval.v_blob); + rettv->vval.v_blob = NULL; + return FAIL; + } + return OK; +} + +/// "readfile()" or "readblob()" function +static void read_file_or_blob(typval_T *argvars, typval_T *rettv, bool always_blob) +{ + bool binary = false; + bool blob = always_blob; + FILE *fd; + char buf[(IOSIZE/256) * 256]; // rounded to avoid odd + 1 + int io_size = sizeof(buf); + 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 + int64_t maxline = MAXLNUM; + off_T offset = 0; + off_T size = -1; + + if (argvars[1].v_type != VAR_UNKNOWN) { + if (always_blob) { + offset = (off_T)tv_get_number(&argvars[1]); + if (argvars[2].v_type != VAR_UNKNOWN) { + size = (off_T)tv_get_number(&argvars[2]); + } + } else { + if (strcmp(tv_get_string(&argvars[1]), "b") == 0) { + binary = true; + } else if (strcmp(tv_get_string(&argvars[1]), "B") == 0) { + blob = true; + } + if (argvars[2].v_type != VAR_UNKNOWN) { + maxline = tv_get_number(&argvars[2]); + } + } + } + + if (blob) { + tv_blob_alloc_ret(rettv); + } else { + tv_list_alloc_ret(rettv, kListLenUnknown); + } + + // Always open the file in binary mode, library functions have a mind of + // their own about CR-LF conversion. + const char *const fname = tv_get_string(&argvars[0]); + + if (os_isdir(fname)) { + semsg(_(e_isadir2), fname); + return; + } + if (*fname == NUL || (fd = os_fopen(fname, READBIN)) == NULL) { + semsg(_(e_notopen), *fname == NUL ? _("<empty>") : fname); + return; + } + + if (blob) { + if (read_blob(fd, rettv, offset, size) == FAIL) { + semsg(_(e_notread), fname); + } + fclose(fd); + return; + } + + list_T *const l = rettv->vval.v_list; + + while (maxline < 0 || tv_list_len(l) < maxline) { + int readlen = (int)fread(buf, 1, (size_t)io_size, fd); + + // This for loop processes what was read, but is also entered at end + // of file so that either: + // - an incomplete line gets written + // - a "binary" file gets an empty line at the end if it ends in a + // newline. + char *p; // Position in buf. + char *start; // Start of current line. + for (p = buf, start = buf; + p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary)); + p++) { + if (readlen <= 0 || *p == '\n') { + char *s = NULL; + size_t len = (size_t)(p - start); + + // Finished a line. Remove CRs before NL. + if (readlen > 0 && !binary) { + while (len > 0 && start[len - 1] == '\r') { + len--; + } + // removal may cross back to the "prev" string + if (len == 0) { + while (prevlen > 0 && prev[prevlen - 1] == '\r') { + prevlen--; + } + } + } + if (prevlen == 0) { + assert(len < INT_MAX); + s = xmemdupz(start, len); + } else { + // Change "prev" buffer to be the right size. This way + // the bytes are only copied once, and very long lines are + // allocated only once. + s = xrealloc(prev, (size_t)prevlen + len + 1); + memcpy(s + prevlen, start, len); + s[(size_t)prevlen + len] = NUL; + prev = NULL; // the list will own the string + prevlen = prevsize = 0; + } + + tv_list_append_owned_tv(l, (typval_T) { + .v_type = VAR_STRING, + .v_lock = VAR_UNLOCKED, + .vval.v_string = s, + }); + + start = p + 1; // Step over newline. + if (maxline < 0) { + if (tv_list_len(l) > -maxline) { + assert(tv_list_len(l) == 1 + (-maxline)); + tv_list_item_remove(l, tv_list_first(l)); + } + } else if (tv_list_len(l) >= maxline) { + assert(tv_list_len(l) == maxline); + break; + } + if (readlen <= 0) { + break; + } + } else if (*p == NUL) { + *p = '\n'; + // Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this + // when finding the BF and check the previous two bytes. + } else if ((uint8_t)(*p) == 0xbf && !binary) { + // Find the two bytes before the 0xbf. If p is at buf, or buf + 1, + // these may be in the "prev" string. + char back1 = p >= buf + 1 ? p[-1] + : prevlen >= 1 ? prev[prevlen - 1] : NUL; + char back2 = p >= buf + 2 ? p[-2] + : (p == buf + 1 && prevlen >= 1 + ? prev[prevlen - 1] + : prevlen >= 2 ? prev[prevlen - 2] : NUL); + + if ((uint8_t)back2 == 0xef && (uint8_t)back1 == 0xbb) { + char *dest = p - 2; + + // Usually a BOM is at the beginning of a file, and so at + // the beginning of a line; then we can just step over it. + if (start == dest) { + start = p + 1; + } else { + // have to shuffle buf to close gap + int adjust_prevlen = 0; + + if (dest < buf) { + // adjust_prevlen must be 1 or 2. + adjust_prevlen = (int)(buf - dest); + dest = buf; + } + if (readlen > p - buf + 1) { + memmove(dest, p + 1, (size_t)readlen - (size_t)(p - buf) - 1); + } + readlen -= 3 - adjust_prevlen; + prevlen -= adjust_prevlen; + p = dest - 1; + } + } + } + } // for + + if ((maxline >= 0 && tv_list_len(l) >= maxline) || readlen <= 0) { + break; + } + if (start < p) { + // There's part of a line in buf, store it in "prev". + if (p - start + prevlen >= prevsize) { + // A common use case is ordinary text files and "prev" gets a + // fragment of a line, so the first allocation is made + // small, to avoid repeatedly 'allocing' large and + // 'reallocing' small. + if (prevsize == 0) { + prevsize = p - start; + } else { + ptrdiff_t grow50pc = (prevsize * 3) / 2; + ptrdiff_t growmin = (p - start) * 2 + prevlen; + prevsize = grow50pc > growmin ? grow50pc : growmin; + } + prev = xrealloc(prev, (size_t)prevsize); + } + // Add the line part to end of "prev". + memmove(prev + prevlen, start, (size_t)(p - start)); + prevlen += p - start; + } + } // while + + xfree(prev); + fclose(fd); +} + +/// "readblob()" function +void f_readblob(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + read_file_or_blob(argvars, rettv, true); +} + +/// "readfile()" function +void f_readfile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + read_file_or_blob(argvars, rettv, false); +} + +/// "rename({from}, {to})" function +void f_rename(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + if (check_secure()) { + rettv->vval.v_number = -1; + } else { + char buf[NUMBUFLEN]; + rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]), + tv_get_string_buf(&argvars[1], buf)); + } +} + +/// "resolve()" function +void f_resolve(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + rettv->v_type = VAR_STRING; + const char *fname = tv_get_string(&argvars[0]); +#ifdef MSWIN + char *v = os_resolve_shortcut(fname); + if (v == NULL) { + if (os_is_reparse_point_include(fname)) { + v = os_realpath(fname, NULL, MAXPATHL + 1); + } + } + rettv->vval.v_string = (v == NULL ? xstrdup(fname) : v); +#else +# ifdef HAVE_READLINK + { + bool is_relative_to_current = false; + bool has_trailing_pathsep = false; + int limit = 100; + + char *p = xstrdup(fname); + + if (p[0] == '.' && (vim_ispathsep(p[1]) + || (p[1] == '.' && (vim_ispathsep(p[2]))))) { + is_relative_to_current = true; + } + + ptrdiff_t len = (ptrdiff_t)strlen(p); + if (len > 1 && after_pathsep(p, p + len)) { + has_trailing_pathsep = true; + p[len - 1] = NUL; // The trailing slash breaks readlink(). + } + + char *q = (char *)path_next_component(p); + char *remain = NULL; + if (*q != NUL) { + // Separate the first path component in "p", and keep the + // remainder (beginning with the path separator). + remain = xstrdup(q - 1); + q[-1] = NUL; + } + + char *const buf = xmallocz(MAXPATHL); + + char *cpy; + while (true) { + while (true) { + len = readlink(p, buf, MAXPATHL); + if (len <= 0) { + break; + } + buf[len] = NUL; + + if (limit-- == 0) { + xfree(p); + xfree(remain); + emsg(_("E655: Too many symbolic links (cycle?)")); + rettv->vval.v_string = NULL; + xfree(buf); + return; + } + + // Ensure that the result will have a trailing path separator + // if the argument has one. + if (remain == NULL && has_trailing_pathsep) { + add_pathsep(buf); + } + + // Separate the first path component in the link value and + // concatenate the remainders. + q = (char *)path_next_component(vim_ispathsep(*buf) ? buf + 1 : buf); + if (*q != NUL) { + cpy = remain; + remain = remain != NULL ? concat_str(q - 1, remain) : xstrdup(q - 1); + xfree(cpy); + q[-1] = NUL; + } + + q = path_tail(p); + if (q > p && *q == NUL) { + // Ignore trailing path separator. + p[q - p - 1] = NUL; + q = path_tail(p); + } + if (q > p && !path_is_absolute(buf)) { + // Symlink is relative to directory of argument. Replace the + // symlink with the resolved name in the same directory. + const size_t p_len = strlen(p); + const size_t buf_len = strlen(buf); + p = xrealloc(p, p_len + buf_len + 1); + memcpy(path_tail(p), buf, buf_len + 1); + } else { + xfree(p); + p = xstrdup(buf); + } + } + + if (remain == NULL) { + break; + } + + // Append the first path component of "remain" to "p". + q = (char *)path_next_component(remain + 1); + len = q - remain - (*q != NUL); + const size_t p_len = strlen(p); + cpy = xmallocz(p_len + (size_t)len); + memcpy(cpy, p, p_len + 1); + xstrlcat(cpy + p_len, remain, (size_t)len + 1); + xfree(p); + p = cpy; + + // Shorten "remain". + if (*q != NUL) { + STRMOVE(remain, q - 1); + } else { + XFREE_CLEAR(remain); + } + } + + // If the result is a relative path name, make it explicitly relative to + // the current directory if and only if the argument had this form. + if (!vim_ispathsep(*p)) { + if (is_relative_to_current + && *p != NUL + && !(p[0] == '.' + && (p[1] == NUL + || vim_ispathsep(p[1]) + || (p[1] == '.' + && (p[2] == NUL + || vim_ispathsep(p[2])))))) { + // Prepend "./". + cpy = concat_str("./", p); + xfree(p); + p = cpy; + } else if (!is_relative_to_current) { + // Strip leading "./". + q = p; + while (q[0] == '.' && vim_ispathsep(q[1])) { + q += 2; + } + if (q > p) { + STRMOVE(p, p + 2); + } + } + } + + // Ensure that the result will have no trailing path separator + // if the argument had none. But keep "/" or "//". + if (!has_trailing_pathsep) { + q = p + strlen(p); + if (after_pathsep(p, q)) { + *path_tail_with_sep(p) = NUL; + } + } + + rettv->vval.v_string = p; + xfree(buf); + } +# else + char *v = os_realpath(fname, NULL, MAXPATHL + 1); + rettv->vval.v_string = v == NULL ? xstrdup(fname) : v; +# endif +#endif + + simplify_filename(rettv->vval.v_string); +} + +/// "simplify()" function +void f_simplify(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + const char *const p = tv_get_string(&argvars[0]); + rettv->vval.v_string = xstrdup(p); + simplify_filename(rettv->vval.v_string); // Simplify in place. + rettv->v_type = VAR_STRING; +} + +/// "tempname()" function +void f_tempname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + rettv->v_type = VAR_STRING; + rettv->vval.v_string = vim_tempname(); +} + +/// Write "list" of strings to file "fd". +/// +/// @param fp File to write to. +/// @param[in] list List to write. +/// @param[in] binary Whether to write in binary mode. +/// +/// @return true in case of success, false otherwise. +static bool write_list(FileDescriptor *const fp, const list_T *const list, const bool binary) + FUNC_ATTR_NONNULL_ARG(1) +{ + int error = 0; + TV_LIST_ITER_CONST(list, li, { + const char *const s = tv_get_string_chk(TV_LIST_ITEM_TV(li)); + if (s == NULL) { + return false; + } + const char *hunk_start = s; + for (const char *p = hunk_start;; p++) { + if (*p == NUL || *p == NL) { + if (p != hunk_start) { + const ptrdiff_t written = file_write(fp, hunk_start, + (size_t)(p - hunk_start)); + if (written < 0) { + error = (int)written; + goto write_list_error; + } + } + if (*p == NUL) { + break; + } else { + hunk_start = p + 1; + const ptrdiff_t written = file_write(fp, (char[]){ NUL }, 1); + if (written < 0) { + error = (int)written; + break; + } + } + } + } + if (!binary || TV_LIST_ITEM_NEXT(list, li) != NULL) { + const ptrdiff_t written = file_write(fp, "\n", 1); + if (written < 0) { + error = (int)written; + goto write_list_error; + } + } + }); + if ((error = file_flush(fp)) != 0) { + goto write_list_error; + } + return true; +write_list_error: + semsg(_(e_error_while_writing_str), os_strerror(error)); + return false; +} + +/// Write a blob to file with descriptor `fp`. +/// +/// @param[in] fp File to write to. +/// @param[in] blob Blob to write. +/// +/// @return true on success, or false on failure. +static bool write_blob(FileDescriptor *const fp, const blob_T *const blob) + FUNC_ATTR_NONNULL_ARG(1) +{ + int error = 0; + const int len = tv_blob_len(blob); + if (len > 0) { + const ptrdiff_t written = file_write(fp, blob->bv_ga.ga_data, (size_t)len); + if (written < (ptrdiff_t)len) { + error = (int)written; + goto write_blob_error; + } + } + error = file_flush(fp); + if (error != 0) { + goto write_blob_error; + } + return true; +write_blob_error: + semsg(_(e_error_while_writing_str), os_strerror(error)); + return false; +} + +/// "writefile()" function +void f_writefile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + rettv->vval.v_number = -1; + + if (check_secure()) { + return; + } + + if (argvars[0].v_type == VAR_LIST) { + TV_LIST_ITER_CONST(argvars[0].vval.v_list, li, { + if (!tv_check_str_or_nr(TV_LIST_ITEM_TV(li))) { + return; + } + }); + } else if (argvars[0].v_type != VAR_BLOB) { + semsg(_(e_invarg2), + _("writefile() first argument must be a List or a Blob")); + return; + } + + bool binary = false; + bool append = false; + bool defer = false; + bool do_fsync = !!p_fs; + bool mkdir_p = false; + if (argvars[2].v_type != VAR_UNKNOWN) { + const char *const flags = tv_get_string_chk(&argvars[2]); + if (flags == NULL) { + return; + } + for (const char *p = flags; *p; p++) { + switch (*p) { + case 'b': + binary = true; break; + case 'a': + append = true; break; + case 'D': + defer = true; break; + case 's': + do_fsync = true; break; + case 'S': + do_fsync = false; break; + case 'p': + mkdir_p = true; break; + default: + // Using %s, p and not %c, *p to preserve multibyte characters + semsg(_("E5060: Unknown flag: %s"), p); + return; + } + } + } + + char buf[NUMBUFLEN]; + const char *const fname = tv_get_string_buf_chk(&argvars[1], buf); + if (fname == NULL) { + return; + } + + if (defer && !can_add_defer()) { + return; + } + + FileDescriptor fp; + int error; + if (*fname == NUL) { + emsg(_("E482: Can't open file with an empty name")); + } else if ((error = file_open(&fp, fname, + ((append ? kFileAppend : kFileTruncate) + | (mkdir_p ? kFileMkDir : kFileCreate) + | kFileCreate), 0666)) != 0) { + semsg(_("E482: Can't open file %s for writing: %s"), fname, os_strerror(error)); + } else { + if (defer) { + typval_T tv = { + .v_type = VAR_STRING, + .v_lock = VAR_UNLOCKED, + .vval.v_string = FullName_save(fname, false), + }; + add_defer("delete", 1, &tv); + } + + bool write_ok; + if (argvars[0].v_type == VAR_BLOB) { + write_ok = write_blob(&fp, argvars[0].vval.v_blob); + } else { + write_ok = write_list(&fp, argvars[0].vval.v_list, binary); + } + if (write_ok) { + rettv->vval.v_number = 0; + } + if ((error = file_close(&fp, do_fsync)) != 0) { + semsg(_("E80: Error when closing file %s: %s"), + fname, os_strerror(error)); + } + } +} diff --git a/src/nvim/eval/fs.h b/src/nvim/eval/fs.h new file mode 100644 index 0000000000..ae6a93d0dc --- /dev/null +++ b/src/nvim/eval/fs.h @@ -0,0 +1,8 @@ +#pragma once + +#include "nvim/eval/typval_defs.h" // IWYU pragma: keep +#include "nvim/types_defs.h" // IWYU pragma: keep + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "eval/fs.h.generated.h" +#endif diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index e3afc1cf54..6d1cb4b2c3 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1,23 +1,19 @@ #include <assert.h> -#include <fcntl.h> #include <float.h> #include <inttypes.h> #include <limits.h> #include <math.h> -#include <msgpack/object.h> -#include <msgpack/pack.h> -#include <msgpack/unpack.h> #include <signal.h> #include <stdarg.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/stat.h> #include <time.h> #include <uv.h> #include "auto/config.h" +#include "mpack/object.h" #include "nvim/api/private/converter.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" @@ -38,6 +34,7 @@ #include "nvim/cursor.h" #include "nvim/diff.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/buffer.h" #include "nvim/eval/decode.h" @@ -52,15 +49,13 @@ #include "nvim/event/defs.h" #include "nvim/event/loop.h" #include "nvim/event/multiqueue.h" -#include "nvim/event/process.h" +#include "nvim/event/proc.h" #include "nvim/event/time.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" #include "nvim/ex_getln.h" -#include "nvim/file_search.h" -#include "nvim/fileio.h" #include "nvim/garray.h" #include "nvim/garray_defs.h" #include "nvim/getchar.h" @@ -93,6 +88,7 @@ #include "nvim/move.h" #include "nvim/msgpack_rpc/channel.h" #include "nvim/msgpack_rpc/channel_defs.h" +#include "nvim/msgpack_rpc/packer.h" #include "nvim/msgpack_rpc/server.h" #include "nvim/normal.h" #include "nvim/normal_defs.h" @@ -102,13 +98,10 @@ #include "nvim/option_vars.h" #include "nvim/optionstr.h" #include "nvim/os/dl.h" -#include "nvim/os/fileio.h" -#include "nvim/os/fileio_defs.h" #include "nvim/os/fs.h" -#include "nvim/os/fs_defs.h" #include "nvim/os/os.h" #include "nvim/os/os_defs.h" -#include "nvim/os/pty_process.h" +#include "nvim/os/pty_proc.h" #include "nvim/os/shell.h" #include "nvim/os/stdpaths_defs.h" #include "nvim/os/time.h" @@ -132,6 +125,7 @@ #include "nvim/tag.h" #include "nvim/types_defs.h" #include "nvim/ui.h" +#include "nvim/ui_compositor.h" #include "nvim/version.h" #include "nvim/vim_defs.h" #include "nvim/window.h" @@ -772,41 +766,6 @@ static void f_charcol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) get_col(argvars, rettv, true); } -/// "chdir(dir)" function -static void f_chdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - - if (argvars[0].v_type != VAR_STRING) { - // Returning an empty string means it failed. - // No error message, for historic reasons. - return; - } - - // Return the current directory - char *cwd = xmalloc(MAXPATHL); - if (os_dirname(cwd, MAXPATHL) != FAIL) { -#ifdef BACKSLASH_IN_FILENAME - slash_adjust(cwd); -#endif - rettv->vval.v_string = xstrdup(cwd); - } - xfree(cwd); - - CdScope scope = kCdScopeGlobal; - if (curwin->w_localdir != NULL) { - scope = kCdScopeWindow; - } else if (curtab->tp_localdir != NULL) { - scope = kCdScopeTabpage; - } - - if (!changedir_func(argvars[0].vval.v_string, scope)) { - // Directory change failed - XFREE_CLEAR(rettv->vval.v_string); - } -} - /// "cindent(lnum)" function static void f_cindent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -951,7 +910,7 @@ static varnumber_T count_list(list_T *l, typval_T *needle, int64_t idx, bool ic) varnumber_T n = 0; for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) { - if (tv_equal(TV_LIST_ITEM_TV(li), needle, ic, false)) { + if (tv_equal(TV_LIST_ITEM_TV(li), needle, ic)) { n++; } } @@ -971,7 +930,7 @@ static varnumber_T count_dict(dict_T *d, typval_T *needle, bool ic) varnumber_T n = 0; TV_DICT_ITER(d, di, { - if (tv_equal(&di->di_tv, needle, ic, false)) { + if (tv_equal(&di->di_tv, needle, ic)) { n++; } }); @@ -1036,9 +995,9 @@ static void f_ctxget(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } Arena arena = ARENA_EMPTY; - Dictionary ctx_dict = ctx_to_dict(ctx, &arena); + Dict ctx_dict = ctx_to_dict(ctx, &arena); Error err = ERROR_INIT; - object_to_vim(DICTIONARY_OBJ(ctx_dict), rettv, &err); + object_to_vim(DICT_OBJ(ctx_dict), rettv, &err); arena_mem_free(arena_finish(&arena)); api_clear_error(&err); } @@ -1108,7 +1067,7 @@ static void f_ctxset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) did_emsg = false; Arena arena = ARENA_EMPTY; - Dictionary dict = vim_to_object(&argvars[0], &arena, true).data.dictionary; + Dict dict = vim_to_object(&argvars[0], &arena, true).data.dict; Context tmp = CONTEXT_INIT; Error err = ERROR_INIT; ctx_from_dict(dict, &tmp, &err); @@ -1250,42 +1209,6 @@ static void f_deepcopy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) var_item_copy(NULL, &argvars[0], rettv, true, (noref == 0 ? get_copyID() : 0)); } -/// "delete()" function -static void f_delete(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - rettv->vval.v_number = -1; - if (check_secure()) { - return; - } - - const char *const name = tv_get_string(&argvars[0]); - if (*name == NUL) { - emsg(_(e_invarg)); - return; - } - - char nbuf[NUMBUFLEN]; - const char *flags; - if (argvars[1].v_type != VAR_UNKNOWN) { - flags = tv_get_string_buf(&argvars[1], nbuf); - } else { - flags = ""; - } - - if (*flags == NUL) { - // delete a file - rettv->vval.v_number = os_remove(name) == 0 ? 0 : -1; - } else if (strcmp(flags, "d") == 0) { - // delete an empty directory - rettv->vval.v_number = os_rmdir(name) == 0 ? 0 : -1; - } else if (strcmp(flags, "rf") == 0) { - // delete a directory recursively - rettv->vval.v_number = delete_recursive(name); - } else { - semsg(_(e_invexpr2), flags); - } -} - /// dictwatcheradd(dict, key, funcref) function static void f_dictwatcheradd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -1568,17 +1491,6 @@ static void f_eventhandler(typval_T *argvars, typval_T *rettv, EvalFuncData fptr rettv->vval.v_number = vgetc_busy; } -/// "executable()" function -static void f_executable(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - if (tv_check_for_string_arg(argvars, 0) == FAIL) { - return; - } - - // Check in $PATH and also check directly if there is a directory name - rettv->vval.v_number = os_can_exe(tv_get_string(&argvars[0]), NULL, true); -} - typedef struct { const list_T *const l; const listitem_T *li; @@ -1682,27 +1594,6 @@ static void f_execute(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) execute_common(argvars, rettv, 0); } -/// "exepath()" function -static void f_exepath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - if (tv_check_for_nonempty_string_arg(argvars, 0) == FAIL) { - return; - } - - char *path = NULL; - - os_can_exe(tv_get_string(&argvars[0]), &path, true); - -#ifdef BACKSLASH_IN_FILENAME - if (path != NULL) { - slash_adjust(path); - } -#endif - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = path; -} - /// "exists()" function static void f_exists(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -2104,100 +1995,6 @@ static void f_feedkeys(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) cstr_as_string(flags), true); } -/// "filereadable()" function -static void f_filereadable(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - const char *const p = tv_get_string(&argvars[0]); - rettv->vval.v_number = - (*p && !os_isdir(p) && os_file_is_readable(p)); -} - -/// @return 0 for not writable -/// 1 for writable file -/// 2 for a dir which we have rights to write into. -static void f_filewritable(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - const char *filename = tv_get_string(&argvars[0]); - rettv->vval.v_number = os_file_is_writable(filename); -} - -static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what) -{ - char *fresult = NULL; - char *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; - int count = 1; - bool first = true; - bool error = false; - - rettv->vval.v_string = NULL; - rettv->v_type = VAR_STRING; - - const char *fname = tv_get_string(&argvars[0]); - - char pathbuf[NUMBUFLEN]; - if (argvars[1].v_type != VAR_UNKNOWN) { - const char *p = tv_get_string_buf_chk(&argvars[1], pathbuf); - if (p == NULL) { - error = true; - } else { - if (*p != NUL) { - path = (char *)p; - } - - if (argvars[2].v_type != VAR_UNKNOWN) { - count = (int)tv_get_number_chk(&argvars[2], &error); - } - } - } - - if (count < 0) { - tv_list_alloc_ret(rettv, kListLenUnknown); - } - - if (*fname != NUL && !error) { - char *file_to_find = NULL; - char *search_ctx = NULL; - - do { - if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST) { - xfree(fresult); - } - fresult = find_file_in_path_option(first ? (char *)fname : NULL, - first ? strlen(fname) : 0, - 0, first, path, - find_what, curbuf->b_ffname, - (find_what == FINDFILE_DIR - ? "" - : curbuf->b_p_sua), - &file_to_find, &search_ctx); - first = false; - - if (fresult != NULL && rettv->v_type == VAR_LIST) { - tv_list_append_string(rettv->vval.v_list, fresult, -1); - } - } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL); - - xfree(file_to_find); - vim_findfile_cleanup(search_ctx); - } - - if (rettv->v_type == VAR_STRING) { - rettv->vval.v_string = fresult; - } -} - -/// "finddir({fname}[, {path}[, {count}]])" function -static void f_finddir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - findfilendir(argvars, rettv, FINDFILE_DIR); -} - -/// "findfile({fname}[, {path}[, {count}]])" function -static void f_findfile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - findfilendir(argvars, rettv, FINDFILE_FILE); -} - /// "float2nr({float})" function static void f_float2nr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -2270,6 +2067,164 @@ static void f_foreground(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { } +/// "function()" function +/// "funcref()" function +static void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref) +{ + char *s; + char *name; + bool use_string = false; + partial_T *arg_pt = NULL; + char *trans_name = NULL; + + if (argvars[0].v_type == VAR_FUNC) { + // function(MyFunc, [arg], dict) + s = argvars[0].vval.v_string; + } else if (argvars[0].v_type == VAR_PARTIAL + && argvars[0].vval.v_partial != NULL) { + // function(dict.MyFunc, [arg]) + arg_pt = argvars[0].vval.v_partial; + s = partial_name(arg_pt); + // TODO(bfredl): do the entire nlua_is_table_from_lua dance + } else { + // function('MyFunc', [arg], dict) + s = (char *)tv_get_string(&argvars[0]); + use_string = true; + } + + if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref) { + name = s; + trans_name = save_function_name(&name, false, + TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL); + if (*name != NUL) { + s = NULL; + } + } + if (s == NULL || *s == NUL || (use_string && ascii_isdigit(*s)) + || (is_funcref && trans_name == NULL)) { + semsg(_(e_invarg2), (use_string ? tv_get_string(&argvars[0]) : s)); + // Don't check an autoload name for existence here. + } else if (trans_name != NULL + && (is_funcref + ? find_func(trans_name) == NULL + : !translated_function_exists(trans_name))) { + semsg(_("E700: Unknown function: %s"), s); + } else { + int dict_idx = 0; + int arg_idx = 0; + list_T *list = NULL; + if (strncmp(s, "s:", 2) == 0 || strncmp(s, "<SID>", 5) == 0) { + // Expand s: and <SID> into <SNR>nr_, so that the function can + // also be called from another script. Using trans_function_name() + // would also work, but some plugins depend on the name being + // printable text. + name = get_scriptlocal_funcname(s); + } else { + name = xstrdup(s); + } + + if (argvars[1].v_type != VAR_UNKNOWN) { + if (argvars[2].v_type != VAR_UNKNOWN) { + // function(name, [args], dict) + arg_idx = 1; + dict_idx = 2; + } else if (argvars[1].v_type == VAR_DICT) { + // function(name, dict) + dict_idx = 1; + } else { + // function(name, [args]) + arg_idx = 1; + } + if (dict_idx > 0) { + if (tv_check_for_dict_arg(argvars, dict_idx) == FAIL) { + xfree(name); + goto theend; + } + if (argvars[dict_idx].vval.v_dict == NULL) { + dict_idx = 0; + } + } + if (arg_idx > 0) { + if (argvars[arg_idx].v_type != VAR_LIST) { + emsg(_("E923: Second argument of function() must be " + "a list or a dict")); + xfree(name); + goto theend; + } + list = argvars[arg_idx].vval.v_list; + if (tv_list_len(list) == 0) { + arg_idx = 0; + } else if (tv_list_len(list) > MAX_FUNC_ARGS) { + emsg_funcname(e_toomanyarg, s); + xfree(name); + goto theend; + } + } + } + if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref) { + partial_T *const pt = xcalloc(1, sizeof(*pt)); + + // result is a VAR_PARTIAL + if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0)) { + const int arg_len = (arg_pt == NULL ? 0 : arg_pt->pt_argc); + const int lv_len = tv_list_len(list); + + pt->pt_argc = arg_len + lv_len; + pt->pt_argv = xmalloc(sizeof(pt->pt_argv[0]) * (size_t)pt->pt_argc); + int i = 0; + for (; i < arg_len; i++) { + tv_copy(&arg_pt->pt_argv[i], &pt->pt_argv[i]); + } + if (lv_len > 0) { + TV_LIST_ITER(list, li, { + tv_copy(TV_LIST_ITEM_TV(li), &pt->pt_argv[i++]); + }); + } + } + + // For "function(dict.func, [], dict)" and "func" is a partial + // use "dict". That is backwards compatible. + if (dict_idx > 0) { + // The dict is bound explicitly, pt_auto is false + pt->pt_dict = argvars[dict_idx].vval.v_dict; + (pt->pt_dict->dv_refcount)++; + } else if (arg_pt != NULL) { + // If the dict was bound automatically the result is also + // bound automatically. + pt->pt_dict = arg_pt->pt_dict; + pt->pt_auto = arg_pt->pt_auto; + if (pt->pt_dict != NULL) { + (pt->pt_dict->dv_refcount)++; + } + } + + pt->pt_refcount = 1; + if (arg_pt != NULL && arg_pt->pt_func != NULL) { + pt->pt_func = arg_pt->pt_func; + func_ptr_ref(pt->pt_func); + xfree(name); + } else if (is_funcref) { + pt->pt_func = find_func(trans_name); + func_ptr_ref(pt->pt_func); + xfree(name); + } else { + pt->pt_name = name; + func_ref(name); + } + + rettv->v_type = VAR_PARTIAL; + rettv->vval.v_partial = pt; + } else { + // result is a VAR_FUNC + rettv->v_type = VAR_FUNC; + rettv->vval.v_string = name; + func_ref(name); + } + } +theend: + xfree(trans_name); +} + static void f_funcref(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { common_function(argvars, rettv, true); @@ -2370,6 +2325,33 @@ static void f_get(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) for (int i = 0; i < pt->pt_argc; i++) { tv_list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]); } + } else if (strcmp(what, "arity") == 0) { + int required = 0; + int optional = 0; + bool varargs = false; + const char *name = partial_name(pt); + + get_func_arity(name, &required, &optional, &varargs); + + rettv->v_type = VAR_DICT; + tv_dict_alloc_ret(rettv); + dict_T *dict = rettv->vval.v_dict; + + // Take into account the arguments of the partial, if any. + // Note that it is possible to supply more arguments than the function + // accepts. + if (pt->pt_argc >= required + optional) { + required = optional = 0; + } else if (pt->pt_argc > required) { + optional -= pt->pt_argc - required; + required = 0; + } else { + required -= pt->pt_argc; + } + + tv_dict_add_nr(dict, S_LEN("required"), required); + tv_dict_add_nr(dict, S_LEN("optional"), optional); + tv_dict_add_bool(dict, S_LEN("varargs"), varargs); } else { semsg(_(e_invarg2), what); } @@ -2516,127 +2498,6 @@ static void f_getcharsearch(typval_T *argvars, typval_T *rettv, EvalFuncData fpt tv_dict_add_nr(dict, S_LEN("until"), last_csearch_until()); } -/// `getcwd([{win}[, {tab}]])` function -/// -/// Every scope not specified implies the currently selected scope object. -/// -/// @pre The arguments must be of type number. -/// @pre There may not be more than two arguments. -/// @pre An argument may not be -1 if preceding arguments are not all -1. -/// -/// @post The return value will be a string. -static void f_getcwd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - // Possible scope of working directory to return. - CdScope scope = kCdScopeInvalid; - - // Numbers of the scope objects (window, tab) we want the working directory - // of. A `-1` means to skip this scope, a `0` means the current object. - int scope_number[] = { - [kCdScopeWindow] = 0, // Number of window to look at. - [kCdScopeTabpage] = 0, // Number of tab to look at. - }; - - char *cwd = NULL; // Current working directory to print - char *from = NULL; // The original string to copy - - tabpage_T *tp = curtab; // The tabpage to look at. - win_T *win = curwin; // The window to look at. - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - - // Pre-conditions and scope extraction together - for (int i = MIN_CD_SCOPE; i < MAX_CD_SCOPE; i++) { - // If there is no argument there are no more scopes after it, break out. - if (argvars[i].v_type == VAR_UNKNOWN) { - break; - } - if (argvars[i].v_type != VAR_NUMBER) { - emsg(_(e_invarg)); - return; - } - scope_number[i] = (int)argvars[i].vval.v_number; - // It is an error for the scope number to be less than `-1`. - if (scope_number[i] < -1) { - emsg(_(e_invarg)); - return; - } - // Use the narrowest scope the user requested - if (scope_number[i] >= 0 && scope == kCdScopeInvalid) { - // The scope is the current iteration step. - scope = i; - } else if (scope_number[i] < 0) { - scope = i + 1; - } - } - - // Find the tabpage by number - if (scope_number[kCdScopeTabpage] > 0) { - tp = find_tabpage(scope_number[kCdScopeTabpage]); - if (!tp) { - emsg(_("E5000: Cannot find tab number.")); - return; - } - } - - // Find the window in `tp` by number, `NULL` if none. - if (scope_number[kCdScopeWindow] >= 0) { - if (scope_number[kCdScopeTabpage] < 0) { - emsg(_("E5001: Higher scope cannot be -1 if lower scope is >= 0.")); - return; - } - - if (scope_number[kCdScopeWindow] > 0) { - win = find_win_by_nr(&argvars[0], tp); - if (!win) { - emsg(_("E5002: Cannot find window number.")); - return; - } - } - } - - cwd = xmalloc(MAXPATHL); - - switch (scope) { - case kCdScopeWindow: - assert(win); - from = win->w_localdir; - if (from) { - break; - } - FALLTHROUGH; - case kCdScopeTabpage: - assert(tp); - from = tp->tp_localdir; - if (from) { - break; - } - FALLTHROUGH; - case kCdScopeGlobal: - if (globaldir) { // `globaldir` is not always set. - from = globaldir; - break; - } - FALLTHROUGH; // In global directory, just need to get OS CWD. - case kCdScopeInvalid: // If called without any arguments, get OS CWD. - if (os_dirname(cwd, MAXPATHL) == FAIL) { - from = ""; // Return empty string on failure. - } - } - - if (from) { - xstrlcpy(cwd, from, MAXPATHL); - } - - rettv->vval.v_string = xstrdup(cwd); -#ifdef BACKSLASH_IN_FILENAME - slash_adjust(rettv->vval.v_string); -#endif - - xfree(cwd); -} - /// "getfontname()" function static void f_getfontname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -2644,98 +2505,6 @@ static void f_getfontname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) rettv->vval.v_string = NULL; } -/// "getfperm({fname})" function -static void f_getfperm(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - char *perm = NULL; - char flags[] = "rwx"; - - const char *filename = tv_get_string(&argvars[0]); - int32_t file_perm = os_getperm(filename); - if (file_perm >= 0) { - perm = xstrdup("---------"); - for (int i = 0; i < 9; i++) { - if (file_perm & (1 << (8 - i))) { - perm[i] = flags[i % 3]; - } - } - } - rettv->v_type = VAR_STRING; - rettv->vval.v_string = perm; -} - -/// "getfsize({fname})" function -static void f_getfsize(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - const char *fname = tv_get_string(&argvars[0]); - - rettv->v_type = VAR_NUMBER; - - FileInfo file_info; - if (os_fileinfo(fname, &file_info)) { - uint64_t filesize = os_fileinfo_size(&file_info); - if (os_isdir(fname)) { - rettv->vval.v_number = 0; - } else { - rettv->vval.v_number = (varnumber_T)filesize; - - // non-perfect check for overflow - if ((uint64_t)rettv->vval.v_number != filesize) { - rettv->vval.v_number = -2; - } - } - } else { - rettv->vval.v_number = -1; - } -} - -/// "getftime({fname})" function -static void f_getftime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - const char *fname = tv_get_string(&argvars[0]); - - FileInfo file_info; - if (os_fileinfo(fname, &file_info)) { - rettv->vval.v_number = (varnumber_T)file_info.stat.st_mtim.tv_sec; - } else { - rettv->vval.v_number = -1; - } -} - -/// "getftype({fname})" function -static void f_getftype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - char *type = NULL; - char *t; - - const char *fname = tv_get_string(&argvars[0]); - - rettv->v_type = VAR_STRING; - FileInfo file_info; - if (os_fileinfo_link(fname, &file_info)) { - uint64_t mode = file_info.stat.st_mode; - if (S_ISREG(mode)) { - t = "file"; - } else if (S_ISDIR(mode)) { - t = "dir"; - } else if (S_ISLNK(mode)) { - t = "link"; - } else if (S_ISBLK(mode)) { - t = "bdev"; - } else if (S_ISCHR(mode)) { - t = "cdev"; - } else if (S_ISFIFO(mode)) { - t = "fifo"; - } else if (S_ISSOCK(mode)) { - t = "socket"; - } else { - t = "other"; - } - type = xstrdup(t); - } - rettv->vval.v_string = type; -} - /// "getjumplist()" function static void f_getjumplist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -2824,7 +2593,7 @@ static char *block_def2str(struct block_def *bd) } static int getregionpos(typval_T *argvars, typval_T *rettv, pos_T *p1, pos_T *p2, - bool *const inclusive, MotionType *region_type, oparg_T *oa) + bool *const inclusive, MotionType *region_type, oparg_T *oap) FUNC_ATTR_NONNULL_ALL { tv_list_alloc_ret(rettv, kListLenMayKnow); @@ -2858,11 +2627,17 @@ static int getregionpos(typval_T *argvars, typval_T *rettv, pos_T *p1, pos_T *p2 type = default_type; } + int block_width = 0; if (type[0] == 'v' && type[1] == NUL) { *region_type = kMTCharWise; } else if (type[0] == 'V' && type[1] == NUL) { *region_type = kMTLineWise; - } else if (type[0] == Ctrl_V && type[1] == NUL) { + } else if (type[0] == Ctrl_V) { + char *p = type + 1; + if (*p != NUL && ((block_width = getdigits_int(&p, false, 0)) <= 0 || *p != NUL)) { + semsg(_(e_invargNval), "type", type); + return FAIL; + } *region_type = kMTBlockWise; } else { semsg(_(e_invargNval), "type", type); @@ -2926,16 +2701,18 @@ static int getregionpos(typval_T *argvars, typval_T *rettv, pos_T *p1, pos_T *p2 colnr_T sc1, ec1, sc2, ec2; getvvcol(curwin, p1, &sc1, NULL, &ec1); getvvcol(curwin, p2, &sc2, NULL, &ec2); - oa->motion_type = kMTBlockWise; - oa->inclusive = true; - oa->op_type = OP_NOP; - oa->start = *p1; - oa->end = *p2; - oa->start_vcol = MIN(sc1, sc2); - if (is_select_exclusive && ec1 < sc2 && 0 < sc2 && ec2 > ec1) { - oa->end_vcol = sc2 - 1; + oap->motion_type = kMTBlockWise; + oap->inclusive = true; + oap->op_type = OP_NOP; + oap->start = *p1; + oap->end = *p2; + oap->start_vcol = MIN(sc1, sc2); + if (block_width > 0) { + oap->end_vcol = oap->start_vcol + block_width - 1; + } else if (is_select_exclusive && ec1 < sc2 && 0 < sc2 && ec2 > ec1) { + oap->end_vcol = sc2 - 1; } else { - oa->end_vcol = MAX(ec1, ec2); + oap->end_vcol = MAX(ec1, ec2); } } @@ -3034,6 +2811,7 @@ static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr for (linenr_T lnum = p1.lnum; lnum <= p2.lnum; lnum++) { pos_T ret_p1, ret_p2; + char *line = ml_get(lnum); colnr_T line_len = ml_get_len(lnum); if (region_type == kMTLineWise) { @@ -3052,7 +2830,7 @@ static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr if (bd.is_oneChar) { // selection entirely inside one char if (region_type == kMTBlockWise) { - ret_p1.col = bd.textcol; + ret_p1.col = (colnr_T)(mb_prevptr(line, bd.textstart) - line) + 1; ret_p1.coladd = bd.start_char_vcols - (bd.start_vcol - oa.start_vcol); } else { ret_p1.col = p1.col + 1; @@ -3064,7 +2842,7 @@ static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr ret_p1.coladd = oa.start_vcol - bd.start_vcol; bd.is_oneChar = true; } else if (bd.startspaces > 0) { - ret_p1.col = bd.textcol; + ret_p1.col = (colnr_T)(mb_prevptr(line, bd.textstart) - line) + 1; ret_p1.coladd = bd.start_char_vcols - bd.startspaces; } else { ret_p1.col = bd.textcol + 1; @@ -3269,113 +3047,6 @@ static void f_wait(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) time_watcher_close(tw, dummy_timer_close_cb); } -/// "glob()" function -static void f_glob(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - int options = WILD_SILENT|WILD_USE_NL; - expand_T xpc; - bool error = false; - - // When the optional second argument is non-zero, don't remove matches - // for 'wildignore' and don't put matches for 'suffixes' at the end. - rettv->v_type = VAR_STRING; - if (argvars[1].v_type != VAR_UNKNOWN) { - if (tv_get_number_chk(&argvars[1], &error)) { - options |= WILD_KEEP_ALL; - } - if (argvars[2].v_type != VAR_UNKNOWN) { - if (tv_get_number_chk(&argvars[2], &error)) { - tv_list_set_ret(rettv, NULL); - } - if (argvars[3].v_type != VAR_UNKNOWN - && tv_get_number_chk(&argvars[3], &error)) { - options |= WILD_ALLLINKS; - } - } - } - if (!error) { - ExpandInit(&xpc); - xpc.xp_context = EXPAND_FILES; - if (p_wic) { - options += WILD_ICASE; - } - if (rettv->v_type == VAR_STRING) { - rettv->vval.v_string = ExpandOne(&xpc, (char *) - tv_get_string(&argvars[0]), NULL, options, - WILD_ALL); - } else { - ExpandOne(&xpc, (char *)tv_get_string(&argvars[0]), NULL, options, - WILD_ALL_KEEP); - tv_list_alloc_ret(rettv, xpc.xp_numfiles); - for (int i = 0; i < xpc.xp_numfiles; i++) { - tv_list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); - } - ExpandCleanup(&xpc); - } - } else { - rettv->vval.v_string = NULL; - } -} - -/// "globpath()" function -static void f_globpath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - int flags = WILD_IGNORE_COMPLETESLASH; // Flags for globpath. - bool error = false; - - // Return a string, or a list if the optional third argument is non-zero. - rettv->v_type = VAR_STRING; - - if (argvars[2].v_type != VAR_UNKNOWN) { - // When the optional second argument is non-zero, don't remove matches - // for 'wildignore' and don't put matches for 'suffixes' at the end. - if (tv_get_number_chk(&argvars[2], &error)) { - flags |= WILD_KEEP_ALL; - } - - if (argvars[3].v_type != VAR_UNKNOWN) { - if (tv_get_number_chk(&argvars[3], &error)) { - tv_list_set_ret(rettv, NULL); - } - if (argvars[4].v_type != VAR_UNKNOWN - && tv_get_number_chk(&argvars[4], &error)) { - flags |= WILD_ALLLINKS; - } - } - } - - char buf1[NUMBUFLEN]; - const char *const file = tv_get_string_buf_chk(&argvars[1], buf1); - if (file != NULL && !error) { - garray_T ga; - ga_init(&ga, (int)sizeof(char *), 10); - globpath((char *)tv_get_string(&argvars[0]), (char *)file, &ga, flags, false); - - if (rettv->v_type == VAR_STRING) { - rettv->vval.v_string = ga_concat_strings_sep(&ga, "\n"); - } else { - tv_list_alloc_ret(rettv, ga.ga_len); - for (int i = 0; i < ga.ga_len; i++) { - tv_list_append_string(rettv->vval.v_list, - ((const char **)(ga.ga_data))[i], -1); - } - } - - ga_clear_strings(&ga); - } else { - rettv->vval.v_string = NULL; - } -} - -/// "glob2regpat()" function -static void f_glob2regpat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - const char *const pat = tv_get_string_chk(&argvars[0]); // NULL on type error - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = (pat == NULL) ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, false); -} - /// "gettext()" function static void f_gettext(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -3596,106 +3267,6 @@ static bool has_wsl(void) return has_wsl == kTrue; } -/// `haslocaldir([{win}[, {tab}]])` function -/// -/// Returns `1` if the scope object has a local directory, `0` otherwise. If a -/// scope object is not specified the current one is implied. This function -/// share a lot of code with `f_getcwd`. -/// -/// @pre The arguments must be of type number. -/// @pre There may not be more than two arguments. -/// @pre An argument may not be -1 if preceding arguments are not all -1. -/// -/// @post The return value will be either the number `1` or `0`. -static void f_haslocaldir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - // Possible scope of working directory to return. - CdScope scope = kCdScopeInvalid; - - // Numbers of the scope objects (window, tab) we want the working directory - // of. A `-1` means to skip this scope, a `0` means the current object. - int scope_number[] = { - [kCdScopeWindow] = 0, // Number of window to look at. - [kCdScopeTabpage] = 0, // Number of tab to look at. - }; - - tabpage_T *tp = curtab; // The tabpage to look at. - win_T *win = curwin; // The window to look at. - - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = 0; - - // Pre-conditions and scope extraction together - for (int i = MIN_CD_SCOPE; i < MAX_CD_SCOPE; i++) { - if (argvars[i].v_type == VAR_UNKNOWN) { - break; - } - if (argvars[i].v_type != VAR_NUMBER) { - emsg(_(e_invarg)); - return; - } - scope_number[i] = (int)argvars[i].vval.v_number; - if (scope_number[i] < -1) { - emsg(_(e_invarg)); - return; - } - // Use the narrowest scope the user requested - if (scope_number[i] >= 0 && scope == kCdScopeInvalid) { - // The scope is the current iteration step. - scope = i; - } else if (scope_number[i] < 0) { - scope = i + 1; - } - } - - // If the user didn't specify anything, default to window scope - if (scope == kCdScopeInvalid) { - scope = MIN_CD_SCOPE; - } - - // Find the tabpage by number - if (scope_number[kCdScopeTabpage] > 0) { - tp = find_tabpage(scope_number[kCdScopeTabpage]); - if (!tp) { - emsg(_("E5000: Cannot find tab number.")); - return; - } - } - - // Find the window in `tp` by number, `NULL` if none. - if (scope_number[kCdScopeWindow] >= 0) { - if (scope_number[kCdScopeTabpage] < 0) { - emsg(_("E5001: Higher scope cannot be -1 if lower scope is >= 0.")); - return; - } - - if (scope_number[kCdScopeWindow] > 0) { - win = find_win_by_nr(&argvars[0], tp); - if (!win) { - emsg(_("E5002: Cannot find window number.")); - return; - } - } - } - - switch (scope) { - case kCdScopeWindow: - assert(win); - rettv->vval.v_number = win->w_localdir ? 1 : 0; - break; - case kCdScopeTabpage: - assert(tp); - rettv->vval.v_number = tp->tp_localdir ? 1 : 0; - break; - case kCdScopeGlobal: - // The global scope never has a local directory - break; - case kCdScopeInvalid: - // We should never get here - abort(); - } -} - /// "highlightID(name)" function static void f_hlID(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -3760,7 +3331,7 @@ static void f_index(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) typval_T tv; tv.v_type = VAR_NUMBER; tv.vval.v_number = tv_blob_get(b, idx); - if (tv_equal(&tv, &argvars[1], ic, false)) { + if (tv_equal(&tv, &argvars[1], ic)) { rettv->vval.v_number = idx; return; } @@ -3797,7 +3368,7 @@ static void f_index(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } for (; item != NULL; item = TV_LIST_ITEM_NEXT(l, item), idx++) { - if (tv_equal(TV_LIST_ITEM_TV(item), &argvars[1], ic, false)) { + if (tv_equal(TV_LIST_ITEM_TV(item), &argvars[1], ic)) { rettv->vval.v_number = idx; break; } @@ -3843,6 +3414,7 @@ static varnumber_T indexof_blob(blob_T *b, varnumber_T startidx, typval_T *expr) } } + const int called_emsg_start = called_emsg; for (varnumber_T idx = startidx; idx < tv_blob_len(b); idx++) { set_vim_var_nr(VV_KEY, idx); set_vim_var_nr(VV_VAL, tv_blob_get(b, (int)idx)); @@ -3850,6 +3422,10 @@ static varnumber_T indexof_blob(blob_T *b, varnumber_T startidx, typval_T *expr) if (indexof_eval_expr(expr)) { return idx; } + + if (called_emsg != called_emsg_start) { + return -1; + } } return -1; @@ -3879,6 +3455,7 @@ static varnumber_T indexof_list(list_T *l, varnumber_T startidx, typval_T *expr) } } + const int called_emsg_start = called_emsg; for (; item != NULL; item = TV_LIST_ITEM_NEXT(l, item), idx++) { set_vim_var_nr(VV_KEY, idx); tv_copy(TV_LIST_ITEM_TV(item), get_vim_var_tv(VV_VAL)); @@ -3889,6 +3466,10 @@ static varnumber_T indexof_list(list_T *l, varnumber_T startidx, typval_T *expr) if (found) { return idx; } + + if (called_emsg != called_emsg_start) { + return -1; + } } return -1; @@ -3905,7 +3486,8 @@ static void f_indexof(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } - if ((argvars[1].v_type == VAR_STRING && argvars[1].vval.v_string == NULL) + if ((argvars[1].v_type == VAR_STRING + && (argvars[1].vval.v_string == NULL || *argvars[1].vval.v_string == NUL)) || (argvars[1].v_type == VAR_FUNC && argvars[1].vval.v_partial == NULL)) { return; } @@ -4101,12 +3683,6 @@ static void f_invert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL); } -/// "isdirectory()" function -static void f_isdirectory(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - rettv->vval.v_number = os_isdir(tv_get_string(&argvars[0])); -} - /// "islocked()" function static void f_islocked(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -4195,7 +3771,7 @@ static void f_jobpid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } - Process *proc = &data->stream.proc; + Proc *proc = &data->stream.proc; rettv->vval.v_number = proc->pid; } @@ -4221,13 +3797,13 @@ static void f_jobresize(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } - if (data->stream.proc.type != kProcessTypePty) { + if (data->stream.proc.type != kProcTypePty) { emsg(_(e_channotpty)); return; } - pty_process_resize(&data->stream.pty, (uint16_t)argvars[1].vval.v_number, - (uint16_t)argvars[2].vval.v_number); + pty_proc_resize(&data->stream.pty, (uint16_t)argvars[1].vval.v_number, + (uint16_t)argvars[2].vval.v_number); rettv->vval.v_number = 1; } @@ -4309,7 +3885,7 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en // Set $NVIM (in the child process) to v:servername. #3118 char *nvim_addr = get_vim_var_str(VV_SEND_SERVER); - if (nvim_addr[0] != '\0') { + if (nvim_addr[0] != NUL) { dictitem_T *dv = tv_dict_find(env, S_LEN("NVIM")); if (dv) { tv_dict_item_remove(env, dv); @@ -4502,7 +4078,7 @@ static void f_jobstop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) // Ignore return code, but show error later. channel_close(data->id, kChannelPartRpc, &error); } - process_stop(&data->stream.proc); + proc_stop(&data->stream.proc); rettv->vval.v_number = 1; if (error) { emsg(error); @@ -4538,10 +4114,10 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) || !(chan = find_channel((uint64_t)TV_LIST_ITEM_TV(arg)->vval.v_number)) || chan->streamtype != kChannelStreamProc) { jobs[i] = NULL; // Invalid job. - } else if (process_is_stopped(&chan->stream.proc)) { + } else if (proc_is_stopped(&chan->stream.proc)) { // Job is stopped but not fully destroyed. // Ensure all callbacks on its event queue are executed. #15402 - process_wait(&chan->stream.proc, -1, NULL); + proc_wait(&chan->stream.proc, -1, NULL); jobs[i] = NULL; // Invalid job. } else { jobs[i] = chan; @@ -4569,8 +4145,8 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (jobs[i] == NULL) { continue; // Invalid job, will assign status=-3 below. } - int status = process_wait(&jobs[i]->stream.proc, remaining, - waiting_jobs); + int status = proc_wait(&jobs[i]->stream.proc, remaining, + waiting_jobs); if (status < 0) { break; // Interrupted (CTRL-C) or timeout, skip remaining jobs. } @@ -5350,78 +4926,6 @@ static void f_min(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) max_min(argvars, rettv, false); } -/// "mkdir()" function -static void f_mkdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - int prot = 0755; - - rettv->vval.v_number = FAIL; - if (check_secure()) { - return; - } - - char buf[NUMBUFLEN]; - const char *const dir = tv_get_string_buf(&argvars[0], buf); - if (*dir == NUL) { - return; - } - - if (*path_tail(dir) == NUL) { - // Remove trailing slashes. - *path_tail_with_sep((char *)dir) = NUL; - } - - bool defer = false; - bool defer_recurse = false; - char *created = NULL; - if (argvars[1].v_type != VAR_UNKNOWN) { - if (argvars[2].v_type != VAR_UNKNOWN) { - prot = (int)tv_get_number_chk(&argvars[2], NULL); - if (prot == -1) { - return; - } - } - const char *arg2 = tv_get_string(&argvars[1]); - defer = vim_strchr(arg2, 'D') != NULL; - defer_recurse = vim_strchr(arg2, 'R') != NULL; - if ((defer || defer_recurse) && !can_add_defer()) { - return; - } - - if (vim_strchr(arg2, 'p') != NULL) { - char *failed_dir; - int ret = os_mkdir_recurse(dir, prot, &failed_dir, - defer || defer_recurse ? &created : NULL); - if (ret != 0) { - semsg(_(e_mkdir), failed_dir, os_strerror(ret)); - xfree(failed_dir); - rettv->vval.v_number = FAIL; - return; - } - rettv->vval.v_number = OK; - } - } - if (rettv->vval.v_number == FAIL) { - rettv->vval.v_number = vim_mkdir_emsg(dir, prot); - } - - // Handle "D" and "R": deferred deletion of the created directory. - if (rettv->vval.v_number == OK - && created == NULL && (defer || defer_recurse)) { - created = FullName_save(dir, false); - } - if (created != NULL) { - typval_T tv[2]; - tv[0].v_type = VAR_STRING; - tv[0].v_lock = VAR_UNLOCKED; - tv[0].vval.v_string = created; - tv[1].v_type = VAR_STRING; - tv[1].v_lock = VAR_UNLOCKED; - tv[1].vval.v_string = xstrdup(defer_recurse ? "rf" : "d"); - add_defer("delete", 2, tv); - } -} - /// "mode()" function static void f_mode(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -5492,15 +4996,7 @@ static void f_msgpackdump(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } list_T *const list = argvars[0].vval.v_list; - msgpack_packer *packer; - if (argvars[1].v_type != VAR_UNKNOWN - && strequal(tv_get_string(&argvars[1]), "B")) { - tv_blob_alloc_ret(rettv); - packer = msgpack_packer_new(rettv->vval.v_blob, &encode_blob_write); - } else { - packer = msgpack_packer_new(tv_list_alloc_ret(rettv, kListLenMayKnow), - &encode_list_write); - } + PackerBuffer packer = packer_string_buffer(); const char *const msg = _("msgpackdump() argument, index %i"); // Assume that translation will not take more then 4 times more space char msgbuf[sizeof("msgpackdump() argument, index ") * 4 + NUMBUFLEN]; @@ -5508,43 +5004,40 @@ static void f_msgpackdump(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) TV_LIST_ITER(list, li, { vim_snprintf(msgbuf, sizeof(msgbuf), msg, idx); idx++; - if (encode_vim_to_msgpack(packer, TV_LIST_ITEM_TV(li), msgbuf) == FAIL) { + if (encode_vim_to_msgpack(&packer, TV_LIST_ITEM_TV(li), msgbuf) == FAIL) { break; } }); - msgpack_packer_free(packer); + String data = packer_take_string(&packer); + if (argvars[1].v_type != VAR_UNKNOWN && strequal(tv_get_string(&argvars[1]), "B")) { + blob_T *b = tv_blob_alloc_ret(rettv); + b->bv_ga.ga_data = data.data; + b->bv_ga.ga_len = (int)data.size; + b->bv_ga.ga_maxlen = (int)(packer.endptr - packer.startptr); + } else { + encode_list_write(tv_list_alloc_ret(rettv, kListLenMayKnow), data.data, data.size); + api_free_string(data); + } } -static int msgpackparse_convert_item(const msgpack_object data, const msgpack_unpack_return result, - list_T *const ret_list, const bool fail_if_incomplete) - FUNC_ATTR_NONNULL_ALL +static void emsg_mpack_error(int status) { - switch (result) { - case MSGPACK_UNPACK_PARSE_ERROR: + switch (status) { + case MPACK_ERROR: semsg(_(e_invarg2), "Failed to parse msgpack string"); - return FAIL; - case MSGPACK_UNPACK_NOMEM_ERROR: - emsg(_(e_outofmem)); - return FAIL; - case MSGPACK_UNPACK_CONTINUE: - if (fail_if_incomplete) { - semsg(_(e_invarg2), "Incomplete msgpack string"); - return FAIL; - } - return NOTDONE; - case MSGPACK_UNPACK_SUCCESS: { - typval_T tv = { .v_type = VAR_UNKNOWN }; - if (msgpack_to_vim(data, &tv) == FAIL) { - semsg(_(e_invarg2), "Failed to convert msgpack string"); - return FAIL; - } - tv_list_append_owned_tv(ret_list, tv); - return OK; - } - case MSGPACK_UNPACK_EXTRA_BYTES: - abort(); + break; + + case MPACK_EOF: + semsg(_(e_invarg2), "Incomplete msgpack string"); + break; + + case MPACK_NOMEM: + semsg(_(e_invarg2), "object was too deep to unpack"); + break; + + default: + break; } - UNREACHABLE; } static void msgpackparse_unpack_list(const list_T *const list, list_T *const ret_list) @@ -5558,48 +5051,57 @@ static void msgpackparse_unpack_list(const list_T *const list, list_T *const ret return; } ListReaderState lrstate = encode_init_lrstate(list); - msgpack_unpacker *const unpacker = msgpack_unpacker_new(IOSIZE); - if (unpacker == NULL) { - emsg(_(e_outofmem)); - return; - } - msgpack_unpacked unpacked; - msgpack_unpacked_init(&unpacked); + char *buf = alloc_block(); + size_t buf_size = 0; + + typval_T cur_item = { .v_type = VAR_UNKNOWN }; + mpack_parser_t parser; + mpack_parser_init(&parser, 0); + parser.data.p = &cur_item; + + int status = MPACK_OK; while (true) { - if (!msgpack_unpacker_reserve_buffer(unpacker, IOSIZE)) { - emsg(_(e_outofmem)); - goto end; - } size_t read_bytes; - const int rlret = encode_read_from_list(&lrstate, msgpack_unpacker_buffer(unpacker), IOSIZE, + const int rlret = encode_read_from_list(&lrstate, buf + buf_size, ARENA_BLOCK_SIZE - buf_size, &read_bytes); if (rlret == FAIL) { semsg(_(e_invarg2), "List item is not a string"); goto end; } - msgpack_unpacker_buffer_consumed(unpacker, read_bytes); - if (read_bytes == 0) { - break; - } - while (unpacker->off < unpacker->used) { - const msgpack_unpack_return result - = msgpack_unpacker_next(unpacker, &unpacked); - const int conv_result = msgpackparse_convert_item(unpacked.data, result, - ret_list, rlret == OK); - if (conv_result == NOTDONE) { + buf_size += read_bytes; + + const char *ptr = buf; + while (buf_size) { + status = mpack_parse_typval(&parser, &ptr, &buf_size); + if (status == MPACK_OK) { + tv_list_append_owned_tv(ret_list, cur_item); + cur_item.v_type = VAR_UNKNOWN; + } else { break; - } else if (conv_result == FAIL) { - goto end; } } + if (rlret == OK) { break; } + + if (status == MPACK_EOF) { + // move remaining data to front of buffer + if (buf_size && ptr > buf) { + memmove(buf, ptr, buf_size); + } + } else if (status != MPACK_OK) { + break; + } + } + + if (status != MPACK_OK) { + typval_parser_error_free(&parser); + emsg_mpack_error(status); } end: - msgpack_unpacker_free(unpacker); - msgpack_unpacked_destroy(&unpacked); + free_block(buf); } static void msgpackparse_unpack_blob(const blob_T *const blob, list_T *const ret_list) @@ -5609,18 +5111,19 @@ static void msgpackparse_unpack_blob(const blob_T *const blob, list_T *const ret if (len == 0) { return; } - msgpack_unpacked unpacked; - msgpack_unpacked_init(&unpacked); - for (size_t offset = 0; offset < (size_t)len;) { - const msgpack_unpack_return result - = msgpack_unpack_next(&unpacked, blob->bv_ga.ga_data, (size_t)len, &offset); - if (msgpackparse_convert_item(unpacked.data, result, ret_list, true) - != OK) { - break; + + const char *data = blob->bv_ga.ga_data; + size_t remaining = (size_t)len; + while (remaining) { + typval_T tv; + int status = unpack_typval(&data, &remaining, &tv); + if (status != MPACK_OK) { + emsg_mpack_error(status); + return; } - } - msgpack_unpacked_destroy(&unpacked); + tv_list_append_owned_tv(ret_list, tv); + } } /// "msgpackparse" function @@ -5694,28 +5197,6 @@ static void f_or(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) | tv_get_number_chk(&argvars[1], NULL); } -/// "pathshorten()" function -static void f_pathshorten(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - int trim_len = 1; - - if (argvars[1].v_type != VAR_UNKNOWN) { - trim_len = (int)tv_get_number(&argvars[1]); - if (trim_len < 1) { - trim_len = 1; - } - } - - rettv->v_type = VAR_STRING; - const char *p = tv_get_string_chk(&argvars[0]); - if (p == NULL) { - rettv->vval.v_string = NULL; - } else { - rettv->vval.v_string = xstrdup(p); - shorten_dir_len(rettv->vval.v_string, trim_len); - } -} - /// "pow()" function static void f_pow(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -5872,42 +5353,20 @@ static void f_py3eval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) static void init_srand(uint32_t *const x) FUNC_ATTR_NONNULL_ALL { -#ifndef MSWIN - static int dev_urandom_state = NOTDONE; // FAIL or OK once tried - - if (dev_urandom_state != FAIL) { - const int fd = os_open("/dev/urandom", O_RDONLY, 0); - struct { - union { - uint32_t number; - char bytes[sizeof(uint32_t)]; - } contents; - } buf; - - // Attempt reading /dev/urandom. - if (fd == -1) { - dev_urandom_state = FAIL; - } else { - buf.contents.number = 0; - if (read(fd, buf.contents.bytes, sizeof(uint32_t)) != sizeof(uint32_t)) { - dev_urandom_state = FAIL; - } else { - dev_urandom_state = OK; - *x = buf.contents.number; - } - os_close(fd); - } - } - if (dev_urandom_state != OK) { - // Reading /dev/urandom doesn't work, fall back to os_hrtime() XOR with process ID -#endif - // uncrustify:off - *x = (uint32_t)os_hrtime(); - *x ^= (uint32_t)os_get_pid(); -#ifndef MSWIN + union { + uint32_t number; + uint8_t bytes[sizeof(uint32_t)]; + } buf; + + if (uv_random(NULL, NULL, buf.bytes, sizeof(buf.bytes), 0, NULL) == 0) { + *x = buf.number; + return; } -#endif - // uncrustify:on + + // The system's random number generator doesn't work, + // fall back to os_hrtime() XOR with process ID + *x = (uint32_t)os_hrtime(); + *x ^= (uint32_t)os_get_pid(); } static inline uint32_t splitmix32(uint32_t *const x) @@ -6076,267 +5535,6 @@ static void f_range(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } -/// Evaluate "expr" (= "context") for readdir(). -static varnumber_T readdir_checkitem(void *context, const char *name) - FUNC_ATTR_NONNULL_ALL -{ - typval_T *expr = (typval_T *)context; - typval_T argv[2]; - varnumber_T retval = 0; - bool error = false; - - if (expr->v_type == VAR_UNKNOWN) { - return 1; - } - - typval_T save_val; - prepare_vimvar(VV_VAL, &save_val); - set_vim_var_string(VV_VAL, name, -1); - argv[0].v_type = VAR_STRING; - argv[0].vval.v_string = (char *)name; - - typval_T rettv; - if (eval_expr_typval(expr, false, argv, 1, &rettv) == FAIL) { - goto theend; - } - - retval = tv_get_number_chk(&rettv, &error); - if (error) { - retval = -1; - } - - tv_clear(&rettv); - -theend: - set_vim_var_string(VV_VAL, NULL, 0); - restore_vimvar(VV_VAL, &save_val); - return retval; -} - -/// "readdir()" function -static void f_readdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - tv_list_alloc_ret(rettv, kListLenUnknown); - - const char *path = tv_get_string(&argvars[0]); - typval_T *expr = &argvars[1]; - garray_T ga; - int ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem); - if (ret == OK && ga.ga_len > 0) { - for (int i = 0; i < ga.ga_len; i++) { - const char *p = ((const char **)ga.ga_data)[i]; - tv_list_append_string(rettv->vval.v_list, p, -1); - } - } - ga_clear_strings(&ga); -} - -/// "readfile()" or "readblob()" function -static void read_file_or_blob(typval_T *argvars, typval_T *rettv, bool always_blob) -{ - bool binary = false; - bool blob = always_blob; - FILE *fd; - char buf[(IOSIZE/256) * 256]; // rounded to avoid odd + 1 - int io_size = sizeof(buf); - 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 - int64_t maxline = MAXLNUM; - off_T offset = 0; - off_T size = -1; - - if (argvars[1].v_type != VAR_UNKNOWN) { - if (always_blob) { - offset = (off_T)tv_get_number(&argvars[1]); - if (argvars[2].v_type != VAR_UNKNOWN) { - size = (off_T)tv_get_number(&argvars[2]); - } - } else { - if (strcmp(tv_get_string(&argvars[1]), "b") == 0) { - binary = true; - } else if (strcmp(tv_get_string(&argvars[1]), "B") == 0) { - blob = true; - } - if (argvars[2].v_type != VAR_UNKNOWN) { - maxline = tv_get_number(&argvars[2]); - } - } - } - - if (blob) { - tv_blob_alloc_ret(rettv); - } else { - tv_list_alloc_ret(rettv, kListLenUnknown); - } - - // Always open the file in binary mode, library functions have a mind of - // their own about CR-LF conversion. - const char *const fname = tv_get_string(&argvars[0]); - - if (os_isdir(fname)) { - semsg(_(e_isadir2), fname); - return; - } - if (*fname == NUL || (fd = os_fopen(fname, READBIN)) == NULL) { - semsg(_(e_notopen), *fname == NUL ? _("<empty>") : fname); - return; - } - - if (blob) { - if (read_blob(fd, rettv, offset, size) == FAIL) { - semsg(_(e_notread), fname); - } - fclose(fd); - return; - } - - list_T *const l = rettv->vval.v_list; - - while (maxline < 0 || tv_list_len(l) < maxline) { - int readlen = (int)fread(buf, 1, (size_t)io_size, fd); - - // This for loop processes what was read, but is also entered at end - // of file so that either: - // - an incomplete line gets written - // - a "binary" file gets an empty line at the end if it ends in a - // newline. - char *p; // Position in buf. - char *start; // Start of current line. - for (p = buf, start = buf; - p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary)); - p++) { - if (readlen <= 0 || *p == '\n') { - char *s = NULL; - size_t len = (size_t)(p - start); - - // Finished a line. Remove CRs before NL. - if (readlen > 0 && !binary) { - while (len > 0 && start[len - 1] == '\r') { - len--; - } - // removal may cross back to the "prev" string - if (len == 0) { - while (prevlen > 0 && prev[prevlen - 1] == '\r') { - prevlen--; - } - } - } - if (prevlen == 0) { - assert(len < INT_MAX); - s = xmemdupz(start, len); - } else { - // Change "prev" buffer to be the right size. This way - // the bytes are only copied once, and very long lines are - // allocated only once. - s = xrealloc(prev, (size_t)prevlen + len + 1); - memcpy(s + prevlen, start, len); - s[(size_t)prevlen + len] = NUL; - prev = NULL; // the list will own the string - prevlen = prevsize = 0; - } - - tv_list_append_owned_tv(l, (typval_T) { - .v_type = VAR_STRING, - .v_lock = VAR_UNLOCKED, - .vval.v_string = s, - }); - - start = p + 1; // Step over newline. - if (maxline < 0) { - if (tv_list_len(l) > -maxline) { - assert(tv_list_len(l) == 1 + (-maxline)); - tv_list_item_remove(l, tv_list_first(l)); - } - } else if (tv_list_len(l) >= maxline) { - assert(tv_list_len(l) == maxline); - break; - } - if (readlen <= 0) { - break; - } - } else if (*p == NUL) { - *p = '\n'; - // Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this - // when finding the BF and check the previous two bytes. - } else if ((uint8_t)(*p) == 0xbf && !binary) { - // Find the two bytes before the 0xbf. If p is at buf, or buf + 1, - // these may be in the "prev" string. - char back1 = p >= buf + 1 ? p[-1] - : prevlen >= 1 ? prev[prevlen - 1] : NUL; - char back2 = p >= buf + 2 ? p[-2] - : (p == buf + 1 && prevlen >= 1 - ? prev[prevlen - 1] - : prevlen >= 2 ? prev[prevlen - 2] : NUL); - - if ((uint8_t)back2 == 0xef && (uint8_t)back1 == 0xbb) { - char *dest = p - 2; - - // Usually a BOM is at the beginning of a file, and so at - // the beginning of a line; then we can just step over it. - if (start == dest) { - start = p + 1; - } else { - // have to shuffle buf to close gap - int adjust_prevlen = 0; - - if (dest < buf) { - // adjust_prevlen must be 1 or 2. - adjust_prevlen = (int)(buf - dest); - dest = buf; - } - if (readlen > p - buf + 1) { - memmove(dest, p + 1, (size_t)readlen - (size_t)(p - buf) - 1); - } - readlen -= 3 - adjust_prevlen; - prevlen -= adjust_prevlen; - p = dest - 1; - } - } - } - } // for - - if ((maxline >= 0 && tv_list_len(l) >= maxline) || readlen <= 0) { - break; - } - if (start < p) { - // There's part of a line in buf, store it in "prev". - if (p - start + prevlen >= prevsize) { - // A common use case is ordinary text files and "prev" gets a - // fragment of a line, so the first allocation is made - // small, to avoid repeatedly 'allocing' large and - // 'reallocing' small. - if (prevsize == 0) { - prevsize = p - start; - } else { - ptrdiff_t grow50pc = (prevsize * 3) / 2; - ptrdiff_t growmin = (p - start) * 2 + prevlen; - prevsize = grow50pc > growmin ? grow50pc : growmin; - } - prev = xrealloc(prev, (size_t)prevsize); - } - // Add the line part to end of "prev". - memmove(prev + prevlen, start, (size_t)(p - start)); - prevlen += p - start; - } - } // while - - xfree(prev); - fclose(fd); -} - -/// "readblob()" function -static void f_readblob(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - read_file_or_blob(argvars, rettv, true); -} - -/// "readfile()" function -static void f_readfile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - read_file_or_blob(argvars, rettv, false); -} - /// "getreginfo()" function static void f_getreginfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -6387,6 +5585,14 @@ static void f_getreginfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } +static void return_register(int regname, typval_T *rettv) +{ + char buf[2] = { (char)regname, 0 }; + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = xstrdup(buf); +} + /// "reg_executing()" function static void f_reg_executing(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -6511,18 +5717,6 @@ static void f_remove(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } -/// "rename({from}, {to})" function -static void f_rename(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - if (check_secure()) { - rettv->vval.v_number = -1; - } else { - char buf[NUMBUFLEN]; - rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]), - tv_get_string_buf(&argvars[1], buf)); - } -} - /// "repeat()" function static void f_repeat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -6591,175 +5785,6 @@ static void f_repeat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } -/// "resolve()" function -static void f_resolve(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - rettv->v_type = VAR_STRING; - const char *fname = tv_get_string(&argvars[0]); -#ifdef MSWIN - char *v = os_resolve_shortcut(fname); - if (v == NULL) { - if (os_is_reparse_point_include(fname)) { - v = os_realpath(fname, NULL, MAXPATHL + 1); - } - } - rettv->vval.v_string = (v == NULL ? xstrdup(fname) : v); -#else -# ifdef HAVE_READLINK - { - bool is_relative_to_current = false; - bool has_trailing_pathsep = false; - int limit = 100; - - char *p = xstrdup(fname); - - if (p[0] == '.' && (vim_ispathsep(p[1]) - || (p[1] == '.' && (vim_ispathsep(p[2]))))) { - is_relative_to_current = true; - } - - ptrdiff_t len = (ptrdiff_t)strlen(p); - if (len > 1 && after_pathsep(p, p + len)) { - has_trailing_pathsep = true; - p[len - 1] = NUL; // The trailing slash breaks readlink(). - } - - char *q = (char *)path_next_component(p); - char *remain = NULL; - if (*q != NUL) { - // Separate the first path component in "p", and keep the - // remainder (beginning with the path separator). - remain = xstrdup(q - 1); - q[-1] = NUL; - } - - char *const buf = xmallocz(MAXPATHL); - - char *cpy; - while (true) { - while (true) { - len = readlink(p, buf, MAXPATHL); - if (len <= 0) { - break; - } - buf[len] = NUL; - - if (limit-- == 0) { - xfree(p); - xfree(remain); - emsg(_("E655: Too many symbolic links (cycle?)")); - rettv->vval.v_string = NULL; - xfree(buf); - return; - } - - // Ensure that the result will have a trailing path separator - // if the argument has one. - if (remain == NULL && has_trailing_pathsep) { - add_pathsep(buf); - } - - // Separate the first path component in the link value and - // concatenate the remainders. - q = (char *)path_next_component(vim_ispathsep(*buf) ? buf + 1 : buf); - if (*q != NUL) { - cpy = remain; - remain = (remain - ? concat_str(q - 1, remain) - : xstrdup(q - 1)); - xfree(cpy); - q[-1] = NUL; - } - - q = path_tail(p); - if (q > p && *q == NUL) { - // Ignore trailing path separator. - p[q - p - 1] = NUL; - q = path_tail(p); - } - if (q > p && !path_is_absolute(buf)) { - // Symlink is relative to directory of argument. Replace the - // symlink with the resolved name in the same directory. - const size_t p_len = strlen(p); - const size_t buf_len = strlen(buf); - p = xrealloc(p, p_len + buf_len + 1); - memcpy(path_tail(p), buf, buf_len + 1); - } else { - xfree(p); - p = xstrdup(buf); - } - } - - if (remain == NULL) { - break; - } - - // Append the first path component of "remain" to "p". - q = (char *)path_next_component(remain + 1); - len = q - remain - (*q != NUL); - const size_t p_len = strlen(p); - cpy = xmallocz(p_len + (size_t)len); - memcpy(cpy, p, p_len + 1); - xstrlcat(cpy + p_len, remain, (size_t)len + 1); - xfree(p); - p = cpy; - - // Shorten "remain". - if (*q != NUL) { - STRMOVE(remain, q - 1); - } else { - XFREE_CLEAR(remain); - } - } - - // If the result is a relative path name, make it explicitly relative to - // the current directory if and only if the argument had this form. - if (!vim_ispathsep(*p)) { - if (is_relative_to_current - && *p != NUL - && !(p[0] == '.' - && (p[1] == NUL - || vim_ispathsep(p[1]) - || (p[1] == '.' - && (p[2] == NUL - || vim_ispathsep(p[2])))))) { - // Prepend "./". - cpy = concat_str("./", p); - xfree(p); - p = cpy; - } else if (!is_relative_to_current) { - // Strip leading "./". - q = p; - while (q[0] == '.' && vim_ispathsep(q[1])) { - q += 2; - } - if (q > p) { - STRMOVE(p, p + 2); - } - } - } - - // Ensure that the result will have no trailing path separator - // if the argument had none. But keep "/" or "//". - if (!has_trailing_pathsep) { - q = p + strlen(p); - if (after_pathsep(p, q)) { - *path_tail_with_sep(p) = NUL; - } - } - - rettv->vval.v_string = p; - xfree(buf); - } -# else - char *v = os_realpath(fname, NULL, MAXPATHL + 1); - rettv->vval.v_string = v == NULL ? xstrdup(fname) : v; -# endif -#endif - - simplify_filename(rettv->vval.v_string); -} - /// "reverse({list})" function static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -7412,6 +6437,21 @@ static void f_rpcstop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } +static void screenchar_adjust(ScreenGrid **grid, int *row, int *col) +{ + // TODO(bfredl): this is a hack for legacy tests which use screenchar() + // to check printed messages on the screen (but not floats etc + // as these are not legacy features). If the compositor is refactored to + // have its own buffer, this should just read from it instead. + msg_scroll_flush(); + + *grid = ui_comp_get_grid_at_coord(*row, *col); + + // Make `row` and `col` relative to the grid + *row -= (*grid)->comp_row; + *col -= (*grid)->comp_col; +} + /// "screenattr()" function static void f_screenattr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -8293,21 +7333,12 @@ static void f_shiftwidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (col < 0) { return; // type error; errmsg already given } - rettv->vval.v_number = get_sw_value_col(curbuf, col); + rettv->vval.v_number = get_sw_value_col(curbuf, col, false); return; } rettv->vval.v_number = get_sw_value(curbuf); } -/// "simplify()" function -static void f_simplify(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - const char *const p = tv_get_string(&argvars[0]); - rettv->vval.v_string = xstrdup(p); - simplify_filename(rettv->vval.v_string); // Simplify in place. - rettv->v_type = VAR_STRING; -} - /// "sockconnect()" function static void f_sockconnect(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -8598,6 +7629,33 @@ theend: p_cpo = save_cpo; } +/// "stdpath()" helper for list results +static void get_xdg_var_list(const XDGVarType xdg, typval_T *rettv) + FUNC_ATTR_NONNULL_ALL +{ + list_T *const list = tv_list_alloc(kListLenShouldKnow); + rettv->v_type = VAR_LIST; + rettv->vval.v_list = list; + tv_list_ref(list); + char *const dirs = stdpaths_get_xdg_var(xdg); + if (dirs == NULL) { + return; + } + const void *iter = NULL; + const char *appname = get_appname(false); + do { + size_t dir_len; + const char *dir; + iter = vim_env_iter(ENV_SEPCHAR, dirs, iter, &dir, &dir_len); + if (dir != NULL && dir_len > 0) { + char *dir_with_nvim = xmemdupz(dir, dir_len); + dir_with_nvim = concat_fnames_realloc(dir_with_nvim, appname, true); + tv_list_append_allocated_string(list, dir_with_nvim); + } + } while (iter != NULL); + xfree(dirs); +} + /// "stdpath(type)" function static void f_stdpath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -9066,13 +8124,6 @@ static void f_taglist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) (char *)tag_pattern, (char *)fname); } -/// "tempname()" function -static void f_tempname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = vim_tempname(); -} - /// "termopen(cmd[, cwd])" function static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -9157,7 +8208,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } - int pid = chan->stream.pty.process.pid; + int pid = chan->stream.pty.proc.pid; // "./…" => "/home/foo/…" vim_FullName(cwd, NameBuff, sizeof(NameBuff), false); @@ -9165,13 +8216,13 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) size_t len = home_replace(NULL, NameBuff, IObuff, sizeof(IObuff), true); // Trim slash. if (len != 1 && (IObuff[len - 1] == '\\' || IObuff[len - 1] == '/')) { - IObuff[len - 1] = '\0'; + IObuff[len - 1] = NUL; } if (len == 1 && IObuff[0] == '/') { // Avoid ambiguity in the URI when CWD is root directory. IObuff[1] = '.'; - IObuff[2] = '\0'; + IObuff[2] = NUL; } // Terminal URI: "term://$CWD//$PID:$CMD" @@ -9418,104 +8469,6 @@ static void f_wordcount(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) cursor_pos_info(rettv->vval.v_dict); } -/// "writefile()" function -static void f_writefile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) -{ - rettv->vval.v_number = -1; - - if (check_secure()) { - return; - } - - if (argvars[0].v_type == VAR_LIST) { - TV_LIST_ITER_CONST(argvars[0].vval.v_list, li, { - if (!tv_check_str_or_nr(TV_LIST_ITEM_TV(li))) { - return; - } - }); - } else if (argvars[0].v_type != VAR_BLOB) { - semsg(_(e_invarg2), - _("writefile() first argument must be a List or a Blob")); - return; - } - - bool binary = false; - bool append = false; - bool defer = false; - bool do_fsync = !!p_fs; - bool mkdir_p = false; - if (argvars[2].v_type != VAR_UNKNOWN) { - const char *const flags = tv_get_string_chk(&argvars[2]); - if (flags == NULL) { - return; - } - for (const char *p = flags; *p; p++) { - switch (*p) { - case 'b': - binary = true; break; - case 'a': - append = true; break; - case 'D': - defer = true; break; - case 's': - do_fsync = true; break; - case 'S': - do_fsync = false; break; - case 'p': - mkdir_p = true; break; - default: - // Using %s, p and not %c, *p to preserve multibyte characters - semsg(_("E5060: Unknown flag: %s"), p); - return; - } - } - } - - char buf[NUMBUFLEN]; - const char *const fname = tv_get_string_buf_chk(&argvars[1], buf); - if (fname == NULL) { - return; - } - - if (defer && !can_add_defer()) { - return; - } - - FileDescriptor fp; - int error; - if (*fname == NUL) { - emsg(_("E482: Can't open file with an empty name")); - } else if ((error = file_open(&fp, fname, - ((append ? kFileAppend : kFileTruncate) - | (mkdir_p ? kFileMkDir : kFileCreate) - | kFileCreate), 0666)) != 0) { - semsg(_("E482: Can't open file %s for writing: %s"), fname, os_strerror(error)); - } else { - if (defer) { - typval_T tv = { - .v_type = VAR_STRING, - .v_lock = VAR_UNLOCKED, - .vval.v_string = FullName_save(fname, false), - }; - add_defer("delete", 1, &tv); - } - - bool write_ok; - if (argvars[0].v_type == VAR_BLOB) { - write_ok = write_blob(&fp, argvars[0].vval.v_blob); - } else { - write_ok = write_list(&fp, argvars[0].vval.v_list, binary); - } - if (write_ok) { - rettv->vval.v_number = 0; - } - if ((error = file_close(&fp, do_fsync)) != 0) { - semsg(_("E80: Error when closing file %s: %s"), - fname, os_strerror(error)); - } - } -} - /// "xor(expr, expr)" function static void f_xor(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index eb8c89c36e..e7b6a0feee 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -10,11 +10,13 @@ #include "nvim/ascii_defs.h" #include "nvim/assert_defs.h" #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/executor.h" #include "nvim/eval/gc.h" #include "nvim/eval/typval.h" +#include "nvim/eval/typval_defs.h" #include "nvim/eval/typval_encode.h" #include "nvim/eval/userfunc.h" #include "nvim/eval/vars.h" @@ -58,6 +60,13 @@ typedef struct { typedef int (*ListSorter)(const void *, const void *); +/// Type for tv_dict2list() function +typedef enum { + kDict2ListKeys, ///< List dictionary keys. + kDict2ListValues, ///< List dictionary values. + kDict2ListItems, ///< List dictionary contents: [keys, values]. +} DictListType; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "eval/typval.c.generated.h" #endif @@ -84,6 +93,8 @@ static const char e_string_or_number_required_for_argument_nr[] = N_("E1220: String or Number required for argument %d"); static const char e_string_or_list_required_for_argument_nr[] = N_("E1222: String or List required for argument %d"); +static const char e_string_list_or_dict_required_for_argument_nr[] + = N_("E1225: String, List or Dictionary required for argument %d"); static const char e_list_or_blob_required_for_argument_nr[] = N_("E1226: List or Blob required for argument %d"); static const char e_blob_required_for_argument_nr[] @@ -474,13 +485,14 @@ void tv_list_append_tv(list_T *const l, typval_T *const tv) /// Like tv_list_append_tv(), but tv is moved to a list /// /// This means that it is no longer valid to use contents of the typval_T after -/// function exits. -void tv_list_append_owned_tv(list_T *const l, typval_T tv) +/// function exits. A pointer is returned to the allocated typval which can be used +typval_T *tv_list_append_owned_tv(list_T *const l, typval_T tv) FUNC_ATTR_NONNULL_ALL { listitem_T *const li = tv_list_item_alloc(); *TV_LIST_ITEM_TV(li) = tv; tv_list_append(l, li); + return TV_LIST_ITEM_TV(li); } /// Append a list to a list as one item @@ -781,6 +793,51 @@ void tv_list_flatten(list_T *list, listitem_T *first, int64_t maxitems, int64_t } } +/// "items(list)" function +/// Caller must have already checked that argvars[0] is a List. +static void tv_list2items(typval_T *argvars, typval_T *rettv) +{ + list_T *l = argvars[0].vval.v_list; + + tv_list_alloc_ret(rettv, tv_list_len(l)); + if (l == NULL) { + return; // null list behaves like an empty list + } + + varnumber_T idx = 0; + TV_LIST_ITER(l, li, { + list_T *l2 = tv_list_alloc(2); + tv_list_append_list(rettv->vval.v_list, l2); + tv_list_append_number(l2, idx); + tv_list_append_tv(l2, TV_LIST_ITEM_TV(li)); + idx++; + }); +} + +/// "items(string)" function +/// Caller must have already checked that argvars[0] is a String. +static void tv_string2items(typval_T *argvars, typval_T *rettv) +{ + const char *p = argvars[0].vval.v_string; + + tv_list_alloc_ret(rettv, kListLenMayKnow); + if (p == NULL) { + return; // null string behaves like an empty string + } + + for (varnumber_T idx = 0; *p != NUL; idx++) { + int len = utfc_ptr2len(p); + if (len == 0) { + break; + } + list_T *l2 = tv_list_alloc(2); + tv_list_append_list(rettv->vval.v_list, l2); + tv_list_append_number(l2, idx); + tv_list_append_string(l2, p, len); + p += len; + } +} + /// Extend first list with the second /// /// @param[out] l1 List to extend. @@ -1459,10 +1516,9 @@ void f_uniq(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// @param[in] l1 First list to compare. /// @param[in] l2 Second list to compare. /// @param[in] ic True if case is to be ignored. -/// @param[in] recursive True when used recursively. /// /// @return True if lists are equal, false otherwise. -bool tv_list_equal(list_T *const l1, list_T *const l2, const bool ic, const bool recursive) +bool tv_list_equal(list_T *const l1, list_T *const l2, const bool ic) FUNC_ATTR_WARN_UNUSED_RESULT { if (l1 == l2) { @@ -1484,8 +1540,7 @@ bool tv_list_equal(list_T *const l1, list_T *const l2, const bool ic, const bool for (; item1 != NULL && item2 != NULL ; (item1 = TV_LIST_ITEM_NEXT(l1, item1), item2 = TV_LIST_ITEM_NEXT(l2, item2))) { - if (!tv_equal(TV_LIST_ITEM_TV(item1), TV_LIST_ITEM_TV(item2), ic, - recursive)) { + if (!tv_equal(TV_LIST_ITEM_TV(item1), TV_LIST_ITEM_TV(item2), ic)) { return false; } } @@ -1823,7 +1878,7 @@ char *callback_to_string(Callback *cb, Arena *arena) snprintf(msg, msglen, "<vim partial: %s>", cb->data.partial->pt_name); break; default: - *msg = '\0'; + *msg = NUL; break; } return msg; @@ -2678,8 +2733,9 @@ void tv_dict_extend(dict_T *const d1, dict_T *const d2, const char *const action /// @param[in] d1 First dictionary. /// @param[in] d2 Second dictionary. /// @param[in] ic True if case is to be ignored. -/// @param[in] recursive True when used recursively. -bool tv_dict_equal(dict_T *const d1, dict_T *const d2, const bool ic, const bool recursive) +/// +/// @return True if dictionaries are equal, false otherwise. +bool tv_dict_equal(dict_T *const d1, dict_T *const d2, const bool ic) FUNC_ATTR_WARN_UNUSED_RESULT { if (d1 == d2) { @@ -2701,7 +2757,7 @@ bool tv_dict_equal(dict_T *const d1, dict_T *const d2, const bool ic, const bool if (di2 == NULL) { return false; } - if (!tv_equal(&di1->di_tv, &di2->di_tv, ic, recursive)) { + if (!tv_equal(&di1->di_tv, &di2->di_tv, ic)) { return false; } }); @@ -3063,8 +3119,7 @@ void f_blob2list(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// list2blob() function void f_list2blob(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - tv_blob_alloc_ret(rettv); - blob_T *const blob = rettv->vval.v_blob; + blob_T *blob = tv_blob_alloc_ret(rettv); if (tv_check_for_list_arg(argvars, 0) == FAIL) { return; @@ -3135,49 +3190,45 @@ void tv_dict_alloc_ret(typval_T *const ret_tv) /// Turn a dictionary into a list /// -/// @param[in] tv Dictionary to convert. Is checked for actually being +/// @param[in] argvars Arguments to items(). The first argument is check for being /// a dictionary, will give an error if not. /// @param[out] rettv Location where result will be saved. /// @param[in] what What to save in rettv. -static void tv_dict_list(typval_T *const tv, typval_T *const rettv, const DictListType what) +static void tv_dict2list(typval_T *const argvars, typval_T *const rettv, const DictListType what) { - if (tv->v_type != VAR_DICT) { - emsg(_(e_dictreq)); + if ((what == kDict2ListItems + ? tv_check_for_string_or_list_or_dict_arg(argvars, 0) + : tv_check_for_dict_arg(argvars, 0)) == FAIL) { + tv_list_alloc_ret(rettv, 0); return; } - tv_list_alloc_ret(rettv, tv_dict_len(tv->vval.v_dict)); - if (tv->vval.v_dict == NULL) { + dict_T *d = argvars[0].vval.v_dict; + tv_list_alloc_ret(rettv, tv_dict_len(d)); + if (d == NULL) { // NULL dict behaves like an empty dict return; } - TV_DICT_ITER(tv->vval.v_dict, di, { + TV_DICT_ITER(d, di, { typval_T tv_item = { .v_lock = VAR_UNLOCKED }; switch (what) { - case kDictListKeys: + case kDict2ListKeys: tv_item.v_type = VAR_STRING; tv_item.vval.v_string = xstrdup(di->di_key); break; - case kDictListValues: + case kDict2ListValues: tv_copy(&di->di_tv, &tv_item); break; - case kDictListItems: { + case kDict2ListItems: { // items() list_T *const sub_l = tv_list_alloc(2); tv_item.v_type = VAR_LIST; tv_item.vval.v_list = sub_l; tv_list_ref(sub_l); - - tv_list_append_owned_tv(sub_l, (typval_T) { - .v_type = VAR_STRING, - .v_lock = VAR_UNLOCKED, - .vval.v_string = xstrdup(di->di_key), - }); - + tv_list_append_string(sub_l, di->di_key, -1); tv_list_append_tv(sub_l, &di->di_tv); - break; } } @@ -3189,19 +3240,25 @@ static void tv_dict_list(typval_T *const tv, typval_T *const rettv, const DictLi /// "items(dict)" function void f_items(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - tv_dict_list(argvars, rettv, 2); + if (argvars[0].v_type == VAR_STRING) { + tv_string2items(argvars, rettv); + } else if (argvars[0].v_type == VAR_LIST) { + tv_list2items(argvars, rettv); + } else { + tv_dict2list(argvars, rettv, kDict2ListItems); + } } /// "keys()" function void f_keys(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - tv_dict_list(argvars, rettv, 0); + tv_dict2list(argvars, rettv, kDict2ListKeys); } /// "values(dict)" function void f_values(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - tv_dict_list(argvars, rettv, 1); + tv_dict2list(argvars, rettv, kDict2ListValues); } /// "has_key()" function @@ -3251,11 +3308,12 @@ void tv_dict_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg) /// Also sets reference count. /// /// @param[out] ret_tv Structure where blob is saved. -void tv_blob_alloc_ret(typval_T *const ret_tv) +blob_T *tv_blob_alloc_ret(typval_T *const ret_tv) FUNC_ATTR_NONNULL_ALL { blob_T *const b = tv_blob_alloc(); tv_blob_set_ret(ret_tv, b); + return b; } /// Copy a blob typval to a different typval. @@ -3283,6 +3341,7 @@ void tv_blob_copy(blob_T *const from, typval_T *const to) //{{{3 Clear #define TYPVAL_ENCODE_ALLOW_SPECIALS false +#define TYPVAL_ENCODE_CHECK_BEFORE #define TYPVAL_ENCODE_CONV_NIL(tv) \ do { \ @@ -3499,6 +3558,7 @@ static inline void _nothing_conv_dict_end(typval_T *const tv, dict_T **const dic #undef TYPVAL_ENCODE_FIRST_ARG_NAME #undef TYPVAL_ENCODE_ALLOW_SPECIALS +#undef TYPVAL_ENCODE_CHECK_BEFORE #undef TYPVAL_ENCODE_CONV_NIL #undef TYPVAL_ENCODE_CONV_BOOL #undef TYPVAL_ENCODE_CONV_NUMBER @@ -3835,10 +3895,9 @@ static int tv_equal_recurse_limit; /// @param[in] tv1 First value to compare. /// @param[in] tv2 Second value to compare. /// @param[in] ic True if case is to be ignored. -/// @param[in] recursive True when used recursively. /// /// @return true if values are equal. -bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic, const bool recursive) +bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { // TODO(ZyX-I): Make this not recursive @@ -3854,7 +3913,7 @@ bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic, const boo // Reduce the limit every time running into it. That should work fine for // deeply linked structures that are not recursively linked and catch // recursiveness quickly. - if (!recursive) { + if (recursive_cnt == 0) { tv_equal_recurse_limit = 1000; } if (recursive_cnt >= tv_equal_recurse_limit) { @@ -3865,15 +3924,13 @@ bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic, const boo switch (tv1->v_type) { case VAR_LIST: { recursive_cnt++; - const bool r = tv_list_equal(tv1->vval.v_list, tv2->vval.v_list, ic, - true); + const bool r = tv_list_equal(tv1->vval.v_list, tv2->vval.v_list, ic); recursive_cnt--; return r; } case VAR_DICT: { recursive_cnt++; - const bool r = tv_dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic, - true); + const bool r = tv_dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic); recursive_cnt--; return r; } @@ -4152,6 +4209,29 @@ linenr_T tv_get_lnum(const typval_T *const tv) return lnum; } +/// Get the line number from Vimscript object +/// +/// @note Unlike tv_get_lnum(), this one supports only "$" special string. +/// +/// @param[in] tv Object to get value from. Is expected to be a number or +/// a special string "$". +/// @param[in] buf Buffer to take last line number from in case tv is "$". May +/// be NULL, in this case "$" results in zero return. +/// +/// @return Line number or 0 in case of error. +linenr_T tv_get_lnum_buf(const typval_T *const tv, const buf_T *const buf) + FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT +{ + if (tv->v_type == VAR_STRING + && tv->vval.v_string != NULL + && tv->vval.v_string[0] == '$' + && tv->vval.v_string[1] == NUL + && buf != NULL) { + return buf->b_ml.ml_line_count; + } + return (linenr_T)tv_get_number_chk(tv, NULL); +} + /// Get the floating-point value of a Vimscript object /// /// Raises an error if object is not number or floating-point. @@ -4399,6 +4479,19 @@ int tv_check_for_opt_string_or_list_arg(const typval_T *const args, const int id || tv_check_for_string_or_list_arg(args, idx) != FAIL) ? OK : FAIL; } +/// Give an error and return FAIL unless "args[idx]" is a string or a list or a dict +int tv_check_for_string_or_list_or_dict_arg(const typval_T *const args, const int idx) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE +{ + if (args[idx].v_type != VAR_STRING + && args[idx].v_type != VAR_LIST + && args[idx].v_type != VAR_DICT) { + semsg(_(e_string_list_or_dict_required_for_argument_nr), idx + 1); + return FAIL; + } + return OK; +} + /// Give an error and return FAIL unless "args[idx]" is a string /// or a function reference. int tv_check_for_string_or_func_arg(const typval_T *const args, const int idx) diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index f9ebd2f778..ff70eadaaa 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -7,7 +7,6 @@ #include <string.h> #include "nvim/eval/typval_defs.h" // IWYU pragma: keep -#include "nvim/func_attr.h" #include "nvim/gettext_defs.h" #include "nvim/hashtab.h" #include "nvim/lib/queue_defs.h" @@ -16,6 +15,10 @@ #include "nvim/message.h" #include "nvim/types_defs.h" +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "eval/typval.h.inline.generated.h" +#endif + // In a hashtab item "hi_key" points to "di_key" in a dictitem. // This avoids adding a pointer to the hashtab item. @@ -23,15 +26,13 @@ #define TV_DICT_HI2DI(hi) \ ((dictitem_T *)((hi)->hi_key - offsetof(dictitem_T, di_key))) -static inline void tv_list_ref(list_T *l) - REAL_FATTR_ALWAYS_INLINE; - /// Increase reference count for a given list /// /// Does nothing for NULL lists. /// /// @param[in,out] l List to modify. static inline void tv_list_ref(list_T *const l) + FUNC_ATTR_ALWAYS_INLINE { if (l == NULL) { return; @@ -39,29 +40,25 @@ static inline void tv_list_ref(list_T *const l) l->lv_refcount++; } -static inline void tv_list_set_ret(typval_T *tv, list_T *l) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ARG(1); - /// Set a list as the return value. Increments the reference count. /// /// @param[out] tv Object to receive the list /// @param[in,out] l List to pass to the object static inline void tv_list_set_ret(typval_T *const tv, list_T *const l) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(1) { tv->v_type = VAR_LIST; tv->vval.v_list = l; tv_list_ref(l); } -static inline VarLockStatus tv_list_locked(const list_T *l) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Get list lock status /// /// Returns VAR_FIXED for NULL lists. /// /// @param[in] l List to check. static inline VarLockStatus tv_list_locked(const list_T *const l) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (l == NULL) { return VAR_FIXED; @@ -84,9 +81,6 @@ static inline void tv_list_set_lock(list_T *const l, const VarLockStatus lock) l->lv_lock = lock; } -static inline void tv_list_set_copyid(list_T *l, int copyid) - REAL_FATTR_NONNULL_ALL; - /// Set list copyID /// /// Does not expect NULL list, be careful. @@ -94,17 +88,16 @@ static inline void tv_list_set_copyid(list_T *l, int copyid) /// @param[out] l List to modify. /// @param[in] copyid New copyID. static inline void tv_list_set_copyid(list_T *const l, const int copyid) + FUNC_ATTR_NONNULL_ALL { l->lv_copyID = copyid; } -static inline int tv_list_len(const list_T *l) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Get the number of items in a list /// /// @param[in] l List to check. static inline int tv_list_len(const list_T *const l) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (l == NULL) { return 0; @@ -112,22 +105,17 @@ static inline int tv_list_len(const list_T *const l) return l->lv_len; } -static inline int tv_list_copyid(const list_T *l) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL; - /// Get list copyID /// /// Does not expect NULL list, be careful. /// /// @param[in] l List to check. static inline int tv_list_copyid(const list_T *const l) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { return l->lv_copyID; } -static inline list_T *tv_list_latest_copy(const list_T *l) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL; - /// Get latest list copy /// /// Gets lv_copylist field assigned by tv_list_copy() earlier. @@ -136,13 +124,11 @@ static inline list_T *tv_list_latest_copy(const list_T *l) /// /// @param[in] l List to check. static inline list_T *tv_list_latest_copy(const list_T *const l) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { return l->lv_copylist; } -static inline int tv_list_uidx(const list_T *l, int n) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Normalize index: that is, return either -1 or non-negative index /// /// @param[in] l List to index. Used to get length. @@ -150,6 +136,7 @@ static inline int tv_list_uidx(const list_T *l, int n) /// /// @return -1 or list index in range [0, tv_list_len(l)). static inline int tv_list_uidx(const list_T *const l, int n) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { // Negative index is relative to the end. if (n < 0) { @@ -163,9 +150,6 @@ static inline int tv_list_uidx(const list_T *const l, int n) return n; } -static inline bool tv_list_has_watchers(const list_T *l) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Check whether list has watchers /// /// E.g. is referenced by a :for loop. @@ -174,19 +158,18 @@ static inline bool tv_list_has_watchers(const list_T *l) /// /// @return true if there are watchers, false otherwise. static inline bool tv_list_has_watchers(const list_T *const l) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { return l && l->lv_watch; } -static inline listitem_T *tv_list_first(const list_T *l) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Get first list item /// /// @param[in] l List to get item from. /// /// @return List item or NULL in case of an empty list. static inline listitem_T *tv_list_first(const list_T *const l) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (l == NULL) { return NULL; @@ -194,15 +177,13 @@ static inline listitem_T *tv_list_first(const list_T *const l) return l->lv_first; } -static inline listitem_T *tv_list_last(const list_T *l) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Get last list item /// /// @param[in] l List to get item from. /// /// @return List item or NULL in case of an empty list. static inline listitem_T *tv_list_last(const list_T *const l) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (l == NULL) { return NULL; @@ -210,14 +191,12 @@ static inline listitem_T *tv_list_last(const list_T *const l) return l->lv_last; } -static inline void tv_dict_set_ret(typval_T *tv, dict_T *d) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ARG(1); - /// Set a dictionary as the return value /// /// @param[out] tv Object to receive the dictionary /// @param[in,out] d Dictionary to pass to the object static inline void tv_dict_set_ret(typval_T *const tv, dict_T *const d) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(1) { tv->v_type = VAR_DICT; tv->vval.v_dict = d; @@ -226,13 +205,11 @@ static inline void tv_dict_set_ret(typval_T *const tv, dict_T *const d) } } -static inline long tv_dict_len(const dict_T *d) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Get the number of items in a Dictionary /// /// @param[in] d Dictionary to check. static inline long tv_dict_len(const dict_T *const d) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (d == NULL) { return 0; @@ -240,22 +217,17 @@ static inline long tv_dict_len(const dict_T *const d) return (long)d->dv_hashtab.ht_used; } -static inline bool tv_dict_is_watched(const dict_T *d) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Check if dictionary is watched /// /// @param[in] d Dictionary to check. /// /// @return true if there is at least one watcher. static inline bool tv_dict_is_watched(const dict_T *const d) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { return d && !QUEUE_EMPTY(&d->watchers); } -static inline void tv_blob_set_ret(typval_T *tv, blob_T *b) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ARG(1); - /// Set a blob as the return value. /// /// Increments the reference count. @@ -263,6 +235,7 @@ static inline void tv_blob_set_ret(typval_T *tv, blob_T *b) /// @param[out] tv Object to receive the blob. /// @param[in,out] b Blob to pass to the object. static inline void tv_blob_set_ret(typval_T *const tv, blob_T *const b) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(1) { tv->v_type = VAR_BLOB; tv->vval.v_blob = b; @@ -271,13 +244,11 @@ static inline void tv_blob_set_ret(typval_T *const tv, blob_T *const b) } } -static inline int tv_blob_len(const blob_T *b) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Get the length of the data in the blob, in bytes. /// /// @param[in] b Blob to check. static inline int tv_blob_len(const blob_T *const b) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (b == NULL) { return 0; @@ -285,9 +256,6 @@ static inline int tv_blob_len(const blob_T *const b) return b->bv_ga.ga_len; } -static inline uint8_t tv_blob_get(const blob_T *b, int idx) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT; - /// Get the byte at index `idx` in the blob. /// /// @param[in] b Blob to index. Cannot be NULL. @@ -295,19 +263,18 @@ static inline uint8_t tv_blob_get(const blob_T *b, int idx) /// /// @return Byte value at the given index. static inline uint8_t tv_blob_get(const blob_T *const b, int idx) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { return ((uint8_t *)b->bv_ga.ga_data)[idx]; } -static inline void tv_blob_set(blob_T *blob, int idx, uint8_t c) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL; - /// Store the byte `c` at index `idx` in the blob. /// /// @param[in] b Blob to index. Cannot be NULL. /// @param[in] idx Index in a blob. Must be valid. /// @param[in] c Value to store. static inline void tv_blob_set(blob_T *const blob, int idx, uint8_t c) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL { ((uint8_t *)blob->bv_ga.ga_data)[idx] = c; } @@ -417,9 +384,6 @@ extern bool tv_in_free_unref_items; } \ }) -static inline bool tv_get_float_chk(const typval_T *tv, float_T *ret_f) - REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT; - /// Get the float value /// /// Raises an error if object is not number or floating-point. @@ -429,6 +393,7 @@ static inline bool tv_get_float_chk(const typval_T *tv, float_T *ret_f) /// /// @return true in case of success, false if tv is not a number or float. static inline bool tv_get_float_chk(const typval_T *const tv, float_T *const ret_f) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { if (tv->v_type == VAR_FLOAT) { *ret_f = tv->vval.v_float; @@ -442,22 +407,17 @@ static inline bool tv_get_float_chk(const typval_T *const tv, float_T *const ret return false; } -static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL REAL_FATTR_NONNULL_RET - REAL_FATTR_NO_SANITIZE_ADDRESS REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Compute the `DictWatcher` address from a QUEUE node. /// /// This only exists for .asan-blacklist (ASAN doesn't handle QUEUE_DATA pointer /// arithmetic). static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET + FUNC_ATTR_NO_SANITIZE_ADDRESS FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { return QUEUE_DATA(q, DictWatcher, node); } -static inline bool tv_is_func(typval_T tv) - REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST; - /// Check whether given typval_T contains a function /// /// That is, whether it contains VAR_FUNC or VAR_PARTIAL. @@ -466,6 +426,7 @@ static inline bool tv_is_func(typval_T tv) /// /// @return True if it is a function or a partial, false otherwise. static inline bool tv_is_func(const typval_T tv) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_CONST { return tv.v_type == VAR_FUNC || tv.v_type == VAR_PARTIAL; } diff --git a/src/nvim/eval/typval_defs.h b/src/nvim/eval/typval_defs.h index e88e6a222a..1ec7631c4b 100644 --- a/src/nvim/eval/typval_defs.h +++ b/src/nvim/eval/typval_defs.h @@ -109,7 +109,7 @@ typedef enum { VAR_STRING, ///< String, .v_string is used. VAR_FUNC, ///< Function reference, .v_string is used as function name. VAR_LIST, ///< List, .v_list is used. - VAR_DICT, ///< Dictionary, .v_dict is used. + VAR_DICT, ///< Dict, .v_dict is used. VAR_FLOAT, ///< Floating-point value, .v_float is used. VAR_BOOL, ///< true, false VAR_SPECIAL, ///< Special value (null), .v_special is used. @@ -141,7 +141,7 @@ typedef struct { float_T v_float; ///< Floating-point number, for VAR_FLOAT. char *v_string; ///< String, for VAR_STRING and VAR_FUNC, can be NULL. list_T *v_list; ///< List for VAR_LIST, can be NULL. - dict_T *v_dict; ///< Dictionary for VAR_DICT, can be NULL. + dict_T *v_dict; ///< Dict for VAR_DICT, can be NULL. partial_T *v_partial; ///< Closure: function with args. blob_T *v_blob; ///< Blob for VAR_BLOB, can be NULL. } vval; ///< Actual value. @@ -259,7 +259,7 @@ struct dictvar_S { dict_T *dv_copydict; ///< Copied dict used by deepcopy(). dict_T *dv_used_next; ///< Next dictionary in used dictionaries list. dict_T *dv_used_prev; ///< Previous dictionary in used dictionaries list. - QUEUE watchers; ///< Dictionary key watchers set by user code. + QUEUE watchers; ///< Dict key watchers set by user code. LuaRef lua_table_ref; }; diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h index c0cd0ce557..c0e994562c 100644 --- a/src/nvim/eval/typval_encode.c.h +++ b/src/nvim/eval/typval_encode.c.h @@ -6,6 +6,11 @@ /// something else. For these macros to work the following macros must be /// defined: +/// @def TYPVAL_ENCODE_CHECK_BEFORE +/// @brief Macro used before any specific CONV function +/// +/// can be used for a common check, like flushing a buffer if necessary + /// @def TYPVAL_ENCODE_CONV_NIL /// @brief Macros used to convert NIL value /// @@ -168,8 +173,7 @@ /// point to a special dictionary. /// @param dict Converted dictionary, lvalue or #TYPVAL_ENCODE_NODICT_VAR /// (for dictionaries represented as special lists). -/// @param len Dictionary length. Is an expression which evaluates to an -/// integer. +/// @param len Dict length. Is an expression which evaluates to an integer. /// @def TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START /// @brief Macros used after pushing dictionary onto the stack @@ -323,6 +327,7 @@ static int TYPVAL_ENCODE_CONVERT_ONE_VALUE( TYPVAL_ENCODE_FIRST_ARG_TYPE TYPVAL_ENCODE_FIRST_ARG_NAME, MPConvStack *const mpstack, MPConvStackVal *const cur_mpsv, typval_T *const tv, const int copyID, const char *const objname) { + TYPVAL_ENCODE_CHECK_BEFORE; switch (tv->v_type) { case VAR_STRING: TYPVAL_ENCODE_CONV_STRING(tv, tv->vval.v_string, tv_strlen(tv)); @@ -420,6 +425,7 @@ static int TYPVAL_ENCODE_CONVERT_ONE_VALUE( break; } } + TYPVAL_ENCODE_CHECK_BEFORE; if (i == ARRAY_SIZE(eval_msgpack_type_lists)) { goto _convert_one_value_regular_dict; } @@ -494,9 +500,7 @@ static int TYPVAL_ENCODE_CONVERT_ONE_VALUE( } TYPVAL_ENCODE_CONV_FLOAT(tv, val_di->di_tv.vval.v_float); break; - case kMPString: - case kMPBinary: { - const bool is_string = ((MessagePackType)i == kMPString); + case kMPString: { if (val_di->di_tv.v_type != VAR_LIST) { goto _convert_one_value_regular_dict; } @@ -506,11 +510,7 @@ static int TYPVAL_ENCODE_CONVERT_ONE_VALUE( &buf)) { goto _convert_one_value_regular_dict; } - if (is_string) { - TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len); - } else { - TYPVAL_ENCODE_CONV_STRING(tv, buf, len); - } + TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len); xfree(buf); break; } diff --git a/src/nvim/eval/typval_encode.h b/src/nvim/eval/typval_encode.h index a6e0bd4b2b..8547783213 100644 --- a/src/nvim/eval/typval_encode.h +++ b/src/nvim/eval/typval_encode.h @@ -11,7 +11,10 @@ #include "klib/kvec.h" #include "nvim/eval/typval_defs.h" -#include "nvim/func_attr.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "eval/typval_encode.h.inline.generated.h" +#endif /// Type of the stack entry typedef enum { @@ -62,10 +65,6 @@ typedef struct { /// Stack used to convert Vimscript values to messagepack. typedef kvec_withinit_t(MPConvStackVal, 8) MPConvStack; -static inline size_t tv_strlen(const typval_T *tv) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT - REAL_FATTR_NONNULL_ALL; - /// Length of the string stored in typval_T /// /// @param[in] tv String for which to compute length for. Must be typval_T @@ -74,6 +73,8 @@ static inline size_t tv_strlen(const typval_T *tv) /// @return Length of the string stored in typval_T, including 0 for NULL /// string. static inline size_t tv_strlen(const typval_T *const tv) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT + FUNC_ATTR_NONNULL_ALL { assert(tv->v_type == VAR_STRING); return (tv->vval.v_string == NULL ? 0 : strlen(tv->vval.v_string)); diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 0ec07399b4..0050a77fe3 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -15,6 +15,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/debugger.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/funcs.h" @@ -264,7 +265,7 @@ static void set_ufunc_name(ufunc_T *fp, char *name) if ((uint8_t)name[0] == K_SPECIAL) { fp->uf_name_exp = xmalloc(strlen(name) + 3); STRCPY(fp->uf_name_exp, "<SNR>"); - STRCAT(fp->uf_name_exp, fp->uf_name + 3); + strcat(fp->uf_name_exp, fp->uf_name + 3); } } @@ -641,6 +642,44 @@ static char *fname_trans_sid(const char *const name, char *const fname_buf, char return fname; } +int get_func_arity(const char *name, int *required, int *optional, bool *varargs) +{ + int argcount = 0; + int min_argcount = 0; + + const EvalFuncDef *fdef = find_internal_func(name); + if (fdef != NULL) { + argcount = fdef->max_argc; + min_argcount = fdef->min_argc; + *varargs = false; + } else { + char fname_buf[FLEN_FIXED + 1]; + char *tofree = NULL; + int error = FCERR_NONE; + + // May need to translate <SNR>123_ to K_SNR. + char *fname = fname_trans_sid(name, fname_buf, &tofree, &error); + ufunc_T *ufunc = NULL; + if (error == FCERR_NONE) { + ufunc = find_func(fname); + } + xfree(tofree); + + if (ufunc == NULL) { + return FAIL; + } + + argcount = ufunc->uf_args.ga_len; + min_argcount = ufunc->uf_args.ga_len - ufunc->uf_def_args.ga_len; + *varargs = ufunc->uf_varargs; + } + + *required = min_argcount; + *optional = argcount - min_argcount; + + return OK; +} + /// Find a function by name, return pointer to it in ufuncs. /// /// @return NULL for unknown function. @@ -916,7 +955,7 @@ void remove_funccal(void) /// @param[out] rettv Return value. /// @param[in] firstline First line of range. /// @param[in] lastline Last line of range. -/// @param selfdict Dictionary for "self" for dictionary functions. +/// @param selfdict Dict for "self" for dictionary functions. void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, linenr_T firstline, linenr_T lastline, dict_T *selfdict) FUNC_ATTR_NONNULL_ARG(1, 3, 4) @@ -1528,12 +1567,12 @@ varnumber_T callback_call_retnr(Callback *callback, int argcount, typval_T *argv /// Give an error message for the result of a function. /// Nothing if "error" is FCERR_NONE. -static void user_func_error(int error, const char *name, funcexe_T *funcexe) +static void user_func_error(int error, const char *name, bool found_var) FUNC_ATTR_NONNULL_ARG(2) { switch (error) { case FCERR_UNKNOWN: - if (funcexe->fe_found_var) { + if (found_var) { semsg(_(e_not_callable_type_str), name); } else { emsg_funcname(e_unknown_function_str, name); @@ -1653,12 +1692,9 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t } if (error == FCERR_NONE && funcexe->fe_evaluate) { - char *rfname = fname; - - // Ignore "g:" before a function name. - if (fp == NULL && fname[0] == 'g' && fname[1] == ':') { - rfname = fname + 2; - } + // Skip "g:" before a function name. + bool is_global = fp == NULL && fname[0] == 'g' && fname[1] == ':'; + char *rfname = is_global ? fname + 2 : fname; rettv->v_type = VAR_NUMBER; // default rettv is number zero rettv->vval.v_number = 0; @@ -1732,7 +1768,7 @@ theend: // Report an error unless the argument evaluation or function call has been // cancelled due to an aborting error, an interrupt, or an exception. if (!aborting()) { - user_func_error(error, (name != NULL) ? name : funcname, funcexe); + user_func_error(error, (name != NULL) ? name : funcname, funcexe->fe_found_var); } // clear the copies made from the partial @@ -1746,6 +1782,70 @@ theend: return ret; } +int call_simple_luafunc(const char *funcname, size_t len, typval_T *rettv) + FUNC_ATTR_NONNULL_ALL +{ + rettv->v_type = VAR_NUMBER; // default rettv is number zero + rettv->vval.v_number = 0; + + typval_T argvars[1]; + argvars[0].v_type = VAR_UNKNOWN; + nlua_typval_call(funcname, len, argvars, 0, rettv); + return OK; +} + +/// Call a function without arguments, partial or dict. +/// This is like call_func() when the call is only "FuncName()". +/// To be used by "expr" options. +/// Returns NOTDONE when the function could not be found. +/// +/// @param funcname name of the function +/// @param len length of "name" +/// @param rettv return value goes here +int call_simple_func(const char *funcname, size_t len, typval_T *rettv) + FUNC_ATTR_NONNULL_ALL +{ + int ret = FAIL; + + rettv->v_type = VAR_NUMBER; // default rettv is number zero + rettv->vval.v_number = 0; + + // Make a copy of the name, an option can be changed in the function. + char *name = xstrnsave(funcname, len); + + int error = FCERR_NONE; + char *tofree = NULL; + char fname_buf[FLEN_FIXED + 1]; + char *fname = fname_trans_sid(name, fname_buf, &tofree, &error); + + // Skip "g:" before a function name. + bool is_global = fname[0] == 'g' && fname[1] == ':'; + char *rfname = is_global ? fname + 2 : fname; + + ufunc_T *fp = find_func(rfname); + if (fp == NULL) { + ret = NOTDONE; + } else if (fp != NULL && (fp->uf_flags & FC_DELETED)) { + error = FCERR_DELETED; + } else if (fp != NULL) { + typval_T argvars[1]; + argvars[0].v_type = VAR_UNKNOWN; + funcexe_T funcexe = FUNCEXE_INIT; + funcexe.fe_evaluate = true; + + error = call_user_func_check(fp, 0, argvars, rettv, &funcexe, NULL); + if (error == FCERR_NONE) { + ret = OK; + } + } + + user_func_error(error, name, false); + xfree(tofree); + xfree(name); + + return ret; +} + char *printable_func_name(ufunc_T *fp) { return fp->uf_name_exp != NULL ? fp->uf_name_exp : fp->uf_name; @@ -1828,7 +1928,7 @@ static int list_func_head(ufunc_T *fp, bool indent, bool force) } /// Get a function name, translating "<SID>" and "<SNR>". -/// Also handles a Funcref in a List or Dictionary. +/// Also handles a Funcref in a List or Dict. /// flags: /// TFN_INT: internal function name OK /// TFN_QUIET: be quiet @@ -2051,7 +2151,7 @@ char *get_scriptlocal_funcname(char *funcname) if (strncmp(funcname, "s:", 2) != 0 && strncmp(funcname, "<SID>", 5) != 0) { - // The function name is not a script-local function name + // The function name does not have a script-local prefix. return NULL; } @@ -2067,7 +2167,7 @@ char *get_scriptlocal_funcname(char *funcname) const int off = *funcname == 's' ? 2 : 5; char *newname = xmalloc(strlen(sid_buf) + strlen(funcname + off) + 1); STRCPY(newname, sid_buf); - STRCAT(newname, funcname + off); + strcat(newname, funcname + off); return newname; } @@ -3148,7 +3248,7 @@ static int ex_call_inner(exarg_T *eap, char *name, char **arg, char *startarg, break; } - // Handle a function returning a Funcref, Dictionary or List. + // Handle a function returning a Funcref, Dict or List. if (handle_subscript((const char **)arg, &rettv, &EVALARG_EVALUATE, true) == FAIL) { failed = true; break; @@ -3215,7 +3315,7 @@ static int ex_defer_inner(char *name, char **arg, const partial_T *const partial if (ufunc != NULL) { int error = check_user_func_argcount(ufunc, argcount); if (error != FCERR_UNKNOWN) { - user_func_error(error, name, NULL); + user_func_error(error, name, false); r = FAIL; } } diff --git a/src/nvim/eval/userfunc.h b/src/nvim/eval/userfunc.h index b3488b15a7..0a27403a4b 100644 --- a/src/nvim/eval/userfunc.h +++ b/src/nvim/eval/userfunc.h @@ -32,9 +32,9 @@ /// Structure used by trans_function_name() typedef struct { - dict_T *fd_dict; ///< Dictionary used. - char *fd_newkey; ///< New key in "dict" in allocated memory. - dictitem_T *fd_di; ///< Dictionary item used. + dict_T *fd_dict; ///< Dict used. + char *fd_newkey; ///< New key in "dict" in allocated memory. + dictitem_T *fd_di; ///< Dict item used. } funcdict_T; typedef struct funccal_entry funccal_entry_T; @@ -69,7 +69,7 @@ typedef struct { bool *fe_doesrange; ///< [out] if not NULL: function handled range bool fe_evaluate; ///< actually evaluate expressions partial_T *fe_partial; ///< for extra arguments - dict_T *fe_selfdict; ///< Dictionary for "self" + dict_T *fe_selfdict; ///< Dict for "self" typval_T *fe_basetv; ///< base for base->method() bool fe_found_var; ///< if the function is not found then give an ///< error that a variable is not callable. diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index 2eca209ea3..0e0088bfad 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -15,6 +15,7 @@ #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/funcs.h" @@ -88,7 +89,7 @@ char *eval_one_expr_in_str(char *p, garray_T *gap, bool evaluate) } if (evaluate) { *block_end = NUL; - char *expr_val = eval_to_string(block_start, false); + char *expr_val = eval_to_string(block_start, false, false); *block_end = '}'; if (expr_val == NULL) { return NULL; @@ -104,7 +105,7 @@ char *eval_one_expr_in_str(char *p, garray_T *gap, bool evaluate) /// string in allocated memory. "{{" is reduced to "{" and "}}" to "}". /// Used for a heredoc assignment. /// Returns NULL for an error. -char *eval_all_expr_in_str(char *str) +static char *eval_all_expr_in_str(char *str) { garray_T ga; ga_init(&ga, 1, 80); @@ -1112,7 +1113,7 @@ static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_ // unlet a List item. tv_list_item_remove(lp->ll_list, lp->ll_li); } else { - // unlet a Dictionary item. + // unlet a Dict item. dict_T *d = lp->ll_dict; assert(d != NULL); dictitem_T *di = lp->ll_di; @@ -1287,7 +1288,7 @@ static int do_lock_var(lval_T *lp, char *name_end FUNC_ATTR_UNUSED, exarg_T *eap // (un)lock a List item. tv_item_lock(TV_LIST_ITEM_TV(lp->ll_li), deep, lock, false); } else { - // (un)lock a Dictionary item. + // (un)lock a Dict item. tv_item_lock(&lp->ll_di->di_tv, deep, lock, false); } diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c index 68de40f983..86495f1cb6 100644 --- a/src/nvim/eval/window.c +++ b/src/nvim/eval/window.c @@ -10,6 +10,7 @@ #include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/cursor.h" +#include "nvim/errors.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -271,7 +272,7 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar) // if count is not specified, default to 1 count = 1; } - if (endp != NULL && *endp != '\0') { + if (endp != NULL && *endp != NUL) { if (strequal(endp, "j")) { twin = win_vert_neighbor(tp, twin, false, count); } else if (strequal(endp, "k")) { diff --git a/src/nvim/eval_defs.h b/src/nvim/eval_defs.h index 4bbebb14f5..7adea6dfa9 100644 --- a/src/nvim/eval_defs.h +++ b/src/nvim/eval_defs.h @@ -9,7 +9,6 @@ typedef enum { kMPInteger, kMPFloat, kMPString, - kMPBinary, kMPArray, kMPMap, kMPExt, diff --git a/src/nvim/event/defs.h b/src/nvim/event/defs.h index 9b7d8708be..20724f9263 100644 --- a/src/nvim/event/defs.h +++ b/src/nvim/event/defs.h @@ -6,7 +6,6 @@ #include <uv.h> #include "nvim/eval/typval_defs.h" -#include "nvim/rbuffer_defs.h" #include "nvim/types_defs.h" enum { EVENT_HANDLER_MAX_ARGC = 10, }; @@ -55,14 +54,17 @@ struct wbuffer { }; typedef struct stream Stream; -/// Type of function called when the Stream buffer is filled with data +typedef struct rstream RStream; +/// Type of function called when the RStream buffer is filled with data /// /// @param stream The Stream instance -/// @param buf The associated RBuffer instance +/// @param read_data data that was read /// @param count Number of bytes that was read. /// @param data User-defined data /// @param eof If the stream reached EOF. -typedef void (*stream_read_cb)(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof); +/// @return number of bytes which were consumed +typedef size_t (*stream_read_cb)(RStream *stream, const char *read_data, size_t count, void *data, + bool eof); /// Type of function called when the Stream has information about a write /// request. @@ -71,11 +73,11 @@ typedef void (*stream_read_cb)(Stream *stream, RBuffer *buf, size_t count, void /// @param data User-defined data /// @param status 0 on success, anything else indicates failure typedef void (*stream_write_cb)(Stream *stream, void *data, int status); + typedef void (*stream_close_cb)(Stream *stream, void *data); struct stream { bool closed; - bool did_eof; union { uv_pipe_t pipe; uv_tcp_t tcp; @@ -84,21 +86,33 @@ struct stream { uv_tty_t tty; #endif } uv; - uv_stream_t *uvstream; - uv_buf_t uvbuf; - RBuffer *buffer; - uv_file fd; - stream_read_cb read_cb; - stream_write_cb write_cb; + uv_stream_t *uvstream; ///< NULL when the stream is a file + uv_file fd; ///< When the stream is a file, this is its file descriptor + int64_t fpos; ///< When the stream is a file, this is the position in file void *cb_data; stream_close_cb close_cb, internal_close_cb; void *close_cb_data, *internal_data; - size_t fpos; + size_t pending_reqs; + MultiQueue *events; + + // only used for writing: + stream_write_cb write_cb; size_t curmem; size_t maxmem; - size_t pending_reqs; +}; + +struct rstream { + Stream s; + bool did_eof; + bool want_read; + bool pending_read; + bool paused_full; + char *buffer; // ARENA_BLOCK_SIZE + char *read_pos; + char *write_pos; + uv_buf_t uvbuf; + stream_read_cb read_cb; size_t num_bytes; - MultiQueue *events; }; #define ADDRESS_MAX_SIZE 256 @@ -128,29 +142,31 @@ struct socket_watcher { }; typedef enum { - kProcessTypeUv, - kProcessTypePty, -} ProcessType; + kProcTypeUv, + kProcTypePty, +} ProcType; -typedef struct process Process; -typedef void (*process_exit_cb)(Process *proc, int status, void *data); -typedef void (*internal_process_cb)(Process *proc); +/// OS process +typedef struct proc Proc; +typedef void (*proc_exit_cb)(Proc *proc, int status, void *data); +typedef void (*internal_proc_cb)(Proc *proc); -struct process { - ProcessType type; +struct proc { + ProcType type; Loop *loop; void *data; int pid, status, refcount; uint8_t exit_signal; // Signal used when killing (on Windows). - uint64_t stopped_time; // process_stop() timestamp + uint64_t stopped_time; // proc_stop() timestamp const char *cwd; char **argv; const char *exepath; dict_T *env; - Stream in, out, err; - /// Exit handler. If set, user must call process_free(). - process_exit_cb cb; - internal_process_cb internal_exit_cb, internal_close_cb; + Stream in; + RStream out, err; + /// Exit handler. If set, user must call proc_free(). + proc_exit_cb cb; + internal_proc_cb internal_exit_cb, internal_close_cb; bool closed, detach, overlapped, fwd_err; MultiQueue *events; }; diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_proc.c index f77d686c10..5b445cdda7 100644 --- a/src/nvim/event/libuv_process.c +++ b/src/nvim/event/libuv_proc.c @@ -5,9 +5,9 @@ #include "nvim/eval/typval.h" #include "nvim/event/defs.h" -#include "nvim/event/libuv_process.h" +#include "nvim/event/libuv_proc.h" #include "nvim/event/loop.h" -#include "nvim/event/process.h" +#include "nvim/event/proc.h" #include "nvim/log.h" #include "nvim/os/os.h" #include "nvim/os/os_defs.h" @@ -15,15 +15,15 @@ #include "nvim/ui_client.h" #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "event/libuv_process.c.generated.h" +# include "event/libuv_proc.c.generated.h" #endif /// @returns zero on success, or negative error code -int libuv_process_spawn(LibuvProcess *uvproc) +int libuv_proc_spawn(LibuvProc *uvproc) FUNC_ATTR_NONNULL_ALL { - Process *proc = (Process *)uvproc; - uvproc->uvopts.file = process_get_exepath(proc); + Proc *proc = (Proc *)uvproc; + uvproc->uvopts.file = proc_get_exepath(proc); uvproc->uvopts.args = proc->argv; uvproc->uvopts.flags = UV_PROCESS_WINDOWS_HIDE; #ifdef MSWIN @@ -70,19 +70,19 @@ int libuv_process_spawn(LibuvProcess *uvproc) uvproc->uvstdio[0].data.stream = (uv_stream_t *)(&proc->in.uv.pipe); } - if (!proc->out.closed) { + if (!proc->out.s.closed) { uvproc->uvstdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; #ifdef MSWIN // pipe must be readable for IOCP to work on Windows. uvproc->uvstdio[1].flags |= proc->overlapped ? (UV_READABLE_PIPE | UV_OVERLAPPED_PIPE) : 0; #endif - uvproc->uvstdio[1].data.stream = (uv_stream_t *)(&proc->out.uv.pipe); + uvproc->uvstdio[1].data.stream = (uv_stream_t *)(&proc->out.s.uv.pipe); } - if (!proc->err.closed) { + if (!proc->err.s.closed) { uvproc->uvstdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; - uvproc->uvstdio[2].data.stream = (uv_stream_t *)(&proc->err.uv.pipe); + uvproc->uvstdio[2].data.stream = (uv_stream_t *)(&proc->err.s.uv.pipe); } else if (proc->fwd_err) { uvproc->uvstdio[2].flags = UV_INHERIT_FD; uvproc->uvstdio[2].data.fd = STDERR_FILENO; @@ -101,7 +101,7 @@ int libuv_process_spawn(LibuvProcess *uvproc) return status; } -void libuv_process_close(LibuvProcess *uvproc) +void libuv_proc_close(LibuvProc *uvproc) FUNC_ATTR_NONNULL_ARG(1) { uv_close((uv_handle_t *)&uvproc->uv, close_cb); @@ -109,11 +109,11 @@ void libuv_process_close(LibuvProcess *uvproc) static void close_cb(uv_handle_t *handle) { - Process *proc = handle->data; + Proc *proc = handle->data; if (proc->internal_close_cb) { proc->internal_close_cb(proc); } - LibuvProcess *uvproc = (LibuvProcess *)proc; + LibuvProc *uvproc = (LibuvProc *)proc; if (uvproc->uvopts.env) { os_free_fullenv(uvproc->uvopts.env); } @@ -121,7 +121,7 @@ static void close_cb(uv_handle_t *handle) static void exit_cb(uv_process_t *handle, int64_t status, int term_signal) { - Process *proc = handle->data; + Proc *proc = handle->data; #if defined(MSWIN) // Use stored/expected signal. term_signal = proc->exit_signal; @@ -130,10 +130,10 @@ static void exit_cb(uv_process_t *handle, int64_t status, int term_signal) proc->internal_exit_cb(proc); } -LibuvProcess libuv_process_init(Loop *loop, void *data) +LibuvProc libuv_proc_init(Loop *loop, void *data) { - LibuvProcess rv = { - .process = process_init(loop, kProcessTypeUv, data) + LibuvProc rv = { + .proc = proc_init(loop, kProcTypeUv, data) }; return rv; } diff --git a/src/nvim/event/libuv_process.h b/src/nvim/event/libuv_proc.h index 12401dbb35..3127e166c0 100644 --- a/src/nvim/event/libuv_process.h +++ b/src/nvim/event/libuv_proc.h @@ -5,12 +5,12 @@ #include "nvim/event/defs.h" typedef struct { - Process process; + Proc proc; uv_process_t uv; uv_process_options_t uvopts; uv_stdio_container_t uvstdio[4]; -} LibuvProcess; +} LibuvProc; #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "event/libuv_process.h.generated.h" +# include "event/libuv_proc.h.generated.h" #endif diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c index e1ebcecbd6..15d993cc62 100644 --- a/src/nvim/event/loop.c +++ b/src/nvim/event/loop.c @@ -20,7 +20,7 @@ void loop_init(Loop *loop, void *data) loop->recursive = 0; loop->closing = false; loop->uv.data = loop; - loop->children = kl_init(WatcherPtr); + kv_init(loop->children); loop->events = multiqueue_new_parent(loop_on_put, loop); loop->fast_events = multiqueue_new_child(loop->events); loop->thread_events = multiqueue_new_parent(NULL, NULL); @@ -187,7 +187,7 @@ bool loop_close(Loop *loop, bool wait) multiqueue_free(loop->fast_events); multiqueue_free(loop->thread_events); multiqueue_free(loop->events); - kl_destroy(WatcherPtr, loop->children); + kv_destroy(loop->children); return rv; } diff --git a/src/nvim/event/loop.h b/src/nvim/event/loop.h index 6ecc7cb781..563b254a0b 100644 --- a/src/nvim/event/loop.h +++ b/src/nvim/event/loop.h @@ -3,32 +3,26 @@ #include <stdbool.h> #include <uv.h> -#include "klib/klist.h" +#include "klib/kvec.h" #include "nvim/event/defs.h" // IWYU pragma: keep #include "nvim/types_defs.h" // IWYU pragma: keep -typedef void *WatcherPtr; - -#define _NOOP(x) -KLIST_INIT(WatcherPtr, WatcherPtr, _NOOP) - struct loop { uv_loop_t uv; MultiQueue *events; MultiQueue *thread_events; - // Immediate events: - // "Processed after exiting uv_run() (to avoid recursion), but before - // returning from loop_poll_events()." 502aee690c98 - // Practical consequence (for main_loop): these events are processed by - // state_enter()..os_inchar() - // whereas "regular" events (main_loop.events) are processed by - // state_enter()..VimState.execute() - // But state_enter()..os_inchar() can be "too early" if you want the event - // to trigger UI updates and other user-activity-related side-effects. + // Immediate events. + // - "Processed after exiting `uv_run()` (to avoid recursion), but before returning from + // `loop_poll_events()`." 502aee690c98 + // - Practical consequence (for `main_loop`): + // - these are processed by `state_enter()..input_get()` whereas "regular" events + // (`main_loop.events`) are processed by `state_enter()..VimState.execute()` + // - `state_enter()..input_get()` can be "too early" if you want the event to trigger UI + // updates and other user-activity-related side-effects. MultiQueue *fast_events; // used by process/job-control subsystem - klist_t(WatcherPtr) *children; + kvec_t(Proc *) children; uv_signal_t children_watcher; uv_timer_t children_kill_timer; diff --git a/src/nvim/event/process.c b/src/nvim/event/proc.c index 7460e92766..5ae3bd8c2d 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/proc.c @@ -3,24 +3,24 @@ #include <signal.h> #include <uv.h> -#include "klib/klist.h" -#include "nvim/event/libuv_process.h" +#include "nvim/event/libuv_proc.h" #include "nvim/event/loop.h" #include "nvim/event/multiqueue.h" -#include "nvim/event/process.h" +#include "nvim/event/proc.h" +#include "nvim/event/rstream.h" #include "nvim/event/stream.h" +#include "nvim/event/wstream.h" #include "nvim/globals.h" #include "nvim/log.h" #include "nvim/main.h" -#include "nvim/os/process.h" -#include "nvim/os/pty_process.h" +#include "nvim/os/proc.h" +#include "nvim/os/pty_proc.h" #include "nvim/os/shell.h" #include "nvim/os/time.h" -#include "nvim/rbuffer_defs.h" #include "nvim/ui_client.h" #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "event/process.c.generated.h" +# include "event/proc.c.generated.h" #endif // Time for a process to exit cleanly before we send KILL. @@ -32,13 +32,13 @@ void __gcov_flush(void); #endif -static bool process_is_tearing_down = false; +static bool proc_is_tearing_down = false; // Delay exit until handles are closed, to avoid deadlocks static int exit_need_delay = 0; /// @returns zero on success, or negative error code -int process_spawn(Process *proc, bool in, bool out, bool err) +int proc_spawn(Proc *proc, bool in, bool out, bool err) FUNC_ATTR_NONNULL_ALL { // forwarding stderr contradicts with processing it internally @@ -51,15 +51,15 @@ int process_spawn(Process *proc, bool in, bool out, bool err) } if (out) { - uv_pipe_init(&proc->loop->uv, &proc->out.uv.pipe, 0); + uv_pipe_init(&proc->loop->uv, &proc->out.s.uv.pipe, 0); } else { - proc->out.closed = true; + proc->out.s.closed = true; } if (err) { - uv_pipe_init(&proc->loop->uv, &proc->err.uv.pipe, 0); + uv_pipe_init(&proc->loop->uv, &proc->err.s.uv.pipe, 0); } else { - proc->err.closed = true; + proc->err.s.closed = true; } #ifdef USE_GCOV @@ -69,11 +69,11 @@ int process_spawn(Process *proc, bool in, bool out, bool err) int status; switch (proc->type) { - case kProcessTypeUv: - status = libuv_process_spawn((LibuvProcess *)proc); + case kProcTypeUv: + status = libuv_proc_spawn((LibuvProc *)proc); break; - case kProcessTypePty: - status = pty_process_spawn((PtyProcess *)proc); + case kProcTypePty: + status = pty_proc_spawn((PtyProc *)proc); break; } @@ -82,18 +82,18 @@ int process_spawn(Process *proc, bool in, bool out, bool err) uv_close((uv_handle_t *)&proc->in.uv.pipe, NULL); } if (out) { - uv_close((uv_handle_t *)&proc->out.uv.pipe, NULL); + uv_close((uv_handle_t *)&proc->out.s.uv.pipe, NULL); } if (err) { - uv_close((uv_handle_t *)&proc->err.uv.pipe, NULL); + uv_close((uv_handle_t *)&proc->err.s.uv.pipe, NULL); } - if (proc->type == kProcessTypeUv) { - uv_close((uv_handle_t *)&(((LibuvProcess *)proc)->uv), NULL); + if (proc->type == kProcTypeUv) { + uv_close((uv_handle_t *)&(((LibuvProc *)proc)->uv), NULL); } else { - process_close(proc); + proc_close(proc); } - process_free(proc); + proc_free(proc); proc->status = -1; return status; } @@ -101,56 +101,56 @@ int process_spawn(Process *proc, bool in, bool out, bool err) if (in) { stream_init(NULL, &proc->in, -1, (uv_stream_t *)&proc->in.uv.pipe); proc->in.internal_data = proc; - proc->in.internal_close_cb = on_process_stream_close; + proc->in.internal_close_cb = on_proc_stream_close; proc->refcount++; } if (out) { - stream_init(NULL, &proc->out, -1, (uv_stream_t *)&proc->out.uv.pipe); - proc->out.internal_data = proc; - proc->out.internal_close_cb = on_process_stream_close; + stream_init(NULL, &proc->out.s, -1, (uv_stream_t *)&proc->out.s.uv.pipe); + proc->out.s.internal_data = proc; + proc->out.s.internal_close_cb = on_proc_stream_close; proc->refcount++; } if (err) { - stream_init(NULL, &proc->err, -1, (uv_stream_t *)&proc->err.uv.pipe); - proc->err.internal_data = proc; - proc->err.internal_close_cb = on_process_stream_close; + stream_init(NULL, &proc->err.s, -1, (uv_stream_t *)&proc->err.s.uv.pipe); + proc->err.s.internal_data = proc; + proc->err.s.internal_close_cb = on_proc_stream_close; proc->refcount++; } - proc->internal_exit_cb = on_process_exit; + proc->internal_exit_cb = on_proc_exit; proc->internal_close_cb = decref; proc->refcount++; - kl_push(WatcherPtr, proc->loop->children, proc); - DLOG("new: pid=%d exepath=[%s]", proc->pid, process_get_exepath(proc)); + kv_push(proc->loop->children, proc); + DLOG("new: pid=%d exepath=[%s]", proc->pid, proc_get_exepath(proc)); return 0; } -void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL +void proc_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL { - process_is_tearing_down = true; - kl_iter(WatcherPtr, loop->children, current) { - Process *proc = (*current)->data; - if (proc->detach || proc->type == kProcessTypePty) { + proc_is_tearing_down = true; + for (size_t i = 0; i < kv_size(loop->children); i++) { + Proc *proc = kv_A(loop->children, i); + if (proc->detach || proc->type == kProcTypePty) { // Close handles to process without killing it. - CREATE_EVENT(loop->events, process_close_handles, proc); + CREATE_EVENT(loop->events, proc_close_handles, proc); } else { - process_stop(proc); + proc_stop(proc); } } // Wait until all children exit and all close events are processed. LOOP_PROCESS_EVENTS_UNTIL(loop, loop->events, -1, - kl_empty(loop->children) && multiqueue_empty(loop->events)); - pty_process_teardown(loop); + kv_size(loop->children) == 0 && multiqueue_empty(loop->events)); + pty_proc_teardown(loop); } -void process_close_streams(Process *proc) FUNC_ATTR_NONNULL_ALL +void proc_close_streams(Proc *proc) FUNC_ATTR_NONNULL_ALL { - stream_may_close(&proc->in); - stream_may_close(&proc->out); - stream_may_close(&proc->err); + wstream_may_close(&proc->in); + rstream_may_close(&proc->out); + rstream_may_close(&proc->err); } /// Synchronously wait for a process to finish @@ -161,7 +161,7 @@ void process_close_streams(Process *proc) FUNC_ATTR_NONNULL_ALL /// @return Exit code of the process. proc->status will have the same value. /// -1 if the timeout expired while the process is still running. /// -2 if the user interrupted the wait. -int process_wait(Process *proc, int ms, MultiQueue *events) +int proc_wait(Proc *proc, int ms, MultiQueue *events) FUNC_ATTR_NONNULL_ARG(1) { if (!proc->refcount) { @@ -185,7 +185,7 @@ int process_wait(Process *proc, int ms, MultiQueue *events) // Assume that a user hitting CTRL-C does not like the current job. Kill it. if (got_int) { got_int = false; - process_stop(proc); + proc_stop(proc); if (ms == -1) { // We can only return if all streams/handles are closed and the job // exited. @@ -213,7 +213,7 @@ int process_wait(Process *proc, int ms, MultiQueue *events) } /// Ask a process to terminate and eventually kill if it doesn't respond -void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL +void proc_stop(Proc *proc) FUNC_ATTR_NONNULL_ALL { bool exited = (proc->status >= 0); if (exited || proc->stopped_time) { @@ -223,13 +223,13 @@ void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL proc->exit_signal = SIGTERM; switch (proc->type) { - case kProcessTypeUv: + case kProcTypeUv: os_proc_tree_kill(proc->pid, SIGTERM); break; - case kProcessTypePty: + case kProcTypePty: // close all streams for pty processes to send SIGHUP to the process - process_close_streams(proc); - pty_process_close_master((PtyProcess *)proc); + proc_close_streams(proc); + pty_proc_close_master((PtyProc *)proc); break; } @@ -239,7 +239,7 @@ void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL } /// Frees process-owned resources. -void process_free(Process *proc) FUNC_ATTR_NONNULL_ALL +void proc_free(Proc *proc) FUNC_ATTR_NONNULL_ALL { if (proc->argv != NULL) { shell_free_argv(proc->argv); @@ -248,19 +248,19 @@ void process_free(Process *proc) FUNC_ATTR_NONNULL_ALL } /// Sends SIGKILL (or SIGTERM..SIGKILL for PTY jobs) to processes that did -/// not terminate after process_stop(). +/// not terminate after proc_stop(). static void children_kill_cb(uv_timer_t *handle) { Loop *loop = handle->loop->data; - kl_iter(WatcherPtr, loop->children, current) { - Process *proc = (*current)->data; + for (size_t i = 0; i < kv_size(loop->children); i++) { + Proc *proc = kv_A(loop->children, i); bool exited = (proc->status >= 0); if (exited || !proc->stopped_time) { continue; } uint64_t term_sent = UINT64_MAX == proc->stopped_time; - if (kProcessTypePty != proc->type || term_sent) { + if (kProcTypePty != proc->type || term_sent) { proc->exit_signal = SIGKILL; os_proc_tree_kill(proc->pid, SIGKILL); } else { @@ -274,41 +274,45 @@ static void children_kill_cb(uv_timer_t *handle) } } -static void process_close_event(void **argv) +static void proc_close_event(void **argv) { - Process *proc = argv[0]; + Proc *proc = argv[0]; if (proc->cb) { // User (hint: channel_job_start) is responsible for calling - // process_free(). + // proc_free(). proc->cb(proc, proc->status, proc->data); } else { - process_free(proc); + proc_free(proc); } } -static void decref(Process *proc) +static void decref(Proc *proc) { if (--proc->refcount != 0) { return; } Loop *loop = proc->loop; - kliter_t(WatcherPtr) **node = NULL; - kl_iter(WatcherPtr, loop->children, current) { - if ((*current)->data == proc) { - node = current; + size_t i; + for (i = 0; i < kv_size(loop->children); i++) { + Proc *current = kv_A(loop->children, i); + if (current == proc) { break; } } - assert(node); - kl_shift_at(WatcherPtr, loop->children, node); - CREATE_EVENT(proc->events, process_close_event, proc); + assert(i < kv_size(loop->children)); // element found + if (i < kv_size(loop->children) - 1) { + memmove(&kv_A(loop->children, i), &kv_A(loop->children, i + 1), + sizeof(&kv_A(loop->children, i)) * (kv_size(loop->children) - (i + 1))); + } + kv_size(loop->children)--; + CREATE_EVENT(proc->events, proc_close_event, proc); } -static void process_close(Process *proc) +static void proc_close(Proc *proc) FUNC_ATTR_NONNULL_ARG(1) { - if (process_is_tearing_down && (proc->detach || proc->type == kProcessTypePty) + if (proc_is_tearing_down && (proc->detach || proc->type == kProcTypePty) && proc->closed) { // If a detached/pty process dies while tearing down it might get closed // twice. @@ -318,17 +322,17 @@ static void process_close(Process *proc) proc->closed = true; if (proc->detach) { - if (proc->type == kProcessTypeUv) { - uv_unref((uv_handle_t *)&(((LibuvProcess *)proc)->uv)); + if (proc->type == kProcTypeUv) { + uv_unref((uv_handle_t *)&(((LibuvProc *)proc)->uv)); } } switch (proc->type) { - case kProcessTypeUv: - libuv_process_close((LibuvProcess *)proc); + case kProcTypeUv: + libuv_proc_close((LibuvProc *)proc); break; - case kProcessTypePty: - pty_process_close((PtyProcess *)proc); + case kProcTypePty: + pty_proc_close((PtyProc *)proc); break; } } @@ -337,10 +341,10 @@ static void process_close(Process *proc) /// /// @param proc Process, for which an output stream should be flushed. /// @param stream Stream to flush. -static void flush_stream(Process *proc, Stream *stream) +static void flush_stream(Proc *proc, RStream *stream) FUNC_ATTR_NONNULL_ARG(1) { - if (!stream || stream->closed) { + if (!stream || stream->s.closed) { return; } @@ -350,23 +354,23 @@ static void flush_stream(Process *proc, Stream *stream) // keeps sending data, we only accept as much data as the system buffer size. // Otherwise this would block cleanup/teardown. int system_buffer_size = 0; - int err = uv_recv_buffer_size((uv_handle_t *)&stream->uv.pipe, + int err = uv_recv_buffer_size((uv_handle_t *)&stream->s.uv.pipe, &system_buffer_size); if (err) { - system_buffer_size = (int)rbuffer_capacity(stream->buffer); + system_buffer_size = ARENA_BLOCK_SIZE; } size_t max_bytes = stream->num_bytes + (size_t)system_buffer_size; // Read remaining data. - while (!stream->closed && stream->num_bytes < max_bytes) { + while (!stream->s.closed && stream->num_bytes < max_bytes) { // Remember number of bytes before polling size_t num_bytes = stream->num_bytes; // Poll for data and process the generated events. loop_poll_events(proc->loop, 0); - if (stream->events) { - multiqueue_process_events(stream->events); + if (stream->s.events) { + multiqueue_process_events(stream->s.events); } // Stream can be closed if it is empty. @@ -374,23 +378,23 @@ static void flush_stream(Process *proc, Stream *stream) if (stream->read_cb && !stream->did_eof) { // Stream callback could miss EOF handling if a child keeps the stream // open. But only send EOF if we haven't already. - stream->read_cb(stream, stream->buffer, 0, stream->cb_data, true); + stream->read_cb(stream, stream->buffer, 0, stream->s.cb_data, true); } break; } } } -static void process_close_handles(void **argv) +static void proc_close_handles(void **argv) { - Process *proc = argv[0]; + Proc *proc = argv[0]; exit_need_delay++; flush_stream(proc, &proc->out); flush_stream(proc, &proc->err); - process_close_streams(proc); - process_close(proc); + proc_close_streams(proc); + proc_close(proc); exit_need_delay--; } @@ -425,7 +429,7 @@ void exit_from_channel(int status) multiqueue_put(main_loop.fast_events, exit_event, (void *)(intptr_t)status); } -static void on_process_exit(Process *proc) +static void on_proc_exit(Proc *proc) { Loop *loop = proc->loop; ILOG("exited: pid=%d status=%d stoptime=%" PRIu64, proc->pid, proc->status, @@ -438,13 +442,13 @@ static void on_process_exit(Process *proc) // Process has terminated, but there could still be data to be read from the // OS. We are still in the libuv loop, so we cannot call code that polls for // more data directly. Instead delay the reading after the libuv loop by - // queueing process_close_handles() as an event. + // queueing proc_close_handles() as an event. MultiQueue *queue = proc->events ? proc->events : loop->events; - CREATE_EVENT(queue, process_close_handles, proc); + CREATE_EVENT(queue, proc_close_handles, proc); } -static void on_process_stream_close(Stream *stream, void *data) +static void on_proc_stream_close(Stream *stream, void *data) { - Process *proc = data; + Proc *proc = data; decref(proc); } diff --git a/src/nvim/event/process.h b/src/nvim/event/proc.h index 421a470244..f525d46f87 100644 --- a/src/nvim/event/process.h +++ b/src/nvim/event/proc.h @@ -6,9 +6,9 @@ #include "nvim/event/defs.h" // IWYU pragma: keep #include "nvim/types_defs.h" -static inline Process process_init(Loop *loop, ProcessType type, void *data) +static inline Proc proc_init(Loop *loop, ProcType type, void *data) { - return (Process) { + return (Proc) { .type = type, .data = data, .loop = loop, @@ -21,8 +21,8 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data) .argv = NULL, .exepath = NULL, .in = { .closed = false }, - .out = { .closed = false }, - .err = { .closed = false }, + .out = { .s.closed = false }, + .err = { .s.closed = false }, .cb = NULL, .closed = false, .internal_close_cb = NULL, @@ -33,17 +33,17 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data) } /// Get the path to the executable of the process. -static inline const char *process_get_exepath(Process *proc) +static inline const char *proc_get_exepath(Proc *proc) { return proc->exepath != NULL ? proc->exepath : proc->argv[0]; } -static inline bool process_is_stopped(Process *proc) +static inline bool proc_is_stopped(Proc *proc) { bool exited = (proc->status >= 0); return exited || (proc->stopped_time != 0); } #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "event/process.h.generated.h" +# include "event/proc.h.generated.h" #endif diff --git a/src/nvim/event/rstream.c b/src/nvim/event/rstream.c index 6b4ab472e4..15bdc547d5 100644 --- a/src/nvim/event/rstream.c +++ b/src/nvim/event/rstream.c @@ -11,75 +11,80 @@ #include "nvim/macros_defs.h" #include "nvim/main.h" #include "nvim/os/os_defs.h" -#include "nvim/rbuffer.h" -#include "nvim/rbuffer_defs.h" #include "nvim/types_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "event/rstream.c.generated.h" #endif -void rstream_init_fd(Loop *loop, Stream *stream, int fd, size_t bufsize) +void rstream_init_fd(Loop *loop, RStream *stream, int fd) FUNC_ATTR_NONNULL_ARG(1, 2) { - stream_init(loop, stream, fd, NULL); - rstream_init(stream, bufsize); + stream_init(loop, &stream->s, fd, NULL); + rstream_init(stream); } -void rstream_init_stream(Stream *stream, uv_stream_t *uvstream, size_t bufsize) +void rstream_init_stream(RStream *stream, uv_stream_t *uvstream) FUNC_ATTR_NONNULL_ARG(1, 2) { - stream_init(NULL, stream, -1, uvstream); - rstream_init(stream, bufsize); + stream_init(NULL, &stream->s, -1, uvstream); + rstream_init(stream); } -void rstream_init(Stream *stream, size_t bufsize) +void rstream_init(RStream *stream) FUNC_ATTR_NONNULL_ARG(1) { - stream->buffer = rbuffer_new(bufsize); - stream->buffer->data = stream; - stream->buffer->full_cb = on_rbuffer_full; - stream->buffer->nonfull_cb = on_rbuffer_nonfull; + stream->read_cb = NULL; + stream->num_bytes = 0; + stream->buffer = alloc_block(); + stream->read_pos = stream->write_pos = stream->buffer; +} + +void rstream_start_inner(RStream *stream) + FUNC_ATTR_NONNULL_ARG(1) +{ + if (stream->s.uvstream) { + uv_read_start(stream->s.uvstream, alloc_cb, read_cb); + } else { + uv_idle_start(&stream->s.uv.idle, fread_idle_cb); + } } /// Starts watching for events from a `Stream` instance. /// /// @param stream The `Stream` instance -void rstream_start(Stream *stream, stream_read_cb cb, void *data) +void rstream_start(RStream *stream, stream_read_cb cb, void *data) FUNC_ATTR_NONNULL_ARG(1) { stream->read_cb = cb; - stream->cb_data = data; - if (stream->uvstream) { - uv_read_start(stream->uvstream, alloc_cb, read_cb); - } else { - uv_idle_start(&stream->uv.idle, fread_idle_cb); + stream->s.cb_data = data; + stream->want_read = true; + if (!stream->paused_full) { + rstream_start_inner(stream); } } /// Stops watching for events from a `Stream` instance. /// /// @param stream The `Stream` instance -void rstream_stop(Stream *stream) +void rstream_stop_inner(RStream *stream) FUNC_ATTR_NONNULL_ALL { - if (stream->uvstream) { - uv_read_stop(stream->uvstream); + if (stream->s.uvstream) { + uv_read_stop(stream->s.uvstream); } else { - uv_idle_stop(&stream->uv.idle); + uv_idle_stop(&stream->s.uv.idle); } } -static void on_rbuffer_full(RBuffer *buf, void *data) -{ - rstream_stop(data); -} - -static void on_rbuffer_nonfull(RBuffer *buf, void *data) +/// Stops watching for events from a `Stream` instance. +/// +/// @param stream The `Stream` instance +void rstream_stop(RStream *stream) + FUNC_ATTR_NONNULL_ALL { - Stream *stream = data; - assert(stream->read_cb); - rstream_start(stream, stream->read_cb, stream->cb_data); + rstream_stop_inner(stream); + stream->want_read = false; } // Callbacks used by libuv @@ -87,11 +92,10 @@ static void on_rbuffer_nonfull(RBuffer *buf, void *data) /// Called by libuv to allocate memory for reading. static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf) { - Stream *stream = handle->data; - // `uv_buf_t.len` happens to have different size on Windows. - size_t write_count; - buf->base = rbuffer_write_ptr(stream->buffer, &write_count); - buf->len = UV_BUF_LEN(write_count); + RStream *stream = handle->data; + buf->base = stream->write_pos; + // `uv_buf_t.len` happens to have different size on Windows (as a treat) + buf->len = UV_BUF_LEN(rstream_space(stream)); } /// Callback invoked by libuv after it copies the data into the buffer provided @@ -99,27 +103,27 @@ static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf) /// 0-length buffer. static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf) { - Stream *stream = uvstream->data; + RStream *stream = uvstream->data; if (cnt <= 0) { // cnt == 0 means libuv asked for a buffer and decided it wasn't needed: // http://docs.libuv.org/en/latest/stream.html#c.uv_read_start. // - // We don't need to do anything with the RBuffer because the next call + // We don't need to do anything with the buffer because the next call // to `alloc_cb` will return the same unused pointer (`rbuffer_produced` // won't be called) if (cnt == UV_ENOBUFS || cnt == 0) { return; } else if (cnt == UV_EOF && uvstream->type == UV_TTY) { // The TTY driver might signal EOF without closing the stream - invoke_read_cb(stream, 0, true); + invoke_read_cb(stream, true); } else { DLOG("closing Stream (%p): %s (%s)", (void *)stream, uv_err_name((int)cnt), os_strerror((int)cnt)); // Read error or EOF, either way stop the stream and invoke the callback // with eof == true uv_read_stop(uvstream); - invoke_read_cb(stream, 0, true); + invoke_read_cb(stream, true); } return; } @@ -127,10 +131,13 @@ static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf) // at this point we're sure that cnt is positive, no error occurred size_t nread = (size_t)cnt; stream->num_bytes += nread; - // Data was already written, so all we need is to update 'wpos' to reflect - // the space actually used in the buffer. - rbuffer_produced(stream->buffer, nread); - invoke_read_cb(stream, nread, false); + stream->write_pos += cnt; + invoke_read_cb(stream, false); +} + +static size_t rstream_space(RStream *stream) +{ + return (size_t)((stream->buffer + ARENA_BLOCK_SIZE) - stream->write_pos); } /// Called by the by the 'idle' handle to emulate a reading event @@ -141,66 +148,91 @@ static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf) static void fread_idle_cb(uv_idle_t *handle) { uv_fs_t req; - Stream *stream = handle->data; + RStream *stream = handle->data; + stream->uvbuf.base = stream->write_pos; // `uv_buf_t.len` happens to have different size on Windows. - size_t write_count; - stream->uvbuf.base = rbuffer_write_ptr(stream->buffer, &write_count); - stream->uvbuf.len = UV_BUF_LEN(write_count); - - // the offset argument to uv_fs_read is int64_t, could someone really try - // to read more than 9 quintillion (9e18) bytes? - // upcast is meant to avoid tautological condition warning on 32 bits - uintmax_t fpos_intmax = stream->fpos; - if (fpos_intmax > INT64_MAX) { - ELOG("stream offset overflow"); - preserve_exit("stream offset overflow"); - } + stream->uvbuf.len = UV_BUF_LEN(rstream_space(stream)); // Synchronous read - uv_fs_read(handle->loop, - &req, - stream->fd, - &stream->uvbuf, - 1, - (int64_t)stream->fpos, - NULL); + uv_fs_read(handle->loop, &req, stream->s.fd, &stream->uvbuf, 1, stream->s.fpos, NULL); uv_fs_req_cleanup(&req); if (req.result <= 0) { - uv_idle_stop(&stream->uv.idle); - invoke_read_cb(stream, 0, true); + uv_idle_stop(&stream->s.uv.idle); + invoke_read_cb(stream, true); return; } - // no errors (req.result (ssize_t) is positive), it's safe to cast. - size_t nread = (size_t)req.result; - rbuffer_produced(stream->buffer, nread); - stream->fpos += nread; - invoke_read_cb(stream, nread, false); + // no errors (req.result (ssize_t) is positive), it's safe to use. + stream->write_pos += req.result; + stream->s.fpos += req.result; + invoke_read_cb(stream, false); } static void read_event(void **argv) { - Stream *stream = argv[0]; + RStream *stream = argv[0]; + stream->pending_read = false; if (stream->read_cb) { - size_t count = (uintptr_t)argv[1]; - bool eof = (uintptr_t)argv[2]; - stream->did_eof = eof; - stream->read_cb(stream, stream->buffer, count, stream->cb_data, eof); + size_t available = rstream_available(stream); + size_t consumed = stream->read_cb(stream, stream->read_pos, available, stream->s.cb_data, + stream->did_eof); + assert(consumed <= available); + rstream_consume(stream, consumed); + } + stream->s.pending_reqs--; + if (stream->s.closed && !stream->s.pending_reqs) { + stream_close_handle(&stream->s, true); + } +} + +size_t rstream_available(RStream *stream) +{ + return (size_t)(stream->write_pos - stream->read_pos); +} + +void rstream_consume(RStream *stream, size_t consumed) +{ + stream->read_pos += consumed; + size_t remaining = (size_t)(stream->write_pos - stream->read_pos); + if (remaining > 0 && stream->read_pos > stream->buffer) { + memmove(stream->buffer, stream->read_pos, remaining); + stream->read_pos = stream->buffer; + stream->write_pos = stream->buffer + remaining; + } else if (remaining == 0) { + stream->read_pos = stream->write_pos = stream->buffer; } - stream->pending_reqs--; - if (stream->closed && !stream->pending_reqs) { - stream_close_handle(stream); + + if (stream->want_read && stream->paused_full && rstream_space(stream)) { + assert(stream->read_cb); + stream->paused_full = false; + rstream_start_inner(stream); } } -static void invoke_read_cb(Stream *stream, size_t count, bool eof) +static void invoke_read_cb(RStream *stream, bool eof) { + stream->did_eof |= eof; + + if (!rstream_space(stream)) { + rstream_stop_inner(stream); + stream->paused_full = true; + } + + // we cannot use pending_reqs as a socket can have both pending reads and writes + if (stream->pending_read) { + return; + } + // Don't let the stream be closed before the event is processed. - stream->pending_reqs++; + stream->s.pending_reqs++; + stream->pending_read = true; + CREATE_EVENT(stream->s.events, read_event, stream); +} - CREATE_EVENT(stream->events, read_event, - stream, (void *)(uintptr_t *)count, (void *)(uintptr_t)eof); +void rstream_may_close(RStream *stream) +{ + stream_may_close(&stream->s, true); } diff --git a/src/nvim/event/socket.c b/src/nvim/event/socket.c index 4e878a2ecf..1214c3e336 100644 --- a/src/nvim/event/socket.c +++ b/src/nvim/event/socket.c @@ -35,7 +35,7 @@ int socket_watcher_init(Loop *loop, SocketWatcher *watcher, const char *endpoint if (host_end && addr != host_end) { // Split user specified address into two strings, addr(hostname) and port. // The port part in watcher->addr will be updated later. - *host_end = '\0'; + *host_end = NUL; char *port = host_end + 1; intmax_t iport; @@ -135,17 +135,17 @@ int socket_watcher_start(SocketWatcher *watcher, int backlog, socket_cb cb) return 0; } -int socket_watcher_accept(SocketWatcher *watcher, Stream *stream) +int socket_watcher_accept(SocketWatcher *watcher, RStream *stream) FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2) { uv_stream_t *client; if (watcher->stream->type == UV_TCP) { - client = (uv_stream_t *)(&stream->uv.tcp); + client = (uv_stream_t *)(&stream->s.uv.tcp); uv_tcp_init(watcher->uv.tcp.handle.loop, (uv_tcp_t *)client); uv_tcp_nodelay((uv_tcp_t *)client, true); } else { - client = (uv_stream_t *)&stream->uv.pipe; + client = (uv_stream_t *)&stream->s.uv.pipe; uv_pipe_init(watcher->uv.pipe.handle.loop, (uv_pipe_t *)client, 0); } @@ -156,7 +156,7 @@ int socket_watcher_accept(SocketWatcher *watcher, Stream *stream) return result; } - stream_init(NULL, stream, -1, client); + stream_init(NULL, &stream->s, -1, client); return 0; } @@ -197,7 +197,7 @@ static void connect_cb(uv_connect_t *req, int status) } } -bool socket_connect(Loop *loop, Stream *stream, bool is_tcp, const char *address, int timeout, +bool socket_connect(Loop *loop, RStream *stream, bool is_tcp, const char *address, int timeout, const char **error) { bool success = false; @@ -206,7 +206,7 @@ bool socket_connect(Loop *loop, Stream *stream, bool is_tcp, const char *address req.data = &status; uv_stream_t *uv_stream; - uv_tcp_t *tcp = &stream->uv.tcp; + uv_tcp_t *tcp = &stream->s.uv.tcp; uv_getaddrinfo_t addr_req; addr_req.addrinfo = NULL; const struct addrinfo *addrinfo = NULL; @@ -237,7 +237,7 @@ tcp_retry: uv_tcp_connect(&req, tcp, addrinfo->ai_addr, connect_cb); uv_stream = (uv_stream_t *)tcp; } else { - uv_pipe_t *pipe = &stream->uv.pipe; + uv_pipe_t *pipe = &stream->s.uv.pipe; uv_pipe_init(&loop->uv, pipe, 0); uv_pipe_connect(&req, pipe, address, connect_cb); uv_stream = (uv_stream_t *)pipe; @@ -245,7 +245,7 @@ tcp_retry: status = 1; LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, timeout, status != 1); if (status == 0) { - stream_init(NULL, stream, -1, uv_stream); + stream_init(NULL, &stream->s, -1, uv_stream); success = true; } else if (is_tcp && addrinfo->ai_next) { addrinfo = addrinfo->ai_next; diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c index 0b9ed4f25b..71de6ee1ba 100644 --- a/src/nvim/event/stream.c +++ b/src/nvim/event/stream.c @@ -8,7 +8,6 @@ #include "nvim/event/loop.h" #include "nvim/event/stream.h" #include "nvim/log.h" -#include "nvim/rbuffer.h" #include "nvim/types_defs.h" #ifdef MSWIN # include "nvim/os/os_win_console.h" @@ -45,6 +44,8 @@ int stream_set_blocking(int fd, bool blocking) void stream_init(Loop *loop, Stream *stream, int fd, uv_stream_t *uvstream) FUNC_ATTR_NONNULL_ARG(2) { + // The underlying stream is either a file or an existing uv stream. + assert(uvstream == NULL ? fd >= 0 : fd < 0); stream->uvstream = uvstream; if (fd >= 0) { @@ -84,29 +85,29 @@ void stream_init(Loop *loop, Stream *stream, int fd, uv_stream_t *uvstream) stream->uvstream->data = stream; } - stream->internal_data = NULL; stream->fpos = 0; + stream->internal_data = NULL; stream->curmem = 0; stream->maxmem = 0; stream->pending_reqs = 0; - stream->read_cb = NULL; stream->write_cb = NULL; stream->close_cb = NULL; stream->internal_close_cb = NULL; stream->closed = false; - stream->buffer = NULL; stream->events = NULL; - stream->num_bytes = 0; } -void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data) +void stream_may_close(Stream *stream, bool rstream) FUNC_ATTR_NONNULL_ARG(1) { + if (stream->closed) { + return; + } assert(!stream->closed); DLOG("closing Stream: %p", (void *)stream); stream->closed = true; - stream->close_cb = on_stream_close; - stream->close_cb_data = data; + stream->close_cb = NULL; + stream->close_cb_data = NULL; #ifdef MSWIN if (UV_TTY == uv_guess_handle(stream->fd)) { @@ -116,18 +117,11 @@ void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data) #endif if (!stream->pending_reqs) { - stream_close_handle(stream); - } -} - -void stream_may_close(Stream *stream) -{ - if (!stream->closed) { - stream_close(stream, NULL, NULL); + stream_close_handle(stream, rstream); } } -void stream_close_handle(Stream *stream) +void stream_close_handle(Stream *stream, bool rstream) FUNC_ATTR_NONNULL_ALL { uv_handle_t *handle = NULL; @@ -145,16 +139,22 @@ void stream_close_handle(Stream *stream) assert(handle != NULL); if (!uv_is_closing(handle)) { - uv_close(handle, close_cb); + uv_close(handle, rstream ? rstream_close_cb : close_cb); } } -static void close_cb(uv_handle_t *handle) +static void rstream_close_cb(uv_handle_t *handle) { - Stream *stream = handle->data; + RStream *stream = handle->data; if (stream->buffer) { - rbuffer_free(stream->buffer); + free_block(stream->buffer); } + close_cb(handle); +} + +static void close_cb(uv_handle_t *handle) +{ + Stream *stream = handle->data; if (stream->close_cb) { stream->close_cb(stream, stream->close_cb_data); } diff --git a/src/nvim/event/wstream.c b/src/nvim/event/wstream.c index c67a9b96ed..5005c4e84f 100644 --- a/src/nvim/event/wstream.c +++ b/src/nvim/event/wstream.c @@ -73,6 +73,26 @@ bool wstream_write(Stream *stream, WBuffer *buffer) // This should not be called after a stream was freed assert(!stream->closed); + uv_buf_t uvbuf; + uvbuf.base = buffer->data; + uvbuf.len = UV_BUF_LEN(buffer->size); + + if (!stream->uvstream) { + uv_fs_t req; + + // Synchronous write + uv_fs_write(stream->uv.idle.loop, &req, stream->fd, &uvbuf, 1, stream->fpos, NULL); + + uv_fs_req_cleanup(&req); + + wstream_release_wbuffer(buffer); + + assert(stream->write_cb == NULL); + + stream->fpos += MAX(req.result, 0); + return req.result > 0; + } + if (stream->curmem > stream->maxmem) { goto err; } @@ -84,10 +104,6 @@ bool wstream_write(Stream *stream, WBuffer *buffer) data->buffer = buffer; data->uv_req.data = data; - uv_buf_t uvbuf; - uvbuf.base = buffer->data; - uvbuf.len = UV_BUF_LEN(buffer->size); - if (uv_write(&data->uv_req, stream->uvstream, &uvbuf, 1, write_cb)) { xfree(data); goto err; @@ -141,7 +157,7 @@ static void write_cb(uv_write_t *req, int status) if (data->stream->closed && data->stream->pending_reqs == 0) { // Last pending write, free the stream; - stream_close_handle(data->stream); + stream_close_handle(data->stream, false); } xfree(data); @@ -158,3 +174,8 @@ void wstream_release_wbuffer(WBuffer *buffer) xfree(buffer); } } + +void wstream_may_close(Stream *stream) +{ + stream_may_close(stream, false); +} diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 834cc6698a..a98de05815 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -34,6 +34,7 @@ #include "nvim/digraph.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -203,7 +204,7 @@ void do_ascii(exarg_T *eap) IObuff[iobuff_len++] = ' '; } IObuff[iobuff_len++] = '<'; - if (utf_iscomposing(c)) { + if (utf_iscomposing_first(c)) { IObuff[iobuff_len++] = ' '; // Draw composing char on top of a space. } iobuff_len += (size_t)utf_char2bytes(c, IObuff + iobuff_len); @@ -310,9 +311,7 @@ void ex_align(exarg_T *eap) } } } - if (new_indent < 0) { - new_indent = 0; - } + new_indent = MAX(new_indent, 0); set_indent(new_indent, 0); // set indent } changed_lines(curbuf, eap->line1, 0, eap->line2 + 1, 0, true); @@ -542,9 +541,7 @@ void ex_sort(exarg_T *eap) for (linenr_T lnum = eap->line1; lnum <= eap->line2; lnum++) { char *s = ml_get(lnum); int len = ml_get_len(lnum); - if (maxlen < len) { - maxlen = len; - } + maxlen = MAX(maxlen, len); colnr_T start_col = 0; colnr_T end_col = len; @@ -704,11 +701,6 @@ sortend: /// @return FAIL for failure, OK otherwise int do_move(linenr_T line1, linenr_T line2, linenr_T dest) { - linenr_T l; - linenr_T extra; // Num lines added before line1 - linenr_T num_lines; // Num lines moved - linenr_T last_line; // Last line in file after adding new text - if (dest >= line1 && dest < line2) { emsg(_("E134: Cannot move a range of lines into itself")); return FAIL; @@ -719,11 +711,9 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) if (dest == line1 - 1 || dest == line2) { // Move the cursor as if lines were moved (see below) to be backwards // compatible. - if (dest >= line1) { - curwin->w_cursor.lnum = dest; - } else { - curwin->w_cursor.lnum = dest + (line2 - line1) + 1; - } + curwin->w_cursor.lnum = dest >= line1 + ? dest + : dest + (line2 - line1) + 1; return OK; } @@ -732,13 +722,16 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) bcount_t extent_byte = end_byte - start_byte; bcount_t dest_byte = ml_find_line_or_offset(curbuf, dest + 1, NULL, true); - num_lines = line2 - line1 + 1; + linenr_T num_lines = line2 - line1 + 1; // Num lines moved // First we copy the old text to its new location -- webb // Also copy the flag that ":global" command uses. if (u_save(dest, dest + 1) == FAIL) { return FAIL; } + + linenr_T l; + linenr_T extra; // Num lines added before line1 for (extra = 0, l = line1; l <= line2; l++) { char *str = xstrnsave(ml_get(l + extra), (size_t)ml_get_len(l + extra)); ml_append(dest + l - line1, str, 0, false); @@ -761,7 +754,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) // // And Finally we adjust the marks we put at the end of the file back to // their final destination at the new text position -- webb - last_line = curbuf->b_ml.ml_line_count; + linenr_T last_line = curbuf->b_ml.ml_line_count; // Last line in file after adding new text mark_adjust_nofold(line1, line2, last_line - line2, 0, kExtmarkNOOP); disable_fold_update++; @@ -837,9 +830,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) if (line1 < dest) { dest += num_lines + 1; last_line = curbuf->b_ml.ml_line_count; - if (dest > last_line + 1) { - dest = last_line + 1; - } + dest = MIN(dest, last_line + 1); changed_lines(curbuf, line1, 0, dest, 0, false); } else { changed_lines(curbuf, dest + 1, 0, line1 + num_lines, 0, false); @@ -969,13 +960,13 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out char *t = xmalloc(len); *t = NUL; if (newcmd != NULL) { - STRCAT(t, newcmd); + strcat(t, newcmd); } if (ins_prevcmd) { - STRCAT(t, prevcmd); + strcat(t, prevcmd); } char *p = t + strlen(t); - STRCAT(t, trailarg); + strcat(t, trailarg); xfree(newcmd); newcmd = t; @@ -1028,8 +1019,8 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out } newcmd = xmalloc(strlen(prevcmd) + 2 * strlen(p_shq) + 1); STRCPY(newcmd, p_shq); - STRCAT(newcmd, prevcmd); - STRCAT(newcmd, p_shq); + strcat(newcmd, prevcmd); + strcat(newcmd, p_shq); free_newcmd = true; } if (addr_count == 0) { // :! @@ -1169,7 +1160,7 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b linenr_T read_linecount = curbuf->b_ml.ml_line_count; // Pass on the kShellOptDoOut flag when the output is being redirected. - call_shell(cmd_buf, (ShellOpts)(kShellOptFilter | shell_flags), NULL); + call_shell(cmd_buf, kShellOptFilter | shell_flags, NULL); xfree(cmd_buf); did_check_timestamps = false; @@ -1314,7 +1305,7 @@ void do_shell(char *cmd, int flags) // This ui_cursor_goto is required for when the '\n' resulted in a "delete line // 1" command to the terminal. ui_cursor_goto(msg_row, msg_col); - call_shell(cmd, (ShellOpts)flags, NULL); + call_shell(cmd, flags, NULL); if (msg_silent == 0) { msg_didout = true; } @@ -2270,6 +2261,16 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum if (buf == NULL) { goto theend; } + // autocommands try to edit a file that is goind to be removed, abort + if (buf_locked(buf)) { + // window was split, but not editing the new buffer, reset b_nwindows again + if (oldwin == NULL + && curwin->w_buffer != NULL + && curwin->w_buffer->b_nwindows > 1) { + curwin->w_buffer->b_nwindows--; + } + goto theend; + } if (curwin->w_alt_fnum == buf->b_fnum && prev_alt_fnum != 0) { // reusing the buffer, keep the old alternate file curwin->w_alt_fnum = prev_alt_fnum; @@ -2356,9 +2357,9 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum win_T *the_curwin = curwin; buf_T *was_curbuf = curbuf; - // Set w_closing to avoid that autocommands close the window. + // Set w_locked to avoid that autocommands close the window. // Set b_locked for the same reason. - the_curwin->w_closing = true; + the_curwin->w_locked = true; buf->b_locked++; if (curbuf == old_curbuf.br_buf) { @@ -2374,7 +2375,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum // Autocommands may have closed the window. if (win_valid(the_curwin)) { - the_curwin->w_closing = false; + the_curwin->w_locked = false; } buf->b_locked--; @@ -2704,7 +2705,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum *so_ptr = 999; // force cursor to be vertically centered in the window } update_topline(curwin); - curwin->w_scbind_pos = curwin->w_topline; + curwin->w_scbind_pos = plines_m_win_fill(curwin, 1, curwin->w_topline); *so_ptr = n; redraw_curbuf_later(UPD_NOT_VALID); // redraw this buffer later } @@ -2783,10 +2784,14 @@ void ex_append(exarg_T *eap) indent = get_indent_lnum(lnum); } } - if (eap->ea_getline == NULL) { + if (*eap->arg == '|') { + // Get the text after the trailing bar. + theline = xstrdup(eap->arg + 1); + *eap->arg = NUL; + } else if (eap->ea_getline == NULL) { // No getline() function, use the lines that follow. This ends // when there is no more. - if (eap->nextcmd == NULL || *eap->nextcmd == NUL) { + if (eap->nextcmd == NULL) { break; } p = vim_strchr(eap->nextcmd, NL); @@ -2796,6 +2801,8 @@ void ex_append(exarg_T *eap) theline = xmemdupz(eap->nextcmd, (size_t)(p - eap->nextcmd)); if (*p != NUL) { p++; + } else { + p = NULL; } eap->nextcmd = p; } else { @@ -2926,9 +2933,7 @@ void ex_z(exarg_T *eap) } else { bigness = curwin->w_height_inner - 3; } - if (bigness < 1) { - bigness = 1; - } + bigness = MAX(bigness, 1); char *x = eap->arg; char *kind = x; @@ -3001,19 +3006,9 @@ void ex_z(exarg_T *eap) break; } - if (start < 1) { - start = 1; - } - - if (end > curbuf->b_ml.ml_line_count) { - end = curbuf->b_ml.ml_line_count; - } - - if (curs > curbuf->b_ml.ml_line_count) { - curs = curbuf->b_ml.ml_line_count; - } else if (curs < 1) { - curs = 1; - } + start = MAX(start, 1); + end = MIN(end, curbuf->b_ml.ml_line_count); + curs = MIN(MAX(curs, 1), curbuf->b_ml.ml_line_count); for (linenr_T i = start; i <= end; i++) { if (minus && i == lnum) { @@ -3083,8 +3078,8 @@ void sub_get_replacement(SubReplacementString *const ret_sub) void sub_set_replacement(SubReplacementString sub) { xfree(old_sub.sub); - if (sub.additional_elements != old_sub.additional_elements) { - tv_list_unref(old_sub.additional_elements); + if (sub.additional_data != old_sub.additional_data) { + xfree(old_sub.additional_data); } old_sub = sub; } @@ -3100,7 +3095,7 @@ void sub_set_replacement(SubReplacementString sub) /// /// @returns true if :substitute can be replaced with a join command static bool sub_joining_lines(exarg_T *eap, char *pat, size_t patlen, const char *sub, - const char *cmd, bool save) + const char *cmd, bool save, bool keeppatterns) FUNC_ATTR_NONNULL_ARG(1, 4, 5) { // TODO(vim): find a generic solution to make line-joining operations more @@ -3138,7 +3133,7 @@ static bool sub_joining_lines(exarg_T *eap, char *pat, size_t patlen, const char } if (save) { - if ((cmdmod.cmod_flags & CMOD_KEEPPATTERNS) == 0) { + if (!keeppatterns) { save_re_pat(RE_SUBST, pat, patlen, magic_isset()); } // put pattern in history @@ -3346,6 +3341,7 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n linenr_T old_line_count = curbuf->b_ml.ml_line_count; char *sub_firstline; // allocated copy of first sub line bool endcolumn = false; // cursor in last column when done + const bool keeppatterns = cmdmod.cmod_flags & CMOD_KEEPPATTERNS; PreviewLines preview_lines = { KV_INITIAL_VALUE, 0 }; static int pre_hl_id = 0; pos_T old_cursor = curwin->w_cursor; @@ -3392,12 +3388,12 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n which_pat = RE_LAST; // use last used regexp delimiter = (uint8_t)(*cmd++); // remember delimiter character pat = cmd; // remember start of search pat - patlen = strlen(pat); cmd = skip_regexp_ex(cmd, delimiter, magic_isset(), &eap->arg, NULL, NULL); if (cmd[0] == delimiter) { // end delimiter found *cmd++ = NUL; // replace it with a NUL has_second_delim = true; } + patlen = strlen(pat); } // Small incompatibility: vi sees '\n' as end of the command, but in @@ -3406,11 +3402,11 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n cmd = skip_substitute(cmd, delimiter); sub = xstrdup(p); - if (!eap->skip && cmdpreview_ns <= 0) { + if (!eap->skip && !keeppatterns && cmdpreview_ns <= 0) { sub_set_replacement((SubReplacementString) { .sub = xstrdup(sub), .timestamp = os_time(), - .additional_elements = NULL, + .additional_data = NULL, }); } } else if (!eap->skip) { // use previous pattern and substitution @@ -3427,7 +3423,8 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n endcolumn = (curwin->w_curswant == MAXCOL); } - if (sub != NULL && sub_joining_lines(eap, pat, patlen, sub, cmd, cmdpreview_ns <= 0)) { + if (sub != NULL && sub_joining_lines(eap, pat, patlen, sub, cmd, cmdpreview_ns <= 0, + keeppatterns)) { xfree(sub); return 0; } @@ -3454,9 +3451,7 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n } eap->line1 = eap->line2; eap->line2 += (linenr_T)i - 1; - if (eap->line2 > curbuf->b_ml.ml_line_count) { - eap->line2 = curbuf->b_ml.ml_line_count; - } + eap->line2 = MIN(eap->line2, curbuf->b_ml.ml_line_count); } // check for trailing command or garbage @@ -3720,10 +3715,8 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n print_line_no_prefix(lnum, subflags.do_number, subflags.do_list); getvcol(curwin, &curwin->w_cursor, &sc, NULL, NULL); - curwin->w_cursor.col = regmatch.endpos[0].col - 1; - if (curwin->w_cursor.col < 0) { - curwin->w_cursor.col = 0; - } + curwin->w_cursor.col = MAX(regmatch.endpos[0].col - 1, 0); + getvcol(curwin, &curwin->w_cursor, NULL, NULL, &ec); curwin->w_cursor.col = regmatch.startpos[0].col; if (subflags.do_number || curwin->w_p_nu) { @@ -4107,7 +4100,7 @@ skip: // the line as reference, because the substitute may // have changed the number of characters. Same for // "prev_matchcol". - STRCAT(new_start, sub_firstline + copycol); + strcat(new_start, sub_firstline + copycol); matchcol = (colnr_T)strlen(sub_firstline) - matchcol; prev_matchcol = (colnr_T)strlen(sub_firstline) - prev_matchcol; diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index f4a6e61831..aff9dce7c1 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -17,6 +17,7 @@ #include "nvim/bufwrite.h" #include "nvim/change.h" #include "nvim/channel.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -226,7 +227,7 @@ void dialog_changed(buf_T *buf, bool checkall) // restore to empty when write failed if (empty_bufname) { - XFREE_CLEAR(buf->b_fname); + buf->b_fname = NULL; XFREE_CLEAR(buf->b_ffname); XFREE_CLEAR(buf->b_sfname); unchanged(buf, true, false); @@ -589,7 +590,7 @@ void ex_listdo(exarg_T *eap) break; } assert(wp); - execute = !wp->w_floating || wp->w_config.focusable; + execute = !wp->w_floating || (!wp->w_config.hide && wp->w_config.focusable); if (execute) { win_goto(wp); if (curwin != wp) { diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h index 07f92ca169..4924e86470 100644 --- a/src/nvim/ex_cmds_defs.h +++ b/src/nvim/ex_cmds_defs.h @@ -233,5 +233,5 @@ typedef struct { typedef struct { char *sub; ///< Previous replacement string. Timestamp timestamp; ///< Time when it was last set. - list_T *additional_elements; ///< Additional data left from ShaDa file. + AdditionalData *additional_data; ///< Additional data left from ShaDa file. } SubReplacementString; diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 1fcfc505df..293aaac036 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -29,6 +29,7 @@ #include "nvim/digraph.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -80,6 +81,7 @@ #include "nvim/os/os_defs.h" #include "nvim/os/shell.h" #include "nvim/path.h" +#include "nvim/plines.h" #include "nvim/popupmenu.h" #include "nvim/pos_defs.h" #include "nvim/profile.h" @@ -971,8 +973,13 @@ void handle_did_throw(void) current_exception->throw_name = NULL; discard_current_exception(); // uses IObuff if 'verbose' - suppress_errthrow = true; - force_abort = true; + + // If "silent!" is active the uncaught exception is not fatal. + if (emsg_silent == 0) { + suppress_errthrow = true; + force_abort = true; + } + msg_ext_set_kind("emsg"); // kind=emsg for :throw, exceptions. #9993 if (messages != NULL) { @@ -1073,7 +1080,6 @@ void *getline_cookie(LineGetter fgetline, void *cookie) /// @return the buffer number. static int compute_buffer_local_count(cmd_addr_T addr_type, linenr_T lnum, int offset) { - buf_T *nextbuf; int count = offset; buf_T *buf = firstbuf; @@ -1082,7 +1088,7 @@ static int compute_buffer_local_count(cmd_addr_T addr_type, linenr_T lnum, int o } while (count != 0) { count += (count < 0) ? 1 : -1; - nextbuf = (offset < 0) ? buf->b_prev : buf->b_next; + buf_T *nextbuf = (offset < 0) ? buf->b_prev : buf->b_next; if (nextbuf == NULL) { break; } @@ -1101,7 +1107,7 @@ static int compute_buffer_local_count(cmd_addr_T addr_type, linenr_T lnum, int o // we might have gone too far, last buffer is not loaded if (addr_type == ADDR_LOADED_BUFFERS) { while (buf->b_ml.ml_mfp == NULL) { - nextbuf = (offset >= 0) ? buf->b_prev : buf->b_next; + buf_T *nextbuf = (offset >= 0) ? buf->b_prev : buf->b_next; if (nextbuf == NULL) { break; } @@ -1405,7 +1411,11 @@ void set_cmd_count(exarg_T *eap, linenr_T count, bool validate) } } else { eap->line1 = eap->line2; - eap->line2 += count - 1; + if (eap->line2 >= INT32_MAX - (count - 1)) { + eap->line2 = INT32_MAX; + } else { + 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) { @@ -1423,7 +1433,7 @@ static int parse_count(exarg_T *eap, const 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))) { - linenr_T n = getdigits_int32(&eap->arg, false, -1); + linenr_T n = getdigits_int32(&eap->arg, false, INT32_MAX); eap->arg = skipwhite(eap->arg); if (eap->args != NULL) { @@ -1686,9 +1696,7 @@ static int execute_cmd0(int *retv, exarg_T *eap, const char **errormsg, bool pre // ":silent! try" was used, it should only apply to :try itself. if (eap->cmdidx == CMD_try && cmdmod.cmod_did_esilent > 0) { emsg_silent -= cmdmod.cmod_did_esilent; - if (emsg_silent < 0) { - emsg_silent = 0; - } + emsg_silent = MAX(emsg_silent, 0); cmdmod.cmod_did_esilent = 0; } @@ -1728,12 +1736,6 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview) } const char *errormsg = NULL; -#undef ERROR -#define ERROR(msg) \ - do { \ - errormsg = msg; \ - goto end; \ - } while (0) cmdmod_T save_cmdmod = cmdmod; cmdmod = cmdinfo->cmdmod; @@ -1744,16 +1746,19 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview) if (!MODIFIABLE(curbuf) && (eap->argt & EX_MODIFY) // allow :put in terminals && !(curbuf->terminal && eap->cmdidx == CMD_put)) { - ERROR(_(e_modifiable)); + errormsg = _(e_modifiable); + goto end; } if (!IS_USER_CMDIDX(eap->cmdidx)) { if (cmdwin_type != 0 && !(eap->argt & EX_CMDWIN)) { // Command not allowed in the command line window - ERROR(_(e_cmdwin)); + errormsg = _(e_cmdwin); + goto end; } if (text_locked() && !(eap->argt & EX_LOCK_OK)) { // Command not allowed when text is locked - ERROR(_(get_text_locked_msg())); + errormsg = _(get_text_locked_msg()); + goto end; } } // Disallow editing another buffer when "curbuf->b_ro_locked" is set. @@ -1801,7 +1806,6 @@ end: do_cmdline_end(); return retv; -#undef ERROR } static void profile_cmd(const exarg_T *eap, cstack_T *cstack, LineGetter fgetline, void *cookie) @@ -2073,29 +2077,8 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter if (ea.skip) { // skip this if inside :if goto doend; } - if (*ea.cmd == '|' || (exmode_active && ea.line1 != ea.line2)) { - ea.cmdidx = CMD_print; - ea.argt = EX_RANGE | EX_COUNT | EX_TRLBAR; - if ((errormsg = invalid_range(&ea)) == NULL) { - correct_range(&ea); - ex_print(&ea); - } - } else if (ea.addr_count != 0) { - if (ea.line2 > curbuf->b_ml.ml_line_count) { - ea.line2 = curbuf->b_ml.ml_line_count; - } - - if (ea.line2 < 0) { - errormsg = _(e_invrange); - } else { - if (ea.line2 == 0) { - curwin->w_cursor.lnum = 1; - } else { - curwin->w_cursor.lnum = ea.line2; - } - beginline(BL_SOL | BL_FIX); - } - } + assert(errormsg == NULL); + errormsg = ex_range_without_command(&ea); goto doend; } @@ -2441,6 +2424,40 @@ char *ex_errmsg(const char *const msg, const char *const arg) return ex_error_buf; } +/// The "+" string used in place of an empty command in Ex mode. +/// This string is used in pointer comparison. +static char exmode_plus[] = "+"; + +/// Handle a range without a command. +/// Returns an error message on failure. +static char *ex_range_without_command(exarg_T *eap) +{ + char *errormsg = NULL; + + if (*eap->cmd == '|' || (exmode_active && eap->cmd != exmode_plus + 1)) { + eap->cmdidx = CMD_print; + eap->argt = EX_RANGE | EX_COUNT | EX_TRLBAR; + if ((errormsg = invalid_range(eap)) == NULL) { + correct_range(eap); + ex_print(eap); + } + } else if (eap->addr_count != 0) { + eap->line2 = MIN(eap->line2, curbuf->b_ml.ml_line_count); + + if (eap->line2 < 0) { + errormsg = _(e_invrange); + } else { + if (eap->line2 == 0) { + curwin->w_cursor.lnum = 1; + } else { + curwin->w_cursor.lnum = eap->line2; + } + beginline(BL_SOL | BL_FIX); + } + } + return errormsg; +} + /// Parse and skip over command modifiers: /// - update eap->cmd /// - store flags in "cmod". @@ -2474,7 +2491,7 @@ int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, if (*eap->cmd == NUL && exmode_active && getline_equal(eap->ea_getline, eap->cookie, getexline) && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { - eap->cmd = "+"; + eap->cmd = exmode_plus; if (!skip_only) { ex_pressedreturn = true; } @@ -2482,6 +2499,15 @@ int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, // ignore comment and empty lines if (*eap->cmd == '"') { + // a comment ends at a NL + eap->nextcmd = vim_strchr(eap->cmd, '\n'); + if (eap->nextcmd != NULL) { + eap->nextcmd++; + } + return FAIL; + } + if (*eap->cmd == '\n') { + eap->nextcmd = eap->cmd + 1; return FAIL; } if (*eap->cmd == NUL) { @@ -2695,7 +2721,7 @@ int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, /// Apply the command modifiers. Saves current state in "cmdmod", call /// undo_cmdmod() later. -static void apply_cmdmod(cmdmod_T *cmod) +void apply_cmdmod(cmdmod_T *cmod) { if ((cmod->cmod_flags & CMOD_SANDBOX) && !cmod->cmod_did_sandbox) { sandbox++; @@ -2764,9 +2790,7 @@ void undo_cmdmod(cmdmod_T *cmod) msg_silent = cmod->cmod_save_msg_silent - 1; } emsg_silent -= cmod->cmod_did_esilent; - if (emsg_silent < 0) { - emsg_silent = 0; - } + emsg_silent = MAX(emsg_silent, 0); // Restore msg_scroll, it's set by file I/O commands, even when no // message is actually displayed. msg_scroll = cmod->cmod_save_msg_scroll; @@ -3499,11 +3523,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, bool // This makes sure we never match in the current // line, and can match anywhere in the // next/previous line. - if (c == '/' && curwin->w_cursor.lnum > 0) { - curwin->w_cursor.col = MAXCOL; - } else { - curwin->w_cursor.col = 0; - } + curwin->w_cursor.col = (c == '/' && curwin->w_cursor.lnum > 0) ? MAXCOL : 0; searchcmdlen = 0; flags = silent ? 0 : SEARCH_HIS | SEARCH_MSG; if (!do_search(NULL, c, c, cmd, strlen(cmd), 1, flags, NULL)) { @@ -3613,6 +3633,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, bool n = getdigits_int32(&cmd, false, MAXLNUM); if (n == MAXLNUM) { *errormsg = _(e_line_number_out_of_range); + cmd = NULL; goto error; } } @@ -3635,6 +3656,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, bool } else { if (lnum >= 0 && n >= INT32_MAX - lnum) { *errormsg = _(e_line_number_out_of_range); + cmd = NULL; goto error; } lnum += n; @@ -3829,8 +3851,8 @@ char *replace_makeprg(exarg_T *eap, char *arg, char **cmdlinep) // No $* in arg, build "<makeprg> <arg>" instead new_cmdline = xmalloc(strlen(program) + strlen(arg) + 2); STRCPY(new_cmdline, program); - STRCAT(new_cmdline, " "); - STRCAT(new_cmdline, arg); + strcat(new_cmdline, " "); + strcat(new_cmdline, arg); } msg_make(arg); @@ -4089,7 +4111,12 @@ void separate_nextcmd(exarg_T *eap) && !(eap->argt & EX_NOTRLCOM) && (eap->cmdidx != CMD_at || p != eap->arg) && (eap->cmdidx != CMD_redir - || p != eap->arg + 1 || p[-1] != '@')) || *p == '|' || *p == '\n') { + || p != eap->arg + 1 || p[-1] != '@')) + || (*p == '|' + && eap->cmdidx != CMD_append + && eap->cmdidx != CMD_change + && eap->cmdidx != CMD_insert) + || *p == '\n') { // We remove the '\' before the '|', unless EX_CTRLV is used // AND 'b' is present in 'cpoptions'. if ((vim_strchr(p_cpo, CPO_BAR) == NULL @@ -4117,7 +4144,7 @@ static char *getargcmd(char **argp) if (*arg == '+') { // +[command] arg++; - if (ascii_isspace(*arg) || *arg == '\0') { + if (ascii_isspace(*arg) || *arg == NUL) { command = dollar_command; } else { command = arg; @@ -4626,7 +4653,7 @@ static void ex_colorscheme(exarg_T *eap) char *expr = xstrdup("g:colors_name"); emsg_off++; - char *p = eval_to_string(expr, false); + char *p = eval_to_string(expr, false, false); emsg_off--; xfree(expr); @@ -4765,11 +4792,9 @@ static void ex_cquit(exarg_T *eap) int before_quit_all(exarg_T *eap) { if (cmdwin_type != 0) { - if (eap->forceit) { - cmdwin_result = K_XF1; // open_cmdwin() takes care of this - } else { - cmdwin_result = K_XF2; - } + cmdwin_result = eap->forceit + ? K_XF1 // open_cmdwin() takes care of this + : K_XF2; return FAIL; } @@ -5565,45 +5590,43 @@ static void ex_swapname(exarg_T *eap) /// (1998-11-02 16:21:01 R. Edward Ralston <eralston@computer.org>) static void ex_syncbind(exarg_T *eap) { - linenr_T topline; - int y; + linenr_T vtopline; // Target topline (including fill) + linenr_T old_linenr = curwin->w_cursor.lnum; setpcmark(); - // determine max topline + // determine max (virtual) topline if (curwin->w_p_scb) { - topline = curwin->w_topline; + vtopline = get_vtopline(curwin); FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_p_scb && wp->w_buffer) { - y = wp->w_buffer->b_ml.ml_line_count - get_scrolloff_value(curwin); - if (topline > y) { - topline = y; - } + linenr_T y = plines_m_win_fill(wp, 1, wp->w_buffer->b_ml.ml_line_count) + - get_scrolloff_value(curwin); + vtopline = MIN(vtopline, y); } } - if (topline < 1) { - topline = 1; - } + vtopline = MAX(vtopline, 1); } else { - topline = 1; + vtopline = 1; } // Set all scrollbind windows to the same topline. FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_p_scb) { - y = topline - wp->w_topline; + int y = vtopline - get_vtopline(wp); if (y > 0) { scrollup(wp, y, true); } else { scrolldown(wp, -y, true); } - wp->w_scbind_pos = topline; + wp->w_scbind_pos = vtopline; redraw_later(wp, UPD_VALID); cursor_correct(wp); wp->w_redr_status = true; } } + if (curwin->w_p_scb) { did_syncbind = true; checkpcmark(); @@ -7239,7 +7262,7 @@ char *expand_sfile(char *arg) memmove(newres, result, (size_t)(p - result)); STRCPY(newres + (p - result), repl); len = strlen(newres); - STRCAT(newres, p + srclen); + strcat(newres, p + srclen); xfree(repl); xfree(result); result = newres; @@ -7316,7 +7339,7 @@ static void ex_filetype(exarg_T *eap) break; } if (strcmp(arg, "on") == 0 || strcmp(arg, "detect") == 0) { - if (*arg == 'o' || !filetype_detect) { + if (*arg == 'o' || filetype_detect != kTrue) { source_runtime(FILETYPE_FILE, DIP_ALL); filetype_detect = kTrue; if (plugin) { diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index 472741d537..f9936dd88e 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -11,6 +11,7 @@ #include "nvim/ascii_defs.h" #include "nvim/charset.h" #include "nvim/debugger.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -405,7 +406,7 @@ char *get_exception_string(void *value, except_type_T type, char *cmdname, bool || (ascii_isdigit(p[3]) && p[4] == ':')))))) { if (*p == NUL || p == mesg) { - STRCAT(val, mesg); // 'E123' missing or at beginning + strcat(val, mesg); // 'E123' missing or at beginning } else { // '"filename" E123: message text' if (mesg[0] != '"' || p - 2 < &mesg[1] @@ -414,7 +415,7 @@ char *get_exception_string(void *value, except_type_T type, char *cmdname, bool continue; } - STRCAT(val, p); + strcat(val, p); p[-2] = NUL; snprintf(val + strlen(p), strlen(" (%s)"), " (%s)", &mesg[1]); p[-2] = '"'; @@ -848,7 +849,7 @@ void ex_if(exarg_T *eap) bool skip = CHECK_SKIP; bool error; - bool result = eval_to_bool(eap->arg, &error, eap, skip); + bool result = eval_to_bool(eap->arg, &error, eap, skip, false); if (!skip && !error) { if (result) { @@ -943,7 +944,7 @@ void ex_else(exarg_T *eap) if (skip && *eap->arg != '"' && ends_excmd(*eap->arg)) { semsg(_(e_invexpr2), eap->arg); } else { - result = eval_to_bool(eap->arg, &error, eap, skip); + result = eval_to_bool(eap->arg, &error, eap, skip, false); } // When throwing error exceptions, we want to throw always the first @@ -989,7 +990,7 @@ void ex_while(exarg_T *eap) int skip = CHECK_SKIP; if (eap->cmdidx == CMD_while) { // ":while bool-expr" - result = eval_to_bool(eap->arg, &error, eap, skip); + result = eval_to_bool(eap->arg, &error, eap, skip, false); } else { // ":for var in list-expr" evalarg_T evalarg; fill_evalarg_from_eap(&evalarg, eap, skip); diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index f18dc0f747..7d87e609ca 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -28,6 +28,7 @@ #include "nvim/digraph.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/vars.h" @@ -132,7 +133,8 @@ typedef struct { int did_wild_list; // did wild_list() recently int wim_index; // index in wim_flags[] int save_msg_scroll; - int save_State; // remember State when called + int save_State; // remember State when called + int prev_cmdpos; char *save_p_icm; int some_key_typed; // one of the keys was typed // mouse drag and release events are ignored, unless they are @@ -222,6 +224,12 @@ static int cmdpreview_ns = 0; static const char e_active_window_or_buffer_changed_or_deleted[] = N_("E199: Active window or buffer changed or deleted"); +static void trigger_cmd_autocmd(int typechar, event_T evt) +{ + char typestr[2] = { (char)typechar, NUL }; + apply_autocmds(evt, typestr, typestr, false, curbuf); +} + static void save_viewstate(win_T *wp, viewstate_T *vs) FUNC_ATTR_NONNULL_ALL { @@ -259,6 +267,18 @@ static void init_incsearch_state(incsearch_state_T *s) save_viewstate(curwin, &s->old_viewstate); } +static void set_search_match(pos_T *t) +{ + // First move cursor to end of match, then to the start. This + // moves the whole match onto the screen when 'nowrap' is set. + t->lnum += search_match_lines; + t->col = search_match_endcol; + if (t->lnum > curbuf->b_ml.ml_line_count) { + t->lnum = curbuf->b_ml.ml_line_count; + coladvance(curwin, MAXCOL); + } +} + // Return true when 'incsearch' highlighting is to be done. // Sets search_first_line and search_last_line to the address range. static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_state_T *s, @@ -382,13 +402,8 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s parse_cmd_address(&ea, &dummy, true); if (ea.addr_count > 0) { // Allow for reverse match. - if (ea.line2 < ea.line1) { - search_first_line = ea.line2; - search_last_line = ea.line1; - } else { - search_first_line = ea.line1; - search_last_line = ea.line2; - } + search_first_line = MIN(ea.line1, ea.line1); + search_last_line = MAX(ea.line2, ea.line1); } else if (cmd[0] == 's' && cmd[1] != 'o') { // :s defaults to the current line search_first_line = curwin->w_cursor.lnum; @@ -683,6 +698,7 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear .indent = indent, .save_msg_scroll = msg_scroll, .save_State = State, + .prev_cmdpos = -1, .ignore_drag_release = true, }; CommandLineState *s = &state; @@ -1025,11 +1041,7 @@ static int command_line_handle_ctrl_bsl(CommandLineState *s) // Restore the cursor or use the position set with // set_cmdline_pos(). - if (new_cmdpos > ccline.cmdlen) { - ccline.cmdpos = ccline.cmdlen; - } else { - ccline.cmdpos = new_cmdpos; - } + ccline.cmdpos = MIN(ccline.cmdlen, new_cmdpos); KeyTyped = false; // Don't do p_wc completion. redrawcmd(); @@ -1649,11 +1661,7 @@ static int command_line_insert_reg(CommandLineState *s) KeyTyped = false; // Don't do p_wc completion. if (new_cmdpos >= 0) { // set_cmdline_pos() was used - if (new_cmdpos > ccline.cmdlen) { - ccline.cmdpos = ccline.cmdlen; - } else { - ccline.cmdpos = new_cmdpos; - } + ccline.cmdpos = MIN(ccline.cmdlen, new_cmdpos); } } new_cmdpos = save_new_cmdpos; @@ -2110,7 +2118,7 @@ static int command_line_handle_key(CommandLineState *s) s->do_abbr = false; // don't do abbreviation now ccline.special_char = NUL; // may need to remove ^ when composing char was typed - if (utf_iscomposing(s->c) && !cmd_silent) { + if (utf_iscomposing_first(s->c) && !cmd_silent) { if (ui_has(kUICmdline)) { // TODO(bfredl): why not make unputcmdline also work with true? unputcmdline(); @@ -2174,6 +2182,12 @@ static int command_line_handle_key(CommandLineState *s) static int command_line_not_changed(CommandLineState *s) { + // Trigger CursorMovedC autocommands. + if (ccline.cmdpos != s->prev_cmdpos) { + trigger_cmd_autocmd(get_cmdline_type(), EVENT_CURSORMOVEDC); + s->prev_cmdpos = ccline.cmdpos; + } + // Incremental searches for "/" and "?": // Enter command_line_not_changed() when a character has been read but the // command line did not change. Then we only search and redraw if something @@ -2532,6 +2546,10 @@ static bool cmdpreview_may_show(CommandLineState *s) goto end; } + // Flush now: external cmdline may itself wish to update the screen which is + // currently disallowed during cmdpreview(no longer needed in case that changes). + cmdline_ui_flush(); + // Swap invalid command range if needed if ((ea.argt & EX_RANGE) && ea.line1 > ea.line2) { linenr_T lnum = ea.line1; @@ -2647,6 +2665,12 @@ static int command_line_changed(CommandLineState *s) // Trigger CmdlineChanged autocommands. do_autocmd_cmdlinechanged(s->firstc > 0 ? s->firstc : '-'); + // Trigger CursorMovedC autocommands. + if (ccline.cmdpos != s->prev_cmdpos) { + trigger_cmd_autocmd(get_cmdline_type(), EVENT_CURSORMOVEDC); + s->prev_cmdpos = ccline.cmdpos; + } + const bool prev_cmdpreview = cmdpreview; if (s->firstc == ':' && current_sctx.sc_sid == 0 // only if interactive @@ -3004,7 +3028,6 @@ void realloc_cmdbuff(int len) // there, thus copy up to the NUL and add a NUL. memmove(ccline.cmdbuff, p, (size_t)ccline.cmdlen); ccline.cmdbuff[ccline.cmdlen] = NUL; - xfree(p); if (ccline.xpc != NULL && ccline.xpc->xp_pattern != NULL @@ -3018,6 +3041,8 @@ void realloc_cmdbuff(int len) ccline.xpc->xp_pattern = ccline.cmdbuff + i; } } + + xfree(p); } enum { MAX_CB_ERRORS = 1, }; @@ -3450,11 +3475,9 @@ void cmdline_screen_cleared(void) /// called by ui_flush, do what redraws necessary to keep cmdline updated. void cmdline_ui_flush(void) { - static bool flushing = false; - if (!ui_has(kUICmdline) || flushing) { + if (!ui_has(kUICmdline)) { return; } - flushing = true; int level = ccline.level; CmdlineInfo *line = &ccline; while (level > 0 && line) { @@ -3469,7 +3492,6 @@ void cmdline_ui_flush(void) } line = line->prev_ccline; } - flushing = false; } // Put a character on the command line. Shifts the following text to the @@ -3524,10 +3546,6 @@ void unputcmdline(void) // called afterwards. void put_on_cmdline(const char *str, int len, bool redraw) { - int i; - int m; - int c; - if (len < 0) { len = (int)strlen(str); } @@ -3541,7 +3559,8 @@ void put_on_cmdline(const char *str, int len, bool redraw) ccline.cmdlen += len; } else { // Count nr of characters in the new string. - m = 0; + int m = 0; + int i; for (i = 0; i < len; i += utfc_ptr2len(str + i)) { m++; } @@ -3565,9 +3584,11 @@ void put_on_cmdline(const char *str, int len, bool redraw) { // When the inserted text starts with a composing character, // backup to the character before it. There could be two of them. - i = 0; - c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos); - while (ccline.cmdpos > 0 && utf_iscomposing(c)) { + int i = 0; + int c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos); + // TODO(bfredl): this can be corrected/simplified as utf_head_off implements the + // correct grapheme cluster breaks + while (ccline.cmdpos > 0 && utf_iscomposing_legacy(c)) { i = utf_head_off(ccline.cmdbuff, ccline.cmdbuff + ccline.cmdpos - 1) + 1; ccline.cmdpos -= i; len += i; @@ -3597,7 +3618,7 @@ void put_on_cmdline(const char *str, int len, bool redraw) if (redraw && !cmd_silent) { msg_no_more = true; - i = cmdline_row; + int i = cmdline_row; cursorcmd(); draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); // Avoid clearing the rest of the line too often. @@ -3606,6 +3627,7 @@ void put_on_cmdline(const char *str, int len, bool redraw) } msg_no_more = false; } + int m; if (KeyTyped) { m = Columns * Rows; if (m < 0) { // overflow, Columns or Rows at weird value @@ -3614,8 +3636,8 @@ void put_on_cmdline(const char *str, int len, bool redraw) } else { m = MAXCOL; } - for (i = 0; i < len; i++) { - c = cmdline_charsize(ccline.cmdpos); + for (int i = 0; i < len; i++) { + int c = cmdline_charsize(ccline.cmdpos); // count ">" for a double-wide char that doesn't fit. correct_screencol(ccline.cmdpos, c, &ccline.cmdspos); // Stop cursor at the end of the screen, but do increment the @@ -3625,9 +3647,7 @@ void put_on_cmdline(const char *str, int len, bool redraw) ccline.cmdspos += c; } c = utfc_ptr2len(ccline.cmdbuff + ccline.cmdpos) - 1; - if (c > len - i - 1) { - c = len - i - 1; - } + c = MIN(c, len - i - 1); ccline.cmdpos += c; i += c; ccline.cmdpos++; @@ -3864,17 +3884,13 @@ void cursorcmd(void) } if (ui_has(kUICmdline)) { - if (ccline.redraw_state < kCmdRedrawPos) { - ccline.redraw_state = kCmdRedrawPos; - } + ccline.redraw_state = MAX(ccline.redraw_state, kCmdRedrawPos); return; } msg_row = cmdline_row + (ccline.cmdspos / Columns); msg_col = ccline.cmdspos % Columns; - if (msg_row >= Rows) { - msg_row = Rows - 1; - } + msg_row = MIN(msg_row, Rows - 1); msg_cursor_goto(msg_row, msg_col); } @@ -4070,18 +4086,22 @@ static char *get_cmdline_completion(void) return NULL; } - set_expand_context(p->xpc); - if (p->xpc->xp_context == EXPAND_UNSUCCESSFUL) { + int xp_context = p->xpc->xp_context; + if (xp_context == EXPAND_NOTHING) { + set_expand_context(p->xpc); + xp_context = p->xpc->xp_context; + p->xpc->xp_context = EXPAND_NOTHING; + } + if (xp_context == EXPAND_UNSUCCESSFUL) { return NULL; } - char *cmd_compl = get_user_cmd_complete(p->xpc, p->xpc->xp_context); + char *cmd_compl = get_user_cmd_complete(NULL, xp_context); if (cmd_compl == NULL) { return NULL; } - if (p->xpc->xp_context == EXPAND_USER_LIST - || p->xpc->xp_context == EXPAND_USER_DEFINED) { + if (xp_context == EXPAND_USER_LIST || xp_context == EXPAND_USER_DEFINED) { size_t buflen = strlen(cmd_compl) + strlen(p->xpc->xp_arg) + 2; char *buffer = xmalloc(buflen); snprintf(buffer, buflen, "%s,%s", cmd_compl, p->xpc->xp_arg); @@ -4112,6 +4132,15 @@ void f_getcmdpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) rettv->vval.v_number = p != NULL ? p->cmdpos + 1 : 0; } +/// "getcmdprompt()" function +void f_getcmdprompt(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + CmdlineInfo *p = get_ccline_ptr(); + rettv->v_type = VAR_STRING; + rettv->vval.v_string = p != NULL && p->cmdprompt != NULL + ? xstrdup(p->cmdprompt) : NULL; +} + /// "getcmdscreenpos()" function void f_getcmdscreenpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { @@ -4166,11 +4195,8 @@ static int set_cmdline_pos(int pos) // The position is not set directly but after CTRL-\ e or CTRL-R = has // changed the command line. - if (pos < 0) { - new_cmdpos = 0; - } else { - new_cmdpos = pos; - } + new_cmdpos = MAX(0, pos); + return 0; } @@ -4276,7 +4302,7 @@ const char *did_set_cedit(optset_T *args) cedit_key = -1; } else { int n = string_to_key(p_cedit); - if (vim_isprintc(n)) { + if (n == 0 || vim_isprintc(n)) { return e_invarg; } cedit_key = n; @@ -4297,7 +4323,6 @@ static int open_cmdwin(void) win_T *old_curwin = curwin; int i; garray_T winsizes; - char typestr[2]; int save_restart_edit = restart_edit; int save_State = State; bool save_exmode = exmode_active; @@ -4440,9 +4465,7 @@ static int open_cmdwin(void) cmdwin_result = 0; // Trigger CmdwinEnter autocommands. - typestr[0] = (char)cmdwin_type; - typestr[1] = NUL; - apply_autocmds(EVENT_CMDWINENTER, typestr, typestr, false, curbuf); + trigger_cmd_autocmd(cmdwin_type, EVENT_CMDWINENTER); if (restart_edit != 0) { // autocmd with ":startinsert" stuffcharReadbuff(K_NOP); } @@ -4460,7 +4483,7 @@ static int open_cmdwin(void) const bool save_KeyTyped = KeyTyped; // Trigger CmdwinLeave autocommands. - apply_autocmds(EVENT_CMDWINLEAVE, typestr, typestr, false, curbuf); + trigger_cmd_autocmd(cmdwin_type, EVENT_CMDWINLEAVE); // Restore KeyTyped in case it is modified by autocommands KeyTyped = save_KeyTyped; @@ -4623,14 +4646,132 @@ char *script_get(exarg_T *const eap, size_t *const lenp) return (char *)ga.ga_data; } -static void set_search_match(pos_T *t) +/// This function is used by f_input() and f_inputdialog() functions. The third +/// argument to f_input() specifies the type of completion to use at the +/// prompt. The third argument to f_inputdialog() specifies the value to return +/// when the user cancels the prompt. +void get_user_input(const typval_T *const argvars, typval_T *const rettv, const bool inputdialog, + const bool secret) + FUNC_ATTR_NONNULL_ALL { - // First move cursor to end of match, then to the start. This - // moves the whole match onto the screen when 'nowrap' is set. - t->lnum += search_match_lines; - t->col = search_match_endcol; - if (t->lnum > curbuf->b_ml.ml_line_count) { - t->lnum = curbuf->b_ml.ml_line_count; - coladvance(curwin, MAXCOL); + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + + const char *prompt; + const char *defstr = ""; + typval_T *cancelreturn = NULL; + typval_T cancelreturn_strarg2 = TV_INITIAL_VALUE; + const char *xp_name = NULL; + Callback input_callback = { .type = kCallbackNone }; + char prompt_buf[NUMBUFLEN]; + char defstr_buf[NUMBUFLEN]; + char cancelreturn_buf[NUMBUFLEN]; + char xp_name_buf[NUMBUFLEN]; + char def[1] = { 0 }; + if (argvars[0].v_type == VAR_DICT) { + if (argvars[1].v_type != VAR_UNKNOWN) { + emsg(_("E5050: {opts} must be the only argument")); + return; + } + dict_T *const dict = argvars[0].vval.v_dict; + prompt = tv_dict_get_string_buf_chk(dict, S_LEN("prompt"), prompt_buf, ""); + if (prompt == NULL) { + return; + } + defstr = tv_dict_get_string_buf_chk(dict, S_LEN("default"), defstr_buf, ""); + if (defstr == NULL) { + return; + } + dictitem_T *cancelreturn_di = tv_dict_find(dict, S_LEN("cancelreturn")); + if (cancelreturn_di != NULL) { + cancelreturn = &cancelreturn_di->di_tv; + } + xp_name = tv_dict_get_string_buf_chk(dict, S_LEN("completion"), + xp_name_buf, def); + if (xp_name == NULL) { // error + return; + } + if (xp_name == def) { // default to NULL + xp_name = NULL; + } + if (!tv_dict_get_callback(dict, S_LEN("highlight"), &input_callback)) { + return; + } + } else { + prompt = tv_get_string_buf_chk(&argvars[0], prompt_buf); + if (prompt == NULL) { + return; + } + if (argvars[1].v_type != VAR_UNKNOWN) { + defstr = tv_get_string_buf_chk(&argvars[1], defstr_buf); + if (defstr == NULL) { + return; + } + if (argvars[2].v_type != VAR_UNKNOWN) { + const char *const strarg2 = tv_get_string_buf_chk(&argvars[2], cancelreturn_buf); + if (strarg2 == NULL) { + return; + } + if (inputdialog) { + cancelreturn_strarg2.v_type = VAR_STRING; + cancelreturn_strarg2.vval.v_string = (char *)strarg2; + cancelreturn = &cancelreturn_strarg2; + } else { + xp_name = strarg2; + } + } + } + } + + int xp_type = EXPAND_NOTHING; + char *xp_arg = NULL; + if (xp_name != NULL) { + // input() with a third argument: completion + const int xp_namelen = (int)strlen(xp_name); + + uint32_t argt = 0; + if (parse_compl_arg(xp_name, xp_namelen, &xp_type, + &argt, &xp_arg) == FAIL) { + return; + } + } + + const bool cmd_silent_save = cmd_silent; + + cmd_silent = false; // Want to see the prompt. + // Only the part of the message after the last NL is considered as + // prompt for the command line, unlsess cmdline is externalized + const char *p = prompt; + if (!ui_has(kUICmdline)) { + const char *lastnl = strrchr(prompt, '\n'); + if (lastnl != NULL) { + p = lastnl + 1; + msg_start(); + msg_clr_eos(); + msg_puts_len(prompt, p - prompt, get_echo_attr()); + msg_didout = false; + msg_starthere(); + } + } + cmdline_row = msg_row; + + stuffReadbuffSpec(defstr); + + const int save_ex_normal_busy = ex_normal_busy; + ex_normal_busy = 0; + rettv->vval.v_string = getcmdline_prompt(secret ? NUL : '@', p, get_echo_attr(), + xp_type, xp_arg, input_callback); + ex_normal_busy = save_ex_normal_busy; + callback_free(&input_callback); + + if (rettv->vval.v_string == NULL && cancelreturn != NULL) { + tv_copy(cancelreturn, rettv); } + + xfree(xp_arg); + + // Since the user typed this, no need to wait for return. + need_wait_return = false; + msg_didout = false; + cmd_silent = cmd_silent_save; } diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c index 0e5d2fe4f5..50ee197ef4 100644 --- a/src/nvim/ex_session.c +++ b/src/nvim/ex_session.c @@ -15,6 +15,7 @@ #include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/buffer_defs.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c index 3236590010..c20c7dea23 100644 --- a/src/nvim/extmark.c +++ b/src/nvim/extmark.c @@ -54,12 +54,12 @@ /// must not be used during iteration! void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col, int end_row, colnr_T end_col, DecorInline decor, uint16_t decor_flags, bool right_gravity, - bool end_right_gravity, bool no_undo, bool invalidate, bool scoped, Error *err) + bool end_right_gravity, bool no_undo, bool invalidate, Error *err) { uint32_t *ns = map_put_ref(uint32_t, uint32_t)(buf->b_extmark_ns, ns_id, NULL, NULL); uint32_t id = idp ? *idp : 0; - uint16_t flags = mt_flags(right_gravity, no_undo, invalidate, decor.ext, scoped) | decor_flags; + uint16_t flags = mt_flags(right_gravity, no_undo, invalidate, decor.ext) | decor_flags; if (id == 0) { id = ++*ns; } else { @@ -70,24 +70,19 @@ void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col extmark_del_id(buf, ns_id, id); } else { assert(marktree_itr_valid(itr)); - bool invalid = mt_invalid(old_mark); if (old_mark.pos.row == row && old_mark.pos.col == col) { // not paired: we can revise in place - if (!invalid && mt_decor_any(old_mark)) { - // TODO(bfredl): conflict of concerns: buf_decor_remove() must process - // the buffer as if MT_FLAG_DECOR_SIGNTEXT is already removed, however - // marktree must precisely adjust the set of flags from the old set to the new - uint16_t save_flags = mt_itr_rawkey(itr).flags; - mt_itr_rawkey(itr).flags &= (uint16_t) ~MT_FLAG_DECOR_SIGNTEXT; + if (!mt_invalid(old_mark) && mt_decor_any(old_mark)) { + mt_itr_rawkey(itr).flags &= (uint16_t) ~MT_FLAG_EXTERNAL_MASK; buf_decor_remove(buf, row, row, col, mt_decor(old_mark), true); - mt_itr_rawkey(itr).flags = save_flags; } - marktree_revise_flags(buf->b_marktree, itr, flags); + mt_itr_rawkey(itr).flags |= flags; mt_itr_rawkey(itr).decor_data = decor.data; + marktree_revise_meta(buf->b_marktree, itr, old_mark); goto revised; } marktree_del_itr(buf->b_marktree, itr, false); - if (!invalid) { + if (!mt_invalid(old_mark)) { buf_decor_remove(buf, old_mark.pos.row, old_mark.pos.row, old_mark.pos.col, mt_decor(old_mark), true); } @@ -116,9 +111,10 @@ static void extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col, bool { MarkTreeIter itr[1] = { 0 }; MTKey key = marktree_lookup(buf->b_marktree, mark, itr); - if (key.pos.row < 0 || (key.pos.row == row && key.pos.col == col)) { - return; - } + bool move = key.pos.row >= 0 && (key.pos.row != row || key.pos.col != col); + // Already valid keys were being revalidated, presumably when encountering a + // SavePos from a modified mark. Avoid adding that to the decor again. + invalid = invalid && mt_invalid(key); // Only the position before undo needs to be redrawn here, // as the position after undo should be marked as changed. @@ -130,19 +126,22 @@ static void extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col, bool int row2 = 0; if (invalid) { mt_itr_rawkey(itr).flags &= (uint16_t) ~MT_FLAG_INVALID; - } else if (key.flags & MT_FLAG_DECOR_SIGNTEXT && buf->b_signcols.autom) { + marktree_revise_meta(buf->b_marktree, itr, key); + } else if (move && key.flags & MT_FLAG_DECOR_SIGNTEXT && buf->b_signcols.autom) { MTPos end = marktree_get_altpos(buf->b_marktree, key, NULL); row1 = MIN(end.row, MIN(key.pos.row, row)); row2 = MAX(end.row, MAX(key.pos.row, row)); buf_signcols_count_range(buf, row1, row2, 0, kTrue); } - marktree_move(buf->b_marktree, itr, row, col); + if (move) { + marktree_move(buf->b_marktree, itr, row, col); + } if (invalid) { - MTPos end = marktree_get_altpos(buf->b_marktree, key, NULL); - buf_put_decor(buf, mt_decor(key), row, end.row); - } else if (key.flags & MT_FLAG_DECOR_SIGNTEXT && buf->b_signcols.autom) { + row2 = mt_paired(key) ? marktree_get_altpos(buf->b_marktree, key, NULL).row : row; + buf_put_decor(buf, mt_decor(key), row, row2); + } else if (move && key.flags & MT_FLAG_DECOR_SIGNTEXT && buf->b_signcols.autom) { buf_signcols_count_range(buf, row1, row2, 0, kNone); } } @@ -391,6 +390,7 @@ void extmark_splice_delete(buf_T *buf, int l_row, colnr_T l_col, int u_row, coln } else { invalidated = true; mt_itr_rawkey(itr).flags |= MT_FLAG_INVALID; + marktree_revise_meta(buf->b_marktree, itr, mark); buf_decor_remove(buf, mark.pos.row, endpos.row, mark.pos.col, mt_decor(mark), false); } } diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index a8b0dbddee..cdfd281718 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -52,7 +52,9 @@ #include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/autocmd_defs.h" -#include "nvim/buffer_defs.h" +#include "nvim/charset.h" +#include "nvim/cursor.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -63,6 +65,7 @@ #include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/message.h" +#include "nvim/normal.h" #include "nvim/option.h" #include "nvim/option_vars.h" #include "nvim/os/fs.h" @@ -349,23 +352,24 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i search_ctx->ffsc_stopdirs_v = xmalloc(sizeof(char *)); do { - char *helper; - void *ptr; - - helper = walker; - ptr = xrealloc(search_ctx->ffsc_stopdirs_v, - (dircount + 1) * sizeof(char *)); + char *helper = walker; + void *ptr = xrealloc(search_ctx->ffsc_stopdirs_v, + (dircount + 1) * sizeof(char *)); search_ctx->ffsc_stopdirs_v = ptr; walker = vim_strchr(walker, ';'); + assert(!walker || walker - helper >= 0); + size_t len = walker ? (size_t)(walker - helper) : strlen(helper); + // "" means ascent till top of directory tree. + if (*helper != NUL && !vim_isAbsName(helper) && len + 1 < MAXPATHL) { + // Make the stop dir an absolute path name. + xmemcpyz(ff_expand_buffer, helper, len); + search_ctx->ffsc_stopdirs_v[dircount - 1] = FullName_save(helper, len); + } else { + search_ctx->ffsc_stopdirs_v[dircount - 1] = xmemdupz(helper, len); + } if (walker) { - assert(walker - helper >= 0); - search_ctx->ffsc_stopdirs_v[dircount - 1] = xstrnsave(helper, (size_t)(walker - helper)); walker++; - } else { - // this might be "", which means ascent till top of directory tree. - search_ctx->ffsc_stopdirs_v[dircount - 1] = xstrdup(helper); } - dircount++; } while (walker != NULL); search_ctx->ffsc_stopdirs_v[dircount - 1] = NULL; @@ -451,7 +455,7 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i STRCPY(buf, ff_expand_buffer); STRCPY(buf + eb_len, search_ctx->ffsc_fix_path); if (os_isdir(buf)) { - STRCAT(ff_expand_buffer, search_ctx->ffsc_fix_path); + strcat(ff_expand_buffer, search_ctx->ffsc_fix_path); add_pathsep(ff_expand_buffer); } else { char *p = path_tail(search_ctx->ffsc_fix_path); @@ -479,7 +483,7 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i + strlen(search_ctx->ffsc_fix_path + len) + 1); STRCPY(temp, search_ctx->ffsc_fix_path + len); - STRCAT(temp, search_ctx->ffsc_wc_path); + strcat(temp, search_ctx->ffsc_wc_path); xfree(search_ctx->ffsc_wc_path); xfree(wc_path); search_ctx->ffsc_wc_path = temp; @@ -505,24 +509,36 @@ error_return: /// @return the stopdir string. Check that ';' is not escaped. char *vim_findfile_stopdir(char *buf) { - char *r_ptr = buf; - - while (*r_ptr != NUL && *r_ptr != ';') { - if (r_ptr[0] == '\\' && r_ptr[1] == ';') { - // Overwrite the escape char, - // use strlen(r_ptr) to move the trailing '\0'. - STRMOVE(r_ptr, r_ptr + 1); - r_ptr++; + for (; *buf != NUL && *buf != ';' && (buf[0] != '\\' || buf[1] != ';'); buf++) {} + char *dst = buf; + if (*buf == ';') { + goto is_semicolon; + } + if (*buf == NUL) { + goto is_nul; + } + goto start; + while (*buf != NUL && *buf != ';') { + if (buf[0] == '\\' && buf[1] == ';') { +start: + // Overwrite the escape char. + *dst++ = ';'; + buf += 2; + } else { + *dst++ = *buf++; } - r_ptr++; } - if (*r_ptr == ';') { - *r_ptr = 0; - r_ptr++; - } else if (*r_ptr == NUL) { - r_ptr = NULL; + assert(dst < buf); + *dst = NUL; + if (*buf == ';') { +is_semicolon: + *buf = NUL; + buf++; + } else { // if (*buf == NUL) +is_nul: + buf = NULL; } - return r_ptr; + return buf; } /// Clean up the given search context. Can handle a NULL pointer. @@ -669,7 +685,7 @@ char *vim_findfile(void *search_ctx_arg) ff_free_stack_element(stackp); goto fail; } - STRCAT(file_path, stackp->ffs_fix_path); + strcat(file_path, stackp->ffs_fix_path); if (!add_pathsep(file_path)) { ff_free_stack_element(stackp); goto fail; @@ -769,7 +785,7 @@ char *vim_findfile(void *search_ctx_arg) ff_free_stack_element(stackp); goto fail; } - STRCAT(file_path, search_ctx->ffsc_file_to_search); + strcat(file_path, search_ctx->ffsc_file_to_search); // Try without extra suffix and then with suffixes // from 'suffixesadd'. @@ -880,11 +896,12 @@ char *vim_findfile(void *search_ctx_arg) if (search_ctx->ffsc_start_dir && search_ctx->ffsc_stopdirs_v != NULL && !got_int) { ff_stack_T *sptr; + // path_end may point to the NUL or the previous path separator + ptrdiff_t plen = (path_end - search_ctx->ffsc_start_dir) + (*path_end != NUL); // is the last starting directory in the stop list? if (ff_path_in_stoplist(search_ctx->ffsc_start_dir, - (int)(path_end - search_ctx->ffsc_start_dir), - search_ctx->ffsc_stopdirs_v)) { + (size_t)plen, search_ctx->ffsc_stopdirs_v)) { break; } @@ -910,7 +927,7 @@ char *vim_findfile(void *search_ctx_arg) if (!add_pathsep(file_path)) { goto fail; } - STRCAT(file_path, search_ctx->ffsc_fix_path); + strcat(file_path, search_ctx->ffsc_fix_path); // create a new stack entry sptr = ff_create_stack_element(file_path, @@ -1219,7 +1236,7 @@ static void ff_clear(ff_search_ctx_T *search_ctx) /// check if the given path is in the stopdirs /// /// @return true if yes else false -static bool ff_path_in_stoplist(char *path, int path_len, char **stopdirs_v) +static bool ff_path_in_stoplist(char *path, size_t path_len, char **stopdirs_v) { // eat up trailing path separators, except the first while (path_len > 1 && vim_ispathsep(path[path_len - 1])) { @@ -1232,20 +1249,16 @@ static bool ff_path_in_stoplist(char *path, int path_len, char **stopdirs_v) } for (int i = 0; stopdirs_v[i] != NULL; i++) { - if ((int)strlen(stopdirs_v[i]) > path_len) { - // match for parent directory. So '/home' also matches - // '/home/rks'. Check for PATHSEP in stopdirs_v[i], else - // '/home/r' would also match '/home/rks' - if (path_fnamencmp(stopdirs_v[i], path, (size_t)path_len) == 0 - && vim_ispathsep(stopdirs_v[i][path_len])) { - return true; - } - } else { - if (path_fnamecmp(stopdirs_v[i], path) == 0) { - return true; - } + // match for parent directory. So '/home' also matches + // '/home/rks'. Check for PATHSEP in stopdirs_v[i], else + // '/home/r' would also match '/home/rks' + if (path_fnamencmp(stopdirs_v[i], path, path_len) == 0 + && (strlen(stopdirs_v[i]) <= path_len + || vim_ispathsep(stopdirs_v[i][path_len]))) { + return true; } } + return false; } @@ -1493,6 +1506,225 @@ theend: return file_name; } +/// Get the file name at the cursor. +/// If Visual mode is active, use the selected text if it's in one line. +/// Returns the name in allocated memory, NULL for failure. +char *grab_file_name(int count, linenr_T *file_lnum) +{ + int options = FNAME_MESS | FNAME_EXP | FNAME_REL | FNAME_UNESC; + if (VIsual_active) { + size_t len; + char *ptr; + if (get_visual_text(NULL, &ptr, &len) == FAIL) { + return NULL; + } + // Only recognize ":123" here + if (file_lnum != NULL && ptr[len] == ':' && isdigit((uint8_t)ptr[len + 1])) { + char *p = ptr + len + 1; + + *file_lnum = getdigits_int32(&p, false, 0); + } + return find_file_name_in_path(ptr, len, options, count, curbuf->b_ffname); + } + return file_name_at_cursor(options | FNAME_HYP, count, file_lnum); +} + +/// Return the file name under or after the cursor. +/// +/// The 'path' option is searched if the file name is not absolute. +/// The string returned has been alloc'ed and should be freed by the caller. +/// NULL is returned if the file name or file is not found. +/// +/// options: +/// FNAME_MESS give error messages +/// FNAME_EXP expand to path +/// FNAME_HYP check for hypertext link +/// FNAME_INCL apply "includeexpr" +char *file_name_at_cursor(int options, int count, linenr_T *file_lnum) +{ + return file_name_in_line(get_cursor_line_ptr(), + curwin->w_cursor.col, options, count, curbuf->b_ffname, + file_lnum); +} + +/// @param rel_fname file we are searching relative to +/// @param file_lnum line number after the file name +/// +/// @return the name of the file under or after ptr[col]. +/// +/// Otherwise like file_name_at_cursor(). +char *file_name_in_line(char *line, int col, int options, int count, char *rel_fname, + linenr_T *file_lnum) +{ + // search forward for what could be the start of a file name + char *ptr = line + col; + while (*ptr != NUL && !vim_isfilec((uint8_t)(*ptr))) { + MB_PTR_ADV(ptr); + } + if (*ptr == NUL) { // nothing found + if (options & FNAME_MESS) { + emsg(_("E446: No file name under cursor")); + } + return NULL; + } + + size_t len; + bool in_type = true; + bool is_url = false; + + // Search backward for first char of the file name. + // Go one char back to ":" before "//", or to the drive letter before ":\" (even if ":" + // is not in 'isfname'). + while (ptr > line) { + if ((len = (size_t)(utf_head_off(line, ptr - 1))) > 0) { + ptr -= len + 1; + } else if (vim_isfilec((uint8_t)ptr[-1]) || ((options & FNAME_HYP) && path_is_url(ptr - 1))) { + ptr--; + } else { + break; + } + } + + // Search forward for the last char of the file name. + // Also allow ":/" when ':' is not in 'isfname'. + len = path_has_drive_letter(ptr) ? 2 : 0; + while (vim_isfilec((uint8_t)ptr[len]) || (ptr[len] == '\\' && ptr[len + 1] == ' ') + || ((options & FNAME_HYP) && path_is_url(ptr + len)) + || (is_url && vim_strchr(":?&=", (uint8_t)ptr[len]) != NULL)) { + // After type:// we also include :, ?, & and = as valid characters, so that + // http://google.com:8080?q=this&that=ok works. + if ((ptr[len] >= 'A' && ptr[len] <= 'Z') || (ptr[len] >= 'a' && ptr[len] <= 'z')) { + if (in_type && path_is_url(ptr + len + 1)) { + is_url = true; + } + } else { + in_type = false; + } + + if (ptr[len] == '\\' && ptr[len + 1] == ' ') { + // Skip over the "\" in "\ ". + len++; + } + len += (size_t)(utfc_ptr2len(ptr + len)); + } + + // If there is trailing punctuation, remove it. + // But don't remove "..", could be a directory name. + if (len > 2 && vim_strchr(".,:;!", (uint8_t)ptr[len - 1]) != NULL + && ptr[len - 2] != '.') { + len--; + } + + if (file_lnum != NULL) { + const char *line_english = " line "; + const char *line_transl = _(line_msg); + + // Get the number after the file name and a separator character. + // Also accept " line 999" with and without the same translation as + // used in last_set_msg(). + char *p = ptr + len; + if (strncmp(p, line_english, strlen(line_english)) == 0) { + p += strlen(line_english); + } else if (strncmp(p, line_transl, strlen(line_transl)) == 0) { + p += strlen(line_transl); + } else { + p = skipwhite(p); + } + if (*p != NUL) { + if (!isdigit((uint8_t)(*p))) { + p++; // skip the separator + } + p = skipwhite(p); + if (isdigit((uint8_t)(*p))) { + *file_lnum = (linenr_T)getdigits_long(&p, false, 0); + } + } + } + + return find_file_name_in_path(ptr, len, options, count, rel_fname); +} + +static char *eval_includeexpr(const char *const ptr, const size_t len) +{ + const sctx_T save_sctx = current_sctx; + set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len); + current_sctx = curbuf->b_p_script_ctx[BV_INEX].script_ctx; + + char *res = eval_to_string_safe(curbuf->b_p_inex, + was_set_insecurely(curwin, kOptIncludeexpr, OPT_LOCAL), + true); + + set_vim_var_string(VV_FNAME, NULL, 0); + current_sctx = save_sctx; + return res; +} + +/// Return the name of the file ptr[len] in 'path'. +/// Otherwise like file_name_at_cursor(). +/// +/// @param rel_fname file we are searching relative to +char *find_file_name_in_path(char *ptr, size_t len, int options, long count, char *rel_fname) +{ + char *file_name; + char *tofree = NULL; + + if (len == 0) { + return NULL; + } + + if ((options & FNAME_INCL) && *curbuf->b_p_inex != NUL) { + tofree = eval_includeexpr(ptr, len); + if (tofree != NULL) { + ptr = tofree; + len = strlen(ptr); + } + } + + if (options & FNAME_EXP) { + char *file_to_find = NULL; + char *search_ctx = NULL; + + file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS, + true, rel_fname, &file_to_find, &search_ctx); + + // If the file could not be found in a normal way, try applying + // 'includeexpr' (unless done already). + if (file_name == NULL + && !(options & FNAME_INCL) && *curbuf->b_p_inex != NUL) { + tofree = eval_includeexpr(ptr, len); + if (tofree != NULL) { + ptr = tofree; + len = strlen(ptr); + file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS, + true, rel_fname, &file_to_find, &search_ctx); + } + } + if (file_name == NULL && (options & FNAME_MESS)) { + char c = ptr[len]; + ptr[len] = NUL; + semsg(_("E447: Can't find file \"%s\" in path"), ptr); + ptr[len] = c; + } + + // Repeat finding the file "count" times. This matters when it + // appears several times in the path. + while (file_name != NULL && --count > 0) { + xfree(file_name); + file_name = find_file_in_path(ptr, len, options, false, rel_fname, + &file_to_find, &search_ctx); + } + + xfree(file_to_find); + vim_findfile_cleanup(search_ctx); + } else { + file_name = xstrnsave(ptr, len); + } + + xfree(tofree); + + return file_name; +} + void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause, bool pre) { static bool recursive = false; diff --git a/src/nvim/file_search.h b/src/nvim/file_search.h index 2450472681..f21d2b8468 100644 --- a/src/nvim/file_search.h +++ b/src/nvim/file_search.h @@ -2,6 +2,7 @@ #include <stddef.h> // IWYU pragma: keep +#include "nvim/pos_defs.h" // IWYU pragma: keep #include "nvim/types_defs.h" // IWYU pragma: keep #include "nvim/vim_defs.h" // IWYU pragma: keep @@ -12,6 +13,17 @@ enum { FINDFILE_BOTH = 2, ///< files and directories }; +/// Values for file_name_in_line() +enum { + FNAME_MESS = 1, ///< give error message + FNAME_EXP = 2, ///< expand to path + FNAME_HYP = 4, ///< check for hypertext link + FNAME_INCL = 8, ///< apply 'includeexpr' + FNAME_REL = 16, ///< ".." and "./" are relative to the (current) + ///< file instead of the current directory + FNAME_UNESC = 32, ///< remove backslashes used for escaping +}; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "file_search.h.generated.h" #endif diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index df9c4928c9..724d754ca7 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -27,6 +27,7 @@ #include "nvim/diff.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_eval.h" @@ -887,10 +888,7 @@ retry: // Use buffer >= 64K. Add linerest to double the size if the // line gets very long, to avoid a lot of copying. But don't // read more than 1 Mbyte at a time, so we can be interrupted. - size = 0x10000 + linerest; - if (size > 0x100000) { - size = 0x100000; - } + size = MIN(0x10000 + linerest, 0x100000); } // Protect against the argument of lalloc() going negative. @@ -2418,7 +2416,7 @@ char *modname(const char *fname, const char *ext, bool prepend_dot) // the file name has at most BASENAMELEN characters. if (strlen(ptr) > BASENAMELEN) { - ptr[BASENAMELEN] = '\0'; + ptr[BASENAMELEN] = NUL; } char *s = ptr + strlen(ptr); @@ -2656,7 +2654,6 @@ static int rename_with_tmp(const char *const from, const char *const to) int vim_rename(const char *from, const char *to) FUNC_ATTR_NONNULL_ALL { - char *errmsg = NULL; bool use_tmp_file = false; // When the names are identical, there is nothing to do. When they refer @@ -2700,61 +2697,57 @@ int vim_rename(const char *from, const char *to) } // Rename() failed, try copying the file. - int perm = os_getperm(from); - // For systems that support ACL: get the ACL from the original file. - vim_acl_T acl = os_get_acl(from); - int fd_in = os_open(from, O_RDONLY, 0); - if (fd_in < 0) { - os_free_acl(acl); + int ret = vim_copyfile(from, to); + if (ret != OK) { return -1; } - // Create the new file with same permissions as the original. - int fd_out = os_open(to, O_CREAT|O_EXCL|O_WRONLY|O_NOFOLLOW, perm); - if (fd_out < 0) { - close(fd_in); - os_free_acl(acl); - return -1; + if (os_fileinfo(from, &from_info)) { + os_remove(from); } - // Avoid xmalloc() here as vim_rename() is called by buf_write() when nvim - // is `preserve_exit()`ing. - char *buffer = try_malloc(WRITEBUFSIZE); - if (buffer == NULL) { - close(fd_out); - close(fd_in); - os_free_acl(acl); - return -1; - } + return 0; +} - int n; - while ((n = read_eintr(fd_in, buffer, WRITEBUFSIZE)) > 0) { - if (write_eintr(fd_out, buffer, (size_t)n) != n) { - errmsg = _("E208: Error writing to \"%s\""); - break; +/// Create the new file with same permissions as the original. +/// Return FAIL for failure, OK for success. +int vim_copyfile(const char *from, const char *to) +{ + char *errmsg = NULL; + +#ifdef HAVE_READLINK + FileInfo from_info; + if (os_fileinfo_link(from, &from_info) && S_ISLNK(from_info.stat.st_mode)) { + int ret = -1; + + char linkbuf[MAXPATHL + 1]; + ssize_t len = readlink(from, linkbuf, MAXPATHL); + if (len > 0) { + linkbuf[len] = NUL; + + // Create link + ret = symlink(linkbuf, to); } - } - xfree(buffer); - close(fd_in); - if (close(fd_out) < 0) { - errmsg = _("E209: Error closing \"%s\""); - } - if (n < 0) { - errmsg = _("E210: Error reading \"%s\""); - to = from; + return ret == 0 ? OK : FAIL; } -#ifndef UNIX // For Unix os_open() already set the permission. - os_setperm(to, perm); #endif + + // For systems that support ACL: get the ACL from the original file. + vim_acl_T acl = os_get_acl(from); + + if (os_copy(from, to, UV_FS_COPYFILE_EXCL) != 0) { + os_free_acl(acl); + return FAIL; + } + os_set_acl(to, acl); os_free_acl(acl); if (errmsg != NULL) { semsg(errmsg, to); - return -1; + return FAIL; } - os_remove(from); - return 0; + return OK; } static bool already_warned = false; @@ -2799,9 +2792,7 @@ int check_timestamps(int focus) bufref_T bufref; set_bufref(&bufref, buf); const int n = buf_check_timestamp(buf); - if (didit < n) { - didit = n; - } + didit = MAX(didit, n); if (n > 0 && !bufref_valid(&bufref)) { // Autocommands have removed the buffer, start at the first one again. buf = firstbuf; @@ -3191,11 +3182,7 @@ void buf_reload(buf_T *buf, int orig_mode, bool reload_options) // Restore the topline and cursor position and check it (lines may // have been removed). - if (old_topline > curbuf->b_ml.ml_line_count) { - curwin->w_topline = curbuf->b_ml.ml_line_count; - } else { - curwin->w_topline = old_topline; - } + curwin->w_topline = MIN(old_topline, curbuf->b_ml.ml_line_count); curwin->w_cursor = old_cursor; check_cursor(curwin); update_topline(curwin); @@ -3277,18 +3264,12 @@ static void vim_mktempdir(void) char tmp[TEMP_FILE_PATH_MAXLEN]; char path[TEMP_FILE_PATH_MAXLEN]; char user[40] = { 0 }; - char appname[40] = { 0 }; os_get_username(user, sizeof(user)); // Usernames may contain slashes! #19240 memchrsub(user, '/', '_', sizeof(user)); memchrsub(user, '\\', '_', sizeof(user)); - // Appname may be a relative path, replace slashes to make it name-like. - xstrlcpy(appname, get_appname(), sizeof(appname)); - memchrsub(appname, '/', '%', sizeof(appname)); - memchrsub(appname, '\\', '%', sizeof(appname)); - // Make sure the umask doesn't remove the executable bit. // "repl" has been reported to use "0177". mode_t umask_save = umask(0077); @@ -3296,14 +3277,15 @@ static void vim_mktempdir(void) // Expand environment variables, leave room for "/tmp/nvim.<user>/XXXXXX/999999999". expand_env((char *)temp_dirs[i], tmp, TEMP_FILE_PATH_MAXLEN - 64); if (!os_isdir(tmp)) { + if (strequal("$TMPDIR", temp_dirs[i])) { + WLOG("$TMPDIR tempdir not a directory (or does not exist): %s", tmp); + } continue; } // "/tmp/" exists, now try to create "/tmp/nvim.<user>/". add_pathsep(tmp); - - xstrlcat(tmp, appname, sizeof(tmp)); - xstrlcat(tmp, ".", sizeof(tmp)); + xstrlcat(tmp, "nvim.", sizeof(tmp)); xstrlcat(tmp, user, sizeof(tmp)); os_mkdir(tmp, 0700); // Always create, to avoid a race. bool owned = os_file_owned(tmp); @@ -3329,7 +3311,7 @@ static void vim_mktempdir(void) #endif // If our "root" tempdir is invalid or fails, proceed without "<user>/". // Else user1 could break user2 by creating "/tmp/nvim.user2/". - tmp[strlen(tmp) - strlen(user)] = '\0'; + tmp[strlen(tmp) - strlen(user)] = NUL; } // Now try to create "/tmp/nvim.<user>/XXXXXX". @@ -3636,6 +3618,7 @@ bool match_file_list(char *list, char *sfname, char *ffname) /// @param pat_end first char after pattern or NULL /// @param allow_dirs Result passed back out in here /// @param no_bslash Don't use a backward slash as pathsep +/// (only makes a difference when BACKSLASH_IN_FILENAME in defined) /// /// @return NULL on failure. char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs, int no_bslash) diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 59a4dc6aad..e7231c31ab 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -22,6 +22,7 @@ #include "nvim/decoration.h" #include "nvim/diff.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/ex_session.h" @@ -247,9 +248,7 @@ bool hasFoldingWin(win_T *const win, const linenr_T lnum, linenr_T *const firstp return false; } - if (last > win->w_buffer->b_ml.ml_line_count) { - last = win->w_buffer->b_ml.ml_line_count; - } + last = MIN(last, win->w_buffer->b_ml.ml_line_count); if (lastp != NULL) { *lastp = last; } @@ -617,15 +616,11 @@ void foldCreate(win_T *wp, pos_T start, pos_T end) ga_grow(&fold_ga, cont); // If the first fold starts before the new fold, let the new fold // start there. Otherwise the existing fold would change. - if (start_rel.lnum > fp->fd_top) { - start_rel.lnum = fp->fd_top; - } + start_rel.lnum = MIN(start_rel.lnum, fp->fd_top); // When last contained fold isn't completely contained, adjust end // of new fold. - if (end_rel.lnum < fp[cont - 1].fd_top + fp[cont - 1].fd_len - 1) { - end_rel.lnum = fp[cont - 1].fd_top + fp[cont - 1].fd_len - 1; - } + end_rel.lnum = MAX(end_rel.lnum, fp[cont - 1].fd_top + fp[cont - 1].fd_len - 1); // Move contained folds to inside new fold memmove(fold_ga.ga_data, fp, sizeof(fold_T) * (size_t)cont); fold_ga.ga_len += cont; @@ -721,12 +716,8 @@ void deleteFold(win_T *const wp, const linenr_T start, const linenr_T end, const (int)(found_fp - (fold_T *)found_ga->ga_data), recursive); } else { - if (first_lnum > found_fp->fd_top + found_off) { - first_lnum = found_fp->fd_top + found_off; - } - if (last_lnum < lnum) { - last_lnum = lnum; - } + first_lnum = MIN(first_lnum, found_fp->fd_top + found_off); + last_lnum = MAX(last_lnum, lnum); if (!did_one) { parseMarker(wp); } @@ -787,14 +778,10 @@ void foldUpdate(win_T *wp, linenr_T top, linenr_T bot) } if (wp->w_folds.ga_len > 0) { - linenr_T maybe_small_start = top; - linenr_T maybe_small_end = bot; - // Mark all folds from top to bot (or bot to top) as maybe-small. - if (top > bot) { - maybe_small_start = bot; - maybe_small_end = top; - } + linenr_T maybe_small_start = MIN(top, bot); + linenr_T maybe_small_end = MAX(top, bot); + fold_T *fp; foldFind(&wp->w_folds, maybe_small_start, &fp); while (fp < (fold_T *)wp->w_folds.ga_data + wp->w_folds.ga_len @@ -1224,11 +1211,7 @@ static linenr_T setManualFoldWin(win_T *wp, linenr_T lnum, bool opening, bool re // Change from level-dependent folding to manual. if (use_level || fp->fd_flags == FD_LEVEL) { use_level = true; - if (level >= wp->w_p_fdl) { - fp->fd_flags = FD_CLOSED; - } else { - fp->fd_flags = FD_OPEN; - } + fp->fd_flags = level >= wp->w_p_fdl ? FD_CLOSED : FD_OPEN; fp2 = (fold_T *)fp->fd_nested.ga_data; for (int j = 0; j < fp->fd_nested.ga_len; j++) { fp2[j].fd_flags = FD_LEVEL; @@ -1353,6 +1336,9 @@ void deleteFoldRecurse(buf_T *bp, garray_T *gap) // foldMarkAdjust() {{{2 /// Update line numbers of folds for inserted/deleted lines. +/// +/// We are adjusting the folds in the range from line1 til line2, +/// make sure that line2 does not get smaller than line1 void foldMarkAdjust(win_T *wp, linenr_T line1, linenr_T line2, linenr_T amount, linenr_T amount_after) { @@ -1361,6 +1347,9 @@ void foldMarkAdjust(win_T *wp, linenr_T line1, linenr_T line2, linenr_T amount, if (amount == MAXLNUM && line2 >= line1 && line2 - line1 >= -amount_after) { line2 = line1 - amount_after - 1; } + if (line2 < line1) { + line2 = line1; + } // If appending a line in Insert mode, it should be included in the fold // just above the line. if ((State & MODE_INSERT) && amount == 1 && line2 == MAXLNUM) { @@ -1377,15 +1366,11 @@ static void foldMarkAdjustRecurse(win_T *wp, garray_T *gap, linenr_T line1, line return; } - linenr_T top; - // In Insert mode an inserted line at the top of a fold is considered part // of the fold, otherwise it isn't. - if ((State & MODE_INSERT) && amount == 1 && line2 == MAXLNUM) { - top = line1 + 1; - } else { - top = line1; - } + linenr_T top = ((State & MODE_INSERT) && amount == 1 && line2 == MAXLNUM) + ? line1 + 1 + : line1; // Find the fold containing or just below "line1". fold_T *fp; @@ -1479,9 +1464,7 @@ static int getDeepestNestingRecurse(garray_T *gap) fold_T *fp = (fold_T *)gap->ga_data; for (int i = 0; i < gap->ga_len; i++) { int level = getDeepestNestingRecurse(&fp[i].fd_nested) + 1; - if (level > maxlevel) { - maxlevel = level; - } + maxlevel = MAX(maxlevel, level); } return maxlevel; @@ -1597,7 +1580,6 @@ static void foldCreateMarkers(win_T *wp, pos_T start, pos_T end) static void foldAddMarker(buf_T *buf, pos_T pos, const char *marker, size_t markerlen) { char *cms = buf->b_p_cms; - char *newline; char *p = strstr(buf->b_p_cms, "%s"); bool line_is_comment = false; linenr_T lnum = pos.lnum; @@ -1613,7 +1595,7 @@ static void foldAddMarker(buf_T *buf, pos_T pos, const char *marker, size_t mark // Check if the line ends with an unclosed comment skip_comment(line, false, false, &line_is_comment); - newline = xmalloc(line_len + markerlen + strlen(cms) + 1); + char *newline = xmalloc(line_len + markerlen + strlen(cms) + 1); STRCPY(newline, line); // Append the marker to the end of the line if (p == NULL || line_is_comment) { @@ -1736,10 +1718,7 @@ char *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldinfo // Set "v:folddashes" to a string of "level" dashes. // Set "v:foldlevel" to "level". - int level = foldinfo.fi_level; - if (level > (int)sizeof(dashes) - 1) { - level = (int)sizeof(dashes) - 1; - } + int level = MIN(foldinfo.fi_level, (int)sizeof(dashes) - 1); memset(dashes, '-', (size_t)level); dashes[level] = NUL; set_vim_var_string(VV_FOLDDASHES, dashes, -1); @@ -1936,9 +1915,7 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot) // When deleting lines at the end of the buffer "top" can be past the end // of the buffer. - if (top > wp->w_buffer->b_ml.ml_line_count) { - top = wp->w_buffer->b_ml.ml_line_count; - } + top = MIN(top, wp->w_buffer->b_ml.ml_line_count); fline_T fline; @@ -2046,9 +2023,7 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot) if (fpn != NULL && current_fdl == fline.lvl) { linenr_T fold_end_lnum = fold_start_lnum + fpn->fd_len; - if (fold_end_lnum > bot) { - bot = fold_end_lnum; - } + bot = MAX(bot, fold_end_lnum); } } @@ -2126,9 +2101,7 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot) if (wp->w_redraw_top == 0 || wp->w_redraw_top > top) { wp->w_redraw_top = top; } - if (wp->w_redraw_bot < end) { - wp->w_redraw_bot = end; - } + wp->w_redraw_bot = MAX(wp->w_redraw_bot, end); } invalid_top = 0; @@ -2204,10 +2177,7 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *const gap, const int level, // and after the first line of the fold, set the level to zero to // force the fold to end. Do the same when had_end is set: Previous // line was marked as end of a fold. - lvl = flp->lvl; - if (lvl > MAX_LEVEL) { - lvl = MAX_LEVEL; - } + lvl = MIN(flp->lvl, MAX_LEVEL); if (flp->lnum > firstlnum && (level > lvl - flp->start || level >= flp->had_end)) { lvl = 0; @@ -2262,12 +2232,7 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *const gap, const int level, while (!got_int) { // set concat to 1 if it's allowed to concatenate this fold // with a previous one that touches it. - int concat; - if (flp->start != 0 || flp->had_end <= MAX_LEVEL) { - concat = 0; - } else { - concat = 1; - } + int concat = (flp->start != 0 || flp->had_end <= MAX_LEVEL) ? 0 : 1; // Find an existing fold to re-use. Preferably one that // includes startlnum, otherwise one that ends just before @@ -2423,9 +2388,7 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *const gap, const int level, if (lvl > level && fp != NULL) { // There is a nested fold, handle it recursively. // At least do one line (can happen when finish is true). - if (bot < flp->lnum) { - bot = flp->lnum; - } + bot = MAX(bot, flp->lnum); // Line numbers in the nested fold are relative to the start of // this fold. @@ -2555,9 +2518,7 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *const gap, const int level, // Need to redraw the lines we inspected, which might be further down than // was asked for. - if (bot < flp->lnum - 1) { - bot = flp->lnum - 1; - } + bot = MAX(bot, flp->lnum - 1); return bot; } @@ -2897,17 +2858,11 @@ static void foldlevelIndent(fline_T *flp) // depends on surrounding lines if (*s == NUL || vim_strchr(flp->wp->w_p_fdi, (uint8_t)(*s)) != NULL) { // first and last line can't be undefined, use level 0 - if (lnum == 1 || lnum == buf->b_ml.ml_line_count) { - flp->lvl = 0; - } else { - flp->lvl = -1; - } + flp->lvl = (lnum == 1 || lnum == buf->b_ml.ml_line_count) ? 0 : -1; } else { flp->lvl = get_indent_buf(buf, lnum) / get_sw_value(buf); } - if (flp->lvl > flp->wp->w_p_fdn) { - flp->lvl = (int)MAX(0, flp->wp->w_p_fdn); - } + flp->lvl = MIN(flp->lvl, (int)MAX(0, flp->wp->w_p_fdn)); } // foldlevelDiff() {{{2 @@ -2915,11 +2870,7 @@ static void foldlevelIndent(fline_T *flp) /// Doesn't use any caching. static void foldlevelDiff(fline_T *flp) { - if (diff_infold(flp->wp, flp->lnum + flp->off)) { - flp->lvl = 1; - } else { - flp->lvl = 0; - } + flp->lvl = (diff_infold(flp->wp, flp->lnum + flp->off)) ? 1 : 0; } // foldlevelExpr() {{{2 @@ -3066,11 +3017,7 @@ static void foldlevelMarker(fline_T *flp) if (n > 0) { flp->lvl = n; flp->lvl_next = n; - if (n <= start_lvl) { - flp->start = 1; - } else { - flp->start = n - start_lvl; - } + flp->start = MAX(n - start_lvl, 1); } } else { flp->lvl++; @@ -3087,9 +3034,7 @@ static void foldlevelMarker(fline_T *flp) flp->lvl = n; flp->lvl_next = n - 1; // never start a fold with an end marker - if (flp->lvl_next > start_lvl) { - flp->lvl_next = start_lvl; - } + flp->lvl_next = MIN(flp->lvl_next, start_lvl); } } else { flp->lvl_next--; @@ -3100,9 +3045,7 @@ static void foldlevelMarker(fline_T *flp) } // The level can't go negative, must be missing a start marker. - if (flp->lvl_next < 0) { - flp->lvl_next = 0; - } + flp->lvl_next = MAX(flp->lvl_next, 0); } // foldlevelSyntax() {{{2 @@ -3243,11 +3186,7 @@ static void foldclosed_both(typval_T *argvars, typval_T *rettv, bool end) linenr_T first; linenr_T last; if (hasFoldingWin(curwin, lnum, &first, &last, false, NULL)) { - if (end) { - rettv->vval.v_number = (varnumber_T)last; - } else { - rettv->vval.v_number = (varnumber_T)first; - } + rettv->vval.v_number = (varnumber_T)(end ? last : first); return; } } @@ -3314,7 +3253,7 @@ void f_foldtext(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) char *r = xmalloc(len); snprintf(r, len, txt, dashes, count); len = strlen(r); - STRCAT(r, s); + strcat(r, s); // remove 'foldmarker' and 'commentstring' foldtext_cleanup(r + len); rettv->vval.v_string = r; @@ -3335,9 +3274,7 @@ void f_foldtextresult(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) entered = true; linenr_T lnum = tv_get_lnum(argvars); // Treat illegal types and illegal string values for {lnum} the same. - if (lnum < 0) { - lnum = 0; - } + lnum = MAX(lnum, 0); foldinfo_T info = fold_info(curwin, lnum); if (info.fi_lines > 0) { diff --git a/src/nvim/garray.c b/src/nvim/garray.c index f87a196361..4f8ba30522 100644 --- a/src/nvim/garray.c +++ b/src/nvim/garray.c @@ -78,16 +78,12 @@ void ga_grow(garray_T *gap, int n) } // the garray grows by at least growsize - if (n < gap->ga_growsize) { - n = gap->ga_growsize; - } + n = MAX(n, gap->ga_growsize); // A linear growth is very inefficient when the array grows big. This // is a compromise between allocating memory that won't be used and too // many copy operations. A factor of 1.5 seems reasonable. - if (n < gap->ga_len / 2) { - n = gap->ga_len / 2; - } + n = MAX(n, gap->ga_len / 2); int new_maxlen = gap->ga_len + n; diff --git a/src/nvim/generators/c_grammar.lua b/src/nvim/generators/c_grammar.lua index 9ce9f3d7a6..ed6e30ea10 100644 --- a/src/nvim/generators/c_grammar.lua +++ b/src/nvim/generators/c_grammar.lua @@ -35,11 +35,7 @@ local cdoc_comment = P('///') * opt(Ct(Cg(rep(space) * rep(not_nl), 'comment'))) local c_preproc = P('#') * rep(not_nl) local dllexport = P('DLLEXPORT') * rep1(ws) -local typed_container = ( - (P('ArrayOf(') + P('DictionaryOf(') + P('Dict(')) - * rep1(any - P(')')) - * P(')') -) +local typed_container = ((P('ArrayOf(') + P('DictOf(') + P('Dict(')) * rep1(any - P(')')) * P(')')) local c_id = (typed_container + (letter * rep(alpha))) local c_void = P('void') @@ -91,7 +87,9 @@ local c_proto = Ct( * (P(';') + (P('{') * nl + (impl_line ^ 0) * P('}'))) ) -local c_field = Ct(Cg(c_id, 'type') * ws * Cg(c_id, 'name') * fill * P(';') * fill) +local dict_key = P('DictKey(') * Cg(rep1(any - P(')')), 'dict_key') * P(')') +local keyset_field = + Ct(Cg(c_id, 'type') * ws * Cg(c_id, 'name') * fill * (dict_key ^ -1) * fill * P(';') * fill) local c_keyset = Ct( P('typedef') * ws @@ -99,7 +97,7 @@ local c_keyset = Ct( * fill * P('{') * fill - * Cg(Ct(c_field ^ 1), 'fields') + * Cg(Ct(keyset_field ^ 1), 'fields') * P('}') * fill * P('Dict') diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua index 62c99ce082..9e0aa407a1 100644 --- a/src/nvim/generators/gen_api_dispatch.lua +++ b/src/nvim/generators/gen_api_dispatch.lua @@ -72,14 +72,19 @@ local keysets = {} local function add_keyset(val) local keys = {} local types = {} + local c_names = {} local is_set_name = 'is_set__' .. val.keyset_name .. '_' local has_optional = false for i, field in ipairs(val.fields) do + local dict_key = field.dict_key or field.name if field.type ~= 'Object' then - types[field.name] = field.type + types[dict_key] = field.type end if field.name ~= is_set_name and field.type ~= 'OptionalKeys' then - table.insert(keys, field.name) + table.insert(keys, dict_key) + if dict_key ~= field.name then + c_names[dict_key] = field.name + end else if i > 1 then error("'is_set__{type}_' must be first if present") @@ -94,6 +99,7 @@ local function add_keyset(val) table.insert(keysets, { name = val.keyset_name, keys = keys, + c_names = c_names, types = types, has_optional = has_optional, }) @@ -210,15 +216,15 @@ for _, f in ipairs(functions) do end f_exported.parameters = {} for i, param in ipairs(f.parameters) do - if param[1] == 'DictionaryOf(LuaRef)' then - param = { 'Dictionary', param[2] } + if param[1] == 'DictOf(LuaRef)' then + param = { 'Dict', param[2] } elseif startswith(param[1], 'Dict(') then - param = { 'Dictionary', param[2] } + param = { 'Dict', param[2] } end f_exported.parameters[i] = param end if startswith(f.return_type, 'Dict(') then - f_exported.return_type = 'Dictionary' + f_exported.return_type = 'Dict' end exported_functions[#exported_functions + 1] = f_exported end @@ -306,6 +312,7 @@ local keysets_defs = assert(io.open(keysets_outputf, 'wb')) -- so that the dispatcher can find the C functions that you are creating! -- =========================================================================== output:write([[ +#include "nvim/errors.h" #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" #include "nvim/globals.h" @@ -331,19 +338,6 @@ output:write([[ keysets_defs:write('// IWYU pragma: private, include "nvim/api/private/dispatch.h"\n\n') for _, k in ipairs(keysets) do - local c_name = {} - - for i = 1, #k.keys do - -- some keys, like "register" are c keywords and get - -- escaped with a trailing _ in the struct. - if vim.endswith(k.keys[i], '_') then - local orig = k.keys[i] - k.keys[i] = string.sub(k.keys[i], 1, #k.keys[i] - 1) - c_name[k.keys[i]] = orig - k.types[k.keys[i]] = k.types[orig] - end - end - local neworder, hashfun = hashy.hashy_hash(k.name, k.keys, function(idx) return k.name .. '_table[' .. idx .. '].str' end) @@ -353,6 +347,8 @@ for _, k in ipairs(keysets) do local function typename(type) if type == 'HLGroupID' then return 'kObjectTypeInteger' + elseif type == 'StringArray' then + return 'kUnpackTypeStringArray' elseif type ~= nil then return 'kObjectType' .. type else @@ -373,7 +369,7 @@ for _, k in ipairs(keysets) do .. '", offsetof(KeyDict_' .. k.name .. ', ' - .. (c_name[key] or key) + .. (k.c_names[key] or key) .. '), ' .. typename(k.types[key]) .. ', ' @@ -410,7 +406,7 @@ local function real_type(type) if rv:match('Array') then rv = 'Array' else - rv = 'Dictionary' + rv = 'Dict' end end return rv @@ -470,7 +466,7 @@ for i = 1, #functions do output:write('\n ' .. converted .. ' = args.items[' .. (j - 1) .. '];\n') elseif rt:match('^KeyDict_') then converted = '&' .. converted - output:write('\n if (args.items[' .. (j - 1) .. '].type == kObjectTypeDictionary) {') --luacheck: ignore 631 + output:write('\n if (args.items[' .. (j - 1) .. '].type == kObjectTypeDict) {') --luacheck: ignore 631 output:write('\n memset(' .. converted .. ', 0, sizeof(*' .. converted .. '));') -- TODO: neeeee output:write( '\n if (!api_dict_to_keydict(' @@ -479,7 +475,7 @@ for i = 1, #functions do .. rt .. '_get_field, args.items[' .. (j - 1) - .. '].data.dictionary, error)) {' + .. '].data.dict, error)) {' ) output:write('\n goto cleanup;') output:write('\n }') @@ -558,7 +554,7 @@ for i = 1, #functions do ) end -- accept empty lua tables as empty dictionaries - if rt:match('^Dictionary') then + if rt:match('^Dict') then output:write( '\n } else if (args.items[' .. (j - 1) @@ -566,7 +562,7 @@ for i = 1, #functions do .. (j - 1) .. '].data.array.size == 0) {' ) --luacheck: ignore 631 - output:write('\n ' .. converted .. ' = (Dictionary)ARRAY_DICT_INIT;') + output:write('\n ' .. converted .. ' = (Dict)ARRAY_DICT_INIT;') end output:write('\n } else {') output:write( @@ -647,7 +643,7 @@ for i = 1, #functions do if string.match(ret_type, '^KeyDict_') then local table = string.sub(ret_type, 9) .. '_table' output:write( - '\n ret = DICTIONARY_OBJ(api_keydict_to_dict(&rv, ' + '\n ret = DICT_OBJ(api_keydict_to_dict(&rv, ' .. table .. ', ARRAY_SIZE(' .. table @@ -783,12 +779,12 @@ local function process_function(fn) local param = fn.parameters[j] local cparam = string.format('arg%u', j) local param_type = real_type(param[1]) - local extra = param_type == 'Dictionary' and 'false, ' or '' + local extra = param_type == 'Dict' and 'false, ' or '' local arg_free_code = '' if param[1] == 'Object' then extra = 'true, ' arg_free_code = 'api_luarefs_free_object(' .. cparam .. ');' - elseif param[1] == 'DictionaryOf(LuaRef)' then + elseif param[1] == 'DictOf(LuaRef)' then extra = 'true, ' arg_free_code = 'api_luarefs_free_dict(' .. cparam .. ');' elseif param[1] == 'LuaRef' then diff --git a/src/nvim/generators/gen_api_ui_events.lua b/src/nvim/generators/gen_api_ui_events.lua index 516b5ad5ae..3e8ae19c9a 100644 --- a/src/nvim/generators/gen_api_ui_events.lua +++ b/src/nvim/generators/gen_api_ui_events.lua @@ -54,7 +54,7 @@ local function call_ui_event_method(output, ev) local kind = ev.parameters[j][1] if kind ~= 'Object' then if kind == 'HlAttrs' then - kind = 'Dictionary' + kind = 'Dict' end output:write('\n || args.items[' .. (j - 1) .. '].type != kObjectType' .. kind .. '') end @@ -74,7 +74,7 @@ local function call_ui_event_method(output, ev) output:write( 'ui_client_dict2hlattrs(args.items[' .. (j - 1) - .. '].data.dictionary, ' + .. '].data.dict, ' .. (hlattrs_args_count == 0 and 'true' or 'false') .. ');\n' ) @@ -128,8 +128,16 @@ for i = 1, #events do write_signature(call_output, ev, '') call_output:write('\n{\n') if ev.remote_only then + -- Lua callbacks may emit other events or the same event again. Avoid the latter + -- by adding a recursion guard to each generated function that may call a Lua callback. + call_output:write(' static bool entered = false;\n') + call_output:write(' if (entered) {\n') + call_output:write(' return;\n') + call_output:write(' }\n') + call_output:write(' entered = true;\n') write_arglist(call_output, ev) call_output:write(' ui_call_event("' .. ev.name .. '", ' .. args .. ');\n') + call_output:write(' entered = false;\n') elseif ev.compositor_impl then call_output:write(' ui_comp_' .. ev.name) write_signature(call_output, ev, '', true) @@ -197,7 +205,8 @@ for _, ev in ipairs(events) do ev_exported[attr] = ev[attr] end for _, p in ipairs(ev_exported.parameters) do - if p[1] == 'HlAttrs' then + if p[1] == 'HlAttrs' or p[1] == 'Dict' then + -- TODO(justinmk): for back-compat, but do clients actually look at this? p[1] = 'Dictionary' end end diff --git a/src/nvim/generators/gen_declarations.lua b/src/nvim/generators/gen_declarations.lua index 5d1e586fe6..2ec0e9ab68 100644 --- a/src/nvim/generators/gen_declarations.lua +++ b/src/nvim/generators/gen_declarations.lua @@ -2,6 +2,7 @@ local fname = arg[1] local static_fname = arg[2] local non_static_fname = arg[3] local preproc_fname = arg[4] +local static_basename = arg[5] local lpeg = vim.lpeg @@ -69,7 +70,7 @@ local raw_word = concat(w, any_amount(aw)) local right_word = concat(raw_word, neg_look_ahead(aw)) local word = branch( concat( - branch(lit('ArrayOf('), lit('DictionaryOf('), lit('Dict(')), -- typed container macro + branch(lit('ArrayOf('), lit('DictOf('), lit('Dict(')), -- typed container macro one_or_more(any_character - lit(')')), lit(')') ), @@ -207,6 +208,10 @@ if fname:find('.*/src/nvim/.*%.c$') then // IWYU pragma: private, include "%s" ]]):format(header_fname:gsub('.*/src/nvim/', 'nvim/')) .. non_static end +elseif fname:find('.*/src/nvim/.*%.h$') then + static = ([[ +// IWYU pragma: private, include "%s" +]]):format(fname:gsub('.*/src/nvim/', 'nvim/')) .. static elseif non_static_fname:find('/include/api/private/dispatch_wrappers%.h%.generated%.h$') then non_static = [[ // IWYU pragma: private, include "nvim/api/private/dispatch.h" @@ -235,6 +240,7 @@ local declendpos = 0 local curdir = nil local is_needed_file = false local init_is_nl = true +local any_static = false while init ~= nil do if init_is_nl and text:sub(init, init) == '#' then local line, dir, file = text:match(filepattern, init) @@ -276,6 +282,9 @@ while init ~= nil do end declaration = declaration .. '\n' if declaration:sub(1, 6) == 'static' then + if declaration:find('FUNC_ATTR_') then + any_static = true + end static = static .. declaration else declaration = 'DLLEXPORT ' .. declaration @@ -303,6 +312,21 @@ F = io.open(static_fname, 'w') F:write(static) F:close() +if any_static then + F = io.open(fname, 'r') + local orig_text = F:read('*a') + local pat = '\n#%s?include%s+"' .. static_basename .. '"\n' + local pat_comment = '\n#%s?include%s+"' .. static_basename .. '"%s*//' + if not string.find(orig_text, pat) and not string.find(orig_text, pat_comment) then + error('fail: missing include for ' .. static_basename .. ' in ' .. fname) + end + F:close() +end + +if non_static_fname == 'SKIP' then + return -- only want static declarations +end + -- Before generating the non-static headers, check if the current file (if -- exists) is different from the new one. If they are the same, we won't touch -- the current version to avoid triggering an unnecessary rebuilds of modules @@ -312,7 +336,7 @@ if F ~= nil then if F:read('*a') == non_static then os.exit(0) end - io.close(F) + F:close() end F = io.open(non_static_fname, 'w') diff --git a/src/nvim/generators/gen_eval.lua b/src/nvim/generators/gen_eval.lua index 1ce7f1af9d..443c68e008 100644 --- a/src/nvim/generators/gen_eval.lua +++ b/src/nvim/generators/gen_eval.lua @@ -19,6 +19,7 @@ hashpipe:write([[ #include "nvim/digraph.h" #include "nvim/eval.h" #include "nvim/eval/buffer.h" +#include "nvim/eval/fs.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" #include "nvim/eval/vars.h" diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua index 0718d965c6..591a6b93df 100644 --- a/src/nvim/generators/gen_options.lua +++ b/src/nvim/generators/gen_options.lua @@ -148,7 +148,7 @@ local get_defaults = function(d, n) return value_dumpers[type(d)](d) end ---- @type {[1]:string,[2]:string}[] +--- @type [string,string][] local defines = {} --- @param i integer diff --git a/src/nvim/generators/gen_options_enum.lua b/src/nvim/generators/gen_options_enum.lua index 9a3953fcbc..d1419137d3 100644 --- a/src/nvim/generators/gen_options_enum.lua +++ b/src/nvim/generators/gen_options_enum.lua @@ -80,7 +80,7 @@ enum_w('') --- @type { [string]: string } local option_index = {} --- Generate option index enum and populate the `option_index` dictionary. +-- Generate option index enum and populate the `option_index` dict. enum_w('typedef enum {') enum_w(' kOptInvalid = -1,') diff --git a/src/nvim/generators/gen_unicode_tables.lua b/src/nvim/generators/gen_unicode_tables.lua deleted file mode 100644 index 6cedb5db50..0000000000 --- a/src/nvim/generators/gen_unicode_tables.lua +++ /dev/null @@ -1,323 +0,0 @@ --- Script creates the following tables in unicode_tables.generated.h: --- --- 1. doublewidth and ambiguous tables: sorted list of non-overlapping closed --- intervals. Codepoints in these intervals have double (W or F) or ambiguous --- (A) east asian width respectively. --- 2. combining table: same as the above, but characters inside are combining --- characters (i.e. have general categories equal to Mn, Mc or Me). --- 3. foldCase, toLower and toUpper tables used to convert characters to --- folded/lower/upper variants. In these tables first two values are --- character ranges: like in previous tables they are sorted and must be --- non-overlapping. Third value means step inside the range: e.g. if it is --- 2 then interval applies only to first, third, fifth, … character in range. --- Fourth value is number that should be added to the codepoint to yield --- folded/lower/upper codepoint. --- 4. emoji_wide and emoji_all tables: sorted lists of non-overlapping closed --- intervals of Emoji characters. emoji_wide contains all the characters --- which don't have ambiguous or double width, and emoji_all has all Emojis. -if arg[1] == '--help' then - print('Usage:') - print(' gen_unicode_tables.lua unicode/ unicode_tables.generated.h') - os.exit(0) -end - -local basedir = arg[1] -local pathsep = package.config:sub(1, 1) -local get_path = function(fname) - return basedir .. pathsep .. fname -end - -local unicodedata_fname = get_path('UnicodeData.txt') -local casefolding_fname = get_path('CaseFolding.txt') -local eastasianwidth_fname = get_path('EastAsianWidth.txt') -local emoji_fname = get_path('emoji-data.txt') - -local utf_tables_fname = arg[2] - -local split_on_semicolons = function(s) - local ret = {} - local idx = 1 - while idx <= #s + 1 do - local item = s:match('^[^;]*', idx) - idx = idx + #item + 1 - if idx <= #s + 1 then - assert(s:sub(idx - 1, idx - 1) == ';') - end - item = item:gsub('^%s*', '') - item = item:gsub('%s*$', '') - table.insert(ret, item) - end - return ret -end - -local fp_lines_to_lists = function(fp, n, has_comments) - local ret = {} - local line - local i = 0 - while true do - i = i + 1 - line = fp:read('*l') - if not line then - break - end - if not has_comments or (line:sub(1, 1) ~= '#' and not line:match('^%s*$')) then - local l = split_on_semicolons(line) - if #l ~= n then - io.stderr:write(('Found %s items in line %u, expected %u\n'):format(#l, i, n)) - io.stderr:write('Line: ' .. line .. '\n') - return nil - end - table.insert(ret, l) - end - end - return ret -end - -local parse_data_to_props = function(ud_fp) - return fp_lines_to_lists(ud_fp, 15, false) -end - -local parse_fold_props = function(cf_fp) - return fp_lines_to_lists(cf_fp, 4, true) -end - -local parse_width_props = function(eaw_fp) - return fp_lines_to_lists(eaw_fp, 2, true) -end - -local parse_emoji_props = function(emoji_fp) - return fp_lines_to_lists(emoji_fp, 2, true) -end - -local make_range = function(start, end_, step, add) - if step and add then - return (' {0x%x, 0x%x, %d, %d},\n'):format(start, end_, step == 0 and -1 or step, add) - else - return (' {0x%04x, 0x%04x},\n'):format(start, end_) - end -end - -local build_convert_table = function(ut_fp, props, cond_func, nl_index, table_name) - ut_fp:write('static const convertStruct ' .. table_name .. '[] = {\n') - local start = -1 - local end_ = -1 - local step = 0 - local add = -1 - for _, p in ipairs(props) do - if cond_func(p) then - local n = tonumber(p[1], 16) - local nl = tonumber(p[nl_index], 16) - if start >= 0 and add == (nl - n) and (step == 0 or n - end_ == step) then - -- Continue with the same range. - step = n - end_ - end_ = n - else - if start >= 0 then - -- Produce previous range. - ut_fp:write(make_range(start, end_, step, add)) - end - start = n - end_ = n - step = 0 - add = nl - n - end - end - end - if start >= 0 then - ut_fp:write(make_range(start, end_, step, add)) - end - ut_fp:write('};\n') -end - -local build_case_table = function(ut_fp, dataprops, table_name, index) - local cond_func = function(p) - return p[index] ~= '' - end - return build_convert_table(ut_fp, dataprops, cond_func, index, 'to' .. table_name) -end - -local build_fold_table = function(ut_fp, foldprops) - local cond_func = function(p) - return (p[2] == 'C' or p[2] == 'S') - end - return build_convert_table(ut_fp, foldprops, cond_func, 3, 'foldCase') -end - -local build_combining_table = function(ut_fp, dataprops) - ut_fp:write('static const struct interval combining[] = {\n') - local start = -1 - local end_ = -1 - for _, p in ipairs(dataprops) do - -- The 'Mc' property was removed, it does take up space. - if ({ Mn = true, Me = true })[p[3]] then - local n = tonumber(p[1], 16) - if start >= 0 and end_ + 1 == n then - -- Continue with the same range. - end_ = n - else - if start >= 0 then - -- Produce previous range. - ut_fp:write(make_range(start, end_)) - end - start = n - end_ = n - end - end - end - if start >= 0 then - ut_fp:write(make_range(start, end_)) - end - ut_fp:write('};\n') -end - -local build_width_table = function(ut_fp, dataprops, widthprops, widths, table_name) - ut_fp:write('static const struct interval ' .. table_name .. '[] = {\n') - local start = -1 - local end_ = -1 - local dataidx = 1 - local ret = {} - for _, p in ipairs(widthprops) do - if widths[p[2]:sub(1, 1)] then - local rng_start, rng_end = p[1]:find('%.%.') - local n, n_last - if rng_start then - -- It is a range. We don’t check for composing char then. - n = tonumber(p[1]:sub(1, rng_start - 1), 16) - n_last = tonumber(p[1]:sub(rng_end + 1), 16) - else - n = tonumber(p[1], 16) - n_last = n - end - local dn - while true do - dn = tonumber(dataprops[dataidx][1], 16) - if dn >= n then - break - end - dataidx = dataidx + 1 - end - if dn ~= n and n_last == n then - io.stderr:write('Cannot find character ' .. n .. ' in data table.\n') - end - -- Only use the char when it’s not a composing char. - -- But use all chars from a range. - local dp = dataprops[dataidx] - if (n_last > n) or not ({ Mn = true, Mc = true, Me = true })[dp[3]] then - if start >= 0 and end_ + 1 == n then -- luacheck: ignore 542 - -- Continue with the same range. - else - if start >= 0 then - ut_fp:write(make_range(start, end_)) - table.insert(ret, { start, end_ }) - end - start = n - end - end_ = n_last - end - end - end - if start >= 0 then - ut_fp:write(make_range(start, end_)) - table.insert(ret, { start, end_ }) - end - ut_fp:write('};\n') - return ret -end - -local build_emoji_table = function(ut_fp, emojiprops, doublewidth, ambiwidth) - local emojiwidth = {} - local emoji = {} - for _, p in ipairs(emojiprops) do - if p[2]:match('Emoji%s+#') then - local rng_start, rng_end = p[1]:find('%.%.') - local n - local n_last - if rng_start then - n = tonumber(p[1]:sub(1, rng_start - 1), 16) - n_last = tonumber(p[1]:sub(rng_end + 1), 16) - else - n = tonumber(p[1], 16) - n_last = n - end - if #emoji > 0 and n - 1 == emoji[#emoji][2] then - emoji[#emoji][2] = n_last - else - table.insert(emoji, { n, n_last }) - end - - -- Characters below 1F000 may be considered single width traditionally, - -- making them double width causes problems. - if n >= 0x1f000 then - -- exclude characters that are in the ambiguous/doublewidth table - for _, ambi in ipairs(ambiwidth) do - if n >= ambi[1] and n <= ambi[2] then - n = ambi[2] + 1 - end - if n_last >= ambi[1] and n_last <= ambi[2] then - n_last = ambi[1] - 1 - end - end - for _, double in ipairs(doublewidth) do - if n >= double[1] and n <= double[2] then - n = double[2] + 1 - end - if n_last >= double[1] and n_last <= double[2] then - n_last = double[1] - 1 - end - end - - if n <= n_last then - if #emojiwidth > 0 and n - 1 == emojiwidth[#emojiwidth][2] then - emojiwidth[#emojiwidth][2] = n_last - else - table.insert(emojiwidth, { n, n_last }) - end - end - end - end - end - - ut_fp:write('static const struct interval emoji_all[] = {\n') - for _, p in ipairs(emoji) do - ut_fp:write(make_range(p[1], p[2])) - end - ut_fp:write('};\n') - - ut_fp:write('static const struct interval emoji_wide[] = {\n') - for _, p in ipairs(emojiwidth) do - ut_fp:write(make_range(p[1], p[2])) - end - ut_fp:write('};\n') -end - -local ud_fp = io.open(unicodedata_fname, 'r') -local dataprops = parse_data_to_props(ud_fp) -ud_fp:close() - -local ut_fp = io.open(utf_tables_fname, 'w') - -build_case_table(ut_fp, dataprops, 'Lower', 14) -build_case_table(ut_fp, dataprops, 'Upper', 13) -build_combining_table(ut_fp, dataprops) - -local cf_fp = io.open(casefolding_fname, 'r') -local foldprops = parse_fold_props(cf_fp) -cf_fp:close() - -build_fold_table(ut_fp, foldprops) - -local eaw_fp = io.open(eastasianwidth_fname, 'r') -local widthprops = parse_width_props(eaw_fp) -eaw_fp:close() - -local doublewidth = - build_width_table(ut_fp, dataprops, widthprops, { W = true, F = true }, 'doublewidth') -local ambiwidth = build_width_table(ut_fp, dataprops, widthprops, { A = true }, 'ambiguous') - -local emoji_fp = io.open(emoji_fname, 'r') -local emojiprops = parse_emoji_props(emoji_fp) -emoji_fp:close() - -build_emoji_table(ut_fp, emojiprops, doublewidth, ambiwidth) - -ut_fp:close() diff --git a/src/nvim/generators/gen_vimvim.lua b/src/nvim/generators/gen_vimvim.lua index fcdc5bddc2..0675f04b73 100644 --- a/src/nvim/generators/gen_vimvim.lua +++ b/src/nvim/generators/gen_vimvim.lua @@ -80,12 +80,13 @@ for _, cmd_desc in ipairs(ex_cmds.cmds) do end local vimopt_start = 'syn keyword vimOption contained ' +local vimopt_end = ' skipwhite nextgroup=vimSetEqual,vimSetMod' w('\n\n' .. vimopt_start) for _, opt_desc in ipairs(options.options) do if not opt_desc.immutable then if lld.line_length > 850 then - w('\n' .. vimopt_start) + w(vimopt_end .. '\n' .. vimopt_start) end w(' ' .. opt_desc.full_name) if opt_desc.abbreviation then @@ -102,7 +103,9 @@ for _, opt_desc in ipairs(options.options) do end end -w('\n\nsyn case ignore') +w(vimopt_end .. '\n') + +w('\nsyn case ignore') local vimau_start = 'syn keyword vimAutoEvent contained ' w('\n\n' .. vimau_start) diff --git a/src/nvim/generators/hashy.lua b/src/nvim/generators/hashy.lua index 711e695742..ea35064962 100644 --- a/src/nvim/generators/hashy.lua +++ b/src/nvim/generators/hashy.lua @@ -73,11 +73,15 @@ function M.switcher(put, tab, maxlen, worst_buck_size) vim.list_extend(neworder, buck) local endidx = #neworder put(" case '" .. c .. "': ") - put('low = ' .. startidx .. '; ') - if bucky then - put('high = ' .. endidx .. '; ') + if len == 1 then + put('return ' .. startidx .. ';\n') + else + put('low = ' .. startidx .. '; ') + if bucky then + put('high = ' .. endidx .. '; ') + end + put 'break;\n' end - put 'break;\n' end put ' default: break;\n' put ' }\n ' @@ -105,13 +109,19 @@ function M.hashy_hash(name, strings, access) end local len_pos_buckets, maxlen, worst_buck_size = M.build_pos_hash(strings) put('int ' .. name .. '_hash(const char *str, size_t len)\n{\n') - if worst_buck_size > 1 then + if maxlen == 1 then + put('\n') -- nothing + elseif worst_buck_size > 1 then put(' int low = 0, high = 0;\n') else put(' int low = -1;\n') end local neworder = M.switcher(put, len_pos_buckets, maxlen, worst_buck_size) - if worst_buck_size > 1 then + if maxlen == 1 then + put([[ + return -1; +]]) + elseif worst_buck_size > 1 then put([[ for (int i = low; i < high; i++) { if (!memcmp(str, ]] .. access('i') .. [[, len)) { diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 9b19644b7e..472bc3a850 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -13,12 +13,14 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/vim.h" #include "nvim/ascii_defs.h" #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -104,10 +106,10 @@ static buffheader_T readbuf1 = { { NULL, { NUL } }, NULL, 0, 0 }; static buffheader_T readbuf2 = { { NULL, { NUL } }, NULL, 0, 0 }; /// Buffer used to store typed characters for vim.on_key(). -static kvec_withinit_t(char, MAXMAPLEN) on_key_buf = KVI_INITIAL_VALUE(on_key_buf); +static kvec_withinit_t(char, MAXMAPLEN + 1) on_key_buf = KVI_INITIAL_VALUE(on_key_buf); /// Number of following bytes that should not be stored for vim.on_key(). -static size_t no_on_key_len = 0; +static size_t on_key_ignore_len = 0; static int typeahead_char = 0; ///< typeahead char that's not flushed @@ -267,17 +269,12 @@ static void add_buff(buffheader_T *const buf, const char *const s, ptrdiff_t sle } buf->bh_index = 0; - size_t len; if (buf->bh_space >= (size_t)slen) { - len = strlen(buf->bh_curr->b_str); + size_t len = strlen(buf->bh_curr->b_str); xmemcpyz(buf->bh_curr->b_str + len, s, (size_t)slen); buf->bh_space -= (size_t)slen; } else { - if (slen < MINIMAL_SIZE) { - len = MINIMAL_SIZE; - } else { - len = (size_t)slen; - } + size_t len = MAX(MINIMAL_SIZE, (size_t)slen); buffblock_T *p = xmalloc(offsetof(buffblock_T, b_str) + len + 1); buf->bh_space = len - (size_t)slen; xmemcpyz(p->b_str, s, (size_t)slen); @@ -312,6 +309,24 @@ static void add_num_buff(buffheader_T *buf, int n) add_buff(buf, number, -1); } +/// Add byte or special key 'c' to buffer "buf". +/// Translates special keys, NUL and K_SPECIAL. +static void add_byte_buff(buffheader_T *buf, int c) +{ + char temp[4]; + if (IS_SPECIAL(c) || c == K_SPECIAL || c == NUL) { + // Translate special key code into three byte sequence. + temp[0] = (char)K_SPECIAL; + temp[1] = (char)K_SECOND(c); + temp[2] = (char)K_THIRD(c); + temp[3] = NUL; + } else { + temp[0] = (char)c; + temp[1] = NUL; + } + add_buff(buf, temp, -1); +} + /// Add character 'c' to buffer "buf". /// Translates special keys, NUL, K_SPECIAL and multibyte characters. static void add_char_buff(buffheader_T *buf, int c) @@ -329,19 +344,7 @@ static void add_char_buff(buffheader_T *buf, int c) if (!IS_SPECIAL(c)) { c = bytes[i]; } - - char temp[4]; - if (IS_SPECIAL(c) || c == K_SPECIAL || c == NUL) { - // Translate special key code into three byte sequence. - temp[0] = (char)K_SPECIAL; - temp[1] = (char)K_SECOND(c); - temp[2] = (char)K_THIRD(c); - temp[3] = NUL; - } else { - temp[0] = (char)c; - temp[1] = NUL; - } - add_buff(buf, temp, -1); + add_byte_buff(buf, c); } } @@ -1009,18 +1012,18 @@ int ins_typebuf(char *str, int noremap, int offset, bool nottyped, bool silent) /// Uses cmd_silent, KeyTyped and KeyNoremap to restore the flags belonging to /// the char. /// -/// @param no_on_key don't store these bytes for vim.on_key() +/// @param on_key_ignore don't store these bytes for vim.on_key() /// /// @return the length of what was inserted -int ins_char_typebuf(int c, int modifiers, bool no_on_key) +int ins_char_typebuf(int c, int modifiers, bool on_key_ignore) { char buf[MB_MAXBYTES * 3 + 4]; unsigned len = special_to_buf(c, modifiers, true, buf); assert(len < sizeof(buf)); buf[len] = NUL; ins_typebuf(buf, KeyNoremap, 0, !KeyTyped, cmd_silent); - if (KeyTyped && no_on_key) { - no_on_key_len += len; + if (KeyTyped && on_key_ignore) { + on_key_ignore_len += len; } return (int)len; } @@ -1188,22 +1191,21 @@ static void gotchars(const uint8_t *chars, size_t len) updatescript(state.buf[i]); } - state.buf[state.buflen] = NUL; + if (state.buflen > on_key_ignore_len) { + kvi_concat_len(on_key_buf, (char *)state.buf + on_key_ignore_len, + state.buflen - on_key_ignore_len); + on_key_ignore_len = 0; + } else { + on_key_ignore_len -= state.buflen; + } if (reg_recording != 0) { + state.buf[state.buflen] = NUL; add_buff(&recordbuff, (char *)state.buf, (ptrdiff_t)state.buflen); // remember how many chars were last recorded last_recorded_len += state.buflen; } - if (state.buflen > no_on_key_len) { - vim_unescape_ks((char *)state.buf + no_on_key_len); - kvi_concat(on_key_buf, (char *)state.buf + no_on_key_len); - no_on_key_len = 0; - } else { - no_on_key_len -= state.buflen; - } - state.buflen = 0; } @@ -1221,7 +1223,7 @@ static void gotchars(const uint8_t *chars, size_t len) void gotchars_ignore(void) { uint8_t nop_buf[3] = { K_SPECIAL, KS_EXTRA, KE_IGNORE }; - no_on_key_len += 3; + on_key_ignore_len += 3; gotchars(nop_buf, 3); } @@ -1634,8 +1636,52 @@ int vgetc(void) c = TO_SPECIAL(c2, c); } - // a keypad or special function key was not mapped, use it like - // its ASCII equivalent + // For a multi-byte character get all the bytes and return the + // converted character. + // Note: This will loop until enough bytes are received! + int n; + if ((n = MB_BYTE2LEN_CHECK(c)) > 1) { + no_mapping++; + buf[0] = (uint8_t)c; + for (int i = 1; i < n; i++) { + buf[i] = (uint8_t)vgetorpeek(true); + if (buf[i] == K_SPECIAL) { + // Must be a K_SPECIAL - KS_SPECIAL - KE_FILLER sequence, + // which represents a K_SPECIAL (0x80). + vgetorpeek(true); // skip KS_SPECIAL + vgetorpeek(true); // skip KE_FILLER + } + } + no_mapping--; + c = utf_ptr2char((char *)buf); + } + + // If mappings are enabled (i.e., not i_CTRL-V) and the user directly typed + // something with MOD_MASK_ALT (<M-/<A- modifier) that was not mapped, interpret + // <M-x> as <Esc>x rather than as an unbound <M-x> keypress. #8213 + // In Terminal mode, however, this is not desirable. #16202 #16220 + // Also do not do this for mouse keys, as terminals encode mouse events as + // CSI sequences, and MOD_MASK_ALT has a meaning even for unmapped mouse keys. + if (!no_mapping && KeyTyped && mod_mask == MOD_MASK_ALT + && !(State & MODE_TERMINAL) && !is_mouse_key(c)) { + mod_mask = 0; + int len = ins_char_typebuf(c, 0, false); + ins_char_typebuf(ESC, 0, false); + int old_len = len + 3; // K_SPECIAL KS_MODIFIER MOD_MASK_ALT takes 3 more bytes + ungetchars(old_len); + if (on_key_buf.size >= (size_t)old_len) { + on_key_buf.size -= (size_t)old_len; + } + continue; + } + + if (vgetc_char == 0) { + vgetc_mod_mask = mod_mask; + vgetc_char = c; + } + + // A keypad or special function key was not mapped, use it like + // its ASCII equivalent. switch (c) { case K_KPLUS: c = '+'; break; @@ -1713,50 +1759,6 @@ int vgetc(void) c = K_RIGHT; break; } - // For a multi-byte character get all the bytes and return the - // converted character. - // Note: This will loop until enough bytes are received! - int n; - if ((n = MB_BYTE2LEN_CHECK(c)) > 1) { - no_mapping++; - buf[0] = (uint8_t)c; - for (int i = 1; i < n; i++) { - buf[i] = (uint8_t)vgetorpeek(true); - if (buf[i] == K_SPECIAL) { - // Must be a K_SPECIAL - KS_SPECIAL - KE_FILLER sequence, - // which represents a K_SPECIAL (0x80). - vgetorpeek(true); // skip KS_SPECIAL - vgetorpeek(true); // skip KE_FILLER - } - } - no_mapping--; - c = utf_ptr2char((char *)buf); - } - - if (vgetc_char == 0) { - vgetc_mod_mask = mod_mask; - vgetc_char = c; - } - - // If mappings are enabled (i.e., not i_CTRL-V) and the user directly typed something with - // MOD_MASK_ALT (<M-/<A- modifier) that was not mapped, interpret <M-x> as <Esc>x rather - // than as an unbound <M-x> keypress. #8213 - // In Terminal mode, however, this is not desirable. #16202 #16220 - // Also do not do this for mouse keys, as terminals encode mouse events as CSI sequences, and - // MOD_MASK_ALT has a meaning even for unmapped mouse keys. - if (!no_mapping && KeyTyped && mod_mask == MOD_MASK_ALT && !(State & MODE_TERMINAL) - && !is_mouse_key(c)) { - mod_mask = 0; - int len = ins_char_typebuf(c, 0, false); - ins_char_typebuf(ESC, 0, false); - int old_len = len + 3; // K_SPECIAL KS_MODIFIER MOD_MASK_ALT takes 3 more bytes - ungetchars(old_len); - if (on_key_buf.size >= (size_t)old_len) { - on_key_buf.size -= (size_t)old_len; - } - continue; - } - break; } @@ -1769,7 +1771,8 @@ int vgetc(void) may_garbage_collect = false; // Execute Lua on_key callbacks. - nlua_execute_on_key(c, on_key_buf.items, on_key_buf.size); + kvi_push(on_key_buf, NUL); + nlua_execute_on_key(c, on_key_buf.items); kvi_destroy(on_key_buf); kvi_init(on_key_buf); @@ -1862,7 +1865,7 @@ static void getchar_common(typval_T *argvars, typval_T *rettv) if (!char_avail()) { // Flush screen updates before blocking. ui_flush(); - os_inchar(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events); + input_get(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events); if (!multiqueue_empty(main_loop.events)) { state_handle_k_event(); continue; @@ -2237,9 +2240,7 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth) } } else { // No match; may have to check for termcode at next character. - if (max_mlen < mlen) { - max_mlen = mlen; - } + max_mlen = MAX(max_mlen, mlen); } } } @@ -2340,8 +2341,8 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth) const int save_m_noremap = mp->m_noremap; const bool save_m_silent = mp->m_silent; char *save_m_keys = NULL; // only saved when needed - char *save_m_str = NULL; // only saved when needed - const LuaRef save_m_luaref = mp->m_luaref; + char *save_alt_m_keys = NULL; // only saved when needed + const int save_alt_m_keylen = mp->m_alt != NULL ? mp->m_alt->m_keylen : 0; // Handle ":map <expr>": evaluate the {rhs} as an // expression. Also save and restore the command line @@ -2354,10 +2355,10 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth) vgetc_busy = 0; may_garbage_collect = false; - save_m_keys = xstrdup(mp->m_keys); - if (save_m_luaref == LUA_NOREF) { - save_m_str = xstrdup(mp->m_str); - } + save_m_keys = xmemdupz(mp->m_keys, (size_t)mp->m_keylen); + save_alt_m_keys = mp->m_alt != NULL + ? xmemdupz(mp->m_alt->m_keys, (size_t)save_alt_m_keylen) + : NULL; map_str = eval_map_expr(mp, NUL); if ((map_str == NULL || *map_str == NUL)) { @@ -2374,9 +2375,7 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth) if (State & MODE_CMDLINE) { // redraw the command below the error msg_didout = true; - if (msg_row < cmdline_row) { - msg_row = cmdline_row; - } + msg_row = MAX(msg_row, cmdline_row); redrawcmd(); } } else if (State & (MODE_NORMAL | MODE_INSERT)) { @@ -2408,11 +2407,18 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth) if (save_m_noremap != REMAP_YES) { noremap = save_m_noremap; - } else if (strncmp(map_str, save_m_keys != NULL ? save_m_keys : mp->m_keys, - (size_t)keylen) != 0) { - noremap = REMAP_YES; - } else { + } else if (save_m_expr + ? strncmp(map_str, save_m_keys, (size_t)keylen) == 0 + || (save_alt_m_keys != NULL + && strncmp(map_str, save_alt_m_keys, + (size_t)save_alt_m_keylen) == 0) + : strncmp(map_str, mp->m_keys, (size_t)keylen) == 0 + || (mp->m_alt != NULL + && strncmp(map_str, mp->m_alt->m_keys, + (size_t)mp->m_alt->m_keylen) == 0)) { noremap = REMAP_SKIP; + } else { + noremap = REMAP_YES; } i = ins_typebuf(map_str, noremap, 0, true, cmd_silent || save_m_silent); if (save_m_expr) { @@ -2420,7 +2426,7 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth) } } xfree(save_m_keys); - xfree(save_m_str); + xfree(save_alt_m_keys); *keylenp = keylen; if (i == FAIL) { return map_result_fail; @@ -2728,16 +2734,12 @@ static int vgetorpeek(bool advance) timedout = true; continue; } - // In Ex-mode \n is compatible with original Vim behaviour. + // For the command line only CTRL-C always breaks it. // For the cmdline window: Alternate between ESC and // CTRL-C: ESC for most situations and CTRL-C to close the // cmdline window. - if ((State & MODE_CMDLINE) || (cmdwin_type > 0 && tc == ESC)) { - c = Ctrl_C; - } else { - c = ESC; - } + c = ((State & MODE_CMDLINE) || (cmdwin_type > 0 && tc == ESC)) ? Ctrl_C : ESC; tc = c; // set a flag to indicate this wasn't a normal char @@ -2986,7 +2988,7 @@ int inchar(uint8_t *buf, int maxlen, long wait_time) uint8_t dum[DUM_LEN + 1]; while (true) { - len = os_inchar(dum, DUM_LEN, 0, 0, NULL); + len = input_get(dum, DUM_LEN, 0, 0, NULL); if (len == 0 || (len == 1 && dum[0] == Ctrl_C)) { break; } @@ -3002,7 +3004,7 @@ int inchar(uint8_t *buf, int maxlen, long wait_time) // Fill up to a third of the buffer, because each character may be // tripled below. - len = os_inchar(buf, maxlen / 3, (int)wait_time, tb_change_cnt, NULL); + len = input_get(buf, maxlen / 3, (int)wait_time, tb_change_cnt, NULL); } // If the typebuf was changed further down, it is like nothing was added by @@ -3179,7 +3181,7 @@ bool map_execute_lua(bool may_repeat) Error err = ERROR_INIT; Array args = ARRAY_DICT_INIT; nlua_call_ref(ref, NULL, args, kRetNilBool, NULL, &err); - if (err.type != kErrorTypeNone) { + if (ERROR_SET(&err)) { semsg_multiline("E5108: %s", err.msg); api_clear_error(&err); } @@ -3187,3 +3189,122 @@ bool map_execute_lua(bool may_repeat) ga_clear(&line_ga); return true; } + +/// Wraps pasted text stream with K_PASTE_START and K_PASTE_END, and +/// appends to redo buffer and/or record buffer if needed. +/// Escapes all K_SPECIAL and NUL bytes in the content. +/// +/// @param state kFalse for the start of a paste +/// kTrue for the end of a paste +/// kNone for the content of a paste +/// @param str the content of the paste (only used when state is kNone) +void paste_store(const uint64_t channel_id, const TriState state, const String str, const bool crlf) +{ + if (State & MODE_CMDLINE) { + return; + } + + const bool need_redo = !block_redo; + const bool need_record = reg_recording != 0 && !is_internal_call(channel_id); + + if (!need_redo && !need_record) { + return; + } + + if (state != kNone) { + const int c = state == kFalse ? K_PASTE_START : K_PASTE_END; + if (need_redo) { + if (state == kFalse && !(State & MODE_INSERT)) { + ResetRedobuff(); + } + add_char_buff(&redobuff, c); + } + if (need_record) { + add_char_buff(&recordbuff, c); + } + return; + } + + const char *s = str.data; + const char *const str_end = str.data + str.size; + + while (s < str_end) { + const char *start = s; + while (s < str_end && (uint8_t)(*s) != K_SPECIAL && *s != NUL + && *s != NL && !(crlf && *s == CAR)) { + s++; + } + + if (s > start) { + if (need_redo) { + add_buff(&redobuff, start, s - start); + } + if (need_record) { + add_buff(&recordbuff, start, s - start); + } + } + + if (s < str_end) { + int c = (uint8_t)(*s++); + if (crlf && c == CAR) { + if (s < str_end && *s == NL) { + s++; + } + c = NL; + } + if (need_redo) { + add_byte_buff(&redobuff, c); + } + if (need_record) { + add_byte_buff(&recordbuff, c); + } + } + } +} + +/// Gets a paste stored by paste_store() from typeahead and repeats it. +void paste_repeat(int count) +{ + garray_T ga = GA_INIT(1, 32); + bool aborted = false; + + no_mapping++; + + got_int = false; + while (!aborted) { + ga_grow(&ga, 32); + uint8_t c1 = (uint8_t)vgetorpeek(true); + if (c1 == K_SPECIAL) { + c1 = (uint8_t)vgetorpeek(true); + uint8_t c2 = (uint8_t)vgetorpeek(true); + int c = TO_SPECIAL(c1, c2); + if (c == K_PASTE_END) { + break; + } else if (c == K_ZERO) { + ga_append(&ga, NUL); + } else if (c == K_SPECIAL) { + ga_append(&ga, K_SPECIAL); + } else { + ga_append(&ga, K_SPECIAL); + ga_append(&ga, c1); + ga_append(&ga, c2); + } + } else { + ga_append(&ga, c1); + } + aborted = got_int; + } + + no_mapping--; + + String str = cbuf_as_string(ga.ga_data, (size_t)ga.ga_len); + Arena arena = ARENA_EMPTY; + Error err = ERROR_INIT; + for (int i = 0; !aborted && i < count; i++) { + nvim_paste(LUA_INTERNAL_CALL, str, false, -1, &arena, &err); + aborted = ERROR_SET(&err); + } + api_clear_error(&err); + arena_mem_free(arena_finish(&arena)); + ga_clear(&ga); +} diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 83fef1fe75..45a31ce6b0 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -106,7 +106,8 @@ EXTERN int Columns INIT( = DFLT_COLS); // nr of columns in the screen // held down based on the MOD_MASK_* symbols that are read first. EXTERN int mod_mask INIT( = 0); // current key modifiers -// The value of "mod_mask" and the unmodified character before calling merge_modifiers(). +// The value of "mod_mask" and the unmodified character in vgetc() after it has +// called vgetorpeek() enough times. EXTERN int vgetc_mod_mask INIT( = 0); EXTERN int vgetc_char INIT( = 0); @@ -146,8 +147,7 @@ EXTERN hlf_T edit_submode_highl; // highl. method for extra info EXTERN bool cmdmsg_rl INIT( = false); // cmdline is drawn right to left EXTERN int msg_col; EXTERN int msg_row; -EXTERN int msg_scrolled; // Number of screen lines that windows have - // scrolled because of printing messages. +EXTERN int msg_scrolled; ///< Number of screen lines that messages have scrolled. // when true don't set need_wait_return in msg_puts_attr() // when msg_scrolled is non-zero EXTERN bool msg_scrolled_ign INIT( = false); @@ -178,8 +178,8 @@ EXTERN long emsg_assert_fails_lnum INIT( = 0); EXTERN char *emsg_assert_fails_context INIT( = NULL); EXTERN bool did_endif INIT( = false); // just had ":endif" -EXTERN dict_T vimvardict; // Dictionary with v: variables -EXTERN dict_T globvardict; // Dictionary with g: variables +EXTERN dict_T vimvardict; // Dict with v: variables +EXTERN dict_T globvardict; // Dict with g: variables /// g: value #define globvarht globvardict.dv_hashtab EXTERN int did_emsg; // incremented by emsg() when a @@ -793,195 +793,7 @@ EXTERN disptick_T display_tick INIT( = 0); // cursor position in Insert mode. EXTERN linenr_T spell_redraw_lnum INIT( = 0); -// uncrustify:off - -// The error messages that can be shared are included here. -// Excluded are errors that are only used once and debugging messages. -EXTERN const char e_abort[] INIT(= N_("E470: Command aborted")); -EXTERN const char e_afterinit[] INIT(= N_("E905: Cannot set this option after startup")); -EXTERN const char e_api_spawn_failed[] INIT(= N_("E903: Could not spawn API job")); -EXTERN const char e_argreq[] INIT(= N_("E471: Argument required")); -EXTERN const char e_backslash[] INIT(= N_("E10: \\ should be followed by /, ? or &")); -EXTERN const char e_cmdwin[] INIT(= N_("E11: Invalid in command-line window; <CR> executes, CTRL-C quits")); -EXTERN const char e_curdir[] INIT(= N_("E12: Command not allowed in secure mode in current dir or tag search")); -EXTERN const char e_invalid_buffer_name_str[] INIT(= N_("E158: Invalid buffer name: %s")); -EXTERN const char e_command_too_recursive[] INIT(= N_("E169: Command too recursive")); -EXTERN const char e_buffer_is_not_loaded[] INIT(= N_("E681: Buffer is not loaded")); -EXTERN const char e_endif[] INIT(= N_("E171: Missing :endif")); -EXTERN const char e_endtry[] INIT(= N_("E600: Missing :endtry")); -EXTERN const char e_endwhile[] INIT(= N_("E170: Missing :endwhile")); -EXTERN const char e_endfor[] INIT(= N_("E170: Missing :endfor")); -EXTERN const char e_while[] INIT(= N_("E588: :endwhile without :while")); -EXTERN const char e_for[] INIT(= N_("E588: :endfor without :for")); -EXTERN const char e_exists[] INIT(= N_("E13: File exists (add ! to override)")); -EXTERN const char e_failed[] INIT(= N_("E472: Command failed")); -EXTERN const char e_internal[] INIT(= N_("E473: Internal error")); -EXTERN const char e_intern2[] INIT(= N_("E685: Internal error: %s")); -EXTERN const char e_interr[] INIT(= N_("Interrupted")); -EXTERN const char e_invarg[] INIT(= N_("E474: Invalid argument")); -EXTERN const char e_invarg2[] INIT(= N_("E475: Invalid argument: %s")); -EXTERN const char e_invargval[] INIT(= N_("E475: Invalid value for argument %s")); -EXTERN const char e_invargNval[] INIT(= N_("E475: Invalid value for argument %s: %s")); -EXTERN const char e_duparg2[] INIT(= N_("E983: Duplicate argument: %s")); -EXTERN const char e_invexpr2[] INIT(= N_("E15: Invalid expression: \"%s\"")); -EXTERN const char e_invrange[] INIT(= N_("E16: Invalid range")); -EXTERN const char e_invcmd[] INIT(= N_("E476: Invalid command")); -EXTERN const char e_isadir2[] INIT(= N_("E17: \"%s\" is a directory")); -EXTERN const char e_no_spell[] INIT(= N_("E756: Spell checking is not possible")); -EXTERN const char e_invchan[] INIT(= N_("E900: Invalid channel id")); -EXTERN const char e_invchanjob[] INIT(= N_("E900: Invalid channel id: not a job")); -EXTERN const char e_jobtblfull[] INIT(= N_("E901: Job table is full")); -EXTERN const char e_jobspawn[] INIT(= N_("E903: Process failed to start: %s: \"%s\"")); -EXTERN const char e_channotpty[] INIT(= N_("E904: channel is not a pty")); -EXTERN const char e_stdiochan2[] INIT(= N_("E905: Couldn't open stdio channel: %s")); -EXTERN const char e_invstream[] INIT(= N_("E906: invalid stream for channel")); -EXTERN const char e_invstreamrpc[] INIT(= N_("E906: invalid stream for rpc channel, use 'rpc'")); -EXTERN const char e_streamkey[] INIT(= N_("E5210: dict key '%s' already set for buffered stream in channel %" PRIu64)); -EXTERN const char e_libcall[] INIT(= N_("E364: Library call failed for \"%s()\"")); -EXTERN const char e_fsync[] INIT(= N_("E667: Fsync failed: %s")); -EXTERN const char e_mkdir[] INIT(= N_("E739: Cannot create directory %s: %s")); -EXTERN const char e_markinval[] INIT(= N_("E19: Mark has invalid line number")); -EXTERN const char e_marknotset[] INIT(= N_("E20: Mark not set")); -EXTERN const char e_modifiable[] INIT(= N_("E21: Cannot make changes, 'modifiable' is off")); -EXTERN const char e_nesting[] INIT(= N_("E22: Scripts nested too deep")); -EXTERN const char e_noalt[] INIT(= N_("E23: No alternate file")); -EXTERN const char e_noabbr[] INIT(= N_("E24: No such abbreviation")); -EXTERN const char e_nobang[] INIT(= N_("E477: No ! allowed")); -EXTERN const char e_nogroup[] INIT(= N_("E28: No such highlight group name: %s")); -EXTERN const char e_noinstext[] INIT(= N_("E29: No inserted text yet")); -EXTERN const char e_nolastcmd[] INIT(= N_("E30: No previous command line")); -EXTERN const char e_nomap[] INIT(= N_("E31: No such mapping")); -EXTERN const char e_nomatch[] INIT(= N_("E479: No match")); -EXTERN const char e_nomatch2[] INIT(= N_("E480: No match: %s")); -EXTERN const char e_noname[] INIT(= N_("E32: No file name")); -EXTERN const char e_nopresub[] INIT(= N_("E33: No previous substitute regular expression")); -EXTERN const char e_noprev[] INIT(= N_("E34: No previous command")); -EXTERN const char e_noprevre[] INIT(= N_("E35: No previous regular expression")); -EXTERN const char e_norange[] INIT(= N_("E481: No range allowed")); -EXTERN const char e_noroom[] INIT(= N_("E36: Not enough room")); -EXTERN const char e_notmp[] INIT(= N_("E483: Can't get temp file name")); -EXTERN const char e_notopen[] INIT(= N_("E484: Can't open file %s")); -EXTERN const char e_notopen_2[] INIT(= N_("E484: Can't open file %s: %s")); -EXTERN const char e_notread[] INIT(= N_("E485: Can't read file %s")); -EXTERN const char e_null[] INIT(= N_("E38: Null argument")); -EXTERN const char e_number_exp[] INIT(= N_("E39: Number expected")); -EXTERN const char e_openerrf[] INIT(= N_("E40: Can't open errorfile %s")); -EXTERN const char e_outofmem[] INIT(= N_("E41: Out of memory!")); -EXTERN const char e_patnotf[] INIT(= N_("Pattern not found")); -EXTERN const char e_patnotf2[] INIT(= N_("E486: Pattern not found: %s")); -EXTERN const char e_positive[] INIT(= N_("E487: Argument must be positive")); -EXTERN const char e_prev_dir[] INIT(= N_("E459: Cannot go back to previous directory")); - -EXTERN const char e_no_errors[] INIT(= N_("E42: No Errors")); -EXTERN const char e_loclist[] INIT(= N_("E776: No location list")); -EXTERN const char e_re_damg[] INIT(= N_("E43: Damaged match string")); -EXTERN const char e_re_corr[] INIT(= N_("E44: Corrupted regexp program")); -EXTERN const char e_readonly[] INIT(= N_("E45: 'readonly' option is set (add ! to override)")); -EXTERN const char e_letwrong[] INIT(= N_("E734: Wrong variable type for %s=")); -EXTERN const char e_illvar[] INIT(= N_("E461: Illegal variable name: %s")); -EXTERN const char e_cannot_mod[] INIT(= N_("E995: Cannot modify existing variable")); -EXTERN const char e_readonlyvar[] INIT(= N_("E46: Cannot change read-only variable \"%.*s\"")); -EXTERN const char e_stringreq[] INIT(= N_("E928: String required")); -EXTERN const char e_dictreq[] INIT(= N_("E715: Dictionary required")); -EXTERN const char e_blobidx[] INIT(= N_("E979: Blob index out of range: %" PRId64)); -EXTERN const char e_invalblob[] INIT(= N_("E978: Invalid operation for Blob")); -EXTERN const char e_toomanyarg[] INIT(= N_("E118: Too many arguments for function: %s")); -EXTERN const char e_toofewarg[] INIT(= N_("E119: Not enough arguments for function: %s")); -EXTERN const char e_dictkey[] INIT(= N_("E716: Key not present in Dictionary: \"%s\"")); -EXTERN const char e_dictkey_len[] INIT(= N_("E716: Key not present in Dictionary: \"%.*s\"")); -EXTERN const char e_listreq[] INIT(= N_("E714: List required")); -EXTERN const char e_listblobreq[] INIT(= N_("E897: List or Blob required")); -EXTERN const char e_listdictarg[] INIT(= N_("E712: Argument of %s must be a List or Dictionary")); -EXTERN const char e_listdictblobarg[] INIT(= N_("E896: Argument of %s must be a List, Dictionary or Blob")); -EXTERN const char e_readerrf[] INIT(= N_("E47: Error while reading errorfile")); -EXTERN const char e_sandbox[] INIT(= N_("E48: Not allowed in sandbox")); -EXTERN const char e_secure[] INIT(= N_("E523: Not allowed here")); -EXTERN const char e_textlock[] INIT(= N_("E565: Not allowed to change text or change window")); -EXTERN const char e_screenmode[] INIT(= N_("E359: Screen mode setting not supported")); -EXTERN const char e_scroll[] INIT(= N_("E49: Invalid scroll size")); -EXTERN const char e_shellempty[] INIT(= N_("E91: 'shell' option is empty")); -EXTERN const char e_signdata[] INIT(= N_("E255: Couldn't read in sign data!")); -EXTERN const char e_swapclose[] INIT(= N_("E72: Close error on swap file")); -EXTERN const char e_toocompl[] INIT(= N_("E74: Command too complex")); -EXTERN const char e_longname[] INIT(= N_("E75: Name too long")); -EXTERN const char e_toomsbra[] INIT(= N_("E76: Too many [")); -EXTERN const char e_toomany[] INIT(= N_("E77: Too many file names")); -EXTERN const char e_trailing[] INIT(= N_("E488: Trailing characters")); -EXTERN const char e_trailing_arg[] INIT(= N_("E488: Trailing characters: %s")); -EXTERN const char e_umark[] INIT(= N_("E78: Unknown mark")); -EXTERN const char e_wildexpand[] INIT(= N_("E79: Cannot expand wildcards")); -EXTERN const char e_winheight[] INIT(= N_("E591: 'winheight' cannot be smaller than 'winminheight'")); -EXTERN const char e_winwidth[] INIT(= N_("E592: 'winwidth' cannot be smaller than 'winminwidth'")); -EXTERN const char e_write[] INIT(= N_("E80: Error while writing")); -EXTERN const char e_zerocount[] INIT(= N_("E939: Positive count required")); -EXTERN const char e_usingsid[] INIT(= N_("E81: Using <SID> not in a script context")); -EXTERN const char e_missingparen[] INIT(= N_("E107: Missing parentheses: %s")); -EXTERN const char e_empty_buffer[] INIT(= N_("E749: Empty buffer")); -EXTERN const char e_nobufnr[] INIT(= N_("E86: Buffer %" PRId64 " does not exist")); - -EXTERN const char e_str_not_inside_function[] INIT(= N_("E193: %s not inside a function")); - -EXTERN const char e_invalpat[] INIT(= N_("E682: Invalid search pattern or delimiter")); -EXTERN const char e_bufloaded[] INIT(= N_("E139: File is loaded in another buffer")); -EXTERN const char e_notset[] INIT(= N_("E764: Option '%s' is not set")); -EXTERN const char e_invalidreg[] INIT(= N_("E850: Invalid register name")); -EXTERN const char e_dirnotf[] INIT(= N_("E919: Directory not found in '%s': \"%s\"")); -EXTERN const char e_au_recursive[] INIT(= N_("E952: Autocommand caused recursive behavior")); -EXTERN const char e_menu_only_exists_in_another_mode[] -INIT(= N_("E328: Menu only exists in another mode")); -EXTERN const char e_autocmd_close[] INIT(= N_("E813: Cannot close autocmd window")); -EXTERN const char e_listarg[] INIT(= N_("E686: Argument of %s must be a List")); -EXTERN const char e_unsupportedoption[] INIT(= N_("E519: Option not supported")); -EXTERN const char e_fnametoolong[] INIT(= N_("E856: Filename too long")); -EXTERN const char e_using_float_as_string[] INIT(= N_("E806: Using a Float as a String")); -EXTERN const char e_cannot_edit_other_buf[] INIT(= N_("E788: Not allowed to edit another buffer now")); -EXTERN const char e_using_number_as_bool_nr[] INIT(= N_("E1023: Using a Number as a Bool: %d")); -EXTERN const char e_not_callable_type_str[] INIT(= N_("E1085: Not a callable type: %s")); -EXTERN const char e_auabort[] INIT(= N_("E855: Autocommands caused command to abort")); - -EXTERN const char e_api_error[] INIT(= N_("E5555: API call: %s")); - -EXTERN const char e_luv_api_disabled[] INIT(= N_("E5560: %s must not be called in a lua loop callback")); - -EXTERN const char e_floatonly[] INIT(= N_("E5601: Cannot close window, only floating window would remain")); -EXTERN const char e_floatexchange[] INIT(= N_("E5602: Cannot exchange or rotate float")); - -EXTERN const char e_cannot_define_autocommands_for_all_events[] INIT(= N_("E1155: Cannot define autocommands for ALL events")); - -EXTERN const char e_resulting_text_too_long[] INIT(= N_("E1240: Resulting text too long")); - -EXTERN const char e_line_number_out_of_range[] INIT(= N_("E1247: Line number out of range")); - -EXTERN const char e_highlight_group_name_invalid_char[] INIT(= N_("E5248: Invalid character in group name")); - -EXTERN const char e_highlight_group_name_too_long[] INIT(= N_("E1249: Highlight group name too long")); - -EXTERN const char e_invalid_column_number_nr[] INIT( = N_("E964: Invalid column number: %ld")); -EXTERN const char e_invalid_line_number_nr[] INIT(= N_("E966: Invalid line number: %ld")); - -EXTERN const char e_stray_closing_curly_str[] -INIT(= N_("E1278: Stray '}' without a matching '{': %s")); -EXTERN const char e_missing_close_curly_str[] -INIT(= N_("E1279: Missing '}': %s")); - -EXTERN const char e_val_too_large[] INIT(= N_("E1510: Value too large: %s")); - -EXTERN const char e_undobang_cannot_redo_or_move_branch[] -INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch")); - -EXTERN const char e_winfixbuf_cannot_go_to_buffer[] -INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled")); - -EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s")); - -EXTERN const char e_unknown_option2[] INIT(= N_("E355: Unknown option: %s")); - -EXTERN const char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM")); -EXTERN const char bot_top_msg[] INIT(= N_("search hit BOTTOM, continuing at TOP")); - -EXTERN const char line_msg[] INIT(= N_(" line ")); - -EXTERN FILE *time_fd INIT(= NULL); // Where to write --startuptime report. +EXTERN FILE *time_fd INIT( = NULL); // Where to write --startuptime report. // Some compilers warn for not using a return value, but in some situations we // can't do anything useful with the value. Assign to this variable to avoid @@ -989,11 +801,9 @@ EXTERN FILE *time_fd INIT(= NULL); // Where to write --startuptime report. EXTERN int vim_ignored; // stdio is an RPC channel (--embed). -EXTERN bool embedded_mode INIT(= false); +EXTERN bool embedded_mode INIT( = false); // Do not start UI (--headless, -l) nor read/write to stdio (unless embedding). -EXTERN bool headless_mode INIT(= false); - -// uncrustify:on +EXTERN bool headless_mode INIT( = false); /// Only filled for Win32. EXTERN char windowsVersion[20] INIT( = { 0 }); diff --git a/src/nvim/grid.c b/src/nvim/grid.c index 56246bf001..acb336c725 100644 --- a/src/nvim/grid.c +++ b/src/nvim/grid.c @@ -186,6 +186,24 @@ size_t schar_len(schar_T sc) } } +int schar_cells(schar_T sc) +{ + // hot path +#ifdef ORDER_BIG_ENDIAN + if (!(sc & 0x80FFFFFF)) { + return 1; + } +#else + if (sc < 0x80) { + return 1; + } +#endif + + char sc_buf[MAX_SCHAR_SIZE]; + schar_get(sc_buf, sc); + return utf_ptr2cells(sc_buf); +} + /// gets first raw UTF-8 byte of an schar static char schar_get_first_byte(schar_T sc) { @@ -428,14 +446,19 @@ int grid_line_puts(int col, const char *text, int textlen, int attr) const int max_col = grid_line_maxcol; while (col < max_col && (len < 0 || (int)(ptr - text) < len) && *ptr != NUL) { // check if this is the first byte of a multibyte - int mbyte_blen = len > 0 - ? utfc_ptr2len_len(ptr, (int)((text + len) - ptr)) - : utfc_ptr2len(ptr); + int mbyte_blen; + if (len >= 0) { + int maxlen = (int)((text + len) - ptr); + mbyte_blen = utfc_ptr2len_len(ptr, maxlen); + if (mbyte_blen > maxlen) { + mbyte_blen = 1; + } + } else { + mbyte_blen = utfc_ptr2len(ptr); + } int firstc; - schar_T schar = len >= 0 - ? utfc_ptr2schar_len(ptr, (int)((text + len) - ptr), &firstc) - : utfc_ptr2schar(ptr, &firstc); - int mbyte_cells = utf_char2cells(firstc); + schar_T schar = utfc_ptrlen2schar(ptr, mbyte_blen, &firstc); + int mbyte_cells = utf_ptr2cells_len(ptr, mbyte_blen); if (mbyte_cells > 2 || schar == 0) { mbyte_cells = 1; schar = schar_from_char(0xFFFD); diff --git a/src/nvim/hashtab.c b/src/nvim/hashtab.c index a8a998a361..95df5e5383 100644 --- a/src/nvim/hashtab.c +++ b/src/nvim/hashtab.c @@ -316,10 +316,7 @@ static void hash_may_resize(hashtab_T *ht, size_t minitems) } } else { // Use specified size. - if (minitems < ht->ht_used) { - // just in case... - minitems = ht->ht_used; - } + minitems = MAX(minitems, ht->ht_used); // array is up to 2/3 full minsize = minitems * 3 / 2; } diff --git a/src/nvim/help.c b/src/nvim/help.c index e9f67ca3e4..0da846bb9f 100644 --- a/src/nvim/help.c +++ b/src/nvim/help.c @@ -13,6 +13,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/cmdexpand_defs.h" +#include "nvim/errors.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" @@ -957,8 +958,8 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool if (s == p2 && (p1 == IObuff || p1[-1] == ' ' || p1[-1] == '\t') && (vim_strchr(" \t\n\r", (uint8_t)s[1]) != NULL - || s[1] == '\0')) { - *p2 = '\0'; + || s[1] == NUL)) { + *p2 = NUL; p1++; size_t s_len = (size_t)(p2 - p1) + strlen(fname) + 2; s = xmalloc(s_len); diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index 8729c74ce8..d39ffcd177 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -219,11 +219,10 @@ int ns_get_hl(NS *ns_hl, int hl_id, bool link, bool nodefault) bool fallback = true; int tmp = false; HlAttrs attrs = HLATTRS_INIT; - if (ret.type == kObjectTypeDictionary) { + if (ret.type == kObjectTypeDict) { fallback = false; Dict(highlight) dict = KEYDICT_INIT; - if (api_dict_to_keydict(&dict, KeyDict_highlight_get_field, - ret.data.dictionary, &err)) { + if (api_dict_to_keydict(&dict, KeyDict_highlight_get_field, ret.data.dict, &err)) { attrs = dict2hlattrs(&dict, true, &it.link_id, &err); fallback = GET_BOOL_OR_TRUE(&dict, highlight, fallback); tmp = dict.fallback; // or false @@ -370,12 +369,15 @@ void update_window_hl(win_T *wp, bool invalid) // determine window specific background set in 'winhighlight' bool float_win = wp->w_floating && !wp->w_config.external; - if (float_win && hl_def[HLF_NFLOAT] != 0) { + if (float_win && hl_def[HLF_NFLOAT] != 0 && ns_id > 0) { wp->w_hl_attr_normal = hl_def[HLF_NFLOAT]; } else if (hl_def[HLF_COUNT] > 0) { wp->w_hl_attr_normal = hl_def[HLF_COUNT]; + } else if (float_win) { + wp->w_hl_attr_normal = HL_ATTR(HLF_NFLOAT) > 0 + ? HL_ATTR(HLF_NFLOAT) : highlight_attr[HLF_NFLOAT]; } else { - wp->w_hl_attr_normal = float_win ? HL_ATTR(HLF_NFLOAT) : 0; + wp->w_hl_attr_normal = 0; } if (wp->w_floating) { @@ -872,9 +874,9 @@ HlAttrs syn_attr2entry(int attr) } /// Gets highlight description for id `attr_id` as a map. -Dictionary hl_get_attr_by_id(Integer attr_id, Boolean rgb, Arena *arena, Error *err) +Dict hl_get_attr_by_id(Integer attr_id, Boolean rgb, Arena *arena, Error *err) { - Dictionary dic = ARRAY_DICT_INIT; + Dict dic = ARRAY_DICT_INIT; if (attr_id == 0) { return dic; @@ -885,19 +887,19 @@ Dictionary hl_get_attr_by_id(Integer attr_id, Boolean rgb, Arena *arena, Error * "Invalid attribute id: %" PRId64, attr_id); return dic; } - Dictionary retval = arena_dict(arena, HLATTRS_DICT_SIZE); + Dict retval = arena_dict(arena, HLATTRS_DICT_SIZE); hlattrs2dict(&retval, NULL, syn_attr2entry((int)attr_id), rgb, false); return retval; } -/// Converts an HlAttrs into Dictionary +/// Converts an HlAttrs into Dict /// -/// @param[in/out] hl Dictionary with pre-allocated space for HLATTRS_DICT_SIZE elements +/// @param[in/out] hl Dict with pre-allocated space for HLATTRS_DICT_SIZE elements /// @param[in] aep data to convert /// @param use_rgb use 'gui*' settings if true, else resorts to 'cterm*' /// @param short_keys change (foreground, background, special) to (fg, bg, sp) for 'gui*' settings /// (foreground, background) to (ctermfg, ctermbg) for 'cterm*' settings -void hlattrs2dict(Dictionary *hl, Dictionary *hl_attrs, HlAttrs ae, bool use_rgb, bool short_keys) +void hlattrs2dict(Dict *hl, Dict *hl_attrs, HlAttrs ae, bool use_rgb, bool short_keys) { hl_attrs = hl_attrs ? hl_attrs : hl; assert(hl->capacity >= HLATTRS_DICT_SIZE); // at most 16 items @@ -1085,10 +1087,10 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e } // Handle cterm attrs - if (dict->cterm.type == kObjectTypeDictionary) { + if (dict->cterm.type == kObjectTypeDict) { Dict(highlight_cterm) cterm[1] = KEYDICT_INIT; if (!api_dict_to_keydict(cterm, KeyDict_highlight_cterm_get_field, - dict->cterm.data.dictionary, err)) { + dict->cterm.data.dict, err)) { return hlattrs; } @@ -1203,7 +1205,7 @@ static size_t hl_inspect_size(int attr) static void hl_inspect_impl(Array *arr, int attr, Arena *arena) { - Dictionary item = ARRAY_DICT_INIT; + Dict item = ARRAY_DICT_INIT; if (attr <= 0 || attr >= (int)set_size(&attr_entries)) { return; } @@ -1242,5 +1244,5 @@ static void hl_inspect_impl(Array *arr, int attr, Arena *arena) return; } PUT_C(item, "id", INTEGER_OBJ(attr)); - ADD_C(*arr, DICTIONARY_OBJ(item)); + ADD_C(*arr, DICT_OBJ(item)); } diff --git a/src/nvim/highlight.h b/src/nvim/highlight.h index cb3a84bcaf..2ba6cf5371 100644 --- a/src/nvim/highlight.h +++ b/src/nvim/highlight.h @@ -54,6 +54,8 @@ EXTERN const char *hlf_names[] INIT( = { [HLF_SPL] = "SpellLocal", [HLF_PNI] = "Pmenu", [HLF_PSI] = "PmenuSel", + [HLF_PMNI] = "PmenuMatch", + [HLF_PMSI] = "PmenuMatchSel", [HLF_PNK] = "PmenuKind", [HLF_PSK] = "PmenuKindSel", [HLF_PNX] = "PmenuExtra", @@ -78,6 +80,8 @@ EXTERN const char *hlf_names[] INIT( = { [HLF_CU] = "Cursor", [HLF_BTITLE] = "FloatTitle", [HLF_BFOOTER] = "FloatFooter", + [HLF_TS] = "StatusLineTerm", + [HLF_TSNC] = "StatusLineTermNC", }); EXTERN int highlight_attr[HLF_COUNT + 1]; // Highl. attr for each context. diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h index 25ab9dc2d9..e0cce81166 100644 --- a/src/nvim/highlight_defs.h +++ b/src/nvim/highlight_defs.h @@ -101,6 +101,8 @@ typedef enum { HLF_SPL, ///< SpellLocal HLF_PNI, ///< popup menu normal item HLF_PSI, ///< popup menu selected item + HLF_PMNI, ///< popup menu matched text in normal item + HLF_PMSI, ///< popup menu matched text in selected item HLF_PNK, ///< popup menu normal item "kind" HLF_PSK, ///< popup menu selected item "kind" HLF_PNX, ///< popup menu normal item "menu" (extra text) @@ -125,6 +127,8 @@ typedef enum { HLF_CU, ///< Cursor HLF_BTITLE, ///< Float Border Title HLF_BFOOTER, ///< Float Border Footer + HLF_TS, ///< status line for terminal window + HLF_TSNC, ///< status line for non-current terminal window HLF_COUNT, ///< MUST be the last one } hlf_T; diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index ccb093c116..1a0ae3ac49 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -22,6 +22,7 @@ #include "nvim/cursor_shape.h" #include "nvim/decoration_provider.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/vars.h" @@ -143,6 +144,7 @@ static const char e_missing_argument_str[] static const char *highlight_init_both[] = { "Cursor guifg=bg guibg=fg", "CursorLineNr gui=bold cterm=bold", + "PmenuSel gui=reverse cterm=reverse,underline blend=0", "RedrawDebugNormal gui=reverse cterm=reverse", "TabLineSel gui=bold cterm=bold", "TermCursor gui=reverse cterm=reverse", @@ -150,34 +152,38 @@ static const char *highlight_init_both[] = { "lCursor guifg=bg guibg=fg", // UI - "default link CursorIM Cursor", - "default link CursorLineFold FoldColumn", - "default link CursorLineSign SignColumn", - "default link EndOfBuffer NonText", - "default link FloatBorder NormalFloat", - "default link FloatFooter FloatTitle", - "default link FloatTitle Title", - "default link FoldColumn SignColumn", - "default link IncSearch CurSearch", - "default link LineNrAbove LineNr", - "default link LineNrBelow LineNr", - "default link MsgSeparator StatusLine", - "default link MsgArea NONE", - "default link NormalNC NONE", - "default link PmenuExtra Pmenu", - "default link PmenuExtraSel PmenuSel", - "default link PmenuKind Pmenu", - "default link PmenuKindSel PmenuSel", - "default link PmenuSbar Pmenu", - "default link Substitute Search", - "default link TabLine StatusLineNC", - "default link TabLineFill TabLine", - "default link TermCursorNC NONE", - "default link VertSplit WinSeparator", - "default link VisualNOS Visual", - "default link Whitespace NonText", - "default link WildMenu PmenuSel", - "default link WinSeparator Normal", + "default link CursorIM Cursor", + "default link CursorLineFold FoldColumn", + "default link CursorLineSign SignColumn", + "default link EndOfBuffer NonText", + "default link FloatBorder NormalFloat", + "default link FloatFooter FloatTitle", + "default link FloatTitle Title", + "default link FoldColumn SignColumn", + "default link IncSearch CurSearch", + "default link LineNrAbove LineNr", + "default link LineNrBelow LineNr", + "default link MsgSeparator StatusLine", + "default link MsgArea NONE", + "default link NormalNC NONE", + "default link PmenuExtra Pmenu", + "default link PmenuExtraSel PmenuSel", + "default link PmenuKind Pmenu", + "default link PmenuKindSel PmenuSel", + "default link PmenuMatch Pmenu", + "default link PmenuMatchSel PmenuSel", + "default link PmenuSbar Pmenu", + "default link Substitute Search", + "default link StatusLineTerm StatusLine", + "default link StatusLineTermNC StatusLineNC", + "default link TabLine StatusLineNC", + "default link TabLineFill TabLine", + "default link TermCursorNC NONE", + "default link VertSplit WinSeparator", + "default link VisualNOS Visual", + "default link Whitespace NonText", + "default link WildMenu PmenuSel", + "default link WinSeparator Normal", // Syntax "default link Character Constant", @@ -295,6 +301,11 @@ static const char *highlight_init_both[] = { "default link @tag Tag", "default link @tag.builtin Special", + // :help + // Higlight "===" and "---" heading delimiters specially. + "default @markup.heading.1.delimiter.vimdoc guibg=bg guifg=bg guisp=fg gui=underdouble,nocombine ctermbg=NONE ctermfg=NONE cterm=underdouble,nocombine", + "default @markup.heading.2.delimiter.vimdoc guibg=bg guifg=bg guisp=fg gui=underline,nocombine ctermbg=NONE ctermfg=NONE cterm=underline,nocombine", + // LSP semantic tokens "default link @lsp.type.class @type", "default link @lsp.type.comment @comment", @@ -353,7 +364,6 @@ static const char *highlight_init_light[] = { "NonText guifg=NvimLightGrey4", "NormalFloat guibg=NvimLightGrey1", "Pmenu guibg=NvimLightGrey3 cterm=reverse", - "PmenuSel guifg=NvimLightGrey3 guibg=NvimDarkGrey2 cterm=reverse,underline blend=0", "PmenuThumb guibg=NvimLightGrey4", "Question guifg=NvimDarkCyan ctermfg=6", "QuickFixLine guifg=NvimDarkCyan ctermfg=6", @@ -438,7 +448,6 @@ static const char *highlight_init_dark[] = { "NonText guifg=NvimDarkGrey4", "NormalFloat guibg=NvimDarkGrey1", "Pmenu guibg=NvimDarkGrey3 cterm=reverse", - "PmenuSel guifg=NvimDarkGrey3 guibg=NvimLightGrey2 cterm=reverse,underline blend=0", "PmenuThumb guibg=NvimDarkGrey4", "Question guifg=NvimLightCyan ctermfg=14", "QuickFixLine guifg=NvimLightCyan ctermfg=14", @@ -848,7 +857,7 @@ static int color_numbers_8[28] = { 0, 4, 2, 6, // color_names[]. // "boldp" will be set to kTrue or kFalse for a foreground color when using 8 // colors, otherwise it will be unchanged. -int lookup_color(const int idx, const bool foreground, TriState *const boldp) +static int lookup_color(const int idx, const bool foreground, TriState *const boldp) { int color = color_numbers_16[idx]; @@ -1173,7 +1182,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) break; } vim_memcpy_up(key, key_start, key_len); - key[key_len] = '\0'; + key[key_len] = NUL; linep = skipwhite(linep); if (strcmp(key, "NONE") == 0) { @@ -1625,7 +1634,7 @@ static void highlight_list_one(const int id) } } -static bool hlgroup2dict(Dictionary *hl, NS ns_id, int hl_id, Arena *arena) +static bool hlgroup2dict(Dict *hl, NS ns_id, int hl_id, Arena *arena) { HlGroup *sgp = &hl_table[hl_id - 1]; int link = ns_id == 0 ? sgp->sg_link : ns_get_hl(&ns_id, hl_id, true, sgp->sg_set); @@ -1643,18 +1652,19 @@ static bool hlgroup2dict(Dictionary *hl, NS ns_id, int hl_id, Arena *arena) PUT_C(*hl, "default", BOOLEAN_OBJ(true)); } if (link > 0) { + assert(1 <= link && link <= highlight_ga.ga_len); PUT_C(*hl, "link", CSTR_AS_OBJ(hl_table[link - 1].sg_name)); } - Dictionary hl_cterm = arena_dict(arena, HLATTRS_DICT_SIZE); + Dict hl_cterm = arena_dict(arena, HLATTRS_DICT_SIZE); hlattrs2dict(hl, NULL, attr, true, true); hlattrs2dict(hl, &hl_cterm, attr, false, true); if (kv_size(hl_cterm)) { - PUT_C(*hl, "cterm", DICTIONARY_OBJ(hl_cterm)); + PUT_C(*hl, "cterm", DICT_OBJ(hl_cterm)); } return true; } -Dictionary ns_get_hl_defs(NS ns_id, Dict(get_highlight) *opts, Arena *arena, Error *err) +Dict ns_get_hl_defs(NS ns_id, Dict(get_highlight) *opts, Arena *arena, Error *err) { Boolean link = GET_BOOL_OR_TRUE(opts, get_highlight, link); int id = -1; @@ -1663,7 +1673,7 @@ Dictionary ns_get_hl_defs(NS ns_id, Dict(get_highlight) *opts, Arena *arena, Err id = create ? syn_check_group(opts->name.data, opts->name.size) : syn_name2id_len(opts->name.data, opts->name.size); if (id == 0 && !create) { - Dictionary attrs = ARRAY_DICT_INIT; + Dict attrs = ARRAY_DICT_INIT; return attrs; } } else if (HAS_KEY(opts, get_highlight, id)) { @@ -1674,7 +1684,7 @@ Dictionary ns_get_hl_defs(NS ns_id, Dict(get_highlight) *opts, Arena *arena, Err VALIDATE(1 <= id && id <= highlight_ga.ga_len, "%s", "Highlight id out of bounds", { goto cleanup; }); - Dictionary attrs = ARRAY_DICT_INIT; + Dict attrs = ARRAY_DICT_INIT; hlgroup2dict(&attrs, ns_id, link ? id : syn_get_final_id(id), arena); return attrs; } @@ -1682,19 +1692,19 @@ Dictionary ns_get_hl_defs(NS ns_id, Dict(get_highlight) *opts, Arena *arena, Err goto cleanup; } - Dictionary rv = arena_dict(arena, (size_t)highlight_ga.ga_len); + Dict rv = arena_dict(arena, (size_t)highlight_ga.ga_len); for (int i = 1; i <= highlight_ga.ga_len; i++) { - Dictionary attrs = ARRAY_DICT_INIT; + Dict attrs = ARRAY_DICT_INIT; if (!hlgroup2dict(&attrs, ns_id, i, arena)) { continue; } - PUT_C(rv, hl_table[(link ? i : syn_get_final_id(i)) - 1].sg_name, DICTIONARY_OBJ(attrs)); + PUT_C(rv, hl_table[(link ? i : syn_get_final_id(i)) - 1].sg_name, DICT_OBJ(attrs)); } return rv; cleanup: - return (Dictionary)ARRAY_DICT_INIT; + return (Dict)ARRAY_DICT_INIT; } /// Outputs a highlight when doing ":hi MyHighlight" @@ -1966,7 +1976,7 @@ int syn_name2id_len(const char *name, size_t len) // Avoid using stricmp() too much, it's slow on some systems // Avoid alloc()/free(), these are slow too. vim_memcpy_up(name_u, name, len); - name_u[len] = '\0'; + name_u[len] = NUL; // map_get(..., int) returns 0 when no key is present, which is // the expected value for missing highlight group. @@ -2268,7 +2278,6 @@ void highlight_changed(void) // sentinel value. used when no highlight namespace is active highlight_attr[HLF_COUNT] = 0; - // // Setup the user highlights // // Temporarily utilize 10 more hl entries: diff --git a/src/nvim/indent.c b/src/nvim/indent.c index d635c7d7bf..b7e3842aad 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -13,6 +13,7 @@ #include "nvim/cursor.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds_defs.h" @@ -146,25 +147,42 @@ int tabstop_padding(colnr_T col, OptInt ts_arg, const colnr_T *vts) } /// Find the size of the tab that covers a particular column. -int tabstop_at(colnr_T col, OptInt ts, const colnr_T *vts) +/// +/// If this is being called as part of a shift operation, col is not the cursor +/// column but is the column number to the left of the first non-whitespace +/// character in the line. If the shift is to the left (left == true), then +/// return the size of the tab interval to the left of the column. +int tabstop_at(colnr_T col, OptInt ts, const colnr_T *vts, bool left) { - colnr_T tabcol = 0; - int t; - int tab_size = 0; - if (vts == NULL || vts[0] == 0) { return (int)ts; } - const int tabcount = vts[0]; + colnr_T tabcol = 0; // Column of the tab stop under consideration. + int t; // Tabstop index in the list of variable tab stops. + int tab_size = 0; // Size of the tab stop interval to the right or left of the col. + const int tabcount // Number of tab stops in the list of variable tab stops. + = vts[0]; for (t = 1; t <= tabcount; t++) { tabcol += vts[t]; if (tabcol > col) { - tab_size = vts[t]; + // If shifting left (left == true), and if the column to the left of + // the first first non-blank character (col) in the line is + // already to the left of the first tabstop, set the shift amount + // (tab_size) to just enough to shift the line to the left margin. + // The value doesn't seem to matter as long as it is at least that + // distance. + if (left && (t == 1)) { + tab_size = col; + } else { + tab_size = vts[t - (left ? 1 : 0)]; + } break; } } - if (t > tabcount) { + if (t > tabcount) { // If the value of the index t is beyond the + // end of the list, use the tab stop value at + // the end of the list. tab_size = vts[tabcount]; } @@ -311,35 +329,35 @@ int tabstop_first(colnr_T *ts) /// 'tabstop' value when 'shiftwidth' is zero. int get_sw_value(buf_T *buf) { - int result = get_sw_value_col(buf, 0); + int result = get_sw_value_col(buf, 0, false); return result; } /// Idem, using "pos". -int get_sw_value_pos(buf_T *buf, pos_T *pos) +int get_sw_value_pos(buf_T *buf, pos_T *pos, bool left) { pos_T save_cursor = curwin->w_cursor; curwin->w_cursor = *pos; - int sw_value = get_sw_value_col(buf, get_nolist_virtcol()); + int sw_value = get_sw_value_col(buf, get_nolist_virtcol(), left); curwin->w_cursor = save_cursor; return sw_value; } /// Idem, using the first non-black in the current line. -int get_sw_value_indent(buf_T *buf) +int get_sw_value_indent(buf_T *buf, bool left) { pos_T pos = curwin->w_cursor; pos.col = (colnr_T)getwhitecols_curline(); - return get_sw_value_pos(buf, &pos); + return get_sw_value_pos(buf, &pos, left); } /// Idem, using virtual column "col". -int get_sw_value_col(buf_T *buf, colnr_T col) +int get_sw_value_col(buf_T *buf, colnr_T col, bool left) { return buf->b_p_sw ? (int)buf->b_p_sw - : tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array); + : tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array, left); } /// Return the effective softtabstop value for the current buffer, @@ -873,7 +891,17 @@ int get_breakindent_win(win_T *wp, char *line) if (wp->w_briopt_list > 0) { prev_list += wp->w_briopt_list; } else { - prev_indent = (int)(*regmatch.endp - *regmatch.startp); + char *ptr = *regmatch.startp; + char *end_ptr = *regmatch.endp; + int indent = 0; + // Compute the width of the matched text. + // Use win_chartabsize() so that TAB size is correct, + // while wrapping is ignored. + while (ptr < end_ptr) { + indent += win_chartabsize(wp, ptr, indent); + MB_PTR_ADV(ptr); + } + prev_indent = indent; } } vim_regfree(regmatch.regprog); @@ -1143,7 +1171,7 @@ int get_expr_indent(void) // Need to make a copy, the 'indentexpr' option could be changed while // evaluating it. char *inde_copy = xstrdup(curbuf->b_p_inde); - int indent = (int)eval_to_number(inde_copy); + int indent = (int)eval_to_number(inde_copy, true); xfree(inde_copy); if (use_sandbox) { @@ -1389,7 +1417,7 @@ void fixthisline(IndentGetter get_the_indent) return; } - change_indent(INDENT_SET, amount, false, 0, true); + change_indent(INDENT_SET, amount, false, true); if (linewhite(curwin->w_cursor.lnum)) { did_ai = true; // delete the indent if the line stays empty } diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c index 65b5f46333..98b0d6003a 100644 --- a/src/nvim/indent_c.c +++ b/src/nvim/indent_c.c @@ -3419,9 +3419,7 @@ term_again: break; } - // // Skip preprocessor directives and blank lines. - // if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount)) { continue; } diff --git a/src/nvim/input.c b/src/nvim/input.c index e14bfe7539..ef400710fe 100644 --- a/src/nvim/input.c +++ b/src/nvim/input.c @@ -37,7 +37,7 @@ /// @param[in] str Prompt: question to ask user. Is always followed by /// " (y/n)?". /// @param[in] direct Determines what function to use to get user input. If -/// true then os_inchar() will be used, otherwise vgetc(). +/// true then input_get() will be used, otherwise vgetc(). /// I.e. when direct is true then characters are obtained /// directly from the user without buffers involved. /// @@ -111,7 +111,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 ? -1 : 100, 0, events); + n = input_get(buf + len, maxlen, len == 0 ? -1 : 100, 0, events); if (n > 0) { // Replace zero and K_SPECIAL by a special key code. n = fix_input_buffer(buf + len, n); diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index b557b9802e..84dd55fa78 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -22,6 +22,7 @@ #include "nvim/cursor.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -38,10 +39,12 @@ #include "nvim/globals.h" #include "nvim/highlight.h" #include "nvim/highlight_defs.h" +#include "nvim/highlight_group.h" #include "nvim/indent.h" #include "nvim/indent_c.h" #include "nvim/insexpand.h" #include "nvim/keycodes.h" +#include "nvim/lua/executor.h" #include "nvim/macros_defs.h" #include "nvim/mark_defs.h" #include "nvim/mbyte.h" @@ -121,7 +124,7 @@ static char *ctrl_x_msgs[] = { N_(" Command-line completion (^V^N^P)"), N_(" User defined completion (^U^N^P)"), N_(" Omni completion (^O^N^P)"), - N_(" Spelling suggestion (s^N^P)"), + N_(" Spelling suggestion (^S^N^P)"), N_(" Keyword Local completion (^N^P)"), NULL, // CTRL_X_EVAL doesn't use msg. N_(" Command-line completion (^V^N^P)"), @@ -148,13 +151,6 @@ static char *ctrl_x_mode_names[] = { "cmdline", }; -// Array indexes used for cp_text[]. -#define CPT_ABBR 0 ///< "abbr" -#define CPT_MENU 1 ///< "menu" -#define CPT_KIND 2 ///< "kind" -#define CPT_INFO 3 ///< "info" -#define CPT_COUNT 4 ///< Number of entries - /// Structure used to store one match for insert completion. typedef struct compl_S compl_T; struct compl_S { @@ -167,6 +163,9 @@ struct compl_S { ///< cp_flags has CP_FREE_FNAME int cp_flags; ///< CP_ values int cp_number; ///< sequence number + int cp_score; ///< fuzzy match score + int cp_user_hlattr; ///< highlight attribute to combine with + int cp_user_kind_hlattr; ///< highlight attribute for kind }; /// state information used for getting the next set of insert completion @@ -224,13 +223,6 @@ static char *compl_leader = NULL; static bool compl_get_longest = false; ///< put longest common string in compl_leader -static bool compl_no_insert = false; ///< false: select & insert - ///< true: noinsert -static bool compl_no_select = false; ///< false: select & insert - ///< true: noselect -static bool compl_longest = false; ///< false: insert full match - ///< true: insert longest prefix - /// Selected one of the matches. When false the match was edited or using the /// longest common string. static bool compl_used_match; @@ -287,7 +279,7 @@ static bool compl_opt_refresh_always = false; static size_t spell_bad_len = 0; // length of located bad word -static int pum_selected_item = -1; +static int compl_selected_item = -1; /// CTRL-X pressed in Insert mode. void ins_ctrl_x(void) @@ -766,7 +758,7 @@ int ins_compl_add_infercase(char *str_arg, int len, bool icase, char *fname, Dir flags |= CP_ICASE; } - int res = ins_compl_add(str, len, fname, NULL, false, NULL, dir, flags, false); + int res = ins_compl_add(str, len, fname, NULL, false, NULL, dir, flags, false, -1, -1); xfree(tofree); return res; } @@ -806,7 +798,7 @@ static inline void free_cptext(char *const *const cptext) /// returned in case of error. static int ins_compl_add(char *const str, int len, char *const fname, char *const *const cptext, const bool cptext_allocated, typval_T *user_data, const Direction cdir, - int flags_arg, const bool adup) + int flags_arg, const bool adup, int user_hlattr, int user_kind_hlattr) FUNC_ATTR_NONNULL_ARG(1) { compl_T *match; @@ -872,6 +864,8 @@ static int ins_compl_add(char *const str, int len, char *const fname, char *cons match->cp_fname = NULL; } match->cp_flags = flags; + match->cp_user_hlattr = user_hlattr; + match->cp_user_kind_hlattr = user_kind_hlattr; if (cptext != NULL) { int i; @@ -1005,7 +999,7 @@ static void ins_compl_add_matches(int num_matches, char **matches, int icase) for (int i = 0; i < num_matches && add_r != FAIL; i++) { if ((add_r = ins_compl_add(matches[i], -1, NULL, NULL, false, NULL, dir, CP_FAST | (icase ? CP_ICASE : 0), - false)) == OK) { + false, -1, -1)) == OK) { // If dir was BACKWARD then honor it just once. dir = FORWARD; } @@ -1048,22 +1042,10 @@ bool ins_compl_long_shown_match(void) && (colnr_T)strlen(compl_shown_match->cp_str) > curwin->w_cursor.col - compl_col; } -/// Set variables that store noselect and noinsert behavior from the -/// 'completeopt' value. -void completeopt_was_set(void) +/// Get the local or global value of 'completeopt' flags. +unsigned get_cot_flags(void) { - compl_no_insert = false; - compl_no_select = false; - compl_longest = false; - if (strstr(p_cot, "noselect") != NULL) { - compl_no_select = true; - } - if (strstr(p_cot, "noinsert") != NULL) { - compl_no_insert = true; - } - if (strstr(p_cot, "longest") != NULL) { - compl_longest = true; - } + return curbuf->b_cot_flags != 0 ? curbuf->b_cot_flags : cot_flags; } /// "compl_match_array" points the currently displayed list of entries in the @@ -1087,7 +1069,7 @@ bool pum_wanted(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { // "completeopt" must contain "menu" or "menuone" - return vim_strchr(p_cot, 'm') != NULL; + return (get_cot_flags() & COT_ANY_MENU) != 0; } /// Check that there are two or more matches to be shown in the popup menu. @@ -1106,7 +1088,7 @@ static bool pum_enough_matches(void) comp = comp->cp_next; } while (!is_first_match(comp)); - if (strstr(p_cot, "menuone") != NULL) { + if (get_cot_flags() & COT_MENUONE) { return i >= 1; } return i >= 2; @@ -1160,6 +1142,16 @@ static void trigger_complete_changed_event(int cur) restore_v_event(v_event, &save_v_event); } +/// pumitem qsort compare func +static int ins_compl_fuzzy_cmp(const void *a, const void *b) +{ + const int sa = (*(pumitem_T *)a).pum_score; + const int sb = (*(pumitem_T *)b).pum_score; + const int ia = (*(pumitem_T *)a).pum_idx; + const int ib = (*(pumitem_T *)b).pum_idx; + return sa == sb ? (ia == ib ? 0 : (ia < ib ? -1 : 1)) : (sa < sb ? 1 : -1); +} + /// Build a popup menu to show the completion matches. /// /// @return the popup menu entry that should be selected, @@ -1177,11 +1169,22 @@ static int ins_compl_build_pum(void) } const int lead_len = compl_leader != NULL ? (int)strlen(compl_leader) : 0; + int max_fuzzy_score = 0; + unsigned cur_cot_flags = get_cot_flags(); + bool compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0; + bool compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0; do { + // When 'completeopt' contains "fuzzy" and leader is not NULL or empty, + // set the cp_score for later comparisons. + if (compl_fuzzy_match && compl_leader != NULL && lead_len > 0) { + comp->cp_score = fuzzy_match_str(comp->cp_str, compl_leader); + } + if (!match_at_original_text(comp) && (compl_leader == NULL - || ins_compl_equal(comp, compl_leader, (size_t)lead_len))) { + || ins_compl_equal(comp, compl_leader, (size_t)lead_len) + || (compl_fuzzy_match && comp->cp_score > 0))) { compl_match_arraysize++; } comp = comp->cp_next; @@ -1198,6 +1201,10 @@ static int ins_compl_build_pum(void) // match after it, don't highlight anything. bool shown_match_ok = match_at_original_text(compl_shown_match); + if (strequal(compl_leader, compl_orig_text) && !shown_match_ok) { + compl_shown_match = compl_no_select ? compl_first_match : compl_first_match->cp_next; + } + compl_T *shown_compl = NULL; bool did_find_shown_match = false; int cur = -1; @@ -1206,8 +1213,9 @@ static int ins_compl_build_pum(void) do { if (!match_at_original_text(comp) && (compl_leader == NULL - || ins_compl_equal(comp, compl_leader, (size_t)lead_len))) { - if (!shown_match_ok) { + || ins_compl_equal(comp, compl_leader, (size_t)lead_len) + || (compl_fuzzy_match && comp->cp_score > 0))) { + if (!shown_match_ok && !compl_fuzzy_match) { if (comp == compl_shown_match || did_find_shown_match) { // This item is the shown match or this is the // first displayed item after the shown match. @@ -1220,6 +1228,36 @@ static int ins_compl_build_pum(void) shown_compl = comp; } cur = i; + } else if (compl_fuzzy_match) { + if (i == 0) { + shown_compl = comp; + } + // Update the maximum fuzzy score and the shown match + // if the current item's score is higher + if (comp->cp_score > max_fuzzy_score) { + did_find_shown_match = true; + max_fuzzy_score = comp->cp_score; + if (!compl_no_select) { + compl_shown_match = comp; + } + } + + if (!shown_match_ok && comp == compl_shown_match && !compl_no_select) { + cur = i; + shown_match_ok = true; + } + + // If there is no "no select" condition and the max fuzzy + // score is positive, or there is no completion leader or the + // leader length is zero, mark the shown match as valid and + // reset the current index. + if (!compl_no_select + && (max_fuzzy_score > 0 + || (compl_leader == NULL || lead_len == 0))) { + if (match_at_original_text(compl_shown_match)) { + compl_shown_match = shown_compl; + } + } } if (comp->cp_text[CPT_ABBR] != NULL) { @@ -1229,6 +1267,9 @@ static int ins_compl_build_pum(void) } compl_match_array[i].pum_kind = comp->cp_text[CPT_KIND]; compl_match_array[i].pum_info = comp->cp_text[CPT_INFO]; + compl_match_array[i].pum_score = comp->cp_score; + compl_match_array[i].pum_user_hlattr = comp->cp_user_hlattr; + compl_match_array[i].pum_user_kind_hlattr = comp->cp_user_kind_hlattr; if (comp->cp_text[CPT_MENU] != NULL) { compl_match_array[i++].pum_extra = comp->cp_text[CPT_MENU]; } else { @@ -1236,7 +1277,7 @@ static int ins_compl_build_pum(void) } } - if (comp == compl_shown_match) { + if (comp == compl_shown_match && !compl_fuzzy_match) { did_find_shown_match = true; // When the original text is the shown match don't set @@ -1255,6 +1296,16 @@ static int ins_compl_build_pum(void) comp = comp->cp_next; } while (comp != NULL && !is_first_match(comp)); + if (compl_fuzzy_match && compl_leader != NULL && lead_len > 0) { + for (i = 0; i < compl_match_arraysize; i++) { + compl_match_array[i].pum_idx = i; + } + // sort by the largest score of fuzzy match + qsort(compl_match_array, (size_t)compl_match_arraysize, sizeof(pumitem_T), + ins_compl_fuzzy_cmp); + shown_match_ok = true; + } + if (!shown_match_ok) { // no displayed match at all cur = -1; } @@ -1306,7 +1357,7 @@ void ins_compl_show_pum(void) // Use the cursor to get all wrapping and other settings right. const colnr_T col = curwin->w_cursor.col; curwin->w_cursor.col = compl_col; - pum_selected_item = cur; + compl_selected_item = cur; pum_display(compl_match_array, compl_match_arraysize, cur, array_changed, 0); curwin->w_cursor.col = col; @@ -1349,6 +1400,12 @@ bool compl_match_curr_select(int selected) #define DICT_FIRST (1) ///< use just first element in "dict" #define DICT_EXACT (2) ///< "dict" is the exact name of a file +/// Get current completion leader +char *ins_compl_leader(void) +{ + return compl_leader != NULL ? compl_leader : compl_orig_text; +} + /// Add any identifiers that match the given pattern "pat" in the list of /// dictionary files "dict_start" to the list of completions. /// @@ -1730,6 +1787,13 @@ int ins_compl_bs(void) return NUL; } +/// Check if the complete function returned "always" in the "refresh" dictionary item. +static bool ins_compl_refresh_always(void) + FUNC_ATTR_PURE +{ + return (ctrl_x_mode_function() || ctrl_x_mode_omni()) && compl_opt_refresh_always; +} + /// Check that we need to find matches again, ins_compl_restart() is to /// be called. static bool ins_compl_need_restart(void) @@ -1737,9 +1801,7 @@ static bool ins_compl_need_restart(void) { // Return true if we didn't complete finding matches or when the // "completefunc" returned "always" in the "refresh" dictionary item. - return compl_was_interrupted - || ((ctrl_x_mode_function() || ctrl_x_mode_omni()) - && compl_opt_refresh_always); + return compl_was_interrupted || ins_compl_refresh_always(); } /// Called after changing "compl_leader". @@ -1772,7 +1834,7 @@ static void ins_compl_new_leader(void) // Don't let Enter select the original text when there is no popup menu. // Don't let Enter select when use user function and refresh_always is set - if (compl_match_array == NULL || ins_compl_need_restart()) { + if (compl_match_array == NULL || ins_compl_refresh_always()) { compl_enter_selects = false; } } @@ -2174,7 +2236,7 @@ bool ins_compl_prep(int c) // Set "compl_get_longest" when finding the first matches. if (ctrl_x_mode_not_defined_yet() || (ctrl_x_mode_normal() && !compl_started)) { - compl_get_longest = compl_longest; + compl_get_longest = (get_cot_flags() & COT_LONGEST) != 0; compl_used_match = true; } @@ -2480,6 +2542,14 @@ theend: } } +static inline int get_user_highlight_attr(const char *hlname) +{ + if (hlname != NULL && *hlname != NUL) { + return syn_name2attr(hlname); + } + return -1; +} + /// Add a match to the list of matches from Vimscript object /// /// @param[in] tv Object to get matches from. @@ -2497,6 +2567,10 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast) bool empty = false; int flags = fast ? CP_FAST : 0; char *(cptext[CPT_COUNT]); + char *user_hlname = NULL; + char *user_kind_hlname = NULL; + int user_hlattr = -1; + int user_kind_hlattr = -1; typval_T user_data; user_data.v_type = VAR_UNKNOWN; @@ -2506,6 +2580,13 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast) cptext[CPT_MENU] = tv_dict_get_string(tv->vval.v_dict, "menu", true); cptext[CPT_KIND] = tv_dict_get_string(tv->vval.v_dict, "kind", true); cptext[CPT_INFO] = tv_dict_get_string(tv->vval.v_dict, "info", true); + + user_hlname = tv_dict_get_string(tv->vval.v_dict, "hl_group", false); + user_hlattr = get_user_highlight_attr(user_hlname); + + user_kind_hlname = tv_dict_get_string(tv->vval.v_dict, "kind_hlgroup", false); + user_kind_hlattr = get_user_highlight_attr(user_kind_hlname); + tv_dict_get_tv(tv->vval.v_dict, "user_data", &user_data); if (tv_dict_get_number(tv->vval.v_dict, "icase")) { @@ -2527,7 +2608,7 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast) return FAIL; } int status = ins_compl_add((char *)word, -1, NULL, cptext, true, - &user_data, dir, flags, dup); + &user_data, dir, flags, dup, user_hlattr, user_kind_hlattr); if (status != OK) { tv_clear(&user_data); } @@ -2594,6 +2675,10 @@ static void restore_orig_extmarks(void) static void set_completion(colnr_T startcol, list_T *list) { int flags = CP_ORIGINAL_TEXT; + unsigned cur_cot_flags = get_cot_flags(); + bool compl_longest = (cur_cot_flags & COT_LONGEST) != 0; + bool compl_no_insert = (cur_cot_flags & COT_NOINSERT) != 0; + bool compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0; // If already doing completions stop it. if (ctrl_x_mode_not_default()) { @@ -2616,7 +2701,7 @@ static void set_completion(colnr_T startcol, list_T *list) flags |= CP_ICASE; } if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0, - flags | CP_FAST, false) != OK) { + flags | CP_FAST, false, -1, -1) != OK) { return; } @@ -3361,7 +3446,7 @@ static void get_next_bufname_token(void) char *tail = path_tail(b->b_sfname); if (strncmp(tail, compl_orig_text, strlen(compl_orig_text)) == 0) { ins_compl_add(tail, (int)strlen(tail), NULL, NULL, false, NULL, 0, - p_ic ? CP_ICASE : 0, false); + p_ic ? CP_ICASE : 0, false, -1, -1); } } } @@ -3584,6 +3669,44 @@ static void ins_compl_show_filename(void) redraw_cmdline = false; // don't overwrite! } +/// Find a completion item when 'completeopt' contains "fuzzy". +static compl_T *find_comp_when_fuzzy(void) +{ + int target_idx = -1; + const bool is_forward = compl_shows_dir_forward(); + const bool is_backward = compl_shows_dir_backward(); + compl_T *comp = NULL; + + assert(compl_match_array != NULL); + if ((is_forward && compl_selected_item == compl_match_arraysize - 1) + || (is_backward && compl_selected_item == 0)) { + return compl_first_match != compl_shown_match + ? compl_first_match + : (compl_first_match->cp_prev ? compl_first_match->cp_prev : NULL); + } + + if (is_forward) { + target_idx = compl_selected_item + 1; + } else if (is_backward) { + target_idx = compl_selected_item == -1 ? compl_match_arraysize - 1 + : compl_selected_item - 1; + } + + const int score = compl_match_array[target_idx].pum_score; + char *const str = compl_match_array[target_idx].pum_text; + + comp = compl_first_match; + do { + if (comp->cp_score == score + && (str == comp->cp_str || str == comp->cp_text[CPT_ABBR])) { + return comp; + } + comp = comp->cp_next; + } while (comp != NULL && !is_first_match(comp)); + + return NULL; +} + /// Find the next set of matches for completion. Repeat the completion "todo" /// times. The number of matches found is returned in 'num_matches'. /// @@ -3601,17 +3724,22 @@ static int find_next_completion_match(bool allow_get_expansion, int todo, bool a { bool found_end = false; compl_T *found_compl = NULL; + unsigned cur_cot_flags = get_cot_flags(); + bool compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0; + bool compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0; while (--todo >= 0) { if (compl_shows_dir_forward() && compl_shown_match->cp_next != NULL) { - compl_shown_match = compl_shown_match->cp_next; + compl_shown_match = compl_fuzzy_match && compl_match_array != NULL + ? find_comp_when_fuzzy() : compl_shown_match->cp_next; found_end = (compl_first_match != NULL && (is_first_match(compl_shown_match->cp_next) || is_first_match(compl_shown_match))); } else if (compl_shows_dir_backward() && compl_shown_match->cp_prev != NULL) { found_end = is_first_match(compl_shown_match); - compl_shown_match = compl_shown_match->cp_prev; + compl_shown_match = compl_fuzzy_match && compl_match_array != NULL + ? find_comp_when_fuzzy() : compl_shown_match->cp_prev; found_end |= is_first_match(compl_shown_match); } else { if (!allow_get_expansion) { @@ -3655,7 +3783,8 @@ static int find_next_completion_match(bool allow_get_expansion, int todo, bool a if (!match_at_original_text(compl_shown_match) && compl_leader != NULL && !ins_compl_equal(compl_shown_match, - compl_leader, strlen(compl_leader))) { + compl_leader, strlen(compl_leader)) + && !(compl_fuzzy_match && compl_shown_match->cp_score > 0)) { todo++; } else { // Remember a matching item. @@ -3700,6 +3829,9 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match int todo = count; const bool started = compl_started; buf_T *const orig_curbuf = curbuf; + unsigned cur_cot_flags = get_cot_flags(); + bool compl_no_insert = (cur_cot_flags & COT_NOINSERT) != 0; + bool compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0; // When user complete function return -1 for findstart which is next // time of 'always', compl_shown_match become NULL. @@ -3707,7 +3839,9 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match return -1; } - if (compl_leader != NULL && !match_at_original_text(compl_shown_match)) { + if (compl_leader != NULL + && !match_at_original_text(compl_shown_match) + && !compl_fuzzy_match) { // Update "compl_shown_match" to the actually shown match ins_compl_update_shown_match(); } @@ -3836,7 +3970,7 @@ void ins_compl_check_keys(int frequency, bool in_compl_func) } } } - if (compl_pending != 0 && !got_int && !compl_no_insert) { + if (compl_pending != 0 && !got_int && !(cot_flags & COT_NOINSERT)) { int todo = compl_pending > 0 ? compl_pending : -compl_pending; compl_pending = 0; @@ -3849,7 +3983,7 @@ void ins_compl_check_keys(int frequency, bool in_compl_func) static int ins_compl_key2dir(int c) { if (c == K_EVENT || c == K_COMMAND || c == K_LUA) { - return pum_want.item < pum_selected_item ? BACKWARD : FORWARD; + return pum_want.item < compl_selected_item ? BACKWARD : FORWARD; } if (c == Ctrl_P || c == Ctrl_L || c == K_PAGEUP || c == K_KPAGEUP @@ -3875,7 +4009,7 @@ static bool ins_compl_pum_key(int c) static int ins_compl_key2count(int c) { if (c == K_EVENT || c == K_COMMAND || c == K_LUA) { - int offset = pum_want.item - pum_selected_item; + int offset = pum_want.item - compl_selected_item; return abs(offset); } @@ -3974,7 +4108,7 @@ static int get_normal_compl_info(char *line, int startcol, colnr_T curs_col) compl_pattern = xmalloc(7); STRCPY(compl_pattern, "\\<"); quote_meta(compl_pattern + 2, line + compl_col, 1); - STRCAT(compl_pattern, "\\k"); + strcat(compl_pattern, "\\k"); } else { compl_pattern = xmalloc(quote_meta(NULL, line + compl_col, compl_length) + 2); STRCPY(compl_pattern, "\\<"); @@ -4042,6 +4176,9 @@ static int get_cmdline_compl_info(char *line, colnr_T curs_col) compl_pattern = xstrnsave(line, (size_t)curs_col); compl_patternlen = (size_t)curs_col; set_cmd_context(&compl_xp, compl_pattern, (int)compl_patternlen, curs_col, false); + if (compl_xp.xp_context == EXPAND_LUA) { + nlua_expand_pat(&compl_xp); + } if (compl_xp.xp_context == EXPAND_UNSUCCESSFUL || compl_xp.xp_context == EXPAND_NOTHING) { // No completion possible, use an empty pattern to get a @@ -4347,7 +4484,7 @@ static int ins_compl_start(void) flags |= CP_ICASE; } if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0, - flags, false) != OK) { + flags, false, -1, -1) != OK) { XFREE_CLEAR(compl_pattern); compl_patternlen = 0; XFREE_CLEAR(compl_orig_text); diff --git a/src/nvim/insexpand.h b/src/nvim/insexpand.h index b880e64ea4..8c05590b79 100644 --- a/src/nvim/insexpand.h +++ b/src/nvim/insexpand.h @@ -8,3 +8,12 @@ #ifdef INCLUDE_GENERATED_DECLARATIONS # include "insexpand.h.generated.h" #endif + +/// Array indexes used for cp_text[]. +typedef enum { + CPT_ABBR, ///< "abbr" + CPT_KIND, ///< "kind" + CPT_MENU, ///< "menu" + CPT_INFO, ///< "info" + CPT_COUNT, ///< Number of entries +} cpitem_T; diff --git a/src/nvim/keycodes.c b/src/nvim/keycodes.c index 44ddfbba00..f7215d3d12 100644 --- a/src/nvim/keycodes.c +++ b/src/nvim/keycodes.c @@ -8,6 +8,7 @@ #include "nvim/ascii_defs.h" #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/vars.h" #include "nvim/gettext_defs.h" diff --git a/src/nvim/keycodes.h b/src/nvim/keycodes.h index 18af3f87d6..5a7ddd4847 100644 --- a/src/nvim/keycodes.h +++ b/src/nvim/keycodes.h @@ -380,6 +380,10 @@ enum key_extra { #define K_KENTER TERMCAP2KEY('K', 'A') // keypad Enter #define K_KPOINT TERMCAP2KEY('K', 'B') // keypad . or , +// Delimits pasted text (to repeat nvim_paste). Internal-only, not sent by UIs. +#define K_PASTE_START TERMCAP2KEY('P', 'S') // paste start +#define K_PASTE_END TERMCAP2KEY('P', 'E') // paste end + #define K_K0 TERMCAP2KEY('K', 'C') // keypad 0 #define K_K1 TERMCAP2KEY('K', 'D') // keypad 1 #define K_K2 TERMCAP2KEY('K', 'E') // keypad 2 diff --git a/src/nvim/lib/queue_defs.h b/src/nvim/lib/queue_defs.h index 1f113a057a..4f32f5fcb6 100644 --- a/src/nvim/lib/queue_defs.h +++ b/src/nvim/lib/queue_defs.h @@ -21,13 +21,15 @@ #include <stddef.h> -#include "nvim/func_attr.h" - typedef struct queue { struct queue *next; struct queue *prev; } QUEUE; +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "lib/queue_defs.h.inline.generated.h" +#endif + // Public macros. #define QUEUE_DATA(ptr, type, field) \ ((type *)((char *)(ptr) - offsetof(type, field))) @@ -44,29 +46,23 @@ typedef struct queue { } // ffi.cdef is unable to swallow `bool` in place of `int` here. -static inline int QUEUE_EMPTY(const QUEUE *q) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - static inline int QUEUE_EMPTY(const QUEUE *const q) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { return q == q->next; } #define QUEUE_HEAD(q) (q)->next -static inline void QUEUE_INIT(QUEUE *q) - REAL_FATTR_ALWAYS_INLINE; - static inline void QUEUE_INIT(QUEUE *const q) + FUNC_ATTR_ALWAYS_INLINE { q->next = q; q->prev = q; } -static inline void QUEUE_ADD(QUEUE *h, QUEUE *n) - REAL_FATTR_ALWAYS_INLINE; - static inline void QUEUE_ADD(QUEUE *const h, QUEUE *const n) + FUNC_ATTR_ALWAYS_INLINE { h->prev->next = n->next; n->next->prev = h->prev; @@ -74,10 +70,8 @@ static inline void QUEUE_ADD(QUEUE *const h, QUEUE *const n) h->prev->next = h; } -static inline void QUEUE_INSERT_HEAD(QUEUE *h, QUEUE *q) - REAL_FATTR_ALWAYS_INLINE; - static inline void QUEUE_INSERT_HEAD(QUEUE *const h, QUEUE *const q) + FUNC_ATTR_ALWAYS_INLINE { q->next = h->next; q->prev = h; @@ -85,10 +79,8 @@ static inline void QUEUE_INSERT_HEAD(QUEUE *const h, QUEUE *const q) h->next = q; } -static inline void QUEUE_INSERT_TAIL(QUEUE *h, QUEUE *q) - REAL_FATTR_ALWAYS_INLINE; - static inline void QUEUE_INSERT_TAIL(QUEUE *const h, QUEUE *const q) + FUNC_ATTR_ALWAYS_INLINE { q->next = h; q->prev = h->prev; @@ -96,10 +88,8 @@ static inline void QUEUE_INSERT_TAIL(QUEUE *const h, QUEUE *const q) h->prev = q; } -static inline void QUEUE_REMOVE(QUEUE *q) - REAL_FATTR_ALWAYS_INLINE; - static inline void QUEUE_REMOVE(QUEUE *const q) + FUNC_ATTR_ALWAYS_INLINE { q->prev->next = q->next; q->next->prev = q->prev; diff --git a/src/nvim/linematch.c b/src/nvim/linematch.c index c34b303193..8943e6e8a6 100644 --- a/src/nvim/linematch.c +++ b/src/nvim/linematch.c @@ -5,10 +5,13 @@ #include <stdint.h> #include <string.h> +#include "nvim/ascii_defs.h" #include "nvim/linematch.h" #include "nvim/macros_defs.h" #include "nvim/memory.h" #include "nvim/pos_defs.h" +#include "nvim/strings.h" +#include "xdiff/xdiff.h" #define LN_MAX_BUFS 8 #define LN_DECISION_MAX 255 // pow(2, LN_MAX_BUFS(8)) - 1 = 255 @@ -28,49 +31,49 @@ struct diffcmppath_S { # include "linematch.c.generated.h" #endif -static size_t line_len(const char *s) +static size_t line_len(const mmfile_t *m) { - char *end = strchr(s, '\n'); + char *s = m->ptr; + size_t n = (size_t)m->size; + char *end = strnchr(s, &n, '\n'); if (end) { return (size_t)(end - s); } - return strlen(s); + return (size_t)m->size; } +#define MATCH_CHAR_MAX_LEN 800 + /// Same as matching_chars but ignore whitespace /// /// @param s1 /// @param s2 -static int matching_chars_iwhite(const char *s1, const char *s2) +static int matching_chars_iwhite(const mmfile_t *s1, const mmfile_t *s2) { // the newly processed strings that will be compared - // delete the white space characters, and/or replace all upper case with lower - char *strsproc[2]; - const char *strsorig[2] = { s1, s2 }; + // delete the white space characters + mmfile_t sp[2]; + char p[2][MATCH_CHAR_MAX_LEN]; for (int k = 0; k < 2; k++) { - size_t d = 0; - size_t i = 0; - size_t slen = line_len(strsorig[k]); - strsproc[k] = xmalloc((slen + 1) * sizeof(char)); - while (d + i < slen) { - char e = strsorig[k][i + d]; + const mmfile_t *s = k == 0 ? s1 : s2; + size_t pi = 0; + size_t slen = MIN(MATCH_CHAR_MAX_LEN - 1, line_len(s)); + for (size_t i = 0; i <= slen; i++) { + char e = s->ptr[i]; if (e != ' ' && e != '\t') { - strsproc[k][i] = e; - i++; - } else { - d++; + p[k][pi] = e; + pi++; } } - strsproc[k][i] = '\0'; + + sp[k] = (mmfile_t){ + .ptr = p[k], + .size = (int)pi, + }; } - int matching = matching_chars(strsproc[0], strsproc[1]); - xfree(strsproc[0]); - xfree(strsproc[1]); - return matching; + return matching_chars(&sp[0], &sp[1]); } -#define MATCH_CHAR_MAX_LEN 800 - /// Return matching characters between "s1" and "s2" whilst respecting sequence order. /// Consider the case of two strings 'AAACCC' and 'CCCAAA', the /// return value from this function will be 3, either to match @@ -82,12 +85,14 @@ static int matching_chars_iwhite(const char *s1, const char *s2) /// matching_chars("abcdefg", "gfedcba") -> 1 // all characters in common, /// // but only at most 1 in sequence /// -/// @param s1 -/// @param s2 -static int matching_chars(const char *s1, const char *s2) +/// @param m1 +/// @param m2 +static int matching_chars(const mmfile_t *m1, const mmfile_t *m2) { - size_t s1len = MIN(MATCH_CHAR_MAX_LEN - 1, line_len(s1)); - size_t s2len = MIN(MATCH_CHAR_MAX_LEN - 1, line_len(s2)); + size_t s1len = MIN(MATCH_CHAR_MAX_LEN - 1, line_len(m1)); + size_t s2len = MIN(MATCH_CHAR_MAX_LEN - 1, line_len(m2)); + char *s1 = m1->ptr; + char *s2 = m2->ptr; int matrix[2][MATCH_CHAR_MAX_LEN] = { 0 }; bool icur = 1; // save space by storing only two rows for i axis for (size_t i = 0; i < s1len; i++) { @@ -118,13 +123,13 @@ static int matching_chars(const char *s1, const char *s2) /// @param sp /// @param fomvals /// @param n -static int count_n_matched_chars(const char **sp, const size_t n, bool iwhite) +static int count_n_matched_chars(mmfile_t **sp, const size_t n, bool iwhite) { int matched_chars = 0; int matched = 0; for (size_t i = 0; i < n; i++) { for (size_t j = i + 1; j < n; j++) { - if (sp[i] != NULL && sp[j] != NULL) { + if (sp[i]->ptr != NULL && sp[j]->ptr != NULL) { matched++; // TODO(lewis6991): handle whitespace ignoring higher up in the stack matched_chars += iwhite ? matching_chars_iwhite(sp[i], sp[j]) @@ -142,15 +147,17 @@ static int count_n_matched_chars(const char **sp, const size_t n, bool iwhite) return matched_chars; } -void fastforward_buf_to_lnum(const char **s, linenr_T lnum) +mmfile_t fastforward_buf_to_lnum(mmfile_t s, linenr_T lnum) { for (int i = 0; i < lnum - 1; i++) { - *s = strchr(*s, '\n'); - if (!*s) { - return; + s.ptr = strnchr(s.ptr, (size_t *)&s.size, '\n'); + if (!s.ptr) { + break; } - (*s)++; + s.ptr++; + s.size--; } + return s; } /// try all the different ways to compare these lines and use the one that @@ -166,25 +173,25 @@ void fastforward_buf_to_lnum(const char **s, linenr_T lnum) /// @param diff_blk static void try_possible_paths(const int *df_iters, const size_t *paths, const int npaths, const int path_idx, int *choice, diffcmppath_T *diffcmppath, - const int *diff_len, const size_t ndiffs, const char **diff_blk, + const int *diff_len, const size_t ndiffs, const mmfile_t **diff_blk, bool iwhite) { if (path_idx == npaths) { if ((*choice) > 0) { int from_vals[LN_MAX_BUFS] = { 0 }; const int *to_vals = df_iters; - const char *current_lines[LN_MAX_BUFS]; + mmfile_t mm[LN_MAX_BUFS]; // stack memory for current_lines + mmfile_t *current_lines[LN_MAX_BUFS]; for (size_t k = 0; k < ndiffs; k++) { from_vals[k] = df_iters[k]; // get the index at all of the places if ((*choice) & (1 << k)) { from_vals[k]--; - const char *p = diff_blk[k]; - fastforward_buf_to_lnum(&p, df_iters[k]); - current_lines[k] = p; + mm[k] = fastforward_buf_to_lnum(*diff_blk[k], df_iters[k]); } else { - current_lines[k] = NULL; + mm[k] = (mmfile_t){ 0 }; } + current_lines[k] = &mm[k]; } size_t unwrapped_idx_from = unwrap_indexes(from_vals, diff_len, ndiffs); size_t unwrapped_idx_to = unwrap_indexes(to_vals, diff_len, ndiffs); @@ -243,7 +250,7 @@ static size_t unwrap_indexes(const int *values, const int *diff_len, const size_ /// @param ndiffs /// @param diff_blk static void populate_tensor(int *df_iters, const size_t ch_dim, diffcmppath_T *diffcmppath, - const int *diff_len, const size_t ndiffs, const char **diff_blk, + const int *diff_len, const size_t ndiffs, const mmfile_t **diff_blk, bool iwhite) { if (ch_dim == ndiffs) { @@ -326,7 +333,7 @@ static void populate_tensor(int *df_iters, const size_t ch_dim, diffcmppath_T *d /// @param ndiffs /// @param [out] [allocated] decisions /// @return the length of decisions -size_t linematch_nbuffers(const char **diff_blk, const int *diff_len, const size_t ndiffs, +size_t linematch_nbuffers(const mmfile_t **diff_blk, const int *diff_len, const size_t ndiffs, int **decisions, bool iwhite) { assert(ndiffs <= LN_MAX_BUFS); diff --git a/src/nvim/linematch.h b/src/nvim/linematch.h index eaf0d54bec..5f6667a7df 100644 --- a/src/nvim/linematch.h +++ b/src/nvim/linematch.h @@ -3,6 +3,7 @@ #include <stddef.h> // IWYU pragma: keep #include "nvim/pos_defs.h" // IWYU pragma: keep +#include "xdiff/xdiff.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "linematch.h.generated.h" diff --git a/src/nvim/log.c b/src/nvim/log.c index fbb3e0385a..ef5e21aa0a 100644 --- a/src/nvim/log.c +++ b/src/nvim/log.c @@ -29,6 +29,7 @@ #include "nvim/os/stdpaths_defs.h" #include "nvim/os/time.h" #include "nvim/path.h" +#include "nvim/ui_client.h" /// Cached location of the expanded log file path decided by log_path_init(). static char log_file_path[MAXPATHL + 1] = { 0 }; @@ -46,7 +47,7 @@ static uv_mutex_t mutex; static bool log_try_create(char *fname) { - if (fname == NULL || fname[0] == '\0') { + if (fname == NULL || fname[0] == NUL) { return false; } FILE *log_file = fopen(fname, "a"); @@ -67,7 +68,7 @@ static void log_path_init(void) size_t size = sizeof(log_file_path); expand_env("$" ENV_LOGFILE, log_file_path, (int)size - 1); if (strequal("$" ENV_LOGFILE, log_file_path) - || log_file_path[0] == '\0' + || log_file_path[0] == NUL || os_isdir(log_file_path) || !log_try_create(log_file_path)) { // Make $XDG_STATE_HOME if it does not exist. @@ -88,7 +89,7 @@ static void log_path_init(void) } // Fall back to stderr if (len >= size || !log_try_create(log_file_path)) { - log_file_path[0] = '\0'; + log_file_path[0] = NUL; return; } os_setenv(ENV_LOGFILE, log_file_path, true); @@ -257,6 +258,7 @@ void log_callstack_to_file(FILE *log_file, const char *const func_name, const in do_log_to_file(log_file, LOGLVL_DBG, NULL, func_name, line_num, true, "trace:"); FILE *fp = popen(cmdbuf, "r"); + assert(fp); char linebuf[IOSIZE]; while (fgets(linebuf, sizeof(linebuf) - 1, fp) != NULL) { fprintf(log_file, " %s", linebuf); @@ -322,20 +324,28 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context, millis = (int)curtime.tv_usec / 1000; } + bool ui = !!ui_client_channel_id; // Running as a UI client (--remote-ui). + + // Regenerate the name when: + // - UI client (to ensure "ui" is in the name) + // - not set yet + // - no v:servername yet + bool regen = ui || name[0] == NUL || name[0] == '?'; + // Get a name for this Nvim instance. // TODO(justinmk): expose this as v:name ? - if (name[0] == '\0') { - // Parent servername. + if (regen) { + // Parent servername ($NVIM). const char *parent = path_tail(os_getenv(ENV_NVIM)); // Servername. Empty until starting=false. const char *serv = path_tail(get_vim_var_str(VV_SEND_SERVER)); if (parent[0] != NUL) { - snprintf(name, sizeof(name), "%s/c", parent); // "/c" indicates child. + snprintf(name, sizeof(name), ui ? "ui/c/%s" : "c/%s", parent); // "c/" = child of $NVIM. } else if (serv[0] != NUL) { - snprintf(name, sizeof(name), "%s", serv); + snprintf(name, sizeof(name), ui ? "ui/%s" : "%s", serv); } else { int64_t pid = os_get_pid(); - snprintf(name, sizeof(name), "?.%-5" PRId64, pid); + snprintf(name, sizeof(name), "%s.%-5" PRId64, ui ? "ui" : "?", pid); } } @@ -348,10 +358,6 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context, log_levels[log_level], date_time, millis, name, (context == NULL ? "" : context), func_name, line_num); - if (name[0] == '?') { - // No v:servername yet. Clear `name` so that the next log can try again. - name[0] = '\0'; - } if (rv < 0) { return false; diff --git a/src/nvim/lua/api_wrappers.c b/src/nvim/lua/api_wrappers.c index 2b7b0c6471..36847d1fc9 100644 --- a/src/nvim/lua/api_wrappers.c +++ b/src/nvim/lua/api_wrappers.c @@ -5,6 +5,7 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" +#include "nvim/errors.h" #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" #include "nvim/func_attr.h" diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 38ccb03cfc..45ead154bc 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -26,13 +26,13 @@ #include "nvim/types_defs.h" #include "nvim/vim_defs.h" -/// Determine, which keys lua table contains +/// Determine, which keys Lua table contains typedef struct { size_t maxidx; ///< Maximum positive integral value found. size_t string_keys_num; ///< Number of string keys. bool has_string_with_nul; ///< True if there is string key with NUL byte. ObjectType type; ///< If has_type_key is true then attached value. Otherwise - ///< either kObjectTypeNil, kObjectTypeDictionary or + ///< either kObjectTypeNil, kObjectTypeDict or ///< kObjectTypeArray, depending on other properties. lua_Number val; ///< If has_val_key and val_type == LUA_TNUMBER: value. bool has_type_key; ///< True if type key is present. @@ -52,7 +52,7 @@ static LuaTableProps nlua_traverse_table(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { size_t tsize = 0; // Total number of keys. - int val_type = 0; // If has_val_key: lua type of the value. + int val_type = 0; // If has_val_key: Lua type of the value. bool has_val_key = false; // True if val key was found, // @see nlua_push_val_idx(). size_t other_keys_num = 0; // Number of keys that are not string, integral @@ -96,7 +96,7 @@ static LuaTableProps nlua_traverse_table(lua_State *const lstate) lua_Number n = lua_tonumber(lstate, -1); if (n == (lua_Number)kObjectTypeFloat || n == (lua_Number)kObjectTypeArray - || n == (lua_Number)kObjectTypeDictionary) { + || n == (lua_Number)kObjectTypeDict) { ret.has_type_key = true; ret.type = (ObjectType)n; } else { @@ -122,6 +122,7 @@ static LuaTableProps nlua_traverse_table(lua_State *const lstate) lua_pop(lstate, 1); } if (ret.has_type_key) { + assert(tsize > 0); if (ret.type == kObjectTypeFloat && (!has_val_key || val_type != LUA_TNUMBER)) { ret.type = kObjectTypeNil; @@ -156,12 +157,12 @@ static LuaTableProps nlua_traverse_table(lua_State *const lstate) if (tsize == 0 && lua_getmetatable(lstate, -1)) { nlua_pushref(lstate, nlua_global_refs->empty_dict_ref); if (lua_rawequal(lstate, -2, -1)) { - ret.type = kObjectTypeDictionary; + ret.type = kObjectTypeDict; } lua_pop(lstate, 2); } } else if (ret.string_keys_num == tsize) { - ret.type = kObjectTypeDictionary; + ret.type = kObjectTypeDict; } else { ret.type = kObjectTypeNil; } @@ -174,14 +175,14 @@ typedef struct { typval_T *tv; ///< Location where conversion result is saved. size_t list_len; ///< Maximum length when tv is a list. bool container; ///< True if tv is a container. - bool special; ///< If true then tv is a _VAL part of special dictionary + bool special; ///< If true then tv is a _VAL part of special dict. ///< that represents mapping. int idx; ///< Container index (used to detect self-referencing structures). } TVPopStackItem; -/// Convert lua object to Vimscript typval_T +/// Convert Lua object to Vimscript typval_T /// -/// Should pop exactly one value from lua stack. +/// Should pop exactly one value from Lua stack. /// /// @param lstate Lua state. /// @param[out] ret_tv Where to put the result. @@ -219,12 +220,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) if (cur.special) { list_T *const kv_pair = tv_list_alloc(2); - typval_T s_tv = decode_string(s, len, kTrue, false, false); - if (s_tv.v_type == VAR_UNKNOWN) { - ret = false; - tv_list_unref(kv_pair); - continue; - } + typval_T s_tv = decode_string(s, len, true, false); tv_list_append_owned_tv(kv_pair, s_tv); // Value: not populated yet, need to create list item to push. @@ -280,10 +276,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) case LUA_TSTRING: { size_t len; const char *s = lua_tolstring(lstate, -1, &len); - *cur.tv = decode_string(s, len, kNone, true, false); - if (cur.tv->v_type == VAR_UNKNOWN) { - ret = false; - } + *cur.tv = decode_string(s, len, false, false); break; } case LUA_TNUMBER: { @@ -330,7 +323,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) kvi_push(stack, cur); } break; - case kObjectTypeDictionary: + case kObjectTypeDict: if (table_props.string_keys_num == 0) { cur.tv->v_type = VAR_DICT; cur.tv->vval.v_dict = tv_dict_alloc(); @@ -365,7 +358,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) cur.tv->vval.v_float = (float_T)table_props.val; break; case kObjectTypeNil: - emsg(_("E5100: Cannot convert given lua table: table should " + emsg(_("E5100: Cannot convert given Lua table: table should " "contain either only integer keys or only string keys")); ret = false; break; @@ -393,13 +386,13 @@ nlua_pop_typval_table_processing_end: cur.tv->v_type = VAR_SPECIAL; cur.tv->vval.v_special = kSpecialVarNull; } else { - emsg(_("E5101: Cannot convert given lua type")); + emsg(_("E5101: Cannot convert given Lua type")); ret = false; } break; } default: - emsg(_("E5101: Cannot convert given lua type")); + emsg(_("E5101: Cannot convert given Lua type")); ret = false; break; } @@ -425,6 +418,8 @@ static bool typval_conv_special = false; #define TYPVAL_ENCODE_ALLOW_SPECIALS true +#define TYPVAL_ENCODE_CHECK_BEFORE + #define TYPVAL_ENCODE_CONV_NIL(tv) \ do { \ if (typval_conv_special) { \ @@ -480,7 +475,7 @@ static bool typval_conv_special = false; #define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ do { \ if (typval_conv_special) { \ - nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary); \ + nlua_create_typed_table(lstate, 0, 0, kObjectTypeDict); \ } else { \ lua_createtable(lstate, 0, 0); \ nlua_pushref(lstate, nlua_global_refs->empty_dict_ref); \ @@ -574,6 +569,7 @@ static bool typval_conv_special = false; #undef TYPVAL_ENCODE_CONV_LIST_START #undef TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START #undef TYPVAL_ENCODE_CONV_EMPTY_DICT +#undef TYPVAL_ENCODE_CHECK_BEFORE #undef TYPVAL_ENCODE_CONV_NIL #undef TYPVAL_ENCODE_CONV_BOOL #undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER @@ -588,10 +584,9 @@ static bool typval_conv_special = false; #undef TYPVAL_ENCODE_CONV_RECURSE #undef TYPVAL_ENCODE_ALLOW_SPECIALS -/// Convert Vimscript typval_T to lua value +/// Convert Vimscript typval_T to Lua value /// -/// Should leave single value in lua stack. May only fail if lua failed to grow -/// stack. +/// Should leave single value in Lua stack. May only fail if Lua failed to grow stack. /// /// @param lstate Lua interpreter state. /// @param[in] tv typval_T to convert. @@ -659,7 +654,7 @@ static inline void nlua_create_typed_table(lua_State *lstate, const size_t narr, lua_rawset(lstate, -3); } -/// Convert given String to lua string +/// Convert given String to Lua string /// /// Leaves converted string on top of the stack. void nlua_push_String(lua_State *lstate, const String s, int flags) @@ -668,7 +663,7 @@ void nlua_push_String(lua_State *lstate, const String s, int flags) lua_pushlstring(lstate, s.data, s.size); } -/// Convert given Integer to lua number +/// Convert given Integer to Lua number /// /// Leaves converted number on top of the stack. void nlua_push_Integer(lua_State *lstate, const Integer n, int flags) @@ -677,7 +672,7 @@ void nlua_push_Integer(lua_State *lstate, const Integer n, int flags) lua_pushnumber(lstate, (lua_Number)n); } -/// Convert given Float to lua table +/// Convert given Float to Lua table /// /// Leaves converted table on top of the stack. void nlua_push_Float(lua_State *lstate, const Float f, int flags) @@ -693,7 +688,7 @@ void nlua_push_Float(lua_State *lstate, const Float f, int flags) } } -/// Convert given Float to lua boolean +/// Convert given Float to Lua boolean /// /// Leaves converted value on top of the stack. void nlua_push_Boolean(lua_State *lstate, const Boolean b, int flags) @@ -702,20 +697,16 @@ void nlua_push_Boolean(lua_State *lstate, const Boolean b, int flags) lua_pushboolean(lstate, b); } -/// Convert given Dictionary to lua table +/// Convert given Dict to Lua table /// /// Leaves converted table on top of the stack. -void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict, int flags) +void nlua_push_Dict(lua_State *lstate, const Dict dict, int flags) FUNC_ATTR_NONNULL_ALL { - if (dict.size == 0 && (flags & kNluaPushSpecial)) { - nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary); - } else { - lua_createtable(lstate, 0, (int)dict.size); - if (dict.size == 0 && !(flags & kNluaPushSpecial)) { - nlua_pushref(lstate, nlua_global_refs->empty_dict_ref); - lua_setmetatable(lstate, -2); - } + lua_createtable(lstate, 0, (int)dict.size); + if (dict.size == 0) { + nlua_pushref(lstate, nlua_global_refs->empty_dict_ref); + lua_setmetatable(lstate, -2); } for (size_t i = 0; i < dict.size; i++) { nlua_push_String(lstate, dict.items[i].key, flags); @@ -724,7 +715,7 @@ void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict, int flags) } } -/// Convert given Array to lua table +/// Convert given Array to Lua table /// /// Leaves converted table on top of the stack. void nlua_push_Array(lua_State *lstate, const Array array, int flags) @@ -750,7 +741,7 @@ GENERATE_INDEX_FUNCTION(Tabpage) #undef GENERATE_INDEX_FUNCTION -/// Convert given Object to lua value +/// Convert given Object to Lua value /// /// Leaves converted value on top of the stack. void nlua_push_Object(lua_State *lstate, Object *obj, int flags) @@ -777,12 +768,12 @@ void nlua_push_Object(lua_State *lstate, Object *obj, int flags) nlua_push_##type(lstate, obj->data.data_key, flags); \ break; \ } - ADD_TYPE(Boolean, boolean) - ADD_TYPE(Integer, integer) - ADD_TYPE(Float, floating) - ADD_TYPE(String, string) - ADD_TYPE(Array, array) - ADD_TYPE(Dictionary, dictionary) + ADD_TYPE(Boolean, boolean) + ADD_TYPE(Integer, integer) + ADD_TYPE(Float, floating) + ADD_TYPE(String, string) + ADD_TYPE(Array, array) + ADD_TYPE(Dict, dict) #undef ADD_TYPE #define ADD_REMOTE_TYPE(type) \ case kObjectType##type: { \ @@ -796,7 +787,7 @@ void nlua_push_Object(lua_State *lstate, Object *obj, int flags) } } -/// Convert lua value to string +/// Convert Lua value to string /// /// Always pops one value from the stack. String nlua_pop_String(lua_State *lstate, Arena *arena, Error *err) @@ -811,16 +802,16 @@ String nlua_pop_String(lua_State *lstate, Arena *arena, Error *err) ret.data = (char *)lua_tolstring(lstate, -1, &(ret.size)); assert(ret.data != NULL); - // TODO(bfredl): it would be "nice" to just use the memory of the lua string + // TODO(bfredl): it would be "nice" to just use the memory of the Lua string // directly, although ensuring the lifetime of such strings is a bit tricky - // (an API call could invoke nested lua, which triggers GC, and kaboom?) + // (an API call could invoke nested Lua, which triggers GC, and kaboom?) ret.data = arena_memdupz(arena, ret.data, ret.size); lua_pop(lstate, 1); return ret; } -/// Convert lua value to integer +/// Convert Lua value to integer /// /// Always pops one value from the stack. Integer nlua_pop_Integer(lua_State *lstate, Arena *arena, Error *err) @@ -841,10 +832,10 @@ Integer nlua_pop_Integer(lua_State *lstate, Arena *arena, Error *err) return (Integer)n; } -/// Convert lua value to boolean +/// Convert Lua value to boolean /// -/// Despite the name of the function, this uses lua semantics for booleans. -/// thus `err` is never set as any lua value can be co-erced into a lua bool +/// Despite the name of the function, this uses Lua semantics for booleans. +/// thus `err` is never set as any Lua value can be co-erced into a Lua bool /// /// Always pops one value from the stack. Boolean nlua_pop_Boolean(lua_State *lstate, Arena *arena, Error *err) @@ -855,7 +846,7 @@ Boolean nlua_pop_Boolean(lua_State *lstate, Arena *arena, Error *err) return ret; } -/// Convert lua value to boolean +/// Convert Lua value to boolean /// /// This follows API conventions for a Boolean value, compare api_object_to_bool /// @@ -905,9 +896,9 @@ static inline LuaTableProps nlua_check_type(lua_State *const lstate, Error *cons } LuaTableProps table_props = nlua_traverse_table(lstate); - if (type == kObjectTypeDictionary && table_props.type == kObjectTypeArray + if (type == kObjectTypeDict && table_props.type == kObjectTypeArray && table_props.maxidx == 0 && !table_props.has_type_key) { - table_props.type = kObjectTypeDictionary; + table_props.type = kObjectTypeDict; } if (table_props.type != type) { @@ -919,7 +910,7 @@ static inline LuaTableProps nlua_check_type(lua_State *const lstate, Error *cons return table_props; } -/// Convert lua table to float +/// Convert Lua table to float /// /// Always pops one value from the stack. Float nlua_pop_Float(lua_State *lstate, Arena *arena, Error *err) @@ -940,7 +931,7 @@ Float nlua_pop_Float(lua_State *lstate, Arena *arena, Error *err) return (Float)table_props.val; } -/// Convert lua table to array without determining whether it is array +/// Convert Lua table to array without determining whether it is array /// /// @param lstate Lua state. /// @param[in] table_props nlua_traverse_table() output. @@ -975,7 +966,7 @@ static Array nlua_pop_Array_unchecked(lua_State *const lstate, const LuaTablePro return ret; } -/// Convert lua table to array +/// Convert Lua table to array /// /// Always pops one value from the stack. Array nlua_pop_Array(lua_State *lstate, Arena *arena, Error *err) @@ -988,7 +979,7 @@ Array nlua_pop_Array(lua_State *lstate, Arena *arena, Error *err) return nlua_pop_Array_unchecked(lstate, table_props, arena, err); } -/// Convert lua table to dictionary +/// Convert Lua table to dictionary /// /// Always pops one value from the stack. Does not check whether whether topmost /// value on the stack is a table. @@ -996,11 +987,11 @@ Array nlua_pop_Array(lua_State *lstate, Arena *arena, Error *err) /// @param lstate Lua interpreter state. /// @param[in] table_props nlua_traverse_table() output. /// @param[out] err Location where error will be saved. -static Dictionary nlua_pop_Dictionary_unchecked(lua_State *lstate, const LuaTableProps table_props, - bool ref, Arena *arena, Error *err) +static Dict nlua_pop_Dict_unchecked(lua_State *lstate, const LuaTableProps table_props, bool ref, + Arena *arena, Error *err) FUNC_ATTR_NONNULL_ARG(1, 5) FUNC_ATTR_WARN_UNUSED_RESULT { - Dictionary ret = arena_dict(arena, table_props.string_keys_num); + Dict ret = arena_dict(arena, table_props.string_keys_num); if (table_props.string_keys_num == 0) { lua_pop(lstate, 1); @@ -1029,11 +1020,11 @@ static Dictionary nlua_pop_Dictionary_unchecked(lua_State *lstate, const LuaTabl if (ERROR_SET(err)) { if (!arena) { - api_free_dictionary(ret); + api_free_dict(ret); } lua_pop(lstate, 2); // stack: - return (Dictionary) { .size = 0, .items = NULL }; + return (Dict) { .size = 0, .items = NULL }; } i++; } else { @@ -1046,20 +1037,20 @@ static Dictionary nlua_pop_Dictionary_unchecked(lua_State *lstate, const LuaTabl return ret; } -/// Convert lua table to dictionary +/// Convert Lua table to dictionary /// /// Always pops one value from the stack. -Dictionary nlua_pop_Dictionary(lua_State *lstate, bool ref, Arena *arena, Error *err) +Dict nlua_pop_Dict(lua_State *lstate, bool ref, Arena *arena, Error *err) FUNC_ATTR_NONNULL_ARG(1, 4) FUNC_ATTR_WARN_UNUSED_RESULT { const LuaTableProps table_props = nlua_check_type(lstate, err, - kObjectTypeDictionary); - if (table_props.type != kObjectTypeDictionary) { + kObjectTypeDict); + if (table_props.type != kObjectTypeDict) { lua_pop(lstate, 1); - return (Dictionary) { .size = 0, .items = NULL }; + return (Dict) { .size = 0, .items = NULL }; } - return nlua_pop_Dictionary_unchecked(lstate, table_props, ref, arena, err); + return nlua_pop_Dict_unchecked(lstate, table_props, ref, arena, err); } /// Helper structure for nlua_pop_Object @@ -1068,7 +1059,7 @@ typedef struct { bool container; ///< True if tv is a container. } ObjPopStackItem; -/// Convert lua table to object +/// Convert Lua table to object /// /// Always pops one value from the stack. Object nlua_pop_Object(lua_State *const lstate, bool ref, Arena *arena, Error *const err) @@ -1086,9 +1077,9 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Arena *arena, Error *c api_set_error(err, kErrorTypeException, "Lua failed to grow stack"); break; } - if (cur.obj->type == kObjectTypeDictionary) { + if (cur.obj->type == kObjectTypeDict) { // stack: …, dict, key - if (cur.obj->data.dictionary.size == cur.obj->data.dictionary.capacity) { + if (cur.obj->data.dict.size == cur.obj->data.dict.capacity) { lua_pop(lstate, 2); continue; } @@ -1106,10 +1097,10 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Arena *arena, Error *c // stack: …, dict, new key, val size_t len; const char *s = lua_tolstring(lstate, -2, &len); - const size_t idx = cur.obj->data.dictionary.size++; - cur.obj->data.dictionary.items[idx].key = CBUF_TO_ARENA_STR(arena, s, len); + const size_t idx = cur.obj->data.dict.size++; + cur.obj->data.dict.items[idx].key = CBUF_TO_ARENA_STR(arena, s, len); kvi_push(stack, cur); - cur = (ObjPopStackItem){ .obj = &cur.obj->data.dictionary.items[idx].value }; + cur = (ObjPopStackItem){ .obj = &cur.obj->data.dict.items[idx].value }; } else { // stack: …, dict lua_pop(lstate, 1); @@ -1160,14 +1151,16 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Arena *arena, Error *c if (table_props.maxidx != 0) { cur.obj->data.array = arena_array(arena, table_props.maxidx); cur.container = true; + assert(kv_size(stack) < SIZE_MAX); kvi_push(stack, cur); } break; - case kObjectTypeDictionary: - *cur.obj = DICTIONARY_OBJ(((Dictionary)ARRAY_DICT_INIT)); + case kObjectTypeDict: + *cur.obj = DICT_OBJ(((Dict)ARRAY_DICT_INIT)); if (table_props.string_keys_num != 0) { - cur.obj->data.dictionary = arena_dict(arena, table_props.string_keys_num); + cur.obj->data.dict = arena_dict(arena, table_props.string_keys_num); cur.container = true; + assert(kv_size(stack) < SIZE_MAX); kvi_push(stack, cur); lua_pushnil(lstate); } @@ -1200,16 +1193,14 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Arena *arena, Error *c if (is_nil) { *cur.obj = NIL; } else { - api_set_error(err, kErrorTypeValidation, - "Cannot convert userdata"); + api_set_error(err, kErrorTypeValidation, "Cannot convert userdata"); } break; } default: type_error: - api_set_error(err, kErrorTypeValidation, - "Cannot convert given lua type"); + api_set_error(err, kErrorTypeValidation, "Cannot convert given Lua type"); break; } if (!cur.container) { @@ -1287,16 +1278,16 @@ void nlua_init_types(lua_State *const lstate) lua_rawset(lstate, -3); LUA_PUSH_STATIC_STRING(lstate, "dictionary"); - lua_pushnumber(lstate, (lua_Number)kObjectTypeDictionary); + lua_pushnumber(lstate, (lua_Number)kObjectTypeDict); lua_rawset(lstate, -3); - lua_pushnumber(lstate, (lua_Number)kObjectTypeDictionary); + lua_pushnumber(lstate, (lua_Number)kObjectTypeDict); LUA_PUSH_STATIC_STRING(lstate, "dictionary"); lua_rawset(lstate, -3); lua_rawset(lstate, -3); } -// lua specific variant of api_dict_to_keydict +// Lua specific variant of api_dict_to_keydict void nlua_pop_keydict(lua_State *L, void *retval, FieldHashfn hashy, char **err_opt, Arena *arena, Error *err) { @@ -1346,8 +1337,8 @@ void nlua_pop_keydict(lua_State *L, void *retval, FieldHashfn hashy, char **err_ *(handle_T *)mem = nlua_pop_handle(L, arena, err); } else if (field->type == kObjectTypeArray) { *(Array *)mem = nlua_pop_Array(L, arena, err); - } else if (field->type == kObjectTypeDictionary) { - *(Dictionary *)mem = nlua_pop_Dictionary(L, false, arena, err); + } else if (field->type == kObjectTypeDict) { + *(Dict *)mem = nlua_pop_Dict(L, false, arena, err); } else if (field->type == kObjectTypeLuaRef) { *(LuaRef *)mem = nlua_pop_LuaRef(L, arena, err); } else { @@ -1396,8 +1387,8 @@ void nlua_push_keydict(lua_State *L, void *value, KeySetLink *table) nlua_push_String(L, *(String *)mem, 0); } else if (field->type == kObjectTypeArray) { nlua_push_Array(L, *(Array *)mem, 0); - } else if (field->type == kObjectTypeDictionary) { - nlua_push_Dictionary(L, *(Dictionary *)mem, 0); + } else if (field->type == kObjectTypeDict) { + nlua_push_Dict(L, *(Dict *)mem, 0); } else if (field->type == kObjectTypeLuaRef) { nlua_pushref(L, *(LuaRef *)mem); } else { diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index a76b8213e5..d4940f3add 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -22,6 +22,7 @@ #include "nvim/cmdexpand_defs.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" @@ -923,6 +924,7 @@ void nlua_free_all_mem(void) lua_State *lstate = global_lstate; nlua_unref_global(lstate, require_ref); nlua_common_free_all_mem(lstate); + tslua_free(); } static void nlua_common_free_all_mem(lua_State *lstate) @@ -1901,8 +1903,13 @@ static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_pushcfunction(lstate, tslua_push_querycursor); lua_setfield(lstate, -2, "_create_ts_querycursor"); - lua_pushcfunction(lstate, tslua_add_language); - lua_setfield(lstate, -2, "_ts_add_language"); + lua_pushcfunction(lstate, tslua_add_language_from_object); + lua_setfield(lstate, -2, "_ts_add_language_from_object"); + +#ifdef HAVE_WASMTIME + lua_pushcfunction(lstate, tslua_add_language_from_wasm); + lua_setfield(lstate, -2, "_ts_add_language_from_wasm"); +#endif lua_pushcfunction(lstate, tslua_has_language); lua_setfield(lstate, -2, "_ts_has_language"); @@ -1923,10 +1930,14 @@ static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_setfield(lstate, -2, "_ts_get_minimum_language_version"); } -int nlua_expand_pat(expand_T *xp, char *pat, int *num_results, char ***results) +static garray_T expand_result_array = GA_EMPTY_INIT_VALUE; + +/// Finds matches for Lua cmdline completion and advances xp->xp_pattern after prefix. +/// This should be called before xp->xp_pattern is first used. +void nlua_expand_pat(expand_T *xp) { lua_State *const lstate = global_lstate; - int ret = OK; + int status = FAIL; // [ vim ] lua_getglobal(lstate, "vim"); @@ -1935,60 +1946,59 @@ int nlua_expand_pat(expand_T *xp, char *pat, int *num_results, char ***results) lua_getfield(lstate, -1, "_expand_pat"); luaL_checktype(lstate, -1, LUA_TFUNCTION); - // [ vim, vim._expand_pat, buf ] - lua_pushlstring(lstate, pat, strlen(pat)); + // [ vim, vim._expand_pat, pat ] + const char *pat = xp->xp_pattern; + assert(xp->xp_line + xp->xp_col >= pat); + ptrdiff_t patlen = xp->xp_line + xp->xp_col - pat; + lua_pushlstring(lstate, pat, (size_t)patlen); if (nlua_pcall(lstate, 1, 2) != 0) { - nlua_error(lstate, - _("Error executing vim._expand_pat: %.*s")); - return FAIL; + nlua_error(lstate, _("Error executing vim._expand_pat: %.*s")); + return; } Error err = ERROR_INIT; - *num_results = 0; - *results = NULL; - Arena arena = ARENA_EMPTY; - int prefix_len = (int)nlua_pop_Integer(lstate, &arena, &err); - if (ERROR_SET(&err)) { - ret = FAIL; + ptrdiff_t prefix_len = nlua_pop_Integer(lstate, &arena, &err); + if (ERROR_SET(&err) || prefix_len > patlen) { goto cleanup; } Array completions = nlua_pop_Array(lstate, &arena, &err); if (ERROR_SET(&err)) { - ret = FAIL; goto cleanup_array; } - garray_T result_array; - ga_init(&result_array, (int)sizeof(char *), 80); + ga_clear(&expand_result_array); + ga_init(&expand_result_array, (int)sizeof(char *), 80); + for (size_t i = 0; i < completions.size; i++) { Object v = completions.items[i]; - if (v.type != kObjectTypeString) { - ret = FAIL; goto cleanup_array; } - - GA_APPEND(char *, &result_array, string_to_cstr(v.data.string)); + GA_APPEND(char *, &expand_result_array, string_to_cstr(v.data.string)); } xp->xp_pattern += prefix_len; - *results = result_array.ga_data; - *num_results = result_array.ga_len; + status = OK; cleanup_array: arena_mem_free(arena_finish(&arena)); cleanup: - - if (ret == FAIL) { - ga_clear(&result_array); + if (status == FAIL) { + ga_clear(&expand_result_array); } +} - return ret; +int nlua_expand_get_matches(int *num_results, char ***results) +{ + *results = expand_result_array.ga_data; + *num_results = expand_result_array.ga_len; + expand_result_array = (garray_T)GA_EMPTY_INIT_VALUE; + return *num_results > 0; } static int nlua_is_thread(lua_State *lstate) @@ -2053,10 +2063,11 @@ char *nlua_register_table_as_callable(const typval_T *const arg) return name; } -void nlua_execute_on_key(int c, char *typed_buf, size_t typed_len) +void nlua_execute_on_key(int c, char *typed_buf) { char buf[MB_MAXBYTES * 3 + 4]; size_t buf_len = special_to_buf(c, mod_mask, false, buf); + vim_unescape_ks(typed_buf); lua_State *const lstate = global_lstate; @@ -2075,7 +2086,7 @@ void nlua_execute_on_key(int c, char *typed_buf, size_t typed_len) lua_pushlstring(lstate, buf, buf_len); // [ vim, vim._on_key, buf, typed_buf ] - lua_pushlstring(lstate, typed_buf, typed_len); + lua_pushstring(lstate, typed_buf); int save_got_int = got_int; got_int = false; // avoid interrupts when the key typed is Ctrl-C diff --git a/src/nvim/lua/secure.c b/src/nvim/lua/secure.c index f62e0ace04..61277949c4 100644 --- a/src/nvim/lua/secure.c +++ b/src/nvim/lua/secure.c @@ -3,6 +3,7 @@ #include <string.h> #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/ex_cmds_defs.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" @@ -103,12 +104,12 @@ void ex_trust(exarg_T *eap) action = "deny"; } else if (strcmp(arg1, "++remove") == 0) { action = "remove"; - } else if (*arg1 != '\0') { + } else if (*arg1 != NUL) { semsg(e_invarg2, arg1); goto theend; } - if (path[0] == '\0') { + if (path[0] == NUL) { path = NULL; } diff --git a/src/nvim/lua/spell.c b/src/nvim/lua/spell.c index ba83239dc5..f4dacd7a55 100644 --- a/src/nvim/lua/spell.c +++ b/src/nvim/lua/spell.c @@ -7,6 +7,7 @@ #include "nvim/ascii_defs.h" #include "nvim/buffer_defs.h" +#include "nvim/errors.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" #include "nvim/highlight_defs.h" diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index 22ee0a1c98..ee0eabbebb 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -17,10 +17,13 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/ascii_defs.h" +#include "nvim/autocmd.h" #include "nvim/buffer_defs.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/vars.h" +#include "nvim/eval/window.h" +#include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" #include "nvim/fold.h" #include "nvim/globals.h" @@ -40,6 +43,7 @@ #include "nvim/runtime.h" #include "nvim/strings.h" #include "nvim/types_defs.h" +#include "nvim/window.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "lua/stdlib.c.generated.h" @@ -568,6 +572,99 @@ static int nlua_foldupdate(lua_State *lstate) return 0; } +static int nlua_with(lua_State *L) +{ + int flags = 0; + buf_T *buf = NULL; + win_T *win = NULL; + +#define APPLY_FLAG(key, flag) \ + if (strequal((key), k) && (v)) { \ + flags |= (flag); \ + } + + luaL_argcheck(L, lua_istable(L, 1), 1, "table expected"); + lua_pushnil(L); // [dict, ..., nil] + while (lua_next(L, 1)) { + // [dict, ..., key, value] + if (lua_type(L, -2) == LUA_TSTRING) { + const char *k = lua_tostring(L, -2); + bool v = lua_toboolean(L, -1); + if (strequal("buf", k)) { \ + buf = handle_get_buffer((int)luaL_checkinteger(L, -1)); + } else if (strequal("win", k)) { \ + win = handle_get_window((int)luaL_checkinteger(L, -1)); + } else { + APPLY_FLAG("sandbox", CMOD_SANDBOX); + APPLY_FLAG("silent", CMOD_SILENT); + APPLY_FLAG("emsg_silent", CMOD_ERRSILENT); + APPLY_FLAG("unsilent", CMOD_UNSILENT); + APPLY_FLAG("noautocmd", CMOD_NOAUTOCMD); + APPLY_FLAG("hide", CMOD_HIDE); + APPLY_FLAG("keepalt", CMOD_KEEPALT); + APPLY_FLAG("keepmarks", CMOD_KEEPMARKS); + APPLY_FLAG("keepjumps", CMOD_KEEPJUMPS); + APPLY_FLAG("lockmarks", CMOD_LOCKMARKS); + APPLY_FLAG("keeppatterns", CMOD_KEEPPATTERNS); + } + } + // pop the value; lua_next will pop the key. + lua_pop(L, 1); // [dict, ..., key] + } + int status = 0; + int rets = 0; + + cmdmod_T save_cmdmod = cmdmod; + cmdmod.cmod_flags = flags; + apply_cmdmod(&cmdmod); + + if (buf || win) { + try_start(); + } + + aco_save_T aco; + win_execute_T win_execute_args; + Error err = ERROR_INIT; + + if (win) { + tabpage_T *tabpage = win_find_tabpage(win); + if (!win_execute_before(&win_execute_args, win, tabpage)) { + goto end; + } + } else if (buf) { + aucmd_prepbuf(&aco, buf); + } + + int s = lua_gettop(L); + lua_pushvalue(L, 2); + status = lua_pcall(L, 0, LUA_MULTRET, 0); + rets = lua_gettop(L) - s; + + if (win) { + win_execute_after(&win_execute_args); + } else if (buf) { + aucmd_restbuf(&aco); + } + +end: + if (buf || win) { + try_end(&err); + } + + undo_cmdmod(&cmdmod); + cmdmod = save_cmdmod; + + if (status) { + return lua_error(L); + } else if (ERROR_SET(&err)) { + nlua_push_errstr(L, "%s", err.msg); + api_clear_error(&err); + return lua_error(L); + } + + return rets; +} + // Access to internal functions. For use in runtime/ static void nlua_state_add_internal(lua_State *const lstate) { @@ -582,6 +679,9 @@ static void nlua_state_add_internal(lua_State *const lstate) // _updatefolds lua_pushcfunction(lstate, &nlua_foldupdate); lua_setfield(lstate, -2, "_foldupdate"); + + lua_pushcfunction(lstate, &nlua_with); + lua_setfield(lstate, -2, "_with_c"); } void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread) diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index e87cf756a8..ab97704dfe 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -15,6 +15,10 @@ #include <tree_sitter/api.h> #include <uv.h> +#ifdef HAVE_WASMTIME +# include <wasm.h> +#endif + #include "klib/kvec.h" #include "nvim/api/private/helpers.h" #include "nvim/buffer_defs.h" @@ -24,6 +28,7 @@ #include "nvim/map_defs.h" #include "nvim/memline.h" #include "nvim/memory.h" +#include "nvim/os/fs.h" #include "nvim/pos_defs.h" #include "nvim/strings.h" #include "nvim/types_defs.h" @@ -34,7 +39,6 @@ #define TS_META_QUERY "treesitter_query" #define TS_META_QUERYCURSOR "treesitter_querycursor" #define TS_META_QUERYMATCH "treesitter_querymatch" -#define TS_META_TREECURSOR "treesitter_treecursor" typedef struct { LuaRef cb; @@ -53,6 +57,11 @@ typedef struct { static PMap(cstr_t) langs = MAP_INIT; +#ifdef HAVE_WASMTIME +static wasm_engine_t *wasmengine; +static TSWasmStore *ts_wasmstore; +#endif + // TSLanguage int tslua_has_language(lua_State *L) @@ -62,8 +71,59 @@ int tslua_has_language(lua_State *L) return 1; } -static TSLanguage *load_language(lua_State *L, const char *path, const char *lang_name, - const char *symbol) +#ifdef HAVE_WASMTIME +static char *read_file(const char *path, size_t *len) + FUNC_ATTR_MALLOC +{ + FILE *file = os_fopen(path, "r"); + if (file == NULL) { + return NULL; + } + fseek(file, 0L, SEEK_END); + *len = (size_t)ftell(file); + fseek(file, 0L, SEEK_SET); + char *data = xmalloc(*len); + if (fread(data, *len, 1, file) != 1) { + xfree(data); + fclose(file); + return NULL; + } + fclose(file); + return data; +} + +static const char *wasmerr_to_str(TSWasmErrorKind werr) +{ + switch (werr) { + case TSWasmErrorKindParse: + return "PARSE"; + case TSWasmErrorKindCompile: + return "COMPILE"; + case TSWasmErrorKindInstantiate: + return "INSTANTIATE"; + case TSWasmErrorKindAllocate: + return "ALLOCATE"; + default: + return "UNKNOWN"; + } +} +#endif + +int tslua_add_language_from_wasm(lua_State *L) +{ + return add_language(L, true); +} + +// Creates the language into the internal language map. +// +// Returns true if the language is correctly loaded in the language map +int tslua_add_language_from_object(lua_State *L) +{ + return add_language(L, false); +} + +static const TSLanguage *load_language_from_object(lua_State *L, const char *path, + const char *lang_name, const char *symbol) { uv_lib_t lib; if (uv_dlopen(path, &lib)) { @@ -91,16 +151,59 @@ static TSLanguage *load_language(lua_State *L, const char *path, const char *lan return lang; } -// Creates the language into the internal language map. -// -// Returns true if the language is correctly loaded in the language map -int tslua_add_language(lua_State *L) +static const TSLanguage *load_language_from_wasm(lua_State *L, const char *path, + const char *lang_name) +{ +#ifndef HAVE_WASMTIME + luaL_error(L, "Not supported"); + return NULL; +#else + if (wasmengine == NULL) { + wasmengine = wasm_engine_new(); + } + assert(wasmengine != NULL); + + TSWasmError werr = { 0 }; + if (ts_wasmstore == NULL) { + ts_wasmstore = ts_wasm_store_new(wasmengine, &werr); + } + + if (werr.kind > 0) { + luaL_error(L, "Error creating wasm store: (%s) %s", wasmerr_to_str(werr.kind), werr.message); + } + + size_t file_size = 0; + char *data = read_file(path, &file_size); + + if (data == NULL) { + luaL_error(L, "Unable to read file", path); + } + + const TSLanguage *lang = ts_wasm_store_load_language(ts_wasmstore, lang_name, data, + (uint32_t)file_size, &werr); + + xfree(data); + + if (werr.kind > 0) { + luaL_error(L, "Failed to load WASM parser %s: (%s) %s", path, wasmerr_to_str(werr.kind), + werr.message); + } + + if (lang == NULL) { + luaL_error(L, "Failed to load parser %s: internal error", path); + } + + return lang; +#endif +} + +static int add_language(lua_State *L, bool is_wasm) { const char *path = luaL_checkstring(L, 1); const char *lang_name = luaL_checkstring(L, 2); const char *symbol_name = lang_name; - if (lua_gettop(L) >= 3 && !lua_isnil(L, 3)) { + if (!is_wasm && lua_gettop(L) >= 3 && !lua_isnil(L, 3)) { symbol_name = luaL_checkstring(L, 3); } @@ -109,7 +212,9 @@ int tslua_add_language(lua_State *L) return 1; } - TSLanguage *lang = load_language(L, path, lang_name, symbol_name); + const TSLanguage *lang = is_wasm + ? load_language_from_wasm(L, path, lang_name) + : load_language_from_object(L, path, lang_name, symbol_name); uint32_t lang_version = ts_language_version(lang); if (lang_version < TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION @@ -121,7 +226,7 @@ int tslua_add_language(lua_State *L) TREE_SITTER_LANGUAGE_VERSION, lang_version); } - pmap_put(cstr_t)(&langs, xstrdup(lang_name), lang); + pmap_put(cstr_t)(&langs, xstrdup(lang_name), (TSLanguage *)lang); lua_pushboolean(L, true); return 1; @@ -186,6 +291,9 @@ int tslua_inspect_lang(lua_State *L) lua_setfield(L, -2, "fields"); // [retval] + lua_pushboolean(L, ts_language_is_wasm(lang)); + lua_setfield(L, -2, "_wasm"); + lua_pushinteger(L, ts_language_version(lang)); // [retval, version] lua_setfield(L, -2, "_abi_version"); @@ -215,6 +323,13 @@ int tslua_push_parser(lua_State *L) TSParser **parser = lua_newuserdata(L, sizeof(TSParser *)); *parser = ts_parser_new(); +#ifdef HAVE_WASMTIME + if (ts_language_is_wasm(lang)) { + assert(wasmengine != NULL); + ts_parser_set_wasm_store(*parser, ts_wasmstore); + } +#endif + if (!ts_parser_set_language(*parser, lang)) { ts_parser_delete(*parser); const char *lang_name = luaL_checkstring(L, 1); @@ -279,7 +394,7 @@ static const char *input_cb(void *payload, uint32_t byte_index, TSPoint position memcpy(buf, line + position.column, tocopy); // Translate embedded \n to NUL - memchrsub(buf, '\n', '\0', tocopy); + memchrsub(buf, '\n', NUL, tocopy); *bytes_read = (uint32_t)tocopy; if (tocopy < BUFSIZE) { // now add the final \n. If it didn't fit, input_cb will be called again @@ -686,20 +801,6 @@ static int tree_root(lua_State *L) return 1; } -// TSTreeCursor - -static struct luaL_Reg treecursor_meta[] = { - { "__gc", treecursor_gc }, - { NULL, NULL } -}; - -static int treecursor_gc(lua_State *L) -{ - TSTreeCursor *cursor = luaL_checkudata(L, 1, TS_META_TREECURSOR); - ts_tree_cursor_delete(cursor); - return 0; -} - // TSNode static struct luaL_Reg node_meta[] = { { "__tostring", node_tostring }, @@ -890,23 +991,14 @@ static int node_field(lua_State *L) size_t name_len; const char *field_name = luaL_checklstring(L, 2, &name_len); - TSTreeCursor cursor = ts_tree_cursor_new(node); - lua_newtable(L); // [table] - size_t curr_index = 0; - - if (ts_tree_cursor_goto_first_child(&cursor)) { - do { - const char *current_field = ts_tree_cursor_current_field_name(&cursor); - if (current_field != NULL && !strcmp(field_name, current_field)) { - push_node(L, ts_tree_cursor_current_node(&cursor), 1); // [table, node] - lua_rawseti(L, -2, (int)++curr_index); - } - } while (ts_tree_cursor_goto_next_sibling(&cursor)); + TSNode field = ts_node_child_by_field_name(node, field_name, (uint32_t)name_len); + if (!ts_node_is_null(field)) { + push_node(L, field, 1); // [table, node] + lua_rawseti(L, -2, 1); } - ts_tree_cursor_delete(&cursor); return 1; } @@ -1002,45 +1094,35 @@ static int node_named_descendant_for_range(lua_State *L) static int node_next_child(lua_State *L) { - TSTreeCursor *cursor = luaL_checkudata(L, lua_upvalueindex(1), TS_META_TREECURSOR); + uint32_t *child_index = lua_touserdata(L, lua_upvalueindex(1)); TSNode source = node_check(L, lua_upvalueindex(2)); - // First call should return first child - if (ts_node_eq(source, ts_tree_cursor_current_node(cursor))) { - if (ts_tree_cursor_goto_first_child(cursor)) { - goto push; - } else { - return 0; - } - } - - if (!ts_tree_cursor_goto_next_sibling(cursor)) { + if (*child_index >= ts_node_child_count(source)) { return 0; } -push: - push_node(L, ts_tree_cursor_current_node(cursor), lua_upvalueindex(2)); // [node] - - const char *field = ts_tree_cursor_current_field_name(cursor); + TSNode child = ts_node_child(source, *child_index); + push_node(L, child, lua_upvalueindex(2)); + const char *field = ts_node_field_name_for_child(source, *child_index); if (field != NULL) { - lua_pushstring(L, ts_tree_cursor_current_field_name(cursor)); + lua_pushstring(L, field); } else { lua_pushnil(L); } // [node, field_name_or_nil] + + (*child_index)++; + return 2; } static int node_iter_children(lua_State *L) { - TSNode node = node_check(L, 1); - - TSTreeCursor *ud = lua_newuserdata(L, sizeof(TSTreeCursor)); // [udata] - *ud = ts_tree_cursor_new(node); + node_check(L, 1); + uint32_t *child_index = lua_newuserdata(L, sizeof(uint32_t)); // [source_node,..., udata] + *child_index = 0; - lua_getfield(L, LUA_REGISTRYINDEX, TS_META_TREECURSOR); // [udata, mt] - lua_setmetatable(L, -2); // [udata] - lua_pushvalue(L, 1); // [udata, source_node] + lua_pushvalue(L, 1); // [source_node, ..., udata, source_node] lua_pushcclosure(L, node_next_child, 2); return 1; @@ -1132,22 +1214,19 @@ static int node_prev_named_sibling(lua_State *L) static int node_named_children(lua_State *L) { TSNode source = node_check(L, 1); - TSTreeCursor cursor = ts_tree_cursor_new(source); lua_newtable(L); int curr_index = 0; - if (ts_tree_cursor_goto_first_child(&cursor)) { - do { - TSNode node = ts_tree_cursor_current_node(&cursor); - if (ts_node_is_named(node)) { - push_node(L, node, 1); - lua_rawseti(L, -2, ++curr_index); - } - } while (ts_tree_cursor_goto_next_sibling(&cursor)); + uint32_t n = ts_node_child_count(source); + for (uint32_t i = 0; i < n; i++) { + TSNode child = ts_node_child(source, i); + if (ts_node_is_named(child)) { + push_node(L, child, 1); + lua_rawseti(L, -2, ++curr_index); + } } - ts_tree_cursor_delete(&cursor); return 1; } @@ -1557,7 +1636,18 @@ void tslua_init(lua_State *L) build_meta(L, TS_META_QUERY, query_meta); build_meta(L, TS_META_QUERYCURSOR, querycursor_meta); build_meta(L, TS_META_QUERYMATCH, querymatch_meta); - build_meta(L, TS_META_TREECURSOR, treecursor_meta); ts_set_allocator(xmalloc, xcalloc, xrealloc, xfree); } + +void tslua_free(void) +{ +#ifdef HAVE_WASMTIME + if (wasmengine != NULL) { + wasm_engine_delete(wasmengine); + } + if (ts_wasmstore != NULL) { + ts_wasm_store_delete(ts_wasmstore); + } +#endif +} diff --git a/src/nvim/lua/xdiff.c b/src/nvim/lua/xdiff.c index 035c171a14..b9f96abf73 100644 --- a/src/nvim/lua/xdiff.c +++ b/src/nvim/lua/xdiff.c @@ -67,11 +67,11 @@ static void get_linematch_results(lua_State *lstate, mmfile_t *ma, mmfile_t *mb, int count_a, int start_b, int count_b, bool iwhite) { // get the pointer to char of the start of the diff to pass it to linematch algorithm - const char *diff_begin[2] = { ma->ptr, mb->ptr }; - int diff_length[2] = { count_a, count_b }; + mmfile_t ma0 = fastforward_buf_to_lnum(*ma, (linenr_T)start_a + 1); + mmfile_t mb0 = fastforward_buf_to_lnum(*mb, (linenr_T)start_b + 1); - fastforward_buf_to_lnum(&diff_begin[0], (linenr_T)start_a + 1); - fastforward_buf_to_lnum(&diff_begin[1], (linenr_T)start_b + 1); + const mmfile_t *diff_begin[2] = { &ma0, &mb0 }; + int diff_length[2] = { count_a, count_b }; int *decisions = NULL; size_t decisions_length = linematch_nbuffers(diff_begin, diff_length, 2, &decisions, iwhite); @@ -185,7 +185,12 @@ static mmfile_t get_string_arg(lua_State *lstate, int idx) luaL_argerror(lstate, idx, "expected string"); } mmfile_t mf; - mf.ptr = (char *)lua_tolstring(lstate, idx, (size_t *)&mf.size); + size_t size; + mf.ptr = (char *)lua_tolstring(lstate, idx, &size); + if (size > INT_MAX) { + luaL_argerror(lstate, idx, "string too long"); + } + mf.size = (int)size; return mf; } diff --git a/src/nvim/main.c b/src/nvim/main.c index 30b6b6e86b..dc102f6f6d 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -6,7 +6,6 @@ #endif #include <assert.h> #include <limits.h> -#include <msgpack/pack.h> #include <stdbool.h> #include <stdint.h> #include <stdio.h> @@ -37,13 +36,14 @@ #include "nvim/diff.h" #include "nvim/drawline.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" #include "nvim/event/loop.h" #include "nvim/event/multiqueue.h" -#include "nvim/event/process.h" +#include "nvim/event/proc.h" #include "nvim/event/stream.h" #include "nvim/ex_cmds.h" #include "nvim/ex_docmd.h" @@ -154,7 +154,6 @@ void event_init(void) loop_init(&main_loop, NULL); resize_events = multiqueue_new_child(main_loop.events); - input_init(); signal_init(); // mspgack-rpc initialization channel_init(); @@ -175,7 +174,7 @@ bool event_teardown(void) loop_poll_events(&main_loop, 0); // Drain thread_events, fast_events. input_stop(); channel_teardown(); - process_teardown(&main_loop); + proc_teardown(&main_loop); timer_teardown(); server_teardown(); signal_teardown(); @@ -267,7 +266,7 @@ int main(int argc, char **argv) if (argc > 1 && STRICMP(argv[1], "-ll") == 0) { if (argc == 2) { - print_mainerr(err_arg_missing, argv[1]); + print_mainerr(err_arg_missing, argv[1], NULL); exit(1); } nlua_run_script(argv, argc, 3); @@ -333,12 +332,6 @@ int main(int argc, char **argv) #endif bool use_builtin_ui = (has_term && !headless_mode && !embedded_mode && !silent_mode); - // don't bind the server yet, if we are using builtin ui. - // This will be done when nvim server has been forked from the ui process - if (!use_builtin_ui) { - server_init(params.listen_addr); - } - if (params.remote) { remote_request(¶ms, params.remote, params.server_addr, argc, argv, use_builtin_ui); @@ -356,11 +349,16 @@ int main(int argc, char **argv) ui_client_channel_id = rv; } + // NORETURN: Start builtin UI client. if (ui_client_channel_id) { - time_finish(); ui_client_run(remote_ui); // NORETURN } assert(!ui_client_channel_id && !use_builtin_ui); + // Nvim server... + + if (!server_init(params.listen_addr)) { + mainerr(IObuff, NULL, NULL); + } TIME_MSG("expanding arguments"); @@ -545,10 +543,8 @@ int main(int argc, char **argv) no_wait_return = true; - // // Create the requested number of windows and edit buffers in them. // Also does recovery if "recoverymode" set. - // create_windows(¶ms); TIME_MSG("opening buffers"); @@ -971,8 +967,8 @@ static void remote_request(mparm_T *params, int remote_args, char *server_addr, os_exit(2); } - if (o.type == kObjectTypeDictionary) { - rvobj.data.dictionary = o.data.dictionary; + if (o.type == kObjectTypeDict) { + rvobj.data.dict = o.data.dict; } else { fprintf(stderr, "vim._cs_remote returned unexpected value\n"); os_exit(2); @@ -981,32 +977,32 @@ static void remote_request(mparm_T *params, int remote_args, char *server_addr, TriState should_exit = kNone; TriState tabbed = kNone; - for (size_t i = 0; i < rvobj.data.dictionary.size; i++) { - if (strequal(rvobj.data.dictionary.items[i].key.data, "errmsg")) { - if (rvobj.data.dictionary.items[i].value.type != kObjectTypeString) { + for (size_t i = 0; i < rvobj.data.dict.size; i++) { + if (strequal(rvobj.data.dict.items[i].key.data, "errmsg")) { + if (rvobj.data.dict.items[i].value.type != kObjectTypeString) { fprintf(stderr, "vim._cs_remote returned an unexpected type for 'errmsg'\n"); os_exit(2); } - fprintf(stderr, "%s\n", rvobj.data.dictionary.items[i].value.data.string.data); + fprintf(stderr, "%s\n", rvobj.data.dict.items[i].value.data.string.data); os_exit(2); - } else if (strequal(rvobj.data.dictionary.items[i].key.data, "result")) { - if (rvobj.data.dictionary.items[i].value.type != kObjectTypeString) { + } else if (strequal(rvobj.data.dict.items[i].key.data, "result")) { + if (rvobj.data.dict.items[i].value.type != kObjectTypeString) { fprintf(stderr, "vim._cs_remote returned an unexpected type for 'result'\n"); os_exit(2); } - printf("%s", rvobj.data.dictionary.items[i].value.data.string.data); - } else if (strequal(rvobj.data.dictionary.items[i].key.data, "tabbed")) { - if (rvobj.data.dictionary.items[i].value.type != kObjectTypeBoolean) { + printf("%s", rvobj.data.dict.items[i].value.data.string.data); + } else if (strequal(rvobj.data.dict.items[i].key.data, "tabbed")) { + if (rvobj.data.dict.items[i].value.type != kObjectTypeBoolean) { fprintf(stderr, "vim._cs_remote returned an unexpected type for 'tabbed'\n"); os_exit(2); } - tabbed = rvobj.data.dictionary.items[i].value.data.boolean ? kTrue : kFalse; - } else if (strequal(rvobj.data.dictionary.items[i].key.data, "should_exit")) { - if (rvobj.data.dictionary.items[i].value.type != kObjectTypeBoolean) { + tabbed = rvobj.data.dict.items[i].value.data.boolean ? kTrue : kFalse; + } else if (strequal(rvobj.data.dict.items[i].key.data, "should_exit")) { + if (rvobj.data.dict.items[i].value.type != kObjectTypeBoolean) { fprintf(stderr, "vim._cs_remote returned an unexpected type for 'should_exit'\n"); os_exit(2); } - should_exit = rvobj.data.dictionary.items[i].value.data.boolean ? kTrue : kFalse; + should_exit = rvobj.data.dict.items[i].value.data.boolean ? kTrue : kFalse; } } if (should_exit == kNone || tabbed == kNone) { @@ -1054,7 +1050,7 @@ static void command_line_scan(mparm_T *parmp) // "+" or "+{number}" or "+/{pat}" or "+{command}" argument. if (argv[0][0] == '+' && !had_minmin) { if (parmp->n_commands >= MAX_ARG_CMDS) { - mainerr(err_extra_cmd, NULL); + mainerr(err_extra_cmd, NULL, NULL); } argv_idx = -1; // skip to next argument if (argv[0][1] == NUL) { @@ -1075,7 +1071,7 @@ static void command_line_scan(mparm_T *parmp) parmp->no_swap_file = true; } else { if (parmp->edit_type > EDIT_STDIN) { - mainerr(err_too_many_args, argv[0]); + mainerr(err_too_many_args, argv[0], NULL); } parmp->had_stdin_file = true; parmp->edit_type = EDIT_STDIN; @@ -1100,23 +1096,13 @@ static void command_line_scan(mparm_T *parmp) // set stdout to binary to avoid crlf in --api-info output _setmode(STDOUT_FILENO, _O_BINARY); #endif - FileDescriptor fp; - const int fof_ret = file_open_fd(&fp, STDOUT_FILENO, - kFileWriteOnly); - if (fof_ret != 0) { - semsg(_("E5421: Failed to open stdin: %s"), os_strerror(fof_ret)); - } String data = api_metadata_raw(); - const ptrdiff_t written_bytes = file_write(&fp, data.data, data.size); + const ptrdiff_t written_bytes = os_write(STDOUT_FILENO, data.data, data.size, false); if (written_bytes < 0) { - msgpack_file_write_error((int)written_bytes); + semsg(_("E5420: Failed to write to file: %s"), os_strerror((int)written_bytes)); } - const int ff_ret = file_flush(&fp); - if (ff_ret < 0) { - msgpack_file_write_error(ff_ret); - } os_exit(0); } else if (STRICMP(argv[0] + argv_idx, "headless") == 0) { headless_mode = true; @@ -1148,7 +1134,7 @@ static void command_line_scan(mparm_T *parmp) nlua_disable_preload = true; } else { if (argv[0][argv_idx]) { - mainerr(err_opt_unknown, argv[0]); + mainerr(err_opt_unknown, argv[0], NULL); } had_minmin = true; } @@ -1222,7 +1208,7 @@ static void command_line_scan(mparm_T *parmp) break; case 'q': // "-q" QuickFix mode if (parmp->edit_type != EDIT_NONE) { - mainerr(err_too_many_args, argv[0]); + mainerr(err_too_many_args, argv[0], NULL); } parmp->edit_type = EDIT_QF; if (argv[0][argv_idx]) { // "-q{errorfile}" @@ -1251,7 +1237,7 @@ static void command_line_scan(mparm_T *parmp) break; case 't': // "-t {tag}" or "-t{tag}" jump to tag if (parmp->edit_type != EDIT_NONE) { - mainerr(err_too_many_args, argv[0]); + mainerr(err_too_many_args, argv[0], NULL); } parmp->edit_type = EDIT_TAG; if (argv[0][argv_idx]) { // "-t{tag}" @@ -1285,7 +1271,7 @@ static void command_line_scan(mparm_T *parmp) case 'c': // "-c{command}" or "-c {command}" exec command if (argv[0][argv_idx] != NUL) { if (parmp->n_commands >= MAX_ARG_CMDS) { - mainerr(err_extra_cmd, NULL); + mainerr(err_extra_cmd, NULL, NULL); } parmp->commands[parmp->n_commands++] = argv[0] + argv_idx; argv_idx = -1; @@ -1302,19 +1288,19 @@ static void command_line_scan(mparm_T *parmp) break; default: - mainerr(err_opt_unknown, argv[0]); + mainerr(err_opt_unknown, argv[0], NULL); } // Handle option arguments with argument. if (want_argument) { // Check for garbage immediately after the option letter. if (argv[0][argv_idx] != NUL) { - mainerr(err_opt_garbage, argv[0]); + mainerr(err_opt_garbage, argv[0], NULL); } argc--; if (argc < 1 && c != 'S') { // -S has an optional argument - mainerr(err_arg_missing, argv[0]); + mainerr(err_arg_missing, argv[0], NULL); } argv++; argv_idx = -1; @@ -1323,7 +1309,7 @@ static void command_line_scan(mparm_T *parmp) case 'c': // "-c {command}" execute command case 'S': // "-S {file}" execute Vim script if (parmp->n_commands >= MAX_ARG_CMDS) { - mainerr(err_extra_cmd, NULL); + mainerr(err_extra_cmd, NULL, NULL); } if (c == 'S') { char *a; @@ -1354,7 +1340,7 @@ static void command_line_scan(mparm_T *parmp) if (strequal(argv[-1], "--cmd")) { // "--cmd {command}" execute command if (parmp->n_pre_commands >= MAX_ARG_CMDS) { - mainerr(err_extra_cmd, NULL); + mainerr(err_extra_cmd, NULL, NULL); } parmp->pre_commands[parmp->n_pre_commands++] = argv[0]; } else if (strequal(argv[-1], "--listen")) { @@ -1436,7 +1422,7 @@ scripterror: // Check for only one type of editing. if (parmp->edit_type > EDIT_STDIN) { - mainerr(err_too_many_args, argv[0]); + mainerr(err_too_many_args, argv[0], NULL); } parmp->edit_type = EDIT_FILE; @@ -1444,6 +1430,17 @@ scripterror: ga_grow(&global_alist.al_ga, 1); char *p = xstrdup(argv[0]); + // On Windows expand "~\" or "~/" prefix in file names to profile directory. +#ifdef MSWIN + if (*p == '~' && (p[1] == '\\' || p[1] == '/')) { + size_t size = strlen(os_homedir()) + strlen(p); + char *tilde_expanded = xmalloc(size); + snprintf(tilde_expanded, size, "%s%s", os_homedir(), p + 1); + xfree(p); + p = tilde_expanded; + } +#endif + if (parmp->diff_mode && os_isdir(p) && GARGCOUNT > 0 && !os_isdir(alist_name(&GARGLIST[0]))) { char *r = concat_fnames(p, path_tail(alist_name(&GARGLIST[0])), true); @@ -1472,7 +1469,7 @@ scripterror: } if (embedded_mode && (silent_mode || parmp->luaf)) { - mainerr(_("--embed conflicts with -es/-Es/-l"), NULL); + mainerr(_("--embed conflicts with -es/-Es/-l"), NULL, NULL); } // If there is a "+123" or "-c" command, set v:swapcommand to the first one. @@ -1516,7 +1513,7 @@ static void init_startuptime(mparm_T *paramp) } for (int i = 1; i < paramp->argc - 1; i++) { if (STRICMP(paramp->argv[i], "--startuptime") == 0) { - time_init(paramp->argv[i + 1], is_embed ? "Embedded" : "Primary/TUI"); + time_init(paramp->argv[i + 1], is_embed ? "Embedded" : "Primary (or UI client)"); time_start("--- NVIM STARTING ---"); break; } @@ -2135,28 +2132,30 @@ static int execute_env(char *env) return OK; } -/// Prints the following then exits: -/// - An error message `errstr` -/// - A string `str` if not null +/// Prints a message of the form "{msg1}: {msg2}: {msg3}", then exits with code 1. /// -/// @param errstr string containing an error message -/// @param str string to append to the primary error message, or NULL -static void mainerr(const char *errstr, const char *str) +/// @param msg1 error message +/// @param msg2 extra message, or NULL +/// @param msg3 extra message, or NULL +static void mainerr(const char *msg1, const char *msg2, const char *msg3) FUNC_ATTR_NORETURN { - print_mainerr(errstr, str); + print_mainerr(msg1, msg2, msg3); os_exit(1); } -static void print_mainerr(const char *errstr, const char *str) +static void print_mainerr(const char *msg1, const char *msg2, const char *msg3) { char *prgname = path_tail(argv0); signal_stop(); // kill us with CTRL-C here, if you like - fprintf(stderr, "%s: %s", prgname, _(errstr)); - if (str != NULL) { - fprintf(stderr, ": \"%s\"", str); + fprintf(stderr, "%s: %s", prgname, _(msg1)); + if (msg2 != NULL) { + fprintf(stderr, ": \"%s\"", msg2); + } + if (msg3 != NULL) { + fprintf(stderr, ": \"%s\"", msg3); } fprintf(stderr, _("\nMore info with \"")); fprintf(stderr, "%s -h\"\n", prgname); @@ -2207,7 +2206,7 @@ static void usage(void) printf(_(" --headless Don't start a user interface\n")); printf(_(" --listen <address> Serve RPC API from this address\n")); printf(_(" --remote[-subcommand] Execute commands remotely on a server\n")); - printf(_(" --server <address> Specify RPC server to send commands to\n")); + printf(_(" --server <address> Connect to this Nvim server\n")); printf(_(" --startuptime <file> Write startup timing messages to <file>\n")); printf(_("\nSee \":help startup-options\" for all options.\n")); } diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c index 9320390d68..e055ebc2fa 100644 --- a/src/nvim/mapping.c +++ b/src/nvim/mapping.c @@ -19,6 +19,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/cmdexpand_defs.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -150,12 +151,14 @@ static void mapblock_free(mapblock_T **mpp) { mapblock_T *mp = *mpp; xfree(mp->m_keys); - if (!mp->m_simplified) { + if (mp->m_alt != NULL) { + mp->m_alt->m_alt = NULL; + } else { NLUA_CLEAR_REF(mp->m_luaref); xfree(mp->m_str); xfree(mp->m_orig_str); + xfree(mp->m_desc); } - xfree(mp->m_desc); *mpp = mp->m_next; xfree(mp); } @@ -492,13 +495,13 @@ static int str_to_mapargs(const char *strargs, bool is_unmap, MapArguments *mapa return 0; } -/// @param args "rhs", "rhs_lua", "orig_rhs", "expr", "silent", "nowait", "replace_keycodes" and -/// and "desc" fields are used. -/// "rhs", "rhs_lua", "orig_rhs" fields are cleared if "simplified" is false. +/// @param args "rhs", "rhs_lua", "orig_rhs", "expr", "silent", "nowait", +/// "replace_keycodes" and "desc" fields are used. /// @param sid 0 to use current_sctx -static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table, const char *keys, - MapArguments *args, int noremap, int mode, bool is_abbr, scid_T sid, - linenr_T lnum, bool simplified) +static mapblock_T *map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table, + const char *keys, MapArguments *args, int noremap, int mode, + bool is_abbr, scid_T sid, linenr_T lnum, bool simplified) + FUNC_ATTR_NONNULL_RET { mapblock_T *mp = xcalloc(1, sizeof(mapblock_T)); @@ -515,11 +518,6 @@ static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table, mp->m_str = args->rhs; mp->m_orig_str = args->orig_rhs; mp->m_luaref = args->rhs_lua; - if (!simplified) { - args->rhs = NULL; - args->orig_rhs = NULL; - args->rhs_lua = LUA_NOREF; - } mp->m_keylen = (int)strlen(mp->m_keys); mp->m_noremap = noremap; mp->m_nowait = args->nowait; @@ -536,10 +534,7 @@ static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table, mp->m_script_ctx.sc_lnum += SOURCING_LNUM; nlua_set_sctx(&mp->m_script_ctx); } - mp->m_desc = NULL; - if (args->desc != NULL) { - mp->m_desc = xstrdup(args->desc); - } + mp->m_desc = args->desc; // add the new entry in front of the abbrlist or maphash[] list if (is_abbr) { @@ -550,6 +545,7 @@ static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table, mp->m_next = map_table[n]; map_table[n] = mp; } + return mp; } /// Sets or removes a mapping or abbreviation in buffer `buf`. @@ -570,6 +566,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, // mappings/abbreviations, not the globals. mapblock_T **map_table = args->buffer ? buf->b_maphash : maphash; mapblock_T **abbr_table = args->buffer ? &buf->b_first_abbr : &first_abbr; + mapblock_T *mp_result[2] = { NULL, NULL }; // For ":noremap" don't remap, otherwise do remap. int noremap = args->script ? REMAP_SCRIPT @@ -803,20 +800,17 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, // new rhs for existing entry mp->m_mode &= ~mode; // remove mode bits if (mp->m_mode == 0 && !did_it) { // reuse entry - XFREE_CLEAR(mp->m_desc); - if (!mp->m_simplified) { + if (mp->m_alt != NULL) { + mp->m_alt = mp->m_alt->m_alt = NULL; + } else { NLUA_CLEAR_REF(mp->m_luaref); - XFREE_CLEAR(mp->m_str); - XFREE_CLEAR(mp->m_orig_str); + xfree(mp->m_str); + xfree(mp->m_orig_str); + xfree(mp->m_desc); } mp->m_str = args->rhs; mp->m_orig_str = args->orig_rhs; mp->m_luaref = args->rhs_lua; - if (!keyround1_simplified) { - args->rhs = NULL; - args->orig_rhs = NULL; - args->rhs_lua = LUA_NOREF; - } mp->m_noremap = noremap; mp->m_nowait = args->nowait; mp->m_silent = args->silent; @@ -827,9 +821,8 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, mp->m_script_ctx = current_sctx; mp->m_script_ctx.sc_lnum += SOURCING_LNUM; nlua_set_sctx(&mp->m_script_ctx); - if (args->desc != NULL) { - mp->m_desc = xstrdup(args->desc); - } + mp->m_desc = args->desc; + mp_result[keyround - 1] = mp; did_it = true; } } @@ -888,13 +881,25 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, } // Get here when adding a new entry to the maphash[] list or abbrlist. - map_add(buf, map_table, abbr_table, lhs, args, noremap, mode, is_abbrev, - 0, // sid - 0, // lnum - keyround1_simplified); + mp_result[keyround - 1] = map_add(buf, map_table, abbr_table, lhs, + args, noremap, mode, is_abbrev, + 0, // sid + 0, // lnum + keyround1_simplified); + } + + if (mp_result[0] != NULL && mp_result[1] != NULL) { + mp_result[0]->m_alt = mp_result[1]; + mp_result[1]->m_alt = mp_result[0]; } theend: + if (mp_result[0] != NULL || mp_result[1] != NULL) { + args->rhs = NULL; + args->orig_rhs = NULL; + args->rhs_lua = LUA_NOREF; + args->desc = NULL; + } return retval; } @@ -1646,12 +1651,12 @@ char *eval_map_expr(mapblock_T *mp, int c) p = string_to_cstr(ret.data.string); } api_free_object(ret); - if (err.type != kErrorTypeNone) { + if (ERROR_SET(&err)) { semsg_multiline("E5108: %s", err.msg); api_clear_error(&err); } } else { - p = eval_to_string(expr, false); + p = eval_to_string(expr, false, false); xfree(expr); } expr_map_lock--; @@ -2056,20 +2061,20 @@ void f_hasmapto(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) rettv->vval.v_number = map_to_exists(name, mode, abbr); } -/// Fill a Dictionary with all applicable maparg() like dictionaries +/// Fill a Dict with all applicable maparg() like dictionaries /// /// @param mp The maphash that contains the mapping information /// @param buffer_value The "buffer" value /// @param abbr True if abbreviation /// @param compatible True for compatible with old maparg() dict /// -/// @return A Dictionary. -static Dictionary mapblock_fill_dict(const mapblock_T *const mp, const char *lhsrawalt, - const int buffer_value, const bool abbr, const bool compatible, - Arena *arena) +/// @return Dict. +static Dict mapblock_fill_dict(const mapblock_T *const mp, const char *lhsrawalt, + const int buffer_value, const bool abbr, const bool compatible, + Arena *arena) FUNC_ATTR_NONNULL_ARG(1) { - Dictionary dict = arena_dict(arena, 19); + Dict dict = arena_dict(arena, 19); char *const lhs = str2special_arena(mp->m_keys, compatible, !compatible, arena); char *mapmode = arena_alloc(arena, 7, false); map_mode_to_chars(mp->m_mode, mapmode); @@ -2188,9 +2193,9 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) // Return a dictionary. if (mp != NULL && (rhs != NULL || rhs_lua != LUA_NOREF)) { Arena arena = ARENA_EMPTY; - Dictionary dict = mapblock_fill_dict(mp, did_simplify ? keys_simplified : NULL, - buffer_local, abbr, true, &arena); - object_to_vim_take_luaref(&DICTIONARY_OBJ(dict), rettv, true, NULL); + Dict dict = mapblock_fill_dict(mp, did_simplify ? keys_simplified : NULL, + buffer_local, abbr, true, &arena); + object_to_vim_take_luaref(&DICT_OBJ(dict), rettv, true, NULL); arena_mem_free(arena_finish(&arena)); } else { // Return an empty dictionary. @@ -2327,7 +2332,7 @@ void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) .silent = tv_dict_get_number(d, "silent") != 0, .nowait = tv_dict_get_number(d, "nowait") != 0, .replace_keycodes = tv_dict_get_number(d, "replace_keycodes") != 0, - .desc = tv_dict_get_string(d, "desc", false), + .desc = tv_dict_get_string(d, "desc", true), }; scid_T sid = (scid_T)tv_dict_get_number(d, "sid"); linenr_T lnum = (linenr_T)tv_dict_get_number(d, "lnum"); @@ -2347,12 +2352,19 @@ void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) xfree(unmap_args.rhs); xfree(unmap_args.orig_rhs); + mapblock_T *mp_result[2] = { NULL, NULL }; + + mp_result[0] = map_add(curbuf, map_table, abbr_table, lhsraw, &args, + noremap, mode, is_abbr, sid, lnum, false); if (lhsrawalt != NULL) { - map_add(curbuf, map_table, abbr_table, lhsrawalt, &args, noremap, mode, is_abbr, - sid, lnum, true); + mp_result[1] = map_add(curbuf, map_table, abbr_table, lhsrawalt, &args, + noremap, mode, is_abbr, sid, lnum, true); + } + + if (mp_result[0] != NULL && mp_result[1] != NULL) { + mp_result[0]->m_alt = mp_result[1]; + mp_result[1]->m_alt = mp_result[0]; } - map_add(curbuf, map_table, abbr_table, lhsraw, &args, noremap, mode, is_abbr, - sid, lnum, false); } /// "maplist()" function @@ -2394,10 +2406,10 @@ void f_maplist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) replace_termcodes(lhs, strlen(lhs), &keys_buf, 0, flags, &did_simplify, p_cpo); - Dictionary dict = mapblock_fill_dict(mp, did_simplify ? keys_buf : NULL, - buffer_local, abbr, true, &arena); + Dict dict = mapblock_fill_dict(mp, did_simplify ? keys_buf : NULL, buffer_local, abbr, true, + &arena); typval_T d = TV_INITIAL_VALUE; - object_to_vim_take_luaref(&DICTIONARY_OBJ(dict), &d, true, NULL); + object_to_vim_take_luaref(&DICT_OBJ(dict), &d, true, NULL); assert(d.v_type == VAR_DICT); tv_list_append_dict(rettv->vval.v_list, d.vval.v_dict); arena_mem_free(arena_finish(&arena)); @@ -2802,7 +2814,7 @@ fail_and_free: /// @param mode The abbreviation for the mode /// @param buf The buffer to get the mapping array. NULL for global /// @returns Array of maparg()-like dictionaries describing mappings -ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf, Arena *arena) +ArrayOf(Dict) keymap_array(String mode, buf_T *buf, Arena *arena) { ArrayBuilder mappings = KV_INITIAL_VALUE; kvi_init(mappings); @@ -2831,8 +2843,8 @@ ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf, Arena *arena) } // Check for correct mode if (int_mode & current_maphash->m_mode) { - kvi_push(mappings, DICTIONARY_OBJ(mapblock_fill_dict(current_maphash, NULL, buffer_value, - is_abbrev, false, arena))); + kvi_push(mappings, DICT_OBJ(mapblock_fill_dict(current_maphash, NULL, buffer_value, + is_abbrev, false, arena))); } } } diff --git a/src/nvim/mapping_defs.h b/src/nvim/mapping_defs.h index 05b8aef23a..4a04b1ebfb 100644 --- a/src/nvim/mapping_defs.h +++ b/src/nvim/mapping_defs.h @@ -10,6 +10,9 @@ enum { MAXMAPLEN = 50, }; ///< Maximum length of key sequence to be mapped. typedef struct mapblock mapblock_T; struct mapblock { mapblock_T *m_next; ///< next mapblock in list + mapblock_T *m_alt; ///< pointer to mapblock of the same mapping + ///< with an alternative form of m_keys, or NULL + ///< if there is no such mapblock char *m_keys; ///< mapped from, lhs char *m_str; ///< mapped to, rhs char *m_orig_str; ///< rhs as entered by the user diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 6ce42bb7fe..a09ade2b03 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -14,6 +14,7 @@ #include "nvim/cursor.h" #include "nvim/diff.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds_defs.h" @@ -42,6 +43,7 @@ #include "nvim/pos_defs.h" #include "nvim/quickfix.h" #include "nvim/strings.h" +#include "nvim/tag.h" #include "nvim/textobject.h" #include "nvim/types_defs.h" #include "nvim/vim_defs.h" @@ -69,7 +71,7 @@ int setmark(int c) /// Free fmark_T item void free_fmark(fmark_T fm) { - tv_dict_unref(fm.additional_data); + xfree(fm.additional_data); } /// Free xfmark_T item @@ -164,6 +166,56 @@ int setmark_pos(int c, pos_T *pos, int fnum, fmarkv_T *view_pt) return FAIL; } +/// Remove every jump list entry referring to a given buffer. +/// This function will also adjust the current jump list index. +void mark_jumplist_forget_file(win_T *wp, int fnum) +{ + // Remove all jump list entries that match the deleted buffer. + for (int i = wp->w_jumplistlen - 1; i >= 0; i--) { + if (wp->w_jumplist[i].fmark.fnum == fnum) { + // Found an entry that we want to delete. + free_xfmark(wp->w_jumplist[i]); + + // If the current jump list index is behind the entry we want to delete, + // move it back by one. + if (wp->w_jumplistidx > i) { + wp->w_jumplistidx--; + } + + // Actually remove the entry from the jump list. + wp->w_jumplistlen--; + memmove(&wp->w_jumplist[i], &wp->w_jumplist[i + 1], + (size_t)(wp->w_jumplistlen - i) * sizeof(wp->w_jumplist[i])); + } + } +} + +/// Delete every entry referring to file "fnum" from both the jumplist and the +/// tag stack. +void mark_forget_file(win_T *wp, int fnum) +{ + mark_jumplist_forget_file(wp, fnum); + + // Remove all tag stack entries that match the deleted buffer. + for (int i = wp->w_tagstacklen - 1; i >= 0; i--) { + if (wp->w_tagstack[i].fmark.fnum == fnum) { + // Found an entry that we want to delete. + tagstack_clear_entry(&wp->w_tagstack[i]); + + // If the current tag stack index is behind the entry we want to delete, + // move it back by one. + if (wp->w_tagstackidx > i) { + wp->w_tagstackidx--; + } + + // Actually remove the entry from the tag stack. + wp->w_tagstacklen--; + memmove(&wp->w_tagstack[i], &wp->w_tagstack[i + 1], + (size_t)(wp->w_tagstacklen - i) * sizeof(wp->w_tagstack[i])); + } + } +} + // Set the previous context mark to the current position and add it to the // jump list. void setpcmark(void) diff --git a/src/nvim/mark.h b/src/nvim/mark.h index c3661e2e22..fdd87f3e96 100644 --- a/src/nvim/mark.h +++ b/src/nvim/mark.h @@ -5,19 +5,18 @@ #include "nvim/ascii_defs.h" #include "nvim/ex_cmds_defs.h" // IWYU pragma: keep #include "nvim/extmark_defs.h" // IWYU pragma: keep -#include "nvim/func_attr.h" #include "nvim/macros_defs.h" #include "nvim/mark_defs.h" // IWYU pragma: keep #include "nvim/os/time.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "mark.h.generated.h" +# include "mark.h.inline.generated.h" #endif -static inline int mark_global_index(char name) - REAL_FATTR_CONST; /// Convert mark name to the offset static inline int mark_global_index(const char name) + FUNC_ATTR_CONST { return (ASCII_ISUPPER(name) ? (name - 'A') @@ -26,10 +25,9 @@ static inline int mark_global_index(const char name) : -1)); } -static inline int mark_local_index(char name) - REAL_FATTR_CONST; /// Convert local mark name to the offset static inline int mark_local_index(const char name) + FUNC_ATTR_CONST { return (ASCII_ISLOWER(name) ? (name - 'a') diff --git a/src/nvim/mark_defs.h b/src/nvim/mark_defs.h index 98bdb6ee04..f953e26e4e 100644 --- a/src/nvim/mark_defs.h +++ b/src/nvim/mark_defs.h @@ -1,7 +1,15 @@ #pragma once -#include "nvim/eval/typval_defs.h" +#include <stdbool.h> + +#include "nvim/func_attr.h" #include "nvim/os/time_defs.h" +#include "nvim/pos_defs.h" +#include "nvim/types_defs.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "mark_defs.h.inline.generated.h" +#endif // marks: positions in a file // (a normal mark is a lnum/col pair, the same as a file position) @@ -71,7 +79,7 @@ typedef struct { int fnum; ///< File number. Timestamp timestamp; ///< Time when this mark was last set. fmarkv_T view; ///< View the mark was created on - dict_T *additional_data; ///< Additional data from ShaDa file. + AdditionalData *additional_data; ///< Additional data from ShaDa file. } fmark_T; #define INIT_FMARK { { 0, 0, 0 }, 0, 0, INIT_FMARKV, NULL } @@ -84,11 +92,9 @@ typedef struct { #define INIT_XFMARK { INIT_FMARK, NULL } -/// Set fmark using given value -static inline bool lt(pos_T a, pos_T b) - REAL_FATTR_CONST REAL_FATTR_ALWAYS_INLINE; /// Return true if position a is before (less than) position b. static inline bool lt(pos_T a, pos_T b) + FUNC_ATTR_CONST FUNC_ATTR_ALWAYS_INLINE { if (a.lnum != b.lnum) { return a.lnum < b.lnum; @@ -100,25 +106,19 @@ static inline bool lt(pos_T a, pos_T b) } static inline bool equalpos(pos_T a, pos_T b) - REAL_FATTR_CONST REAL_FATTR_ALWAYS_INLINE; -/// Return true if position a and b are equal. -static inline bool equalpos(pos_T a, pos_T b) + FUNC_ATTR_CONST FUNC_ATTR_ALWAYS_INLINE { return (a.lnum == b.lnum) && (a.col == b.col) && (a.coladd == b.coladd); } static inline bool ltoreq(pos_T a, pos_T b) - REAL_FATTR_CONST REAL_FATTR_ALWAYS_INLINE; -/// Return true if position a is less than or equal to b. -static inline bool ltoreq(pos_T a, pos_T b) + FUNC_ATTR_CONST FUNC_ATTR_ALWAYS_INLINE { return lt(a, b) || equalpos(a, b); } static inline void clearpos(pos_T *a) - REAL_FATTR_ALWAYS_INLINE; -/// Clear the pos_T structure pointed to by a. -static inline void clearpos(pos_T *a) + FUNC_ATTR_ALWAYS_INLINE { a->lnum = 0; a->col = 0; diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c index 34d6cd118f..555fef5bbd 100644 --- a/src/nvim/marktree.c +++ b/src/nvim/marktree.c @@ -446,7 +446,7 @@ static MTNode *marktree_alloc_node(MarkTree *b, bool internal) // really meta_inc[kMTMetaCount] static void meta_describe_key_inc(uint32_t *meta_inc, MTKey *k) { - if (!mt_end(*k)) { + if (!mt_end(*k) && !mt_invalid(*k)) { meta_inc[kMTMetaInline] += (k->flags & MT_FLAG_DECOR_VIRT_TEXT_INLINE) ? 1 : 0; meta_inc[kMTMetaLines] += (k->flags & MT_FLAG_DECOR_VIRT_LINES) ? 1 : 0; meta_inc[kMTMetaSignHL] += (k->flags & MT_FLAG_DECOR_SIGNHL) ? 1 : 0; @@ -774,14 +774,10 @@ uint64_t marktree_del_itr(MarkTree *b, MarkTreeIter *itr, bool rev) return other; } -void marktree_revise_flags(MarkTree *b, MarkTreeIter *itr, uint16_t new_flags) +void marktree_revise_meta(MarkTree *b, MarkTreeIter *itr, MTKey old_key) { - uint32_t meta_old[4]; - meta_describe_key(meta_old, rawkey(itr)); - rawkey(itr).flags &= (uint16_t) ~MT_FLAG_EXTERNAL_MASK; - rawkey(itr).flags |= new_flags; - - uint32_t meta_new[4]; + uint32_t meta_old[4], meta_new[4]; + meta_describe_key(meta_old, old_key); meta_describe_key(meta_new, rawkey(itr)); if (!memcmp(meta_old, meta_new, sizeof(meta_old))) { @@ -2286,7 +2282,7 @@ static void marktree_itr_fix_pos(MarkTree *b, MarkTreeIter *itr) void marktree_put_test(MarkTree *b, uint32_t ns, uint32_t id, int row, int col, bool right_gravity, int end_row, int end_col, bool end_right, bool meta_inline) { - uint16_t flags = mt_flags(right_gravity, false, false, false, false); + uint16_t flags = mt_flags(right_gravity, false, false, false); // The specific choice is irrelevant here, we pick one counted decor // type to test the counting and filtering logic. flags |= meta_inline ? MT_FLAG_DECOR_VIRT_TEXT_INLINE : 0; diff --git a/src/nvim/marktree.h b/src/nvim/marktree.h index 8e5cf30ff3..15df57ef63 100644 --- a/src/nvim/marktree.h +++ b/src/nvim/marktree.h @@ -35,8 +35,6 @@ #define MT_FLAG_DECOR_VIRT_LINES (((uint16_t)1) << 11) #define MT_FLAG_DECOR_VIRT_TEXT_INLINE (((uint16_t)1) << 12) -#define MT_FLAG_SCOPED (((uint16_t)1) << 13) - // These _must_ be last to preserve ordering of marks #define MT_FLAG_RIGHT_GRAVITY (((uint16_t)1) << 14) #define MT_FLAG_LAST (((uint16_t)1) << 15) @@ -46,7 +44,7 @@ | MT_FLAG_DECOR_VIRT_TEXT_INLINE) #define MT_FLAG_EXTERNAL_MASK (MT_FLAG_DECOR_MASK | MT_FLAG_NO_UNDO \ - | MT_FLAG_INVALIDATE | MT_FLAG_INVALID | MT_FLAG_SCOPED) + | MT_FLAG_INVALIDATE | MT_FLAG_INVALID) // this is defined so that start and end of the same range have adjacent ids #define MARKTREE_END_FLAG ((uint64_t)1) @@ -110,24 +108,12 @@ static inline bool mt_decor_sign(MTKey key) return key.flags & (MT_FLAG_DECOR_SIGNTEXT | MT_FLAG_DECOR_SIGNHL); } -static inline bool mt_scoped(MTKey key) -{ - return key.flags & MT_FLAG_SCOPED; -} - -static inline bool mt_scoped_in_win(MTKey key, win_T *wp) -{ - return !mt_scoped(key) || set_has(uint32_t, &wp->w_ns_set, key.ns); -} - -static inline uint16_t mt_flags(bool right_gravity, bool no_undo, bool invalidate, bool decor_ext, - bool scoped) +static inline uint16_t mt_flags(bool right_gravity, bool no_undo, bool invalidate, bool decor_ext) { return (uint16_t)((right_gravity ? MT_FLAG_RIGHT_GRAVITY : 0) | (no_undo ? MT_FLAG_NO_UNDO : 0) | (invalidate ? MT_FLAG_INVALIDATE : 0) - | (decor_ext ? MT_FLAG_DECOR_EXT : 0) - | (scoped ? MT_FLAG_SCOPED : 0)); + | (decor_ext ? MT_FLAG_DECOR_EXT : 0)); } static inline MTPair mtpair_from(MTKey start, MTKey end) diff --git a/src/nvim/match.c b/src/nvim/match.c index 580d7d1069..86cab5221d 100644 --- a/src/nvim/match.c +++ b/src/nvim/match.c @@ -10,6 +10,7 @@ #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" #include "nvim/eval/window.h" @@ -705,6 +706,9 @@ int update_search_hl(win_T *wp, linenr_T lnum, colnr_T col, char **line, match_T // group. if (shl == search_hl && shl->has_cursor) { shl->attr_cur = win_hl_attr(wp, HLF_LC); + if (shl->attr_cur != shl->attr) { + search_hl_has_cursor_lnum = lnum; + } } else { shl->attr_cur = shl->attr; } diff --git a/src/nvim/math.c b/src/nvim/math.c index 1ccf4d7806..4ca212413b 100644 --- a/src/nvim/math.c +++ b/src/nvim/math.c @@ -78,13 +78,15 @@ int xctz(uint64_t x) } /// Count number of set bits in bit field. -int popcount(uint64_t x) +unsigned xpopcount(uint64_t x) { // Use compiler builtin if possible. -#if defined(__clang__) || defined(__GNUC__) - return __builtin_popcountll(x); +#if defined(__NetBSD__) + return popcount64(x); +#elif defined(__clang__) || defined(__GNUC__) + return (unsigned)__builtin_popcountll(x); #else - int count = 0; + unsigned count = 0; for (; x != 0; x >>= 1) { if (x & 1) { count++; diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index a345795bbe..01e720283e 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -32,6 +32,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <utf8proc.h> #include <uv.h> #include <wctype.h> @@ -43,6 +44,7 @@ #include "nvim/cmdexpand_defs.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/getchar.h" @@ -83,7 +85,6 @@ struct interval { // uncrustify:off #ifdef INCLUDE_GENERATED_DECLARATIONS # include "mbyte.c.generated.h" -# include "unicode_tables.generated.h" #endif // uncrustify:on @@ -442,31 +443,10 @@ int mb_get_class_tab(const char *p, const uint64_t *const chartab) return utf_class_tab(utf_ptr2char(p), chartab); } -// Return true if "c" is in "table". -static bool intable(const struct interval *table, size_t n_items, int c) - FUNC_ATTR_PURE +static bool prop_is_emojilike(const utf8proc_property_t *prop) { - assert(n_items > 0); - // first quick check for Latin1 etc. characters - if (c < table[0].first) { - return false; - } - - assert(n_items <= SIZE_MAX / 2); - // binary search in table - size_t bot = 0; - size_t top = n_items; - do { - size_t mid = (bot + top) >> 1; - if (table[mid].last < c) { - bot = mid + 1; - } else if (table[mid].first > c) { - top = mid; - } else { - return true; - } - } while (top > bot); - return false; + return prop->boundclass == UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC + || prop->boundclass == UTF8PROC_BOUNDCLASS_REGIONAL_INDICATOR; } /// For UTF-8 character "c" return 2 for a double-width character, 1 for others. @@ -494,13 +474,18 @@ int utf_char2cells(int c) return n; } - if (intable(doublewidth, ARRAY_SIZE(doublewidth), c)) { + const utf8proc_property_t *prop = utf8proc_get_property(c); + + if (prop->charwidth == 2) { return 2; } - if (p_emoji && intable(emoji_wide, ARRAY_SIZE(emoji_wide), c)) { + if (*p_ambw == 'd' && prop->ambiguous_width) { return 2; } - if (*p_ambw == 'd' && intable(ambiguous, ARRAY_SIZE(ambiguous), c)) { + + // Characters below 1F000 may be considered single width traditionally, + // making them double width causes problems. + if (p_emoji && c >= 0x1f000 && !prop->ambiguous_width && prop_is_emojilike(prop)) { return 2; } @@ -509,31 +494,43 @@ int utf_char2cells(int c) /// Return the number of display cells character at "*p" occupies. /// This doesn't take care of unprintable characters, use ptr2cells() for that. -int utf_ptr2cells(const char *p) +int utf_ptr2cells(const char *p_in) { + const uint8_t *p = (const uint8_t *)p_in; // Need to convert to a character number. - if ((uint8_t)(*p) >= 0x80) { - int c = utf_ptr2char(p); + if ((*p) >= 0x80) { + int len = utf8len_tab[*p]; + int32_t c = utf_ptr2CharInfo_impl(p, (uintptr_t)len); // An illegal byte is displayed as <xx>. - if (utf_ptr2len(p) == 1 || c == NUL) { + if (c <= 0) { return 4; } // If the char is ASCII it must be an overlong sequence. if (c < 0x80) { return char2cells(c); } - return utf_char2cells(c); + int cells = utf_char2cells(c); + if (cells == 1 && p_emoji + && prop_is_emojilike(utf8proc_get_property(c))) { + int c2 = utf_ptr2char(p_in + len); + if (c2 == 0xFE0F) { + return 2; // emoji presentation + } + } + return cells; } return 1; } /// Convert a UTF-8 byte sequence to a character number. -/// Doesn't handle ascii! only multibyte and illegal sequences. +/// Doesn't handle ascii! only multibyte and illegal sequences. ASCII (including NUL) +/// are treated like illegal sequences. /// /// @param[in] p String to convert. /// @param[in] len Length of the character in bytes, 0 or 1 if illegal. /// -/// @return Unicode codepoint. A negative value when the sequence is illegal. +/// @return Unicode codepoint. A negative value when the sequence is illegal (or +/// ASCII, including NUL). int32_t utf_ptr2CharInfo_impl(uint8_t const *p, uintptr_t const len) FUNC_ATTR_PURE FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { @@ -601,7 +598,8 @@ int utf_ptr2cells_len(const char *p, int size) { // 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)]) { + int len = utf_ptr2len_len(p, size); + if (len < utf8len_tab[(uint8_t)(*p)]) { return 1; // truncated } int c = utf_ptr2char(p); @@ -613,7 +611,16 @@ int utf_ptr2cells_len(const char *p, int size) if (c < 0x80) { return char2cells(c); } - return utf_char2cells(c); + int cells = utf_char2cells(c); + if (cells == 1 && p_emoji && size > len + && prop_is_emojilike(utf8proc_get_property(c)) + && utf_ptr2len_len(p + len, size - len) == utf8len_tab[(uint8_t)p[len]]) { + int c2 = utf_ptr2char(p + len); + if (c2 == 0xFE0F) { + return 2; // emoji presentation + } + } + return cells; } return 1; } @@ -646,8 +653,8 @@ size_t mb_string2cells_len(const char *str, size_t size) size_t clen = 0; for (const char *p = str; *p != NUL && p < str + size; - p += utfc_ptr2len_len(p, (int)size + (int)(p - str))) { - clen += (size_t)utf_ptr2cells(p); + p += utfc_ptr2len_len(p, (int)size - (int)(p - str))) { + clen += (size_t)utf_ptr2cells_len(p, (int)size - (int)(p - str)); } return clen; @@ -791,29 +798,48 @@ int mb_cptr2char_adv(const char **pp) return c; } +/// When "c" is the first char of a string, determine if it needs to be prefixed +/// by a space byte to be drawn correctly, and not merge with the space left of +/// the string. +bool utf_iscomposing_first(int c) +{ + return c >= 128 && !utf8proc_grapheme_break(' ', c); +} + /// Check if the character pointed to by "p2" is a composing character when it -/// comes after "p1". For Arabic sometimes "ab" is replaced with "c", which -/// behaves like a composing character. -bool utf_composinglike(const char *p1, const char *p2) +/// comes after "p1". +/// +/// We use the definition in UAX#29 as implemented by utf8proc with the following +/// exceptions: +/// +/// - ASCII chars always begin a new cluster. This is a long assumed invariant +/// in the code base and very useful for performance (we can exit early for ASCII +/// all over the place, branch predictor go brrr in ASCII-only text). +/// As of Unicode 15.1 this will only break BOUNDCLASS_UREPEND followed by ASCII, +/// which should be exceedingly rare (these PREPEND chars are expected to be +/// followed by multibyte chars within the same script family) +/// +/// - When 'arabicshape' is active, some pairs of arabic letters "ab" is replaced with +/// "c" taking one single cell, which behaves like a cluster. +/// +/// @param "state" should be set to GRAPHEME_STATE_INIT before first call +/// it is allowed to be null, but will then not handle some longer +/// sequences, like ZWJ based emoji +bool utf_composinglike(const char *p1, const char *p2, GraphemeState *state) + FUNC_ATTR_NONNULL_ARG(1, 2) { - int c2 = utf_ptr2char(p2); - if (utf_iscomposing(c2)) { - return true; - } - if (!arabic_maycombine(c2)) { + if ((uint8_t)(*p2) < 128) { return false; } - return arabic_combine(utf_ptr2char(p1), c2); -} -/// Check if the next character is a composing character when it -/// comes after the first. For Arabic sometimes "ab" is replaced with "c", which -/// behaves like a composing character. -/// returns false for negative values -bool utf_char_composinglike(int32_t const first, int32_t const next) - FUNC_ATTR_PURE -{ - return utf_iscomposing(next) || arabic_combine(first, next); + int first = utf_ptr2char(p1); + int second = utf_ptr2char(p2); + + if (!utf8proc_grapheme_break_stateful(first, second, state)) { + return true; + } + + return arabic_combine(first, second); } /// Get the screen char at the beginning of a string @@ -832,7 +858,7 @@ schar_T utfc_ptr2schar(const char *p, int *firstc) { int c = utf_ptr2char(p); *firstc = c; // NOT optional, you are gonna need it - bool first_compose = utf_iscomposing(c); + bool first_compose = utf_iscomposing_first(c); size_t maxlen = MAX_SCHAR_SIZE - 1 - first_compose; size_t len = (size_t)utfc_ptr2len_len(p, (int)maxlen); @@ -843,16 +869,13 @@ schar_T utfc_ptr2schar(const char *p, int *firstc) return schar_from_buf_first(p, len, first_compose); } -/// Get the screen char at the beginning of a string with length +/// Get the screen char from a char with a known length /// /// Like utfc_ptr2schar but use no more than p[maxlen]. -schar_T utfc_ptr2schar_len(const char *p, int maxlen, int *firstc) +schar_T utfc_ptrlen2schar(const char *p, int len, int *firstc) FUNC_ATTR_NONNULL_ALL { - assert(maxlen > 0); - - size_t len = (size_t)utf_ptr2len_len(p, maxlen); - if (len > (size_t)maxlen || (len == 1 && (uint8_t)(*p) >= 0x80) || len == 0) { + if ((len == 1 && (uint8_t)(*p) >= 0x80) || len == 0) { // invalid or truncated sequence *firstc = (uint8_t)(*p); return 0; @@ -860,11 +883,13 @@ schar_T utfc_ptr2schar_len(const char *p, int maxlen, int *firstc) int c = utf_ptr2char(p); *firstc = c; - bool first_compose = utf_iscomposing(c); - maxlen = MIN(maxlen, MAX_SCHAR_SIZE - 1 - first_compose); - len = (size_t)utfc_ptr2len_len(p, maxlen); + bool first_compose = utf_iscomposing_first(c); + int maxlen = MAX_SCHAR_SIZE - 1 - first_compose; + if (len > maxlen) { + len = utfc_ptr2len_len(p, maxlen); + } - return schar_from_buf_first(p, len, first_compose); + return schar_from_buf_first(p, (size_t)len, first_compose); } /// Caller must ensure there is space for `first_compose` @@ -962,8 +987,9 @@ int utfc_ptr2len(const char *const p) // Check for composing characters. int prevlen = 0; + GraphemeState state = GRAPHEME_STATE_INIT; while (true) { - if ((uint8_t)p[len] < 0x80 || !utf_composinglike(p + prevlen, p + len)) { + if ((uint8_t)p[len] < 0x80 || !utf_composinglike(p + prevlen, p + len, &state)) { return len; } @@ -994,9 +1020,10 @@ int utfc_ptr2len_len(const char *p, int size) return 1; } - // Check for composing characters. We can handle only the first six, but + // Check for composing characters. We can only display a limited amount, but // skip all of them (otherwise the cursor would get stuck). int prevlen = 0; + GraphemeState state = GRAPHEME_STATE_INIT; while (len < size) { if ((uint8_t)p[len] < 0x80) { break; @@ -1009,7 +1036,7 @@ int utfc_ptr2len_len(const char *p, int size) break; } - if (!utf_composinglike(p + prevlen, p + len)) { + if (!utf_composinglike(p + prevlen, p + len, &state)) { break; } @@ -1082,13 +1109,21 @@ int utf_char2bytes(const int c, char *const buf) } } -/// Return true if "c" is a composing UTF-8 character. -/// This means it will be drawn on top of the preceding character. +/// Return true if "c" is a legacy composing UTF-8 character. +/// +/// This is deprecated in favour of utf_composinglike() which uses the modern +/// stateful algorithm to determine grapheme clusters. Still available +/// to support some legacy code which hasn't been refactored yet. +/// +/// To check if a char would combine with a preceeding space, use +/// utf_iscomposing_first() instead. +/// /// Based on code from Markus Kuhn. /// Returns false for negative values. -bool utf_iscomposing(int c) +bool utf_iscomposing_legacy(int c) { - return intable(combining, ARRAY_SIZE(combining), c); + const utf8proc_property_t *prop = utf8proc_get_property(c); + return prop->category == UTF8PROC_CATEGORY_MN || prop->category == UTF8PROC_CATEGORY_ME; } #ifdef __SSE2__ @@ -1133,6 +1168,33 @@ bool utf_printable(int c) #else +// Return true if "c" is in "table". +static bool intable(const struct interval *table, size_t n_items, int c) + FUNC_ATTR_PURE +{ + assert(n_items > 0); + // first quick check for Latin1 etc. characters + if (c < table[0].first) { + return false; + } + + assert(n_items <= SIZE_MAX / 2); + // binary search in table + size_t bot = 0; + size_t top = n_items; + do { + size_t mid = (bot + top) >> 1; + if (table[mid].last < c) { + bot = mid + 1; + } else if (table[mid].first > c) { + top = mid; + } else { + return true; + } + } while (top > bot); + return false; +} + // Return true for characters that can be displayed in a normal way. // Only for characters of 0x100 and above! bool utf_printable(int c) @@ -1255,8 +1317,9 @@ int utf_class_tab(const int c, const uint64_t *const chartab) return 1; // punctuation } + const utf8proc_property_t *prop = utf8proc_get_property(c); // emoji - if (intable(emoji_all, ARRAY_SIZE(emoji_all), c)) { + if (prop_is_emojilike(prop)) { return 3; } @@ -1276,47 +1339,51 @@ int utf_class_tab(const int c, const uint64_t *const chartab) return 2; } -bool utf_ambiguous_width(int c) +bool utf_ambiguous_width(const char *p) { - return c >= 0x80 && (intable(ambiguous, ARRAY_SIZE(ambiguous), c) - || intable(emoji_all, ARRAY_SIZE(emoji_all), c)); -} + // be quick if there is nothing to print or ASCII-only + if (p[0] == NUL || p[1] == NUL) { + return false; + } -// Generic conversion function for case operations. -// Return the converted equivalent of "a", which is a UCS-4 character. Use -// the given conversion "table". Uses binary search on "table". -static int utf_convert(int a, const convertStruct *const table, size_t n_items) -{ - // indices into table - size_t start = 0; - size_t end = n_items; - while (start < end) { - // need to search further - size_t mid = (end + start) / 2; - if (table[mid].rangeEnd < a) { - start = mid + 1; - } else { - end = mid; + CharInfo info = utf_ptr2CharInfo(p); + if (info.value >= 0x80) { + const utf8proc_property_t *prop = utf8proc_get_property(info.value); + if (prop->ambiguous_width || prop_is_emojilike(prop)) { + return true; } } - if (start < n_items - && table[start].rangeStart <= a - && a <= table[start].rangeEnd - && (a - table[start].rangeStart) % table[start].step == 0) { - return a + table[start].offset; - } - return a; + + // check if second sequence is 0xFE0F VS-16 which can turn things into emoji, + // safe with NUL (no second sequence) + return memcmp(p + info.len, "\xef\xb8\x8f", 3) == 0; } // Return the folded-case equivalent of "a", which is a UCS-4 character. Uses -// simple case folding. +// full case folding. int utf_fold(int a) { if (a < 0x80) { // be fast for ASCII return a >= 0x41 && a <= 0x5a ? a + 32 : a; } - return utf_convert(a, foldCase, ARRAY_SIZE(foldCase)); + + // TODO(dundargoc): utf8proc only does full case folding, which breaks some tests. This is a + // temporary workaround to circumvent failing tests. + // + // (0xdf) ß == ss in full casefolding. Using this however breaks the vim spell tests and the error + // E763 is thrown. This is due to the test spells relying on the vim spell files. + // + // (0x130) İ == i̇ in full casefolding. + if (a == 0xdf || a == 0x130) { + return a; + } + + utf8proc_int32_t result[1]; + + utf8proc_ssize_t res = utf8proc_decompose_char(a, result, 1, UTF8PROC_CASEFOLD, NULL); + + return (res == 1) ? result[0] : a; } // Vim's own character class functions. These exist because many library @@ -1324,9 +1391,6 @@ int utf_fold(int a) // invalid values or can't handle latin1 when the locale is C. // Speed is most important here. -// Note: UnicodeData.txt does not define U+1E9E as being the corresponding upper -// case letter for U+00DF (ß), however it is part of the toLower table - /// Return the upper-case equivalent of "a", which is a UCS-4 character. Use /// simple case folding. int mb_toupper(int a) @@ -1345,14 +1409,12 @@ int mb_toupper(int a) return TOUPPER_LOC(a); } - // For any other characters use the above mapping table. - return utf_convert(a, toUpper, ARRAY_SIZE(toUpper)); + return utf8proc_toupper(a); } bool mb_islower(int a) { - // German sharp s is lower case but has no upper case equivalent. - return (mb_toupper(a) != a) || a == 0xdf; + return mb_toupper(a) != a; } /// Return the lower-case equivalent of "a", which is a UCS-4 character. Use @@ -1373,8 +1435,7 @@ int mb_tolower(int a) return TOLOWER_LOC(a); } - // For any other characters use the above mapping table. - return utf_convert(a, toLower, ARRAY_SIZE(toLower)); + return utf8proc_tolower(a); } bool mb_isupper(int a) @@ -1388,7 +1449,7 @@ bool mb_isalpha(int a) return mb_islower(a) || mb_isupper(a); } -static int utf_strnicmp(const char *s1, const char *s2, size_t n1, size_t n2) +int utf_strnicmp(const char *s1, const char *s2, size_t n1, size_t n2) { int c1, c2; char buffer[6]; @@ -1545,7 +1606,7 @@ int utf16_to_utf8(const wchar_t *utf16, int utf16len, char **utf8) return uv_translate_sys_error(GetLastError()); } - (*utf8)[bufsize] = '\0'; + (*utf8)[bufsize] = NUL; return 0; } @@ -1673,6 +1734,26 @@ void show_utf8(void) msg(IObuff, 0); } +/// @return true if boundclass bc always starts a new cluster regardless of what's before +/// false negatives are allowed (perf cost, not correctness) +static bool always_break(int bc) +{ + return (bc == UTF8PROC_BOUNDCLASS_CONTROL); +} + +/// @return true if bc2 always starts a cluster after bc1 +/// false negatives are allowed (perf cost, not correctness) +static bool always_break_two(int bc1, int bc2) +{ + // don't check for UTF8PROC_BOUNDCLASS_CONTROL for bc2 as it either has been checked by + // "always_break" on first iteration or when it was bc1 in the previous iteration + return ((bc1 != UTF8PROC_BOUNDCLASS_PREPEND && bc2 == UTF8PROC_BOUNDCLASS_OTHER) + || (bc1 >= UTF8PROC_BOUNDCLASS_CR && bc1 <= UTF8PROC_BOUNDCLASS_CONTROL) + || (bc2 == UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC + && (bc1 == UTF8PROC_BOUNDCLASS_OTHER + || bc1 == UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC))); +} + /// Return offset from "p" to the start of a character, including composing characters. /// "base" must be the start of the string, which must be NUL terminated. /// If "p" points to the NUL at the end of the string return 0. @@ -1686,50 +1767,111 @@ int utf_head_off(const char *base_in, const char *p_in) const uint8_t *base = (uint8_t *)base_in; const uint8_t *p = (uint8_t *)p_in; - // Skip backwards over trailing bytes: 10xx.xxxx - // Skip backwards again if on a composing char. - const uint8_t *q; - for (q = p;; q--) { - // Move s to the last byte of this char. - const uint8_t *s; - for (s = q; (s[1] & 0xc0) == 0x80; s++) {} - - // Move q to the first byte of this char. - while (q > base && (*q & 0xc0) == 0x80) { - q--; - } - // Check for illegal sequence. Do allow an illegal byte after where we - // started. - int len = utf8len_tab[*q]; - if (len != (int)(s - q + 1) && len != (int)(p - q + 1)) { - return 0; + const uint8_t *start = p; + + // move start to the first byte of this codepoint + // might stop on a continuation byte if overlong, handled by utf_ptr2CharInfo_impl + while (start > base && (*start & 0xc0) == 0x80 && (p - start) < 6) { + start--; + } + + const uint8_t last_len = utf8len_tab[*start]; + int32_t cur_code = utf_ptr2CharInfo_impl(start, (uintptr_t)last_len); + if (cur_code < 0 || p - start >= last_len) { + return 0; // p must be part of an illegal sequence + } + const uint8_t * const safe_end = start + last_len; + + int cur_bc = utf8proc_get_property(cur_code)->boundclass; + if (always_break(cur_bc) || start == base) { + return (int)(p - start); + } + + // backtrack to find the start of a cluster. we might go too far, checked in the next loop + const uint8_t *cur_pos = start; + const uint8_t *const p_start = start; + + while (true) { + if (start[-1] == NUL) { + break; } - if (q <= base) { + start--; + if (*start < 0x80) { // stop on ascii, we are done break; } - int c = utf_ptr2char((char *)q); - if (utf_iscomposing(c)) { - continue; + while (start > base && (*start & 0xc0) == 0x80 && (cur_pos - start) < 6) { + start--; } - if (arabic_maycombine(c)) { - // Advance to get a sneak-peak at the next char - const uint8_t *j = q; - j--; - // Move j to the first byte of this char. - while (j > base && (*j & 0xc0) == 0x80) { - j--; - } - if (arabic_combine(utf_ptr2char((char *)j), c)) { - continue; - } + int prev_len = utf8len_tab[*start]; + int32_t prev_code = utf_ptr2CharInfo_impl(start, (uintptr_t)prev_len); + if (prev_code < 0 || prev_len < cur_pos - start) { + start = cur_pos; // start at valid sequence after invalid bytes + break; } - break; + + int prev_bc = utf8proc_get_property(prev_code)->boundclass; + if (always_break_two(prev_bc, cur_bc) && !arabic_combine(prev_code, cur_code)) { + start = cur_pos; // prev_code cannot be a part of this cluster + break; + } else if (start == base) { + break; + } + cur_pos = start; + cur_bc = prev_bc; + cur_code = prev_code; + } + + // hot path: we are already on the first codepoint of a sequence + if (start == p_start && last_len > p - start) { + return (int)(p - start); } - return (int)(p - q); + const uint8_t *q = start; + while (q < p) { + // don't need to find end of cluster. once we reached the codepoint of p, we are done + int len = utfc_ptr2len_len((const char *)q, (int)(safe_end - q)); + + if (q + len > p) { + return (int)(p - q); + } + + q += len; + } + + return 0; +} + +/// Assumes caller already handles ascii. see `utfc_next` +StrCharInfo utfc_next_impl(StrCharInfo cur) +{ + int32_t prev_code = cur.chr.value; + uint8_t *next = (uint8_t *)(cur.ptr + cur.chr.len); + GraphemeState state = GRAPHEME_STATE_INIT; + assert(*next >= 0x80); + + while (true) { + uint8_t const next_len = utf8len_tab[*next]; + int32_t const next_code = utf_ptr2CharInfo_impl(next, (uintptr_t)next_len); + if (utf8proc_grapheme_break_stateful(prev_code, next_code, &state) + && !arabic_combine(prev_code, next_code)) { + return (StrCharInfo){ + .ptr = (char *)next, + .chr = (CharInfo){ .value = next_code, .len = (next_code < 0 ? 1 : next_len) }, + }; + } + + prev_code = next_code; + next += next_len; + if (EXPECT(*next < 0x80U, true)) { + return (StrCharInfo){ + .ptr = (char *)next, + .chr = (CharInfo){ .value = *next, .len = 1 }, + }; + } + } } // Whether space is NOT allowed before/after 'c'. @@ -2688,7 +2830,7 @@ char *string_convert_ext(const vimconv_T *const vcp, char *ptr, size_t *lenp, si c = 0x100; break; // not in latin9 } } - if (!utf_iscomposing(c)) { // skip composing chars + if (!utf_iscomposing_legacy(c)) { // skip composing chars if (c < 0x100) { *d++ = (uint8_t)c; } else if (vcp->vc_fail) { @@ -2776,17 +2918,17 @@ void f_setcellwidths(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) emsg(_(e_listreq)); return; } + const list_T *const l = argvars[0].vval.v_list; - if (tv_list_len(l) == 0) { + cw_interval_T *table = NULL; + const size_t table_size = (size_t)tv_list_len(l); + if (table_size == 0) { // Clearing the table. - xfree(cw_table); - cw_table = NULL; - cw_table_size = 0; - return; + goto update; } // Note: use list_T instead of listitem_T so that TV_LIST_ITEM_NEXT can be used properly below. - const list_T **ptrs = xmalloc(sizeof(const list_T *) * (size_t)tv_list_len(l)); + const list_T **ptrs = xmalloc(sizeof(const list_T *) * table_size); // Check that all entries are a list with three numbers, the range is // valid and the cell width is valid. @@ -2838,12 +2980,12 @@ void f_setcellwidths(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) }); // Sort the list on the first number. - qsort((void *)ptrs, (size_t)tv_list_len(l), sizeof(const list_T *), tv_nr_compare); + qsort((void *)ptrs, table_size, sizeof(const list_T *), tv_nr_compare); - cw_interval_T *table = xmalloc(sizeof(cw_interval_T) * (size_t)tv_list_len(l)); + table = xmalloc(sizeof(cw_interval_T) * table_size); // Store the items in the new table. - for (item = 0; item < tv_list_len(l); item++) { + for (item = 0; (size_t)item < table_size; item++) { const list_T *const li_l = ptrs[item]; const listitem_T *lili = tv_list_first(li_l); const varnumber_T n1 = TV_LIST_ITEM_TV(lili)->vval.v_number; @@ -2862,10 +3004,12 @@ void f_setcellwidths(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) xfree((void *)ptrs); +update: + ; cw_interval_T *const cw_table_save = cw_table; const size_t cw_table_size_save = cw_table_size; cw_table = table; - cw_table_size = (size_t)tv_list_len(l); + cw_table_size = table_size; // Check that the new value does not conflict with 'listchars' or // 'fillchars'. diff --git a/src/nvim/mbyte.h b/src/nvim/mbyte.h index ddac040aae..2da051fca2 100644 --- a/src/nvim/mbyte.h +++ b/src/nvim/mbyte.h @@ -3,17 +3,21 @@ #include <stdbool.h> #include <stdint.h> #include <sys/types.h> // IWYU pragma: keep +#include <utf8proc.h> #include <uv.h> // IWYU pragma: keep #include "nvim/cmdexpand_defs.h" // IWYU pragma: keep #include "nvim/eval/typval_defs.h" // IWYU pragma: keep -#include "nvim/func_attr.h" #include "nvim/macros_defs.h" #include "nvim/mbyte_defs.h" // IWYU pragma: keep #include "nvim/types_defs.h" // IWYU pragma: keep +typedef utf8proc_int32_t GraphemeState; +#define GRAPHEME_STATE_INIT 0 + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "mbyte.h.generated.h" +# include "mbyte.h.inline.generated.h" #endif enum { @@ -53,18 +57,14 @@ extern const uint8_t utf8len_tab[256]; (p -= utf_head_off((char *)(s), (char *)(p) - 1) + 1) /// Check whether a given UTF-8 byte is a trailing byte (10xx.xxxx). -static inline bool utf_is_trail_byte(uint8_t byte) - REAL_FATTR_CONST REAL_FATTR_ALWAYS_INLINE; static inline bool utf_is_trail_byte(uint8_t const byte) + FUNC_ATTR_CONST FUNC_ATTR_ALWAYS_INLINE { // uint8_t is for clang to use smaller cmp return (uint8_t)(byte & 0xC0U) == 0x80U; } -static inline CharInfo utf_ptr2CharInfo(char const *p_in) - REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_ALWAYS_INLINE; - /// Convert a UTF-8 byte sequence to a Unicode code point. /// Handles ascii, multibyte sequiences and illegal sequences. /// @@ -73,6 +73,7 @@ static inline CharInfo utf_ptr2CharInfo(char const *p_in) /// @return information abouth the character. When the sequence is illegal, /// "value" is negative, "len" is 1. static inline CharInfo utf_ptr2CharInfo(char const *const p_in) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE { uint8_t const *const p = (uint8_t const *)p_in; uint8_t const first = *p; @@ -88,43 +89,27 @@ static inline CharInfo utf_ptr2CharInfo(char const *const p_in) } } -static inline StrCharInfo utfc_next(StrCharInfo cur) - REAL_FATTR_NONNULL_ALL REAL_FATTR_ALWAYS_INLINE REAL_FATTR_PURE; - /// Return information about the next character. /// Composing and combining characters are considered a part of the current character. /// /// @param[in] cur Information about the current character in the string. static inline StrCharInfo utfc_next(StrCharInfo cur) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_PURE { - int32_t prev_code = cur.chr.value; + // handle ASCII case inline uint8_t *next = (uint8_t *)(cur.ptr + cur.chr.len); - - while (true) { - if (EXPECT(*next < 0x80U, true)) { - return (StrCharInfo){ - .ptr = (char *)next, - .chr = (CharInfo){ .value = *next, .len = 1 }, - }; - } - uint8_t const next_len = utf8len_tab[*next]; - int32_t const next_code = utf_ptr2CharInfo_impl(next, (uintptr_t)next_len); - if (!utf_char_composinglike(prev_code, next_code)) { - return (StrCharInfo){ - .ptr = (char *)next, - .chr = (CharInfo){ .value = next_code, .len = (next_code < 0 ? 1 : next_len) }, - }; - } - - prev_code = next_code; - next += next_len; + if (EXPECT(*next < 0x80U, true)) { + return (StrCharInfo){ + .ptr = (char *)next, + .chr = (CharInfo){ .value = *next, .len = 1 }, + }; } -} -static inline StrCharInfo utf_ptr2StrCharInfo(char *ptr) - REAL_FATTR_NONNULL_ALL REAL_FATTR_ALWAYS_INLINE REAL_FATTR_PURE; + return utfc_next_impl(cur); +} static inline StrCharInfo utf_ptr2StrCharInfo(char *ptr) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_PURE { return (StrCharInfo){ .ptr = ptr, .chr = utf_ptr2CharInfo(ptr) }; } diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c index a1713edb66..d032caa3be 100644 --- a/src/nvim/memfile.c +++ b/src/nvim/memfile.c @@ -46,6 +46,7 @@ #include "nvim/assert_defs.h" #include "nvim/buffer_defs.h" +#include "nvim/errors.h" #include "nvim/fileio.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" @@ -565,7 +566,8 @@ static int mf_write(memfile_T *mfp, bhdr_T *hp) bhdr_T *hp2; unsigned page_count; // number of pages written - if (mfp->mf_fd < 0) { // there is no file, can't write + if (mfp->mf_fd < 0 && !mfp->mf_reopen) { + // there is no file and there was no file, can't write return FAIL; } @@ -592,28 +594,48 @@ static int mf_write(memfile_T *mfp, bhdr_T *hp) // TODO(elmart): Check (page_size * nr) within off_T bounds. off_T offset = (off_T)(page_size * nr); // offset in the file - if (vim_lseek(mfp->mf_fd, offset, SEEK_SET) != offset) { - PERROR(_("E296: Seek error in swap file write")); - return FAIL; - } if (hp2 == NULL) { // freed block, fill with dummy data page_count = 1; } else { page_count = hp2->bh_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 - /// disk is full. We give the message again only after a successful - /// write or when hitting a key. We keep on trying, in case some - /// space becomes available. - if (!did_swapwrite_msg) { - emsg(_("E297: Write error in swap file")); + + for (int attempt = 1; attempt <= 2; attempt++) { + if (mfp->mf_fd >= 0) { + if (vim_lseek(mfp->mf_fd, offset, SEEK_SET) != offset) { + PERROR(_("E296: Seek error in swap file write")); + return FAIL; + } + void *data = (hp2 == NULL) ? hp->bh_data : hp2->bh_data; + if ((unsigned)write_eintr(mfp->mf_fd, data, size) == size) { + break; + } + } + + if (attempt == 1) { + // If the swap file is on a network drive, and the network + // gets disconnected and then re-connected, we can maybe fix it + // by closing and then re-opening the file. + if (mfp->mf_fd >= 0) { + close(mfp->mf_fd); + } + mfp->mf_fd = os_open(mfp->mf_fname, mfp->mf_flags, S_IREAD | S_IWRITE); + mfp->mf_reopen = (mfp->mf_fd < 0); + } + if (attempt == 2 || mfp->mf_fd < 0) { + // Avoid repeating the error message, this mostly happens when the + // disk is full. We give the message again only after a successful + // write or when hitting a key. We keep on trying, in case some + // space becomes available. + if (!did_swapwrite_msg) { + emsg(_("E297: Write error in swap file")); + } + did_swapwrite_msg = true; + return FAIL; } - did_swapwrite_msg = true; - return FAIL; } + did_swapwrite_msg = false; if (hp2 != NULL) { // written a non-dummy block hp2->bh_flags &= ~BH_DIRTY; @@ -750,7 +772,9 @@ static bool mf_do_open(memfile_T *mfp, char *fname, int flags) emsg(_("E300: Swap file already exists (symlink attack?)")); } else { // try to open the file - mfp->mf_fd = os_open(mfp->mf_fname, flags | O_NOFOLLOW, S_IREAD | S_IWRITE); + flags |= O_NOFOLLOW; + mfp->mf_flags = flags; + mfp->mf_fd = os_open(mfp->mf_fname, flags, S_IREAD | S_IWRITE); } // If the file cannot be opened, use memory only diff --git a/src/nvim/memfile_defs.h b/src/nvim/memfile_defs.h index 5caf13c9fb..5f2468c947 100644 --- a/src/nvim/memfile_defs.h +++ b/src/nvim/memfile_defs.h @@ -46,6 +46,8 @@ typedef struct { char *mf_fname; ///< name of the file char *mf_ffname; ///< idem, full path int mf_fd; ///< file descriptor + int mf_flags; ///< flags used when opening this memfile + bool mf_reopen; ///< mf_fd was closed, retry opening bhdr_T *mf_free_first; ///< first block header in free list /// The used blocks are kept in mf_hash. diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 5acf4f0c37..92e2ef2b55 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -84,7 +84,7 @@ #include "nvim/os/input.h" #include "nvim/os/os.h" #include "nvim/os/os_defs.h" -#include "nvim/os/process.h" +#include "nvim/os/proc.h" #include "nvim/os/time.h" #include "nvim/os/time_defs.h" #include "nvim/path.h" @@ -743,7 +743,7 @@ static void add_b0_fenc(ZeroBlock *b0p, buf_T *buf) /// @param swap_fname Name of the swapfile. If it's from before a reboot, the result is 0. /// /// @return PID, or 0 if process is not running or the swapfile is from before a reboot. -static int swapfile_process_running(const ZeroBlock *b0p, const char *swap_fname) +static int swapfile_proc_running(const ZeroBlock *b0p, const char *swap_fname) { FileInfo st; double uptime; @@ -905,12 +905,9 @@ void ml_recover(bool checkext) msg_end(); goto theend; } - off_T size; - if ((size = vim_lseek(mfp->mf_fd, 0, SEEK_END)) <= 0) { - mfp->mf_blocknr_max = 0; // no file or empty file - } else { - mfp->mf_blocknr_max = size / mfp->mf_page_size; - } + off_T size = vim_lseek(mfp->mf_fd, 0, SEEK_END); + // 0 means no file or empty file + mfp->mf_blocknr_max = size <= 0 ? 0 : size / mfp->mf_page_size; mfp->mf_infile_count = mfp->mf_blocknr_max; // need to reallocate the memory used to store the data @@ -1217,7 +1214,7 @@ void ml_recover(bool checkext) msg(_("Recovery completed. Buffer contents equals file contents."), 0); } msg_puts(_("\nYou may want to delete the .swp file now.")); - if (swapfile_process_running(b0p, fname_used)) { + if (swapfile_proc_running(b0p, fname_used)) { // Warn there could be an active Vim on the same file, the user may // want to kill it. msg_puts(_("\nNote: process STILL RUNNING: ")); @@ -1253,7 +1250,7 @@ theend: /// with the 'directory' option. /// /// Used to: -/// - list the swapfiles for "vim -r" +/// - list the swapfiles for "nvim -r" /// - count the number of swapfiles when recovering /// - list the swapfiles when recovering /// - list the swapfiles for swapfilelist() @@ -1325,11 +1322,9 @@ int recover_names(char *fname, bool do_list, list_T *ret_list, int nr, char **fn } else { int len = (int)strlen(dir_name); p = dir_name + len; - if (after_pathsep(dir_name, p) - && len > 1 - && p[-1] == p[-2]) { + if (after_pathsep(dir_name, p) && len > 1 && p[-1] == p[-2]) { // Ends with '//', Use Full path for swap name - tail = make_percent_swname(dir_name, fname_res); + tail = make_percent_swname(dir_name, p, fname_res); } else { tail = path_tail(fname_res); tail = concat_fnames(dir_name, tail, true); @@ -1440,8 +1435,11 @@ int recover_names(char *fname, bool do_list, list_T *ret_list, int nr, char **fn /// Append the full path to name with path separators made into percent /// signs, to dir. An unnamed buffer is handled as "" (<currentdir>/"") -char *make_percent_swname(const char *dir, const char *name) - FUNC_ATTR_NONNULL_ARG(1) +/// signs, to "dir". An unnamed buffer is handled as "" (<currentdir>/"") +/// The last character in "dir" must be an extra slash or backslash, it is +/// removed. +char *make_percent_swname(char *dir, char *dir_end, const char *name) + FUNC_ATTR_NONNULL_ARG(1, 2) { char *d = NULL; char *f = fix_fname(name != NULL ? name : ""); @@ -1455,6 +1453,8 @@ char *make_percent_swname(const char *dir, const char *name) *d = '%'; } } + + dir_end[-1] = NUL; // remove one trailing slash d = concat_fnames(dir, s, true); xfree(s); xfree(f); @@ -1462,7 +1462,7 @@ char *make_percent_swname(const char *dir, const char *name) } // PID of swapfile owner, or zero if not running. -static int process_running; +static int proc_running; /// For Vimscript "swapinfo()". /// @@ -1488,7 +1488,7 @@ void swapfile_dict(const char *fname, dict_T *d) tv_dict_add_str_len(d, S_LEN("fname"), b0.b0_fname, B0_FNAME_SIZE_ORG); - tv_dict_add_nr(d, S_LEN("pid"), swapfile_process_running(&b0, fname)); + tv_dict_add_nr(d, S_LEN("pid"), swapfile_proc_running(&b0, fname)); tv_dict_add_nr(d, S_LEN("mtime"), char_to_long(b0.b0_mtime)); tv_dict_add_nr(d, S_LEN("dirty"), b0.b0_dirty ? 1 : 0); tv_dict_add_nr(d, S_LEN("inode"), char_to_long(b0.b0_ino)); @@ -1572,7 +1572,7 @@ static time_t swapfile_info(char *fname) if (char_to_long(b0.b0_pid) != 0) { msg_puts(_("\n process ID: ")); msg_outnum((int)char_to_long(b0.b0_pid)); - if ((process_running = swapfile_process_running(&b0, fname))) { + if ((proc_running = swapfile_proc_running(&b0, fname))) { msg_puts(_(" (STILL RUNNING)")); } } @@ -1640,7 +1640,7 @@ static bool swapfile_unchanged(char *fname) } // process must be known and not running. - if (char_to_long(b0.b0_pid) == 0 || swapfile_process_running(&b0, fname)) { + if (char_to_long(b0.b0_pid) == 0 || swapfile_proc_running(&b0, fname)) { ret = false; } @@ -1895,9 +1895,7 @@ errorret: buf->b_ml.ml_line_lnum = lnum; return questions; } - if (lnum <= 0) { // pretend line 0 is line 1 - lnum = 1; - } + lnum = MAX(lnum, 1); // pretend line 0 is line 1 if (buf->b_ml.ml_mfp == NULL) { // there are no lines buf->b_ml.ml_line_len = 1; @@ -2108,12 +2106,8 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char *line, colnr_T len, boo if (line_count > db_idx + 1) { // if there are following lines // Offset is the start of the previous line. // This will become the character just after the new line. - int offset; - if (db_idx < 0) { - offset = (int)dp->db_txt_end; - } else { - offset = ((dp->db_index[db_idx]) & DB_INDEX_MASK); - } + int offset = db_idx < 0 ? (int)dp->db_txt_end + : (int)((dp->db_index[db_idx]) & DB_INDEX_MASK); memmove((char *)dp + dp->db_txt_start, (char *)dp + dp->db_txt_start + len, (size_t)offset - (dp->db_txt_start + (size_t)len)); @@ -3192,11 +3186,10 @@ char *makeswapname(char *fname, char *ffname, buf_T *buf, char *dir_name) int len = (int)strlen(dir_name); char *s = dir_name + len; - if (after_pathsep(dir_name, s) - && len > 1 - && s[-1] == s[-2]) { // Ends with '//', Use Full path + if (after_pathsep(dir_name, s) && len > 1 && s[-1] == s[-2]) { + // Ends with '//', Use Full path char *r = NULL; - s = make_percent_swname(dir_name, fname_res); + s = make_percent_swname(dir_name, s, fname_res); if (s != NULL) { r = modname(s, ".swp", false); xfree(s); @@ -3287,7 +3280,7 @@ static void attention_message(buf_T *buf, char *fname) " instances of the same\n file when making changes." " Quit, or continue with caution.\n")); msg_puts(_("(2) An edit session for this file crashed.\n")); - msg_puts(_(" If this is the case, use \":recover\" or \"vim -r ")); + msg_puts(_(" If this is the case, use \":recover\" or \"nvim -r ")); msg_outtrans(buf->b_fname, 0); msg_puts(_("\"\n to recover the changes (see \":help recovery\").\n")); msg_puts(_(" If you did this already, delete the swap file \"")); @@ -3406,7 +3399,7 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ fd = os_open(fname, O_RDONLY, 0); if (fd >= 0) { if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0)) { - process_running = swapfile_process_running(&b0, fname); + proc_running = swapfile_proc_running(&b0, fname); // If the swapfile has the same directory as the // buffer don't compare the directory names, they can @@ -3466,7 +3459,7 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ choice = SEA_CHOICE_READONLY; } - process_running = 0; // Set by attention_message..swapfile_info. + proc_running = 0; // Set by attention_message..swapfile_info. if (choice == SEA_CHOICE_NONE) { // Show info about the existing swapfile. attention_message(buf, fname); @@ -3498,12 +3491,12 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ = do_dialog(VIM_WARNING, _("VIM - ATTENTION"), name, - process_running + proc_running ? _("&Open Read-Only\n&Edit anyway\n&Recover\n&Quit\n&Abort") : _("&Open Read-Only\n&Edit anyway\n&Recover\n&Delete it\n&Quit\n&Abort"), 1, NULL, false); - if (process_running && dialog_result >= 4) { + if (proc_running && dialog_result >= 4) { // compensate for missing "Delete it" button dialog_result++; } diff --git a/src/nvim/memory.c b/src/nvim/memory.c index 789535e270..3aa37c047c 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -19,6 +19,7 @@ #include "nvim/context.h" #include "nvim/decoration_provider.h" #include "nvim/drawline.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" @@ -198,11 +199,11 @@ void *xmallocz(size_t size) { size_t total_size = size + 1; if (total_size < size) { - preserve_exit(_("Vim: Data too large to fit into virtual memory space\n")); + preserve_exit(_("Nvim: Data too large to fit into virtual memory space\n")); } void *ret = xmalloc(total_size); - ((char *)ret)[size] = '\0'; + ((char *)ret)[size] = NUL; return ret; } @@ -232,7 +233,7 @@ void *xmemcpyz(void *dst, const void *src, size_t len) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { memcpy(dst, src, len); - ((char *)dst)[len] = '\0'; + ((char *)dst)[len] = NUL; return dst; } @@ -240,7 +241,7 @@ void *xmemcpyz(void *dst, const void *src, size_t len) size_t xstrnlen(const char *s, size_t n) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE { - const char *end = memchr(s, '\0', n); + const char *end = memchr(s, NUL, n); if (end == NULL) { return n; } @@ -287,7 +288,7 @@ void *xmemscan(const void *addr, char c, size_t size) void strchrsub(char *str, char c, char x) FUNC_ATTR_NONNULL_ALL { - assert(c != '\0'); + assert(c != NUL); while ((str = strchr(str, c))) { *str++ = x; } @@ -387,7 +388,7 @@ char *xstpcpy(char *restrict dst, const char *restrict src) char *xstpncpy(char *restrict dst, const char *restrict src, size_t maxlen) FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { - const char *p = memchr(src, '\0', maxlen); + const char *p = memchr(src, NUL, maxlen); if (p) { size_t srclen = (size_t)(p - src); memcpy(dst, src, srclen); @@ -419,7 +420,7 @@ size_t xstrlcpy(char *restrict dst, const char *restrict src, size_t dsize) if (dsize) { size_t len = MIN(slen, dsize - 1); memcpy(dst, src, len); - dst[len] = '\0'; + dst[len] = NUL; } return slen; // Does not include NUL. @@ -449,7 +450,7 @@ size_t xstrlcat(char *const dst, const char *const src, const size_t dsize) if (slen > dsize - dlen - 1) { memmove(dst + dlen, src, dsize - dlen - 1); - dst[dsize - 1] = '\0'; + dst[dsize - 1] = NUL; } else { memmove(dst + dlen, src, slen + 1); } @@ -509,7 +510,7 @@ char *xstrndup(const char *str, size_t len) FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL { - char *p = memchr(str, '\0', len); + char *p = memchr(str, NUL, len); return xmemdupz(str, p ? (size_t)(p - str) : len); } @@ -882,7 +883,6 @@ void free_all_mem(void) decor_free_all_mem(); drawline_free_all_mem(); - input_free_all_mem(); if (ui_client_channel_id) { ui_client_free_all_mem(); diff --git a/src/nvim/memory.h b/src/nvim/memory.h index 0788670142..a6ff82e39d 100644 --- a/src/nvim/memory.h +++ b/src/nvim/memory.h @@ -45,8 +45,6 @@ EXTERN size_t arena_alloc_count INIT( = 0); ((v).capacity = (s), \ (v).items = (void *)arena_alloc(a, sizeof((v).items[0]) * (v).capacity, true)) -#define ARENA_BLOCK_SIZE 4096 - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "memory.h.generated.h" #endif @@ -72,5 +70,3 @@ EXTERN size_t arena_alloc_count INIT( = 0); // Like strcpy() but allows overlapped source and destination. #define STRMOVE(d, s) memmove((d), (s), strlen(s) + 1) - -#define STRCAT(d, s) strcat((char *)(d), (char *)(s)) // NOLINT(runtime/printf) diff --git a/src/nvim/memory_defs.h b/src/nvim/memory_defs.h index bde0e54f54..df271ceca5 100644 --- a/src/nvim/memory_defs.h +++ b/src/nvim/memory_defs.h @@ -11,5 +11,7 @@ typedef struct { size_t pos, size; } Arena; +#define ARENA_BLOCK_SIZE 4096 + // inits an empty arena. #define ARENA_EMPTY { .cur_blk = NULL, .pos = 0, .size = 0 } diff --git a/src/nvim/menu.c b/src/nvim/menu.c index ab28eeca1c..c33d3cc712 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -13,6 +13,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/cursor.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -1056,7 +1057,7 @@ char *get_menu_names(expand_T *xp, int idx) } // hack on menu separators: use a 'magic' char for the separator // so that '.' in names gets escaped properly - STRCAT(tbuffer, "\001"); + strcat(tbuffer, "\001"); str = tbuffer; } else { if (should_advance) { diff --git a/src/nvim/message.c b/src/nvim/message.c index 10b90bde29..79e6bc8be7 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -18,6 +18,7 @@ #include "nvim/channel.h" #include "nvim/charset.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -445,9 +446,7 @@ void trunc_string(const char *s, char *buf, int room_in, int buflen) // Last part: End of the string. half = i = (int)strlen(s); while (true) { - do { - half = half - utf_head_off(s, s + half - 1) - 1; - } while (half > 0 && utf_iscomposing(utf_ptr2char(s + half))); + half = half - utf_head_off(s, s + half - 1) - 1; n = ptr2cells(s + half); if (len + n > room || half == 0) { break; @@ -1383,11 +1382,7 @@ void msgmore(int n) return; } - if (n > 0) { - pn = n; - } else { - pn = -n; - } + pn = abs(n); if (pn > p_report) { if (n > 0) { @@ -1425,9 +1420,7 @@ void msg_start(void) { bool did_return = false; - if (msg_row < cmdline_row) { - msg_row = cmdline_row; - } + msg_row = MAX(msg_row, cmdline_row); if (!msg_silent) { XFREE_CLEAR(keep_msg); // don't display old message now @@ -2689,7 +2682,7 @@ static void msg_puts_printf(const char *str, const ptrdiff_t maxlen) *p++ = '\r'; } memcpy(p, s, (size_t)len); - *(p + len) = '\0'; + *(p + len) = NUL; if (info_message) { printf("%s", buf); } else { @@ -3381,9 +3374,7 @@ void msg_advance(int col) } return; } - if (col >= Columns) { // not enough room - col = Columns - 1; - } + col = MIN(col, Columns - 1); // not enough room while (msg_col < col) { msg_putchar(' '); } diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index f393b0fd0f..884bc88d73 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -194,7 +194,11 @@ static void call_click_def_func(StlClickDefinition *click_defs, int col, int whi ? "r" : (which_button == MOUSE_MIDDLE ? "m" - : "?"))) + : (which_button == MOUSE_X1 + ? "x1" + : (which_button == MOUSE_X2 + ? "x2" + : "?"))))) }, }, { @@ -250,11 +254,17 @@ static int get_fpos_of_mouse(pos_T *mpos) } // winpos and height may change in win_enter()! - if (winrow >= wp->w_height_inner) { // In (or below) status line + if (winrow >= wp->w_height_inner + wp->w_status_height) { // Below window + if (mouse_grid <= 1 && mouse_row < Rows - p_ch + && mouse_row >= Rows - p_ch - global_stl_height()) { // In global status line + return IN_STATUS_LINE; + } + return IN_UNKNOWN; + } else if (winrow >= wp->w_height_inner) { // In window status line return IN_STATUS_LINE; } - if (winrow < 0 && winrow + wp->w_winbar_height >= 0) { + if (winrow < 0 && winrow + wp->w_winbar_height >= 0) { // In winbar return MOUSE_WINBAR; } @@ -688,6 +698,9 @@ popupexit: if (in_statuscol && wp->w_p_rl) { click_col = wp->w_width_inner - click_col - 1; } + if (in_statuscol && click_col >= (int)wp->w_statuscol_click_defs_size) { + return false; + } if (click_defs != NULL) { switch (click_defs[click_col].type) { @@ -1041,9 +1054,7 @@ void do_mousescroll(cmdarg_T *cap) // Horizontal scrolling int step = shift_or_ctrl ? curwin->w_width_inner : (int)p_mousescroll_hor; colnr_T leftcol = curwin->w_leftcol + (cap->arg == MSCR_RIGHT ? -step : +step); - if (leftcol < 0) { - leftcol = 0; - } + leftcol = MAX(leftcol, 0); do_mousescroll_horiz(leftcol); } } @@ -1610,11 +1621,8 @@ bool mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump) while (row > 0) { // Don't include filler lines in "count" if (win_may_fill(win)) { - if (lnum == win->w_topline) { - row -= win->w_topfill; - } else { - row -= win_get_fill(win, lnum); - } + row -= lnum == win->w_topline ? win->w_topfill + : win_get_fill(win, lnum); count = plines_win_nofill(win, lnum, false); } else { count = plines_win(win, lnum, false); @@ -1655,9 +1663,7 @@ bool mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump) if (!retval) { // Compute the column without wrapping. int off = win_col_off(win) - win_col_off2(win); - if (col < off) { - col = off; - } + col = MAX(col, off); col += row * (win->w_width_inner - off); // Add skip column for the topline. @@ -1672,9 +1678,7 @@ bool mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump) // skip line number and fold column in front of the line col -= win_col_off(win); - if (col <= 0) { - col = 0; - } + col = MAX(col, 0); *colp = col; *rowp = row; diff --git a/src/nvim/move.c b/src/nvim/move.c index 418ece09ed..6324466dcc 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -20,6 +20,7 @@ #include "nvim/diff.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval/typval.h" #include "nvim/eval/window.h" #include "nvim/fold.h" @@ -152,7 +153,6 @@ static void redraw_for_cursorline(win_T *wp) /// Redraw when w_virtcol changes and /// - 'cursorcolumn' is set, or /// - 'cursorlineopt' contains "screenline", or -/// - "CurSearch" highlight is in use, or /// - 'concealcursor' is active, or /// - Visual mode is active. static void redraw_for_cursorcolumn(win_T *wp) @@ -172,10 +172,8 @@ static void redraw_for_cursorcolumn(win_T *wp) return; } - if (wp->w_p_cuc - || (win_hl_attr(wp, HLF_LC) != win_hl_attr(wp, HLF_L) && using_hlsearch())) { - // When 'cursorcolumn' is set or "CurSearch" is in use - // need to redraw with UPD_SOME_VALID. + if (wp->w_p_cuc) { + // When 'cursorcolumn' is set need to redraw with UPD_SOME_VALID. redraw_later(wp, UPD_SOME_VALID); } else if (wp->w_p_cul && (wp->w_p_culopt_flags & CULOPT_SCRLINE)) { // When 'cursorlineopt' contains "screenline" need to redraw with UPD_VALID. @@ -896,9 +894,7 @@ void curs_columns(win_T *wp, int may_scroll) new_leftcol = wp->w_leftcol + diff; } } - if (new_leftcol < 0) { - new_leftcol = 0; - } + new_leftcol = MAX(new_leftcol, 0); if (new_leftcol != (int)wp->w_leftcol) { wp->w_leftcol = new_leftcol; win_check_anchored_floats(wp); @@ -971,11 +967,8 @@ void curs_columns(win_T *wp, int may_scroll) if (n > plines - wp->w_height_inner + 1) { n = plines - wp->w_height_inner + 1; } - if (n > 0) { - wp->w_skipcol = width1 + (n - 1) * width2; - } else { - wp->w_skipcol = 0; - } + wp->w_skipcol = n > 0 ? width1 + (n - 1) * width2 + : 0; } else if (extra == 1) { // less than 'scrolloff' lines above, decrease skipcol assert(so <= INT_MAX); @@ -992,9 +985,7 @@ void curs_columns(win_T *wp, int may_scroll) while (endcol > wp->w_virtcol) { endcol -= width2; } - if (endcol > wp->w_skipcol) { - wp->w_skipcol = endcol; - } + wp->w_skipcol = MAX(wp->w_skipcol, endcol); } // adjust w_wrow for the changed w_skipcol @@ -1131,9 +1122,7 @@ void f_screenpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) semsg(_(e_invalid_line_number_nr), pos.lnum); return; } - if (pos.col < 0) { - pos.col = 0; - } + pos.col = MAX(pos.col, 0); int row = 0; int scol = 0; int ccol = 0; @@ -1425,9 +1414,7 @@ bool scrolldown(win_T *wp, linenr_T line_count, int byfold) foldAdjustCursor(wp); coladvance(wp, wp->w_curswant); } - if (wp->w_cursor.lnum < wp->w_topline) { - wp->w_cursor.lnum = wp->w_topline; - } + wp->w_cursor.lnum = MAX(wp->w_cursor.lnum, wp->w_topline); return moved; } @@ -1508,12 +1495,8 @@ bool scrollup(win_T *wp, linenr_T line_count, bool byfold) wp->w_botline += line_count; // approximate w_botline } - if (wp->w_topline > wp->w_buffer->b_ml.ml_line_count) { - wp->w_topline = wp->w_buffer->b_ml.ml_line_count; - } - if (wp->w_botline > wp->w_buffer->b_ml.ml_line_count + 1) { - wp->w_botline = wp->w_buffer->b_ml.ml_line_count + 1; - } + wp->w_topline = MIN(wp->w_topline, wp->w_buffer->b_ml.ml_line_count); + wp->w_botline = MIN(wp->w_botline, wp->w_buffer->b_ml.ml_line_count + 1); check_topfill(wp, false); @@ -1625,9 +1608,7 @@ void check_topfill(win_T *wp, bool down) wp->w_topfill = 0; } else { wp->w_topfill = wp->w_height_inner - n; - if (wp->w_topfill < 0) { - wp->w_topfill = 0; - } + wp->w_topfill = MAX(wp->w_topfill, 0); } } } @@ -1851,15 +1832,11 @@ void scroll_cursor_top(win_T *wp, int min_scroll, int always) if (new_topline < wp->w_topline || always) { wp->w_topline = new_topline; } - if (wp->w_topline > wp->w_cursor.lnum) { - wp->w_topline = wp->w_cursor.lnum; - } + wp->w_topline = MIN(wp->w_topline, wp->w_cursor.lnum); wp->w_topfill = win_get_fill(wp, wp->w_topline); if (wp->w_topfill > 0 && extra > off) { wp->w_topfill -= extra - off; - if (wp->w_topfill < 0) { - wp->w_topfill = 0; - } + wp->w_topfill = MAX(wp->w_topfill, 0); } check_topfill(wp, false); if (wp->w_topline != old_topline) { @@ -2278,18 +2255,14 @@ void cursor_correct(win_T *wp) if (wp->w_topline == 1) { above_wanted = 0; int max_off = wp->w_height_inner / 2; - if (below_wanted > max_off) { - below_wanted = max_off; - } + below_wanted = MIN(below_wanted, max_off); } validate_botline(wp); if (wp->w_botline == wp->w_buffer->b_ml.ml_line_count + 1 && mouse_dragging == 0) { below_wanted = 0; int max_off = (wp->w_height_inner - 1) / 2; - if (above_wanted > max_off) { - above_wanted = max_off; - } + above_wanted = MIN(above_wanted, max_off); } // If there are sufficient file-lines above and below the cursor, we can @@ -2520,9 +2493,11 @@ int pagescroll(Direction dir, int count, bool half) ? MAX(1, (int)p_window - 2) : get_scroll_overlap(dir)); nochange = scroll_with_sms(dir, count, &count); - // Place cursor at top or bottom of window. - validate_botline(curwin); - curwin->w_cursor.lnum = (dir == FORWARD ? curwin->w_topline : curwin->w_botline - 1); + if (!nochange) { + // Place cursor at top or bottom of window. + validate_botline(curwin); + curwin->w_cursor.lnum = (dir == FORWARD ? curwin->w_topline : curwin->w_botline - 1); + } } if (get_scrolloff_value(curwin) > 0) { diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 5737a0440f..626312b666 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -1,8 +1,5 @@ #include <assert.h> #include <inttypes.h> -#include <msgpack/object.h> -#include <msgpack/sbuffer.h> -#include <msgpack/unpack.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -17,7 +14,7 @@ #include "nvim/event/defs.h" #include "nvim/event/loop.h" #include "nvim/event/multiqueue.h" -#include "nvim/event/process.h" +#include "nvim/event/proc.h" #include "nvim/event/rstream.h" #include "nvim/event/wstream.h" #include "nvim/globals.h" @@ -31,8 +28,6 @@ #include "nvim/msgpack_rpc/packer.h" #include "nvim/msgpack_rpc/unpacker.h" #include "nvim/os/input.h" -#include "nvim/rbuffer.h" -#include "nvim/rbuffer_defs.h" #include "nvim/types_defs.h" #include "nvim/ui.h" #include "nvim/ui_client.h" @@ -85,11 +80,11 @@ void rpc_start(Channel *channel) rpc->unpacker = xcalloc(1, sizeof *rpc->unpacker); unpacker_init(rpc->unpacker); rpc->next_request_id = 1; - rpc->info = (Dictionary)ARRAY_DICT_INIT; + rpc->info = (Dict)ARRAY_DICT_INIT; kv_init(rpc->call_stack); if (channel->streamtype != kChannelStreamInternal) { - Stream *out = channel_outstream(channel); + RStream *out = channel_outstream(channel); #ifdef NVIM_LOG_DEBUG Stream *in = channel_instream(channel); DLOG("rpc ch %" PRIu64 " in-stream=%p out-stream=%p", channel->id, @@ -202,10 +197,25 @@ Object rpc_send_call(uint64_t id, const char *method_name, Array args, ArenaMem return frame.errored ? NIL : frame.result; } -static void receive_msgpack(Stream *stream, RBuffer *rbuf, size_t c, void *data, bool eof) +static size_t receive_msgpack(RStream *stream, const char *rbuf, size_t c, void *data, bool eof) { Channel *channel = data; channel_incref(channel); + size_t consumed = 0; + + DLOG("ch %" PRIu64 ": parsing %zu bytes from msgpack Stream: %p", + channel->id, c, (void *)stream); + + if (c > 0) { + Unpacker *p = channel->rpc.unpacker; + p->read_ptr = rbuf; + p->read_size = c; + parse_msgpack(channel); + + if (!unpacker_closed(p)) { + consumed = c - p->read_size; + } + } if (eof) { channel_close(channel->id, kChannelPartRpc, NULL); @@ -213,25 +223,10 @@ static void receive_msgpack(Stream *stream, RBuffer *rbuf, size_t c, void *data, snprintf(buf, sizeof(buf), "ch %" PRIu64 " was closed by the client", channel->id); chan_close_with_error(channel, buf, LOGLVL_INF); - goto end; - } - - DLOG("ch %" PRIu64 ": parsing %zu bytes from msgpack Stream: %p", - channel->id, rbuffer_size(rbuf), (void *)stream); - - Unpacker *p = channel->rpc.unpacker; - size_t size = 0; - p->read_ptr = rbuffer_read_ptr(rbuf, &size); - p->read_size = size; - parse_msgpack(channel); - - if (!unpacker_closed(p)) { - size_t consumed = size - p->read_size; - rbuffer_consumed_compact(rbuf, consumed); } -end: channel_decref(channel); + return consumed; } static ChannelCallFrame *find_call_frame(RpcState *rpc, uint32_t request_id) @@ -505,7 +500,7 @@ void rpc_free(Channel *channel) xfree(channel->rpc.unpacker); kv_destroy(channel->rpc.call_stack); - api_free_dictionary(channel->rpc.info); + api_free_dict(channel->rpc.info); } static void chan_close_with_error(Channel *channel, char *msg, int loglevel) @@ -592,16 +587,16 @@ static void packer_buffer_init_channels(Channel **chans, size_t nchans, PackerBu packer->endptr = packer->startptr + ARENA_BLOCK_SIZE; packer->packer_flush = channel_flush_callback; packer->anydata = chans; - packer->anylen = nchans; + packer->anyint = (int64_t)nchans; } static void packer_buffer_finish_channels(PackerBuffer *packer) { size_t len = (size_t)(packer->ptr - packer->startptr); if (len > 0) { - WBuffer *buf = wstream_new_buffer(packer->startptr, len, packer->anylen, free_block); + WBuffer *buf = wstream_new_buffer(packer->startptr, len, (size_t)packer->anyint, free_block); Channel **chans = packer->anydata; - for (size_t i = 0; i < packer->anylen; i++) { + for (int64_t i = 0; i < packer->anyint; i++) { channel_write(chans[i], buf); } } else { @@ -612,17 +607,17 @@ static void packer_buffer_finish_channels(PackerBuffer *packer) static void channel_flush_callback(PackerBuffer *packer) { packer_buffer_finish_channels(packer); - packer_buffer_init_channels(packer->anydata, packer->anylen, packer); + packer_buffer_init_channels(packer->anydata, (size_t)packer->anyint, packer); } -void rpc_set_client_info(uint64_t id, Dictionary info) +void rpc_set_client_info(uint64_t id, Dict info) { Channel *chan = find_rpc_channel(id); if (!chan) { abort(); } - api_free_dictionary(chan->rpc.info); + api_free_dict(chan->rpc.info); chan->rpc.info = info; // Parse "type" on "info" and set "client_type" @@ -646,9 +641,9 @@ void rpc_set_client_info(uint64_t id, Dictionary info) channel_info_changed(chan, false); } -Dictionary rpc_client_info(Channel *chan) +Dict rpc_client_info(Channel *chan) { - return copy_dictionary(chan->rpc.info, NULL); + return copy_dict(chan->rpc.info, NULL); } const char *get_client_info(Channel *chan, const char *key) @@ -657,7 +652,7 @@ const char *get_client_info(Channel *chan, const char *key) if (!chan->is_rpc) { return NULL; } - Dictionary info = chan->rpc.info; + Dict info = chan->rpc.info; for (size_t i = 0; i < info.size; i++) { if (strequal(key, info.items[i].key.data) && info.items[i].value.type == kObjectTypeString) { diff --git a/src/nvim/msgpack_rpc/channel.h b/src/nvim/msgpack_rpc/channel.h index ff73a2fc53..abf1ce7bf6 100644 --- a/src/nvim/msgpack_rpc/channel.h +++ b/src/nvim/msgpack_rpc/channel.h @@ -12,7 +12,7 @@ /// HACK: os/input.c drains this queue immediately before blocking for input. /// Events on this queue are async-safe, but they need the resolved state -/// of os_inchar(), so they are processed "just-in-time". +/// of input_get(), so they are processed "just-in-time". EXTERN MultiQueue *ch_before_blocking_events INIT( = NULL); #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/msgpack_rpc/channel_defs.h b/src/nvim/msgpack_rpc/channel_defs.h index 7dc1374964..871d4e615f 100644 --- a/src/nvim/msgpack_rpc/channel_defs.h +++ b/src/nvim/msgpack_rpc/channel_defs.h @@ -1,6 +1,5 @@ #pragma once -#include <msgpack.h> #include <stdbool.h> #include <uv.h> @@ -41,6 +40,6 @@ typedef struct { Unpacker *unpacker; uint32_t next_request_id; kvec_t(ChannelCallFrame *) call_stack; - Dictionary info; + Dict info; ClientType client_type; } RpcState; diff --git a/src/nvim/msgpack_rpc/packer.c b/src/nvim/msgpack_rpc/packer.c index cac68f76f0..b739f7ba28 100644 --- a/src/nvim/msgpack_rpc/packer.c +++ b/src/nvim/msgpack_rpc/packer.c @@ -8,10 +8,9 @@ # include "msgpack_rpc/packer.c.generated.h" #endif -static void check_buffer(PackerBuffer *packer) +void mpack_check_buffer(PackerBuffer *packer) { - ptrdiff_t remaining = packer->endptr - packer->ptr; - if (remaining < MPACK_ITEM_SIZE) { + if (mpack_remaining(packer) < 2 * MPACK_ITEM_SIZE) { packer->packer_flush(packer); } } @@ -28,15 +27,20 @@ static void mpack_w8(char **b, const char *data) #endif } +void mpack_uint64(char **ptr, uint64_t i) +{ + if (i > 0xfffffff) { + mpack_w(ptr, 0xcf); + mpack_w8(ptr, (char *)&i); + } else { + mpack_uint(ptr, (uint32_t)i); + } +} + void mpack_integer(char **ptr, Integer i) { if (i >= 0) { - if (i > 0xfffffff) { - mpack_w(ptr, 0xcf); - mpack_w8(ptr, (char *)&i); - } else { - mpack_uint(ptr, (uint32_t)i); - } + mpack_uint64(ptr, (uint64_t)i); } else { if (i < -0x80000000LL) { mpack_w(ptr, 0xd3); @@ -80,11 +84,35 @@ void mpack_str(String str, PackerBuffer *packer) abort(); } + mpack_raw(str.data, len, packer); +} + +void mpack_bin(String str, PackerBuffer *packer) +{ + const size_t len = str.size; + if (len < 0xff) { + mpack_w(&packer->ptr, 0xc4); + mpack_w(&packer->ptr, len); + } else if (len < 0xffff) { + mpack_w(&packer->ptr, 0xc5); + mpack_w2(&packer->ptr, (uint32_t)len); + } else if (len < 0xffffffff) { + mpack_w(&packer->ptr, 0xc6); + mpack_w4(&packer->ptr, (uint32_t)len); + } else { + abort(); + } + + mpack_raw(str.data, len, packer); +} + +void mpack_raw(const char *data, size_t len, PackerBuffer *packer) +{ size_t pos = 0; while (pos < len) { ptrdiff_t remaining = packer->endptr - packer->ptr; size_t to_copy = MIN(len - pos, (size_t)remaining); - memcpy(packer->ptr, str.data + pos, to_copy); + memcpy(packer->ptr, data + pos, to_copy); packer->ptr += to_copy; pos += to_copy; @@ -92,6 +120,28 @@ void mpack_str(String str, PackerBuffer *packer) packer->packer_flush(packer); } } + mpack_check_buffer(packer); +} + +void mpack_ext(char *buf, size_t len, int8_t type, PackerBuffer *packer) +{ + if (len == 1) { + mpack_w(&packer->ptr, 0xd4); + } else if (len == 2) { + mpack_w(&packer->ptr, 0xd5); + } else if (len <= 0xff) { + mpack_w(&packer->ptr, 0xc7); + } else if (len < 0xffff) { + mpack_w(&packer->ptr, 0xc8); + mpack_w2(&packer->ptr, (uint32_t)len); + } else if (len < 0xffffffff) { + mpack_w(&packer->ptr, 0xc9); + mpack_w4(&packer->ptr, (uint32_t)len); + } else { + abort(); + } + mpack_w(&packer->ptr, type); + mpack_raw(buf, len, packer); } void mpack_handle(ObjectType type, handle_T handle, PackerBuffer *packer) @@ -113,7 +163,6 @@ void mpack_handle(ObjectType type, handle_T handle, PackerBuffer *packer) mpack_w(&packer->ptr, 0xc7); mpack_w(&packer->ptr, packsize); mpack_w(&packer->ptr, exttype); - // check_buffer(packer); memcpy(packer->ptr, buf, (size_t)packsize); packer->ptr += packsize; } @@ -148,7 +197,7 @@ void mpack_object_inner(Object *current, Object *container, size_t container_idx kvi_init(stack); while (true) { - check_buffer(packer); + mpack_check_buffer(packer); switch (current->type) { case kObjectTypeLuaRef: // TODO(bfredl): could also be an error. Though kObjectTypeLuaRef @@ -177,14 +226,14 @@ void mpack_object_inner(Object *current, Object *container, size_t container_idx case kObjectTypeTabpage: mpack_handle(current->type, (handle_T)current->data.integer, packer); break; - case kObjectTypeDictionary: + case kObjectTypeDict: case kObjectTypeArray: {} size_t current_size; if (current->type == kObjectTypeArray) { current_size = current->data.array.size; mpack_array(&packer->ptr, (uint32_t)current_size); } else { - current_size = current->data.dictionary.size; + current_size = current->data.dict.size; mpack_map(&packer->ptr, (uint32_t)current_size); } if (current_size > 0) { @@ -221,9 +270,9 @@ void mpack_object_inner(Object *current, Object *container, size_t container_idx container = NULL; } } else { - Dictionary dict = container->data.dictionary; + Dict dict = container->data.dict; KeyValuePair *it = &dict.items[container_idx++]; - check_buffer(packer); + mpack_check_buffer(packer); mpack_str(it->key, packer); current = &it->value; if (container_idx >= dict.size) { @@ -233,3 +282,32 @@ void mpack_object_inner(Object *current, Object *container, size_t container_idx } kvi_destroy(stack); } + +PackerBuffer packer_string_buffer(void) +{ + const size_t initial_size = 64; // must be larger than SHADA_MPACK_FREE_SPACE + char *alloc = xmalloc(initial_size); + return (PackerBuffer) { + .startptr = alloc, + .ptr = alloc, + .endptr = alloc + initial_size, + .packer_flush = flush_string_buffer, + }; +} + +static void flush_string_buffer(PackerBuffer *buffer) +{ + size_t current_capacity = (size_t)(buffer->endptr - buffer->startptr); + size_t new_capacity = 2 * current_capacity; + size_t len = (size_t)(buffer->ptr - buffer->startptr); + + buffer->startptr = xrealloc(buffer->startptr, new_capacity); + buffer->ptr = buffer->startptr + len; + buffer->endptr = buffer->startptr + new_capacity; +} + +/// can only be used with a PackerBuffer from `packer_string_buffer` +String packer_take_string(PackerBuffer *buffer) +{ + return (String){ .data = buffer->startptr, .size = (size_t)(buffer->ptr - buffer->startptr) }; +} diff --git a/src/nvim/msgpack_rpc/packer.h b/src/nvim/msgpack_rpc/packer.h index 8117bd09bd..299962bab4 100644 --- a/src/nvim/msgpack_rpc/packer.h +++ b/src/nvim/msgpack_rpc/packer.h @@ -71,6 +71,11 @@ static inline void mpack_map(char **buf, uint32_t len) } } +static inline size_t mpack_remaining(PackerBuffer *packer) +{ + return (size_t)(packer->endptr - packer->ptr); +} + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "msgpack_rpc/packer.h.generated.h" #endif diff --git a/src/nvim/msgpack_rpc/packer_defs.h b/src/nvim/msgpack_rpc/packer_defs.h index 420f3dc424..95d86caaab 100644 --- a/src/nvim/msgpack_rpc/packer_defs.h +++ b/src/nvim/msgpack_rpc/packer_defs.h @@ -19,6 +19,6 @@ struct packer_buffer_t { // these are free to be used by packer_flush for any purpose, if want void *anydata; - size_t anylen; + int64_t anyint; PackerBufferFlush packer_flush; }; diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c index 56b03d67d0..462f8397f4 100644 --- a/src/nvim/msgpack_rpc/server.c +++ b/src/nvim/msgpack_rpc/server.c @@ -4,18 +4,21 @@ #include <string.h> #include <uv.h> +#include "nvim/ascii_defs.h" #include "nvim/channel.h" #include "nvim/eval.h" #include "nvim/event/defs.h" #include "nvim/event/socket.h" #include "nvim/garray.h" #include "nvim/garray_defs.h" +#include "nvim/globals.h" #include "nvim/log.h" #include "nvim/main.h" #include "nvim/memory.h" #include "nvim/msgpack_rpc/server.h" #include "nvim/os/os.h" #include "nvim/os/stdpaths_defs.h" +#include "nvim/types_defs.h" #define MAX_CONNECTIONS 32 #define ENV_LISTEN "NVIM_LISTEN_ADDRESS" // deprecated @@ -26,37 +29,61 @@ static garray_T watchers = GA_EMPTY_INIT_VALUE; # include "msgpack_rpc/server.c.generated.h" #endif -/// Initializes the module +/// Initializes resources, handles `--listen`, starts the primary server at v:servername. +/// +/// @returns true on success, false on fatal error (message stored in IObuff) bool server_init(const char *listen_addr) { + bool ok = true; + bool must_free = false; + TriState user_arg = kTrue; // User-provided --listen arg. ga_init(&watchers, sizeof(SocketWatcher *), 1); // $NVIM_LISTEN_ADDRESS (deprecated) - if (!listen_addr && os_env_exists(ENV_LISTEN)) { + if ((!listen_addr || listen_addr[0] == '\0') && os_env_exists(ENV_LISTEN)) { + user_arg = kFalse; // User-provided env var. listen_addr = os_getenv(ENV_LISTEN); } - int rv = listen_addr ? server_start(listen_addr) : 1; - if (0 != rv) { + if (!listen_addr || listen_addr[0] == '\0') { + user_arg = kNone; // Autogenerated server address. listen_addr = server_address_new(NULL); - if (!listen_addr) { - return false; - } - rv = server_start(listen_addr); - xfree((char *)listen_addr); + must_free = true; } - if (os_env_exists(ENV_LISTEN)) { - // Unset $NVIM_LISTEN_ADDRESS, it's a liability hereafter. - os_unsetenv(ENV_LISTEN); - } + int rv = server_start(listen_addr); - // TODO(justinmk): this is for logging_spec. Can remove this after nvim_log #7062 is merged. + // TODO(justinmk): this is for log_spec. Can remove this after nvim_log #7062 is merged. if (os_env_exists("__NVIM_TEST_LOG")) { ELOG("test log message"); } - return rv == 0; + if (must_free) { + xfree((char *)listen_addr); + } + + if (rv == 0 || user_arg == kNone) { + // The autogenerated servername can fail if the user has a broken $XDG_RUNTIME_DIR. #30282 + // But that is not fatal (startup will continue, logged in $NVIM_LOGFILE, empty v:servername). + goto end; + } + + (void)snprintf(IObuff, IOSIZE, + user_arg == + kTrue ? "Failed to --listen: %s: \"%s\"" + : "Failed $NVIM_LISTEN_ADDRESS: %s: \"%s\"", + rv < 0 ? os_strerror(rv) : (rv == 1 ? "empty address" : "?"), + listen_addr); + ok = false; + +end: + if (os_env_exists(ENV_LISTEN)) { + // Unset $NVIM_LISTEN_ADDRESS, it's a liability hereafter. It is "input only", it must not be + // leaked to child jobs or :terminal. + os_unsetenv(ENV_LISTEN); + } + + return ok; } /// Teardown a single server @@ -87,17 +114,19 @@ void server_teardown(void) /// - Windows: "\\.\pipe\<name>.<pid>.<counter>" /// - Other: "/tmp/nvim.user/xxx/<name>.<pid>.<counter>" char *server_address_new(const char *name) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET { static uint32_t count = 0; char fmt[ADDRESS_MAX_SIZE]; - const char *appname = get_appname(); #ifdef MSWIN + (void)get_appname(true); int r = snprintf(fmt, sizeof(fmt), "\\\\.\\pipe\\%s.%" PRIu64 ".%" PRIu32, - name ? name : appname, os_get_pid(), count++); + name ? name : NameBuff, os_get_pid(), count++); #else char *dir = stdpaths_get_xdg_var(kXDGRuntimeDir); + (void)get_appname(true); int r = snprintf(fmt, sizeof(fmt), "%s/%s.%" PRIu64 ".%" PRIu32, - dir, name ? name : appname, os_get_pid(), count++); + dir, name ? name : NameBuff, os_get_pid(), count++); xfree(dir); #endif if ((size_t)r >= sizeof(fmt)) { @@ -131,7 +160,7 @@ bool server_owns_pipe_address(const char *path) /// @returns 0: success, 1: validation error, 2: already listening, -errno: failed to bind/listen. int server_start(const char *addr) { - if (addr == NULL || addr[0] == '\0') { + if (addr == NULL || addr[0] == NUL) { WLOG("Empty or NULL address"); return 1; } diff --git a/src/nvim/msgpack_rpc/unpacker.c b/src/nvim/msgpack_rpc/unpacker.c index 28d27e8268..4ddc41e596 100644 --- a/src/nvim/msgpack_rpc/unpacker.c +++ b/src/nvim/msgpack_rpc/unpacker.c @@ -11,6 +11,7 @@ #include "nvim/memory.h" #include "nvim/msgpack_rpc/channel_defs.h" #include "nvim/msgpack_rpc/unpacker.h" +#include "nvim/strings.h" #include "nvim/ui_client.h" #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -58,7 +59,7 @@ static void api_parse_enter(mpack_parser_t *parser, mpack_node_t *node) } case MPACK_TOKEN_MAP: { Object *obj = parent->data[0].p; - KeyValuePair *kv = &kv_A(obj->data.dictionary, parent->pos); + KeyValuePair *kv = &kv_A(obj->data.dict, parent->pos); if (!parent->key_visited) { // TODO(bfredl): when implementing interrupt parse on error, // stop parsing here when node is not a STR/BIN @@ -165,10 +166,10 @@ static void api_parse_enter(mpack_parser_t *parser, mpack_node_t *node) break; } case MPACK_TOKEN_MAP: { - Dictionary dict = KV_INITIAL_VALUE; + Dict dict = KV_INITIAL_VALUE; kv_fixsize_arena(&p->arena, dict, node->tok.length); kv_size(dict) = node->tok.length; - *result = DICTIONARY_OBJ(dict); + *result = DICT_OBJ(dict); node->data[0].p = result; break; } @@ -206,6 +207,7 @@ bool unpacker_parse_header(Unpacker *p) assert(!ERROR_SET(&p->unpack_error)); + // TODO(bfredl): eliminate p->reader, we can use mpack_rtoken directly #define NEXT(tok) \ result = mpack_read(&p->reader, &data, &size, &tok); \ if (result) { goto error; } @@ -522,3 +524,197 @@ bool unpacker_parse_redraw(Unpacker *p) abort(); } } + +/// Requires a complete string. safe to use e.g. in shada as we have loaded a +/// complete shada item into a linear buffer. +/// +/// Data and size are preserved in cause of failure. +/// +/// @return "data" is NULL only when failure (non-null data and size=0 for +/// valid empty string) +String unpack_string(const char **data, size_t *size) +{ + const char *data2 = *data; + size_t size2 = *size; + mpack_token_t tok; + + // TODO(bfredl): this code is hot a f, specialize! + int result = mpack_rtoken(&data2, &size2, &tok); + if (result || (tok.type != MPACK_TOKEN_STR && tok.type != MPACK_TOKEN_BIN)) { + return (String)STRING_INIT; + } + if (*size < tok.length) { + // result = MPACK_EOF; + return (String)STRING_INIT; + } + (*data) = data2 + tok.length; + (*size) = size2 - tok.length; + return cbuf_as_string((char *)data2, tok.length); +} + +/// @return -1 if not an array or EOF. otherwise size of valid array +ssize_t unpack_array(const char **data, size_t *size) +{ + // TODO(bfredl): this code is hot, specialize! + mpack_token_t tok; + int result = mpack_rtoken(data, size, &tok); + if (result || tok.type != MPACK_TOKEN_ARRAY) { + return -1; + } + return tok.length; +} + +/// does not keep "data" untouched on failure +bool unpack_integer(const char **data, size_t *size, Integer *res) +{ + mpack_token_t tok; + int result = mpack_rtoken(data, size, &tok); + if (result) { + return false; + } + return unpack_uint_or_sint(tok, res); +} + +bool unpack_uint_or_sint(mpack_token_t tok, Integer *res) +{ + if (tok.type == MPACK_TOKEN_UINT) { + *res = (Integer)mpack_unpack_uint(tok); + return true; + } else if (tok.type == MPACK_TOKEN_SINT) { + *res = (Integer)mpack_unpack_sint(tok); + return true; + } + return false; +} + +static void parse_nop(mpack_parser_t *parser, mpack_node_t *node) +{ +} + +int unpack_skip(const char **data, size_t *size) +{ + mpack_parser_t parser; + mpack_parser_init(&parser, 0); + + return mpack_parse(&parser, data, size, parse_nop, parse_nop); +} + +void push_additional_data(AdditionalDataBuilder *ad, const char *data, size_t size) +{ + if (kv_size(*ad) == 0) { + AdditionalData init = { 0 }; + kv_concat_len(*ad, &init, sizeof(init)); + } + AdditionalData *a = (AdditionalData *)ad->items; + a->nitems++; + a->nbytes += (uint32_t)size; + kv_concat_len(*ad, data, size); +} + +// currently only used for shada, so not re-entrant like unpacker_parse_redraw +bool unpack_keydict(void *retval, FieldHashfn hashy, AdditionalDataBuilder *ad, const char **data, + size_t *restrict size, char **error) +{ + OptKeySet *ks = (OptKeySet *)retval; + mpack_token_t tok; + + int result = mpack_rtoken(data, size, &tok); + if (result || tok.type != MPACK_TOKEN_MAP) { + *error = xstrdup("is not a dict"); + return false; + } + + size_t map_size = tok.length; + + for (size_t i = 0; i < map_size; i++) { + const char *item_start = *data; + // TODO(bfredl): we could specialize a hot path for FIXSTR here + String key = unpack_string(data, size); + if (!key.data) { + *error = arena_printf(NULL, "has key value which is not a string").data; + return false; + } else if (key.size == 0) { + *error = arena_printf(NULL, "has empty key").data; + return false; + } + KeySetLink *field = hashy(key.data, key.size); + + if (!field) { + int status = unpack_skip(data, size); + if (status) { + return false; + } + + if (ad) { + push_additional_data(ad, item_start, (size_t)(*data - item_start)); + } + continue; + } + + assert(field->opt_index >= 0); + uint64_t flag = (1ULL << field->opt_index); + if (ks->is_set_ & flag) { + *error = xstrdup("duplicate key"); + return false; + } + ks->is_set_ |= flag; + + char *mem = ((char *)retval + field->ptr_off); + switch (field->type) { + case kObjectTypeBoolean: + if (*size == 0 || (**data & 0xfe) != 0xc2) { + *error = arena_printf(NULL, "has %.*s key value which is not a boolean", (int)key.size, + key.data).data; + return false; + } + *(Boolean *)mem = **data & 0x01; + (*data)++; (*size)--; + break; + + case kObjectTypeInteger: + if (!unpack_integer(data, size, (Integer *)mem)) { + *error = arena_printf(NULL, "has %.*s key value which is not an integer", (int)key.size, + key.data).data; + return false; + } + break; + + case kObjectTypeString: { + String val = unpack_string(data, size); + if (!val.data) { + *error = arena_printf(NULL, "has %.*s key value which is not a binary", (int)key.size, + key.data).data; + return false; + } + *(String *)mem = val; + break; + } + + case kUnpackTypeStringArray: { + ssize_t len = unpack_array(data, size); + if (len < 0) { + *error = arena_printf(NULL, "has %.*s key with non-array value", (int)key.size, + key.data).data; + return false; + } + StringArray *a = (StringArray *)mem; + kv_ensure_space(*a, (size_t)len); + for (size_t j = 0; j < (size_t)len; j++) { + String item = unpack_string(data, size); + if (!item.data) { + *error = arena_printf(NULL, "has %.*s array with non-binary value", (int)key.size, + key.data).data; + return false; + } + kv_push(*a, item); + } + break; + } + + default: + abort(); // not supported + } + } + + return true; +} diff --git a/src/nvim/msgpack_rpc/unpacker.h b/src/nvim/msgpack_rpc/unpacker.h index ed55fdd4af..c29462292f 100644 --- a/src/nvim/msgpack_rpc/unpacker.h +++ b/src/nvim/msgpack_rpc/unpacker.h @@ -41,6 +41,8 @@ struct Unpacker { bool has_grid_line_event; }; +typedef kvec_t(char) AdditionalDataBuilder; + // unrecovareble error. unpack_error should be set! #define unpacker_closed(p) ((p)->state < 0) diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 8ba375f29d..be9987cc7f 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -28,12 +28,14 @@ #include "nvim/digraph.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds2.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" #include "nvim/ex_getln.h" +#include "nvim/file_search.h" #include "nvim/fileio.h" #include "nvim/fold.h" #include "nvim/getchar.h" @@ -349,6 +351,7 @@ static const struct nv_cmd { { K_F1, nv_help, NV_NCW, 0 }, { K_XF1, nv_help, NV_NCW, 0 }, { K_SELECT, nv_select, 0, 0 }, + { K_PASTE_START, nv_paste, NV_KEEPREG, 0 }, { K_EVENT, nv_event, NV_KEEPREG, 0 }, { K_COMMAND, nv_colon, 0, 0 }, { K_LUA, nv_colon, 0, 0 }, @@ -835,7 +838,10 @@ static void normal_get_additional_char(NormalState *s) while ((s->c = vpeekc()) > 0 && (s->c >= 0x100 || MB_BYTE2LEN(vpeekc()) > 1)) { s->c = plain_vgetc(); - if (!utf_iscomposing(s->c)) { + // TODO(bfredl): only allowing up to two composing chars is cringe af. + // Could reuse/abuse schar_T to at least allow us to input anything we are able + // to display and use the stateful utf8proc algorithm like utf_composinglike + if (!utf_iscomposing_legacy(s->c)) { vungetc(s->c); // it wasn't, put it back break; } else if (s->ca.ncharC1 == 0) { @@ -1659,7 +1665,6 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char **text // When starting on a ']' count it, so that we include the '['. bn = ptr[col] == ']'; - // // 2. Back up to start of identifier/text. // // Remember class of character under cursor. @@ -1685,9 +1690,7 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char **text // If we don't want just any old text, or we've found an // identifier, stop searching. - if (this_class > 2) { - this_class = 2; - } + this_class = MIN(this_class, 2); if (!(find_type & FIND_STRING) || this_class == 2) { break; } @@ -1986,7 +1989,7 @@ bool add_to_showcmd(int c) size_t overflow = old_len + extra_len - limit; memmove(showcmd_buf, showcmd_buf + overflow, old_len - overflow + 1); } - STRCAT(showcmd_buf, p); + strcat(showcmd_buf, p); if (char_avail()) { return false; @@ -2011,9 +2014,7 @@ static void del_from_showcmd(int len) } int old_len = (int)strlen(showcmd_buf); - if (len > old_len) { - len = old_len; - } + len = MIN(len, old_len); showcmd_buf[old_len - len] = NUL; if (!char_avail()) { @@ -2096,17 +2097,23 @@ static void display_showcmd(void) grid_line_flush(); } +int get_vtopline(win_T *wp) +{ + return plines_m_win_fill(wp, 1, wp->w_topline) - wp->w_topfill; +} + /// When "check" is false, prepare for commands that scroll the window. /// When "check" is true, take care of scroll-binding after the window has /// scrolled. Called from normal_cmd() and edit(). void do_check_scrollbind(bool check) { static win_T *old_curwin = NULL; - static linenr_T old_topline = 0; - static int old_topfill = 0; + static linenr_T old_vtopline = 0; static buf_T *old_buf = NULL; static colnr_T old_leftcol = 0; + int vtopline = get_vtopline(curwin); + if (check && curwin->w_p_scb) { // If a ":syncbind" command was just used, don't scroll, only reset // the values. @@ -2119,10 +2126,9 @@ void do_check_scrollbind(bool check) if ((curwin->w_buffer == old_buf || curwin->w_p_diff ) - && (curwin->w_topline != old_topline - || curwin->w_topfill != old_topfill + && (vtopline != old_vtopline || curwin->w_leftcol != old_leftcol)) { - check_scrollbind(curwin->w_topline - old_topline, curwin->w_leftcol - old_leftcol); + check_scrollbind(vtopline - old_vtopline, curwin->w_leftcol - old_leftcol); } } else if (vim_strchr(p_sbo, 'j')) { // jump flag set in 'scrollopt' // When switching between windows, make sure that the relative @@ -2133,14 +2139,13 @@ void do_check_scrollbind(bool check) // resync is performed, some of the other 'scrollbind' windows may // need to jump so that the current window's relative position is // visible on-screen. - check_scrollbind(curwin->w_topline - (linenr_T)curwin->w_scbind_pos, 0); + check_scrollbind(vtopline - curwin->w_scbind_pos, 0); } - curwin->w_scbind_pos = curwin->w_topline; + curwin->w_scbind_pos = vtopline; } old_curwin = curwin; - old_topline = curwin->w_topline; - old_topfill = curwin->w_topfill; + old_vtopline = vtopline; old_buf = curwin->w_buffer; old_leftcol = curwin->w_leftcol; } @@ -2148,20 +2153,18 @@ void do_check_scrollbind(bool check) /// Synchronize any windows that have "scrollbind" set, based on the /// number of rows by which the current window has changed /// (1998-11-02 16:21:01 R. Edward Ralston <eralston@computer.org>) -void check_scrollbind(linenr_T topline_diff, int leftcol_diff) +void check_scrollbind(linenr_T vtopline_diff, int leftcol_diff) { win_T *old_curwin = curwin; buf_T *old_curbuf = curbuf; int old_VIsual_select = VIsual_select; int old_VIsual_active = VIsual_active; colnr_T tgt_leftcol = curwin->w_leftcol; - linenr_T topline; - linenr_T y; // check 'scrollopt' string for vertical and horizontal scroll options - bool want_ver = (vim_strchr(p_sbo, 'v') && topline_diff != 0); - want_ver |= old_curwin->w_p_diff; - bool want_hor = (vim_strchr(p_sbo, 'h') && (leftcol_diff || topline_diff != 0)); + bool want_ver = old_curwin->w_p_diff + || (vim_strchr(p_sbo, 'v') && vtopline_diff != 0); + bool want_hor = (vim_strchr(p_sbo, 'h') && (leftcol_diff || vtopline_diff != 0)); // loop through the scrollbound windows and scroll accordingly VIsual_select = VIsual_active = 0; @@ -2178,16 +2181,19 @@ void check_scrollbind(linenr_T topline_diff, int leftcol_diff) if (old_curwin->w_p_diff && curwin->w_p_diff) { diff_set_topline(old_curwin, curwin); } else { - curwin->w_scbind_pos += topline_diff; - topline = (linenr_T)curwin->w_scbind_pos; - if (topline > curbuf->b_ml.ml_line_count) { - topline = curbuf->b_ml.ml_line_count; - } - if (topline < 1) { - topline = 1; - } + curwin->w_scbind_pos += vtopline_diff; + int curr_vtopline = get_vtopline(curwin); - y = topline - curwin->w_topline; + // Perf: reuse curr_vtopline to reduce the time in plines_m_win_fill(). + // Equivalent to: + // int max_vtopline = plines_m_win_fill(curwin, 1, curbuf->b_ml.ml_line_count); + int max_vtopline = curr_vtopline + curwin->w_topfill + + plines_m_win_fill(curwin, curwin->w_topline + 1, + curbuf->b_ml.ml_line_count); + + int new_vtopline = MAX(MIN((linenr_T)curwin->w_scbind_pos, max_vtopline), 1); + + int y = new_vtopline - curr_vtopline; if (y > 0) { scrollup(curwin, y, false); } else { @@ -2515,9 +2521,7 @@ bool nv_screengo(oparg_T *oap, int dir, int dist) } else { n = width1; } - if (curwin->w_curswant >= n) { - curwin->w_curswant = n - 1; - } + curwin->w_curswant = MIN(curwin->w_curswant, n - 1); } while (dist--) { @@ -2776,11 +2780,7 @@ static void nv_zet(cmdarg_T *cap) if (cap->count0 == 0) { // No count given: put cursor at the line below screen validate_botline(curwin); // make sure w_botline is valid - if (curwin->w_botline > curbuf->b_ml.ml_line_count) { - curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - } else { - curwin->w_cursor.lnum = curwin->w_botline; - } + curwin->w_cursor.lnum = MIN(curwin->w_botline, curbuf->b_ml.ml_line_count); } FALLTHROUGH; case NL: @@ -3049,9 +3049,7 @@ static void nv_zet(cmdarg_T *cap) case 'm': if (curwin->w_p_fdl > 0) { curwin->w_p_fdl -= cap->count1; - if (curwin->w_p_fdl < 0) { - curwin->w_p_fdl = 0; - } + curwin->w_p_fdl = MAX(curwin->w_p_fdl, 0); } old_fdl = -1; // force an update curwin->w_p_fen = true; @@ -3069,9 +3067,7 @@ static void nv_zet(cmdarg_T *cap) curwin->w_p_fdl += cap->count1; { int d = getDeepestNesting(curwin); - if (curwin->w_p_fdl >= d) { - curwin->w_p_fdl = d; - } + curwin->w_p_fdl = MIN(curwin->w_p_fdl, d); } break; @@ -3662,10 +3658,7 @@ static void nv_scroll(cmdarg_T *cap) n = lnum - curwin->w_topline; } } - curwin->w_cursor.lnum = curwin->w_topline + n; - if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { - curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - } + curwin->w_cursor.lnum = MIN(curwin->w_topline + n, curbuf->b_ml.ml_line_count); } // Correct for 'so', except when an operator is pending. @@ -3972,6 +3965,12 @@ static void nv_next(cmdarg_T *cap) normal_search(cap, 0, NULL, 0, SEARCH_MARK | cap->arg, NULL); cap->count1 -= 1; } + + // Redraw the window to refresh the highlighted matches. + if (i > 0 && p_hls && !no_hlsearch + && win_hl_attr(curwin, HLF_LC) != win_hl_attr(curwin, HLF_L)) { + redraw_later(curwin, UPD_SOME_VALID); + } } /// Search for "pat" in direction "dir" ('/' or '?', 0 for repeat). @@ -3983,6 +3982,7 @@ static void nv_next(cmdarg_T *cap) static int normal_search(cmdarg_T *cap, int dir, char *pat, size_t patlen, int opt, int *wrapped) { searchit_arg_T sia; + pos_T const prev_cursor = curwin->w_cursor; cap->oap->motion_type = kMTCharWise; cap->oap->inclusive = false; @@ -4006,6 +4006,11 @@ static int normal_search(cmdarg_T *cap, int dir, char *pat, size_t patlen, int o foldOpenCursor(); } } + // Redraw the window to refresh the highlighted matches. + if (!equalpos(curwin->w_cursor, prev_cursor) && p_hls && !no_hlsearch + && win_hl_attr(curwin, HLF_LC) != win_hl_attr(curwin, HLF_L)) { + redraw_later(curwin, UPD_SOME_VALID); + } // "/$" will put the cursor after the end of the line, may need to // correct that here @@ -4332,12 +4337,8 @@ static void nv_percent(cmdarg_T *cap) curwin->w_cursor.lnum = (curbuf->b_ml.ml_line_count * cap->count0 + 99) / 100; } - if (curwin->w_cursor.lnum < 1) { - curwin->w_cursor.lnum = 1; - } - if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { - curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - } + curwin->w_cursor.lnum = MIN(MAX(curwin->w_cursor.lnum, 1), curbuf->b_ml.ml_line_count); + beginline(BL_SOL | BL_FIX); } } else { // "%" : go to matching paren @@ -5634,6 +5635,7 @@ static void nv_g_cmd(cmdarg_T *cap) // "go": goto byte count from start of buffer case 'o': + oap->inclusive = false; goto_byte(cap->count0); break; @@ -6076,11 +6078,7 @@ static void nv_goto(cmdarg_T *cap) if (cap->count0 != 0) { lnum = cap->count0; } - if (lnum < 1) { - lnum = 1; - } else if (lnum > curbuf->b_ml.ml_line_count) { - lnum = curbuf->b_ml.ml_line_count; - } + lnum = MIN(MAX(lnum, 1), curbuf->b_ml.ml_line_count); curwin->w_cursor.lnum = lnum; beginline(BL_SOL | BL_FIX); if ((fdo_flags & FDO_JUMP) && KeyTyped && cap->oap->op_type == OP_NOP) { @@ -6410,9 +6408,8 @@ static void nv_join(cmdarg_T *cap) return; } - if (cap->count0 <= 1) { - cap->count0 = 2; // default for join is two lines! - } + cap->count0 = MAX(cap->count0, 2); // default for join is two lines! + if (curwin->w_cursor.lnum + cap->count0 - 1 > curbuf->b_ml.ml_line_count) { // can't join when on the last line @@ -6597,15 +6594,21 @@ static void nv_open(cmdarg_T *cap) } } +/// Handles K_PASTE_START, repeats pasted text. +static void nv_paste(cmdarg_T *cap) +{ + paste_repeat(cap->count1); +} + /// Handle an arbitrary event in normal mode static void nv_event(cmdarg_T *cap) { // Garbage collection should have been executed before blocking for events in - // the `os_inchar` in `state_enter`, but we also disable it here in case the - // `os_inchar` branch was not executed (!multiqueue_empty(loop.events), which + // the `input_get` in `state_enter`, but we also disable it here in case the + // `input_get` branch was not executed (!multiqueue_empty(loop.events), which // could have `may_garbage_collect` set to true in `normal_check`). // - // That is because here we may run code that calls `os_inchar` + // That is because here we may run code that calls `input_get` // later(`f_confirm` or `get_keystroke` for example), but in these cases it is // not safe to perform garbage collection because there could be unreferenced // lists or dicts being used. diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 6233e446e0..4b8382c971 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -24,6 +24,7 @@ #include "nvim/cursor.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" @@ -31,6 +32,7 @@ #include "nvim/ex_cmds_defs.h" #include "nvim/ex_getln.h" #include "nvim/extmark.h" +#include "nvim/file_search.h" #include "nvim/fold.h" #include "nvim/garray.h" #include "nvim/garray_defs.h" @@ -262,12 +264,7 @@ void op_shift(oparg_T *oap, bool curs_top, int amount) foldOpenCursor(); if (oap->line_count > p_report) { - char *op; - if (oap->op_type == OP_RSHIFT) { - op = ">"; - } else { - op = "<"; - } + char *op = oap->op_type == OP_RSHIFT ? ">" : "<"; char *msg_line_single = NGETTEXT("%" PRId64 " line %sed %d time", "%" PRId64 " line %sed %d times", amount); @@ -298,8 +295,10 @@ void op_shift(oparg_T *oap, bool curs_top, int amount) /// @param call_changed_bytes call changed_bytes() void shift_line(bool left, bool round, int amount, int call_changed_bytes) { - const int sw_val = get_sw_value_indent(curbuf); - + int sw_val = get_sw_value_indent(curbuf, left); + if (sw_val == 0) { + sw_val = 1; // shouldn't happen, just in case + } int count = get_indent(); // get current indent if (round) { // round off indent @@ -309,20 +308,14 @@ void shift_line(bool left, bool round, int amount, int call_changed_bytes) amount--; } if (left) { - i -= amount; - if (i < 0) { - i = 0; - } + i = MAX(i - amount, 0); } else { i += amount; } count = i * sw_val; } else { // original vi indent if (left) { - count -= sw_val * amount; - if (count < 0) { - count = 0; - } + count = MAX(count - sw_val * amount, 0); } else { count += sw_val * amount; } @@ -330,7 +323,7 @@ void shift_line(bool left, bool round, int amount, int call_changed_bytes) // Set new indent if (State & VREPLACE_FLAG) { - change_indent(INDENT_SET, count, false, NUL, call_changed_bytes); + change_indent(INDENT_SET, count, false, call_changed_bytes); } else { set_indent(count, call_changed_bytes ? SIN_CHANGED : 0); } @@ -344,7 +337,7 @@ static void shift_block(oparg_T *oap, int amount) const int oldstate = State; char *newp; const int oldcol = curwin->w_cursor.col; - const int sw_val = get_sw_value_indent(curbuf); + const int sw_val = get_sw_value_indent(curbuf, left); const int ts_val = (int)curbuf->b_p_ts; struct block_def bd; int incr; @@ -459,9 +452,7 @@ static void shift_block(oparg_T *oap, int amount) const colnr_T block_space_width = non_white_col - oap->start_vcol; // We will shift by "total" or "block_space_width", whichever is less. - const colnr_T shift_amount = block_space_width < total - ? block_space_width - : total; + const colnr_T shift_amount = MIN(block_space_width, total); // The column to which we will shift the text. const colnr_T destination_col = non_white_col - shift_amount; @@ -575,9 +566,7 @@ static void block_insert(oparg_T *oap, const char *s, size_t slen, bool b_insert // avoid copying part of a multi-byte character offset -= utf_head_off(oldp, oldp + offset); } - if (spaces < 0) { // can happen when the cursor was moved - spaces = 0; - } + spaces = MAX(spaces, 0); // can happen when the cursor was moved assert(count >= 0); // Make sure the allocated size matches what is actually copied below. @@ -763,7 +752,7 @@ char *get_expr_line(void) } nested++; - char *rv = eval_to_string(expr_copy, true); + char *rv = eval_to_string(expr_copy, true, false); nested--; xfree(expr_copy); return rv; @@ -906,7 +895,7 @@ static void typval_to_yankreg(yankreg_T* yankreg, typval_T* val) if (tv_dict_get_tv(dict, "additional_data", &tv) == OK) { if (tv.v_type == VAR_DICT) { - yankreg->additional_data = tv.vval.v_dict; + yankreg->additional_data = NULL; // tv.vval.v_dict; } } break; @@ -1125,16 +1114,6 @@ int do_record(int c) return retval; } -static void set_yreg_additional_data(yankreg_T *reg, dict_T *additional_data) - FUNC_ATTR_NONNULL_ARG(1) -{ - if (reg->additional_data == additional_data) { - return; - } - tv_dict_unref(reg->additional_data); - reg->additional_data = additional_data; -} - /// Stuff string "p" into yank register "regname" as a single line (append if /// uppercase). "p" must have been allocated. /// @@ -1164,7 +1143,7 @@ static int stuff_yank(int regname, char *p) *pp = lp; } else { free_register(reg); - set_yreg_additional_data(reg, NULL); + reg->additional_data = NULL; reg->y_array = xmalloc(sizeof(char *)); reg->y_array[0] = p; reg->y_size = 1; @@ -1506,9 +1485,9 @@ static dict_T* yankreg_to_dict(yankreg_T* yankreg) { } tv_dict_add_str(dict, S_LEN("type"), type); - if (yankreg->additional_data) { - tv_dict_add_dict(dict, S_LEN("additional_data"), yankreg->additional_data); - } + // if (yankreg->additional_data) { + // tv_dict_add_dict(dict, S_LEN("additional_data"), yankreg->additional_data); + // } list_T *const lines = tv_list_alloc((long)yankreg->y_size); @@ -2418,18 +2397,6 @@ bool swapchar(int op_type, pos_T *pos) return false; } - // ~ is OP_NOP, g~ is OP_TILDE, gU is OP_UPPER - if ((op_type == OP_UPPER || op_type == OP_NOP || op_type == OP_TILDE) && c == 0xdf) { - pos_T sp = curwin->w_cursor; - - // Special handling for lowercase German sharp s (ß): convert to uppercase (ẞ). - curwin->w_cursor = *pos; - del_char(false); - ins_char(0x1E9E); - curwin->w_cursor = sp; - return true; - } - int nc = c; if (mb_islower(c)) { if (op_type == OP_ROT13) { @@ -2651,9 +2618,7 @@ void op_insert(oparg_T *oap, int count1) } } } - if (add > len) { - add = len; // short line, point to the NUL - } + add = MIN(add, len); // short line, point to the NUL firstline += add; len -= add; int ins_len = len - pre_textlen - offset; @@ -2815,7 +2780,7 @@ void clear_registers(void) void free_register(yankreg_T *reg) FUNC_ATTR_NONNULL_ALL { - set_yreg_additional_data(reg, NULL); + XFREE_CLEAR(reg->additional_data); if (reg->y_array == NULL) { return; } @@ -2953,7 +2918,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) char *pnew = xmalloc(strlen(curr->y_array[curr->y_size - 1]) + strlen(reg->y_array[0]) + 1); STRCPY(pnew, curr->y_array[--j]); - STRCAT(pnew, reg->y_array[0]); + strcat(pnew, reg->y_array[0]); xfree(curr->y_array[j]); xfree(reg->y_array[0]); curr->y_array[j++] = pnew; @@ -3111,13 +3076,13 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg) /// /// @param oap Operator arguments. /// @param reg The yank register used. -static void do_autocmd_textputpost(int regname, yankreg_T *reg) +static void do_autocmd_textput(int regname, yankreg_T *reg, enum auto_event evt) FUNC_ATTR_NONNULL_ALL { static bool recursive = false; int len; - if (recursive || !has_event(EVENT_TEXTPUTPOST)) { + if (recursive || !has_event(evt)) { // No autocommand was defined, or we yanked from this autocommand. return; } @@ -3142,7 +3107,7 @@ static void do_autocmd_textputpost(int regname, yankreg_T *reg) (void)tv_dict_add_str(dict, S_LEN("regtype"), buf); // Name of requested register, or empty string for unnamed operation. - len = (*utf_char2len)(regname); + len = utf_char2len(regname); buf[len] = 0; utf_char2bytes(regname, buf); recursive = true; @@ -3150,7 +3115,7 @@ static void do_autocmd_textputpost(int regname, yankreg_T *reg) tv_dict_set_keys_readonly(dict); textlock++; - apply_autocmds(EVENT_TEXTPUTPOST, NULL, NULL, false, curbuf); + apply_autocmds(evt, NULL, NULL, false, curbuf); textlock--; restore_v_event(dict, &save_v_event); @@ -3188,6 +3153,10 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) const pos_T orig_end = curbuf->b_op_end; unsigned cur_ve_flags = get_ve_flags(curwin); + if (reg) { + do_autocmd_textput(regname, reg, EVENT_TEXTPUTPRE); + } + if (flags & PUT_FIXINDENT) { orig_indent = get_indent(); } @@ -3400,9 +3369,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) if (y_type == kMTBlockWise) { lnum = curwin->w_cursor.lnum + (linenr_T)y_size + 1; - if (lnum > curbuf->b_ml.ml_line_count) { - lnum = curbuf->b_ml.ml_line_count + 1; - } + lnum = MIN(lnum, curbuf->b_ml.ml_line_count + 1); if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL) { goto end; } @@ -3563,9 +3530,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) spaces -= win_charsize(cstype, 0, ci.ptr, ci.chr.value, &csarg).width; ci = utfc_next(ci); } - if (spaces < 0) { - spaces = 0; - } + spaces = MAX(spaces, 0); } // Insert the new text. @@ -3630,10 +3595,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) // adjust '] mark curbuf->b_op_end.lnum = curwin->w_cursor.lnum - 1; - curbuf->b_op_end.col = bd.textcol + (colnr_T)totlen - 1; - if (curbuf->b_op_end.col < 0) { - curbuf->b_op_end.col = 0; - } + curbuf->b_op_end.col = MAX(bd.textcol + (colnr_T)totlen - 1, 0); curbuf->b_op_end.coladd = 0; if (flags & PUT_CURSEND) { curwin->w_cursor = curbuf->b_op_end; @@ -3641,9 +3603,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) // in Insert mode we might be after the NUL, correct for that colnr_T len = get_cursor_line_len(); - if (curwin->w_cursor.col > len) { - curwin->w_cursor.col = len; - } + curwin->w_cursor.col = MIN(curwin->w_cursor.col, len); } else { curwin->w_cursor.lnum = lnum; } @@ -3676,10 +3636,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) int first_byte_off = 0; if (VIsual_active) { - end_lnum = curbuf->b_visual.vi_end.lnum; - if (end_lnum < curbuf->b_visual.vi_start.lnum) { - end_lnum = curbuf->b_visual.vi_start.lnum; - } + end_lnum = MAX(curbuf->b_visual.vi_end.lnum, curbuf->b_visual.vi_start.lnum); if (end_lnum > start_lnum) { // "col" is valid for the first line, in following lines // the virtual column needs to be used. Matters for @@ -3778,7 +3735,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) totlen = strlen(y_array[y_size - 1]); char *newp = xmalloc((size_t)ml_get_len(lnum) - (size_t)col + totlen + 1); STRCPY(newp, y_array[y_size - 1]); - STRCAT(newp, ptr); + strcat(newp, ptr); // insert second line ml_append(lnum, newp, 0, false); new_lnum++; @@ -3943,7 +3900,7 @@ error: end: if (reg) { - do_autocmd_textputpost(regname, reg); + do_autocmd_textput(regname, reg, EVENT_TEXTPUTPOST); } if (cmdmod.cmod_flags & CMOD_LOCKMARKS) { @@ -4622,10 +4579,7 @@ void charwise_block_prep(pos_T start, pos_T end, struct block_def *bdp, linenr_T if (ce != cs && start.coladd > 0) { // Part of a tab selected -- but don't double-count it. bdp->start_char_vcols = ce - cs + 1; - bdp->startspaces = bdp->start_char_vcols - start.coladd; - if (bdp->startspaces < 0) { - bdp->startspaces = 0; - } + bdp->startspaces = MAX(bdp->start_char_vcols - start.coladd, 0); startcol++; } } @@ -4725,9 +4679,7 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd) } if (pos.lnum == oap->end.lnum) { length = ml_get_len(oap->end.lnum); - if (oap->end.col >= length) { - oap->end.col = length - 1; - } + oap->end.col = MIN(oap->end.col, length - 1); length = oap->end.col - pos.col + 1; } } @@ -4783,6 +4735,7 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) int pre; // 'X' or 'x': hex; '0': octal; 'B' or 'b': bin static bool hexupper = false; // 0xABC uvarnumber_T n; + bool blank_unsigned = false; // blank: treat as unsigned? bool negative = false; bool was_positive = true; bool visual = VIsual_active; @@ -4793,12 +4746,12 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) pos_T endpos; colnr_T save_coladd = 0; - const bool do_hex = vim_strchr(curbuf->b_p_nf, 'x') != NULL; // "heX" - const bool do_oct = vim_strchr(curbuf->b_p_nf, 'o') != NULL; // "Octal" - const bool do_bin = vim_strchr(curbuf->b_p_nf, 'b') != NULL; // "Bin" - const bool do_alpha = vim_strchr(curbuf->b_p_nf, 'p') != NULL; // "alPha" - // "Unsigned" - const bool do_unsigned = vim_strchr(curbuf->b_p_nf, 'u') != NULL; + const bool do_hex = vim_strchr(curbuf->b_p_nf, 'x') != NULL; // "heX" + const bool do_oct = vim_strchr(curbuf->b_p_nf, 'o') != NULL; // "Octal" + const bool do_bin = vim_strchr(curbuf->b_p_nf, 'b') != NULL; // "Bin" + const bool do_alpha = vim_strchr(curbuf->b_p_nf, 'p') != NULL; // "alPha" + const bool do_unsigned = vim_strchr(curbuf->b_p_nf, 'u') != NULL; // "Unsigned" + const bool do_blank = vim_strchr(curbuf->b_p_nf, 'k') != NULL; // "blanK" if (virtual_active(curwin)) { save_coladd = pos->coladd; @@ -4895,8 +4848,12 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) if (col > pos->col && ptr[col - 1] == '-' && !utf_head_off(ptr, ptr + col - 1) && !do_unsigned) { - negative = true; - was_positive = false; + if (do_blank && col >= 2 && !ascii_iswhite(ptr[col - 2])) { + blank_unsigned = true; + } else { + negative = true; + was_positive = false; + } } } @@ -4911,21 +4868,13 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) // decrement or increment alphabetic character if (op_type == OP_NR_SUB) { if (CHAR_ORD(firstdigit) < Prenum1) { - if (isupper(firstdigit)) { - firstdigit = 'A'; - } else { - firstdigit = 'a'; - } + firstdigit = isupper(firstdigit) ? 'A' : 'a'; } else { firstdigit -= (int)Prenum1; } } else { if (26 - CHAR_ORD(firstdigit) - 1 < Prenum1) { - if (isupper(firstdigit)) { - firstdigit = 'Z'; - } else { - firstdigit = 'z'; - } + firstdigit = isupper(firstdigit) ? 'Z' : 'z'; } else { firstdigit += (int)Prenum1; } @@ -4942,9 +4891,13 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) && !utf_head_off(ptr, ptr + col - 1) && !visual && !do_unsigned) { - // negative number - col--; - negative = true; + if (do_blank && col >= 2 && !ascii_iswhite(ptr[col - 2])) { + blank_unsigned = true; + } else { + // negative number + col--; + negative = true; + } } // get the number value (unsigned) @@ -5001,7 +4954,7 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) } } - if (do_unsigned && negative) { + if ((do_unsigned || blank_unsigned) && negative) { if (subtract) { // sticking at zero. n = 0; @@ -5032,11 +4985,7 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) } while (todel-- > 0) { if (c < 0x100 && isalpha(c)) { - if (isupper(c)) { - hexupper = true; - } else { - hexupper = false; - } + hexupper = isupper(c); } // del_char() will mark line needing displaying del_char(false); @@ -5076,7 +5025,7 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) buf2[i++] = ((n >> --bits) & 0x1) ? '1' : '0'; } - buf2[i] = '\0'; + buf2[i] = NUL; } else if (pre == 0) { vim_snprintf(buf2, ARRAY_SIZE(buf2), "%" PRIu64, (uint64_t)n); } else if (pre == '0') { @@ -5098,7 +5047,7 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) } } *ptr = NUL; - STRCAT(buf1, buf2); + strcat(buf1, buf2); ins_str(buf1); // insert the new number endpos = curwin->w_cursor; if (curwin->w_cursor.col) { @@ -5516,9 +5465,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char *str, for (char **ss = (char **)str; *ss != NULL; ss++, lnum++) { size_t ss_len = strlen(*ss); pp[lnum] = xmemdupz(*ss, ss_len); - if (ss_len > maxlen) { - maxlen = ss_len; - } + maxlen = MAX(maxlen, ss_len); } } else { size_t line_len; @@ -5527,9 +5474,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char *str, start += line_len + 1, lnum++) { assert(end - start >= 0); line_len = (size_t)((char *)xmemscan(start, '\n', (size_t)(end - start)) - start); - if (line_len > maxlen) { - maxlen = line_len; - } + maxlen = MAX(maxlen, line_len); // When appending, copy the previous line and free it after. size_t extra = append ? strlen(pp[--lnum]) : 0; @@ -5552,7 +5497,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char *str, } y_ptr->y_type = yank_type; y_ptr->y_size = lnum; - set_yreg_additional_data(y_ptr, NULL); + XFREE_CLEAR(y_ptr->additional_data); y_ptr->timestamp = os_time(); if (yank_type == kMTBlockWise) { y_ptr->y_width = (blocklen == -1 ? (colnr_T)maxlen - 1 : blocklen); @@ -6019,9 +5964,7 @@ static void get_op_vcol(oparg_T *oap, colnr_T redo_VIsual_vcol, bool initial) if (!redo_VIsual_busy) { getvvcol(curwin, &(oap->end), &start, NULL, &end); - if (start < oap->start_vcol) { - oap->start_vcol = start; - } + oap->start_vcol = MIN(oap->start_vcol, start); if (end > oap->end_vcol) { if (initial && *p_sel == 'e' && start >= 1 @@ -6040,9 +5983,7 @@ static void get_op_vcol(oparg_T *oap, colnr_T redo_VIsual_vcol, bool initial) for (curwin->w_cursor.lnum = oap->start.lnum; curwin->w_cursor.lnum <= oap->end.lnum; curwin->w_cursor.lnum++) { getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &end); - if (end > oap->end_vcol) { - oap->end_vcol = end; - } + oap->end_vcol = MAX(oap->end_vcol, end); } } else if (redo_VIsual_busy) { oap->end_vcol = oap->start_vcol + redo_VIsual_vcol - 1; @@ -6176,9 +6117,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) // redo_VIsual.rv_line_count and redo_VIsual.rv_vcol. oap->start = curwin->w_cursor; curwin->w_cursor.lnum += redo_VIsual.rv_line_count - 1; - if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { - curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - } + curwin->w_cursor.lnum = MIN(curwin->w_cursor.lnum, curbuf->b_ml.ml_line_count); VIsual_mode = redo_VIsual.rv_mode; if (redo_VIsual.rv_vcol == MAXCOL || VIsual_mode == 'v') { if (VIsual_mode == 'v') { @@ -6466,9 +6405,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) case OP_JOIN_NS: case OP_JOIN: - if (oap->line_count < 2) { - oap->line_count = 2; - } + oap->line_count = MAX(oap->line_count, 2); if (curwin->w_cursor.lnum + oap->line_count - 1 > curbuf->b_ml.ml_line_count) { beep_flush(); @@ -6867,9 +6804,7 @@ void finish_yankreg_from_object(yankreg_T *reg, bool clipboard_adjust) size_t maxlen = 0; for (size_t i = 0; i < reg->y_size; i++) { size_t rowlen = strlen(reg->y_array[i]); - if (rowlen > maxlen) { - maxlen = rowlen; - } + maxlen = MAX(maxlen, rowlen); } assert(maxlen <= INT_MAX); reg->y_width = MAX(reg->y_width, (int)maxlen - 1); @@ -6973,9 +6908,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet) size_t maxlen = 0; for (size_t i = 0; i < reg->y_size; i++) { size_t rowlen = strlen(reg->y_array[i]); - if (rowlen > maxlen) { - maxlen = rowlen; - } + maxlen = MAX(maxlen, rowlen); } assert(maxlen <= INT_MAX); reg->y_width = (int)maxlen - 1; diff --git a/src/nvim/ops.h b/src/nvim/ops.h index 643d2a2deb..3cca52572f 100644 --- a/src/nvim/ops.h +++ b/src/nvim/ops.h @@ -7,7 +7,6 @@ #include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds_defs.h" // IWYU pragma: keep #include "nvim/extmark_defs.h" // IWYU pragma: keep -#include "nvim/func_attr.h" #include "nvim/macros_defs.h" #include "nvim/normal_defs.h" #include "nvim/option_defs.h" // IWYU pragma: keep @@ -99,6 +98,10 @@ enum { OP_NR_SUB = 29, ///< "<C-X>" Subtract from the number or alphabetic character }; +struct yank_registers; +typedef struct yank_registers yank_registers_T; +typedef size_t iter_register_T; + /// Flags for get_reg_contents(). enum GRegFlags { kGRegNoExpr = 1, ///< Do not allow expression register. @@ -113,7 +116,7 @@ typedef struct { MotionType y_type; ///< Register type colnr_T y_width; ///< Register width (only valid for y_type == kBlockWise). Timestamp timestamp; ///< Time when register was last modified. - dict_T *additional_data; ///< Additional data from ShaDa file. + AdditionalData *additional_data; ///< Additional data from ShaDa file. } yankreg_T; /// Modes for get_yank_register() @@ -125,8 +128,10 @@ typedef enum { /// Returns a reference to a user-defined register. int get_userreg(int regname); -static inline int op_reg_index(int regname) - REAL_FATTR_CONST; +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "ops.h.generated.h" +# include "ops.h.inline.generated.h" +#endif /// Convert register name into register index /// @@ -134,6 +139,7 @@ static inline int op_reg_index(int regname) /// /// @return Index in y_regs array or -1 if register name was not recognized. static inline int op_reg_index(const int regname) + FUNC_ATTR_CONST { if (ascii_isdigit(regname)) { return regname - '0'; @@ -152,23 +158,13 @@ static inline int op_reg_index(const int regname) } } -struct yank_registers; -typedef struct yank_registers yank_registers_T; - -typedef size_t iter_register_T; - -static inline bool is_literal_register(int regname) - REAL_FATTR_CONST; /// @see get_yank_register /// @return true when register should be inserted literally /// (selection or clipboard) static inline bool is_literal_register(const int regname) + FUNC_ATTR_CONST { return regname == '*' || regname == '+'; } -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "ops.h.generated.h" -#endif - EXTERN LuaRef repeat_luaref INIT( = LUA_NOREF); ///< LuaRef for "." diff --git a/src/nvim/option.c b/src/nvim/option.c index 22897d4f7e..ff0c0e2acf 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -44,6 +44,7 @@ #include "nvim/decoration_provider.h" #include "nvim/diff.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/vars.h" @@ -87,6 +88,7 @@ #include "nvim/os/os.h" #include "nvim/os/os_defs.h" #include "nvim/path.h" +#include "nvim/plines.h" #include "nvim/popupmenu.h" #include "nvim/pos_defs.h" #include "nvim/regexp.h" @@ -208,39 +210,53 @@ static void set_init_default_backupskip(void) OptIndex opt_idx = kOptBackupskip; ga_init(&ga, 1, 100); - for (size_t n = 0; n < ARRAY_SIZE(names); n++) { + for (size_t i = 0; i < ARRAY_SIZE(names); i++) { bool mustfree = true; char *p; + size_t plen; #ifdef UNIX - if (*names[n] == NUL) { + if (*names[i] == NUL) { # ifdef __APPLE__ p = "/private/tmp"; + plen = STRLEN_LITERAL("/private/tmp"); # else p = "/tmp"; + plen = STRLEN_LITERAL("/tmp"); # endif mustfree = false; } else #endif { - p = vim_getenv(names[n]); + p = vim_getenv(names[i]); + plen = 0; // will be calcuated below } 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, ","); + bool has_trailing_path_sep = false; + + if (plen == 0) { + // the value was retrieved from the environment + plen = strlen(p); + // does the value include a trailing path separator? + if (after_pathsep(p, p + plen)) { + has_trailing_path_sep = true; } - STRCAT(ga.ga_data, p); - add_pathsep(ga.ga_data); - STRCAT(ga.ga_data, "*"); - ga.ga_len += (int)len; + } + + // item size needs to be large enough to include "/*" and a trailing NUL + // note: the value (and therefore plen) may already include a path separator + size_t itemsize = plen + (has_trailing_path_sep ? 0 : 1) + 2; + char *item = xmalloc(itemsize); + // add a preceding comma as a separator after the first item + size_t itemseplen = (ga.ga_len == 0) ? 0 : 1; + + size_t itemlen = (size_t)vim_snprintf(item, itemsize, "%s%s*", p, + has_trailing_path_sep ? "" : PATHSEPSTR); + + if (find_dup_item(ga.ga_data, item, itemlen, options[opt_idx].flags) == NULL) { + ga_grow(&ga, (int)(itemseplen + itemlen + 1)); + ga.ga_len += vim_snprintf((char *)ga.ga_data + ga.ga_len, + itemseplen + itemlen + 1, + "%s%s", (itemseplen > 0) ? "," : "", item); } xfree(item); } @@ -524,7 +540,8 @@ static void set_string_default(OptIndex opt_idx, char *val, bool allocated) /// For an option value that contains comma separated items, find "newval" in /// "origval". Return NULL if not found. -static char *find_dup_item(char *origval, const char *newval, uint32_t flags) +static char *find_dup_item(char *origval, const char *newval, const size_t newvallen, + uint32_t flags) FUNC_ATTR_NONNULL_ARG(2) { if (origval == NULL) { @@ -533,11 +550,10 @@ static char *find_dup_item(char *origval, const char *newval, uint32_t flags) int bs = 0; - const size_t newlen = strlen(newval); for (char *s = origval; *s != NUL; s++) { if ((!(flags & P_COMMA) || s == origval || (s[-1] == ',' && !(bs & 1))) - && strncmp(s, newval, newlen) == 0 - && (!(flags & P_COMMA) || s[newlen] == ',' || s[newlen] == NUL)) { + && strncmp(s, newval, newvallen) == 0 + && (!(flags & P_COMMA) || s[newvallen] == ',' || s[newvallen] == NUL)) { return s; } // Count backslashes. Only a comma with an even number of backslashes @@ -695,10 +711,10 @@ void set_helplang_default(const char *lang) } p_hlg = xmemdupz(lang, lang_len); // zh_CN becomes "cn", zh_TW becomes "tw". - if (STRNICMP(p_hlg, "zh_", 3) == 0 && strlen(p_hlg) >= 5) { + if (STRNICMP(p_hlg, "zh_", 3) == 0 && lang_len >= 5) { p_hlg[0] = (char)TOLOWER_ASC(p_hlg[3]); p_hlg[1] = (char)TOLOWER_ASC(p_hlg[4]); - } else if (strlen(p_hlg) >= 1 && *p_hlg == 'C') { + } else if (lang_len && *p_hlg == 'C') { // any C like setting, such as C.UTF-8, becomes "en" p_hlg[0] = 'e'; p_hlg[1] = 'n'; @@ -948,7 +964,7 @@ static char *stropt_get_newval(int nextchar, OptIndex opt_idx, char **argp, void int len = 0; if (op == OP_REMOVING || (flags & P_NODUP)) { len = (int)strlen(newval); - s = find_dup_item(origval, newval, flags); + s = find_dup_item(origval, newval, (size_t)len, flags); // do not add if already there if ((op == OP_ADDING || op == OP_PREPENDING) && s != NULL) { @@ -1200,8 +1216,9 @@ static OptVal get_option_newval(OptIndex opt_idx, int opt_flags, set_prefix_T pr // Different ways to set a number option: // & set to default value // < set to global value - // <xx> accept special key codes for 'wildchar' - // c accept any non-digit for 'wildchar' + // <xx> accept special key codes for 'wildchar' or 'wildcharm' + // ^x accept ctrl key codes for 'wildchar' or 'wildcharm' + // c accept any non-digit for 'wildchar' or 'wildcharm' // [-]0-9 set number // other error arg++; @@ -1223,7 +1240,7 @@ static OptVal get_option_newval(OptIndex opt_idx, int opt_flags, set_prefix_T pr || (*arg != NUL && (!arg[1] || ascii_iswhite(arg[1])) && !ascii_isdigit(*arg)))) { newval_num = string_to_key(arg); - if (newval_num == 0 && (OptInt *)varp != &p_wcm) { + if (newval_num == 0) { *errmsg = e_invarg; return newval; } @@ -1462,11 +1479,10 @@ int do_set(char *arg, int opt_flags) } if (errmsg != NULL) { - xstrlcpy(IObuff, _(errmsg), IOSIZE); - int i = (int)strlen(IObuff) + 2; + int i = vim_snprintf((char *)IObuff, IOSIZE, "%s", _(errmsg)) + 2; if (i + (arg - startarg) < IOSIZE) { // append the argument with the error - xstrlcat(IObuff, ": ", IOSIZE); + xstrlcpy(IObuff + i - 2, ": ", (size_t)(IOSIZE - i + 2)); assert(arg >= startarg); memmove(IObuff + i, startarg, (size_t)(arg - startarg)); IObuff[i + (arg - startarg)] = NUL; @@ -1509,7 +1525,9 @@ static int find_key_len(const char *arg_arg, size_t len, bool has_lt) // Don't use get_special_key_code() for t_xx, we don't want it to call // add_termcap_entry(). if (len >= 4 && arg[0] == 't' && arg[1] == '_') { - key = TERMCAP2KEY((uint8_t)arg[2], (uint8_t)arg[3]); + if (!has_lt || arg[4] == '>') { + key = TERMCAP2KEY((uint8_t)arg[2], (uint8_t)arg[3]); + } } else if (has_lt) { arg--; // put arg at the '<' int modifiers = 0; @@ -1523,14 +1541,18 @@ static int find_key_len(const char *arg_arg, size_t len, bool has_lt) } /// Convert a key name or string into a key value. -/// Used for 'wildchar' and 'cedit' options. +/// Used for 'cedit', 'wildchar' and 'wildcharm' options. int string_to_key(char *arg) { - if (*arg == '<') { + if (*arg == '<' && arg[1]) { return find_key_len(arg + 1, strlen(arg), true); } - if (*arg == '^') { - return CTRL_CHR((uint8_t)arg[1]); + if (*arg == '^' && arg[1]) { + int key = CTRL_CHR((uint8_t)arg[1]); + if (key == 0) { // ^@ is <Nul> + key = K_ZERO; + } + return key; } return (uint8_t)(*arg); } @@ -2473,7 +2495,7 @@ static const char *did_set_scrollbind(optset_T *args) return NULL; } do_check_scrollbind(false); - win->w_scbind_pos = win->w_topline; + win->w_scbind_pos = get_vtopline(win); return NULL; } @@ -4569,6 +4591,8 @@ void *get_varp_scope_from(vimoption_T *p, int scope, buf_T *buf, win_T *win) return &(buf->b_p_def); case PV_INC: return &(buf->b_p_inc); + case PV_COT: + return &(buf->b_p_cot); case PV_DICT: return &(buf->b_p_dict); case PV_TSR: @@ -4652,6 +4676,8 @@ void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win) return *buf->b_p_def != NUL ? &(buf->b_p_def) : p->var; case PV_INC: return *buf->b_p_inc != NUL ? &(buf->b_p_inc) : p->var; + case PV_COT: + return *buf->b_p_cot != NUL ? &(buf->b_p_cot) : p->var; case PV_DICT: return *buf->b_p_dict != NUL ? &(buf->b_p_dict) : p->var; case PV_TSR: @@ -5078,6 +5104,12 @@ void clear_winopt(winopt_T *wop) void didset_window_options(win_T *wp, bool valid_cursor) { + // Set w_leftcol or w_skipcol to zero. + if (wp->w_p_wrap) { + wp->w_leftcol = 0; + } else { + wp->w_skipcol = 0; + } check_colorcolumn(wp); briopt_check(wp); fill_culopt_flags(NULL, wp); @@ -5335,6 +5367,8 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_inc = empty_string_option; buf->b_p_inex = xstrdup(p_inex); COPY_OPT_SCTX(buf, BV_INEX); + buf->b_p_cot = empty_string_option; + buf->b_cot_flags = 0; buf->b_p_dict = empty_string_option; buf->b_p_tsr = empty_string_option; buf->b_p_tsrfu = empty_string_option; @@ -5427,7 +5461,8 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags) xp->xp_pattern = arg; return; } - char *p = arg + strlen(arg) - 1; + char *const argend = arg + strlen(arg); + char *p = argend - 1; if (*p == ' ' && *(p - 1) != '\\') { xp->xp_pattern = p + 1; return; @@ -5614,7 +5649,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags) // Triple-backslashed escaped file names (e.g. 'path') can also be // delimited by space. if ((flags & P_EXPAND) || (flags & P_COMMA) || (flags & P_COLON)) { - for (p = arg + strlen(arg) - 1; p > xp->xp_pattern; p--) { + for (p = argend - 1; p > xp->xp_pattern; p--) { // count number of backslashes before ' ' or ',' if (*p == ' ' || *p == ',' || (*p == ':' && (flags & P_COLON))) { char *s = p; @@ -5638,7 +5673,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags) // An option that is a list of single-character flags should always start // at the end as we don't complete words. if (flags & P_FLAGLIST) { - xp->xp_pattern = arg + strlen(arg); + xp->xp_pattern = argend; } // Some options can either be using file/dir expansions, or custom value @@ -5948,7 +5983,7 @@ int ExpandSettingSubtract(expand_T *xp, regmatch_T *regmatch, int *numMatches, c int count = 0; - (*matches)[count++] = xstrdup(option_val); + (*matches)[count++] = xmemdupz(option_val, num_flags); if (num_flags > 1) { // If more than one flags, split the flags up and expose each @@ -6189,10 +6224,10 @@ bool can_bs(int what) return vim_strchr(p_bs, what) != NULL; } -/// Get the local or global value of 'backupcopy'. +/// Get the local or global value of 'backupcopy' flags. /// /// @param buf The buffer. -unsigned get_bkc_value(buf_T *buf) +unsigned get_bkc_flags(buf_T *buf) { return buf->b_bkc_flags ? buf->b_bkc_flags : bkc_flags; } @@ -6208,7 +6243,7 @@ char *get_flp_value(buf_T *buf) return buf->b_p_flp; } -/// Get the local or global value of the 'virtualedit' flags. +/// Get the local or global value of 'virtualedit' flags. unsigned get_ve_flags(win_T *wp) { return (wp->w_ve_flags ? wp->w_ve_flags : ve_flags) & ~(VE_NONE | VE_NONEU); @@ -6420,30 +6455,29 @@ int get_sidescrolloff_value(win_T *wp) return (int)(wp->w_p_siso < 0 ? p_siso : wp->w_p_siso); } -Dictionary get_vimoption(String name, int scope, buf_T *buf, win_T *win, Arena *arena, Error *err) +Dict get_vimoption(String name, int scope, buf_T *buf, win_T *win, Arena *arena, Error *err) { OptIndex opt_idx = find_option_len(name.data, name.size); VALIDATE_S(opt_idx != kOptInvalid, "option (not found)", name.data, { - return (Dictionary)ARRAY_DICT_INIT; + return (Dict)ARRAY_DICT_INIT; }); return vimoption2dict(&options[opt_idx], scope, buf, win, arena); } -Dictionary get_all_vimoptions(Arena *arena) +Dict get_all_vimoptions(Arena *arena) { - Dictionary retval = arena_dict(arena, kOptIndexCount); + Dict retval = arena_dict(arena, kOptIndexCount); for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) { - Dictionary opt_dict = vimoption2dict(&options[opt_idx], OPT_GLOBAL, curbuf, curwin, arena); - PUT_C(retval, options[opt_idx].fullname, DICTIONARY_OBJ(opt_dict)); + Dict opt_dict = vimoption2dict(&options[opt_idx], OPT_GLOBAL, curbuf, curwin, arena); + PUT_C(retval, options[opt_idx].fullname, DICT_OBJ(opt_dict)); } return retval; } -static Dictionary vimoption2dict(vimoption_T *opt, int req_scope, buf_T *buf, win_T *win, - Arena *arena) +static Dict vimoption2dict(vimoption_T *opt, int req_scope, buf_T *buf, win_T *win, Arena *arena) { - Dictionary dict = arena_dict(arena, 13); + Dict dict = arena_dict(arena, 13); PUT_C(dict, "name", CSTR_AS_OBJ(opt->fullname)); PUT_C(dict, "shortname", CSTR_AS_OBJ(opt->shortname)); diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h index be78a708ad..6b78007253 100644 --- a/src/nvim/option_vars.h +++ b/src/nvim/option_vars.h @@ -55,13 +55,13 @@ #define HIGHLIGHT_INIT \ "8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText,d:Directory,e:ErrorMsg," \ "i:IncSearch,l:Search,y:CurSearch,m:MoreMsg,M:ModeMsg,n:LineNr,a:LineNrAbove,b:LineNrBelow," \ - "N:CursorLineNr,G:CursorLineSign,O:CursorLineFold" \ - "r:Question,s:StatusLine,S:StatusLineNC,c:VertSplit,t:Title,v:Visual,V:VisualNOS,w:WarningMsg," \ - "W:WildMenu,f:Folded,F:FoldColumn,A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,>:SignColumn," \ - "-:Conceal,B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel," \ - "[:PmenuKind,]:PmenuKindSel,{:PmenuExtra,}:PmenuExtraSel,x:PmenuSbar,X:PmenuThumb," \ - "*:TabLine,#:TabLineSel,_:TabLineFill,!:CursorColumn,.:CursorLine,o:ColorColumn," \ - "q:QuickFixLine,g:MsgArea,0:Whitespace,I:NormalNC" + "N:CursorLineNr,G:CursorLineSign,O:CursorLineFold,r:Question,s:StatusLine,S:StatusLineNC," \ + "c:VertSplit,t:Title,v:Visual,V:VisualNOS,w:WarningMsg,W:WildMenu,f:Folded,F:FoldColumn," \ + "A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,>:SignColumn,-:Conceal,B:SpellBad,P:SpellCap," \ + "R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel,k:PmenuMatch,<:PmenuMatchSel,[:PmenuKind," \ + "]:PmenuKindSel,{:PmenuExtra,}:PmenuExtraSel,x:PmenuSbar,X:PmenuThumb,*:TabLine,#:TabLineSel," \ + "_:TabLineFill,!:CursorColumn,.:CursorLine,o:ColorColumn,q:QuickFixLine,z:StatusLineTerm," \ + "Z:StatusLineTermNC,g:MsgArea,0:Whitespace,I:NormalNC" // Default values for 'errorformat'. // The "%f|%l| %m" one is used for when the contents of the quickfix window is @@ -429,7 +429,22 @@ EXTERN char *p_cms; ///< 'commentstring' EXTERN char *p_cpt; ///< 'complete' EXTERN OptInt p_columns; ///< 'columns' EXTERN int p_confirm; ///< 'confirm' +EXTERN char *p_cia; ///< 'completeitemalign' +EXTERN unsigned cia_flags; ///< order flags of 'completeitemalign' EXTERN char *p_cot; ///< 'completeopt' +EXTERN unsigned cot_flags; ///< flags from 'completeopt' +// Keep in sync with p_cot_values in optionstr.c +#define COT_MENU 0x001 +#define COT_MENUONE 0x002 +#define COT_ANY_MENU 0x003 // combination of menu flags +#define COT_LONGEST 0x004 // false: insert full match, + // true: insert longest prefix +#define COT_PREVIEW 0x008 +#define COT_POPUP 0x010 +#define COT_ANY_PREVIEW 0x018 // combination of preview flags +#define COT_NOINSERT 0x020 // false: select & insert, true: noinsert +#define COT_NOSELECT 0x040 // false: select & insert, true: noselect +#define COT_FUZZY 0x080 // true: fuzzy match enabled #ifdef BACKSLASH_IN_FILENAME EXTERN char *p_csl; ///< 'completeslash' #endif @@ -527,6 +542,7 @@ EXTERN char *p_jop; ///< 'jumpooptions' EXTERN unsigned jop_flags; #define JOP_STACK 0x01 #define JOP_VIEW 0x02 +#define JOP_CLEAN 0x04 EXTERN char *p_keymap; ///< 'keymap' EXTERN char *p_kp; ///< 'keywordprg' EXTERN char *p_km; ///< 'keymodel' @@ -680,7 +696,6 @@ EXTERN unsigned tpf_flags; ///< flags from 'termpastefilter' EXTERN char *p_tfu; ///< 'tagfunc' EXTERN char *p_spc; ///< 'spellcapcheck' EXTERN char *p_spf; ///< 'spellfile' -EXTERN char *p_spk; ///< 'splitkeep' EXTERN char *p_spl; ///< 'spelllang' EXTERN char *p_spo; ///< 'spelloptions' EXTERN unsigned spo_flags; @@ -697,7 +712,12 @@ EXTERN unsigned swb_flags; #define SWB_NEWTAB 0x008 #define SWB_VSPLIT 0x010 #define SWB_USELAST 0x020 +EXTERN char *p_spk; ///< 'splitkeep' EXTERN char *p_syn; ///< 'syntax' +EXTERN char *p_tcl; ///< 'tabclose' +EXTERN unsigned tcl_flags; ///< flags from 'tabclose' +#define TCL_LEFT 0x001 +#define TCL_USELAST 0x002 EXTERN OptInt p_ts; ///< 'tabstop' EXTERN int p_tbs; ///< 'tagbsearch' EXTERN char *p_tc; ///< 'tagcase' diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 5173240384..932d8f8d0e 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -1,3 +1,5 @@ +-- vim: tw=80 + --- @class vim.option_meta --- @field full_name string --- @field desc? string @@ -747,7 +749,7 @@ return { applying 'breakindent', even if the resulting text should normally be narrower. This prevents text indented almost to the right window border - occupying lot of vertical space when broken. + occupying lots of vertical space when broken. (default: 20) shift:{n} After applying 'breakindent', the wrapped line's beginning will be shifted by the given number of @@ -761,9 +763,9 @@ return { list:{n} Adds an additional indent for lines that match a numbered or bulleted list (using the 'formatlistpat' setting). - list:-1 Uses the length of a match with 'formatlistpat' - for indentation. (default: 0) + list:-1 Uses the width of a match with 'formatlistpat' for + indentation. column:{n} Indent at column {n}. Will overrule the other sub-options. Note: an additional indent may be added for the 'showbreak' setting. @@ -996,9 +998,10 @@ return { The key used in Command-line Mode to open the command-line window. Only non-printable keys are allowed. The key can be specified as a single character, but it is difficult to - type. The preferred way is to use the <> notation. Examples: >vim - exe "set cedit=\\<C-Y>" - exe "set cedit=\\<Esc>" + type. The preferred way is to use |key-notation| (e.g. <Up>, <C-F>) or + a letter preceded with a caret (e.g. `^F` is CTRL-F). Examples: >vim + set cedit=^Y + set cedit=<Esc> < |Nvi| also has this option, but it only uses the first character. See |cmdwin|. ]=], @@ -1058,6 +1061,17 @@ return { v:fname_in name of the input file v:fname_out name of the output file Note that v:fname_in and v:fname_out will never be the same. + + The advantage of using a function call without arguments is that it is + faster, see |expr-option-function|. + + If the 'charconvert' expression starts with s: or |<SID>|, then it is + replaced with the script ID (|local-function|). Example: >vim + set charconvert=s:MyConvert() + set charconvert=<SID>SomeConvert() + < Otherwise the expression is evaluated in the context of the script + where the option was set, thus script-local items are available. + This option cannot be set from a |modeline| or in the |sandbox|, for security reasons. ]=], @@ -1217,11 +1231,10 @@ return { used. The command-line will cover the last line of the screen when shown. - WARNING: `cmdheight=0` is considered experimental. Expect some - unwanted behaviour. Some 'shortmess' flags and similar - mechanism might fail to take effect, causing unwanted hit-enter - prompts. Some informative messages, both from Nvim itself and - plugins, will not be displayed. + WARNING: `cmdheight=0` is EXPERIMENTAL. Expect some unwanted behaviour. + Some 'shortmess' flags and similar mechanism might fail to take effect, + causing unwanted hit-enter prompts. Some informative messages, both + from Nvim itself and plugins, will not be displayed. ]=], full_name = 'cmdheight', redraw = { 'all_windows' }, @@ -1310,7 +1323,6 @@ return { ]=], full_name = 'comments', list = 'onecomma', - redraw = { 'curswant' }, scope = { 'buffer' }, short_desc = N_('patterns that can start a comment line'), tags = { 'E524', 'E525' }, @@ -1324,11 +1336,10 @@ return { defaults = { if_true = '' }, desc = [=[ A template for a comment. The "%s" in the value is replaced with the - comment text. For example, C uses "/*%s*/". Used for |commenting| and to - add markers for folding, see |fold-marker|. + comment text, and should be padded with a space when possible. + Used for |commenting| and to add markers for folding, see |fold-marker|. ]=], full_name = 'commentstring', - redraw = { 'curswant' }, scope = { 'buffer' }, short_desc = N_('template for comments; used for fold marker'), tags = { 'E537' }, @@ -1417,6 +1428,26 @@ return { varname = 'p_cfu', }, { + abbreviation = 'cia', + cb = 'did_set_completeitemalign', + defaults = { if_true = 'abbr,kind,menu' }, + deny_duplicates = true, + desc = [=[ + A comma-separated list of |complete-items| that controls the alignment + and display order of items in the popup menu during Insert mode + completion. The supported values are abbr, kind, and menu. These + options allow to customize how the completion items are shown in the + popup menu. Note: must always contain those three values in any + order. + ]=], + full_name = 'completeitemalign', + list = 'onecomma', + scope = { 'global' }, + short_desc = N_('Insert mode completion item align order'), + type = 'string', + varname = 'p_cia', + }, + { abbreviation = 'cot', cb = 'did_set_completeopt', defaults = { if_true = 'menu,preview' }, @@ -1443,6 +1474,10 @@ return { completion in the preview window. Only works in combination with "menu" or "menuone". + popup Show extra information about the currently selected + completion in a popup window. Only works in combination + with "menu" or "menuone". Overrides "preview". + noinsert Do not insert any text for a match until the user selects a match from the menu. Only works in combination with "menu" or "menuone". No effect if "longest" is present. @@ -1451,14 +1486,18 @@ return { select one from the menu. Only works in combination with "menu" or "menuone". - popup Show extra information about the currently selected - completion in a popup window. Only works in combination - with "menu" or "menuone". Overrides "preview". + fuzzy Enable |fuzzy-matching| for completion candidates. This + allows for more flexible and intuitive matching, where + characters can be skipped and matches can be found even + if the exact sequence is not typed. Only makes a + difference how completion candidates are reduced from the + list of alternatives, but not how the candidates are + collected (using different completion types). ]=], expand_cb = 'expand_set_completeopt', full_name = 'completeopt', list = 'onecomma', - scope = { 'global' }, + scope = { 'global', 'buffer' }, short_desc = N_('options for Insert mode completion'), type = 'string', varname = 'p_cot', @@ -1956,7 +1995,6 @@ return { < ]=], full_name = 'define', - redraw = { 'curswant' }, scope = { 'global', 'buffer' }, short_desc = N_('pattern to be used to find a macro definition'), type = 'string', @@ -2310,9 +2348,12 @@ return { desc = [=[ When on all Unicode emoji characters are considered to be full width. This excludes "text emoji" characters, which are normally displayed as - single width. Unfortunately there is no good specification for this - and it has been determined on trial-and-error basis. Use the - |setcellwidths()| function to change the behavior. + single width. However, such "text emoji" are treated as full-width + emoji if they are followed by the U+FE0F variant selector. + + Unfortunately there is no good specification for this and it has been + determined on trial-and-error basis. Use the |setcellwidths()| + function to change the behavior. ]=], full_name = 'emoji', redraw = { 'all_windows', 'ui_option' }, @@ -2792,14 +2833,14 @@ return { /* vim: set filetype=idl : */ < |FileType| |filetypes| When a dot appears in the value then this separates two filetype - names. Example: >c + names, it should therefore not be used for a filetype. Example: >c /* vim: set filetype=c.doxygen : */ < This will use the "c" filetype first, then the "doxygen" filetype. This works both for filetype plugins and for syntax files. More than one dot may appear. This option is not copied to another buffer, independent of the 's' or 'S' flag in 'cpoptions'. - Only normal file name characters can be used, `/\*?[|<>` are illegal. + Only alphanumeric characters, '-' and '_' can be used. ]=], full_name = 'filetype', noglob = true, @@ -3215,6 +3256,9 @@ return { < This will invoke the mylang#Format() function in the autoload/mylang.vim file in 'runtimepath'. |autoload| + The advantage of using a function call without arguments is that it is + faster, see |expr-option-function|. + The expression is also evaluated when 'textwidth' is set and adding text beyond that limit. This happens under the same conditions as when internal formatting is used. Make sure the cursor is kept in the @@ -4149,11 +4193,14 @@ return { If the expression starts with s: or |<SID>|, then it is replaced with the script ID (|local-function|). Example: >vim - setlocal includeexpr=s:MyIncludeExpr(v:fname) - setlocal includeexpr=<SID>SomeIncludeExpr(v:fname) + setlocal includeexpr=s:MyIncludeExpr() + setlocal includeexpr=<SID>SomeIncludeExpr() < Otherwise, the expression is evaluated in the context of the script where the option was set, thus script-local items are available. + It is more efficient if the value is just a function call without + arguments, see |expr-option-function|. + The expression will be evaluated in the |sandbox| when set from a modeline, see |sandbox-option|. This option cannot be set in a modeline when 'modelineexpr' is off. @@ -4221,7 +4268,7 @@ return { in Insert mode as specified with the 'indentkeys' option. When this option is not empty, it overrules the 'cindent' and 'smartindent' indenting. When 'lisp' is set, this option is - is only used when 'lispoptions' contains "expr:1". + only used when 'lispoptions' contains "expr:1". The expression is evaluated with |v:lnum| set to the line number for which the indent is to be computed. The cursor is also in this line when the expression is evaluated (but it may be moved around). @@ -4233,6 +4280,9 @@ return { < Otherwise, the expression is evaluated in the context of the script where the option was set, thus script-local items are available. + The advantage of using a function call without arguments is that it is + faster, see |expr-option-function|. + The expression must return the number of spaces worth of indent. It can return "-1" to keep the current indent (this means 'autoindent' is used for the indent). @@ -4487,7 +4537,7 @@ return { { abbreviation = 'jop', cb = 'did_set_jumpoptions', - defaults = { if_true = '' }, + defaults = { if_true = 'clean' }, deny_duplicates = true, desc = [=[ List of words that change the behavior of the |jumplist|. @@ -4500,6 +4550,9 @@ return { view When moving through the jumplist, |changelist|, |alternate-file| or using |mark-motions| try to restore the |mark-view| in which the action occurred. + + clean Remove unloaded buffers from the jumplist. + EXPERIMENTAL: this flag may change in the future. ]=], expand_cb = 'expand_set_jumpoptions', full_name = 'jumpoptions', @@ -4519,7 +4572,7 @@ return { Setting this option to a valid keymap name has the side effect of setting 'iminsert' to one, so that the keymap becomes effective. 'imsearch' is also set to one, unless it was -1 - Only normal file name characters can be used, `/\*?[|<>` are illegal. + Only alphanumeric characters, '.', '-' and '_' can be used. ]=], full_name = 'keymap', normal_fname_chars = true, @@ -4612,7 +4665,7 @@ return { part can be in one of two forms: 1. A list of pairs. Each pair is a "from" character immediately followed by the "to" character. Examples: "aA", "aAbBcC". - 2. A list of "from" characters, a semi-colon and a list of "to" + 2. A list of "from" characters, a semicolon and a list of "to" characters. Example: "abc;ABC" Example: "aA,fgh;FGH,cCdDeE" Special characters need to be preceded with a backslash. These are @@ -4725,7 +4778,7 @@ return { update use |:redraw|. This may occasionally cause display errors. It is only meant to be set temporarily when performing an operation where redrawing may cause - flickering or cause a slow down. + flickering or cause a slowdown. ]=], full_name = 'lazyredraw', scope = { 'global' }, @@ -4868,6 +4921,9 @@ return { between tabs and spaces and for trailing blanks. Further changed by the 'listchars' option. + When 'listchars' does not contain "tab" field, tabs are shown as "^I" + or "<09>", like how unprintable characters are displayed. + The cursor is displayed at the start of the space a Tab character occupies, not at the end as usual in Normal mode. To get this cursor position while displaying Tabs with spaces, use: >vim @@ -5703,6 +5759,20 @@ return { (without "unsigned" it would become "9-2019"). Using CTRL-X on "0" or CTRL-A on "18446744073709551615" (2^64 - 1) has no effect, overflow is prevented. + blank If included, treat numbers as signed or unsigned based on + preceding whitespace. If a number with a leading dash has its + dash immediately preceded by a non-whitespace character (i.e., + not a tab or a " "), the negative sign won't be considered as + part of the number. For example: + Using CTRL-A on "14" in "Carbon-14" results in "Carbon-15" + (without "blank" it would become "Carbon-13"). + Using CTRL-X on "8" in "Carbon -8" results in "Carbon -9" + (because -8 is preceded by whitespace. If "unsigned" was + set, it would result in "Carbon -7"). + If this format is included, overflow is prevented as if + "unsigned" were set. If both this format and "unsigned" are + included, "unsigned" will take precedence. + Numbers which simply begin with a digit in the range 1-9 are always considered decimal. This also happens for numbers that are not recognized as octal or hex. @@ -5984,7 +6054,7 @@ return { set path+= < To use an environment variable, you probably need to replace the separator. Here is an example to append $INCL, in which directory - names are separated with a semi-colon: >vim + names are separated with a semicolon: >vim let &path = &path .. "," .. substitute($INCL, ';', ',', 'g') < Replace the ';' with a ':' or whatever separator is used. Note that this doesn't work when $INCL contains a comma or white space. @@ -6582,6 +6652,9 @@ return { top are deleted if new lines exceed this limit. Minimum is 1, maximum is 100000. Only in |terminal| buffers. + + Note: Lines that are not visible and kept in scrollback are not + reflown when the terminal buffer is resized horizontally. ]=], full_name = 'scrollback', redraw = { 'current_buffer' }, @@ -7300,7 +7373,7 @@ return { defaults = { if_true = 'ltToOCF' }, desc = [=[ This option helps to avoid all the |hit-enter| prompts caused by file - messages, for example with CTRL-G, and to avoid some other messages. + messages, for example with CTRL-G, and to avoid some other messages. It is a list of flags: flag meaning when present ~ l use "999L, 888B" instead of "999 lines, 888 bytes" *shm-l* @@ -7317,8 +7390,8 @@ return { message; also for quickfix message (e.g., ":cn") s don't give "search hit BOTTOM, continuing at TOP" or *shm-s* "search hit TOP, continuing at BOTTOM" messages; when using - the search count do not show "W" after the count message (see - S below) + the search count do not show "W" before the count message + (see |shm-S| below) t truncate file message at the start if it is too long *shm-t* to fit on the command-line, "<" will appear in the left most column; ignored in Ex mode @@ -7340,7 +7413,11 @@ return { `:silent` was used for the command; note that this also affects messages from 'autoread' reloading S do not show search count message when searching, e.g. *shm-S* - "[1/5]" + "[1/5]". When the "S" flag is not present (e.g. search count + is shown), the "search hit BOTTOM, continuing at TOP" and + "search hit TOP, continuing at BOTTOM" messages are only + indicated by a "W" (Mnemonic: Wrapped) letter before the + search count statistics. This gives you the opportunity to avoid that a change between buffers requires you to hit <Enter>, but still gives as useful a message as @@ -7889,7 +7966,7 @@ return { minus two. timeout:{millisec} Limit the time searching for suggestions to - {millisec} milli seconds. Applies to the following + {millisec} milliseconds. Applies to the following methods. When omitted the limit is 5000. When negative there is no limit. @@ -7909,9 +7986,11 @@ return { The file is used for all languages. expr:{expr} Evaluate expression {expr}. Use a function to avoid - trouble with spaces. |v:val| holds the badly spelled - word. The expression must evaluate to a List of - Lists, each with a suggestion and a score. + trouble with spaces. Best is to call a function + without arguments, see |expr-option-function|. + |v:val| holds the badly spelled word. The expression + must evaluate to a List of Lists, each with a + suggestion and a score. Example: [['the', 33], ['that', 44]] ~ Set 'verbose' and use |z=| to see the scores that the @@ -7997,7 +8076,8 @@ return { non-blank of the line. When off the cursor is kept in the same column (if possible). This applies to the commands: - CTRL-D, CTRL-U, CTRL-B, CTRL-F, "G", "H", "M", "L", "gg" - - "d", "<<" and ">>" with a linewise operator + - "d", "<<", "==" and ">>" with a linewise operator + (|operator-resulting-pos|) - "%" with a count - buffer changing commands (CTRL-^, :bnext, :bNext, etc.) - Ex commands that only have a line number, e.g., ":25" or ":+". @@ -8017,7 +8097,6 @@ return { cb = 'did_set_statuscolumn', defaults = { if_true = '' }, desc = [=[ - EXPERIMENTAL When non-empty, this option determines the content of the area to the side of a window, normally containing the fold, sign and number columns. The format of this option is like that of 'statusline'. @@ -8025,8 +8104,7 @@ return { Some of the items from the 'statusline' format are different for 'statuscolumn': - %l line number of currently drawn line - %r relative line number of currently drawn line + %l line number column for currently drawn line %s sign column for currently drawn line %C fold column for currently drawn line @@ -8053,11 +8131,8 @@ return { handler should be written with this in mind. Examples: >vim - " Relative number with bar separator and click handlers: - set statuscolumn=%@SignCb@%s%=%T%@NumCb@%r│%T - - " Right aligned relative cursor line number: - let &stc='%=%{v:relnum?v:relnum:v:lnum} ' + " Line number with bar separator and click handlers: + set statuscolumn=%@SignCb@%s%=%T%@NumCb@%l│%T " Line numbers in hexadecimal for non wrapped part of lines: let &stc='%=%{v:virtnum>0?"":printf("%x",v:lnum)} ' @@ -8468,7 +8543,7 @@ return { Syntax autocommand event is triggered with the value as argument. This option is not copied to another buffer, independent of the 's' or 'S' flag in 'cpoptions'. - Only normal file name characters can be used, `/\*?[|<>` are illegal. + Only alphanumeric characters, '.', '-' and '_' can be used. ]=], full_name = 'syntax', noglob = true, @@ -8479,6 +8554,30 @@ return { varname = 'p_syn', }, { + abbreviation = 'tcl', + cb = 'did_set_tabclose', + defaults = { if_true = '' }, + deny_duplicates = true, + desc = [=[ + This option controls the behavior when closing tab pages (e.g., using + |:tabclose|). When empty Vim goes to the next (right) tab page. + + Possible values (comma-separated list): + left If included, go to the previous tab page instead of + the next one. + uselast If included, go to the previously used tab page if + possible. This option takes precedence over the + others. + ]=], + expand_cb = 'expand_set_tabclose', + full_name = 'tabclose', + list = 'onecomma', + scope = { 'global' }, + short_desc = N_('which tab page to focus when closing a tab'), + type = 'string', + varname = 'p_tcl', + }, + { abbreviation = 'tal', cb = 'did_set_tabline', defaults = { if_true = '' }, @@ -8970,7 +9069,7 @@ return { desc = [=[ When on, the title of the window will be set to the value of 'titlestring' (if it is not empty), or to: - filename [+=-] (path) - NVIM + filename [+=-] (path) - Nvim Where: filename the name of the file being edited - indicates the file cannot be modified, 'ma' off @@ -8978,11 +9077,11 @@ return { = indicates the file is read-only =+ indicates the file is read-only and modified (path) is the path of the file being edited - - NVIM the server name |v:servername| or "NVIM" + - Nvim the server name |v:servername| or "Nvim" ]=], full_name = 'title', scope = { 'global' }, - short_desc = N_('Vim set the title of the window'), + short_desc = N_('set the title of the window'), type = 'boolean', varname = 'p_title', }, @@ -9579,7 +9678,12 @@ return { Some keys will not work, such as CTRL-C, <CR> and Enter. <Esc> can be used, but hitting it twice in a row will still exit command-line as a failsafe measure. - Although 'wc' is a number option, you can set it to a special key: >vim + Although 'wc' is a number option, it can be specified as a number, a + single character, a |key-notation| (e.g. <Up>, <C-F>) or a letter + preceded with a caret (e.g. `^F` is CTRL-F): >vim + :set wc=27 + :set wc=X + :set wc=^I set wc=<Tab> < ]=], @@ -9895,7 +9999,6 @@ return { ]=], full_name = 'winfixbuf', pv_name = 'p_wfb', - redraw = { 'current_window' }, scope = { 'window' }, short_desc = N_('pin a window to a specific buffer'), type = 'boolean', diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 29433ddbb5..c8f19d7ccf 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -14,6 +14,7 @@ #include "nvim/diff.h" #include "nvim/digraph.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" #include "nvim/eval/vars.h" @@ -81,7 +82,7 @@ static char *(p_dip_values[]) = { "filler", "context:", "iblank", "icase", "closeoff", "hiddenoff", "foldcolumn:", "followwrap", "internal", "indent-heuristic", "linematch:", "algorithm:", NULL }; static char *(p_dip_algorithm_values[]) = { "myers", "minimal", "patience", "histogram", NULL }; -static char *(p_nf_values[]) = { "bin", "octal", "hex", "alpha", "unsigned", NULL }; +static char *(p_nf_values[]) = { "bin", "octal", "hex", "alpha", "unsigned", "blank", NULL }; static char *(p_ff_values[]) = { FF_UNIX, FF_DOS, FF_MAC, NULL }; static char *(p_cb_values[]) = { "unnamed", "unnamedplus", NULL }; static char *(p_cmp_values[]) = { "internal", "keepascii", NULL }; @@ -97,11 +98,13 @@ static char *(p_ssop_values[]) = { "buffers", "winpos", "resize", "winsize", "lo "options", "help", "blank", "globals", "slash", "unix", "sesdir", "curdir", "folds", "cursor", "tabpages", "terminal", "skiprtp", NULL }; -// Keep in sync with SWB_ flags in option_defs.h +// Keep in sync with SWB_ flags in option_vars.h static char *(p_swb_values[]) = { "useopen", "usetab", "split", "newtab", "vsplit", "uselast", NULL }; static char *(p_spk_values[]) = { "cursor", "screen", "topline", NULL }; static char *(p_tc_values[]) = { "followic", "ignore", "match", "followscs", "smart", NULL }; +// Keep in sync with TCL_ flags in option_vars.h +static char *(p_tcl_values[]) = { "left", "uselast", NULL }; static char *(p_ve_values[]) = { "block", "insert", "all", "onemore", "none", "NONE", NULL }; // Note: Keep this in sync with check_opt_wim() static char *(p_wim_values[]) = { "full", "longest", "list", "lastused", NULL }; @@ -121,8 +124,8 @@ static char *(p_bs_values[]) = { "indent", "eol", "start", "nostop", NULL }; static char *(p_fdm_values[]) = { "manual", "expr", "marker", "indent", "syntax", "diff", NULL }; static char *(p_fcl_values[]) = { "all", NULL }; -static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview", "noinsert", "noselect", - "popup", NULL }; +static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview", "popup", + "noinsert", "noselect", "fuzzy", NULL }; #ifdef BACKSLASH_IN_FILENAME static char *(p_csl_values[]) = { "slash", "backslash", NULL }; #endif @@ -136,7 +139,7 @@ static char *(p_fdc_values[]) = { "auto", "auto:1", "auto:2", "auto:3", "auto:4" "5", "6", "7", "8", "9", NULL }; 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_jop_values[]) = { "stack", "view", "clean", NULL }; static char *(p_tpf_values[]) = { "BS", "HT", "FF", "ESC", "DEL", "C0", "C1", NULL }; static char *(p_rdb_values[]) = { "compositor", "nothrottle", "invalid", "nodelta", "line", "flush", NULL }; @@ -157,6 +160,7 @@ void didset_string_options(void) opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, true); opt_strings_flags(p_bkc, p_bkc_values, &bkc_flags, true); opt_strings_flags(p_bo, p_bo_values, &bo_flags, true); + opt_strings_flags(p_cot, p_cot_values, &cot_flags, true); opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, true); opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true); opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true); @@ -167,6 +171,7 @@ void didset_string_options(void) opt_strings_flags(p_tpf, p_tpf_values, &tpf_flags, true); opt_strings_flags(p_ve, p_ve_values, &ve_flags, true); opt_strings_flags(p_swb, p_swb_values, &swb_flags, true); + opt_strings_flags(p_tcl, p_tcl_values, &tcl_flags, true); opt_strings_flags(p_wop, p_wop_values, &wop_flags, true); opt_strings_flags(p_cb, p_cb_values, &cb_flags, true); } @@ -218,6 +223,7 @@ void check_buf_options(buf_T *buf) check_string_option(&buf->b_p_ft); check_string_option(&buf->b_p_cinw); check_string_option(&buf->b_p_cinsd); + check_string_option(&buf->b_p_cot); check_string_option(&buf->b_p_cpt); check_string_option(&buf->b_p_cfu); check_string_option(&buf->b_p_ofu); @@ -300,26 +306,26 @@ int check_signcolumn(win_T *wp) wp->w_minscwidth = 0; wp->w_maxscwidth = 1; } - return OK; - } - - if (strncmp(val, "auto:", 5) != 0 - || strlen(val) != 8 - || !ascii_isdigit(val[5]) - || val[6] != '-' - || !ascii_isdigit(val[7])) { - return FAIL; - } - - // auto:<NUM>-<NUM> - int min = val[5] - '0'; - int max = val[7] - '0'; - if (min < 1 || max < 2 || min > 8 || min >= max) { - return FAIL; + } else { + if (strncmp(val, "auto:", 5) != 0 + || strlen(val) != 8 + || !ascii_isdigit(val[5]) + || val[6] != '-' + || !ascii_isdigit(val[7])) { + return FAIL; + } + // auto:<NUM>-<NUM> + int min = val[5] - '0'; + int max = val[7] - '0'; + if (min < 1 || max < 2 || min > 8 || min >= max) { + return FAIL; + } + wp->w_minscwidth = min; + wp->w_maxscwidth = max; } - wp->w_minscwidth = min; - wp->w_maxscwidth = max; + int scwidth = wp->w_minscwidth <= 0 ? 0 : MIN(wp->w_maxscwidth, wp->w_scwidth); + wp->w_scwidth = MAX(wp->w_minscwidth, scwidth); return OK; } @@ -989,13 +995,71 @@ int expand_set_complete(optexpand_T *args, int *numMatches, char ***matches) matches); } +/// The 'completeitemalign' option is changed. +const char *did_set_completeitemalign(optset_T *args) +{ + char *p = p_cia; + unsigned new_cia_flags = 0; + bool seen[3] = { false, false, false }; + int count = 0; + char buf[10]; + while (*p) { + copy_option_part(&p, buf, sizeof(buf), ","); + if (count >= 3) { + return e_invarg; + } + if (strequal(buf, "abbr")) { + if (seen[CPT_ABBR]) { + return e_invarg; + } + new_cia_flags = new_cia_flags * 10 + CPT_ABBR; + seen[CPT_ABBR] = true; + count++; + } else if (strequal(buf, "kind")) { + if (seen[CPT_KIND]) { + return e_invarg; + } + new_cia_flags = new_cia_flags * 10 + CPT_KIND; + seen[CPT_KIND] = true; + count++; + } else if (strequal(buf, "menu")) { + if (seen[CPT_MENU]) { + return e_invarg; + } + new_cia_flags = new_cia_flags * 10 + CPT_MENU; + seen[CPT_MENU] = true; + count++; + } else { + return e_invarg; + } + } + if (new_cia_flags == 0 || count != 3) { + return e_invarg; + } + cia_flags = new_cia_flags; + return NULL; +} + /// The 'completeopt' option is changed. const char *did_set_completeopt(optset_T *args FUNC_ATTR_UNUSED) { - if (check_opt_strings(p_cot, p_cot_values, true) != OK) { + buf_T *buf = (buf_T *)args->os_buf; + char *cot = p_cot; + unsigned *flags = &cot_flags; + + if (args->os_flags & OPT_LOCAL) { + cot = buf->b_p_cot; + flags = &buf->b_cot_flags; + } + + if (check_opt_strings(cot, p_cot_values, true) != OK) { return e_invarg; } - completeopt_was_set(); + + if (opt_strings_flags(cot, p_cot_values, flags, true) != OK) { + return e_invarg; + } + return NULL; } @@ -2019,8 +2083,6 @@ const char *did_set_signcolumn(optset_T *args) if (check_signcolumn(win) != OK) { return e_invarg; } - int scwidth = win->w_minscwidth <= 0 ? 0 : MIN(win->w_maxscwidth, win->w_scwidth); - win->w_scwidth = MAX(win->w_minscwidth, scwidth); // When changing the 'signcolumn' to or from 'number', recompute the // width of the number column if 'number' or 'relativenumber' is set. if ((*oldval == 'n' && *(oldval + 1) == 'u') || win->w_minscwidth == SCL_NUM) { @@ -2191,6 +2253,21 @@ int expand_set_switchbuf(optexpand_T *args, int *numMatches, char ***matches) matches); } +/// The 'tabclose' option is changed. +const char *did_set_tabclose(optset_T *args FUNC_ATTR_UNUSED) +{ + return did_set_opt_flags(p_tcl, p_tcl_values, &tcl_flags, true); +} + +int expand_set_tabclose(optexpand_T *args, int *numMatches, char ***matches) +{ + return expand_set_opt_string(args, + p_tcl_values, + ARRAY_SIZE(p_tcl_values) - 1, + numMatches, + matches); +} + /// The 'tabline' option is changed. const char *did_set_tabline(optset_T *args) { diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 5a79004c41..ccf6c9554a 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -63,13 +63,13 @@ const char *os_getenv(const char *name) FUNC_ATTR_NONNULL_ALL { char *e = NULL; - if (name[0] == '\0') { + if (name[0] == NUL) { return NULL; } int r = 0; if (map_has(cstr_t, &envmap, name) && !!(e = (char *)pmap_get(cstr_t)(&envmap, name))) { - if (e[0] != '\0') { + if (e[0] != NUL) { // Found non-empty cached env var. // NOTE: This risks incoherence if an in-process library changes the // environment without going through our os_setenv() wrapper. If @@ -85,11 +85,11 @@ const char *os_getenv(const char *name) if (r == UV_ENOBUFS) { e = xmalloc(size); r = uv_os_getenv(name, e, &size); - if (r != 0 || size == 0 || e[0] == '\0') { + if (r != 0 || size == 0 || e[0] == NUL) { XFREE_CLEAR(e); goto end; } - } else if (r != 0 || size == 0 || buf[0] == '\0') { + } else if (r != 0 || size == 0 || buf[0] == NUL) { e = NULL; goto end; } else { @@ -110,7 +110,7 @@ end: bool os_env_exists(const char *name) FUNC_ATTR_NONNULL_ALL { - if (name[0] == '\0') { + if (name[0] == NUL) { return false; } // Use a tiny buffer because we don't care about the value: if uv_os_getenv() @@ -134,14 +134,14 @@ bool os_env_exists(const char *name) int os_setenv(const char *name, const char *value, int overwrite) FUNC_ATTR_NONNULL_ALL { - if (name[0] == '\0') { + if (name[0] == NUL) { return -1; } #ifdef MSWIN if (!overwrite && os_getenv(name) != NULL) { return 0; } - if (value[0] == '\0') { + if (value[0] == NUL) { // Windows (Vim-compat): Empty string undefines the env var. return os_unsetenv(name); } @@ -174,7 +174,7 @@ int os_setenv(const char *name, const char *value, int overwrite) int os_unsetenv(const char *name) FUNC_ATTR_NONNULL_ALL { - if (name[0] == '\0') { + if (name[0] == NUL) { return -1; } pmap_del2(&envmap, name); @@ -344,7 +344,7 @@ char *os_getenvname_at_index(size_t index) #endif } -/// Get the process ID of the Neovim process. +/// Get the process ID of the Nvim process. /// /// @return the process ID. int64_t os_get_pid(void) @@ -366,7 +366,7 @@ void os_get_hostname(char *hostname, size_t size) struct utsname vutsname; if (uname(&vutsname) < 0) { - *hostname = '\0'; + *hostname = NUL; } else { xstrlcpy(hostname, vutsname.nodename, size); } @@ -374,12 +374,12 @@ void os_get_hostname(char *hostname, size_t size) wchar_t host_utf16[MAX_COMPUTERNAME_LENGTH + 1]; DWORD host_wsize = sizeof(host_utf16) / sizeof(host_utf16[0]); if (GetComputerNameW(host_utf16, &host_wsize) == 0) { - *hostname = '\0'; + *hostname = NUL; DWORD err = GetLastError(); semsg("GetComputerNameW failed: %d", err); return; } - host_utf16[host_wsize] = '\0'; + host_utf16[host_wsize] = NUL; char *host_utf8; int conversion_result = utf16_to_utf8(host_utf16, -1, &host_utf8); @@ -391,27 +391,38 @@ void os_get_hostname(char *hostname, size_t size) xfree(host_utf8); #else emsg("os_get_hostname failed: missing uname()"); - *hostname = '\0'; + *hostname = NUL; #endif } -/// To get the "real" home directory: +/// The "real" home directory as determined by `init_homedir`. +static char *homedir = NULL; +static char *os_uv_homedir(void); + +/// Gets the "real", resolved user home directory as determined by `init_homedir`. +const char *os_homedir(void) +{ + if (!homedir) { + emsg("os_homedir failed: homedir not initialized"); + return NULL; + } + return homedir; +} + +/// Sets `homedir` to the "real", resolved user home directory, as follows: /// 1. get value of $HOME /// 2. if $HOME is not set, try the following /// For Windows: /// 1. assemble homedir using HOMEDRIVE and HOMEPATH -/// 2. try os_homedir() +/// 2. try os_uv_homedir() /// 3. resolve a direct reference to another system variable /// 4. guess C drive /// For Unix: -/// 1. try os_homedir() +/// 1. try os_uv_homedir() /// 2. go to that directory /// This also works with mounts and links. /// Don't do this for Windows, it will change the "current dir" for a drive. /// 3. fall back to current working directory as a last resort -static char *homedir = NULL; -static char *os_homedir(void); - void init_homedir(void) { // In case we are called a second time. @@ -440,7 +451,7 @@ void init_homedir(void) } } if (var == NULL) { - var = os_homedir(); + var = os_uv_homedir(); } // Weird but true: $HOME may contain an indirect reference to another @@ -471,7 +482,7 @@ void init_homedir(void) #ifdef UNIX if (var == NULL) { - var = os_homedir(); + var = os_uv_homedir(); } // Get the actual path. This resolves links. @@ -492,7 +503,7 @@ void init_homedir(void) static char homedir_buf[MAXPATHL]; -static char *os_homedir(void) +static char *os_uv_homedir(void) { homedir_buf[0] = NUL; size_t homedir_size = MAXPATHL; @@ -885,9 +896,9 @@ void vim_get_prefix_from_exepath(char *exe_name) // but c_grammar.lua does not recognize it (yet). xstrlcpy(exe_name, get_vim_var_str(VV_PROGPATH), MAXPATHL * sizeof(*exe_name)); char *path_end = path_tail_with_sep(exe_name); - *path_end = '\0'; // remove the trailing "nvim.exe" + *path_end = NUL; // remove the trailing "nvim.exe" path_end = path_tail(exe_name); - *path_end = '\0'; // remove the trailing "bin/" + *path_end = NUL; // remove the trailing "bin/" } /// Vim getenv() wrapper with special handling of $HOME, $VIM, $VIMRUNTIME, diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c index da6fb13768..1981d0dfd4 100644 --- a/src/nvim/os/fileio.c +++ b/src/nvim/os/fileio.c @@ -21,8 +21,6 @@ #include "nvim/os/fileio.h" #include "nvim/os/fs.h" #include "nvim/os/os_defs.h" -#include "nvim/rbuffer.h" -#include "nvim/rbuffer_defs.h" #include "nvim/types_defs.h" #ifdef HAVE_SYS_UIO_H @@ -120,12 +118,10 @@ int file_open_fd(FileDescriptor *const ret_fp, const int fd, const int flags) assert(!ret_fp->wr || !ret_fp->non_blocking); ret_fp->fd = fd; ret_fp->eof = false; - ret_fp->rv = rbuffer_new(kRWBufferSize); - ret_fp->_error = 0; - if (ret_fp->wr) { - ret_fp->rv->data = ret_fp; - ret_fp->rv->full_cb = (rbuffer_callback)&file_rb_write_full_cb; - } + ret_fp->buffer = alloc_block(); + ret_fp->read_pos = ret_fp->buffer; + ret_fp->write_pos = ret_fp->buffer; + ret_fp->bytes_read = 0; return 0; } @@ -140,6 +136,19 @@ int file_open_stdin(FileDescriptor *fp) return error; } +/// opens buffer for reading +void file_open_buffer(FileDescriptor *ret_fp, char *data, size_t len) +{ + ret_fp->wr = false; + ret_fp->non_blocking = false; + ret_fp->fd = -1; + ret_fp->eof = true; + ret_fp->buffer = NULL; // we don't take ownership + ret_fp->read_pos = data; + ret_fp->write_pos = data + len; + ret_fp->bytes_read = 0; +} + /// Close file and free its buffer /// /// @param[in,out] fp File to close. @@ -149,32 +158,19 @@ int file_open_stdin(FileDescriptor *fp) int file_close(FileDescriptor *const fp, const bool do_fsync) FUNC_ATTR_NONNULL_ALL { + if (fp->fd < 0) { + return 0; + } + const int flush_error = (do_fsync ? file_fsync(fp) : file_flush(fp)); const int close_error = os_close(fp->fd); - rbuffer_free(fp->rv); + free_block(fp->buffer); if (close_error != 0) { return close_error; } return flush_error; } -/// Flush file modifications to disk -/// -/// @param[in,out] fp File to work with. -/// -/// @return 0 or error code. -int file_flush(FileDescriptor *const fp) - FUNC_ATTR_NONNULL_ALL -{ - if (!fp->wr) { - return 0; - } - file_rb_write_full_cb(fp->rv, fp); - const int error = fp->_error; - fp->_error = 0; - return error; -} - /// Flush file modifications to disk and run fsync() /// /// @param[in,out] fp File to work with. @@ -200,36 +196,29 @@ int file_fsync(FileDescriptor *const fp) return 0; } -/// Buffer used for writing -/// -/// Like IObuff, but allows file_\* callers not to care about spoiling it. -static char writebuf[kRWBufferSize]; - -/// Function run when RBuffer is full when writing to a file -/// -/// Actually does writing to the file, may also be invoked directly. +/// Flush file modifications to disk /// -/// @param[in,out] rv RBuffer instance used. /// @param[in,out] fp File to work with. -static void file_rb_write_full_cb(RBuffer *const rv, void *const fp_in) +/// +/// @return 0 or error code. +int file_flush(FileDescriptor *fp) FUNC_ATTR_NONNULL_ALL { - FileDescriptor *const fp = fp_in; - assert(fp->wr); - assert(rv->data == (void *)fp); - if (rbuffer_size(rv) == 0) { - return; + if (!fp->wr) { + return 0; } - const size_t read_bytes = rbuffer_read(rv, writebuf, kRWBufferSize); - const ptrdiff_t wres = os_write(fp->fd, writebuf, read_bytes, + + ptrdiff_t to_write = fp->write_pos - fp->read_pos; + if (to_write == 0) { + return 0; + } + const ptrdiff_t wres = os_write(fp->fd, fp->read_pos, (size_t)to_write, fp->non_blocking); - if (wres != (ptrdiff_t)read_bytes) { - if (wres >= 0) { - fp->_error = UV_EIO; - } else { - fp->_error = (int)wres; - } + fp->read_pos = fp->write_pos = fp->buffer; + if (wres != to_write) { + return (wres >= 0) ? UV_EIO : (int)wres; } + return 0; } /// Read from file @@ -244,79 +233,98 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, const size_t FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { assert(!fp->wr); - char *buf = ret_buf; - size_t read_remaining = size; - RBuffer *const rv = fp->rv; + size_t from_buffer = MIN((size_t)(fp->write_pos - fp->read_pos), size); + memcpy(ret_buf, fp->read_pos, from_buffer); + + char *buf = ret_buf + from_buffer; + size_t read_remaining = size - from_buffer; + if (!read_remaining) { + fp->bytes_read += from_buffer; + fp->read_pos += from_buffer; + return (ptrdiff_t)from_buffer; + } + + // at this point, we have consumed all of an existing buffer. restart from the beginning + fp->read_pos = fp->write_pos = fp->buffer; + +#ifdef HAVE_READV bool called_read = false; while (read_remaining) { - const size_t rv_size = rbuffer_size(rv); - if (rv_size > 0) { - const size_t rsize = rbuffer_read(rv, buf, MIN(rv_size, read_remaining)); - buf += rsize; - read_remaining -= rsize; - } - if (fp->eof - // Allow only at most one os_read[v] call. - || (called_read && fp->non_blocking)) { + // Allow only at most one os_read[v] call. + if (fp->eof || (called_read && fp->non_blocking)) { break; } - if (read_remaining) { - assert(rbuffer_size(rv) == 0); - rbuffer_reset(rv); -#ifdef HAVE_READV - // If there is readv() syscall, then take an opportunity to populate - // both target buffer and RBuffer at once, … - size_t write_count; - struct iovec iov[] = { - { .iov_base = buf, .iov_len = read_remaining }, - { .iov_base = rbuffer_write_ptr(rv, &write_count), - .iov_len = kRWBufferSize }, - }; - assert(write_count == kRWBufferSize); - const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov, - ARRAY_SIZE(iov), fp->non_blocking); - if (r_ret > 0) { - if (r_ret > (ptrdiff_t)read_remaining) { - rbuffer_produced(rv, (size_t)(r_ret - (ptrdiff_t)read_remaining)); - read_remaining = 0; - } else { - buf += (size_t)r_ret; - read_remaining -= (size_t)r_ret; - } - } else if (r_ret < 0) { - return r_ret; - } -#else - if (read_remaining >= kRWBufferSize) { - // …otherwise leave RBuffer empty and populate only target buffer, - // because filtering information through rbuffer will be more syscalls. - const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining, - fp->non_blocking); - if (r_ret >= 0) { - read_remaining -= (size_t)r_ret; - return (ptrdiff_t)(size - read_remaining); - } else if (r_ret < 0) { - return r_ret; - } + // If there is readv() syscall, then take an opportunity to populate + // both target buffer and RBuffer at once, … + struct iovec iov[] = { + { .iov_base = buf, .iov_len = read_remaining }, + { .iov_base = fp->write_pos, + .iov_len = ARENA_BLOCK_SIZE }, + }; + const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov, + ARRAY_SIZE(iov), fp->non_blocking); + if (r_ret > 0) { + if (r_ret > (ptrdiff_t)read_remaining) { + fp->write_pos += (size_t)(r_ret - (ptrdiff_t)read_remaining); + read_remaining = 0; } else { - size_t write_count; - const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, - rbuffer_write_ptr(rv, &write_count), - kRWBufferSize, fp->non_blocking); - assert(write_count == kRWBufferSize); - if (r_ret > 0) { - rbuffer_produced(rv, (size_t)r_ret); - } else if (r_ret < 0) { - return r_ret; - } + buf += r_ret; + read_remaining -= (size_t)r_ret; } -#endif - called_read = true; + } else if (r_ret < 0) { + return r_ret; } + called_read = true; } +#else + if (fp->eof) { + // already eof, cannot read more + } else if (read_remaining >= ARENA_BLOCK_SIZE) { + // …otherwise leave fp->buffer empty and populate only target buffer, + // because filtering information through rbuffer will be more syscalls. + const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining, + fp->non_blocking); + if (r_ret >= 0) { + read_remaining -= (size_t)r_ret; + } else if (r_ret < 0) { + return r_ret; + } + } else { + const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, + fp->write_pos, + ARENA_BLOCK_SIZE, fp->non_blocking); + if (r_ret < 0) { + return r_ret; + } else { + fp->write_pos += r_ret; + size_t to_copy = MIN((size_t)r_ret, read_remaining); + memcpy(buf, fp->read_pos, to_copy); + fp->read_pos += to_copy; + read_remaining -= to_copy; + } + } +#endif + + fp->bytes_read += (size - read_remaining); return (ptrdiff_t)(size - read_remaining); } +/// try to read already buffered data in place +/// +/// @return NULL if enough data is not available +/// valid pointer to chunk of "size". pointer becomes invalid in the next "file_read" call! +char *file_try_read_buffered(FileDescriptor *const fp, const size_t size) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +{ + if ((size_t)(fp->write_pos - fp->read_pos) >= size) { + char *ret = fp->read_pos; + fp->read_pos += size; + fp->bytes_read += size; + return ret; + } + return NULL; +} + /// Write to a file /// /// @param[in] fd File descriptor to write to. @@ -328,51 +336,67 @@ ptrdiff_t file_write(FileDescriptor *const fp, const char *const buf, const size FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) { assert(fp->wr); - const size_t written = rbuffer_write(fp->rv, buf, size); - if (fp->_error != 0) { - const int error = fp->_error; - fp->_error = 0; - return error; - } else if (written != size) { - return UV_EIO; + // includes the trivial case of size==0 + if (size < file_space(fp)) { + memcpy(fp->write_pos, buf, size); + fp->write_pos += size; + return (ptrdiff_t)size; } - return (ptrdiff_t)written; -} -/// Buffer used for skipping. Its contents is undefined and should never be -/// used. -static char skipbuf[kRWBufferSize]; + // TODO(bfredl): just as for reading, use iovec to combine fp->buffer with buf + int status = file_flush(fp); + if (status < 0) { + return status; + } + + if (size < ARENA_BLOCK_SIZE) { + memcpy(fp->write_pos, buf, size); + fp->write_pos += size; + return (ptrdiff_t)size; + } + + const ptrdiff_t wres = os_write(fp->fd, buf, size, + fp->non_blocking); + return (wres != (ptrdiff_t)size && wres >= 0) ? UV_EIO : wres; +} /// Skip some bytes /// /// This is like `fseek(fp, size, SEEK_CUR)`, but actual implementation simply -/// reads to a buffer and discards the result. +/// reads to the buffer and discards the result. ptrdiff_t file_skip(FileDescriptor *const fp, const size_t size) FUNC_ATTR_NONNULL_ALL { assert(!fp->wr); - size_t read_bytes = 0; - do { - const ptrdiff_t new_read_bytes = - file_read(fp, skipbuf, MIN(size - read_bytes, sizeof(skipbuf))); - if (new_read_bytes < 0) { - return new_read_bytes; - } else if (new_read_bytes == 0) { + size_t from_buffer = MIN((size_t)(fp->write_pos - fp->read_pos), size); + size_t skip_remaining = size - from_buffer; + if (skip_remaining == 0) { + fp->read_pos += from_buffer; + fp->bytes_read += from_buffer; + return (ptrdiff_t)from_buffer; + } + + fp->read_pos = fp->write_pos = fp->buffer; + bool called_read = false; + while (skip_remaining > 0) { + // Allow only at most one os_read[v] call. + if (fp->eof || (called_read && fp->non_blocking)) { break; } - read_bytes += (size_t)new_read_bytes; - } while (read_bytes < size && !file_eof(fp)); - - return (ptrdiff_t)read_bytes; -} + const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, fp->buffer, ARENA_BLOCK_SIZE, + fp->non_blocking); + if (r_ret < 0) { + return r_ret; + } else if ((size_t)r_ret > skip_remaining) { + fp->read_pos = fp->buffer + skip_remaining; + fp->write_pos = fp->buffer + r_ret; + fp->bytes_read += size; + return (ptrdiff_t)size; + } + skip_remaining -= (size_t)r_ret; + called_read = true; + } -/// Print error which occurs when failing to write msgpack data -/// -/// @param[in] error Error code of the error to print. -/// -/// @return -1 (error return for msgpack_packer callbacks). -int msgpack_file_write_error(const int error) -{ - semsg(_("E5420: Failed to write to file: %s"), os_strerror(error)); - return -1; + fp->bytes_read += size - skip_remaining; + return (ptrdiff_t)(size - skip_remaining); } diff --git a/src/nvim/os/fileio.h b/src/nvim/os/fileio.h index e8fd2209db..523f9657a4 100644 --- a/src/nvim/os/fileio.h +++ b/src/nvim/os/fileio.h @@ -2,6 +2,7 @@ #include <stddef.h> // IWYU pragma: keep +#include "nvim/memory_defs.h" #include "nvim/os/fileio_defs.h" // IWYU pragma: keep /// file_open() flags @@ -32,6 +33,11 @@ enum { kRWBufferSize = 1024, }; +static inline size_t file_space(FileDescriptor *fp) +{ + return (size_t)((fp->buffer + ARENA_BLOCK_SIZE) - fp->write_pos); +} + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/fileio.h.generated.h" #endif diff --git a/src/nvim/os/fileio_defs.h b/src/nvim/os/fileio_defs.h index 3dc8c7b22a..47f0629ccf 100644 --- a/src/nvim/os/fileio_defs.h +++ b/src/nvim/os/fileio_defs.h @@ -1,22 +1,23 @@ #pragma once #include <stdbool.h> - -#include "nvim/func_attr.h" -#include "nvim/rbuffer_defs.h" +#include <stdint.h> /// Structure used to read from/write to file typedef struct { - int fd; ///< File descriptor. - int _error; ///< Error code for use with RBuffer callbacks or zero. - RBuffer *rv; ///< Read or write buffer. + int fd; ///< File descriptor. Can be -1 if no backing file (file_open_buffer) + char *buffer; ///< Read or write buffer. always ARENA_BLOCK_SIZE if allocated + char *read_pos; ///< read position in buffer + char *write_pos; ///< write position in buffer bool wr; ///< True if file is in write mode. bool eof; ///< True if end of file was encountered. bool non_blocking; ///< True if EAGAIN should not restart syscalls. + uint64_t bytes_read; ///< total bytes read so far } FileDescriptor; -static inline bool file_eof(const FileDescriptor *fp) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL; +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "os/fileio_defs.h.inline.generated.h" +#endif /// Check whether end of file was encountered /// @@ -25,19 +26,18 @@ static inline bool file_eof(const FileDescriptor *fp) /// @return true if it was, false if it was not or read operation was never /// performed. static inline bool file_eof(const FileDescriptor *const fp) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { - return fp->eof && rbuffer_size(fp->rv) == 0; + return fp->eof && fp->read_pos == fp->write_pos; } -static inline int file_fd(const FileDescriptor *fp) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL; - /// Return the file descriptor associated with the FileDescriptor structure /// /// @param[in] fp File to check. /// /// @return File descriptor. static inline int file_fd(const FileDescriptor *const fp) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { return fp->fd; } diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 19bdf30311..d0da37b8e7 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -35,6 +35,7 @@ #include "nvim/api/private/helpers.h" #include "nvim/ascii_defs.h" +#include "nvim/errors.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" #include "nvim/log.h" @@ -301,7 +302,7 @@ static bool is_executable_ext(const char *name, char **abspath) char *nameext = strrchr(name, '.'); size_t nameext_len = nameext ? strlen(nameext) : 0; xstrlcpy(os_buf, name, sizeof(os_buf)); - char *buf_end = xstrchrnul(os_buf, '\0'); + char *buf_end = xstrchrnul(os_buf, NUL); const char *pathext = os_getenv("PATHEXT"); if (!pathext) { pathext = ".com;.exe;.bat;.cmd"; @@ -309,7 +310,7 @@ static bool is_executable_ext(const char *name, char **abspath) const char *ext = pathext; while (*ext) { // If $PATHEXT itself contains dot: - if (ext[0] == '.' && (ext[1] == '\0' || ext[1] == ENV_SEPCHAR)) { + if (ext[0] == '.' && (ext[1] == NUL || ext[1] == ENV_SEPCHAR)) { if (is_executable(name, abspath)) { return true; } @@ -355,10 +356,16 @@ static bool is_executable_in_path(const char *name, char **abspath) } #ifdef MSWIN - // Prepend ".;" to $PATH. - size_t pathlen = strlen(path_env); - char *path = memcpy(xmallocz(pathlen + 2), "." ENV_SEPSTR, 2); - memcpy(path + 2, path_env, pathlen); + char *path = NULL; + if (!os_env_exists("NoDefaultCurrentDirectoryInExePath")) { + // Prepend ".;" to $PATH. + size_t pathlen = strlen(path_env); + path = xmallocz(pathlen + 2); + memcpy(path, "." ENV_SEPSTR, 2); + memcpy(path + 2, path_env, pathlen); + } else { + path = xstrdup(path_env); + } #else char *path = xstrdup(path_env); #endif @@ -435,7 +442,7 @@ FILE *os_fopen(const char *path, const char *flags) assert(flags != NULL && strlen(flags) > 0 && strlen(flags) <= 2); int iflags = 0; // Per table in fopen(3) manpage. - if (flags[1] == '\0' || flags[1] == 'b') { + if (flags[1] == NUL || flags[1] == 'b') { switch (flags[0]) { case 'r': iflags = O_RDONLY; diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 60b5b48745..7c5293a8b8 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -27,22 +27,17 @@ #include "nvim/os/os_defs.h" #include "nvim/os/time.h" #include "nvim/profile.h" -#include "nvim/rbuffer.h" -#include "nvim/rbuffer_defs.h" #include "nvim/state.h" #include "nvim/state_defs.h" #define READ_BUFFER_SIZE 0xfff -#define INPUT_BUFFER_SIZE (READ_BUFFER_SIZE * 4) +#define INPUT_BUFFER_SIZE ((READ_BUFFER_SIZE * 4) + MAX_KEY_CODE_LEN) -typedef enum { - kInputNone, - kInputAvail, - kInputEof, -} InbufPollResult; +static RStream read_stream = { .s.closed = true }; // Input before UI starts. +static char input_buffer[INPUT_BUFFER_SIZE]; +static char *input_read_pos = input_buffer; +static char *input_write_pos = input_buffer; -static Stream read_stream = { .closed = true }; // Input before UI starts. -static RBuffer *input_buffer = NULL; static bool input_eof = false; static bool blocking = false; static int cursorhold_time = 0; ///< time waiting for CursorHold event @@ -52,39 +47,27 @@ static int cursorhold_tb_change_cnt = 0; ///< tb_change_cnt when waiting starte # include "os/input.c.generated.h" #endif -void input_init(void) -{ - input_buffer = rbuffer_new(INPUT_BUFFER_SIZE + MAX_KEY_CODE_LEN); -} - void input_start(void) { - if (!read_stream.closed) { + if (!read_stream.s.closed) { return; } used_stdin = true; - rstream_init_fd(&main_loop, &read_stream, STDIN_FILENO, READ_BUFFER_SIZE); + rstream_init_fd(&main_loop, &read_stream, STDIN_FILENO); rstream_start(&read_stream, input_read_cb, NULL); } void input_stop(void) { - if (read_stream.closed) { + if (read_stream.s.closed) { return; } rstream_stop(&read_stream); - stream_close(&read_stream, NULL, NULL); + rstream_may_close(&read_stream); } -#ifdef EXITFREE -void input_free_all_mem(void) -{ - rbuffer_free(input_buffer); -} -#endif - static void cursorhold_event(void **argv) { event_T event = State & MODE_INSERT ? EVENT_CURSORHOLDI : EVENT_CURSORHOLD; @@ -95,54 +78,76 @@ static void cursorhold_event(void **argv) static void create_cursorhold_event(bool events_enabled) { // If events are enabled and the queue has any items, this function should not - // have been called (inbuf_poll would return kInputAvail). + // have been called (`inbuf_poll` would return `kTrue`). // TODO(tarruda): Cursorhold should be implemented as a timer set during the // `state_check` callback for the states where it can be triggered. assert(!events_enabled || multiqueue_empty(main_loop.events)); multiqueue_put(main_loop.events, cursorhold_event, NULL); } -static void restart_cursorhold_wait(int tb_change_cnt) +static void reset_cursorhold_wait(int tb_change_cnt) { cursorhold_time = 0; cursorhold_tb_change_cnt = tb_change_cnt; } -/// Low level input function +/// Reads OS input into `buf`, and consumes pending events while waiting (if `ms != 0`). /// -/// Wait until either the input buffer is non-empty or, if `events` is not NULL -/// until `events` is non-empty. -int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *events) +/// - Consumes available input received from the OS. +/// - Consumes pending events. +/// - Manages CursorHold events. +/// - Handles EOF conditions. +/// +/// Originally based on the Vim `mch_inchar` function. +/// +/// @param buf Buffer to store consumed input. +/// @param maxlen Maximum bytes to read into `buf`, or 0 to skip reading. +/// @param ms Timeout in milliseconds. -1 for indefinite wait, 0 for no wait. +/// @param tb_change_cnt Used to detect when typeahead changes. +/// @param events (optional) Events to process. +/// @return Bytes read into buf, or 0 if no input was read +int input_get(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *events) { // This check is needed so that feeding typeahead from RPC can prevent CursorHold. if (tb_change_cnt != cursorhold_tb_change_cnt) { - restart_cursorhold_wait(tb_change_cnt); + reset_cursorhold_wait(tb_change_cnt); } - if (maxlen && rbuffer_size(input_buffer)) { - restart_cursorhold_wait(tb_change_cnt); - return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen); - } +#define TRY_READ() \ + do { \ + if (maxlen && input_available()) { \ + reset_cursorhold_wait(tb_change_cnt); \ + assert(maxlen >= 0); \ + size_t to_read = MIN((size_t)maxlen, input_available()); \ + memcpy(buf, input_read_pos, to_read); \ + input_read_pos += to_read; \ + /* This is safe because INPUT_BUFFER_SIZE fits in an int. */ \ + assert(to_read <= INT_MAX); \ + return (int)to_read; \ + } \ + } while (0) + + TRY_READ(); // No risk of a UI flood, so disable CTRL-C "interrupt" behavior if it's mapped. if ((mapped_ctrl_c | curbuf->b_mapped_ctrl_c) & get_real_state()) { ctrl_c_interrupts = false; } - InbufPollResult result; + TriState result; ///< inbuf_poll result. if (ms >= 0) { - if ((result = inbuf_poll(ms, events)) == kInputNone) { + if ((result = inbuf_poll(ms, events)) == kFalse) { return 0; } } else { uint64_t wait_start = os_hrtime(); cursorhold_time = MIN(cursorhold_time, (int)p_ut); - if ((result = inbuf_poll((int)p_ut - cursorhold_time, events)) == kInputNone) { - if (read_stream.closed && silent_mode) { + if ((result = inbuf_poll((int)p_ut - cursorhold_time, events)) == kFalse) { + if (read_stream.s.closed && silent_mode) { // Drained eventloop & initial input; exit silent/batch-mode (-es/-Es). read_error_exit(); } - restart_cursorhold_wait(tb_change_cnt); + reset_cursorhold_wait(tb_change_cnt); if (trigger_cursorhold() && !typebuf_changed(tb_change_cnt)) { create_cursorhold_event(events == main_loop.events); } else { @@ -161,29 +166,26 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e return 0; } - if (maxlen && rbuffer_size(input_buffer)) { - restart_cursorhold_wait(tb_change_cnt); - // Safe to convert rbuffer_read to int, it will never overflow since we use - // relatively small buffers. - return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen); - } + TRY_READ(); // If there are events, return the keys directly if (maxlen && pending_events(events)) { return push_event_key(buf, maxlen); } - if (result == kInputEof) { + if (result == kNone) { read_error_exit(); } return 0; + +#undef TRY_READ } // Check if a character is available for reading bool os_char_avail(void) { - return inbuf_poll(0, NULL) == kInputAvail; + return inbuf_poll(0, NULL) == kTrue; } /// Poll for fast events. `got_int` will be set to `true` if CTRL-C was typed. @@ -247,11 +249,28 @@ bool os_isatty(int fd) return uv_guess_handle(fd) == UV_TTY; } -void input_enqueue_raw(String keys) +size_t input_available(void) { - if (keys.size > 0) { - rbuffer_write(input_buffer, keys.data, keys.size); + return (size_t)(input_write_pos - input_read_pos); +} + +static size_t input_space(void) +{ + return (size_t)(input_buffer + INPUT_BUFFER_SIZE - input_write_pos); +} + +void input_enqueue_raw(const char *data, size_t size) +{ + if (input_read_pos > input_buffer) { + size_t available = input_available(); + memmove(input_buffer, input_read_pos, available); + input_read_pos = input_buffer; + input_write_pos = input_buffer + available; } + + size_t to_write = MIN(size, input_space()); + memcpy(input_write_pos, data, to_write); + input_write_pos += to_write; } size_t input_enqueue(String keys) @@ -259,7 +278,7 @@ size_t input_enqueue(String keys) const char *ptr = keys.data; const char *end = ptr + keys.size; - while (rbuffer_space(input_buffer) >= 19 && ptr < end) { + while (input_space() >= 19 && ptr < end) { // A "<x>" form occupies at least 1 characters, and produces up // to 19 characters (1 + 5 * 3 for the char and 3 for a modifier). // In the case of K_SPECIAL (0x80), 3 bytes are escaped and needed, @@ -272,7 +291,7 @@ size_t input_enqueue(String keys) if (new_size) { new_size = handle_mouse_event(&ptr, buf, new_size); - rbuffer_write(input_buffer, (char *)buf, new_size); + input_enqueue_raw((char *)buf, new_size); continue; } @@ -293,11 +312,11 @@ size_t input_enqueue(String keys) // copy the character, escaping K_SPECIAL if ((uint8_t)(*ptr) == K_SPECIAL) { - rbuffer_write(input_buffer, (char *)&(uint8_t){ K_SPECIAL }, 1); - rbuffer_write(input_buffer, (char *)&(uint8_t){ KS_SPECIAL }, 1); - rbuffer_write(input_buffer, (char *)&(uint8_t){ KE_FILLER }, 1); + input_enqueue_raw((char *)&(uint8_t){ K_SPECIAL }, 1); + input_enqueue_raw((char *)&(uint8_t){ KS_SPECIAL }, 1); + input_enqueue_raw((char *)&(uint8_t){ KE_FILLER }, 1); } else { - rbuffer_write(input_buffer, ptr, 1); + input_enqueue_raw(ptr, 1); } ptr++; } @@ -422,7 +441,7 @@ static unsigned handle_mouse_event(const char **ptr, uint8_t *buf, unsigned bufs return bufsize; } -size_t input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col) +void input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col) { modifier |= check_multiclick(code, grid, row, col); uint8_t buf[7]; @@ -442,8 +461,7 @@ size_t input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int co mouse_col = col; size_t written = 3 + (size_t)(p - buf); - rbuffer_write(input_buffer, (char *)buf, written); - return written; + input_enqueue_raw((char *)buf, written); } /// @return true if the main loop is blocked and waiting for input. @@ -452,15 +470,22 @@ bool input_blocking(void) return blocking; } -// This is a replacement for the old `WaitForChar` function in os_unix.c -static InbufPollResult inbuf_poll(int ms, MultiQueue *events) +/// Checks for (but does not read) available input, and consumes `main_loop.events` while waiting. +/// +/// @param ms Timeout in milliseconds. -1 for indefinite wait, 0 for no wait. +/// @param events (optional) Queue to check for pending events. +/// @return TriState: +/// - kTrue: Input/events available +/// - kFalse: No input/events +/// - kNone: EOF reached on the input stream +static TriState inbuf_poll(int ms, MultiQueue *events) { if (os_input_ready(events)) { - return kInputAvail; + return kTrue; } if (do_profiling == PROF_YES && ms) { - prof_inchar_enter(); + prof_input_start(); } if ((ms == -1 || ms > 0) && events != main_loop.events && !input_eof) { @@ -468,38 +493,29 @@ static InbufPollResult inbuf_poll(int ms, MultiQueue *events) blocking = true; multiqueue_process_events(ch_before_blocking_events); } - DLOG("blocking... events_enabled=%d events_pending=%d", events != NULL, - events && !multiqueue_empty(events)); - LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms, - os_input_ready(events) || input_eof); + DLOG("blocking... events=%s", !!events ? "true" : "false"); + LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms, os_input_ready(events) || input_eof); blocking = false; if (do_profiling == PROF_YES && ms) { - prof_inchar_exit(); + prof_input_end(); } if (os_input_ready(events)) { - return kInputAvail; + return kTrue; } - return input_eof ? kInputEof : kInputNone; -} - -bool input_available(void) -{ - return rbuffer_size(input_buffer) != 0; + return input_eof ? kNone : kFalse; } -static void input_read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, bool at_eof) +static size_t input_read_cb(RStream *stream, const char *buf, size_t c, void *data, bool at_eof) { if (at_eof) { input_eof = true; } - assert(rbuffer_space(input_buffer) >= rbuffer_size(buf)); - RBUFFER_UNTIL_EMPTY(buf, ptr, len) { - (void)rbuffer_write(input_buffer, ptr, len); - rbuffer_consumed(buf, len); - } + assert(input_space() >= c); + input_enqueue_raw(buf, c); + return c; } static void process_ctrl_c(void) @@ -508,28 +524,29 @@ static void process_ctrl_c(void) return; } - size_t consume_count = 0; - RBUFFER_EACH_REVERSE(input_buffer, c, i) { - if ((uint8_t)c == Ctrl_C - || ((uint8_t)c == 'C' && i >= 3 - && (uint8_t)(*rbuffer_get(input_buffer, i - 3)) == K_SPECIAL - && (uint8_t)(*rbuffer_get(input_buffer, i - 2)) == KS_MODIFIER - && (uint8_t)(*rbuffer_get(input_buffer, i - 1)) == MOD_MASK_CTRL)) { - *rbuffer_get(input_buffer, i) = Ctrl_C; + size_t available = input_available(); + ssize_t i; + for (i = (ssize_t)available - 1; i >= 0; i--) { // Reverse-search input for Ctrl_C. + uint8_t c = (uint8_t)input_read_pos[i]; + if (c == Ctrl_C + || (c == 'C' && i >= 3 + && (uint8_t)input_read_pos[i - 3] == K_SPECIAL + && (uint8_t)input_read_pos[i - 2] == KS_MODIFIER + && (uint8_t)input_read_pos[i - 1] == MOD_MASK_CTRL)) { + input_read_pos[i] = Ctrl_C; got_int = true; - consume_count = i; break; } } - if (got_int && consume_count) { + if (got_int && i > 0) { // Remove all unprocessed input (typeahead) before the CTRL-C. - rbuffer_consumed(input_buffer, consume_count); + input_read_pos += i; } } -// Helper function used to push bytes from the 'event' key sequence partially -// between calls to os_inchar when maxlen < 3 +/// Pushes bytes from the "event" key sequence (KE_EVENT) partially between calls to input_get when +/// `maxlen < 3`. static int push_event_key(uint8_t *buf, int maxlen) { static const uint8_t key[3] = { K_SPECIAL, KS_EXTRA, KE_EVENT }; @@ -548,7 +565,7 @@ static int push_event_key(uint8_t *buf, int maxlen) bool os_input_ready(MultiQueue *events) { return (typebuf_was_filled // API call filled typeahead - || rbuffer_size(input_buffer) // Input buffer filled + || input_available() // Input buffer filled || pending_events(events)); // Events must be processed } @@ -559,7 +576,7 @@ static void read_error_exit(void) if (silent_mode) { // Normal way to exit for "nvim -es". getout(0); } - preserve_exit(_("Vim: Error reading input, exiting...\n")); + preserve_exit(_("Nvim: Error reading input, exiting...\n")); } static bool pending_events(MultiQueue *events) diff --git a/src/nvim/os/process.c b/src/nvim/os/proc.c index e8d38d5b8a..053f5f3ba0 100644 --- a/src/nvim/os/process.c +++ b/src/nvim/os/proc.c @@ -37,24 +37,24 @@ #include "nvim/log.h" #include "nvim/memory.h" -#include "nvim/os/process.h" +#include "nvim/os/proc.h" #ifdef MSWIN # include "nvim/api/private/helpers.h" #endif #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "os/process.c.generated.h" +# include "os/proc.c.generated.h" #endif #ifdef MSWIN -static bool os_proc_tree_kill_rec(HANDLE process, int sig) +static bool os_proc_tree_kill_rec(HANDLE proc, int sig) { - if (process == NULL) { + if (proc == NULL) { return false; } PROCESSENTRY32 pe; - DWORD pid = GetProcessId(process); + DWORD pid = GetProcessId(proc); if (pid != 0) { HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); @@ -77,7 +77,7 @@ static bool os_proc_tree_kill_rec(HANDLE process, int sig) } theend: - return (bool)TerminateProcess(process, (unsigned)sig); + return (bool)TerminateProcess(proc, (unsigned)sig); } /// Kills process `pid` and its descendants recursively. bool os_proc_tree_kill(int pid, int sig) @@ -230,9 +230,9 @@ int os_proc_children(int ppid, int **proc_list, size_t *proc_count) /// /// @param pid Process to inspect. /// @return Map of process properties, empty on error. -Dictionary os_proc_info(int pid, Arena *arena) +Dict os_proc_info(int pid, Arena *arena) { - Dictionary pinfo = ARRAY_DICT_INIT; + Dict pinfo = ARRAY_DICT_INIT; PROCESSENTRY32 pe; // Snapshot of all processes. This is used instead of: diff --git a/src/nvim/os/process.h b/src/nvim/os/proc.h index 3b116b4bad..1831f21cc3 100644 --- a/src/nvim/os/process.h +++ b/src/nvim/os/proc.h @@ -7,5 +7,5 @@ #endif #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "os/process.h.generated.h" +# include "os/proc.h.generated.h" #endif diff --git a/src/nvim/os/pty_conpty_win.c b/src/nvim/os/pty_conpty_win.c index e7697880af..6402330a52 100644 --- a/src/nvim/os/pty_conpty_win.c +++ b/src/nvim/os/pty_conpty_win.c @@ -143,7 +143,7 @@ finished: return conpty_object; } -bool os_conpty_spawn(conpty_t *conpty_object, HANDLE *process_handle, wchar_t *name, +bool os_conpty_spawn(conpty_t *conpty_object, HANDLE *proc_handle, wchar_t *name, wchar_t *cmd_line, wchar_t *cwd, wchar_t *env) { PROCESS_INFORMATION pi = { 0 }; @@ -159,7 +159,7 @@ bool os_conpty_spawn(conpty_t *conpty_object, HANDLE *process_handle, wchar_t *n &pi)) { return false; } - *process_handle = pi.hProcess; + *proc_handle = pi.hProcess; return true; } diff --git a/src/nvim/os/pty_proc.h b/src/nvim/os/pty_proc.h new file mode 100644 index 0000000000..d815aae69c --- /dev/null +++ b/src/nvim/os/pty_proc.h @@ -0,0 +1,7 @@ +#pragma once + +#ifdef MSWIN +# include "nvim/os/pty_proc_win.h" +#else +# include "nvim/os/pty_proc_unix.h" +#endif diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_proc_unix.c index 4d34e8fac4..3bca065d2d 100644 --- a/src/nvim/os/pty_process_unix.c +++ b/src/nvim/os/pty_proc_unix.c @@ -30,20 +30,19 @@ #endif #include "auto/config.h" -#include "klib/klist.h" #include "nvim/eval/typval.h" #include "nvim/event/defs.h" #include "nvim/event/loop.h" -#include "nvim/event/process.h" +#include "nvim/event/proc.h" #include "nvim/log.h" #include "nvim/os/fs.h" #include "nvim/os/os_defs.h" -#include "nvim/os/pty_process.h" -#include "nvim/os/pty_process_unix.h" +#include "nvim/os/pty_proc.h" +#include "nvim/os/pty_proc_unix.h" #include "nvim/types_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "os/pty_process_unix.c.generated.h" +# include "os/pty_proc_unix.c.generated.h" #endif #if defined(__sun) && !defined(HAVE_FORKPTY) @@ -158,7 +157,7 @@ static pid_t forkpty(int *amaster, char *name, struct termios *termp, struct win #endif /// @returns zero on success, or negative error code -int pty_process_spawn(PtyProcess *ptyproc) +int pty_proc_spawn(PtyProc *ptyproc) FUNC_ATTR_NONNULL_ALL { // termios initialized at first use @@ -168,8 +167,8 @@ int pty_process_spawn(PtyProcess *ptyproc) } int status = 0; // zero or negative error code (libuv convention) - Process *proc = (Process *)ptyproc; - assert(proc->err.closed); + Proc *proc = (Proc *)ptyproc; + assert(proc->err.s.closed); uv_signal_start(&proc->loop->children_watcher, chld_handler, SIGCHLD); ptyproc->winsize = (struct winsize){ ptyproc->height, ptyproc->width, 0, 0 }; uv_disable_stdio_inheritance(); @@ -208,8 +207,8 @@ int pty_process_spawn(PtyProcess *ptyproc) && (status = set_duplicating_descriptor(master, &proc->in.uv.pipe))) { goto error; } - if (!proc->out.closed - && (status = set_duplicating_descriptor(master, &proc->out.uv.pipe))) { + if (!proc->out.s.closed + && (status = set_duplicating_descriptor(master, &proc->out.s.uv.pipe))) { goto error; } @@ -224,29 +223,29 @@ error: return status; } -const char *pty_process_tty_name(PtyProcess *ptyproc) +const char *pty_proc_tty_name(PtyProc *ptyproc) { return ptsname(ptyproc->tty_fd); } -void pty_process_resize(PtyProcess *ptyproc, uint16_t width, uint16_t height) +void pty_proc_resize(PtyProc *ptyproc, uint16_t width, uint16_t height) FUNC_ATTR_NONNULL_ALL { ptyproc->winsize = (struct winsize){ height, width, 0, 0 }; ioctl(ptyproc->tty_fd, TIOCSWINSZ, &ptyproc->winsize); } -void pty_process_close(PtyProcess *ptyproc) +void pty_proc_close(PtyProc *ptyproc) FUNC_ATTR_NONNULL_ALL { - pty_process_close_master(ptyproc); - Process *proc = (Process *)ptyproc; + pty_proc_close_master(ptyproc); + Proc *proc = (Proc *)ptyproc; if (proc->internal_close_cb) { proc->internal_close_cb(proc); } } -void pty_process_close_master(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL +void pty_proc_close_master(PtyProc *ptyproc) FUNC_ATTR_NONNULL_ALL { if (ptyproc->tty_fd >= 0) { close(ptyproc->tty_fd); @@ -254,12 +253,12 @@ void pty_process_close_master(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL } } -void pty_process_teardown(Loop *loop) +void pty_proc_teardown(Loop *loop) { uv_signal_stop(&loop->children_watcher); } -static void init_child(PtyProcess *ptyproc) +static void init_child(PtyProc *ptyproc) FUNC_ATTR_NONNULL_ALL { #if defined(HAVE__NSGETENVIRON) @@ -277,13 +276,13 @@ static void init_child(PtyProcess *ptyproc) signal(SIGTERM, SIG_DFL); signal(SIGALRM, SIG_DFL); - Process *proc = (Process *)ptyproc; + Proc *proc = (Proc *)ptyproc; if (proc->cwd && os_chdir(proc->cwd) != 0) { ELOG("chdir(%s) failed: %s", proc->cwd, strerror(errno)); return; } - const char *prog = process_get_exepath(proc); + const char *prog = proc_get_exepath(proc); assert(proc->env); environ = tv_dict_to_env(proc->env); @@ -387,8 +386,8 @@ static void chld_handler(uv_signal_t *handle, int signum) Loop *loop = handle->loop->data; - kl_iter(WatcherPtr, loop->children, current) { - Process *proc = (*current)->data; + for (size_t i = 0; i < kv_size(loop->children); i++) { + Proc *proc = kv_A(loop->children, i); do { pid = waitpid(proc->pid, &stat, WNOHANG); } while (pid < 0 && errno == EINTR); @@ -406,10 +405,10 @@ static void chld_handler(uv_signal_t *handle, int signum) } } -PtyProcess pty_process_init(Loop *loop, void *data) +PtyProc pty_proc_init(Loop *loop, void *data) { - PtyProcess rv; - rv.process = process_init(loop, kProcessTypePty, data); + PtyProc rv = { 0 }; + rv.proc = proc_init(loop, kProcTypePty, data); rv.width = 80; rv.height = 24; rv.tty_fd = -1; diff --git a/src/nvim/os/pty_process_unix.h b/src/nvim/os/pty_proc_unix.h index 1a77ae5fd5..47f9af088e 100644 --- a/src/nvim/os/pty_process_unix.h +++ b/src/nvim/os/pty_proc_unix.h @@ -1,5 +1,5 @@ #pragma once -// IWYU pragma: private, include "nvim/os/pty_process.h" +// IWYU pragma: private, include "nvim/os/pty_proc.h" #include <stdint.h> #include <sys/ioctl.h> @@ -7,12 +7,12 @@ #include "nvim/event/defs.h" typedef struct { - Process process; + Proc proc; uint16_t width, height; struct winsize winsize; int tty_fd; -} PtyProcess; +} PtyProc; #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "os/pty_process_unix.h.generated.h" +# include "os/pty_proc_unix.h.generated.h" #endif diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_proc_win.c index 12831ff05f..5bd6eead51 100644 --- a/src/nvim/os/pty_process_win.c +++ b/src/nvim/os/pty_proc_win.c @@ -10,20 +10,20 @@ #include "nvim/memory.h" #include "nvim/os/os.h" #include "nvim/os/pty_conpty_win.h" -#include "nvim/os/pty_process_win.h" +#include "nvim/os/pty_proc_win.h" #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "os/pty_process_win.c.generated.h" +# include "os/pty_proc_win.c.generated.h" #endif -static void CALLBACK pty_process_finish1(void *context, BOOLEAN unused) +static void CALLBACK pty_proc_finish1(void *context, BOOLEAN unused) FUNC_ATTR_NONNULL_ALL { - PtyProcess *ptyproc = (PtyProcess *)context; - Process *proc = (Process *)ptyproc; + PtyProc *ptyproc = (PtyProc *)context; + Proc *proc = (Proc *)ptyproc; os_conpty_free(ptyproc->conpty); - // NB: pty_process_finish1() is called on a separate thread, + // NB: pty_proc_finish1() is called on a separate thread, // but the timer only works properly if it's started by the main thread. loop_schedule_fast(proc->loop, event_create(start_wait_eof_timer, ptyproc)); } @@ -31,7 +31,7 @@ static void CALLBACK pty_process_finish1(void *context, BOOLEAN unused) static void start_wait_eof_timer(void **argv) FUNC_ATTR_NONNULL_ALL { - PtyProcess *ptyproc = (PtyProcess *)argv[0]; + PtyProc *ptyproc = (PtyProc *)argv[0]; if (ptyproc->finish_wait != NULL) { uv_timer_start(&ptyproc->wait_eof_timer, wait_eof_timer_cb, 200, 200); @@ -39,15 +39,15 @@ static void start_wait_eof_timer(void **argv) } /// @returns zero on success, or negative error code. -int pty_process_spawn(PtyProcess *ptyproc) +int pty_proc_spawn(PtyProc *ptyproc) FUNC_ATTR_NONNULL_ALL { - Process *proc = (Process *)ptyproc; + Proc *proc = (Proc *)ptyproc; int status = 0; conpty_t *conpty_object = NULL; char *in_name = NULL; char *out_name = NULL; - HANDLE process_handle = NULL; + HANDLE proc_handle = NULL; uv_connect_t *in_req = NULL; uv_connect_t *out_req = NULL; wchar_t *cmd_line = NULL; @@ -55,7 +55,7 @@ int pty_process_spawn(PtyProcess *ptyproc) wchar_t *env = NULL; const char *emsg = NULL; - assert(proc->err.closed); + assert(proc->err.s.closed); if (!os_has_conpty_working() || (conpty_object = os_conpty_init(&in_name, &out_name, ptyproc->width, @@ -69,15 +69,15 @@ int pty_process_spawn(PtyProcess *ptyproc) uv_pipe_connect(in_req, &proc->in.uv.pipe, in_name, - pty_process_connect_cb); + pty_proc_connect_cb); } - if (!proc->out.closed) { + if (!proc->out.s.closed) { out_req = xmalloc(sizeof(uv_connect_t)); uv_pipe_connect(out_req, - &proc->out.uv.pipe, + &proc->out.s.uv.pipe, out_name, - pty_process_connect_cb); + pty_proc_connect_cb); } if (proc->cwd != NULL) { @@ -105,7 +105,7 @@ int pty_process_spawn(PtyProcess *ptyproc) } if (!os_conpty_spawn(conpty_object, - &process_handle, + &proc_handle, NULL, cmd_line, cwd, @@ -114,42 +114,42 @@ int pty_process_spawn(PtyProcess *ptyproc) status = (int)GetLastError(); goto cleanup; } - proc->pid = (int)GetProcessId(process_handle); + proc->pid = (int)GetProcessId(proc_handle); uv_timer_init(&proc->loop->uv, &ptyproc->wait_eof_timer); ptyproc->wait_eof_timer.data = (void *)ptyproc; if (!RegisterWaitForSingleObject(&ptyproc->finish_wait, - process_handle, - pty_process_finish1, + proc_handle, + pty_proc_finish1, ptyproc, INFINITE, WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE)) { abort(); } - // Wait until pty_process_connect_cb is called. + // Wait until pty_proc_connect_cb is called. while ((in_req != NULL && in_req->handle != NULL) || (out_req != NULL && out_req->handle != NULL)) { uv_run(&proc->loop->uv, UV_RUN_ONCE); } ptyproc->conpty = conpty_object; - ptyproc->process_handle = process_handle; + ptyproc->proc_handle = proc_handle; conpty_object = NULL; - process_handle = NULL; + proc_handle = NULL; cleanup: if (status) { // In the case of an error of MultiByteToWideChar or CreateProcessW. - ELOG("pty_process_spawn(%s): %s: error code: %d", + ELOG("pty_proc_spawn(%s): %s: error code: %d", proc->argv[0], emsg, status); status = os_translate_sys_error(status); } os_conpty_free(conpty_object); xfree(in_name); xfree(out_name); - if (process_handle != NULL) { - CloseHandle(process_handle); + if (proc_handle != NULL) { + CloseHandle(proc_handle); } xfree(in_req); xfree(out_req); @@ -159,32 +159,32 @@ cleanup: return status; } -const char *pty_process_tty_name(PtyProcess *ptyproc) +const char *pty_proc_tty_name(PtyProc *ptyproc) { return "?"; } -void pty_process_resize(PtyProcess *ptyproc, uint16_t width, uint16_t height) +void pty_proc_resize(PtyProc *ptyproc, uint16_t width, uint16_t height) FUNC_ATTR_NONNULL_ALL { os_conpty_set_size(ptyproc->conpty, width, height); } -void pty_process_close(PtyProcess *ptyproc) +void pty_proc_close(PtyProc *ptyproc) FUNC_ATTR_NONNULL_ALL { - Process *proc = (Process *)ptyproc; + Proc *proc = (Proc *)ptyproc; - pty_process_close_master(ptyproc); + pty_proc_close_master(ptyproc); if (ptyproc->finish_wait != NULL) { UnregisterWaitEx(ptyproc->finish_wait, NULL); ptyproc->finish_wait = NULL; uv_close((uv_handle_t *)&ptyproc->wait_eof_timer, NULL); } - if (ptyproc->process_handle != NULL) { - CloseHandle(ptyproc->process_handle); - ptyproc->process_handle = NULL; + if (ptyproc->proc_handle != NULL) { + CloseHandle(ptyproc->proc_handle); + ptyproc->proc_handle = NULL; } if (proc->internal_close_cb) { @@ -192,17 +192,17 @@ void pty_process_close(PtyProcess *ptyproc) } } -void pty_process_close_master(PtyProcess *ptyproc) +void pty_proc_close_master(PtyProc *ptyproc) FUNC_ATTR_NONNULL_ALL { } -void pty_process_teardown(Loop *loop) +void pty_proc_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL { } -static void pty_process_connect_cb(uv_connect_t *req, int status) +static void pty_proc_connect_cb(uv_connect_t *req, int status) FUNC_ATTR_NONNULL_ALL { assert(status == 0); @@ -212,23 +212,23 @@ static void pty_process_connect_cb(uv_connect_t *req, int status) static void wait_eof_timer_cb(uv_timer_t *wait_eof_timer) FUNC_ATTR_NONNULL_ALL { - PtyProcess *ptyproc = wait_eof_timer->data; - Process *proc = (Process *)ptyproc; + PtyProc *ptyproc = wait_eof_timer->data; + Proc *proc = (Proc *)ptyproc; assert(ptyproc->finish_wait != NULL); - if (proc->out.closed || proc->out.did_eof || !uv_is_readable(proc->out.uvstream)) { + if (proc->out.s.closed || proc->out.did_eof || !uv_is_readable(proc->out.s.uvstream)) { uv_timer_stop(&ptyproc->wait_eof_timer); - pty_process_finish2(ptyproc); + pty_proc_finish2(ptyproc); } } -static void pty_process_finish2(PtyProcess *ptyproc) +static void pty_proc_finish2(PtyProc *ptyproc) FUNC_ATTR_NONNULL_ALL { - Process *proc = (Process *)ptyproc; + Proc *proc = (Proc *)ptyproc; DWORD exit_code = 0; - GetExitCodeProcess(ptyproc->process_handle, &exit_code); + GetExitCodeProcess(ptyproc->proc_handle, &exit_code); proc->status = proc->exit_signal ? 128 + proc->exit_signal : (int)exit_code; proc->internal_exit_cb(proc); @@ -399,7 +399,7 @@ static int build_env_block(dict_T *denv, wchar_t **env_block) QUEUE_INSERT_TAIL(&env_q, &env_node->node); } - // Additional '\0' after the final entry + // Additional NUL after the final entry env_block_len++; *env_block = xmalloc(sizeof(**env_block) * env_block_len); @@ -427,14 +427,14 @@ cleanup: return rc; } -PtyProcess pty_process_init(Loop *loop, void *data) +PtyProc pty_proc_init(Loop *loop, void *data) { - PtyProcess rv; - rv.process = process_init(loop, kProcessTypePty, data); + PtyProc rv; + rv.proc = proc_init(loop, kProcTypePty, data); rv.width = 80; rv.height = 24; rv.conpty = NULL; rv.finish_wait = NULL; - rv.process_handle = NULL; + rv.proc_handle = NULL; return rv; } diff --git a/src/nvim/os/pty_process_win.h b/src/nvim/os/pty_proc_win.h index 3528f6bfe5..c2fdea506e 100644 --- a/src/nvim/os/pty_process_win.h +++ b/src/nvim/os/pty_proc_win.h @@ -1,20 +1,20 @@ #pragma once -// IWYU pragma: private, include "nvim/os/pty_process.h" +// IWYU pragma: private, include "nvim/os/pty_proc.h" #include <uv.h> -#include "nvim/event/process.h" +#include "nvim/event/proc.h" #include "nvim/lib/queue_defs.h" #include "nvim/os/pty_conpty_win.h" typedef struct pty_process { - Process process; + Proc proc; uint16_t width, height; conpty_t *conpty; HANDLE finish_wait; - HANDLE process_handle; + HANDLE proc_handle; uv_timer_t wait_eof_timer; -} PtyProcess; +} PtyProc; // Structure used by build_cmd_line() typedef struct arg_node { @@ -23,5 +23,5 @@ typedef struct arg_node { } ArgNode; #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "os/pty_process_win.h.generated.h" +# include "os/pty_proc_win.h.generated.h" #endif diff --git a/src/nvim/os/pty_process.h b/src/nvim/os/pty_process.h deleted file mode 100644 index 2c7a5f66bd..0000000000 --- a/src/nvim/os/pty_process.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#ifdef MSWIN -# include "nvim/os/pty_process_win.h" -#else -# include "nvim/os/pty_process_unix.h" -#endif diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index 2a10510b0f..efcdee9c8b 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -10,13 +10,14 @@ #include "nvim/ascii_defs.h" #include "nvim/buffer_defs.h" #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/event/defs.h" -#include "nvim/event/libuv_process.h" +#include "nvim/event/libuv_proc.h" #include "nvim/event/loop.h" #include "nvim/event/multiqueue.h" -#include "nvim/event/process.h" +#include "nvim/event/proc.h" #include "nvim/event/rstream.h" #include "nvim/event/stream.h" #include "nvim/event/wstream.h" @@ -39,8 +40,6 @@ #include "nvim/path.h" #include "nvim/pos_defs.h" #include "nvim/profile.h" -#include "nvim/rbuffer.h" -#include "nvim/rbuffer_defs.h" #include "nvim/state_defs.h" #include "nvim/strings.h" #include "nvim/tag.h" @@ -48,17 +47,11 @@ #include "nvim/ui.h" #include "nvim/vim_defs.h" -#define DYNAMIC_BUFFER_INIT { NULL, 0, 0 } #define NS_1_SECOND 1000000000U // 1 second, in nanoseconds #define OUT_DATA_THRESHOLD 1024 * 10U // 10KB, "a few screenfuls" of data. #define SHELL_SPECIAL "\t \"&'$;<>()\\|" -typedef struct { - char *data; - size_t cap, len; -} DynamicBuffer; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/shell.c.generated.h" #endif @@ -122,7 +115,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in size_t len; char *p; char *extra_shell_arg = NULL; - ShellOpts shellopts = kShellOptExpand | kShellOptSilent; + int shellopts = kShellOptExpand | kShellOptSilent; int j; char *tempname; #define STYLE_ECHO 0 // use "echo", the default @@ -255,11 +248,11 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in } else { STRCPY(command, "("); } - STRCAT(command, pat[0] + 1); // exclude first backtick + strcat(command, pat[0] + 1); // exclude first backtick p = command + strlen(command) - 1; if (is_fish_shell) { *p-- = ';'; - STRCAT(command, " end"); + strcat(command, " end"); } else { *p-- = ')'; // remove last backtick } @@ -270,7 +263,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in ampersand = true; *p = ' '; } - STRCAT(command, ">"); + strcat(command, ">"); } else { STRCPY(command, ""); if (shell_style == STYLE_GLOB) { @@ -278,26 +271,26 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in // otherwise, this may set the positional parameters for the shell, // e.g. "$*". if (flags & EW_NOTFOUND) { - STRCAT(command, "set nonomatch; "); + strcat(command, "set nonomatch; "); } else { - STRCAT(command, "unset nonomatch; "); + strcat(command, "unset nonomatch; "); } } if (shell_style == STYLE_GLOB) { - STRCAT(command, "glob >"); + strcat(command, "glob >"); } else if (shell_style == STYLE_PRINT) { - STRCAT(command, "print -N >"); + strcat(command, "print -N >"); } else if (shell_style == STYLE_VIMGLOB) { - STRCAT(command, sh_vimglob_func); + strcat(command, sh_vimglob_func); } else if (shell_style == STYLE_GLOBSTAR) { - STRCAT(command, sh_globstar_opt); - STRCAT(command, sh_vimglob_func); + strcat(command, sh_globstar_opt); + strcat(command, sh_vimglob_func); } else { - STRCAT(command, "echo >"); + strcat(command, "echo >"); } } - STRCAT(command, tempname); + strcat(command, tempname); if (shell_style != STYLE_BT) { for (i = 0; i < num_pat; i++) { @@ -341,7 +334,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in } if (ampersand) { - STRCAT(command, "&"); // put the '&' after the redirection + strcat(command, "&"); // put the '&' after the redirection } // Using zsh -G: If a pattern has no matches, it is just deleted from @@ -647,13 +640,13 @@ char *shell_argv_to_str(char **const argv) p++; } if (n < maxsize) { - rv[n - 1] = '\0'; + rv[n - 1] = NUL; } else { // Command too long, show ellipsis: "/bin/bash 'foo' 'bar'..." rv[maxsize - 4] = '.'; rv[maxsize - 3] = '.'; rv[maxsize - 2] = '.'; - rv[maxsize - 1] = '\0'; + rv[maxsize - 1] = NUL; } return rv; } @@ -666,9 +659,9 @@ char *shell_argv_to_str(char **const argv) /// @param extra_args Extra arguments to the shell, or NULL. /// /// @return shell command exit code -int os_call_shell(char *cmd, ShellOpts opts, char *extra_args) +int os_call_shell(char *cmd, int opts, char *extra_args) { - DynamicBuffer input = DYNAMIC_BUFFER_INIT; + StringBuilder input = KV_INITIAL_VALUE; char *output = NULL; char **output_ptr = NULL; int current_state = State; @@ -697,9 +690,9 @@ int os_call_shell(char *cmd, ShellOpts opts, char *extra_args) size_t nread; int exitcode = do_os_system(shell_build_argv(cmd, extra_args), - input.data, input.len, output_ptr, &nread, + input.items, input.size, output_ptr, &nread, emsg_silent, forward_output); - xfree(input.data); + kv_destroy(input); if (output) { write_output(output, nread, true); @@ -721,8 +714,10 @@ int os_call_shell(char *cmd, ShellOpts opts, char *extra_args) /// os_call_shell() wrapper. Handles 'verbose', :profile, and v:shell_error. /// Invalidates cached tags. /// +/// @param opts a combination of ShellOpts flags +/// /// @return shell command exit code -int call_shell(char *cmd, ShellOpts opts, char *extra_shell_arg) +int call_shell(char *cmd, int opts, char *extra_shell_arg) { int retval; proftime_T wait_time; @@ -766,7 +761,7 @@ int call_shell(char *cmd, ShellOpts opts, char *extra_shell_arg) /// @param ret_len length of the stdout /// /// @return an allocated string, or NULL for error. -char *get_cmd_output(char *cmd, char *infile, ShellOpts flags, size_t *ret_len) +char *get_cmd_output(char *cmd, char *infile, int flags, size_t *ret_len) { char *buffer = NULL; @@ -860,10 +855,10 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu { out_data_decide_throttle(0); // Initialize throttle decider. out_data_ring(NULL, 0); // Initialize output ring-buffer. - bool has_input = (input != NULL && input[0] != '\0'); + bool has_input = (input != NULL && input[0] != NUL); // the output buffer - DynamicBuffer buf = DYNAMIC_BUFFER_INIT; + StringBuilder buf = KV_INITIAL_VALUE; stream_read_cb data_cb = system_data_cb; if (nread) { *nread = 0; @@ -879,12 +874,12 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu char prog[MAXPATHL]; xstrlcpy(prog, argv[0], MAXPATHL); - LibuvProcess uvproc = libuv_process_init(&main_loop, &buf); - Process *proc = &uvproc.process; + LibuvProc uvproc = libuv_proc_init(&main_loop, &buf); + Proc *proc = &uvproc.proc; MultiQueue *events = multiqueue_new_child(main_loop.events); proc->events = events; proc->argv = argv; - int status = process_spawn(proc, has_input, true, true); + int status = proc_spawn(proc, has_input, true, true); if (status) { loop_poll_events(&main_loop, 0); // Failed, probably 'shell' is not executable. @@ -906,9 +901,9 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu if (has_input) { wstream_init(&proc->in, 0); } - rstream_init(&proc->out, 0); + rstream_init(&proc->out); rstream_start(&proc->out, data_cb, &buf); - rstream_init(&proc->err, 0); + rstream_init(&proc->err); rstream_start(&proc->err, data_cb, &buf); // write the input, if any @@ -917,7 +912,7 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu if (!wstream_write(&proc->in, input_buffer)) { // couldn't write, stop the process and tell the user about it - process_stop(proc); + proc_stop(proc); return -1; } // close the input stream after everything is written @@ -934,7 +929,7 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu msg_no_more = true; lines_left = -1; } - int exitcode = process_wait(proc, -1, NULL); + int exitcode = proc_wait(proc, -1, NULL); if (!got_int && out_data_decide_throttle(0)) { // Last chunk of output was skipped; display it now. out_data_ring(NULL, SIZE_MAX); @@ -951,18 +946,17 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu // prepare the out parameters if requested if (output) { - if (buf.len == 0) { + assert(nread); + if (buf.size == 0) { // no data received from the process, return NULL *output = NULL; - xfree(buf.data); + *nread = 0; + kv_destroy(buf); } else { + *nread = buf.size; // NUL-terminate to make the output directly usable as a C string - buf.data[buf.len] = NUL; - *output = buf.data; - } - - if (nread) { - *nread = buf.len; + kv_push(buf, NUL); + *output = buf.items; } } @@ -972,29 +966,11 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu return exitcode; } -/// - ensures at least `desired` bytes in buffer -/// -/// TODO(aktau): fold with kvec/garray -static void dynamic_buffer_ensure(DynamicBuffer *buf, size_t desired) +static size_t system_data_cb(RStream *stream, const char *buf, size_t count, void *data, bool eof) { - if (buf->cap >= desired) { - assert(buf->data); - return; - } - - buf->cap = desired; - kv_roundup32(buf->cap); - buf->data = xrealloc(buf->data, buf->cap); -} - -static void system_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof) -{ - DynamicBuffer *dbuf = data; - - size_t nread = buf->size; - dynamic_buffer_ensure(dbuf, dbuf->len + nread + 1); - rbuffer_read(buf, dbuf->data + dbuf->len, nread); - dbuf->len += nread; + StringBuilder *dbuf = data; + kv_concat_len(*dbuf, buf, count); + return count; } /// Tracks output received for the current executing shell command, and displays @@ -1023,7 +999,7 @@ static bool out_data_decide_throttle(size_t size) static uint64_t started = 0; // Start time of the current throttle. static size_t received = 0; // Bytes observed since last throttle. static size_t visit = 0; // "Pulse" count of the current throttle. - static char pulse_msg[] = { ' ', ' ', ' ', '\0' }; + static char pulse_msg[] = { ' ', ' ', ' ', NUL }; if (!size) { bool previous_decision = (visit > 0); @@ -1077,7 +1053,7 @@ static bool out_data_decide_throttle(size_t size) /// /// @param output Data to save, or NULL to invoke a special mode. /// @param size Length of `output`. -static void out_data_ring(char *output, size_t size) +static void out_data_ring(const char *output, size_t size) { #define MAX_CHUNK_SIZE (OUT_DATA_THRESHOLD / 2) static char last_skipped[MAX_CHUNK_SIZE]; // Saved output. @@ -1119,11 +1095,11 @@ static void out_data_ring(char *output, size_t size) /// @param output Data to append to screen lines. /// @param count Size of data. /// @param eof If true, there will be no more data output. -static void out_data_append_to_screen(char *output, size_t *count, bool eof) +static void out_data_append_to_screen(const char *output, size_t *count, bool eof) FUNC_ATTR_NONNULL_ALL { - char *p = output; - char *end = output + *count; + const char *p = output; + const char *end = output + *count; while (p < end) { if (*p == '\n' || *p == '\r' || *p == TAB || *p == BELL) { msg_putchar_attr((uint8_t)(*p), 0); @@ -1151,25 +1127,16 @@ end: ui_flush(); } -static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof) +static size_t out_data_cb(RStream *stream, const char *ptr, size_t count, void *data, bool eof) { - size_t cnt; - char *ptr = rbuffer_read_ptr(buf, &cnt); - - if (ptr != NULL && cnt > 0 - && out_data_decide_throttle(cnt)) { // Skip output above a threshold. + if (count > 0 && out_data_decide_throttle(count)) { // Skip output above a threshold. // Save the skipped output. If it is the final chunk, we display it later. - out_data_ring(ptr, cnt); - } else if (ptr != NULL) { - out_data_append_to_screen(ptr, &cnt, eof); - } - - if (cnt) { - rbuffer_consumed(buf, cnt); + out_data_ring(ptr, count); + } else if (count > 0) { + out_data_append_to_screen(ptr, &count, eof); } - // Move remaining data to start of buffer, so the buffer can never wrap around. - rbuffer_reset(buf); + return count; } /// Parses a command string into a sequence of words, taking quotes into @@ -1233,7 +1200,7 @@ static size_t word_length(const char *str) /// event loop starts. If we don't (by writing in chunks returned by `ml_get`) /// the buffer being modified might get modified by reading from the process /// before we finish writing. -static void read_input(DynamicBuffer *buf) +static void read_input(StringBuilder *buf) { size_t written = 0; size_t len = 0; @@ -1247,14 +1214,11 @@ static void read_input(DynamicBuffer *buf) } else if (lp[written] == NL) { // NL -> NUL translation len = 1; - dynamic_buffer_ensure(buf, buf->len + len); - buf->data[buf->len++] = NUL; + kv_push(*buf, NUL); } else { char *s = vim_strchr(lp + written, NL); len = s == NULL ? l : (size_t)(s - (lp + written)); - dynamic_buffer_ensure(buf, buf->len + len); - memcpy(buf->data + buf->len, lp + written, len); - buf->len += len; + kv_concat_len(*buf, lp + written, len); } if (len == l) { @@ -1263,8 +1227,7 @@ static void read_input(DynamicBuffer *buf) || (!curbuf->b_p_bin && curbuf->b_p_fixeol) || (lnum != curbuf->b_no_eol_lnum && (lnum != curbuf->b_ml.ml_line_count || curbuf->b_p_eol))) { - dynamic_buffer_ensure(buf, buf->len + 1); - buf->data[buf->len++] = NL; + kv_push(*buf, NL); } lnum++; if (lnum > curbuf->b_op_end.lnum) { @@ -1331,7 +1294,7 @@ static void shell_write_cb(Stream *stream, void *data, int status) msg_schedule_semsg(_("E5677: Error writing input to shell-command: %s"), uv_err_name(status)); } - stream_close(stream, NULL, NULL); + stream_may_close(stream, false); } /// Applies 'shellxescape' (p_sxe) and 'shellxquote' (p_sxq) to a command. diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c index e5bdd56fe6..e9a74d197f 100644 --- a/src/nvim/os/stdpaths.c +++ b/src/nvim/os/stdpaths.c @@ -63,22 +63,32 @@ static const char *const xdg_defaults[] = { #endif }; -/// Get the value of $NVIM_APPNAME or "nvim" if not set. +/// Gets the value of $NVIM_APPNAME, or "nvim" if not set. +/// +/// @param namelike Write "name-like" value (no path separators) in `NameBuff`. /// /// @return $NVIM_APPNAME value -const char *get_appname(void) +const char *get_appname(bool namelike) { const char *env_val = os_getenv("NVIM_APPNAME"); - if (env_val == NULL || *env_val == '\0') { + if (env_val == NULL || *env_val == NUL) { env_val = "nvim"; } + + if (namelike) { + // Appname may be a relative path, replace slashes to make it name-like. + xstrlcpy(NameBuff, env_val, sizeof(NameBuff)); + memchrsub(NameBuff, '/', '-', sizeof(NameBuff)); + memchrsub(NameBuff, '\\', '-', sizeof(NameBuff)); + } + return env_val; } /// Ensure that APPNAME is valid. Must be a name or relative path. bool appname_is_valid(void) { - const char *appname = get_appname(); + const char *appname = get_appname(false); if (path_is_absolute(appname) // TODO(justinmk): on Windows, path_is_absolute says "/" is NOT absolute. Should it? || strequal(appname, "/") @@ -193,7 +203,7 @@ char *get_xdg_home(const XDGVarType idx) FUNC_ATTR_WARN_UNUSED_RESULT { char *dir = stdpaths_get_xdg_var(idx); - const char *appname = get_appname(); + const char *appname = get_appname(false); size_t appname_len = strlen(appname); assert(appname_len < (IOSIZE - sizeof("-data"))); diff --git a/src/nvim/path.c b/src/nvim/path.c index d782d1a989..9cce504831 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -8,23 +8,17 @@ #include "auto/config.h" #include "nvim/ascii_defs.h" -#include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/eval.h" -#include "nvim/eval/typval_defs.h" #include "nvim/ex_docmd.h" -#include "nvim/file_search.h" #include "nvim/fileio.h" #include "nvim/garray.h" -#include "nvim/gettext_defs.h" #include "nvim/globals.h" #include "nvim/macros_defs.h" #include "nvim/mbyte.h" #include "nvim/memory.h" -#include "nvim/message.h" #include "nvim/option.h" -#include "nvim/option_defs.h" #include "nvim/option_vars.h" #include "nvim/os/fs.h" #include "nvim/os/fs_defs.h" @@ -37,7 +31,6 @@ #include "nvim/regexp_defs.h" #include "nvim/strings.h" #include "nvim/vim_defs.h" -#include "nvim/window.h" enum { URL_SLASH = 1, // path_is_url() has found ":/" @@ -390,14 +383,14 @@ int path_fnamencmp(const char *const fname1, const char *const fname2, size_t le c2 = utf_ptr2char(p2); if ((c1 == NUL || c2 == NUL || (!((c1 == '/' || c1 == '\\') && (c2 == '\\' || c2 == '/')))) - && (p_fic ? (c1 != c2 && CH_FOLD(c1) != CH_FOLD(c2)) : c1 != c2)) { + && (p_fic ? (c1 != c2 && utf_fold(c1) != utf_fold(c2)) : c1 != c2)) { break; } len -= (size_t)utfc_ptr2len(p1); p1 += utfc_ptr2len(p1); p2 += utfc_ptr2len(p2); } - return p_fic ? CH_FOLD(c1) - CH_FOLD(c2) : c1 - c2; + return p_fic ? utf_fold(c1) - utf_fold(c2) : c1 - c2; #else if (p_fic) { return mb_strnicmp(fname1, fname2, len); @@ -842,17 +835,18 @@ static bool is_unique(char *maybe_unique, garray_T *gap, int i) return true; // no match found } -// Split the 'path' option into an array of strings in garray_T. Relative -// paths are expanded to their equivalent fullpath. This includes the "." -// (relative to current buffer directory) and empty path (relative to current -// directory) notations. -// -// TODO(vim): handle upward search (;) and path limiter (**N) notations by -// expanding each into their equivalent path(s). -static void expand_path_option(char *curdir, garray_T *gap) +/// Split the 'path' option into an array of strings in garray_T. Relative +/// paths are expanded to their equivalent fullpath. This includes the "." +/// (relative to current buffer directory) and empty path (relative to current +/// directory) notations. +/// +/// @param path_option p_path or p_cdpath +/// +/// TODO(vim): handle upward search (;) and path limiter (**N) notations by +/// expanding each into their equivalent path(s). +static void expand_path_option(char *curdir, char *path_option, garray_T *gap) FUNC_ATTR_NONNULL_ALL { - char *path_option = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; char *buf = xmalloc(MAXPATHL); while (*path_option != NUL) { @@ -942,7 +936,9 @@ static char *get_path_cutoff(char *fname, garray_T *gap) /// Sorts, removes duplicates and modifies all the fullpath names in "gap" so /// that they are unique with respect to each other while conserving the part /// that matches the pattern. Beware, this is at least O(n^2) wrt "gap->ga_len". -static void uniquefy_paths(garray_T *gap, char *pattern) +/// +/// @param path_option p_path or p_cdpath +static void uniquefy_paths(garray_T *gap, char *pattern, char *path_option) FUNC_ATTR_NONNULL_ALL { char **fnames = gap->ga_data; @@ -962,8 +958,8 @@ static void uniquefy_paths(garray_T *gap, char *pattern) char *file_pattern = xmalloc(len + 2); file_pattern[0] = '*'; file_pattern[1] = NUL; - STRCAT(file_pattern, pattern); - char *pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, true); + strcat(file_pattern, pattern); + char *pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, false); xfree(file_pattern); if (pat == NULL) { return; @@ -978,7 +974,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern) char *curdir = xmalloc(MAXPATHL); os_dirname(curdir, MAXPATHL); - expand_path_option(curdir, &path_ga); + expand_path_option(curdir, path_option, &path_ga); in_curdir = xcalloc((size_t)gap->ga_len, sizeof(char *)); @@ -1065,7 +1061,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern) rel_path = xmalloc(strlen(short_name) + strlen(PATHSEPSTR) + 2); STRCPY(rel_path, "."); add_pathsep(rel_path); - STRCAT(rel_path, short_name); + strcat(rel_path, short_name); xfree(fnames[i]); fnames[i] = rel_path; @@ -1127,12 +1123,17 @@ static int expand_in_path(garray_T *const gap, char *const pattern, const int fl FUNC_ATTR_NONNULL_ALL { garray_T path_ga; + char *path_option = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; char *const curdir = xmalloc(MAXPATHL); os_dirname(curdir, MAXPATHL); ga_init(&path_ga, (int)sizeof(char *), 1); - expand_path_option(curdir, &path_ga); + if (flags & EW_CDPATH) { + expand_path_option(curdir, p_cdpath, &path_ga); + } else { + expand_path_option(curdir, path_option, &path_ga); + } xfree(curdir); if (GA_EMPTY(&path_ga)) { return 0; @@ -1148,7 +1149,7 @@ static int expand_in_path(garray_T *const gap, char *const pattern, const int fl if (flags & EW_ADDSLASH) { glob_flags |= WILD_ADD_SLASH; } - globpath(paths, pattern, gap, glob_flags, false); + globpath(paths, pattern, gap, glob_flags, !!(flags & EW_CDPATH)); xfree(paths); return gap->ga_len; @@ -1229,6 +1230,7 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i static bool recursive = false; int add_pat; bool did_expand_in_path = false; + char *path_option = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; // expand_env() is called to expand things like "~user". If this fails, // it calls ExpandOne(), which brings us back here. In this case, always @@ -1302,7 +1304,7 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i // Otherwise: Add the file name if it exists or when EW_NOTFOUND is // given. if (path_has_exp_wildcard(p) || (flags & EW_ICASE)) { - if ((flags & EW_PATH) + if ((flags & (EW_PATH | EW_CDPATH)) && !path_is_absolute(p) && !(p[0] == '.' && (vim_ispathsep(p[1]) @@ -1338,8 +1340,8 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i } } - if (did_expand_in_path && !GA_EMPTY(&ga) && (flags & EW_PATH)) { - uniquefy_paths(&ga, p); + if (did_expand_in_path && !GA_EMPTY(&ga) && (flags & (EW_PATH | EW_CDPATH))) { + uniquefy_paths(&ga, p, path_option); } if (p != pat[i]) { xfree(p); @@ -1389,7 +1391,7 @@ static int expand_backtick(garray_T *gap, char *pat, int flags) char *cmd = xmemdupz(pat + 1, strlen(pat) - 2); if (*cmd == '=') { // `={expr}`: Expand expression - buffer = eval_to_string(cmd + 1, true); + buffer = eval_to_string(cmd + 1, true, false); } else { buffer = get_cmd_output(cmd, NULL, (flags & EW_SILENT) ? kShellOptSilent : 0, NULL); } @@ -1678,86 +1680,6 @@ void simplify_filename(char *filename) } while (*p != NUL); } -static char *eval_includeexpr(const char *const ptr, const size_t len) -{ - const sctx_T save_sctx = current_sctx; - set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len); - current_sctx = curbuf->b_p_script_ctx[BV_INEX].script_ctx; - - char *res = eval_to_string_safe(curbuf->b_p_inex, - was_set_insecurely(curwin, kOptIncludeexpr, OPT_LOCAL)); - - set_vim_var_string(VV_FNAME, NULL, 0); - current_sctx = save_sctx; - return res; -} - -/// Return the name of the file ptr[len] in 'path'. -/// Otherwise like file_name_at_cursor(). -/// -/// @param rel_fname file we are searching relative to -char *find_file_name_in_path(char *ptr, size_t len, int options, long count, char *rel_fname) -{ - char *file_name; - char *tofree = NULL; - - if (len == 0) { - return NULL; - } - - if ((options & FNAME_INCL) && *curbuf->b_p_inex != NUL) { - tofree = eval_includeexpr(ptr, len); - if (tofree != NULL) { - ptr = tofree; - len = strlen(ptr); - } - } - - if (options & FNAME_EXP) { - char *file_to_find = NULL; - char *search_ctx = NULL; - - file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS, - true, rel_fname, &file_to_find, &search_ctx); - - // If the file could not be found in a normal way, try applying - // 'includeexpr' (unless done already). - if (file_name == NULL - && !(options & FNAME_INCL) && *curbuf->b_p_inex != NUL) { - tofree = eval_includeexpr(ptr, len); - if (tofree != NULL) { - ptr = tofree; - len = strlen(ptr); - file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS, - true, rel_fname, &file_to_find, &search_ctx); - } - } - if (file_name == NULL && (options & FNAME_MESS)) { - char c = ptr[len]; - ptr[len] = NUL; - semsg(_("E447: Can't find file \"%s\" in path"), ptr); - ptr[len] = c; - } - - // Repeat finding the file "count" times. This matters when it - // appears several times in the path. - while (file_name != NULL && --count > 0) { - xfree(file_name); - file_name = find_file_in_path(ptr, len, options, false, rel_fname, - &file_to_find, &search_ctx); - } - - xfree(file_to_find); - vim_findfile_cleanup(search_ctx); - } else { - file_name = xstrnsave(ptr, len); - } - - xfree(tofree); - - return file_name; -} - /// Checks for a Windows drive letter ("C:/") at the start of the path. /// /// @see https://url.spec.whatwg.org/#start-with-a-windows-drive-letter @@ -2384,11 +2306,19 @@ static int path_to_absolute(const char *fname, char *buf, size_t len, int force) p = strrchr(fname, '\\'); } #endif + if (p == NULL && strcmp(fname, "..") == 0) { + // Handle ".." without path separators. + p = fname + 2; + } if (p != NULL) { + if (vim_ispathsep_nocolon(*p) && strcmp(p + 1, "..") == 0) { + // For "/path/dir/.." include the "/..". + p += 3; + } assert(p >= fname); memcpy(relative_directory, fname, (size_t)(p - fname + 1)); relative_directory[p - fname + 1] = NUL; - end_of_path = p + 1; + end_of_path = (vim_ispathsep_nocolon(*p) ? p + 1 : p); } else { relative_directory[0] = NUL; } diff --git a/src/nvim/path.h b/src/nvim/path.h index a8eb893bb3..26c2bdf14e 100644 --- a/src/nvim/path.h +++ b/src/nvim/path.h @@ -25,7 +25,8 @@ enum { EW_DODOT = 0x4000, ///< also files starting with a dot EW_EMPTYOK = 0x8000, ///< no matches is not an error EW_NOTENV = 0x10000, ///< do not expand environment variables - EW_NOBREAK = 0x20000, ///< do not invoke breakcheck + EW_CDPATH = 0x20000, ///< search in 'cdpath' too + EW_NOBREAK = 0x40000, ///< do not invoke breakcheck }; // Note: mostly EW_NOTFOUND and EW_SILENT are mutually exclusive: EW_NOTFOUND // is used when executing commands and EW_SILENT for interactive expanding. diff --git a/src/nvim/plines.c b/src/nvim/plines.c index 5881d34c48..9bf486fb06 100644 --- a/src/nvim/plines.c +++ b/src/nvim/plines.c @@ -5,6 +5,7 @@ #include <stdint.h> #include <string.h> +#include "nvim/api/extmark.h" #include "nvim/ascii_defs.h" #include "nvim/buffer.h" #include "nvim/buffer_defs.h" @@ -145,8 +146,8 @@ CharSize charsize_regular(CharsizeArg *csarg, char *const cur, colnr_T const vco } else if (cur_char < 0) { size = kInvalidByteCells; } else { - size = char2cells(cur_char); - is_doublewidth = size == 2 && cur_char > 0x80; + size = ptr2cells(cur); + is_doublewidth = size == 2 && cur_char >= 0x80; } if (csarg->virt_row >= 0) { @@ -157,8 +158,7 @@ CharSize charsize_regular(CharsizeArg *csarg, char *const cur, colnr_T const vco if (mark.pos.row != csarg->virt_row || mark.pos.col > col) { break; } else if (mark.pos.col == col) { - if (!mt_end(mark) && (mark.flags & MT_FLAG_DECOR_VIRT_TEXT_INLINE) - && mt_scoped_in_win(mark, wp)) { + if (!mt_invalid(mark) && ns_in_win(mark.ns, wp)) { DecorInline decor = mt_decor(mark); DecorVirtText *vt = decor.ext ? decor.data.ext.vt : NULL; while (vt) { @@ -267,7 +267,7 @@ CharSize charsize_regular(CharsizeArg *csarg, char *const cur, colnr_T const vco head += (max_head_vcol - (vcol + head_prev + prev_rem) + width2 - 1) / width2 * head_mid; } else if (max_head_vcol < 0) { - int off = virt_text_cursor_off(csarg, *cur == NUL); + int off = mb_added + virt_text_cursor_off(csarg, *cur == NUL); if (off >= prev_rem) { if (size > off) { head += (1 + (off - prev_rem) / width) * head_mid; @@ -337,8 +337,8 @@ CharSize charsize_regular(CharsizeArg *csarg, char *const cur, colnr_T const vco /// /// @see charsize_regular /// @see charsize_fast -static inline CharSize charsize_fast_impl(win_T *const wp, bool use_tabstop, colnr_T const vcol, - int32_t const cur_char) +static inline CharSize charsize_fast_impl(win_T *const wp, const char *cur, bool use_tabstop, + colnr_T const vcol, int32_t const cur_char) FUNC_ATTR_PURE FUNC_ATTR_ALWAYS_INLINE { // A tab gets expanded, depending on the current column @@ -352,7 +352,11 @@ static inline CharSize charsize_fast_impl(win_T *const wp, bool use_tabstop, col if (cur_char < 0) { width = kInvalidByteCells; } else { - width = char2cells(cur_char); + // TODO(bfredl): perf: often cur_char is enough at this point to determine width. + // we likely want a specialized version of utf_ptr2StrCharInfo also determining + // the ptr2cells width at the same time without any extra decoding. (also applies + // to charsize_regular and charsize_nowrap) + width = ptr2cells(cur); } // If a double-width char doesn't fit at the end of a line, it wraps to the next line, @@ -371,23 +375,23 @@ static inline CharSize charsize_fast_impl(win_T *const wp, bool use_tabstop, col /// Can be used if CSType is kCharsizeFast. /// /// @see charsize_regular -CharSize charsize_fast(CharsizeArg *csarg, colnr_T const vcol, int32_t const cur_char) +CharSize charsize_fast(CharsizeArg *csarg, const char *cur, colnr_T vcol, int32_t cur_char) FUNC_ATTR_PURE { - return charsize_fast_impl(csarg->win, csarg->use_tabstop, vcol, cur_char); + return charsize_fast_impl(csarg->win, cur, csarg->use_tabstop, vcol, cur_char); } /// Get the number of cells taken up on the screen at given virtual column. /// /// @see win_chartabsize() -int charsize_nowrap(buf_T *buf, bool use_tabstop, colnr_T vcol, int32_t cur_char) +int charsize_nowrap(buf_T *buf, const char *cur, bool use_tabstop, colnr_T vcol, int32_t cur_char) { if (cur_char == TAB && use_tabstop) { return tabstop_padding(vcol, buf->b_p_ts, buf->b_p_vts_array); } else if (cur_char < 0) { return kInvalidByteCells; } else { - return char2cells(cur_char); + return ptr2cells(cur); } } @@ -467,7 +471,7 @@ int linesize_fast(CharsizeArg const *const csarg, int vcol_arg, colnr_T const le StrCharInfo ci = utf_ptr2StrCharInfo(line); while (ci.ptr - line < len && *ci.ptr != NUL) { - vcol += charsize_fast_impl(wp, use_tabstop, vcol_arg, ci.chr.value).width; + vcol += charsize_fast_impl(wp, ci.ptr, use_tabstop, vcol_arg, ci.chr.value).width; ci = utfc_next(ci); if (vcol > MAXCOL) { vcol_arg = MAXCOL; @@ -512,7 +516,7 @@ static int virt_text_cursor_off(const CharsizeArg *csarg, bool on_NUL) void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end) { char *const line = ml_get_buf(wp->w_buffer, pos->lnum); // start of the line - int const end_col = pos->col; + colnr_T const end_col = pos->col; CharsizeArg csarg; bool on_NUL = false; @@ -530,7 +534,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en char_size = (CharSize){ .width = 1 }; break; } - char_size = charsize_fast_impl(wp, use_tabstop, vcol, ci.chr.value); + char_size = charsize_fast_impl(wp, ci.ptr, use_tabstop, vcol, ci.chr.value); StrCharInfo const next = utfc_next(ci); if (next.ptr - line > end_col) { break; @@ -556,6 +560,10 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en } } + if (*ci.ptr == NUL && end_col < MAXCOL && end_col > ci.ptr - line) { + pos->col = (colnr_T)(ci.ptr - line); + } + int head = char_size.head; int incr = char_size.width; @@ -627,7 +635,7 @@ void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *e if (pos->col < ml_get_buf_len(wp->w_buffer, pos->lnum)) { int c = utf_ptr2char(ptr + pos->col); if ((c != TAB) && vim_isprintc(c)) { - endadd = (colnr_T)(char2cells(c) - 1); + endadd = (colnr_T)(ptr2cells(ptr + pos->col) - 1); if (coladd > endadd) { // past end of line endadd = 0; @@ -712,7 +720,7 @@ bool win_may_fill(win_T *wp) /// @return Number of filler lines above lnum int win_get_fill(win_T *wp, linenr_T lnum) { - int virt_lines = decor_virt_lines(wp, lnum, NULL, kNone); + int virt_lines = decor_virt_lines(wp, lnum - 1, lnum, NULL, true); // be quick when there are no filler lines if (diffopt_filler()) { @@ -824,7 +832,7 @@ int plines_win_col(win_T *wp, linenr_T lnum, long column) if (cstype == kCharsizeFast) { bool const use_tabstop = csarg.use_tabstop; while (*ci.ptr != NUL && --column >= 0) { - vcol += charsize_fast_impl(wp, use_tabstop, vcol, ci.chr.value).width; + vcol += charsize_fast_impl(wp, ci.ptr, use_tabstop, vcol, ci.chr.value).width; ci = utfc_next(ci); } } else { @@ -906,6 +914,25 @@ int plines_m_win(win_T *wp, linenr_T first, linenr_T last, int max) return MIN(max, count); } +/// Return number of window lines a physical line range will occupy. +/// Only considers real and filler lines. +/// +/// Mainly used for calculating scrolling offsets. +int plines_m_win_fill(win_T *wp, linenr_T first, linenr_T last) +{ + int count = last - first + 1 + decor_virt_lines(wp, first - 1, last, NULL, false); + + if (diffopt_filler()) { + for (int lnum = first; lnum <= last; lnum++) { + // Note: this also considers folds. + int n = diff_check(wp, lnum); + count += MAX(n, 0); + } + } + + return MAX(count, 0); +} + /// Get the number of screen lines a range of text will take in window "wp". /// /// @param[in] start_lnum Starting line number, 1-based inclusive. diff --git a/src/nvim/plines.h b/src/nvim/plines.h index 658206e1be..50310b8ce1 100644 --- a/src/nvim/plines.h +++ b/src/nvim/plines.h @@ -3,7 +3,6 @@ #include <stdbool.h> #include <stdint.h> -#include "nvim/func_attr.h" #include "nvim/marktree_defs.h" #include "nvim/pos_defs.h" #include "nvim/types_defs.h" @@ -39,12 +38,9 @@ typedef struct { #ifdef INCLUDE_GENERATED_DECLARATIONS # include "plines.h.generated.h" +# include "plines.h.inline.generated.h" #endif -static inline CharSize win_charsize(CSType cstype, int vcol, char *ptr, int32_t chr, - CharsizeArg *csarg) - REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_ALWAYS_INLINE; - /// Get the number of cells taken up on the screen by the given character at vcol. /// "csarg->cur_text_width_left" and "csarg->cur_text_width_right" are set /// to the extra size for inline virtual text. @@ -55,17 +51,15 @@ static inline CharSize win_charsize(CSType cstype, int vcol, char *ptr, int32_t /// of 'showbreak'/'breakindent' before where cursor should be placed. static inline CharSize win_charsize(CSType cstype, int vcol, char *ptr, int32_t chr, CharsizeArg *csarg) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE { if (cstype == kCharsizeFast) { - return charsize_fast(csarg, vcol, chr); + return charsize_fast(csarg, ptr, vcol, chr); } else { return charsize_regular(csarg, ptr, vcol, chr); } } -static inline int linetabsize_str(char *s) - REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_ALWAYS_INLINE; - /// Return the number of cells the string "s" will take on the screen, /// taking into account the size of a tab. /// @@ -73,13 +67,11 @@ static inline int linetabsize_str(char *s) /// /// @return Number of cells the string will take on the screen. static inline int linetabsize_str(char *s) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE { return linetabsize_col(0, s); } -static inline int win_linetabsize(win_T *wp, linenr_T lnum, char *line, colnr_T len) - REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_ALWAYS_INLINE; - /// Like linetabsize_str(), but for a given window instead of the current one. /// /// @param wp @@ -88,6 +80,7 @@ static inline int win_linetabsize(win_T *wp, linenr_T lnum, char *line, colnr_T /// /// @return Number of cells the string will take on the screen. static inline int win_linetabsize(win_T *wp, linenr_T lnum, char *line, colnr_T len) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE { CharsizeArg csarg; CSType const cstype = init_charsize_arg(&csarg, wp, lnum, line); diff --git a/src/nvim/po/CMakeLists.txt b/src/nvim/po/CMakeLists.txt index 6c2008926a..348ba2881c 100644 --- a/src/nvim/po/CMakeLists.txt +++ b/src/nvim/po/CMakeLists.txt @@ -54,13 +54,15 @@ if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG) add_custom_command( OUTPUT ${NVIM_POT} COMMAND $<TARGET_FILE:nvim_bin> -u NONE -i NONE -n --headless --cmd "set cpo+=+" - -S ${CMAKE_CURRENT_SOURCE_DIR}/tojavascript.vim ${NVIM_POT} ${PROJECT_SOURCE_DIR}/runtime/optwin.vim + -c "silent source ${CMAKE_CURRENT_SOURCE_DIR}/tojavascript.vim" + ${NVIM_POT} ${PROJECT_SOURCE_DIR}/runtime/optwin.vim COMMAND ${XGETTEXT_PRG} -o ${NVIM_POT} --default-domain=nvim --add-comments --keyword=_ --keyword=N_ --keyword=NGETTEXT:1,2 -D ${CMAKE_CURRENT_SOURCE_DIR} -D ${CMAKE_CURRENT_BINARY_DIR} ${NVIM_RELATIVE_SOURCES} optwin.js COMMAND $<TARGET_FILE:nvim_bin> -u NONE -i NONE -n --headless --cmd "set cpo+=+" - -S ${CMAKE_CURRENT_SOURCE_DIR}/fixfilenames.vim ${NVIM_POT} ../../../runtime/optwin.vim + -c "silent source ${CMAKE_CURRENT_SOURCE_DIR}/fixfilenames.vim" + ${NVIM_POT} ${PROJECT_SOURCE_DIR}/runtime/optwin.vim VERBATIM DEPENDS ${NVIM_SOURCES} nvim_bin nvim_runtime_deps) diff --git a/src/nvim/po/af.po b/src/nvim/po/af.po index 92a1a6ca3c..64acd93f57 100644 --- a/src/nvim/po/af.po +++ b/src/nvim/po/af.po @@ -315,7 +315,7 @@ msgstr " Bevelreëlvoltooiing (^V^N^P)" #~ msgstr " Etiketvoltooiing (^]^N^P)" #, fuzzy -#~ msgid " Spelling suggestion (s^N^P)" +#~ msgid " Spelling suggestion (^S^N^P)" #~ msgstr " Hele-reël voltooiing (^L^N^P)" msgid " Keyword Local completion (^N^P)" @@ -3608,8 +3608,8 @@ msgstr "" #~ "\n" #~ "(2) 'n Bewerkingsessie van hierdie lêer het ineengestort.\n" -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Indien wel, gebruik \":recover\" of \"vim -r" +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Indien wel, gebruik \":recover\" of \"nvim -r" msgid "" "\"\n" diff --git a/src/nvim/po/ca.po b/src/nvim/po/ca.po index 964fcc9325..44975d9161 100644 --- a/src/nvim/po/ca.po +++ b/src/nvim/po/ca.po @@ -393,8 +393,8 @@ msgid " Omni completion (^O^N^P)" msgstr " Omni-compleció (^O^N^P)" #: ../edit.c:96 -msgid " Spelling suggestion (s^N^P)" -msgstr "Suggeriment ortogràfic (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr "Suggeriment ortogràfic (^S^N^P)" # buscar un nom, en lloc del verb «completar». eac #: ../edit.c:97 @@ -4015,8 +4015,8 @@ msgstr "" "(2) El Vim s'ha estrellat mentre s'editava aquest fitxer.\n" #: ../memline.c:3247 -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " En aquest cas, useu \":recover\" o bé \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " En aquest cas, useu \":recover\" o bé \"nvim -r " #: ../memline.c:3249 msgid "" diff --git a/src/nvim/po/cs.cp1250.po b/src/nvim/po/cs.cp1250.po index b939139fb5..43b6c82960 100644 --- a/src/nvim/po/cs.cp1250.po +++ b/src/nvim/po/cs.cp1250.po @@ -404,7 +404,7 @@ msgid " Omni completion (^O^N^P)" msgstr " Doplòování tagù (^I/^N/^P)" #: ../edit.c:96 -msgid " Spelling suggestion (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" msgstr "" #: ../edit.c:97 @@ -4077,8 +4077,8 @@ msgstr "" "(2) Editace tohoto souboru byla pøerušena neèekaným ukonèením programu.\n" #: ../memline.c:3247 -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Je-li tomu tak, pak použijte \":recover\" èi \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Je-li tomu tak, pak použijte \":recover\" èi \"nvim -r " #: ../memline.c:3249 msgid "" diff --git a/src/nvim/po/cs.po b/src/nvim/po/cs.po index f98dc2828e..7df69e061f 100644 --- a/src/nvim/po/cs.po +++ b/src/nvim/po/cs.po @@ -404,7 +404,7 @@ msgid " Omni completion (^O^N^P)" msgstr " Doplòování tagù (^I/^N/^P)" #: ../edit.c:96 -msgid " Spelling suggestion (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" msgstr "" #: ../edit.c:97 @@ -4077,8 +4077,8 @@ msgstr "" "(2) Editace tohoto souboru byla pøeru¹ena neèekaným ukonèením programu.\n" #: ../memline.c:3247 -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Je-li tomu tak, pak pou¾ijte \":recover\" èi \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Je-li tomu tak, pak pou¾ijte \":recover\" èi \"nvim -r " #: ../memline.c:3249 msgid "" diff --git a/src/nvim/po/da.po b/src/nvim/po/da.po index ba0301589c..c65477bf13 100644 --- a/src/nvim/po/da.po +++ b/src/nvim/po/da.po @@ -403,8 +403,8 @@ msgstr " Fuldførelse af brugerdefineret (^U^N^P)" msgid " Omni completion (^O^N^P)" msgstr " Fuldførelse af omni (^O^N^P)" -msgid " Spelling suggestion (s^N^P)" -msgstr " Staveforslag (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr " Staveforslag (^S^N^P)" msgid " Keyword Local completion (^N^P)" msgstr " Fuldførelse af nøgleord local (^N^P)" @@ -3663,8 +3663,8 @@ msgstr "" msgid "(2) An edit session for this file crashed.\n" msgstr "(2) En redigeringssession for filen holdt op med at virke.\n" -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Hvis det er tilfældet, sÃ¥ brug \":recover\" eller \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Hvis det er tilfældet, sÃ¥ brug \":recover\" eller \"nvim -r " msgid "" "\"\n" diff --git a/src/nvim/po/de.po b/src/nvim/po/de.po index efd52d3efe..0d1195eecf 100644 --- a/src/nvim/po/de.po +++ b/src/nvim/po/de.po @@ -397,8 +397,8 @@ msgid " Omni completion (^O^N^P)" msgstr " Omni-Ergänzung (^O^N^P)" #: ../edit.c:97 -msgid " Spelling suggestion (s^N^P)" -msgstr " Vorschlag der Rechtschreibprüfung (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr " Vorschlag der Rechtschreibprüfung (^S^N^P)" #: ../edit.c:98 msgid " Keyword Local completion (^N^P)" @@ -3436,9 +3436,9 @@ msgid "(2) An edit session for this file crashed.\n" msgstr "(2) Eine Sitzung für diese Datei ist abgestürzt.\n" #: ../memline.c:3204 -msgid " If this is the case, use \":recover\" or \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " msgstr "" -" Wenn dies der Fall ist, so verwenden Sie \":recover\" oder \"vim -r " +" Wenn dies der Fall ist, so verwenden Sie \":recover\" oder \"nvim -r " #: ../memline.c:3206 msgid "" diff --git a/src/nvim/po/en_GB.po b/src/nvim/po/en_GB.po index 1c03b305f9..7b849d4e68 100644 --- a/src/nvim/po/en_GB.po +++ b/src/nvim/po/en_GB.po @@ -386,7 +386,7 @@ msgid " Omni completion (^O^N^P)" msgstr "" #: ../edit.c:96 -msgid " Spelling suggestion (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" msgstr "" #: ../edit.c:97 @@ -3847,7 +3847,7 @@ msgid "(2) An edit session for this file crashed.\n" msgstr "" #: ../memline.c:3247 -msgid " If this is the case, use \":recover\" or \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " msgstr "" #: ../memline.c:3249 diff --git a/src/nvim/po/eo.po b/src/nvim/po/eo.po index f619c4c408..5cd18ad24b 100644 --- a/src/nvim/po/eo.po +++ b/src/nvim/po/eo.po @@ -410,8 +410,8 @@ msgstr " Kompletigo difinita de uzanto (^U^N^P)" msgid " Omni completion (^O^N^P)" msgstr " Kompletigo Omni (^O^N^P)" -msgid " Spelling suggestion (s^N^P)" -msgstr " Sugesto de literumo (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr " Sugesto de literumo (^S^N^P)" msgid " Keyword Local completion (^N^P)" msgstr " Kompletigo loka de Ålosilvorto (^N/^P)" @@ -3531,8 +3531,8 @@ msgstr "" msgid "(2) An edit session for this file crashed.\n" msgstr "(2) Redakta seanco de tiu dosiero kolapsis.\n" -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Se veras, uzu \":recover\" aÅ \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Se veras, uzu \":recover\" aÅ \"nvim -r " msgid "" "\"\n" diff --git a/src/nvim/po/es.po b/src/nvim/po/es.po index 120a29af15..292ca15264 100644 --- a/src/nvim/po/es.po +++ b/src/nvim/po/es.po @@ -387,8 +387,8 @@ msgid " Omni completion (^O^N^P)" msgstr " Completar con método Omni (^O^N^P)" #: ../edit.c:96 -msgid " Spelling suggestion (s^N^P)" -msgstr " Sugerencia de ortografÃa (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr " Sugerencia de ortografÃa (^S^N^P)" # Scroll has it's own msgs, in it's place there is the msg for local # * ctrl_x_mode = 0 (eg continue_status & CONT_LOCAL) -- Acevedo @@ -4078,8 +4078,8 @@ msgstr "" "(2) Falló una sesión de edición de este archivo.\n" #: ../memline.c:3247 -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Si es asÃ, use \":recover\" o \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Si es asÃ, use \":recover\" o \"nvim -r " #: ../memline.c:3249 msgid "" diff --git a/src/nvim/po/fi.po b/src/nvim/po/fi.po index ab6acf685f..c9cad6cc69 100644 --- a/src/nvim/po/fi.po +++ b/src/nvim/po/fi.po @@ -526,8 +526,8 @@ msgstr " Käyttäjän määrittelemä täydennys (^U^N^P)" msgid " Omni completion (^O^N^P)" msgstr " Omnitäydennys (^O^N^P)" -msgid " Spelling suggestion (s^N^P)" -msgstr " Oikaisulukuehdotus (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr " Oikaisulukuehdotus (^S^N^P)" msgid " Keyword Local completion (^N^P)" msgstr " Avainsanan paikallinen täydennys (^N^P)" @@ -3660,8 +3660,8 @@ msgstr "" msgid "(2) An edit session for this file crashed.\n" msgstr "(2) Tiedostonmuokkausistunto on kaatunut.\n" -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Jos näin on, käytä komentoa :recover tai vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Jos näin on, käytä komentoa :recover tai nvim -r " msgid "" "\"\n" diff --git a/src/nvim/po/fr.po b/src/nvim/po/fr.po index fae6fe2297..92d2ad215f 100644 --- a/src/nvim/po/fr.po +++ b/src/nvim/po/fr.po @@ -3241,8 +3241,8 @@ msgstr "" msgid "(2) An edit session for this file crashed.\n" msgstr "(2) Une session d'édition de ce fichier a planté.\n" -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Si c'est le cas, utilisez \":recover\" ou \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Si c'est le cas, utilisez \":recover\" ou \"nvim -r " msgid "" "\"\n" diff --git a/src/nvim/po/ga.po b/src/nvim/po/ga.po index 5107aed75f..7a5893b5f2 100644 --- a/src/nvim/po/ga.po +++ b/src/nvim/po/ga.po @@ -389,8 +389,8 @@ msgstr " Comhlánú saincheaptha (^U^N^P)" msgid " Omni completion (^O^N^P)" msgstr " Comhlánú Omni (^O^N^P)" -msgid " Spelling suggestion (s^N^P)" -msgstr " Moladh litrithe (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr " Moladh litrithe (^S^N^P)" msgid " Keyword Local completion (^N^P)" msgstr " Comhlánú logánta lorgfhocal (^N^P)" @@ -3696,8 +3696,8 @@ msgstr "" msgid "(2) An edit session for this file crashed.\n" msgstr "(2) Thuairteáil seisiún eagarthóireachta.\n" -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Más amhlaidh, bain úsáid as \":recover\" nó \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Más amhlaidh, bain úsáid as \":recover\" nó \"nvim -r " msgid "" "\"\n" diff --git a/src/nvim/po/it.po b/src/nvim/po/it.po index 2191876724..d02052ec39 100644 --- a/src/nvim/po/it.po +++ b/src/nvim/po/it.po @@ -383,8 +383,8 @@ msgid " Omni completion (^O^N^P)" msgstr " Completamento globale (^O^N^P)" #: ../edit.c:96 -msgid " Spelling suggestion (s^N^P)" -msgstr " Suggerimento ortografico (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr " Suggerimento ortografico (^S^N^P)" #: ../edit.c:97 msgid " Keyword Local completion (^N^P)" @@ -4037,8 +4037,8 @@ msgid "(2) An edit session for this file crashed.\n" msgstr "(2) Una sessione di edit per questo file è finita male.\n" #: ../memline.c:3247 -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Se è così, usa \":recover\" oppure \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Se è così, usa \":recover\" oppure \"nvim -r " #: ../memline.c:3249 msgid "" diff --git a/src/nvim/po/ja.euc-jp.po b/src/nvim/po/ja.euc-jp.po index 87b4fc5ccd..78f927c21d 100644 --- a/src/nvim/po/ja.euc-jp.po +++ b/src/nvim/po/ja.euc-jp.po @@ -409,8 +409,8 @@ msgstr " ¥æ¡¼¥¶¡¼ÄêµÁÊä´° (^U^N^P)" msgid " Omni completion (^O^N^P)" msgstr " ¥ª¥à¥ËÊä´° (^O^N^P)" -msgid " Spelling suggestion (s^N^P)" -msgstr " Ä֤꽤Àµ¸õÊä (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr " Ä֤꽤Àµ¸õÊä (^S^N^P)" msgid " Keyword Local completion (^N^P)" msgstr " ¶É½ê¥¡¼¥ï¡¼¥ÉÊä´° (^N^P)" @@ -3466,8 +3466,8 @@ msgstr "" msgid "(2) An edit session for this file crashed.\n" msgstr "(2) ¤³¤Î¥Õ¥¡¥¤¥ë¤ÎÊÔ½¸¥»¥Ã¥·¥ç¥ó¤¬¥¯¥é¥Ã¥·¥å¤·¤¿.\n" -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " ¤³¤Î¾ì¹ç¤Ë¤Ï \":recover\" ¤« \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " ¤³¤Î¾ì¹ç¤Ë¤Ï \":recover\" ¤« \"nvim -r " msgid "" "\"\n" diff --git a/src/nvim/po/ja.po b/src/nvim/po/ja.po index 315c860307..1a493c0336 100644 --- a/src/nvim/po/ja.po +++ b/src/nvim/po/ja.po @@ -4247,8 +4247,8 @@ msgstr " ユーザー定義補完 (^U^N^P)" msgid " Omni completion (^O^N^P)" msgstr " オムニ補完 (^O^N^P)" -msgid " Spelling suggestion (s^N^P)" -msgstr " 綴り修æ£å€™è£œ (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr " 綴り修æ£å€™è£œ (^S^N^P)" msgid " Keyword Local completion (^N^P)" msgstr " 局所ã‚ーワード補完 (^N^P)" @@ -5092,8 +5092,8 @@ msgstr "" msgid "(2) An edit session for this file crashed.\n" msgstr "(2) ã“ã®ãƒ•ァイルã®ç·¨é›†ã‚»ãƒƒã‚·ãƒ§ãƒ³ãŒã‚¯ãƒ©ãƒƒã‚·ãƒ¥ã—ãŸ.\n" -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " ã“ã®å ´åˆã«ã¯ \":recover\" ã‹ \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " ã“ã®å ´åˆã«ã¯ \":recover\" ã‹ \"nvim -r " msgid "" "\"\n" diff --git a/src/nvim/po/ko.UTF-8.po b/src/nvim/po/ko.UTF-8.po index 8a6b228b18..03dff518f3 100644 --- a/src/nvim/po/ko.UTF-8.po +++ b/src/nvim/po/ko.UTF-8.po @@ -381,8 +381,8 @@ msgid " Omni completion (^O^N^P)" msgstr " Omni 완성 (^O^N^P)" #: ../edit.c:96 -msgid " Spelling suggestion (s^N^P)" -msgstr " 단어 ì œì•ˆ (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr " 단어 ì œì•ˆ (^S^N^P)" #: ../edit.c:97 msgid " Keyword Local completion (^N^P)" @@ -3957,8 +3957,8 @@ msgstr "" "(2) 파ì¼ì„ ê³ ì¹˜ë‹¤ê°€ 죽었었습니다.\n" #: ../memline.c:3247 -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " 만약 ê·¸ë ‡ë‹¤ë©´ \":recover\" í˜¹ì€ \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " 만약 ê·¸ë ‡ë‹¤ë©´ \":recover\" í˜¹ì€ \"nvim -r " #: ../memline.c:3249 msgid "" diff --git a/src/nvim/po/nb.po b/src/nvim/po/nb.po index 75f4eb28a3..d512789246 100644 --- a/src/nvim/po/nb.po +++ b/src/nvim/po/nb.po @@ -401,8 +401,7 @@ msgid " Omni completion (^O^N^P)" msgstr " Omni-fullføring (^O^N^P)" #: ../edit.c:96 -#, fuzzy -msgid " Spelling suggestion (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" msgstr " Staveforslag (^S^N^P)" #: ../edit.c:97 @@ -3979,8 +3978,8 @@ msgstr "" "(2) En økt for denne filen kræsjet.\n" #: ../memline.c:3247 -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Hvis det er tilfelle, bruk \":recover\" eller \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Hvis det er tilfelle, bruk \":recover\" eller \"nvim -r " #: ../memline.c:3249 msgid "" diff --git a/src/nvim/po/nl.po b/src/nvim/po/nl.po index d07c566e28..f6ce5ddc9f 100644 --- a/src/nvim/po/nl.po +++ b/src/nvim/po/nl.po @@ -384,8 +384,8 @@ msgid " Omni completion (^O^N^P)" msgstr " omni-voltooiing (^O^N^P)" #: ../edit.c:96 -msgid " Spelling suggestion (s^N^P)" -msgstr " spellingsuggestie (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr " spellingsuggestie (^S^N^P)" #: ../edit.c:97 msgid " Keyword Local completion (^N^P)" @@ -3984,8 +3984,8 @@ msgstr "" "(2) Een sessie waarin dit bestand werd bewerkt is onverhoeds gestopt.\n" #: ../memline.c:3247 -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Als dit het geval is, gebruikt dan \":recover\" of \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Als dit het geval is, gebruikt dan \":recover\" of \"nvim -r " #: ../memline.c:3249 msgid "" diff --git a/src/nvim/po/no.po b/src/nvim/po/no.po index 75f4eb28a3..d512789246 100644 --- a/src/nvim/po/no.po +++ b/src/nvim/po/no.po @@ -401,8 +401,7 @@ msgid " Omni completion (^O^N^P)" msgstr " Omni-fullføring (^O^N^P)" #: ../edit.c:96 -#, fuzzy -msgid " Spelling suggestion (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" msgstr " Staveforslag (^S^N^P)" #: ../edit.c:97 @@ -3979,8 +3978,8 @@ msgstr "" "(2) En økt for denne filen kræsjet.\n" #: ../memline.c:3247 -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Hvis det er tilfelle, bruk \":recover\" eller \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Hvis det er tilfelle, bruk \":recover\" eller \"nvim -r " #: ../memline.c:3249 msgid "" diff --git a/src/nvim/po/pl.UTF-8.po b/src/nvim/po/pl.UTF-8.po index c00130ac8c..b7200a7ba8 100644 --- a/src/nvim/po/pl.UTF-8.po +++ b/src/nvim/po/pl.UTF-8.po @@ -380,8 +380,8 @@ msgid " Omni completion (^O^N^P)" msgstr " Omni uzupeÅ‚nianie (^O^N^P)" #: ../edit.c:96 -msgid " Spelling suggestion (s^N^P)" -msgstr "Propozycja pisowni (^L^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr "Propozycja pisowni (^S^N^P)" #: ../edit.c:97 msgid " Keyword Local completion (^N^P)" @@ -3946,8 +3946,8 @@ msgid "(2) An edit session for this file crashed.\n" msgstr "(2) Sesja edycji dla pliku zaÅ‚amaÅ‚a siÄ™.\n" #: ../memline.c:3247 -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " JeÅ›li tak, to użyj \":recover\" lub \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " JeÅ›li tak, to użyj \":recover\" lub \"nvim -r " #: ../memline.c:3249 msgid "" diff --git a/src/nvim/po/pt_BR.po b/src/nvim/po/pt_BR.po index ca5a4508c7..3f2f87991c 100644 --- a/src/nvim/po/pt_BR.po +++ b/src/nvim/po/pt_BR.po @@ -625,8 +625,8 @@ msgstr "" "(2) Ocorreu um travamento numa sessão de edição desse arquivo.\n" #: ../memline.c:3206 -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Se esse for o caso, use \":recover\" ou \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Se esse for o caso, use \":recover\" ou \"nvim -r " #: ../memline.c:3208 msgid "" @@ -5610,8 +5610,8 @@ msgid " Omni completion (^O^N^P)" msgstr " Completação inteligente (^O^N^P)" #: ../edit.c:97 -msgid " Spelling suggestion (s^N^P)" -msgstr " Sugestão de ortografia (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr " Sugestão de ortografia (^S^N^P)" #: ../edit.c:98 msgid " Keyword Local completion (^N^P)" diff --git a/src/nvim/po/ru.po b/src/nvim/po/ru.po index 160de6c67e..64c18f890c 100644 --- a/src/nvim/po/ru.po +++ b/src/nvim/po/ru.po @@ -382,8 +382,8 @@ msgid " Omni completion (^O^N^P)" msgstr " Omni-дополнение (^O^N^P)" #: ../edit.c:96 -msgid " Spelling suggestion (s^N^P)" -msgstr " Предложение иÑÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð°Ð²Ð¾Ð¿Ð¸ÑÐ°Ð½Ð¸Ñ (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr " Предложение иÑÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð°Ð²Ð¾Ð¿Ð¸ÑÐ°Ð½Ð¸Ñ (^S^N^P)" #: ../edit.c:97 msgid " Keyword Local completion (^N^P)" @@ -3985,8 +3985,8 @@ msgid "(2) An edit session for this file crashed.\n" msgstr "(2) Ð¡ÐµÐ°Ð½Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñтого файла завершён аварийно.\n" #: ../memline.c:3247 -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Ð’ Ñтом Ñлучае, иÑпользуйте команду \":recover\" или \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Ð’ Ñтом Ñлучае, иÑпользуйте команду \":recover\" или \"nvim -r " #: ../memline.c:3249 msgid "" diff --git a/src/nvim/po/sk.cp1250.po b/src/nvim/po/sk.cp1250.po index f0fdc47a1e..9510a357f0 100644 --- a/src/nvim/po/sk.cp1250.po +++ b/src/nvim/po/sk.cp1250.po @@ -383,8 +383,7 @@ msgid " Omni completion (^O^N^P)" msgstr " Doplòovanie tagov (^O^N^P)" #: ../edit.c:96 -#, fuzzy -msgid " Spelling suggestion (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" msgstr " Doplòovanie celých riadkov (^S^N^P)" #: ../edit.c:97 @@ -3976,8 +3975,8 @@ msgstr "" "(2) Úprava tohoto súboru bola prerušená neoèakávaným ukonèením programu.\n" #: ../memline.c:3247 -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Ak je tomu tak, potom použite \":recover\" alebo \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Ak je tomu tak, potom použite \":recover\" alebo \"nvim -r " #: ../memline.c:3249 msgid "" diff --git a/src/nvim/po/sk.po b/src/nvim/po/sk.po index 2d6b4ed901..21791e0061 100644 --- a/src/nvim/po/sk.po +++ b/src/nvim/po/sk.po @@ -383,8 +383,7 @@ msgid " Omni completion (^O^N^P)" msgstr " Doplòovanie tagov (^O^N^P)" #: ../edit.c:96 -#, fuzzy -msgid " Spelling suggestion (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" msgstr " Doplòovanie celých riadkov (^S^N^P)" #: ../edit.c:97 @@ -3976,8 +3975,8 @@ msgstr "" "(2) Úprava tohoto súboru bola preru¹ená neoèakávaným ukonèením programu.\n" #: ../memline.c:3247 -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Ak je tomu tak, potom pou¾ite \":recover\" alebo \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Ak je tomu tak, potom pou¾ite \":recover\" alebo \"nvim -r " #: ../memline.c:3249 msgid "" diff --git a/src/nvim/po/sr.po b/src/nvim/po/sr.po index 4a9dcf4a5d..1cbb37eeb1 100644 --- a/src/nvim/po/sr.po +++ b/src/nvim/po/sr.po @@ -643,8 +643,8 @@ msgstr " КориÑнички дефиниÑано довршавање (^U^N^P) msgid " Omni completion (^O^N^P)" msgstr " Omni довршавање (^O^N^P)" -msgid " Spelling suggestion (s^N^P)" -msgstr " ПравопиÑни предлог (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr " ПравопиÑни предлог (^S^N^P)" msgid " Keyword Local completion (^N^P)" msgstr " Довршавање локалне кључне речи (^N^P)" @@ -3002,8 +3002,8 @@ msgstr " КориÑнички дефиниÑано довршавање (^U^N^P) msgid " Omni completion (^O^N^P)" msgstr " Omni довршавање (^O^N^P)" -msgid " Spelling suggestion (s^N^P)" -msgstr " ПравопиÑни предлог (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr " ПравопиÑни предлог (^S^N^P)" msgid " Keyword Local completion (^N^P)" msgstr " Довршавање локалне кључне речи (^N^P)" @@ -4048,8 +4048,8 @@ msgstr "" msgid "(2) An edit session for this file crashed.\n" msgstr "(2) СеÑија уређивања ове датотеке Ñе Ñрушила.\n" -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Ðко је ово Ñлучај, кориÑтите \":recover\" или \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Ðко је ово Ñлучај, кориÑтите \":recover\" или \"nvim -r " msgid "" "\"\n" diff --git a/src/nvim/po/sv.po b/src/nvim/po/sv.po index e46579c067..89a7717746 100644 --- a/src/nvim/po/sv.po +++ b/src/nvim/po/sv.po @@ -4335,8 +4335,8 @@ msgid " Omni completion (^O^N^P)" msgstr " Omnikomplettering (^O^N^P)" #: ../edit.c:97 -msgid " Spelling suggestion (s^N^P)" -msgstr " Stavningsförslag (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr " Stavningsförslag (^S^N^P)" #: ../edit.c:98 msgid " Keyword Local completion (^N^P)" @@ -6171,8 +6171,8 @@ msgid "(2) An edit session for this file crashed.\n" msgstr "(2) En redigeringssession för den här filen kraschade.\n" #: ../memline.c:3200 -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Om så är fallet, använd \":recover\" eller \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Om så är fallet, använd \":recover\" eller \"nvim -r " #: ../memline.c:3202 msgid "" diff --git a/src/nvim/po/tr.po b/src/nvim/po/tr.po index 08b97ec180..5b9a549cb2 100644 --- a/src/nvim/po/tr.po +++ b/src/nvim/po/tr.po @@ -3109,8 +3109,8 @@ msgstr " Kullanıcı tanımlı tamamlamalar (^U^N^P)" msgid " Omni completion (^O^N^P)" msgstr " Omni tamamlaması (^O^N^P)" -msgid " Spelling suggestion (s^N^P)" -msgstr " Yazım önerisi (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr " Yazım önerisi (^S^N^P)" msgid " Keyword Local completion (^N^P)" msgstr " Dahili anahtar sözcük tamamlaması (^N^P)" @@ -3947,8 +3947,8 @@ msgstr "" msgid "(2) An edit session for this file crashed.\n" msgstr "(2) Bu dosya düzenleme oturumu çöktü.\n" -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Durum buysa \":recover\" veya \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Durum buysa \":recover\" veya \"nvim -r " msgid "" "\"\n" diff --git a/src/nvim/po/uk.po b/src/nvim/po/uk.po index e62de86b09..6f2f90ad2c 100644 --- a/src/nvim/po/uk.po +++ b/src/nvim/po/uk.po @@ -4254,8 +4254,8 @@ msgstr " КориÑтувацьке Ð´Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ (^U^N^P)" msgid " Omni completion (^O^N^P)" msgstr " Кмітливе Ð´Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ (^O^N^P)" -msgid " Spelling suggestion (s^N^P)" -msgstr " Орфографічна підказка (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr " Орфографічна підказка (^S^N^P)" msgid " Keyword Local completion (^N^P)" msgstr " Ð”Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ð¼Ñ–Ñцевих ключових Ñлів (^N^P)" @@ -5108,8 +5108,8 @@ msgstr "" msgid "(2) An edit session for this file crashed.\n" msgstr "(2) Ð¡ÐµÐ°Ð½Ñ Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ файлу зазнав краху.\n" -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " Якщо це Ñправді трапилоÑÑ, Ñпробуйте «:recover» або «vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " Якщо це Ñправді трапилоÑÑ, Ñпробуйте «:recover» або «nvim -r " msgid "" "\"\n" diff --git a/src/nvim/po/vi.po b/src/nvim/po/vi.po index 44772c99ad..3e88ac446c 100644 --- a/src/nvim/po/vi.po +++ b/src/nvim/po/vi.po @@ -388,7 +388,7 @@ msgstr " Tá»± động kết thúc thẻ đánh dấu (^]^N^P)" #: ../edit.c:96 #, fuzzy -msgid " Spelling suggestion (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" msgstr " Tá»± động kết thúc cho cả dòng (^L^N^P)" #: ../edit.c:97 @@ -4009,9 +4009,9 @@ msgstr "" "(2) Lần soạn thảo trước cá»§a táºp tin nà y gặp sá»± cố.\n" #: ../memline.c:3247 -msgid " If this is the case, use \":recover\" or \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " msgstr "" -" Trong trưá»ng hợp nà y, hãy sá» dụng câu lệnh \":recover\" hoặc \"vim -r " +" Trong trưá»ng hợp nà y, hãy sá» dụng câu lệnh \":recover\" hoặc \"nvim -r " #: ../memline.c:3249 msgid "" diff --git a/src/nvim/po/zh_CN.UTF-8.po b/src/nvim/po/zh_CN.UTF-8.po index af050823d3..e30fc47806 100644 --- a/src/nvim/po/zh_CN.UTF-8.po +++ b/src/nvim/po/zh_CN.UTF-8.po @@ -3716,8 +3716,8 @@ msgid " Omni completion (^O^N^P)" msgstr " 全能补全 (^O^N^P)" #: ../insexpand.c:113 -msgid " Spelling suggestion (s^N^P)" -msgstr " 拼写建议 (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" +msgstr " 拼写建议 (^S^N^P)" #: ../insexpand.c:114 msgid " Keyword Local completion (^N^P)" @@ -4780,8 +4780,8 @@ msgid "(2) An edit session for this file crashed.\n" msgstr "(2) ä¸Šæ¬¡ç¼–è¾‘æ¤æ–‡ä»¶æ—¶å´©æºƒã€‚\n" #: ../memline.c:3099 -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " å¦‚æžœæ˜¯è¿™æ ·ï¼Œè¯·ç”¨ \":recover\" 或 \"vim -r " +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " å¦‚æžœæ˜¯è¿™æ ·ï¼Œè¯·ç”¨ \":recover\" 或 \"nvim -r " #: ../memline.c:3101 msgid "" diff --git a/src/nvim/po/zh_TW.UTF-8.po b/src/nvim/po/zh_TW.UTF-8.po index cba95e2af2..cbbc4ad6eb 100644 --- a/src/nvim/po/zh_TW.UTF-8.po +++ b/src/nvim/po/zh_TW.UTF-8.po @@ -421,7 +421,7 @@ msgstr " æ¨™ç±¤è‡ªå‹•å®Œæˆ (^]^N^P)" #: ../edit.c:96 #, fuzzy -msgid " Spelling suggestion (s^N^P)" +msgid " Spelling suggestion (^S^N^P)" msgstr " æ•´è¡Œè‡ªå‹•å®Œæˆ (^L^N^P)" #: ../edit.c:97 @@ -4017,8 +4017,8 @@ msgstr "" "(2) 剿¬¡ç·¨è¼¯æ¤æª”時當機\n" #: ../memline.c:3247 -msgid " If this is the case, use \":recover\" or \"vim -r " -msgstr " 如果是這樣, 請用 \":recover\" 或 \"vim -r" +msgid " If this is the case, use \":recover\" or \"nvim -r " +msgstr " 如果是這樣, 請用 \":recover\" 或 \"nvim -r" #: ../memline.c:3249 msgid "" diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index 86f3611ec5..ddcb819054 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -17,13 +17,16 @@ #include "nvim/buffer_updates.h" #include "nvim/change.h" #include "nvim/charset.h" +#include "nvim/cmdexpand.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" #include "nvim/extmark.h" #include "nvim/extmark_defs.h" +#include "nvim/garray.h" #include "nvim/getchar.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" @@ -47,6 +50,7 @@ #include "nvim/plines.h" #include "nvim/popupmenu.h" #include "nvim/pos_defs.h" +#include "nvim/search.h" #include "nvim/state_defs.h" #include "nvim/strings.h" #include "nvim/types_defs.h" @@ -140,7 +144,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i || (State == MODE_CMDLINE && ui_has(kUIWildmenu)); } - pum_rl = (curwin->w_p_rl && State != MODE_CMDLINE); + pum_rl = State != MODE_CMDLINE && curwin->w_p_rl; do { // Mark the pum as visible already here, @@ -434,6 +438,114 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i pum_redraw(); } +/// Computes attributes of text on the popup menu. +/// Returns attributes for every cell, or NULL if all attributes are the same. +static int *pum_compute_text_attrs(char *text, hlf_T hlf, int user_hlattr) +{ + if ((hlf != HLF_PSI && hlf != HLF_PNI) + || (win_hl_attr(curwin, HLF_PMSI) == win_hl_attr(curwin, HLF_PSI) + && win_hl_attr(curwin, HLF_PMNI) == win_hl_attr(curwin, HLF_PNI))) { + return NULL; + } + + char *leader = State == MODE_CMDLINE ? cmdline_compl_pattern() + : ins_compl_leader(); + if (leader == NULL || *leader == NUL) { + return NULL; + } + + int *attrs = xmalloc(sizeof(int) * (size_t)vim_strsize(text)); + bool in_fuzzy = State == MODE_CMDLINE ? cmdline_compl_is_fuzzy() + : (get_cot_flags() & COT_FUZZY) != 0; + size_t leader_len = strlen(leader); + + garray_T *ga = NULL; + bool matched_start = false; + + if (in_fuzzy) { + ga = fuzzy_match_str_with_pos(text, leader); + } else { + matched_start = mb_strnicmp(text, leader, leader_len) == 0; + } + + const char *ptr = text; + int cell_idx = 0; + uint32_t char_pos = 0; + + while (*ptr != NUL) { + int new_attr = win_hl_attr(curwin, (int)hlf); + + if (ga != NULL) { + // Handle fuzzy matching + for (int i = 0; i < ga->ga_len; i++) { + if (char_pos == ((uint32_t *)ga->ga_data)[i]) { + new_attr = win_hl_attr(curwin, hlf == HLF_PSI ? HLF_PMSI : HLF_PMNI); + break; + } + } + } else if (matched_start && ptr < text + leader_len) { + new_attr = win_hl_attr(curwin, hlf == HLF_PSI ? HLF_PMSI : HLF_PMNI); + } + + if (user_hlattr > 0) { + new_attr = hl_combine_attr(new_attr, user_hlattr); + } + + int char_cells = utf_ptr2cells(ptr); + for (int i = 0; i < char_cells; i++) { + attrs[cell_idx + i] = new_attr; + } + cell_idx += char_cells; + + MB_PTR_ADV(ptr); + char_pos++; + } + + if (ga != NULL) { + ga_clear(ga); + xfree(ga); + } + return attrs; +} + +/// Displays text on the popup menu with specific attributes. +static void pum_grid_puts_with_attrs(int col, int cells, const char *text, int textlen, + const int *attrs) +{ + const int col_start = col; + const char *ptr = text; + + // Render text with proper attributes + while (*ptr != NUL && (textlen < 0 || ptr < text + textlen)) { + int char_len = utfc_ptr2len(ptr); + int attr = attrs[pum_rl ? (col_start + cells - col - 1) : (col - col_start)]; + grid_line_puts(col, ptr, char_len, attr); + col += utf_ptr2cells(ptr); + ptr += char_len; + } +} + +static inline void pum_align_order(int *order) +{ + bool is_default = cia_flags == 0; + order[0] = is_default ? CPT_ABBR : cia_flags / 100; + order[1] = is_default ? CPT_KIND : (cia_flags / 10) % 10; + order[2] = is_default ? CPT_MENU : cia_flags % 10; +} + +static inline char *pum_get_item(int index, int type) +{ + switch (type) { + case CPT_ABBR: + return pum_array[index].pum_text; + case CPT_KIND: + return pum_array[index].pum_kind; + case CPT_MENU: + return pum_array[index].pum_extra; + } + return NULL; +} + /// Redraw the popup menu, using "pum_first" and "pum_selected". void pum_redraw(void) { @@ -445,11 +557,9 @@ void pum_redraw(void) int thumb_height = 1; int n; -#define HA(hlf) (win_hl_attr(curwin, (hlf))) - // "word" "kind" "extra text" - const int attrsNorm[3] = { HA(HLF_PNI), HA(HLF_PNK), HA(HLF_PNX) }; - const int attrsSel[3] = { HA(HLF_PSI), HA(HLF_PSK), HA(HLF_PSX) }; -#undef HA + // "word" "kind" "extra text" + const hlf_T hlfsNorm[3] = { HLF_PNI, HLF_PNK, HLF_PNX }; + const hlf_T hlfsSel[3] = { HLF_PSI, HLF_PSK, HLF_PSX }; int grid_width = pum_width; int col_off = 0; @@ -516,8 +626,9 @@ void pum_redraw(void) for (int i = 0; i < pum_height; i++) { int idx = i + pum_first; - const int *const attrs = (idx == pum_selected) ? attrsSel : attrsNorm; - int attr = attrs[0]; // start with "word" highlight + const hlf_T *const hlfs = (idx == pum_selected) ? hlfsSel : hlfsNorm; + hlf_T hlf = hlfs[0]; // start with "word" highlight + int attr = win_hl_attr(curwin, (int)hlf); grid_line_start(&pum_grid, row); @@ -531,27 +642,27 @@ void pum_redraw(void) } // Display each entry, use two spaces for a Tab. - // Do this 3 times: - // 0 - main text - // 1 - kind - // 2 - extra info + // Do this 3 times and order from p_cia int grid_col = col_off; int totwidth = 0; - - for (int round = 0; round < 3; round++) { - attr = attrs[round]; + int order[3]; + int items_width_array[3] = { pum_base_width, pum_kind_width, pum_extra_width }; + pum_align_order(order); + int basic_width = items_width_array[order[0]]; // first item width + bool last_isabbr = order[2] == CPT_ABBR; + for (int j = 0; j < 3; j++) { + int item_type = order[j]; + hlf = hlfs[item_type]; + attr = win_hl_attr(curwin, (int)hlf); + if (pum_array[idx].pum_user_hlattr > 0) { + attr = hl_combine_attr(attr, pum_array[idx].pum_user_hlattr); + } + if (item_type == CPT_KIND && pum_array[idx].pum_user_kind_hlattr > 0) { + attr = hl_combine_attr(attr, pum_array[idx].pum_user_kind_hlattr); + } int width = 0; char *s = NULL; - - switch (round) { - case 0: - p = pum_array[idx].pum_text; break; - case 1: - p = pum_array[idx].pum_kind; break; - case 2: - p = pum_array[idx].pum_extra; break; - } - + p = pum_get_item(idx, item_type); if (p != NULL) { for (;; MB_PTR_ADV(p)) { if (s == NULL) { @@ -573,36 +684,51 @@ void pum_redraw(void) *p = saved; } + int user_hlattr = pum_array[idx].pum_user_hlattr; + int *attrs = pum_compute_text_attrs(st, hlf, user_hlattr); + if (pum_rl) { char *rt = reverse_text(st); char *rt_start = rt; - int size = vim_strsize(rt); + int cells = vim_strsize(rt); - if (size > pum_width) { + if (cells > pum_width) { do { - size -= utf_ptr2cells(rt); + cells -= utf_ptr2cells(rt); MB_PTR_ADV(rt); - } while (size > pum_width); + } while (cells > pum_width); - if (size < pum_width) { + if (cells < pum_width) { // Most left character requires 2-cells but only 1 cell // is available on screen. Put a '<' on the left of the // pum item *(--rt) = '<'; - size++; + cells++; } } - grid_line_puts(grid_col - size + 1, rt, -1, attr); + + if (attrs == NULL) { + grid_line_puts(grid_col - cells + 1, rt, -1, attr); + } else { + pum_grid_puts_with_attrs(grid_col - cells + 1, cells, rt, -1, attrs); + } + xfree(rt_start); xfree(st); grid_col -= width; } else { - // use grid_line_puts() to truncate the text - grid_line_puts(grid_col, st, -1, attr); + if (attrs == NULL) { + grid_line_puts(grid_col, st, -1, attr); + } else { + pum_grid_puts_with_attrs(grid_col, vim_strsize(st), st, -1, attrs); + } + xfree(st); grid_col += width; } + xfree(attrs); + if (*p != TAB) { break; } @@ -625,31 +751,31 @@ void pum_redraw(void) } } - if (round > 0) { - n = pum_kind_width + 1; + if (j > 0) { + n = items_width_array[order[1]] + (last_isabbr ? 0 : 1); } else { - n = 1; + n = order[j] == CPT_ABBR ? 1 : 0; } + bool next_isempty = false; + if (j + 1 < 3) { + next_isempty = pum_get_item(idx, order[j + 1]) == NULL; + } // Stop when there is nothing more to display. - if ((round == 2) - || ((round == 1) - && (pum_array[idx].pum_extra == NULL)) - || ((round == 0) - && (pum_array[idx].pum_kind == NULL) - && (pum_array[idx].pum_extra == NULL)) - || (pum_base_width + n >= pum_width)) { + if ((j == 2) + || (next_isempty && (j == 1 || (j == 0 && pum_get_item(idx, order[j + 2]) == NULL))) + || (basic_width + n >= pum_width)) { break; } if (pum_rl) { - grid_line_fill(col_off - pum_base_width - n + 1, grid_col + 1, schar_from_ascii(' '), attr); - grid_col = col_off - pum_base_width - n + 1; + grid_line_fill(col_off - basic_width - n + 1, grid_col + 1, schar_from_ascii(' '), attr); + grid_col = col_off - basic_width - n; } else { - grid_line_fill(grid_col, col_off + pum_base_width + n, schar_from_ascii(' '), attr); - grid_col = col_off + pum_base_width + n; + grid_line_fill(grid_col, col_off + basic_width + n, schar_from_ascii(' '), attr); + grid_col = col_off + basic_width + n; } - totwidth = pum_base_width + n; + totwidth = basic_width + n; } if (pum_rl) { @@ -699,7 +825,7 @@ static void pum_preview_set_text(buf_T *buf, char *info, linenr_T *lnum, int *ma } // delete the empty last line ml_delete_buf(buf, buf->b_ml.ml_line_count, false); - if (strstr(p_cot, "popup") != NULL) { + if (get_cot_flags() & COT_POPUP) { extmark_splice(buf, 1, 0, 1, 0, 0, buf->b_ml.ml_line_count, 0, inserted_bytes, kExtmarkNoUndo); } } @@ -794,7 +920,8 @@ static bool pum_set_selected(int n, int repeat) int prev_selected = pum_selected; pum_selected = n; - bool use_float = strstr(p_cot, "popup") != NULL; + unsigned cur_cot_flags = get_cot_flags(); + bool use_float = (cur_cot_flags & COT_POPUP) != 0; // when new leader add and info window is shown and no selected we still // need use the first index item to update the info float window position. bool force_select = use_float && pum_selected < 0 && win_float_find_preview(); @@ -860,7 +987,7 @@ static bool pum_set_selected(int n, int repeat) if ((pum_array[pum_selected].pum_info != NULL) && (Rows > 10) && (repeat <= 1) - && (vim_strchr(p_cot, 'p') != NULL)) { + && (cur_cot_flags & COT_ANY_PREVIEW)) { win_T *curwin_save = curwin; tabpage_T *curtab_save = curtab; @@ -1142,12 +1269,14 @@ void pum_set_event_info(dict_T *dict) static void pum_position_at_mouse(int min_width) { int min_row = 0; + int min_col = 0; int max_row = Rows; int max_col = Columns; if (mouse_grid > 1) { win_T *wp = get_win_by_grid_handle(mouse_grid); if (wp != NULL) { min_row = -wp->w_winrow; + min_col = -wp->w_wincol; max_row = MAX(Rows - wp->w_winrow, wp->w_grid.rows); max_col = MAX(Columns - wp->w_wincol, wp->w_grid.cols); } @@ -1160,8 +1289,10 @@ static void pum_position_at_mouse(int min_width) } else { pum_anchor_grid = mouse_grid; } - if (max_row - mouse_row > pum_size) { - // Enough space below the mouse row. + + if (max_row - mouse_row > pum_size || max_row - mouse_row > mouse_row - min_row) { + // Enough space below the mouse row, + // or there is more space below the mouse row than above. pum_above = false; pum_row = mouse_row + 1; if (pum_height > max_row - pum_row) { @@ -1176,16 +1307,29 @@ static void pum_position_at_mouse(int min_width) pum_row = min_row; } } - if (max_col - mouse_col >= pum_base_width - || max_col - mouse_col > min_width) { - // Enough space to show at mouse column. - pum_col = mouse_col; + + if (pum_rl) { + if (mouse_col - min_col + 1 >= pum_base_width + || mouse_col - min_col + 1 > min_width) { + // Enough space to show at mouse column. + pum_col = mouse_col; + } else { + // Not enough space, left align with window. + pum_col = min_col + MIN(pum_base_width, min_width) - 1; + } + pum_width = pum_col - min_col + 1; } else { - // Not enough space, right align with window. - pum_col = max_col - (pum_base_width > min_width ? min_width : pum_base_width); + if (max_col - mouse_col >= pum_base_width + || max_col - mouse_col > min_width) { + // Enough space to show at mouse column. + pum_col = mouse_col; + } else { + // Not enough space, right align with window. + pum_col = max_col - MIN(pum_base_width, min_width); + } + pum_width = max_col - pum_col; } - pum_width = max_col - pum_col; if (pum_width > pum_base_width + 1) { pum_width = pum_base_width + 1; } @@ -1204,7 +1348,7 @@ static void pum_select_mouse_pos(void) int idx = mouse_row - pum_row; - if (idx < 0 || idx >= pum_size) { + if (idx < 0 || idx >= pum_height) { pum_selected = -1; } else if (*pum_array[idx].pum_text != NUL) { pum_selected = idx; @@ -1267,6 +1411,7 @@ void pum_show_popupmenu(vimmenu_T *menu) pum_compute_size(); pum_scrollbar = 0; pum_height = pum_size; + pum_rl = curwin->w_p_rl; pum_position_at_mouse(20); pum_selected = -1; @@ -1346,7 +1491,9 @@ void pum_make_popup(const char *path_name, int use_mouse_pos) // Hack: set mouse position at the cursor so that the menu pops up // around there. mouse_row = curwin->w_grid.row_offset + curwin->w_wrow; - mouse_col = curwin->w_grid.col_offset + curwin->w_wcol; + mouse_col = curwin->w_grid.col_offset + + (curwin->w_p_rl ? curwin->w_width_inner - curwin->w_wcol - 1 + : curwin->w_wcol); if (ui_has(kUIMultigrid)) { mouse_grid = curwin->w_grid.target->handle; } else if (curwin->w_grid.target != &default_grid) { diff --git a/src/nvim/popupmenu.h b/src/nvim/popupmenu.h index 20a342b841..f7eb0240ae 100644 --- a/src/nvim/popupmenu.h +++ b/src/nvim/popupmenu.h @@ -10,10 +10,14 @@ /// Used for popup menu items. typedef struct { - char *pum_text; // main menu text - char *pum_kind; // extra kind text (may be truncated) - char *pum_extra; // extra menu text (may be truncated) - char *pum_info; // extra info + char *pum_text; ///< main menu text + char *pum_kind; ///< extra kind text (may be truncated) + char *pum_extra; ///< extra menu text (may be truncated) + char *pum_info; ///< extra info + int pum_score; ///< fuzzy match score + int pum_idx; ///< index of item before sorting by score + int pum_user_hlattr; ///< highlight attribute to combine with + int pum_user_kind_hlattr; ///< highlight attribute for kind } pumitem_T; EXTERN ScreenGrid pum_grid INIT( = SCREEN_GRID_INIT); diff --git a/src/nvim/profile.c b/src/nvim/profile.c index b88b08d3f0..81207b4e39 100644 --- a/src/nvim/profile.c +++ b/src/nvim/profile.c @@ -10,6 +10,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/debugger.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" @@ -382,19 +383,19 @@ void set_context_in_profile_cmd(expand_T *xp, const char *arg) xp->xp_context = EXPAND_NOTHING; } -static proftime_T inchar_time; +static proftime_T wait_time; /// Called when starting to wait for the user to type a character. -void prof_inchar_enter(void) +void prof_input_start(void) { - inchar_time = profile_start(); + wait_time = profile_start(); } /// Called when finished waiting for the user to type a character. -void prof_inchar_exit(void) +void prof_input_end(void) { - inchar_time = profile_end(inchar_time); - profile_set_wait(profile_add(profile_get_wait(), inchar_time)); + wait_time = profile_end(wait_time); + profile_set_wait(profile_add(profile_get_wait(), wait_time)); } /// @return true when a function defined in the current script should be @@ -949,8 +950,8 @@ void time_msg(const char *mesg, const proftime_T *start) /// Initializes the `time_fd` stream for the --startuptime report. /// /// @param fname startuptime report file path -/// @param process_name name of the current Nvim process to write in the report. -void time_init(const char *fname, const char *process_name) +/// @param proc_name name of the current Nvim process to write in the report. +void time_init(const char *fname, const char *proc_name) { const size_t bufsize = 8192; // Big enough for the entire --startuptime report. time_fd = fopen(fname, "a"); @@ -971,7 +972,7 @@ void time_init(const char *fname, const char *process_name) semsg("time_init: setvbuf failed: %d %s", r, uv_err_name(r)); return; } - fprintf(time_fd, "--- Startup times for process: %s ---\n", process_name); + fprintf(time_fd, "--- Startup times for process: %s ---\n", proc_name); } /// Flushes the startuptimes to disk for the current process diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index e022184f2f..ddf2a7247f 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -20,6 +20,7 @@ #include "nvim/cursor.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/window.h" @@ -90,6 +91,7 @@ struct qfline_S { int qf_end_col; ///< column when the error has range or zero int qf_nr; ///< error number char *qf_module; ///< module name for this error + char *qf_fname; ///< different filename if there're hard links char *qf_pattern; ///< search pattern for the error char *qf_text; ///< description of the error char qf_viscol; ///< set to true if qf_col and qf_end_col is screen column @@ -381,11 +383,7 @@ static int qf_init_process_nextline(qf_list_T *qfl, efm_T *fmt_first, qfstate_T int qf_init(win_T *wp, const char *restrict efile, char *restrict errorformat, int newlist, const char *restrict qf_title, char *restrict enc) { - qf_info_T *qi = &ql_info; - - if (wp != NULL) { - qi = ll_get_or_alloc_list(wp); - } + qf_info_T *qi = wp == NULL ? &ql_info : ll_get_or_alloc_list(wp); return qf_init_ext(qi, qi->qf_curlist, efile, curbuf, NULL, errorformat, newlist, 0, 0, qf_title, enc); @@ -723,7 +721,7 @@ static int qf_get_next_str_line(qfstate_T *state) state->linelen = len; } memcpy(state->linebuf, p_str, state->linelen); - state->linebuf[state->linelen] = '\0'; + state->linebuf[state->linelen] = NUL; // Increment using len in order to discard the rest of the line if it // exceeds LINE_MAXLEN. @@ -833,8 +831,7 @@ retry: break; } - state->growbufsiz = (2 * state->growbufsiz < LINE_MAXLEN) - ? 2 * state->growbufsiz : LINE_MAXLEN; + state->growbufsiz = MIN(2 * state->growbufsiz, LINE_MAXLEN); state->growbuf = xrealloc(state->growbuf, state->growbufsiz); } @@ -870,8 +867,7 @@ retry: xfree(state->growbuf); state->linebuf = line; state->growbuf = line; - state->growbufsiz = state->linelen < LINE_MAXLEN - ? state->linelen : LINE_MAXLEN; + state->growbufsiz = MIN(state->linelen, LINE_MAXLEN); } } } @@ -1151,14 +1147,10 @@ static int qf_init_ext(qf_info_T *qi, int qf_idx, const char *restrict efile, bu } } - char *efm; - // Use the local value of 'errorformat' if it's set. - if (errorformat == p_efm && tv == NULL && buf && *buf->b_p_efm != NUL) { - efm = buf->b_p_efm; - } else { - efm = errorformat; - } + char *efm = (errorformat == p_efm && tv == NULL && buf && *buf->b_p_efm != NUL) + ? buf->b_p_efm + : errorformat; // If the errorformat didn't change between calls, then reuse the previously // parsed values. @@ -1490,9 +1482,7 @@ static int qf_parse_fmt_s(regmatch_T *rmp, int midx, qffields_T *fields) return QF_FAIL; } size_t len = (size_t)(rmp->endp[midx] - rmp->startp[midx]); - if (len > CMDBUFFSIZE - 5) { - len = CMDBUFFSIZE - 5; - } + len = MIN(len, CMDBUFFSIZE - 5); STRCPY(fields->pattern, "^\\V"); xstrlcat(fields->pattern, rmp->startp[midx], len + 4); fields->pattern[len + 3] = '\\'; @@ -1510,9 +1500,7 @@ static int qf_parse_fmt_o(regmatch_T *rmp, int midx, qffields_T *fields) } size_t len = (size_t)(rmp->endp[midx] - rmp->startp[midx]); size_t dsize = strlen(fields->module) + len + 1; - if (dsize > CMDBUFFSIZE) { - dsize = CMDBUFFSIZE; - } + dsize = MIN(dsize, CMDBUFFSIZE); xstrlcat(fields->module, rmp->startp[midx], dsize); return QF_OK; } @@ -1879,11 +1867,13 @@ static int qf_add_entry(qf_list_T *qfl, char *dir, char *fname, char *module, in char vis_col, char *pattern, int nr, char type, typval_T *user_data, char valid) { + buf_T *buf; qfline_T *qfp = xmalloc(sizeof(qfline_T)); + char *fullname = NULL; + char *p = NULL; if (bufnum != 0) { - buf_T *buf = buflist_findnr(bufnum); - + buf = buflist_findnr(bufnum); qfp->qf_fnum = bufnum; if (buf != NULL) { buf->b_has_qf_entry |= @@ -1891,7 +1881,21 @@ static int qf_add_entry(qf_list_T *qfl, char *dir, char *fname, char *module, in } } else { qfp->qf_fnum = qf_get_fnum(qfl, dir, fname); + buf = buflist_findnr(qfp->qf_fnum); + } + if (fname != NULL) { + fullname = fix_fname(fname); + } + qfp->qf_fname = NULL; + if (buf != NULL && buf->b_ffname != NULL && fullname != NULL) { + if (path_fnamecmp(fullname, buf->b_ffname) != 0) { + p = path_try_shorten_fname(fullname); + if (p != NULL) { + qfp->qf_fname = xstrdup(p); + } + } } + xfree(fullname); qfp->qf_text = xstrdup(mesg); qfp->qf_lnum = lnum; qfp->qf_end_lnum = end_lnum; @@ -2526,13 +2530,7 @@ static void win_set_loclist(win_T *wp, qf_info_T *qi) /// window. static int jump_to_help_window(qf_info_T *qi, bool newwin, bool *opened_window) { - win_T *wp = NULL; - - if (cmdmod.cmod_tab != 0 || newwin) { - wp = NULL; - } else { - wp = qf_find_help_win(); - } + win_T *wp = (cmdmod.cmod_tab != 0 || newwin) ? NULL : qf_find_help_win(); if (wp != NULL && wp->w_buffer->b_nwindows > 0) { win_enter(wp, true); @@ -2881,9 +2879,7 @@ static void qf_jump_goto_line(linenr_T qf_lnum, int qf_col, char qf_viscol, char // Go to line with error, unless qf_lnum is 0. linenr_T i = qf_lnum; if (i > 0) { - if (i > curbuf->b_ml.ml_line_count) { - i = curbuf->b_ml.ml_line_count; - } + i = MIN(i, curbuf->b_ml.ml_line_count); curwin->w_cursor.lnum = i; } if (qf_col > 0) { @@ -2914,8 +2910,7 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, buf { garray_T *const gap = qfga_get(); - // Update the screen before showing the message, unless the screen - // scrolled up. + // Update the screen before showing the message, unless messages scrolled. if (!msg_scrolled) { update_topline(curwin); if (must_redraw) { @@ -2937,7 +2932,8 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, buf linenr_T i = msg_scroll; if (curbuf == old_curbuf && curwin->w_cursor.lnum == old_lnum) { msg_scroll = true; - } else if (!msg_scrolled && shortmess(SHM_OVERALL)) { + } else if ((msg_scrolled == 0 || (p_ch == 0 && msg_scrolled == 1)) + && shortmess(SHM_OVERALL)) { msg_scroll = false; } msg_ext_set_kind("quickfix"); @@ -3166,7 +3162,7 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel) buf_T *buf; if (qfp->qf_fnum != 0 && (buf = buflist_findnr(qfp->qf_fnum)) != NULL) { - fname = buf->b_fname; + fname = qfp->qf_fname == NULL ? buf->b_fname : qfp->qf_fname; if (qfp->qf_type == 1) { // :helpgrep fname = path_tail(fname); } @@ -3452,6 +3448,7 @@ static void qf_free_items(qf_list_T *qfl) qfline_T *qfp = qfl->qf_start; qfline_T *qfpnext = qfp->qf_next; if (!stop) { + xfree(qfp->qf_fname); xfree(qfp->qf_module); xfree(qfp->qf_text); xfree(qfp->qf_pattern); @@ -3897,13 +3894,8 @@ static bool qf_win_pos_update(qf_info_T *qi, int old_qf_index) if (win != NULL && qf_index <= win->w_buffer->b_ml.ml_line_count && old_qf_index != qf_index) { - if (qf_index > old_qf_index) { - win->w_redraw_top = old_qf_index; - win->w_redraw_bot = qf_index; - } else { - win->w_redraw_top = qf_index; - win->w_redraw_bot = old_qf_index; - } + win->w_redraw_top = MIN(old_qf_index, qf_index); + win->w_redraw_bot = MAX(old_qf_index, qf_index); qf_win_goto(win, qf_index); } return win != NULL; @@ -4085,7 +4077,7 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, const qfli } shorten_buf_fname(errbuf, dirname, false); } - ga_concat(gap, errbuf->b_fname); + ga_concat(gap, qfp->qf_fname == NULL ? errbuf->b_fname : qfp->qf_fname); } } @@ -4219,11 +4211,7 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q qfp = qfl->qf_start; lnum = 0; } else { - if (old_last->qf_next != NULL) { - qfp = old_last->qf_next; - } else { - qfp = old_last; - } + qfp = old_last->qf_next != NULL ? old_last->qf_next : old_last; lnum = buf->b_ml.ml_line_count; } @@ -4450,15 +4438,11 @@ void ex_make(exarg_T *eap) incr_quickfix_busy(); - char *errorformat = p_efm; - bool newlist = true; + char *errorformat = (eap->cmdidx != CMD_make && eap->cmdidx != CMD_lmake) + ? p_gefm + : p_efm; - if (eap->cmdidx != CMD_make && eap->cmdidx != CMD_lmake) { - errorformat = p_gefm; - } - if (eap->cmdidx == CMD_grepadd || eap->cmdidx == CMD_lgrepadd) { - newlist = false; - } + bool newlist = eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd; int res = qf_init(wp, fname, errorformat, newlist, qf_cmdtitle(*eap->cmdlinep), enc); @@ -4530,7 +4514,7 @@ static char *get_mef_name(void) name = xmalloc(strlen(p_mef) + 30); STRCPY(name, p_mef); snprintf(name + (p - p_mef), strlen(name), "%d%d", start, off); - STRCAT(name, p + 2); + strcat(name, p + 2); // Don't accept a symbolic link, it's a security risk. FileInfo file_info; bool file_or_link_found = os_fileinfo_link(name, &file_info); @@ -5322,9 +5306,7 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp { bool found_match = false; size_t pat_len = strlen(spat); - if (pat_len > MAX_FUZZY_MATCHES) { - pat_len = MAX_FUZZY_MATCHES; - } + pat_len = MIN(pat_len, MAX_FUZZY_MATCHES); for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count && *tomatch > 0; lnum++) { colnr_T col = 0; @@ -5466,12 +5448,7 @@ static int vgr_process_args(exarg_T *eap, vgr_args_T *args) args->regmatch.regprog = NULL; args->qf_title = xstrdup(qf_cmdtitle(*eap->cmdlinep)); - - if (eap->addr_count > 0) { - args->tomatch = eap->line2; - } else { - args->tomatch = MAXLNUM; - } + args->tomatch = eap->addr_count > 0 ? eap->line2 : MAXLNUM; // Get the search pattern: either white-separated or enclosed in // char *p = skip_vimgrep_pat(eap->arg, &args->spat, &args->flags); @@ -6701,9 +6678,7 @@ static int qf_setprop_curidx(qf_info_T *qi, qf_list_T *qfl, const dictitem_T *di if (newidx < 1) { // sanity check return FAIL; } - if (newidx > qfl->qf_count) { - newidx = qfl->qf_count; - } + newidx = MIN(newidx, qfl->qf_count); const int old_qfidx = qfl->qf_index; qfline_T *const qf_ptr = get_nth_entry(qfl, newidx, &newidx); if (qf_ptr == NULL) { @@ -6900,31 +6875,17 @@ static bool mark_quickfix_ctx(qf_info_T *qi, int copyID) /// "in use". So that garbage collection doesn't free the context. bool set_ref_in_quickfix(int copyID) { - bool abort = mark_quickfix_ctx(&ql_info, copyID); - if (abort) { - return abort; - } - - abort = mark_quickfix_user_data(&ql_info, copyID); - if (abort) { - return abort; - } - - abort = set_ref_in_callback(&qftf_cb, copyID, NULL, NULL); - if (abort) { - return abort; + if (mark_quickfix_ctx(&ql_info, copyID) + || mark_quickfix_user_data(&ql_info, copyID) + || set_ref_in_callback(&qftf_cb, copyID, NULL, NULL)) { + return true; } FOR_ALL_TAB_WINDOWS(tp, win) { if (win->w_llist != NULL) { - abort = mark_quickfix_ctx(win->w_llist, copyID); - if (abort) { - return abort; - } - - abort = mark_quickfix_user_data(win->w_llist, copyID); - if (abort) { - return abort; + if (mark_quickfix_ctx(win->w_llist, copyID) + || mark_quickfix_user_data(win->w_llist, copyID)) { + return true; } } @@ -6932,14 +6893,14 @@ bool set_ref_in_quickfix(int copyID) // In a location list window and none of the other windows is // referring to this location list. Mark the location list // context as still in use. - abort = mark_quickfix_ctx(win->w_llist_ref, copyID); - if (abort) { - return abort; + if (mark_quickfix_ctx(win->w_llist_ref, copyID) + || mark_quickfix_user_data(win->w_llist_ref, copyID)) { + return true; } } } - return abort; + return false; } /// Return the autocmd name for the :cbuffer Ex commands @@ -7236,7 +7197,7 @@ static void hgr_search_files_in_dir(qf_list_T *qfl, char *dirname, regmatch_T *p // Find all "*.txt" and "*.??x" files in the "doc" directory. add_pathsep(dirname); - STRCAT(dirname, "doc/*.\\(txt\\|??x\\)"); // NOLINT + strcat(dirname, "doc/*.\\(txt\\|??x\\)"); // NOLINT if (gen_expand_wildcards(1, &dirname, &fcount, &fnames, EW_FILE|EW_SILENT) == OK && fcount > 0) { for (int fi = 0; fi < fcount && !got_int; fi++) { diff --git a/src/nvim/rbuffer.c b/src/nvim/rbuffer.c deleted file mode 100644 index 493c079d4c..0000000000 --- a/src/nvim/rbuffer.c +++ /dev/null @@ -1,230 +0,0 @@ -#include <assert.h> -#include <stdbool.h> -#include <stddef.h> -#include <string.h> - -#include "nvim/macros_defs.h" -#include "nvim/memory.h" -#include "nvim/rbuffer.h" - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "rbuffer.c.generated.h" -#endif - -/// Creates a new `RBuffer` instance. -RBuffer *rbuffer_new(size_t capacity) - FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET -{ - if (!capacity) { - capacity = 0x10000; - } - - RBuffer *rv = xcalloc(1, sizeof(RBuffer) + capacity); - rv->full_cb = rv->nonfull_cb = NULL; - rv->data = NULL; - rv->size = 0; - rv->write_ptr = rv->read_ptr = rv->start_ptr; - rv->end_ptr = rv->start_ptr + capacity; - rv->temp = NULL; - return rv; -} - -void rbuffer_free(RBuffer *buf) FUNC_ATTR_NONNULL_ALL -{ - xfree(buf->temp); - xfree(buf); -} - -/// Return a pointer to a raw buffer containing the first empty slot available -/// for writing. The second argument is a pointer to the maximum number of -/// bytes that could be written. -/// -/// It is necessary to call this function twice to ensure all empty space was -/// used. See RBUFFER_UNTIL_FULL for a macro that simplifies this task. -char *rbuffer_write_ptr(RBuffer *buf, size_t *write_count) FUNC_ATTR_NONNULL_ALL -{ - if (buf->size == rbuffer_capacity(buf)) { - *write_count = 0; - return NULL; - } - - if (buf->write_ptr >= buf->read_ptr) { - *write_count = (size_t)(buf->end_ptr - buf->write_ptr); - } else { - *write_count = (size_t)(buf->read_ptr - buf->write_ptr); - } - - return buf->write_ptr; -} - -// Reset an RBuffer so read_ptr is at the beginning of the memory. If -// necessary, this moves existing data by allocating temporary memory. -void rbuffer_reset(RBuffer *buf) FUNC_ATTR_NONNULL_ALL -{ - size_t temp_size; - if ((temp_size = rbuffer_size(buf))) { - if (buf->temp == NULL) { - buf->temp = xcalloc(1, rbuffer_capacity(buf)); - } - rbuffer_read(buf, buf->temp, buf->size); - } - buf->read_ptr = buf->write_ptr = buf->start_ptr; - if (temp_size) { - rbuffer_write(buf, buf->temp, temp_size); - } -} - -/// Adjust `rbuffer` write pointer to reflect produced data. This is called -/// automatically by `rbuffer_write`, but when using `rbuffer_write_ptr` -/// directly, this needs to called after the data was copied to the internal -/// buffer. The write pointer will be wrapped if required. -void rbuffer_produced(RBuffer *buf, size_t count) FUNC_ATTR_NONNULL_ALL -{ - assert(count && count <= rbuffer_space(buf)); - - buf->write_ptr += count; - if (buf->write_ptr >= buf->end_ptr) { - // wrap around - buf->write_ptr -= rbuffer_capacity(buf); - } - - buf->size += count; - if (buf->full_cb && !rbuffer_space(buf)) { - buf->full_cb(buf, buf->data); - } -} - -/// Return a pointer to a raw buffer containing the first byte available -/// for reading. The second argument is a pointer to the maximum number of -/// bytes that could be read. -/// -/// It is necessary to call this function twice to ensure all available bytes -/// were read. See RBUFFER_UNTIL_EMPTY for a macro that simplifies this task. -char *rbuffer_read_ptr(RBuffer *buf, size_t *read_count) FUNC_ATTR_NONNULL_ALL -{ - if (!buf->size) { - *read_count = 0; - return buf->read_ptr; - } - - if (buf->read_ptr < buf->write_ptr) { - *read_count = (size_t)(buf->write_ptr - buf->read_ptr); - } else { - *read_count = (size_t)(buf->end_ptr - buf->read_ptr); - } - - return buf->read_ptr; -} - -/// Adjust `rbuffer` read pointer to reflect consumed data. This is called -/// automatically by `rbuffer_read`, but when using `rbuffer_read_ptr` -/// directly, this needs to called after the data was copied from the internal -/// buffer. The read pointer will be wrapped if required. -void rbuffer_consumed(RBuffer *buf, size_t count) - FUNC_ATTR_NONNULL_ALL -{ - if (count == 0) { - return; - } - assert(count <= buf->size); - - buf->read_ptr += count; - if (buf->read_ptr >= buf->end_ptr) { - buf->read_ptr -= rbuffer_capacity(buf); - } - - bool was_full = buf->size == rbuffer_capacity(buf); - buf->size -= count; - if (buf->nonfull_cb && was_full) { - buf->nonfull_cb(buf, buf->data); - } -} - -/// Use instead of rbuffer_consumed to use rbuffer in a linear, non-cyclic fashion. -/// -/// This is generally useful if we can guarantee to parse all input -/// except some small incomplete token, like when parsing msgpack. -void rbuffer_consumed_compact(RBuffer *buf, size_t count) - FUNC_ATTR_NONNULL_ALL -{ - assert(buf->read_ptr <= buf->write_ptr); - rbuffer_consumed(buf, count); - if (buf->read_ptr > buf->start_ptr) { - assert((size_t)(buf->write_ptr - buf->read_ptr) == buf->size - || buf->write_ptr == buf->start_ptr); - memmove(buf->start_ptr, buf->read_ptr, buf->size); - buf->read_ptr = buf->start_ptr; - buf->write_ptr = buf->read_ptr + buf->size; - } -} - -// Higher level functions for copying from/to RBuffer instances and data -// pointers -size_t rbuffer_write(RBuffer *buf, const char *src, size_t src_size) - FUNC_ATTR_NONNULL_ALL -{ - size_t size = src_size; - - RBUFFER_UNTIL_FULL(buf, wptr, wcnt) { - size_t copy_count = MIN(src_size, wcnt); - memcpy(wptr, src, copy_count); - rbuffer_produced(buf, copy_count); - - if (!(src_size -= copy_count)) { - return size; - } - - src += copy_count; - } - - return size - src_size; -} - -size_t rbuffer_read(RBuffer *buf, char *dst, size_t dst_size) - FUNC_ATTR_NONNULL_ALL -{ - size_t size = dst_size; - - RBUFFER_UNTIL_EMPTY(buf, rptr, rcnt) { - size_t copy_count = MIN(dst_size, rcnt); - memcpy(dst, rptr, copy_count); - rbuffer_consumed(buf, copy_count); - - if (!(dst_size -= copy_count)) { - return size; - } - - dst += copy_count; - } - - return size - dst_size; -} - -char *rbuffer_get(RBuffer *buf, size_t index) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET -{ - assert(index < buf->size); - char *rptr = buf->read_ptr + index; - if (rptr >= buf->end_ptr) { - rptr -= rbuffer_capacity(buf); - } - return rptr; -} - -int rbuffer_cmp(RBuffer *buf, const char *str, size_t count) - FUNC_ATTR_NONNULL_ALL -{ - assert(count <= buf->size); - size_t rcnt; - rbuffer_read_ptr(buf, &rcnt); - size_t n = MIN(count, rcnt); - int rv = memcmp(str, buf->read_ptr, n); - count -= n; - size_t remaining = buf->size - rcnt; - - if (rv || !count || !remaining) { - return rv; - } - - return memcmp(str + n, buf->start_ptr, count); -} diff --git a/src/nvim/rbuffer.h b/src/nvim/rbuffer.h deleted file mode 100644 index 942e1f2365..0000000000 --- a/src/nvim/rbuffer.h +++ /dev/null @@ -1,71 +0,0 @@ -// Specialized ring buffer. This is basically an array that wraps read/write -// pointers around the memory region. It should be more efficient than the old -// RBuffer which required memmove() calls to relocate read/write positions. -// -// The main purpose of RBuffer is simplify memory management when reading from -// uv_stream_t instances: -// -// - The event loop writes data to a RBuffer, advancing the write pointer -// - The main loop reads data, advancing the read pointer -// - If the buffer becomes full(size == capacity) the rstream is temporarily -// stopped(automatic backpressure handling) -// -// Reference: http://en.wikipedia.org/wiki/Circular_buffer -#pragma once - -#include <stddef.h> -#include <stdint.h> - -#include "nvim/rbuffer_defs.h" // IWYU pragma: keep - -// Macros that simplify working with the read/write pointers directly by hiding -// ring buffer wrap logic. Some examples: -// -// - Pass the write pointer to a function(write_data) that incrementally -// produces data, returning the number of bytes actually written to the -// ring buffer: -// -// RBUFFER_UNTIL_FULL(rbuf, ptr, cnt) -// rbuffer_produced(rbuf, write_data(state, ptr, cnt)); -// -// - Pass the read pointer to a function(read_data) that incrementally -// consumes data, returning the number of bytes actually read from the -// ring buffer: -// -// RBUFFER_UNTIL_EMPTY(rbuf, ptr, cnt) -// rbuffer_consumed(rbuf, read_data(state, ptr, cnt)); -// -// Note that the rbuffer_{produced,consumed} calls are necessary or these macros -// create infinite loops -#define RBUFFER_UNTIL_EMPTY(buf, rptr, rcnt) \ - for (size_t rcnt = 0, _r = 1; _r; _r = 0) \ - for (char *rptr = rbuffer_read_ptr(buf, &rcnt); \ - buf->size; \ - rptr = rbuffer_read_ptr(buf, &rcnt)) - -#define RBUFFER_UNTIL_FULL(buf, wptr, wcnt) \ - for (size_t wcnt = 0, _r = 1; _r; _r = 0) \ - for (char *wptr = rbuffer_write_ptr(buf, &wcnt); \ - rbuffer_space(buf); \ - wptr = rbuffer_write_ptr(buf, &wcnt)) - -// Iteration -#define RBUFFER_EACH(buf, c, i) \ - for (size_t i = 0; \ - i < buf->size; \ - i = buf->size) \ - for (char c = 0; \ - i < buf->size ? ((int)(c = *rbuffer_get(buf, i))) || 1 : 0; \ - i++) - -#define RBUFFER_EACH_REVERSE(buf, c, i) \ - for (size_t i = buf->size; \ - i != SIZE_MAX; \ - i = SIZE_MAX) \ - for (char c = 0; \ - i-- > 0 ? ((int)(c = *rbuffer_get(buf, i))) || 1 : 0; \ - ) - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "rbuffer.h.generated.h" -#endif diff --git a/src/nvim/rbuffer_defs.h b/src/nvim/rbuffer_defs.h deleted file mode 100644 index 51dc349846..0000000000 --- a/src/nvim/rbuffer_defs.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include <stddef.h> - -#include "nvim/func_attr.h" - -typedef struct rbuffer RBuffer; -/// Type of function invoked during certain events: -/// - When the RBuffer switches to the full state -/// - When the RBuffer switches to the non-full state -typedef void (*rbuffer_callback)(RBuffer *buf, void *data); - -struct rbuffer { - rbuffer_callback full_cb, nonfull_cb; - void *data; - size_t size; - // helper memory used to by rbuffer_reset if required - char *temp; - char *end_ptr, *read_ptr, *write_ptr; - char start_ptr[]; -}; - -static inline size_t rbuffer_size(RBuffer *buf) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL; - -static inline size_t rbuffer_size(RBuffer *buf) -{ - return buf->size; -} - -static inline size_t rbuffer_capacity(RBuffer *buf) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL; - -static inline size_t rbuffer_capacity(RBuffer *buf) -{ - return (size_t)(buf->end_ptr - buf->start_ptr); -} - -static inline size_t rbuffer_space(RBuffer *buf) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL; - -static inline size_t rbuffer_space(RBuffer *buf) -{ - return rbuffer_capacity(buf) - buf->size; -} diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index 5600d6a2f8..c91c112c3c 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -18,6 +18,7 @@ #include "nvim/ascii_defs.h" #include "nvim/buffer_defs.h" #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" @@ -1731,7 +1732,9 @@ static void mb_decompose(int c, int *c1, int *c2, int *c3) /// Compare two strings, ignore case if rex.reg_ic set. /// Return 0 if strings match, non-zero otherwise. -/// Correct the length "*n" when composing characters are ignored. +/// Correct the length "*n" when composing characters are ignored +/// or when both utf codepoints are considered equal because of +/// case-folding but have different length (e.g. 's' and 'Å¿') static int cstrncmp(char *s1, char *s2, int *n) { int result; @@ -1739,8 +1742,27 @@ static int cstrncmp(char *s1, char *s2, int *n) if (!rex.reg_ic) { result = strncmp(s1, s2, (size_t)(*n)); } else { - assert(*n >= 0); - result = mb_strnicmp(s1, s2, (size_t)(*n)); + char *p = s1; + int n2 = 0; + int n1 = *n; + // count the number of characters for byte-length of s1 + while (n1 > 0 && *p != NUL) { + n1 -= utfc_ptr2len(s1); + MB_PTR_ADV(p); + n2++; + } + // count the number of bytes to advance the same number of chars for s2 + p = s2; + while (n2-- > 0 && *p != NUL) { + MB_PTR_ADV(p); + } + + n2 = (int)(p - s2); + + result = utf_strnicmp(s1, s2, (size_t)(*n), (size_t)n2); + if (result == 0 && n2 < *n) { + *n = n2; + } } // if it failed and it's utf8 and we want to combineignore: @@ -1798,29 +1820,34 @@ static inline char *cstrchr(const char *const s, const int c) return vim_strchr(s, c); } - // Use folded case for UTF-8, slow! For ASCII use libc strpbrk which is - // expected to be highly optimized. + int cc, lc; if (c > 0x80) { - const int folded_c = utf_fold(c); - for (const char *p = s; *p != NUL; p += utfc_ptr2len(p)) { - if (utf_fold(utf_ptr2char(p)) == folded_c) { - return (char *)p; - } - } - return NULL; - } - - int cc; - if (ASCII_ISUPPER(c)) { + cc = utf_fold(c); + lc = cc; + } else if (ASCII_ISUPPER(c)) { cc = TOLOWER_ASC(c); + lc = cc; } else if (ASCII_ISLOWER(c)) { cc = TOUPPER_ASC(c); + lc = c; } else { return vim_strchr(s, c); } - char tofind[] = { (char)c, (char)cc, NUL }; - return strpbrk(s, tofind); + for (const char *p = s; *p != NUL; p += utfc_ptr2len(p)) { + const int uc = utf_ptr2char(p); + if (c > 0x80 || uc > 0x80) { + // Do not match an illegal byte. E.g. 0xff matches 0xc3 0xbf, not 0xff. + // Compare with lower case of the character. + if ((uc < 0x80 || uc != (uint8_t)(*p)) && utf_fold(uc) == lc) { + return (char *)p; + } + } else if ((uint8_t)(*p) == c || (uint8_t)(*p) == cc) { + return (char *)p; + } + } + + return NULL; } //////////////////////////////////////////////////////////////// @@ -2167,7 +2194,7 @@ static int vim_regsub_both(char *source, typval_T *expr, char *dest, int destlen } tv_clear(&rettv); } else { - eval_result[nested] = eval_to_string(source + 2, true); + eval_result[nested] = eval_to_string(source + 2, true, false); } nesting--; @@ -3004,7 +3031,7 @@ static bool use_multibytecode(int c) { return utf_char2len(c) > 1 && (re_multi_type(peekchr()) != NOT_MULTI - || utf_iscomposing(c)); + || utf_iscomposing_legacy(c)); } // Emit (if appropriate) a byte of code @@ -4299,7 +4326,7 @@ static uint8_t *regatom(int *flagp) } // When '.' is followed by a composing char ignore the dot, so that // the composing char is matched here. - if (c == Magic('.') && utf_iscomposing(peekchr())) { + if (c == Magic('.') && utf_iscomposing_legacy(peekchr())) { c = getchr(); goto do_multibyte; } @@ -4974,9 +5001,10 @@ do_multibyte: int l; // Need to get composing character too. + GraphemeState state = GRAPHEME_STATE_INIT; while (true) { l = utf_ptr2len(regparse); - if (!utf_composinglike(regparse, regparse + l)) { + if (!utf_composinglike(regparse, regparse + l, &state)) { break; } regmbc(utf_ptr2char(regparse)); @@ -6253,15 +6281,20 @@ static bool regmatch(uint8_t *scan, const proftime_T *tm, int *timed_out) } break; - case RE_VCOL: - if (!re_num_cmp((unsigned)win_linetabsize(rex.reg_win == NULL ? curwin : rex.reg_win, - rex.reg_firstlnum + rex.lnum, - (char *)rex.line, - (colnr_T)(rex.input - rex.line)) + 1, - scan)) { + case RE_VCOL: { + win_T *wp = rex.reg_win == NULL ? curwin : rex.reg_win; + linenr_T lnum = REG_MULTI ? rex.reg_firstlnum + rex.lnum : 1; + if (REG_MULTI && (lnum <= 0 || lnum > wp->w_buffer->b_ml.ml_line_count)) { + lnum = 1; + } + int vcol = win_linetabsize(wp, lnum, (char *)rex.line, + (colnr_T)(rex.input - rex.line)); + if (!re_num_cmp((uint32_t)vcol + 1, scan)) { status = RA_NOMATCH; } break; + } + break; case BOW: // \<word; rex.input points to w if (c == NUL) { // Can't match at end of line @@ -6537,7 +6570,7 @@ static bool regmatch(uint8_t *scan, const proftime_T *tm, int *timed_out) // Check for following composing character, unless %C // follows (skips over all composing chars). if (status != RA_NOMATCH - && utf_composinglike((char *)rex.input, (char *)rex.input + len) + && utf_composinglike((char *)rex.input, (char *)rex.input + len, NULL) && !rex.reg_icombine && OP(next) != RE_COMPOSING) { // raaron: This code makes a composing character get @@ -6592,14 +6625,14 @@ static bool regmatch(uint8_t *scan, const proftime_T *tm, int *timed_out) break; } const int opndc = utf_ptr2char((char *)opnd); - if (utf_iscomposing(opndc)) { + if (utf_iscomposing_legacy(opndc)) { // When only a composing char is given match at any // position where that composing char appears. status = RA_NOMATCH; for (i = 0; rex.input[i] != NUL; i += utf_ptr2len((char *)rex.input + i)) { const int inpc = utf_ptr2char((char *)rex.input + i); - if (!utf_iscomposing(inpc)) { + if (!utf_iscomposing_legacy(inpc)) { if (i > 0) { break; } @@ -6611,11 +6644,9 @@ static bool regmatch(uint8_t *scan, const proftime_T *tm, int *timed_out) } } } else { - for (i = 0; i < len; i++) { - if (opnd[i] != rex.input[i]) { - status = RA_NOMATCH; - break; - } + if (cstrncmp((char *)opnd, (char *)rex.input, &len) != 0) { + status = RA_NOMATCH; + break; } } rex.input += len; @@ -6624,7 +6655,7 @@ static bool regmatch(uint8_t *scan, const proftime_T *tm, int *timed_out) case RE_COMPOSING: // Skip composing characters. - while (utf_iscomposing(utf_ptr2char((char *)rex.input))) { + while (utf_iscomposing_legacy(utf_ptr2char((char *)rex.input))) { rex.input += utf_ptr2len((char *)rex.input); } break; @@ -10040,7 +10071,7 @@ static int nfa_regatom(void) } // When '.' is followed by a composing char ignore the dot, so that // the composing char is matched here. - if (c == Magic('.') && utf_iscomposing(peekchr())) { + if (c == Magic('.') && utf_iscomposing_legacy(peekchr())) { old_regparse = (uint8_t *)regparse; c = getchr(); goto nfa_do_multibyte; @@ -10136,7 +10167,7 @@ static int nfa_regatom(void) case 'e': EMIT(NFA_ZEND); rex.nfa_has_zend = true; - if (!re_mult_next("\\zs")) { + if (!re_mult_next("\\ze")) { return false; } break; @@ -10675,7 +10706,7 @@ collection: nfa_do_multibyte: // plen is length of current char with composing chars if (utf_char2len(c) != (plen = utfc_ptr2len((char *)old_regparse)) - || utf_iscomposing(c)) { + || utf_iscomposing_legacy(c)) { int i = 0; // A base character plus composing characters, or just one @@ -11450,7 +11481,7 @@ static void nfa_set_code(int c) } if (addnl == true) { - STRCAT(code, " + NEWLINE "); + strcat(code, " + NEWLINE "); } } @@ -11494,7 +11525,7 @@ static void nfa_print_state(FILE *debugf, nfa_state_T *state) garray_T indent; ga_init(&indent, 1, 64); - ga_append(&indent, '\0'); + ga_append(&indent, NUL); nfa_print_state2(debugf, state, &indent); ga_clear(&indent); } @@ -13976,19 +14007,25 @@ static int skip_to_start(int c, colnr_T *colp) static int find_match_text(colnr_T *startcol, int regstart, uint8_t *match_text) { colnr_T col = *startcol; - const int regstart_len = utf_ptr2len((char *)rex.line + col); + const int regstart_len = utf_char2len(regstart); while (true) { bool match = true; uint8_t *s1 = match_text; - uint8_t *s2 = rex.line + col + regstart_len; // skip regstart + // skip regstart + int regstart_len2 = regstart_len; + if (regstart_len2 > 1 && utf_ptr2len((char *)rex.line + col) != regstart_len2) { + // because of case-folding of the previously matched text, we may need + // to skip fewer bytes than utf_char2len(regstart) + regstart_len2 = utf_char2len(utf_fold(regstart)); + } + uint8_t *s2 = rex.line + col + regstart_len2; while (*s1) { int c1_len = utf_ptr2len((char *)s1); int c1 = utf_ptr2char((char *)s1); int c2_len = utf_ptr2len((char *)s2); int c2 = utf_ptr2char((char *)s2); - if ((c1 != c2 && (!rex.reg_ic || utf_fold(c1) != utf_fold(c2))) - || c1_len != c2_len) { + if (c1 != c2 && (!rex.reg_ic || utf_fold(c1) != utf_fold(c2))) { match = false; break; } @@ -13997,7 +14034,7 @@ static int find_match_text(colnr_T *startcol, int regstart, uint8_t *match_text) } if (match // check that no composing char follows - && !utf_iscomposing(utf_ptr2char((char *)s2))) { + && !utf_iscomposing_legacy(utf_ptr2char((char *)s2))) { cleanup_subexpr(); if (REG_MULTI) { rex.reg_startpos[0].lnum = rex.lnum; @@ -14242,7 +14279,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm // is not really a match. if (!rex.reg_icombine && rex.input != rex.line - && utf_iscomposing(curc)) { + && utf_iscomposing_legacy(curc)) { break; } nfa_match = true; @@ -14586,7 +14623,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm sta = t->state->out; len = 0; - if (utf_iscomposing(sta->c)) { + if (utf_iscomposing_legacy(sta->c)) { // Only match composing character(s), ignore base // character. Used for ".{composing}" and "{composing}" // (no preceding character). @@ -14688,7 +14725,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm int j; sta = t->state->out->out; - if (utf_iscomposing(sta->c)) { + if (utf_iscomposing_legacy(sta->c)) { // Only match composing character(s), ignore base // character. Used for ".{composing}" and "{composing}" // (no preceding character). @@ -14800,7 +14837,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm } case NFA_ANY: - // Any char except '\0', (end of input) does not match. + // Any char except NUL, (end of input) does not match. if (curc > 0) { add_state = t->state->out; add_off = clen; @@ -14810,7 +14847,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm case NFA_ANY_COMPOSING: // On a composing character skip over it. Otherwise do // nothing. Always matches. - if (utf_iscomposing(curc)) { + if (utf_iscomposing_legacy(curc)) { add_off = clen; } else { add_here = true; @@ -15098,9 +15135,13 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm result = col > t->state->val * ts; } if (!result) { - int lts = win_linetabsize(wp, rex.reg_firstlnum + rex.lnum, (char *)rex.line, col); + linenr_T lnum = REG_MULTI ? rex.reg_firstlnum + rex.lnum : 1; + if (REG_MULTI && (lnum <= 0 || lnum > wp->w_buffer->b_ml.ml_line_count)) { + lnum = 1; + } + int vcol = win_linetabsize(wp, lnum, (char *)rex.line, col); assert(t->state->val >= 0); - result = nfa_re_num_cmp((uintmax_t)t->state->val, op, (uintmax_t)lts + 1); + result = nfa_re_num_cmp((uintmax_t)t->state->val, op, (uintmax_t)vcol + 1); } if (result) { add_here = true; @@ -15652,7 +15693,7 @@ static int nfa_regexec_both(uint8_t *line, colnr_T startcol, proftime_T *tm, int // If match_text is set it contains the full text that must match. // Nothing else to try. Doesn't handle combining chars well. - if (prog->match_text != NULL && !rex.reg_icombine) { + if (prog->match_text != NULL && *prog->match_text != NUL && !rex.reg_icombine) { retval = find_match_text(&col, prog->regstart, prog->match_text); if (REG_MULTI) { rex.reg_mmatch->rmm_matchcol = col; diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index d913d311db..030bda4fa5 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -22,6 +22,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/debugger.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" @@ -408,7 +409,7 @@ int do_in_path(const char *path, const char *prefix, char *name, int flags, did_one = true; } else if (buflen + 2 + strlen(prefix) + strlen(name) < MAXPATHL) { add_pathsep(buf); - STRCAT(buf, prefix); + strcat(buf, prefix); tail = buf + strlen(buf); // Loop over all patterns in "name" @@ -1099,7 +1100,7 @@ static int load_pack_plugin(bool opt, char *fname) // If runtime/filetype.lua wasn't loaded yet, the scripts will be // found when it loads. - if (opt && eval_to_number(cmd) > 0) { + if (opt && eval_to_number(cmd, false) > 0) { do_cmdline_cmd("augroup filetypedetect"); vim_snprintf(pat, len, ftpat, ffname); gen_expand_wildcards_and_cb(1, &pat, EW_FILE, true, source_callback_vim_lua, NULL); @@ -1558,7 +1559,7 @@ static inline char *add_env_sep_dirs(char *dest, const char *const val, const ch return dest; } const void *iter = NULL; - const char *appname = get_appname(); + const char *appname = get_appname(false); const size_t appname_len = strlen(appname); do { size_t dir_len; @@ -1625,7 +1626,7 @@ static inline char *add_dir(char *dest, const char *const dir, const size_t dir_ if (!after_pathsep(dest - 1, dest)) { *dest++ = PATHSEP; } - const char *appname = get_appname(); + const char *appname = get_appname(false); size_t appname_len = strlen(appname); assert(appname_len < (IOSIZE - sizeof("-data"))); xmemcpyz(IObuff, appname, appname_len); @@ -1696,7 +1697,7 @@ char *runtimepath_default(bool clean_arg) size_t config_len = 0; size_t vimruntime_len = 0; size_t libdir_len = 0; - const char *appname = get_appname(); + const char *appname = get_appname(false); size_t appname_len = strlen(appname); if (data_home != NULL) { data_len = strlen(data_home); @@ -2856,7 +2857,7 @@ bool script_autoload(const char *const name, const size_t name_len, const bool r // Try loading the package from $VIMRUNTIME/autoload/<name>.vim // Use "ret_sid" to avoid loading the same script again. int ret_sid; - if (do_in_runtimepath(scriptname, 0, source_callback, &ret_sid) == OK) { + if (do_in_runtimepath(scriptname, DIP_START, source_callback, &ret_sid) == OK) { ret = true; } } diff --git a/src/nvim/search.c b/src/nvim/search.c index 746c253708..ff6e135df1 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -18,14 +18,18 @@ #include "nvim/cmdhist.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" +#include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" +#include "nvim/file_search.h" #include "nvim/fileio.h" #include "nvim/fold.h" +#include "nvim/garray.h" #include "nvim/getchar.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" @@ -287,7 +291,7 @@ void restore_search_patterns(void) static inline void free_spat(SearchPattern *const spat) { xfree(spat->pat); - tv_dict_unref(spat->additional_data); + xfree(spat->additional_data); } #if defined(EXITFREE) @@ -944,11 +948,9 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, // This message is also remembered in keep_msg for when the screen // is redrawn. The keep_msg is cleared whenever another message is // written. - if (dir == BACKWARD) { // start second loop at the other end - lnum = buf->b_ml.ml_line_count; - } else { - lnum = 1; - } + lnum = dir == BACKWARD // start second loop at the other end + ? buf->b_ml.ml_line_count + : 1; if (!shortmess(SHM_SEARCH) && shortmess(SHM_SEARCHCOUNT) && (options & SEARCH_MSG)) { @@ -1050,7 +1052,6 @@ static int first_submatch(regmmatch_T *rp) int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, size_t patlen, int count, int options, searchit_arg_T *sia) { - pos_T pos; // position of the last match char *searchstr; size_t searchstrlen; int retval; // Return value @@ -1075,7 +1076,8 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, size_t patlen // (there is no "if ()" around this because gcc wants them initialized) SearchOffset old_off = spats[0].off; - pos = curwin->w_cursor; // start searching at the cursor position + pos_T pos = curwin->w_cursor; // Position of the last match. + // Start searching at the cursor position. // Find out the direction of the search. if (dirc == 0) { @@ -1085,11 +1087,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, size_t patlen set_vv_searchforward(); } if (options & SEARCH_REV) { - if (dirc == '/') { - dirc = '?'; - } else { - dirc = '/'; - } + dirc = dirc == '/' ? '?' : '/'; } // If the cursor is in a closed fold, don't find another match in the same @@ -1262,7 +1260,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, size_t patlen // empty for the search_stat feature. if (!cmd_silent) { msgbuf[0] = (char)dirc; - if (utf_iscomposing(utf_ptr2char(p))) { + if (utf_iscomposing_first(utf_ptr2char(p))) { // Use a space to draw the composing char on. msgbuf[1] = ' '; memmove(msgbuf + 2, p, plen); @@ -1561,11 +1559,9 @@ int searchc(cmdarg_T *cap, bool t_cmd) if (*lastc == NUL && lastc_bytelen <= 1) { return FAIL; } - if (dir) { // repeat in opposite direction - dir = -lastcdir; - } else { - dir = lastcdir; - } + dir = dir // repeat in opposite direction + ? -lastcdir + : lastcdir; t_cmd = last_t_cmd; c = *lastc; // For multi-byte re-use last lastc_bytes[] and lastc_bytelen. @@ -1578,11 +1574,7 @@ int searchc(cmdarg_T *cap, bool t_cmd) } } - if (dir == BACKWARD) { - cap->oap->inclusive = false; - } else { - cap->oap->inclusive = true; - } + cap->oap->inclusive = dir != BACKWARD; char *p = get_cursor_line_ptr(); int col = curwin->w_cursor.col; @@ -2429,17 +2421,13 @@ int current_search(int count, bool forward) dec_cursor(); } - pos_T end_pos; // end position of the pattern match - pos_T orig_pos; // position of the cursor at beginning - pos_T pos; // position after the pattern - int result; // result of various function calls - // When searching forward and the cursor is at the start of the Visual // area, skip the first search backward, otherwise it doesn't move. const bool skip_first_backward = forward && VIsual_active && lt(curwin->w_cursor, VIsual); - orig_pos = pos = curwin->w_cursor; + pos_T pos = curwin->w_cursor; // position after the pattern + pos_T orig_pos = curwin->w_cursor; // position of the cursor at beginning if (VIsual_active) { // Searching further will extend the match. if (forward) { @@ -2456,6 +2444,9 @@ int current_search(int count, bool forward) return FAIL; // pattern not found } + pos_T end_pos; // end position of the pattern match + int result; // result of various function calls + // The trick is to first search backwards and then search forward again, // so that a match at the current cursor position will be correctly // captured. When "forward" is false do it the other way around. @@ -3235,9 +3226,8 @@ static int fuzzy_match_item_compare(const void *const s1, const void *const s2) if (v1 == v2) { return idx1 == idx2 ? 0 : idx1 > idx2 ? 1 : -1; - } else { - return v1 > v2 ? -1 : 1; } + return v1 > v2 ? -1 : 1; } /// Fuzzy search the string "str" in a list of "items" and return the matching @@ -3511,9 +3501,8 @@ static int fuzzy_match_func_compare(const void *const s1, const void *const s2) } if (v1 == v2) { return idx1 == idx2 ? 0 : idx1 > idx2 ? 1 : -1; - } else { - return v1 > v2 ? -1 : 1; } + return v1 > v2 ? -1 : 1; } /// Sort fuzzy matches of function names by score. @@ -3541,6 +3530,37 @@ int fuzzy_match_str(char *const str, const char *const pat) return score; } +/// Fuzzy match the position of string "pat" in string "str". +/// @returns a dynamic array of matching positions. If there is no match, returns NULL. +garray_T *fuzzy_match_str_with_pos(char *const str, const char *const pat) +{ + if (str == NULL || pat == NULL) { + return NULL; + } + + garray_T *match_positions = xmalloc(sizeof(garray_T)); + ga_init(match_positions, sizeof(uint32_t), 10); + + unsigned matches[MAX_FUZZY_MATCHES]; + int score = 0; + if (!fuzzy_match(str, pat, false, &score, matches, MAX_FUZZY_MATCHES) + || score == 0) { + ga_clear(match_positions); + xfree(match_positions); + return NULL; + } + + int j = 0; + for (const char *p = pat; *p != NUL; MB_PTR_ADV(p)) { + if (!ascii_iswhite(utf_ptr2char(p))) { + GA_APPEND(uint32_t, match_positions, matches[j]); + j++; + } + } + + return match_positions; +} + /// Copy a list of fuzzy matches into a string list after sorting the matches by /// the fuzzy score. Frees the memory allocated for "fuzmatch". void fuzzymatches_to_strmatches(fuzmatch_str_T *const fuzmatch, char ***const matches, @@ -3670,13 +3690,8 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool int old_files = max_path_depth; int depth = depth_displayed = -1; - linenr_T lnum = start_lnum; - if (end_lnum > curbuf->b_ml.ml_line_count) { - end_lnum = curbuf->b_ml.ml_line_count; - } - if (lnum > end_lnum) { // do at least one line - lnum = end_lnum; - } + end_lnum = MIN(end_lnum, curbuf->b_ml.ml_line_count); + linenr_T lnum = MIN(start_lnum, end_lnum); // do at least one line char *line = get_line_and_copy(lnum, file_line); while (true) { @@ -4125,9 +4140,7 @@ exit_matched: depth--; curr_fname = (depth == -1) ? curbuf->b_fname : files[depth].name; - if (depth < depth_displayed) { - depth_displayed = depth; - } + depth_displayed = MIN(depth_displayed, depth); } if (depth >= 0) { // we could read the line files[depth].lnum++; @@ -4288,9 +4301,3 @@ bool search_was_last_used(void) { return last_idx == 0; } - -/// @return true if 'hlsearch' highlight is currently in use. -bool using_hlsearch(void) -{ - return spats[last_idx].pat != NULL && p_hls && !no_hlsearch; -} diff --git a/src/nvim/search.h b/src/nvim/search.h index 783756b781..1b6c1a6375 100644 --- a/src/nvim/search.h +++ b/src/nvim/search.h @@ -84,12 +84,12 @@ typedef struct { /// Structure containing last search pattern and its attributes. typedef struct { char *pat; ///< The pattern (in allocated memory) or NULL. - size_t patlen; ///< The length of the patten (0 is pat is NULL). + size_t patlen; ///< The length of the pattern (0 if pat is NULL). bool magic; ///< Magicness of the pattern. bool no_scs; ///< No smartcase for this pattern. Timestamp timestamp; ///< Time of the last change. SearchOffset off; ///< Pattern offset. - dict_T *additional_data; ///< Additional data from ShaDa file. + AdditionalData *additional_data; ///< Additional data from ShaDa file. } SearchPattern; /// Optional extra arguments for searchit(). diff --git a/src/nvim/sha256.c b/src/nvim/sha256.c index d49224a987..f892d93236 100644 --- a/src/nvim/sha256.c +++ b/src/nvim/sha256.c @@ -15,6 +15,7 @@ #include <stdio.h> #include <string.h> +#include "nvim/ascii_defs.h" #include "nvim/memory.h" #include "nvim/sha256.h" @@ -222,18 +223,15 @@ static uint8_t sha256_padding[SHA256_BUFFER_SIZE] = { void sha256_finish(context_sha256_T *ctx, uint8_t digest[SHA256_SUM_SIZE]) { - uint32_t last, padn; - uint32_t high, low; - uint8_t msglen[8]; - - high = (ctx->total[0] >> 29) | (ctx->total[1] << 3); - low = (ctx->total[0] << 3); + uint32_t high = (ctx->total[0] >> 29) | (ctx->total[1] << 3); + uint32_t low = (ctx->total[0] << 3); + uint8_t msglen[8]; PUT_UINT32(high, msglen, 0); PUT_UINT32(low, msglen, 4); - last = ctx->total[0] & 0x3F; - padn = (last < 56) ? (56 - last) : (120 - last); + uint32_t last = ctx->total[0] & 0x3F; + uint32_t padn = (last < 56) ? (56 - last) : (120 - last); sha256_update(ctx, sha256_padding, padn); sha256_update(ctx, msglen, 8); @@ -262,24 +260,24 @@ void sha256_finish(context_sha256_T *ctx, uint8_t digest[SHA256_SUM_SIZE]) const char *sha256_bytes(const uint8_t *restrict buf, size_t buf_len, const uint8_t *restrict salt, size_t salt_len) { - uint8_t sha256sum[SHA256_SUM_SIZE]; static char hexit[SHA256_BUFFER_SIZE + 1]; // buf size + NULL - context_sha256_T ctx; sha256_self_test(); + context_sha256_T ctx; sha256_start(&ctx); sha256_update(&ctx, buf, buf_len); if (salt != NULL) { sha256_update(&ctx, salt, salt_len); } + uint8_t sha256sum[SHA256_SUM_SIZE]; sha256_finish(&ctx, sha256sum); for (size_t j = 0; j < SHA256_SUM_SIZE; j++) { snprintf(hexit + j * SHA_STEP, SHA_STEP + 1, "%02x", sha256sum[j]); } - hexit[sizeof(hexit) - 1] = '\0'; + hexit[sizeof(hexit) - 1] = NUL; return hexit; } @@ -340,7 +338,7 @@ bool sha256_self_test(void) if (memcmp(output, sha_self_test_vector[i], SHA256_BUFFER_SIZE) != 0) { failures = true; - output[sizeof(output) - 1] = '\0'; + output[sizeof(output) - 1] = NUL; // printf("sha256_self_test %d failed %s\n", i, output); } diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 34c36f850f..2b401fa106 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -1,9 +1,5 @@ #include <assert.h> #include <inttypes.h> -#include <msgpack/object.h> -#include <msgpack/pack.h> -#include <msgpack/sbuffer.h> -#include <msgpack/unpack.h> #include <stdbool.h> #include <stddef.h> #include <stdio.h> @@ -13,12 +9,14 @@ #include <uv.h> #include "auto/config.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/ascii_defs.h" #include "nvim/buffer.h" #include "nvim/buffer_defs.h" #include "nvim/cmdhist.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/decode.h" #include "nvim/eval/encode.h" @@ -41,6 +39,8 @@ #include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/message.h" +#include "nvim/msgpack_rpc/packer.h" +#include "nvim/msgpack_rpc/unpacker.h" #include "nvim/normal_defs.h" #include "nvim/ops.h" #include "nvim/option.h" @@ -69,26 +69,26 @@ # include ENDIAN_INCLUDE_FILE #endif -#define SEARCH_KEY_MAGIC "sm" -#define SEARCH_KEY_SMARTCASE "sc" -#define SEARCH_KEY_HAS_LINE_OFFSET "sl" -#define SEARCH_KEY_PLACE_CURSOR_AT_END "se" -#define SEARCH_KEY_IS_LAST_USED "su" -#define SEARCH_KEY_IS_SUBSTITUTE_PATTERN "ss" -#define SEARCH_KEY_HIGHLIGHTED "sh" -#define SEARCH_KEY_OFFSET "so" -#define SEARCH_KEY_PAT "sp" -#define SEARCH_KEY_BACKWARD "sb" - -#define REG_KEY_TYPE "rt" -#define REG_KEY_WIDTH "rw" -#define REG_KEY_CONTENTS "rc" -#define REG_KEY_UNNAMED "ru" - -#define KEY_LNUM "l" -#define KEY_COL "c" -#define KEY_FILE "f" -#define KEY_NAME_CHAR "n" +#define SEARCH_KEY_MAGIC sm +#define SEARCH_KEY_SMARTCASE sc +#define SEARCH_KEY_HAS_LINE_OFFSET sl +#define SEARCH_KEY_PLACE_CURSOR_AT_END se +#define SEARCH_KEY_IS_LAST_USED su +#define SEARCH_KEY_IS_SUBSTITUTE_PATTERN ss +#define SEARCH_KEY_HIGHLIGHTED sh +#define SEARCH_KEY_OFFSET so +#define SEARCH_KEY_PAT sp +#define SEARCH_KEY_BACKWARD sb + +#define REG_KEY_TYPE rt +#define REG_KEY_WIDTH rw +#define REG_KEY_CONTENTS rc +#define REG_KEY_UNNAMED ru + +#define KEY_LNUM l +#define KEY_COL c +#define KEY_FILE f +#define KEY_NAME_CHAR n // Error messages formerly used by viminfo code: // E136: viminfo: Too many errors, skipping rest of file @@ -231,31 +231,17 @@ typedef struct { ShadaEntryType type; Timestamp timestamp; union { - Dictionary header; + Dict header; struct shada_filemark { char name; pos_T mark; char *fname; - dict_T *additional_data; } filemark; - struct search_pattern { - bool magic; - bool smartcase; - bool has_line_offset; - bool place_cursor_at_end; - int64_t offset; - bool is_last_used; - bool is_substitute_pattern; - bool highlighted; - bool search_backward; - char *pat; - dict_T *additional_data; - } search_pattern; + Dict(_shada_search_pat) search_pattern; struct history_item { uint8_t histtype; char *string; char sep; - list_T *additional_elements; } history_item; struct reg { // yankreg_T char name; @@ -264,12 +250,10 @@ typedef struct { bool is_unnamed; size_t contents_size; size_t width; - dict_T *additional_data; } reg; struct global_var { char *name; typval_T value; - list_T *additional_elements; } global_var; struct { uint64_t type; @@ -278,17 +262,17 @@ typedef struct { } unknown_item; struct sub_string { char *sub; - list_T *additional_elements; } sub_string; struct buffer_list { size_t size; struct buffer_list_buffer { pos_T pos; char *fname; - dict_T *additional_data; + AdditionalData *additional_data; } *buffers; } buffer_list; } data; + AdditionalData *additional_data; } ShadaEntry; /// One entry in sized linked list @@ -356,35 +340,6 @@ typedef struct { PMap(cstr_t) file_marks; ///< All file marks. } WriteMergerState; -typedef struct sd_read_def ShaDaReadDef; - -/// Function used to close files defined by ShaDaReadDef -typedef void (*ShaDaReadCloser)(ShaDaReadDef *const sd_reader) - REAL_FATTR_NONNULL_ALL; - -/// Function used to read ShaDa files -typedef ptrdiff_t (*ShaDaFileReader)(ShaDaReadDef *const sd_reader, - void *const dest, - const size_t size) - REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT; - -/// Function used to skip in ShaDa files -typedef int (*ShaDaFileSkipper)(ShaDaReadDef *const sd_reader, - const size_t offset) - REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT; - -/// Structure containing necessary pointers for reading ShaDa files -struct sd_read_def { - ShaDaFileReader read; ///< Reader function. - ShaDaReadCloser close; ///< Close function. - ShaDaFileSkipper skip; ///< Function used to skip some bytes. - void *cookie; ///< Data describing object read from. - bool eof; ///< True if reader reached end of file. - const char *error; ///< Error message in case of error. - uintmax_t fpos; ///< Current position (amount of bytes read since - ///< reader structure initialization). May overflow. -}; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "shada.c.generated.h" #endif @@ -393,6 +348,7 @@ struct sd_read_def { [kSDItem##name] = { \ .timestamp = 0, \ .type = kSDItem##name, \ + .additional_data = NULL, \ .data = { \ .attr = { __VA_ARGS__ } \ } \ @@ -412,49 +368,41 @@ static const ShadaEntry sd_default_values[] = { .is_substitute_pattern = false, .highlighted = false, .search_backward = false, - .pat = NULL, - .additional_data = NULL), - DEF_SDE(SubString, sub_string, .sub = NULL, .additional_elements = NULL), + .pat = STRING_INIT), + DEF_SDE(SubString, sub_string, .sub = NULL), DEF_SDE(HistoryEntry, history_item, .histtype = HIST_CMD, .string = NULL, - .sep = NUL, - .additional_elements = NULL), + .sep = NUL), DEF_SDE(Register, reg, .name = NUL, .type = kMTCharWise, .contents = NULL, .contents_size = 0, .is_unnamed = false, - .width = 0, - .additional_data = NULL), + .width = 0), DEF_SDE(Variable, global_var, .name = NULL, - .value = { .v_type = VAR_UNKNOWN, .vval = { .v_string = NULL } }, - .additional_elements = NULL), + .value = { .v_type = VAR_UNKNOWN, .vval = { .v_string = NULL } }), DEF_SDE(GlobalMark, filemark, .name = '"', .mark = DEFAULT_POS, - .fname = NULL, - .additional_data = NULL), + .fname = NULL), DEF_SDE(Jump, filemark, .name = NUL, .mark = DEFAULT_POS, - .fname = NULL, - .additional_data = NULL), + .fname = NULL), DEF_SDE(BufferList, buffer_list, .size = 0, .buffers = NULL), DEF_SDE(LocalMark, filemark, .name = '"', .mark = DEFAULT_POS, - .fname = NULL, - .additional_data = NULL), + .fname = NULL), DEF_SDE(Change, filemark, .name = NUL, .mark = DEFAULT_POS, - .fname = NULL, - .additional_data = NULL), + .fname = NULL), }; #undef DEFAULT_POS #undef DEF_SDE @@ -587,70 +535,6 @@ static inline void hmll_dealloc(HMLList *const hmll) xfree(hmll->entries); } -/// Wrapper for reading from file descriptors -/// -/// @return -1 or number of bytes read. -static ptrdiff_t read_file(ShaDaReadDef *const sd_reader, void *const dest, const size_t size) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - const ptrdiff_t ret = file_read(sd_reader->cookie, dest, size); - sd_reader->eof = file_eof(sd_reader->cookie); - if (ret < 0) { - sd_reader->error = os_strerror((int)ret); - return -1; - } - sd_reader->fpos += (size_t)ret; - return ret; -} - -/// Read one character -static int read_char(ShaDaReadDef *const sd_reader) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - uint8_t ret; - ptrdiff_t read_bytes = sd_reader->read(sd_reader, &ret, 1); - if (read_bytes != 1) { - return EOF; - } - return (int)ret; -} - -/// Wrapper for closing file descriptors opened for reading -static void close_sd_reader(ShaDaReadDef *const sd_reader) - FUNC_ATTR_NONNULL_ALL -{ - close_file(sd_reader->cookie); - xfree(sd_reader->cookie); -} - -/// Wrapper for read that reads to IObuff and ignores bytes read -/// -/// Used for skipping. -/// -/// @param[in,out] sd_reader File read. -/// @param[in] offset Amount of bytes to skip. -/// -/// @return FAIL in case of failure, OK in case of success. May set -/// sd_reader->eof or sd_reader->error. -static int sd_reader_skip_read(ShaDaReadDef *const sd_reader, const size_t offset) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - const ptrdiff_t skip_bytes = file_skip(sd_reader->cookie, offset); - if (skip_bytes < 0) { - sd_reader->error = os_strerror((int)skip_bytes); - return FAIL; - } else if (skip_bytes != (ptrdiff_t)offset) { - assert(skip_bytes < (ptrdiff_t)offset); - sd_reader->eof = file_eof(sd_reader->cookie); - if (!sd_reader->eof) { - sd_reader->error = _("too few bytes read"); - } - return FAIL; - } - sd_reader->fpos += (size_t)skip_bytes; - return OK; -} - /// Wrapper for read that can be used when lseek cannot be used /// /// E.g. when trying to read from a pipe. @@ -660,55 +544,30 @@ static int sd_reader_skip_read(ShaDaReadDef *const sd_reader, const size_t offse /// /// @return kSDReadStatusReadError, kSDReadStatusNotShaDa or /// kSDReadStatusSuccess. -static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader, const size_t offset) +static ShaDaReadResult sd_reader_skip(FileDescriptor *const sd_reader, const size_t offset) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { - if (sd_reader->skip(sd_reader, offset) != OK) { - if (sd_reader->error != NULL) { - semsg(_(SERR "System error while skipping in ShaDa file: %s"), - sd_reader->error); - return kSDReadStatusReadError; - } else if (sd_reader->eof) { + const ptrdiff_t skip_bytes = file_skip(sd_reader, offset); + if (skip_bytes < 0) { + semsg(_(SERR "System error while skipping in ShaDa file: %s"), + os_strerror((int)skip_bytes)); + return kSDReadStatusReadError; + } else if (skip_bytes != (ptrdiff_t)offset) { + assert(skip_bytes < (ptrdiff_t)offset); + if (file_eof(sd_reader)) { semsg(_(RCERR "Error while reading ShaDa file: " "last entry specified that it occupies %" PRIu64 " bytes, " "but file ended earlier"), (uint64_t)offset); - return kSDReadStatusNotShaDa; + } else { + semsg(_(SERR "System error while skipping in ShaDa file: %s"), + _("too few bytes read")); } - abort(); + return kSDReadStatusNotShaDa; } return kSDReadStatusSuccess; } -/// Open ShaDa file for reading -/// -/// @param[in] fname File name to open. -/// @param[out] sd_reader Location where reader structure will be saved. -/// -/// @return libuv error in case of error, 0 otherwise. -static int open_shada_file_for_reading(const char *const fname, ShaDaReadDef *sd_reader) - FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL -{ - *sd_reader = (ShaDaReadDef) { - .read = &read_file, - .close = &close_sd_reader, - .skip = &sd_reader_skip_read, - .error = NULL, - .eof = false, - .fpos = 0, - .cookie = xmalloc(sizeof(FileDescriptor)), - }; - int error = file_open(sd_reader->cookie, fname, kFileReadOnly, 0); - if (error) { - XFREE_CLEAR(sd_reader->cookie); - return error; - } - - assert(strcmp(p_enc, "utf-8") == 0); - - return 0; -} - /// Wrapper for closing file descriptors static void close_file(FileDescriptor *cookie) { @@ -719,20 +578,6 @@ static void close_file(FileDescriptor *cookie) } } -/// Msgpack callback for writing to FileDescriptor* -static int msgpack_sd_writer_write(void *data, const char *buf, size_t len) -{ - FileDescriptor *const sd_writer = (FileDescriptor *)data; - const ptrdiff_t ret = file_write(sd_writer, buf, len); - if (ret < 0) { - semsg(_(SERR "System error while writing ShaDa file: %s"), - os_strerror((int)ret)); - return -1; - } - - return 0; -} - /// Check whether writing to shada file was disabled ("-i NONE" or "--clean"). /// /// @return true if it was disabled, false otherwise. @@ -757,8 +602,8 @@ static int shada_read_file(const char *const file, const int flags) char *const fname = shada_filename(file); - ShaDaReadDef sd_reader; - const int of_ret = open_shada_file_for_reading(fname, &sd_reader); + FileDescriptor sd_reader; + int of_ret = file_open(&sd_reader, fname, kFileReadOnly, 0); if (p_verbose > 1) { verbose_enter(); @@ -782,7 +627,7 @@ static int shada_read_file(const char *const file, const int flags) xfree(fname); shada_read(&sd_reader, flags); - sd_reader.close(&sd_reader); + close_file(&sd_reader); return OK; } @@ -815,9 +660,9 @@ static const void *shada_hist_iter(const void *const iter, const uint8_t history .sep = (char)(history_type == HIST_SEARCH ? hist_he.hisstr[strlen(hist_he.hisstr) + 1] : 0), - .additional_elements = hist_he.additional_elements, } - } + }, + .additional_data = hist_he.additional_data, }; } return ret; @@ -939,8 +784,7 @@ static inline void hms_to_he_array(const HistoryMergerState *const hms_p, hist->timestamp = cur_entry->data.timestamp; hist->hisnum = (int)(hist - hist_array) + 1; hist->hisstr = cur_entry->data.data.history_item.string; - hist->additional_elements = - cur_entry->data.data.history_item.additional_elements; + hist->additional_data = cur_entry->data.additional_data; hist++; }) *new_hisnum = (int)(hist - hist_array); @@ -968,7 +812,7 @@ static inline void hms_dealloc(HistoryMergerState *const hms_p) /// Iterate over global variables /// -/// @warning No modifications to global variable dictionary must be performed +/// @warning No modifications to global variable Dict must be performed /// while iteration is in progress. /// /// @param[in] iter Iterator. Pass NULL to start iteration. @@ -1094,7 +938,7 @@ static inline bool marks_equal(const pos_T a, const pos_T b) /// /// @param[in] sd_reader Structure containing file reader definition. /// @param[in] flags What to read, see ShaDaReadFileFlags enum. -static void shada_read(ShaDaReadDef *const sd_reader, const int flags) +static void shada_read(FileDescriptor *const sd_reader, const int flags) FUNC_ATTR_NONNULL_ALL { list_T *oldfiles_list = get_vim_var_list(VV_OLDFILES); @@ -1187,9 +1031,9 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) .end = cur_entry.data.search_pattern.place_cursor_at_end, .off = cur_entry.data.search_pattern.offset, }, - .pat = cur_entry.data.search_pattern.pat, - .patlen = strlen(cur_entry.data.search_pattern.pat), - .additional_data = cur_entry.data.search_pattern.additional_data, + .pat = cur_entry.data.search_pattern.pat.data, + .patlen = cur_entry.data.search_pattern.pat.size, + .additional_data = cur_entry.additional_data, .timestamp = cur_entry.timestamp, }; @@ -1217,7 +1061,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) sub_set_replacement((SubReplacementString) { .sub = cur_entry.data.sub_string.sub, .timestamp = cur_entry.timestamp, - .additional_elements = cur_entry.data.sub_string.additional_elements, + .additional_data = cur_entry.additional_data, }); // Without using regtilde and without / &cpo flag previous substitute // string is close to useless: you can only use it with :& or :~ and @@ -1255,7 +1099,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) .y_type = cur_entry.data.reg.type, .y_width = (colnr_T)cur_entry.data.reg.width, .timestamp = cur_entry.timestamp, - .additional_data = cur_entry.data.reg.additional_data, + .additional_data = cur_entry.additional_data, }, cur_entry.data.reg.is_unnamed)) { shada_free_shada_entry(&cur_entry); } @@ -1280,7 +1124,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) .fnum = (buf == NULL ? 0 : buf->b_fnum), .timestamp = cur_entry.timestamp, .view = INIT_FMARKV, - .additional_data = cur_entry.data.filemark.additional_data, + .additional_data = cur_entry.additional_data, }, }; if (cur_entry.type == kSDItemGlobalMark) { @@ -1322,8 +1166,9 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) cur_entry.data.buffer_list.buffers[i].pos, 0, view); buflist_setfpos(buf, curwin, buf->b_last_cursor.mark.lnum, buf->b_last_cursor.mark.col, false); - buf->additional_data = - cur_entry.data.buffer_list.buffers[i].additional_data; + + xfree(buf->additional_data); + buf->additional_data = cur_entry.data.buffer_list.buffers[i].additional_data; cur_entry.data.buffer_list.buffers[i].additional_data = NULL; } } @@ -1360,7 +1205,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) .fnum = 0, .timestamp = cur_entry.timestamp, .view = INIT_FMARKV, - .additional_data = cur_entry.data.filemark.additional_data, + .additional_data = cur_entry.additional_data, }; if (cur_entry.type == kSDItemLocalMark) { if (!mark_set_local(cur_entry.data.filemark.name, buf, fm, !force)) { @@ -1468,19 +1313,30 @@ static char *shada_filename(const char *file) return xstrdup(file); } -#define PACK_STATIC_STR(s) \ - do { \ - msgpack_pack_str(spacker, sizeof(s) - 1); \ - msgpack_pack_str_body(spacker, s, sizeof(s) - 1); \ - } while (0) -#define PACK_BIN(s) \ - do { \ - const String s_ = (s); \ - msgpack_pack_bin(spacker, s_.size); \ - if (s_.size > 0) { \ - msgpack_pack_bin_body(spacker, s_.data, s_.size); \ - } \ - } while (0) +#define KEY_NAME_(s) #s +#define PACK_KEY(s) mpack_str(STATIC_CSTR_AS_STRING(KEY_NAME_(s)), &sbuf); +#define KEY_NAME(s) KEY_NAME_(s) + +#define SHADA_MPACK_FREE_SPACE (4 * MPACK_ITEM_SIZE) + +static void shada_check_buffer(PackerBuffer *packer) +{ + if (mpack_remaining(packer) < SHADA_MPACK_FREE_SPACE) { + packer->packer_flush(packer); + } +} + +static uint32_t additional_data_len(AdditionalData *src) +{ + return src ? src->nitems : 0; +} + +static void dump_additional_data(AdditionalData *src, PackerBuffer *sbuf) +{ + if (src != NULL) { + mpack_raw(src->data, src->nbytes, sbuf); + } +} /// Write single ShaDa entry /// @@ -1490,145 +1346,93 @@ static char *shada_filename(const char *file) /// restrictions. /// /// @return kSDWriteSuccessful, kSDWriteFailed or kSDWriteIgnError. -static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, ShadaEntry entry, +static ShaDaWriteResult shada_pack_entry(PackerBuffer *const packer, ShadaEntry entry, const size_t max_kbyte) FUNC_ATTR_NONNULL_ALL { ShaDaWriteResult ret = kSDWriteFailed; - msgpack_sbuffer sbuf; - msgpack_sbuffer_init(&sbuf); - msgpack_packer *spacker = msgpack_packer_new(&sbuf, &msgpack_sbuffer_write); -#define DUMP_ADDITIONAL_ELEMENTS(src, what) \ - do { \ - if ((src) != NULL) { \ - TV_LIST_ITER((src), li, { \ - if (encode_vim_to_msgpack(spacker, TV_LIST_ITEM_TV(li), \ - _("additional elements of ShaDa " what)) \ - == FAIL) { \ - goto shada_pack_entry_error; \ - } \ - }); \ - } \ - } while (0) -#define DUMP_ADDITIONAL_DATA(src, what) \ - do { \ - dict_T *const d = (src); \ - if (d != NULL) { \ - size_t todo = d->dv_hashtab.ht_used; \ - for (const hashitem_T *hi = d->dv_hashtab.ht_array; todo; hi++) { \ - if (!HASHITEM_EMPTY(hi)) { \ - todo--; \ - dictitem_T *const di = TV_DICT_HI2DI(hi); \ - const size_t key_len = strlen(hi->hi_key); \ - msgpack_pack_str(spacker, key_len); \ - msgpack_pack_str_body(spacker, hi->hi_key, key_len); \ - if (encode_vim_to_msgpack(spacker, &di->di_tv, \ - _("additional data of ShaDa " what)) \ - == FAIL) { \ - goto shada_pack_entry_error; \ - } \ - } \ - } \ - } \ - } while (0) + PackerBuffer sbuf = packer_string_buffer(); + #define CHECK_DEFAULT(entry, attr) \ (sd_default_values[(entry).type].data.attr == (entry).data.attr) #define ONE_IF_NOT_DEFAULT(entry, attr) \ - ((size_t)(!CHECK_DEFAULT(entry, attr))) + ((uint32_t)(!CHECK_DEFAULT(entry, attr))) #define PACK_BOOL(entry, name, attr) \ do { \ if (!CHECK_DEFAULT(entry, search_pattern.attr)) { \ - PACK_STATIC_STR(name); \ - if (sd_default_values[(entry).type].data.search_pattern.attr) { \ - msgpack_pack_false(spacker); \ - } else { \ - msgpack_pack_true(spacker); \ - } \ + PACK_KEY(name); \ + mpack_bool(&sbuf.ptr, !sd_default_values[(entry).type].data.search_pattern.attr); \ } \ } while (0) + + shada_check_buffer(&sbuf); switch (entry.type) { case kSDItemMissing: abort(); case kSDItemUnknown: - if (spacker->callback(spacker->data, entry.data.unknown_item.contents, - (unsigned)entry.data.unknown_item.size) == -1) { - goto shada_pack_entry_error; - } + mpack_raw(entry.data.unknown_item.contents, entry.data.unknown_item.size, &sbuf); break; case kSDItemHistoryEntry: { const bool is_hist_search = entry.data.history_item.histtype == HIST_SEARCH; - const size_t arr_size = 2 + (size_t)is_hist_search + (size_t)( - tv_list_len(entry.data. - history_item. - additional_elements)); - msgpack_pack_array(spacker, arr_size); - msgpack_pack_uint8(spacker, entry.data.history_item.histtype); - PACK_BIN(cstr_as_string(entry.data.history_item.string)); + uint32_t arr_size = (2 + (uint32_t)is_hist_search + + additional_data_len(entry.additional_data)); + mpack_array(&sbuf.ptr, arr_size); + mpack_uint(&sbuf.ptr, entry.data.history_item.histtype); + mpack_bin(cstr_as_string(entry.data.history_item.string), &sbuf); if (is_hist_search) { - msgpack_pack_uint8(spacker, (uint8_t)entry.data.history_item.sep); + mpack_uint(&sbuf.ptr, (uint8_t)entry.data.history_item.sep); } - DUMP_ADDITIONAL_ELEMENTS(entry.data.history_item.additional_elements, - "history entry item"); + dump_additional_data(entry.additional_data, &sbuf); break; } case kSDItemVariable: { - if (entry.data.global_var.value.v_type == VAR_BLOB) { - // Strings and Blobs both pack as msgpack BINs; differentiate them by - // storing an additional VAR_TYPE_BLOB element alongside Blobs - list_T *const list = tv_list_alloc(1); - tv_list_append_number(list, VAR_TYPE_BLOB); - entry.data.global_var.additional_elements = list; - } - const size_t arr_size = 2 + (size_t)(tv_list_len(entry.data.global_var.additional_elements)); - msgpack_pack_array(spacker, arr_size); + bool is_blob = (entry.data.global_var.value.v_type == VAR_BLOB); + uint32_t arr_size = 2 + (is_blob ? 1 : 0) + additional_data_len(entry.additional_data); + mpack_array(&sbuf.ptr, arr_size); const String varname = cstr_as_string(entry.data.global_var.name); - PACK_BIN(varname); + mpack_bin(varname, &sbuf); char vardesc[256] = "variable g:"; memcpy(&vardesc[sizeof("variable g:") - 1], varname.data, varname.size + 1); - if (encode_vim_to_msgpack(spacker, &entry.data.global_var.value, vardesc) + if (encode_vim_to_msgpack(&sbuf, &entry.data.global_var.value, vardesc) == FAIL) { ret = kSDWriteIgnError; semsg(_(WERR "Failed to write variable %s"), entry.data.global_var.name); goto shada_pack_entry_error; } - DUMP_ADDITIONAL_ELEMENTS(entry.data.global_var.additional_elements, - "variable item"); + if (is_blob) { + mpack_check_buffer(&sbuf); + mpack_integer(&sbuf.ptr, VAR_TYPE_BLOB); + } + dump_additional_data(entry.additional_data, &sbuf); break; } case kSDItemSubString: { - const size_t arr_size = 1 + (size_t)( - tv_list_len(entry.data.sub_string.additional_elements)); - msgpack_pack_array(spacker, arr_size); - PACK_BIN(cstr_as_string(entry.data.sub_string.sub)); - DUMP_ADDITIONAL_ELEMENTS(entry.data.sub_string.additional_elements, - "sub string item"); + uint32_t arr_size = 1 + additional_data_len(entry.additional_data); + mpack_array(&sbuf.ptr, arr_size); + mpack_bin(cstr_as_string(entry.data.sub_string.sub), &sbuf); + dump_additional_data(entry.additional_data, &sbuf); break; } case kSDItemSearchPattern: { - size_t entry_map_size = ( - 1 // Search pattern is always present - + ONE_IF_NOT_DEFAULT(entry, search_pattern.magic) - + ONE_IF_NOT_DEFAULT(entry, search_pattern.is_last_used) - + ONE_IF_NOT_DEFAULT(entry, search_pattern.smartcase) - + ONE_IF_NOT_DEFAULT(entry, search_pattern.has_line_offset) - + ONE_IF_NOT_DEFAULT(entry, search_pattern.place_cursor_at_end) - + ONE_IF_NOT_DEFAULT(entry, - search_pattern.is_substitute_pattern) - + ONE_IF_NOT_DEFAULT(entry, search_pattern.highlighted) - + ONE_IF_NOT_DEFAULT(entry, search_pattern.offset) - + ONE_IF_NOT_DEFAULT(entry, search_pattern.search_backward) - // finally, additional data: - + ( - entry.data.search_pattern.additional_data - ? entry.data.search_pattern.additional_data->dv_hashtab.ht_used - : 0)); - msgpack_pack_map(spacker, entry_map_size); - PACK_STATIC_STR(SEARCH_KEY_PAT); - PACK_BIN(cstr_as_string(entry.data.search_pattern.pat)); + uint32_t entry_map_size = (1 // Search pattern is always present + + ONE_IF_NOT_DEFAULT(entry, search_pattern.magic) + + ONE_IF_NOT_DEFAULT(entry, search_pattern.is_last_used) + + ONE_IF_NOT_DEFAULT(entry, search_pattern.smartcase) + + ONE_IF_NOT_DEFAULT(entry, search_pattern.has_line_offset) + + ONE_IF_NOT_DEFAULT(entry, search_pattern.place_cursor_at_end) + + ONE_IF_NOT_DEFAULT(entry, + search_pattern.is_substitute_pattern) + + ONE_IF_NOT_DEFAULT(entry, search_pattern.highlighted) + + ONE_IF_NOT_DEFAULT(entry, search_pattern.offset) + + ONE_IF_NOT_DEFAULT(entry, search_pattern.search_backward) + + additional_data_len(entry.additional_data)); + mpack_map(&sbuf.ptr, entry_map_size); + PACK_KEY(SEARCH_KEY_PAT); + mpack_bin(entry.data.search_pattern.pat, &sbuf); PACK_BOOL(entry, SEARCH_KEY_MAGIC, magic); PACK_BOOL(entry, SEARCH_KEY_IS_LAST_USED, is_last_used); PACK_BOOL(entry, SEARCH_KEY_SMARTCASE, smartcase); @@ -1638,132 +1442,108 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, ShadaEntr PACK_BOOL(entry, SEARCH_KEY_HIGHLIGHTED, highlighted); PACK_BOOL(entry, SEARCH_KEY_BACKWARD, search_backward); if (!CHECK_DEFAULT(entry, search_pattern.offset)) { - PACK_STATIC_STR(SEARCH_KEY_OFFSET); - msgpack_pack_int64(spacker, entry.data.search_pattern.offset); + PACK_KEY(SEARCH_KEY_OFFSET); + mpack_integer(&sbuf.ptr, entry.data.search_pattern.offset); } #undef PACK_BOOL - DUMP_ADDITIONAL_DATA(entry.data.search_pattern.additional_data, - "search pattern item"); + dump_additional_data(entry.additional_data, &sbuf); break; } case kSDItemChange: case kSDItemGlobalMark: case kSDItemLocalMark: case kSDItemJump: { - size_t entry_map_size = ( - 1 // File name + size_t entry_map_size = (1 // File name + ONE_IF_NOT_DEFAULT(entry, filemark.mark.lnum) + ONE_IF_NOT_DEFAULT(entry, filemark.mark.col) + ONE_IF_NOT_DEFAULT(entry, filemark.name) - // Additional entries, if any: - + ( - entry.data.filemark.additional_data == NULL - ? 0 - : entry.data.filemark.additional_data->dv_hashtab.ht_used)); - msgpack_pack_map(spacker, entry_map_size); - PACK_STATIC_STR(KEY_FILE); - PACK_BIN(cstr_as_string(entry.data.filemark.fname)); + + additional_data_len(entry.additional_data)); + mpack_map(&sbuf.ptr, (uint32_t)entry_map_size); + PACK_KEY(KEY_FILE); + mpack_bin(cstr_as_string(entry.data.filemark.fname), &sbuf); if (!CHECK_DEFAULT(entry, filemark.mark.lnum)) { - PACK_STATIC_STR(KEY_LNUM); - msgpack_pack_long(spacker, entry.data.filemark.mark.lnum); + PACK_KEY(KEY_LNUM); + mpack_integer(&sbuf.ptr, entry.data.filemark.mark.lnum); } if (!CHECK_DEFAULT(entry, filemark.mark.col)) { - PACK_STATIC_STR(KEY_COL); - msgpack_pack_long(spacker, entry.data.filemark.mark.col); + PACK_KEY(KEY_COL); + mpack_integer(&sbuf.ptr, entry.data.filemark.mark.col); } assert(entry.type == kSDItemJump || entry.type == kSDItemChange ? CHECK_DEFAULT(entry, filemark.name) : true); if (!CHECK_DEFAULT(entry, filemark.name)) { - PACK_STATIC_STR(KEY_NAME_CHAR); - msgpack_pack_uint8(spacker, (uint8_t)entry.data.filemark.name); + PACK_KEY(KEY_NAME_CHAR); + mpack_uint(&sbuf.ptr, (uint8_t)entry.data.filemark.name); } - DUMP_ADDITIONAL_DATA(entry.data.filemark.additional_data, - "mark (change, jump, global or local) item"); + dump_additional_data(entry.additional_data, &sbuf); break; } case kSDItemRegister: { - size_t entry_map_size = (2 // Register contents and name - + ONE_IF_NOT_DEFAULT(entry, reg.type) - + ONE_IF_NOT_DEFAULT(entry, reg.width) - + ONE_IF_NOT_DEFAULT(entry, reg.is_unnamed) - // Additional entries, if any: - + (entry.data.reg.additional_data == NULL - ? 0 - : entry.data.reg.additional_data->dv_hashtab.ht_used)); - msgpack_pack_map(spacker, entry_map_size); - PACK_STATIC_STR(REG_KEY_CONTENTS); - msgpack_pack_array(spacker, entry.data.reg.contents_size); + uint32_t entry_map_size = (2 // Register contents and name + + ONE_IF_NOT_DEFAULT(entry, reg.type) + + ONE_IF_NOT_DEFAULT(entry, reg.width) + + ONE_IF_NOT_DEFAULT(entry, reg.is_unnamed) + + additional_data_len(entry.additional_data)); + + mpack_map(&sbuf.ptr, entry_map_size); + PACK_KEY(REG_KEY_CONTENTS); + mpack_array(&sbuf.ptr, (uint32_t)entry.data.reg.contents_size); for (size_t i = 0; i < entry.data.reg.contents_size; i++) { - PACK_BIN(cstr_as_string(entry.data.reg.contents[i])); + mpack_bin(cstr_as_string(entry.data.reg.contents[i]), &sbuf); } - PACK_STATIC_STR(KEY_NAME_CHAR); - msgpack_pack_char(spacker, entry.data.reg.name); + PACK_KEY(KEY_NAME_CHAR); + mpack_uint(&sbuf.ptr, (uint8_t)entry.data.reg.name); if (!CHECK_DEFAULT(entry, reg.type)) { - PACK_STATIC_STR(REG_KEY_TYPE); - msgpack_pack_uint8(spacker, (uint8_t)entry.data.reg.type); + PACK_KEY(REG_KEY_TYPE); + mpack_uint(&sbuf.ptr, (uint8_t)entry.data.reg.type); } if (!CHECK_DEFAULT(entry, reg.width)) { - PACK_STATIC_STR(REG_KEY_WIDTH); - msgpack_pack_uint64(spacker, (uint64_t)entry.data.reg.width); + PACK_KEY(REG_KEY_WIDTH); + mpack_uint64(&sbuf.ptr, (uint64_t)entry.data.reg.width); } if (!CHECK_DEFAULT(entry, reg.is_unnamed)) { - PACK_STATIC_STR(REG_KEY_UNNAMED); - if (entry.data.reg.is_unnamed) { - msgpack_pack_true(spacker); - } else { - msgpack_pack_false(spacker); - } + PACK_KEY(REG_KEY_UNNAMED); + mpack_bool(&sbuf.ptr, entry.data.reg.is_unnamed); } - DUMP_ADDITIONAL_DATA(entry.data.reg.additional_data, "register item"); + dump_additional_data(entry.additional_data, &sbuf); break; } case kSDItemBufferList: - msgpack_pack_array(spacker, entry.data.buffer_list.size); + mpack_array(&sbuf.ptr, (uint32_t)entry.data.buffer_list.size); for (size_t i = 0; i < entry.data.buffer_list.size; i++) { - size_t entry_map_size = ( - 1 // Buffer name + size_t entry_map_size = (1 // Buffer name + (size_t)(entry.data.buffer_list.buffers[i].pos.lnum != default_pos.lnum) + (size_t)(entry.data.buffer_list.buffers[i].pos.col != default_pos.col) - // Additional entries, if any: - + ( - entry.data.buffer_list.buffers[i].additional_data - == NULL - ? 0 - : (entry.data.buffer_list.buffers[i].additional_data - ->dv_hashtab.ht_used))); - msgpack_pack_map(spacker, entry_map_size); - PACK_STATIC_STR(KEY_FILE); - PACK_BIN(cstr_as_string(entry.data.buffer_list.buffers[i].fname)); + + additional_data_len(entry.data.buffer_list.buffers[i]. + additional_data)); + mpack_map(&sbuf.ptr, (uint32_t)entry_map_size); + PACK_KEY(KEY_FILE); + mpack_bin(cstr_as_string(entry.data.buffer_list.buffers[i].fname), &sbuf); if (entry.data.buffer_list.buffers[i].pos.lnum != 1) { - PACK_STATIC_STR(KEY_LNUM); - msgpack_pack_uint64(spacker, (uint64_t)entry.data.buffer_list.buffers[i].pos.lnum); + PACK_KEY(KEY_LNUM); + mpack_uint64(&sbuf.ptr, (uint64_t)entry.data.buffer_list.buffers[i].pos.lnum); } if (entry.data.buffer_list.buffers[i].pos.col != 0) { - PACK_STATIC_STR(KEY_COL); - msgpack_pack_uint64(spacker, (uint64_t)entry.data.buffer_list.buffers[i].pos.col); + PACK_KEY(KEY_COL); + mpack_uint64(&sbuf.ptr, (uint64_t)entry.data.buffer_list.buffers[i].pos.col); } - DUMP_ADDITIONAL_DATA(entry.data.buffer_list.buffers[i].additional_data, - "buffer list subitem"); + dump_additional_data(entry.data.buffer_list.buffers[i].additional_data, &sbuf); } break; case kSDItemHeader: - msgpack_pack_map(spacker, entry.data.header.size); + mpack_map(&sbuf.ptr, (uint32_t)entry.data.header.size); for (size_t i = 0; i < entry.data.header.size; i++) { - const String s = entry.data.header.items[i].key; - msgpack_pack_str(spacker, s.size); - if (s.size) { - msgpack_pack_str_body(spacker, s.data, s.size); - } + mpack_str(entry.data.header.items[i].key, &sbuf); const Object obj = entry.data.header.items[i].value; switch (obj.type) { case kObjectTypeString: - PACK_BIN(obj.data.string); + mpack_bin(obj.data.string, &sbuf); break; case kObjectTypeInteger: - msgpack_pack_int64(spacker, (int64_t)obj.data.integer); + mpack_integer(&sbuf.ptr, obj.data.integer); break; default: abort(); @@ -1773,33 +1553,28 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, ShadaEntr } #undef CHECK_DEFAULT #undef ONE_IF_NOT_DEFAULT - if (!max_kbyte || sbuf.size <= max_kbyte * 1024) { + String packed = packer_take_string(&sbuf); + if (!max_kbyte || packed.size <= max_kbyte * 1024) { + shada_check_buffer(packer); + if (entry.type == kSDItemUnknown) { - if (msgpack_pack_uint64(packer, entry.data.unknown_item.type) == -1) { - goto shada_pack_entry_error; - } + mpack_uint64(&packer->ptr, entry.data.unknown_item.type); } else { - if (msgpack_pack_uint64(packer, (uint64_t)entry.type) == -1) { - goto shada_pack_entry_error; - } + mpack_uint64(&packer->ptr, (uint64_t)entry.type); } - if (msgpack_pack_uint64(packer, (uint64_t)entry.timestamp) == -1) { - goto shada_pack_entry_error; + mpack_uint64(&packer->ptr, (uint64_t)entry.timestamp); + if (packed.size > 0) { + mpack_uint64(&packer->ptr, (uint64_t)packed.size); + mpack_raw(packed.data, packed.size, packer); } - if (sbuf.size > 0) { - if ((msgpack_pack_uint64(packer, (uint64_t)sbuf.size) == -1) - || (packer->callback(packer->data, sbuf.data, - (unsigned)sbuf.size) == -1)) { - goto shada_pack_entry_error; - } + + if (packer->anyint != 0) { // error code + goto shada_pack_entry_error; } } - msgpack_packer_free(spacker); - msgpack_sbuffer_destroy(&sbuf); - return kSDWriteSuccessful; + ret = kSDWriteSuccessful; shada_pack_entry_error: - msgpack_packer_free(spacker); - msgpack_sbuffer_destroy(&sbuf); + xfree(sbuf.startptr); return ret; } @@ -1811,7 +1586,7 @@ shada_pack_entry_error: /// @param[in] entry Entry written. /// @param[in] max_kbyte Maximum size of an item in KiB. Zero means no /// restrictions. -static inline ShaDaWriteResult shada_pack_pfreed_entry(msgpack_packer *const packer, +static inline ShaDaWriteResult shada_pack_pfreed_entry(PackerBuffer *const packer, PossiblyFreedShadaEntry entry, const size_t max_kbyte) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE @@ -1849,76 +1624,29 @@ static int compare_file_marks(const void *a, const void *b) /// /// @return kSDReadStatusNotShaDa, kSDReadStatusReadError or /// kSDReadStatusSuccess. -static inline ShaDaReadResult shada_parse_msgpack(ShaDaReadDef *const sd_reader, - const size_t length, - msgpack_unpacked *ret_unpacked, - char **const ret_buf) - FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) +static ShaDaReadResult shada_check_status(uintmax_t initial_fpos, int status, size_t remaining) + FUNC_ATTR_WARN_UNUSED_RESULT { - const uintmax_t initial_fpos = sd_reader->fpos; - char *const buf = xmalloc(length); - - const ShaDaReadResult fl_ret = fread_len(sd_reader, buf, length); - if (fl_ret != kSDReadStatusSuccess) { - xfree(buf); - return fl_ret; - } - bool did_try_to_free = false; -shada_parse_msgpack_read_next: {} - size_t off = 0; - msgpack_unpacked unpacked; - msgpack_unpacked_init(&unpacked); - const msgpack_unpack_return result = - msgpack_unpack_next(&unpacked, buf, length, &off); - ShaDaReadResult ret = kSDReadStatusSuccess; - switch (result) { - case MSGPACK_UNPACK_SUCCESS: - if (off < length) { - goto shada_parse_msgpack_extra_bytes; - } - break; - case MSGPACK_UNPACK_PARSE_ERROR: - semsg(_(RCERR "Failed to parse ShaDa file due to a msgpack parser error " - "at position %" PRIu64), - (uint64_t)initial_fpos); - ret = kSDReadStatusNotShaDa; - break; - case MSGPACK_UNPACK_NOMEM_ERROR: - if (!did_try_to_free) { - did_try_to_free = true; - try_to_free_memory(); - goto shada_parse_msgpack_read_next; + switch (status) { + case MPACK_OK: + if (remaining) { + semsg(_(RCERR "Failed to parse ShaDa file: extra bytes in msgpack string " + "at position %" PRIu64), + (uint64_t)initial_fpos); + return kSDReadStatusNotShaDa; } - emsg(_(e_outofmem)); - ret = kSDReadStatusReadError; - break; - case MSGPACK_UNPACK_CONTINUE: + return kSDReadStatusSuccess; + case MPACK_EOF: semsg(_(RCERR "Failed to parse ShaDa file: incomplete msgpack string " "at position %" PRIu64), (uint64_t)initial_fpos); - ret = kSDReadStatusNotShaDa; - break; - case MSGPACK_UNPACK_EXTRA_BYTES: -shada_parse_msgpack_extra_bytes: - semsg(_(RCERR "Failed to parse ShaDa file: extra bytes in msgpack string " + return kSDReadStatusNotShaDa; + default: + semsg(_(RCERR "Failed to parse ShaDa file due to a msgpack parser error " "at position %" PRIu64), (uint64_t)initial_fpos); - ret = kSDReadStatusNotShaDa; - break; - } - if (ret_buf != NULL && ret == kSDReadStatusSuccess) { - if (ret_unpacked == NULL) { - msgpack_unpacked_destroy(&unpacked); - } else { - *ret_unpacked = unpacked; - } - *ret_buf = buf; - } else { - assert(ret_buf == NULL || ret != kSDReadStatusSuccess); - msgpack_unpacked_destroy(&unpacked); - xfree(buf); + return kSDReadStatusNotShaDa; } - return ret; } /// Format shada entry for debugging purposes @@ -1935,25 +1663,16 @@ static const char *shada_format_entry(const ShadaEntry entry) // ^ Space for `can_free_entry` #define FORMAT_MARK_ENTRY(entry_name, name_fmt, name_fmt_arg) \ do { \ - typval_T ad_tv = { \ - .v_type = VAR_DICT, \ - .vval.v_dict = entry.data.filemark.additional_data \ - }; \ - size_t ad_len; \ - char *const ad = encode_tv2string(&ad_tv, &ad_len); \ vim_snprintf_add(S_LEN(ret), \ entry_name " {" name_fmt " file=[%zu]\"%.512s\", " \ "pos={l=%" PRIdLINENR ",c=%" PRIdCOLNR ",a=%" PRIdCOLNR "}, " \ - "ad={%p:[%zu]%.64s} }", \ + "}", \ name_fmt_arg, \ strlen(entry.data.filemark.fname), \ entry.data.filemark.fname, \ entry.data.filemark.mark.lnum, \ entry.data.filemark.mark.col, \ - entry.data.filemark.mark.coladd, \ - (void *)entry.data.filemark.additional_data, \ - ad_len, \ - ad); \ + entry.data.filemark.mark.coladd); \ } while (0) switch (entry.type) { case kSDItemMissing: @@ -2021,11 +1740,11 @@ static const char *shada_format_pfreed_entry(const PossiblyFreedShadaEntry pfs_e /// @param[in,out] ret_wms Location where results are saved. /// @param[out] packer MessagePack packer for entries which are not /// merged. -static inline ShaDaWriteResult shada_read_when_writing(ShaDaReadDef *const sd_reader, +static inline ShaDaWriteResult shada_read_when_writing(FileDescriptor *const sd_reader, const unsigned srni_flags, const size_t max_kbyte, WriteMergerState *const wms, - msgpack_packer *const packer) + PackerBuffer *const packer) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { ShaDaWriteResult ret = kSDWriteSuccessful; @@ -2137,8 +1856,8 @@ static inline ShaDaWriteResult shada_read_when_writing(ShaDaReadDef *const sd_re } // Ignore duplicates. if (wms_entry.timestamp == entry.timestamp - && (wms_entry.data.filemark.additional_data == NULL - && entry.data.filemark.additional_data == NULL) + && (wms_entry.additional_data == NULL + && entry.additional_data == NULL) && marks_equal(wms_entry.data.filemark.mark, entry.data.filemark.mark) && strcmp(wms_entry.data.filemark.fname, @@ -2167,13 +1886,18 @@ static inline ShaDaWriteResult shada_read_when_writing(ShaDaReadDef *const sd_re shada_free_shada_entry(&entry); break; } - if (wms->global_marks[idx].data.type == kSDItemMissing) { + + // Global or numbered mark. + PossiblyFreedShadaEntry *mark + = idx < 26 ? &wms->global_marks[idx] : &wms->numbered_marks[idx - 26]; + + if (mark->data.type == kSDItemMissing) { if (namedfm[idx].fmark.timestamp >= entry.timestamp) { shada_free_shada_entry(&entry); break; } } - COMPARE_WITH_ENTRY(&wms->global_marks[idx], entry); + COMPARE_WITH_ENTRY(mark, entry); } break; case kSDItemChange: @@ -2366,11 +2090,11 @@ static inline void add_search_pattern(PossiblyFreedShadaEntry *const ret_pse, .is_substitute_pattern = is_substitute_pattern, .highlighted = ((is_substitute_pattern ^ search_last_used) && search_highlighted), - .pat = pat.pat, - .additional_data = pat.additional_data, + .pat = cstr_as_string(pat.pat), .search_backward = (!is_substitute_pattern && pat.off.dir == '?'), } - } + }, + .additional_data = pat.additional_data, } }; } @@ -2407,11 +2131,11 @@ static inline void shada_initialize_registers(WriteMergerState *const wms, int m .contents_size = reg.y_size, .type = reg.y_type, .width = (size_t)(reg.y_type == kMTBlockWise ? reg.y_width : 0), - .additional_data = reg.additional_data, .name = name, .is_unnamed = is_unnamed, } - } + }, + .additional_data = reg.additional_data, } }; } while (reg_iter != ITER_REGISTER_NULL); @@ -2477,13 +2201,37 @@ static int hist_type2char(const int type) return NUL; } +static PackerBuffer packer_buffer_for_file(FileDescriptor *file) +{ + if (file_space(file) < SHADA_MPACK_FREE_SPACE) { + file_flush(file); + } + return (PackerBuffer) { + .startptr = file->buffer, + .ptr = file->write_pos, + .endptr = file->buffer + ARENA_BLOCK_SIZE, + .anydata = file, + .anyint = 0, // set to nonzero if error + .packer_flush = flush_file_buffer, + }; +} + +static void flush_file_buffer(PackerBuffer *buffer) +{ + FileDescriptor *fd = buffer->anydata; + fd->write_pos = buffer->ptr; + buffer->anyint = file_flush(fd); + buffer->ptr = fd->write_pos; +} + /// Write ShaDa file /// /// @param[in] sd_writer Structure containing file writer definition. /// @param[in] sd_reader Structure containing file reader definition. If it is /// not NULL then contents of this file will be merged /// with current Neovim runtime. -static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDef *const sd_reader) +static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, + FileDescriptor *const sd_reader) FUNC_ATTR_NONNULL_ARG(1) { ShaDaWriteResult ret = kSDWriteSuccessful; @@ -2524,8 +2272,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDe } } - const unsigned srni_flags = (unsigned)( - kSDReadUndisableableData + const unsigned srni_flags = (unsigned)(kSDReadUndisableableData | kSDReadUnknown | (dump_history ? kSDReadHistory : 0) | (dump_registers ? kSDReadRegisters : 0) @@ -2534,8 +2281,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDe | (num_marked_files ? kSDReadLocalMarks | kSDReadChanges : 0)); - msgpack_packer *const packer = msgpack_packer_new(sd_writer, - &msgpack_sd_writer_write); + PackerBuffer packer = packer_buffer_for_file(sd_writer); // Set b_last_cursor for all the buffers that have a window. // @@ -2549,7 +2295,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDe find_removable_bufs(&removable_bufs); // Write header - if (shada_pack_entry(packer, (ShadaEntry) { + if (shada_pack_entry(&packer, (ShadaEntry) { .type = kSDItemHeader, .timestamp = os_time(), .data = { @@ -2578,7 +2324,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDe // Write buffer list if (find_shada_parameter('%') != NULL) { ShadaEntry buflist_entry = shada_get_buflist(&removable_bufs); - if (shada_pack_entry(packer, buflist_entry, 0) == kSDWriteFailed) { + if (shada_pack_entry(&packer, buflist_entry, 0) == kSDWriteFailed) { xfree(buflist_entry.data.buffer_list.buffers); ret = kSDWriteFailed; goto shada_write_exit; @@ -2628,16 +2374,16 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDe typval_T tgttv; tv_copy(&vartv, &tgttv); ShaDaWriteResult spe_ret; - if ((spe_ret = shada_pack_entry(packer, (ShadaEntry) { + if ((spe_ret = shada_pack_entry(&packer, (ShadaEntry) { .type = kSDItemVariable, .timestamp = cur_timestamp, .data = { .global_var = { .name = (char *)name, .value = tgttv, - .additional_elements = NULL, } - } + }, + .additional_data = NULL, }, max_kbyte)) == kSDWriteFailed) { tv_clear(&vartv); tv_clear(&tgttv); @@ -2679,9 +2425,9 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDe .data = { .sub_string = { .sub = sub.sub, - .additional_elements = sub.additional_elements, } - } + }, + .additional_data = sub.additional_data, } }; } @@ -2721,10 +2467,10 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDe .filemark = { .mark = fm.fmark.mark, .name = name, - .additional_data = fm.fmark.additional_data, .fname = (char *)fname, } - } + }, + .additional_data = fm.fmark.additional_data, }, }; if (ascii_isdigit(name)) { @@ -2770,9 +2516,9 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDe .mark = fm.mark, .name = name, .fname = (char *)fname, - .additional_data = fm.additional_data, } - } + }, + .additional_data = fm.additional_data, } }; if (fm.timestamp > filemarks->greatest_timestamp) { @@ -2790,9 +2536,9 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDe .filemark = { .mark = fm.mark, .fname = (char *)fname, - .additional_data = fm.additional_data, } - } + }, + .additional_data = fm.additional_data, } }; if (fm.timestamp > filemarks->greatest_timestamp) { @@ -2805,7 +2551,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDe if (sd_reader != NULL) { const ShaDaWriteResult srww_ret = shada_read_when_writing(sd_reader, srni_flags, max_kbyte, wms, - packer); + &packer); if (srww_ret != kSDWriteSuccessful) { ret = srww_ret; } @@ -2823,10 +2569,10 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDe .filemark = { .mark = curwin->w_cursor, .name = '0', - .additional_data = NULL, .fname = curbuf->b_ffname, } - } + }, + .additional_data = NULL, }, }); } @@ -2836,7 +2582,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDe do { \ for (size_t i_ = 0; i_ < ARRAY_SIZE(wms_array); i_++) { \ if ((wms_array)[i_].data.type != kSDItemMissing) { \ - if (shada_pack_pfreed_entry(packer, (wms_array)[i_], max_kbyte) \ + if (shada_pack_pfreed_entry(&packer, (wms_array)[i_], max_kbyte) \ == kSDWriteFailed) { \ ret = kSDWriteFailed; \ goto shada_write_exit; \ @@ -2848,7 +2594,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDe PACK_WMS_ARRAY(wms->numbered_marks); PACK_WMS_ARRAY(wms->registers); for (size_t i = 0; i < wms->jumps_size; i++) { - if (shada_pack_pfreed_entry(packer, wms->jumps[i], max_kbyte) + if (shada_pack_pfreed_entry(&packer, wms->jumps[i], max_kbyte) == kSDWriteFailed) { ret = kSDWriteFailed; goto shada_write_exit; @@ -2857,7 +2603,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDe #define PACK_WMS_ENTRY(wms_entry) \ do { \ if ((wms_entry).data.type != kSDItemMissing) { \ - if (shada_pack_pfreed_entry(packer, wms_entry, max_kbyte) \ + if (shada_pack_pfreed_entry(&packer, wms_entry, max_kbyte) \ == kSDWriteFailed) { \ ret = kSDWriteFailed; \ goto shada_write_exit; \ @@ -2883,14 +2629,14 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDe for (size_t i = 0; i < file_markss_to_dump; i++) { PACK_WMS_ARRAY(all_file_markss[i]->marks); for (size_t j = 0; j < all_file_markss[i]->changes_size; j++) { - if (shada_pack_pfreed_entry(packer, all_file_markss[i]->changes[j], + if (shada_pack_pfreed_entry(&packer, all_file_markss[i]->changes[j], max_kbyte) == kSDWriteFailed) { ret = kSDWriteFailed; goto shada_write_exit; } } for (size_t j = 0; j < all_file_markss[i]->additional_marks_size; j++) { - if (shada_pack_entry(packer, all_file_markss[i]->additional_marks[j], + if (shada_pack_entry(&packer, all_file_markss[i]->additional_marks[j], 0) == kSDWriteFailed) { shada_free_shada_entry(&all_file_markss[i]->additional_marks[j]); ret = kSDWriteFailed; @@ -2908,7 +2654,7 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDe if (dump_one_history[i]) { hms_insert_whole_neovim_history(&wms->hms[i]); HMS_ITER(&wms->hms[i], cur_entry, { - if (shada_pack_pfreed_entry(packer, (PossiblyFreedShadaEntry) { + if (shada_pack_pfreed_entry(&packer, (PossiblyFreedShadaEntry) { .data = cur_entry->data, .can_free_entry = cur_entry->can_free_entry, }, max_kbyte) == kSDWriteFailed) { @@ -2934,13 +2680,13 @@ shada_write_exit: }) map_destroy(cstr_t, &wms->file_marks); set_destroy(ptr_t, &removable_bufs); - msgpack_packer_free(packer); + packer.packer_flush(&packer); set_destroy(cstr_t, &wms->dumped_variables); xfree(wms); return ret; } -#undef PACK_STATIC_STR +#undef PACK_KEY /// Write ShaDa file to a given location /// @@ -2958,12 +2704,13 @@ int shada_write_file(const char *const file, bool nomerge) char *const fname = shada_filename(file); char *tempname = NULL; FileDescriptor sd_writer; - ShaDaReadDef sd_reader = { .close = NULL }; + FileDescriptor sd_reader; bool did_open_writer = false; + bool did_open_reader = false; if (!nomerge) { int error; - if ((error = open_shada_file_for_reading(fname, &sd_reader)) != 0) { + if ((error = file_open(&sd_reader, fname, kFileReadOnly, 0)) != 0) { if (error != UV_ENOENT) { semsg(_(SERR "System error while opening ShaDa file %s for reading " "to merge before writing it: %s"), @@ -2973,6 +2720,8 @@ int shada_write_file(const char *const file, bool nomerge) } nomerge = true; goto shada_write_file_nomerge; + } else { + did_open_reader = true; } tempname = modname(fname, ".tmp.a", false); if (tempname == NULL) { @@ -3001,8 +2750,9 @@ shada_write_file_open: {} fname); xfree(fname); xfree(tempname); - assert(sd_reader.close != NULL); - sd_reader.close(&sd_reader); + if (did_open_reader) { + close_file(&sd_reader); + } return FAIL; } (*wp)++; @@ -3047,8 +2797,8 @@ shada_write_file_nomerge: {} if (!did_open_writer) { xfree(fname); xfree(tempname); - if (sd_reader.cookie != NULL) { - sd_reader.close(&sd_reader); + if (did_open_reader) { + close_file(&sd_reader); } return FAIL; } @@ -3062,7 +2812,9 @@ shada_write_file_nomerge: {} const ShaDaWriteResult sw_ret = shada_write(&sd_writer, (nomerge ? NULL : &sd_reader)); assert(sw_ret != kSDWriteIgnError); if (!nomerge) { - sd_reader.close(&sd_reader); + if (did_open_reader) { + close_file(&sd_reader); + } bool did_remove = false; if (sw_ret == kSDWriteSuccessful) { FileInfo old_info; @@ -3164,47 +2916,42 @@ static void shada_free_shada_entry(ShadaEntry *const entry) xfree(entry->data.unknown_item.contents); break; case kSDItemHeader: - api_free_dictionary(entry->data.header); + api_free_dict(entry->data.header); break; case kSDItemChange: case kSDItemJump: case kSDItemGlobalMark: case kSDItemLocalMark: - tv_dict_unref(entry->data.filemark.additional_data); xfree(entry->data.filemark.fname); break; case kSDItemSearchPattern: - tv_dict_unref(entry->data.search_pattern.additional_data); - xfree(entry->data.search_pattern.pat); + api_free_string(entry->data.search_pattern.pat); break; case kSDItemRegister: - tv_dict_unref(entry->data.reg.additional_data); for (size_t i = 0; i < entry->data.reg.contents_size; i++) { xfree(entry->data.reg.contents[i]); } xfree(entry->data.reg.contents); break; case kSDItemHistoryEntry: - tv_list_unref(entry->data.history_item.additional_elements); xfree(entry->data.history_item.string); break; case kSDItemVariable: - tv_list_unref(entry->data.global_var.additional_elements); xfree(entry->data.global_var.name); tv_clear(&entry->data.global_var.value); break; case kSDItemSubString: - tv_list_unref(entry->data.sub_string.additional_elements); xfree(entry->data.sub_string.sub); break; case kSDItemBufferList: for (size_t i = 0; i < entry->data.buffer_list.size; i++) { xfree(entry->data.buffer_list.buffers[i].fname); - tv_dict_unref(entry->data.buffer_list.buffers[i].additional_data); + xfree(entry->data.buffer_list.buffers[i].additional_data); } xfree(entry->data.buffer_list.buffers); break; } + XFREE_CLEAR(entry->additional_data); } #ifndef HAVE_BE64TOH @@ -3235,18 +2982,18 @@ static inline uint64_t be64toh(uint64_t big_endian_64_bits) /// @return kSDReadStatusSuccess if everything was OK, kSDReadStatusNotShaDa if /// there were not enough bytes to read or kSDReadStatusReadError if /// there was some error while reading. -static ShaDaReadResult fread_len(ShaDaReadDef *const sd_reader, char *const buffer, +static ShaDaReadResult fread_len(FileDescriptor *const sd_reader, char *const buffer, const size_t length) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - const ptrdiff_t read_bytes = sd_reader->read(sd_reader, buffer, length); + const ptrdiff_t read_bytes = file_read(sd_reader, buffer, length); + if (read_bytes < 0) { + semsg(_(SERR "System error while reading ShaDa file: %s"), + os_strerror((int)read_bytes)); + return kSDReadStatusReadError; + } if (read_bytes != (ptrdiff_t)length) { - if (sd_reader->error != NULL) { - semsg(_(SERR "System error while reading ShaDa file: %s"), - sd_reader->error); - return kSDReadStatusReadError; - } semsg(_(RCERR "Error while reading ShaDa file: " "last entry specified that it occupies %" PRIu64 " bytes, " "but file ended earlier"), @@ -3272,26 +3019,32 @@ static ShaDaReadResult fread_len(ShaDaReadDef *const sd_reader, char *const buff /// @return kSDReadStatusSuccess if reading was successful, /// kSDReadStatusNotShaDa if there were not enough bytes to read or /// kSDReadStatusReadError if reading failed for whatever reason. -static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader, const int first_char, +/// kSDReadStatusFinished if eof and that was allowed +static ShaDaReadResult msgpack_read_uint64(FileDescriptor *const sd_reader, bool allow_eof, uint64_t *const result) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - const uintmax_t fpos = sd_reader->fpos - 1; - - if (first_char == EOF) { - if (sd_reader->error) { - semsg(_(SERR "System error while reading integer from ShaDa file: %s"), - sd_reader->error); - return kSDReadStatusReadError; - } else if (sd_reader->eof) { - semsg(_(RCERR "Error while reading ShaDa file: " - "expected positive integer at position %" PRIu64 - ", but got nothing"), - (uint64_t)fpos); - return kSDReadStatusNotShaDa; + const uintmax_t fpos = sd_reader->bytes_read; + + uint8_t ret; + ptrdiff_t read_bytes = file_read(sd_reader, (char *)&ret, 1); + + if (read_bytes < 0) { + semsg(_(SERR "System error while reading integer from ShaDa file: %s"), + os_strerror((int)read_bytes)); + return kSDReadStatusReadError; + } else if (read_bytes == 0) { + if (allow_eof && file_eof(sd_reader)) { + return kSDReadStatusFinished; } + semsg(_(RCERR "Error while reading ShaDa file: " + "expected positive integer at position %" PRIu64 + ", but got nothing"), + (uint64_t)fpos); + return kSDReadStatusNotShaDa; } + int first_char = (int)ret; if (~first_char & 0x80) { // Positive fixnum *result = (uint64_t)((uint8_t)first_char); @@ -3332,128 +3085,6 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader, const RERR "Error while reading ShaDa file: " \ entry_name " entry at position %" PRIu64 " " \ error_desc -#define CHECK_KEY(key, \ - expected) ((key).via.str.size == (sizeof(expected) - 1) \ - && strncmp((key).via.str.ptr, expected, (sizeof(expected) - 1)) == 0) -#define CLEAR_GA_AND_ERROR_OUT(ga) \ - do { \ - ga_clear(&(ga)); \ - goto shada_read_next_item_error; \ - } while (0) -#define ID(s) s -#define BINDUP(b) xmemdupz((b).ptr, (b).size) -#define TOINT(s) ((int)(s)) -#define TOCHAR(s) ((char)(s)) -#define TOU8(s) ((uint8_t)(s)) -#define TOSIZE(s) ((size_t)(s)) -#define CHECKED_ENTRY(condition, error_desc, entry_name, obj, tgt, attr, \ - proc) \ - do { \ - if (!(condition)) { \ - semsg(_(READERR(entry_name, error_desc)), initial_fpos); \ - CLEAR_GA_AND_ERROR_OUT(ad_ga); \ - } \ - (tgt) = proc((obj).via.attr); \ - } while (0) -#define CHECK_KEY_IS_STR(un, entry_name) \ - if ((un).data.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR) { \ - semsg(_(READERR(entry_name, "has key which is not a string")), \ - initial_fpos); \ - CLEAR_GA_AND_ERROR_OUT(ad_ga); \ - } else if ((un).data.via.map.ptr[i].key.via.str.size == 0) { \ - semsg(_(READERR(entry_name, "has empty key")), initial_fpos); \ - CLEAR_GA_AND_ERROR_OUT(ad_ga); \ - } -#define CHECKED_KEY(un, entry_name, name, error_desc, tgt, condition, attr, proc) \ - else if (CHECK_KEY((un).data.via.map.ptr[i].key, name)) \ - { \ - CHECKED_ENTRY(condition, \ - "has " name " key value " error_desc, \ - entry_name, \ - (un).data.via.map.ptr[i].val, \ - tgt, \ - attr, \ - proc); \ - } -#define TYPED_KEY(un, entry_name, name, type_name, tgt, objtype, attr, proc) \ - CHECKED_KEY(un, entry_name, name, "which is not " type_name, tgt, \ - (un).data.via.map.ptr[i].val.type == MSGPACK_OBJECT_##objtype, \ - attr, proc) -#define BOOLEAN_KEY(un, entry_name, name, tgt) \ - TYPED_KEY(un, entry_name, name, "a boolean", tgt, BOOLEAN, boolean, ID) -#define STRING_KEY(un, entry_name, name, tgt) \ - TYPED_KEY(un, entry_name, name, "a binary", tgt, BIN, bin, BINDUP) -#define CONVERTED_STRING_KEY(un, entry_name, name, tgt) \ - TYPED_KEY(un, entry_name, name, "a binary", tgt, BIN, bin, \ - BIN_CONVERTED) -#define INT_KEY(un, entry_name, name, tgt, proc) \ - CHECKED_KEY(un, entry_name, name, "which is not an integer", tgt, \ - (((un).data.via.map.ptr[i].val.type \ - == MSGPACK_OBJECT_POSITIVE_INTEGER) \ - || ((un).data.via.map.ptr[i].val.type \ - == MSGPACK_OBJECT_NEGATIVE_INTEGER)), \ - i64, proc) -#define INTEGER_KEY(un, entry_name, name, tgt) \ - INT_KEY(un, entry_name, name, tgt, TOINT) -#define ADDITIONAL_KEY(un) \ - else { \ - ga_grow(&ad_ga, 1); \ - memcpy(((char *)ad_ga.ga_data) + ((size_t)ad_ga.ga_len \ - * sizeof(*(un).data.via.map.ptr)), \ - (un).data.via.map.ptr + i, \ - sizeof(*(un).data.via.map.ptr)); \ - ad_ga.ga_len++; \ - } -#define BIN_CONVERTED(b) (xmemdupz(((b).ptr), ((b).size))) -#define SET_ADDITIONAL_DATA(tgt, name) \ - do { \ - if (ad_ga.ga_len) { \ - msgpack_object obj = { \ - .type = MSGPACK_OBJECT_MAP, \ - .via = { \ - .map = { \ - .size = (uint32_t)ad_ga.ga_len, \ - .ptr = ad_ga.ga_data, \ - } \ - } \ - }; \ - typval_T adtv; \ - if (msgpack_to_vim(obj, &adtv) == FAIL \ - || adtv.v_type != VAR_DICT) { \ - semsg(_(READERR(name, \ - "cannot be converted to a Vimscript dictionary")), \ - initial_fpos); \ - ga_clear(&ad_ga); \ - tv_clear(&adtv); \ - goto shada_read_next_item_error; \ - } \ - (tgt) = adtv.vval.v_dict; \ - } \ - ga_clear(&ad_ga); \ - } while (0) -#define SET_ADDITIONAL_ELEMENTS(src, src_maxsize, tgt, name) \ - do { \ - if ((src).size > (size_t)(src_maxsize)) { \ - msgpack_object obj = { \ - .type = MSGPACK_OBJECT_ARRAY, \ - .via = { \ - .array = { \ - .size = ((src).size - (uint32_t)(src_maxsize)), \ - .ptr = (src).ptr + (src_maxsize), \ - } \ - } \ - }; \ - typval_T aetv; \ - if (msgpack_to_vim(obj, &aetv) == FAIL) { \ - semsg(_(READERR(name, "cannot be converted to a Vimscript list")), \ - initial_fpos); \ - tv_clear(&aetv); \ - goto shada_read_next_item_error; \ - } \ - assert(aetv.v_type == VAR_LIST); \ - (tgt) = aetv.vval.v_list; \ - } \ - } while (0) /// Iterate over shada file contents /// @@ -3465,8 +3096,9 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader, const /// greater then given. /// /// @return Any value from ShaDaReadResult enum. -static ShaDaReadResult shada_read_next_item(ShaDaReadDef *const sd_reader, ShadaEntry *const entry, - const unsigned flags, const size_t max_kbyte) +static ShaDaReadResult shada_read_next_item(FileDescriptor *const sd_reader, + ShadaEntry *const entry, const unsigned flags, + const size_t max_kbyte) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { ShaDaReadResult ret = kSDReadStatusMalformed; @@ -3476,29 +3108,30 @@ shada_read_next_item_start: // somebody calls goto shada_read_next_item_error before anything is set in // the switch. CLEAR_POINTER(entry); - if (sd_reader->eof) { + if (file_eof(sd_reader)) { return kSDReadStatusFinished; } + bool verify_but_ignore = false; + // First: manually unpack type, timestamp and length. // This is needed to avoid both seeking and having to maintain a buffer. uint64_t type_u64 = (uint64_t)kSDItemMissing; uint64_t timestamp_u64; uint64_t length_u64; - const uint64_t initial_fpos = (uint64_t)sd_reader->fpos; - const int first_char = read_char(sd_reader); - if (first_char == EOF && sd_reader->eof) { - return kSDReadStatusFinished; - } + const uint64_t initial_fpos = sd_reader->bytes_read; + AdditionalDataBuilder ad = KV_INITIAL_VALUE; + uint32_t read_additional_array_elements = 0; + char *error_alloc = NULL; ShaDaReadResult mru_ret; - if (((mru_ret = msgpack_read_uint64(sd_reader, first_char, &type_u64)) + if (((mru_ret = msgpack_read_uint64(sd_reader, true, &type_u64)) != kSDReadStatusSuccess) - || ((mru_ret = msgpack_read_uint64(sd_reader, read_char(sd_reader), + || ((mru_ret = msgpack_read_uint64(sd_reader, false, ×tamp_u64)) != kSDReadStatusSuccess) - || ((mru_ret = msgpack_read_uint64(sd_reader, read_char(sd_reader), + || ((mru_ret = msgpack_read_uint64(sd_reader, false, &length_u64)) != kSDReadStatusSuccess)) { return mru_ret; @@ -3538,16 +3171,42 @@ shada_read_next_item_start: // in incomplete MessagePack string. if (initial_fpos == 0 && (type_u64 == '\n' || type_u64 > SHADA_LAST_ENTRY)) { - const ShaDaReadResult spm_ret = shada_parse_msgpack(sd_reader, length, - NULL, NULL); - if (spm_ret != kSDReadStatusSuccess) { - return spm_ret; - } + verify_but_ignore = true; } else { const ShaDaReadResult srs_ret = sd_reader_skip(sd_reader, length); if (srs_ret != kSDReadStatusSuccess) { return srs_ret; } + goto shada_read_next_item_start; + } + } + + const uint64_t parse_pos = sd_reader->bytes_read; + bool buf_allocated = false; + // try to avoid allocation for small items which fits entirely + // in the internal buffer of sd_reader + char *buf = file_try_read_buffered(sd_reader, length); + if (!buf) { + buf_allocated = true; + buf = xmalloc(length); + const ShaDaReadResult fl_ret = fread_len(sd_reader, buf, length); + if (fl_ret != kSDReadStatusSuccess) { + ret = fl_ret; + goto shada_read_next_item_error; + } + } + + const char *read_ptr = buf; + size_t read_size = length; + + if (verify_but_ignore) { + int status = unpack_skip(&read_ptr, &read_size); + ShaDaReadResult spm_ret = shada_check_status(parse_pos, status, read_size); + if (buf_allocated) { + xfree(buf); + } + if (spm_ret != kSDReadStatusSuccess) { + return spm_ret; } goto shada_read_next_item_start; } @@ -3557,397 +3216,308 @@ shada_read_next_item_start: entry->data.unknown_item.size = length; entry->data.unknown_item.type = type_u64; if (initial_fpos == 0) { - const ShaDaReadResult spm_ret = shada_parse_msgpack(sd_reader, length, NULL, - &entry->data.unknown_item.contents); + int status = unpack_skip(&read_ptr, &read_size); + ShaDaReadResult spm_ret = shada_check_status(parse_pos, status, read_size); if (spm_ret != kSDReadStatusSuccess) { + if (buf_allocated) { + xfree(buf); + } entry->type = kSDItemMissing; + return spm_ret; } - return spm_ret; } - entry->data.unknown_item.contents = xmalloc(length); - const ShaDaReadResult fl_ret = - fread_len(sd_reader, entry->data.unknown_item.contents, length); - if (fl_ret != kSDReadStatusSuccess) { - shada_free_shada_entry(entry); - entry->type = kSDItemMissing; - } - return fl_ret; + entry->data.unknown_item.contents = buf_allocated ? buf : xmemdup(buf, length); + return kSDReadStatusSuccess; } - msgpack_unpacked unpacked; - char *buf = NULL; - - const ShaDaReadResult spm_ret = shada_parse_msgpack(sd_reader, length, - &unpacked, &buf); - if (spm_ret != kSDReadStatusSuccess) { - ret = spm_ret; - goto shada_read_next_item_error; - } entry->data = sd_default_values[type_u64].data; switch ((ShadaEntryType)type_u64) { case kSDItemHeader: // TODO(bfredl): header is written to file and provides useful debugging // info. It is never read by nvim (earlier we parsed it back to a - // Dictionary, but that value was never used) + // Dict, but that value was never used) break; case kSDItemSearchPattern: { - if (unpacked.data.type != MSGPACK_OBJECT_MAP) { - semsg(_(READERR("search pattern", "is not a dictionary")), - initial_fpos); + Dict(_shada_search_pat) *it = &entry->data.search_pattern; + if (!unpack_keydict(it, DictHash(_shada_search_pat), &ad, &read_ptr, &read_size, + &error_alloc)) { + semsg(_(READERR("search pattern", "%s")), initial_fpos, error_alloc); + it->pat = NULL_STRING; goto shada_read_next_item_error; } - garray_T ad_ga; - ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1); - for (size_t i = 0; i < unpacked.data.via.map.size; i++) { - CHECK_KEY_IS_STR(unpacked, "search pattern") - BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_MAGIC, - entry->data.search_pattern.magic) - BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_SMARTCASE, - entry->data.search_pattern.smartcase) - BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_HAS_LINE_OFFSET, - entry->data.search_pattern.has_line_offset) - BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_PLACE_CURSOR_AT_END, - entry->data.search_pattern.place_cursor_at_end) - BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_IS_LAST_USED, - entry->data.search_pattern.is_last_used) - BOOLEAN_KEY(unpacked, "search pattern", - SEARCH_KEY_IS_SUBSTITUTE_PATTERN, - entry->data.search_pattern.is_substitute_pattern) - BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_HIGHLIGHTED, - entry->data.search_pattern.highlighted) - BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_BACKWARD, - entry->data.search_pattern.search_backward) - INTEGER_KEY(unpacked, "search pattern", SEARCH_KEY_OFFSET, - entry->data.search_pattern.offset) - CONVERTED_STRING_KEY(unpacked, "search pattern", SEARCH_KEY_PAT, - entry->data.search_pattern.pat) - ADDITIONAL_KEY(unpacked) - } - if (entry->data.search_pattern.pat == NULL) { + + if (!HAS_KEY(it, _shada_search_pat, sp)) { // SEARCH_KEY_PAT semsg(_(READERR("search pattern", "has no pattern")), initial_fpos); - CLEAR_GA_AND_ERROR_OUT(ad_ga); + goto shada_read_next_item_error; } - SET_ADDITIONAL_DATA(entry->data.search_pattern.additional_data, - "search pattern"); + entry->data.search_pattern.pat = copy_string(entry->data.search_pattern.pat, NULL); + break; } case kSDItemChange: case kSDItemJump: case kSDItemGlobalMark: case kSDItemLocalMark: { - if (unpacked.data.type != MSGPACK_OBJECT_MAP) { - semsg(_(READERR("mark", "is not a dictionary")), initial_fpos); + Dict(_shada_mark) it = { 0 }; + if (!unpack_keydict(&it, DictHash(_shada_mark), &ad, &read_ptr, &read_size, &error_alloc)) { + semsg(_(READERR("mark", "%s")), initial_fpos, error_alloc); goto shada_read_next_item_error; } - garray_T ad_ga; - ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1); - for (size_t i = 0; i < unpacked.data.via.map.size; i++) { - CHECK_KEY_IS_STR(unpacked, "mark") - if (CHECK_KEY(unpacked.data.via.map.ptr[i].key, KEY_NAME_CHAR)) { - if (type_u64 == kSDItemJump || type_u64 == kSDItemChange) { - semsg(_(READERR("mark", "has n key which is only valid for " - "local and global mark entries")), initial_fpos); - CLEAR_GA_AND_ERROR_OUT(ad_ga); - } - CHECKED_ENTRY((unpacked.data.via.map.ptr[i].val.type - == MSGPACK_OBJECT_POSITIVE_INTEGER), - "has n key value which is not an unsigned integer", - "mark", unpacked.data.via.map.ptr[i].val, - entry->data.filemark.name, u64, TOCHAR); + + if (HAS_KEY(&it, _shada_mark, n)) { + if (type_u64 == kSDItemJump || type_u64 == kSDItemChange) { + semsg(_(READERR("mark", "has n key which is only valid for " + "local and global mark entries")), initial_fpos); + goto shada_read_next_item_error; } - INTEGER_KEY(unpacked, "mark", KEY_LNUM, entry->data.filemark.mark.lnum) - INTEGER_KEY(unpacked, "mark", KEY_COL, entry->data.filemark.mark.col) - STRING_KEY(unpacked, "mark", KEY_FILE, entry->data.filemark.fname) - ADDITIONAL_KEY(unpacked) + entry->data.filemark.name = (char)it.n; + } + + if (HAS_KEY(&it, _shada_mark, l)) { + entry->data.filemark.mark.lnum = (linenr_T)it.l; + } + if (HAS_KEY(&it, _shada_mark, c)) { + entry->data.filemark.mark.col = (colnr_T)it.c; } + if (HAS_KEY(&it, _shada_mark, f)) { + entry->data.filemark.fname = xmemdupz(it.f.data, it.f.size); + } + if (entry->data.filemark.fname == NULL) { semsg(_(READERR("mark", "is missing file name")), initial_fpos); - CLEAR_GA_AND_ERROR_OUT(ad_ga); + goto shada_read_next_item_error; } if (entry->data.filemark.mark.lnum <= 0) { semsg(_(READERR("mark", "has invalid line number")), initial_fpos); - CLEAR_GA_AND_ERROR_OUT(ad_ga); + goto shada_read_next_item_error; } if (entry->data.filemark.mark.col < 0) { semsg(_(READERR("mark", "has invalid column number")), initial_fpos); - CLEAR_GA_AND_ERROR_OUT(ad_ga); + goto shada_read_next_item_error; } - SET_ADDITIONAL_DATA(entry->data.filemark.additional_data, "mark"); break; } case kSDItemRegister: { - if (unpacked.data.type != MSGPACK_OBJECT_MAP) { - semsg(_(READERR("register", "is not a dictionary")), initial_fpos); + Dict(_shada_register) it = { 0 }; + if (!unpack_keydict(&it, DictHash(_shada_register), &ad, &read_ptr, &read_size, &error_alloc)) { + semsg(_(READERR("register", "%s")), initial_fpos, error_alloc); + kv_destroy(it.rc); goto shada_read_next_item_error; } - garray_T ad_ga; - ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1); - for (size_t i = 0; i < unpacked.data.via.map.size; i++) { - CHECK_KEY_IS_STR(unpacked, "register") - if (CHECK_KEY(unpacked.data.via.map.ptr[i].key, - REG_KEY_CONTENTS)) { - if (unpacked.data.via.map.ptr[i].val.type != MSGPACK_OBJECT_ARRAY) { - semsg(_(READERR("register", - "has " REG_KEY_CONTENTS - " key with non-array value")), - initial_fpos); - CLEAR_GA_AND_ERROR_OUT(ad_ga); - } - if (unpacked.data.via.map.ptr[i].val.via.array.size == 0) { - semsg(_(READERR("register", - "has " REG_KEY_CONTENTS " key with empty array")), - initial_fpos); - CLEAR_GA_AND_ERROR_OUT(ad_ga); - } - const msgpack_object_array arr = - unpacked.data.via.map.ptr[i].val.via.array; - for (size_t j = 0; j < arr.size; j++) { - if (arr.ptr[j].type != MSGPACK_OBJECT_BIN) { - semsg(_(READERR("register", "has " REG_KEY_CONTENTS " array " - "with non-binary value")), initial_fpos); - CLEAR_GA_AND_ERROR_OUT(ad_ga); - } - } - entry->data.reg.contents_size = arr.size; - entry->data.reg.contents = xmalloc(arr.size * sizeof(char *)); - for (size_t j = 0; j < arr.size; j++) { - entry->data.reg.contents[j] = BIN_CONVERTED(arr.ptr[j].via.bin); - } - } - BOOLEAN_KEY(unpacked, "register", REG_KEY_UNNAMED, - entry->data.reg.is_unnamed) - TYPED_KEY(unpacked, "register", REG_KEY_TYPE, "an unsigned integer", - entry->data.reg.type, POSITIVE_INTEGER, u64, TOU8) - TYPED_KEY(unpacked, "register", KEY_NAME_CHAR, "an unsigned integer", - entry->data.reg.name, POSITIVE_INTEGER, u64, TOCHAR) - TYPED_KEY(unpacked, "register", REG_KEY_WIDTH, "an unsigned integer", - entry->data.reg.width, POSITIVE_INTEGER, u64, TOSIZE) - ADDITIONAL_KEY(unpacked) - } - if (entry->data.reg.contents == NULL) { - semsg(_(READERR("register", "has missing " REG_KEY_CONTENTS " array")), + if (it.rc.size == 0) { + semsg(_(READERR("register", + "has " KEY_NAME(REG_KEY_CONTENTS) " key with missing or empty array")), initial_fpos); - CLEAR_GA_AND_ERROR_OUT(ad_ga); + goto shada_read_next_item_error; + } + entry->data.reg.contents_size = it.rc.size; + entry->data.reg.contents = xmalloc(it.rc.size * sizeof(char *)); + for (size_t j = 0; j < it.rc.size; j++) { + entry->data.reg.contents[j] = xmemdupz(it.rc.items[j].data, it.rc.items[j].size); } - SET_ADDITIONAL_DATA(entry->data.reg.additional_data, "register"); + kv_destroy(it.rc); + +#define REGISTER_VAL(name, loc, type) \ + if (HAS_KEY(&it, _shada_register, name)) { \ + loc = (type)it.name; \ + } + REGISTER_VAL(REG_KEY_UNNAMED, entry->data.reg.is_unnamed, bool) + REGISTER_VAL(REG_KEY_TYPE, entry->data.reg.type, uint8_t) + REGISTER_VAL(KEY_NAME_CHAR, entry->data.reg.name, char) + REGISTER_VAL(REG_KEY_WIDTH, entry->data.reg.width, size_t) break; } case kSDItemHistoryEntry: { - if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) { - semsg(_(READERR("history", "is not an array")), initial_fpos); - goto shada_read_next_item_error; - } - if (unpacked.data.via.array.size < 2) { - semsg(_(READERR("history", "does not have enough elements")), - initial_fpos); + ssize_t len = unpack_array(&read_ptr, &read_size); + + if (len < 2) { + semsg(_(READERR("history", "is not an array with enough elements")), initial_fpos); goto shada_read_next_item_error; } - if (unpacked.data.via.array.ptr[0].type - != MSGPACK_OBJECT_POSITIVE_INTEGER) { - semsg(_(READERR("history", "has wrong history type type")), - initial_fpos); + Integer hist_type; + if (!unpack_integer(&read_ptr, &read_size, &hist_type)) { + semsg(_(READERR("history", "has wrong history type type")), initial_fpos); goto shada_read_next_item_error; } - if (unpacked.data.via.array.ptr[1].type - != MSGPACK_OBJECT_BIN) { - semsg(_(READERR("history", "has wrong history string type")), - initial_fpos); + const String item = unpack_string(&read_ptr, &read_size); + if (!item.data) { + semsg(_(READERR("history", "has wrong history string type")), initial_fpos); goto shada_read_next_item_error; } - if (memchr(unpacked.data.via.array.ptr[1].via.bin.ptr, 0, - unpacked.data.via.array.ptr[1].via.bin.size) != NULL) { - semsg(_(READERR("history", "contains string with zero byte inside")), - initial_fpos); + if (memchr(item.data, 0, item.size) != NULL) { + semsg(_(READERR("history", "contains string with zero byte inside")), initial_fpos); goto shada_read_next_item_error; } - entry->data.history_item.histtype = - (uint8_t)unpacked.data.via.array.ptr[0].via.u64; - const bool is_hist_search = - entry->data.history_item.histtype == HIST_SEARCH; + entry->data.history_item.histtype = (uint8_t)hist_type; + const bool is_hist_search = entry->data.history_item.histtype == HIST_SEARCH; if (is_hist_search) { - if (unpacked.data.via.array.size < 3) { + if (len < 3) { semsg(_(READERR("search history", "does not have separator character")), initial_fpos); goto shada_read_next_item_error; } - if (unpacked.data.via.array.ptr[2].type - != MSGPACK_OBJECT_POSITIVE_INTEGER) { - semsg(_(READERR("search history", - "has wrong history separator type")), initial_fpos); + Integer sep_type; + if (!unpack_integer(&read_ptr, &read_size, &sep_type)) { + semsg(_(READERR("search history", "has wrong history separator type")), initial_fpos); goto shada_read_next_item_error; } - entry->data.history_item.sep = - (char)unpacked.data.via.array.ptr[2].via.u64; + entry->data.history_item.sep = (char)sep_type; } - size_t strsize; - strsize = ( - unpacked.data.via.array.ptr[1].via.bin.size - + 1 // Zero byte - + 1); // Separator character + size_t strsize = (item.size + + 1 // Zero byte + + 1); // Separator character entry->data.history_item.string = xmalloc(strsize); - memcpy(entry->data.history_item.string, - unpacked.data.via.array.ptr[1].via.bin.ptr, - unpacked.data.via.array.ptr[1].via.bin.size); + memcpy(entry->data.history_item.string, item.data, item.size); entry->data.history_item.string[strsize - 2] = 0; - entry->data.history_item.string[strsize - 1] = - entry->data.history_item.sep; - SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, (2 + is_hist_search), - entry->data.history_item.additional_elements, - "history"); + entry->data.history_item.string[strsize - 1] = entry->data.history_item.sep; + read_additional_array_elements = (uint32_t)(len - (2 + is_hist_search)); break; } case kSDItemVariable: { - if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) { - semsg(_(READERR("variable", "is not an array")), initial_fpos); - goto shada_read_next_item_error; - } - if (unpacked.data.via.array.size < 2) { - semsg(_(READERR("variable", "does not have enough elements")), - initial_fpos); + ssize_t len = unpack_array(&read_ptr, &read_size); + + if (len < 2) { + semsg(_(READERR("variable", "is not an array with enough elements")), initial_fpos); goto shada_read_next_item_error; } - if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) { - semsg(_(READERR("variable", "has wrong variable name type")), - initial_fpos); + + String name = unpack_string(&read_ptr, &read_size); + + if (!name.data) { + semsg(_(READERR("variable", "has wrong variable name type")), initial_fpos); goto shada_read_next_item_error; } - entry->data.global_var.name = - xmemdupz(unpacked.data.via.array.ptr[0].via.bin.ptr, - unpacked.data.via.array.ptr[0].via.bin.size); - SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, 2, - entry->data.global_var.additional_elements, - "variable"); + entry->data.global_var.name = xmemdupz(name.data, name.size); + + String binval = unpack_string(&read_ptr, &read_size); + bool is_blob = false; - // A msgpack BIN could be a String or Blob; an additional VAR_TYPE_BLOB - // element is stored with Blobs which can be used to differentiate them - if (unpacked.data.via.array.ptr[1].type == MSGPACK_OBJECT_BIN) { - const listitem_T *type_item - = tv_list_first(entry->data.global_var.additional_elements); - if (type_item != NULL) { - const typval_T *type_tv = TV_LIST_ITEM_TV(type_item); - if (type_tv->v_type != VAR_NUMBER - || type_tv->vval.v_number != VAR_TYPE_BLOB) { + if (binval.data) { + if (len > 2) { + // A msgpack BIN could be a String or Blob; an additional VAR_TYPE_BLOB + // element is stored with Blobs which can be used to differentiate them + Integer type; + if (!unpack_integer(&read_ptr, &read_size, &type) || type != VAR_TYPE_BLOB) { semsg(_(READERR("variable", "has wrong variable type")), initial_fpos); goto shada_read_next_item_error; } is_blob = true; } + entry->data.global_var.value = decode_string(binval.data, binval.size, is_blob, false); + } else { + int status = unpack_typval(&read_ptr, &read_size, &entry->data.global_var.value); + if (status != MPACK_OK) { + semsg(_(READERR("variable", "has value that cannot " + "be converted to the Vimscript value")), initial_fpos); + goto shada_read_next_item_error; + } } - if (is_blob) { - const msgpack_object_bin *const bin - = &unpacked.data.via.array.ptr[1].via.bin; - blob_T *const blob = tv_blob_alloc(); - ga_concat_len(&blob->bv_ga, bin->ptr, (size_t)bin->size); - tv_blob_set_ret(&entry->data.global_var.value, blob); - } else if (msgpack_to_vim(unpacked.data.via.array.ptr[1], - &(entry->data.global_var.value)) == FAIL) { - semsg(_(READERR("variable", "has value that cannot " - "be converted to the Vimscript value")), initial_fpos); - goto shada_read_next_item_error; - } + read_additional_array_elements = (uint32_t)(len - 2 - (is_blob ? 1 : 0)); break; } - case kSDItemSubString: - if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) { - semsg(_(READERR("sub string", "is not an array")), initial_fpos); - goto shada_read_next_item_error; - } - if (unpacked.data.via.array.size < 1) { - semsg(_(READERR("sub string", "does not have enough elements")), - initial_fpos); + case kSDItemSubString: { + ssize_t len = unpack_array(&read_ptr, &read_size); + + if (len < 1) { + semsg(_(READERR("sub string", "is not an array with enough elements")), initial_fpos); goto shada_read_next_item_error; } - if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) { - semsg(_(READERR("sub string", "has wrong sub string type")), - initial_fpos); + + String sub = unpack_string(&read_ptr, &read_size); + if (!sub.data) { + semsg(_(READERR("sub string", "has wrong sub string type")), initial_fpos); goto shada_read_next_item_error; } - entry->data.sub_string.sub = - BIN_CONVERTED(unpacked.data.via.array.ptr[0].via.bin); - SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, 1, - entry->data.sub_string.additional_elements, - "sub string"); + entry->data.sub_string.sub = xmemdupz(sub.data, sub.size); + read_additional_array_elements = (uint32_t)(len - 1); break; - case kSDItemBufferList: - if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) { + } + case kSDItemBufferList: { + ssize_t len = unpack_array(&read_ptr, &read_size); + if (len < 0) { semsg(_(READERR("buffer list", "is not an array")), initial_fpos); goto shada_read_next_item_error; } - if (unpacked.data.via.array.size == 0) { + if (len == 0) { break; } - entry->data.buffer_list.buffers = - xcalloc(unpacked.data.via.array.size, - sizeof(*entry->data.buffer_list.buffers)); - for (size_t i = 0; i < unpacked.data.via.array.size; i++) { + entry->data.buffer_list.buffers = xcalloc((size_t)len, + sizeof(*entry->data.buffer_list.buffers)); + for (size_t i = 0; i < (size_t)len; i++) { entry->data.buffer_list.size++; - msgpack_unpacked unpacked_2 = (msgpack_unpacked) { - .data = unpacked.data.via.array.ptr[i], - }; - { - if (unpacked_2.data.type != MSGPACK_OBJECT_MAP) { - semsg(_(RERR "Error while reading ShaDa file: " - "buffer list at position %" PRIu64 " " - "contains entry that is not a dictionary"), - initial_fpos); - goto shada_read_next_item_error; - } - entry->data.buffer_list.buffers[i].pos = default_pos; - garray_T ad_ga; - ga_init(&ad_ga, sizeof(*(unpacked_2.data.via.map.ptr)), 1); - { - // XXX: Temporarily reassign `i` because the macros depend on it. - const size_t j = i; - { - for (i = 0; i < unpacked_2.data.via.map.size; i++) { - CHECK_KEY_IS_STR(unpacked_2, "buffer list entry") - INTEGER_KEY(unpacked_2, "buffer list entry", KEY_LNUM, - entry->data.buffer_list.buffers[j].pos.lnum) - INTEGER_KEY(unpacked_2, "buffer list entry", KEY_COL, - entry->data.buffer_list.buffers[j].pos.col) - STRING_KEY(unpacked_2, "buffer list entry", KEY_FILE, - entry->data.buffer_list.buffers[j].fname) - ADDITIONAL_KEY(unpacked_2) - } - } - i = j; // XXX: Restore `i`. - } - if (entry->data.buffer_list.buffers[i].pos.lnum <= 0) { - semsg(_(RERR "Error while reading ShaDa file: " - "buffer list at position %" PRIu64 " " - "contains entry with invalid line number"), - initial_fpos); - CLEAR_GA_AND_ERROR_OUT(ad_ga); - } - if (entry->data.buffer_list.buffers[i].pos.col < 0) { - semsg(_(RERR "Error while reading ShaDa file: " - "buffer list at position %" PRIu64 " " - "contains entry with invalid column number"), - initial_fpos); - CLEAR_GA_AND_ERROR_OUT(ad_ga); - } - if (entry->data.buffer_list.buffers[i].fname == NULL) { - semsg(_(RERR "Error while reading ShaDa file: " - "buffer list at position %" PRIu64 " " - "contains entry that does not have a file name"), - initial_fpos); - CLEAR_GA_AND_ERROR_OUT(ad_ga); - } - SET_ADDITIONAL_DATA(entry->data.buffer_list.buffers[i].additional_data, - "buffer list entry"); + Dict(_shada_buflist_item) it = { 0 }; + AdditionalDataBuilder it_ad = KV_INITIAL_VALUE; + if (!unpack_keydict(&it, DictHash(_shada_buflist_item), &it_ad, &read_ptr, &read_size, + &error_alloc)) { + semsg(_(RERR "Error while reading ShaDa file: " + "buffer list at position %" PRIu64 " contains entry that %s"), + initial_fpos, error_alloc); + kv_destroy(it_ad); + goto shada_read_next_item_error; + } + struct buffer_list_buffer *e = &entry->data.buffer_list.buffers[i]; + e->additional_data = (AdditionalData *)it_ad.items; + e->pos = default_pos; + if (HAS_KEY(&it, _shada_buflist_item, l)) { + e->pos.lnum = (linenr_T)it.l; + } + if (HAS_KEY(&it, _shada_buflist_item, c)) { + e->pos.col = (colnr_T)it.c; + } + if (HAS_KEY(&it, _shada_buflist_item, f)) { + e->fname = xmemdupz(it.f.data, it.f.size); + } + + if (e->pos.lnum <= 0) { + semsg(_(RERR "Error while reading ShaDa file: " + "buffer list at position %" PRIu64 " " + "contains entry with invalid line number"), + initial_fpos); + goto shada_read_next_item_error; + } + if (e->pos.col < 0) { + semsg(_(RERR "Error while reading ShaDa file: " + "buffer list at position %" PRIu64 " " + "contains entry with invalid column number"), + initial_fpos); + goto shada_read_next_item_error; + } + if (e->fname == NULL) { + semsg(_(RERR "Error while reading ShaDa file: " + "buffer list at position %" PRIu64 " " + "contains entry that does not have a file name"), + initial_fpos); + goto shada_read_next_item_error; } } break; + } case kSDItemMissing: case kSDItemUnknown: abort(); } + + for (uint32_t i = 0; i < read_additional_array_elements; i++) { + const char *item_start = read_ptr; + int status = unpack_skip(&read_ptr, &read_size); + if (status) { + goto shada_read_next_item_error; + } + + push_additional_data(&ad, item_start, (size_t)(read_ptr - item_start)); + } + + if (read_size) { + semsg(_(READERR("item", "additional bytes")), initial_fpos); + goto shada_read_next_item_error; + } + entry->type = (ShadaEntryType)type_u64; + entry->additional_data = (AdditionalData *)ad.items; ret = kSDReadStatusSuccess; shada_read_next_item_end: - if (buf != NULL) { - msgpack_unpacked_destroy(&unpacked); + if (buf_allocated) { xfree(buf); } return ret; @@ -3955,26 +3525,10 @@ shada_read_next_item_error: entry->type = (ShadaEntryType)type_u64; shada_free_shada_entry(entry); entry->type = kSDItemMissing; + xfree(error_alloc); + kv_destroy(ad); goto shada_read_next_item_end; } -#undef BIN_CONVERTED -#undef CHECK_KEY -#undef BOOLEAN_KEY -#undef CONVERTED_STRING_KEY -#undef STRING_KEY -#undef ADDITIONAL_KEY -#undef ID -#undef BINDUP -#undef TOCHAR -#undef TOINT -#undef TYPED_KEY -#undef INT_KEY -#undef INTEGER_KEY -#undef TOU8 -#undef TOSIZE -#undef SET_ADDITIONAL_DATA -#undef SET_ADDITIONAL_ELEMENTS -#undef CLEAR_GA_AND_ERROR_OUT /// Check whether "name" is on removable media (according to 'shada') /// @@ -4051,9 +3605,9 @@ static inline size_t shada_init_jumps(PossiblyFreedShadaEntry *jumps, .name = NUL, .mark = fm.fmark.mark, .fname = (char *)fname, - .additional_data = fm.fmark.additional_data, } - } + }, + .additional_data = fm.fmark.additional_data, } }; } while (jump_iter != NULL); @@ -4063,13 +3617,12 @@ static inline size_t shada_init_jumps(PossiblyFreedShadaEntry *jumps, /// Write registers ShaDa entries in given msgpack_sbuffer. /// /// @param[in] sbuf target msgpack_sbuffer to write to. -void shada_encode_regs(msgpack_sbuffer *const sbuf) +String shada_encode_regs(void) FUNC_ATTR_NONNULL_ALL { WriteMergerState *const wms = xcalloc(1, sizeof(*wms)); shada_initialize_registers(wms, -1); - msgpack_packer packer; - msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write); + PackerBuffer packer = packer_string_buffer(); for (size_t i = 0; i < ARRAY_SIZE(wms->registers); i++) { if (wms->registers[i].data.type == kSDItemRegister) { if (kSDWriteFailed @@ -4079,52 +3632,53 @@ void shada_encode_regs(msgpack_sbuffer *const sbuf) } } xfree(wms); + return packer_take_string(&packer); } /// Write jumplist ShaDa entries in given msgpack_sbuffer. /// /// @param[in] sbuf target msgpack_sbuffer to write to. -void shada_encode_jumps(msgpack_sbuffer *const sbuf) +String shada_encode_jumps(void) FUNC_ATTR_NONNULL_ALL { Set(ptr_t) removable_bufs = SET_INIT; find_removable_bufs(&removable_bufs); PossiblyFreedShadaEntry jumps[JUMPLISTSIZE]; size_t jumps_size = shada_init_jumps(jumps, &removable_bufs); - msgpack_packer packer; - msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write); + PackerBuffer packer = packer_string_buffer(); for (size_t i = 0; i < jumps_size; i++) { if (kSDWriteFailed == shada_pack_pfreed_entry(&packer, jumps[i], 0)) { abort(); } } + return packer_take_string(&packer); } /// Write buffer list ShaDa entry in given msgpack_sbuffer. /// /// @param[in] sbuf target msgpack_sbuffer to write to. -void shada_encode_buflist(msgpack_sbuffer *const sbuf) +String shada_encode_buflist(void) FUNC_ATTR_NONNULL_ALL { Set(ptr_t) removable_bufs = SET_INIT; find_removable_bufs(&removable_bufs); ShadaEntry buflist_entry = shada_get_buflist(&removable_bufs); - msgpack_packer packer; - msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write); + + PackerBuffer packer = packer_string_buffer(); if (kSDWriteFailed == shada_pack_entry(&packer, buflist_entry, 0)) { abort(); } xfree(buflist_entry.data.buffer_list.buffers); + return packer_take_string(&packer); } /// Write global variables ShaDa entries in given msgpack_sbuffer. /// /// @param[in] sbuf target msgpack_sbuffer to write to. -void shada_encode_gvars(msgpack_sbuffer *const sbuf) +String shada_encode_gvars(void) FUNC_ATTR_NONNULL_ALL { - msgpack_packer packer; - msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write); + PackerBuffer packer = packer_string_buffer(); const void *var_iter = NULL; const Timestamp cur_timestamp = os_time(); do { @@ -4145,9 +3699,9 @@ void shada_encode_gvars(msgpack_sbuffer *const sbuf) .global_var = { .name = (char *)name, .value = tgttv, - .additional_elements = NULL, } - } + }, + .additional_data = NULL, }, 0); if (kSDWriteFailed == r) { abort(); @@ -4156,77 +3710,21 @@ void shada_encode_gvars(msgpack_sbuffer *const sbuf) } tv_clear(&vartv); } while (var_iter != NULL); + return packer_take_string(&packer); } -/// Wrapper for reading from msgpack_sbuffer. -/// -/// @return number of bytes read. -static ptrdiff_t read_sbuf(ShaDaReadDef *const sd_reader, void *const dest, const size_t size) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - msgpack_sbuffer *sbuf = (msgpack_sbuffer *)sd_reader->cookie; - const uintmax_t bytes_read = MIN(size, sbuf->size - sd_reader->fpos); - if (bytes_read < size) { - sd_reader->eof = true; - } - memcpy(dest, sbuf->data + sd_reader->fpos, (size_t)bytes_read); - sd_reader->fpos += bytes_read; - return (ptrdiff_t)bytes_read; -} - -/// Wrapper for read that ignores bytes read from msgpack_sbuffer. -/// -/// Used for skipping. -/// -/// @param[in,out] sd_reader ShaDaReadDef with msgpack_sbuffer. -/// @param[in] offset Amount of bytes to skip. -/// -/// @return FAIL in case of failure, OK in case of success. May set -/// sd_reader->eof. -static int sd_sbuf_reader_skip_read(ShaDaReadDef *const sd_reader, const size_t offset) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - msgpack_sbuffer *sbuf = (msgpack_sbuffer *)sd_reader->cookie; - assert(sbuf->size >= sd_reader->fpos); - const uintmax_t skip_bytes = MIN(offset, sbuf->size - sd_reader->fpos); - if (skip_bytes < offset) { - sd_reader->eof = true; - return FAIL; - } - sd_reader->fpos += offset; - return OK; -} - -/// Prepare ShaDaReadDef with msgpack_sbuffer for reading. -/// -/// @param[in] sbuf msgpack_sbuffer to read from. -/// @param[out] sd_reader Location where reader structure will be saved. -static void open_shada_sbuf_for_reading(const msgpack_sbuffer *const sbuf, ShaDaReadDef *sd_reader) - FUNC_ATTR_NONNULL_ALL -{ - *sd_reader = (ShaDaReadDef) { - .read = &read_sbuf, - .close = NULL, - .skip = &sd_sbuf_reader_skip_read, - .error = NULL, - .eof = false, - .fpos = 0, - .cookie = (void *)sbuf, - }; -} - -/// Read ShaDa from msgpack_sbuffer. +/// Read ShaDa from String. /// -/// @param[in] file msgpack_sbuffer to read from. +/// @param[in] string string to read from. /// @param[in] flags Flags, see ShaDaReadFileFlags enum. -void shada_read_sbuf(msgpack_sbuffer *const sbuf, const int flags) +void shada_read_string(String string, const int flags) FUNC_ATTR_NONNULL_ALL { - assert(sbuf != NULL); - if (sbuf->data == NULL) { + if (string.size == 0) { return; } - ShaDaReadDef sd_reader; - open_shada_sbuf_for_reading(sbuf, &sd_reader); + FileDescriptor sd_reader; + file_open_buffer(&sd_reader, string.data, string.size); shada_read(&sd_reader, flags); + close_file(&sd_reader); } diff --git a/src/nvim/shada.h b/src/nvim/shada.h index d7cac24afc..7d736dadc7 100644 --- a/src/nvim/shada.h +++ b/src/nvim/shada.h @@ -1,6 +1,6 @@ #pragma once -#include <msgpack.h> // IWYU pragma: keep +#include "nvim/api/private/defs.h" /// Flags for shada_read_file and children typedef enum { diff --git a/src/nvim/sign.c b/src/nvim/sign.c index 4e6672c5dd..b4ba7833e9 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -21,6 +21,7 @@ #include "nvim/decoration_defs.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -125,8 +126,8 @@ static void buf_set_sign(buf_T *buf, uint32_t *id, char *group, int prio, linenr | (has_hl ? MT_FLAG_DECOR_SIGNHL : 0); DecorInline decor = { .ext = true, .data.ext = { .vt = NULL, .sh_idx = decor_put_sh(sign) } }; - extmark_set(buf, ns, id, lnum - 1, 0, -1, -1, decor, decor_flags, true, - false, true, true, false, NULL); + extmark_set(buf, ns, id, MIN(buf->b_ml.ml_line_count, lnum) - 1, 0, -1, -1, + decor, decor_flags, true, false, true, true, NULL); } /// For an existing, placed sign with "id", modify the sign, group or priority. @@ -246,12 +247,6 @@ static int buf_delete_signs(buf_T *buf, char *group, int id, linenr_T atlnum) return FAIL; } - // When deleting the last sign need to redraw the windows to remove the - // sign column. Not when curwin is NULL (this means we're exiting). - if (!buf_meta_total(buf, kMTMetaSignText) && curwin != NULL) { - changed_line_abv_curs(); - } - return OK; } @@ -297,8 +292,8 @@ static void sign_list_placed(buf_T *rbuf, char *group) qsort((void *)&kv_A(signs, 0), kv_size(signs), sizeof(MTKey), sign_row_cmp); for (size_t i = 0; i < kv_size(signs); i++) { - namebuf[0] = '\0'; - groupbuf[0] = '\0'; + namebuf[0] = NUL; + groupbuf[0] = NUL; MTKey mark = kv_A(signs, i); DecorSignHighlight *sh = decor_find_sign(mt_decor(mark)); @@ -381,7 +376,7 @@ int init_sign_text(sign_T *sp, schar_T *sign_text, char *text) if (!vim_isprintc(c)) { break; } - int width = utf_char2cells(c); + int width = utf_ptr2cells(s); if (width == 2) { sign_text[cells + 1] = 0; } @@ -406,22 +401,16 @@ int init_sign_text(sign_T *sp, schar_T *sign_text, char *text) /// Define a new sign or update an existing sign static int sign_define_by_name(char *name, char *icon, char *text, char *linehl, char *texthl, - char *culhl, char *numhl) + char *culhl, char *numhl, int prio) { cstr_t *key; - sign_T **sp = (sign_T **)pmap_put_ref(cstr_t)(&sign_map, name, &key, NULL); + bool new_sign = false; + sign_T **sp = (sign_T **)pmap_put_ref(cstr_t)(&sign_map, name, &key, &new_sign); - if (*sp == NULL) { + if (new_sign) { *key = xstrdup(name); *sp = xcalloc(1, sizeof(sign_T)); (*sp)->sn_name = (char *)(*key); - } else { - // Signs may already exist, a redraw is needed in windows with a non-empty sign list. - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (buf_has_signs(wp->w_buffer)) { - redraw_buf_later(wp->w_buffer, UPD_NOT_VALID); - } - } } // Set values for a defined sign. @@ -436,6 +425,8 @@ static int sign_define_by_name(char *name, char *icon, char *text, char *linehl, return FAIL; } + (*sp)->sn_priority = prio; + char *arg[] = { linehl, texthl, culhl, numhl }; int *hl[] = { &(*sp)->sn_line_hl, &(*sp)->sn_text_hl, &(*sp)->sn_cul_hl, &(*sp)->sn_num_hl }; for (int i = 0; i < 4; i++) { @@ -444,6 +435,28 @@ static int sign_define_by_name(char *name, char *icon, char *text, char *linehl, } } + // Update already placed signs and redraw if necessary when modifying a sign. + if (!new_sign) { + bool did_redraw = false; + for (size_t i = 0; i < kv_size(decor_items); i++) { + DecorSignHighlight *sh = &kv_A(decor_items, i); + if (sh->sign_name && strcmp(sh->sign_name, name) == 0) { + memcpy(sh->text, (*sp)->sn_text, SIGN_WIDTH * sizeof(schar_T)); + sh->hl_id = (*sp)->sn_text_hl; + sh->line_hl_id = (*sp)->sn_line_hl; + sh->number_hl_id = (*sp)->sn_num_hl; + sh->cursorline_hl_id = (*sp)->sn_cul_hl; + if (!did_redraw) { + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + if (buf_has_signs(wp->w_buffer)) { + redraw_buf_later(wp->w_buffer, UPD_NOT_VALID); + } + } + did_redraw = true; + } + } + } + } return OK; } @@ -477,6 +490,11 @@ static void sign_list_defined(sign_T *sp) describe_sign_text(buf, sp->sn_text); msg_outtrans(buf, 0); } + if (sp->sn_priority > 0) { + char lbuf[MSG_BUF_LEN]; + vim_snprintf(lbuf, MSG_BUF_LEN, " priority=%d", sp->sn_priority); + msg_puts(lbuf); + } static char *arg[] = { " linehl=", " texthl=", " culhl=", " numhl=" }; int hl[] = { sp->sn_line_hl, sp->sn_text_hl, sp->sn_cul_hl, sp->sn_num_hl }; for (int i = 0; i < 4; i++) { @@ -499,22 +517,11 @@ static void sign_list_by_name(char *name) } } -static void may_force_numberwidth_recompute(buf_T *buf, int unplace) -{ - FOR_ALL_TAB_WINDOWS(tp, wp) - if (wp->w_buffer == buf - && (wp->w_p_nu || wp->w_p_rnu) - && (unplace || wp->w_nrwidth_width < 2) - && (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u')) { - wp->w_nrwidth_line_count = 0; - } -} - /// Place a sign at the specified file location or update a sign. static int sign_place(uint32_t *id, char *group, char *name, buf_T *buf, linenr_T lnum, int prio) { // Check for reserved character '*' in group name - if (group != NULL && (*group == '*' || *group == '\0')) { + if (group != NULL && (*group == '*' || *group == NUL)) { return FAIL; } @@ -524,6 +531,11 @@ static int sign_place(uint32_t *id, char *group, char *name, buf_T *buf, linenr_ return FAIL; } + // Use the default priority value for this sign. + if (prio == -1) { + prio = (sp->sn_priority != -1) ? sp->sn_priority : SIGN_DEF_PRIO; + } + if (lnum > 0) { // ":sign place {id} line={lnum} name={name} file={fname}": place a sign buf_set_sign(buf, id, group, prio, lnum, sp); @@ -531,11 +543,7 @@ static int sign_place(uint32_t *id, char *group, char *name, buf_T *buf, linenr_ // ":sign place {id} file={fname}": change sign type and/or priority lnum = buf_mod_sign(buf, id, group, prio, sp); } - if (lnum > 0) { - // When displaying signs in the 'number' column, if the width of the - // number column is less than 2, then force recomputing the width. - may_force_numberwidth_recompute(buf, false); - } else { + if (lnum <= 0) { semsg(_("E885: Not possible to change sign %s"), name); return FAIL; } @@ -562,13 +570,6 @@ static int sign_unplace_inner(buf_T *buf, int id, char *group, linenr_T atlnum) } } - // When all the signs in a buffer are removed, force recomputing the - // number column width (if enabled) in all the windows displaying the - // buffer if 'signcolumn' is set to 'number' in that window. - if (!buf_meta_total(buf, kMTMetaSignText)) { - may_force_numberwidth_recompute(buf, true); - } - return OK; } @@ -629,6 +630,7 @@ static void sign_define_cmd(char *name, char *cmdline) char *texthl = NULL; char *culhl = NULL; char *numhl = NULL; + int prio = -1; // set values for a defined sign. while (true) { @@ -649,6 +651,8 @@ static void sign_define_cmd(char *name, char *cmdline) culhl = arg + 6; } else if (strncmp(arg, "numhl=", 6) == 0) { numhl = arg + 6; + } else if (strncmp(arg, "priority=", 9) == 0) { + prio = atoi(arg + 9); } else { semsg(_(e_invarg2), arg); return; @@ -659,7 +663,7 @@ static void sign_define_cmd(char *name, char *cmdline) *cmdline++ = NUL; } - sign_define_by_name(name, icon, text, linehl, texthl, culhl, numhl); + sign_define_by_name(name, icon, text, linehl, texthl, culhl, numhl, prio); } /// ":sign place" command @@ -676,14 +680,14 @@ static void sign_place_cmd(buf_T *buf, linenr_T lnum, char *name, int id, char * // :sign place // :sign place group={group} // :sign place group=* - if (lnum >= 0 || name != NULL || (group != NULL && *group == '\0')) { + if (lnum >= 0 || name != NULL || (group != NULL && *group == NUL)) { emsg(_(e_invarg)); } else { sign_list_placed(buf, group); } } else { // Place a new sign - if (name == NULL || buf == NULL || (group != NULL && *group == '\0')) { + if (name == NULL || buf == NULL || (group != NULL && *group == NUL)) { emsg(_(e_invarg)); return; } @@ -695,7 +699,7 @@ static void sign_place_cmd(buf_T *buf, linenr_T lnum, char *name, int id, char * /// ":sign unplace" command static void sign_unplace_cmd(buf_T *buf, linenr_T lnum, const char *name, int id, char *group) { - if (lnum >= 0 || name != NULL || (group != NULL && *group == '\0')) { + if (lnum >= 0 || name != NULL || (group != NULL && *group == NUL)) { emsg(_(e_invarg)); return; } @@ -722,7 +726,7 @@ static void sign_jump_cmd(buf_T *buf, linenr_T lnum, const char *name, int id, c return; } - if (buf == NULL || (group != NULL && *group == '\0') || lnum >= 0 || name != NULL) { + if (buf == NULL || (group != NULL && *group == NUL) || lnum >= 0 || name != NULL) { // File or buffer is not specified or an empty group is used // or a line number or a sign name is specified. emsg(_(e_invarg)); @@ -874,7 +878,7 @@ void ex_sign(exarg_T *eap) linenr_T lnum = -1; char *name = NULL; char *group = NULL; - int prio = SIGN_DEF_PRIO; + int prio = -1; buf_T *buf = NULL; // Parse command line arguments @@ -907,6 +911,9 @@ static dict_T *sign_get_info_dict(sign_T *sp) describe_sign_text(buf, sp->sn_text); tv_dict_add_str(d, S_LEN("text"), buf); } + if (sp->sn_priority > 0) { + tv_dict_add_nr(d, S_LEN("priority"), sp->sn_priority); + } static char *arg[] = { "linehl", "texthl", "culhl", "numhl" }; int hl[] = { sp->sn_line_hl, sp->sn_text_hl, sp->sn_cul_hl, sp->sn_num_hl }; for (int i = 0; i < 4; i++) { @@ -1071,7 +1078,8 @@ char *get_sign_name(expand_T *xp, int idx) case EXP_SUBCMD: return cmds[idx]; case EXP_DEFINE: { - char *define_arg[] = { "culhl=", "icon=", "linehl=", "numhl=", "text=", "texthl=", NULL }; + char *define_arg[] = { "culhl=", "icon=", "linehl=", "numhl=", "text=", "texthl=", + "priority=", NULL }; return define_arg[idx]; } case EXP_PLACE: { @@ -1227,6 +1235,7 @@ static int sign_define_from_dict(char *name, dict_T *dict) char *texthl = NULL; char *culhl = NULL; char *numhl = NULL; + int prio = -1; if (dict != NULL) { icon = tv_dict_get_string(dict, "icon", false); @@ -1235,9 +1244,10 @@ static int sign_define_from_dict(char *name, dict_T *dict) texthl = tv_dict_get_string(dict, "texthl", false); culhl = tv_dict_get_string(dict, "culhl", false); numhl = tv_dict_get_string(dict, "numhl", false); + prio = (int)tv_dict_get_number_def(dict, "priority", -1); } - return sign_define_by_name(name, icon, text, linehl, texthl, culhl, numhl) - 1; + return sign_define_by_name(name, icon, text, linehl, texthl, culhl, numhl, prio) - 1; } /// Define multiple signs using attributes from list 'l' and store the return @@ -1343,7 +1353,7 @@ void f_sign_getplaced(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (group == NULL) { return; } - if (*group == '\0') { // empty string means global group + if (*group == NUL) { // empty string means global group group = NULL; } } @@ -1469,7 +1479,7 @@ static int sign_place_from_dict(typval_T *id_tv, typval_T *group_tv, typval_T *n } } - int prio = SIGN_DEF_PRIO; + int prio = -1; di = tv_dict_find(dict, "priority", -1); if (di != NULL) { prio = (int)tv_get_number_chk(&di->di_tv, ¬anum); diff --git a/src/nvim/sign_defs.h b/src/nvim/sign_defs.h index ad2a2b737d..f6712513b7 100644 --- a/src/nvim/sign_defs.h +++ b/src/nvim/sign_defs.h @@ -18,6 +18,7 @@ typedef struct { int sn_text_hl; // highlight ID for text int sn_cul_hl; // highlight ID for text on current line when 'cursorline' is set int sn_num_hl; // highlight ID for line number + int sn_priority; // default priority of this sign, -1 means SIGN_DEF_PRIO } sign_T; typedef struct { diff --git a/src/nvim/spell.c b/src/nvim/spell.c index d7a6adef58..8ec28c7f61 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -72,6 +72,7 @@ #include "nvim/decoration.h" #include "nvim/decoration_provider.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" @@ -230,14 +231,6 @@ char *repl_to = NULL; /// caller can skip over the word. size_t spell_check(win_T *wp, char *ptr, hlf_T *attrp, int *capcol, bool docount) { - matchinf_T mi; // Most things are put in "mi" so that it can - // be passed to functions quickly. - size_t nrlen = 0; // found a number first - size_t wrongcaplen = 0; - bool count_word = docount; - bool use_camel_case = (wp->w_s->b_p_spo_flags & SPO_CAMEL) != 0; - bool is_camel_case = false; - // A word never starts at a space or a control character. Return quickly // then, skipping over the character. if ((uint8_t)(*ptr) <= ' ') { @@ -249,6 +242,13 @@ size_t spell_check(win_T *wp, char *ptr, hlf_T *attrp, int *capcol, bool docount return 1; } + size_t nrlen = 0; // found a number first + size_t wrongcaplen = 0; + bool count_word = docount; + bool use_camel_case = (wp->w_s->b_p_spo_flags & SPO_CAMEL) != 0; + bool is_camel_case = false; + + matchinf_T mi; // Most things are put in "mi" so that it can be passed to functions quickly. CLEAR_FIELD(mi); // A number is always OK. Also skip hexadecimal numbers 0xFF99 and @@ -540,7 +540,6 @@ static void find_word(matchinf_T *mip, int mode) int endlen[MAXWLEN]; // length at possible word endings idx_T endidx[MAXWLEN]; // possible word endings int endidxcnt = 0; - int c; // Repeat advancing in the tree until: // - there is a byte that doesn't match, @@ -582,7 +581,7 @@ static void find_word(matchinf_T *mip, int mode) } // Perform a binary search in the list of accepted bytes. - c = (uint8_t)ptr[wlen]; + int c = (uint8_t)ptr[wlen]; if (c == TAB) { // <Tab> is handled like <Space> c = ' '; } @@ -626,9 +625,6 @@ static void find_word(matchinf_T *mip, int mode) } } - char *p; - bool word_ends; - // Verify that one of the possible endings is valid. Try the longest // first. while (endidxcnt > 0) { @@ -639,6 +635,7 @@ static void find_word(matchinf_T *mip, int mode) if (utf_head_off(ptr, ptr + wlen) > 0) { continue; // not at first byte of character } + bool word_ends; if (spell_iswordp(ptr + wlen, mip->mi_win)) { if (slang->sl_compprog == NULL && !slang->sl_nobreak) { continue; // next char is a word character @@ -655,7 +652,7 @@ static void find_word(matchinf_T *mip, int mode) // Compute byte length in original word, length may change // when folding case. This can be slow, take a shortcut when the // case-folded word is equal to the keep-case word. - p = mip->mi_word; + char *p = mip->mi_word; if (strncmp(ptr, p, (size_t)wlen) != 0) { for (char *s = ptr; s < ptr + wlen; MB_PTR_ADV(s)) { MB_PTR_ADV(p); @@ -691,10 +688,10 @@ static void find_word(matchinf_T *mip, int mode) // When mode is FIND_PREFIX the word must support the prefix: // check the prefix ID and the condition. Do that for the list at // mip->mi_prefarridx that find_prefix() filled. - c = valid_word_prefix(mip->mi_prefcnt, mip->mi_prefarridx, - (int)flags, - mip->mi_word + mip->mi_cprefixlen, slang, - false); + int c = valid_word_prefix(mip->mi_prefcnt, mip->mi_prefarridx, + (int)flags, + mip->mi_word + mip->mi_cprefixlen, slang, + false); if (c == 0) { continue; } @@ -765,6 +762,7 @@ static void find_word(matchinf_T *mip, int mode) if (mode == FIND_COMPOUND) { int capflags; + char *p; // Need to check the caps type of the appended compound // word. @@ -851,7 +849,7 @@ static void find_word(matchinf_T *mip, int mode) // byte length in keep-case word. Length may change when // folding case. This can be slow, take a shortcut when // the case-folded word is equal to the keep-case word. - p = mip->mi_fword; + char *p = mip->mi_fword; if (strncmp(ptr, p, (size_t)wlen) != 0) { for (char *s = ptr; s < ptr + wlen; MB_PTR_ADV(s)) { MB_PTR_ADV(p); @@ -1296,12 +1294,14 @@ static inline bool can_syn_spell(win_T *wp, linenr_T lnum, int col) /// @return 0 if not found, length of the badly spelled word otherwise. size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *attrp) { + if (no_spell_checking(wp)) { + return 0; + } + pos_T found_pos; size_t found_len = 0; hlf_T attr = HLF_COUNT; - size_t len; bool has_syntax = syntax_present(wp); - colnr_T col; char *buf = NULL; size_t buflen = 0; int skip = 0; @@ -1309,10 +1309,6 @@ size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *a bool found_one = false; bool wrapped = false; - if (no_spell_checking(wp)) { - return 0; - } - size_t ret = 0; // Start looking for bad word at the start of the line, because we can't @@ -1342,7 +1338,7 @@ size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *a while (!got_int) { char *line = ml_get_buf(wp->w_buffer, lnum); - len = (size_t)ml_get_buf_len(wp->w_buffer, lnum); + size_t len = (size_t)ml_get_buf_len(wp->w_buffer, lnum); if (buflen < len + MAXWLEN + 2) { xfree(buf); buflen = len + MAXWLEN + 2; @@ -1360,7 +1356,7 @@ size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *a capcol = (colnr_T)getwhitecols(line); } else if (curline && wp == curwin) { // For spellbadword(): check if first word needs a capital. - col = (colnr_T)getwhitecols(line); + colnr_T col = (colnr_T)getwhitecols(line); if (check_need_cap(curwin, lnum, col)) { capcol = col; } @@ -1409,7 +1405,7 @@ size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *a || ((colnr_T)(curline ? p - buf + (ptrdiff_t)len : p - buf) > wp->w_cursor.col)) { - col = (colnr_T)(p - buf); + colnr_T col = (colnr_T)(p - buf); bool no_plain_buffer = (wp->w_s->b_p_spo_flags & SPO_NPBUFFER) != 0; bool can_spell = !no_plain_buffer; @@ -1816,17 +1812,16 @@ void count_common_word(slang_T *lp, char *word, int len, uint8_t count) p = buf; } - wordcount_T *wc; hash_T hash = hash_hash(p); const size_t p_len = strlen(p); hashitem_T *hi = hash_lookup(&lp->sl_wordcount, p, p_len, hash); if (HASHITEM_EMPTY(hi)) { - wc = xmalloc(offsetof(wordcount_T, wc_word) + p_len + 1); + wordcount_T *wc = xmalloc(offsetof(wordcount_T, wc_word) + p_len + 1); memcpy(wc->wc_word, p, p_len + 1); wc->wc_count = count; hash_add_item(&lp->sl_wordcount, hi, wc->wc_word, hash); } else { - wc = HI2WC(hi); + wordcount_T *wc = HI2WC(hi); wc->wc_count = (uint16_t)(wc->wc_count + count); if (wc->wc_count < count) { // check for overflow wc->wc_count = MAXWORDCOUNT; @@ -1882,14 +1877,14 @@ int init_syl_tab(slang_T *slang) static int count_syllables(slang_T *slang, const char *word) FUNC_ATTR_NONNULL_ALL { - int cnt = 0; - bool skip = false; - int len; - if (slang->sl_syllable == NULL) { return 0; } + int cnt = 0; + bool skip = false; + int len; + for (const char *p = word; *p != NUL; p += len) { // When running into a space reset counter. if (*p == ' ') { @@ -1929,25 +1924,14 @@ static int count_syllables(slang_T *slang, const char *word) /// @return NULL if it's OK, an untranslated error message otherwise. char *parse_spelllang(win_T *wp) { - garray_T ga; - char *splp; - char *region; char region_cp[3]; - bool filename; - int region_mask; - slang_T *slang; - int c; char lang[MAXWLEN + 1]; char spf_name[MAXPATHL]; - char *p; - int round; - char *spf; char *use_region = NULL; bool dont_use_region = false; bool nobreak = false; static bool recursive = false; char *ret_msg = NULL; - char *spl_copy; bufref_T bufref; set_bufref(&bufref, wp->w_buffer); @@ -1960,20 +1944,21 @@ char *parse_spelllang(win_T *wp) } recursive = true; + garray_T ga; ga_init(&ga, sizeof(langp_T), 2); clear_midword(wp); // Make a copy of 'spelllang', the SpellFileMissing autocommands may change // it under our fingers. - spl_copy = xstrdup(wp->w_s->b_p_spl); + char *spl_copy = xstrdup(wp->w_s->b_p_spl); wp->w_s->b_cjk = 0; // Loop over comma separated language names. - for (splp = spl_copy; *splp != NUL;) { + for (char *splp = spl_copy; *splp != NUL;) { // Get one language name. copy_option_part(&splp, lang, MAXWLEN, ","); - region = NULL; + char *region = NULL; int len = (int)strlen(lang); if (!valid_spelllang(lang)) { @@ -1985,6 +1970,8 @@ char *parse_spelllang(win_T *wp) continue; } + slang_T *slang; + bool filename; // If the name ends in ".spl" use it as the name of the spell file. // If there is a region name let "region" point to it and remove it // from the name. @@ -1992,7 +1979,7 @@ char *parse_spelllang(win_T *wp) filename = true; // Locate a region and remove it from the file name. - p = vim_strchr(path_tail(lang), '_'); + char *p = vim_strchr(path_tail(lang), '_'); if (p != NULL && ASCII_ISALPHA(p[1]) && ASCII_ISALPHA(p[2]) && !ASCII_ISALPHA(p[3])) { xstrlcpy(region_cp, p + 1, 3); @@ -2055,10 +2042,10 @@ char *parse_spelllang(win_T *wp) if (filename ? path_full_compare(lang, slang->sl_fname, false, true) == kEqualFiles : STRICMP(lang, slang->sl_name) == 0) { - region_mask = REGION_ALL; + int region_mask = REGION_ALL; if (!filename && region != NULL) { // find region in sl_regions - c = find_region(slang->sl_regions, region); + int c = find_region(slang->sl_regions, region); if (c == REGION_ALL) { if (slang->sl_add) { if (*slang->sl_regions != NUL) { @@ -2094,8 +2081,8 @@ char *parse_spelllang(win_T *wp) // round 1: load first name in 'spellfile'. // round 2: load second name in 'spellfile. // etc. - spf = curwin->w_s->b_p_spf; - for (round = 0; round == 0 || *spf != NUL; round++) { + char *spf = curwin->w_s->b_p_spf; + for (int round = 0; round == 0 || *spf != NUL; round++) { if (round == 0) { // Internal wordlist, if there is one. if (int_wordlist == NULL) { @@ -2105,11 +2092,12 @@ char *parse_spelllang(win_T *wp) } else { // One entry in 'spellfile'. copy_option_part(&spf, spf_name, MAXPATHL - 5, ","); - STRCAT(spf_name, ".spl"); + strcat(spf_name, ".spl"); + int c; // If it was already found above then skip it. for (c = 0; c < ga.ga_len; c++) { - p = LANGP_ENTRY(ga, c)->lp_slang->sl_fname; + char *p = LANGP_ENTRY(ga, c)->lp_slang->sl_fname; if (p != NULL && path_full_compare(spf_name, p, false, true) == kEqualFiles) { break; @@ -2120,6 +2108,8 @@ char *parse_spelllang(win_T *wp) } } + slang_T *slang; + // Check if it was loaded already. for (slang = first_lang; slang != NULL; slang = slang->sl_next) { if (path_full_compare(spf_name, slang->sl_fname, false, true) @@ -2135,7 +2125,7 @@ char *parse_spelllang(win_T *wp) STRCPY(lang, "internal wordlist"); } else { xstrlcpy(lang, path_tail(spf_name), MAXWLEN + 1); - p = vim_strchr(lang, '.'); + char *p = vim_strchr(lang, '.'); if (p != NULL) { *p = NUL; // truncate at ".encoding.add" } @@ -2149,10 +2139,10 @@ char *parse_spelllang(win_T *wp) } } if (slang != NULL) { - region_mask = REGION_ALL; + int region_mask = REGION_ALL; if (use_region != NULL && !dont_use_region) { // find region in sl_regions - c = find_region(slang->sl_regions, use_region); + int c = find_region(slang->sl_regions, use_region); if (c != REGION_ALL) { region_mask = 1 << c; } else if (*slang->sl_regions != NUL) { @@ -2687,7 +2677,7 @@ void ex_spellrepall(exarg_T *eap) char *p = xmalloc((size_t)get_cursor_line_len() + (size_t)addlen + 1); memmove(p, line, (size_t)curwin->w_cursor.col); STRCPY(p + curwin->w_cursor.col, repl_to); - STRCAT(p, line + curwin->w_cursor.col + repl_from_len); + strcat(p, line + curwin->w_cursor.col + repl_from_len); ml_replace(curwin->w_cursor.lnum, p, false); inserted_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col, (int)repl_from_len, (int)repl_to_len); @@ -2902,19 +2892,7 @@ static void spell_soundfold_sofo(slang_T *slang, const char *inword, char *res) // Multi-byte version of spell_soundfold(). static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) { - salitem_T *smp = (salitem_T *)slang->sl_sal.ga_data; int word[MAXWLEN] = { 0 }; - int wres[MAXWLEN] = { 0 }; - int *ws; - int *pf; - int j, z; - int reslen; - int k = 0; - int k0; - int n0; - int pri; - int p0 = -333; - int c0; bool did_white = false; // Convert the multi-byte string to a wide-character string. @@ -2942,17 +2920,24 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) } word[wordlen] = NUL; + salitem_T *smp = (salitem_T *)slang->sl_sal.ga_data; + int wres[MAXWLEN] = { 0 }; + int k = 0; + int p0 = -333; int c; // This algorithm comes from Aspell phonet.cpp. // Converted from C++ to C. Added support for multi-byte chars. // Changed to keep spaces. - int i = reslen = z = 0; + int i = 0; + int reslen = 0; + int z = 0; 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]; int z0 = 0; if (n >= 0) { + int *ws; // Check all rules for the same index byte. // If c is 0x300 need extra check for the end of the array, as // (c & 0xff) is NUL. @@ -2969,6 +2954,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) continue; } if (k > 2) { + int j; for (j = 2; j < k; j++) { if (word[i + j] != ws[j]) { break; @@ -2980,6 +2966,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) } } + int *pf; if ((pf = smp[n].sm_oneof_w) != NULL) { // Check for match with one of the chars in "sm_oneof". while (*pf != NUL && *pf != word[i + k]) { @@ -2991,10 +2978,10 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) k++; } char *s = smp[n].sm_rules; - pri = 5; // default priority + int pri = 5; // default priority p0 = (uint8_t)(*s); - k0 = k; + int k0 = k; while (*s == '-' && k > 1) { k--; s++; @@ -3022,8 +3009,8 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) && (!spell_iswordp_w(word + i + k0, curwin)))) { // search for followup rules, if: // followup and k > 1 and NO '-' in searchstring - c0 = word[i + k - 1]; - n0 = slang->sl_sal_first[c0 & 0xff]; + int c0 = word[i + k - 1]; + int n0 = slang->sl_sal_first[c0 & 0xff]; if (slang->sl_followup && k > 1 && n0 >= 0 && p0 != '-' && word[i + k] != NUL) { @@ -3042,6 +3029,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) } if (k0 > 2) { pf = word + i + k + 1; + int j; for (j = 2; j < k0; j++) { if (*pf++ != ws[j]) { break; @@ -3262,23 +3250,13 @@ void ex_spelldump(exarg_T *eap) /// @param dumpflags_arg DUMPFLAG_* void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) { - langp_T *lp; - slang_T *slang; idx_T arridx[MAXWLEN]; int curi[MAXWLEN]; char word[MAXWLEN]; - int c; - uint8_t *byts; - idx_T *idxs; linenr_T lnum = 0; - int depth; - int n; - int flags; char *region_names = NULL; // region names being used bool do_region = true; // dump region names and numbers - char *p; int dumpflags = dumpflags_arg; - int patlen; // When ignoring case or when the pattern starts with capital pass this on // to dump_word(). @@ -3286,7 +3264,7 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) if (ic) { dumpflags |= DUMPFLAG_ICASE; } else { - n = captype(pat, NULL); + int n = captype(pat, NULL); if (n == WF_ONECAP) { dumpflags |= DUMPFLAG_ONECAP; } else if (n == WF_ALLCAP @@ -3299,8 +3277,8 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) // Find out if we can support regions: All languages must support the same // regions or none at all. for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; lpi++) { - lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi); - p = lp->lp_slang->sl_regions; + langp_T *lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi); + char *p = lp->lp_slang->sl_regions; if (p[0] != 0) { if (region_names == NULL) { // first language with regions region_names = p; @@ -3320,8 +3298,8 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) // Loop over all files loaded for the entries in 'spelllang'. for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; lpi++) { - lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi); - slang = lp->lp_slang; + langp_T *lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi); + slang_T *slang = lp->lp_slang; if (slang->sl_fbyts == NULL) { // reloading failed continue; } @@ -3331,6 +3309,7 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) ml_append(lnum++, IObuff, 0, false); } + int patlen; // When matching with a pattern and there are no prefixes only use // parts of the tree that match "pat". if (pat != NULL && slang->sl_pbyts == NULL) { @@ -3342,6 +3321,8 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) // round 1: case-folded tree // round 2: keep-case tree for (int round = 1; round <= 2; round++) { + uint8_t *byts; + idx_T *idxs; if (round == 1) { dumpflags &= ~DUMPFLAG_KEEPCASE; byts = slang->sl_fbyts; @@ -3354,7 +3335,7 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) if (byts == NULL) { continue; // array is empty } - depth = 0; + int depth = 0; arridx[0] = 0; curi[0] = 1; while (depth >= 0 && !got_int @@ -3366,16 +3347,16 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) ins_compl_check_keys(50, false); } else { // Do one more byte at this node. - n = arridx[depth] + curi[depth]; + int n = arridx[depth] + curi[depth]; curi[depth]++; - c = byts[n]; + int c = byts[n]; if (c == 0 || depth >= MAXWLEN - 1) { // End of word or reached maximum length, deal with the // word. // Don't use keep-case words in the fold-case tree, // they will appear in the keep-case tree. // Only use the word when the region matches. - flags = (int)idxs[n]; + int flags = (int)idxs[n]; if ((round == 2 || (flags & WF_KEEPCAP) == 0) && (flags & WF_NEEDCOMP) == 0 && (do_region @@ -3463,14 +3444,14 @@ static void dump_word(slang_T *slang, char *word, char *pat, Direction *dir, int // Add flags and regions after a slash. if ((flags & (WF_BANNED | WF_RARE | WF_REGION)) || keepcap) { STRCPY(badword, p); - STRCAT(badword, "/"); + strcat(badword, "/"); if (keepcap) { - STRCAT(badword, "="); + strcat(badword, "="); } if (flags & WF_BANNED) { - STRCAT(badword, "!"); + strcat(badword, "!"); } else if (flags & WF_RARE) { - STRCAT(badword, "?"); + strcat(badword, "?"); } if (flags & WF_REGION) { for (int i = 0; i < 7; i++) { diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index 046a0a56e5..ae8c243486 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -240,6 +240,7 @@ #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/ex_cmds_defs.h" #include "nvim/fileio.h" #include "nvim/garray.h" @@ -2139,11 +2140,11 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname) + strlen(items[1]) + 3, false); if (spin->si_info != NULL) { STRCPY(p, spin->si_info); - STRCAT(p, "\n"); + strcat(p, "\n"); } - STRCAT(p, items[0]); - STRCAT(p, " "); - STRCAT(p, items[1]); + strcat(p, items[0]); + strcat(p, " "); + strcat(p, items[1]); spin->si_info = p; } else if (is_aff_rule(items, itemcnt, "MIDWORD", 2) && midword == NULL) { midword = getroom_save(spin, items[1]); @@ -2199,7 +2200,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname) // "Na" into "Na+", "1234" into "1234+". p = getroom(spin, strlen(items[1]) + 2, false); STRCPY(p, items[1]); - STRCAT(p, "+"); + strcat(p, "+"); compflags = p; } else if (is_aff_rule(items, itemcnt, "COMPOUNDRULES", 2)) { // We don't use the count, but do check that it's a number and @@ -2220,9 +2221,9 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname) p = getroom(spin, (size_t)l, false); if (compflags != NULL) { STRCPY(p, compflags); - STRCAT(p, "/"); + strcat(p, "/"); } - STRCAT(p, items[1]); + strcat(p, items[1]); compflags = p; } } else if (is_aff_rule(items, itemcnt, "COMPOUNDWORDMAX", 2) @@ -2843,7 +2844,7 @@ static void process_compflags(spellinfo_T *spin, afffile_T *aff, char *compflags char *p = getroom(spin, (size_t)len, false); if (spin->si_compflags != NULL) { STRCPY(p, spin->si_compflags); - STRCAT(p, "/"); + strcat(p, "/"); } spin->si_compflags = p; uint8_t *tp = (uint8_t *)p + strlen(p); @@ -3385,7 +3386,7 @@ static int store_aff_word(spellinfo_T *spin, char *word, char *afflist, afffile_ MB_PTR_ADV(p); } } - STRCAT(newword, p); + strcat(newword, p); } else { // suffix: chop/add at the end of the word xstrlcpy(newword, word, MAXWLEN); @@ -3399,7 +3400,7 @@ static int store_aff_word(spellinfo_T *spin, char *word, char *afflist, afffile_ *p = NUL; } if (ae->ae_add != NULL) { - STRCAT(newword, ae->ae_add); + strcat(newword, ae->ae_add); } } @@ -4104,8 +4105,8 @@ static void wordtree_compress(spellinfo_T *spin, wordnode_T *root, const char *n perc = (tot - n) * 100 / tot; } vim_snprintf(IObuff, IOSIZE, - _("Compressed %s of %d nodes; %d (%ld%%) remaining"), - name, tot, tot - n, perc); + _("Compressed %s: %d of %d nodes; %d (%ld%%) remaining"), + name, n, tot, tot - n, perc); spell_message(spin, IObuff); } #ifdef SPELL_PRINTTREE diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c index a7de20d14e..b37f01e769 100644 --- a/src/nvim/spellsuggest.c +++ b/src/nvim/spellsuggest.c @@ -14,6 +14,7 @@ #include "nvim/change.h" #include "nvim/charset.h" #include "nvim/cursor.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -275,7 +276,6 @@ static bool can_be_compound(trystate_T *sp, slang_T *slang, uint8_t *compflags, static int score_wordcount_adj(slang_T *slang, int score, char *word, bool split) { int bonus; - int newscore; hashitem_T *hi = hash_find(&slang->sl_wordcount, word); if (HASHITEM_EMPTY(hi)) { @@ -290,11 +290,8 @@ static int score_wordcount_adj(slang_T *slang, int score, char *word, bool split } else { bonus = SCORE_COMMON3; } - if (split) { - newscore = score - bonus / 2; - } else { - newscore = score - bonus; - } + int newscore = split ? score - bonus / 2 + : score - bonus; if (newscore < 0) { return 0; } @@ -448,7 +445,6 @@ void spell_suggest(int count) suginfo_T sug; suggest_T *stp; bool mouse_used; - int limit; int selected = count; int badlen = 0; int msg_scroll_save = msg_scroll; @@ -480,9 +476,7 @@ void spell_suggest(int count) badlen++; end_visual_mode(); // make sure we don't include the NUL at the end of the line - if (badlen > get_cursor_line_len() - curwin->w_cursor.col) { - badlen = get_cursor_line_len() - curwin->w_cursor.col; - } + badlen = MIN(badlen, get_cursor_line_len() - curwin->w_cursor.col); // Find the start of the badly spelled word. } else if (spell_move_to(curwin, FORWARD, SMT_ALL, true, NULL) == 0 || curwin->w_cursor.col > prev_cursor.col) { @@ -518,11 +512,7 @@ void spell_suggest(int count) // Get the list of suggestions. Limit to 'lines' - 2 or the number in // 'spellsuggest', whatever is smaller. - if (sps_limit > Rows - 2) { - limit = Rows - 2; - } else { - limit = sps_limit; - } + int limit = MIN(sps_limit, Rows - 2); spell_find_suggest(line + curwin->w_cursor.col, badlen, &sug, limit, true, need_cap, true); @@ -642,7 +632,7 @@ void spell_suggest(int count) 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); + strcat(p, sug.su_badptr + stp->st_orglen); // For redo we use a change-word command. ResetRedobuff(); @@ -730,10 +720,7 @@ static void spell_find_suggest(char *badptr, int badlen, suginfo_T *su, int maxc } su->su_maxcount = maxcount; su->su_maxscore = SCORE_MAXINIT; - - if (su->su_badlen >= MAXWLEN) { - su->su_badlen = MAXWLEN - 1; // just in case - } + su->su_badlen = MIN(su->su_badlen, MAXWLEN - 1); // just in case xmemcpyz(su->su_badword, su->su_badptr, (size_t)su->su_badlen); spell_casefold(curwin, su->su_badptr, su->su_badlen, su->su_fbadword, MAXWLEN); @@ -1144,7 +1131,6 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun idx_T *idxs, *fidxs, *pidxs; int c, c2, c3; int n = 0; - garray_T *gap; idx_T arridx; int fl = 0; int tl; @@ -1637,7 +1623,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun // Append a space to preword when splitting. if (!try_compound && !fword_ends) { - STRCAT(preword, " "); + strcat(preword, " "); } sp->ts_prewordlen = (uint8_t)strlen(preword); sp->ts_splitoff = sp->ts_twordlen; @@ -1735,11 +1721,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun // Done all bytes at this node, do next state. When still at // already changed bytes skip the other tricks. PROF_STORE(sp->ts_state) - if (sp->ts_fidx >= sp->ts_fidxtry) { - sp->ts_state = STATE_DEL; - } else { - sp->ts_state = STATE_FINAL; - } + sp->ts_state = sp->ts_fidx >= sp->ts_fidxtry ? STATE_DEL + : STATE_FINAL; } else { arridx += sp->ts_curi++; c = byts[arridx]; @@ -1809,10 +1792,8 @@ 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(tword + sp->ts_twordlen - - sp->ts_tcharlen)) - && utf_iscomposing(utf_ptr2char(fword - + sp->ts_fcharstart))) { + if (utf_iscomposing_legacy(utf_ptr2char(tword + sp->ts_twordlen - sp->ts_tcharlen)) + && utf_iscomposing_legacy(utf_ptr2char(fword + sp->ts_fcharstart))) { sp->ts_score -= SCORE_SUBST - SCORE_SUBCOMP; } else if (!soundfold && slang->sl_has_map @@ -1828,7 +1809,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun && sp->ts_twordlen > sp->ts_tcharlen) { p = tword + sp->ts_twordlen - sp->ts_tcharlen; c = utf_ptr2char(p); - if (utf_iscomposing(c)) { + if (utf_iscomposing_legacy(c)) { // Inserting a composing char doesn't // count that much. sp->ts_score -= SCORE_INS - SCORE_INSCOMP; @@ -1893,7 +1874,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun c = utf_ptr2char(fword + sp->ts_fidx); stack[depth].ts_fidx = (uint8_t)(stack[depth].ts_fidx + utfc_ptr2len(fword + sp->ts_fidx)); - if (utf_iscomposing(c)) { + if (utf_iscomposing_legacy(c)) { stack[depth].ts_score -= SCORE_DEL - SCORE_DELCOMP; } else if (c == utf_ptr2char(fword + stack[depth].ts_fidx)) { stack[depth].ts_score -= SCORE_DEL - SCORE_DELDUP; @@ -2253,11 +2234,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun // valid. p = fword + sp->ts_fidx; - if (soundfold) { - gap = &slang->sl_repsal; - } else { - gap = &lp->lp_replang->sl_rep; - } + garray_T *gap = soundfold ? &slang->sl_repsal + : &lp->lp_replang->sl_rep; while (sp->ts_curi < gap->ga_len) { fromto_T *ftp = (fromto_T *)gap->ga_data + sp->ts_curi++; if (*ftp->ft_from != *p) { @@ -3125,11 +3103,9 @@ static void add_suggestion(suginfo_T *su, garray_T *gap, const char *goodword, i // the best suggestions. if (gap->ga_len > SUG_MAX_COUNT(su)) { if (maxsf) { - su->su_sfmaxscore = cleanup_suggestions(gap, - su->su_sfmaxscore, SUG_CLEAN_COUNT(su)); + su->su_sfmaxscore = cleanup_suggestions(gap, su->su_sfmaxscore, SUG_CLEAN_COUNT(su)); } else { - su->su_maxscore = cleanup_suggestions(gap, - su->su_maxscore, SUG_CLEAN_COUNT(su)); + su->su_maxscore = cleanup_suggestions(gap, su->su_maxscore, SUG_CLEAN_COUNT(su)); } } } @@ -3275,8 +3251,6 @@ static int soundalike_score(char *goodstart, char *badstart) { char *goodsound = goodstart; char *badsound = badstart; - char *pl, *ps; - char *pl2, *ps2; int score = 0; // Adding/inserting "*" at the start (word starts with vowel) shouldn't be @@ -3317,13 +3291,10 @@ static int soundalike_score(char *goodstart, char *badstart) return SCORE_MAXMAX; } - if (n > 0) { - pl = goodsound; // goodsound is longest - ps = badsound; - } else { - pl = badsound; // badsound is longest - ps = goodsound; - } + // n > 0 : goodsound is longest + // n <= 0 : badsound is longest + char *pl = n > 0 ? goodsound : badsound; + char *ps = n > 0 ? badsound : goodsound; // Skip over the identical part. while (*pl == *ps && *pl != NUL) { @@ -3331,6 +3302,8 @@ static int soundalike_score(char *goodstart, char *badstart) ps++; } + char *pl2, *ps2; + switch (n) { case -2: case 2: @@ -3551,19 +3524,13 @@ static int spell_edit_score(slang_T *slang, const char *badword, const char *goo int pgc = wgoodword[j - 2]; if (bc == pgc && pbc == gc) { int t = SCORE_SWAP + CNT(i - 2, j - 2); - if (t < CNT(i, j)) { - CNT(i, j) = t; - } + CNT(i, j) = MIN(CNT(i, j), t); } } int t = SCORE_DEL + CNT(i - 1, j); - if (t < CNT(i, j)) { - CNT(i, j) = t; - } + CNT(i, j) = MIN(CNT(i, j), t); t = SCORE_INS + CNT(i, j - 1); - if (t < CNT(i, j)) { - CNT(i, j) = t; - } + CNT(i, j) = MIN(CNT(i, j), t); } } } diff --git a/src/nvim/state.c b/src/nvim/state.c index 993db255de..908f724792 100644 --- a/src/nvim/state.c +++ b/src/nvim/state.c @@ -66,18 +66,19 @@ getkey: // Event was made available after the last multiqueue_process_events call key = K_EVENT; } else { - // Duplicate display updating logic in vgetorpeek() - if (((State & MODE_INSERT) != 0 || p_lz) && (State & MODE_CMDLINE) == 0 - && must_redraw != 0 && !need_wait_return) { + // Ensure the screen is fully updated before blocking for input. Because of the duality of + // redraw_later, this can't be done in command-line or when waiting for "Press ENTER". + // In many of those cases the redraw is expected AFTER the key press, while normally it should + // update the screen immediately. + if (must_redraw != 0 && !need_wait_return && (State & MODE_CMDLINE) == 0) { update_screen(); setcursor(); // put cursor back where it belongs } // Flush screen updates before blocking. ui_flush(); - // Call `os_inchar` directly to block for events or user input without - // consuming anything from `input_buffer`(os/input.c) or calling the - // mapping engine. - os_inchar(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events); + // Call `input_get` directly to block for events or user input without consuming anything from + // `os/input.c:input_buffer` or calling the mapping engine. + input_get(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events); // If an event was put into the queue, we send K_EVENT directly. if (!input_available() && !multiqueue_empty(main_loop.events)) { key = K_EVENT; @@ -177,17 +178,8 @@ void get_mode(char *buf) { int i = 0; - if (VIsual_active) { - if (VIsual_select) { - buf[i++] = (char)(VIsual_mode + 's' - 'v'); - } else { - buf[i++] = (char)VIsual_mode; - if (restart_VIsual_select) { - buf[i++] = 's'; - } - } - } else if (State == MODE_HITRETURN || State == MODE_ASKMORE || State == MODE_SETWSIZE - || State == MODE_CONFIRM) { + if (State == MODE_HITRETURN || State == MODE_ASKMORE + || State == MODE_SETWSIZE || State == MODE_CONFIRM) { buf[i++] = 'r'; if (State == MODE_ASKMORE) { buf[i++] = 'm'; @@ -222,6 +214,15 @@ void get_mode(char *buf) } } else if (State & MODE_TERMINAL) { buf[i++] = 't'; + } else if (VIsual_active) { + if (VIsual_select) { + buf[i++] = (char)(VIsual_mode + 's' - 'v'); + } else { + buf[i++] = (char)VIsual_mode; + if (restart_VIsual_select) { + buf[i++] = 's'; + } + } } else { buf[i++] = 'n'; if (finish_op) { @@ -233,8 +234,7 @@ void get_mode(char *buf) if (restart_edit == 'I') { buf[i++] = 'T'; } - } else if (restart_edit == 'I' || restart_edit == 'R' - || restart_edit == 'V') { + } else if (restart_edit == 'I' || restart_edit == 'R' || restart_edit == 'V') { buf[i++] = 'i'; buf[i++] = (char)restart_edit; } diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c index ca7083a9e3..07bb7dd69a 100644 --- a/src/nvim/statusline.c +++ b/src/nvim/statusline.c @@ -123,10 +123,7 @@ void win_redr_status(win_T *wp) // len += (int)strlen(p + len); // dead assignment } - int this_ru_col = ru_col - (Columns - stl_width); - if (this_ru_col < (stl_width + 1) / 2) { - this_ru_col = (stl_width + 1) / 2; - } + int this_ru_col = MAX(ru_col - (Columns - stl_width), (stl_width + 1) / 2); if (this_ru_col <= 1) { p = "<"; // No room for file name! len = 1; @@ -374,10 +371,7 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler) stl = p_ruf; } } - col = ru_col - (Columns - maxwidth); - if (col < (maxwidth + 1) / 2) { - col = (maxwidth + 1) / 2; - } + col = MAX(ru_col - (Columns - maxwidth), (maxwidth + 1) / 2); maxwidth -= col; if (!in_status_line) { grid = &msg_grid_adj; @@ -574,15 +568,9 @@ void win_redr_ruler(win_T *wp) if (wp->w_status_height == 0 && !is_stl_global) { // can't use last char of screen o++; } - int this_ru_col = ru_col - (Columns - width); - if (this_ru_col < 0) { - this_ru_col = 0; - } // Never use more than half the window/screen width, leave the other half // for the filename. - if (this_ru_col < (width + 1) / 2) { - this_ru_col = (width + 1) / 2; - } + int this_ru_col = MAX(ru_col - (Columns - width), (width + 1) / 2); if (this_ru_col + o < width) { // Need at least 3 chars left for get_rel_pos() + NUL. while (this_ru_col + o < width && RULER_BUF_LEN > i + 4) { @@ -660,14 +648,14 @@ static void ui_ext_tabline_update(void) Array tabs = arena_array(&arena, n_tabs); FOR_ALL_TABS(tp) { - Dictionary tab_info = arena_dict(&arena, 2); + Dict tab_info = arena_dict(&arena, 2); PUT_C(tab_info, "tab", TABPAGE_OBJ(tp->handle)); win_T *cwp = (tp == curtab) ? curwin : tp->tp_curwin; get_trans_bufname(cwp->w_buffer); PUT_C(tab_info, "name", CSTR_TO_ARENA_OBJ(&arena, NameBuff)); - ADD_C(tabs, DICTIONARY_OBJ(tab_info)); + ADD_C(tabs, DICT_OBJ(tab_info)); } size_t n_buffers = 0; @@ -682,13 +670,13 @@ static void ui_ext_tabline_update(void) continue; } - Dictionary buffer_info = arena_dict(&arena, 2); + Dict buffer_info = arena_dict(&arena, 2); PUT_C(buffer_info, "buffer", BUFFER_OBJ(buf->handle)); get_trans_bufname(buf); PUT_C(buffer_info, "name", CSTR_TO_ARENA_OBJ(&arena, NameBuff)); - ADD_C(buffers, DICTIONARY_OBJ(buffer_info)); + ADD_C(buffers, DICT_OBJ(buffer_info)); } ui_call_tabline_update(curtab->handle, tabs, curbuf->handle, buffers); @@ -726,7 +714,6 @@ void draw_tabline(void) win_redr_custom(NULL, false, false); } else { int tabcount = 0; - int tabwidth = 0; int col = 0; win_T *cwp; int wincount; @@ -735,13 +722,7 @@ void draw_tabline(void) tabcount++; } - if (tabcount > 0) { - tabwidth = (Columns - 1 + tabcount / 2) / tabcount; - } - - if (tabwidth < 6) { - tabwidth = 6; - } + int tabwidth = MAX(tabcount > 0 ? (Columns - 1 + tabcount / 2) / tabcount : 0, 6); int attr = attr_nosel; tabcount = 0; @@ -810,9 +791,7 @@ void draw_tabline(void) len -= ptr2cells(p); MB_PTR_ADV(p); } - if (len > Columns - col - 1) { - len = Columns - col - 1; - } + len = MIN(len, Columns - col - 1); grid_line_puts(col, p, -1, attr); col += len; @@ -831,6 +810,16 @@ void draw_tabline(void) } } + for (int scol = col; scol < Columns; scol++) { + // Use 0 as tabpage number here, so that double-click opens a tabpage + // after the last one, and single-click goes to the next tabpage. + tab_page_click_defs[scol] = (StlClickDefinition) { + .type = kStlClickTabSwitch, + .tabnr = 0, + .func = NULL, + }; + } + char c = use_sep_chars ? '_' : ' '; grid_line_fill(col, Columns, schar_from_ascii(c), attr_fill); @@ -975,7 +964,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op }; set_var(S_LEN("g:statusline_winid"), &tv, false); - usefmt = eval_to_string_safe(fmt + 2, use_sandbox); + usefmt = eval_to_string_safe(fmt + 2, use_sandbox, false); if (usefmt == NULL) { usefmt = fmt; } @@ -1017,7 +1006,6 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op int evaldepth = 0; int curitem = 0; - int foldsignitem = -1; bool prevchar_isflag = true; bool prevchar_isitem = false; @@ -1194,9 +1182,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op // If the item was partially or completely truncated, set its // start to the start of the group - if (stl_items[idx].start < t) { - stl_items[idx].start = t; - } + stl_items[idx].start = MAX(stl_items[idx].start, t); } // If the group is shorter than the minimum width, add padding characters. } else if (abs(stl_items[stl_groupitems[groupdepth]].minwid) > group_len) { @@ -1234,6 +1220,8 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op } int minwid = 0; int maxwid = 9999; + int foldsignitem = -1; // Start of fold or sign item + bool left_align_num = false; // Number item for should be left-aligned bool left_align = false; // Denotes that numbers should be left-padded with zeros @@ -1268,24 +1256,17 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op // TABPAGE pairs are used to denote a region that when clicked will // either switch to or close a tab. // - // Ex: tabline=%0Ttab\ zero%X - // This tabline has a TABPAGENR item with minwid `0`, + // Ex: tabline=%1Ttab\ one%X + // This tabline has a TABPAGENR item with minwid `1`, // which is then closed with a TABCLOSENR item. - // Clicking on this region with mouse enabled will switch to tab 0. + // Clicking on this region with mouse enabled will switch to tab 1. // Setting the minwid to a different value will switch // to that tab, if it exists // // Ex: tabline=%1Xtab\ one%X // This tabline has a TABCLOSENR item with minwid `1`, // which is then closed with a TABCLOSENR item. - // Clicking on this region with mouse enabled will close tab 0. - // This is determined by the following formula: - // tab to close = (1 - minwid) - // This is because for TABPAGENR we use `minwid` = `tab number`. - // For TABCLOSENR we store the tab number as a negative value. - // Because 0 is a valid TABPAGENR value, we have to - // start our numbering at `-1`. - // So, `-1` corresponds to us wanting to close tab `0` + // Clicking on this region with mouse enabled will close tab 1. // // Note: These options are only valid when creating a tabline. if (*fmt_p == STL_TABPAGENR || *fmt_p == STL_TABCLOSENR) { @@ -1451,7 +1432,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op } // Note: The result stored in `t` is unused. - str = eval_to_string_safe(out_p, use_sandbox); + str = eval_to_string_safe(out_p, use_sandbox, false); curwin = save_curwin; curbuf = save_curbuf; @@ -1505,12 +1486,20 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op } case STL_LINE: - // Overload %l with v:lnum for 'statuscolumn' - if (stcp != NULL) { - if (wp->w_p_nu && !get_vim_var_nr(VV_VIRTNUM)) { - num = (int)get_vim_var_nr(VV_LNUM); + // Overload %l with v:(re)lnum for 'statuscolumn'. Place a sign when 'signcolumn' + // is set to "number". Take care of alignment for 'number' + 'relativenumber'. + if (stcp != NULL && (wp->w_p_nu || wp->w_p_rnu) && get_vim_var_nr(VV_VIRTNUM) == 0) { + if (wp->w_maxscwidth == SCL_NUM && stcp->sattrs[0].text[0]) { + goto stcsign; } - } else { + int relnum = (int)get_vim_var_nr(VV_RELNUM); + num = (!wp->w_p_rnu || (wp->w_p_nu && relnum == 0)) ? (int)get_vim_var_nr(VV_LNUM) : relnum; + left_align_num = wp->w_p_rnu && wp->w_p_nu && relnum == 0; + if (!left_align_num) { + stl_items[curitem].type = Separate; + stl_items[curitem++].start = out_p; + } + } else if (stcp == NULL) { num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) ? 0 : wp->w_cursor.lnum; } break; @@ -1609,16 +1598,9 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op case STL_ROFLAG: case STL_ROFLAG_ALT: - // Overload %r with v:relnum for 'statuscolumn' - if (stcp != NULL) { - if (wp->w_p_rnu && !get_vim_var_nr(VV_VIRTNUM)) { - num = (int)get_vim_var_nr(VV_RELNUM); - } - } else { - itemisflag = true; - if (wp->w_buffer->b_p_ro) { - str = (opt == STL_ROFLAG_ALT) ? ",RO" : _("[RO]"); - } + itemisflag = true; + if (wp->w_buffer->b_p_ro) { + str = (opt == STL_ROFLAG_ALT) ? ",RO" : _("[RO]"); } break; @@ -1632,21 +1614,20 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op case STL_FOLDCOL: // 'C' for 'statuscolumn' case STL_SIGNCOL: { // 's' for 'statuscolumn' +stcsign: if (stcp == NULL) { break; } - bool fold = opt == STL_FOLDCOL; - int fdc = fold ? compute_foldcolumn(wp, 0) : 0; - int width = fold ? fdc > 0 : wp->w_scwidth; + int fdc = opt == STL_FOLDCOL ? compute_foldcolumn(wp, 0) : 0; + int width = opt == STL_FOLDCOL ? fdc > 0 : opt == STL_SIGNCOL ? wp->w_scwidth : 1; if (width <= 0) { break; } foldsignitem = curitem; - char *p = NULL; - if (fold) { - schar_T fold_buf[10]; + if (fdc > 0) { + schar_T fold_buf[9]; fill_foldcolumn(wp, stcp->foldinfo, (linenr_T)get_vim_var_nr(VV_LNUM), 0, fdc, NULL, fold_buf); stl_items[curitem].minwid = -((stcp->use_cul ? HLF_CLF : HLF_FC) + 1); @@ -1654,31 +1635,26 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op // TODO(bfredl): this is very backwards. we must support schar_T // being used directly in 'statuscolumn' for (int i = 0; i < fdc; i++) { - buflen += schar_get(out_p + buflen, fold_buf[i]); + buflen += schar_get(buf_tmp + buflen, fold_buf[i]); } - p = out_p; } - char buf[SIGN_WIDTH * MAX_SCHAR_SIZE]; - size_t buflen = 0; - varnumber_T virtnum = get_vim_var_nr(VV_VIRTNUM); + size_t signlen = 0; for (int i = 0; i < width; i++) { - if (!fold) { - SignTextAttrs *sattr = virtnum ? NULL : &stcp->sattrs[i]; - p = " "; - if (sattr && sattr->text[0]) { - describe_sign_text(buf, sattr->text); - p = buf; + stl_items[curitem].start = out_p + signlen; + if (fdc == 0) { + if (stcp->sattrs[i].text[0] && get_vim_var_nr(VV_VIRTNUM) == 0) { + SignTextAttrs sattrs = stcp->sattrs[i]; + signlen += describe_sign_text(buf_tmp + signlen, sattrs.text); + stl_items[curitem].minwid = -(stcp->sign_cul_id ? stcp->sign_cul_id : sattrs.hl_id); + } else { + buf_tmp[signlen++] = ' '; + buf_tmp[signlen++] = ' '; + buf_tmp[signlen] = NUL; + stl_items[curitem].minwid = -((stcp->use_cul ? HLF_CLS : HLF_SC) + 1); } - stl_items[curitem].minwid = -(sattr && sattr->text[0] - ? (stcp->sign_cul_id ? stcp->sign_cul_id : sattr->hl_id) - : (stcp->use_cul ? HLF_CLS : HLF_SC) + 1); } - stl_items[curitem].type = Highlight; - stl_items[curitem].start = out_p + buflen; - xstrlcpy(buf_tmp + buflen, p, TMPLEN - buflen); - buflen += strlen(p); - curitem++; + stl_items[curitem++].type = Highlight; } str = buf_tmp; break; @@ -1851,7 +1827,6 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op // For a 'statuscolumn' sign or fold item, add an item to reset the highlight group if (foldsignitem >= 0) { - foldsignitem = -1; stl_items[curitem].type = Highlight; stl_items[curitem].start = out_p; stl_items[curitem].minwid = 0; @@ -1956,6 +1931,11 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op // Item processed, move to the next curitem++; + // For a 'statuscolumn' number item that is left aligned, add a separator item. + if (left_align_num) { + stl_items[curitem].type = Separate; + stl_items[curitem++].start = out_p; + } } *out_p = NUL; diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 16ae35272b..118abbae6d 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -12,6 +12,7 @@ #include "nvim/ascii_defs.h" #include "nvim/assert_defs.h" #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/eval/encode.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -268,9 +269,9 @@ char *vim_strsave_shellescape(const char *string, bool do_special, bool do_newli } if (do_special && find_cmdline_var(p, &l) >= 0) { *d++ = '\\'; // insert backslash - while (--l != SIZE_MAX) { // copy the var - *d++ = *p++; - } + memcpy(d, p, l); // copy the var + d += l; + p += l; continue; } if (*p == '\\' && fish_like) { @@ -332,7 +333,7 @@ void vim_strcpy_up(char *restrict dst, const char *restrict src) while ((c = (uint8_t)(*src++)) != NUL) { *dst++ = (char)(uint8_t)(c < 'a' || c > 'z' ? c : c - 0x20); } - *dst = '\0'; + *dst = NUL; } // strncpy (NUL-terminated) plus vim_strup. @@ -343,7 +344,7 @@ void vim_strncpy_up(char *restrict dst, const char *restrict src, size_t n) while (n-- && (c = (uint8_t)(*src++)) != NUL) { *dst++ = (char)(uint8_t)(c < 'a' || c > 'z' ? c : c - 0x20); } - *dst = '\0'; + *dst = NUL; } // memcpy (does not NUL-terminate) plus vim_strup. @@ -495,6 +496,20 @@ char *vim_strchr(const char *const string, const int c) } } +// Sized version of strchr that can handle embedded NULs. +// Adjusts n to the new size. +char *strnchr(const char *p, size_t *n, int c) +{ + while (*n > 0) { + if (*p == c) { + return (char *)p; + } + p++; + (*n)--; + } + return NULL; +} + // Sort an array of strings. static int sort_compare(const void *s1, const void *s2) @@ -628,12 +643,14 @@ static const void *tv_ptr(const typval_T *const tvs, int *const idxp) #define OFF(attr) offsetof(union typval_vval_union, attr) STATIC_ASSERT(OFF(v_string) == OFF(v_list) && OFF(v_string) == OFF(v_dict) + && OFF(v_string) == OFF(v_blob) && OFF(v_string) == OFF(v_partial) && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_list) && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_dict) + && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_blob) && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_partial), - "Strings, dictionaries, lists and partials are expected to be pointers, " - "so that all three of them can be accessed via v_string"); + "Strings, Dictionaries, Lists, Blobs and Partials are expected to be pointers, " + "so that all of them can be accessed via v_string"); #undef OFF const int idx = *idxp - 1; if (tvs[idx].v_type == VAR_UNKNOWN) { @@ -793,10 +810,10 @@ static int format_typeof(const char *type) FUNC_ATTR_NONNULL_ALL { // allowed values: \0, h, l, L - char length_modifier = '\0'; + char length_modifier = NUL; // current conversion specifier character - char fmt_spec = '\0'; + char fmt_spec = NUL; // parse 'h', 'l', 'll' and 'z' length modifiers if (*type == 'h' || *type == 'l' || *type == 'z') { @@ -864,7 +881,7 @@ static int format_typeof(const char *type) } else if (fmt_spec == 'd') { // signed switch (length_modifier) { - case '\0': + case NUL: case 'h': // char and short arguments are passed as int. return TYPE_INT; @@ -878,7 +895,7 @@ static int format_typeof(const char *type) } else { // unsigned switch (length_modifier) { - case '\0': + case NUL: case 'h': return TYPE_UNSIGNEDINT; case 'l': @@ -1002,7 +1019,7 @@ static void format_overflow_error(const char *pstart) enum { MAX_ALLOWED_STRING_WIDTH = 6400, }; -static int get_unsigned_int(const char *pstart, const char **p, unsigned *uj) +static int get_unsigned_int(const char *pstart, const char **p, unsigned *uj, bool overflow_err) { *uj = (unsigned)(**p - '0'); (*p)++; @@ -1013,8 +1030,12 @@ static int get_unsigned_int(const char *pstart, const char **p, unsigned *uj) } if (*uj > MAX_ALLOWED_STRING_WIDTH) { - format_overflow_error(pstart); - return FAIL; + if (overflow_err) { + format_overflow_error(pstart); + return FAIL; + } else { + *uj = MAX_ALLOWED_STRING_WIDTH; + } } return OK; @@ -1049,7 +1070,7 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char * p += n; } else { // allowed values: \0, h, l, L - char length_modifier = '\0'; + char length_modifier = NUL; // variable for positional arg int pos_arg = -1; @@ -1075,7 +1096,7 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char * // Positional argument unsigned uj; - if (get_unsigned_int(pstart, &p, &uj) == FAIL) { + if (get_unsigned_int(pstart, &p, &uj, tvs != NULL) == FAIL) { goto error; } @@ -1118,7 +1139,7 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char * // Positional argument field width unsigned uj; - if (get_unsigned_int(arg + 1, &p, &uj) == FAIL) { + if (get_unsigned_int(arg + 1, &p, &uj, tvs != NULL) == FAIL) { goto error; } @@ -1144,7 +1165,7 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char * const char *digstart = p; unsigned uj; - if (get_unsigned_int(digstart, &p, &uj) == FAIL) { + if (get_unsigned_int(digstart, &p, &uj, tvs != NULL) == FAIL) { goto error; } @@ -1165,7 +1186,7 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char * // Parse precision unsigned uj; - if (get_unsigned_int(arg + 1, &p, &uj) == FAIL) { + if (get_unsigned_int(arg + 1, &p, &uj, tvs != NULL) == FAIL) { goto error; } @@ -1192,7 +1213,7 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char * const char *digstart = p; unsigned uj; - if (get_unsigned_int(digstart, &p, &uj) == FAIL) { + if (get_unsigned_int(digstart, &p, &uj, tvs != NULL) == FAIL) { goto error; } @@ -1440,7 +1461,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st int space_for_positive = 1; // allowed values: \0, h, l, 2 (for ll), z, L - char length_modifier = '\0'; + char length_modifier = NUL; // temporary buffer for simple numeric->string conversion #define TMP_LEN 350 // 1e308 seems reasonable as the maximum printable @@ -1465,7 +1486,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st size_t zero_padding_insertion_ind = 0; // current conversion specifier character - char fmt_spec = '\0'; + char fmt_spec = NUL; // buffer for 's' and 'S' specs char *tofree = NULL; @@ -1488,7 +1509,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st const char *digstart = p; unsigned uj; - if (get_unsigned_int(digstart, &p, &uj) == FAIL) { + if (get_unsigned_int(digstart, &p, &uj, tvs != NULL) == FAIL) { goto error; } @@ -1530,7 +1551,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st // Positional argument field width unsigned uj; - if (get_unsigned_int(digstart, &p, &uj) == FAIL) { + if (get_unsigned_int(digstart, &p, &uj, tvs != NULL) == FAIL) { goto error; } @@ -1539,15 +1560,19 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st p++; } - const int j = (tvs - ? (int)tv_nr(tvs, &arg_idx) - : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, - &arg_cur, fmt), - va_arg(ap, int))); + int j = (tvs + ? (int)tv_nr(tvs, &arg_idx) + : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, + &arg_cur, fmt), + va_arg(ap, int))); if (j > MAX_ALLOWED_STRING_WIDTH) { - format_overflow_error(digstart); - goto error; + if (tvs != NULL) { + format_overflow_error(digstart); + goto error; + } else { + j = MAX_ALLOWED_STRING_WIDTH; + } } if (j >= 0) { @@ -1562,12 +1587,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st const char *digstart = p; unsigned uj; - if (get_unsigned_int(digstart, &p, &uj) == FAIL) { - goto error; - } - - if (uj > MAX_ALLOWED_STRING_WIDTH) { - format_overflow_error(digstart); + if (get_unsigned_int(digstart, &p, &uj, tvs != NULL) == FAIL) { goto error; } @@ -1585,12 +1605,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st const char *digstart = p; unsigned uj; - if (get_unsigned_int(digstart, &p, &uj) == FAIL) { - goto error; - } - - if (uj > MAX_ALLOWED_STRING_WIDTH) { - format_overflow_error(digstart); + if (get_unsigned_int(digstart, &p, &uj, tvs != NULL) == FAIL) { goto error; } @@ -1604,7 +1619,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st // positional argument unsigned uj; - if (get_unsigned_int(digstart, &p, &uj) == FAIL) { + if (get_unsigned_int(digstart, &p, &uj, tvs != NULL) == FAIL) { goto error; } @@ -1613,15 +1628,19 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st p++; } - const int j = (tvs - ? (int)tv_nr(tvs, &arg_idx) - : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, - &arg_cur, fmt), - va_arg(ap, int))); + int j = (tvs + ? (int)tv_nr(tvs, &arg_idx) + : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, + &arg_cur, fmt), + va_arg(ap, int))); if (j > MAX_ALLOWED_STRING_WIDTH) { - format_overflow_error(digstart); - goto error; + if (tvs != NULL) { + format_overflow_error(digstart); + goto error; + } else { + j = MAX_ALLOWED_STRING_WIDTH; + } } if (j >= 0) { @@ -1668,7 +1687,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st case 'o': case 'x': case 'X': - if (tvs && length_modifier == '\0') { + if (tvs && length_modifier == NUL) { length_modifier = 'L'; } } @@ -1789,7 +1808,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st } else if (fmt_spec == 'd') { // signed switch (length_modifier) { - case '\0': + case NUL: arg = (tvs ? (int)tv_nr(tvs, &arg_idx) : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, @@ -1835,7 +1854,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st } else { // unsigned switch (length_modifier) { - case '\0': + case NUL: uarg = (tvs ? (unsigned)tv_nr(tvs, &arg_idx) : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, @@ -2222,7 +2241,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st if (str_m > 0) { // make sure the string is nul-terminated even at the expense of // overwriting the last character (shouldn't happen, but just in case) - str[str_l <= str_m - 1 ? str_l : str_m - 1] = '\0'; + str[str_l <= str_m - 1 ? str_l : str_m - 1] = NUL; } if (tvs != NULL diff --git a/src/nvim/strings.h b/src/nvim/strings.h index f80e85afb0..c2d078615d 100644 --- a/src/nvim/strings.h +++ b/src/nvim/strings.h @@ -7,29 +7,9 @@ #include "klib/kvec.h" #include "nvim/api/private/defs.h" #include "nvim/eval/typval_defs.h" // IWYU pragma: keep -#include "nvim/func_attr.h" #include "nvim/os/os_defs.h" #include "nvim/types_defs.h" // IWYU pragma: keep -static inline char *strappend(char *dst, const char *src) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL - REAL_FATTR_NONNULL_RET REAL_FATTR_WARN_UNUSED_RESULT; - -/// Append string to string and return pointer to the next byte -/// -/// Unlike strcat, this one does *not* add NUL byte and returns pointer to the -/// past of the added string. -/// -/// @param[out] dst String to append to. -/// @param[in] src String to append. -/// -/// @return pointer to the byte just past the appended byte. -static inline char *strappend(char *const dst, const char *const src) -{ - const size_t src_len = strlen(src); - return (char *)memmove(dst, src, src_len) + src_len; -} - typedef kvec_t(char) StringBuilder; // Return the length of a string literal @@ -46,8 +26,26 @@ typedef struct { #ifdef INCLUDE_GENERATED_DECLARATIONS # include "strings.h.generated.h" +# include "strings.h.inline.generated.h" #endif +/// Append string to string and return pointer to the next byte +/// +/// Unlike strcat, this one does *not* add NUL byte and returns pointer to the +/// past of the added string. +/// +/// @param[out] dst String to append to. +/// @param[in] src String to append. +/// +/// @return pointer to the byte just past the appended byte. +static inline char *strappend(char *const dst, const char *const src) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL + FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT +{ + const size_t src_len = strlen(src); + return (char *)memmove(dst, src, src_len) + src_len; +} + #ifdef HAVE_STRCASECMP # define STRICMP(d, s) strcasecmp((char *)(d), (char *)(s)) #else diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index b63d2a729d..9eeed3fbd2 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -15,6 +15,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/vars.h" @@ -157,11 +158,6 @@ typedef struct { char *pattern; } time_entry_T; -struct name_list { - int flag; - char *name; -}; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "syntax.c.generated.h" #endif @@ -2286,7 +2282,7 @@ static void update_si_end(stateitem_T *sip, int startcol, bool force) // a "oneline" never continues in the next line sip->si_ends = true; sip->si_m_endpos.lnum = current_lnum; - sip->si_m_endpos.col = (colnr_T)strlen(syn_getcurline()); + sip->si_m_endpos.col = syn_getcurline_len(); } else { // continues in the next line sip->si_ends = false; @@ -2658,6 +2654,12 @@ static char *syn_getcurline(void) return ml_get_buf(syn_buf, current_lnum); } +/// Get length of current line in syntax buffer. +static colnr_T syn_getcurline_len(void) +{ + return ml_get_buf_len(syn_buf, current_lnum); +} + // Call vim_regexec() to find a match with "rmp" in "syn_buf". // Returns true when there is a match. static bool syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T *st) @@ -3326,24 +3328,22 @@ static int last_matchgroup; static void syn_list_one(const int id, const bool syncing, const bool link_only) { bool did_header = false; - static struct name_list namelist1[] = { - { HL_DISPLAY, "display" }, - { HL_CONTAINED, "contained" }, - { HL_ONELINE, "oneline" }, - { HL_KEEPEND, "keepend" }, - { HL_EXTEND, "extend" }, - { HL_EXCLUDENL, "excludenl" }, - { HL_TRANSP, "transparent" }, - { HL_FOLD, "fold" }, - { HL_CONCEAL, "conceal" }, - { HL_CONCEALENDS, "concealends" }, - { 0, NULL } + static keyvalue_T namelist1[] = { + KEYVALUE_ENTRY(HL_DISPLAY, "display"), + KEYVALUE_ENTRY(HL_CONTAINED, "contained"), + KEYVALUE_ENTRY(HL_ONELINE, "oneline"), + KEYVALUE_ENTRY(HL_KEEPEND, "keepend"), + KEYVALUE_ENTRY(HL_EXTEND, "extend"), + KEYVALUE_ENTRY(HL_EXCLUDENL, "excludenl"), + KEYVALUE_ENTRY(HL_TRANSP, "transparent"), + KEYVALUE_ENTRY(HL_FOLD, "fold"), + KEYVALUE_ENTRY(HL_CONCEAL, "conceal"), + KEYVALUE_ENTRY(HL_CONCEALENDS, "concealends"), }; - static struct name_list namelist2[] = { - { HL_SKIPWHITE, "skipwhite" }, - { HL_SKIPNL, "skipnl" }, - { HL_SKIPEMPTY, "skipempty" }, - { 0, NULL } + static keyvalue_T namelist2[] = { + KEYVALUE_ENTRY(HL_SKIPWHITE, "skipwhite"), + KEYVALUE_ENTRY(HL_SKIPNL, "skipnl"), + KEYVALUE_ENTRY(HL_SKIPEMPTY, "skipempty"), }; const int attr = HL_ATTR(HLF_D); // highlight like directories @@ -3384,7 +3384,7 @@ static void syn_list_one(const int id, const bool syncing, const bool link_only) idx--; msg_putchar(' '); } - syn_list_flags(namelist1, spp->sp_flags, attr); + syn_list_flags(namelist1, ARRAY_SIZE(namelist1), spp->sp_flags, attr); if (spp->sp_cont_list != NULL) { put_id_list("contains", spp->sp_cont_list, attr); @@ -3396,7 +3396,7 @@ static void syn_list_one(const int id, const bool syncing, const bool link_only) if (spp->sp_next_list != NULL) { put_id_list("nextgroup", spp->sp_next_list, attr); - syn_list_flags(namelist2, spp->sp_flags, attr); + syn_list_flags(namelist2, ARRAY_SIZE(namelist2), spp->sp_flags, attr); } if (spp->sp_flags & (HL_SYNC_HERE|HL_SYNC_THERE)) { if (spp->sp_flags & HL_SYNC_HERE) { @@ -3424,11 +3424,11 @@ 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) +static void syn_list_flags(keyvalue_T *nlist, size_t nr_entries, int flags, int attr) { - for (int i = 0; nlist[i].flag != 0; i++) { - if (flags & nlist[i].flag) { - msg_puts_attr(nlist[i].name, attr); + for (size_t i = 0; i < nr_entries; i++) { + if (flags & nlist[i].key) { + msg_puts_attr(nlist[i].value, attr); msg_putchar(' '); } } @@ -3700,17 +3700,22 @@ static void clear_keywtab(hashtab_T *ht) /// @param flags flags for this keyword /// @param cont_in_list containedin for this keyword /// @param next_list nextgroup for this keyword -static void add_keyword(char *const name, const int id, const int flags, +static void add_keyword(char *const name, size_t namelen, const int id, const int flags, int16_t *const cont_in_list, int16_t *const next_list, const int conceal_char) { char name_folded[MAXKEYWLEN + 1]; - const char *const name_ic = (curwin->w_s->b_syn_ic) - ? str_foldcase(name, (int)strlen(name), name_folded, - sizeof(name_folded)) - : name; + const char *name_ic; + size_t name_iclen; + if (curwin->w_s->b_syn_ic) { + name_ic = str_foldcase(name, (int)namelen, name_folded, MAXKEYWLEN + 1); + name_iclen = strlen(name_ic); + } else { + name_ic = name; + name_iclen = namelen; + } - keyentry_T *const kp = xmalloc(offsetof(keyentry_T, keyword) + strlen(name_ic) + 1); + keyentry_T *const kp = xmalloc(offsetof(keyentry_T, keyword) + name_iclen + 1); STRCPY(kp->keyword, name_ic); kp->k_syn.id = (int16_t)id; kp->k_syn.inc_tag = current_syn_inc_tag; @@ -4061,12 +4066,16 @@ static void syn_cmd_keyword(exarg_T *eap, int syncing) syn_incl_toplevel(syn_id, &syn_opt_arg.flags); // 2: Add an entry for each keyword. - for (char *kw = keyword_copy; --cnt >= 0; kw += strlen(kw) + 1) { + size_t kwlen = 0; + for (char *kw = keyword_copy; --cnt >= 0; kw += kwlen + 1) { for (p = vim_strchr(kw, '[');;) { - if (p != NULL) { + if (p == NULL) { + kwlen = strlen(kw); + } else { *p = NUL; + kwlen = (size_t)(p - kw); } - add_keyword(kw, syn_id, syn_opt_arg.flags, + add_keyword(kw, kwlen, syn_id, syn_opt_arg.flags, syn_opt_arg.cont_in_list, syn_opt_arg.next_list, conceal_char); if (p == NULL) { @@ -4082,6 +4091,7 @@ static void syn_cmd_keyword(exarg_T *eap, int syncing) goto error; } kw = p + 1; + kwlen = 1; break; // skip over the "]" } const int l = utfc_ptr2len(p + 1); @@ -4991,7 +5001,7 @@ static int get_id_list(char **const arg, const int keylen, int16_t **const list, } else { // Handle match of regexp with group names. *name = '^'; - STRCAT(name, "$"); + strcat(name, "$"); regmatch.regprog = vim_regcomp(name, RE_MAGIC); if (regmatch.regprog == NULL) { failed = true; @@ -5205,7 +5215,6 @@ static struct subcommand subcommands[] = { { "spell", syn_cmd_spell }, { "sync", syn_cmd_sync }, { "", syn_cmd_list }, - { NULL, NULL } }; /// ":syntax". @@ -5224,17 +5233,19 @@ void ex_syntax(exarg_T *eap) if (eap->skip) { // skip error messages for all subcommands emsg_skip++; } - for (int i = 0;; i++) { - if (subcommands[i].name == NULL) { - semsg(_("E410: Invalid :syntax subcommand: %s"), subcmd_name); - break; - } + size_t i; + for (i = 0; i < ARRAY_SIZE(subcommands); i++) { if (strcmp(subcmd_name, subcommands[i].name) == 0) { eap->arg = skipwhite(subcmd_end); (subcommands[i].func)(eap, false); break; } } + + if (i == ARRAY_SIZE(subcommands)) { + semsg(_("E410: Invalid :syntax subcommand: %s"), subcmd_name); + } + xfree(subcmd_name); if (eap->skip) { emsg_skip--; @@ -5365,6 +5376,9 @@ char *get_syntax_name(expand_T *xp, int idx) { switch (expand_what) { case EXP_SUBCMD: + if (idx < 0 || idx >= (int)ARRAY_SIZE(subcommands)) { + return NULL; + } return subcommands[idx].name; case EXP_CASE: { static char *case_args[] = { "match", "ignore", NULL }; @@ -5645,9 +5659,8 @@ static void syntime_report(void) } else { len = Columns - 70; } - if (len > (int)strlen(p->pattern)) { - len = (int)strlen(p->pattern); - } + int patlen = (int)strlen(p->pattern); + len = MIN(len, patlen); msg_outtrans_len(p->pattern, len, 0); msg_puts("\n"); } diff --git a/src/nvim/tag.c b/src/nvim/tag.c index e7f483dd3d..7a0c1cd810 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -18,6 +18,7 @@ #include "nvim/cmdexpand_defs.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds.h" @@ -585,11 +586,7 @@ void do_tag(char *tag, int type, int count, int forceit, bool verbose) || type == DT_LTAG) { cur_match = MAXCOL - 1; } - if (type == DT_TAG) { - max_num_matches = MAXCOL; - } else { - max_num_matches = cur_match + 1; - } + max_num_matches = type == DT_TAG ? MAXCOL : cur_match + 1; // when the argument starts with '/', use it as a regexp if (!no_regexp && *name == '/') { @@ -599,12 +596,8 @@ void do_tag(char *tag, int type, int count, int forceit, bool verbose) flags = TAG_NOIC; } - if (verbose) { - flags |= TAG_VERBOSE; - } - if (!use_tfu) { - flags |= TAG_NO_TAGFUNC; - } + flags |= verbose ? TAG_VERBOSE : 0; + flags |= !use_tfu ? TAG_NO_TAGFUNC : 0; if (find_tags(name, &new_num_matches, &new_matches, flags, max_num_matches, buf_ffname) == OK @@ -814,10 +807,7 @@ static void print_tag_list(bool new_tag, bool use_tagstack, int num_matches, cha // Assume that the first match indicates how long the tags can // be, and align the file names to that. parse_match(matches[0], &tagp); - int taglen = (int)(tagp.tagname_end - tagp.tagname + 2); - if (taglen < 18) { - taglen = 18; - } + int taglen = MAX((int)(tagp.tagname_end - tagp.tagname + 2), 18); if (taglen > Columns - 25) { taglen = MAXCOL; } @@ -998,10 +988,7 @@ static int add_llist_tags(char *tag, int num_matches, char **matches) parse_match(matches[i], &tagp); // Save the tag name - int len = (int)(tagp.tagname_end - tagp.tagname); - if (len > 128) { - len = 128; - } + int len = MIN((int)(tagp.tagname_end - tagp.tagname), 128); xmemcpyz(tag_name, tagp.tagname, (size_t)len); tag_name[len] = NUL; @@ -1059,13 +1046,10 @@ static int add_llist_tags(char *tag, int num_matches, char **matches) // Precede the tag pattern with \V to make it very // nomagic. - STRCAT(cmd, "\\V"); + strcat(cmd, "\\V"); len += 2; - int cmd_len = (int)(cmd_end - cmd_start + 1); - if (cmd_len > (CMDBUFFSIZE - 5)) { - cmd_len = CMDBUFFSIZE - 5; - } + int cmd_len = MIN((int)(cmd_end - cmd_start + 1), CMDBUFFSIZE - 5); snprintf(cmd + len, (size_t)(CMDBUFFSIZE + 1 - len), "%.*s", cmd_len, cmd_start); len += cmd_len; @@ -1819,11 +1803,9 @@ static tagmatch_status_T findtags_parse_line(findtags_state_T *st, tagptrs_T *ta } else if (st->state == TS_STEP_FORWARD) { assert(cmplen >= 0); if (mb_strnicmp(tagpp->tagname, st->orgpat->head, (size_t)cmplen) != 0) { - if ((off_T)vim_ftell(st->fp) > sinfo_p->match_offset) { - return TAG_MATCH_STOP; // past last match - } else { - return TAG_MATCH_NEXT; // before first match - } + return ((off_T)vim_ftell(st->fp) > sinfo_p->match_offset) + ? TAG_MATCH_STOP // past last match + : TAG_MATCH_NEXT; // before first match } } else { // skip this match if it can't match @@ -1846,11 +1828,9 @@ static tagmatch_status_T findtags_parse_line(findtags_state_T *st, tagptrs_T *ta status = parse_tag_line(st->lbuf, tagpp); } - if (status == FAIL) { - return TAG_MATCH_FAIL; - } - - return TAG_MATCH_SUCCESS; + return status == FAIL + ? TAG_MATCH_FAIL + : TAG_MATCH_SUCCESS; } /// Initialize the structure used for tag matching. @@ -1943,32 +1923,22 @@ static void findtags_add_match(findtags_state_T *st, tagptrs_T *tagpp, findtags_ char *buf_ffname, hash_T *hash) { const bool name_only = (st->flags & TAG_NAMES); - int mtt; size_t len = 0; size_t mfp_size = 0; - bool is_current; // file name matches - bool is_static; // current tag line is static char *mfp; // Decide in which array to store this match. - is_current = test_for_current(tagpp->fname, tagpp->fname_end, - st->tag_fname, buf_ffname); - is_static = test_for_static(tagpp); + bool is_current = test_for_current(tagpp->fname, tagpp->fname_end, + st->tag_fname, buf_ffname); + + // current tag line is static + bool is_static = test_for_static(tagpp); // Decide in which of the sixteen tables to store this match. - if (is_static) { - if (is_current) { - mtt = MT_ST_CUR; - } else { - mtt = MT_ST_OTH; - } - } else { - if (is_current) { - mtt = MT_GL_CUR; - } else { - mtt = MT_GL_OTH; - } - } + int mtt = is_static + ? is_current ? MT_ST_CUR : MT_ST_OTH + : is_current ? MT_GL_CUR : MT_GL_OTH; + if (st->orgpat->regmatch.rm_ic && !margs->match_no_ic) { mtt += MT_IC_OFF; } @@ -2236,13 +2206,11 @@ static void findtags_in_file(findtags_state_T *st, int flags, char *buf_ffname) static int findtags_copy_matches(findtags_state_T *st, char ***matchesp) { const bool name_only = (st->flags & TAG_NAMES); - char **matches; - if (st->match_count > 0) { - matches = xmalloc((size_t)st->match_count * sizeof(char *)); - } else { - matches = NULL; - } + char **matches = st->match_count > 0 + ? xmalloc((size_t)st->match_count * sizeof(char *)) + : NULL; + st->match_count = 0; for (int mtt = 0; mtt < MT_COUNT; mtt++) { for (int i = 0; i < st->ga_match[mtt].ga_len; i++) { @@ -2582,6 +2550,10 @@ int get_tagfname(tagname_T *tnp, int first, char *buf) // move the filename one char forward and truncate the // filepath with a NUL filename = path_tail(buf); + if (r_ptr != NULL) { + STRMOVE(r_ptr + 1, r_ptr); + r_ptr++; + } STRMOVE(filename + 1, filename); *filename++ = NUL; @@ -2951,13 +2923,13 @@ static int jumpto_tag(const char *lbuf_arg, int forceit, bool keep_help) p_ic = false; // don't ignore case now p_scs = false; linenr_T save_lnum = curwin->w_cursor.lnum; - if (tagp.tagline > 0) { - // start search before line from "line:" field - curwin->w_cursor.lnum = tagp.tagline - 1; - } else { - // start search before first line - curwin->w_cursor.lnum = 0; - } + + curwin->w_cursor.lnum = tagp.tagline > 0 + // start search before line from "line:" field + ? tagp.tagline - 1 + // start search before first line + : 0; + if (do_search(NULL, pbuf[0], pbuf[0], pbuf + 1, pbuflen - 1, 1, search_options, NULL)) { retval = OK; @@ -3180,10 +3152,8 @@ static int find_extra(char **pp) return FAIL; } -// -// Free a single entry in a tag stack -// -static void tagstack_clear_entry(taggy_T *item) +/// Free a single entry in a tag stack +void tagstack_clear_entry(taggy_T *item) { XFREE_CLEAR(item->tagname); XFREE_CLEAR(item->user_data); @@ -3192,18 +3162,12 @@ static void tagstack_clear_entry(taggy_T *item) /// @param tagnames expand tag names int expand_tags(bool tagnames, char *pat, int *num_file, char ***file) { - int extra_flag; size_t name_buf_size = 100; - tagptrs_T t_p; int ret; char *name_buf = xmalloc(name_buf_size); - if (tagnames) { - extra_flag = TAG_NAMES; - } else { - extra_flag = 0; - } + int extra_flag = tagnames ? TAG_NAMES : 0; if (pat[0] == '/') { ret = find_tags(pat + 1, num_file, file, TAG_REGEXP | extra_flag | TAG_VERBOSE | TAG_NO_TAGFUNC, @@ -3217,10 +3181,9 @@ int expand_tags(bool tagnames, char *pat, int *num_file, char ***file) // Reorganize the tags for display and matching as strings of: // "<tagname>\0<kind>\0<filename>\0" for (int i = 0; i < *num_file; i++) { - size_t len; - + tagptrs_T t_p; parse_match((*file)[i], &t_p); - len = (size_t)(t_p.tagname_end - t_p.tagname); + size_t len = (size_t)(t_p.tagname_end - t_p.tagname); if (len > name_buf_size - 3) { name_buf_size = len + 3; char *buf = xrealloc(name_buf, name_buf_size); @@ -3249,8 +3212,6 @@ int expand_tags(bool tagnames, char *pat, int *num_file, char ***file) static int add_tag_field(dict_T *dict, const char *field_name, const char *start, const char *end) FUNC_ATTR_NONNULL_ARG(1, 2) { - int len = 0; - // Check that the field name doesn't exist yet. if (tv_dict_find(dict, field_name, -1) != NULL) { if (p_verbose > 0) { @@ -3260,6 +3221,7 @@ static int add_tag_field(dict_T *dict, const char *field_name, const char *start } return FAIL; } + int len = 0; char *buf = xmalloc(MAXPATHL); if (start != NULL) { if (end == NULL) { @@ -3268,10 +3230,7 @@ static int add_tag_field(dict_T *dict, const char *field_name, const char *start end--; } } - len = (int)(end - start); - if (len > MAXPATHL - 1) { - len = MAXPATHL - 1; - } + len = MIN((int)(end - start), MAXPATHL - 1); xmemcpyz(buf, start, (size_t)len); } buf[len] = NUL; @@ -3450,9 +3409,7 @@ static void tagstack_push_item(win_T *wp, char *tagname, int cur_fnum, int cur_m tagstack[idx].tagname = tagname; tagstack[idx].cur_fnum = cur_fnum; tagstack[idx].cur_match = cur_match; - if (tagstack[idx].cur_match < 0) { - tagstack[idx].cur_match = 0; - } + tagstack[idx].cur_match = MAX(tagstack[idx].cur_match, 0); tagstack[idx].fmark.mark = mark; tagstack[idx].fmark.fnum = fnum; tagstack[idx].user_data = user_data; @@ -3502,12 +3459,8 @@ static void tagstack_push_items(win_T *wp, list_T *l) static void tagstack_set_curidx(win_T *wp, int curidx) { wp->w_tagstackidx = curidx; - if (wp->w_tagstackidx < 0) { // sanity check - wp->w_tagstackidx = 0; - } - if (wp->w_tagstackidx > wp->w_tagstacklen) { - wp->w_tagstackidx = wp->w_tagstacklen; - } + // sanity check + wp->w_tagstackidx = MIN(MAX(wp->w_tagstackidx, 0), wp->w_tagstacklen); } // Set the tag stack entries of the specified window. @@ -3518,15 +3471,15 @@ static void tagstack_set_curidx(win_T *wp, int curidx) int set_tagstack(win_T *wp, const dict_T *d, int action) FUNC_ATTR_NONNULL_ARG(1) { - dictitem_T *di; - list_T *l = NULL; - // not allowed to alter the tag stack entries from inside tagfunc if (tfu_in_use) { emsg(_(e_cannot_modify_tag_stack_within_tagfunc)); return FAIL; } + dictitem_T *di; + list_T *l = NULL; + if ((di = tv_dict_find(d, "items", -1)) != NULL) { if (di->di_tv.v_type != VAR_LIST) { emsg(_(e_listreq)); diff --git a/src/nvim/tag.h b/src/nvim/tag.h index 42196b44b7..1c6f41050d 100644 --- a/src/nvim/tag.h +++ b/src/nvim/tag.h @@ -1,5 +1,6 @@ #pragma once +#include "nvim/buffer_defs.h" // IWYU pragma: keep #include "nvim/eval/typval_defs.h" // IWYU pragma: keep #include "nvim/ex_cmds_defs.h" // IWYU pragma: keep #include "nvim/option_defs.h" // IWYU pragma: keep diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 2b05a8047e..b916660024 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -40,8 +40,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <vterm.h> -#include <vterm_keycodes.h> #include "klib/kvec.h" #include "nvim/api/private/helpers.h" @@ -94,6 +92,8 @@ #include "nvim/ui.h" #include "nvim/vim_defs.h" #include "nvim/window.h" +#include "vterm/vterm.h" +#include "vterm/vterm_keycodes.h" typedef struct { VimState state; @@ -112,6 +112,9 @@ typedef struct { // libvterm. Improves performance when receiving large bursts of data. #define REFRESH_DELAY 10 +#define TEXTBUF_SIZE 0x1fff +#define SELECTIONBUF_SIZE 0x0400 + static TimeWatcher refresh_timer; static bool refresh_pending = false; @@ -127,7 +130,7 @@ struct terminal { // buffer used to: // - convert VTermScreen cell arrays into utf8 strings // - receive data from libvterm as a result of key presses. - char textbuf[0x1fff]; + char textbuf[TEXTBUF_SIZE]; ScrollbackLine **sb_buffer; // Scrollback storage. size_t sb_current; // Lines stored in sb_buffer. @@ -166,6 +169,9 @@ struct terminal { // When there is a pending TermRequest autocommand, block and store input. StringBuilder *pending_send; + char *selection_buffer; /// libvterm selection buffer + StringBuilder selection; /// Growable array containing full selection data + size_t refcount; // reference count }; @@ -179,6 +185,12 @@ static VTermScreenCallbacks vterm_screen_callbacks = { .sb_popline = term_sb_pop, }; +static VTermSelectionCallbacks vterm_selection_callbacks = { + .set = term_selection_set, + // For security reasons we don't support querying the system clipboard from the embedded terminal + .query = NULL, +}; + static Set(ptr_t) invalidated_terminals = SET_INIT; static void emit_termrequest(void **argv) @@ -215,11 +227,67 @@ static void schedule_termrequest(Terminal *term, char *payload, size_t payload_l term->pending_send); } +static int parse_osc8(VTermStringFragment frag, int *attr) + FUNC_ATTR_NONNULL_ALL +{ + // Parse the URI from the OSC 8 sequence and add the URL to our URL set. + // Skip the ID, we don't use it (for now) + size_t i = 0; + for (; i < frag.len; i++) { + if (frag.str[i] == ';') { + break; + } + } + + // Move past the semicolon + i++; + + if (i >= frag.len) { + // Invalid OSC sequence + return 0; + } + + // Find the terminator + const size_t start = i; + for (; i < frag.len; i++) { + if (frag.str[i] == '\a' || frag.str[i] == '\x1b') { + break; + } + } + + const size_t len = i - start; + if (len == 0) { + // Empty OSC 8, no URL + *attr = 0; + return 1; + } + + char *url = xmemdupz(&frag.str[start], len + 1); + url[len] = 0; + *attr = hl_add_url(0, url); + xfree(url); + + return 1; +} + static int on_osc(int command, VTermStringFragment frag, void *user) + FUNC_ATTR_NONNULL_ALL { - if (frag.str == NULL) { + Terminal *term = user; + + if (frag.str == NULL || frag.len == 0) { return 0; } + + if (command == 8) { + int attr = 0; + if (parse_osc8(frag, &attr)) { + VTermState *state = vterm_obtain_state(term->vt); + VTermValue value = { .number = attr }; + vterm_state_set_penattr(state, VTERM_ATTR_URI, VTERM_VALUETYPE_INT, &value); + } + } + if (!has_event(EVENT_TERMREQUEST)) { return 1; } @@ -227,7 +295,7 @@ static int on_osc(int command, VTermStringFragment frag, void *user) StringBuilder request = KV_INITIAL_VALUE; kv_printf(request, "\x1b]%d;", command); kv_concat_len(request, frag.str, frag.len); - schedule_termrequest(user, request.items, request.size); + schedule_termrequest(term, request.items, request.size); return 1; } @@ -307,14 +375,18 @@ void terminal_open(Terminal **termpp, buf_T *buf, TerminalOptions opts) // Set up screen term->vts = vterm_obtain_screen(term->vt); vterm_screen_enable_altscreen(term->vts, true); - // TODO(clason): reenable when https://github.com/neovim/neovim/issues/23762 is fixed - // vterm_screen_enable_reflow(term->vts, true); + vterm_screen_enable_reflow(term->vts, true); // delete empty lines at the end of the buffer vterm_screen_set_callbacks(term->vts, &vterm_screen_callbacks, term); vterm_screen_set_unrecognised_fallbacks(term->vts, &vterm_fallbacks, term); vterm_screen_set_damage_merge(term->vts, VTERM_DAMAGE_SCROLL); vterm_screen_reset(term->vts, 1); vterm_output_set_callback(term->vt, term_output_callback, term); + + term->selection_buffer = xcalloc(SELECTIONBUF_SIZE, 1); + vterm_state_set_selection_callbacks(state, &vterm_selection_callbacks, term, + term->selection_buffer, SELECTIONBUF_SIZE); + // force a initial refresh of the screen to ensure the buffer will always // have as many lines as screen rows when refresh_scrollback is called term->invalid_start = 0; @@ -326,14 +398,6 @@ void terminal_open(Terminal **termpp, buf_T *buf, TerminalOptions opts) refresh_screen(term, buf); set_option_value(kOptBuftype, STATIC_CSTR_AS_OPTVAL("terminal"), OPT_LOCAL); - // Default settings for terminal buffers - buf->b_p_ma = false; // 'nomodifiable' - buf->b_p_ul = -1; // 'undolevels' - buf->b_p_scbk = // 'scrollback' (initialize local from global) - (p_scbk < 0) ? 10000 : MAX(1, p_scbk); - buf->b_p_tw = 0; // 'textwidth' - set_option_value(kOptWrap, BOOLEAN_OPTVAL(false), OPT_LOCAL); - set_option_value(kOptList, BOOLEAN_OPTVAL(false), OPT_LOCAL); if (buf->b_ffname != NULL) { buf_set_term_title(buf, buf->b_ffname, strlen(buf->b_ffname)); } @@ -684,6 +748,10 @@ static int terminal_execute(VimState *state, int key) } break; + case K_PASTE_START: + paste_repeat(1); + break; + case K_EVENT: // We cannot let an event free the terminal yet. It is still needed. s->term->refcount++; @@ -718,6 +786,12 @@ static int terminal_execute(VimState *state, int key) FALLTHROUGH; default: + if (key == Ctrl_C) { + // terminal_enter() always sets `mapped_ctrl_c` to avoid `got_int`. 8eeda7169aa4 + // But `got_int` may be set elsewhere, e.g. by interrupt() or an autocommand, + // so ensure that it is cleared. + got_int = false; + } if (key == Ctrl_BSL && !s->got_bsl) { s->got_bsl = true; break; @@ -769,6 +843,8 @@ void terminal_destroy(Terminal **termpp) } xfree(term->sb_buffer); xfree(term->title); + xfree(term->selection_buffer); + kv_destroy(term->selection); vterm_free(term->vt); xfree(term); *termpp = NULL; // coverity[dead-store] @@ -845,7 +921,7 @@ void terminal_paste(int count, char **y_array, size_t y_size) } char *dst = buff; char *src = y_array[j]; - while (*src != '\0') { + while (*src != NUL) { len = (size_t)utf_ptr2len(src); int c = utf_ptr2char(src); if (!is_filter_char(c)) { @@ -982,6 +1058,10 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, int *te }); } + if (cell.uri > 0) { + attr_id = hl_combine_attr(attr_id, cell.uri); + } + if (term->cursor.visible && term->cursor.row == row && term->cursor.col == col) { attr_id = hl_combine_attr(attr_id, @@ -1180,10 +1260,7 @@ static int term_sb_pop(int cols, VTermScreenCell *cells, void *data) memmove(term->sb_buffer, term->sb_buffer + 1, sizeof(term->sb_buffer[0]) * (term->sb_current)); - size_t cols_to_copy = (size_t)cols; - if (cols_to_copy > sbrow->cols) { - cols_to_copy = sbrow->cols; - } + size_t cols_to_copy = MIN((size_t)cols, sbrow->cols); // copy to vterm state memcpy(cells, sbrow->cells, sizeof(cells[0]) * cols_to_copy); @@ -1198,6 +1275,54 @@ static int term_sb_pop(int cols, VTermScreenCell *cells, void *data) return 1; } +static void term_clipboard_set(void **argv) +{ + VTermSelectionMask mask = (VTermSelectionMask)(long)argv[0]; + char *data = argv[1]; + + char regname; + switch (mask) { + case VTERM_SELECTION_CLIPBOARD: + regname = '+'; + break; + case VTERM_SELECTION_PRIMARY: + regname = '*'; + break; + default: + regname = '+'; + break; + } + + list_T *lines = tv_list_alloc(1); + tv_list_append_allocated_string(lines, data); + + list_T *args = tv_list_alloc(3); + tv_list_append_list(args, lines); + + const char regtype = 'v'; + tv_list_append_string(args, ®type, 1); + + tv_list_append_string(args, ®name, 1); + eval_call_provider("clipboard", "set", args, true); +} + +static int term_selection_set(VTermSelectionMask mask, VTermStringFragment frag, void *user) +{ + Terminal *term = user; + if (frag.initial) { + kv_size(term->selection) = 0; + } + + kv_concat_len(term->selection, frag.str, frag.len); + + if (frag.final) { + char *data = xmemdupz(term->selection.items, kv_size(term->selection)); + multiqueue_put(main_loop.events, term_clipboard_set, (void *)mask, data); + } + + return 1; +} + // }}} // input handling {{{ diff --git a/src/nvim/testing.c b/src/nvim/testing.c index 343568d71e..adbdd3e611 100644 --- a/src/nvim/testing.c +++ b/src/nvim/testing.c @@ -7,6 +7,7 @@ #include <string.h> #include "nvim/ascii_defs.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/typval.h" @@ -129,7 +130,7 @@ static void ga_concat_shorten_esc(garray_T *gap, const char *str) return; } - for (const char *p = str; *p != NUL; p++) { + for (const char *p = str; *p != NUL;) { int same_len = 1; const char *s = p; const int c = mb_cptr2char_adv(&s); @@ -145,9 +146,10 @@ static void ga_concat_shorten_esc(garray_T *gap, const char *str) vim_snprintf(buf, NUMBUFLEN, "%d", same_len); ga_concat(gap, buf); ga_concat(gap, " times]"); - p = s - 1; + p = s; } else { ga_concat_esc(gap, p, clen); + p += clen; } } } @@ -197,7 +199,7 @@ static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, const char *e if (!HASHITEM_EMPTY(hi)) { dictitem_T *item2 = tv_dict_find(got_d, hi->hi_key, -1); if (item2 == NULL - || !tv_equal(&TV_DICT_HI2DI(hi)->di_tv, &item2->di_tv, false, false)) { + || !tv_equal(&TV_DICT_HI2DI(hi)->di_tv, &item2->di_tv, false)) { // item of exp_d not present in got_d or values differ. const size_t key_len = strlen(hi->hi_key); tv_dict_add_tv(exp_tv->vval.v_dict, hi->hi_key, key_len, &TV_DICT_HI2DI(hi)->di_tv); @@ -270,8 +272,7 @@ static int assert_equal_common(typval_T *argvars, assert_type_T atype) { garray_T ga; - if (tv_equal(&argvars[0], &argvars[1], false, false) - != (atype == ASSERT_EQUAL)) { + if (tv_equal(&argvars[0], &argvars[1], false) != (atype == ASSERT_EQUAL)) { prepare_assert_error(&ga); fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1], atype); diff --git a/src/nvim/textformat.c b/src/nvim/textformat.c index 1722bcc968..9095d4e8c9 100644 --- a/src/nvim/textformat.c +++ b/src/nvim/textformat.c @@ -47,7 +47,7 @@ static bool did_add_space = false; ///< auto_format() added an extra space ///< under the cursor #define WHITECHAR(cc) (ascii_iswhite(cc) \ - && !utf_iscomposing(utf_ptr2char((char *)get_cursor_pos_ptr() + 1))) + && !utf_iscomposing_first(utf_ptr2char((char *)get_cursor_pos_ptr() + 1))) /// Return true if format option 'x' is in effect. /// Take care of no formatting when 'paste' is set. @@ -348,9 +348,7 @@ void internal_format(int textwidth, int second_indent, int flags, bool format_on inc_cursor(); } startcol -= curwin->w_cursor.col; - if (startcol < 0) { - startcol = 0; - } + startcol = MAX(startcol, 0); if (State & VREPLACE_FLAG) { // In MODE_VREPLACE state, we will backspace over the text to be @@ -402,7 +400,7 @@ void internal_format(int textwidth, int second_indent, int flags, bool format_on } if (second_indent >= 0) { if (State & VREPLACE_FLAG) { - change_indent(INDENT_SET, second_indent, false, NUL, true); + change_indent(INDENT_SET, second_indent, false, true); } else if (leader_len > 0 && second_indent - leader_len > 0) { int padding = second_indent - leader_len; @@ -433,9 +431,7 @@ void internal_format(int textwidth, int second_indent, int flags, bool format_on // may have added or removed indent. curwin->w_cursor.col += startcol; colnr_T len = get_cursor_line_len(); - if (curwin->w_cursor.col > len) { - curwin->w_cursor.col = len; - } + curwin->w_cursor.col = MIN(curwin->w_cursor.col, len); } haveto_redraw = true; @@ -758,14 +754,9 @@ int comp_textwidth(bool ff) textwidth -= 8; } } - if (textwidth < 0) { - textwidth = 0; - } + textwidth = MAX(textwidth, 0); if (ff && textwidth == 0) { - textwidth = curwin->w_width_inner - 1; - if (textwidth > 79) { - textwidth = 79; - } + textwidth = MIN(curwin->w_width_inner - 1, 79); } return textwidth; } @@ -878,7 +869,7 @@ int fex_format(linenr_T lnum, long count, int c) if (use_sandbox) { sandbox++; } - int r = (int)eval_to_number(fex); + int r = (int)eval_to_number(fex, true); if (use_sandbox) { sandbox--; } @@ -1105,11 +1096,7 @@ void format_lines(linenr_T line_count, bool avoid_fex) } first_par_line = false; // If the line is getting long, format it next time - if (get_cursor_line_len() > max_len) { - force_format = true; - } else { - force_format = false; - } + force_format = get_cursor_line_len() > max_len; } } line_breakcheck(); diff --git a/src/nvim/textobject.c b/src/nvim/textobject.c index 3c81a840ea..45978765bf 100644 --- a/src/nvim/textobject.c +++ b/src/nvim/textobject.c @@ -1193,13 +1193,18 @@ again: pos_T end_pos = curwin->w_cursor; if (!do_include) { - // Exclude the start tag. + // Exclude the start tag, + // but skip over '>' if it appears in quotes + bool in_quotes = false; curwin->w_cursor = start_pos; while (inc_cursor() >= 0) { - if (*get_cursor_pos_ptr() == '>') { + p = get_cursor_pos_ptr(); + if (*p == '>' && !in_quotes) { inc_cursor(); start_pos = curwin->w_cursor; break; + } else if (*p == '"' || *p == '\'') { + in_quotes = !in_quotes; } } curwin->w_cursor = end_pos; @@ -1264,11 +1269,7 @@ int current_par(oparg_T *oap, int count, bool include, int type) // When visual area is more than one line: extend it. if (VIsual_active && start_lnum != VIsual.lnum) { extend: - if (start_lnum < VIsual.lnum) { - dir = BACKWARD; - } else { - dir = FORWARD; - } + dir = start_lnum < VIsual.lnum ? BACKWARD : FORWARD; for (int i = count; --i >= 0;) { if (start_lnum == (dir == BACKWARD ? 1 : curbuf->b_ml.ml_line_count)) { diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index f1594dfcb9..98dd7b4b45 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -7,28 +7,29 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/event/loop.h" +#include "nvim/event/rstream.h" #include "nvim/event/stream.h" #include "nvim/macros_defs.h" #include "nvim/main.h" #include "nvim/map_defs.h" #include "nvim/memory.h" +#include "nvim/msgpack_rpc/channel.h" #include "nvim/option_vars.h" #include "nvim/os/os.h" #include "nvim/os/os_defs.h" -#include "nvim/rbuffer.h" #include "nvim/strings.h" #include "nvim/tui/input.h" #include "nvim/tui/input_defs.h" +#include "nvim/tui/termkey/driver-csi.h" +#include "nvim/tui/termkey/termkey.h" #include "nvim/tui/tui.h" #include "nvim/ui_client.h" + #ifdef MSWIN # include "nvim/os/os_win_console.h" #endif -#include "nvim/event/rstream.h" -#include "nvim/msgpack_rpc/channel.h" #define READ_STREAM_SIZE 0xfff -#define KEY_BUFFER_SIZE 0xfff /// Size of libtermkey's internal input buffer. The buffer may grow larger than /// this when processing very long escape sequences, but will shrink back to @@ -132,7 +133,6 @@ void tinput_init(TermInput *input, Loop *loop) input->key_encoding = kKeyEncodingLegacy; input->ttimeout = (bool)p_ttimeout; input->ttimeoutlen = p_ttm; - input->key_buffer = rbuffer_new(KEY_BUFFER_SIZE); for (size_t i = 0; i < ARRAY_SIZE(kitty_key_map_entry); i++) { pmap_put(int)(&kitty_key_map, kitty_key_map_entry[i].key, (ptr_t)kitty_key_map_entry[i].name); @@ -155,7 +155,7 @@ void tinput_init(TermInput *input, Loop *loop) termkey_set_canonflags(input->tk, curflags | TERMKEY_CANON_DELBS); // setup input handle - rstream_init_fd(loop, &input->read_stream, input->in_fd, READ_STREAM_SIZE); + rstream_init_fd(loop, &input->read_stream, input->in_fd); // initialize a timer handle for handling ESC with libtermkey uv_timer_init(&loop->uv, &input->timer_handle); @@ -165,9 +165,8 @@ void tinput_init(TermInput *input, Loop *loop) void tinput_destroy(TermInput *input) { map_destroy(int, &kitty_key_map); - rbuffer_free(input->key_buffer); uv_close((uv_handle_t *)&input->timer_handle, NULL); - stream_close(&input->read_stream, NULL, NULL); + rstream_may_close(&input->read_stream); termkey_destroy(input->tk); } @@ -191,44 +190,38 @@ static void tinput_done_event(void **argv) /// Send all pending input in key buffer to Nvim server. static void tinput_flush(TermInput *input) { + String keys = { .data = input->key_buffer, .size = input->key_buffer_len }; if (input->paste) { // produce exactly one paste event - const size_t len = rbuffer_size(input->key_buffer); - String keys = { .data = xmallocz(len), .size = len }; - rbuffer_read(input->key_buffer, keys.data, len); MAXSIZE_TEMP_ARRAY(args, 3); ADD_C(args, STRING_OBJ(keys)); // 'data' ADD_C(args, BOOLEAN_OBJ(true)); // 'crlf' ADD_C(args, INTEGER_OBJ(input->paste)); // 'phase' rpc_send_event(ui_client_channel_id, "nvim_paste", args); - api_free_string(keys); if (input->paste == 1) { // Paste phase: "continue" input->paste = 2; } - rbuffer_reset(input->key_buffer); } else { // enqueue input - RBUFFER_UNTIL_EMPTY(input->key_buffer, buf, len) { - const String keys = { .data = buf, .size = len }; + if (input->key_buffer_len > 0) { MAXSIZE_TEMP_ARRAY(args, 1); ADD_C(args, STRING_OBJ(keys)); // NOTE: This is non-blocking and won't check partially processed input, // but should be fine as all big sends are handled with nvim_paste, not nvim_input rpc_send_event(ui_client_channel_id, "nvim_input", args); - rbuffer_consumed(input->key_buffer, len); - rbuffer_reset(input->key_buffer); } } + input->key_buffer_len = 0; } -static void tinput_enqueue(TermInput *input, char *buf, size_t size) +static void tinput_enqueue(TermInput *input, const char *buf, size_t size) { - if (rbuffer_size(input->key_buffer) > - rbuffer_capacity(input->key_buffer) - 0xff) { - // don't ever let the buffer get too full or we risk putting incomplete keys - // into it + if (input->key_buffer_len > KEY_BUFFER_SIZE - size) { + // don't ever let the buffer get too full or we risk putting incomplete keys into it tinput_flush(input); } - rbuffer_write(input->key_buffer, buf, size); + size_t to_copy = MIN(size, KEY_BUFFER_SIZE - input->key_buffer_len); + memcpy(input->key_buffer + input->key_buffer_len, buf, to_copy); + input->key_buffer_len += to_copy; } /// Handle TERMKEY_KEYMOD_* modifiers, i.e. Shift, Alt and Ctrl. @@ -271,7 +264,7 @@ static size_t handle_more_modifiers(TermKeyKey *key, char *buf, size_t buflen) static void handle_kitty_key_protocol(TermInput *input, TermKeyKey *key) { - const char *name = pmap_get(int)(&kitty_key_map, (int)key->code.codepoint); + const char *name = pmap_get(int)(&kitty_key_map, key->code.codepoint); if (name) { char buf[64]; size_t len = 0; @@ -471,9 +464,11 @@ static void tinput_timer_cb(uv_timer_t *handle) { TermInput *input = handle->data; // If the raw buffer is not empty, process the raw buffer first because it is - // processing an incomplete bracketed paster sequence. - if (rbuffer_size(input->read_stream.buffer)) { - handle_raw_buffer(input, true); + // processing an incomplete bracketed paste sequence. + size_t size = rstream_available(&input->read_stream); + if (size) { + size_t consumed = handle_raw_buffer(input, true, input->read_stream.read_pos, size); + rstream_consume(&input->read_stream, consumed); } tk_getkeys(input, true); tinput_flush(input); @@ -487,39 +482,37 @@ static void tinput_timer_cb(uv_timer_t *handle) /// /// @param input the input stream /// @return true iff handle_focus_event consumed some input -static bool handle_focus_event(TermInput *input) +static size_t handle_focus_event(TermInput *input, const char *ptr, size_t size) { - if (rbuffer_size(input->read_stream.buffer) > 2 - && (!rbuffer_cmp(input->read_stream.buffer, "\x1b[I", 3) - || !rbuffer_cmp(input->read_stream.buffer, "\x1b[O", 3))) { - bool focus_gained = *rbuffer_get(input->read_stream.buffer, 2) == 'I'; - // Advance past the sequence - rbuffer_consumed(input->read_stream.buffer, 3); + if (size >= 3 + && (!memcmp(ptr, "\x1b[I", 3) + || !memcmp(ptr, "\x1b[O", 3))) { + bool focus_gained = ptr[2] == 'I'; MAXSIZE_TEMP_ARRAY(args, 1); ADD_C(args, BOOLEAN_OBJ(focus_gained)); rpc_send_event(ui_client_channel_id, "nvim_ui_set_focus", args); - return true; + return 3; // Advance past the sequence } - return false; + return 0; } #define START_PASTE "\x1b[200~" #define END_PASTE "\x1b[201~" -static HandleState handle_bracketed_paste(TermInput *input) +static size_t handle_bracketed_paste(TermInput *input, const char *ptr, size_t size, + bool *incomplete) { - size_t buf_size = rbuffer_size(input->read_stream.buffer); - if (buf_size > 5 - && (!rbuffer_cmp(input->read_stream.buffer, START_PASTE, 6) - || !rbuffer_cmp(input->read_stream.buffer, END_PASTE, 6))) { - bool enable = *rbuffer_get(input->read_stream.buffer, 4) == '0'; + if (size >= 6 + && (!memcmp(ptr, START_PASTE, 6) + || !memcmp(ptr, END_PASTE, 6))) { + bool enable = ptr[4] == '0'; if (input->paste && enable) { - return kNotApplicable; // Pasting "start paste" code literally. + return 0; // Pasting "start paste" code literally. } + // Advance past the sequence - rbuffer_consumed(input->read_stream.buffer, 6); if (!!input->paste == enable) { - return kComplete; // Spurious "disable paste" code. + return 6; // Spurious "disable paste" code. } if (enable) { @@ -534,15 +527,15 @@ static HandleState handle_bracketed_paste(TermInput *input) // Paste phase: "disabled". input->paste = 0; } - return kComplete; - } else if (buf_size < 6 - && (!rbuffer_cmp(input->read_stream.buffer, START_PASTE, buf_size) - || !rbuffer_cmp(input->read_stream.buffer, - END_PASTE, buf_size))) { + return 6; + } else if (size < 6 + && (!memcmp(ptr, START_PASTE, size) + || !memcmp(ptr, END_PASTE, size))) { // Wait for further input, as the sequence may be split. - return kIncomplete; + *incomplete = true; + return 0; } - return kNotApplicable; + return 0; } /// Handle an OSC or DCS response sequence from the terminal. @@ -606,10 +599,10 @@ static void handle_unknown_csi(TermInput *input, const TermKeyKey *key) { // There is no specified limit on the number of parameters a CSI sequence can // contain, so just allocate enough space for a large upper bound - long args[16]; - size_t nargs = 16; - unsigned long cmd; - if (termkey_interpret_csi(input->tk, key, args, &nargs, &cmd) != TERMKEY_RES_KEY) { + TermKeyCsiParam params[16]; + size_t nparams = 16; + unsigned cmd; + if (termkey_interpret_csi(input->tk, key, params, &nparams, &cmd) != TERMKEY_RES_KEY) { return; } @@ -648,25 +641,55 @@ static void handle_unknown_csi(TermInput *input, const TermKeyKey *key) break; } break; + case 't': + if (nparams == 5) { + // We only care about the first 3 parameters, and we ignore subparameters + int args[3]; + for (size_t i = 0; i < ARRAY_SIZE(args); i++) { + if (termkey_interpret_csi_param(params[i], &args[i], NULL, NULL) != TERMKEY_RES_KEY) { + return; + } + } + + if (args[0] == 48) { + // In-band resize event (DEC private mode 2048) + int height_chars = args[1]; + int width_chars = args[2]; + tui_set_size(input->tui_data, width_chars, height_chars); + ui_client_set_size(width_chars, height_chars); + } + } + break; default: break; } } -static void handle_raw_buffer(TermInput *input, bool force) +static size_t handle_raw_buffer(TermInput *input, bool force, const char *data, size_t size) { - HandleState is_paste = kNotApplicable; + const char *ptr = data; do { - if (!force - && (handle_focus_event(input) - || (is_paste = handle_bracketed_paste(input)) != kNotApplicable)) { - if (is_paste == kIncomplete) { + if (!force) { + size_t consumed = handle_focus_event(input, ptr, size); + if (consumed) { + ptr += consumed; + size -= consumed; + continue; + } + + bool incomplete = false; + consumed = handle_bracketed_paste(input, ptr, size, &incomplete); + if (incomplete) { + assert(consumed == 0); // Wait for the next input, leaving it in the raw buffer due to an // incomplete sequence. - return; + return (size_t)(ptr - data); + } else if (consumed) { + ptr += consumed; + size -= consumed; + continue; } - continue; } // @@ -675,55 +698,47 @@ static void handle_raw_buffer(TermInput *input, bool force) // calls (above) depend on this. // size_t count = 0; - RBUFFER_EACH(input->read_stream.buffer, c, i) { + for (size_t i = 0; i < size; i++) { count = i + 1; - if (c == '\x1b' && count > 1) { + if (ptr[i] == '\x1b' && count > 1) { count--; break; } } // Push bytes directly (paste). if (input->paste) { - RBUFFER_UNTIL_EMPTY(input->read_stream.buffer, ptr, len) { - size_t consumed = MIN(count, len); - assert(consumed <= input->read_stream.buffer->size); - tinput_enqueue(input, ptr, consumed); - rbuffer_consumed(input->read_stream.buffer, consumed); - if (!(count -= consumed)) { - break; - } - } + tinput_enqueue(input, ptr, count); + ptr += count; + size -= count; continue; } + // Push through libtermkey (translates to "<keycode>" strings, etc.). - RBUFFER_UNTIL_EMPTY(input->read_stream.buffer, ptr, len) { - const size_t size = MIN(count, len); - if (size > termkey_get_buffer_remaining(input->tk)) { + { + const size_t to_use = MIN(count, size); + if (to_use > termkey_get_buffer_remaining(input->tk)) { // We are processing a very long escape sequence. Increase termkey's // internal buffer size. We don't handle out of memory situations so // abort if it fails - const size_t delta = size - termkey_get_buffer_remaining(input->tk); + const size_t delta = to_use - termkey_get_buffer_remaining(input->tk); const size_t bufsize = termkey_get_buffer_size(input->tk); if (!termkey_set_buffer_size(input->tk, MAX(bufsize + delta, bufsize * 2))) { abort(); } } - size_t consumed = termkey_push_bytes(input->tk, ptr, size); + size_t consumed = termkey_push_bytes(input->tk, ptr, to_use); // We resize termkey's buffer when it runs out of space, so this should // never happen - assert(consumed <= rbuffer_size(input->read_stream.buffer)); - rbuffer_consumed(input->read_stream.buffer, consumed); + assert(consumed <= to_use); + ptr += consumed; + size -= consumed; // Process the input buffer now for any keys tk_getkeys(input, false); - - if (!(count -= consumed)) { - break; - } } - } while (rbuffer_size(input->read_stream.buffer)); + } while (size); const size_t tk_size = termkey_get_buffer_size(input->tk); const size_t tk_remaining = termkey_get_buffer_remaining(input->tk); @@ -735,23 +750,25 @@ static void handle_raw_buffer(TermInput *input, bool force) abort(); } } + + return (size_t)(ptr - data); } -static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_, void *data, bool eof) +static size_t tinput_read_cb(RStream *stream, const char *buf, size_t count_, void *data, bool eof) { TermInput *input = data; + size_t consumed = handle_raw_buffer(input, false, buf, count_); + tinput_flush(input); + if (eof) { loop_schedule_fast(&main_loop, event_create(tinput_done_event, NULL)); - return; + return consumed; } - handle_raw_buffer(input, false); - tinput_flush(input); - // An incomplete sequence was found. Leave it in the raw buffer and wait for // the next input. - if (rbuffer_size(input->read_stream.buffer)) { + if (consumed < count_) { // If 'ttimeout' is not set, start the timer with a timeout of 0 to process // the next input. int64_t ms = input->ttimeout @@ -759,11 +776,7 @@ static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_, void *da // Stop the current timer if already running uv_timer_stop(&input->timer_handle); uv_timer_start(&input->timer_handle, tinput_timer_cb, (uint32_t)ms, 0); - return; } - // Make sure the next input escape sequence fits into the ring buffer without - // wraparound, else it could be misinterpreted (because rbuffer_read_ptr() - // exposes the underlying buffer to callers unaware of the wraparound). - rbuffer_reset(input->read_stream.buffer); + return consumed; } diff --git a/src/nvim/tui/input.h b/src/nvim/tui/input.h index bf6d0f2978..4c2baf908e 100644 --- a/src/nvim/tui/input.h +++ b/src/nvim/tui/input.h @@ -5,11 +5,10 @@ #include <uv.h> #include "nvim/event/defs.h" -#include "nvim/rbuffer_defs.h" #include "nvim/tui/input_defs.h" // IWYU pragma: keep +#include "nvim/tui/termkey/termkey_defs.h" #include "nvim/tui/tui_defs.h" #include "nvim/types_defs.h" -#include "termkey/termkey.h" typedef enum { kKeyEncodingLegacy, ///< Legacy key encoding @@ -17,6 +16,7 @@ typedef enum { kKeyEncodingXterm, ///< Xterm's modifyOtherKeys encoding (XTMODKEYS) } KeyEncoding; +#define KEY_BUFFER_SIZE 0x1000 typedef struct { int in_fd; // Phases: -1=all 0=disabled 1=first-chunk 2=continue 3=last-chunk @@ -33,17 +33,12 @@ typedef struct { TermKey_Terminfo_Getstr_Hook *tk_ti_hook_fn; ///< libtermkey terminfo hook uv_timer_t timer_handle; Loop *loop; - Stream read_stream; - RBuffer *key_buffer; + RStream read_stream; TUIData *tui_data; + char key_buffer[KEY_BUFFER_SIZE]; + size_t key_buffer_len; } TermInput; -typedef enum { - kIncomplete = -1, - kNotApplicable = 0, - kComplete = 1, -} HandleState; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "tui/input.h.generated.h" #endif diff --git a/src/nvim/tui/terminfo.c b/src/nvim/tui/terminfo.c index 3cf9650428..657bd6dd10 100644 --- a/src/nvim/tui/terminfo.c +++ b/src/nvim/tui/terminfo.c @@ -35,7 +35,7 @@ bool terminfo_is_term_family(const char *term, const char *family) // The screen terminfo may have a terminal name like screen.xterm. By making // the dot(.) a valid separator, such terminal names will also be the // terminal family of the screen. - && ('\0' == term[flen] || '-' == term[flen] || '.' == term[flen]); + && (NUL == term[flen] || '-' == term[flen] || '.' == term[flen]); } bool terminfo_is_bsd_console(const char *term) diff --git a/src/nvim/tui/termkey/README b/src/nvim/tui/termkey/README new file mode 100644 index 0000000000..fd081025fc --- /dev/null +++ b/src/nvim/tui/termkey/README @@ -0,0 +1 @@ +// Adapted from libtermkey: https://github.com/neovim/libtermkey diff --git a/src/nvim/tui/termkey/driver-csi.c b/src/nvim/tui/termkey/driver-csi.c new file mode 100644 index 0000000000..28c7eaccfd --- /dev/null +++ b/src/nvim/tui/termkey/driver-csi.c @@ -0,0 +1,902 @@ +#include <assert.h> +#include <stdio.h> +#include <string.h> + +#include "nvim/memory.h" +#include "nvim/tui/termkey/driver-csi.h" +#include "nvim/tui/termkey/termkey-internal.h" +#include "nvim/tui/termkey/termkey.h" +#include "nvim/tui/termkey/termkey_defs.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "tui/termkey/driver-csi.c.generated.h" +#endif + +// There are 64 codes 0x40 - 0x7F +static int keyinfo_initialised = 0; +static struct keyinfo ss3s[64]; +static char ss3_kpalts[64]; + +typedef TermKeyResult CsiHandler(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params, + int nparams); +static CsiHandler *csi_handlers[64]; + +// Handler for CSI/SS3 cmd keys + +static struct keyinfo csi_ss3s[64]; + +static TermKeyResult handle_csi_ss3_full(TermKey *tk, TermKeyKey *key, int cmd, + TermKeyCsiParam *params, int nparams) +{ + TermKeyResult result = TERMKEY_RES_KEY; + + if (nparams > 1 && params[1].param != NULL) { + int arg = 0; + result = termkey_interpret_csi_param(params[1], &arg, NULL, NULL); + if (result != TERMKEY_RES_KEY) { + return result; + } + + key->modifiers = arg - 1; + } else { + key->modifiers = 0; + } + + key->type = csi_ss3s[cmd - 0x40].type; + key->code.sym = csi_ss3s[cmd - 0x40].sym; + key->modifiers &= ~(csi_ss3s[cmd - 0x40].modifier_mask); + key->modifiers |= csi_ss3s[cmd - 0x40].modifier_set; + + if (key->code.sym == TERMKEY_SYM_UNKNOWN) { + result = TERMKEY_RES_NONE; + } + + return result; +} + +static void register_csi_ss3_full(TermKeyType type, TermKeySym sym, int modifier_set, + int modifier_mask, unsigned char cmd) +{ + if (cmd < 0x40 || cmd >= 0x80) { + return; + } + + csi_ss3s[cmd - 0x40].type = type; + csi_ss3s[cmd - 0x40].sym = sym; + csi_ss3s[cmd - 0x40].modifier_set = modifier_set; + csi_ss3s[cmd - 0x40].modifier_mask = modifier_mask; + + csi_handlers[cmd - 0x40] = &handle_csi_ss3_full; +} + +static void register_csi_ss3(TermKeyType type, TermKeySym sym, unsigned char cmd) +{ + register_csi_ss3_full(type, sym, 0, 0, cmd); +} + +/// Handler for SS3 keys with kpad alternate representations +static void register_ss3kpalt(TermKeyType type, TermKeySym sym, unsigned char cmd, char kpalt) +{ + if (cmd < 0x40 || cmd >= 0x80) { + return; + } + + ss3s[cmd - 0x40].type = type; + ss3s[cmd - 0x40].sym = sym; + ss3s[cmd - 0x40].modifier_set = 0; + ss3s[cmd - 0x40].modifier_mask = 0; + ss3_kpalts[cmd - 0x40] = kpalt; +} + +// Handler for CSI number ~ function keys + +#define NCSIFUNCS 35 // This value must be increased if more CSI function keys are added +static struct keyinfo csifuncs[NCSIFUNCS]; + +static TermKeyResult handle_csifunc(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params, + int nparams) +{ + if (nparams == 0) { + return TERMKEY_RES_NONE; + } + + TermKeyResult result = TERMKEY_RES_KEY; + int args[3]; + + if (nparams > 1 && params[1].param != NULL) { + result = termkey_interpret_csi_param(params[1], &args[1], NULL, NULL); + if (result != TERMKEY_RES_KEY) { + return result; + } + + key->modifiers = args[1] - 1; + } else { + key->modifiers = 0; + } + + key->type = TERMKEY_TYPE_KEYSYM; + + result = termkey_interpret_csi_param(params[0], &args[0], NULL, NULL); + if (result != TERMKEY_RES_KEY) { + return result; + } + + if (args[0] == 27 && nparams > 2 && params[2].param != NULL) { + result = termkey_interpret_csi_param(params[2], &args[2], NULL, NULL); + if (result != TERMKEY_RES_KEY) { + return result; + } + + int mod = key->modifiers; + (*tk->method.emit_codepoint)(tk, args[2], key); + key->modifiers |= mod; + } else if (args[0] >= 0 && args[0] < NCSIFUNCS) { + key->type = csifuncs[args[0]].type; + key->code.sym = csifuncs[args[0]].sym; + key->modifiers &= ~(csifuncs[args[0]].modifier_mask); + key->modifiers |= csifuncs[args[0]].modifier_set; + } else { + key->code.sym = TERMKEY_SYM_UNKNOWN; + } + + if (key->code.sym == TERMKEY_SYM_UNKNOWN) { +#ifdef DEBUG + fprintf(stderr, "CSI: Unknown function key %ld\n", arg[0]); +#endif + result = TERMKEY_RES_NONE; + } + + return result; +} + +static void register_csifunc(TermKeyType type, TermKeySym sym, int number) +{ + if (number >= NCSIFUNCS) { + return; + } + + csifuncs[number].type = type; + csifuncs[number].sym = sym; + csifuncs[number].modifier_set = 0; + csifuncs[number].modifier_mask = 0; + + csi_handlers['~' - 0x40] = &handle_csifunc; +} + +/// Handler for CSI u extended Unicode keys +static TermKeyResult handle_csi_u(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params, + int nparams) +{ + switch (cmd) { + case 'u': { + int args[2]; + if (nparams > 1 && params[1].param != NULL) { + int subparam = 0; + size_t nsubparams = 1; + if (termkey_interpret_csi_param(params[1], &args[1], &subparam, + &nsubparams) != TERMKEY_RES_KEY) { + return TERMKEY_RES_ERROR; + } + + if (nsubparams > 0 && subparam != 1) { + // Not a press event. Ignore for now + return TERMKEY_RES_NONE; + } + + key->modifiers = args[1] - 1; + } else { + key->modifiers = 0; + } + + if (termkey_interpret_csi_param(params[0], &args[0], NULL, NULL) != TERMKEY_RES_KEY) { + return TERMKEY_RES_ERROR; + } + + int mod = key->modifiers; + key->type = TERMKEY_TYPE_KEYSYM; + (*tk->method.emit_codepoint)(tk, args[0], key); + key->modifiers |= mod; + + return TERMKEY_RES_KEY; + } + default: + return TERMKEY_RES_NONE; + } +} + +/// Handler for CSI M / CSI m mouse events in SGR and rxvt encodings +/// Note: This does not handle X10 encoding +static TermKeyResult handle_csi_m(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params, + int nparams) +{ + int initial = cmd >> 8; + cmd &= 0xff; + + switch (cmd) { + case 'M': + case 'm': + break; + default: + return TERMKEY_RES_NONE; + } + + if (nparams < 3) { + return TERMKEY_RES_NONE; + } + + int args[3]; + for (size_t i = 0; i < 3; i++) { + if (termkey_interpret_csi_param(params[i], &args[i], NULL, NULL) != TERMKEY_RES_KEY) { + return TERMKEY_RES_ERROR; + } + } + + if (!initial) { // rxvt protocol + key->type = TERMKEY_TYPE_MOUSE; + key->code.mouse[0] = (char)args[0]; + + key->modifiers = (key->code.mouse[0] & 0x1c) >> 2; + key->code.mouse[0] &= ~0x1c; + + termkey_key_set_linecol(key, args[1], args[2]); + + return TERMKEY_RES_KEY; + } + + if (initial == '<') { // SGR protocol + key->type = TERMKEY_TYPE_MOUSE; + key->code.mouse[0] = (char)args[0]; + + key->modifiers = (key->code.mouse[0] & 0x1c) >> 2; + key->code.mouse[0] &= ~0x1c; + + termkey_key_set_linecol(key, args[1], args[2]); + + if (cmd == 'm') { // release + key->code.mouse[3] |= 0x80; + } + + return TERMKEY_RES_KEY; + } + + return TERMKEY_RES_NONE; +} + +TermKeyResult termkey_interpret_mouse(TermKey *tk, const TermKeyKey *key, TermKeyMouseEvent *event, + int *button, int *line, int *col) +{ + if (key->type != TERMKEY_TYPE_MOUSE) { + return TERMKEY_RES_NONE; + } + + if (button) { + *button = 0; + } + + termkey_key_get_linecol(key, line, col); + + if (!event) { + return TERMKEY_RES_KEY; + } + + int btn = 0; + + int code = (unsigned char)key->code.mouse[0]; + + int drag = code & 0x20; + + code &= ~0x3c; + + switch (code) { + case 0: + case 1: + case 2: + *event = drag ? TERMKEY_MOUSE_DRAG : TERMKEY_MOUSE_PRESS; + btn = code + 1; + break; + + case 3: + *event = TERMKEY_MOUSE_RELEASE; + // no button hint + break; + + case 64: + case 65: + case 66: + case 67: + *event = drag ? TERMKEY_MOUSE_DRAG : TERMKEY_MOUSE_PRESS; + btn = code + 4 - 64; + break; + + default: + *event = TERMKEY_MOUSE_UNKNOWN; + } + + if (button) { + *button = btn; + } + + if (key->code.mouse[3] & 0x80) { + *event = TERMKEY_MOUSE_RELEASE; + } + + return TERMKEY_RES_KEY; +} + +/// Handler for CSI ? R position reports +/// A plain CSI R with no arguments is probably actually <F3> +static TermKeyResult handle_csi_R(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params, + int nparams) +{ + switch (cmd) { + case 'R'|'?' << 8: + if (nparams < 2) { + return TERMKEY_RES_NONE; + } + + int args[2]; + if (termkey_interpret_csi_param(params[0], &args[0], NULL, NULL) != TERMKEY_RES_KEY) { + return TERMKEY_RES_ERROR; + } + + if (termkey_interpret_csi_param(params[1], &args[1], NULL, NULL) != TERMKEY_RES_KEY) { + return TERMKEY_RES_ERROR; + } + + key->type = TERMKEY_TYPE_POSITION; + termkey_key_set_linecol(key, args[1], args[0]); + return TERMKEY_RES_KEY; + + default: + return handle_csi_ss3_full(tk, key, cmd, params, nparams); + } +} + +TermKeyResult termkey_interpret_position(TermKey *tk, const TermKeyKey *key, int *line, int *col) +{ + if (key->type != TERMKEY_TYPE_POSITION) { + return TERMKEY_RES_NONE; + } + + termkey_key_get_linecol(key, line, col); + + return TERMKEY_RES_KEY; +} + +/// Handler for CSI $y mode status reports +static TermKeyResult handle_csi_y(TermKey *tk, TermKeyKey *key, int cmd, TermKeyCsiParam *params, + int nparams) +{ + switch (cmd) { + case 'y'|'$' << 16: + case 'y'|'$' << 16 | '?' << 8: + if (nparams < 2) { + return TERMKEY_RES_NONE; + } + + int args[2]; + if (termkey_interpret_csi_param(params[0], &args[0], NULL, NULL) != TERMKEY_RES_KEY) { + return TERMKEY_RES_ERROR; + } + + if (termkey_interpret_csi_param(params[1], &args[1], NULL, NULL) != TERMKEY_RES_KEY) { + return TERMKEY_RES_ERROR; + } + + key->type = TERMKEY_TYPE_MODEREPORT; + key->code.mouse[0] = (char)(cmd >> 8); + key->code.mouse[1] = (char)(args[0] >> 8); + key->code.mouse[2] = (char)(args[0] & 0xff); + key->code.mouse[3] = (char)args[1]; + return TERMKEY_RES_KEY; + + default: + return TERMKEY_RES_NONE; + } +} + +TermKeyResult termkey_interpret_modereport(TermKey *tk, const TermKeyKey *key, int *initial, + int *mode, int *value) +{ + if (key->type != TERMKEY_TYPE_MODEREPORT) { + return TERMKEY_RES_NONE; + } + + if (initial) { + *initial = (unsigned char)key->code.mouse[0]; + } + + if (mode) { + *mode = ((uint8_t)key->code.mouse[1] << 8) | (uint8_t)key->code.mouse[2]; + } + + if (value) { + *value = (unsigned char)key->code.mouse[3]; + } + + return TERMKEY_RES_KEY; +} + +#define CHARAT(i) (tk->buffer[tk->buffstart + (i)]) + +static TermKeyResult parse_csi(TermKey *tk, size_t introlen, size_t *csi_len, + TermKeyCsiParam params[], size_t *nargs, unsigned *commandp) +{ + size_t csi_end = introlen; + + while (csi_end < tk->buffcount) { + if (CHARAT(csi_end) >= 0x40 && CHARAT(csi_end) < 0x80) { + break; + } + csi_end++; + } + + if (csi_end >= tk->buffcount) { + return TERMKEY_RES_AGAIN; + } + + unsigned char cmd = CHARAT(csi_end); + *commandp = cmd; + + char present = 0; + int argi = 0; + + size_t p = introlen; + + // See if there is an initial byte + if (CHARAT(p) >= '<' && CHARAT(p) <= '?') { + *commandp |= (unsigned)(CHARAT(p) << 8); + p++; + } + + // Now attempt to parse out up number;number;... separated values + while (p < csi_end) { + unsigned char c = CHARAT(p); + + if (c >= '0' && c < ';') { + if (!present) { + params[argi].param = &CHARAT(p); + present = 1; + } + } else if (c == ';') { + if (!present) { + params[argi].param = NULL; + params[argi].length = 0; + } else { + params[argi].length = (size_t)(&CHARAT(p) - params[argi].param); + } + present = 0; + argi++; + + if (argi > 16) { + break; + } + } else if (c >= 0x20 && c <= 0x2f) { + *commandp |= (unsigned)(c << 16); + break; + } + + p++; + } + + if (present) { + params[argi].length = (size_t)(&CHARAT(p) - params[argi].param); + argi++; + } + + *nargs = (size_t)argi; + *csi_len = csi_end + 1; + + return TERMKEY_RES_KEY; +} + +TermKeyResult termkey_interpret_csi(TermKey *tk, const TermKeyKey *key, TermKeyCsiParam params[], + size_t *nparams, unsigned *cmd) +{ + size_t dummy; + + if (tk->hightide == 0) { + return TERMKEY_RES_NONE; + } + if (key->type != TERMKEY_TYPE_UNKNOWN_CSI) { + return TERMKEY_RES_NONE; + } + + return parse_csi(tk, 0, &dummy, params, nparams, cmd); +} + +TermKeyResult termkey_interpret_csi_param(TermKeyCsiParam param, int *paramp, int subparams[], + size_t *nsubparams) +{ + if (paramp == NULL) { + return TERMKEY_RES_ERROR; + } + + if (param.param == NULL) { + *paramp = -1; + if (nsubparams) { + *nsubparams = 0; + } + return TERMKEY_RES_KEY; + } + + int arg = 0; + size_t i = 0; + size_t capacity = nsubparams ? *nsubparams : 0; + size_t length = 0; + for (; i < param.length && length <= capacity; i++) { + unsigned char c = param.param[i]; + if (c == ':') { + if (length == 0) { + *paramp = arg; + } else { + subparams[length - 1] = arg; + } + + arg = 0; + length++; + continue; + } + + assert(c >= '0' && c <= '9'); + arg = (10 * arg) + (c - '0'); + } + + if (length == 0) { + *paramp = arg; + } else { + subparams[length - 1] = arg; + } + + if (nsubparams) { + *nsubparams = length; + } + + return TERMKEY_RES_KEY; +} + +static int register_keys(void) +{ + int i; + + for (i = 0; i < 64; i++) { + csi_ss3s[i].sym = TERMKEY_SYM_UNKNOWN; + ss3s[i].sym = TERMKEY_SYM_UNKNOWN; + ss3_kpalts[i] = 0; + } + + for (i = 0; i < NCSIFUNCS; i++) { + csifuncs[i].sym = TERMKEY_SYM_UNKNOWN; + } + + register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UP, 'A'); + register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_DOWN, 'B'); + register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_RIGHT, 'C'); + register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_LEFT, 'D'); + register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BEGIN, 'E'); + register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_END, 'F'); + register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_HOME, 'H'); + register_csi_ss3(TERMKEY_TYPE_FUNCTION, 1, 'P'); + register_csi_ss3(TERMKEY_TYPE_FUNCTION, 2, 'Q'); + register_csi_ss3(TERMKEY_TYPE_FUNCTION, 3, 'R'); + register_csi_ss3(TERMKEY_TYPE_FUNCTION, 4, 'S'); + + register_csi_ss3_full(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_TAB, TERMKEY_KEYMOD_SHIFT, + TERMKEY_KEYMOD_SHIFT, 'Z'); + + register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPENTER, 'M', 0); + register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPEQUALS, 'X', '='); + register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPMULT, 'j', '*'); + register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPPLUS, 'k', '+'); + register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPCOMMA, 'l', ','); + register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPMINUS, 'm', '-'); + register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPPERIOD, 'n', '.'); + register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPDIV, 'o', '/'); + register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP0, 'p', '0'); + register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP1, 'q', '1'); + register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP2, 'r', '2'); + register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP3, 's', '3'); + register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP4, 't', '4'); + register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP5, 'u', '5'); + register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP6, 'v', '6'); + register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP7, 'w', '7'); + register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP8, 'x', '8'); + register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP9, 'y', '9'); + + register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_FIND, 1); + register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_INSERT, 2); + register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_DELETE, 3); + register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SELECT, 4); + register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEUP, 5); + register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEDOWN, 6); + register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_HOME, 7); + register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_END, 8); + + register_csifunc(TERMKEY_TYPE_FUNCTION, 1, 11); + register_csifunc(TERMKEY_TYPE_FUNCTION, 2, 12); + register_csifunc(TERMKEY_TYPE_FUNCTION, 3, 13); + register_csifunc(TERMKEY_TYPE_FUNCTION, 4, 14); + register_csifunc(TERMKEY_TYPE_FUNCTION, 5, 15); + register_csifunc(TERMKEY_TYPE_FUNCTION, 6, 17); + register_csifunc(TERMKEY_TYPE_FUNCTION, 7, 18); + register_csifunc(TERMKEY_TYPE_FUNCTION, 8, 19); + register_csifunc(TERMKEY_TYPE_FUNCTION, 9, 20); + register_csifunc(TERMKEY_TYPE_FUNCTION, 10, 21); + register_csifunc(TERMKEY_TYPE_FUNCTION, 11, 23); + register_csifunc(TERMKEY_TYPE_FUNCTION, 12, 24); + register_csifunc(TERMKEY_TYPE_FUNCTION, 13, 25); + register_csifunc(TERMKEY_TYPE_FUNCTION, 14, 26); + register_csifunc(TERMKEY_TYPE_FUNCTION, 15, 28); + register_csifunc(TERMKEY_TYPE_FUNCTION, 16, 29); + register_csifunc(TERMKEY_TYPE_FUNCTION, 17, 31); + register_csifunc(TERMKEY_TYPE_FUNCTION, 18, 32); + register_csifunc(TERMKEY_TYPE_FUNCTION, 19, 33); + register_csifunc(TERMKEY_TYPE_FUNCTION, 20, 34); + + csi_handlers['u' - 0x40] = &handle_csi_u; + + csi_handlers['M' - 0x40] = &handle_csi_m; + csi_handlers['m' - 0x40] = &handle_csi_m; + + csi_handlers['R' - 0x40] = &handle_csi_R; + + csi_handlers['y' - 0x40] = &handle_csi_y; + + keyinfo_initialised = 1; + return 1; +} + +void *new_driver_csi(TermKey *tk, const char *term) +{ + if (!keyinfo_initialised) { + if (!register_keys()) { + return NULL; + } + } + + TermKeyCsi *csi = xmalloc(sizeof *csi); + + csi->tk = tk; + csi->saved_string_id = 0; + csi->saved_string = NULL; + + return csi; +} + +void free_driver_csi(void *info) +{ + TermKeyCsi *csi = info; + + if (csi->saved_string) { + xfree(csi->saved_string); + } + + xfree(csi); +} + +static TermKeyResult peekkey_csi_csi(TermKey *tk, TermKeyCsi *csi, size_t introlen, TermKeyKey *key, + int force, size_t *nbytep) +{ + size_t csi_len; + size_t nparams = 16; + TermKeyCsiParam params[16]; + unsigned cmd; + + TermKeyResult ret = parse_csi(tk, introlen, &csi_len, params, &nparams, &cmd); + + if (ret == TERMKEY_RES_AGAIN) { + if (!force) { + return TERMKEY_RES_AGAIN; + } + + (*tk->method.emit_codepoint)(tk, '[', key); + key->modifiers |= TERMKEY_KEYMOD_ALT; + *nbytep = introlen; + return TERMKEY_RES_KEY; + } + + if (cmd == 'M' && nparams < 3) { // Mouse in X10 encoding consumes the next 3 bytes also + tk->buffstart += csi_len; + tk->buffcount -= csi_len; + + TermKeyResult mouse_result = (*tk->method.peekkey_mouse)(tk, key, nbytep); + + tk->buffstart -= csi_len; + tk->buffcount += csi_len; + + if (mouse_result == TERMKEY_RES_KEY) { + *nbytep += csi_len; + } + + return mouse_result; + } + + TermKeyResult result = TERMKEY_RES_NONE; + + // We know from the logic above that cmd must be >= 0x40 and < 0x80 + if (csi_handlers[(cmd & 0xff) - 0x40]) { + result = (*csi_handlers[(cmd & 0xff) - 0x40])(tk, key, (int)cmd, params, (int)nparams); + } + + if (result == TERMKEY_RES_NONE) { +#ifdef DEBUG + switch (args) { + case 0: + fprintf(stderr, "CSI: Unknown cmd=%c\n", (char)cmd); + break; + case 1: + fprintf(stderr, "CSI: Unknown arg1=%ld cmd=%c\n", arg[0], (char)cmd); + break; + case 2: + fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld cmd=%c\n", arg[0], arg[1], (char)cmd); + break; + case 3: + fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld arg3=%ld cmd=%c\n", arg[0], arg[1], arg[2], + (char)cmd); + break; + default: + fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld arg3=%ld ... args=%d cmd=%c\n", arg[0], + arg[1], arg[2], args, (char)cmd); + break; + } +#endif + key->type = TERMKEY_TYPE_UNKNOWN_CSI; + key->code.number = (int)cmd; + key->modifiers = 0; + + tk->hightide = csi_len - introlen; + *nbytep = introlen; // Do not yet eat the data bytes + return TERMKEY_RES_KEY; + } + + *nbytep = csi_len; + return result; +} + +static TermKeyResult peekkey_ss3(TermKey *tk, TermKeyCsi *csi, size_t introlen, TermKeyKey *key, + int force, size_t *nbytep) +{ + if (tk->buffcount < introlen + 1) { + if (!force) { + return TERMKEY_RES_AGAIN; + } + + (*tk->method.emit_codepoint)(tk, 'O', key); + key->modifiers |= TERMKEY_KEYMOD_ALT; + *nbytep = tk->buffcount; + return TERMKEY_RES_KEY; + } + + unsigned char cmd = CHARAT(introlen); + + if (cmd < 0x40 || cmd >= 0x80) { + return TERMKEY_RES_NONE; + } + + key->type = csi_ss3s[cmd - 0x40].type; + key->code.sym = csi_ss3s[cmd - 0x40].sym; + key->modifiers = csi_ss3s[cmd - 0x40].modifier_set; + + if (key->code.sym == TERMKEY_SYM_UNKNOWN) { + if (tk->flags & TERMKEY_FLAG_CONVERTKP && ss3_kpalts[cmd - 0x40]) { + key->type = TERMKEY_TYPE_UNICODE; + key->code.codepoint = (unsigned char)ss3_kpalts[cmd - 0x40]; + key->modifiers = 0; + + key->utf8[0] = (char)key->code.codepoint; + key->utf8[1] = 0; + } else { + key->type = ss3s[cmd - 0x40].type; + key->code.sym = ss3s[cmd - 0x40].sym; + key->modifiers = ss3s[cmd - 0x40].modifier_set; + } + } + + if (key->code.sym == TERMKEY_SYM_UNKNOWN) { +#ifdef DEBUG + fprintf(stderr, "CSI: Unknown SS3 %c (0x%02x)\n", (char)cmd, cmd); +#endif + return TERMKEY_RES_NONE; + } + + *nbytep = introlen + 1; + + return TERMKEY_RES_KEY; +} + +static TermKeyResult peekkey_ctrlstring(TermKey *tk, TermKeyCsi *csi, size_t introlen, + TermKeyKey *key, int force, size_t *nbytep) +{ + size_t str_end = introlen; + + while (str_end < tk->buffcount) { + if (CHARAT(str_end) == 0x07) { // BEL + break; + } + if (CHARAT(str_end) == 0x9c) { // ST + break; + } + if (CHARAT(str_end) == 0x1b + && (str_end + 1) < tk->buffcount + && CHARAT(str_end + 1) == 0x5c) { // ESC-prefixed ST + break; + } + + str_end++; + } + + if (str_end >= tk->buffcount) { + return TERMKEY_RES_AGAIN; + } + +#ifdef DEBUG + fprintf(stderr, "Found a control string: %*s", + str_end - introlen, tk->buffer + tk->buffstart + introlen); +#endif + + *nbytep = str_end + 1; + if (CHARAT(str_end) == 0x1b) { + (*nbytep)++; + } + + if (csi->saved_string) { + xfree(csi->saved_string); + } + + size_t len = str_end - introlen; + + csi->saved_string_id++; + csi->saved_string = xmalloc(len + 1); + + strncpy(csi->saved_string, (char *)tk->buffer + tk->buffstart + introlen, len); // NOLINT(runtime/printf) + csi->saved_string[len] = 0; + + key->type = (CHARAT(introlen - 1) & 0x1f) == 0x10 + ? TERMKEY_TYPE_DCS : TERMKEY_TYPE_OSC; + key->code.number = csi->saved_string_id; + key->modifiers = 0; + + return TERMKEY_RES_KEY; +} + +TermKeyResult peekkey_csi(TermKey *tk, void *info, TermKeyKey *key, int force, size_t *nbytep) +{ + if (tk->buffcount == 0) { + return tk->is_closed ? TERMKEY_RES_EOF : TERMKEY_RES_NONE; + } + + TermKeyCsi *csi = info; + + switch (CHARAT(0)) { + case 0x1b: + if (tk->buffcount < 2) { + return TERMKEY_RES_NONE; + } + + switch (CHARAT(1)) { + case 0x4f: // ESC-prefixed SS3 + return peekkey_ss3(tk, csi, 2, key, force, nbytep); + + case 0x50: // ESC-prefixed DCS + case 0x5d: // ESC-prefixed OSC + return peekkey_ctrlstring(tk, csi, 2, key, force, nbytep); + + case 0x5b: // ESC-prefixed CSI + return peekkey_csi_csi(tk, csi, 2, key, force, nbytep); + } + + return TERMKEY_RES_NONE; + + case 0x8f: // SS3 + return peekkey_ss3(tk, csi, 1, key, force, nbytep); + + case 0x90: // DCS + case 0x9d: // OSC + return peekkey_ctrlstring(tk, csi, 1, key, force, nbytep); + + case 0x9b: // CSI + return peekkey_csi_csi(tk, csi, 1, key, force, nbytep); + } + + return TERMKEY_RES_NONE; +} diff --git a/src/nvim/tui/termkey/driver-csi.h b/src/nvim/tui/termkey/driver-csi.h new file mode 100644 index 0000000000..0abd8b5c2e --- /dev/null +++ b/src/nvim/tui/termkey/driver-csi.h @@ -0,0 +1,7 @@ +#pragma once + +#include "nvim/tui/termkey/termkey_defs.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "tui/termkey/driver-csi.h.generated.h" +#endif diff --git a/src/termkey/driver-ti.c b/src/nvim/tui/termkey/driver-ti.c index 1f8ee10808..745ee9902f 100644 --- a/src/termkey/driver-ti.c +++ b/src/nvim/tui/termkey/driver-ti.c @@ -1,33 +1,28 @@ -// we want strdup() -#define _XOPEN_SOURCE 600 - -#include "termkey.h" -#include "termkey-internal.h" - -#ifdef HAVE_UNIBILIUM -# include <unibilium.h> -#else -# include <curses.h> -# include <term.h> - -/* curses.h has just polluted our namespace. We want this back */ -# undef buttons -#endif - #include <ctype.h> #include <errno.h> #include <stdbool.h> #include <stdio.h> #include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unibilium.h> + +#include "nvim/memory.h" +#include "nvim/tui/termkey/driver-ti.h" +#include "nvim/tui/termkey/termkey-internal.h" +#include "nvim/tui/termkey/termkey.h" + #ifndef _WIN32 # include <unistd.h> #else # include <io.h> #endif -#include <sys/types.h> -#include <sys/stat.h> -#define streq(a,b) (!strcmp(a,b)) +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "tui/termkey/driver-ti.c.generated.h" +#endif + +#define streq(a, b) (!strcmp(a, b)) #define MAX_FUNCNAME 9 @@ -36,9 +31,8 @@ static struct { TermKeyType type; TermKeySym sym; int mods; -} funcs[] = -{ - /* THIS LIST MUST REMAIN SORTED! */ +} funcs[] = { + // THIS LIST MUST REMAIN SORTED! { "backspace", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BACKSPACE, 0 }, { "begin", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BEGIN, 0 }, { "beg", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BEGIN, 0 }, @@ -61,12 +55,12 @@ static struct { { "mark", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_MARK, 0 }, { "message", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_MESSAGE, 0 }, { "move", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_MOVE, 0 }, - { "next", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEDOWN, 0 }, // Not quite, but it's the best we can do + { "next", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEDOWN, 0 }, // Not quite, but it's the best we can do { "npage", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEDOWN, 0 }, { "open", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_OPEN, 0 }, { "options", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_OPTIONS, 0 }, { "ppage", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEUP, 0 }, - { "previous", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEUP, 0 }, // Not quite, but it's the best we can do + { "previous", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEUP, 0 }, // Not quite, but it's the best we can do { "print", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PRINT, 0 }, { "redo", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_REDO, 0 }, { "reference", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_REFERENCE, 0 }, @@ -80,34 +74,34 @@ static struct { { "suspend", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SUSPEND, 0 }, { "undo", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UNDO, 0 }, { "up", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UP, 0 }, - { NULL }, + { NULL, 0, 0, 0 }, }; -#ifdef HAVE_UNIBILIUM static enum unibi_string unibi_lookup_str(const char *name) { - for(enum unibi_string ret = unibi_string_begin_+1; ret < unibi_string_end_; ret++) - if(streq(unibi_name_str(ret), name)) + for (enum unibi_string ret = unibi_string_begin_ + 1; ret < unibi_string_end_; ret++) { + if (streq(unibi_name_str(ret), name)) { return ret; + } + } - return -1; + return (enum unibi_string)-1; } static const char *unibi_get_str_by_name(const unibi_term *ut, const char *name) { enum unibi_string idx = unibi_lookup_str(name); - if(idx == (enum unibi_string)-1) + if (idx == (enum unibi_string)-1) { return NULL; + } return unibi_get_str(ut, idx); } -#endif -/* To be efficient at lookups, we store the byte sequence => keyinfo mapping - * in a trie. This avoids a slow linear search through a flat list of - * sequences. Because it is likely most nodes will be very sparse, we optimise - * vector to store an extent map after the database is loaded. - */ +// To be efficient at lookups, we store the byte sequence => keyinfo mapping +// in a trie. This avoids a slow linear search through a flat list of +// sequences. Because it is likely most nodes will be very sparse, we optimise +// vector to store an extent map after the database is loaded. typedef enum { TYPE_KEY, @@ -125,126 +119,110 @@ struct trie_node_key { struct trie_node_arr { trie_nodetype type; - unsigned char min, max; /* INCLUSIVE endpoints of the extent range */ - struct trie_node *arr[]; /* dynamic size at allocation time */ + unsigned char min, max; // INCLUSIVE endpoints of the extent range + struct trie_node *arr[]; // dynamic size at allocation time }; -typedef struct { - TermKey *tk; - -#ifdef HAVE_UNIBILIUM - unibi_term *unibi; /* only valid until first 'start' call */ -#else - char *term; /* only valid until first 'start' call */ -#endif - - struct trie_node *root; - - char *start_string; - char *stop_string; -} TermKeyTI; - static int insert_seq(TermKeyTI *ti, const char *seq, struct trie_node *node); static struct trie_node *new_node_key(TermKeyType type, TermKeySym sym, int modmask, int modset) { - struct trie_node_key *n = malloc(sizeof(*n)); - if(!n) - return NULL; + struct trie_node_key *n = xmalloc(sizeof(*n)); n->type = TYPE_KEY; n->key.type = type; - n->key.sym = sym; + n->key.sym = sym; n->key.modifier_mask = modmask; - n->key.modifier_set = modset; + n->key.modifier_set = modset; - return (struct trie_node*)n; + return (struct trie_node *)n; } static struct trie_node *new_node_arr(unsigned char min, unsigned char max) { - struct trie_node_arr *n = malloc(sizeof(*n) + ((int)max-min+1) * sizeof(n->arr[0])); - if(!n) - return NULL; + struct trie_node_arr *n = xmalloc(sizeof(*n) + (max - min + 1) * sizeof(n->arr[0])); n->type = TYPE_ARR; n->min = min; n->max = max; int i; - for(i = min; i <= max; i++) - n->arr[i-min] = NULL; + for (i = min; i <= max; i++) { + n->arr[i - min] = NULL; + } - return (struct trie_node*)n; + return (struct trie_node *)n; } static struct trie_node *lookup_next(struct trie_node *n, unsigned char b) { - switch(n->type) { + switch (n->type) { case TYPE_KEY: fprintf(stderr, "ABORT: lookup_next within a TYPE_KEY node\n"); abort(); - case TYPE_ARR: - { - struct trie_node_arr *nar = (struct trie_node_arr*)n; - if(b < nar->min || b > nar->max) - return NULL; - return nar->arr[b - nar->min]; + case TYPE_ARR: { + struct trie_node_arr *nar = (struct trie_node_arr *)n; + if (b < nar->min || b > nar->max) { + return NULL; } + return nar->arr[b - nar->min]; + } } - return NULL; // Never reached but keeps compiler happy + return NULL; // Never reached but keeps compiler happy } static void free_trie(struct trie_node *n) { - switch(n->type) { + switch (n->type) { case TYPE_KEY: break; - case TYPE_ARR: - { - struct trie_node_arr *nar = (struct trie_node_arr*)n; - int i; - for(i = nar->min; i <= nar->max; i++) - if(nar->arr[i - nar->min]) - free_trie(nar->arr[i - nar->min]); - break; + case TYPE_ARR: { + struct trie_node_arr *nar = (struct trie_node_arr *)n; + int i; + for (i = nar->min; i <= nar->max; i++) { + if (nar->arr[i - nar->min]) { + free_trie(nar->arr[i - nar->min]); + } } + break; + } } - free(n); + xfree(n); } static struct trie_node *compress_trie(struct trie_node *n) { - if(!n) + if (!n) { return NULL; + } - switch(n->type) { + switch (n->type) { case TYPE_KEY: return n; - case TYPE_ARR: - { - struct trie_node_arr *nar = (struct trie_node_arr*)n; - unsigned char min, max; - // Find the real bounds - for(min = 0; !nar->arr[min]; min++) - if(min == 255 && !nar->arr[min]) { - free(nar); - return new_node_arr(1, 0); - } - - for(max = 0xff; !nar->arr[max]; max--) - ; - - struct trie_node_arr *new = (struct trie_node_arr*)new_node_arr(min, max); - int i; - for(i = min; i <= max; i++) - new->arr[i - min] = compress_trie(nar->arr[i]); - - free(nar); - return (struct trie_node*)new; + case TYPE_ARR: { + struct trie_node_arr *nar = (struct trie_node_arr *)n; + unsigned char min, max; + // Find the real bounds + for (min = 0; !nar->arr[min]; min++) { + if (min == 255 && !nar->arr[min]) { + xfree(nar); + return new_node_arr(1, 0); + } + } + + for (max = 0xff; !nar->arr[max]; max--) {} + + struct trie_node_arr *new = (struct trie_node_arr *)new_node_arr(min, max); + int i; + for (i = min; i <= max; i++) { + new->arr[i - min] = compress_trie(nar->arr[i]); } + + xfree(nar); + return (struct trie_node *)new; + } } return n; @@ -254,21 +232,20 @@ static bool try_load_terminfo_key(TermKeyTI *ti, const char *name, struct keyinf { const char *value = NULL; -#ifdef HAVE_UNIBILIUM - if(ti->unibi) + if (ti->unibi) { value = unibi_get_str_by_name(ti->unibi, name); -#else - if(ti->term) - value = tigetstr(name); -#endif + } - if(ti->tk->ti_getstr_hook) + if (ti->tk->ti_getstr_hook) { value = (ti->tk->ti_getstr_hook)(name, value, ti->tk->ti_getstr_hook_data); + } - if(!value || value == (char*)-1 || !value[0]) + if (!value || value == (char *)-1 || !value[0]) { return false; + } - struct trie_node *node = new_node_key(info->type, info->sym, info->modifier_mask, info->modifier_set); + struct trie_node *node = new_node_key(info->type, info->sym, info->modifier_mask, + info->modifier_set); insert_seq(ti, value, node); return true; @@ -278,288 +255,259 @@ static int load_terminfo(TermKeyTI *ti) { int i; -#ifdef HAVE_UNIBILIUM unibi_term *unibi = ti->unibi; -#else - { - int err; - - /* Have to cast away the const. But it's OK - we know terminfo won't really - * modify term */ - if(setupterm((char*)ti->term, 1, &err) != OK) - return 0; - } -#endif ti->root = new_node_arr(0, 0xff); - if(!ti->root) + if (!ti->root) { return 0; + } - /* First the regular key strings - */ - for(i = 0; funcs[i].funcname; i++) { + // First the regular key strings + for (i = 0; funcs[i].funcname; i++) { char name[MAX_FUNCNAME + 5 + 1]; - sprintf(name, "key_%s", funcs[i].funcname); - if(!try_load_terminfo_key(ti, name, &(struct keyinfo){ - .type = funcs[i].type, - .sym = funcs[i].sym, - .modifier_mask = funcs[i].mods, - .modifier_set = funcs[i].mods, - })) + sprintf(name, "key_%s", funcs[i].funcname); // NOLINT(runtime/printf) + if (!try_load_terminfo_key(ti, name, &(struct keyinfo){ + .type = funcs[i].type, + .sym = funcs[i].sym, + .modifier_mask = funcs[i].mods, + .modifier_set = funcs[i].mods, + })) { continue; + } - /* Maybe it has a shifted version */ - sprintf(name, "key_s%s", funcs[i].funcname); + // Maybe it has a shifted version + sprintf(name, "key_s%s", funcs[i].funcname); // NOLINT(runtime/printf) try_load_terminfo_key(ti, name, &(struct keyinfo){ - .type = funcs[i].type, - .sym = funcs[i].sym, - .modifier_mask = funcs[i].mods | TERMKEY_KEYMOD_SHIFT, - .modifier_set = funcs[i].mods | TERMKEY_KEYMOD_SHIFT, + .type = funcs[i].type, + .sym = funcs[i].sym, + .modifier_mask = funcs[i].mods | TERMKEY_KEYMOD_SHIFT, + .modifier_set = funcs[i].mods | TERMKEY_KEYMOD_SHIFT, }); } - /* Now the F<digit> keys - */ - for(i = 1; i < 255; i++) { + // Now the F<digit> keys + for (i = 1; i < 255; i++) { char name[9]; - sprintf(name, "key_f%d", i); - if(!try_load_terminfo_key(ti, name, &(struct keyinfo){ - .type = TERMKEY_TYPE_FUNCTION, - .sym = i, - .modifier_mask = 0, - .modifier_set = 0, - })) + sprintf(name, "key_f%d", i); // NOLINT(runtime/printf) + if (!try_load_terminfo_key(ti, name, &(struct keyinfo){ + .type = TERMKEY_TYPE_FUNCTION, + .sym = i, + .modifier_mask = 0, + .modifier_set = 0, + })) { break; + } } - /* Finally mouse mode */ + // Finally mouse mode { const char *value = NULL; -#ifdef HAVE_UNIBILIUM - if(ti->unibi) + if (ti->unibi) { value = unibi_get_str_by_name(ti->unibi, "key_mouse"); -#else - if(ti->term) - value = tigetstr("key_mouse"); -#endif + } - if(ti->tk->ti_getstr_hook) + if (ti->tk->ti_getstr_hook) { value = (ti->tk->ti_getstr_hook)("key_mouse", value, ti->tk->ti_getstr_hook_data); + } - /* Some terminfos (e.g. xterm-1006) claim a different key_mouse that won't - * give X10 encoding. We'll only accept this if it's exactly "\e[M" - */ - if(value && streq(value, "\x1b[M")) { + // Some terminfos (e.g. xterm-1006) claim a different key_mouse that won't + // give X10 encoding. We'll only accept this if it's exactly "\e[M" + if (value && streq(value, "\x1b[M")) { struct trie_node *node = new_node_key(TERMKEY_TYPE_MOUSE, 0, 0, 0); insert_seq(ti, value, node); } } - /* Take copies of these terminfo strings, in case we build multiple termkey - * instances for multiple different termtypes, and it's different by the - * time we want to use it - */ -#ifdef HAVE_UNIBILIUM - const char *keypad_xmit = unibi ? - unibi_get_str(unibi, unibi_keypad_xmit) : - NULL; -#endif + // Take copies of these terminfo strings, in case we build multiple termkey + // instances for multiple different termtypes, and it's different by the + // time we want to use it + const char *keypad_xmit = unibi + ? unibi_get_str(unibi, unibi_keypad_xmit) + : NULL; - if(keypad_xmit) - ti->start_string = strdup(keypad_xmit); - else + if (keypad_xmit) { + ti->start_string = xstrdup(keypad_xmit); + } else { ti->start_string = NULL; + } -#ifdef HAVE_UNIBILIUM - const char *keypad_local = unibi ? - unibi_get_str(unibi, unibi_keypad_local) : - NULL; -#endif + const char *keypad_local = unibi + ? unibi_get_str(unibi, unibi_keypad_local) + : NULL; - if(keypad_local) - ti->stop_string = strdup(keypad_local); - else + if (keypad_local) { + ti->stop_string = xstrdup(keypad_local); + } else { ti->stop_string = NULL; + } -#ifdef HAVE_UNIBILIUM - if(unibi) + if (unibi) { unibi_destroy(unibi); + } ti->unibi = NULL; -#else - if(ti->term) - free(ti->term); - - ti->term = NULL; -#endif ti->root = compress_trie(ti->root); return 1; } -static void *new_driver(TermKey *tk, const char *term) +void *new_driver_ti(TermKey *tk, const char *term) { - TermKeyTI *ti = malloc(sizeof *ti); - if(!ti) - return NULL; + TermKeyTI *ti = xmalloc(sizeof *ti); ti->tk = tk; ti->root = NULL; ti->start_string = NULL; ti->stop_string = NULL; -#ifdef HAVE_UNIBILIUM ti->unibi = unibi_from_term(term); int saved_errno = errno; - if(!ti->unibi && saved_errno != ENOENT) { - free(ti); + if (!ti->unibi && saved_errno != ENOENT) { + xfree(ti); return NULL; } - /* ti->unibi may be NULL if errno == ENOENT. That means the terminal wasn't - * known. Lets keep going because if we get getstr hook that might invent - * new strings for us - */ -#else - { - int err; - - ti->term = NULL; - - /* Have to cast away the const. But it's OK - we know terminfo won't really - * modify term */ - if(setupterm((char*)term, 1, &err) == OK) - ti->term = strdup(term); - } -#endif + // ti->unibi may be NULL if errno == ENOENT. That means the terminal wasn't + // known. Lets keep going because if we get getstr hook that might invent + // new strings for us return ti; } -static int start_driver(TermKey *tk, void *info) +int start_driver_ti(TermKey *tk, void *info) { TermKeyTI *ti = info; struct stat statbuf; char *start_string; size_t len; - if(!ti->root) + if (!ti->root) { load_terminfo(ti); + } start_string = ti->start_string; - if(tk->fd == -1 || !start_string) + if (tk->fd == -1 || !start_string) { return 1; + } - /* The terminfo database will contain keys in application cursor key mode. - * We may need to enable that mode - */ + // The terminfo database will contain keys in application cursor key mode. + // We may need to enable that mode - /* There's no point trying to write() to a pipe */ - if(fstat(tk->fd, &statbuf) == -1) + // There's no point trying to write() to a pipe + if (fstat(tk->fd, &statbuf) == -1) { return 0; + } #ifndef _WIN32 - if(S_ISFIFO(statbuf.st_mode)) + if (S_ISFIFO(statbuf.st_mode)) { return 1; + } #endif // Can't call putp or tputs because they suck and don't give us fd control len = strlen(start_string); - while(len) { - size_t written = write(tk->fd, start_string, len); - if(written == -1) + while (len) { + ssize_t result = write(tk->fd, start_string, (unsigned)len); + if (result < 0) { return 0; + } + size_t written = (size_t)result; start_string += written; len -= written; } return 1; } -static int stop_driver(TermKey *tk, void *info) +int stop_driver_ti(TermKey *tk, void *info) { TermKeyTI *ti = info; struct stat statbuf; char *stop_string = ti->stop_string; size_t len; - if(tk->fd == -1 || !stop_string) + if (tk->fd == -1 || !stop_string) { return 1; + } - /* There's no point trying to write() to a pipe */ - if(fstat(tk->fd, &statbuf) == -1) + // There's no point trying to write() to a pipe + if (fstat(tk->fd, &statbuf) == -1) { return 0; + } #ifndef _WIN32 - if(S_ISFIFO(statbuf.st_mode)) + if (S_ISFIFO(statbuf.st_mode)) { return 1; + } #endif - /* The terminfo database will contain keys in application cursor key mode. - * We may need to enable that mode - */ + // The terminfo database will contain keys in application cursor key mode. + // We may need to enable that mode // Can't call putp or tputs because they suck and don't give us fd control len = strlen(stop_string); - while(len) { - size_t written = write(tk->fd, stop_string, len); - if(written == -1) + while (len) { + ssize_t result = write(tk->fd, stop_string, (unsigned)len); + if (result < 0) { return 0; + } + size_t written = (size_t)result; stop_string += written; len -= written; } return 1; } -static void free_driver(void *info) +void free_driver_ti(void *info) { TermKeyTI *ti = info; free_trie(ti->root); - if(ti->start_string) - free(ti->start_string); + if (ti->start_string) { + xfree(ti->start_string); + } - if(ti->stop_string) - free(ti->stop_string); + if (ti->stop_string) { + xfree(ti->stop_string); + } -#ifdef HAVE_UNIBILIUM - if(ti->unibi) + if (ti->unibi) { unibi_destroy(ti->unibi); -#else - if(ti->term) - free(ti->term); -#endif + } - free(ti); + xfree(ti); } #define CHARAT(i) (tk->buffer[tk->buffstart + (i)]) -static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force, size_t *nbytep) +TermKeyResult peekkey_ti(TermKey *tk, void *info, TermKeyKey *key, int force, size_t *nbytep) { TermKeyTI *ti = info; - if(tk->buffcount == 0) + if (tk->buffcount == 0) { return tk->is_closed ? TERMKEY_RES_EOF : TERMKEY_RES_NONE; + } struct trie_node *p = ti->root; - unsigned int pos = 0; - while(pos < tk->buffcount) { + unsigned pos = 0; + while (pos < tk->buffcount) { p = lookup_next(p, CHARAT(pos)); - if(!p) + if (!p) { break; + } pos++; - if(p->type != TYPE_KEY) + if (p->type != TYPE_KEY) { continue; + } - struct trie_node_key *nk = (struct trie_node_key*)p; - if(nk->key.type == TERMKEY_TYPE_MOUSE) { + struct trie_node_key *nk = (struct trie_node_key *)p; + if (nk->key.type == TERMKEY_TYPE_MOUSE) { tk->buffstart += pos; tk->buffcount -= pos; @@ -568,14 +516,15 @@ static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force tk->buffstart -= pos; tk->buffcount += pos; - if(mouse_result == TERMKEY_RES_KEY) + if (mouse_result == TERMKEY_RES_KEY) { *nbytep += pos; + } return mouse_result; } - key->type = nk->key.type; - key->code.sym = nk->key.sym; + key->type = nk->key.type; + key->code.sym = nk->key.sym; key->modifiers = nk->key.modifier_set; *nbytep = pos; return TERMKEY_RES_KEY; @@ -583,8 +532,9 @@ static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force // If p is not NULL then we hadn't walked off the end yet, so we have a // partial match - if(p && !force) + if (p && !force) { return TERMKEY_RES_AGAIN; + } return TERMKEY_RES_NONE; } @@ -597,39 +547,42 @@ static int insert_seq(TermKeyTI *ti, const char *seq, struct trie_node *node) // Unsigned because we'll be using it as an array subscript unsigned char b; - while((b = seq[pos])) { + while ((b = (unsigned char)seq[pos])) { struct trie_node *next = lookup_next(p, b); - if(!next) + if (!next) { break; + } p = next; pos++; } - while((b = seq[pos])) { + while ((b = (unsigned char)seq[pos])) { struct trie_node *next; - if(seq[pos+1]) + if (seq[pos + 1]) { // Intermediate node next = new_node_arr(0, 0xff); - else + } else { // Final key node next = node; + } - if(!next) + if (!next) { return 0; + } - switch(p->type) { - case TYPE_ARR: - { - struct trie_node_arr *nar = (struct trie_node_arr*)p; - if(b < nar->min || b > nar->max) { - fprintf(stderr, "ASSERT FAIL: Trie insert at 0x%02x is outside of extent bounds (0x%02x..0x%02x)\n", - b, nar->min, nar->max); - abort(); - } - nar->arr[b - nar->min] = next; - p = next; - break; + switch (p->type) { + case TYPE_ARR: { + struct trie_node_arr *nar = (struct trie_node_arr *)p; + if (b < nar->min || b > nar->max) { + fprintf(stderr, + "ASSERT FAIL: Trie insert at 0x%02x is outside of extent bounds (0x%02x..0x%02x)\n", + b, nar->min, nar->max); + abort(); } + nar->arr[b - nar->min] = next; + p = next; + break; + } case TYPE_KEY: fprintf(stderr, "ASSERT FAIL: Tried to insert child node in TYPE_KEY\n"); abort(); @@ -640,15 +593,3 @@ static int insert_seq(TermKeyTI *ti, const char *seq, struct trie_node *node) return 1; } - -struct TermKeyDriver termkey_driver_ti = { - .name = "terminfo", - - .new_driver = new_driver, - .free_driver = free_driver, - - .start_driver = start_driver, - .stop_driver = stop_driver, - - .peekkey = peekkey, -}; diff --git a/src/nvim/tui/termkey/driver-ti.h b/src/nvim/tui/termkey/driver-ti.h new file mode 100644 index 0000000000..df9bd72d5b --- /dev/null +++ b/src/nvim/tui/termkey/driver-ti.h @@ -0,0 +1,7 @@ +#pragma once + +#include "nvim/tui/termkey/termkey_defs.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "tui/termkey/driver-ti.h.generated.h" +#endif diff --git a/src/termkey/termkey-internal.h b/src/nvim/tui/termkey/termkey-internal.h index c300b02616..107591f950 100644 --- a/src/termkey/termkey-internal.h +++ b/src/nvim/tui/termkey/termkey-internal.h @@ -1,31 +1,29 @@ -#ifndef GUARD_TERMKEY_INTERNAL_H_ -#define GUARD_TERMKEY_INTERNAL_H_ +#pragma once -#define HAVE_TERMIOS +#include <stdint.h> + +#include "nvim/tui/termkey/termkey_defs.h" +#define HAVE_TERMIOS #ifdef _WIN32 # undef HAVE_TERMIOS #endif -#include "termkey.h" - -#include <stdint.h> #ifdef HAVE_TERMIOS # include <termios.h> #endif #ifdef _MSC_VER -#include <BaseTsd.h> +# include <BaseTsd.h> typedef SSIZE_T ssize_t; #endif -struct TermKeyDriver -{ - const char *name; - void *(*new_driver)(TermKey *tk, const char *term); - void (*free_driver)(void *info); - int (*start_driver)(TermKey *tk, void *info); - int (*stop_driver)(TermKey *tk, void *info); +struct TermKeyDriver { + const char *name; + void *(*new_driver)(TermKey *tk, const char *term); + void (*free_driver)(void *info); + int (*start_driver)(TermKey *tk, void *info); + int (*stop_driver)(TermKey *tk, void *info); TermKeyResult (*peekkey)(TermKey *tk, void *info, TermKeyKey *key, int force, size_t *nbytes); }; @@ -38,21 +36,21 @@ struct keyinfo { struct TermKeyDriverNode; struct TermKeyDriverNode { - struct TermKeyDriver *driver; - void *info; + struct TermKeyDriver *driver; + void *info; struct TermKeyDriverNode *next; }; struct TermKey { - int fd; - int flags; - int canonflags; + int fd; + int flags; + int canonflags; unsigned char *buffer; - size_t buffstart; // First offset in buffer - size_t buffcount; // NUMBER of entires valid in buffer - size_t buffsize; // Total malloc'ed size - size_t hightide; /* Position beyond buffstart at which peekkey() should next start - * normally 0, but see also termkey_interpret_csi */ + size_t buffstart; // First offset in buffer + size_t buffcount; // NUMBER of entires valid in buffer + size_t buffsize; // Total malloc'ed size + size_t hightide; // Position beyond buffstart at which peekkey() should next start + // normally 0, but see also termkey_interpret_csi #ifdef HAVE_TERMIOS struct termios restore_termios; @@ -62,12 +60,12 @@ struct TermKey { TermKey_Terminfo_Getstr_Hook *ti_getstr_hook; void *ti_getstr_hook_data; - int waittime; // msec + int waittime; // msec - char is_closed; - char is_started; + char is_closed; + char is_started; - int nkeynames; + int nkeynames; const char **keynames; // There are 32 C0 codes @@ -78,7 +76,7 @@ struct TermKey { // Now some "protected" methods for the driver to call but which we don't // want exported as real symbols in the library struct { - void (*emit_codepoint)(TermKey *tk, long codepoint, TermKeyKey *key); + void (*emit_codepoint)(TermKey *tk, int codepoint, TermKeyKey *key); TermKeyResult (*peekkey_simple)(TermKey *tk, TermKeyKey *key, int force, size_t *nbytes); TermKeyResult (*peekkey_mouse)(TermKey *tk, TermKeyKey *key, size_t *nbytes); } method; @@ -86,27 +84,26 @@ struct TermKey { static inline void termkey_key_get_linecol(const TermKeyKey *key, int *line, int *col) { - if(col) - *col = (unsigned char)key->code.mouse[1] | ((unsigned char)key->code.mouse[3] & 0x0f) << 8; + if (col) { + *col = (unsigned char)key->code.mouse[1] | ((unsigned char)key->code.mouse[3] & 0x0f) << 8; + } - if(line) + if (line) { *line = (unsigned char)key->code.mouse[2] | ((unsigned char)key->code.mouse[3] & 0x70) << 4; + } } static inline void termkey_key_set_linecol(TermKeyKey *key, int line, int col) { - if(line > 0xfff) + if (line > 0xfff) { line = 0xfff; + } - if(col > 0x7ff) + if (col > 0x7ff) { col = 0x7ff; + } - key->code.mouse[1] = (line & 0x0ff); - key->code.mouse[2] = (col & 0x0ff); + key->code.mouse[1] = (char)(line & 0x0ff); + key->code.mouse[2] = (char)(col & 0x0ff); key->code.mouse[3] = (line & 0xf00) >> 8 | (col & 0x300) >> 4; } - -extern struct TermKeyDriver termkey_driver_csi; -extern struct TermKeyDriver termkey_driver_ti; - -#endif diff --git a/src/nvim/tui/termkey/termkey.c b/src/nvim/tui/termkey/termkey.c new file mode 100644 index 0000000000..e6440118f3 --- /dev/null +++ b/src/nvim/tui/termkey/termkey.c @@ -0,0 +1,1315 @@ +#include <ctype.h> +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> + +#include "nvim/mbyte.h" +#include "nvim/memory.h" +#include "nvim/tui/termkey/driver-csi.h" +#include "nvim/tui/termkey/driver-ti.h" +#include "nvim/tui/termkey/termkey-internal.h" +#include "nvim/tui/termkey/termkey.h" +#include "nvim/tui/termkey/termkey_defs.h" + +#ifndef _WIN32 +# include <poll.h> +# include <strings.h> +# include <unistd.h> +#else +# include <io.h> +#endif + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "tui/termkey/termkey.c.generated.h" +#endif + +#ifdef _MSC_VER +# define strcaseeq(a, b) (_stricmp(a, b) == 0) +#else +# define strcaseeq(a, b) (strcasecmp(a, b) == 0) +#endif + +struct TermKeyDriver termkey_driver_ti = { + .name = "terminfo", + + .new_driver = new_driver_ti, + .free_driver = free_driver_ti, + + .start_driver = start_driver_ti, + .stop_driver = stop_driver_ti, + + .peekkey = peekkey_ti, +}; + +struct TermKeyDriver termkey_driver_csi = { + .name = "CSI", + + .new_driver = new_driver_csi, + .free_driver = free_driver_csi, + + .peekkey = peekkey_csi, +}; + +static struct TermKeyDriver *drivers[] = { + &termkey_driver_ti, + &termkey_driver_csi, + NULL, +}; + +static struct { + TermKeySym sym; + const char *name; +} keynames[] = { + { TERMKEY_SYM_NONE, "NONE" }, + { TERMKEY_SYM_BACKSPACE, "Backspace" }, + { TERMKEY_SYM_TAB, "Tab" }, + { TERMKEY_SYM_ENTER, "Enter" }, + { TERMKEY_SYM_ESCAPE, "Escape" }, + { TERMKEY_SYM_SPACE, "Space" }, + { TERMKEY_SYM_DEL, "DEL" }, + { TERMKEY_SYM_UP, "Up" }, + { TERMKEY_SYM_DOWN, "Down" }, + { TERMKEY_SYM_LEFT, "Left" }, + { TERMKEY_SYM_RIGHT, "Right" }, + { TERMKEY_SYM_BEGIN, "Begin" }, + { TERMKEY_SYM_FIND, "Find" }, + { TERMKEY_SYM_INSERT, "Insert" }, + { TERMKEY_SYM_DELETE, "Delete" }, + { TERMKEY_SYM_SELECT, "Select" }, + { TERMKEY_SYM_PAGEUP, "PageUp" }, + { TERMKEY_SYM_PAGEDOWN, "PageDown" }, + { TERMKEY_SYM_HOME, "Home" }, + { TERMKEY_SYM_END, "End" }, + { TERMKEY_SYM_CANCEL, "Cancel" }, + { TERMKEY_SYM_CLEAR, "Clear" }, + { TERMKEY_SYM_CLOSE, "Close" }, + { TERMKEY_SYM_COMMAND, "Command" }, + { TERMKEY_SYM_COPY, "Copy" }, + { TERMKEY_SYM_EXIT, "Exit" }, + { TERMKEY_SYM_HELP, "Help" }, + { TERMKEY_SYM_MARK, "Mark" }, + { TERMKEY_SYM_MESSAGE, "Message" }, + { TERMKEY_SYM_MOVE, "Move" }, + { TERMKEY_SYM_OPEN, "Open" }, + { TERMKEY_SYM_OPTIONS, "Options" }, + { TERMKEY_SYM_PRINT, "Print" }, + { TERMKEY_SYM_REDO, "Redo" }, + { TERMKEY_SYM_REFERENCE, "Reference" }, + { TERMKEY_SYM_REFRESH, "Refresh" }, + { TERMKEY_SYM_REPLACE, "Replace" }, + { TERMKEY_SYM_RESTART, "Restart" }, + { TERMKEY_SYM_RESUME, "Resume" }, + { TERMKEY_SYM_SAVE, "Save" }, + { TERMKEY_SYM_SUSPEND, "Suspend" }, + { TERMKEY_SYM_UNDO, "Undo" }, + { TERMKEY_SYM_KP0, "KP0" }, + { TERMKEY_SYM_KP1, "KP1" }, + { TERMKEY_SYM_KP2, "KP2" }, + { TERMKEY_SYM_KP3, "KP3" }, + { TERMKEY_SYM_KP4, "KP4" }, + { TERMKEY_SYM_KP5, "KP5" }, + { TERMKEY_SYM_KP6, "KP6" }, + { TERMKEY_SYM_KP7, "KP7" }, + { TERMKEY_SYM_KP8, "KP8" }, + { TERMKEY_SYM_KP9, "KP9" }, + { TERMKEY_SYM_KPENTER, "KPEnter" }, + { TERMKEY_SYM_KPPLUS, "KPPlus" }, + { TERMKEY_SYM_KPMINUS, "KPMinus" }, + { TERMKEY_SYM_KPMULT, "KPMult" }, + { TERMKEY_SYM_KPDIV, "KPDiv" }, + { TERMKEY_SYM_KPCOMMA, "KPComma" }, + { TERMKEY_SYM_KPPERIOD, "KPPeriod" }, + { TERMKEY_SYM_KPEQUALS, "KPEquals" }, + { 0, NULL }, +}; + +// Mouse event names +static const char *evnames[] = { "Unknown", "Press", "Drag", "Release" }; + +#define CHARAT(i) (tk->buffer[tk->buffstart + (i)]) + +#ifdef DEBUG +// Some internal debugging functions + +static void print_buffer(TermKey *tk) +{ + int i; + for (i = 0; i < tk->buffcount && i < 20; i++) { + fprintf(stderr, "%02x ", CHARAT(i)); + } + if (tk->buffcount > 20) { + fprintf(stderr, "..."); + } +} + +static void print_key(TermKey *tk, TermKeyKey *key) +{ + switch (key->type) { + case TERMKEY_TYPE_UNICODE: + fprintf(stderr, "Unicode codepoint=U+%04lx utf8='%s'", key->code.codepoint, key->utf8); + break; + case TERMKEY_TYPE_FUNCTION: + fprintf(stderr, "Function F%d", key->code.number); + break; + case TERMKEY_TYPE_KEYSYM: + fprintf(stderr, "Keysym sym=%d(%s)", key->code.sym, termkey_get_keyname(tk, key->code.sym)); + break; + case TERMKEY_TYPE_MOUSE: { + TermKeyMouseEvent ev; + int button, line, col; + termkey_interpret_mouse(tk, key, &ev, &button, &line, &col); + fprintf(stderr, "Mouse ev=%d button=%d pos=(%d,%d)\n", ev, button, line, col); + } + break; + case TERMKEY_TYPE_POSITION: { + int line, col; + termkey_interpret_position(tk, key, &line, &col); + fprintf(stderr, "Position report pos=(%d,%d)\n", line, col); + } + break; + case TERMKEY_TYPE_MODEREPORT: { + int initial, mode, value; + termkey_interpret_modereport(tk, key, &initial, &mode, &value); + fprintf(stderr, "Mode report mode=%s %d val=%d\n", initial == '?' ? "DEC" : "ANSI", mode, + value); + } + break; + case TERMKEY_TYPE_DCS: + fprintf(stderr, "Device Control String"); + break; + case TERMKEY_TYPE_OSC: + fprintf(stderr, "Operating System Control"); + break; + case TERMKEY_TYPE_UNKNOWN_CSI: + fprintf(stderr, "unknown CSI\n"); + break; + } + + int m = key->modifiers; + fprintf(stderr, " mod=%s%s%s+%02x", + (m & TERMKEY_KEYMOD_CTRL ? "C" : ""), + (m & TERMKEY_KEYMOD_ALT ? "A" : ""), + (m & TERMKEY_KEYMOD_SHIFT ? "S" : ""), + m & ~(TERMKEY_KEYMOD_CTRL|TERMKEY_KEYMOD_ALT|TERMKEY_KEYMOD_SHIFT)); +} + +static const char *res2str(TermKeyResult res) +{ + static char errorbuffer[256]; + + switch (res) { + case TERMKEY_RES_KEY: + return "TERMKEY_RES_KEY"; + case TERMKEY_RES_EOF: + return "TERMKEY_RES_EOF"; + case TERMKEY_RES_AGAIN: + return "TERMKEY_RES_AGAIN"; + case TERMKEY_RES_NONE: + return "TERMKEY_RES_NONE"; + case TERMKEY_RES_ERROR: + snprintf(errorbuffer, sizeof errorbuffer, "TERMKEY_RES_ERROR(errno=%d)\n", errno); + return (const char *)errorbuffer; + } + + return "unknown"; +} +#endif + +TermKeyResult termkey_interpret_string(TermKey *tk, const TermKeyKey *key, const char **strp) +{ + struct TermKeyDriverNode *p; + for (p = tk->drivers; p; p = p->next) { + if (p->driver == &termkey_driver_csi) { + break; + } + } + + if (!p) { + return TERMKEY_RES_NONE; + } + + if (key->type != TERMKEY_TYPE_DCS + && key->type != TERMKEY_TYPE_OSC) { + return TERMKEY_RES_NONE; + } + + TermKeyCsi *csi = p->info; + + if (csi->saved_string_id != key->code.number) { + return TERMKEY_RES_NONE; + } + + *strp = csi->saved_string; + + return TERMKEY_RES_KEY; +} + +/// Similar to snprintf(str, size, "%s", src) except it turns CamelCase into +/// space separated values +static int snprint_cameltospaces(char *str, size_t size, const char *src) +{ + int prev_lower = 0; + size_t l = 0; + while (*src && l < size - 1) { + if (isupper(*src) && prev_lower) { + if (str) { + str[l++] = ' '; + } + if (l >= size - 1) { + break; + } + } + prev_lower = islower(*src); + str[l++] = (char)tolower(*src++); + } + str[l] = 0; + // For consistency with snprintf, return the number of bytes that would have + // been written, excluding '\0' + while (*src) { + if (isupper(*src) && prev_lower) { + l++; + } + prev_lower = islower(*src); + src++; l++; + } + return (int)l; +} + +/// Similar to strcmp(str, strcamel, n) except that: +/// it compares CamelCase in strcamel with space separated values in str; +/// it takes char**s and updates them +/// n counts bytes of strcamel, not str +static int strpncmp_camel(const char **strp, const char **strcamelp, size_t n) +{ + const char *str = *strp, *strcamel = *strcamelp; + int prev_lower = 0; + + for (; (*str || *strcamel) && n; n--) { + char b = (char)tolower(*strcamel); + if (isupper(*strcamel) && prev_lower) { + if (*str != ' ') { + break; + } + str++; + if (*str != b) { + break; + } + } else if (*str != b) { + break; + } + + prev_lower = islower(*strcamel); + + str++; + strcamel++; + } + + *strp = str; + *strcamelp = strcamel; + return *str - *strcamel; +} + +static TermKey *termkey_alloc(void) +{ + TermKey *tk = xmalloc(sizeof(TermKey)); + + // Default all the object fields but don't allocate anything + + tk->fd = -1; + tk->flags = 0; + tk->canonflags = 0; + + tk->buffer = NULL; + tk->buffstart = 0; + tk->buffcount = 0; + tk->buffsize = 256; // bytes + tk->hightide = 0; + +#ifdef HAVE_TERMIOS + tk->restore_termios_valid = 0; +#endif + + tk->ti_getstr_hook = NULL; + tk->ti_getstr_hook_data = NULL; + + tk->waittime = 50; // msec + + tk->is_closed = 0; + tk->is_started = 0; + + tk->nkeynames = 64; + tk->keynames = NULL; + + for (int i = 0; i < 32; i++) { + tk->c0[i].sym = TERMKEY_SYM_NONE; + } + + tk->drivers = NULL; + + tk->method.emit_codepoint = &emit_codepoint; + tk->method.peekkey_simple = &peekkey_simple; + tk->method.peekkey_mouse = &peekkey_mouse; + + return tk; +} + +static int termkey_init(TermKey *tk, const char *term) +{ + tk->buffer = xmalloc(tk->buffsize); + tk->keynames = xmalloc(sizeof(tk->keynames[0]) * (size_t)tk->nkeynames); + + int i; + for (i = 0; i < tk->nkeynames; i++) { + tk->keynames[i] = NULL; + } + + for (i = 0; keynames[i].name; i++) { + if (termkey_register_keyname(tk, keynames[i].sym, keynames[i].name) == -1) { + goto abort_free_keynames; + } + } + + register_c0(tk, TERMKEY_SYM_TAB, 0x09, NULL); + register_c0(tk, TERMKEY_SYM_ENTER, 0x0d, NULL); + register_c0(tk, TERMKEY_SYM_ESCAPE, 0x1b, NULL); + + struct TermKeyDriverNode *tail = NULL; + + for (i = 0; drivers[i]; i++) { + void *info = (*drivers[i]->new_driver)(tk, term); + if (!info) { + continue; + } + +#ifdef DEBUG + fprintf(stderr, "Loading the %s driver...\n", drivers[i]->name); +#endif + + struct TermKeyDriverNode *thisdrv = xmalloc(sizeof(*thisdrv)); + if (!thisdrv) { + goto abort_free_drivers; + } + + thisdrv->driver = drivers[i]; + thisdrv->info = info; + thisdrv->next = NULL; + + if (!tail) { + tk->drivers = thisdrv; + } else { + tail->next = thisdrv; + } + + tail = thisdrv; + +#ifdef DEBUG + fprintf(stderr, "Loaded %s driver\n", drivers[i]->name); +#endif + } + + if (!tk->drivers) { + errno = ENOENT; + goto abort_free_keynames; + } + + return 1; + +abort_free_drivers: + for (struct TermKeyDriverNode *p = tk->drivers; p;) { + (*p->driver->free_driver)(p->info); + struct TermKeyDriverNode *next = p->next; + xfree(p); + p = next; + } + +abort_free_keynames: + xfree(tk->keynames); + xfree(tk->buffer); + + return 0; +} + +TermKey *termkey_new_abstract(const char *term, int flags) +{ + TermKey *tk = termkey_alloc(); + if (!tk) { + return NULL; + } + + tk->fd = -1; + + termkey_set_flags(tk, flags); + + if (!termkey_init(tk, term)) { + xfree(tk); + return NULL; + } + + if (!(flags & TERMKEY_FLAG_NOSTART) && !termkey_start(tk)) { + goto abort; + } + + return tk; + +abort: + xfree(tk); + return NULL; +} + +void termkey_free(TermKey *tk) +{ + xfree(tk->buffer); tk->buffer = NULL; + xfree(tk->keynames); tk->keynames = NULL; + + struct TermKeyDriverNode *p; + for (p = tk->drivers; p;) { + (*p->driver->free_driver)(p->info); + struct TermKeyDriverNode *next = p->next; + xfree(p); + p = next; + } + + xfree(tk); +} + +void termkey_destroy(TermKey *tk) +{ + if (tk->is_started) { + termkey_stop(tk); + } + + termkey_free(tk); +} + +void termkey_hook_terminfo_getstr(TermKey *tk, TermKey_Terminfo_Getstr_Hook *hookfn, void *data) +{ + tk->ti_getstr_hook = hookfn; + tk->ti_getstr_hook_data = data; +} + +int termkey_start(TermKey *tk) +{ + if (tk->is_started) { + return 1; + } + +#ifdef HAVE_TERMIOS + if (tk->fd != -1 && !(tk->flags & TERMKEY_FLAG_NOTERMIOS)) { + struct termios termios; + if (tcgetattr(tk->fd, &termios) == 0) { + tk->restore_termios = termios; + tk->restore_termios_valid = 1; + + termios.c_iflag &= (tcflag_t) ~(IXON|INLCR|ICRNL); + termios.c_lflag &= (tcflag_t) ~(ICANON|ECHO +# ifdef IEXTEN + | IEXTEN +# endif + ); + termios.c_cc[VMIN] = 1; + termios.c_cc[VTIME] = 0; + + if (tk->flags & TERMKEY_FLAG_CTRLC) { + // want no signal keys at all, so just disable ISIG + termios.c_lflag &= (tcflag_t) ~ISIG; + } else { + // Disable Ctrl-\==VQUIT and Ctrl-D==VSUSP but leave Ctrl-C as SIGINT + termios.c_cc[VQUIT] = _POSIX_VDISABLE; + termios.c_cc[VSUSP] = _POSIX_VDISABLE; + // Some OSes have Ctrl-Y==VDSUSP +# ifdef VDSUSP + termios.c_cc[VDSUSP] = _POSIX_VDISABLE; +# endif + } + +# ifdef DEBUG + fprintf(stderr, "Setting termios(3) flags\n"); +# endif + tcsetattr(tk->fd, TCSANOW, &termios); + } + } +#endif + + struct TermKeyDriverNode *p; + for (p = tk->drivers; p; p = p->next) { + if (p->driver->start_driver) { + if (!(*p->driver->start_driver)(tk, p->info)) { + return 0; + } + } + } + +#ifdef DEBUG + fprintf(stderr, "Drivers started; termkey instance %p is ready\n", tk); +#endif + + tk->is_started = 1; + return 1; +} + +int termkey_stop(TermKey *tk) +{ + if (!tk->is_started) { + return 1; + } + + struct TermKeyDriverNode *p; + for (p = tk->drivers; p; p = p->next) { + if (p->driver->stop_driver) { + (*p->driver->stop_driver)(tk, p->info); + } + } + +#ifdef HAVE_TERMIOS + if (tk->restore_termios_valid) { + tcsetattr(tk->fd, TCSANOW, &tk->restore_termios); + } +#endif + + tk->is_started = 0; + + return 1; +} + +void termkey_set_flags(TermKey *tk, int newflags) +{ + tk->flags = newflags; + + if (tk->flags & TERMKEY_FLAG_SPACESYMBOL) { + tk->canonflags |= TERMKEY_CANON_SPACESYMBOL; + } else { + tk->canonflags &= ~TERMKEY_CANON_SPACESYMBOL; + } +} + +int termkey_get_canonflags(TermKey *tk) +{ + return tk->canonflags; +} + +void termkey_set_canonflags(TermKey *tk, int flags) +{ + tk->canonflags = flags; + + if (tk->canonflags & TERMKEY_CANON_SPACESYMBOL) { + tk->flags |= TERMKEY_FLAG_SPACESYMBOL; + } else { + tk->flags &= ~TERMKEY_FLAG_SPACESYMBOL; + } +} + +size_t termkey_get_buffer_size(TermKey *tk) +{ + return tk->buffsize; +} + +int termkey_set_buffer_size(TermKey *tk, size_t size) +{ + unsigned char *buffer = xrealloc(tk->buffer, size); + + tk->buffer = buffer; + tk->buffsize = size; + + return 1; +} + +size_t termkey_get_buffer_remaining(TermKey *tk) +{ + // Return the total number of free bytes in the buffer, because that's what + // is available to the user. + return tk->buffsize - tk->buffcount; +} + +static void eat_bytes(TermKey *tk, size_t count) +{ + if (count >= tk->buffcount) { + tk->buffstart = 0; + tk->buffcount = 0; + return; + } + + tk->buffstart += count; + tk->buffcount -= count; +} + +// TODO(dundargoc): we should be able to replace this with utf_char2bytes from mbyte.c +int fill_utf8(int codepoint, char *str) +{ + int nbytes = utf_char2len(codepoint); + + str[nbytes] = 0; + + // This is easier done backwards + int b = nbytes; + while (b > 1) { + b--; + str[b] = (char)0x80 | (codepoint & 0x3f); + codepoint >>= 6; + } + + switch (nbytes) { + case 1: + str[0] = (codepoint & 0x7f); break; + case 2: + str[0] = (char)0xc0 | (codepoint & 0x1f); break; + case 3: + str[0] = (char)0xe0 | (codepoint & 0x0f); break; + case 4: + str[0] = (char)0xf0 | (codepoint & 0x07); break; + case 5: + str[0] = (char)0xf8 | (codepoint & 0x03); break; + case 6: + str[0] = (char)0xfc | (codepoint & 0x01); break; + } + + return nbytes; +} + +#define UTF8_INVALID 0xFFFD +static TermKeyResult parse_utf8(const unsigned char *bytes, size_t len, int *cp, size_t *nbytep) +{ + unsigned nbytes; + + unsigned char b0 = bytes[0]; + + if (b0 < 0x80) { + // Single byte ASCII + *cp = b0; + *nbytep = 1; + return TERMKEY_RES_KEY; + } else if (b0 < 0xc0) { + // Starts with a continuation byte - that's not right + *cp = UTF8_INVALID; + *nbytep = 1; + return TERMKEY_RES_KEY; + } else if (b0 < 0xe0) { + nbytes = 2; + *cp = b0 & 0x1f; + } else if (b0 < 0xf0) { + nbytes = 3; + *cp = b0 & 0x0f; + } else if (b0 < 0xf8) { + nbytes = 4; + *cp = b0 & 0x07; + } else if (b0 < 0xfc) { + nbytes = 5; + *cp = b0 & 0x03; + } else if (b0 < 0xfe) { + nbytes = 6; + *cp = b0 & 0x01; + } else { + *cp = UTF8_INVALID; + *nbytep = 1; + return TERMKEY_RES_KEY; + } + + for (unsigned b = 1; b < nbytes; b++) { + unsigned char cb; + + if (b >= len) { + return TERMKEY_RES_AGAIN; + } + + cb = bytes[b]; + if (cb < 0x80 || cb >= 0xc0) { + *cp = UTF8_INVALID; + *nbytep = b; + return TERMKEY_RES_KEY; + } + + *cp <<= 6; + *cp |= cb & 0x3f; + } + + // Check for overlong sequences + if ((int)nbytes > utf_char2len(*cp)) { + *cp = UTF8_INVALID; + } + + // Check for UTF-16 surrogates or invalid *cps + if ((*cp >= 0xD800 && *cp <= 0xDFFF) + || *cp == 0xFFFE + || *cp == 0xFFFF) { + *cp = UTF8_INVALID; + } + + *nbytep = nbytes; + return TERMKEY_RES_KEY; +} + +static void emit_codepoint(TermKey *tk, int codepoint, TermKeyKey *key) +{ + if (codepoint == 0) { + // ASCII NUL = Ctrl-Space + key->type = TERMKEY_TYPE_KEYSYM; + key->code.sym = TERMKEY_SYM_SPACE; + key->modifiers = TERMKEY_KEYMOD_CTRL; + } else if (codepoint < 0x20) { + // C0 range + key->code.codepoint = 0; + key->modifiers = 0; + + if (!(tk->flags & TERMKEY_FLAG_NOINTERPRET) && tk->c0[codepoint].sym != TERMKEY_SYM_UNKNOWN) { + key->code.sym = tk->c0[codepoint].sym; + key->modifiers |= tk->c0[codepoint].modifier_set; + } + + if (!key->code.sym) { + key->type = TERMKEY_TYPE_UNICODE; + // Generically modified Unicode ought not report the SHIFT state, or else + // we get into complications trying to report Shift-; vs : and so on... + // In order to be able to represent Ctrl-Shift-A as CTRL modified + // unicode A, we need to call Ctrl-A simply 'a', lowercase + if (codepoint + 0x40 >= 'A' && codepoint + 0x40 <= 'Z') { + // it's a letter - use lowercase instead + key->code.codepoint = codepoint + 0x60; + } else { + key->code.codepoint = codepoint + 0x40; + } + key->modifiers = TERMKEY_KEYMOD_CTRL; + } else { + key->type = TERMKEY_TYPE_KEYSYM; + } + } else if (codepoint == 0x7f && !(tk->flags & TERMKEY_FLAG_NOINTERPRET)) { + // ASCII DEL + key->type = TERMKEY_TYPE_KEYSYM; + key->code.sym = TERMKEY_SYM_DEL; + key->modifiers = 0; + } else if (codepoint >= 0x20 && codepoint < 0x80) { + // ASCII lowbyte range + key->type = TERMKEY_TYPE_UNICODE; + key->code.codepoint = codepoint; + key->modifiers = 0; + } else if (codepoint >= 0x80 && codepoint < 0xa0) { + // UTF-8 never starts with a C1 byte. So we can be sure of these + key->type = TERMKEY_TYPE_UNICODE; + key->code.codepoint = codepoint - 0x40; + key->modifiers = TERMKEY_KEYMOD_CTRL|TERMKEY_KEYMOD_ALT; + } else { + // UTF-8 codepoint + key->type = TERMKEY_TYPE_UNICODE; + key->code.codepoint = codepoint; + key->modifiers = 0; + } + + termkey_canonicalise(tk, key); + + if (key->type == TERMKEY_TYPE_UNICODE) { + fill_utf8(key->code.codepoint, key->utf8); + } +} + +void termkey_canonicalise(TermKey *tk, TermKeyKey *key) +{ + int flags = tk->canonflags; + + if (flags & TERMKEY_CANON_SPACESYMBOL) { + if (key->type == TERMKEY_TYPE_UNICODE && key->code.codepoint == 0x20) { + key->type = TERMKEY_TYPE_KEYSYM; + key->code.sym = TERMKEY_SYM_SPACE; + } + } else { + if (key->type == TERMKEY_TYPE_KEYSYM && key->code.sym == TERMKEY_SYM_SPACE) { + key->type = TERMKEY_TYPE_UNICODE; + key->code.codepoint = 0x20; + fill_utf8(key->code.codepoint, key->utf8); + } + } + + if (flags & TERMKEY_CANON_DELBS) { + if (key->type == TERMKEY_TYPE_KEYSYM && key->code.sym == TERMKEY_SYM_DEL) { + key->code.sym = TERMKEY_SYM_BACKSPACE; + } + } +} + +static TermKeyResult peekkey(TermKey *tk, TermKeyKey *key, int force, size_t *nbytep) +{ + int again = 0; + + if (!tk->is_started) { + errno = EINVAL; + return TERMKEY_RES_ERROR; + } + +#ifdef DEBUG + fprintf(stderr, "getkey(force=%d): buffer ", force); + print_buffer(tk); + fprintf(stderr, "\n"); +#endif + + if (tk->hightide) { + tk->buffstart += tk->hightide; + tk->buffcount -= tk->hightide; + tk->hightide = 0; + } + + TermKeyResult ret; + struct TermKeyDriverNode *p; + for (p = tk->drivers; p; p = p->next) { + ret = (p->driver->peekkey)(tk, p->info, key, force, nbytep); + +#ifdef DEBUG + fprintf(stderr, "Driver %s yields %s\n", p->driver->name, res2str(ret)); +#endif + + switch (ret) { + case TERMKEY_RES_KEY: +#ifdef DEBUG + print_key(tk, key); fprintf(stderr, "\n"); +#endif + // Slide the data down to stop it running away + { + size_t halfsize = tk->buffsize / 2; + + if (tk->buffstart > halfsize) { + memcpy(tk->buffer, tk->buffer + halfsize, halfsize); + tk->buffstart -= halfsize; + } + } + FALLTHROUGH; + case TERMKEY_RES_EOF: + case TERMKEY_RES_ERROR: + return ret; + + case TERMKEY_RES_AGAIN: + if (!force) { + again = 1; + } + FALLTHROUGH; + case TERMKEY_RES_NONE: + break; + } + } + + if (again) { + return TERMKEY_RES_AGAIN; + } + + ret = peekkey_simple(tk, key, force, nbytep); + +#ifdef DEBUG + fprintf(stderr, "getkey_simple(force=%d) yields %s\n", force, res2str(ret)); + if (ret == TERMKEY_RES_KEY) { + print_key(tk, key); fprintf(stderr, "\n"); + } +#endif + + return ret; +} + +static TermKeyResult peekkey_simple(TermKey *tk, TermKeyKey *key, int force, size_t *nbytep) +{ + if (tk->buffcount == 0) { + return tk->is_closed ? TERMKEY_RES_EOF : TERMKEY_RES_NONE; + } + + unsigned char b0 = CHARAT(0); + + if (b0 == 0x1b) { + // Escape-prefixed value? Might therefore be Alt+key + if (tk->buffcount == 1) { + // This might be an <Esc> press, or it may want to be part of a longer + // sequence + if (!force) { + return TERMKEY_RES_AGAIN; + } + + (*tk->method.emit_codepoint)(tk, b0, key); + *nbytep = 1; + return TERMKEY_RES_KEY; + } + + // Try another key there + tk->buffstart++; + tk->buffcount--; + + // Run the full driver + TermKeyResult metakey_result = peekkey(tk, key, force, nbytep); + + tk->buffstart--; + tk->buffcount++; + + switch (metakey_result) { + case TERMKEY_RES_KEY: + key->modifiers |= TERMKEY_KEYMOD_ALT; + (*nbytep)++; + break; + + case TERMKEY_RES_NONE: + case TERMKEY_RES_EOF: + case TERMKEY_RES_AGAIN: + case TERMKEY_RES_ERROR: + break; + } + + return metakey_result; + } else if (b0 < 0xa0) { + // Single byte C0, G0 or C1 - C1 is never UTF-8 initial byte + (*tk->method.emit_codepoint)(tk, b0, key); + *nbytep = 1; + return TERMKEY_RES_KEY; + } else if (tk->flags & TERMKEY_FLAG_UTF8) { + // Some UTF-8 + int codepoint; + TermKeyResult res = parse_utf8(tk->buffer + tk->buffstart, tk->buffcount, &codepoint, nbytep); + + if (res == TERMKEY_RES_AGAIN && force) { + // There weren't enough bytes for a complete UTF-8 sequence but caller + // demands an answer. About the best thing we can do here is eat as many + // bytes as we have, and emit a UTF8_INVALID. If the remaining bytes + // arrive later, they'll be invalid too. + codepoint = UTF8_INVALID; + *nbytep = tk->buffcount; + res = TERMKEY_RES_KEY; + } + + key->type = TERMKEY_TYPE_UNICODE; + key->modifiers = 0; + (*tk->method.emit_codepoint)(tk, codepoint, key); + return res; + } else { + // Non UTF-8 case - just report the raw byte + key->type = TERMKEY_TYPE_UNICODE; + key->code.codepoint = b0; + key->modifiers = 0; + + key->utf8[0] = (char)key->code.codepoint; + key->utf8[1] = 0; + + *nbytep = 1; + + return TERMKEY_RES_KEY; + } +} + +static TermKeyResult peekkey_mouse(TermKey *tk, TermKeyKey *key, size_t *nbytep) +{ + if (tk->buffcount < 3) { + return TERMKEY_RES_AGAIN; + } + + key->type = TERMKEY_TYPE_MOUSE; + key->code.mouse[0] = (char)CHARAT(0) - 0x20; + key->code.mouse[1] = (char)CHARAT(1) - 0x20; + key->code.mouse[2] = (char)CHARAT(2) - 0x20; + key->code.mouse[3] = 0; + + key->modifiers = (key->code.mouse[0] & 0x1c) >> 2; + key->code.mouse[0] &= ~0x1c; + + *nbytep = 3; + return TERMKEY_RES_KEY; +} + +TermKeyResult termkey_getkey(TermKey *tk, TermKeyKey *key) +{ + size_t nbytes = 0; + TermKeyResult ret = peekkey(tk, key, 0, &nbytes); + + if (ret == TERMKEY_RES_KEY) { + eat_bytes(tk, nbytes); + } + + if (ret == TERMKEY_RES_AGAIN) { + // Call peekkey() again in force mode to obtain whatever it can + (void)peekkey(tk, key, 1, &nbytes); + } + // Don't eat it yet though + + return ret; +} + +TermKeyResult termkey_getkey_force(TermKey *tk, TermKeyKey *key) +{ + size_t nbytes = 0; + TermKeyResult ret = peekkey(tk, key, 1, &nbytes); + + if (ret == TERMKEY_RES_KEY) { + eat_bytes(tk, nbytes); + } + + return ret; +} + +size_t termkey_push_bytes(TermKey *tk, const char *bytes, size_t len) +{ + if (tk->buffstart) { + memmove(tk->buffer, tk->buffer + tk->buffstart, tk->buffcount); + tk->buffstart = 0; + } + + // Not expecting it ever to be greater but doesn't hurt to handle that + if (tk->buffcount >= tk->buffsize) { + errno = ENOMEM; + return (size_t)-1; + } + + if (len > tk->buffsize - tk->buffcount) { + len = tk->buffsize - tk->buffcount; + } + + // memcpy(), not strncpy() in case of null bytes in input + memcpy(tk->buffer + tk->buffcount, bytes, len); + tk->buffcount += len; + + return len; +} + +TermKeySym termkey_register_keyname(TermKey *tk, TermKeySym sym, const char *name) +{ + if (!sym) { + sym = tk->nkeynames; + } + + if (sym >= tk->nkeynames) { + const char **new_keynames = xrealloc(tk->keynames, sizeof(new_keynames[0]) * ((size_t)sym + 1)); + + tk->keynames = new_keynames; + + // Fill in the hole + for (int i = tk->nkeynames; i < sym; i++) { + tk->keynames[i] = NULL; + } + + tk->nkeynames = sym + 1; + } + + tk->keynames[sym] = name; + + return sym; +} + +const char *termkey_get_keyname(TermKey *tk, TermKeySym sym) +{ + if (sym == TERMKEY_SYM_UNKNOWN) { + return "UNKNOWN"; + } + + if (sym < tk->nkeynames) { + return tk->keynames[sym]; + } + + return "UNKNOWN"; +} + +static const char *termkey_lookup_keyname_format(TermKey *tk, const char *str, TermKeySym *sym, + TermKeyFormat format) +{ + // We store an array, so we can't do better than a linear search. Doesn't + // matter because user won't be calling this too often + + for (*sym = 0; *sym < tk->nkeynames; (*sym)++) { + const char *thiskey = tk->keynames[*sym]; + if (!thiskey) { + continue; + } + size_t len = strlen(thiskey); + if (format & TERMKEY_FORMAT_LOWERSPACE) { + const char *thisstr = str; + if (strpncmp_camel(&thisstr, &thiskey, len) == 0) { + return thisstr; + } + } else { + if (strncmp(str, thiskey, len) == 0) { + return (char *)str + len; + } + } + } + + return NULL; +} + +const char *termkey_lookup_keyname(TermKey *tk, const char *str, TermKeySym *sym) +{ + return termkey_lookup_keyname_format(tk, str, sym, 0); +} + +static TermKeySym register_c0(TermKey *tk, TermKeySym sym, unsigned char ctrl, const char *name) +{ + return register_c0_full(tk, sym, 0, 0, ctrl, name); +} + +static TermKeySym register_c0_full(TermKey *tk, TermKeySym sym, int modifier_set, int modifier_mask, + unsigned char ctrl, const char *name) +{ + if (ctrl >= 0x20) { + errno = EINVAL; + return -1; + } + + if (name) { + sym = termkey_register_keyname(tk, sym, name); + } + + tk->c0[ctrl].sym = sym; + tk->c0[ctrl].modifier_set = modifier_set; + tk->c0[ctrl].modifier_mask = modifier_mask; + + return sym; +} + +static struct modnames { + const char *shift, *alt, *ctrl; +} +modnames[] = { + { "S", "A", "C" }, // 0 + { "Shift", "Alt", "Ctrl" }, // LONGMOD + { "S", "M", "C" }, // ALTISMETA + { "Shift", "Meta", "Ctrl" }, // ALTISMETA+LONGMOD + { "s", "a", "c" }, // LOWERMOD + { "shift", "alt", "ctrl" }, // LOWERMOD+LONGMOD + { "s", "m", "c" }, // LOWERMOD+ALTISMETA + { "shift", "meta", "ctrl" }, // LOWERMOD+ALTISMETA+LONGMOD +}; + +size_t termkey_strfkey(TermKey *tk, char *buffer, size_t len, TermKeyKey *key, TermKeyFormat format) +{ + size_t pos = 0; + size_t l = 0; + + struct modnames *mods = &modnames[!!(format & TERMKEY_FORMAT_LONGMOD) + + !!(format & TERMKEY_FORMAT_ALTISMETA) * 2 + + !!(format & TERMKEY_FORMAT_LOWERMOD) * 4]; + + int wrapbracket = (format & TERMKEY_FORMAT_WRAPBRACKET) + && (key->type != TERMKEY_TYPE_UNICODE || key->modifiers != 0); + + char sep = (format & TERMKEY_FORMAT_SPACEMOD) ? ' ' : '-'; + + if (format & TERMKEY_FORMAT_CARETCTRL + && key->type == TERMKEY_TYPE_UNICODE + && key->modifiers == TERMKEY_KEYMOD_CTRL) { + long codepoint = key->code.codepoint; + + // Handle some of the special cases first + if (codepoint >= 'a' && codepoint <= 'z') { + l = (size_t)snprintf(buffer + pos, len - pos, wrapbracket ? "<^%c>" : "^%c", + (char)codepoint - 0x20); + if (l <= 0) { + return pos; + } + pos += l; + return pos; + } else if ((codepoint >= '@' && codepoint < 'A') + || (codepoint > 'Z' && codepoint <= '_')) { + l = (size_t)snprintf(buffer + pos, len - pos, wrapbracket ? "<^%c>" : "^%c", (char)codepoint); + if (l <= 0) { + return pos; + } + pos += l; + return pos; + } + } + + if (wrapbracket) { + l = (size_t)snprintf(buffer + pos, len - pos, "<"); + if (l <= 0) { + return pos; + } + pos += l; + } + + if (key->modifiers & TERMKEY_KEYMOD_ALT) { + l = (size_t)snprintf(buffer + pos, len - pos, "%s%c", mods->alt, sep); + if (l <= 0) { + return pos; + } + pos += l; + } + + if (key->modifiers & TERMKEY_KEYMOD_CTRL) { + l = (size_t)snprintf(buffer + pos, len - pos, "%s%c", mods->ctrl, sep); + if (l <= 0) { + return pos; + } + pos += l; + } + + if (key->modifiers & TERMKEY_KEYMOD_SHIFT) { + l = (size_t)snprintf(buffer + pos, len - pos, "%s%c", mods->shift, sep); + if (l <= 0) { + return pos; + } + pos += l; + } + + switch (key->type) { + case TERMKEY_TYPE_UNICODE: + if (!key->utf8[0]) { // In case of user-supplied key structures + fill_utf8(key->code.codepoint, key->utf8); + } + l = (size_t)snprintf(buffer + pos, len - pos, "%s", key->utf8); + break; + case TERMKEY_TYPE_KEYSYM: { + const char *name = termkey_get_keyname(tk, key->code.sym); + if (format & TERMKEY_FORMAT_LOWERSPACE) { + l = (size_t)snprint_cameltospaces(buffer + pos, len - pos, name); + } else { + l = (size_t)snprintf(buffer + pos, len - pos, "%s", name); + } + } + break; + case TERMKEY_TYPE_FUNCTION: + l = (size_t)snprintf(buffer + pos, len - pos, "%c%d", + (format & TERMKEY_FORMAT_LOWERSPACE ? 'f' : 'F'), key->code.number); + break; + case TERMKEY_TYPE_MOUSE: { + TermKeyMouseEvent ev; + int button; + int line, col; + termkey_interpret_mouse(tk, key, &ev, &button, &line, &col); + + l = (size_t)snprintf(buffer + pos, len - pos, "Mouse%s(%d)", + evnames[ev], button); + + if (format & TERMKEY_FORMAT_MOUSE_POS) { + if (l <= 0) { + return pos; + } + pos += l; + + l = (size_t)snprintf(buffer + pos, len - pos, " @ (%u,%u)", col, line); + } + } + break; + case TERMKEY_TYPE_POSITION: + l = (size_t)snprintf(buffer + pos, len - pos, "Position"); + break; + case TERMKEY_TYPE_MODEREPORT: { + int initial, mode, value; + termkey_interpret_modereport(tk, key, &initial, &mode, &value); + if (initial) { + l = (size_t)snprintf(buffer + pos, len - pos, "Mode(%c%d=%d)", initial, mode, value); + } else { + l = (size_t)snprintf(buffer + pos, len - pos, "Mode(%d=%d)", mode, value); + } + } + break; + case TERMKEY_TYPE_DCS: + l = (size_t)snprintf(buffer + pos, len - pos, "DCS"); + break; + case TERMKEY_TYPE_OSC: + l = (size_t)snprintf(buffer + pos, len - pos, "OSC"); + break; + case TERMKEY_TYPE_UNKNOWN_CSI: + l = (size_t)snprintf(buffer + pos, len - pos, "CSI %c", key->code.number & 0xff); + break; + } + + if (l <= 0) { + return pos; + } + pos += l; + + if (wrapbracket) { + l = (size_t)snprintf(buffer + pos, len - pos, ">"); + if (l <= 0) { + return pos; + } + pos += l; + } + + return pos; +} diff --git a/src/nvim/tui/termkey/termkey.h b/src/nvim/tui/termkey/termkey.h new file mode 100644 index 0000000000..21ed141346 --- /dev/null +++ b/src/nvim/tui/termkey/termkey.h @@ -0,0 +1,10 @@ +#pragma once + +#include <stdint.h> +#include <stdlib.h> + +#include "nvim/tui/termkey/termkey_defs.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "tui/termkey/termkey.h.generated.h" +#endif diff --git a/src/nvim/tui/termkey/termkey_defs.h b/src/nvim/tui/termkey/termkey_defs.h new file mode 100644 index 0000000000..7c218ba7c2 --- /dev/null +++ b/src/nvim/tui/termkey/termkey_defs.h @@ -0,0 +1,199 @@ +#pragma once + +#include <stddef.h> +#include <stdint.h> +#include <unibilium.h> +#include <uv.h> + +#include "nvim/event/defs.h" +#include "nvim/tui/tui_defs.h" +#include "nvim/types_defs.h" + +typedef struct TermKey TermKey; + +typedef struct { + TermKey *tk; + int saved_string_id; + char *saved_string; +} TermKeyCsi; + +typedef enum { + TERMKEY_RES_NONE, + TERMKEY_RES_KEY, + TERMKEY_RES_EOF, + TERMKEY_RES_AGAIN, + TERMKEY_RES_ERROR, +} TermKeyResult; + +typedef enum { + TERMKEY_SYM_UNKNOWN = -1, + TERMKEY_SYM_NONE = 0, + + // Special names in C0 + TERMKEY_SYM_BACKSPACE, + TERMKEY_SYM_TAB, + TERMKEY_SYM_ENTER, + TERMKEY_SYM_ESCAPE, + + // Special names in G0 + TERMKEY_SYM_SPACE, + TERMKEY_SYM_DEL, + + // Special keys + TERMKEY_SYM_UP, + TERMKEY_SYM_DOWN, + TERMKEY_SYM_LEFT, + TERMKEY_SYM_RIGHT, + TERMKEY_SYM_BEGIN, + TERMKEY_SYM_FIND, + TERMKEY_SYM_INSERT, + TERMKEY_SYM_DELETE, + TERMKEY_SYM_SELECT, + TERMKEY_SYM_PAGEUP, + TERMKEY_SYM_PAGEDOWN, + TERMKEY_SYM_HOME, + TERMKEY_SYM_END, + + // Special keys from terminfo + TERMKEY_SYM_CANCEL, + TERMKEY_SYM_CLEAR, + TERMKEY_SYM_CLOSE, + TERMKEY_SYM_COMMAND, + TERMKEY_SYM_COPY, + TERMKEY_SYM_EXIT, + TERMKEY_SYM_HELP, + TERMKEY_SYM_MARK, + TERMKEY_SYM_MESSAGE, + TERMKEY_SYM_MOVE, + TERMKEY_SYM_OPEN, + TERMKEY_SYM_OPTIONS, + TERMKEY_SYM_PRINT, + TERMKEY_SYM_REDO, + TERMKEY_SYM_REFERENCE, + TERMKEY_SYM_REFRESH, + TERMKEY_SYM_REPLACE, + TERMKEY_SYM_RESTART, + TERMKEY_SYM_RESUME, + TERMKEY_SYM_SAVE, + TERMKEY_SYM_SUSPEND, + TERMKEY_SYM_UNDO, + + // Numeric keypad special keys + TERMKEY_SYM_KP0, + TERMKEY_SYM_KP1, + TERMKEY_SYM_KP2, + TERMKEY_SYM_KP3, + TERMKEY_SYM_KP4, + TERMKEY_SYM_KP5, + TERMKEY_SYM_KP6, + TERMKEY_SYM_KP7, + TERMKEY_SYM_KP8, + TERMKEY_SYM_KP9, + TERMKEY_SYM_KPENTER, + TERMKEY_SYM_KPPLUS, + TERMKEY_SYM_KPMINUS, + TERMKEY_SYM_KPMULT, + TERMKEY_SYM_KPDIV, + TERMKEY_SYM_KPCOMMA, + TERMKEY_SYM_KPPERIOD, + TERMKEY_SYM_KPEQUALS, + + // et cetera ad nauseum + TERMKEY_N_SYMS, +} TermKeySym; + +typedef enum { + TERMKEY_TYPE_UNICODE, + TERMKEY_TYPE_FUNCTION, + TERMKEY_TYPE_KEYSYM, + TERMKEY_TYPE_MOUSE, + TERMKEY_TYPE_POSITION, + TERMKEY_TYPE_MODEREPORT, + TERMKEY_TYPE_DCS, + TERMKEY_TYPE_OSC, + // add other recognised types here + + TERMKEY_TYPE_UNKNOWN_CSI = -1, +} TermKeyType; + +typedef enum { + TERMKEY_MOUSE_UNKNOWN, + TERMKEY_MOUSE_PRESS, + TERMKEY_MOUSE_DRAG, + TERMKEY_MOUSE_RELEASE, +} TermKeyMouseEvent; + +enum { + TERMKEY_KEYMOD_SHIFT = 1 << 0, + TERMKEY_KEYMOD_ALT = 1 << 1, + TERMKEY_KEYMOD_CTRL = 1 << 2, +}; + +typedef struct { + const unsigned char *param; + size_t length; +} TermKeyCsiParam; + +enum { + TERMKEY_FLAG_NOINTERPRET = 1 << 0, // Do not interpret C0//DEL codes if possible + TERMKEY_FLAG_CONVERTKP = 1 << 1, // Convert KP codes to regular keypresses + TERMKEY_FLAG_RAW = 1 << 2, // Input is raw bytes, not UTF-8 + TERMKEY_FLAG_UTF8 = 1 << 3, // Input is definitely UTF-8 + TERMKEY_FLAG_NOTERMIOS = 1 << 4, // Do not make initial termios calls on construction + TERMKEY_FLAG_SPACESYMBOL = 1 << 5, // Sets TERMKEY_CANON_SPACESYMBOL + TERMKEY_FLAG_CTRLC = 1 << 6, // Allow Ctrl-C to be read as normal, disabling SIGINT + TERMKEY_FLAG_EINTR = 1 << 7, // Return ERROR on signal (EINTR) rather than retry + TERMKEY_FLAG_NOSTART = 1 << 8, // Do not call termkey_start() in constructor +}; + +enum { + TERMKEY_CANON_SPACESYMBOL = 1 << 0, // Space is symbolic rather than Unicode + TERMKEY_CANON_DELBS = 1 << 1, // Del is converted to Backspace +}; + +typedef struct { + TermKeyType type; + union { + int codepoint; // TERMKEY_TYPE_UNICODE + int number; // TERMKEY_TYPE_FUNCTION + TermKeySym sym; // TERMKEY_TYPE_KEYSYM + char mouse[4]; // TERMKEY_TYPE_MOUSE + // opaque. see termkey_interpret_mouse + } code; + + int modifiers; + + // Any Unicode character can be UTF-8 encoded in no more than 6 bytes, plus + // terminating NUL + char utf8[7]; +} TermKeyKey; + +// Mostly-undocumented hooks for doing evil evil things +typedef const char *TermKey_Terminfo_Getstr_Hook(const char *name, const char *value, void *data); + +typedef enum { + TERMKEY_FORMAT_LONGMOD = 1 << 0, // Shift-... instead of S-... + TERMKEY_FORMAT_CARETCTRL = 1 << 1, // ^X instead of C-X + TERMKEY_FORMAT_ALTISMETA = 1 << 2, // Meta- or M- instead of Alt- or A- + TERMKEY_FORMAT_WRAPBRACKET = 1 << 3, // Wrap special keys in brackets like <Escape> + TERMKEY_FORMAT_SPACEMOD = 1 << 4, // M Foo instead of M-Foo + TERMKEY_FORMAT_LOWERMOD = 1 << 5, // meta or m instead of Meta or M + TERMKEY_FORMAT_LOWERSPACE = 1 << 6, // page down instead of PageDown + + TERMKEY_FORMAT_MOUSE_POS = 1 << 8, // Include mouse position if relevant; @ col,line +} TermKeyFormat; + +// Some useful combinations + +#define TERMKEY_FORMAT_VIM (TermKeyFormat)(TERMKEY_FORMAT_ALTISMETA|TERMKEY_FORMAT_WRAPBRACKET) + +typedef struct { + TermKey *tk; + + unibi_term *unibi; // only valid until first 'start' call + + struct trie_node *root; + + char *start_string; + char *stop_string; +} TermKeyTI; diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 2a9530defb..fa50a8252d 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -109,12 +109,14 @@ struct TUIData { bool set_cursor_color_as_str; bool cursor_color_changed; bool is_starting; + bool did_set_grapheme_cluster_mode; FILE *screenshot; cursorentry_T cursor_shapes[SHAPE_IDX_COUNT]; HlAttrs clear_attrs; kvec_t(HlAttrs) attrs; int print_attr_id; bool default_attr; + bool set_default_colors; bool can_clear_attr; ModeShape showing_mode; Integer verbose; @@ -166,18 +168,11 @@ void tui_start(TUIData **tui_p, int *width, int *height, char **term, bool *rgb) tui->seen_error_exit = 0; tui->loop = &main_loop; tui->url = -1; - // Because setting the default colors is delayed until after startup to avoid - // flickering with the default colorscheme background, any flush that happens - // during startup in turn would result in clearing invalidated regions with - // uninitialized attrs(black). Instead initialize clear_attrs with current - // terminal background so that it is at least not perceived as flickering, even - // though it may be different from the colorscheme that is set during startup. - tui->clear_attrs.rgb_bg_color = normal_bg; - tui->clear_attrs.cterm_bg_color = (int16_t)cterm_normal_bg_color; kv_init(tui->invalid_regions); kv_init(tui->urlbuf); signal_watcher_init(tui->loop, &tui->winch_handle, tui); + signal_watcher_start(&tui->winch_handle, sigwinch_cb, SIGWINCH); // TODO(bfredl): zero hl is empty, send this explicitly? kv_push(tui->attrs, HLATTRS_INIT); @@ -212,10 +207,21 @@ static void tui_request_term_mode(TUIData *tui, TermMode mode) out(tui, buf, (size_t)len); } +/// Set (DECSET) or reset (DECRST) a terminal mode. +static void tui_set_term_mode(TUIData *tui, TermMode mode, bool set) + FUNC_ATTR_NONNULL_ALL +{ + char buf[12]; + int len = snprintf(buf, sizeof(buf), "\x1b[?%d%c", (int)mode, set ? 'h' : 'l'); + assert((len > 0) && (len < (int)sizeof(buf))); + out(tui, buf, (size_t)len); +} + /// Handle a mode report (DECRPM) from the terminal. void tui_handle_term_mode(TUIData *tui, TermMode mode, TermModeState state) FUNC_ATTR_NONNULL_ALL { + bool is_set = false; switch (state) { case kTermModeNotRecognized: case kTermModePermanentlySet: @@ -224,6 +230,8 @@ void tui_handle_term_mode(TUIData *tui, TermMode mode, TermModeState state) // then there is nothing to do break; case kTermModeSet: + is_set = true; + FALLTHROUGH; case kTermModeReset: // The terminal supports changing the given mode switch (mode) { @@ -231,6 +239,17 @@ void tui_handle_term_mode(TUIData *tui, TermMode mode, TermModeState state) // Ref: https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036 tui->unibi_ext.sync = (int)unibi_add_ext_str(tui->ut, "Sync", "\x1b[?2026%?%p1%{1}%-%tl%eh%;"); + break; + case kTermModeResizeEvents: + signal_watcher_stop(&tui->winch_handle); + tui_set_term_mode(tui, mode, true); + break; + case kTermModeGraphemeClusters: + if (!is_set) { + tui_set_term_mode(tui, mode, true); + tui->did_set_grapheme_cluster_mode = true; + } + break; } } } @@ -424,6 +443,8 @@ static void terminfo_start(TUIData *tui) // Some terminals (such as Terminal.app) do not support DECRQM, so skip the query. if (!nsterm) { tui_request_term_mode(tui, kTermModeSynchronizedOutput); + tui_request_term_mode(tui, kTermModeResizeEvents); + tui_request_term_mode(tui, kTermModeGraphemeClusters); } // Don't use DECRQSS in screen or tmux, as they behave strangely when receiving it. @@ -482,6 +503,11 @@ static void terminfo_stop(TUIData *tui) // Reset the key encoding tui_reset_key_encoding(tui); + // Disable resize events + tui_set_term_mode(tui, kTermModeResizeEvents, false); + if (tui->did_set_grapheme_cluster_mode) { + tui_set_term_mode(tui, kTermModeGraphemeClusters, false); + } // May restore old title before exiting alternate screen. tui_set_title(tui, NULL_STRING); if (ui_client_exit_status == 0) { @@ -517,7 +543,6 @@ static void tui_terminal_start(TUIData *tui) tui->print_attr_id = -1; terminfo_start(tui); tui_guess_size(tui); - signal_watcher_start(&tui->winch_handle, sigwinch_cb, SIGWINCH); tinput_start(&tui->input); } @@ -546,7 +571,6 @@ static void tui_terminal_stop(TUIData *tui) return; } tinput_stop(&tui->input); - signal_watcher_stop(&tui->winch_handle); // Position the cursor on the last screen line, below all the text cursor_goto(tui, tui->height - 1, 0); terminfo_stop(tui); @@ -563,6 +587,7 @@ void tui_stop(TUIData *tui) stream_set_blocking(tui->input.in_fd, true); // normalize stream (#2598) tinput_destroy(&tui->input); tui->stopped = true; + signal_watcher_stop(&tui->winch_handle); signal_watcher_close(&tui->winch_handle, NULL); uv_close((uv_handle_t *)&tui->startup_delay_timer, NULL); } @@ -781,7 +806,12 @@ static void update_attrs(TUIData *tui, int attr_id) if (attrs.url >= 0) { const char *url = urls.keys[attrs.url]; kv_size(tui->urlbuf) = 0; - kv_printf(tui->urlbuf, "\x1b]8;;%s\x1b\\", url); + + // Add some fixed offset to the URL ID to deconflict with other + // applications which may set their own IDs + const uint64_t id = 0xE1EA0000U + (uint32_t)attrs.url; + + kv_printf(tui->urlbuf, "\x1b]8;id=%" PRIu64 ";%s\x1b\\", id, url); out(tui, tui->urlbuf.items, kv_size(tui->urlbuf)); } else { out(tui, S_LEN("\x1b]8;;\x1b\\")); @@ -871,6 +901,7 @@ static void cursor_goto(TUIData *tui, int row, int col) if (tui->url >= 0) { out(tui, S_LEN("\x1b]8;;\x1b\\")); tui->url = -1; + tui->print_attr_id = -1; } if (0 == row && 0 == col) { @@ -992,7 +1023,7 @@ static void print_cell_at_pos(TUIData *tui, int row, int col, UCell *cell, bool char buf[MAX_SCHAR_SIZE]; schar_get(buf, cell->data); int c = utf_ptr2char(buf); - bool is_ambiwidth = utf_ambiguous_width(c); + bool is_ambiwidth = utf_ambiguous_width(buf); if (is_doublewidth && (is_ambiwidth || utf_char2cells(c) == 1)) { // If the server used setcellwidths() to treat a single-width char as double-width, // it needs to be treated like an ambiguous-width char. @@ -1016,7 +1047,16 @@ static void clear_region(TUIData *tui, int top, int bot, int left, int right, in { UGrid *grid = &tui->grid; - update_attrs(tui, attr_id); + // Setting the default colors is delayed until after startup to avoid flickering + // with the default colorscheme background. Consequently, any flush that happens + // during startup would result in clearing invalidated regions with zeroed + // clear_attrs, perceived as a black flicker. Reset attributes to clear with + // current terminal background instead (#28667, #28668). + if (tui->set_default_colors) { + update_attrs(tui, attr_id); + } else { + unibi_out(tui, unibi_exit_attribute_mode); + } // Background is set to the default color and the right edge matches the // screen end, try to use terminal codes for clearing the requested area. @@ -1159,7 +1199,7 @@ static CursorShape tui_cursor_decode_shape(const char *shape_str) return shape; } -static cursorentry_T decode_cursor_entry(Dictionary args) +static cursorentry_T decode_cursor_entry(Dict args) { cursorentry_T r = shape_table[0]; @@ -1191,8 +1231,8 @@ void tui_mode_info_set(TUIData *tui, bool guicursor_enabled, Array args) // cursor style entries as defined by `shape_table`. for (size_t i = 0; i < args.size; i++) { - assert(args.items[i].type == kObjectTypeDictionary); - cursorentry_T r = decode_cursor_entry(args.items[i].data.dictionary); + assert(args.items[i].type == kObjectTypeDict); + cursorentry_T r = decode_cursor_entry(args.items[i].data.dict); tui->cursor_shapes[i] = r; } @@ -1419,6 +1459,7 @@ void tui_default_colors_set(TUIData *tui, Integer rgb_fg, Integer rgb_bg, Intege tui->clear_attrs.cterm_bg_color = (int16_t)cterm_bg; tui->print_attr_id = -1; + tui->set_default_colors = true; invalidate(tui, 0, tui->grid.height, 0, tui->grid.width); } @@ -1498,7 +1539,7 @@ static void show_verbose_terminfo(TUIData *tui) ADD_C(args, BOOLEAN_OBJ(true)); // history MAXSIZE_TEMP_DICT(opts, 1); PUT_C(opts, "verbose", BOOLEAN_OBJ(true)); - ADD_C(args, DICTIONARY_OBJ(opts)); + ADD_C(args, DICT_OBJ(opts)); rpc_send_event(ui_client_channel_id, "nvim_echo", args); xfree(str.data); } @@ -1694,6 +1735,14 @@ static void ensure_space_buf_size(TUIData *tui, size_t len) } } +void tui_set_size(TUIData *tui, int width, int height) + FUNC_ATTR_NONNULL_ALL +{ + tui->width = width; + tui->height = height; + ensure_space_buf_size(tui, (size_t)tui->width); +} + /// Tries to get the user's wanted dimensions (columns and rows) for the entire /// application (i.e., the host terminal). void tui_guess_size(TUIData *tui) @@ -1701,7 +1750,7 @@ void tui_guess_size(TUIData *tui) int width = 0; int height = 0; - // 1 - try from a system call(ioctl/TIOCGWINSZ on unix) + // 1 - try from a system call (ioctl/TIOCGWINSZ on unix) if (tui->out_isatty && !uv_tty_get_winsize(&tui->output_handle.tty, &width, &height)) { goto end; @@ -1728,9 +1777,7 @@ void tui_guess_size(TUIData *tui) height = DFLT_ROWS; } - tui->width = width; - tui->height = height; - ensure_space_buf_size(tui, (size_t)tui->width); + tui_set_size(tui, width, height); // Redraw on SIGWINCH event if size didn't change. #23411 ui_client_set_size(width, height); @@ -1852,20 +1899,12 @@ static int unibi_find_ext_bool(unibi_term *ut, const char *name) return -1; } -/// Determine if the terminal supports truecolor or not: +/// Determine if the terminal supports truecolor or not. /// -/// 1. If $COLORTERM is "24bit" or "truecolor", return true -/// 2. Else, check terminfo for Tc, RGB, setrgbf, or setrgbb capabilities. If -/// found, return true -/// 3. Else, return false +/// If terminfo contains Tc, RGB, or both setrgbf and setrgbb capabilities, return true. static bool term_has_truecolor(TUIData *tui, const char *colorterm) { - // Check $COLORTERM - if (strequal(colorterm, "truecolor") || strequal(colorterm, "24bit")) { - return true; - } - - // Check for Tc and RGB + // Check for Tc or RGB for (size_t i = 0; i < unibi_count_ext_bool(tui->ut); i++) { const char *n = unibi_get_ext_bool_name(tui->ut, i); if (n && (!strcmp(n, "Tc") || !strcmp(n, "RGB"))) { @@ -2505,7 +2544,7 @@ static const char *tui_get_stty_erase(int fd) struct termios t; if (tcgetattr(fd, &t) != -1) { stty_erase[0] = (char)t.c_cc[VERASE]; - stty_erase[1] = '\0'; + stty_erase[1] = NUL; DLOG("stty/termios:erase=%s", stty_erase); } #endif diff --git a/src/nvim/tui/tui_defs.h b/src/nvim/tui/tui_defs.h index c5149d4829..bd99d6b0ad 100644 --- a/src/nvim/tui/tui_defs.h +++ b/src/nvim/tui/tui_defs.h @@ -4,6 +4,8 @@ typedef struct TUIData TUIData; typedef enum { kTermModeSynchronizedOutput = 2026, + kTermModeGraphemeClusters = 2027, + kTermModeResizeEvents = 2048, } TermMode; typedef enum { diff --git a/src/nvim/types_defs.h b/src/nvim/types_defs.h index 934159b9d9..2dd2b01adf 100644 --- a/src/nvim/types_defs.h +++ b/src/nvim/types_defs.h @@ -56,3 +56,9 @@ typedef struct regprog regprog_T; typedef struct syn_state synstate_T; typedef struct terminal Terminal; typedef struct window_S win_T; + +typedef struct { + uint32_t nitems; + uint32_t nbytes; + char data[]; +} AdditionalData; diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 9bb66b886e..365aa5c74f 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -144,11 +144,15 @@ void ui_free_all_mem(void) /// Returns true if any `rgb=true` UI is attached. bool ui_rgb_attached(void) { - if (!headless_mode && p_tgc) { + if (p_tgc) { return true; } for (size_t i = 0; i < ui_count; i++) { - if (uis[i]->rgb) { + // We do not consider the TUI in this loop because we already checked for 'termguicolors' at the + // beginning of this function. In this loop, we are checking to see if any _other_ UIs which + // support RGB are attached. + bool tui = uis[i]->stdin_tty || uis[i]->stdout_tty; + if (!tui && uis[i]->rgb) { return true; } } @@ -178,9 +182,10 @@ bool ui_override(void) return false; } -bool ui_active(void) +/// Gets the number of UIs connected to this server. +size_t ui_active(void) { - return ui_count > 0; + return ui_count; } void ui_refresh(void) @@ -193,7 +198,7 @@ void ui_refresh(void) int height = INT_MAX; bool ext_widgets[kUIExtCount]; bool inclusive = ui_override(); - memset(ext_widgets, ui_active(), ARRAY_SIZE(ext_widgets)); + memset(ext_widgets, !!ui_active(), ARRAY_SIZE(ext_widgets)); for (size_t i = 0; i < ui_count; i++) { RemoteUI *ui = uis[i]; @@ -654,7 +659,7 @@ Array ui_array(Arena *arena) Array all_uis = arena_array(arena, ui_count); for (size_t i = 0; i < ui_count; i++) { RemoteUI *ui = uis[i]; - Dictionary info = arena_dict(arena, 10 + kUIExtCount); + Dict info = arena_dict(arena, 10 + kUIExtCount); PUT_C(info, "width", INTEGER_OBJ(ui->width)); PUT_C(info, "height", INTEGER_OBJ(ui->height)); PUT_C(info, "rgb", BOOLEAN_OBJ(ui->rgb)); @@ -677,7 +682,7 @@ Array ui_array(Arena *arena) } PUT_C(info, "chan", INTEGER_OBJ((Integer)ui->channel_id)); - ADD_C(all_uis, DICTIONARY_OBJ(info)); + ADD_C(all_uis, DICT_OBJ(info)); } return all_uis; } diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c index 4f36cae4b2..adaf3eadb8 100644 --- a/src/nvim/ui_client.c +++ b/src/nvim/ui_client.c @@ -22,7 +22,9 @@ #include "nvim/memory_defs.h" #include "nvim/msgpack_rpc/channel.h" #include "nvim/msgpack_rpc/channel_defs.h" +#include "nvim/os/os.h" #include "nvim/os/os_defs.h" +#include "nvim/profile.h" #include "nvim/tui/tui.h" #include "nvim/tui/tui_defs.h" #include "nvim/ui.h" @@ -80,12 +82,15 @@ uint64_t ui_client_start_server(int argc, char **argv) return channel->id; } +/// Attaches this client to the UI channel, and sets its client info. void ui_client_attach(int width, int height, char *term, bool rgb) { + // + // nvim_ui_attach + // MAXSIZE_TEMP_ARRAY(args, 3); ADD_C(args, INTEGER_OBJ(width)); ADD_C(args, INTEGER_OBJ(height)); - MAXSIZE_TEMP_DICT(opts, 9); PUT_C(opts, "rgb", BOOLEAN_OBJ(rgb)); PUT_C(opts, "ext_linegrid", BOOLEAN_OBJ(true)); @@ -93,7 +98,6 @@ void ui_client_attach(int width, int height, char *term, bool rgb) if (term) { PUT_C(opts, "term_name", CSTR_AS_OBJ(term)); } - PUT_C(opts, "term_colors", INTEGER_OBJ(t_colors)); if (!ui_client_is_remote) { PUT_C(opts, "stdin_tty", BOOLEAN_OBJ(stdin_isatty)); @@ -103,10 +107,44 @@ void ui_client_attach(int width, int height, char *term, bool rgb) ui_client_forward_stdin = false; // stdin shouldn't be forwarded again #22292 } } - ADD_C(args, DICTIONARY_OBJ(opts)); + ADD_C(args, DICT_OBJ(opts)); rpc_send_event(ui_client_channel_id, "nvim_ui_attach", args); ui_client_attached = true; + + TIME_MSG("nvim_ui_attach"); + + // + // nvim_set_client_info + // + MAXSIZE_TEMP_ARRAY(args2, 5); + ADD_C(args2, CSTR_AS_OBJ("nvim-tui")); // name + Object m = api_metadata(); + Dict version = { 0 }; + assert(m.data.dict.size > 0); + for (size_t i = 0; i < m.data.dict.size; i++) { + if (strequal(m.data.dict.items[i].key.data, "version")) { + version = m.data.dict.items[i].value.data.dict; + break; + } else if (i + 1 == m.data.dict.size) { + abort(); + } + } + ADD_C(args2, DICT_OBJ(version)); // version + ADD_C(args2, CSTR_AS_OBJ("ui")); // type + // We don't send api_metadata.functions as the "methods" because: + // 1. it consumes memory. + // 2. it is unlikely to be useful, since the peer can just call `nvim_get_api`. + // 3. nvim_set_client_info expects a dict instead of an array. + ADD_C(args2, ARRAY_OBJ((Array)ARRAY_DICT_INIT)); // methods + MAXSIZE_TEMP_DICT(info, 9); // attributes + PUT_C(info, "website", CSTR_AS_OBJ("https://neovim.io")); + PUT_C(info, "license", CSTR_AS_OBJ("Apache 2")); + PUT_C(info, "pid", INTEGER_OBJ(os_get_pid())); + ADD_C(args2, DICT_OBJ(info)); // attributes + rpc_send_event(ui_client_channel_id, "nvim_set_client_info", args2); + + TIME_MSG("nvim_set_client_info"); } void ui_client_detach(void) @@ -126,6 +164,13 @@ void ui_client_run(bool remote_ui) ui_client_attach(width, height, term, rgb); + // TODO(justinmk): this is for log_spec. Can remove this after nvim_log #7062 is merged. + if (os_env_exists("__NVIM_TEST_LOG")) { + ELOG("test log message"); + } + + time_finish(); + // os_exit() will be invoked when the client channel detaches while (true) { LOOP_PROCESS_EVENTS(&main_loop, resize_events, -1); @@ -170,11 +215,11 @@ Object handle_ui_client_redraw(uint64_t channel_id, Array args, Arena *arena, Er return NIL; } -static HlAttrs ui_client_dict2hlattrs(Dictionary d, bool rgb) +static HlAttrs ui_client_dict2hlattrs(Dict d, bool rgb) { Error err = ERROR_INIT; Dict(highlight) dict = KEYDICT_INIT; - if (!api_dict_to_keydict(&dict, KeyDict_highlight_get_field, d, &err)) { + if (!api_dict_to_keydict(&dict, DictHash(highlight), d, &err)) { // TODO(bfredl): log "err" return HLATTRS_INIT; } diff --git a/src/nvim/ui_client.h b/src/nvim/ui_client.h index d3be9882aa..928bd4c0a5 100644 --- a/src/nvim/ui_client.h +++ b/src/nvim/ui_client.h @@ -14,7 +14,7 @@ EXTERN size_t grid_line_buf_size INIT( = 0); EXTERN schar_T *grid_line_buf_char INIT( = NULL); EXTERN sattr_T *grid_line_buf_attr INIT( = NULL); -// ID of the ui client channel. If zero, the client is not running. +// Client-side UI channel. Zero during early startup or if not a (--remote-ui) UI client. EXTERN uint64_t ui_client_channel_id INIT( = 0); // exit status from embedded nvim process diff --git a/src/nvim/undo.c b/src/nvim/undo.c index ba720c9f6a..15c8e0b283 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -92,6 +92,7 @@ #include "nvim/decoration.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds_defs.h" @@ -342,8 +343,7 @@ static OptInt get_undolevel(buf_T *buf) static inline void zero_fmark_additional_data(fmark_T *fmarks) { for (size_t i = 0; i < NMARKS; i++) { - tv_dict_unref(fmarks[i].additional_data); - fmarks[i].additional_data = NULL; + XFREE_CLEAR(fmarks[i].additional_data); } } @@ -1131,17 +1131,11 @@ static void serialize_pos(bufinfo_T *bi, pos_T pos) static void unserialize_pos(bufinfo_T *bi, pos_T *pos) { pos->lnum = undo_read_4c(bi); - if (pos->lnum < 0) { - pos->lnum = 0; - } + pos->lnum = MAX(pos->lnum, 0); pos->col = undo_read_4c(bi); - if (pos->col < 0) { - pos->col = 0; - } + pos->col = MAX(pos->col, 0); pos->coladd = undo_read_4c(bi); - if (pos->coladd < 0) { - pos->coladd = 0; - } + pos->coladd = MAX(pos->coladd, 0); } /// Serializes "info". @@ -1208,14 +1202,12 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf, // Strip any sticky and executable bits. perm = perm & 0666; - int fd; - // If the undo file already exists, verify that it actually is an undo // file, and delete it. if (os_path_exists(file_name)) { if (name == NULL || !forceit) { // Check we can read it and it's an undo file. - fd = os_open(file_name, O_RDONLY, 0); + int fd = os_open(file_name, O_RDONLY, 0); if (fd < 0) { if (name != NULL || p_verbose > 0) { if (name == NULL) { @@ -1260,7 +1252,7 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf, goto theend; } - fd = os_open(file_name, O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm); + int fd = os_open(file_name, O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm); if (fd < 0) { semsg(_(e_not_open), file_name); goto theend; @@ -2000,9 +1992,7 @@ void undo_time(int step, bool sec, bool file, bool absolute) target = curbuf->b_u_seq_cur + step; } if (step < 0) { - if (target < 0) { - target = 0; - } + target = MAX(target, 0); closest = -1; } else { if (dosec) { @@ -2395,9 +2385,7 @@ static void u_undoredo(bool undo, bool do_buf_event) } // Set the '[ mark. - if (top + 1 < curbuf->b_op_start.lnum) { - curbuf->b_op_start.lnum = top + 1; - } + curbuf->b_op_start.lnum = MIN(curbuf->b_op_start.lnum, top + 1); // Set the '] mark. if (newsize == 0 && top + 1 > curbuf->b_op_end.lnum) { curbuf->b_op_end.lnum = top + 1; @@ -2418,12 +2406,8 @@ static void u_undoredo(bool undo, bool do_buf_event) } // Ensure the '[ and '] marks are within bounds. - if (curbuf->b_op_start.lnum > curbuf->b_ml.ml_line_count) { - curbuf->b_op_start.lnum = curbuf->b_ml.ml_line_count; - } - if (curbuf->b_op_end.lnum > curbuf->b_ml.ml_line_count) { - curbuf->b_op_end.lnum = curbuf->b_ml.ml_line_count; - } + curbuf->b_op_start.lnum = MIN(curbuf->b_op_start.lnum, curbuf->b_ml.ml_line_count); + curbuf->b_op_end.lnum = MIN(curbuf->b_op_end.lnum, curbuf->b_ml.ml_line_count); // Adjust Extmarks if (undo) { diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c index e3d9dc5f54..d32e0ee319 100644 --- a/src/nvim/usercmd.c +++ b/src/nvim/usercmd.c @@ -98,6 +98,7 @@ static const char *command_complete[] = { [EXPAND_USER_VARS] = "var", [EXPAND_BREAKPOINT] = "breakpoint", [EXPAND_SCRIPTNAMES] = "scriptnames", + [EXPAND_DIRS_IN_CDPATH] = "dir_in_path", }; /// List of names of address types. Must be alphabetical for completion. @@ -414,7 +415,7 @@ char *get_user_cmd_complete(expand_T *xp, int idx) return NULL; } char *cmd_compl = get_command_complete(idx); - if (cmd_compl == NULL) { + if (cmd_compl == NULL || idx == EXPAND_USER_LUA) { return ""; } return cmd_compl; @@ -580,7 +581,7 @@ static void uc_list(char *name, size_t name_len) IObuff[len++] = ' '; } while ((int64_t)len < 25 - over); - IObuff[len] = '\0'; + IObuff[len] = NUL; msg_outtrans(IObuff, 0); if (cmd->uc_luaref != LUA_NOREF) { @@ -804,9 +805,7 @@ invalid_count: } } - if (*def < 0) { - *def = 0; - } + *def = MAX(*def, 0); } else if (STRNICMP(attr, "complete", attrlen) == 0) { if (val == NULL) { semsg(_(e_argument_required_for_str), "-complete"); @@ -831,7 +830,7 @@ invalid_count: } } else { char ch = attr[len]; - attr[len] = '\0'; + attr[len] = NUL; semsg(_("E181: Invalid attribute: %s"), attr); attr[len] = ch; return FAIL; @@ -1274,9 +1273,9 @@ static size_t add_cmd_modifier(char *buf, char *mod_str, bool *multi_mods) if (buf != NULL) { if (*multi_mods) { - STRCAT(buf, " "); + strcat(buf, " "); } - STRCAT(buf, mod_str); + strcat(buf, mod_str); } *multi_mods = true; @@ -1364,7 +1363,7 @@ size_t uc_mods(char *buf, const cmdmod_T *cmod, bool quote) if (quote) { *buf++ = '"'; } - *buf = '\0'; + *buf = NUL; } // the modifiers that are simple flags @@ -1744,14 +1743,14 @@ int do_ucmd(exarg_T *eap, bool preview) /// @param buf Buffer to inspect, or NULL to get global commands. /// /// @return Map of maps describing commands -Dictionary commands_array(buf_T *buf, Arena *arena) +Dict commands_array(buf_T *buf, Arena *arena) { garray_T *gap = (buf == NULL) ? &ucmds : &buf->b_ucmds; - Dictionary rv = arena_dict(arena, (size_t)gap->ga_len); + Dict rv = arena_dict(arena, (size_t)gap->ga_len); for (int i = 0; i < gap->ga_len; i++) { char arg[2] = { 0, 0 }; - Dictionary d = arena_dict(arena, 14); + Dict d = arena_dict(arena, 14); ucmd_T *cmd = USER_CMD_GA(gap, i); PUT_C(d, "name", CSTR_AS_OBJ(cmd->uc_name)); @@ -1815,7 +1814,7 @@ Dictionary commands_array(buf_T *buf, Arena *arena) } PUT_C(d, "addr", obj); - PUT_C(rv, cmd->uc_name, DICTIONARY_OBJ(d)); + PUT_C(rv, cmd->uc_name, DICT_OBJ(d)); } return rv; } diff --git a/src/nvim/version.c b/src/nvim/version.c index c392362bf4..368bf79cf4 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -1069,7 +1069,7 @@ static const int included_patches[] = { 1416, 1415, 1414, - // 1413, + 1413, 1412, 1411, 1410, @@ -1376,7 +1376,7 @@ static const int included_patches[] = { 1109, 1108, 1107, - // 1106, + 1106, 1105, 1104, 1103, diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c index 3403fb7926..7fb4c62b35 100644 --- a/src/nvim/viml/parser/expressions.c +++ b/src/nvim/viml/parser/expressions.c @@ -1264,21 +1264,12 @@ static bool viml_pexpr_handle_bop(const ParserState *const pstate, ExprASTStack || bop_node->type == kExprNodeSubscript) ? kEOpLvlSubscript : node_lvl(*bop_node)); -#ifndef NDEBUG - const ExprOpAssociativity bop_node_ass = ( - (bop_node->type == kExprNodeCall - || bop_node->type == kExprNodeSubscript) - ? kEOpAssLeft - : node_ass(*bop_node)); -#endif do { ExprASTNode **new_top_node_p = kv_last(*ast_stack); ExprASTNode *new_top_node = *new_top_node_p; assert(new_top_node != NULL); const ExprOpLvl new_top_node_lvl = node_lvl(*new_top_node); const ExprOpAssociativity new_top_node_ass = node_ass(*new_top_node); - assert(bop_node_lvl != new_top_node_lvl - || bop_node_ass == new_top_node_ass); if (top_node_p != NULL && ((bop_node_lvl > new_top_node_lvl || (bop_node_lvl == new_top_node_lvl @@ -3014,8 +3005,7 @@ viml_pexpr_parse_end: break; case kExprNodeCurlyBracesIdentifier: // Until trailing "}" it is impossible to distinguish curly braces - // identifier and dictionary, so it must not appear in the stack like - // this. + // identifier and Dict, so it must not appear in the stack like this. abort(); case kExprNodeInteger: case kExprNodeFloat: diff --git a/src/nvim/viml/parser/expressions.h b/src/nvim/viml/parser/expressions.h index ba54c4de07..60c3db8c8f 100644 --- a/src/nvim/viml/parser/expressions.h +++ b/src/nvim/viml/parser/expressions.h @@ -216,7 +216,7 @@ typedef enum { /// kExprNodeCurlyBracesIdentifier. kExprNodeUnknownFigure, kExprNodeLambda, ///< Lambda. - kExprNodeDictLiteral, ///< Dictionary literal. + kExprNodeDictLiteral, ///< Dict literal. kExprNodeCurlyBracesIdentifier, ///< Part of the curly braces name. kExprNodeComma, ///< Comma “operatorâ€. kExprNodeColon, ///< Colon “operatorâ€. diff --git a/src/nvim/viml/parser/parser.h b/src/nvim/viml/parser/parser.h index 31decdc798..c4ebc1589a 100644 --- a/src/nvim/viml/parser/parser.h +++ b/src/nvim/viml/parser/parser.h @@ -5,13 +5,13 @@ #include <stddef.h> #include "klib/kvec.h" -#include "nvim/func_attr.h" #include "nvim/mbyte_defs.h" #include "nvim/viml/parser/parser_defs.h" // IWYU pragma: keep -static inline void viml_parser_init(ParserState *ret_pstate, ParserLineGetter get_line, - void *cookie, ParserHighlight *colors) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ARG(1, 2); +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "viml/parser/parser.h.generated.h" +# include "viml/parser/parser.h.inline.generated.h" +#endif /// Initialize a new parser state instance /// @@ -22,6 +22,7 @@ static inline void viml_parser_init(ParserState *ret_pstate, ParserLineGetter ge /// needed. static inline void viml_parser_init(ParserState *const ret_pstate, const ParserLineGetter get_line, void *const cookie, ParserHighlight *const colors) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(1, 2) { *ret_pstate = (ParserState) { .reader = { @@ -37,9 +38,6 @@ static inline void viml_parser_init(ParserState *const ret_pstate, const ParserL kvi_init(ret_pstate->stack); } -static inline void viml_parser_advance(ParserState *pstate, size_t len) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL; - /// Advance position by a given number of bytes /// /// At maximum advances to the next line. @@ -47,6 +45,7 @@ static inline void viml_parser_advance(ParserState *pstate, size_t len) /// @param pstate Parser state to advance. /// @param[in] len Number of bytes to advance. static inline void viml_parser_advance(ParserState *const pstate, const size_t len) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL { assert(pstate->pos.line == kv_size(pstate->reader.lines) - 1); const ParserLine pline = kv_last(pstate->reader.lines); @@ -58,10 +57,6 @@ static inline void viml_parser_advance(ParserState *const pstate, const size_t l } } -static inline void viml_parser_highlight(ParserState *pstate, ParserPosition start, size_t len, - const char *group) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL; - /// Record highlighting of some region of text /// /// @param pstate Parser state to work with. @@ -70,6 +65,7 @@ static inline void viml_parser_highlight(ParserState *pstate, ParserPosition sta /// @param[in] group Highlight group. static inline void viml_parser_highlight(ParserState *const pstate, const ParserPosition start, const size_t len, const char *const group) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL { if (pstate->colors == NULL || len == 0) { return; @@ -83,7 +79,3 @@ static inline void viml_parser_highlight(ParserState *const pstate, const Parser .group = group, })); } - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "viml/parser/parser.h.generated.h" -#endif diff --git a/src/nvim/window.c b/src/nvim/window.c index 1a6c3f7263..d3280a3478 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -22,6 +22,7 @@ #include "nvim/diff.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" @@ -72,6 +73,7 @@ #include "nvim/statusline.h" #include "nvim/strings.h" #include "nvim/syntax.h" +#include "nvim/tag.h" #include "nvim/terminal.h" #include "nvim/types_defs.h" #include "nvim/ui.h" @@ -357,13 +359,13 @@ newwindow: wp = lastwin; // wrap around } while (wp != NULL && wp->w_floating - && !wp->w_config.focusable) { + && (wp->w_config.hide || !wp->w_config.focusable)) { wp = wp->w_prev; } } else { // go to next window wp = curwin->w_next; while (wp != NULL && wp->w_floating - && !wp->w_config.focusable) { + && (wp->w_config.hide || !wp->w_config.focusable)) { wp = wp->w_next; } if (wp == NULL) { @@ -796,6 +798,19 @@ int win_fdccol_count(win_T *wp) return fdc[0] - '0'; } +/// Merges two window configs, freeing replaced fields if necessary. +void merge_win_config(WinConfig *dst, const WinConfig src) + FUNC_ATTR_NONNULL_ALL +{ + if (dst->title_chunks.items != src.title_chunks.items) { + clear_virttext(&dst->title_chunks); + } + if (dst->footer_chunks.items != src.footer_chunks.items) { + clear_virttext(&dst->footer_chunks); + } + *dst = src; +} + void ui_ext_win_position(win_T *wp, bool validate) { wp->w_pos_changed = false; @@ -1111,12 +1126,7 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir, frame_T *to_fl if (new_size == 0) { new_size = oldwin->w_width / 2; } - if (new_size > available - minwidth - 1) { - new_size = available - minwidth - 1; - } - if (new_size < wmw1) { - new_size = wmw1; - } + new_size = MAX(MIN(new_size, available - minwidth - 1), wmw1); // if it doesn't fit in the current window, need win_equal() if (oldwin->w_width - new_size - 1 < p_wmw) { @@ -1197,12 +1207,7 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir, frame_T *to_fl new_size = oldwin_height / 2; } - if (new_size > available - minheight - STATUS_HEIGHT) { - new_size = available - minheight - STATUS_HEIGHT; - } - if (new_size < wmh1) { - new_size = wmh1; - } + new_size = MAX(MIN(new_size, available - minheight - STATUS_HEIGHT), wmh1); // if it doesn't fit in the current window, need win_equal() if (oldwin_height - new_size - STATUS_HEIGHT < p_wmh) { @@ -1296,7 +1301,7 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir, frame_T *to_fl new_frame(wp); // non-floating window doesn't store float config or have a border. - wp->w_config = WIN_CONFIG_INIT; + merge_win_config(&wp->w_config, WIN_CONFIG_INIT); CLEAR_FIELD(wp->w_border_adj); } @@ -1729,12 +1734,8 @@ int make_windows(int count, bool vertical) - (p_wh - p_wmh)) / ((int)p_wmh + STATUS_HEIGHT + global_winbar_height()); } - if (maxcount < 2) { - maxcount = 2; - } - if (count > maxcount) { - count = maxcount; - } + maxcount = MAX(maxcount, 2); + count = MIN(count, maxcount); // add status line now, otherwise first window will be too big if (count > 1) { @@ -2188,9 +2189,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int if (frame_has_win(fr, next_curwin)) { room += (int)p_wiw - (int)p_wmw; next_curwin_size = 0; - if (new_size < p_wiw) { - new_size = (int)p_wiw; - } + new_size = MAX(new_size, (int)p_wiw); } else { // These windows don't use up room. totwincount -= (n + (fr->fr_next == NULL ? extra_sep : 0)) / ((int)p_wmw + 1); @@ -2253,9 +2252,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int } if (hnc) { // add next_curwin size next_curwin_size -= (int)p_wiw - (m - n); - if (next_curwin_size < 0) { - next_curwin_size = 0; - } + next_curwin_size = MAX(next_curwin_size, 0); new_size += next_curwin_size; room -= new_size - next_curwin_size; } else { @@ -2318,9 +2315,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int if (frame_has_win(fr, next_curwin)) { room += (int)p_wh - (int)p_wmh; next_curwin_size = 0; - if (new_size < p_wh) { - new_size = (int)p_wh; - } + new_size = MAX(new_size, (int)p_wh); } else { // These windows don't use up room. totwincount -= get_maximum_wincount(fr, (n + (fr->fr_next == NULL ? extra_sep : 0))); @@ -2489,7 +2484,7 @@ void close_windows(buf_T *buf, bool keep_curwin) // When the autocommand window is involved win_close() may need to print an error message. for (win_T *wp = lastwin; wp != NULL && (is_aucmd_win(lastwin) || !one_window(wp));) { if (wp->w_buffer == buf && (!keep_curwin || wp != curwin) - && !(wp->w_closing || wp->w_buffer->b_locked > 0)) { + && !(win_locked(wp) || wp->w_buffer->b_locked > 0)) { if (win_close(wp, false, false) == FAIL) { // If closing the window fails give up, to avoid looping forever. break; @@ -2511,7 +2506,7 @@ void close_windows(buf_T *buf, bool keep_curwin) // Start from tp_lastwin to close floating windows with the same buffer first. for (win_T *wp = tp->tp_lastwin; wp != NULL; wp = wp->w_prev) { if (wp->w_buffer == buf - && !(wp->w_closing || wp->w_buffer->b_locked > 0)) { + && !(win_locked(wp) || wp->w_buffer->b_locked > 0)) { win_close_othertab(wp, false, tp); // Start all over, the tab page may be closed and @@ -2648,10 +2643,10 @@ static void win_close_buffer(win_T *win, int action, bool abort_if_last) if (win->w_buffer != NULL) { bufref_T bufref; set_bufref(&bufref, curbuf); - win->w_closing = true; + win->w_locked = true; close_buffer(win, win->w_buffer, action, abort_if_last, true); if (win_valid_any_tab(win)) { - win->w_closing = false; + win->w_locked = false; } // Make sure curbuf is valid. It can become invalid if 'bufhidden' is @@ -2679,7 +2674,7 @@ int win_close(win_T *win, bool free_buf, bool force) return FAIL; } - if (win->w_closing + if (win_locked(win) || (win->w_buffer != NULL && win->w_buffer->b_locked > 0)) { return FAIL; // window is already being closed } @@ -2754,22 +2749,22 @@ int win_close(win_T *win, bool free_buf, bool force) if (!win_valid(win)) { return FAIL; } - win->w_closing = true; + win->w_locked = true; apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, false, curbuf); if (!win_valid(win)) { return FAIL; } - win->w_closing = false; + win->w_locked = false; if (last_window(win)) { return FAIL; } } - win->w_closing = true; + win->w_locked = true; apply_autocmds(EVENT_WINLEAVE, NULL, NULL, false, curbuf); if (!win_valid(win)) { return FAIL; } - win->w_closing = false; + win->w_locked = false; if (last_window(win)) { return FAIL; } @@ -2816,9 +2811,6 @@ int win_close(win_T *win, bool free_buf, bool force) // to split a window to avoid trouble. split_disallowed++; - // let terminal buffers know that this window dimensions may be ignored - win->w_closing = true; - bool was_floating = win->w_floating; if (ui_has(kUIMultigrid)) { ui_call_win_close(win->w_grid_alloc.handle); @@ -2872,7 +2864,7 @@ int win_close(win_T *win, bool free_buf, bool force) break; } if (!wp->w_p_pvw && !bt_quickfix(wp->w_buffer) - && !(wp->w_floating && !wp->w_config.focusable)) { + && !(wp->w_floating && (wp->w_config.hide || !wp->w_config.focusable))) { curwin = wp; break; } @@ -2967,7 +2959,7 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp) { // Get here with win->w_buffer == NULL when win_close() detects the tab page // changed. - if (win->w_closing + if (win_locked(win) || (win->w_buffer != NULL && win->w_buffer->b_locked > 0)) { return; // window is already being closed } @@ -3455,14 +3447,23 @@ static frame_T *win_altframe(win_T *win, tabpage_T *tp) // Return the tabpage that will be used if the current one is closed. static tabpage_T *alt_tabpage(void) { - // Use the next tab page if possible. - if (curtab->tp_next != NULL) { - return curtab->tp_next; + // Use the last accessed tab page, if possible. + if ((tcl_flags & TCL_USELAST) && valid_tabpage(lastused_tabpage)) { + return lastused_tabpage; } - // Find the last but one tab page. + // Use the next tab page, if possible. + bool forward = curtab->tp_next != NULL + && ((tcl_flags & TCL_LEFT) == 0 || curtab == first_tabpage); + tabpage_T *tp; - for (tp = first_tabpage; tp->tp_next != curtab; tp = tp->tp_next) {} + if (forward) { + tp = curtab->tp_next; + } else { + // Use the previous tab page. + for (tp = first_tabpage; tp->tp_next != curtab; tp = tp->tp_next) {} + } + return tp; } @@ -3921,9 +3922,7 @@ static int frame_minwidth(frame_T *topfrp, win_T *next_curwin) frame_T *frp; FOR_ALL_FRAMES(frp, topfrp->fr_child) { int n = frame_minwidth(frp, next_curwin); - if (n > m) { - m = n; - } + m = MAX(m, n); } } else { // Add up the minimal widths for all frames in this row. @@ -4256,9 +4255,7 @@ int make_tabpages(int maxcount) int count = maxcount; // Limit to 'tabpagemax' tabs. - if (count > p_tpm) { - count = (int)p_tpm; - } + count = MIN(count, (int)p_tpm); // Don't execute autocommands while creating the tab pages. Must do that // when putting the buffers in the windows. @@ -5219,8 +5216,7 @@ void win_free(win_T *wp, tabpage_T *tp) xfree(wp->w_lines); for (int i = 0; i < wp->w_tagstacklen; i++) { - xfree(wp->w_tagstack[i].tagname); - xfree(wp->w_tagstack[i].user_data); + tagstack_clear_entry(&wp->w_tagstack[i]); } xfree(wp->w_localdir); @@ -5418,14 +5414,10 @@ void win_new_screensize(void) /// This only does the current tab page, others must be done when made active. void win_new_screen_rows(void) { - int h = (int)ROWS_AVAIL; - if (firstwin == NULL) { // not initialized yet return; } - if (h < frame_minheight(topframe, NULL)) { - h = frame_minheight(topframe, NULL); - } + int h = MAX((int)ROWS_AVAIL, frame_minheight(topframe, NULL)); // First try setting the heights of windows with 'winfixheight'. If // that doesn't result in the right height, forget about that option. @@ -5922,9 +5914,7 @@ static void frame_setheight(frame_T *curfrp, int height) // Row of frames: Also need to resize frames left and right of this // one. First check for the minimal height of these. int h = frame_minheight(curfrp->fr_parent, NULL); - if (height < h) { - height = h; - } + height = MAX(height, h); frame_setheight(curfrp->fr_parent, height); } else { // Column of frames: try to change only frames in this column. @@ -5959,9 +5949,7 @@ static void frame_setheight(frame_T *curfrp, int height) win_T *wp = lastwin_nofloating(); room_cmdline = Rows - (int)p_ch - global_stl_height() - (wp->w_winrow + wp->w_height + wp->w_hsep_height + wp->w_status_height); - if (room_cmdline < 0) { - room_cmdline = 0; - } + room_cmdline = MAX(room_cmdline, 0); } if (height <= room + room_cmdline) { @@ -5993,9 +5981,7 @@ static void frame_setheight(frame_T *curfrp, int height) if (take > 0 && room_cmdline > 0) { // use lines from cmdline first - if (take < room_cmdline) { - room_cmdline = take; - } + room_cmdline = MIN(room_cmdline, take), take -= room_cmdline; topframe->fr_height += room_cmdline; } @@ -6057,12 +6043,7 @@ void win_setwidth_win(int width, win_T *wp) // Always keep current window at least one column wide, even when // 'winminwidth' is zero. if (wp == curwin) { - if (width < p_wmw) { - width = (int)p_wmw; - } - if (width == 0) { - width = 1; - } + width = MAX(MAX(width, (int)p_wmw), 1); } else if (width < 0) { width = 0; } @@ -6100,9 +6081,7 @@ static void frame_setwidth(frame_T *curfrp, int width) // Column of frames: Also need to resize frames above and below of // this one. First check for the minimal width of these. int w = frame_minwidth(curfrp->fr_parent, NULL); - if (width < w) { - width = w; - } + width = MAX(width, w); frame_setwidth(curfrp->fr_parent, width); } else { // Row of frames: try to change only frames in this row. @@ -6299,9 +6278,7 @@ void win_drag_status_line(win_T *dragwin, int offset) } else if (!p_ch_was_zero) { room--; } - if (room < 0) { - room = 0; - } + room = MAX(room, 0); // sum up the room of frames below of the current one FOR_ALL_FRAMES(fr, curfr->fr_next) { room += fr->fr_height - frame_minheight(fr, NULL); @@ -6309,9 +6286,8 @@ void win_drag_status_line(win_T *dragwin, int offset) fr = curfr; // put fr at window that grows } - if (room < offset) { // Not enough room - offset = room; // Move as far as we can - } + // If not enough room then move as far as we can + offset = MIN(offset, room); if (offset <= 0) { return; } @@ -6413,10 +6389,8 @@ void win_drag_vsep_line(win_T *dragwin, int offset) fr = curfr; // put fr at window that grows } - // Not enough room - if (room < offset) { - offset = room; // Move as far as we can - } + // If not enough room thn move as far as we can + offset = MIN(offset, room); // No room at all, quit. if (offset <= 0) { @@ -6587,9 +6561,7 @@ void win_new_height(win_T *wp, int height) { // Don't want a negative height. Happens when splitting a tiny window. // Will equalize heights soon to fix it. - if (height < 0) { - height = 0; - } + height = MAX(height, 0); if (wp->w_height == height) { return; // nothing to do } @@ -6615,9 +6587,8 @@ void scroll_to_fraction(win_T *wp, int prev_height) // Find a value for w_topline that shows the cursor at the same // relative position in the window as before (more or less). linenr_T lnum = wp->w_cursor.lnum; - if (lnum < 1) { // can happen when starting up - lnum = 1; - } + // can happen when starting up + lnum = MAX(lnum, 1); wp->w_wrow = (wp->w_fraction * height - 1) / FRACTION_MULT; int line_size = plines_win_col(wp, lnum, wp->w_cursor.col) - 1; int sline = wp->w_wrow - line_size; @@ -6833,9 +6804,7 @@ void command_height(void) break; } int h = frp->fr_height - frame_minheight(frp, NULL); - if (h > p_ch - old_p_ch) { - h = (int)p_ch - old_p_ch; - } + h = MIN(h, (int)p_ch - old_p_ch); old_p_ch += h; frame_add_height(frp, -h); frp = frp->fr_prev; @@ -6853,9 +6822,7 @@ void command_height(void) return; } - if (msg_row < cmdline_row) { - msg_row = cmdline_row; - } + msg_row = MAX(msg_row, cmdline_row); redraw_cmdline = true; } frame_add_height(frp, (int)(old_p_ch - p_ch)); @@ -6880,142 +6847,6 @@ static void frame_add_height(frame_T *frp, int n) } } -// Get the file name at the cursor. -// If Visual mode is active, use the selected text if it's in one line. -// Returns the name in allocated memory, NULL for failure. -char *grab_file_name(int count, linenr_T *file_lnum) -{ - int options = FNAME_MESS | FNAME_EXP | FNAME_REL | FNAME_UNESC; - if (VIsual_active) { - size_t len; - char *ptr; - if (get_visual_text(NULL, &ptr, &len) == FAIL) { - return NULL; - } - // Only recognize ":123" here - if (file_lnum != NULL && ptr[len] == ':' && isdigit((uint8_t)ptr[len + 1])) { - char *p = ptr + len + 1; - - *file_lnum = getdigits_int32(&p, false, 0); - } - return find_file_name_in_path(ptr, len, options, count, curbuf->b_ffname); - } - return file_name_at_cursor(options | FNAME_HYP, count, file_lnum); -} - -// Return the file name under or after the cursor. -// -// The 'path' option is searched if the file name is not absolute. -// The string returned has been alloc'ed and should be freed by the caller. -// NULL is returned if the file name or file is not found. -// -// options: -// FNAME_MESS give error messages -// FNAME_EXP expand to path -// FNAME_HYP check for hypertext link -// FNAME_INCL apply "includeexpr" -char *file_name_at_cursor(int options, int count, linenr_T *file_lnum) -{ - return file_name_in_line(get_cursor_line_ptr(), - curwin->w_cursor.col, options, count, curbuf->b_ffname, - file_lnum); -} - -/// @param rel_fname file we are searching relative to -/// @param file_lnum line number after the file name -/// -/// @return the name of the file under or after ptr[col]. Otherwise like file_name_at_cursor(). -char *file_name_in_line(char *line, int col, int options, int count, char *rel_fname, - linenr_T *file_lnum) -{ - // search forward for what could be the start of a file name - char *ptr = line + col; - while (*ptr != NUL && !vim_isfilec((uint8_t)(*ptr))) { - MB_PTR_ADV(ptr); - } - if (*ptr == NUL) { // nothing found - if (options & FNAME_MESS) { - emsg(_("E446: No file name under cursor")); - } - return NULL; - } - - size_t len; - bool in_type = true; - bool is_url = false; - - // Search backward for first char of the file name. - // Go one char back to ":" before "//", or to the drive letter before ":\" (even if ":" - // is not in 'isfname'). - while (ptr > line) { - if ((len = (size_t)(utf_head_off(line, ptr - 1))) > 0) { - ptr -= len + 1; - } else if (vim_isfilec((uint8_t)ptr[-1]) || ((options & FNAME_HYP) && path_is_url(ptr - 1))) { - ptr--; - } else { - break; - } - } - - // Search forward for the last char of the file name. - // Also allow ":/" when ':' is not in 'isfname'. - len = path_has_drive_letter(ptr) ? 2 : 0; - while (vim_isfilec((uint8_t)ptr[len]) || (ptr[len] == '\\' && ptr[len + 1] == ' ') - || ((options & FNAME_HYP) && path_is_url(ptr + len)) - || (is_url && vim_strchr(":?&=", (uint8_t)ptr[len]) != NULL)) { - // After type:// we also include :, ?, & and = as valid characters, so that - // http://google.com:8080?q=this&that=ok works. - if ((ptr[len] >= 'A' && ptr[len] <= 'Z') || (ptr[len] >= 'a' && ptr[len] <= 'z')) { - if (in_type && path_is_url(ptr + len + 1)) { - is_url = true; - } - } else { - in_type = false; - } - - if (ptr[len] == '\\' && ptr[len + 1] == ' ') { - // Skip over the "\" in "\ ". - len++; - } - len += (size_t)(utfc_ptr2len(ptr + len)); - } - - // If there is trailing punctuation, remove it. - // But don't remove "..", could be a directory name. - if (len > 2 && vim_strchr(".,:;!", (uint8_t)ptr[len - 1]) != NULL - && ptr[len - 2] != '.') { - len--; - } - - if (file_lnum != NULL) { - const char *line_english = " line "; - const char *line_transl = _(line_msg); - - // Get the number after the file name and a separator character. - // Also accept " line 999" with and without the same translation as - // used in last_set_msg(). - char *p = ptr + len; - if (strncmp(p, line_english, strlen(line_english)) == 0) { - p += strlen(line_english); - } else if (strncmp(p, line_transl, strlen(line_transl)) == 0) { - p += strlen(line_transl); - } else { - p = skipwhite(p); - } - if (*p != NUL) { - if (!isdigit((uint8_t)(*p))) { - p++; // skip the separator - } - p = skipwhite(p); - if (isdigit((uint8_t)(*p))) { - *file_lnum = (linenr_T)getdigits_long(&p, false, 0); - } - } - } - - return find_file_name_in_path(ptr, len, options, count, rel_fname); -} - /// Add or remove a status line from window(s), according to the /// value of 'laststatus'. /// @@ -7241,9 +7072,7 @@ int min_rows(void) int total = 0; FOR_ALL_TABS(tp) { int n = frame_minheight(tp->tp_topframe, NULL); - if (total < n) { - total = n; - } + total = MAX(total, n); } total += tabline_height() + global_stl_height(); if (p_ch > 0) { @@ -7538,13 +7367,7 @@ static int int_cmp(const void *pa, const void *pb) { const int a = *(const int *)pa; const int b = *(const int *)pb; - if (a > b) { - return 1; - } - if (a < b) { - return -1; - } - return 0; + return a == b ? 0 : a < b ? -1 : 1; } /// Handle setting 'colorcolumn' or 'textwidth' in window "wp". @@ -7626,6 +7449,12 @@ int get_last_winid(void) return last_win_id; } +/// Don't let autocommands close the given window +int win_locked(win_T *wp) +{ + return wp->w_locked; +} + void win_get_tabwin(handle_T id, int *tabnr, int *winnr) { *tabnr = 0; diff --git a/src/nvim/window.h b/src/nvim/window.h index d20b799e20..9618ff1c2a 100644 --- a/src/nvim/window.h +++ b/src/nvim/window.h @@ -8,17 +8,6 @@ #include "nvim/option_defs.h" // IWYU pragma: keep #include "nvim/types_defs.h" // IWYU pragma: keep -/// Values for file_name_in_line() -enum { - FNAME_MESS = 1, ///< give error message - FNAME_EXP = 2, ///< expand to path - FNAME_HYP = 4, ///< check for hypertext link - FNAME_INCL = 8, ///< apply 'includeexpr' - FNAME_REL = 16, ///< ".." and "./" are relative to the (current) - ///< file instead of the current directory - FNAME_UNESC = 32, ///< remove backslashes used for escaping -}; - /// arguments for win_split() enum { WSP_ROOM = 0x01, ///< require enough room diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c index e3ca0ff139..fdb65ad614 100644 --- a/src/nvim/winfloat.c +++ b/src/nvim/winfloat.c @@ -10,12 +10,15 @@ #include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/buffer_defs.h" +#include "nvim/decoration.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/grid_defs.h" #include "nvim/macros_defs.h" #include "nvim/memory.h" +#include "nvim/message.h" #include "nvim/mouse.h" #include "nvim/move.h" #include "nvim/option.h" @@ -56,7 +59,7 @@ win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err) if (!tp) { return NULL; } - tp_last = tp->tp_lastwin; + tp_last = tp == curtab ? lastwin : tp->tp_lastwin; while (tp_last->w_floating && tp_last->w_prev) { tp_last = tp_last->w_prev; } @@ -200,7 +203,7 @@ void win_config_float(win_T *wp, WinConfig fconfig) wp->w_config.border_hl_ids, sizeof fconfig.border_hl_ids) != 0); - wp->w_config = fconfig; + merge_win_config(&wp->w_config, fconfig); bool has_border = wp->w_floating && wp->w_config.border; for (int i = 0; i < 4; i++) { @@ -358,6 +361,21 @@ win_T *win_float_find_altwin(const win_T *win, const tabpage_T *tp) : tp->tp_firstwin; } +/// Inline helper function for handling errors and cleanup in win_float_create. +static inline win_T *handle_error_and_cleanup(win_T *wp, Error *err) +{ + if (ERROR_SET(err)) { + emsg(err->msg); + api_clear_error(err); + } + if (wp) { + win_remove(wp, NULL); + win_free(wp, NULL); + } + unblock_autocmds(); + return NULL; +} + /// create a floating preview window. /// /// @param[in] bool enter floating window. @@ -380,23 +398,25 @@ win_T *win_float_create(bool enter, bool new_buf) block_autocmds(); win_T *wp = win_new_float(NULL, false, config, &err); if (!wp) { - unblock_autocmds(); - return NULL; + return handle_error_and_cleanup(wp, &err); } if (new_buf) { Buffer b = nvim_create_buf(false, true, &err); if (!b) { - win_remove(wp, NULL); - win_free(wp, NULL); - unblock_autocmds(); - return NULL; + return handle_error_and_cleanup(wp, &err); } buf_T *buf = find_buffer_by_handle(b, &err); + if (!buf) { + return handle_error_and_cleanup(wp, &err); + } buf->b_p_bl = false; // unlist set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("wipe"), OPT_LOCAL, 0, kOptReqBuf, buf); win_set_buf(wp, buf, &err); + if (ERROR_SET(&err)) { + return handle_error_and_cleanup(wp, &err); + } } unblock_autocmds(); wp->w_p_diff = false; diff --git a/src/termkey/driver-csi.c b/src/termkey/driver-csi.c deleted file mode 100644 index 4cd5bbafe4..0000000000 --- a/src/termkey/driver-csi.c +++ /dev/null @@ -1,772 +0,0 @@ -#include "termkey.h" -#include "termkey-internal.h" - -#include <stdio.h> -#include <string.h> - -// There are 64 codes 0x40 - 0x7F -static int keyinfo_initialised = 0; -static struct keyinfo ss3s[64]; -static char ss3_kpalts[64]; - -typedef struct { - TermKey *tk; - int saved_string_id; - char *saved_string; -} TermKeyCsi; - -typedef TermKeyResult CsiHandler(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args); -static CsiHandler *csi_handlers[64]; - -/* - * Handler for CSI/SS3 cmd keys - */ - -static struct keyinfo csi_ss3s[64]; - -static TermKeyResult handle_csi_ss3_full(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args) -{ - if(args > 1 && arg[1] != -1) - key->modifiers = arg[1] - 1; - else - key->modifiers = 0; - - key->type = csi_ss3s[cmd - 0x40].type; - key->code.sym = csi_ss3s[cmd - 0x40].sym; - key->modifiers &= ~(csi_ss3s[cmd - 0x40].modifier_mask); - key->modifiers |= csi_ss3s[cmd - 0x40].modifier_set; - - if(key->code.sym == TERMKEY_SYM_UNKNOWN) - return TERMKEY_RES_NONE; - - return TERMKEY_RES_KEY; -} - -static void register_csi_ss3_full(TermKeyType type, TermKeySym sym, int modifier_set, int modifier_mask, unsigned char cmd) -{ - if(cmd < 0x40 || cmd >= 0x80) { - return; - } - - csi_ss3s[cmd - 0x40].type = type; - csi_ss3s[cmd - 0x40].sym = sym; - csi_ss3s[cmd - 0x40].modifier_set = modifier_set; - csi_ss3s[cmd - 0x40].modifier_mask = modifier_mask; - - csi_handlers[cmd - 0x40] = &handle_csi_ss3_full; -} - -static void register_csi_ss3(TermKeyType type, TermKeySym sym, unsigned char cmd) -{ - register_csi_ss3_full(type, sym, 0, 0, cmd); -} - -/* - * Handler for SS3 keys with kpad alternate representations - */ - -static void register_ss3kpalt(TermKeyType type, TermKeySym sym, unsigned char cmd, char kpalt) -{ - if(cmd < 0x40 || cmd >= 0x80) { - return; - } - - ss3s[cmd - 0x40].type = type; - ss3s[cmd - 0x40].sym = sym; - ss3s[cmd - 0x40].modifier_set = 0; - ss3s[cmd - 0x40].modifier_mask = 0; - ss3_kpalts[cmd - 0x40] = kpalt; -} - -/* - * Handler for CSI number ~ function keys - */ - -static struct keyinfo csifuncs[35]; /* This value must be increased if more CSI function keys are added */ -#define NCSIFUNCS (sizeof(csifuncs)/sizeof(csifuncs[0])) - -static TermKeyResult handle_csifunc(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args) -{ - if(args > 1 && arg[1] != -1) - key->modifiers = arg[1] - 1; - else - key->modifiers = 0; - - key->type = TERMKEY_TYPE_KEYSYM; - - if(arg[0] == 27) { - int mod = key->modifiers; - (*tk->method.emit_codepoint)(tk, arg[2], key); - key->modifiers |= mod; - } - else if(arg[0] >= 0 && arg[0] < NCSIFUNCS) { - key->type = csifuncs[arg[0]].type; - key->code.sym = csifuncs[arg[0]].sym; - key->modifiers &= ~(csifuncs[arg[0]].modifier_mask); - key->modifiers |= csifuncs[arg[0]].modifier_set; - } - else - key->code.sym = TERMKEY_SYM_UNKNOWN; - - if(key->code.sym == TERMKEY_SYM_UNKNOWN) { -#ifdef DEBUG - fprintf(stderr, "CSI: Unknown function key %ld\n", arg[0]); -#endif - return TERMKEY_RES_NONE; - } - - return TERMKEY_RES_KEY; -} - -static void register_csifunc(TermKeyType type, TermKeySym sym, int number) -{ - if(number >= NCSIFUNCS) { - return; - } - - csifuncs[number].type = type; - csifuncs[number].sym = sym; - csifuncs[number].modifier_set = 0; - csifuncs[number].modifier_mask = 0; - - csi_handlers['~' - 0x40] = &handle_csifunc; -} - -/* - * Handler for CSI u extended Unicode keys - */ - -static TermKeyResult handle_csi_u(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args) -{ - switch(cmd) { - case 'u': { - if(args > 1 && arg[1] != -1) - key->modifiers = arg[1] - 1; - else - key->modifiers = 0; - - int mod = key->modifiers; - key->type = TERMKEY_TYPE_KEYSYM; - (*tk->method.emit_codepoint)(tk, arg[0], key); - key->modifiers |= mod; - - return TERMKEY_RES_KEY; - } - default: - return TERMKEY_RES_NONE; - } -} - -/* - * Handler for CSI M / CSI m mouse events in SGR and rxvt encodings - * Note: This does not handle X10 encoding - */ - -static TermKeyResult handle_csi_m(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args) -{ - int initial = cmd >> 8; - cmd &= 0xff; - - switch(cmd) { - case 'M': - case 'm': - break; - default: - return TERMKEY_RES_NONE; - } - - if(!initial && args >= 3) { // rxvt protocol - key->type = TERMKEY_TYPE_MOUSE; - key->code.mouse[0] = arg[0]; - - key->modifiers = (key->code.mouse[0] & 0x1c) >> 2; - key->code.mouse[0] &= ~0x1c; - - termkey_key_set_linecol(key, arg[1], arg[2]); - - return TERMKEY_RES_KEY; - } - - if(initial == '<' && args >= 3) { // SGR protocol - key->type = TERMKEY_TYPE_MOUSE; - key->code.mouse[0] = arg[0]; - - key->modifiers = (key->code.mouse[0] & 0x1c) >> 2; - key->code.mouse[0] &= ~0x1c; - - termkey_key_set_linecol(key, arg[1], arg[2]); - - if(cmd == 'm') // release - key->code.mouse[3] |= 0x80; - - return TERMKEY_RES_KEY; - } - - return TERMKEY_RES_NONE; -} - -TermKeyResult termkey_interpret_mouse(TermKey *tk, const TermKeyKey *key, TermKeyMouseEvent *event, int *button, int *line, int *col) -{ - if(key->type != TERMKEY_TYPE_MOUSE) - return TERMKEY_RES_NONE; - - if(button) - *button = 0; - - termkey_key_get_linecol(key, line, col); - - if(!event) - return TERMKEY_RES_KEY; - - int btn = 0; - - int code = key->code.mouse[0]; - - int drag = code & 0x20; - - code &= ~0x3c; - - switch(code) { - case 0: - case 1: - case 2: - *event = drag ? TERMKEY_MOUSE_DRAG : TERMKEY_MOUSE_PRESS; - btn = code + 1; - break; - - case 3: - *event = TERMKEY_MOUSE_RELEASE; - // no button hint - break; - - case 64: - case 65: - case 66: - case 67: - *event = drag ? TERMKEY_MOUSE_DRAG : TERMKEY_MOUSE_PRESS; - btn = code + 4 - 64; - break; - - default: - *event = TERMKEY_MOUSE_UNKNOWN; - } - - if(button) - *button = btn; - - if(key->code.mouse[3] & 0x80) - *event = TERMKEY_MOUSE_RELEASE; - - return TERMKEY_RES_KEY; -} - -/* - * Handler for CSI ? R position reports - * A plain CSI R with no arguments is probably actually <F3> - */ - -static TermKeyResult handle_csi_R(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args) -{ - switch(cmd) { - case 'R'|'?'<<8: - if(args < 2) - return TERMKEY_RES_NONE; - - key->type = TERMKEY_TYPE_POSITION; - termkey_key_set_linecol(key, arg[1], arg[0]); - return TERMKEY_RES_KEY; - - default: - return handle_csi_ss3_full(tk, key, cmd, arg, args); - } -} - -TermKeyResult termkey_interpret_position(TermKey *tk, const TermKeyKey *key, int *line, int *col) -{ - if(key->type != TERMKEY_TYPE_POSITION) - return TERMKEY_RES_NONE; - - termkey_key_get_linecol(key, line, col); - - return TERMKEY_RES_KEY; -} - -/* - * Handler for CSI $y mode status reports - */ - -static TermKeyResult handle_csi_y(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args) -{ - switch(cmd) { - case 'y'|'$'<<16: - case 'y'|'$'<<16 | '?'<<8: - if(args < 2) - return TERMKEY_RES_NONE; - - key->type = TERMKEY_TYPE_MODEREPORT; - key->code.mouse[0] = (cmd >> 8); - key->code.mouse[1] = arg[0] >> 8; - key->code.mouse[2] = arg[0] & 0xff; - key->code.mouse[3] = arg[1]; - return TERMKEY_RES_KEY; - - default: - return TERMKEY_RES_NONE; - } -} - -TermKeyResult termkey_interpret_modereport(TermKey *tk, const TermKeyKey *key, int *initial, int *mode, int *value) -{ - if(key->type != TERMKEY_TYPE_MODEREPORT) - return TERMKEY_RES_NONE; - - if(initial) - *initial = key->code.mouse[0]; - - if(mode) - *mode = ((uint8_t)key->code.mouse[1] << 8) | (uint8_t)key->code.mouse[2]; - - if(value) - *value = key->code.mouse[3]; - - return TERMKEY_RES_KEY; -} - -#define CHARAT(i) (tk->buffer[tk->buffstart + (i)]) - -static TermKeyResult parse_csi(TermKey *tk, size_t introlen, size_t *csi_len, long args[], size_t *nargs, unsigned long *commandp) -{ - size_t csi_end = introlen; - - while(csi_end < tk->buffcount) { - if(CHARAT(csi_end) >= 0x40 && CHARAT(csi_end) < 0x80) - break; - csi_end++; - } - - if(csi_end >= tk->buffcount) - return TERMKEY_RES_AGAIN; - - unsigned char cmd = CHARAT(csi_end); - *commandp = cmd; - - char present = 0; - int argi = 0; - - size_t p = introlen; - - // See if there is an initial byte - if(CHARAT(p) >= '<' && CHARAT(p) <= '?') { - *commandp |= (CHARAT(p) << 8); - p++; - } - - // Now attempt to parse out up number;number;... separated values - while(p < csi_end) { - unsigned char c = CHARAT(p); - - if(c >= '0' && c <= '9') { - if(!present) { - args[argi] = c - '0'; - present = 1; - } - else { - args[argi] = (args[argi] * 10) + c - '0'; - } - } - else if(c == ';') { - if(!present) - args[argi] = -1; - present = 0; - argi++; - - if(argi > 16) - break; - } - else if(c >= 0x20 && c <= 0x2f) { - *commandp |= c << 16; - break; - } - - p++; - } - - if(present) - argi++; - - *nargs = argi; - *csi_len = csi_end + 1; - - return TERMKEY_RES_KEY; -} - -TermKeyResult termkey_interpret_csi(TermKey *tk, const TermKeyKey *key, long args[], size_t *nargs, unsigned long *cmd) -{ - size_t dummy; - - if(tk->hightide == 0) - return TERMKEY_RES_NONE; - if(key->type != TERMKEY_TYPE_UNKNOWN_CSI) - return TERMKEY_RES_NONE; - - return parse_csi(tk, 0, &dummy, args, nargs, cmd); -} - -static int register_keys(void) -{ - int i; - - for(i = 0; i < 64; i++) { - csi_ss3s[i].sym = TERMKEY_SYM_UNKNOWN; - ss3s[i].sym = TERMKEY_SYM_UNKNOWN; - ss3_kpalts[i] = 0; - } - - for(i = 0; i < NCSIFUNCS; i++) - csifuncs[i].sym = TERMKEY_SYM_UNKNOWN; - - register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UP, 'A'); - register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_DOWN, 'B'); - register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_RIGHT, 'C'); - register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_LEFT, 'D'); - register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BEGIN, 'E'); - register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_END, 'F'); - register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_HOME, 'H'); - register_csi_ss3(TERMKEY_TYPE_FUNCTION, 1, 'P'); - register_csi_ss3(TERMKEY_TYPE_FUNCTION, 2, 'Q'); - register_csi_ss3(TERMKEY_TYPE_FUNCTION, 3, 'R'); - register_csi_ss3(TERMKEY_TYPE_FUNCTION, 4, 'S'); - - register_csi_ss3_full(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_TAB, TERMKEY_KEYMOD_SHIFT, TERMKEY_KEYMOD_SHIFT, 'Z'); - - register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPENTER, 'M', 0); - register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPEQUALS, 'X', '='); - register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPMULT, 'j', '*'); - register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPPLUS, 'k', '+'); - register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPCOMMA, 'l', ','); - register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPMINUS, 'm', '-'); - register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPPERIOD, 'n', '.'); - register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPDIV, 'o', '/'); - register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP0, 'p', '0'); - register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP1, 'q', '1'); - register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP2, 'r', '2'); - register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP3, 's', '3'); - register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP4, 't', '4'); - register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP5, 'u', '5'); - register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP6, 'v', '6'); - register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP7, 'w', '7'); - register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP8, 'x', '8'); - register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP9, 'y', '9'); - - register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_FIND, 1); - register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_INSERT, 2); - register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_DELETE, 3); - register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SELECT, 4); - register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEUP, 5); - register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEDOWN, 6); - register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_HOME, 7); - register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_END, 8); - - register_csifunc(TERMKEY_TYPE_FUNCTION, 1, 11); - register_csifunc(TERMKEY_TYPE_FUNCTION, 2, 12); - register_csifunc(TERMKEY_TYPE_FUNCTION, 3, 13); - register_csifunc(TERMKEY_TYPE_FUNCTION, 4, 14); - register_csifunc(TERMKEY_TYPE_FUNCTION, 5, 15); - register_csifunc(TERMKEY_TYPE_FUNCTION, 6, 17); - register_csifunc(TERMKEY_TYPE_FUNCTION, 7, 18); - register_csifunc(TERMKEY_TYPE_FUNCTION, 8, 19); - register_csifunc(TERMKEY_TYPE_FUNCTION, 9, 20); - register_csifunc(TERMKEY_TYPE_FUNCTION, 10, 21); - register_csifunc(TERMKEY_TYPE_FUNCTION, 11, 23); - register_csifunc(TERMKEY_TYPE_FUNCTION, 12, 24); - register_csifunc(TERMKEY_TYPE_FUNCTION, 13, 25); - register_csifunc(TERMKEY_TYPE_FUNCTION, 14, 26); - register_csifunc(TERMKEY_TYPE_FUNCTION, 15, 28); - register_csifunc(TERMKEY_TYPE_FUNCTION, 16, 29); - register_csifunc(TERMKEY_TYPE_FUNCTION, 17, 31); - register_csifunc(TERMKEY_TYPE_FUNCTION, 18, 32); - register_csifunc(TERMKEY_TYPE_FUNCTION, 19, 33); - register_csifunc(TERMKEY_TYPE_FUNCTION, 20, 34); - - csi_handlers['u' - 0x40] = &handle_csi_u; - - csi_handlers['M' - 0x40] = &handle_csi_m; - csi_handlers['m' - 0x40] = &handle_csi_m; - - csi_handlers['R' - 0x40] = &handle_csi_R; - - csi_handlers['y' - 0x40] = &handle_csi_y; - - keyinfo_initialised = 1; - return 1; -} - -static void *new_driver(TermKey *tk, const char *term) -{ - if(!keyinfo_initialised) - if(!register_keys()) - return NULL; - - TermKeyCsi *csi = malloc(sizeof *csi); - if(!csi) - return NULL; - - csi->tk = tk; - csi->saved_string_id = 0; - csi->saved_string = NULL; - - return csi; -} - -static void free_driver(void *info) -{ - TermKeyCsi *csi = info; - - if(csi->saved_string) - free(csi->saved_string); - - free(csi); -} - -static TermKeyResult peekkey_csi(TermKey *tk, TermKeyCsi *csi, size_t introlen, TermKeyKey *key, int force, size_t *nbytep) -{ - size_t csi_len; - size_t args = 16; - long arg[16]; - unsigned long cmd; - - TermKeyResult ret = parse_csi(tk, introlen, &csi_len, arg, &args, &cmd); - - if(ret == TERMKEY_RES_AGAIN) { - if(!force) - return TERMKEY_RES_AGAIN; - - (*tk->method.emit_codepoint)(tk, '[', key); - key->modifiers |= TERMKEY_KEYMOD_ALT; - *nbytep = introlen; - return TERMKEY_RES_KEY; - } - - if(cmd == 'M' && args < 3) { // Mouse in X10 encoding consumes the next 3 bytes also - tk->buffstart += csi_len; - tk->buffcount -= csi_len; - - TermKeyResult mouse_result = (*tk->method.peekkey_mouse)(tk, key, nbytep); - - tk->buffstart -= csi_len; - tk->buffcount += csi_len; - - if(mouse_result == TERMKEY_RES_KEY) - *nbytep += csi_len; - - return mouse_result; - } - - TermKeyResult result = TERMKEY_RES_NONE; - - // We know from the logic above that cmd must be >= 0x40 and < 0x80 - if(csi_handlers[(cmd & 0xff) - 0x40]) - result = (*csi_handlers[(cmd & 0xff) - 0x40])(tk, key, cmd, arg, args); - - if(result == TERMKEY_RES_NONE) { -#ifdef DEBUG - switch(args) { - case 0: - fprintf(stderr, "CSI: Unknown cmd=%c\n", (char)cmd); - break; - case 1: - fprintf(stderr, "CSI: Unknown arg1=%ld cmd=%c\n", arg[0], (char)cmd); - break; - case 2: - fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld cmd=%c\n", arg[0], arg[1], (char)cmd); - break; - case 3: - fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld arg3=%ld cmd=%c\n", arg[0], arg[1], arg[2], (char)cmd); - break; - default: - fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld arg3=%ld ... args=%d cmd=%c\n", arg[0], arg[1], arg[2], args, (char)cmd); - break; - } -#endif - key->type = TERMKEY_TYPE_UNKNOWN_CSI; - key->code.number = cmd; - key->modifiers = 0; - - tk->hightide = csi_len - introlen; - *nbytep = introlen; // Do not yet eat the data bytes - return TERMKEY_RES_KEY; - } - - *nbytep = csi_len; - return result; -} - -static TermKeyResult peekkey_ss3(TermKey *tk, TermKeyCsi *csi, size_t introlen, TermKeyKey *key, int force, size_t *nbytep) -{ - if(tk->buffcount < introlen + 1) { - if(!force) - return TERMKEY_RES_AGAIN; - - (*tk->method.emit_codepoint)(tk, 'O', key); - key->modifiers |= TERMKEY_KEYMOD_ALT; - *nbytep = tk->buffcount; - return TERMKEY_RES_KEY; - } - - unsigned char cmd = CHARAT(introlen); - - if(cmd < 0x40 || cmd >= 0x80) - return TERMKEY_RES_NONE; - - key->type = csi_ss3s[cmd - 0x40].type; - key->code.sym = csi_ss3s[cmd - 0x40].sym; - key->modifiers = csi_ss3s[cmd - 0x40].modifier_set; - - if(key->code.sym == TERMKEY_SYM_UNKNOWN) { - if(tk->flags & TERMKEY_FLAG_CONVERTKP && ss3_kpalts[cmd - 0x40]) { - key->type = TERMKEY_TYPE_UNICODE; - key->code.codepoint = ss3_kpalts[cmd - 0x40]; - key->modifiers = 0; - - key->utf8[0] = key->code.codepoint; - key->utf8[1] = 0; - } - else { - key->type = ss3s[cmd - 0x40].type; - key->code.sym = ss3s[cmd - 0x40].sym; - key->modifiers = ss3s[cmd - 0x40].modifier_set; - } - } - - if(key->code.sym == TERMKEY_SYM_UNKNOWN) { -#ifdef DEBUG - fprintf(stderr, "CSI: Unknown SS3 %c (0x%02x)\n", (char)cmd, cmd); -#endif - return TERMKEY_RES_NONE; - } - - *nbytep = introlen + 1; - - return TERMKEY_RES_KEY; -} - -static TermKeyResult peekkey_ctrlstring(TermKey *tk, TermKeyCsi *csi, size_t introlen, TermKeyKey *key, int force, size_t *nbytep) -{ - size_t str_end = introlen; - - while(str_end < tk->buffcount) { - if(CHARAT(str_end) == 0x07) // BEL - break; - if(CHARAT(str_end) == 0x9c) // ST - break; - if(CHARAT(str_end) == 0x1b && - (str_end + 1) < tk->buffcount && - CHARAT(str_end+1) == 0x5c) // ESC-prefixed ST - break; - - str_end++; - } - - if(str_end >= tk->buffcount) - return TERMKEY_RES_AGAIN; - -#ifdef DEBUG - fprintf(stderr, "Found a control string: %*s", - str_end - introlen, tk->buffer + tk->buffstart + introlen); -#endif - - *nbytep = str_end + 1; - if(CHARAT(str_end) == 0x1b) - (*nbytep)++; - - if(csi->saved_string) - free(csi->saved_string); - - size_t len = str_end - introlen; - - csi->saved_string_id++; - csi->saved_string = malloc(len + 1); - - strncpy(csi->saved_string, (char *)tk->buffer + tk->buffstart + introlen, len); - csi->saved_string[len] = 0; - - key->type = (CHARAT(introlen-1) & 0x1f) == 0x10 ? - TERMKEY_TYPE_DCS : TERMKEY_TYPE_OSC; - key->code.number = csi->saved_string_id; - key->modifiers = 0; - - return TERMKEY_RES_KEY; -} - -static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force, size_t *nbytep) -{ - if(tk->buffcount == 0) - return tk->is_closed ? TERMKEY_RES_EOF : TERMKEY_RES_NONE; - - TermKeyCsi *csi = info; - - switch(CHARAT(0)) { - case 0x1b: - if(tk->buffcount < 2) - return TERMKEY_RES_NONE; - - switch(CHARAT(1)) { - case 0x4f: // ESC-prefixed SS3 - return peekkey_ss3(tk, csi, 2, key, force, nbytep); - - case 0x50: // ESC-prefixed DCS - case 0x5d: // ESC-prefixed OSC - return peekkey_ctrlstring(tk, csi, 2, key, force, nbytep); - - case 0x5b: // ESC-prefixed CSI - return peekkey_csi(tk, csi, 2, key, force, nbytep); - } - - return TERMKEY_RES_NONE; - - case 0x8f: // SS3 - return peekkey_ss3(tk, csi, 1, key, force, nbytep); - - case 0x90: // DCS - case 0x9d: // OSC - return peekkey_ctrlstring(tk, csi, 1, key, force, nbytep); - - case 0x9b: // CSI - return peekkey_csi(tk, csi, 1, key, force, nbytep); - } - - return TERMKEY_RES_NONE; -} - -struct TermKeyDriver termkey_driver_csi = { - .name = "CSI", - - .new_driver = new_driver, - .free_driver = free_driver, - - .peekkey = peekkey, -}; - -TermKeyResult termkey_interpret_string(TermKey *tk, const TermKeyKey *key, const char **strp) -{ - struct TermKeyDriverNode *p; - for(p = tk->drivers; p; p = p->next) - if(p->driver == &termkey_driver_csi) - break; - - if(!p) - return TERMKEY_RES_NONE; - - if(key->type != TERMKEY_TYPE_DCS && - key->type != TERMKEY_TYPE_OSC) - return TERMKEY_RES_NONE; - - TermKeyCsi *csi = p->info; - - if(csi->saved_string_id != key->code.number) - return TERMKEY_RES_NONE; - - *strp = csi->saved_string; - - return TERMKEY_RES_KEY; -} diff --git a/src/termkey/termkey.c b/src/termkey/termkey.c deleted file mode 100644 index 832e5a9a9e..0000000000 --- a/src/termkey/termkey.c +++ /dev/null @@ -1,1606 +0,0 @@ -#include "termkey.h" -#include "termkey-internal.h" - -#include <ctype.h> -#include <errno.h> -#ifndef _WIN32 -# include <poll.h> -# include <unistd.h> -# include <strings.h> -#else -# include <io.h> -#endif -#include <string.h> - -#include <stdio.h> - -#ifdef _MSC_VER -# define strcaseeq(a,b) (_stricmp(a,b) == 0) -#else -# define strcaseeq(a,b) (strcasecmp(a,b) == 0) -#endif - -void termkey_check_version(int major, int minor) -{ - if(major != TERMKEY_VERSION_MAJOR) { - fprintf(stderr, "libtermkey major version mismatch; %d (wants) != %d (library)\n", - major, TERMKEY_VERSION_MAJOR); - exit(1); - } - - if(minor > TERMKEY_VERSION_MINOR) { - fprintf(stderr, "libtermkey minor version mismatch; %d (wants) > %d (library)\n", - minor, TERMKEY_VERSION_MINOR); - exit(1); - } - - // Happy -} - -static struct TermKeyDriver *drivers[] = { - &termkey_driver_ti, - &termkey_driver_csi, - NULL, -}; - -// Forwards for the "protected" methods -// static void eat_bytes(TermKey *tk, size_t count); -static void emit_codepoint(TermKey *tk, long codepoint, TermKeyKey *key); -static TermKeyResult peekkey_simple(TermKey *tk, TermKeyKey *key, int force, size_t *nbytes); -static TermKeyResult peekkey_mouse(TermKey *tk, TermKeyKey *key, size_t *nbytes); - -static TermKeySym register_c0(TermKey *tk, TermKeySym sym, unsigned char ctrl, const char *name); -static TermKeySym register_c0_full(TermKey *tk, TermKeySym sym, int modifier_set, int modifier_mask, unsigned char ctrl, const char *name); - -static struct { - TermKeySym sym; - const char *name; -} keynames[] = { - { TERMKEY_SYM_NONE, "NONE" }, - { TERMKEY_SYM_BACKSPACE, "Backspace" }, - { TERMKEY_SYM_TAB, "Tab" }, - { TERMKEY_SYM_ENTER, "Enter" }, - { TERMKEY_SYM_ESCAPE, "Escape" }, - { TERMKEY_SYM_SPACE, "Space" }, - { TERMKEY_SYM_DEL, "DEL" }, - { TERMKEY_SYM_UP, "Up" }, - { TERMKEY_SYM_DOWN, "Down" }, - { TERMKEY_SYM_LEFT, "Left" }, - { TERMKEY_SYM_RIGHT, "Right" }, - { TERMKEY_SYM_BEGIN, "Begin" }, - { TERMKEY_SYM_FIND, "Find" }, - { TERMKEY_SYM_INSERT, "Insert" }, - { TERMKEY_SYM_DELETE, "Delete" }, - { TERMKEY_SYM_SELECT, "Select" }, - { TERMKEY_SYM_PAGEUP, "PageUp" }, - { TERMKEY_SYM_PAGEDOWN, "PageDown" }, - { TERMKEY_SYM_HOME, "Home" }, - { TERMKEY_SYM_END, "End" }, - { TERMKEY_SYM_CANCEL, "Cancel" }, - { TERMKEY_SYM_CLEAR, "Clear" }, - { TERMKEY_SYM_CLOSE, "Close" }, - { TERMKEY_SYM_COMMAND, "Command" }, - { TERMKEY_SYM_COPY, "Copy" }, - { TERMKEY_SYM_EXIT, "Exit" }, - { TERMKEY_SYM_HELP, "Help" }, - { TERMKEY_SYM_MARK, "Mark" }, - { TERMKEY_SYM_MESSAGE, "Message" }, - { TERMKEY_SYM_MOVE, "Move" }, - { TERMKEY_SYM_OPEN, "Open" }, - { TERMKEY_SYM_OPTIONS, "Options" }, - { TERMKEY_SYM_PRINT, "Print" }, - { TERMKEY_SYM_REDO, "Redo" }, - { TERMKEY_SYM_REFERENCE, "Reference" }, - { TERMKEY_SYM_REFRESH, "Refresh" }, - { TERMKEY_SYM_REPLACE, "Replace" }, - { TERMKEY_SYM_RESTART, "Restart" }, - { TERMKEY_SYM_RESUME, "Resume" }, - { TERMKEY_SYM_SAVE, "Save" }, - { TERMKEY_SYM_SUSPEND, "Suspend" }, - { TERMKEY_SYM_UNDO, "Undo" }, - { TERMKEY_SYM_KP0, "KP0" }, - { TERMKEY_SYM_KP1, "KP1" }, - { TERMKEY_SYM_KP2, "KP2" }, - { TERMKEY_SYM_KP3, "KP3" }, - { TERMKEY_SYM_KP4, "KP4" }, - { TERMKEY_SYM_KP5, "KP5" }, - { TERMKEY_SYM_KP6, "KP6" }, - { TERMKEY_SYM_KP7, "KP7" }, - { TERMKEY_SYM_KP8, "KP8" }, - { TERMKEY_SYM_KP9, "KP9" }, - { TERMKEY_SYM_KPENTER, "KPEnter" }, - { TERMKEY_SYM_KPPLUS, "KPPlus" }, - { TERMKEY_SYM_KPMINUS, "KPMinus" }, - { TERMKEY_SYM_KPMULT, "KPMult" }, - { TERMKEY_SYM_KPDIV, "KPDiv" }, - { TERMKEY_SYM_KPCOMMA, "KPComma" }, - { TERMKEY_SYM_KPPERIOD, "KPPeriod" }, - { TERMKEY_SYM_KPEQUALS, "KPEquals" }, - { 0, NULL }, -}; - -// Mouse event names -static const char *evnames[] = { "Unknown", "Press", "Drag", "Release" }; - -#define CHARAT(i) (tk->buffer[tk->buffstart + (i)]) - -#ifdef DEBUG -/* Some internal debugging functions */ - -static void print_buffer(TermKey *tk) -{ - int i; - for(i = 0; i < tk->buffcount && i < 20; i++) - fprintf(stderr, "%02x ", CHARAT(i)); - if(tk->buffcount > 20) - fprintf(stderr, "..."); -} - -static void print_key(TermKey *tk, TermKeyKey *key) -{ - switch(key->type) { - case TERMKEY_TYPE_UNICODE: - fprintf(stderr, "Unicode codepoint=U+%04lx utf8='%s'", key->code.codepoint, key->utf8); - break; - case TERMKEY_TYPE_FUNCTION: - fprintf(stderr, "Function F%d", key->code.number); - break; - case TERMKEY_TYPE_KEYSYM: - fprintf(stderr, "Keysym sym=%d(%s)", key->code.sym, termkey_get_keyname(tk, key->code.sym)); - break; - case TERMKEY_TYPE_MOUSE: - { - TermKeyMouseEvent ev; - int button, line, col; - termkey_interpret_mouse(tk, key, &ev, &button, &line, &col); - fprintf(stderr, "Mouse ev=%d button=%d pos=(%d,%d)\n", ev, button, line, col); - } - break; - case TERMKEY_TYPE_POSITION: - { - int line, col; - termkey_interpret_position(tk, key, &line, &col); - fprintf(stderr, "Position report pos=(%d,%d)\n", line, col); - } - break; - case TERMKEY_TYPE_MODEREPORT: - { - int initial, mode, value; - termkey_interpret_modereport(tk, key, &initial, &mode, &value); - fprintf(stderr, "Mode report mode=%s %d val=%d\n", initial == '?' ? "DEC" : "ANSI", mode, value); - } - break; - case TERMKEY_TYPE_DCS: - fprintf(stderr, "Device Control String"); - break; - case TERMKEY_TYPE_OSC: - fprintf(stderr, "Operating System Control"); - break; - case TERMKEY_TYPE_UNKNOWN_CSI: - fprintf(stderr, "unknown CSI\n"); - break; - } - - int m = key->modifiers; - fprintf(stderr, " mod=%s%s%s+%02x", - (m & TERMKEY_KEYMOD_CTRL ? "C" : ""), - (m & TERMKEY_KEYMOD_ALT ? "A" : ""), - (m & TERMKEY_KEYMOD_SHIFT ? "S" : ""), - m & ~(TERMKEY_KEYMOD_CTRL|TERMKEY_KEYMOD_ALT|TERMKEY_KEYMOD_SHIFT)); -} - -static const char *res2str(TermKeyResult res) -{ - static char errorbuffer[256]; - - switch(res) { - case TERMKEY_RES_KEY: - return "TERMKEY_RES_KEY"; - case TERMKEY_RES_EOF: - return "TERMKEY_RES_EOF"; - case TERMKEY_RES_AGAIN: - return "TERMKEY_RES_AGAIN"; - case TERMKEY_RES_NONE: - return "TERMKEY_RES_NONE"; - case TERMKEY_RES_ERROR: - snprintf(errorbuffer, sizeof errorbuffer, "TERMKEY_RES_ERROR(errno=%d)\n", errno); - return (const char*)errorbuffer; - } - - return "unknown"; -} -#endif - -/* Similar to snprintf(str, size, "%s", src) except it turns CamelCase into - * space separated values - */ -static int snprint_cameltospaces(char *str, size_t size, const char *src) -{ - int prev_lower = 0; - size_t l = 0; - while(*src && l < size - 1) { - if(isupper(*src) && prev_lower) { - if(str) - str[l++] = ' '; - if(l >= size - 1) - break; - } - prev_lower = islower(*src); - str[l++] = tolower(*src++); - } - str[l] = 0; - /* For consistency with snprintf, return the number of bytes that would have - * been written, excluding '\0' */ - while(*src) { - if(isupper(*src) && prev_lower) { - l++; - } - prev_lower = islower(*src); - src++; l++; - } - return l; -} - -/* Similar to strcmp(str, strcamel, n) except that: - * it compares CamelCase in strcamel with space separated values in str; - * it takes char**s and updates them - * n counts bytes of strcamel, not str - */ -static int strpncmp_camel(const char **strp, const char **strcamelp, size_t n) -{ - const char *str = *strp, *strcamel = *strcamelp; - int prev_lower = 0; - - for( ; (*str || *strcamel) && n; n--) { - char b = tolower(*strcamel); - if(isupper(*strcamel) && prev_lower) { - if(*str != ' ') - break; - str++; - if(*str != b) - break; - } - else - if(*str != b) - break; - - prev_lower = islower(*strcamel); - - str++; - strcamel++; - } - - *strp = str; - *strcamelp = strcamel; - return *str - *strcamel; -} - -static TermKey *termkey_alloc(void) -{ - TermKey *tk = malloc(sizeof(TermKey)); - if(!tk) - return NULL; - - /* Default all the object fields but don't allocate anything */ - - tk->fd = -1; - tk->flags = 0; - tk->canonflags = 0; - - tk->buffer = NULL; - tk->buffstart = 0; - tk->buffcount = 0; - tk->buffsize = 256; /* bytes */ - tk->hightide = 0; - -#ifdef HAVE_TERMIOS - tk->restore_termios_valid = 0; -#endif - - tk->ti_getstr_hook = NULL; - tk->ti_getstr_hook_data = NULL; - - tk->waittime = 50; /* msec */ - - tk->is_closed = 0; - tk->is_started = 0; - - tk->nkeynames = 64; - tk->keynames = NULL; - - for(int i = 0; i < 32; i++) - tk->c0[i].sym = TERMKEY_SYM_NONE; - - tk->drivers = NULL; - - tk->method.emit_codepoint = &emit_codepoint; - tk->method.peekkey_simple = &peekkey_simple; - tk->method.peekkey_mouse = &peekkey_mouse; - - return tk; -} - -static int termkey_init(TermKey *tk, const char *term) -{ - tk->buffer = malloc(tk->buffsize); - if(!tk->buffer) - return 0; - - tk->keynames = malloc(sizeof(tk->keynames[0]) * tk->nkeynames); - if(!tk->keynames) - goto abort_free_buffer; - - int i; - for(i = 0; i < tk->nkeynames; i++) - tk->keynames[i] = NULL; - - for(i = 0; keynames[i].name; i++) - if(termkey_register_keyname(tk, keynames[i].sym, keynames[i].name) == -1) - goto abort_free_keynames; - - register_c0(tk, TERMKEY_SYM_TAB, 0x09, NULL); - register_c0(tk, TERMKEY_SYM_ENTER, 0x0d, NULL); - register_c0(tk, TERMKEY_SYM_ESCAPE, 0x1b, NULL); - - struct TermKeyDriverNode *tail = NULL; - - for(i = 0; drivers[i]; i++) { - void *info = (*drivers[i]->new_driver)(tk, term); - if(!info) - continue; - -#ifdef DEBUG - fprintf(stderr, "Loading the %s driver...\n", drivers[i]->name); -#endif - - struct TermKeyDriverNode *thisdrv = malloc(sizeof(*thisdrv)); - if(!thisdrv) - goto abort_free_drivers; - - thisdrv->driver = drivers[i]; - thisdrv->info = info; - thisdrv->next = NULL; - - if(!tail) - tk->drivers = thisdrv; - else - tail->next = thisdrv; - - tail = thisdrv; - -#ifdef DEBUG - fprintf(stderr, "Loaded %s driver\n", drivers[i]->name); -#endif - } - - if(!tk->drivers) { - errno = ENOENT; - goto abort_free_keynames; - } - - return 1; - -abort_free_drivers: - for(struct TermKeyDriverNode *p = tk->drivers; p; ) { - (*p->driver->free_driver)(p->info); - struct TermKeyDriverNode *next = p->next; - free(p); - p = next; - } - -abort_free_keynames: - free(tk->keynames); - -abort_free_buffer: - free(tk->buffer); - - return 0; -} - -TermKey *termkey_new(int fd, int flags) -{ - TermKey *tk = termkey_alloc(); - if(!tk) - return NULL; - - tk->fd = fd; - - if(!(flags & (TERMKEY_FLAG_RAW|TERMKEY_FLAG_UTF8))) { - char *e; - - /* Most OSes will set .UTF-8. Some will set .utf8. Try to be fairly - * generous in parsing these - */ - if(((e = getenv("LANG")) || (e = getenv("LC_MESSAGES")) || (e = getenv("LC_ALL"))) && - (e = strchr(e, '.')) && e++ && - (strcaseeq(e, "UTF-8") || strcaseeq(e, "UTF8"))) - flags |= TERMKEY_FLAG_UTF8; - else - flags |= TERMKEY_FLAG_RAW; - } - - termkey_set_flags(tk, flags); - - const char *term = getenv("TERM"); - - if(!termkey_init(tk, term)) - goto abort; - - if(!(flags & TERMKEY_FLAG_NOSTART) && !termkey_start(tk)) - goto abort; - - return tk; - -abort: - free(tk); - return NULL; -} - -TermKey *termkey_new_abstract(const char *term, int flags) -{ - TermKey *tk = termkey_alloc(); - if(!tk) - return NULL; - - tk->fd = -1; - - termkey_set_flags(tk, flags); - - if(!termkey_init(tk, term)) { - free(tk); - return NULL; - } - - if(!(flags & TERMKEY_FLAG_NOSTART) && !termkey_start(tk)) - goto abort; - - return tk; - -abort: - free(tk); - return NULL; -} - -void termkey_free(TermKey *tk) -{ - free(tk->buffer); tk->buffer = NULL; - free(tk->keynames); tk->keynames = NULL; - - struct TermKeyDriverNode *p; - for(p = tk->drivers; p; ) { - (*p->driver->free_driver)(p->info); - struct TermKeyDriverNode *next = p->next; - free(p); - p = next; - } - - free(tk); -} - -void termkey_destroy(TermKey *tk) -{ - if(tk->is_started) - termkey_stop(tk); - - termkey_free(tk); -} - -void termkey_hook_terminfo_getstr(TermKey *tk, TermKey_Terminfo_Getstr_Hook *hookfn, void *data) -{ - tk->ti_getstr_hook = hookfn; - tk->ti_getstr_hook_data = data; -} - -int termkey_start(TermKey *tk) -{ - if(tk->is_started) - return 1; - -#ifdef HAVE_TERMIOS - if(tk->fd != -1 && !(tk->flags & TERMKEY_FLAG_NOTERMIOS)) { - struct termios termios; - if(tcgetattr(tk->fd, &termios) == 0) { - tk->restore_termios = termios; - tk->restore_termios_valid = 1; - - termios.c_iflag &= ~(IXON|INLCR|ICRNL); - termios.c_lflag &= ~(ICANON|ECHO -#ifdef IEXTEN - | IEXTEN -#endif - ); - termios.c_cc[VMIN] = 1; - termios.c_cc[VTIME] = 0; - - if(tk->flags & TERMKEY_FLAG_CTRLC) - /* want no signal keys at all, so just disable ISIG */ - termios.c_lflag &= ~ISIG; - else { - /* Disable Ctrl-\==VQUIT and Ctrl-D==VSUSP but leave Ctrl-C as SIGINT */ - termios.c_cc[VQUIT] = _POSIX_VDISABLE; - termios.c_cc[VSUSP] = _POSIX_VDISABLE; - /* Some OSes have Ctrl-Y==VDSUSP */ -#ifdef VDSUSP - termios.c_cc[VDSUSP] = _POSIX_VDISABLE; -#endif - } - -#ifdef DEBUG - fprintf(stderr, "Setting termios(3) flags\n"); -#endif - tcsetattr(tk->fd, TCSANOW, &termios); - } - } -#endif - - struct TermKeyDriverNode *p; - for(p = tk->drivers; p; p = p->next) - if(p->driver->start_driver) - if(!(*p->driver->start_driver)(tk, p->info)) - return 0; - -#ifdef DEBUG - fprintf(stderr, "Drivers started; termkey instance %p is ready\n", tk); -#endif - - tk->is_started = 1; - return 1; -} - -int termkey_stop(TermKey *tk) -{ - if(!tk->is_started) - return 1; - - struct TermKeyDriverNode *p; - for(p = tk->drivers; p; p = p->next) - if(p->driver->stop_driver) - (*p->driver->stop_driver)(tk, p->info); - -#ifdef HAVE_TERMIOS - if(tk->restore_termios_valid) - tcsetattr(tk->fd, TCSANOW, &tk->restore_termios); -#endif - - tk->is_started = 0; - - return 1; -} - -int termkey_is_started(TermKey *tk) -{ - return tk->is_started; -} - -int termkey_get_fd(TermKey *tk) -{ - return tk->fd; -} - -int termkey_get_flags(TermKey *tk) -{ - return tk->flags; -} - -void termkey_set_flags(TermKey *tk, int newflags) -{ - tk->flags = newflags; - - if(tk->flags & TERMKEY_FLAG_SPACESYMBOL) - tk->canonflags |= TERMKEY_CANON_SPACESYMBOL; - else - tk->canonflags &= ~TERMKEY_CANON_SPACESYMBOL; -} - -void termkey_set_waittime(TermKey *tk, int msec) -{ - tk->waittime = msec; -} - -int termkey_get_waittime(TermKey *tk) -{ - return tk->waittime; -} - -int termkey_get_canonflags(TermKey *tk) -{ - return tk->canonflags; -} - -void termkey_set_canonflags(TermKey *tk, int flags) -{ - tk->canonflags = flags; - - if(tk->canonflags & TERMKEY_CANON_SPACESYMBOL) - tk->flags |= TERMKEY_FLAG_SPACESYMBOL; - else - tk->flags &= ~TERMKEY_FLAG_SPACESYMBOL; -} - -size_t termkey_get_buffer_size(TermKey *tk) -{ - return tk->buffsize; -} - -int termkey_set_buffer_size(TermKey *tk, size_t size) -{ - unsigned char *buffer = realloc(tk->buffer, size); - if(!buffer) - return 0; - - tk->buffer = buffer; - tk->buffsize = size; - - return 1; -} - -size_t termkey_get_buffer_remaining(TermKey *tk) -{ - /* Return the total number of free bytes in the buffer, because that's what - * is available to the user. */ - return tk->buffsize - tk->buffcount; -} - -static void eat_bytes(TermKey *tk, size_t count) -{ - if(count >= tk->buffcount) { - tk->buffstart = 0; - tk->buffcount = 0; - return; - } - - tk->buffstart += count; - tk->buffcount -= count; -} - -static inline unsigned int utf8_seqlen(long codepoint) -{ - if(codepoint < 0x0000080) return 1; - if(codepoint < 0x0000800) return 2; - if(codepoint < 0x0010000) return 3; - if(codepoint < 0x0200000) return 4; - if(codepoint < 0x4000000) return 5; - return 6; -} - -static void fill_utf8(TermKeyKey *key) -{ - long codepoint = key->code.codepoint; - int nbytes = utf8_seqlen(codepoint); - - key->utf8[nbytes] = 0; - - // This is easier done backwards - int b = nbytes; - while(b > 1) { - b--; - key->utf8[b] = 0x80 | (codepoint & 0x3f); - codepoint >>= 6; - } - - switch(nbytes) { - case 1: key->utf8[0] = (codepoint & 0x7f); break; - case 2: key->utf8[0] = 0xc0 | (codepoint & 0x1f); break; - case 3: key->utf8[0] = 0xe0 | (codepoint & 0x0f); break; - case 4: key->utf8[0] = 0xf0 | (codepoint & 0x07); break; - case 5: key->utf8[0] = 0xf8 | (codepoint & 0x03); break; - case 6: key->utf8[0] = 0xfc | (codepoint & 0x01); break; - } -} - -#define UTF8_INVALID 0xFFFD -static TermKeyResult parse_utf8(const unsigned char *bytes, size_t len, long *cp, size_t *nbytep) -{ - unsigned int nbytes; - - unsigned char b0 = bytes[0]; - - if(b0 < 0x80) { - // Single byte ASCII - *cp = b0; - *nbytep = 1; - return TERMKEY_RES_KEY; - } - else if(b0 < 0xc0) { - // Starts with a continuation byte - that's not right - *cp = UTF8_INVALID; - *nbytep = 1; - return TERMKEY_RES_KEY; - } - else if(b0 < 0xe0) { - nbytes = 2; - *cp = b0 & 0x1f; - } - else if(b0 < 0xf0) { - nbytes = 3; - *cp = b0 & 0x0f; - } - else if(b0 < 0xf8) { - nbytes = 4; - *cp = b0 & 0x07; - } - else if(b0 < 0xfc) { - nbytes = 5; - *cp = b0 & 0x03; - } - else if(b0 < 0xfe) { - nbytes = 6; - *cp = b0 & 0x01; - } - else { - *cp = UTF8_INVALID; - *nbytep = 1; - return TERMKEY_RES_KEY; - } - - for(unsigned int b = 1; b < nbytes; b++) { - unsigned char cb; - - if(b >= len) - return TERMKEY_RES_AGAIN; - - cb = bytes[b]; - if(cb < 0x80 || cb >= 0xc0) { - *cp = UTF8_INVALID; - *nbytep = b; - return TERMKEY_RES_KEY; - } - - *cp <<= 6; - *cp |= cb & 0x3f; - } - - // Check for overlong sequences - if(nbytes > utf8_seqlen(*cp)) - *cp = UTF8_INVALID; - - // Check for UTF-16 surrogates or invalid *cps - if((*cp >= 0xD800 && *cp <= 0xDFFF) || - *cp == 0xFFFE || - *cp == 0xFFFF) - *cp = UTF8_INVALID; - - *nbytep = nbytes; - return TERMKEY_RES_KEY; -} - -static void emit_codepoint(TermKey *tk, long codepoint, TermKeyKey *key) -{ - if(codepoint == 0) { - // ASCII NUL = Ctrl-Space - key->type = TERMKEY_TYPE_KEYSYM; - key->code.sym = TERMKEY_SYM_SPACE; - key->modifiers = TERMKEY_KEYMOD_CTRL; - } - else if(codepoint < 0x20) { - // C0 range - key->code.codepoint = 0; - key->modifiers = 0; - - if(!(tk->flags & TERMKEY_FLAG_NOINTERPRET) && tk->c0[codepoint].sym != TERMKEY_SYM_UNKNOWN) { - key->code.sym = tk->c0[codepoint].sym; - key->modifiers |= tk->c0[codepoint].modifier_set; - } - - if(!key->code.sym) { - key->type = TERMKEY_TYPE_UNICODE; - /* Generically modified Unicode ought not report the SHIFT state, or else - * we get into complications trying to report Shift-; vs : and so on... - * In order to be able to represent Ctrl-Shift-A as CTRL modified - * unicode A, we need to call Ctrl-A simply 'a', lowercase - */ - if(codepoint+0x40 >= 'A' && codepoint+0x40 <= 'Z') - // it's a letter - use lowercase instead - key->code.codepoint = codepoint + 0x60; - else - key->code.codepoint = codepoint + 0x40; - key->modifiers = TERMKEY_KEYMOD_CTRL; - } - else { - key->type = TERMKEY_TYPE_KEYSYM; - } - } - else if(codepoint == 0x7f && !(tk->flags & TERMKEY_FLAG_NOINTERPRET)) { - // ASCII DEL - key->type = TERMKEY_TYPE_KEYSYM; - key->code.sym = TERMKEY_SYM_DEL; - key->modifiers = 0; - } - else if(codepoint >= 0x20 && codepoint < 0x80) { - // ASCII lowbyte range - key->type = TERMKEY_TYPE_UNICODE; - key->code.codepoint = codepoint; - key->modifiers = 0; - } - else if(codepoint >= 0x80 && codepoint < 0xa0) { - // UTF-8 never starts with a C1 byte. So we can be sure of these - key->type = TERMKEY_TYPE_UNICODE; - key->code.codepoint = codepoint - 0x40; - key->modifiers = TERMKEY_KEYMOD_CTRL|TERMKEY_KEYMOD_ALT; - } - else { - // UTF-8 codepoint - key->type = TERMKEY_TYPE_UNICODE; - key->code.codepoint = codepoint; - key->modifiers = 0; - } - - termkey_canonicalise(tk, key); - - if(key->type == TERMKEY_TYPE_UNICODE) - fill_utf8(key); -} - -void termkey_canonicalise(TermKey *tk, TermKeyKey *key) -{ - int flags = tk->canonflags; - - if(flags & TERMKEY_CANON_SPACESYMBOL) { - if(key->type == TERMKEY_TYPE_UNICODE && key->code.codepoint == 0x20) { - key->type = TERMKEY_TYPE_KEYSYM; - key->code.sym = TERMKEY_SYM_SPACE; - } - } - else { - if(key->type == TERMKEY_TYPE_KEYSYM && key->code.sym == TERMKEY_SYM_SPACE) { - key->type = TERMKEY_TYPE_UNICODE; - key->code.codepoint = 0x20; - fill_utf8(key); - } - } - - if(flags & TERMKEY_CANON_DELBS) { - if(key->type == TERMKEY_TYPE_KEYSYM && key->code.sym == TERMKEY_SYM_DEL) { - key->code.sym = TERMKEY_SYM_BACKSPACE; - } - } -} - -static TermKeyResult peekkey(TermKey *tk, TermKeyKey *key, int force, size_t *nbytep) -{ - int again = 0; - - if(!tk->is_started) { - errno = EINVAL; - return TERMKEY_RES_ERROR; - } - -#ifdef DEBUG - fprintf(stderr, "getkey(force=%d): buffer ", force); - print_buffer(tk); - fprintf(stderr, "\n"); -#endif - - if(tk->hightide) { - tk->buffstart += tk->hightide; - tk->buffcount -= tk->hightide; - tk->hightide = 0; - } - - TermKeyResult ret; - struct TermKeyDriverNode *p; - for(p = tk->drivers; p; p = p->next) { - ret = (p->driver->peekkey)(tk, p->info, key, force, nbytep); - -#ifdef DEBUG - fprintf(stderr, "Driver %s yields %s\n", p->driver->name, res2str(ret)); -#endif - - switch(ret) { - case TERMKEY_RES_KEY: -#ifdef DEBUG - print_key(tk, key); fprintf(stderr, "\n"); -#endif - // Slide the data down to stop it running away - { - size_t halfsize = tk->buffsize / 2; - - if(tk->buffstart > halfsize) { - memcpy(tk->buffer, tk->buffer + halfsize, halfsize); - tk->buffstart -= halfsize; - } - } - - /* fallthrough */ - case TERMKEY_RES_EOF: - case TERMKEY_RES_ERROR: - return ret; - - case TERMKEY_RES_AGAIN: - if(!force) - again = 1; - - /* fallthrough */ - case TERMKEY_RES_NONE: - break; - } - } - - if(again) - return TERMKEY_RES_AGAIN; - - ret = peekkey_simple(tk, key, force, nbytep); - -#ifdef DEBUG - fprintf(stderr, "getkey_simple(force=%d) yields %s\n", force, res2str(ret)); - if(ret == TERMKEY_RES_KEY) { - print_key(tk, key); fprintf(stderr, "\n"); - } -#endif - - return ret; -} - -static TermKeyResult peekkey_simple(TermKey *tk, TermKeyKey *key, int force, size_t *nbytep) -{ - if(tk->buffcount == 0) - return tk->is_closed ? TERMKEY_RES_EOF : TERMKEY_RES_NONE; - - unsigned char b0 = CHARAT(0); - - if(b0 == 0x1b) { - // Escape-prefixed value? Might therefore be Alt+key - if(tk->buffcount == 1) { - // This might be an <Esc> press, or it may want to be part of a longer - // sequence - if(!force) - return TERMKEY_RES_AGAIN; - - (*tk->method.emit_codepoint)(tk, b0, key); - *nbytep = 1; - return TERMKEY_RES_KEY; - } - - // Try another key there - tk->buffstart++; - tk->buffcount--; - - // Run the full driver - TermKeyResult metakey_result = peekkey(tk, key, force, nbytep); - - tk->buffstart--; - tk->buffcount++; - - switch(metakey_result) { - case TERMKEY_RES_KEY: - key->modifiers |= TERMKEY_KEYMOD_ALT; - (*nbytep)++; - break; - - case TERMKEY_RES_NONE: - case TERMKEY_RES_EOF: - case TERMKEY_RES_AGAIN: - case TERMKEY_RES_ERROR: - break; - } - - return metakey_result; - } - else if(b0 < 0xa0) { - // Single byte C0, G0 or C1 - C1 is never UTF-8 initial byte - (*tk->method.emit_codepoint)(tk, b0, key); - *nbytep = 1; - return TERMKEY_RES_KEY; - } - else if(tk->flags & TERMKEY_FLAG_UTF8) { - // Some UTF-8 - long codepoint; - TermKeyResult res = parse_utf8(tk->buffer + tk->buffstart, tk->buffcount, &codepoint, nbytep); - - if(res == TERMKEY_RES_AGAIN && force) { - /* There weren't enough bytes for a complete UTF-8 sequence but caller - * demands an answer. About the best thing we can do here is eat as many - * bytes as we have, and emit a UTF8_INVALID. If the remaining bytes - * arrive later, they'll be invalid too. - */ - codepoint = UTF8_INVALID; - *nbytep = tk->buffcount; - res = TERMKEY_RES_KEY; - } - - key->type = TERMKEY_TYPE_UNICODE; - key->modifiers = 0; - (*tk->method.emit_codepoint)(tk, codepoint, key); - return res; - } - else { - // Non UTF-8 case - just report the raw byte - key->type = TERMKEY_TYPE_UNICODE; - key->code.codepoint = b0; - key->modifiers = 0; - - key->utf8[0] = key->code.codepoint; - key->utf8[1] = 0; - - *nbytep = 1; - - return TERMKEY_RES_KEY; - } -} - -static TermKeyResult peekkey_mouse(TermKey *tk, TermKeyKey *key, size_t *nbytep) -{ - if(tk->buffcount < 3) - return TERMKEY_RES_AGAIN; - - key->type = TERMKEY_TYPE_MOUSE; - key->code.mouse[0] = CHARAT(0) - 0x20; - key->code.mouse[1] = CHARAT(1) - 0x20; - key->code.mouse[2] = CHARAT(2) - 0x20; - key->code.mouse[3] = 0; - - key->modifiers = (key->code.mouse[0] & 0x1c) >> 2; - key->code.mouse[0] &= ~0x1c; - - *nbytep = 3; - return TERMKEY_RES_KEY; -} - -TermKeyResult termkey_getkey(TermKey *tk, TermKeyKey *key) -{ - size_t nbytes = 0; - TermKeyResult ret = peekkey(tk, key, 0, &nbytes); - - if(ret == TERMKEY_RES_KEY) - eat_bytes(tk, nbytes); - - if(ret == TERMKEY_RES_AGAIN) - /* Call peekkey() again in force mode to obtain whatever it can */ - (void)peekkey(tk, key, 1, &nbytes); - /* Don't eat it yet though */ - - return ret; -} - -TermKeyResult termkey_getkey_force(TermKey *tk, TermKeyKey *key) -{ - size_t nbytes = 0; - TermKeyResult ret = peekkey(tk, key, 1, &nbytes); - - if(ret == TERMKEY_RES_KEY) - eat_bytes(tk, nbytes); - - return ret; -} - -#ifndef _WIN32 -TermKeyResult termkey_waitkey(TermKey *tk, TermKeyKey *key) -{ - if(tk->fd == -1) { - errno = EBADF; - return TERMKEY_RES_ERROR; - } - - while(1) { - TermKeyResult ret = termkey_getkey(tk, key); - - switch(ret) { - case TERMKEY_RES_KEY: - case TERMKEY_RES_EOF: - case TERMKEY_RES_ERROR: - return ret; - - case TERMKEY_RES_NONE: - ret = termkey_advisereadable(tk); - if(ret == TERMKEY_RES_ERROR) - return ret; - break; - - case TERMKEY_RES_AGAIN: - { - if(tk->is_closed) - // We're closed now. Never going to get more bytes so just go with - // what we have - return termkey_getkey_force(tk, key); - - struct pollfd fd; - -retry: - fd.fd = tk->fd; - fd.events = POLLIN; - - int pollret = poll(&fd, 1, tk->waittime); - if(pollret == -1) { - if(errno == EINTR && !(tk->flags & TERMKEY_FLAG_EINTR)) - goto retry; - - return TERMKEY_RES_ERROR; - } - - if(fd.revents & (POLLIN|POLLHUP|POLLERR)) - ret = termkey_advisereadable(tk); - else - ret = TERMKEY_RES_NONE; - - if(ret == TERMKEY_RES_ERROR) - return ret; - if(ret == TERMKEY_RES_NONE) - return termkey_getkey_force(tk, key); - } - break; - } - } - - /* UNREACHABLE */ -} -#endif - -TermKeyResult termkey_advisereadable(TermKey *tk) -{ - ssize_t len; - - if(tk->fd == -1) { - errno = EBADF; - return TERMKEY_RES_ERROR; - } - - if(tk->buffstart) { - memmove(tk->buffer, tk->buffer + tk->buffstart, tk->buffcount); - tk->buffstart = 0; - } - - /* Not expecting it ever to be greater but doesn't hurt to handle that */ - if(tk->buffcount >= tk->buffsize) { - errno = ENOMEM; - return TERMKEY_RES_ERROR; - } - -retry: - len = read(tk->fd, tk->buffer + tk->buffcount, tk->buffsize - tk->buffcount); - - if(len == -1) { - if(errno == EAGAIN) - return TERMKEY_RES_NONE; - else if(errno == EINTR && !(tk->flags & TERMKEY_FLAG_EINTR)) - goto retry; - else - return TERMKEY_RES_ERROR; - } - else if(len < 1) { - tk->is_closed = 1; - return TERMKEY_RES_NONE; - } - else { - tk->buffcount += len; - return TERMKEY_RES_AGAIN; - } -} - -size_t termkey_push_bytes(TermKey *tk, const char *bytes, size_t len) -{ - if(tk->buffstart) { - memmove(tk->buffer, tk->buffer + tk->buffstart, tk->buffcount); - tk->buffstart = 0; - } - - /* Not expecting it ever to be greater but doesn't hurt to handle that */ - if(tk->buffcount >= tk->buffsize) { - errno = ENOMEM; - return (size_t)-1; - } - - if(len > tk->buffsize - tk->buffcount) - len = tk->buffsize - tk->buffcount; - - // memcpy(), not strncpy() in case of null bytes in input - memcpy(tk->buffer + tk->buffcount, bytes, len); - tk->buffcount += len; - - return len; -} - -TermKeySym termkey_register_keyname(TermKey *tk, TermKeySym sym, const char *name) -{ - if(!sym) - sym = tk->nkeynames; - - if(sym >= tk->nkeynames) { - const char **new_keynames = realloc(tk->keynames, sizeof(new_keynames[0]) * (sym + 1)); - if(!new_keynames) - return -1; - - tk->keynames = new_keynames; - - // Fill in the hole - for(int i = tk->nkeynames; i < sym; i++) - tk->keynames[i] = NULL; - - tk->nkeynames = sym + 1; - } - - tk->keynames[sym] = name; - - return sym; -} - -const char *termkey_get_keyname(TermKey *tk, TermKeySym sym) -{ - if(sym == TERMKEY_SYM_UNKNOWN) - return "UNKNOWN"; - - if(sym < tk->nkeynames) - return tk->keynames[sym]; - - return "UNKNOWN"; -} - -static const char *termkey_lookup_keyname_format(TermKey *tk, const char *str, TermKeySym *sym, TermKeyFormat format) -{ - /* We store an array, so we can't do better than a linear search. Doesn't - * matter because user won't be calling this too often */ - - for(*sym = 0; *sym < tk->nkeynames; (*sym)++) { - const char *thiskey = tk->keynames[*sym]; - if(!thiskey) - continue; - size_t len = strlen(thiskey); - if(format & TERMKEY_FORMAT_LOWERSPACE) { - const char *thisstr = str; - if(strpncmp_camel(&thisstr, &thiskey, len) == 0) - return thisstr; - } - else { - if(strncmp(str, thiskey, len) == 0) - return (char *)str + len; - } - } - - return NULL; -} - -const char *termkey_lookup_keyname(TermKey *tk, const char *str, TermKeySym *sym) -{ - return termkey_lookup_keyname_format(tk, str, sym, 0); -} - -TermKeySym termkey_keyname2sym(TermKey *tk, const char *keyname) -{ - TermKeySym sym; - const char *endp = termkey_lookup_keyname(tk, keyname, &sym); - if(!endp || endp[0]) - return TERMKEY_SYM_UNKNOWN; - return sym; -} - -static TermKeySym register_c0(TermKey *tk, TermKeySym sym, unsigned char ctrl, const char *name) -{ - return register_c0_full(tk, sym, 0, 0, ctrl, name); -} - -static TermKeySym register_c0_full(TermKey *tk, TermKeySym sym, int modifier_set, int modifier_mask, unsigned char ctrl, const char *name) -{ - if(ctrl >= 0x20) { - errno = EINVAL; - return -1; - } - - if(name) - sym = termkey_register_keyname(tk, sym, name); - - tk->c0[ctrl].sym = sym; - tk->c0[ctrl].modifier_set = modifier_set; - tk->c0[ctrl].modifier_mask = modifier_mask; - - return sym; -} - -/* Previous name for this function - * No longer declared in termkey.h but it remains in the compiled library for - * backward-compatibility reasons. - */ -size_t termkey_snprint_key(TermKey *tk, char *buffer, size_t len, TermKeyKey *key, TermKeyFormat format) -{ - return termkey_strfkey(tk, buffer, len, key, format); -} - -static struct modnames { - const char *shift, *alt, *ctrl; -} -modnames[] = { - { "S", "A", "C" }, // 0 - { "Shift", "Alt", "Ctrl" }, // LONGMOD - { "S", "M", "C" }, // ALTISMETA - { "Shift", "Meta", "Ctrl" }, // ALTISMETA+LONGMOD - { "s", "a", "c" }, // LOWERMOD - { "shift", "alt", "ctrl" }, // LOWERMOD+LONGMOD - { "s", "m", "c" }, // LOWERMOD+ALTISMETA - { "shift", "meta", "ctrl" }, // LOWERMOD+ALTISMETA+LONGMOD -}; - -size_t termkey_strfkey(TermKey *tk, char *buffer, size_t len, TermKeyKey *key, TermKeyFormat format) -{ - size_t pos = 0; - size_t l = 0; - - struct modnames *mods = &modnames[!!(format & TERMKEY_FORMAT_LONGMOD) + - !!(format & TERMKEY_FORMAT_ALTISMETA) * 2 + - !!(format & TERMKEY_FORMAT_LOWERMOD) * 4]; - - int wrapbracket = (format & TERMKEY_FORMAT_WRAPBRACKET) && - (key->type != TERMKEY_TYPE_UNICODE || key->modifiers != 0); - - char sep = (format & TERMKEY_FORMAT_SPACEMOD) ? ' ' : '-'; - - if(format & TERMKEY_FORMAT_CARETCTRL && - key->type == TERMKEY_TYPE_UNICODE && - key->modifiers == TERMKEY_KEYMOD_CTRL) { - long codepoint = key->code.codepoint; - - // Handle some of the special cases first - if(codepoint >= 'a' && codepoint <= 'z') { - l = snprintf(buffer + pos, len - pos, wrapbracket ? "<^%c>" : "^%c", (char)codepoint - 0x20); - if(l <= 0) return pos; - pos += l; - return pos; - } - else if((codepoint >= '@' && codepoint < 'A') || - (codepoint > 'Z' && codepoint <= '_')) { - l = snprintf(buffer + pos, len - pos, wrapbracket ? "<^%c>" : "^%c", (char)codepoint); - if(l <= 0) return pos; - pos += l; - return pos; - } - } - - if(wrapbracket) { - l = snprintf(buffer + pos, len - pos, "<"); - if(l <= 0) return pos; - pos += l; - } - - if(key->modifiers & TERMKEY_KEYMOD_ALT) { - l = snprintf(buffer + pos, len - pos, "%s%c", mods->alt, sep); - if(l <= 0) return pos; - pos += l; - } - - if(key->modifiers & TERMKEY_KEYMOD_CTRL) { - l = snprintf(buffer + pos, len - pos, "%s%c", mods->ctrl, sep); - if(l <= 0) return pos; - pos += l; - } - - if(key->modifiers & TERMKEY_KEYMOD_SHIFT) { - l = snprintf(buffer + pos, len - pos, "%s%c", mods->shift, sep); - if(l <= 0) return pos; - pos += l; - } - - switch(key->type) { - case TERMKEY_TYPE_UNICODE: - if(!key->utf8[0]) // In case of user-supplied key structures - fill_utf8(key); - l = snprintf(buffer + pos, len - pos, "%s", key->utf8); - break; - case TERMKEY_TYPE_KEYSYM: - { - const char *name = termkey_get_keyname(tk, key->code.sym); - if(format & TERMKEY_FORMAT_LOWERSPACE) - l = snprint_cameltospaces(buffer + pos, len - pos, name); - else - l = snprintf(buffer + pos, len - pos, "%s", name); - } - break; - case TERMKEY_TYPE_FUNCTION: - l = snprintf(buffer + pos, len - pos, "%c%d", - (format & TERMKEY_FORMAT_LOWERSPACE ? 'f' : 'F'), key->code.number); - break; - case TERMKEY_TYPE_MOUSE: - { - TermKeyMouseEvent ev; - int button; - int line, col; - termkey_interpret_mouse(tk, key, &ev, &button, &line, &col); - - l = snprintf(buffer + pos, len - pos, "Mouse%s(%d)", - evnames[ev], button); - - if(format & TERMKEY_FORMAT_MOUSE_POS) { - if(l <= 0) return pos; - pos += l; - - l = snprintf(buffer + pos, len - pos, " @ (%u,%u)", col, line); - } - } - break; - case TERMKEY_TYPE_POSITION: - l = snprintf(buffer + pos, len - pos, "Position"); - break; - case TERMKEY_TYPE_MODEREPORT: - { - int initial, mode, value; - termkey_interpret_modereport(tk, key, &initial, &mode, &value); - if(initial) - l = snprintf(buffer + pos, len - pos, "Mode(%c%d=%d)", initial, mode, value); - else - l = snprintf(buffer + pos, len - pos, "Mode(%d=%d)", mode, value); - } - case TERMKEY_TYPE_DCS: - l = snprintf(buffer + pos, len - pos, "DCS"); - break; - case TERMKEY_TYPE_OSC: - l = snprintf(buffer + pos, len - pos, "OSC"); - break; - case TERMKEY_TYPE_UNKNOWN_CSI: - l = snprintf(buffer + pos, len - pos, "CSI %c", key->code.number & 0xff); - break; - } - - if(l <= 0) return pos; - pos += l; - - if(wrapbracket) { - l = snprintf(buffer + pos, len - pos, ">"); - if(l <= 0) return pos; - pos += l; - } - - return pos; -} - -const char *termkey_strpkey(TermKey *tk, const char *str, TermKeyKey *key, TermKeyFormat format) -{ - struct modnames *mods = &modnames[!!(format & TERMKEY_FORMAT_LONGMOD) + - !!(format & TERMKEY_FORMAT_ALTISMETA) * 2 + - !!(format & TERMKEY_FORMAT_LOWERMOD) * 4]; - - key->modifiers = 0; - - if((format & TERMKEY_FORMAT_CARETCTRL) && str[0] == '^' && str[1]) { - str = termkey_strpkey(tk, str+1, key, format & ~TERMKEY_FORMAT_CARETCTRL); - - if(!str || - key->type != TERMKEY_TYPE_UNICODE || - key->code.codepoint < '@' || key->code.codepoint > '_' || - key->modifiers != 0) - return NULL; - - if(key->code.codepoint >= 'A' && key->code.codepoint <= 'Z') - key->code.codepoint += 0x20; - key->modifiers = TERMKEY_KEYMOD_CTRL; - fill_utf8(key); - return (char *)str; - } - - const char *sep_at; - - while((sep_at = strchr(str, (format & TERMKEY_FORMAT_SPACEMOD) ? ' ' : '-'))) { - size_t n = sep_at - str; - - if(n == strlen(mods->alt) && strncmp(mods->alt, str, n) == 0) - key->modifiers |= TERMKEY_KEYMOD_ALT; - else if(n == strlen(mods->ctrl) && strncmp(mods->ctrl, str, n) == 0) - key->modifiers |= TERMKEY_KEYMOD_CTRL; - else if(n == strlen(mods->shift) && strncmp(mods->shift, str, n) == 0) - key->modifiers |= TERMKEY_KEYMOD_SHIFT; - - else - break; - - str = sep_at + 1; - } - - size_t nbytes; - ssize_t snbytes; - const char *endstr; - int button; - char event_name[32]; - - if((endstr = termkey_lookup_keyname_format(tk, str, &key->code.sym, format))) { - key->type = TERMKEY_TYPE_KEYSYM; - str = endstr; - } - else if(sscanf(str, "F%d%zn", &key->code.number, &snbytes) == 1) { - key->type = TERMKEY_TYPE_FUNCTION; - str += snbytes; - } - else if(sscanf(str, "Mouse%31[^(](%d)%zn", event_name, &button, &snbytes) == 2) { - str += snbytes; - key->type = TERMKEY_TYPE_MOUSE; - - TermKeyMouseEvent ev = TERMKEY_MOUSE_UNKNOWN; - for(size_t i = 0; i < sizeof(evnames)/sizeof(evnames[0]); i++) { - if(strcmp(evnames[i], event_name) == 0) { - ev = TERMKEY_MOUSE_UNKNOWN + i; - break; - } - } - - int code; - switch(ev) { - case TERMKEY_MOUSE_PRESS: - case TERMKEY_MOUSE_DRAG: - code = button - 1; - if(ev == TERMKEY_MOUSE_DRAG) { - code |= 0x20; - } - break; - case TERMKEY_MOUSE_RELEASE: - code = 3; - break; - default: - code = 128; - break; - } - key->code.mouse[0] = code; - - unsigned int line = 0, col = 0; - if((format & TERMKEY_FORMAT_MOUSE_POS) && sscanf(str, " @ (%u,%u)%zn", &col, &line, &snbytes) == 2) { - str += snbytes; - } - termkey_key_set_linecol(key, col, line); - } - // Unicode must be last - else if(parse_utf8((unsigned const char *)str, strlen(str), &key->code.codepoint, &nbytes) == TERMKEY_RES_KEY) { - key->type = TERMKEY_TYPE_UNICODE; - fill_utf8(key); - str += nbytes; - } - else - return NULL; - - termkey_canonicalise(tk, key); - - return (char *)str; -} - -int termkey_keycmp(TermKey *tk, const TermKeyKey *key1p, const TermKeyKey *key2p) -{ - /* Copy the key structs since we'll be modifying them */ - TermKeyKey key1 = *key1p, key2 = *key2p; - - termkey_canonicalise(tk, &key1); - termkey_canonicalise(tk, &key2); - - if(key1.type != key2.type) - return key1.type - key2.type; - - switch(key1.type) { - case TERMKEY_TYPE_UNICODE: - if(key1.code.codepoint != key2.code.codepoint) - return key1.code.codepoint - key2.code.codepoint; - break; - case TERMKEY_TYPE_KEYSYM: - if(key1.code.sym != key2.code.sym) - return key1.code.sym - key2.code.sym; - break; - case TERMKEY_TYPE_FUNCTION: - case TERMKEY_TYPE_UNKNOWN_CSI: - if(key1.code.number != key2.code.number) - return key1.code.number - key2.code.number; - break; - case TERMKEY_TYPE_MOUSE: - { - int cmp = strncmp(key1.code.mouse, key2.code.mouse, 4); - if(cmp != 0) - return cmp; - } - break; - case TERMKEY_TYPE_POSITION: - { - int line1, col1, line2, col2; - termkey_interpret_position(tk, &key1, &line1, &col1); - termkey_interpret_position(tk, &key2, &line2, &col2); - if(line1 != line2) - return line1 - line2; - return col1 - col2; - } - break; - case TERMKEY_TYPE_DCS: - case TERMKEY_TYPE_OSC: - return key1p - key2p; - case TERMKEY_TYPE_MODEREPORT: - { - int initial1, initial2, mode1, mode2, value1, value2; - termkey_interpret_modereport(tk, &key1, &initial1, &mode1, &value1); - termkey_interpret_modereport(tk, &key2, &initial2, &mode2, &value2); - if(initial1 != initial2) - return initial1 - initial2; - if(mode1 != mode2) - return mode1 - mode2; - return value1 - value2; - } - } - - return key1.modifiers - key2.modifiers; -} diff --git a/src/termkey/termkey.h b/src/termkey/termkey.h deleted file mode 100644 index 8e10fcff0c..0000000000 --- a/src/termkey/termkey.h +++ /dev/null @@ -1,249 +0,0 @@ -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef GUARD_TERMKEY_H_ -#define GUARD_TERMKEY_H_ - -#include <stdint.h> -#include <stdlib.h> - -#define TERMKEY_VERSION_MAJOR 0 -#define TERMKEY_VERSION_MINOR 22 - -#define TERMKEY_CHECK_VERSION \ - termkey_check_version(TERMKEY_VERSION_MAJOR, TERMKEY_VERSION_MINOR) - -typedef enum { - TERMKEY_SYM_UNKNOWN = -1, - TERMKEY_SYM_NONE = 0, - - /* Special names in C0 */ - TERMKEY_SYM_BACKSPACE, - TERMKEY_SYM_TAB, - TERMKEY_SYM_ENTER, - TERMKEY_SYM_ESCAPE, - - /* Special names in G0 */ - TERMKEY_SYM_SPACE, - TERMKEY_SYM_DEL, - - /* Special keys */ - TERMKEY_SYM_UP, - TERMKEY_SYM_DOWN, - TERMKEY_SYM_LEFT, - TERMKEY_SYM_RIGHT, - TERMKEY_SYM_BEGIN, - TERMKEY_SYM_FIND, - TERMKEY_SYM_INSERT, - TERMKEY_SYM_DELETE, - TERMKEY_SYM_SELECT, - TERMKEY_SYM_PAGEUP, - TERMKEY_SYM_PAGEDOWN, - TERMKEY_SYM_HOME, - TERMKEY_SYM_END, - - /* Special keys from terminfo */ - TERMKEY_SYM_CANCEL, - TERMKEY_SYM_CLEAR, - TERMKEY_SYM_CLOSE, - TERMKEY_SYM_COMMAND, - TERMKEY_SYM_COPY, - TERMKEY_SYM_EXIT, - TERMKEY_SYM_HELP, - TERMKEY_SYM_MARK, - TERMKEY_SYM_MESSAGE, - TERMKEY_SYM_MOVE, - TERMKEY_SYM_OPEN, - TERMKEY_SYM_OPTIONS, - TERMKEY_SYM_PRINT, - TERMKEY_SYM_REDO, - TERMKEY_SYM_REFERENCE, - TERMKEY_SYM_REFRESH, - TERMKEY_SYM_REPLACE, - TERMKEY_SYM_RESTART, - TERMKEY_SYM_RESUME, - TERMKEY_SYM_SAVE, - TERMKEY_SYM_SUSPEND, - TERMKEY_SYM_UNDO, - - /* Numeric keypad special keys */ - TERMKEY_SYM_KP0, - TERMKEY_SYM_KP1, - TERMKEY_SYM_KP2, - TERMKEY_SYM_KP3, - TERMKEY_SYM_KP4, - TERMKEY_SYM_KP5, - TERMKEY_SYM_KP6, - TERMKEY_SYM_KP7, - TERMKEY_SYM_KP8, - TERMKEY_SYM_KP9, - TERMKEY_SYM_KPENTER, - TERMKEY_SYM_KPPLUS, - TERMKEY_SYM_KPMINUS, - TERMKEY_SYM_KPMULT, - TERMKEY_SYM_KPDIV, - TERMKEY_SYM_KPCOMMA, - TERMKEY_SYM_KPPERIOD, - TERMKEY_SYM_KPEQUALS, - - /* et cetera ad nauseum */ - TERMKEY_N_SYMS -} TermKeySym; - -typedef enum { - TERMKEY_TYPE_UNICODE, - TERMKEY_TYPE_FUNCTION, - TERMKEY_TYPE_KEYSYM, - TERMKEY_TYPE_MOUSE, - TERMKEY_TYPE_POSITION, - TERMKEY_TYPE_MODEREPORT, - TERMKEY_TYPE_DCS, - TERMKEY_TYPE_OSC, - /* add other recognised types here */ - - TERMKEY_TYPE_UNKNOWN_CSI = -1 -} TermKeyType; - -typedef enum { - TERMKEY_RES_NONE, - TERMKEY_RES_KEY, - TERMKEY_RES_EOF, - TERMKEY_RES_AGAIN, - TERMKEY_RES_ERROR -} TermKeyResult; - -typedef enum { - TERMKEY_MOUSE_UNKNOWN, - TERMKEY_MOUSE_PRESS, - TERMKEY_MOUSE_DRAG, - TERMKEY_MOUSE_RELEASE -} TermKeyMouseEvent; - -enum { - TERMKEY_KEYMOD_SHIFT = 1 << 0, - TERMKEY_KEYMOD_ALT = 1 << 1, - TERMKEY_KEYMOD_CTRL = 1 << 2 -}; - -typedef struct { - TermKeyType type; - union { - long codepoint; /* TERMKEY_TYPE_UNICODE */ - int number; /* TERMKEY_TYPE_FUNCTION */ - TermKeySym sym; /* TERMKEY_TYPE_KEYSYM */ - char mouse[4]; /* TERMKEY_TYPE_MOUSE */ - /* opaque. see termkey_interpret_mouse */ - } code; - - int modifiers; - - /* Any Unicode character can be UTF-8 encoded in no more than 6 bytes, plus - * terminating NUL */ - char utf8[7]; -} TermKeyKey; - -typedef struct TermKey TermKey; - -enum { - TERMKEY_FLAG_NOINTERPRET = 1 << 0, /* Do not interpret C0//DEL codes if possible */ - TERMKEY_FLAG_CONVERTKP = 1 << 1, /* Convert KP codes to regular keypresses */ - TERMKEY_FLAG_RAW = 1 << 2, /* Input is raw bytes, not UTF-8 */ - TERMKEY_FLAG_UTF8 = 1 << 3, /* Input is definitely UTF-8 */ - TERMKEY_FLAG_NOTERMIOS = 1 << 4, /* Do not make initial termios calls on construction */ - TERMKEY_FLAG_SPACESYMBOL = 1 << 5, /* Sets TERMKEY_CANON_SPACESYMBOL */ - TERMKEY_FLAG_CTRLC = 1 << 6, /* Allow Ctrl-C to be read as normal, disabling SIGINT */ - TERMKEY_FLAG_EINTR = 1 << 7, /* Return ERROR on signal (EINTR) rather than retry */ - TERMKEY_FLAG_NOSTART = 1 << 8 /* Do not call termkey_start() in constructor */ -}; - -enum { - TERMKEY_CANON_SPACESYMBOL = 1 << 0, /* Space is symbolic rather than Unicode */ - TERMKEY_CANON_DELBS = 1 << 1 /* Del is converted to Backspace */ -}; - -void termkey_check_version(int major, int minor); - -TermKey *termkey_new(int fd, int flags); -TermKey *termkey_new_abstract(const char *term, int flags); -void termkey_free(TermKey *tk); -void termkey_destroy(TermKey *tk); - -/* Mostly-undocumented hooks for doing evil evil things */ -typedef const char *TermKey_Terminfo_Getstr_Hook(const char *name, const char *value, void *data); -void termkey_hook_terminfo_getstr(TermKey *tk, TermKey_Terminfo_Getstr_Hook *hookfn, void *data); - -int termkey_start(TermKey *tk); -int termkey_stop(TermKey *tk); -int termkey_is_started(TermKey *tk); - -int termkey_get_fd(TermKey *tk); - -int termkey_get_flags(TermKey *tk); -void termkey_set_flags(TermKey *tk, int newflags); - -int termkey_get_waittime(TermKey *tk); -void termkey_set_waittime(TermKey *tk, int msec); - -int termkey_get_canonflags(TermKey *tk); -void termkey_set_canonflags(TermKey *tk, int); - -size_t termkey_get_buffer_size(TermKey *tk); -int termkey_set_buffer_size(TermKey *tk, size_t size); - -size_t termkey_get_buffer_remaining(TermKey *tk); - -void termkey_canonicalise(TermKey *tk, TermKeyKey *key); - -TermKeyResult termkey_getkey(TermKey *tk, TermKeyKey *key); -TermKeyResult termkey_getkey_force(TermKey *tk, TermKeyKey *key); -TermKeyResult termkey_waitkey(TermKey *tk, TermKeyKey *key); - -TermKeyResult termkey_advisereadable(TermKey *tk); - -size_t termkey_push_bytes(TermKey *tk, const char *bytes, size_t len); - -TermKeySym termkey_register_keyname(TermKey *tk, TermKeySym sym, const char *name); -const char *termkey_get_keyname(TermKey *tk, TermKeySym sym); -const char *termkey_lookup_keyname(TermKey *tk, const char *str, TermKeySym *sym); - -TermKeySym termkey_keyname2sym(TermKey *tk, const char *keyname); - -TermKeyResult termkey_interpret_mouse(TermKey *tk, const TermKeyKey *key, TermKeyMouseEvent *event, int *button, int *line, int *col); - -TermKeyResult termkey_interpret_position(TermKey *tk, const TermKeyKey *key, int *line, int *col); - -TermKeyResult termkey_interpret_modereport(TermKey *tk, const TermKeyKey *key, int *initial, int *mode, int *value); - -TermKeyResult termkey_interpret_csi(TermKey *tk, const TermKeyKey *key, long args[], size_t *nargs, unsigned long *cmd); - -TermKeyResult termkey_interpret_string(TermKey *tk, const TermKeyKey *key, const char **strp); - -typedef enum { - TERMKEY_FORMAT_LONGMOD = 1 << 0, /* Shift-... instead of S-... */ - TERMKEY_FORMAT_CARETCTRL = 1 << 1, /* ^X instead of C-X */ - TERMKEY_FORMAT_ALTISMETA = 1 << 2, /* Meta- or M- instead of Alt- or A- */ - TERMKEY_FORMAT_WRAPBRACKET = 1 << 3, /* Wrap special keys in brackets like <Escape> */ - TERMKEY_FORMAT_SPACEMOD = 1 << 4, /* M Foo instead of M-Foo */ - TERMKEY_FORMAT_LOWERMOD = 1 << 5, /* meta or m instead of Meta or M */ - TERMKEY_FORMAT_LOWERSPACE = 1 << 6, /* page down instead of PageDown */ - - TERMKEY_FORMAT_MOUSE_POS = 1 << 8 /* Include mouse position if relevant; @ col,line */ -} TermKeyFormat; - -/* Some useful combinations */ - -#define TERMKEY_FORMAT_VIM (TermKeyFormat)(TERMKEY_FORMAT_ALTISMETA|TERMKEY_FORMAT_WRAPBRACKET) -#define TERMKEY_FORMAT_URWID (TermKeyFormat)(TERMKEY_FORMAT_LONGMOD|TERMKEY_FORMAT_ALTISMETA| \ - TERMKEY_FORMAT_LOWERMOD|TERMKEY_FORMAT_SPACEMOD|TERMKEY_FORMAT_LOWERSPACE) - -size_t termkey_strfkey(TermKey *tk, char *buffer, size_t len, TermKeyKey *key, TermKeyFormat format); -const char *termkey_strpkey(TermKey *tk, const char *str, TermKeyKey *key, TermKeyFormat format); - -int termkey_keycmp(TermKey *tk, const TermKeyKey *key1, const TermKeyKey *key2); - -#endif - -#ifdef __cplusplus -} -#endif diff --git a/src/unicode/CaseFolding.txt b/src/unicode/CaseFolding.txt deleted file mode 100644 index 69c5c64b4c..0000000000 --- a/src/unicode/CaseFolding.txt +++ /dev/null @@ -1,1627 +0,0 @@ -# CaseFolding-15.1.0.txt -# Date: 2023-05-12, 21:53:10 GMT -# © 2023 Unicode®, Inc. -# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see https://www.unicode.org/terms_of_use.html -# -# Unicode Character Database -# For documentation, see https://www.unicode.org/reports/tr44/ -# -# Case Folding Properties -# -# This file is a supplement to the UnicodeData file. -# It provides a case folding mapping generated from the Unicode Character Database. -# If all characters are mapped according to the full mapping below, then -# case differences (according to UnicodeData.txt and SpecialCasing.txt) -# are eliminated. -# -# The data supports both implementations that require simple case foldings -# (where string lengths don't change), and implementations that allow full case folding -# (where string lengths may grow). Note that where they can be supported, the -# full case foldings are superior: for example, they allow "MASSE" and "Maße" to match. -# -# All code points not listed in this file map to themselves. -# -# NOTE: case folding does not preserve normalization formats! -# -# For information on case folding, including how to have case folding -# preserve normalization formats, see Section 3.13 Default Case Algorithms in -# The Unicode Standard. -# -# ================================================================================ -# Format -# ================================================================================ -# The entries in this file are in the following machine-readable format: -# -# <code>; <status>; <mapping>; # <name> -# -# The status field is: -# C: common case folding, common mappings shared by both simple and full mappings. -# F: full case folding, mappings that cause strings to grow in length. Multiple characters are separated by spaces. -# S: simple case folding, mappings to single characters where different from F. -# T: special case for uppercase I and dotted uppercase I -# - For non-Turkic languages, this mapping is normally not used. -# - For Turkic languages (tr, az), this mapping can be used instead of the normal mapping for these characters. -# Note that the Turkic mappings do not maintain canonical equivalence without additional processing. -# See the discussions of case mapping in the Unicode Standard for more information. -# -# Usage: -# A. To do a simple case folding, use the mappings with status C + S. -# B. To do a full case folding, use the mappings with status C + F. -# -# The mappings with status T can be used or omitted depending on the desired case-folding -# behavior. (The default option is to exclude them.) -# -# ================================================================= - -# Property: Case_Folding - -# All code points not explicitly listed for Case_Folding -# have the value C for the status field, and the code point itself for the mapping field. - -# ================================================================= -0041; C; 0061; # LATIN CAPITAL LETTER A -0042; C; 0062; # LATIN CAPITAL LETTER B -0043; C; 0063; # LATIN CAPITAL LETTER C -0044; C; 0064; # LATIN CAPITAL LETTER D -0045; C; 0065; # LATIN CAPITAL LETTER E -0046; C; 0066; # LATIN CAPITAL LETTER F -0047; C; 0067; # LATIN CAPITAL LETTER G -0048; C; 0068; # LATIN CAPITAL LETTER H -0049; C; 0069; # LATIN CAPITAL LETTER I -0049; T; 0131; # LATIN CAPITAL LETTER I -004A; C; 006A; # LATIN CAPITAL LETTER J -004B; C; 006B; # LATIN CAPITAL LETTER K -004C; C; 006C; # LATIN CAPITAL LETTER L -004D; C; 006D; # LATIN CAPITAL LETTER M -004E; C; 006E; # LATIN CAPITAL LETTER N -004F; C; 006F; # LATIN CAPITAL LETTER O -0050; C; 0070; # LATIN CAPITAL LETTER P -0051; C; 0071; # LATIN CAPITAL LETTER Q -0052; C; 0072; # LATIN CAPITAL LETTER R -0053; C; 0073; # LATIN CAPITAL LETTER S -0054; C; 0074; # LATIN CAPITAL LETTER T -0055; C; 0075; # LATIN CAPITAL LETTER U -0056; C; 0076; # LATIN CAPITAL LETTER V -0057; C; 0077; # LATIN CAPITAL LETTER W -0058; C; 0078; # LATIN CAPITAL LETTER X -0059; C; 0079; # LATIN CAPITAL LETTER Y -005A; C; 007A; # LATIN CAPITAL LETTER Z -00B5; C; 03BC; # MICRO SIGN -00C0; C; 00E0; # LATIN CAPITAL LETTER A WITH GRAVE -00C1; C; 00E1; # LATIN CAPITAL LETTER A WITH ACUTE -00C2; C; 00E2; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX -00C3; C; 00E3; # LATIN CAPITAL LETTER A WITH TILDE -00C4; C; 00E4; # LATIN CAPITAL LETTER A WITH DIAERESIS -00C5; C; 00E5; # LATIN CAPITAL LETTER A WITH RING ABOVE -00C6; C; 00E6; # LATIN CAPITAL LETTER AE -00C7; C; 00E7; # LATIN CAPITAL LETTER C WITH CEDILLA -00C8; C; 00E8; # LATIN CAPITAL LETTER E WITH GRAVE -00C9; C; 00E9; # LATIN CAPITAL LETTER E WITH ACUTE -00CA; C; 00EA; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX -00CB; C; 00EB; # LATIN CAPITAL LETTER E WITH DIAERESIS -00CC; C; 00EC; # LATIN CAPITAL LETTER I WITH GRAVE -00CD; C; 00ED; # LATIN CAPITAL LETTER I WITH ACUTE -00CE; C; 00EE; # LATIN CAPITAL LETTER I WITH CIRCUMFLEX -00CF; C; 00EF; # LATIN CAPITAL LETTER I WITH DIAERESIS -00D0; C; 00F0; # LATIN CAPITAL LETTER ETH -00D1; C; 00F1; # LATIN CAPITAL LETTER N WITH TILDE -00D2; C; 00F2; # LATIN CAPITAL LETTER O WITH GRAVE -00D3; C; 00F3; # LATIN CAPITAL LETTER O WITH ACUTE -00D4; C; 00F4; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX -00D5; C; 00F5; # LATIN CAPITAL LETTER O WITH TILDE -00D6; C; 00F6; # LATIN CAPITAL LETTER O WITH DIAERESIS -00D8; C; 00F8; # LATIN CAPITAL LETTER O WITH STROKE -00D9; C; 00F9; # LATIN CAPITAL LETTER U WITH GRAVE -00DA; C; 00FA; # LATIN CAPITAL LETTER U WITH ACUTE -00DB; C; 00FB; # LATIN CAPITAL LETTER U WITH CIRCUMFLEX -00DC; C; 00FC; # LATIN CAPITAL LETTER U WITH DIAERESIS -00DD; C; 00FD; # LATIN CAPITAL LETTER Y WITH ACUTE -00DE; C; 00FE; # LATIN CAPITAL LETTER THORN -00DF; F; 0073 0073; # LATIN SMALL LETTER SHARP S -0100; C; 0101; # LATIN CAPITAL LETTER A WITH MACRON -0102; C; 0103; # LATIN CAPITAL LETTER A WITH BREVE -0104; C; 0105; # LATIN CAPITAL LETTER A WITH OGONEK -0106; C; 0107; # LATIN CAPITAL LETTER C WITH ACUTE -0108; C; 0109; # LATIN CAPITAL LETTER C WITH CIRCUMFLEX -010A; C; 010B; # LATIN CAPITAL LETTER C WITH DOT ABOVE -010C; C; 010D; # LATIN CAPITAL LETTER C WITH CARON -010E; C; 010F; # LATIN CAPITAL LETTER D WITH CARON -0110; C; 0111; # LATIN CAPITAL LETTER D WITH STROKE -0112; C; 0113; # LATIN CAPITAL LETTER E WITH MACRON -0114; C; 0115; # LATIN CAPITAL LETTER E WITH BREVE -0116; C; 0117; # LATIN CAPITAL LETTER E WITH DOT ABOVE -0118; C; 0119; # LATIN CAPITAL LETTER E WITH OGONEK -011A; C; 011B; # LATIN CAPITAL LETTER E WITH CARON -011C; C; 011D; # LATIN CAPITAL LETTER G WITH CIRCUMFLEX -011E; C; 011F; # LATIN CAPITAL LETTER G WITH BREVE -0120; C; 0121; # LATIN CAPITAL LETTER G WITH DOT ABOVE -0122; C; 0123; # LATIN CAPITAL LETTER G WITH CEDILLA -0124; C; 0125; # LATIN CAPITAL LETTER H WITH CIRCUMFLEX -0126; C; 0127; # LATIN CAPITAL LETTER H WITH STROKE -0128; C; 0129; # LATIN CAPITAL LETTER I WITH TILDE -012A; C; 012B; # LATIN CAPITAL LETTER I WITH MACRON -012C; C; 012D; # LATIN CAPITAL LETTER I WITH BREVE -012E; C; 012F; # LATIN CAPITAL LETTER I WITH OGONEK -0130; F; 0069 0307; # LATIN CAPITAL LETTER I WITH DOT ABOVE -0130; T; 0069; # LATIN CAPITAL LETTER I WITH DOT ABOVE -0132; C; 0133; # LATIN CAPITAL LIGATURE IJ -0134; C; 0135; # LATIN CAPITAL LETTER J WITH CIRCUMFLEX -0136; C; 0137; # LATIN CAPITAL LETTER K WITH CEDILLA -0139; C; 013A; # LATIN CAPITAL LETTER L WITH ACUTE -013B; C; 013C; # LATIN CAPITAL LETTER L WITH CEDILLA -013D; C; 013E; # LATIN CAPITAL LETTER L WITH CARON -013F; C; 0140; # LATIN CAPITAL LETTER L WITH MIDDLE DOT -0141; C; 0142; # LATIN CAPITAL LETTER L WITH STROKE -0143; C; 0144; # LATIN CAPITAL LETTER N WITH ACUTE -0145; C; 0146; # LATIN CAPITAL LETTER N WITH CEDILLA -0147; C; 0148; # LATIN CAPITAL LETTER N WITH CARON -0149; F; 02BC 006E; # LATIN SMALL LETTER N PRECEDED BY APOSTROPHE -014A; C; 014B; # LATIN CAPITAL LETTER ENG -014C; C; 014D; # LATIN CAPITAL LETTER O WITH MACRON -014E; C; 014F; # LATIN CAPITAL LETTER O WITH BREVE -0150; C; 0151; # LATIN CAPITAL LETTER O WITH DOUBLE ACUTE -0152; C; 0153; # LATIN CAPITAL LIGATURE OE -0154; C; 0155; # LATIN CAPITAL LETTER R WITH ACUTE -0156; C; 0157; # LATIN CAPITAL LETTER R WITH CEDILLA -0158; C; 0159; # LATIN CAPITAL LETTER R WITH CARON -015A; C; 015B; # LATIN CAPITAL LETTER S WITH ACUTE -015C; C; 015D; # LATIN CAPITAL LETTER S WITH CIRCUMFLEX -015E; C; 015F; # LATIN CAPITAL LETTER S WITH CEDILLA -0160; C; 0161; # LATIN CAPITAL LETTER S WITH CARON -0162; C; 0163; # LATIN CAPITAL LETTER T WITH CEDILLA -0164; C; 0165; # LATIN CAPITAL LETTER T WITH CARON -0166; C; 0167; # LATIN CAPITAL LETTER T WITH STROKE -0168; C; 0169; # LATIN CAPITAL LETTER U WITH TILDE -016A; C; 016B; # LATIN CAPITAL LETTER U WITH MACRON -016C; C; 016D; # LATIN CAPITAL LETTER U WITH BREVE -016E; C; 016F; # LATIN CAPITAL LETTER U WITH RING ABOVE -0170; C; 0171; # LATIN CAPITAL LETTER U WITH DOUBLE ACUTE -0172; C; 0173; # LATIN CAPITAL LETTER U WITH OGONEK -0174; C; 0175; # LATIN CAPITAL LETTER W WITH CIRCUMFLEX -0176; C; 0177; # LATIN CAPITAL LETTER Y WITH CIRCUMFLEX -0178; C; 00FF; # LATIN CAPITAL LETTER Y WITH DIAERESIS -0179; C; 017A; # LATIN CAPITAL LETTER Z WITH ACUTE -017B; C; 017C; # LATIN CAPITAL LETTER Z WITH DOT ABOVE -017D; C; 017E; # LATIN CAPITAL LETTER Z WITH CARON -017F; C; 0073; # LATIN SMALL LETTER LONG S -0181; C; 0253; # LATIN CAPITAL LETTER B WITH HOOK -0182; C; 0183; # LATIN CAPITAL LETTER B WITH TOPBAR -0184; C; 0185; # LATIN CAPITAL LETTER TONE SIX -0186; C; 0254; # LATIN CAPITAL LETTER OPEN O -0187; C; 0188; # LATIN CAPITAL LETTER C WITH HOOK -0189; C; 0256; # LATIN CAPITAL LETTER AFRICAN D -018A; C; 0257; # LATIN CAPITAL LETTER D WITH HOOK -018B; C; 018C; # LATIN CAPITAL LETTER D WITH TOPBAR -018E; C; 01DD; # LATIN CAPITAL LETTER REVERSED E -018F; C; 0259; # LATIN CAPITAL LETTER SCHWA -0190; C; 025B; # LATIN CAPITAL LETTER OPEN E -0191; C; 0192; # LATIN CAPITAL LETTER F WITH HOOK -0193; C; 0260; # LATIN CAPITAL LETTER G WITH HOOK -0194; C; 0263; # LATIN CAPITAL LETTER GAMMA -0196; C; 0269; # LATIN CAPITAL LETTER IOTA -0197; C; 0268; # LATIN CAPITAL LETTER I WITH STROKE -0198; C; 0199; # LATIN CAPITAL LETTER K WITH HOOK -019C; C; 026F; # LATIN CAPITAL LETTER TURNED M -019D; C; 0272; # LATIN CAPITAL LETTER N WITH LEFT HOOK -019F; C; 0275; # LATIN CAPITAL LETTER O WITH MIDDLE TILDE -01A0; C; 01A1; # LATIN CAPITAL LETTER O WITH HORN -01A2; C; 01A3; # LATIN CAPITAL LETTER OI -01A4; C; 01A5; # LATIN CAPITAL LETTER P WITH HOOK -01A6; C; 0280; # LATIN LETTER YR -01A7; C; 01A8; # LATIN CAPITAL LETTER TONE TWO -01A9; C; 0283; # LATIN CAPITAL LETTER ESH -01AC; C; 01AD; # LATIN CAPITAL LETTER T WITH HOOK -01AE; C; 0288; # LATIN CAPITAL LETTER T WITH RETROFLEX HOOK -01AF; C; 01B0; # LATIN CAPITAL LETTER U WITH HORN -01B1; C; 028A; # LATIN CAPITAL LETTER UPSILON -01B2; C; 028B; # LATIN CAPITAL LETTER V WITH HOOK -01B3; C; 01B4; # LATIN CAPITAL LETTER Y WITH HOOK -01B5; C; 01B6; # LATIN CAPITAL LETTER Z WITH STROKE -01B7; C; 0292; # LATIN CAPITAL LETTER EZH -01B8; C; 01B9; # LATIN CAPITAL LETTER EZH REVERSED -01BC; C; 01BD; # LATIN CAPITAL LETTER TONE FIVE -01C4; C; 01C6; # LATIN CAPITAL LETTER DZ WITH CARON -01C5; C; 01C6; # LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON -01C7; C; 01C9; # LATIN CAPITAL LETTER LJ -01C8; C; 01C9; # LATIN CAPITAL LETTER L WITH SMALL LETTER J -01CA; C; 01CC; # LATIN CAPITAL LETTER NJ -01CB; C; 01CC; # LATIN CAPITAL LETTER N WITH SMALL LETTER J -01CD; C; 01CE; # LATIN CAPITAL LETTER A WITH CARON -01CF; C; 01D0; # LATIN CAPITAL LETTER I WITH CARON -01D1; C; 01D2; # LATIN CAPITAL LETTER O WITH CARON -01D3; C; 01D4; # LATIN CAPITAL LETTER U WITH CARON -01D5; C; 01D6; # LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON -01D7; C; 01D8; # LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE -01D9; C; 01DA; # LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON -01DB; C; 01DC; # LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE -01DE; C; 01DF; # LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON -01E0; C; 01E1; # LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON -01E2; C; 01E3; # LATIN CAPITAL LETTER AE WITH MACRON -01E4; C; 01E5; # LATIN CAPITAL LETTER G WITH STROKE -01E6; C; 01E7; # LATIN CAPITAL LETTER G WITH CARON -01E8; C; 01E9; # LATIN CAPITAL LETTER K WITH CARON -01EA; C; 01EB; # LATIN CAPITAL LETTER O WITH OGONEK -01EC; C; 01ED; # LATIN CAPITAL LETTER O WITH OGONEK AND MACRON -01EE; C; 01EF; # LATIN CAPITAL LETTER EZH WITH CARON -01F0; F; 006A 030C; # LATIN SMALL LETTER J WITH CARON -01F1; C; 01F3; # LATIN CAPITAL LETTER DZ -01F2; C; 01F3; # LATIN CAPITAL LETTER D WITH SMALL LETTER Z -01F4; C; 01F5; # LATIN CAPITAL LETTER G WITH ACUTE -01F6; C; 0195; # LATIN CAPITAL LETTER HWAIR -01F7; C; 01BF; # LATIN CAPITAL LETTER WYNN -01F8; C; 01F9; # LATIN CAPITAL LETTER N WITH GRAVE -01FA; C; 01FB; # LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE -01FC; C; 01FD; # LATIN CAPITAL LETTER AE WITH ACUTE -01FE; C; 01FF; # LATIN CAPITAL LETTER O WITH STROKE AND ACUTE -0200; C; 0201; # LATIN CAPITAL LETTER A WITH DOUBLE GRAVE -0202; C; 0203; # LATIN CAPITAL LETTER A WITH INVERTED BREVE -0204; C; 0205; # LATIN CAPITAL LETTER E WITH DOUBLE GRAVE -0206; C; 0207; # LATIN CAPITAL LETTER E WITH INVERTED BREVE -0208; C; 0209; # LATIN CAPITAL LETTER I WITH DOUBLE GRAVE -020A; C; 020B; # LATIN CAPITAL LETTER I WITH INVERTED BREVE -020C; C; 020D; # LATIN CAPITAL LETTER O WITH DOUBLE GRAVE -020E; C; 020F; # LATIN CAPITAL LETTER O WITH INVERTED BREVE -0210; C; 0211; # LATIN CAPITAL LETTER R WITH DOUBLE GRAVE -0212; C; 0213; # LATIN CAPITAL LETTER R WITH INVERTED BREVE -0214; C; 0215; # LATIN CAPITAL LETTER U WITH DOUBLE GRAVE -0216; C; 0217; # LATIN CAPITAL LETTER U WITH INVERTED BREVE -0218; C; 0219; # LATIN CAPITAL LETTER S WITH COMMA BELOW -021A; C; 021B; # LATIN CAPITAL LETTER T WITH COMMA BELOW -021C; C; 021D; # LATIN CAPITAL LETTER YOGH -021E; C; 021F; # LATIN CAPITAL LETTER H WITH CARON -0220; C; 019E; # LATIN CAPITAL LETTER N WITH LONG RIGHT LEG -0222; C; 0223; # LATIN CAPITAL LETTER OU -0224; C; 0225; # LATIN CAPITAL LETTER Z WITH HOOK -0226; C; 0227; # LATIN CAPITAL LETTER A WITH DOT ABOVE -0228; C; 0229; # LATIN CAPITAL LETTER E WITH CEDILLA -022A; C; 022B; # LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON -022C; C; 022D; # LATIN CAPITAL LETTER O WITH TILDE AND MACRON -022E; C; 022F; # LATIN CAPITAL LETTER O WITH DOT ABOVE -0230; C; 0231; # LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON -0232; C; 0233; # LATIN CAPITAL LETTER Y WITH MACRON -023A; C; 2C65; # LATIN CAPITAL LETTER A WITH STROKE -023B; C; 023C; # LATIN CAPITAL LETTER C WITH STROKE -023D; C; 019A; # LATIN CAPITAL LETTER L WITH BAR -023E; C; 2C66; # LATIN CAPITAL LETTER T WITH DIAGONAL STROKE -0241; C; 0242; # LATIN CAPITAL LETTER GLOTTAL STOP -0243; C; 0180; # LATIN CAPITAL LETTER B WITH STROKE -0244; C; 0289; # LATIN CAPITAL LETTER U BAR -0245; C; 028C; # LATIN CAPITAL LETTER TURNED V -0246; C; 0247; # LATIN CAPITAL LETTER E WITH STROKE -0248; C; 0249; # LATIN CAPITAL LETTER J WITH STROKE -024A; C; 024B; # LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL -024C; C; 024D; # LATIN CAPITAL LETTER R WITH STROKE -024E; C; 024F; # LATIN CAPITAL LETTER Y WITH STROKE -0345; C; 03B9; # COMBINING GREEK YPOGEGRAMMENI -0370; C; 0371; # GREEK CAPITAL LETTER HETA -0372; C; 0373; # GREEK CAPITAL LETTER ARCHAIC SAMPI -0376; C; 0377; # GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA -037F; C; 03F3; # GREEK CAPITAL LETTER YOT -0386; C; 03AC; # GREEK CAPITAL LETTER ALPHA WITH TONOS -0388; C; 03AD; # GREEK CAPITAL LETTER EPSILON WITH TONOS -0389; C; 03AE; # GREEK CAPITAL LETTER ETA WITH TONOS -038A; C; 03AF; # GREEK CAPITAL LETTER IOTA WITH TONOS -038C; C; 03CC; # GREEK CAPITAL LETTER OMICRON WITH TONOS -038E; C; 03CD; # GREEK CAPITAL LETTER UPSILON WITH TONOS -038F; C; 03CE; # GREEK CAPITAL LETTER OMEGA WITH TONOS -0390; F; 03B9 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS -0391; C; 03B1; # GREEK CAPITAL LETTER ALPHA -0392; C; 03B2; # GREEK CAPITAL LETTER BETA -0393; C; 03B3; # GREEK CAPITAL LETTER GAMMA -0394; C; 03B4; # GREEK CAPITAL LETTER DELTA -0395; C; 03B5; # GREEK CAPITAL LETTER EPSILON -0396; C; 03B6; # GREEK CAPITAL LETTER ZETA -0397; C; 03B7; # GREEK CAPITAL LETTER ETA -0398; C; 03B8; # GREEK CAPITAL LETTER THETA -0399; C; 03B9; # GREEK CAPITAL LETTER IOTA -039A; C; 03BA; # GREEK CAPITAL LETTER KAPPA -039B; C; 03BB; # GREEK CAPITAL LETTER LAMDA -039C; C; 03BC; # GREEK CAPITAL LETTER MU -039D; C; 03BD; # GREEK CAPITAL LETTER NU -039E; C; 03BE; # GREEK CAPITAL LETTER XI -039F; C; 03BF; # GREEK CAPITAL LETTER OMICRON -03A0; C; 03C0; # GREEK CAPITAL LETTER PI -03A1; C; 03C1; # GREEK CAPITAL LETTER RHO -03A3; C; 03C3; # GREEK CAPITAL LETTER SIGMA -03A4; C; 03C4; # GREEK CAPITAL LETTER TAU -03A5; C; 03C5; # GREEK CAPITAL LETTER UPSILON -03A6; C; 03C6; # GREEK CAPITAL LETTER PHI -03A7; C; 03C7; # GREEK CAPITAL LETTER CHI -03A8; C; 03C8; # GREEK CAPITAL LETTER PSI -03A9; C; 03C9; # GREEK CAPITAL LETTER OMEGA -03AA; C; 03CA; # GREEK CAPITAL LETTER IOTA WITH DIALYTIKA -03AB; C; 03CB; # GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA -03B0; F; 03C5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS -03C2; C; 03C3; # GREEK SMALL LETTER FINAL SIGMA -03CF; C; 03D7; # GREEK CAPITAL KAI SYMBOL -03D0; C; 03B2; # GREEK BETA SYMBOL -03D1; C; 03B8; # GREEK THETA SYMBOL -03D5; C; 03C6; # GREEK PHI SYMBOL -03D6; C; 03C0; # GREEK PI SYMBOL -03D8; C; 03D9; # GREEK LETTER ARCHAIC KOPPA -03DA; C; 03DB; # GREEK LETTER STIGMA -03DC; C; 03DD; # GREEK LETTER DIGAMMA -03DE; C; 03DF; # GREEK LETTER KOPPA -03E0; C; 03E1; # GREEK LETTER SAMPI -03E2; C; 03E3; # COPTIC CAPITAL LETTER SHEI -03E4; C; 03E5; # COPTIC CAPITAL LETTER FEI -03E6; C; 03E7; # COPTIC CAPITAL LETTER KHEI -03E8; C; 03E9; # COPTIC CAPITAL LETTER HORI -03EA; C; 03EB; # COPTIC CAPITAL LETTER GANGIA -03EC; C; 03ED; # COPTIC CAPITAL LETTER SHIMA -03EE; C; 03EF; # COPTIC CAPITAL LETTER DEI -03F0; C; 03BA; # GREEK KAPPA SYMBOL -03F1; C; 03C1; # GREEK RHO SYMBOL -03F4; C; 03B8; # GREEK CAPITAL THETA SYMBOL -03F5; C; 03B5; # GREEK LUNATE EPSILON SYMBOL -03F7; C; 03F8; # GREEK CAPITAL LETTER SHO -03F9; C; 03F2; # GREEK CAPITAL LUNATE SIGMA SYMBOL -03FA; C; 03FB; # GREEK CAPITAL LETTER SAN -03FD; C; 037B; # GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL -03FE; C; 037C; # GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL -03FF; C; 037D; # GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL -0400; C; 0450; # CYRILLIC CAPITAL LETTER IE WITH GRAVE -0401; C; 0451; # CYRILLIC CAPITAL LETTER IO -0402; C; 0452; # CYRILLIC CAPITAL LETTER DJE -0403; C; 0453; # CYRILLIC CAPITAL LETTER GJE -0404; C; 0454; # CYRILLIC CAPITAL LETTER UKRAINIAN IE -0405; C; 0455; # CYRILLIC CAPITAL LETTER DZE -0406; C; 0456; # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I -0407; C; 0457; # CYRILLIC CAPITAL LETTER YI -0408; C; 0458; # CYRILLIC CAPITAL LETTER JE -0409; C; 0459; # CYRILLIC CAPITAL LETTER LJE -040A; C; 045A; # CYRILLIC CAPITAL LETTER NJE -040B; C; 045B; # CYRILLIC CAPITAL LETTER TSHE -040C; C; 045C; # CYRILLIC CAPITAL LETTER KJE -040D; C; 045D; # CYRILLIC CAPITAL LETTER I WITH GRAVE -040E; C; 045E; # CYRILLIC CAPITAL LETTER SHORT U -040F; C; 045F; # CYRILLIC CAPITAL LETTER DZHE -0410; C; 0430; # CYRILLIC CAPITAL LETTER A -0411; C; 0431; # CYRILLIC CAPITAL LETTER BE -0412; C; 0432; # CYRILLIC CAPITAL LETTER VE -0413; C; 0433; # CYRILLIC CAPITAL LETTER GHE -0414; C; 0434; # CYRILLIC CAPITAL LETTER DE -0415; C; 0435; # CYRILLIC CAPITAL LETTER IE -0416; C; 0436; # CYRILLIC CAPITAL LETTER ZHE -0417; C; 0437; # CYRILLIC CAPITAL LETTER ZE -0418; C; 0438; # CYRILLIC CAPITAL LETTER I -0419; C; 0439; # CYRILLIC CAPITAL LETTER SHORT I -041A; C; 043A; # CYRILLIC CAPITAL LETTER KA -041B; C; 043B; # CYRILLIC CAPITAL LETTER EL -041C; C; 043C; # CYRILLIC CAPITAL LETTER EM -041D; C; 043D; # CYRILLIC CAPITAL LETTER EN -041E; C; 043E; # CYRILLIC CAPITAL LETTER O -041F; C; 043F; # CYRILLIC CAPITAL LETTER PE -0420; C; 0440; # CYRILLIC CAPITAL LETTER ER -0421; C; 0441; # CYRILLIC CAPITAL LETTER ES -0422; C; 0442; # CYRILLIC CAPITAL LETTER TE -0423; C; 0443; # CYRILLIC CAPITAL LETTER U -0424; C; 0444; # CYRILLIC CAPITAL LETTER EF -0425; C; 0445; # CYRILLIC CAPITAL LETTER HA -0426; C; 0446; # CYRILLIC CAPITAL LETTER TSE -0427; C; 0447; # CYRILLIC CAPITAL LETTER CHE -0428; C; 0448; # CYRILLIC CAPITAL LETTER SHA -0429; C; 0449; # CYRILLIC CAPITAL LETTER SHCHA -042A; C; 044A; # CYRILLIC CAPITAL LETTER HARD SIGN -042B; C; 044B; # CYRILLIC CAPITAL LETTER YERU -042C; C; 044C; # CYRILLIC CAPITAL LETTER SOFT SIGN -042D; C; 044D; # CYRILLIC CAPITAL LETTER E -042E; C; 044E; # CYRILLIC CAPITAL LETTER YU -042F; C; 044F; # CYRILLIC CAPITAL LETTER YA -0460; C; 0461; # CYRILLIC CAPITAL LETTER OMEGA -0462; C; 0463; # CYRILLIC CAPITAL LETTER YAT -0464; C; 0465; # CYRILLIC CAPITAL LETTER IOTIFIED E -0466; C; 0467; # CYRILLIC CAPITAL LETTER LITTLE YUS -0468; C; 0469; # CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS -046A; C; 046B; # CYRILLIC CAPITAL LETTER BIG YUS -046C; C; 046D; # CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS -046E; C; 046F; # CYRILLIC CAPITAL LETTER KSI -0470; C; 0471; # CYRILLIC CAPITAL LETTER PSI -0472; C; 0473; # CYRILLIC CAPITAL LETTER FITA -0474; C; 0475; # CYRILLIC CAPITAL LETTER IZHITSA -0476; C; 0477; # CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT -0478; C; 0479; # CYRILLIC CAPITAL LETTER UK -047A; C; 047B; # CYRILLIC CAPITAL LETTER ROUND OMEGA -047C; C; 047D; # CYRILLIC CAPITAL LETTER OMEGA WITH TITLO -047E; C; 047F; # CYRILLIC CAPITAL LETTER OT -0480; C; 0481; # CYRILLIC CAPITAL LETTER KOPPA -048A; C; 048B; # CYRILLIC CAPITAL LETTER SHORT I WITH TAIL -048C; C; 048D; # CYRILLIC CAPITAL LETTER SEMISOFT SIGN -048E; C; 048F; # CYRILLIC CAPITAL LETTER ER WITH TICK -0490; C; 0491; # CYRILLIC CAPITAL LETTER GHE WITH UPTURN -0492; C; 0493; # CYRILLIC CAPITAL LETTER GHE WITH STROKE -0494; C; 0495; # CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK -0496; C; 0497; # CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER -0498; C; 0499; # CYRILLIC CAPITAL LETTER ZE WITH DESCENDER -049A; C; 049B; # CYRILLIC CAPITAL LETTER KA WITH DESCENDER -049C; C; 049D; # CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE -049E; C; 049F; # CYRILLIC CAPITAL LETTER KA WITH STROKE -04A0; C; 04A1; # CYRILLIC CAPITAL LETTER BASHKIR KA -04A2; C; 04A3; # CYRILLIC CAPITAL LETTER EN WITH DESCENDER -04A4; C; 04A5; # CYRILLIC CAPITAL LIGATURE EN GHE -04A6; C; 04A7; # CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK -04A8; C; 04A9; # CYRILLIC CAPITAL LETTER ABKHASIAN HA -04AA; C; 04AB; # CYRILLIC CAPITAL LETTER ES WITH DESCENDER -04AC; C; 04AD; # CYRILLIC CAPITAL LETTER TE WITH DESCENDER -04AE; C; 04AF; # CYRILLIC CAPITAL LETTER STRAIGHT U -04B0; C; 04B1; # CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE -04B2; C; 04B3; # CYRILLIC CAPITAL LETTER HA WITH DESCENDER -04B4; C; 04B5; # CYRILLIC CAPITAL LIGATURE TE TSE -04B6; C; 04B7; # CYRILLIC CAPITAL LETTER CHE WITH DESCENDER -04B8; C; 04B9; # CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE -04BA; C; 04BB; # CYRILLIC CAPITAL LETTER SHHA -04BC; C; 04BD; # CYRILLIC CAPITAL LETTER ABKHASIAN CHE -04BE; C; 04BF; # CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER -04C0; C; 04CF; # CYRILLIC LETTER PALOCHKA -04C1; C; 04C2; # CYRILLIC CAPITAL LETTER ZHE WITH BREVE -04C3; C; 04C4; # CYRILLIC CAPITAL LETTER KA WITH HOOK -04C5; C; 04C6; # CYRILLIC CAPITAL LETTER EL WITH TAIL -04C7; C; 04C8; # CYRILLIC CAPITAL LETTER EN WITH HOOK -04C9; C; 04CA; # CYRILLIC CAPITAL LETTER EN WITH TAIL -04CB; C; 04CC; # CYRILLIC CAPITAL LETTER KHAKASSIAN CHE -04CD; C; 04CE; # CYRILLIC CAPITAL LETTER EM WITH TAIL -04D0; C; 04D1; # CYRILLIC CAPITAL LETTER A WITH BREVE -04D2; C; 04D3; # CYRILLIC CAPITAL LETTER A WITH DIAERESIS -04D4; C; 04D5; # CYRILLIC CAPITAL LIGATURE A IE -04D6; C; 04D7; # CYRILLIC CAPITAL LETTER IE WITH BREVE -04D8; C; 04D9; # CYRILLIC CAPITAL LETTER SCHWA -04DA; C; 04DB; # CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS -04DC; C; 04DD; # CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS -04DE; C; 04DF; # CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS -04E0; C; 04E1; # CYRILLIC CAPITAL LETTER ABKHASIAN DZE -04E2; C; 04E3; # CYRILLIC CAPITAL LETTER I WITH MACRON -04E4; C; 04E5; # CYRILLIC CAPITAL LETTER I WITH DIAERESIS -04E6; C; 04E7; # CYRILLIC CAPITAL LETTER O WITH DIAERESIS -04E8; C; 04E9; # CYRILLIC CAPITAL LETTER BARRED O -04EA; C; 04EB; # CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS -04EC; C; 04ED; # CYRILLIC CAPITAL LETTER E WITH DIAERESIS -04EE; C; 04EF; # CYRILLIC CAPITAL LETTER U WITH MACRON -04F0; C; 04F1; # CYRILLIC CAPITAL LETTER U WITH DIAERESIS -04F2; C; 04F3; # CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE -04F4; C; 04F5; # CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS -04F6; C; 04F7; # CYRILLIC CAPITAL LETTER GHE WITH DESCENDER -04F8; C; 04F9; # CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS -04FA; C; 04FB; # CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK -04FC; C; 04FD; # CYRILLIC CAPITAL LETTER HA WITH HOOK -04FE; C; 04FF; # CYRILLIC CAPITAL LETTER HA WITH STROKE -0500; C; 0501; # CYRILLIC CAPITAL LETTER KOMI DE -0502; C; 0503; # CYRILLIC CAPITAL LETTER KOMI DJE -0504; C; 0505; # CYRILLIC CAPITAL LETTER KOMI ZJE -0506; C; 0507; # CYRILLIC CAPITAL LETTER KOMI DZJE -0508; C; 0509; # CYRILLIC CAPITAL LETTER KOMI LJE -050A; C; 050B; # CYRILLIC CAPITAL LETTER KOMI NJE -050C; C; 050D; # CYRILLIC CAPITAL LETTER KOMI SJE -050E; C; 050F; # CYRILLIC CAPITAL LETTER KOMI TJE -0510; C; 0511; # CYRILLIC CAPITAL LETTER REVERSED ZE -0512; C; 0513; # CYRILLIC CAPITAL LETTER EL WITH HOOK -0514; C; 0515; # CYRILLIC CAPITAL LETTER LHA -0516; C; 0517; # CYRILLIC CAPITAL LETTER RHA -0518; C; 0519; # CYRILLIC CAPITAL LETTER YAE -051A; C; 051B; # CYRILLIC CAPITAL LETTER QA -051C; C; 051D; # CYRILLIC CAPITAL LETTER WE -051E; C; 051F; # CYRILLIC CAPITAL LETTER ALEUT KA -0520; C; 0521; # CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK -0522; C; 0523; # CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK -0524; C; 0525; # CYRILLIC CAPITAL LETTER PE WITH DESCENDER -0526; C; 0527; # CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER -0528; C; 0529; # CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK -052A; C; 052B; # CYRILLIC CAPITAL LETTER DZZHE -052C; C; 052D; # CYRILLIC CAPITAL LETTER DCHE -052E; C; 052F; # CYRILLIC CAPITAL LETTER EL WITH DESCENDER -0531; C; 0561; # ARMENIAN CAPITAL LETTER AYB -0532; C; 0562; # ARMENIAN CAPITAL LETTER BEN -0533; C; 0563; # ARMENIAN CAPITAL LETTER GIM -0534; C; 0564; # ARMENIAN CAPITAL LETTER DA -0535; C; 0565; # ARMENIAN CAPITAL LETTER ECH -0536; C; 0566; # ARMENIAN CAPITAL LETTER ZA -0537; C; 0567; # ARMENIAN CAPITAL LETTER EH -0538; C; 0568; # ARMENIAN CAPITAL LETTER ET -0539; C; 0569; # ARMENIAN CAPITAL LETTER TO -053A; C; 056A; # ARMENIAN CAPITAL LETTER ZHE -053B; C; 056B; # ARMENIAN CAPITAL LETTER INI -053C; C; 056C; # ARMENIAN CAPITAL LETTER LIWN -053D; C; 056D; # ARMENIAN CAPITAL LETTER XEH -053E; C; 056E; # ARMENIAN CAPITAL LETTER CA -053F; C; 056F; # ARMENIAN CAPITAL LETTER KEN -0540; C; 0570; # ARMENIAN CAPITAL LETTER HO -0541; C; 0571; # ARMENIAN CAPITAL LETTER JA -0542; C; 0572; # ARMENIAN CAPITAL LETTER GHAD -0543; C; 0573; # ARMENIAN CAPITAL LETTER CHEH -0544; C; 0574; # ARMENIAN CAPITAL LETTER MEN -0545; C; 0575; # ARMENIAN CAPITAL LETTER YI -0546; C; 0576; # ARMENIAN CAPITAL LETTER NOW -0547; C; 0577; # ARMENIAN CAPITAL LETTER SHA -0548; C; 0578; # ARMENIAN CAPITAL LETTER VO -0549; C; 0579; # ARMENIAN CAPITAL LETTER CHA -054A; C; 057A; # ARMENIAN CAPITAL LETTER PEH -054B; C; 057B; # ARMENIAN CAPITAL LETTER JHEH -054C; C; 057C; # ARMENIAN CAPITAL LETTER RA -054D; C; 057D; # ARMENIAN CAPITAL LETTER SEH -054E; C; 057E; # ARMENIAN CAPITAL LETTER VEW -054F; C; 057F; # ARMENIAN CAPITAL LETTER TIWN -0550; C; 0580; # ARMENIAN CAPITAL LETTER REH -0551; C; 0581; # ARMENIAN CAPITAL LETTER CO -0552; C; 0582; # ARMENIAN CAPITAL LETTER YIWN -0553; C; 0583; # ARMENIAN CAPITAL LETTER PIWR -0554; C; 0584; # ARMENIAN CAPITAL LETTER KEH -0555; C; 0585; # ARMENIAN CAPITAL LETTER OH -0556; C; 0586; # ARMENIAN CAPITAL LETTER FEH -0587; F; 0565 0582; # ARMENIAN SMALL LIGATURE ECH YIWN -10A0; C; 2D00; # GEORGIAN CAPITAL LETTER AN -10A1; C; 2D01; # GEORGIAN CAPITAL LETTER BAN -10A2; C; 2D02; # GEORGIAN CAPITAL LETTER GAN -10A3; C; 2D03; # GEORGIAN CAPITAL LETTER DON -10A4; C; 2D04; # GEORGIAN CAPITAL LETTER EN -10A5; C; 2D05; # GEORGIAN CAPITAL LETTER VIN -10A6; C; 2D06; # GEORGIAN CAPITAL LETTER ZEN -10A7; C; 2D07; # GEORGIAN CAPITAL LETTER TAN -10A8; C; 2D08; # GEORGIAN CAPITAL LETTER IN -10A9; C; 2D09; # GEORGIAN CAPITAL LETTER KAN -10AA; C; 2D0A; # GEORGIAN CAPITAL LETTER LAS -10AB; C; 2D0B; # GEORGIAN CAPITAL LETTER MAN -10AC; C; 2D0C; # GEORGIAN CAPITAL LETTER NAR -10AD; C; 2D0D; # GEORGIAN CAPITAL LETTER ON -10AE; C; 2D0E; # GEORGIAN CAPITAL LETTER PAR -10AF; C; 2D0F; # GEORGIAN CAPITAL LETTER ZHAR -10B0; C; 2D10; # GEORGIAN CAPITAL LETTER RAE -10B1; C; 2D11; # GEORGIAN CAPITAL LETTER SAN -10B2; C; 2D12; # GEORGIAN CAPITAL LETTER TAR -10B3; C; 2D13; # GEORGIAN CAPITAL LETTER UN -10B4; C; 2D14; # GEORGIAN CAPITAL LETTER PHAR -10B5; C; 2D15; # GEORGIAN CAPITAL LETTER KHAR -10B6; C; 2D16; # GEORGIAN CAPITAL LETTER GHAN -10B7; C; 2D17; # GEORGIAN CAPITAL LETTER QAR -10B8; C; 2D18; # GEORGIAN CAPITAL LETTER SHIN -10B9; C; 2D19; # GEORGIAN CAPITAL LETTER CHIN -10BA; C; 2D1A; # GEORGIAN CAPITAL LETTER CAN -10BB; C; 2D1B; # GEORGIAN CAPITAL LETTER JIL -10BC; C; 2D1C; # GEORGIAN CAPITAL LETTER CIL -10BD; C; 2D1D; # GEORGIAN CAPITAL LETTER CHAR -10BE; C; 2D1E; # GEORGIAN CAPITAL LETTER XAN -10BF; C; 2D1F; # GEORGIAN CAPITAL LETTER JHAN -10C0; C; 2D20; # GEORGIAN CAPITAL LETTER HAE -10C1; C; 2D21; # GEORGIAN CAPITAL LETTER HE -10C2; C; 2D22; # GEORGIAN CAPITAL LETTER HIE -10C3; C; 2D23; # GEORGIAN CAPITAL LETTER WE -10C4; C; 2D24; # GEORGIAN CAPITAL LETTER HAR -10C5; C; 2D25; # GEORGIAN CAPITAL LETTER HOE -10C7; C; 2D27; # GEORGIAN CAPITAL LETTER YN -10CD; C; 2D2D; # GEORGIAN CAPITAL LETTER AEN -13F8; C; 13F0; # CHEROKEE SMALL LETTER YE -13F9; C; 13F1; # CHEROKEE SMALL LETTER YI -13FA; C; 13F2; # CHEROKEE SMALL LETTER YO -13FB; C; 13F3; # CHEROKEE SMALL LETTER YU -13FC; C; 13F4; # CHEROKEE SMALL LETTER YV -13FD; C; 13F5; # CHEROKEE SMALL LETTER MV -1C80; C; 0432; # CYRILLIC SMALL LETTER ROUNDED VE -1C81; C; 0434; # CYRILLIC SMALL LETTER LONG-LEGGED DE -1C82; C; 043E; # CYRILLIC SMALL LETTER NARROW O -1C83; C; 0441; # CYRILLIC SMALL LETTER WIDE ES -1C84; C; 0442; # CYRILLIC SMALL LETTER TALL TE -1C85; C; 0442; # CYRILLIC SMALL LETTER THREE-LEGGED TE -1C86; C; 044A; # CYRILLIC SMALL LETTER TALL HARD SIGN -1C87; C; 0463; # CYRILLIC SMALL LETTER TALL YAT -1C88; C; A64B; # CYRILLIC SMALL LETTER UNBLENDED UK -1C90; C; 10D0; # GEORGIAN MTAVRULI CAPITAL LETTER AN -1C91; C; 10D1; # GEORGIAN MTAVRULI CAPITAL LETTER BAN -1C92; C; 10D2; # GEORGIAN MTAVRULI CAPITAL LETTER GAN -1C93; C; 10D3; # GEORGIAN MTAVRULI CAPITAL LETTER DON -1C94; C; 10D4; # GEORGIAN MTAVRULI CAPITAL LETTER EN -1C95; C; 10D5; # GEORGIAN MTAVRULI CAPITAL LETTER VIN -1C96; C; 10D6; # GEORGIAN MTAVRULI CAPITAL LETTER ZEN -1C97; C; 10D7; # GEORGIAN MTAVRULI CAPITAL LETTER TAN -1C98; C; 10D8; # GEORGIAN MTAVRULI CAPITAL LETTER IN -1C99; C; 10D9; # GEORGIAN MTAVRULI CAPITAL LETTER KAN -1C9A; C; 10DA; # GEORGIAN MTAVRULI CAPITAL LETTER LAS -1C9B; C; 10DB; # GEORGIAN MTAVRULI CAPITAL LETTER MAN -1C9C; C; 10DC; # GEORGIAN MTAVRULI CAPITAL LETTER NAR -1C9D; C; 10DD; # GEORGIAN MTAVRULI CAPITAL LETTER ON -1C9E; C; 10DE; # GEORGIAN MTAVRULI CAPITAL LETTER PAR -1C9F; C; 10DF; # GEORGIAN MTAVRULI CAPITAL LETTER ZHAR -1CA0; C; 10E0; # GEORGIAN MTAVRULI CAPITAL LETTER RAE -1CA1; C; 10E1; # GEORGIAN MTAVRULI CAPITAL LETTER SAN -1CA2; C; 10E2; # GEORGIAN MTAVRULI CAPITAL LETTER TAR -1CA3; C; 10E3; # GEORGIAN MTAVRULI CAPITAL LETTER UN -1CA4; C; 10E4; # GEORGIAN MTAVRULI CAPITAL LETTER PHAR -1CA5; C; 10E5; # GEORGIAN MTAVRULI CAPITAL LETTER KHAR -1CA6; C; 10E6; # GEORGIAN MTAVRULI CAPITAL LETTER GHAN -1CA7; C; 10E7; # GEORGIAN MTAVRULI CAPITAL LETTER QAR -1CA8; C; 10E8; # GEORGIAN MTAVRULI CAPITAL LETTER SHIN -1CA9; C; 10E9; # GEORGIAN MTAVRULI CAPITAL LETTER CHIN -1CAA; C; 10EA; # GEORGIAN MTAVRULI CAPITAL LETTER CAN -1CAB; C; 10EB; # GEORGIAN MTAVRULI CAPITAL LETTER JIL -1CAC; C; 10EC; # GEORGIAN MTAVRULI CAPITAL LETTER CIL -1CAD; C; 10ED; # GEORGIAN MTAVRULI CAPITAL LETTER CHAR -1CAE; C; 10EE; # GEORGIAN MTAVRULI CAPITAL LETTER XAN -1CAF; C; 10EF; # GEORGIAN MTAVRULI CAPITAL LETTER JHAN -1CB0; C; 10F0; # GEORGIAN MTAVRULI CAPITAL LETTER HAE -1CB1; C; 10F1; # GEORGIAN MTAVRULI CAPITAL LETTER HE -1CB2; C; 10F2; # GEORGIAN MTAVRULI CAPITAL LETTER HIE -1CB3; C; 10F3; # GEORGIAN MTAVRULI CAPITAL LETTER WE -1CB4; C; 10F4; # GEORGIAN MTAVRULI CAPITAL LETTER HAR -1CB5; C; 10F5; # GEORGIAN MTAVRULI CAPITAL LETTER HOE -1CB6; C; 10F6; # GEORGIAN MTAVRULI CAPITAL LETTER FI -1CB7; C; 10F7; # GEORGIAN MTAVRULI CAPITAL LETTER YN -1CB8; C; 10F8; # GEORGIAN MTAVRULI CAPITAL LETTER ELIFI -1CB9; C; 10F9; # GEORGIAN MTAVRULI CAPITAL LETTER TURNED GAN -1CBA; C; 10FA; # GEORGIAN MTAVRULI CAPITAL LETTER AIN -1CBD; C; 10FD; # GEORGIAN MTAVRULI CAPITAL LETTER AEN -1CBE; C; 10FE; # GEORGIAN MTAVRULI CAPITAL LETTER HARD SIGN -1CBF; C; 10FF; # GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN -1E00; C; 1E01; # LATIN CAPITAL LETTER A WITH RING BELOW -1E02; C; 1E03; # LATIN CAPITAL LETTER B WITH DOT ABOVE -1E04; C; 1E05; # LATIN CAPITAL LETTER B WITH DOT BELOW -1E06; C; 1E07; # LATIN CAPITAL LETTER B WITH LINE BELOW -1E08; C; 1E09; # LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE -1E0A; C; 1E0B; # LATIN CAPITAL LETTER D WITH DOT ABOVE -1E0C; C; 1E0D; # LATIN CAPITAL LETTER D WITH DOT BELOW -1E0E; C; 1E0F; # LATIN CAPITAL LETTER D WITH LINE BELOW -1E10; C; 1E11; # LATIN CAPITAL LETTER D WITH CEDILLA -1E12; C; 1E13; # LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW -1E14; C; 1E15; # LATIN CAPITAL LETTER E WITH MACRON AND GRAVE -1E16; C; 1E17; # LATIN CAPITAL LETTER E WITH MACRON AND ACUTE -1E18; C; 1E19; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW -1E1A; C; 1E1B; # LATIN CAPITAL LETTER E WITH TILDE BELOW -1E1C; C; 1E1D; # LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE -1E1E; C; 1E1F; # LATIN CAPITAL LETTER F WITH DOT ABOVE -1E20; C; 1E21; # LATIN CAPITAL LETTER G WITH MACRON -1E22; C; 1E23; # LATIN CAPITAL LETTER H WITH DOT ABOVE -1E24; C; 1E25; # LATIN CAPITAL LETTER H WITH DOT BELOW -1E26; C; 1E27; # LATIN CAPITAL LETTER H WITH DIAERESIS -1E28; C; 1E29; # LATIN CAPITAL LETTER H WITH CEDILLA -1E2A; C; 1E2B; # LATIN CAPITAL LETTER H WITH BREVE BELOW -1E2C; C; 1E2D; # LATIN CAPITAL LETTER I WITH TILDE BELOW -1E2E; C; 1E2F; # LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE -1E30; C; 1E31; # LATIN CAPITAL LETTER K WITH ACUTE -1E32; C; 1E33; # LATIN CAPITAL LETTER K WITH DOT BELOW -1E34; C; 1E35; # LATIN CAPITAL LETTER K WITH LINE BELOW -1E36; C; 1E37; # LATIN CAPITAL LETTER L WITH DOT BELOW -1E38; C; 1E39; # LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON -1E3A; C; 1E3B; # LATIN CAPITAL LETTER L WITH LINE BELOW -1E3C; C; 1E3D; # LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW -1E3E; C; 1E3F; # LATIN CAPITAL LETTER M WITH ACUTE -1E40; C; 1E41; # LATIN CAPITAL LETTER M WITH DOT ABOVE -1E42; C; 1E43; # LATIN CAPITAL LETTER M WITH DOT BELOW -1E44; C; 1E45; # LATIN CAPITAL LETTER N WITH DOT ABOVE -1E46; C; 1E47; # LATIN CAPITAL LETTER N WITH DOT BELOW -1E48; C; 1E49; # LATIN CAPITAL LETTER N WITH LINE BELOW -1E4A; C; 1E4B; # LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW -1E4C; C; 1E4D; # LATIN CAPITAL LETTER O WITH TILDE AND ACUTE -1E4E; C; 1E4F; # LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS -1E50; C; 1E51; # LATIN CAPITAL LETTER O WITH MACRON AND GRAVE -1E52; C; 1E53; # LATIN CAPITAL LETTER O WITH MACRON AND ACUTE -1E54; C; 1E55; # LATIN CAPITAL LETTER P WITH ACUTE -1E56; C; 1E57; # LATIN CAPITAL LETTER P WITH DOT ABOVE -1E58; C; 1E59; # LATIN CAPITAL LETTER R WITH DOT ABOVE -1E5A; C; 1E5B; # LATIN CAPITAL LETTER R WITH DOT BELOW -1E5C; C; 1E5D; # LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON -1E5E; C; 1E5F; # LATIN CAPITAL LETTER R WITH LINE BELOW -1E60; C; 1E61; # LATIN CAPITAL LETTER S WITH DOT ABOVE -1E62; C; 1E63; # LATIN CAPITAL LETTER S WITH DOT BELOW -1E64; C; 1E65; # LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE -1E66; C; 1E67; # LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE -1E68; C; 1E69; # LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE -1E6A; C; 1E6B; # LATIN CAPITAL LETTER T WITH DOT ABOVE -1E6C; C; 1E6D; # LATIN CAPITAL LETTER T WITH DOT BELOW -1E6E; C; 1E6F; # LATIN CAPITAL LETTER T WITH LINE BELOW -1E70; C; 1E71; # LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW -1E72; C; 1E73; # LATIN CAPITAL LETTER U WITH DIAERESIS BELOW -1E74; C; 1E75; # LATIN CAPITAL LETTER U WITH TILDE BELOW -1E76; C; 1E77; # LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW -1E78; C; 1E79; # LATIN CAPITAL LETTER U WITH TILDE AND ACUTE -1E7A; C; 1E7B; # LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS -1E7C; C; 1E7D; # LATIN CAPITAL LETTER V WITH TILDE -1E7E; C; 1E7F; # LATIN CAPITAL LETTER V WITH DOT BELOW -1E80; C; 1E81; # LATIN CAPITAL LETTER W WITH GRAVE -1E82; C; 1E83; # LATIN CAPITAL LETTER W WITH ACUTE -1E84; C; 1E85; # LATIN CAPITAL LETTER W WITH DIAERESIS -1E86; C; 1E87; # LATIN CAPITAL LETTER W WITH DOT ABOVE -1E88; C; 1E89; # LATIN CAPITAL LETTER W WITH DOT BELOW -1E8A; C; 1E8B; # LATIN CAPITAL LETTER X WITH DOT ABOVE -1E8C; C; 1E8D; # LATIN CAPITAL LETTER X WITH DIAERESIS -1E8E; C; 1E8F; # LATIN CAPITAL LETTER Y WITH DOT ABOVE -1E90; C; 1E91; # LATIN CAPITAL LETTER Z WITH CIRCUMFLEX -1E92; C; 1E93; # LATIN CAPITAL LETTER Z WITH DOT BELOW -1E94; C; 1E95; # LATIN CAPITAL LETTER Z WITH LINE BELOW -1E96; F; 0068 0331; # LATIN SMALL LETTER H WITH LINE BELOW -1E97; F; 0074 0308; # LATIN SMALL LETTER T WITH DIAERESIS -1E98; F; 0077 030A; # LATIN SMALL LETTER W WITH RING ABOVE -1E99; F; 0079 030A; # LATIN SMALL LETTER Y WITH RING ABOVE -1E9A; F; 0061 02BE; # LATIN SMALL LETTER A WITH RIGHT HALF RING -1E9B; C; 1E61; # LATIN SMALL LETTER LONG S WITH DOT ABOVE -1E9E; F; 0073 0073; # LATIN CAPITAL LETTER SHARP S -1E9E; S; 00DF; # LATIN CAPITAL LETTER SHARP S -1EA0; C; 1EA1; # LATIN CAPITAL LETTER A WITH DOT BELOW -1EA2; C; 1EA3; # LATIN CAPITAL LETTER A WITH HOOK ABOVE -1EA4; C; 1EA5; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE -1EA6; C; 1EA7; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE -1EA8; C; 1EA9; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE -1EAA; C; 1EAB; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE -1EAC; C; 1EAD; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW -1EAE; C; 1EAF; # LATIN CAPITAL LETTER A WITH BREVE AND ACUTE -1EB0; C; 1EB1; # LATIN CAPITAL LETTER A WITH BREVE AND GRAVE -1EB2; C; 1EB3; # LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE -1EB4; C; 1EB5; # LATIN CAPITAL LETTER A WITH BREVE AND TILDE -1EB6; C; 1EB7; # LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW -1EB8; C; 1EB9; # LATIN CAPITAL LETTER E WITH DOT BELOW -1EBA; C; 1EBB; # LATIN CAPITAL LETTER E WITH HOOK ABOVE -1EBC; C; 1EBD; # LATIN CAPITAL LETTER E WITH TILDE -1EBE; C; 1EBF; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE -1EC0; C; 1EC1; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE -1EC2; C; 1EC3; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE -1EC4; C; 1EC5; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE -1EC6; C; 1EC7; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW -1EC8; C; 1EC9; # LATIN CAPITAL LETTER I WITH HOOK ABOVE -1ECA; C; 1ECB; # LATIN CAPITAL LETTER I WITH DOT BELOW -1ECC; C; 1ECD; # LATIN CAPITAL LETTER O WITH DOT BELOW -1ECE; C; 1ECF; # LATIN CAPITAL LETTER O WITH HOOK ABOVE -1ED0; C; 1ED1; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE -1ED2; C; 1ED3; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE -1ED4; C; 1ED5; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE -1ED6; C; 1ED7; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE -1ED8; C; 1ED9; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW -1EDA; C; 1EDB; # LATIN CAPITAL LETTER O WITH HORN AND ACUTE -1EDC; C; 1EDD; # LATIN CAPITAL LETTER O WITH HORN AND GRAVE -1EDE; C; 1EDF; # LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE -1EE0; C; 1EE1; # LATIN CAPITAL LETTER O WITH HORN AND TILDE -1EE2; C; 1EE3; # LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW -1EE4; C; 1EE5; # LATIN CAPITAL LETTER U WITH DOT BELOW -1EE6; C; 1EE7; # LATIN CAPITAL LETTER U WITH HOOK ABOVE -1EE8; C; 1EE9; # LATIN CAPITAL LETTER U WITH HORN AND ACUTE -1EEA; C; 1EEB; # LATIN CAPITAL LETTER U WITH HORN AND GRAVE -1EEC; C; 1EED; # LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE -1EEE; C; 1EEF; # LATIN CAPITAL LETTER U WITH HORN AND TILDE -1EF0; C; 1EF1; # LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW -1EF2; C; 1EF3; # LATIN CAPITAL LETTER Y WITH GRAVE -1EF4; C; 1EF5; # LATIN CAPITAL LETTER Y WITH DOT BELOW -1EF6; C; 1EF7; # LATIN CAPITAL LETTER Y WITH HOOK ABOVE -1EF8; C; 1EF9; # LATIN CAPITAL LETTER Y WITH TILDE -1EFA; C; 1EFB; # LATIN CAPITAL LETTER MIDDLE-WELSH LL -1EFC; C; 1EFD; # LATIN CAPITAL LETTER MIDDLE-WELSH V -1EFE; C; 1EFF; # LATIN CAPITAL LETTER Y WITH LOOP -1F08; C; 1F00; # GREEK CAPITAL LETTER ALPHA WITH PSILI -1F09; C; 1F01; # GREEK CAPITAL LETTER ALPHA WITH DASIA -1F0A; C; 1F02; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA -1F0B; C; 1F03; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA -1F0C; C; 1F04; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA -1F0D; C; 1F05; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA -1F0E; C; 1F06; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI -1F0F; C; 1F07; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI -1F18; C; 1F10; # GREEK CAPITAL LETTER EPSILON WITH PSILI -1F19; C; 1F11; # GREEK CAPITAL LETTER EPSILON WITH DASIA -1F1A; C; 1F12; # GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA -1F1B; C; 1F13; # GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA -1F1C; C; 1F14; # GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA -1F1D; C; 1F15; # GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA -1F28; C; 1F20; # GREEK CAPITAL LETTER ETA WITH PSILI -1F29; C; 1F21; # GREEK CAPITAL LETTER ETA WITH DASIA -1F2A; C; 1F22; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA -1F2B; C; 1F23; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA -1F2C; C; 1F24; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA -1F2D; C; 1F25; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA -1F2E; C; 1F26; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI -1F2F; C; 1F27; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI -1F38; C; 1F30; # GREEK CAPITAL LETTER IOTA WITH PSILI -1F39; C; 1F31; # GREEK CAPITAL LETTER IOTA WITH DASIA -1F3A; C; 1F32; # GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA -1F3B; C; 1F33; # GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA -1F3C; C; 1F34; # GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA -1F3D; C; 1F35; # GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA -1F3E; C; 1F36; # GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI -1F3F; C; 1F37; # GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI -1F48; C; 1F40; # GREEK CAPITAL LETTER OMICRON WITH PSILI -1F49; C; 1F41; # GREEK CAPITAL LETTER OMICRON WITH DASIA -1F4A; C; 1F42; # GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA -1F4B; C; 1F43; # GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA -1F4C; C; 1F44; # GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA -1F4D; C; 1F45; # GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA -1F50; F; 03C5 0313; # GREEK SMALL LETTER UPSILON WITH PSILI -1F52; F; 03C5 0313 0300; # GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA -1F54; F; 03C5 0313 0301; # GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA -1F56; F; 03C5 0313 0342; # GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI -1F59; C; 1F51; # GREEK CAPITAL LETTER UPSILON WITH DASIA -1F5B; C; 1F53; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA -1F5D; C; 1F55; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA -1F5F; C; 1F57; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI -1F68; C; 1F60; # GREEK CAPITAL LETTER OMEGA WITH PSILI -1F69; C; 1F61; # GREEK CAPITAL LETTER OMEGA WITH DASIA -1F6A; C; 1F62; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA -1F6B; C; 1F63; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA -1F6C; C; 1F64; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA -1F6D; C; 1F65; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA -1F6E; C; 1F66; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI -1F6F; C; 1F67; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI -1F80; F; 1F00 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI -1F81; F; 1F01 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI -1F82; F; 1F02 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI -1F83; F; 1F03 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI -1F84; F; 1F04 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI -1F85; F; 1F05 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI -1F86; F; 1F06 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI -1F87; F; 1F07 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI -1F88; F; 1F00 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI -1F88; S; 1F80; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI -1F89; F; 1F01 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI -1F89; S; 1F81; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI -1F8A; F; 1F02 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI -1F8A; S; 1F82; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI -1F8B; F; 1F03 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI -1F8B; S; 1F83; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI -1F8C; F; 1F04 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI -1F8C; S; 1F84; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI -1F8D; F; 1F05 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI -1F8D; S; 1F85; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI -1F8E; F; 1F06 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI -1F8E; S; 1F86; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI -1F8F; F; 1F07 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI -1F8F; S; 1F87; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI -1F90; F; 1F20 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI -1F91; F; 1F21 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI -1F92; F; 1F22 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI -1F93; F; 1F23 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI -1F94; F; 1F24 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI -1F95; F; 1F25 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI -1F96; F; 1F26 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI -1F97; F; 1F27 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI -1F98; F; 1F20 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI -1F98; S; 1F90; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI -1F99; F; 1F21 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI -1F99; S; 1F91; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI -1F9A; F; 1F22 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI -1F9A; S; 1F92; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI -1F9B; F; 1F23 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI -1F9B; S; 1F93; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI -1F9C; F; 1F24 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI -1F9C; S; 1F94; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI -1F9D; F; 1F25 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI -1F9D; S; 1F95; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI -1F9E; F; 1F26 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI -1F9E; S; 1F96; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI -1F9F; F; 1F27 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI -1F9F; S; 1F97; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI -1FA0; F; 1F60 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI -1FA1; F; 1F61 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI -1FA2; F; 1F62 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI -1FA3; F; 1F63 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI -1FA4; F; 1F64 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI -1FA5; F; 1F65 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI -1FA6; F; 1F66 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI -1FA7; F; 1F67 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI -1FA8; F; 1F60 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI -1FA8; S; 1FA0; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI -1FA9; F; 1F61 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI -1FA9; S; 1FA1; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI -1FAA; F; 1F62 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI -1FAA; S; 1FA2; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI -1FAB; F; 1F63 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI -1FAB; S; 1FA3; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI -1FAC; F; 1F64 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI -1FAC; S; 1FA4; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI -1FAD; F; 1F65 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI -1FAD; S; 1FA5; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI -1FAE; F; 1F66 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI -1FAE; S; 1FA6; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI -1FAF; F; 1F67 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI -1FAF; S; 1FA7; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI -1FB2; F; 1F70 03B9; # GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI -1FB3; F; 03B1 03B9; # GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI -1FB4; F; 03AC 03B9; # GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI -1FB6; F; 03B1 0342; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI -1FB7; F; 03B1 0342 03B9; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI -1FB8; C; 1FB0; # GREEK CAPITAL LETTER ALPHA WITH VRACHY -1FB9; C; 1FB1; # GREEK CAPITAL LETTER ALPHA WITH MACRON -1FBA; C; 1F70; # GREEK CAPITAL LETTER ALPHA WITH VARIA -1FBB; C; 1F71; # GREEK CAPITAL LETTER ALPHA WITH OXIA -1FBC; F; 03B1 03B9; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI -1FBC; S; 1FB3; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI -1FBE; C; 03B9; # GREEK PROSGEGRAMMENI -1FC2; F; 1F74 03B9; # GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI -1FC3; F; 03B7 03B9; # GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI -1FC4; F; 03AE 03B9; # GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI -1FC6; F; 03B7 0342; # GREEK SMALL LETTER ETA WITH PERISPOMENI -1FC7; F; 03B7 0342 03B9; # GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI -1FC8; C; 1F72; # GREEK CAPITAL LETTER EPSILON WITH VARIA -1FC9; C; 1F73; # GREEK CAPITAL LETTER EPSILON WITH OXIA -1FCA; C; 1F74; # GREEK CAPITAL LETTER ETA WITH VARIA -1FCB; C; 1F75; # GREEK CAPITAL LETTER ETA WITH OXIA -1FCC; F; 03B7 03B9; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI -1FCC; S; 1FC3; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI -1FD2; F; 03B9 0308 0300; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA -1FD3; F; 03B9 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA -1FD3; S; 0390; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA -1FD6; F; 03B9 0342; # GREEK SMALL LETTER IOTA WITH PERISPOMENI -1FD7; F; 03B9 0308 0342; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI -1FD8; C; 1FD0; # GREEK CAPITAL LETTER IOTA WITH VRACHY -1FD9; C; 1FD1; # GREEK CAPITAL LETTER IOTA WITH MACRON -1FDA; C; 1F76; # GREEK CAPITAL LETTER IOTA WITH VARIA -1FDB; C; 1F77; # GREEK CAPITAL LETTER IOTA WITH OXIA -1FE2; F; 03C5 0308 0300; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA -1FE3; F; 03C5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA -1FE3; S; 03B0; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA -1FE4; F; 03C1 0313; # GREEK SMALL LETTER RHO WITH PSILI -1FE6; F; 03C5 0342; # GREEK SMALL LETTER UPSILON WITH PERISPOMENI -1FE7; F; 03C5 0308 0342; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI -1FE8; C; 1FE0; # GREEK CAPITAL LETTER UPSILON WITH VRACHY -1FE9; C; 1FE1; # GREEK CAPITAL LETTER UPSILON WITH MACRON -1FEA; C; 1F7A; # GREEK CAPITAL LETTER UPSILON WITH VARIA -1FEB; C; 1F7B; # GREEK CAPITAL LETTER UPSILON WITH OXIA -1FEC; C; 1FE5; # GREEK CAPITAL LETTER RHO WITH DASIA -1FF2; F; 1F7C 03B9; # GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI -1FF3; F; 03C9 03B9; # GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI -1FF4; F; 03CE 03B9; # GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI -1FF6; F; 03C9 0342; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI -1FF7; F; 03C9 0342 03B9; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI -1FF8; C; 1F78; # GREEK CAPITAL LETTER OMICRON WITH VARIA -1FF9; C; 1F79; # GREEK CAPITAL LETTER OMICRON WITH OXIA -1FFA; C; 1F7C; # GREEK CAPITAL LETTER OMEGA WITH VARIA -1FFB; C; 1F7D; # GREEK CAPITAL LETTER OMEGA WITH OXIA -1FFC; F; 03C9 03B9; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI -1FFC; S; 1FF3; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI -2126; C; 03C9; # OHM SIGN -212A; C; 006B; # KELVIN SIGN -212B; C; 00E5; # ANGSTROM SIGN -2132; C; 214E; # TURNED CAPITAL F -2160; C; 2170; # ROMAN NUMERAL ONE -2161; C; 2171; # ROMAN NUMERAL TWO -2162; C; 2172; # ROMAN NUMERAL THREE -2163; C; 2173; # ROMAN NUMERAL FOUR -2164; C; 2174; # ROMAN NUMERAL FIVE -2165; C; 2175; # ROMAN NUMERAL SIX -2166; C; 2176; # ROMAN NUMERAL SEVEN -2167; C; 2177; # ROMAN NUMERAL EIGHT -2168; C; 2178; # ROMAN NUMERAL NINE -2169; C; 2179; # ROMAN NUMERAL TEN -216A; C; 217A; # ROMAN NUMERAL ELEVEN -216B; C; 217B; # ROMAN NUMERAL TWELVE -216C; C; 217C; # ROMAN NUMERAL FIFTY -216D; C; 217D; # ROMAN NUMERAL ONE HUNDRED -216E; C; 217E; # ROMAN NUMERAL FIVE HUNDRED -216F; C; 217F; # ROMAN NUMERAL ONE THOUSAND -2183; C; 2184; # ROMAN NUMERAL REVERSED ONE HUNDRED -24B6; C; 24D0; # CIRCLED LATIN CAPITAL LETTER A -24B7; C; 24D1; # CIRCLED LATIN CAPITAL LETTER B -24B8; C; 24D2; # CIRCLED LATIN CAPITAL LETTER C -24B9; C; 24D3; # CIRCLED LATIN CAPITAL LETTER D -24BA; C; 24D4; # CIRCLED LATIN CAPITAL LETTER E -24BB; C; 24D5; # CIRCLED LATIN CAPITAL LETTER F -24BC; C; 24D6; # CIRCLED LATIN CAPITAL LETTER G -24BD; C; 24D7; # CIRCLED LATIN CAPITAL LETTER H -24BE; C; 24D8; # CIRCLED LATIN CAPITAL LETTER I -24BF; C; 24D9; # CIRCLED LATIN CAPITAL LETTER J -24C0; C; 24DA; # CIRCLED LATIN CAPITAL LETTER K -24C1; C; 24DB; # CIRCLED LATIN CAPITAL LETTER L -24C2; C; 24DC; # CIRCLED LATIN CAPITAL LETTER M -24C3; C; 24DD; # CIRCLED LATIN CAPITAL LETTER N -24C4; C; 24DE; # CIRCLED LATIN CAPITAL LETTER O -24C5; C; 24DF; # CIRCLED LATIN CAPITAL LETTER P -24C6; C; 24E0; # CIRCLED LATIN CAPITAL LETTER Q -24C7; C; 24E1; # CIRCLED LATIN CAPITAL LETTER R -24C8; C; 24E2; # CIRCLED LATIN CAPITAL LETTER S -24C9; C; 24E3; # CIRCLED LATIN CAPITAL LETTER T -24CA; C; 24E4; # CIRCLED LATIN CAPITAL LETTER U -24CB; C; 24E5; # CIRCLED LATIN CAPITAL LETTER V -24CC; C; 24E6; # CIRCLED LATIN CAPITAL LETTER W -24CD; C; 24E7; # CIRCLED LATIN CAPITAL LETTER X -24CE; C; 24E8; # CIRCLED LATIN CAPITAL LETTER Y -24CF; C; 24E9; # CIRCLED LATIN CAPITAL LETTER Z -2C00; C; 2C30; # GLAGOLITIC CAPITAL LETTER AZU -2C01; C; 2C31; # GLAGOLITIC CAPITAL LETTER BUKY -2C02; C; 2C32; # GLAGOLITIC CAPITAL LETTER VEDE -2C03; C; 2C33; # GLAGOLITIC CAPITAL LETTER GLAGOLI -2C04; C; 2C34; # GLAGOLITIC CAPITAL LETTER DOBRO -2C05; C; 2C35; # GLAGOLITIC CAPITAL LETTER YESTU -2C06; C; 2C36; # GLAGOLITIC CAPITAL LETTER ZHIVETE -2C07; C; 2C37; # GLAGOLITIC CAPITAL LETTER DZELO -2C08; C; 2C38; # GLAGOLITIC CAPITAL LETTER ZEMLJA -2C09; C; 2C39; # GLAGOLITIC CAPITAL LETTER IZHE -2C0A; C; 2C3A; # GLAGOLITIC CAPITAL LETTER INITIAL IZHE -2C0B; C; 2C3B; # GLAGOLITIC CAPITAL LETTER I -2C0C; C; 2C3C; # GLAGOLITIC CAPITAL LETTER DJERVI -2C0D; C; 2C3D; # GLAGOLITIC CAPITAL LETTER KAKO -2C0E; C; 2C3E; # GLAGOLITIC CAPITAL LETTER LJUDIJE -2C0F; C; 2C3F; # GLAGOLITIC CAPITAL LETTER MYSLITE -2C10; C; 2C40; # GLAGOLITIC CAPITAL LETTER NASHI -2C11; C; 2C41; # GLAGOLITIC CAPITAL LETTER ONU -2C12; C; 2C42; # GLAGOLITIC CAPITAL LETTER POKOJI -2C13; C; 2C43; # GLAGOLITIC CAPITAL LETTER RITSI -2C14; C; 2C44; # GLAGOLITIC CAPITAL LETTER SLOVO -2C15; C; 2C45; # GLAGOLITIC CAPITAL LETTER TVRIDO -2C16; C; 2C46; # GLAGOLITIC CAPITAL LETTER UKU -2C17; C; 2C47; # GLAGOLITIC CAPITAL LETTER FRITU -2C18; C; 2C48; # GLAGOLITIC CAPITAL LETTER HERU -2C19; C; 2C49; # GLAGOLITIC CAPITAL LETTER OTU -2C1A; C; 2C4A; # GLAGOLITIC CAPITAL LETTER PE -2C1B; C; 2C4B; # GLAGOLITIC CAPITAL LETTER SHTA -2C1C; C; 2C4C; # GLAGOLITIC CAPITAL LETTER TSI -2C1D; C; 2C4D; # GLAGOLITIC CAPITAL LETTER CHRIVI -2C1E; C; 2C4E; # GLAGOLITIC CAPITAL LETTER SHA -2C1F; C; 2C4F; # GLAGOLITIC CAPITAL LETTER YERU -2C20; C; 2C50; # GLAGOLITIC CAPITAL LETTER YERI -2C21; C; 2C51; # GLAGOLITIC CAPITAL LETTER YATI -2C22; C; 2C52; # GLAGOLITIC CAPITAL LETTER SPIDERY HA -2C23; C; 2C53; # GLAGOLITIC CAPITAL LETTER YU -2C24; C; 2C54; # GLAGOLITIC CAPITAL LETTER SMALL YUS -2C25; C; 2C55; # GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL -2C26; C; 2C56; # GLAGOLITIC CAPITAL LETTER YO -2C27; C; 2C57; # GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS -2C28; C; 2C58; # GLAGOLITIC CAPITAL LETTER BIG YUS -2C29; C; 2C59; # GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS -2C2A; C; 2C5A; # GLAGOLITIC CAPITAL LETTER FITA -2C2B; C; 2C5B; # GLAGOLITIC CAPITAL LETTER IZHITSA -2C2C; C; 2C5C; # GLAGOLITIC CAPITAL LETTER SHTAPIC -2C2D; C; 2C5D; # GLAGOLITIC CAPITAL LETTER TROKUTASTI A -2C2E; C; 2C5E; # GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE -2C2F; C; 2C5F; # GLAGOLITIC CAPITAL LETTER CAUDATE CHRIVI -2C60; C; 2C61; # LATIN CAPITAL LETTER L WITH DOUBLE BAR -2C62; C; 026B; # LATIN CAPITAL LETTER L WITH MIDDLE TILDE -2C63; C; 1D7D; # LATIN CAPITAL LETTER P WITH STROKE -2C64; C; 027D; # LATIN CAPITAL LETTER R WITH TAIL -2C67; C; 2C68; # LATIN CAPITAL LETTER H WITH DESCENDER -2C69; C; 2C6A; # LATIN CAPITAL LETTER K WITH DESCENDER -2C6B; C; 2C6C; # LATIN CAPITAL LETTER Z WITH DESCENDER -2C6D; C; 0251; # LATIN CAPITAL LETTER ALPHA -2C6E; C; 0271; # LATIN CAPITAL LETTER M WITH HOOK -2C6F; C; 0250; # LATIN CAPITAL LETTER TURNED A -2C70; C; 0252; # LATIN CAPITAL LETTER TURNED ALPHA -2C72; C; 2C73; # LATIN CAPITAL LETTER W WITH HOOK -2C75; C; 2C76; # LATIN CAPITAL LETTER HALF H -2C7E; C; 023F; # LATIN CAPITAL LETTER S WITH SWASH TAIL -2C7F; C; 0240; # LATIN CAPITAL LETTER Z WITH SWASH TAIL -2C80; C; 2C81; # COPTIC CAPITAL LETTER ALFA -2C82; C; 2C83; # COPTIC CAPITAL LETTER VIDA -2C84; C; 2C85; # COPTIC CAPITAL LETTER GAMMA -2C86; C; 2C87; # COPTIC CAPITAL LETTER DALDA -2C88; C; 2C89; # COPTIC CAPITAL LETTER EIE -2C8A; C; 2C8B; # COPTIC CAPITAL LETTER SOU -2C8C; C; 2C8D; # COPTIC CAPITAL LETTER ZATA -2C8E; C; 2C8F; # COPTIC CAPITAL LETTER HATE -2C90; C; 2C91; # COPTIC CAPITAL LETTER THETHE -2C92; C; 2C93; # COPTIC CAPITAL LETTER IAUDA -2C94; C; 2C95; # COPTIC CAPITAL LETTER KAPA -2C96; C; 2C97; # COPTIC CAPITAL LETTER LAULA -2C98; C; 2C99; # COPTIC CAPITAL LETTER MI -2C9A; C; 2C9B; # COPTIC CAPITAL LETTER NI -2C9C; C; 2C9D; # COPTIC CAPITAL LETTER KSI -2C9E; C; 2C9F; # COPTIC CAPITAL LETTER O -2CA0; C; 2CA1; # COPTIC CAPITAL LETTER PI -2CA2; C; 2CA3; # COPTIC CAPITAL LETTER RO -2CA4; C; 2CA5; # COPTIC CAPITAL LETTER SIMA -2CA6; C; 2CA7; # COPTIC CAPITAL LETTER TAU -2CA8; C; 2CA9; # COPTIC CAPITAL LETTER UA -2CAA; C; 2CAB; # COPTIC CAPITAL LETTER FI -2CAC; C; 2CAD; # COPTIC CAPITAL LETTER KHI -2CAE; C; 2CAF; # COPTIC CAPITAL LETTER PSI -2CB0; C; 2CB1; # COPTIC CAPITAL LETTER OOU -2CB2; C; 2CB3; # COPTIC CAPITAL LETTER DIALECT-P ALEF -2CB4; C; 2CB5; # COPTIC CAPITAL LETTER OLD COPTIC AIN -2CB6; C; 2CB7; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE -2CB8; C; 2CB9; # COPTIC CAPITAL LETTER DIALECT-P KAPA -2CBA; C; 2CBB; # COPTIC CAPITAL LETTER DIALECT-P NI -2CBC; C; 2CBD; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI -2CBE; C; 2CBF; # COPTIC CAPITAL LETTER OLD COPTIC OOU -2CC0; C; 2CC1; # COPTIC CAPITAL LETTER SAMPI -2CC2; C; 2CC3; # COPTIC CAPITAL LETTER CROSSED SHEI -2CC4; C; 2CC5; # COPTIC CAPITAL LETTER OLD COPTIC SHEI -2CC6; C; 2CC7; # COPTIC CAPITAL LETTER OLD COPTIC ESH -2CC8; C; 2CC9; # COPTIC CAPITAL LETTER AKHMIMIC KHEI -2CCA; C; 2CCB; # COPTIC CAPITAL LETTER DIALECT-P HORI -2CCC; C; 2CCD; # COPTIC CAPITAL LETTER OLD COPTIC HORI -2CCE; C; 2CCF; # COPTIC CAPITAL LETTER OLD COPTIC HA -2CD0; C; 2CD1; # COPTIC CAPITAL LETTER L-SHAPED HA -2CD2; C; 2CD3; # COPTIC CAPITAL LETTER OLD COPTIC HEI -2CD4; C; 2CD5; # COPTIC CAPITAL LETTER OLD COPTIC HAT -2CD6; C; 2CD7; # COPTIC CAPITAL LETTER OLD COPTIC GANGIA -2CD8; C; 2CD9; # COPTIC CAPITAL LETTER OLD COPTIC DJA -2CDA; C; 2CDB; # COPTIC CAPITAL LETTER OLD COPTIC SHIMA -2CDC; C; 2CDD; # COPTIC CAPITAL LETTER OLD NUBIAN SHIMA -2CDE; C; 2CDF; # COPTIC CAPITAL LETTER OLD NUBIAN NGI -2CE0; C; 2CE1; # COPTIC CAPITAL LETTER OLD NUBIAN NYI -2CE2; C; 2CE3; # COPTIC CAPITAL LETTER OLD NUBIAN WAU -2CEB; C; 2CEC; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI -2CED; C; 2CEE; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA -2CF2; C; 2CF3; # COPTIC CAPITAL LETTER BOHAIRIC KHEI -A640; C; A641; # CYRILLIC CAPITAL LETTER ZEMLYA -A642; C; A643; # CYRILLIC CAPITAL LETTER DZELO -A644; C; A645; # CYRILLIC CAPITAL LETTER REVERSED DZE -A646; C; A647; # CYRILLIC CAPITAL LETTER IOTA -A648; C; A649; # CYRILLIC CAPITAL LETTER DJERV -A64A; C; A64B; # CYRILLIC CAPITAL LETTER MONOGRAPH UK -A64C; C; A64D; # CYRILLIC CAPITAL LETTER BROAD OMEGA -A64E; C; A64F; # CYRILLIC CAPITAL LETTER NEUTRAL YER -A650; C; A651; # CYRILLIC CAPITAL LETTER YERU WITH BACK YER -A652; C; A653; # CYRILLIC CAPITAL LETTER IOTIFIED YAT -A654; C; A655; # CYRILLIC CAPITAL LETTER REVERSED YU -A656; C; A657; # CYRILLIC CAPITAL LETTER IOTIFIED A -A658; C; A659; # CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS -A65A; C; A65B; # CYRILLIC CAPITAL LETTER BLENDED YUS -A65C; C; A65D; # CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS -A65E; C; A65F; # CYRILLIC CAPITAL LETTER YN -A660; C; A661; # CYRILLIC CAPITAL LETTER REVERSED TSE -A662; C; A663; # CYRILLIC CAPITAL LETTER SOFT DE -A664; C; A665; # CYRILLIC CAPITAL LETTER SOFT EL -A666; C; A667; # CYRILLIC CAPITAL LETTER SOFT EM -A668; C; A669; # CYRILLIC CAPITAL LETTER MONOCULAR O -A66A; C; A66B; # CYRILLIC CAPITAL LETTER BINOCULAR O -A66C; C; A66D; # CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O -A680; C; A681; # CYRILLIC CAPITAL LETTER DWE -A682; C; A683; # CYRILLIC CAPITAL LETTER DZWE -A684; C; A685; # CYRILLIC CAPITAL LETTER ZHWE -A686; C; A687; # CYRILLIC CAPITAL LETTER CCHE -A688; C; A689; # CYRILLIC CAPITAL LETTER DZZE -A68A; C; A68B; # CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK -A68C; C; A68D; # CYRILLIC CAPITAL LETTER TWE -A68E; C; A68F; # CYRILLIC CAPITAL LETTER TSWE -A690; C; A691; # CYRILLIC CAPITAL LETTER TSSE -A692; C; A693; # CYRILLIC CAPITAL LETTER TCHE -A694; C; A695; # CYRILLIC CAPITAL LETTER HWE -A696; C; A697; # CYRILLIC CAPITAL LETTER SHWE -A698; C; A699; # CYRILLIC CAPITAL LETTER DOUBLE O -A69A; C; A69B; # CYRILLIC CAPITAL LETTER CROSSED O -A722; C; A723; # LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF -A724; C; A725; # LATIN CAPITAL LETTER EGYPTOLOGICAL AIN -A726; C; A727; # LATIN CAPITAL LETTER HENG -A728; C; A729; # LATIN CAPITAL LETTER TZ -A72A; C; A72B; # LATIN CAPITAL LETTER TRESILLO -A72C; C; A72D; # LATIN CAPITAL LETTER CUATRILLO -A72E; C; A72F; # LATIN CAPITAL LETTER CUATRILLO WITH COMMA -A732; C; A733; # LATIN CAPITAL LETTER AA -A734; C; A735; # LATIN CAPITAL LETTER AO -A736; C; A737; # LATIN CAPITAL LETTER AU -A738; C; A739; # LATIN CAPITAL LETTER AV -A73A; C; A73B; # LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR -A73C; C; A73D; # LATIN CAPITAL LETTER AY -A73E; C; A73F; # LATIN CAPITAL LETTER REVERSED C WITH DOT -A740; C; A741; # LATIN CAPITAL LETTER K WITH STROKE -A742; C; A743; # LATIN CAPITAL LETTER K WITH DIAGONAL STROKE -A744; C; A745; # LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE -A746; C; A747; # LATIN CAPITAL LETTER BROKEN L -A748; C; A749; # LATIN CAPITAL LETTER L WITH HIGH STROKE -A74A; C; A74B; # LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY -A74C; C; A74D; # LATIN CAPITAL LETTER O WITH LOOP -A74E; C; A74F; # LATIN CAPITAL LETTER OO -A750; C; A751; # LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER -A752; C; A753; # LATIN CAPITAL LETTER P WITH FLOURISH -A754; C; A755; # LATIN CAPITAL LETTER P WITH SQUIRREL TAIL -A756; C; A757; # LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER -A758; C; A759; # LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE -A75A; C; A75B; # LATIN CAPITAL LETTER R ROTUNDA -A75C; C; A75D; # LATIN CAPITAL LETTER RUM ROTUNDA -A75E; C; A75F; # LATIN CAPITAL LETTER V WITH DIAGONAL STROKE -A760; C; A761; # LATIN CAPITAL LETTER VY -A762; C; A763; # LATIN CAPITAL LETTER VISIGOTHIC Z -A764; C; A765; # LATIN CAPITAL LETTER THORN WITH STROKE -A766; C; A767; # LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER -A768; C; A769; # LATIN CAPITAL LETTER VEND -A76A; C; A76B; # LATIN CAPITAL LETTER ET -A76C; C; A76D; # LATIN CAPITAL LETTER IS -A76E; C; A76F; # LATIN CAPITAL LETTER CON -A779; C; A77A; # LATIN CAPITAL LETTER INSULAR D -A77B; C; A77C; # LATIN CAPITAL LETTER INSULAR F -A77D; C; 1D79; # LATIN CAPITAL LETTER INSULAR G -A77E; C; A77F; # LATIN CAPITAL LETTER TURNED INSULAR G -A780; C; A781; # LATIN CAPITAL LETTER TURNED L -A782; C; A783; # LATIN CAPITAL LETTER INSULAR R -A784; C; A785; # LATIN CAPITAL LETTER INSULAR S -A786; C; A787; # LATIN CAPITAL LETTER INSULAR T -A78B; C; A78C; # LATIN CAPITAL LETTER SALTILLO -A78D; C; 0265; # LATIN CAPITAL LETTER TURNED H -A790; C; A791; # LATIN CAPITAL LETTER N WITH DESCENDER -A792; C; A793; # LATIN CAPITAL LETTER C WITH BAR -A796; C; A797; # LATIN CAPITAL LETTER B WITH FLOURISH -A798; C; A799; # LATIN CAPITAL LETTER F WITH STROKE -A79A; C; A79B; # LATIN CAPITAL LETTER VOLAPUK AE -A79C; C; A79D; # LATIN CAPITAL LETTER VOLAPUK OE -A79E; C; A79F; # LATIN CAPITAL LETTER VOLAPUK UE -A7A0; C; A7A1; # LATIN CAPITAL LETTER G WITH OBLIQUE STROKE -A7A2; C; A7A3; # LATIN CAPITAL LETTER K WITH OBLIQUE STROKE -A7A4; C; A7A5; # LATIN CAPITAL LETTER N WITH OBLIQUE STROKE -A7A6; C; A7A7; # LATIN CAPITAL LETTER R WITH OBLIQUE STROKE -A7A8; C; A7A9; # LATIN CAPITAL LETTER S WITH OBLIQUE STROKE -A7AA; C; 0266; # LATIN CAPITAL LETTER H WITH HOOK -A7AB; C; 025C; # LATIN CAPITAL LETTER REVERSED OPEN E -A7AC; C; 0261; # LATIN CAPITAL LETTER SCRIPT G -A7AD; C; 026C; # LATIN CAPITAL LETTER L WITH BELT -A7AE; C; 026A; # LATIN CAPITAL LETTER SMALL CAPITAL I -A7B0; C; 029E; # LATIN CAPITAL LETTER TURNED K -A7B1; C; 0287; # LATIN CAPITAL LETTER TURNED T -A7B2; C; 029D; # LATIN CAPITAL LETTER J WITH CROSSED-TAIL -A7B3; C; AB53; # LATIN CAPITAL LETTER CHI -A7B4; C; A7B5; # LATIN CAPITAL LETTER BETA -A7B6; C; A7B7; # LATIN CAPITAL LETTER OMEGA -A7B8; C; A7B9; # LATIN CAPITAL LETTER U WITH STROKE -A7BA; C; A7BB; # LATIN CAPITAL LETTER GLOTTAL A -A7BC; C; A7BD; # LATIN CAPITAL LETTER GLOTTAL I -A7BE; C; A7BF; # LATIN CAPITAL LETTER GLOTTAL U -A7C0; C; A7C1; # LATIN CAPITAL LETTER OLD POLISH O -A7C2; C; A7C3; # LATIN CAPITAL LETTER ANGLICANA W -A7C4; C; A794; # LATIN CAPITAL LETTER C WITH PALATAL HOOK -A7C5; C; 0282; # LATIN CAPITAL LETTER S WITH HOOK -A7C6; C; 1D8E; # LATIN CAPITAL LETTER Z WITH PALATAL HOOK -A7C7; C; A7C8; # LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY -A7C9; C; A7CA; # LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY -A7D0; C; A7D1; # LATIN CAPITAL LETTER CLOSED INSULAR G -A7D6; C; A7D7; # LATIN CAPITAL LETTER MIDDLE SCOTS S -A7D8; C; A7D9; # LATIN CAPITAL LETTER SIGMOID S -A7F5; C; A7F6; # LATIN CAPITAL LETTER REVERSED HALF H -AB70; C; 13A0; # CHEROKEE SMALL LETTER A -AB71; C; 13A1; # CHEROKEE SMALL LETTER E -AB72; C; 13A2; # CHEROKEE SMALL LETTER I -AB73; C; 13A3; # CHEROKEE SMALL LETTER O -AB74; C; 13A4; # CHEROKEE SMALL LETTER U -AB75; C; 13A5; # CHEROKEE SMALL LETTER V -AB76; C; 13A6; # CHEROKEE SMALL LETTER GA -AB77; C; 13A7; # CHEROKEE SMALL LETTER KA -AB78; C; 13A8; # CHEROKEE SMALL LETTER GE -AB79; C; 13A9; # CHEROKEE SMALL LETTER GI -AB7A; C; 13AA; # CHEROKEE SMALL LETTER GO -AB7B; C; 13AB; # CHEROKEE SMALL LETTER GU -AB7C; C; 13AC; # CHEROKEE SMALL LETTER GV -AB7D; C; 13AD; # CHEROKEE SMALL LETTER HA -AB7E; C; 13AE; # CHEROKEE SMALL LETTER HE -AB7F; C; 13AF; # CHEROKEE SMALL LETTER HI -AB80; C; 13B0; # CHEROKEE SMALL LETTER HO -AB81; C; 13B1; # CHEROKEE SMALL LETTER HU -AB82; C; 13B2; # CHEROKEE SMALL LETTER HV -AB83; C; 13B3; # CHEROKEE SMALL LETTER LA -AB84; C; 13B4; # CHEROKEE SMALL LETTER LE -AB85; C; 13B5; # CHEROKEE SMALL LETTER LI -AB86; C; 13B6; # CHEROKEE SMALL LETTER LO -AB87; C; 13B7; # CHEROKEE SMALL LETTER LU -AB88; C; 13B8; # CHEROKEE SMALL LETTER LV -AB89; C; 13B9; # CHEROKEE SMALL LETTER MA -AB8A; C; 13BA; # CHEROKEE SMALL LETTER ME -AB8B; C; 13BB; # CHEROKEE SMALL LETTER MI -AB8C; C; 13BC; # CHEROKEE SMALL LETTER MO -AB8D; C; 13BD; # CHEROKEE SMALL LETTER MU -AB8E; C; 13BE; # CHEROKEE SMALL LETTER NA -AB8F; C; 13BF; # CHEROKEE SMALL LETTER HNA -AB90; C; 13C0; # CHEROKEE SMALL LETTER NAH -AB91; C; 13C1; # CHEROKEE SMALL LETTER NE -AB92; C; 13C2; # CHEROKEE SMALL LETTER NI -AB93; C; 13C3; # CHEROKEE SMALL LETTER NO -AB94; C; 13C4; # CHEROKEE SMALL LETTER NU -AB95; C; 13C5; # CHEROKEE SMALL LETTER NV -AB96; C; 13C6; # CHEROKEE SMALL LETTER QUA -AB97; C; 13C7; # CHEROKEE SMALL LETTER QUE -AB98; C; 13C8; # CHEROKEE SMALL LETTER QUI -AB99; C; 13C9; # CHEROKEE SMALL LETTER QUO -AB9A; C; 13CA; # CHEROKEE SMALL LETTER QUU -AB9B; C; 13CB; # CHEROKEE SMALL LETTER QUV -AB9C; C; 13CC; # CHEROKEE SMALL LETTER SA -AB9D; C; 13CD; # CHEROKEE SMALL LETTER S -AB9E; C; 13CE; # CHEROKEE SMALL LETTER SE -AB9F; C; 13CF; # CHEROKEE SMALL LETTER SI -ABA0; C; 13D0; # CHEROKEE SMALL LETTER SO -ABA1; C; 13D1; # CHEROKEE SMALL LETTER SU -ABA2; C; 13D2; # CHEROKEE SMALL LETTER SV -ABA3; C; 13D3; # CHEROKEE SMALL LETTER DA -ABA4; C; 13D4; # CHEROKEE SMALL LETTER TA -ABA5; C; 13D5; # CHEROKEE SMALL LETTER DE -ABA6; C; 13D6; # CHEROKEE SMALL LETTER TE -ABA7; C; 13D7; # CHEROKEE SMALL LETTER DI -ABA8; C; 13D8; # CHEROKEE SMALL LETTER TI -ABA9; C; 13D9; # CHEROKEE SMALL LETTER DO -ABAA; C; 13DA; # CHEROKEE SMALL LETTER DU -ABAB; C; 13DB; # CHEROKEE SMALL LETTER DV -ABAC; C; 13DC; # CHEROKEE SMALL LETTER DLA -ABAD; C; 13DD; # CHEROKEE SMALL LETTER TLA -ABAE; C; 13DE; # CHEROKEE SMALL LETTER TLE -ABAF; C; 13DF; # CHEROKEE SMALL LETTER TLI -ABB0; C; 13E0; # CHEROKEE SMALL LETTER TLO -ABB1; C; 13E1; # CHEROKEE SMALL LETTER TLU -ABB2; C; 13E2; # CHEROKEE SMALL LETTER TLV -ABB3; C; 13E3; # CHEROKEE SMALL LETTER TSA -ABB4; C; 13E4; # CHEROKEE SMALL LETTER TSE -ABB5; C; 13E5; # CHEROKEE SMALL LETTER TSI -ABB6; C; 13E6; # CHEROKEE SMALL LETTER TSO -ABB7; C; 13E7; # CHEROKEE SMALL LETTER TSU -ABB8; C; 13E8; # CHEROKEE SMALL LETTER TSV -ABB9; C; 13E9; # CHEROKEE SMALL LETTER WA -ABBA; C; 13EA; # CHEROKEE SMALL LETTER WE -ABBB; C; 13EB; # CHEROKEE SMALL LETTER WI -ABBC; C; 13EC; # CHEROKEE SMALL LETTER WO -ABBD; C; 13ED; # CHEROKEE SMALL LETTER WU -ABBE; C; 13EE; # CHEROKEE SMALL LETTER WV -ABBF; C; 13EF; # CHEROKEE SMALL LETTER YA -FB00; F; 0066 0066; # LATIN SMALL LIGATURE FF -FB01; F; 0066 0069; # LATIN SMALL LIGATURE FI -FB02; F; 0066 006C; # LATIN SMALL LIGATURE FL -FB03; F; 0066 0066 0069; # LATIN SMALL LIGATURE FFI -FB04; F; 0066 0066 006C; # LATIN SMALL LIGATURE FFL -FB05; F; 0073 0074; # LATIN SMALL LIGATURE LONG S T -FB05; S; FB06; # LATIN SMALL LIGATURE LONG S T -FB06; F; 0073 0074; # LATIN SMALL LIGATURE ST -FB13; F; 0574 0576; # ARMENIAN SMALL LIGATURE MEN NOW -FB14; F; 0574 0565; # ARMENIAN SMALL LIGATURE MEN ECH -FB15; F; 0574 056B; # ARMENIAN SMALL LIGATURE MEN INI -FB16; F; 057E 0576; # ARMENIAN SMALL LIGATURE VEW NOW -FB17; F; 0574 056D; # ARMENIAN SMALL LIGATURE MEN XEH -FF21; C; FF41; # FULLWIDTH LATIN CAPITAL LETTER A -FF22; C; FF42; # FULLWIDTH LATIN CAPITAL LETTER B -FF23; C; FF43; # FULLWIDTH LATIN CAPITAL LETTER C -FF24; C; FF44; # FULLWIDTH LATIN CAPITAL LETTER D -FF25; C; FF45; # FULLWIDTH LATIN CAPITAL LETTER E -FF26; C; FF46; # FULLWIDTH LATIN CAPITAL LETTER F -FF27; C; FF47; # FULLWIDTH LATIN CAPITAL LETTER G -FF28; C; FF48; # FULLWIDTH LATIN CAPITAL LETTER H -FF29; C; FF49; # FULLWIDTH LATIN CAPITAL LETTER I -FF2A; C; FF4A; # FULLWIDTH LATIN CAPITAL LETTER J -FF2B; C; FF4B; # FULLWIDTH LATIN CAPITAL LETTER K -FF2C; C; FF4C; # FULLWIDTH LATIN CAPITAL LETTER L -FF2D; C; FF4D; # FULLWIDTH LATIN CAPITAL LETTER M -FF2E; C; FF4E; # FULLWIDTH LATIN CAPITAL LETTER N -FF2F; C; FF4F; # FULLWIDTH LATIN CAPITAL LETTER O -FF30; C; FF50; # FULLWIDTH LATIN CAPITAL LETTER P -FF31; C; FF51; # FULLWIDTH LATIN CAPITAL LETTER Q -FF32; C; FF52; # FULLWIDTH LATIN CAPITAL LETTER R -FF33; C; FF53; # FULLWIDTH LATIN CAPITAL LETTER S -FF34; C; FF54; # FULLWIDTH LATIN CAPITAL LETTER T -FF35; C; FF55; # FULLWIDTH LATIN CAPITAL LETTER U -FF36; C; FF56; # FULLWIDTH LATIN CAPITAL LETTER V -FF37; C; FF57; # FULLWIDTH LATIN CAPITAL LETTER W -FF38; C; FF58; # FULLWIDTH LATIN CAPITAL LETTER X -FF39; C; FF59; # FULLWIDTH LATIN CAPITAL LETTER Y -FF3A; C; FF5A; # FULLWIDTH LATIN CAPITAL LETTER Z -10400; C; 10428; # DESERET CAPITAL LETTER LONG I -10401; C; 10429; # DESERET CAPITAL LETTER LONG E -10402; C; 1042A; # DESERET CAPITAL LETTER LONG A -10403; C; 1042B; # DESERET CAPITAL LETTER LONG AH -10404; C; 1042C; # DESERET CAPITAL LETTER LONG O -10405; C; 1042D; # DESERET CAPITAL LETTER LONG OO -10406; C; 1042E; # DESERET CAPITAL LETTER SHORT I -10407; C; 1042F; # DESERET CAPITAL LETTER SHORT E -10408; C; 10430; # DESERET CAPITAL LETTER SHORT A -10409; C; 10431; # DESERET CAPITAL LETTER SHORT AH -1040A; C; 10432; # DESERET CAPITAL LETTER SHORT O -1040B; C; 10433; # DESERET CAPITAL LETTER SHORT OO -1040C; C; 10434; # DESERET CAPITAL LETTER AY -1040D; C; 10435; # DESERET CAPITAL LETTER OW -1040E; C; 10436; # DESERET CAPITAL LETTER WU -1040F; C; 10437; # DESERET CAPITAL LETTER YEE -10410; C; 10438; # DESERET CAPITAL LETTER H -10411; C; 10439; # DESERET CAPITAL LETTER PEE -10412; C; 1043A; # DESERET CAPITAL LETTER BEE -10413; C; 1043B; # DESERET CAPITAL LETTER TEE -10414; C; 1043C; # DESERET CAPITAL LETTER DEE -10415; C; 1043D; # DESERET CAPITAL LETTER CHEE -10416; C; 1043E; # DESERET CAPITAL LETTER JEE -10417; C; 1043F; # DESERET CAPITAL LETTER KAY -10418; C; 10440; # DESERET CAPITAL LETTER GAY -10419; C; 10441; # DESERET CAPITAL LETTER EF -1041A; C; 10442; # DESERET CAPITAL LETTER VEE -1041B; C; 10443; # DESERET CAPITAL LETTER ETH -1041C; C; 10444; # DESERET CAPITAL LETTER THEE -1041D; C; 10445; # DESERET CAPITAL LETTER ES -1041E; C; 10446; # DESERET CAPITAL LETTER ZEE -1041F; C; 10447; # DESERET CAPITAL LETTER ESH -10420; C; 10448; # DESERET CAPITAL LETTER ZHEE -10421; C; 10449; # DESERET CAPITAL LETTER ER -10422; C; 1044A; # DESERET CAPITAL LETTER EL -10423; C; 1044B; # DESERET CAPITAL LETTER EM -10424; C; 1044C; # DESERET CAPITAL LETTER EN -10425; C; 1044D; # DESERET CAPITAL LETTER ENG -10426; C; 1044E; # DESERET CAPITAL LETTER OI -10427; C; 1044F; # DESERET CAPITAL LETTER EW -104B0; C; 104D8; # OSAGE CAPITAL LETTER A -104B1; C; 104D9; # OSAGE CAPITAL LETTER AI -104B2; C; 104DA; # OSAGE CAPITAL LETTER AIN -104B3; C; 104DB; # OSAGE CAPITAL LETTER AH -104B4; C; 104DC; # OSAGE CAPITAL LETTER BRA -104B5; C; 104DD; # OSAGE CAPITAL LETTER CHA -104B6; C; 104DE; # OSAGE CAPITAL LETTER EHCHA -104B7; C; 104DF; # OSAGE CAPITAL LETTER E -104B8; C; 104E0; # OSAGE CAPITAL LETTER EIN -104B9; C; 104E1; # OSAGE CAPITAL LETTER HA -104BA; C; 104E2; # OSAGE CAPITAL LETTER HYA -104BB; C; 104E3; # OSAGE CAPITAL LETTER I -104BC; C; 104E4; # OSAGE CAPITAL LETTER KA -104BD; C; 104E5; # OSAGE CAPITAL LETTER EHKA -104BE; C; 104E6; # OSAGE CAPITAL LETTER KYA -104BF; C; 104E7; # OSAGE CAPITAL LETTER LA -104C0; C; 104E8; # OSAGE CAPITAL LETTER MA -104C1; C; 104E9; # OSAGE CAPITAL LETTER NA -104C2; C; 104EA; # OSAGE CAPITAL LETTER O -104C3; C; 104EB; # OSAGE CAPITAL LETTER OIN -104C4; C; 104EC; # OSAGE CAPITAL LETTER PA -104C5; C; 104ED; # OSAGE CAPITAL LETTER EHPA -104C6; C; 104EE; # OSAGE CAPITAL LETTER SA -104C7; C; 104EF; # OSAGE CAPITAL LETTER SHA -104C8; C; 104F0; # OSAGE CAPITAL LETTER TA -104C9; C; 104F1; # OSAGE CAPITAL LETTER EHTA -104CA; C; 104F2; # OSAGE CAPITAL LETTER TSA -104CB; C; 104F3; # OSAGE CAPITAL LETTER EHTSA -104CC; C; 104F4; # OSAGE CAPITAL LETTER TSHA -104CD; C; 104F5; # OSAGE CAPITAL LETTER DHA -104CE; C; 104F6; # OSAGE CAPITAL LETTER U -104CF; C; 104F7; # OSAGE CAPITAL LETTER WA -104D0; C; 104F8; # OSAGE CAPITAL LETTER KHA -104D1; C; 104F9; # OSAGE CAPITAL LETTER GHA -104D2; C; 104FA; # OSAGE CAPITAL LETTER ZA -104D3; C; 104FB; # OSAGE CAPITAL LETTER ZHA -10570; C; 10597; # VITHKUQI CAPITAL LETTER A -10571; C; 10598; # VITHKUQI CAPITAL LETTER BBE -10572; C; 10599; # VITHKUQI CAPITAL LETTER BE -10573; C; 1059A; # VITHKUQI CAPITAL LETTER CE -10574; C; 1059B; # VITHKUQI CAPITAL LETTER CHE -10575; C; 1059C; # VITHKUQI CAPITAL LETTER DE -10576; C; 1059D; # VITHKUQI CAPITAL LETTER DHE -10577; C; 1059E; # VITHKUQI CAPITAL LETTER EI -10578; C; 1059F; # VITHKUQI CAPITAL LETTER E -10579; C; 105A0; # VITHKUQI CAPITAL LETTER FE -1057A; C; 105A1; # VITHKUQI CAPITAL LETTER GA -1057C; C; 105A3; # VITHKUQI CAPITAL LETTER HA -1057D; C; 105A4; # VITHKUQI CAPITAL LETTER HHA -1057E; C; 105A5; # VITHKUQI CAPITAL LETTER I -1057F; C; 105A6; # VITHKUQI CAPITAL LETTER IJE -10580; C; 105A7; # VITHKUQI CAPITAL LETTER JE -10581; C; 105A8; # VITHKUQI CAPITAL LETTER KA -10582; C; 105A9; # VITHKUQI CAPITAL LETTER LA -10583; C; 105AA; # VITHKUQI CAPITAL LETTER LLA -10584; C; 105AB; # VITHKUQI CAPITAL LETTER ME -10585; C; 105AC; # VITHKUQI CAPITAL LETTER NE -10586; C; 105AD; # VITHKUQI CAPITAL LETTER NJE -10587; C; 105AE; # VITHKUQI CAPITAL LETTER O -10588; C; 105AF; # VITHKUQI CAPITAL LETTER PE -10589; C; 105B0; # VITHKUQI CAPITAL LETTER QA -1058A; C; 105B1; # VITHKUQI CAPITAL LETTER RE -1058C; C; 105B3; # VITHKUQI CAPITAL LETTER SE -1058D; C; 105B4; # VITHKUQI CAPITAL LETTER SHE -1058E; C; 105B5; # VITHKUQI CAPITAL LETTER TE -1058F; C; 105B6; # VITHKUQI CAPITAL LETTER THE -10590; C; 105B7; # VITHKUQI CAPITAL LETTER U -10591; C; 105B8; # VITHKUQI CAPITAL LETTER VE -10592; C; 105B9; # VITHKUQI CAPITAL LETTER XE -10594; C; 105BB; # VITHKUQI CAPITAL LETTER Y -10595; C; 105BC; # VITHKUQI CAPITAL LETTER ZE -10C80; C; 10CC0; # OLD HUNGARIAN CAPITAL LETTER A -10C81; C; 10CC1; # OLD HUNGARIAN CAPITAL LETTER AA -10C82; C; 10CC2; # OLD HUNGARIAN CAPITAL LETTER EB -10C83; C; 10CC3; # OLD HUNGARIAN CAPITAL LETTER AMB -10C84; C; 10CC4; # OLD HUNGARIAN CAPITAL LETTER EC -10C85; C; 10CC5; # OLD HUNGARIAN CAPITAL LETTER ENC -10C86; C; 10CC6; # OLD HUNGARIAN CAPITAL LETTER ECS -10C87; C; 10CC7; # OLD HUNGARIAN CAPITAL LETTER ED -10C88; C; 10CC8; # OLD HUNGARIAN CAPITAL LETTER AND -10C89; C; 10CC9; # OLD HUNGARIAN CAPITAL LETTER E -10C8A; C; 10CCA; # OLD HUNGARIAN CAPITAL LETTER CLOSE E -10C8B; C; 10CCB; # OLD HUNGARIAN CAPITAL LETTER EE -10C8C; C; 10CCC; # OLD HUNGARIAN CAPITAL LETTER EF -10C8D; C; 10CCD; # OLD HUNGARIAN CAPITAL LETTER EG -10C8E; C; 10CCE; # OLD HUNGARIAN CAPITAL LETTER EGY -10C8F; C; 10CCF; # OLD HUNGARIAN CAPITAL LETTER EH -10C90; C; 10CD0; # OLD HUNGARIAN CAPITAL LETTER I -10C91; C; 10CD1; # OLD HUNGARIAN CAPITAL LETTER II -10C92; C; 10CD2; # OLD HUNGARIAN CAPITAL LETTER EJ -10C93; C; 10CD3; # OLD HUNGARIAN CAPITAL LETTER EK -10C94; C; 10CD4; # OLD HUNGARIAN CAPITAL LETTER AK -10C95; C; 10CD5; # OLD HUNGARIAN CAPITAL LETTER UNK -10C96; C; 10CD6; # OLD HUNGARIAN CAPITAL LETTER EL -10C97; C; 10CD7; # OLD HUNGARIAN CAPITAL LETTER ELY -10C98; C; 10CD8; # OLD HUNGARIAN CAPITAL LETTER EM -10C99; C; 10CD9; # OLD HUNGARIAN CAPITAL LETTER EN -10C9A; C; 10CDA; # OLD HUNGARIAN CAPITAL LETTER ENY -10C9B; C; 10CDB; # OLD HUNGARIAN CAPITAL LETTER O -10C9C; C; 10CDC; # OLD HUNGARIAN CAPITAL LETTER OO -10C9D; C; 10CDD; # OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG OE -10C9E; C; 10CDE; # OLD HUNGARIAN CAPITAL LETTER RUDIMENTA OE -10C9F; C; 10CDF; # OLD HUNGARIAN CAPITAL LETTER OEE -10CA0; C; 10CE0; # OLD HUNGARIAN CAPITAL LETTER EP -10CA1; C; 10CE1; # OLD HUNGARIAN CAPITAL LETTER EMP -10CA2; C; 10CE2; # OLD HUNGARIAN CAPITAL LETTER ER -10CA3; C; 10CE3; # OLD HUNGARIAN CAPITAL LETTER SHORT ER -10CA4; C; 10CE4; # OLD HUNGARIAN CAPITAL LETTER ES -10CA5; C; 10CE5; # OLD HUNGARIAN CAPITAL LETTER ESZ -10CA6; C; 10CE6; # OLD HUNGARIAN CAPITAL LETTER ET -10CA7; C; 10CE7; # OLD HUNGARIAN CAPITAL LETTER ENT -10CA8; C; 10CE8; # OLD HUNGARIAN CAPITAL LETTER ETY -10CA9; C; 10CE9; # OLD HUNGARIAN CAPITAL LETTER ECH -10CAA; C; 10CEA; # OLD HUNGARIAN CAPITAL LETTER U -10CAB; C; 10CEB; # OLD HUNGARIAN CAPITAL LETTER UU -10CAC; C; 10CEC; # OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG UE -10CAD; C; 10CED; # OLD HUNGARIAN CAPITAL LETTER RUDIMENTA UE -10CAE; C; 10CEE; # OLD HUNGARIAN CAPITAL LETTER EV -10CAF; C; 10CEF; # OLD HUNGARIAN CAPITAL LETTER EZ -10CB0; C; 10CF0; # OLD HUNGARIAN CAPITAL LETTER EZS -10CB1; C; 10CF1; # OLD HUNGARIAN CAPITAL LETTER ENT-SHAPED SIGN -10CB2; C; 10CF2; # OLD HUNGARIAN CAPITAL LETTER US -118A0; C; 118C0; # WARANG CITI CAPITAL LETTER NGAA -118A1; C; 118C1; # WARANG CITI CAPITAL LETTER A -118A2; C; 118C2; # WARANG CITI CAPITAL LETTER WI -118A3; C; 118C3; # WARANG CITI CAPITAL LETTER YU -118A4; C; 118C4; # WARANG CITI CAPITAL LETTER YA -118A5; C; 118C5; # WARANG CITI CAPITAL LETTER YO -118A6; C; 118C6; # WARANG CITI CAPITAL LETTER II -118A7; C; 118C7; # WARANG CITI CAPITAL LETTER UU -118A8; C; 118C8; # WARANG CITI CAPITAL LETTER E -118A9; C; 118C9; # WARANG CITI CAPITAL LETTER O -118AA; C; 118CA; # WARANG CITI CAPITAL LETTER ANG -118AB; C; 118CB; # WARANG CITI CAPITAL LETTER GA -118AC; C; 118CC; # WARANG CITI CAPITAL LETTER KO -118AD; C; 118CD; # WARANG CITI CAPITAL LETTER ENY -118AE; C; 118CE; # WARANG CITI CAPITAL LETTER YUJ -118AF; C; 118CF; # WARANG CITI CAPITAL LETTER UC -118B0; C; 118D0; # WARANG CITI CAPITAL LETTER ENN -118B1; C; 118D1; # WARANG CITI CAPITAL LETTER ODD -118B2; C; 118D2; # WARANG CITI CAPITAL LETTER TTE -118B3; C; 118D3; # WARANG CITI CAPITAL LETTER NUNG -118B4; C; 118D4; # WARANG CITI CAPITAL LETTER DA -118B5; C; 118D5; # WARANG CITI CAPITAL LETTER AT -118B6; C; 118D6; # WARANG CITI CAPITAL LETTER AM -118B7; C; 118D7; # WARANG CITI CAPITAL LETTER BU -118B8; C; 118D8; # WARANG CITI CAPITAL LETTER PU -118B9; C; 118D9; # WARANG CITI CAPITAL LETTER HIYO -118BA; C; 118DA; # WARANG CITI CAPITAL LETTER HOLO -118BB; C; 118DB; # WARANG CITI CAPITAL LETTER HORR -118BC; C; 118DC; # WARANG CITI CAPITAL LETTER HAR -118BD; C; 118DD; # WARANG CITI CAPITAL LETTER SSUU -118BE; C; 118DE; # WARANG CITI CAPITAL LETTER SII -118BF; C; 118DF; # WARANG CITI CAPITAL LETTER VIYO -16E40; C; 16E60; # MEDEFAIDRIN CAPITAL LETTER M -16E41; C; 16E61; # MEDEFAIDRIN CAPITAL LETTER S -16E42; C; 16E62; # MEDEFAIDRIN CAPITAL LETTER V -16E43; C; 16E63; # MEDEFAIDRIN CAPITAL LETTER W -16E44; C; 16E64; # MEDEFAIDRIN CAPITAL LETTER ATIU -16E45; C; 16E65; # MEDEFAIDRIN CAPITAL LETTER Z -16E46; C; 16E66; # MEDEFAIDRIN CAPITAL LETTER KP -16E47; C; 16E67; # MEDEFAIDRIN CAPITAL LETTER P -16E48; C; 16E68; # MEDEFAIDRIN CAPITAL LETTER T -16E49; C; 16E69; # MEDEFAIDRIN CAPITAL LETTER G -16E4A; C; 16E6A; # MEDEFAIDRIN CAPITAL LETTER F -16E4B; C; 16E6B; # MEDEFAIDRIN CAPITAL LETTER I -16E4C; C; 16E6C; # MEDEFAIDRIN CAPITAL LETTER K -16E4D; C; 16E6D; # MEDEFAIDRIN CAPITAL LETTER A -16E4E; C; 16E6E; # MEDEFAIDRIN CAPITAL LETTER J -16E4F; C; 16E6F; # MEDEFAIDRIN CAPITAL LETTER E -16E50; C; 16E70; # MEDEFAIDRIN CAPITAL LETTER B -16E51; C; 16E71; # MEDEFAIDRIN CAPITAL LETTER C -16E52; C; 16E72; # MEDEFAIDRIN CAPITAL LETTER U -16E53; C; 16E73; # MEDEFAIDRIN CAPITAL LETTER YU -16E54; C; 16E74; # MEDEFAIDRIN CAPITAL LETTER L -16E55; C; 16E75; # MEDEFAIDRIN CAPITAL LETTER Q -16E56; C; 16E76; # MEDEFAIDRIN CAPITAL LETTER HP -16E57; C; 16E77; # MEDEFAIDRIN CAPITAL LETTER NY -16E58; C; 16E78; # MEDEFAIDRIN CAPITAL LETTER X -16E59; C; 16E79; # MEDEFAIDRIN CAPITAL LETTER D -16E5A; C; 16E7A; # MEDEFAIDRIN CAPITAL LETTER OE -16E5B; C; 16E7B; # MEDEFAIDRIN CAPITAL LETTER N -16E5C; C; 16E7C; # MEDEFAIDRIN CAPITAL LETTER R -16E5D; C; 16E7D; # MEDEFAIDRIN CAPITAL LETTER O -16E5E; C; 16E7E; # MEDEFAIDRIN CAPITAL LETTER AI -16E5F; C; 16E7F; # MEDEFAIDRIN CAPITAL LETTER Y -1E900; C; 1E922; # ADLAM CAPITAL LETTER ALIF -1E901; C; 1E923; # ADLAM CAPITAL LETTER DAALI -1E902; C; 1E924; # ADLAM CAPITAL LETTER LAAM -1E903; C; 1E925; # ADLAM CAPITAL LETTER MIIM -1E904; C; 1E926; # ADLAM CAPITAL LETTER BA -1E905; C; 1E927; # ADLAM CAPITAL LETTER SINNYIIYHE -1E906; C; 1E928; # ADLAM CAPITAL LETTER PE -1E907; C; 1E929; # ADLAM CAPITAL LETTER BHE -1E908; C; 1E92A; # ADLAM CAPITAL LETTER RA -1E909; C; 1E92B; # ADLAM CAPITAL LETTER E -1E90A; C; 1E92C; # ADLAM CAPITAL LETTER FA -1E90B; C; 1E92D; # ADLAM CAPITAL LETTER I -1E90C; C; 1E92E; # ADLAM CAPITAL LETTER O -1E90D; C; 1E92F; # ADLAM CAPITAL LETTER DHA -1E90E; C; 1E930; # ADLAM CAPITAL LETTER YHE -1E90F; C; 1E931; # ADLAM CAPITAL LETTER WAW -1E910; C; 1E932; # ADLAM CAPITAL LETTER NUN -1E911; C; 1E933; # ADLAM CAPITAL LETTER KAF -1E912; C; 1E934; # ADLAM CAPITAL LETTER YA -1E913; C; 1E935; # ADLAM CAPITAL LETTER U -1E914; C; 1E936; # ADLAM CAPITAL LETTER JIIM -1E915; C; 1E937; # ADLAM CAPITAL LETTER CHI -1E916; C; 1E938; # ADLAM CAPITAL LETTER HA -1E917; C; 1E939; # ADLAM CAPITAL LETTER QAAF -1E918; C; 1E93A; # ADLAM CAPITAL LETTER GA -1E919; C; 1E93B; # ADLAM CAPITAL LETTER NYA -1E91A; C; 1E93C; # ADLAM CAPITAL LETTER TU -1E91B; C; 1E93D; # ADLAM CAPITAL LETTER NHA -1E91C; C; 1E93E; # ADLAM CAPITAL LETTER VA -1E91D; C; 1E93F; # ADLAM CAPITAL LETTER KHA -1E91E; C; 1E940; # ADLAM CAPITAL LETTER GBE -1E91F; C; 1E941; # ADLAM CAPITAL LETTER ZAL -1E920; C; 1E942; # ADLAM CAPITAL LETTER KPO -1E921; C; 1E943; # ADLAM CAPITAL LETTER SHA -# -# EOF diff --git a/src/unicode/Copyright.txt b/src/unicode/Copyright.txt deleted file mode 100644 index 9d281d674a..0000000000 --- a/src/unicode/Copyright.txt +++ /dev/null @@ -1,37 +0,0 @@ -COPYRIGHT AND PERMISSION NOTICE - -Copyright © 1991-2015 Unicode, Inc. All rights reserved. -Distributed under the Terms of Use in -https://www.unicode.org/copyright.html. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Unicode data files and any associated documentation -(the "Data Files") or Unicode software and any associated documentation -(the "Software") to deal in the Data Files or Software -without restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, and/or sell copies of -the Data Files or Software, and to permit persons to whom the Data Files -or Software are furnished to do so, provided that -(a) this copyright and permission notice appear with all copies -of the Data Files or Software, -(b) this copyright and permission notice appear in associated -documentation, and -(c) there is clear notice in each modified Data File or in the Software -as well as in the documentation associated with the Data File(s) or -Software that the data or software has been modified. - -THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT OF THIRD PARTY RIGHTS. -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS -NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL -DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, -DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THE DATA FILES OR SOFTWARE. - -Except as contained in this notice, the name of a copyright holder -shall not be used in advertising or otherwise to promote the sale, -use or other dealings in these Data Files or Software without prior -written authorization of the copyright holder. diff --git a/src/unicode/EastAsianWidth.txt b/src/unicode/EastAsianWidth.txt deleted file mode 100644 index 02df4df475..0000000000 --- a/src/unicode/EastAsianWidth.txt +++ /dev/null @@ -1,2621 +0,0 @@ -# EastAsianWidth-15.1.0.txt -# Date: 2023-07-28, 23:34:08 GMT -# © 2023 Unicode®, Inc. -# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see https://www.unicode.org/terms_of_use.html -# -# Unicode Character Database -# For documentation, see https://www.unicode.org/reports/tr44/ -# -# East_Asian_Width Property -# -# This file is a normative contributory data file in the -# Unicode Character Database. -# -# The format is two fields separated by a semicolon. -# Field 0: Unicode code point value or range of code point values -# Field 1: East_Asian_Width property, consisting of one of the following values: -# "A", "F", "H", "N", "Na", "W" -# - All code points, assigned or unassigned, that are not listed -# explicitly are given the value "N". -# - The unassigned code points in the following blocks default to "W": -# CJK Unified Ideographs Extension A: U+3400..U+4DBF -# CJK Unified Ideographs: U+4E00..U+9FFF -# CJK Compatibility Ideographs: U+F900..U+FAFF -# - All undesignated code points in Planes 2 and 3, whether inside or -# outside of allocated blocks, default to "W": -# Plane 2: U+20000..U+2FFFD -# Plane 3: U+30000..U+3FFFD -# -# Character ranges are specified as for other property files in the -# Unicode Character Database. -# -# The comments following the number sign "#" list the General_Category -# property value or the L& alias of the derived value LC, the Unicode -# character name or names, and, in lines with ranges of code points, -# the code point count in square brackets. -# -# For more information, see UAX #11: East Asian Width, -# at https://www.unicode.org/reports/tr11/ -# -# @missing: 0000..10FFFF; N -0000..001F ; N # Cc [32] <control-0000>..<control-001F> -0020 ; Na # Zs SPACE -0021..0023 ; Na # Po [3] EXCLAMATION MARK..NUMBER SIGN -0024 ; Na # Sc DOLLAR SIGN -0025..0027 ; Na # Po [3] PERCENT SIGN..APOSTROPHE -0028 ; Na # Ps LEFT PARENTHESIS -0029 ; Na # Pe RIGHT PARENTHESIS -002A ; Na # Po ASTERISK -002B ; Na # Sm PLUS SIGN -002C ; Na # Po COMMA -002D ; Na # Pd HYPHEN-MINUS -002E..002F ; Na # Po [2] FULL STOP..SOLIDUS -0030..0039 ; Na # Nd [10] DIGIT ZERO..DIGIT NINE -003A..003B ; Na # Po [2] COLON..SEMICOLON -003C..003E ; Na # Sm [3] LESS-THAN SIGN..GREATER-THAN SIGN -003F..0040 ; Na # Po [2] QUESTION MARK..COMMERCIAL AT -0041..005A ; Na # Lu [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z -005B ; Na # Ps LEFT SQUARE BRACKET -005C ; Na # Po REVERSE SOLIDUS -005D ; Na # Pe RIGHT SQUARE BRACKET -005E ; Na # Sk CIRCUMFLEX ACCENT -005F ; Na # Pc LOW LINE -0060 ; Na # Sk GRAVE ACCENT -0061..007A ; Na # Ll [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z -007B ; Na # Ps LEFT CURLY BRACKET -007C ; Na # Sm VERTICAL LINE -007D ; Na # Pe RIGHT CURLY BRACKET -007E ; Na # Sm TILDE -007F ; N # Cc <control-007F> -0080..009F ; N # Cc [32] <control-0080>..<control-009F> -00A0 ; N # Zs NO-BREAK SPACE -00A1 ; A # Po INVERTED EXCLAMATION MARK -00A2..00A3 ; Na # Sc [2] CENT SIGN..POUND SIGN -00A4 ; A # Sc CURRENCY SIGN -00A5 ; Na # Sc YEN SIGN -00A6 ; Na # So BROKEN BAR -00A7 ; A # Po SECTION SIGN -00A8 ; A # Sk DIAERESIS -00A9 ; N # So COPYRIGHT SIGN -00AA ; A # Lo FEMININE ORDINAL INDICATOR -00AB ; N # Pi LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -00AC ; Na # Sm NOT SIGN -00AD ; A # Cf SOFT HYPHEN -00AE ; A # So REGISTERED SIGN -00AF ; Na # Sk MACRON -00B0 ; A # So DEGREE SIGN -00B1 ; A # Sm PLUS-MINUS SIGN -00B2..00B3 ; A # No [2] SUPERSCRIPT TWO..SUPERSCRIPT THREE -00B4 ; A # Sk ACUTE ACCENT -00B5 ; N # Ll MICRO SIGN -00B6..00B7 ; A # Po [2] PILCROW SIGN..MIDDLE DOT -00B8 ; A # Sk CEDILLA -00B9 ; A # No SUPERSCRIPT ONE -00BA ; A # Lo MASCULINE ORDINAL INDICATOR -00BB ; N # Pf RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -00BC..00BE ; A # No [3] VULGAR FRACTION ONE QUARTER..VULGAR FRACTION THREE QUARTERS -00BF ; A # Po INVERTED QUESTION MARK -00C0..00C5 ; N # Lu [6] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER A WITH RING ABOVE -00C6 ; A # Lu LATIN CAPITAL LETTER AE -00C7..00CF ; N # Lu [9] LATIN CAPITAL LETTER C WITH CEDILLA..LATIN CAPITAL LETTER I WITH DIAERESIS -00D0 ; A # Lu LATIN CAPITAL LETTER ETH -00D1..00D6 ; N # Lu [6] LATIN CAPITAL LETTER N WITH TILDE..LATIN CAPITAL LETTER O WITH DIAERESIS -00D7 ; A # Sm MULTIPLICATION SIGN -00D8 ; A # Lu LATIN CAPITAL LETTER O WITH STROKE -00D9..00DD ; N # Lu [5] LATIN CAPITAL LETTER U WITH GRAVE..LATIN CAPITAL LETTER Y WITH ACUTE -00DE..00E1 ; A # L& [4] LATIN CAPITAL LETTER THORN..LATIN SMALL LETTER A WITH ACUTE -00E2..00E5 ; N # Ll [4] LATIN SMALL LETTER A WITH CIRCUMFLEX..LATIN SMALL LETTER A WITH RING ABOVE -00E6 ; A # Ll LATIN SMALL LETTER AE -00E7 ; N # Ll LATIN SMALL LETTER C WITH CEDILLA -00E8..00EA ; A # Ll [3] LATIN SMALL LETTER E WITH GRAVE..LATIN SMALL LETTER E WITH CIRCUMFLEX -00EB ; N # Ll LATIN SMALL LETTER E WITH DIAERESIS -00EC..00ED ; A # Ll [2] LATIN SMALL LETTER I WITH GRAVE..LATIN SMALL LETTER I WITH ACUTE -00EE..00EF ; N # Ll [2] LATIN SMALL LETTER I WITH CIRCUMFLEX..LATIN SMALL LETTER I WITH DIAERESIS -00F0 ; A # Ll LATIN SMALL LETTER ETH -00F1 ; N # Ll LATIN SMALL LETTER N WITH TILDE -00F2..00F3 ; A # Ll [2] LATIN SMALL LETTER O WITH GRAVE..LATIN SMALL LETTER O WITH ACUTE -00F4..00F6 ; N # Ll [3] LATIN SMALL LETTER O WITH CIRCUMFLEX..LATIN SMALL LETTER O WITH DIAERESIS -00F7 ; A # Sm DIVISION SIGN -00F8..00FA ; A # Ll [3] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER U WITH ACUTE -00FB ; N # Ll LATIN SMALL LETTER U WITH CIRCUMFLEX -00FC ; A # Ll LATIN SMALL LETTER U WITH DIAERESIS -00FD ; N # Ll LATIN SMALL LETTER Y WITH ACUTE -00FE ; A # Ll LATIN SMALL LETTER THORN -00FF ; N # Ll LATIN SMALL LETTER Y WITH DIAERESIS -0100 ; N # Lu LATIN CAPITAL LETTER A WITH MACRON -0101 ; A # Ll LATIN SMALL LETTER A WITH MACRON -0102..0110 ; N # L& [15] LATIN CAPITAL LETTER A WITH BREVE..LATIN CAPITAL LETTER D WITH STROKE -0111 ; A # Ll LATIN SMALL LETTER D WITH STROKE -0112 ; N # Lu LATIN CAPITAL LETTER E WITH MACRON -0113 ; A # Ll LATIN SMALL LETTER E WITH MACRON -0114..011A ; N # L& [7] LATIN CAPITAL LETTER E WITH BREVE..LATIN CAPITAL LETTER E WITH CARON -011B ; A # Ll LATIN SMALL LETTER E WITH CARON -011C..0125 ; N # L& [10] LATIN CAPITAL LETTER G WITH CIRCUMFLEX..LATIN SMALL LETTER H WITH CIRCUMFLEX -0126..0127 ; A # L& [2] LATIN CAPITAL LETTER H WITH STROKE..LATIN SMALL LETTER H WITH STROKE -0128..012A ; N # L& [3] LATIN CAPITAL LETTER I WITH TILDE..LATIN CAPITAL LETTER I WITH MACRON -012B ; A # Ll LATIN SMALL LETTER I WITH MACRON -012C..0130 ; N # L& [5] LATIN CAPITAL LETTER I WITH BREVE..LATIN CAPITAL LETTER I WITH DOT ABOVE -0131..0133 ; A # L& [3] LATIN SMALL LETTER DOTLESS I..LATIN SMALL LIGATURE IJ -0134..0137 ; N # L& [4] LATIN CAPITAL LETTER J WITH CIRCUMFLEX..LATIN SMALL LETTER K WITH CEDILLA -0138 ; A # Ll LATIN SMALL LETTER KRA -0139..013E ; N # L& [6] LATIN CAPITAL LETTER L WITH ACUTE..LATIN SMALL LETTER L WITH CARON -013F..0142 ; A # L& [4] LATIN CAPITAL LETTER L WITH MIDDLE DOT..LATIN SMALL LETTER L WITH STROKE -0143 ; N # Lu LATIN CAPITAL LETTER N WITH ACUTE -0144 ; A # Ll LATIN SMALL LETTER N WITH ACUTE -0145..0147 ; N # L& [3] LATIN CAPITAL LETTER N WITH CEDILLA..LATIN CAPITAL LETTER N WITH CARON -0148..014B ; A # L& [4] LATIN SMALL LETTER N WITH CARON..LATIN SMALL LETTER ENG -014C ; N # Lu LATIN CAPITAL LETTER O WITH MACRON -014D ; A # Ll LATIN SMALL LETTER O WITH MACRON -014E..0151 ; N # L& [4] LATIN CAPITAL LETTER O WITH BREVE..LATIN SMALL LETTER O WITH DOUBLE ACUTE -0152..0153 ; A # L& [2] LATIN CAPITAL LIGATURE OE..LATIN SMALL LIGATURE OE -0154..0165 ; N # L& [18] LATIN CAPITAL LETTER R WITH ACUTE..LATIN SMALL LETTER T WITH CARON -0166..0167 ; A # L& [2] LATIN CAPITAL LETTER T WITH STROKE..LATIN SMALL LETTER T WITH STROKE -0168..016A ; N # L& [3] LATIN CAPITAL LETTER U WITH TILDE..LATIN CAPITAL LETTER U WITH MACRON -016B ; A # Ll LATIN SMALL LETTER U WITH MACRON -016C..017F ; N # L& [20] LATIN CAPITAL LETTER U WITH BREVE..LATIN SMALL LETTER LONG S -0180..01BA ; N # L& [59] LATIN SMALL LETTER B WITH STROKE..LATIN SMALL LETTER EZH WITH TAIL -01BB ; N # Lo LATIN LETTER TWO WITH STROKE -01BC..01BF ; N # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN -01C0..01C3 ; N # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK -01C4..01CD ; N # L& [10] LATIN CAPITAL LETTER DZ WITH CARON..LATIN CAPITAL LETTER A WITH CARON -01CE ; A # Ll LATIN SMALL LETTER A WITH CARON -01CF ; N # Lu LATIN CAPITAL LETTER I WITH CARON -01D0 ; A # Ll LATIN SMALL LETTER I WITH CARON -01D1 ; N # Lu LATIN CAPITAL LETTER O WITH CARON -01D2 ; A # Ll LATIN SMALL LETTER O WITH CARON -01D3 ; N # Lu LATIN CAPITAL LETTER U WITH CARON -01D4 ; A # Ll LATIN SMALL LETTER U WITH CARON -01D5 ; N # Lu LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON -01D6 ; A # Ll LATIN SMALL LETTER U WITH DIAERESIS AND MACRON -01D7 ; N # Lu LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE -01D8 ; A # Ll LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE -01D9 ; N # Lu LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON -01DA ; A # Ll LATIN SMALL LETTER U WITH DIAERESIS AND CARON -01DB ; N # Lu LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE -01DC ; A # Ll LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE -01DD..024F ; N # L& [115] LATIN SMALL LETTER TURNED E..LATIN SMALL LETTER Y WITH STROKE -0250 ; N # Ll LATIN SMALL LETTER TURNED A -0251 ; A # Ll LATIN SMALL LETTER ALPHA -0252..0260 ; N # Ll [15] LATIN SMALL LETTER TURNED ALPHA..LATIN SMALL LETTER G WITH HOOK -0261 ; A # Ll LATIN SMALL LETTER SCRIPT G -0262..0293 ; N # Ll [50] LATIN LETTER SMALL CAPITAL G..LATIN SMALL LETTER EZH WITH CURL -0294 ; N # Lo LATIN LETTER GLOTTAL STOP -0295..02AF ; N # Ll [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL -02B0..02C1 ; N # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP -02C2..02C3 ; N # Sk [2] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER RIGHT ARROWHEAD -02C4 ; A # Sk MODIFIER LETTER UP ARROWHEAD -02C5 ; N # Sk MODIFIER LETTER DOWN ARROWHEAD -02C6 ; N # Lm MODIFIER LETTER CIRCUMFLEX ACCENT -02C7 ; A # Lm CARON -02C8 ; N # Lm MODIFIER LETTER VERTICAL LINE -02C9..02CB ; A # Lm [3] MODIFIER LETTER MACRON..MODIFIER LETTER GRAVE ACCENT -02CC ; N # Lm MODIFIER LETTER LOW VERTICAL LINE -02CD ; A # Lm MODIFIER LETTER LOW MACRON -02CE..02CF ; N # Lm [2] MODIFIER LETTER LOW GRAVE ACCENT..MODIFIER LETTER LOW ACUTE ACCENT -02D0 ; A # Lm MODIFIER LETTER TRIANGULAR COLON -02D1 ; N # Lm MODIFIER LETTER HALF TRIANGULAR COLON -02D2..02D7 ; N # Sk [6] MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER MINUS SIGN -02D8..02DB ; A # Sk [4] BREVE..OGONEK -02DC ; N # Sk SMALL TILDE -02DD ; A # Sk DOUBLE ACUTE ACCENT -02DE ; N # Sk MODIFIER LETTER RHOTIC HOOK -02DF ; A # Sk MODIFIER LETTER CROSS ACCENT -02E0..02E4 ; N # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP -02E5..02EB ; N # Sk [7] MODIFIER LETTER EXTRA-HIGH TONE BAR..MODIFIER LETTER YANG DEPARTING TONE MARK -02EC ; N # Lm MODIFIER LETTER VOICING -02ED ; N # Sk MODIFIER LETTER UNASPIRATED -02EE ; N # Lm MODIFIER LETTER DOUBLE APOSTROPHE -02EF..02FF ; N # Sk [17] MODIFIER LETTER LOW DOWN ARROWHEAD..MODIFIER LETTER LOW LEFT ARROW -0300..036F ; A # Mn [112] COMBINING GRAVE ACCENT..COMBINING LATIN SMALL LETTER X -0370..0373 ; N # L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI -0374 ; N # Lm GREEK NUMERAL SIGN -0375 ; N # Sk GREEK LOWER NUMERAL SIGN -0376..0377 ; N # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA -037A ; N # Lm GREEK YPOGEGRAMMENI -037B..037D ; N # Ll [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL -037E ; N # Po GREEK QUESTION MARK -037F ; N # Lu GREEK CAPITAL LETTER YOT -0384..0385 ; N # Sk [2] GREEK TONOS..GREEK DIALYTIKA TONOS -0386 ; N # Lu GREEK CAPITAL LETTER ALPHA WITH TONOS -0387 ; N # Po GREEK ANO TELEIA -0388..038A ; N # Lu [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS -038C ; N # Lu GREEK CAPITAL LETTER OMICRON WITH TONOS -038E..0390 ; N # L& [3] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS -0391..03A1 ; A # Lu [17] GREEK CAPITAL LETTER ALPHA..GREEK CAPITAL LETTER RHO -03A3..03A9 ; A # Lu [7] GREEK CAPITAL LETTER SIGMA..GREEK CAPITAL LETTER OMEGA -03AA..03B0 ; N # L& [7] GREEK CAPITAL LETTER IOTA WITH DIALYTIKA..GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS -03B1..03C1 ; A # Ll [17] GREEK SMALL LETTER ALPHA..GREEK SMALL LETTER RHO -03C2 ; N # Ll GREEK SMALL LETTER FINAL SIGMA -03C3..03C9 ; A # Ll [7] GREEK SMALL LETTER SIGMA..GREEK SMALL LETTER OMEGA -03CA..03F5 ; N # L& [44] GREEK SMALL LETTER IOTA WITH DIALYTIKA..GREEK LUNATE EPSILON SYMBOL -03F6 ; N # Sm GREEK REVERSED LUNATE EPSILON SYMBOL -03F7..03FF ; N # L& [9] GREEK CAPITAL LETTER SHO..GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL -0400 ; N # Lu CYRILLIC CAPITAL LETTER IE WITH GRAVE -0401 ; A # Lu CYRILLIC CAPITAL LETTER IO -0402..040F ; N # Lu [14] CYRILLIC CAPITAL LETTER DJE..CYRILLIC CAPITAL LETTER DZHE -0410..044F ; A # L& [64] CYRILLIC CAPITAL LETTER A..CYRILLIC SMALL LETTER YA -0450 ; N # Ll CYRILLIC SMALL LETTER IE WITH GRAVE -0451 ; A # Ll CYRILLIC SMALL LETTER IO -0452..0481 ; N # L& [48] CYRILLIC SMALL LETTER DJE..CYRILLIC SMALL LETTER KOPPA -0482 ; N # So CYRILLIC THOUSANDS SIGN -0483..0487 ; N # Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE -0488..0489 ; N # Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN -048A..04FF ; N # L& [118] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER HA WITH STROKE -0500..052F ; N # L& [48] CYRILLIC CAPITAL LETTER KOMI DE..CYRILLIC SMALL LETTER EL WITH DESCENDER -0531..0556 ; N # Lu [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH -0559 ; N # Lm ARMENIAN MODIFIER LETTER LEFT HALF RING -055A..055F ; N # Po [6] ARMENIAN APOSTROPHE..ARMENIAN ABBREVIATION MARK -0560..0588 ; N # Ll [41] ARMENIAN SMALL LETTER TURNED AYB..ARMENIAN SMALL LETTER YI WITH STROKE -0589 ; N # Po ARMENIAN FULL STOP -058A ; N # Pd ARMENIAN HYPHEN -058D..058E ; N # So [2] RIGHT-FACING ARMENIAN ETERNITY SIGN..LEFT-FACING ARMENIAN ETERNITY SIGN -058F ; N # Sc ARMENIAN DRAM SIGN -0591..05BD ; N # Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG -05BE ; N # Pd HEBREW PUNCTUATION MAQAF -05BF ; N # Mn HEBREW POINT RAFE -05C0 ; N # Po HEBREW PUNCTUATION PASEQ -05C1..05C2 ; N # Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT -05C3 ; N # Po HEBREW PUNCTUATION SOF PASUQ -05C4..05C5 ; N # Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT -05C6 ; N # Po HEBREW PUNCTUATION NUN HAFUKHA -05C7 ; N # Mn HEBREW POINT QAMATS QATAN -05D0..05EA ; N # Lo [27] HEBREW LETTER ALEF..HEBREW LETTER TAV -05EF..05F2 ; N # Lo [4] HEBREW YOD TRIANGLE..HEBREW LIGATURE YIDDISH DOUBLE YOD -05F3..05F4 ; N # Po [2] HEBREW PUNCTUATION GERESH..HEBREW PUNCTUATION GERSHAYIM -0600..0605 ; N # Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE -0606..0608 ; N # Sm [3] ARABIC-INDIC CUBE ROOT..ARABIC RAY -0609..060A ; N # Po [2] ARABIC-INDIC PER MILLE SIGN..ARABIC-INDIC PER TEN THOUSAND SIGN -060B ; N # Sc AFGHANI SIGN -060C..060D ; N # Po [2] ARABIC COMMA..ARABIC DATE SEPARATOR -060E..060F ; N # So [2] ARABIC POETIC VERSE SIGN..ARABIC SIGN MISRA -0610..061A ; N # Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA -061B ; N # Po ARABIC SEMICOLON -061C ; N # Cf ARABIC LETTER MARK -061D..061F ; N # Po [3] ARABIC END OF TEXT MARK..ARABIC QUESTION MARK -0620..063F ; N # Lo [32] ARABIC LETTER KASHMIRI YEH..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE -0640 ; N # Lm ARABIC TATWEEL -0641..064A ; N # Lo [10] ARABIC LETTER FEH..ARABIC LETTER YEH -064B..065F ; N # Mn [21] ARABIC FATHATAN..ARABIC WAVY HAMZA BELOW -0660..0669 ; N # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE -066A..066D ; N # Po [4] ARABIC PERCENT SIGN..ARABIC FIVE POINTED STAR -066E..066F ; N # Lo [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF -0670 ; N # Mn ARABIC LETTER SUPERSCRIPT ALEF -0671..06D3 ; N # Lo [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE -06D4 ; N # Po ARABIC FULL STOP -06D5 ; N # Lo ARABIC LETTER AE -06D6..06DC ; N # Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN -06DD ; N # Cf ARABIC END OF AYAH -06DE ; N # So ARABIC START OF RUB EL HIZB -06DF..06E4 ; N # Mn [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA -06E5..06E6 ; N # Lm [2] ARABIC SMALL WAW..ARABIC SMALL YEH -06E7..06E8 ; N # Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON -06E9 ; N # So ARABIC PLACE OF SAJDAH -06EA..06ED ; N # Mn [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM -06EE..06EF ; N # Lo [2] ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V -06F0..06F9 ; N # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE -06FA..06FC ; N # Lo [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW -06FD..06FE ; N # So [2] ARABIC SIGN SINDHI AMPERSAND..ARABIC SIGN SINDHI POSTPOSITION MEN -06FF ; N # Lo ARABIC LETTER HEH WITH INVERTED V -0700..070D ; N # Po [14] SYRIAC END OF PARAGRAPH..SYRIAC HARKLEAN ASTERISCUS -070F ; N # Cf SYRIAC ABBREVIATION MARK -0710 ; N # Lo SYRIAC LETTER ALAPH -0711 ; N # Mn SYRIAC LETTER SUPERSCRIPT ALAPH -0712..072F ; N # Lo [30] SYRIAC LETTER BETH..SYRIAC LETTER PERSIAN DHALATH -0730..074A ; N # Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH -074D..074F ; N # Lo [3] SYRIAC LETTER SOGDIAN ZHAIN..SYRIAC LETTER SOGDIAN FE -0750..077F ; N # Lo [48] ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS ABOVE -0780..07A5 ; N # Lo [38] THAANA LETTER HAA..THAANA LETTER WAAVU -07A6..07B0 ; N # Mn [11] THAANA ABAFILI..THAANA SUKUN -07B1 ; N # Lo THAANA LETTER NAA -07C0..07C9 ; N # Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE -07CA..07EA ; N # Lo [33] NKO LETTER A..NKO LETTER JONA RA -07EB..07F3 ; N # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE -07F4..07F5 ; N # Lm [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE -07F6 ; N # So NKO SYMBOL OO DENNEN -07F7..07F9 ; N # Po [3] NKO SYMBOL GBAKURUNEN..NKO EXCLAMATION MARK -07FA ; N # Lm NKO LAJANYALAN -07FD ; N # Mn NKO DANTAYALAN -07FE..07FF ; N # Sc [2] NKO DOROME SIGN..NKO TAMAN SIGN -0800..0815 ; N # Lo [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF -0816..0819 ; N # Mn [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH -081A ; N # Lm SAMARITAN MODIFIER LETTER EPENTHETIC YUT -081B..0823 ; N # Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A -0824 ; N # Lm SAMARITAN MODIFIER LETTER SHORT A -0825..0827 ; N # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U -0828 ; N # Lm SAMARITAN MODIFIER LETTER I -0829..082D ; N # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA -0830..083E ; N # Po [15] SAMARITAN PUNCTUATION NEQUDAA..SAMARITAN PUNCTUATION ANNAAU -0840..0858 ; N # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN -0859..085B ; N # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK -085E ; N # Po MANDAIC PUNCTUATION -0860..086A ; N # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA -0870..0887 ; N # Lo [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT -0888 ; N # Sk ARABIC RAISED ROUND DOT -0889..088E ; N # Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL -0890..0891 ; N # Cf [2] ARABIC POUND MARK ABOVE..ARABIC PIASTRE MARK ABOVE -0898..089F ; N # Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA -08A0..08C8 ; N # Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF -08C9 ; N # Lm ARABIC SMALL FARSI YEH -08CA..08E1 ; N # Mn [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA -08E2 ; N # Cf ARABIC DISPUTED END OF AYAH -08E3..08FF ; N # Mn [29] ARABIC TURNED DAMMA BELOW..ARABIC MARK SIDEWAYS NOON GHUNNA -0900..0902 ; N # Mn [3] DEVANAGARI SIGN INVERTED CANDRABINDU..DEVANAGARI SIGN ANUSVARA -0903 ; N # Mc DEVANAGARI SIGN VISARGA -0904..0939 ; N # Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA -093A ; N # Mn DEVANAGARI VOWEL SIGN OE -093B ; N # Mc DEVANAGARI VOWEL SIGN OOE -093C ; N # Mn DEVANAGARI SIGN NUKTA -093D ; N # Lo DEVANAGARI SIGN AVAGRAHA -093E..0940 ; N # Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II -0941..0948 ; N # Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI -0949..094C ; N # Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU -094D ; N # Mn DEVANAGARI SIGN VIRAMA -094E..094F ; N # Mc [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW -0950 ; N # Lo DEVANAGARI OM -0951..0957 ; N # Mn [7] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI VOWEL SIGN UUE -0958..0961 ; N # Lo [10] DEVANAGARI LETTER QA..DEVANAGARI LETTER VOCALIC LL -0962..0963 ; N # Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL -0964..0965 ; N # Po [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA -0966..096F ; N # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE -0970 ; N # Po DEVANAGARI ABBREVIATION SIGN -0971 ; N # Lm DEVANAGARI SIGN HIGH SPACING DOT -0972..097F ; N # Lo [14] DEVANAGARI LETTER CANDRA A..DEVANAGARI LETTER BBA -0980 ; N # Lo BENGALI ANJI -0981 ; N # Mn BENGALI SIGN CANDRABINDU -0982..0983 ; N # Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA -0985..098C ; N # Lo [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L -098F..0990 ; N # Lo [2] BENGALI LETTER E..BENGALI LETTER AI -0993..09A8 ; N # Lo [22] BENGALI LETTER O..BENGALI LETTER NA -09AA..09B0 ; N # Lo [7] BENGALI LETTER PA..BENGALI LETTER RA -09B2 ; N # Lo BENGALI LETTER LA -09B6..09B9 ; N # Lo [4] BENGALI LETTER SHA..BENGALI LETTER HA -09BC ; N # Mn BENGALI SIGN NUKTA -09BD ; N # Lo BENGALI SIGN AVAGRAHA -09BE..09C0 ; N # Mc [3] BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN II -09C1..09C4 ; N # Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR -09C7..09C8 ; N # Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI -09CB..09CC ; N # Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU -09CD ; N # Mn BENGALI SIGN VIRAMA -09CE ; N # Lo BENGALI LETTER KHANDA TA -09D7 ; N # Mc BENGALI AU LENGTH MARK -09DC..09DD ; N # Lo [2] BENGALI LETTER RRA..BENGALI LETTER RHA -09DF..09E1 ; N # Lo [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL -09E2..09E3 ; N # Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL -09E6..09EF ; N # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE -09F0..09F1 ; N # Lo [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL -09F2..09F3 ; N # Sc [2] BENGALI RUPEE MARK..BENGALI RUPEE SIGN -09F4..09F9 ; N # No [6] BENGALI CURRENCY NUMERATOR ONE..BENGALI CURRENCY DENOMINATOR SIXTEEN -09FA ; N # So BENGALI ISSHAR -09FB ; N # Sc BENGALI GANDA MARK -09FC ; N # Lo BENGALI LETTER VEDIC ANUSVARA -09FD ; N # Po BENGALI ABBREVIATION SIGN -09FE ; N # Mn BENGALI SANDHI MARK -0A01..0A02 ; N # Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI -0A03 ; N # Mc GURMUKHI SIGN VISARGA -0A05..0A0A ; N # Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU -0A0F..0A10 ; N # Lo [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI -0A13..0A28 ; N # Lo [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA -0A2A..0A30 ; N # Lo [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA -0A32..0A33 ; N # Lo [2] GURMUKHI LETTER LA..GURMUKHI LETTER LLA -0A35..0A36 ; N # Lo [2] GURMUKHI LETTER VA..GURMUKHI LETTER SHA -0A38..0A39 ; N # Lo [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA -0A3C ; N # Mn GURMUKHI SIGN NUKTA -0A3E..0A40 ; N # Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II -0A41..0A42 ; N # Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU -0A47..0A48 ; N # Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI -0A4B..0A4D ; N # Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA -0A51 ; N # Mn GURMUKHI SIGN UDAAT -0A59..0A5C ; N # Lo [4] GURMUKHI LETTER KHHA..GURMUKHI LETTER RRA -0A5E ; N # Lo GURMUKHI LETTER FA -0A66..0A6F ; N # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE -0A70..0A71 ; N # Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK -0A72..0A74 ; N # Lo [3] GURMUKHI IRI..GURMUKHI EK ONKAR -0A75 ; N # Mn GURMUKHI SIGN YAKASH -0A76 ; N # Po GURMUKHI ABBREVIATION SIGN -0A81..0A82 ; N # Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA -0A83 ; N # Mc GUJARATI SIGN VISARGA -0A85..0A8D ; N # Lo [9] GUJARATI LETTER A..GUJARATI VOWEL CANDRA E -0A8F..0A91 ; N # Lo [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O -0A93..0AA8 ; N # Lo [22] GUJARATI LETTER O..GUJARATI LETTER NA -0AAA..0AB0 ; N # Lo [7] GUJARATI LETTER PA..GUJARATI LETTER RA -0AB2..0AB3 ; N # Lo [2] GUJARATI LETTER LA..GUJARATI LETTER LLA -0AB5..0AB9 ; N # Lo [5] GUJARATI LETTER VA..GUJARATI LETTER HA -0ABC ; N # Mn GUJARATI SIGN NUKTA -0ABD ; N # Lo GUJARATI SIGN AVAGRAHA -0ABE..0AC0 ; N # Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II -0AC1..0AC5 ; N # Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E -0AC7..0AC8 ; N # Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI -0AC9 ; N # Mc GUJARATI VOWEL SIGN CANDRA O -0ACB..0ACC ; N # Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU -0ACD ; N # Mn GUJARATI SIGN VIRAMA -0AD0 ; N # Lo GUJARATI OM -0AE0..0AE1 ; N # Lo [2] GUJARATI LETTER VOCALIC RR..GUJARATI LETTER VOCALIC LL -0AE2..0AE3 ; N # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL -0AE6..0AEF ; N # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE -0AF0 ; N # Po GUJARATI ABBREVIATION SIGN -0AF1 ; N # Sc GUJARATI RUPEE SIGN -0AF9 ; N # Lo GUJARATI LETTER ZHA -0AFA..0AFF ; N # Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE -0B01 ; N # Mn ORIYA SIGN CANDRABINDU -0B02..0B03 ; N # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA -0B05..0B0C ; N # Lo [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L -0B0F..0B10 ; N # Lo [2] ORIYA LETTER E..ORIYA LETTER AI -0B13..0B28 ; N # Lo [22] ORIYA LETTER O..ORIYA LETTER NA -0B2A..0B30 ; N # Lo [7] ORIYA LETTER PA..ORIYA LETTER RA -0B32..0B33 ; N # Lo [2] ORIYA LETTER LA..ORIYA LETTER LLA -0B35..0B39 ; N # Lo [5] ORIYA LETTER VA..ORIYA LETTER HA -0B3C ; N # Mn ORIYA SIGN NUKTA -0B3D ; N # Lo ORIYA SIGN AVAGRAHA -0B3E ; N # Mc ORIYA VOWEL SIGN AA -0B3F ; N # Mn ORIYA VOWEL SIGN I -0B40 ; N # Mc ORIYA VOWEL SIGN II -0B41..0B44 ; N # Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR -0B47..0B48 ; N # Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI -0B4B..0B4C ; N # Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU -0B4D ; N # Mn ORIYA SIGN VIRAMA -0B55..0B56 ; N # Mn [2] ORIYA SIGN OVERLINE..ORIYA AI LENGTH MARK -0B57 ; N # Mc ORIYA AU LENGTH MARK -0B5C..0B5D ; N # Lo [2] ORIYA LETTER RRA..ORIYA LETTER RHA -0B5F..0B61 ; N # Lo [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL -0B62..0B63 ; N # Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL -0B66..0B6F ; N # Nd [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE -0B70 ; N # So ORIYA ISSHAR -0B71 ; N # Lo ORIYA LETTER WA -0B72..0B77 ; N # No [6] ORIYA FRACTION ONE QUARTER..ORIYA FRACTION THREE SIXTEENTHS -0B82 ; N # Mn TAMIL SIGN ANUSVARA -0B83 ; N # Lo TAMIL SIGN VISARGA -0B85..0B8A ; N # Lo [6] TAMIL LETTER A..TAMIL LETTER UU -0B8E..0B90 ; N # Lo [3] TAMIL LETTER E..TAMIL LETTER AI -0B92..0B95 ; N # Lo [4] TAMIL LETTER O..TAMIL LETTER KA -0B99..0B9A ; N # Lo [2] TAMIL LETTER NGA..TAMIL LETTER CA -0B9C ; N # Lo TAMIL LETTER JA -0B9E..0B9F ; N # Lo [2] TAMIL LETTER NYA..TAMIL LETTER TTA -0BA3..0BA4 ; N # Lo [2] TAMIL LETTER NNA..TAMIL LETTER TA -0BA8..0BAA ; N # Lo [3] TAMIL LETTER NA..TAMIL LETTER PA -0BAE..0BB9 ; N # Lo [12] TAMIL LETTER MA..TAMIL LETTER HA -0BBE..0BBF ; N # Mc [2] TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN I -0BC0 ; N # Mn TAMIL VOWEL SIGN II -0BC1..0BC2 ; N # Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU -0BC6..0BC8 ; N # Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI -0BCA..0BCC ; N # Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU -0BCD ; N # Mn TAMIL SIGN VIRAMA -0BD0 ; N # Lo TAMIL OM -0BD7 ; N # Mc TAMIL AU LENGTH MARK -0BE6..0BEF ; N # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE -0BF0..0BF2 ; N # No [3] TAMIL NUMBER TEN..TAMIL NUMBER ONE THOUSAND -0BF3..0BF8 ; N # So [6] TAMIL DAY SIGN..TAMIL AS ABOVE SIGN -0BF9 ; N # Sc TAMIL RUPEE SIGN -0BFA ; N # So TAMIL NUMBER SIGN -0C00 ; N # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE -0C01..0C03 ; N # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA -0C04 ; N # Mn TELUGU SIGN COMBINING ANUSVARA ABOVE -0C05..0C0C ; N # Lo [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L -0C0E..0C10 ; N # Lo [3] TELUGU LETTER E..TELUGU LETTER AI -0C12..0C28 ; N # Lo [23] TELUGU LETTER O..TELUGU LETTER NA -0C2A..0C39 ; N # Lo [16] TELUGU LETTER PA..TELUGU LETTER HA -0C3C ; N # Mn TELUGU SIGN NUKTA -0C3D ; N # Lo TELUGU SIGN AVAGRAHA -0C3E..0C40 ; N # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II -0C41..0C44 ; N # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR -0C46..0C48 ; N # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI -0C4A..0C4D ; N # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA -0C55..0C56 ; N # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK -0C58..0C5A ; N # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA -0C5D ; N # Lo TELUGU LETTER NAKAARA POLLU -0C60..0C61 ; N # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL -0C62..0C63 ; N # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL -0C66..0C6F ; N # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE -0C77 ; N # Po TELUGU SIGN SIDDHAM -0C78..0C7E ; N # No [7] TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR..TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR -0C7F ; N # So TELUGU SIGN TUUMU -0C80 ; N # Lo KANNADA SIGN SPACING CANDRABINDU -0C81 ; N # Mn KANNADA SIGN CANDRABINDU -0C82..0C83 ; N # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA -0C84 ; N # Po KANNADA SIGN SIDDHAM -0C85..0C8C ; N # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L -0C8E..0C90 ; N # Lo [3] KANNADA LETTER E..KANNADA LETTER AI -0C92..0CA8 ; N # Lo [23] KANNADA LETTER O..KANNADA LETTER NA -0CAA..0CB3 ; N # Lo [10] KANNADA LETTER PA..KANNADA LETTER LLA -0CB5..0CB9 ; N # Lo [5] KANNADA LETTER VA..KANNADA LETTER HA -0CBC ; N # Mn KANNADA SIGN NUKTA -0CBD ; N # Lo KANNADA SIGN AVAGRAHA -0CBE ; N # Mc KANNADA VOWEL SIGN AA -0CBF ; N # Mn KANNADA VOWEL SIGN I -0CC0..0CC4 ; N # Mc [5] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN VOCALIC RR -0CC6 ; N # Mn KANNADA VOWEL SIGN E -0CC7..0CC8 ; N # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI -0CCA..0CCB ; N # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO -0CCC..0CCD ; N # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA -0CD5..0CD6 ; N # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK -0CDD..0CDE ; N # Lo [2] KANNADA LETTER NAKAARA POLLU..KANNADA LETTER FA -0CE0..0CE1 ; N # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL -0CE2..0CE3 ; N # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL -0CE6..0CEF ; N # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE -0CF1..0CF2 ; N # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA -0CF3 ; N # Mc KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT -0D00..0D01 ; N # Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU -0D02..0D03 ; N # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA -0D04..0D0C ; N # Lo [9] MALAYALAM LETTER VEDIC ANUSVARA..MALAYALAM LETTER VOCALIC L -0D0E..0D10 ; N # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI -0D12..0D3A ; N # Lo [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA -0D3B..0D3C ; N # Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA -0D3D ; N # Lo MALAYALAM SIGN AVAGRAHA -0D3E..0D40 ; N # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II -0D41..0D44 ; N # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR -0D46..0D48 ; N # Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI -0D4A..0D4C ; N # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU -0D4D ; N # Mn MALAYALAM SIGN VIRAMA -0D4E ; N # Lo MALAYALAM LETTER DOT REPH -0D4F ; N # So MALAYALAM SIGN PARA -0D54..0D56 ; N # Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL -0D57 ; N # Mc MALAYALAM AU LENGTH MARK -0D58..0D5E ; N # No [7] MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH..MALAYALAM FRACTION ONE FIFTH -0D5F..0D61 ; N # Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL -0D62..0D63 ; N # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL -0D66..0D6F ; N # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE -0D70..0D78 ; N # No [9] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE SIXTEENTHS -0D79 ; N # So MALAYALAM DATE MARK -0D7A..0D7F ; N # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K -0D81 ; N # Mn SINHALA SIGN CANDRABINDU -0D82..0D83 ; N # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA -0D85..0D96 ; N # Lo [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA -0D9A..0DB1 ; N # Lo [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA -0DB3..0DBB ; N # Lo [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA -0DBD ; N # Lo SINHALA LETTER DANTAJA LAYANNA -0DC0..0DC6 ; N # Lo [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA -0DCA ; N # Mn SINHALA SIGN AL-LAKUNA -0DCF..0DD1 ; N # Mc [3] SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA -0DD2..0DD4 ; N # Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA -0DD6 ; N # Mn SINHALA VOWEL SIGN DIGA PAA-PILLA -0DD8..0DDF ; N # Mc [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA -0DE6..0DEF ; N # Nd [10] SINHALA LITH DIGIT ZERO..SINHALA LITH DIGIT NINE -0DF2..0DF3 ; N # Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA -0DF4 ; N # Po SINHALA PUNCTUATION KUNDDALIYA -0E01..0E30 ; N # Lo [48] THAI CHARACTER KO KAI..THAI CHARACTER SARA A -0E31 ; N # Mn THAI CHARACTER MAI HAN-AKAT -0E32..0E33 ; N # Lo [2] THAI CHARACTER SARA AA..THAI CHARACTER SARA AM -0E34..0E3A ; N # Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU -0E3F ; N # Sc THAI CURRENCY SYMBOL BAHT -0E40..0E45 ; N # Lo [6] THAI CHARACTER SARA E..THAI CHARACTER LAKKHANGYAO -0E46 ; N # Lm THAI CHARACTER MAIYAMOK -0E47..0E4E ; N # Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN -0E4F ; N # Po THAI CHARACTER FONGMAN -0E50..0E59 ; N # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE -0E5A..0E5B ; N # Po [2] THAI CHARACTER ANGKHANKHU..THAI CHARACTER KHOMUT -0E81..0E82 ; N # Lo [2] LAO LETTER KO..LAO LETTER KHO SUNG -0E84 ; N # Lo LAO LETTER KHO TAM -0E86..0E8A ; N # Lo [5] LAO LETTER PALI GHA..LAO LETTER SO TAM -0E8C..0EA3 ; N # Lo [24] LAO LETTER PALI JHA..LAO LETTER LO LING -0EA5 ; N # Lo LAO LETTER LO LOOT -0EA7..0EB0 ; N # Lo [10] LAO LETTER WO..LAO VOWEL SIGN A -0EB1 ; N # Mn LAO VOWEL SIGN MAI KAN -0EB2..0EB3 ; N # Lo [2] LAO VOWEL SIGN AA..LAO VOWEL SIGN AM -0EB4..0EBC ; N # Mn [9] LAO VOWEL SIGN I..LAO SEMIVOWEL SIGN LO -0EBD ; N # Lo LAO SEMIVOWEL SIGN NYO -0EC0..0EC4 ; N # Lo [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI -0EC6 ; N # Lm LAO KO LA -0EC8..0ECE ; N # Mn [7] LAO TONE MAI EK..LAO YAMAKKAN -0ED0..0ED9 ; N # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE -0EDC..0EDF ; N # Lo [4] LAO HO NO..LAO LETTER KHMU NYO -0F00 ; N # Lo TIBETAN SYLLABLE OM -0F01..0F03 ; N # So [3] TIBETAN MARK GTER YIG MGO TRUNCATED A..TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA -0F04..0F12 ; N # Po [15] TIBETAN MARK INITIAL YIG MGO MDUN MA..TIBETAN MARK RGYA GRAM SHAD -0F13 ; N # So TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN -0F14 ; N # Po TIBETAN MARK GTER TSHEG -0F15..0F17 ; N # So [3] TIBETAN LOGOTYPE SIGN CHAD RTAGS..TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS -0F18..0F19 ; N # Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS -0F1A..0F1F ; N # So [6] TIBETAN SIGN RDEL DKAR GCIG..TIBETAN SIGN RDEL DKAR RDEL NAG -0F20..0F29 ; N # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE -0F2A..0F33 ; N # No [10] TIBETAN DIGIT HALF ONE..TIBETAN DIGIT HALF ZERO -0F34 ; N # So TIBETAN MARK BSDUS RTAGS -0F35 ; N # Mn TIBETAN MARK NGAS BZUNG NYI ZLA -0F36 ; N # So TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN -0F37 ; N # Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS -0F38 ; N # So TIBETAN MARK CHE MGO -0F39 ; N # Mn TIBETAN MARK TSA -PHRU -0F3A ; N # Ps TIBETAN MARK GUG RTAGS GYON -0F3B ; N # Pe TIBETAN MARK GUG RTAGS GYAS -0F3C ; N # Ps TIBETAN MARK ANG KHANG GYON -0F3D ; N # Pe TIBETAN MARK ANG KHANG GYAS -0F3E..0F3F ; N # Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES -0F40..0F47 ; N # Lo [8] TIBETAN LETTER KA..TIBETAN LETTER JA -0F49..0F6C ; N # Lo [36] TIBETAN LETTER NYA..TIBETAN LETTER RRA -0F71..0F7E ; N # Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO -0F7F ; N # Mc TIBETAN SIGN RNAM BCAD -0F80..0F84 ; N # Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA -0F85 ; N # Po TIBETAN MARK PALUTA -0F86..0F87 ; N # Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS -0F88..0F8C ; N # Lo [5] TIBETAN SIGN LCE TSA CAN..TIBETAN SIGN INVERTED MCHU CAN -0F8D..0F97 ; N # Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA -0F99..0FBC ; N # Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA -0FBE..0FC5 ; N # So [8] TIBETAN KU RU KHA..TIBETAN SYMBOL RDO RJE -0FC6 ; N # Mn TIBETAN SYMBOL PADMA GDAN -0FC7..0FCC ; N # So [6] TIBETAN SYMBOL RDO RJE RGYA GRAM..TIBETAN SYMBOL NOR BU BZHI -KHYIL -0FCE..0FCF ; N # So [2] TIBETAN SIGN RDEL NAG RDEL DKAR..TIBETAN SIGN RDEL NAG GSUM -0FD0..0FD4 ; N # Po [5] TIBETAN MARK BSKA- SHOG GI MGO RGYAN..TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA -0FD5..0FD8 ; N # So [4] RIGHT-FACING SVASTI SIGN..LEFT-FACING SVASTI SIGN WITH DOTS -0FD9..0FDA ; N # Po [2] TIBETAN MARK LEADING MCHAN RTAGS..TIBETAN MARK TRAILING MCHAN RTAGS -1000..102A ; N # Lo [43] MYANMAR LETTER KA..MYANMAR LETTER AU -102B..102C ; N # Mc [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA -102D..1030 ; N # Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU -1031 ; N # Mc MYANMAR VOWEL SIGN E -1032..1037 ; N # Mn [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW -1038 ; N # Mc MYANMAR SIGN VISARGA -1039..103A ; N # Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT -103B..103C ; N # Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA -103D..103E ; N # Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA -103F ; N # Lo MYANMAR LETTER GREAT SA -1040..1049 ; N # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE -104A..104F ; N # Po [6] MYANMAR SIGN LITTLE SECTION..MYANMAR SYMBOL GENITIVE -1050..1055 ; N # Lo [6] MYANMAR LETTER SHA..MYANMAR LETTER VOCALIC LL -1056..1057 ; N # Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR -1058..1059 ; N # Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL -105A..105D ; N # Lo [4] MYANMAR LETTER MON NGA..MYANMAR LETTER MON BBE -105E..1060 ; N # Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA -1061 ; N # Lo MYANMAR LETTER SGAW KAREN SHA -1062..1064 ; N # Mc [3] MYANMAR VOWEL SIGN SGAW KAREN EU..MYANMAR TONE MARK SGAW KAREN KE PHO -1065..1066 ; N # Lo [2] MYANMAR LETTER WESTERN PWO KAREN THA..MYANMAR LETTER WESTERN PWO KAREN PWA -1067..106D ; N # Mc [7] MYANMAR VOWEL SIGN WESTERN PWO KAREN EU..MYANMAR SIGN WESTERN PWO KAREN TONE-5 -106E..1070 ; N # Lo [3] MYANMAR LETTER EASTERN PWO KAREN NNA..MYANMAR LETTER EASTERN PWO KAREN GHWA -1071..1074 ; N # Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE -1075..1081 ; N # Lo [13] MYANMAR LETTER SHAN KA..MYANMAR LETTER SHAN HA -1082 ; N # Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA -1083..1084 ; N # Mc [2] MYANMAR VOWEL SIGN SHAN AA..MYANMAR VOWEL SIGN SHAN E -1085..1086 ; N # Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y -1087..108C ; N # Mc [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3 -108D ; N # Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE -108E ; N # Lo MYANMAR LETTER RUMAI PALAUNG FA -108F ; N # Mc MYANMAR SIGN RUMAI PALAUNG TONE-5 -1090..1099 ; N # Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE -109A..109C ; N # Mc [3] MYANMAR SIGN KHAMTI TONE-1..MYANMAR VOWEL SIGN AITON A -109D ; N # Mn MYANMAR VOWEL SIGN AITON AI -109E..109F ; N # So [2] MYANMAR SYMBOL SHAN ONE..MYANMAR SYMBOL SHAN EXCLAMATION -10A0..10C5 ; N # Lu [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE -10C7 ; N # Lu GEORGIAN CAPITAL LETTER YN -10CD ; N # Lu GEORGIAN CAPITAL LETTER AEN -10D0..10FA ; N # Ll [43] GEORGIAN LETTER AN..GEORGIAN LETTER AIN -10FB ; N # Po GEORGIAN PARAGRAPH SEPARATOR -10FC ; N # Lm MODIFIER LETTER GEORGIAN NAR -10FD..10FF ; N # Ll [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN -1100..115F ; W # Lo [96] HANGUL CHOSEONG KIYEOK..HANGUL CHOSEONG FILLER -1160..11FF ; N # Lo [160] HANGUL JUNGSEONG FILLER..HANGUL JONGSEONG SSANGNIEUN -1200..1248 ; N # Lo [73] ETHIOPIC SYLLABLE HA..ETHIOPIC SYLLABLE QWA -124A..124D ; N # Lo [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE -1250..1256 ; N # Lo [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO -1258 ; N # Lo ETHIOPIC SYLLABLE QHWA -125A..125D ; N # Lo [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE -1260..1288 ; N # Lo [41] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XWA -128A..128D ; N # Lo [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE -1290..12B0 ; N # Lo [33] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KWA -12B2..12B5 ; N # Lo [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE -12B8..12BE ; N # Lo [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO -12C0 ; N # Lo ETHIOPIC SYLLABLE KXWA -12C2..12C5 ; N # Lo [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE -12C8..12D6 ; N # Lo [15] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE PHARYNGEAL O -12D8..1310 ; N # Lo [57] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE GWA -1312..1315 ; N # Lo [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE -1318..135A ; N # Lo [67] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE FYA -135D..135F ; N # Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK -1360..1368 ; N # Po [9] ETHIOPIC SECTION MARK..ETHIOPIC PARAGRAPH SEPARATOR -1369..137C ; N # No [20] ETHIOPIC DIGIT ONE..ETHIOPIC NUMBER TEN THOUSAND -1380..138F ; N # Lo [16] ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE -1390..1399 ; N # So [10] ETHIOPIC TONAL MARK YIZET..ETHIOPIC TONAL MARK KURT -13A0..13F5 ; N # Lu [86] CHEROKEE LETTER A..CHEROKEE LETTER MV -13F8..13FD ; N # Ll [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV -1400 ; N # Pd CANADIAN SYLLABICS HYPHEN -1401..166C ; N # Lo [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA -166D ; N # So CANADIAN SYLLABICS CHI SIGN -166E ; N # Po CANADIAN SYLLABICS FULL STOP -166F..167F ; N # Lo [17] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS BLACKFOOT W -1680 ; N # Zs OGHAM SPACE MARK -1681..169A ; N # Lo [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH -169B ; N # Ps OGHAM FEATHER MARK -169C ; N # Pe OGHAM REVERSED FEATHER MARK -16A0..16EA ; N # Lo [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X -16EB..16ED ; N # Po [3] RUNIC SINGLE PUNCTUATION..RUNIC CROSS PUNCTUATION -16EE..16F0 ; N # Nl [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL -16F1..16F8 ; N # Lo [8] RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC -1700..1711 ; N # Lo [18] TAGALOG LETTER A..TAGALOG LETTER HA -1712..1714 ; N # Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA -1715 ; N # Mc TAGALOG SIGN PAMUDPOD -171F ; N # Lo TAGALOG LETTER ARCHAIC RA -1720..1731 ; N # Lo [18] HANUNOO LETTER A..HANUNOO LETTER HA -1732..1733 ; N # Mn [2] HANUNOO VOWEL SIGN I..HANUNOO VOWEL SIGN U -1734 ; N # Mc HANUNOO SIGN PAMUDPOD -1735..1736 ; N # Po [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION -1740..1751 ; N # Lo [18] BUHID LETTER A..BUHID LETTER HA -1752..1753 ; N # Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U -1760..176C ; N # Lo [13] TAGBANWA LETTER A..TAGBANWA LETTER YA -176E..1770 ; N # Lo [3] TAGBANWA LETTER LA..TAGBANWA LETTER SA -1772..1773 ; N # Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U -1780..17B3 ; N # Lo [52] KHMER LETTER KA..KHMER INDEPENDENT VOWEL QAU -17B4..17B5 ; N # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA -17B6 ; N # Mc KHMER VOWEL SIGN AA -17B7..17BD ; N # Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA -17BE..17C5 ; N # Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU -17C6 ; N # Mn KHMER SIGN NIKAHIT -17C7..17C8 ; N # Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU -17C9..17D3 ; N # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT -17D4..17D6 ; N # Po [3] KHMER SIGN KHAN..KHMER SIGN CAMNUC PII KUUH -17D7 ; N # Lm KHMER SIGN LEK TOO -17D8..17DA ; N # Po [3] KHMER SIGN BEYYAL..KHMER SIGN KOOMUUT -17DB ; N # Sc KHMER CURRENCY SYMBOL RIEL -17DC ; N # Lo KHMER SIGN AVAKRAHASANYA -17DD ; N # Mn KHMER SIGN ATTHACAN -17E0..17E9 ; N # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE -17F0..17F9 ; N # No [10] KHMER SYMBOL LEK ATTAK SON..KHMER SYMBOL LEK ATTAK PRAM-BUON -1800..1805 ; N # Po [6] MONGOLIAN BIRGA..MONGOLIAN FOUR DOTS -1806 ; N # Pd MONGOLIAN TODO SOFT HYPHEN -1807..180A ; N # Po [4] MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER..MONGOLIAN NIRUGU -180B..180D ; N # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE -180E ; N # Cf MONGOLIAN VOWEL SEPARATOR -180F ; N # Mn MONGOLIAN FREE VARIATION SELECTOR FOUR -1810..1819 ; N # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE -1820..1842 ; N # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI -1843 ; N # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN -1844..1878 ; N # Lo [53] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER CHA WITH TWO DOTS -1880..1884 ; N # Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA -1885..1886 ; N # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA -1887..18A8 ; N # Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA -18A9 ; N # Mn MONGOLIAN LETTER ALI GALI DAGALGA -18AA ; N # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA -18B0..18F5 ; N # Lo [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S -1900..191E ; N # Lo [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA -1920..1922 ; N # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U -1923..1926 ; N # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU -1927..1928 ; N # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O -1929..192B ; N # Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA -1930..1931 ; N # Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA -1932 ; N # Mn LIMBU SMALL LETTER ANUSVARA -1933..1938 ; N # Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA -1939..193B ; N # Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I -1940 ; N # So LIMBU SIGN LOO -1944..1945 ; N # Po [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK -1946..194F ; N # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE -1950..196D ; N # Lo [30] TAI LE LETTER KA..TAI LE LETTER AI -1970..1974 ; N # Lo [5] TAI LE LETTER TONE-2..TAI LE LETTER TONE-6 -1980..19AB ; N # Lo [44] NEW TAI LUE LETTER HIGH QA..NEW TAI LUE LETTER LOW SUA -19B0..19C9 ; N # Lo [26] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE TONE MARK-2 -19D0..19D9 ; N # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE -19DA ; N # No NEW TAI LUE THAM DIGIT ONE -19DE..19DF ; N # So [2] NEW TAI LUE SIGN LAE..NEW TAI LUE SIGN LAEV -19E0..19FF ; N # So [32] KHMER SYMBOL PATHAMASAT..KHMER SYMBOL DAP-PRAM ROC -1A00..1A16 ; N # Lo [23] BUGINESE LETTER KA..BUGINESE LETTER HA -1A17..1A18 ; N # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U -1A19..1A1A ; N # Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O -1A1B ; N # Mn BUGINESE VOWEL SIGN AE -1A1E..1A1F ; N # Po [2] BUGINESE PALLAWA..BUGINESE END OF SECTION -1A20..1A54 ; N # Lo [53] TAI THAM LETTER HIGH KA..TAI THAM LETTER GREAT SA -1A55 ; N # Mc TAI THAM CONSONANT SIGN MEDIAL RA -1A56 ; N # Mn TAI THAM CONSONANT SIGN MEDIAL LA -1A57 ; N # Mc TAI THAM CONSONANT SIGN LA TANG LAI -1A58..1A5E ; N # Mn [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA -1A60 ; N # Mn TAI THAM SIGN SAKOT -1A61 ; N # Mc TAI THAM VOWEL SIGN A -1A62 ; N # Mn TAI THAM VOWEL SIGN MAI SAT -1A63..1A64 ; N # Mc [2] TAI THAM VOWEL SIGN AA..TAI THAM VOWEL SIGN TALL AA -1A65..1A6C ; N # Mn [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW -1A6D..1A72 ; N # Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI -1A73..1A7C ; N # Mn [10] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN KHUEN-LUE KARAN -1A7F ; N # Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT -1A80..1A89 ; N # Nd [10] TAI THAM HORA DIGIT ZERO..TAI THAM HORA DIGIT NINE -1A90..1A99 ; N # Nd [10] TAI THAM THAM DIGIT ZERO..TAI THAM THAM DIGIT NINE -1AA0..1AA6 ; N # Po [7] TAI THAM SIGN WIANG..TAI THAM SIGN REVERSED ROTATED RANA -1AA7 ; N # Lm TAI THAM SIGN MAI YAMOK -1AA8..1AAD ; N # Po [6] TAI THAM SIGN KAAN..TAI THAM SIGN CAANG -1AB0..1ABD ; N # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW -1ABE ; N # Me COMBINING PARENTHESES OVERLAY -1ABF..1ACE ; N # Mn [16] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER INSULAR T -1B00..1B03 ; N # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG -1B04 ; N # Mc BALINESE SIGN BISAH -1B05..1B33 ; N # Lo [47] BALINESE LETTER AKARA..BALINESE LETTER HA -1B34 ; N # Mn BALINESE SIGN REREKAN -1B35 ; N # Mc BALINESE VOWEL SIGN TEDUNG -1B36..1B3A ; N # Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA -1B3B ; N # Mc BALINESE VOWEL SIGN RA REPA TEDUNG -1B3C ; N # Mn BALINESE VOWEL SIGN LA LENGA -1B3D..1B41 ; N # Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG -1B42 ; N # Mn BALINESE VOWEL SIGN PEPET -1B43..1B44 ; N # Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG -1B45..1B4C ; N # Lo [8] BALINESE LETTER KAF SASAK..BALINESE LETTER ARCHAIC JNYA -1B50..1B59 ; N # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE -1B5A..1B60 ; N # Po [7] BALINESE PANTI..BALINESE PAMENENG -1B61..1B6A ; N # So [10] BALINESE MUSICAL SYMBOL DONG..BALINESE MUSICAL SYMBOL DANG GEDE -1B6B..1B73 ; N # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG -1B74..1B7C ; N # So [9] BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG..BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING -1B7D..1B7E ; N # Po [2] BALINESE PANTI LANTANG..BALINESE PAMADA LANTANG -1B80..1B81 ; N # Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR -1B82 ; N # Mc SUNDANESE SIGN PANGWISAD -1B83..1BA0 ; N # Lo [30] SUNDANESE LETTER A..SUNDANESE LETTER HA -1BA1 ; N # Mc SUNDANESE CONSONANT SIGN PAMINGKAL -1BA2..1BA5 ; N # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU -1BA6..1BA7 ; N # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG -1BA8..1BA9 ; N # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG -1BAA ; N # Mc SUNDANESE SIGN PAMAAEH -1BAB..1BAD ; N # Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA -1BAE..1BAF ; N # Lo [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA -1BB0..1BB9 ; N # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE -1BBA..1BBF ; N # Lo [6] SUNDANESE AVAGRAHA..SUNDANESE LETTER FINAL M -1BC0..1BE5 ; N # Lo [38] BATAK LETTER A..BATAK LETTER U -1BE6 ; N # Mn BATAK SIGN TOMPI -1BE7 ; N # Mc BATAK VOWEL SIGN E -1BE8..1BE9 ; N # Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE -1BEA..1BEC ; N # Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O -1BED ; N # Mn BATAK VOWEL SIGN KARO O -1BEE ; N # Mc BATAK VOWEL SIGN U -1BEF..1BF1 ; N # Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H -1BF2..1BF3 ; N # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN -1BFC..1BFF ; N # Po [4] BATAK SYMBOL BINDU NA METEK..BATAK SYMBOL BINDU PANGOLAT -1C00..1C23 ; N # Lo [36] LEPCHA LETTER KA..LEPCHA LETTER A -1C24..1C2B ; N # Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU -1C2C..1C33 ; N # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T -1C34..1C35 ; N # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG -1C36..1C37 ; N # Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA -1C3B..1C3F ; N # Po [5] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION TSHOOK -1C40..1C49 ; N # Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE -1C4D..1C4F ; N # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA -1C50..1C59 ; N # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE -1C5A..1C77 ; N # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH -1C78..1C7D ; N # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD -1C7E..1C7F ; N # Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD -1C80..1C88 ; N # Ll [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK -1C90..1CBA ; N # Lu [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN -1CBD..1CBF ; N # Lu [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN -1CC0..1CC7 ; N # Po [8] SUNDANESE PUNCTUATION BINDU SURYA..SUNDANESE PUNCTUATION BINDU BA SATANGA -1CD0..1CD2 ; N # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA -1CD3 ; N # Po VEDIC SIGN NIHSHVASA -1CD4..1CE0 ; N # Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA -1CE1 ; N # Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA -1CE2..1CE8 ; N # Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL -1CE9..1CEC ; N # Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL -1CED ; N # Mn VEDIC SIGN TIRYAK -1CEE..1CF3 ; N # Lo [6] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ROTATED ARDHAVISARGA -1CF4 ; N # Mn VEDIC TONE CANDRA ABOVE -1CF5..1CF6 ; N # Lo [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA -1CF7 ; N # Mc VEDIC SIGN ATIKRAMA -1CF8..1CF9 ; N # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE -1CFA ; N # Lo VEDIC SIGN DOUBLE ANUSVARA ANTARGOMUKHA -1D00..1D2B ; N # Ll [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL -1D2C..1D6A ; N # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI -1D6B..1D77 ; N # Ll [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G -1D78 ; N # Lm MODIFIER LETTER CYRILLIC EN -1D79..1D7F ; N # Ll [7] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER UPSILON WITH STROKE -1D80..1D9A ; N # Ll [27] LATIN SMALL LETTER B WITH PALATAL HOOK..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK -1D9B..1DBF ; N # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA -1DC0..1DFF ; N # Mn [64] COMBINING DOTTED GRAVE ACCENT..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW -1E00..1EFF ; N # L& [256] LATIN CAPITAL LETTER A WITH RING BELOW..LATIN SMALL LETTER Y WITH LOOP -1F00..1F15 ; N # L& [22] GREEK SMALL LETTER ALPHA WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA -1F18..1F1D ; N # Lu [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA -1F20..1F45 ; N # L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA -1F48..1F4D ; N # Lu [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA -1F50..1F57 ; N # Ll [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI -1F59 ; N # Lu GREEK CAPITAL LETTER UPSILON WITH DASIA -1F5B ; N # Lu GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA -1F5D ; N # Lu GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA -1F5F..1F7D ; N # L& [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA -1F80..1FB4 ; N # L& [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI -1FB6..1FBC ; N # L& [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI -1FBD ; N # Sk GREEK KORONIS -1FBE ; N # Ll GREEK PROSGEGRAMMENI -1FBF..1FC1 ; N # Sk [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI -1FC2..1FC4 ; N # Ll [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI -1FC6..1FCC ; N # L& [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI -1FCD..1FCF ; N # Sk [3] GREEK PSILI AND VARIA..GREEK PSILI AND PERISPOMENI -1FD0..1FD3 ; N # Ll [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA -1FD6..1FDB ; N # L& [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA -1FDD..1FDF ; N # Sk [3] GREEK DASIA AND VARIA..GREEK DASIA AND PERISPOMENI -1FE0..1FEC ; N # L& [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA -1FED..1FEF ; N # Sk [3] GREEK DIALYTIKA AND VARIA..GREEK VARIA -1FF2..1FF4 ; N # Ll [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI -1FF6..1FFC ; N # L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI -1FFD..1FFE ; N # Sk [2] GREEK OXIA..GREEK DASIA -2000..200A ; N # Zs [11] EN QUAD..HAIR SPACE -200B..200F ; N # Cf [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK -2010 ; A # Pd HYPHEN -2011..2012 ; N # Pd [2] NON-BREAKING HYPHEN..FIGURE DASH -2013..2015 ; A # Pd [3] EN DASH..HORIZONTAL BAR -2016 ; A # Po DOUBLE VERTICAL LINE -2017 ; N # Po DOUBLE LOW LINE -2018 ; A # Pi LEFT SINGLE QUOTATION MARK -2019 ; A # Pf RIGHT SINGLE QUOTATION MARK -201A ; N # Ps SINGLE LOW-9 QUOTATION MARK -201B ; N # Pi SINGLE HIGH-REVERSED-9 QUOTATION MARK -201C ; A # Pi LEFT DOUBLE QUOTATION MARK -201D ; A # Pf RIGHT DOUBLE QUOTATION MARK -201E ; N # Ps DOUBLE LOW-9 QUOTATION MARK -201F ; N # Pi DOUBLE HIGH-REVERSED-9 QUOTATION MARK -2020..2022 ; A # Po [3] DAGGER..BULLET -2023 ; N # Po TRIANGULAR BULLET -2024..2027 ; A # Po [4] ONE DOT LEADER..HYPHENATION POINT -2028 ; N # Zl LINE SEPARATOR -2029 ; N # Zp PARAGRAPH SEPARATOR -202A..202E ; N # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE -202F ; N # Zs NARROW NO-BREAK SPACE -2030 ; A # Po PER MILLE SIGN -2031 ; N # Po PER TEN THOUSAND SIGN -2032..2033 ; A # Po [2] PRIME..DOUBLE PRIME -2034 ; N # Po TRIPLE PRIME -2035 ; A # Po REVERSED PRIME -2036..2038 ; N # Po [3] REVERSED DOUBLE PRIME..CARET -2039 ; N # Pi SINGLE LEFT-POINTING ANGLE QUOTATION MARK -203A ; N # Pf SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -203B ; A # Po REFERENCE MARK -203C..203D ; N # Po [2] DOUBLE EXCLAMATION MARK..INTERROBANG -203E ; A # Po OVERLINE -203F..2040 ; N # Pc [2] UNDERTIE..CHARACTER TIE -2041..2043 ; N # Po [3] CARET INSERTION POINT..HYPHEN BULLET -2044 ; N # Sm FRACTION SLASH -2045 ; N # Ps LEFT SQUARE BRACKET WITH QUILL -2046 ; N # Pe RIGHT SQUARE BRACKET WITH QUILL -2047..2051 ; N # Po [11] DOUBLE QUESTION MARK..TWO ASTERISKS ALIGNED VERTICALLY -2052 ; N # Sm COMMERCIAL MINUS SIGN -2053 ; N # Po SWUNG DASH -2054 ; N # Pc INVERTED UNDERTIE -2055..205E ; N # Po [10] FLOWER PUNCTUATION MARK..VERTICAL FOUR DOTS -205F ; N # Zs MEDIUM MATHEMATICAL SPACE -2060..2064 ; N # Cf [5] WORD JOINER..INVISIBLE PLUS -2066..206F ; N # Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES -2070 ; N # No SUPERSCRIPT ZERO -2071 ; N # Lm SUPERSCRIPT LATIN SMALL LETTER I -2074 ; A # No SUPERSCRIPT FOUR -2075..2079 ; N # No [5] SUPERSCRIPT FIVE..SUPERSCRIPT NINE -207A..207C ; N # Sm [3] SUPERSCRIPT PLUS SIGN..SUPERSCRIPT EQUALS SIGN -207D ; N # Ps SUPERSCRIPT LEFT PARENTHESIS -207E ; N # Pe SUPERSCRIPT RIGHT PARENTHESIS -207F ; A # Lm SUPERSCRIPT LATIN SMALL LETTER N -2080 ; N # No SUBSCRIPT ZERO -2081..2084 ; A # No [4] SUBSCRIPT ONE..SUBSCRIPT FOUR -2085..2089 ; N # No [5] SUBSCRIPT FIVE..SUBSCRIPT NINE -208A..208C ; N # Sm [3] SUBSCRIPT PLUS SIGN..SUBSCRIPT EQUALS SIGN -208D ; N # Ps SUBSCRIPT LEFT PARENTHESIS -208E ; N # Pe SUBSCRIPT RIGHT PARENTHESIS -2090..209C ; N # Lm [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T -20A0..20A8 ; N # Sc [9] EURO-CURRENCY SIGN..RUPEE SIGN -20A9 ; H # Sc WON SIGN -20AA..20AB ; N # Sc [2] NEW SHEQEL SIGN..DONG SIGN -20AC ; A # Sc EURO SIGN -20AD..20C0 ; N # Sc [20] KIP SIGN..SOM SIGN -20D0..20DC ; N # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE -20DD..20E0 ; N # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH -20E1 ; N # Mn COMBINING LEFT RIGHT ARROW ABOVE -20E2..20E4 ; N # Me [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE -20E5..20F0 ; N # Mn [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE -2100..2101 ; N # So [2] ACCOUNT OF..ADDRESSED TO THE SUBJECT -2102 ; N # Lu DOUBLE-STRUCK CAPITAL C -2103 ; A # So DEGREE CELSIUS -2104 ; N # So CENTRE LINE SYMBOL -2105 ; A # So CARE OF -2106 ; N # So CADA UNA -2107 ; N # Lu EULER CONSTANT -2108 ; N # So SCRUPLE -2109 ; A # So DEGREE FAHRENHEIT -210A..2112 ; N # L& [9] SCRIPT SMALL G..SCRIPT CAPITAL L -2113 ; A # Ll SCRIPT SMALL L -2114 ; N # So L B BAR SYMBOL -2115 ; N # Lu DOUBLE-STRUCK CAPITAL N -2116 ; A # So NUMERO SIGN -2117 ; N # So SOUND RECORDING COPYRIGHT -2118 ; N # Sm SCRIPT CAPITAL P -2119..211D ; N # Lu [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R -211E..2120 ; N # So [3] PRESCRIPTION TAKE..SERVICE MARK -2121..2122 ; A # So [2] TELEPHONE SIGN..TRADE MARK SIGN -2123 ; N # So VERSICLE -2124 ; N # Lu DOUBLE-STRUCK CAPITAL Z -2125 ; N # So OUNCE SIGN -2126 ; A # Lu OHM SIGN -2127 ; N # So INVERTED OHM SIGN -2128 ; N # Lu BLACK-LETTER CAPITAL Z -2129 ; N # So TURNED GREEK SMALL LETTER IOTA -212A ; N # Lu KELVIN SIGN -212B ; A # Lu ANGSTROM SIGN -212C..212D ; N # Lu [2] SCRIPT CAPITAL B..BLACK-LETTER CAPITAL C -212E ; N # So ESTIMATED SYMBOL -212F..2134 ; N # L& [6] SCRIPT SMALL E..SCRIPT SMALL O -2135..2138 ; N # Lo [4] ALEF SYMBOL..DALET SYMBOL -2139 ; N # Ll INFORMATION SOURCE -213A..213B ; N # So [2] ROTATED CAPITAL Q..FACSIMILE SIGN -213C..213F ; N # L& [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI -2140..2144 ; N # Sm [5] DOUBLE-STRUCK N-ARY SUMMATION..TURNED SANS-SERIF CAPITAL Y -2145..2149 ; N # L& [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J -214A ; N # So PROPERTY LINE -214B ; N # Sm TURNED AMPERSAND -214C..214D ; N # So [2] PER SIGN..AKTIESELSKAB -214E ; N # Ll TURNED SMALL F -214F ; N # So SYMBOL FOR SAMARITAN SOURCE -2150..2152 ; N # No [3] VULGAR FRACTION ONE SEVENTH..VULGAR FRACTION ONE TENTH -2153..2154 ; A # No [2] VULGAR FRACTION ONE THIRD..VULGAR FRACTION TWO THIRDS -2155..215A ; N # No [6] VULGAR FRACTION ONE FIFTH..VULGAR FRACTION FIVE SIXTHS -215B..215E ; A # No [4] VULGAR FRACTION ONE EIGHTH..VULGAR FRACTION SEVEN EIGHTHS -215F ; N # No FRACTION NUMERATOR ONE -2160..216B ; A # Nl [12] ROMAN NUMERAL ONE..ROMAN NUMERAL TWELVE -216C..216F ; N # Nl [4] ROMAN NUMERAL FIFTY..ROMAN NUMERAL ONE THOUSAND -2170..2179 ; A # Nl [10] SMALL ROMAN NUMERAL ONE..SMALL ROMAN NUMERAL TEN -217A..2182 ; N # Nl [9] SMALL ROMAN NUMERAL ELEVEN..ROMAN NUMERAL TEN THOUSAND -2183..2184 ; N # L& [2] ROMAN NUMERAL REVERSED ONE HUNDRED..LATIN SMALL LETTER REVERSED C -2185..2188 ; N # Nl [4] ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND -2189 ; A # No VULGAR FRACTION ZERO THIRDS -218A..218B ; N # So [2] TURNED DIGIT TWO..TURNED DIGIT THREE -2190..2194 ; A # Sm [5] LEFTWARDS ARROW..LEFT RIGHT ARROW -2195..2199 ; A # So [5] UP DOWN ARROW..SOUTH WEST ARROW -219A..219B ; N # Sm [2] LEFTWARDS ARROW WITH STROKE..RIGHTWARDS ARROW WITH STROKE -219C..219F ; N # So [4] LEFTWARDS WAVE ARROW..UPWARDS TWO HEADED ARROW -21A0 ; N # Sm RIGHTWARDS TWO HEADED ARROW -21A1..21A2 ; N # So [2] DOWNWARDS TWO HEADED ARROW..LEFTWARDS ARROW WITH TAIL -21A3 ; N # Sm RIGHTWARDS ARROW WITH TAIL -21A4..21A5 ; N # So [2] LEFTWARDS ARROW FROM BAR..UPWARDS ARROW FROM BAR -21A6 ; N # Sm RIGHTWARDS ARROW FROM BAR -21A7..21AD ; N # So [7] DOWNWARDS ARROW FROM BAR..LEFT RIGHT WAVE ARROW -21AE ; N # Sm LEFT RIGHT ARROW WITH STROKE -21AF..21B7 ; N # So [9] DOWNWARDS ZIGZAG ARROW..CLOCKWISE TOP SEMICIRCLE ARROW -21B8..21B9 ; A # So [2] NORTH WEST ARROW TO LONG BAR..LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR -21BA..21CD ; N # So [20] ANTICLOCKWISE OPEN CIRCLE ARROW..LEFTWARDS DOUBLE ARROW WITH STROKE -21CE..21CF ; N # Sm [2] LEFT RIGHT DOUBLE ARROW WITH STROKE..RIGHTWARDS DOUBLE ARROW WITH STROKE -21D0..21D1 ; N # So [2] LEFTWARDS DOUBLE ARROW..UPWARDS DOUBLE ARROW -21D2 ; A # Sm RIGHTWARDS DOUBLE ARROW -21D3 ; N # So DOWNWARDS DOUBLE ARROW -21D4 ; A # Sm LEFT RIGHT DOUBLE ARROW -21D5..21E6 ; N # So [18] UP DOWN DOUBLE ARROW..LEFTWARDS WHITE ARROW -21E7 ; A # So UPWARDS WHITE ARROW -21E8..21F3 ; N # So [12] RIGHTWARDS WHITE ARROW..UP DOWN WHITE ARROW -21F4..21FF ; N # Sm [12] RIGHT ARROW WITH SMALL CIRCLE..LEFT RIGHT OPEN-HEADED ARROW -2200 ; A # Sm FOR ALL -2201 ; N # Sm COMPLEMENT -2202..2203 ; A # Sm [2] PARTIAL DIFFERENTIAL..THERE EXISTS -2204..2206 ; N # Sm [3] THERE DOES NOT EXIST..INCREMENT -2207..2208 ; A # Sm [2] NABLA..ELEMENT OF -2209..220A ; N # Sm [2] NOT AN ELEMENT OF..SMALL ELEMENT OF -220B ; A # Sm CONTAINS AS MEMBER -220C..220E ; N # Sm [3] DOES NOT CONTAIN AS MEMBER..END OF PROOF -220F ; A # Sm N-ARY PRODUCT -2210 ; N # Sm N-ARY COPRODUCT -2211 ; A # Sm N-ARY SUMMATION -2212..2214 ; N # Sm [3] MINUS SIGN..DOT PLUS -2215 ; A # Sm DIVISION SLASH -2216..2219 ; N # Sm [4] SET MINUS..BULLET OPERATOR -221A ; A # Sm SQUARE ROOT -221B..221C ; N # Sm [2] CUBE ROOT..FOURTH ROOT -221D..2220 ; A # Sm [4] PROPORTIONAL TO..ANGLE -2221..2222 ; N # Sm [2] MEASURED ANGLE..SPHERICAL ANGLE -2223 ; A # Sm DIVIDES -2224 ; N # Sm DOES NOT DIVIDE -2225 ; A # Sm PARALLEL TO -2226 ; N # Sm NOT PARALLEL TO -2227..222C ; A # Sm [6] LOGICAL AND..DOUBLE INTEGRAL -222D ; N # Sm TRIPLE INTEGRAL -222E ; A # Sm CONTOUR INTEGRAL -222F..2233 ; N # Sm [5] SURFACE INTEGRAL..ANTICLOCKWISE CONTOUR INTEGRAL -2234..2237 ; A # Sm [4] THEREFORE..PROPORTION -2238..223B ; N # Sm [4] DOT MINUS..HOMOTHETIC -223C..223D ; A # Sm [2] TILDE OPERATOR..REVERSED TILDE -223E..2247 ; N # Sm [10] INVERTED LAZY S..NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO -2248 ; A # Sm ALMOST EQUAL TO -2249..224B ; N # Sm [3] NOT ALMOST EQUAL TO..TRIPLE TILDE -224C ; A # Sm ALL EQUAL TO -224D..2251 ; N # Sm [5] EQUIVALENT TO..GEOMETRICALLY EQUAL TO -2252 ; A # Sm APPROXIMATELY EQUAL TO OR THE IMAGE OF -2253..225F ; N # Sm [13] IMAGE OF OR APPROXIMATELY EQUAL TO..QUESTIONED EQUAL TO -2260..2261 ; A # Sm [2] NOT EQUAL TO..IDENTICAL TO -2262..2263 ; N # Sm [2] NOT IDENTICAL TO..STRICTLY EQUIVALENT TO -2264..2267 ; A # Sm [4] LESS-THAN OR EQUAL TO..GREATER-THAN OVER EQUAL TO -2268..2269 ; N # Sm [2] LESS-THAN BUT NOT EQUAL TO..GREATER-THAN BUT NOT EQUAL TO -226A..226B ; A # Sm [2] MUCH LESS-THAN..MUCH GREATER-THAN -226C..226D ; N # Sm [2] BETWEEN..NOT EQUIVALENT TO -226E..226F ; A # Sm [2] NOT LESS-THAN..NOT GREATER-THAN -2270..2281 ; N # Sm [18] NEITHER LESS-THAN NOR EQUAL TO..DOES NOT SUCCEED -2282..2283 ; A # Sm [2] SUBSET OF..SUPERSET OF -2284..2285 ; N # Sm [2] NOT A SUBSET OF..NOT A SUPERSET OF -2286..2287 ; A # Sm [2] SUBSET OF OR EQUAL TO..SUPERSET OF OR EQUAL TO -2288..2294 ; N # Sm [13] NEITHER A SUBSET OF NOR EQUAL TO..SQUARE CUP -2295 ; A # Sm CIRCLED PLUS -2296..2298 ; N # Sm [3] CIRCLED MINUS..CIRCLED DIVISION SLASH -2299 ; A # Sm CIRCLED DOT OPERATOR -229A..22A4 ; N # Sm [11] CIRCLED RING OPERATOR..DOWN TACK -22A5 ; A # Sm UP TACK -22A6..22BE ; N # Sm [25] ASSERTION..RIGHT ANGLE WITH ARC -22BF ; A # Sm RIGHT TRIANGLE -22C0..22FF ; N # Sm [64] N-ARY LOGICAL AND..Z NOTATION BAG MEMBERSHIP -2300..2307 ; N # So [8] DIAMETER SIGN..WAVY LINE -2308 ; N # Ps LEFT CEILING -2309 ; N # Pe RIGHT CEILING -230A ; N # Ps LEFT FLOOR -230B ; N # Pe RIGHT FLOOR -230C..2311 ; N # So [6] BOTTOM RIGHT CROP..SQUARE LOZENGE -2312 ; A # So ARC -2313..2319 ; N # So [7] SEGMENT..TURNED NOT SIGN -231A..231B ; W # So [2] WATCH..HOURGLASS -231C..231F ; N # So [4] TOP LEFT CORNER..BOTTOM RIGHT CORNER -2320..2321 ; N # Sm [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL -2322..2328 ; N # So [7] FROWN..KEYBOARD -2329 ; W # Ps LEFT-POINTING ANGLE BRACKET -232A ; W # Pe RIGHT-POINTING ANGLE BRACKET -232B..237B ; N # So [81] ERASE TO THE LEFT..NOT CHECK MARK -237C ; N # Sm RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW -237D..239A ; N # So [30] SHOULDERED OPEN BOX..CLEAR SCREEN SYMBOL -239B..23B3 ; N # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM -23B4..23DB ; N # So [40] TOP SQUARE BRACKET..FUSE -23DC..23E1 ; N # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET -23E2..23E8 ; N # So [7] WHITE TRAPEZIUM..DECIMAL EXPONENT SYMBOL -23E9..23EC ; W # So [4] BLACK RIGHT-POINTING DOUBLE TRIANGLE..BLACK DOWN-POINTING DOUBLE TRIANGLE -23ED..23EF ; N # So [3] BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR..BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR -23F0 ; W # So ALARM CLOCK -23F1..23F2 ; N # So [2] STOPWATCH..TIMER CLOCK -23F3 ; W # So HOURGLASS WITH FLOWING SAND -23F4..23FF ; N # So [12] BLACK MEDIUM LEFT-POINTING TRIANGLE..OBSERVER EYE SYMBOL -2400..2426 ; N # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO -2440..244A ; N # So [11] OCR HOOK..OCR DOUBLE BACKSLASH -2460..249B ; A # No [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP -249C..24E9 ; A # So [78] PARENTHESIZED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z -24EA ; N # No CIRCLED DIGIT ZERO -24EB..24FF ; A # No [21] NEGATIVE CIRCLED NUMBER ELEVEN..NEGATIVE CIRCLED DIGIT ZERO -2500..254B ; A # So [76] BOX DRAWINGS LIGHT HORIZONTAL..BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL -254C..254F ; N # So [4] BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL..BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL -2550..2573 ; A # So [36] BOX DRAWINGS DOUBLE HORIZONTAL..BOX DRAWINGS LIGHT DIAGONAL CROSS -2574..257F ; N # So [12] BOX DRAWINGS LIGHT LEFT..BOX DRAWINGS HEAVY UP AND LIGHT DOWN -2580..258F ; A # So [16] UPPER HALF BLOCK..LEFT ONE EIGHTH BLOCK -2590..2591 ; N # So [2] RIGHT HALF BLOCK..LIGHT SHADE -2592..2595 ; A # So [4] MEDIUM SHADE..RIGHT ONE EIGHTH BLOCK -2596..259F ; N # So [10] QUADRANT LOWER LEFT..QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT -25A0..25A1 ; A # So [2] BLACK SQUARE..WHITE SQUARE -25A2 ; N # So WHITE SQUARE WITH ROUNDED CORNERS -25A3..25A9 ; A # So [7] WHITE SQUARE CONTAINING BLACK SMALL SQUARE..SQUARE WITH DIAGONAL CROSSHATCH FILL -25AA..25B1 ; N # So [8] BLACK SMALL SQUARE..WHITE PARALLELOGRAM -25B2..25B3 ; A # So [2] BLACK UP-POINTING TRIANGLE..WHITE UP-POINTING TRIANGLE -25B4..25B5 ; N # So [2] BLACK UP-POINTING SMALL TRIANGLE..WHITE UP-POINTING SMALL TRIANGLE -25B6 ; A # So BLACK RIGHT-POINTING TRIANGLE -25B7 ; A # Sm WHITE RIGHT-POINTING TRIANGLE -25B8..25BB ; N # So [4] BLACK RIGHT-POINTING SMALL TRIANGLE..WHITE RIGHT-POINTING POINTER -25BC..25BD ; A # So [2] BLACK DOWN-POINTING TRIANGLE..WHITE DOWN-POINTING TRIANGLE -25BE..25BF ; N # So [2] BLACK DOWN-POINTING SMALL TRIANGLE..WHITE DOWN-POINTING SMALL TRIANGLE -25C0 ; A # So BLACK LEFT-POINTING TRIANGLE -25C1 ; A # Sm WHITE LEFT-POINTING TRIANGLE -25C2..25C5 ; N # So [4] BLACK LEFT-POINTING SMALL TRIANGLE..WHITE LEFT-POINTING POINTER -25C6..25C8 ; A # So [3] BLACK DIAMOND..WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND -25C9..25CA ; N # So [2] FISHEYE..LOZENGE -25CB ; A # So WHITE CIRCLE -25CC..25CD ; N # So [2] DOTTED CIRCLE..CIRCLE WITH VERTICAL FILL -25CE..25D1 ; A # So [4] BULLSEYE..CIRCLE WITH RIGHT HALF BLACK -25D2..25E1 ; N # So [16] CIRCLE WITH LOWER HALF BLACK..LOWER HALF CIRCLE -25E2..25E5 ; A # So [4] BLACK LOWER RIGHT TRIANGLE..BLACK UPPER RIGHT TRIANGLE -25E6..25EE ; N # So [9] WHITE BULLET..UP-POINTING TRIANGLE WITH RIGHT HALF BLACK -25EF ; A # So LARGE CIRCLE -25F0..25F7 ; N # So [8] WHITE SQUARE WITH UPPER LEFT QUADRANT..WHITE CIRCLE WITH UPPER RIGHT QUADRANT -25F8..25FC ; N # Sm [5] UPPER LEFT TRIANGLE..BLACK MEDIUM SQUARE -25FD..25FE ; W # Sm [2] WHITE MEDIUM SMALL SQUARE..BLACK MEDIUM SMALL SQUARE -25FF ; N # Sm LOWER RIGHT TRIANGLE -2600..2604 ; N # So [5] BLACK SUN WITH RAYS..COMET -2605..2606 ; A # So [2] BLACK STAR..WHITE STAR -2607..2608 ; N # So [2] LIGHTNING..THUNDERSTORM -2609 ; A # So SUN -260A..260D ; N # So [4] ASCENDING NODE..OPPOSITION -260E..260F ; A # So [2] BLACK TELEPHONE..WHITE TELEPHONE -2610..2613 ; N # So [4] BALLOT BOX..SALTIRE -2614..2615 ; W # So [2] UMBRELLA WITH RAIN DROPS..HOT BEVERAGE -2616..261B ; N # So [6] WHITE SHOGI PIECE..BLACK RIGHT POINTING INDEX -261C ; A # So WHITE LEFT POINTING INDEX -261D ; N # So WHITE UP POINTING INDEX -261E ; A # So WHITE RIGHT POINTING INDEX -261F..263F ; N # So [33] WHITE DOWN POINTING INDEX..MERCURY -2640 ; A # So FEMALE SIGN -2641 ; N # So EARTH -2642 ; A # So MALE SIGN -2643..2647 ; N # So [5] JUPITER..PLUTO -2648..2653 ; W # So [12] ARIES..PISCES -2654..265F ; N # So [12] WHITE CHESS KING..BLACK CHESS PAWN -2660..2661 ; A # So [2] BLACK SPADE SUIT..WHITE HEART SUIT -2662 ; N # So WHITE DIAMOND SUIT -2663..2665 ; A # So [3] BLACK CLUB SUIT..BLACK HEART SUIT -2666 ; N # So BLACK DIAMOND SUIT -2667..266A ; A # So [4] WHITE CLUB SUIT..EIGHTH NOTE -266B ; N # So BEAMED EIGHTH NOTES -266C..266D ; A # So [2] BEAMED SIXTEENTH NOTES..MUSIC FLAT SIGN -266E ; N # So MUSIC NATURAL SIGN -266F ; A # Sm MUSIC SHARP SIGN -2670..267E ; N # So [15] WEST SYRIAC CROSS..PERMANENT PAPER SIGN -267F ; W # So WHEELCHAIR SYMBOL -2680..2692 ; N # So [19] DIE FACE-1..HAMMER AND PICK -2693 ; W # So ANCHOR -2694..269D ; N # So [10] CROSSED SWORDS..OUTLINED WHITE STAR -269E..269F ; A # So [2] THREE LINES CONVERGING RIGHT..THREE LINES CONVERGING LEFT -26A0 ; N # So WARNING SIGN -26A1 ; W # So HIGH VOLTAGE SIGN -26A2..26A9 ; N # So [8] DOUBLED FEMALE SIGN..HORIZONTAL MALE WITH STROKE SIGN -26AA..26AB ; W # So [2] MEDIUM WHITE CIRCLE..MEDIUM BLACK CIRCLE -26AC..26BC ; N # So [17] MEDIUM SMALL WHITE CIRCLE..SESQUIQUADRATE -26BD..26BE ; W # So [2] SOCCER BALL..BASEBALL -26BF ; A # So SQUARED KEY -26C0..26C3 ; N # So [4] WHITE DRAUGHTS MAN..BLACK DRAUGHTS KING -26C4..26C5 ; W # So [2] SNOWMAN WITHOUT SNOW..SUN BEHIND CLOUD -26C6..26CD ; A # So [8] RAIN..DISABLED CAR -26CE ; W # So OPHIUCHUS -26CF..26D3 ; A # So [5] PICK..CHAINS -26D4 ; W # So NO ENTRY -26D5..26E1 ; A # So [13] ALTERNATE ONE-WAY LEFT WAY TRAFFIC..RESTRICTED LEFT ENTRY-2 -26E2 ; N # So ASTRONOMICAL SYMBOL FOR URANUS -26E3 ; A # So HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE -26E4..26E7 ; N # So [4] PENTAGRAM..INVERTED PENTAGRAM -26E8..26E9 ; A # So [2] BLACK CROSS ON SHIELD..SHINTO SHRINE -26EA ; W # So CHURCH -26EB..26F1 ; A # So [7] CASTLE..UMBRELLA ON GROUND -26F2..26F3 ; W # So [2] FOUNTAIN..FLAG IN HOLE -26F4 ; A # So FERRY -26F5 ; W # So SAILBOAT -26F6..26F9 ; A # So [4] SQUARE FOUR CORNERS..PERSON WITH BALL -26FA ; W # So TENT -26FB..26FC ; A # So [2] JAPANESE BANK SYMBOL..HEADSTONE GRAVEYARD SYMBOL -26FD ; W # So FUEL PUMP -26FE..26FF ; A # So [2] CUP ON BLACK SQUARE..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE -2700..2704 ; N # So [5] BLACK SAFETY SCISSORS..WHITE SCISSORS -2705 ; W # So WHITE HEAVY CHECK MARK -2706..2709 ; N # So [4] TELEPHONE LOCATION SIGN..ENVELOPE -270A..270B ; W # So [2] RAISED FIST..RAISED HAND -270C..2727 ; N # So [28] VICTORY HAND..WHITE FOUR POINTED STAR -2728 ; W # So SPARKLES -2729..273C ; N # So [20] STRESS OUTLINED WHITE STAR..OPEN CENTRE TEARDROP-SPOKED ASTERISK -273D ; A # So HEAVY TEARDROP-SPOKED ASTERISK -273E..274B ; N # So [14] SIX PETALLED BLACK AND WHITE FLORETTE..HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK -274C ; W # So CROSS MARK -274D ; N # So SHADOWED WHITE CIRCLE -274E ; W # So NEGATIVE SQUARED CROSS MARK -274F..2752 ; N # So [4] LOWER RIGHT DROP-SHADOWED WHITE SQUARE..UPPER RIGHT SHADOWED WHITE SQUARE -2753..2755 ; W # So [3] BLACK QUESTION MARK ORNAMENT..WHITE EXCLAMATION MARK ORNAMENT -2756 ; N # So BLACK DIAMOND MINUS WHITE X -2757 ; W # So HEAVY EXCLAMATION MARK SYMBOL -2758..2767 ; N # So [16] LIGHT VERTICAL BAR..ROTATED FLORAL HEART BULLET -2768 ; N # Ps MEDIUM LEFT PARENTHESIS ORNAMENT -2769 ; N # Pe MEDIUM RIGHT PARENTHESIS ORNAMENT -276A ; N # Ps MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT -276B ; N # Pe MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT -276C ; N # Ps MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT -276D ; N # Pe MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT -276E ; N # Ps HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT -276F ; N # Pe HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT -2770 ; N # Ps HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT -2771 ; N # Pe HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT -2772 ; N # Ps LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT -2773 ; N # Pe LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT -2774 ; N # Ps MEDIUM LEFT CURLY BRACKET ORNAMENT -2775 ; N # Pe MEDIUM RIGHT CURLY BRACKET ORNAMENT -2776..277F ; A # No [10] DINGBAT NEGATIVE CIRCLED DIGIT ONE..DINGBAT NEGATIVE CIRCLED NUMBER TEN -2780..2793 ; N # No [20] DINGBAT CIRCLED SANS-SERIF DIGIT ONE..DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN -2794 ; N # So HEAVY WIDE-HEADED RIGHTWARDS ARROW -2795..2797 ; W # So [3] HEAVY PLUS SIGN..HEAVY DIVISION SIGN -2798..27AF ; N # So [24] HEAVY SOUTH EAST ARROW..NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW -27B0 ; W # So CURLY LOOP -27B1..27BE ; N # So [14] NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW..OPEN-OUTLINED RIGHTWARDS ARROW -27BF ; W # So DOUBLE CURLY LOOP -27C0..27C4 ; N # Sm [5] THREE DIMENSIONAL ANGLE..OPEN SUPERSET -27C5 ; N # Ps LEFT S-SHAPED BAG DELIMITER -27C6 ; N # Pe RIGHT S-SHAPED BAG DELIMITER -27C7..27E5 ; N # Sm [31] OR WITH DOT INSIDE..WHITE SQUARE WITH RIGHTWARDS TICK -27E6 ; Na # Ps MATHEMATICAL LEFT WHITE SQUARE BRACKET -27E7 ; Na # Pe MATHEMATICAL RIGHT WHITE SQUARE BRACKET -27E8 ; Na # Ps MATHEMATICAL LEFT ANGLE BRACKET -27E9 ; Na # Pe MATHEMATICAL RIGHT ANGLE BRACKET -27EA ; Na # Ps MATHEMATICAL LEFT DOUBLE ANGLE BRACKET -27EB ; Na # Pe MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET -27EC ; Na # Ps MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET -27ED ; Na # Pe MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET -27EE ; N # Ps MATHEMATICAL LEFT FLATTENED PARENTHESIS -27EF ; N # Pe MATHEMATICAL RIGHT FLATTENED PARENTHESIS -27F0..27FF ; N # Sm [16] UPWARDS QUADRUPLE ARROW..LONG RIGHTWARDS SQUIGGLE ARROW -2800..28FF ; N # So [256] BRAILLE PATTERN BLANK..BRAILLE PATTERN DOTS-12345678 -2900..297F ; N # Sm [128] RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE..DOWN FISH TAIL -2980..2982 ; N # Sm [3] TRIPLE VERTICAL BAR DELIMITER..Z NOTATION TYPE COLON -2983 ; N # Ps LEFT WHITE CURLY BRACKET -2984 ; N # Pe RIGHT WHITE CURLY BRACKET -2985 ; Na # Ps LEFT WHITE PARENTHESIS -2986 ; Na # Pe RIGHT WHITE PARENTHESIS -2987 ; N # Ps Z NOTATION LEFT IMAGE BRACKET -2988 ; N # Pe Z NOTATION RIGHT IMAGE BRACKET -2989 ; N # Ps Z NOTATION LEFT BINDING BRACKET -298A ; N # Pe Z NOTATION RIGHT BINDING BRACKET -298B ; N # Ps LEFT SQUARE BRACKET WITH UNDERBAR -298C ; N # Pe RIGHT SQUARE BRACKET WITH UNDERBAR -298D ; N # Ps LEFT SQUARE BRACKET WITH TICK IN TOP CORNER -298E ; N # Pe RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER -298F ; N # Ps LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER -2990 ; N # Pe RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER -2991 ; N # Ps LEFT ANGLE BRACKET WITH DOT -2992 ; N # Pe RIGHT ANGLE BRACKET WITH DOT -2993 ; N # Ps LEFT ARC LESS-THAN BRACKET -2994 ; N # Pe RIGHT ARC GREATER-THAN BRACKET -2995 ; N # Ps DOUBLE LEFT ARC GREATER-THAN BRACKET -2996 ; N # Pe DOUBLE RIGHT ARC LESS-THAN BRACKET -2997 ; N # Ps LEFT BLACK TORTOISE SHELL BRACKET -2998 ; N # Pe RIGHT BLACK TORTOISE SHELL BRACKET -2999..29D7 ; N # Sm [63] DOTTED FENCE..BLACK HOURGLASS -29D8 ; N # Ps LEFT WIGGLY FENCE -29D9 ; N # Pe RIGHT WIGGLY FENCE -29DA ; N # Ps LEFT DOUBLE WIGGLY FENCE -29DB ; N # Pe RIGHT DOUBLE WIGGLY FENCE -29DC..29FB ; N # Sm [32] INCOMPLETE INFINITY..TRIPLE PLUS -29FC ; N # Ps LEFT-POINTING CURVED ANGLE BRACKET -29FD ; N # Pe RIGHT-POINTING CURVED ANGLE BRACKET -29FE..29FF ; N # Sm [2] TINY..MINY -2A00..2AFF ; N # Sm [256] N-ARY CIRCLED DOT OPERATOR..N-ARY WHITE VERTICAL BAR -2B00..2B1A ; N # So [27] NORTH EAST WHITE ARROW..DOTTED SQUARE -2B1B..2B1C ; W # So [2] BLACK LARGE SQUARE..WHITE LARGE SQUARE -2B1D..2B2F ; N # So [19] BLACK VERY SMALL SQUARE..WHITE VERTICAL ELLIPSE -2B30..2B44 ; N # Sm [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET -2B45..2B46 ; N # So [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW -2B47..2B4C ; N # Sm [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR -2B4D..2B4F ; N # So [3] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..SHORT BACKSLANTED SOUTH ARROW -2B50 ; W # So WHITE MEDIUM STAR -2B51..2B54 ; N # So [4] BLACK SMALL STAR..WHITE RIGHT-POINTING PENTAGON -2B55 ; W # So HEAVY LARGE CIRCLE -2B56..2B59 ; A # So [4] HEAVY OVAL WITH OVAL INSIDE..HEAVY CIRCLED SALTIRE -2B5A..2B73 ; N # So [26] SLANTED NORTH ARROW WITH HOOKED HEAD..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR -2B76..2B95 ; N # So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW -2B97..2BFF ; N # So [105] SYMBOL FOR TYPE A ELECTRONICS..HELLSCHREIBER PAUSE SYMBOL -2C00..2C5F ; N # L& [96] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC SMALL LETTER CAUDATE CHRIVI -2C60..2C7B ; N # L& [28] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN LETTER SMALL CAPITAL TURNED E -2C7C..2C7D ; N # Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V -2C7E..2C7F ; N # Lu [2] LATIN CAPITAL LETTER S WITH SWASH TAIL..LATIN CAPITAL LETTER Z WITH SWASH TAIL -2C80..2CE4 ; N # L& [101] COPTIC CAPITAL LETTER ALFA..COPTIC SYMBOL KAI -2CE5..2CEA ; N # So [6] COPTIC SYMBOL MI RO..COPTIC SYMBOL SHIMA SIMA -2CEB..2CEE ; N # L& [4] COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI..COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA -2CEF..2CF1 ; N # Mn [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS -2CF2..2CF3 ; N # L& [2] COPTIC CAPITAL LETTER BOHAIRIC KHEI..COPTIC SMALL LETTER BOHAIRIC KHEI -2CF9..2CFC ; N # Po [4] COPTIC OLD NUBIAN FULL STOP..COPTIC OLD NUBIAN VERSE DIVIDER -2CFD ; N # No COPTIC FRACTION ONE HALF -2CFE..2CFF ; N # Po [2] COPTIC FULL STOP..COPTIC MORPHOLOGICAL DIVIDER -2D00..2D25 ; N # Ll [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE -2D27 ; N # Ll GEORGIAN SMALL LETTER YN -2D2D ; N # Ll GEORGIAN SMALL LETTER AEN -2D30..2D67 ; N # Lo [56] TIFINAGH LETTER YA..TIFINAGH LETTER YO -2D6F ; N # Lm TIFINAGH MODIFIER LETTER LABIALIZATION MARK -2D70 ; N # Po TIFINAGH SEPARATOR MARK -2D7F ; N # Mn TIFINAGH CONSONANT JOINER -2D80..2D96 ; N # Lo [23] ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE -2DA0..2DA6 ; N # Lo [7] ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO -2DA8..2DAE ; N # Lo [7] ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO -2DB0..2DB6 ; N # Lo [7] ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO -2DB8..2DBE ; N # Lo [7] ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO -2DC0..2DC6 ; N # Lo [7] ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO -2DC8..2DCE ; N # Lo [7] ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO -2DD0..2DD6 ; N # Lo [7] ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO -2DD8..2DDE ; N # Lo [7] ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO -2DE0..2DFF ; N # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS -2E00..2E01 ; N # Po [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER -2E02 ; N # Pi LEFT SUBSTITUTION BRACKET -2E03 ; N # Pf RIGHT SUBSTITUTION BRACKET -2E04 ; N # Pi LEFT DOTTED SUBSTITUTION BRACKET -2E05 ; N # Pf RIGHT DOTTED SUBSTITUTION BRACKET -2E06..2E08 ; N # Po [3] RAISED INTERPOLATION MARKER..DOTTED TRANSPOSITION MARKER -2E09 ; N # Pi LEFT TRANSPOSITION BRACKET -2E0A ; N # Pf RIGHT TRANSPOSITION BRACKET -2E0B ; N # Po RAISED SQUARE -2E0C ; N # Pi LEFT RAISED OMISSION BRACKET -2E0D ; N # Pf RIGHT RAISED OMISSION BRACKET -2E0E..2E16 ; N # Po [9] EDITORIAL CORONIS..DOTTED RIGHT-POINTING ANGLE -2E17 ; N # Pd DOUBLE OBLIQUE HYPHEN -2E18..2E19 ; N # Po [2] INVERTED INTERROBANG..PALM BRANCH -2E1A ; N # Pd HYPHEN WITH DIAERESIS -2E1B ; N # Po TILDE WITH RING ABOVE -2E1C ; N # Pi LEFT LOW PARAPHRASE BRACKET -2E1D ; N # Pf RIGHT LOW PARAPHRASE BRACKET -2E1E..2E1F ; N # Po [2] TILDE WITH DOT ABOVE..TILDE WITH DOT BELOW -2E20 ; N # Pi LEFT VERTICAL BAR WITH QUILL -2E21 ; N # Pf RIGHT VERTICAL BAR WITH QUILL -2E22 ; N # Ps TOP LEFT HALF BRACKET -2E23 ; N # Pe TOP RIGHT HALF BRACKET -2E24 ; N # Ps BOTTOM LEFT HALF BRACKET -2E25 ; N # Pe BOTTOM RIGHT HALF BRACKET -2E26 ; N # Ps LEFT SIDEWAYS U BRACKET -2E27 ; N # Pe RIGHT SIDEWAYS U BRACKET -2E28 ; N # Ps LEFT DOUBLE PARENTHESIS -2E29 ; N # Pe RIGHT DOUBLE PARENTHESIS -2E2A..2E2E ; N # Po [5] TWO DOTS OVER ONE DOT PUNCTUATION..REVERSED QUESTION MARK -2E2F ; N # Lm VERTICAL TILDE -2E30..2E39 ; N # Po [10] RING POINT..TOP HALF SECTION SIGN -2E3A..2E3B ; N # Pd [2] TWO-EM DASH..THREE-EM DASH -2E3C..2E3F ; N # Po [4] STENOGRAPHIC FULL STOP..CAPITULUM -2E40 ; N # Pd DOUBLE HYPHEN -2E41 ; N # Po REVERSED COMMA -2E42 ; N # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK -2E43..2E4F ; N # Po [13] DASH WITH LEFT UPTURN..CORNISH VERSE DIVIDER -2E50..2E51 ; N # So [2] CROSS PATTY WITH RIGHT CROSSBAR..CROSS PATTY WITH LEFT CROSSBAR -2E52..2E54 ; N # Po [3] TIRONIAN SIGN CAPITAL ET..MEDIEVAL QUESTION MARK -2E55 ; N # Ps LEFT SQUARE BRACKET WITH STROKE -2E56 ; N # Pe RIGHT SQUARE BRACKET WITH STROKE -2E57 ; N # Ps LEFT SQUARE BRACKET WITH DOUBLE STROKE -2E58 ; N # Pe RIGHT SQUARE BRACKET WITH DOUBLE STROKE -2E59 ; N # Ps TOP HALF LEFT PARENTHESIS -2E5A ; N # Pe TOP HALF RIGHT PARENTHESIS -2E5B ; N # Ps BOTTOM HALF LEFT PARENTHESIS -2E5C ; N # Pe BOTTOM HALF RIGHT PARENTHESIS -2E5D ; N # Pd OBLIQUE HYPHEN -2E80..2E99 ; W # So [26] CJK RADICAL REPEAT..CJK RADICAL RAP -2E9B..2EF3 ; W # So [89] CJK RADICAL CHOKE..CJK RADICAL C-SIMPLIFIED TURTLE -2F00..2FD5 ; W # So [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE -2FF0..2FFF ; W # So [16] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER ROTATION -3000 ; F # Zs IDEOGRAPHIC SPACE -3001..3003 ; W # Po [3] IDEOGRAPHIC COMMA..DITTO MARK -3004 ; W # So JAPANESE INDUSTRIAL STANDARD SYMBOL -3005 ; W # Lm IDEOGRAPHIC ITERATION MARK -3006 ; W # Lo IDEOGRAPHIC CLOSING MARK -3007 ; W # Nl IDEOGRAPHIC NUMBER ZERO -3008 ; W # Ps LEFT ANGLE BRACKET -3009 ; W # Pe RIGHT ANGLE BRACKET -300A ; W # Ps LEFT DOUBLE ANGLE BRACKET -300B ; W # Pe RIGHT DOUBLE ANGLE BRACKET -300C ; W # Ps LEFT CORNER BRACKET -300D ; W # Pe RIGHT CORNER BRACKET -300E ; W # Ps LEFT WHITE CORNER BRACKET -300F ; W # Pe RIGHT WHITE CORNER BRACKET -3010 ; W # Ps LEFT BLACK LENTICULAR BRACKET -3011 ; W # Pe RIGHT BLACK LENTICULAR BRACKET -3012..3013 ; W # So [2] POSTAL MARK..GETA MARK -3014 ; W # Ps LEFT TORTOISE SHELL BRACKET -3015 ; W # Pe RIGHT TORTOISE SHELL BRACKET -3016 ; W # Ps LEFT WHITE LENTICULAR BRACKET -3017 ; W # Pe RIGHT WHITE LENTICULAR BRACKET -3018 ; W # Ps LEFT WHITE TORTOISE SHELL BRACKET -3019 ; W # Pe RIGHT WHITE TORTOISE SHELL BRACKET -301A ; W # Ps LEFT WHITE SQUARE BRACKET -301B ; W # Pe RIGHT WHITE SQUARE BRACKET -301C ; W # Pd WAVE DASH -301D ; W # Ps REVERSED DOUBLE PRIME QUOTATION MARK -301E..301F ; W # Pe [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK -3020 ; W # So POSTAL MARK FACE -3021..3029 ; W # Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE -302A..302D ; W # Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK -302E..302F ; W # Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK -3030 ; W # Pd WAVY DASH -3031..3035 ; W # Lm [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF -3036..3037 ; W # So [2] CIRCLED POSTAL MARK..IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL -3038..303A ; W # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY -303B ; W # Lm VERTICAL IDEOGRAPHIC ITERATION MARK -303C ; W # Lo MASU MARK -303D ; W # Po PART ALTERNATION MARK -303E ; W # So IDEOGRAPHIC VARIATION INDICATOR -303F ; N # So IDEOGRAPHIC HALF FILL SPACE -3041..3096 ; W # Lo [86] HIRAGANA LETTER SMALL A..HIRAGANA LETTER SMALL KE -3099..309A ; W # Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK -309B..309C ; W # Sk [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK -309D..309E ; W # Lm [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK -309F ; W # Lo HIRAGANA DIGRAPH YORI -30A0 ; W # Pd KATAKANA-HIRAGANA DOUBLE HYPHEN -30A1..30FA ; W # Lo [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO -30FB ; W # Po KATAKANA MIDDLE DOT -30FC..30FE ; W # Lm [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK -30FF ; W # Lo KATAKANA DIGRAPH KOTO -3105..312F ; W # Lo [43] BOPOMOFO LETTER B..BOPOMOFO LETTER NN -3131..318E ; W # Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE -3190..3191 ; W # So [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK -3192..3195 ; W # No [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK -3196..319F ; W # So [10] IDEOGRAPHIC ANNOTATION TOP MARK..IDEOGRAPHIC ANNOTATION MAN MARK -31A0..31BF ; W # Lo [32] BOPOMOFO LETTER BU..BOPOMOFO LETTER AH -31C0..31E3 ; W # So [36] CJK STROKE T..CJK STROKE Q -31EF ; W # So IDEOGRAPHIC DESCRIPTION CHARACTER SUBTRACTION -31F0..31FF ; W # Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO -3200..321E ; W # So [31] PARENTHESIZED HANGUL KIYEOK..PARENTHESIZED KOREAN CHARACTER O HU -3220..3229 ; W # No [10] PARENTHESIZED IDEOGRAPH ONE..PARENTHESIZED IDEOGRAPH TEN -322A..3247 ; W # So [30] PARENTHESIZED IDEOGRAPH MOON..CIRCLED IDEOGRAPH KOTO -3248..324F ; A # No [8] CIRCLED NUMBER TEN ON BLACK SQUARE..CIRCLED NUMBER EIGHTY ON BLACK SQUARE -3250 ; W # So PARTNERSHIP SIGN -3251..325F ; W # No [15] CIRCLED NUMBER TWENTY ONE..CIRCLED NUMBER THIRTY FIVE -3260..327F ; W # So [32] CIRCLED HANGUL KIYEOK..KOREAN STANDARD SYMBOL -3280..3289 ; W # No [10] CIRCLED IDEOGRAPH ONE..CIRCLED IDEOGRAPH TEN -328A..32B0 ; W # So [39] CIRCLED IDEOGRAPH MOON..CIRCLED IDEOGRAPH NIGHT -32B1..32BF ; W # No [15] CIRCLED NUMBER THIRTY SIX..CIRCLED NUMBER FIFTY -32C0..32FF ; W # So [64] IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY..SQUARE ERA NAME REIWA -3300..33FF ; W # So [256] SQUARE APAATO..SQUARE GAL -3400..4DBF ; W # Lo [6592] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DBF -4DC0..4DFF ; N # So [64] HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION -4E00..9FFF ; W # Lo [20992] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FFF -A000..A014 ; W # Lo [21] YI SYLLABLE IT..YI SYLLABLE E -A015 ; W # Lm YI SYLLABLE WU -A016..A48C ; W # Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR -A490..A4C6 ; W # So [55] YI RADICAL QOT..YI RADICAL KE -A4D0..A4F7 ; N # Lo [40] LISU LETTER BA..LISU LETTER OE -A4F8..A4FD ; N # Lm [6] LISU LETTER TONE MYA TI..LISU LETTER TONE MYA JEU -A4FE..A4FF ; N # Po [2] LISU PUNCTUATION COMMA..LISU PUNCTUATION FULL STOP -A500..A60B ; N # Lo [268] VAI SYLLABLE EE..VAI SYLLABLE NG -A60C ; N # Lm VAI SYLLABLE LENGTHENER -A60D..A60F ; N # Po [3] VAI COMMA..VAI QUESTION MARK -A610..A61F ; N # Lo [16] VAI SYLLABLE NDOLE FA..VAI SYMBOL JONG -A620..A629 ; N # Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE -A62A..A62B ; N # Lo [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO -A640..A66D ; N # L& [46] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER DOUBLE MONOCULAR O -A66E ; N # Lo CYRILLIC LETTER MULTIOCULAR O -A66F ; N # Mn COMBINING CYRILLIC VZMET -A670..A672 ; N # Me [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN -A673 ; N # Po SLAVONIC ASTERISK -A674..A67D ; N # Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK -A67E ; N # Po CYRILLIC KAVYKA -A67F ; N # Lm CYRILLIC PAYEROK -A680..A69B ; N # L& [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O -A69C..A69D ; N # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN -A69E..A69F ; N # Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E -A6A0..A6E5 ; N # Lo [70] BAMUM LETTER A..BAMUM LETTER KI -A6E6..A6EF ; N # Nl [10] BAMUM LETTER MO..BAMUM LETTER KOGHOM -A6F0..A6F1 ; N # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS -A6F2..A6F7 ; N # Po [6] BAMUM NJAEMLI..BAMUM QUESTION MARK -A700..A716 ; N # Sk [23] MODIFIER LETTER CHINESE TONE YIN PING..MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR -A717..A71F ; N # Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK -A720..A721 ; N # Sk [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE -A722..A76F ; N # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CON -A770 ; N # Lm MODIFIER LETTER US -A771..A787 ; N # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T -A788 ; N # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT -A789..A78A ; N # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN -A78B..A78E ; N # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT -A78F ; N # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7CA ; N # L& [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY -A7D0..A7D1 ; N # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G -A7D3 ; N # Ll LATIN SMALL LETTER DOUBLE THORN -A7D5..A7D9 ; N # L& [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S -A7F2..A7F4 ; N # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q -A7F5..A7F6 ; N # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H -A7F7 ; N # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I -A7F8..A7F9 ; N # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE -A7FA ; N # Ll LATIN LETTER SMALL CAPITAL TURNED M -A7FB..A7FF ; N # Lo [5] LATIN EPIGRAPHIC LETTER REVERSED F..LATIN EPIGRAPHIC LETTER ARCHAIC M -A800..A801 ; N # Lo [2] SYLOTI NAGRI LETTER A..SYLOTI NAGRI LETTER I -A802 ; N # Mn SYLOTI NAGRI SIGN DVISVARA -A803..A805 ; N # Lo [3] SYLOTI NAGRI LETTER U..SYLOTI NAGRI LETTER O -A806 ; N # Mn SYLOTI NAGRI SIGN HASANTA -A807..A80A ; N # Lo [4] SYLOTI NAGRI LETTER KO..SYLOTI NAGRI LETTER GHO -A80B ; N # Mn SYLOTI NAGRI SIGN ANUSVARA -A80C..A822 ; N # Lo [23] SYLOTI NAGRI LETTER CO..SYLOTI NAGRI LETTER HO -A823..A824 ; N # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I -A825..A826 ; N # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E -A827 ; N # Mc SYLOTI NAGRI VOWEL SIGN OO -A828..A82B ; N # So [4] SYLOTI NAGRI POETRY MARK-1..SYLOTI NAGRI POETRY MARK-4 -A82C ; N # Mn SYLOTI NAGRI SIGN ALTERNATE HASANTA -A830..A835 ; N # No [6] NORTH INDIC FRACTION ONE QUARTER..NORTH INDIC FRACTION THREE SIXTEENTHS -A836..A837 ; N # So [2] NORTH INDIC QUARTER MARK..NORTH INDIC PLACEHOLDER MARK -A838 ; N # Sc NORTH INDIC RUPEE MARK -A839 ; N # So NORTH INDIC QUANTITY MARK -A840..A873 ; N # Lo [52] PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU -A874..A877 ; N # Po [4] PHAGS-PA SINGLE HEAD MARK..PHAGS-PA MARK DOUBLE SHAD -A880..A881 ; N # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA -A882..A8B3 ; N # Lo [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA -A8B4..A8C3 ; N # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU -A8C4..A8C5 ; N # Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU -A8CE..A8CF ; N # Po [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA -A8D0..A8D9 ; N # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE -A8E0..A8F1 ; N # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA -A8F2..A8F7 ; N # Lo [6] DEVANAGARI SIGN SPACING CANDRABINDU..DEVANAGARI SIGN CANDRABINDU AVAGRAHA -A8F8..A8FA ; N # Po [3] DEVANAGARI SIGN PUSHPIKA..DEVANAGARI CARET -A8FB ; N # Lo DEVANAGARI HEADSTROKE -A8FC ; N # Po DEVANAGARI SIGN SIDDHAM -A8FD..A8FE ; N # Lo [2] DEVANAGARI JAIN OM..DEVANAGARI LETTER AY -A8FF ; N # Mn DEVANAGARI VOWEL SIGN AY -A900..A909 ; N # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE -A90A..A925 ; N # Lo [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO -A926..A92D ; N # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU -A92E..A92F ; N # Po [2] KAYAH LI SIGN CWI..KAYAH LI SIGN SHYA -A930..A946 ; N # Lo [23] REJANG LETTER KA..REJANG LETTER A -A947..A951 ; N # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R -A952..A953 ; N # Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA -A95F ; N # Po REJANG SECTION MARK -A960..A97C ; W # Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH -A980..A982 ; N # Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR -A983 ; N # Mc JAVANESE SIGN WIGNYAN -A984..A9B2 ; N # Lo [47] JAVANESE LETTER A..JAVANESE LETTER HA -A9B3 ; N # Mn JAVANESE SIGN CECAK TELU -A9B4..A9B5 ; N # Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG -A9B6..A9B9 ; N # Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT -A9BA..A9BB ; N # Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE -A9BC..A9BD ; N # Mn [2] JAVANESE VOWEL SIGN PEPET..JAVANESE CONSONANT SIGN KERET -A9BE..A9C0 ; N # Mc [3] JAVANESE CONSONANT SIGN PENGKAL..JAVANESE PANGKON -A9C1..A9CD ; N # Po [13] JAVANESE LEFT RERENGGAN..JAVANESE TURNED PADA PISELEH -A9CF ; N # Lm JAVANESE PANGRANGKEP -A9D0..A9D9 ; N # Nd [10] JAVANESE DIGIT ZERO..JAVANESE DIGIT NINE -A9DE..A9DF ; N # Po [2] JAVANESE PADA TIRTA TUMETES..JAVANESE PADA ISEN-ISEN -A9E0..A9E4 ; N # Lo [5] MYANMAR LETTER SHAN GHA..MYANMAR LETTER SHAN BHA -A9E5 ; N # Mn MYANMAR SIGN SHAN SAW -A9E6 ; N # Lm MYANMAR MODIFIER LETTER SHAN REDUPLICATION -A9E7..A9EF ; N # Lo [9] MYANMAR LETTER TAI LAING NYA..MYANMAR LETTER TAI LAING NNA -A9F0..A9F9 ; N # Nd [10] MYANMAR TAI LAING DIGIT ZERO..MYANMAR TAI LAING DIGIT NINE -A9FA..A9FE ; N # Lo [5] MYANMAR LETTER TAI LAING LLA..MYANMAR LETTER TAI LAING BHA -AA00..AA28 ; N # Lo [41] CHAM LETTER A..CHAM LETTER HA -AA29..AA2E ; N # Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE -AA2F..AA30 ; N # Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI -AA31..AA32 ; N # Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE -AA33..AA34 ; N # Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA -AA35..AA36 ; N # Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA -AA40..AA42 ; N # Lo [3] CHAM LETTER FINAL K..CHAM LETTER FINAL NG -AA43 ; N # Mn CHAM CONSONANT SIGN FINAL NG -AA44..AA4B ; N # Lo [8] CHAM LETTER FINAL CH..CHAM LETTER FINAL SS -AA4C ; N # Mn CHAM CONSONANT SIGN FINAL M -AA4D ; N # Mc CHAM CONSONANT SIGN FINAL H -AA50..AA59 ; N # Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE -AA5C..AA5F ; N # Po [4] CHAM PUNCTUATION SPIRAL..CHAM PUNCTUATION TRIPLE DANDA -AA60..AA6F ; N # Lo [16] MYANMAR LETTER KHAMTI GA..MYANMAR LETTER KHAMTI FA -AA70 ; N # Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION -AA71..AA76 ; N # Lo [6] MYANMAR LETTER KHAMTI XA..MYANMAR LOGOGRAM KHAMTI HM -AA77..AA79 ; N # So [3] MYANMAR SYMBOL AITON EXCLAMATION..MYANMAR SYMBOL AITON TWO -AA7A ; N # Lo MYANMAR LETTER AITON RA -AA7B ; N # Mc MYANMAR SIGN PAO KAREN TONE -AA7C ; N # Mn MYANMAR SIGN TAI LAING TONE-2 -AA7D ; N # Mc MYANMAR SIGN TAI LAING TONE-5 -AA7E..AA7F ; N # Lo [2] MYANMAR LETTER SHWE PALAUNG CHA..MYANMAR LETTER SHWE PALAUNG SHA -AA80..AAAF ; N # Lo [48] TAI VIET LETTER LOW KO..TAI VIET LETTER HIGH O -AAB0 ; N # Mn TAI VIET MAI KANG -AAB1 ; N # Lo TAI VIET VOWEL AA -AAB2..AAB4 ; N # Mn [3] TAI VIET VOWEL I..TAI VIET VOWEL U -AAB5..AAB6 ; N # Lo [2] TAI VIET VOWEL E..TAI VIET VOWEL O -AAB7..AAB8 ; N # Mn [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA -AAB9..AABD ; N # Lo [5] TAI VIET VOWEL UEA..TAI VIET VOWEL AN -AABE..AABF ; N # Mn [2] TAI VIET VOWEL AM..TAI VIET TONE MAI EK -AAC0 ; N # Lo TAI VIET TONE MAI NUENG -AAC1 ; N # Mn TAI VIET TONE MAI THO -AAC2 ; N # Lo TAI VIET TONE MAI SONG -AADB..AADC ; N # Lo [2] TAI VIET SYMBOL KON..TAI VIET SYMBOL NUENG -AADD ; N # Lm TAI VIET SYMBOL SAM -AADE..AADF ; N # Po [2] TAI VIET SYMBOL HO HOI..TAI VIET SYMBOL KOI KOI -AAE0..AAEA ; N # Lo [11] MEETEI MAYEK LETTER E..MEETEI MAYEK LETTER SSA -AAEB ; N # Mc MEETEI MAYEK VOWEL SIGN II -AAEC..AAED ; N # Mn [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI -AAEE..AAEF ; N # Mc [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU -AAF0..AAF1 ; N # Po [2] MEETEI MAYEK CHEIKHAN..MEETEI MAYEK AHANG KHUDAM -AAF2 ; N # Lo MEETEI MAYEK ANJI -AAF3..AAF4 ; N # Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK -AAF5 ; N # Mc MEETEI MAYEK VOWEL SIGN VISARGA -AAF6 ; N # Mn MEETEI MAYEK VIRAMA -AB01..AB06 ; N # Lo [6] ETHIOPIC SYLLABLE TTHU..ETHIOPIC SYLLABLE TTHO -AB09..AB0E ; N # Lo [6] ETHIOPIC SYLLABLE DDHU..ETHIOPIC SYLLABLE DDHO -AB11..AB16 ; N # Lo [6] ETHIOPIC SYLLABLE DZU..ETHIOPIC SYLLABLE DZO -AB20..AB26 ; N # Lo [7] ETHIOPIC SYLLABLE CCHHA..ETHIOPIC SYLLABLE CCHHO -AB28..AB2E ; N # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO -AB30..AB5A ; N # Ll [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG -AB5B ; N # Sk MODIFIER BREVE WITH INVERTED BREVE -AB5C..AB5F ; N # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK -AB60..AB68 ; N # Ll [9] LATIN SMALL LETTER SAKHA YAT..LATIN SMALL LETTER TURNED R WITH MIDDLE TILDE -AB69 ; N # Lm MODIFIER LETTER SMALL TURNED W -AB6A..AB6B ; N # Sk [2] MODIFIER LETTER LEFT TACK..MODIFIER LETTER RIGHT TACK -AB70..ABBF ; N # Ll [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA -ABC0..ABE2 ; N # Lo [35] MEETEI MAYEK LETTER KOK..MEETEI MAYEK LETTER I LONSUM -ABE3..ABE4 ; N # Mc [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP -ABE5 ; N # Mn MEETEI MAYEK VOWEL SIGN ANAP -ABE6..ABE7 ; N # Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP -ABE8 ; N # Mn MEETEI MAYEK VOWEL SIGN UNAP -ABE9..ABEA ; N # Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG -ABEB ; N # Po MEETEI MAYEK CHEIKHEI -ABEC ; N # Mc MEETEI MAYEK LUM IYEK -ABED ; N # Mn MEETEI MAYEK APUN IYEK -ABF0..ABF9 ; N # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DIGIT NINE -AC00..D7A3 ; W # Lo [11172] HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH -D7B0..D7C6 ; N # Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E -D7CB..D7FB ; N # Lo [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH -D800..DB7F ; N # Cs [896] <surrogate-D800>..<surrogate-DB7F> -DB80..DBFF ; N # Cs [128] <surrogate-DB80>..<surrogate-DBFF> -DC00..DFFF ; N # Cs [1024] <surrogate-DC00>..<surrogate-DFFF> -E000..F8FF ; A # Co [6400] <private-use-E000>..<private-use-F8FF> -F900..FA6D ; W # Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D -FA6E..FA6F ; W # Cn [2] <reserved-FA6E>..<reserved-FA6F> -FA70..FAD9 ; W # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9 -FADA..FAFF ; W # Cn [38] <reserved-FADA>..<reserved-FAFF> -FB00..FB06 ; N # Ll [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST -FB13..FB17 ; N # Ll [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH -FB1D ; N # Lo HEBREW LETTER YOD WITH HIRIQ -FB1E ; N # Mn HEBREW POINT JUDEO-SPANISH VARIKA -FB1F..FB28 ; N # Lo [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV -FB29 ; N # Sm HEBREW LETTER ALTERNATIVE PLUS SIGN -FB2A..FB36 ; N # Lo [13] HEBREW LETTER SHIN WITH SHIN DOT..HEBREW LETTER ZAYIN WITH DAGESH -FB38..FB3C ; N # Lo [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH -FB3E ; N # Lo HEBREW LETTER MEM WITH DAGESH -FB40..FB41 ; N # Lo [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH -FB43..FB44 ; N # Lo [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH -FB46..FB4F ; N # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATURE ALEF LAMED -FB50..FBB1 ; N # Lo [98] ARABIC LETTER ALEF WASLA ISOLATED FORM..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM -FBB2..FBC2 ; N # Sk [17] ARABIC SYMBOL DOT ABOVE..ARABIC SYMBOL WASLA ABOVE -FBD3..FD3D ; N # Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM -FD3E ; N # Pe ORNATE LEFT PARENTHESIS -FD3F ; N # Ps ORNATE RIGHT PARENTHESIS -FD40..FD4F ; N # So [16] ARABIC LIGATURE RAHIMAHU ALLAAH..ARABIC LIGATURE RAHIMAHUM ALLAAH -FD50..FD8F ; N # Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM -FD92..FDC7 ; N # Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM -FDCF ; N # So ARABIC LIGATURE SALAAMUHU ALAYNAA -FDF0..FDFB ; N # Lo [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU -FDFC ; N # Sc RIAL SIGN -FDFD..FDFF ; N # So [3] ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM..ARABIC LIGATURE AZZA WA JALL -FE00..FE0F ; A # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16 -FE10..FE16 ; W # Po [7] PRESENTATION FORM FOR VERTICAL COMMA..PRESENTATION FORM FOR VERTICAL QUESTION MARK -FE17 ; W # Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET -FE18 ; W # Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET -FE19 ; W # Po PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS -FE20..FE2F ; N # Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF -FE30 ; W # Po PRESENTATION FORM FOR VERTICAL TWO DOT LEADER -FE31..FE32 ; W # Pd [2] PRESENTATION FORM FOR VERTICAL EM DASH..PRESENTATION FORM FOR VERTICAL EN DASH -FE33..FE34 ; W # Pc [2] PRESENTATION FORM FOR VERTICAL LOW LINE..PRESENTATION FORM FOR VERTICAL WAVY LOW LINE -FE35 ; W # Ps PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS -FE36 ; W # Pe PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS -FE37 ; W # Ps PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET -FE38 ; W # Pe PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET -FE39 ; W # Ps PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET -FE3A ; W # Pe PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET -FE3B ; W # Ps PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET -FE3C ; W # Pe PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET -FE3D ; W # Ps PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET -FE3E ; W # Pe PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET -FE3F ; W # Ps PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET -FE40 ; W # Pe PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET -FE41 ; W # Ps PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET -FE42 ; W # Pe PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET -FE43 ; W # Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET -FE44 ; W # Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET -FE45..FE46 ; W # Po [2] SESAME DOT..WHITE SESAME DOT -FE47 ; W # Ps PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET -FE48 ; W # Pe PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET -FE49..FE4C ; W # Po [4] DASHED OVERLINE..DOUBLE WAVY OVERLINE -FE4D..FE4F ; W # Pc [3] DASHED LOW LINE..WAVY LOW LINE -FE50..FE52 ; W # Po [3] SMALL COMMA..SMALL FULL STOP -FE54..FE57 ; W # Po [4] SMALL SEMICOLON..SMALL EXCLAMATION MARK -FE58 ; W # Pd SMALL EM DASH -FE59 ; W # Ps SMALL LEFT PARENTHESIS -FE5A ; W # Pe SMALL RIGHT PARENTHESIS -FE5B ; W # Ps SMALL LEFT CURLY BRACKET -FE5C ; W # Pe SMALL RIGHT CURLY BRACKET -FE5D ; W # Ps SMALL LEFT TORTOISE SHELL BRACKET -FE5E ; W # Pe SMALL RIGHT TORTOISE SHELL BRACKET -FE5F..FE61 ; W # Po [3] SMALL NUMBER SIGN..SMALL ASTERISK -FE62 ; W # Sm SMALL PLUS SIGN -FE63 ; W # Pd SMALL HYPHEN-MINUS -FE64..FE66 ; W # Sm [3] SMALL LESS-THAN SIGN..SMALL EQUALS SIGN -FE68 ; W # Po SMALL REVERSE SOLIDUS -FE69 ; W # Sc SMALL DOLLAR SIGN -FE6A..FE6B ; W # Po [2] SMALL PERCENT SIGN..SMALL COMMERCIAL AT -FE70..FE74 ; N # Lo [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN ISOLATED FORM -FE76..FEFC ; N # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM -FEFF ; N # Cf ZERO WIDTH NO-BREAK SPACE -FF01..FF03 ; F # Po [3] FULLWIDTH EXCLAMATION MARK..FULLWIDTH NUMBER SIGN -FF04 ; F # Sc FULLWIDTH DOLLAR SIGN -FF05..FF07 ; F # Po [3] FULLWIDTH PERCENT SIGN..FULLWIDTH APOSTROPHE -FF08 ; F # Ps FULLWIDTH LEFT PARENTHESIS -FF09 ; F # Pe FULLWIDTH RIGHT PARENTHESIS -FF0A ; F # Po FULLWIDTH ASTERISK -FF0B ; F # Sm FULLWIDTH PLUS SIGN -FF0C ; F # Po FULLWIDTH COMMA -FF0D ; F # Pd FULLWIDTH HYPHEN-MINUS -FF0E..FF0F ; F # Po [2] FULLWIDTH FULL STOP..FULLWIDTH SOLIDUS -FF10..FF19 ; F # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE -FF1A..FF1B ; F # Po [2] FULLWIDTH COLON..FULLWIDTH SEMICOLON -FF1C..FF1E ; F # Sm [3] FULLWIDTH LESS-THAN SIGN..FULLWIDTH GREATER-THAN SIGN -FF1F..FF20 ; F # Po [2] FULLWIDTH QUESTION MARK..FULLWIDTH COMMERCIAL AT -FF21..FF3A ; F # Lu [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z -FF3B ; F # Ps FULLWIDTH LEFT SQUARE BRACKET -FF3C ; F # Po FULLWIDTH REVERSE SOLIDUS -FF3D ; F # Pe FULLWIDTH RIGHT SQUARE BRACKET -FF3E ; F # Sk FULLWIDTH CIRCUMFLEX ACCENT -FF3F ; F # Pc FULLWIDTH LOW LINE -FF40 ; F # Sk FULLWIDTH GRAVE ACCENT -FF41..FF5A ; F # Ll [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z -FF5B ; F # Ps FULLWIDTH LEFT CURLY BRACKET -FF5C ; F # Sm FULLWIDTH VERTICAL LINE -FF5D ; F # Pe FULLWIDTH RIGHT CURLY BRACKET -FF5E ; F # Sm FULLWIDTH TILDE -FF5F ; F # Ps FULLWIDTH LEFT WHITE PARENTHESIS -FF60 ; F # Pe FULLWIDTH RIGHT WHITE PARENTHESIS -FF61 ; H # Po HALFWIDTH IDEOGRAPHIC FULL STOP -FF62 ; H # Ps HALFWIDTH LEFT CORNER BRACKET -FF63 ; H # Pe HALFWIDTH RIGHT CORNER BRACKET -FF64..FF65 ; H # Po [2] HALFWIDTH IDEOGRAPHIC COMMA..HALFWIDTH KATAKANA MIDDLE DOT -FF66..FF6F ; H # Lo [10] HALFWIDTH KATAKANA LETTER WO..HALFWIDTH KATAKANA LETTER SMALL TU -FF70 ; H # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK -FF71..FF9D ; H # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N -FF9E..FF9F ; H # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK -FFA0..FFBE ; H # Lo [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH -FFC2..FFC7 ; H # Lo [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E -FFCA..FFCF ; H # Lo [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE -FFD2..FFD7 ; H # Lo [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU -FFDA..FFDC ; H # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I -FFE0..FFE1 ; F # Sc [2] FULLWIDTH CENT SIGN..FULLWIDTH POUND SIGN -FFE2 ; F # Sm FULLWIDTH NOT SIGN -FFE3 ; F # Sk FULLWIDTH MACRON -FFE4 ; F # So FULLWIDTH BROKEN BAR -FFE5..FFE6 ; F # Sc [2] FULLWIDTH YEN SIGN..FULLWIDTH WON SIGN -FFE8 ; H # So HALFWIDTH FORMS LIGHT VERTICAL -FFE9..FFEC ; H # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW -FFED..FFEE ; H # So [2] HALFWIDTH BLACK SQUARE..HALFWIDTH WHITE CIRCLE -FFF9..FFFB ; N # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR -FFFC ; N # So OBJECT REPLACEMENT CHARACTER -FFFD ; A # So REPLACEMENT CHARACTER -10000..1000B ; N # Lo [12] LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE -1000D..10026 ; N # Lo [26] LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO -10028..1003A ; N # Lo [19] LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO -1003C..1003D ; N # Lo [2] LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE -1003F..1004D ; N # Lo [15] LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO -10050..1005D ; N # Lo [14] LINEAR B SYMBOL B018..LINEAR B SYMBOL B089 -10080..100FA ; N # Lo [123] LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305 -10100..10102 ; N # Po [3] AEGEAN WORD SEPARATOR LINE..AEGEAN CHECK MARK -10107..10133 ; N # No [45] AEGEAN NUMBER ONE..AEGEAN NUMBER NINETY THOUSAND -10137..1013F ; N # So [9] AEGEAN WEIGHT BASE UNIT..AEGEAN MEASURE THIRD SUBUNIT -10140..10174 ; N # Nl [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS -10175..10178 ; N # No [4] GREEK ONE HALF SIGN..GREEK THREE QUARTERS SIGN -10179..10189 ; N # So [17] GREEK YEAR SIGN..GREEK TRYBLION BASE SIGN -1018A..1018B ; N # No [2] GREEK ZERO SIGN..GREEK ONE QUARTER SIGN -1018C..1018E ; N # So [3] GREEK SINUSOID SIGN..NOMISMA SIGN -10190..1019C ; N # So [13] ROMAN SEXTANS SIGN..ASCIA SYMBOL -101A0 ; N # So GREEK SYMBOL TAU RHO -101D0..101FC ; N # So [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND -101FD ; N # Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE -10280..1029C ; N # Lo [29] LYCIAN LETTER A..LYCIAN LETTER X -102A0..102D0 ; N # Lo [49] CARIAN LETTER A..CARIAN LETTER UUU3 -102E0 ; N # Mn COPTIC EPACT THOUSANDS MARK -102E1..102FB ; N # No [27] COPTIC EPACT DIGIT ONE..COPTIC EPACT NUMBER NINE HUNDRED -10300..1031F ; N # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS -10320..10323 ; N # No [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY -1032D..1032F ; N # Lo [3] OLD ITALIC LETTER YE..OLD ITALIC LETTER SOUTHERN TSE -10330..10340 ; N # Lo [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA -10341 ; N # Nl GOTHIC LETTER NINETY -10342..10349 ; N # Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL -1034A ; N # Nl GOTHIC LETTER NINE HUNDRED -10350..10375 ; N # Lo [38] OLD PERMIC LETTER AN..OLD PERMIC LETTER IA -10376..1037A ; N # Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII -10380..1039D ; N # Lo [30] UGARITIC LETTER ALPA..UGARITIC LETTER SSU -1039F ; N # Po UGARITIC WORD DIVIDER -103A0..103C3 ; N # Lo [36] OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA -103C8..103CF ; N # Lo [8] OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH -103D0 ; N # Po OLD PERSIAN WORD DIVIDER -103D1..103D5 ; N # Nl [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED -10400..1044F ; N # L& [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW -10450..1047F ; N # Lo [48] SHAVIAN LETTER PEEP..SHAVIAN LETTER YEW -10480..1049D ; N # Lo [30] OSMANYA LETTER ALEF..OSMANYA LETTER OO -104A0..104A9 ; N # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE -104B0..104D3 ; N # Lu [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA -104D8..104FB ; N # Ll [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA -10500..10527 ; N # Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE -10530..10563 ; N # Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW -1056F ; N # Po CAUCASIAN ALBANIAN CITATION MARK -10570..1057A ; N # Lu [11] VITHKUQI CAPITAL LETTER A..VITHKUQI CAPITAL LETTER GA -1057C..1058A ; N # Lu [15] VITHKUQI CAPITAL LETTER HA..VITHKUQI CAPITAL LETTER RE -1058C..10592 ; N # Lu [7] VITHKUQI CAPITAL LETTER SE..VITHKUQI CAPITAL LETTER XE -10594..10595 ; N # Lu [2] VITHKUQI CAPITAL LETTER Y..VITHKUQI CAPITAL LETTER ZE -10597..105A1 ; N # Ll [11] VITHKUQI SMALL LETTER A..VITHKUQI SMALL LETTER GA -105A3..105B1 ; N # Ll [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE -105B3..105B9 ; N # Ll [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE -105BB..105BC ; N # Ll [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE -10600..10736 ; N # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 -10740..10755 ; N # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE -10760..10767 ; N # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807 -10780..10785 ; N # Lm [6] MODIFIER LETTER SMALL CAPITAL AA..MODIFIER LETTER SMALL B WITH HOOK -10787..107B0 ; N # Lm [42] MODIFIER LETTER SMALL DZ DIGRAPH..MODIFIER LETTER SMALL V WITH RIGHT HOOK -107B2..107BA ; N # Lm [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL -10800..10805 ; N # Lo [6] CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA -10808 ; N # Lo CYPRIOT SYLLABLE JO -1080A..10835 ; N # Lo [44] CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO -10837..10838 ; N # Lo [2] CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE -1083C ; N # Lo CYPRIOT SYLLABLE ZA -1083F ; N # Lo CYPRIOT SYLLABLE ZO -10840..10855 ; N # Lo [22] IMPERIAL ARAMAIC LETTER ALEPH..IMPERIAL ARAMAIC LETTER TAW -10857 ; N # Po IMPERIAL ARAMAIC SECTION SIGN -10858..1085F ; N # No [8] IMPERIAL ARAMAIC NUMBER ONE..IMPERIAL ARAMAIC NUMBER TEN THOUSAND -10860..10876 ; N # Lo [23] PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW -10877..10878 ; N # So [2] PALMYRENE LEFT-POINTING FLEURON..PALMYRENE RIGHT-POINTING FLEURON -10879..1087F ; N # No [7] PALMYRENE NUMBER ONE..PALMYRENE NUMBER TWENTY -10880..1089E ; N # Lo [31] NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW -108A7..108AF ; N # No [9] NABATAEAN NUMBER ONE..NABATAEAN NUMBER ONE HUNDRED -108E0..108F2 ; N # Lo [19] HATRAN LETTER ALEPH..HATRAN LETTER QOPH -108F4..108F5 ; N # Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW -108FB..108FF ; N # No [5] HATRAN NUMBER ONE..HATRAN NUMBER ONE HUNDRED -10900..10915 ; N # Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU -10916..1091B ; N # No [6] PHOENICIAN NUMBER ONE..PHOENICIAN NUMBER THREE -1091F ; N # Po PHOENICIAN WORD SEPARATOR -10920..10939 ; N # Lo [26] LYDIAN LETTER A..LYDIAN LETTER C -1093F ; N # Po LYDIAN TRIANGULAR MARK -10980..1099F ; N # Lo [32] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC HIEROGLYPHIC SYMBOL VIDJ-2 -109A0..109B7 ; N # Lo [24] MEROITIC CURSIVE LETTER A..MEROITIC CURSIVE LETTER DA -109BC..109BD ; N # No [2] MEROITIC CURSIVE FRACTION ELEVEN TWELFTHS..MEROITIC CURSIVE FRACTION ONE HALF -109BE..109BF ; N # Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN -109C0..109CF ; N # No [16] MEROITIC CURSIVE NUMBER ONE..MEROITIC CURSIVE NUMBER SEVENTY -109D2..109FF ; N # No [46] MEROITIC CURSIVE NUMBER ONE HUNDRED..MEROITIC CURSIVE FRACTION TEN TWELFTHS -10A00 ; N # Lo KHAROSHTHI LETTER A -10A01..10A03 ; N # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R -10A05..10A06 ; N # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O -10A0C..10A0F ; N # Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA -10A10..10A13 ; N # Lo [4] KHAROSHTHI LETTER KA..KHAROSHTHI LETTER GHA -10A15..10A17 ; N # Lo [3] KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA -10A19..10A35 ; N # Lo [29] KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER VHA -10A38..10A3A ; N # Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW -10A3F ; N # Mn KHAROSHTHI VIRAMA -10A40..10A48 ; N # No [9] KHAROSHTHI DIGIT ONE..KHAROSHTHI FRACTION ONE HALF -10A50..10A58 ; N # Po [9] KHAROSHTHI PUNCTUATION DOT..KHAROSHTHI PUNCTUATION LINES -10A60..10A7C ; N # Lo [29] OLD SOUTH ARABIAN LETTER HE..OLD SOUTH ARABIAN LETTER THETH -10A7D..10A7E ; N # No [2] OLD SOUTH ARABIAN NUMBER ONE..OLD SOUTH ARABIAN NUMBER FIFTY -10A7F ; N # Po OLD SOUTH ARABIAN NUMERIC INDICATOR -10A80..10A9C ; N # Lo [29] OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH -10A9D..10A9F ; N # No [3] OLD NORTH ARABIAN NUMBER ONE..OLD NORTH ARABIAN NUMBER TWENTY -10AC0..10AC7 ; N # Lo [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW -10AC8 ; N # So MANICHAEAN SIGN UD -10AC9..10AE4 ; N # Lo [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW -10AE5..10AE6 ; N # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW -10AEB..10AEF ; N # No [5] MANICHAEAN NUMBER ONE..MANICHAEAN NUMBER ONE HUNDRED -10AF0..10AF6 ; N # Po [7] MANICHAEAN PUNCTUATION STAR..MANICHAEAN PUNCTUATION LINE FILLER -10B00..10B35 ; N # Lo [54] AVESTAN LETTER A..AVESTAN LETTER HE -10B39..10B3F ; N # Po [7] AVESTAN ABBREVIATION MARK..LARGE ONE RING OVER TWO RINGS PUNCTUATION -10B40..10B55 ; N # Lo [22] INSCRIPTIONAL PARTHIAN LETTER ALEPH..INSCRIPTIONAL PARTHIAN LETTER TAW -10B58..10B5F ; N # No [8] INSCRIPTIONAL PARTHIAN NUMBER ONE..INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND -10B60..10B72 ; N # Lo [19] INSCRIPTIONAL PAHLAVI LETTER ALEPH..INSCRIPTIONAL PAHLAVI LETTER TAW -10B78..10B7F ; N # No [8] INSCRIPTIONAL PAHLAVI NUMBER ONE..INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND -10B80..10B91 ; N # Lo [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW -10B99..10B9C ; N # Po [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT -10BA9..10BAF ; N # No [7] PSALTER PAHLAVI NUMBER ONE..PSALTER PAHLAVI NUMBER ONE HUNDRED -10C00..10C48 ; N # Lo [73] OLD TURKIC LETTER ORKHON A..OLD TURKIC LETTER ORKHON BASH -10C80..10CB2 ; N # Lu [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US -10CC0..10CF2 ; N # Ll [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US -10CFA..10CFF ; N # No [6] OLD HUNGARIAN NUMBER ONE..OLD HUNGARIAN NUMBER ONE THOUSAND -10D00..10D23 ; N # Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA -10D24..10D27 ; N # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI -10D30..10D39 ; N # Nd [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE -10E60..10E7E ; N # No [31] RUMI DIGIT ONE..RUMI FRACTION TWO THIRDS -10E80..10EA9 ; N # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET -10EAB..10EAC ; N # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK -10EAD ; N # Pd YEZIDI HYPHENATION MARK -10EB0..10EB1 ; N # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE -10EFD..10EFF ; N # Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA -10F00..10F1C ; N # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL -10F1D..10F26 ; N # No [10] OLD SOGDIAN NUMBER ONE..OLD SOGDIAN FRACTION ONE HALF -10F27 ; N # Lo OLD SOGDIAN LIGATURE AYIN-DALETH -10F30..10F45 ; N # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN -10F46..10F50 ; N # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW -10F51..10F54 ; N # No [4] SOGDIAN NUMBER ONE..SOGDIAN NUMBER ONE HUNDRED -10F55..10F59 ; N # Po [5] SOGDIAN PUNCTUATION TWO VERTICAL BARS..SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT -10F70..10F81 ; N # Lo [18] OLD UYGHUR LETTER ALEPH..OLD UYGHUR LETTER LESH -10F82..10F85 ; N # Mn [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW -10F86..10F89 ; N # Po [4] OLD UYGHUR PUNCTUATION BAR..OLD UYGHUR PUNCTUATION FOUR DOTS -10FB0..10FC4 ; N # Lo [21] CHORASMIAN LETTER ALEPH..CHORASMIAN LETTER TAW -10FC5..10FCB ; N # No [7] CHORASMIAN NUMBER ONE..CHORASMIAN NUMBER ONE HUNDRED -10FE0..10FF6 ; N # Lo [23] ELYMAIC LETTER ALEPH..ELYMAIC LIGATURE ZAYIN-YODH -11000 ; N # Mc BRAHMI SIGN CANDRABINDU -11001 ; N # Mn BRAHMI SIGN ANUSVARA -11002 ; N # Mc BRAHMI SIGN VISARGA -11003..11037 ; N # Lo [53] BRAHMI SIGN JIHVAMULIYA..BRAHMI LETTER OLD TAMIL NNNA -11038..11046 ; N # Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA -11047..1104D ; N # Po [7] BRAHMI DANDA..BRAHMI PUNCTUATION LOTUS -11052..11065 ; N # No [20] BRAHMI NUMBER ONE..BRAHMI NUMBER ONE THOUSAND -11066..1106F ; N # Nd [10] BRAHMI DIGIT ZERO..BRAHMI DIGIT NINE -11070 ; N # Mn BRAHMI SIGN OLD TAMIL VIRAMA -11071..11072 ; N # Lo [2] BRAHMI LETTER OLD TAMIL SHORT E..BRAHMI LETTER OLD TAMIL SHORT O -11073..11074 ; N # Mn [2] BRAHMI VOWEL SIGN OLD TAMIL SHORT E..BRAHMI VOWEL SIGN OLD TAMIL SHORT O -11075 ; N # Lo BRAHMI LETTER OLD TAMIL LLA -1107F ; N # Mn BRAHMI NUMBER JOINER -11080..11081 ; N # Mn [2] KAITHI SIGN CANDRABINDU..KAITHI SIGN ANUSVARA -11082 ; N # Mc KAITHI SIGN VISARGA -11083..110AF ; N # Lo [45] KAITHI LETTER A..KAITHI LETTER HA -110B0..110B2 ; N # Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II -110B3..110B6 ; N # Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI -110B7..110B8 ; N # Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU -110B9..110BA ; N # Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA -110BB..110BC ; N # Po [2] KAITHI ABBREVIATION SIGN..KAITHI ENUMERATION SIGN -110BD ; N # Cf KAITHI NUMBER SIGN -110BE..110C1 ; N # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA -110C2 ; N # Mn KAITHI VOWEL SIGN VOCALIC R -110CD ; N # Cf KAITHI NUMBER SIGN ABOVE -110D0..110E8 ; N # Lo [25] SORA SOMPENG LETTER SAH..SORA SOMPENG LETTER MAE -110F0..110F9 ; N # Nd [10] SORA SOMPENG DIGIT ZERO..SORA SOMPENG DIGIT NINE -11100..11102 ; N # Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA -11103..11126 ; N # Lo [36] CHAKMA LETTER AA..CHAKMA LETTER HAA -11127..1112B ; N # Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU -1112C ; N # Mc CHAKMA VOWEL SIGN E -1112D..11134 ; N # Mn [8] CHAKMA VOWEL SIGN AI..CHAKMA MAAYYAA -11136..1113F ; N # Nd [10] CHAKMA DIGIT ZERO..CHAKMA DIGIT NINE -11140..11143 ; N # Po [4] CHAKMA SECTION MARK..CHAKMA QUESTION MARK -11144 ; N # Lo CHAKMA LETTER LHAA -11145..11146 ; N # Mc [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI -11147 ; N # Lo CHAKMA LETTER VAA -11150..11172 ; N # Lo [35] MAHAJANI LETTER A..MAHAJANI LETTER RRA -11173 ; N # Mn MAHAJANI SIGN NUKTA -11174..11175 ; N # Po [2] MAHAJANI ABBREVIATION SIGN..MAHAJANI SECTION MARK -11176 ; N # Lo MAHAJANI LIGATURE SHRI -11180..11181 ; N # Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA -11182 ; N # Mc SHARADA SIGN VISARGA -11183..111B2 ; N # Lo [48] SHARADA LETTER A..SHARADA LETTER HA -111B3..111B5 ; N # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II -111B6..111BE ; N # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O -111BF..111C0 ; N # Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA -111C1..111C4 ; N # Lo [4] SHARADA SIGN AVAGRAHA..SHARADA OM -111C5..111C8 ; N # Po [4] SHARADA DANDA..SHARADA SEPARATOR -111C9..111CC ; N # Mn [4] SHARADA SANDHI MARK..SHARADA EXTRA SHORT VOWEL MARK -111CD ; N # Po SHARADA SUTRA MARK -111CE ; N # Mc SHARADA VOWEL SIGN PRISHTHAMATRA E -111CF ; N # Mn SHARADA SIGN INVERTED CANDRABINDU -111D0..111D9 ; N # Nd [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE -111DA ; N # Lo SHARADA EKAM -111DB ; N # Po SHARADA SIGN SIDDHAM -111DC ; N # Lo SHARADA HEADSTROKE -111DD..111DF ; N # Po [3] SHARADA CONTINUATION SIGN..SHARADA SECTION MARK-2 -111E1..111F4 ; N # No [20] SINHALA ARCHAIC DIGIT ONE..SINHALA ARCHAIC NUMBER ONE THOUSAND -11200..11211 ; N # Lo [18] KHOJKI LETTER A..KHOJKI LETTER JJA -11213..1122B ; N # Lo [25] KHOJKI LETTER NYA..KHOJKI LETTER LLA -1122C..1122E ; N # Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II -1122F..11231 ; N # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI -11232..11233 ; N # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU -11234 ; N # Mn KHOJKI SIGN ANUSVARA -11235 ; N # Mc KHOJKI SIGN VIRAMA -11236..11237 ; N # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA -11238..1123D ; N # Po [6] KHOJKI DANDA..KHOJKI ABBREVIATION SIGN -1123E ; N # Mn KHOJKI SIGN SUKUN -1123F..11240 ; N # Lo [2] KHOJKI LETTER QA..KHOJKI LETTER SHORT I -11241 ; N # Mn KHOJKI VOWEL SIGN VOCALIC R -11280..11286 ; N # Lo [7] MULTANI LETTER A..MULTANI LETTER GA -11288 ; N # Lo MULTANI LETTER GHA -1128A..1128D ; N # Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA -1128F..1129D ; N # Lo [15] MULTANI LETTER NYA..MULTANI LETTER BA -1129F..112A8 ; N # Lo [10] MULTANI LETTER BHA..MULTANI LETTER RHA -112A9 ; N # Po MULTANI SECTION MARK -112B0..112DE ; N # Lo [47] KHUDAWADI LETTER A..KHUDAWADI LETTER HA -112DF ; N # Mn KHUDAWADI SIGN ANUSVARA -112E0..112E2 ; N # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II -112E3..112EA ; N # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA -112F0..112F9 ; N # Nd [10] KHUDAWADI DIGIT ZERO..KHUDAWADI DIGIT NINE -11300..11301 ; N # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU -11302..11303 ; N # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA -11305..1130C ; N # Lo [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L -1130F..11310 ; N # Lo [2] GRANTHA LETTER EE..GRANTHA LETTER AI -11313..11328 ; N # Lo [22] GRANTHA LETTER OO..GRANTHA LETTER NA -1132A..11330 ; N # Lo [7] GRANTHA LETTER PA..GRANTHA LETTER RA -11332..11333 ; N # Lo [2] GRANTHA LETTER LA..GRANTHA LETTER LLA -11335..11339 ; N # Lo [5] GRANTHA LETTER VA..GRANTHA LETTER HA -1133B..1133C ; N # Mn [2] COMBINING BINDU BELOW..GRANTHA SIGN NUKTA -1133D ; N # Lo GRANTHA SIGN AVAGRAHA -1133E..1133F ; N # Mc [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I -11340 ; N # Mn GRANTHA VOWEL SIGN II -11341..11344 ; N # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR -11347..11348 ; N # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI -1134B..1134D ; N # Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA -11350 ; N # Lo GRANTHA OM -11357 ; N # Mc GRANTHA AU LENGTH MARK -1135D..11361 ; N # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL -11362..11363 ; N # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL -11366..1136C ; N # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX -11370..11374 ; N # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA -11400..11434 ; N # Lo [53] NEWA LETTER A..NEWA LETTER HA -11435..11437 ; N # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II -11438..1143F ; N # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI -11440..11441 ; N # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU -11442..11444 ; N # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA -11445 ; N # Mc NEWA SIGN VISARGA -11446 ; N # Mn NEWA SIGN NUKTA -11447..1144A ; N # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI -1144B..1144F ; N # Po [5] NEWA DANDA..NEWA ABBREVIATION SIGN -11450..11459 ; N # Nd [10] NEWA DIGIT ZERO..NEWA DIGIT NINE -1145A..1145B ; N # Po [2] NEWA DOUBLE COMMA..NEWA PLACEHOLDER MARK -1145D ; N # Po NEWA INSERTION SIGN -1145E ; N # Mn NEWA SANDHI MARK -1145F..11461 ; N # Lo [3] NEWA LETTER VEDIC ANUSVARA..NEWA SIGN UPADHMANIYA -11480..114AF ; N # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA -114B0..114B2 ; N # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II -114B3..114B8 ; N # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL -114B9 ; N # Mc TIRHUTA VOWEL SIGN E -114BA ; N # Mn TIRHUTA VOWEL SIGN SHORT E -114BB..114BE ; N # Mc [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU -114BF..114C0 ; N # Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA -114C1 ; N # Mc TIRHUTA SIGN VISARGA -114C2..114C3 ; N # Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA -114C4..114C5 ; N # Lo [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG -114C6 ; N # Po TIRHUTA ABBREVIATION SIGN -114C7 ; N # Lo TIRHUTA OM -114D0..114D9 ; N # Nd [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE -11580..115AE ; N # Lo [47] SIDDHAM LETTER A..SIDDHAM LETTER HA -115AF..115B1 ; N # Mc [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II -115B2..115B5 ; N # Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR -115B8..115BB ; N # Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU -115BC..115BD ; N # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA -115BE ; N # Mc SIDDHAM SIGN VISARGA -115BF..115C0 ; N # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA -115C1..115D7 ; N # Po [23] SIDDHAM SIGN SIDDHAM..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES -115D8..115DB ; N # Lo [4] SIDDHAM LETTER THREE-CIRCLE ALTERNATE I..SIDDHAM LETTER ALTERNATE U -115DC..115DD ; N # Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU -11600..1162F ; N # Lo [48] MODI LETTER A..MODI LETTER LLA -11630..11632 ; N # Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II -11633..1163A ; N # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI -1163B..1163C ; N # Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU -1163D ; N # Mn MODI SIGN ANUSVARA -1163E ; N # Mc MODI SIGN VISARGA -1163F..11640 ; N # Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA -11641..11643 ; N # Po [3] MODI DANDA..MODI ABBREVIATION SIGN -11644 ; N # Lo MODI SIGN HUVA -11650..11659 ; N # Nd [10] MODI DIGIT ZERO..MODI DIGIT NINE -11660..1166C ; N # Po [13] MONGOLIAN BIRGA WITH ORNAMENT..MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT -11680..116AA ; N # Lo [43] TAKRI LETTER A..TAKRI LETTER RRA -116AB ; N # Mn TAKRI SIGN ANUSVARA -116AC ; N # Mc TAKRI SIGN VISARGA -116AD ; N # Mn TAKRI VOWEL SIGN AA -116AE..116AF ; N # Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II -116B0..116B5 ; N # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU -116B6 ; N # Mc TAKRI SIGN VIRAMA -116B7 ; N # Mn TAKRI SIGN NUKTA -116B8 ; N # Lo TAKRI LETTER ARCHAIC KHA -116B9 ; N # Po TAKRI ABBREVIATION SIGN -116C0..116C9 ; N # Nd [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE -11700..1171A ; N # Lo [27] AHOM LETTER KA..AHOM LETTER ALTERNATE BA -1171D..1171F ; N # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA -11720..11721 ; N # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA -11722..11725 ; N # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU -11726 ; N # Mc AHOM VOWEL SIGN E -11727..1172B ; N # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER -11730..11739 ; N # Nd [10] AHOM DIGIT ZERO..AHOM DIGIT NINE -1173A..1173B ; N # No [2] AHOM NUMBER TEN..AHOM NUMBER TWENTY -1173C..1173E ; N # Po [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI -1173F ; N # So AHOM SYMBOL VI -11740..11746 ; N # Lo [7] AHOM LETTER CA..AHOM LETTER LLA -11800..1182B ; N # Lo [44] DOGRA LETTER A..DOGRA LETTER RRA -1182C..1182E ; N # Mc [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II -1182F..11837 ; N # Mn [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA -11838 ; N # Mc DOGRA SIGN VISARGA -11839..1183A ; N # Mn [2] DOGRA SIGN VIRAMA..DOGRA SIGN NUKTA -1183B ; N # Po DOGRA ABBREVIATION SIGN -118A0..118DF ; N # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO -118E0..118E9 ; N # Nd [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE -118EA..118F2 ; N # No [9] WARANG CITI NUMBER TEN..WARANG CITI NUMBER NINETY -118FF ; N # Lo WARANG CITI OM -11900..11906 ; N # Lo [7] DIVES AKURU LETTER A..DIVES AKURU LETTER E -11909 ; N # Lo DIVES AKURU LETTER O -1190C..11913 ; N # Lo [8] DIVES AKURU LETTER KA..DIVES AKURU LETTER JA -11915..11916 ; N # Lo [2] DIVES AKURU LETTER NYA..DIVES AKURU LETTER TTA -11918..1192F ; N # Lo [24] DIVES AKURU LETTER DDA..DIVES AKURU LETTER ZA -11930..11935 ; N # Mc [6] DIVES AKURU VOWEL SIGN AA..DIVES AKURU VOWEL SIGN E -11937..11938 ; N # Mc [2] DIVES AKURU VOWEL SIGN AI..DIVES AKURU VOWEL SIGN O -1193B..1193C ; N # Mn [2] DIVES AKURU SIGN ANUSVARA..DIVES AKURU SIGN CANDRABINDU -1193D ; N # Mc DIVES AKURU SIGN HALANTA -1193E ; N # Mn DIVES AKURU VIRAMA -1193F ; N # Lo DIVES AKURU PREFIXED NASAL SIGN -11940 ; N # Mc DIVES AKURU MEDIAL YA -11941 ; N # Lo DIVES AKURU INITIAL RA -11942 ; N # Mc DIVES AKURU MEDIAL RA -11943 ; N # Mn DIVES AKURU SIGN NUKTA -11944..11946 ; N # Po [3] DIVES AKURU DOUBLE DANDA..DIVES AKURU END OF TEXT MARK -11950..11959 ; N # Nd [10] DIVES AKURU DIGIT ZERO..DIVES AKURU DIGIT NINE -119A0..119A7 ; N # Lo [8] NANDINAGARI LETTER A..NANDINAGARI LETTER VOCALIC RR -119AA..119D0 ; N # Lo [39] NANDINAGARI LETTER E..NANDINAGARI LETTER RRA -119D1..119D3 ; N # Mc [3] NANDINAGARI VOWEL SIGN AA..NANDINAGARI VOWEL SIGN II -119D4..119D7 ; N # Mn [4] NANDINAGARI VOWEL SIGN U..NANDINAGARI VOWEL SIGN VOCALIC RR -119DA..119DB ; N # Mn [2] NANDINAGARI VOWEL SIGN E..NANDINAGARI VOWEL SIGN AI -119DC..119DF ; N # Mc [4] NANDINAGARI VOWEL SIGN O..NANDINAGARI SIGN VISARGA -119E0 ; N # Mn NANDINAGARI SIGN VIRAMA -119E1 ; N # Lo NANDINAGARI SIGN AVAGRAHA -119E2 ; N # Po NANDINAGARI SIGN SIDDHAM -119E3 ; N # Lo NANDINAGARI HEADSTROKE -119E4 ; N # Mc NANDINAGARI VOWEL SIGN PRISHTHAMATRA E -11A00 ; N # Lo ZANABAZAR SQUARE LETTER A -11A01..11A0A ; N # Mn [10] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL LENGTH MARK -11A0B..11A32 ; N # Lo [40] ZANABAZAR SQUARE LETTER KA..ZANABAZAR SQUARE LETTER KSSA -11A33..11A38 ; N # Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA -11A39 ; N # Mc ZANABAZAR SQUARE SIGN VISARGA -11A3A ; N # Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA -11A3B..11A3E ; N # Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA -11A3F..11A46 ; N # Po [8] ZANABAZAR SQUARE INITIAL HEAD MARK..ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK -11A47 ; N # Mn ZANABAZAR SQUARE SUBJOINER -11A50 ; N # Lo SOYOMBO LETTER A -11A51..11A56 ; N # Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE -11A57..11A58 ; N # Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU -11A59..11A5B ; N # Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK -11A5C..11A89 ; N # Lo [46] SOYOMBO LETTER KA..SOYOMBO CLUSTER-INITIAL LETTER SA -11A8A..11A96 ; N # Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA -11A97 ; N # Mc SOYOMBO SIGN VISARGA -11A98..11A99 ; N # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER -11A9A..11A9C ; N # Po [3] SOYOMBO MARK TSHEG..SOYOMBO MARK DOUBLE SHAD -11A9D ; N # Lo SOYOMBO MARK PLUTA -11A9E..11AA2 ; N # Po [5] SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME..SOYOMBO TERMINAL MARK-2 -11AB0..11ABF ; N # Lo [16] CANADIAN SYLLABICS NATTILIK HI..CANADIAN SYLLABICS SPA -11AC0..11AF8 ; N # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL -11B00..11B09 ; N # Po [10] DEVANAGARI HEAD MARK..DEVANAGARI SIGN MINDU -11C00..11C08 ; N # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L -11C0A..11C2E ; N # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA -11C2F ; N # Mc BHAIKSUKI VOWEL SIGN AA -11C30..11C36 ; N # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L -11C38..11C3D ; N # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA -11C3E ; N # Mc BHAIKSUKI SIGN VISARGA -11C3F ; N # Mn BHAIKSUKI SIGN VIRAMA -11C40 ; N # Lo BHAIKSUKI SIGN AVAGRAHA -11C41..11C45 ; N # Po [5] BHAIKSUKI DANDA..BHAIKSUKI GAP FILLER-2 -11C50..11C59 ; N # Nd [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE -11C5A..11C6C ; N # No [19] BHAIKSUKI NUMBER ONE..BHAIKSUKI HUNDREDS UNIT MARK -11C70..11C71 ; N # Po [2] MARCHEN HEAD MARK..MARCHEN MARK SHAD -11C72..11C8F ; N # Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A -11C92..11CA7 ; N # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA -11CA9 ; N # Mc MARCHEN SUBJOINED LETTER YA -11CAA..11CB0 ; N # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA -11CB1 ; N # Mc MARCHEN VOWEL SIGN I -11CB2..11CB3 ; N # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E -11CB4 ; N # Mc MARCHEN VOWEL SIGN O -11CB5..11CB6 ; N # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU -11D00..11D06 ; N # Lo [7] MASARAM GONDI LETTER A..MASARAM GONDI LETTER E -11D08..11D09 ; N # Lo [2] MASARAM GONDI LETTER AI..MASARAM GONDI LETTER O -11D0B..11D30 ; N # Lo [38] MASARAM GONDI LETTER AU..MASARAM GONDI LETTER TRA -11D31..11D36 ; N # Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R -11D3A ; N # Mn MASARAM GONDI VOWEL SIGN E -11D3C..11D3D ; N # Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O -11D3F..11D45 ; N # Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA -11D46 ; N # Lo MASARAM GONDI REPHA -11D47 ; N # Mn MASARAM GONDI RA-KARA -11D50..11D59 ; N # Nd [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE -11D60..11D65 ; N # Lo [6] GUNJALA GONDI LETTER A..GUNJALA GONDI LETTER UU -11D67..11D68 ; N # Lo [2] GUNJALA GONDI LETTER EE..GUNJALA GONDI LETTER AI -11D6A..11D89 ; N # Lo [32] GUNJALA GONDI LETTER OO..GUNJALA GONDI LETTER SA -11D8A..11D8E ; N # Mc [5] GUNJALA GONDI VOWEL SIGN AA..GUNJALA GONDI VOWEL SIGN UU -11D90..11D91 ; N # Mn [2] GUNJALA GONDI VOWEL SIGN EE..GUNJALA GONDI VOWEL SIGN AI -11D93..11D94 ; N # Mc [2] GUNJALA GONDI VOWEL SIGN OO..GUNJALA GONDI VOWEL SIGN AU -11D95 ; N # Mn GUNJALA GONDI SIGN ANUSVARA -11D96 ; N # Mc GUNJALA GONDI SIGN VISARGA -11D97 ; N # Mn GUNJALA GONDI VIRAMA -11D98 ; N # Lo GUNJALA GONDI OM -11DA0..11DA9 ; N # Nd [10] GUNJALA GONDI DIGIT ZERO..GUNJALA GONDI DIGIT NINE -11EE0..11EF2 ; N # Lo [19] MAKASAR LETTER KA..MAKASAR ANGKA -11EF3..11EF4 ; N # Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U -11EF5..11EF6 ; N # Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O -11EF7..11EF8 ; N # Po [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION -11F00..11F01 ; N # Mn [2] KAWI SIGN CANDRABINDU..KAWI SIGN ANUSVARA -11F02 ; N # Lo KAWI SIGN REPHA -11F03 ; N # Mc KAWI SIGN VISARGA -11F04..11F10 ; N # Lo [13] KAWI LETTER A..KAWI LETTER O -11F12..11F33 ; N # Lo [34] KAWI LETTER KA..KAWI LETTER JNYA -11F34..11F35 ; N # Mc [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA -11F36..11F3A ; N # Mn [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R -11F3E..11F3F ; N # Mc [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI -11F40 ; N # Mn KAWI VOWEL SIGN EU -11F41 ; N # Mc KAWI SIGN KILLER -11F42 ; N # Mn KAWI CONJOINER -11F43..11F4F ; N # Po [13] KAWI DANDA..KAWI PUNCTUATION CLOSING SPIRAL -11F50..11F59 ; N # Nd [10] KAWI DIGIT ZERO..KAWI DIGIT NINE -11FB0 ; N # Lo LISU LETTER YHA -11FC0..11FD4 ; N # No [21] TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH..TAMIL FRACTION DOWNSCALING FACTOR KIIZH -11FD5..11FDC ; N # So [8] TAMIL SIGN NEL..TAMIL SIGN MUKKURUNI -11FDD..11FE0 ; N # Sc [4] TAMIL SIGN KAACU..TAMIL SIGN VARAAKAN -11FE1..11FF1 ; N # So [17] TAMIL SIGN PAARAM..TAMIL SIGN VAKAIYARAA -11FFF ; N # Po TAMIL PUNCTUATION END OF TEXT -12000..12399 ; N # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U -12400..1246E ; N # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM -12470..12474 ; N # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON -12480..12543 ; N # Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU -12F90..12FF0 ; N # Lo [97] CYPRO-MINOAN SIGN CM001..CYPRO-MINOAN SIGN CM114 -12FF1..12FF2 ; N # Po [2] CYPRO-MINOAN SIGN CM301..CYPRO-MINOAN SIGN CM302 -13000..1342F ; N # Lo [1072] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D -13430..1343F ; N # Cf [16] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE -13440 ; N # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY -13441..13446 ; N # Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN -13447..13455 ; N # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED -14400..14646 ; N # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 -16800..16A38 ; N # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ -16A40..16A5E ; N # Lo [31] MRO LETTER TA..MRO LETTER TEK -16A60..16A69 ; N # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE -16A6E..16A6F ; N # Po [2] MRO DANDA..MRO DOUBLE DANDA -16A70..16ABE ; N # Lo [79] TANGSA LETTER OZ..TANGSA LETTER ZA -16AC0..16AC9 ; N # Nd [10] TANGSA DIGIT ZERO..TANGSA DIGIT NINE -16AD0..16AED ; N # Lo [30] BASSA VAH LETTER ENNI..BASSA VAH LETTER I -16AF0..16AF4 ; N # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE -16AF5 ; N # Po BASSA VAH FULL STOP -16B00..16B2F ; N # Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU -16B30..16B36 ; N # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM -16B37..16B3B ; N # Po [5] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS FEEM -16B3C..16B3F ; N # So [4] PAHAWH HMONG SIGN XYEEM NTXIV..PAHAWH HMONG SIGN XYEEM FAIB -16B40..16B43 ; N # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM -16B44 ; N # Po PAHAWH HMONG SIGN XAUS -16B45 ; N # So PAHAWH HMONG SIGN CIM TSOV ROG -16B50..16B59 ; N # Nd [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE -16B5B..16B61 ; N # No [7] PAHAWH HMONG NUMBER TENS..PAHAWH HMONG NUMBER TRILLIONS -16B63..16B77 ; N # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS -16B7D..16B8F ; N # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ -16E40..16E7F ; N # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y -16E80..16E96 ; N # No [23] MEDEFAIDRIN DIGIT ZERO..MEDEFAIDRIN DIGIT THREE ALTERNATE FORM -16E97..16E9A ; N # Po [4] MEDEFAIDRIN COMMA..MEDEFAIDRIN EXCLAMATION OH -16F00..16F4A ; N # Lo [75] MIAO LETTER PA..MIAO LETTER RTE -16F4F ; N # Mn MIAO SIGN CONSONANT MODIFIER BAR -16F50 ; N # Lo MIAO LETTER NASALIZATION -16F51..16F87 ; N # Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI -16F8F..16F92 ; N # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW -16F93..16F9F ; N # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 -16FE0..16FE1 ; W # Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK -16FE2 ; W # Po OLD CHINESE HOOK MARK -16FE3 ; W # Lm OLD CHINESE ITERATION MARK -16FE4 ; W # Mn KHITAN SMALL SCRIPT FILLER -16FF0..16FF1 ; W # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY -17000..187F7 ; W # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 -18800..18AFF ; W # Lo [768] TANGUT COMPONENT-001..TANGUT COMPONENT-768 -18B00..18CD5 ; W # Lo [470] KHITAN SMALL SCRIPT CHARACTER-18B00..KHITAN SMALL SCRIPT CHARACTER-18CD5 -18D00..18D08 ; W # Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08 -1AFF0..1AFF3 ; W # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 -1AFF5..1AFFB ; W # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 -1AFFD..1AFFE ; W # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 -1B000..1B0FF ; W # Lo [256] KATAKANA LETTER ARCHAIC E..HENTAIGANA LETTER RE-2 -1B100..1B122 ; W # Lo [35] HENTAIGANA LETTER RE-3..KATAKANA LETTER ARCHAIC WU -1B132 ; W # Lo HIRAGANA LETTER SMALL KO -1B150..1B152 ; W # Lo [3] HIRAGANA LETTER SMALL WI..HIRAGANA LETTER SMALL WO -1B155 ; W # Lo KATAKANA LETTER SMALL KO -1B164..1B167 ; W # Lo [4] KATAKANA LETTER SMALL WI..KATAKANA LETTER SMALL N -1B170..1B2FB ; W # Lo [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB -1BC00..1BC6A ; N # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M -1BC70..1BC7C ; N # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK -1BC80..1BC88 ; N # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL -1BC90..1BC99 ; N # Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW -1BC9C ; N # So DUPLOYAN SIGN O WITH CROSS -1BC9D..1BC9E ; N # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK -1BC9F ; N # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP -1BCA0..1BCA3 ; N # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP -1CF00..1CF2D ; N # Mn [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT -1CF30..1CF46 ; N # Mn [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG -1CF50..1CFC3 ; N # So [116] ZNAMENNY NEUME KRYUK..ZNAMENNY NEUME PAUK -1D000..1D0F5 ; N # So [246] BYZANTINE MUSICAL SYMBOL PSILI..BYZANTINE MUSICAL SYMBOL GORGON NEO KATO -1D100..1D126 ; N # So [39] MUSICAL SYMBOL SINGLE BARLINE..MUSICAL SYMBOL DRUM CLEF-2 -1D129..1D164 ; N # So [60] MUSICAL SYMBOL MULTIPLE MEASURE REST..MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE -1D165..1D166 ; N # Mc [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM -1D167..1D169 ; N # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3 -1D16A..1D16C ; N # So [3] MUSICAL SYMBOL FINGERED TREMOLO-1..MUSICAL SYMBOL FINGERED TREMOLO-3 -1D16D..1D172 ; N # Mc [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5 -1D173..1D17A ; N # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE -1D17B..1D182 ; N # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE -1D183..1D184 ; N # So [2] MUSICAL SYMBOL ARPEGGIATO UP..MUSICAL SYMBOL ARPEGGIATO DOWN -1D185..1D18B ; N # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE -1D18C..1D1A9 ; N # So [30] MUSICAL SYMBOL RINFORZANDO..MUSICAL SYMBOL DEGREE SLASH -1D1AA..1D1AD ; N # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO -1D1AE..1D1EA ; N # So [61] MUSICAL SYMBOL PEDAL MARK..MUSICAL SYMBOL KORON -1D200..1D241 ; N # So [66] GREEK VOCAL NOTATION SYMBOL-1..GREEK INSTRUMENTAL NOTATION SYMBOL-54 -1D242..1D244 ; N # Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME -1D245 ; N # So GREEK MUSICAL LEIMMA -1D2C0..1D2D3 ; N # No [20] KAKTOVIK NUMERAL ZERO..KAKTOVIK NUMERAL NINETEEN -1D2E0..1D2F3 ; N # No [20] MAYAN NUMERAL ZERO..MAYAN NUMERAL NINETEEN -1D300..1D356 ; N # So [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING -1D360..1D378 ; N # No [25] COUNTING ROD UNIT DIGIT ONE..TALLY MARK FIVE -1D400..1D454 ; N # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G -1D456..1D49C ; N # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A -1D49E..1D49F ; N # Lu [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D -1D4A2 ; N # Lu MATHEMATICAL SCRIPT CAPITAL G -1D4A5..1D4A6 ; N # Lu [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K -1D4A9..1D4AC ; N # Lu [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q -1D4AE..1D4B9 ; N # L& [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D -1D4BB ; N # Ll MATHEMATICAL SCRIPT SMALL F -1D4BD..1D4C3 ; N # Ll [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N -1D4C5..1D505 ; N # L& [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B -1D507..1D50A ; N # Lu [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G -1D50D..1D514 ; N # Lu [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q -1D516..1D51C ; N # Lu [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y -1D51E..1D539 ; N # L& [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B -1D53B..1D53E ; N # Lu [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G -1D540..1D544 ; N # Lu [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M -1D546 ; N # Lu MATHEMATICAL DOUBLE-STRUCK CAPITAL O -1D54A..1D550 ; N # Lu [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y -1D552..1D6A5 ; N # L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J -1D6A8..1D6C0 ; N # Lu [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA -1D6C1 ; N # Sm MATHEMATICAL BOLD NABLA -1D6C2..1D6DA ; N # Ll [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA -1D6DB ; N # Sm MATHEMATICAL BOLD PARTIAL DIFFERENTIAL -1D6DC..1D6FA ; N # L& [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA -1D6FB ; N # Sm MATHEMATICAL ITALIC NABLA -1D6FC..1D714 ; N # Ll [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA -1D715 ; N # Sm MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL -1D716..1D734 ; N # L& [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA -1D735 ; N # Sm MATHEMATICAL BOLD ITALIC NABLA -1D736..1D74E ; N # Ll [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA -1D74F ; N # Sm MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL -1D750..1D76E ; N # L& [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA -1D76F ; N # Sm MATHEMATICAL SANS-SERIF BOLD NABLA -1D770..1D788 ; N # Ll [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA -1D789 ; N # Sm MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL -1D78A..1D7A8 ; N # L& [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA -1D7A9 ; N # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA -1D7AA..1D7C2 ; N # Ll [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA -1D7C3 ; N # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL -1D7C4..1D7CB ; N # L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA -1D7CE..1D7FF ; N # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE -1D800..1D9FF ; N # So [512] SIGNWRITING HAND-FIST INDEX..SIGNWRITING HEAD -1DA00..1DA36 ; N # Mn [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN -1DA37..1DA3A ; N # So [4] SIGNWRITING AIR BLOW SMALL ROTATIONS..SIGNWRITING BREATH EXHALE -1DA3B..1DA6C ; N # Mn [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT -1DA6D..1DA74 ; N # So [8] SIGNWRITING SHOULDER HIP SPINE..SIGNWRITING TORSO-FLOORPLANE TWISTING -1DA75 ; N # Mn SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS -1DA76..1DA83 ; N # So [14] SIGNWRITING LIMB COMBINATION..SIGNWRITING LOCATION DEPTH -1DA84 ; N # Mn SIGNWRITING LOCATION HEAD NECK -1DA85..1DA86 ; N # So [2] SIGNWRITING LOCATION TORSO..SIGNWRITING LOCATION LIMBS DIGITS -1DA87..1DA8B ; N # Po [5] SIGNWRITING COMMA..SIGNWRITING PARENTHESIS -1DA9B..1DA9F ; N # Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6 -1DAA1..1DAAF ; N # Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16 -1DF00..1DF09 ; N # Ll [10] LATIN SMALL LETTER FENG DIGRAPH WITH TRILL..LATIN SMALL LETTER T WITH HOOK AND RETROFLEX HOOK -1DF0A ; N # Lo LATIN LETTER RETROFLEX CLICK WITH RETROFLEX HOOK -1DF0B..1DF1E ; N # Ll [20] LATIN SMALL LETTER ESH WITH DOUBLE BAR..LATIN SMALL LETTER S WITH CURL -1DF25..1DF2A ; N # Ll [6] LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK..LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK -1E000..1E006 ; N # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE -1E008..1E018 ; N # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU -1E01B..1E021 ; N # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI -1E023..1E024 ; N # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS -1E026..1E02A ; N # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA -1E030..1E06D ; N # Lm [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE -1E08F ; N # Mn COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I -1E100..1E12C ; N # Lo [45] NYIAKENG PUACHUE HMONG LETTER MA..NYIAKENG PUACHUE HMONG LETTER W -1E130..1E136 ; N # Mn [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D -1E137..1E13D ; N # Lm [7] NYIAKENG PUACHUE HMONG SIGN FOR PERSON..NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER -1E140..1E149 ; N # Nd [10] NYIAKENG PUACHUE HMONG DIGIT ZERO..NYIAKENG PUACHUE HMONG DIGIT NINE -1E14E ; N # Lo NYIAKENG PUACHUE HMONG LOGOGRAM NYAJ -1E14F ; N # So NYIAKENG PUACHUE HMONG CIRCLED CA -1E290..1E2AD ; N # Lo [30] TOTO LETTER PA..TOTO LETTER A -1E2AE ; N # Mn TOTO SIGN RISING TONE -1E2C0..1E2EB ; N # Lo [44] WANCHO LETTER AA..WANCHO LETTER YIH -1E2EC..1E2EF ; N # Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI -1E2F0..1E2F9 ; N # Nd [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE -1E2FF ; N # Sc WANCHO NGUN SIGN -1E4D0..1E4EA ; N # Lo [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL -1E4EB ; N # Lm NAG MUNDARI SIGN OJOD -1E4EC..1E4EF ; N # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH -1E4F0..1E4F9 ; N # Nd [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE -1E7E0..1E7E6 ; N # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO -1E7E8..1E7EB ; N # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE -1E7ED..1E7EE ; N # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE -1E7F0..1E7FE ; N # Lo [15] ETHIOPIC SYLLABLE GURAGE QWI..ETHIOPIC SYLLABLE GURAGE PWEE -1E800..1E8C4 ; N # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON -1E8C7..1E8CF ; N # No [9] MENDE KIKAKUI DIGIT ONE..MENDE KIKAKUI DIGIT NINE -1E8D0..1E8D6 ; N # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS -1E900..1E943 ; N # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA -1E944..1E94A ; N # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA -1E94B ; N # Lm ADLAM NASALIZATION MARK -1E950..1E959 ; N # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE -1E95E..1E95F ; N # Po [2] ADLAM INITIAL EXCLAMATION MARK..ADLAM INITIAL QUESTION MARK -1EC71..1ECAB ; N # No [59] INDIC SIYAQ NUMBER ONE..INDIC SIYAQ NUMBER PREFIXED NINE -1ECAC ; N # So INDIC SIYAQ PLACEHOLDER -1ECAD..1ECAF ; N # No [3] INDIC SIYAQ FRACTION ONE QUARTER..INDIC SIYAQ FRACTION THREE QUARTERS -1ECB0 ; N # Sc INDIC SIYAQ RUPEE MARK -1ECB1..1ECB4 ; N # No [4] INDIC SIYAQ NUMBER ALTERNATE ONE..INDIC SIYAQ ALTERNATE LAKH MARK -1ED01..1ED2D ; N # No [45] OTTOMAN SIYAQ NUMBER ONE..OTTOMAN SIYAQ NUMBER NINETY THOUSAND -1ED2E ; N # So OTTOMAN SIYAQ MARRATAN -1ED2F..1ED3D ; N # No [15] OTTOMAN SIYAQ ALTERNATE NUMBER TWO..OTTOMAN SIYAQ FRACTION ONE SIXTH -1EE00..1EE03 ; N # Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL -1EE05..1EE1F ; N # Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF -1EE21..1EE22 ; N # Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM -1EE24 ; N # Lo ARABIC MATHEMATICAL INITIAL HEH -1EE27 ; N # Lo ARABIC MATHEMATICAL INITIAL HAH -1EE29..1EE32 ; N # Lo [10] ARABIC MATHEMATICAL INITIAL YEH..ARABIC MATHEMATICAL INITIAL QAF -1EE34..1EE37 ; N # Lo [4] ARABIC MATHEMATICAL INITIAL SHEEN..ARABIC MATHEMATICAL INITIAL KHAH -1EE39 ; N # Lo ARABIC MATHEMATICAL INITIAL DAD -1EE3B ; N # Lo ARABIC MATHEMATICAL INITIAL GHAIN -1EE42 ; N # Lo ARABIC MATHEMATICAL TAILED JEEM -1EE47 ; N # Lo ARABIC MATHEMATICAL TAILED HAH -1EE49 ; N # Lo ARABIC MATHEMATICAL TAILED YEH -1EE4B ; N # Lo ARABIC MATHEMATICAL TAILED LAM -1EE4D..1EE4F ; N # Lo [3] ARABIC MATHEMATICAL TAILED NOON..ARABIC MATHEMATICAL TAILED AIN -1EE51..1EE52 ; N # Lo [2] ARABIC MATHEMATICAL TAILED SAD..ARABIC MATHEMATICAL TAILED QAF -1EE54 ; N # Lo ARABIC MATHEMATICAL TAILED SHEEN -1EE57 ; N # Lo ARABIC MATHEMATICAL TAILED KHAH -1EE59 ; N # Lo ARABIC MATHEMATICAL TAILED DAD -1EE5B ; N # Lo ARABIC MATHEMATICAL TAILED GHAIN -1EE5D ; N # Lo ARABIC MATHEMATICAL TAILED DOTLESS NOON -1EE5F ; N # Lo ARABIC MATHEMATICAL TAILED DOTLESS QAF -1EE61..1EE62 ; N # Lo [2] ARABIC MATHEMATICAL STRETCHED BEH..ARABIC MATHEMATICAL STRETCHED JEEM -1EE64 ; N # Lo ARABIC MATHEMATICAL STRETCHED HEH -1EE67..1EE6A ; N # Lo [4] ARABIC MATHEMATICAL STRETCHED HAH..ARABIC MATHEMATICAL STRETCHED KAF -1EE6C..1EE72 ; N # Lo [7] ARABIC MATHEMATICAL STRETCHED MEEM..ARABIC MATHEMATICAL STRETCHED QAF -1EE74..1EE77 ; N # Lo [4] ARABIC MATHEMATICAL STRETCHED SHEEN..ARABIC MATHEMATICAL STRETCHED KHAH -1EE79..1EE7C ; N # Lo [4] ARABIC MATHEMATICAL STRETCHED DAD..ARABIC MATHEMATICAL STRETCHED DOTLESS BEH -1EE7E ; N # Lo ARABIC MATHEMATICAL STRETCHED DOTLESS FEH -1EE80..1EE89 ; N # Lo [10] ARABIC MATHEMATICAL LOOPED ALEF..ARABIC MATHEMATICAL LOOPED YEH -1EE8B..1EE9B ; N # Lo [17] ARABIC MATHEMATICAL LOOPED LAM..ARABIC MATHEMATICAL LOOPED GHAIN -1EEA1..1EEA3 ; N # Lo [3] ARABIC MATHEMATICAL DOUBLE-STRUCK BEH..ARABIC MATHEMATICAL DOUBLE-STRUCK DAL -1EEA5..1EEA9 ; N # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH -1EEAB..1EEBB ; N # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN -1EEF0..1EEF1 ; N # Sm [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL -1F000..1F003 ; N # So [4] MAHJONG TILE EAST WIND..MAHJONG TILE NORTH WIND -1F004 ; W # So MAHJONG TILE RED DRAGON -1F005..1F02B ; N # So [39] MAHJONG TILE GREEN DRAGON..MAHJONG TILE BACK -1F030..1F093 ; N # So [100] DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06 -1F0A0..1F0AE ; N # So [15] PLAYING CARD BACK..PLAYING CARD KING OF SPADES -1F0B1..1F0BF ; N # So [15] PLAYING CARD ACE OF HEARTS..PLAYING CARD RED JOKER -1F0C1..1F0CE ; N # So [14] PLAYING CARD ACE OF DIAMONDS..PLAYING CARD KING OF DIAMONDS -1F0CF ; W # So PLAYING CARD BLACK JOKER -1F0D1..1F0F5 ; N # So [37] PLAYING CARD ACE OF CLUBS..PLAYING CARD TRUMP-21 -1F100..1F10A ; A # No [11] DIGIT ZERO FULL STOP..DIGIT NINE COMMA -1F10B..1F10C ; N # No [2] DINGBAT CIRCLED SANS-SERIF DIGIT ZERO..DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO -1F10D..1F10F ; N # So [3] CIRCLED ZERO WITH SLASH..CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH -1F110..1F12D ; A # So [30] PARENTHESIZED LATIN CAPITAL LETTER A..CIRCLED CD -1F12E..1F12F ; N # So [2] CIRCLED WZ..COPYLEFT SYMBOL -1F130..1F169 ; A # So [58] SQUARED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z -1F16A..1F16F ; N # So [6] RAISED MC SIGN..CIRCLED HUMAN FIGURE -1F170..1F18D ; A # So [30] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED SA -1F18E ; W # So NEGATIVE SQUARED AB -1F18F..1F190 ; A # So [2] NEGATIVE SQUARED WC..SQUARE DJ -1F191..1F19A ; W # So [10] SQUARED CL..SQUARED VS -1F19B..1F1AC ; A # So [18] SQUARED THREE D..SQUARED VOD -1F1AD ; N # So MASK WORK SYMBOL -1F1E6..1F1FF ; N # So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z -1F200..1F202 ; W # So [3] SQUARE HIRAGANA HOKA..SQUARED KATAKANA SA -1F210..1F23B ; W # So [44] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-914D -1F240..1F248 ; W # So [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 -1F250..1F251 ; W # So [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT -1F260..1F265 ; W # So [6] ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI -1F300..1F320 ; W # So [33] CYCLONE..SHOOTING STAR -1F321..1F32C ; N # So [12] THERMOMETER..WIND BLOWING FACE -1F32D..1F335 ; W # So [9] HOT DOG..CACTUS -1F336 ; N # So HOT PEPPER -1F337..1F37C ; W # So [70] TULIP..BABY BOTTLE -1F37D ; N # So FORK AND KNIFE WITH PLATE -1F37E..1F393 ; W # So [22] BOTTLE WITH POPPING CORK..GRADUATION CAP -1F394..1F39F ; N # So [12] HEART WITH TIP ON THE LEFT..ADMISSION TICKETS -1F3A0..1F3CA ; W # So [43] CAROUSEL HORSE..SWIMMER -1F3CB..1F3CE ; N # So [4] WEIGHT LIFTER..RACING CAR -1F3CF..1F3D3 ; W # So [5] CRICKET BAT AND BALL..TABLE TENNIS PADDLE AND BALL -1F3D4..1F3DF ; N # So [12] SNOW CAPPED MOUNTAIN..STADIUM -1F3E0..1F3F0 ; W # So [17] HOUSE BUILDING..EUROPEAN CASTLE -1F3F1..1F3F3 ; N # So [3] WHITE PENNANT..WAVING WHITE FLAG -1F3F4 ; W # So WAVING BLACK FLAG -1F3F5..1F3F7 ; N # So [3] ROSETTE..LABEL -1F3F8..1F3FA ; W # So [3] BADMINTON RACQUET AND SHUTTLECOCK..AMPHORA -1F3FB..1F3FF ; W # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 -1F400..1F43E ; W # So [63] RAT..PAW PRINTS -1F43F ; N # So CHIPMUNK -1F440 ; W # So EYES -1F441 ; N # So EYE -1F442..1F4FC ; W # So [187] EAR..VIDEOCASSETTE -1F4FD..1F4FE ; N # So [2] FILM PROJECTOR..PORTABLE STEREO -1F4FF..1F53D ; W # So [63] PRAYER BEADS..DOWN-POINTING SMALL RED TRIANGLE -1F53E..1F54A ; N # So [13] LOWER RIGHT SHADOWED WHITE CIRCLE..DOVE OF PEACE -1F54B..1F54E ; W # So [4] KAABA..MENORAH WITH NINE BRANCHES -1F54F ; N # So BOWL OF HYGIEIA -1F550..1F567 ; W # So [24] CLOCK FACE ONE OCLOCK..CLOCK FACE TWELVE-THIRTY -1F568..1F579 ; N # So [18] RIGHT SPEAKER..JOYSTICK -1F57A ; W # So MAN DANCING -1F57B..1F594 ; N # So [26] LEFT HAND TELEPHONE RECEIVER..REVERSED VICTORY HAND -1F595..1F596 ; W # So [2] REVERSED HAND WITH MIDDLE FINGER EXTENDED..RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS -1F597..1F5A3 ; N # So [13] WHITE DOWN POINTING LEFT HAND INDEX..BLACK DOWN POINTING BACKHAND INDEX -1F5A4 ; W # So BLACK HEART -1F5A5..1F5FA ; N # So [86] DESKTOP COMPUTER..WORLD MAP -1F5FB..1F5FF ; W # So [5] MOUNT FUJI..MOYAI -1F600..1F64F ; W # So [80] GRINNING FACE..PERSON WITH FOLDED HANDS -1F650..1F67F ; N # So [48] NORTH WEST POINTING LEAF..REVERSE CHECKER BOARD -1F680..1F6C5 ; W # So [70] ROCKET..LEFT LUGGAGE -1F6C6..1F6CB ; N # So [6] TRIANGLE WITH ROUNDED CORNERS..COUCH AND LAMP -1F6CC ; W # So SLEEPING ACCOMMODATION -1F6CD..1F6CF ; N # So [3] SHOPPING BAGS..BED -1F6D0..1F6D2 ; W # So [3] PLACE OF WORSHIP..SHOPPING TROLLEY -1F6D3..1F6D4 ; N # So [2] STUPA..PAGODA -1F6D5..1F6D7 ; W # So [3] HINDU TEMPLE..ELEVATOR -1F6DC..1F6DF ; W # So [4] WIRELESS..RING BUOY -1F6E0..1F6EA ; N # So [11] HAMMER AND WRENCH..NORTHEAST-POINTING AIRPLANE -1F6EB..1F6EC ; W # So [2] AIRPLANE DEPARTURE..AIRPLANE ARRIVING -1F6F0..1F6F3 ; N # So [4] SATELLITE..PASSENGER SHIP -1F6F4..1F6FC ; W # So [9] SCOOTER..ROLLER SKATE -1F700..1F776 ; N # So [119] ALCHEMICAL SYMBOL FOR QUINTESSENCE..LUNAR ECLIPSE -1F77B..1F77F ; N # So [5] HAUMEA..ORCUS -1F780..1F7D9 ; N # So [90] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..NINE POINTED WHITE STAR -1F7E0..1F7EB ; W # So [12] LARGE ORANGE CIRCLE..LARGE BROWN SQUARE -1F7F0 ; W # So HEAVY EQUALS SIGN -1F800..1F80B ; N # So [12] LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD -1F810..1F847 ; N # So [56] LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD..DOWNWARDS HEAVY ARROW -1F850..1F859 ; N # So [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW -1F860..1F887 ; N # So [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW -1F890..1F8AD ; N # So [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS -1F8B0..1F8B1 ; N # So [2] ARROW POINTING UPWARDS THEN NORTH WEST..ARROW POINTING RIGHTWARDS THEN CURVING SOUTH WEST -1F900..1F90B ; N # So [12] CIRCLED CROSS FORMEE WITH FOUR DOTS..DOWNWARD FACING NOTCHED HOOK WITH DOT -1F90C..1F93A ; W # So [47] PINCHED FINGERS..FENCER -1F93B ; N # So MODERN PENTATHLON -1F93C..1F945 ; W # So [10] WRESTLERS..GOAL NET -1F946 ; N # So RIFLE -1F947..1F9FF ; W # So [185] FIRST PLACE MEDAL..NAZAR AMULET -1FA00..1FA53 ; N # So [84] NEUTRAL CHESS KING..BLACK CHESS KNIGHT-BISHOP -1FA60..1FA6D ; N # So [14] XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER -1FA70..1FA7C ; W # So [13] BALLET SHOES..CRUTCH -1FA80..1FA88 ; W # So [9] YO-YO..FLUTE -1FA90..1FABD ; W # So [46] RINGED PLANET..WING -1FABF..1FAC5 ; W # So [7] GOOSE..PERSON WITH CROWN -1FACE..1FADB ; W # So [14] MOOSE..PEA POD -1FAE0..1FAE8 ; W # So [9] MELTING FACE..SHAKING FACE -1FAF0..1FAF8 ; W # So [9] HAND WITH INDEX FINGER AND THUMB CROSSED..RIGHTWARDS PUSHING HAND -1FB00..1FB92 ; N # So [147] BLOCK SEXTANT-1..UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK -1FB94..1FBCA ; N # So [55] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..WHITE UP-POINTING CHEVRON -1FBF0..1FBF9 ; N # Nd [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE -20000..2A6DF ; W # Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF -2A6E0..2A6FF ; W # Cn [32] <reserved-2A6E0>..<reserved-2A6FF> -2A700..2B739 ; W # Lo [4154] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B739 -2B73A..2B73F ; W # Cn [6] <reserved-2B73A>..<reserved-2B73F> -2B740..2B81D ; W # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D -2B81E..2B81F ; W # Cn [2] <reserved-2B81E>..<reserved-2B81F> -2B820..2CEA1 ; W # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 -2CEA2..2CEAF ; W # Cn [14] <reserved-2CEA2>..<reserved-2CEAF> -2CEB0..2EBE0 ; W # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 -2EBE1..2EBEF ; W # Cn [15] <reserved-2EBE1>..<reserved-2EBEF> -2EBF0..2EE5D ; W # Lo [622] CJK UNIFIED IDEOGRAPH-2EBF0..CJK UNIFIED IDEOGRAPH-2EE5D -2EE5E..2F7FF ; W # Cn [2466] <reserved-2EE5E>..<reserved-2F7FF> -2F800..2FA1D ; W # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D -2FA1E..2FA1F ; W # Cn [2] <reserved-2FA1E>..<reserved-2FA1F> -2FA20..2FFFD ; W # Cn [1502] <reserved-2FA20>..<reserved-2FFFD> -30000..3134A ; W # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A -3134B..3134F ; W # Cn [5] <reserved-3134B>..<reserved-3134F> -31350..323AF ; W # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF -323B0..3FFFD ; W # Cn [56398] <reserved-323B0>..<reserved-3FFFD> -E0001 ; N # Cf LANGUAGE TAG -E0020..E007F ; N # Cf [96] TAG SPACE..CANCEL TAG -E0100..E01EF ; A # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -F0000..FFFFD ; A # Co [65534] <private-use-F0000>..<private-use-FFFFD> -100000..10FFFD ; A # Co [65534] <private-use-100000>..<private-use-10FFFD> - -# EOF diff --git a/src/unicode/UnicodeData.txt b/src/unicode/UnicodeData.txt deleted file mode 100644 index bdcc41850d..0000000000 --- a/src/unicode/UnicodeData.txt +++ /dev/null @@ -1,34931 +0,0 @@ -0000;<control>;Cc;0;BN;;;;;N;NULL;;;; -0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;; -0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; -0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; -0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; -0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; -0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; -0007;<control>;Cc;0;BN;;;;;N;BELL;;;; -0008;<control>;Cc;0;BN;;;;;N;BACKSPACE;;;; -0009;<control>;Cc;0;S;;;;;N;CHARACTER TABULATION;;;; -000A;<control>;Cc;0;B;;;;;N;LINE FEED (LF);;;; -000B;<control>;Cc;0;S;;;;;N;LINE TABULATION;;;; -000C;<control>;Cc;0;WS;;;;;N;FORM FEED (FF);;;; -000D;<control>;Cc;0;B;;;;;N;CARRIAGE RETURN (CR);;;; -000E;<control>;Cc;0;BN;;;;;N;SHIFT OUT;;;; -000F;<control>;Cc;0;BN;;;;;N;SHIFT IN;;;; -0010;<control>;Cc;0;BN;;;;;N;DATA LINK ESCAPE;;;; -0011;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL ONE;;;; -0012;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL TWO;;;; -0013;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL THREE;;;; -0014;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL FOUR;;;; -0015;<control>;Cc;0;BN;;;;;N;NEGATIVE ACKNOWLEDGE;;;; -0016;<control>;Cc;0;BN;;;;;N;SYNCHRONOUS IDLE;;;; -0017;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION BLOCK;;;; -0018;<control>;Cc;0;BN;;;;;N;CANCEL;;;; -0019;<control>;Cc;0;BN;;;;;N;END OF MEDIUM;;;; -001A;<control>;Cc;0;BN;;;;;N;SUBSTITUTE;;;; -001B;<control>;Cc;0;BN;;;;;N;ESCAPE;;;; -001C;<control>;Cc;0;B;;;;;N;INFORMATION SEPARATOR FOUR;;;; -001D;<control>;Cc;0;B;;;;;N;INFORMATION SEPARATOR THREE;;;; -001E;<control>;Cc;0;B;;;;;N;INFORMATION SEPARATOR TWO;;;; -001F;<control>;Cc;0;S;;;;;N;INFORMATION SEPARATOR ONE;;;; -0020;SPACE;Zs;0;WS;;;;;N;;;;; -0021;EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; -0022;QUOTATION MARK;Po;0;ON;;;;;N;;;;; -0023;NUMBER SIGN;Po;0;ET;;;;;N;;;;; -0024;DOLLAR SIGN;Sc;0;ET;;;;;N;;;;; -0025;PERCENT SIGN;Po;0;ET;;;;;N;;;;; -0026;AMPERSAND;Po;0;ON;;;;;N;;;;; -0027;APOSTROPHE;Po;0;ON;;;;;N;APOSTROPHE-QUOTE;;;; -0028;LEFT PARENTHESIS;Ps;0;ON;;;;;Y;OPENING PARENTHESIS;;;; -0029;RIGHT PARENTHESIS;Pe;0;ON;;;;;Y;CLOSING PARENTHESIS;;;; -002A;ASTERISK;Po;0;ON;;;;;N;;;;; -002B;PLUS SIGN;Sm;0;ES;;;;;N;;;;; -002C;COMMA;Po;0;CS;;;;;N;;;;; -002D;HYPHEN-MINUS;Pd;0;ES;;;;;N;;;;; -002E;FULL STOP;Po;0;CS;;;;;N;PERIOD;;;; -002F;SOLIDUS;Po;0;CS;;;;;N;SLASH;;;; -0030;DIGIT ZERO;Nd;0;EN;;0;0;0;N;;;;; -0031;DIGIT ONE;Nd;0;EN;;1;1;1;N;;;;; -0032;DIGIT TWO;Nd;0;EN;;2;2;2;N;;;;; -0033;DIGIT THREE;Nd;0;EN;;3;3;3;N;;;;; -0034;DIGIT FOUR;Nd;0;EN;;4;4;4;N;;;;; -0035;DIGIT FIVE;Nd;0;EN;;5;5;5;N;;;;; -0036;DIGIT SIX;Nd;0;EN;;6;6;6;N;;;;; -0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;; -0038;DIGIT EIGHT;Nd;0;EN;;8;8;8;N;;;;; -0039;DIGIT NINE;Nd;0;EN;;9;9;9;N;;;;; -003A;COLON;Po;0;CS;;;;;N;;;;; -003B;SEMICOLON;Po;0;ON;;;;;N;;;;; -003C;LESS-THAN SIGN;Sm;0;ON;;;;;Y;;;;; -003D;EQUALS SIGN;Sm;0;ON;;;;;N;;;;; -003E;GREATER-THAN SIGN;Sm;0;ON;;;;;Y;;;;; -003F;QUESTION MARK;Po;0;ON;;;;;N;;;;; -0040;COMMERCIAL AT;Po;0;ON;;;;;N;;;;; -0041;LATIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0061; -0042;LATIN CAPITAL LETTER B;Lu;0;L;;;;;N;;;;0062; -0043;LATIN CAPITAL LETTER C;Lu;0;L;;;;;N;;;;0063; -0044;LATIN CAPITAL LETTER D;Lu;0;L;;;;;N;;;;0064; -0045;LATIN CAPITAL LETTER E;Lu;0;L;;;;;N;;;;0065; -0046;LATIN CAPITAL LETTER F;Lu;0;L;;;;;N;;;;0066; -0047;LATIN CAPITAL LETTER G;Lu;0;L;;;;;N;;;;0067; -0048;LATIN CAPITAL LETTER H;Lu;0;L;;;;;N;;;;0068; -0049;LATIN CAPITAL LETTER I;Lu;0;L;;;;;N;;;;0069; -004A;LATIN CAPITAL LETTER J;Lu;0;L;;;;;N;;;;006A; -004B;LATIN CAPITAL LETTER K;Lu;0;L;;;;;N;;;;006B; -004C;LATIN CAPITAL LETTER L;Lu;0;L;;;;;N;;;;006C; -004D;LATIN CAPITAL LETTER M;Lu;0;L;;;;;N;;;;006D; -004E;LATIN CAPITAL LETTER N;Lu;0;L;;;;;N;;;;006E; -004F;LATIN CAPITAL LETTER O;Lu;0;L;;;;;N;;;;006F; -0050;LATIN CAPITAL LETTER P;Lu;0;L;;;;;N;;;;0070; -0051;LATIN CAPITAL LETTER Q;Lu;0;L;;;;;N;;;;0071; -0052;LATIN CAPITAL LETTER R;Lu;0;L;;;;;N;;;;0072; -0053;LATIN CAPITAL LETTER S;Lu;0;L;;;;;N;;;;0073; -0054;LATIN CAPITAL LETTER T;Lu;0;L;;;;;N;;;;0074; -0055;LATIN CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0075; -0056;LATIN CAPITAL LETTER V;Lu;0;L;;;;;N;;;;0076; -0057;LATIN CAPITAL LETTER W;Lu;0;L;;;;;N;;;;0077; -0058;LATIN CAPITAL LETTER X;Lu;0;L;;;;;N;;;;0078; -0059;LATIN CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;0079; -005A;LATIN CAPITAL LETTER Z;Lu;0;L;;;;;N;;;;007A; -005B;LEFT SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING SQUARE BRACKET;;;; -005C;REVERSE SOLIDUS;Po;0;ON;;;;;N;BACKSLASH;;;; -005D;RIGHT SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING SQUARE BRACKET;;;; -005E;CIRCUMFLEX ACCENT;Sk;0;ON;;;;;N;SPACING CIRCUMFLEX;;;; -005F;LOW LINE;Pc;0;ON;;;;;N;SPACING UNDERSCORE;;;; -0060;GRAVE ACCENT;Sk;0;ON;;;;;N;SPACING GRAVE;;;; -0061;LATIN SMALL LETTER A;Ll;0;L;;;;;N;;;0041;;0041 -0062;LATIN SMALL LETTER B;Ll;0;L;;;;;N;;;0042;;0042 -0063;LATIN SMALL LETTER C;Ll;0;L;;;;;N;;;0043;;0043 -0064;LATIN SMALL LETTER D;Ll;0;L;;;;;N;;;0044;;0044 -0065;LATIN SMALL LETTER E;Ll;0;L;;;;;N;;;0045;;0045 -0066;LATIN SMALL LETTER F;Ll;0;L;;;;;N;;;0046;;0046 -0067;LATIN SMALL LETTER G;Ll;0;L;;;;;N;;;0047;;0047 -0068;LATIN SMALL LETTER H;Ll;0;L;;;;;N;;;0048;;0048 -0069;LATIN SMALL LETTER I;Ll;0;L;;;;;N;;;0049;;0049 -006A;LATIN SMALL LETTER J;Ll;0;L;;;;;N;;;004A;;004A -006B;LATIN SMALL LETTER K;Ll;0;L;;;;;N;;;004B;;004B -006C;LATIN SMALL LETTER L;Ll;0;L;;;;;N;;;004C;;004C -006D;LATIN SMALL LETTER M;Ll;0;L;;;;;N;;;004D;;004D -006E;LATIN SMALL LETTER N;Ll;0;L;;;;;N;;;004E;;004E -006F;LATIN SMALL LETTER O;Ll;0;L;;;;;N;;;004F;;004F -0070;LATIN SMALL LETTER P;Ll;0;L;;;;;N;;;0050;;0050 -0071;LATIN SMALL LETTER Q;Ll;0;L;;;;;N;;;0051;;0051 -0072;LATIN SMALL LETTER R;Ll;0;L;;;;;N;;;0052;;0052 -0073;LATIN SMALL LETTER S;Ll;0;L;;;;;N;;;0053;;0053 -0074;LATIN SMALL LETTER T;Ll;0;L;;;;;N;;;0054;;0054 -0075;LATIN SMALL LETTER U;Ll;0;L;;;;;N;;;0055;;0055 -0076;LATIN SMALL LETTER V;Ll;0;L;;;;;N;;;0056;;0056 -0077;LATIN SMALL LETTER W;Ll;0;L;;;;;N;;;0057;;0057 -0078;LATIN SMALL LETTER X;Ll;0;L;;;;;N;;;0058;;0058 -0079;LATIN SMALL LETTER Y;Ll;0;L;;;;;N;;;0059;;0059 -007A;LATIN SMALL LETTER Z;Ll;0;L;;;;;N;;;005A;;005A -007B;LEFT CURLY BRACKET;Ps;0;ON;;;;;Y;OPENING CURLY BRACKET;;;; -007C;VERTICAL LINE;Sm;0;ON;;;;;N;VERTICAL BAR;;;; -007D;RIGHT CURLY BRACKET;Pe;0;ON;;;;;Y;CLOSING CURLY BRACKET;;;; -007E;TILDE;Sm;0;ON;;;;;N;;;;; -007F;<control>;Cc;0;BN;;;;;N;DELETE;;;; -0080;<control>;Cc;0;BN;;;;;N;;;;; -0081;<control>;Cc;0;BN;;;;;N;;;;; -0082;<control>;Cc;0;BN;;;;;N;BREAK PERMITTED HERE;;;; -0083;<control>;Cc;0;BN;;;;;N;NO BREAK HERE;;;; -0084;<control>;Cc;0;BN;;;;;N;;;;; -0085;<control>;Cc;0;B;;;;;N;NEXT LINE (NEL);;;; -0086;<control>;Cc;0;BN;;;;;N;START OF SELECTED AREA;;;; -0087;<control>;Cc;0;BN;;;;;N;END OF SELECTED AREA;;;; -0088;<control>;Cc;0;BN;;;;;N;CHARACTER TABULATION SET;;;; -0089;<control>;Cc;0;BN;;;;;N;CHARACTER TABULATION WITH JUSTIFICATION;;;; -008A;<control>;Cc;0;BN;;;;;N;LINE TABULATION SET;;;; -008B;<control>;Cc;0;BN;;;;;N;PARTIAL LINE FORWARD;;;; -008C;<control>;Cc;0;BN;;;;;N;PARTIAL LINE BACKWARD;;;; -008D;<control>;Cc;0;BN;;;;;N;REVERSE LINE FEED;;;; -008E;<control>;Cc;0;BN;;;;;N;SINGLE SHIFT TWO;;;; -008F;<control>;Cc;0;BN;;;;;N;SINGLE SHIFT THREE;;;; -0090;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL STRING;;;; -0091;<control>;Cc;0;BN;;;;;N;PRIVATE USE ONE;;;; -0092;<control>;Cc;0;BN;;;;;N;PRIVATE USE TWO;;;; -0093;<control>;Cc;0;BN;;;;;N;SET TRANSMIT STATE;;;; -0094;<control>;Cc;0;BN;;;;;N;CANCEL CHARACTER;;;; -0095;<control>;Cc;0;BN;;;;;N;MESSAGE WAITING;;;; -0096;<control>;Cc;0;BN;;;;;N;START OF GUARDED AREA;;;; -0097;<control>;Cc;0;BN;;;;;N;END OF GUARDED AREA;;;; -0098;<control>;Cc;0;BN;;;;;N;START OF STRING;;;; -0099;<control>;Cc;0;BN;;;;;N;;;;; -009A;<control>;Cc;0;BN;;;;;N;SINGLE CHARACTER INTRODUCER;;;; -009B;<control>;Cc;0;BN;;;;;N;CONTROL SEQUENCE INTRODUCER;;;; -009C;<control>;Cc;0;BN;;;;;N;STRING TERMINATOR;;;; -009D;<control>;Cc;0;BN;;;;;N;OPERATING SYSTEM COMMAND;;;; -009E;<control>;Cc;0;BN;;;;;N;PRIVACY MESSAGE;;;; -009F;<control>;Cc;0;BN;;;;;N;APPLICATION PROGRAM COMMAND;;;; -00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;; -00A1;INVERTED EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; -00A2;CENT SIGN;Sc;0;ET;;;;;N;;;;; -00A3;POUND SIGN;Sc;0;ET;;;;;N;;;;; -00A4;CURRENCY SIGN;Sc;0;ET;;;;;N;;;;; -00A5;YEN SIGN;Sc;0;ET;;;;;N;;;;; -00A6;BROKEN BAR;So;0;ON;;;;;N;BROKEN VERTICAL BAR;;;; -00A7;SECTION SIGN;Po;0;ON;;;;;N;;;;; -00A8;DIAERESIS;Sk;0;ON;<compat> 0020 0308;;;;N;SPACING DIAERESIS;;;; -00A9;COPYRIGHT SIGN;So;0;ON;;;;;N;;;;; -00AA;FEMININE ORDINAL INDICATOR;Lo;0;L;<super> 0061;;;;N;;;;; -00AB;LEFT-POINTING DOUBLE ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING GUILLEMET;;;; -00AC;NOT SIGN;Sm;0;ON;;;;;N;;;;; -00AD;SOFT HYPHEN;Cf;0;BN;;;;;N;;;;; -00AE;REGISTERED SIGN;So;0;ON;;;;;N;REGISTERED TRADE MARK SIGN;;;; -00AF;MACRON;Sk;0;ON;<compat> 0020 0304;;;;N;SPACING MACRON;;;; -00B0;DEGREE SIGN;So;0;ET;;;;;N;;;;; -00B1;PLUS-MINUS SIGN;Sm;0;ET;;;;;N;PLUS-OR-MINUS SIGN;;;; -00B2;SUPERSCRIPT TWO;No;0;EN;<super> 0032;;2;2;N;SUPERSCRIPT DIGIT TWO;;;; -00B3;SUPERSCRIPT THREE;No;0;EN;<super> 0033;;3;3;N;SUPERSCRIPT DIGIT THREE;;;; -00B4;ACUTE ACCENT;Sk;0;ON;<compat> 0020 0301;;;;N;SPACING ACUTE;;;; -00B5;MICRO SIGN;Ll;0;L;<compat> 03BC;;;;N;;;039C;;039C -00B6;PILCROW SIGN;Po;0;ON;;;;;N;PARAGRAPH SIGN;;;; -00B7;MIDDLE DOT;Po;0;ON;;;;;N;;;;; -00B8;CEDILLA;Sk;0;ON;<compat> 0020 0327;;;;N;SPACING CEDILLA;;;; -00B9;SUPERSCRIPT ONE;No;0;EN;<super> 0031;;1;1;N;SUPERSCRIPT DIGIT ONE;;;; -00BA;MASCULINE ORDINAL INDICATOR;Lo;0;L;<super> 006F;;;;N;;;;; -00BB;RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING GUILLEMET;;;; -00BC;VULGAR FRACTION ONE QUARTER;No;0;ON;<fraction> 0031 2044 0034;;;1/4;N;FRACTION ONE QUARTER;;;; -00BD;VULGAR FRACTION ONE HALF;No;0;ON;<fraction> 0031 2044 0032;;;1/2;N;FRACTION ONE HALF;;;; -00BE;VULGAR FRACTION THREE QUARTERS;No;0;ON;<fraction> 0033 2044 0034;;;3/4;N;FRACTION THREE QUARTERS;;;; -00BF;INVERTED QUESTION MARK;Po;0;ON;;;;;N;;;;; -00C0;LATIN CAPITAL LETTER A WITH GRAVE;Lu;0;L;0041 0300;;;;N;LATIN CAPITAL LETTER A GRAVE;;;00E0; -00C1;LATIN CAPITAL LETTER A WITH ACUTE;Lu;0;L;0041 0301;;;;N;LATIN CAPITAL LETTER A ACUTE;;;00E1; -00C2;LATIN CAPITAL LETTER A WITH CIRCUMFLEX;Lu;0;L;0041 0302;;;;N;LATIN CAPITAL LETTER A CIRCUMFLEX;;;00E2; -00C3;LATIN CAPITAL LETTER A WITH TILDE;Lu;0;L;0041 0303;;;;N;LATIN CAPITAL LETTER A TILDE;;;00E3; -00C4;LATIN CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0041 0308;;;;N;LATIN CAPITAL LETTER A DIAERESIS;;;00E4; -00C5;LATIN CAPITAL LETTER A WITH RING ABOVE;Lu;0;L;0041 030A;;;;N;LATIN CAPITAL LETTER A RING;;;00E5; -00C6;LATIN CAPITAL LETTER AE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER A E;;;00E6; -00C7;LATIN CAPITAL LETTER C WITH CEDILLA;Lu;0;L;0043 0327;;;;N;LATIN CAPITAL LETTER C CEDILLA;;;00E7; -00C8;LATIN CAPITAL LETTER E WITH GRAVE;Lu;0;L;0045 0300;;;;N;LATIN CAPITAL LETTER E GRAVE;;;00E8; -00C9;LATIN CAPITAL LETTER E WITH ACUTE;Lu;0;L;0045 0301;;;;N;LATIN CAPITAL LETTER E ACUTE;;;00E9; -00CA;LATIN CAPITAL LETTER E WITH CIRCUMFLEX;Lu;0;L;0045 0302;;;;N;LATIN CAPITAL LETTER E CIRCUMFLEX;;;00EA; -00CB;LATIN CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;0045 0308;;;;N;LATIN CAPITAL LETTER E DIAERESIS;;;00EB; -00CC;LATIN CAPITAL LETTER I WITH GRAVE;Lu;0;L;0049 0300;;;;N;LATIN CAPITAL LETTER I GRAVE;;;00EC; -00CD;LATIN CAPITAL LETTER I WITH ACUTE;Lu;0;L;0049 0301;;;;N;LATIN CAPITAL LETTER I ACUTE;;;00ED; -00CE;LATIN CAPITAL LETTER I WITH CIRCUMFLEX;Lu;0;L;0049 0302;;;;N;LATIN CAPITAL LETTER I CIRCUMFLEX;;;00EE; -00CF;LATIN CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0049 0308;;;;N;LATIN CAPITAL LETTER I DIAERESIS;;;00EF; -00D0;LATIN CAPITAL LETTER ETH;Lu;0;L;;;;;N;;;;00F0; -00D1;LATIN CAPITAL LETTER N WITH TILDE;Lu;0;L;004E 0303;;;;N;LATIN CAPITAL LETTER N TILDE;;;00F1; -00D2;LATIN CAPITAL LETTER O WITH GRAVE;Lu;0;L;004F 0300;;;;N;LATIN CAPITAL LETTER O GRAVE;;;00F2; -00D3;LATIN CAPITAL LETTER O WITH ACUTE;Lu;0;L;004F 0301;;;;N;LATIN CAPITAL LETTER O ACUTE;;;00F3; -00D4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX;Lu;0;L;004F 0302;;;;N;LATIN CAPITAL LETTER O CIRCUMFLEX;;;00F4; -00D5;LATIN CAPITAL LETTER O WITH TILDE;Lu;0;L;004F 0303;;;;N;LATIN CAPITAL LETTER O TILDE;;;00F5; -00D6;LATIN CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;004F 0308;;;;N;LATIN CAPITAL LETTER O DIAERESIS;;;00F6; -00D7;MULTIPLICATION SIGN;Sm;0;ON;;;;;N;;;;; -00D8;LATIN CAPITAL LETTER O WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O SLASH;;;00F8; -00D9;LATIN CAPITAL LETTER U WITH GRAVE;Lu;0;L;0055 0300;;;;N;LATIN CAPITAL LETTER U GRAVE;;;00F9; -00DA;LATIN CAPITAL LETTER U WITH ACUTE;Lu;0;L;0055 0301;;;;N;LATIN CAPITAL LETTER U ACUTE;;;00FA; -00DB;LATIN CAPITAL LETTER U WITH CIRCUMFLEX;Lu;0;L;0055 0302;;;;N;LATIN CAPITAL LETTER U CIRCUMFLEX;;;00FB; -00DC;LATIN CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0055 0308;;;;N;LATIN CAPITAL LETTER U DIAERESIS;;;00FC; -00DD;LATIN CAPITAL LETTER Y WITH ACUTE;Lu;0;L;0059 0301;;;;N;LATIN CAPITAL LETTER Y ACUTE;;;00FD; -00DE;LATIN CAPITAL LETTER THORN;Lu;0;L;;;;;N;;;;00FE; -00DF;LATIN SMALL LETTER SHARP S;Ll;0;L;;;;;N;;;;; -00E0;LATIN SMALL LETTER A WITH GRAVE;Ll;0;L;0061 0300;;;;N;LATIN SMALL LETTER A GRAVE;;00C0;;00C0 -00E1;LATIN SMALL LETTER A WITH ACUTE;Ll;0;L;0061 0301;;;;N;LATIN SMALL LETTER A ACUTE;;00C1;;00C1 -00E2;LATIN SMALL LETTER A WITH CIRCUMFLEX;Ll;0;L;0061 0302;;;;N;LATIN SMALL LETTER A CIRCUMFLEX;;00C2;;00C2 -00E3;LATIN SMALL LETTER A WITH TILDE;Ll;0;L;0061 0303;;;;N;LATIN SMALL LETTER A TILDE;;00C3;;00C3 -00E4;LATIN SMALL LETTER A WITH DIAERESIS;Ll;0;L;0061 0308;;;;N;LATIN SMALL LETTER A DIAERESIS;;00C4;;00C4 -00E5;LATIN SMALL LETTER A WITH RING ABOVE;Ll;0;L;0061 030A;;;;N;LATIN SMALL LETTER A RING;;00C5;;00C5 -00E6;LATIN SMALL LETTER AE;Ll;0;L;;;;;N;LATIN SMALL LETTER A E;;00C6;;00C6 -00E7;LATIN SMALL LETTER C WITH CEDILLA;Ll;0;L;0063 0327;;;;N;LATIN SMALL LETTER C CEDILLA;;00C7;;00C7 -00E8;LATIN SMALL LETTER E WITH GRAVE;Ll;0;L;0065 0300;;;;N;LATIN SMALL LETTER E GRAVE;;00C8;;00C8 -00E9;LATIN SMALL LETTER E WITH ACUTE;Ll;0;L;0065 0301;;;;N;LATIN SMALL LETTER E ACUTE;;00C9;;00C9 -00EA;LATIN SMALL LETTER E WITH CIRCUMFLEX;Ll;0;L;0065 0302;;;;N;LATIN SMALL LETTER E CIRCUMFLEX;;00CA;;00CA -00EB;LATIN SMALL LETTER E WITH DIAERESIS;Ll;0;L;0065 0308;;;;N;LATIN SMALL LETTER E DIAERESIS;;00CB;;00CB -00EC;LATIN SMALL LETTER I WITH GRAVE;Ll;0;L;0069 0300;;;;N;LATIN SMALL LETTER I GRAVE;;00CC;;00CC -00ED;LATIN SMALL LETTER I WITH ACUTE;Ll;0;L;0069 0301;;;;N;LATIN SMALL LETTER I ACUTE;;00CD;;00CD -00EE;LATIN SMALL LETTER I WITH CIRCUMFLEX;Ll;0;L;0069 0302;;;;N;LATIN SMALL LETTER I CIRCUMFLEX;;00CE;;00CE -00EF;LATIN SMALL LETTER I WITH DIAERESIS;Ll;0;L;0069 0308;;;;N;LATIN SMALL LETTER I DIAERESIS;;00CF;;00CF -00F0;LATIN SMALL LETTER ETH;Ll;0;L;;;;;N;;;00D0;;00D0 -00F1;LATIN SMALL LETTER N WITH TILDE;Ll;0;L;006E 0303;;;;N;LATIN SMALL LETTER N TILDE;;00D1;;00D1 -00F2;LATIN SMALL LETTER O WITH GRAVE;Ll;0;L;006F 0300;;;;N;LATIN SMALL LETTER O GRAVE;;00D2;;00D2 -00F3;LATIN SMALL LETTER O WITH ACUTE;Ll;0;L;006F 0301;;;;N;LATIN SMALL LETTER O ACUTE;;00D3;;00D3 -00F4;LATIN SMALL LETTER O WITH CIRCUMFLEX;Ll;0;L;006F 0302;;;;N;LATIN SMALL LETTER O CIRCUMFLEX;;00D4;;00D4 -00F5;LATIN SMALL LETTER O WITH TILDE;Ll;0;L;006F 0303;;;;N;LATIN SMALL LETTER O TILDE;;00D5;;00D5 -00F6;LATIN SMALL LETTER O WITH DIAERESIS;Ll;0;L;006F 0308;;;;N;LATIN SMALL LETTER O DIAERESIS;;00D6;;00D6 -00F7;DIVISION SIGN;Sm;0;ON;;;;;N;;;;; -00F8;LATIN SMALL LETTER O WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER O SLASH;;00D8;;00D8 -00F9;LATIN SMALL LETTER U WITH GRAVE;Ll;0;L;0075 0300;;;;N;LATIN SMALL LETTER U GRAVE;;00D9;;00D9 -00FA;LATIN SMALL LETTER U WITH ACUTE;Ll;0;L;0075 0301;;;;N;LATIN SMALL LETTER U ACUTE;;00DA;;00DA -00FB;LATIN SMALL LETTER U WITH CIRCUMFLEX;Ll;0;L;0075 0302;;;;N;LATIN SMALL LETTER U CIRCUMFLEX;;00DB;;00DB -00FC;LATIN SMALL LETTER U WITH DIAERESIS;Ll;0;L;0075 0308;;;;N;LATIN SMALL LETTER U DIAERESIS;;00DC;;00DC -00FD;LATIN SMALL LETTER Y WITH ACUTE;Ll;0;L;0079 0301;;;;N;LATIN SMALL LETTER Y ACUTE;;00DD;;00DD -00FE;LATIN SMALL LETTER THORN;Ll;0;L;;;;;N;;;00DE;;00DE -00FF;LATIN SMALL LETTER Y WITH DIAERESIS;Ll;0;L;0079 0308;;;;N;LATIN SMALL LETTER Y DIAERESIS;;0178;;0178 -0100;LATIN CAPITAL LETTER A WITH MACRON;Lu;0;L;0041 0304;;;;N;LATIN CAPITAL LETTER A MACRON;;;0101; -0101;LATIN SMALL LETTER A WITH MACRON;Ll;0;L;0061 0304;;;;N;LATIN SMALL LETTER A MACRON;;0100;;0100 -0102;LATIN CAPITAL LETTER A WITH BREVE;Lu;0;L;0041 0306;;;;N;LATIN CAPITAL LETTER A BREVE;;;0103; -0103;LATIN SMALL LETTER A WITH BREVE;Ll;0;L;0061 0306;;;;N;LATIN SMALL LETTER A BREVE;;0102;;0102 -0104;LATIN CAPITAL LETTER A WITH OGONEK;Lu;0;L;0041 0328;;;;N;LATIN CAPITAL LETTER A OGONEK;;;0105; -0105;LATIN SMALL LETTER A WITH OGONEK;Ll;0;L;0061 0328;;;;N;LATIN SMALL LETTER A OGONEK;;0104;;0104 -0106;LATIN CAPITAL LETTER C WITH ACUTE;Lu;0;L;0043 0301;;;;N;LATIN CAPITAL LETTER C ACUTE;;;0107; -0107;LATIN SMALL LETTER C WITH ACUTE;Ll;0;L;0063 0301;;;;N;LATIN SMALL LETTER C ACUTE;;0106;;0106 -0108;LATIN CAPITAL LETTER C WITH CIRCUMFLEX;Lu;0;L;0043 0302;;;;N;LATIN CAPITAL LETTER C CIRCUMFLEX;;;0109; -0109;LATIN SMALL LETTER C WITH CIRCUMFLEX;Ll;0;L;0063 0302;;;;N;LATIN SMALL LETTER C CIRCUMFLEX;;0108;;0108 -010A;LATIN CAPITAL LETTER C WITH DOT ABOVE;Lu;0;L;0043 0307;;;;N;LATIN CAPITAL LETTER C DOT;;;010B; -010B;LATIN SMALL LETTER C WITH DOT ABOVE;Ll;0;L;0063 0307;;;;N;LATIN SMALL LETTER C DOT;;010A;;010A -010C;LATIN CAPITAL LETTER C WITH CARON;Lu;0;L;0043 030C;;;;N;LATIN CAPITAL LETTER C HACEK;;;010D; -010D;LATIN SMALL LETTER C WITH CARON;Ll;0;L;0063 030C;;;;N;LATIN SMALL LETTER C HACEK;;010C;;010C -010E;LATIN CAPITAL LETTER D WITH CARON;Lu;0;L;0044 030C;;;;N;LATIN CAPITAL LETTER D HACEK;;;010F; -010F;LATIN SMALL LETTER D WITH CARON;Ll;0;L;0064 030C;;;;N;LATIN SMALL LETTER D HACEK;;010E;;010E -0110;LATIN CAPITAL LETTER D WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D BAR;;;0111; -0111;LATIN SMALL LETTER D WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER D BAR;;0110;;0110 -0112;LATIN CAPITAL LETTER E WITH MACRON;Lu;0;L;0045 0304;;;;N;LATIN CAPITAL LETTER E MACRON;;;0113; -0113;LATIN SMALL LETTER E WITH MACRON;Ll;0;L;0065 0304;;;;N;LATIN SMALL LETTER E MACRON;;0112;;0112 -0114;LATIN CAPITAL LETTER E WITH BREVE;Lu;0;L;0045 0306;;;;N;LATIN CAPITAL LETTER E BREVE;;;0115; -0115;LATIN SMALL LETTER E WITH BREVE;Ll;0;L;0065 0306;;;;N;LATIN SMALL LETTER E BREVE;;0114;;0114 -0116;LATIN CAPITAL LETTER E WITH DOT ABOVE;Lu;0;L;0045 0307;;;;N;LATIN CAPITAL LETTER E DOT;;;0117; -0117;LATIN SMALL LETTER E WITH DOT ABOVE;Ll;0;L;0065 0307;;;;N;LATIN SMALL LETTER E DOT;;0116;;0116 -0118;LATIN CAPITAL LETTER E WITH OGONEK;Lu;0;L;0045 0328;;;;N;LATIN CAPITAL LETTER E OGONEK;;;0119; -0119;LATIN SMALL LETTER E WITH OGONEK;Ll;0;L;0065 0328;;;;N;LATIN SMALL LETTER E OGONEK;;0118;;0118 -011A;LATIN CAPITAL LETTER E WITH CARON;Lu;0;L;0045 030C;;;;N;LATIN CAPITAL LETTER E HACEK;;;011B; -011B;LATIN SMALL LETTER E WITH CARON;Ll;0;L;0065 030C;;;;N;LATIN SMALL LETTER E HACEK;;011A;;011A -011C;LATIN CAPITAL LETTER G WITH CIRCUMFLEX;Lu;0;L;0047 0302;;;;N;LATIN CAPITAL LETTER G CIRCUMFLEX;;;011D; -011D;LATIN SMALL LETTER G WITH CIRCUMFLEX;Ll;0;L;0067 0302;;;;N;LATIN SMALL LETTER G CIRCUMFLEX;;011C;;011C -011E;LATIN CAPITAL LETTER G WITH BREVE;Lu;0;L;0047 0306;;;;N;LATIN CAPITAL LETTER G BREVE;;;011F; -011F;LATIN SMALL LETTER G WITH BREVE;Ll;0;L;0067 0306;;;;N;LATIN SMALL LETTER G BREVE;;011E;;011E -0120;LATIN CAPITAL LETTER G WITH DOT ABOVE;Lu;0;L;0047 0307;;;;N;LATIN CAPITAL LETTER G DOT;;;0121; -0121;LATIN SMALL LETTER G WITH DOT ABOVE;Ll;0;L;0067 0307;;;;N;LATIN SMALL LETTER G DOT;;0120;;0120 -0122;LATIN CAPITAL LETTER G WITH CEDILLA;Lu;0;L;0047 0327;;;;N;LATIN CAPITAL LETTER G CEDILLA;;;0123; -0123;LATIN SMALL LETTER G WITH CEDILLA;Ll;0;L;0067 0327;;;;N;LATIN SMALL LETTER G CEDILLA;;0122;;0122 -0124;LATIN CAPITAL LETTER H WITH CIRCUMFLEX;Lu;0;L;0048 0302;;;;N;LATIN CAPITAL LETTER H CIRCUMFLEX;;;0125; -0125;LATIN SMALL LETTER H WITH CIRCUMFLEX;Ll;0;L;0068 0302;;;;N;LATIN SMALL LETTER H CIRCUMFLEX;;0124;;0124 -0126;LATIN CAPITAL LETTER H WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER H BAR;;;0127; -0127;LATIN SMALL LETTER H WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER H BAR;;0126;;0126 -0128;LATIN CAPITAL LETTER I WITH TILDE;Lu;0;L;0049 0303;;;;N;LATIN CAPITAL LETTER I TILDE;;;0129; -0129;LATIN SMALL LETTER I WITH TILDE;Ll;0;L;0069 0303;;;;N;LATIN SMALL LETTER I TILDE;;0128;;0128 -012A;LATIN CAPITAL LETTER I WITH MACRON;Lu;0;L;0049 0304;;;;N;LATIN CAPITAL LETTER I MACRON;;;012B; -012B;LATIN SMALL LETTER I WITH MACRON;Ll;0;L;0069 0304;;;;N;LATIN SMALL LETTER I MACRON;;012A;;012A -012C;LATIN CAPITAL LETTER I WITH BREVE;Lu;0;L;0049 0306;;;;N;LATIN CAPITAL LETTER I BREVE;;;012D; -012D;LATIN SMALL LETTER I WITH BREVE;Ll;0;L;0069 0306;;;;N;LATIN SMALL LETTER I BREVE;;012C;;012C -012E;LATIN CAPITAL LETTER I WITH OGONEK;Lu;0;L;0049 0328;;;;N;LATIN CAPITAL LETTER I OGONEK;;;012F; -012F;LATIN SMALL LETTER I WITH OGONEK;Ll;0;L;0069 0328;;;;N;LATIN SMALL LETTER I OGONEK;;012E;;012E -0130;LATIN CAPITAL LETTER I WITH DOT ABOVE;Lu;0;L;0049 0307;;;;N;LATIN CAPITAL LETTER I DOT;;;0069; -0131;LATIN SMALL LETTER DOTLESS I;Ll;0;L;;;;;N;;;0049;;0049 -0132;LATIN CAPITAL LIGATURE IJ;Lu;0;L;<compat> 0049 004A;;;;N;LATIN CAPITAL LETTER I J;;;0133; -0133;LATIN SMALL LIGATURE IJ;Ll;0;L;<compat> 0069 006A;;;;N;LATIN SMALL LETTER I J;;0132;;0132 -0134;LATIN CAPITAL LETTER J WITH CIRCUMFLEX;Lu;0;L;004A 0302;;;;N;LATIN CAPITAL LETTER J CIRCUMFLEX;;;0135; -0135;LATIN SMALL LETTER J WITH CIRCUMFLEX;Ll;0;L;006A 0302;;;;N;LATIN SMALL LETTER J CIRCUMFLEX;;0134;;0134 -0136;LATIN CAPITAL LETTER K WITH CEDILLA;Lu;0;L;004B 0327;;;;N;LATIN CAPITAL LETTER K CEDILLA;;;0137; -0137;LATIN SMALL LETTER K WITH CEDILLA;Ll;0;L;006B 0327;;;;N;LATIN SMALL LETTER K CEDILLA;;0136;;0136 -0138;LATIN SMALL LETTER KRA;Ll;0;L;;;;;N;;;;; -0139;LATIN CAPITAL LETTER L WITH ACUTE;Lu;0;L;004C 0301;;;;N;LATIN CAPITAL LETTER L ACUTE;;;013A; -013A;LATIN SMALL LETTER L WITH ACUTE;Ll;0;L;006C 0301;;;;N;LATIN SMALL LETTER L ACUTE;;0139;;0139 -013B;LATIN CAPITAL LETTER L WITH CEDILLA;Lu;0;L;004C 0327;;;;N;LATIN CAPITAL LETTER L CEDILLA;;;013C; -013C;LATIN SMALL LETTER L WITH CEDILLA;Ll;0;L;006C 0327;;;;N;LATIN SMALL LETTER L CEDILLA;;013B;;013B -013D;LATIN CAPITAL LETTER L WITH CARON;Lu;0;L;004C 030C;;;;N;LATIN CAPITAL LETTER L HACEK;;;013E; -013E;LATIN SMALL LETTER L WITH CARON;Ll;0;L;006C 030C;;;;N;LATIN SMALL LETTER L HACEK;;013D;;013D -013F;LATIN CAPITAL LETTER L WITH MIDDLE DOT;Lu;0;L;<compat> 004C 00B7;;;;N;;;;0140; -0140;LATIN SMALL LETTER L WITH MIDDLE DOT;Ll;0;L;<compat> 006C 00B7;;;;N;;;013F;;013F -0141;LATIN CAPITAL LETTER L WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER L SLASH;;;0142; -0142;LATIN SMALL LETTER L WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER L SLASH;;0141;;0141 -0143;LATIN CAPITAL LETTER N WITH ACUTE;Lu;0;L;004E 0301;;;;N;LATIN CAPITAL LETTER N ACUTE;;;0144; -0144;LATIN SMALL LETTER N WITH ACUTE;Ll;0;L;006E 0301;;;;N;LATIN SMALL LETTER N ACUTE;;0143;;0143 -0145;LATIN CAPITAL LETTER N WITH CEDILLA;Lu;0;L;004E 0327;;;;N;LATIN CAPITAL LETTER N CEDILLA;;;0146; -0146;LATIN SMALL LETTER N WITH CEDILLA;Ll;0;L;006E 0327;;;;N;LATIN SMALL LETTER N CEDILLA;;0145;;0145 -0147;LATIN CAPITAL LETTER N WITH CARON;Lu;0;L;004E 030C;;;;N;LATIN CAPITAL LETTER N HACEK;;;0148; -0148;LATIN SMALL LETTER N WITH CARON;Ll;0;L;006E 030C;;;;N;LATIN SMALL LETTER N HACEK;;0147;;0147 -0149;LATIN SMALL LETTER N PRECEDED BY APOSTROPHE;Ll;0;L;<compat> 02BC 006E;;;;N;LATIN SMALL LETTER APOSTROPHE N;;;; -014A;LATIN CAPITAL LETTER ENG;Lu;0;L;;;;;N;;;;014B; -014B;LATIN SMALL LETTER ENG;Ll;0;L;;;;;N;;;014A;;014A -014C;LATIN CAPITAL LETTER O WITH MACRON;Lu;0;L;004F 0304;;;;N;LATIN CAPITAL LETTER O MACRON;;;014D; -014D;LATIN SMALL LETTER O WITH MACRON;Ll;0;L;006F 0304;;;;N;LATIN SMALL LETTER O MACRON;;014C;;014C -014E;LATIN CAPITAL LETTER O WITH BREVE;Lu;0;L;004F 0306;;;;N;LATIN CAPITAL LETTER O BREVE;;;014F; -014F;LATIN SMALL LETTER O WITH BREVE;Ll;0;L;006F 0306;;;;N;LATIN SMALL LETTER O BREVE;;014E;;014E -0150;LATIN CAPITAL LETTER O WITH DOUBLE ACUTE;Lu;0;L;004F 030B;;;;N;LATIN CAPITAL LETTER O DOUBLE ACUTE;;;0151; -0151;LATIN SMALL LETTER O WITH DOUBLE ACUTE;Ll;0;L;006F 030B;;;;N;LATIN SMALL LETTER O DOUBLE ACUTE;;0150;;0150 -0152;LATIN CAPITAL LIGATURE OE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O E;;;0153; -0153;LATIN SMALL LIGATURE OE;Ll;0;L;;;;;N;LATIN SMALL LETTER O E;;0152;;0152 -0154;LATIN CAPITAL LETTER R WITH ACUTE;Lu;0;L;0052 0301;;;;N;LATIN CAPITAL LETTER R ACUTE;;;0155; -0155;LATIN SMALL LETTER R WITH ACUTE;Ll;0;L;0072 0301;;;;N;LATIN SMALL LETTER R ACUTE;;0154;;0154 -0156;LATIN CAPITAL LETTER R WITH CEDILLA;Lu;0;L;0052 0327;;;;N;LATIN CAPITAL LETTER R CEDILLA;;;0157; -0157;LATIN SMALL LETTER R WITH CEDILLA;Ll;0;L;0072 0327;;;;N;LATIN SMALL LETTER R CEDILLA;;0156;;0156 -0158;LATIN CAPITAL LETTER R WITH CARON;Lu;0;L;0052 030C;;;;N;LATIN CAPITAL LETTER R HACEK;;;0159; -0159;LATIN SMALL LETTER R WITH CARON;Ll;0;L;0072 030C;;;;N;LATIN SMALL LETTER R HACEK;;0158;;0158 -015A;LATIN CAPITAL LETTER S WITH ACUTE;Lu;0;L;0053 0301;;;;N;LATIN CAPITAL LETTER S ACUTE;;;015B; -015B;LATIN SMALL LETTER S WITH ACUTE;Ll;0;L;0073 0301;;;;N;LATIN SMALL LETTER S ACUTE;;015A;;015A -015C;LATIN CAPITAL LETTER S WITH CIRCUMFLEX;Lu;0;L;0053 0302;;;;N;LATIN CAPITAL LETTER S CIRCUMFLEX;;;015D; -015D;LATIN SMALL LETTER S WITH CIRCUMFLEX;Ll;0;L;0073 0302;;;;N;LATIN SMALL LETTER S CIRCUMFLEX;;015C;;015C -015E;LATIN CAPITAL LETTER S WITH CEDILLA;Lu;0;L;0053 0327;;;;N;LATIN CAPITAL LETTER S CEDILLA;;;015F; -015F;LATIN SMALL LETTER S WITH CEDILLA;Ll;0;L;0073 0327;;;;N;LATIN SMALL LETTER S CEDILLA;;015E;;015E -0160;LATIN CAPITAL LETTER S WITH CARON;Lu;0;L;0053 030C;;;;N;LATIN CAPITAL LETTER S HACEK;;;0161; -0161;LATIN SMALL LETTER S WITH CARON;Ll;0;L;0073 030C;;;;N;LATIN SMALL LETTER S HACEK;;0160;;0160 -0162;LATIN CAPITAL LETTER T WITH CEDILLA;Lu;0;L;0054 0327;;;;N;LATIN CAPITAL LETTER T CEDILLA;;;0163; -0163;LATIN SMALL LETTER T WITH CEDILLA;Ll;0;L;0074 0327;;;;N;LATIN SMALL LETTER T CEDILLA;;0162;;0162 -0164;LATIN CAPITAL LETTER T WITH CARON;Lu;0;L;0054 030C;;;;N;LATIN CAPITAL LETTER T HACEK;;;0165; -0165;LATIN SMALL LETTER T WITH CARON;Ll;0;L;0074 030C;;;;N;LATIN SMALL LETTER T HACEK;;0164;;0164 -0166;LATIN CAPITAL LETTER T WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T BAR;;;0167; -0167;LATIN SMALL LETTER T WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER T BAR;;0166;;0166 -0168;LATIN CAPITAL LETTER U WITH TILDE;Lu;0;L;0055 0303;;;;N;LATIN CAPITAL LETTER U TILDE;;;0169; -0169;LATIN SMALL LETTER U WITH TILDE;Ll;0;L;0075 0303;;;;N;LATIN SMALL LETTER U TILDE;;0168;;0168 -016A;LATIN CAPITAL LETTER U WITH MACRON;Lu;0;L;0055 0304;;;;N;LATIN CAPITAL LETTER U MACRON;;;016B; -016B;LATIN SMALL LETTER U WITH MACRON;Ll;0;L;0075 0304;;;;N;LATIN SMALL LETTER U MACRON;;016A;;016A -016C;LATIN CAPITAL LETTER U WITH BREVE;Lu;0;L;0055 0306;;;;N;LATIN CAPITAL LETTER U BREVE;;;016D; -016D;LATIN SMALL LETTER U WITH BREVE;Ll;0;L;0075 0306;;;;N;LATIN SMALL LETTER U BREVE;;016C;;016C -016E;LATIN CAPITAL LETTER U WITH RING ABOVE;Lu;0;L;0055 030A;;;;N;LATIN CAPITAL LETTER U RING;;;016F; -016F;LATIN SMALL LETTER U WITH RING ABOVE;Ll;0;L;0075 030A;;;;N;LATIN SMALL LETTER U RING;;016E;;016E -0170;LATIN CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0055 030B;;;;N;LATIN CAPITAL LETTER U DOUBLE ACUTE;;;0171; -0171;LATIN SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0075 030B;;;;N;LATIN SMALL LETTER U DOUBLE ACUTE;;0170;;0170 -0172;LATIN CAPITAL LETTER U WITH OGONEK;Lu;0;L;0055 0328;;;;N;LATIN CAPITAL LETTER U OGONEK;;;0173; -0173;LATIN SMALL LETTER U WITH OGONEK;Ll;0;L;0075 0328;;;;N;LATIN SMALL LETTER U OGONEK;;0172;;0172 -0174;LATIN CAPITAL LETTER W WITH CIRCUMFLEX;Lu;0;L;0057 0302;;;;N;LATIN CAPITAL LETTER W CIRCUMFLEX;;;0175; -0175;LATIN SMALL LETTER W WITH CIRCUMFLEX;Ll;0;L;0077 0302;;;;N;LATIN SMALL LETTER W CIRCUMFLEX;;0174;;0174 -0176;LATIN CAPITAL LETTER Y WITH CIRCUMFLEX;Lu;0;L;0059 0302;;;;N;LATIN CAPITAL LETTER Y CIRCUMFLEX;;;0177; -0177;LATIN SMALL LETTER Y WITH CIRCUMFLEX;Ll;0;L;0079 0302;;;;N;LATIN SMALL LETTER Y CIRCUMFLEX;;0176;;0176 -0178;LATIN CAPITAL LETTER Y WITH DIAERESIS;Lu;0;L;0059 0308;;;;N;LATIN CAPITAL LETTER Y DIAERESIS;;;00FF; -0179;LATIN CAPITAL LETTER Z WITH ACUTE;Lu;0;L;005A 0301;;;;N;LATIN CAPITAL LETTER Z ACUTE;;;017A; -017A;LATIN SMALL LETTER Z WITH ACUTE;Ll;0;L;007A 0301;;;;N;LATIN SMALL LETTER Z ACUTE;;0179;;0179 -017B;LATIN CAPITAL LETTER Z WITH DOT ABOVE;Lu;0;L;005A 0307;;;;N;LATIN CAPITAL LETTER Z DOT;;;017C; -017C;LATIN SMALL LETTER Z WITH DOT ABOVE;Ll;0;L;007A 0307;;;;N;LATIN SMALL LETTER Z DOT;;017B;;017B -017D;LATIN CAPITAL LETTER Z WITH CARON;Lu;0;L;005A 030C;;;;N;LATIN CAPITAL LETTER Z HACEK;;;017E; -017E;LATIN SMALL LETTER Z WITH CARON;Ll;0;L;007A 030C;;;;N;LATIN SMALL LETTER Z HACEK;;017D;;017D -017F;LATIN SMALL LETTER LONG S;Ll;0;L;<compat> 0073;;;;N;;;0053;;0053 -0180;LATIN SMALL LETTER B WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER B BAR;;0243;;0243 -0181;LATIN CAPITAL LETTER B WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B HOOK;;;0253; -0182;LATIN CAPITAL LETTER B WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B TOPBAR;;;0183; -0183;LATIN SMALL LETTER B WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER B TOPBAR;;0182;;0182 -0184;LATIN CAPITAL LETTER TONE SIX;Lu;0;L;;;;;N;;;;0185; -0185;LATIN SMALL LETTER TONE SIX;Ll;0;L;;;;;N;;;0184;;0184 -0186;LATIN CAPITAL LETTER OPEN O;Lu;0;L;;;;;N;;;;0254; -0187;LATIN CAPITAL LETTER C WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER C HOOK;;;0188; -0188;LATIN SMALL LETTER C WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER C HOOK;;0187;;0187 -0189;LATIN CAPITAL LETTER AFRICAN D;Lu;0;L;;;;;N;;;;0256; -018A;LATIN CAPITAL LETTER D WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D HOOK;;;0257; -018B;LATIN CAPITAL LETTER D WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D TOPBAR;;;018C; -018C;LATIN SMALL LETTER D WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER D TOPBAR;;018B;;018B -018D;LATIN SMALL LETTER TURNED DELTA;Ll;0;L;;;;;N;;;;; -018E;LATIN CAPITAL LETTER REVERSED E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER TURNED E;;;01DD; -018F;LATIN CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;0259; -0190;LATIN CAPITAL LETTER OPEN E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER EPSILON;;;025B; -0191;LATIN CAPITAL LETTER F WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER F HOOK;;;0192; -0192;LATIN SMALL LETTER F WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT F;;0191;;0191 -0193;LATIN CAPITAL LETTER G WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G HOOK;;;0260; -0194;LATIN CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;0263; -0195;LATIN SMALL LETTER HV;Ll;0;L;;;;;N;LATIN SMALL LETTER H V;;01F6;;01F6 -0196;LATIN CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;0269; -0197;LATIN CAPITAL LETTER I WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED I;;;0268; -0198;LATIN CAPITAL LETTER K WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER K HOOK;;;0199; -0199;LATIN SMALL LETTER K WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER K HOOK;;0198;;0198 -019A;LATIN SMALL LETTER L WITH BAR;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED L;;023D;;023D -019B;LATIN SMALL LETTER LAMBDA WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED LAMBDA;;;; -019C;LATIN CAPITAL LETTER TURNED M;Lu;0;L;;;;;N;;;;026F; -019D;LATIN CAPITAL LETTER N WITH LEFT HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER N HOOK;;;0272; -019E;LATIN SMALL LETTER N WITH LONG RIGHT LEG;Ll;0;L;;;;;N;;;0220;;0220 -019F;LATIN CAPITAL LETTER O WITH MIDDLE TILDE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED O;;;0275; -01A0;LATIN CAPITAL LETTER O WITH HORN;Lu;0;L;004F 031B;;;;N;LATIN CAPITAL LETTER O HORN;;;01A1; -01A1;LATIN SMALL LETTER O WITH HORN;Ll;0;L;006F 031B;;;;N;LATIN SMALL LETTER O HORN;;01A0;;01A0 -01A2;LATIN CAPITAL LETTER OI;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O I;;;01A3; -01A3;LATIN SMALL LETTER OI;Ll;0;L;;;;;N;LATIN SMALL LETTER O I;;01A2;;01A2 -01A4;LATIN CAPITAL LETTER P WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER P HOOK;;;01A5; -01A5;LATIN SMALL LETTER P WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER P HOOK;;01A4;;01A4 -01A6;LATIN LETTER YR;Lu;0;L;;;;;N;LATIN LETTER Y R;;;0280; -01A7;LATIN CAPITAL LETTER TONE TWO;Lu;0;L;;;;;N;;;;01A8; -01A8;LATIN SMALL LETTER TONE TWO;Ll;0;L;;;;;N;;;01A7;;01A7 -01A9;LATIN CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;0283; -01AA;LATIN LETTER REVERSED ESH LOOP;Ll;0;L;;;;;N;;;;; -01AB;LATIN SMALL LETTER T WITH PALATAL HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T PALATAL HOOK;;;; -01AC;LATIN CAPITAL LETTER T WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T HOOK;;;01AD; -01AD;LATIN SMALL LETTER T WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T HOOK;;01AC;;01AC -01AE;LATIN CAPITAL LETTER T WITH RETROFLEX HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T RETROFLEX HOOK;;;0288; -01AF;LATIN CAPITAL LETTER U WITH HORN;Lu;0;L;0055 031B;;;;N;LATIN CAPITAL LETTER U HORN;;;01B0; -01B0;LATIN SMALL LETTER U WITH HORN;Ll;0;L;0075 031B;;;;N;LATIN SMALL LETTER U HORN;;01AF;;01AF -01B1;LATIN CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;028A; -01B2;LATIN CAPITAL LETTER V WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER SCRIPT V;;;028B; -01B3;LATIN CAPITAL LETTER Y WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Y HOOK;;;01B4; -01B4;LATIN SMALL LETTER Y WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Y HOOK;;01B3;;01B3 -01B5;LATIN CAPITAL LETTER Z WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Z BAR;;;01B6; -01B6;LATIN SMALL LETTER Z WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER Z BAR;;01B5;;01B5 -01B7;LATIN CAPITAL LETTER EZH;Lu;0;L;;;;;N;LATIN CAPITAL LETTER YOGH;;;0292; -01B8;LATIN CAPITAL LETTER EZH REVERSED;Lu;0;L;;;;;N;LATIN CAPITAL LETTER REVERSED YOGH;;;01B9; -01B9;LATIN SMALL LETTER EZH REVERSED;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED YOGH;;01B8;;01B8 -01BA;LATIN SMALL LETTER EZH WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH WITH TAIL;;;; -01BB;LATIN LETTER TWO WITH STROKE;Lo;0;L;;;;;N;LATIN LETTER TWO BAR;;;; -01BC;LATIN CAPITAL LETTER TONE FIVE;Lu;0;L;;;;;N;;;;01BD; -01BD;LATIN SMALL LETTER TONE FIVE;Ll;0;L;;;;;N;;;01BC;;01BC -01BE;LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER INVERTED GLOTTAL STOP BAR;;;; -01BF;LATIN LETTER WYNN;Ll;0;L;;;;;N;;;01F7;;01F7 -01C0;LATIN LETTER DENTAL CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE;;;; -01C1;LATIN LETTER LATERAL CLICK;Lo;0;L;;;;;N;LATIN LETTER DOUBLE PIPE;;;; -01C2;LATIN LETTER ALVEOLAR CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE DOUBLE BAR;;;; -01C3;LATIN LETTER RETROFLEX CLICK;Lo;0;L;;;;;N;LATIN LETTER EXCLAMATION MARK;;;; -01C4;LATIN CAPITAL LETTER DZ WITH CARON;Lu;0;L;<compat> 0044 017D;;;;N;LATIN CAPITAL LETTER D Z HACEK;;;01C6;01C5 -01C5;LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON;Lt;0;L;<compat> 0044 017E;;;;N;LATIN LETTER CAPITAL D SMALL Z HACEK;;01C4;01C6;01C5 -01C6;LATIN SMALL LETTER DZ WITH CARON;Ll;0;L;<compat> 0064 017E;;;;N;LATIN SMALL LETTER D Z HACEK;;01C4;;01C5 -01C7;LATIN CAPITAL LETTER LJ;Lu;0;L;<compat> 004C 004A;;;;N;LATIN CAPITAL LETTER L J;;;01C9;01C8 -01C8;LATIN CAPITAL LETTER L WITH SMALL LETTER J;Lt;0;L;<compat> 004C 006A;;;;N;LATIN LETTER CAPITAL L SMALL J;;01C7;01C9;01C8 -01C9;LATIN SMALL LETTER LJ;Ll;0;L;<compat> 006C 006A;;;;N;LATIN SMALL LETTER L J;;01C7;;01C8 -01CA;LATIN CAPITAL LETTER NJ;Lu;0;L;<compat> 004E 004A;;;;N;LATIN CAPITAL LETTER N J;;;01CC;01CB -01CB;LATIN CAPITAL LETTER N WITH SMALL LETTER J;Lt;0;L;<compat> 004E 006A;;;;N;LATIN LETTER CAPITAL N SMALL J;;01CA;01CC;01CB -01CC;LATIN SMALL LETTER NJ;Ll;0;L;<compat> 006E 006A;;;;N;LATIN SMALL LETTER N J;;01CA;;01CB -01CD;LATIN CAPITAL LETTER A WITH CARON;Lu;0;L;0041 030C;;;;N;LATIN CAPITAL LETTER A HACEK;;;01CE; -01CE;LATIN SMALL LETTER A WITH CARON;Ll;0;L;0061 030C;;;;N;LATIN SMALL LETTER A HACEK;;01CD;;01CD -01CF;LATIN CAPITAL LETTER I WITH CARON;Lu;0;L;0049 030C;;;;N;LATIN CAPITAL LETTER I HACEK;;;01D0; -01D0;LATIN SMALL LETTER I WITH CARON;Ll;0;L;0069 030C;;;;N;LATIN SMALL LETTER I HACEK;;01CF;;01CF -01D1;LATIN CAPITAL LETTER O WITH CARON;Lu;0;L;004F 030C;;;;N;LATIN CAPITAL LETTER O HACEK;;;01D2; -01D2;LATIN SMALL LETTER O WITH CARON;Ll;0;L;006F 030C;;;;N;LATIN SMALL LETTER O HACEK;;01D1;;01D1 -01D3;LATIN CAPITAL LETTER U WITH CARON;Lu;0;L;0055 030C;;;;N;LATIN CAPITAL LETTER U HACEK;;;01D4; -01D4;LATIN SMALL LETTER U WITH CARON;Ll;0;L;0075 030C;;;;N;LATIN SMALL LETTER U HACEK;;01D3;;01D3 -01D5;LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON;Lu;0;L;00DC 0304;;;;N;LATIN CAPITAL LETTER U DIAERESIS MACRON;;;01D6; -01D6;LATIN SMALL LETTER U WITH DIAERESIS AND MACRON;Ll;0;L;00FC 0304;;;;N;LATIN SMALL LETTER U DIAERESIS MACRON;;01D5;;01D5 -01D7;LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE;Lu;0;L;00DC 0301;;;;N;LATIN CAPITAL LETTER U DIAERESIS ACUTE;;;01D8; -01D8;LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE;Ll;0;L;00FC 0301;;;;N;LATIN SMALL LETTER U DIAERESIS ACUTE;;01D7;;01D7 -01D9;LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON;Lu;0;L;00DC 030C;;;;N;LATIN CAPITAL LETTER U DIAERESIS HACEK;;;01DA; -01DA;LATIN SMALL LETTER U WITH DIAERESIS AND CARON;Ll;0;L;00FC 030C;;;;N;LATIN SMALL LETTER U DIAERESIS HACEK;;01D9;;01D9 -01DB;LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE;Lu;0;L;00DC 0300;;;;N;LATIN CAPITAL LETTER U DIAERESIS GRAVE;;;01DC; -01DC;LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE;Ll;0;L;00FC 0300;;;;N;LATIN SMALL LETTER U DIAERESIS GRAVE;;01DB;;01DB -01DD;LATIN SMALL LETTER TURNED E;Ll;0;L;;;;;N;;;018E;;018E -01DE;LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON;Lu;0;L;00C4 0304;;;;N;LATIN CAPITAL LETTER A DIAERESIS MACRON;;;01DF; -01DF;LATIN SMALL LETTER A WITH DIAERESIS AND MACRON;Ll;0;L;00E4 0304;;;;N;LATIN SMALL LETTER A DIAERESIS MACRON;;01DE;;01DE -01E0;LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON;Lu;0;L;0226 0304;;;;N;LATIN CAPITAL LETTER A DOT MACRON;;;01E1; -01E1;LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON;Ll;0;L;0227 0304;;;;N;LATIN SMALL LETTER A DOT MACRON;;01E0;;01E0 -01E2;LATIN CAPITAL LETTER AE WITH MACRON;Lu;0;L;00C6 0304;;;;N;LATIN CAPITAL LETTER A E MACRON;;;01E3; -01E3;LATIN SMALL LETTER AE WITH MACRON;Ll;0;L;00E6 0304;;;;N;LATIN SMALL LETTER A E MACRON;;01E2;;01E2 -01E4;LATIN CAPITAL LETTER G WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G BAR;;;01E5; -01E5;LATIN SMALL LETTER G WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER G BAR;;01E4;;01E4 -01E6;LATIN CAPITAL LETTER G WITH CARON;Lu;0;L;0047 030C;;;;N;LATIN CAPITAL LETTER G HACEK;;;01E7; -01E7;LATIN SMALL LETTER G WITH CARON;Ll;0;L;0067 030C;;;;N;LATIN SMALL LETTER G HACEK;;01E6;;01E6 -01E8;LATIN CAPITAL LETTER K WITH CARON;Lu;0;L;004B 030C;;;;N;LATIN CAPITAL LETTER K HACEK;;;01E9; -01E9;LATIN SMALL LETTER K WITH CARON;Ll;0;L;006B 030C;;;;N;LATIN SMALL LETTER K HACEK;;01E8;;01E8 -01EA;LATIN CAPITAL LETTER O WITH OGONEK;Lu;0;L;004F 0328;;;;N;LATIN CAPITAL LETTER O OGONEK;;;01EB; -01EB;LATIN SMALL LETTER O WITH OGONEK;Ll;0;L;006F 0328;;;;N;LATIN SMALL LETTER O OGONEK;;01EA;;01EA -01EC;LATIN CAPITAL LETTER O WITH OGONEK AND MACRON;Lu;0;L;01EA 0304;;;;N;LATIN CAPITAL LETTER O OGONEK MACRON;;;01ED; -01ED;LATIN SMALL LETTER O WITH OGONEK AND MACRON;Ll;0;L;01EB 0304;;;;N;LATIN SMALL LETTER O OGONEK MACRON;;01EC;;01EC -01EE;LATIN CAPITAL LETTER EZH WITH CARON;Lu;0;L;01B7 030C;;;;N;LATIN CAPITAL LETTER YOGH HACEK;;;01EF; -01EF;LATIN SMALL LETTER EZH WITH CARON;Ll;0;L;0292 030C;;;;N;LATIN SMALL LETTER YOGH HACEK;;01EE;;01EE -01F0;LATIN SMALL LETTER J WITH CARON;Ll;0;L;006A 030C;;;;N;LATIN SMALL LETTER J HACEK;;;; -01F1;LATIN CAPITAL LETTER DZ;Lu;0;L;<compat> 0044 005A;;;;N;;;;01F3;01F2 -01F2;LATIN CAPITAL LETTER D WITH SMALL LETTER Z;Lt;0;L;<compat> 0044 007A;;;;N;;;01F1;01F3;01F2 -01F3;LATIN SMALL LETTER DZ;Ll;0;L;<compat> 0064 007A;;;;N;;;01F1;;01F2 -01F4;LATIN CAPITAL LETTER G WITH ACUTE;Lu;0;L;0047 0301;;;;N;;;;01F5; -01F5;LATIN SMALL LETTER G WITH ACUTE;Ll;0;L;0067 0301;;;;N;;;01F4;;01F4 -01F6;LATIN CAPITAL LETTER HWAIR;Lu;0;L;;;;;N;;;;0195; -01F7;LATIN CAPITAL LETTER WYNN;Lu;0;L;;;;;N;;;;01BF; -01F8;LATIN CAPITAL LETTER N WITH GRAVE;Lu;0;L;004E 0300;;;;N;;;;01F9; -01F9;LATIN SMALL LETTER N WITH GRAVE;Ll;0;L;006E 0300;;;;N;;;01F8;;01F8 -01FA;LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE;Lu;0;L;00C5 0301;;;;N;;;;01FB; -01FB;LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE;Ll;0;L;00E5 0301;;;;N;;;01FA;;01FA -01FC;LATIN CAPITAL LETTER AE WITH ACUTE;Lu;0;L;00C6 0301;;;;N;;;;01FD; -01FD;LATIN SMALL LETTER AE WITH ACUTE;Ll;0;L;00E6 0301;;;;N;;;01FC;;01FC -01FE;LATIN CAPITAL LETTER O WITH STROKE AND ACUTE;Lu;0;L;00D8 0301;;;;N;;;;01FF; -01FF;LATIN SMALL LETTER O WITH STROKE AND ACUTE;Ll;0;L;00F8 0301;;;;N;;;01FE;;01FE -0200;LATIN CAPITAL LETTER A WITH DOUBLE GRAVE;Lu;0;L;0041 030F;;;;N;;;;0201; -0201;LATIN SMALL LETTER A WITH DOUBLE GRAVE;Ll;0;L;0061 030F;;;;N;;;0200;;0200 -0202;LATIN CAPITAL LETTER A WITH INVERTED BREVE;Lu;0;L;0041 0311;;;;N;;;;0203; -0203;LATIN SMALL LETTER A WITH INVERTED BREVE;Ll;0;L;0061 0311;;;;N;;;0202;;0202 -0204;LATIN CAPITAL LETTER E WITH DOUBLE GRAVE;Lu;0;L;0045 030F;;;;N;;;;0205; -0205;LATIN SMALL LETTER E WITH DOUBLE GRAVE;Ll;0;L;0065 030F;;;;N;;;0204;;0204 -0206;LATIN CAPITAL LETTER E WITH INVERTED BREVE;Lu;0;L;0045 0311;;;;N;;;;0207; -0207;LATIN SMALL LETTER E WITH INVERTED BREVE;Ll;0;L;0065 0311;;;;N;;;0206;;0206 -0208;LATIN CAPITAL LETTER I WITH DOUBLE GRAVE;Lu;0;L;0049 030F;;;;N;;;;0209; -0209;LATIN SMALL LETTER I WITH DOUBLE GRAVE;Ll;0;L;0069 030F;;;;N;;;0208;;0208 -020A;LATIN CAPITAL LETTER I WITH INVERTED BREVE;Lu;0;L;0049 0311;;;;N;;;;020B; -020B;LATIN SMALL LETTER I WITH INVERTED BREVE;Ll;0;L;0069 0311;;;;N;;;020A;;020A -020C;LATIN CAPITAL LETTER O WITH DOUBLE GRAVE;Lu;0;L;004F 030F;;;;N;;;;020D; -020D;LATIN SMALL LETTER O WITH DOUBLE GRAVE;Ll;0;L;006F 030F;;;;N;;;020C;;020C -020E;LATIN CAPITAL LETTER O WITH INVERTED BREVE;Lu;0;L;004F 0311;;;;N;;;;020F; -020F;LATIN SMALL LETTER O WITH INVERTED BREVE;Ll;0;L;006F 0311;;;;N;;;020E;;020E -0210;LATIN CAPITAL LETTER R WITH DOUBLE GRAVE;Lu;0;L;0052 030F;;;;N;;;;0211; -0211;LATIN SMALL LETTER R WITH DOUBLE GRAVE;Ll;0;L;0072 030F;;;;N;;;0210;;0210 -0212;LATIN CAPITAL LETTER R WITH INVERTED BREVE;Lu;0;L;0052 0311;;;;N;;;;0213; -0213;LATIN SMALL LETTER R WITH INVERTED BREVE;Ll;0;L;0072 0311;;;;N;;;0212;;0212 -0214;LATIN CAPITAL LETTER U WITH DOUBLE GRAVE;Lu;0;L;0055 030F;;;;N;;;;0215; -0215;LATIN SMALL LETTER U WITH DOUBLE GRAVE;Ll;0;L;0075 030F;;;;N;;;0214;;0214 -0216;LATIN CAPITAL LETTER U WITH INVERTED BREVE;Lu;0;L;0055 0311;;;;N;;;;0217; -0217;LATIN SMALL LETTER U WITH INVERTED BREVE;Ll;0;L;0075 0311;;;;N;;;0216;;0216 -0218;LATIN CAPITAL LETTER S WITH COMMA BELOW;Lu;0;L;0053 0326;;;;N;;;;0219; -0219;LATIN SMALL LETTER S WITH COMMA BELOW;Ll;0;L;0073 0326;;;;N;;;0218;;0218 -021A;LATIN CAPITAL LETTER T WITH COMMA BELOW;Lu;0;L;0054 0326;;;;N;;;;021B; -021B;LATIN SMALL LETTER T WITH COMMA BELOW;Ll;0;L;0074 0326;;;;N;;;021A;;021A -021C;LATIN CAPITAL LETTER YOGH;Lu;0;L;;;;;N;;;;021D; -021D;LATIN SMALL LETTER YOGH;Ll;0;L;;;;;N;;;021C;;021C -021E;LATIN CAPITAL LETTER H WITH CARON;Lu;0;L;0048 030C;;;;N;;;;021F; -021F;LATIN SMALL LETTER H WITH CARON;Ll;0;L;0068 030C;;;;N;;;021E;;021E -0220;LATIN CAPITAL LETTER N WITH LONG RIGHT LEG;Lu;0;L;;;;;N;;;;019E; -0221;LATIN SMALL LETTER D WITH CURL;Ll;0;L;;;;;N;;;;; -0222;LATIN CAPITAL LETTER OU;Lu;0;L;;;;;N;;;;0223; -0223;LATIN SMALL LETTER OU;Ll;0;L;;;;;N;;;0222;;0222 -0224;LATIN CAPITAL LETTER Z WITH HOOK;Lu;0;L;;;;;N;;;;0225; -0225;LATIN SMALL LETTER Z WITH HOOK;Ll;0;L;;;;;N;;;0224;;0224 -0226;LATIN CAPITAL LETTER A WITH DOT ABOVE;Lu;0;L;0041 0307;;;;N;;;;0227; -0227;LATIN SMALL LETTER A WITH DOT ABOVE;Ll;0;L;0061 0307;;;;N;;;0226;;0226 -0228;LATIN CAPITAL LETTER E WITH CEDILLA;Lu;0;L;0045 0327;;;;N;;;;0229; -0229;LATIN SMALL LETTER E WITH CEDILLA;Ll;0;L;0065 0327;;;;N;;;0228;;0228 -022A;LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON;Lu;0;L;00D6 0304;;;;N;;;;022B; -022B;LATIN SMALL LETTER O WITH DIAERESIS AND MACRON;Ll;0;L;00F6 0304;;;;N;;;022A;;022A -022C;LATIN CAPITAL LETTER O WITH TILDE AND MACRON;Lu;0;L;00D5 0304;;;;N;;;;022D; -022D;LATIN SMALL LETTER O WITH TILDE AND MACRON;Ll;0;L;00F5 0304;;;;N;;;022C;;022C -022E;LATIN CAPITAL LETTER O WITH DOT ABOVE;Lu;0;L;004F 0307;;;;N;;;;022F; -022F;LATIN SMALL LETTER O WITH DOT ABOVE;Ll;0;L;006F 0307;;;;N;;;022E;;022E -0230;LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON;Lu;0;L;022E 0304;;;;N;;;;0231; -0231;LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON;Ll;0;L;022F 0304;;;;N;;;0230;;0230 -0232;LATIN CAPITAL LETTER Y WITH MACRON;Lu;0;L;0059 0304;;;;N;;;;0233; -0233;LATIN SMALL LETTER Y WITH MACRON;Ll;0;L;0079 0304;;;;N;;;0232;;0232 -0234;LATIN SMALL LETTER L WITH CURL;Ll;0;L;;;;;N;;;;; -0235;LATIN SMALL LETTER N WITH CURL;Ll;0;L;;;;;N;;;;; -0236;LATIN SMALL LETTER T WITH CURL;Ll;0;L;;;;;N;;;;; -0237;LATIN SMALL LETTER DOTLESS J;Ll;0;L;;;;;N;;;;; -0238;LATIN SMALL LETTER DB DIGRAPH;Ll;0;L;;;;;N;;;;; -0239;LATIN SMALL LETTER QP DIGRAPH;Ll;0;L;;;;;N;;;;; -023A;LATIN CAPITAL LETTER A WITH STROKE;Lu;0;L;;;;;N;;;;2C65; -023B;LATIN CAPITAL LETTER C WITH STROKE;Lu;0;L;;;;;N;;;;023C; -023C;LATIN SMALL LETTER C WITH STROKE;Ll;0;L;;;;;N;;;023B;;023B -023D;LATIN CAPITAL LETTER L WITH BAR;Lu;0;L;;;;;N;;;;019A; -023E;LATIN CAPITAL LETTER T WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;2C66; -023F;LATIN SMALL LETTER S WITH SWASH TAIL;Ll;0;L;;;;;N;;;2C7E;;2C7E -0240;LATIN SMALL LETTER Z WITH SWASH TAIL;Ll;0;L;;;;;N;;;2C7F;;2C7F -0241;LATIN CAPITAL LETTER GLOTTAL STOP;Lu;0;L;;;;;N;;;;0242; -0242;LATIN SMALL LETTER GLOTTAL STOP;Ll;0;L;;;;;N;;;0241;;0241 -0243;LATIN CAPITAL LETTER B WITH STROKE;Lu;0;L;;;;;N;;;;0180; -0244;LATIN CAPITAL LETTER U BAR;Lu;0;L;;;;;N;;;;0289; -0245;LATIN CAPITAL LETTER TURNED V;Lu;0;L;;;;;N;;;;028C; -0246;LATIN CAPITAL LETTER E WITH STROKE;Lu;0;L;;;;;N;;;;0247; -0247;LATIN SMALL LETTER E WITH STROKE;Ll;0;L;;;;;N;;;0246;;0246 -0248;LATIN CAPITAL LETTER J WITH STROKE;Lu;0;L;;;;;N;;;;0249; -0249;LATIN SMALL LETTER J WITH STROKE;Ll;0;L;;;;;N;;;0248;;0248 -024A;LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL;Lu;0;L;;;;;N;;;;024B; -024B;LATIN SMALL LETTER Q WITH HOOK TAIL;Ll;0;L;;;;;N;;;024A;;024A -024C;LATIN CAPITAL LETTER R WITH STROKE;Lu;0;L;;;;;N;;;;024D; -024D;LATIN SMALL LETTER R WITH STROKE;Ll;0;L;;;;;N;;;024C;;024C -024E;LATIN CAPITAL LETTER Y WITH STROKE;Lu;0;L;;;;;N;;;;024F; -024F;LATIN SMALL LETTER Y WITH STROKE;Ll;0;L;;;;;N;;;024E;;024E -0250;LATIN SMALL LETTER TURNED A;Ll;0;L;;;;;N;;;2C6F;;2C6F -0251;LATIN SMALL LETTER ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT A;;2C6D;;2C6D -0252;LATIN SMALL LETTER TURNED ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED SCRIPT A;;2C70;;2C70 -0253;LATIN SMALL LETTER B WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER B HOOK;;0181;;0181 -0254;LATIN SMALL LETTER OPEN O;Ll;0;L;;;;;N;;;0186;;0186 -0255;LATIN SMALL LETTER C WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER C CURL;;;; -0256;LATIN SMALL LETTER D WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER D RETROFLEX HOOK;;0189;;0189 -0257;LATIN SMALL LETTER D WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER D HOOK;;018A;;018A -0258;LATIN SMALL LETTER REVERSED E;Ll;0;L;;;;;N;;;;; -0259;LATIN SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;018F;;018F -025A;LATIN SMALL LETTER SCHWA WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCHWA HOOK;;;; -025B;LATIN SMALL LETTER OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER EPSILON;;0190;;0190 -025C;LATIN SMALL LETTER REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON;;A7AB;;A7AB -025D;LATIN SMALL LETTER REVERSED OPEN E WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON HOOK;;;; -025E;LATIN SMALL LETTER CLOSED REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED REVERSED EPSILON;;;; -025F;LATIN SMALL LETTER DOTLESS J WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR;;;; -0260;LATIN SMALL LETTER G WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER G HOOK;;0193;;0193 -0261;LATIN SMALL LETTER SCRIPT G;Ll;0;L;;;;;N;;;A7AC;;A7AC -0262;LATIN LETTER SMALL CAPITAL G;Ll;0;L;;;;;N;;;;; -0263;LATIN SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0194;;0194 -0264;LATIN SMALL LETTER RAMS HORN;Ll;0;L;;;;;N;LATIN SMALL LETTER BABY GAMMA;;;; -0265;LATIN SMALL LETTER TURNED H;Ll;0;L;;;;;N;;;A78D;;A78D -0266;LATIN SMALL LETTER H WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER H HOOK;;A7AA;;A7AA -0267;LATIN SMALL LETTER HENG WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER HENG HOOK;;;; -0268;LATIN SMALL LETTER I WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED I;;0197;;0197 -0269;LATIN SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0196;;0196 -026A;LATIN LETTER SMALL CAPITAL I;Ll;0;L;;;;;N;;;A7AE;;A7AE -026B;LATIN SMALL LETTER L WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;2C62;;2C62 -026C;LATIN SMALL LETTER L WITH BELT;Ll;0;L;;;;;N;LATIN SMALL LETTER L BELT;;A7AD;;A7AD -026D;LATIN SMALL LETTER L WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER L RETROFLEX HOOK;;;; -026E;LATIN SMALL LETTER LEZH;Ll;0;L;;;;;N;LATIN SMALL LETTER L YOGH;;;; -026F;LATIN SMALL LETTER TURNED M;Ll;0;L;;;;;N;;;019C;;019C -0270;LATIN SMALL LETTER TURNED M WITH LONG LEG;Ll;0;L;;;;;N;;;;; -0271;LATIN SMALL LETTER M WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER M HOOK;;2C6E;;2C6E -0272;LATIN SMALL LETTER N WITH LEFT HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N HOOK;;019D;;019D -0273;LATIN SMALL LETTER N WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N RETROFLEX HOOK;;;; -0274;LATIN LETTER SMALL CAPITAL N;Ll;0;L;;;;;N;;;;; -0275;LATIN SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;019F;;019F -0276;LATIN LETTER SMALL CAPITAL OE;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL O E;;;; -0277;LATIN SMALL LETTER CLOSED OMEGA;Ll;0;L;;;;;N;;;;; -0278;LATIN SMALL LETTER PHI;Ll;0;L;;;;;N;;;;; -0279;LATIN SMALL LETTER TURNED R;Ll;0;L;;;;;N;;;;; -027A;LATIN SMALL LETTER TURNED R WITH LONG LEG;Ll;0;L;;;;;N;;;;; -027B;LATIN SMALL LETTER TURNED R WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED R HOOK;;;; -027C;LATIN SMALL LETTER R WITH LONG LEG;Ll;0;L;;;;;N;;;;; -027D;LATIN SMALL LETTER R WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER R HOOK;;2C64;;2C64 -027E;LATIN SMALL LETTER R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER FISHHOOK R;;;; -027F;LATIN SMALL LETTER REVERSED R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED FISHHOOK R;;;; -0280;LATIN LETTER SMALL CAPITAL R;Ll;0;L;;;;;N;;;01A6;;01A6 -0281;LATIN LETTER SMALL CAPITAL INVERTED R;Ll;0;L;;;;;N;;;;; -0282;LATIN SMALL LETTER S WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER S HOOK;;A7C5;;A7C5 -0283;LATIN SMALL LETTER ESH;Ll;0;L;;;;;N;;;01A9;;01A9 -0284;LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR HOOK;;;; -0285;LATIN SMALL LETTER SQUAT REVERSED ESH;Ll;0;L;;;;;N;;;;; -0286;LATIN SMALL LETTER ESH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER ESH CURL;;;; -0287;LATIN SMALL LETTER TURNED T;Ll;0;L;;;;;N;;;A7B1;;A7B1 -0288;LATIN SMALL LETTER T WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T RETROFLEX HOOK;;01AE;;01AE -0289;LATIN SMALL LETTER U BAR;Ll;0;L;;;;;N;;;0244;;0244 -028A;LATIN SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;01B1;;01B1 -028B;LATIN SMALL LETTER V WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT V;;01B2;;01B2 -028C;LATIN SMALL LETTER TURNED V;Ll;0;L;;;;;N;;;0245;;0245 -028D;LATIN SMALL LETTER TURNED W;Ll;0;L;;;;;N;;;;; -028E;LATIN SMALL LETTER TURNED Y;Ll;0;L;;;;;N;;;;; -028F;LATIN LETTER SMALL CAPITAL Y;Ll;0;L;;;;;N;;;;; -0290;LATIN SMALL LETTER Z WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Z RETROFLEX HOOK;;;; -0291;LATIN SMALL LETTER Z WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER Z CURL;;;; -0292;LATIN SMALL LETTER EZH;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH;;01B7;;01B7 -0293;LATIN SMALL LETTER EZH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH CURL;;;; -0294;LATIN LETTER GLOTTAL STOP;Lo;0;L;;;;;N;;;;; -0295;LATIN LETTER PHARYNGEAL VOICED FRICATIVE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP;;;; -0296;LATIN LETTER INVERTED GLOTTAL STOP;Ll;0;L;;;;;N;;;;; -0297;LATIN LETTER STRETCHED C;Ll;0;L;;;;;N;;;;; -0298;LATIN LETTER BILABIAL CLICK;Ll;0;L;;;;;N;LATIN LETTER BULLSEYE;;;; -0299;LATIN LETTER SMALL CAPITAL B;Ll;0;L;;;;;N;;;;; -029A;LATIN SMALL LETTER CLOSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED EPSILON;;;; -029B;LATIN LETTER SMALL CAPITAL G WITH HOOK;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL G HOOK;;;; -029C;LATIN LETTER SMALL CAPITAL H;Ll;0;L;;;;;N;;;;; -029D;LATIN SMALL LETTER J WITH CROSSED-TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER CROSSED-TAIL J;;A7B2;;A7B2 -029E;LATIN SMALL LETTER TURNED K;Ll;0;L;;;;;N;;;A7B0;;A7B0 -029F;LATIN LETTER SMALL CAPITAL L;Ll;0;L;;;;;N;;;;; -02A0;LATIN SMALL LETTER Q WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Q HOOK;;;; -02A1;LATIN LETTER GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER GLOTTAL STOP BAR;;;; -02A2;LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP BAR;;;; -02A3;LATIN SMALL LETTER DZ DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z;;;; -02A4;LATIN SMALL LETTER DEZH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D YOGH;;;; -02A5;LATIN SMALL LETTER DZ DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z CURL;;;; -02A6;LATIN SMALL LETTER TS DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T S;;;; -02A7;LATIN SMALL LETTER TESH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T ESH;;;; -02A8;LATIN SMALL LETTER TC DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER T C CURL;;;; -02A9;LATIN SMALL LETTER FENG DIGRAPH;Ll;0;L;;;;;N;;;;; -02AA;LATIN SMALL LETTER LS DIGRAPH;Ll;0;L;;;;;N;;;;; -02AB;LATIN SMALL LETTER LZ DIGRAPH;Ll;0;L;;;;;N;;;;; -02AC;LATIN LETTER BILABIAL PERCUSSIVE;Ll;0;L;;;;;N;;;;; -02AD;LATIN LETTER BIDENTAL PERCUSSIVE;Ll;0;L;;;;;N;;;;; -02AE;LATIN SMALL LETTER TURNED H WITH FISHHOOK;Ll;0;L;;;;;N;;;;; -02AF;LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL;Ll;0;L;;;;;N;;;;; -02B0;MODIFIER LETTER SMALL H;Lm;0;L;<super> 0068;;;;N;;;;; -02B1;MODIFIER LETTER SMALL H WITH HOOK;Lm;0;L;<super> 0266;;;;N;MODIFIER LETTER SMALL H HOOK;;;; -02B2;MODIFIER LETTER SMALL J;Lm;0;L;<super> 006A;;;;N;;;;; -02B3;MODIFIER LETTER SMALL R;Lm;0;L;<super> 0072;;;;N;;;;; -02B4;MODIFIER LETTER SMALL TURNED R;Lm;0;L;<super> 0279;;;;N;;;;; -02B5;MODIFIER LETTER SMALL TURNED R WITH HOOK;Lm;0;L;<super> 027B;;;;N;MODIFIER LETTER SMALL TURNED R HOOK;;;; -02B6;MODIFIER LETTER SMALL CAPITAL INVERTED R;Lm;0;L;<super> 0281;;;;N;;;;; -02B7;MODIFIER LETTER SMALL W;Lm;0;L;<super> 0077;;;;N;;;;; -02B8;MODIFIER LETTER SMALL Y;Lm;0;L;<super> 0079;;;;N;;;;; -02B9;MODIFIER LETTER PRIME;Lm;0;ON;;;;;N;;;;; -02BA;MODIFIER LETTER DOUBLE PRIME;Lm;0;ON;;;;;N;;;;; -02BB;MODIFIER LETTER TURNED COMMA;Lm;0;L;;;;;N;;;;; -02BC;MODIFIER LETTER APOSTROPHE;Lm;0;L;;;;;N;;;;; -02BD;MODIFIER LETTER REVERSED COMMA;Lm;0;L;;;;;N;;;;; -02BE;MODIFIER LETTER RIGHT HALF RING;Lm;0;L;;;;;N;;;;; -02BF;MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;; -02C0;MODIFIER LETTER GLOTTAL STOP;Lm;0;L;;;;;N;;;;; -02C1;MODIFIER LETTER REVERSED GLOTTAL STOP;Lm;0;L;;;;;N;;;;; -02C2;MODIFIER LETTER LEFT ARROWHEAD;Sk;0;ON;;;;;N;;;;; -02C3;MODIFIER LETTER RIGHT ARROWHEAD;Sk;0;ON;;;;;N;;;;; -02C4;MODIFIER LETTER UP ARROWHEAD;Sk;0;ON;;;;;N;;;;; -02C5;MODIFIER LETTER DOWN ARROWHEAD;Sk;0;ON;;;;;N;;;;; -02C6;MODIFIER LETTER CIRCUMFLEX ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER CIRCUMFLEX;;;; -02C7;CARON;Lm;0;ON;;;;;N;MODIFIER LETTER HACEK;;;; -02C8;MODIFIER LETTER VERTICAL LINE;Lm;0;ON;;;;;N;;;;; -02C9;MODIFIER LETTER MACRON;Lm;0;ON;;;;;N;;;;; -02CA;MODIFIER LETTER ACUTE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER ACUTE;;;; -02CB;MODIFIER LETTER GRAVE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER GRAVE;;;; -02CC;MODIFIER LETTER LOW VERTICAL LINE;Lm;0;ON;;;;;N;;;;; -02CD;MODIFIER LETTER LOW MACRON;Lm;0;ON;;;;;N;;;;; -02CE;MODIFIER LETTER LOW GRAVE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER LOW GRAVE;;;; -02CF;MODIFIER LETTER LOW ACUTE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER LOW ACUTE;;;; -02D0;MODIFIER LETTER TRIANGULAR COLON;Lm;0;L;;;;;N;;;;; -02D1;MODIFIER LETTER HALF TRIANGULAR COLON;Lm;0;L;;;;;N;;;;; -02D2;MODIFIER LETTER CENTRED RIGHT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED RIGHT HALF RING;;;; -02D3;MODIFIER LETTER CENTRED LEFT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED LEFT HALF RING;;;; -02D4;MODIFIER LETTER UP TACK;Sk;0;ON;;;;;N;;;;; -02D5;MODIFIER LETTER DOWN TACK;Sk;0;ON;;;;;N;;;;; -02D6;MODIFIER LETTER PLUS SIGN;Sk;0;ON;;;;;N;;;;; -02D7;MODIFIER LETTER MINUS SIGN;Sk;0;ON;;;;;N;;;;; -02D8;BREVE;Sk;0;ON;<compat> 0020 0306;;;;N;SPACING BREVE;;;; -02D9;DOT ABOVE;Sk;0;ON;<compat> 0020 0307;;;;N;SPACING DOT ABOVE;;;; -02DA;RING ABOVE;Sk;0;ON;<compat> 0020 030A;;;;N;SPACING RING ABOVE;;;; -02DB;OGONEK;Sk;0;ON;<compat> 0020 0328;;;;N;SPACING OGONEK;;;; -02DC;SMALL TILDE;Sk;0;ON;<compat> 0020 0303;;;;N;SPACING TILDE;;;; -02DD;DOUBLE ACUTE ACCENT;Sk;0;ON;<compat> 0020 030B;;;;N;SPACING DOUBLE ACUTE;;;; -02DE;MODIFIER LETTER RHOTIC HOOK;Sk;0;ON;;;;;N;;;;; -02DF;MODIFIER LETTER CROSS ACCENT;Sk;0;ON;;;;;N;;;;; -02E0;MODIFIER LETTER SMALL GAMMA;Lm;0;L;<super> 0263;;;;N;;;;; -02E1;MODIFIER LETTER SMALL L;Lm;0;L;<super> 006C;;;;N;;;;; -02E2;MODIFIER LETTER SMALL S;Lm;0;L;<super> 0073;;;;N;;;;; -02E3;MODIFIER LETTER SMALL X;Lm;0;L;<super> 0078;;;;N;;;;; -02E4;MODIFIER LETTER SMALL REVERSED GLOTTAL STOP;Lm;0;L;<super> 0295;;;;N;;;;; -02E5;MODIFIER LETTER EXTRA-HIGH TONE BAR;Sk;0;ON;;;;;N;;;;; -02E6;MODIFIER LETTER HIGH TONE BAR;Sk;0;ON;;;;;N;;;;; -02E7;MODIFIER LETTER MID TONE BAR;Sk;0;ON;;;;;N;;;;; -02E8;MODIFIER LETTER LOW TONE BAR;Sk;0;ON;;;;;N;;;;; -02E9;MODIFIER LETTER EXTRA-LOW TONE BAR;Sk;0;ON;;;;;N;;;;; -02EA;MODIFIER LETTER YIN DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;; -02EB;MODIFIER LETTER YANG DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;; -02EC;MODIFIER LETTER VOICING;Lm;0;ON;;;;;N;;;;; -02ED;MODIFIER LETTER UNASPIRATED;Sk;0;ON;;;;;N;;;;; -02EE;MODIFIER LETTER DOUBLE APOSTROPHE;Lm;0;L;;;;;N;;;;; -02EF;MODIFIER LETTER LOW DOWN ARROWHEAD;Sk;0;ON;;;;;N;;;;; -02F0;MODIFIER LETTER LOW UP ARROWHEAD;Sk;0;ON;;;;;N;;;;; -02F1;MODIFIER LETTER LOW LEFT ARROWHEAD;Sk;0;ON;;;;;N;;;;; -02F2;MODIFIER LETTER LOW RIGHT ARROWHEAD;Sk;0;ON;;;;;N;;;;; -02F3;MODIFIER LETTER LOW RING;Sk;0;ON;;;;;N;;;;; -02F4;MODIFIER LETTER MIDDLE GRAVE ACCENT;Sk;0;ON;;;;;N;;;;; -02F5;MODIFIER LETTER MIDDLE DOUBLE GRAVE ACCENT;Sk;0;ON;;;;;N;;;;; -02F6;MODIFIER LETTER MIDDLE DOUBLE ACUTE ACCENT;Sk;0;ON;;;;;N;;;;; -02F7;MODIFIER LETTER LOW TILDE;Sk;0;ON;;;;;N;;;;; -02F8;MODIFIER LETTER RAISED COLON;Sk;0;ON;;;;;N;;;;; -02F9;MODIFIER LETTER BEGIN HIGH TONE;Sk;0;ON;;;;;N;;;;; -02FA;MODIFIER LETTER END HIGH TONE;Sk;0;ON;;;;;N;;;;; -02FB;MODIFIER LETTER BEGIN LOW TONE;Sk;0;ON;;;;;N;;;;; -02FC;MODIFIER LETTER END LOW TONE;Sk;0;ON;;;;;N;;;;; -02FD;MODIFIER LETTER SHELF;Sk;0;ON;;;;;N;;;;; -02FE;MODIFIER LETTER OPEN SHELF;Sk;0;ON;;;;;N;;;;; -02FF;MODIFIER LETTER LOW LEFT ARROW;Sk;0;ON;;;;;N;;;;; -0300;COMBINING GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING GRAVE;;;; -0301;COMBINING ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING ACUTE;;;; -0302;COMBINING CIRCUMFLEX ACCENT;Mn;230;NSM;;;;;N;NON-SPACING CIRCUMFLEX;;;; -0303;COMBINING TILDE;Mn;230;NSM;;;;;N;NON-SPACING TILDE;;;; -0304;COMBINING MACRON;Mn;230;NSM;;;;;N;NON-SPACING MACRON;;;; -0305;COMBINING OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING OVERSCORE;;;; -0306;COMBINING BREVE;Mn;230;NSM;;;;;N;NON-SPACING BREVE;;;; -0307;COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOT ABOVE;;;; -0308;COMBINING DIAERESIS;Mn;230;NSM;;;;;N;NON-SPACING DIAERESIS;;;; -0309;COMBINING HOOK ABOVE;Mn;230;NSM;;;;;N;NON-SPACING HOOK ABOVE;;;; -030A;COMBINING RING ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RING ABOVE;;;; -030B;COMBINING DOUBLE ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE ACUTE;;;; -030C;COMBINING CARON;Mn;230;NSM;;;;;N;NON-SPACING HACEK;;;; -030D;COMBINING VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL LINE ABOVE;;;; -030E;COMBINING DOUBLE VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE VERTICAL LINE ABOVE;;;; -030F;COMBINING DOUBLE GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE GRAVE;;;; -0310;COMBINING CANDRABINDU;Mn;230;NSM;;;;;N;NON-SPACING CANDRABINDU;;;; -0311;COMBINING INVERTED BREVE;Mn;230;NSM;;;;;N;NON-SPACING INVERTED BREVE;;;; -0312;COMBINING TURNED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING TURNED COMMA ABOVE;;;; -0313;COMBINING COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING COMMA ABOVE;;;; -0314;COMBINING REVERSED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING REVERSED COMMA ABOVE;;;; -0315;COMBINING COMMA ABOVE RIGHT;Mn;232;NSM;;;;;N;NON-SPACING COMMA ABOVE RIGHT;;;; -0316;COMBINING GRAVE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING GRAVE BELOW;;;; -0317;COMBINING ACUTE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING ACUTE BELOW;;;; -0318;COMBINING LEFT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT TACK BELOW;;;; -0319;COMBINING RIGHT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT TACK BELOW;;;; -031A;COMBINING LEFT ANGLE ABOVE;Mn;232;NSM;;;;;N;NON-SPACING LEFT ANGLE ABOVE;;;; -031B;COMBINING HORN;Mn;216;NSM;;;;;N;NON-SPACING HORN;;;; -031C;COMBINING LEFT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT HALF RING BELOW;;;; -031D;COMBINING UP TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING UP TACK BELOW;;;; -031E;COMBINING DOWN TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOWN TACK BELOW;;;; -031F;COMBINING PLUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING PLUS SIGN BELOW;;;; -0320;COMBINING MINUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING MINUS SIGN BELOW;;;; -0321;COMBINING PALATALIZED HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING PALATALIZED HOOK BELOW;;;; -0322;COMBINING RETROFLEX HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING RETROFLEX HOOK BELOW;;;; -0323;COMBINING DOT BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOT BELOW;;;; -0324;COMBINING DIAERESIS BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE DOT BELOW;;;; -0325;COMBINING RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RING BELOW;;;; -0326;COMBINING COMMA BELOW;Mn;220;NSM;;;;;N;NON-SPACING COMMA BELOW;;;; -0327;COMBINING CEDILLA;Mn;202;NSM;;;;;N;NON-SPACING CEDILLA;;;; -0328;COMBINING OGONEK;Mn;202;NSM;;;;;N;NON-SPACING OGONEK;;;; -0329;COMBINING VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;NON-SPACING VERTICAL LINE BELOW;;;; -032A;COMBINING BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BRIDGE BELOW;;;; -032B;COMBINING INVERTED DOUBLE ARCH BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED DOUBLE ARCH BELOW;;;; -032C;COMBINING CARON BELOW;Mn;220;NSM;;;;;N;NON-SPACING HACEK BELOW;;;; -032D;COMBINING CIRCUMFLEX ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING CIRCUMFLEX BELOW;;;; -032E;COMBINING BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BREVE BELOW;;;; -032F;COMBINING INVERTED BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BREVE BELOW;;;; -0330;COMBINING TILDE BELOW;Mn;220;NSM;;;;;N;NON-SPACING TILDE BELOW;;;; -0331;COMBINING MACRON BELOW;Mn;220;NSM;;;;;N;NON-SPACING MACRON BELOW;;;; -0332;COMBINING LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING UNDERSCORE;;;; -0333;COMBINING DOUBLE LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE UNDERSCORE;;;; -0334;COMBINING TILDE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING TILDE OVERLAY;;;; -0335;COMBINING SHORT STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT BAR OVERLAY;;;; -0336;COMBINING LONG STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG BAR OVERLAY;;;; -0337;COMBINING SHORT SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT SLASH OVERLAY;;;; -0338;COMBINING LONG SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG SLASH OVERLAY;;;; -0339;COMBINING RIGHT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT HALF RING BELOW;;;; -033A;COMBINING INVERTED BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BRIDGE BELOW;;;; -033B;COMBINING SQUARE BELOW;Mn;220;NSM;;;;;N;NON-SPACING SQUARE BELOW;;;; -033C;COMBINING SEAGULL BELOW;Mn;220;NSM;;;;;N;NON-SPACING SEAGULL BELOW;;;; -033D;COMBINING X ABOVE;Mn;230;NSM;;;;;N;NON-SPACING X ABOVE;;;; -033E;COMBINING VERTICAL TILDE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL TILDE;;;; -033F;COMBINING DOUBLE OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE OVERSCORE;;;; -0340;COMBINING GRAVE TONE MARK;Mn;230;NSM;0300;;;;N;NON-SPACING GRAVE TONE MARK;;;; -0341;COMBINING ACUTE TONE MARK;Mn;230;NSM;0301;;;;N;NON-SPACING ACUTE TONE MARK;;;; -0342;COMBINING GREEK PERISPOMENI;Mn;230;NSM;;;;;N;;;;; -0343;COMBINING GREEK KORONIS;Mn;230;NSM;0313;;;;N;;;;; -0344;COMBINING GREEK DIALYTIKA TONOS;Mn;230;NSM;0308 0301;;;;N;GREEK NON-SPACING DIAERESIS TONOS;;;; -0345;COMBINING GREEK YPOGEGRAMMENI;Mn;240;NSM;;;;;N;GREEK NON-SPACING IOTA BELOW;;0399;;0399 -0346;COMBINING BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;; -0347;COMBINING EQUALS SIGN BELOW;Mn;220;NSM;;;;;N;;;;; -0348;COMBINING DOUBLE VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;;;;; -0349;COMBINING LEFT ANGLE BELOW;Mn;220;NSM;;;;;N;;;;; -034A;COMBINING NOT TILDE ABOVE;Mn;230;NSM;;;;;N;;;;; -034B;COMBINING HOMOTHETIC ABOVE;Mn;230;NSM;;;;;N;;;;; -034C;COMBINING ALMOST EQUAL TO ABOVE;Mn;230;NSM;;;;;N;;;;; -034D;COMBINING LEFT RIGHT ARROW BELOW;Mn;220;NSM;;;;;N;;;;; -034E;COMBINING UPWARDS ARROW BELOW;Mn;220;NSM;;;;;N;;;;; -034F;COMBINING GRAPHEME JOINER;Mn;0;NSM;;;;;N;;;;; -0350;COMBINING RIGHT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;; -0351;COMBINING LEFT HALF RING ABOVE;Mn;230;NSM;;;;;N;;;;; -0352;COMBINING FERMATA;Mn;230;NSM;;;;;N;;;;; -0353;COMBINING X BELOW;Mn;220;NSM;;;;;N;;;;; -0354;COMBINING LEFT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; -0355;COMBINING RIGHT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; -0356;COMBINING RIGHT ARROWHEAD AND UP ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; -0357;COMBINING RIGHT HALF RING ABOVE;Mn;230;NSM;;;;;N;;;;; -0358;COMBINING DOT ABOVE RIGHT;Mn;232;NSM;;;;;N;;;;; -0359;COMBINING ASTERISK BELOW;Mn;220;NSM;;;;;N;;;;; -035A;COMBINING DOUBLE RING BELOW;Mn;220;NSM;;;;;N;;;;; -035B;COMBINING ZIGZAG ABOVE;Mn;230;NSM;;;;;N;;;;; -035C;COMBINING DOUBLE BREVE BELOW;Mn;233;NSM;;;;;N;;;;; -035D;COMBINING DOUBLE BREVE;Mn;234;NSM;;;;;N;;;;; -035E;COMBINING DOUBLE MACRON;Mn;234;NSM;;;;;N;;;;; -035F;COMBINING DOUBLE MACRON BELOW;Mn;233;NSM;;;;;N;;;;; -0360;COMBINING DOUBLE TILDE;Mn;234;NSM;;;;;N;;;;; -0361;COMBINING DOUBLE INVERTED BREVE;Mn;234;NSM;;;;;N;;;;; -0362;COMBINING DOUBLE RIGHTWARDS ARROW BELOW;Mn;233;NSM;;;;;N;;;;; -0363;COMBINING LATIN SMALL LETTER A;Mn;230;NSM;;;;;N;;;;; -0364;COMBINING LATIN SMALL LETTER E;Mn;230;NSM;;;;;N;;;;; -0365;COMBINING LATIN SMALL LETTER I;Mn;230;NSM;;;;;N;;;;; -0366;COMBINING LATIN SMALL LETTER O;Mn;230;NSM;;;;;N;;;;; -0367;COMBINING LATIN SMALL LETTER U;Mn;230;NSM;;;;;N;;;;; -0368;COMBINING LATIN SMALL LETTER C;Mn;230;NSM;;;;;N;;;;; -0369;COMBINING LATIN SMALL LETTER D;Mn;230;NSM;;;;;N;;;;; -036A;COMBINING LATIN SMALL LETTER H;Mn;230;NSM;;;;;N;;;;; -036B;COMBINING LATIN SMALL LETTER M;Mn;230;NSM;;;;;N;;;;; -036C;COMBINING LATIN SMALL LETTER R;Mn;230;NSM;;;;;N;;;;; -036D;COMBINING LATIN SMALL LETTER T;Mn;230;NSM;;;;;N;;;;; -036E;COMBINING LATIN SMALL LETTER V;Mn;230;NSM;;;;;N;;;;; -036F;COMBINING LATIN SMALL LETTER X;Mn;230;NSM;;;;;N;;;;; -0370;GREEK CAPITAL LETTER HETA;Lu;0;L;;;;;N;;;;0371; -0371;GREEK SMALL LETTER HETA;Ll;0;L;;;;;N;;;0370;;0370 -0372;GREEK CAPITAL LETTER ARCHAIC SAMPI;Lu;0;L;;;;;N;;;;0373; -0373;GREEK SMALL LETTER ARCHAIC SAMPI;Ll;0;L;;;;;N;;;0372;;0372 -0374;GREEK NUMERAL SIGN;Lm;0;ON;02B9;;;;N;GREEK UPPER NUMERAL SIGN;;;; -0375;GREEK LOWER NUMERAL SIGN;Sk;0;ON;;;;;N;;;;; -0376;GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA;Lu;0;L;;;;;N;;;;0377; -0377;GREEK SMALL LETTER PAMPHYLIAN DIGAMMA;Ll;0;L;;;;;N;;;0376;;0376 -037A;GREEK YPOGEGRAMMENI;Lm;0;L;<compat> 0020 0345;;;;N;GREEK SPACING IOTA BELOW;;;; -037B;GREEK SMALL REVERSED LUNATE SIGMA SYMBOL;Ll;0;L;;;;;N;;;03FD;;03FD -037C;GREEK SMALL DOTTED LUNATE SIGMA SYMBOL;Ll;0;L;;;;;N;;;03FE;;03FE -037D;GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL;Ll;0;L;;;;;N;;;03FF;;03FF -037E;GREEK QUESTION MARK;Po;0;ON;003B;;;;N;;;;; -037F;GREEK CAPITAL LETTER YOT;Lu;0;L;;;;;N;;;;03F3; -0384;GREEK TONOS;Sk;0;ON;<compat> 0020 0301;;;;N;GREEK SPACING TONOS;;;; -0385;GREEK DIALYTIKA TONOS;Sk;0;ON;00A8 0301;;;;N;GREEK SPACING DIAERESIS TONOS;;;; -0386;GREEK CAPITAL LETTER ALPHA WITH TONOS;Lu;0;L;0391 0301;;;;N;GREEK CAPITAL LETTER ALPHA TONOS;;;03AC; -0387;GREEK ANO TELEIA;Po;0;ON;00B7;;;;N;;;;; -0388;GREEK CAPITAL LETTER EPSILON WITH TONOS;Lu;0;L;0395 0301;;;;N;GREEK CAPITAL LETTER EPSILON TONOS;;;03AD; -0389;GREEK CAPITAL LETTER ETA WITH TONOS;Lu;0;L;0397 0301;;;;N;GREEK CAPITAL LETTER ETA TONOS;;;03AE; -038A;GREEK CAPITAL LETTER IOTA WITH TONOS;Lu;0;L;0399 0301;;;;N;GREEK CAPITAL LETTER IOTA TONOS;;;03AF; -038C;GREEK CAPITAL LETTER OMICRON WITH TONOS;Lu;0;L;039F 0301;;;;N;GREEK CAPITAL LETTER OMICRON TONOS;;;03CC; -038E;GREEK CAPITAL LETTER UPSILON WITH TONOS;Lu;0;L;03A5 0301;;;;N;GREEK CAPITAL LETTER UPSILON TONOS;;;03CD; -038F;GREEK CAPITAL LETTER OMEGA WITH TONOS;Lu;0;L;03A9 0301;;;;N;GREEK CAPITAL LETTER OMEGA TONOS;;;03CE; -0390;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS;Ll;0;L;03CA 0301;;;;N;GREEK SMALL LETTER IOTA DIAERESIS TONOS;;;; -0391;GREEK CAPITAL LETTER ALPHA;Lu;0;L;;;;;N;;;;03B1; -0392;GREEK CAPITAL LETTER BETA;Lu;0;L;;;;;N;;;;03B2; -0393;GREEK CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;03B3; -0394;GREEK CAPITAL LETTER DELTA;Lu;0;L;;;;;N;;;;03B4; -0395;GREEK CAPITAL LETTER EPSILON;Lu;0;L;;;;;N;;;;03B5; -0396;GREEK CAPITAL LETTER ZETA;Lu;0;L;;;;;N;;;;03B6; -0397;GREEK CAPITAL LETTER ETA;Lu;0;L;;;;;N;;;;03B7; -0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8; -0399;GREEK CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;03B9; -039A;GREEK CAPITAL LETTER KAPPA;Lu;0;L;;;;;N;;;;03BA; -039B;GREEK CAPITAL LETTER LAMDA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER LAMBDA;;;03BB; -039C;GREEK CAPITAL LETTER MU;Lu;0;L;;;;;N;;;;03BC; -039D;GREEK CAPITAL LETTER NU;Lu;0;L;;;;;N;;;;03BD; -039E;GREEK CAPITAL LETTER XI;Lu;0;L;;;;;N;;;;03BE; -039F;GREEK CAPITAL LETTER OMICRON;Lu;0;L;;;;;N;;;;03BF; -03A0;GREEK CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;03C0; -03A1;GREEK CAPITAL LETTER RHO;Lu;0;L;;;;;N;;;;03C1; -03A3;GREEK CAPITAL LETTER SIGMA;Lu;0;L;;;;;N;;;;03C3; -03A4;GREEK CAPITAL LETTER TAU;Lu;0;L;;;;;N;;;;03C4; -03A5;GREEK CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;03C5; -03A6;GREEK CAPITAL LETTER PHI;Lu;0;L;;;;;N;;;;03C6; -03A7;GREEK CAPITAL LETTER CHI;Lu;0;L;;;;;N;;;;03C7; -03A8;GREEK CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;03C8; -03A9;GREEK CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;03C9; -03AA;GREEK CAPITAL LETTER IOTA WITH DIALYTIKA;Lu;0;L;0399 0308;;;;N;GREEK CAPITAL LETTER IOTA DIAERESIS;;;03CA; -03AB;GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA;Lu;0;L;03A5 0308;;;;N;GREEK CAPITAL LETTER UPSILON DIAERESIS;;;03CB; -03AC;GREEK SMALL LETTER ALPHA WITH TONOS;Ll;0;L;03B1 0301;;;;N;GREEK SMALL LETTER ALPHA TONOS;;0386;;0386 -03AD;GREEK SMALL LETTER EPSILON WITH TONOS;Ll;0;L;03B5 0301;;;;N;GREEK SMALL LETTER EPSILON TONOS;;0388;;0388 -03AE;GREEK SMALL LETTER ETA WITH TONOS;Ll;0;L;03B7 0301;;;;N;GREEK SMALL LETTER ETA TONOS;;0389;;0389 -03AF;GREEK SMALL LETTER IOTA WITH TONOS;Ll;0;L;03B9 0301;;;;N;GREEK SMALL LETTER IOTA TONOS;;038A;;038A -03B0;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS;Ll;0;L;03CB 0301;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS TONOS;;;; -03B1;GREEK SMALL LETTER ALPHA;Ll;0;L;;;;;N;;;0391;;0391 -03B2;GREEK SMALL LETTER BETA;Ll;0;L;;;;;N;;;0392;;0392 -03B3;GREEK SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0393;;0393 -03B4;GREEK SMALL LETTER DELTA;Ll;0;L;;;;;N;;;0394;;0394 -03B5;GREEK SMALL LETTER EPSILON;Ll;0;L;;;;;N;;;0395;;0395 -03B6;GREEK SMALL LETTER ZETA;Ll;0;L;;;;;N;;;0396;;0396 -03B7;GREEK SMALL LETTER ETA;Ll;0;L;;;;;N;;;0397;;0397 -03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398 -03B9;GREEK SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0399;;0399 -03BA;GREEK SMALL LETTER KAPPA;Ll;0;L;;;;;N;;;039A;;039A -03BB;GREEK SMALL LETTER LAMDA;Ll;0;L;;;;;N;GREEK SMALL LETTER LAMBDA;;039B;;039B -03BC;GREEK SMALL LETTER MU;Ll;0;L;;;;;N;;;039C;;039C -03BD;GREEK SMALL LETTER NU;Ll;0;L;;;;;N;;;039D;;039D -03BE;GREEK SMALL LETTER XI;Ll;0;L;;;;;N;;;039E;;039E -03BF;GREEK SMALL LETTER OMICRON;Ll;0;L;;;;;N;;;039F;;039F -03C0;GREEK SMALL LETTER PI;Ll;0;L;;;;;N;;;03A0;;03A0 -03C1;GREEK SMALL LETTER RHO;Ll;0;L;;;;;N;;;03A1;;03A1 -03C2;GREEK SMALL LETTER FINAL SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3 -03C3;GREEK SMALL LETTER SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3 -03C4;GREEK SMALL LETTER TAU;Ll;0;L;;;;;N;;;03A4;;03A4 -03C5;GREEK SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;03A5;;03A5 -03C6;GREEK SMALL LETTER PHI;Ll;0;L;;;;;N;;;03A6;;03A6 -03C7;GREEK SMALL LETTER CHI;Ll;0;L;;;;;N;;;03A7;;03A7 -03C8;GREEK SMALL LETTER PSI;Ll;0;L;;;;;N;;;03A8;;03A8 -03C9;GREEK SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;03A9;;03A9 -03CA;GREEK SMALL LETTER IOTA WITH DIALYTIKA;Ll;0;L;03B9 0308;;;;N;GREEK SMALL LETTER IOTA DIAERESIS;;03AA;;03AA -03CB;GREEK SMALL LETTER UPSILON WITH DIALYTIKA;Ll;0;L;03C5 0308;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS;;03AB;;03AB -03CC;GREEK SMALL LETTER OMICRON WITH TONOS;Ll;0;L;03BF 0301;;;;N;GREEK SMALL LETTER OMICRON TONOS;;038C;;038C -03CD;GREEK SMALL LETTER UPSILON WITH TONOS;Ll;0;L;03C5 0301;;;;N;GREEK SMALL LETTER UPSILON TONOS;;038E;;038E -03CE;GREEK SMALL LETTER OMEGA WITH TONOS;Ll;0;L;03C9 0301;;;;N;GREEK SMALL LETTER OMEGA TONOS;;038F;;038F -03CF;GREEK CAPITAL KAI SYMBOL;Lu;0;L;;;;;N;;;;03D7; -03D0;GREEK BETA SYMBOL;Ll;0;L;<compat> 03B2;;;;N;GREEK SMALL LETTER CURLED BETA;;0392;;0392 -03D1;GREEK THETA SYMBOL;Ll;0;L;<compat> 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398 -03D2;GREEK UPSILON WITH HOOK SYMBOL;Lu;0;L;<compat> 03A5;;;;N;GREEK CAPITAL LETTER UPSILON HOOK;;;; -03D3;GREEK UPSILON WITH ACUTE AND HOOK SYMBOL;Lu;0;L;03D2 0301;;;;N;GREEK CAPITAL LETTER UPSILON HOOK TONOS;;;; -03D4;GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL;Lu;0;L;03D2 0308;;;;N;GREEK CAPITAL LETTER UPSILON HOOK DIAERESIS;;;; -03D5;GREEK PHI SYMBOL;Ll;0;L;<compat> 03C6;;;;N;GREEK SMALL LETTER SCRIPT PHI;;03A6;;03A6 -03D6;GREEK PI SYMBOL;Ll;0;L;<compat> 03C0;;;;N;GREEK SMALL LETTER OMEGA PI;;03A0;;03A0 -03D7;GREEK KAI SYMBOL;Ll;0;L;;;;;N;;;03CF;;03CF -03D8;GREEK LETTER ARCHAIC KOPPA;Lu;0;L;;;;;N;;;;03D9; -03D9;GREEK SMALL LETTER ARCHAIC KOPPA;Ll;0;L;;;;;N;;;03D8;;03D8 -03DA;GREEK LETTER STIGMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER STIGMA;;;03DB; -03DB;GREEK SMALL LETTER STIGMA;Ll;0;L;;;;;N;;;03DA;;03DA -03DC;GREEK LETTER DIGAMMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DIGAMMA;;;03DD; -03DD;GREEK SMALL LETTER DIGAMMA;Ll;0;L;;;;;N;;;03DC;;03DC -03DE;GREEK LETTER KOPPA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KOPPA;;;03DF; -03DF;GREEK SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;03DE;;03DE -03E0;GREEK LETTER SAMPI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SAMPI;;;03E1; -03E1;GREEK SMALL LETTER SAMPI;Ll;0;L;;;;;N;;;03E0;;03E0 -03E2;COPTIC CAPITAL LETTER SHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHEI;;;03E3; -03E3;COPTIC SMALL LETTER SHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER SHEI;;03E2;;03E2 -03E4;COPTIC CAPITAL LETTER FEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER FEI;;;03E5; -03E5;COPTIC SMALL LETTER FEI;Ll;0;L;;;;;N;GREEK SMALL LETTER FEI;;03E4;;03E4 -03E6;COPTIC CAPITAL LETTER KHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KHEI;;;03E7; -03E7;COPTIC SMALL LETTER KHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER KHEI;;03E6;;03E6 -03E8;COPTIC CAPITAL LETTER HORI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER HORI;;;03E9; -03E9;COPTIC SMALL LETTER HORI;Ll;0;L;;;;;N;GREEK SMALL LETTER HORI;;03E8;;03E8 -03EA;COPTIC CAPITAL LETTER GANGIA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER GANGIA;;;03EB; -03EB;COPTIC SMALL LETTER GANGIA;Ll;0;L;;;;;N;GREEK SMALL LETTER GANGIA;;03EA;;03EA -03EC;COPTIC CAPITAL LETTER SHIMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHIMA;;;03ED; -03ED;COPTIC SMALL LETTER SHIMA;Ll;0;L;;;;;N;GREEK SMALL LETTER SHIMA;;03EC;;03EC -03EE;COPTIC CAPITAL LETTER DEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DEI;;;03EF; -03EF;COPTIC SMALL LETTER DEI;Ll;0;L;;;;;N;GREEK SMALL LETTER DEI;;03EE;;03EE -03F0;GREEK KAPPA SYMBOL;Ll;0;L;<compat> 03BA;;;;N;GREEK SMALL LETTER SCRIPT KAPPA;;039A;;039A -03F1;GREEK RHO SYMBOL;Ll;0;L;<compat> 03C1;;;;N;GREEK SMALL LETTER TAILED RHO;;03A1;;03A1 -03F2;GREEK LUNATE SIGMA SYMBOL;Ll;0;L;<compat> 03C2;;;;N;GREEK SMALL LETTER LUNATE SIGMA;;03F9;;03F9 -03F3;GREEK LETTER YOT;Ll;0;L;;;;;N;;;037F;;037F -03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L;<compat> 0398;;;;N;;;;03B8; -03F5;GREEK LUNATE EPSILON SYMBOL;Ll;0;L;<compat> 03B5;;;;N;;;0395;;0395 -03F6;GREEK REVERSED LUNATE EPSILON SYMBOL;Sm;0;ON;;;;;N;;;;; -03F7;GREEK CAPITAL LETTER SHO;Lu;0;L;;;;;N;;;;03F8; -03F8;GREEK SMALL LETTER SHO;Ll;0;L;;;;;N;;;03F7;;03F7 -03F9;GREEK CAPITAL LUNATE SIGMA SYMBOL;Lu;0;L;<compat> 03A3;;;;N;;;;03F2; -03FA;GREEK CAPITAL LETTER SAN;Lu;0;L;;;;;N;;;;03FB; -03FB;GREEK SMALL LETTER SAN;Ll;0;L;;;;;N;;;03FA;;03FA -03FC;GREEK RHO WITH STROKE SYMBOL;Ll;0;L;;;;;N;;;;; -03FD;GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;037B; -03FE;GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;037C; -03FF;GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;037D; -0400;CYRILLIC CAPITAL LETTER IE WITH GRAVE;Lu;0;L;0415 0300;;;;N;;;;0450; -0401;CYRILLIC CAPITAL LETTER IO;Lu;0;L;0415 0308;;;;N;;;;0451; -0402;CYRILLIC CAPITAL LETTER DJE;Lu;0;L;;;;;N;;;;0452; -0403;CYRILLIC CAPITAL LETTER GJE;Lu;0;L;0413 0301;;;;N;;;;0453; -0404;CYRILLIC CAPITAL LETTER UKRAINIAN IE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER E;;;0454; -0405;CYRILLIC CAPITAL LETTER DZE;Lu;0;L;;;;;N;;;;0455; -0406;CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER I;;;0456; -0407;CYRILLIC CAPITAL LETTER YI;Lu;0;L;0406 0308;;;;N;;;;0457; -0408;CYRILLIC CAPITAL LETTER JE;Lu;0;L;;;;;N;;;;0458; -0409;CYRILLIC CAPITAL LETTER LJE;Lu;0;L;;;;;N;;;;0459; -040A;CYRILLIC CAPITAL LETTER NJE;Lu;0;L;;;;;N;;;;045A; -040B;CYRILLIC CAPITAL LETTER TSHE;Lu;0;L;;;;;N;;;;045B; -040C;CYRILLIC CAPITAL LETTER KJE;Lu;0;L;041A 0301;;;;N;;;;045C; -040D;CYRILLIC CAPITAL LETTER I WITH GRAVE;Lu;0;L;0418 0300;;;;N;;;;045D; -040E;CYRILLIC CAPITAL LETTER SHORT U;Lu;0;L;0423 0306;;;;N;;;;045E; -040F;CYRILLIC CAPITAL LETTER DZHE;Lu;0;L;;;;;N;;;;045F; -0410;CYRILLIC CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0430; -0411;CYRILLIC CAPITAL LETTER BE;Lu;0;L;;;;;N;;;;0431; -0412;CYRILLIC CAPITAL LETTER VE;Lu;0;L;;;;;N;;;;0432; -0413;CYRILLIC CAPITAL LETTER GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE;;;0433; -0414;CYRILLIC CAPITAL LETTER DE;Lu;0;L;;;;;N;;;;0434; -0415;CYRILLIC CAPITAL LETTER IE;Lu;0;L;;;;;N;;;;0435; -0416;CYRILLIC CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;0436; -0417;CYRILLIC CAPITAL LETTER ZE;Lu;0;L;;;;;N;;;;0437; -0418;CYRILLIC CAPITAL LETTER I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER II;;;0438; -0419;CYRILLIC CAPITAL LETTER SHORT I;Lu;0;L;0418 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT II;;;0439; -041A;CYRILLIC CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;043A; -041B;CYRILLIC CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;043B; -041C;CYRILLIC CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;043C; -041D;CYRILLIC CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;043D; -041E;CYRILLIC CAPITAL LETTER O;Lu;0;L;;;;;N;;;;043E; -041F;CYRILLIC CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;043F; -0420;CYRILLIC CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;0440; -0421;CYRILLIC CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;0441; -0422;CYRILLIC CAPITAL LETTER TE;Lu;0;L;;;;;N;;;;0442; -0423;CYRILLIC CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0443; -0424;CYRILLIC CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;0444; -0425;CYRILLIC CAPITAL LETTER HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA;;;0445; -0426;CYRILLIC CAPITAL LETTER TSE;Lu;0;L;;;;;N;;;;0446; -0427;CYRILLIC CAPITAL LETTER CHE;Lu;0;L;;;;;N;;;;0447; -0428;CYRILLIC CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0448; -0429;CYRILLIC CAPITAL LETTER SHCHA;Lu;0;L;;;;;N;;;;0449; -042A;CYRILLIC CAPITAL LETTER HARD SIGN;Lu;0;L;;;;;N;;;;044A; -042B;CYRILLIC CAPITAL LETTER YERU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER YERI;;;044B; -042C;CYRILLIC CAPITAL LETTER SOFT SIGN;Lu;0;L;;;;;N;;;;044C; -042D;CYRILLIC CAPITAL LETTER E;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED E;;;044D; -042E;CYRILLIC CAPITAL LETTER YU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IU;;;044E; -042F;CYRILLIC CAPITAL LETTER YA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IA;;;044F; -0430;CYRILLIC SMALL LETTER A;Ll;0;L;;;;;N;;;0410;;0410 -0431;CYRILLIC SMALL LETTER BE;Ll;0;L;;;;;N;;;0411;;0411 -0432;CYRILLIC SMALL LETTER VE;Ll;0;L;;;;;N;;;0412;;0412 -0433;CYRILLIC SMALL LETTER GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE;;0413;;0413 -0434;CYRILLIC SMALL LETTER DE;Ll;0;L;;;;;N;;;0414;;0414 -0435;CYRILLIC SMALL LETTER IE;Ll;0;L;;;;;N;;;0415;;0415 -0436;CYRILLIC SMALL LETTER ZHE;Ll;0;L;;;;;N;;;0416;;0416 -0437;CYRILLIC SMALL LETTER ZE;Ll;0;L;;;;;N;;;0417;;0417 -0438;CYRILLIC SMALL LETTER I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER II;;0418;;0418 -0439;CYRILLIC SMALL LETTER SHORT I;Ll;0;L;0438 0306;;;;N;CYRILLIC SMALL LETTER SHORT II;;0419;;0419 -043A;CYRILLIC SMALL LETTER KA;Ll;0;L;;;;;N;;;041A;;041A -043B;CYRILLIC SMALL LETTER EL;Ll;0;L;;;;;N;;;041B;;041B -043C;CYRILLIC SMALL LETTER EM;Ll;0;L;;;;;N;;;041C;;041C -043D;CYRILLIC SMALL LETTER EN;Ll;0;L;;;;;N;;;041D;;041D -043E;CYRILLIC SMALL LETTER O;Ll;0;L;;;;;N;;;041E;;041E -043F;CYRILLIC SMALL LETTER PE;Ll;0;L;;;;;N;;;041F;;041F -0440;CYRILLIC SMALL LETTER ER;Ll;0;L;;;;;N;;;0420;;0420 -0441;CYRILLIC SMALL LETTER ES;Ll;0;L;;;;;N;;;0421;;0421 -0442;CYRILLIC SMALL LETTER TE;Ll;0;L;;;;;N;;;0422;;0422 -0443;CYRILLIC SMALL LETTER U;Ll;0;L;;;;;N;;;0423;;0423 -0444;CYRILLIC SMALL LETTER EF;Ll;0;L;;;;;N;;;0424;;0424 -0445;CYRILLIC SMALL LETTER HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA;;0425;;0425 -0446;CYRILLIC SMALL LETTER TSE;Ll;0;L;;;;;N;;;0426;;0426 -0447;CYRILLIC SMALL LETTER CHE;Ll;0;L;;;;;N;;;0427;;0427 -0448;CYRILLIC SMALL LETTER SHA;Ll;0;L;;;;;N;;;0428;;0428 -0449;CYRILLIC SMALL LETTER SHCHA;Ll;0;L;;;;;N;;;0429;;0429 -044A;CYRILLIC SMALL LETTER HARD SIGN;Ll;0;L;;;;;N;;;042A;;042A -044B;CYRILLIC SMALL LETTER YERU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER YERI;;042B;;042B -044C;CYRILLIC SMALL LETTER SOFT SIGN;Ll;0;L;;;;;N;;;042C;;042C -044D;CYRILLIC SMALL LETTER E;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED E;;042D;;042D -044E;CYRILLIC SMALL LETTER YU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IU;;042E;;042E -044F;CYRILLIC SMALL LETTER YA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IA;;042F;;042F -0450;CYRILLIC SMALL LETTER IE WITH GRAVE;Ll;0;L;0435 0300;;;;N;;;0400;;0400 -0451;CYRILLIC SMALL LETTER IO;Ll;0;L;0435 0308;;;;N;;;0401;;0401 -0452;CYRILLIC SMALL LETTER DJE;Ll;0;L;;;;;N;;;0402;;0402 -0453;CYRILLIC SMALL LETTER GJE;Ll;0;L;0433 0301;;;;N;;;0403;;0403 -0454;CYRILLIC SMALL LETTER UKRAINIAN IE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER E;;0404;;0404 -0455;CYRILLIC SMALL LETTER DZE;Ll;0;L;;;;;N;;;0405;;0405 -0456;CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER I;;0406;;0406 -0457;CYRILLIC SMALL LETTER YI;Ll;0;L;0456 0308;;;;N;;;0407;;0407 -0458;CYRILLIC SMALL LETTER JE;Ll;0;L;;;;;N;;;0408;;0408 -0459;CYRILLIC SMALL LETTER LJE;Ll;0;L;;;;;N;;;0409;;0409 -045A;CYRILLIC SMALL LETTER NJE;Ll;0;L;;;;;N;;;040A;;040A -045B;CYRILLIC SMALL LETTER TSHE;Ll;0;L;;;;;N;;;040B;;040B -045C;CYRILLIC SMALL LETTER KJE;Ll;0;L;043A 0301;;;;N;;;040C;;040C -045D;CYRILLIC SMALL LETTER I WITH GRAVE;Ll;0;L;0438 0300;;;;N;;;040D;;040D -045E;CYRILLIC SMALL LETTER SHORT U;Ll;0;L;0443 0306;;;;N;;;040E;;040E -045F;CYRILLIC SMALL LETTER DZHE;Ll;0;L;;;;;N;;;040F;;040F -0460;CYRILLIC CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;0461; -0461;CYRILLIC SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;0460;;0460 -0462;CYRILLIC CAPITAL LETTER YAT;Lu;0;L;;;;;N;;;;0463; -0463;CYRILLIC SMALL LETTER YAT;Ll;0;L;;;;;N;;;0462;;0462 -0464;CYRILLIC CAPITAL LETTER IOTIFIED E;Lu;0;L;;;;;N;;;;0465; -0465;CYRILLIC SMALL LETTER IOTIFIED E;Ll;0;L;;;;;N;;;0464;;0464 -0466;CYRILLIC CAPITAL LETTER LITTLE YUS;Lu;0;L;;;;;N;;;;0467; -0467;CYRILLIC SMALL LETTER LITTLE YUS;Ll;0;L;;;;;N;;;0466;;0466 -0468;CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS;Lu;0;L;;;;;N;;;;0469; -0469;CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS;Ll;0;L;;;;;N;;;0468;;0468 -046A;CYRILLIC CAPITAL LETTER BIG YUS;Lu;0;L;;;;;N;;;;046B; -046B;CYRILLIC SMALL LETTER BIG YUS;Ll;0;L;;;;;N;;;046A;;046A -046C;CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS;Lu;0;L;;;;;N;;;;046D; -046D;CYRILLIC SMALL LETTER IOTIFIED BIG YUS;Ll;0;L;;;;;N;;;046C;;046C -046E;CYRILLIC CAPITAL LETTER KSI;Lu;0;L;;;;;N;;;;046F; -046F;CYRILLIC SMALL LETTER KSI;Ll;0;L;;;;;N;;;046E;;046E -0470;CYRILLIC CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;0471; -0471;CYRILLIC SMALL LETTER PSI;Ll;0;L;;;;;N;;;0470;;0470 -0472;CYRILLIC CAPITAL LETTER FITA;Lu;0;L;;;;;N;;;;0473; -0473;CYRILLIC SMALL LETTER FITA;Ll;0;L;;;;;N;;;0472;;0472 -0474;CYRILLIC CAPITAL LETTER IZHITSA;Lu;0;L;;;;;N;;;;0475; -0475;CYRILLIC SMALL LETTER IZHITSA;Ll;0;L;;;;;N;;;0474;;0474 -0476;CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Lu;0;L;0474 030F;;;;N;CYRILLIC CAPITAL LETTER IZHITSA DOUBLE GRAVE;;;0477; -0477;CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Ll;0;L;0475 030F;;;;N;CYRILLIC SMALL LETTER IZHITSA DOUBLE GRAVE;;0476;;0476 -0478;CYRILLIC CAPITAL LETTER UK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER UK DIGRAPH;;;0479; -0479;CYRILLIC SMALL LETTER UK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER UK DIGRAPH;;0478;;0478 -047A;CYRILLIC CAPITAL LETTER ROUND OMEGA;Lu;0;L;;;;;N;;;;047B; -047B;CYRILLIC SMALL LETTER ROUND OMEGA;Ll;0;L;;;;;N;;;047A;;047A -047C;CYRILLIC CAPITAL LETTER OMEGA WITH TITLO;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER OMEGA TITLO;;;047D; -047D;CYRILLIC SMALL LETTER OMEGA WITH TITLO;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER OMEGA TITLO;;047C;;047C -047E;CYRILLIC CAPITAL LETTER OT;Lu;0;L;;;;;N;;;;047F; -047F;CYRILLIC SMALL LETTER OT;Ll;0;L;;;;;N;;;047E;;047E -0480;CYRILLIC CAPITAL LETTER KOPPA;Lu;0;L;;;;;N;;;;0481; -0481;CYRILLIC SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;0480;;0480 -0482;CYRILLIC THOUSANDS SIGN;So;0;L;;;;;N;;;;; -0483;COMBINING CYRILLIC TITLO;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING TITLO;;;; -0484;COMBINING CYRILLIC PALATALIZATION;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PALATALIZATION;;;; -0485;COMBINING CYRILLIC DASIA PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING DASIA PNEUMATA;;;; -0486;COMBINING CYRILLIC PSILI PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PSILI PNEUMATA;;;; -0487;COMBINING CYRILLIC POKRYTIE;Mn;230;NSM;;;;;N;;;;; -0488;COMBINING CYRILLIC HUNDRED THOUSANDS SIGN;Me;0;NSM;;;;;N;;;;; -0489;COMBINING CYRILLIC MILLIONS SIGN;Me;0;NSM;;;;;N;;;;; -048A;CYRILLIC CAPITAL LETTER SHORT I WITH TAIL;Lu;0;L;;;;;N;;;;048B; -048B;CYRILLIC SMALL LETTER SHORT I WITH TAIL;Ll;0;L;;;;;N;;;048A;;048A -048C;CYRILLIC CAPITAL LETTER SEMISOFT SIGN;Lu;0;L;;;;;N;;;;048D; -048D;CYRILLIC SMALL LETTER SEMISOFT SIGN;Ll;0;L;;;;;N;;;048C;;048C -048E;CYRILLIC CAPITAL LETTER ER WITH TICK;Lu;0;L;;;;;N;;;;048F; -048F;CYRILLIC SMALL LETTER ER WITH TICK;Ll;0;L;;;;;N;;;048E;;048E -0490;CYRILLIC CAPITAL LETTER GHE WITH UPTURN;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE WITH UPTURN;;;0491; -0491;CYRILLIC SMALL LETTER GHE WITH UPTURN;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE WITH UPTURN;;0490;;0490 -0492;CYRILLIC CAPITAL LETTER GHE WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE BAR;;;0493; -0493;CYRILLIC SMALL LETTER GHE WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE BAR;;0492;;0492 -0494;CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE HOOK;;;0495; -0495;CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE HOOK;;0494;;0494 -0496;CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZHE WITH RIGHT DESCENDER;;;0497; -0497;CYRILLIC SMALL LETTER ZHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZHE WITH RIGHT DESCENDER;;0496;;0496 -0498;CYRILLIC CAPITAL LETTER ZE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZE CEDILLA;;;0499; -0499;CYRILLIC SMALL LETTER ZE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZE CEDILLA;;0498;;0498 -049A;CYRILLIC CAPITAL LETTER KA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA WITH RIGHT DESCENDER;;;049B; -049B;CYRILLIC SMALL LETTER KA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA WITH RIGHT DESCENDER;;049A;;049A -049C;CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA VERTICAL BAR;;;049D; -049D;CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA VERTICAL BAR;;049C;;049C -049E;CYRILLIC CAPITAL LETTER KA WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA BAR;;;049F; -049F;CYRILLIC SMALL LETTER KA WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA BAR;;049E;;049E -04A0;CYRILLIC CAPITAL LETTER BASHKIR KA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED GE KA;;;04A1; -04A1;CYRILLIC SMALL LETTER BASHKIR KA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED GE KA;;04A0;;04A0 -04A2;CYRILLIC CAPITAL LETTER EN WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN WITH RIGHT DESCENDER;;;04A3; -04A3;CYRILLIC SMALL LETTER EN WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN WITH RIGHT DESCENDER;;04A2;;04A2 -04A4;CYRILLIC CAPITAL LIGATURE EN GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN GE;;;04A5; -04A5;CYRILLIC SMALL LIGATURE EN GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN GE;;04A4;;04A4 -04A6;CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER PE HOOK;;;04A7; -04A7;CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER PE HOOK;;04A6;;04A6 -04A8;CYRILLIC CAPITAL LETTER ABKHASIAN HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER O HOOK;;;04A9; -04A9;CYRILLIC SMALL LETTER ABKHASIAN HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER O HOOK;;04A8;;04A8 -04AA;CYRILLIC CAPITAL LETTER ES WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ES CEDILLA;;;04AB; -04AB;CYRILLIC SMALL LETTER ES WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ES CEDILLA;;04AA;;04AA -04AC;CYRILLIC CAPITAL LETTER TE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE WITH RIGHT DESCENDER;;;04AD; -04AD;CYRILLIC SMALL LETTER TE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE WITH RIGHT DESCENDER;;04AC;;04AC -04AE;CYRILLIC CAPITAL LETTER STRAIGHT U;Lu;0;L;;;;;N;;;;04AF; -04AF;CYRILLIC SMALL LETTER STRAIGHT U;Ll;0;L;;;;;N;;;04AE;;04AE -04B0;CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER STRAIGHT U BAR;;;04B1; -04B1;CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER STRAIGHT U BAR;;04B0;;04B0 -04B2;CYRILLIC CAPITAL LETTER HA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA WITH RIGHT DESCENDER;;;04B3; -04B3;CYRILLIC SMALL LETTER HA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA WITH RIGHT DESCENDER;;04B2;;04B2 -04B4;CYRILLIC CAPITAL LIGATURE TE TSE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE TSE;;;04B5; -04B5;CYRILLIC SMALL LIGATURE TE TSE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE TSE;;04B4;;04B4 -04B6;CYRILLIC CAPITAL LETTER CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH RIGHT DESCENDER;;;04B7; -04B7;CYRILLIC SMALL LETTER CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH RIGHT DESCENDER;;04B6;;04B6 -04B8;CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE VERTICAL BAR;;;04B9; -04B9;CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE VERTICAL BAR;;04B8;;04B8 -04BA;CYRILLIC CAPITAL LETTER SHHA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER H;;;04BB; -04BB;CYRILLIC SMALL LETTER SHHA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER H;;04BA;;04BA -04BC;CYRILLIC CAPITAL LETTER ABKHASIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK;;;04BD; -04BD;CYRILLIC SMALL LETTER ABKHASIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK;;04BC;;04BC -04BE;CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK OGONEK;;;04BF; -04BF;CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK OGONEK;;04BE;;04BE -04C0;CYRILLIC LETTER PALOCHKA;Lu;0;L;;;;;N;CYRILLIC LETTER I;;;04CF; -04C1;CYRILLIC CAPITAL LETTER ZHE WITH BREVE;Lu;0;L;0416 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT ZHE;;;04C2; -04C2;CYRILLIC SMALL LETTER ZHE WITH BREVE;Ll;0;L;0436 0306;;;;N;CYRILLIC SMALL LETTER SHORT ZHE;;04C1;;04C1 -04C3;CYRILLIC CAPITAL LETTER KA WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA HOOK;;;04C4; -04C4;CYRILLIC SMALL LETTER KA WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA HOOK;;04C3;;04C3 -04C5;CYRILLIC CAPITAL LETTER EL WITH TAIL;Lu;0;L;;;;;N;;;;04C6; -04C6;CYRILLIC SMALL LETTER EL WITH TAIL;Ll;0;L;;;;;N;;;04C5;;04C5 -04C7;CYRILLIC CAPITAL LETTER EN WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN HOOK;;;04C8; -04C8;CYRILLIC SMALL LETTER EN WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN HOOK;;04C7;;04C7 -04C9;CYRILLIC CAPITAL LETTER EN WITH TAIL;Lu;0;L;;;;;N;;;;04CA; -04CA;CYRILLIC SMALL LETTER EN WITH TAIL;Ll;0;L;;;;;N;;;04C9;;04C9 -04CB;CYRILLIC CAPITAL LETTER KHAKASSIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH LEFT DESCENDER;;;04CC; -04CC;CYRILLIC SMALL LETTER KHAKASSIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH LEFT DESCENDER;;04CB;;04CB -04CD;CYRILLIC CAPITAL LETTER EM WITH TAIL;Lu;0;L;;;;;N;;;;04CE; -04CE;CYRILLIC SMALL LETTER EM WITH TAIL;Ll;0;L;;;;;N;;;04CD;;04CD -04CF;CYRILLIC SMALL LETTER PALOCHKA;Ll;0;L;;;;;N;;;04C0;;04C0 -04D0;CYRILLIC CAPITAL LETTER A WITH BREVE;Lu;0;L;0410 0306;;;;N;;;;04D1; -04D1;CYRILLIC SMALL LETTER A WITH BREVE;Ll;0;L;0430 0306;;;;N;;;04D0;;04D0 -04D2;CYRILLIC CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0410 0308;;;;N;;;;04D3; -04D3;CYRILLIC SMALL LETTER A WITH DIAERESIS;Ll;0;L;0430 0308;;;;N;;;04D2;;04D2 -04D4;CYRILLIC CAPITAL LIGATURE A IE;Lu;0;L;;;;;N;;;;04D5; -04D5;CYRILLIC SMALL LIGATURE A IE;Ll;0;L;;;;;N;;;04D4;;04D4 -04D6;CYRILLIC CAPITAL LETTER IE WITH BREVE;Lu;0;L;0415 0306;;;;N;;;;04D7; -04D7;CYRILLIC SMALL LETTER IE WITH BREVE;Ll;0;L;0435 0306;;;;N;;;04D6;;04D6 -04D8;CYRILLIC CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;04D9; -04D9;CYRILLIC SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;04D8;;04D8 -04DA;CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS;Lu;0;L;04D8 0308;;;;N;;;;04DB; -04DB;CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS;Ll;0;L;04D9 0308;;;;N;;;04DA;;04DA -04DC;CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS;Lu;0;L;0416 0308;;;;N;;;;04DD; -04DD;CYRILLIC SMALL LETTER ZHE WITH DIAERESIS;Ll;0;L;0436 0308;;;;N;;;04DC;;04DC -04DE;CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS;Lu;0;L;0417 0308;;;;N;;;;04DF; -04DF;CYRILLIC SMALL LETTER ZE WITH DIAERESIS;Ll;0;L;0437 0308;;;;N;;;04DE;;04DE -04E0;CYRILLIC CAPITAL LETTER ABKHASIAN DZE;Lu;0;L;;;;;N;;;;04E1; -04E1;CYRILLIC SMALL LETTER ABKHASIAN DZE;Ll;0;L;;;;;N;;;04E0;;04E0 -04E2;CYRILLIC CAPITAL LETTER I WITH MACRON;Lu;0;L;0418 0304;;;;N;;;;04E3; -04E3;CYRILLIC SMALL LETTER I WITH MACRON;Ll;0;L;0438 0304;;;;N;;;04E2;;04E2 -04E4;CYRILLIC CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0418 0308;;;;N;;;;04E5; -04E5;CYRILLIC SMALL LETTER I WITH DIAERESIS;Ll;0;L;0438 0308;;;;N;;;04E4;;04E4 -04E6;CYRILLIC CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;041E 0308;;;;N;;;;04E7; -04E7;CYRILLIC SMALL LETTER O WITH DIAERESIS;Ll;0;L;043E 0308;;;;N;;;04E6;;04E6 -04E8;CYRILLIC CAPITAL LETTER BARRED O;Lu;0;L;;;;;N;;;;04E9; -04E9;CYRILLIC SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;04E8;;04E8 -04EA;CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS;Lu;0;L;04E8 0308;;;;N;;;;04EB; -04EB;CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS;Ll;0;L;04E9 0308;;;;N;;;04EA;;04EA -04EC;CYRILLIC CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;042D 0308;;;;N;;;;04ED; -04ED;CYRILLIC SMALL LETTER E WITH DIAERESIS;Ll;0;L;044D 0308;;;;N;;;04EC;;04EC -04EE;CYRILLIC CAPITAL LETTER U WITH MACRON;Lu;0;L;0423 0304;;;;N;;;;04EF; -04EF;CYRILLIC SMALL LETTER U WITH MACRON;Ll;0;L;0443 0304;;;;N;;;04EE;;04EE -04F0;CYRILLIC CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0423 0308;;;;N;;;;04F1; -04F1;CYRILLIC SMALL LETTER U WITH DIAERESIS;Ll;0;L;0443 0308;;;;N;;;04F0;;04F0 -04F2;CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0423 030B;;;;N;;;;04F3; -04F3;CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0443 030B;;;;N;;;04F2;;04F2 -04F4;CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS;Lu;0;L;0427 0308;;;;N;;;;04F5; -04F5;CYRILLIC SMALL LETTER CHE WITH DIAERESIS;Ll;0;L;0447 0308;;;;N;;;04F4;;04F4 -04F6;CYRILLIC CAPITAL LETTER GHE WITH DESCENDER;Lu;0;L;;;;;N;;;;04F7; -04F7;CYRILLIC SMALL LETTER GHE WITH DESCENDER;Ll;0;L;;;;;N;;;04F6;;04F6 -04F8;CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS;Lu;0;L;042B 0308;;;;N;;;;04F9; -04F9;CYRILLIC SMALL LETTER YERU WITH DIAERESIS;Ll;0;L;044B 0308;;;;N;;;04F8;;04F8 -04FA;CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK;Lu;0;L;;;;;N;;;;04FB; -04FB;CYRILLIC SMALL LETTER GHE WITH STROKE AND HOOK;Ll;0;L;;;;;N;;;04FA;;04FA -04FC;CYRILLIC CAPITAL LETTER HA WITH HOOK;Lu;0;L;;;;;N;;;;04FD; -04FD;CYRILLIC SMALL LETTER HA WITH HOOK;Ll;0;L;;;;;N;;;04FC;;04FC -04FE;CYRILLIC CAPITAL LETTER HA WITH STROKE;Lu;0;L;;;;;N;;;;04FF; -04FF;CYRILLIC SMALL LETTER HA WITH STROKE;Ll;0;L;;;;;N;;;04FE;;04FE -0500;CYRILLIC CAPITAL LETTER KOMI DE;Lu;0;L;;;;;N;;;;0501; -0501;CYRILLIC SMALL LETTER KOMI DE;Ll;0;L;;;;;N;;;0500;;0500 -0502;CYRILLIC CAPITAL LETTER KOMI DJE;Lu;0;L;;;;;N;;;;0503; -0503;CYRILLIC SMALL LETTER KOMI DJE;Ll;0;L;;;;;N;;;0502;;0502 -0504;CYRILLIC CAPITAL LETTER KOMI ZJE;Lu;0;L;;;;;N;;;;0505; -0505;CYRILLIC SMALL LETTER KOMI ZJE;Ll;0;L;;;;;N;;;0504;;0504 -0506;CYRILLIC CAPITAL LETTER KOMI DZJE;Lu;0;L;;;;;N;;;;0507; -0507;CYRILLIC SMALL LETTER KOMI DZJE;Ll;0;L;;;;;N;;;0506;;0506 -0508;CYRILLIC CAPITAL LETTER KOMI LJE;Lu;0;L;;;;;N;;;;0509; -0509;CYRILLIC SMALL LETTER KOMI LJE;Ll;0;L;;;;;N;;;0508;;0508 -050A;CYRILLIC CAPITAL LETTER KOMI NJE;Lu;0;L;;;;;N;;;;050B; -050B;CYRILLIC SMALL LETTER KOMI NJE;Ll;0;L;;;;;N;;;050A;;050A -050C;CYRILLIC CAPITAL LETTER KOMI SJE;Lu;0;L;;;;;N;;;;050D; -050D;CYRILLIC SMALL LETTER KOMI SJE;Ll;0;L;;;;;N;;;050C;;050C -050E;CYRILLIC CAPITAL LETTER KOMI TJE;Lu;0;L;;;;;N;;;;050F; -050F;CYRILLIC SMALL LETTER KOMI TJE;Ll;0;L;;;;;N;;;050E;;050E -0510;CYRILLIC CAPITAL LETTER REVERSED ZE;Lu;0;L;;;;;N;;;;0511; -0511;CYRILLIC SMALL LETTER REVERSED ZE;Ll;0;L;;;;;N;;;0510;;0510 -0512;CYRILLIC CAPITAL LETTER EL WITH HOOK;Lu;0;L;;;;;N;;;;0513; -0513;CYRILLIC SMALL LETTER EL WITH HOOK;Ll;0;L;;;;;N;;;0512;;0512 -0514;CYRILLIC CAPITAL LETTER LHA;Lu;0;L;;;;;N;;;;0515; -0515;CYRILLIC SMALL LETTER LHA;Ll;0;L;;;;;N;;;0514;;0514 -0516;CYRILLIC CAPITAL LETTER RHA;Lu;0;L;;;;;N;;;;0517; -0517;CYRILLIC SMALL LETTER RHA;Ll;0;L;;;;;N;;;0516;;0516 -0518;CYRILLIC CAPITAL LETTER YAE;Lu;0;L;;;;;N;;;;0519; -0519;CYRILLIC SMALL LETTER YAE;Ll;0;L;;;;;N;;;0518;;0518 -051A;CYRILLIC CAPITAL LETTER QA;Lu;0;L;;;;;N;;;;051B; -051B;CYRILLIC SMALL LETTER QA;Ll;0;L;;;;;N;;;051A;;051A -051C;CYRILLIC CAPITAL LETTER WE;Lu;0;L;;;;;N;;;;051D; -051D;CYRILLIC SMALL LETTER WE;Ll;0;L;;;;;N;;;051C;;051C -051E;CYRILLIC CAPITAL LETTER ALEUT KA;Lu;0;L;;;;;N;;;;051F; -051F;CYRILLIC SMALL LETTER ALEUT KA;Ll;0;L;;;;;N;;;051E;;051E -0520;CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK;Lu;0;L;;;;;N;;;;0521; -0521;CYRILLIC SMALL LETTER EL WITH MIDDLE HOOK;Ll;0;L;;;;;N;;;0520;;0520 -0522;CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK;Lu;0;L;;;;;N;;;;0523; -0523;CYRILLIC SMALL LETTER EN WITH MIDDLE HOOK;Ll;0;L;;;;;N;;;0522;;0522 -0524;CYRILLIC CAPITAL LETTER PE WITH DESCENDER;Lu;0;L;;;;;N;;;;0525; -0525;CYRILLIC SMALL LETTER PE WITH DESCENDER;Ll;0;L;;;;;N;;;0524;;0524 -0526;CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER;Lu;0;L;;;;;N;;;;0527; -0527;CYRILLIC SMALL LETTER SHHA WITH DESCENDER;Ll;0;L;;;;;N;;;0526;;0526 -0528;CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK;Lu;0;L;;;;;N;;;;0529; -0529;CYRILLIC SMALL LETTER EN WITH LEFT HOOK;Ll;0;L;;;;;N;;;0528;;0528 -052A;CYRILLIC CAPITAL LETTER DZZHE;Lu;0;L;;;;;N;;;;052B; -052B;CYRILLIC SMALL LETTER DZZHE;Ll;0;L;;;;;N;;;052A;;052A -052C;CYRILLIC CAPITAL LETTER DCHE;Lu;0;L;;;;;N;;;;052D; -052D;CYRILLIC SMALL LETTER DCHE;Ll;0;L;;;;;N;;;052C;;052C -052E;CYRILLIC CAPITAL LETTER EL WITH DESCENDER;Lu;0;L;;;;;N;;;;052F; -052F;CYRILLIC SMALL LETTER EL WITH DESCENDER;Ll;0;L;;;;;N;;;052E;;052E -0531;ARMENIAN CAPITAL LETTER AYB;Lu;0;L;;;;;N;;;;0561; -0532;ARMENIAN CAPITAL LETTER BEN;Lu;0;L;;;;;N;;;;0562; -0533;ARMENIAN CAPITAL LETTER GIM;Lu;0;L;;;;;N;;;;0563; -0534;ARMENIAN CAPITAL LETTER DA;Lu;0;L;;;;;N;;;;0564; -0535;ARMENIAN CAPITAL LETTER ECH;Lu;0;L;;;;;N;;;;0565; -0536;ARMENIAN CAPITAL LETTER ZA;Lu;0;L;;;;;N;;;;0566; -0537;ARMENIAN CAPITAL LETTER EH;Lu;0;L;;;;;N;;;;0567; -0538;ARMENIAN CAPITAL LETTER ET;Lu;0;L;;;;;N;;;;0568; -0539;ARMENIAN CAPITAL LETTER TO;Lu;0;L;;;;;N;;;;0569; -053A;ARMENIAN CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;056A; -053B;ARMENIAN CAPITAL LETTER INI;Lu;0;L;;;;;N;;;;056B; -053C;ARMENIAN CAPITAL LETTER LIWN;Lu;0;L;;;;;N;;;;056C; -053D;ARMENIAN CAPITAL LETTER XEH;Lu;0;L;;;;;N;;;;056D; -053E;ARMENIAN CAPITAL LETTER CA;Lu;0;L;;;;;N;;;;056E; -053F;ARMENIAN CAPITAL LETTER KEN;Lu;0;L;;;;;N;;;;056F; -0540;ARMENIAN CAPITAL LETTER HO;Lu;0;L;;;;;N;;;;0570; -0541;ARMENIAN CAPITAL LETTER JA;Lu;0;L;;;;;N;;;;0571; -0542;ARMENIAN CAPITAL LETTER GHAD;Lu;0;L;;;;;N;ARMENIAN CAPITAL LETTER LAD;;;0572; -0543;ARMENIAN CAPITAL LETTER CHEH;Lu;0;L;;;;;N;;;;0573; -0544;ARMENIAN CAPITAL LETTER MEN;Lu;0;L;;;;;N;;;;0574; -0545;ARMENIAN CAPITAL LETTER YI;Lu;0;L;;;;;N;;;;0575; -0546;ARMENIAN CAPITAL LETTER NOW;Lu;0;L;;;;;N;;;;0576; -0547;ARMENIAN CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0577; -0548;ARMENIAN CAPITAL LETTER VO;Lu;0;L;;;;;N;;;;0578; -0549;ARMENIAN CAPITAL LETTER CHA;Lu;0;L;;;;;N;;;;0579; -054A;ARMENIAN CAPITAL LETTER PEH;Lu;0;L;;;;;N;;;;057A; -054B;ARMENIAN CAPITAL LETTER JHEH;Lu;0;L;;;;;N;;;;057B; -054C;ARMENIAN CAPITAL LETTER RA;Lu;0;L;;;;;N;;;;057C; -054D;ARMENIAN CAPITAL LETTER SEH;Lu;0;L;;;;;N;;;;057D; -054E;ARMENIAN CAPITAL LETTER VEW;Lu;0;L;;;;;N;;;;057E; -054F;ARMENIAN CAPITAL LETTER TIWN;Lu;0;L;;;;;N;;;;057F; -0550;ARMENIAN CAPITAL LETTER REH;Lu;0;L;;;;;N;;;;0580; -0551;ARMENIAN CAPITAL LETTER CO;Lu;0;L;;;;;N;;;;0581; -0552;ARMENIAN CAPITAL LETTER YIWN;Lu;0;L;;;;;N;;;;0582; -0553;ARMENIAN CAPITAL LETTER PIWR;Lu;0;L;;;;;N;;;;0583; -0554;ARMENIAN CAPITAL LETTER KEH;Lu;0;L;;;;;N;;;;0584; -0555;ARMENIAN CAPITAL LETTER OH;Lu;0;L;;;;;N;;;;0585; -0556;ARMENIAN CAPITAL LETTER FEH;Lu;0;L;;;;;N;;;;0586; -0559;ARMENIAN MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;; -055A;ARMENIAN APOSTROPHE;Po;0;L;;;;;N;ARMENIAN MODIFIER LETTER RIGHT HALF RING;;;; -055B;ARMENIAN EMPHASIS MARK;Po;0;L;;;;;N;;;;; -055C;ARMENIAN EXCLAMATION MARK;Po;0;L;;;;;N;;;;; -055D;ARMENIAN COMMA;Po;0;L;;;;;N;;;;; -055E;ARMENIAN QUESTION MARK;Po;0;L;;;;;N;;;;; -055F;ARMENIAN ABBREVIATION MARK;Po;0;L;;;;;N;;;;; -0560;ARMENIAN SMALL LETTER TURNED AYB;Ll;0;L;;;;;N;;;;; -0561;ARMENIAN SMALL LETTER AYB;Ll;0;L;;;;;N;;;0531;;0531 -0562;ARMENIAN SMALL LETTER BEN;Ll;0;L;;;;;N;;;0532;;0532 -0563;ARMENIAN SMALL LETTER GIM;Ll;0;L;;;;;N;;;0533;;0533 -0564;ARMENIAN SMALL LETTER DA;Ll;0;L;;;;;N;;;0534;;0534 -0565;ARMENIAN SMALL LETTER ECH;Ll;0;L;;;;;N;;;0535;;0535 -0566;ARMENIAN SMALL LETTER ZA;Ll;0;L;;;;;N;;;0536;;0536 -0567;ARMENIAN SMALL LETTER EH;Ll;0;L;;;;;N;;;0537;;0537 -0568;ARMENIAN SMALL LETTER ET;Ll;0;L;;;;;N;;;0538;;0538 -0569;ARMENIAN SMALL LETTER TO;Ll;0;L;;;;;N;;;0539;;0539 -056A;ARMENIAN SMALL LETTER ZHE;Ll;0;L;;;;;N;;;053A;;053A -056B;ARMENIAN SMALL LETTER INI;Ll;0;L;;;;;N;;;053B;;053B -056C;ARMENIAN SMALL LETTER LIWN;Ll;0;L;;;;;N;;;053C;;053C -056D;ARMENIAN SMALL LETTER XEH;Ll;0;L;;;;;N;;;053D;;053D -056E;ARMENIAN SMALL LETTER CA;Ll;0;L;;;;;N;;;053E;;053E -056F;ARMENIAN SMALL LETTER KEN;Ll;0;L;;;;;N;;;053F;;053F -0570;ARMENIAN SMALL LETTER HO;Ll;0;L;;;;;N;;;0540;;0540 -0571;ARMENIAN SMALL LETTER JA;Ll;0;L;;;;;N;;;0541;;0541 -0572;ARMENIAN SMALL LETTER GHAD;Ll;0;L;;;;;N;ARMENIAN SMALL LETTER LAD;;0542;;0542 -0573;ARMENIAN SMALL LETTER CHEH;Ll;0;L;;;;;N;;;0543;;0543 -0574;ARMENIAN SMALL LETTER MEN;Ll;0;L;;;;;N;;;0544;;0544 -0575;ARMENIAN SMALL LETTER YI;Ll;0;L;;;;;N;;;0545;;0545 -0576;ARMENIAN SMALL LETTER NOW;Ll;0;L;;;;;N;;;0546;;0546 -0577;ARMENIAN SMALL LETTER SHA;Ll;0;L;;;;;N;;;0547;;0547 -0578;ARMENIAN SMALL LETTER VO;Ll;0;L;;;;;N;;;0548;;0548 -0579;ARMENIAN SMALL LETTER CHA;Ll;0;L;;;;;N;;;0549;;0549 -057A;ARMENIAN SMALL LETTER PEH;Ll;0;L;;;;;N;;;054A;;054A -057B;ARMENIAN SMALL LETTER JHEH;Ll;0;L;;;;;N;;;054B;;054B -057C;ARMENIAN SMALL LETTER RA;Ll;0;L;;;;;N;;;054C;;054C -057D;ARMENIAN SMALL LETTER SEH;Ll;0;L;;;;;N;;;054D;;054D -057E;ARMENIAN SMALL LETTER VEW;Ll;0;L;;;;;N;;;054E;;054E -057F;ARMENIAN SMALL LETTER TIWN;Ll;0;L;;;;;N;;;054F;;054F -0580;ARMENIAN SMALL LETTER REH;Ll;0;L;;;;;N;;;0550;;0550 -0581;ARMENIAN SMALL LETTER CO;Ll;0;L;;;;;N;;;0551;;0551 -0582;ARMENIAN SMALL LETTER YIWN;Ll;0;L;;;;;N;;;0552;;0552 -0583;ARMENIAN SMALL LETTER PIWR;Ll;0;L;;;;;N;;;0553;;0553 -0584;ARMENIAN SMALL LETTER KEH;Ll;0;L;;;;;N;;;0554;;0554 -0585;ARMENIAN SMALL LETTER OH;Ll;0;L;;;;;N;;;0555;;0555 -0586;ARMENIAN SMALL LETTER FEH;Ll;0;L;;;;;N;;;0556;;0556 -0587;ARMENIAN SMALL LIGATURE ECH YIWN;Ll;0;L;<compat> 0565 0582;;;;N;;;;; -0588;ARMENIAN SMALL LETTER YI WITH STROKE;Ll;0;L;;;;;N;;;;; -0589;ARMENIAN FULL STOP;Po;0;L;;;;;N;ARMENIAN PERIOD;;;; -058A;ARMENIAN HYPHEN;Pd;0;ON;;;;;N;;;;; -058D;RIGHT-FACING ARMENIAN ETERNITY SIGN;So;0;ON;;;;;N;;;;; -058E;LEFT-FACING ARMENIAN ETERNITY SIGN;So;0;ON;;;;;N;;;;; -058F;ARMENIAN DRAM SIGN;Sc;0;ET;;;;;N;;;;; -0591;HEBREW ACCENT ETNAHTA;Mn;220;NSM;;;;;N;;;;; -0592;HEBREW ACCENT SEGOL;Mn;230;NSM;;;;;N;;;;; -0593;HEBREW ACCENT SHALSHELET;Mn;230;NSM;;;;;N;;;;; -0594;HEBREW ACCENT ZAQEF QATAN;Mn;230;NSM;;;;;N;;;;; -0595;HEBREW ACCENT ZAQEF GADOL;Mn;230;NSM;;;;;N;;;;; -0596;HEBREW ACCENT TIPEHA;Mn;220;NSM;;;;;N;;;;; -0597;HEBREW ACCENT REVIA;Mn;230;NSM;;;;;N;;;;; -0598;HEBREW ACCENT ZARQA;Mn;230;NSM;;;;;N;;;;; -0599;HEBREW ACCENT PASHTA;Mn;230;NSM;;;;;N;;;;; -059A;HEBREW ACCENT YETIV;Mn;222;NSM;;;;;N;;;;; -059B;HEBREW ACCENT TEVIR;Mn;220;NSM;;;;;N;;;;; -059C;HEBREW ACCENT GERESH;Mn;230;NSM;;;;;N;;;;; -059D;HEBREW ACCENT GERESH MUQDAM;Mn;230;NSM;;;;;N;;;;; -059E;HEBREW ACCENT GERSHAYIM;Mn;230;NSM;;;;;N;;;;; -059F;HEBREW ACCENT QARNEY PARA;Mn;230;NSM;;;;;N;;;;; -05A0;HEBREW ACCENT TELISHA GEDOLA;Mn;230;NSM;;;;;N;;;;; -05A1;HEBREW ACCENT PAZER;Mn;230;NSM;;;;;N;;;;; -05A2;HEBREW ACCENT ATNAH HAFUKH;Mn;220;NSM;;;;;N;;;;; -05A3;HEBREW ACCENT MUNAH;Mn;220;NSM;;;;;N;;;;; -05A4;HEBREW ACCENT MAHAPAKH;Mn;220;NSM;;;;;N;;;;; -05A5;HEBREW ACCENT MERKHA;Mn;220;NSM;;;;;N;;;;; -05A6;HEBREW ACCENT MERKHA KEFULA;Mn;220;NSM;;;;;N;;;;; -05A7;HEBREW ACCENT DARGA;Mn;220;NSM;;;;;N;;;;; -05A8;HEBREW ACCENT QADMA;Mn;230;NSM;;;;;N;;;;; -05A9;HEBREW ACCENT TELISHA QETANA;Mn;230;NSM;;;;;N;;;;; -05AA;HEBREW ACCENT YERAH BEN YOMO;Mn;220;NSM;;;;;N;;;;; -05AB;HEBREW ACCENT OLE;Mn;230;NSM;;;;;N;;;;; -05AC;HEBREW ACCENT ILUY;Mn;230;NSM;;;;;N;;;;; -05AD;HEBREW ACCENT DEHI;Mn;222;NSM;;;;;N;;;;; -05AE;HEBREW ACCENT ZINOR;Mn;228;NSM;;;;;N;;;;; -05AF;HEBREW MARK MASORA CIRCLE;Mn;230;NSM;;;;;N;;;;; -05B0;HEBREW POINT SHEVA;Mn;10;NSM;;;;;N;;;;; -05B1;HEBREW POINT HATAF SEGOL;Mn;11;NSM;;;;;N;;;;; -05B2;HEBREW POINT HATAF PATAH;Mn;12;NSM;;;;;N;;;;; -05B3;HEBREW POINT HATAF QAMATS;Mn;13;NSM;;;;;N;;;;; -05B4;HEBREW POINT HIRIQ;Mn;14;NSM;;;;;N;;;;; -05B5;HEBREW POINT TSERE;Mn;15;NSM;;;;;N;;;;; -05B6;HEBREW POINT SEGOL;Mn;16;NSM;;;;;N;;;;; -05B7;HEBREW POINT PATAH;Mn;17;NSM;;;;;N;;;;; -05B8;HEBREW POINT QAMATS;Mn;18;NSM;;;;;N;;;;; -05B9;HEBREW POINT HOLAM;Mn;19;NSM;;;;;N;;;;; -05BA;HEBREW POINT HOLAM HASER FOR VAV;Mn;19;NSM;;;;;N;;;;; -05BB;HEBREW POINT QUBUTS;Mn;20;NSM;;;;;N;;;;; -05BC;HEBREW POINT DAGESH OR MAPIQ;Mn;21;NSM;;;;;N;HEBREW POINT DAGESH;;;; -05BD;HEBREW POINT METEG;Mn;22;NSM;;;;;N;;;;; -05BE;HEBREW PUNCTUATION MAQAF;Pd;0;R;;;;;N;;;;; -05BF;HEBREW POINT RAFE;Mn;23;NSM;;;;;N;;;;; -05C0;HEBREW PUNCTUATION PASEQ;Po;0;R;;;;;N;HEBREW POINT PASEQ;;;; -05C1;HEBREW POINT SHIN DOT;Mn;24;NSM;;;;;N;;;;; -05C2;HEBREW POINT SIN DOT;Mn;25;NSM;;;;;N;;;;; -05C3;HEBREW PUNCTUATION SOF PASUQ;Po;0;R;;;;;N;;;;; -05C4;HEBREW MARK UPPER DOT;Mn;230;NSM;;;;;N;;;;; -05C5;HEBREW MARK LOWER DOT;Mn;220;NSM;;;;;N;;;;; -05C6;HEBREW PUNCTUATION NUN HAFUKHA;Po;0;R;;;;;N;;;;; -05C7;HEBREW POINT QAMATS QATAN;Mn;18;NSM;;;;;N;;;;; -05D0;HEBREW LETTER ALEF;Lo;0;R;;;;;N;;;;; -05D1;HEBREW LETTER BET;Lo;0;R;;;;;N;;;;; -05D2;HEBREW LETTER GIMEL;Lo;0;R;;;;;N;;;;; -05D3;HEBREW LETTER DALET;Lo;0;R;;;;;N;;;;; -05D4;HEBREW LETTER HE;Lo;0;R;;;;;N;;;;; -05D5;HEBREW LETTER VAV;Lo;0;R;;;;;N;;;;; -05D6;HEBREW LETTER ZAYIN;Lo;0;R;;;;;N;;;;; -05D7;HEBREW LETTER HET;Lo;0;R;;;;;N;;;;; -05D8;HEBREW LETTER TET;Lo;0;R;;;;;N;;;;; -05D9;HEBREW LETTER YOD;Lo;0;R;;;;;N;;;;; -05DA;HEBREW LETTER FINAL KAF;Lo;0;R;;;;;N;;;;; -05DB;HEBREW LETTER KAF;Lo;0;R;;;;;N;;;;; -05DC;HEBREW LETTER LAMED;Lo;0;R;;;;;N;;;;; -05DD;HEBREW LETTER FINAL MEM;Lo;0;R;;;;;N;;;;; -05DE;HEBREW LETTER MEM;Lo;0;R;;;;;N;;;;; -05DF;HEBREW LETTER FINAL NUN;Lo;0;R;;;;;N;;;;; -05E0;HEBREW LETTER NUN;Lo;0;R;;;;;N;;;;; -05E1;HEBREW LETTER SAMEKH;Lo;0;R;;;;;N;;;;; -05E2;HEBREW LETTER AYIN;Lo;0;R;;;;;N;;;;; -05E3;HEBREW LETTER FINAL PE;Lo;0;R;;;;;N;;;;; -05E4;HEBREW LETTER PE;Lo;0;R;;;;;N;;;;; -05E5;HEBREW LETTER FINAL TSADI;Lo;0;R;;;;;N;;;;; -05E6;HEBREW LETTER TSADI;Lo;0;R;;;;;N;;;;; -05E7;HEBREW LETTER QOF;Lo;0;R;;;;;N;;;;; -05E8;HEBREW LETTER RESH;Lo;0;R;;;;;N;;;;; -05E9;HEBREW LETTER SHIN;Lo;0;R;;;;;N;;;;; -05EA;HEBREW LETTER TAV;Lo;0;R;;;;;N;;;;; -05EF;HEBREW YOD TRIANGLE;Lo;0;R;;;;;N;;;;; -05F0;HEBREW LIGATURE YIDDISH DOUBLE VAV;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE VAV;;;; -05F1;HEBREW LIGATURE YIDDISH VAV YOD;Lo;0;R;;;;;N;HEBREW LETTER VAV YOD;;;; -05F2;HEBREW LIGATURE YIDDISH DOUBLE YOD;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE YOD;;;; -05F3;HEBREW PUNCTUATION GERESH;Po;0;R;;;;;N;;;;; -05F4;HEBREW PUNCTUATION GERSHAYIM;Po;0;R;;;;;N;;;;; -0600;ARABIC NUMBER SIGN;Cf;0;AN;;;;;N;;;;; -0601;ARABIC SIGN SANAH;Cf;0;AN;;;;;N;;;;; -0602;ARABIC FOOTNOTE MARKER;Cf;0;AN;;;;;N;;;;; -0603;ARABIC SIGN SAFHA;Cf;0;AN;;;;;N;;;;; -0604;ARABIC SIGN SAMVAT;Cf;0;AN;;;;;N;;;;; -0605;ARABIC NUMBER MARK ABOVE;Cf;0;AN;;;;;N;;;;; -0606;ARABIC-INDIC CUBE ROOT;Sm;0;ON;;;;;N;;;;; -0607;ARABIC-INDIC FOURTH ROOT;Sm;0;ON;;;;;N;;;;; -0608;ARABIC RAY;Sm;0;AL;;;;;N;;;;; -0609;ARABIC-INDIC PER MILLE SIGN;Po;0;ET;;;;;N;;;;; -060A;ARABIC-INDIC PER TEN THOUSAND SIGN;Po;0;ET;;;;;N;;;;; -060B;AFGHANI SIGN;Sc;0;AL;;;;;N;;;;; -060C;ARABIC COMMA;Po;0;CS;;;;;N;;;;; -060D;ARABIC DATE SEPARATOR;Po;0;AL;;;;;N;;;;; -060E;ARABIC POETIC VERSE SIGN;So;0;ON;;;;;N;;;;; -060F;ARABIC SIGN MISRA;So;0;ON;;;;;N;;;;; -0610;ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM;Mn;230;NSM;;;;;N;;;;; -0611;ARABIC SIGN ALAYHE ASSALLAM;Mn;230;NSM;;;;;N;;;;; -0612;ARABIC SIGN RAHMATULLAH ALAYHE;Mn;230;NSM;;;;;N;;;;; -0613;ARABIC SIGN RADI ALLAHOU ANHU;Mn;230;NSM;;;;;N;;;;; -0614;ARABIC SIGN TAKHALLUS;Mn;230;NSM;;;;;N;;;;; -0615;ARABIC SMALL HIGH TAH;Mn;230;NSM;;;;;N;;;;; -0616;ARABIC SMALL HIGH LIGATURE ALEF WITH LAM WITH YEH;Mn;230;NSM;;;;;N;;;;; -0617;ARABIC SMALL HIGH ZAIN;Mn;230;NSM;;;;;N;;;;; -0618;ARABIC SMALL FATHA;Mn;30;NSM;;;;;N;;;;; -0619;ARABIC SMALL DAMMA;Mn;31;NSM;;;;;N;;;;; -061A;ARABIC SMALL KASRA;Mn;32;NSM;;;;;N;;;;; -061B;ARABIC SEMICOLON;Po;0;AL;;;;;N;;;;; -061C;ARABIC LETTER MARK;Cf;0;AL;;;;;N;;;;; -061D;ARABIC END OF TEXT MARK;Po;0;AL;;;;;N;;;;; -061E;ARABIC TRIPLE DOT PUNCTUATION MARK;Po;0;AL;;;;;N;;;;; -061F;ARABIC QUESTION MARK;Po;0;AL;;;;;N;;;;; -0620;ARABIC LETTER KASHMIRI YEH;Lo;0;AL;;;;;N;;;;; -0621;ARABIC LETTER HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH;;;; -0622;ARABIC LETTER ALEF WITH MADDA ABOVE;Lo;0;AL;0627 0653;;;;N;ARABIC LETTER MADDAH ON ALEF;;;; -0623;ARABIC LETTER ALEF WITH HAMZA ABOVE;Lo;0;AL;0627 0654;;;;N;ARABIC LETTER HAMZAH ON ALEF;;;; -0624;ARABIC LETTER WAW WITH HAMZA ABOVE;Lo;0;AL;0648 0654;;;;N;ARABIC LETTER HAMZAH ON WAW;;;; -0625;ARABIC LETTER ALEF WITH HAMZA BELOW;Lo;0;AL;0627 0655;;;;N;ARABIC LETTER HAMZAH UNDER ALEF;;;; -0626;ARABIC LETTER YEH WITH HAMZA ABOVE;Lo;0;AL;064A 0654;;;;N;ARABIC LETTER HAMZAH ON YA;;;; -0627;ARABIC LETTER ALEF;Lo;0;AL;;;;;N;;;;; -0628;ARABIC LETTER BEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA;;;; -0629;ARABIC LETTER TEH MARBUTA;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH;;;; -062A;ARABIC LETTER TEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA;;;; -062B;ARABIC LETTER THEH;Lo;0;AL;;;;;N;ARABIC LETTER THAA;;;; -062C;ARABIC LETTER JEEM;Lo;0;AL;;;;;N;;;;; -062D;ARABIC LETTER HAH;Lo;0;AL;;;;;N;ARABIC LETTER HAA;;;; -062E;ARABIC LETTER KHAH;Lo;0;AL;;;;;N;ARABIC LETTER KHAA;;;; -062F;ARABIC LETTER DAL;Lo;0;AL;;;;;N;;;;; -0630;ARABIC LETTER THAL;Lo;0;AL;;;;;N;;;;; -0631;ARABIC LETTER REH;Lo;0;AL;;;;;N;ARABIC LETTER RA;;;; -0632;ARABIC LETTER ZAIN;Lo;0;AL;;;;;N;;;;; -0633;ARABIC LETTER SEEN;Lo;0;AL;;;;;N;;;;; -0634;ARABIC LETTER SHEEN;Lo;0;AL;;;;;N;;;;; -0635;ARABIC LETTER SAD;Lo;0;AL;;;;;N;;;;; -0636;ARABIC LETTER DAD;Lo;0;AL;;;;;N;;;;; -0637;ARABIC LETTER TAH;Lo;0;AL;;;;;N;;;;; -0638;ARABIC LETTER ZAH;Lo;0;AL;;;;;N;ARABIC LETTER DHAH;;;; -0639;ARABIC LETTER AIN;Lo;0;AL;;;;;N;;;;; -063A;ARABIC LETTER GHAIN;Lo;0;AL;;;;;N;;;;; -063B;ARABIC LETTER KEHEH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -063C;ARABIC LETTER KEHEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; -063D;ARABIC LETTER FARSI YEH WITH INVERTED V;Lo;0;AL;;;;;N;;;;; -063E;ARABIC LETTER FARSI YEH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -063F;ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -0640;ARABIC TATWEEL;Lm;0;AL;;;;;N;;;;; -0641;ARABIC LETTER FEH;Lo;0;AL;;;;;N;ARABIC LETTER FA;;;; -0642;ARABIC LETTER QAF;Lo;0;AL;;;;;N;;;;; -0643;ARABIC LETTER KAF;Lo;0;AL;;;;;N;ARABIC LETTER CAF;;;; -0644;ARABIC LETTER LAM;Lo;0;AL;;;;;N;;;;; -0645;ARABIC LETTER MEEM;Lo;0;AL;;;;;N;;;;; -0646;ARABIC LETTER NOON;Lo;0;AL;;;;;N;;;;; -0647;ARABIC LETTER HEH;Lo;0;AL;;;;;N;ARABIC LETTER HA;;;; -0648;ARABIC LETTER WAW;Lo;0;AL;;;;;N;;;;; -0649;ARABIC LETTER ALEF MAKSURA;Lo;0;AL;;;;;N;ARABIC LETTER ALEF MAQSURAH;;;; -064A;ARABIC LETTER YEH;Lo;0;AL;;;;;N;ARABIC LETTER YA;;;; -064B;ARABIC FATHATAN;Mn;27;NSM;;;;;N;;;;; -064C;ARABIC DAMMATAN;Mn;28;NSM;;;;;N;;;;; -064D;ARABIC KASRATAN;Mn;29;NSM;;;;;N;;;;; -064E;ARABIC FATHA;Mn;30;NSM;;;;;N;ARABIC FATHAH;;;; -064F;ARABIC DAMMA;Mn;31;NSM;;;;;N;ARABIC DAMMAH;;;; -0650;ARABIC KASRA;Mn;32;NSM;;;;;N;ARABIC KASRAH;;;; -0651;ARABIC SHADDA;Mn;33;NSM;;;;;N;ARABIC SHADDAH;;;; -0652;ARABIC SUKUN;Mn;34;NSM;;;;;N;;;;; -0653;ARABIC MADDAH ABOVE;Mn;230;NSM;;;;;N;;;;; -0654;ARABIC HAMZA ABOVE;Mn;230;NSM;;;;;N;;;;; -0655;ARABIC HAMZA BELOW;Mn;220;NSM;;;;;N;;;;; -0656;ARABIC SUBSCRIPT ALEF;Mn;220;NSM;;;;;N;;;;; -0657;ARABIC INVERTED DAMMA;Mn;230;NSM;;;;;N;;;;; -0658;ARABIC MARK NOON GHUNNA;Mn;230;NSM;;;;;N;;;;; -0659;ARABIC ZWARAKAY;Mn;230;NSM;;;;;N;;;;; -065A;ARABIC VOWEL SIGN SMALL V ABOVE;Mn;230;NSM;;;;;N;;;;; -065B;ARABIC VOWEL SIGN INVERTED SMALL V ABOVE;Mn;230;NSM;;;;;N;;;;; -065C;ARABIC VOWEL SIGN DOT BELOW;Mn;220;NSM;;;;;N;;;;; -065D;ARABIC REVERSED DAMMA;Mn;230;NSM;;;;;N;;;;; -065E;ARABIC FATHA WITH TWO DOTS;Mn;230;NSM;;;;;N;;;;; -065F;ARABIC WAVY HAMZA BELOW;Mn;220;NSM;;;;;N;;;;; -0660;ARABIC-INDIC DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;; -0661;ARABIC-INDIC DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;; -0662;ARABIC-INDIC DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;; -0663;ARABIC-INDIC DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;; -0664;ARABIC-INDIC DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;; -0665;ARABIC-INDIC DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;; -0666;ARABIC-INDIC DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;; -0667;ARABIC-INDIC DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;; -0668;ARABIC-INDIC DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;; -0669;ARABIC-INDIC DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;; -066A;ARABIC PERCENT SIGN;Po;0;ET;;;;;N;;;;; -066B;ARABIC DECIMAL SEPARATOR;Po;0;AN;;;;;N;;;;; -066C;ARABIC THOUSANDS SEPARATOR;Po;0;AN;;;;;N;;;;; -066D;ARABIC FIVE POINTED STAR;Po;0;AL;;;;;N;;;;; -066E;ARABIC LETTER DOTLESS BEH;Lo;0;AL;;;;;N;;;;; -066F;ARABIC LETTER DOTLESS QAF;Lo;0;AL;;;;;N;;;;; -0670;ARABIC LETTER SUPERSCRIPT ALEF;Mn;35;NSM;;;;;N;ARABIC ALEF ABOVE;;;; -0671;ARABIC LETTER ALEF WASLA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAT WASL ON ALEF;;;; -0672;ARABIC LETTER ALEF WITH WAVY HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH ON ALEF;;;; -0673;ARABIC LETTER ALEF WITH WAVY HAMZA BELOW;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH UNDER ALEF;;;; -0674;ARABIC LETTER HIGH HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HIGH HAMZAH;;;; -0675;ARABIC LETTER HIGH HAMZA ALEF;Lo;0;AL;<compat> 0627 0674;;;;N;ARABIC LETTER HIGH HAMZAH ALEF;;;; -0676;ARABIC LETTER HIGH HAMZA WAW;Lo;0;AL;<compat> 0648 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW;;;; -0677;ARABIC LETTER U WITH HAMZA ABOVE;Lo;0;AL;<compat> 06C7 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW WITH DAMMAH;;;; -0678;ARABIC LETTER HIGH HAMZA YEH;Lo;0;AL;<compat> 064A 0674;;;;N;ARABIC LETTER HIGH HAMZAH YA;;;; -0679;ARABIC LETTER TTEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH SMALL TAH;;;; -067A;ARABIC LETTER TTEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH TWO DOTS VERTICAL ABOVE;;;; -067B;ARABIC LETTER BEEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH TWO DOTS VERTICAL BELOW;;;; -067C;ARABIC LETTER TEH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH RING;;;; -067D;ARABIC LETTER TEH WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS ABOVE DOWNWARD;;;; -067E;ARABIC LETTER PEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS BELOW;;;; -067F;ARABIC LETTER TEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH FOUR DOTS ABOVE;;;; -0680;ARABIC LETTER BEHEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH FOUR DOTS BELOW;;;; -0681;ARABIC LETTER HAH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH ON HAA;;;; -0682;ARABIC LETTER HAH WITH TWO DOTS VERTICAL ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH TWO DOTS VERTICAL ABOVE;;;; -0683;ARABIC LETTER NYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS;;;; -0684;ARABIC LETTER DYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS VERTICAL;;;; -0685;ARABIC LETTER HAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH THREE DOTS ABOVE;;;; -0686;ARABIC LETTER TCHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE THREE DOTS DOWNWARD;;;; -0687;ARABIC LETTER TCHEHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE FOUR DOTS;;;; -0688;ARABIC LETTER DDAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH SMALL TAH;;;; -0689;ARABIC LETTER DAL WITH RING;Lo;0;AL;;;;;N;;;;; -068A;ARABIC LETTER DAL WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; -068B;ARABIC LETTER DAL WITH DOT BELOW AND SMALL TAH;Lo;0;AL;;;;;N;;;;; -068C;ARABIC LETTER DAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS ABOVE;;;; -068D;ARABIC LETTER DDAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS BELOW;;;; -068E;ARABIC LETTER DUL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE;;;; -068F;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARD;;;; -0690;ARABIC LETTER DAL WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -0691;ARABIC LETTER RREH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL TAH;;;; -0692;ARABIC LETTER REH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V;;;; -0693;ARABIC LETTER REH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH RING;;;; -0694;ARABIC LETTER REH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW;;;; -0695;ARABIC LETTER REH WITH SMALL V BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V BELOW;;;; -0696;ARABIC LETTER REH WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW AND DOT ABOVE;;;; -0697;ARABIC LETTER REH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH TWO DOTS ABOVE;;;; -0698;ARABIC LETTER JEH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH THREE DOTS ABOVE;;;; -0699;ARABIC LETTER REH WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH FOUR DOTS ABOVE;;;; -069A;ARABIC LETTER SEEN WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; -069B;ARABIC LETTER SEEN WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; -069C;ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -069D;ARABIC LETTER SAD WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;; -069E;ARABIC LETTER SAD WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -069F;ARABIC LETTER TAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -06A0;ARABIC LETTER AIN WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -06A1;ARABIC LETTER DOTLESS FEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS FA;;;; -06A2;ARABIC LETTER FEH WITH DOT MOVED BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT MOVED BELOW;;;; -06A3;ARABIC LETTER FEH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT BELOW;;;; -06A4;ARABIC LETTER VEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS ABOVE;;;; -06A5;ARABIC LETTER FEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS BELOW;;;; -06A6;ARABIC LETTER PEHEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH FOUR DOTS ABOVE;;;; -06A7;ARABIC LETTER QAF WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; -06A8;ARABIC LETTER QAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -06A9;ARABIC LETTER KEHEH;Lo;0;AL;;;;;N;ARABIC LETTER OPEN CAF;;;; -06AA;ARABIC LETTER SWASH KAF;Lo;0;AL;;;;;N;ARABIC LETTER SWASH CAF;;;; -06AB;ARABIC LETTER KAF WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH RING;;;; -06AC;ARABIC LETTER KAF WITH DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH DOT ABOVE;;;; -06AD;ARABIC LETTER NG;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS ABOVE;;;; -06AE;ARABIC LETTER KAF WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS BELOW;;;; -06AF;ARABIC LETTER GAF;Lo;0;AL;;;;;N;;;;; -06B0;ARABIC LETTER GAF WITH RING;Lo;0;AL;;;;;N;;;;; -06B1;ARABIC LETTER NGOEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS ABOVE;;;; -06B2;ARABIC LETTER GAF WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;; -06B3;ARABIC LETTER GUEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS VERTICAL BELOW;;;; -06B4;ARABIC LETTER GAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -06B5;ARABIC LETTER LAM WITH SMALL V;Lo;0;AL;;;;;N;;;;; -06B6;ARABIC LETTER LAM WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; -06B7;ARABIC LETTER LAM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -06B8;ARABIC LETTER LAM WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; -06B9;ARABIC LETTER NOON WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; -06BA;ARABIC LETTER NOON GHUNNA;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON;;;; -06BB;ARABIC LETTER RNOON;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON WITH SMALL TAH;;;; -06BC;ARABIC LETTER NOON WITH RING;Lo;0;AL;;;;;N;;;;; -06BD;ARABIC LETTER NOON WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -06BE;ARABIC LETTER HEH DOACHASHMEE;Lo;0;AL;;;;;N;ARABIC LETTER KNOTTED HA;;;; -06BF;ARABIC LETTER TCHEH WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; -06C0;ARABIC LETTER HEH WITH YEH ABOVE;Lo;0;AL;06D5 0654;;;;N;ARABIC LETTER HAMZAH ON HA;;;; -06C1;ARABIC LETTER HEH GOAL;Lo;0;AL;;;;;N;ARABIC LETTER HA GOAL;;;; -06C2;ARABIC LETTER HEH GOAL WITH HAMZA ABOVE;Lo;0;AL;06C1 0654;;;;N;ARABIC LETTER HAMZAH ON HA GOAL;;;; -06C3;ARABIC LETTER TEH MARBUTA GOAL;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH GOAL;;;; -06C4;ARABIC LETTER WAW WITH RING;Lo;0;AL;;;;;N;;;;; -06C5;ARABIC LETTER KIRGHIZ OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH BAR;;;; -06C6;ARABIC LETTER OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH SMALL V;;;; -06C7;ARABIC LETTER U;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH DAMMAH;;;; -06C8;ARABIC LETTER YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH ALEF ABOVE;;;; -06C9;ARABIC LETTER KIRGHIZ YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH INVERTED SMALL V;;;; -06CA;ARABIC LETTER WAW WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -06CB;ARABIC LETTER VE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH THREE DOTS ABOVE;;;; -06CC;ARABIC LETTER FARSI YEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS YA;;;; -06CD;ARABIC LETTER YEH WITH TAIL;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TAIL;;;; -06CE;ARABIC LETTER YEH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH SMALL V;;;; -06CF;ARABIC LETTER WAW WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; -06D0;ARABIC LETTER E;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TWO DOTS VERTICAL BELOW;;;; -06D1;ARABIC LETTER YEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH THREE DOTS BELOW;;;; -06D2;ARABIC LETTER YEH BARREE;Lo;0;AL;;;;;N;ARABIC LETTER YA BARREE;;;; -06D3;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE;Lo;0;AL;06D2 0654;;;;N;ARABIC LETTER HAMZAH ON YA BARREE;;;; -06D4;ARABIC FULL STOP;Po;0;AL;;;;;N;ARABIC PERIOD;;;; -06D5;ARABIC LETTER AE;Lo;0;AL;;;;;N;;;;; -06D6;ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;; -06D7;ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;; -06D8;ARABIC SMALL HIGH MEEM INITIAL FORM;Mn;230;NSM;;;;;N;;;;; -06D9;ARABIC SMALL HIGH LAM ALEF;Mn;230;NSM;;;;;N;;;;; -06DA;ARABIC SMALL HIGH JEEM;Mn;230;NSM;;;;;N;;;;; -06DB;ARABIC SMALL HIGH THREE DOTS;Mn;230;NSM;;;;;N;;;;; -06DC;ARABIC SMALL HIGH SEEN;Mn;230;NSM;;;;;N;;;;; -06DD;ARABIC END OF AYAH;Cf;0;AN;;;;;N;;;;; -06DE;ARABIC START OF RUB EL HIZB;So;0;ON;;;;;N;;;;; -06DF;ARABIC SMALL HIGH ROUNDED ZERO;Mn;230;NSM;;;;;N;;;;; -06E0;ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO;Mn;230;NSM;;;;;N;;;;; -06E1;ARABIC SMALL HIGH DOTLESS HEAD OF KHAH;Mn;230;NSM;;;;;N;;;;; -06E2;ARABIC SMALL HIGH MEEM ISOLATED FORM;Mn;230;NSM;;;;;N;;;;; -06E3;ARABIC SMALL LOW SEEN;Mn;220;NSM;;;;;N;;;;; -06E4;ARABIC SMALL HIGH MADDA;Mn;230;NSM;;;;;N;;;;; -06E5;ARABIC SMALL WAW;Lm;0;AL;;;;;N;;;;; -06E6;ARABIC SMALL YEH;Lm;0;AL;;;;;N;;;;; -06E7;ARABIC SMALL HIGH YEH;Mn;230;NSM;;;;;N;;;;; -06E8;ARABIC SMALL HIGH NOON;Mn;230;NSM;;;;;N;;;;; -06E9;ARABIC PLACE OF SAJDAH;So;0;ON;;;;;N;;;;; -06EA;ARABIC EMPTY CENTRE LOW STOP;Mn;220;NSM;;;;;N;;;;; -06EB;ARABIC EMPTY CENTRE HIGH STOP;Mn;230;NSM;;;;;N;;;;; -06EC;ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE;Mn;230;NSM;;;;;N;;;;; -06ED;ARABIC SMALL LOW MEEM;Mn;220;NSM;;;;;N;;;;; -06EE;ARABIC LETTER DAL WITH INVERTED V;Lo;0;AL;;;;;N;;;;; -06EF;ARABIC LETTER REH WITH INVERTED V;Lo;0;AL;;;;;N;;;;; -06F0;EXTENDED ARABIC-INDIC DIGIT ZERO;Nd;0;EN;;0;0;0;N;EASTERN ARABIC-INDIC DIGIT ZERO;;;; -06F1;EXTENDED ARABIC-INDIC DIGIT ONE;Nd;0;EN;;1;1;1;N;EASTERN ARABIC-INDIC DIGIT ONE;;;; -06F2;EXTENDED ARABIC-INDIC DIGIT TWO;Nd;0;EN;;2;2;2;N;EASTERN ARABIC-INDIC DIGIT TWO;;;; -06F3;EXTENDED ARABIC-INDIC DIGIT THREE;Nd;0;EN;;3;3;3;N;EASTERN ARABIC-INDIC DIGIT THREE;;;; -06F4;EXTENDED ARABIC-INDIC DIGIT FOUR;Nd;0;EN;;4;4;4;N;EASTERN ARABIC-INDIC DIGIT FOUR;;;; -06F5;EXTENDED ARABIC-INDIC DIGIT FIVE;Nd;0;EN;;5;5;5;N;EASTERN ARABIC-INDIC DIGIT FIVE;;;; -06F6;EXTENDED ARABIC-INDIC DIGIT SIX;Nd;0;EN;;6;6;6;N;EASTERN ARABIC-INDIC DIGIT SIX;;;; -06F7;EXTENDED ARABIC-INDIC DIGIT SEVEN;Nd;0;EN;;7;7;7;N;EASTERN ARABIC-INDIC DIGIT SEVEN;;;; -06F8;EXTENDED ARABIC-INDIC DIGIT EIGHT;Nd;0;EN;;8;8;8;N;EASTERN ARABIC-INDIC DIGIT EIGHT;;;; -06F9;EXTENDED ARABIC-INDIC DIGIT NINE;Nd;0;EN;;9;9;9;N;EASTERN ARABIC-INDIC DIGIT NINE;;;; -06FA;ARABIC LETTER SHEEN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; -06FB;ARABIC LETTER DAD WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; -06FC;ARABIC LETTER GHAIN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; -06FD;ARABIC SIGN SINDHI AMPERSAND;So;0;AL;;;;;N;;;;; -06FE;ARABIC SIGN SINDHI POSTPOSITION MEN;So;0;AL;;;;;N;;;;; -06FF;ARABIC LETTER HEH WITH INVERTED V;Lo;0;AL;;;;;N;;;;; -0700;SYRIAC END OF PARAGRAPH;Po;0;AL;;;;;N;;;;; -0701;SYRIAC SUPRALINEAR FULL STOP;Po;0;AL;;;;;N;;;;; -0702;SYRIAC SUBLINEAR FULL STOP;Po;0;AL;;;;;N;;;;; -0703;SYRIAC SUPRALINEAR COLON;Po;0;AL;;;;;N;;;;; -0704;SYRIAC SUBLINEAR COLON;Po;0;AL;;;;;N;;;;; -0705;SYRIAC HORIZONTAL COLON;Po;0;AL;;;;;N;;;;; -0706;SYRIAC COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;; -0707;SYRIAC COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;; -0708;SYRIAC SUPRALINEAR COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;; -0709;SYRIAC SUBLINEAR COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;; -070A;SYRIAC CONTRACTION;Po;0;AL;;;;;N;;;;; -070B;SYRIAC HARKLEAN OBELUS;Po;0;AL;;;;;N;;;;; -070C;SYRIAC HARKLEAN METOBELUS;Po;0;AL;;;;;N;;;;; -070D;SYRIAC HARKLEAN ASTERISCUS;Po;0;AL;;;;;N;;;;; -070F;SYRIAC ABBREVIATION MARK;Cf;0;AL;;;;;N;;;;; -0710;SYRIAC LETTER ALAPH;Lo;0;AL;;;;;N;;;;; -0711;SYRIAC LETTER SUPERSCRIPT ALAPH;Mn;36;NSM;;;;;N;;;;; -0712;SYRIAC LETTER BETH;Lo;0;AL;;;;;N;;;;; -0713;SYRIAC LETTER GAMAL;Lo;0;AL;;;;;N;;;;; -0714;SYRIAC LETTER GAMAL GARSHUNI;Lo;0;AL;;;;;N;;;;; -0715;SYRIAC LETTER DALATH;Lo;0;AL;;;;;N;;;;; -0716;SYRIAC LETTER DOTLESS DALATH RISH;Lo;0;AL;;;;;N;;;;; -0717;SYRIAC LETTER HE;Lo;0;AL;;;;;N;;;;; -0718;SYRIAC LETTER WAW;Lo;0;AL;;;;;N;;;;; -0719;SYRIAC LETTER ZAIN;Lo;0;AL;;;;;N;;;;; -071A;SYRIAC LETTER HETH;Lo;0;AL;;;;;N;;;;; -071B;SYRIAC LETTER TETH;Lo;0;AL;;;;;N;;;;; -071C;SYRIAC LETTER TETH GARSHUNI;Lo;0;AL;;;;;N;;;;; -071D;SYRIAC LETTER YUDH;Lo;0;AL;;;;;N;;;;; -071E;SYRIAC LETTER YUDH HE;Lo;0;AL;;;;;N;;;;; -071F;SYRIAC LETTER KAPH;Lo;0;AL;;;;;N;;;;; -0720;SYRIAC LETTER LAMADH;Lo;0;AL;;;;;N;;;;; -0721;SYRIAC LETTER MIM;Lo;0;AL;;;;;N;;;;; -0722;SYRIAC LETTER NUN;Lo;0;AL;;;;;N;;;;; -0723;SYRIAC LETTER SEMKATH;Lo;0;AL;;;;;N;;;;; -0724;SYRIAC LETTER FINAL SEMKATH;Lo;0;AL;;;;;N;;;;; -0725;SYRIAC LETTER E;Lo;0;AL;;;;;N;;;;; -0726;SYRIAC LETTER PE;Lo;0;AL;;;;;N;;;;; -0727;SYRIAC LETTER REVERSED PE;Lo;0;AL;;;;;N;;;;; -0728;SYRIAC LETTER SADHE;Lo;0;AL;;;;;N;;;;; -0729;SYRIAC LETTER QAPH;Lo;0;AL;;;;;N;;;;; -072A;SYRIAC LETTER RISH;Lo;0;AL;;;;;N;;;;; -072B;SYRIAC LETTER SHIN;Lo;0;AL;;;;;N;;;;; -072C;SYRIAC LETTER TAW;Lo;0;AL;;;;;N;;;;; -072D;SYRIAC LETTER PERSIAN BHETH;Lo;0;AL;;;;;N;;;;; -072E;SYRIAC LETTER PERSIAN GHAMAL;Lo;0;AL;;;;;N;;;;; -072F;SYRIAC LETTER PERSIAN DHALATH;Lo;0;AL;;;;;N;;;;; -0730;SYRIAC PTHAHA ABOVE;Mn;230;NSM;;;;;N;;;;; -0731;SYRIAC PTHAHA BELOW;Mn;220;NSM;;;;;N;;;;; -0732;SYRIAC PTHAHA DOTTED;Mn;230;NSM;;;;;N;;;;; -0733;SYRIAC ZQAPHA ABOVE;Mn;230;NSM;;;;;N;;;;; -0734;SYRIAC ZQAPHA BELOW;Mn;220;NSM;;;;;N;;;;; -0735;SYRIAC ZQAPHA DOTTED;Mn;230;NSM;;;;;N;;;;; -0736;SYRIAC RBASA ABOVE;Mn;230;NSM;;;;;N;;;;; -0737;SYRIAC RBASA BELOW;Mn;220;NSM;;;;;N;;;;; -0738;SYRIAC DOTTED ZLAMA HORIZONTAL;Mn;220;NSM;;;;;N;;;;; -0739;SYRIAC DOTTED ZLAMA ANGULAR;Mn;220;NSM;;;;;N;;;;; -073A;SYRIAC HBASA ABOVE;Mn;230;NSM;;;;;N;;;;; -073B;SYRIAC HBASA BELOW;Mn;220;NSM;;;;;N;;;;; -073C;SYRIAC HBASA-ESASA DOTTED;Mn;220;NSM;;;;;N;;;;; -073D;SYRIAC ESASA ABOVE;Mn;230;NSM;;;;;N;;;;; -073E;SYRIAC ESASA BELOW;Mn;220;NSM;;;;;N;;;;; -073F;SYRIAC RWAHA;Mn;230;NSM;;;;;N;;;;; -0740;SYRIAC FEMININE DOT;Mn;230;NSM;;;;;N;;;;; -0741;SYRIAC QUSHSHAYA;Mn;230;NSM;;;;;N;;;;; -0742;SYRIAC RUKKAKHA;Mn;220;NSM;;;;;N;;;;; -0743;SYRIAC TWO VERTICAL DOTS ABOVE;Mn;230;NSM;;;;;N;;;;; -0744;SYRIAC TWO VERTICAL DOTS BELOW;Mn;220;NSM;;;;;N;;;;; -0745;SYRIAC THREE DOTS ABOVE;Mn;230;NSM;;;;;N;;;;; -0746;SYRIAC THREE DOTS BELOW;Mn;220;NSM;;;;;N;;;;; -0747;SYRIAC OBLIQUE LINE ABOVE;Mn;230;NSM;;;;;N;;;;; -0748;SYRIAC OBLIQUE LINE BELOW;Mn;220;NSM;;;;;N;;;;; -0749;SYRIAC MUSIC;Mn;230;NSM;;;;;N;;;;; -074A;SYRIAC BARREKH;Mn;230;NSM;;;;;N;;;;; -074D;SYRIAC LETTER SOGDIAN ZHAIN;Lo;0;AL;;;;;N;;;;; -074E;SYRIAC LETTER SOGDIAN KHAPH;Lo;0;AL;;;;;N;;;;; -074F;SYRIAC LETTER SOGDIAN FE;Lo;0;AL;;;;;N;;;;; -0750;ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW;Lo;0;AL;;;;;N;;;;; -0751;ARABIC LETTER BEH WITH DOT BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -0752;ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;; -0753;ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW AND TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -0754;ARABIC LETTER BEH WITH TWO DOTS BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; -0755;ARABIC LETTER BEH WITH INVERTED SMALL V BELOW;Lo;0;AL;;;;;N;;;;; -0756;ARABIC LETTER BEH WITH SMALL V;Lo;0;AL;;;;;N;;;;; -0757;ARABIC LETTER HAH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -0758;ARABIC LETTER HAH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;; -0759;ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW AND SMALL TAH;Lo;0;AL;;;;;N;;;;; -075A;ARABIC LETTER DAL WITH INVERTED SMALL V BELOW;Lo;0;AL;;;;;N;;;;; -075B;ARABIC LETTER REH WITH STROKE;Lo;0;AL;;;;;N;;;;; -075C;ARABIC LETTER SEEN WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -075D;ARABIC LETTER AIN WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -075E;ARABIC LETTER AIN WITH THREE DOTS POINTING DOWNWARDS ABOVE;Lo;0;AL;;;;;N;;;;; -075F;ARABIC LETTER AIN WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;; -0760;ARABIC LETTER FEH WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;; -0761;ARABIC LETTER FEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;; -0762;ARABIC LETTER KEHEH WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; -0763;ARABIC LETTER KEHEH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -0764;ARABIC LETTER KEHEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;; -0765;ARABIC LETTER MEEM WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; -0766;ARABIC LETTER MEEM WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; -0767;ARABIC LETTER NOON WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;; -0768;ARABIC LETTER NOON WITH SMALL TAH;Lo;0;AL;;;;;N;;;;; -0769;ARABIC LETTER NOON WITH SMALL V;Lo;0;AL;;;;;N;;;;; -076A;ARABIC LETTER LAM WITH BAR;Lo;0;AL;;;;;N;;;;; -076B;ARABIC LETTER REH WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;; -076C;ARABIC LETTER REH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;;;;; -076D;ARABIC LETTER SEEN WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;; -076E;ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH BELOW;Lo;0;AL;;;;;N;;;;; -076F;ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH AND TWO DOTS;Lo;0;AL;;;;;N;;;;; -0770;ARABIC LETTER SEEN WITH SMALL ARABIC LETTER TAH AND TWO DOTS;Lo;0;AL;;;;;N;;;;; -0771;ARABIC LETTER REH WITH SMALL ARABIC LETTER TAH AND TWO DOTS;Lo;0;AL;;;;;N;;;;; -0772;ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH ABOVE;Lo;0;AL;;;;;N;;;;; -0773;ARABIC LETTER ALEF WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;; -0774;ARABIC LETTER ALEF WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;; -0775;ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;; -0776;ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;; -0777;ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT FOUR BELOW;Lo;0;AL;;;;;N;;;;; -0778;ARABIC LETTER WAW WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;; -0779;ARABIC LETTER WAW WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;; -077A;ARABIC LETTER YEH BARREE WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;; -077B;ARABIC LETTER YEH BARREE WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;; -077C;ARABIC LETTER HAH WITH EXTENDED ARABIC-INDIC DIGIT FOUR BELOW;Lo;0;AL;;;;;N;;;;; -077D;ARABIC LETTER SEEN WITH EXTENDED ARABIC-INDIC DIGIT FOUR ABOVE;Lo;0;AL;;;;;N;;;;; -077E;ARABIC LETTER SEEN WITH INVERTED V;Lo;0;AL;;;;;N;;;;; -077F;ARABIC LETTER KAF WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -0780;THAANA LETTER HAA;Lo;0;AL;;;;;N;;;;; -0781;THAANA LETTER SHAVIYANI;Lo;0;AL;;;;;N;;;;; -0782;THAANA LETTER NOONU;Lo;0;AL;;;;;N;;;;; -0783;THAANA LETTER RAA;Lo;0;AL;;;;;N;;;;; -0784;THAANA LETTER BAA;Lo;0;AL;;;;;N;;;;; -0785;THAANA LETTER LHAVIYANI;Lo;0;AL;;;;;N;;;;; -0786;THAANA LETTER KAAFU;Lo;0;AL;;;;;N;;;;; -0787;THAANA LETTER ALIFU;Lo;0;AL;;;;;N;;;;; -0788;THAANA LETTER VAAVU;Lo;0;AL;;;;;N;;;;; -0789;THAANA LETTER MEEMU;Lo;0;AL;;;;;N;;;;; -078A;THAANA LETTER FAAFU;Lo;0;AL;;;;;N;;;;; -078B;THAANA LETTER DHAALU;Lo;0;AL;;;;;N;;;;; -078C;THAANA LETTER THAA;Lo;0;AL;;;;;N;;;;; -078D;THAANA LETTER LAAMU;Lo;0;AL;;;;;N;;;;; -078E;THAANA LETTER GAAFU;Lo;0;AL;;;;;N;;;;; -078F;THAANA LETTER GNAVIYANI;Lo;0;AL;;;;;N;;;;; -0790;THAANA LETTER SEENU;Lo;0;AL;;;;;N;;;;; -0791;THAANA LETTER DAVIYANI;Lo;0;AL;;;;;N;;;;; -0792;THAANA LETTER ZAVIYANI;Lo;0;AL;;;;;N;;;;; -0793;THAANA LETTER TAVIYANI;Lo;0;AL;;;;;N;;;;; -0794;THAANA LETTER YAA;Lo;0;AL;;;;;N;;;;; -0795;THAANA LETTER PAVIYANI;Lo;0;AL;;;;;N;;;;; -0796;THAANA LETTER JAVIYANI;Lo;0;AL;;;;;N;;;;; -0797;THAANA LETTER CHAVIYANI;Lo;0;AL;;;;;N;;;;; -0798;THAANA LETTER TTAA;Lo;0;AL;;;;;N;;;;; -0799;THAANA LETTER HHAA;Lo;0;AL;;;;;N;;;;; -079A;THAANA LETTER KHAA;Lo;0;AL;;;;;N;;;;; -079B;THAANA LETTER THAALU;Lo;0;AL;;;;;N;;;;; -079C;THAANA LETTER ZAA;Lo;0;AL;;;;;N;;;;; -079D;THAANA LETTER SHEENU;Lo;0;AL;;;;;N;;;;; -079E;THAANA LETTER SAADHU;Lo;0;AL;;;;;N;;;;; -079F;THAANA LETTER DAADHU;Lo;0;AL;;;;;N;;;;; -07A0;THAANA LETTER TO;Lo;0;AL;;;;;N;;;;; -07A1;THAANA LETTER ZO;Lo;0;AL;;;;;N;;;;; -07A2;THAANA LETTER AINU;Lo;0;AL;;;;;N;;;;; -07A3;THAANA LETTER GHAINU;Lo;0;AL;;;;;N;;;;; -07A4;THAANA LETTER QAAFU;Lo;0;AL;;;;;N;;;;; -07A5;THAANA LETTER WAAVU;Lo;0;AL;;;;;N;;;;; -07A6;THAANA ABAFILI;Mn;0;NSM;;;;;N;;;;; -07A7;THAANA AABAAFILI;Mn;0;NSM;;;;;N;;;;; -07A8;THAANA IBIFILI;Mn;0;NSM;;;;;N;;;;; -07A9;THAANA EEBEEFILI;Mn;0;NSM;;;;;N;;;;; -07AA;THAANA UBUFILI;Mn;0;NSM;;;;;N;;;;; -07AB;THAANA OOBOOFILI;Mn;0;NSM;;;;;N;;;;; -07AC;THAANA EBEFILI;Mn;0;NSM;;;;;N;;;;; -07AD;THAANA EYBEYFILI;Mn;0;NSM;;;;;N;;;;; -07AE;THAANA OBOFILI;Mn;0;NSM;;;;;N;;;;; -07AF;THAANA OABOAFILI;Mn;0;NSM;;;;;N;;;;; -07B0;THAANA SUKUN;Mn;0;NSM;;;;;N;;;;; -07B1;THAANA LETTER NAA;Lo;0;AL;;;;;N;;;;; -07C0;NKO DIGIT ZERO;Nd;0;R;;0;0;0;N;;;;; -07C1;NKO DIGIT ONE;Nd;0;R;;1;1;1;N;;;;; -07C2;NKO DIGIT TWO;Nd;0;R;;2;2;2;N;;;;; -07C3;NKO DIGIT THREE;Nd;0;R;;3;3;3;N;;;;; -07C4;NKO DIGIT FOUR;Nd;0;R;;4;4;4;N;;;;; -07C5;NKO DIGIT FIVE;Nd;0;R;;5;5;5;N;;;;; -07C6;NKO DIGIT SIX;Nd;0;R;;6;6;6;N;;;;; -07C7;NKO DIGIT SEVEN;Nd;0;R;;7;7;7;N;;;;; -07C8;NKO DIGIT EIGHT;Nd;0;R;;8;8;8;N;;;;; -07C9;NKO DIGIT NINE;Nd;0;R;;9;9;9;N;;;;; -07CA;NKO LETTER A;Lo;0;R;;;;;N;;;;; -07CB;NKO LETTER EE;Lo;0;R;;;;;N;;;;; -07CC;NKO LETTER I;Lo;0;R;;;;;N;;;;; -07CD;NKO LETTER E;Lo;0;R;;;;;N;;;;; -07CE;NKO LETTER U;Lo;0;R;;;;;N;;;;; -07CF;NKO LETTER OO;Lo;0;R;;;;;N;;;;; -07D0;NKO LETTER O;Lo;0;R;;;;;N;;;;; -07D1;NKO LETTER DAGBASINNA;Lo;0;R;;;;;N;;;;; -07D2;NKO LETTER N;Lo;0;R;;;;;N;;;;; -07D3;NKO LETTER BA;Lo;0;R;;;;;N;;;;; -07D4;NKO LETTER PA;Lo;0;R;;;;;N;;;;; -07D5;NKO LETTER TA;Lo;0;R;;;;;N;;;;; -07D6;NKO LETTER JA;Lo;0;R;;;;;N;;;;; -07D7;NKO LETTER CHA;Lo;0;R;;;;;N;;;;; -07D8;NKO LETTER DA;Lo;0;R;;;;;N;;;;; -07D9;NKO LETTER RA;Lo;0;R;;;;;N;;;;; -07DA;NKO LETTER RRA;Lo;0;R;;;;;N;;;;; -07DB;NKO LETTER SA;Lo;0;R;;;;;N;;;;; -07DC;NKO LETTER GBA;Lo;0;R;;;;;N;;;;; -07DD;NKO LETTER FA;Lo;0;R;;;;;N;;;;; -07DE;NKO LETTER KA;Lo;0;R;;;;;N;;;;; -07DF;NKO LETTER LA;Lo;0;R;;;;;N;;;;; -07E0;NKO LETTER NA WOLOSO;Lo;0;R;;;;;N;;;;; -07E1;NKO LETTER MA;Lo;0;R;;;;;N;;;;; -07E2;NKO LETTER NYA;Lo;0;R;;;;;N;;;;; -07E3;NKO LETTER NA;Lo;0;R;;;;;N;;;;; -07E4;NKO LETTER HA;Lo;0;R;;;;;N;;;;; -07E5;NKO LETTER WA;Lo;0;R;;;;;N;;;;; -07E6;NKO LETTER YA;Lo;0;R;;;;;N;;;;; -07E7;NKO LETTER NYA WOLOSO;Lo;0;R;;;;;N;;;;; -07E8;NKO LETTER JONA JA;Lo;0;R;;;;;N;;;;; -07E9;NKO LETTER JONA CHA;Lo;0;R;;;;;N;;;;; -07EA;NKO LETTER JONA RA;Lo;0;R;;;;;N;;;;; -07EB;NKO COMBINING SHORT HIGH TONE;Mn;230;NSM;;;;;N;;;;; -07EC;NKO COMBINING SHORT LOW TONE;Mn;230;NSM;;;;;N;;;;; -07ED;NKO COMBINING SHORT RISING TONE;Mn;230;NSM;;;;;N;;;;; -07EE;NKO COMBINING LONG DESCENDING TONE;Mn;230;NSM;;;;;N;;;;; -07EF;NKO COMBINING LONG HIGH TONE;Mn;230;NSM;;;;;N;;;;; -07F0;NKO COMBINING LONG LOW TONE;Mn;230;NSM;;;;;N;;;;; -07F1;NKO COMBINING LONG RISING TONE;Mn;230;NSM;;;;;N;;;;; -07F2;NKO COMBINING NASALIZATION MARK;Mn;220;NSM;;;;;N;;;;; -07F3;NKO COMBINING DOUBLE DOT ABOVE;Mn;230;NSM;;;;;N;;;;; -07F4;NKO HIGH TONE APOSTROPHE;Lm;0;R;;;;;N;;;;; -07F5;NKO LOW TONE APOSTROPHE;Lm;0;R;;;;;N;;;;; -07F6;NKO SYMBOL OO DENNEN;So;0;ON;;;;;N;;;;; -07F7;NKO SYMBOL GBAKURUNEN;Po;0;ON;;;;;N;;;;; -07F8;NKO COMMA;Po;0;ON;;;;;N;;;;; -07F9;NKO EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; -07FA;NKO LAJANYALAN;Lm;0;R;;;;;N;;;;; -07FD;NKO DANTAYALAN;Mn;220;NSM;;;;;N;;;;; -07FE;NKO DOROME SIGN;Sc;0;R;;;;;N;;;;; -07FF;NKO TAMAN SIGN;Sc;0;R;;;;;N;;;;; -0800;SAMARITAN LETTER ALAF;Lo;0;R;;;;;N;;;;; -0801;SAMARITAN LETTER BIT;Lo;0;R;;;;;N;;;;; -0802;SAMARITAN LETTER GAMAN;Lo;0;R;;;;;N;;;;; -0803;SAMARITAN LETTER DALAT;Lo;0;R;;;;;N;;;;; -0804;SAMARITAN LETTER IY;Lo;0;R;;;;;N;;;;; -0805;SAMARITAN LETTER BAA;Lo;0;R;;;;;N;;;;; -0806;SAMARITAN LETTER ZEN;Lo;0;R;;;;;N;;;;; -0807;SAMARITAN LETTER IT;Lo;0;R;;;;;N;;;;; -0808;SAMARITAN LETTER TIT;Lo;0;R;;;;;N;;;;; -0809;SAMARITAN LETTER YUT;Lo;0;R;;;;;N;;;;; -080A;SAMARITAN LETTER KAAF;Lo;0;R;;;;;N;;;;; -080B;SAMARITAN LETTER LABAT;Lo;0;R;;;;;N;;;;; -080C;SAMARITAN LETTER MIM;Lo;0;R;;;;;N;;;;; -080D;SAMARITAN LETTER NUN;Lo;0;R;;;;;N;;;;; -080E;SAMARITAN LETTER SINGAAT;Lo;0;R;;;;;N;;;;; -080F;SAMARITAN LETTER IN;Lo;0;R;;;;;N;;;;; -0810;SAMARITAN LETTER FI;Lo;0;R;;;;;N;;;;; -0811;SAMARITAN LETTER TSAADIY;Lo;0;R;;;;;N;;;;; -0812;SAMARITAN LETTER QUF;Lo;0;R;;;;;N;;;;; -0813;SAMARITAN LETTER RISH;Lo;0;R;;;;;N;;;;; -0814;SAMARITAN LETTER SHAN;Lo;0;R;;;;;N;;;;; -0815;SAMARITAN LETTER TAAF;Lo;0;R;;;;;N;;;;; -0816;SAMARITAN MARK IN;Mn;230;NSM;;;;;N;;;;; -0817;SAMARITAN MARK IN-ALAF;Mn;230;NSM;;;;;N;;;;; -0818;SAMARITAN MARK OCCLUSION;Mn;230;NSM;;;;;N;;;;; -0819;SAMARITAN MARK DAGESH;Mn;230;NSM;;;;;N;;;;; -081A;SAMARITAN MODIFIER LETTER EPENTHETIC YUT;Lm;0;R;;;;;N;;;;; -081B;SAMARITAN MARK EPENTHETIC YUT;Mn;230;NSM;;;;;N;;;;; -081C;SAMARITAN VOWEL SIGN LONG E;Mn;230;NSM;;;;;N;;;;; -081D;SAMARITAN VOWEL SIGN E;Mn;230;NSM;;;;;N;;;;; -081E;SAMARITAN VOWEL SIGN OVERLONG AA;Mn;230;NSM;;;;;N;;;;; -081F;SAMARITAN VOWEL SIGN LONG AA;Mn;230;NSM;;;;;N;;;;; -0820;SAMARITAN VOWEL SIGN AA;Mn;230;NSM;;;;;N;;;;; -0821;SAMARITAN VOWEL SIGN OVERLONG A;Mn;230;NSM;;;;;N;;;;; -0822;SAMARITAN VOWEL SIGN LONG A;Mn;230;NSM;;;;;N;;;;; -0823;SAMARITAN VOWEL SIGN A;Mn;230;NSM;;;;;N;;;;; -0824;SAMARITAN MODIFIER LETTER SHORT A;Lm;0;R;;;;;N;;;;; -0825;SAMARITAN VOWEL SIGN SHORT A;Mn;230;NSM;;;;;N;;;;; -0826;SAMARITAN VOWEL SIGN LONG U;Mn;230;NSM;;;;;N;;;;; -0827;SAMARITAN VOWEL SIGN U;Mn;230;NSM;;;;;N;;;;; -0828;SAMARITAN MODIFIER LETTER I;Lm;0;R;;;;;N;;;;; -0829;SAMARITAN VOWEL SIGN LONG I;Mn;230;NSM;;;;;N;;;;; -082A;SAMARITAN VOWEL SIGN I;Mn;230;NSM;;;;;N;;;;; -082B;SAMARITAN VOWEL SIGN O;Mn;230;NSM;;;;;N;;;;; -082C;SAMARITAN VOWEL SIGN SUKUN;Mn;230;NSM;;;;;N;;;;; -082D;SAMARITAN MARK NEQUDAA;Mn;230;NSM;;;;;N;;;;; -0830;SAMARITAN PUNCTUATION NEQUDAA;Po;0;R;;;;;N;;;;; -0831;SAMARITAN PUNCTUATION AFSAAQ;Po;0;R;;;;;N;;;;; -0832;SAMARITAN PUNCTUATION ANGED;Po;0;R;;;;;N;;;;; -0833;SAMARITAN PUNCTUATION BAU;Po;0;R;;;;;N;;;;; -0834;SAMARITAN PUNCTUATION ATMAAU;Po;0;R;;;;;N;;;;; -0835;SAMARITAN PUNCTUATION SHIYYAALAA;Po;0;R;;;;;N;;;;; -0836;SAMARITAN ABBREVIATION MARK;Po;0;R;;;;;N;;;;; -0837;SAMARITAN PUNCTUATION MELODIC QITSA;Po;0;R;;;;;N;;;;; -0838;SAMARITAN PUNCTUATION ZIQAA;Po;0;R;;;;;N;;;;; -0839;SAMARITAN PUNCTUATION QITSA;Po;0;R;;;;;N;;;;; -083A;SAMARITAN PUNCTUATION ZAEF;Po;0;R;;;;;N;;;;; -083B;SAMARITAN PUNCTUATION TURU;Po;0;R;;;;;N;;;;; -083C;SAMARITAN PUNCTUATION ARKAANU;Po;0;R;;;;;N;;;;; -083D;SAMARITAN PUNCTUATION SOF MASHFAAT;Po;0;R;;;;;N;;;;; -083E;SAMARITAN PUNCTUATION ANNAAU;Po;0;R;;;;;N;;;;; -0840;MANDAIC LETTER HALQA;Lo;0;R;;;;;N;;;;; -0841;MANDAIC LETTER AB;Lo;0;R;;;;;N;;;;; -0842;MANDAIC LETTER AG;Lo;0;R;;;;;N;;;;; -0843;MANDAIC LETTER AD;Lo;0;R;;;;;N;;;;; -0844;MANDAIC LETTER AH;Lo;0;R;;;;;N;;;;; -0845;MANDAIC LETTER USHENNA;Lo;0;R;;;;;N;;;;; -0846;MANDAIC LETTER AZ;Lo;0;R;;;;;N;;;;; -0847;MANDAIC LETTER IT;Lo;0;R;;;;;N;;;;; -0848;MANDAIC LETTER ATT;Lo;0;R;;;;;N;;;;; -0849;MANDAIC LETTER AKSA;Lo;0;R;;;;;N;;;;; -084A;MANDAIC LETTER AK;Lo;0;R;;;;;N;;;;; -084B;MANDAIC LETTER AL;Lo;0;R;;;;;N;;;;; -084C;MANDAIC LETTER AM;Lo;0;R;;;;;N;;;;; -084D;MANDAIC LETTER AN;Lo;0;R;;;;;N;;;;; -084E;MANDAIC LETTER AS;Lo;0;R;;;;;N;;;;; -084F;MANDAIC LETTER IN;Lo;0;R;;;;;N;;;;; -0850;MANDAIC LETTER AP;Lo;0;R;;;;;N;;;;; -0851;MANDAIC LETTER ASZ;Lo;0;R;;;;;N;;;;; -0852;MANDAIC LETTER AQ;Lo;0;R;;;;;N;;;;; -0853;MANDAIC LETTER AR;Lo;0;R;;;;;N;;;;; -0854;MANDAIC LETTER ASH;Lo;0;R;;;;;N;;;;; -0855;MANDAIC LETTER AT;Lo;0;R;;;;;N;;;;; -0856;MANDAIC LETTER DUSHENNA;Lo;0;R;;;;;N;;;;; -0857;MANDAIC LETTER KAD;Lo;0;R;;;;;N;;;;; -0858;MANDAIC LETTER AIN;Lo;0;R;;;;;N;;;;; -0859;MANDAIC AFFRICATION MARK;Mn;220;NSM;;;;;N;;;;; -085A;MANDAIC VOCALIZATION MARK;Mn;220;NSM;;;;;N;;;;; -085B;MANDAIC GEMINATION MARK;Mn;220;NSM;;;;;N;;;;; -085E;MANDAIC PUNCTUATION;Po;0;R;;;;;N;;;;; -0860;SYRIAC LETTER MALAYALAM NGA;Lo;0;AL;;;;;N;;;;; -0861;SYRIAC LETTER MALAYALAM JA;Lo;0;AL;;;;;N;;;;; -0862;SYRIAC LETTER MALAYALAM NYA;Lo;0;AL;;;;;N;;;;; -0863;SYRIAC LETTER MALAYALAM TTA;Lo;0;AL;;;;;N;;;;; -0864;SYRIAC LETTER MALAYALAM NNA;Lo;0;AL;;;;;N;;;;; -0865;SYRIAC LETTER MALAYALAM NNNA;Lo;0;AL;;;;;N;;;;; -0866;SYRIAC LETTER MALAYALAM BHA;Lo;0;AL;;;;;N;;;;; -0867;SYRIAC LETTER MALAYALAM RA;Lo;0;AL;;;;;N;;;;; -0868;SYRIAC LETTER MALAYALAM LLA;Lo;0;AL;;;;;N;;;;; -0869;SYRIAC LETTER MALAYALAM LLLA;Lo;0;AL;;;;;N;;;;; -086A;SYRIAC LETTER MALAYALAM SSA;Lo;0;AL;;;;;N;;;;; -0870;ARABIC LETTER ALEF WITH ATTACHED FATHA;Lo;0;AL;;;;;N;;;;; -0871;ARABIC LETTER ALEF WITH ATTACHED TOP RIGHT FATHA;Lo;0;AL;;;;;N;;;;; -0872;ARABIC LETTER ALEF WITH RIGHT MIDDLE STROKE;Lo;0;AL;;;;;N;;;;; -0873;ARABIC LETTER ALEF WITH LEFT MIDDLE STROKE;Lo;0;AL;;;;;N;;;;; -0874;ARABIC LETTER ALEF WITH ATTACHED KASRA;Lo;0;AL;;;;;N;;;;; -0875;ARABIC LETTER ALEF WITH ATTACHED BOTTOM RIGHT KASRA;Lo;0;AL;;;;;N;;;;; -0876;ARABIC LETTER ALEF WITH ATTACHED ROUND DOT ABOVE;Lo;0;AL;;;;;N;;;;; -0877;ARABIC LETTER ALEF WITH ATTACHED RIGHT ROUND DOT;Lo;0;AL;;;;;N;;;;; -0878;ARABIC LETTER ALEF WITH ATTACHED LEFT ROUND DOT;Lo;0;AL;;;;;N;;;;; -0879;ARABIC LETTER ALEF WITH ATTACHED ROUND DOT BELOW;Lo;0;AL;;;;;N;;;;; -087A;ARABIC LETTER ALEF WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; -087B;ARABIC LETTER ALEF WITH ATTACHED TOP RIGHT FATHA AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; -087C;ARABIC LETTER ALEF WITH RIGHT MIDDLE STROKE AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; -087D;ARABIC LETTER ALEF WITH ATTACHED BOTTOM RIGHT KASRA AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; -087E;ARABIC LETTER ALEF WITH ATTACHED TOP RIGHT FATHA AND LEFT RING;Lo;0;AL;;;;;N;;;;; -087F;ARABIC LETTER ALEF WITH RIGHT MIDDLE STROKE AND LEFT RING;Lo;0;AL;;;;;N;;;;; -0880;ARABIC LETTER ALEF WITH ATTACHED BOTTOM RIGHT KASRA AND LEFT RING;Lo;0;AL;;;;;N;;;;; -0881;ARABIC LETTER ALEF WITH ATTACHED RIGHT HAMZA;Lo;0;AL;;;;;N;;;;; -0882;ARABIC LETTER ALEF WITH ATTACHED LEFT HAMZA;Lo;0;AL;;;;;N;;;;; -0883;ARABIC TATWEEL WITH OVERSTRUCK HAMZA;Lo;0;AL;;;;;N;;;;; -0884;ARABIC TATWEEL WITH OVERSTRUCK WAW;Lo;0;AL;;;;;N;;;;; -0885;ARABIC TATWEEL WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;; -0886;ARABIC LETTER THIN YEH;Lo;0;AL;;;;;N;;;;; -0887;ARABIC BASELINE ROUND DOT;Lo;0;AL;;;;;N;;;;; -0888;ARABIC RAISED ROUND DOT;Sk;0;AL;;;;;N;;;;; -0889;ARABIC LETTER NOON WITH INVERTED SMALL V;Lo;0;AL;;;;;N;;;;; -088A;ARABIC LETTER HAH WITH INVERTED SMALL V BELOW;Lo;0;AL;;;;;N;;;;; -088B;ARABIC LETTER TAH WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; -088C;ARABIC LETTER TAH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; -088D;ARABIC LETTER KEHEH WITH TWO DOTS VERTICALLY BELOW;Lo;0;AL;;;;;N;;;;; -088E;ARABIC VERTICAL TAIL;Lo;0;AL;;;;;N;;;;; -0890;ARABIC POUND MARK ABOVE;Cf;0;AN;;;;;N;;;;; -0891;ARABIC PIASTRE MARK ABOVE;Cf;0;AN;;;;;N;;;;; -0898;ARABIC SMALL HIGH WORD AL-JUZ;Mn;230;NSM;;;;;N;;;;; -0899;ARABIC SMALL LOW WORD ISHMAAM;Mn;220;NSM;;;;;N;;;;; -089A;ARABIC SMALL LOW WORD IMAALA;Mn;220;NSM;;;;;N;;;;; -089B;ARABIC SMALL LOW WORD TASHEEL;Mn;220;NSM;;;;;N;;;;; -089C;ARABIC MADDA WAAJIB;Mn;230;NSM;;;;;N;;;;; -089D;ARABIC SUPERSCRIPT ALEF MOKHASSAS;Mn;230;NSM;;;;;N;;;;; -089E;ARABIC DOUBLED MADDA;Mn;230;NSM;;;;;N;;;;; -089F;ARABIC HALF MADDA OVER MADDA;Mn;230;NSM;;;;;N;;;;; -08A0;ARABIC LETTER BEH WITH SMALL V BELOW;Lo;0;AL;;;;;N;;;;; -08A1;ARABIC LETTER BEH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;;;;; -08A2;ARABIC LETTER JEEM WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -08A3;ARABIC LETTER TAH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -08A4;ARABIC LETTER FEH WITH DOT BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -08A5;ARABIC LETTER QAF WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; -08A6;ARABIC LETTER LAM WITH DOUBLE BAR;Lo;0;AL;;;;;N;;;;; -08A7;ARABIC LETTER MEEM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -08A8;ARABIC LETTER YEH WITH TWO DOTS BELOW AND HAMZA ABOVE;Lo;0;AL;;;;;N;;;;; -08A9;ARABIC LETTER YEH WITH TWO DOTS BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; -08AA;ARABIC LETTER REH WITH LOOP;Lo;0;AL;;;;;N;;;;; -08AB;ARABIC LETTER WAW WITH DOT WITHIN;Lo;0;AL;;;;;N;;;;; -08AC;ARABIC LETTER ROHINGYA YEH;Lo;0;AL;;;;;N;;;;; -08AD;ARABIC LETTER LOW ALEF;Lo;0;AL;;;;;N;;;;; -08AE;ARABIC LETTER DAL WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; -08AF;ARABIC LETTER SAD WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; -08B0;ARABIC LETTER GAF WITH INVERTED STROKE;Lo;0;AL;;;;;N;;;;; -08B1;ARABIC LETTER STRAIGHT WAW;Lo;0;AL;;;;;N;;;;; -08B2;ARABIC LETTER ZAIN WITH INVERTED V ABOVE;Lo;0;AL;;;;;N;;;;; -08B3;ARABIC LETTER AIN WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; -08B4;ARABIC LETTER KAF WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; -08B5;ARABIC LETTER QAF WITH DOT BELOW AND NO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -08B6;ARABIC LETTER BEH WITH SMALL MEEM ABOVE;Lo;0;AL;;;;;N;;;;; -08B7;ARABIC LETTER PEH WITH SMALL MEEM ABOVE;Lo;0;AL;;;;;N;;;;; -08B8;ARABIC LETTER TEH WITH SMALL TEH ABOVE;Lo;0;AL;;;;;N;;;;; -08B9;ARABIC LETTER REH WITH SMALL NOON ABOVE;Lo;0;AL;;;;;N;;;;; -08BA;ARABIC LETTER YEH WITH TWO DOTS BELOW AND SMALL NOON ABOVE;Lo;0;AL;;;;;N;;;;; -08BB;ARABIC LETTER AFRICAN FEH;Lo;0;AL;;;;;N;;;;; -08BC;ARABIC LETTER AFRICAN QAF;Lo;0;AL;;;;;N;;;;; -08BD;ARABIC LETTER AFRICAN NOON;Lo;0;AL;;;;;N;;;;; -08BE;ARABIC LETTER PEH WITH SMALL V;Lo;0;AL;;;;;N;;;;; -08BF;ARABIC LETTER TEH WITH SMALL V;Lo;0;AL;;;;;N;;;;; -08C0;ARABIC LETTER TTEH WITH SMALL V;Lo;0;AL;;;;;N;;;;; -08C1;ARABIC LETTER TCHEH WITH SMALL V;Lo;0;AL;;;;;N;;;;; -08C2;ARABIC LETTER KEHEH WITH SMALL V;Lo;0;AL;;;;;N;;;;; -08C3;ARABIC LETTER GHAIN WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -08C4;ARABIC LETTER AFRICAN QAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -08C5;ARABIC LETTER JEEM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; -08C6;ARABIC LETTER JEEM WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; -08C7;ARABIC LETTER LAM WITH SMALL ARABIC LETTER TAH ABOVE;Lo;0;AL;;;;;N;;;;; -08C8;ARABIC LETTER GRAF;Lo;0;AL;;;;;N;;;;; -08C9;ARABIC SMALL FARSI YEH;Lm;0;AL;;;;;N;;;;; -08CA;ARABIC SMALL HIGH FARSI YEH;Mn;230;NSM;;;;;N;;;;; -08CB;ARABIC SMALL HIGH YEH BARREE WITH TWO DOTS BELOW;Mn;230;NSM;;;;;N;;;;; -08CC;ARABIC SMALL HIGH WORD SAH;Mn;230;NSM;;;;;N;;;;; -08CD;ARABIC SMALL HIGH ZAH;Mn;230;NSM;;;;;N;;;;; -08CE;ARABIC LARGE ROUND DOT ABOVE;Mn;230;NSM;;;;;N;;;;; -08CF;ARABIC LARGE ROUND DOT BELOW;Mn;220;NSM;;;;;N;;;;; -08D0;ARABIC SUKUN BELOW;Mn;220;NSM;;;;;N;;;;; -08D1;ARABIC LARGE CIRCLE BELOW;Mn;220;NSM;;;;;N;;;;; -08D2;ARABIC LARGE ROUND DOT INSIDE CIRCLE BELOW;Mn;220;NSM;;;;;N;;;;; -08D3;ARABIC SMALL LOW WAW;Mn;220;NSM;;;;;N;;;;; -08D4;ARABIC SMALL HIGH WORD AR-RUB;Mn;230;NSM;;;;;N;;;;; -08D5;ARABIC SMALL HIGH SAD;Mn;230;NSM;;;;;N;;;;; -08D6;ARABIC SMALL HIGH AIN;Mn;230;NSM;;;;;N;;;;; -08D7;ARABIC SMALL HIGH QAF;Mn;230;NSM;;;;;N;;;;; -08D8;ARABIC SMALL HIGH NOON WITH KASRA;Mn;230;NSM;;;;;N;;;;; -08D9;ARABIC SMALL LOW NOON WITH KASRA;Mn;230;NSM;;;;;N;;;;; -08DA;ARABIC SMALL HIGH WORD ATH-THALATHA;Mn;230;NSM;;;;;N;;;;; -08DB;ARABIC SMALL HIGH WORD AS-SAJDA;Mn;230;NSM;;;;;N;;;;; -08DC;ARABIC SMALL HIGH WORD AN-NISF;Mn;230;NSM;;;;;N;;;;; -08DD;ARABIC SMALL HIGH WORD SAKTA;Mn;230;NSM;;;;;N;;;;; -08DE;ARABIC SMALL HIGH WORD QIF;Mn;230;NSM;;;;;N;;;;; -08DF;ARABIC SMALL HIGH WORD WAQFA;Mn;230;NSM;;;;;N;;;;; -08E0;ARABIC SMALL HIGH FOOTNOTE MARKER;Mn;230;NSM;;;;;N;;;;; -08E1;ARABIC SMALL HIGH SIGN SAFHA;Mn;230;NSM;;;;;N;;;;; -08E2;ARABIC DISPUTED END OF AYAH;Cf;0;AN;;;;;N;;;;; -08E3;ARABIC TURNED DAMMA BELOW;Mn;220;NSM;;;;;N;;;;; -08E4;ARABIC CURLY FATHA;Mn;230;NSM;;;;;N;;;;; -08E5;ARABIC CURLY DAMMA;Mn;230;NSM;;;;;N;;;;; -08E6;ARABIC CURLY KASRA;Mn;220;NSM;;;;;N;;;;; -08E7;ARABIC CURLY FATHATAN;Mn;230;NSM;;;;;N;;;;; -08E8;ARABIC CURLY DAMMATAN;Mn;230;NSM;;;;;N;;;;; -08E9;ARABIC CURLY KASRATAN;Mn;220;NSM;;;;;N;;;;; -08EA;ARABIC TONE ONE DOT ABOVE;Mn;230;NSM;;;;;N;;;;; -08EB;ARABIC TONE TWO DOTS ABOVE;Mn;230;NSM;;;;;N;;;;; -08EC;ARABIC TONE LOOP ABOVE;Mn;230;NSM;;;;;N;;;;; -08ED;ARABIC TONE ONE DOT BELOW;Mn;220;NSM;;;;;N;;;;; -08EE;ARABIC TONE TWO DOTS BELOW;Mn;220;NSM;;;;;N;;;;; -08EF;ARABIC TONE LOOP BELOW;Mn;220;NSM;;;;;N;;;;; -08F0;ARABIC OPEN FATHATAN;Mn;27;NSM;;;;;N;;;;; -08F1;ARABIC OPEN DAMMATAN;Mn;28;NSM;;;;;N;;;;; -08F2;ARABIC OPEN KASRATAN;Mn;29;NSM;;;;;N;;;;; -08F3;ARABIC SMALL HIGH WAW;Mn;230;NSM;;;;;N;;;;; -08F4;ARABIC FATHA WITH RING;Mn;230;NSM;;;;;N;;;;; -08F5;ARABIC FATHA WITH DOT ABOVE;Mn;230;NSM;;;;;N;;;;; -08F6;ARABIC KASRA WITH DOT BELOW;Mn;220;NSM;;;;;N;;;;; -08F7;ARABIC LEFT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;; -08F8;ARABIC RIGHT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;; -08F9;ARABIC LEFT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; -08FA;ARABIC RIGHT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; -08FB;ARABIC DOUBLE RIGHT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;; -08FC;ARABIC DOUBLE RIGHT ARROWHEAD ABOVE WITH DOT;Mn;230;NSM;;;;;N;;;;; -08FD;ARABIC RIGHT ARROWHEAD ABOVE WITH DOT;Mn;230;NSM;;;;;N;;;;; -08FE;ARABIC DAMMA WITH DOT;Mn;230;NSM;;;;;N;;;;; -08FF;ARABIC MARK SIDEWAYS NOON GHUNNA;Mn;230;NSM;;;;;N;;;;; -0900;DEVANAGARI SIGN INVERTED CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -0901;DEVANAGARI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -0902;DEVANAGARI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -0903;DEVANAGARI SIGN VISARGA;Mc;0;L;;;;;N;;;;; -0904;DEVANAGARI LETTER SHORT A;Lo;0;L;;;;;N;;;;; -0905;DEVANAGARI LETTER A;Lo;0;L;;;;;N;;;;; -0906;DEVANAGARI LETTER AA;Lo;0;L;;;;;N;;;;; -0907;DEVANAGARI LETTER I;Lo;0;L;;;;;N;;;;; -0908;DEVANAGARI LETTER II;Lo;0;L;;;;;N;;;;; -0909;DEVANAGARI LETTER U;Lo;0;L;;;;;N;;;;; -090A;DEVANAGARI LETTER UU;Lo;0;L;;;;;N;;;;; -090B;DEVANAGARI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; -090C;DEVANAGARI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; -090D;DEVANAGARI LETTER CANDRA E;Lo;0;L;;;;;N;;;;; -090E;DEVANAGARI LETTER SHORT E;Lo;0;L;;;;;N;;;;; -090F;DEVANAGARI LETTER E;Lo;0;L;;;;;N;;;;; -0910;DEVANAGARI LETTER AI;Lo;0;L;;;;;N;;;;; -0911;DEVANAGARI LETTER CANDRA O;Lo;0;L;;;;;N;;;;; -0912;DEVANAGARI LETTER SHORT O;Lo;0;L;;;;;N;;;;; -0913;DEVANAGARI LETTER O;Lo;0;L;;;;;N;;;;; -0914;DEVANAGARI LETTER AU;Lo;0;L;;;;;N;;;;; -0915;DEVANAGARI LETTER KA;Lo;0;L;;;;;N;;;;; -0916;DEVANAGARI LETTER KHA;Lo;0;L;;;;;N;;;;; -0917;DEVANAGARI LETTER GA;Lo;0;L;;;;;N;;;;; -0918;DEVANAGARI LETTER GHA;Lo;0;L;;;;;N;;;;; -0919;DEVANAGARI LETTER NGA;Lo;0;L;;;;;N;;;;; -091A;DEVANAGARI LETTER CA;Lo;0;L;;;;;N;;;;; -091B;DEVANAGARI LETTER CHA;Lo;0;L;;;;;N;;;;; -091C;DEVANAGARI LETTER JA;Lo;0;L;;;;;N;;;;; -091D;DEVANAGARI LETTER JHA;Lo;0;L;;;;;N;;;;; -091E;DEVANAGARI LETTER NYA;Lo;0;L;;;;;N;;;;; -091F;DEVANAGARI LETTER TTA;Lo;0;L;;;;;N;;;;; -0920;DEVANAGARI LETTER TTHA;Lo;0;L;;;;;N;;;;; -0921;DEVANAGARI LETTER DDA;Lo;0;L;;;;;N;;;;; -0922;DEVANAGARI LETTER DDHA;Lo;0;L;;;;;N;;;;; -0923;DEVANAGARI LETTER NNA;Lo;0;L;;;;;N;;;;; -0924;DEVANAGARI LETTER TA;Lo;0;L;;;;;N;;;;; -0925;DEVANAGARI LETTER THA;Lo;0;L;;;;;N;;;;; -0926;DEVANAGARI LETTER DA;Lo;0;L;;;;;N;;;;; -0927;DEVANAGARI LETTER DHA;Lo;0;L;;;;;N;;;;; -0928;DEVANAGARI LETTER NA;Lo;0;L;;;;;N;;;;; -0929;DEVANAGARI LETTER NNNA;Lo;0;L;0928 093C;;;;N;;;;; -092A;DEVANAGARI LETTER PA;Lo;0;L;;;;;N;;;;; -092B;DEVANAGARI LETTER PHA;Lo;0;L;;;;;N;;;;; -092C;DEVANAGARI LETTER BA;Lo;0;L;;;;;N;;;;; -092D;DEVANAGARI LETTER BHA;Lo;0;L;;;;;N;;;;; -092E;DEVANAGARI LETTER MA;Lo;0;L;;;;;N;;;;; -092F;DEVANAGARI LETTER YA;Lo;0;L;;;;;N;;;;; -0930;DEVANAGARI LETTER RA;Lo;0;L;;;;;N;;;;; -0931;DEVANAGARI LETTER RRA;Lo;0;L;0930 093C;;;;N;;;;; -0932;DEVANAGARI LETTER LA;Lo;0;L;;;;;N;;;;; -0933;DEVANAGARI LETTER LLA;Lo;0;L;;;;;N;;;;; -0934;DEVANAGARI LETTER LLLA;Lo;0;L;0933 093C;;;;N;;;;; -0935;DEVANAGARI LETTER VA;Lo;0;L;;;;;N;;;;; -0936;DEVANAGARI LETTER SHA;Lo;0;L;;;;;N;;;;; -0937;DEVANAGARI LETTER SSA;Lo;0;L;;;;;N;;;;; -0938;DEVANAGARI LETTER SA;Lo;0;L;;;;;N;;;;; -0939;DEVANAGARI LETTER HA;Lo;0;L;;;;;N;;;;; -093A;DEVANAGARI VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;; -093B;DEVANAGARI VOWEL SIGN OOE;Mc;0;L;;;;;N;;;;; -093C;DEVANAGARI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -093D;DEVANAGARI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; -093E;DEVANAGARI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -093F;DEVANAGARI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -0940;DEVANAGARI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -0941;DEVANAGARI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -0942;DEVANAGARI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -0943;DEVANAGARI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -0944;DEVANAGARI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; -0945;DEVANAGARI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;; -0946;DEVANAGARI VOWEL SIGN SHORT E;Mn;0;NSM;;;;;N;;;;; -0947;DEVANAGARI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -0948;DEVANAGARI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -0949;DEVANAGARI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;; -094A;DEVANAGARI VOWEL SIGN SHORT O;Mc;0;L;;;;;N;;;;; -094B;DEVANAGARI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; -094C;DEVANAGARI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; -094D;DEVANAGARI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -094E;DEVANAGARI VOWEL SIGN PRISHTHAMATRA E;Mc;0;L;;;;;N;;;;; -094F;DEVANAGARI VOWEL SIGN AW;Mc;0;L;;;;;N;;;;; -0950;DEVANAGARI OM;Lo;0;L;;;;;N;;;;; -0951;DEVANAGARI STRESS SIGN UDATTA;Mn;230;NSM;;;;;N;;;;; -0952;DEVANAGARI STRESS SIGN ANUDATTA;Mn;220;NSM;;;;;N;;;;; -0953;DEVANAGARI GRAVE ACCENT;Mn;230;NSM;;;;;N;;;;; -0954;DEVANAGARI ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;; -0955;DEVANAGARI VOWEL SIGN CANDRA LONG E;Mn;0;NSM;;;;;N;;;;; -0956;DEVANAGARI VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;; -0957;DEVANAGARI VOWEL SIGN UUE;Mn;0;NSM;;;;;N;;;;; -0958;DEVANAGARI LETTER QA;Lo;0;L;0915 093C;;;;N;;;;; -0959;DEVANAGARI LETTER KHHA;Lo;0;L;0916 093C;;;;N;;;;; -095A;DEVANAGARI LETTER GHHA;Lo;0;L;0917 093C;;;;N;;;;; -095B;DEVANAGARI LETTER ZA;Lo;0;L;091C 093C;;;;N;;;;; -095C;DEVANAGARI LETTER DDDHA;Lo;0;L;0921 093C;;;;N;;;;; -095D;DEVANAGARI LETTER RHA;Lo;0;L;0922 093C;;;;N;;;;; -095E;DEVANAGARI LETTER FA;Lo;0;L;092B 093C;;;;N;;;;; -095F;DEVANAGARI LETTER YYA;Lo;0;L;092F 093C;;;;N;;;;; -0960;DEVANAGARI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; -0961;DEVANAGARI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; -0962;DEVANAGARI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; -0963;DEVANAGARI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; -0964;DEVANAGARI DANDA;Po;0;L;;;;;N;;;;; -0965;DEVANAGARI DOUBLE DANDA;Po;0;L;;;;;N;;;;; -0966;DEVANAGARI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -0967;DEVANAGARI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -0968;DEVANAGARI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -0969;DEVANAGARI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -096A;DEVANAGARI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -096B;DEVANAGARI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -096C;DEVANAGARI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -096D;DEVANAGARI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -096E;DEVANAGARI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -096F;DEVANAGARI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -0970;DEVANAGARI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; -0971;DEVANAGARI SIGN HIGH SPACING DOT;Lm;0;L;;;;;N;;;;; -0972;DEVANAGARI LETTER CANDRA A;Lo;0;L;;;;;N;;;;; -0973;DEVANAGARI LETTER OE;Lo;0;L;;;;;N;;;;; -0974;DEVANAGARI LETTER OOE;Lo;0;L;;;;;N;;;;; -0975;DEVANAGARI LETTER AW;Lo;0;L;;;;;N;;;;; -0976;DEVANAGARI LETTER UE;Lo;0;L;;;;;N;;;;; -0977;DEVANAGARI LETTER UUE;Lo;0;L;;;;;N;;;;; -0978;DEVANAGARI LETTER MARWARI DDA;Lo;0;L;;;;;N;;;;; -0979;DEVANAGARI LETTER ZHA;Lo;0;L;;;;;N;;;;; -097A;DEVANAGARI LETTER HEAVY YA;Lo;0;L;;;;;N;;;;; -097B;DEVANAGARI LETTER GGA;Lo;0;L;;;;;N;;;;; -097C;DEVANAGARI LETTER JJA;Lo;0;L;;;;;N;;;;; -097D;DEVANAGARI LETTER GLOTTAL STOP;Lo;0;L;;;;;N;;;;; -097E;DEVANAGARI LETTER DDDA;Lo;0;L;;;;;N;;;;; -097F;DEVANAGARI LETTER BBA;Lo;0;L;;;;;N;;;;; -0980;BENGALI ANJI;Lo;0;L;;;;;N;;;;; -0981;BENGALI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -0982;BENGALI SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; -0983;BENGALI SIGN VISARGA;Mc;0;L;;;;;N;;;;; -0985;BENGALI LETTER A;Lo;0;L;;;;;N;;;;; -0986;BENGALI LETTER AA;Lo;0;L;;;;;N;;;;; -0987;BENGALI LETTER I;Lo;0;L;;;;;N;;;;; -0988;BENGALI LETTER II;Lo;0;L;;;;;N;;;;; -0989;BENGALI LETTER U;Lo;0;L;;;;;N;;;;; -098A;BENGALI LETTER UU;Lo;0;L;;;;;N;;;;; -098B;BENGALI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; -098C;BENGALI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; -098F;BENGALI LETTER E;Lo;0;L;;;;;N;;;;; -0990;BENGALI LETTER AI;Lo;0;L;;;;;N;;;;; -0993;BENGALI LETTER O;Lo;0;L;;;;;N;;;;; -0994;BENGALI LETTER AU;Lo;0;L;;;;;N;;;;; -0995;BENGALI LETTER KA;Lo;0;L;;;;;N;;;;; -0996;BENGALI LETTER KHA;Lo;0;L;;;;;N;;;;; -0997;BENGALI LETTER GA;Lo;0;L;;;;;N;;;;; -0998;BENGALI LETTER GHA;Lo;0;L;;;;;N;;;;; -0999;BENGALI LETTER NGA;Lo;0;L;;;;;N;;;;; -099A;BENGALI LETTER CA;Lo;0;L;;;;;N;;;;; -099B;BENGALI LETTER CHA;Lo;0;L;;;;;N;;;;; -099C;BENGALI LETTER JA;Lo;0;L;;;;;N;;;;; -099D;BENGALI LETTER JHA;Lo;0;L;;;;;N;;;;; -099E;BENGALI LETTER NYA;Lo;0;L;;;;;N;;;;; -099F;BENGALI LETTER TTA;Lo;0;L;;;;;N;;;;; -09A0;BENGALI LETTER TTHA;Lo;0;L;;;;;N;;;;; -09A1;BENGALI LETTER DDA;Lo;0;L;;;;;N;;;;; -09A2;BENGALI LETTER DDHA;Lo;0;L;;;;;N;;;;; -09A3;BENGALI LETTER NNA;Lo;0;L;;;;;N;;;;; -09A4;BENGALI LETTER TA;Lo;0;L;;;;;N;;;;; -09A5;BENGALI LETTER THA;Lo;0;L;;;;;N;;;;; -09A6;BENGALI LETTER DA;Lo;0;L;;;;;N;;;;; -09A7;BENGALI LETTER DHA;Lo;0;L;;;;;N;;;;; -09A8;BENGALI LETTER NA;Lo;0;L;;;;;N;;;;; -09AA;BENGALI LETTER PA;Lo;0;L;;;;;N;;;;; -09AB;BENGALI LETTER PHA;Lo;0;L;;;;;N;;;;; -09AC;BENGALI LETTER BA;Lo;0;L;;;;;N;;;;; -09AD;BENGALI LETTER BHA;Lo;0;L;;;;;N;;;;; -09AE;BENGALI LETTER MA;Lo;0;L;;;;;N;;;;; -09AF;BENGALI LETTER YA;Lo;0;L;;;;;N;;;;; -09B0;BENGALI LETTER RA;Lo;0;L;;;;;N;;;;; -09B2;BENGALI LETTER LA;Lo;0;L;;;;;N;;;;; -09B6;BENGALI LETTER SHA;Lo;0;L;;;;;N;;;;; -09B7;BENGALI LETTER SSA;Lo;0;L;;;;;N;;;;; -09B8;BENGALI LETTER SA;Lo;0;L;;;;;N;;;;; -09B9;BENGALI LETTER HA;Lo;0;L;;;;;N;;;;; -09BC;BENGALI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -09BD;BENGALI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; -09BE;BENGALI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -09BF;BENGALI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -09C0;BENGALI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -09C1;BENGALI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -09C2;BENGALI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -09C3;BENGALI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -09C4;BENGALI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; -09C7;BENGALI VOWEL SIGN E;Mc;0;L;;;;;N;;;;; -09C8;BENGALI VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; -09CB;BENGALI VOWEL SIGN O;Mc;0;L;09C7 09BE;;;;N;;;;; -09CC;BENGALI VOWEL SIGN AU;Mc;0;L;09C7 09D7;;;;N;;;;; -09CD;BENGALI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -09CE;BENGALI LETTER KHANDA TA;Lo;0;L;;;;;N;;;;; -09D7;BENGALI AU LENGTH MARK;Mc;0;L;;;;;N;;;;; -09DC;BENGALI LETTER RRA;Lo;0;L;09A1 09BC;;;;N;;;;; -09DD;BENGALI LETTER RHA;Lo;0;L;09A2 09BC;;;;N;;;;; -09DF;BENGALI LETTER YYA;Lo;0;L;09AF 09BC;;;;N;;;;; -09E0;BENGALI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; -09E1;BENGALI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; -09E2;BENGALI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; -09E3;BENGALI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; -09E6;BENGALI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -09E7;BENGALI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -09E8;BENGALI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -09E9;BENGALI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -09EA;BENGALI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -09EB;BENGALI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -09EC;BENGALI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -09ED;BENGALI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -09EE;BENGALI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -09EF;BENGALI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -09F0;BENGALI LETTER RA WITH MIDDLE DIAGONAL;Lo;0;L;;;;;N;;;;; -09F1;BENGALI LETTER RA WITH LOWER DIAGONAL;Lo;0;L;;;;;N;BENGALI LETTER VA WITH LOWER DIAGONAL;;;; -09F2;BENGALI RUPEE MARK;Sc;0;ET;;;;;N;;;;; -09F3;BENGALI RUPEE SIGN;Sc;0;ET;;;;;N;;;;; -09F4;BENGALI CURRENCY NUMERATOR ONE;No;0;L;;;;1/16;N;;;;; -09F5;BENGALI CURRENCY NUMERATOR TWO;No;0;L;;;;1/8;N;;;;; -09F6;BENGALI CURRENCY NUMERATOR THREE;No;0;L;;;;3/16;N;;;;; -09F7;BENGALI CURRENCY NUMERATOR FOUR;No;0;L;;;;1/4;N;;;;; -09F8;BENGALI CURRENCY NUMERATOR ONE LESS THAN THE DENOMINATOR;No;0;L;;;;3/4;N;;;;; -09F9;BENGALI CURRENCY DENOMINATOR SIXTEEN;No;0;L;;;;16;N;;;;; -09FA;BENGALI ISSHAR;So;0;L;;;;;N;;;;; -09FB;BENGALI GANDA MARK;Sc;0;ET;;;;;N;;;;; -09FC;BENGALI LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;; -09FD;BENGALI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; -09FE;BENGALI SANDHI MARK;Mn;230;NSM;;;;;N;;;;; -0A01;GURMUKHI SIGN ADAK BINDI;Mn;0;NSM;;;;;N;;;;; -0A02;GURMUKHI SIGN BINDI;Mn;0;NSM;;;;;N;;;;; -0A03;GURMUKHI SIGN VISARGA;Mc;0;L;;;;;N;;;;; -0A05;GURMUKHI LETTER A;Lo;0;L;;;;;N;;;;; -0A06;GURMUKHI LETTER AA;Lo;0;L;;;;;N;;;;; -0A07;GURMUKHI LETTER I;Lo;0;L;;;;;N;;;;; -0A08;GURMUKHI LETTER II;Lo;0;L;;;;;N;;;;; -0A09;GURMUKHI LETTER U;Lo;0;L;;;;;N;;;;; -0A0A;GURMUKHI LETTER UU;Lo;0;L;;;;;N;;;;; -0A0F;GURMUKHI LETTER EE;Lo;0;L;;;;;N;;;;; -0A10;GURMUKHI LETTER AI;Lo;0;L;;;;;N;;;;; -0A13;GURMUKHI LETTER OO;Lo;0;L;;;;;N;;;;; -0A14;GURMUKHI LETTER AU;Lo;0;L;;;;;N;;;;; -0A15;GURMUKHI LETTER KA;Lo;0;L;;;;;N;;;;; -0A16;GURMUKHI LETTER KHA;Lo;0;L;;;;;N;;;;; -0A17;GURMUKHI LETTER GA;Lo;0;L;;;;;N;;;;; -0A18;GURMUKHI LETTER GHA;Lo;0;L;;;;;N;;;;; -0A19;GURMUKHI LETTER NGA;Lo;0;L;;;;;N;;;;; -0A1A;GURMUKHI LETTER CA;Lo;0;L;;;;;N;;;;; -0A1B;GURMUKHI LETTER CHA;Lo;0;L;;;;;N;;;;; -0A1C;GURMUKHI LETTER JA;Lo;0;L;;;;;N;;;;; -0A1D;GURMUKHI LETTER JHA;Lo;0;L;;;;;N;;;;; -0A1E;GURMUKHI LETTER NYA;Lo;0;L;;;;;N;;;;; -0A1F;GURMUKHI LETTER TTA;Lo;0;L;;;;;N;;;;; -0A20;GURMUKHI LETTER TTHA;Lo;0;L;;;;;N;;;;; -0A21;GURMUKHI LETTER DDA;Lo;0;L;;;;;N;;;;; -0A22;GURMUKHI LETTER DDHA;Lo;0;L;;;;;N;;;;; -0A23;GURMUKHI LETTER NNA;Lo;0;L;;;;;N;;;;; -0A24;GURMUKHI LETTER TA;Lo;0;L;;;;;N;;;;; -0A25;GURMUKHI LETTER THA;Lo;0;L;;;;;N;;;;; -0A26;GURMUKHI LETTER DA;Lo;0;L;;;;;N;;;;; -0A27;GURMUKHI LETTER DHA;Lo;0;L;;;;;N;;;;; -0A28;GURMUKHI LETTER NA;Lo;0;L;;;;;N;;;;; -0A2A;GURMUKHI LETTER PA;Lo;0;L;;;;;N;;;;; -0A2B;GURMUKHI LETTER PHA;Lo;0;L;;;;;N;;;;; -0A2C;GURMUKHI LETTER BA;Lo;0;L;;;;;N;;;;; -0A2D;GURMUKHI LETTER BHA;Lo;0;L;;;;;N;;;;; -0A2E;GURMUKHI LETTER MA;Lo;0;L;;;;;N;;;;; -0A2F;GURMUKHI LETTER YA;Lo;0;L;;;;;N;;;;; -0A30;GURMUKHI LETTER RA;Lo;0;L;;;;;N;;;;; -0A32;GURMUKHI LETTER LA;Lo;0;L;;;;;N;;;;; -0A33;GURMUKHI LETTER LLA;Lo;0;L;0A32 0A3C;;;;N;;;;; -0A35;GURMUKHI LETTER VA;Lo;0;L;;;;;N;;;;; -0A36;GURMUKHI LETTER SHA;Lo;0;L;0A38 0A3C;;;;N;;;;; -0A38;GURMUKHI LETTER SA;Lo;0;L;;;;;N;;;;; -0A39;GURMUKHI LETTER HA;Lo;0;L;;;;;N;;;;; -0A3C;GURMUKHI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -0A3E;GURMUKHI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -0A3F;GURMUKHI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -0A40;GURMUKHI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -0A41;GURMUKHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -0A42;GURMUKHI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -0A47;GURMUKHI VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;; -0A48;GURMUKHI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -0A4B;GURMUKHI VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;; -0A4C;GURMUKHI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; -0A4D;GURMUKHI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -0A51;GURMUKHI SIGN UDAAT;Mn;0;NSM;;;;;N;;;;; -0A59;GURMUKHI LETTER KHHA;Lo;0;L;0A16 0A3C;;;;N;;;;; -0A5A;GURMUKHI LETTER GHHA;Lo;0;L;0A17 0A3C;;;;N;;;;; -0A5B;GURMUKHI LETTER ZA;Lo;0;L;0A1C 0A3C;;;;N;;;;; -0A5C;GURMUKHI LETTER RRA;Lo;0;L;;;;;N;;;;; -0A5E;GURMUKHI LETTER FA;Lo;0;L;0A2B 0A3C;;;;N;;;;; -0A66;GURMUKHI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -0A67;GURMUKHI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -0A68;GURMUKHI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -0A69;GURMUKHI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -0A6A;GURMUKHI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -0A6B;GURMUKHI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -0A6C;GURMUKHI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -0A6D;GURMUKHI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -0A6E;GURMUKHI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -0A6F;GURMUKHI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -0A70;GURMUKHI TIPPI;Mn;0;NSM;;;;;N;;;;; -0A71;GURMUKHI ADDAK;Mn;0;NSM;;;;;N;;;;; -0A72;GURMUKHI IRI;Lo;0;L;;;;;N;;;;; -0A73;GURMUKHI URA;Lo;0;L;;;;;N;;;;; -0A74;GURMUKHI EK ONKAR;Lo;0;L;;;;;N;;;;; -0A75;GURMUKHI SIGN YAKASH;Mn;0;NSM;;;;;N;;;;; -0A76;GURMUKHI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; -0A81;GUJARATI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -0A82;GUJARATI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -0A83;GUJARATI SIGN VISARGA;Mc;0;L;;;;;N;;;;; -0A85;GUJARATI LETTER A;Lo;0;L;;;;;N;;;;; -0A86;GUJARATI LETTER AA;Lo;0;L;;;;;N;;;;; -0A87;GUJARATI LETTER I;Lo;0;L;;;;;N;;;;; -0A88;GUJARATI LETTER II;Lo;0;L;;;;;N;;;;; -0A89;GUJARATI LETTER U;Lo;0;L;;;;;N;;;;; -0A8A;GUJARATI LETTER UU;Lo;0;L;;;;;N;;;;; -0A8B;GUJARATI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; -0A8C;GUJARATI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; -0A8D;GUJARATI VOWEL CANDRA E;Lo;0;L;;;;;N;;;;; -0A8F;GUJARATI LETTER E;Lo;0;L;;;;;N;;;;; -0A90;GUJARATI LETTER AI;Lo;0;L;;;;;N;;;;; -0A91;GUJARATI VOWEL CANDRA O;Lo;0;L;;;;;N;;;;; -0A93;GUJARATI LETTER O;Lo;0;L;;;;;N;;;;; -0A94;GUJARATI LETTER AU;Lo;0;L;;;;;N;;;;; -0A95;GUJARATI LETTER KA;Lo;0;L;;;;;N;;;;; -0A96;GUJARATI LETTER KHA;Lo;0;L;;;;;N;;;;; -0A97;GUJARATI LETTER GA;Lo;0;L;;;;;N;;;;; -0A98;GUJARATI LETTER GHA;Lo;0;L;;;;;N;;;;; -0A99;GUJARATI LETTER NGA;Lo;0;L;;;;;N;;;;; -0A9A;GUJARATI LETTER CA;Lo;0;L;;;;;N;;;;; -0A9B;GUJARATI LETTER CHA;Lo;0;L;;;;;N;;;;; -0A9C;GUJARATI LETTER JA;Lo;0;L;;;;;N;;;;; -0A9D;GUJARATI LETTER JHA;Lo;0;L;;;;;N;;;;; -0A9E;GUJARATI LETTER NYA;Lo;0;L;;;;;N;;;;; -0A9F;GUJARATI LETTER TTA;Lo;0;L;;;;;N;;;;; -0AA0;GUJARATI LETTER TTHA;Lo;0;L;;;;;N;;;;; -0AA1;GUJARATI LETTER DDA;Lo;0;L;;;;;N;;;;; -0AA2;GUJARATI LETTER DDHA;Lo;0;L;;;;;N;;;;; -0AA3;GUJARATI LETTER NNA;Lo;0;L;;;;;N;;;;; -0AA4;GUJARATI LETTER TA;Lo;0;L;;;;;N;;;;; -0AA5;GUJARATI LETTER THA;Lo;0;L;;;;;N;;;;; -0AA6;GUJARATI LETTER DA;Lo;0;L;;;;;N;;;;; -0AA7;GUJARATI LETTER DHA;Lo;0;L;;;;;N;;;;; -0AA8;GUJARATI LETTER NA;Lo;0;L;;;;;N;;;;; -0AAA;GUJARATI LETTER PA;Lo;0;L;;;;;N;;;;; -0AAB;GUJARATI LETTER PHA;Lo;0;L;;;;;N;;;;; -0AAC;GUJARATI LETTER BA;Lo;0;L;;;;;N;;;;; -0AAD;GUJARATI LETTER BHA;Lo;0;L;;;;;N;;;;; -0AAE;GUJARATI LETTER MA;Lo;0;L;;;;;N;;;;; -0AAF;GUJARATI LETTER YA;Lo;0;L;;;;;N;;;;; -0AB0;GUJARATI LETTER RA;Lo;0;L;;;;;N;;;;; -0AB2;GUJARATI LETTER LA;Lo;0;L;;;;;N;;;;; -0AB3;GUJARATI LETTER LLA;Lo;0;L;;;;;N;;;;; -0AB5;GUJARATI LETTER VA;Lo;0;L;;;;;N;;;;; -0AB6;GUJARATI LETTER SHA;Lo;0;L;;;;;N;;;;; -0AB7;GUJARATI LETTER SSA;Lo;0;L;;;;;N;;;;; -0AB8;GUJARATI LETTER SA;Lo;0;L;;;;;N;;;;; -0AB9;GUJARATI LETTER HA;Lo;0;L;;;;;N;;;;; -0ABC;GUJARATI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -0ABD;GUJARATI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; -0ABE;GUJARATI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -0ABF;GUJARATI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -0AC0;GUJARATI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -0AC1;GUJARATI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -0AC2;GUJARATI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -0AC3;GUJARATI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -0AC4;GUJARATI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; -0AC5;GUJARATI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;; -0AC7;GUJARATI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -0AC8;GUJARATI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -0AC9;GUJARATI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;; -0ACB;GUJARATI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; -0ACC;GUJARATI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; -0ACD;GUJARATI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -0AD0;GUJARATI OM;Lo;0;L;;;;;N;;;;; -0AE0;GUJARATI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; -0AE1;GUJARATI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; -0AE2;GUJARATI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; -0AE3;GUJARATI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; -0AE6;GUJARATI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -0AE7;GUJARATI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -0AE8;GUJARATI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -0AE9;GUJARATI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -0AEA;GUJARATI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -0AEB;GUJARATI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -0AEC;GUJARATI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -0AED;GUJARATI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -0AEE;GUJARATI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -0AEF;GUJARATI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -0AF0;GUJARATI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; -0AF1;GUJARATI RUPEE SIGN;Sc;0;ET;;;;;N;;;;; -0AF9;GUJARATI LETTER ZHA;Lo;0;L;;;;;N;;;;; -0AFA;GUJARATI SIGN SUKUN;Mn;0;NSM;;;;;N;;;;; -0AFB;GUJARATI SIGN SHADDA;Mn;0;NSM;;;;;N;;;;; -0AFC;GUJARATI SIGN MADDAH;Mn;0;NSM;;;;;N;;;;; -0AFD;GUJARATI SIGN THREE-DOT NUKTA ABOVE;Mn;0;NSM;;;;;N;;;;; -0AFE;GUJARATI SIGN CIRCLE NUKTA ABOVE;Mn;0;NSM;;;;;N;;;;; -0AFF;GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE;Mn;0;NSM;;;;;N;;;;; -0B01;ORIYA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -0B02;ORIYA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; -0B03;ORIYA SIGN VISARGA;Mc;0;L;;;;;N;;;;; -0B05;ORIYA LETTER A;Lo;0;L;;;;;N;;;;; -0B06;ORIYA LETTER AA;Lo;0;L;;;;;N;;;;; -0B07;ORIYA LETTER I;Lo;0;L;;;;;N;;;;; -0B08;ORIYA LETTER II;Lo;0;L;;;;;N;;;;; -0B09;ORIYA LETTER U;Lo;0;L;;;;;N;;;;; -0B0A;ORIYA LETTER UU;Lo;0;L;;;;;N;;;;; -0B0B;ORIYA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; -0B0C;ORIYA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; -0B0F;ORIYA LETTER E;Lo;0;L;;;;;N;;;;; -0B10;ORIYA LETTER AI;Lo;0;L;;;;;N;;;;; -0B13;ORIYA LETTER O;Lo;0;L;;;;;N;;;;; -0B14;ORIYA LETTER AU;Lo;0;L;;;;;N;;;;; -0B15;ORIYA LETTER KA;Lo;0;L;;;;;N;;;;; -0B16;ORIYA LETTER KHA;Lo;0;L;;;;;N;;;;; -0B17;ORIYA LETTER GA;Lo;0;L;;;;;N;;;;; -0B18;ORIYA LETTER GHA;Lo;0;L;;;;;N;;;;; -0B19;ORIYA LETTER NGA;Lo;0;L;;;;;N;;;;; -0B1A;ORIYA LETTER CA;Lo;0;L;;;;;N;;;;; -0B1B;ORIYA LETTER CHA;Lo;0;L;;;;;N;;;;; -0B1C;ORIYA LETTER JA;Lo;0;L;;;;;N;;;;; -0B1D;ORIYA LETTER JHA;Lo;0;L;;;;;N;;;;; -0B1E;ORIYA LETTER NYA;Lo;0;L;;;;;N;;;;; -0B1F;ORIYA LETTER TTA;Lo;0;L;;;;;N;;;;; -0B20;ORIYA LETTER TTHA;Lo;0;L;;;;;N;;;;; -0B21;ORIYA LETTER DDA;Lo;0;L;;;;;N;;;;; -0B22;ORIYA LETTER DDHA;Lo;0;L;;;;;N;;;;; -0B23;ORIYA LETTER NNA;Lo;0;L;;;;;N;;;;; -0B24;ORIYA LETTER TA;Lo;0;L;;;;;N;;;;; -0B25;ORIYA LETTER THA;Lo;0;L;;;;;N;;;;; -0B26;ORIYA LETTER DA;Lo;0;L;;;;;N;;;;; -0B27;ORIYA LETTER DHA;Lo;0;L;;;;;N;;;;; -0B28;ORIYA LETTER NA;Lo;0;L;;;;;N;;;;; -0B2A;ORIYA LETTER PA;Lo;0;L;;;;;N;;;;; -0B2B;ORIYA LETTER PHA;Lo;0;L;;;;;N;;;;; -0B2C;ORIYA LETTER BA;Lo;0;L;;;;;N;;;;; -0B2D;ORIYA LETTER BHA;Lo;0;L;;;;;N;;;;; -0B2E;ORIYA LETTER MA;Lo;0;L;;;;;N;;;;; -0B2F;ORIYA LETTER YA;Lo;0;L;;;;;N;;;;; -0B30;ORIYA LETTER RA;Lo;0;L;;;;;N;;;;; -0B32;ORIYA LETTER LA;Lo;0;L;;;;;N;;;;; -0B33;ORIYA LETTER LLA;Lo;0;L;;;;;N;;;;; -0B35;ORIYA LETTER VA;Lo;0;L;;;;;N;;;;; -0B36;ORIYA LETTER SHA;Lo;0;L;;;;;N;;;;; -0B37;ORIYA LETTER SSA;Lo;0;L;;;;;N;;;;; -0B38;ORIYA LETTER SA;Lo;0;L;;;;;N;;;;; -0B39;ORIYA LETTER HA;Lo;0;L;;;;;N;;;;; -0B3C;ORIYA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -0B3D;ORIYA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; -0B3E;ORIYA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -0B3F;ORIYA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -0B40;ORIYA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -0B41;ORIYA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -0B42;ORIYA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -0B43;ORIYA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -0B44;ORIYA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; -0B47;ORIYA VOWEL SIGN E;Mc;0;L;;;;;N;;;;; -0B48;ORIYA VOWEL SIGN AI;Mc;0;L;0B47 0B56;;;;N;;;;; -0B4B;ORIYA VOWEL SIGN O;Mc;0;L;0B47 0B3E;;;;N;;;;; -0B4C;ORIYA VOWEL SIGN AU;Mc;0;L;0B47 0B57;;;;N;;;;; -0B4D;ORIYA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -0B55;ORIYA SIGN OVERLINE;Mn;0;NSM;;;;;N;;;;; -0B56;ORIYA AI LENGTH MARK;Mn;0;NSM;;;;;N;;;;; -0B57;ORIYA AU LENGTH MARK;Mc;0;L;;;;;N;;;;; -0B5C;ORIYA LETTER RRA;Lo;0;L;0B21 0B3C;;;;N;;;;; -0B5D;ORIYA LETTER RHA;Lo;0;L;0B22 0B3C;;;;N;;;;; -0B5F;ORIYA LETTER YYA;Lo;0;L;;;;;N;;;;; -0B60;ORIYA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; -0B61;ORIYA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; -0B62;ORIYA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; -0B63;ORIYA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; -0B66;ORIYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -0B67;ORIYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -0B68;ORIYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -0B69;ORIYA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -0B6A;ORIYA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -0B6B;ORIYA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -0B6C;ORIYA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -0B6D;ORIYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -0B6E;ORIYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -0B6F;ORIYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -0B70;ORIYA ISSHAR;So;0;L;;;;;N;;;;; -0B71;ORIYA LETTER WA;Lo;0;L;;;;;N;;;;; -0B72;ORIYA FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;; -0B73;ORIYA FRACTION ONE HALF;No;0;L;;;;1/2;N;;;;; -0B74;ORIYA FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;; -0B75;ORIYA FRACTION ONE SIXTEENTH;No;0;L;;;;1/16;N;;;;; -0B76;ORIYA FRACTION ONE EIGHTH;No;0;L;;;;1/8;N;;;;; -0B77;ORIYA FRACTION THREE SIXTEENTHS;No;0;L;;;;3/16;N;;;;; -0B82;TAMIL SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -0B83;TAMIL SIGN VISARGA;Lo;0;L;;;;;N;;;;; -0B85;TAMIL LETTER A;Lo;0;L;;;;;N;;;;; -0B86;TAMIL LETTER AA;Lo;0;L;;;;;N;;;;; -0B87;TAMIL LETTER I;Lo;0;L;;;;;N;;;;; -0B88;TAMIL LETTER II;Lo;0;L;;;;;N;;;;; -0B89;TAMIL LETTER U;Lo;0;L;;;;;N;;;;; -0B8A;TAMIL LETTER UU;Lo;0;L;;;;;N;;;;; -0B8E;TAMIL LETTER E;Lo;0;L;;;;;N;;;;; -0B8F;TAMIL LETTER EE;Lo;0;L;;;;;N;;;;; -0B90;TAMIL LETTER AI;Lo;0;L;;;;;N;;;;; -0B92;TAMIL LETTER O;Lo;0;L;;;;;N;;;;; -0B93;TAMIL LETTER OO;Lo;0;L;;;;;N;;;;; -0B94;TAMIL LETTER AU;Lo;0;L;0B92 0BD7;;;;N;;;;; -0B95;TAMIL LETTER KA;Lo;0;L;;;;;N;;;;; -0B99;TAMIL LETTER NGA;Lo;0;L;;;;;N;;;;; -0B9A;TAMIL LETTER CA;Lo;0;L;;;;;N;;;;; -0B9C;TAMIL LETTER JA;Lo;0;L;;;;;N;;;;; -0B9E;TAMIL LETTER NYA;Lo;0;L;;;;;N;;;;; -0B9F;TAMIL LETTER TTA;Lo;0;L;;;;;N;;;;; -0BA3;TAMIL LETTER NNA;Lo;0;L;;;;;N;;;;; -0BA4;TAMIL LETTER TA;Lo;0;L;;;;;N;;;;; -0BA8;TAMIL LETTER NA;Lo;0;L;;;;;N;;;;; -0BA9;TAMIL LETTER NNNA;Lo;0;L;;;;;N;;;;; -0BAA;TAMIL LETTER PA;Lo;0;L;;;;;N;;;;; -0BAE;TAMIL LETTER MA;Lo;0;L;;;;;N;;;;; -0BAF;TAMIL LETTER YA;Lo;0;L;;;;;N;;;;; -0BB0;TAMIL LETTER RA;Lo;0;L;;;;;N;;;;; -0BB1;TAMIL LETTER RRA;Lo;0;L;;;;;N;;;;; -0BB2;TAMIL LETTER LA;Lo;0;L;;;;;N;;;;; -0BB3;TAMIL LETTER LLA;Lo;0;L;;;;;N;;;;; -0BB4;TAMIL LETTER LLLA;Lo;0;L;;;;;N;;;;; -0BB5;TAMIL LETTER VA;Lo;0;L;;;;;N;;;;; -0BB6;TAMIL LETTER SHA;Lo;0;L;;;;;N;;;;; -0BB7;TAMIL LETTER SSA;Lo;0;L;;;;;N;;;;; -0BB8;TAMIL LETTER SA;Lo;0;L;;;;;N;;;;; -0BB9;TAMIL LETTER HA;Lo;0;L;;;;;N;;;;; -0BBE;TAMIL VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -0BBF;TAMIL VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -0BC0;TAMIL VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; -0BC1;TAMIL VOWEL SIGN U;Mc;0;L;;;;;N;;;;; -0BC2;TAMIL VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; -0BC6;TAMIL VOWEL SIGN E;Mc;0;L;;;;;N;;;;; -0BC7;TAMIL VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; -0BC8;TAMIL VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; -0BCA;TAMIL VOWEL SIGN O;Mc;0;L;0BC6 0BBE;;;;N;;;;; -0BCB;TAMIL VOWEL SIGN OO;Mc;0;L;0BC7 0BBE;;;;N;;;;; -0BCC;TAMIL VOWEL SIGN AU;Mc;0;L;0BC6 0BD7;;;;N;;;;; -0BCD;TAMIL SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -0BD0;TAMIL OM;Lo;0;L;;;;;N;;;;; -0BD7;TAMIL AU LENGTH MARK;Mc;0;L;;;;;N;;;;; -0BE6;TAMIL DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -0BE7;TAMIL DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -0BE8;TAMIL DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -0BE9;TAMIL DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -0BEA;TAMIL DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -0BEB;TAMIL DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -0BEC;TAMIL DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -0BED;TAMIL DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -0BEE;TAMIL DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -0BEF;TAMIL DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -0BF0;TAMIL NUMBER TEN;No;0;L;;;;10;N;;;;; -0BF1;TAMIL NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;; -0BF2;TAMIL NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;; -0BF3;TAMIL DAY SIGN;So;0;ON;;;;;N;;;;; -0BF4;TAMIL MONTH SIGN;So;0;ON;;;;;N;;;;; -0BF5;TAMIL YEAR SIGN;So;0;ON;;;;;N;;;;; -0BF6;TAMIL DEBIT SIGN;So;0;ON;;;;;N;;;;; -0BF7;TAMIL CREDIT SIGN;So;0;ON;;;;;N;;;;; -0BF8;TAMIL AS ABOVE SIGN;So;0;ON;;;;;N;;;;; -0BF9;TAMIL RUPEE SIGN;Sc;0;ET;;;;;N;;;;; -0BFA;TAMIL NUMBER SIGN;So;0;ON;;;;;N;;;;; -0C00;TELUGU SIGN COMBINING CANDRABINDU ABOVE;Mn;0;NSM;;;;;N;;;;; -0C01;TELUGU SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;; -0C02;TELUGU SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; -0C03;TELUGU SIGN VISARGA;Mc;0;L;;;;;N;;;;; -0C04;TELUGU SIGN COMBINING ANUSVARA ABOVE;Mn;0;NSM;;;;;N;;;;; -0C05;TELUGU LETTER A;Lo;0;L;;;;;N;;;;; -0C06;TELUGU LETTER AA;Lo;0;L;;;;;N;;;;; -0C07;TELUGU LETTER I;Lo;0;L;;;;;N;;;;; -0C08;TELUGU LETTER II;Lo;0;L;;;;;N;;;;; -0C09;TELUGU LETTER U;Lo;0;L;;;;;N;;;;; -0C0A;TELUGU LETTER UU;Lo;0;L;;;;;N;;;;; -0C0B;TELUGU LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; -0C0C;TELUGU LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; -0C0E;TELUGU LETTER E;Lo;0;L;;;;;N;;;;; -0C0F;TELUGU LETTER EE;Lo;0;L;;;;;N;;;;; -0C10;TELUGU LETTER AI;Lo;0;L;;;;;N;;;;; -0C12;TELUGU LETTER O;Lo;0;L;;;;;N;;;;; -0C13;TELUGU LETTER OO;Lo;0;L;;;;;N;;;;; -0C14;TELUGU LETTER AU;Lo;0;L;;;;;N;;;;; -0C15;TELUGU LETTER KA;Lo;0;L;;;;;N;;;;; -0C16;TELUGU LETTER KHA;Lo;0;L;;;;;N;;;;; -0C17;TELUGU LETTER GA;Lo;0;L;;;;;N;;;;; -0C18;TELUGU LETTER GHA;Lo;0;L;;;;;N;;;;; -0C19;TELUGU LETTER NGA;Lo;0;L;;;;;N;;;;; -0C1A;TELUGU LETTER CA;Lo;0;L;;;;;N;;;;; -0C1B;TELUGU LETTER CHA;Lo;0;L;;;;;N;;;;; -0C1C;TELUGU LETTER JA;Lo;0;L;;;;;N;;;;; -0C1D;TELUGU LETTER JHA;Lo;0;L;;;;;N;;;;; -0C1E;TELUGU LETTER NYA;Lo;0;L;;;;;N;;;;; -0C1F;TELUGU LETTER TTA;Lo;0;L;;;;;N;;;;; -0C20;TELUGU LETTER TTHA;Lo;0;L;;;;;N;;;;; -0C21;TELUGU LETTER DDA;Lo;0;L;;;;;N;;;;; -0C22;TELUGU LETTER DDHA;Lo;0;L;;;;;N;;;;; -0C23;TELUGU LETTER NNA;Lo;0;L;;;;;N;;;;; -0C24;TELUGU LETTER TA;Lo;0;L;;;;;N;;;;; -0C25;TELUGU LETTER THA;Lo;0;L;;;;;N;;;;; -0C26;TELUGU LETTER DA;Lo;0;L;;;;;N;;;;; -0C27;TELUGU LETTER DHA;Lo;0;L;;;;;N;;;;; -0C28;TELUGU LETTER NA;Lo;0;L;;;;;N;;;;; -0C2A;TELUGU LETTER PA;Lo;0;L;;;;;N;;;;; -0C2B;TELUGU LETTER PHA;Lo;0;L;;;;;N;;;;; -0C2C;TELUGU LETTER BA;Lo;0;L;;;;;N;;;;; -0C2D;TELUGU LETTER BHA;Lo;0;L;;;;;N;;;;; -0C2E;TELUGU LETTER MA;Lo;0;L;;;;;N;;;;; -0C2F;TELUGU LETTER YA;Lo;0;L;;;;;N;;;;; -0C30;TELUGU LETTER RA;Lo;0;L;;;;;N;;;;; -0C31;TELUGU LETTER RRA;Lo;0;L;;;;;N;;;;; -0C32;TELUGU LETTER LA;Lo;0;L;;;;;N;;;;; -0C33;TELUGU LETTER LLA;Lo;0;L;;;;;N;;;;; -0C34;TELUGU LETTER LLLA;Lo;0;L;;;;;N;;;;; -0C35;TELUGU LETTER VA;Lo;0;L;;;;;N;;;;; -0C36;TELUGU LETTER SHA;Lo;0;L;;;;;N;;;;; -0C37;TELUGU LETTER SSA;Lo;0;L;;;;;N;;;;; -0C38;TELUGU LETTER SA;Lo;0;L;;;;;N;;;;; -0C39;TELUGU LETTER HA;Lo;0;L;;;;;N;;;;; -0C3C;TELUGU SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -0C3D;TELUGU SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; -0C3E;TELUGU VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; -0C3F;TELUGU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -0C40;TELUGU VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; -0C41;TELUGU VOWEL SIGN U;Mc;0;L;;;;;N;;;;; -0C42;TELUGU VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; -0C43;TELUGU VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; -0C44;TELUGU VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; -0C46;TELUGU VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -0C47;TELUGU VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;; -0C48;TELUGU VOWEL SIGN AI;Mn;0;NSM;0C46 0C56;;;;N;;;;; -0C4A;TELUGU VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; -0C4B;TELUGU VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;; -0C4C;TELUGU VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; -0C4D;TELUGU SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -0C55;TELUGU LENGTH MARK;Mn;84;NSM;;;;;N;;;;; -0C56;TELUGU AI LENGTH MARK;Mn;91;NSM;;;;;N;;;;; -0C58;TELUGU LETTER TSA;Lo;0;L;;;;;N;;;;; -0C59;TELUGU LETTER DZA;Lo;0;L;;;;;N;;;;; -0C5A;TELUGU LETTER RRRA;Lo;0;L;;;;;N;;;;; -0C5D;TELUGU LETTER NAKAARA POLLU;Lo;0;L;;;;;N;;;;; -0C60;TELUGU LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; -0C61;TELUGU LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; -0C62;TELUGU VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; -0C63;TELUGU VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; -0C66;TELUGU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -0C67;TELUGU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -0C68;TELUGU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -0C69;TELUGU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -0C6A;TELUGU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -0C6B;TELUGU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -0C6C;TELUGU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -0C6D;TELUGU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -0C6E;TELUGU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -0C6F;TELUGU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -0C77;TELUGU SIGN SIDDHAM;Po;0;L;;;;;N;;;;; -0C78;TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR;No;0;ON;;;;0;N;;;;; -0C79;TELUGU FRACTION DIGIT ONE FOR ODD POWERS OF FOUR;No;0;ON;;;;1;N;;;;; -0C7A;TELUGU FRACTION DIGIT TWO FOR ODD POWERS OF FOUR;No;0;ON;;;;2;N;;;;; -0C7B;TELUGU FRACTION DIGIT THREE FOR ODD POWERS OF FOUR;No;0;ON;;;;3;N;;;;; -0C7C;TELUGU FRACTION DIGIT ONE FOR EVEN POWERS OF FOUR;No;0;ON;;;;1;N;;;;; -0C7D;TELUGU FRACTION DIGIT TWO FOR EVEN POWERS OF FOUR;No;0;ON;;;;2;N;;;;; -0C7E;TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR;No;0;ON;;;;3;N;;;;; -0C7F;TELUGU SIGN TUUMU;So;0;L;;;;;N;;;;; -0C80;KANNADA SIGN SPACING CANDRABINDU;Lo;0;L;;;;;N;;;;; -0C81;KANNADA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -0C82;KANNADA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; -0C83;KANNADA SIGN VISARGA;Mc;0;L;;;;;N;;;;; -0C84;KANNADA SIGN SIDDHAM;Po;0;L;;;;;N;;;;; -0C85;KANNADA LETTER A;Lo;0;L;;;;;N;;;;; -0C86;KANNADA LETTER AA;Lo;0;L;;;;;N;;;;; -0C87;KANNADA LETTER I;Lo;0;L;;;;;N;;;;; -0C88;KANNADA LETTER II;Lo;0;L;;;;;N;;;;; -0C89;KANNADA LETTER U;Lo;0;L;;;;;N;;;;; -0C8A;KANNADA LETTER UU;Lo;0;L;;;;;N;;;;; -0C8B;KANNADA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; -0C8C;KANNADA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; -0C8E;KANNADA LETTER E;Lo;0;L;;;;;N;;;;; -0C8F;KANNADA LETTER EE;Lo;0;L;;;;;N;;;;; -0C90;KANNADA LETTER AI;Lo;0;L;;;;;N;;;;; -0C92;KANNADA LETTER O;Lo;0;L;;;;;N;;;;; -0C93;KANNADA LETTER OO;Lo;0;L;;;;;N;;;;; -0C94;KANNADA LETTER AU;Lo;0;L;;;;;N;;;;; -0C95;KANNADA LETTER KA;Lo;0;L;;;;;N;;;;; -0C96;KANNADA LETTER KHA;Lo;0;L;;;;;N;;;;; -0C97;KANNADA LETTER GA;Lo;0;L;;;;;N;;;;; -0C98;KANNADA LETTER GHA;Lo;0;L;;;;;N;;;;; -0C99;KANNADA LETTER NGA;Lo;0;L;;;;;N;;;;; -0C9A;KANNADA LETTER CA;Lo;0;L;;;;;N;;;;; -0C9B;KANNADA LETTER CHA;Lo;0;L;;;;;N;;;;; -0C9C;KANNADA LETTER JA;Lo;0;L;;;;;N;;;;; -0C9D;KANNADA LETTER JHA;Lo;0;L;;;;;N;;;;; -0C9E;KANNADA LETTER NYA;Lo;0;L;;;;;N;;;;; -0C9F;KANNADA LETTER TTA;Lo;0;L;;;;;N;;;;; -0CA0;KANNADA LETTER TTHA;Lo;0;L;;;;;N;;;;; -0CA1;KANNADA LETTER DDA;Lo;0;L;;;;;N;;;;; -0CA2;KANNADA LETTER DDHA;Lo;0;L;;;;;N;;;;; -0CA3;KANNADA LETTER NNA;Lo;0;L;;;;;N;;;;; -0CA4;KANNADA LETTER TA;Lo;0;L;;;;;N;;;;; -0CA5;KANNADA LETTER THA;Lo;0;L;;;;;N;;;;; -0CA6;KANNADA LETTER DA;Lo;0;L;;;;;N;;;;; -0CA7;KANNADA LETTER DHA;Lo;0;L;;;;;N;;;;; -0CA8;KANNADA LETTER NA;Lo;0;L;;;;;N;;;;; -0CAA;KANNADA LETTER PA;Lo;0;L;;;;;N;;;;; -0CAB;KANNADA LETTER PHA;Lo;0;L;;;;;N;;;;; -0CAC;KANNADA LETTER BA;Lo;0;L;;;;;N;;;;; -0CAD;KANNADA LETTER BHA;Lo;0;L;;;;;N;;;;; -0CAE;KANNADA LETTER MA;Lo;0;L;;;;;N;;;;; -0CAF;KANNADA LETTER YA;Lo;0;L;;;;;N;;;;; -0CB0;KANNADA LETTER RA;Lo;0;L;;;;;N;;;;; -0CB1;KANNADA LETTER RRA;Lo;0;L;;;;;N;;;;; -0CB2;KANNADA LETTER LA;Lo;0;L;;;;;N;;;;; -0CB3;KANNADA LETTER LLA;Lo;0;L;;;;;N;;;;; -0CB5;KANNADA LETTER VA;Lo;0;L;;;;;N;;;;; -0CB6;KANNADA LETTER SHA;Lo;0;L;;;;;N;;;;; -0CB7;KANNADA LETTER SSA;Lo;0;L;;;;;N;;;;; -0CB8;KANNADA LETTER SA;Lo;0;L;;;;;N;;;;; -0CB9;KANNADA LETTER HA;Lo;0;L;;;;;N;;;;; -0CBC;KANNADA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -0CBD;KANNADA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; -0CBE;KANNADA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -0CBF;KANNADA VOWEL SIGN I;Mn;0;L;;;;;N;;;;; -0CC0;KANNADA VOWEL SIGN II;Mc;0;L;0CBF 0CD5;;;;N;;;;; -0CC1;KANNADA VOWEL SIGN U;Mc;0;L;;;;;N;;;;; -0CC2;KANNADA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; -0CC3;KANNADA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; -0CC4;KANNADA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; -0CC6;KANNADA VOWEL SIGN E;Mn;0;L;;;;;N;;;;; -0CC7;KANNADA VOWEL SIGN EE;Mc;0;L;0CC6 0CD5;;;;N;;;;; -0CC8;KANNADA VOWEL SIGN AI;Mc;0;L;0CC6 0CD6;;;;N;;;;; -0CCA;KANNADA VOWEL SIGN O;Mc;0;L;0CC6 0CC2;;;;N;;;;; -0CCB;KANNADA VOWEL SIGN OO;Mc;0;L;0CCA 0CD5;;;;N;;;;; -0CCC;KANNADA VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; -0CCD;KANNADA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -0CD5;KANNADA LENGTH MARK;Mc;0;L;;;;;N;;;;; -0CD6;KANNADA AI LENGTH MARK;Mc;0;L;;;;;N;;;;; -0CDD;KANNADA LETTER NAKAARA POLLU;Lo;0;L;;;;;N;;;;; -0CDE;KANNADA LETTER FA;Lo;0;L;;;;;N;;;;; -0CE0;KANNADA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; -0CE1;KANNADA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; -0CE2;KANNADA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; -0CE3;KANNADA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; -0CE6;KANNADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -0CE7;KANNADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -0CE8;KANNADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -0CE9;KANNADA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -0CEA;KANNADA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -0CEB;KANNADA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -0CEC;KANNADA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -0CED;KANNADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -0CEE;KANNADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -0CEF;KANNADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -0CF1;KANNADA SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; -0CF2;KANNADA SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; -0CF3;KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT;Mc;0;L;;;;;N;;;;; -0D00;MALAYALAM SIGN COMBINING ANUSVARA ABOVE;Mn;0;NSM;;;;;N;;;;; -0D01;MALAYALAM SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -0D02;MALAYALAM SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; -0D03;MALAYALAM SIGN VISARGA;Mc;0;L;;;;;N;;;;; -0D04;MALAYALAM LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;; -0D05;MALAYALAM LETTER A;Lo;0;L;;;;;N;;;;; -0D06;MALAYALAM LETTER AA;Lo;0;L;;;;;N;;;;; -0D07;MALAYALAM LETTER I;Lo;0;L;;;;;N;;;;; -0D08;MALAYALAM LETTER II;Lo;0;L;;;;;N;;;;; -0D09;MALAYALAM LETTER U;Lo;0;L;;;;;N;;;;; -0D0A;MALAYALAM LETTER UU;Lo;0;L;;;;;N;;;;; -0D0B;MALAYALAM LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; -0D0C;MALAYALAM LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; -0D0E;MALAYALAM LETTER E;Lo;0;L;;;;;N;;;;; -0D0F;MALAYALAM LETTER EE;Lo;0;L;;;;;N;;;;; -0D10;MALAYALAM LETTER AI;Lo;0;L;;;;;N;;;;; -0D12;MALAYALAM LETTER O;Lo;0;L;;;;;N;;;;; -0D13;MALAYALAM LETTER OO;Lo;0;L;;;;;N;;;;; -0D14;MALAYALAM LETTER AU;Lo;0;L;;;;;N;;;;; -0D15;MALAYALAM LETTER KA;Lo;0;L;;;;;N;;;;; -0D16;MALAYALAM LETTER KHA;Lo;0;L;;;;;N;;;;; -0D17;MALAYALAM LETTER GA;Lo;0;L;;;;;N;;;;; -0D18;MALAYALAM LETTER GHA;Lo;0;L;;;;;N;;;;; -0D19;MALAYALAM LETTER NGA;Lo;0;L;;;;;N;;;;; -0D1A;MALAYALAM LETTER CA;Lo;0;L;;;;;N;;;;; -0D1B;MALAYALAM LETTER CHA;Lo;0;L;;;;;N;;;;; -0D1C;MALAYALAM LETTER JA;Lo;0;L;;;;;N;;;;; -0D1D;MALAYALAM LETTER JHA;Lo;0;L;;;;;N;;;;; -0D1E;MALAYALAM LETTER NYA;Lo;0;L;;;;;N;;;;; -0D1F;MALAYALAM LETTER TTA;Lo;0;L;;;;;N;;;;; -0D20;MALAYALAM LETTER TTHA;Lo;0;L;;;;;N;;;;; -0D21;MALAYALAM LETTER DDA;Lo;0;L;;;;;N;;;;; -0D22;MALAYALAM LETTER DDHA;Lo;0;L;;;;;N;;;;; -0D23;MALAYALAM LETTER NNA;Lo;0;L;;;;;N;;;;; -0D24;MALAYALAM LETTER TA;Lo;0;L;;;;;N;;;;; -0D25;MALAYALAM LETTER THA;Lo;0;L;;;;;N;;;;; -0D26;MALAYALAM LETTER DA;Lo;0;L;;;;;N;;;;; -0D27;MALAYALAM LETTER DHA;Lo;0;L;;;;;N;;;;; -0D28;MALAYALAM LETTER NA;Lo;0;L;;;;;N;;;;; -0D29;MALAYALAM LETTER NNNA;Lo;0;L;;;;;N;;;;; -0D2A;MALAYALAM LETTER PA;Lo;0;L;;;;;N;;;;; -0D2B;MALAYALAM LETTER PHA;Lo;0;L;;;;;N;;;;; -0D2C;MALAYALAM LETTER BA;Lo;0;L;;;;;N;;;;; -0D2D;MALAYALAM LETTER BHA;Lo;0;L;;;;;N;;;;; -0D2E;MALAYALAM LETTER MA;Lo;0;L;;;;;N;;;;; -0D2F;MALAYALAM LETTER YA;Lo;0;L;;;;;N;;;;; -0D30;MALAYALAM LETTER RA;Lo;0;L;;;;;N;;;;; -0D31;MALAYALAM LETTER RRA;Lo;0;L;;;;;N;;;;; -0D32;MALAYALAM LETTER LA;Lo;0;L;;;;;N;;;;; -0D33;MALAYALAM LETTER LLA;Lo;0;L;;;;;N;;;;; -0D34;MALAYALAM LETTER LLLA;Lo;0;L;;;;;N;;;;; -0D35;MALAYALAM LETTER VA;Lo;0;L;;;;;N;;;;; -0D36;MALAYALAM LETTER SHA;Lo;0;L;;;;;N;;;;; -0D37;MALAYALAM LETTER SSA;Lo;0;L;;;;;N;;;;; -0D38;MALAYALAM LETTER SA;Lo;0;L;;;;;N;;;;; -0D39;MALAYALAM LETTER HA;Lo;0;L;;;;;N;;;;; -0D3A;MALAYALAM LETTER TTTA;Lo;0;L;;;;;N;;;;; -0D3B;MALAYALAM SIGN VERTICAL BAR VIRAMA;Mn;9;NSM;;;;;N;;;;; -0D3C;MALAYALAM SIGN CIRCULAR VIRAMA;Mn;9;NSM;;;;;N;;;;; -0D3D;MALAYALAM SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; -0D3E;MALAYALAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -0D3F;MALAYALAM VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -0D40;MALAYALAM VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -0D41;MALAYALAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -0D42;MALAYALAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -0D43;MALAYALAM VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -0D44;MALAYALAM VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; -0D46;MALAYALAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;; -0D47;MALAYALAM VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; -0D48;MALAYALAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; -0D4A;MALAYALAM VOWEL SIGN O;Mc;0;L;0D46 0D3E;;;;N;;;;; -0D4B;MALAYALAM VOWEL SIGN OO;Mc;0;L;0D47 0D3E;;;;N;;;;; -0D4C;MALAYALAM VOWEL SIGN AU;Mc;0;L;0D46 0D57;;;;N;;;;; -0D4D;MALAYALAM SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -0D4E;MALAYALAM LETTER DOT REPH;Lo;0;L;;;;;N;;;;; -0D4F;MALAYALAM SIGN PARA;So;0;L;;;;;N;;;;; -0D54;MALAYALAM LETTER CHILLU M;Lo;0;L;;;;;N;;;;; -0D55;MALAYALAM LETTER CHILLU Y;Lo;0;L;;;;;N;;;;; -0D56;MALAYALAM LETTER CHILLU LLL;Lo;0;L;;;;;N;;;;; -0D57;MALAYALAM AU LENGTH MARK;Mc;0;L;;;;;N;;;;; -0D58;MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH;No;0;L;;;;1/160;N;;;;; -0D59;MALAYALAM FRACTION ONE FORTIETH;No;0;L;;;;1/40;N;;;;; -0D5A;MALAYALAM FRACTION THREE EIGHTIETHS;No;0;L;;;;3/80;N;;;;; -0D5B;MALAYALAM FRACTION ONE TWENTIETH;No;0;L;;;;1/20;N;;;;; -0D5C;MALAYALAM FRACTION ONE TENTH;No;0;L;;;;1/10;N;;;;; -0D5D;MALAYALAM FRACTION THREE TWENTIETHS;No;0;L;;;;3/20;N;;;;; -0D5E;MALAYALAM FRACTION ONE FIFTH;No;0;L;;;;1/5;N;;;;; -0D5F;MALAYALAM LETTER ARCHAIC II;Lo;0;L;;;;;N;;;;; -0D60;MALAYALAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; -0D61;MALAYALAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; -0D62;MALAYALAM VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; -0D63;MALAYALAM VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; -0D66;MALAYALAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -0D67;MALAYALAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -0D68;MALAYALAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -0D69;MALAYALAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -0D6A;MALAYALAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -0D6B;MALAYALAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -0D6C;MALAYALAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -0D6D;MALAYALAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -0D6E;MALAYALAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -0D6F;MALAYALAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -0D70;MALAYALAM NUMBER TEN;No;0;L;;;;10;N;;;;; -0D71;MALAYALAM NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;; -0D72;MALAYALAM NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;; -0D73;MALAYALAM FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;; -0D74;MALAYALAM FRACTION ONE HALF;No;0;L;;;;1/2;N;;;;; -0D75;MALAYALAM FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;; -0D76;MALAYALAM FRACTION ONE SIXTEENTH;No;0;L;;;;1/16;N;;;;; -0D77;MALAYALAM FRACTION ONE EIGHTH;No;0;L;;;;1/8;N;;;;; -0D78;MALAYALAM FRACTION THREE SIXTEENTHS;No;0;L;;;;3/16;N;;;;; -0D79;MALAYALAM DATE MARK;So;0;L;;;;;N;;;;; -0D7A;MALAYALAM LETTER CHILLU NN;Lo;0;L;;;;;N;;;;; -0D7B;MALAYALAM LETTER CHILLU N;Lo;0;L;;;;;N;;;;; -0D7C;MALAYALAM LETTER CHILLU RR;Lo;0;L;;;;;N;;;;; -0D7D;MALAYALAM LETTER CHILLU L;Lo;0;L;;;;;N;;;;; -0D7E;MALAYALAM LETTER CHILLU LL;Lo;0;L;;;;;N;;;;; -0D7F;MALAYALAM LETTER CHILLU K;Lo;0;L;;;;;N;;;;; -0D81;SINHALA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -0D82;SINHALA SIGN ANUSVARAYA;Mc;0;L;;;;;N;;;;; -0D83;SINHALA SIGN VISARGAYA;Mc;0;L;;;;;N;;;;; -0D85;SINHALA LETTER AYANNA;Lo;0;L;;;;;N;;;;; -0D86;SINHALA LETTER AAYANNA;Lo;0;L;;;;;N;;;;; -0D87;SINHALA LETTER AEYANNA;Lo;0;L;;;;;N;;;;; -0D88;SINHALA LETTER AEEYANNA;Lo;0;L;;;;;N;;;;; -0D89;SINHALA LETTER IYANNA;Lo;0;L;;;;;N;;;;; -0D8A;SINHALA LETTER IIYANNA;Lo;0;L;;;;;N;;;;; -0D8B;SINHALA LETTER UYANNA;Lo;0;L;;;;;N;;;;; -0D8C;SINHALA LETTER UUYANNA;Lo;0;L;;;;;N;;;;; -0D8D;SINHALA LETTER IRUYANNA;Lo;0;L;;;;;N;;;;; -0D8E;SINHALA LETTER IRUUYANNA;Lo;0;L;;;;;N;;;;; -0D8F;SINHALA LETTER ILUYANNA;Lo;0;L;;;;;N;;;;; -0D90;SINHALA LETTER ILUUYANNA;Lo;0;L;;;;;N;;;;; -0D91;SINHALA LETTER EYANNA;Lo;0;L;;;;;N;;;;; -0D92;SINHALA LETTER EEYANNA;Lo;0;L;;;;;N;;;;; -0D93;SINHALA LETTER AIYANNA;Lo;0;L;;;;;N;;;;; -0D94;SINHALA LETTER OYANNA;Lo;0;L;;;;;N;;;;; -0D95;SINHALA LETTER OOYANNA;Lo;0;L;;;;;N;;;;; -0D96;SINHALA LETTER AUYANNA;Lo;0;L;;;;;N;;;;; -0D9A;SINHALA LETTER ALPAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;; -0D9B;SINHALA LETTER MAHAAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;; -0D9C;SINHALA LETTER ALPAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;; -0D9D;SINHALA LETTER MAHAAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;; -0D9E;SINHALA LETTER KANTAJA NAASIKYAYA;Lo;0;L;;;;;N;;;;; -0D9F;SINHALA LETTER SANYAKA GAYANNA;Lo;0;L;;;;;N;;;;; -0DA0;SINHALA LETTER ALPAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;; -0DA1;SINHALA LETTER MAHAAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;; -0DA2;SINHALA LETTER ALPAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;; -0DA3;SINHALA LETTER MAHAAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;; -0DA4;SINHALA LETTER TAALUJA NAASIKYAYA;Lo;0;L;;;;;N;;;;; -0DA5;SINHALA LETTER TAALUJA SANYOOGA NAAKSIKYAYA;Lo;0;L;;;;;N;;;;; -0DA6;SINHALA LETTER SANYAKA JAYANNA;Lo;0;L;;;;;N;;;;; -0DA7;SINHALA LETTER ALPAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;; -0DA8;SINHALA LETTER MAHAAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;; -0DA9;SINHALA LETTER ALPAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;; -0DAA;SINHALA LETTER MAHAAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;; -0DAB;SINHALA LETTER MUURDHAJA NAYANNA;Lo;0;L;;;;;N;;;;; -0DAC;SINHALA LETTER SANYAKA DDAYANNA;Lo;0;L;;;;;N;;;;; -0DAD;SINHALA LETTER ALPAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;; -0DAE;SINHALA LETTER MAHAAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;; -0DAF;SINHALA LETTER ALPAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;; -0DB0;SINHALA LETTER MAHAAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;; -0DB1;SINHALA LETTER DANTAJA NAYANNA;Lo;0;L;;;;;N;;;;; -0DB3;SINHALA LETTER SANYAKA DAYANNA;Lo;0;L;;;;;N;;;;; -0DB4;SINHALA LETTER ALPAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;; -0DB5;SINHALA LETTER MAHAAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;; -0DB6;SINHALA LETTER ALPAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;; -0DB7;SINHALA LETTER MAHAAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;; -0DB8;SINHALA LETTER MAYANNA;Lo;0;L;;;;;N;;;;; -0DB9;SINHALA LETTER AMBA BAYANNA;Lo;0;L;;;;;N;;;;; -0DBA;SINHALA LETTER YAYANNA;Lo;0;L;;;;;N;;;;; -0DBB;SINHALA LETTER RAYANNA;Lo;0;L;;;;;N;;;;; -0DBD;SINHALA LETTER DANTAJA LAYANNA;Lo;0;L;;;;;N;;;;; -0DC0;SINHALA LETTER VAYANNA;Lo;0;L;;;;;N;;;;; -0DC1;SINHALA LETTER TAALUJA SAYANNA;Lo;0;L;;;;;N;;;;; -0DC2;SINHALA LETTER MUURDHAJA SAYANNA;Lo;0;L;;;;;N;;;;; -0DC3;SINHALA LETTER DANTAJA SAYANNA;Lo;0;L;;;;;N;;;;; -0DC4;SINHALA LETTER HAYANNA;Lo;0;L;;;;;N;;;;; -0DC5;SINHALA LETTER MUURDHAJA LAYANNA;Lo;0;L;;;;;N;;;;; -0DC6;SINHALA LETTER FAYANNA;Lo;0;L;;;;;N;;;;; -0DCA;SINHALA SIGN AL-LAKUNA;Mn;9;NSM;;;;;N;;;;; -0DCF;SINHALA VOWEL SIGN AELA-PILLA;Mc;0;L;;;;;N;;;;; -0DD0;SINHALA VOWEL SIGN KETTI AEDA-PILLA;Mc;0;L;;;;;N;;;;; -0DD1;SINHALA VOWEL SIGN DIGA AEDA-PILLA;Mc;0;L;;;;;N;;;;; -0DD2;SINHALA VOWEL SIGN KETTI IS-PILLA;Mn;0;NSM;;;;;N;;;;; -0DD3;SINHALA VOWEL SIGN DIGA IS-PILLA;Mn;0;NSM;;;;;N;;;;; -0DD4;SINHALA VOWEL SIGN KETTI PAA-PILLA;Mn;0;NSM;;;;;N;;;;; -0DD6;SINHALA VOWEL SIGN DIGA PAA-PILLA;Mn;0;NSM;;;;;N;;;;; -0DD8;SINHALA VOWEL SIGN GAETTA-PILLA;Mc;0;L;;;;;N;;;;; -0DD9;SINHALA VOWEL SIGN KOMBUVA;Mc;0;L;;;;;N;;;;; -0DDA;SINHALA VOWEL SIGN DIGA KOMBUVA;Mc;0;L;0DD9 0DCA;;;;N;;;;; -0DDB;SINHALA VOWEL SIGN KOMBU DEKA;Mc;0;L;;;;;N;;;;; -0DDC;SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA;Mc;0;L;0DD9 0DCF;;;;N;;;;; -0DDD;SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA;Mc;0;L;0DDC 0DCA;;;;N;;;;; -0DDE;SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA;Mc;0;L;0DD9 0DDF;;;;N;;;;; -0DDF;SINHALA VOWEL SIGN GAYANUKITTA;Mc;0;L;;;;;N;;;;; -0DE6;SINHALA LITH DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -0DE7;SINHALA LITH DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -0DE8;SINHALA LITH DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -0DE9;SINHALA LITH DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -0DEA;SINHALA LITH DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -0DEB;SINHALA LITH DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -0DEC;SINHALA LITH DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -0DED;SINHALA LITH DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -0DEE;SINHALA LITH DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -0DEF;SINHALA LITH DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -0DF2;SINHALA VOWEL SIGN DIGA GAETTA-PILLA;Mc;0;L;;;;;N;;;;; -0DF3;SINHALA VOWEL SIGN DIGA GAYANUKITTA;Mc;0;L;;;;;N;;;;; -0DF4;SINHALA PUNCTUATION KUNDDALIYA;Po;0;L;;;;;N;;;;; -0E01;THAI CHARACTER KO KAI;Lo;0;L;;;;;N;THAI LETTER KO KAI;;;; -0E02;THAI CHARACTER KHO KHAI;Lo;0;L;;;;;N;THAI LETTER KHO KHAI;;;; -0E03;THAI CHARACTER KHO KHUAT;Lo;0;L;;;;;N;THAI LETTER KHO KHUAT;;;; -0E04;THAI CHARACTER KHO KHWAI;Lo;0;L;;;;;N;THAI LETTER KHO KHWAI;;;; -0E05;THAI CHARACTER KHO KHON;Lo;0;L;;;;;N;THAI LETTER KHO KHON;;;; -0E06;THAI CHARACTER KHO RAKHANG;Lo;0;L;;;;;N;THAI LETTER KHO RAKHANG;;;; -0E07;THAI CHARACTER NGO NGU;Lo;0;L;;;;;N;THAI LETTER NGO NGU;;;; -0E08;THAI CHARACTER CHO CHAN;Lo;0;L;;;;;N;THAI LETTER CHO CHAN;;;; -0E09;THAI CHARACTER CHO CHING;Lo;0;L;;;;;N;THAI LETTER CHO CHING;;;; -0E0A;THAI CHARACTER CHO CHANG;Lo;0;L;;;;;N;THAI LETTER CHO CHANG;;;; -0E0B;THAI CHARACTER SO SO;Lo;0;L;;;;;N;THAI LETTER SO SO;;;; -0E0C;THAI CHARACTER CHO CHOE;Lo;0;L;;;;;N;THAI LETTER CHO CHOE;;;; -0E0D;THAI CHARACTER YO YING;Lo;0;L;;;;;N;THAI LETTER YO YING;;;; -0E0E;THAI CHARACTER DO CHADA;Lo;0;L;;;;;N;THAI LETTER DO CHADA;;;; -0E0F;THAI CHARACTER TO PATAK;Lo;0;L;;;;;N;THAI LETTER TO PATAK;;;; -0E10;THAI CHARACTER THO THAN;Lo;0;L;;;;;N;THAI LETTER THO THAN;;;; -0E11;THAI CHARACTER THO NANGMONTHO;Lo;0;L;;;;;N;THAI LETTER THO NANGMONTHO;;;; -0E12;THAI CHARACTER THO PHUTHAO;Lo;0;L;;;;;N;THAI LETTER THO PHUTHAO;;;; -0E13;THAI CHARACTER NO NEN;Lo;0;L;;;;;N;THAI LETTER NO NEN;;;; -0E14;THAI CHARACTER DO DEK;Lo;0;L;;;;;N;THAI LETTER DO DEK;;;; -0E15;THAI CHARACTER TO TAO;Lo;0;L;;;;;N;THAI LETTER TO TAO;;;; -0E16;THAI CHARACTER THO THUNG;Lo;0;L;;;;;N;THAI LETTER THO THUNG;;;; -0E17;THAI CHARACTER THO THAHAN;Lo;0;L;;;;;N;THAI LETTER THO THAHAN;;;; -0E18;THAI CHARACTER THO THONG;Lo;0;L;;;;;N;THAI LETTER THO THONG;;;; -0E19;THAI CHARACTER NO NU;Lo;0;L;;;;;N;THAI LETTER NO NU;;;; -0E1A;THAI CHARACTER BO BAIMAI;Lo;0;L;;;;;N;THAI LETTER BO BAIMAI;;;; -0E1B;THAI CHARACTER PO PLA;Lo;0;L;;;;;N;THAI LETTER PO PLA;;;; -0E1C;THAI CHARACTER PHO PHUNG;Lo;0;L;;;;;N;THAI LETTER PHO PHUNG;;;; -0E1D;THAI CHARACTER FO FA;Lo;0;L;;;;;N;THAI LETTER FO FA;;;; -0E1E;THAI CHARACTER PHO PHAN;Lo;0;L;;;;;N;THAI LETTER PHO PHAN;;;; -0E1F;THAI CHARACTER FO FAN;Lo;0;L;;;;;N;THAI LETTER FO FAN;;;; -0E20;THAI CHARACTER PHO SAMPHAO;Lo;0;L;;;;;N;THAI LETTER PHO SAMPHAO;;;; -0E21;THAI CHARACTER MO MA;Lo;0;L;;;;;N;THAI LETTER MO MA;;;; -0E22;THAI CHARACTER YO YAK;Lo;0;L;;;;;N;THAI LETTER YO YAK;;;; -0E23;THAI CHARACTER RO RUA;Lo;0;L;;;;;N;THAI LETTER RO RUA;;;; -0E24;THAI CHARACTER RU;Lo;0;L;;;;;N;THAI LETTER RU;;;; -0E25;THAI CHARACTER LO LING;Lo;0;L;;;;;N;THAI LETTER LO LING;;;; -0E26;THAI CHARACTER LU;Lo;0;L;;;;;N;THAI LETTER LU;;;; -0E27;THAI CHARACTER WO WAEN;Lo;0;L;;;;;N;THAI LETTER WO WAEN;;;; -0E28;THAI CHARACTER SO SALA;Lo;0;L;;;;;N;THAI LETTER SO SALA;;;; -0E29;THAI CHARACTER SO RUSI;Lo;0;L;;;;;N;THAI LETTER SO RUSI;;;; -0E2A;THAI CHARACTER SO SUA;Lo;0;L;;;;;N;THAI LETTER SO SUA;;;; -0E2B;THAI CHARACTER HO HIP;Lo;0;L;;;;;N;THAI LETTER HO HIP;;;; -0E2C;THAI CHARACTER LO CHULA;Lo;0;L;;;;;N;THAI LETTER LO CHULA;;;; -0E2D;THAI CHARACTER O ANG;Lo;0;L;;;;;N;THAI LETTER O ANG;;;; -0E2E;THAI CHARACTER HO NOKHUK;Lo;0;L;;;;;N;THAI LETTER HO NOK HUK;;;; -0E2F;THAI CHARACTER PAIYANNOI;Lo;0;L;;;;;N;THAI PAI YAN NOI;;;; -0E30;THAI CHARACTER SARA A;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA A;;;; -0E31;THAI CHARACTER MAI HAN-AKAT;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI HAN-AKAT;;;; -0E32;THAI CHARACTER SARA AA;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AA;;;; -0E33;THAI CHARACTER SARA AM;Lo;0;L;<compat> 0E4D 0E32;;;;N;THAI VOWEL SIGN SARA AM;;;; -0E34;THAI CHARACTER SARA I;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA I;;;; -0E35;THAI CHARACTER SARA II;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA II;;;; -0E36;THAI CHARACTER SARA UE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UE;;;; -0E37;THAI CHARACTER SARA UEE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UEE;;;; -0E38;THAI CHARACTER SARA U;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA U;;;; -0E39;THAI CHARACTER SARA UU;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA UU;;;; -0E3A;THAI CHARACTER PHINTHU;Mn;9;NSM;;;;;N;THAI VOWEL SIGN PHINTHU;;;; -0E3F;THAI CURRENCY SYMBOL BAHT;Sc;0;ET;;;;;N;THAI BAHT SIGN;;;; -0E40;THAI CHARACTER SARA E;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA E;;;; -0E41;THAI CHARACTER SARA AE;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AE;;;; -0E42;THAI CHARACTER SARA O;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA O;;;; -0E43;THAI CHARACTER SARA AI MAIMUAN;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MUAN;;;; -0E44;THAI CHARACTER SARA AI MAIMALAI;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MALAI;;;; -0E45;THAI CHARACTER LAKKHANGYAO;Lo;0;L;;;;;N;THAI LAK KHANG YAO;;;; -0E46;THAI CHARACTER MAIYAMOK;Lm;0;L;;;;;N;THAI MAI YAMOK;;;; -0E47;THAI CHARACTER MAITAIKHU;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI TAI KHU;;;; -0E48;THAI CHARACTER MAI EK;Mn;107;NSM;;;;;N;THAI TONE MAI EK;;;; -0E49;THAI CHARACTER MAI THO;Mn;107;NSM;;;;;N;THAI TONE MAI THO;;;; -0E4A;THAI CHARACTER MAI TRI;Mn;107;NSM;;;;;N;THAI TONE MAI TRI;;;; -0E4B;THAI CHARACTER MAI CHATTAWA;Mn;107;NSM;;;;;N;THAI TONE MAI CHATTAWA;;;; -0E4C;THAI CHARACTER THANTHAKHAT;Mn;0;NSM;;;;;N;THAI THANTHAKHAT;;;; -0E4D;THAI CHARACTER NIKHAHIT;Mn;0;NSM;;;;;N;THAI NIKKHAHIT;;;; -0E4E;THAI CHARACTER YAMAKKAN;Mn;0;NSM;;;;;N;THAI YAMAKKAN;;;; -0E4F;THAI CHARACTER FONGMAN;Po;0;L;;;;;N;THAI FONGMAN;;;; -0E50;THAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -0E51;THAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -0E52;THAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -0E53;THAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -0E54;THAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -0E55;THAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -0E56;THAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -0E57;THAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -0E58;THAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -0E59;THAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -0E5A;THAI CHARACTER ANGKHANKHU;Po;0;L;;;;;N;THAI ANGKHANKHU;;;; -0E5B;THAI CHARACTER KHOMUT;Po;0;L;;;;;N;THAI KHOMUT;;;; -0E81;LAO LETTER KO;Lo;0;L;;;;;N;;;;; -0E82;LAO LETTER KHO SUNG;Lo;0;L;;;;;N;;;;; -0E84;LAO LETTER KHO TAM;Lo;0;L;;;;;N;;;;; -0E86;LAO LETTER PALI GHA;Lo;0;L;;;;;N;;;;; -0E87;LAO LETTER NGO;Lo;0;L;;;;;N;;;;; -0E88;LAO LETTER CO;Lo;0;L;;;;;N;;;;; -0E89;LAO LETTER PALI CHA;Lo;0;L;;;;;N;;;;; -0E8A;LAO LETTER SO TAM;Lo;0;L;;;;;N;;;;; -0E8C;LAO LETTER PALI JHA;Lo;0;L;;;;;N;;;;; -0E8D;LAO LETTER NYO;Lo;0;L;;;;;N;;;;; -0E8E;LAO LETTER PALI NYA;Lo;0;L;;;;;N;;;;; -0E8F;LAO LETTER PALI TTA;Lo;0;L;;;;;N;;;;; -0E90;LAO LETTER PALI TTHA;Lo;0;L;;;;;N;;;;; -0E91;LAO LETTER PALI DDA;Lo;0;L;;;;;N;;;;; -0E92;LAO LETTER PALI DDHA;Lo;0;L;;;;;N;;;;; -0E93;LAO LETTER PALI NNA;Lo;0;L;;;;;N;;;;; -0E94;LAO LETTER DO;Lo;0;L;;;;;N;;;;; -0E95;LAO LETTER TO;Lo;0;L;;;;;N;;;;; -0E96;LAO LETTER THO SUNG;Lo;0;L;;;;;N;;;;; -0E97;LAO LETTER THO TAM;Lo;0;L;;;;;N;;;;; -0E98;LAO LETTER PALI DHA;Lo;0;L;;;;;N;;;;; -0E99;LAO LETTER NO;Lo;0;L;;;;;N;;;;; -0E9A;LAO LETTER BO;Lo;0;L;;;;;N;;;;; -0E9B;LAO LETTER PO;Lo;0;L;;;;;N;;;;; -0E9C;LAO LETTER PHO SUNG;Lo;0;L;;;;;N;;;;; -0E9D;LAO LETTER FO TAM;Lo;0;L;;;;;N;;;;; -0E9E;LAO LETTER PHO TAM;Lo;0;L;;;;;N;;;;; -0E9F;LAO LETTER FO SUNG;Lo;0;L;;;;;N;;;;; -0EA0;LAO LETTER PALI BHA;Lo;0;L;;;;;N;;;;; -0EA1;LAO LETTER MO;Lo;0;L;;;;;N;;;;; -0EA2;LAO LETTER YO;Lo;0;L;;;;;N;;;;; -0EA3;LAO LETTER LO LING;Lo;0;L;;;;;N;;;;; -0EA5;LAO LETTER LO LOOT;Lo;0;L;;;;;N;;;;; -0EA7;LAO LETTER WO;Lo;0;L;;;;;N;;;;; -0EA8;LAO LETTER SANSKRIT SHA;Lo;0;L;;;;;N;;;;; -0EA9;LAO LETTER SANSKRIT SSA;Lo;0;L;;;;;N;;;;; -0EAA;LAO LETTER SO SUNG;Lo;0;L;;;;;N;;;;; -0EAB;LAO LETTER HO SUNG;Lo;0;L;;;;;N;;;;; -0EAC;LAO LETTER PALI LLA;Lo;0;L;;;;;N;;;;; -0EAD;LAO LETTER O;Lo;0;L;;;;;N;;;;; -0EAE;LAO LETTER HO TAM;Lo;0;L;;;;;N;;;;; -0EAF;LAO ELLIPSIS;Lo;0;L;;;;;N;;;;; -0EB0;LAO VOWEL SIGN A;Lo;0;L;;;;;N;;;;; -0EB1;LAO VOWEL SIGN MAI KAN;Mn;0;NSM;;;;;N;;;;; -0EB2;LAO VOWEL SIGN AA;Lo;0;L;;;;;N;;;;; -0EB3;LAO VOWEL SIGN AM;Lo;0;L;<compat> 0ECD 0EB2;;;;N;;;;; -0EB4;LAO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -0EB5;LAO VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; -0EB6;LAO VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;; -0EB7;LAO VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;; -0EB8;LAO VOWEL SIGN U;Mn;118;NSM;;;;;N;;;;; -0EB9;LAO VOWEL SIGN UU;Mn;118;NSM;;;;;N;;;;; -0EBA;LAO SIGN PALI VIRAMA;Mn;9;NSM;;;;;N;;;;; -0EBB;LAO VOWEL SIGN MAI KON;Mn;0;NSM;;;;;N;;;;; -0EBC;LAO SEMIVOWEL SIGN LO;Mn;0;NSM;;;;;N;;;;; -0EBD;LAO SEMIVOWEL SIGN NYO;Lo;0;L;;;;;N;;;;; -0EC0;LAO VOWEL SIGN E;Lo;0;L;;;;;N;;;;; -0EC1;LAO VOWEL SIGN EI;Lo;0;L;;;;;N;;;;; -0EC2;LAO VOWEL SIGN O;Lo;0;L;;;;;N;;;;; -0EC3;LAO VOWEL SIGN AY;Lo;0;L;;;;;N;;;;; -0EC4;LAO VOWEL SIGN AI;Lo;0;L;;;;;N;;;;; -0EC6;LAO KO LA;Lm;0;L;;;;;N;;;;; -0EC8;LAO TONE MAI EK;Mn;122;NSM;;;;;N;;;;; -0EC9;LAO TONE MAI THO;Mn;122;NSM;;;;;N;;;;; -0ECA;LAO TONE MAI TI;Mn;122;NSM;;;;;N;;;;; -0ECB;LAO TONE MAI CATAWA;Mn;122;NSM;;;;;N;;;;; -0ECC;LAO CANCELLATION MARK;Mn;0;NSM;;;;;N;;;;; -0ECD;LAO NIGGAHITA;Mn;0;NSM;;;;;N;;;;; -0ECE;LAO YAMAKKAN;Mn;0;NSM;;;;;N;;;;; -0ED0;LAO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -0ED1;LAO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -0ED2;LAO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -0ED3;LAO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -0ED4;LAO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -0ED5;LAO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -0ED6;LAO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -0ED7;LAO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -0ED8;LAO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -0ED9;LAO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -0EDC;LAO HO NO;Lo;0;L;<compat> 0EAB 0E99;;;;N;;;;; -0EDD;LAO HO MO;Lo;0;L;<compat> 0EAB 0EA1;;;;N;;;;; -0EDE;LAO LETTER KHMU GO;Lo;0;L;;;;;N;;;;; -0EDF;LAO LETTER KHMU NYO;Lo;0;L;;;;;N;;;;; -0F00;TIBETAN SYLLABLE OM;Lo;0;L;;;;;N;;;;; -0F01;TIBETAN MARK GTER YIG MGO TRUNCATED A;So;0;L;;;;;N;;;;; -0F02;TIBETAN MARK GTER YIG MGO -UM RNAM BCAD MA;So;0;L;;;;;N;;;;; -0F03;TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA;So;0;L;;;;;N;;;;; -0F04;TIBETAN MARK INITIAL YIG MGO MDUN MA;Po;0;L;;;;;N;TIBETAN SINGLE ORNAMENT;;;; -0F05;TIBETAN MARK CLOSING YIG MGO SGAB MA;Po;0;L;;;;;N;;;;; -0F06;TIBETAN MARK CARET YIG MGO PHUR SHAD MA;Po;0;L;;;;;N;;;;; -0F07;TIBETAN MARK YIG MGO TSHEG SHAD MA;Po;0;L;;;;;N;;;;; -0F08;TIBETAN MARK SBRUL SHAD;Po;0;L;;;;;N;TIBETAN RGYANSHAD;;;; -0F09;TIBETAN MARK BSKUR YIG MGO;Po;0;L;;;;;N;;;;; -0F0A;TIBETAN MARK BKA- SHOG YIG MGO;Po;0;L;;;;;N;;;;; -0F0B;TIBETAN MARK INTERSYLLABIC TSHEG;Po;0;L;;;;;N;TIBETAN TSEG;;;; -0F0C;TIBETAN MARK DELIMITER TSHEG BSTAR;Po;0;L;<noBreak> 0F0B;;;;N;;;;; -0F0D;TIBETAN MARK SHAD;Po;0;L;;;;;N;TIBETAN SHAD;;;; -0F0E;TIBETAN MARK NYIS SHAD;Po;0;L;;;;;N;TIBETAN DOUBLE SHAD;;;; -0F0F;TIBETAN MARK TSHEG SHAD;Po;0;L;;;;;N;;;;; -0F10;TIBETAN MARK NYIS TSHEG SHAD;Po;0;L;;;;;N;;;;; -0F11;TIBETAN MARK RIN CHEN SPUNGS SHAD;Po;0;L;;;;;N;TIBETAN RINCHANPHUNGSHAD;;;; -0F12;TIBETAN MARK RGYA GRAM SHAD;Po;0;L;;;;;N;;;;; -0F13;TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN;So;0;L;;;;;N;;;;; -0F14;TIBETAN MARK GTER TSHEG;Po;0;L;;;;;N;TIBETAN COMMA;;;; -0F15;TIBETAN LOGOTYPE SIGN CHAD RTAGS;So;0;L;;;;;N;;;;; -0F16;TIBETAN LOGOTYPE SIGN LHAG RTAGS;So;0;L;;;;;N;;;;; -0F17;TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS;So;0;L;;;;;N;;;;; -0F18;TIBETAN ASTROLOGICAL SIGN -KHYUD PA;Mn;220;NSM;;;;;N;;;;; -0F19;TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS;Mn;220;NSM;;;;;N;;;;; -0F1A;TIBETAN SIGN RDEL DKAR GCIG;So;0;L;;;;;N;;;;; -0F1B;TIBETAN SIGN RDEL DKAR GNYIS;So;0;L;;;;;N;;;;; -0F1C;TIBETAN SIGN RDEL DKAR GSUM;So;0;L;;;;;N;;;;; -0F1D;TIBETAN SIGN RDEL NAG GCIG;So;0;L;;;;;N;;;;; -0F1E;TIBETAN SIGN RDEL NAG GNYIS;So;0;L;;;;;N;;;;; -0F1F;TIBETAN SIGN RDEL DKAR RDEL NAG;So;0;L;;;;;N;;;;; -0F20;TIBETAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -0F21;TIBETAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -0F22;TIBETAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -0F23;TIBETAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -0F24;TIBETAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -0F25;TIBETAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -0F26;TIBETAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -0F27;TIBETAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -0F28;TIBETAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -0F29;TIBETAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -0F2A;TIBETAN DIGIT HALF ONE;No;0;L;;;;1/2;N;;;;; -0F2B;TIBETAN DIGIT HALF TWO;No;0;L;;;;3/2;N;;;;; -0F2C;TIBETAN DIGIT HALF THREE;No;0;L;;;;5/2;N;;;;; -0F2D;TIBETAN DIGIT HALF FOUR;No;0;L;;;;7/2;N;;;;; -0F2E;TIBETAN DIGIT HALF FIVE;No;0;L;;;;9/2;N;;;;; -0F2F;TIBETAN DIGIT HALF SIX;No;0;L;;;;11/2;N;;;;; -0F30;TIBETAN DIGIT HALF SEVEN;No;0;L;;;;13/2;N;;;;; -0F31;TIBETAN DIGIT HALF EIGHT;No;0;L;;;;15/2;N;;;;; -0F32;TIBETAN DIGIT HALF NINE;No;0;L;;;;17/2;N;;;;; -0F33;TIBETAN DIGIT HALF ZERO;No;0;L;;;;-1/2;N;;;;; -0F34;TIBETAN MARK BSDUS RTAGS;So;0;L;;;;;N;;;;; -0F35;TIBETAN MARK NGAS BZUNG NYI ZLA;Mn;220;NSM;;;;;N;TIBETAN HONORIFIC UNDER RING;;;; -0F36;TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN;So;0;L;;;;;N;;;;; -0F37;TIBETAN MARK NGAS BZUNG SGOR RTAGS;Mn;220;NSM;;;;;N;TIBETAN UNDER RING;;;; -0F38;TIBETAN MARK CHE MGO;So;0;L;;;;;N;;;;; -0F39;TIBETAN MARK TSA -PHRU;Mn;216;NSM;;;;;N;TIBETAN LENITION MARK;;;; -0F3A;TIBETAN MARK GUG RTAGS GYON;Ps;0;ON;;;;;Y;;;;; -0F3B;TIBETAN MARK GUG RTAGS GYAS;Pe;0;ON;;;;;Y;;;;; -0F3C;TIBETAN MARK ANG KHANG GYON;Ps;0;ON;;;;;Y;TIBETAN LEFT BRACE;;;; -0F3D;TIBETAN MARK ANG KHANG GYAS;Pe;0;ON;;;;;Y;TIBETAN RIGHT BRACE;;;; -0F3E;TIBETAN SIGN YAR TSHES;Mc;0;L;;;;;N;;;;; -0F3F;TIBETAN SIGN MAR TSHES;Mc;0;L;;;;;N;;;;; -0F40;TIBETAN LETTER KA;Lo;0;L;;;;;N;;;;; -0F41;TIBETAN LETTER KHA;Lo;0;L;;;;;N;;;;; -0F42;TIBETAN LETTER GA;Lo;0;L;;;;;N;;;;; -0F43;TIBETAN LETTER GHA;Lo;0;L;0F42 0FB7;;;;N;;;;; -0F44;TIBETAN LETTER NGA;Lo;0;L;;;;;N;;;;; -0F45;TIBETAN LETTER CA;Lo;0;L;;;;;N;;;;; -0F46;TIBETAN LETTER CHA;Lo;0;L;;;;;N;;;;; -0F47;TIBETAN LETTER JA;Lo;0;L;;;;;N;;;;; -0F49;TIBETAN LETTER NYA;Lo;0;L;;;;;N;;;;; -0F4A;TIBETAN LETTER TTA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED TA;;;; -0F4B;TIBETAN LETTER TTHA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED THA;;;; -0F4C;TIBETAN LETTER DDA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED DA;;;; -0F4D;TIBETAN LETTER DDHA;Lo;0;L;0F4C 0FB7;;;;N;;;;; -0F4E;TIBETAN LETTER NNA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED NA;;;; -0F4F;TIBETAN LETTER TA;Lo;0;L;;;;;N;;;;; -0F50;TIBETAN LETTER THA;Lo;0;L;;;;;N;;;;; -0F51;TIBETAN LETTER DA;Lo;0;L;;;;;N;;;;; -0F52;TIBETAN LETTER DHA;Lo;0;L;0F51 0FB7;;;;N;;;;; -0F53;TIBETAN LETTER NA;Lo;0;L;;;;;N;;;;; -0F54;TIBETAN LETTER PA;Lo;0;L;;;;;N;;;;; -0F55;TIBETAN LETTER PHA;Lo;0;L;;;;;N;;;;; -0F56;TIBETAN LETTER BA;Lo;0;L;;;;;N;;;;; -0F57;TIBETAN LETTER BHA;Lo;0;L;0F56 0FB7;;;;N;;;;; -0F58;TIBETAN LETTER MA;Lo;0;L;;;;;N;;;;; -0F59;TIBETAN LETTER TSA;Lo;0;L;;;;;N;;;;; -0F5A;TIBETAN LETTER TSHA;Lo;0;L;;;;;N;;;;; -0F5B;TIBETAN LETTER DZA;Lo;0;L;;;;;N;;;;; -0F5C;TIBETAN LETTER DZHA;Lo;0;L;0F5B 0FB7;;;;N;;;;; -0F5D;TIBETAN LETTER WA;Lo;0;L;;;;;N;;;;; -0F5E;TIBETAN LETTER ZHA;Lo;0;L;;;;;N;;;;; -0F5F;TIBETAN LETTER ZA;Lo;0;L;;;;;N;;;;; -0F60;TIBETAN LETTER -A;Lo;0;L;;;;;N;TIBETAN LETTER AA;;;; -0F61;TIBETAN LETTER YA;Lo;0;L;;;;;N;;;;; -0F62;TIBETAN LETTER RA;Lo;0;L;;;;;N;;;;; -0F63;TIBETAN LETTER LA;Lo;0;L;;;;;N;;;;; -0F64;TIBETAN LETTER SHA;Lo;0;L;;;;;N;;;;; -0F65;TIBETAN LETTER SSA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED SHA;;;; -0F66;TIBETAN LETTER SA;Lo;0;L;;;;;N;;;;; -0F67;TIBETAN LETTER HA;Lo;0;L;;;;;N;;;;; -0F68;TIBETAN LETTER A;Lo;0;L;;;;;N;;;;; -0F69;TIBETAN LETTER KSSA;Lo;0;L;0F40 0FB5;;;;N;;;;; -0F6A;TIBETAN LETTER FIXED-FORM RA;Lo;0;L;;;;;N;;;;; -0F6B;TIBETAN LETTER KKA;Lo;0;L;;;;;N;;;;; -0F6C;TIBETAN LETTER RRA;Lo;0;L;;;;;N;;;;; -0F71;TIBETAN VOWEL SIGN AA;Mn;129;NSM;;;;;N;;;;; -0F72;TIBETAN VOWEL SIGN I;Mn;130;NSM;;;;;N;;;;; -0F73;TIBETAN VOWEL SIGN II;Mn;0;NSM;0F71 0F72;;;;N;;;;; -0F74;TIBETAN VOWEL SIGN U;Mn;132;NSM;;;;;N;;;;; -0F75;TIBETAN VOWEL SIGN UU;Mn;0;NSM;0F71 0F74;;;;N;;;;; -0F76;TIBETAN VOWEL SIGN VOCALIC R;Mn;0;NSM;0FB2 0F80;;;;N;;;;; -0F77;TIBETAN VOWEL SIGN VOCALIC RR;Mn;0;NSM;<compat> 0FB2 0F81;;;;N;;;;; -0F78;TIBETAN VOWEL SIGN VOCALIC L;Mn;0;NSM;0FB3 0F80;;;;N;;;;; -0F79;TIBETAN VOWEL SIGN VOCALIC LL;Mn;0;NSM;<compat> 0FB3 0F81;;;;N;;;;; -0F7A;TIBETAN VOWEL SIGN E;Mn;130;NSM;;;;;N;;;;; -0F7B;TIBETAN VOWEL SIGN EE;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AI;;;; -0F7C;TIBETAN VOWEL SIGN O;Mn;130;NSM;;;;;N;;;;; -0F7D;TIBETAN VOWEL SIGN OO;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AU;;;; -0F7E;TIBETAN SIGN RJES SU NGA RO;Mn;0;NSM;;;;;N;TIBETAN ANUSVARA;;;; -0F7F;TIBETAN SIGN RNAM BCAD;Mc;0;L;;;;;N;TIBETAN VISARGA;;;; -0F80;TIBETAN VOWEL SIGN REVERSED I;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN SHORT I;;;; -0F81;TIBETAN VOWEL SIGN REVERSED II;Mn;0;NSM;0F71 0F80;;;;N;;;;; -0F82;TIBETAN SIGN NYI ZLA NAA DA;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU WITH ORNAMENT;;;; -0F83;TIBETAN SIGN SNA LDAN;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU;;;; -0F84;TIBETAN MARK HALANTA;Mn;9;NSM;;;;;N;TIBETAN VIRAMA;;;; -0F85;TIBETAN MARK PALUTA;Po;0;L;;;;;N;TIBETAN CHUCHENYIGE;;;; -0F86;TIBETAN SIGN LCI RTAGS;Mn;230;NSM;;;;;N;;;;; -0F87;TIBETAN SIGN YANG RTAGS;Mn;230;NSM;;;;;N;;;;; -0F88;TIBETAN SIGN LCE TSA CAN;Lo;0;L;;;;;N;;;;; -0F89;TIBETAN SIGN MCHU CAN;Lo;0;L;;;;;N;;;;; -0F8A;TIBETAN SIGN GRU CAN RGYINGS;Lo;0;L;;;;;N;;;;; -0F8B;TIBETAN SIGN GRU MED RGYINGS;Lo;0;L;;;;;N;;;;; -0F8C;TIBETAN SIGN INVERTED MCHU CAN;Lo;0;L;;;;;N;;;;; -0F8D;TIBETAN SUBJOINED SIGN LCE TSA CAN;Mn;0;NSM;;;;;N;;;;; -0F8E;TIBETAN SUBJOINED SIGN MCHU CAN;Mn;0;NSM;;;;;N;;;;; -0F8F;TIBETAN SUBJOINED SIGN INVERTED MCHU CAN;Mn;0;NSM;;;;;N;;;;; -0F90;TIBETAN SUBJOINED LETTER KA;Mn;0;NSM;;;;;N;;;;; -0F91;TIBETAN SUBJOINED LETTER KHA;Mn;0;NSM;;;;;N;;;;; -0F92;TIBETAN SUBJOINED LETTER GA;Mn;0;NSM;;;;;N;;;;; -0F93;TIBETAN SUBJOINED LETTER GHA;Mn;0;NSM;0F92 0FB7;;;;N;;;;; -0F94;TIBETAN SUBJOINED LETTER NGA;Mn;0;NSM;;;;;N;;;;; -0F95;TIBETAN SUBJOINED LETTER CA;Mn;0;NSM;;;;;N;;;;; -0F96;TIBETAN SUBJOINED LETTER CHA;Mn;0;NSM;;;;;N;;;;; -0F97;TIBETAN SUBJOINED LETTER JA;Mn;0;NSM;;;;;N;;;;; -0F99;TIBETAN SUBJOINED LETTER NYA;Mn;0;NSM;;;;;N;;;;; -0F9A;TIBETAN SUBJOINED LETTER TTA;Mn;0;NSM;;;;;N;;;;; -0F9B;TIBETAN SUBJOINED LETTER TTHA;Mn;0;NSM;;;;;N;;;;; -0F9C;TIBETAN SUBJOINED LETTER DDA;Mn;0;NSM;;;;;N;;;;; -0F9D;TIBETAN SUBJOINED LETTER DDHA;Mn;0;NSM;0F9C 0FB7;;;;N;;;;; -0F9E;TIBETAN SUBJOINED LETTER NNA;Mn;0;NSM;;;;;N;;;;; -0F9F;TIBETAN SUBJOINED LETTER TA;Mn;0;NSM;;;;;N;;;;; -0FA0;TIBETAN SUBJOINED LETTER THA;Mn;0;NSM;;;;;N;;;;; -0FA1;TIBETAN SUBJOINED LETTER DA;Mn;0;NSM;;;;;N;;;;; -0FA2;TIBETAN SUBJOINED LETTER DHA;Mn;0;NSM;0FA1 0FB7;;;;N;;;;; -0FA3;TIBETAN SUBJOINED LETTER NA;Mn;0;NSM;;;;;N;;;;; -0FA4;TIBETAN SUBJOINED LETTER PA;Mn;0;NSM;;;;;N;;;;; -0FA5;TIBETAN SUBJOINED LETTER PHA;Mn;0;NSM;;;;;N;;;;; -0FA6;TIBETAN SUBJOINED LETTER BA;Mn;0;NSM;;;;;N;;;;; -0FA7;TIBETAN SUBJOINED LETTER BHA;Mn;0;NSM;0FA6 0FB7;;;;N;;;;; -0FA8;TIBETAN SUBJOINED LETTER MA;Mn;0;NSM;;;;;N;;;;; -0FA9;TIBETAN SUBJOINED LETTER TSA;Mn;0;NSM;;;;;N;;;;; -0FAA;TIBETAN SUBJOINED LETTER TSHA;Mn;0;NSM;;;;;N;;;;; -0FAB;TIBETAN SUBJOINED LETTER DZA;Mn;0;NSM;;;;;N;;;;; -0FAC;TIBETAN SUBJOINED LETTER DZHA;Mn;0;NSM;0FAB 0FB7;;;;N;;;;; -0FAD;TIBETAN SUBJOINED LETTER WA;Mn;0;NSM;;;;;N;;;;; -0FAE;TIBETAN SUBJOINED LETTER ZHA;Mn;0;NSM;;;;;N;;;;; -0FAF;TIBETAN SUBJOINED LETTER ZA;Mn;0;NSM;;;;;N;;;;; -0FB0;TIBETAN SUBJOINED LETTER -A;Mn;0;NSM;;;;;N;;;;; -0FB1;TIBETAN SUBJOINED LETTER YA;Mn;0;NSM;;;;;N;;;;; -0FB2;TIBETAN SUBJOINED LETTER RA;Mn;0;NSM;;;;;N;;;;; -0FB3;TIBETAN SUBJOINED LETTER LA;Mn;0;NSM;;;;;N;;;;; -0FB4;TIBETAN SUBJOINED LETTER SHA;Mn;0;NSM;;;;;N;;;;; -0FB5;TIBETAN SUBJOINED LETTER SSA;Mn;0;NSM;;;;;N;;;;; -0FB6;TIBETAN SUBJOINED LETTER SA;Mn;0;NSM;;;;;N;;;;; -0FB7;TIBETAN SUBJOINED LETTER HA;Mn;0;NSM;;;;;N;;;;; -0FB8;TIBETAN SUBJOINED LETTER A;Mn;0;NSM;;;;;N;;;;; -0FB9;TIBETAN SUBJOINED LETTER KSSA;Mn;0;NSM;0F90 0FB5;;;;N;;;;; -0FBA;TIBETAN SUBJOINED LETTER FIXED-FORM WA;Mn;0;NSM;;;;;N;;;;; -0FBB;TIBETAN SUBJOINED LETTER FIXED-FORM YA;Mn;0;NSM;;;;;N;;;;; -0FBC;TIBETAN SUBJOINED LETTER FIXED-FORM RA;Mn;0;NSM;;;;;N;;;;; -0FBE;TIBETAN KU RU KHA;So;0;L;;;;;N;;;;; -0FBF;TIBETAN KU RU KHA BZHI MIG CAN;So;0;L;;;;;N;;;;; -0FC0;TIBETAN CANTILLATION SIGN HEAVY BEAT;So;0;L;;;;;N;;;;; -0FC1;TIBETAN CANTILLATION SIGN LIGHT BEAT;So;0;L;;;;;N;;;;; -0FC2;TIBETAN CANTILLATION SIGN CANG TE-U;So;0;L;;;;;N;;;;; -0FC3;TIBETAN CANTILLATION SIGN SBUB -CHAL;So;0;L;;;;;N;;;;; -0FC4;TIBETAN SYMBOL DRIL BU;So;0;L;;;;;N;;;;; -0FC5;TIBETAN SYMBOL RDO RJE;So;0;L;;;;;N;;;;; -0FC6;TIBETAN SYMBOL PADMA GDAN;Mn;220;NSM;;;;;N;;;;; -0FC7;TIBETAN SYMBOL RDO RJE RGYA GRAM;So;0;L;;;;;N;;;;; -0FC8;TIBETAN SYMBOL PHUR PA;So;0;L;;;;;N;;;;; -0FC9;TIBETAN SYMBOL NOR BU;So;0;L;;;;;N;;;;; -0FCA;TIBETAN SYMBOL NOR BU NYIS -KHYIL;So;0;L;;;;;N;;;;; -0FCB;TIBETAN SYMBOL NOR BU GSUM -KHYIL;So;0;L;;;;;N;;;;; -0FCC;TIBETAN SYMBOL NOR BU BZHI -KHYIL;So;0;L;;;;;N;;;;; -0FCE;TIBETAN SIGN RDEL NAG RDEL DKAR;So;0;L;;;;;N;;;;; -0FCF;TIBETAN SIGN RDEL NAG GSUM;So;0;L;;;;;N;;;;; -0FD0;TIBETAN MARK BSKA- SHOG GI MGO RGYAN;Po;0;L;;;;;N;;;;; -0FD1;TIBETAN MARK MNYAM YIG GI MGO RGYAN;Po;0;L;;;;;N;;;;; -0FD2;TIBETAN MARK NYIS TSHEG;Po;0;L;;;;;N;;;;; -0FD3;TIBETAN MARK INITIAL BRDA RNYING YIG MGO MDUN MA;Po;0;L;;;;;N;;;;; -0FD4;TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA;Po;0;L;;;;;N;;;;; -0FD5;RIGHT-FACING SVASTI SIGN;So;0;L;;;;;N;;;;; -0FD6;LEFT-FACING SVASTI SIGN;So;0;L;;;;;N;;;;; -0FD7;RIGHT-FACING SVASTI SIGN WITH DOTS;So;0;L;;;;;N;;;;; -0FD8;LEFT-FACING SVASTI SIGN WITH DOTS;So;0;L;;;;;N;;;;; -0FD9;TIBETAN MARK LEADING MCHAN RTAGS;Po;0;L;;;;;N;;;;; -0FDA;TIBETAN MARK TRAILING MCHAN RTAGS;Po;0;L;;;;;N;;;;; -1000;MYANMAR LETTER KA;Lo;0;L;;;;;N;;;;; -1001;MYANMAR LETTER KHA;Lo;0;L;;;;;N;;;;; -1002;MYANMAR LETTER GA;Lo;0;L;;;;;N;;;;; -1003;MYANMAR LETTER GHA;Lo;0;L;;;;;N;;;;; -1004;MYANMAR LETTER NGA;Lo;0;L;;;;;N;;;;; -1005;MYANMAR LETTER CA;Lo;0;L;;;;;N;;;;; -1006;MYANMAR LETTER CHA;Lo;0;L;;;;;N;;;;; -1007;MYANMAR LETTER JA;Lo;0;L;;;;;N;;;;; -1008;MYANMAR LETTER JHA;Lo;0;L;;;;;N;;;;; -1009;MYANMAR LETTER NYA;Lo;0;L;;;;;N;;;;; -100A;MYANMAR LETTER NNYA;Lo;0;L;;;;;N;;;;; -100B;MYANMAR LETTER TTA;Lo;0;L;;;;;N;;;;; -100C;MYANMAR LETTER TTHA;Lo;0;L;;;;;N;;;;; -100D;MYANMAR LETTER DDA;Lo;0;L;;;;;N;;;;; -100E;MYANMAR LETTER DDHA;Lo;0;L;;;;;N;;;;; -100F;MYANMAR LETTER NNA;Lo;0;L;;;;;N;;;;; -1010;MYANMAR LETTER TA;Lo;0;L;;;;;N;;;;; -1011;MYANMAR LETTER THA;Lo;0;L;;;;;N;;;;; -1012;MYANMAR LETTER DA;Lo;0;L;;;;;N;;;;; -1013;MYANMAR LETTER DHA;Lo;0;L;;;;;N;;;;; -1014;MYANMAR LETTER NA;Lo;0;L;;;;;N;;;;; -1015;MYANMAR LETTER PA;Lo;0;L;;;;;N;;;;; -1016;MYANMAR LETTER PHA;Lo;0;L;;;;;N;;;;; -1017;MYANMAR LETTER BA;Lo;0;L;;;;;N;;;;; -1018;MYANMAR LETTER BHA;Lo;0;L;;;;;N;;;;; -1019;MYANMAR LETTER MA;Lo;0;L;;;;;N;;;;; -101A;MYANMAR LETTER YA;Lo;0;L;;;;;N;;;;; -101B;MYANMAR LETTER RA;Lo;0;L;;;;;N;;;;; -101C;MYANMAR LETTER LA;Lo;0;L;;;;;N;;;;; -101D;MYANMAR LETTER WA;Lo;0;L;;;;;N;;;;; -101E;MYANMAR LETTER SA;Lo;0;L;;;;;N;;;;; -101F;MYANMAR LETTER HA;Lo;0;L;;;;;N;;;;; -1020;MYANMAR LETTER LLA;Lo;0;L;;;;;N;;;;; -1021;MYANMAR LETTER A;Lo;0;L;;;;;N;;;;; -1022;MYANMAR LETTER SHAN A;Lo;0;L;;;;;N;;;;; -1023;MYANMAR LETTER I;Lo;0;L;;;;;N;;;;; -1024;MYANMAR LETTER II;Lo;0;L;;;;;N;;;;; -1025;MYANMAR LETTER U;Lo;0;L;;;;;N;;;;; -1026;MYANMAR LETTER UU;Lo;0;L;1025 102E;;;;N;;;;; -1027;MYANMAR LETTER E;Lo;0;L;;;;;N;;;;; -1028;MYANMAR LETTER MON E;Lo;0;L;;;;;N;;;;; -1029;MYANMAR LETTER O;Lo;0;L;;;;;N;;;;; -102A;MYANMAR LETTER AU;Lo;0;L;;;;;N;;;;; -102B;MYANMAR VOWEL SIGN TALL AA;Mc;0;L;;;;;N;;;;; -102C;MYANMAR VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -102D;MYANMAR VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -102E;MYANMAR VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; -102F;MYANMAR VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -1030;MYANMAR VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -1031;MYANMAR VOWEL SIGN E;Mc;0;L;;;;;N;;;;; -1032;MYANMAR VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -1033;MYANMAR VOWEL SIGN MON II;Mn;0;NSM;;;;;N;;;;; -1034;MYANMAR VOWEL SIGN MON O;Mn;0;NSM;;;;;N;;;;; -1035;MYANMAR VOWEL SIGN E ABOVE;Mn;0;NSM;;;;;N;;;;; -1036;MYANMAR SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -1037;MYANMAR SIGN DOT BELOW;Mn;7;NSM;;;;;N;;;;; -1038;MYANMAR SIGN VISARGA;Mc;0;L;;;;;N;;;;; -1039;MYANMAR SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -103A;MYANMAR SIGN ASAT;Mn;9;NSM;;;;;N;;;;; -103B;MYANMAR CONSONANT SIGN MEDIAL YA;Mc;0;L;;;;;N;;;;; -103C;MYANMAR CONSONANT SIGN MEDIAL RA;Mc;0;L;;;;;N;;;;; -103D;MYANMAR CONSONANT SIGN MEDIAL WA;Mn;0;NSM;;;;;N;;;;; -103E;MYANMAR CONSONANT SIGN MEDIAL HA;Mn;0;NSM;;;;;N;;;;; -103F;MYANMAR LETTER GREAT SA;Lo;0;L;;;;;N;;;;; -1040;MYANMAR DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -1041;MYANMAR DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -1042;MYANMAR DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -1043;MYANMAR DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -1044;MYANMAR DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -1045;MYANMAR DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -1046;MYANMAR DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -1047;MYANMAR DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -1048;MYANMAR DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -1049;MYANMAR DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -104A;MYANMAR SIGN LITTLE SECTION;Po;0;L;;;;;N;;;;; -104B;MYANMAR SIGN SECTION;Po;0;L;;;;;N;;;;; -104C;MYANMAR SYMBOL LOCATIVE;Po;0;L;;;;;N;;;;; -104D;MYANMAR SYMBOL COMPLETED;Po;0;L;;;;;N;;;;; -104E;MYANMAR SYMBOL AFOREMENTIONED;Po;0;L;;;;;N;;;;; -104F;MYANMAR SYMBOL GENITIVE;Po;0;L;;;;;N;;;;; -1050;MYANMAR LETTER SHA;Lo;0;L;;;;;N;;;;; -1051;MYANMAR LETTER SSA;Lo;0;L;;;;;N;;;;; -1052;MYANMAR LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; -1053;MYANMAR LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; -1054;MYANMAR LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; -1055;MYANMAR LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; -1056;MYANMAR VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; -1057;MYANMAR VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; -1058;MYANMAR VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; -1059;MYANMAR VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; -105A;MYANMAR LETTER MON NGA;Lo;0;L;;;;;N;;;;; -105B;MYANMAR LETTER MON JHA;Lo;0;L;;;;;N;;;;; -105C;MYANMAR LETTER MON BBA;Lo;0;L;;;;;N;;;;; -105D;MYANMAR LETTER MON BBE;Lo;0;L;;;;;N;;;;; -105E;MYANMAR CONSONANT SIGN MON MEDIAL NA;Mn;0;NSM;;;;;N;;;;; -105F;MYANMAR CONSONANT SIGN MON MEDIAL MA;Mn;0;NSM;;;;;N;;;;; -1060;MYANMAR CONSONANT SIGN MON MEDIAL LA;Mn;0;NSM;;;;;N;;;;; -1061;MYANMAR LETTER SGAW KAREN SHA;Lo;0;L;;;;;N;;;;; -1062;MYANMAR VOWEL SIGN SGAW KAREN EU;Mc;0;L;;;;;N;;;;; -1063;MYANMAR TONE MARK SGAW KAREN HATHI;Mc;0;L;;;;;N;;;;; -1064;MYANMAR TONE MARK SGAW KAREN KE PHO;Mc;0;L;;;;;N;;;;; -1065;MYANMAR LETTER WESTERN PWO KAREN THA;Lo;0;L;;;;;N;;;;; -1066;MYANMAR LETTER WESTERN PWO KAREN PWA;Lo;0;L;;;;;N;;;;; -1067;MYANMAR VOWEL SIGN WESTERN PWO KAREN EU;Mc;0;L;;;;;N;;;;; -1068;MYANMAR VOWEL SIGN WESTERN PWO KAREN UE;Mc;0;L;;;;;N;;;;; -1069;MYANMAR SIGN WESTERN PWO KAREN TONE-1;Mc;0;L;;;;;N;;;;; -106A;MYANMAR SIGN WESTERN PWO KAREN TONE-2;Mc;0;L;;;;;N;;;;; -106B;MYANMAR SIGN WESTERN PWO KAREN TONE-3;Mc;0;L;;;;;N;;;;; -106C;MYANMAR SIGN WESTERN PWO KAREN TONE-4;Mc;0;L;;;;;N;;;;; -106D;MYANMAR SIGN WESTERN PWO KAREN TONE-5;Mc;0;L;;;;;N;;;;; -106E;MYANMAR LETTER EASTERN PWO KAREN NNA;Lo;0;L;;;;;N;;;;; -106F;MYANMAR LETTER EASTERN PWO KAREN YWA;Lo;0;L;;;;;N;;;;; -1070;MYANMAR LETTER EASTERN PWO KAREN GHWA;Lo;0;L;;;;;N;;;;; -1071;MYANMAR VOWEL SIGN GEBA KAREN I;Mn;0;NSM;;;;;N;;;;; -1072;MYANMAR VOWEL SIGN KAYAH OE;Mn;0;NSM;;;;;N;;;;; -1073;MYANMAR VOWEL SIGN KAYAH U;Mn;0;NSM;;;;;N;;;;; -1074;MYANMAR VOWEL SIGN KAYAH EE;Mn;0;NSM;;;;;N;;;;; -1075;MYANMAR LETTER SHAN KA;Lo;0;L;;;;;N;;;;; -1076;MYANMAR LETTER SHAN KHA;Lo;0;L;;;;;N;;;;; -1077;MYANMAR LETTER SHAN GA;Lo;0;L;;;;;N;;;;; -1078;MYANMAR LETTER SHAN CA;Lo;0;L;;;;;N;;;;; -1079;MYANMAR LETTER SHAN ZA;Lo;0;L;;;;;N;;;;; -107A;MYANMAR LETTER SHAN NYA;Lo;0;L;;;;;N;;;;; -107B;MYANMAR LETTER SHAN DA;Lo;0;L;;;;;N;;;;; -107C;MYANMAR LETTER SHAN NA;Lo;0;L;;;;;N;;;;; -107D;MYANMAR LETTER SHAN PHA;Lo;0;L;;;;;N;;;;; -107E;MYANMAR LETTER SHAN FA;Lo;0;L;;;;;N;;;;; -107F;MYANMAR LETTER SHAN BA;Lo;0;L;;;;;N;;;;; -1080;MYANMAR LETTER SHAN THA;Lo;0;L;;;;;N;;;;; -1081;MYANMAR LETTER SHAN HA;Lo;0;L;;;;;N;;;;; -1082;MYANMAR CONSONANT SIGN SHAN MEDIAL WA;Mn;0;NSM;;;;;N;;;;; -1083;MYANMAR VOWEL SIGN SHAN AA;Mc;0;L;;;;;N;;;;; -1084;MYANMAR VOWEL SIGN SHAN E;Mc;0;L;;;;;N;;;;; -1085;MYANMAR VOWEL SIGN SHAN E ABOVE;Mn;0;NSM;;;;;N;;;;; -1086;MYANMAR VOWEL SIGN SHAN FINAL Y;Mn;0;NSM;;;;;N;;;;; -1087;MYANMAR SIGN SHAN TONE-2;Mc;0;L;;;;;N;;;;; -1088;MYANMAR SIGN SHAN TONE-3;Mc;0;L;;;;;N;;;;; -1089;MYANMAR SIGN SHAN TONE-5;Mc;0;L;;;;;N;;;;; -108A;MYANMAR SIGN SHAN TONE-6;Mc;0;L;;;;;N;;;;; -108B;MYANMAR SIGN SHAN COUNCIL TONE-2;Mc;0;L;;;;;N;;;;; -108C;MYANMAR SIGN SHAN COUNCIL TONE-3;Mc;0;L;;;;;N;;;;; -108D;MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE;Mn;220;NSM;;;;;N;;;;; -108E;MYANMAR LETTER RUMAI PALAUNG FA;Lo;0;L;;;;;N;;;;; -108F;MYANMAR SIGN RUMAI PALAUNG TONE-5;Mc;0;L;;;;;N;;;;; -1090;MYANMAR SHAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -1091;MYANMAR SHAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -1092;MYANMAR SHAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -1093;MYANMAR SHAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -1094;MYANMAR SHAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -1095;MYANMAR SHAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -1096;MYANMAR SHAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -1097;MYANMAR SHAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -1098;MYANMAR SHAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -1099;MYANMAR SHAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -109A;MYANMAR SIGN KHAMTI TONE-1;Mc;0;L;;;;;N;;;;; -109B;MYANMAR SIGN KHAMTI TONE-3;Mc;0;L;;;;;N;;;;; -109C;MYANMAR VOWEL SIGN AITON A;Mc;0;L;;;;;N;;;;; -109D;MYANMAR VOWEL SIGN AITON AI;Mn;0;NSM;;;;;N;;;;; -109E;MYANMAR SYMBOL SHAN ONE;So;0;L;;;;;N;;;;; -109F;MYANMAR SYMBOL SHAN EXCLAMATION;So;0;L;;;;;N;;;;; -10A0;GEORGIAN CAPITAL LETTER AN;Lu;0;L;;;;;N;;;;2D00; -10A1;GEORGIAN CAPITAL LETTER BAN;Lu;0;L;;;;;N;;;;2D01; -10A2;GEORGIAN CAPITAL LETTER GAN;Lu;0;L;;;;;N;;;;2D02; -10A3;GEORGIAN CAPITAL LETTER DON;Lu;0;L;;;;;N;;;;2D03; -10A4;GEORGIAN CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;2D04; -10A5;GEORGIAN CAPITAL LETTER VIN;Lu;0;L;;;;;N;;;;2D05; -10A6;GEORGIAN CAPITAL LETTER ZEN;Lu;0;L;;;;;N;;;;2D06; -10A7;GEORGIAN CAPITAL LETTER TAN;Lu;0;L;;;;;N;;;;2D07; -10A8;GEORGIAN CAPITAL LETTER IN;Lu;0;L;;;;;N;;;;2D08; -10A9;GEORGIAN CAPITAL LETTER KAN;Lu;0;L;;;;;N;;;;2D09; -10AA;GEORGIAN CAPITAL LETTER LAS;Lu;0;L;;;;;N;;;;2D0A; -10AB;GEORGIAN CAPITAL LETTER MAN;Lu;0;L;;;;;N;;;;2D0B; -10AC;GEORGIAN CAPITAL LETTER NAR;Lu;0;L;;;;;N;;;;2D0C; -10AD;GEORGIAN CAPITAL LETTER ON;Lu;0;L;;;;;N;;;;2D0D; -10AE;GEORGIAN CAPITAL LETTER PAR;Lu;0;L;;;;;N;;;;2D0E; -10AF;GEORGIAN CAPITAL LETTER ZHAR;Lu;0;L;;;;;N;;;;2D0F; -10B0;GEORGIAN CAPITAL LETTER RAE;Lu;0;L;;;;;N;;;;2D10; -10B1;GEORGIAN CAPITAL LETTER SAN;Lu;0;L;;;;;N;;;;2D11; -10B2;GEORGIAN CAPITAL LETTER TAR;Lu;0;L;;;;;N;;;;2D12; -10B3;GEORGIAN CAPITAL LETTER UN;Lu;0;L;;;;;N;;;;2D13; -10B4;GEORGIAN CAPITAL LETTER PHAR;Lu;0;L;;;;;N;;;;2D14; -10B5;GEORGIAN CAPITAL LETTER KHAR;Lu;0;L;;;;;N;;;;2D15; -10B6;GEORGIAN CAPITAL LETTER GHAN;Lu;0;L;;;;;N;;;;2D16; -10B7;GEORGIAN CAPITAL LETTER QAR;Lu;0;L;;;;;N;;;;2D17; -10B8;GEORGIAN CAPITAL LETTER SHIN;Lu;0;L;;;;;N;;;;2D18; -10B9;GEORGIAN CAPITAL LETTER CHIN;Lu;0;L;;;;;N;;;;2D19; -10BA;GEORGIAN CAPITAL LETTER CAN;Lu;0;L;;;;;N;;;;2D1A; -10BB;GEORGIAN CAPITAL LETTER JIL;Lu;0;L;;;;;N;;;;2D1B; -10BC;GEORGIAN CAPITAL LETTER CIL;Lu;0;L;;;;;N;;;;2D1C; -10BD;GEORGIAN CAPITAL LETTER CHAR;Lu;0;L;;;;;N;;;;2D1D; -10BE;GEORGIAN CAPITAL LETTER XAN;Lu;0;L;;;;;N;;;;2D1E; -10BF;GEORGIAN CAPITAL LETTER JHAN;Lu;0;L;;;;;N;;;;2D1F; -10C0;GEORGIAN CAPITAL LETTER HAE;Lu;0;L;;;;;N;;;;2D20; -10C1;GEORGIAN CAPITAL LETTER HE;Lu;0;L;;;;;N;;;;2D21; -10C2;GEORGIAN CAPITAL LETTER HIE;Lu;0;L;;;;;N;;;;2D22; -10C3;GEORGIAN CAPITAL LETTER WE;Lu;0;L;;;;;N;;;;2D23; -10C4;GEORGIAN CAPITAL LETTER HAR;Lu;0;L;;;;;N;;;;2D24; -10C5;GEORGIAN CAPITAL LETTER HOE;Lu;0;L;;;;;N;;;;2D25; -10C7;GEORGIAN CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;2D27; -10CD;GEORGIAN CAPITAL LETTER AEN;Lu;0;L;;;;;N;;;;2D2D; -10D0;GEORGIAN LETTER AN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER AN;;1C90;;10D0 -10D1;GEORGIAN LETTER BAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER BAN;;1C91;;10D1 -10D2;GEORGIAN LETTER GAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER GAN;;1C92;;10D2 -10D3;GEORGIAN LETTER DON;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER DON;;1C93;;10D3 -10D4;GEORGIAN LETTER EN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER EN;;1C94;;10D4 -10D5;GEORGIAN LETTER VIN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER VIN;;1C95;;10D5 -10D6;GEORGIAN LETTER ZEN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER ZEN;;1C96;;10D6 -10D7;GEORGIAN LETTER TAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER TAN;;1C97;;10D7 -10D8;GEORGIAN LETTER IN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER IN;;1C98;;10D8 -10D9;GEORGIAN LETTER KAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER KAN;;1C99;;10D9 -10DA;GEORGIAN LETTER LAS;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER LAS;;1C9A;;10DA -10DB;GEORGIAN LETTER MAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER MAN;;1C9B;;10DB -10DC;GEORGIAN LETTER NAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER NAR;;1C9C;;10DC -10DD;GEORGIAN LETTER ON;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER ON;;1C9D;;10DD -10DE;GEORGIAN LETTER PAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER PAR;;1C9E;;10DE -10DF;GEORGIAN LETTER ZHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER ZHAR;;1C9F;;10DF -10E0;GEORGIAN LETTER RAE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER RAE;;1CA0;;10E0 -10E1;GEORGIAN LETTER SAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER SAN;;1CA1;;10E1 -10E2;GEORGIAN LETTER TAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER TAR;;1CA2;;10E2 -10E3;GEORGIAN LETTER UN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER UN;;1CA3;;10E3 -10E4;GEORGIAN LETTER PHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER PHAR;;1CA4;;10E4 -10E5;GEORGIAN LETTER KHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER KHAR;;1CA5;;10E5 -10E6;GEORGIAN LETTER GHAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER GHAN;;1CA6;;10E6 -10E7;GEORGIAN LETTER QAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER QAR;;1CA7;;10E7 -10E8;GEORGIAN LETTER SHIN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER SHIN;;1CA8;;10E8 -10E9;GEORGIAN LETTER CHIN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CHIN;;1CA9;;10E9 -10EA;GEORGIAN LETTER CAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CAN;;1CAA;;10EA -10EB;GEORGIAN LETTER JIL;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER JIL;;1CAB;;10EB -10EC;GEORGIAN LETTER CIL;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CIL;;1CAC;;10EC -10ED;GEORGIAN LETTER CHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CHAR;;1CAD;;10ED -10EE;GEORGIAN LETTER XAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER XAN;;1CAE;;10EE -10EF;GEORGIAN LETTER JHAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER JHAN;;1CAF;;10EF -10F0;GEORGIAN LETTER HAE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HAE;;1CB0;;10F0 -10F1;GEORGIAN LETTER HE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HE;;1CB1;;10F1 -10F2;GEORGIAN LETTER HIE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HIE;;1CB2;;10F2 -10F3;GEORGIAN LETTER WE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER WE;;1CB3;;10F3 -10F4;GEORGIAN LETTER HAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HAR;;1CB4;;10F4 -10F5;GEORGIAN LETTER HOE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HOE;;1CB5;;10F5 -10F6;GEORGIAN LETTER FI;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER FI;;1CB6;;10F6 -10F7;GEORGIAN LETTER YN;Ll;0;L;;;;;N;;;1CB7;;10F7 -10F8;GEORGIAN LETTER ELIFI;Ll;0;L;;;;;N;;;1CB8;;10F8 -10F9;GEORGIAN LETTER TURNED GAN;Ll;0;L;;;;;N;;;1CB9;;10F9 -10FA;GEORGIAN LETTER AIN;Ll;0;L;;;;;N;;;1CBA;;10FA -10FB;GEORGIAN PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;; -10FC;MODIFIER LETTER GEORGIAN NAR;Lm;0;L;<super> 10DC;;;;N;;;;; -10FD;GEORGIAN LETTER AEN;Ll;0;L;;;;;N;;;1CBD;;10FD -10FE;GEORGIAN LETTER HARD SIGN;Ll;0;L;;;;;N;;;1CBE;;10FE -10FF;GEORGIAN LETTER LABIAL SIGN;Ll;0;L;;;;;N;;;1CBF;;10FF -1100;HANGUL CHOSEONG KIYEOK;Lo;0;L;;;;;N;;;;; -1101;HANGUL CHOSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;;;; -1102;HANGUL CHOSEONG NIEUN;Lo;0;L;;;;;N;;;;; -1103;HANGUL CHOSEONG TIKEUT;Lo;0;L;;;;;N;;;;; -1104;HANGUL CHOSEONG SSANGTIKEUT;Lo;0;L;;;;;N;;;;; -1105;HANGUL CHOSEONG RIEUL;Lo;0;L;;;;;N;;;;; -1106;HANGUL CHOSEONG MIEUM;Lo;0;L;;;;;N;;;;; -1107;HANGUL CHOSEONG PIEUP;Lo;0;L;;;;;N;;;;; -1108;HANGUL CHOSEONG SSANGPIEUP;Lo;0;L;;;;;N;;;;; -1109;HANGUL CHOSEONG SIOS;Lo;0;L;;;;;N;;;;; -110A;HANGUL CHOSEONG SSANGSIOS;Lo;0;L;;;;;N;;;;; -110B;HANGUL CHOSEONG IEUNG;Lo;0;L;;;;;N;;;;; -110C;HANGUL CHOSEONG CIEUC;Lo;0;L;;;;;N;;;;; -110D;HANGUL CHOSEONG SSANGCIEUC;Lo;0;L;;;;;N;;;;; -110E;HANGUL CHOSEONG CHIEUCH;Lo;0;L;;;;;N;;;;; -110F;HANGUL CHOSEONG KHIEUKH;Lo;0;L;;;;;N;;;;; -1110;HANGUL CHOSEONG THIEUTH;Lo;0;L;;;;;N;;;;; -1111;HANGUL CHOSEONG PHIEUPH;Lo;0;L;;;;;N;;;;; -1112;HANGUL CHOSEONG HIEUH;Lo;0;L;;;;;N;;;;; -1113;HANGUL CHOSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;; -1114;HANGUL CHOSEONG SSANGNIEUN;Lo;0;L;;;;;N;;;;; -1115;HANGUL CHOSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;; -1116;HANGUL CHOSEONG NIEUN-PIEUP;Lo;0;L;;;;;N;;;;; -1117;HANGUL CHOSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;; -1118;HANGUL CHOSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;; -1119;HANGUL CHOSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;; -111A;HANGUL CHOSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;;;; -111B;HANGUL CHOSEONG KAPYEOUNRIEUL;Lo;0;L;;;;;N;;;;; -111C;HANGUL CHOSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;; -111D;HANGUL CHOSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;; -111E;HANGUL CHOSEONG PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;; -111F;HANGUL CHOSEONG PIEUP-NIEUN;Lo;0;L;;;;;N;;;;; -1120;HANGUL CHOSEONG PIEUP-TIKEUT;Lo;0;L;;;;;N;;;;; -1121;HANGUL CHOSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;;;; -1122;HANGUL CHOSEONG PIEUP-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; -1123;HANGUL CHOSEONG PIEUP-SIOS-TIKEUT;Lo;0;L;;;;;N;;;;; -1124;HANGUL CHOSEONG PIEUP-SIOS-PIEUP;Lo;0;L;;;;;N;;;;; -1125;HANGUL CHOSEONG PIEUP-SSANGSIOS;Lo;0;L;;;;;N;;;;; -1126;HANGUL CHOSEONG PIEUP-SIOS-CIEUC;Lo;0;L;;;;;N;;;;; -1127;HANGUL CHOSEONG PIEUP-CIEUC;Lo;0;L;;;;;N;;;;; -1128;HANGUL CHOSEONG PIEUP-CHIEUCH;Lo;0;L;;;;;N;;;;; -1129;HANGUL CHOSEONG PIEUP-THIEUTH;Lo;0;L;;;;;N;;;;; -112A;HANGUL CHOSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;; -112B;HANGUL CHOSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; -112C;HANGUL CHOSEONG KAPYEOUNSSANGPIEUP;Lo;0;L;;;;;N;;;;; -112D;HANGUL CHOSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; -112E;HANGUL CHOSEONG SIOS-NIEUN;Lo;0;L;;;;;N;;;;; -112F;HANGUL CHOSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;; -1130;HANGUL CHOSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;; -1131;HANGUL CHOSEONG SIOS-MIEUM;Lo;0;L;;;;;N;;;;; -1132;HANGUL CHOSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;; -1133;HANGUL CHOSEONG SIOS-PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;; -1134;HANGUL CHOSEONG SIOS-SSANGSIOS;Lo;0;L;;;;;N;;;;; -1135;HANGUL CHOSEONG SIOS-IEUNG;Lo;0;L;;;;;N;;;;; -1136;HANGUL CHOSEONG SIOS-CIEUC;Lo;0;L;;;;;N;;;;; -1137;HANGUL CHOSEONG SIOS-CHIEUCH;Lo;0;L;;;;;N;;;;; -1138;HANGUL CHOSEONG SIOS-KHIEUKH;Lo;0;L;;;;;N;;;;; -1139;HANGUL CHOSEONG SIOS-THIEUTH;Lo;0;L;;;;;N;;;;; -113A;HANGUL CHOSEONG SIOS-PHIEUPH;Lo;0;L;;;;;N;;;;; -113B;HANGUL CHOSEONG SIOS-HIEUH;Lo;0;L;;;;;N;;;;; -113C;HANGUL CHOSEONG CHITUEUMSIOS;Lo;0;L;;;;;N;;;;; -113D;HANGUL CHOSEONG CHITUEUMSSANGSIOS;Lo;0;L;;;;;N;;;;; -113E;HANGUL CHOSEONG CEONGCHIEUMSIOS;Lo;0;L;;;;;N;;;;; -113F;HANGUL CHOSEONG CEONGCHIEUMSSANGSIOS;Lo;0;L;;;;;N;;;;; -1140;HANGUL CHOSEONG PANSIOS;Lo;0;L;;;;;N;;;;; -1141;HANGUL CHOSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;; -1142;HANGUL CHOSEONG IEUNG-TIKEUT;Lo;0;L;;;;;N;;;;; -1143;HANGUL CHOSEONG IEUNG-MIEUM;Lo;0;L;;;;;N;;;;; -1144;HANGUL CHOSEONG IEUNG-PIEUP;Lo;0;L;;;;;N;;;;; -1145;HANGUL CHOSEONG IEUNG-SIOS;Lo;0;L;;;;;N;;;;; -1146;HANGUL CHOSEONG IEUNG-PANSIOS;Lo;0;L;;;;;N;;;;; -1147;HANGUL CHOSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;; -1148;HANGUL CHOSEONG IEUNG-CIEUC;Lo;0;L;;;;;N;;;;; -1149;HANGUL CHOSEONG IEUNG-CHIEUCH;Lo;0;L;;;;;N;;;;; -114A;HANGUL CHOSEONG IEUNG-THIEUTH;Lo;0;L;;;;;N;;;;; -114B;HANGUL CHOSEONG IEUNG-PHIEUPH;Lo;0;L;;;;;N;;;;; -114C;HANGUL CHOSEONG YESIEUNG;Lo;0;L;;;;;N;;;;; -114D;HANGUL CHOSEONG CIEUC-IEUNG;Lo;0;L;;;;;N;;;;; -114E;HANGUL CHOSEONG CHITUEUMCIEUC;Lo;0;L;;;;;N;;;;; -114F;HANGUL CHOSEONG CHITUEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;; -1150;HANGUL CHOSEONG CEONGCHIEUMCIEUC;Lo;0;L;;;;;N;;;;; -1151;HANGUL CHOSEONG CEONGCHIEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;; -1152;HANGUL CHOSEONG CHIEUCH-KHIEUKH;Lo;0;L;;;;;N;;;;; -1153;HANGUL CHOSEONG CHIEUCH-HIEUH;Lo;0;L;;;;;N;;;;; -1154;HANGUL CHOSEONG CHITUEUMCHIEUCH;Lo;0;L;;;;;N;;;;; -1155;HANGUL CHOSEONG CEONGCHIEUMCHIEUCH;Lo;0;L;;;;;N;;;;; -1156;HANGUL CHOSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;; -1157;HANGUL CHOSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;; -1158;HANGUL CHOSEONG SSANGHIEUH;Lo;0;L;;;;;N;;;;; -1159;HANGUL CHOSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;; -115A;HANGUL CHOSEONG KIYEOK-TIKEUT;Lo;0;L;;;;;N;;;;; -115B;HANGUL CHOSEONG NIEUN-SIOS;Lo;0;L;;;;;N;;;;; -115C;HANGUL CHOSEONG NIEUN-CIEUC;Lo;0;L;;;;;N;;;;; -115D;HANGUL CHOSEONG NIEUN-HIEUH;Lo;0;L;;;;;N;;;;; -115E;HANGUL CHOSEONG TIKEUT-RIEUL;Lo;0;L;;;;;N;;;;; -115F;HANGUL CHOSEONG FILLER;Lo;0;L;;;;;N;;;;; -1160;HANGUL JUNGSEONG FILLER;Lo;0;L;;;;;N;;;;; -1161;HANGUL JUNGSEONG A;Lo;0;L;;;;;N;;;;; -1162;HANGUL JUNGSEONG AE;Lo;0;L;;;;;N;;;;; -1163;HANGUL JUNGSEONG YA;Lo;0;L;;;;;N;;;;; -1164;HANGUL JUNGSEONG YAE;Lo;0;L;;;;;N;;;;; -1165;HANGUL JUNGSEONG EO;Lo;0;L;;;;;N;;;;; -1166;HANGUL JUNGSEONG E;Lo;0;L;;;;;N;;;;; -1167;HANGUL JUNGSEONG YEO;Lo;0;L;;;;;N;;;;; -1168;HANGUL JUNGSEONG YE;Lo;0;L;;;;;N;;;;; -1169;HANGUL JUNGSEONG O;Lo;0;L;;;;;N;;;;; -116A;HANGUL JUNGSEONG WA;Lo;0;L;;;;;N;;;;; -116B;HANGUL JUNGSEONG WAE;Lo;0;L;;;;;N;;;;; -116C;HANGUL JUNGSEONG OE;Lo;0;L;;;;;N;;;;; -116D;HANGUL JUNGSEONG YO;Lo;0;L;;;;;N;;;;; -116E;HANGUL JUNGSEONG U;Lo;0;L;;;;;N;;;;; -116F;HANGUL JUNGSEONG WEO;Lo;0;L;;;;;N;;;;; -1170;HANGUL JUNGSEONG WE;Lo;0;L;;;;;N;;;;; -1171;HANGUL JUNGSEONG WI;Lo;0;L;;;;;N;;;;; -1172;HANGUL JUNGSEONG YU;Lo;0;L;;;;;N;;;;; -1173;HANGUL JUNGSEONG EU;Lo;0;L;;;;;N;;;;; -1174;HANGUL JUNGSEONG YI;Lo;0;L;;;;;N;;;;; -1175;HANGUL JUNGSEONG I;Lo;0;L;;;;;N;;;;; -1176;HANGUL JUNGSEONG A-O;Lo;0;L;;;;;N;;;;; -1177;HANGUL JUNGSEONG A-U;Lo;0;L;;;;;N;;;;; -1178;HANGUL JUNGSEONG YA-O;Lo;0;L;;;;;N;;;;; -1179;HANGUL JUNGSEONG YA-YO;Lo;0;L;;;;;N;;;;; -117A;HANGUL JUNGSEONG EO-O;Lo;0;L;;;;;N;;;;; -117B;HANGUL JUNGSEONG EO-U;Lo;0;L;;;;;N;;;;; -117C;HANGUL JUNGSEONG EO-EU;Lo;0;L;;;;;N;;;;; -117D;HANGUL JUNGSEONG YEO-O;Lo;0;L;;;;;N;;;;; -117E;HANGUL JUNGSEONG YEO-U;Lo;0;L;;;;;N;;;;; -117F;HANGUL JUNGSEONG O-EO;Lo;0;L;;;;;N;;;;; -1180;HANGUL JUNGSEONG O-E;Lo;0;L;;;;;N;;;;; -1181;HANGUL JUNGSEONG O-YE;Lo;0;L;;;;;N;;;;; -1182;HANGUL JUNGSEONG O-O;Lo;0;L;;;;;N;;;;; -1183;HANGUL JUNGSEONG O-U;Lo;0;L;;;;;N;;;;; -1184;HANGUL JUNGSEONG YO-YA;Lo;0;L;;;;;N;;;;; -1185;HANGUL JUNGSEONG YO-YAE;Lo;0;L;;;;;N;;;;; -1186;HANGUL JUNGSEONG YO-YEO;Lo;0;L;;;;;N;;;;; -1187;HANGUL JUNGSEONG YO-O;Lo;0;L;;;;;N;;;;; -1188;HANGUL JUNGSEONG YO-I;Lo;0;L;;;;;N;;;;; -1189;HANGUL JUNGSEONG U-A;Lo;0;L;;;;;N;;;;; -118A;HANGUL JUNGSEONG U-AE;Lo;0;L;;;;;N;;;;; -118B;HANGUL JUNGSEONG U-EO-EU;Lo;0;L;;;;;N;;;;; -118C;HANGUL JUNGSEONG U-YE;Lo;0;L;;;;;N;;;;; -118D;HANGUL JUNGSEONG U-U;Lo;0;L;;;;;N;;;;; -118E;HANGUL JUNGSEONG YU-A;Lo;0;L;;;;;N;;;;; -118F;HANGUL JUNGSEONG YU-EO;Lo;0;L;;;;;N;;;;; -1190;HANGUL JUNGSEONG YU-E;Lo;0;L;;;;;N;;;;; -1191;HANGUL JUNGSEONG YU-YEO;Lo;0;L;;;;;N;;;;; -1192;HANGUL JUNGSEONG YU-YE;Lo;0;L;;;;;N;;;;; -1193;HANGUL JUNGSEONG YU-U;Lo;0;L;;;;;N;;;;; -1194;HANGUL JUNGSEONG YU-I;Lo;0;L;;;;;N;;;;; -1195;HANGUL JUNGSEONG EU-U;Lo;0;L;;;;;N;;;;; -1196;HANGUL JUNGSEONG EU-EU;Lo;0;L;;;;;N;;;;; -1197;HANGUL JUNGSEONG YI-U;Lo;0;L;;;;;N;;;;; -1198;HANGUL JUNGSEONG I-A;Lo;0;L;;;;;N;;;;; -1199;HANGUL JUNGSEONG I-YA;Lo;0;L;;;;;N;;;;; -119A;HANGUL JUNGSEONG I-O;Lo;0;L;;;;;N;;;;; -119B;HANGUL JUNGSEONG I-U;Lo;0;L;;;;;N;;;;; -119C;HANGUL JUNGSEONG I-EU;Lo;0;L;;;;;N;;;;; -119D;HANGUL JUNGSEONG I-ARAEA;Lo;0;L;;;;;N;;;;; -119E;HANGUL JUNGSEONG ARAEA;Lo;0;L;;;;;N;;;;; -119F;HANGUL JUNGSEONG ARAEA-EO;Lo;0;L;;;;;N;;;;; -11A0;HANGUL JUNGSEONG ARAEA-U;Lo;0;L;;;;;N;;;;; -11A1;HANGUL JUNGSEONG ARAEA-I;Lo;0;L;;;;;N;;;;; -11A2;HANGUL JUNGSEONG SSANGARAEA;Lo;0;L;;;;;N;;;;; -11A3;HANGUL JUNGSEONG A-EU;Lo;0;L;;;;;N;;;;; -11A4;HANGUL JUNGSEONG YA-U;Lo;0;L;;;;;N;;;;; -11A5;HANGUL JUNGSEONG YEO-YA;Lo;0;L;;;;;N;;;;; -11A6;HANGUL JUNGSEONG O-YA;Lo;0;L;;;;;N;;;;; -11A7;HANGUL JUNGSEONG O-YAE;Lo;0;L;;;;;N;;;;; -11A8;HANGUL JONGSEONG KIYEOK;Lo;0;L;;;;;N;;;;; -11A9;HANGUL JONGSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;;;; -11AA;HANGUL JONGSEONG KIYEOK-SIOS;Lo;0;L;;;;;N;;;;; -11AB;HANGUL JONGSEONG NIEUN;Lo;0;L;;;;;N;;;;; -11AC;HANGUL JONGSEONG NIEUN-CIEUC;Lo;0;L;;;;;N;;;;; -11AD;HANGUL JONGSEONG NIEUN-HIEUH;Lo;0;L;;;;;N;;;;; -11AE;HANGUL JONGSEONG TIKEUT;Lo;0;L;;;;;N;;;;; -11AF;HANGUL JONGSEONG RIEUL;Lo;0;L;;;;;N;;;;; -11B0;HANGUL JONGSEONG RIEUL-KIYEOK;Lo;0;L;;;;;N;;;;; -11B1;HANGUL JONGSEONG RIEUL-MIEUM;Lo;0;L;;;;;N;;;;; -11B2;HANGUL JONGSEONG RIEUL-PIEUP;Lo;0;L;;;;;N;;;;; -11B3;HANGUL JONGSEONG RIEUL-SIOS;Lo;0;L;;;;;N;;;;; -11B4;HANGUL JONGSEONG RIEUL-THIEUTH;Lo;0;L;;;;;N;;;;; -11B5;HANGUL JONGSEONG RIEUL-PHIEUPH;Lo;0;L;;;;;N;;;;; -11B6;HANGUL JONGSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;;;; -11B7;HANGUL JONGSEONG MIEUM;Lo;0;L;;;;;N;;;;; -11B8;HANGUL JONGSEONG PIEUP;Lo;0;L;;;;;N;;;;; -11B9;HANGUL JONGSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;;;; -11BA;HANGUL JONGSEONG SIOS;Lo;0;L;;;;;N;;;;; -11BB;HANGUL JONGSEONG SSANGSIOS;Lo;0;L;;;;;N;;;;; -11BC;HANGUL JONGSEONG IEUNG;Lo;0;L;;;;;N;;;;; -11BD;HANGUL JONGSEONG CIEUC;Lo;0;L;;;;;N;;;;; -11BE;HANGUL JONGSEONG CHIEUCH;Lo;0;L;;;;;N;;;;; -11BF;HANGUL JONGSEONG KHIEUKH;Lo;0;L;;;;;N;;;;; -11C0;HANGUL JONGSEONG THIEUTH;Lo;0;L;;;;;N;;;;; -11C1;HANGUL JONGSEONG PHIEUPH;Lo;0;L;;;;;N;;;;; -11C2;HANGUL JONGSEONG HIEUH;Lo;0;L;;;;;N;;;;; -11C3;HANGUL JONGSEONG KIYEOK-RIEUL;Lo;0;L;;;;;N;;;;; -11C4;HANGUL JONGSEONG KIYEOK-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; -11C5;HANGUL JONGSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;; -11C6;HANGUL JONGSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;; -11C7;HANGUL JONGSEONG NIEUN-SIOS;Lo;0;L;;;;;N;;;;; -11C8;HANGUL JONGSEONG NIEUN-PANSIOS;Lo;0;L;;;;;N;;;;; -11C9;HANGUL JONGSEONG NIEUN-THIEUTH;Lo;0;L;;;;;N;;;;; -11CA;HANGUL JONGSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;; -11CB;HANGUL JONGSEONG TIKEUT-RIEUL;Lo;0;L;;;;;N;;;;; -11CC;HANGUL JONGSEONG RIEUL-KIYEOK-SIOS;Lo;0;L;;;;;N;;;;; -11CD;HANGUL JONGSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;; -11CE;HANGUL JONGSEONG RIEUL-TIKEUT;Lo;0;L;;;;;N;;;;; -11CF;HANGUL JONGSEONG RIEUL-TIKEUT-HIEUH;Lo;0;L;;;;;N;;;;; -11D0;HANGUL JONGSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;; -11D1;HANGUL JONGSEONG RIEUL-MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;; -11D2;HANGUL JONGSEONG RIEUL-MIEUM-SIOS;Lo;0;L;;;;;N;;;;; -11D3;HANGUL JONGSEONG RIEUL-PIEUP-SIOS;Lo;0;L;;;;;N;;;;; -11D4;HANGUL JONGSEONG RIEUL-PIEUP-HIEUH;Lo;0;L;;;;;N;;;;; -11D5;HANGUL JONGSEONG RIEUL-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; -11D6;HANGUL JONGSEONG RIEUL-SSANGSIOS;Lo;0;L;;;;;N;;;;; -11D7;HANGUL JONGSEONG RIEUL-PANSIOS;Lo;0;L;;;;;N;;;;; -11D8;HANGUL JONGSEONG RIEUL-KHIEUKH;Lo;0;L;;;;;N;;;;; -11D9;HANGUL JONGSEONG RIEUL-YEORINHIEUH;Lo;0;L;;;;;N;;;;; -11DA;HANGUL JONGSEONG MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;; -11DB;HANGUL JONGSEONG MIEUM-RIEUL;Lo;0;L;;;;;N;;;;; -11DC;HANGUL JONGSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;; -11DD;HANGUL JONGSEONG MIEUM-SIOS;Lo;0;L;;;;;N;;;;; -11DE;HANGUL JONGSEONG MIEUM-SSANGSIOS;Lo;0;L;;;;;N;;;;; -11DF;HANGUL JONGSEONG MIEUM-PANSIOS;Lo;0;L;;;;;N;;;;; -11E0;HANGUL JONGSEONG MIEUM-CHIEUCH;Lo;0;L;;;;;N;;;;; -11E1;HANGUL JONGSEONG MIEUM-HIEUH;Lo;0;L;;;;;N;;;;; -11E2;HANGUL JONGSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;; -11E3;HANGUL JONGSEONG PIEUP-RIEUL;Lo;0;L;;;;;N;;;;; -11E4;HANGUL JONGSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;; -11E5;HANGUL JONGSEONG PIEUP-HIEUH;Lo;0;L;;;;;N;;;;; -11E6;HANGUL JONGSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; -11E7;HANGUL JONGSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; -11E8;HANGUL JONGSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;; -11E9;HANGUL JONGSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;; -11EA;HANGUL JONGSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;; -11EB;HANGUL JONGSEONG PANSIOS;Lo;0;L;;;;;N;;;;; -11EC;HANGUL JONGSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;; -11ED;HANGUL JONGSEONG IEUNG-SSANGKIYEOK;Lo;0;L;;;;;N;;;;; -11EE;HANGUL JONGSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;; -11EF;HANGUL JONGSEONG IEUNG-KHIEUKH;Lo;0;L;;;;;N;;;;; -11F0;HANGUL JONGSEONG YESIEUNG;Lo;0;L;;;;;N;;;;; -11F1;HANGUL JONGSEONG YESIEUNG-SIOS;Lo;0;L;;;;;N;;;;; -11F2;HANGUL JONGSEONG YESIEUNG-PANSIOS;Lo;0;L;;;;;N;;;;; -11F3;HANGUL JONGSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;; -11F4;HANGUL JONGSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;; -11F5;HANGUL JONGSEONG HIEUH-NIEUN;Lo;0;L;;;;;N;;;;; -11F6;HANGUL JONGSEONG HIEUH-RIEUL;Lo;0;L;;;;;N;;;;; -11F7;HANGUL JONGSEONG HIEUH-MIEUM;Lo;0;L;;;;;N;;;;; -11F8;HANGUL JONGSEONG HIEUH-PIEUP;Lo;0;L;;;;;N;;;;; -11F9;HANGUL JONGSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;; -11FA;HANGUL JONGSEONG KIYEOK-NIEUN;Lo;0;L;;;;;N;;;;; -11FB;HANGUL JONGSEONG KIYEOK-PIEUP;Lo;0;L;;;;;N;;;;; -11FC;HANGUL JONGSEONG KIYEOK-CHIEUCH;Lo;0;L;;;;;N;;;;; -11FD;HANGUL JONGSEONG KIYEOK-KHIEUKH;Lo;0;L;;;;;N;;;;; -11FE;HANGUL JONGSEONG KIYEOK-HIEUH;Lo;0;L;;;;;N;;;;; -11FF;HANGUL JONGSEONG SSANGNIEUN;Lo;0;L;;;;;N;;;;; -1200;ETHIOPIC SYLLABLE HA;Lo;0;L;;;;;N;;;;; -1201;ETHIOPIC SYLLABLE HU;Lo;0;L;;;;;N;;;;; -1202;ETHIOPIC SYLLABLE HI;Lo;0;L;;;;;N;;;;; -1203;ETHIOPIC SYLLABLE HAA;Lo;0;L;;;;;N;;;;; -1204;ETHIOPIC SYLLABLE HEE;Lo;0;L;;;;;N;;;;; -1205;ETHIOPIC SYLLABLE HE;Lo;0;L;;;;;N;;;;; -1206;ETHIOPIC SYLLABLE HO;Lo;0;L;;;;;N;;;;; -1207;ETHIOPIC SYLLABLE HOA;Lo;0;L;;;;;N;;;;; -1208;ETHIOPIC SYLLABLE LA;Lo;0;L;;;;;N;;;;; -1209;ETHIOPIC SYLLABLE LU;Lo;0;L;;;;;N;;;;; -120A;ETHIOPIC SYLLABLE LI;Lo;0;L;;;;;N;;;;; -120B;ETHIOPIC SYLLABLE LAA;Lo;0;L;;;;;N;;;;; -120C;ETHIOPIC SYLLABLE LEE;Lo;0;L;;;;;N;;;;; -120D;ETHIOPIC SYLLABLE LE;Lo;0;L;;;;;N;;;;; -120E;ETHIOPIC SYLLABLE LO;Lo;0;L;;;;;N;;;;; -120F;ETHIOPIC SYLLABLE LWA;Lo;0;L;;;;;N;;;;; -1210;ETHIOPIC SYLLABLE HHA;Lo;0;L;;;;;N;;;;; -1211;ETHIOPIC SYLLABLE HHU;Lo;0;L;;;;;N;;;;; -1212;ETHIOPIC SYLLABLE HHI;Lo;0;L;;;;;N;;;;; -1213;ETHIOPIC SYLLABLE HHAA;Lo;0;L;;;;;N;;;;; -1214;ETHIOPIC SYLLABLE HHEE;Lo;0;L;;;;;N;;;;; -1215;ETHIOPIC SYLLABLE HHE;Lo;0;L;;;;;N;;;;; -1216;ETHIOPIC SYLLABLE HHO;Lo;0;L;;;;;N;;;;; -1217;ETHIOPIC SYLLABLE HHWA;Lo;0;L;;;;;N;;;;; -1218;ETHIOPIC SYLLABLE MA;Lo;0;L;;;;;N;;;;; -1219;ETHIOPIC SYLLABLE MU;Lo;0;L;;;;;N;;;;; -121A;ETHIOPIC SYLLABLE MI;Lo;0;L;;;;;N;;;;; -121B;ETHIOPIC SYLLABLE MAA;Lo;0;L;;;;;N;;;;; -121C;ETHIOPIC SYLLABLE MEE;Lo;0;L;;;;;N;;;;; -121D;ETHIOPIC SYLLABLE ME;Lo;0;L;;;;;N;;;;; -121E;ETHIOPIC SYLLABLE MO;Lo;0;L;;;;;N;;;;; -121F;ETHIOPIC SYLLABLE MWA;Lo;0;L;;;;;N;;;;; -1220;ETHIOPIC SYLLABLE SZA;Lo;0;L;;;;;N;;;;; -1221;ETHIOPIC SYLLABLE SZU;Lo;0;L;;;;;N;;;;; -1222;ETHIOPIC SYLLABLE SZI;Lo;0;L;;;;;N;;;;; -1223;ETHIOPIC SYLLABLE SZAA;Lo;0;L;;;;;N;;;;; -1224;ETHIOPIC SYLLABLE SZEE;Lo;0;L;;;;;N;;;;; -1225;ETHIOPIC SYLLABLE SZE;Lo;0;L;;;;;N;;;;; -1226;ETHIOPIC SYLLABLE SZO;Lo;0;L;;;;;N;;;;; -1227;ETHIOPIC SYLLABLE SZWA;Lo;0;L;;;;;N;;;;; -1228;ETHIOPIC SYLLABLE RA;Lo;0;L;;;;;N;;;;; -1229;ETHIOPIC SYLLABLE RU;Lo;0;L;;;;;N;;;;; -122A;ETHIOPIC SYLLABLE RI;Lo;0;L;;;;;N;;;;; -122B;ETHIOPIC SYLLABLE RAA;Lo;0;L;;;;;N;;;;; -122C;ETHIOPIC SYLLABLE REE;Lo;0;L;;;;;N;;;;; -122D;ETHIOPIC SYLLABLE RE;Lo;0;L;;;;;N;;;;; -122E;ETHIOPIC SYLLABLE RO;Lo;0;L;;;;;N;;;;; -122F;ETHIOPIC SYLLABLE RWA;Lo;0;L;;;;;N;;;;; -1230;ETHIOPIC SYLLABLE SA;Lo;0;L;;;;;N;;;;; -1231;ETHIOPIC SYLLABLE SU;Lo;0;L;;;;;N;;;;; -1232;ETHIOPIC SYLLABLE SI;Lo;0;L;;;;;N;;;;; -1233;ETHIOPIC SYLLABLE SAA;Lo;0;L;;;;;N;;;;; -1234;ETHIOPIC SYLLABLE SEE;Lo;0;L;;;;;N;;;;; -1235;ETHIOPIC SYLLABLE SE;Lo;0;L;;;;;N;;;;; -1236;ETHIOPIC SYLLABLE SO;Lo;0;L;;;;;N;;;;; -1237;ETHIOPIC SYLLABLE SWA;Lo;0;L;;;;;N;;;;; -1238;ETHIOPIC SYLLABLE SHA;Lo;0;L;;;;;N;;;;; -1239;ETHIOPIC SYLLABLE SHU;Lo;0;L;;;;;N;;;;; -123A;ETHIOPIC SYLLABLE SHI;Lo;0;L;;;;;N;;;;; -123B;ETHIOPIC SYLLABLE SHAA;Lo;0;L;;;;;N;;;;; -123C;ETHIOPIC SYLLABLE SHEE;Lo;0;L;;;;;N;;;;; -123D;ETHIOPIC SYLLABLE SHE;Lo;0;L;;;;;N;;;;; -123E;ETHIOPIC SYLLABLE SHO;Lo;0;L;;;;;N;;;;; -123F;ETHIOPIC SYLLABLE SHWA;Lo;0;L;;;;;N;;;;; -1240;ETHIOPIC SYLLABLE QA;Lo;0;L;;;;;N;;;;; -1241;ETHIOPIC SYLLABLE QU;Lo;0;L;;;;;N;;;;; -1242;ETHIOPIC SYLLABLE QI;Lo;0;L;;;;;N;;;;; -1243;ETHIOPIC SYLLABLE QAA;Lo;0;L;;;;;N;;;;; -1244;ETHIOPIC SYLLABLE QEE;Lo;0;L;;;;;N;;;;; -1245;ETHIOPIC SYLLABLE QE;Lo;0;L;;;;;N;;;;; -1246;ETHIOPIC SYLLABLE QO;Lo;0;L;;;;;N;;;;; -1247;ETHIOPIC SYLLABLE QOA;Lo;0;L;;;;;N;;;;; -1248;ETHIOPIC SYLLABLE QWA;Lo;0;L;;;;;N;;;;; -124A;ETHIOPIC SYLLABLE QWI;Lo;0;L;;;;;N;;;;; -124B;ETHIOPIC SYLLABLE QWAA;Lo;0;L;;;;;N;;;;; -124C;ETHIOPIC SYLLABLE QWEE;Lo;0;L;;;;;N;;;;; -124D;ETHIOPIC SYLLABLE QWE;Lo;0;L;;;;;N;;;;; -1250;ETHIOPIC SYLLABLE QHA;Lo;0;L;;;;;N;;;;; -1251;ETHIOPIC SYLLABLE QHU;Lo;0;L;;;;;N;;;;; -1252;ETHIOPIC SYLLABLE QHI;Lo;0;L;;;;;N;;;;; -1253;ETHIOPIC SYLLABLE QHAA;Lo;0;L;;;;;N;;;;; -1254;ETHIOPIC SYLLABLE QHEE;Lo;0;L;;;;;N;;;;; -1255;ETHIOPIC SYLLABLE QHE;Lo;0;L;;;;;N;;;;; -1256;ETHIOPIC SYLLABLE QHO;Lo;0;L;;;;;N;;;;; -1258;ETHIOPIC SYLLABLE QHWA;Lo;0;L;;;;;N;;;;; -125A;ETHIOPIC SYLLABLE QHWI;Lo;0;L;;;;;N;;;;; -125B;ETHIOPIC SYLLABLE QHWAA;Lo;0;L;;;;;N;;;;; -125C;ETHIOPIC SYLLABLE QHWEE;Lo;0;L;;;;;N;;;;; -125D;ETHIOPIC SYLLABLE QHWE;Lo;0;L;;;;;N;;;;; -1260;ETHIOPIC SYLLABLE BA;Lo;0;L;;;;;N;;;;; -1261;ETHIOPIC SYLLABLE BU;Lo;0;L;;;;;N;;;;; -1262;ETHIOPIC SYLLABLE BI;Lo;0;L;;;;;N;;;;; -1263;ETHIOPIC SYLLABLE BAA;Lo;0;L;;;;;N;;;;; -1264;ETHIOPIC SYLLABLE BEE;Lo;0;L;;;;;N;;;;; -1265;ETHIOPIC SYLLABLE BE;Lo;0;L;;;;;N;;;;; -1266;ETHIOPIC SYLLABLE BO;Lo;0;L;;;;;N;;;;; -1267;ETHIOPIC SYLLABLE BWA;Lo;0;L;;;;;N;;;;; -1268;ETHIOPIC SYLLABLE VA;Lo;0;L;;;;;N;;;;; -1269;ETHIOPIC SYLLABLE VU;Lo;0;L;;;;;N;;;;; -126A;ETHIOPIC SYLLABLE VI;Lo;0;L;;;;;N;;;;; -126B;ETHIOPIC SYLLABLE VAA;Lo;0;L;;;;;N;;;;; -126C;ETHIOPIC SYLLABLE VEE;Lo;0;L;;;;;N;;;;; -126D;ETHIOPIC SYLLABLE VE;Lo;0;L;;;;;N;;;;; -126E;ETHIOPIC SYLLABLE VO;Lo;0;L;;;;;N;;;;; -126F;ETHIOPIC SYLLABLE VWA;Lo;0;L;;;;;N;;;;; -1270;ETHIOPIC SYLLABLE TA;Lo;0;L;;;;;N;;;;; -1271;ETHIOPIC SYLLABLE TU;Lo;0;L;;;;;N;;;;; -1272;ETHIOPIC SYLLABLE TI;Lo;0;L;;;;;N;;;;; -1273;ETHIOPIC SYLLABLE TAA;Lo;0;L;;;;;N;;;;; -1274;ETHIOPIC SYLLABLE TEE;Lo;0;L;;;;;N;;;;; -1275;ETHIOPIC SYLLABLE TE;Lo;0;L;;;;;N;;;;; -1276;ETHIOPIC SYLLABLE TO;Lo;0;L;;;;;N;;;;; -1277;ETHIOPIC SYLLABLE TWA;Lo;0;L;;;;;N;;;;; -1278;ETHIOPIC SYLLABLE CA;Lo;0;L;;;;;N;;;;; -1279;ETHIOPIC SYLLABLE CU;Lo;0;L;;;;;N;;;;; -127A;ETHIOPIC SYLLABLE CI;Lo;0;L;;;;;N;;;;; -127B;ETHIOPIC SYLLABLE CAA;Lo;0;L;;;;;N;;;;; -127C;ETHIOPIC SYLLABLE CEE;Lo;0;L;;;;;N;;;;; -127D;ETHIOPIC SYLLABLE CE;Lo;0;L;;;;;N;;;;; -127E;ETHIOPIC SYLLABLE CO;Lo;0;L;;;;;N;;;;; -127F;ETHIOPIC SYLLABLE CWA;Lo;0;L;;;;;N;;;;; -1280;ETHIOPIC SYLLABLE XA;Lo;0;L;;;;;N;;;;; -1281;ETHIOPIC SYLLABLE XU;Lo;0;L;;;;;N;;;;; -1282;ETHIOPIC SYLLABLE XI;Lo;0;L;;;;;N;;;;; -1283;ETHIOPIC SYLLABLE XAA;Lo;0;L;;;;;N;;;;; -1284;ETHIOPIC SYLLABLE XEE;Lo;0;L;;;;;N;;;;; -1285;ETHIOPIC SYLLABLE XE;Lo;0;L;;;;;N;;;;; -1286;ETHIOPIC SYLLABLE XO;Lo;0;L;;;;;N;;;;; -1287;ETHIOPIC SYLLABLE XOA;Lo;0;L;;;;;N;;;;; -1288;ETHIOPIC SYLLABLE XWA;Lo;0;L;;;;;N;;;;; -128A;ETHIOPIC SYLLABLE XWI;Lo;0;L;;;;;N;;;;; -128B;ETHIOPIC SYLLABLE XWAA;Lo;0;L;;;;;N;;;;; -128C;ETHIOPIC SYLLABLE XWEE;Lo;0;L;;;;;N;;;;; -128D;ETHIOPIC SYLLABLE XWE;Lo;0;L;;;;;N;;;;; -1290;ETHIOPIC SYLLABLE NA;Lo;0;L;;;;;N;;;;; -1291;ETHIOPIC SYLLABLE NU;Lo;0;L;;;;;N;;;;; -1292;ETHIOPIC SYLLABLE NI;Lo;0;L;;;;;N;;;;; -1293;ETHIOPIC SYLLABLE NAA;Lo;0;L;;;;;N;;;;; -1294;ETHIOPIC SYLLABLE NEE;Lo;0;L;;;;;N;;;;; -1295;ETHIOPIC SYLLABLE NE;Lo;0;L;;;;;N;;;;; -1296;ETHIOPIC SYLLABLE NO;Lo;0;L;;;;;N;;;;; -1297;ETHIOPIC SYLLABLE NWA;Lo;0;L;;;;;N;;;;; -1298;ETHIOPIC SYLLABLE NYA;Lo;0;L;;;;;N;;;;; -1299;ETHIOPIC SYLLABLE NYU;Lo;0;L;;;;;N;;;;; -129A;ETHIOPIC SYLLABLE NYI;Lo;0;L;;;;;N;;;;; -129B;ETHIOPIC SYLLABLE NYAA;Lo;0;L;;;;;N;;;;; -129C;ETHIOPIC SYLLABLE NYEE;Lo;0;L;;;;;N;;;;; -129D;ETHIOPIC SYLLABLE NYE;Lo;0;L;;;;;N;;;;; -129E;ETHIOPIC SYLLABLE NYO;Lo;0;L;;;;;N;;;;; -129F;ETHIOPIC SYLLABLE NYWA;Lo;0;L;;;;;N;;;;; -12A0;ETHIOPIC SYLLABLE GLOTTAL A;Lo;0;L;;;;;N;;;;; -12A1;ETHIOPIC SYLLABLE GLOTTAL U;Lo;0;L;;;;;N;;;;; -12A2;ETHIOPIC SYLLABLE GLOTTAL I;Lo;0;L;;;;;N;;;;; -12A3;ETHIOPIC SYLLABLE GLOTTAL AA;Lo;0;L;;;;;N;;;;; -12A4;ETHIOPIC SYLLABLE GLOTTAL EE;Lo;0;L;;;;;N;;;;; -12A5;ETHIOPIC SYLLABLE GLOTTAL E;Lo;0;L;;;;;N;;;;; -12A6;ETHIOPIC SYLLABLE GLOTTAL O;Lo;0;L;;;;;N;;;;; -12A7;ETHIOPIC SYLLABLE GLOTTAL WA;Lo;0;L;;;;;N;;;;; -12A8;ETHIOPIC SYLLABLE KA;Lo;0;L;;;;;N;;;;; -12A9;ETHIOPIC SYLLABLE KU;Lo;0;L;;;;;N;;;;; -12AA;ETHIOPIC SYLLABLE KI;Lo;0;L;;;;;N;;;;; -12AB;ETHIOPIC SYLLABLE KAA;Lo;0;L;;;;;N;;;;; -12AC;ETHIOPIC SYLLABLE KEE;Lo;0;L;;;;;N;;;;; -12AD;ETHIOPIC SYLLABLE KE;Lo;0;L;;;;;N;;;;; -12AE;ETHIOPIC SYLLABLE KO;Lo;0;L;;;;;N;;;;; -12AF;ETHIOPIC SYLLABLE KOA;Lo;0;L;;;;;N;;;;; -12B0;ETHIOPIC SYLLABLE KWA;Lo;0;L;;;;;N;;;;; -12B2;ETHIOPIC SYLLABLE KWI;Lo;0;L;;;;;N;;;;; -12B3;ETHIOPIC SYLLABLE KWAA;Lo;0;L;;;;;N;;;;; -12B4;ETHIOPIC SYLLABLE KWEE;Lo;0;L;;;;;N;;;;; -12B5;ETHIOPIC SYLLABLE KWE;Lo;0;L;;;;;N;;;;; -12B8;ETHIOPIC SYLLABLE KXA;Lo;0;L;;;;;N;;;;; -12B9;ETHIOPIC SYLLABLE KXU;Lo;0;L;;;;;N;;;;; -12BA;ETHIOPIC SYLLABLE KXI;Lo;0;L;;;;;N;;;;; -12BB;ETHIOPIC SYLLABLE KXAA;Lo;0;L;;;;;N;;;;; -12BC;ETHIOPIC SYLLABLE KXEE;Lo;0;L;;;;;N;;;;; -12BD;ETHIOPIC SYLLABLE KXE;Lo;0;L;;;;;N;;;;; -12BE;ETHIOPIC SYLLABLE KXO;Lo;0;L;;;;;N;;;;; -12C0;ETHIOPIC SYLLABLE KXWA;Lo;0;L;;;;;N;;;;; -12C2;ETHIOPIC SYLLABLE KXWI;Lo;0;L;;;;;N;;;;; -12C3;ETHIOPIC SYLLABLE KXWAA;Lo;0;L;;;;;N;;;;; -12C4;ETHIOPIC SYLLABLE KXWEE;Lo;0;L;;;;;N;;;;; -12C5;ETHIOPIC SYLLABLE KXWE;Lo;0;L;;;;;N;;;;; -12C8;ETHIOPIC SYLLABLE WA;Lo;0;L;;;;;N;;;;; -12C9;ETHIOPIC SYLLABLE WU;Lo;0;L;;;;;N;;;;; -12CA;ETHIOPIC SYLLABLE WI;Lo;0;L;;;;;N;;;;; -12CB;ETHIOPIC SYLLABLE WAA;Lo;0;L;;;;;N;;;;; -12CC;ETHIOPIC SYLLABLE WEE;Lo;0;L;;;;;N;;;;; -12CD;ETHIOPIC SYLLABLE WE;Lo;0;L;;;;;N;;;;; -12CE;ETHIOPIC SYLLABLE WO;Lo;0;L;;;;;N;;;;; -12CF;ETHIOPIC SYLLABLE WOA;Lo;0;L;;;;;N;;;;; -12D0;ETHIOPIC SYLLABLE PHARYNGEAL A;Lo;0;L;;;;;N;;;;; -12D1;ETHIOPIC SYLLABLE PHARYNGEAL U;Lo;0;L;;;;;N;;;;; -12D2;ETHIOPIC SYLLABLE PHARYNGEAL I;Lo;0;L;;;;;N;;;;; -12D3;ETHIOPIC SYLLABLE PHARYNGEAL AA;Lo;0;L;;;;;N;;;;; -12D4;ETHIOPIC SYLLABLE PHARYNGEAL EE;Lo;0;L;;;;;N;;;;; -12D5;ETHIOPIC SYLLABLE PHARYNGEAL E;Lo;0;L;;;;;N;;;;; -12D6;ETHIOPIC SYLLABLE PHARYNGEAL O;Lo;0;L;;;;;N;;;;; -12D8;ETHIOPIC SYLLABLE ZA;Lo;0;L;;;;;N;;;;; -12D9;ETHIOPIC SYLLABLE ZU;Lo;0;L;;;;;N;;;;; -12DA;ETHIOPIC SYLLABLE ZI;Lo;0;L;;;;;N;;;;; -12DB;ETHIOPIC SYLLABLE ZAA;Lo;0;L;;;;;N;;;;; -12DC;ETHIOPIC SYLLABLE ZEE;Lo;0;L;;;;;N;;;;; -12DD;ETHIOPIC SYLLABLE ZE;Lo;0;L;;;;;N;;;;; -12DE;ETHIOPIC SYLLABLE ZO;Lo;0;L;;;;;N;;;;; -12DF;ETHIOPIC SYLLABLE ZWA;Lo;0;L;;;;;N;;;;; -12E0;ETHIOPIC SYLLABLE ZHA;Lo;0;L;;;;;N;;;;; -12E1;ETHIOPIC SYLLABLE ZHU;Lo;0;L;;;;;N;;;;; -12E2;ETHIOPIC SYLLABLE ZHI;Lo;0;L;;;;;N;;;;; -12E3;ETHIOPIC SYLLABLE ZHAA;Lo;0;L;;;;;N;;;;; -12E4;ETHIOPIC SYLLABLE ZHEE;Lo;0;L;;;;;N;;;;; -12E5;ETHIOPIC SYLLABLE ZHE;Lo;0;L;;;;;N;;;;; -12E6;ETHIOPIC SYLLABLE ZHO;Lo;0;L;;;;;N;;;;; -12E7;ETHIOPIC SYLLABLE ZHWA;Lo;0;L;;;;;N;;;;; -12E8;ETHIOPIC SYLLABLE YA;Lo;0;L;;;;;N;;;;; -12E9;ETHIOPIC SYLLABLE YU;Lo;0;L;;;;;N;;;;; -12EA;ETHIOPIC SYLLABLE YI;Lo;0;L;;;;;N;;;;; -12EB;ETHIOPIC SYLLABLE YAA;Lo;0;L;;;;;N;;;;; -12EC;ETHIOPIC SYLLABLE YEE;Lo;0;L;;;;;N;;;;; -12ED;ETHIOPIC SYLLABLE YE;Lo;0;L;;;;;N;;;;; -12EE;ETHIOPIC SYLLABLE YO;Lo;0;L;;;;;N;;;;; -12EF;ETHIOPIC SYLLABLE YOA;Lo;0;L;;;;;N;;;;; -12F0;ETHIOPIC SYLLABLE DA;Lo;0;L;;;;;N;;;;; -12F1;ETHIOPIC SYLLABLE DU;Lo;0;L;;;;;N;;;;; -12F2;ETHIOPIC SYLLABLE DI;Lo;0;L;;;;;N;;;;; -12F3;ETHIOPIC SYLLABLE DAA;Lo;0;L;;;;;N;;;;; -12F4;ETHIOPIC SYLLABLE DEE;Lo;0;L;;;;;N;;;;; -12F5;ETHIOPIC SYLLABLE DE;Lo;0;L;;;;;N;;;;; -12F6;ETHIOPIC SYLLABLE DO;Lo;0;L;;;;;N;;;;; -12F7;ETHIOPIC SYLLABLE DWA;Lo;0;L;;;;;N;;;;; -12F8;ETHIOPIC SYLLABLE DDA;Lo;0;L;;;;;N;;;;; -12F9;ETHIOPIC SYLLABLE DDU;Lo;0;L;;;;;N;;;;; -12FA;ETHIOPIC SYLLABLE DDI;Lo;0;L;;;;;N;;;;; -12FB;ETHIOPIC SYLLABLE DDAA;Lo;0;L;;;;;N;;;;; -12FC;ETHIOPIC SYLLABLE DDEE;Lo;0;L;;;;;N;;;;; -12FD;ETHIOPIC SYLLABLE DDE;Lo;0;L;;;;;N;;;;; -12FE;ETHIOPIC SYLLABLE DDO;Lo;0;L;;;;;N;;;;; -12FF;ETHIOPIC SYLLABLE DDWA;Lo;0;L;;;;;N;;;;; -1300;ETHIOPIC SYLLABLE JA;Lo;0;L;;;;;N;;;;; -1301;ETHIOPIC SYLLABLE JU;Lo;0;L;;;;;N;;;;; -1302;ETHIOPIC SYLLABLE JI;Lo;0;L;;;;;N;;;;; -1303;ETHIOPIC SYLLABLE JAA;Lo;0;L;;;;;N;;;;; -1304;ETHIOPIC SYLLABLE JEE;Lo;0;L;;;;;N;;;;; -1305;ETHIOPIC SYLLABLE JE;Lo;0;L;;;;;N;;;;; -1306;ETHIOPIC SYLLABLE JO;Lo;0;L;;;;;N;;;;; -1307;ETHIOPIC SYLLABLE JWA;Lo;0;L;;;;;N;;;;; -1308;ETHIOPIC SYLLABLE GA;Lo;0;L;;;;;N;;;;; -1309;ETHIOPIC SYLLABLE GU;Lo;0;L;;;;;N;;;;; -130A;ETHIOPIC SYLLABLE GI;Lo;0;L;;;;;N;;;;; -130B;ETHIOPIC SYLLABLE GAA;Lo;0;L;;;;;N;;;;; -130C;ETHIOPIC SYLLABLE GEE;Lo;0;L;;;;;N;;;;; -130D;ETHIOPIC SYLLABLE GE;Lo;0;L;;;;;N;;;;; -130E;ETHIOPIC SYLLABLE GO;Lo;0;L;;;;;N;;;;; -130F;ETHIOPIC SYLLABLE GOA;Lo;0;L;;;;;N;;;;; -1310;ETHIOPIC SYLLABLE GWA;Lo;0;L;;;;;N;;;;; -1312;ETHIOPIC SYLLABLE GWI;Lo;0;L;;;;;N;;;;; -1313;ETHIOPIC SYLLABLE GWAA;Lo;0;L;;;;;N;;;;; -1314;ETHIOPIC SYLLABLE GWEE;Lo;0;L;;;;;N;;;;; -1315;ETHIOPIC SYLLABLE GWE;Lo;0;L;;;;;N;;;;; -1318;ETHIOPIC SYLLABLE GGA;Lo;0;L;;;;;N;;;;; -1319;ETHIOPIC SYLLABLE GGU;Lo;0;L;;;;;N;;;;; -131A;ETHIOPIC SYLLABLE GGI;Lo;0;L;;;;;N;;;;; -131B;ETHIOPIC SYLLABLE GGAA;Lo;0;L;;;;;N;;;;; -131C;ETHIOPIC SYLLABLE GGEE;Lo;0;L;;;;;N;;;;; -131D;ETHIOPIC SYLLABLE GGE;Lo;0;L;;;;;N;;;;; -131E;ETHIOPIC SYLLABLE GGO;Lo;0;L;;;;;N;;;;; -131F;ETHIOPIC SYLLABLE GGWAA;Lo;0;L;;;;;N;;;;; -1320;ETHIOPIC SYLLABLE THA;Lo;0;L;;;;;N;;;;; -1321;ETHIOPIC SYLLABLE THU;Lo;0;L;;;;;N;;;;; -1322;ETHIOPIC SYLLABLE THI;Lo;0;L;;;;;N;;;;; -1323;ETHIOPIC SYLLABLE THAA;Lo;0;L;;;;;N;;;;; -1324;ETHIOPIC SYLLABLE THEE;Lo;0;L;;;;;N;;;;; -1325;ETHIOPIC SYLLABLE THE;Lo;0;L;;;;;N;;;;; -1326;ETHIOPIC SYLLABLE THO;Lo;0;L;;;;;N;;;;; -1327;ETHIOPIC SYLLABLE THWA;Lo;0;L;;;;;N;;;;; -1328;ETHIOPIC SYLLABLE CHA;Lo;0;L;;;;;N;;;;; -1329;ETHIOPIC SYLLABLE CHU;Lo;0;L;;;;;N;;;;; -132A;ETHIOPIC SYLLABLE CHI;Lo;0;L;;;;;N;;;;; -132B;ETHIOPIC SYLLABLE CHAA;Lo;0;L;;;;;N;;;;; -132C;ETHIOPIC SYLLABLE CHEE;Lo;0;L;;;;;N;;;;; -132D;ETHIOPIC SYLLABLE CHE;Lo;0;L;;;;;N;;;;; -132E;ETHIOPIC SYLLABLE CHO;Lo;0;L;;;;;N;;;;; -132F;ETHIOPIC SYLLABLE CHWA;Lo;0;L;;;;;N;;;;; -1330;ETHIOPIC SYLLABLE PHA;Lo;0;L;;;;;N;;;;; -1331;ETHIOPIC SYLLABLE PHU;Lo;0;L;;;;;N;;;;; -1332;ETHIOPIC SYLLABLE PHI;Lo;0;L;;;;;N;;;;; -1333;ETHIOPIC SYLLABLE PHAA;Lo;0;L;;;;;N;;;;; -1334;ETHIOPIC SYLLABLE PHEE;Lo;0;L;;;;;N;;;;; -1335;ETHIOPIC SYLLABLE PHE;Lo;0;L;;;;;N;;;;; -1336;ETHIOPIC SYLLABLE PHO;Lo;0;L;;;;;N;;;;; -1337;ETHIOPIC SYLLABLE PHWA;Lo;0;L;;;;;N;;;;; -1338;ETHIOPIC SYLLABLE TSA;Lo;0;L;;;;;N;;;;; -1339;ETHIOPIC SYLLABLE TSU;Lo;0;L;;;;;N;;;;; -133A;ETHIOPIC SYLLABLE TSI;Lo;0;L;;;;;N;;;;; -133B;ETHIOPIC SYLLABLE TSAA;Lo;0;L;;;;;N;;;;; -133C;ETHIOPIC SYLLABLE TSEE;Lo;0;L;;;;;N;;;;; -133D;ETHIOPIC SYLLABLE TSE;Lo;0;L;;;;;N;;;;; -133E;ETHIOPIC SYLLABLE TSO;Lo;0;L;;;;;N;;;;; -133F;ETHIOPIC SYLLABLE TSWA;Lo;0;L;;;;;N;;;;; -1340;ETHIOPIC SYLLABLE TZA;Lo;0;L;;;;;N;;;;; -1341;ETHIOPIC SYLLABLE TZU;Lo;0;L;;;;;N;;;;; -1342;ETHIOPIC SYLLABLE TZI;Lo;0;L;;;;;N;;;;; -1343;ETHIOPIC SYLLABLE TZAA;Lo;0;L;;;;;N;;;;; -1344;ETHIOPIC SYLLABLE TZEE;Lo;0;L;;;;;N;;;;; -1345;ETHIOPIC SYLLABLE TZE;Lo;0;L;;;;;N;;;;; -1346;ETHIOPIC SYLLABLE TZO;Lo;0;L;;;;;N;;;;; -1347;ETHIOPIC SYLLABLE TZOA;Lo;0;L;;;;;N;;;;; -1348;ETHIOPIC SYLLABLE FA;Lo;0;L;;;;;N;;;;; -1349;ETHIOPIC SYLLABLE FU;Lo;0;L;;;;;N;;;;; -134A;ETHIOPIC SYLLABLE FI;Lo;0;L;;;;;N;;;;; -134B;ETHIOPIC SYLLABLE FAA;Lo;0;L;;;;;N;;;;; -134C;ETHIOPIC SYLLABLE FEE;Lo;0;L;;;;;N;;;;; -134D;ETHIOPIC SYLLABLE FE;Lo;0;L;;;;;N;;;;; -134E;ETHIOPIC SYLLABLE FO;Lo;0;L;;;;;N;;;;; -134F;ETHIOPIC SYLLABLE FWA;Lo;0;L;;;;;N;;;;; -1350;ETHIOPIC SYLLABLE PA;Lo;0;L;;;;;N;;;;; -1351;ETHIOPIC SYLLABLE PU;Lo;0;L;;;;;N;;;;; -1352;ETHIOPIC SYLLABLE PI;Lo;0;L;;;;;N;;;;; -1353;ETHIOPIC SYLLABLE PAA;Lo;0;L;;;;;N;;;;; -1354;ETHIOPIC SYLLABLE PEE;Lo;0;L;;;;;N;;;;; -1355;ETHIOPIC SYLLABLE PE;Lo;0;L;;;;;N;;;;; -1356;ETHIOPIC SYLLABLE PO;Lo;0;L;;;;;N;;;;; -1357;ETHIOPIC SYLLABLE PWA;Lo;0;L;;;;;N;;;;; -1358;ETHIOPIC SYLLABLE RYA;Lo;0;L;;;;;N;;;;; -1359;ETHIOPIC SYLLABLE MYA;Lo;0;L;;;;;N;;;;; -135A;ETHIOPIC SYLLABLE FYA;Lo;0;L;;;;;N;;;;; -135D;ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK;Mn;230;NSM;;;;;N;;;;; -135E;ETHIOPIC COMBINING VOWEL LENGTH MARK;Mn;230;NSM;;;;;N;;;;; -135F;ETHIOPIC COMBINING GEMINATION MARK;Mn;230;NSM;;;;;N;;;;; -1360;ETHIOPIC SECTION MARK;Po;0;L;;;;;N;;;;; -1361;ETHIOPIC WORDSPACE;Po;0;L;;;;;N;;;;; -1362;ETHIOPIC FULL STOP;Po;0;L;;;;;N;;;;; -1363;ETHIOPIC COMMA;Po;0;L;;;;;N;;;;; -1364;ETHIOPIC SEMICOLON;Po;0;L;;;;;N;;;;; -1365;ETHIOPIC COLON;Po;0;L;;;;;N;;;;; -1366;ETHIOPIC PREFACE COLON;Po;0;L;;;;;N;;;;; -1367;ETHIOPIC QUESTION MARK;Po;0;L;;;;;N;;;;; -1368;ETHIOPIC PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;; -1369;ETHIOPIC DIGIT ONE;No;0;L;;;1;1;N;;;;; -136A;ETHIOPIC DIGIT TWO;No;0;L;;;2;2;N;;;;; -136B;ETHIOPIC DIGIT THREE;No;0;L;;;3;3;N;;;;; -136C;ETHIOPIC DIGIT FOUR;No;0;L;;;4;4;N;;;;; -136D;ETHIOPIC DIGIT FIVE;No;0;L;;;5;5;N;;;;; -136E;ETHIOPIC DIGIT SIX;No;0;L;;;6;6;N;;;;; -136F;ETHIOPIC DIGIT SEVEN;No;0;L;;;7;7;N;;;;; -1370;ETHIOPIC DIGIT EIGHT;No;0;L;;;8;8;N;;;;; -1371;ETHIOPIC DIGIT NINE;No;0;L;;;9;9;N;;;;; -1372;ETHIOPIC NUMBER TEN;No;0;L;;;;10;N;;;;; -1373;ETHIOPIC NUMBER TWENTY;No;0;L;;;;20;N;;;;; -1374;ETHIOPIC NUMBER THIRTY;No;0;L;;;;30;N;;;;; -1375;ETHIOPIC NUMBER FORTY;No;0;L;;;;40;N;;;;; -1376;ETHIOPIC NUMBER FIFTY;No;0;L;;;;50;N;;;;; -1377;ETHIOPIC NUMBER SIXTY;No;0;L;;;;60;N;;;;; -1378;ETHIOPIC NUMBER SEVENTY;No;0;L;;;;70;N;;;;; -1379;ETHIOPIC NUMBER EIGHTY;No;0;L;;;;80;N;;;;; -137A;ETHIOPIC NUMBER NINETY;No;0;L;;;;90;N;;;;; -137B;ETHIOPIC NUMBER HUNDRED;No;0;L;;;;100;N;;;;; -137C;ETHIOPIC NUMBER TEN THOUSAND;No;0;L;;;;10000;N;;;;; -1380;ETHIOPIC SYLLABLE SEBATBEIT MWA;Lo;0;L;;;;;N;;;;; -1381;ETHIOPIC SYLLABLE MWI;Lo;0;L;;;;;N;;;;; -1382;ETHIOPIC SYLLABLE MWEE;Lo;0;L;;;;;N;;;;; -1383;ETHIOPIC SYLLABLE MWE;Lo;0;L;;;;;N;;;;; -1384;ETHIOPIC SYLLABLE SEBATBEIT BWA;Lo;0;L;;;;;N;;;;; -1385;ETHIOPIC SYLLABLE BWI;Lo;0;L;;;;;N;;;;; -1386;ETHIOPIC SYLLABLE BWEE;Lo;0;L;;;;;N;;;;; -1387;ETHIOPIC SYLLABLE BWE;Lo;0;L;;;;;N;;;;; -1388;ETHIOPIC SYLLABLE SEBATBEIT FWA;Lo;0;L;;;;;N;;;;; -1389;ETHIOPIC SYLLABLE FWI;Lo;0;L;;;;;N;;;;; -138A;ETHIOPIC SYLLABLE FWEE;Lo;0;L;;;;;N;;;;; -138B;ETHIOPIC SYLLABLE FWE;Lo;0;L;;;;;N;;;;; -138C;ETHIOPIC SYLLABLE SEBATBEIT PWA;Lo;0;L;;;;;N;;;;; -138D;ETHIOPIC SYLLABLE PWI;Lo;0;L;;;;;N;;;;; -138E;ETHIOPIC SYLLABLE PWEE;Lo;0;L;;;;;N;;;;; -138F;ETHIOPIC SYLLABLE PWE;Lo;0;L;;;;;N;;;;; -1390;ETHIOPIC TONAL MARK YIZET;So;0;ON;;;;;N;;;;; -1391;ETHIOPIC TONAL MARK DERET;So;0;ON;;;;;N;;;;; -1392;ETHIOPIC TONAL MARK RIKRIK;So;0;ON;;;;;N;;;;; -1393;ETHIOPIC TONAL MARK SHORT RIKRIK;So;0;ON;;;;;N;;;;; -1394;ETHIOPIC TONAL MARK DIFAT;So;0;ON;;;;;N;;;;; -1395;ETHIOPIC TONAL MARK KENAT;So;0;ON;;;;;N;;;;; -1396;ETHIOPIC TONAL MARK CHIRET;So;0;ON;;;;;N;;;;; -1397;ETHIOPIC TONAL MARK HIDET;So;0;ON;;;;;N;;;;; -1398;ETHIOPIC TONAL MARK DERET-HIDET;So;0;ON;;;;;N;;;;; -1399;ETHIOPIC TONAL MARK KURT;So;0;ON;;;;;N;;;;; -13A0;CHEROKEE LETTER A;Lu;0;L;;;;;N;;;;AB70; -13A1;CHEROKEE LETTER E;Lu;0;L;;;;;N;;;;AB71; -13A2;CHEROKEE LETTER I;Lu;0;L;;;;;N;;;;AB72; -13A3;CHEROKEE LETTER O;Lu;0;L;;;;;N;;;;AB73; -13A4;CHEROKEE LETTER U;Lu;0;L;;;;;N;;;;AB74; -13A5;CHEROKEE LETTER V;Lu;0;L;;;;;N;;;;AB75; -13A6;CHEROKEE LETTER GA;Lu;0;L;;;;;N;;;;AB76; -13A7;CHEROKEE LETTER KA;Lu;0;L;;;;;N;;;;AB77; -13A8;CHEROKEE LETTER GE;Lu;0;L;;;;;N;;;;AB78; -13A9;CHEROKEE LETTER GI;Lu;0;L;;;;;N;;;;AB79; -13AA;CHEROKEE LETTER GO;Lu;0;L;;;;;N;;;;AB7A; -13AB;CHEROKEE LETTER GU;Lu;0;L;;;;;N;;;;AB7B; -13AC;CHEROKEE LETTER GV;Lu;0;L;;;;;N;;;;AB7C; -13AD;CHEROKEE LETTER HA;Lu;0;L;;;;;N;;;;AB7D; -13AE;CHEROKEE LETTER HE;Lu;0;L;;;;;N;;;;AB7E; -13AF;CHEROKEE LETTER HI;Lu;0;L;;;;;N;;;;AB7F; -13B0;CHEROKEE LETTER HO;Lu;0;L;;;;;N;;;;AB80; -13B1;CHEROKEE LETTER HU;Lu;0;L;;;;;N;;;;AB81; -13B2;CHEROKEE LETTER HV;Lu;0;L;;;;;N;;;;AB82; -13B3;CHEROKEE LETTER LA;Lu;0;L;;;;;N;;;;AB83; -13B4;CHEROKEE LETTER LE;Lu;0;L;;;;;N;;;;AB84; -13B5;CHEROKEE LETTER LI;Lu;0;L;;;;;N;;;;AB85; -13B6;CHEROKEE LETTER LO;Lu;0;L;;;;;N;;;;AB86; -13B7;CHEROKEE LETTER LU;Lu;0;L;;;;;N;;;;AB87; -13B8;CHEROKEE LETTER LV;Lu;0;L;;;;;N;;;;AB88; -13B9;CHEROKEE LETTER MA;Lu;0;L;;;;;N;;;;AB89; -13BA;CHEROKEE LETTER ME;Lu;0;L;;;;;N;;;;AB8A; -13BB;CHEROKEE LETTER MI;Lu;0;L;;;;;N;;;;AB8B; -13BC;CHEROKEE LETTER MO;Lu;0;L;;;;;N;;;;AB8C; -13BD;CHEROKEE LETTER MU;Lu;0;L;;;;;N;;;;AB8D; -13BE;CHEROKEE LETTER NA;Lu;0;L;;;;;N;;;;AB8E; -13BF;CHEROKEE LETTER HNA;Lu;0;L;;;;;N;;;;AB8F; -13C0;CHEROKEE LETTER NAH;Lu;0;L;;;;;N;;;;AB90; -13C1;CHEROKEE LETTER NE;Lu;0;L;;;;;N;;;;AB91; -13C2;CHEROKEE LETTER NI;Lu;0;L;;;;;N;;;;AB92; -13C3;CHEROKEE LETTER NO;Lu;0;L;;;;;N;;;;AB93; -13C4;CHEROKEE LETTER NU;Lu;0;L;;;;;N;;;;AB94; -13C5;CHEROKEE LETTER NV;Lu;0;L;;;;;N;;;;AB95; -13C6;CHEROKEE LETTER QUA;Lu;0;L;;;;;N;;;;AB96; -13C7;CHEROKEE LETTER QUE;Lu;0;L;;;;;N;;;;AB97; -13C8;CHEROKEE LETTER QUI;Lu;0;L;;;;;N;;;;AB98; -13C9;CHEROKEE LETTER QUO;Lu;0;L;;;;;N;;;;AB99; -13CA;CHEROKEE LETTER QUU;Lu;0;L;;;;;N;;;;AB9A; -13CB;CHEROKEE LETTER QUV;Lu;0;L;;;;;N;;;;AB9B; -13CC;CHEROKEE LETTER SA;Lu;0;L;;;;;N;;;;AB9C; -13CD;CHEROKEE LETTER S;Lu;0;L;;;;;N;;;;AB9D; -13CE;CHEROKEE LETTER SE;Lu;0;L;;;;;N;;;;AB9E; -13CF;CHEROKEE LETTER SI;Lu;0;L;;;;;N;;;;AB9F; -13D0;CHEROKEE LETTER SO;Lu;0;L;;;;;N;;;;ABA0; -13D1;CHEROKEE LETTER SU;Lu;0;L;;;;;N;;;;ABA1; -13D2;CHEROKEE LETTER SV;Lu;0;L;;;;;N;;;;ABA2; -13D3;CHEROKEE LETTER DA;Lu;0;L;;;;;N;;;;ABA3; -13D4;CHEROKEE LETTER TA;Lu;0;L;;;;;N;;;;ABA4; -13D5;CHEROKEE LETTER DE;Lu;0;L;;;;;N;;;;ABA5; -13D6;CHEROKEE LETTER TE;Lu;0;L;;;;;N;;;;ABA6; -13D7;CHEROKEE LETTER DI;Lu;0;L;;;;;N;;;;ABA7; -13D8;CHEROKEE LETTER TI;Lu;0;L;;;;;N;;;;ABA8; -13D9;CHEROKEE LETTER DO;Lu;0;L;;;;;N;;;;ABA9; -13DA;CHEROKEE LETTER DU;Lu;0;L;;;;;N;;;;ABAA; -13DB;CHEROKEE LETTER DV;Lu;0;L;;;;;N;;;;ABAB; -13DC;CHEROKEE LETTER DLA;Lu;0;L;;;;;N;;;;ABAC; -13DD;CHEROKEE LETTER TLA;Lu;0;L;;;;;N;;;;ABAD; -13DE;CHEROKEE LETTER TLE;Lu;0;L;;;;;N;;;;ABAE; -13DF;CHEROKEE LETTER TLI;Lu;0;L;;;;;N;;;;ABAF; -13E0;CHEROKEE LETTER TLO;Lu;0;L;;;;;N;;;;ABB0; -13E1;CHEROKEE LETTER TLU;Lu;0;L;;;;;N;;;;ABB1; -13E2;CHEROKEE LETTER TLV;Lu;0;L;;;;;N;;;;ABB2; -13E3;CHEROKEE LETTER TSA;Lu;0;L;;;;;N;;;;ABB3; -13E4;CHEROKEE LETTER TSE;Lu;0;L;;;;;N;;;;ABB4; -13E5;CHEROKEE LETTER TSI;Lu;0;L;;;;;N;;;;ABB5; -13E6;CHEROKEE LETTER TSO;Lu;0;L;;;;;N;;;;ABB6; -13E7;CHEROKEE LETTER TSU;Lu;0;L;;;;;N;;;;ABB7; -13E8;CHEROKEE LETTER TSV;Lu;0;L;;;;;N;;;;ABB8; -13E9;CHEROKEE LETTER WA;Lu;0;L;;;;;N;;;;ABB9; -13EA;CHEROKEE LETTER WE;Lu;0;L;;;;;N;;;;ABBA; -13EB;CHEROKEE LETTER WI;Lu;0;L;;;;;N;;;;ABBB; -13EC;CHEROKEE LETTER WO;Lu;0;L;;;;;N;;;;ABBC; -13ED;CHEROKEE LETTER WU;Lu;0;L;;;;;N;;;;ABBD; -13EE;CHEROKEE LETTER WV;Lu;0;L;;;;;N;;;;ABBE; -13EF;CHEROKEE LETTER YA;Lu;0;L;;;;;N;;;;ABBF; -13F0;CHEROKEE LETTER YE;Lu;0;L;;;;;N;;;;13F8; -13F1;CHEROKEE LETTER YI;Lu;0;L;;;;;N;;;;13F9; -13F2;CHEROKEE LETTER YO;Lu;0;L;;;;;N;;;;13FA; -13F3;CHEROKEE LETTER YU;Lu;0;L;;;;;N;;;;13FB; -13F4;CHEROKEE LETTER YV;Lu;0;L;;;;;N;;;;13FC; -13F5;CHEROKEE LETTER MV;Lu;0;L;;;;;N;;;;13FD; -13F8;CHEROKEE SMALL LETTER YE;Ll;0;L;;;;;N;;;13F0;;13F0 -13F9;CHEROKEE SMALL LETTER YI;Ll;0;L;;;;;N;;;13F1;;13F1 -13FA;CHEROKEE SMALL LETTER YO;Ll;0;L;;;;;N;;;13F2;;13F2 -13FB;CHEROKEE SMALL LETTER YU;Ll;0;L;;;;;N;;;13F3;;13F3 -13FC;CHEROKEE SMALL LETTER YV;Ll;0;L;;;;;N;;;13F4;;13F4 -13FD;CHEROKEE SMALL LETTER MV;Ll;0;L;;;;;N;;;13F5;;13F5 -1400;CANADIAN SYLLABICS HYPHEN;Pd;0;ON;;;;;N;;;;; -1401;CANADIAN SYLLABICS E;Lo;0;L;;;;;N;;;;; -1402;CANADIAN SYLLABICS AAI;Lo;0;L;;;;;N;;;;; -1403;CANADIAN SYLLABICS I;Lo;0;L;;;;;N;;;;; -1404;CANADIAN SYLLABICS II;Lo;0;L;;;;;N;;;;; -1405;CANADIAN SYLLABICS O;Lo;0;L;;;;;N;;;;; -1406;CANADIAN SYLLABICS OO;Lo;0;L;;;;;N;;;;; -1407;CANADIAN SYLLABICS Y-CREE OO;Lo;0;L;;;;;N;;;;; -1408;CANADIAN SYLLABICS CARRIER EE;Lo;0;L;;;;;N;;;;; -1409;CANADIAN SYLLABICS CARRIER I;Lo;0;L;;;;;N;;;;; -140A;CANADIAN SYLLABICS A;Lo;0;L;;;;;N;;;;; -140B;CANADIAN SYLLABICS AA;Lo;0;L;;;;;N;;;;; -140C;CANADIAN SYLLABICS WE;Lo;0;L;;;;;N;;;;; -140D;CANADIAN SYLLABICS WEST-CREE WE;Lo;0;L;;;;;N;;;;; -140E;CANADIAN SYLLABICS WI;Lo;0;L;;;;;N;;;;; -140F;CANADIAN SYLLABICS WEST-CREE WI;Lo;0;L;;;;;N;;;;; -1410;CANADIAN SYLLABICS WII;Lo;0;L;;;;;N;;;;; -1411;CANADIAN SYLLABICS WEST-CREE WII;Lo;0;L;;;;;N;;;;; -1412;CANADIAN SYLLABICS WO;Lo;0;L;;;;;N;;;;; -1413;CANADIAN SYLLABICS WEST-CREE WO;Lo;0;L;;;;;N;;;;; -1414;CANADIAN SYLLABICS WOO;Lo;0;L;;;;;N;;;;; -1415;CANADIAN SYLLABICS WEST-CREE WOO;Lo;0;L;;;;;N;;;;; -1416;CANADIAN SYLLABICS NASKAPI WOO;Lo;0;L;;;;;N;;;;; -1417;CANADIAN SYLLABICS WA;Lo;0;L;;;;;N;;;;; -1418;CANADIAN SYLLABICS WEST-CREE WA;Lo;0;L;;;;;N;;;;; -1419;CANADIAN SYLLABICS WAA;Lo;0;L;;;;;N;;;;; -141A;CANADIAN SYLLABICS WEST-CREE WAA;Lo;0;L;;;;;N;;;;; -141B;CANADIAN SYLLABICS NASKAPI WAA;Lo;0;L;;;;;N;;;;; -141C;CANADIAN SYLLABICS AI;Lo;0;L;;;;;N;;;;; -141D;CANADIAN SYLLABICS Y-CREE W;Lo;0;L;;;;;N;;;;; -141E;CANADIAN SYLLABICS GLOTTAL STOP;Lo;0;L;;;;;N;;;;; -141F;CANADIAN SYLLABICS FINAL ACUTE;Lo;0;L;;;;;N;;;;; -1420;CANADIAN SYLLABICS FINAL GRAVE;Lo;0;L;;;;;N;;;;; -1421;CANADIAN SYLLABICS FINAL BOTTOM HALF RING;Lo;0;L;;;;;N;;;;; -1422;CANADIAN SYLLABICS FINAL TOP HALF RING;Lo;0;L;;;;;N;;;;; -1423;CANADIAN SYLLABICS FINAL RIGHT HALF RING;Lo;0;L;;;;;N;;;;; -1424;CANADIAN SYLLABICS FINAL RING;Lo;0;L;;;;;N;;;;; -1425;CANADIAN SYLLABICS FINAL DOUBLE ACUTE;Lo;0;L;;;;;N;;;;; -1426;CANADIAN SYLLABICS FINAL DOUBLE SHORT VERTICAL STROKES;Lo;0;L;;;;;N;;;;; -1427;CANADIAN SYLLABICS FINAL MIDDLE DOT;Lo;0;L;;;;;N;;;;; -1428;CANADIAN SYLLABICS FINAL SHORT HORIZONTAL STROKE;Lo;0;L;;;;;N;;;;; -1429;CANADIAN SYLLABICS FINAL PLUS;Lo;0;L;;;;;N;;;;; -142A;CANADIAN SYLLABICS FINAL DOWN TACK;Lo;0;L;;;;;N;;;;; -142B;CANADIAN SYLLABICS EN;Lo;0;L;;;;;N;;;;; -142C;CANADIAN SYLLABICS IN;Lo;0;L;;;;;N;;;;; -142D;CANADIAN SYLLABICS ON;Lo;0;L;;;;;N;;;;; -142E;CANADIAN SYLLABICS AN;Lo;0;L;;;;;N;;;;; -142F;CANADIAN SYLLABICS PE;Lo;0;L;;;;;N;;;;; -1430;CANADIAN SYLLABICS PAAI;Lo;0;L;;;;;N;;;;; -1431;CANADIAN SYLLABICS PI;Lo;0;L;;;;;N;;;;; -1432;CANADIAN SYLLABICS PII;Lo;0;L;;;;;N;;;;; -1433;CANADIAN SYLLABICS PO;Lo;0;L;;;;;N;;;;; -1434;CANADIAN SYLLABICS POO;Lo;0;L;;;;;N;;;;; -1435;CANADIAN SYLLABICS Y-CREE POO;Lo;0;L;;;;;N;;;;; -1436;CANADIAN SYLLABICS CARRIER HEE;Lo;0;L;;;;;N;;;;; -1437;CANADIAN SYLLABICS CARRIER HI;Lo;0;L;;;;;N;;;;; -1438;CANADIAN SYLLABICS PA;Lo;0;L;;;;;N;;;;; -1439;CANADIAN SYLLABICS PAA;Lo;0;L;;;;;N;;;;; -143A;CANADIAN SYLLABICS PWE;Lo;0;L;;;;;N;;;;; -143B;CANADIAN SYLLABICS WEST-CREE PWE;Lo;0;L;;;;;N;;;;; -143C;CANADIAN SYLLABICS PWI;Lo;0;L;;;;;N;;;;; -143D;CANADIAN SYLLABICS WEST-CREE PWI;Lo;0;L;;;;;N;;;;; -143E;CANADIAN SYLLABICS PWII;Lo;0;L;;;;;N;;;;; -143F;CANADIAN SYLLABICS WEST-CREE PWII;Lo;0;L;;;;;N;;;;; -1440;CANADIAN SYLLABICS PWO;Lo;0;L;;;;;N;;;;; -1441;CANADIAN SYLLABICS WEST-CREE PWO;Lo;0;L;;;;;N;;;;; -1442;CANADIAN SYLLABICS PWOO;Lo;0;L;;;;;N;;;;; -1443;CANADIAN SYLLABICS WEST-CREE PWOO;Lo;0;L;;;;;N;;;;; -1444;CANADIAN SYLLABICS PWA;Lo;0;L;;;;;N;;;;; -1445;CANADIAN SYLLABICS WEST-CREE PWA;Lo;0;L;;;;;N;;;;; -1446;CANADIAN SYLLABICS PWAA;Lo;0;L;;;;;N;;;;; -1447;CANADIAN SYLLABICS WEST-CREE PWAA;Lo;0;L;;;;;N;;;;; -1448;CANADIAN SYLLABICS Y-CREE PWAA;Lo;0;L;;;;;N;;;;; -1449;CANADIAN SYLLABICS P;Lo;0;L;;;;;N;;;;; -144A;CANADIAN SYLLABICS WEST-CREE P;Lo;0;L;;;;;N;;;;; -144B;CANADIAN SYLLABICS CARRIER H;Lo;0;L;;;;;N;;;;; -144C;CANADIAN SYLLABICS TE;Lo;0;L;;;;;N;;;;; -144D;CANADIAN SYLLABICS TAAI;Lo;0;L;;;;;N;;;;; -144E;CANADIAN SYLLABICS TI;Lo;0;L;;;;;N;;;;; -144F;CANADIAN SYLLABICS TII;Lo;0;L;;;;;N;;;;; -1450;CANADIAN SYLLABICS TO;Lo;0;L;;;;;N;;;;; -1451;CANADIAN SYLLABICS TOO;Lo;0;L;;;;;N;;;;; -1452;CANADIAN SYLLABICS Y-CREE TOO;Lo;0;L;;;;;N;;;;; -1453;CANADIAN SYLLABICS CARRIER DEE;Lo;0;L;;;;;N;;;;; -1454;CANADIAN SYLLABICS CARRIER DI;Lo;0;L;;;;;N;;;;; -1455;CANADIAN SYLLABICS TA;Lo;0;L;;;;;N;;;;; -1456;CANADIAN SYLLABICS TAA;Lo;0;L;;;;;N;;;;; -1457;CANADIAN SYLLABICS TWE;Lo;0;L;;;;;N;;;;; -1458;CANADIAN SYLLABICS WEST-CREE TWE;Lo;0;L;;;;;N;;;;; -1459;CANADIAN SYLLABICS TWI;Lo;0;L;;;;;N;;;;; -145A;CANADIAN SYLLABICS WEST-CREE TWI;Lo;0;L;;;;;N;;;;; -145B;CANADIAN SYLLABICS TWII;Lo;0;L;;;;;N;;;;; -145C;CANADIAN SYLLABICS WEST-CREE TWII;Lo;0;L;;;;;N;;;;; -145D;CANADIAN SYLLABICS TWO;Lo;0;L;;;;;N;;;;; -145E;CANADIAN SYLLABICS WEST-CREE TWO;Lo;0;L;;;;;N;;;;; -145F;CANADIAN SYLLABICS TWOO;Lo;0;L;;;;;N;;;;; -1460;CANADIAN SYLLABICS WEST-CREE TWOO;Lo;0;L;;;;;N;;;;; -1461;CANADIAN SYLLABICS TWA;Lo;0;L;;;;;N;;;;; -1462;CANADIAN SYLLABICS WEST-CREE TWA;Lo;0;L;;;;;N;;;;; -1463;CANADIAN SYLLABICS TWAA;Lo;0;L;;;;;N;;;;; -1464;CANADIAN SYLLABICS WEST-CREE TWAA;Lo;0;L;;;;;N;;;;; -1465;CANADIAN SYLLABICS NASKAPI TWAA;Lo;0;L;;;;;N;;;;; -1466;CANADIAN SYLLABICS T;Lo;0;L;;;;;N;;;;; -1467;CANADIAN SYLLABICS TTE;Lo;0;L;;;;;N;;;;; -1468;CANADIAN SYLLABICS TTI;Lo;0;L;;;;;N;;;;; -1469;CANADIAN SYLLABICS TTO;Lo;0;L;;;;;N;;;;; -146A;CANADIAN SYLLABICS TTA;Lo;0;L;;;;;N;;;;; -146B;CANADIAN SYLLABICS KE;Lo;0;L;;;;;N;;;;; -146C;CANADIAN SYLLABICS KAAI;Lo;0;L;;;;;N;;;;; -146D;CANADIAN SYLLABICS KI;Lo;0;L;;;;;N;;;;; -146E;CANADIAN SYLLABICS KII;Lo;0;L;;;;;N;;;;; -146F;CANADIAN SYLLABICS KO;Lo;0;L;;;;;N;;;;; -1470;CANADIAN SYLLABICS KOO;Lo;0;L;;;;;N;;;;; -1471;CANADIAN SYLLABICS Y-CREE KOO;Lo;0;L;;;;;N;;;;; -1472;CANADIAN SYLLABICS KA;Lo;0;L;;;;;N;;;;; -1473;CANADIAN SYLLABICS KAA;Lo;0;L;;;;;N;;;;; -1474;CANADIAN SYLLABICS KWE;Lo;0;L;;;;;N;;;;; -1475;CANADIAN SYLLABICS WEST-CREE KWE;Lo;0;L;;;;;N;;;;; -1476;CANADIAN SYLLABICS KWI;Lo;0;L;;;;;N;;;;; -1477;CANADIAN SYLLABICS WEST-CREE KWI;Lo;0;L;;;;;N;;;;; -1478;CANADIAN SYLLABICS KWII;Lo;0;L;;;;;N;;;;; -1479;CANADIAN SYLLABICS WEST-CREE KWII;Lo;0;L;;;;;N;;;;; -147A;CANADIAN SYLLABICS KWO;Lo;0;L;;;;;N;;;;; -147B;CANADIAN SYLLABICS WEST-CREE KWO;Lo;0;L;;;;;N;;;;; -147C;CANADIAN SYLLABICS KWOO;Lo;0;L;;;;;N;;;;; -147D;CANADIAN SYLLABICS WEST-CREE KWOO;Lo;0;L;;;;;N;;;;; -147E;CANADIAN SYLLABICS KWA;Lo;0;L;;;;;N;;;;; -147F;CANADIAN SYLLABICS WEST-CREE KWA;Lo;0;L;;;;;N;;;;; -1480;CANADIAN SYLLABICS KWAA;Lo;0;L;;;;;N;;;;; -1481;CANADIAN SYLLABICS WEST-CREE KWAA;Lo;0;L;;;;;N;;;;; -1482;CANADIAN SYLLABICS NASKAPI KWAA;Lo;0;L;;;;;N;;;;; -1483;CANADIAN SYLLABICS K;Lo;0;L;;;;;N;;;;; -1484;CANADIAN SYLLABICS KW;Lo;0;L;;;;;N;;;;; -1485;CANADIAN SYLLABICS SOUTH-SLAVEY KEH;Lo;0;L;;;;;N;;;;; -1486;CANADIAN SYLLABICS SOUTH-SLAVEY KIH;Lo;0;L;;;;;N;;;;; -1487;CANADIAN SYLLABICS SOUTH-SLAVEY KOH;Lo;0;L;;;;;N;;;;; -1488;CANADIAN SYLLABICS SOUTH-SLAVEY KAH;Lo;0;L;;;;;N;;;;; -1489;CANADIAN SYLLABICS CE;Lo;0;L;;;;;N;;;;; -148A;CANADIAN SYLLABICS CAAI;Lo;0;L;;;;;N;;;;; -148B;CANADIAN SYLLABICS CI;Lo;0;L;;;;;N;;;;; -148C;CANADIAN SYLLABICS CII;Lo;0;L;;;;;N;;;;; -148D;CANADIAN SYLLABICS CO;Lo;0;L;;;;;N;;;;; -148E;CANADIAN SYLLABICS COO;Lo;0;L;;;;;N;;;;; -148F;CANADIAN SYLLABICS Y-CREE COO;Lo;0;L;;;;;N;;;;; -1490;CANADIAN SYLLABICS CA;Lo;0;L;;;;;N;;;;; -1491;CANADIAN SYLLABICS CAA;Lo;0;L;;;;;N;;;;; -1492;CANADIAN SYLLABICS CWE;Lo;0;L;;;;;N;;;;; -1493;CANADIAN SYLLABICS WEST-CREE CWE;Lo;0;L;;;;;N;;;;; -1494;CANADIAN SYLLABICS CWI;Lo;0;L;;;;;N;;;;; -1495;CANADIAN SYLLABICS WEST-CREE CWI;Lo;0;L;;;;;N;;;;; -1496;CANADIAN SYLLABICS CWII;Lo;0;L;;;;;N;;;;; -1497;CANADIAN SYLLABICS WEST-CREE CWII;Lo;0;L;;;;;N;;;;; -1498;CANADIAN SYLLABICS CWO;Lo;0;L;;;;;N;;;;; -1499;CANADIAN SYLLABICS WEST-CREE CWO;Lo;0;L;;;;;N;;;;; -149A;CANADIAN SYLLABICS CWOO;Lo;0;L;;;;;N;;;;; -149B;CANADIAN SYLLABICS WEST-CREE CWOO;Lo;0;L;;;;;N;;;;; -149C;CANADIAN SYLLABICS CWA;Lo;0;L;;;;;N;;;;; -149D;CANADIAN SYLLABICS WEST-CREE CWA;Lo;0;L;;;;;N;;;;; -149E;CANADIAN SYLLABICS CWAA;Lo;0;L;;;;;N;;;;; -149F;CANADIAN SYLLABICS WEST-CREE CWAA;Lo;0;L;;;;;N;;;;; -14A0;CANADIAN SYLLABICS NASKAPI CWAA;Lo;0;L;;;;;N;;;;; -14A1;CANADIAN SYLLABICS C;Lo;0;L;;;;;N;;;;; -14A2;CANADIAN SYLLABICS SAYISI TH;Lo;0;L;;;;;N;;;;; -14A3;CANADIAN SYLLABICS ME;Lo;0;L;;;;;N;;;;; -14A4;CANADIAN SYLLABICS MAAI;Lo;0;L;;;;;N;;;;; -14A5;CANADIAN SYLLABICS MI;Lo;0;L;;;;;N;;;;; -14A6;CANADIAN SYLLABICS MII;Lo;0;L;;;;;N;;;;; -14A7;CANADIAN SYLLABICS MO;Lo;0;L;;;;;N;;;;; -14A8;CANADIAN SYLLABICS MOO;Lo;0;L;;;;;N;;;;; -14A9;CANADIAN SYLLABICS Y-CREE MOO;Lo;0;L;;;;;N;;;;; -14AA;CANADIAN SYLLABICS MA;Lo;0;L;;;;;N;;;;; -14AB;CANADIAN SYLLABICS MAA;Lo;0;L;;;;;N;;;;; -14AC;CANADIAN SYLLABICS MWE;Lo;0;L;;;;;N;;;;; -14AD;CANADIAN SYLLABICS WEST-CREE MWE;Lo;0;L;;;;;N;;;;; -14AE;CANADIAN SYLLABICS MWI;Lo;0;L;;;;;N;;;;; -14AF;CANADIAN SYLLABICS WEST-CREE MWI;Lo;0;L;;;;;N;;;;; -14B0;CANADIAN SYLLABICS MWII;Lo;0;L;;;;;N;;;;; -14B1;CANADIAN SYLLABICS WEST-CREE MWII;Lo;0;L;;;;;N;;;;; -14B2;CANADIAN SYLLABICS MWO;Lo;0;L;;;;;N;;;;; -14B3;CANADIAN SYLLABICS WEST-CREE MWO;Lo;0;L;;;;;N;;;;; -14B4;CANADIAN SYLLABICS MWOO;Lo;0;L;;;;;N;;;;; -14B5;CANADIAN SYLLABICS WEST-CREE MWOO;Lo;0;L;;;;;N;;;;; -14B6;CANADIAN SYLLABICS MWA;Lo;0;L;;;;;N;;;;; -14B7;CANADIAN SYLLABICS WEST-CREE MWA;Lo;0;L;;;;;N;;;;; -14B8;CANADIAN SYLLABICS MWAA;Lo;0;L;;;;;N;;;;; -14B9;CANADIAN SYLLABICS WEST-CREE MWAA;Lo;0;L;;;;;N;;;;; -14BA;CANADIAN SYLLABICS NASKAPI MWAA;Lo;0;L;;;;;N;;;;; -14BB;CANADIAN SYLLABICS M;Lo;0;L;;;;;N;;;;; -14BC;CANADIAN SYLLABICS WEST-CREE M;Lo;0;L;;;;;N;;;;; -14BD;CANADIAN SYLLABICS MH;Lo;0;L;;;;;N;;;;; -14BE;CANADIAN SYLLABICS ATHAPASCAN M;Lo;0;L;;;;;N;;;;; -14BF;CANADIAN SYLLABICS SAYISI M;Lo;0;L;;;;;N;;;;; -14C0;CANADIAN SYLLABICS NE;Lo;0;L;;;;;N;;;;; -14C1;CANADIAN SYLLABICS NAAI;Lo;0;L;;;;;N;;;;; -14C2;CANADIAN SYLLABICS NI;Lo;0;L;;;;;N;;;;; -14C3;CANADIAN SYLLABICS NII;Lo;0;L;;;;;N;;;;; -14C4;CANADIAN SYLLABICS NO;Lo;0;L;;;;;N;;;;; -14C5;CANADIAN SYLLABICS NOO;Lo;0;L;;;;;N;;;;; -14C6;CANADIAN SYLLABICS Y-CREE NOO;Lo;0;L;;;;;N;;;;; -14C7;CANADIAN SYLLABICS NA;Lo;0;L;;;;;N;;;;; -14C8;CANADIAN SYLLABICS NAA;Lo;0;L;;;;;N;;;;; -14C9;CANADIAN SYLLABICS NWE;Lo;0;L;;;;;N;;;;; -14CA;CANADIAN SYLLABICS WEST-CREE NWE;Lo;0;L;;;;;N;;;;; -14CB;CANADIAN SYLLABICS NWA;Lo;0;L;;;;;N;;;;; -14CC;CANADIAN SYLLABICS WEST-CREE NWA;Lo;0;L;;;;;N;;;;; -14CD;CANADIAN SYLLABICS NWAA;Lo;0;L;;;;;N;;;;; -14CE;CANADIAN SYLLABICS WEST-CREE NWAA;Lo;0;L;;;;;N;;;;; -14CF;CANADIAN SYLLABICS NASKAPI NWAA;Lo;0;L;;;;;N;;;;; -14D0;CANADIAN SYLLABICS N;Lo;0;L;;;;;N;;;;; -14D1;CANADIAN SYLLABICS CARRIER NG;Lo;0;L;;;;;N;;;;; -14D2;CANADIAN SYLLABICS NH;Lo;0;L;;;;;N;;;;; -14D3;CANADIAN SYLLABICS LE;Lo;0;L;;;;;N;;;;; -14D4;CANADIAN SYLLABICS LAAI;Lo;0;L;;;;;N;;;;; -14D5;CANADIAN SYLLABICS LI;Lo;0;L;;;;;N;;;;; -14D6;CANADIAN SYLLABICS LII;Lo;0;L;;;;;N;;;;; -14D7;CANADIAN SYLLABICS LO;Lo;0;L;;;;;N;;;;; -14D8;CANADIAN SYLLABICS LOO;Lo;0;L;;;;;N;;;;; -14D9;CANADIAN SYLLABICS Y-CREE LOO;Lo;0;L;;;;;N;;;;; -14DA;CANADIAN SYLLABICS LA;Lo;0;L;;;;;N;;;;; -14DB;CANADIAN SYLLABICS LAA;Lo;0;L;;;;;N;;;;; -14DC;CANADIAN SYLLABICS LWE;Lo;0;L;;;;;N;;;;; -14DD;CANADIAN SYLLABICS WEST-CREE LWE;Lo;0;L;;;;;N;;;;; -14DE;CANADIAN SYLLABICS LWI;Lo;0;L;;;;;N;;;;; -14DF;CANADIAN SYLLABICS WEST-CREE LWI;Lo;0;L;;;;;N;;;;; -14E0;CANADIAN SYLLABICS LWII;Lo;0;L;;;;;N;;;;; -14E1;CANADIAN SYLLABICS WEST-CREE LWII;Lo;0;L;;;;;N;;;;; -14E2;CANADIAN SYLLABICS LWO;Lo;0;L;;;;;N;;;;; -14E3;CANADIAN SYLLABICS WEST-CREE LWO;Lo;0;L;;;;;N;;;;; -14E4;CANADIAN SYLLABICS LWOO;Lo;0;L;;;;;N;;;;; -14E5;CANADIAN SYLLABICS WEST-CREE LWOO;Lo;0;L;;;;;N;;;;; -14E6;CANADIAN SYLLABICS LWA;Lo;0;L;;;;;N;;;;; -14E7;CANADIAN SYLLABICS WEST-CREE LWA;Lo;0;L;;;;;N;;;;; -14E8;CANADIAN SYLLABICS LWAA;Lo;0;L;;;;;N;;;;; -14E9;CANADIAN SYLLABICS WEST-CREE LWAA;Lo;0;L;;;;;N;;;;; -14EA;CANADIAN SYLLABICS L;Lo;0;L;;;;;N;;;;; -14EB;CANADIAN SYLLABICS WEST-CREE L;Lo;0;L;;;;;N;;;;; -14EC;CANADIAN SYLLABICS MEDIAL L;Lo;0;L;;;;;N;;;;; -14ED;CANADIAN SYLLABICS SE;Lo;0;L;;;;;N;;;;; -14EE;CANADIAN SYLLABICS SAAI;Lo;0;L;;;;;N;;;;; -14EF;CANADIAN SYLLABICS SI;Lo;0;L;;;;;N;;;;; -14F0;CANADIAN SYLLABICS SII;Lo;0;L;;;;;N;;;;; -14F1;CANADIAN SYLLABICS SO;Lo;0;L;;;;;N;;;;; -14F2;CANADIAN SYLLABICS SOO;Lo;0;L;;;;;N;;;;; -14F3;CANADIAN SYLLABICS Y-CREE SOO;Lo;0;L;;;;;N;;;;; -14F4;CANADIAN SYLLABICS SA;Lo;0;L;;;;;N;;;;; -14F5;CANADIAN SYLLABICS SAA;Lo;0;L;;;;;N;;;;; -14F6;CANADIAN SYLLABICS SWE;Lo;0;L;;;;;N;;;;; -14F7;CANADIAN SYLLABICS WEST-CREE SWE;Lo;0;L;;;;;N;;;;; -14F8;CANADIAN SYLLABICS SWI;Lo;0;L;;;;;N;;;;; -14F9;CANADIAN SYLLABICS WEST-CREE SWI;Lo;0;L;;;;;N;;;;; -14FA;CANADIAN SYLLABICS SWII;Lo;0;L;;;;;N;;;;; -14FB;CANADIAN SYLLABICS WEST-CREE SWII;Lo;0;L;;;;;N;;;;; -14FC;CANADIAN SYLLABICS SWO;Lo;0;L;;;;;N;;;;; -14FD;CANADIAN SYLLABICS WEST-CREE SWO;Lo;0;L;;;;;N;;;;; -14FE;CANADIAN SYLLABICS SWOO;Lo;0;L;;;;;N;;;;; -14FF;CANADIAN SYLLABICS WEST-CREE SWOO;Lo;0;L;;;;;N;;;;; -1500;CANADIAN SYLLABICS SWA;Lo;0;L;;;;;N;;;;; -1501;CANADIAN SYLLABICS WEST-CREE SWA;Lo;0;L;;;;;N;;;;; -1502;CANADIAN SYLLABICS SWAA;Lo;0;L;;;;;N;;;;; -1503;CANADIAN SYLLABICS WEST-CREE SWAA;Lo;0;L;;;;;N;;;;; -1504;CANADIAN SYLLABICS NASKAPI SWAA;Lo;0;L;;;;;N;;;;; -1505;CANADIAN SYLLABICS S;Lo;0;L;;;;;N;;;;; -1506;CANADIAN SYLLABICS ATHAPASCAN S;Lo;0;L;;;;;N;;;;; -1507;CANADIAN SYLLABICS SW;Lo;0;L;;;;;N;;;;; -1508;CANADIAN SYLLABICS BLACKFOOT S;Lo;0;L;;;;;N;;;;; -1509;CANADIAN SYLLABICS MOOSE-CREE SK;Lo;0;L;;;;;N;;;;; -150A;CANADIAN SYLLABICS NASKAPI SKW;Lo;0;L;;;;;N;;;;; -150B;CANADIAN SYLLABICS NASKAPI S-W;Lo;0;L;;;;;N;;;;; -150C;CANADIAN SYLLABICS NASKAPI SPWA;Lo;0;L;;;;;N;;;;; -150D;CANADIAN SYLLABICS NASKAPI STWA;Lo;0;L;;;;;N;;;;; -150E;CANADIAN SYLLABICS NASKAPI SKWA;Lo;0;L;;;;;N;;;;; -150F;CANADIAN SYLLABICS NASKAPI SCWA;Lo;0;L;;;;;N;;;;; -1510;CANADIAN SYLLABICS SHE;Lo;0;L;;;;;N;;;;; -1511;CANADIAN SYLLABICS SHI;Lo;0;L;;;;;N;;;;; -1512;CANADIAN SYLLABICS SHII;Lo;0;L;;;;;N;;;;; -1513;CANADIAN SYLLABICS SHO;Lo;0;L;;;;;N;;;;; -1514;CANADIAN SYLLABICS SHOO;Lo;0;L;;;;;N;;;;; -1515;CANADIAN SYLLABICS SHA;Lo;0;L;;;;;N;;;;; -1516;CANADIAN SYLLABICS SHAA;Lo;0;L;;;;;N;;;;; -1517;CANADIAN SYLLABICS SHWE;Lo;0;L;;;;;N;;;;; -1518;CANADIAN SYLLABICS WEST-CREE SHWE;Lo;0;L;;;;;N;;;;; -1519;CANADIAN SYLLABICS SHWI;Lo;0;L;;;;;N;;;;; -151A;CANADIAN SYLLABICS WEST-CREE SHWI;Lo;0;L;;;;;N;;;;; -151B;CANADIAN SYLLABICS SHWII;Lo;0;L;;;;;N;;;;; -151C;CANADIAN SYLLABICS WEST-CREE SHWII;Lo;0;L;;;;;N;;;;; -151D;CANADIAN SYLLABICS SHWO;Lo;0;L;;;;;N;;;;; -151E;CANADIAN SYLLABICS WEST-CREE SHWO;Lo;0;L;;;;;N;;;;; -151F;CANADIAN SYLLABICS SHWOO;Lo;0;L;;;;;N;;;;; -1520;CANADIAN SYLLABICS WEST-CREE SHWOO;Lo;0;L;;;;;N;;;;; -1521;CANADIAN SYLLABICS SHWA;Lo;0;L;;;;;N;;;;; -1522;CANADIAN SYLLABICS WEST-CREE SHWA;Lo;0;L;;;;;N;;;;; -1523;CANADIAN SYLLABICS SHWAA;Lo;0;L;;;;;N;;;;; -1524;CANADIAN SYLLABICS WEST-CREE SHWAA;Lo;0;L;;;;;N;;;;; -1525;CANADIAN SYLLABICS SH;Lo;0;L;;;;;N;;;;; -1526;CANADIAN SYLLABICS YE;Lo;0;L;;;;;N;;;;; -1527;CANADIAN SYLLABICS YAAI;Lo;0;L;;;;;N;;;;; -1528;CANADIAN SYLLABICS YI;Lo;0;L;;;;;N;;;;; -1529;CANADIAN SYLLABICS YII;Lo;0;L;;;;;N;;;;; -152A;CANADIAN SYLLABICS YO;Lo;0;L;;;;;N;;;;; -152B;CANADIAN SYLLABICS YOO;Lo;0;L;;;;;N;;;;; -152C;CANADIAN SYLLABICS Y-CREE YOO;Lo;0;L;;;;;N;;;;; -152D;CANADIAN SYLLABICS YA;Lo;0;L;;;;;N;;;;; -152E;CANADIAN SYLLABICS YAA;Lo;0;L;;;;;N;;;;; -152F;CANADIAN SYLLABICS YWE;Lo;0;L;;;;;N;;;;; -1530;CANADIAN SYLLABICS WEST-CREE YWE;Lo;0;L;;;;;N;;;;; -1531;CANADIAN SYLLABICS YWI;Lo;0;L;;;;;N;;;;; -1532;CANADIAN SYLLABICS WEST-CREE YWI;Lo;0;L;;;;;N;;;;; -1533;CANADIAN SYLLABICS YWII;Lo;0;L;;;;;N;;;;; -1534;CANADIAN SYLLABICS WEST-CREE YWII;Lo;0;L;;;;;N;;;;; -1535;CANADIAN SYLLABICS YWO;Lo;0;L;;;;;N;;;;; -1536;CANADIAN SYLLABICS WEST-CREE YWO;Lo;0;L;;;;;N;;;;; -1537;CANADIAN SYLLABICS YWOO;Lo;0;L;;;;;N;;;;; -1538;CANADIAN SYLLABICS WEST-CREE YWOO;Lo;0;L;;;;;N;;;;; -1539;CANADIAN SYLLABICS YWA;Lo;0;L;;;;;N;;;;; -153A;CANADIAN SYLLABICS WEST-CREE YWA;Lo;0;L;;;;;N;;;;; -153B;CANADIAN SYLLABICS YWAA;Lo;0;L;;;;;N;;;;; -153C;CANADIAN SYLLABICS WEST-CREE YWAA;Lo;0;L;;;;;N;;;;; -153D;CANADIAN SYLLABICS NASKAPI YWAA;Lo;0;L;;;;;N;;;;; -153E;CANADIAN SYLLABICS Y;Lo;0;L;;;;;N;;;;; -153F;CANADIAN SYLLABICS BIBLE-CREE Y;Lo;0;L;;;;;N;;;;; -1540;CANADIAN SYLLABICS WEST-CREE Y;Lo;0;L;;;;;N;;;;; -1541;CANADIAN SYLLABICS SAYISI YI;Lo;0;L;;;;;N;;;;; -1542;CANADIAN SYLLABICS RE;Lo;0;L;;;;;N;;;;; -1543;CANADIAN SYLLABICS R-CREE RE;Lo;0;L;;;;;N;;;;; -1544;CANADIAN SYLLABICS WEST-CREE LE;Lo;0;L;;;;;N;;;;; -1545;CANADIAN SYLLABICS RAAI;Lo;0;L;;;;;N;;;;; -1546;CANADIAN SYLLABICS RI;Lo;0;L;;;;;N;;;;; -1547;CANADIAN SYLLABICS RII;Lo;0;L;;;;;N;;;;; -1548;CANADIAN SYLLABICS RO;Lo;0;L;;;;;N;;;;; -1549;CANADIAN SYLLABICS ROO;Lo;0;L;;;;;N;;;;; -154A;CANADIAN SYLLABICS WEST-CREE LO;Lo;0;L;;;;;N;;;;; -154B;CANADIAN SYLLABICS RA;Lo;0;L;;;;;N;;;;; -154C;CANADIAN SYLLABICS RAA;Lo;0;L;;;;;N;;;;; -154D;CANADIAN SYLLABICS WEST-CREE LA;Lo;0;L;;;;;N;;;;; -154E;CANADIAN SYLLABICS RWAA;Lo;0;L;;;;;N;;;;; -154F;CANADIAN SYLLABICS WEST-CREE RWAA;Lo;0;L;;;;;N;;;;; -1550;CANADIAN SYLLABICS R;Lo;0;L;;;;;N;;;;; -1551;CANADIAN SYLLABICS WEST-CREE R;Lo;0;L;;;;;N;;;;; -1552;CANADIAN SYLLABICS MEDIAL R;Lo;0;L;;;;;N;;;;; -1553;CANADIAN SYLLABICS FE;Lo;0;L;;;;;N;;;;; -1554;CANADIAN SYLLABICS FAAI;Lo;0;L;;;;;N;;;;; -1555;CANADIAN SYLLABICS FI;Lo;0;L;;;;;N;;;;; -1556;CANADIAN SYLLABICS FII;Lo;0;L;;;;;N;;;;; -1557;CANADIAN SYLLABICS FO;Lo;0;L;;;;;N;;;;; -1558;CANADIAN SYLLABICS FOO;Lo;0;L;;;;;N;;;;; -1559;CANADIAN SYLLABICS FA;Lo;0;L;;;;;N;;;;; -155A;CANADIAN SYLLABICS FAA;Lo;0;L;;;;;N;;;;; -155B;CANADIAN SYLLABICS FWAA;Lo;0;L;;;;;N;;;;; -155C;CANADIAN SYLLABICS WEST-CREE FWAA;Lo;0;L;;;;;N;;;;; -155D;CANADIAN SYLLABICS F;Lo;0;L;;;;;N;;;;; -155E;CANADIAN SYLLABICS THE;Lo;0;L;;;;;N;;;;; -155F;CANADIAN SYLLABICS N-CREE THE;Lo;0;L;;;;;N;;;;; -1560;CANADIAN SYLLABICS THI;Lo;0;L;;;;;N;;;;; -1561;CANADIAN SYLLABICS N-CREE THI;Lo;0;L;;;;;N;;;;; -1562;CANADIAN SYLLABICS THII;Lo;0;L;;;;;N;;;;; -1563;CANADIAN SYLLABICS N-CREE THII;Lo;0;L;;;;;N;;;;; -1564;CANADIAN SYLLABICS THO;Lo;0;L;;;;;N;;;;; -1565;CANADIAN SYLLABICS THOO;Lo;0;L;;;;;N;;;;; -1566;CANADIAN SYLLABICS THA;Lo;0;L;;;;;N;;;;; -1567;CANADIAN SYLLABICS THAA;Lo;0;L;;;;;N;;;;; -1568;CANADIAN SYLLABICS THWAA;Lo;0;L;;;;;N;;;;; -1569;CANADIAN SYLLABICS WEST-CREE THWAA;Lo;0;L;;;;;N;;;;; -156A;CANADIAN SYLLABICS TH;Lo;0;L;;;;;N;;;;; -156B;CANADIAN SYLLABICS TTHE;Lo;0;L;;;;;N;;;;; -156C;CANADIAN SYLLABICS TTHI;Lo;0;L;;;;;N;;;;; -156D;CANADIAN SYLLABICS TTHO;Lo;0;L;;;;;N;;;;; -156E;CANADIAN SYLLABICS TTHA;Lo;0;L;;;;;N;;;;; -156F;CANADIAN SYLLABICS TTH;Lo;0;L;;;;;N;;;;; -1570;CANADIAN SYLLABICS TYE;Lo;0;L;;;;;N;;;;; -1571;CANADIAN SYLLABICS TYI;Lo;0;L;;;;;N;;;;; -1572;CANADIAN SYLLABICS TYO;Lo;0;L;;;;;N;;;;; -1573;CANADIAN SYLLABICS TYA;Lo;0;L;;;;;N;;;;; -1574;CANADIAN SYLLABICS NUNAVIK HE;Lo;0;L;;;;;N;;;;; -1575;CANADIAN SYLLABICS NUNAVIK HI;Lo;0;L;;;;;N;;;;; -1576;CANADIAN SYLLABICS NUNAVIK HII;Lo;0;L;;;;;N;;;;; -1577;CANADIAN SYLLABICS NUNAVIK HO;Lo;0;L;;;;;N;;;;; -1578;CANADIAN SYLLABICS NUNAVIK HOO;Lo;0;L;;;;;N;;;;; -1579;CANADIAN SYLLABICS NUNAVIK HA;Lo;0;L;;;;;N;;;;; -157A;CANADIAN SYLLABICS NUNAVIK HAA;Lo;0;L;;;;;N;;;;; -157B;CANADIAN SYLLABICS NUNAVIK H;Lo;0;L;;;;;N;;;;; -157C;CANADIAN SYLLABICS NUNAVUT H;Lo;0;L;;;;;N;;;;; -157D;CANADIAN SYLLABICS HK;Lo;0;L;;;;;N;;;;; -157E;CANADIAN SYLLABICS QAAI;Lo;0;L;;;;;N;;;;; -157F;CANADIAN SYLLABICS QI;Lo;0;L;;;;;N;;;;; -1580;CANADIAN SYLLABICS QII;Lo;0;L;;;;;N;;;;; -1581;CANADIAN SYLLABICS QO;Lo;0;L;;;;;N;;;;; -1582;CANADIAN SYLLABICS QOO;Lo;0;L;;;;;N;;;;; -1583;CANADIAN SYLLABICS QA;Lo;0;L;;;;;N;;;;; -1584;CANADIAN SYLLABICS QAA;Lo;0;L;;;;;N;;;;; -1585;CANADIAN SYLLABICS Q;Lo;0;L;;;;;N;;;;; -1586;CANADIAN SYLLABICS TLHE;Lo;0;L;;;;;N;;;;; -1587;CANADIAN SYLLABICS TLHI;Lo;0;L;;;;;N;;;;; -1588;CANADIAN SYLLABICS TLHO;Lo;0;L;;;;;N;;;;; -1589;CANADIAN SYLLABICS TLHA;Lo;0;L;;;;;N;;;;; -158A;CANADIAN SYLLABICS WEST-CREE RE;Lo;0;L;;;;;N;;;;; -158B;CANADIAN SYLLABICS WEST-CREE RI;Lo;0;L;;;;;N;;;;; -158C;CANADIAN SYLLABICS WEST-CREE RO;Lo;0;L;;;;;N;;;;; -158D;CANADIAN SYLLABICS WEST-CREE RA;Lo;0;L;;;;;N;;;;; -158E;CANADIAN SYLLABICS NGAAI;Lo;0;L;;;;;N;;;;; -158F;CANADIAN SYLLABICS NGI;Lo;0;L;;;;;N;;;;; -1590;CANADIAN SYLLABICS NGII;Lo;0;L;;;;;N;;;;; -1591;CANADIAN SYLLABICS NGO;Lo;0;L;;;;;N;;;;; -1592;CANADIAN SYLLABICS NGOO;Lo;0;L;;;;;N;;;;; -1593;CANADIAN SYLLABICS NGA;Lo;0;L;;;;;N;;;;; -1594;CANADIAN SYLLABICS NGAA;Lo;0;L;;;;;N;;;;; -1595;CANADIAN SYLLABICS NG;Lo;0;L;;;;;N;;;;; -1596;CANADIAN SYLLABICS NNG;Lo;0;L;;;;;N;;;;; -1597;CANADIAN SYLLABICS SAYISI SHE;Lo;0;L;;;;;N;;;;; -1598;CANADIAN SYLLABICS SAYISI SHI;Lo;0;L;;;;;N;;;;; -1599;CANADIAN SYLLABICS SAYISI SHO;Lo;0;L;;;;;N;;;;; -159A;CANADIAN SYLLABICS SAYISI SHA;Lo;0;L;;;;;N;;;;; -159B;CANADIAN SYLLABICS WOODS-CREE THE;Lo;0;L;;;;;N;;;;; -159C;CANADIAN SYLLABICS WOODS-CREE THI;Lo;0;L;;;;;N;;;;; -159D;CANADIAN SYLLABICS WOODS-CREE THO;Lo;0;L;;;;;N;;;;; -159E;CANADIAN SYLLABICS WOODS-CREE THA;Lo;0;L;;;;;N;;;;; -159F;CANADIAN SYLLABICS WOODS-CREE TH;Lo;0;L;;;;;N;;;;; -15A0;CANADIAN SYLLABICS LHI;Lo;0;L;;;;;N;;;;; -15A1;CANADIAN SYLLABICS LHII;Lo;0;L;;;;;N;;;;; -15A2;CANADIAN SYLLABICS LHO;Lo;0;L;;;;;N;;;;; -15A3;CANADIAN SYLLABICS LHOO;Lo;0;L;;;;;N;;;;; -15A4;CANADIAN SYLLABICS LHA;Lo;0;L;;;;;N;;;;; -15A5;CANADIAN SYLLABICS LHAA;Lo;0;L;;;;;N;;;;; -15A6;CANADIAN SYLLABICS LH;Lo;0;L;;;;;N;;;;; -15A7;CANADIAN SYLLABICS TH-CREE THE;Lo;0;L;;;;;N;;;;; -15A8;CANADIAN SYLLABICS TH-CREE THI;Lo;0;L;;;;;N;;;;; -15A9;CANADIAN SYLLABICS TH-CREE THII;Lo;0;L;;;;;N;;;;; -15AA;CANADIAN SYLLABICS TH-CREE THO;Lo;0;L;;;;;N;;;;; -15AB;CANADIAN SYLLABICS TH-CREE THOO;Lo;0;L;;;;;N;;;;; -15AC;CANADIAN SYLLABICS TH-CREE THA;Lo;0;L;;;;;N;;;;; -15AD;CANADIAN SYLLABICS TH-CREE THAA;Lo;0;L;;;;;N;;;;; -15AE;CANADIAN SYLLABICS TH-CREE TH;Lo;0;L;;;;;N;;;;; -15AF;CANADIAN SYLLABICS AIVILIK B;Lo;0;L;;;;;N;;;;; -15B0;CANADIAN SYLLABICS BLACKFOOT E;Lo;0;L;;;;;N;;;;; -15B1;CANADIAN SYLLABICS BLACKFOOT I;Lo;0;L;;;;;N;;;;; -15B2;CANADIAN SYLLABICS BLACKFOOT O;Lo;0;L;;;;;N;;;;; -15B3;CANADIAN SYLLABICS BLACKFOOT A;Lo;0;L;;;;;N;;;;; -15B4;CANADIAN SYLLABICS BLACKFOOT WE;Lo;0;L;;;;;N;;;;; -15B5;CANADIAN SYLLABICS BLACKFOOT WI;Lo;0;L;;;;;N;;;;; -15B6;CANADIAN SYLLABICS BLACKFOOT WO;Lo;0;L;;;;;N;;;;; -15B7;CANADIAN SYLLABICS BLACKFOOT WA;Lo;0;L;;;;;N;;;;; -15B8;CANADIAN SYLLABICS BLACKFOOT NE;Lo;0;L;;;;;N;;;;; -15B9;CANADIAN SYLLABICS BLACKFOOT NI;Lo;0;L;;;;;N;;;;; -15BA;CANADIAN SYLLABICS BLACKFOOT NO;Lo;0;L;;;;;N;;;;; -15BB;CANADIAN SYLLABICS BLACKFOOT NA;Lo;0;L;;;;;N;;;;; -15BC;CANADIAN SYLLABICS BLACKFOOT KE;Lo;0;L;;;;;N;;;;; -15BD;CANADIAN SYLLABICS BLACKFOOT KI;Lo;0;L;;;;;N;;;;; -15BE;CANADIAN SYLLABICS BLACKFOOT KO;Lo;0;L;;;;;N;;;;; -15BF;CANADIAN SYLLABICS BLACKFOOT KA;Lo;0;L;;;;;N;;;;; -15C0;CANADIAN SYLLABICS SAYISI HE;Lo;0;L;;;;;N;;;;; -15C1;CANADIAN SYLLABICS SAYISI HI;Lo;0;L;;;;;N;;;;; -15C2;CANADIAN SYLLABICS SAYISI HO;Lo;0;L;;;;;N;;;;; -15C3;CANADIAN SYLLABICS SAYISI HA;Lo;0;L;;;;;N;;;;; -15C4;CANADIAN SYLLABICS CARRIER GHU;Lo;0;L;;;;;N;;;;; -15C5;CANADIAN SYLLABICS CARRIER GHO;Lo;0;L;;;;;N;;;;; -15C6;CANADIAN SYLLABICS CARRIER GHE;Lo;0;L;;;;;N;;;;; -15C7;CANADIAN SYLLABICS CARRIER GHEE;Lo;0;L;;;;;N;;;;; -15C8;CANADIAN SYLLABICS CARRIER GHI;Lo;0;L;;;;;N;;;;; -15C9;CANADIAN SYLLABICS CARRIER GHA;Lo;0;L;;;;;N;;;;; -15CA;CANADIAN SYLLABICS CARRIER RU;Lo;0;L;;;;;N;;;;; -15CB;CANADIAN SYLLABICS CARRIER RO;Lo;0;L;;;;;N;;;;; -15CC;CANADIAN SYLLABICS CARRIER RE;Lo;0;L;;;;;N;;;;; -15CD;CANADIAN SYLLABICS CARRIER REE;Lo;0;L;;;;;N;;;;; -15CE;CANADIAN SYLLABICS CARRIER RI;Lo;0;L;;;;;N;;;;; -15CF;CANADIAN SYLLABICS CARRIER RA;Lo;0;L;;;;;N;;;;; -15D0;CANADIAN SYLLABICS CARRIER WU;Lo;0;L;;;;;N;;;;; -15D1;CANADIAN SYLLABICS CARRIER WO;Lo;0;L;;;;;N;;;;; -15D2;CANADIAN SYLLABICS CARRIER WE;Lo;0;L;;;;;N;;;;; -15D3;CANADIAN SYLLABICS CARRIER WEE;Lo;0;L;;;;;N;;;;; -15D4;CANADIAN SYLLABICS CARRIER WI;Lo;0;L;;;;;N;;;;; -15D5;CANADIAN SYLLABICS CARRIER WA;Lo;0;L;;;;;N;;;;; -15D6;CANADIAN SYLLABICS CARRIER HWU;Lo;0;L;;;;;N;;;;; -15D7;CANADIAN SYLLABICS CARRIER HWO;Lo;0;L;;;;;N;;;;; -15D8;CANADIAN SYLLABICS CARRIER HWE;Lo;0;L;;;;;N;;;;; -15D9;CANADIAN SYLLABICS CARRIER HWEE;Lo;0;L;;;;;N;;;;; -15DA;CANADIAN SYLLABICS CARRIER HWI;Lo;0;L;;;;;N;;;;; -15DB;CANADIAN SYLLABICS CARRIER HWA;Lo;0;L;;;;;N;;;;; -15DC;CANADIAN SYLLABICS CARRIER THU;Lo;0;L;;;;;N;;;;; -15DD;CANADIAN SYLLABICS CARRIER THO;Lo;0;L;;;;;N;;;;; -15DE;CANADIAN SYLLABICS CARRIER THE;Lo;0;L;;;;;N;;;;; -15DF;CANADIAN SYLLABICS CARRIER THEE;Lo;0;L;;;;;N;;;;; -15E0;CANADIAN SYLLABICS CARRIER THI;Lo;0;L;;;;;N;;;;; -15E1;CANADIAN SYLLABICS CARRIER THA;Lo;0;L;;;;;N;;;;; -15E2;CANADIAN SYLLABICS CARRIER TTU;Lo;0;L;;;;;N;;;;; -15E3;CANADIAN SYLLABICS CARRIER TTO;Lo;0;L;;;;;N;;;;; -15E4;CANADIAN SYLLABICS CARRIER TTE;Lo;0;L;;;;;N;;;;; -15E5;CANADIAN SYLLABICS CARRIER TTEE;Lo;0;L;;;;;N;;;;; -15E6;CANADIAN SYLLABICS CARRIER TTI;Lo;0;L;;;;;N;;;;; -15E7;CANADIAN SYLLABICS CARRIER TTA;Lo;0;L;;;;;N;;;;; -15E8;CANADIAN SYLLABICS CARRIER PU;Lo;0;L;;;;;N;;;;; -15E9;CANADIAN SYLLABICS CARRIER PO;Lo;0;L;;;;;N;;;;; -15EA;CANADIAN SYLLABICS CARRIER PE;Lo;0;L;;;;;N;;;;; -15EB;CANADIAN SYLLABICS CARRIER PEE;Lo;0;L;;;;;N;;;;; -15EC;CANADIAN SYLLABICS CARRIER PI;Lo;0;L;;;;;N;;;;; -15ED;CANADIAN SYLLABICS CARRIER PA;Lo;0;L;;;;;N;;;;; -15EE;CANADIAN SYLLABICS CARRIER P;Lo;0;L;;;;;N;;;;; -15EF;CANADIAN SYLLABICS CARRIER GU;Lo;0;L;;;;;N;;;;; -15F0;CANADIAN SYLLABICS CARRIER GO;Lo;0;L;;;;;N;;;;; -15F1;CANADIAN SYLLABICS CARRIER GE;Lo;0;L;;;;;N;;;;; -15F2;CANADIAN SYLLABICS CARRIER GEE;Lo;0;L;;;;;N;;;;; -15F3;CANADIAN SYLLABICS CARRIER GI;Lo;0;L;;;;;N;;;;; -15F4;CANADIAN SYLLABICS CARRIER GA;Lo;0;L;;;;;N;;;;; -15F5;CANADIAN SYLLABICS CARRIER KHU;Lo;0;L;;;;;N;;;;; -15F6;CANADIAN SYLLABICS CARRIER KHO;Lo;0;L;;;;;N;;;;; -15F7;CANADIAN SYLLABICS CARRIER KHE;Lo;0;L;;;;;N;;;;; -15F8;CANADIAN SYLLABICS CARRIER KHEE;Lo;0;L;;;;;N;;;;; -15F9;CANADIAN SYLLABICS CARRIER KHI;Lo;0;L;;;;;N;;;;; -15FA;CANADIAN SYLLABICS CARRIER KHA;Lo;0;L;;;;;N;;;;; -15FB;CANADIAN SYLLABICS CARRIER KKU;Lo;0;L;;;;;N;;;;; -15FC;CANADIAN SYLLABICS CARRIER KKO;Lo;0;L;;;;;N;;;;; -15FD;CANADIAN SYLLABICS CARRIER KKE;Lo;0;L;;;;;N;;;;; -15FE;CANADIAN SYLLABICS CARRIER KKEE;Lo;0;L;;;;;N;;;;; -15FF;CANADIAN SYLLABICS CARRIER KKI;Lo;0;L;;;;;N;;;;; -1600;CANADIAN SYLLABICS CARRIER KKA;Lo;0;L;;;;;N;;;;; -1601;CANADIAN SYLLABICS CARRIER KK;Lo;0;L;;;;;N;;;;; -1602;CANADIAN SYLLABICS CARRIER NU;Lo;0;L;;;;;N;;;;; -1603;CANADIAN SYLLABICS CARRIER NO;Lo;0;L;;;;;N;;;;; -1604;CANADIAN SYLLABICS CARRIER NE;Lo;0;L;;;;;N;;;;; -1605;CANADIAN SYLLABICS CARRIER NEE;Lo;0;L;;;;;N;;;;; -1606;CANADIAN SYLLABICS CARRIER NI;Lo;0;L;;;;;N;;;;; -1607;CANADIAN SYLLABICS CARRIER NA;Lo;0;L;;;;;N;;;;; -1608;CANADIAN SYLLABICS CARRIER MU;Lo;0;L;;;;;N;;;;; -1609;CANADIAN SYLLABICS CARRIER MO;Lo;0;L;;;;;N;;;;; -160A;CANADIAN SYLLABICS CARRIER ME;Lo;0;L;;;;;N;;;;; -160B;CANADIAN SYLLABICS CARRIER MEE;Lo;0;L;;;;;N;;;;; -160C;CANADIAN SYLLABICS CARRIER MI;Lo;0;L;;;;;N;;;;; -160D;CANADIAN SYLLABICS CARRIER MA;Lo;0;L;;;;;N;;;;; -160E;CANADIAN SYLLABICS CARRIER YU;Lo;0;L;;;;;N;;;;; -160F;CANADIAN SYLLABICS CARRIER YO;Lo;0;L;;;;;N;;;;; -1610;CANADIAN SYLLABICS CARRIER YE;Lo;0;L;;;;;N;;;;; -1611;CANADIAN SYLLABICS CARRIER YEE;Lo;0;L;;;;;N;;;;; -1612;CANADIAN SYLLABICS CARRIER YI;Lo;0;L;;;;;N;;;;; -1613;CANADIAN SYLLABICS CARRIER YA;Lo;0;L;;;;;N;;;;; -1614;CANADIAN SYLLABICS CARRIER JU;Lo;0;L;;;;;N;;;;; -1615;CANADIAN SYLLABICS SAYISI JU;Lo;0;L;;;;;N;;;;; -1616;CANADIAN SYLLABICS CARRIER JO;Lo;0;L;;;;;N;;;;; -1617;CANADIAN SYLLABICS CARRIER JE;Lo;0;L;;;;;N;;;;; -1618;CANADIAN SYLLABICS CARRIER JEE;Lo;0;L;;;;;N;;;;; -1619;CANADIAN SYLLABICS CARRIER JI;Lo;0;L;;;;;N;;;;; -161A;CANADIAN SYLLABICS SAYISI JI;Lo;0;L;;;;;N;;;;; -161B;CANADIAN SYLLABICS CARRIER JA;Lo;0;L;;;;;N;;;;; -161C;CANADIAN SYLLABICS CARRIER JJU;Lo;0;L;;;;;N;;;;; -161D;CANADIAN SYLLABICS CARRIER JJO;Lo;0;L;;;;;N;;;;; -161E;CANADIAN SYLLABICS CARRIER JJE;Lo;0;L;;;;;N;;;;; -161F;CANADIAN SYLLABICS CARRIER JJEE;Lo;0;L;;;;;N;;;;; -1620;CANADIAN SYLLABICS CARRIER JJI;Lo;0;L;;;;;N;;;;; -1621;CANADIAN SYLLABICS CARRIER JJA;Lo;0;L;;;;;N;;;;; -1622;CANADIAN SYLLABICS CARRIER LU;Lo;0;L;;;;;N;;;;; -1623;CANADIAN SYLLABICS CARRIER LO;Lo;0;L;;;;;N;;;;; -1624;CANADIAN SYLLABICS CARRIER LE;Lo;0;L;;;;;N;;;;; -1625;CANADIAN SYLLABICS CARRIER LEE;Lo;0;L;;;;;N;;;;; -1626;CANADIAN SYLLABICS CARRIER LI;Lo;0;L;;;;;N;;;;; -1627;CANADIAN SYLLABICS CARRIER LA;Lo;0;L;;;;;N;;;;; -1628;CANADIAN SYLLABICS CARRIER DLU;Lo;0;L;;;;;N;;;;; -1629;CANADIAN SYLLABICS CARRIER DLO;Lo;0;L;;;;;N;;;;; -162A;CANADIAN SYLLABICS CARRIER DLE;Lo;0;L;;;;;N;;;;; -162B;CANADIAN SYLLABICS CARRIER DLEE;Lo;0;L;;;;;N;;;;; -162C;CANADIAN SYLLABICS CARRIER DLI;Lo;0;L;;;;;N;;;;; -162D;CANADIAN SYLLABICS CARRIER DLA;Lo;0;L;;;;;N;;;;; -162E;CANADIAN SYLLABICS CARRIER LHU;Lo;0;L;;;;;N;;;;; -162F;CANADIAN SYLLABICS CARRIER LHO;Lo;0;L;;;;;N;;;;; -1630;CANADIAN SYLLABICS CARRIER LHE;Lo;0;L;;;;;N;;;;; -1631;CANADIAN SYLLABICS CARRIER LHEE;Lo;0;L;;;;;N;;;;; -1632;CANADIAN SYLLABICS CARRIER LHI;Lo;0;L;;;;;N;;;;; -1633;CANADIAN SYLLABICS CARRIER LHA;Lo;0;L;;;;;N;;;;; -1634;CANADIAN SYLLABICS CARRIER TLHU;Lo;0;L;;;;;N;;;;; -1635;CANADIAN SYLLABICS CARRIER TLHO;Lo;0;L;;;;;N;;;;; -1636;CANADIAN SYLLABICS CARRIER TLHE;Lo;0;L;;;;;N;;;;; -1637;CANADIAN SYLLABICS CARRIER TLHEE;Lo;0;L;;;;;N;;;;; -1638;CANADIAN SYLLABICS CARRIER TLHI;Lo;0;L;;;;;N;;;;; -1639;CANADIAN SYLLABICS CARRIER TLHA;Lo;0;L;;;;;N;;;;; -163A;CANADIAN SYLLABICS CARRIER TLU;Lo;0;L;;;;;N;;;;; -163B;CANADIAN SYLLABICS CARRIER TLO;Lo;0;L;;;;;N;;;;; -163C;CANADIAN SYLLABICS CARRIER TLE;Lo;0;L;;;;;N;;;;; -163D;CANADIAN SYLLABICS CARRIER TLEE;Lo;0;L;;;;;N;;;;; -163E;CANADIAN SYLLABICS CARRIER TLI;Lo;0;L;;;;;N;;;;; -163F;CANADIAN SYLLABICS CARRIER TLA;Lo;0;L;;;;;N;;;;; -1640;CANADIAN SYLLABICS CARRIER ZU;Lo;0;L;;;;;N;;;;; -1641;CANADIAN SYLLABICS CARRIER ZO;Lo;0;L;;;;;N;;;;; -1642;CANADIAN SYLLABICS CARRIER ZE;Lo;0;L;;;;;N;;;;; -1643;CANADIAN SYLLABICS CARRIER ZEE;Lo;0;L;;;;;N;;;;; -1644;CANADIAN SYLLABICS CARRIER ZI;Lo;0;L;;;;;N;;;;; -1645;CANADIAN SYLLABICS CARRIER ZA;Lo;0;L;;;;;N;;;;; -1646;CANADIAN SYLLABICS CARRIER Z;Lo;0;L;;;;;N;;;;; -1647;CANADIAN SYLLABICS CARRIER INITIAL Z;Lo;0;L;;;;;N;;;;; -1648;CANADIAN SYLLABICS CARRIER DZU;Lo;0;L;;;;;N;;;;; -1649;CANADIAN SYLLABICS CARRIER DZO;Lo;0;L;;;;;N;;;;; -164A;CANADIAN SYLLABICS CARRIER DZE;Lo;0;L;;;;;N;;;;; -164B;CANADIAN SYLLABICS CARRIER DZEE;Lo;0;L;;;;;N;;;;; -164C;CANADIAN SYLLABICS CARRIER DZI;Lo;0;L;;;;;N;;;;; -164D;CANADIAN SYLLABICS CARRIER DZA;Lo;0;L;;;;;N;;;;; -164E;CANADIAN SYLLABICS CARRIER SU;Lo;0;L;;;;;N;;;;; -164F;CANADIAN SYLLABICS CARRIER SO;Lo;0;L;;;;;N;;;;; -1650;CANADIAN SYLLABICS CARRIER SE;Lo;0;L;;;;;N;;;;; -1651;CANADIAN SYLLABICS CARRIER SEE;Lo;0;L;;;;;N;;;;; -1652;CANADIAN SYLLABICS CARRIER SI;Lo;0;L;;;;;N;;;;; -1653;CANADIAN SYLLABICS CARRIER SA;Lo;0;L;;;;;N;;;;; -1654;CANADIAN SYLLABICS CARRIER SHU;Lo;0;L;;;;;N;;;;; -1655;CANADIAN SYLLABICS CARRIER SHO;Lo;0;L;;;;;N;;;;; -1656;CANADIAN SYLLABICS CARRIER SHE;Lo;0;L;;;;;N;;;;; -1657;CANADIAN SYLLABICS CARRIER SHEE;Lo;0;L;;;;;N;;;;; -1658;CANADIAN SYLLABICS CARRIER SHI;Lo;0;L;;;;;N;;;;; -1659;CANADIAN SYLLABICS CARRIER SHA;Lo;0;L;;;;;N;;;;; -165A;CANADIAN SYLLABICS CARRIER SH;Lo;0;L;;;;;N;;;;; -165B;CANADIAN SYLLABICS CARRIER TSU;Lo;0;L;;;;;N;;;;; -165C;CANADIAN SYLLABICS CARRIER TSO;Lo;0;L;;;;;N;;;;; -165D;CANADIAN SYLLABICS CARRIER TSE;Lo;0;L;;;;;N;;;;; -165E;CANADIAN SYLLABICS CARRIER TSEE;Lo;0;L;;;;;N;;;;; -165F;CANADIAN SYLLABICS CARRIER TSI;Lo;0;L;;;;;N;;;;; -1660;CANADIAN SYLLABICS CARRIER TSA;Lo;0;L;;;;;N;;;;; -1661;CANADIAN SYLLABICS CARRIER CHU;Lo;0;L;;;;;N;;;;; -1662;CANADIAN SYLLABICS CARRIER CHO;Lo;0;L;;;;;N;;;;; -1663;CANADIAN SYLLABICS CARRIER CHE;Lo;0;L;;;;;N;;;;; -1664;CANADIAN SYLLABICS CARRIER CHEE;Lo;0;L;;;;;N;;;;; -1665;CANADIAN SYLLABICS CARRIER CHI;Lo;0;L;;;;;N;;;;; -1666;CANADIAN SYLLABICS CARRIER CHA;Lo;0;L;;;;;N;;;;; -1667;CANADIAN SYLLABICS CARRIER TTSU;Lo;0;L;;;;;N;;;;; -1668;CANADIAN SYLLABICS CARRIER TTSO;Lo;0;L;;;;;N;;;;; -1669;CANADIAN SYLLABICS CARRIER TTSE;Lo;0;L;;;;;N;;;;; -166A;CANADIAN SYLLABICS CARRIER TTSEE;Lo;0;L;;;;;N;;;;; -166B;CANADIAN SYLLABICS CARRIER TTSI;Lo;0;L;;;;;N;;;;; -166C;CANADIAN SYLLABICS CARRIER TTSA;Lo;0;L;;;;;N;;;;; -166D;CANADIAN SYLLABICS CHI SIGN;So;0;L;;;;;N;;;;; -166E;CANADIAN SYLLABICS FULL STOP;Po;0;L;;;;;N;;;;; -166F;CANADIAN SYLLABICS QAI;Lo;0;L;;;;;N;;;;; -1670;CANADIAN SYLLABICS NGAI;Lo;0;L;;;;;N;;;;; -1671;CANADIAN SYLLABICS NNGI;Lo;0;L;;;;;N;;;;; -1672;CANADIAN SYLLABICS NNGII;Lo;0;L;;;;;N;;;;; -1673;CANADIAN SYLLABICS NNGO;Lo;0;L;;;;;N;;;;; -1674;CANADIAN SYLLABICS NNGOO;Lo;0;L;;;;;N;;;;; -1675;CANADIAN SYLLABICS NNGA;Lo;0;L;;;;;N;;;;; -1676;CANADIAN SYLLABICS NNGAA;Lo;0;L;;;;;N;;;;; -1677;CANADIAN SYLLABICS WOODS-CREE THWEE;Lo;0;L;;;;;N;;;;; -1678;CANADIAN SYLLABICS WOODS-CREE THWI;Lo;0;L;;;;;N;;;;; -1679;CANADIAN SYLLABICS WOODS-CREE THWII;Lo;0;L;;;;;N;;;;; -167A;CANADIAN SYLLABICS WOODS-CREE THWO;Lo;0;L;;;;;N;;;;; -167B;CANADIAN SYLLABICS WOODS-CREE THWOO;Lo;0;L;;;;;N;;;;; -167C;CANADIAN SYLLABICS WOODS-CREE THWA;Lo;0;L;;;;;N;;;;; -167D;CANADIAN SYLLABICS WOODS-CREE THWAA;Lo;0;L;;;;;N;;;;; -167E;CANADIAN SYLLABICS WOODS-CREE FINAL TH;Lo;0;L;;;;;N;;;;; -167F;CANADIAN SYLLABICS BLACKFOOT W;Lo;0;L;;;;;N;;;;; -1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;; -1681;OGHAM LETTER BEITH;Lo;0;L;;;;;N;;;;; -1682;OGHAM LETTER LUIS;Lo;0;L;;;;;N;;;;; -1683;OGHAM LETTER FEARN;Lo;0;L;;;;;N;;;;; -1684;OGHAM LETTER SAIL;Lo;0;L;;;;;N;;;;; -1685;OGHAM LETTER NION;Lo;0;L;;;;;N;;;;; -1686;OGHAM LETTER UATH;Lo;0;L;;;;;N;;;;; -1687;OGHAM LETTER DAIR;Lo;0;L;;;;;N;;;;; -1688;OGHAM LETTER TINNE;Lo;0;L;;;;;N;;;;; -1689;OGHAM LETTER COLL;Lo;0;L;;;;;N;;;;; -168A;OGHAM LETTER CEIRT;Lo;0;L;;;;;N;;;;; -168B;OGHAM LETTER MUIN;Lo;0;L;;;;;N;;;;; -168C;OGHAM LETTER GORT;Lo;0;L;;;;;N;;;;; -168D;OGHAM LETTER NGEADAL;Lo;0;L;;;;;N;;;;; -168E;OGHAM LETTER STRAIF;Lo;0;L;;;;;N;;;;; -168F;OGHAM LETTER RUIS;Lo;0;L;;;;;N;;;;; -1690;OGHAM LETTER AILM;Lo;0;L;;;;;N;;;;; -1691;OGHAM LETTER ONN;Lo;0;L;;;;;N;;;;; -1692;OGHAM LETTER UR;Lo;0;L;;;;;N;;;;; -1693;OGHAM LETTER EADHADH;Lo;0;L;;;;;N;;;;; -1694;OGHAM LETTER IODHADH;Lo;0;L;;;;;N;;;;; -1695;OGHAM LETTER EABHADH;Lo;0;L;;;;;N;;;;; -1696;OGHAM LETTER OR;Lo;0;L;;;;;N;;;;; -1697;OGHAM LETTER UILLEANN;Lo;0;L;;;;;N;;;;; -1698;OGHAM LETTER IFIN;Lo;0;L;;;;;N;;;;; -1699;OGHAM LETTER EAMHANCHOLL;Lo;0;L;;;;;N;;;;; -169A;OGHAM LETTER PEITH;Lo;0;L;;;;;N;;;;; -169B;OGHAM FEATHER MARK;Ps;0;ON;;;;;Y;;;;; -169C;OGHAM REVERSED FEATHER MARK;Pe;0;ON;;;;;Y;;;;; -16A0;RUNIC LETTER FEHU FEOH FE F;Lo;0;L;;;;;N;;;;; -16A1;RUNIC LETTER V;Lo;0;L;;;;;N;;;;; -16A2;RUNIC LETTER URUZ UR U;Lo;0;L;;;;;N;;;;; -16A3;RUNIC LETTER YR;Lo;0;L;;;;;N;;;;; -16A4;RUNIC LETTER Y;Lo;0;L;;;;;N;;;;; -16A5;RUNIC LETTER W;Lo;0;L;;;;;N;;;;; -16A6;RUNIC LETTER THURISAZ THURS THORN;Lo;0;L;;;;;N;;;;; -16A7;RUNIC LETTER ETH;Lo;0;L;;;;;N;;;;; -16A8;RUNIC LETTER ANSUZ A;Lo;0;L;;;;;N;;;;; -16A9;RUNIC LETTER OS O;Lo;0;L;;;;;N;;;;; -16AA;RUNIC LETTER AC A;Lo;0;L;;;;;N;;;;; -16AB;RUNIC LETTER AESC;Lo;0;L;;;;;N;;;;; -16AC;RUNIC LETTER LONG-BRANCH-OSS O;Lo;0;L;;;;;N;;;;; -16AD;RUNIC LETTER SHORT-TWIG-OSS O;Lo;0;L;;;;;N;;;;; -16AE;RUNIC LETTER O;Lo;0;L;;;;;N;;;;; -16AF;RUNIC LETTER OE;Lo;0;L;;;;;N;;;;; -16B0;RUNIC LETTER ON;Lo;0;L;;;;;N;;;;; -16B1;RUNIC LETTER RAIDO RAD REID R;Lo;0;L;;;;;N;;;;; -16B2;RUNIC LETTER KAUNA;Lo;0;L;;;;;N;;;;; -16B3;RUNIC LETTER CEN;Lo;0;L;;;;;N;;;;; -16B4;RUNIC LETTER KAUN K;Lo;0;L;;;;;N;;;;; -16B5;RUNIC LETTER G;Lo;0;L;;;;;N;;;;; -16B6;RUNIC LETTER ENG;Lo;0;L;;;;;N;;;;; -16B7;RUNIC LETTER GEBO GYFU G;Lo;0;L;;;;;N;;;;; -16B8;RUNIC LETTER GAR;Lo;0;L;;;;;N;;;;; -16B9;RUNIC LETTER WUNJO WYNN W;Lo;0;L;;;;;N;;;;; -16BA;RUNIC LETTER HAGLAZ H;Lo;0;L;;;;;N;;;;; -16BB;RUNIC LETTER HAEGL H;Lo;0;L;;;;;N;;;;; -16BC;RUNIC LETTER LONG-BRANCH-HAGALL H;Lo;0;L;;;;;N;;;;; -16BD;RUNIC LETTER SHORT-TWIG-HAGALL H;Lo;0;L;;;;;N;;;;; -16BE;RUNIC LETTER NAUDIZ NYD NAUD N;Lo;0;L;;;;;N;;;;; -16BF;RUNIC LETTER SHORT-TWIG-NAUD N;Lo;0;L;;;;;N;;;;; -16C0;RUNIC LETTER DOTTED-N;Lo;0;L;;;;;N;;;;; -16C1;RUNIC LETTER ISAZ IS ISS I;Lo;0;L;;;;;N;;;;; -16C2;RUNIC LETTER E;Lo;0;L;;;;;N;;;;; -16C3;RUNIC LETTER JERAN J;Lo;0;L;;;;;N;;;;; -16C4;RUNIC LETTER GER;Lo;0;L;;;;;N;;;;; -16C5;RUNIC LETTER LONG-BRANCH-AR AE;Lo;0;L;;;;;N;;;;; -16C6;RUNIC LETTER SHORT-TWIG-AR A;Lo;0;L;;;;;N;;;;; -16C7;RUNIC LETTER IWAZ EOH;Lo;0;L;;;;;N;;;;; -16C8;RUNIC LETTER PERTHO PEORTH P;Lo;0;L;;;;;N;;;;; -16C9;RUNIC LETTER ALGIZ EOLHX;Lo;0;L;;;;;N;;;;; -16CA;RUNIC LETTER SOWILO S;Lo;0;L;;;;;N;;;;; -16CB;RUNIC LETTER SIGEL LONG-BRANCH-SOL S;Lo;0;L;;;;;N;;;;; -16CC;RUNIC LETTER SHORT-TWIG-SOL S;Lo;0;L;;;;;N;;;;; -16CD;RUNIC LETTER C;Lo;0;L;;;;;N;;;;; -16CE;RUNIC LETTER Z;Lo;0;L;;;;;N;;;;; -16CF;RUNIC LETTER TIWAZ TIR TYR T;Lo;0;L;;;;;N;;;;; -16D0;RUNIC LETTER SHORT-TWIG-TYR T;Lo;0;L;;;;;N;;;;; -16D1;RUNIC LETTER D;Lo;0;L;;;;;N;;;;; -16D2;RUNIC LETTER BERKANAN BEORC BJARKAN B;Lo;0;L;;;;;N;;;;; -16D3;RUNIC LETTER SHORT-TWIG-BJARKAN B;Lo;0;L;;;;;N;;;;; -16D4;RUNIC LETTER DOTTED-P;Lo;0;L;;;;;N;;;;; -16D5;RUNIC LETTER OPEN-P;Lo;0;L;;;;;N;;;;; -16D6;RUNIC LETTER EHWAZ EH E;Lo;0;L;;;;;N;;;;; -16D7;RUNIC LETTER MANNAZ MAN M;Lo;0;L;;;;;N;;;;; -16D8;RUNIC LETTER LONG-BRANCH-MADR M;Lo;0;L;;;;;N;;;;; -16D9;RUNIC LETTER SHORT-TWIG-MADR M;Lo;0;L;;;;;N;;;;; -16DA;RUNIC LETTER LAUKAZ LAGU LOGR L;Lo;0;L;;;;;N;;;;; -16DB;RUNIC LETTER DOTTED-L;Lo;0;L;;;;;N;;;;; -16DC;RUNIC LETTER INGWAZ;Lo;0;L;;;;;N;;;;; -16DD;RUNIC LETTER ING;Lo;0;L;;;;;N;;;;; -16DE;RUNIC LETTER DAGAZ DAEG D;Lo;0;L;;;;;N;;;;; -16DF;RUNIC LETTER OTHALAN ETHEL O;Lo;0;L;;;;;N;;;;; -16E0;RUNIC LETTER EAR;Lo;0;L;;;;;N;;;;; -16E1;RUNIC LETTER IOR;Lo;0;L;;;;;N;;;;; -16E2;RUNIC LETTER CWEORTH;Lo;0;L;;;;;N;;;;; -16E3;RUNIC LETTER CALC;Lo;0;L;;;;;N;;;;; -16E4;RUNIC LETTER CEALC;Lo;0;L;;;;;N;;;;; -16E5;RUNIC LETTER STAN;Lo;0;L;;;;;N;;;;; -16E6;RUNIC LETTER LONG-BRANCH-YR;Lo;0;L;;;;;N;;;;; -16E7;RUNIC LETTER SHORT-TWIG-YR;Lo;0;L;;;;;N;;;;; -16E8;RUNIC LETTER ICELANDIC-YR;Lo;0;L;;;;;N;;;;; -16E9;RUNIC LETTER Q;Lo;0;L;;;;;N;;;;; -16EA;RUNIC LETTER X;Lo;0;L;;;;;N;;;;; -16EB;RUNIC SINGLE PUNCTUATION;Po;0;L;;;;;N;;;;; -16EC;RUNIC MULTIPLE PUNCTUATION;Po;0;L;;;;;N;;;;; -16ED;RUNIC CROSS PUNCTUATION;Po;0;L;;;;;N;;;;; -16EE;RUNIC ARLAUG SYMBOL;Nl;0;L;;;;17;N;;;;; -16EF;RUNIC TVIMADUR SYMBOL;Nl;0;L;;;;18;N;;;;; -16F0;RUNIC BELGTHOR SYMBOL;Nl;0;L;;;;19;N;;;;; -16F1;RUNIC LETTER K;Lo;0;L;;;;;N;;;;; -16F2;RUNIC LETTER SH;Lo;0;L;;;;;N;;;;; -16F3;RUNIC LETTER OO;Lo;0;L;;;;;N;;;;; -16F4;RUNIC LETTER FRANKS CASKET OS;Lo;0;L;;;;;N;;;;; -16F5;RUNIC LETTER FRANKS CASKET IS;Lo;0;L;;;;;N;;;;; -16F6;RUNIC LETTER FRANKS CASKET EH;Lo;0;L;;;;;N;;;;; -16F7;RUNIC LETTER FRANKS CASKET AC;Lo;0;L;;;;;N;;;;; -16F8;RUNIC LETTER FRANKS CASKET AESC;Lo;0;L;;;;;N;;;;; -1700;TAGALOG LETTER A;Lo;0;L;;;;;N;;;;; -1701;TAGALOG LETTER I;Lo;0;L;;;;;N;;;;; -1702;TAGALOG LETTER U;Lo;0;L;;;;;N;;;;; -1703;TAGALOG LETTER KA;Lo;0;L;;;;;N;;;;; -1704;TAGALOG LETTER GA;Lo;0;L;;;;;N;;;;; -1705;TAGALOG LETTER NGA;Lo;0;L;;;;;N;;;;; -1706;TAGALOG LETTER TA;Lo;0;L;;;;;N;;;;; -1707;TAGALOG LETTER DA;Lo;0;L;;;;;N;;;;; -1708;TAGALOG LETTER NA;Lo;0;L;;;;;N;;;;; -1709;TAGALOG LETTER PA;Lo;0;L;;;;;N;;;;; -170A;TAGALOG LETTER BA;Lo;0;L;;;;;N;;;;; -170B;TAGALOG LETTER MA;Lo;0;L;;;;;N;;;;; -170C;TAGALOG LETTER YA;Lo;0;L;;;;;N;;;;; -170D;TAGALOG LETTER RA;Lo;0;L;;;;;N;;;;; -170E;TAGALOG LETTER LA;Lo;0;L;;;;;N;;;;; -170F;TAGALOG LETTER WA;Lo;0;L;;;;;N;;;;; -1710;TAGALOG LETTER SA;Lo;0;L;;;;;N;;;;; -1711;TAGALOG LETTER HA;Lo;0;L;;;;;N;;;;; -1712;TAGALOG VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -1713;TAGALOG VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -1714;TAGALOG SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -1715;TAGALOG SIGN PAMUDPOD;Mc;9;L;;;;;N;;;;; -171F;TAGALOG LETTER ARCHAIC RA;Lo;0;L;;;;;N;;;;; -1720;HANUNOO LETTER A;Lo;0;L;;;;;N;;;;; -1721;HANUNOO LETTER I;Lo;0;L;;;;;N;;;;; -1722;HANUNOO LETTER U;Lo;0;L;;;;;N;;;;; -1723;HANUNOO LETTER KA;Lo;0;L;;;;;N;;;;; -1724;HANUNOO LETTER GA;Lo;0;L;;;;;N;;;;; -1725;HANUNOO LETTER NGA;Lo;0;L;;;;;N;;;;; -1726;HANUNOO LETTER TA;Lo;0;L;;;;;N;;;;; -1727;HANUNOO LETTER DA;Lo;0;L;;;;;N;;;;; -1728;HANUNOO LETTER NA;Lo;0;L;;;;;N;;;;; -1729;HANUNOO LETTER PA;Lo;0;L;;;;;N;;;;; -172A;HANUNOO LETTER BA;Lo;0;L;;;;;N;;;;; -172B;HANUNOO LETTER MA;Lo;0;L;;;;;N;;;;; -172C;HANUNOO LETTER YA;Lo;0;L;;;;;N;;;;; -172D;HANUNOO LETTER RA;Lo;0;L;;;;;N;;;;; -172E;HANUNOO LETTER LA;Lo;0;L;;;;;N;;;;; -172F;HANUNOO LETTER WA;Lo;0;L;;;;;N;;;;; -1730;HANUNOO LETTER SA;Lo;0;L;;;;;N;;;;; -1731;HANUNOO LETTER HA;Lo;0;L;;;;;N;;;;; -1732;HANUNOO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -1733;HANUNOO VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -1734;HANUNOO SIGN PAMUDPOD;Mc;9;L;;;;;N;;;;; -1735;PHILIPPINE SINGLE PUNCTUATION;Po;0;L;;;;;N;;;;; -1736;PHILIPPINE DOUBLE PUNCTUATION;Po;0;L;;;;;N;;;;; -1740;BUHID LETTER A;Lo;0;L;;;;;N;;;;; -1741;BUHID LETTER I;Lo;0;L;;;;;N;;;;; -1742;BUHID LETTER U;Lo;0;L;;;;;N;;;;; -1743;BUHID LETTER KA;Lo;0;L;;;;;N;;;;; -1744;BUHID LETTER GA;Lo;0;L;;;;;N;;;;; -1745;BUHID LETTER NGA;Lo;0;L;;;;;N;;;;; -1746;BUHID LETTER TA;Lo;0;L;;;;;N;;;;; -1747;BUHID LETTER DA;Lo;0;L;;;;;N;;;;; -1748;BUHID LETTER NA;Lo;0;L;;;;;N;;;;; -1749;BUHID LETTER PA;Lo;0;L;;;;;N;;;;; -174A;BUHID LETTER BA;Lo;0;L;;;;;N;;;;; -174B;BUHID LETTER MA;Lo;0;L;;;;;N;;;;; -174C;BUHID LETTER YA;Lo;0;L;;;;;N;;;;; -174D;BUHID LETTER RA;Lo;0;L;;;;;N;;;;; -174E;BUHID LETTER LA;Lo;0;L;;;;;N;;;;; -174F;BUHID LETTER WA;Lo;0;L;;;;;N;;;;; -1750;BUHID LETTER SA;Lo;0;L;;;;;N;;;;; -1751;BUHID LETTER HA;Lo;0;L;;;;;N;;;;; -1752;BUHID VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -1753;BUHID VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -1760;TAGBANWA LETTER A;Lo;0;L;;;;;N;;;;; -1761;TAGBANWA LETTER I;Lo;0;L;;;;;N;;;;; -1762;TAGBANWA LETTER U;Lo;0;L;;;;;N;;;;; -1763;TAGBANWA LETTER KA;Lo;0;L;;;;;N;;;;; -1764;TAGBANWA LETTER GA;Lo;0;L;;;;;N;;;;; -1765;TAGBANWA LETTER NGA;Lo;0;L;;;;;N;;;;; -1766;TAGBANWA LETTER TA;Lo;0;L;;;;;N;;;;; -1767;TAGBANWA LETTER DA;Lo;0;L;;;;;N;;;;; -1768;TAGBANWA LETTER NA;Lo;0;L;;;;;N;;;;; -1769;TAGBANWA LETTER PA;Lo;0;L;;;;;N;;;;; -176A;TAGBANWA LETTER BA;Lo;0;L;;;;;N;;;;; -176B;TAGBANWA LETTER MA;Lo;0;L;;;;;N;;;;; -176C;TAGBANWA LETTER YA;Lo;0;L;;;;;N;;;;; -176E;TAGBANWA LETTER LA;Lo;0;L;;;;;N;;;;; -176F;TAGBANWA LETTER WA;Lo;0;L;;;;;N;;;;; -1770;TAGBANWA LETTER SA;Lo;0;L;;;;;N;;;;; -1772;TAGBANWA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -1773;TAGBANWA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -1780;KHMER LETTER KA;Lo;0;L;;;;;N;;;;; -1781;KHMER LETTER KHA;Lo;0;L;;;;;N;;;;; -1782;KHMER LETTER KO;Lo;0;L;;;;;N;;;;; -1783;KHMER LETTER KHO;Lo;0;L;;;;;N;;;;; -1784;KHMER LETTER NGO;Lo;0;L;;;;;N;;;;; -1785;KHMER LETTER CA;Lo;0;L;;;;;N;;;;; -1786;KHMER LETTER CHA;Lo;0;L;;;;;N;;;;; -1787;KHMER LETTER CO;Lo;0;L;;;;;N;;;;; -1788;KHMER LETTER CHO;Lo;0;L;;;;;N;;;;; -1789;KHMER LETTER NYO;Lo;0;L;;;;;N;;;;; -178A;KHMER LETTER DA;Lo;0;L;;;;;N;;;;; -178B;KHMER LETTER TTHA;Lo;0;L;;;;;N;;;;; -178C;KHMER LETTER DO;Lo;0;L;;;;;N;;;;; -178D;KHMER LETTER TTHO;Lo;0;L;;;;;N;;;;; -178E;KHMER LETTER NNO;Lo;0;L;;;;;N;;;;; -178F;KHMER LETTER TA;Lo;0;L;;;;;N;;;;; -1790;KHMER LETTER THA;Lo;0;L;;;;;N;;;;; -1791;KHMER LETTER TO;Lo;0;L;;;;;N;;;;; -1792;KHMER LETTER THO;Lo;0;L;;;;;N;;;;; -1793;KHMER LETTER NO;Lo;0;L;;;;;N;;;;; -1794;KHMER LETTER BA;Lo;0;L;;;;;N;;;;; -1795;KHMER LETTER PHA;Lo;0;L;;;;;N;;;;; -1796;KHMER LETTER PO;Lo;0;L;;;;;N;;;;; -1797;KHMER LETTER PHO;Lo;0;L;;;;;N;;;;; -1798;KHMER LETTER MO;Lo;0;L;;;;;N;;;;; -1799;KHMER LETTER YO;Lo;0;L;;;;;N;;;;; -179A;KHMER LETTER RO;Lo;0;L;;;;;N;;;;; -179B;KHMER LETTER LO;Lo;0;L;;;;;N;;;;; -179C;KHMER LETTER VO;Lo;0;L;;;;;N;;;;; -179D;KHMER LETTER SHA;Lo;0;L;;;;;N;;;;; -179E;KHMER LETTER SSO;Lo;0;L;;;;;N;;;;; -179F;KHMER LETTER SA;Lo;0;L;;;;;N;;;;; -17A0;KHMER LETTER HA;Lo;0;L;;;;;N;;;;; -17A1;KHMER LETTER LA;Lo;0;L;;;;;N;;;;; -17A2;KHMER LETTER QA;Lo;0;L;;;;;N;;;;; -17A3;KHMER INDEPENDENT VOWEL QAQ;Lo;0;L;;;;;N;;;;; -17A4;KHMER INDEPENDENT VOWEL QAA;Lo;0;L;;;;;N;;;;; -17A5;KHMER INDEPENDENT VOWEL QI;Lo;0;L;;;;;N;;;;; -17A6;KHMER INDEPENDENT VOWEL QII;Lo;0;L;;;;;N;;;;; -17A7;KHMER INDEPENDENT VOWEL QU;Lo;0;L;;;;;N;;;;; -17A8;KHMER INDEPENDENT VOWEL QUK;Lo;0;L;;;;;N;;;;; -17A9;KHMER INDEPENDENT VOWEL QUU;Lo;0;L;;;;;N;;;;; -17AA;KHMER INDEPENDENT VOWEL QUUV;Lo;0;L;;;;;N;;;;; -17AB;KHMER INDEPENDENT VOWEL RY;Lo;0;L;;;;;N;;;;; -17AC;KHMER INDEPENDENT VOWEL RYY;Lo;0;L;;;;;N;;;;; -17AD;KHMER INDEPENDENT VOWEL LY;Lo;0;L;;;;;N;;;;; -17AE;KHMER INDEPENDENT VOWEL LYY;Lo;0;L;;;;;N;;;;; -17AF;KHMER INDEPENDENT VOWEL QE;Lo;0;L;;;;;N;;;;; -17B0;KHMER INDEPENDENT VOWEL QAI;Lo;0;L;;;;;N;;;;; -17B1;KHMER INDEPENDENT VOWEL QOO TYPE ONE;Lo;0;L;;;;;N;;;;; -17B2;KHMER INDEPENDENT VOWEL QOO TYPE TWO;Lo;0;L;;;;;N;;;;; -17B3;KHMER INDEPENDENT VOWEL QAU;Lo;0;L;;;;;N;;;;; -17B4;KHMER VOWEL INHERENT AQ;Mn;0;NSM;;;;;N;;;;; -17B5;KHMER VOWEL INHERENT AA;Mn;0;NSM;;;;;N;;;;; -17B6;KHMER VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -17B7;KHMER VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -17B8;KHMER VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; -17B9;KHMER VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;; -17BA;KHMER VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;; -17BB;KHMER VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -17BC;KHMER VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -17BD;KHMER VOWEL SIGN UA;Mn;0;NSM;;;;;N;;;;; -17BE;KHMER VOWEL SIGN OE;Mc;0;L;;;;;N;;;;; -17BF;KHMER VOWEL SIGN YA;Mc;0;L;;;;;N;;;;; -17C0;KHMER VOWEL SIGN IE;Mc;0;L;;;;;N;;;;; -17C1;KHMER VOWEL SIGN E;Mc;0;L;;;;;N;;;;; -17C2;KHMER VOWEL SIGN AE;Mc;0;L;;;;;N;;;;; -17C3;KHMER VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; -17C4;KHMER VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; -17C5;KHMER VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; -17C6;KHMER SIGN NIKAHIT;Mn;0;NSM;;;;;N;;;;; -17C7;KHMER SIGN REAHMUK;Mc;0;L;;;;;N;;;;; -17C8;KHMER SIGN YUUKALEAPINTU;Mc;0;L;;;;;N;;;;; -17C9;KHMER SIGN MUUSIKATOAN;Mn;0;NSM;;;;;N;;;;; -17CA;KHMER SIGN TRIISAP;Mn;0;NSM;;;;;N;;;;; -17CB;KHMER SIGN BANTOC;Mn;0;NSM;;;;;N;;;;; -17CC;KHMER SIGN ROBAT;Mn;0;NSM;;;;;N;;;;; -17CD;KHMER SIGN TOANDAKHIAT;Mn;0;NSM;;;;;N;;;;; -17CE;KHMER SIGN KAKABAT;Mn;0;NSM;;;;;N;;;;; -17CF;KHMER SIGN AHSDA;Mn;0;NSM;;;;;N;;;;; -17D0;KHMER SIGN SAMYOK SANNYA;Mn;0;NSM;;;;;N;;;;; -17D1;KHMER SIGN VIRIAM;Mn;0;NSM;;;;;N;;;;; -17D2;KHMER SIGN COENG;Mn;9;NSM;;;;;N;;;;; -17D3;KHMER SIGN BATHAMASAT;Mn;0;NSM;;;;;N;;;;; -17D4;KHMER SIGN KHAN;Po;0;L;;;;;N;;;;; -17D5;KHMER SIGN BARIYOOSAN;Po;0;L;;;;;N;;;;; -17D6;KHMER SIGN CAMNUC PII KUUH;Po;0;L;;;;;N;;;;; -17D7;KHMER SIGN LEK TOO;Lm;0;L;;;;;N;;;;; -17D8;KHMER SIGN BEYYAL;Po;0;L;;;;;N;;;;; -17D9;KHMER SIGN PHNAEK MUAN;Po;0;L;;;;;N;;;;; -17DA;KHMER SIGN KOOMUUT;Po;0;L;;;;;N;;;;; -17DB;KHMER CURRENCY SYMBOL RIEL;Sc;0;ET;;;;;N;;;;; -17DC;KHMER SIGN AVAKRAHASANYA;Lo;0;L;;;;;N;;;;; -17DD;KHMER SIGN ATTHACAN;Mn;230;NSM;;;;;N;;;;; -17E0;KHMER DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -17E1;KHMER DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -17E2;KHMER DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -17E3;KHMER DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -17E4;KHMER DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -17E5;KHMER DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -17E6;KHMER DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -17E7;KHMER DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -17E8;KHMER DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -17E9;KHMER DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -17F0;KHMER SYMBOL LEK ATTAK SON;No;0;ON;;;;0;N;;;;; -17F1;KHMER SYMBOL LEK ATTAK MUOY;No;0;ON;;;;1;N;;;;; -17F2;KHMER SYMBOL LEK ATTAK PII;No;0;ON;;;;2;N;;;;; -17F3;KHMER SYMBOL LEK ATTAK BEI;No;0;ON;;;;3;N;;;;; -17F4;KHMER SYMBOL LEK ATTAK BUON;No;0;ON;;;;4;N;;;;; -17F5;KHMER SYMBOL LEK ATTAK PRAM;No;0;ON;;;;5;N;;;;; -17F6;KHMER SYMBOL LEK ATTAK PRAM-MUOY;No;0;ON;;;;6;N;;;;; -17F7;KHMER SYMBOL LEK ATTAK PRAM-PII;No;0;ON;;;;7;N;;;;; -17F8;KHMER SYMBOL LEK ATTAK PRAM-BEI;No;0;ON;;;;8;N;;;;; -17F9;KHMER SYMBOL LEK ATTAK PRAM-BUON;No;0;ON;;;;9;N;;;;; -1800;MONGOLIAN BIRGA;Po;0;ON;;;;;N;;;;; -1801;MONGOLIAN ELLIPSIS;Po;0;ON;;;;;N;;;;; -1802;MONGOLIAN COMMA;Po;0;ON;;;;;N;;;;; -1803;MONGOLIAN FULL STOP;Po;0;ON;;;;;N;;;;; -1804;MONGOLIAN COLON;Po;0;ON;;;;;N;;;;; -1805;MONGOLIAN FOUR DOTS;Po;0;ON;;;;;N;;;;; -1806;MONGOLIAN TODO SOFT HYPHEN;Pd;0;ON;;;;;N;;;;; -1807;MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER;Po;0;ON;;;;;N;;;;; -1808;MONGOLIAN MANCHU COMMA;Po;0;ON;;;;;N;;;;; -1809;MONGOLIAN MANCHU FULL STOP;Po;0;ON;;;;;N;;;;; -180A;MONGOLIAN NIRUGU;Po;0;ON;;;;;N;;;;; -180B;MONGOLIAN FREE VARIATION SELECTOR ONE;Mn;0;NSM;;;;;N;;;;; -180C;MONGOLIAN FREE VARIATION SELECTOR TWO;Mn;0;NSM;;;;;N;;;;; -180D;MONGOLIAN FREE VARIATION SELECTOR THREE;Mn;0;NSM;;;;;N;;;;; -180E;MONGOLIAN VOWEL SEPARATOR;Cf;0;BN;;;;;N;;;;; -180F;MONGOLIAN FREE VARIATION SELECTOR FOUR;Mn;0;NSM;;;;;N;;;;; -1810;MONGOLIAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -1811;MONGOLIAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -1812;MONGOLIAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -1813;MONGOLIAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -1814;MONGOLIAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -1815;MONGOLIAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -1816;MONGOLIAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -1817;MONGOLIAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -1818;MONGOLIAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -1819;MONGOLIAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -1820;MONGOLIAN LETTER A;Lo;0;L;;;;;N;;;;; -1821;MONGOLIAN LETTER E;Lo;0;L;;;;;N;;;;; -1822;MONGOLIAN LETTER I;Lo;0;L;;;;;N;;;;; -1823;MONGOLIAN LETTER O;Lo;0;L;;;;;N;;;;; -1824;MONGOLIAN LETTER U;Lo;0;L;;;;;N;;;;; -1825;MONGOLIAN LETTER OE;Lo;0;L;;;;;N;;;;; -1826;MONGOLIAN LETTER UE;Lo;0;L;;;;;N;;;;; -1827;MONGOLIAN LETTER EE;Lo;0;L;;;;;N;;;;; -1828;MONGOLIAN LETTER NA;Lo;0;L;;;;;N;;;;; -1829;MONGOLIAN LETTER ANG;Lo;0;L;;;;;N;;;;; -182A;MONGOLIAN LETTER BA;Lo;0;L;;;;;N;;;;; -182B;MONGOLIAN LETTER PA;Lo;0;L;;;;;N;;;;; -182C;MONGOLIAN LETTER QA;Lo;0;L;;;;;N;;;;; -182D;MONGOLIAN LETTER GA;Lo;0;L;;;;;N;;;;; -182E;MONGOLIAN LETTER MA;Lo;0;L;;;;;N;;;;; -182F;MONGOLIAN LETTER LA;Lo;0;L;;;;;N;;;;; -1830;MONGOLIAN LETTER SA;Lo;0;L;;;;;N;;;;; -1831;MONGOLIAN LETTER SHA;Lo;0;L;;;;;N;;;;; -1832;MONGOLIAN LETTER TA;Lo;0;L;;;;;N;;;;; -1833;MONGOLIAN LETTER DA;Lo;0;L;;;;;N;;;;; -1834;MONGOLIAN LETTER CHA;Lo;0;L;;;;;N;;;;; -1835;MONGOLIAN LETTER JA;Lo;0;L;;;;;N;;;;; -1836;MONGOLIAN LETTER YA;Lo;0;L;;;;;N;;;;; -1837;MONGOLIAN LETTER RA;Lo;0;L;;;;;N;;;;; -1838;MONGOLIAN LETTER WA;Lo;0;L;;;;;N;;;;; -1839;MONGOLIAN LETTER FA;Lo;0;L;;;;;N;;;;; -183A;MONGOLIAN LETTER KA;Lo;0;L;;;;;N;;;;; -183B;MONGOLIAN LETTER KHA;Lo;0;L;;;;;N;;;;; -183C;MONGOLIAN LETTER TSA;Lo;0;L;;;;;N;;;;; -183D;MONGOLIAN LETTER ZA;Lo;0;L;;;;;N;;;;; -183E;MONGOLIAN LETTER HAA;Lo;0;L;;;;;N;;;;; -183F;MONGOLIAN LETTER ZRA;Lo;0;L;;;;;N;;;;; -1840;MONGOLIAN LETTER LHA;Lo;0;L;;;;;N;;;;; -1841;MONGOLIAN LETTER ZHI;Lo;0;L;;;;;N;;;;; -1842;MONGOLIAN LETTER CHI;Lo;0;L;;;;;N;;;;; -1843;MONGOLIAN LETTER TODO LONG VOWEL SIGN;Lm;0;L;;;;;N;;;;; -1844;MONGOLIAN LETTER TODO E;Lo;0;L;;;;;N;;;;; -1845;MONGOLIAN LETTER TODO I;Lo;0;L;;;;;N;;;;; -1846;MONGOLIAN LETTER TODO O;Lo;0;L;;;;;N;;;;; -1847;MONGOLIAN LETTER TODO U;Lo;0;L;;;;;N;;;;; -1848;MONGOLIAN LETTER TODO OE;Lo;0;L;;;;;N;;;;; -1849;MONGOLIAN LETTER TODO UE;Lo;0;L;;;;;N;;;;; -184A;MONGOLIAN LETTER TODO ANG;Lo;0;L;;;;;N;;;;; -184B;MONGOLIAN LETTER TODO BA;Lo;0;L;;;;;N;;;;; -184C;MONGOLIAN LETTER TODO PA;Lo;0;L;;;;;N;;;;; -184D;MONGOLIAN LETTER TODO QA;Lo;0;L;;;;;N;;;;; -184E;MONGOLIAN LETTER TODO GA;Lo;0;L;;;;;N;;;;; -184F;MONGOLIAN LETTER TODO MA;Lo;0;L;;;;;N;;;;; -1850;MONGOLIAN LETTER TODO TA;Lo;0;L;;;;;N;;;;; -1851;MONGOLIAN LETTER TODO DA;Lo;0;L;;;;;N;;;;; -1852;MONGOLIAN LETTER TODO CHA;Lo;0;L;;;;;N;;;;; -1853;MONGOLIAN LETTER TODO JA;Lo;0;L;;;;;N;;;;; -1854;MONGOLIAN LETTER TODO TSA;Lo;0;L;;;;;N;;;;; -1855;MONGOLIAN LETTER TODO YA;Lo;0;L;;;;;N;;;;; -1856;MONGOLIAN LETTER TODO WA;Lo;0;L;;;;;N;;;;; -1857;MONGOLIAN LETTER TODO KA;Lo;0;L;;;;;N;;;;; -1858;MONGOLIAN LETTER TODO GAA;Lo;0;L;;;;;N;;;;; -1859;MONGOLIAN LETTER TODO HAA;Lo;0;L;;;;;N;;;;; -185A;MONGOLIAN LETTER TODO JIA;Lo;0;L;;;;;N;;;;; -185B;MONGOLIAN LETTER TODO NIA;Lo;0;L;;;;;N;;;;; -185C;MONGOLIAN LETTER TODO DZA;Lo;0;L;;;;;N;;;;; -185D;MONGOLIAN LETTER SIBE E;Lo;0;L;;;;;N;;;;; -185E;MONGOLIAN LETTER SIBE I;Lo;0;L;;;;;N;;;;; -185F;MONGOLIAN LETTER SIBE IY;Lo;0;L;;;;;N;;;;; -1860;MONGOLIAN LETTER SIBE UE;Lo;0;L;;;;;N;;;;; -1861;MONGOLIAN LETTER SIBE U;Lo;0;L;;;;;N;;;;; -1862;MONGOLIAN LETTER SIBE ANG;Lo;0;L;;;;;N;;;;; -1863;MONGOLIAN LETTER SIBE KA;Lo;0;L;;;;;N;;;;; -1864;MONGOLIAN LETTER SIBE GA;Lo;0;L;;;;;N;;;;; -1865;MONGOLIAN LETTER SIBE HA;Lo;0;L;;;;;N;;;;; -1866;MONGOLIAN LETTER SIBE PA;Lo;0;L;;;;;N;;;;; -1867;MONGOLIAN LETTER SIBE SHA;Lo;0;L;;;;;N;;;;; -1868;MONGOLIAN LETTER SIBE TA;Lo;0;L;;;;;N;;;;; -1869;MONGOLIAN LETTER SIBE DA;Lo;0;L;;;;;N;;;;; -186A;MONGOLIAN LETTER SIBE JA;Lo;0;L;;;;;N;;;;; -186B;MONGOLIAN LETTER SIBE FA;Lo;0;L;;;;;N;;;;; -186C;MONGOLIAN LETTER SIBE GAA;Lo;0;L;;;;;N;;;;; -186D;MONGOLIAN LETTER SIBE HAA;Lo;0;L;;;;;N;;;;; -186E;MONGOLIAN LETTER SIBE TSA;Lo;0;L;;;;;N;;;;; -186F;MONGOLIAN LETTER SIBE ZA;Lo;0;L;;;;;N;;;;; -1870;MONGOLIAN LETTER SIBE RAA;Lo;0;L;;;;;N;;;;; -1871;MONGOLIAN LETTER SIBE CHA;Lo;0;L;;;;;N;;;;; -1872;MONGOLIAN LETTER SIBE ZHA;Lo;0;L;;;;;N;;;;; -1873;MONGOLIAN LETTER MANCHU I;Lo;0;L;;;;;N;;;;; -1874;MONGOLIAN LETTER MANCHU KA;Lo;0;L;;;;;N;;;;; -1875;MONGOLIAN LETTER MANCHU RA;Lo;0;L;;;;;N;;;;; -1876;MONGOLIAN LETTER MANCHU FA;Lo;0;L;;;;;N;;;;; -1877;MONGOLIAN LETTER MANCHU ZHA;Lo;0;L;;;;;N;;;;; -1878;MONGOLIAN LETTER CHA WITH TWO DOTS;Lo;0;L;;;;;N;;;;; -1880;MONGOLIAN LETTER ALI GALI ANUSVARA ONE;Lo;0;L;;;;;N;;;;; -1881;MONGOLIAN LETTER ALI GALI VISARGA ONE;Lo;0;L;;;;;N;;;;; -1882;MONGOLIAN LETTER ALI GALI DAMARU;Lo;0;L;;;;;N;;;;; -1883;MONGOLIAN LETTER ALI GALI UBADAMA;Lo;0;L;;;;;N;;;;; -1884;MONGOLIAN LETTER ALI GALI INVERTED UBADAMA;Lo;0;L;;;;;N;;;;; -1885;MONGOLIAN LETTER ALI GALI BALUDA;Mn;0;NSM;;;;;N;;;;; -1886;MONGOLIAN LETTER ALI GALI THREE BALUDA;Mn;0;NSM;;;;;N;;;;; -1887;MONGOLIAN LETTER ALI GALI A;Lo;0;L;;;;;N;;;;; -1888;MONGOLIAN LETTER ALI GALI I;Lo;0;L;;;;;N;;;;; -1889;MONGOLIAN LETTER ALI GALI KA;Lo;0;L;;;;;N;;;;; -188A;MONGOLIAN LETTER ALI GALI NGA;Lo;0;L;;;;;N;;;;; -188B;MONGOLIAN LETTER ALI GALI CA;Lo;0;L;;;;;N;;;;; -188C;MONGOLIAN LETTER ALI GALI TTA;Lo;0;L;;;;;N;;;;; -188D;MONGOLIAN LETTER ALI GALI TTHA;Lo;0;L;;;;;N;;;;; -188E;MONGOLIAN LETTER ALI GALI DDA;Lo;0;L;;;;;N;;;;; -188F;MONGOLIAN LETTER ALI GALI NNA;Lo;0;L;;;;;N;;;;; -1890;MONGOLIAN LETTER ALI GALI TA;Lo;0;L;;;;;N;;;;; -1891;MONGOLIAN LETTER ALI GALI DA;Lo;0;L;;;;;N;;;;; -1892;MONGOLIAN LETTER ALI GALI PA;Lo;0;L;;;;;N;;;;; -1893;MONGOLIAN LETTER ALI GALI PHA;Lo;0;L;;;;;N;;;;; -1894;MONGOLIAN LETTER ALI GALI SSA;Lo;0;L;;;;;N;;;;; -1895;MONGOLIAN LETTER ALI GALI ZHA;Lo;0;L;;;;;N;;;;; -1896;MONGOLIAN LETTER ALI GALI ZA;Lo;0;L;;;;;N;;;;; -1897;MONGOLIAN LETTER ALI GALI AH;Lo;0;L;;;;;N;;;;; -1898;MONGOLIAN LETTER TODO ALI GALI TA;Lo;0;L;;;;;N;;;;; -1899;MONGOLIAN LETTER TODO ALI GALI ZHA;Lo;0;L;;;;;N;;;;; -189A;MONGOLIAN LETTER MANCHU ALI GALI GHA;Lo;0;L;;;;;N;;;;; -189B;MONGOLIAN LETTER MANCHU ALI GALI NGA;Lo;0;L;;;;;N;;;;; -189C;MONGOLIAN LETTER MANCHU ALI GALI CA;Lo;0;L;;;;;N;;;;; -189D;MONGOLIAN LETTER MANCHU ALI GALI JHA;Lo;0;L;;;;;N;;;;; -189E;MONGOLIAN LETTER MANCHU ALI GALI TTA;Lo;0;L;;;;;N;;;;; -189F;MONGOLIAN LETTER MANCHU ALI GALI DDHA;Lo;0;L;;;;;N;;;;; -18A0;MONGOLIAN LETTER MANCHU ALI GALI TA;Lo;0;L;;;;;N;;;;; -18A1;MONGOLIAN LETTER MANCHU ALI GALI DHA;Lo;0;L;;;;;N;;;;; -18A2;MONGOLIAN LETTER MANCHU ALI GALI SSA;Lo;0;L;;;;;N;;;;; -18A3;MONGOLIAN LETTER MANCHU ALI GALI CYA;Lo;0;L;;;;;N;;;;; -18A4;MONGOLIAN LETTER MANCHU ALI GALI ZHA;Lo;0;L;;;;;N;;;;; -18A5;MONGOLIAN LETTER MANCHU ALI GALI ZA;Lo;0;L;;;;;N;;;;; -18A6;MONGOLIAN LETTER ALI GALI HALF U;Lo;0;L;;;;;N;;;;; -18A7;MONGOLIAN LETTER ALI GALI HALF YA;Lo;0;L;;;;;N;;;;; -18A8;MONGOLIAN LETTER MANCHU ALI GALI BHA;Lo;0;L;;;;;N;;;;; -18A9;MONGOLIAN LETTER ALI GALI DAGALGA;Mn;228;NSM;;;;;N;;;;; -18AA;MONGOLIAN LETTER MANCHU ALI GALI LHA;Lo;0;L;;;;;N;;;;; -18B0;CANADIAN SYLLABICS OY;Lo;0;L;;;;;N;;;;; -18B1;CANADIAN SYLLABICS AY;Lo;0;L;;;;;N;;;;; -18B2;CANADIAN SYLLABICS AAY;Lo;0;L;;;;;N;;;;; -18B3;CANADIAN SYLLABICS WAY;Lo;0;L;;;;;N;;;;; -18B4;CANADIAN SYLLABICS POY;Lo;0;L;;;;;N;;;;; -18B5;CANADIAN SYLLABICS PAY;Lo;0;L;;;;;N;;;;; -18B6;CANADIAN SYLLABICS PWOY;Lo;0;L;;;;;N;;;;; -18B7;CANADIAN SYLLABICS TAY;Lo;0;L;;;;;N;;;;; -18B8;CANADIAN SYLLABICS KAY;Lo;0;L;;;;;N;;;;; -18B9;CANADIAN SYLLABICS KWAY;Lo;0;L;;;;;N;;;;; -18BA;CANADIAN SYLLABICS MAY;Lo;0;L;;;;;N;;;;; -18BB;CANADIAN SYLLABICS NOY;Lo;0;L;;;;;N;;;;; -18BC;CANADIAN SYLLABICS NAY;Lo;0;L;;;;;N;;;;; -18BD;CANADIAN SYLLABICS LAY;Lo;0;L;;;;;N;;;;; -18BE;CANADIAN SYLLABICS SOY;Lo;0;L;;;;;N;;;;; -18BF;CANADIAN SYLLABICS SAY;Lo;0;L;;;;;N;;;;; -18C0;CANADIAN SYLLABICS SHOY;Lo;0;L;;;;;N;;;;; -18C1;CANADIAN SYLLABICS SHAY;Lo;0;L;;;;;N;;;;; -18C2;CANADIAN SYLLABICS SHWOY;Lo;0;L;;;;;N;;;;; -18C3;CANADIAN SYLLABICS YOY;Lo;0;L;;;;;N;;;;; -18C4;CANADIAN SYLLABICS YAY;Lo;0;L;;;;;N;;;;; -18C5;CANADIAN SYLLABICS RAY;Lo;0;L;;;;;N;;;;; -18C6;CANADIAN SYLLABICS NWI;Lo;0;L;;;;;N;;;;; -18C7;CANADIAN SYLLABICS OJIBWAY NWI;Lo;0;L;;;;;N;;;;; -18C8;CANADIAN SYLLABICS NWII;Lo;0;L;;;;;N;;;;; -18C9;CANADIAN SYLLABICS OJIBWAY NWII;Lo;0;L;;;;;N;;;;; -18CA;CANADIAN SYLLABICS NWO;Lo;0;L;;;;;N;;;;; -18CB;CANADIAN SYLLABICS OJIBWAY NWO;Lo;0;L;;;;;N;;;;; -18CC;CANADIAN SYLLABICS NWOO;Lo;0;L;;;;;N;;;;; -18CD;CANADIAN SYLLABICS OJIBWAY NWOO;Lo;0;L;;;;;N;;;;; -18CE;CANADIAN SYLLABICS RWEE;Lo;0;L;;;;;N;;;;; -18CF;CANADIAN SYLLABICS RWI;Lo;0;L;;;;;N;;;;; -18D0;CANADIAN SYLLABICS RWII;Lo;0;L;;;;;N;;;;; -18D1;CANADIAN SYLLABICS RWO;Lo;0;L;;;;;N;;;;; -18D2;CANADIAN SYLLABICS RWOO;Lo;0;L;;;;;N;;;;; -18D3;CANADIAN SYLLABICS RWA;Lo;0;L;;;;;N;;;;; -18D4;CANADIAN SYLLABICS OJIBWAY P;Lo;0;L;;;;;N;;;;; -18D5;CANADIAN SYLLABICS OJIBWAY T;Lo;0;L;;;;;N;;;;; -18D6;CANADIAN SYLLABICS OJIBWAY K;Lo;0;L;;;;;N;;;;; -18D7;CANADIAN SYLLABICS OJIBWAY C;Lo;0;L;;;;;N;;;;; -18D8;CANADIAN SYLLABICS OJIBWAY M;Lo;0;L;;;;;N;;;;; -18D9;CANADIAN SYLLABICS OJIBWAY N;Lo;0;L;;;;;N;;;;; -18DA;CANADIAN SYLLABICS OJIBWAY S;Lo;0;L;;;;;N;;;;; -18DB;CANADIAN SYLLABICS OJIBWAY SH;Lo;0;L;;;;;N;;;;; -18DC;CANADIAN SYLLABICS EASTERN W;Lo;0;L;;;;;N;;;;; -18DD;CANADIAN SYLLABICS WESTERN W;Lo;0;L;;;;;N;;;;; -18DE;CANADIAN SYLLABICS FINAL SMALL RING;Lo;0;L;;;;;N;;;;; -18DF;CANADIAN SYLLABICS FINAL RAISED DOT;Lo;0;L;;;;;N;;;;; -18E0;CANADIAN SYLLABICS R-CREE RWE;Lo;0;L;;;;;N;;;;; -18E1;CANADIAN SYLLABICS WEST-CREE LOO;Lo;0;L;;;;;N;;;;; -18E2;CANADIAN SYLLABICS WEST-CREE LAA;Lo;0;L;;;;;N;;;;; -18E3;CANADIAN SYLLABICS THWE;Lo;0;L;;;;;N;;;;; -18E4;CANADIAN SYLLABICS THWA;Lo;0;L;;;;;N;;;;; -18E5;CANADIAN SYLLABICS TTHWE;Lo;0;L;;;;;N;;;;; -18E6;CANADIAN SYLLABICS TTHOO;Lo;0;L;;;;;N;;;;; -18E7;CANADIAN SYLLABICS TTHAA;Lo;0;L;;;;;N;;;;; -18E8;CANADIAN SYLLABICS TLHWE;Lo;0;L;;;;;N;;;;; -18E9;CANADIAN SYLLABICS TLHOO;Lo;0;L;;;;;N;;;;; -18EA;CANADIAN SYLLABICS SAYISI SHWE;Lo;0;L;;;;;N;;;;; -18EB;CANADIAN SYLLABICS SAYISI SHOO;Lo;0;L;;;;;N;;;;; -18EC;CANADIAN SYLLABICS SAYISI HOO;Lo;0;L;;;;;N;;;;; -18ED;CANADIAN SYLLABICS CARRIER GWU;Lo;0;L;;;;;N;;;;; -18EE;CANADIAN SYLLABICS CARRIER DENE GEE;Lo;0;L;;;;;N;;;;; -18EF;CANADIAN SYLLABICS CARRIER GAA;Lo;0;L;;;;;N;;;;; -18F0;CANADIAN SYLLABICS CARRIER GWA;Lo;0;L;;;;;N;;;;; -18F1;CANADIAN SYLLABICS SAYISI JUU;Lo;0;L;;;;;N;;;;; -18F2;CANADIAN SYLLABICS CARRIER JWA;Lo;0;L;;;;;N;;;;; -18F3;CANADIAN SYLLABICS BEAVER DENE L;Lo;0;L;;;;;N;;;;; -18F4;CANADIAN SYLLABICS BEAVER DENE R;Lo;0;L;;;;;N;;;;; -18F5;CANADIAN SYLLABICS CARRIER DENTAL S;Lo;0;L;;;;;N;;;;; -1900;LIMBU VOWEL-CARRIER LETTER;Lo;0;L;;;;;N;;;;; -1901;LIMBU LETTER KA;Lo;0;L;;;;;N;;;;; -1902;LIMBU LETTER KHA;Lo;0;L;;;;;N;;;;; -1903;LIMBU LETTER GA;Lo;0;L;;;;;N;;;;; -1904;LIMBU LETTER GHA;Lo;0;L;;;;;N;;;;; -1905;LIMBU LETTER NGA;Lo;0;L;;;;;N;;;;; -1906;LIMBU LETTER CA;Lo;0;L;;;;;N;;;;; -1907;LIMBU LETTER CHA;Lo;0;L;;;;;N;;;;; -1908;LIMBU LETTER JA;Lo;0;L;;;;;N;;;;; -1909;LIMBU LETTER JHA;Lo;0;L;;;;;N;;;;; -190A;LIMBU LETTER YAN;Lo;0;L;;;;;N;;;;; -190B;LIMBU LETTER TA;Lo;0;L;;;;;N;;;;; -190C;LIMBU LETTER THA;Lo;0;L;;;;;N;;;;; -190D;LIMBU LETTER DA;Lo;0;L;;;;;N;;;;; -190E;LIMBU LETTER DHA;Lo;0;L;;;;;N;;;;; -190F;LIMBU LETTER NA;Lo;0;L;;;;;N;;;;; -1910;LIMBU LETTER PA;Lo;0;L;;;;;N;;;;; -1911;LIMBU LETTER PHA;Lo;0;L;;;;;N;;;;; -1912;LIMBU LETTER BA;Lo;0;L;;;;;N;;;;; -1913;LIMBU LETTER BHA;Lo;0;L;;;;;N;;;;; -1914;LIMBU LETTER MA;Lo;0;L;;;;;N;;;;; -1915;LIMBU LETTER YA;Lo;0;L;;;;;N;;;;; -1916;LIMBU LETTER RA;Lo;0;L;;;;;N;;;;; -1917;LIMBU LETTER LA;Lo;0;L;;;;;N;;;;; -1918;LIMBU LETTER WA;Lo;0;L;;;;;N;;;;; -1919;LIMBU LETTER SHA;Lo;0;L;;;;;N;;;;; -191A;LIMBU LETTER SSA;Lo;0;L;;;;;N;;;;; -191B;LIMBU LETTER SA;Lo;0;L;;;;;N;;;;; -191C;LIMBU LETTER HA;Lo;0;L;;;;;N;;;;; -191D;LIMBU LETTER GYAN;Lo;0;L;;;;;N;;;;; -191E;LIMBU LETTER TRA;Lo;0;L;;;;;N;;;;; -1920;LIMBU VOWEL SIGN A;Mn;0;NSM;;;;;N;;;;; -1921;LIMBU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -1922;LIMBU VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -1923;LIMBU VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; -1924;LIMBU VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; -1925;LIMBU VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; -1926;LIMBU VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; -1927;LIMBU VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -1928;LIMBU VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; -1929;LIMBU SUBJOINED LETTER YA;Mc;0;L;;;;;N;;;;; -192A;LIMBU SUBJOINED LETTER RA;Mc;0;L;;;;;N;;;;; -192B;LIMBU SUBJOINED LETTER WA;Mc;0;L;;;;;N;;;;; -1930;LIMBU SMALL LETTER KA;Mc;0;L;;;;;N;;;;; -1931;LIMBU SMALL LETTER NGA;Mc;0;L;;;;;N;;;;; -1932;LIMBU SMALL LETTER ANUSVARA;Mn;0;NSM;;;;;N;;;;; -1933;LIMBU SMALL LETTER TA;Mc;0;L;;;;;N;;;;; -1934;LIMBU SMALL LETTER NA;Mc;0;L;;;;;N;;;;; -1935;LIMBU SMALL LETTER PA;Mc;0;L;;;;;N;;;;; -1936;LIMBU SMALL LETTER MA;Mc;0;L;;;;;N;;;;; -1937;LIMBU SMALL LETTER RA;Mc;0;L;;;;;N;;;;; -1938;LIMBU SMALL LETTER LA;Mc;0;L;;;;;N;;;;; -1939;LIMBU SIGN MUKPHRENG;Mn;222;NSM;;;;;N;;;;; -193A;LIMBU SIGN KEMPHRENG;Mn;230;NSM;;;;;N;;;;; -193B;LIMBU SIGN SA-I;Mn;220;NSM;;;;;N;;;;; -1940;LIMBU SIGN LOO;So;0;ON;;;;;N;;;;; -1944;LIMBU EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; -1945;LIMBU QUESTION MARK;Po;0;ON;;;;;N;;;;; -1946;LIMBU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -1947;LIMBU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -1948;LIMBU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -1949;LIMBU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -194A;LIMBU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -194B;LIMBU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -194C;LIMBU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -194D;LIMBU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -194E;LIMBU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -194F;LIMBU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -1950;TAI LE LETTER KA;Lo;0;L;;;;;N;;;;; -1951;TAI LE LETTER XA;Lo;0;L;;;;;N;;;;; -1952;TAI LE LETTER NGA;Lo;0;L;;;;;N;;;;; -1953;TAI LE LETTER TSA;Lo;0;L;;;;;N;;;;; -1954;TAI LE LETTER SA;Lo;0;L;;;;;N;;;;; -1955;TAI LE LETTER YA;Lo;0;L;;;;;N;;;;; -1956;TAI LE LETTER TA;Lo;0;L;;;;;N;;;;; -1957;TAI LE LETTER THA;Lo;0;L;;;;;N;;;;; -1958;TAI LE LETTER LA;Lo;0;L;;;;;N;;;;; -1959;TAI LE LETTER PA;Lo;0;L;;;;;N;;;;; -195A;TAI LE LETTER PHA;Lo;0;L;;;;;N;;;;; -195B;TAI LE LETTER MA;Lo;0;L;;;;;N;;;;; -195C;TAI LE LETTER FA;Lo;0;L;;;;;N;;;;; -195D;TAI LE LETTER VA;Lo;0;L;;;;;N;;;;; -195E;TAI LE LETTER HA;Lo;0;L;;;;;N;;;;; -195F;TAI LE LETTER QA;Lo;0;L;;;;;N;;;;; -1960;TAI LE LETTER KHA;Lo;0;L;;;;;N;;;;; -1961;TAI LE LETTER TSHA;Lo;0;L;;;;;N;;;;; -1962;TAI LE LETTER NA;Lo;0;L;;;;;N;;;;; -1963;TAI LE LETTER A;Lo;0;L;;;;;N;;;;; -1964;TAI LE LETTER I;Lo;0;L;;;;;N;;;;; -1965;TAI LE LETTER EE;Lo;0;L;;;;;N;;;;; -1966;TAI LE LETTER EH;Lo;0;L;;;;;N;;;;; -1967;TAI LE LETTER U;Lo;0;L;;;;;N;;;;; -1968;TAI LE LETTER OO;Lo;0;L;;;;;N;;;;; -1969;TAI LE LETTER O;Lo;0;L;;;;;N;;;;; -196A;TAI LE LETTER UE;Lo;0;L;;;;;N;;;;; -196B;TAI LE LETTER E;Lo;0;L;;;;;N;;;;; -196C;TAI LE LETTER AUE;Lo;0;L;;;;;N;;;;; -196D;TAI LE LETTER AI;Lo;0;L;;;;;N;;;;; -1970;TAI LE LETTER TONE-2;Lo;0;L;;;;;N;;;;; -1971;TAI LE LETTER TONE-3;Lo;0;L;;;;;N;;;;; -1972;TAI LE LETTER TONE-4;Lo;0;L;;;;;N;;;;; -1973;TAI LE LETTER TONE-5;Lo;0;L;;;;;N;;;;; -1974;TAI LE LETTER TONE-6;Lo;0;L;;;;;N;;;;; -1980;NEW TAI LUE LETTER HIGH QA;Lo;0;L;;;;;N;;;;; -1981;NEW TAI LUE LETTER LOW QA;Lo;0;L;;;;;N;;;;; -1982;NEW TAI LUE LETTER HIGH KA;Lo;0;L;;;;;N;;;;; -1983;NEW TAI LUE LETTER HIGH XA;Lo;0;L;;;;;N;;;;; -1984;NEW TAI LUE LETTER HIGH NGA;Lo;0;L;;;;;N;;;;; -1985;NEW TAI LUE LETTER LOW KA;Lo;0;L;;;;;N;;;;; -1986;NEW TAI LUE LETTER LOW XA;Lo;0;L;;;;;N;;;;; -1987;NEW TAI LUE LETTER LOW NGA;Lo;0;L;;;;;N;;;;; -1988;NEW TAI LUE LETTER HIGH TSA;Lo;0;L;;;;;N;;;;; -1989;NEW TAI LUE LETTER HIGH SA;Lo;0;L;;;;;N;;;;; -198A;NEW TAI LUE LETTER HIGH YA;Lo;0;L;;;;;N;;;;; -198B;NEW TAI LUE LETTER LOW TSA;Lo;0;L;;;;;N;;;;; -198C;NEW TAI LUE LETTER LOW SA;Lo;0;L;;;;;N;;;;; -198D;NEW TAI LUE LETTER LOW YA;Lo;0;L;;;;;N;;;;; -198E;NEW TAI LUE LETTER HIGH TA;Lo;0;L;;;;;N;;;;; -198F;NEW TAI LUE LETTER HIGH THA;Lo;0;L;;;;;N;;;;; -1990;NEW TAI LUE LETTER HIGH NA;Lo;0;L;;;;;N;;;;; -1991;NEW TAI LUE LETTER LOW TA;Lo;0;L;;;;;N;;;;; -1992;NEW TAI LUE LETTER LOW THA;Lo;0;L;;;;;N;;;;; -1993;NEW TAI LUE LETTER LOW NA;Lo;0;L;;;;;N;;;;; -1994;NEW TAI LUE LETTER HIGH PA;Lo;0;L;;;;;N;;;;; -1995;NEW TAI LUE LETTER HIGH PHA;Lo;0;L;;;;;N;;;;; -1996;NEW TAI LUE LETTER HIGH MA;Lo;0;L;;;;;N;;;;; -1997;NEW TAI LUE LETTER LOW PA;Lo;0;L;;;;;N;;;;; -1998;NEW TAI LUE LETTER LOW PHA;Lo;0;L;;;;;N;;;;; -1999;NEW TAI LUE LETTER LOW MA;Lo;0;L;;;;;N;;;;; -199A;NEW TAI LUE LETTER HIGH FA;Lo;0;L;;;;;N;;;;; -199B;NEW TAI LUE LETTER HIGH VA;Lo;0;L;;;;;N;;;;; -199C;NEW TAI LUE LETTER HIGH LA;Lo;0;L;;;;;N;;;;; -199D;NEW TAI LUE LETTER LOW FA;Lo;0;L;;;;;N;;;;; -199E;NEW TAI LUE LETTER LOW VA;Lo;0;L;;;;;N;;;;; -199F;NEW TAI LUE LETTER LOW LA;Lo;0;L;;;;;N;;;;; -19A0;NEW TAI LUE LETTER HIGH HA;Lo;0;L;;;;;N;;;;; -19A1;NEW TAI LUE LETTER HIGH DA;Lo;0;L;;;;;N;;;;; -19A2;NEW TAI LUE LETTER HIGH BA;Lo;0;L;;;;;N;;;;; -19A3;NEW TAI LUE LETTER LOW HA;Lo;0;L;;;;;N;;;;; -19A4;NEW TAI LUE LETTER LOW DA;Lo;0;L;;;;;N;;;;; -19A5;NEW TAI LUE LETTER LOW BA;Lo;0;L;;;;;N;;;;; -19A6;NEW TAI LUE LETTER HIGH KVA;Lo;0;L;;;;;N;;;;; -19A7;NEW TAI LUE LETTER HIGH XVA;Lo;0;L;;;;;N;;;;; -19A8;NEW TAI LUE LETTER LOW KVA;Lo;0;L;;;;;N;;;;; -19A9;NEW TAI LUE LETTER LOW XVA;Lo;0;L;;;;;N;;;;; -19AA;NEW TAI LUE LETTER HIGH SUA;Lo;0;L;;;;;N;;;;; -19AB;NEW TAI LUE LETTER LOW SUA;Lo;0;L;;;;;N;;;;; -19B0;NEW TAI LUE VOWEL SIGN VOWEL SHORTENER;Lo;0;L;;;;;N;;;;; -19B1;NEW TAI LUE VOWEL SIGN AA;Lo;0;L;;;;;N;;;;; -19B2;NEW TAI LUE VOWEL SIGN II;Lo;0;L;;;;;N;;;;; -19B3;NEW TAI LUE VOWEL SIGN U;Lo;0;L;;;;;N;;;;; -19B4;NEW TAI LUE VOWEL SIGN UU;Lo;0;L;;;;;N;;;;; -19B5;NEW TAI LUE VOWEL SIGN E;Lo;0;L;;;;;N;;;;; -19B6;NEW TAI LUE VOWEL SIGN AE;Lo;0;L;;;;;N;;;;; -19B7;NEW TAI LUE VOWEL SIGN O;Lo;0;L;;;;;N;;;;; -19B8;NEW TAI LUE VOWEL SIGN OA;Lo;0;L;;;;;N;;;;; -19B9;NEW TAI LUE VOWEL SIGN UE;Lo;0;L;;;;;N;;;;; -19BA;NEW TAI LUE VOWEL SIGN AY;Lo;0;L;;;;;N;;;;; -19BB;NEW TAI LUE VOWEL SIGN AAY;Lo;0;L;;;;;N;;;;; -19BC;NEW TAI LUE VOWEL SIGN UY;Lo;0;L;;;;;N;;;;; -19BD;NEW TAI LUE VOWEL SIGN OY;Lo;0;L;;;;;N;;;;; -19BE;NEW TAI LUE VOWEL SIGN OAY;Lo;0;L;;;;;N;;;;; -19BF;NEW TAI LUE VOWEL SIGN UEY;Lo;0;L;;;;;N;;;;; -19C0;NEW TAI LUE VOWEL SIGN IY;Lo;0;L;;;;;N;;;;; -19C1;NEW TAI LUE LETTER FINAL V;Lo;0;L;;;;;N;;;;; -19C2;NEW TAI LUE LETTER FINAL NG;Lo;0;L;;;;;N;;;;; -19C3;NEW TAI LUE LETTER FINAL N;Lo;0;L;;;;;N;;;;; -19C4;NEW TAI LUE LETTER FINAL M;Lo;0;L;;;;;N;;;;; -19C5;NEW TAI LUE LETTER FINAL K;Lo;0;L;;;;;N;;;;; -19C6;NEW TAI LUE LETTER FINAL D;Lo;0;L;;;;;N;;;;; -19C7;NEW TAI LUE LETTER FINAL B;Lo;0;L;;;;;N;;;;; -19C8;NEW TAI LUE TONE MARK-1;Lo;0;L;;;;;N;;;;; -19C9;NEW TAI LUE TONE MARK-2;Lo;0;L;;;;;N;;;;; -19D0;NEW TAI LUE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -19D1;NEW TAI LUE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -19D2;NEW TAI LUE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -19D3;NEW TAI LUE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -19D4;NEW TAI LUE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -19D5;NEW TAI LUE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -19D6;NEW TAI LUE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -19D7;NEW TAI LUE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -19D8;NEW TAI LUE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -19D9;NEW TAI LUE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -19DA;NEW TAI LUE THAM DIGIT ONE;No;0;L;;;1;1;N;;;;; -19DE;NEW TAI LUE SIGN LAE;So;0;ON;;;;;N;;;;; -19DF;NEW TAI LUE SIGN LAEV;So;0;ON;;;;;N;;;;; -19E0;KHMER SYMBOL PATHAMASAT;So;0;ON;;;;;N;;;;; -19E1;KHMER SYMBOL MUOY KOET;So;0;ON;;;;;N;;;;; -19E2;KHMER SYMBOL PII KOET;So;0;ON;;;;;N;;;;; -19E3;KHMER SYMBOL BEI KOET;So;0;ON;;;;;N;;;;; -19E4;KHMER SYMBOL BUON KOET;So;0;ON;;;;;N;;;;; -19E5;KHMER SYMBOL PRAM KOET;So;0;ON;;;;;N;;;;; -19E6;KHMER SYMBOL PRAM-MUOY KOET;So;0;ON;;;;;N;;;;; -19E7;KHMER SYMBOL PRAM-PII KOET;So;0;ON;;;;;N;;;;; -19E8;KHMER SYMBOL PRAM-BEI KOET;So;0;ON;;;;;N;;;;; -19E9;KHMER SYMBOL PRAM-BUON KOET;So;0;ON;;;;;N;;;;; -19EA;KHMER SYMBOL DAP KOET;So;0;ON;;;;;N;;;;; -19EB;KHMER SYMBOL DAP-MUOY KOET;So;0;ON;;;;;N;;;;; -19EC;KHMER SYMBOL DAP-PII KOET;So;0;ON;;;;;N;;;;; -19ED;KHMER SYMBOL DAP-BEI KOET;So;0;ON;;;;;N;;;;; -19EE;KHMER SYMBOL DAP-BUON KOET;So;0;ON;;;;;N;;;;; -19EF;KHMER SYMBOL DAP-PRAM KOET;So;0;ON;;;;;N;;;;; -19F0;KHMER SYMBOL TUTEYASAT;So;0;ON;;;;;N;;;;; -19F1;KHMER SYMBOL MUOY ROC;So;0;ON;;;;;N;;;;; -19F2;KHMER SYMBOL PII ROC;So;0;ON;;;;;N;;;;; -19F3;KHMER SYMBOL BEI ROC;So;0;ON;;;;;N;;;;; -19F4;KHMER SYMBOL BUON ROC;So;0;ON;;;;;N;;;;; -19F5;KHMER SYMBOL PRAM ROC;So;0;ON;;;;;N;;;;; -19F6;KHMER SYMBOL PRAM-MUOY ROC;So;0;ON;;;;;N;;;;; -19F7;KHMER SYMBOL PRAM-PII ROC;So;0;ON;;;;;N;;;;; -19F8;KHMER SYMBOL PRAM-BEI ROC;So;0;ON;;;;;N;;;;; -19F9;KHMER SYMBOL PRAM-BUON ROC;So;0;ON;;;;;N;;;;; -19FA;KHMER SYMBOL DAP ROC;So;0;ON;;;;;N;;;;; -19FB;KHMER SYMBOL DAP-MUOY ROC;So;0;ON;;;;;N;;;;; -19FC;KHMER SYMBOL DAP-PII ROC;So;0;ON;;;;;N;;;;; -19FD;KHMER SYMBOL DAP-BEI ROC;So;0;ON;;;;;N;;;;; -19FE;KHMER SYMBOL DAP-BUON ROC;So;0;ON;;;;;N;;;;; -19FF;KHMER SYMBOL DAP-PRAM ROC;So;0;ON;;;;;N;;;;; -1A00;BUGINESE LETTER KA;Lo;0;L;;;;;N;;;;; -1A01;BUGINESE LETTER GA;Lo;0;L;;;;;N;;;;; -1A02;BUGINESE LETTER NGA;Lo;0;L;;;;;N;;;;; -1A03;BUGINESE LETTER NGKA;Lo;0;L;;;;;N;;;;; -1A04;BUGINESE LETTER PA;Lo;0;L;;;;;N;;;;; -1A05;BUGINESE LETTER BA;Lo;0;L;;;;;N;;;;; -1A06;BUGINESE LETTER MA;Lo;0;L;;;;;N;;;;; -1A07;BUGINESE LETTER MPA;Lo;0;L;;;;;N;;;;; -1A08;BUGINESE LETTER TA;Lo;0;L;;;;;N;;;;; -1A09;BUGINESE LETTER DA;Lo;0;L;;;;;N;;;;; -1A0A;BUGINESE LETTER NA;Lo;0;L;;;;;N;;;;; -1A0B;BUGINESE LETTER NRA;Lo;0;L;;;;;N;;;;; -1A0C;BUGINESE LETTER CA;Lo;0;L;;;;;N;;;;; -1A0D;BUGINESE LETTER JA;Lo;0;L;;;;;N;;;;; -1A0E;BUGINESE LETTER NYA;Lo;0;L;;;;;N;;;;; -1A0F;BUGINESE LETTER NYCA;Lo;0;L;;;;;N;;;;; -1A10;BUGINESE LETTER YA;Lo;0;L;;;;;N;;;;; -1A11;BUGINESE LETTER RA;Lo;0;L;;;;;N;;;;; -1A12;BUGINESE LETTER LA;Lo;0;L;;;;;N;;;;; -1A13;BUGINESE LETTER VA;Lo;0;L;;;;;N;;;;; -1A14;BUGINESE LETTER SA;Lo;0;L;;;;;N;;;;; -1A15;BUGINESE LETTER A;Lo;0;L;;;;;N;;;;; -1A16;BUGINESE LETTER HA;Lo;0;L;;;;;N;;;;; -1A17;BUGINESE VOWEL SIGN I;Mn;230;NSM;;;;;N;;;;; -1A18;BUGINESE VOWEL SIGN U;Mn;220;NSM;;;;;N;;;;; -1A19;BUGINESE VOWEL SIGN E;Mc;0;L;;;;;N;;;;; -1A1A;BUGINESE VOWEL SIGN O;Mc;0;L;;;;;N;;;;; -1A1B;BUGINESE VOWEL SIGN AE;Mn;0;NSM;;;;;N;;;;; -1A1E;BUGINESE PALLAWA;Po;0;L;;;;;N;;;;; -1A1F;BUGINESE END OF SECTION;Po;0;L;;;;;N;;;;; -1A20;TAI THAM LETTER HIGH KA;Lo;0;L;;;;;N;;;;; -1A21;TAI THAM LETTER HIGH KHA;Lo;0;L;;;;;N;;;;; -1A22;TAI THAM LETTER HIGH KXA;Lo;0;L;;;;;N;;;;; -1A23;TAI THAM LETTER LOW KA;Lo;0;L;;;;;N;;;;; -1A24;TAI THAM LETTER LOW KXA;Lo;0;L;;;;;N;;;;; -1A25;TAI THAM LETTER LOW KHA;Lo;0;L;;;;;N;;;;; -1A26;TAI THAM LETTER NGA;Lo;0;L;;;;;N;;;;; -1A27;TAI THAM LETTER HIGH CA;Lo;0;L;;;;;N;;;;; -1A28;TAI THAM LETTER HIGH CHA;Lo;0;L;;;;;N;;;;; -1A29;TAI THAM LETTER LOW CA;Lo;0;L;;;;;N;;;;; -1A2A;TAI THAM LETTER LOW SA;Lo;0;L;;;;;N;;;;; -1A2B;TAI THAM LETTER LOW CHA;Lo;0;L;;;;;N;;;;; -1A2C;TAI THAM LETTER NYA;Lo;0;L;;;;;N;;;;; -1A2D;TAI THAM LETTER RATA;Lo;0;L;;;;;N;;;;; -1A2E;TAI THAM LETTER HIGH RATHA;Lo;0;L;;;;;N;;;;; -1A2F;TAI THAM LETTER DA;Lo;0;L;;;;;N;;;;; -1A30;TAI THAM LETTER LOW RATHA;Lo;0;L;;;;;N;;;;; -1A31;TAI THAM LETTER RANA;Lo;0;L;;;;;N;;;;; -1A32;TAI THAM LETTER HIGH TA;Lo;0;L;;;;;N;;;;; -1A33;TAI THAM LETTER HIGH THA;Lo;0;L;;;;;N;;;;; -1A34;TAI THAM LETTER LOW TA;Lo;0;L;;;;;N;;;;; -1A35;TAI THAM LETTER LOW THA;Lo;0;L;;;;;N;;;;; -1A36;TAI THAM LETTER NA;Lo;0;L;;;;;N;;;;; -1A37;TAI THAM LETTER BA;Lo;0;L;;;;;N;;;;; -1A38;TAI THAM LETTER HIGH PA;Lo;0;L;;;;;N;;;;; -1A39;TAI THAM LETTER HIGH PHA;Lo;0;L;;;;;N;;;;; -1A3A;TAI THAM LETTER HIGH FA;Lo;0;L;;;;;N;;;;; -1A3B;TAI THAM LETTER LOW PA;Lo;0;L;;;;;N;;;;; -1A3C;TAI THAM LETTER LOW FA;Lo;0;L;;;;;N;;;;; -1A3D;TAI THAM LETTER LOW PHA;Lo;0;L;;;;;N;;;;; -1A3E;TAI THAM LETTER MA;Lo;0;L;;;;;N;;;;; -1A3F;TAI THAM LETTER LOW YA;Lo;0;L;;;;;N;;;;; -1A40;TAI THAM LETTER HIGH YA;Lo;0;L;;;;;N;;;;; -1A41;TAI THAM LETTER RA;Lo;0;L;;;;;N;;;;; -1A42;TAI THAM LETTER RUE;Lo;0;L;;;;;N;;;;; -1A43;TAI THAM LETTER LA;Lo;0;L;;;;;N;;;;; -1A44;TAI THAM LETTER LUE;Lo;0;L;;;;;N;;;;; -1A45;TAI THAM LETTER WA;Lo;0;L;;;;;N;;;;; -1A46;TAI THAM LETTER HIGH SHA;Lo;0;L;;;;;N;;;;; -1A47;TAI THAM LETTER HIGH SSA;Lo;0;L;;;;;N;;;;; -1A48;TAI THAM LETTER HIGH SA;Lo;0;L;;;;;N;;;;; -1A49;TAI THAM LETTER HIGH HA;Lo;0;L;;;;;N;;;;; -1A4A;TAI THAM LETTER LLA;Lo;0;L;;;;;N;;;;; -1A4B;TAI THAM LETTER A;Lo;0;L;;;;;N;;;;; -1A4C;TAI THAM LETTER LOW HA;Lo;0;L;;;;;N;;;;; -1A4D;TAI THAM LETTER I;Lo;0;L;;;;;N;;;;; -1A4E;TAI THAM LETTER II;Lo;0;L;;;;;N;;;;; -1A4F;TAI THAM LETTER U;Lo;0;L;;;;;N;;;;; -1A50;TAI THAM LETTER UU;Lo;0;L;;;;;N;;;;; -1A51;TAI THAM LETTER EE;Lo;0;L;;;;;N;;;;; -1A52;TAI THAM LETTER OO;Lo;0;L;;;;;N;;;;; -1A53;TAI THAM LETTER LAE;Lo;0;L;;;;;N;;;;; -1A54;TAI THAM LETTER GREAT SA;Lo;0;L;;;;;N;;;;; -1A55;TAI THAM CONSONANT SIGN MEDIAL RA;Mc;0;L;;;;;N;;;;; -1A56;TAI THAM CONSONANT SIGN MEDIAL LA;Mn;0;NSM;;;;;N;;;;; -1A57;TAI THAM CONSONANT SIGN LA TANG LAI;Mc;0;L;;;;;N;;;;; -1A58;TAI THAM SIGN MAI KANG LAI;Mn;0;NSM;;;;;N;;;;; -1A59;TAI THAM CONSONANT SIGN FINAL NGA;Mn;0;NSM;;;;;N;;;;; -1A5A;TAI THAM CONSONANT SIGN LOW PA;Mn;0;NSM;;;;;N;;;;; -1A5B;TAI THAM CONSONANT SIGN HIGH RATHA OR LOW PA;Mn;0;NSM;;;;;N;;;;; -1A5C;TAI THAM CONSONANT SIGN MA;Mn;0;NSM;;;;;N;;;;; -1A5D;TAI THAM CONSONANT SIGN BA;Mn;0;NSM;;;;;N;;;;; -1A5E;TAI THAM CONSONANT SIGN SA;Mn;0;NSM;;;;;N;;;;; -1A60;TAI THAM SIGN SAKOT;Mn;9;NSM;;;;;N;;;;; -1A61;TAI THAM VOWEL SIGN A;Mc;0;L;;;;;N;;;;; -1A62;TAI THAM VOWEL SIGN MAI SAT;Mn;0;NSM;;;;;N;;;;; -1A63;TAI THAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -1A64;TAI THAM VOWEL SIGN TALL AA;Mc;0;L;;;;;N;;;;; -1A65;TAI THAM VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -1A66;TAI THAM VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; -1A67;TAI THAM VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;; -1A68;TAI THAM VOWEL SIGN UUE;Mn;0;NSM;;;;;N;;;;; -1A69;TAI THAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -1A6A;TAI THAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -1A6B;TAI THAM VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; -1A6C;TAI THAM VOWEL SIGN OA BELOW;Mn;0;NSM;;;;;N;;;;; -1A6D;TAI THAM VOWEL SIGN OY;Mc;0;L;;;;;N;;;;; -1A6E;TAI THAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;; -1A6F;TAI THAM VOWEL SIGN AE;Mc;0;L;;;;;N;;;;; -1A70;TAI THAM VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; -1A71;TAI THAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; -1A72;TAI THAM VOWEL SIGN THAM AI;Mc;0;L;;;;;N;;;;; -1A73;TAI THAM VOWEL SIGN OA ABOVE;Mn;0;NSM;;;;;N;;;;; -1A74;TAI THAM SIGN MAI KANG;Mn;0;NSM;;;;;N;;;;; -1A75;TAI THAM SIGN TONE-1;Mn;230;NSM;;;;;N;;;;; -1A76;TAI THAM SIGN TONE-2;Mn;230;NSM;;;;;N;;;;; -1A77;TAI THAM SIGN KHUEN TONE-3;Mn;230;NSM;;;;;N;;;;; -1A78;TAI THAM SIGN KHUEN TONE-4;Mn;230;NSM;;;;;N;;;;; -1A79;TAI THAM SIGN KHUEN TONE-5;Mn;230;NSM;;;;;N;;;;; -1A7A;TAI THAM SIGN RA HAAM;Mn;230;NSM;;;;;N;;;;; -1A7B;TAI THAM SIGN MAI SAM;Mn;230;NSM;;;;;N;;;;; -1A7C;TAI THAM SIGN KHUEN-LUE KARAN;Mn;230;NSM;;;;;N;;;;; -1A7F;TAI THAM COMBINING CRYPTOGRAMMIC DOT;Mn;220;NSM;;;;;N;;;;; -1A80;TAI THAM HORA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -1A81;TAI THAM HORA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -1A82;TAI THAM HORA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -1A83;TAI THAM HORA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -1A84;TAI THAM HORA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -1A85;TAI THAM HORA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -1A86;TAI THAM HORA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -1A87;TAI THAM HORA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -1A88;TAI THAM HORA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -1A89;TAI THAM HORA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -1A90;TAI THAM THAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -1A91;TAI THAM THAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -1A92;TAI THAM THAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -1A93;TAI THAM THAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -1A94;TAI THAM THAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -1A95;TAI THAM THAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -1A96;TAI THAM THAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -1A97;TAI THAM THAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -1A98;TAI THAM THAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -1A99;TAI THAM THAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -1AA0;TAI THAM SIGN WIANG;Po;0;L;;;;;N;;;;; -1AA1;TAI THAM SIGN WIANGWAAK;Po;0;L;;;;;N;;;;; -1AA2;TAI THAM SIGN SAWAN;Po;0;L;;;;;N;;;;; -1AA3;TAI THAM SIGN KEOW;Po;0;L;;;;;N;;;;; -1AA4;TAI THAM SIGN HOY;Po;0;L;;;;;N;;;;; -1AA5;TAI THAM SIGN DOKMAI;Po;0;L;;;;;N;;;;; -1AA6;TAI THAM SIGN REVERSED ROTATED RANA;Po;0;L;;;;;N;;;;; -1AA7;TAI THAM SIGN MAI YAMOK;Lm;0;L;;;;;N;;;;; -1AA8;TAI THAM SIGN KAAN;Po;0;L;;;;;N;;;;; -1AA9;TAI THAM SIGN KAANKUU;Po;0;L;;;;;N;;;;; -1AAA;TAI THAM SIGN SATKAAN;Po;0;L;;;;;N;;;;; -1AAB;TAI THAM SIGN SATKAANKUU;Po;0;L;;;;;N;;;;; -1AAC;TAI THAM SIGN HANG;Po;0;L;;;;;N;;;;; -1AAD;TAI THAM SIGN CAANG;Po;0;L;;;;;N;;;;; -1AB0;COMBINING DOUBLED CIRCUMFLEX ACCENT;Mn;230;NSM;;;;;N;;;;; -1AB1;COMBINING DIAERESIS-RING;Mn;230;NSM;;;;;N;;;;; -1AB2;COMBINING INFINITY;Mn;230;NSM;;;;;N;;;;; -1AB3;COMBINING DOWNWARDS ARROW;Mn;230;NSM;;;;;N;;;;; -1AB4;COMBINING TRIPLE DOT;Mn;230;NSM;;;;;N;;;;; -1AB5;COMBINING X-X BELOW;Mn;220;NSM;;;;;N;;;;; -1AB6;COMBINING WIGGLY LINE BELOW;Mn;220;NSM;;;;;N;;;;; -1AB7;COMBINING OPEN MARK BELOW;Mn;220;NSM;;;;;N;;;;; -1AB8;COMBINING DOUBLE OPEN MARK BELOW;Mn;220;NSM;;;;;N;;;;; -1AB9;COMBINING LIGHT CENTRALIZATION STROKE BELOW;Mn;220;NSM;;;;;N;;;;; -1ABA;COMBINING STRONG CENTRALIZATION STROKE BELOW;Mn;220;NSM;;;;;N;;;;; -1ABB;COMBINING PARENTHESES ABOVE;Mn;230;NSM;;;;;N;;;;; -1ABC;COMBINING DOUBLE PARENTHESES ABOVE;Mn;230;NSM;;;;;N;;;;; -1ABD;COMBINING PARENTHESES BELOW;Mn;220;NSM;;;;;N;;;;; -1ABE;COMBINING PARENTHESES OVERLAY;Me;0;NSM;;;;;N;;;;; -1ABF;COMBINING LATIN SMALL LETTER W BELOW;Mn;220;NSM;;;;;N;;;;; -1AC0;COMBINING LATIN SMALL LETTER TURNED W BELOW;Mn;220;NSM;;;;;N;;;;; -1AC1;COMBINING LEFT PARENTHESIS ABOVE LEFT;Mn;230;NSM;;;;;N;;;;; -1AC2;COMBINING RIGHT PARENTHESIS ABOVE RIGHT;Mn;230;NSM;;;;;N;;;;; -1AC3;COMBINING LEFT PARENTHESIS BELOW LEFT;Mn;220;NSM;;;;;N;;;;; -1AC4;COMBINING RIGHT PARENTHESIS BELOW RIGHT;Mn;220;NSM;;;;;N;;;;; -1AC5;COMBINING SQUARE BRACKETS ABOVE;Mn;230;NSM;;;;;N;;;;; -1AC6;COMBINING NUMBER SIGN ABOVE;Mn;230;NSM;;;;;N;;;;; -1AC7;COMBINING INVERTED DOUBLE ARCH ABOVE;Mn;230;NSM;;;;;N;;;;; -1AC8;COMBINING PLUS SIGN ABOVE;Mn;230;NSM;;;;;N;;;;; -1AC9;COMBINING DOUBLE PLUS SIGN ABOVE;Mn;230;NSM;;;;;N;;;;; -1ACA;COMBINING DOUBLE PLUS SIGN BELOW;Mn;220;NSM;;;;;N;;;;; -1ACB;COMBINING TRIPLE ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;; -1ACC;COMBINING LATIN SMALL LETTER INSULAR G;Mn;230;NSM;;;;;N;;;;; -1ACD;COMBINING LATIN SMALL LETTER INSULAR R;Mn;230;NSM;;;;;N;;;;; -1ACE;COMBINING LATIN SMALL LETTER INSULAR T;Mn;230;NSM;;;;;N;;;;; -1B00;BALINESE SIGN ULU RICEM;Mn;0;NSM;;;;;N;;;;; -1B01;BALINESE SIGN ULU CANDRA;Mn;0;NSM;;;;;N;;;;; -1B02;BALINESE SIGN CECEK;Mn;0;NSM;;;;;N;;;;; -1B03;BALINESE SIGN SURANG;Mn;0;NSM;;;;;N;;;;; -1B04;BALINESE SIGN BISAH;Mc;0;L;;;;;N;;;;; -1B05;BALINESE LETTER AKARA;Lo;0;L;;;;;N;;;;; -1B06;BALINESE LETTER AKARA TEDUNG;Lo;0;L;1B05 1B35;;;;N;;;;; -1B07;BALINESE LETTER IKARA;Lo;0;L;;;;;N;;;;; -1B08;BALINESE LETTER IKARA TEDUNG;Lo;0;L;1B07 1B35;;;;N;;;;; -1B09;BALINESE LETTER UKARA;Lo;0;L;;;;;N;;;;; -1B0A;BALINESE LETTER UKARA TEDUNG;Lo;0;L;1B09 1B35;;;;N;;;;; -1B0B;BALINESE LETTER RA REPA;Lo;0;L;;;;;N;;;;; -1B0C;BALINESE LETTER RA REPA TEDUNG;Lo;0;L;1B0B 1B35;;;;N;;;;; -1B0D;BALINESE LETTER LA LENGA;Lo;0;L;;;;;N;;;;; -1B0E;BALINESE LETTER LA LENGA TEDUNG;Lo;0;L;1B0D 1B35;;;;N;;;;; -1B0F;BALINESE LETTER EKARA;Lo;0;L;;;;;N;;;;; -1B10;BALINESE LETTER AIKARA;Lo;0;L;;;;;N;;;;; -1B11;BALINESE LETTER OKARA;Lo;0;L;;;;;N;;;;; -1B12;BALINESE LETTER OKARA TEDUNG;Lo;0;L;1B11 1B35;;;;N;;;;; -1B13;BALINESE LETTER KA;Lo;0;L;;;;;N;;;;; -1B14;BALINESE LETTER KA MAHAPRANA;Lo;0;L;;;;;N;;;;; -1B15;BALINESE LETTER GA;Lo;0;L;;;;;N;;;;; -1B16;BALINESE LETTER GA GORA;Lo;0;L;;;;;N;;;;; -1B17;BALINESE LETTER NGA;Lo;0;L;;;;;N;;;;; -1B18;BALINESE LETTER CA;Lo;0;L;;;;;N;;;;; -1B19;BALINESE LETTER CA LACA;Lo;0;L;;;;;N;;;;; -1B1A;BALINESE LETTER JA;Lo;0;L;;;;;N;;;;; -1B1B;BALINESE LETTER JA JERA;Lo;0;L;;;;;N;;;;; -1B1C;BALINESE LETTER NYA;Lo;0;L;;;;;N;;;;; -1B1D;BALINESE LETTER TA LATIK;Lo;0;L;;;;;N;;;;; -1B1E;BALINESE LETTER TA MURDA MAHAPRANA;Lo;0;L;;;;;N;;;;; -1B1F;BALINESE LETTER DA MURDA ALPAPRANA;Lo;0;L;;;;;N;;;;; -1B20;BALINESE LETTER DA MURDA MAHAPRANA;Lo;0;L;;;;;N;;;;; -1B21;BALINESE LETTER NA RAMBAT;Lo;0;L;;;;;N;;;;; -1B22;BALINESE LETTER TA;Lo;0;L;;;;;N;;;;; -1B23;BALINESE LETTER TA TAWA;Lo;0;L;;;;;N;;;;; -1B24;BALINESE LETTER DA;Lo;0;L;;;;;N;;;;; -1B25;BALINESE LETTER DA MADU;Lo;0;L;;;;;N;;;;; -1B26;BALINESE LETTER NA;Lo;0;L;;;;;N;;;;; -1B27;BALINESE LETTER PA;Lo;0;L;;;;;N;;;;; -1B28;BALINESE LETTER PA KAPAL;Lo;0;L;;;;;N;;;;; -1B29;BALINESE LETTER BA;Lo;0;L;;;;;N;;;;; -1B2A;BALINESE LETTER BA KEMBANG;Lo;0;L;;;;;N;;;;; -1B2B;BALINESE LETTER MA;Lo;0;L;;;;;N;;;;; -1B2C;BALINESE LETTER YA;Lo;0;L;;;;;N;;;;; -1B2D;BALINESE LETTER RA;Lo;0;L;;;;;N;;;;; -1B2E;BALINESE LETTER LA;Lo;0;L;;;;;N;;;;; -1B2F;BALINESE LETTER WA;Lo;0;L;;;;;N;;;;; -1B30;BALINESE LETTER SA SAGA;Lo;0;L;;;;;N;;;;; -1B31;BALINESE LETTER SA SAPA;Lo;0;L;;;;;N;;;;; -1B32;BALINESE LETTER SA;Lo;0;L;;;;;N;;;;; -1B33;BALINESE LETTER HA;Lo;0;L;;;;;N;;;;; -1B34;BALINESE SIGN REREKAN;Mn;7;NSM;;;;;N;;;;; -1B35;BALINESE VOWEL SIGN TEDUNG;Mc;0;L;;;;;N;;;;; -1B36;BALINESE VOWEL SIGN ULU;Mn;0;NSM;;;;;N;;;;; -1B37;BALINESE VOWEL SIGN ULU SARI;Mn;0;NSM;;;;;N;;;;; -1B38;BALINESE VOWEL SIGN SUKU;Mn;0;NSM;;;;;N;;;;; -1B39;BALINESE VOWEL SIGN SUKU ILUT;Mn;0;NSM;;;;;N;;;;; -1B3A;BALINESE VOWEL SIGN RA REPA;Mn;0;NSM;;;;;N;;;;; -1B3B;BALINESE VOWEL SIGN RA REPA TEDUNG;Mc;0;L;1B3A 1B35;;;;N;;;;; -1B3C;BALINESE VOWEL SIGN LA LENGA;Mn;0;NSM;;;;;N;;;;; -1B3D;BALINESE VOWEL SIGN LA LENGA TEDUNG;Mc;0;L;1B3C 1B35;;;;N;;;;; -1B3E;BALINESE VOWEL SIGN TALING;Mc;0;L;;;;;N;;;;; -1B3F;BALINESE VOWEL SIGN TALING REPA;Mc;0;L;;;;;N;;;;; -1B40;BALINESE VOWEL SIGN TALING TEDUNG;Mc;0;L;1B3E 1B35;;;;N;;;;; -1B41;BALINESE VOWEL SIGN TALING REPA TEDUNG;Mc;0;L;1B3F 1B35;;;;N;;;;; -1B42;BALINESE VOWEL SIGN PEPET;Mn;0;NSM;;;;;N;;;;; -1B43;BALINESE VOWEL SIGN PEPET TEDUNG;Mc;0;L;1B42 1B35;;;;N;;;;; -1B44;BALINESE ADEG ADEG;Mc;9;L;;;;;N;;;;; -1B45;BALINESE LETTER KAF SASAK;Lo;0;L;;;;;N;;;;; -1B46;BALINESE LETTER KHOT SASAK;Lo;0;L;;;;;N;;;;; -1B47;BALINESE LETTER TZIR SASAK;Lo;0;L;;;;;N;;;;; -1B48;BALINESE LETTER EF SASAK;Lo;0;L;;;;;N;;;;; -1B49;BALINESE LETTER VE SASAK;Lo;0;L;;;;;N;;;;; -1B4A;BALINESE LETTER ZAL SASAK;Lo;0;L;;;;;N;;;;; -1B4B;BALINESE LETTER ASYURA SASAK;Lo;0;L;;;;;N;;;;; -1B4C;BALINESE LETTER ARCHAIC JNYA;Lo;0;L;;;;;N;;;;; -1B50;BALINESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -1B51;BALINESE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -1B52;BALINESE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -1B53;BALINESE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -1B54;BALINESE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -1B55;BALINESE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -1B56;BALINESE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -1B57;BALINESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -1B58;BALINESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -1B59;BALINESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -1B5A;BALINESE PANTI;Po;0;L;;;;;N;;;;; -1B5B;BALINESE PAMADA;Po;0;L;;;;;N;;;;; -1B5C;BALINESE WINDU;Po;0;L;;;;;N;;;;; -1B5D;BALINESE CARIK PAMUNGKAH;Po;0;L;;;;;N;;;;; -1B5E;BALINESE CARIK SIKI;Po;0;L;;;;;N;;;;; -1B5F;BALINESE CARIK PAREREN;Po;0;L;;;;;N;;;;; -1B60;BALINESE PAMENENG;Po;0;L;;;;;N;;;;; -1B61;BALINESE MUSICAL SYMBOL DONG;So;0;L;;;;;N;;;;; -1B62;BALINESE MUSICAL SYMBOL DENG;So;0;L;;;;;N;;;;; -1B63;BALINESE MUSICAL SYMBOL DUNG;So;0;L;;;;;N;;;;; -1B64;BALINESE MUSICAL SYMBOL DANG;So;0;L;;;;;N;;;;; -1B65;BALINESE MUSICAL SYMBOL DANG SURANG;So;0;L;;;;;N;;;;; -1B66;BALINESE MUSICAL SYMBOL DING;So;0;L;;;;;N;;;;; -1B67;BALINESE MUSICAL SYMBOL DAENG;So;0;L;;;;;N;;;;; -1B68;BALINESE MUSICAL SYMBOL DEUNG;So;0;L;;;;;N;;;;; -1B69;BALINESE MUSICAL SYMBOL DAING;So;0;L;;;;;N;;;;; -1B6A;BALINESE MUSICAL SYMBOL DANG GEDE;So;0;L;;;;;N;;;;; -1B6B;BALINESE MUSICAL SYMBOL COMBINING TEGEH;Mn;230;NSM;;;;;N;;;;; -1B6C;BALINESE MUSICAL SYMBOL COMBINING ENDEP;Mn;220;NSM;;;;;N;;;;; -1B6D;BALINESE MUSICAL SYMBOL COMBINING KEMPUL;Mn;230;NSM;;;;;N;;;;; -1B6E;BALINESE MUSICAL SYMBOL COMBINING KEMPLI;Mn;230;NSM;;;;;N;;;;; -1B6F;BALINESE MUSICAL SYMBOL COMBINING JEGOGAN;Mn;230;NSM;;;;;N;;;;; -1B70;BALINESE MUSICAL SYMBOL COMBINING KEMPUL WITH JEGOGAN;Mn;230;NSM;;;;;N;;;;; -1B71;BALINESE MUSICAL SYMBOL COMBINING KEMPLI WITH JEGOGAN;Mn;230;NSM;;;;;N;;;;; -1B72;BALINESE MUSICAL SYMBOL COMBINING BENDE;Mn;230;NSM;;;;;N;;;;; -1B73;BALINESE MUSICAL SYMBOL COMBINING GONG;Mn;230;NSM;;;;;N;;;;; -1B74;BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG;So;0;L;;;;;N;;;;; -1B75;BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DAG;So;0;L;;;;;N;;;;; -1B76;BALINESE MUSICAL SYMBOL RIGHT-HAND CLOSED TUK;So;0;L;;;;;N;;;;; -1B77;BALINESE MUSICAL SYMBOL RIGHT-HAND CLOSED TAK;So;0;L;;;;;N;;;;; -1B78;BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PANG;So;0;L;;;;;N;;;;; -1B79;BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PUNG;So;0;L;;;;;N;;;;; -1B7A;BALINESE MUSICAL SYMBOL LEFT-HAND CLOSED PLAK;So;0;L;;;;;N;;;;; -1B7B;BALINESE MUSICAL SYMBOL LEFT-HAND CLOSED PLUK;So;0;L;;;;;N;;;;; -1B7C;BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING;So;0;L;;;;;N;;;;; -1B7D;BALINESE PANTI LANTANG;Po;0;L;;;;;N;;;;; -1B7E;BALINESE PAMADA LANTANG;Po;0;L;;;;;N;;;;; -1B80;SUNDANESE SIGN PANYECEK;Mn;0;NSM;;;;;N;;;;; -1B81;SUNDANESE SIGN PANGLAYAR;Mn;0;NSM;;;;;N;;;;; -1B82;SUNDANESE SIGN PANGWISAD;Mc;0;L;;;;;N;;;;; -1B83;SUNDANESE LETTER A;Lo;0;L;;;;;N;;;;; -1B84;SUNDANESE LETTER I;Lo;0;L;;;;;N;;;;; -1B85;SUNDANESE LETTER U;Lo;0;L;;;;;N;;;;; -1B86;SUNDANESE LETTER AE;Lo;0;L;;;;;N;;;;; -1B87;SUNDANESE LETTER O;Lo;0;L;;;;;N;;;;; -1B88;SUNDANESE LETTER E;Lo;0;L;;;;;N;;;;; -1B89;SUNDANESE LETTER EU;Lo;0;L;;;;;N;;;;; -1B8A;SUNDANESE LETTER KA;Lo;0;L;;;;;N;;;;; -1B8B;SUNDANESE LETTER QA;Lo;0;L;;;;;N;;;;; -1B8C;SUNDANESE LETTER GA;Lo;0;L;;;;;N;;;;; -1B8D;SUNDANESE LETTER NGA;Lo;0;L;;;;;N;;;;; -1B8E;SUNDANESE LETTER CA;Lo;0;L;;;;;N;;;;; -1B8F;SUNDANESE LETTER JA;Lo;0;L;;;;;N;;;;; -1B90;SUNDANESE LETTER ZA;Lo;0;L;;;;;N;;;;; -1B91;SUNDANESE LETTER NYA;Lo;0;L;;;;;N;;;;; -1B92;SUNDANESE LETTER TA;Lo;0;L;;;;;N;;;;; -1B93;SUNDANESE LETTER DA;Lo;0;L;;;;;N;;;;; -1B94;SUNDANESE LETTER NA;Lo;0;L;;;;;N;;;;; -1B95;SUNDANESE LETTER PA;Lo;0;L;;;;;N;;;;; -1B96;SUNDANESE LETTER FA;Lo;0;L;;;;;N;;;;; -1B97;SUNDANESE LETTER VA;Lo;0;L;;;;;N;;;;; -1B98;SUNDANESE LETTER BA;Lo;0;L;;;;;N;;;;; -1B99;SUNDANESE LETTER MA;Lo;0;L;;;;;N;;;;; -1B9A;SUNDANESE LETTER YA;Lo;0;L;;;;;N;;;;; -1B9B;SUNDANESE LETTER RA;Lo;0;L;;;;;N;;;;; -1B9C;SUNDANESE LETTER LA;Lo;0;L;;;;;N;;;;; -1B9D;SUNDANESE LETTER WA;Lo;0;L;;;;;N;;;;; -1B9E;SUNDANESE LETTER SA;Lo;0;L;;;;;N;;;;; -1B9F;SUNDANESE LETTER XA;Lo;0;L;;;;;N;;;;; -1BA0;SUNDANESE LETTER HA;Lo;0;L;;;;;N;;;;; -1BA1;SUNDANESE CONSONANT SIGN PAMINGKAL;Mc;0;L;;;;;N;;;;; -1BA2;SUNDANESE CONSONANT SIGN PANYAKRA;Mn;0;NSM;;;;;N;;;;; -1BA3;SUNDANESE CONSONANT SIGN PANYIKU;Mn;0;NSM;;;;;N;;;;; -1BA4;SUNDANESE VOWEL SIGN PANGHULU;Mn;0;NSM;;;;;N;;;;; -1BA5;SUNDANESE VOWEL SIGN PANYUKU;Mn;0;NSM;;;;;N;;;;; -1BA6;SUNDANESE VOWEL SIGN PANAELAENG;Mc;0;L;;;;;N;;;;; -1BA7;SUNDANESE VOWEL SIGN PANOLONG;Mc;0;L;;;;;N;;;;; -1BA8;SUNDANESE VOWEL SIGN PAMEPET;Mn;0;NSM;;;;;N;;;;; -1BA9;SUNDANESE VOWEL SIGN PANEULEUNG;Mn;0;NSM;;;;;N;;;;; -1BAA;SUNDANESE SIGN PAMAAEH;Mc;9;L;;;;;N;;;;; -1BAB;SUNDANESE SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -1BAC;SUNDANESE CONSONANT SIGN PASANGAN MA;Mn;0;NSM;;;;;N;;;;; -1BAD;SUNDANESE CONSONANT SIGN PASANGAN WA;Mn;0;NSM;;;;;N;;;;; -1BAE;SUNDANESE LETTER KHA;Lo;0;L;;;;;N;;;;; -1BAF;SUNDANESE LETTER SYA;Lo;0;L;;;;;N;;;;; -1BB0;SUNDANESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -1BB1;SUNDANESE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -1BB2;SUNDANESE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -1BB3;SUNDANESE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -1BB4;SUNDANESE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -1BB5;SUNDANESE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -1BB6;SUNDANESE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -1BB7;SUNDANESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -1BB8;SUNDANESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -1BB9;SUNDANESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -1BBA;SUNDANESE AVAGRAHA;Lo;0;L;;;;;N;;;;; -1BBB;SUNDANESE LETTER REU;Lo;0;L;;;;;N;;;;; -1BBC;SUNDANESE LETTER LEU;Lo;0;L;;;;;N;;;;; -1BBD;SUNDANESE LETTER BHA;Lo;0;L;;;;;N;;;;; -1BBE;SUNDANESE LETTER FINAL K;Lo;0;L;;;;;N;;;;; -1BBF;SUNDANESE LETTER FINAL M;Lo;0;L;;;;;N;;;;; -1BC0;BATAK LETTER A;Lo;0;L;;;;;N;;;;; -1BC1;BATAK LETTER SIMALUNGUN A;Lo;0;L;;;;;N;;;;; -1BC2;BATAK LETTER HA;Lo;0;L;;;;;N;;;;; -1BC3;BATAK LETTER SIMALUNGUN HA;Lo;0;L;;;;;N;;;;; -1BC4;BATAK LETTER MANDAILING HA;Lo;0;L;;;;;N;;;;; -1BC5;BATAK LETTER BA;Lo;0;L;;;;;N;;;;; -1BC6;BATAK LETTER KARO BA;Lo;0;L;;;;;N;;;;; -1BC7;BATAK LETTER PA;Lo;0;L;;;;;N;;;;; -1BC8;BATAK LETTER SIMALUNGUN PA;Lo;0;L;;;;;N;;;;; -1BC9;BATAK LETTER NA;Lo;0;L;;;;;N;;;;; -1BCA;BATAK LETTER MANDAILING NA;Lo;0;L;;;;;N;;;;; -1BCB;BATAK LETTER WA;Lo;0;L;;;;;N;;;;; -1BCC;BATAK LETTER SIMALUNGUN WA;Lo;0;L;;;;;N;;;;; -1BCD;BATAK LETTER PAKPAK WA;Lo;0;L;;;;;N;;;;; -1BCE;BATAK LETTER GA;Lo;0;L;;;;;N;;;;; -1BCF;BATAK LETTER SIMALUNGUN GA;Lo;0;L;;;;;N;;;;; -1BD0;BATAK LETTER JA;Lo;0;L;;;;;N;;;;; -1BD1;BATAK LETTER DA;Lo;0;L;;;;;N;;;;; -1BD2;BATAK LETTER RA;Lo;0;L;;;;;N;;;;; -1BD3;BATAK LETTER SIMALUNGUN RA;Lo;0;L;;;;;N;;;;; -1BD4;BATAK LETTER MA;Lo;0;L;;;;;N;;;;; -1BD5;BATAK LETTER SIMALUNGUN MA;Lo;0;L;;;;;N;;;;; -1BD6;BATAK LETTER SOUTHERN TA;Lo;0;L;;;;;N;;;;; -1BD7;BATAK LETTER NORTHERN TA;Lo;0;L;;;;;N;;;;; -1BD8;BATAK LETTER SA;Lo;0;L;;;;;N;;;;; -1BD9;BATAK LETTER SIMALUNGUN SA;Lo;0;L;;;;;N;;;;; -1BDA;BATAK LETTER MANDAILING SA;Lo;0;L;;;;;N;;;;; -1BDB;BATAK LETTER YA;Lo;0;L;;;;;N;;;;; -1BDC;BATAK LETTER SIMALUNGUN YA;Lo;0;L;;;;;N;;;;; -1BDD;BATAK LETTER NGA;Lo;0;L;;;;;N;;;;; -1BDE;BATAK LETTER LA;Lo;0;L;;;;;N;;;;; -1BDF;BATAK LETTER SIMALUNGUN LA;Lo;0;L;;;;;N;;;;; -1BE0;BATAK LETTER NYA;Lo;0;L;;;;;N;;;;; -1BE1;BATAK LETTER CA;Lo;0;L;;;;;N;;;;; -1BE2;BATAK LETTER NDA;Lo;0;L;;;;;N;;;;; -1BE3;BATAK LETTER MBA;Lo;0;L;;;;;N;;;;; -1BE4;BATAK LETTER I;Lo;0;L;;;;;N;;;;; -1BE5;BATAK LETTER U;Lo;0;L;;;;;N;;;;; -1BE6;BATAK SIGN TOMPI;Mn;7;NSM;;;;;N;;;;; -1BE7;BATAK VOWEL SIGN E;Mc;0;L;;;;;N;;;;; -1BE8;BATAK VOWEL SIGN PAKPAK E;Mn;0;NSM;;;;;N;;;;; -1BE9;BATAK VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;; -1BEA;BATAK VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -1BEB;BATAK VOWEL SIGN KARO I;Mc;0;L;;;;;N;;;;; -1BEC;BATAK VOWEL SIGN O;Mc;0;L;;;;;N;;;;; -1BED;BATAK VOWEL SIGN KARO O;Mn;0;NSM;;;;;N;;;;; -1BEE;BATAK VOWEL SIGN U;Mc;0;L;;;;;N;;;;; -1BEF;BATAK VOWEL SIGN U FOR SIMALUNGUN SA;Mn;0;NSM;;;;;N;;;;; -1BF0;BATAK CONSONANT SIGN NG;Mn;0;NSM;;;;;N;;;;; -1BF1;BATAK CONSONANT SIGN H;Mn;0;NSM;;;;;N;;;;; -1BF2;BATAK PANGOLAT;Mc;9;L;;;;;N;;;;; -1BF3;BATAK PANONGONAN;Mc;9;L;;;;;N;;;;; -1BFC;BATAK SYMBOL BINDU NA METEK;Po;0;L;;;;;N;;;;; -1BFD;BATAK SYMBOL BINDU PINARBORAS;Po;0;L;;;;;N;;;;; -1BFE;BATAK SYMBOL BINDU JUDUL;Po;0;L;;;;;N;;;;; -1BFF;BATAK SYMBOL BINDU PANGOLAT;Po;0;L;;;;;N;;;;; -1C00;LEPCHA LETTER KA;Lo;0;L;;;;;N;;;;; -1C01;LEPCHA LETTER KLA;Lo;0;L;;;;;N;;;;; -1C02;LEPCHA LETTER KHA;Lo;0;L;;;;;N;;;;; -1C03;LEPCHA LETTER GA;Lo;0;L;;;;;N;;;;; -1C04;LEPCHA LETTER GLA;Lo;0;L;;;;;N;;;;; -1C05;LEPCHA LETTER NGA;Lo;0;L;;;;;N;;;;; -1C06;LEPCHA LETTER CA;Lo;0;L;;;;;N;;;;; -1C07;LEPCHA LETTER CHA;Lo;0;L;;;;;N;;;;; -1C08;LEPCHA LETTER JA;Lo;0;L;;;;;N;;;;; -1C09;LEPCHA LETTER NYA;Lo;0;L;;;;;N;;;;; -1C0A;LEPCHA LETTER TA;Lo;0;L;;;;;N;;;;; -1C0B;LEPCHA LETTER THA;Lo;0;L;;;;;N;;;;; -1C0C;LEPCHA LETTER DA;Lo;0;L;;;;;N;;;;; -1C0D;LEPCHA LETTER NA;Lo;0;L;;;;;N;;;;; -1C0E;LEPCHA LETTER PA;Lo;0;L;;;;;N;;;;; -1C0F;LEPCHA LETTER PLA;Lo;0;L;;;;;N;;;;; -1C10;LEPCHA LETTER PHA;Lo;0;L;;;;;N;;;;; -1C11;LEPCHA LETTER FA;Lo;0;L;;;;;N;;;;; -1C12;LEPCHA LETTER FLA;Lo;0;L;;;;;N;;;;; -1C13;LEPCHA LETTER BA;Lo;0;L;;;;;N;;;;; -1C14;LEPCHA LETTER BLA;Lo;0;L;;;;;N;;;;; -1C15;LEPCHA LETTER MA;Lo;0;L;;;;;N;;;;; -1C16;LEPCHA LETTER MLA;Lo;0;L;;;;;N;;;;; -1C17;LEPCHA LETTER TSA;Lo;0;L;;;;;N;;;;; -1C18;LEPCHA LETTER TSHA;Lo;0;L;;;;;N;;;;; -1C19;LEPCHA LETTER DZA;Lo;0;L;;;;;N;;;;; -1C1A;LEPCHA LETTER YA;Lo;0;L;;;;;N;;;;; -1C1B;LEPCHA LETTER RA;Lo;0;L;;;;;N;;;;; -1C1C;LEPCHA LETTER LA;Lo;0;L;;;;;N;;;;; -1C1D;LEPCHA LETTER HA;Lo;0;L;;;;;N;;;;; -1C1E;LEPCHA LETTER HLA;Lo;0;L;;;;;N;;;;; -1C1F;LEPCHA LETTER VA;Lo;0;L;;;;;N;;;;; -1C20;LEPCHA LETTER SA;Lo;0;L;;;;;N;;;;; -1C21;LEPCHA LETTER SHA;Lo;0;L;;;;;N;;;;; -1C22;LEPCHA LETTER WA;Lo;0;L;;;;;N;;;;; -1C23;LEPCHA LETTER A;Lo;0;L;;;;;N;;;;; -1C24;LEPCHA SUBJOINED LETTER YA;Mc;0;L;;;;;N;;;;; -1C25;LEPCHA SUBJOINED LETTER RA;Mc;0;L;;;;;N;;;;; -1C26;LEPCHA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -1C27;LEPCHA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -1C28;LEPCHA VOWEL SIGN O;Mc;0;L;;;;;N;;;;; -1C29;LEPCHA VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; -1C2A;LEPCHA VOWEL SIGN U;Mc;0;L;;;;;N;;;;; -1C2B;LEPCHA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; -1C2C;LEPCHA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -1C2D;LEPCHA CONSONANT SIGN K;Mn;0;NSM;;;;;N;;;;; -1C2E;LEPCHA CONSONANT SIGN M;Mn;0;NSM;;;;;N;;;;; -1C2F;LEPCHA CONSONANT SIGN L;Mn;0;NSM;;;;;N;;;;; -1C30;LEPCHA CONSONANT SIGN N;Mn;0;NSM;;;;;N;;;;; -1C31;LEPCHA CONSONANT SIGN P;Mn;0;NSM;;;;;N;;;;; -1C32;LEPCHA CONSONANT SIGN R;Mn;0;NSM;;;;;N;;;;; -1C33;LEPCHA CONSONANT SIGN T;Mn;0;NSM;;;;;N;;;;; -1C34;LEPCHA CONSONANT SIGN NYIN-DO;Mc;0;L;;;;;N;;;;; -1C35;LEPCHA CONSONANT SIGN KANG;Mc;0;L;;;;;N;;;;; -1C36;LEPCHA SIGN RAN;Mn;0;NSM;;;;;N;;;;; -1C37;LEPCHA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -1C3B;LEPCHA PUNCTUATION TA-ROL;Po;0;L;;;;;N;;;;; -1C3C;LEPCHA PUNCTUATION NYET THYOOM TA-ROL;Po;0;L;;;;;N;;;;; -1C3D;LEPCHA PUNCTUATION CER-WA;Po;0;L;;;;;N;;;;; -1C3E;LEPCHA PUNCTUATION TSHOOK CER-WA;Po;0;L;;;;;N;;;;; -1C3F;LEPCHA PUNCTUATION TSHOOK;Po;0;L;;;;;N;;;;; -1C40;LEPCHA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -1C41;LEPCHA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -1C42;LEPCHA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -1C43;LEPCHA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -1C44;LEPCHA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -1C45;LEPCHA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -1C46;LEPCHA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -1C47;LEPCHA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -1C48;LEPCHA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -1C49;LEPCHA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -1C4D;LEPCHA LETTER TTA;Lo;0;L;;;;;N;;;;; -1C4E;LEPCHA LETTER TTHA;Lo;0;L;;;;;N;;;;; -1C4F;LEPCHA LETTER DDA;Lo;0;L;;;;;N;;;;; -1C50;OL CHIKI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -1C51;OL CHIKI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -1C52;OL CHIKI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -1C53;OL CHIKI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -1C54;OL CHIKI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -1C55;OL CHIKI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -1C56;OL CHIKI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -1C57;OL CHIKI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -1C58;OL CHIKI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -1C59;OL CHIKI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -1C5A;OL CHIKI LETTER LA;Lo;0;L;;;;;N;;;;; -1C5B;OL CHIKI LETTER AT;Lo;0;L;;;;;N;;;;; -1C5C;OL CHIKI LETTER AG;Lo;0;L;;;;;N;;;;; -1C5D;OL CHIKI LETTER ANG;Lo;0;L;;;;;N;;;;; -1C5E;OL CHIKI LETTER AL;Lo;0;L;;;;;N;;;;; -1C5F;OL CHIKI LETTER LAA;Lo;0;L;;;;;N;;;;; -1C60;OL CHIKI LETTER AAK;Lo;0;L;;;;;N;;;;; -1C61;OL CHIKI LETTER AAJ;Lo;0;L;;;;;N;;;;; -1C62;OL CHIKI LETTER AAM;Lo;0;L;;;;;N;;;;; -1C63;OL CHIKI LETTER AAW;Lo;0;L;;;;;N;;;;; -1C64;OL CHIKI LETTER LI;Lo;0;L;;;;;N;;;;; -1C65;OL CHIKI LETTER IS;Lo;0;L;;;;;N;;;;; -1C66;OL CHIKI LETTER IH;Lo;0;L;;;;;N;;;;; -1C67;OL CHIKI LETTER INY;Lo;0;L;;;;;N;;;;; -1C68;OL CHIKI LETTER IR;Lo;0;L;;;;;N;;;;; -1C69;OL CHIKI LETTER LU;Lo;0;L;;;;;N;;;;; -1C6A;OL CHIKI LETTER UC;Lo;0;L;;;;;N;;;;; -1C6B;OL CHIKI LETTER UD;Lo;0;L;;;;;N;;;;; -1C6C;OL CHIKI LETTER UNN;Lo;0;L;;;;;N;;;;; -1C6D;OL CHIKI LETTER UY;Lo;0;L;;;;;N;;;;; -1C6E;OL CHIKI LETTER LE;Lo;0;L;;;;;N;;;;; -1C6F;OL CHIKI LETTER EP;Lo;0;L;;;;;N;;;;; -1C70;OL CHIKI LETTER EDD;Lo;0;L;;;;;N;;;;; -1C71;OL CHIKI LETTER EN;Lo;0;L;;;;;N;;;;; -1C72;OL CHIKI LETTER ERR;Lo;0;L;;;;;N;;;;; -1C73;OL CHIKI LETTER LO;Lo;0;L;;;;;N;;;;; -1C74;OL CHIKI LETTER OTT;Lo;0;L;;;;;N;;;;; -1C75;OL CHIKI LETTER OB;Lo;0;L;;;;;N;;;;; -1C76;OL CHIKI LETTER OV;Lo;0;L;;;;;N;;;;; -1C77;OL CHIKI LETTER OH;Lo;0;L;;;;;N;;;;; -1C78;OL CHIKI MU TTUDDAG;Lm;0;L;;;;;N;;;;; -1C79;OL CHIKI GAAHLAA TTUDDAAG;Lm;0;L;;;;;N;;;;; -1C7A;OL CHIKI MU-GAAHLAA TTUDDAAG;Lm;0;L;;;;;N;;;;; -1C7B;OL CHIKI RELAA;Lm;0;L;;;;;N;;;;; -1C7C;OL CHIKI PHAARKAA;Lm;0;L;;;;;N;;;;; -1C7D;OL CHIKI AHAD;Lm;0;L;;;;;N;;;;; -1C7E;OL CHIKI PUNCTUATION MUCAAD;Po;0;L;;;;;N;;;;; -1C7F;OL CHIKI PUNCTUATION DOUBLE MUCAAD;Po;0;L;;;;;N;;;;; -1C80;CYRILLIC SMALL LETTER ROUNDED VE;Ll;0;L;;;;;N;;;0412;;0412 -1C81;CYRILLIC SMALL LETTER LONG-LEGGED DE;Ll;0;L;;;;;N;;;0414;;0414 -1C82;CYRILLIC SMALL LETTER NARROW O;Ll;0;L;;;;;N;;;041E;;041E -1C83;CYRILLIC SMALL LETTER WIDE ES;Ll;0;L;;;;;N;;;0421;;0421 -1C84;CYRILLIC SMALL LETTER TALL TE;Ll;0;L;;;;;N;;;0422;;0422 -1C85;CYRILLIC SMALL LETTER THREE-LEGGED TE;Ll;0;L;;;;;N;;;0422;;0422 -1C86;CYRILLIC SMALL LETTER TALL HARD SIGN;Ll;0;L;;;;;N;;;042A;;042A -1C87;CYRILLIC SMALL LETTER TALL YAT;Ll;0;L;;;;;N;;;0462;;0462 -1C88;CYRILLIC SMALL LETTER UNBLENDED UK;Ll;0;L;;;;;N;;;A64A;;A64A -1C90;GEORGIAN MTAVRULI CAPITAL LETTER AN;Lu;0;L;;;;;N;;;;10D0; -1C91;GEORGIAN MTAVRULI CAPITAL LETTER BAN;Lu;0;L;;;;;N;;;;10D1; -1C92;GEORGIAN MTAVRULI CAPITAL LETTER GAN;Lu;0;L;;;;;N;;;;10D2; -1C93;GEORGIAN MTAVRULI CAPITAL LETTER DON;Lu;0;L;;;;;N;;;;10D3; -1C94;GEORGIAN MTAVRULI CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;10D4; -1C95;GEORGIAN MTAVRULI CAPITAL LETTER VIN;Lu;0;L;;;;;N;;;;10D5; -1C96;GEORGIAN MTAVRULI CAPITAL LETTER ZEN;Lu;0;L;;;;;N;;;;10D6; -1C97;GEORGIAN MTAVRULI CAPITAL LETTER TAN;Lu;0;L;;;;;N;;;;10D7; -1C98;GEORGIAN MTAVRULI CAPITAL LETTER IN;Lu;0;L;;;;;N;;;;10D8; -1C99;GEORGIAN MTAVRULI CAPITAL LETTER KAN;Lu;0;L;;;;;N;;;;10D9; -1C9A;GEORGIAN MTAVRULI CAPITAL LETTER LAS;Lu;0;L;;;;;N;;;;10DA; -1C9B;GEORGIAN MTAVRULI CAPITAL LETTER MAN;Lu;0;L;;;;;N;;;;10DB; -1C9C;GEORGIAN MTAVRULI CAPITAL LETTER NAR;Lu;0;L;;;;;N;;;;10DC; -1C9D;GEORGIAN MTAVRULI CAPITAL LETTER ON;Lu;0;L;;;;;N;;;;10DD; -1C9E;GEORGIAN MTAVRULI CAPITAL LETTER PAR;Lu;0;L;;;;;N;;;;10DE; -1C9F;GEORGIAN MTAVRULI CAPITAL LETTER ZHAR;Lu;0;L;;;;;N;;;;10DF; -1CA0;GEORGIAN MTAVRULI CAPITAL LETTER RAE;Lu;0;L;;;;;N;;;;10E0; -1CA1;GEORGIAN MTAVRULI CAPITAL LETTER SAN;Lu;0;L;;;;;N;;;;10E1; -1CA2;GEORGIAN MTAVRULI CAPITAL LETTER TAR;Lu;0;L;;;;;N;;;;10E2; -1CA3;GEORGIAN MTAVRULI CAPITAL LETTER UN;Lu;0;L;;;;;N;;;;10E3; -1CA4;GEORGIAN MTAVRULI CAPITAL LETTER PHAR;Lu;0;L;;;;;N;;;;10E4; -1CA5;GEORGIAN MTAVRULI CAPITAL LETTER KHAR;Lu;0;L;;;;;N;;;;10E5; -1CA6;GEORGIAN MTAVRULI CAPITAL LETTER GHAN;Lu;0;L;;;;;N;;;;10E6; -1CA7;GEORGIAN MTAVRULI CAPITAL LETTER QAR;Lu;0;L;;;;;N;;;;10E7; -1CA8;GEORGIAN MTAVRULI CAPITAL LETTER SHIN;Lu;0;L;;;;;N;;;;10E8; -1CA9;GEORGIAN MTAVRULI CAPITAL LETTER CHIN;Lu;0;L;;;;;N;;;;10E9; -1CAA;GEORGIAN MTAVRULI CAPITAL LETTER CAN;Lu;0;L;;;;;N;;;;10EA; -1CAB;GEORGIAN MTAVRULI CAPITAL LETTER JIL;Lu;0;L;;;;;N;;;;10EB; -1CAC;GEORGIAN MTAVRULI CAPITAL LETTER CIL;Lu;0;L;;;;;N;;;;10EC; -1CAD;GEORGIAN MTAVRULI CAPITAL LETTER CHAR;Lu;0;L;;;;;N;;;;10ED; -1CAE;GEORGIAN MTAVRULI CAPITAL LETTER XAN;Lu;0;L;;;;;N;;;;10EE; -1CAF;GEORGIAN MTAVRULI CAPITAL LETTER JHAN;Lu;0;L;;;;;N;;;;10EF; -1CB0;GEORGIAN MTAVRULI CAPITAL LETTER HAE;Lu;0;L;;;;;N;;;;10F0; -1CB1;GEORGIAN MTAVRULI CAPITAL LETTER HE;Lu;0;L;;;;;N;;;;10F1; -1CB2;GEORGIAN MTAVRULI CAPITAL LETTER HIE;Lu;0;L;;;;;N;;;;10F2; -1CB3;GEORGIAN MTAVRULI CAPITAL LETTER WE;Lu;0;L;;;;;N;;;;10F3; -1CB4;GEORGIAN MTAVRULI CAPITAL LETTER HAR;Lu;0;L;;;;;N;;;;10F4; -1CB5;GEORGIAN MTAVRULI CAPITAL LETTER HOE;Lu;0;L;;;;;N;;;;10F5; -1CB6;GEORGIAN MTAVRULI CAPITAL LETTER FI;Lu;0;L;;;;;N;;;;10F6; -1CB7;GEORGIAN MTAVRULI CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;10F7; -1CB8;GEORGIAN MTAVRULI CAPITAL LETTER ELIFI;Lu;0;L;;;;;N;;;;10F8; -1CB9;GEORGIAN MTAVRULI CAPITAL LETTER TURNED GAN;Lu;0;L;;;;;N;;;;10F9; -1CBA;GEORGIAN MTAVRULI CAPITAL LETTER AIN;Lu;0;L;;;;;N;;;;10FA; -1CBD;GEORGIAN MTAVRULI CAPITAL LETTER AEN;Lu;0;L;;;;;N;;;;10FD; -1CBE;GEORGIAN MTAVRULI CAPITAL LETTER HARD SIGN;Lu;0;L;;;;;N;;;;10FE; -1CBF;GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN;Lu;0;L;;;;;N;;;;10FF; -1CC0;SUNDANESE PUNCTUATION BINDU SURYA;Po;0;L;;;;;N;;;;; -1CC1;SUNDANESE PUNCTUATION BINDU PANGLONG;Po;0;L;;;;;N;;;;; -1CC2;SUNDANESE PUNCTUATION BINDU PURNAMA;Po;0;L;;;;;N;;;;; -1CC3;SUNDANESE PUNCTUATION BINDU CAKRA;Po;0;L;;;;;N;;;;; -1CC4;SUNDANESE PUNCTUATION BINDU LEU SATANGA;Po;0;L;;;;;N;;;;; -1CC5;SUNDANESE PUNCTUATION BINDU KA SATANGA;Po;0;L;;;;;N;;;;; -1CC6;SUNDANESE PUNCTUATION BINDU DA SATANGA;Po;0;L;;;;;N;;;;; -1CC7;SUNDANESE PUNCTUATION BINDU BA SATANGA;Po;0;L;;;;;N;;;;; -1CD0;VEDIC TONE KARSHANA;Mn;230;NSM;;;;;N;;;;; -1CD1;VEDIC TONE SHARA;Mn;230;NSM;;;;;N;;;;; -1CD2;VEDIC TONE PRENKHA;Mn;230;NSM;;;;;N;;;;; -1CD3;VEDIC SIGN NIHSHVASA;Po;0;L;;;;;N;;;;; -1CD4;VEDIC SIGN YAJURVEDIC MIDLINE SVARITA;Mn;1;NSM;;;;;N;;;;; -1CD5;VEDIC TONE YAJURVEDIC AGGRAVATED INDEPENDENT SVARITA;Mn;220;NSM;;;;;N;;;;; -1CD6;VEDIC TONE YAJURVEDIC INDEPENDENT SVARITA;Mn;220;NSM;;;;;N;;;;; -1CD7;VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA;Mn;220;NSM;;;;;N;;;;; -1CD8;VEDIC TONE CANDRA BELOW;Mn;220;NSM;;;;;N;;;;; -1CD9;VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA SCHROEDER;Mn;220;NSM;;;;;N;;;;; -1CDA;VEDIC TONE DOUBLE SVARITA;Mn;230;NSM;;;;;N;;;;; -1CDB;VEDIC TONE TRIPLE SVARITA;Mn;230;NSM;;;;;N;;;;; -1CDC;VEDIC TONE KATHAKA ANUDATTA;Mn;220;NSM;;;;;N;;;;; -1CDD;VEDIC TONE DOT BELOW;Mn;220;NSM;;;;;N;;;;; -1CDE;VEDIC TONE TWO DOTS BELOW;Mn;220;NSM;;;;;N;;;;; -1CDF;VEDIC TONE THREE DOTS BELOW;Mn;220;NSM;;;;;N;;;;; -1CE0;VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA;Mn;230;NSM;;;;;N;;;;; -1CE1;VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA;Mc;0;L;;;;;N;;;;; -1CE2;VEDIC SIGN VISARGA SVARITA;Mn;1;NSM;;;;;N;;;;; -1CE3;VEDIC SIGN VISARGA UDATTA;Mn;1;NSM;;;;;N;;;;; -1CE4;VEDIC SIGN REVERSED VISARGA UDATTA;Mn;1;NSM;;;;;N;;;;; -1CE5;VEDIC SIGN VISARGA ANUDATTA;Mn;1;NSM;;;;;N;;;;; -1CE6;VEDIC SIGN REVERSED VISARGA ANUDATTA;Mn;1;NSM;;;;;N;;;;; -1CE7;VEDIC SIGN VISARGA UDATTA WITH TAIL;Mn;1;NSM;;;;;N;;;;; -1CE8;VEDIC SIGN VISARGA ANUDATTA WITH TAIL;Mn;1;NSM;;;;;N;;;;; -1CE9;VEDIC SIGN ANUSVARA ANTARGOMUKHA;Lo;0;L;;;;;N;;;;; -1CEA;VEDIC SIGN ANUSVARA BAHIRGOMUKHA;Lo;0;L;;;;;N;;;;; -1CEB;VEDIC SIGN ANUSVARA VAMAGOMUKHA;Lo;0;L;;;;;N;;;;; -1CEC;VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL;Lo;0;L;;;;;N;;;;; -1CED;VEDIC SIGN TIRYAK;Mn;220;NSM;;;;;N;;;;; -1CEE;VEDIC SIGN HEXIFORM LONG ANUSVARA;Lo;0;L;;;;;N;;;;; -1CEF;VEDIC SIGN LONG ANUSVARA;Lo;0;L;;;;;N;;;;; -1CF0;VEDIC SIGN RTHANG LONG ANUSVARA;Lo;0;L;;;;;N;;;;; -1CF1;VEDIC SIGN ANUSVARA UBHAYATO MUKHA;Lo;0;L;;;;;N;;;;; -1CF2;VEDIC SIGN ARDHAVISARGA;Lo;0;L;;;;;N;;;;; -1CF3;VEDIC SIGN ROTATED ARDHAVISARGA;Lo;0;L;;;;;N;;;;; -1CF4;VEDIC TONE CANDRA ABOVE;Mn;230;NSM;;;;;N;;;;; -1CF5;VEDIC SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; -1CF6;VEDIC SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; -1CF7;VEDIC SIGN ATIKRAMA;Mc;0;L;;;;;N;;;;; -1CF8;VEDIC TONE RING ABOVE;Mn;230;NSM;;;;;N;;;;; -1CF9;VEDIC TONE DOUBLE RING ABOVE;Mn;230;NSM;;;;;N;;;;; -1CFA;VEDIC SIGN DOUBLE ANUSVARA ANTARGOMUKHA;Lo;0;L;;;;;N;;;;; -1D00;LATIN LETTER SMALL CAPITAL A;Ll;0;L;;;;;N;;;;; -1D01;LATIN LETTER SMALL CAPITAL AE;Ll;0;L;;;;;N;;;;; -1D02;LATIN SMALL LETTER TURNED AE;Ll;0;L;;;;;N;;;;; -1D03;LATIN LETTER SMALL CAPITAL BARRED B;Ll;0;L;;;;;N;;;;; -1D04;LATIN LETTER SMALL CAPITAL C;Ll;0;L;;;;;N;;;;; -1D05;LATIN LETTER SMALL CAPITAL D;Ll;0;L;;;;;N;;;;; -1D06;LATIN LETTER SMALL CAPITAL ETH;Ll;0;L;;;;;N;;;;; -1D07;LATIN LETTER SMALL CAPITAL E;Ll;0;L;;;;;N;;;;; -1D08;LATIN SMALL LETTER TURNED OPEN E;Ll;0;L;;;;;N;;;;; -1D09;LATIN SMALL LETTER TURNED I;Ll;0;L;;;;;N;;;;; -1D0A;LATIN LETTER SMALL CAPITAL J;Ll;0;L;;;;;N;;;;; -1D0B;LATIN LETTER SMALL CAPITAL K;Ll;0;L;;;;;N;;;;; -1D0C;LATIN LETTER SMALL CAPITAL L WITH STROKE;Ll;0;L;;;;;N;;;;; -1D0D;LATIN LETTER SMALL CAPITAL M;Ll;0;L;;;;;N;;;;; -1D0E;LATIN LETTER SMALL CAPITAL REVERSED N;Ll;0;L;;;;;N;;;;; -1D0F;LATIN LETTER SMALL CAPITAL O;Ll;0;L;;;;;N;;;;; -1D10;LATIN LETTER SMALL CAPITAL OPEN O;Ll;0;L;;;;;N;;;;; -1D11;LATIN SMALL LETTER SIDEWAYS O;Ll;0;L;;;;;N;;;;; -1D12;LATIN SMALL LETTER SIDEWAYS OPEN O;Ll;0;L;;;;;N;;;;; -1D13;LATIN SMALL LETTER SIDEWAYS O WITH STROKE;Ll;0;L;;;;;N;;;;; -1D14;LATIN SMALL LETTER TURNED OE;Ll;0;L;;;;;N;;;;; -1D15;LATIN LETTER SMALL CAPITAL OU;Ll;0;L;;;;;N;;;;; -1D16;LATIN SMALL LETTER TOP HALF O;Ll;0;L;;;;;N;;;;; -1D17;LATIN SMALL LETTER BOTTOM HALF O;Ll;0;L;;;;;N;;;;; -1D18;LATIN LETTER SMALL CAPITAL P;Ll;0;L;;;;;N;;;;; -1D19;LATIN LETTER SMALL CAPITAL REVERSED R;Ll;0;L;;;;;N;;;;; -1D1A;LATIN LETTER SMALL CAPITAL TURNED R;Ll;0;L;;;;;N;;;;; -1D1B;LATIN LETTER SMALL CAPITAL T;Ll;0;L;;;;;N;;;;; -1D1C;LATIN LETTER SMALL CAPITAL U;Ll;0;L;;;;;N;;;;; -1D1D;LATIN SMALL LETTER SIDEWAYS U;Ll;0;L;;;;;N;;;;; -1D1E;LATIN SMALL LETTER SIDEWAYS DIAERESIZED U;Ll;0;L;;;;;N;;;;; -1D1F;LATIN SMALL LETTER SIDEWAYS TURNED M;Ll;0;L;;;;;N;;;;; -1D20;LATIN LETTER SMALL CAPITAL V;Ll;0;L;;;;;N;;;;; -1D21;LATIN LETTER SMALL CAPITAL W;Ll;0;L;;;;;N;;;;; -1D22;LATIN LETTER SMALL CAPITAL Z;Ll;0;L;;;;;N;;;;; -1D23;LATIN LETTER SMALL CAPITAL EZH;Ll;0;L;;;;;N;;;;; -1D24;LATIN LETTER VOICED LARYNGEAL SPIRANT;Ll;0;L;;;;;N;;;;; -1D25;LATIN LETTER AIN;Ll;0;L;;;;;N;;;;; -1D26;GREEK LETTER SMALL CAPITAL GAMMA;Ll;0;L;;;;;N;;;;; -1D27;GREEK LETTER SMALL CAPITAL LAMDA;Ll;0;L;;;;;N;;;;; -1D28;GREEK LETTER SMALL CAPITAL PI;Ll;0;L;;;;;N;;;;; -1D29;GREEK LETTER SMALL CAPITAL RHO;Ll;0;L;;;;;N;;;;; -1D2A;GREEK LETTER SMALL CAPITAL PSI;Ll;0;L;;;;;N;;;;; -1D2B;CYRILLIC LETTER SMALL CAPITAL EL;Ll;0;L;;;;;N;;;;; -1D2C;MODIFIER LETTER CAPITAL A;Lm;0;L;<super> 0041;;;;N;;;;; -1D2D;MODIFIER LETTER CAPITAL AE;Lm;0;L;<super> 00C6;;;;N;;;;; -1D2E;MODIFIER LETTER CAPITAL B;Lm;0;L;<super> 0042;;;;N;;;;; -1D2F;MODIFIER LETTER CAPITAL BARRED B;Lm;0;L;;;;;N;;;;; -1D30;MODIFIER LETTER CAPITAL D;Lm;0;L;<super> 0044;;;;N;;;;; -1D31;MODIFIER LETTER CAPITAL E;Lm;0;L;<super> 0045;;;;N;;;;; -1D32;MODIFIER LETTER CAPITAL REVERSED E;Lm;0;L;<super> 018E;;;;N;;;;; -1D33;MODIFIER LETTER CAPITAL G;Lm;0;L;<super> 0047;;;;N;;;;; -1D34;MODIFIER LETTER CAPITAL H;Lm;0;L;<super> 0048;;;;N;;;;; -1D35;MODIFIER LETTER CAPITAL I;Lm;0;L;<super> 0049;;;;N;;;;; -1D36;MODIFIER LETTER CAPITAL J;Lm;0;L;<super> 004A;;;;N;;;;; -1D37;MODIFIER LETTER CAPITAL K;Lm;0;L;<super> 004B;;;;N;;;;; -1D38;MODIFIER LETTER CAPITAL L;Lm;0;L;<super> 004C;;;;N;;;;; -1D39;MODIFIER LETTER CAPITAL M;Lm;0;L;<super> 004D;;;;N;;;;; -1D3A;MODIFIER LETTER CAPITAL N;Lm;0;L;<super> 004E;;;;N;;;;; -1D3B;MODIFIER LETTER CAPITAL REVERSED N;Lm;0;L;;;;;N;;;;; -1D3C;MODIFIER LETTER CAPITAL O;Lm;0;L;<super> 004F;;;;N;;;;; -1D3D;MODIFIER LETTER CAPITAL OU;Lm;0;L;<super> 0222;;;;N;;;;; -1D3E;MODIFIER LETTER CAPITAL P;Lm;0;L;<super> 0050;;;;N;;;;; -1D3F;MODIFIER LETTER CAPITAL R;Lm;0;L;<super> 0052;;;;N;;;;; -1D40;MODIFIER LETTER CAPITAL T;Lm;0;L;<super> 0054;;;;N;;;;; -1D41;MODIFIER LETTER CAPITAL U;Lm;0;L;<super> 0055;;;;N;;;;; -1D42;MODIFIER LETTER CAPITAL W;Lm;0;L;<super> 0057;;;;N;;;;; -1D43;MODIFIER LETTER SMALL A;Lm;0;L;<super> 0061;;;;N;;;;; -1D44;MODIFIER LETTER SMALL TURNED A;Lm;0;L;<super> 0250;;;;N;;;;; -1D45;MODIFIER LETTER SMALL ALPHA;Lm;0;L;<super> 0251;;;;N;;;;; -1D46;MODIFIER LETTER SMALL TURNED AE;Lm;0;L;<super> 1D02;;;;N;;;;; -1D47;MODIFIER LETTER SMALL B;Lm;0;L;<super> 0062;;;;N;;;;; -1D48;MODIFIER LETTER SMALL D;Lm;0;L;<super> 0064;;;;N;;;;; -1D49;MODIFIER LETTER SMALL E;Lm;0;L;<super> 0065;;;;N;;;;; -1D4A;MODIFIER LETTER SMALL SCHWA;Lm;0;L;<super> 0259;;;;N;;;;; -1D4B;MODIFIER LETTER SMALL OPEN E;Lm;0;L;<super> 025B;;;;N;;;;; -1D4C;MODIFIER LETTER SMALL TURNED OPEN E;Lm;0;L;<super> 025C;;;;N;;;;; -1D4D;MODIFIER LETTER SMALL G;Lm;0;L;<super> 0067;;;;N;;;;; -1D4E;MODIFIER LETTER SMALL TURNED I;Lm;0;L;;;;;N;;;;; -1D4F;MODIFIER LETTER SMALL K;Lm;0;L;<super> 006B;;;;N;;;;; -1D50;MODIFIER LETTER SMALL M;Lm;0;L;<super> 006D;;;;N;;;;; -1D51;MODIFIER LETTER SMALL ENG;Lm;0;L;<super> 014B;;;;N;;;;; -1D52;MODIFIER LETTER SMALL O;Lm;0;L;<super> 006F;;;;N;;;;; -1D53;MODIFIER LETTER SMALL OPEN O;Lm;0;L;<super> 0254;;;;N;;;;; -1D54;MODIFIER LETTER SMALL TOP HALF O;Lm;0;L;<super> 1D16;;;;N;;;;; -1D55;MODIFIER LETTER SMALL BOTTOM HALF O;Lm;0;L;<super> 1D17;;;;N;;;;; -1D56;MODIFIER LETTER SMALL P;Lm;0;L;<super> 0070;;;;N;;;;; -1D57;MODIFIER LETTER SMALL T;Lm;0;L;<super> 0074;;;;N;;;;; -1D58;MODIFIER LETTER SMALL U;Lm;0;L;<super> 0075;;;;N;;;;; -1D59;MODIFIER LETTER SMALL SIDEWAYS U;Lm;0;L;<super> 1D1D;;;;N;;;;; -1D5A;MODIFIER LETTER SMALL TURNED M;Lm;0;L;<super> 026F;;;;N;;;;; -1D5B;MODIFIER LETTER SMALL V;Lm;0;L;<super> 0076;;;;N;;;;; -1D5C;MODIFIER LETTER SMALL AIN;Lm;0;L;<super> 1D25;;;;N;;;;; -1D5D;MODIFIER LETTER SMALL BETA;Lm;0;L;<super> 03B2;;;;N;;;;; -1D5E;MODIFIER LETTER SMALL GREEK GAMMA;Lm;0;L;<super> 03B3;;;;N;;;;; -1D5F;MODIFIER LETTER SMALL DELTA;Lm;0;L;<super> 03B4;;;;N;;;;; -1D60;MODIFIER LETTER SMALL GREEK PHI;Lm;0;L;<super> 03C6;;;;N;;;;; -1D61;MODIFIER LETTER SMALL CHI;Lm;0;L;<super> 03C7;;;;N;;;;; -1D62;LATIN SUBSCRIPT SMALL LETTER I;Lm;0;L;<sub> 0069;;;;N;;;;; -1D63;LATIN SUBSCRIPT SMALL LETTER R;Lm;0;L;<sub> 0072;;;;N;;;;; -1D64;LATIN SUBSCRIPT SMALL LETTER U;Lm;0;L;<sub> 0075;;;;N;;;;; -1D65;LATIN SUBSCRIPT SMALL LETTER V;Lm;0;L;<sub> 0076;;;;N;;;;; -1D66;GREEK SUBSCRIPT SMALL LETTER BETA;Lm;0;L;<sub> 03B2;;;;N;;;;; -1D67;GREEK SUBSCRIPT SMALL LETTER GAMMA;Lm;0;L;<sub> 03B3;;;;N;;;;; -1D68;GREEK SUBSCRIPT SMALL LETTER RHO;Lm;0;L;<sub> 03C1;;;;N;;;;; -1D69;GREEK SUBSCRIPT SMALL LETTER PHI;Lm;0;L;<sub> 03C6;;;;N;;;;; -1D6A;GREEK SUBSCRIPT SMALL LETTER CHI;Lm;0;L;<sub> 03C7;;;;N;;;;; -1D6B;LATIN SMALL LETTER UE;Ll;0;L;;;;;N;;;;; -1D6C;LATIN SMALL LETTER B WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; -1D6D;LATIN SMALL LETTER D WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; -1D6E;LATIN SMALL LETTER F WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; -1D6F;LATIN SMALL LETTER M WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; -1D70;LATIN SMALL LETTER N WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; -1D71;LATIN SMALL LETTER P WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; -1D72;LATIN SMALL LETTER R WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; -1D73;LATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TILDE;Ll;0;L;;;;;N;;;;; -1D74;LATIN SMALL LETTER S WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; -1D75;LATIN SMALL LETTER T WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; -1D76;LATIN SMALL LETTER Z WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; -1D77;LATIN SMALL LETTER TURNED G;Ll;0;L;;;;;N;;;;; -1D78;MODIFIER LETTER CYRILLIC EN;Lm;0;L;<super> 043D;;;;N;;;;; -1D79;LATIN SMALL LETTER INSULAR G;Ll;0;L;;;;;N;;;A77D;;A77D -1D7A;LATIN SMALL LETTER TH WITH STRIKETHROUGH;Ll;0;L;;;;;N;;;;; -1D7B;LATIN SMALL CAPITAL LETTER I WITH STROKE;Ll;0;L;;;;;N;;;;; -1D7C;LATIN SMALL LETTER IOTA WITH STROKE;Ll;0;L;;;;;N;;;;; -1D7D;LATIN SMALL LETTER P WITH STROKE;Ll;0;L;;;;;N;;;2C63;;2C63 -1D7E;LATIN SMALL CAPITAL LETTER U WITH STROKE;Ll;0;L;;;;;N;;;;; -1D7F;LATIN SMALL LETTER UPSILON WITH STROKE;Ll;0;L;;;;;N;;;;; -1D80;LATIN SMALL LETTER B WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1D81;LATIN SMALL LETTER D WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1D82;LATIN SMALL LETTER F WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1D83;LATIN SMALL LETTER G WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1D84;LATIN SMALL LETTER K WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1D85;LATIN SMALL LETTER L WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1D86;LATIN SMALL LETTER M WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1D87;LATIN SMALL LETTER N WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1D88;LATIN SMALL LETTER P WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1D89;LATIN SMALL LETTER R WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1D8A;LATIN SMALL LETTER S WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1D8B;LATIN SMALL LETTER ESH WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1D8C;LATIN SMALL LETTER V WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1D8D;LATIN SMALL LETTER X WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1D8E;LATIN SMALL LETTER Z WITH PALATAL HOOK;Ll;0;L;;;;;N;;;A7C6;;A7C6 -1D8F;LATIN SMALL LETTER A WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -1D90;LATIN SMALL LETTER ALPHA WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -1D91;LATIN SMALL LETTER D WITH HOOK AND TAIL;Ll;0;L;;;;;N;;;;; -1D92;LATIN SMALL LETTER E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -1D93;LATIN SMALL LETTER OPEN E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -1D94;LATIN SMALL LETTER REVERSED OPEN E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -1D95;LATIN SMALL LETTER SCHWA WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -1D96;LATIN SMALL LETTER I WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -1D97;LATIN SMALL LETTER OPEN O WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -1D98;LATIN SMALL LETTER ESH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -1D99;LATIN SMALL LETTER U WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -1D9A;LATIN SMALL LETTER EZH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -1D9B;MODIFIER LETTER SMALL TURNED ALPHA;Lm;0;L;<super> 0252;;;;N;;;;; -1D9C;MODIFIER LETTER SMALL C;Lm;0;L;<super> 0063;;;;N;;;;; -1D9D;MODIFIER LETTER SMALL C WITH CURL;Lm;0;L;<super> 0255;;;;N;;;;; -1D9E;MODIFIER LETTER SMALL ETH;Lm;0;L;<super> 00F0;;;;N;;;;; -1D9F;MODIFIER LETTER SMALL REVERSED OPEN E;Lm;0;L;<super> 025C;;;;N;;;;; -1DA0;MODIFIER LETTER SMALL F;Lm;0;L;<super> 0066;;;;N;;;;; -1DA1;MODIFIER LETTER SMALL DOTLESS J WITH STROKE;Lm;0;L;<super> 025F;;;;N;;;;; -1DA2;MODIFIER LETTER SMALL SCRIPT G;Lm;0;L;<super> 0261;;;;N;;;;; -1DA3;MODIFIER LETTER SMALL TURNED H;Lm;0;L;<super> 0265;;;;N;;;;; -1DA4;MODIFIER LETTER SMALL I WITH STROKE;Lm;0;L;<super> 0268;;;;N;;;;; -1DA5;MODIFIER LETTER SMALL IOTA;Lm;0;L;<super> 0269;;;;N;;;;; -1DA6;MODIFIER LETTER SMALL CAPITAL I;Lm;0;L;<super> 026A;;;;N;;;;; -1DA7;MODIFIER LETTER SMALL CAPITAL I WITH STROKE;Lm;0;L;<super> 1D7B;;;;N;;;;; -1DA8;MODIFIER LETTER SMALL J WITH CROSSED-TAIL;Lm;0;L;<super> 029D;;;;N;;;;; -1DA9;MODIFIER LETTER SMALL L WITH RETROFLEX HOOK;Lm;0;L;<super> 026D;;;;N;;;;; -1DAA;MODIFIER LETTER SMALL L WITH PALATAL HOOK;Lm;0;L;<super> 1D85;;;;N;;;;; -1DAB;MODIFIER LETTER SMALL CAPITAL L;Lm;0;L;<super> 029F;;;;N;;;;; -1DAC;MODIFIER LETTER SMALL M WITH HOOK;Lm;0;L;<super> 0271;;;;N;;;;; -1DAD;MODIFIER LETTER SMALL TURNED M WITH LONG LEG;Lm;0;L;<super> 0270;;;;N;;;;; -1DAE;MODIFIER LETTER SMALL N WITH LEFT HOOK;Lm;0;L;<super> 0272;;;;N;;;;; -1DAF;MODIFIER LETTER SMALL N WITH RETROFLEX HOOK;Lm;0;L;<super> 0273;;;;N;;;;; -1DB0;MODIFIER LETTER SMALL CAPITAL N;Lm;0;L;<super> 0274;;;;N;;;;; -1DB1;MODIFIER LETTER SMALL BARRED O;Lm;0;L;<super> 0275;;;;N;;;;; -1DB2;MODIFIER LETTER SMALL PHI;Lm;0;L;<super> 0278;;;;N;;;;; -1DB3;MODIFIER LETTER SMALL S WITH HOOK;Lm;0;L;<super> 0282;;;;N;;;;; -1DB4;MODIFIER LETTER SMALL ESH;Lm;0;L;<super> 0283;;;;N;;;;; -1DB5;MODIFIER LETTER SMALL T WITH PALATAL HOOK;Lm;0;L;<super> 01AB;;;;N;;;;; -1DB6;MODIFIER LETTER SMALL U BAR;Lm;0;L;<super> 0289;;;;N;;;;; -1DB7;MODIFIER LETTER SMALL UPSILON;Lm;0;L;<super> 028A;;;;N;;;;; -1DB8;MODIFIER LETTER SMALL CAPITAL U;Lm;0;L;<super> 1D1C;;;;N;;;;; -1DB9;MODIFIER LETTER SMALL V WITH HOOK;Lm;0;L;<super> 028B;;;;N;;;;; -1DBA;MODIFIER LETTER SMALL TURNED V;Lm;0;L;<super> 028C;;;;N;;;;; -1DBB;MODIFIER LETTER SMALL Z;Lm;0;L;<super> 007A;;;;N;;;;; -1DBC;MODIFIER LETTER SMALL Z WITH RETROFLEX HOOK;Lm;0;L;<super> 0290;;;;N;;;;; -1DBD;MODIFIER LETTER SMALL Z WITH CURL;Lm;0;L;<super> 0291;;;;N;;;;; -1DBE;MODIFIER LETTER SMALL EZH;Lm;0;L;<super> 0292;;;;N;;;;; -1DBF;MODIFIER LETTER SMALL THETA;Lm;0;L;<super> 03B8;;;;N;;;;; -1DC0;COMBINING DOTTED GRAVE ACCENT;Mn;230;NSM;;;;;N;;;;; -1DC1;COMBINING DOTTED ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;; -1DC2;COMBINING SNAKE BELOW;Mn;220;NSM;;;;;N;;;;; -1DC3;COMBINING SUSPENSION MARK;Mn;230;NSM;;;;;N;;;;; -1DC4;COMBINING MACRON-ACUTE;Mn;230;NSM;;;;;N;;;;; -1DC5;COMBINING GRAVE-MACRON;Mn;230;NSM;;;;;N;;;;; -1DC6;COMBINING MACRON-GRAVE;Mn;230;NSM;;;;;N;;;;; -1DC7;COMBINING ACUTE-MACRON;Mn;230;NSM;;;;;N;;;;; -1DC8;COMBINING GRAVE-ACUTE-GRAVE;Mn;230;NSM;;;;;N;;;;; -1DC9;COMBINING ACUTE-GRAVE-ACUTE;Mn;230;NSM;;;;;N;;;;; -1DCA;COMBINING LATIN SMALL LETTER R BELOW;Mn;220;NSM;;;;;N;;;;; -1DCB;COMBINING BREVE-MACRON;Mn;230;NSM;;;;;N;;;;; -1DCC;COMBINING MACRON-BREVE;Mn;230;NSM;;;;;N;;;;; -1DCD;COMBINING DOUBLE CIRCUMFLEX ABOVE;Mn;234;NSM;;;;;N;;;;; -1DCE;COMBINING OGONEK ABOVE;Mn;214;NSM;;;;;N;;;;; -1DCF;COMBINING ZIGZAG BELOW;Mn;220;NSM;;;;;N;;;;; -1DD0;COMBINING IS BELOW;Mn;202;NSM;;;;;N;;;;; -1DD1;COMBINING UR ABOVE;Mn;230;NSM;;;;;N;;;;; -1DD2;COMBINING US ABOVE;Mn;230;NSM;;;;;N;;;;; -1DD3;COMBINING LATIN SMALL LETTER FLATTENED OPEN A ABOVE;Mn;230;NSM;;;;;N;;;;; -1DD4;COMBINING LATIN SMALL LETTER AE;Mn;230;NSM;;;;;N;;;;; -1DD5;COMBINING LATIN SMALL LETTER AO;Mn;230;NSM;;;;;N;;;;; -1DD6;COMBINING LATIN SMALL LETTER AV;Mn;230;NSM;;;;;N;;;;; -1DD7;COMBINING LATIN SMALL LETTER C CEDILLA;Mn;230;NSM;;;;;N;;;;; -1DD8;COMBINING LATIN SMALL LETTER INSULAR D;Mn;230;NSM;;;;;N;;;;; -1DD9;COMBINING LATIN SMALL LETTER ETH;Mn;230;NSM;;;;;N;;;;; -1DDA;COMBINING LATIN SMALL LETTER G;Mn;230;NSM;;;;;N;;;;; -1DDB;COMBINING LATIN LETTER SMALL CAPITAL G;Mn;230;NSM;;;;;N;;;;; -1DDC;COMBINING LATIN SMALL LETTER K;Mn;230;NSM;;;;;N;;;;; -1DDD;COMBINING LATIN SMALL LETTER L;Mn;230;NSM;;;;;N;;;;; -1DDE;COMBINING LATIN LETTER SMALL CAPITAL L;Mn;230;NSM;;;;;N;;;;; -1DDF;COMBINING LATIN LETTER SMALL CAPITAL M;Mn;230;NSM;;;;;N;;;;; -1DE0;COMBINING LATIN SMALL LETTER N;Mn;230;NSM;;;;;N;;;;; -1DE1;COMBINING LATIN LETTER SMALL CAPITAL N;Mn;230;NSM;;;;;N;;;;; -1DE2;COMBINING LATIN LETTER SMALL CAPITAL R;Mn;230;NSM;;;;;N;;;;; -1DE3;COMBINING LATIN SMALL LETTER R ROTUNDA;Mn;230;NSM;;;;;N;;;;; -1DE4;COMBINING LATIN SMALL LETTER S;Mn;230;NSM;;;;;N;;;;; -1DE5;COMBINING LATIN SMALL LETTER LONG S;Mn;230;NSM;;;;;N;;;;; -1DE6;COMBINING LATIN SMALL LETTER Z;Mn;230;NSM;;;;;N;;;;; -1DE7;COMBINING LATIN SMALL LETTER ALPHA;Mn;230;NSM;;;;;N;;;;; -1DE8;COMBINING LATIN SMALL LETTER B;Mn;230;NSM;;;;;N;;;;; -1DE9;COMBINING LATIN SMALL LETTER BETA;Mn;230;NSM;;;;;N;;;;; -1DEA;COMBINING LATIN SMALL LETTER SCHWA;Mn;230;NSM;;;;;N;;;;; -1DEB;COMBINING LATIN SMALL LETTER F;Mn;230;NSM;;;;;N;;;;; -1DEC;COMBINING LATIN SMALL LETTER L WITH DOUBLE MIDDLE TILDE;Mn;230;NSM;;;;;N;;;;; -1DED;COMBINING LATIN SMALL LETTER O WITH LIGHT CENTRALIZATION STROKE;Mn;230;NSM;;;;;N;;;;; -1DEE;COMBINING LATIN SMALL LETTER P;Mn;230;NSM;;;;;N;;;;; -1DEF;COMBINING LATIN SMALL LETTER ESH;Mn;230;NSM;;;;;N;;;;; -1DF0;COMBINING LATIN SMALL LETTER U WITH LIGHT CENTRALIZATION STROKE;Mn;230;NSM;;;;;N;;;;; -1DF1;COMBINING LATIN SMALL LETTER W;Mn;230;NSM;;;;;N;;;;; -1DF2;COMBINING LATIN SMALL LETTER A WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;; -1DF3;COMBINING LATIN SMALL LETTER O WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;; -1DF4;COMBINING LATIN SMALL LETTER U WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;; -1DF5;COMBINING UP TACK ABOVE;Mn;230;NSM;;;;;N;;;;; -1DF6;COMBINING KAVYKA ABOVE RIGHT;Mn;232;NSM;;;;;N;;;;; -1DF7;COMBINING KAVYKA ABOVE LEFT;Mn;228;NSM;;;;;N;;;;; -1DF8;COMBINING DOT ABOVE LEFT;Mn;228;NSM;;;;;N;;;;; -1DF9;COMBINING WIDE INVERTED BRIDGE BELOW;Mn;220;NSM;;;;;N;;;;; -1DFA;COMBINING DOT BELOW LEFT;Mn;218;NSM;;;;;N;;;;; -1DFB;COMBINING DELETION MARK;Mn;230;NSM;;;;;N;;;;; -1DFC;COMBINING DOUBLE INVERTED BREVE BELOW;Mn;233;NSM;;;;;N;;;;; -1DFD;COMBINING ALMOST EQUAL TO BELOW;Mn;220;NSM;;;;;N;;;;; -1DFE;COMBINING LEFT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;; -1DFF;COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; -1E00;LATIN CAPITAL LETTER A WITH RING BELOW;Lu;0;L;0041 0325;;;;N;;;;1E01; -1E01;LATIN SMALL LETTER A WITH RING BELOW;Ll;0;L;0061 0325;;;;N;;;1E00;;1E00 -1E02;LATIN CAPITAL LETTER B WITH DOT ABOVE;Lu;0;L;0042 0307;;;;N;;;;1E03; -1E03;LATIN SMALL LETTER B WITH DOT ABOVE;Ll;0;L;0062 0307;;;;N;;;1E02;;1E02 -1E04;LATIN CAPITAL LETTER B WITH DOT BELOW;Lu;0;L;0042 0323;;;;N;;;;1E05; -1E05;LATIN SMALL LETTER B WITH DOT BELOW;Ll;0;L;0062 0323;;;;N;;;1E04;;1E04 -1E06;LATIN CAPITAL LETTER B WITH LINE BELOW;Lu;0;L;0042 0331;;;;N;;;;1E07; -1E07;LATIN SMALL LETTER B WITH LINE BELOW;Ll;0;L;0062 0331;;;;N;;;1E06;;1E06 -1E08;LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE;Lu;0;L;00C7 0301;;;;N;;;;1E09; -1E09;LATIN SMALL LETTER C WITH CEDILLA AND ACUTE;Ll;0;L;00E7 0301;;;;N;;;1E08;;1E08 -1E0A;LATIN CAPITAL LETTER D WITH DOT ABOVE;Lu;0;L;0044 0307;;;;N;;;;1E0B; -1E0B;LATIN SMALL LETTER D WITH DOT ABOVE;Ll;0;L;0064 0307;;;;N;;;1E0A;;1E0A -1E0C;LATIN CAPITAL LETTER D WITH DOT BELOW;Lu;0;L;0044 0323;;;;N;;;;1E0D; -1E0D;LATIN SMALL LETTER D WITH DOT BELOW;Ll;0;L;0064 0323;;;;N;;;1E0C;;1E0C -1E0E;LATIN CAPITAL LETTER D WITH LINE BELOW;Lu;0;L;0044 0331;;;;N;;;;1E0F; -1E0F;LATIN SMALL LETTER D WITH LINE BELOW;Ll;0;L;0064 0331;;;;N;;;1E0E;;1E0E -1E10;LATIN CAPITAL LETTER D WITH CEDILLA;Lu;0;L;0044 0327;;;;N;;;;1E11; -1E11;LATIN SMALL LETTER D WITH CEDILLA;Ll;0;L;0064 0327;;;;N;;;1E10;;1E10 -1E12;LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW;Lu;0;L;0044 032D;;;;N;;;;1E13; -1E13;LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW;Ll;0;L;0064 032D;;;;N;;;1E12;;1E12 -1E14;LATIN CAPITAL LETTER E WITH MACRON AND GRAVE;Lu;0;L;0112 0300;;;;N;;;;1E15; -1E15;LATIN SMALL LETTER E WITH MACRON AND GRAVE;Ll;0;L;0113 0300;;;;N;;;1E14;;1E14 -1E16;LATIN CAPITAL LETTER E WITH MACRON AND ACUTE;Lu;0;L;0112 0301;;;;N;;;;1E17; -1E17;LATIN SMALL LETTER E WITH MACRON AND ACUTE;Ll;0;L;0113 0301;;;;N;;;1E16;;1E16 -1E18;LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW;Lu;0;L;0045 032D;;;;N;;;;1E19; -1E19;LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW;Ll;0;L;0065 032D;;;;N;;;1E18;;1E18 -1E1A;LATIN CAPITAL LETTER E WITH TILDE BELOW;Lu;0;L;0045 0330;;;;N;;;;1E1B; -1E1B;LATIN SMALL LETTER E WITH TILDE BELOW;Ll;0;L;0065 0330;;;;N;;;1E1A;;1E1A -1E1C;LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE;Lu;0;L;0228 0306;;;;N;;;;1E1D; -1E1D;LATIN SMALL LETTER E WITH CEDILLA AND BREVE;Ll;0;L;0229 0306;;;;N;;;1E1C;;1E1C -1E1E;LATIN CAPITAL LETTER F WITH DOT ABOVE;Lu;0;L;0046 0307;;;;N;;;;1E1F; -1E1F;LATIN SMALL LETTER F WITH DOT ABOVE;Ll;0;L;0066 0307;;;;N;;;1E1E;;1E1E -1E20;LATIN CAPITAL LETTER G WITH MACRON;Lu;0;L;0047 0304;;;;N;;;;1E21; -1E21;LATIN SMALL LETTER G WITH MACRON;Ll;0;L;0067 0304;;;;N;;;1E20;;1E20 -1E22;LATIN CAPITAL LETTER H WITH DOT ABOVE;Lu;0;L;0048 0307;;;;N;;;;1E23; -1E23;LATIN SMALL LETTER H WITH DOT ABOVE;Ll;0;L;0068 0307;;;;N;;;1E22;;1E22 -1E24;LATIN CAPITAL LETTER H WITH DOT BELOW;Lu;0;L;0048 0323;;;;N;;;;1E25; -1E25;LATIN SMALL LETTER H WITH DOT BELOW;Ll;0;L;0068 0323;;;;N;;;1E24;;1E24 -1E26;LATIN CAPITAL LETTER H WITH DIAERESIS;Lu;0;L;0048 0308;;;;N;;;;1E27; -1E27;LATIN SMALL LETTER H WITH DIAERESIS;Ll;0;L;0068 0308;;;;N;;;1E26;;1E26 -1E28;LATIN CAPITAL LETTER H WITH CEDILLA;Lu;0;L;0048 0327;;;;N;;;;1E29; -1E29;LATIN SMALL LETTER H WITH CEDILLA;Ll;0;L;0068 0327;;;;N;;;1E28;;1E28 -1E2A;LATIN CAPITAL LETTER H WITH BREVE BELOW;Lu;0;L;0048 032E;;;;N;;;;1E2B; -1E2B;LATIN SMALL LETTER H WITH BREVE BELOW;Ll;0;L;0068 032E;;;;N;;;1E2A;;1E2A -1E2C;LATIN CAPITAL LETTER I WITH TILDE BELOW;Lu;0;L;0049 0330;;;;N;;;;1E2D; -1E2D;LATIN SMALL LETTER I WITH TILDE BELOW;Ll;0;L;0069 0330;;;;N;;;1E2C;;1E2C -1E2E;LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE;Lu;0;L;00CF 0301;;;;N;;;;1E2F; -1E2F;LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE;Ll;0;L;00EF 0301;;;;N;;;1E2E;;1E2E -1E30;LATIN CAPITAL LETTER K WITH ACUTE;Lu;0;L;004B 0301;;;;N;;;;1E31; -1E31;LATIN SMALL LETTER K WITH ACUTE;Ll;0;L;006B 0301;;;;N;;;1E30;;1E30 -1E32;LATIN CAPITAL LETTER K WITH DOT BELOW;Lu;0;L;004B 0323;;;;N;;;;1E33; -1E33;LATIN SMALL LETTER K WITH DOT BELOW;Ll;0;L;006B 0323;;;;N;;;1E32;;1E32 -1E34;LATIN CAPITAL LETTER K WITH LINE BELOW;Lu;0;L;004B 0331;;;;N;;;;1E35; -1E35;LATIN SMALL LETTER K WITH LINE BELOW;Ll;0;L;006B 0331;;;;N;;;1E34;;1E34 -1E36;LATIN CAPITAL LETTER L WITH DOT BELOW;Lu;0;L;004C 0323;;;;N;;;;1E37; -1E37;LATIN SMALL LETTER L WITH DOT BELOW;Ll;0;L;006C 0323;;;;N;;;1E36;;1E36 -1E38;LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON;Lu;0;L;1E36 0304;;;;N;;;;1E39; -1E39;LATIN SMALL LETTER L WITH DOT BELOW AND MACRON;Ll;0;L;1E37 0304;;;;N;;;1E38;;1E38 -1E3A;LATIN CAPITAL LETTER L WITH LINE BELOW;Lu;0;L;004C 0331;;;;N;;;;1E3B; -1E3B;LATIN SMALL LETTER L WITH LINE BELOW;Ll;0;L;006C 0331;;;;N;;;1E3A;;1E3A -1E3C;LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW;Lu;0;L;004C 032D;;;;N;;;;1E3D; -1E3D;LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW;Ll;0;L;006C 032D;;;;N;;;1E3C;;1E3C -1E3E;LATIN CAPITAL LETTER M WITH ACUTE;Lu;0;L;004D 0301;;;;N;;;;1E3F; -1E3F;LATIN SMALL LETTER M WITH ACUTE;Ll;0;L;006D 0301;;;;N;;;1E3E;;1E3E -1E40;LATIN CAPITAL LETTER M WITH DOT ABOVE;Lu;0;L;004D 0307;;;;N;;;;1E41; -1E41;LATIN SMALL LETTER M WITH DOT ABOVE;Ll;0;L;006D 0307;;;;N;;;1E40;;1E40 -1E42;LATIN CAPITAL LETTER M WITH DOT BELOW;Lu;0;L;004D 0323;;;;N;;;;1E43; -1E43;LATIN SMALL LETTER M WITH DOT BELOW;Ll;0;L;006D 0323;;;;N;;;1E42;;1E42 -1E44;LATIN CAPITAL LETTER N WITH DOT ABOVE;Lu;0;L;004E 0307;;;;N;;;;1E45; -1E45;LATIN SMALL LETTER N WITH DOT ABOVE;Ll;0;L;006E 0307;;;;N;;;1E44;;1E44 -1E46;LATIN CAPITAL LETTER N WITH DOT BELOW;Lu;0;L;004E 0323;;;;N;;;;1E47; -1E47;LATIN SMALL LETTER N WITH DOT BELOW;Ll;0;L;006E 0323;;;;N;;;1E46;;1E46 -1E48;LATIN CAPITAL LETTER N WITH LINE BELOW;Lu;0;L;004E 0331;;;;N;;;;1E49; -1E49;LATIN SMALL LETTER N WITH LINE BELOW;Ll;0;L;006E 0331;;;;N;;;1E48;;1E48 -1E4A;LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW;Lu;0;L;004E 032D;;;;N;;;;1E4B; -1E4B;LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW;Ll;0;L;006E 032D;;;;N;;;1E4A;;1E4A -1E4C;LATIN CAPITAL LETTER O WITH TILDE AND ACUTE;Lu;0;L;00D5 0301;;;;N;;;;1E4D; -1E4D;LATIN SMALL LETTER O WITH TILDE AND ACUTE;Ll;0;L;00F5 0301;;;;N;;;1E4C;;1E4C -1E4E;LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS;Lu;0;L;00D5 0308;;;;N;;;;1E4F; -1E4F;LATIN SMALL LETTER O WITH TILDE AND DIAERESIS;Ll;0;L;00F5 0308;;;;N;;;1E4E;;1E4E -1E50;LATIN CAPITAL LETTER O WITH MACRON AND GRAVE;Lu;0;L;014C 0300;;;;N;;;;1E51; -1E51;LATIN SMALL LETTER O WITH MACRON AND GRAVE;Ll;0;L;014D 0300;;;;N;;;1E50;;1E50 -1E52;LATIN CAPITAL LETTER O WITH MACRON AND ACUTE;Lu;0;L;014C 0301;;;;N;;;;1E53; -1E53;LATIN SMALL LETTER O WITH MACRON AND ACUTE;Ll;0;L;014D 0301;;;;N;;;1E52;;1E52 -1E54;LATIN CAPITAL LETTER P WITH ACUTE;Lu;0;L;0050 0301;;;;N;;;;1E55; -1E55;LATIN SMALL LETTER P WITH ACUTE;Ll;0;L;0070 0301;;;;N;;;1E54;;1E54 -1E56;LATIN CAPITAL LETTER P WITH DOT ABOVE;Lu;0;L;0050 0307;;;;N;;;;1E57; -1E57;LATIN SMALL LETTER P WITH DOT ABOVE;Ll;0;L;0070 0307;;;;N;;;1E56;;1E56 -1E58;LATIN CAPITAL LETTER R WITH DOT ABOVE;Lu;0;L;0052 0307;;;;N;;;;1E59; -1E59;LATIN SMALL LETTER R WITH DOT ABOVE;Ll;0;L;0072 0307;;;;N;;;1E58;;1E58 -1E5A;LATIN CAPITAL LETTER R WITH DOT BELOW;Lu;0;L;0052 0323;;;;N;;;;1E5B; -1E5B;LATIN SMALL LETTER R WITH DOT BELOW;Ll;0;L;0072 0323;;;;N;;;1E5A;;1E5A -1E5C;LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON;Lu;0;L;1E5A 0304;;;;N;;;;1E5D; -1E5D;LATIN SMALL LETTER R WITH DOT BELOW AND MACRON;Ll;0;L;1E5B 0304;;;;N;;;1E5C;;1E5C -1E5E;LATIN CAPITAL LETTER R WITH LINE BELOW;Lu;0;L;0052 0331;;;;N;;;;1E5F; -1E5F;LATIN SMALL LETTER R WITH LINE BELOW;Ll;0;L;0072 0331;;;;N;;;1E5E;;1E5E -1E60;LATIN CAPITAL LETTER S WITH DOT ABOVE;Lu;0;L;0053 0307;;;;N;;;;1E61; -1E61;LATIN SMALL LETTER S WITH DOT ABOVE;Ll;0;L;0073 0307;;;;N;;;1E60;;1E60 -1E62;LATIN CAPITAL LETTER S WITH DOT BELOW;Lu;0;L;0053 0323;;;;N;;;;1E63; -1E63;LATIN SMALL LETTER S WITH DOT BELOW;Ll;0;L;0073 0323;;;;N;;;1E62;;1E62 -1E64;LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE;Lu;0;L;015A 0307;;;;N;;;;1E65; -1E65;LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE;Ll;0;L;015B 0307;;;;N;;;1E64;;1E64 -1E66;LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE;Lu;0;L;0160 0307;;;;N;;;;1E67; -1E67;LATIN SMALL LETTER S WITH CARON AND DOT ABOVE;Ll;0;L;0161 0307;;;;N;;;1E66;;1E66 -1E68;LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE;Lu;0;L;1E62 0307;;;;N;;;;1E69; -1E69;LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE;Ll;0;L;1E63 0307;;;;N;;;1E68;;1E68 -1E6A;LATIN CAPITAL LETTER T WITH DOT ABOVE;Lu;0;L;0054 0307;;;;N;;;;1E6B; -1E6B;LATIN SMALL LETTER T WITH DOT ABOVE;Ll;0;L;0074 0307;;;;N;;;1E6A;;1E6A -1E6C;LATIN CAPITAL LETTER T WITH DOT BELOW;Lu;0;L;0054 0323;;;;N;;;;1E6D; -1E6D;LATIN SMALL LETTER T WITH DOT BELOW;Ll;0;L;0074 0323;;;;N;;;1E6C;;1E6C -1E6E;LATIN CAPITAL LETTER T WITH LINE BELOW;Lu;0;L;0054 0331;;;;N;;;;1E6F; -1E6F;LATIN SMALL LETTER T WITH LINE BELOW;Ll;0;L;0074 0331;;;;N;;;1E6E;;1E6E -1E70;LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW;Lu;0;L;0054 032D;;;;N;;;;1E71; -1E71;LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW;Ll;0;L;0074 032D;;;;N;;;1E70;;1E70 -1E72;LATIN CAPITAL LETTER U WITH DIAERESIS BELOW;Lu;0;L;0055 0324;;;;N;;;;1E73; -1E73;LATIN SMALL LETTER U WITH DIAERESIS BELOW;Ll;0;L;0075 0324;;;;N;;;1E72;;1E72 -1E74;LATIN CAPITAL LETTER U WITH TILDE BELOW;Lu;0;L;0055 0330;;;;N;;;;1E75; -1E75;LATIN SMALL LETTER U WITH TILDE BELOW;Ll;0;L;0075 0330;;;;N;;;1E74;;1E74 -1E76;LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW;Lu;0;L;0055 032D;;;;N;;;;1E77; -1E77;LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW;Ll;0;L;0075 032D;;;;N;;;1E76;;1E76 -1E78;LATIN CAPITAL LETTER U WITH TILDE AND ACUTE;Lu;0;L;0168 0301;;;;N;;;;1E79; -1E79;LATIN SMALL LETTER U WITH TILDE AND ACUTE;Ll;0;L;0169 0301;;;;N;;;1E78;;1E78 -1E7A;LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS;Lu;0;L;016A 0308;;;;N;;;;1E7B; -1E7B;LATIN SMALL LETTER U WITH MACRON AND DIAERESIS;Ll;0;L;016B 0308;;;;N;;;1E7A;;1E7A -1E7C;LATIN CAPITAL LETTER V WITH TILDE;Lu;0;L;0056 0303;;;;N;;;;1E7D; -1E7D;LATIN SMALL LETTER V WITH TILDE;Ll;0;L;0076 0303;;;;N;;;1E7C;;1E7C -1E7E;LATIN CAPITAL LETTER V WITH DOT BELOW;Lu;0;L;0056 0323;;;;N;;;;1E7F; -1E7F;LATIN SMALL LETTER V WITH DOT BELOW;Ll;0;L;0076 0323;;;;N;;;1E7E;;1E7E -1E80;LATIN CAPITAL LETTER W WITH GRAVE;Lu;0;L;0057 0300;;;;N;;;;1E81; -1E81;LATIN SMALL LETTER W WITH GRAVE;Ll;0;L;0077 0300;;;;N;;;1E80;;1E80 -1E82;LATIN CAPITAL LETTER W WITH ACUTE;Lu;0;L;0057 0301;;;;N;;;;1E83; -1E83;LATIN SMALL LETTER W WITH ACUTE;Ll;0;L;0077 0301;;;;N;;;1E82;;1E82 -1E84;LATIN CAPITAL LETTER W WITH DIAERESIS;Lu;0;L;0057 0308;;;;N;;;;1E85; -1E85;LATIN SMALL LETTER W WITH DIAERESIS;Ll;0;L;0077 0308;;;;N;;;1E84;;1E84 -1E86;LATIN CAPITAL LETTER W WITH DOT ABOVE;Lu;0;L;0057 0307;;;;N;;;;1E87; -1E87;LATIN SMALL LETTER W WITH DOT ABOVE;Ll;0;L;0077 0307;;;;N;;;1E86;;1E86 -1E88;LATIN CAPITAL LETTER W WITH DOT BELOW;Lu;0;L;0057 0323;;;;N;;;;1E89; -1E89;LATIN SMALL LETTER W WITH DOT BELOW;Ll;0;L;0077 0323;;;;N;;;1E88;;1E88 -1E8A;LATIN CAPITAL LETTER X WITH DOT ABOVE;Lu;0;L;0058 0307;;;;N;;;;1E8B; -1E8B;LATIN SMALL LETTER X WITH DOT ABOVE;Ll;0;L;0078 0307;;;;N;;;1E8A;;1E8A -1E8C;LATIN CAPITAL LETTER X WITH DIAERESIS;Lu;0;L;0058 0308;;;;N;;;;1E8D; -1E8D;LATIN SMALL LETTER X WITH DIAERESIS;Ll;0;L;0078 0308;;;;N;;;1E8C;;1E8C -1E8E;LATIN CAPITAL LETTER Y WITH DOT ABOVE;Lu;0;L;0059 0307;;;;N;;;;1E8F; -1E8F;LATIN SMALL LETTER Y WITH DOT ABOVE;Ll;0;L;0079 0307;;;;N;;;1E8E;;1E8E -1E90;LATIN CAPITAL LETTER Z WITH CIRCUMFLEX;Lu;0;L;005A 0302;;;;N;;;;1E91; -1E91;LATIN SMALL LETTER Z WITH CIRCUMFLEX;Ll;0;L;007A 0302;;;;N;;;1E90;;1E90 -1E92;LATIN CAPITAL LETTER Z WITH DOT BELOW;Lu;0;L;005A 0323;;;;N;;;;1E93; -1E93;LATIN SMALL LETTER Z WITH DOT BELOW;Ll;0;L;007A 0323;;;;N;;;1E92;;1E92 -1E94;LATIN CAPITAL LETTER Z WITH LINE BELOW;Lu;0;L;005A 0331;;;;N;;;;1E95; -1E95;LATIN SMALL LETTER Z WITH LINE BELOW;Ll;0;L;007A 0331;;;;N;;;1E94;;1E94 -1E96;LATIN SMALL LETTER H WITH LINE BELOW;Ll;0;L;0068 0331;;;;N;;;;; -1E97;LATIN SMALL LETTER T WITH DIAERESIS;Ll;0;L;0074 0308;;;;N;;;;; -1E98;LATIN SMALL LETTER W WITH RING ABOVE;Ll;0;L;0077 030A;;;;N;;;;; -1E99;LATIN SMALL LETTER Y WITH RING ABOVE;Ll;0;L;0079 030A;;;;N;;;;; -1E9A;LATIN SMALL LETTER A WITH RIGHT HALF RING;Ll;0;L;<compat> 0061 02BE;;;;N;;;;; -1E9B;LATIN SMALL LETTER LONG S WITH DOT ABOVE;Ll;0;L;017F 0307;;;;N;;;1E60;;1E60 -1E9C;LATIN SMALL LETTER LONG S WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;;; -1E9D;LATIN SMALL LETTER LONG S WITH HIGH STROKE;Ll;0;L;;;;;N;;;;; -1E9E;LATIN CAPITAL LETTER SHARP S;Lu;0;L;;;;;N;;;;00DF; -1E9F;LATIN SMALL LETTER DELTA;Ll;0;L;;;;;N;;;;; -1EA0;LATIN CAPITAL LETTER A WITH DOT BELOW;Lu;0;L;0041 0323;;;;N;;;;1EA1; -1EA1;LATIN SMALL LETTER A WITH DOT BELOW;Ll;0;L;0061 0323;;;;N;;;1EA0;;1EA0 -1EA2;LATIN CAPITAL LETTER A WITH HOOK ABOVE;Lu;0;L;0041 0309;;;;N;;;;1EA3; -1EA3;LATIN SMALL LETTER A WITH HOOK ABOVE;Ll;0;L;0061 0309;;;;N;;;1EA2;;1EA2 -1EA4;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00C2 0301;;;;N;;;;1EA5; -1EA5;LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00E2 0301;;;;N;;;1EA4;;1EA4 -1EA6;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00C2 0300;;;;N;;;;1EA7; -1EA7;LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00E2 0300;;;;N;;;1EA6;;1EA6 -1EA8;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00C2 0309;;;;N;;;;1EA9; -1EA9;LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00E2 0309;;;;N;;;1EA8;;1EA8 -1EAA;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE;Lu;0;L;00C2 0303;;;;N;;;;1EAB; -1EAB;LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE;Ll;0;L;00E2 0303;;;;N;;;1EAA;;1EAA -1EAC;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EA0 0302;;;;N;;;;1EAD; -1EAD;LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EA1 0302;;;;N;;;1EAC;;1EAC -1EAE;LATIN CAPITAL LETTER A WITH BREVE AND ACUTE;Lu;0;L;0102 0301;;;;N;;;;1EAF; -1EAF;LATIN SMALL LETTER A WITH BREVE AND ACUTE;Ll;0;L;0103 0301;;;;N;;;1EAE;;1EAE -1EB0;LATIN CAPITAL LETTER A WITH BREVE AND GRAVE;Lu;0;L;0102 0300;;;;N;;;;1EB1; -1EB1;LATIN SMALL LETTER A WITH BREVE AND GRAVE;Ll;0;L;0103 0300;;;;N;;;1EB0;;1EB0 -1EB2;LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE;Lu;0;L;0102 0309;;;;N;;;;1EB3; -1EB3;LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE;Ll;0;L;0103 0309;;;;N;;;1EB2;;1EB2 -1EB4;LATIN CAPITAL LETTER A WITH BREVE AND TILDE;Lu;0;L;0102 0303;;;;N;;;;1EB5; -1EB5;LATIN SMALL LETTER A WITH BREVE AND TILDE;Ll;0;L;0103 0303;;;;N;;;1EB4;;1EB4 -1EB6;LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW;Lu;0;L;1EA0 0306;;;;N;;;;1EB7; -1EB7;LATIN SMALL LETTER A WITH BREVE AND DOT BELOW;Ll;0;L;1EA1 0306;;;;N;;;1EB6;;1EB6 -1EB8;LATIN CAPITAL LETTER E WITH DOT BELOW;Lu;0;L;0045 0323;;;;N;;;;1EB9; -1EB9;LATIN SMALL LETTER E WITH DOT BELOW;Ll;0;L;0065 0323;;;;N;;;1EB8;;1EB8 -1EBA;LATIN CAPITAL LETTER E WITH HOOK ABOVE;Lu;0;L;0045 0309;;;;N;;;;1EBB; -1EBB;LATIN SMALL LETTER E WITH HOOK ABOVE;Ll;0;L;0065 0309;;;;N;;;1EBA;;1EBA -1EBC;LATIN CAPITAL LETTER E WITH TILDE;Lu;0;L;0045 0303;;;;N;;;;1EBD; -1EBD;LATIN SMALL LETTER E WITH TILDE;Ll;0;L;0065 0303;;;;N;;;1EBC;;1EBC -1EBE;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00CA 0301;;;;N;;;;1EBF; -1EBF;LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00EA 0301;;;;N;;;1EBE;;1EBE -1EC0;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00CA 0300;;;;N;;;;1EC1; -1EC1;LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00EA 0300;;;;N;;;1EC0;;1EC0 -1EC2;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00CA 0309;;;;N;;;;1EC3; -1EC3;LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00EA 0309;;;;N;;;1EC2;;1EC2 -1EC4;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE;Lu;0;L;00CA 0303;;;;N;;;;1EC5; -1EC5;LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE;Ll;0;L;00EA 0303;;;;N;;;1EC4;;1EC4 -1EC6;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EB8 0302;;;;N;;;;1EC7; -1EC7;LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EB9 0302;;;;N;;;1EC6;;1EC6 -1EC8;LATIN CAPITAL LETTER I WITH HOOK ABOVE;Lu;0;L;0049 0309;;;;N;;;;1EC9; -1EC9;LATIN SMALL LETTER I WITH HOOK ABOVE;Ll;0;L;0069 0309;;;;N;;;1EC8;;1EC8 -1ECA;LATIN CAPITAL LETTER I WITH DOT BELOW;Lu;0;L;0049 0323;;;;N;;;;1ECB; -1ECB;LATIN SMALL LETTER I WITH DOT BELOW;Ll;0;L;0069 0323;;;;N;;;1ECA;;1ECA -1ECC;LATIN CAPITAL LETTER O WITH DOT BELOW;Lu;0;L;004F 0323;;;;N;;;;1ECD; -1ECD;LATIN SMALL LETTER O WITH DOT BELOW;Ll;0;L;006F 0323;;;;N;;;1ECC;;1ECC -1ECE;LATIN CAPITAL LETTER O WITH HOOK ABOVE;Lu;0;L;004F 0309;;;;N;;;;1ECF; -1ECF;LATIN SMALL LETTER O WITH HOOK ABOVE;Ll;0;L;006F 0309;;;;N;;;1ECE;;1ECE -1ED0;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00D4 0301;;;;N;;;;1ED1; -1ED1;LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00F4 0301;;;;N;;;1ED0;;1ED0 -1ED2;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00D4 0300;;;;N;;;;1ED3; -1ED3;LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00F4 0300;;;;N;;;1ED2;;1ED2 -1ED4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00D4 0309;;;;N;;;;1ED5; -1ED5;LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00F4 0309;;;;N;;;1ED4;;1ED4 -1ED6;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE;Lu;0;L;00D4 0303;;;;N;;;;1ED7; -1ED7;LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE;Ll;0;L;00F4 0303;;;;N;;;1ED6;;1ED6 -1ED8;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1ECC 0302;;;;N;;;;1ED9; -1ED9;LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1ECD 0302;;;;N;;;1ED8;;1ED8 -1EDA;LATIN CAPITAL LETTER O WITH HORN AND ACUTE;Lu;0;L;01A0 0301;;;;N;;;;1EDB; -1EDB;LATIN SMALL LETTER O WITH HORN AND ACUTE;Ll;0;L;01A1 0301;;;;N;;;1EDA;;1EDA -1EDC;LATIN CAPITAL LETTER O WITH HORN AND GRAVE;Lu;0;L;01A0 0300;;;;N;;;;1EDD; -1EDD;LATIN SMALL LETTER O WITH HORN AND GRAVE;Ll;0;L;01A1 0300;;;;N;;;1EDC;;1EDC -1EDE;LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE;Lu;0;L;01A0 0309;;;;N;;;;1EDF; -1EDF;LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE;Ll;0;L;01A1 0309;;;;N;;;1EDE;;1EDE -1EE0;LATIN CAPITAL LETTER O WITH HORN AND TILDE;Lu;0;L;01A0 0303;;;;N;;;;1EE1; -1EE1;LATIN SMALL LETTER O WITH HORN AND TILDE;Ll;0;L;01A1 0303;;;;N;;;1EE0;;1EE0 -1EE2;LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW;Lu;0;L;01A0 0323;;;;N;;;;1EE3; -1EE3;LATIN SMALL LETTER O WITH HORN AND DOT BELOW;Ll;0;L;01A1 0323;;;;N;;;1EE2;;1EE2 -1EE4;LATIN CAPITAL LETTER U WITH DOT BELOW;Lu;0;L;0055 0323;;;;N;;;;1EE5; -1EE5;LATIN SMALL LETTER U WITH DOT BELOW;Ll;0;L;0075 0323;;;;N;;;1EE4;;1EE4 -1EE6;LATIN CAPITAL LETTER U WITH HOOK ABOVE;Lu;0;L;0055 0309;;;;N;;;;1EE7; -1EE7;LATIN SMALL LETTER U WITH HOOK ABOVE;Ll;0;L;0075 0309;;;;N;;;1EE6;;1EE6 -1EE8;LATIN CAPITAL LETTER U WITH HORN AND ACUTE;Lu;0;L;01AF 0301;;;;N;;;;1EE9; -1EE9;LATIN SMALL LETTER U WITH HORN AND ACUTE;Ll;0;L;01B0 0301;;;;N;;;1EE8;;1EE8 -1EEA;LATIN CAPITAL LETTER U WITH HORN AND GRAVE;Lu;0;L;01AF 0300;;;;N;;;;1EEB; -1EEB;LATIN SMALL LETTER U WITH HORN AND GRAVE;Ll;0;L;01B0 0300;;;;N;;;1EEA;;1EEA -1EEC;LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE;Lu;0;L;01AF 0309;;;;N;;;;1EED; -1EED;LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE;Ll;0;L;01B0 0309;;;;N;;;1EEC;;1EEC -1EEE;LATIN CAPITAL LETTER U WITH HORN AND TILDE;Lu;0;L;01AF 0303;;;;N;;;;1EEF; -1EEF;LATIN SMALL LETTER U WITH HORN AND TILDE;Ll;0;L;01B0 0303;;;;N;;;1EEE;;1EEE -1EF0;LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW;Lu;0;L;01AF 0323;;;;N;;;;1EF1; -1EF1;LATIN SMALL LETTER U WITH HORN AND DOT BELOW;Ll;0;L;01B0 0323;;;;N;;;1EF0;;1EF0 -1EF2;LATIN CAPITAL LETTER Y WITH GRAVE;Lu;0;L;0059 0300;;;;N;;;;1EF3; -1EF3;LATIN SMALL LETTER Y WITH GRAVE;Ll;0;L;0079 0300;;;;N;;;1EF2;;1EF2 -1EF4;LATIN CAPITAL LETTER Y WITH DOT BELOW;Lu;0;L;0059 0323;;;;N;;;;1EF5; -1EF5;LATIN SMALL LETTER Y WITH DOT BELOW;Ll;0;L;0079 0323;;;;N;;;1EF4;;1EF4 -1EF6;LATIN CAPITAL LETTER Y WITH HOOK ABOVE;Lu;0;L;0059 0309;;;;N;;;;1EF7; -1EF7;LATIN SMALL LETTER Y WITH HOOK ABOVE;Ll;0;L;0079 0309;;;;N;;;1EF6;;1EF6 -1EF8;LATIN CAPITAL LETTER Y WITH TILDE;Lu;0;L;0059 0303;;;;N;;;;1EF9; -1EF9;LATIN SMALL LETTER Y WITH TILDE;Ll;0;L;0079 0303;;;;N;;;1EF8;;1EF8 -1EFA;LATIN CAPITAL LETTER MIDDLE-WELSH LL;Lu;0;L;;;;;N;;;;1EFB; -1EFB;LATIN SMALL LETTER MIDDLE-WELSH LL;Ll;0;L;;;;;N;;;1EFA;;1EFA -1EFC;LATIN CAPITAL LETTER MIDDLE-WELSH V;Lu;0;L;;;;;N;;;;1EFD; -1EFD;LATIN SMALL LETTER MIDDLE-WELSH V;Ll;0;L;;;;;N;;;1EFC;;1EFC -1EFE;LATIN CAPITAL LETTER Y WITH LOOP;Lu;0;L;;;;;N;;;;1EFF; -1EFF;LATIN SMALL LETTER Y WITH LOOP;Ll;0;L;;;;;N;;;1EFE;;1EFE -1F00;GREEK SMALL LETTER ALPHA WITH PSILI;Ll;0;L;03B1 0313;;;;N;;;1F08;;1F08 -1F01;GREEK SMALL LETTER ALPHA WITH DASIA;Ll;0;L;03B1 0314;;;;N;;;1F09;;1F09 -1F02;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA;Ll;0;L;1F00 0300;;;;N;;;1F0A;;1F0A -1F03;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA;Ll;0;L;1F01 0300;;;;N;;;1F0B;;1F0B -1F04;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA;Ll;0;L;1F00 0301;;;;N;;;1F0C;;1F0C -1F05;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA;Ll;0;L;1F01 0301;;;;N;;;1F0D;;1F0D -1F06;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI;Ll;0;L;1F00 0342;;;;N;;;1F0E;;1F0E -1F07;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI;Ll;0;L;1F01 0342;;;;N;;;1F0F;;1F0F -1F08;GREEK CAPITAL LETTER ALPHA WITH PSILI;Lu;0;L;0391 0313;;;;N;;;;1F00; -1F09;GREEK CAPITAL LETTER ALPHA WITH DASIA;Lu;0;L;0391 0314;;;;N;;;;1F01; -1F0A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA;Lu;0;L;1F08 0300;;;;N;;;;1F02; -1F0B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA;Lu;0;L;1F09 0300;;;;N;;;;1F03; -1F0C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA;Lu;0;L;1F08 0301;;;;N;;;;1F04; -1F0D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA;Lu;0;L;1F09 0301;;;;N;;;;1F05; -1F0E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI;Lu;0;L;1F08 0342;;;;N;;;;1F06; -1F0F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI;Lu;0;L;1F09 0342;;;;N;;;;1F07; -1F10;GREEK SMALL LETTER EPSILON WITH PSILI;Ll;0;L;03B5 0313;;;;N;;;1F18;;1F18 -1F11;GREEK SMALL LETTER EPSILON WITH DASIA;Ll;0;L;03B5 0314;;;;N;;;1F19;;1F19 -1F12;GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA;Ll;0;L;1F10 0300;;;;N;;;1F1A;;1F1A -1F13;GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA;Ll;0;L;1F11 0300;;;;N;;;1F1B;;1F1B -1F14;GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA;Ll;0;L;1F10 0301;;;;N;;;1F1C;;1F1C -1F15;GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA;Ll;0;L;1F11 0301;;;;N;;;1F1D;;1F1D -1F18;GREEK CAPITAL LETTER EPSILON WITH PSILI;Lu;0;L;0395 0313;;;;N;;;;1F10; -1F19;GREEK CAPITAL LETTER EPSILON WITH DASIA;Lu;0;L;0395 0314;;;;N;;;;1F11; -1F1A;GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA;Lu;0;L;1F18 0300;;;;N;;;;1F12; -1F1B;GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA;Lu;0;L;1F19 0300;;;;N;;;;1F13; -1F1C;GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA;Lu;0;L;1F18 0301;;;;N;;;;1F14; -1F1D;GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA;Lu;0;L;1F19 0301;;;;N;;;;1F15; -1F20;GREEK SMALL LETTER ETA WITH PSILI;Ll;0;L;03B7 0313;;;;N;;;1F28;;1F28 -1F21;GREEK SMALL LETTER ETA WITH DASIA;Ll;0;L;03B7 0314;;;;N;;;1F29;;1F29 -1F22;GREEK SMALL LETTER ETA WITH PSILI AND VARIA;Ll;0;L;1F20 0300;;;;N;;;1F2A;;1F2A -1F23;GREEK SMALL LETTER ETA WITH DASIA AND VARIA;Ll;0;L;1F21 0300;;;;N;;;1F2B;;1F2B -1F24;GREEK SMALL LETTER ETA WITH PSILI AND OXIA;Ll;0;L;1F20 0301;;;;N;;;1F2C;;1F2C -1F25;GREEK SMALL LETTER ETA WITH DASIA AND OXIA;Ll;0;L;1F21 0301;;;;N;;;1F2D;;1F2D -1F26;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI;Ll;0;L;1F20 0342;;;;N;;;1F2E;;1F2E -1F27;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI;Ll;0;L;1F21 0342;;;;N;;;1F2F;;1F2F -1F28;GREEK CAPITAL LETTER ETA WITH PSILI;Lu;0;L;0397 0313;;;;N;;;;1F20; -1F29;GREEK CAPITAL LETTER ETA WITH DASIA;Lu;0;L;0397 0314;;;;N;;;;1F21; -1F2A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA;Lu;0;L;1F28 0300;;;;N;;;;1F22; -1F2B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA;Lu;0;L;1F29 0300;;;;N;;;;1F23; -1F2C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA;Lu;0;L;1F28 0301;;;;N;;;;1F24; -1F2D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA;Lu;0;L;1F29 0301;;;;N;;;;1F25; -1F2E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI;Lu;0;L;1F28 0342;;;;N;;;;1F26; -1F2F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI;Lu;0;L;1F29 0342;;;;N;;;;1F27; -1F30;GREEK SMALL LETTER IOTA WITH PSILI;Ll;0;L;03B9 0313;;;;N;;;1F38;;1F38 -1F31;GREEK SMALL LETTER IOTA WITH DASIA;Ll;0;L;03B9 0314;;;;N;;;1F39;;1F39 -1F32;GREEK SMALL LETTER IOTA WITH PSILI AND VARIA;Ll;0;L;1F30 0300;;;;N;;;1F3A;;1F3A -1F33;GREEK SMALL LETTER IOTA WITH DASIA AND VARIA;Ll;0;L;1F31 0300;;;;N;;;1F3B;;1F3B -1F34;GREEK SMALL LETTER IOTA WITH PSILI AND OXIA;Ll;0;L;1F30 0301;;;;N;;;1F3C;;1F3C -1F35;GREEK SMALL LETTER IOTA WITH DASIA AND OXIA;Ll;0;L;1F31 0301;;;;N;;;1F3D;;1F3D -1F36;GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI;Ll;0;L;1F30 0342;;;;N;;;1F3E;;1F3E -1F37;GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI;Ll;0;L;1F31 0342;;;;N;;;1F3F;;1F3F -1F38;GREEK CAPITAL LETTER IOTA WITH PSILI;Lu;0;L;0399 0313;;;;N;;;;1F30; -1F39;GREEK CAPITAL LETTER IOTA WITH DASIA;Lu;0;L;0399 0314;;;;N;;;;1F31; -1F3A;GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA;Lu;0;L;1F38 0300;;;;N;;;;1F32; -1F3B;GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA;Lu;0;L;1F39 0300;;;;N;;;;1F33; -1F3C;GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA;Lu;0;L;1F38 0301;;;;N;;;;1F34; -1F3D;GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA;Lu;0;L;1F39 0301;;;;N;;;;1F35; -1F3E;GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI;Lu;0;L;1F38 0342;;;;N;;;;1F36; -1F3F;GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI;Lu;0;L;1F39 0342;;;;N;;;;1F37; -1F40;GREEK SMALL LETTER OMICRON WITH PSILI;Ll;0;L;03BF 0313;;;;N;;;1F48;;1F48 -1F41;GREEK SMALL LETTER OMICRON WITH DASIA;Ll;0;L;03BF 0314;;;;N;;;1F49;;1F49 -1F42;GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA;Ll;0;L;1F40 0300;;;;N;;;1F4A;;1F4A -1F43;GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA;Ll;0;L;1F41 0300;;;;N;;;1F4B;;1F4B -1F44;GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA;Ll;0;L;1F40 0301;;;;N;;;1F4C;;1F4C -1F45;GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA;Ll;0;L;1F41 0301;;;;N;;;1F4D;;1F4D -1F48;GREEK CAPITAL LETTER OMICRON WITH PSILI;Lu;0;L;039F 0313;;;;N;;;;1F40; -1F49;GREEK CAPITAL LETTER OMICRON WITH DASIA;Lu;0;L;039F 0314;;;;N;;;;1F41; -1F4A;GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA;Lu;0;L;1F48 0300;;;;N;;;;1F42; -1F4B;GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA;Lu;0;L;1F49 0300;;;;N;;;;1F43; -1F4C;GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA;Lu;0;L;1F48 0301;;;;N;;;;1F44; -1F4D;GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA;Lu;0;L;1F49 0301;;;;N;;;;1F45; -1F50;GREEK SMALL LETTER UPSILON WITH PSILI;Ll;0;L;03C5 0313;;;;N;;;;; -1F51;GREEK SMALL LETTER UPSILON WITH DASIA;Ll;0;L;03C5 0314;;;;N;;;1F59;;1F59 -1F52;GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA;Ll;0;L;1F50 0300;;;;N;;;;; -1F53;GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA;Ll;0;L;1F51 0300;;;;N;;;1F5B;;1F5B -1F54;GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA;Ll;0;L;1F50 0301;;;;N;;;;; -1F55;GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA;Ll;0;L;1F51 0301;;;;N;;;1F5D;;1F5D -1F56;GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI;Ll;0;L;1F50 0342;;;;N;;;;; -1F57;GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI;Ll;0;L;1F51 0342;;;;N;;;1F5F;;1F5F -1F59;GREEK CAPITAL LETTER UPSILON WITH DASIA;Lu;0;L;03A5 0314;;;;N;;;;1F51; -1F5B;GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA;Lu;0;L;1F59 0300;;;;N;;;;1F53; -1F5D;GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA;Lu;0;L;1F59 0301;;;;N;;;;1F55; -1F5F;GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI;Lu;0;L;1F59 0342;;;;N;;;;1F57; -1F60;GREEK SMALL LETTER OMEGA WITH PSILI;Ll;0;L;03C9 0313;;;;N;;;1F68;;1F68 -1F61;GREEK SMALL LETTER OMEGA WITH DASIA;Ll;0;L;03C9 0314;;;;N;;;1F69;;1F69 -1F62;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA;Ll;0;L;1F60 0300;;;;N;;;1F6A;;1F6A -1F63;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA;Ll;0;L;1F61 0300;;;;N;;;1F6B;;1F6B -1F64;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA;Ll;0;L;1F60 0301;;;;N;;;1F6C;;1F6C -1F65;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA;Ll;0;L;1F61 0301;;;;N;;;1F6D;;1F6D -1F66;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI;Ll;0;L;1F60 0342;;;;N;;;1F6E;;1F6E -1F67;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI;Ll;0;L;1F61 0342;;;;N;;;1F6F;;1F6F -1F68;GREEK CAPITAL LETTER OMEGA WITH PSILI;Lu;0;L;03A9 0313;;;;N;;;;1F60; -1F69;GREEK CAPITAL LETTER OMEGA WITH DASIA;Lu;0;L;03A9 0314;;;;N;;;;1F61; -1F6A;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA;Lu;0;L;1F68 0300;;;;N;;;;1F62; -1F6B;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA;Lu;0;L;1F69 0300;;;;N;;;;1F63; -1F6C;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA;Lu;0;L;1F68 0301;;;;N;;;;1F64; -1F6D;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA;Lu;0;L;1F69 0301;;;;N;;;;1F65; -1F6E;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI;Lu;0;L;1F68 0342;;;;N;;;;1F66; -1F6F;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI;Lu;0;L;1F69 0342;;;;N;;;;1F67; -1F70;GREEK SMALL LETTER ALPHA WITH VARIA;Ll;0;L;03B1 0300;;;;N;;;1FBA;;1FBA -1F71;GREEK SMALL LETTER ALPHA WITH OXIA;Ll;0;L;03AC;;;;N;;;1FBB;;1FBB -1F72;GREEK SMALL LETTER EPSILON WITH VARIA;Ll;0;L;03B5 0300;;;;N;;;1FC8;;1FC8 -1F73;GREEK SMALL LETTER EPSILON WITH OXIA;Ll;0;L;03AD;;;;N;;;1FC9;;1FC9 -1F74;GREEK SMALL LETTER ETA WITH VARIA;Ll;0;L;03B7 0300;;;;N;;;1FCA;;1FCA -1F75;GREEK SMALL LETTER ETA WITH OXIA;Ll;0;L;03AE;;;;N;;;1FCB;;1FCB -1F76;GREEK SMALL LETTER IOTA WITH VARIA;Ll;0;L;03B9 0300;;;;N;;;1FDA;;1FDA -1F77;GREEK SMALL LETTER IOTA WITH OXIA;Ll;0;L;03AF;;;;N;;;1FDB;;1FDB -1F78;GREEK SMALL LETTER OMICRON WITH VARIA;Ll;0;L;03BF 0300;;;;N;;;1FF8;;1FF8 -1F79;GREEK SMALL LETTER OMICRON WITH OXIA;Ll;0;L;03CC;;;;N;;;1FF9;;1FF9 -1F7A;GREEK SMALL LETTER UPSILON WITH VARIA;Ll;0;L;03C5 0300;;;;N;;;1FEA;;1FEA -1F7B;GREEK SMALL LETTER UPSILON WITH OXIA;Ll;0;L;03CD;;;;N;;;1FEB;;1FEB -1F7C;GREEK SMALL LETTER OMEGA WITH VARIA;Ll;0;L;03C9 0300;;;;N;;;1FFA;;1FFA -1F7D;GREEK SMALL LETTER OMEGA WITH OXIA;Ll;0;L;03CE;;;;N;;;1FFB;;1FFB -1F80;GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F00 0345;;;;N;;;1F88;;1F88 -1F81;GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F01 0345;;;;N;;;1F89;;1F89 -1F82;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F02 0345;;;;N;;;1F8A;;1F8A -1F83;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F03 0345;;;;N;;;1F8B;;1F8B -1F84;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F04 0345;;;;N;;;1F8C;;1F8C -1F85;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F05 0345;;;;N;;;1F8D;;1F8D -1F86;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F06 0345;;;;N;;;1F8E;;1F8E -1F87;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F07 0345;;;;N;;;1F8F;;1F8F -1F88;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F08 0345;;;;N;;;;1F80; -1F89;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F09 0345;;;;N;;;;1F81; -1F8A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0A 0345;;;;N;;;;1F82; -1F8B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0B 0345;;;;N;;;;1F83; -1F8C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0C 0345;;;;N;;;;1F84; -1F8D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0D 0345;;;;N;;;;1F85; -1F8E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0E 0345;;;;N;;;;1F86; -1F8F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0F 0345;;;;N;;;;1F87; -1F90;GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F20 0345;;;;N;;;1F98;;1F98 -1F91;GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F21 0345;;;;N;;;1F99;;1F99 -1F92;GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F22 0345;;;;N;;;1F9A;;1F9A -1F93;GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F23 0345;;;;N;;;1F9B;;1F9B -1F94;GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F24 0345;;;;N;;;1F9C;;1F9C -1F95;GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F25 0345;;;;N;;;1F9D;;1F9D -1F96;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F26 0345;;;;N;;;1F9E;;1F9E -1F97;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F27 0345;;;;N;;;1F9F;;1F9F -1F98;GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F28 0345;;;;N;;;;1F90; -1F99;GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F29 0345;;;;N;;;;1F91; -1F9A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2A 0345;;;;N;;;;1F92; -1F9B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2B 0345;;;;N;;;;1F93; -1F9C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2C 0345;;;;N;;;;1F94; -1F9D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2D 0345;;;;N;;;;1F95; -1F9E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2E 0345;;;;N;;;;1F96; -1F9F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2F 0345;;;;N;;;;1F97; -1FA0;GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F60 0345;;;;N;;;1FA8;;1FA8 -1FA1;GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F61 0345;;;;N;;;1FA9;;1FA9 -1FA2;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F62 0345;;;;N;;;1FAA;;1FAA -1FA3;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F63 0345;;;;N;;;1FAB;;1FAB -1FA4;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F64 0345;;;;N;;;1FAC;;1FAC -1FA5;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F65 0345;;;;N;;;1FAD;;1FAD -1FA6;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F66 0345;;;;N;;;1FAE;;1FAE -1FA7;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F67 0345;;;;N;;;1FAF;;1FAF -1FA8;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F68 0345;;;;N;;;;1FA0; -1FA9;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F69 0345;;;;N;;;;1FA1; -1FAA;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6A 0345;;;;N;;;;1FA2; -1FAB;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6B 0345;;;;N;;;;1FA3; -1FAC;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6C 0345;;;;N;;;;1FA4; -1FAD;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6D 0345;;;;N;;;;1FA5; -1FAE;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6E 0345;;;;N;;;;1FA6; -1FAF;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6F 0345;;;;N;;;;1FA7; -1FB0;GREEK SMALL LETTER ALPHA WITH VRACHY;Ll;0;L;03B1 0306;;;;N;;;1FB8;;1FB8 -1FB1;GREEK SMALL LETTER ALPHA WITH MACRON;Ll;0;L;03B1 0304;;;;N;;;1FB9;;1FB9 -1FB2;GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F70 0345;;;;N;;;;; -1FB3;GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI;Ll;0;L;03B1 0345;;;;N;;;1FBC;;1FBC -1FB4;GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AC 0345;;;;N;;;;; -1FB6;GREEK SMALL LETTER ALPHA WITH PERISPOMENI;Ll;0;L;03B1 0342;;;;N;;;;; -1FB7;GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FB6 0345;;;;N;;;;; -1FB8;GREEK CAPITAL LETTER ALPHA WITH VRACHY;Lu;0;L;0391 0306;;;;N;;;;1FB0; -1FB9;GREEK CAPITAL LETTER ALPHA WITH MACRON;Lu;0;L;0391 0304;;;;N;;;;1FB1; -1FBA;GREEK CAPITAL LETTER ALPHA WITH VARIA;Lu;0;L;0391 0300;;;;N;;;;1F70; -1FBB;GREEK CAPITAL LETTER ALPHA WITH OXIA;Lu;0;L;0386;;;;N;;;;1F71; -1FBC;GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI;Lt;0;L;0391 0345;;;;N;;;;1FB3; -1FBD;GREEK KORONIS;Sk;0;ON;<compat> 0020 0313;;;;N;;;;; -1FBE;GREEK PROSGEGRAMMENI;Ll;0;L;03B9;;;;N;;;0399;;0399 -1FBF;GREEK PSILI;Sk;0;ON;<compat> 0020 0313;;;;N;;;;; -1FC0;GREEK PERISPOMENI;Sk;0;ON;<compat> 0020 0342;;;;N;;;;; -1FC1;GREEK DIALYTIKA AND PERISPOMENI;Sk;0;ON;00A8 0342;;;;N;;;;; -1FC2;GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F74 0345;;;;N;;;;; -1FC3;GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI;Ll;0;L;03B7 0345;;;;N;;;1FCC;;1FCC -1FC4;GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AE 0345;;;;N;;;;; -1FC6;GREEK SMALL LETTER ETA WITH PERISPOMENI;Ll;0;L;03B7 0342;;;;N;;;;; -1FC7;GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FC6 0345;;;;N;;;;; -1FC8;GREEK CAPITAL LETTER EPSILON WITH VARIA;Lu;0;L;0395 0300;;;;N;;;;1F72; -1FC9;GREEK CAPITAL LETTER EPSILON WITH OXIA;Lu;0;L;0388;;;;N;;;;1F73; -1FCA;GREEK CAPITAL LETTER ETA WITH VARIA;Lu;0;L;0397 0300;;;;N;;;;1F74; -1FCB;GREEK CAPITAL LETTER ETA WITH OXIA;Lu;0;L;0389;;;;N;;;;1F75; -1FCC;GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI;Lt;0;L;0397 0345;;;;N;;;;1FC3; -1FCD;GREEK PSILI AND VARIA;Sk;0;ON;1FBF 0300;;;;N;;;;; -1FCE;GREEK PSILI AND OXIA;Sk;0;ON;1FBF 0301;;;;N;;;;; -1FCF;GREEK PSILI AND PERISPOMENI;Sk;0;ON;1FBF 0342;;;;N;;;;; -1FD0;GREEK SMALL LETTER IOTA WITH VRACHY;Ll;0;L;03B9 0306;;;;N;;;1FD8;;1FD8 -1FD1;GREEK SMALL LETTER IOTA WITH MACRON;Ll;0;L;03B9 0304;;;;N;;;1FD9;;1FD9 -1FD2;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA;Ll;0;L;03CA 0300;;;;N;;;;; -1FD3;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA;Ll;0;L;0390;;;;N;;;;; -1FD6;GREEK SMALL LETTER IOTA WITH PERISPOMENI;Ll;0;L;03B9 0342;;;;N;;;;; -1FD7;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CA 0342;;;;N;;;;; -1FD8;GREEK CAPITAL LETTER IOTA WITH VRACHY;Lu;0;L;0399 0306;;;;N;;;;1FD0; -1FD9;GREEK CAPITAL LETTER IOTA WITH MACRON;Lu;0;L;0399 0304;;;;N;;;;1FD1; -1FDA;GREEK CAPITAL LETTER IOTA WITH VARIA;Lu;0;L;0399 0300;;;;N;;;;1F76; -1FDB;GREEK CAPITAL LETTER IOTA WITH OXIA;Lu;0;L;038A;;;;N;;;;1F77; -1FDD;GREEK DASIA AND VARIA;Sk;0;ON;1FFE 0300;;;;N;;;;; -1FDE;GREEK DASIA AND OXIA;Sk;0;ON;1FFE 0301;;;;N;;;;; -1FDF;GREEK DASIA AND PERISPOMENI;Sk;0;ON;1FFE 0342;;;;N;;;;; -1FE0;GREEK SMALL LETTER UPSILON WITH VRACHY;Ll;0;L;03C5 0306;;;;N;;;1FE8;;1FE8 -1FE1;GREEK SMALL LETTER UPSILON WITH MACRON;Ll;0;L;03C5 0304;;;;N;;;1FE9;;1FE9 -1FE2;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA;Ll;0;L;03CB 0300;;;;N;;;;; -1FE3;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA;Ll;0;L;03B0;;;;N;;;;; -1FE4;GREEK SMALL LETTER RHO WITH PSILI;Ll;0;L;03C1 0313;;;;N;;;;; -1FE5;GREEK SMALL LETTER RHO WITH DASIA;Ll;0;L;03C1 0314;;;;N;;;1FEC;;1FEC -1FE6;GREEK SMALL LETTER UPSILON WITH PERISPOMENI;Ll;0;L;03C5 0342;;;;N;;;;; -1FE7;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CB 0342;;;;N;;;;; -1FE8;GREEK CAPITAL LETTER UPSILON WITH VRACHY;Lu;0;L;03A5 0306;;;;N;;;;1FE0; -1FE9;GREEK CAPITAL LETTER UPSILON WITH MACRON;Lu;0;L;03A5 0304;;;;N;;;;1FE1; -1FEA;GREEK CAPITAL LETTER UPSILON WITH VARIA;Lu;0;L;03A5 0300;;;;N;;;;1F7A; -1FEB;GREEK CAPITAL LETTER UPSILON WITH OXIA;Lu;0;L;038E;;;;N;;;;1F7B; -1FEC;GREEK CAPITAL LETTER RHO WITH DASIA;Lu;0;L;03A1 0314;;;;N;;;;1FE5; -1FED;GREEK DIALYTIKA AND VARIA;Sk;0;ON;00A8 0300;;;;N;;;;; -1FEE;GREEK DIALYTIKA AND OXIA;Sk;0;ON;0385;;;;N;;;;; -1FEF;GREEK VARIA;Sk;0;ON;0060;;;;N;;;;; -1FF2;GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F7C 0345;;;;N;;;;; -1FF3;GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI;Ll;0;L;03C9 0345;;;;N;;;1FFC;;1FFC -1FF4;GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03CE 0345;;;;N;;;;; -1FF6;GREEK SMALL LETTER OMEGA WITH PERISPOMENI;Ll;0;L;03C9 0342;;;;N;;;;; -1FF7;GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FF6 0345;;;;N;;;;; -1FF8;GREEK CAPITAL LETTER OMICRON WITH VARIA;Lu;0;L;039F 0300;;;;N;;;;1F78; -1FF9;GREEK CAPITAL LETTER OMICRON WITH OXIA;Lu;0;L;038C;;;;N;;;;1F79; -1FFA;GREEK CAPITAL LETTER OMEGA WITH VARIA;Lu;0;L;03A9 0300;;;;N;;;;1F7C; -1FFB;GREEK CAPITAL LETTER OMEGA WITH OXIA;Lu;0;L;038F;;;;N;;;;1F7D; -1FFC;GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI;Lt;0;L;03A9 0345;;;;N;;;;1FF3; -1FFD;GREEK OXIA;Sk;0;ON;00B4;;;;N;;;;; -1FFE;GREEK DASIA;Sk;0;ON;<compat> 0020 0314;;;;N;;;;; -2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;; -2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;; -2002;EN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; -2003;EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; -2004;THREE-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; -2005;FOUR-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; -2006;SIX-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; -2007;FIGURE SPACE;Zs;0;WS;<noBreak> 0020;;;;N;;;;; -2008;PUNCTUATION SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; -2009;THIN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; -200A;HAIR SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; -200B;ZERO WIDTH SPACE;Cf;0;BN;;;;;N;;;;; -200C;ZERO WIDTH NON-JOINER;Cf;0;BN;;;;;N;;;;; -200D;ZERO WIDTH JOINER;Cf;0;BN;;;;;N;;;;; -200E;LEFT-TO-RIGHT MARK;Cf;0;L;;;;;N;;;;; -200F;RIGHT-TO-LEFT MARK;Cf;0;R;;;;;N;;;;; -2010;HYPHEN;Pd;0;ON;;;;;N;;;;; -2011;NON-BREAKING HYPHEN;Pd;0;ON;<noBreak> 2010;;;;N;;;;; -2012;FIGURE DASH;Pd;0;ON;;;;;N;;;;; -2013;EN DASH;Pd;0;ON;;;;;N;;;;; -2014;EM DASH;Pd;0;ON;;;;;N;;;;; -2015;HORIZONTAL BAR;Pd;0;ON;;;;;N;QUOTATION DASH;;;; -2016;DOUBLE VERTICAL LINE;Po;0;ON;;;;;N;DOUBLE VERTICAL BAR;;;; -2017;DOUBLE LOW LINE;Po;0;ON;<compat> 0020 0333;;;;N;SPACING DOUBLE UNDERSCORE;;;; -2018;LEFT SINGLE QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE TURNED COMMA QUOTATION MARK;;;; -2019;RIGHT SINGLE QUOTATION MARK;Pf;0;ON;;;;;N;SINGLE COMMA QUOTATION MARK;;;; -201A;SINGLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW SINGLE COMMA QUOTATION MARK;;;; -201B;SINGLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE REVERSED COMMA QUOTATION MARK;;;; -201C;LEFT DOUBLE QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE TURNED COMMA QUOTATION MARK;;;; -201D;RIGHT DOUBLE QUOTATION MARK;Pf;0;ON;;;;;N;DOUBLE COMMA QUOTATION MARK;;;; -201E;DOUBLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW DOUBLE COMMA QUOTATION MARK;;;; -201F;DOUBLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE REVERSED COMMA QUOTATION MARK;;;; -2020;DAGGER;Po;0;ON;;;;;N;;;;; -2021;DOUBLE DAGGER;Po;0;ON;;;;;N;;;;; -2022;BULLET;Po;0;ON;;;;;N;;;;; -2023;TRIANGULAR BULLET;Po;0;ON;;;;;N;;;;; -2024;ONE DOT LEADER;Po;0;ON;<compat> 002E;;;;N;;;;; -2025;TWO DOT LEADER;Po;0;ON;<compat> 002E 002E;;;;N;;;;; -2026;HORIZONTAL ELLIPSIS;Po;0;ON;<compat> 002E 002E 002E;;;;N;;;;; -2027;HYPHENATION POINT;Po;0;ON;;;;;N;;;;; -2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; -2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; -202A;LEFT-TO-RIGHT EMBEDDING;Cf;0;LRE;;;;;N;;;;; -202B;RIGHT-TO-LEFT EMBEDDING;Cf;0;RLE;;;;;N;;;;; -202C;POP DIRECTIONAL FORMATTING;Cf;0;PDF;;;;;N;;;;; -202D;LEFT-TO-RIGHT OVERRIDE;Cf;0;LRO;;;;;N;;;;; -202E;RIGHT-TO-LEFT OVERRIDE;Cf;0;RLO;;;;;N;;;;; -202F;NARROW NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;;;;; -2030;PER MILLE SIGN;Po;0;ET;;;;;N;;;;; -2031;PER TEN THOUSAND SIGN;Po;0;ET;;;;;N;;;;; -2032;PRIME;Po;0;ET;;;;;N;;;;; -2033;DOUBLE PRIME;Po;0;ET;<compat> 2032 2032;;;;N;;;;; -2034;TRIPLE PRIME;Po;0;ET;<compat> 2032 2032 2032;;;;N;;;;; -2035;REVERSED PRIME;Po;0;ON;;;;;N;;;;; -2036;REVERSED DOUBLE PRIME;Po;0;ON;<compat> 2035 2035;;;;N;;;;; -2037;REVERSED TRIPLE PRIME;Po;0;ON;<compat> 2035 2035 2035;;;;N;;;;; -2038;CARET;Po;0;ON;;;;;N;;;;; -2039;SINGLE LEFT-POINTING ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING SINGLE GUILLEMET;;;; -203A;SINGLE RIGHT-POINTING ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING SINGLE GUILLEMET;;;; -203B;REFERENCE MARK;Po;0;ON;;;;;N;;;;; -203C;DOUBLE EXCLAMATION MARK;Po;0;ON;<compat> 0021 0021;;;;N;;;;; -203D;INTERROBANG;Po;0;ON;;;;;N;;;;; -203E;OVERLINE;Po;0;ON;<compat> 0020 0305;;;;N;SPACING OVERSCORE;;;; -203F;UNDERTIE;Pc;0;ON;;;;;N;;;;; -2040;CHARACTER TIE;Pc;0;ON;;;;;N;;;;; -2041;CARET INSERTION POINT;Po;0;ON;;;;;N;;;;; -2042;ASTERISM;Po;0;ON;;;;;N;;;;; -2043;HYPHEN BULLET;Po;0;ON;;;;;N;;;;; -2044;FRACTION SLASH;Sm;0;CS;;;;;N;;;;; -2045;LEFT SQUARE BRACKET WITH QUILL;Ps;0;ON;;;;;Y;;;;; -2046;RIGHT SQUARE BRACKET WITH QUILL;Pe;0;ON;;;;;Y;;;;; -2047;DOUBLE QUESTION MARK;Po;0;ON;<compat> 003F 003F;;;;N;;;;; -2048;QUESTION EXCLAMATION MARK;Po;0;ON;<compat> 003F 0021;;;;N;;;;; -2049;EXCLAMATION QUESTION MARK;Po;0;ON;<compat> 0021 003F;;;;N;;;;; -204A;TIRONIAN SIGN ET;Po;0;ON;;;;;N;;;;; -204B;REVERSED PILCROW SIGN;Po;0;ON;;;;;N;;;;; -204C;BLACK LEFTWARDS BULLET;Po;0;ON;;;;;N;;;;; -204D;BLACK RIGHTWARDS BULLET;Po;0;ON;;;;;N;;;;; -204E;LOW ASTERISK;Po;0;ON;;;;;N;;;;; -204F;REVERSED SEMICOLON;Po;0;ON;;;;;N;;;;; -2050;CLOSE UP;Po;0;ON;;;;;N;;;;; -2051;TWO ASTERISKS ALIGNED VERTICALLY;Po;0;ON;;;;;N;;;;; -2052;COMMERCIAL MINUS SIGN;Sm;0;ON;;;;;N;;;;; -2053;SWUNG DASH;Po;0;ON;;;;;N;;;;; -2054;INVERTED UNDERTIE;Pc;0;ON;;;;;N;;;;; -2055;FLOWER PUNCTUATION MARK;Po;0;ON;;;;;N;;;;; -2056;THREE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; -2057;QUADRUPLE PRIME;Po;0;ON;<compat> 2032 2032 2032 2032;;;;N;;;;; -2058;FOUR DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; -2059;FIVE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; -205A;TWO DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; -205B;FOUR DOT MARK;Po;0;ON;;;;;N;;;;; -205C;DOTTED CROSS;Po;0;ON;;;;;N;;;;; -205D;TRICOLON;Po;0;ON;;;;;N;;;;; -205E;VERTICAL FOUR DOTS;Po;0;ON;;;;;N;;;;; -205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; -2060;WORD JOINER;Cf;0;BN;;;;;N;;;;; -2061;FUNCTION APPLICATION;Cf;0;BN;;;;;N;;;;; -2062;INVISIBLE TIMES;Cf;0;BN;;;;;N;;;;; -2063;INVISIBLE SEPARATOR;Cf;0;BN;;;;;N;;;;; -2064;INVISIBLE PLUS;Cf;0;BN;;;;;N;;;;; -2066;LEFT-TO-RIGHT ISOLATE;Cf;0;LRI;;;;;N;;;;; -2067;RIGHT-TO-LEFT ISOLATE;Cf;0;RLI;;;;;N;;;;; -2068;FIRST STRONG ISOLATE;Cf;0;FSI;;;;;N;;;;; -2069;POP DIRECTIONAL ISOLATE;Cf;0;PDI;;;;;N;;;;; -206A;INHIBIT SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;; -206B;ACTIVATE SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;; -206C;INHIBIT ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;; -206D;ACTIVATE ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;; -206E;NATIONAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;; -206F;NOMINAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;; -2070;SUPERSCRIPT ZERO;No;0;EN;<super> 0030;;0;0;N;SUPERSCRIPT DIGIT ZERO;;;; -2071;SUPERSCRIPT LATIN SMALL LETTER I;Lm;0;L;<super> 0069;;;;N;;;;; -2074;SUPERSCRIPT FOUR;No;0;EN;<super> 0034;;4;4;N;SUPERSCRIPT DIGIT FOUR;;;; -2075;SUPERSCRIPT FIVE;No;0;EN;<super> 0035;;5;5;N;SUPERSCRIPT DIGIT FIVE;;;; -2076;SUPERSCRIPT SIX;No;0;EN;<super> 0036;;6;6;N;SUPERSCRIPT DIGIT SIX;;;; -2077;SUPERSCRIPT SEVEN;No;0;EN;<super> 0037;;7;7;N;SUPERSCRIPT DIGIT SEVEN;;;; -2078;SUPERSCRIPT EIGHT;No;0;EN;<super> 0038;;8;8;N;SUPERSCRIPT DIGIT EIGHT;;;; -2079;SUPERSCRIPT NINE;No;0;EN;<super> 0039;;9;9;N;SUPERSCRIPT DIGIT NINE;;;; -207A;SUPERSCRIPT PLUS SIGN;Sm;0;ES;<super> 002B;;;;N;;;;; -207B;SUPERSCRIPT MINUS;Sm;0;ES;<super> 2212;;;;N;SUPERSCRIPT HYPHEN-MINUS;;;; -207C;SUPERSCRIPT EQUALS SIGN;Sm;0;ON;<super> 003D;;;;N;;;;; -207D;SUPERSCRIPT LEFT PARENTHESIS;Ps;0;ON;<super> 0028;;;;Y;SUPERSCRIPT OPENING PARENTHESIS;;;; -207E;SUPERSCRIPT RIGHT PARENTHESIS;Pe;0;ON;<super> 0029;;;;Y;SUPERSCRIPT CLOSING PARENTHESIS;;;; -207F;SUPERSCRIPT LATIN SMALL LETTER N;Lm;0;L;<super> 006E;;;;N;;;;; -2080;SUBSCRIPT ZERO;No;0;EN;<sub> 0030;;0;0;N;SUBSCRIPT DIGIT ZERO;;;; -2081;SUBSCRIPT ONE;No;0;EN;<sub> 0031;;1;1;N;SUBSCRIPT DIGIT ONE;;;; -2082;SUBSCRIPT TWO;No;0;EN;<sub> 0032;;2;2;N;SUBSCRIPT DIGIT TWO;;;; -2083;SUBSCRIPT THREE;No;0;EN;<sub> 0033;;3;3;N;SUBSCRIPT DIGIT THREE;;;; -2084;SUBSCRIPT FOUR;No;0;EN;<sub> 0034;;4;4;N;SUBSCRIPT DIGIT FOUR;;;; -2085;SUBSCRIPT FIVE;No;0;EN;<sub> 0035;;5;5;N;SUBSCRIPT DIGIT FIVE;;;; -2086;SUBSCRIPT SIX;No;0;EN;<sub> 0036;;6;6;N;SUBSCRIPT DIGIT SIX;;;; -2087;SUBSCRIPT SEVEN;No;0;EN;<sub> 0037;;7;7;N;SUBSCRIPT DIGIT SEVEN;;;; -2088;SUBSCRIPT EIGHT;No;0;EN;<sub> 0038;;8;8;N;SUBSCRIPT DIGIT EIGHT;;;; -2089;SUBSCRIPT NINE;No;0;EN;<sub> 0039;;9;9;N;SUBSCRIPT DIGIT NINE;;;; -208A;SUBSCRIPT PLUS SIGN;Sm;0;ES;<sub> 002B;;;;N;;;;; -208B;SUBSCRIPT MINUS;Sm;0;ES;<sub> 2212;;;;N;SUBSCRIPT HYPHEN-MINUS;;;; -208C;SUBSCRIPT EQUALS SIGN;Sm;0;ON;<sub> 003D;;;;N;;;;; -208D;SUBSCRIPT LEFT PARENTHESIS;Ps;0;ON;<sub> 0028;;;;Y;SUBSCRIPT OPENING PARENTHESIS;;;; -208E;SUBSCRIPT RIGHT PARENTHESIS;Pe;0;ON;<sub> 0029;;;;Y;SUBSCRIPT CLOSING PARENTHESIS;;;; -2090;LATIN SUBSCRIPT SMALL LETTER A;Lm;0;L;<sub> 0061;;;;N;;;;; -2091;LATIN SUBSCRIPT SMALL LETTER E;Lm;0;L;<sub> 0065;;;;N;;;;; -2092;LATIN SUBSCRIPT SMALL LETTER O;Lm;0;L;<sub> 006F;;;;N;;;;; -2093;LATIN SUBSCRIPT SMALL LETTER X;Lm;0;L;<sub> 0078;;;;N;;;;; -2094;LATIN SUBSCRIPT SMALL LETTER SCHWA;Lm;0;L;<sub> 0259;;;;N;;;;; -2095;LATIN SUBSCRIPT SMALL LETTER H;Lm;0;L;<sub> 0068;;;;N;;;;; -2096;LATIN SUBSCRIPT SMALL LETTER K;Lm;0;L;<sub> 006B;;;;N;;;;; -2097;LATIN SUBSCRIPT SMALL LETTER L;Lm;0;L;<sub> 006C;;;;N;;;;; -2098;LATIN SUBSCRIPT SMALL LETTER M;Lm;0;L;<sub> 006D;;;;N;;;;; -2099;LATIN SUBSCRIPT SMALL LETTER N;Lm;0;L;<sub> 006E;;;;N;;;;; -209A;LATIN SUBSCRIPT SMALL LETTER P;Lm;0;L;<sub> 0070;;;;N;;;;; -209B;LATIN SUBSCRIPT SMALL LETTER S;Lm;0;L;<sub> 0073;;;;N;;;;; -209C;LATIN SUBSCRIPT SMALL LETTER T;Lm;0;L;<sub> 0074;;;;N;;;;; -20A0;EURO-CURRENCY SIGN;Sc;0;ET;;;;;N;;;;; -20A1;COLON SIGN;Sc;0;ET;;;;;N;;;;; -20A2;CRUZEIRO SIGN;Sc;0;ET;;;;;N;;;;; -20A3;FRENCH FRANC SIGN;Sc;0;ET;;;;;N;;;;; -20A4;LIRA SIGN;Sc;0;ET;;;;;N;;;;; -20A5;MILL SIGN;Sc;0;ET;;;;;N;;;;; -20A6;NAIRA SIGN;Sc;0;ET;;;;;N;;;;; -20A7;PESETA SIGN;Sc;0;ET;;;;;N;;;;; -20A8;RUPEE SIGN;Sc;0;ET;<compat> 0052 0073;;;;N;;;;; -20A9;WON SIGN;Sc;0;ET;;;;;N;;;;; -20AA;NEW SHEQEL SIGN;Sc;0;ET;;;;;N;;;;; -20AB;DONG SIGN;Sc;0;ET;;;;;N;;;;; -20AC;EURO SIGN;Sc;0;ET;;;;;N;;;;; -20AD;KIP SIGN;Sc;0;ET;;;;;N;;;;; -20AE;TUGRIK SIGN;Sc;0;ET;;;;;N;;;;; -20AF;DRACHMA SIGN;Sc;0;ET;;;;;N;;;;; -20B0;GERMAN PENNY SIGN;Sc;0;ET;;;;;N;;;;; -20B1;PESO SIGN;Sc;0;ET;;;;;N;;;;; -20B2;GUARANI SIGN;Sc;0;ET;;;;;N;;;;; -20B3;AUSTRAL SIGN;Sc;0;ET;;;;;N;;;;; -20B4;HRYVNIA SIGN;Sc;0;ET;;;;;N;;;;; -20B5;CEDI SIGN;Sc;0;ET;;;;;N;;;;; -20B6;LIVRE TOURNOIS SIGN;Sc;0;ET;;;;;N;;;;; -20B7;SPESMILO SIGN;Sc;0;ET;;;;;N;;;;; -20B8;TENGE SIGN;Sc;0;ET;;;;;N;;;;; -20B9;INDIAN RUPEE SIGN;Sc;0;ET;;;;;N;;;;; -20BA;TURKISH LIRA SIGN;Sc;0;ET;;;;;N;;;;; -20BB;NORDIC MARK SIGN;Sc;0;ET;;;;;N;;;;; -20BC;MANAT SIGN;Sc;0;ET;;;;;N;;;;; -20BD;RUBLE SIGN;Sc;0;ET;;;;;N;;;;; -20BE;LARI SIGN;Sc;0;ET;;;;;N;;;;; -20BF;BITCOIN SIGN;Sc;0;ET;;;;;N;;;;; -20C0;SOM SIGN;Sc;0;ET;;;;;N;;;;; -20D0;COMBINING LEFT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT HARPOON ABOVE;;;; -20D1;COMBINING RIGHT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT HARPOON ABOVE;;;; -20D2;COMBINING LONG VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG VERTICAL BAR OVERLAY;;;; -20D3;COMBINING SHORT VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT VERTICAL BAR OVERLAY;;;; -20D4;COMBINING ANTICLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING ANTICLOCKWISE ARROW ABOVE;;;; -20D5;COMBINING CLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING CLOCKWISE ARROW ABOVE;;;; -20D6;COMBINING LEFT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT ARROW ABOVE;;;; -20D7;COMBINING RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT ARROW ABOVE;;;; -20D8;COMBINING RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING RING OVERLAY;;;; -20D9;COMBINING CLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING CLOCKWISE RING OVERLAY;;;; -20DA;COMBINING ANTICLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING ANTICLOCKWISE RING OVERLAY;;;; -20DB;COMBINING THREE DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING THREE DOTS ABOVE;;;; -20DC;COMBINING FOUR DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING FOUR DOTS ABOVE;;;; -20DD;COMBINING ENCLOSING CIRCLE;Me;0;NSM;;;;;N;ENCLOSING CIRCLE;;;; -20DE;COMBINING ENCLOSING SQUARE;Me;0;NSM;;;;;N;ENCLOSING SQUARE;;;; -20DF;COMBINING ENCLOSING DIAMOND;Me;0;NSM;;;;;N;ENCLOSING DIAMOND;;;; -20E0;COMBINING ENCLOSING CIRCLE BACKSLASH;Me;0;NSM;;;;;N;ENCLOSING CIRCLE SLASH;;;; -20E1;COMBINING LEFT RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT RIGHT ARROW ABOVE;;;; -20E2;COMBINING ENCLOSING SCREEN;Me;0;NSM;;;;;N;;;;; -20E3;COMBINING ENCLOSING KEYCAP;Me;0;NSM;;;;;N;;;;; -20E4;COMBINING ENCLOSING UPWARD POINTING TRIANGLE;Me;0;NSM;;;;;N;;;;; -20E5;COMBINING REVERSE SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;;;;; -20E6;COMBINING DOUBLE VERTICAL STROKE OVERLAY;Mn;1;NSM;;;;;N;;;;; -20E7;COMBINING ANNUITY SYMBOL;Mn;230;NSM;;;;;N;;;;; -20E8;COMBINING TRIPLE UNDERDOT;Mn;220;NSM;;;;;N;;;;; -20E9;COMBINING WIDE BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;; -20EA;COMBINING LEFTWARDS ARROW OVERLAY;Mn;1;NSM;;;;;N;;;;; -20EB;COMBINING LONG DOUBLE SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;;;;; -20EC;COMBINING RIGHTWARDS HARPOON WITH BARB DOWNWARDS;Mn;220;NSM;;;;;N;;;;; -20ED;COMBINING LEFTWARDS HARPOON WITH BARB DOWNWARDS;Mn;220;NSM;;;;;N;;;;; -20EE;COMBINING LEFT ARROW BELOW;Mn;220;NSM;;;;;N;;;;; -20EF;COMBINING RIGHT ARROW BELOW;Mn;220;NSM;;;;;N;;;;; -20F0;COMBINING ASTERISK ABOVE;Mn;230;NSM;;;;;N;;;;; -2100;ACCOUNT OF;So;0;ON;<compat> 0061 002F 0063;;;;N;;;;; -2101;ADDRESSED TO THE SUBJECT;So;0;ON;<compat> 0061 002F 0073;;;;N;;;;; -2102;DOUBLE-STRUCK CAPITAL C;Lu;0;L;<font> 0043;;;;N;DOUBLE-STRUCK C;;;; -2103;DEGREE CELSIUS;So;0;ON;<compat> 00B0 0043;;;;N;DEGREES CENTIGRADE;;;; -2104;CENTRE LINE SYMBOL;So;0;ON;;;;;N;C L SYMBOL;;;; -2105;CARE OF;So;0;ON;<compat> 0063 002F 006F;;;;N;;;;; -2106;CADA UNA;So;0;ON;<compat> 0063 002F 0075;;;;N;;;;; -2107;EULER CONSTANT;Lu;0;L;<compat> 0190;;;;N;EULERS;;;; -2108;SCRUPLE;So;0;ON;;;;;N;;;;; -2109;DEGREE FAHRENHEIT;So;0;ON;<compat> 00B0 0046;;;;N;DEGREES FAHRENHEIT;;;; -210A;SCRIPT SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; -210B;SCRIPT CAPITAL H;Lu;0;L;<font> 0048;;;;N;SCRIPT H;;;; -210C;BLACK-LETTER CAPITAL H;Lu;0;L;<font> 0048;;;;N;BLACK-LETTER H;;;; -210D;DOUBLE-STRUCK CAPITAL H;Lu;0;L;<font> 0048;;;;N;DOUBLE-STRUCK H;;;; -210E;PLANCK CONSTANT;Ll;0;L;<font> 0068;;;;N;;;;; -210F;PLANCK CONSTANT OVER TWO PI;Ll;0;L;<font> 0127;;;;N;PLANCK CONSTANT OVER 2 PI;;;; -2110;SCRIPT CAPITAL I;Lu;0;L;<font> 0049;;;;N;SCRIPT I;;;; -2111;BLACK-LETTER CAPITAL I;Lu;0;L;<font> 0049;;;;N;BLACK-LETTER I;;;; -2112;SCRIPT CAPITAL L;Lu;0;L;<font> 004C;;;;N;SCRIPT L;;;; -2113;SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; -2114;L B BAR SYMBOL;So;0;ON;;;;;N;;;;; -2115;DOUBLE-STRUCK CAPITAL N;Lu;0;L;<font> 004E;;;;N;DOUBLE-STRUCK N;;;; -2116;NUMERO SIGN;So;0;ON;<compat> 004E 006F;;;;N;NUMERO;;;; -2117;SOUND RECORDING COPYRIGHT;So;0;ON;;;;;N;;;;; -2118;SCRIPT CAPITAL P;Sm;0;ON;;;;;N;SCRIPT P;;;; -2119;DOUBLE-STRUCK CAPITAL P;Lu;0;L;<font> 0050;;;;N;DOUBLE-STRUCK P;;;; -211A;DOUBLE-STRUCK CAPITAL Q;Lu;0;L;<font> 0051;;;;N;DOUBLE-STRUCK Q;;;; -211B;SCRIPT CAPITAL R;Lu;0;L;<font> 0052;;;;N;SCRIPT R;;;; -211C;BLACK-LETTER CAPITAL R;Lu;0;L;<font> 0052;;;;N;BLACK-LETTER R;;;; -211D;DOUBLE-STRUCK CAPITAL R;Lu;0;L;<font> 0052;;;;N;DOUBLE-STRUCK R;;;; -211E;PRESCRIPTION TAKE;So;0;ON;;;;;N;;;;; -211F;RESPONSE;So;0;ON;;;;;N;;;;; -2120;SERVICE MARK;So;0;ON;<super> 0053 004D;;;;N;;;;; -2121;TELEPHONE SIGN;So;0;ON;<compat> 0054 0045 004C;;;;N;T E L SYMBOL;;;; -2122;TRADE MARK SIGN;So;0;ON;<super> 0054 004D;;;;N;TRADEMARK;;;; -2123;VERSICLE;So;0;ON;;;;;N;;;;; -2124;DOUBLE-STRUCK CAPITAL Z;Lu;0;L;<font> 005A;;;;N;DOUBLE-STRUCK Z;;;; -2125;OUNCE SIGN;So;0;ON;;;;;N;OUNCE;;;; -2126;OHM SIGN;Lu;0;L;03A9;;;;N;OHM;;;03C9; -2127;INVERTED OHM SIGN;So;0;ON;;;;;N;MHO;;;; -2128;BLACK-LETTER CAPITAL Z;Lu;0;L;<font> 005A;;;;N;BLACK-LETTER Z;;;; -2129;TURNED GREEK SMALL LETTER IOTA;So;0;ON;;;;;N;;;;; -212A;KELVIN SIGN;Lu;0;L;004B;;;;N;DEGREES KELVIN;;;006B; -212B;ANGSTROM SIGN;Lu;0;L;00C5;;;;N;ANGSTROM UNIT;;;00E5; -212C;SCRIPT CAPITAL B;Lu;0;L;<font> 0042;;;;N;SCRIPT B;;;; -212D;BLACK-LETTER CAPITAL C;Lu;0;L;<font> 0043;;;;N;BLACK-LETTER C;;;; -212E;ESTIMATED SYMBOL;So;0;ET;;;;;N;;;;; -212F;SCRIPT SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; -2130;SCRIPT CAPITAL E;Lu;0;L;<font> 0045;;;;N;SCRIPT E;;;; -2131;SCRIPT CAPITAL F;Lu;0;L;<font> 0046;;;;N;SCRIPT F;;;; -2132;TURNED CAPITAL F;Lu;0;L;;;;;N;TURNED F;;;214E; -2133;SCRIPT CAPITAL M;Lu;0;L;<font> 004D;;;;N;SCRIPT M;;;; -2134;SCRIPT SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; -2135;ALEF SYMBOL;Lo;0;L;<compat> 05D0;;;;N;FIRST TRANSFINITE CARDINAL;;;; -2136;BET SYMBOL;Lo;0;L;<compat> 05D1;;;;N;SECOND TRANSFINITE CARDINAL;;;; -2137;GIMEL SYMBOL;Lo;0;L;<compat> 05D2;;;;N;THIRD TRANSFINITE CARDINAL;;;; -2138;DALET SYMBOL;Lo;0;L;<compat> 05D3;;;;N;FOURTH TRANSFINITE CARDINAL;;;; -2139;INFORMATION SOURCE;Ll;0;L;<font> 0069;;;;N;;;;; -213A;ROTATED CAPITAL Q;So;0;ON;;;;;N;;;;; -213B;FACSIMILE SIGN;So;0;ON;<compat> 0046 0041 0058;;;;N;;;;; -213C;DOUBLE-STRUCK SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;; -213D;DOUBLE-STRUCK SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;; -213E;DOUBLE-STRUCK CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;; -213F;DOUBLE-STRUCK CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;; -2140;DOUBLE-STRUCK N-ARY SUMMATION;Sm;0;ON;<font> 2211;;;;Y;;;;; -2141;TURNED SANS-SERIF CAPITAL G;Sm;0;ON;;;;;N;;;;; -2142;TURNED SANS-SERIF CAPITAL L;Sm;0;ON;;;;;N;;;;; -2143;REVERSED SANS-SERIF CAPITAL L;Sm;0;ON;;;;;N;;;;; -2144;TURNED SANS-SERIF CAPITAL Y;Sm;0;ON;;;;;N;;;;; -2145;DOUBLE-STRUCK ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; -2146;DOUBLE-STRUCK ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; -2147;DOUBLE-STRUCK ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; -2148;DOUBLE-STRUCK ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; -2149;DOUBLE-STRUCK ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; -214A;PROPERTY LINE;So;0;ON;;;;;N;;;;; -214B;TURNED AMPERSAND;Sm;0;ON;;;;;N;;;;; -214C;PER SIGN;So;0;ON;;;;;N;;;;; -214D;AKTIESELSKAB;So;0;ON;;;;;N;;;;; -214E;TURNED SMALL F;Ll;0;L;;;;;N;;;2132;;2132 -214F;SYMBOL FOR SAMARITAN SOURCE;So;0;L;;;;;N;;;;; -2150;VULGAR FRACTION ONE SEVENTH;No;0;ON;<fraction> 0031 2044 0037;;;1/7;N;;;;; -2151;VULGAR FRACTION ONE NINTH;No;0;ON;<fraction> 0031 2044 0039;;;1/9;N;;;;; -2152;VULGAR FRACTION ONE TENTH;No;0;ON;<fraction> 0031 2044 0031 0030;;;1/10;N;;;;; -2153;VULGAR FRACTION ONE THIRD;No;0;ON;<fraction> 0031 2044 0033;;;1/3;N;FRACTION ONE THIRD;;;; -2154;VULGAR FRACTION TWO THIRDS;No;0;ON;<fraction> 0032 2044 0033;;;2/3;N;FRACTION TWO THIRDS;;;; -2155;VULGAR FRACTION ONE FIFTH;No;0;ON;<fraction> 0031 2044 0035;;;1/5;N;FRACTION ONE FIFTH;;;; -2156;VULGAR FRACTION TWO FIFTHS;No;0;ON;<fraction> 0032 2044 0035;;;2/5;N;FRACTION TWO FIFTHS;;;; -2157;VULGAR FRACTION THREE FIFTHS;No;0;ON;<fraction> 0033 2044 0035;;;3/5;N;FRACTION THREE FIFTHS;;;; -2158;VULGAR FRACTION FOUR FIFTHS;No;0;ON;<fraction> 0034 2044 0035;;;4/5;N;FRACTION FOUR FIFTHS;;;; -2159;VULGAR FRACTION ONE SIXTH;No;0;ON;<fraction> 0031 2044 0036;;;1/6;N;FRACTION ONE SIXTH;;;; -215A;VULGAR FRACTION FIVE SIXTHS;No;0;ON;<fraction> 0035 2044 0036;;;5/6;N;FRACTION FIVE SIXTHS;;;; -215B;VULGAR FRACTION ONE EIGHTH;No;0;ON;<fraction> 0031 2044 0038;;;1/8;N;FRACTION ONE EIGHTH;;;; -215C;VULGAR FRACTION THREE EIGHTHS;No;0;ON;<fraction> 0033 2044 0038;;;3/8;N;FRACTION THREE EIGHTHS;;;; -215D;VULGAR FRACTION FIVE EIGHTHS;No;0;ON;<fraction> 0035 2044 0038;;;5/8;N;FRACTION FIVE EIGHTHS;;;; -215E;VULGAR FRACTION SEVEN EIGHTHS;No;0;ON;<fraction> 0037 2044 0038;;;7/8;N;FRACTION SEVEN EIGHTHS;;;; -215F;FRACTION NUMERATOR ONE;No;0;ON;<fraction> 0031 2044;;;1;N;;;;; -2160;ROMAN NUMERAL ONE;Nl;0;L;<compat> 0049;;;1;N;;;;2170; -2161;ROMAN NUMERAL TWO;Nl;0;L;<compat> 0049 0049;;;2;N;;;;2171; -2162;ROMAN NUMERAL THREE;Nl;0;L;<compat> 0049 0049 0049;;;3;N;;;;2172; -2163;ROMAN NUMERAL FOUR;Nl;0;L;<compat> 0049 0056;;;4;N;;;;2173; -2164;ROMAN NUMERAL FIVE;Nl;0;L;<compat> 0056;;;5;N;;;;2174; -2165;ROMAN NUMERAL SIX;Nl;0;L;<compat> 0056 0049;;;6;N;;;;2175; -2166;ROMAN NUMERAL SEVEN;Nl;0;L;<compat> 0056 0049 0049;;;7;N;;;;2176; -2167;ROMAN NUMERAL EIGHT;Nl;0;L;<compat> 0056 0049 0049 0049;;;8;N;;;;2177; -2168;ROMAN NUMERAL NINE;Nl;0;L;<compat> 0049 0058;;;9;N;;;;2178; -2169;ROMAN NUMERAL TEN;Nl;0;L;<compat> 0058;;;10;N;;;;2179; -216A;ROMAN NUMERAL ELEVEN;Nl;0;L;<compat> 0058 0049;;;11;N;;;;217A; -216B;ROMAN NUMERAL TWELVE;Nl;0;L;<compat> 0058 0049 0049;;;12;N;;;;217B; -216C;ROMAN NUMERAL FIFTY;Nl;0;L;<compat> 004C;;;50;N;;;;217C; -216D;ROMAN NUMERAL ONE HUNDRED;Nl;0;L;<compat> 0043;;;100;N;;;;217D; -216E;ROMAN NUMERAL FIVE HUNDRED;Nl;0;L;<compat> 0044;;;500;N;;;;217E; -216F;ROMAN NUMERAL ONE THOUSAND;Nl;0;L;<compat> 004D;;;1000;N;;;;217F; -2170;SMALL ROMAN NUMERAL ONE;Nl;0;L;<compat> 0069;;;1;N;;;2160;;2160 -2171;SMALL ROMAN NUMERAL TWO;Nl;0;L;<compat> 0069 0069;;;2;N;;;2161;;2161 -2172;SMALL ROMAN NUMERAL THREE;Nl;0;L;<compat> 0069 0069 0069;;;3;N;;;2162;;2162 -2173;SMALL ROMAN NUMERAL FOUR;Nl;0;L;<compat> 0069 0076;;;4;N;;;2163;;2163 -2174;SMALL ROMAN NUMERAL FIVE;Nl;0;L;<compat> 0076;;;5;N;;;2164;;2164 -2175;SMALL ROMAN NUMERAL SIX;Nl;0;L;<compat> 0076 0069;;;6;N;;;2165;;2165 -2176;SMALL ROMAN NUMERAL SEVEN;Nl;0;L;<compat> 0076 0069 0069;;;7;N;;;2166;;2166 -2177;SMALL ROMAN NUMERAL EIGHT;Nl;0;L;<compat> 0076 0069 0069 0069;;;8;N;;;2167;;2167 -2178;SMALL ROMAN NUMERAL NINE;Nl;0;L;<compat> 0069 0078;;;9;N;;;2168;;2168 -2179;SMALL ROMAN NUMERAL TEN;Nl;0;L;<compat> 0078;;;10;N;;;2169;;2169 -217A;SMALL ROMAN NUMERAL ELEVEN;Nl;0;L;<compat> 0078 0069;;;11;N;;;216A;;216A -217B;SMALL ROMAN NUMERAL TWELVE;Nl;0;L;<compat> 0078 0069 0069;;;12;N;;;216B;;216B -217C;SMALL ROMAN NUMERAL FIFTY;Nl;0;L;<compat> 006C;;;50;N;;;216C;;216C -217D;SMALL ROMAN NUMERAL ONE HUNDRED;Nl;0;L;<compat> 0063;;;100;N;;;216D;;216D -217E;SMALL ROMAN NUMERAL FIVE HUNDRED;Nl;0;L;<compat> 0064;;;500;N;;;216E;;216E -217F;SMALL ROMAN NUMERAL ONE THOUSAND;Nl;0;L;<compat> 006D;;;1000;N;;;216F;;216F -2180;ROMAN NUMERAL ONE THOUSAND C D;Nl;0;L;;;;1000;N;;;;; -2181;ROMAN NUMERAL FIVE THOUSAND;Nl;0;L;;;;5000;N;;;;; -2182;ROMAN NUMERAL TEN THOUSAND;Nl;0;L;;;;10000;N;;;;; -2183;ROMAN NUMERAL REVERSED ONE HUNDRED;Lu;0;L;;;;;N;;;;2184; -2184;LATIN SMALL LETTER REVERSED C;Ll;0;L;;;;;N;;;2183;;2183 -2185;ROMAN NUMERAL SIX LATE FORM;Nl;0;L;;;;6;N;;;;; -2186;ROMAN NUMERAL FIFTY EARLY FORM;Nl;0;L;;;;50;N;;;;; -2187;ROMAN NUMERAL FIFTY THOUSAND;Nl;0;L;;;;50000;N;;;;; -2188;ROMAN NUMERAL ONE HUNDRED THOUSAND;Nl;0;L;;;;100000;N;;;;; -2189;VULGAR FRACTION ZERO THIRDS;No;0;ON;<fraction> 0030 2044 0033;;;0;N;;;;; -218A;TURNED DIGIT TWO;So;0;ON;;;;;N;;;;; -218B;TURNED DIGIT THREE;So;0;ON;;;;;N;;;;; -2190;LEFTWARDS ARROW;Sm;0;ON;;;;;N;LEFT ARROW;;;; -2191;UPWARDS ARROW;Sm;0;ON;;;;;N;UP ARROW;;;; -2192;RIGHTWARDS ARROW;Sm;0;ON;;;;;N;RIGHT ARROW;;;; -2193;DOWNWARDS ARROW;Sm;0;ON;;;;;N;DOWN ARROW;;;; -2194;LEFT RIGHT ARROW;Sm;0;ON;;;;;N;;;;; -2195;UP DOWN ARROW;So;0;ON;;;;;N;;;;; -2196;NORTH WEST ARROW;So;0;ON;;;;;N;UPPER LEFT ARROW;;;; -2197;NORTH EAST ARROW;So;0;ON;;;;;N;UPPER RIGHT ARROW;;;; -2198;SOUTH EAST ARROW;So;0;ON;;;;;N;LOWER RIGHT ARROW;;;; -2199;SOUTH WEST ARROW;So;0;ON;;;;;N;LOWER LEFT ARROW;;;; -219A;LEFTWARDS ARROW WITH STROKE;Sm;0;ON;2190 0338;;;;N;LEFT ARROW WITH STROKE;;;; -219B;RIGHTWARDS ARROW WITH STROKE;Sm;0;ON;2192 0338;;;;N;RIGHT ARROW WITH STROKE;;;; -219C;LEFTWARDS WAVE ARROW;So;0;ON;;;;;N;LEFT WAVE ARROW;;;; -219D;RIGHTWARDS WAVE ARROW;So;0;ON;;;;;N;RIGHT WAVE ARROW;;;; -219E;LEFTWARDS TWO HEADED ARROW;So;0;ON;;;;;N;LEFT TWO HEADED ARROW;;;; -219F;UPWARDS TWO HEADED ARROW;So;0;ON;;;;;N;UP TWO HEADED ARROW;;;; -21A0;RIGHTWARDS TWO HEADED ARROW;Sm;0;ON;;;;;N;RIGHT TWO HEADED ARROW;;;; -21A1;DOWNWARDS TWO HEADED ARROW;So;0;ON;;;;;N;DOWN TWO HEADED ARROW;;;; -21A2;LEFTWARDS ARROW WITH TAIL;So;0;ON;;;;;N;LEFT ARROW WITH TAIL;;;; -21A3;RIGHTWARDS ARROW WITH TAIL;Sm;0;ON;;;;;N;RIGHT ARROW WITH TAIL;;;; -21A4;LEFTWARDS ARROW FROM BAR;So;0;ON;;;;;N;LEFT ARROW FROM BAR;;;; -21A5;UPWARDS ARROW FROM BAR;So;0;ON;;;;;N;UP ARROW FROM BAR;;;; -21A6;RIGHTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;RIGHT ARROW FROM BAR;;;; -21A7;DOWNWARDS ARROW FROM BAR;So;0;ON;;;;;N;DOWN ARROW FROM BAR;;;; -21A8;UP DOWN ARROW WITH BASE;So;0;ON;;;;;N;;;;; -21A9;LEFTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;LEFT ARROW WITH HOOK;;;; -21AA;RIGHTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;RIGHT ARROW WITH HOOK;;;; -21AB;LEFTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;LEFT ARROW WITH LOOP;;;; -21AC;RIGHTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;RIGHT ARROW WITH LOOP;;;; -21AD;LEFT RIGHT WAVE ARROW;So;0;ON;;;;;N;;;;; -21AE;LEFT RIGHT ARROW WITH STROKE;Sm;0;ON;2194 0338;;;;N;;;;; -21AF;DOWNWARDS ZIGZAG ARROW;So;0;ON;;;;;N;DOWN ZIGZAG ARROW;;;; -21B0;UPWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP LEFT;;;; -21B1;UPWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP RIGHT;;;; -21B2;DOWNWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP LEFT;;;; -21B3;DOWNWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP RIGHT;;;; -21B4;RIGHTWARDS ARROW WITH CORNER DOWNWARDS;So;0;ON;;;;;N;RIGHT ARROW WITH CORNER DOWN;;;; -21B5;DOWNWARDS ARROW WITH CORNER LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH CORNER LEFT;;;; -21B6;ANTICLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;; -21B7;CLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;; -21B8;NORTH WEST ARROW TO LONG BAR;So;0;ON;;;;;N;UPPER LEFT ARROW TO LONG BAR;;;; -21B9;LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR OVER RIGHT ARROW TO BAR;;;; -21BA;ANTICLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;; -21BB;CLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;; -21BC;LEFTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB UP;;;; -21BD;LEFTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB DOWN;;;; -21BE;UPWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB RIGHT;;;; -21BF;UPWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB LEFT;;;; -21C0;RIGHTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB UP;;;; -21C1;RIGHTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB DOWN;;;; -21C2;DOWNWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB RIGHT;;;; -21C3;DOWNWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB LEFT;;;; -21C4;RIGHTWARDS ARROW OVER LEFTWARDS ARROW;So;0;ON;;;;;N;RIGHT ARROW OVER LEFT ARROW;;;; -21C5;UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW;So;0;ON;;;;;N;UP ARROW LEFT OF DOWN ARROW;;;; -21C6;LEFTWARDS ARROW OVER RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT ARROW OVER RIGHT ARROW;;;; -21C7;LEFTWARDS PAIRED ARROWS;So;0;ON;;;;;N;LEFT PAIRED ARROWS;;;; -21C8;UPWARDS PAIRED ARROWS;So;0;ON;;;;;N;UP PAIRED ARROWS;;;; -21C9;RIGHTWARDS PAIRED ARROWS;So;0;ON;;;;;N;RIGHT PAIRED ARROWS;;;; -21CA;DOWNWARDS PAIRED ARROWS;So;0;ON;;;;;N;DOWN PAIRED ARROWS;;;; -21CB;LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON;So;0;ON;;;;;N;LEFT HARPOON OVER RIGHT HARPOON;;;; -21CC;RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON;So;0;ON;;;;;N;RIGHT HARPOON OVER LEFT HARPOON;;;; -21CD;LEFTWARDS DOUBLE ARROW WITH STROKE;So;0;ON;21D0 0338;;;;N;LEFT DOUBLE ARROW WITH STROKE;;;; -21CE;LEFT RIGHT DOUBLE ARROW WITH STROKE;Sm;0;ON;21D4 0338;;;;N;;;;; -21CF;RIGHTWARDS DOUBLE ARROW WITH STROKE;Sm;0;ON;21D2 0338;;;;N;RIGHT DOUBLE ARROW WITH STROKE;;;; -21D0;LEFTWARDS DOUBLE ARROW;So;0;ON;;;;;N;LEFT DOUBLE ARROW;;;; -21D1;UPWARDS DOUBLE ARROW;So;0;ON;;;;;N;UP DOUBLE ARROW;;;; -21D2;RIGHTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;RIGHT DOUBLE ARROW;;;; -21D3;DOWNWARDS DOUBLE ARROW;So;0;ON;;;;;N;DOWN DOUBLE ARROW;;;; -21D4;LEFT RIGHT DOUBLE ARROW;Sm;0;ON;;;;;N;;;;; -21D5;UP DOWN DOUBLE ARROW;So;0;ON;;;;;N;;;;; -21D6;NORTH WEST DOUBLE ARROW;So;0;ON;;;;;N;UPPER LEFT DOUBLE ARROW;;;; -21D7;NORTH EAST DOUBLE ARROW;So;0;ON;;;;;N;UPPER RIGHT DOUBLE ARROW;;;; -21D8;SOUTH EAST DOUBLE ARROW;So;0;ON;;;;;N;LOWER RIGHT DOUBLE ARROW;;;; -21D9;SOUTH WEST DOUBLE ARROW;So;0;ON;;;;;N;LOWER LEFT DOUBLE ARROW;;;; -21DA;LEFTWARDS TRIPLE ARROW;So;0;ON;;;;;N;LEFT TRIPLE ARROW;;;; -21DB;RIGHTWARDS TRIPLE ARROW;So;0;ON;;;;;N;RIGHT TRIPLE ARROW;;;; -21DC;LEFTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;LEFT SQUIGGLE ARROW;;;; -21DD;RIGHTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;RIGHT SQUIGGLE ARROW;;;; -21DE;UPWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;UP ARROW WITH DOUBLE STROKE;;;; -21DF;DOWNWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;DOWN ARROW WITH DOUBLE STROKE;;;; -21E0;LEFTWARDS DASHED ARROW;So;0;ON;;;;;N;LEFT DASHED ARROW;;;; -21E1;UPWARDS DASHED ARROW;So;0;ON;;;;;N;UP DASHED ARROW;;;; -21E2;RIGHTWARDS DASHED ARROW;So;0;ON;;;;;N;RIGHT DASHED ARROW;;;; -21E3;DOWNWARDS DASHED ARROW;So;0;ON;;;;;N;DOWN DASHED ARROW;;;; -21E4;LEFTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR;;;; -21E5;RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;RIGHT ARROW TO BAR;;;; -21E6;LEFTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE LEFT ARROW;;;; -21E7;UPWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE UP ARROW;;;; -21E8;RIGHTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE RIGHT ARROW;;;; -21E9;DOWNWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE DOWN ARROW;;;; -21EA;UPWARDS WHITE ARROW FROM BAR;So;0;ON;;;;;N;WHITE UP ARROW FROM BAR;;;; -21EB;UPWARDS WHITE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;; -21EC;UPWARDS WHITE ARROW ON PEDESTAL WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;; -21ED;UPWARDS WHITE ARROW ON PEDESTAL WITH VERTICAL BAR;So;0;ON;;;;;N;;;;; -21EE;UPWARDS WHITE DOUBLE ARROW;So;0;ON;;;;;N;;;;; -21EF;UPWARDS WHITE DOUBLE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;; -21F0;RIGHTWARDS WHITE ARROW FROM WALL;So;0;ON;;;;;N;;;;; -21F1;NORTH WEST ARROW TO CORNER;So;0;ON;;;;;N;;;;; -21F2;SOUTH EAST ARROW TO CORNER;So;0;ON;;;;;N;;;;; -21F3;UP DOWN WHITE ARROW;So;0;ON;;;;;N;;;;; -21F4;RIGHT ARROW WITH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;; -21F5;DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW;Sm;0;ON;;;;;N;;;;; -21F6;THREE RIGHTWARDS ARROWS;Sm;0;ON;;;;;N;;;;; -21F7;LEFTWARDS ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -21F8;RIGHTWARDS ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -21F9;LEFT RIGHT ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -21FA;LEFTWARDS ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -21FB;RIGHTWARDS ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -21FC;LEFT RIGHT ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -21FD;LEFTWARDS OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;; -21FE;RIGHTWARDS OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;; -21FF;LEFT RIGHT OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;; -2200;FOR ALL;Sm;0;ON;;;;;N;;;;; -2201;COMPLEMENT;Sm;0;ON;;;;;Y;;;;; -2202;PARTIAL DIFFERENTIAL;Sm;0;ON;;;;;Y;;;;; -2203;THERE EXISTS;Sm;0;ON;;;;;Y;;;;; -2204;THERE DOES NOT EXIST;Sm;0;ON;2203 0338;;;;Y;;;;; -2205;EMPTY SET;Sm;0;ON;;;;;N;;;;; -2206;INCREMENT;Sm;0;ON;;;;;N;;;;; -2207;NABLA;Sm;0;ON;;;;;N;;;;; -2208;ELEMENT OF;Sm;0;ON;;;;;Y;;;;; -2209;NOT AN ELEMENT OF;Sm;0;ON;2208 0338;;;;Y;;;;; -220A;SMALL ELEMENT OF;Sm;0;ON;;;;;Y;;;;; -220B;CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;; -220C;DOES NOT CONTAIN AS MEMBER;Sm;0;ON;220B 0338;;;;Y;;;;; -220D;SMALL CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;; -220E;END OF PROOF;Sm;0;ON;;;;;N;;;;; -220F;N-ARY PRODUCT;Sm;0;ON;;;;;N;;;;; -2210;N-ARY COPRODUCT;Sm;0;ON;;;;;N;;;;; -2211;N-ARY SUMMATION;Sm;0;ON;;;;;Y;;;;; -2212;MINUS SIGN;Sm;0;ES;;;;;N;;;;; -2213;MINUS-OR-PLUS SIGN;Sm;0;ET;;;;;N;;;;; -2214;DOT PLUS;Sm;0;ON;;;;;N;;;;; -2215;DIVISION SLASH;Sm;0;ON;;;;;Y;;;;; -2216;SET MINUS;Sm;0;ON;;;;;Y;;;;; -2217;ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;; -2218;RING OPERATOR;Sm;0;ON;;;;;N;;;;; -2219;BULLET OPERATOR;Sm;0;ON;;;;;N;;;;; -221A;SQUARE ROOT;Sm;0;ON;;;;;Y;;;;; -221B;CUBE ROOT;Sm;0;ON;;;;;Y;;;;; -221C;FOURTH ROOT;Sm;0;ON;;;;;Y;;;;; -221D;PROPORTIONAL TO;Sm;0;ON;;;;;Y;;;;; -221E;INFINITY;Sm;0;ON;;;;;N;;;;; -221F;RIGHT ANGLE;Sm;0;ON;;;;;Y;;;;; -2220;ANGLE;Sm;0;ON;;;;;Y;;;;; -2221;MEASURED ANGLE;Sm;0;ON;;;;;Y;;;;; -2222;SPHERICAL ANGLE;Sm;0;ON;;;;;Y;;;;; -2223;DIVIDES;Sm;0;ON;;;;;N;;;;; -2224;DOES NOT DIVIDE;Sm;0;ON;2223 0338;;;;Y;;;;; -2225;PARALLEL TO;Sm;0;ON;;;;;N;;;;; -2226;NOT PARALLEL TO;Sm;0;ON;2225 0338;;;;Y;;;;; -2227;LOGICAL AND;Sm;0;ON;;;;;N;;;;; -2228;LOGICAL OR;Sm;0;ON;;;;;N;;;;; -2229;INTERSECTION;Sm;0;ON;;;;;N;;;;; -222A;UNION;Sm;0;ON;;;;;N;;;;; -222B;INTEGRAL;Sm;0;ON;;;;;Y;;;;; -222C;DOUBLE INTEGRAL;Sm;0;ON;<compat> 222B 222B;;;;Y;;;;; -222D;TRIPLE INTEGRAL;Sm;0;ON;<compat> 222B 222B 222B;;;;Y;;;;; -222E;CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;; -222F;SURFACE INTEGRAL;Sm;0;ON;<compat> 222E 222E;;;;Y;;;;; -2230;VOLUME INTEGRAL;Sm;0;ON;<compat> 222E 222E 222E;;;;Y;;;;; -2231;CLOCKWISE INTEGRAL;Sm;0;ON;;;;;Y;;;;; -2232;CLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;; -2233;ANTICLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;; -2234;THEREFORE;Sm;0;ON;;;;;N;;;;; -2235;BECAUSE;Sm;0;ON;;;;;N;;;;; -2236;RATIO;Sm;0;ON;;;;;N;;;;; -2237;PROPORTION;Sm;0;ON;;;;;N;;;;; -2238;DOT MINUS;Sm;0;ON;;;;;N;;;;; -2239;EXCESS;Sm;0;ON;;;;;Y;;;;; -223A;GEOMETRIC PROPORTION;Sm;0;ON;;;;;N;;;;; -223B;HOMOTHETIC;Sm;0;ON;;;;;Y;;;;; -223C;TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; -223D;REVERSED TILDE;Sm;0;ON;;;;;Y;;;;; -223E;INVERTED LAZY S;Sm;0;ON;;;;;Y;;;;; -223F;SINE WAVE;Sm;0;ON;;;;;Y;;;;; -2240;WREATH PRODUCT;Sm;0;ON;;;;;Y;;;;; -2241;NOT TILDE;Sm;0;ON;223C 0338;;;;Y;;;;; -2242;MINUS TILDE;Sm;0;ON;;;;;Y;;;;; -2243;ASYMPTOTICALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2244;NOT ASYMPTOTICALLY EQUAL TO;Sm;0;ON;2243 0338;;;;Y;;;;; -2245;APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2246;APPROXIMATELY BUT NOT ACTUALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2247;NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO;Sm;0;ON;2245 0338;;;;Y;;;;; -2248;ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2249;NOT ALMOST EQUAL TO;Sm;0;ON;2248 0338;;;;Y;;;;; -224A;ALMOST EQUAL OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; -224B;TRIPLE TILDE;Sm;0;ON;;;;;Y;;;;; -224C;ALL EQUAL TO;Sm;0;ON;;;;;Y;;;;; -224D;EQUIVALENT TO;Sm;0;ON;;;;;N;;;;; -224E;GEOMETRICALLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;; -224F;DIFFERENCE BETWEEN;Sm;0;ON;;;;;N;;;;; -2250;APPROACHES THE LIMIT;Sm;0;ON;;;;;N;;;;; -2251;GEOMETRICALLY EQUAL TO;Sm;0;ON;;;;;N;;;;; -2252;APPROXIMATELY EQUAL TO OR THE IMAGE OF;Sm;0;ON;;;;;Y;;;;; -2253;IMAGE OF OR APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2254;COLON EQUALS;Sm;0;ON;;;;;Y;COLON EQUAL;;;; -2255;EQUALS COLON;Sm;0;ON;;;;;Y;EQUAL COLON;;;; -2256;RING IN EQUAL TO;Sm;0;ON;;;;;N;;;;; -2257;RING EQUAL TO;Sm;0;ON;;;;;N;;;;; -2258;CORRESPONDS TO;Sm;0;ON;;;;;N;;;;; -2259;ESTIMATES;Sm;0;ON;;;;;N;;;;; -225A;EQUIANGULAR TO;Sm;0;ON;;;;;N;;;;; -225B;STAR EQUALS;Sm;0;ON;;;;;N;;;;; -225C;DELTA EQUAL TO;Sm;0;ON;;;;;N;;;;; -225D;EQUAL TO BY DEFINITION;Sm;0;ON;;;;;N;;;;; -225E;MEASURED BY;Sm;0;ON;;;;;N;;;;; -225F;QUESTIONED EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2260;NOT EQUAL TO;Sm;0;ON;003D 0338;;;;Y;;;;; -2261;IDENTICAL TO;Sm;0;ON;;;;;N;;;;; -2262;NOT IDENTICAL TO;Sm;0;ON;2261 0338;;;;Y;;;;; -2263;STRICTLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;; -2264;LESS-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUAL TO;;;; -2265;GREATER-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUAL TO;;;; -2266;LESS-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OVER EQUAL TO;;;; -2267;GREATER-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OVER EQUAL TO;;;; -2268;LESS-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUAL TO;;;; -2269;GREATER-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUAL TO;;;; -226A;MUCH LESS-THAN;Sm;0;ON;;;;;Y;MUCH LESS THAN;;;; -226B;MUCH GREATER-THAN;Sm;0;ON;;;;;Y;MUCH GREATER THAN;;;; -226C;BETWEEN;Sm;0;ON;;;;;N;;;;; -226D;NOT EQUIVALENT TO;Sm;0;ON;224D 0338;;;;N;;;;; -226E;NOT LESS-THAN;Sm;0;ON;003C 0338;;;;Y;NOT LESS THAN;;;; -226F;NOT GREATER-THAN;Sm;0;ON;003E 0338;;;;Y;NOT GREATER THAN;;;; -2270;NEITHER LESS-THAN NOR EQUAL TO;Sm;0;ON;2264 0338;;;;Y;NEITHER LESS THAN NOR EQUAL TO;;;; -2271;NEITHER GREATER-THAN NOR EQUAL TO;Sm;0;ON;2265 0338;;;;Y;NEITHER GREATER THAN NOR EQUAL TO;;;; -2272;LESS-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUIVALENT TO;;;; -2273;GREATER-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUIVALENT TO;;;; -2274;NEITHER LESS-THAN NOR EQUIVALENT TO;Sm;0;ON;2272 0338;;;;Y;NEITHER LESS THAN NOR EQUIVALENT TO;;;; -2275;NEITHER GREATER-THAN NOR EQUIVALENT TO;Sm;0;ON;2273 0338;;;;Y;NEITHER GREATER THAN NOR EQUIVALENT TO;;;; -2276;LESS-THAN OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN OR GREATER THAN;;;; -2277;GREATER-THAN OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN OR LESS THAN;;;; -2278;NEITHER LESS-THAN NOR GREATER-THAN;Sm;0;ON;2276 0338;;;;Y;NEITHER LESS THAN NOR GREATER THAN;;;; -2279;NEITHER GREATER-THAN NOR LESS-THAN;Sm;0;ON;2277 0338;;;;Y;NEITHER GREATER THAN NOR LESS THAN;;;; -227A;PRECEDES;Sm;0;ON;;;;;Y;;;;; -227B;SUCCEEDS;Sm;0;ON;;;;;Y;;;;; -227C;PRECEDES OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; -227D;SUCCEEDS OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; -227E;PRECEDES OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; -227F;SUCCEEDS OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; -2280;DOES NOT PRECEDE;Sm;0;ON;227A 0338;;;;Y;;;;; -2281;DOES NOT SUCCEED;Sm;0;ON;227B 0338;;;;Y;;;;; -2282;SUBSET OF;Sm;0;ON;;;;;Y;;;;; -2283;SUPERSET OF;Sm;0;ON;;;;;Y;;;;; -2284;NOT A SUBSET OF;Sm;0;ON;2282 0338;;;;Y;;;;; -2285;NOT A SUPERSET OF;Sm;0;ON;2283 0338;;;;Y;;;;; -2286;SUBSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2287;SUPERSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2288;NEITHER A SUBSET OF NOR EQUAL TO;Sm;0;ON;2286 0338;;;;Y;;;;; -2289;NEITHER A SUPERSET OF NOR EQUAL TO;Sm;0;ON;2287 0338;;;;Y;;;;; -228A;SUBSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUBSET OF OR NOT EQUAL TO;;;; -228B;SUPERSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUPERSET OF OR NOT EQUAL TO;;;; -228C;MULTISET;Sm;0;ON;;;;;Y;;;;; -228D;MULTISET MULTIPLICATION;Sm;0;ON;;;;;N;;;;; -228E;MULTISET UNION;Sm;0;ON;;;;;N;;;;; -228F;SQUARE IMAGE OF;Sm;0;ON;;;;;Y;;;;; -2290;SQUARE ORIGINAL OF;Sm;0;ON;;;;;Y;;;;; -2291;SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2292;SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2293;SQUARE CAP;Sm;0;ON;;;;;N;;;;; -2294;SQUARE CUP;Sm;0;ON;;;;;N;;;;; -2295;CIRCLED PLUS;Sm;0;ON;;;;;N;;;;; -2296;CIRCLED MINUS;Sm;0;ON;;;;;N;;;;; -2297;CIRCLED TIMES;Sm;0;ON;;;;;N;;;;; -2298;CIRCLED DIVISION SLASH;Sm;0;ON;;;;;Y;;;;; -2299;CIRCLED DOT OPERATOR;Sm;0;ON;;;;;N;;;;; -229A;CIRCLED RING OPERATOR;Sm;0;ON;;;;;N;;;;; -229B;CIRCLED ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;; -229C;CIRCLED EQUALS;Sm;0;ON;;;;;N;;;;; -229D;CIRCLED DASH;Sm;0;ON;;;;;N;;;;; -229E;SQUARED PLUS;Sm;0;ON;;;;;N;;;;; -229F;SQUARED MINUS;Sm;0;ON;;;;;N;;;;; -22A0;SQUARED TIMES;Sm;0;ON;;;;;N;;;;; -22A1;SQUARED DOT OPERATOR;Sm;0;ON;;;;;N;;;;; -22A2;RIGHT TACK;Sm;0;ON;;;;;Y;;;;; -22A3;LEFT TACK;Sm;0;ON;;;;;Y;;;;; -22A4;DOWN TACK;Sm;0;ON;;;;;N;;;;; -22A5;UP TACK;Sm;0;ON;;;;;N;;;;; -22A6;ASSERTION;Sm;0;ON;;;;;Y;;;;; -22A7;MODELS;Sm;0;ON;;;;;Y;;;;; -22A8;TRUE;Sm;0;ON;;;;;Y;;;;; -22A9;FORCES;Sm;0;ON;;;;;Y;;;;; -22AA;TRIPLE VERTICAL BAR RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;; -22AB;DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;; -22AC;DOES NOT PROVE;Sm;0;ON;22A2 0338;;;;Y;;;;; -22AD;NOT TRUE;Sm;0;ON;22A8 0338;;;;Y;;;;; -22AE;DOES NOT FORCE;Sm;0;ON;22A9 0338;;;;Y;;;;; -22AF;NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;22AB 0338;;;;Y;;;;; -22B0;PRECEDES UNDER RELATION;Sm;0;ON;;;;;Y;;;;; -22B1;SUCCEEDS UNDER RELATION;Sm;0;ON;;;;;Y;;;;; -22B2;NORMAL SUBGROUP OF;Sm;0;ON;;;;;Y;;;;; -22B3;CONTAINS AS NORMAL SUBGROUP;Sm;0;ON;;;;;Y;;;;; -22B4;NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; -22B5;CONTAINS AS NORMAL SUBGROUP OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; -22B6;ORIGINAL OF;Sm;0;ON;;;;;Y;;;;; -22B7;IMAGE OF;Sm;0;ON;;;;;Y;;;;; -22B8;MULTIMAP;Sm;0;ON;;;;;Y;;;;; -22B9;HERMITIAN CONJUGATE MATRIX;Sm;0;ON;;;;;N;;;;; -22BA;INTERCALATE;Sm;0;ON;;;;;N;;;;; -22BB;XOR;Sm;0;ON;;;;;N;;;;; -22BC;NAND;Sm;0;ON;;;;;N;;;;; -22BD;NOR;Sm;0;ON;;;;;N;;;;; -22BE;RIGHT ANGLE WITH ARC;Sm;0;ON;;;;;Y;;;;; -22BF;RIGHT TRIANGLE;Sm;0;ON;;;;;Y;;;;; -22C0;N-ARY LOGICAL AND;Sm;0;ON;;;;;N;;;;; -22C1;N-ARY LOGICAL OR;Sm;0;ON;;;;;N;;;;; -22C2;N-ARY INTERSECTION;Sm;0;ON;;;;;N;;;;; -22C3;N-ARY UNION;Sm;0;ON;;;;;N;;;;; -22C4;DIAMOND OPERATOR;Sm;0;ON;;;;;N;;;;; -22C5;DOT OPERATOR;Sm;0;ON;;;;;N;;;;; -22C6;STAR OPERATOR;Sm;0;ON;;;;;N;;;;; -22C7;DIVISION TIMES;Sm;0;ON;;;;;N;;;;; -22C8;BOWTIE;Sm;0;ON;;;;;N;;;;; -22C9;LEFT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; -22CA;RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; -22CB;LEFT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; -22CC;RIGHT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; -22CD;REVERSED TILDE EQUALS;Sm;0;ON;;;;;Y;;;;; -22CE;CURLY LOGICAL OR;Sm;0;ON;;;;;N;;;;; -22CF;CURLY LOGICAL AND;Sm;0;ON;;;;;N;;;;; -22D0;DOUBLE SUBSET;Sm;0;ON;;;;;Y;;;;; -22D1;DOUBLE SUPERSET;Sm;0;ON;;;;;Y;;;;; -22D2;DOUBLE INTERSECTION;Sm;0;ON;;;;;N;;;;; -22D3;DOUBLE UNION;Sm;0;ON;;;;;N;;;;; -22D4;PITCHFORK;Sm;0;ON;;;;;N;;;;; -22D5;EQUAL AND PARALLEL TO;Sm;0;ON;;;;;N;;;;; -22D6;LESS-THAN WITH DOT;Sm;0;ON;;;;;Y;LESS THAN WITH DOT;;;; -22D7;GREATER-THAN WITH DOT;Sm;0;ON;;;;;Y;GREATER THAN WITH DOT;;;; -22D8;VERY MUCH LESS-THAN;Sm;0;ON;;;;;Y;VERY MUCH LESS THAN;;;; -22D9;VERY MUCH GREATER-THAN;Sm;0;ON;;;;;Y;VERY MUCH GREATER THAN;;;; -22DA;LESS-THAN EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN EQUAL TO OR GREATER THAN;;;; -22DB;GREATER-THAN EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN EQUAL TO OR LESS THAN;;;; -22DC;EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR LESS THAN;;;; -22DD;EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR GREATER THAN;;;; -22DE;EQUAL TO OR PRECEDES;Sm;0;ON;;;;;Y;;;;; -22DF;EQUAL TO OR SUCCEEDS;Sm;0;ON;;;;;Y;;;;; -22E0;DOES NOT PRECEDE OR EQUAL;Sm;0;ON;227C 0338;;;;Y;;;;; -22E1;DOES NOT SUCCEED OR EQUAL;Sm;0;ON;227D 0338;;;;Y;;;;; -22E2;NOT SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;2291 0338;;;;Y;;;;; -22E3;NOT SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;2292 0338;;;;Y;;;;; -22E4;SQUARE IMAGE OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; -22E5;SQUARE ORIGINAL OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; -22E6;LESS-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUIVALENT TO;;;; -22E7;GREATER-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUIVALENT TO;;;; -22E8;PRECEDES BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; -22E9;SUCCEEDS BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; -22EA;NOT NORMAL SUBGROUP OF;Sm;0;ON;22B2 0338;;;;Y;;;;; -22EB;DOES NOT CONTAIN AS NORMAL SUBGROUP;Sm;0;ON;22B3 0338;;;;Y;;;;; -22EC;NOT NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;22B4 0338;;;;Y;;;;; -22ED;DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL;Sm;0;ON;22B5 0338;;;;Y;;;;; -22EE;VERTICAL ELLIPSIS;Sm;0;ON;;;;;N;;;;; -22EF;MIDLINE HORIZONTAL ELLIPSIS;Sm;0;ON;;;;;N;;;;; -22F0;UP RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;; -22F1;DOWN RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;; -22F2;ELEMENT OF WITH LONG HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; -22F3;ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; -22F4;SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; -22F5;ELEMENT OF WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; -22F6;ELEMENT OF WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; -22F7;SMALL ELEMENT OF WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; -22F8;ELEMENT OF WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; -22F9;ELEMENT OF WITH TWO HORIZONTAL STROKES;Sm;0;ON;;;;;Y;;;;; -22FA;CONTAINS WITH LONG HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; -22FB;CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; -22FC;SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; -22FD;CONTAINS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; -22FE;SMALL CONTAINS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; -22FF;Z NOTATION BAG MEMBERSHIP;Sm;0;ON;;;;;Y;;;;; -2300;DIAMETER SIGN;So;0;ON;;;;;N;;;;; -2301;ELECTRIC ARROW;So;0;ON;;;;;N;;;;; -2302;HOUSE;So;0;ON;;;;;N;;;;; -2303;UP ARROWHEAD;So;0;ON;;;;;N;;;;; -2304;DOWN ARROWHEAD;So;0;ON;;;;;N;;;;; -2305;PROJECTIVE;So;0;ON;;;;;N;;;;; -2306;PERSPECTIVE;So;0;ON;;;;;N;;;;; -2307;WAVY LINE;So;0;ON;;;;;N;;;;; -2308;LEFT CEILING;Ps;0;ON;;;;;Y;;;;; -2309;RIGHT CEILING;Pe;0;ON;;;;;Y;;;;; -230A;LEFT FLOOR;Ps;0;ON;;;;;Y;;;;; -230B;RIGHT FLOOR;Pe;0;ON;;;;;Y;;;;; -230C;BOTTOM RIGHT CROP;So;0;ON;;;;;N;;;;; -230D;BOTTOM LEFT CROP;So;0;ON;;;;;N;;;;; -230E;TOP RIGHT CROP;So;0;ON;;;;;N;;;;; -230F;TOP LEFT CROP;So;0;ON;;;;;N;;;;; -2310;REVERSED NOT SIGN;So;0;ON;;;;;N;;;;; -2311;SQUARE LOZENGE;So;0;ON;;;;;N;;;;; -2312;ARC;So;0;ON;;;;;N;;;;; -2313;SEGMENT;So;0;ON;;;;;N;;;;; -2314;SECTOR;So;0;ON;;;;;N;;;;; -2315;TELEPHONE RECORDER;So;0;ON;;;;;N;;;;; -2316;POSITION INDICATOR;So;0;ON;;;;;N;;;;; -2317;VIEWDATA SQUARE;So;0;ON;;;;;N;;;;; -2318;PLACE OF INTEREST SIGN;So;0;ON;;;;;N;COMMAND KEY;;;; -2319;TURNED NOT SIGN;So;0;ON;;;;;N;;;;; -231A;WATCH;So;0;ON;;;;;N;;;;; -231B;HOURGLASS;So;0;ON;;;;;N;;;;; -231C;TOP LEFT CORNER;So;0;ON;;;;;N;;;;; -231D;TOP RIGHT CORNER;So;0;ON;;;;;N;;;;; -231E;BOTTOM LEFT CORNER;So;0;ON;;;;;N;;;;; -231F;BOTTOM RIGHT CORNER;So;0;ON;;;;;N;;;;; -2320;TOP HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;; -2321;BOTTOM HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;; -2322;FROWN;So;0;ON;;;;;N;;;;; -2323;SMILE;So;0;ON;;;;;N;;;;; -2324;UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS;So;0;ON;;;;;N;ENTER KEY;;;; -2325;OPTION KEY;So;0;ON;;;;;N;;;;; -2326;ERASE TO THE RIGHT;So;0;ON;;;;;N;DELETE TO THE RIGHT KEY;;;; -2327;X IN A RECTANGLE BOX;So;0;ON;;;;;N;CLEAR KEY;;;; -2328;KEYBOARD;So;0;ON;;;;;N;;;;; -2329;LEFT-POINTING ANGLE BRACKET;Ps;0;ON;3008;;;;Y;BRA;;;; -232A;RIGHT-POINTING ANGLE BRACKET;Pe;0;ON;3009;;;;Y;KET;;;; -232B;ERASE TO THE LEFT;So;0;ON;;;;;N;DELETE TO THE LEFT KEY;;;; -232C;BENZENE RING;So;0;ON;;;;;N;;;;; -232D;CYLINDRICITY;So;0;ON;;;;;N;;;;; -232E;ALL AROUND-PROFILE;So;0;ON;;;;;N;;;;; -232F;SYMMETRY;So;0;ON;;;;;N;;;;; -2330;TOTAL RUNOUT;So;0;ON;;;;;N;;;;; -2331;DIMENSION ORIGIN;So;0;ON;;;;;N;;;;; -2332;CONICAL TAPER;So;0;ON;;;;;N;;;;; -2333;SLOPE;So;0;ON;;;;;N;;;;; -2334;COUNTERBORE;So;0;ON;;;;;N;;;;; -2335;COUNTERSINK;So;0;ON;;;;;N;;;;; -2336;APL FUNCTIONAL SYMBOL I-BEAM;So;0;L;;;;;N;;;;; -2337;APL FUNCTIONAL SYMBOL SQUISH QUAD;So;0;L;;;;;N;;;;; -2338;APL FUNCTIONAL SYMBOL QUAD EQUAL;So;0;L;;;;;N;;;;; -2339;APL FUNCTIONAL SYMBOL QUAD DIVIDE;So;0;L;;;;;N;;;;; -233A;APL FUNCTIONAL SYMBOL QUAD DIAMOND;So;0;L;;;;;N;;;;; -233B;APL FUNCTIONAL SYMBOL QUAD JOT;So;0;L;;;;;N;;;;; -233C;APL FUNCTIONAL SYMBOL QUAD CIRCLE;So;0;L;;;;;N;;;;; -233D;APL FUNCTIONAL SYMBOL CIRCLE STILE;So;0;L;;;;;N;;;;; -233E;APL FUNCTIONAL SYMBOL CIRCLE JOT;So;0;L;;;;;N;;;;; -233F;APL FUNCTIONAL SYMBOL SLASH BAR;So;0;L;;;;;N;;;;; -2340;APL FUNCTIONAL SYMBOL BACKSLASH BAR;So;0;L;;;;;N;;;;; -2341;APL FUNCTIONAL SYMBOL QUAD SLASH;So;0;L;;;;;N;;;;; -2342;APL FUNCTIONAL SYMBOL QUAD BACKSLASH;So;0;L;;;;;N;;;;; -2343;APL FUNCTIONAL SYMBOL QUAD LESS-THAN;So;0;L;;;;;N;;;;; -2344;APL FUNCTIONAL SYMBOL QUAD GREATER-THAN;So;0;L;;;;;N;;;;; -2345;APL FUNCTIONAL SYMBOL LEFTWARDS VANE;So;0;L;;;;;N;;;;; -2346;APL FUNCTIONAL SYMBOL RIGHTWARDS VANE;So;0;L;;;;;N;;;;; -2347;APL FUNCTIONAL SYMBOL QUAD LEFTWARDS ARROW;So;0;L;;;;;N;;;;; -2348;APL FUNCTIONAL SYMBOL QUAD RIGHTWARDS ARROW;So;0;L;;;;;N;;;;; -2349;APL FUNCTIONAL SYMBOL CIRCLE BACKSLASH;So;0;L;;;;;N;;;;; -234A;APL FUNCTIONAL SYMBOL DOWN TACK UNDERBAR;So;0;L;;;;;N;;;;; -234B;APL FUNCTIONAL SYMBOL DELTA STILE;So;0;L;;;;;N;;;;; -234C;APL FUNCTIONAL SYMBOL QUAD DOWN CARET;So;0;L;;;;;N;;;;; -234D;APL FUNCTIONAL SYMBOL QUAD DELTA;So;0;L;;;;;N;;;;; -234E;APL FUNCTIONAL SYMBOL DOWN TACK JOT;So;0;L;;;;;N;;;;; -234F;APL FUNCTIONAL SYMBOL UPWARDS VANE;So;0;L;;;;;N;;;;; -2350;APL FUNCTIONAL SYMBOL QUAD UPWARDS ARROW;So;0;L;;;;;N;;;;; -2351;APL FUNCTIONAL SYMBOL UP TACK OVERBAR;So;0;L;;;;;N;;;;; -2352;APL FUNCTIONAL SYMBOL DEL STILE;So;0;L;;;;;N;;;;; -2353;APL FUNCTIONAL SYMBOL QUAD UP CARET;So;0;L;;;;;N;;;;; -2354;APL FUNCTIONAL SYMBOL QUAD DEL;So;0;L;;;;;N;;;;; -2355;APL FUNCTIONAL SYMBOL UP TACK JOT;So;0;L;;;;;N;;;;; -2356;APL FUNCTIONAL SYMBOL DOWNWARDS VANE;So;0;L;;;;;N;;;;; -2357;APL FUNCTIONAL SYMBOL QUAD DOWNWARDS ARROW;So;0;L;;;;;N;;;;; -2358;APL FUNCTIONAL SYMBOL QUOTE UNDERBAR;So;0;L;;;;;N;;;;; -2359;APL FUNCTIONAL SYMBOL DELTA UNDERBAR;So;0;L;;;;;N;;;;; -235A;APL FUNCTIONAL SYMBOL DIAMOND UNDERBAR;So;0;L;;;;;N;;;;; -235B;APL FUNCTIONAL SYMBOL JOT UNDERBAR;So;0;L;;;;;N;;;;; -235C;APL FUNCTIONAL SYMBOL CIRCLE UNDERBAR;So;0;L;;;;;N;;;;; -235D;APL FUNCTIONAL SYMBOL UP SHOE JOT;So;0;L;;;;;N;;;;; -235E;APL FUNCTIONAL SYMBOL QUOTE QUAD;So;0;L;;;;;N;;;;; -235F;APL FUNCTIONAL SYMBOL CIRCLE STAR;So;0;L;;;;;N;;;;; -2360;APL FUNCTIONAL SYMBOL QUAD COLON;So;0;L;;;;;N;;;;; -2361;APL FUNCTIONAL SYMBOL UP TACK DIAERESIS;So;0;L;;;;;N;;;;; -2362;APL FUNCTIONAL SYMBOL DEL DIAERESIS;So;0;L;;;;;N;;;;; -2363;APL FUNCTIONAL SYMBOL STAR DIAERESIS;So;0;L;;;;;N;;;;; -2364;APL FUNCTIONAL SYMBOL JOT DIAERESIS;So;0;L;;;;;N;;;;; -2365;APL FUNCTIONAL SYMBOL CIRCLE DIAERESIS;So;0;L;;;;;N;;;;; -2366;APL FUNCTIONAL SYMBOL DOWN SHOE STILE;So;0;L;;;;;N;;;;; -2367;APL FUNCTIONAL SYMBOL LEFT SHOE STILE;So;0;L;;;;;N;;;;; -2368;APL FUNCTIONAL SYMBOL TILDE DIAERESIS;So;0;L;;;;;N;;;;; -2369;APL FUNCTIONAL SYMBOL GREATER-THAN DIAERESIS;So;0;L;;;;;N;;;;; -236A;APL FUNCTIONAL SYMBOL COMMA BAR;So;0;L;;;;;N;;;;; -236B;APL FUNCTIONAL SYMBOL DEL TILDE;So;0;L;;;;;N;;;;; -236C;APL FUNCTIONAL SYMBOL ZILDE;So;0;L;;;;;N;;;;; -236D;APL FUNCTIONAL SYMBOL STILE TILDE;So;0;L;;;;;N;;;;; -236E;APL FUNCTIONAL SYMBOL SEMICOLON UNDERBAR;So;0;L;;;;;N;;;;; -236F;APL FUNCTIONAL SYMBOL QUAD NOT EQUAL;So;0;L;;;;;N;;;;; -2370;APL FUNCTIONAL SYMBOL QUAD QUESTION;So;0;L;;;;;N;;;;; -2371;APL FUNCTIONAL SYMBOL DOWN CARET TILDE;So;0;L;;;;;N;;;;; -2372;APL FUNCTIONAL SYMBOL UP CARET TILDE;So;0;L;;;;;N;;;;; -2373;APL FUNCTIONAL SYMBOL IOTA;So;0;L;;;;;N;;;;; -2374;APL FUNCTIONAL SYMBOL RHO;So;0;L;;;;;N;;;;; -2375;APL FUNCTIONAL SYMBOL OMEGA;So;0;L;;;;;N;;;;; -2376;APL FUNCTIONAL SYMBOL ALPHA UNDERBAR;So;0;L;;;;;N;;;;; -2377;APL FUNCTIONAL SYMBOL EPSILON UNDERBAR;So;0;L;;;;;N;;;;; -2378;APL FUNCTIONAL SYMBOL IOTA UNDERBAR;So;0;L;;;;;N;;;;; -2379;APL FUNCTIONAL SYMBOL OMEGA UNDERBAR;So;0;L;;;;;N;;;;; -237A;APL FUNCTIONAL SYMBOL ALPHA;So;0;L;;;;;N;;;;; -237B;NOT CHECK MARK;So;0;ON;;;;;N;;;;; -237C;RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW;Sm;0;ON;;;;;N;;;;; -237D;SHOULDERED OPEN BOX;So;0;ON;;;;;N;;;;; -237E;BELL SYMBOL;So;0;ON;;;;;N;;;;; -237F;VERTICAL LINE WITH MIDDLE DOT;So;0;ON;;;;;N;;;;; -2380;INSERTION SYMBOL;So;0;ON;;;;;N;;;;; -2381;CONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;; -2382;DISCONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;; -2383;EMPHASIS SYMBOL;So;0;ON;;;;;N;;;;; -2384;COMPOSITION SYMBOL;So;0;ON;;;;;N;;;;; -2385;WHITE SQUARE WITH CENTRE VERTICAL LINE;So;0;ON;;;;;N;;;;; -2386;ENTER SYMBOL;So;0;ON;;;;;N;;;;; -2387;ALTERNATIVE KEY SYMBOL;So;0;ON;;;;;N;;;;; -2388;HELM SYMBOL;So;0;ON;;;;;N;;;;; -2389;CIRCLED HORIZONTAL BAR WITH NOTCH;So;0;ON;;;;;N;;;;; -238A;CIRCLED TRIANGLE DOWN;So;0;ON;;;;;N;;;;; -238B;BROKEN CIRCLE WITH NORTHWEST ARROW;So;0;ON;;;;;N;;;;; -238C;UNDO SYMBOL;So;0;ON;;;;;N;;;;; -238D;MONOSTABLE SYMBOL;So;0;ON;;;;;N;;;;; -238E;HYSTERESIS SYMBOL;So;0;ON;;;;;N;;;;; -238F;OPEN-CIRCUIT-OUTPUT H-TYPE SYMBOL;So;0;ON;;;;;N;;;;; -2390;OPEN-CIRCUIT-OUTPUT L-TYPE SYMBOL;So;0;ON;;;;;N;;;;; -2391;PASSIVE-PULL-DOWN-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;; -2392;PASSIVE-PULL-UP-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;; -2393;DIRECT CURRENT SYMBOL FORM TWO;So;0;ON;;;;;N;;;;; -2394;SOFTWARE-FUNCTION SYMBOL;So;0;ON;;;;;N;;;;; -2395;APL FUNCTIONAL SYMBOL QUAD;So;0;L;;;;;N;;;;; -2396;DECIMAL SEPARATOR KEY SYMBOL;So;0;ON;;;;;N;;;;; -2397;PREVIOUS PAGE;So;0;ON;;;;;N;;;;; -2398;NEXT PAGE;So;0;ON;;;;;N;;;;; -2399;PRINT SCREEN SYMBOL;So;0;ON;;;;;N;;;;; -239A;CLEAR SCREEN SYMBOL;So;0;ON;;;;;N;;;;; -239B;LEFT PARENTHESIS UPPER HOOK;Sm;0;ON;;;;;N;;;;; -239C;LEFT PARENTHESIS EXTENSION;Sm;0;ON;;;;;N;;;;; -239D;LEFT PARENTHESIS LOWER HOOK;Sm;0;ON;;;;;N;;;;; -239E;RIGHT PARENTHESIS UPPER HOOK;Sm;0;ON;;;;;N;;;;; -239F;RIGHT PARENTHESIS EXTENSION;Sm;0;ON;;;;;N;;;;; -23A0;RIGHT PARENTHESIS LOWER HOOK;Sm;0;ON;;;;;N;;;;; -23A1;LEFT SQUARE BRACKET UPPER CORNER;Sm;0;ON;;;;;N;;;;; -23A2;LEFT SQUARE BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;; -23A3;LEFT SQUARE BRACKET LOWER CORNER;Sm;0;ON;;;;;N;;;;; -23A4;RIGHT SQUARE BRACKET UPPER CORNER;Sm;0;ON;;;;;N;;;;; -23A5;RIGHT SQUARE BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;; -23A6;RIGHT SQUARE BRACKET LOWER CORNER;Sm;0;ON;;;;;N;;;;; -23A7;LEFT CURLY BRACKET UPPER HOOK;Sm;0;ON;;;;;N;;;;; -23A8;LEFT CURLY BRACKET MIDDLE PIECE;Sm;0;ON;;;;;N;;;;; -23A9;LEFT CURLY BRACKET LOWER HOOK;Sm;0;ON;;;;;N;;;;; -23AA;CURLY BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;; -23AB;RIGHT CURLY BRACKET UPPER HOOK;Sm;0;ON;;;;;N;;;;; -23AC;RIGHT CURLY BRACKET MIDDLE PIECE;Sm;0;ON;;;;;N;;;;; -23AD;RIGHT CURLY BRACKET LOWER HOOK;Sm;0;ON;;;;;N;;;;; -23AE;INTEGRAL EXTENSION;Sm;0;ON;;;;;N;;;;; -23AF;HORIZONTAL LINE EXTENSION;Sm;0;ON;;;;;N;;;;; -23B0;UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION;Sm;0;ON;;;;;N;;;;; -23B1;UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION;Sm;0;ON;;;;;N;;;;; -23B2;SUMMATION TOP;Sm;0;ON;;;;;N;;;;; -23B3;SUMMATION BOTTOM;Sm;0;ON;;;;;N;;;;; -23B4;TOP SQUARE BRACKET;So;0;ON;;;;;N;;;;; -23B5;BOTTOM SQUARE BRACKET;So;0;ON;;;;;N;;;;; -23B6;BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET;So;0;ON;;;;;N;;;;; -23B7;RADICAL SYMBOL BOTTOM;So;0;ON;;;;;N;;;;; -23B8;LEFT VERTICAL BOX LINE;So;0;ON;;;;;N;;;;; -23B9;RIGHT VERTICAL BOX LINE;So;0;ON;;;;;N;;;;; -23BA;HORIZONTAL SCAN LINE-1;So;0;ON;;;;;N;;;;; -23BB;HORIZONTAL SCAN LINE-3;So;0;ON;;;;;N;;;;; -23BC;HORIZONTAL SCAN LINE-7;So;0;ON;;;;;N;;;;; -23BD;HORIZONTAL SCAN LINE-9;So;0;ON;;;;;N;;;;; -23BE;DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT;So;0;ON;;;;;N;;;;; -23BF;DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT;So;0;ON;;;;;N;;;;; -23C0;DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE;So;0;ON;;;;;N;;;;; -23C1;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE;So;0;ON;;;;;N;;;;; -23C2;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE;So;0;ON;;;;;N;;;;; -23C3;DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE;So;0;ON;;;;;N;;;;; -23C4;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE;So;0;ON;;;;;N;;;;; -23C5;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE;So;0;ON;;;;;N;;;;; -23C6;DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE;So;0;ON;;;;;N;;;;; -23C7;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE;So;0;ON;;;;;N;;;;; -23C8;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE;So;0;ON;;;;;N;;;;; -23C9;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL;So;0;ON;;;;;N;;;;; -23CA;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL;So;0;ON;;;;;N;;;;; -23CB;DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT;So;0;ON;;;;;N;;;;; -23CC;DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT;So;0;ON;;;;;N;;;;; -23CD;SQUARE FOOT;So;0;ON;;;;;N;;;;; -23CE;RETURN SYMBOL;So;0;ON;;;;;N;;;;; -23CF;EJECT SYMBOL;So;0;ON;;;;;N;;;;; -23D0;VERTICAL LINE EXTENSION;So;0;ON;;;;;N;;;;; -23D1;METRICAL BREVE;So;0;ON;;;;;N;;;;; -23D2;METRICAL LONG OVER SHORT;So;0;ON;;;;;N;;;;; -23D3;METRICAL SHORT OVER LONG;So;0;ON;;;;;N;;;;; -23D4;METRICAL LONG OVER TWO SHORTS;So;0;ON;;;;;N;;;;; -23D5;METRICAL TWO SHORTS OVER LONG;So;0;ON;;;;;N;;;;; -23D6;METRICAL TWO SHORTS JOINED;So;0;ON;;;;;N;;;;; -23D7;METRICAL TRISEME;So;0;ON;;;;;N;;;;; -23D8;METRICAL TETRASEME;So;0;ON;;;;;N;;;;; -23D9;METRICAL PENTASEME;So;0;ON;;;;;N;;;;; -23DA;EARTH GROUND;So;0;ON;;;;;N;;;;; -23DB;FUSE;So;0;ON;;;;;N;;;;; -23DC;TOP PARENTHESIS;Sm;0;ON;;;;;N;;;;; -23DD;BOTTOM PARENTHESIS;Sm;0;ON;;;;;N;;;;; -23DE;TOP CURLY BRACKET;Sm;0;ON;;;;;N;;;;; -23DF;BOTTOM CURLY BRACKET;Sm;0;ON;;;;;N;;;;; -23E0;TOP TORTOISE SHELL BRACKET;Sm;0;ON;;;;;N;;;;; -23E1;BOTTOM TORTOISE SHELL BRACKET;Sm;0;ON;;;;;N;;;;; -23E2;WHITE TRAPEZIUM;So;0;ON;;;;;N;;;;; -23E3;BENZENE RING WITH CIRCLE;So;0;ON;;;;;N;;;;; -23E4;STRAIGHTNESS;So;0;ON;;;;;N;;;;; -23E5;FLATNESS;So;0;ON;;;;;N;;;;; -23E6;AC CURRENT;So;0;ON;;;;;N;;;;; -23E7;ELECTRICAL INTERSECTION;So;0;ON;;;;;N;;;;; -23E8;DECIMAL EXPONENT SYMBOL;So;0;ON;;;;;N;;;;; -23E9;BLACK RIGHT-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;; -23EA;BLACK LEFT-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;; -23EB;BLACK UP-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;; -23EC;BLACK DOWN-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;; -23ED;BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR;So;0;ON;;;;;N;;;;; -23EE;BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR;So;0;ON;;;;;N;;;;; -23EF;BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR;So;0;ON;;;;;N;;;;; -23F0;ALARM CLOCK;So;0;ON;;;;;N;;;;; -23F1;STOPWATCH;So;0;ON;;;;;N;;;;; -23F2;TIMER CLOCK;So;0;ON;;;;;N;;;;; -23F3;HOURGLASS WITH FLOWING SAND;So;0;ON;;;;;N;;;;; -23F4;BLACK MEDIUM LEFT-POINTING TRIANGLE;So;0;ON;;;;;N;;;;; -23F5;BLACK MEDIUM RIGHT-POINTING TRIANGLE;So;0;ON;;;;;N;;;;; -23F6;BLACK MEDIUM UP-POINTING TRIANGLE;So;0;ON;;;;;N;;;;; -23F7;BLACK MEDIUM DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;;;;; -23F8;DOUBLE VERTICAL BAR;So;0;ON;;;;;N;;;;; -23F9;BLACK SQUARE FOR STOP;So;0;ON;;;;;N;;;;; -23FA;BLACK CIRCLE FOR RECORD;So;0;ON;;;;;N;;;;; -23FB;POWER SYMBOL;So;0;ON;;;;;N;;;;; -23FC;POWER ON-OFF SYMBOL;So;0;ON;;;;;N;;;;; -23FD;POWER ON SYMBOL;So;0;ON;;;;;N;;;;; -23FE;POWER SLEEP SYMBOL;So;0;ON;;;;;N;;;;; -23FF;OBSERVER EYE SYMBOL;So;0;ON;;;;;N;;;;; -2400;SYMBOL FOR NULL;So;0;ON;;;;;N;GRAPHIC FOR NULL;;;; -2401;SYMBOL FOR START OF HEADING;So;0;ON;;;;;N;GRAPHIC FOR START OF HEADING;;;; -2402;SYMBOL FOR START OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR START OF TEXT;;;; -2403;SYMBOL FOR END OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR END OF TEXT;;;; -2404;SYMBOL FOR END OF TRANSMISSION;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION;;;; -2405;SYMBOL FOR ENQUIRY;So;0;ON;;;;;N;GRAPHIC FOR ENQUIRY;;;; -2406;SYMBOL FOR ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR ACKNOWLEDGE;;;; -2407;SYMBOL FOR BELL;So;0;ON;;;;;N;GRAPHIC FOR BELL;;;; -2408;SYMBOL FOR BACKSPACE;So;0;ON;;;;;N;GRAPHIC FOR BACKSPACE;;;; -2409;SYMBOL FOR HORIZONTAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR HORIZONTAL TABULATION;;;; -240A;SYMBOL FOR LINE FEED;So;0;ON;;;;;N;GRAPHIC FOR LINE FEED;;;; -240B;SYMBOL FOR VERTICAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR VERTICAL TABULATION;;;; -240C;SYMBOL FOR FORM FEED;So;0;ON;;;;;N;GRAPHIC FOR FORM FEED;;;; -240D;SYMBOL FOR CARRIAGE RETURN;So;0;ON;;;;;N;GRAPHIC FOR CARRIAGE RETURN;;;; -240E;SYMBOL FOR SHIFT OUT;So;0;ON;;;;;N;GRAPHIC FOR SHIFT OUT;;;; -240F;SYMBOL FOR SHIFT IN;So;0;ON;;;;;N;GRAPHIC FOR SHIFT IN;;;; -2410;SYMBOL FOR DATA LINK ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR DATA LINK ESCAPE;;;; -2411;SYMBOL FOR DEVICE CONTROL ONE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL ONE;;;; -2412;SYMBOL FOR DEVICE CONTROL TWO;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL TWO;;;; -2413;SYMBOL FOR DEVICE CONTROL THREE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL THREE;;;; -2414;SYMBOL FOR DEVICE CONTROL FOUR;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL FOUR;;;; -2415;SYMBOL FOR NEGATIVE ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR NEGATIVE ACKNOWLEDGE;;;; -2416;SYMBOL FOR SYNCHRONOUS IDLE;So;0;ON;;;;;N;GRAPHIC FOR SYNCHRONOUS IDLE;;;; -2417;SYMBOL FOR END OF TRANSMISSION BLOCK;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION BLOCK;;;; -2418;SYMBOL FOR CANCEL;So;0;ON;;;;;N;GRAPHIC FOR CANCEL;;;; -2419;SYMBOL FOR END OF MEDIUM;So;0;ON;;;;;N;GRAPHIC FOR END OF MEDIUM;;;; -241A;SYMBOL FOR SUBSTITUTE;So;0;ON;;;;;N;GRAPHIC FOR SUBSTITUTE;;;; -241B;SYMBOL FOR ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR ESCAPE;;;; -241C;SYMBOL FOR FILE SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR FILE SEPARATOR;;;; -241D;SYMBOL FOR GROUP SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR GROUP SEPARATOR;;;; -241E;SYMBOL FOR RECORD SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR RECORD SEPARATOR;;;; -241F;SYMBOL FOR UNIT SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR UNIT SEPARATOR;;;; -2420;SYMBOL FOR SPACE;So;0;ON;;;;;N;GRAPHIC FOR SPACE;;;; -2421;SYMBOL FOR DELETE;So;0;ON;;;;;N;GRAPHIC FOR DELETE;;;; -2422;BLANK SYMBOL;So;0;ON;;;;;N;BLANK;;;; -2423;OPEN BOX;So;0;ON;;;;;N;;;;; -2424;SYMBOL FOR NEWLINE;So;0;ON;;;;;N;GRAPHIC FOR NEWLINE;;;; -2425;SYMBOL FOR DELETE FORM TWO;So;0;ON;;;;;N;;;;; -2426;SYMBOL FOR SUBSTITUTE FORM TWO;So;0;ON;;;;;N;;;;; -2440;OCR HOOK;So;0;ON;;;;;N;;;;; -2441;OCR CHAIR;So;0;ON;;;;;N;;;;; -2442;OCR FORK;So;0;ON;;;;;N;;;;; -2443;OCR INVERTED FORK;So;0;ON;;;;;N;;;;; -2444;OCR BELT BUCKLE;So;0;ON;;;;;N;;;;; -2445;OCR BOW TIE;So;0;ON;;;;;N;;;;; -2446;OCR BRANCH BANK IDENTIFICATION;So;0;ON;;;;;N;;;;; -2447;OCR AMOUNT OF CHECK;So;0;ON;;;;;N;;;;; -2448;OCR DASH;So;0;ON;;;;;N;;;;; -2449;OCR CUSTOMER ACCOUNT NUMBER;So;0;ON;;;;;N;;;;; -244A;OCR DOUBLE BACKSLASH;So;0;ON;;;;;N;;;;; -2460;CIRCLED DIGIT ONE;No;0;ON;<circle> 0031;;1;1;N;;;;; -2461;CIRCLED DIGIT TWO;No;0;ON;<circle> 0032;;2;2;N;;;;; -2462;CIRCLED DIGIT THREE;No;0;ON;<circle> 0033;;3;3;N;;;;; -2463;CIRCLED DIGIT FOUR;No;0;ON;<circle> 0034;;4;4;N;;;;; -2464;CIRCLED DIGIT FIVE;No;0;ON;<circle> 0035;;5;5;N;;;;; -2465;CIRCLED DIGIT SIX;No;0;ON;<circle> 0036;;6;6;N;;;;; -2466;CIRCLED DIGIT SEVEN;No;0;ON;<circle> 0037;;7;7;N;;;;; -2467;CIRCLED DIGIT EIGHT;No;0;ON;<circle> 0038;;8;8;N;;;;; -2468;CIRCLED DIGIT NINE;No;0;ON;<circle> 0039;;9;9;N;;;;; -2469;CIRCLED NUMBER TEN;No;0;ON;<circle> 0031 0030;;;10;N;;;;; -246A;CIRCLED NUMBER ELEVEN;No;0;ON;<circle> 0031 0031;;;11;N;;;;; -246B;CIRCLED NUMBER TWELVE;No;0;ON;<circle> 0031 0032;;;12;N;;;;; -246C;CIRCLED NUMBER THIRTEEN;No;0;ON;<circle> 0031 0033;;;13;N;;;;; -246D;CIRCLED NUMBER FOURTEEN;No;0;ON;<circle> 0031 0034;;;14;N;;;;; -246E;CIRCLED NUMBER FIFTEEN;No;0;ON;<circle> 0031 0035;;;15;N;;;;; -246F;CIRCLED NUMBER SIXTEEN;No;0;ON;<circle> 0031 0036;;;16;N;;;;; -2470;CIRCLED NUMBER SEVENTEEN;No;0;ON;<circle> 0031 0037;;;17;N;;;;; -2471;CIRCLED NUMBER EIGHTEEN;No;0;ON;<circle> 0031 0038;;;18;N;;;;; -2472;CIRCLED NUMBER NINETEEN;No;0;ON;<circle> 0031 0039;;;19;N;;;;; -2473;CIRCLED NUMBER TWENTY;No;0;ON;<circle> 0032 0030;;;20;N;;;;; -2474;PARENTHESIZED DIGIT ONE;No;0;ON;<compat> 0028 0031 0029;;1;1;N;;;;; -2475;PARENTHESIZED DIGIT TWO;No;0;ON;<compat> 0028 0032 0029;;2;2;N;;;;; -2476;PARENTHESIZED DIGIT THREE;No;0;ON;<compat> 0028 0033 0029;;3;3;N;;;;; -2477;PARENTHESIZED DIGIT FOUR;No;0;ON;<compat> 0028 0034 0029;;4;4;N;;;;; -2478;PARENTHESIZED DIGIT FIVE;No;0;ON;<compat> 0028 0035 0029;;5;5;N;;;;; -2479;PARENTHESIZED DIGIT SIX;No;0;ON;<compat> 0028 0036 0029;;6;6;N;;;;; -247A;PARENTHESIZED DIGIT SEVEN;No;0;ON;<compat> 0028 0037 0029;;7;7;N;;;;; -247B;PARENTHESIZED DIGIT EIGHT;No;0;ON;<compat> 0028 0038 0029;;8;8;N;;;;; -247C;PARENTHESIZED DIGIT NINE;No;0;ON;<compat> 0028 0039 0029;;9;9;N;;;;; -247D;PARENTHESIZED NUMBER TEN;No;0;ON;<compat> 0028 0031 0030 0029;;;10;N;;;;; -247E;PARENTHESIZED NUMBER ELEVEN;No;0;ON;<compat> 0028 0031 0031 0029;;;11;N;;;;; -247F;PARENTHESIZED NUMBER TWELVE;No;0;ON;<compat> 0028 0031 0032 0029;;;12;N;;;;; -2480;PARENTHESIZED NUMBER THIRTEEN;No;0;ON;<compat> 0028 0031 0033 0029;;;13;N;;;;; -2481;PARENTHESIZED NUMBER FOURTEEN;No;0;ON;<compat> 0028 0031 0034 0029;;;14;N;;;;; -2482;PARENTHESIZED NUMBER FIFTEEN;No;0;ON;<compat> 0028 0031 0035 0029;;;15;N;;;;; -2483;PARENTHESIZED NUMBER SIXTEEN;No;0;ON;<compat> 0028 0031 0036 0029;;;16;N;;;;; -2484;PARENTHESIZED NUMBER SEVENTEEN;No;0;ON;<compat> 0028 0031 0037 0029;;;17;N;;;;; -2485;PARENTHESIZED NUMBER EIGHTEEN;No;0;ON;<compat> 0028 0031 0038 0029;;;18;N;;;;; -2486;PARENTHESIZED NUMBER NINETEEN;No;0;ON;<compat> 0028 0031 0039 0029;;;19;N;;;;; -2487;PARENTHESIZED NUMBER TWENTY;No;0;ON;<compat> 0028 0032 0030 0029;;;20;N;;;;; -2488;DIGIT ONE FULL STOP;No;0;EN;<compat> 0031 002E;;1;1;N;DIGIT ONE PERIOD;;;; -2489;DIGIT TWO FULL STOP;No;0;EN;<compat> 0032 002E;;2;2;N;DIGIT TWO PERIOD;;;; -248A;DIGIT THREE FULL STOP;No;0;EN;<compat> 0033 002E;;3;3;N;DIGIT THREE PERIOD;;;; -248B;DIGIT FOUR FULL STOP;No;0;EN;<compat> 0034 002E;;4;4;N;DIGIT FOUR PERIOD;;;; -248C;DIGIT FIVE FULL STOP;No;0;EN;<compat> 0035 002E;;5;5;N;DIGIT FIVE PERIOD;;;; -248D;DIGIT SIX FULL STOP;No;0;EN;<compat> 0036 002E;;6;6;N;DIGIT SIX PERIOD;;;; -248E;DIGIT SEVEN FULL STOP;No;0;EN;<compat> 0037 002E;;7;7;N;DIGIT SEVEN PERIOD;;;; -248F;DIGIT EIGHT FULL STOP;No;0;EN;<compat> 0038 002E;;8;8;N;DIGIT EIGHT PERIOD;;;; -2490;DIGIT NINE FULL STOP;No;0;EN;<compat> 0039 002E;;9;9;N;DIGIT NINE PERIOD;;;; -2491;NUMBER TEN FULL STOP;No;0;EN;<compat> 0031 0030 002E;;;10;N;NUMBER TEN PERIOD;;;; -2492;NUMBER ELEVEN FULL STOP;No;0;EN;<compat> 0031 0031 002E;;;11;N;NUMBER ELEVEN PERIOD;;;; -2493;NUMBER TWELVE FULL STOP;No;0;EN;<compat> 0031 0032 002E;;;12;N;NUMBER TWELVE PERIOD;;;; -2494;NUMBER THIRTEEN FULL STOP;No;0;EN;<compat> 0031 0033 002E;;;13;N;NUMBER THIRTEEN PERIOD;;;; -2495;NUMBER FOURTEEN FULL STOP;No;0;EN;<compat> 0031 0034 002E;;;14;N;NUMBER FOURTEEN PERIOD;;;; -2496;NUMBER FIFTEEN FULL STOP;No;0;EN;<compat> 0031 0035 002E;;;15;N;NUMBER FIFTEEN PERIOD;;;; -2497;NUMBER SIXTEEN FULL STOP;No;0;EN;<compat> 0031 0036 002E;;;16;N;NUMBER SIXTEEN PERIOD;;;; -2498;NUMBER SEVENTEEN FULL STOP;No;0;EN;<compat> 0031 0037 002E;;;17;N;NUMBER SEVENTEEN PERIOD;;;; -2499;NUMBER EIGHTEEN FULL STOP;No;0;EN;<compat> 0031 0038 002E;;;18;N;NUMBER EIGHTEEN PERIOD;;;; -249A;NUMBER NINETEEN FULL STOP;No;0;EN;<compat> 0031 0039 002E;;;19;N;NUMBER NINETEEN PERIOD;;;; -249B;NUMBER TWENTY FULL STOP;No;0;EN;<compat> 0032 0030 002E;;;20;N;NUMBER TWENTY PERIOD;;;; -249C;PARENTHESIZED LATIN SMALL LETTER A;So;0;L;<compat> 0028 0061 0029;;;;N;;;;; -249D;PARENTHESIZED LATIN SMALL LETTER B;So;0;L;<compat> 0028 0062 0029;;;;N;;;;; -249E;PARENTHESIZED LATIN SMALL LETTER C;So;0;L;<compat> 0028 0063 0029;;;;N;;;;; -249F;PARENTHESIZED LATIN SMALL LETTER D;So;0;L;<compat> 0028 0064 0029;;;;N;;;;; -24A0;PARENTHESIZED LATIN SMALL LETTER E;So;0;L;<compat> 0028 0065 0029;;;;N;;;;; -24A1;PARENTHESIZED LATIN SMALL LETTER F;So;0;L;<compat> 0028 0066 0029;;;;N;;;;; -24A2;PARENTHESIZED LATIN SMALL LETTER G;So;0;L;<compat> 0028 0067 0029;;;;N;;;;; -24A3;PARENTHESIZED LATIN SMALL LETTER H;So;0;L;<compat> 0028 0068 0029;;;;N;;;;; -24A4;PARENTHESIZED LATIN SMALL LETTER I;So;0;L;<compat> 0028 0069 0029;;;;N;;;;; -24A5;PARENTHESIZED LATIN SMALL LETTER J;So;0;L;<compat> 0028 006A 0029;;;;N;;;;; -24A6;PARENTHESIZED LATIN SMALL LETTER K;So;0;L;<compat> 0028 006B 0029;;;;N;;;;; -24A7;PARENTHESIZED LATIN SMALL LETTER L;So;0;L;<compat> 0028 006C 0029;;;;N;;;;; -24A8;PARENTHESIZED LATIN SMALL LETTER M;So;0;L;<compat> 0028 006D 0029;;;;N;;;;; -24A9;PARENTHESIZED LATIN SMALL LETTER N;So;0;L;<compat> 0028 006E 0029;;;;N;;;;; -24AA;PARENTHESIZED LATIN SMALL LETTER O;So;0;L;<compat> 0028 006F 0029;;;;N;;;;; -24AB;PARENTHESIZED LATIN SMALL LETTER P;So;0;L;<compat> 0028 0070 0029;;;;N;;;;; -24AC;PARENTHESIZED LATIN SMALL LETTER Q;So;0;L;<compat> 0028 0071 0029;;;;N;;;;; -24AD;PARENTHESIZED LATIN SMALL LETTER R;So;0;L;<compat> 0028 0072 0029;;;;N;;;;; -24AE;PARENTHESIZED LATIN SMALL LETTER S;So;0;L;<compat> 0028 0073 0029;;;;N;;;;; -24AF;PARENTHESIZED LATIN SMALL LETTER T;So;0;L;<compat> 0028 0074 0029;;;;N;;;;; -24B0;PARENTHESIZED LATIN SMALL LETTER U;So;0;L;<compat> 0028 0075 0029;;;;N;;;;; -24B1;PARENTHESIZED LATIN SMALL LETTER V;So;0;L;<compat> 0028 0076 0029;;;;N;;;;; -24B2;PARENTHESIZED LATIN SMALL LETTER W;So;0;L;<compat> 0028 0077 0029;;;;N;;;;; -24B3;PARENTHESIZED LATIN SMALL LETTER X;So;0;L;<compat> 0028 0078 0029;;;;N;;;;; -24B4;PARENTHESIZED LATIN SMALL LETTER Y;So;0;L;<compat> 0028 0079 0029;;;;N;;;;; -24B5;PARENTHESIZED LATIN SMALL LETTER Z;So;0;L;<compat> 0028 007A 0029;;;;N;;;;; -24B6;CIRCLED LATIN CAPITAL LETTER A;So;0;L;<circle> 0041;;;;N;;;;24D0; -24B7;CIRCLED LATIN CAPITAL LETTER B;So;0;L;<circle> 0042;;;;N;;;;24D1; -24B8;CIRCLED LATIN CAPITAL LETTER C;So;0;L;<circle> 0043;;;;N;;;;24D2; -24B9;CIRCLED LATIN CAPITAL LETTER D;So;0;L;<circle> 0044;;;;N;;;;24D3; -24BA;CIRCLED LATIN CAPITAL LETTER E;So;0;L;<circle> 0045;;;;N;;;;24D4; -24BB;CIRCLED LATIN CAPITAL LETTER F;So;0;L;<circle> 0046;;;;N;;;;24D5; -24BC;CIRCLED LATIN CAPITAL LETTER G;So;0;L;<circle> 0047;;;;N;;;;24D6; -24BD;CIRCLED LATIN CAPITAL LETTER H;So;0;L;<circle> 0048;;;;N;;;;24D7; -24BE;CIRCLED LATIN CAPITAL LETTER I;So;0;L;<circle> 0049;;;;N;;;;24D8; -24BF;CIRCLED LATIN CAPITAL LETTER J;So;0;L;<circle> 004A;;;;N;;;;24D9; -24C0;CIRCLED LATIN CAPITAL LETTER K;So;0;L;<circle> 004B;;;;N;;;;24DA; -24C1;CIRCLED LATIN CAPITAL LETTER L;So;0;L;<circle> 004C;;;;N;;;;24DB; -24C2;CIRCLED LATIN CAPITAL LETTER M;So;0;L;<circle> 004D;;;;N;;;;24DC; -24C3;CIRCLED LATIN CAPITAL LETTER N;So;0;L;<circle> 004E;;;;N;;;;24DD; -24C4;CIRCLED LATIN CAPITAL LETTER O;So;0;L;<circle> 004F;;;;N;;;;24DE; -24C5;CIRCLED LATIN CAPITAL LETTER P;So;0;L;<circle> 0050;;;;N;;;;24DF; -24C6;CIRCLED LATIN CAPITAL LETTER Q;So;0;L;<circle> 0051;;;;N;;;;24E0; -24C7;CIRCLED LATIN CAPITAL LETTER R;So;0;L;<circle> 0052;;;;N;;;;24E1; -24C8;CIRCLED LATIN CAPITAL LETTER S;So;0;L;<circle> 0053;;;;N;;;;24E2; -24C9;CIRCLED LATIN CAPITAL LETTER T;So;0;L;<circle> 0054;;;;N;;;;24E3; -24CA;CIRCLED LATIN CAPITAL LETTER U;So;0;L;<circle> 0055;;;;N;;;;24E4; -24CB;CIRCLED LATIN CAPITAL LETTER V;So;0;L;<circle> 0056;;;;N;;;;24E5; -24CC;CIRCLED LATIN CAPITAL LETTER W;So;0;L;<circle> 0057;;;;N;;;;24E6; -24CD;CIRCLED LATIN CAPITAL LETTER X;So;0;L;<circle> 0058;;;;N;;;;24E7; -24CE;CIRCLED LATIN CAPITAL LETTER Y;So;0;L;<circle> 0059;;;;N;;;;24E8; -24CF;CIRCLED LATIN CAPITAL LETTER Z;So;0;L;<circle> 005A;;;;N;;;;24E9; -24D0;CIRCLED LATIN SMALL LETTER A;So;0;L;<circle> 0061;;;;N;;;24B6;;24B6 -24D1;CIRCLED LATIN SMALL LETTER B;So;0;L;<circle> 0062;;;;N;;;24B7;;24B7 -24D2;CIRCLED LATIN SMALL LETTER C;So;0;L;<circle> 0063;;;;N;;;24B8;;24B8 -24D3;CIRCLED LATIN SMALL LETTER D;So;0;L;<circle> 0064;;;;N;;;24B9;;24B9 -24D4;CIRCLED LATIN SMALL LETTER E;So;0;L;<circle> 0065;;;;N;;;24BA;;24BA -24D5;CIRCLED LATIN SMALL LETTER F;So;0;L;<circle> 0066;;;;N;;;24BB;;24BB -24D6;CIRCLED LATIN SMALL LETTER G;So;0;L;<circle> 0067;;;;N;;;24BC;;24BC -24D7;CIRCLED LATIN SMALL LETTER H;So;0;L;<circle> 0068;;;;N;;;24BD;;24BD -24D8;CIRCLED LATIN SMALL LETTER I;So;0;L;<circle> 0069;;;;N;;;24BE;;24BE -24D9;CIRCLED LATIN SMALL LETTER J;So;0;L;<circle> 006A;;;;N;;;24BF;;24BF -24DA;CIRCLED LATIN SMALL LETTER K;So;0;L;<circle> 006B;;;;N;;;24C0;;24C0 -24DB;CIRCLED LATIN SMALL LETTER L;So;0;L;<circle> 006C;;;;N;;;24C1;;24C1 -24DC;CIRCLED LATIN SMALL LETTER M;So;0;L;<circle> 006D;;;;N;;;24C2;;24C2 -24DD;CIRCLED LATIN SMALL LETTER N;So;0;L;<circle> 006E;;;;N;;;24C3;;24C3 -24DE;CIRCLED LATIN SMALL LETTER O;So;0;L;<circle> 006F;;;;N;;;24C4;;24C4 -24DF;CIRCLED LATIN SMALL LETTER P;So;0;L;<circle> 0070;;;;N;;;24C5;;24C5 -24E0;CIRCLED LATIN SMALL LETTER Q;So;0;L;<circle> 0071;;;;N;;;24C6;;24C6 -24E1;CIRCLED LATIN SMALL LETTER R;So;0;L;<circle> 0072;;;;N;;;24C7;;24C7 -24E2;CIRCLED LATIN SMALL LETTER S;So;0;L;<circle> 0073;;;;N;;;24C8;;24C8 -24E3;CIRCLED LATIN SMALL LETTER T;So;0;L;<circle> 0074;;;;N;;;24C9;;24C9 -24E4;CIRCLED LATIN SMALL LETTER U;So;0;L;<circle> 0075;;;;N;;;24CA;;24CA -24E5;CIRCLED LATIN SMALL LETTER V;So;0;L;<circle> 0076;;;;N;;;24CB;;24CB -24E6;CIRCLED LATIN SMALL LETTER W;So;0;L;<circle> 0077;;;;N;;;24CC;;24CC -24E7;CIRCLED LATIN SMALL LETTER X;So;0;L;<circle> 0078;;;;N;;;24CD;;24CD -24E8;CIRCLED LATIN SMALL LETTER Y;So;0;L;<circle> 0079;;;;N;;;24CE;;24CE -24E9;CIRCLED LATIN SMALL LETTER Z;So;0;L;<circle> 007A;;;;N;;;24CF;;24CF -24EA;CIRCLED DIGIT ZERO;No;0;ON;<circle> 0030;;0;0;N;;;;; -24EB;NEGATIVE CIRCLED NUMBER ELEVEN;No;0;ON;;;;11;N;;;;; -24EC;NEGATIVE CIRCLED NUMBER TWELVE;No;0;ON;;;;12;N;;;;; -24ED;NEGATIVE CIRCLED NUMBER THIRTEEN;No;0;ON;;;;13;N;;;;; -24EE;NEGATIVE CIRCLED NUMBER FOURTEEN;No;0;ON;;;;14;N;;;;; -24EF;NEGATIVE CIRCLED NUMBER FIFTEEN;No;0;ON;;;;15;N;;;;; -24F0;NEGATIVE CIRCLED NUMBER SIXTEEN;No;0;ON;;;;16;N;;;;; -24F1;NEGATIVE CIRCLED NUMBER SEVENTEEN;No;0;ON;;;;17;N;;;;; -24F2;NEGATIVE CIRCLED NUMBER EIGHTEEN;No;0;ON;;;;18;N;;;;; -24F3;NEGATIVE CIRCLED NUMBER NINETEEN;No;0;ON;;;;19;N;;;;; -24F4;NEGATIVE CIRCLED NUMBER TWENTY;No;0;ON;;;;20;N;;;;; -24F5;DOUBLE CIRCLED DIGIT ONE;No;0;ON;;;1;1;N;;;;; -24F6;DOUBLE CIRCLED DIGIT TWO;No;0;ON;;;2;2;N;;;;; -24F7;DOUBLE CIRCLED DIGIT THREE;No;0;ON;;;3;3;N;;;;; -24F8;DOUBLE CIRCLED DIGIT FOUR;No;0;ON;;;4;4;N;;;;; -24F9;DOUBLE CIRCLED DIGIT FIVE;No;0;ON;;;5;5;N;;;;; -24FA;DOUBLE CIRCLED DIGIT SIX;No;0;ON;;;6;6;N;;;;; -24FB;DOUBLE CIRCLED DIGIT SEVEN;No;0;ON;;;7;7;N;;;;; -24FC;DOUBLE CIRCLED DIGIT EIGHT;No;0;ON;;;8;8;N;;;;; -24FD;DOUBLE CIRCLED DIGIT NINE;No;0;ON;;;9;9;N;;;;; -24FE;DOUBLE CIRCLED NUMBER TEN;No;0;ON;;;;10;N;;;;; -24FF;NEGATIVE CIRCLED DIGIT ZERO;No;0;ON;;;0;0;N;;;;; -2500;BOX DRAWINGS LIGHT HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT HORIZONTAL;;;; -2501;BOX DRAWINGS HEAVY HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY HORIZONTAL;;;; -2502;BOX DRAWINGS LIGHT VERTICAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL;;;; -2503;BOX DRAWINGS HEAVY VERTICAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL;;;; -2504;BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH HORIZONTAL;;;; -2505;BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH HORIZONTAL;;;; -2506;BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH VERTICAL;;;; -2507;BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH VERTICAL;;;; -2508;BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH HORIZONTAL;;;; -2509;BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH HORIZONTAL;;;; -250A;BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH VERTICAL;;;; -250B;BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH VERTICAL;;;; -250C;BOX DRAWINGS LIGHT DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND RIGHT;;;; -250D;BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT HEAVY;;;; -250E;BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT LIGHT;;;; -250F;BOX DRAWINGS HEAVY DOWN AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND RIGHT;;;; -2510;BOX DRAWINGS LIGHT DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND LEFT;;;; -2511;BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT HEAVY;;;; -2512;BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT LIGHT;;;; -2513;BOX DRAWINGS HEAVY DOWN AND LEFT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND LEFT;;;; -2514;BOX DRAWINGS LIGHT UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT UP AND RIGHT;;;; -2515;BOX DRAWINGS UP LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT HEAVY;;;; -2516;BOX DRAWINGS UP HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT LIGHT;;;; -2517;BOX DRAWINGS HEAVY UP AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY UP AND RIGHT;;;; -2518;BOX DRAWINGS LIGHT UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT UP AND LEFT;;;; -2519;BOX DRAWINGS UP LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT HEAVY;;;; -251A;BOX DRAWINGS UP HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT LIGHT;;;; -251B;BOX DRAWINGS HEAVY UP AND LEFT;So;0;ON;;;;;N;FORMS HEAVY UP AND LEFT;;;; -251C;BOX DRAWINGS LIGHT VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND RIGHT;;;; -251D;BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND RIGHT HEAVY;;;; -251E;BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT DOWN LIGHT;;;; -251F;BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT UP LIGHT;;;; -2520;BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND RIGHT LIGHT;;;; -2521;BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT UP HEAVY;;;; -2522;BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT DOWN HEAVY;;;; -2523;BOX DRAWINGS HEAVY VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND RIGHT;;;; -2524;BOX DRAWINGS LIGHT VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND LEFT;;;; -2525;BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND LEFT HEAVY;;;; -2526;BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT DOWN LIGHT;;;; -2527;BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT UP LIGHT;;;; -2528;BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND LEFT LIGHT;;;; -2529;BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT UP HEAVY;;;; -252A;BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT DOWN HEAVY;;;; -252B;BOX DRAWINGS HEAVY VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND LEFT;;;; -252C;BOX DRAWINGS LIGHT DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOWN AND HORIZONTAL;;;; -252D;BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT DOWN LIGHT;;;; -252E;BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT DOWN LIGHT;;;; -252F;BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND HORIZONTAL HEAVY;;;; -2530;BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND HORIZONTAL LIGHT;;;; -2531;BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT DOWN HEAVY;;;; -2532;BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT DOWN HEAVY;;;; -2533;BOX DRAWINGS HEAVY DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOWN AND HORIZONTAL;;;; -2534;BOX DRAWINGS LIGHT UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT UP AND HORIZONTAL;;;; -2535;BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT UP LIGHT;;;; -2536;BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT UP LIGHT;;;; -2537;BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND HORIZONTAL HEAVY;;;; -2538;BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND HORIZONTAL LIGHT;;;; -2539;BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT UP HEAVY;;;; -253A;BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT UP HEAVY;;;; -253B;BOX DRAWINGS HEAVY UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY UP AND HORIZONTAL;;;; -253C;BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND HORIZONTAL;;;; -253D;BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT VERTICAL LIGHT;;;; -253E;BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT VERTICAL LIGHT;;;; -253F;BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND HORIZONTAL HEAVY;;;; -2540;BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND DOWN HORIZONTAL LIGHT;;;; -2541;BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND UP HORIZONTAL LIGHT;;;; -2542;BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND HORIZONTAL LIGHT;;;; -2543;BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT UP HEAVY AND RIGHT DOWN LIGHT;;;; -2544;BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT UP HEAVY AND LEFT DOWN LIGHT;;;; -2545;BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT DOWN HEAVY AND RIGHT UP LIGHT;;;; -2546;BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT DOWN HEAVY AND LEFT UP LIGHT;;;; -2547;BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND UP HORIZONTAL HEAVY;;;; -2548;BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND DOWN HORIZONTAL HEAVY;;;; -2549;BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT VERTICAL HEAVY;;;; -254A;BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT VERTICAL HEAVY;;;; -254B;BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND HORIZONTAL;;;; -254C;BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH HORIZONTAL;;;; -254D;BOX DRAWINGS HEAVY DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH HORIZONTAL;;;; -254E;BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH VERTICAL;;;; -254F;BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH VERTICAL;;;; -2550;BOX DRAWINGS DOUBLE HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE HORIZONTAL;;;; -2551;BOX DRAWINGS DOUBLE VERTICAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL;;;; -2552;BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND RIGHT DOUBLE;;;; -2553;BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND RIGHT SINGLE;;;; -2554;BOX DRAWINGS DOUBLE DOWN AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND RIGHT;;;; -2555;BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND LEFT DOUBLE;;;; -2556;BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND LEFT SINGLE;;;; -2557;BOX DRAWINGS DOUBLE DOWN AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND LEFT;;;; -2558;BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND RIGHT DOUBLE;;;; -2559;BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND RIGHT SINGLE;;;; -255A;BOX DRAWINGS DOUBLE UP AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE UP AND RIGHT;;;; -255B;BOX DRAWINGS UP SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND LEFT DOUBLE;;;; -255C;BOX DRAWINGS UP DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND LEFT SINGLE;;;; -255D;BOX DRAWINGS DOUBLE UP AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE UP AND LEFT;;;; -255E;BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND RIGHT DOUBLE;;;; -255F;BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND RIGHT SINGLE;;;; -2560;BOX DRAWINGS DOUBLE VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND RIGHT;;;; -2561;BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND LEFT DOUBLE;;;; -2562;BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND LEFT SINGLE;;;; -2563;BOX DRAWINGS DOUBLE VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND LEFT;;;; -2564;BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND HORIZONTAL DOUBLE;;;; -2565;BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND HORIZONTAL SINGLE;;;; -2566;BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND HORIZONTAL;;;; -2567;BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND HORIZONTAL DOUBLE;;;; -2568;BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND HORIZONTAL SINGLE;;;; -2569;BOX DRAWINGS DOUBLE UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE UP AND HORIZONTAL;;;; -256A;BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND HORIZONTAL DOUBLE;;;; -256B;BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND HORIZONTAL SINGLE;;;; -256C;BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND HORIZONTAL;;;; -256D;BOX DRAWINGS LIGHT ARC DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND RIGHT;;;; -256E;BOX DRAWINGS LIGHT ARC DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND LEFT;;;; -256F;BOX DRAWINGS LIGHT ARC UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND LEFT;;;; -2570;BOX DRAWINGS LIGHT ARC UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND RIGHT;;;; -2571;BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;;;; -2572;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;;;; -2573;BOX DRAWINGS LIGHT DIAGONAL CROSS;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL CROSS;;;; -2574;BOX DRAWINGS LIGHT LEFT;So;0;ON;;;;;N;FORMS LIGHT LEFT;;;; -2575;BOX DRAWINGS LIGHT UP;So;0;ON;;;;;N;FORMS LIGHT UP;;;; -2576;BOX DRAWINGS LIGHT RIGHT;So;0;ON;;;;;N;FORMS LIGHT RIGHT;;;; -2577;BOX DRAWINGS LIGHT DOWN;So;0;ON;;;;;N;FORMS LIGHT DOWN;;;; -2578;BOX DRAWINGS HEAVY LEFT;So;0;ON;;;;;N;FORMS HEAVY LEFT;;;; -2579;BOX DRAWINGS HEAVY UP;So;0;ON;;;;;N;FORMS HEAVY UP;;;; -257A;BOX DRAWINGS HEAVY RIGHT;So;0;ON;;;;;N;FORMS HEAVY RIGHT;;;; -257B;BOX DRAWINGS HEAVY DOWN;So;0;ON;;;;;N;FORMS HEAVY DOWN;;;; -257C;BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT;So;0;ON;;;;;N;FORMS LIGHT LEFT AND HEAVY RIGHT;;;; -257D;BOX DRAWINGS LIGHT UP AND HEAVY DOWN;So;0;ON;;;;;N;FORMS LIGHT UP AND HEAVY DOWN;;;; -257E;BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT;So;0;ON;;;;;N;FORMS HEAVY LEFT AND LIGHT RIGHT;;;; -257F;BOX DRAWINGS HEAVY UP AND LIGHT DOWN;So;0;ON;;;;;N;FORMS HEAVY UP AND LIGHT DOWN;;;; -2580;UPPER HALF BLOCK;So;0;ON;;;;;N;;;;; -2581;LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; -2582;LOWER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; -2583;LOWER THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; -2584;LOWER HALF BLOCK;So;0;ON;;;;;N;;;;; -2585;LOWER FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; -2586;LOWER THREE QUARTERS BLOCK;So;0;ON;;;;;N;LOWER THREE QUARTER BLOCK;;;; -2587;LOWER SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; -2588;FULL BLOCK;So;0;ON;;;;;N;;;;; -2589;LEFT SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; -258A;LEFT THREE QUARTERS BLOCK;So;0;ON;;;;;N;LEFT THREE QUARTER BLOCK;;;; -258B;LEFT FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; -258C;LEFT HALF BLOCK;So;0;ON;;;;;N;;;;; -258D;LEFT THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; -258E;LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; -258F;LEFT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; -2590;RIGHT HALF BLOCK;So;0;ON;;;;;N;;;;; -2591;LIGHT SHADE;So;0;ON;;;;;N;;;;; -2592;MEDIUM SHADE;So;0;ON;;;;;N;;;;; -2593;DARK SHADE;So;0;ON;;;;;N;;;;; -2594;UPPER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; -2595;RIGHT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; -2596;QUADRANT LOWER LEFT;So;0;ON;;;;;N;;;;; -2597;QUADRANT LOWER RIGHT;So;0;ON;;;;;N;;;;; -2598;QUADRANT UPPER LEFT;So;0;ON;;;;;N;;;;; -2599;QUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;; -259A;QUADRANT UPPER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;; -259B;QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFT;So;0;ON;;;;;N;;;;; -259C;QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHT;So;0;ON;;;;;N;;;;; -259D;QUADRANT UPPER RIGHT;So;0;ON;;;;;N;;;;; -259E;QUADRANT UPPER RIGHT AND LOWER LEFT;So;0;ON;;;;;N;;;;; -259F;QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;; -25A0;BLACK SQUARE;So;0;ON;;;;;N;;;;; -25A1;WHITE SQUARE;So;0;ON;;;;;N;;;;; -25A2;WHITE SQUARE WITH ROUNDED CORNERS;So;0;ON;;;;;N;;;;; -25A3;WHITE SQUARE CONTAINING BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;; -25A4;SQUARE WITH HORIZONTAL FILL;So;0;ON;;;;;N;;;;; -25A5;SQUARE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;; -25A6;SQUARE WITH ORTHOGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;; -25A7;SQUARE WITH UPPER LEFT TO LOWER RIGHT FILL;So;0;ON;;;;;N;;;;; -25A8;SQUARE WITH UPPER RIGHT TO LOWER LEFT FILL;So;0;ON;;;;;N;;;;; -25A9;SQUARE WITH DIAGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;; -25AA;BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;; -25AB;WHITE SMALL SQUARE;So;0;ON;;;;;N;;;;; -25AC;BLACK RECTANGLE;So;0;ON;;;;;N;;;;; -25AD;WHITE RECTANGLE;So;0;ON;;;;;N;;;;; -25AE;BLACK VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;; -25AF;WHITE VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;; -25B0;BLACK PARALLELOGRAM;So;0;ON;;;;;N;;;;; -25B1;WHITE PARALLELOGRAM;So;0;ON;;;;;N;;;;; -25B2;BLACK UP-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING TRIANGLE;;;; -25B3;WHITE UP-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE;;;; -25B4;BLACK UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING SMALL TRIANGLE;;;; -25B5;WHITE UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING SMALL TRIANGLE;;;; -25B6;BLACK RIGHT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING TRIANGLE;;;; -25B7;WHITE RIGHT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE RIGHT POINTING TRIANGLE;;;; -25B8;BLACK RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING SMALL TRIANGLE;;;; -25B9;WHITE RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE RIGHT POINTING SMALL TRIANGLE;;;; -25BA;BLACK RIGHT-POINTING POINTER;So;0;ON;;;;;N;BLACK RIGHT POINTING POINTER;;;; -25BB;WHITE RIGHT-POINTING POINTER;So;0;ON;;;;;N;WHITE RIGHT POINTING POINTER;;;; -25BC;BLACK DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING TRIANGLE;;;; -25BD;WHITE DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING TRIANGLE;;;; -25BE;BLACK DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING SMALL TRIANGLE;;;; -25BF;WHITE DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING SMALL TRIANGLE;;;; -25C0;BLACK LEFT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING TRIANGLE;;;; -25C1;WHITE LEFT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE LEFT POINTING TRIANGLE;;;; -25C2;BLACK LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING SMALL TRIANGLE;;;; -25C3;WHITE LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE LEFT POINTING SMALL TRIANGLE;;;; -25C4;BLACK LEFT-POINTING POINTER;So;0;ON;;;;;N;BLACK LEFT POINTING POINTER;;;; -25C5;WHITE LEFT-POINTING POINTER;So;0;ON;;;;;N;WHITE LEFT POINTING POINTER;;;; -25C6;BLACK DIAMOND;So;0;ON;;;;;N;;;;; -25C7;WHITE DIAMOND;So;0;ON;;;;;N;;;;; -25C8;WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND;So;0;ON;;;;;N;;;;; -25C9;FISHEYE;So;0;ON;;;;;N;;;;; -25CA;LOZENGE;So;0;ON;;;;;N;;;;; -25CB;WHITE CIRCLE;So;0;ON;;;;;N;;;;; -25CC;DOTTED CIRCLE;So;0;ON;;;;;N;;;;; -25CD;CIRCLE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;; -25CE;BULLSEYE;So;0;ON;;;;;N;;;;; -25CF;BLACK CIRCLE;So;0;ON;;;;;N;;;;; -25D0;CIRCLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;; -25D1;CIRCLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;; -25D2;CIRCLE WITH LOWER HALF BLACK;So;0;ON;;;;;N;;;;; -25D3;CIRCLE WITH UPPER HALF BLACK;So;0;ON;;;;;N;;;;; -25D4;CIRCLE WITH UPPER RIGHT QUADRANT BLACK;So;0;ON;;;;;N;;;;; -25D5;CIRCLE WITH ALL BUT UPPER LEFT QUADRANT BLACK;So;0;ON;;;;;N;;;;; -25D6;LEFT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; -25D7;RIGHT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; -25D8;INVERSE BULLET;So;0;ON;;;;;N;;;;; -25D9;INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;; -25DA;UPPER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;; -25DB;LOWER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;; -25DC;UPPER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; -25DD;UPPER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; -25DE;LOWER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; -25DF;LOWER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; -25E0;UPPER HALF CIRCLE;So;0;ON;;;;;N;;;;; -25E1;LOWER HALF CIRCLE;So;0;ON;;;;;N;;;;; -25E2;BLACK LOWER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; -25E3;BLACK LOWER LEFT TRIANGLE;So;0;ON;;;;;N;;;;; -25E4;BLACK UPPER LEFT TRIANGLE;So;0;ON;;;;;N;;;;; -25E5;BLACK UPPER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; -25E6;WHITE BULLET;So;0;ON;;;;;N;;;;; -25E7;SQUARE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;; -25E8;SQUARE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;; -25E9;SQUARE WITH UPPER LEFT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;; -25EA;SQUARE WITH LOWER RIGHT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;; -25EB;WHITE SQUARE WITH VERTICAL BISECTING LINE;So;0;ON;;;;;N;;;;; -25EC;WHITE UP-POINTING TRIANGLE WITH DOT;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE WITH DOT;;;; -25ED;UP-POINTING TRIANGLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH LEFT HALF BLACK;;;; -25EE;UP-POINTING TRIANGLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH RIGHT HALF BLACK;;;; -25EF;LARGE CIRCLE;So;0;ON;;;;;N;;;;; -25F0;WHITE SQUARE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;; -25F1;WHITE SQUARE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;; -25F2;WHITE SQUARE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; -25F3;WHITE SQUARE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; -25F4;WHITE CIRCLE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;; -25F5;WHITE CIRCLE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;; -25F6;WHITE CIRCLE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; -25F7;WHITE CIRCLE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; -25F8;UPPER LEFT TRIANGLE;Sm;0;ON;;;;;N;;;;; -25F9;UPPER RIGHT TRIANGLE;Sm;0;ON;;;;;N;;;;; -25FA;LOWER LEFT TRIANGLE;Sm;0;ON;;;;;N;;;;; -25FB;WHITE MEDIUM SQUARE;Sm;0;ON;;;;;N;;;;; -25FC;BLACK MEDIUM SQUARE;Sm;0;ON;;;;;N;;;;; -25FD;WHITE MEDIUM SMALL SQUARE;Sm;0;ON;;;;;N;;;;; -25FE;BLACK MEDIUM SMALL SQUARE;Sm;0;ON;;;;;N;;;;; -25FF;LOWER RIGHT TRIANGLE;Sm;0;ON;;;;;N;;;;; -2600;BLACK SUN WITH RAYS;So;0;ON;;;;;N;;;;; -2601;CLOUD;So;0;ON;;;;;N;;;;; -2602;UMBRELLA;So;0;ON;;;;;N;;;;; -2603;SNOWMAN;So;0;ON;;;;;N;;;;; -2604;COMET;So;0;ON;;;;;N;;;;; -2605;BLACK STAR;So;0;ON;;;;;N;;;;; -2606;WHITE STAR;So;0;ON;;;;;N;;;;; -2607;LIGHTNING;So;0;ON;;;;;N;;;;; -2608;THUNDERSTORM;So;0;ON;;;;;N;;;;; -2609;SUN;So;0;ON;;;;;N;;;;; -260A;ASCENDING NODE;So;0;ON;;;;;N;;;;; -260B;DESCENDING NODE;So;0;ON;;;;;N;;;;; -260C;CONJUNCTION;So;0;ON;;;;;N;;;;; -260D;OPPOSITION;So;0;ON;;;;;N;;;;; -260E;BLACK TELEPHONE;So;0;ON;;;;;N;;;;; -260F;WHITE TELEPHONE;So;0;ON;;;;;N;;;;; -2610;BALLOT BOX;So;0;ON;;;;;N;;;;; -2611;BALLOT BOX WITH CHECK;So;0;ON;;;;;N;;;;; -2612;BALLOT BOX WITH X;So;0;ON;;;;;N;;;;; -2613;SALTIRE;So;0;ON;;;;;N;;;;; -2614;UMBRELLA WITH RAIN DROPS;So;0;ON;;;;;N;;;;; -2615;HOT BEVERAGE;So;0;ON;;;;;N;;;;; -2616;WHITE SHOGI PIECE;So;0;ON;;;;;N;;;;; -2617;BLACK SHOGI PIECE;So;0;ON;;;;;N;;;;; -2618;SHAMROCK;So;0;ON;;;;;N;;;;; -2619;REVERSED ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;; -261A;BLACK LEFT POINTING INDEX;So;0;ON;;;;;N;;;;; -261B;BLACK RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; -261C;WHITE LEFT POINTING INDEX;So;0;ON;;;;;N;;;;; -261D;WHITE UP POINTING INDEX;So;0;ON;;;;;N;;;;; -261E;WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; -261F;WHITE DOWN POINTING INDEX;So;0;ON;;;;;N;;;;; -2620;SKULL AND CROSSBONES;So;0;ON;;;;;N;;;;; -2621;CAUTION SIGN;So;0;ON;;;;;N;;;;; -2622;RADIOACTIVE SIGN;So;0;ON;;;;;N;;;;; -2623;BIOHAZARD SIGN;So;0;ON;;;;;N;;;;; -2624;CADUCEUS;So;0;ON;;;;;N;;;;; -2625;ANKH;So;0;ON;;;;;N;;;;; -2626;ORTHODOX CROSS;So;0;ON;;;;;N;;;;; -2627;CHI RHO;So;0;ON;;;;;N;;;;; -2628;CROSS OF LORRAINE;So;0;ON;;;;;N;;;;; -2629;CROSS OF JERUSALEM;So;0;ON;;;;;N;;;;; -262A;STAR AND CRESCENT;So;0;ON;;;;;N;;;;; -262B;FARSI SYMBOL;So;0;ON;;;;;N;SYMBOL OF IRAN;;;; -262C;ADI SHAKTI;So;0;ON;;;;;N;;;;; -262D;HAMMER AND SICKLE;So;0;ON;;;;;N;;;;; -262E;PEACE SYMBOL;So;0;ON;;;;;N;;;;; -262F;YIN YANG;So;0;ON;;;;;N;;;;; -2630;TRIGRAM FOR HEAVEN;So;0;ON;;;;;N;;;;; -2631;TRIGRAM FOR LAKE;So;0;ON;;;;;N;;;;; -2632;TRIGRAM FOR FIRE;So;0;ON;;;;;N;;;;; -2633;TRIGRAM FOR THUNDER;So;0;ON;;;;;N;;;;; -2634;TRIGRAM FOR WIND;So;0;ON;;;;;N;;;;; -2635;TRIGRAM FOR WATER;So;0;ON;;;;;N;;;;; -2636;TRIGRAM FOR MOUNTAIN;So;0;ON;;;;;N;;;;; -2637;TRIGRAM FOR EARTH;So;0;ON;;;;;N;;;;; -2638;WHEEL OF DHARMA;So;0;ON;;;;;N;;;;; -2639;WHITE FROWNING FACE;So;0;ON;;;;;N;;;;; -263A;WHITE SMILING FACE;So;0;ON;;;;;N;;;;; -263B;BLACK SMILING FACE;So;0;ON;;;;;N;;;;; -263C;WHITE SUN WITH RAYS;So;0;ON;;;;;N;;;;; -263D;FIRST QUARTER MOON;So;0;ON;;;;;N;;;;; -263E;LAST QUARTER MOON;So;0;ON;;;;;N;;;;; -263F;MERCURY;So;0;ON;;;;;N;;;;; -2640;FEMALE SIGN;So;0;ON;;;;;N;;;;; -2641;EARTH;So;0;ON;;;;;N;;;;; -2642;MALE SIGN;So;0;ON;;;;;N;;;;; -2643;JUPITER;So;0;ON;;;;;N;;;;; -2644;SATURN;So;0;ON;;;;;N;;;;; -2645;URANUS;So;0;ON;;;;;N;;;;; -2646;NEPTUNE;So;0;ON;;;;;N;;;;; -2647;PLUTO;So;0;ON;;;;;N;;;;; -2648;ARIES;So;0;ON;;;;;N;;;;; -2649;TAURUS;So;0;ON;;;;;N;;;;; -264A;GEMINI;So;0;ON;;;;;N;;;;; -264B;CANCER;So;0;ON;;;;;N;;;;; -264C;LEO;So;0;ON;;;;;N;;;;; -264D;VIRGO;So;0;ON;;;;;N;;;;; -264E;LIBRA;So;0;ON;;;;;N;;;;; -264F;SCORPIUS;So;0;ON;;;;;N;;;;; -2650;SAGITTARIUS;So;0;ON;;;;;N;;;;; -2651;CAPRICORN;So;0;ON;;;;;N;;;;; -2652;AQUARIUS;So;0;ON;;;;;N;;;;; -2653;PISCES;So;0;ON;;;;;N;;;;; -2654;WHITE CHESS KING;So;0;ON;;;;;N;;;;; -2655;WHITE CHESS QUEEN;So;0;ON;;;;;N;;;;; -2656;WHITE CHESS ROOK;So;0;ON;;;;;N;;;;; -2657;WHITE CHESS BISHOP;So;0;ON;;;;;N;;;;; -2658;WHITE CHESS KNIGHT;So;0;ON;;;;;N;;;;; -2659;WHITE CHESS PAWN;So;0;ON;;;;;N;;;;; -265A;BLACK CHESS KING;So;0;ON;;;;;N;;;;; -265B;BLACK CHESS QUEEN;So;0;ON;;;;;N;;;;; -265C;BLACK CHESS ROOK;So;0;ON;;;;;N;;;;; -265D;BLACK CHESS BISHOP;So;0;ON;;;;;N;;;;; -265E;BLACK CHESS KNIGHT;So;0;ON;;;;;N;;;;; -265F;BLACK CHESS PAWN;So;0;ON;;;;;N;;;;; -2660;BLACK SPADE SUIT;So;0;ON;;;;;N;;;;; -2661;WHITE HEART SUIT;So;0;ON;;;;;N;;;;; -2662;WHITE DIAMOND SUIT;So;0;ON;;;;;N;;;;; -2663;BLACK CLUB SUIT;So;0;ON;;;;;N;;;;; -2664;WHITE SPADE SUIT;So;0;ON;;;;;N;;;;; -2665;BLACK HEART SUIT;So;0;ON;;;;;N;;;;; -2666;BLACK DIAMOND SUIT;So;0;ON;;;;;N;;;;; -2667;WHITE CLUB SUIT;So;0;ON;;;;;N;;;;; -2668;HOT SPRINGS;So;0;ON;;;;;N;;;;; -2669;QUARTER NOTE;So;0;ON;;;;;N;;;;; -266A;EIGHTH NOTE;So;0;ON;;;;;N;;;;; -266B;BEAMED EIGHTH NOTES;So;0;ON;;;;;N;BARRED EIGHTH NOTES;;;; -266C;BEAMED SIXTEENTH NOTES;So;0;ON;;;;;N;BARRED SIXTEENTH NOTES;;;; -266D;MUSIC FLAT SIGN;So;0;ON;;;;;N;FLAT;;;; -266E;MUSIC NATURAL SIGN;So;0;ON;;;;;N;NATURAL;;;; -266F;MUSIC SHARP SIGN;Sm;0;ON;;;;;N;SHARP;;;; -2670;WEST SYRIAC CROSS;So;0;ON;;;;;N;;;;; -2671;EAST SYRIAC CROSS;So;0;ON;;;;;N;;;;; -2672;UNIVERSAL RECYCLING SYMBOL;So;0;ON;;;;;N;;;;; -2673;RECYCLING SYMBOL FOR TYPE-1 PLASTICS;So;0;ON;;;;;N;;;;; -2674;RECYCLING SYMBOL FOR TYPE-2 PLASTICS;So;0;ON;;;;;N;;;;; -2675;RECYCLING SYMBOL FOR TYPE-3 PLASTICS;So;0;ON;;;;;N;;;;; -2676;RECYCLING SYMBOL FOR TYPE-4 PLASTICS;So;0;ON;;;;;N;;;;; -2677;RECYCLING SYMBOL FOR TYPE-5 PLASTICS;So;0;ON;;;;;N;;;;; -2678;RECYCLING SYMBOL FOR TYPE-6 PLASTICS;So;0;ON;;;;;N;;;;; -2679;RECYCLING SYMBOL FOR TYPE-7 PLASTICS;So;0;ON;;;;;N;;;;; -267A;RECYCLING SYMBOL FOR GENERIC MATERIALS;So;0;ON;;;;;N;;;;; -267B;BLACK UNIVERSAL RECYCLING SYMBOL;So;0;ON;;;;;N;;;;; -267C;RECYCLED PAPER SYMBOL;So;0;ON;;;;;N;;;;; -267D;PARTIALLY-RECYCLED PAPER SYMBOL;So;0;ON;;;;;N;;;;; -267E;PERMANENT PAPER SIGN;So;0;ON;;;;;N;;;;; -267F;WHEELCHAIR SYMBOL;So;0;ON;;;;;N;;;;; -2680;DIE FACE-1;So;0;ON;;;;;N;;;;; -2681;DIE FACE-2;So;0;ON;;;;;N;;;;; -2682;DIE FACE-3;So;0;ON;;;;;N;;;;; -2683;DIE FACE-4;So;0;ON;;;;;N;;;;; -2684;DIE FACE-5;So;0;ON;;;;;N;;;;; -2685;DIE FACE-6;So;0;ON;;;;;N;;;;; -2686;WHITE CIRCLE WITH DOT RIGHT;So;0;ON;;;;;N;;;;; -2687;WHITE CIRCLE WITH TWO DOTS;So;0;ON;;;;;N;;;;; -2688;BLACK CIRCLE WITH WHITE DOT RIGHT;So;0;ON;;;;;N;;;;; -2689;BLACK CIRCLE WITH TWO WHITE DOTS;So;0;ON;;;;;N;;;;; -268A;MONOGRAM FOR YANG;So;0;ON;;;;;N;;;;; -268B;MONOGRAM FOR YIN;So;0;ON;;;;;N;;;;; -268C;DIGRAM FOR GREATER YANG;So;0;ON;;;;;N;;;;; -268D;DIGRAM FOR LESSER YIN;So;0;ON;;;;;N;;;;; -268E;DIGRAM FOR LESSER YANG;So;0;ON;;;;;N;;;;; -268F;DIGRAM FOR GREATER YIN;So;0;ON;;;;;N;;;;; -2690;WHITE FLAG;So;0;ON;;;;;N;;;;; -2691;BLACK FLAG;So;0;ON;;;;;N;;;;; -2692;HAMMER AND PICK;So;0;ON;;;;;N;;;;; -2693;ANCHOR;So;0;ON;;;;;N;;;;; -2694;CROSSED SWORDS;So;0;ON;;;;;N;;;;; -2695;STAFF OF AESCULAPIUS;So;0;ON;;;;;N;;;;; -2696;SCALES;So;0;ON;;;;;N;;;;; -2697;ALEMBIC;So;0;ON;;;;;N;;;;; -2698;FLOWER;So;0;ON;;;;;N;;;;; -2699;GEAR;So;0;ON;;;;;N;;;;; -269A;STAFF OF HERMES;So;0;ON;;;;;N;;;;; -269B;ATOM SYMBOL;So;0;ON;;;;;N;;;;; -269C;FLEUR-DE-LIS;So;0;ON;;;;;N;;;;; -269D;OUTLINED WHITE STAR;So;0;ON;;;;;N;;;;; -269E;THREE LINES CONVERGING RIGHT;So;0;ON;;;;;N;;;;; -269F;THREE LINES CONVERGING LEFT;So;0;ON;;;;;N;;;;; -26A0;WARNING SIGN;So;0;ON;;;;;N;;;;; -26A1;HIGH VOLTAGE SIGN;So;0;ON;;;;;N;;;;; -26A2;DOUBLED FEMALE SIGN;So;0;ON;;;;;N;;;;; -26A3;DOUBLED MALE SIGN;So;0;ON;;;;;N;;;;; -26A4;INTERLOCKED FEMALE AND MALE SIGN;So;0;ON;;;;;N;;;;; -26A5;MALE AND FEMALE SIGN;So;0;ON;;;;;N;;;;; -26A6;MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;; -26A7;MALE WITH STROKE AND MALE AND FEMALE SIGN;So;0;ON;;;;;N;;;;; -26A8;VERTICAL MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;; -26A9;HORIZONTAL MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;; -26AA;MEDIUM WHITE CIRCLE;So;0;ON;;;;;N;;;;; -26AB;MEDIUM BLACK CIRCLE;So;0;ON;;;;;N;;;;; -26AC;MEDIUM SMALL WHITE CIRCLE;So;0;L;;;;;N;;;;; -26AD;MARRIAGE SYMBOL;So;0;ON;;;;;N;;;;; -26AE;DIVORCE SYMBOL;So;0;ON;;;;;N;;;;; -26AF;UNMARRIED PARTNERSHIP SYMBOL;So;0;ON;;;;;N;;;;; -26B0;COFFIN;So;0;ON;;;;;N;;;;; -26B1;FUNERAL URN;So;0;ON;;;;;N;;;;; -26B2;NEUTER;So;0;ON;;;;;N;;;;; -26B3;CERES;So;0;ON;;;;;N;;;;; -26B4;PALLAS;So;0;ON;;;;;N;;;;; -26B5;JUNO;So;0;ON;;;;;N;;;;; -26B6;VESTA;So;0;ON;;;;;N;;;;; -26B7;CHIRON;So;0;ON;;;;;N;;;;; -26B8;BLACK MOON LILITH;So;0;ON;;;;;N;;;;; -26B9;SEXTILE;So;0;ON;;;;;N;;;;; -26BA;SEMISEXTILE;So;0;ON;;;;;N;;;;; -26BB;QUINCUNX;So;0;ON;;;;;N;;;;; -26BC;SESQUIQUADRATE;So;0;ON;;;;;N;;;;; -26BD;SOCCER BALL;So;0;ON;;;;;N;;;;; -26BE;BASEBALL;So;0;ON;;;;;N;;;;; -26BF;SQUARED KEY;So;0;ON;;;;;N;;;;; -26C0;WHITE DRAUGHTS MAN;So;0;ON;;;;;N;;;;; -26C1;WHITE DRAUGHTS KING;So;0;ON;;;;;N;;;;; -26C2;BLACK DRAUGHTS MAN;So;0;ON;;;;;N;;;;; -26C3;BLACK DRAUGHTS KING;So;0;ON;;;;;N;;;;; -26C4;SNOWMAN WITHOUT SNOW;So;0;ON;;;;;N;;;;; -26C5;SUN BEHIND CLOUD;So;0;ON;;;;;N;;;;; -26C6;RAIN;So;0;ON;;;;;N;;;;; -26C7;BLACK SNOWMAN;So;0;ON;;;;;N;;;;; -26C8;THUNDER CLOUD AND RAIN;So;0;ON;;;;;N;;;;; -26C9;TURNED WHITE SHOGI PIECE;So;0;ON;;;;;N;;;;; -26CA;TURNED BLACK SHOGI PIECE;So;0;ON;;;;;N;;;;; -26CB;WHITE DIAMOND IN SQUARE;So;0;ON;;;;;N;;;;; -26CC;CROSSING LANES;So;0;ON;;;;;N;;;;; -26CD;DISABLED CAR;So;0;ON;;;;;N;;;;; -26CE;OPHIUCHUS;So;0;ON;;;;;N;;;;; -26CF;PICK;So;0;ON;;;;;N;;;;; -26D0;CAR SLIDING;So;0;ON;;;;;N;;;;; -26D1;HELMET WITH WHITE CROSS;So;0;ON;;;;;N;;;;; -26D2;CIRCLED CROSSING LANES;So;0;ON;;;;;N;;;;; -26D3;CHAINS;So;0;ON;;;;;N;;;;; -26D4;NO ENTRY;So;0;ON;;;;;N;;;;; -26D5;ALTERNATE ONE-WAY LEFT WAY TRAFFIC;So;0;ON;;;;;N;;;;; -26D6;BLACK TWO-WAY LEFT WAY TRAFFIC;So;0;ON;;;;;N;;;;; -26D7;WHITE TWO-WAY LEFT WAY TRAFFIC;So;0;ON;;;;;N;;;;; -26D8;BLACK LEFT LANE MERGE;So;0;ON;;;;;N;;;;; -26D9;WHITE LEFT LANE MERGE;So;0;ON;;;;;N;;;;; -26DA;DRIVE SLOW SIGN;So;0;ON;;;;;N;;;;; -26DB;HEAVY WHITE DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;;;;; -26DC;LEFT CLOSED ENTRY;So;0;ON;;;;;N;;;;; -26DD;SQUARED SALTIRE;So;0;ON;;;;;N;;;;; -26DE;FALLING DIAGONAL IN WHITE CIRCLE IN BLACK SQUARE;So;0;ON;;;;;N;;;;; -26DF;BLACK TRUCK;So;0;ON;;;;;N;;;;; -26E0;RESTRICTED LEFT ENTRY-1;So;0;ON;;;;;N;;;;; -26E1;RESTRICTED LEFT ENTRY-2;So;0;ON;;;;;N;;;;; -26E2;ASTRONOMICAL SYMBOL FOR URANUS;So;0;ON;;;;;N;;;;; -26E3;HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE;So;0;ON;;;;;N;;;;; -26E4;PENTAGRAM;So;0;ON;;;;;N;;;;; -26E5;RIGHT-HANDED INTERLACED PENTAGRAM;So;0;ON;;;;;N;;;;; -26E6;LEFT-HANDED INTERLACED PENTAGRAM;So;0;ON;;;;;N;;;;; -26E7;INVERTED PENTAGRAM;So;0;ON;;;;;N;;;;; -26E8;BLACK CROSS ON SHIELD;So;0;ON;;;;;N;;;;; -26E9;SHINTO SHRINE;So;0;ON;;;;;N;;;;; -26EA;CHURCH;So;0;ON;;;;;N;;;;; -26EB;CASTLE;So;0;ON;;;;;N;;;;; -26EC;HISTORIC SITE;So;0;ON;;;;;N;;;;; -26ED;GEAR WITHOUT HUB;So;0;ON;;;;;N;;;;; -26EE;GEAR WITH HANDLES;So;0;ON;;;;;N;;;;; -26EF;MAP SYMBOL FOR LIGHTHOUSE;So;0;ON;;;;;N;;;;; -26F0;MOUNTAIN;So;0;ON;;;;;N;;;;; -26F1;UMBRELLA ON GROUND;So;0;ON;;;;;N;;;;; -26F2;FOUNTAIN;So;0;ON;;;;;N;;;;; -26F3;FLAG IN HOLE;So;0;ON;;;;;N;;;;; -26F4;FERRY;So;0;ON;;;;;N;;;;; -26F5;SAILBOAT;So;0;ON;;;;;N;;;;; -26F6;SQUARE FOUR CORNERS;So;0;ON;;;;;N;;;;; -26F7;SKIER;So;0;ON;;;;;N;;;;; -26F8;ICE SKATE;So;0;ON;;;;;N;;;;; -26F9;PERSON WITH BALL;So;0;ON;;;;;N;;;;; -26FA;TENT;So;0;ON;;;;;N;;;;; -26FB;JAPANESE BANK SYMBOL;So;0;ON;;;;;N;;;;; -26FC;HEADSTONE GRAVEYARD SYMBOL;So;0;ON;;;;;N;;;;; -26FD;FUEL PUMP;So;0;ON;;;;;N;;;;; -26FE;CUP ON BLACK SQUARE;So;0;ON;;;;;N;;;;; -26FF;WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE;So;0;ON;;;;;N;;;;; -2700;BLACK SAFETY SCISSORS;So;0;ON;;;;;N;;;;; -2701;UPPER BLADE SCISSORS;So;0;ON;;;;;N;;;;; -2702;BLACK SCISSORS;So;0;ON;;;;;N;;;;; -2703;LOWER BLADE SCISSORS;So;0;ON;;;;;N;;;;; -2704;WHITE SCISSORS;So;0;ON;;;;;N;;;;; -2705;WHITE HEAVY CHECK MARK;So;0;ON;;;;;N;;;;; -2706;TELEPHONE LOCATION SIGN;So;0;ON;;;;;N;;;;; -2707;TAPE DRIVE;So;0;ON;;;;;N;;;;; -2708;AIRPLANE;So;0;ON;;;;;N;;;;; -2709;ENVELOPE;So;0;ON;;;;;N;;;;; -270A;RAISED FIST;So;0;ON;;;;;N;;;;; -270B;RAISED HAND;So;0;ON;;;;;N;;;;; -270C;VICTORY HAND;So;0;ON;;;;;N;;;;; -270D;WRITING HAND;So;0;ON;;;;;N;;;;; -270E;LOWER RIGHT PENCIL;So;0;ON;;;;;N;;;;; -270F;PENCIL;So;0;ON;;;;;N;;;;; -2710;UPPER RIGHT PENCIL;So;0;ON;;;;;N;;;;; -2711;WHITE NIB;So;0;ON;;;;;N;;;;; -2712;BLACK NIB;So;0;ON;;;;;N;;;;; -2713;CHECK MARK;So;0;ON;;;;;N;;;;; -2714;HEAVY CHECK MARK;So;0;ON;;;;;N;;;;; -2715;MULTIPLICATION X;So;0;ON;;;;;N;;;;; -2716;HEAVY MULTIPLICATION X;So;0;ON;;;;;N;;;;; -2717;BALLOT X;So;0;ON;;;;;N;;;;; -2718;HEAVY BALLOT X;So;0;ON;;;;;N;;;;; -2719;OUTLINED GREEK CROSS;So;0;ON;;;;;N;;;;; -271A;HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;; -271B;OPEN CENTRE CROSS;So;0;ON;;;;;N;OPEN CENTER CROSS;;;; -271C;HEAVY OPEN CENTRE CROSS;So;0;ON;;;;;N;HEAVY OPEN CENTER CROSS;;;; -271D;LATIN CROSS;So;0;ON;;;;;N;;;;; -271E;SHADOWED WHITE LATIN CROSS;So;0;ON;;;;;N;;;;; -271F;OUTLINED LATIN CROSS;So;0;ON;;;;;N;;;;; -2720;MALTESE CROSS;So;0;ON;;;;;N;;;;; -2721;STAR OF DAVID;So;0;ON;;;;;N;;;;; -2722;FOUR TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -2723;FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -2724;HEAVY FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -2725;FOUR CLUB-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -2726;BLACK FOUR POINTED STAR;So;0;ON;;;;;N;;;;; -2727;WHITE FOUR POINTED STAR;So;0;ON;;;;;N;;;;; -2728;SPARKLES;So;0;ON;;;;;N;;;;; -2729;STRESS OUTLINED WHITE STAR;So;0;ON;;;;;N;;;;; -272A;CIRCLED WHITE STAR;So;0;ON;;;;;N;;;;; -272B;OPEN CENTRE BLACK STAR;So;0;ON;;;;;N;OPEN CENTER BLACK STAR;;;; -272C;BLACK CENTRE WHITE STAR;So;0;ON;;;;;N;BLACK CENTER WHITE STAR;;;; -272D;OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;; -272E;HEAVY OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;; -272F;PINWHEEL STAR;So;0;ON;;;;;N;;;;; -2730;SHADOWED WHITE STAR;So;0;ON;;;;;N;;;;; -2731;HEAVY ASTERISK;So;0;ON;;;;;N;;;;; -2732;OPEN CENTRE ASTERISK;So;0;ON;;;;;N;OPEN CENTER ASTERISK;;;; -2733;EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -2734;EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;; -2735;EIGHT POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; -2736;SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;; -2737;EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;; -2738;HEAVY EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;; -2739;TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; -273A;SIXTEEN POINTED ASTERISK;So;0;ON;;;;;N;;;;; -273B;TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -273C;OPEN CENTRE TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;OPEN CENTER TEARDROP-SPOKED ASTERISK;;;; -273D;HEAVY TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -273E;SIX PETALLED BLACK AND WHITE FLORETTE;So;0;ON;;;;;N;;;;; -273F;BLACK FLORETTE;So;0;ON;;;;;N;;;;; -2740;WHITE FLORETTE;So;0;ON;;;;;N;;;;; -2741;EIGHT PETALLED OUTLINED BLACK FLORETTE;So;0;ON;;;;;N;;;;; -2742;CIRCLED OPEN CENTRE EIGHT POINTED STAR;So;0;ON;;;;;N;CIRCLED OPEN CENTER EIGHT POINTED STAR;;;; -2743;HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK;So;0;ON;;;;;N;;;;; -2744;SNOWFLAKE;So;0;ON;;;;;N;;;;; -2745;TIGHT TRIFOLIATE SNOWFLAKE;So;0;ON;;;;;N;;;;; -2746;HEAVY CHEVRON SNOWFLAKE;So;0;ON;;;;;N;;;;; -2747;SPARKLE;So;0;ON;;;;;N;;;;; -2748;HEAVY SPARKLE;So;0;ON;;;;;N;;;;; -2749;BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -274A;EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;; -274B;HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;; -274C;CROSS MARK;So;0;ON;;;;;N;;;;; -274D;SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;; -274E;NEGATIVE SQUARED CROSS MARK;So;0;ON;;;;;N;;;;; -274F;LOWER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; -2750;UPPER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; -2751;LOWER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; -2752;UPPER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; -2753;BLACK QUESTION MARK ORNAMENT;So;0;ON;;;;;N;;;;; -2754;WHITE QUESTION MARK ORNAMENT;So;0;ON;;;;;N;;;;; -2755;WHITE EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; -2756;BLACK DIAMOND MINUS WHITE X;So;0;ON;;;;;N;;;;; -2757;HEAVY EXCLAMATION MARK SYMBOL;So;0;ON;;;;;N;;;;; -2758;LIGHT VERTICAL BAR;So;0;ON;;;;;N;;;;; -2759;MEDIUM VERTICAL BAR;So;0;ON;;;;;N;;;;; -275A;HEAVY VERTICAL BAR;So;0;ON;;;;;N;;;;; -275B;HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; -275C;HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; -275D;HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; -275E;HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; -275F;HEAVY LOW SINGLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; -2760;HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; -2761;CURVED STEM PARAGRAPH SIGN ORNAMENT;So;0;ON;;;;;N;;;;; -2762;HEAVY EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; -2763;HEAVY HEART EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; -2764;HEAVY BLACK HEART;So;0;ON;;;;;N;;;;; -2765;ROTATED HEAVY BLACK HEART BULLET;So;0;ON;;;;;N;;;;; -2766;FLORAL HEART;So;0;ON;;;;;N;;;;; -2767;ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;; -2768;MEDIUM LEFT PARENTHESIS ORNAMENT;Ps;0;ON;;;;;Y;;;;; -2769;MEDIUM RIGHT PARENTHESIS ORNAMENT;Pe;0;ON;;;;;Y;;;;; -276A;MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT;Ps;0;ON;;;;;Y;;;;; -276B;MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT;Pe;0;ON;;;;;Y;;;;; -276C;MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;; -276D;MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;; -276E;HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT;Ps;0;ON;;;;;Y;;;;; -276F;HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT;Pe;0;ON;;;;;Y;;;;; -2770;HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;; -2771;HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;; -2772;LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;; -2773;LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;; -2774;MEDIUM LEFT CURLY BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;; -2775;MEDIUM RIGHT CURLY BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;; -2776;DINGBAT NEGATIVE CIRCLED DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED DIGIT ONE;;;; -2777;DINGBAT NEGATIVE CIRCLED DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED DIGIT TWO;;;; -2778;DINGBAT NEGATIVE CIRCLED DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED DIGIT THREE;;;; -2779;DINGBAT NEGATIVE CIRCLED DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED DIGIT FOUR;;;; -277A;DINGBAT NEGATIVE CIRCLED DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED DIGIT FIVE;;;; -277B;DINGBAT NEGATIVE CIRCLED DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED DIGIT SIX;;;; -277C;DINGBAT NEGATIVE CIRCLED DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED DIGIT SEVEN;;;; -277D;DINGBAT NEGATIVE CIRCLED DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED DIGIT EIGHT;;;; -277E;DINGBAT NEGATIVE CIRCLED DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED DIGIT NINE;;;; -277F;DINGBAT NEGATIVE CIRCLED NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED NUMBER TEN;;;; -2780;DINGBAT CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;CIRCLED SANS-SERIF DIGIT ONE;;;; -2781;DINGBAT CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;CIRCLED SANS-SERIF DIGIT TWO;;;; -2782;DINGBAT CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;CIRCLED SANS-SERIF DIGIT THREE;;;; -2783;DINGBAT CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;CIRCLED SANS-SERIF DIGIT FOUR;;;; -2784;DINGBAT CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;CIRCLED SANS-SERIF DIGIT FIVE;;;; -2785;DINGBAT CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;CIRCLED SANS-SERIF DIGIT SIX;;;; -2786;DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;CIRCLED SANS-SERIF DIGIT SEVEN;;;; -2787;DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;CIRCLED SANS-SERIF DIGIT EIGHT;;;; -2788;DINGBAT CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;CIRCLED SANS-SERIF DIGIT NINE;;;; -2789;DINGBAT CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;CIRCLED SANS-SERIF NUMBER TEN;;;; -278A;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED SANS-SERIF DIGIT ONE;;;; -278B;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED SANS-SERIF DIGIT TWO;;;; -278C;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED SANS-SERIF DIGIT THREE;;;; -278D;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED SANS-SERIF DIGIT FOUR;;;; -278E;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED SANS-SERIF DIGIT FIVE;;;; -278F;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED SANS-SERIF DIGIT SIX;;;; -2790;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED SANS-SERIF DIGIT SEVEN;;;; -2791;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED SANS-SERIF DIGIT EIGHT;;;; -2792;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED SANS-SERIF DIGIT NINE;;;; -2793;DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED SANS-SERIF NUMBER TEN;;;; -2794;HEAVY WIDE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WIDE-HEADED RIGHT ARROW;;;; -2795;HEAVY PLUS SIGN;So;0;ON;;;;;N;;;;; -2796;HEAVY MINUS SIGN;So;0;ON;;;;;N;;;;; -2797;HEAVY DIVISION SIGN;So;0;ON;;;;;N;;;;; -2798;HEAVY SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT ARROW;;;; -2799;HEAVY RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY RIGHT ARROW;;;; -279A;HEAVY NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT ARROW;;;; -279B;DRAFTING POINT RIGHTWARDS ARROW;So;0;ON;;;;;N;DRAFTING POINT RIGHT ARROW;;;; -279C;HEAVY ROUND-TIPPED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY ROUND-TIPPED RIGHT ARROW;;;; -279D;TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;TRIANGLE-HEADED RIGHT ARROW;;;; -279E;HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TRIANGLE-HEADED RIGHT ARROW;;;; -279F;DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;DASHED TRIANGLE-HEADED RIGHT ARROW;;;; -27A0;HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY DASHED TRIANGLE-HEADED RIGHT ARROW;;;; -27A1;BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK RIGHT ARROW;;;; -27A2;THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D TOP-LIGHTED RIGHT ARROWHEAD;;;; -27A3;THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D BOTTOM-LIGHTED RIGHT ARROWHEAD;;;; -27A4;BLACK RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;BLACK RIGHT ARROWHEAD;;;; -27A5;HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED DOWN AND RIGHT ARROW;;;; -27A6;HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED UP AND RIGHT ARROW;;;; -27A7;SQUAT BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;SQUAT BLACK RIGHT ARROW;;;; -27A8;HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY CONCAVE-POINTED BLACK RIGHT ARROW;;;; -27A9;RIGHT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;RIGHT-SHADED WHITE RIGHT ARROW;;;; -27AA;LEFT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT-SHADED WHITE RIGHT ARROW;;;; -27AB;BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;BACK-TILTED SHADOWED WHITE RIGHT ARROW;;;; -27AC;FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;FRONT-TILTED SHADOWED WHITE RIGHT ARROW;;;; -27AD;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; -27AE;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; -27AF;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; -27B0;CURLY LOOP;So;0;ON;;;;;N;;;;; -27B1;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; -27B2;CIRCLED HEAVY WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;CIRCLED HEAVY WHITE RIGHT ARROW;;;; -27B3;WHITE-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;WHITE-FEATHERED RIGHT ARROW;;;; -27B4;BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED LOWER RIGHT ARROW;;;; -27B5;BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK-FEATHERED RIGHT ARROW;;;; -27B6;BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED UPPER RIGHT ARROW;;;; -27B7;HEAVY BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED LOWER RIGHT ARROW;;;; -27B8;HEAVY BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED RIGHT ARROW;;;; -27B9;HEAVY BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED UPPER RIGHT ARROW;;;; -27BA;TEARDROP-BARBED RIGHTWARDS ARROW;So;0;ON;;;;;N;TEARDROP-BARBED RIGHT ARROW;;;; -27BB;HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TEARDROP-SHANKED RIGHT ARROW;;;; -27BC;WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;WEDGE-TAILED RIGHT ARROW;;;; -27BD;HEAVY WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WEDGE-TAILED RIGHT ARROW;;;; -27BE;OPEN-OUTLINED RIGHTWARDS ARROW;So;0;ON;;;;;N;OPEN-OUTLINED RIGHT ARROW;;;; -27BF;DOUBLE CURLY LOOP;So;0;ON;;;;;N;;;;; -27C0;THREE DIMENSIONAL ANGLE;Sm;0;ON;;;;;Y;;;;; -27C1;WHITE TRIANGLE CONTAINING SMALL WHITE TRIANGLE;Sm;0;ON;;;;;N;;;;; -27C2;PERPENDICULAR;Sm;0;ON;;;;;N;;;;; -27C3;OPEN SUBSET;Sm;0;ON;;;;;Y;;;;; -27C4;OPEN SUPERSET;Sm;0;ON;;;;;Y;;;;; -27C5;LEFT S-SHAPED BAG DELIMITER;Ps;0;ON;;;;;Y;;;;; -27C6;RIGHT S-SHAPED BAG DELIMITER;Pe;0;ON;;;;;Y;;;;; -27C7;OR WITH DOT INSIDE;Sm;0;ON;;;;;N;;;;; -27C8;REVERSE SOLIDUS PRECEDING SUBSET;Sm;0;ON;;;;;Y;;;;; -27C9;SUPERSET PRECEDING SOLIDUS;Sm;0;ON;;;;;Y;;;;; -27CA;VERTICAL BAR WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; -27CB;MATHEMATICAL RISING DIAGONAL;Sm;0;ON;;;;;Y;;;;; -27CC;LONG DIVISION;Sm;0;ON;;;;;Y;;;;; -27CD;MATHEMATICAL FALLING DIAGONAL;Sm;0;ON;;;;;Y;;;;; -27CE;SQUARED LOGICAL AND;Sm;0;ON;;;;;N;;;;; -27CF;SQUARED LOGICAL OR;Sm;0;ON;;;;;N;;;;; -27D0;WHITE DIAMOND WITH CENTRED DOT;Sm;0;ON;;;;;N;;;;; -27D1;AND WITH DOT;Sm;0;ON;;;;;N;;;;; -27D2;ELEMENT OF OPENING UPWARDS;Sm;0;ON;;;;;N;;;;; -27D3;LOWER RIGHT CORNER WITH DOT;Sm;0;ON;;;;;Y;;;;; -27D4;UPPER LEFT CORNER WITH DOT;Sm;0;ON;;;;;Y;;;;; -27D5;LEFT OUTER JOIN;Sm;0;ON;;;;;Y;;;;; -27D6;RIGHT OUTER JOIN;Sm;0;ON;;;;;Y;;;;; -27D7;FULL OUTER JOIN;Sm;0;ON;;;;;N;;;;; -27D8;LARGE UP TACK;Sm;0;ON;;;;;N;;;;; -27D9;LARGE DOWN TACK;Sm;0;ON;;;;;N;;;;; -27DA;LEFT AND RIGHT DOUBLE TURNSTILE;Sm;0;ON;;;;;N;;;;; -27DB;LEFT AND RIGHT TACK;Sm;0;ON;;;;;N;;;;; -27DC;LEFT MULTIMAP;Sm;0;ON;;;;;Y;;;;; -27DD;LONG RIGHT TACK;Sm;0;ON;;;;;Y;;;;; -27DE;LONG LEFT TACK;Sm;0;ON;;;;;Y;;;;; -27DF;UP TACK WITH CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;; -27E0;LOZENGE DIVIDED BY HORIZONTAL RULE;Sm;0;ON;;;;;N;;;;; -27E1;WHITE CONCAVE-SIDED DIAMOND;Sm;0;ON;;;;;N;;;;; -27E2;WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK;Sm;0;ON;;;;;Y;;;;; -27E3;WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK;Sm;0;ON;;;;;Y;;;;; -27E4;WHITE SQUARE WITH LEFTWARDS TICK;Sm;0;ON;;;;;Y;;;;; -27E5;WHITE SQUARE WITH RIGHTWARDS TICK;Sm;0;ON;;;;;Y;;;;; -27E6;MATHEMATICAL LEFT WHITE SQUARE BRACKET;Ps;0;ON;;;;;Y;;;;; -27E7;MATHEMATICAL RIGHT WHITE SQUARE BRACKET;Pe;0;ON;;;;;Y;;;;; -27E8;MATHEMATICAL LEFT ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;; -27E9;MATHEMATICAL RIGHT ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;; -27EA;MATHEMATICAL LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;; -27EB;MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;; -27EC;MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;;;;; -27ED;MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;;;;; -27EE;MATHEMATICAL LEFT FLATTENED PARENTHESIS;Ps;0;ON;;;;;Y;;;;; -27EF;MATHEMATICAL RIGHT FLATTENED PARENTHESIS;Pe;0;ON;;;;;Y;;;;; -27F0;UPWARDS QUADRUPLE ARROW;Sm;0;ON;;;;;N;;;;; -27F1;DOWNWARDS QUADRUPLE ARROW;Sm;0;ON;;;;;N;;;;; -27F2;ANTICLOCKWISE GAPPED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;; -27F3;CLOCKWISE GAPPED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;; -27F4;RIGHT ARROW WITH CIRCLED PLUS;Sm;0;ON;;;;;N;;;;; -27F5;LONG LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; -27F6;LONG RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; -27F7;LONG LEFT RIGHT ARROW;Sm;0;ON;;;;;N;;;;; -27F8;LONG LEFTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;;;;; -27F9;LONG RIGHTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;;;;; -27FA;LONG LEFT RIGHT DOUBLE ARROW;Sm;0;ON;;;;;N;;;;; -27FB;LONG LEFTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; -27FC;LONG RIGHTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; -27FD;LONG LEFTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; -27FE;LONG RIGHTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; -27FF;LONG RIGHTWARDS SQUIGGLE ARROW;Sm;0;ON;;;;;N;;;;; -2800;BRAILLE PATTERN BLANK;So;0;L;;;;;N;;;;; -2801;BRAILLE PATTERN DOTS-1;So;0;L;;;;;N;;;;; -2802;BRAILLE PATTERN DOTS-2;So;0;L;;;;;N;;;;; -2803;BRAILLE PATTERN DOTS-12;So;0;L;;;;;N;;;;; -2804;BRAILLE PATTERN DOTS-3;So;0;L;;;;;N;;;;; -2805;BRAILLE PATTERN DOTS-13;So;0;L;;;;;N;;;;; -2806;BRAILLE PATTERN DOTS-23;So;0;L;;;;;N;;;;; -2807;BRAILLE PATTERN DOTS-123;So;0;L;;;;;N;;;;; -2808;BRAILLE PATTERN DOTS-4;So;0;L;;;;;N;;;;; -2809;BRAILLE PATTERN DOTS-14;So;0;L;;;;;N;;;;; -280A;BRAILLE PATTERN DOTS-24;So;0;L;;;;;N;;;;; -280B;BRAILLE PATTERN DOTS-124;So;0;L;;;;;N;;;;; -280C;BRAILLE PATTERN DOTS-34;So;0;L;;;;;N;;;;; -280D;BRAILLE PATTERN DOTS-134;So;0;L;;;;;N;;;;; -280E;BRAILLE PATTERN DOTS-234;So;0;L;;;;;N;;;;; -280F;BRAILLE PATTERN DOTS-1234;So;0;L;;;;;N;;;;; -2810;BRAILLE PATTERN DOTS-5;So;0;L;;;;;N;;;;; -2811;BRAILLE PATTERN DOTS-15;So;0;L;;;;;N;;;;; -2812;BRAILLE PATTERN DOTS-25;So;0;L;;;;;N;;;;; -2813;BRAILLE PATTERN DOTS-125;So;0;L;;;;;N;;;;; -2814;BRAILLE PATTERN DOTS-35;So;0;L;;;;;N;;;;; -2815;BRAILLE PATTERN DOTS-135;So;0;L;;;;;N;;;;; -2816;BRAILLE PATTERN DOTS-235;So;0;L;;;;;N;;;;; -2817;BRAILLE PATTERN DOTS-1235;So;0;L;;;;;N;;;;; -2818;BRAILLE PATTERN DOTS-45;So;0;L;;;;;N;;;;; -2819;BRAILLE PATTERN DOTS-145;So;0;L;;;;;N;;;;; -281A;BRAILLE PATTERN DOTS-245;So;0;L;;;;;N;;;;; -281B;BRAILLE PATTERN DOTS-1245;So;0;L;;;;;N;;;;; -281C;BRAILLE PATTERN DOTS-345;So;0;L;;;;;N;;;;; -281D;BRAILLE PATTERN DOTS-1345;So;0;L;;;;;N;;;;; -281E;BRAILLE PATTERN DOTS-2345;So;0;L;;;;;N;;;;; -281F;BRAILLE PATTERN DOTS-12345;So;0;L;;;;;N;;;;; -2820;BRAILLE PATTERN DOTS-6;So;0;L;;;;;N;;;;; -2821;BRAILLE PATTERN DOTS-16;So;0;L;;;;;N;;;;; -2822;BRAILLE PATTERN DOTS-26;So;0;L;;;;;N;;;;; -2823;BRAILLE PATTERN DOTS-126;So;0;L;;;;;N;;;;; -2824;BRAILLE PATTERN DOTS-36;So;0;L;;;;;N;;;;; -2825;BRAILLE PATTERN DOTS-136;So;0;L;;;;;N;;;;; -2826;BRAILLE PATTERN DOTS-236;So;0;L;;;;;N;;;;; -2827;BRAILLE PATTERN DOTS-1236;So;0;L;;;;;N;;;;; -2828;BRAILLE PATTERN DOTS-46;So;0;L;;;;;N;;;;; -2829;BRAILLE PATTERN DOTS-146;So;0;L;;;;;N;;;;; -282A;BRAILLE PATTERN DOTS-246;So;0;L;;;;;N;;;;; -282B;BRAILLE PATTERN DOTS-1246;So;0;L;;;;;N;;;;; -282C;BRAILLE PATTERN DOTS-346;So;0;L;;;;;N;;;;; -282D;BRAILLE PATTERN DOTS-1346;So;0;L;;;;;N;;;;; -282E;BRAILLE PATTERN DOTS-2346;So;0;L;;;;;N;;;;; -282F;BRAILLE PATTERN DOTS-12346;So;0;L;;;;;N;;;;; -2830;BRAILLE PATTERN DOTS-56;So;0;L;;;;;N;;;;; -2831;BRAILLE PATTERN DOTS-156;So;0;L;;;;;N;;;;; -2832;BRAILLE PATTERN DOTS-256;So;0;L;;;;;N;;;;; -2833;BRAILLE PATTERN DOTS-1256;So;0;L;;;;;N;;;;; -2834;BRAILLE PATTERN DOTS-356;So;0;L;;;;;N;;;;; -2835;BRAILLE PATTERN DOTS-1356;So;0;L;;;;;N;;;;; -2836;BRAILLE PATTERN DOTS-2356;So;0;L;;;;;N;;;;; -2837;BRAILLE PATTERN DOTS-12356;So;0;L;;;;;N;;;;; -2838;BRAILLE PATTERN DOTS-456;So;0;L;;;;;N;;;;; -2839;BRAILLE PATTERN DOTS-1456;So;0;L;;;;;N;;;;; -283A;BRAILLE PATTERN DOTS-2456;So;0;L;;;;;N;;;;; -283B;BRAILLE PATTERN DOTS-12456;So;0;L;;;;;N;;;;; -283C;BRAILLE PATTERN DOTS-3456;So;0;L;;;;;N;;;;; -283D;BRAILLE PATTERN DOTS-13456;So;0;L;;;;;N;;;;; -283E;BRAILLE PATTERN DOTS-23456;So;0;L;;;;;N;;;;; -283F;BRAILLE PATTERN DOTS-123456;So;0;L;;;;;N;;;;; -2840;BRAILLE PATTERN DOTS-7;So;0;L;;;;;N;;;;; -2841;BRAILLE PATTERN DOTS-17;So;0;L;;;;;N;;;;; -2842;BRAILLE PATTERN DOTS-27;So;0;L;;;;;N;;;;; -2843;BRAILLE PATTERN DOTS-127;So;0;L;;;;;N;;;;; -2844;BRAILLE PATTERN DOTS-37;So;0;L;;;;;N;;;;; -2845;BRAILLE PATTERN DOTS-137;So;0;L;;;;;N;;;;; -2846;BRAILLE PATTERN DOTS-237;So;0;L;;;;;N;;;;; -2847;BRAILLE PATTERN DOTS-1237;So;0;L;;;;;N;;;;; -2848;BRAILLE PATTERN DOTS-47;So;0;L;;;;;N;;;;; -2849;BRAILLE PATTERN DOTS-147;So;0;L;;;;;N;;;;; -284A;BRAILLE PATTERN DOTS-247;So;0;L;;;;;N;;;;; -284B;BRAILLE PATTERN DOTS-1247;So;0;L;;;;;N;;;;; -284C;BRAILLE PATTERN DOTS-347;So;0;L;;;;;N;;;;; -284D;BRAILLE PATTERN DOTS-1347;So;0;L;;;;;N;;;;; -284E;BRAILLE PATTERN DOTS-2347;So;0;L;;;;;N;;;;; -284F;BRAILLE PATTERN DOTS-12347;So;0;L;;;;;N;;;;; -2850;BRAILLE PATTERN DOTS-57;So;0;L;;;;;N;;;;; -2851;BRAILLE PATTERN DOTS-157;So;0;L;;;;;N;;;;; -2852;BRAILLE PATTERN DOTS-257;So;0;L;;;;;N;;;;; -2853;BRAILLE PATTERN DOTS-1257;So;0;L;;;;;N;;;;; -2854;BRAILLE PATTERN DOTS-357;So;0;L;;;;;N;;;;; -2855;BRAILLE PATTERN DOTS-1357;So;0;L;;;;;N;;;;; -2856;BRAILLE PATTERN DOTS-2357;So;0;L;;;;;N;;;;; -2857;BRAILLE PATTERN DOTS-12357;So;0;L;;;;;N;;;;; -2858;BRAILLE PATTERN DOTS-457;So;0;L;;;;;N;;;;; -2859;BRAILLE PATTERN DOTS-1457;So;0;L;;;;;N;;;;; -285A;BRAILLE PATTERN DOTS-2457;So;0;L;;;;;N;;;;; -285B;BRAILLE PATTERN DOTS-12457;So;0;L;;;;;N;;;;; -285C;BRAILLE PATTERN DOTS-3457;So;0;L;;;;;N;;;;; -285D;BRAILLE PATTERN DOTS-13457;So;0;L;;;;;N;;;;; -285E;BRAILLE PATTERN DOTS-23457;So;0;L;;;;;N;;;;; -285F;BRAILLE PATTERN DOTS-123457;So;0;L;;;;;N;;;;; -2860;BRAILLE PATTERN DOTS-67;So;0;L;;;;;N;;;;; -2861;BRAILLE PATTERN DOTS-167;So;0;L;;;;;N;;;;; -2862;BRAILLE PATTERN DOTS-267;So;0;L;;;;;N;;;;; -2863;BRAILLE PATTERN DOTS-1267;So;0;L;;;;;N;;;;; -2864;BRAILLE PATTERN DOTS-367;So;0;L;;;;;N;;;;; -2865;BRAILLE PATTERN DOTS-1367;So;0;L;;;;;N;;;;; -2866;BRAILLE PATTERN DOTS-2367;So;0;L;;;;;N;;;;; -2867;BRAILLE PATTERN DOTS-12367;So;0;L;;;;;N;;;;; -2868;BRAILLE PATTERN DOTS-467;So;0;L;;;;;N;;;;; -2869;BRAILLE PATTERN DOTS-1467;So;0;L;;;;;N;;;;; -286A;BRAILLE PATTERN DOTS-2467;So;0;L;;;;;N;;;;; -286B;BRAILLE PATTERN DOTS-12467;So;0;L;;;;;N;;;;; -286C;BRAILLE PATTERN DOTS-3467;So;0;L;;;;;N;;;;; -286D;BRAILLE PATTERN DOTS-13467;So;0;L;;;;;N;;;;; -286E;BRAILLE PATTERN DOTS-23467;So;0;L;;;;;N;;;;; -286F;BRAILLE PATTERN DOTS-123467;So;0;L;;;;;N;;;;; -2870;BRAILLE PATTERN DOTS-567;So;0;L;;;;;N;;;;; -2871;BRAILLE PATTERN DOTS-1567;So;0;L;;;;;N;;;;; -2872;BRAILLE PATTERN DOTS-2567;So;0;L;;;;;N;;;;; -2873;BRAILLE PATTERN DOTS-12567;So;0;L;;;;;N;;;;; -2874;BRAILLE PATTERN DOTS-3567;So;0;L;;;;;N;;;;; -2875;BRAILLE PATTERN DOTS-13567;So;0;L;;;;;N;;;;; -2876;BRAILLE PATTERN DOTS-23567;So;0;L;;;;;N;;;;; -2877;BRAILLE PATTERN DOTS-123567;So;0;L;;;;;N;;;;; -2878;BRAILLE PATTERN DOTS-4567;So;0;L;;;;;N;;;;; -2879;BRAILLE PATTERN DOTS-14567;So;0;L;;;;;N;;;;; -287A;BRAILLE PATTERN DOTS-24567;So;0;L;;;;;N;;;;; -287B;BRAILLE PATTERN DOTS-124567;So;0;L;;;;;N;;;;; -287C;BRAILLE PATTERN DOTS-34567;So;0;L;;;;;N;;;;; -287D;BRAILLE PATTERN DOTS-134567;So;0;L;;;;;N;;;;; -287E;BRAILLE PATTERN DOTS-234567;So;0;L;;;;;N;;;;; -287F;BRAILLE PATTERN DOTS-1234567;So;0;L;;;;;N;;;;; -2880;BRAILLE PATTERN DOTS-8;So;0;L;;;;;N;;;;; -2881;BRAILLE PATTERN DOTS-18;So;0;L;;;;;N;;;;; -2882;BRAILLE PATTERN DOTS-28;So;0;L;;;;;N;;;;; -2883;BRAILLE PATTERN DOTS-128;So;0;L;;;;;N;;;;; -2884;BRAILLE PATTERN DOTS-38;So;0;L;;;;;N;;;;; -2885;BRAILLE PATTERN DOTS-138;So;0;L;;;;;N;;;;; -2886;BRAILLE PATTERN DOTS-238;So;0;L;;;;;N;;;;; -2887;BRAILLE PATTERN DOTS-1238;So;0;L;;;;;N;;;;; -2888;BRAILLE PATTERN DOTS-48;So;0;L;;;;;N;;;;; -2889;BRAILLE PATTERN DOTS-148;So;0;L;;;;;N;;;;; -288A;BRAILLE PATTERN DOTS-248;So;0;L;;;;;N;;;;; -288B;BRAILLE PATTERN DOTS-1248;So;0;L;;;;;N;;;;; -288C;BRAILLE PATTERN DOTS-348;So;0;L;;;;;N;;;;; -288D;BRAILLE PATTERN DOTS-1348;So;0;L;;;;;N;;;;; -288E;BRAILLE PATTERN DOTS-2348;So;0;L;;;;;N;;;;; -288F;BRAILLE PATTERN DOTS-12348;So;0;L;;;;;N;;;;; -2890;BRAILLE PATTERN DOTS-58;So;0;L;;;;;N;;;;; -2891;BRAILLE PATTERN DOTS-158;So;0;L;;;;;N;;;;; -2892;BRAILLE PATTERN DOTS-258;So;0;L;;;;;N;;;;; -2893;BRAILLE PATTERN DOTS-1258;So;0;L;;;;;N;;;;; -2894;BRAILLE PATTERN DOTS-358;So;0;L;;;;;N;;;;; -2895;BRAILLE PATTERN DOTS-1358;So;0;L;;;;;N;;;;; -2896;BRAILLE PATTERN DOTS-2358;So;0;L;;;;;N;;;;; -2897;BRAILLE PATTERN DOTS-12358;So;0;L;;;;;N;;;;; -2898;BRAILLE PATTERN DOTS-458;So;0;L;;;;;N;;;;; -2899;BRAILLE PATTERN DOTS-1458;So;0;L;;;;;N;;;;; -289A;BRAILLE PATTERN DOTS-2458;So;0;L;;;;;N;;;;; -289B;BRAILLE PATTERN DOTS-12458;So;0;L;;;;;N;;;;; -289C;BRAILLE PATTERN DOTS-3458;So;0;L;;;;;N;;;;; -289D;BRAILLE PATTERN DOTS-13458;So;0;L;;;;;N;;;;; -289E;BRAILLE PATTERN DOTS-23458;So;0;L;;;;;N;;;;; -289F;BRAILLE PATTERN DOTS-123458;So;0;L;;;;;N;;;;; -28A0;BRAILLE PATTERN DOTS-68;So;0;L;;;;;N;;;;; -28A1;BRAILLE PATTERN DOTS-168;So;0;L;;;;;N;;;;; -28A2;BRAILLE PATTERN DOTS-268;So;0;L;;;;;N;;;;; -28A3;BRAILLE PATTERN DOTS-1268;So;0;L;;;;;N;;;;; -28A4;BRAILLE PATTERN DOTS-368;So;0;L;;;;;N;;;;; -28A5;BRAILLE PATTERN DOTS-1368;So;0;L;;;;;N;;;;; -28A6;BRAILLE PATTERN DOTS-2368;So;0;L;;;;;N;;;;; -28A7;BRAILLE PATTERN DOTS-12368;So;0;L;;;;;N;;;;; -28A8;BRAILLE PATTERN DOTS-468;So;0;L;;;;;N;;;;; -28A9;BRAILLE PATTERN DOTS-1468;So;0;L;;;;;N;;;;; -28AA;BRAILLE PATTERN DOTS-2468;So;0;L;;;;;N;;;;; -28AB;BRAILLE PATTERN DOTS-12468;So;0;L;;;;;N;;;;; -28AC;BRAILLE PATTERN DOTS-3468;So;0;L;;;;;N;;;;; -28AD;BRAILLE PATTERN DOTS-13468;So;0;L;;;;;N;;;;; -28AE;BRAILLE PATTERN DOTS-23468;So;0;L;;;;;N;;;;; -28AF;BRAILLE PATTERN DOTS-123468;So;0;L;;;;;N;;;;; -28B0;BRAILLE PATTERN DOTS-568;So;0;L;;;;;N;;;;; -28B1;BRAILLE PATTERN DOTS-1568;So;0;L;;;;;N;;;;; -28B2;BRAILLE PATTERN DOTS-2568;So;0;L;;;;;N;;;;; -28B3;BRAILLE PATTERN DOTS-12568;So;0;L;;;;;N;;;;; -28B4;BRAILLE PATTERN DOTS-3568;So;0;L;;;;;N;;;;; -28B5;BRAILLE PATTERN DOTS-13568;So;0;L;;;;;N;;;;; -28B6;BRAILLE PATTERN DOTS-23568;So;0;L;;;;;N;;;;; -28B7;BRAILLE PATTERN DOTS-123568;So;0;L;;;;;N;;;;; -28B8;BRAILLE PATTERN DOTS-4568;So;0;L;;;;;N;;;;; -28B9;BRAILLE PATTERN DOTS-14568;So;0;L;;;;;N;;;;; -28BA;BRAILLE PATTERN DOTS-24568;So;0;L;;;;;N;;;;; -28BB;BRAILLE PATTERN DOTS-124568;So;0;L;;;;;N;;;;; -28BC;BRAILLE PATTERN DOTS-34568;So;0;L;;;;;N;;;;; -28BD;BRAILLE PATTERN DOTS-134568;So;0;L;;;;;N;;;;; -28BE;BRAILLE PATTERN DOTS-234568;So;0;L;;;;;N;;;;; -28BF;BRAILLE PATTERN DOTS-1234568;So;0;L;;;;;N;;;;; -28C0;BRAILLE PATTERN DOTS-78;So;0;L;;;;;N;;;;; -28C1;BRAILLE PATTERN DOTS-178;So;0;L;;;;;N;;;;; -28C2;BRAILLE PATTERN DOTS-278;So;0;L;;;;;N;;;;; -28C3;BRAILLE PATTERN DOTS-1278;So;0;L;;;;;N;;;;; -28C4;BRAILLE PATTERN DOTS-378;So;0;L;;;;;N;;;;; -28C5;BRAILLE PATTERN DOTS-1378;So;0;L;;;;;N;;;;; -28C6;BRAILLE PATTERN DOTS-2378;So;0;L;;;;;N;;;;; -28C7;BRAILLE PATTERN DOTS-12378;So;0;L;;;;;N;;;;; -28C8;BRAILLE PATTERN DOTS-478;So;0;L;;;;;N;;;;; -28C9;BRAILLE PATTERN DOTS-1478;So;0;L;;;;;N;;;;; -28CA;BRAILLE PATTERN DOTS-2478;So;0;L;;;;;N;;;;; -28CB;BRAILLE PATTERN DOTS-12478;So;0;L;;;;;N;;;;; -28CC;BRAILLE PATTERN DOTS-3478;So;0;L;;;;;N;;;;; -28CD;BRAILLE PATTERN DOTS-13478;So;0;L;;;;;N;;;;; -28CE;BRAILLE PATTERN DOTS-23478;So;0;L;;;;;N;;;;; -28CF;BRAILLE PATTERN DOTS-123478;So;0;L;;;;;N;;;;; -28D0;BRAILLE PATTERN DOTS-578;So;0;L;;;;;N;;;;; -28D1;BRAILLE PATTERN DOTS-1578;So;0;L;;;;;N;;;;; -28D2;BRAILLE PATTERN DOTS-2578;So;0;L;;;;;N;;;;; -28D3;BRAILLE PATTERN DOTS-12578;So;0;L;;;;;N;;;;; -28D4;BRAILLE PATTERN DOTS-3578;So;0;L;;;;;N;;;;; -28D5;BRAILLE PATTERN DOTS-13578;So;0;L;;;;;N;;;;; -28D6;BRAILLE PATTERN DOTS-23578;So;0;L;;;;;N;;;;; -28D7;BRAILLE PATTERN DOTS-123578;So;0;L;;;;;N;;;;; -28D8;BRAILLE PATTERN DOTS-4578;So;0;L;;;;;N;;;;; -28D9;BRAILLE PATTERN DOTS-14578;So;0;L;;;;;N;;;;; -28DA;BRAILLE PATTERN DOTS-24578;So;0;L;;;;;N;;;;; -28DB;BRAILLE PATTERN DOTS-124578;So;0;L;;;;;N;;;;; -28DC;BRAILLE PATTERN DOTS-34578;So;0;L;;;;;N;;;;; -28DD;BRAILLE PATTERN DOTS-134578;So;0;L;;;;;N;;;;; -28DE;BRAILLE PATTERN DOTS-234578;So;0;L;;;;;N;;;;; -28DF;BRAILLE PATTERN DOTS-1234578;So;0;L;;;;;N;;;;; -28E0;BRAILLE PATTERN DOTS-678;So;0;L;;;;;N;;;;; -28E1;BRAILLE PATTERN DOTS-1678;So;0;L;;;;;N;;;;; -28E2;BRAILLE PATTERN DOTS-2678;So;0;L;;;;;N;;;;; -28E3;BRAILLE PATTERN DOTS-12678;So;0;L;;;;;N;;;;; -28E4;BRAILLE PATTERN DOTS-3678;So;0;L;;;;;N;;;;; -28E5;BRAILLE PATTERN DOTS-13678;So;0;L;;;;;N;;;;; -28E6;BRAILLE PATTERN DOTS-23678;So;0;L;;;;;N;;;;; -28E7;BRAILLE PATTERN DOTS-123678;So;0;L;;;;;N;;;;; -28E8;BRAILLE PATTERN DOTS-4678;So;0;L;;;;;N;;;;; -28E9;BRAILLE PATTERN DOTS-14678;So;0;L;;;;;N;;;;; -28EA;BRAILLE PATTERN DOTS-24678;So;0;L;;;;;N;;;;; -28EB;BRAILLE PATTERN DOTS-124678;So;0;L;;;;;N;;;;; -28EC;BRAILLE PATTERN DOTS-34678;So;0;L;;;;;N;;;;; -28ED;BRAILLE PATTERN DOTS-134678;So;0;L;;;;;N;;;;; -28EE;BRAILLE PATTERN DOTS-234678;So;0;L;;;;;N;;;;; -28EF;BRAILLE PATTERN DOTS-1234678;So;0;L;;;;;N;;;;; -28F0;BRAILLE PATTERN DOTS-5678;So;0;L;;;;;N;;;;; -28F1;BRAILLE PATTERN DOTS-15678;So;0;L;;;;;N;;;;; -28F2;BRAILLE PATTERN DOTS-25678;So;0;L;;;;;N;;;;; -28F3;BRAILLE PATTERN DOTS-125678;So;0;L;;;;;N;;;;; -28F4;BRAILLE PATTERN DOTS-35678;So;0;L;;;;;N;;;;; -28F5;BRAILLE PATTERN DOTS-135678;So;0;L;;;;;N;;;;; -28F6;BRAILLE PATTERN DOTS-235678;So;0;L;;;;;N;;;;; -28F7;BRAILLE PATTERN DOTS-1235678;So;0;L;;;;;N;;;;; -28F8;BRAILLE PATTERN DOTS-45678;So;0;L;;;;;N;;;;; -28F9;BRAILLE PATTERN DOTS-145678;So;0;L;;;;;N;;;;; -28FA;BRAILLE PATTERN DOTS-245678;So;0;L;;;;;N;;;;; -28FB;BRAILLE PATTERN DOTS-1245678;So;0;L;;;;;N;;;;; -28FC;BRAILLE PATTERN DOTS-345678;So;0;L;;;;;N;;;;; -28FD;BRAILLE PATTERN DOTS-1345678;So;0;L;;;;;N;;;;; -28FE;BRAILLE PATTERN DOTS-2345678;So;0;L;;;;;N;;;;; -28FF;BRAILLE PATTERN DOTS-12345678;So;0;L;;;;;N;;;;; -2900;RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -2901;RIGHTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -2902;LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -2903;RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -2904;LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -2905;RIGHTWARDS TWO-HEADED ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; -2906;LEFTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; -2907;RIGHTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; -2908;DOWNWARDS ARROW WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; -2909;UPWARDS ARROW WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; -290A;UPWARDS TRIPLE ARROW;Sm;0;ON;;;;;N;;;;; -290B;DOWNWARDS TRIPLE ARROW;Sm;0;ON;;;;;N;;;;; -290C;LEFTWARDS DOUBLE DASH ARROW;Sm;0;ON;;;;;N;;;;; -290D;RIGHTWARDS DOUBLE DASH ARROW;Sm;0;ON;;;;;N;;;;; -290E;LEFTWARDS TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;; -290F;RIGHTWARDS TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;; -2910;RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;; -2911;RIGHTWARDS ARROW WITH DOTTED STEM;Sm;0;ON;;;;;N;;;;; -2912;UPWARDS ARROW TO BAR;Sm;0;ON;;;;;N;;;;; -2913;DOWNWARDS ARROW TO BAR;Sm;0;ON;;;;;N;;;;; -2914;RIGHTWARDS ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -2915;RIGHTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -2916;RIGHTWARDS TWO-HEADED ARROW WITH TAIL;Sm;0;ON;;;;;N;;;;; -2917;RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -2918;RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -2919;LEFTWARDS ARROW-TAIL;Sm;0;ON;;;;;N;;;;; -291A;RIGHTWARDS ARROW-TAIL;Sm;0;ON;;;;;N;;;;; -291B;LEFTWARDS DOUBLE ARROW-TAIL;Sm;0;ON;;;;;N;;;;; -291C;RIGHTWARDS DOUBLE ARROW-TAIL;Sm;0;ON;;;;;N;;;;; -291D;LEFTWARDS ARROW TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; -291E;RIGHTWARDS ARROW TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; -291F;LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; -2920;RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; -2921;NORTH WEST AND SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;; -2922;NORTH EAST AND SOUTH WEST ARROW;Sm;0;ON;;;;;N;;;;; -2923;NORTH WEST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;; -2924;NORTH EAST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;; -2925;SOUTH EAST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;; -2926;SOUTH WEST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;; -2927;NORTH WEST ARROW AND NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;; -2928;NORTH EAST ARROW AND SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;; -2929;SOUTH EAST ARROW AND SOUTH WEST ARROW;Sm;0;ON;;;;;N;;;;; -292A;SOUTH WEST ARROW AND NORTH WEST ARROW;Sm;0;ON;;;;;N;;;;; -292B;RISING DIAGONAL CROSSING FALLING DIAGONAL;Sm;0;ON;;;;;N;;;;; -292C;FALLING DIAGONAL CROSSING RISING DIAGONAL;Sm;0;ON;;;;;N;;;;; -292D;SOUTH EAST ARROW CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;; -292E;NORTH EAST ARROW CROSSING SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;; -292F;FALLING DIAGONAL CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;; -2930;RISING DIAGONAL CROSSING SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;; -2931;NORTH EAST ARROW CROSSING NORTH WEST ARROW;Sm;0;ON;;;;;N;;;;; -2932;NORTH WEST ARROW CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;; -2933;WAVE ARROW POINTING DIRECTLY RIGHT;Sm;0;ON;;;;;N;;;;; -2934;ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS;Sm;0;ON;;;;;N;;;;; -2935;ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS;Sm;0;ON;;;;;N;;;;; -2936;ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS;Sm;0;ON;;;;;N;;;;; -2937;ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS;Sm;0;ON;;;;;N;;;;; -2938;RIGHT-SIDE ARC CLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; -2939;LEFT-SIDE ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; -293A;TOP ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; -293B;BOTTOM ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; -293C;TOP ARC CLOCKWISE ARROW WITH MINUS;Sm;0;ON;;;;;N;;;;; -293D;TOP ARC ANTICLOCKWISE ARROW WITH PLUS;Sm;0;ON;;;;;N;;;;; -293E;LOWER RIGHT SEMICIRCULAR CLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; -293F;LOWER LEFT SEMICIRCULAR ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; -2940;ANTICLOCKWISE CLOSED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;; -2941;CLOCKWISE CLOSED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;; -2942;RIGHTWARDS ARROW ABOVE SHORT LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; -2943;LEFTWARDS ARROW ABOVE SHORT RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; -2944;SHORT RIGHTWARDS ARROW ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; -2945;RIGHTWARDS ARROW WITH PLUS BELOW;Sm;0;ON;;;;;N;;;;; -2946;LEFTWARDS ARROW WITH PLUS BELOW;Sm;0;ON;;;;;N;;;;; -2947;RIGHTWARDS ARROW THROUGH X;Sm;0;ON;;;;;N;;;;; -2948;LEFT RIGHT ARROW THROUGH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;; -2949;UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE;Sm;0;ON;;;;;N;;;;; -294A;LEFT BARB UP RIGHT BARB DOWN HARPOON;Sm;0;ON;;;;;N;;;;; -294B;LEFT BARB DOWN RIGHT BARB UP HARPOON;Sm;0;ON;;;;;N;;;;; -294C;UP BARB RIGHT DOWN BARB LEFT HARPOON;Sm;0;ON;;;;;N;;;;; -294D;UP BARB LEFT DOWN BARB RIGHT HARPOON;Sm;0;ON;;;;;N;;;;; -294E;LEFT BARB UP RIGHT BARB UP HARPOON;Sm;0;ON;;;;;N;;;;; -294F;UP BARB RIGHT DOWN BARB RIGHT HARPOON;Sm;0;ON;;;;;N;;;;; -2950;LEFT BARB DOWN RIGHT BARB DOWN HARPOON;Sm;0;ON;;;;;N;;;;; -2951;UP BARB LEFT DOWN BARB LEFT HARPOON;Sm;0;ON;;;;;N;;;;; -2952;LEFTWARDS HARPOON WITH BARB UP TO BAR;Sm;0;ON;;;;;N;;;;; -2953;RIGHTWARDS HARPOON WITH BARB UP TO BAR;Sm;0;ON;;;;;N;;;;; -2954;UPWARDS HARPOON WITH BARB RIGHT TO BAR;Sm;0;ON;;;;;N;;;;; -2955;DOWNWARDS HARPOON WITH BARB RIGHT TO BAR;Sm;0;ON;;;;;N;;;;; -2956;LEFTWARDS HARPOON WITH BARB DOWN TO BAR;Sm;0;ON;;;;;N;;;;; -2957;RIGHTWARDS HARPOON WITH BARB DOWN TO BAR;Sm;0;ON;;;;;N;;;;; -2958;UPWARDS HARPOON WITH BARB LEFT TO BAR;Sm;0;ON;;;;;N;;;;; -2959;DOWNWARDS HARPOON WITH BARB LEFT TO BAR;Sm;0;ON;;;;;N;;;;; -295A;LEFTWARDS HARPOON WITH BARB UP FROM BAR;Sm;0;ON;;;;;N;;;;; -295B;RIGHTWARDS HARPOON WITH BARB UP FROM BAR;Sm;0;ON;;;;;N;;;;; -295C;UPWARDS HARPOON WITH BARB RIGHT FROM BAR;Sm;0;ON;;;;;N;;;;; -295D;DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR;Sm;0;ON;;;;;N;;;;; -295E;LEFTWARDS HARPOON WITH BARB DOWN FROM BAR;Sm;0;ON;;;;;N;;;;; -295F;RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR;Sm;0;ON;;;;;N;;;;; -2960;UPWARDS HARPOON WITH BARB LEFT FROM BAR;Sm;0;ON;;;;;N;;;;; -2961;DOWNWARDS HARPOON WITH BARB LEFT FROM BAR;Sm;0;ON;;;;;N;;;;; -2962;LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;; -2963;UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;; -2964;RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;; -2965;DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;; -2966;LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP;Sm;0;ON;;;;;N;;;;; -2967;LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;; -2968;RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP;Sm;0;ON;;;;;N;;;;; -2969;RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;; -296A;LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH;Sm;0;ON;;;;;N;;;;; -296B;LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH;Sm;0;ON;;;;;N;;;;; -296C;RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH;Sm;0;ON;;;;;N;;;;; -296D;RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH;Sm;0;ON;;;;;N;;;;; -296E;UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;; -296F;DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;; -2970;RIGHT DOUBLE ARROW WITH ROUNDED HEAD;Sm;0;ON;;;;;N;;;;; -2971;EQUALS SIGN ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; -2972;TILDE OPERATOR ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; -2973;LEFTWARDS ARROW ABOVE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;; -2974;RIGHTWARDS ARROW ABOVE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;; -2975;RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;; -2976;LESS-THAN ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; -2977;LEFTWARDS ARROW THROUGH LESS-THAN;Sm;0;ON;;;;;N;;;;; -2978;GREATER-THAN ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; -2979;SUBSET ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; -297A;LEFTWARDS ARROW THROUGH SUBSET;Sm;0;ON;;;;;N;;;;; -297B;SUPERSET ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; -297C;LEFT FISH TAIL;Sm;0;ON;;;;;N;;;;; -297D;RIGHT FISH TAIL;Sm;0;ON;;;;;N;;;;; -297E;UP FISH TAIL;Sm;0;ON;;;;;N;;;;; -297F;DOWN FISH TAIL;Sm;0;ON;;;;;N;;;;; -2980;TRIPLE VERTICAL BAR DELIMITER;Sm;0;ON;;;;;N;;;;; -2981;Z NOTATION SPOT;Sm;0;ON;;;;;N;;;;; -2982;Z NOTATION TYPE COLON;Sm;0;ON;;;;;N;;;;; -2983;LEFT WHITE CURLY BRACKET;Ps;0;ON;;;;;Y;;;;; -2984;RIGHT WHITE CURLY BRACKET;Pe;0;ON;;;;;Y;;;;; -2985;LEFT WHITE PARENTHESIS;Ps;0;ON;;;;;Y;;;;; -2986;RIGHT WHITE PARENTHESIS;Pe;0;ON;;;;;Y;;;;; -2987;Z NOTATION LEFT IMAGE BRACKET;Ps;0;ON;;;;;Y;;;;; -2988;Z NOTATION RIGHT IMAGE BRACKET;Pe;0;ON;;;;;Y;;;;; -2989;Z NOTATION LEFT BINDING BRACKET;Ps;0;ON;;;;;Y;;;;; -298A;Z NOTATION RIGHT BINDING BRACKET;Pe;0;ON;;;;;Y;;;;; -298B;LEFT SQUARE BRACKET WITH UNDERBAR;Ps;0;ON;;;;;Y;;;;; -298C;RIGHT SQUARE BRACKET WITH UNDERBAR;Pe;0;ON;;;;;Y;;;;; -298D;LEFT SQUARE BRACKET WITH TICK IN TOP CORNER;Ps;0;ON;;;;;Y;;;;; -298E;RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER;Pe;0;ON;;;;;Y;;;;; -298F;LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER;Ps;0;ON;;;;;Y;;;;; -2990;RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER;Pe;0;ON;;;;;Y;;;;; -2991;LEFT ANGLE BRACKET WITH DOT;Ps;0;ON;;;;;Y;;;;; -2992;RIGHT ANGLE BRACKET WITH DOT;Pe;0;ON;;;;;Y;;;;; -2993;LEFT ARC LESS-THAN BRACKET;Ps;0;ON;;;;;Y;;;;; -2994;RIGHT ARC GREATER-THAN BRACKET;Pe;0;ON;;;;;Y;;;;; -2995;DOUBLE LEFT ARC GREATER-THAN BRACKET;Ps;0;ON;;;;;Y;;;;; -2996;DOUBLE RIGHT ARC LESS-THAN BRACKET;Pe;0;ON;;;;;Y;;;;; -2997;LEFT BLACK TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;;;;; -2998;RIGHT BLACK TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;;;;; -2999;DOTTED FENCE;Sm;0;ON;;;;;N;;;;; -299A;VERTICAL ZIGZAG LINE;Sm;0;ON;;;;;N;;;;; -299B;MEASURED ANGLE OPENING LEFT;Sm;0;ON;;;;;Y;;;;; -299C;RIGHT ANGLE VARIANT WITH SQUARE;Sm;0;ON;;;;;Y;;;;; -299D;MEASURED RIGHT ANGLE WITH DOT;Sm;0;ON;;;;;Y;;;;; -299E;ANGLE WITH S INSIDE;Sm;0;ON;;;;;Y;;;;; -299F;ACUTE ANGLE;Sm;0;ON;;;;;Y;;;;; -29A0;SPHERICAL ANGLE OPENING LEFT;Sm;0;ON;;;;;Y;;;;; -29A1;SPHERICAL ANGLE OPENING UP;Sm;0;ON;;;;;N;;;;; -29A2;TURNED ANGLE;Sm;0;ON;;;;;Y;;;;; -29A3;REVERSED ANGLE;Sm;0;ON;;;;;Y;;;;; -29A4;ANGLE WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; -29A5;REVERSED ANGLE WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; -29A6;OBLIQUE ANGLE OPENING UP;Sm;0;ON;;;;;Y;;;;; -29A7;OBLIQUE ANGLE OPENING DOWN;Sm;0;ON;;;;;Y;;;;; -29A8;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT;Sm;0;ON;;;;;Y;;;;; -29A9;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT;Sm;0;ON;;;;;Y;;;;; -29AA;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT;Sm;0;ON;;;;;Y;;;;; -29AB;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT;Sm;0;ON;;;;;Y;;;;; -29AC;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP;Sm;0;ON;;;;;Y;;;;; -29AD;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP;Sm;0;ON;;;;;Y;;;;; -29AE;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN;Sm;0;ON;;;;;Y;;;;; -29AF;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN;Sm;0;ON;;;;;Y;;;;; -29B0;REVERSED EMPTY SET;Sm;0;ON;;;;;N;;;;; -29B1;EMPTY SET WITH OVERBAR;Sm;0;ON;;;;;N;;;;; -29B2;EMPTY SET WITH SMALL CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;; -29B3;EMPTY SET WITH RIGHT ARROW ABOVE;Sm;0;ON;;;;;N;;;;; -29B4;EMPTY SET WITH LEFT ARROW ABOVE;Sm;0;ON;;;;;N;;;;; -29B5;CIRCLE WITH HORIZONTAL BAR;Sm;0;ON;;;;;N;;;;; -29B6;CIRCLED VERTICAL BAR;Sm;0;ON;;;;;N;;;;; -29B7;CIRCLED PARALLEL;Sm;0;ON;;;;;N;;;;; -29B8;CIRCLED REVERSE SOLIDUS;Sm;0;ON;;;;;Y;;;;; -29B9;CIRCLED PERPENDICULAR;Sm;0;ON;;;;;N;;;;; -29BA;CIRCLE DIVIDED BY HORIZONTAL BAR AND TOP HALF DIVIDED BY VERTICAL BAR;Sm;0;ON;;;;;N;;;;; -29BB;CIRCLE WITH SUPERIMPOSED X;Sm;0;ON;;;;;N;;;;; -29BC;CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN;Sm;0;ON;;;;;N;;;;; -29BD;UP ARROW THROUGH CIRCLE;Sm;0;ON;;;;;N;;;;; -29BE;CIRCLED WHITE BULLET;Sm;0;ON;;;;;N;;;;; -29BF;CIRCLED BULLET;Sm;0;ON;;;;;N;;;;; -29C0;CIRCLED LESS-THAN;Sm;0;ON;;;;;Y;;;;; -29C1;CIRCLED GREATER-THAN;Sm;0;ON;;;;;Y;;;;; -29C2;CIRCLE WITH SMALL CIRCLE TO THE RIGHT;Sm;0;ON;;;;;Y;;;;; -29C3;CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT;Sm;0;ON;;;;;Y;;;;; -29C4;SQUARED RISING DIAGONAL SLASH;Sm;0;ON;;;;;Y;;;;; -29C5;SQUARED FALLING DIAGONAL SLASH;Sm;0;ON;;;;;Y;;;;; -29C6;SQUARED ASTERISK;Sm;0;ON;;;;;N;;;;; -29C7;SQUARED SMALL CIRCLE;Sm;0;ON;;;;;N;;;;; -29C8;SQUARED SQUARE;Sm;0;ON;;;;;N;;;;; -29C9;TWO JOINED SQUARES;Sm;0;ON;;;;;Y;;;;; -29CA;TRIANGLE WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; -29CB;TRIANGLE WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; -29CC;S IN TRIANGLE;Sm;0;ON;;;;;N;;;;; -29CD;TRIANGLE WITH SERIFS AT BOTTOM;Sm;0;ON;;;;;N;;;;; -29CE;RIGHT TRIANGLE ABOVE LEFT TRIANGLE;Sm;0;ON;;;;;Y;;;;; -29CF;LEFT TRIANGLE BESIDE VERTICAL BAR;Sm;0;ON;;;;;Y;;;;; -29D0;VERTICAL BAR BESIDE RIGHT TRIANGLE;Sm;0;ON;;;;;Y;;;;; -29D1;BOWTIE WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;; -29D2;BOWTIE WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;; -29D3;BLACK BOWTIE;Sm;0;ON;;;;;N;;;;; -29D4;TIMES WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;; -29D5;TIMES WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;; -29D6;WHITE HOURGLASS;Sm;0;ON;;;;;N;;;;; -29D7;BLACK HOURGLASS;Sm;0;ON;;;;;N;;;;; -29D8;LEFT WIGGLY FENCE;Ps;0;ON;;;;;Y;;;;; -29D9;RIGHT WIGGLY FENCE;Pe;0;ON;;;;;Y;;;;; -29DA;LEFT DOUBLE WIGGLY FENCE;Ps;0;ON;;;;;Y;;;;; -29DB;RIGHT DOUBLE WIGGLY FENCE;Pe;0;ON;;;;;Y;;;;; -29DC;INCOMPLETE INFINITY;Sm;0;ON;;;;;Y;;;;; -29DD;TIE OVER INFINITY;Sm;0;ON;;;;;N;;;;; -29DE;INFINITY NEGATED WITH VERTICAL BAR;Sm;0;ON;;;;;N;;;;; -29DF;DOUBLE-ENDED MULTIMAP;Sm;0;ON;;;;;N;;;;; -29E0;SQUARE WITH CONTOURED OUTLINE;Sm;0;ON;;;;;N;;;;; -29E1;INCREASES AS;Sm;0;ON;;;;;Y;;;;; -29E2;SHUFFLE PRODUCT;Sm;0;ON;;;;;N;;;;; -29E3;EQUALS SIGN AND SLANTED PARALLEL;Sm;0;ON;;;;;Y;;;;; -29E4;EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE;Sm;0;ON;;;;;Y;;;;; -29E5;IDENTICAL TO AND SLANTED PARALLEL;Sm;0;ON;;;;;Y;;;;; -29E6;GLEICH STARK;Sm;0;ON;;;;;N;;;;; -29E7;THERMODYNAMIC;Sm;0;ON;;;;;N;;;;; -29E8;DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;; -29E9;DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;; -29EA;BLACK DIAMOND WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;; -29EB;BLACK LOZENGE;Sm;0;ON;;;;;N;;;;; -29EC;WHITE CIRCLE WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;; -29ED;BLACK CIRCLE WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;; -29EE;ERROR-BARRED WHITE SQUARE;Sm;0;ON;;;;;N;;;;; -29EF;ERROR-BARRED BLACK SQUARE;Sm;0;ON;;;;;N;;;;; -29F0;ERROR-BARRED WHITE DIAMOND;Sm;0;ON;;;;;N;;;;; -29F1;ERROR-BARRED BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; -29F2;ERROR-BARRED WHITE CIRCLE;Sm;0;ON;;;;;N;;;;; -29F3;ERROR-BARRED BLACK CIRCLE;Sm;0;ON;;;;;N;;;;; -29F4;RULE-DELAYED;Sm;0;ON;;;;;Y;;;;; -29F5;REVERSE SOLIDUS OPERATOR;Sm;0;ON;;;;;Y;;;;; -29F6;SOLIDUS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; -29F7;REVERSE SOLIDUS WITH HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; -29F8;BIG SOLIDUS;Sm;0;ON;;;;;Y;;;;; -29F9;BIG REVERSE SOLIDUS;Sm;0;ON;;;;;Y;;;;; -29FA;DOUBLE PLUS;Sm;0;ON;;;;;N;;;;; -29FB;TRIPLE PLUS;Sm;0;ON;;;;;N;;;;; -29FC;LEFT-POINTING CURVED ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;; -29FD;RIGHT-POINTING CURVED ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;; -29FE;TINY;Sm;0;ON;;;;;N;;;;; -29FF;MINY;Sm;0;ON;;;;;N;;;;; -2A00;N-ARY CIRCLED DOT OPERATOR;Sm;0;ON;;;;;N;;;;; -2A01;N-ARY CIRCLED PLUS OPERATOR;Sm;0;ON;;;;;N;;;;; -2A02;N-ARY CIRCLED TIMES OPERATOR;Sm;0;ON;;;;;N;;;;; -2A03;N-ARY UNION OPERATOR WITH DOT;Sm;0;ON;;;;;N;;;;; -2A04;N-ARY UNION OPERATOR WITH PLUS;Sm;0;ON;;;;;N;;;;; -2A05;N-ARY SQUARE INTERSECTION OPERATOR;Sm;0;ON;;;;;N;;;;; -2A06;N-ARY SQUARE UNION OPERATOR;Sm;0;ON;;;;;N;;;;; -2A07;TWO LOGICAL AND OPERATOR;Sm;0;ON;;;;;N;;;;; -2A08;TWO LOGICAL OR OPERATOR;Sm;0;ON;;;;;N;;;;; -2A09;N-ARY TIMES OPERATOR;Sm;0;ON;;;;;N;;;;; -2A0A;MODULO TWO SUM;Sm;0;ON;;;;;Y;;;;; -2A0B;SUMMATION WITH INTEGRAL;Sm;0;ON;;;;;Y;;;;; -2A0C;QUADRUPLE INTEGRAL OPERATOR;Sm;0;ON;<compat> 222B 222B 222B 222B;;;;Y;;;;; -2A0D;FINITE PART INTEGRAL;Sm;0;ON;;;;;Y;;;;; -2A0E;INTEGRAL WITH DOUBLE STROKE;Sm;0;ON;;;;;Y;;;;; -2A0F;INTEGRAL AVERAGE WITH SLASH;Sm;0;ON;;;;;Y;;;;; -2A10;CIRCULATION FUNCTION;Sm;0;ON;;;;;Y;;;;; -2A11;ANTICLOCKWISE INTEGRATION;Sm;0;ON;;;;;Y;;;;; -2A12;LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE;Sm;0;ON;;;;;Y;;;;; -2A13;LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE;Sm;0;ON;;;;;Y;;;;; -2A14;LINE INTEGRATION NOT INCLUDING THE POLE;Sm;0;ON;;;;;Y;;;;; -2A15;INTEGRAL AROUND A POINT OPERATOR;Sm;0;ON;;;;;Y;;;;; -2A16;QUATERNION INTEGRAL OPERATOR;Sm;0;ON;;;;;Y;;;;; -2A17;INTEGRAL WITH LEFTWARDS ARROW WITH HOOK;Sm;0;ON;;;;;Y;;;;; -2A18;INTEGRAL WITH TIMES SIGN;Sm;0;ON;;;;;Y;;;;; -2A19;INTEGRAL WITH INTERSECTION;Sm;0;ON;;;;;Y;;;;; -2A1A;INTEGRAL WITH UNION;Sm;0;ON;;;;;Y;;;;; -2A1B;INTEGRAL WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; -2A1C;INTEGRAL WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; -2A1D;JOIN;Sm;0;ON;;;;;N;;;;; -2A1E;LARGE LEFT TRIANGLE OPERATOR;Sm;0;ON;;;;;Y;;;;; -2A1F;Z NOTATION SCHEMA COMPOSITION;Sm;0;ON;;;;;Y;;;;; -2A20;Z NOTATION SCHEMA PIPING;Sm;0;ON;;;;;Y;;;;; -2A21;Z NOTATION SCHEMA PROJECTION;Sm;0;ON;;;;;Y;;;;; -2A22;PLUS SIGN WITH SMALL CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;; -2A23;PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE;Sm;0;ON;;;;;N;;;;; -2A24;PLUS SIGN WITH TILDE ABOVE;Sm;0;ON;;;;;Y;;;;; -2A25;PLUS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;; -2A26;PLUS SIGN WITH TILDE BELOW;Sm;0;ON;;;;;Y;;;;; -2A27;PLUS SIGN WITH SUBSCRIPT TWO;Sm;0;ON;;;;;N;;;;; -2A28;PLUS SIGN WITH BLACK TRIANGLE;Sm;0;ON;;;;;N;;;;; -2A29;MINUS SIGN WITH COMMA ABOVE;Sm;0;ON;;;;;Y;;;;; -2A2A;MINUS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;; -2A2B;MINUS SIGN WITH FALLING DOTS;Sm;0;ON;;;;;Y;;;;; -2A2C;MINUS SIGN WITH RISING DOTS;Sm;0;ON;;;;;Y;;;;; -2A2D;PLUS SIGN IN LEFT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;; -2A2E;PLUS SIGN IN RIGHT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;; -2A2F;VECTOR OR CROSS PRODUCT;Sm;0;ON;;;;;N;;;;; -2A30;MULTIPLICATION SIGN WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; -2A31;MULTIPLICATION SIGN WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; -2A32;SEMIDIRECT PRODUCT WITH BOTTOM CLOSED;Sm;0;ON;;;;;N;;;;; -2A33;SMASH PRODUCT;Sm;0;ON;;;;;N;;;;; -2A34;MULTIPLICATION SIGN IN LEFT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;; -2A35;MULTIPLICATION SIGN IN RIGHT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;; -2A36;CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT;Sm;0;ON;;;;;N;;;;; -2A37;MULTIPLICATION SIGN IN DOUBLE CIRCLE;Sm;0;ON;;;;;N;;;;; -2A38;CIRCLED DIVISION SIGN;Sm;0;ON;;;;;N;;;;; -2A39;PLUS SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;; -2A3A;MINUS SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;; -2A3B;MULTIPLICATION SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;; -2A3C;INTERIOR PRODUCT;Sm;0;ON;;;;;Y;;;;; -2A3D;RIGHTHAND INTERIOR PRODUCT;Sm;0;ON;;;;;Y;;;;; -2A3E;Z NOTATION RELATIONAL COMPOSITION;Sm;0;ON;;;;;Y;;;;; -2A3F;AMALGAMATION OR COPRODUCT;Sm;0;ON;;;;;N;;;;; -2A40;INTERSECTION WITH DOT;Sm;0;ON;;;;;N;;;;; -2A41;UNION WITH MINUS SIGN;Sm;0;ON;;;;;N;;;;; -2A42;UNION WITH OVERBAR;Sm;0;ON;;;;;N;;;;; -2A43;INTERSECTION WITH OVERBAR;Sm;0;ON;;;;;N;;;;; -2A44;INTERSECTION WITH LOGICAL AND;Sm;0;ON;;;;;N;;;;; -2A45;UNION WITH LOGICAL OR;Sm;0;ON;;;;;N;;;;; -2A46;UNION ABOVE INTERSECTION;Sm;0;ON;;;;;N;;;;; -2A47;INTERSECTION ABOVE UNION;Sm;0;ON;;;;;N;;;;; -2A48;UNION ABOVE BAR ABOVE INTERSECTION;Sm;0;ON;;;;;N;;;;; -2A49;INTERSECTION ABOVE BAR ABOVE UNION;Sm;0;ON;;;;;N;;;;; -2A4A;UNION BESIDE AND JOINED WITH UNION;Sm;0;ON;;;;;N;;;;; -2A4B;INTERSECTION BESIDE AND JOINED WITH INTERSECTION;Sm;0;ON;;;;;N;;;;; -2A4C;CLOSED UNION WITH SERIFS;Sm;0;ON;;;;;N;;;;; -2A4D;CLOSED INTERSECTION WITH SERIFS;Sm;0;ON;;;;;N;;;;; -2A4E;DOUBLE SQUARE INTERSECTION;Sm;0;ON;;;;;N;;;;; -2A4F;DOUBLE SQUARE UNION;Sm;0;ON;;;;;N;;;;; -2A50;CLOSED UNION WITH SERIFS AND SMASH PRODUCT;Sm;0;ON;;;;;N;;;;; -2A51;LOGICAL AND WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; -2A52;LOGICAL OR WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; -2A53;DOUBLE LOGICAL AND;Sm;0;ON;;;;;N;;;;; -2A54;DOUBLE LOGICAL OR;Sm;0;ON;;;;;N;;;;; -2A55;TWO INTERSECTING LOGICAL AND;Sm;0;ON;;;;;N;;;;; -2A56;TWO INTERSECTING LOGICAL OR;Sm;0;ON;;;;;N;;;;; -2A57;SLOPING LARGE OR;Sm;0;ON;;;;;Y;;;;; -2A58;SLOPING LARGE AND;Sm;0;ON;;;;;Y;;;;; -2A59;LOGICAL OR OVERLAPPING LOGICAL AND;Sm;0;ON;;;;;N;;;;; -2A5A;LOGICAL AND WITH MIDDLE STEM;Sm;0;ON;;;;;N;;;;; -2A5B;LOGICAL OR WITH MIDDLE STEM;Sm;0;ON;;;;;N;;;;; -2A5C;LOGICAL AND WITH HORIZONTAL DASH;Sm;0;ON;;;;;N;;;;; -2A5D;LOGICAL OR WITH HORIZONTAL DASH;Sm;0;ON;;;;;N;;;;; -2A5E;LOGICAL AND WITH DOUBLE OVERBAR;Sm;0;ON;;;;;N;;;;; -2A5F;LOGICAL AND WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; -2A60;LOGICAL AND WITH DOUBLE UNDERBAR;Sm;0;ON;;;;;N;;;;; -2A61;SMALL VEE WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; -2A62;LOGICAL OR WITH DOUBLE OVERBAR;Sm;0;ON;;;;;N;;;;; -2A63;LOGICAL OR WITH DOUBLE UNDERBAR;Sm;0;ON;;;;;N;;;;; -2A64;Z NOTATION DOMAIN ANTIRESTRICTION;Sm;0;ON;;;;;Y;;;;; -2A65;Z NOTATION RANGE ANTIRESTRICTION;Sm;0;ON;;;;;Y;;;;; -2A66;EQUALS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;; -2A67;IDENTICAL WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; -2A68;TRIPLE HORIZONTAL BAR WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -2A69;TRIPLE HORIZONTAL BAR WITH TRIPLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -2A6A;TILDE OPERATOR WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; -2A6B;TILDE OPERATOR WITH RISING DOTS;Sm;0;ON;;;;;Y;;;;; -2A6C;SIMILAR MINUS SIMILAR;Sm;0;ON;;;;;Y;;;;; -2A6D;CONGRUENT WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; -2A6E;EQUALS WITH ASTERISK;Sm;0;ON;;;;;N;;;;; -2A6F;ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT;Sm;0;ON;;;;;Y;;;;; -2A70;APPROXIMATELY EQUAL OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2A71;EQUALS SIGN ABOVE PLUS SIGN;Sm;0;ON;;;;;N;;;;; -2A72;PLUS SIGN ABOVE EQUALS SIGN;Sm;0;ON;;;;;N;;;;; -2A73;EQUALS SIGN ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; -2A74;DOUBLE COLON EQUAL;Sm;0;ON;<compat> 003A 003A 003D;;;;Y;;;;; -2A75;TWO CONSECUTIVE EQUALS SIGNS;Sm;0;ON;<compat> 003D 003D;;;;N;;;;; -2A76;THREE CONSECUTIVE EQUALS SIGNS;Sm;0;ON;<compat> 003D 003D 003D;;;;N;;;;; -2A77;EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW;Sm;0;ON;;;;;N;;;;; -2A78;EQUIVALENT WITH FOUR DOTS ABOVE;Sm;0;ON;;;;;N;;;;; -2A79;LESS-THAN WITH CIRCLE INSIDE;Sm;0;ON;;;;;Y;;;;; -2A7A;GREATER-THAN WITH CIRCLE INSIDE;Sm;0;ON;;;;;Y;;;;; -2A7B;LESS-THAN WITH QUESTION MARK ABOVE;Sm;0;ON;;;;;Y;;;;; -2A7C;GREATER-THAN WITH QUESTION MARK ABOVE;Sm;0;ON;;;;;Y;;;;; -2A7D;LESS-THAN OR SLANTED EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2A7E;GREATER-THAN OR SLANTED EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2A7F;LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;; -2A80;GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;; -2A81;LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; -2A82;GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; -2A83;LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT;Sm;0;ON;;;;;Y;;;;; -2A84;GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT;Sm;0;ON;;;;;Y;;;;; -2A85;LESS-THAN OR APPROXIMATE;Sm;0;ON;;;;;Y;;;;; -2A86;GREATER-THAN OR APPROXIMATE;Sm;0;ON;;;;;Y;;;;; -2A87;LESS-THAN AND SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2A88;GREATER-THAN AND SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2A89;LESS-THAN AND NOT APPROXIMATE;Sm;0;ON;;;;;Y;;;;; -2A8A;GREATER-THAN AND NOT APPROXIMATE;Sm;0;ON;;;;;Y;;;;; -2A8B;LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN;Sm;0;ON;;;;;Y;;;;; -2A8C;GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN;Sm;0;ON;;;;;Y;;;;; -2A8D;LESS-THAN ABOVE SIMILAR OR EQUAL;Sm;0;ON;;;;;Y;;;;; -2A8E;GREATER-THAN ABOVE SIMILAR OR EQUAL;Sm;0;ON;;;;;Y;;;;; -2A8F;LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN;Sm;0;ON;;;;;Y;;;;; -2A90;GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN;Sm;0;ON;;;;;Y;;;;; -2A91;LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL;Sm;0;ON;;;;;Y;;;;; -2A92;GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL;Sm;0;ON;;;;;Y;;;;; -2A93;LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;; -2A94;GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;; -2A95;SLANTED EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;; -2A96;SLANTED EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;; -2A97;SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;; -2A98;SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;; -2A99;DOUBLE-LINE EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;; -2A9A;DOUBLE-LINE EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;; -2A9B;DOUBLE-LINE SLANTED EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;; -2A9C;DOUBLE-LINE SLANTED EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;; -2A9D;SIMILAR OR LESS-THAN;Sm;0;ON;;;;;Y;;;;; -2A9E;SIMILAR OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;; -2A9F;SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; -2AA0;SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; -2AA1;DOUBLE NESTED LESS-THAN;Sm;0;ON;;;;;Y;;;;; -2AA2;DOUBLE NESTED GREATER-THAN;Sm;0;ON;;;;;Y;;;;; -2AA3;DOUBLE NESTED LESS-THAN WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; -2AA4;GREATER-THAN OVERLAPPING LESS-THAN;Sm;0;ON;;;;;N;;;;; -2AA5;GREATER-THAN BESIDE LESS-THAN;Sm;0;ON;;;;;N;;;;; -2AA6;LESS-THAN CLOSED BY CURVE;Sm;0;ON;;;;;Y;;;;; -2AA7;GREATER-THAN CLOSED BY CURVE;Sm;0;ON;;;;;Y;;;;; -2AA8;LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;; -2AA9;GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;; -2AAA;SMALLER THAN;Sm;0;ON;;;;;Y;;;;; -2AAB;LARGER THAN;Sm;0;ON;;;;;Y;;;;; -2AAC;SMALLER THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2AAD;LARGER THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2AAE;EQUALS SIGN WITH BUMPY ABOVE;Sm;0;ON;;;;;N;;;;; -2AAF;PRECEDES ABOVE SINGLE-LINE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; -2AB0;SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; -2AB1;PRECEDES ABOVE SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2AB2;SUCCEEDS ABOVE SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2AB3;PRECEDES ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; -2AB4;SUCCEEDS ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; -2AB5;PRECEDES ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2AB6;SUCCEEDS ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2AB7;PRECEDES ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2AB8;SUCCEEDS ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2AB9;PRECEDES ABOVE NOT ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2ABA;SUCCEEDS ABOVE NOT ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2ABB;DOUBLE PRECEDES;Sm;0;ON;;;;;Y;;;;; -2ABC;DOUBLE SUCCEEDS;Sm;0;ON;;;;;Y;;;;; -2ABD;SUBSET WITH DOT;Sm;0;ON;;;;;Y;;;;; -2ABE;SUPERSET WITH DOT;Sm;0;ON;;;;;Y;;;;; -2ABF;SUBSET WITH PLUS SIGN BELOW;Sm;0;ON;;;;;Y;;;;; -2AC0;SUPERSET WITH PLUS SIGN BELOW;Sm;0;ON;;;;;Y;;;;; -2AC1;SUBSET WITH MULTIPLICATION SIGN BELOW;Sm;0;ON;;;;;Y;;;;; -2AC2;SUPERSET WITH MULTIPLICATION SIGN BELOW;Sm;0;ON;;;;;Y;;;;; -2AC3;SUBSET OF OR EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; -2AC4;SUPERSET OF OR EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; -2AC5;SUBSET OF ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; -2AC6;SUPERSET OF ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; -2AC7;SUBSET OF ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; -2AC8;SUPERSET OF ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; -2AC9;SUBSET OF ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2ACA;SUPERSET OF ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2ACB;SUBSET OF ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2ACC;SUPERSET OF ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2ACD;SQUARE LEFT OPEN BOX OPERATOR;Sm;0;ON;;;;;Y;;;;; -2ACE;SQUARE RIGHT OPEN BOX OPERATOR;Sm;0;ON;;;;;Y;;;;; -2ACF;CLOSED SUBSET;Sm;0;ON;;;;;Y;;;;; -2AD0;CLOSED SUPERSET;Sm;0;ON;;;;;Y;;;;; -2AD1;CLOSED SUBSET OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2AD2;CLOSED SUPERSET OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2AD3;SUBSET ABOVE SUPERSET;Sm;0;ON;;;;;Y;;;;; -2AD4;SUPERSET ABOVE SUBSET;Sm;0;ON;;;;;Y;;;;; -2AD5;SUBSET ABOVE SUBSET;Sm;0;ON;;;;;Y;;;;; -2AD6;SUPERSET ABOVE SUPERSET;Sm;0;ON;;;;;Y;;;;; -2AD7;SUPERSET BESIDE SUBSET;Sm;0;ON;;;;;N;;;;; -2AD8;SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET;Sm;0;ON;;;;;N;;;;; -2AD9;ELEMENT OF OPENING DOWNWARDS;Sm;0;ON;;;;;N;;;;; -2ADA;PITCHFORK WITH TEE TOP;Sm;0;ON;;;;;N;;;;; -2ADB;TRANSVERSAL INTERSECTION;Sm;0;ON;;;;;N;;;;; -2ADC;FORKING;Sm;0;ON;2ADD 0338;;;;Y;;;;; -2ADD;NONFORKING;Sm;0;ON;;;;;N;;;;; -2ADE;SHORT LEFT TACK;Sm;0;ON;;;;;Y;;;;; -2ADF;SHORT DOWN TACK;Sm;0;ON;;;;;N;;;;; -2AE0;SHORT UP TACK;Sm;0;ON;;;;;N;;;;; -2AE1;PERPENDICULAR WITH S;Sm;0;ON;;;;;N;;;;; -2AE2;VERTICAL BAR TRIPLE RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;; -2AE3;DOUBLE VERTICAL BAR LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;; -2AE4;VERTICAL BAR DOUBLE LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;; -2AE5;DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;; -2AE6;LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL;Sm;0;ON;;;;;Y;;;;; -2AE7;SHORT DOWN TACK WITH OVERBAR;Sm;0;ON;;;;;N;;;;; -2AE8;SHORT UP TACK WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; -2AE9;SHORT UP TACK ABOVE SHORT DOWN TACK;Sm;0;ON;;;;;N;;;;; -2AEA;DOUBLE DOWN TACK;Sm;0;ON;;;;;N;;;;; -2AEB;DOUBLE UP TACK;Sm;0;ON;;;;;N;;;;; -2AEC;DOUBLE STROKE NOT SIGN;Sm;0;ON;;;;;Y;;;;; -2AED;REVERSED DOUBLE STROKE NOT SIGN;Sm;0;ON;;;;;Y;;;;; -2AEE;DOES NOT DIVIDE WITH REVERSED NEGATION SLASH;Sm;0;ON;;;;;Y;;;;; -2AEF;VERTICAL LINE WITH CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;; -2AF0;VERTICAL LINE WITH CIRCLE BELOW;Sm;0;ON;;;;;N;;;;; -2AF1;DOWN TACK WITH CIRCLE BELOW;Sm;0;ON;;;;;N;;;;; -2AF2;PARALLEL WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; -2AF3;PARALLEL WITH TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; -2AF4;TRIPLE VERTICAL BAR BINARY RELATION;Sm;0;ON;;;;;N;;;;; -2AF5;TRIPLE VERTICAL BAR WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; -2AF6;TRIPLE COLON OPERATOR;Sm;0;ON;;;;;N;;;;; -2AF7;TRIPLE NESTED LESS-THAN;Sm;0;ON;;;;;Y;;;;; -2AF8;TRIPLE NESTED GREATER-THAN;Sm;0;ON;;;;;Y;;;;; -2AF9;DOUBLE-LINE SLANTED LESS-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2AFA;DOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; -2AFB;TRIPLE SOLIDUS BINARY RELATION;Sm;0;ON;;;;;Y;;;;; -2AFC;LARGE TRIPLE VERTICAL BAR OPERATOR;Sm;0;ON;;;;;N;;;;; -2AFD;DOUBLE SOLIDUS OPERATOR;Sm;0;ON;;;;;Y;;;;; -2AFE;WHITE VERTICAL BAR;Sm;0;ON;;;;;N;;;;; -2AFF;N-ARY WHITE VERTICAL BAR;Sm;0;ON;;;;;N;;;;; -2B00;NORTH EAST WHITE ARROW;So;0;ON;;;;;N;;;;; -2B01;NORTH WEST WHITE ARROW;So;0;ON;;;;;N;;;;; -2B02;SOUTH EAST WHITE ARROW;So;0;ON;;;;;N;;;;; -2B03;SOUTH WEST WHITE ARROW;So;0;ON;;;;;N;;;;; -2B04;LEFT RIGHT WHITE ARROW;So;0;ON;;;;;N;;;;; -2B05;LEFTWARDS BLACK ARROW;So;0;ON;;;;;N;;;;; -2B06;UPWARDS BLACK ARROW;So;0;ON;;;;;N;;;;; -2B07;DOWNWARDS BLACK ARROW;So;0;ON;;;;;N;;;;; -2B08;NORTH EAST BLACK ARROW;So;0;ON;;;;;N;;;;; -2B09;NORTH WEST BLACK ARROW;So;0;ON;;;;;N;;;;; -2B0A;SOUTH EAST BLACK ARROW;So;0;ON;;;;;N;;;;; -2B0B;SOUTH WEST BLACK ARROW;So;0;ON;;;;;N;;;;; -2B0C;LEFT RIGHT BLACK ARROW;So;0;ON;;;;;N;;;;; -2B0D;UP DOWN BLACK ARROW;So;0;ON;;;;;N;;;;; -2B0E;RIGHTWARDS ARROW WITH TIP DOWNWARDS;So;0;ON;;;;;N;;;;; -2B0F;RIGHTWARDS ARROW WITH TIP UPWARDS;So;0;ON;;;;;N;;;;; -2B10;LEFTWARDS ARROW WITH TIP DOWNWARDS;So;0;ON;;;;;N;;;;; -2B11;LEFTWARDS ARROW WITH TIP UPWARDS;So;0;ON;;;;;N;;;;; -2B12;SQUARE WITH TOP HALF BLACK;So;0;ON;;;;;N;;;;; -2B13;SQUARE WITH BOTTOM HALF BLACK;So;0;ON;;;;;N;;;;; -2B14;SQUARE WITH UPPER RIGHT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;; -2B15;SQUARE WITH LOWER LEFT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;; -2B16;DIAMOND WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;; -2B17;DIAMOND WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;; -2B18;DIAMOND WITH TOP HALF BLACK;So;0;ON;;;;;N;;;;; -2B19;DIAMOND WITH BOTTOM HALF BLACK;So;0;ON;;;;;N;;;;; -2B1A;DOTTED SQUARE;So;0;ON;;;;;N;;;;; -2B1B;BLACK LARGE SQUARE;So;0;ON;;;;;N;;;;; -2B1C;WHITE LARGE SQUARE;So;0;ON;;;;;N;;;;; -2B1D;BLACK VERY SMALL SQUARE;So;0;ON;;;;;N;;;;; -2B1E;WHITE VERY SMALL SQUARE;So;0;ON;;;;;N;;;;; -2B1F;BLACK PENTAGON;So;0;ON;;;;;N;;;;; -2B20;WHITE PENTAGON;So;0;ON;;;;;N;;;;; -2B21;WHITE HEXAGON;So;0;ON;;;;;N;;;;; -2B22;BLACK HEXAGON;So;0;ON;;;;;N;;;;; -2B23;HORIZONTAL BLACK HEXAGON;So;0;ON;;;;;N;;;;; -2B24;BLACK LARGE CIRCLE;So;0;ON;;;;;N;;;;; -2B25;BLACK MEDIUM DIAMOND;So;0;ON;;;;;N;;;;; -2B26;WHITE MEDIUM DIAMOND;So;0;ON;;;;;N;;;;; -2B27;BLACK MEDIUM LOZENGE;So;0;ON;;;;;N;;;;; -2B28;WHITE MEDIUM LOZENGE;So;0;ON;;;;;N;;;;; -2B29;BLACK SMALL DIAMOND;So;0;ON;;;;;N;;;;; -2B2A;BLACK SMALL LOZENGE;So;0;ON;;;;;N;;;;; -2B2B;WHITE SMALL LOZENGE;So;0;ON;;;;;N;;;;; -2B2C;BLACK HORIZONTAL ELLIPSE;So;0;ON;;;;;N;;;;; -2B2D;WHITE HORIZONTAL ELLIPSE;So;0;ON;;;;;N;;;;; -2B2E;BLACK VERTICAL ELLIPSE;So;0;ON;;;;;N;;;;; -2B2F;WHITE VERTICAL ELLIPSE;So;0;ON;;;;;N;;;;; -2B30;LEFT ARROW WITH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;; -2B31;THREE LEFTWARDS ARROWS;Sm;0;ON;;;;;N;;;;; -2B32;LEFT ARROW WITH CIRCLED PLUS;Sm;0;ON;;;;;N;;;;; -2B33;LONG LEFTWARDS SQUIGGLE ARROW;Sm;0;ON;;;;;N;;;;; -2B34;LEFTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -2B35;LEFTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -2B36;LEFTWARDS TWO-HEADED ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; -2B37;LEFTWARDS TWO-HEADED TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;; -2B38;LEFTWARDS ARROW WITH DOTTED STEM;Sm;0;ON;;;;;N;;;;; -2B39;LEFTWARDS ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -2B3A;LEFTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -2B3B;LEFTWARDS TWO-HEADED ARROW WITH TAIL;Sm;0;ON;;;;;N;;;;; -2B3C;LEFTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -2B3D;LEFTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; -2B3E;LEFTWARDS ARROW THROUGH X;Sm;0;ON;;;;;N;;;;; -2B3F;WAVE ARROW POINTING DIRECTLY LEFT;Sm;0;ON;;;;;N;;;;; -2B40;EQUALS SIGN ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; -2B41;REVERSE TILDE OPERATOR ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; -2B42;LEFTWARDS ARROW ABOVE REVERSE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;; -2B43;RIGHTWARDS ARROW THROUGH GREATER-THAN;Sm;0;ON;;;;;N;;;;; -2B44;RIGHTWARDS ARROW THROUGH SUPERSET;Sm;0;ON;;;;;N;;;;; -2B45;LEFTWARDS QUADRUPLE ARROW;So;0;ON;;;;;N;;;;; -2B46;RIGHTWARDS QUADRUPLE ARROW;So;0;ON;;;;;N;;;;; -2B47;REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; -2B48;RIGHTWARDS ARROW ABOVE REVERSE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;; -2B49;TILDE OPERATOR ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; -2B4A;LEFTWARDS ARROW ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;; -2B4B;LEFTWARDS ARROW ABOVE REVERSE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;; -2B4C;RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;; -2B4D;DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW;So;0;ON;;;;;N;;;;; -2B4E;SHORT SLANTED NORTH ARROW;So;0;ON;;;;;N;;;;; -2B4F;SHORT BACKSLANTED SOUTH ARROW;So;0;ON;;;;;N;;;;; -2B50;WHITE MEDIUM STAR;So;0;ON;;;;;N;;;;; -2B51;BLACK SMALL STAR;So;0;ON;;;;;N;;;;; -2B52;WHITE SMALL STAR;So;0;ON;;;;;N;;;;; -2B53;BLACK RIGHT-POINTING PENTAGON;So;0;ON;;;;;N;;;;; -2B54;WHITE RIGHT-POINTING PENTAGON;So;0;ON;;;;;N;;;;; -2B55;HEAVY LARGE CIRCLE;So;0;ON;;;;;N;;;;; -2B56;HEAVY OVAL WITH OVAL INSIDE;So;0;ON;;;;;N;;;;; -2B57;HEAVY CIRCLE WITH CIRCLE INSIDE;So;0;ON;;;;;N;;;;; -2B58;HEAVY CIRCLE;So;0;ON;;;;;N;;;;; -2B59;HEAVY CIRCLED SALTIRE;So;0;ON;;;;;N;;;;; -2B5A;SLANTED NORTH ARROW WITH HOOKED HEAD;So;0;ON;;;;;N;;;;; -2B5B;BACKSLANTED SOUTH ARROW WITH HOOKED TAIL;So;0;ON;;;;;N;;;;; -2B5C;SLANTED NORTH ARROW WITH HORIZONTAL TAIL;So;0;ON;;;;;N;;;;; -2B5D;BACKSLANTED SOUTH ARROW WITH HORIZONTAL TAIL;So;0;ON;;;;;N;;;;; -2B5E;BENT ARROW POINTING DOWNWARDS THEN NORTH EAST;So;0;ON;;;;;N;;;;; -2B5F;SHORT BENT ARROW POINTING DOWNWARDS THEN NORTH EAST;So;0;ON;;;;;N;;;;; -2B60;LEFTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; -2B61;UPWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; -2B62;RIGHTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; -2B63;DOWNWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; -2B64;LEFT RIGHT TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; -2B65;UP DOWN TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; -2B66;NORTH WEST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; -2B67;NORTH EAST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; -2B68;SOUTH EAST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; -2B69;SOUTH WEST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; -2B6A;LEFTWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;; -2B6B;UPWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;; -2B6C;RIGHTWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;; -2B6D;DOWNWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;; -2B6E;CLOCKWISE TRIANGLE-HEADED OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;; -2B6F;ANTICLOCKWISE TRIANGLE-HEADED OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;; -2B70;LEFTWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; -2B71;UPWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; -2B72;RIGHTWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; -2B73;DOWNWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; -2B76;NORTH WEST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; -2B77;NORTH EAST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; -2B78;SOUTH EAST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; -2B79;SOUTH WEST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; -2B7A;LEFTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;; -2B7B;UPWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;; -2B7C;RIGHTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;; -2B7D;DOWNWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;; -2B7E;HORIZONTAL TAB KEY;So;0;ON;;;;;N;;;;; -2B7F;VERTICAL TAB KEY;So;0;ON;;;;;N;;;;; -2B80;LEFTWARDS TRIANGLE-HEADED ARROW OVER RIGHTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; -2B81;UPWARDS TRIANGLE-HEADED ARROW LEFTWARDS OF DOWNWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; -2B82;RIGHTWARDS TRIANGLE-HEADED ARROW OVER LEFTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; -2B83;DOWNWARDS TRIANGLE-HEADED ARROW LEFTWARDS OF UPWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; -2B84;LEFTWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;; -2B85;UPWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;; -2B86;RIGHTWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;; -2B87;DOWNWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;; -2B88;LEFTWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;; -2B89;UPWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;; -2B8A;RIGHTWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;; -2B8B;DOWNWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;; -2B8C;ANTICLOCKWISE TRIANGLE-HEADED RIGHT U-SHAPED ARROW;So;0;ON;;;;;N;;;;; -2B8D;ANTICLOCKWISE TRIANGLE-HEADED BOTTOM U-SHAPED ARROW;So;0;ON;;;;;N;;;;; -2B8E;ANTICLOCKWISE TRIANGLE-HEADED LEFT U-SHAPED ARROW;So;0;ON;;;;;N;;;;; -2B8F;ANTICLOCKWISE TRIANGLE-HEADED TOP U-SHAPED ARROW;So;0;ON;;;;;N;;;;; -2B90;RETURN LEFT;So;0;ON;;;;;N;;;;; -2B91;RETURN RIGHT;So;0;ON;;;;;N;;;;; -2B92;NEWLINE LEFT;So;0;ON;;;;;N;;;;; -2B93;NEWLINE RIGHT;So;0;ON;;;;;N;;;;; -2B94;FOUR CORNER ARROWS CIRCLING ANTICLOCKWISE;So;0;ON;;;;;N;;;;; -2B95;RIGHTWARDS BLACK ARROW;So;0;ON;;;;;N;;;;; -2B97;SYMBOL FOR TYPE A ELECTRONICS;So;0;ON;;;;;N;;;;; -2B98;THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -2B99;THREE-D RIGHT-LIGHTED UPWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -2B9A;THREE-D TOP-LIGHTED RIGHTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -2B9B;THREE-D LEFT-LIGHTED DOWNWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -2B9C;BLACK LEFTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -2B9D;BLACK UPWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -2B9E;BLACK RIGHTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -2B9F;BLACK DOWNWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -2BA0;DOWNWARDS TRIANGLE-HEADED ARROW WITH LONG TIP LEFTWARDS;So;0;ON;;;;;N;;;;; -2BA1;DOWNWARDS TRIANGLE-HEADED ARROW WITH LONG TIP RIGHTWARDS;So;0;ON;;;;;N;;;;; -2BA2;UPWARDS TRIANGLE-HEADED ARROW WITH LONG TIP LEFTWARDS;So;0;ON;;;;;N;;;;; -2BA3;UPWARDS TRIANGLE-HEADED ARROW WITH LONG TIP RIGHTWARDS;So;0;ON;;;;;N;;;;; -2BA4;LEFTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP UPWARDS;So;0;ON;;;;;N;;;;; -2BA5;RIGHTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP UPWARDS;So;0;ON;;;;;N;;;;; -2BA6;LEFTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP DOWNWARDS;So;0;ON;;;;;N;;;;; -2BA7;RIGHTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP DOWNWARDS;So;0;ON;;;;;N;;;;; -2BA8;BLACK CURVED DOWNWARDS AND LEFTWARDS ARROW;So;0;ON;;;;;N;;;;; -2BA9;BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;;;;; -2BAA;BLACK CURVED UPWARDS AND LEFTWARDS ARROW;So;0;ON;;;;;N;;;;; -2BAB;BLACK CURVED UPWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;;;;; -2BAC;BLACK CURVED LEFTWARDS AND UPWARDS ARROW;So;0;ON;;;;;N;;;;; -2BAD;BLACK CURVED RIGHTWARDS AND UPWARDS ARROW;So;0;ON;;;;;N;;;;; -2BAE;BLACK CURVED LEFTWARDS AND DOWNWARDS ARROW;So;0;ON;;;;;N;;;;; -2BAF;BLACK CURVED RIGHTWARDS AND DOWNWARDS ARROW;So;0;ON;;;;;N;;;;; -2BB0;RIBBON ARROW DOWN LEFT;So;0;ON;;;;;N;;;;; -2BB1;RIBBON ARROW DOWN RIGHT;So;0;ON;;;;;N;;;;; -2BB2;RIBBON ARROW UP LEFT;So;0;ON;;;;;N;;;;; -2BB3;RIBBON ARROW UP RIGHT;So;0;ON;;;;;N;;;;; -2BB4;RIBBON ARROW LEFT UP;So;0;ON;;;;;N;;;;; -2BB5;RIBBON ARROW RIGHT UP;So;0;ON;;;;;N;;;;; -2BB6;RIBBON ARROW LEFT DOWN;So;0;ON;;;;;N;;;;; -2BB7;RIBBON ARROW RIGHT DOWN;So;0;ON;;;;;N;;;;; -2BB8;UPWARDS WHITE ARROW FROM BAR WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;; -2BB9;UP ARROWHEAD IN A RECTANGLE BOX;So;0;ON;;;;;N;;;;; -2BBA;OVERLAPPING WHITE SQUARES;So;0;ON;;;;;N;;;;; -2BBB;OVERLAPPING WHITE AND BLACK SQUARES;So;0;ON;;;;;N;;;;; -2BBC;OVERLAPPING BLACK SQUARES;So;0;ON;;;;;N;;;;; -2BBD;BALLOT BOX WITH LIGHT X;So;0;ON;;;;;N;;;;; -2BBE;CIRCLED X;So;0;ON;;;;;N;;;;; -2BBF;CIRCLED BOLD X;So;0;ON;;;;;N;;;;; -2BC0;BLACK SQUARE CENTRED;So;0;ON;;;;;N;;;;; -2BC1;BLACK DIAMOND CENTRED;So;0;ON;;;;;N;;;;; -2BC2;TURNED BLACK PENTAGON;So;0;ON;;;;;N;;;;; -2BC3;HORIZONTAL BLACK OCTAGON;So;0;ON;;;;;N;;;;; -2BC4;BLACK OCTAGON;So;0;ON;;;;;N;;;;; -2BC5;BLACK MEDIUM UP-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;; -2BC6;BLACK MEDIUM DOWN-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;; -2BC7;BLACK MEDIUM LEFT-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;; -2BC8;BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;; -2BC9;NEPTUNE FORM TWO;So;0;ON;;;;;N;;;;; -2BCA;TOP HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; -2BCB;BOTTOM HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; -2BCC;LIGHT FOUR POINTED BLACK CUSP;So;0;ON;;;;;N;;;;; -2BCD;ROTATED LIGHT FOUR POINTED BLACK CUSP;So;0;ON;;;;;N;;;;; -2BCE;WHITE FOUR POINTED CUSP;So;0;ON;;;;;N;;;;; -2BCF;ROTATED WHITE FOUR POINTED CUSP;So;0;ON;;;;;N;;;;; -2BD0;SQUARE POSITION INDICATOR;So;0;ON;;;;;N;;;;; -2BD1;UNCERTAINTY SIGN;So;0;ON;;;;;N;;;;; -2BD2;GROUP MARK;So;0;ON;;;;;N;;;;; -2BD3;PLUTO FORM TWO;So;0;ON;;;;;N;;;;; -2BD4;PLUTO FORM THREE;So;0;ON;;;;;N;;;;; -2BD5;PLUTO FORM FOUR;So;0;ON;;;;;N;;;;; -2BD6;PLUTO FORM FIVE;So;0;ON;;;;;N;;;;; -2BD7;TRANSPLUTO;So;0;ON;;;;;N;;;;; -2BD8;PROSERPINA;So;0;ON;;;;;N;;;;; -2BD9;ASTRAEA;So;0;ON;;;;;N;;;;; -2BDA;HYGIEA;So;0;ON;;;;;N;;;;; -2BDB;PHOLUS;So;0;ON;;;;;N;;;;; -2BDC;NESSUS;So;0;ON;;;;;N;;;;; -2BDD;WHITE MOON SELENA;So;0;ON;;;;;N;;;;; -2BDE;BLACK DIAMOND ON CROSS;So;0;ON;;;;;N;;;;; -2BDF;TRUE LIGHT MOON ARTA;So;0;ON;;;;;N;;;;; -2BE0;CUPIDO;So;0;ON;;;;;N;;;;; -2BE1;HADES;So;0;ON;;;;;N;;;;; -2BE2;ZEUS;So;0;ON;;;;;N;;;;; -2BE3;KRONOS;So;0;ON;;;;;N;;;;; -2BE4;APOLLON;So;0;ON;;;;;N;;;;; -2BE5;ADMETOS;So;0;ON;;;;;N;;;;; -2BE6;VULCANUS;So;0;ON;;;;;N;;;;; -2BE7;POSEIDON;So;0;ON;;;;;N;;;;; -2BE8;LEFT HALF BLACK STAR;So;0;ON;;;;;N;;;;; -2BE9;RIGHT HALF BLACK STAR;So;0;ON;;;;;N;;;;; -2BEA;STAR WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;; -2BEB;STAR WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;; -2BEC;LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;; -2BED;UPWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;; -2BEE;RIGHTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;; -2BEF;DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;; -2BF0;ERIS FORM ONE;So;0;ON;;;;;N;;;;; -2BF1;ERIS FORM TWO;So;0;ON;;;;;N;;;;; -2BF2;SEDNA;So;0;ON;;;;;N;;;;; -2BF3;RUSSIAN ASTROLOGICAL SYMBOL VIGINTILE;So;0;ON;;;;;N;;;;; -2BF4;RUSSIAN ASTROLOGICAL SYMBOL NOVILE;So;0;ON;;;;;N;;;;; -2BF5;RUSSIAN ASTROLOGICAL SYMBOL QUINTILE;So;0;ON;;;;;N;;;;; -2BF6;RUSSIAN ASTROLOGICAL SYMBOL BINOVILE;So;0;ON;;;;;N;;;;; -2BF7;RUSSIAN ASTROLOGICAL SYMBOL SENTAGON;So;0;ON;;;;;N;;;;; -2BF8;RUSSIAN ASTROLOGICAL SYMBOL TREDECILE;So;0;ON;;;;;N;;;;; -2BF9;EQUALS SIGN WITH INFINITY BELOW;So;0;ON;;;;;N;;;;; -2BFA;UNITED SYMBOL;So;0;ON;;;;;N;;;;; -2BFB;SEPARATED SYMBOL;So;0;ON;;;;;N;;;;; -2BFC;DOUBLED SYMBOL;So;0;ON;;;;;N;;;;; -2BFD;PASSED SYMBOL;So;0;ON;;;;;N;;;;; -2BFE;REVERSED RIGHT ANGLE;So;0;ON;;;;;Y;;;;; -2BFF;HELLSCHREIBER PAUSE SYMBOL;So;0;ON;;;;;N;;;;; -2C00;GLAGOLITIC CAPITAL LETTER AZU;Lu;0;L;;;;;N;;;;2C30; -2C01;GLAGOLITIC CAPITAL LETTER BUKY;Lu;0;L;;;;;N;;;;2C31; -2C02;GLAGOLITIC CAPITAL LETTER VEDE;Lu;0;L;;;;;N;;;;2C32; -2C03;GLAGOLITIC CAPITAL LETTER GLAGOLI;Lu;0;L;;;;;N;;;;2C33; -2C04;GLAGOLITIC CAPITAL LETTER DOBRO;Lu;0;L;;;;;N;;;;2C34; -2C05;GLAGOLITIC CAPITAL LETTER YESTU;Lu;0;L;;;;;N;;;;2C35; -2C06;GLAGOLITIC CAPITAL LETTER ZHIVETE;Lu;0;L;;;;;N;;;;2C36; -2C07;GLAGOLITIC CAPITAL LETTER DZELO;Lu;0;L;;;;;N;;;;2C37; -2C08;GLAGOLITIC CAPITAL LETTER ZEMLJA;Lu;0;L;;;;;N;;;;2C38; -2C09;GLAGOLITIC CAPITAL LETTER IZHE;Lu;0;L;;;;;N;;;;2C39; -2C0A;GLAGOLITIC CAPITAL LETTER INITIAL IZHE;Lu;0;L;;;;;N;;;;2C3A; -2C0B;GLAGOLITIC CAPITAL LETTER I;Lu;0;L;;;;;N;;;;2C3B; -2C0C;GLAGOLITIC CAPITAL LETTER DJERVI;Lu;0;L;;;;;N;;;;2C3C; -2C0D;GLAGOLITIC CAPITAL LETTER KAKO;Lu;0;L;;;;;N;;;;2C3D; -2C0E;GLAGOLITIC CAPITAL LETTER LJUDIJE;Lu;0;L;;;;;N;;;;2C3E; -2C0F;GLAGOLITIC CAPITAL LETTER MYSLITE;Lu;0;L;;;;;N;;;;2C3F; -2C10;GLAGOLITIC CAPITAL LETTER NASHI;Lu;0;L;;;;;N;;;;2C40; -2C11;GLAGOLITIC CAPITAL LETTER ONU;Lu;0;L;;;;;N;;;;2C41; -2C12;GLAGOLITIC CAPITAL LETTER POKOJI;Lu;0;L;;;;;N;;;;2C42; -2C13;GLAGOLITIC CAPITAL LETTER RITSI;Lu;0;L;;;;;N;;;;2C43; -2C14;GLAGOLITIC CAPITAL LETTER SLOVO;Lu;0;L;;;;;N;;;;2C44; -2C15;GLAGOLITIC CAPITAL LETTER TVRIDO;Lu;0;L;;;;;N;;;;2C45; -2C16;GLAGOLITIC CAPITAL LETTER UKU;Lu;0;L;;;;;N;;;;2C46; -2C17;GLAGOLITIC CAPITAL LETTER FRITU;Lu;0;L;;;;;N;;;;2C47; -2C18;GLAGOLITIC CAPITAL LETTER HERU;Lu;0;L;;;;;N;;;;2C48; -2C19;GLAGOLITIC CAPITAL LETTER OTU;Lu;0;L;;;;;N;;;;2C49; -2C1A;GLAGOLITIC CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;2C4A; -2C1B;GLAGOLITIC CAPITAL LETTER SHTA;Lu;0;L;;;;;N;;;;2C4B; -2C1C;GLAGOLITIC CAPITAL LETTER TSI;Lu;0;L;;;;;N;;;;2C4C; -2C1D;GLAGOLITIC CAPITAL LETTER CHRIVI;Lu;0;L;;;;;N;;;;2C4D; -2C1E;GLAGOLITIC CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;2C4E; -2C1F;GLAGOLITIC CAPITAL LETTER YERU;Lu;0;L;;;;;N;;;;2C4F; -2C20;GLAGOLITIC CAPITAL LETTER YERI;Lu;0;L;;;;;N;;;;2C50; -2C21;GLAGOLITIC CAPITAL LETTER YATI;Lu;0;L;;;;;N;;;;2C51; -2C22;GLAGOLITIC CAPITAL LETTER SPIDERY HA;Lu;0;L;;;;;N;;;;2C52; -2C23;GLAGOLITIC CAPITAL LETTER YU;Lu;0;L;;;;;N;;;;2C53; -2C24;GLAGOLITIC CAPITAL LETTER SMALL YUS;Lu;0;L;;;;;N;;;;2C54; -2C25;GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL;Lu;0;L;;;;;N;;;;2C55; -2C26;GLAGOLITIC CAPITAL LETTER YO;Lu;0;L;;;;;N;;;;2C56; -2C27;GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS;Lu;0;L;;;;;N;;;;2C57; -2C28;GLAGOLITIC CAPITAL LETTER BIG YUS;Lu;0;L;;;;;N;;;;2C58; -2C29;GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS;Lu;0;L;;;;;N;;;;2C59; -2C2A;GLAGOLITIC CAPITAL LETTER FITA;Lu;0;L;;;;;N;;;;2C5A; -2C2B;GLAGOLITIC CAPITAL LETTER IZHITSA;Lu;0;L;;;;;N;;;;2C5B; -2C2C;GLAGOLITIC CAPITAL LETTER SHTAPIC;Lu;0;L;;;;;N;;;;2C5C; -2C2D;GLAGOLITIC CAPITAL LETTER TROKUTASTI A;Lu;0;L;;;;;N;;;;2C5D; -2C2E;GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE;Lu;0;L;;;;;N;;;;2C5E; -2C2F;GLAGOLITIC CAPITAL LETTER CAUDATE CHRIVI;Lu;0;L;;;;;N;;;;2C5F; -2C30;GLAGOLITIC SMALL LETTER AZU;Ll;0;L;;;;;N;;;2C00;;2C00 -2C31;GLAGOLITIC SMALL LETTER BUKY;Ll;0;L;;;;;N;;;2C01;;2C01 -2C32;GLAGOLITIC SMALL LETTER VEDE;Ll;0;L;;;;;N;;;2C02;;2C02 -2C33;GLAGOLITIC SMALL LETTER GLAGOLI;Ll;0;L;;;;;N;;;2C03;;2C03 -2C34;GLAGOLITIC SMALL LETTER DOBRO;Ll;0;L;;;;;N;;;2C04;;2C04 -2C35;GLAGOLITIC SMALL LETTER YESTU;Ll;0;L;;;;;N;;;2C05;;2C05 -2C36;GLAGOLITIC SMALL LETTER ZHIVETE;Ll;0;L;;;;;N;;;2C06;;2C06 -2C37;GLAGOLITIC SMALL LETTER DZELO;Ll;0;L;;;;;N;;;2C07;;2C07 -2C38;GLAGOLITIC SMALL LETTER ZEMLJA;Ll;0;L;;;;;N;;;2C08;;2C08 -2C39;GLAGOLITIC SMALL LETTER IZHE;Ll;0;L;;;;;N;;;2C09;;2C09 -2C3A;GLAGOLITIC SMALL LETTER INITIAL IZHE;Ll;0;L;;;;;N;;;2C0A;;2C0A -2C3B;GLAGOLITIC SMALL LETTER I;Ll;0;L;;;;;N;;;2C0B;;2C0B -2C3C;GLAGOLITIC SMALL LETTER DJERVI;Ll;0;L;;;;;N;;;2C0C;;2C0C -2C3D;GLAGOLITIC SMALL LETTER KAKO;Ll;0;L;;;;;N;;;2C0D;;2C0D -2C3E;GLAGOLITIC SMALL LETTER LJUDIJE;Ll;0;L;;;;;N;;;2C0E;;2C0E -2C3F;GLAGOLITIC SMALL LETTER MYSLITE;Ll;0;L;;;;;N;;;2C0F;;2C0F -2C40;GLAGOLITIC SMALL LETTER NASHI;Ll;0;L;;;;;N;;;2C10;;2C10 -2C41;GLAGOLITIC SMALL LETTER ONU;Ll;0;L;;;;;N;;;2C11;;2C11 -2C42;GLAGOLITIC SMALL LETTER POKOJI;Ll;0;L;;;;;N;;;2C12;;2C12 -2C43;GLAGOLITIC SMALL LETTER RITSI;Ll;0;L;;;;;N;;;2C13;;2C13 -2C44;GLAGOLITIC SMALL LETTER SLOVO;Ll;0;L;;;;;N;;;2C14;;2C14 -2C45;GLAGOLITIC SMALL LETTER TVRIDO;Ll;0;L;;;;;N;;;2C15;;2C15 -2C46;GLAGOLITIC SMALL LETTER UKU;Ll;0;L;;;;;N;;;2C16;;2C16 -2C47;GLAGOLITIC SMALL LETTER FRITU;Ll;0;L;;;;;N;;;2C17;;2C17 -2C48;GLAGOLITIC SMALL LETTER HERU;Ll;0;L;;;;;N;;;2C18;;2C18 -2C49;GLAGOLITIC SMALL LETTER OTU;Ll;0;L;;;;;N;;;2C19;;2C19 -2C4A;GLAGOLITIC SMALL LETTER PE;Ll;0;L;;;;;N;;;2C1A;;2C1A -2C4B;GLAGOLITIC SMALL LETTER SHTA;Ll;0;L;;;;;N;;;2C1B;;2C1B -2C4C;GLAGOLITIC SMALL LETTER TSI;Ll;0;L;;;;;N;;;2C1C;;2C1C -2C4D;GLAGOLITIC SMALL LETTER CHRIVI;Ll;0;L;;;;;N;;;2C1D;;2C1D -2C4E;GLAGOLITIC SMALL LETTER SHA;Ll;0;L;;;;;N;;;2C1E;;2C1E -2C4F;GLAGOLITIC SMALL LETTER YERU;Ll;0;L;;;;;N;;;2C1F;;2C1F -2C50;GLAGOLITIC SMALL LETTER YERI;Ll;0;L;;;;;N;;;2C20;;2C20 -2C51;GLAGOLITIC SMALL LETTER YATI;Ll;0;L;;;;;N;;;2C21;;2C21 -2C52;GLAGOLITIC SMALL LETTER SPIDERY HA;Ll;0;L;;;;;N;;;2C22;;2C22 -2C53;GLAGOLITIC SMALL LETTER YU;Ll;0;L;;;;;N;;;2C23;;2C23 -2C54;GLAGOLITIC SMALL LETTER SMALL YUS;Ll;0;L;;;;;N;;;2C24;;2C24 -2C55;GLAGOLITIC SMALL LETTER SMALL YUS WITH TAIL;Ll;0;L;;;;;N;;;2C25;;2C25 -2C56;GLAGOLITIC SMALL LETTER YO;Ll;0;L;;;;;N;;;2C26;;2C26 -2C57;GLAGOLITIC SMALL LETTER IOTATED SMALL YUS;Ll;0;L;;;;;N;;;2C27;;2C27 -2C58;GLAGOLITIC SMALL LETTER BIG YUS;Ll;0;L;;;;;N;;;2C28;;2C28 -2C59;GLAGOLITIC SMALL LETTER IOTATED BIG YUS;Ll;0;L;;;;;N;;;2C29;;2C29 -2C5A;GLAGOLITIC SMALL LETTER FITA;Ll;0;L;;;;;N;;;2C2A;;2C2A -2C5B;GLAGOLITIC SMALL LETTER IZHITSA;Ll;0;L;;;;;N;;;2C2B;;2C2B -2C5C;GLAGOLITIC SMALL LETTER SHTAPIC;Ll;0;L;;;;;N;;;2C2C;;2C2C -2C5D;GLAGOLITIC SMALL LETTER TROKUTASTI A;Ll;0;L;;;;;N;;;2C2D;;2C2D -2C5E;GLAGOLITIC SMALL LETTER LATINATE MYSLITE;Ll;0;L;;;;;N;;;2C2E;;2C2E -2C5F;GLAGOLITIC SMALL LETTER CAUDATE CHRIVI;Ll;0;L;;;;;N;;;2C2F;;2C2F -2C60;LATIN CAPITAL LETTER L WITH DOUBLE BAR;Lu;0;L;;;;;N;;;;2C61; -2C61;LATIN SMALL LETTER L WITH DOUBLE BAR;Ll;0;L;;;;;N;;;2C60;;2C60 -2C62;LATIN CAPITAL LETTER L WITH MIDDLE TILDE;Lu;0;L;;;;;N;;;;026B; -2C63;LATIN CAPITAL LETTER P WITH STROKE;Lu;0;L;;;;;N;;;;1D7D; -2C64;LATIN CAPITAL LETTER R WITH TAIL;Lu;0;L;;;;;N;;;;027D; -2C65;LATIN SMALL LETTER A WITH STROKE;Ll;0;L;;;;;N;;;023A;;023A -2C66;LATIN SMALL LETTER T WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;023E;;023E -2C67;LATIN CAPITAL LETTER H WITH DESCENDER;Lu;0;L;;;;;N;;;;2C68; -2C68;LATIN SMALL LETTER H WITH DESCENDER;Ll;0;L;;;;;N;;;2C67;;2C67 -2C69;LATIN CAPITAL LETTER K WITH DESCENDER;Lu;0;L;;;;;N;;;;2C6A; -2C6A;LATIN SMALL LETTER K WITH DESCENDER;Ll;0;L;;;;;N;;;2C69;;2C69 -2C6B;LATIN CAPITAL LETTER Z WITH DESCENDER;Lu;0;L;;;;;N;;;;2C6C; -2C6C;LATIN SMALL LETTER Z WITH DESCENDER;Ll;0;L;;;;;N;;;2C6B;;2C6B -2C6D;LATIN CAPITAL LETTER ALPHA;Lu;0;L;;;;;N;;;;0251; -2C6E;LATIN CAPITAL LETTER M WITH HOOK;Lu;0;L;;;;;N;;;;0271; -2C6F;LATIN CAPITAL LETTER TURNED A;Lu;0;L;;;;;N;;;;0250; -2C70;LATIN CAPITAL LETTER TURNED ALPHA;Lu;0;L;;;;;N;;;;0252; -2C71;LATIN SMALL LETTER V WITH RIGHT HOOK;Ll;0;L;;;;;N;;;;; -2C72;LATIN CAPITAL LETTER W WITH HOOK;Lu;0;L;;;;;N;;;;2C73; -2C73;LATIN SMALL LETTER W WITH HOOK;Ll;0;L;;;;;N;;;2C72;;2C72 -2C74;LATIN SMALL LETTER V WITH CURL;Ll;0;L;;;;;N;;;;; -2C75;LATIN CAPITAL LETTER HALF H;Lu;0;L;;;;;N;;;;2C76; -2C76;LATIN SMALL LETTER HALF H;Ll;0;L;;;;;N;;;2C75;;2C75 -2C77;LATIN SMALL LETTER TAILLESS PHI;Ll;0;L;;;;;N;;;;; -2C78;LATIN SMALL LETTER E WITH NOTCH;Ll;0;L;;;;;N;;;;; -2C79;LATIN SMALL LETTER TURNED R WITH TAIL;Ll;0;L;;;;;N;;;;; -2C7A;LATIN SMALL LETTER O WITH LOW RING INSIDE;Ll;0;L;;;;;N;;;;; -2C7B;LATIN LETTER SMALL CAPITAL TURNED E;Ll;0;L;;;;;N;;;;; -2C7C;LATIN SUBSCRIPT SMALL LETTER J;Lm;0;L;<sub> 006A;;;;N;;;;; -2C7D;MODIFIER LETTER CAPITAL V;Lm;0;L;<super> 0056;;;;N;;;;; -2C7E;LATIN CAPITAL LETTER S WITH SWASH TAIL;Lu;0;L;;;;;N;;;;023F; -2C7F;LATIN CAPITAL LETTER Z WITH SWASH TAIL;Lu;0;L;;;;;N;;;;0240; -2C80;COPTIC CAPITAL LETTER ALFA;Lu;0;L;;;;;N;;;;2C81; -2C81;COPTIC SMALL LETTER ALFA;Ll;0;L;;;;;N;;;2C80;;2C80 -2C82;COPTIC CAPITAL LETTER VIDA;Lu;0;L;;;;;N;;;;2C83; -2C83;COPTIC SMALL LETTER VIDA;Ll;0;L;;;;;N;;;2C82;;2C82 -2C84;COPTIC CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;2C85; -2C85;COPTIC SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;2C84;;2C84 -2C86;COPTIC CAPITAL LETTER DALDA;Lu;0;L;;;;;N;;;;2C87; -2C87;COPTIC SMALL LETTER DALDA;Ll;0;L;;;;;N;;;2C86;;2C86 -2C88;COPTIC CAPITAL LETTER EIE;Lu;0;L;;;;;N;;;;2C89; -2C89;COPTIC SMALL LETTER EIE;Ll;0;L;;;;;N;;;2C88;;2C88 -2C8A;COPTIC CAPITAL LETTER SOU;Lu;0;L;;;;;N;;;;2C8B; -2C8B;COPTIC SMALL LETTER SOU;Ll;0;L;;;;;N;;;2C8A;;2C8A -2C8C;COPTIC CAPITAL LETTER ZATA;Lu;0;L;;;;;N;;;;2C8D; -2C8D;COPTIC SMALL LETTER ZATA;Ll;0;L;;;;;N;;;2C8C;;2C8C -2C8E;COPTIC CAPITAL LETTER HATE;Lu;0;L;;;;;N;;;;2C8F; -2C8F;COPTIC SMALL LETTER HATE;Ll;0;L;;;;;N;;;2C8E;;2C8E -2C90;COPTIC CAPITAL LETTER THETHE;Lu;0;L;;;;;N;;;;2C91; -2C91;COPTIC SMALL LETTER THETHE;Ll;0;L;;;;;N;;;2C90;;2C90 -2C92;COPTIC CAPITAL LETTER IAUDA;Lu;0;L;;;;;N;;;;2C93; -2C93;COPTIC SMALL LETTER IAUDA;Ll;0;L;;;;;N;;;2C92;;2C92 -2C94;COPTIC CAPITAL LETTER KAPA;Lu;0;L;;;;;N;;;;2C95; -2C95;COPTIC SMALL LETTER KAPA;Ll;0;L;;;;;N;;;2C94;;2C94 -2C96;COPTIC CAPITAL LETTER LAULA;Lu;0;L;;;;;N;;;;2C97; -2C97;COPTIC SMALL LETTER LAULA;Ll;0;L;;;;;N;;;2C96;;2C96 -2C98;COPTIC CAPITAL LETTER MI;Lu;0;L;;;;;N;;;;2C99; -2C99;COPTIC SMALL LETTER MI;Ll;0;L;;;;;N;;;2C98;;2C98 -2C9A;COPTIC CAPITAL LETTER NI;Lu;0;L;;;;;N;;;;2C9B; -2C9B;COPTIC SMALL LETTER NI;Ll;0;L;;;;;N;;;2C9A;;2C9A -2C9C;COPTIC CAPITAL LETTER KSI;Lu;0;L;;;;;N;;;;2C9D; -2C9D;COPTIC SMALL LETTER KSI;Ll;0;L;;;;;N;;;2C9C;;2C9C -2C9E;COPTIC CAPITAL LETTER O;Lu;0;L;;;;;N;;;;2C9F; -2C9F;COPTIC SMALL LETTER O;Ll;0;L;;;;;N;;;2C9E;;2C9E -2CA0;COPTIC CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;2CA1; -2CA1;COPTIC SMALL LETTER PI;Ll;0;L;;;;;N;;;2CA0;;2CA0 -2CA2;COPTIC CAPITAL LETTER RO;Lu;0;L;;;;;N;;;;2CA3; -2CA3;COPTIC SMALL LETTER RO;Ll;0;L;;;;;N;;;2CA2;;2CA2 -2CA4;COPTIC CAPITAL LETTER SIMA;Lu;0;L;;;;;N;;;;2CA5; -2CA5;COPTIC SMALL LETTER SIMA;Ll;0;L;;;;;N;;;2CA4;;2CA4 -2CA6;COPTIC CAPITAL LETTER TAU;Lu;0;L;;;;;N;;;;2CA7; -2CA7;COPTIC SMALL LETTER TAU;Ll;0;L;;;;;N;;;2CA6;;2CA6 -2CA8;COPTIC CAPITAL LETTER UA;Lu;0;L;;;;;N;;;;2CA9; -2CA9;COPTIC SMALL LETTER UA;Ll;0;L;;;;;N;;;2CA8;;2CA8 -2CAA;COPTIC CAPITAL LETTER FI;Lu;0;L;;;;;N;;;;2CAB; -2CAB;COPTIC SMALL LETTER FI;Ll;0;L;;;;;N;;;2CAA;;2CAA -2CAC;COPTIC CAPITAL LETTER KHI;Lu;0;L;;;;;N;;;;2CAD; -2CAD;COPTIC SMALL LETTER KHI;Ll;0;L;;;;;N;;;2CAC;;2CAC -2CAE;COPTIC CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;2CAF; -2CAF;COPTIC SMALL LETTER PSI;Ll;0;L;;;;;N;;;2CAE;;2CAE -2CB0;COPTIC CAPITAL LETTER OOU;Lu;0;L;;;;;N;;;;2CB1; -2CB1;COPTIC SMALL LETTER OOU;Ll;0;L;;;;;N;;;2CB0;;2CB0 -2CB2;COPTIC CAPITAL LETTER DIALECT-P ALEF;Lu;0;L;;;;;N;;;;2CB3; -2CB3;COPTIC SMALL LETTER DIALECT-P ALEF;Ll;0;L;;;;;N;;;2CB2;;2CB2 -2CB4;COPTIC CAPITAL LETTER OLD COPTIC AIN;Lu;0;L;;;;;N;;;;2CB5; -2CB5;COPTIC SMALL LETTER OLD COPTIC AIN;Ll;0;L;;;;;N;;;2CB4;;2CB4 -2CB6;COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE;Lu;0;L;;;;;N;;;;2CB7; -2CB7;COPTIC SMALL LETTER CRYPTOGRAMMIC EIE;Ll;0;L;;;;;N;;;2CB6;;2CB6 -2CB8;COPTIC CAPITAL LETTER DIALECT-P KAPA;Lu;0;L;;;;;N;;;;2CB9; -2CB9;COPTIC SMALL LETTER DIALECT-P KAPA;Ll;0;L;;;;;N;;;2CB8;;2CB8 -2CBA;COPTIC CAPITAL LETTER DIALECT-P NI;Lu;0;L;;;;;N;;;;2CBB; -2CBB;COPTIC SMALL LETTER DIALECT-P NI;Ll;0;L;;;;;N;;;2CBA;;2CBA -2CBC;COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI;Lu;0;L;;;;;N;;;;2CBD; -2CBD;COPTIC SMALL LETTER CRYPTOGRAMMIC NI;Ll;0;L;;;;;N;;;2CBC;;2CBC -2CBE;COPTIC CAPITAL LETTER OLD COPTIC OOU;Lu;0;L;;;;;N;;;;2CBF; -2CBF;COPTIC SMALL LETTER OLD COPTIC OOU;Ll;0;L;;;;;N;;;2CBE;;2CBE -2CC0;COPTIC CAPITAL LETTER SAMPI;Lu;0;L;;;;;N;;;;2CC1; -2CC1;COPTIC SMALL LETTER SAMPI;Ll;0;L;;;;;N;;;2CC0;;2CC0 -2CC2;COPTIC CAPITAL LETTER CROSSED SHEI;Lu;0;L;;;;;N;;;;2CC3; -2CC3;COPTIC SMALL LETTER CROSSED SHEI;Ll;0;L;;;;;N;;;2CC2;;2CC2 -2CC4;COPTIC CAPITAL LETTER OLD COPTIC SHEI;Lu;0;L;;;;;N;;;;2CC5; -2CC5;COPTIC SMALL LETTER OLD COPTIC SHEI;Ll;0;L;;;;;N;;;2CC4;;2CC4 -2CC6;COPTIC CAPITAL LETTER OLD COPTIC ESH;Lu;0;L;;;;;N;;;;2CC7; -2CC7;COPTIC SMALL LETTER OLD COPTIC ESH;Ll;0;L;;;;;N;;;2CC6;;2CC6 -2CC8;COPTIC CAPITAL LETTER AKHMIMIC KHEI;Lu;0;L;;;;;N;;;;2CC9; -2CC9;COPTIC SMALL LETTER AKHMIMIC KHEI;Ll;0;L;;;;;N;;;2CC8;;2CC8 -2CCA;COPTIC CAPITAL LETTER DIALECT-P HORI;Lu;0;L;;;;;N;;;;2CCB; -2CCB;COPTIC SMALL LETTER DIALECT-P HORI;Ll;0;L;;;;;N;;;2CCA;;2CCA -2CCC;COPTIC CAPITAL LETTER OLD COPTIC HORI;Lu;0;L;;;;;N;;;;2CCD; -2CCD;COPTIC SMALL LETTER OLD COPTIC HORI;Ll;0;L;;;;;N;;;2CCC;;2CCC -2CCE;COPTIC CAPITAL LETTER OLD COPTIC HA;Lu;0;L;;;;;N;;;;2CCF; -2CCF;COPTIC SMALL LETTER OLD COPTIC HA;Ll;0;L;;;;;N;;;2CCE;;2CCE -2CD0;COPTIC CAPITAL LETTER L-SHAPED HA;Lu;0;L;;;;;N;;;;2CD1; -2CD1;COPTIC SMALL LETTER L-SHAPED HA;Ll;0;L;;;;;N;;;2CD0;;2CD0 -2CD2;COPTIC CAPITAL LETTER OLD COPTIC HEI;Lu;0;L;;;;;N;;;;2CD3; -2CD3;COPTIC SMALL LETTER OLD COPTIC HEI;Ll;0;L;;;;;N;;;2CD2;;2CD2 -2CD4;COPTIC CAPITAL LETTER OLD COPTIC HAT;Lu;0;L;;;;;N;;;;2CD5; -2CD5;COPTIC SMALL LETTER OLD COPTIC HAT;Ll;0;L;;;;;N;;;2CD4;;2CD4 -2CD6;COPTIC CAPITAL LETTER OLD COPTIC GANGIA;Lu;0;L;;;;;N;;;;2CD7; -2CD7;COPTIC SMALL LETTER OLD COPTIC GANGIA;Ll;0;L;;;;;N;;;2CD6;;2CD6 -2CD8;COPTIC CAPITAL LETTER OLD COPTIC DJA;Lu;0;L;;;;;N;;;;2CD9; -2CD9;COPTIC SMALL LETTER OLD COPTIC DJA;Ll;0;L;;;;;N;;;2CD8;;2CD8 -2CDA;COPTIC CAPITAL LETTER OLD COPTIC SHIMA;Lu;0;L;;;;;N;;;;2CDB; -2CDB;COPTIC SMALL LETTER OLD COPTIC SHIMA;Ll;0;L;;;;;N;;;2CDA;;2CDA -2CDC;COPTIC CAPITAL LETTER OLD NUBIAN SHIMA;Lu;0;L;;;;;N;;;;2CDD; -2CDD;COPTIC SMALL LETTER OLD NUBIAN SHIMA;Ll;0;L;;;;;N;;;2CDC;;2CDC -2CDE;COPTIC CAPITAL LETTER OLD NUBIAN NGI;Lu;0;L;;;;;N;;;;2CDF; -2CDF;COPTIC SMALL LETTER OLD NUBIAN NGI;Ll;0;L;;;;;N;;;2CDE;;2CDE -2CE0;COPTIC CAPITAL LETTER OLD NUBIAN NYI;Lu;0;L;;;;;N;;;;2CE1; -2CE1;COPTIC SMALL LETTER OLD NUBIAN NYI;Ll;0;L;;;;;N;;;2CE0;;2CE0 -2CE2;COPTIC CAPITAL LETTER OLD NUBIAN WAU;Lu;0;L;;;;;N;;;;2CE3; -2CE3;COPTIC SMALL LETTER OLD NUBIAN WAU;Ll;0;L;;;;;N;;;2CE2;;2CE2 -2CE4;COPTIC SYMBOL KAI;Ll;0;L;;;;;N;;;;; -2CE5;COPTIC SYMBOL MI RO;So;0;ON;;;;;N;;;;; -2CE6;COPTIC SYMBOL PI RO;So;0;ON;;;;;N;;;;; -2CE7;COPTIC SYMBOL STAUROS;So;0;ON;;;;;N;;;;; -2CE8;COPTIC SYMBOL TAU RO;So;0;ON;;;;;N;;;;; -2CE9;COPTIC SYMBOL KHI RO;So;0;ON;;;;;N;;;;; -2CEA;COPTIC SYMBOL SHIMA SIMA;So;0;ON;;;;;N;;;;; -2CEB;COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI;Lu;0;L;;;;;N;;;;2CEC; -2CEC;COPTIC SMALL LETTER CRYPTOGRAMMIC SHEI;Ll;0;L;;;;;N;;;2CEB;;2CEB -2CED;COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA;Lu;0;L;;;;;N;;;;2CEE; -2CEE;COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA;Ll;0;L;;;;;N;;;2CED;;2CED -2CEF;COPTIC COMBINING NI ABOVE;Mn;230;NSM;;;;;N;;;;; -2CF0;COPTIC COMBINING SPIRITUS ASPER;Mn;230;NSM;;;;;N;;;;; -2CF1;COPTIC COMBINING SPIRITUS LENIS;Mn;230;NSM;;;;;N;;;;; -2CF2;COPTIC CAPITAL LETTER BOHAIRIC KHEI;Lu;0;L;;;;;N;;;;2CF3; -2CF3;COPTIC SMALL LETTER BOHAIRIC KHEI;Ll;0;L;;;;;N;;;2CF2;;2CF2 -2CF9;COPTIC OLD NUBIAN FULL STOP;Po;0;ON;;;;;N;;;;; -2CFA;COPTIC OLD NUBIAN DIRECT QUESTION MARK;Po;0;ON;;;;;N;;;;; -2CFB;COPTIC OLD NUBIAN INDIRECT QUESTION MARK;Po;0;ON;;;;;N;;;;; -2CFC;COPTIC OLD NUBIAN VERSE DIVIDER;Po;0;ON;;;;;N;;;;; -2CFD;COPTIC FRACTION ONE HALF;No;0;ON;;;;1/2;N;;;;; -2CFE;COPTIC FULL STOP;Po;0;ON;;;;;N;;;;; -2CFF;COPTIC MORPHOLOGICAL DIVIDER;Po;0;ON;;;;;N;;;;; -2D00;GEORGIAN SMALL LETTER AN;Ll;0;L;;;;;N;;;10A0;;10A0 -2D01;GEORGIAN SMALL LETTER BAN;Ll;0;L;;;;;N;;;10A1;;10A1 -2D02;GEORGIAN SMALL LETTER GAN;Ll;0;L;;;;;N;;;10A2;;10A2 -2D03;GEORGIAN SMALL LETTER DON;Ll;0;L;;;;;N;;;10A3;;10A3 -2D04;GEORGIAN SMALL LETTER EN;Ll;0;L;;;;;N;;;10A4;;10A4 -2D05;GEORGIAN SMALL LETTER VIN;Ll;0;L;;;;;N;;;10A5;;10A5 -2D06;GEORGIAN SMALL LETTER ZEN;Ll;0;L;;;;;N;;;10A6;;10A6 -2D07;GEORGIAN SMALL LETTER TAN;Ll;0;L;;;;;N;;;10A7;;10A7 -2D08;GEORGIAN SMALL LETTER IN;Ll;0;L;;;;;N;;;10A8;;10A8 -2D09;GEORGIAN SMALL LETTER KAN;Ll;0;L;;;;;N;;;10A9;;10A9 -2D0A;GEORGIAN SMALL LETTER LAS;Ll;0;L;;;;;N;;;10AA;;10AA -2D0B;GEORGIAN SMALL LETTER MAN;Ll;0;L;;;;;N;;;10AB;;10AB -2D0C;GEORGIAN SMALL LETTER NAR;Ll;0;L;;;;;N;;;10AC;;10AC -2D0D;GEORGIAN SMALL LETTER ON;Ll;0;L;;;;;N;;;10AD;;10AD -2D0E;GEORGIAN SMALL LETTER PAR;Ll;0;L;;;;;N;;;10AE;;10AE -2D0F;GEORGIAN SMALL LETTER ZHAR;Ll;0;L;;;;;N;;;10AF;;10AF -2D10;GEORGIAN SMALL LETTER RAE;Ll;0;L;;;;;N;;;10B0;;10B0 -2D11;GEORGIAN SMALL LETTER SAN;Ll;0;L;;;;;N;;;10B1;;10B1 -2D12;GEORGIAN SMALL LETTER TAR;Ll;0;L;;;;;N;;;10B2;;10B2 -2D13;GEORGIAN SMALL LETTER UN;Ll;0;L;;;;;N;;;10B3;;10B3 -2D14;GEORGIAN SMALL LETTER PHAR;Ll;0;L;;;;;N;;;10B4;;10B4 -2D15;GEORGIAN SMALL LETTER KHAR;Ll;0;L;;;;;N;;;10B5;;10B5 -2D16;GEORGIAN SMALL LETTER GHAN;Ll;0;L;;;;;N;;;10B6;;10B6 -2D17;GEORGIAN SMALL LETTER QAR;Ll;0;L;;;;;N;;;10B7;;10B7 -2D18;GEORGIAN SMALL LETTER SHIN;Ll;0;L;;;;;N;;;10B8;;10B8 -2D19;GEORGIAN SMALL LETTER CHIN;Ll;0;L;;;;;N;;;10B9;;10B9 -2D1A;GEORGIAN SMALL LETTER CAN;Ll;0;L;;;;;N;;;10BA;;10BA -2D1B;GEORGIAN SMALL LETTER JIL;Ll;0;L;;;;;N;;;10BB;;10BB -2D1C;GEORGIAN SMALL LETTER CIL;Ll;0;L;;;;;N;;;10BC;;10BC -2D1D;GEORGIAN SMALL LETTER CHAR;Ll;0;L;;;;;N;;;10BD;;10BD -2D1E;GEORGIAN SMALL LETTER XAN;Ll;0;L;;;;;N;;;10BE;;10BE -2D1F;GEORGIAN SMALL LETTER JHAN;Ll;0;L;;;;;N;;;10BF;;10BF -2D20;GEORGIAN SMALL LETTER HAE;Ll;0;L;;;;;N;;;10C0;;10C0 -2D21;GEORGIAN SMALL LETTER HE;Ll;0;L;;;;;N;;;10C1;;10C1 -2D22;GEORGIAN SMALL LETTER HIE;Ll;0;L;;;;;N;;;10C2;;10C2 -2D23;GEORGIAN SMALL LETTER WE;Ll;0;L;;;;;N;;;10C3;;10C3 -2D24;GEORGIAN SMALL LETTER HAR;Ll;0;L;;;;;N;;;10C4;;10C4 -2D25;GEORGIAN SMALL LETTER HOE;Ll;0;L;;;;;N;;;10C5;;10C5 -2D27;GEORGIAN SMALL LETTER YN;Ll;0;L;;;;;N;;;10C7;;10C7 -2D2D;GEORGIAN SMALL LETTER AEN;Ll;0;L;;;;;N;;;10CD;;10CD -2D30;TIFINAGH LETTER YA;Lo;0;L;;;;;N;;;;; -2D31;TIFINAGH LETTER YAB;Lo;0;L;;;;;N;;;;; -2D32;TIFINAGH LETTER YABH;Lo;0;L;;;;;N;;;;; -2D33;TIFINAGH LETTER YAG;Lo;0;L;;;;;N;;;;; -2D34;TIFINAGH LETTER YAGHH;Lo;0;L;;;;;N;;;;; -2D35;TIFINAGH LETTER BERBER ACADEMY YAJ;Lo;0;L;;;;;N;;;;; -2D36;TIFINAGH LETTER YAJ;Lo;0;L;;;;;N;;;;; -2D37;TIFINAGH LETTER YAD;Lo;0;L;;;;;N;;;;; -2D38;TIFINAGH LETTER YADH;Lo;0;L;;;;;N;;;;; -2D39;TIFINAGH LETTER YADD;Lo;0;L;;;;;N;;;;; -2D3A;TIFINAGH LETTER YADDH;Lo;0;L;;;;;N;;;;; -2D3B;TIFINAGH LETTER YEY;Lo;0;L;;;;;N;;;;; -2D3C;TIFINAGH LETTER YAF;Lo;0;L;;;;;N;;;;; -2D3D;TIFINAGH LETTER YAK;Lo;0;L;;;;;N;;;;; -2D3E;TIFINAGH LETTER TUAREG YAK;Lo;0;L;;;;;N;;;;; -2D3F;TIFINAGH LETTER YAKHH;Lo;0;L;;;;;N;;;;; -2D40;TIFINAGH LETTER YAH;Lo;0;L;;;;;N;;;;; -2D41;TIFINAGH LETTER BERBER ACADEMY YAH;Lo;0;L;;;;;N;;;;; -2D42;TIFINAGH LETTER TUAREG YAH;Lo;0;L;;;;;N;;;;; -2D43;TIFINAGH LETTER YAHH;Lo;0;L;;;;;N;;;;; -2D44;TIFINAGH LETTER YAA;Lo;0;L;;;;;N;;;;; -2D45;TIFINAGH LETTER YAKH;Lo;0;L;;;;;N;;;;; -2D46;TIFINAGH LETTER TUAREG YAKH;Lo;0;L;;;;;N;;;;; -2D47;TIFINAGH LETTER YAQ;Lo;0;L;;;;;N;;;;; -2D48;TIFINAGH LETTER TUAREG YAQ;Lo;0;L;;;;;N;;;;; -2D49;TIFINAGH LETTER YI;Lo;0;L;;;;;N;;;;; -2D4A;TIFINAGH LETTER YAZH;Lo;0;L;;;;;N;;;;; -2D4B;TIFINAGH LETTER AHAGGAR YAZH;Lo;0;L;;;;;N;;;;; -2D4C;TIFINAGH LETTER TUAREG YAZH;Lo;0;L;;;;;N;;;;; -2D4D;TIFINAGH LETTER YAL;Lo;0;L;;;;;N;;;;; -2D4E;TIFINAGH LETTER YAM;Lo;0;L;;;;;N;;;;; -2D4F;TIFINAGH LETTER YAN;Lo;0;L;;;;;N;;;;; -2D50;TIFINAGH LETTER TUAREG YAGN;Lo;0;L;;;;;N;;;;; -2D51;TIFINAGH LETTER TUAREG YANG;Lo;0;L;;;;;N;;;;; -2D52;TIFINAGH LETTER YAP;Lo;0;L;;;;;N;;;;; -2D53;TIFINAGH LETTER YU;Lo;0;L;;;;;N;;;;; -2D54;TIFINAGH LETTER YAR;Lo;0;L;;;;;N;;;;; -2D55;TIFINAGH LETTER YARR;Lo;0;L;;;;;N;;;;; -2D56;TIFINAGH LETTER YAGH;Lo;0;L;;;;;N;;;;; -2D57;TIFINAGH LETTER TUAREG YAGH;Lo;0;L;;;;;N;;;;; -2D58;TIFINAGH LETTER AYER YAGH;Lo;0;L;;;;;N;;;;; -2D59;TIFINAGH LETTER YAS;Lo;0;L;;;;;N;;;;; -2D5A;TIFINAGH LETTER YASS;Lo;0;L;;;;;N;;;;; -2D5B;TIFINAGH LETTER YASH;Lo;0;L;;;;;N;;;;; -2D5C;TIFINAGH LETTER YAT;Lo;0;L;;;;;N;;;;; -2D5D;TIFINAGH LETTER YATH;Lo;0;L;;;;;N;;;;; -2D5E;TIFINAGH LETTER YACH;Lo;0;L;;;;;N;;;;; -2D5F;TIFINAGH LETTER YATT;Lo;0;L;;;;;N;;;;; -2D60;TIFINAGH LETTER YAV;Lo;0;L;;;;;N;;;;; -2D61;TIFINAGH LETTER YAW;Lo;0;L;;;;;N;;;;; -2D62;TIFINAGH LETTER YAY;Lo;0;L;;;;;N;;;;; -2D63;TIFINAGH LETTER YAZ;Lo;0;L;;;;;N;;;;; -2D64;TIFINAGH LETTER TAWELLEMET YAZ;Lo;0;L;;;;;N;;;;; -2D65;TIFINAGH LETTER YAZZ;Lo;0;L;;;;;N;;;;; -2D66;TIFINAGH LETTER YE;Lo;0;L;;;;;N;;;;; -2D67;TIFINAGH LETTER YO;Lo;0;L;;;;;N;;;;; -2D6F;TIFINAGH MODIFIER LETTER LABIALIZATION MARK;Lm;0;L;<super> 2D61;;;;N;;;;; -2D70;TIFINAGH SEPARATOR MARK;Po;0;L;;;;;N;;;;; -2D7F;TIFINAGH CONSONANT JOINER;Mn;9;NSM;;;;;N;;;;; -2D80;ETHIOPIC SYLLABLE LOA;Lo;0;L;;;;;N;;;;; -2D81;ETHIOPIC SYLLABLE MOA;Lo;0;L;;;;;N;;;;; -2D82;ETHIOPIC SYLLABLE ROA;Lo;0;L;;;;;N;;;;; -2D83;ETHIOPIC SYLLABLE SOA;Lo;0;L;;;;;N;;;;; -2D84;ETHIOPIC SYLLABLE SHOA;Lo;0;L;;;;;N;;;;; -2D85;ETHIOPIC SYLLABLE BOA;Lo;0;L;;;;;N;;;;; -2D86;ETHIOPIC SYLLABLE TOA;Lo;0;L;;;;;N;;;;; -2D87;ETHIOPIC SYLLABLE COA;Lo;0;L;;;;;N;;;;; -2D88;ETHIOPIC SYLLABLE NOA;Lo;0;L;;;;;N;;;;; -2D89;ETHIOPIC SYLLABLE NYOA;Lo;0;L;;;;;N;;;;; -2D8A;ETHIOPIC SYLLABLE GLOTTAL OA;Lo;0;L;;;;;N;;;;; -2D8B;ETHIOPIC SYLLABLE ZOA;Lo;0;L;;;;;N;;;;; -2D8C;ETHIOPIC SYLLABLE DOA;Lo;0;L;;;;;N;;;;; -2D8D;ETHIOPIC SYLLABLE DDOA;Lo;0;L;;;;;N;;;;; -2D8E;ETHIOPIC SYLLABLE JOA;Lo;0;L;;;;;N;;;;; -2D8F;ETHIOPIC SYLLABLE THOA;Lo;0;L;;;;;N;;;;; -2D90;ETHIOPIC SYLLABLE CHOA;Lo;0;L;;;;;N;;;;; -2D91;ETHIOPIC SYLLABLE PHOA;Lo;0;L;;;;;N;;;;; -2D92;ETHIOPIC SYLLABLE POA;Lo;0;L;;;;;N;;;;; -2D93;ETHIOPIC SYLLABLE GGWA;Lo;0;L;;;;;N;;;;; -2D94;ETHIOPIC SYLLABLE GGWI;Lo;0;L;;;;;N;;;;; -2D95;ETHIOPIC SYLLABLE GGWEE;Lo;0;L;;;;;N;;;;; -2D96;ETHIOPIC SYLLABLE GGWE;Lo;0;L;;;;;N;;;;; -2DA0;ETHIOPIC SYLLABLE SSA;Lo;0;L;;;;;N;;;;; -2DA1;ETHIOPIC SYLLABLE SSU;Lo;0;L;;;;;N;;;;; -2DA2;ETHIOPIC SYLLABLE SSI;Lo;0;L;;;;;N;;;;; -2DA3;ETHIOPIC SYLLABLE SSAA;Lo;0;L;;;;;N;;;;; -2DA4;ETHIOPIC SYLLABLE SSEE;Lo;0;L;;;;;N;;;;; -2DA5;ETHIOPIC SYLLABLE SSE;Lo;0;L;;;;;N;;;;; -2DA6;ETHIOPIC SYLLABLE SSO;Lo;0;L;;;;;N;;;;; -2DA8;ETHIOPIC SYLLABLE CCA;Lo;0;L;;;;;N;;;;; -2DA9;ETHIOPIC SYLLABLE CCU;Lo;0;L;;;;;N;;;;; -2DAA;ETHIOPIC SYLLABLE CCI;Lo;0;L;;;;;N;;;;; -2DAB;ETHIOPIC SYLLABLE CCAA;Lo;0;L;;;;;N;;;;; -2DAC;ETHIOPIC SYLLABLE CCEE;Lo;0;L;;;;;N;;;;; -2DAD;ETHIOPIC SYLLABLE CCE;Lo;0;L;;;;;N;;;;; -2DAE;ETHIOPIC SYLLABLE CCO;Lo;0;L;;;;;N;;;;; -2DB0;ETHIOPIC SYLLABLE ZZA;Lo;0;L;;;;;N;;;;; -2DB1;ETHIOPIC SYLLABLE ZZU;Lo;0;L;;;;;N;;;;; -2DB2;ETHIOPIC SYLLABLE ZZI;Lo;0;L;;;;;N;;;;; -2DB3;ETHIOPIC SYLLABLE ZZAA;Lo;0;L;;;;;N;;;;; -2DB4;ETHIOPIC SYLLABLE ZZEE;Lo;0;L;;;;;N;;;;; -2DB5;ETHIOPIC SYLLABLE ZZE;Lo;0;L;;;;;N;;;;; -2DB6;ETHIOPIC SYLLABLE ZZO;Lo;0;L;;;;;N;;;;; -2DB8;ETHIOPIC SYLLABLE CCHA;Lo;0;L;;;;;N;;;;; -2DB9;ETHIOPIC SYLLABLE CCHU;Lo;0;L;;;;;N;;;;; -2DBA;ETHIOPIC SYLLABLE CCHI;Lo;0;L;;;;;N;;;;; -2DBB;ETHIOPIC SYLLABLE CCHAA;Lo;0;L;;;;;N;;;;; -2DBC;ETHIOPIC SYLLABLE CCHEE;Lo;0;L;;;;;N;;;;; -2DBD;ETHIOPIC SYLLABLE CCHE;Lo;0;L;;;;;N;;;;; -2DBE;ETHIOPIC SYLLABLE CCHO;Lo;0;L;;;;;N;;;;; -2DC0;ETHIOPIC SYLLABLE QYA;Lo;0;L;;;;;N;;;;; -2DC1;ETHIOPIC SYLLABLE QYU;Lo;0;L;;;;;N;;;;; -2DC2;ETHIOPIC SYLLABLE QYI;Lo;0;L;;;;;N;;;;; -2DC3;ETHIOPIC SYLLABLE QYAA;Lo;0;L;;;;;N;;;;; -2DC4;ETHIOPIC SYLLABLE QYEE;Lo;0;L;;;;;N;;;;; -2DC5;ETHIOPIC SYLLABLE QYE;Lo;0;L;;;;;N;;;;; -2DC6;ETHIOPIC SYLLABLE QYO;Lo;0;L;;;;;N;;;;; -2DC8;ETHIOPIC SYLLABLE KYA;Lo;0;L;;;;;N;;;;; -2DC9;ETHIOPIC SYLLABLE KYU;Lo;0;L;;;;;N;;;;; -2DCA;ETHIOPIC SYLLABLE KYI;Lo;0;L;;;;;N;;;;; -2DCB;ETHIOPIC SYLLABLE KYAA;Lo;0;L;;;;;N;;;;; -2DCC;ETHIOPIC SYLLABLE KYEE;Lo;0;L;;;;;N;;;;; -2DCD;ETHIOPIC SYLLABLE KYE;Lo;0;L;;;;;N;;;;; -2DCE;ETHIOPIC SYLLABLE KYO;Lo;0;L;;;;;N;;;;; -2DD0;ETHIOPIC SYLLABLE XYA;Lo;0;L;;;;;N;;;;; -2DD1;ETHIOPIC SYLLABLE XYU;Lo;0;L;;;;;N;;;;; -2DD2;ETHIOPIC SYLLABLE XYI;Lo;0;L;;;;;N;;;;; -2DD3;ETHIOPIC SYLLABLE XYAA;Lo;0;L;;;;;N;;;;; -2DD4;ETHIOPIC SYLLABLE XYEE;Lo;0;L;;;;;N;;;;; -2DD5;ETHIOPIC SYLLABLE XYE;Lo;0;L;;;;;N;;;;; -2DD6;ETHIOPIC SYLLABLE XYO;Lo;0;L;;;;;N;;;;; -2DD8;ETHIOPIC SYLLABLE GYA;Lo;0;L;;;;;N;;;;; -2DD9;ETHIOPIC SYLLABLE GYU;Lo;0;L;;;;;N;;;;; -2DDA;ETHIOPIC SYLLABLE GYI;Lo;0;L;;;;;N;;;;; -2DDB;ETHIOPIC SYLLABLE GYAA;Lo;0;L;;;;;N;;;;; -2DDC;ETHIOPIC SYLLABLE GYEE;Lo;0;L;;;;;N;;;;; -2DDD;ETHIOPIC SYLLABLE GYE;Lo;0;L;;;;;N;;;;; -2DDE;ETHIOPIC SYLLABLE GYO;Lo;0;L;;;;;N;;;;; -2DE0;COMBINING CYRILLIC LETTER BE;Mn;230;NSM;;;;;N;;;;; -2DE1;COMBINING CYRILLIC LETTER VE;Mn;230;NSM;;;;;N;;;;; -2DE2;COMBINING CYRILLIC LETTER GHE;Mn;230;NSM;;;;;N;;;;; -2DE3;COMBINING CYRILLIC LETTER DE;Mn;230;NSM;;;;;N;;;;; -2DE4;COMBINING CYRILLIC LETTER ZHE;Mn;230;NSM;;;;;N;;;;; -2DE5;COMBINING CYRILLIC LETTER ZE;Mn;230;NSM;;;;;N;;;;; -2DE6;COMBINING CYRILLIC LETTER KA;Mn;230;NSM;;;;;N;;;;; -2DE7;COMBINING CYRILLIC LETTER EL;Mn;230;NSM;;;;;N;;;;; -2DE8;COMBINING CYRILLIC LETTER EM;Mn;230;NSM;;;;;N;;;;; -2DE9;COMBINING CYRILLIC LETTER EN;Mn;230;NSM;;;;;N;;;;; -2DEA;COMBINING CYRILLIC LETTER O;Mn;230;NSM;;;;;N;;;;; -2DEB;COMBINING CYRILLIC LETTER PE;Mn;230;NSM;;;;;N;;;;; -2DEC;COMBINING CYRILLIC LETTER ER;Mn;230;NSM;;;;;N;;;;; -2DED;COMBINING CYRILLIC LETTER ES;Mn;230;NSM;;;;;N;;;;; -2DEE;COMBINING CYRILLIC LETTER TE;Mn;230;NSM;;;;;N;;;;; -2DEF;COMBINING CYRILLIC LETTER HA;Mn;230;NSM;;;;;N;;;;; -2DF0;COMBINING CYRILLIC LETTER TSE;Mn;230;NSM;;;;;N;;;;; -2DF1;COMBINING CYRILLIC LETTER CHE;Mn;230;NSM;;;;;N;;;;; -2DF2;COMBINING CYRILLIC LETTER SHA;Mn;230;NSM;;;;;N;;;;; -2DF3;COMBINING CYRILLIC LETTER SHCHA;Mn;230;NSM;;;;;N;;;;; -2DF4;COMBINING CYRILLIC LETTER FITA;Mn;230;NSM;;;;;N;;;;; -2DF5;COMBINING CYRILLIC LETTER ES-TE;Mn;230;NSM;;;;;N;;;;; -2DF6;COMBINING CYRILLIC LETTER A;Mn;230;NSM;;;;;N;;;;; -2DF7;COMBINING CYRILLIC LETTER IE;Mn;230;NSM;;;;;N;;;;; -2DF8;COMBINING CYRILLIC LETTER DJERV;Mn;230;NSM;;;;;N;;;;; -2DF9;COMBINING CYRILLIC LETTER MONOGRAPH UK;Mn;230;NSM;;;;;N;;;;; -2DFA;COMBINING CYRILLIC LETTER YAT;Mn;230;NSM;;;;;N;;;;; -2DFB;COMBINING CYRILLIC LETTER YU;Mn;230;NSM;;;;;N;;;;; -2DFC;COMBINING CYRILLIC LETTER IOTIFIED A;Mn;230;NSM;;;;;N;;;;; -2DFD;COMBINING CYRILLIC LETTER LITTLE YUS;Mn;230;NSM;;;;;N;;;;; -2DFE;COMBINING CYRILLIC LETTER BIG YUS;Mn;230;NSM;;;;;N;;;;; -2DFF;COMBINING CYRILLIC LETTER IOTIFIED BIG YUS;Mn;230;NSM;;;;;N;;;;; -2E00;RIGHT ANGLE SUBSTITUTION MARKER;Po;0;ON;;;;;N;;;;; -2E01;RIGHT ANGLE DOTTED SUBSTITUTION MARKER;Po;0;ON;;;;;N;;;;; -2E02;LEFT SUBSTITUTION BRACKET;Pi;0;ON;;;;;Y;;;;; -2E03;RIGHT SUBSTITUTION BRACKET;Pf;0;ON;;;;;Y;;;;; -2E04;LEFT DOTTED SUBSTITUTION BRACKET;Pi;0;ON;;;;;Y;;;;; -2E05;RIGHT DOTTED SUBSTITUTION BRACKET;Pf;0;ON;;;;;Y;;;;; -2E06;RAISED INTERPOLATION MARKER;Po;0;ON;;;;;N;;;;; -2E07;RAISED DOTTED INTERPOLATION MARKER;Po;0;ON;;;;;N;;;;; -2E08;DOTTED TRANSPOSITION MARKER;Po;0;ON;;;;;N;;;;; -2E09;LEFT TRANSPOSITION BRACKET;Pi;0;ON;;;;;Y;;;;; -2E0A;RIGHT TRANSPOSITION BRACKET;Pf;0;ON;;;;;Y;;;;; -2E0B;RAISED SQUARE;Po;0;ON;;;;;N;;;;; -2E0C;LEFT RAISED OMISSION BRACKET;Pi;0;ON;;;;;Y;;;;; -2E0D;RIGHT RAISED OMISSION BRACKET;Pf;0;ON;;;;;Y;;;;; -2E0E;EDITORIAL CORONIS;Po;0;ON;;;;;N;;;;; -2E0F;PARAGRAPHOS;Po;0;ON;;;;;N;;;;; -2E10;FORKED PARAGRAPHOS;Po;0;ON;;;;;N;;;;; -2E11;REVERSED FORKED PARAGRAPHOS;Po;0;ON;;;;;N;;;;; -2E12;HYPODIASTOLE;Po;0;ON;;;;;N;;;;; -2E13;DOTTED OBELOS;Po;0;ON;;;;;N;;;;; -2E14;DOWNWARDS ANCORA;Po;0;ON;;;;;N;;;;; -2E15;UPWARDS ANCORA;Po;0;ON;;;;;N;;;;; -2E16;DOTTED RIGHT-POINTING ANGLE;Po;0;ON;;;;;N;;;;; -2E17;DOUBLE OBLIQUE HYPHEN;Pd;0;ON;;;;;N;;;;; -2E18;INVERTED INTERROBANG;Po;0;ON;;;;;N;;;;; -2E19;PALM BRANCH;Po;0;ON;;;;;N;;;;; -2E1A;HYPHEN WITH DIAERESIS;Pd;0;ON;;;;;N;;;;; -2E1B;TILDE WITH RING ABOVE;Po;0;ON;;;;;N;;;;; -2E1C;LEFT LOW PARAPHRASE BRACKET;Pi;0;ON;;;;;Y;;;;; -2E1D;RIGHT LOW PARAPHRASE BRACKET;Pf;0;ON;;;;;Y;;;;; -2E1E;TILDE WITH DOT ABOVE;Po;0;ON;;;;;N;;;;; -2E1F;TILDE WITH DOT BELOW;Po;0;ON;;;;;N;;;;; -2E20;LEFT VERTICAL BAR WITH QUILL;Pi;0;ON;;;;;Y;;;;; -2E21;RIGHT VERTICAL BAR WITH QUILL;Pf;0;ON;;;;;Y;;;;; -2E22;TOP LEFT HALF BRACKET;Ps;0;ON;;;;;Y;;;;; -2E23;TOP RIGHT HALF BRACKET;Pe;0;ON;;;;;Y;;;;; -2E24;BOTTOM LEFT HALF BRACKET;Ps;0;ON;;;;;Y;;;;; -2E25;BOTTOM RIGHT HALF BRACKET;Pe;0;ON;;;;;Y;;;;; -2E26;LEFT SIDEWAYS U BRACKET;Ps;0;ON;;;;;Y;;;;; -2E27;RIGHT SIDEWAYS U BRACKET;Pe;0;ON;;;;;Y;;;;; -2E28;LEFT DOUBLE PARENTHESIS;Ps;0;ON;;;;;Y;;;;; -2E29;RIGHT DOUBLE PARENTHESIS;Pe;0;ON;;;;;Y;;;;; -2E2A;TWO DOTS OVER ONE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; -2E2B;ONE DOT OVER TWO DOTS PUNCTUATION;Po;0;ON;;;;;N;;;;; -2E2C;SQUARED FOUR DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; -2E2D;FIVE DOT MARK;Po;0;ON;;;;;N;;;;; -2E2E;REVERSED QUESTION MARK;Po;0;ON;;;;;N;;;;; -2E2F;VERTICAL TILDE;Lm;0;ON;;;;;N;;;;; -2E30;RING POINT;Po;0;ON;;;;;N;;;;; -2E31;WORD SEPARATOR MIDDLE DOT;Po;0;ON;;;;;N;;;;; -2E32;TURNED COMMA;Po;0;ON;;;;;N;;;;; -2E33;RAISED DOT;Po;0;ON;;;;;N;;;;; -2E34;RAISED COMMA;Po;0;ON;;;;;N;;;;; -2E35;TURNED SEMICOLON;Po;0;ON;;;;;N;;;;; -2E36;DAGGER WITH LEFT GUARD;Po;0;ON;;;;;N;;;;; -2E37;DAGGER WITH RIGHT GUARD;Po;0;ON;;;;;N;;;;; -2E38;TURNED DAGGER;Po;0;ON;;;;;N;;;;; -2E39;TOP HALF SECTION SIGN;Po;0;ON;;;;;N;;;;; -2E3A;TWO-EM DASH;Pd;0;ON;;;;;N;;;;; -2E3B;THREE-EM DASH;Pd;0;ON;;;;;N;;;;; -2E3C;STENOGRAPHIC FULL STOP;Po;0;ON;;;;;N;;;;; -2E3D;VERTICAL SIX DOTS;Po;0;ON;;;;;N;;;;; -2E3E;WIGGLY VERTICAL LINE;Po;0;ON;;;;;N;;;;; -2E3F;CAPITULUM;Po;0;ON;;;;;N;;;;; -2E40;DOUBLE HYPHEN;Pd;0;ON;;;;;N;;;;; -2E41;REVERSED COMMA;Po;0;ON;;;;;N;;;;; -2E42;DOUBLE LOW-REVERSED-9 QUOTATION MARK;Ps;0;ON;;;;;N;;;;; -2E43;DASH WITH LEFT UPTURN;Po;0;ON;;;;;N;;;;; -2E44;DOUBLE SUSPENSION MARK;Po;0;ON;;;;;N;;;;; -2E45;INVERTED LOW KAVYKA;Po;0;ON;;;;;N;;;;; -2E46;INVERTED LOW KAVYKA WITH KAVYKA ABOVE;Po;0;ON;;;;;N;;;;; -2E47;LOW KAVYKA;Po;0;ON;;;;;N;;;;; -2E48;LOW KAVYKA WITH DOT;Po;0;ON;;;;;N;;;;; -2E49;DOUBLE STACKED COMMA;Po;0;ON;;;;;N;;;;; -2E4A;DOTTED SOLIDUS;Po;0;ON;;;;;N;;;;; -2E4B;TRIPLE DAGGER;Po;0;ON;;;;;N;;;;; -2E4C;MEDIEVAL COMMA;Po;0;ON;;;;;N;;;;; -2E4D;PARAGRAPHUS MARK;Po;0;ON;;;;;N;;;;; -2E4E;PUNCTUS ELEVATUS MARK;Po;0;ON;;;;;N;;;;; -2E4F;CORNISH VERSE DIVIDER;Po;0;ON;;;;;N;;;;; -2E50;CROSS PATTY WITH RIGHT CROSSBAR;So;0;ON;;;;;N;;;;; -2E51;CROSS PATTY WITH LEFT CROSSBAR;So;0;ON;;;;;N;;;;; -2E52;TIRONIAN SIGN CAPITAL ET;Po;0;ON;;;;;N;;;;; -2E53;MEDIEVAL EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; -2E54;MEDIEVAL QUESTION MARK;Po;0;ON;;;;;N;;;;; -2E55;LEFT SQUARE BRACKET WITH STROKE;Ps;0;ON;;;;;Y;;;;; -2E56;RIGHT SQUARE BRACKET WITH STROKE;Pe;0;ON;;;;;Y;;;;; -2E57;LEFT SQUARE BRACKET WITH DOUBLE STROKE;Ps;0;ON;;;;;Y;;;;; -2E58;RIGHT SQUARE BRACKET WITH DOUBLE STROKE;Pe;0;ON;;;;;Y;;;;; -2E59;TOP HALF LEFT PARENTHESIS;Ps;0;ON;;;;;Y;;;;; -2E5A;TOP HALF RIGHT PARENTHESIS;Pe;0;ON;;;;;Y;;;;; -2E5B;BOTTOM HALF LEFT PARENTHESIS;Ps;0;ON;;;;;Y;;;;; -2E5C;BOTTOM HALF RIGHT PARENTHESIS;Pe;0;ON;;;;;Y;;;;; -2E5D;OBLIQUE HYPHEN;Pd;0;ON;;;;;N;;;;; -2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;; -2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;; -2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;; -2E83;CJK RADICAL SECOND TWO;So;0;ON;;;;;N;;;;; -2E84;CJK RADICAL SECOND THREE;So;0;ON;;;;;N;;;;; -2E85;CJK RADICAL PERSON;So;0;ON;;;;;N;;;;; -2E86;CJK RADICAL BOX;So;0;ON;;;;;N;;;;; -2E87;CJK RADICAL TABLE;So;0;ON;;;;;N;;;;; -2E88;CJK RADICAL KNIFE ONE;So;0;ON;;;;;N;;;;; -2E89;CJK RADICAL KNIFE TWO;So;0;ON;;;;;N;;;;; -2E8A;CJK RADICAL DIVINATION;So;0;ON;;;;;N;;;;; -2E8B;CJK RADICAL SEAL;So;0;ON;;;;;N;;;;; -2E8C;CJK RADICAL SMALL ONE;So;0;ON;;;;;N;;;;; -2E8D;CJK RADICAL SMALL TWO;So;0;ON;;;;;N;;;;; -2E8E;CJK RADICAL LAME ONE;So;0;ON;;;;;N;;;;; -2E8F;CJK RADICAL LAME TWO;So;0;ON;;;;;N;;;;; -2E90;CJK RADICAL LAME THREE;So;0;ON;;;;;N;;;;; -2E91;CJK RADICAL LAME FOUR;So;0;ON;;;;;N;;;;; -2E92;CJK RADICAL SNAKE;So;0;ON;;;;;N;;;;; -2E93;CJK RADICAL THREAD;So;0;ON;;;;;N;;;;; -2E94;CJK RADICAL SNOUT ONE;So;0;ON;;;;;N;;;;; -2E95;CJK RADICAL SNOUT TWO;So;0;ON;;;;;N;;;;; -2E96;CJK RADICAL HEART ONE;So;0;ON;;;;;N;;;;; -2E97;CJK RADICAL HEART TWO;So;0;ON;;;;;N;;;;; -2E98;CJK RADICAL HAND;So;0;ON;;;;;N;;;;; -2E99;CJK RADICAL RAP;So;0;ON;;;;;N;;;;; -2E9B;CJK RADICAL CHOKE;So;0;ON;;;;;N;;;;; -2E9C;CJK RADICAL SUN;So;0;ON;;;;;N;;;;; -2E9D;CJK RADICAL MOON;So;0;ON;;;;;N;;;;; -2E9E;CJK RADICAL DEATH;So;0;ON;;;;;N;;;;; -2E9F;CJK RADICAL MOTHER;So;0;ON;<compat> 6BCD;;;;N;;;;; -2EA0;CJK RADICAL CIVILIAN;So;0;ON;;;;;N;;;;; -2EA1;CJK RADICAL WATER ONE;So;0;ON;;;;;N;;;;; -2EA2;CJK RADICAL WATER TWO;So;0;ON;;;;;N;;;;; -2EA3;CJK RADICAL FIRE;So;0;ON;;;;;N;;;;; -2EA4;CJK RADICAL PAW ONE;So;0;ON;;;;;N;;;;; -2EA5;CJK RADICAL PAW TWO;So;0;ON;;;;;N;;;;; -2EA6;CJK RADICAL SIMPLIFIED HALF TREE TRUNK;So;0;ON;;;;;N;;;;; -2EA7;CJK RADICAL COW;So;0;ON;;;;;N;;;;; -2EA8;CJK RADICAL DOG;So;0;ON;;;;;N;;;;; -2EA9;CJK RADICAL JADE;So;0;ON;;;;;N;;;;; -2EAA;CJK RADICAL BOLT OF CLOTH;So;0;ON;;;;;N;;;;; -2EAB;CJK RADICAL EYE;So;0;ON;;;;;N;;;;; -2EAC;CJK RADICAL SPIRIT ONE;So;0;ON;;;;;N;;;;; -2EAD;CJK RADICAL SPIRIT TWO;So;0;ON;;;;;N;;;;; -2EAE;CJK RADICAL BAMBOO;So;0;ON;;;;;N;;;;; -2EAF;CJK RADICAL SILK;So;0;ON;;;;;N;;;;; -2EB0;CJK RADICAL C-SIMPLIFIED SILK;So;0;ON;;;;;N;;;;; -2EB1;CJK RADICAL NET ONE;So;0;ON;;;;;N;;;;; -2EB2;CJK RADICAL NET TWO;So;0;ON;;;;;N;;;;; -2EB3;CJK RADICAL NET THREE;So;0;ON;;;;;N;;;;; -2EB4;CJK RADICAL NET FOUR;So;0;ON;;;;;N;;;;; -2EB5;CJK RADICAL MESH;So;0;ON;;;;;N;;;;; -2EB6;CJK RADICAL SHEEP;So;0;ON;;;;;N;;;;; -2EB7;CJK RADICAL RAM;So;0;ON;;;;;N;;;;; -2EB8;CJK RADICAL EWE;So;0;ON;;;;;N;;;;; -2EB9;CJK RADICAL OLD;So;0;ON;;;;;N;;;;; -2EBA;CJK RADICAL BRUSH ONE;So;0;ON;;;;;N;;;;; -2EBB;CJK RADICAL BRUSH TWO;So;0;ON;;;;;N;;;;; -2EBC;CJK RADICAL MEAT;So;0;ON;;;;;N;;;;; -2EBD;CJK RADICAL MORTAR;So;0;ON;;;;;N;;;;; -2EBE;CJK RADICAL GRASS ONE;So;0;ON;;;;;N;;;;; -2EBF;CJK RADICAL GRASS TWO;So;0;ON;;;;;N;;;;; -2EC0;CJK RADICAL GRASS THREE;So;0;ON;;;;;N;;;;; -2EC1;CJK RADICAL TIGER;So;0;ON;;;;;N;;;;; -2EC2;CJK RADICAL CLOTHES;So;0;ON;;;;;N;;;;; -2EC3;CJK RADICAL WEST ONE;So;0;ON;;;;;N;;;;; -2EC4;CJK RADICAL WEST TWO;So;0;ON;;;;;N;;;;; -2EC5;CJK RADICAL C-SIMPLIFIED SEE;So;0;ON;;;;;N;;;;; -2EC6;CJK RADICAL SIMPLIFIED HORN;So;0;ON;;;;;N;;;;; -2EC7;CJK RADICAL HORN;So;0;ON;;;;;N;;;;; -2EC8;CJK RADICAL C-SIMPLIFIED SPEECH;So;0;ON;;;;;N;;;;; -2EC9;CJK RADICAL C-SIMPLIFIED SHELL;So;0;ON;;;;;N;;;;; -2ECA;CJK RADICAL FOOT;So;0;ON;;;;;N;;;;; -2ECB;CJK RADICAL C-SIMPLIFIED CART;So;0;ON;;;;;N;;;;; -2ECC;CJK RADICAL SIMPLIFIED WALK;So;0;ON;;;;;N;;;;; -2ECD;CJK RADICAL WALK ONE;So;0;ON;;;;;N;;;;; -2ECE;CJK RADICAL WALK TWO;So;0;ON;;;;;N;;;;; -2ECF;CJK RADICAL CITY;So;0;ON;;;;;N;;;;; -2ED0;CJK RADICAL C-SIMPLIFIED GOLD;So;0;ON;;;;;N;;;;; -2ED1;CJK RADICAL LONG ONE;So;0;ON;;;;;N;;;;; -2ED2;CJK RADICAL LONG TWO;So;0;ON;;;;;N;;;;; -2ED3;CJK RADICAL C-SIMPLIFIED LONG;So;0;ON;;;;;N;;;;; -2ED4;CJK RADICAL C-SIMPLIFIED GATE;So;0;ON;;;;;N;;;;; -2ED5;CJK RADICAL MOUND ONE;So;0;ON;;;;;N;;;;; -2ED6;CJK RADICAL MOUND TWO;So;0;ON;;;;;N;;;;; -2ED7;CJK RADICAL RAIN;So;0;ON;;;;;N;;;;; -2ED8;CJK RADICAL BLUE;So;0;ON;;;;;N;;;;; -2ED9;CJK RADICAL C-SIMPLIFIED TANNED LEATHER;So;0;ON;;;;;N;;;;; -2EDA;CJK RADICAL C-SIMPLIFIED LEAF;So;0;ON;;;;;N;;;;; -2EDB;CJK RADICAL C-SIMPLIFIED WIND;So;0;ON;;;;;N;;;;; -2EDC;CJK RADICAL C-SIMPLIFIED FLY;So;0;ON;;;;;N;;;;; -2EDD;CJK RADICAL EAT ONE;So;0;ON;;;;;N;;;;; -2EDE;CJK RADICAL EAT TWO;So;0;ON;;;;;N;;;;; -2EDF;CJK RADICAL EAT THREE;So;0;ON;;;;;N;;;;; -2EE0;CJK RADICAL C-SIMPLIFIED EAT;So;0;ON;;;;;N;;;;; -2EE1;CJK RADICAL HEAD;So;0;ON;;;;;N;;;;; -2EE2;CJK RADICAL C-SIMPLIFIED HORSE;So;0;ON;;;;;N;;;;; -2EE3;CJK RADICAL BONE;So;0;ON;;;;;N;;;;; -2EE4;CJK RADICAL GHOST;So;0;ON;;;;;N;;;;; -2EE5;CJK RADICAL C-SIMPLIFIED FISH;So;0;ON;;;;;N;;;;; -2EE6;CJK RADICAL C-SIMPLIFIED BIRD;So;0;ON;;;;;N;;;;; -2EE7;CJK RADICAL C-SIMPLIFIED SALT;So;0;ON;;;;;N;;;;; -2EE8;CJK RADICAL SIMPLIFIED WHEAT;So;0;ON;;;;;N;;;;; -2EE9;CJK RADICAL SIMPLIFIED YELLOW;So;0;ON;;;;;N;;;;; -2EEA;CJK RADICAL C-SIMPLIFIED FROG;So;0;ON;;;;;N;;;;; -2EEB;CJK RADICAL J-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;; -2EEC;CJK RADICAL C-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;; -2EED;CJK RADICAL J-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;; -2EEE;CJK RADICAL C-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;; -2EEF;CJK RADICAL J-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;; -2EF0;CJK RADICAL C-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;; -2EF1;CJK RADICAL TURTLE;So;0;ON;;;;;N;;;;; -2EF2;CJK RADICAL J-SIMPLIFIED TURTLE;So;0;ON;;;;;N;;;;; -2EF3;CJK RADICAL C-SIMPLIFIED TURTLE;So;0;ON;<compat> 9F9F;;;;N;;;;; -2F00;KANGXI RADICAL ONE;So;0;ON;<compat> 4E00;;;;N;;;;; -2F01;KANGXI RADICAL LINE;So;0;ON;<compat> 4E28;;;;N;;;;; -2F02;KANGXI RADICAL DOT;So;0;ON;<compat> 4E36;;;;N;;;;; -2F03;KANGXI RADICAL SLASH;So;0;ON;<compat> 4E3F;;;;N;;;;; -2F04;KANGXI RADICAL SECOND;So;0;ON;<compat> 4E59;;;;N;;;;; -2F05;KANGXI RADICAL HOOK;So;0;ON;<compat> 4E85;;;;N;;;;; -2F06;KANGXI RADICAL TWO;So;0;ON;<compat> 4E8C;;;;N;;;;; -2F07;KANGXI RADICAL LID;So;0;ON;<compat> 4EA0;;;;N;;;;; -2F08;KANGXI RADICAL MAN;So;0;ON;<compat> 4EBA;;;;N;;;;; -2F09;KANGXI RADICAL LEGS;So;0;ON;<compat> 513F;;;;N;;;;; -2F0A;KANGXI RADICAL ENTER;So;0;ON;<compat> 5165;;;;N;;;;; -2F0B;KANGXI RADICAL EIGHT;So;0;ON;<compat> 516B;;;;N;;;;; -2F0C;KANGXI RADICAL DOWN BOX;So;0;ON;<compat> 5182;;;;N;;;;; -2F0D;KANGXI RADICAL COVER;So;0;ON;<compat> 5196;;;;N;;;;; -2F0E;KANGXI RADICAL ICE;So;0;ON;<compat> 51AB;;;;N;;;;; -2F0F;KANGXI RADICAL TABLE;So;0;ON;<compat> 51E0;;;;N;;;;; -2F10;KANGXI RADICAL OPEN BOX;So;0;ON;<compat> 51F5;;;;N;;;;; -2F11;KANGXI RADICAL KNIFE;So;0;ON;<compat> 5200;;;;N;;;;; -2F12;KANGXI RADICAL POWER;So;0;ON;<compat> 529B;;;;N;;;;; -2F13;KANGXI RADICAL WRAP;So;0;ON;<compat> 52F9;;;;N;;;;; -2F14;KANGXI RADICAL SPOON;So;0;ON;<compat> 5315;;;;N;;;;; -2F15;KANGXI RADICAL RIGHT OPEN BOX;So;0;ON;<compat> 531A;;;;N;;;;; -2F16;KANGXI RADICAL HIDING ENCLOSURE;So;0;ON;<compat> 5338;;;;N;;;;; -2F17;KANGXI RADICAL TEN;So;0;ON;<compat> 5341;;;;N;;;;; -2F18;KANGXI RADICAL DIVINATION;So;0;ON;<compat> 535C;;;;N;;;;; -2F19;KANGXI RADICAL SEAL;So;0;ON;<compat> 5369;;;;N;;;;; -2F1A;KANGXI RADICAL CLIFF;So;0;ON;<compat> 5382;;;;N;;;;; -2F1B;KANGXI RADICAL PRIVATE;So;0;ON;<compat> 53B6;;;;N;;;;; -2F1C;KANGXI RADICAL AGAIN;So;0;ON;<compat> 53C8;;;;N;;;;; -2F1D;KANGXI RADICAL MOUTH;So;0;ON;<compat> 53E3;;;;N;;;;; -2F1E;KANGXI RADICAL ENCLOSURE;So;0;ON;<compat> 56D7;;;;N;;;;; -2F1F;KANGXI RADICAL EARTH;So;0;ON;<compat> 571F;;;;N;;;;; -2F20;KANGXI RADICAL SCHOLAR;So;0;ON;<compat> 58EB;;;;N;;;;; -2F21;KANGXI RADICAL GO;So;0;ON;<compat> 5902;;;;N;;;;; -2F22;KANGXI RADICAL GO SLOWLY;So;0;ON;<compat> 590A;;;;N;;;;; -2F23;KANGXI RADICAL EVENING;So;0;ON;<compat> 5915;;;;N;;;;; -2F24;KANGXI RADICAL BIG;So;0;ON;<compat> 5927;;;;N;;;;; -2F25;KANGXI RADICAL WOMAN;So;0;ON;<compat> 5973;;;;N;;;;; -2F26;KANGXI RADICAL CHILD;So;0;ON;<compat> 5B50;;;;N;;;;; -2F27;KANGXI RADICAL ROOF;So;0;ON;<compat> 5B80;;;;N;;;;; -2F28;KANGXI RADICAL INCH;So;0;ON;<compat> 5BF8;;;;N;;;;; -2F29;KANGXI RADICAL SMALL;So;0;ON;<compat> 5C0F;;;;N;;;;; -2F2A;KANGXI RADICAL LAME;So;0;ON;<compat> 5C22;;;;N;;;;; -2F2B;KANGXI RADICAL CORPSE;So;0;ON;<compat> 5C38;;;;N;;;;; -2F2C;KANGXI RADICAL SPROUT;So;0;ON;<compat> 5C6E;;;;N;;;;; -2F2D;KANGXI RADICAL MOUNTAIN;So;0;ON;<compat> 5C71;;;;N;;;;; -2F2E;KANGXI RADICAL RIVER;So;0;ON;<compat> 5DDB;;;;N;;;;; -2F2F;KANGXI RADICAL WORK;So;0;ON;<compat> 5DE5;;;;N;;;;; -2F30;KANGXI RADICAL ONESELF;So;0;ON;<compat> 5DF1;;;;N;;;;; -2F31;KANGXI RADICAL TURBAN;So;0;ON;<compat> 5DFE;;;;N;;;;; -2F32;KANGXI RADICAL DRY;So;0;ON;<compat> 5E72;;;;N;;;;; -2F33;KANGXI RADICAL SHORT THREAD;So;0;ON;<compat> 5E7A;;;;N;;;;; -2F34;KANGXI RADICAL DOTTED CLIFF;So;0;ON;<compat> 5E7F;;;;N;;;;; -2F35;KANGXI RADICAL LONG STRIDE;So;0;ON;<compat> 5EF4;;;;N;;;;; -2F36;KANGXI RADICAL TWO HANDS;So;0;ON;<compat> 5EFE;;;;N;;;;; -2F37;KANGXI RADICAL SHOOT;So;0;ON;<compat> 5F0B;;;;N;;;;; -2F38;KANGXI RADICAL BOW;So;0;ON;<compat> 5F13;;;;N;;;;; -2F39;KANGXI RADICAL SNOUT;So;0;ON;<compat> 5F50;;;;N;;;;; -2F3A;KANGXI RADICAL BRISTLE;So;0;ON;<compat> 5F61;;;;N;;;;; -2F3B;KANGXI RADICAL STEP;So;0;ON;<compat> 5F73;;;;N;;;;; -2F3C;KANGXI RADICAL HEART;So;0;ON;<compat> 5FC3;;;;N;;;;; -2F3D;KANGXI RADICAL HALBERD;So;0;ON;<compat> 6208;;;;N;;;;; -2F3E;KANGXI RADICAL DOOR;So;0;ON;<compat> 6236;;;;N;;;;; -2F3F;KANGXI RADICAL HAND;So;0;ON;<compat> 624B;;;;N;;;;; -2F40;KANGXI RADICAL BRANCH;So;0;ON;<compat> 652F;;;;N;;;;; -2F41;KANGXI RADICAL RAP;So;0;ON;<compat> 6534;;;;N;;;;; -2F42;KANGXI RADICAL SCRIPT;So;0;ON;<compat> 6587;;;;N;;;;; -2F43;KANGXI RADICAL DIPPER;So;0;ON;<compat> 6597;;;;N;;;;; -2F44;KANGXI RADICAL AXE;So;0;ON;<compat> 65A4;;;;N;;;;; -2F45;KANGXI RADICAL SQUARE;So;0;ON;<compat> 65B9;;;;N;;;;; -2F46;KANGXI RADICAL NOT;So;0;ON;<compat> 65E0;;;;N;;;;; -2F47;KANGXI RADICAL SUN;So;0;ON;<compat> 65E5;;;;N;;;;; -2F48;KANGXI RADICAL SAY;So;0;ON;<compat> 66F0;;;;N;;;;; -2F49;KANGXI RADICAL MOON;So;0;ON;<compat> 6708;;;;N;;;;; -2F4A;KANGXI RADICAL TREE;So;0;ON;<compat> 6728;;;;N;;;;; -2F4B;KANGXI RADICAL LACK;So;0;ON;<compat> 6B20;;;;N;;;;; -2F4C;KANGXI RADICAL STOP;So;0;ON;<compat> 6B62;;;;N;;;;; -2F4D;KANGXI RADICAL DEATH;So;0;ON;<compat> 6B79;;;;N;;;;; -2F4E;KANGXI RADICAL WEAPON;So;0;ON;<compat> 6BB3;;;;N;;;;; -2F4F;KANGXI RADICAL DO NOT;So;0;ON;<compat> 6BCB;;;;N;;;;; -2F50;KANGXI RADICAL COMPARE;So;0;ON;<compat> 6BD4;;;;N;;;;; -2F51;KANGXI RADICAL FUR;So;0;ON;<compat> 6BDB;;;;N;;;;; -2F52;KANGXI RADICAL CLAN;So;0;ON;<compat> 6C0F;;;;N;;;;; -2F53;KANGXI RADICAL STEAM;So;0;ON;<compat> 6C14;;;;N;;;;; -2F54;KANGXI RADICAL WATER;So;0;ON;<compat> 6C34;;;;N;;;;; -2F55;KANGXI RADICAL FIRE;So;0;ON;<compat> 706B;;;;N;;;;; -2F56;KANGXI RADICAL CLAW;So;0;ON;<compat> 722A;;;;N;;;;; -2F57;KANGXI RADICAL FATHER;So;0;ON;<compat> 7236;;;;N;;;;; -2F58;KANGXI RADICAL DOUBLE X;So;0;ON;<compat> 723B;;;;N;;;;; -2F59;KANGXI RADICAL HALF TREE TRUNK;So;0;ON;<compat> 723F;;;;N;;;;; -2F5A;KANGXI RADICAL SLICE;So;0;ON;<compat> 7247;;;;N;;;;; -2F5B;KANGXI RADICAL FANG;So;0;ON;<compat> 7259;;;;N;;;;; -2F5C;KANGXI RADICAL COW;So;0;ON;<compat> 725B;;;;N;;;;; -2F5D;KANGXI RADICAL DOG;So;0;ON;<compat> 72AC;;;;N;;;;; -2F5E;KANGXI RADICAL PROFOUND;So;0;ON;<compat> 7384;;;;N;;;;; -2F5F;KANGXI RADICAL JADE;So;0;ON;<compat> 7389;;;;N;;;;; -2F60;KANGXI RADICAL MELON;So;0;ON;<compat> 74DC;;;;N;;;;; -2F61;KANGXI RADICAL TILE;So;0;ON;<compat> 74E6;;;;N;;;;; -2F62;KANGXI RADICAL SWEET;So;0;ON;<compat> 7518;;;;N;;;;; -2F63;KANGXI RADICAL LIFE;So;0;ON;<compat> 751F;;;;N;;;;; -2F64;KANGXI RADICAL USE;So;0;ON;<compat> 7528;;;;N;;;;; -2F65;KANGXI RADICAL FIELD;So;0;ON;<compat> 7530;;;;N;;;;; -2F66;KANGXI RADICAL BOLT OF CLOTH;So;0;ON;<compat> 758B;;;;N;;;;; -2F67;KANGXI RADICAL SICKNESS;So;0;ON;<compat> 7592;;;;N;;;;; -2F68;KANGXI RADICAL DOTTED TENT;So;0;ON;<compat> 7676;;;;N;;;;; -2F69;KANGXI RADICAL WHITE;So;0;ON;<compat> 767D;;;;N;;;;; -2F6A;KANGXI RADICAL SKIN;So;0;ON;<compat> 76AE;;;;N;;;;; -2F6B;KANGXI RADICAL DISH;So;0;ON;<compat> 76BF;;;;N;;;;; -2F6C;KANGXI RADICAL EYE;So;0;ON;<compat> 76EE;;;;N;;;;; -2F6D;KANGXI RADICAL SPEAR;So;0;ON;<compat> 77DB;;;;N;;;;; -2F6E;KANGXI RADICAL ARROW;So;0;ON;<compat> 77E2;;;;N;;;;; -2F6F;KANGXI RADICAL STONE;So;0;ON;<compat> 77F3;;;;N;;;;; -2F70;KANGXI RADICAL SPIRIT;So;0;ON;<compat> 793A;;;;N;;;;; -2F71;KANGXI RADICAL TRACK;So;0;ON;<compat> 79B8;;;;N;;;;; -2F72;KANGXI RADICAL GRAIN;So;0;ON;<compat> 79BE;;;;N;;;;; -2F73;KANGXI RADICAL CAVE;So;0;ON;<compat> 7A74;;;;N;;;;; -2F74;KANGXI RADICAL STAND;So;0;ON;<compat> 7ACB;;;;N;;;;; -2F75;KANGXI RADICAL BAMBOO;So;0;ON;<compat> 7AF9;;;;N;;;;; -2F76;KANGXI RADICAL RICE;So;0;ON;<compat> 7C73;;;;N;;;;; -2F77;KANGXI RADICAL SILK;So;0;ON;<compat> 7CF8;;;;N;;;;; -2F78;KANGXI RADICAL JAR;So;0;ON;<compat> 7F36;;;;N;;;;; -2F79;KANGXI RADICAL NET;So;0;ON;<compat> 7F51;;;;N;;;;; -2F7A;KANGXI RADICAL SHEEP;So;0;ON;<compat> 7F8A;;;;N;;;;; -2F7B;KANGXI RADICAL FEATHER;So;0;ON;<compat> 7FBD;;;;N;;;;; -2F7C;KANGXI RADICAL OLD;So;0;ON;<compat> 8001;;;;N;;;;; -2F7D;KANGXI RADICAL AND;So;0;ON;<compat> 800C;;;;N;;;;; -2F7E;KANGXI RADICAL PLOW;So;0;ON;<compat> 8012;;;;N;;;;; -2F7F;KANGXI RADICAL EAR;So;0;ON;<compat> 8033;;;;N;;;;; -2F80;KANGXI RADICAL BRUSH;So;0;ON;<compat> 807F;;;;N;;;;; -2F81;KANGXI RADICAL MEAT;So;0;ON;<compat> 8089;;;;N;;;;; -2F82;KANGXI RADICAL MINISTER;So;0;ON;<compat> 81E3;;;;N;;;;; -2F83;KANGXI RADICAL SELF;So;0;ON;<compat> 81EA;;;;N;;;;; -2F84;KANGXI RADICAL ARRIVE;So;0;ON;<compat> 81F3;;;;N;;;;; -2F85;KANGXI RADICAL MORTAR;So;0;ON;<compat> 81FC;;;;N;;;;; -2F86;KANGXI RADICAL TONGUE;So;0;ON;<compat> 820C;;;;N;;;;; -2F87;KANGXI RADICAL OPPOSE;So;0;ON;<compat> 821B;;;;N;;;;; -2F88;KANGXI RADICAL BOAT;So;0;ON;<compat> 821F;;;;N;;;;; -2F89;KANGXI RADICAL STOPPING;So;0;ON;<compat> 826E;;;;N;;;;; -2F8A;KANGXI RADICAL COLOR;So;0;ON;<compat> 8272;;;;N;;;;; -2F8B;KANGXI RADICAL GRASS;So;0;ON;<compat> 8278;;;;N;;;;; -2F8C;KANGXI RADICAL TIGER;So;0;ON;<compat> 864D;;;;N;;;;; -2F8D;KANGXI RADICAL INSECT;So;0;ON;<compat> 866B;;;;N;;;;; -2F8E;KANGXI RADICAL BLOOD;So;0;ON;<compat> 8840;;;;N;;;;; -2F8F;KANGXI RADICAL WALK ENCLOSURE;So;0;ON;<compat> 884C;;;;N;;;;; -2F90;KANGXI RADICAL CLOTHES;So;0;ON;<compat> 8863;;;;N;;;;; -2F91;KANGXI RADICAL WEST;So;0;ON;<compat> 897E;;;;N;;;;; -2F92;KANGXI RADICAL SEE;So;0;ON;<compat> 898B;;;;N;;;;; -2F93;KANGXI RADICAL HORN;So;0;ON;<compat> 89D2;;;;N;;;;; -2F94;KANGXI RADICAL SPEECH;So;0;ON;<compat> 8A00;;;;N;;;;; -2F95;KANGXI RADICAL VALLEY;So;0;ON;<compat> 8C37;;;;N;;;;; -2F96;KANGXI RADICAL BEAN;So;0;ON;<compat> 8C46;;;;N;;;;; -2F97;KANGXI RADICAL PIG;So;0;ON;<compat> 8C55;;;;N;;;;; -2F98;KANGXI RADICAL BADGER;So;0;ON;<compat> 8C78;;;;N;;;;; -2F99;KANGXI RADICAL SHELL;So;0;ON;<compat> 8C9D;;;;N;;;;; -2F9A;KANGXI RADICAL RED;So;0;ON;<compat> 8D64;;;;N;;;;; -2F9B;KANGXI RADICAL RUN;So;0;ON;<compat> 8D70;;;;N;;;;; -2F9C;KANGXI RADICAL FOOT;So;0;ON;<compat> 8DB3;;;;N;;;;; -2F9D;KANGXI RADICAL BODY;So;0;ON;<compat> 8EAB;;;;N;;;;; -2F9E;KANGXI RADICAL CART;So;0;ON;<compat> 8ECA;;;;N;;;;; -2F9F;KANGXI RADICAL BITTER;So;0;ON;<compat> 8F9B;;;;N;;;;; -2FA0;KANGXI RADICAL MORNING;So;0;ON;<compat> 8FB0;;;;N;;;;; -2FA1;KANGXI RADICAL WALK;So;0;ON;<compat> 8FB5;;;;N;;;;; -2FA2;KANGXI RADICAL CITY;So;0;ON;<compat> 9091;;;;N;;;;; -2FA3;KANGXI RADICAL WINE;So;0;ON;<compat> 9149;;;;N;;;;; -2FA4;KANGXI RADICAL DISTINGUISH;So;0;ON;<compat> 91C6;;;;N;;;;; -2FA5;KANGXI RADICAL VILLAGE;So;0;ON;<compat> 91CC;;;;N;;;;; -2FA6;KANGXI RADICAL GOLD;So;0;ON;<compat> 91D1;;;;N;;;;; -2FA7;KANGXI RADICAL LONG;So;0;ON;<compat> 9577;;;;N;;;;; -2FA8;KANGXI RADICAL GATE;So;0;ON;<compat> 9580;;;;N;;;;; -2FA9;KANGXI RADICAL MOUND;So;0;ON;<compat> 961C;;;;N;;;;; -2FAA;KANGXI RADICAL SLAVE;So;0;ON;<compat> 96B6;;;;N;;;;; -2FAB;KANGXI RADICAL SHORT TAILED BIRD;So;0;ON;<compat> 96B9;;;;N;;;;; -2FAC;KANGXI RADICAL RAIN;So;0;ON;<compat> 96E8;;;;N;;;;; -2FAD;KANGXI RADICAL BLUE;So;0;ON;<compat> 9751;;;;N;;;;; -2FAE;KANGXI RADICAL WRONG;So;0;ON;<compat> 975E;;;;N;;;;; -2FAF;KANGXI RADICAL FACE;So;0;ON;<compat> 9762;;;;N;;;;; -2FB0;KANGXI RADICAL LEATHER;So;0;ON;<compat> 9769;;;;N;;;;; -2FB1;KANGXI RADICAL TANNED LEATHER;So;0;ON;<compat> 97CB;;;;N;;;;; -2FB2;KANGXI RADICAL LEEK;So;0;ON;<compat> 97ED;;;;N;;;;; -2FB3;KANGXI RADICAL SOUND;So;0;ON;<compat> 97F3;;;;N;;;;; -2FB4;KANGXI RADICAL LEAF;So;0;ON;<compat> 9801;;;;N;;;;; -2FB5;KANGXI RADICAL WIND;So;0;ON;<compat> 98A8;;;;N;;;;; -2FB6;KANGXI RADICAL FLY;So;0;ON;<compat> 98DB;;;;N;;;;; -2FB7;KANGXI RADICAL EAT;So;0;ON;<compat> 98DF;;;;N;;;;; -2FB8;KANGXI RADICAL HEAD;So;0;ON;<compat> 9996;;;;N;;;;; -2FB9;KANGXI RADICAL FRAGRANT;So;0;ON;<compat> 9999;;;;N;;;;; -2FBA;KANGXI RADICAL HORSE;So;0;ON;<compat> 99AC;;;;N;;;;; -2FBB;KANGXI RADICAL BONE;So;0;ON;<compat> 9AA8;;;;N;;;;; -2FBC;KANGXI RADICAL TALL;So;0;ON;<compat> 9AD8;;;;N;;;;; -2FBD;KANGXI RADICAL HAIR;So;0;ON;<compat> 9ADF;;;;N;;;;; -2FBE;KANGXI RADICAL FIGHT;So;0;ON;<compat> 9B25;;;;N;;;;; -2FBF;KANGXI RADICAL SACRIFICIAL WINE;So;0;ON;<compat> 9B2F;;;;N;;;;; -2FC0;KANGXI RADICAL CAULDRON;So;0;ON;<compat> 9B32;;;;N;;;;; -2FC1;KANGXI RADICAL GHOST;So;0;ON;<compat> 9B3C;;;;N;;;;; -2FC2;KANGXI RADICAL FISH;So;0;ON;<compat> 9B5A;;;;N;;;;; -2FC3;KANGXI RADICAL BIRD;So;0;ON;<compat> 9CE5;;;;N;;;;; -2FC4;KANGXI RADICAL SALT;So;0;ON;<compat> 9E75;;;;N;;;;; -2FC5;KANGXI RADICAL DEER;So;0;ON;<compat> 9E7F;;;;N;;;;; -2FC6;KANGXI RADICAL WHEAT;So;0;ON;<compat> 9EA5;;;;N;;;;; -2FC7;KANGXI RADICAL HEMP;So;0;ON;<compat> 9EBB;;;;N;;;;; -2FC8;KANGXI RADICAL YELLOW;So;0;ON;<compat> 9EC3;;;;N;;;;; -2FC9;KANGXI RADICAL MILLET;So;0;ON;<compat> 9ECD;;;;N;;;;; -2FCA;KANGXI RADICAL BLACK;So;0;ON;<compat> 9ED1;;;;N;;;;; -2FCB;KANGXI RADICAL EMBROIDERY;So;0;ON;<compat> 9EF9;;;;N;;;;; -2FCC;KANGXI RADICAL FROG;So;0;ON;<compat> 9EFD;;;;N;;;;; -2FCD;KANGXI RADICAL TRIPOD;So;0;ON;<compat> 9F0E;;;;N;;;;; -2FCE;KANGXI RADICAL DRUM;So;0;ON;<compat> 9F13;;;;N;;;;; -2FCF;KANGXI RADICAL RAT;So;0;ON;<compat> 9F20;;;;N;;;;; -2FD0;KANGXI RADICAL NOSE;So;0;ON;<compat> 9F3B;;;;N;;;;; -2FD1;KANGXI RADICAL EVEN;So;0;ON;<compat> 9F4A;;;;N;;;;; -2FD2;KANGXI RADICAL TOOTH;So;0;ON;<compat> 9F52;;;;N;;;;; -2FD3;KANGXI RADICAL DRAGON;So;0;ON;<compat> 9F8D;;;;N;;;;; -2FD4;KANGXI RADICAL TURTLE;So;0;ON;<compat> 9F9C;;;;N;;;;; -2FD5;KANGXI RADICAL FLUTE;So;0;ON;<compat> 9FA0;;;;N;;;;; -2FF0;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT;So;0;ON;;;;;N;;;;; -2FF1;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO BELOW;So;0;ON;;;;;N;;;;; -2FF2;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO MIDDLE AND RIGHT;So;0;ON;;;;;N;;;;; -2FF3;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO MIDDLE AND BELOW;So;0;ON;;;;;N;;;;; -2FF4;IDEOGRAPHIC DESCRIPTION CHARACTER FULL SURROUND;So;0;ON;;;;;N;;;;; -2FF5;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM ABOVE;So;0;ON;;;;;N;;;;; -2FF6;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM BELOW;So;0;ON;;;;;N;;;;; -2FF7;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LEFT;So;0;ON;;;;;N;;;;; -2FF8;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER LEFT;So;0;ON;;;;;N;;;;; -2FF9;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER RIGHT;So;0;ON;;;;;N;;;;; -2FFA;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LOWER LEFT;So;0;ON;;;;;N;;;;; -2FFB;IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID;So;0;ON;;;;;N;;;;; -2FFC;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM RIGHT;So;0;ON;;;;;N;;;;; -2FFD;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LOWER RIGHT;So;0;ON;;;;;N;;;;; -2FFE;IDEOGRAPHIC DESCRIPTION CHARACTER HORIZONTAL REFLECTION;So;0;ON;;;;;N;;;;; -2FFF;IDEOGRAPHIC DESCRIPTION CHARACTER ROTATION;So;0;ON;;;;;N;;;;; -3000;IDEOGRAPHIC SPACE;Zs;0;WS;<wide> 0020;;;;N;;;;; -3001;IDEOGRAPHIC COMMA;Po;0;ON;;;;;N;;;;; -3002;IDEOGRAPHIC FULL STOP;Po;0;ON;;;;;N;IDEOGRAPHIC PERIOD;;;; -3003;DITTO MARK;Po;0;ON;;;;;N;;;;; -3004;JAPANESE INDUSTRIAL STANDARD SYMBOL;So;0;ON;;;;;N;;;;; -3005;IDEOGRAPHIC ITERATION MARK;Lm;0;L;;;;;N;;;;; -3006;IDEOGRAPHIC CLOSING MARK;Lo;0;L;;;;;N;;;;; -3007;IDEOGRAPHIC NUMBER ZERO;Nl;0;L;;;;0;N;;;;; -3008;LEFT ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING ANGLE BRACKET;;;; -3009;RIGHT ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING ANGLE BRACKET;;;; -300A;LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING DOUBLE ANGLE BRACKET;;;; -300B;RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING DOUBLE ANGLE BRACKET;;;; -300C;LEFT CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING CORNER BRACKET;;;; -300D;RIGHT CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING CORNER BRACKET;;;; -300E;LEFT WHITE CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE CORNER BRACKET;;;; -300F;RIGHT WHITE CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE CORNER BRACKET;;;; -3010;LEFT BLACK LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING BLACK LENTICULAR BRACKET;;;; -3011;RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING BLACK LENTICULAR BRACKET;;;; -3012;POSTAL MARK;So;0;ON;;;;;N;;;;; -3013;GETA MARK;So;0;ON;;;;;N;;;;; -3014;LEFT TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING TORTOISE SHELL BRACKET;;;; -3015;RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING TORTOISE SHELL BRACKET;;;; -3016;LEFT WHITE LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE LENTICULAR BRACKET;;;; -3017;RIGHT WHITE LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE LENTICULAR BRACKET;;;; -3018;LEFT WHITE TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE TORTOISE SHELL BRACKET;;;; -3019;RIGHT WHITE TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE TORTOISE SHELL BRACKET;;;; -301A;LEFT WHITE SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE SQUARE BRACKET;;;; -301B;RIGHT WHITE SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE SQUARE BRACKET;;;; -301C;WAVE DASH;Pd;0;ON;;;;;N;;;;; -301D;REVERSED DOUBLE PRIME QUOTATION MARK;Ps;0;ON;;;;;N;;;;; -301E;DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;; -301F;LOW DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;; -3020;POSTAL MARK FACE;So;0;ON;;;;;N;;;;; -3021;HANGZHOU NUMERAL ONE;Nl;0;L;;;;1;N;;;;; -3022;HANGZHOU NUMERAL TWO;Nl;0;L;;;;2;N;;;;; -3023;HANGZHOU NUMERAL THREE;Nl;0;L;;;;3;N;;;;; -3024;HANGZHOU NUMERAL FOUR;Nl;0;L;;;;4;N;;;;; -3025;HANGZHOU NUMERAL FIVE;Nl;0;L;;;;5;N;;;;; -3026;HANGZHOU NUMERAL SIX;Nl;0;L;;;;6;N;;;;; -3027;HANGZHOU NUMERAL SEVEN;Nl;0;L;;;;7;N;;;;; -3028;HANGZHOU NUMERAL EIGHT;Nl;0;L;;;;8;N;;;;; -3029;HANGZHOU NUMERAL NINE;Nl;0;L;;;;9;N;;;;; -302A;IDEOGRAPHIC LEVEL TONE MARK;Mn;218;NSM;;;;;N;;;;; -302B;IDEOGRAPHIC RISING TONE MARK;Mn;228;NSM;;;;;N;;;;; -302C;IDEOGRAPHIC DEPARTING TONE MARK;Mn;232;NSM;;;;;N;;;;; -302D;IDEOGRAPHIC ENTERING TONE MARK;Mn;222;NSM;;;;;N;;;;; -302E;HANGUL SINGLE DOT TONE MARK;Mc;224;L;;;;;N;;;;; -302F;HANGUL DOUBLE DOT TONE MARK;Mc;224;L;;;;;N;;;;; -3030;WAVY DASH;Pd;0;ON;;;;;N;;;;; -3031;VERTICAL KANA REPEAT MARK;Lm;0;L;;;;;N;;;;; -3032;VERTICAL KANA REPEAT WITH VOICED SOUND MARK;Lm;0;L;;;;;N;;;;; -3033;VERTICAL KANA REPEAT MARK UPPER HALF;Lm;0;L;;;;;N;;;;; -3034;VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF;Lm;0;L;;;;;N;;;;; -3035;VERTICAL KANA REPEAT MARK LOWER HALF;Lm;0;L;;;;;N;;;;; -3036;CIRCLED POSTAL MARK;So;0;ON;<compat> 3012;;;;N;;;;; -3037;IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL;So;0;ON;;;;;N;;;;; -3038;HANGZHOU NUMERAL TEN;Nl;0;L;<compat> 5341;;;10;N;;;;; -3039;HANGZHOU NUMERAL TWENTY;Nl;0;L;<compat> 5344;;;20;N;;;;; -303A;HANGZHOU NUMERAL THIRTY;Nl;0;L;<compat> 5345;;;30;N;;;;; -303B;VERTICAL IDEOGRAPHIC ITERATION MARK;Lm;0;L;;;;;N;;;;; -303C;MASU MARK;Lo;0;L;;;;;N;;;;; -303D;PART ALTERNATION MARK;Po;0;ON;;;;;N;;;;; -303E;IDEOGRAPHIC VARIATION INDICATOR;So;0;ON;;;;;N;;;;; -303F;IDEOGRAPHIC HALF FILL SPACE;So;0;ON;;;;;N;;;;; -3041;HIRAGANA LETTER SMALL A;Lo;0;L;;;;;N;;;;; -3042;HIRAGANA LETTER A;Lo;0;L;;;;;N;;;;; -3043;HIRAGANA LETTER SMALL I;Lo;0;L;;;;;N;;;;; -3044;HIRAGANA LETTER I;Lo;0;L;;;;;N;;;;; -3045;HIRAGANA LETTER SMALL U;Lo;0;L;;;;;N;;;;; -3046;HIRAGANA LETTER U;Lo;0;L;;;;;N;;;;; -3047;HIRAGANA LETTER SMALL E;Lo;0;L;;;;;N;;;;; -3048;HIRAGANA LETTER E;Lo;0;L;;;;;N;;;;; -3049;HIRAGANA LETTER SMALL O;Lo;0;L;;;;;N;;;;; -304A;HIRAGANA LETTER O;Lo;0;L;;;;;N;;;;; -304B;HIRAGANA LETTER KA;Lo;0;L;;;;;N;;;;; -304C;HIRAGANA LETTER GA;Lo;0;L;304B 3099;;;;N;;;;; -304D;HIRAGANA LETTER KI;Lo;0;L;;;;;N;;;;; -304E;HIRAGANA LETTER GI;Lo;0;L;304D 3099;;;;N;;;;; -304F;HIRAGANA LETTER KU;Lo;0;L;;;;;N;;;;; -3050;HIRAGANA LETTER GU;Lo;0;L;304F 3099;;;;N;;;;; -3051;HIRAGANA LETTER KE;Lo;0;L;;;;;N;;;;; -3052;HIRAGANA LETTER GE;Lo;0;L;3051 3099;;;;N;;;;; -3053;HIRAGANA LETTER KO;Lo;0;L;;;;;N;;;;; -3054;HIRAGANA LETTER GO;Lo;0;L;3053 3099;;;;N;;;;; -3055;HIRAGANA LETTER SA;Lo;0;L;;;;;N;;;;; -3056;HIRAGANA LETTER ZA;Lo;0;L;3055 3099;;;;N;;;;; -3057;HIRAGANA LETTER SI;Lo;0;L;;;;;N;;;;; -3058;HIRAGANA LETTER ZI;Lo;0;L;3057 3099;;;;N;;;;; -3059;HIRAGANA LETTER SU;Lo;0;L;;;;;N;;;;; -305A;HIRAGANA LETTER ZU;Lo;0;L;3059 3099;;;;N;;;;; -305B;HIRAGANA LETTER SE;Lo;0;L;;;;;N;;;;; -305C;HIRAGANA LETTER ZE;Lo;0;L;305B 3099;;;;N;;;;; -305D;HIRAGANA LETTER SO;Lo;0;L;;;;;N;;;;; -305E;HIRAGANA LETTER ZO;Lo;0;L;305D 3099;;;;N;;;;; -305F;HIRAGANA LETTER TA;Lo;0;L;;;;;N;;;;; -3060;HIRAGANA LETTER DA;Lo;0;L;305F 3099;;;;N;;;;; -3061;HIRAGANA LETTER TI;Lo;0;L;;;;;N;;;;; -3062;HIRAGANA LETTER DI;Lo;0;L;3061 3099;;;;N;;;;; -3063;HIRAGANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;; -3064;HIRAGANA LETTER TU;Lo;0;L;;;;;N;;;;; -3065;HIRAGANA LETTER DU;Lo;0;L;3064 3099;;;;N;;;;; -3066;HIRAGANA LETTER TE;Lo;0;L;;;;;N;;;;; -3067;HIRAGANA LETTER DE;Lo;0;L;3066 3099;;;;N;;;;; -3068;HIRAGANA LETTER TO;Lo;0;L;;;;;N;;;;; -3069;HIRAGANA LETTER DO;Lo;0;L;3068 3099;;;;N;;;;; -306A;HIRAGANA LETTER NA;Lo;0;L;;;;;N;;;;; -306B;HIRAGANA LETTER NI;Lo;0;L;;;;;N;;;;; -306C;HIRAGANA LETTER NU;Lo;0;L;;;;;N;;;;; -306D;HIRAGANA LETTER NE;Lo;0;L;;;;;N;;;;; -306E;HIRAGANA LETTER NO;Lo;0;L;;;;;N;;;;; -306F;HIRAGANA LETTER HA;Lo;0;L;;;;;N;;;;; -3070;HIRAGANA LETTER BA;Lo;0;L;306F 3099;;;;N;;;;; -3071;HIRAGANA LETTER PA;Lo;0;L;306F 309A;;;;N;;;;; -3072;HIRAGANA LETTER HI;Lo;0;L;;;;;N;;;;; -3073;HIRAGANA LETTER BI;Lo;0;L;3072 3099;;;;N;;;;; -3074;HIRAGANA LETTER PI;Lo;0;L;3072 309A;;;;N;;;;; -3075;HIRAGANA LETTER HU;Lo;0;L;;;;;N;;;;; -3076;HIRAGANA LETTER BU;Lo;0;L;3075 3099;;;;N;;;;; -3077;HIRAGANA LETTER PU;Lo;0;L;3075 309A;;;;N;;;;; -3078;HIRAGANA LETTER HE;Lo;0;L;;;;;N;;;;; -3079;HIRAGANA LETTER BE;Lo;0;L;3078 3099;;;;N;;;;; -307A;HIRAGANA LETTER PE;Lo;0;L;3078 309A;;;;N;;;;; -307B;HIRAGANA LETTER HO;Lo;0;L;;;;;N;;;;; -307C;HIRAGANA LETTER BO;Lo;0;L;307B 3099;;;;N;;;;; -307D;HIRAGANA LETTER PO;Lo;0;L;307B 309A;;;;N;;;;; -307E;HIRAGANA LETTER MA;Lo;0;L;;;;;N;;;;; -307F;HIRAGANA LETTER MI;Lo;0;L;;;;;N;;;;; -3080;HIRAGANA LETTER MU;Lo;0;L;;;;;N;;;;; -3081;HIRAGANA LETTER ME;Lo;0;L;;;;;N;;;;; -3082;HIRAGANA LETTER MO;Lo;0;L;;;;;N;;;;; -3083;HIRAGANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;; -3084;HIRAGANA LETTER YA;Lo;0;L;;;;;N;;;;; -3085;HIRAGANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;; -3086;HIRAGANA LETTER YU;Lo;0;L;;;;;N;;;;; -3087;HIRAGANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;; -3088;HIRAGANA LETTER YO;Lo;0;L;;;;;N;;;;; -3089;HIRAGANA LETTER RA;Lo;0;L;;;;;N;;;;; -308A;HIRAGANA LETTER RI;Lo;0;L;;;;;N;;;;; -308B;HIRAGANA LETTER RU;Lo;0;L;;;;;N;;;;; -308C;HIRAGANA LETTER RE;Lo;0;L;;;;;N;;;;; -308D;HIRAGANA LETTER RO;Lo;0;L;;;;;N;;;;; -308E;HIRAGANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;; -308F;HIRAGANA LETTER WA;Lo;0;L;;;;;N;;;;; -3090;HIRAGANA LETTER WI;Lo;0;L;;;;;N;;;;; -3091;HIRAGANA LETTER WE;Lo;0;L;;;;;N;;;;; -3092;HIRAGANA LETTER WO;Lo;0;L;;;;;N;;;;; -3093;HIRAGANA LETTER N;Lo;0;L;;;;;N;;;;; -3094;HIRAGANA LETTER VU;Lo;0;L;3046 3099;;;;N;;;;; -3095;HIRAGANA LETTER SMALL KA;Lo;0;L;;;;;N;;;;; -3096;HIRAGANA LETTER SMALL KE;Lo;0;L;;;;;N;;;;; -3099;COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA VOICED SOUND MARK;;;; -309A;COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;;;; -309B;KATAKANA-HIRAGANA VOICED SOUND MARK;Sk;0;ON;<compat> 0020 3099;;;;N;;;;; -309C;KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Sk;0;ON;<compat> 0020 309A;;;;N;;;;; -309D;HIRAGANA ITERATION MARK;Lm;0;L;;;;;N;;;;; -309E;HIRAGANA VOICED ITERATION MARK;Lm;0;L;309D 3099;;;;N;;;;; -309F;HIRAGANA DIGRAPH YORI;Lo;0;L;<vertical> 3088 308A;;;;N;;;;; -30A0;KATAKANA-HIRAGANA DOUBLE HYPHEN;Pd;0;ON;;;;;N;;;;; -30A1;KATAKANA LETTER SMALL A;Lo;0;L;;;;;N;;;;; -30A2;KATAKANA LETTER A;Lo;0;L;;;;;N;;;;; -30A3;KATAKANA LETTER SMALL I;Lo;0;L;;;;;N;;;;; -30A4;KATAKANA LETTER I;Lo;0;L;;;;;N;;;;; -30A5;KATAKANA LETTER SMALL U;Lo;0;L;;;;;N;;;;; -30A6;KATAKANA LETTER U;Lo;0;L;;;;;N;;;;; -30A7;KATAKANA LETTER SMALL E;Lo;0;L;;;;;N;;;;; -30A8;KATAKANA LETTER E;Lo;0;L;;;;;N;;;;; -30A9;KATAKANA LETTER SMALL O;Lo;0;L;;;;;N;;;;; -30AA;KATAKANA LETTER O;Lo;0;L;;;;;N;;;;; -30AB;KATAKANA LETTER KA;Lo;0;L;;;;;N;;;;; -30AC;KATAKANA LETTER GA;Lo;0;L;30AB 3099;;;;N;;;;; -30AD;KATAKANA LETTER KI;Lo;0;L;;;;;N;;;;; -30AE;KATAKANA LETTER GI;Lo;0;L;30AD 3099;;;;N;;;;; -30AF;KATAKANA LETTER KU;Lo;0;L;;;;;N;;;;; -30B0;KATAKANA LETTER GU;Lo;0;L;30AF 3099;;;;N;;;;; -30B1;KATAKANA LETTER KE;Lo;0;L;;;;;N;;;;; -30B2;KATAKANA LETTER GE;Lo;0;L;30B1 3099;;;;N;;;;; -30B3;KATAKANA LETTER KO;Lo;0;L;;;;;N;;;;; -30B4;KATAKANA LETTER GO;Lo;0;L;30B3 3099;;;;N;;;;; -30B5;KATAKANA LETTER SA;Lo;0;L;;;;;N;;;;; -30B6;KATAKANA LETTER ZA;Lo;0;L;30B5 3099;;;;N;;;;; -30B7;KATAKANA LETTER SI;Lo;0;L;;;;;N;;;;; -30B8;KATAKANA LETTER ZI;Lo;0;L;30B7 3099;;;;N;;;;; -30B9;KATAKANA LETTER SU;Lo;0;L;;;;;N;;;;; -30BA;KATAKANA LETTER ZU;Lo;0;L;30B9 3099;;;;N;;;;; -30BB;KATAKANA LETTER SE;Lo;0;L;;;;;N;;;;; -30BC;KATAKANA LETTER ZE;Lo;0;L;30BB 3099;;;;N;;;;; -30BD;KATAKANA LETTER SO;Lo;0;L;;;;;N;;;;; -30BE;KATAKANA LETTER ZO;Lo;0;L;30BD 3099;;;;N;;;;; -30BF;KATAKANA LETTER TA;Lo;0;L;;;;;N;;;;; -30C0;KATAKANA LETTER DA;Lo;0;L;30BF 3099;;;;N;;;;; -30C1;KATAKANA LETTER TI;Lo;0;L;;;;;N;;;;; -30C2;KATAKANA LETTER DI;Lo;0;L;30C1 3099;;;;N;;;;; -30C3;KATAKANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;; -30C4;KATAKANA LETTER TU;Lo;0;L;;;;;N;;;;; -30C5;KATAKANA LETTER DU;Lo;0;L;30C4 3099;;;;N;;;;; -30C6;KATAKANA LETTER TE;Lo;0;L;;;;;N;;;;; -30C7;KATAKANA LETTER DE;Lo;0;L;30C6 3099;;;;N;;;;; -30C8;KATAKANA LETTER TO;Lo;0;L;;;;;N;;;;; -30C9;KATAKANA LETTER DO;Lo;0;L;30C8 3099;;;;N;;;;; -30CA;KATAKANA LETTER NA;Lo;0;L;;;;;N;;;;; -30CB;KATAKANA LETTER NI;Lo;0;L;;;;;N;;;;; -30CC;KATAKANA LETTER NU;Lo;0;L;;;;;N;;;;; -30CD;KATAKANA LETTER NE;Lo;0;L;;;;;N;;;;; -30CE;KATAKANA LETTER NO;Lo;0;L;;;;;N;;;;; -30CF;KATAKANA LETTER HA;Lo;0;L;;;;;N;;;;; -30D0;KATAKANA LETTER BA;Lo;0;L;30CF 3099;;;;N;;;;; -30D1;KATAKANA LETTER PA;Lo;0;L;30CF 309A;;;;N;;;;; -30D2;KATAKANA LETTER HI;Lo;0;L;;;;;N;;;;; -30D3;KATAKANA LETTER BI;Lo;0;L;30D2 3099;;;;N;;;;; -30D4;KATAKANA LETTER PI;Lo;0;L;30D2 309A;;;;N;;;;; -30D5;KATAKANA LETTER HU;Lo;0;L;;;;;N;;;;; -30D6;KATAKANA LETTER BU;Lo;0;L;30D5 3099;;;;N;;;;; -30D7;KATAKANA LETTER PU;Lo;0;L;30D5 309A;;;;N;;;;; -30D8;KATAKANA LETTER HE;Lo;0;L;;;;;N;;;;; -30D9;KATAKANA LETTER BE;Lo;0;L;30D8 3099;;;;N;;;;; -30DA;KATAKANA LETTER PE;Lo;0;L;30D8 309A;;;;N;;;;; -30DB;KATAKANA LETTER HO;Lo;0;L;;;;;N;;;;; -30DC;KATAKANA LETTER BO;Lo;0;L;30DB 3099;;;;N;;;;; -30DD;KATAKANA LETTER PO;Lo;0;L;30DB 309A;;;;N;;;;; -30DE;KATAKANA LETTER MA;Lo;0;L;;;;;N;;;;; -30DF;KATAKANA LETTER MI;Lo;0;L;;;;;N;;;;; -30E0;KATAKANA LETTER MU;Lo;0;L;;;;;N;;;;; -30E1;KATAKANA LETTER ME;Lo;0;L;;;;;N;;;;; -30E2;KATAKANA LETTER MO;Lo;0;L;;;;;N;;;;; -30E3;KATAKANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;; -30E4;KATAKANA LETTER YA;Lo;0;L;;;;;N;;;;; -30E5;KATAKANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;; -30E6;KATAKANA LETTER YU;Lo;0;L;;;;;N;;;;; -30E7;KATAKANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;; -30E8;KATAKANA LETTER YO;Lo;0;L;;;;;N;;;;; -30E9;KATAKANA LETTER RA;Lo;0;L;;;;;N;;;;; -30EA;KATAKANA LETTER RI;Lo;0;L;;;;;N;;;;; -30EB;KATAKANA LETTER RU;Lo;0;L;;;;;N;;;;; -30EC;KATAKANA LETTER RE;Lo;0;L;;;;;N;;;;; -30ED;KATAKANA LETTER RO;Lo;0;L;;;;;N;;;;; -30EE;KATAKANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;; -30EF;KATAKANA LETTER WA;Lo;0;L;;;;;N;;;;; -30F0;KATAKANA LETTER WI;Lo;0;L;;;;;N;;;;; -30F1;KATAKANA LETTER WE;Lo;0;L;;;;;N;;;;; -30F2;KATAKANA LETTER WO;Lo;0;L;;;;;N;;;;; -30F3;KATAKANA LETTER N;Lo;0;L;;;;;N;;;;; -30F4;KATAKANA LETTER VU;Lo;0;L;30A6 3099;;;;N;;;;; -30F5;KATAKANA LETTER SMALL KA;Lo;0;L;;;;;N;;;;; -30F6;KATAKANA LETTER SMALL KE;Lo;0;L;;;;;N;;;;; -30F7;KATAKANA LETTER VA;Lo;0;L;30EF 3099;;;;N;;;;; -30F8;KATAKANA LETTER VI;Lo;0;L;30F0 3099;;;;N;;;;; -30F9;KATAKANA LETTER VE;Lo;0;L;30F1 3099;;;;N;;;;; -30FA;KATAKANA LETTER VO;Lo;0;L;30F2 3099;;;;N;;;;; -30FB;KATAKANA MIDDLE DOT;Po;0;ON;;;;;N;;;;; -30FC;KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L;;;;;N;;;;; -30FD;KATAKANA ITERATION MARK;Lm;0;L;;;;;N;;;;; -30FE;KATAKANA VOICED ITERATION MARK;Lm;0;L;30FD 3099;;;;N;;;;; -30FF;KATAKANA DIGRAPH KOTO;Lo;0;L;<vertical> 30B3 30C8;;;;N;;;;; -3105;BOPOMOFO LETTER B;Lo;0;L;;;;;N;;;;; -3106;BOPOMOFO LETTER P;Lo;0;L;;;;;N;;;;; -3107;BOPOMOFO LETTER M;Lo;0;L;;;;;N;;;;; -3108;BOPOMOFO LETTER F;Lo;0;L;;;;;N;;;;; -3109;BOPOMOFO LETTER D;Lo;0;L;;;;;N;;;;; -310A;BOPOMOFO LETTER T;Lo;0;L;;;;;N;;;;; -310B;BOPOMOFO LETTER N;Lo;0;L;;;;;N;;;;; -310C;BOPOMOFO LETTER L;Lo;0;L;;;;;N;;;;; -310D;BOPOMOFO LETTER G;Lo;0;L;;;;;N;;;;; -310E;BOPOMOFO LETTER K;Lo;0;L;;;;;N;;;;; -310F;BOPOMOFO LETTER H;Lo;0;L;;;;;N;;;;; -3110;BOPOMOFO LETTER J;Lo;0;L;;;;;N;;;;; -3111;BOPOMOFO LETTER Q;Lo;0;L;;;;;N;;;;; -3112;BOPOMOFO LETTER X;Lo;0;L;;;;;N;;;;; -3113;BOPOMOFO LETTER ZH;Lo;0;L;;;;;N;;;;; -3114;BOPOMOFO LETTER CH;Lo;0;L;;;;;N;;;;; -3115;BOPOMOFO LETTER SH;Lo;0;L;;;;;N;;;;; -3116;BOPOMOFO LETTER R;Lo;0;L;;;;;N;;;;; -3117;BOPOMOFO LETTER Z;Lo;0;L;;;;;N;;;;; -3118;BOPOMOFO LETTER C;Lo;0;L;;;;;N;;;;; -3119;BOPOMOFO LETTER S;Lo;0;L;;;;;N;;;;; -311A;BOPOMOFO LETTER A;Lo;0;L;;;;;N;;;;; -311B;BOPOMOFO LETTER O;Lo;0;L;;;;;N;;;;; -311C;BOPOMOFO LETTER E;Lo;0;L;;;;;N;;;;; -311D;BOPOMOFO LETTER EH;Lo;0;L;;;;;N;;;;; -311E;BOPOMOFO LETTER AI;Lo;0;L;;;;;N;;;;; -311F;BOPOMOFO LETTER EI;Lo;0;L;;;;;N;;;;; -3120;BOPOMOFO LETTER AU;Lo;0;L;;;;;N;;;;; -3121;BOPOMOFO LETTER OU;Lo;0;L;;;;;N;;;;; -3122;BOPOMOFO LETTER AN;Lo;0;L;;;;;N;;;;; -3123;BOPOMOFO LETTER EN;Lo;0;L;;;;;N;;;;; -3124;BOPOMOFO LETTER ANG;Lo;0;L;;;;;N;;;;; -3125;BOPOMOFO LETTER ENG;Lo;0;L;;;;;N;;;;; -3126;BOPOMOFO LETTER ER;Lo;0;L;;;;;N;;;;; -3127;BOPOMOFO LETTER I;Lo;0;L;;;;;N;;;;; -3128;BOPOMOFO LETTER U;Lo;0;L;;;;;N;;;;; -3129;BOPOMOFO LETTER IU;Lo;0;L;;;;;N;;;;; -312A;BOPOMOFO LETTER V;Lo;0;L;;;;;N;;;;; -312B;BOPOMOFO LETTER NG;Lo;0;L;;;;;N;;;;; -312C;BOPOMOFO LETTER GN;Lo;0;L;;;;;N;;;;; -312D;BOPOMOFO LETTER IH;Lo;0;L;;;;;N;;;;; -312E;BOPOMOFO LETTER O WITH DOT ABOVE;Lo;0;L;;;;;N;;;;; -312F;BOPOMOFO LETTER NN;Lo;0;L;;;;;N;;;;; -3131;HANGUL LETTER KIYEOK;Lo;0;L;<compat> 1100;;;;N;HANGUL LETTER GIYEOG;;;; -3132;HANGUL LETTER SSANGKIYEOK;Lo;0;L;<compat> 1101;;;;N;HANGUL LETTER SSANG GIYEOG;;;; -3133;HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<compat> 11AA;;;;N;HANGUL LETTER GIYEOG SIOS;;;; -3134;HANGUL LETTER NIEUN;Lo;0;L;<compat> 1102;;;;N;;;;; -3135;HANGUL LETTER NIEUN-CIEUC;Lo;0;L;<compat> 11AC;;;;N;HANGUL LETTER NIEUN JIEUJ;;;; -3136;HANGUL LETTER NIEUN-HIEUH;Lo;0;L;<compat> 11AD;;;;N;HANGUL LETTER NIEUN HIEUH;;;; -3137;HANGUL LETTER TIKEUT;Lo;0;L;<compat> 1103;;;;N;HANGUL LETTER DIGEUD;;;; -3138;HANGUL LETTER SSANGTIKEUT;Lo;0;L;<compat> 1104;;;;N;HANGUL LETTER SSANG DIGEUD;;;; -3139;HANGUL LETTER RIEUL;Lo;0;L;<compat> 1105;;;;N;HANGUL LETTER LIEUL;;;; -313A;HANGUL LETTER RIEUL-KIYEOK;Lo;0;L;<compat> 11B0;;;;N;HANGUL LETTER LIEUL GIYEOG;;;; -313B;HANGUL LETTER RIEUL-MIEUM;Lo;0;L;<compat> 11B1;;;;N;HANGUL LETTER LIEUL MIEUM;;;; -313C;HANGUL LETTER RIEUL-PIEUP;Lo;0;L;<compat> 11B2;;;;N;HANGUL LETTER LIEUL BIEUB;;;; -313D;HANGUL LETTER RIEUL-SIOS;Lo;0;L;<compat> 11B3;;;;N;HANGUL LETTER LIEUL SIOS;;;; -313E;HANGUL LETTER RIEUL-THIEUTH;Lo;0;L;<compat> 11B4;;;;N;HANGUL LETTER LIEUL TIEUT;;;; -313F;HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L;<compat> 11B5;;;;N;HANGUL LETTER LIEUL PIEUP;;;; -3140;HANGUL LETTER RIEUL-HIEUH;Lo;0;L;<compat> 111A;;;;N;HANGUL LETTER LIEUL HIEUH;;;; -3141;HANGUL LETTER MIEUM;Lo;0;L;<compat> 1106;;;;N;;;;; -3142;HANGUL LETTER PIEUP;Lo;0;L;<compat> 1107;;;;N;HANGUL LETTER BIEUB;;;; -3143;HANGUL LETTER SSANGPIEUP;Lo;0;L;<compat> 1108;;;;N;HANGUL LETTER SSANG BIEUB;;;; -3144;HANGUL LETTER PIEUP-SIOS;Lo;0;L;<compat> 1121;;;;N;HANGUL LETTER BIEUB SIOS;;;; -3145;HANGUL LETTER SIOS;Lo;0;L;<compat> 1109;;;;N;;;;; -3146;HANGUL LETTER SSANGSIOS;Lo;0;L;<compat> 110A;;;;N;HANGUL LETTER SSANG SIOS;;;; -3147;HANGUL LETTER IEUNG;Lo;0;L;<compat> 110B;;;;N;;;;; -3148;HANGUL LETTER CIEUC;Lo;0;L;<compat> 110C;;;;N;HANGUL LETTER JIEUJ;;;; -3149;HANGUL LETTER SSANGCIEUC;Lo;0;L;<compat> 110D;;;;N;HANGUL LETTER SSANG JIEUJ;;;; -314A;HANGUL LETTER CHIEUCH;Lo;0;L;<compat> 110E;;;;N;HANGUL LETTER CIEUC;;;; -314B;HANGUL LETTER KHIEUKH;Lo;0;L;<compat> 110F;;;;N;HANGUL LETTER KIYEOK;;;; -314C;HANGUL LETTER THIEUTH;Lo;0;L;<compat> 1110;;;;N;HANGUL LETTER TIEUT;;;; -314D;HANGUL LETTER PHIEUPH;Lo;0;L;<compat> 1111;;;;N;HANGUL LETTER PIEUP;;;; -314E;HANGUL LETTER HIEUH;Lo;0;L;<compat> 1112;;;;N;;;;; -314F;HANGUL LETTER A;Lo;0;L;<compat> 1161;;;;N;;;;; -3150;HANGUL LETTER AE;Lo;0;L;<compat> 1162;;;;N;;;;; -3151;HANGUL LETTER YA;Lo;0;L;<compat> 1163;;;;N;;;;; -3152;HANGUL LETTER YAE;Lo;0;L;<compat> 1164;;;;N;;;;; -3153;HANGUL LETTER EO;Lo;0;L;<compat> 1165;;;;N;;;;; -3154;HANGUL LETTER E;Lo;0;L;<compat> 1166;;;;N;;;;; -3155;HANGUL LETTER YEO;Lo;0;L;<compat> 1167;;;;N;;;;; -3156;HANGUL LETTER YE;Lo;0;L;<compat> 1168;;;;N;;;;; -3157;HANGUL LETTER O;Lo;0;L;<compat> 1169;;;;N;;;;; -3158;HANGUL LETTER WA;Lo;0;L;<compat> 116A;;;;N;;;;; -3159;HANGUL LETTER WAE;Lo;0;L;<compat> 116B;;;;N;;;;; -315A;HANGUL LETTER OE;Lo;0;L;<compat> 116C;;;;N;;;;; -315B;HANGUL LETTER YO;Lo;0;L;<compat> 116D;;;;N;;;;; -315C;HANGUL LETTER U;Lo;0;L;<compat> 116E;;;;N;;;;; -315D;HANGUL LETTER WEO;Lo;0;L;<compat> 116F;;;;N;;;;; -315E;HANGUL LETTER WE;Lo;0;L;<compat> 1170;;;;N;;;;; -315F;HANGUL LETTER WI;Lo;0;L;<compat> 1171;;;;N;;;;; -3160;HANGUL LETTER YU;Lo;0;L;<compat> 1172;;;;N;;;;; -3161;HANGUL LETTER EU;Lo;0;L;<compat> 1173;;;;N;;;;; -3162;HANGUL LETTER YI;Lo;0;L;<compat> 1174;;;;N;;;;; -3163;HANGUL LETTER I;Lo;0;L;<compat> 1175;;;;N;;;;; -3164;HANGUL FILLER;Lo;0;L;<compat> 1160;;;;N;HANGUL CAE OM;;;; -3165;HANGUL LETTER SSANGNIEUN;Lo;0;L;<compat> 1114;;;;N;HANGUL LETTER SSANG NIEUN;;;; -3166;HANGUL LETTER NIEUN-TIKEUT;Lo;0;L;<compat> 1115;;;;N;HANGUL LETTER NIEUN DIGEUD;;;; -3167;HANGUL LETTER NIEUN-SIOS;Lo;0;L;<compat> 11C7;;;;N;HANGUL LETTER NIEUN SIOS;;;; -3168;HANGUL LETTER NIEUN-PANSIOS;Lo;0;L;<compat> 11C8;;;;N;HANGUL LETTER NIEUN BAN CHI EUM;;;; -3169;HANGUL LETTER RIEUL-KIYEOK-SIOS;Lo;0;L;<compat> 11CC;;;;N;HANGUL LETTER LIEUL GIYEOG SIOS;;;; -316A;HANGUL LETTER RIEUL-TIKEUT;Lo;0;L;<compat> 11CE;;;;N;HANGUL LETTER LIEUL DIGEUD;;;; -316B;HANGUL LETTER RIEUL-PIEUP-SIOS;Lo;0;L;<compat> 11D3;;;;N;HANGUL LETTER LIEUL BIEUB SIOS;;;; -316C;HANGUL LETTER RIEUL-PANSIOS;Lo;0;L;<compat> 11D7;;;;N;HANGUL LETTER LIEUL BAN CHI EUM;;;; -316D;HANGUL LETTER RIEUL-YEORINHIEUH;Lo;0;L;<compat> 11D9;;;;N;HANGUL LETTER LIEUL YEOLIN HIEUH;;;; -316E;HANGUL LETTER MIEUM-PIEUP;Lo;0;L;<compat> 111C;;;;N;HANGUL LETTER MIEUM BIEUB;;;; -316F;HANGUL LETTER MIEUM-SIOS;Lo;0;L;<compat> 11DD;;;;N;HANGUL LETTER MIEUM SIOS;;;; -3170;HANGUL LETTER MIEUM-PANSIOS;Lo;0;L;<compat> 11DF;;;;N;HANGUL LETTER BIEUB BAN CHI EUM;;;; -3171;HANGUL LETTER KAPYEOUNMIEUM;Lo;0;L;<compat> 111D;;;;N;HANGUL LETTER MIEUM SUN GYEONG EUM;;;; -3172;HANGUL LETTER PIEUP-KIYEOK;Lo;0;L;<compat> 111E;;;;N;HANGUL LETTER BIEUB GIYEOG;;;; -3173;HANGUL LETTER PIEUP-TIKEUT;Lo;0;L;<compat> 1120;;;;N;HANGUL LETTER BIEUB DIGEUD;;;; -3174;HANGUL LETTER PIEUP-SIOS-KIYEOK;Lo;0;L;<compat> 1122;;;;N;HANGUL LETTER BIEUB SIOS GIYEOG;;;; -3175;HANGUL LETTER PIEUP-SIOS-TIKEUT;Lo;0;L;<compat> 1123;;;;N;HANGUL LETTER BIEUB SIOS DIGEUD;;;; -3176;HANGUL LETTER PIEUP-CIEUC;Lo;0;L;<compat> 1127;;;;N;HANGUL LETTER BIEUB JIEUJ;;;; -3177;HANGUL LETTER PIEUP-THIEUTH;Lo;0;L;<compat> 1129;;;;N;HANGUL LETTER BIEUB TIEUT;;;; -3178;HANGUL LETTER KAPYEOUNPIEUP;Lo;0;L;<compat> 112B;;;;N;HANGUL LETTER BIEUB SUN GYEONG EUM;;;; -3179;HANGUL LETTER KAPYEOUNSSANGPIEUP;Lo;0;L;<compat> 112C;;;;N;HANGUL LETTER SSANG BIEUB SUN GYEONG EUM;;;; -317A;HANGUL LETTER SIOS-KIYEOK;Lo;0;L;<compat> 112D;;;;N;HANGUL LETTER SIOS GIYEOG;;;; -317B;HANGUL LETTER SIOS-NIEUN;Lo;0;L;<compat> 112E;;;;N;HANGUL LETTER SIOS NIEUN;;;; -317C;HANGUL LETTER SIOS-TIKEUT;Lo;0;L;<compat> 112F;;;;N;HANGUL LETTER SIOS DIGEUD;;;; -317D;HANGUL LETTER SIOS-PIEUP;Lo;0;L;<compat> 1132;;;;N;HANGUL LETTER SIOS BIEUB;;;; -317E;HANGUL LETTER SIOS-CIEUC;Lo;0;L;<compat> 1136;;;;N;HANGUL LETTER SIOS JIEUJ;;;; -317F;HANGUL LETTER PANSIOS;Lo;0;L;<compat> 1140;;;;N;HANGUL LETTER BAN CHI EUM;;;; -3180;HANGUL LETTER SSANGIEUNG;Lo;0;L;<compat> 1147;;;;N;HANGUL LETTER SSANG IEUNG;;;; -3181;HANGUL LETTER YESIEUNG;Lo;0;L;<compat> 114C;;;;N;HANGUL LETTER NGIEUNG;;;; -3182;HANGUL LETTER YESIEUNG-SIOS;Lo;0;L;<compat> 11F1;;;;N;HANGUL LETTER NGIEUNG SIOS;;;; -3183;HANGUL LETTER YESIEUNG-PANSIOS;Lo;0;L;<compat> 11F2;;;;N;HANGUL LETTER NGIEUNG BAN CHI EUM;;;; -3184;HANGUL LETTER KAPYEOUNPHIEUPH;Lo;0;L;<compat> 1157;;;;N;HANGUL LETTER PIEUP SUN GYEONG EUM;;;; -3185;HANGUL LETTER SSANGHIEUH;Lo;0;L;<compat> 1158;;;;N;HANGUL LETTER SSANG HIEUH;;;; -3186;HANGUL LETTER YEORINHIEUH;Lo;0;L;<compat> 1159;;;;N;HANGUL LETTER YEOLIN HIEUH;;;; -3187;HANGUL LETTER YO-YA;Lo;0;L;<compat> 1184;;;;N;HANGUL LETTER YOYA;;;; -3188;HANGUL LETTER YO-YAE;Lo;0;L;<compat> 1185;;;;N;HANGUL LETTER YOYAE;;;; -3189;HANGUL LETTER YO-I;Lo;0;L;<compat> 1188;;;;N;HANGUL LETTER YOI;;;; -318A;HANGUL LETTER YU-YEO;Lo;0;L;<compat> 1191;;;;N;HANGUL LETTER YUYEO;;;; -318B;HANGUL LETTER YU-YE;Lo;0;L;<compat> 1192;;;;N;HANGUL LETTER YUYE;;;; -318C;HANGUL LETTER YU-I;Lo;0;L;<compat> 1194;;;;N;HANGUL LETTER YUI;;;; -318D;HANGUL LETTER ARAEA;Lo;0;L;<compat> 119E;;;;N;HANGUL LETTER ALAE A;;;; -318E;HANGUL LETTER ARAEAE;Lo;0;L;<compat> 11A1;;;;N;HANGUL LETTER ALAE AE;;;; -3190;IDEOGRAPHIC ANNOTATION LINKING MARK;So;0;L;;;;;N;KANBUN TATETEN;;;; -3191;IDEOGRAPHIC ANNOTATION REVERSE MARK;So;0;L;;;;;N;KAERITEN RE;;;; -3192;IDEOGRAPHIC ANNOTATION ONE MARK;No;0;L;<super> 4E00;;;1;N;KAERITEN ITI;;;; -3193;IDEOGRAPHIC ANNOTATION TWO MARK;No;0;L;<super> 4E8C;;;2;N;KAERITEN NI;;;; -3194;IDEOGRAPHIC ANNOTATION THREE MARK;No;0;L;<super> 4E09;;;3;N;KAERITEN SAN;;;; -3195;IDEOGRAPHIC ANNOTATION FOUR MARK;No;0;L;<super> 56DB;;;4;N;KAERITEN SI;;;; -3196;IDEOGRAPHIC ANNOTATION TOP MARK;So;0;L;<super> 4E0A;;;;N;KAERITEN ZYOU;;;; -3197;IDEOGRAPHIC ANNOTATION MIDDLE MARK;So;0;L;<super> 4E2D;;;;N;KAERITEN TYUU;;;; -3198;IDEOGRAPHIC ANNOTATION BOTTOM MARK;So;0;L;<super> 4E0B;;;;N;KAERITEN GE;;;; -3199;IDEOGRAPHIC ANNOTATION FIRST MARK;So;0;L;<super> 7532;;;;N;KAERITEN KOU;;;; -319A;IDEOGRAPHIC ANNOTATION SECOND MARK;So;0;L;<super> 4E59;;;;N;KAERITEN OTU;;;; -319B;IDEOGRAPHIC ANNOTATION THIRD MARK;So;0;L;<super> 4E19;;;;N;KAERITEN HEI;;;; -319C;IDEOGRAPHIC ANNOTATION FOURTH MARK;So;0;L;<super> 4E01;;;;N;KAERITEN TEI;;;; -319D;IDEOGRAPHIC ANNOTATION HEAVEN MARK;So;0;L;<super> 5929;;;;N;KAERITEN TEN;;;; -319E;IDEOGRAPHIC ANNOTATION EARTH MARK;So;0;L;<super> 5730;;;;N;KAERITEN TI;;;; -319F;IDEOGRAPHIC ANNOTATION MAN MARK;So;0;L;<super> 4EBA;;;;N;KAERITEN ZIN;;;; -31A0;BOPOMOFO LETTER BU;Lo;0;L;;;;;N;;;;; -31A1;BOPOMOFO LETTER ZI;Lo;0;L;;;;;N;;;;; -31A2;BOPOMOFO LETTER JI;Lo;0;L;;;;;N;;;;; -31A3;BOPOMOFO LETTER GU;Lo;0;L;;;;;N;;;;; -31A4;BOPOMOFO LETTER EE;Lo;0;L;;;;;N;;;;; -31A5;BOPOMOFO LETTER ENN;Lo;0;L;;;;;N;;;;; -31A6;BOPOMOFO LETTER OO;Lo;0;L;;;;;N;;;;; -31A7;BOPOMOFO LETTER ONN;Lo;0;L;;;;;N;;;;; -31A8;BOPOMOFO LETTER IR;Lo;0;L;;;;;N;;;;; -31A9;BOPOMOFO LETTER ANN;Lo;0;L;;;;;N;;;;; -31AA;BOPOMOFO LETTER INN;Lo;0;L;;;;;N;;;;; -31AB;BOPOMOFO LETTER UNN;Lo;0;L;;;;;N;;;;; -31AC;BOPOMOFO LETTER IM;Lo;0;L;;;;;N;;;;; -31AD;BOPOMOFO LETTER NGG;Lo;0;L;;;;;N;;;;; -31AE;BOPOMOFO LETTER AINN;Lo;0;L;;;;;N;;;;; -31AF;BOPOMOFO LETTER AUNN;Lo;0;L;;;;;N;;;;; -31B0;BOPOMOFO LETTER AM;Lo;0;L;;;;;N;;;;; -31B1;BOPOMOFO LETTER OM;Lo;0;L;;;;;N;;;;; -31B2;BOPOMOFO LETTER ONG;Lo;0;L;;;;;N;;;;; -31B3;BOPOMOFO LETTER INNN;Lo;0;L;;;;;N;;;;; -31B4;BOPOMOFO FINAL LETTER P;Lo;0;L;;;;;N;;;;; -31B5;BOPOMOFO FINAL LETTER T;Lo;0;L;;;;;N;;;;; -31B6;BOPOMOFO FINAL LETTER K;Lo;0;L;;;;;N;;;;; -31B7;BOPOMOFO FINAL LETTER H;Lo;0;L;;;;;N;;;;; -31B8;BOPOMOFO LETTER GH;Lo;0;L;;;;;N;;;;; -31B9;BOPOMOFO LETTER LH;Lo;0;L;;;;;N;;;;; -31BA;BOPOMOFO LETTER ZY;Lo;0;L;;;;;N;;;;; -31BB;BOPOMOFO FINAL LETTER G;Lo;0;L;;;;;N;;;;; -31BC;BOPOMOFO LETTER GW;Lo;0;L;;;;;N;;;;; -31BD;BOPOMOFO LETTER KW;Lo;0;L;;;;;N;;;;; -31BE;BOPOMOFO LETTER OE;Lo;0;L;;;;;N;;;;; -31BF;BOPOMOFO LETTER AH;Lo;0;L;;;;;N;;;;; -31C0;CJK STROKE T;So;0;ON;;;;;N;;;;; -31C1;CJK STROKE WG;So;0;ON;;;;;N;;;;; -31C2;CJK STROKE XG;So;0;ON;;;;;N;;;;; -31C3;CJK STROKE BXG;So;0;ON;;;;;N;;;;; -31C4;CJK STROKE SW;So;0;ON;;;;;N;;;;; -31C5;CJK STROKE HZZ;So;0;ON;;;;;N;;;;; -31C6;CJK STROKE HZG;So;0;ON;;;;;N;;;;; -31C7;CJK STROKE HP;So;0;ON;;;;;N;;;;; -31C8;CJK STROKE HZWG;So;0;ON;;;;;N;;;;; -31C9;CJK STROKE SZWG;So;0;ON;;;;;N;;;;; -31CA;CJK STROKE HZT;So;0;ON;;;;;N;;;;; -31CB;CJK STROKE HZZP;So;0;ON;;;;;N;;;;; -31CC;CJK STROKE HPWG;So;0;ON;;;;;N;;;;; -31CD;CJK STROKE HZW;So;0;ON;;;;;N;;;;; -31CE;CJK STROKE HZZZ;So;0;ON;;;;;N;;;;; -31CF;CJK STROKE N;So;0;ON;;;;;N;;;;; -31D0;CJK STROKE H;So;0;ON;;;;;N;;;;; -31D1;CJK STROKE S;So;0;ON;;;;;N;;;;; -31D2;CJK STROKE P;So;0;ON;;;;;N;;;;; -31D3;CJK STROKE SP;So;0;ON;;;;;N;;;;; -31D4;CJK STROKE D;So;0;ON;;;;;N;;;;; -31D5;CJK STROKE HZ;So;0;ON;;;;;N;;;;; -31D6;CJK STROKE HG;So;0;ON;;;;;N;;;;; -31D7;CJK STROKE SZ;So;0;ON;;;;;N;;;;; -31D8;CJK STROKE SWZ;So;0;ON;;;;;N;;;;; -31D9;CJK STROKE ST;So;0;ON;;;;;N;;;;; -31DA;CJK STROKE SG;So;0;ON;;;;;N;;;;; -31DB;CJK STROKE PD;So;0;ON;;;;;N;;;;; -31DC;CJK STROKE PZ;So;0;ON;;;;;N;;;;; -31DD;CJK STROKE TN;So;0;ON;;;;;N;;;;; -31DE;CJK STROKE SZZ;So;0;ON;;;;;N;;;;; -31DF;CJK STROKE SWG;So;0;ON;;;;;N;;;;; -31E0;CJK STROKE HXWG;So;0;ON;;;;;N;;;;; -31E1;CJK STROKE HZZZG;So;0;ON;;;;;N;;;;; -31E2;CJK STROKE PG;So;0;ON;;;;;N;;;;; -31E3;CJK STROKE Q;So;0;ON;;;;;N;;;;; -31EF;IDEOGRAPHIC DESCRIPTION CHARACTER SUBTRACTION;So;0;ON;;;;;N;;;;; -31F0;KATAKANA LETTER SMALL KU;Lo;0;L;;;;;N;;;;; -31F1;KATAKANA LETTER SMALL SI;Lo;0;L;;;;;N;;;;; -31F2;KATAKANA LETTER SMALL SU;Lo;0;L;;;;;N;;;;; -31F3;KATAKANA LETTER SMALL TO;Lo;0;L;;;;;N;;;;; -31F4;KATAKANA LETTER SMALL NU;Lo;0;L;;;;;N;;;;; -31F5;KATAKANA LETTER SMALL HA;Lo;0;L;;;;;N;;;;; -31F6;KATAKANA LETTER SMALL HI;Lo;0;L;;;;;N;;;;; -31F7;KATAKANA LETTER SMALL HU;Lo;0;L;;;;;N;;;;; -31F8;KATAKANA LETTER SMALL HE;Lo;0;L;;;;;N;;;;; -31F9;KATAKANA LETTER SMALL HO;Lo;0;L;;;;;N;;;;; -31FA;KATAKANA LETTER SMALL MU;Lo;0;L;;;;;N;;;;; -31FB;KATAKANA LETTER SMALL RA;Lo;0;L;;;;;N;;;;; -31FC;KATAKANA LETTER SMALL RI;Lo;0;L;;;;;N;;;;; -31FD;KATAKANA LETTER SMALL RU;Lo;0;L;;;;;N;;;;; -31FE;KATAKANA LETTER SMALL RE;Lo;0;L;;;;;N;;;;; -31FF;KATAKANA LETTER SMALL RO;Lo;0;L;;;;;N;;;;; -3200;PARENTHESIZED HANGUL KIYEOK;So;0;L;<compat> 0028 1100 0029;;;;N;PARENTHESIZED HANGUL GIYEOG;;;; -3201;PARENTHESIZED HANGUL NIEUN;So;0;L;<compat> 0028 1102 0029;;;;N;;;;; -3202;PARENTHESIZED HANGUL TIKEUT;So;0;L;<compat> 0028 1103 0029;;;;N;PARENTHESIZED HANGUL DIGEUD;;;; -3203;PARENTHESIZED HANGUL RIEUL;So;0;L;<compat> 0028 1105 0029;;;;N;PARENTHESIZED HANGUL LIEUL;;;; -3204;PARENTHESIZED HANGUL MIEUM;So;0;L;<compat> 0028 1106 0029;;;;N;;;;; -3205;PARENTHESIZED HANGUL PIEUP;So;0;L;<compat> 0028 1107 0029;;;;N;PARENTHESIZED HANGUL BIEUB;;;; -3206;PARENTHESIZED HANGUL SIOS;So;0;L;<compat> 0028 1109 0029;;;;N;;;;; -3207;PARENTHESIZED HANGUL IEUNG;So;0;L;<compat> 0028 110B 0029;;;;N;;;;; -3208;PARENTHESIZED HANGUL CIEUC;So;0;L;<compat> 0028 110C 0029;;;;N;PARENTHESIZED HANGUL JIEUJ;;;; -3209;PARENTHESIZED HANGUL CHIEUCH;So;0;L;<compat> 0028 110E 0029;;;;N;PARENTHESIZED HANGUL CIEUC;;;; -320A;PARENTHESIZED HANGUL KHIEUKH;So;0;L;<compat> 0028 110F 0029;;;;N;PARENTHESIZED HANGUL KIYEOK;;;; -320B;PARENTHESIZED HANGUL THIEUTH;So;0;L;<compat> 0028 1110 0029;;;;N;PARENTHESIZED HANGUL TIEUT;;;; -320C;PARENTHESIZED HANGUL PHIEUPH;So;0;L;<compat> 0028 1111 0029;;;;N;PARENTHESIZED HANGUL PIEUP;;;; -320D;PARENTHESIZED HANGUL HIEUH;So;0;L;<compat> 0028 1112 0029;;;;N;;;;; -320E;PARENTHESIZED HANGUL KIYEOK A;So;0;L;<compat> 0028 1100 1161 0029;;;;N;PARENTHESIZED HANGUL GA;;;; -320F;PARENTHESIZED HANGUL NIEUN A;So;0;L;<compat> 0028 1102 1161 0029;;;;N;PARENTHESIZED HANGUL NA;;;; -3210;PARENTHESIZED HANGUL TIKEUT A;So;0;L;<compat> 0028 1103 1161 0029;;;;N;PARENTHESIZED HANGUL DA;;;; -3211;PARENTHESIZED HANGUL RIEUL A;So;0;L;<compat> 0028 1105 1161 0029;;;;N;PARENTHESIZED HANGUL LA;;;; -3212;PARENTHESIZED HANGUL MIEUM A;So;0;L;<compat> 0028 1106 1161 0029;;;;N;PARENTHESIZED HANGUL MA;;;; -3213;PARENTHESIZED HANGUL PIEUP A;So;0;L;<compat> 0028 1107 1161 0029;;;;N;PARENTHESIZED HANGUL BA;;;; -3214;PARENTHESIZED HANGUL SIOS A;So;0;L;<compat> 0028 1109 1161 0029;;;;N;PARENTHESIZED HANGUL SA;;;; -3215;PARENTHESIZED HANGUL IEUNG A;So;0;L;<compat> 0028 110B 1161 0029;;;;N;PARENTHESIZED HANGUL A;;;; -3216;PARENTHESIZED HANGUL CIEUC A;So;0;L;<compat> 0028 110C 1161 0029;;;;N;PARENTHESIZED HANGUL JA;;;; -3217;PARENTHESIZED HANGUL CHIEUCH A;So;0;L;<compat> 0028 110E 1161 0029;;;;N;PARENTHESIZED HANGUL CA;;;; -3218;PARENTHESIZED HANGUL KHIEUKH A;So;0;L;<compat> 0028 110F 1161 0029;;;;N;PARENTHESIZED HANGUL KA;;;; -3219;PARENTHESIZED HANGUL THIEUTH A;So;0;L;<compat> 0028 1110 1161 0029;;;;N;PARENTHESIZED HANGUL TA;;;; -321A;PARENTHESIZED HANGUL PHIEUPH A;So;0;L;<compat> 0028 1111 1161 0029;;;;N;PARENTHESIZED HANGUL PA;;;; -321B;PARENTHESIZED HANGUL HIEUH A;So;0;L;<compat> 0028 1112 1161 0029;;;;N;PARENTHESIZED HANGUL HA;;;; -321C;PARENTHESIZED HANGUL CIEUC U;So;0;L;<compat> 0028 110C 116E 0029;;;;N;PARENTHESIZED HANGUL JU;;;; -321D;PARENTHESIZED KOREAN CHARACTER OJEON;So;0;ON;<compat> 0028 110B 1169 110C 1165 11AB 0029;;;;N;;;;; -321E;PARENTHESIZED KOREAN CHARACTER O HU;So;0;ON;<compat> 0028 110B 1169 1112 116E 0029;;;;N;;;;; -3220;PARENTHESIZED IDEOGRAPH ONE;No;0;L;<compat> 0028 4E00 0029;;;1;N;;;;; -3221;PARENTHESIZED IDEOGRAPH TWO;No;0;L;<compat> 0028 4E8C 0029;;;2;N;;;;; -3222;PARENTHESIZED IDEOGRAPH THREE;No;0;L;<compat> 0028 4E09 0029;;;3;N;;;;; -3223;PARENTHESIZED IDEOGRAPH FOUR;No;0;L;<compat> 0028 56DB 0029;;;4;N;;;;; -3224;PARENTHESIZED IDEOGRAPH FIVE;No;0;L;<compat> 0028 4E94 0029;;;5;N;;;;; -3225;PARENTHESIZED IDEOGRAPH SIX;No;0;L;<compat> 0028 516D 0029;;;6;N;;;;; -3226;PARENTHESIZED IDEOGRAPH SEVEN;No;0;L;<compat> 0028 4E03 0029;;;7;N;;;;; -3227;PARENTHESIZED IDEOGRAPH EIGHT;No;0;L;<compat> 0028 516B 0029;;;8;N;;;;; -3228;PARENTHESIZED IDEOGRAPH NINE;No;0;L;<compat> 0028 4E5D 0029;;;9;N;;;;; -3229;PARENTHESIZED IDEOGRAPH TEN;No;0;L;<compat> 0028 5341 0029;;;10;N;;;;; -322A;PARENTHESIZED IDEOGRAPH MOON;So;0;L;<compat> 0028 6708 0029;;;;N;;;;; -322B;PARENTHESIZED IDEOGRAPH FIRE;So;0;L;<compat> 0028 706B 0029;;;;N;;;;; -322C;PARENTHESIZED IDEOGRAPH WATER;So;0;L;<compat> 0028 6C34 0029;;;;N;;;;; -322D;PARENTHESIZED IDEOGRAPH WOOD;So;0;L;<compat> 0028 6728 0029;;;;N;;;;; -322E;PARENTHESIZED IDEOGRAPH METAL;So;0;L;<compat> 0028 91D1 0029;;;;N;;;;; -322F;PARENTHESIZED IDEOGRAPH EARTH;So;0;L;<compat> 0028 571F 0029;;;;N;;;;; -3230;PARENTHESIZED IDEOGRAPH SUN;So;0;L;<compat> 0028 65E5 0029;;;;N;;;;; -3231;PARENTHESIZED IDEOGRAPH STOCK;So;0;L;<compat> 0028 682A 0029;;;;N;;;;; -3232;PARENTHESIZED IDEOGRAPH HAVE;So;0;L;<compat> 0028 6709 0029;;;;N;;;;; -3233;PARENTHESIZED IDEOGRAPH SOCIETY;So;0;L;<compat> 0028 793E 0029;;;;N;;;;; -3234;PARENTHESIZED IDEOGRAPH NAME;So;0;L;<compat> 0028 540D 0029;;;;N;;;;; -3235;PARENTHESIZED IDEOGRAPH SPECIAL;So;0;L;<compat> 0028 7279 0029;;;;N;;;;; -3236;PARENTHESIZED IDEOGRAPH FINANCIAL;So;0;L;<compat> 0028 8CA1 0029;;;;N;;;;; -3237;PARENTHESIZED IDEOGRAPH CONGRATULATION;So;0;L;<compat> 0028 795D 0029;;;;N;;;;; -3238;PARENTHESIZED IDEOGRAPH LABOR;So;0;L;<compat> 0028 52B4 0029;;;;N;;;;; -3239;PARENTHESIZED IDEOGRAPH REPRESENT;So;0;L;<compat> 0028 4EE3 0029;;;;N;;;;; -323A;PARENTHESIZED IDEOGRAPH CALL;So;0;L;<compat> 0028 547C 0029;;;;N;;;;; -323B;PARENTHESIZED IDEOGRAPH STUDY;So;0;L;<compat> 0028 5B66 0029;;;;N;;;;; -323C;PARENTHESIZED IDEOGRAPH SUPERVISE;So;0;L;<compat> 0028 76E3 0029;;;;N;;;;; -323D;PARENTHESIZED IDEOGRAPH ENTERPRISE;So;0;L;<compat> 0028 4F01 0029;;;;N;;;;; -323E;PARENTHESIZED IDEOGRAPH RESOURCE;So;0;L;<compat> 0028 8CC7 0029;;;;N;;;;; -323F;PARENTHESIZED IDEOGRAPH ALLIANCE;So;0;L;<compat> 0028 5354 0029;;;;N;;;;; -3240;PARENTHESIZED IDEOGRAPH FESTIVAL;So;0;L;<compat> 0028 796D 0029;;;;N;;;;; -3241;PARENTHESIZED IDEOGRAPH REST;So;0;L;<compat> 0028 4F11 0029;;;;N;;;;; -3242;PARENTHESIZED IDEOGRAPH SELF;So;0;L;<compat> 0028 81EA 0029;;;;N;;;;; -3243;PARENTHESIZED IDEOGRAPH REACH;So;0;L;<compat> 0028 81F3 0029;;;;N;;;;; -3244;CIRCLED IDEOGRAPH QUESTION;So;0;L;<circle> 554F;;;;N;;;;; -3245;CIRCLED IDEOGRAPH KINDERGARTEN;So;0;L;<circle> 5E7C;;;;N;;;;; -3246;CIRCLED IDEOGRAPH SCHOOL;So;0;L;<circle> 6587;;;;N;;;;; -3247;CIRCLED IDEOGRAPH KOTO;So;0;L;<circle> 7B8F;;;;N;;;;; -3248;CIRCLED NUMBER TEN ON BLACK SQUARE;No;0;L;;;;10;N;;;;; -3249;CIRCLED NUMBER TWENTY ON BLACK SQUARE;No;0;L;;;;20;N;;;;; -324A;CIRCLED NUMBER THIRTY ON BLACK SQUARE;No;0;L;;;;30;N;;;;; -324B;CIRCLED NUMBER FORTY ON BLACK SQUARE;No;0;L;;;;40;N;;;;; -324C;CIRCLED NUMBER FIFTY ON BLACK SQUARE;No;0;L;;;;50;N;;;;; -324D;CIRCLED NUMBER SIXTY ON BLACK SQUARE;No;0;L;;;;60;N;;;;; -324E;CIRCLED NUMBER SEVENTY ON BLACK SQUARE;No;0;L;;;;70;N;;;;; -324F;CIRCLED NUMBER EIGHTY ON BLACK SQUARE;No;0;L;;;;80;N;;;;; -3250;PARTNERSHIP SIGN;So;0;ON;<square> 0050 0054 0045;;;;N;;;;; -3251;CIRCLED NUMBER TWENTY ONE;No;0;ON;<circle> 0032 0031;;;21;N;;;;; -3252;CIRCLED NUMBER TWENTY TWO;No;0;ON;<circle> 0032 0032;;;22;N;;;;; -3253;CIRCLED NUMBER TWENTY THREE;No;0;ON;<circle> 0032 0033;;;23;N;;;;; -3254;CIRCLED NUMBER TWENTY FOUR;No;0;ON;<circle> 0032 0034;;;24;N;;;;; -3255;CIRCLED NUMBER TWENTY FIVE;No;0;ON;<circle> 0032 0035;;;25;N;;;;; -3256;CIRCLED NUMBER TWENTY SIX;No;0;ON;<circle> 0032 0036;;;26;N;;;;; -3257;CIRCLED NUMBER TWENTY SEVEN;No;0;ON;<circle> 0032 0037;;;27;N;;;;; -3258;CIRCLED NUMBER TWENTY EIGHT;No;0;ON;<circle> 0032 0038;;;28;N;;;;; -3259;CIRCLED NUMBER TWENTY NINE;No;0;ON;<circle> 0032 0039;;;29;N;;;;; -325A;CIRCLED NUMBER THIRTY;No;0;ON;<circle> 0033 0030;;;30;N;;;;; -325B;CIRCLED NUMBER THIRTY ONE;No;0;ON;<circle> 0033 0031;;;31;N;;;;; -325C;CIRCLED NUMBER THIRTY TWO;No;0;ON;<circle> 0033 0032;;;32;N;;;;; -325D;CIRCLED NUMBER THIRTY THREE;No;0;ON;<circle> 0033 0033;;;33;N;;;;; -325E;CIRCLED NUMBER THIRTY FOUR;No;0;ON;<circle> 0033 0034;;;34;N;;;;; -325F;CIRCLED NUMBER THIRTY FIVE;No;0;ON;<circle> 0033 0035;;;35;N;;;;; -3260;CIRCLED HANGUL KIYEOK;So;0;L;<circle> 1100;;;;N;CIRCLED HANGUL GIYEOG;;;; -3261;CIRCLED HANGUL NIEUN;So;0;L;<circle> 1102;;;;N;;;;; -3262;CIRCLED HANGUL TIKEUT;So;0;L;<circle> 1103;;;;N;CIRCLED HANGUL DIGEUD;;;; -3263;CIRCLED HANGUL RIEUL;So;0;L;<circle> 1105;;;;N;CIRCLED HANGUL LIEUL;;;; -3264;CIRCLED HANGUL MIEUM;So;0;L;<circle> 1106;;;;N;;;;; -3265;CIRCLED HANGUL PIEUP;So;0;L;<circle> 1107;;;;N;CIRCLED HANGUL BIEUB;;;; -3266;CIRCLED HANGUL SIOS;So;0;L;<circle> 1109;;;;N;;;;; -3267;CIRCLED HANGUL IEUNG;So;0;L;<circle> 110B;;;;N;;;;; -3268;CIRCLED HANGUL CIEUC;So;0;L;<circle> 110C;;;;N;CIRCLED HANGUL JIEUJ;;;; -3269;CIRCLED HANGUL CHIEUCH;So;0;L;<circle> 110E;;;;N;CIRCLED HANGUL CIEUC;;;; -326A;CIRCLED HANGUL KHIEUKH;So;0;L;<circle> 110F;;;;N;CIRCLED HANGUL KIYEOK;;;; -326B;CIRCLED HANGUL THIEUTH;So;0;L;<circle> 1110;;;;N;CIRCLED HANGUL TIEUT;;;; -326C;CIRCLED HANGUL PHIEUPH;So;0;L;<circle> 1111;;;;N;CIRCLED HANGUL PIEUP;;;; -326D;CIRCLED HANGUL HIEUH;So;0;L;<circle> 1112;;;;N;;;;; -326E;CIRCLED HANGUL KIYEOK A;So;0;L;<circle> 1100 1161;;;;N;CIRCLED HANGUL GA;;;; -326F;CIRCLED HANGUL NIEUN A;So;0;L;<circle> 1102 1161;;;;N;CIRCLED HANGUL NA;;;; -3270;CIRCLED HANGUL TIKEUT A;So;0;L;<circle> 1103 1161;;;;N;CIRCLED HANGUL DA;;;; -3271;CIRCLED HANGUL RIEUL A;So;0;L;<circle> 1105 1161;;;;N;CIRCLED HANGUL LA;;;; -3272;CIRCLED HANGUL MIEUM A;So;0;L;<circle> 1106 1161;;;;N;CIRCLED HANGUL MA;;;; -3273;CIRCLED HANGUL PIEUP A;So;0;L;<circle> 1107 1161;;;;N;CIRCLED HANGUL BA;;;; -3274;CIRCLED HANGUL SIOS A;So;0;L;<circle> 1109 1161;;;;N;CIRCLED HANGUL SA;;;; -3275;CIRCLED HANGUL IEUNG A;So;0;L;<circle> 110B 1161;;;;N;CIRCLED HANGUL A;;;; -3276;CIRCLED HANGUL CIEUC A;So;0;L;<circle> 110C 1161;;;;N;CIRCLED HANGUL JA;;;; -3277;CIRCLED HANGUL CHIEUCH A;So;0;L;<circle> 110E 1161;;;;N;CIRCLED HANGUL CA;;;; -3278;CIRCLED HANGUL KHIEUKH A;So;0;L;<circle> 110F 1161;;;;N;CIRCLED HANGUL KA;;;; -3279;CIRCLED HANGUL THIEUTH A;So;0;L;<circle> 1110 1161;;;;N;CIRCLED HANGUL TA;;;; -327A;CIRCLED HANGUL PHIEUPH A;So;0;L;<circle> 1111 1161;;;;N;CIRCLED HANGUL PA;;;; -327B;CIRCLED HANGUL HIEUH A;So;0;L;<circle> 1112 1161;;;;N;CIRCLED HANGUL HA;;;; -327C;CIRCLED KOREAN CHARACTER CHAMKO;So;0;ON;<circle> 110E 1161 11B7 1100 1169;;;;N;;;;; -327D;CIRCLED KOREAN CHARACTER JUEUI;So;0;ON;<circle> 110C 116E 110B 1174;;;;N;;;;; -327E;CIRCLED HANGUL IEUNG U;So;0;ON;<circle> 110B 116E;;;;N;;;;; -327F;KOREAN STANDARD SYMBOL;So;0;L;;;;;N;;;;; -3280;CIRCLED IDEOGRAPH ONE;No;0;L;<circle> 4E00;;;1;N;;;;; -3281;CIRCLED IDEOGRAPH TWO;No;0;L;<circle> 4E8C;;;2;N;;;;; -3282;CIRCLED IDEOGRAPH THREE;No;0;L;<circle> 4E09;;;3;N;;;;; -3283;CIRCLED IDEOGRAPH FOUR;No;0;L;<circle> 56DB;;;4;N;;;;; -3284;CIRCLED IDEOGRAPH FIVE;No;0;L;<circle> 4E94;;;5;N;;;;; -3285;CIRCLED IDEOGRAPH SIX;No;0;L;<circle> 516D;;;6;N;;;;; -3286;CIRCLED IDEOGRAPH SEVEN;No;0;L;<circle> 4E03;;;7;N;;;;; -3287;CIRCLED IDEOGRAPH EIGHT;No;0;L;<circle> 516B;;;8;N;;;;; -3288;CIRCLED IDEOGRAPH NINE;No;0;L;<circle> 4E5D;;;9;N;;;;; -3289;CIRCLED IDEOGRAPH TEN;No;0;L;<circle> 5341;;;10;N;;;;; -328A;CIRCLED IDEOGRAPH MOON;So;0;L;<circle> 6708;;;;N;;;;; -328B;CIRCLED IDEOGRAPH FIRE;So;0;L;<circle> 706B;;;;N;;;;; -328C;CIRCLED IDEOGRAPH WATER;So;0;L;<circle> 6C34;;;;N;;;;; -328D;CIRCLED IDEOGRAPH WOOD;So;0;L;<circle> 6728;;;;N;;;;; -328E;CIRCLED IDEOGRAPH METAL;So;0;L;<circle> 91D1;;;;N;;;;; -328F;CIRCLED IDEOGRAPH EARTH;So;0;L;<circle> 571F;;;;N;;;;; -3290;CIRCLED IDEOGRAPH SUN;So;0;L;<circle> 65E5;;;;N;;;;; -3291;CIRCLED IDEOGRAPH STOCK;So;0;L;<circle> 682A;;;;N;;;;; -3292;CIRCLED IDEOGRAPH HAVE;So;0;L;<circle> 6709;;;;N;;;;; -3293;CIRCLED IDEOGRAPH SOCIETY;So;0;L;<circle> 793E;;;;N;;;;; -3294;CIRCLED IDEOGRAPH NAME;So;0;L;<circle> 540D;;;;N;;;;; -3295;CIRCLED IDEOGRAPH SPECIAL;So;0;L;<circle> 7279;;;;N;;;;; -3296;CIRCLED IDEOGRAPH FINANCIAL;So;0;L;<circle> 8CA1;;;;N;;;;; -3297;CIRCLED IDEOGRAPH CONGRATULATION;So;0;L;<circle> 795D;;;;N;;;;; -3298;CIRCLED IDEOGRAPH LABOR;So;0;L;<circle> 52B4;;;;N;;;;; -3299;CIRCLED IDEOGRAPH SECRET;So;0;L;<circle> 79D8;;;;N;;;;; -329A;CIRCLED IDEOGRAPH MALE;So;0;L;<circle> 7537;;;;N;;;;; -329B;CIRCLED IDEOGRAPH FEMALE;So;0;L;<circle> 5973;;;;N;;;;; -329C;CIRCLED IDEOGRAPH SUITABLE;So;0;L;<circle> 9069;;;;N;;;;; -329D;CIRCLED IDEOGRAPH EXCELLENT;So;0;L;<circle> 512A;;;;N;;;;; -329E;CIRCLED IDEOGRAPH PRINT;So;0;L;<circle> 5370;;;;N;;;;; -329F;CIRCLED IDEOGRAPH ATTENTION;So;0;L;<circle> 6CE8;;;;N;;;;; -32A0;CIRCLED IDEOGRAPH ITEM;So;0;L;<circle> 9805;;;;N;;;;; -32A1;CIRCLED IDEOGRAPH REST;So;0;L;<circle> 4F11;;;;N;;;;; -32A2;CIRCLED IDEOGRAPH COPY;So;0;L;<circle> 5199;;;;N;;;;; -32A3;CIRCLED IDEOGRAPH CORRECT;So;0;L;<circle> 6B63;;;;N;;;;; -32A4;CIRCLED IDEOGRAPH HIGH;So;0;L;<circle> 4E0A;;;;N;;;;; -32A5;CIRCLED IDEOGRAPH CENTRE;So;0;L;<circle> 4E2D;;;;N;CIRCLED IDEOGRAPH CENTER;;;; -32A6;CIRCLED IDEOGRAPH LOW;So;0;L;<circle> 4E0B;;;;N;;;;; -32A7;CIRCLED IDEOGRAPH LEFT;So;0;L;<circle> 5DE6;;;;N;;;;; -32A8;CIRCLED IDEOGRAPH RIGHT;So;0;L;<circle> 53F3;;;;N;;;;; -32A9;CIRCLED IDEOGRAPH MEDICINE;So;0;L;<circle> 533B;;;;N;;;;; -32AA;CIRCLED IDEOGRAPH RELIGION;So;0;L;<circle> 5B97;;;;N;;;;; -32AB;CIRCLED IDEOGRAPH STUDY;So;0;L;<circle> 5B66;;;;N;;;;; -32AC;CIRCLED IDEOGRAPH SUPERVISE;So;0;L;<circle> 76E3;;;;N;;;;; -32AD;CIRCLED IDEOGRAPH ENTERPRISE;So;0;L;<circle> 4F01;;;;N;;;;; -32AE;CIRCLED IDEOGRAPH RESOURCE;So;0;L;<circle> 8CC7;;;;N;;;;; -32AF;CIRCLED IDEOGRAPH ALLIANCE;So;0;L;<circle> 5354;;;;N;;;;; -32B0;CIRCLED IDEOGRAPH NIGHT;So;0;L;<circle> 591C;;;;N;;;;; -32B1;CIRCLED NUMBER THIRTY SIX;No;0;ON;<circle> 0033 0036;;;36;N;;;;; -32B2;CIRCLED NUMBER THIRTY SEVEN;No;0;ON;<circle> 0033 0037;;;37;N;;;;; -32B3;CIRCLED NUMBER THIRTY EIGHT;No;0;ON;<circle> 0033 0038;;;38;N;;;;; -32B4;CIRCLED NUMBER THIRTY NINE;No;0;ON;<circle> 0033 0039;;;39;N;;;;; -32B5;CIRCLED NUMBER FORTY;No;0;ON;<circle> 0034 0030;;;40;N;;;;; -32B6;CIRCLED NUMBER FORTY ONE;No;0;ON;<circle> 0034 0031;;;41;N;;;;; -32B7;CIRCLED NUMBER FORTY TWO;No;0;ON;<circle> 0034 0032;;;42;N;;;;; -32B8;CIRCLED NUMBER FORTY THREE;No;0;ON;<circle> 0034 0033;;;43;N;;;;; -32B9;CIRCLED NUMBER FORTY FOUR;No;0;ON;<circle> 0034 0034;;;44;N;;;;; -32BA;CIRCLED NUMBER FORTY FIVE;No;0;ON;<circle> 0034 0035;;;45;N;;;;; -32BB;CIRCLED NUMBER FORTY SIX;No;0;ON;<circle> 0034 0036;;;46;N;;;;; -32BC;CIRCLED NUMBER FORTY SEVEN;No;0;ON;<circle> 0034 0037;;;47;N;;;;; -32BD;CIRCLED NUMBER FORTY EIGHT;No;0;ON;<circle> 0034 0038;;;48;N;;;;; -32BE;CIRCLED NUMBER FORTY NINE;No;0;ON;<circle> 0034 0039;;;49;N;;;;; -32BF;CIRCLED NUMBER FIFTY;No;0;ON;<circle> 0035 0030;;;50;N;;;;; -32C0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY;So;0;L;<compat> 0031 6708;;;;N;;;;; -32C1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR FEBRUARY;So;0;L;<compat> 0032 6708;;;;N;;;;; -32C2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MARCH;So;0;L;<compat> 0033 6708;;;;N;;;;; -32C3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR APRIL;So;0;L;<compat> 0034 6708;;;;N;;;;; -32C4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MAY;So;0;L;<compat> 0035 6708;;;;N;;;;; -32C5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JUNE;So;0;L;<compat> 0036 6708;;;;N;;;;; -32C6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JULY;So;0;L;<compat> 0037 6708;;;;N;;;;; -32C7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR AUGUST;So;0;L;<compat> 0038 6708;;;;N;;;;; -32C8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR SEPTEMBER;So;0;L;<compat> 0039 6708;;;;N;;;;; -32C9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR OCTOBER;So;0;L;<compat> 0031 0030 6708;;;;N;;;;; -32CA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR NOVEMBER;So;0;L;<compat> 0031 0031 6708;;;;N;;;;; -32CB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER;So;0;L;<compat> 0031 0032 6708;;;;N;;;;; -32CC;SQUARE HG;So;0;ON;<square> 0048 0067;;;;N;;;;; -32CD;SQUARE ERG;So;0;ON;<square> 0065 0072 0067;;;;N;;;;; -32CE;SQUARE EV;So;0;ON;<square> 0065 0056;;;;N;;;;; -32CF;LIMITED LIABILITY SIGN;So;0;ON;<square> 004C 0054 0044;;;;N;;;;; -32D0;CIRCLED KATAKANA A;So;0;L;<circle> 30A2;;;;N;;;;; -32D1;CIRCLED KATAKANA I;So;0;L;<circle> 30A4;;;;N;;;;; -32D2;CIRCLED KATAKANA U;So;0;L;<circle> 30A6;;;;N;;;;; -32D3;CIRCLED KATAKANA E;So;0;L;<circle> 30A8;;;;N;;;;; -32D4;CIRCLED KATAKANA O;So;0;L;<circle> 30AA;;;;N;;;;; -32D5;CIRCLED KATAKANA KA;So;0;L;<circle> 30AB;;;;N;;;;; -32D6;CIRCLED KATAKANA KI;So;0;L;<circle> 30AD;;;;N;;;;; -32D7;CIRCLED KATAKANA KU;So;0;L;<circle> 30AF;;;;N;;;;; -32D8;CIRCLED KATAKANA KE;So;0;L;<circle> 30B1;;;;N;;;;; -32D9;CIRCLED KATAKANA KO;So;0;L;<circle> 30B3;;;;N;;;;; -32DA;CIRCLED KATAKANA SA;So;0;L;<circle> 30B5;;;;N;;;;; -32DB;CIRCLED KATAKANA SI;So;0;L;<circle> 30B7;;;;N;;;;; -32DC;CIRCLED KATAKANA SU;So;0;L;<circle> 30B9;;;;N;;;;; -32DD;CIRCLED KATAKANA SE;So;0;L;<circle> 30BB;;;;N;;;;; -32DE;CIRCLED KATAKANA SO;So;0;L;<circle> 30BD;;;;N;;;;; -32DF;CIRCLED KATAKANA TA;So;0;L;<circle> 30BF;;;;N;;;;; -32E0;CIRCLED KATAKANA TI;So;0;L;<circle> 30C1;;;;N;;;;; -32E1;CIRCLED KATAKANA TU;So;0;L;<circle> 30C4;;;;N;;;;; -32E2;CIRCLED KATAKANA TE;So;0;L;<circle> 30C6;;;;N;;;;; -32E3;CIRCLED KATAKANA TO;So;0;L;<circle> 30C8;;;;N;;;;; -32E4;CIRCLED KATAKANA NA;So;0;L;<circle> 30CA;;;;N;;;;; -32E5;CIRCLED KATAKANA NI;So;0;L;<circle> 30CB;;;;N;;;;; -32E6;CIRCLED KATAKANA NU;So;0;L;<circle> 30CC;;;;N;;;;; -32E7;CIRCLED KATAKANA NE;So;0;L;<circle> 30CD;;;;N;;;;; -32E8;CIRCLED KATAKANA NO;So;0;L;<circle> 30CE;;;;N;;;;; -32E9;CIRCLED KATAKANA HA;So;0;L;<circle> 30CF;;;;N;;;;; -32EA;CIRCLED KATAKANA HI;So;0;L;<circle> 30D2;;;;N;;;;; -32EB;CIRCLED KATAKANA HU;So;0;L;<circle> 30D5;;;;N;;;;; -32EC;CIRCLED KATAKANA HE;So;0;L;<circle> 30D8;;;;N;;;;; -32ED;CIRCLED KATAKANA HO;So;0;L;<circle> 30DB;;;;N;;;;; -32EE;CIRCLED KATAKANA MA;So;0;L;<circle> 30DE;;;;N;;;;; -32EF;CIRCLED KATAKANA MI;So;0;L;<circle> 30DF;;;;N;;;;; -32F0;CIRCLED KATAKANA MU;So;0;L;<circle> 30E0;;;;N;;;;; -32F1;CIRCLED KATAKANA ME;So;0;L;<circle> 30E1;;;;N;;;;; -32F2;CIRCLED KATAKANA MO;So;0;L;<circle> 30E2;;;;N;;;;; -32F3;CIRCLED KATAKANA YA;So;0;L;<circle> 30E4;;;;N;;;;; -32F4;CIRCLED KATAKANA YU;So;0;L;<circle> 30E6;;;;N;;;;; -32F5;CIRCLED KATAKANA YO;So;0;L;<circle> 30E8;;;;N;;;;; -32F6;CIRCLED KATAKANA RA;So;0;L;<circle> 30E9;;;;N;;;;; -32F7;CIRCLED KATAKANA RI;So;0;L;<circle> 30EA;;;;N;;;;; -32F8;CIRCLED KATAKANA RU;So;0;L;<circle> 30EB;;;;N;;;;; -32F9;CIRCLED KATAKANA RE;So;0;L;<circle> 30EC;;;;N;;;;; -32FA;CIRCLED KATAKANA RO;So;0;L;<circle> 30ED;;;;N;;;;; -32FB;CIRCLED KATAKANA WA;So;0;L;<circle> 30EF;;;;N;;;;; -32FC;CIRCLED KATAKANA WI;So;0;L;<circle> 30F0;;;;N;;;;; -32FD;CIRCLED KATAKANA WE;So;0;L;<circle> 30F1;;;;N;;;;; -32FE;CIRCLED KATAKANA WO;So;0;L;<circle> 30F2;;;;N;;;;; -32FF;SQUARE ERA NAME REIWA;So;0;L;<square> 4EE4 548C;;;;N;;;;; -3300;SQUARE APAATO;So;0;L;<square> 30A2 30D1 30FC 30C8;;;;N;SQUARED APAATO;;;; -3301;SQUARE ARUHUA;So;0;L;<square> 30A2 30EB 30D5 30A1;;;;N;SQUARED ARUHUA;;;; -3302;SQUARE ANPEA;So;0;L;<square> 30A2 30F3 30DA 30A2;;;;N;SQUARED ANPEA;;;; -3303;SQUARE AARU;So;0;L;<square> 30A2 30FC 30EB;;;;N;SQUARED AARU;;;; -3304;SQUARE ININGU;So;0;L;<square> 30A4 30CB 30F3 30B0;;;;N;SQUARED ININGU;;;; -3305;SQUARE INTI;So;0;L;<square> 30A4 30F3 30C1;;;;N;SQUARED INTI;;;; -3306;SQUARE UON;So;0;L;<square> 30A6 30A9 30F3;;;;N;SQUARED UON;;;; -3307;SQUARE ESUKUUDO;So;0;L;<square> 30A8 30B9 30AF 30FC 30C9;;;;N;SQUARED ESUKUUDO;;;; -3308;SQUARE EEKAA;So;0;L;<square> 30A8 30FC 30AB 30FC;;;;N;SQUARED EEKAA;;;; -3309;SQUARE ONSU;So;0;L;<square> 30AA 30F3 30B9;;;;N;SQUARED ONSU;;;; -330A;SQUARE OOMU;So;0;L;<square> 30AA 30FC 30E0;;;;N;SQUARED OOMU;;;; -330B;SQUARE KAIRI;So;0;L;<square> 30AB 30A4 30EA;;;;N;SQUARED KAIRI;;;; -330C;SQUARE KARATTO;So;0;L;<square> 30AB 30E9 30C3 30C8;;;;N;SQUARED KARATTO;;;; -330D;SQUARE KARORII;So;0;L;<square> 30AB 30ED 30EA 30FC;;;;N;SQUARED KARORII;;;; -330E;SQUARE GARON;So;0;L;<square> 30AC 30ED 30F3;;;;N;SQUARED GARON;;;; -330F;SQUARE GANMA;So;0;L;<square> 30AC 30F3 30DE;;;;N;SQUARED GANMA;;;; -3310;SQUARE GIGA;So;0;L;<square> 30AE 30AC;;;;N;SQUARED GIGA;;;; -3311;SQUARE GINII;So;0;L;<square> 30AE 30CB 30FC;;;;N;SQUARED GINII;;;; -3312;SQUARE KYURII;So;0;L;<square> 30AD 30E5 30EA 30FC;;;;N;SQUARED KYURII;;;; -3313;SQUARE GIRUDAA;So;0;L;<square> 30AE 30EB 30C0 30FC;;;;N;SQUARED GIRUDAA;;;; -3314;SQUARE KIRO;So;0;L;<square> 30AD 30ED;;;;N;SQUARED KIRO;;;; -3315;SQUARE KIROGURAMU;So;0;L;<square> 30AD 30ED 30B0 30E9 30E0;;;;N;SQUARED KIROGURAMU;;;; -3316;SQUARE KIROMEETORU;So;0;L;<square> 30AD 30ED 30E1 30FC 30C8 30EB;;;;N;SQUARED KIROMEETORU;;;; -3317;SQUARE KIROWATTO;So;0;L;<square> 30AD 30ED 30EF 30C3 30C8;;;;N;SQUARED KIROWATTO;;;; -3318;SQUARE GURAMU;So;0;L;<square> 30B0 30E9 30E0;;;;N;SQUARED GURAMU;;;; -3319;SQUARE GURAMUTON;So;0;L;<square> 30B0 30E9 30E0 30C8 30F3;;;;N;SQUARED GURAMUTON;;;; -331A;SQUARE KURUZEIRO;So;0;L;<square> 30AF 30EB 30BC 30A4 30ED;;;;N;SQUARED KURUZEIRO;;;; -331B;SQUARE KUROONE;So;0;L;<square> 30AF 30ED 30FC 30CD;;;;N;SQUARED KUROONE;;;; -331C;SQUARE KEESU;So;0;L;<square> 30B1 30FC 30B9;;;;N;SQUARED KEESU;;;; -331D;SQUARE KORUNA;So;0;L;<square> 30B3 30EB 30CA;;;;N;SQUARED KORUNA;;;; -331E;SQUARE KOOPO;So;0;L;<square> 30B3 30FC 30DD;;;;N;SQUARED KOOPO;;;; -331F;SQUARE SAIKURU;So;0;L;<square> 30B5 30A4 30AF 30EB;;;;N;SQUARED SAIKURU;;;; -3320;SQUARE SANTIIMU;So;0;L;<square> 30B5 30F3 30C1 30FC 30E0;;;;N;SQUARED SANTIIMU;;;; -3321;SQUARE SIRINGU;So;0;L;<square> 30B7 30EA 30F3 30B0;;;;N;SQUARED SIRINGU;;;; -3322;SQUARE SENTI;So;0;L;<square> 30BB 30F3 30C1;;;;N;SQUARED SENTI;;;; -3323;SQUARE SENTO;So;0;L;<square> 30BB 30F3 30C8;;;;N;SQUARED SENTO;;;; -3324;SQUARE DAASU;So;0;L;<square> 30C0 30FC 30B9;;;;N;SQUARED DAASU;;;; -3325;SQUARE DESI;So;0;L;<square> 30C7 30B7;;;;N;SQUARED DESI;;;; -3326;SQUARE DORU;So;0;L;<square> 30C9 30EB;;;;N;SQUARED DORU;;;; -3327;SQUARE TON;So;0;L;<square> 30C8 30F3;;;;N;SQUARED TON;;;; -3328;SQUARE NANO;So;0;L;<square> 30CA 30CE;;;;N;SQUARED NANO;;;; -3329;SQUARE NOTTO;So;0;L;<square> 30CE 30C3 30C8;;;;N;SQUARED NOTTO;;;; -332A;SQUARE HAITU;So;0;L;<square> 30CF 30A4 30C4;;;;N;SQUARED HAITU;;;; -332B;SQUARE PAASENTO;So;0;L;<square> 30D1 30FC 30BB 30F3 30C8;;;;N;SQUARED PAASENTO;;;; -332C;SQUARE PAATU;So;0;L;<square> 30D1 30FC 30C4;;;;N;SQUARED PAATU;;;; -332D;SQUARE BAARERU;So;0;L;<square> 30D0 30FC 30EC 30EB;;;;N;SQUARED BAARERU;;;; -332E;SQUARE PIASUTORU;So;0;L;<square> 30D4 30A2 30B9 30C8 30EB;;;;N;SQUARED PIASUTORU;;;; -332F;SQUARE PIKURU;So;0;L;<square> 30D4 30AF 30EB;;;;N;SQUARED PIKURU;;;; -3330;SQUARE PIKO;So;0;L;<square> 30D4 30B3;;;;N;SQUARED PIKO;;;; -3331;SQUARE BIRU;So;0;L;<square> 30D3 30EB;;;;N;SQUARED BIRU;;;; -3332;SQUARE HUARADDO;So;0;L;<square> 30D5 30A1 30E9 30C3 30C9;;;;N;SQUARED HUARADDO;;;; -3333;SQUARE HUIITO;So;0;L;<square> 30D5 30A3 30FC 30C8;;;;N;SQUARED HUIITO;;;; -3334;SQUARE BUSSYERU;So;0;L;<square> 30D6 30C3 30B7 30A7 30EB;;;;N;SQUARED BUSSYERU;;;; -3335;SQUARE HURAN;So;0;L;<square> 30D5 30E9 30F3;;;;N;SQUARED HURAN;;;; -3336;SQUARE HEKUTAARU;So;0;L;<square> 30D8 30AF 30BF 30FC 30EB;;;;N;SQUARED HEKUTAARU;;;; -3337;SQUARE PESO;So;0;L;<square> 30DA 30BD;;;;N;SQUARED PESO;;;; -3338;SQUARE PENIHI;So;0;L;<square> 30DA 30CB 30D2;;;;N;SQUARED PENIHI;;;; -3339;SQUARE HERUTU;So;0;L;<square> 30D8 30EB 30C4;;;;N;SQUARED HERUTU;;;; -333A;SQUARE PENSU;So;0;L;<square> 30DA 30F3 30B9;;;;N;SQUARED PENSU;;;; -333B;SQUARE PEEZI;So;0;L;<square> 30DA 30FC 30B8;;;;N;SQUARED PEEZI;;;; -333C;SQUARE BEETA;So;0;L;<square> 30D9 30FC 30BF;;;;N;SQUARED BEETA;;;; -333D;SQUARE POINTO;So;0;L;<square> 30DD 30A4 30F3 30C8;;;;N;SQUARED POINTO;;;; -333E;SQUARE BORUTO;So;0;L;<square> 30DC 30EB 30C8;;;;N;SQUARED BORUTO;;;; -333F;SQUARE HON;So;0;L;<square> 30DB 30F3;;;;N;SQUARED HON;;;; -3340;SQUARE PONDO;So;0;L;<square> 30DD 30F3 30C9;;;;N;SQUARED PONDO;;;; -3341;SQUARE HOORU;So;0;L;<square> 30DB 30FC 30EB;;;;N;SQUARED HOORU;;;; -3342;SQUARE HOON;So;0;L;<square> 30DB 30FC 30F3;;;;N;SQUARED HOON;;;; -3343;SQUARE MAIKURO;So;0;L;<square> 30DE 30A4 30AF 30ED;;;;N;SQUARED MAIKURO;;;; -3344;SQUARE MAIRU;So;0;L;<square> 30DE 30A4 30EB;;;;N;SQUARED MAIRU;;;; -3345;SQUARE MAHHA;So;0;L;<square> 30DE 30C3 30CF;;;;N;SQUARED MAHHA;;;; -3346;SQUARE MARUKU;So;0;L;<square> 30DE 30EB 30AF;;;;N;SQUARED MARUKU;;;; -3347;SQUARE MANSYON;So;0;L;<square> 30DE 30F3 30B7 30E7 30F3;;;;N;SQUARED MANSYON;;;; -3348;SQUARE MIKURON;So;0;L;<square> 30DF 30AF 30ED 30F3;;;;N;SQUARED MIKURON;;;; -3349;SQUARE MIRI;So;0;L;<square> 30DF 30EA;;;;N;SQUARED MIRI;;;; -334A;SQUARE MIRIBAARU;So;0;L;<square> 30DF 30EA 30D0 30FC 30EB;;;;N;SQUARED MIRIBAARU;;;; -334B;SQUARE MEGA;So;0;L;<square> 30E1 30AC;;;;N;SQUARED MEGA;;;; -334C;SQUARE MEGATON;So;0;L;<square> 30E1 30AC 30C8 30F3;;;;N;SQUARED MEGATON;;;; -334D;SQUARE MEETORU;So;0;L;<square> 30E1 30FC 30C8 30EB;;;;N;SQUARED MEETORU;;;; -334E;SQUARE YAADO;So;0;L;<square> 30E4 30FC 30C9;;;;N;SQUARED YAADO;;;; -334F;SQUARE YAARU;So;0;L;<square> 30E4 30FC 30EB;;;;N;SQUARED YAARU;;;; -3350;SQUARE YUAN;So;0;L;<square> 30E6 30A2 30F3;;;;N;SQUARED YUAN;;;; -3351;SQUARE RITTORU;So;0;L;<square> 30EA 30C3 30C8 30EB;;;;N;SQUARED RITTORU;;;; -3352;SQUARE RIRA;So;0;L;<square> 30EA 30E9;;;;N;SQUARED RIRA;;;; -3353;SQUARE RUPII;So;0;L;<square> 30EB 30D4 30FC;;;;N;SQUARED RUPII;;;; -3354;SQUARE RUUBURU;So;0;L;<square> 30EB 30FC 30D6 30EB;;;;N;SQUARED RUUBURU;;;; -3355;SQUARE REMU;So;0;L;<square> 30EC 30E0;;;;N;SQUARED REMU;;;; -3356;SQUARE RENTOGEN;So;0;L;<square> 30EC 30F3 30C8 30B2 30F3;;;;N;SQUARED RENTOGEN;;;; -3357;SQUARE WATTO;So;0;L;<square> 30EF 30C3 30C8;;;;N;SQUARED WATTO;;;; -3358;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO;So;0;L;<compat> 0030 70B9;;;;N;;;;; -3359;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ONE;So;0;L;<compat> 0031 70B9;;;;N;;;;; -335A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWO;So;0;L;<compat> 0032 70B9;;;;N;;;;; -335B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THREE;So;0;L;<compat> 0033 70B9;;;;N;;;;; -335C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOUR;So;0;L;<compat> 0034 70B9;;;;N;;;;; -335D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIVE;So;0;L;<compat> 0035 70B9;;;;N;;;;; -335E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIX;So;0;L;<compat> 0036 70B9;;;;N;;;;; -335F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVEN;So;0;L;<compat> 0037 70B9;;;;N;;;;; -3360;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHT;So;0;L;<compat> 0038 70B9;;;;N;;;;; -3361;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINE;So;0;L;<compat> 0039 70B9;;;;N;;;;; -3362;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TEN;So;0;L;<compat> 0031 0030 70B9;;;;N;;;;; -3363;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ELEVEN;So;0;L;<compat> 0031 0031 70B9;;;;N;;;;; -3364;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWELVE;So;0;L;<compat> 0031 0032 70B9;;;;N;;;;; -3365;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THIRTEEN;So;0;L;<compat> 0031 0033 70B9;;;;N;;;;; -3366;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOURTEEN;So;0;L;<compat> 0031 0034 70B9;;;;N;;;;; -3367;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIFTEEN;So;0;L;<compat> 0031 0035 70B9;;;;N;;;;; -3368;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIXTEEN;So;0;L;<compat> 0031 0036 70B9;;;;N;;;;; -3369;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENTEEN;So;0;L;<compat> 0031 0037 70B9;;;;N;;;;; -336A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHTEEN;So;0;L;<compat> 0031 0038 70B9;;;;N;;;;; -336B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINETEEN;So;0;L;<compat> 0031 0039 70B9;;;;N;;;;; -336C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY;So;0;L;<compat> 0032 0030 70B9;;;;N;;;;; -336D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-ONE;So;0;L;<compat> 0032 0031 70B9;;;;N;;;;; -336E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-TWO;So;0;L;<compat> 0032 0032 70B9;;;;N;;;;; -336F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-THREE;So;0;L;<compat> 0032 0033 70B9;;;;N;;;;; -3370;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOUR;So;0;L;<compat> 0032 0034 70B9;;;;N;;;;; -3371;SQUARE HPA;So;0;L;<square> 0068 0050 0061;;;;N;;;;; -3372;SQUARE DA;So;0;L;<square> 0064 0061;;;;N;;;;; -3373;SQUARE AU;So;0;L;<square> 0041 0055;;;;N;;;;; -3374;SQUARE BAR;So;0;L;<square> 0062 0061 0072;;;;N;;;;; -3375;SQUARE OV;So;0;L;<square> 006F 0056;;;;N;;;;; -3376;SQUARE PC;So;0;L;<square> 0070 0063;;;;N;;;;; -3377;SQUARE DM;So;0;ON;<square> 0064 006D;;;;N;;;;; -3378;SQUARE DM SQUARED;So;0;ON;<square> 0064 006D 00B2;;;;N;;;;; -3379;SQUARE DM CUBED;So;0;ON;<square> 0064 006D 00B3;;;;N;;;;; -337A;SQUARE IU;So;0;ON;<square> 0049 0055;;;;N;;;;; -337B;SQUARE ERA NAME HEISEI;So;0;L;<square> 5E73 6210;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME HEISEI;;;; -337C;SQUARE ERA NAME SYOUWA;So;0;L;<square> 662D 548C;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME SYOUWA;;;; -337D;SQUARE ERA NAME TAISYOU;So;0;L;<square> 5927 6B63;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME TAISYOU;;;; -337E;SQUARE ERA NAME MEIZI;So;0;L;<square> 660E 6CBB;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME MEIZI;;;; -337F;SQUARE CORPORATION;So;0;L;<square> 682A 5F0F 4F1A 793E;;;;N;SQUARED FOUR IDEOGRAPHS CORPORATION;;;; -3380;SQUARE PA AMPS;So;0;L;<square> 0070 0041;;;;N;SQUARED PA AMPS;;;; -3381;SQUARE NA;So;0;L;<square> 006E 0041;;;;N;SQUARED NA;;;; -3382;SQUARE MU A;So;0;L;<square> 03BC 0041;;;;N;SQUARED MU A;;;; -3383;SQUARE MA;So;0;L;<square> 006D 0041;;;;N;SQUARED MA;;;; -3384;SQUARE KA;So;0;L;<square> 006B 0041;;;;N;SQUARED KA;;;; -3385;SQUARE KB;So;0;L;<square> 004B 0042;;;;N;SQUARED KB;;;; -3386;SQUARE MB;So;0;L;<square> 004D 0042;;;;N;SQUARED MB;;;; -3387;SQUARE GB;So;0;L;<square> 0047 0042;;;;N;SQUARED GB;;;; -3388;SQUARE CAL;So;0;L;<square> 0063 0061 006C;;;;N;SQUARED CAL;;;; -3389;SQUARE KCAL;So;0;L;<square> 006B 0063 0061 006C;;;;N;SQUARED KCAL;;;; -338A;SQUARE PF;So;0;L;<square> 0070 0046;;;;N;SQUARED PF;;;; -338B;SQUARE NF;So;0;L;<square> 006E 0046;;;;N;SQUARED NF;;;; -338C;SQUARE MU F;So;0;L;<square> 03BC 0046;;;;N;SQUARED MU F;;;; -338D;SQUARE MU G;So;0;L;<square> 03BC 0067;;;;N;SQUARED MU G;;;; -338E;SQUARE MG;So;0;L;<square> 006D 0067;;;;N;SQUARED MG;;;; -338F;SQUARE KG;So;0;L;<square> 006B 0067;;;;N;SQUARED KG;;;; -3390;SQUARE HZ;So;0;L;<square> 0048 007A;;;;N;SQUARED HZ;;;; -3391;SQUARE KHZ;So;0;L;<square> 006B 0048 007A;;;;N;SQUARED KHZ;;;; -3392;SQUARE MHZ;So;0;L;<square> 004D 0048 007A;;;;N;SQUARED MHZ;;;; -3393;SQUARE GHZ;So;0;L;<square> 0047 0048 007A;;;;N;SQUARED GHZ;;;; -3394;SQUARE THZ;So;0;L;<square> 0054 0048 007A;;;;N;SQUARED THZ;;;; -3395;SQUARE MU L;So;0;L;<square> 03BC 2113;;;;N;SQUARED MU L;;;; -3396;SQUARE ML;So;0;L;<square> 006D 2113;;;;N;SQUARED ML;;;; -3397;SQUARE DL;So;0;L;<square> 0064 2113;;;;N;SQUARED DL;;;; -3398;SQUARE KL;So;0;L;<square> 006B 2113;;;;N;SQUARED KL;;;; -3399;SQUARE FM;So;0;L;<square> 0066 006D;;;;N;SQUARED FM;;;; -339A;SQUARE NM;So;0;L;<square> 006E 006D;;;;N;SQUARED NM;;;; -339B;SQUARE MU M;So;0;L;<square> 03BC 006D;;;;N;SQUARED MU M;;;; -339C;SQUARE MM;So;0;L;<square> 006D 006D;;;;N;SQUARED MM;;;; -339D;SQUARE CM;So;0;L;<square> 0063 006D;;;;N;SQUARED CM;;;; -339E;SQUARE KM;So;0;L;<square> 006B 006D;;;;N;SQUARED KM;;;; -339F;SQUARE MM SQUARED;So;0;L;<square> 006D 006D 00B2;;;;N;SQUARED MM SQUARED;;;; -33A0;SQUARE CM SQUARED;So;0;L;<square> 0063 006D 00B2;;;;N;SQUARED CM SQUARED;;;; -33A1;SQUARE M SQUARED;So;0;L;<square> 006D 00B2;;;;N;SQUARED M SQUARED;;;; -33A2;SQUARE KM SQUARED;So;0;L;<square> 006B 006D 00B2;;;;N;SQUARED KM SQUARED;;;; -33A3;SQUARE MM CUBED;So;0;L;<square> 006D 006D 00B3;;;;N;SQUARED MM CUBED;;;; -33A4;SQUARE CM CUBED;So;0;L;<square> 0063 006D 00B3;;;;N;SQUARED CM CUBED;;;; -33A5;SQUARE M CUBED;So;0;L;<square> 006D 00B3;;;;N;SQUARED M CUBED;;;; -33A6;SQUARE KM CUBED;So;0;L;<square> 006B 006D 00B3;;;;N;SQUARED KM CUBED;;;; -33A7;SQUARE M OVER S;So;0;L;<square> 006D 2215 0073;;;;N;SQUARED M OVER S;;;; -33A8;SQUARE M OVER S SQUARED;So;0;L;<square> 006D 2215 0073 00B2;;;;N;SQUARED M OVER S SQUARED;;;; -33A9;SQUARE PA;So;0;L;<square> 0050 0061;;;;N;SQUARED PA;;;; -33AA;SQUARE KPA;So;0;L;<square> 006B 0050 0061;;;;N;SQUARED KPA;;;; -33AB;SQUARE MPA;So;0;L;<square> 004D 0050 0061;;;;N;SQUARED MPA;;;; -33AC;SQUARE GPA;So;0;L;<square> 0047 0050 0061;;;;N;SQUARED GPA;;;; -33AD;SQUARE RAD;So;0;L;<square> 0072 0061 0064;;;;N;SQUARED RAD;;;; -33AE;SQUARE RAD OVER S;So;0;L;<square> 0072 0061 0064 2215 0073;;;;N;SQUARED RAD OVER S;;;; -33AF;SQUARE RAD OVER S SQUARED;So;0;L;<square> 0072 0061 0064 2215 0073 00B2;;;;N;SQUARED RAD OVER S SQUARED;;;; -33B0;SQUARE PS;So;0;L;<square> 0070 0073;;;;N;SQUARED PS;;;; -33B1;SQUARE NS;So;0;L;<square> 006E 0073;;;;N;SQUARED NS;;;; -33B2;SQUARE MU S;So;0;L;<square> 03BC 0073;;;;N;SQUARED MU S;;;; -33B3;SQUARE MS;So;0;L;<square> 006D 0073;;;;N;SQUARED MS;;;; -33B4;SQUARE PV;So;0;L;<square> 0070 0056;;;;N;SQUARED PV;;;; -33B5;SQUARE NV;So;0;L;<square> 006E 0056;;;;N;SQUARED NV;;;; -33B6;SQUARE MU V;So;0;L;<square> 03BC 0056;;;;N;SQUARED MU V;;;; -33B7;SQUARE MV;So;0;L;<square> 006D 0056;;;;N;SQUARED MV;;;; -33B8;SQUARE KV;So;0;L;<square> 006B 0056;;;;N;SQUARED KV;;;; -33B9;SQUARE MV MEGA;So;0;L;<square> 004D 0056;;;;N;SQUARED MV MEGA;;;; -33BA;SQUARE PW;So;0;L;<square> 0070 0057;;;;N;SQUARED PW;;;; -33BB;SQUARE NW;So;0;L;<square> 006E 0057;;;;N;SQUARED NW;;;; -33BC;SQUARE MU W;So;0;L;<square> 03BC 0057;;;;N;SQUARED MU W;;;; -33BD;SQUARE MW;So;0;L;<square> 006D 0057;;;;N;SQUARED MW;;;; -33BE;SQUARE KW;So;0;L;<square> 006B 0057;;;;N;SQUARED KW;;;; -33BF;SQUARE MW MEGA;So;0;L;<square> 004D 0057;;;;N;SQUARED MW MEGA;;;; -33C0;SQUARE K OHM;So;0;L;<square> 006B 03A9;;;;N;SQUARED K OHM;;;; -33C1;SQUARE M OHM;So;0;L;<square> 004D 03A9;;;;N;SQUARED M OHM;;;; -33C2;SQUARE AM;So;0;L;<square> 0061 002E 006D 002E;;;;N;SQUARED AM;;;; -33C3;SQUARE BQ;So;0;L;<square> 0042 0071;;;;N;SQUARED BQ;;;; -33C4;SQUARE CC;So;0;L;<square> 0063 0063;;;;N;SQUARED CC;;;; -33C5;SQUARE CD;So;0;L;<square> 0063 0064;;;;N;SQUARED CD;;;; -33C6;SQUARE C OVER KG;So;0;L;<square> 0043 2215 006B 0067;;;;N;SQUARED C OVER KG;;;; -33C7;SQUARE CO;So;0;L;<square> 0043 006F 002E;;;;N;SQUARED CO;;;; -33C8;SQUARE DB;So;0;L;<square> 0064 0042;;;;N;SQUARED DB;;;; -33C9;SQUARE GY;So;0;L;<square> 0047 0079;;;;N;SQUARED GY;;;; -33CA;SQUARE HA;So;0;L;<square> 0068 0061;;;;N;SQUARED HA;;;; -33CB;SQUARE HP;So;0;L;<square> 0048 0050;;;;N;SQUARED HP;;;; -33CC;SQUARE IN;So;0;L;<square> 0069 006E;;;;N;SQUARED IN;;;; -33CD;SQUARE KK;So;0;L;<square> 004B 004B;;;;N;SQUARED KK;;;; -33CE;SQUARE KM CAPITAL;So;0;L;<square> 004B 004D;;;;N;SQUARED KM CAPITAL;;;; -33CF;SQUARE KT;So;0;L;<square> 006B 0074;;;;N;SQUARED KT;;;; -33D0;SQUARE LM;So;0;L;<square> 006C 006D;;;;N;SQUARED LM;;;; -33D1;SQUARE LN;So;0;L;<square> 006C 006E;;;;N;SQUARED LN;;;; -33D2;SQUARE LOG;So;0;L;<square> 006C 006F 0067;;;;N;SQUARED LOG;;;; -33D3;SQUARE LX;So;0;L;<square> 006C 0078;;;;N;SQUARED LX;;;; -33D4;SQUARE MB SMALL;So;0;L;<square> 006D 0062;;;;N;SQUARED MB SMALL;;;; -33D5;SQUARE MIL;So;0;L;<square> 006D 0069 006C;;;;N;SQUARED MIL;;;; -33D6;SQUARE MOL;So;0;L;<square> 006D 006F 006C;;;;N;SQUARED MOL;;;; -33D7;SQUARE PH;So;0;L;<square> 0050 0048;;;;N;SQUARED PH;;;; -33D8;SQUARE PM;So;0;L;<square> 0070 002E 006D 002E;;;;N;SQUARED PM;;;; -33D9;SQUARE PPM;So;0;L;<square> 0050 0050 004D;;;;N;SQUARED PPM;;;; -33DA;SQUARE PR;So;0;L;<square> 0050 0052;;;;N;SQUARED PR;;;; -33DB;SQUARE SR;So;0;L;<square> 0073 0072;;;;N;SQUARED SR;;;; -33DC;SQUARE SV;So;0;L;<square> 0053 0076;;;;N;SQUARED SV;;;; -33DD;SQUARE WB;So;0;L;<square> 0057 0062;;;;N;SQUARED WB;;;; -33DE;SQUARE V OVER M;So;0;ON;<square> 0056 2215 006D;;;;N;;;;; -33DF;SQUARE A OVER M;So;0;ON;<square> 0041 2215 006D;;;;N;;;;; -33E0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE;So;0;L;<compat> 0031 65E5;;;;N;;;;; -33E1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWO;So;0;L;<compat> 0032 65E5;;;;N;;;;; -33E2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THREE;So;0;L;<compat> 0033 65E5;;;;N;;;;; -33E3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOUR;So;0;L;<compat> 0034 65E5;;;;N;;;;; -33E4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIVE;So;0;L;<compat> 0035 65E5;;;;N;;;;; -33E5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIX;So;0;L;<compat> 0036 65E5;;;;N;;;;; -33E6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVEN;So;0;L;<compat> 0037 65E5;;;;N;;;;; -33E7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHT;So;0;L;<compat> 0038 65E5;;;;N;;;;; -33E8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINE;So;0;L;<compat> 0039 65E5;;;;N;;;;; -33E9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TEN;So;0;L;<compat> 0031 0030 65E5;;;;N;;;;; -33EA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ELEVEN;So;0;L;<compat> 0031 0031 65E5;;;;N;;;;; -33EB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWELVE;So;0;L;<compat> 0031 0032 65E5;;;;N;;;;; -33EC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTEEN;So;0;L;<compat> 0031 0033 65E5;;;;N;;;;; -33ED;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOURTEEN;So;0;L;<compat> 0031 0034 65E5;;;;N;;;;; -33EE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIFTEEN;So;0;L;<compat> 0031 0035 65E5;;;;N;;;;; -33EF;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIXTEEN;So;0;L;<compat> 0031 0036 65E5;;;;N;;;;; -33F0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVENTEEN;So;0;L;<compat> 0031 0037 65E5;;;;N;;;;; -33F1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTEEN;So;0;L;<compat> 0031 0038 65E5;;;;N;;;;; -33F2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINETEEN;So;0;L;<compat> 0031 0039 65E5;;;;N;;;;; -33F3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY;So;0;L;<compat> 0032 0030 65E5;;;;N;;;;; -33F4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-ONE;So;0;L;<compat> 0032 0031 65E5;;;;N;;;;; -33F5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-TWO;So;0;L;<compat> 0032 0032 65E5;;;;N;;;;; -33F6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-THREE;So;0;L;<compat> 0032 0033 65E5;;;;N;;;;; -33F7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FOUR;So;0;L;<compat> 0032 0034 65E5;;;;N;;;;; -33F8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FIVE;So;0;L;<compat> 0032 0035 65E5;;;;N;;;;; -33F9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SIX;So;0;L;<compat> 0032 0036 65E5;;;;N;;;;; -33FA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SEVEN;So;0;L;<compat> 0032 0037 65E5;;;;N;;;;; -33FB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-EIGHT;So;0;L;<compat> 0032 0038 65E5;;;;N;;;;; -33FC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-NINE;So;0;L;<compat> 0032 0039 65E5;;;;N;;;;; -33FD;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY;So;0;L;<compat> 0033 0030 65E5;;;;N;;;;; -33FE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE;So;0;L;<compat> 0033 0031 65E5;;;;N;;;;; -33FF;SQUARE GAL;So;0;ON;<square> 0067 0061 006C;;;;N;;;;; -3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;; -4DBF;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;; -4DC0;HEXAGRAM FOR THE CREATIVE HEAVEN;So;0;ON;;;;;N;;;;; -4DC1;HEXAGRAM FOR THE RECEPTIVE EARTH;So;0;ON;;;;;N;;;;; -4DC2;HEXAGRAM FOR DIFFICULTY AT THE BEGINNING;So;0;ON;;;;;N;;;;; -4DC3;HEXAGRAM FOR YOUTHFUL FOLLY;So;0;ON;;;;;N;;;;; -4DC4;HEXAGRAM FOR WAITING;So;0;ON;;;;;N;;;;; -4DC5;HEXAGRAM FOR CONFLICT;So;0;ON;;;;;N;;;;; -4DC6;HEXAGRAM FOR THE ARMY;So;0;ON;;;;;N;;;;; -4DC7;HEXAGRAM FOR HOLDING TOGETHER;So;0;ON;;;;;N;;;;; -4DC8;HEXAGRAM FOR SMALL TAMING;So;0;ON;;;;;N;;;;; -4DC9;HEXAGRAM FOR TREADING;So;0;ON;;;;;N;;;;; -4DCA;HEXAGRAM FOR PEACE;So;0;ON;;;;;N;;;;; -4DCB;HEXAGRAM FOR STANDSTILL;So;0;ON;;;;;N;;;;; -4DCC;HEXAGRAM FOR FELLOWSHIP;So;0;ON;;;;;N;;;;; -4DCD;HEXAGRAM FOR GREAT POSSESSION;So;0;ON;;;;;N;;;;; -4DCE;HEXAGRAM FOR MODESTY;So;0;ON;;;;;N;;;;; -4DCF;HEXAGRAM FOR ENTHUSIASM;So;0;ON;;;;;N;;;;; -4DD0;HEXAGRAM FOR FOLLOWING;So;0;ON;;;;;N;;;;; -4DD1;HEXAGRAM FOR WORK ON THE DECAYED;So;0;ON;;;;;N;;;;; -4DD2;HEXAGRAM FOR APPROACH;So;0;ON;;;;;N;;;;; -4DD3;HEXAGRAM FOR CONTEMPLATION;So;0;ON;;;;;N;;;;; -4DD4;HEXAGRAM FOR BITING THROUGH;So;0;ON;;;;;N;;;;; -4DD5;HEXAGRAM FOR GRACE;So;0;ON;;;;;N;;;;; -4DD6;HEXAGRAM FOR SPLITTING APART;So;0;ON;;;;;N;;;;; -4DD7;HEXAGRAM FOR RETURN;So;0;ON;;;;;N;;;;; -4DD8;HEXAGRAM FOR INNOCENCE;So;0;ON;;;;;N;;;;; -4DD9;HEXAGRAM FOR GREAT TAMING;So;0;ON;;;;;N;;;;; -4DDA;HEXAGRAM FOR MOUTH CORNERS;So;0;ON;;;;;N;;;;; -4DDB;HEXAGRAM FOR GREAT PREPONDERANCE;So;0;ON;;;;;N;;;;; -4DDC;HEXAGRAM FOR THE ABYSMAL WATER;So;0;ON;;;;;N;;;;; -4DDD;HEXAGRAM FOR THE CLINGING FIRE;So;0;ON;;;;;N;;;;; -4DDE;HEXAGRAM FOR INFLUENCE;So;0;ON;;;;;N;;;;; -4DDF;HEXAGRAM FOR DURATION;So;0;ON;;;;;N;;;;; -4DE0;HEXAGRAM FOR RETREAT;So;0;ON;;;;;N;;;;; -4DE1;HEXAGRAM FOR GREAT POWER;So;0;ON;;;;;N;;;;; -4DE2;HEXAGRAM FOR PROGRESS;So;0;ON;;;;;N;;;;; -4DE3;HEXAGRAM FOR DARKENING OF THE LIGHT;So;0;ON;;;;;N;;;;; -4DE4;HEXAGRAM FOR THE FAMILY;So;0;ON;;;;;N;;;;; -4DE5;HEXAGRAM FOR OPPOSITION;So;0;ON;;;;;N;;;;; -4DE6;HEXAGRAM FOR OBSTRUCTION;So;0;ON;;;;;N;;;;; -4DE7;HEXAGRAM FOR DELIVERANCE;So;0;ON;;;;;N;;;;; -4DE8;HEXAGRAM FOR DECREASE;So;0;ON;;;;;N;;;;; -4DE9;HEXAGRAM FOR INCREASE;So;0;ON;;;;;N;;;;; -4DEA;HEXAGRAM FOR BREAKTHROUGH;So;0;ON;;;;;N;;;;; -4DEB;HEXAGRAM FOR COMING TO MEET;So;0;ON;;;;;N;;;;; -4DEC;HEXAGRAM FOR GATHERING TOGETHER;So;0;ON;;;;;N;;;;; -4DED;HEXAGRAM FOR PUSHING UPWARD;So;0;ON;;;;;N;;;;; -4DEE;HEXAGRAM FOR OPPRESSION;So;0;ON;;;;;N;;;;; -4DEF;HEXAGRAM FOR THE WELL;So;0;ON;;;;;N;;;;; -4DF0;HEXAGRAM FOR REVOLUTION;So;0;ON;;;;;N;;;;; -4DF1;HEXAGRAM FOR THE CAULDRON;So;0;ON;;;;;N;;;;; -4DF2;HEXAGRAM FOR THE AROUSING THUNDER;So;0;ON;;;;;N;;;;; -4DF3;HEXAGRAM FOR THE KEEPING STILL MOUNTAIN;So;0;ON;;;;;N;;;;; -4DF4;HEXAGRAM FOR DEVELOPMENT;So;0;ON;;;;;N;;;;; -4DF5;HEXAGRAM FOR THE MARRYING MAIDEN;So;0;ON;;;;;N;;;;; -4DF6;HEXAGRAM FOR ABUNDANCE;So;0;ON;;;;;N;;;;; -4DF7;HEXAGRAM FOR THE WANDERER;So;0;ON;;;;;N;;;;; -4DF8;HEXAGRAM FOR THE GENTLE WIND;So;0;ON;;;;;N;;;;; -4DF9;HEXAGRAM FOR THE JOYOUS LAKE;So;0;ON;;;;;N;;;;; -4DFA;HEXAGRAM FOR DISPERSION;So;0;ON;;;;;N;;;;; -4DFB;HEXAGRAM FOR LIMITATION;So;0;ON;;;;;N;;;;; -4DFC;HEXAGRAM FOR INNER TRUTH;So;0;ON;;;;;N;;;;; -4DFD;HEXAGRAM FOR SMALL PREPONDERANCE;So;0;ON;;;;;N;;;;; -4DFE;HEXAGRAM FOR AFTER COMPLETION;So;0;ON;;;;;N;;;;; -4DFF;HEXAGRAM FOR BEFORE COMPLETION;So;0;ON;;;;;N;;;;; -4E00;<CJK Ideograph, First>;Lo;0;L;;;;;N;;;;; -9FFF;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;; -A000;YI SYLLABLE IT;Lo;0;L;;;;;N;;;;; -A001;YI SYLLABLE IX;Lo;0;L;;;;;N;;;;; -A002;YI SYLLABLE I;Lo;0;L;;;;;N;;;;; -A003;YI SYLLABLE IP;Lo;0;L;;;;;N;;;;; -A004;YI SYLLABLE IET;Lo;0;L;;;;;N;;;;; -A005;YI SYLLABLE IEX;Lo;0;L;;;;;N;;;;; -A006;YI SYLLABLE IE;Lo;0;L;;;;;N;;;;; -A007;YI SYLLABLE IEP;Lo;0;L;;;;;N;;;;; -A008;YI SYLLABLE AT;Lo;0;L;;;;;N;;;;; -A009;YI SYLLABLE AX;Lo;0;L;;;;;N;;;;; -A00A;YI SYLLABLE A;Lo;0;L;;;;;N;;;;; -A00B;YI SYLLABLE AP;Lo;0;L;;;;;N;;;;; -A00C;YI SYLLABLE UOX;Lo;0;L;;;;;N;;;;; -A00D;YI SYLLABLE UO;Lo;0;L;;;;;N;;;;; -A00E;YI SYLLABLE UOP;Lo;0;L;;;;;N;;;;; -A00F;YI SYLLABLE OT;Lo;0;L;;;;;N;;;;; -A010;YI SYLLABLE OX;Lo;0;L;;;;;N;;;;; -A011;YI SYLLABLE O;Lo;0;L;;;;;N;;;;; -A012;YI SYLLABLE OP;Lo;0;L;;;;;N;;;;; -A013;YI SYLLABLE EX;Lo;0;L;;;;;N;;;;; -A014;YI SYLLABLE E;Lo;0;L;;;;;N;;;;; -A015;YI SYLLABLE WU;Lm;0;L;;;;;N;;;;; -A016;YI SYLLABLE BIT;Lo;0;L;;;;;N;;;;; -A017;YI SYLLABLE BIX;Lo;0;L;;;;;N;;;;; -A018;YI SYLLABLE BI;Lo;0;L;;;;;N;;;;; -A019;YI SYLLABLE BIP;Lo;0;L;;;;;N;;;;; -A01A;YI SYLLABLE BIET;Lo;0;L;;;;;N;;;;; -A01B;YI SYLLABLE BIEX;Lo;0;L;;;;;N;;;;; -A01C;YI SYLLABLE BIE;Lo;0;L;;;;;N;;;;; -A01D;YI SYLLABLE BIEP;Lo;0;L;;;;;N;;;;; -A01E;YI SYLLABLE BAT;Lo;0;L;;;;;N;;;;; -A01F;YI SYLLABLE BAX;Lo;0;L;;;;;N;;;;; -A020;YI SYLLABLE BA;Lo;0;L;;;;;N;;;;; -A021;YI SYLLABLE BAP;Lo;0;L;;;;;N;;;;; -A022;YI SYLLABLE BUOX;Lo;0;L;;;;;N;;;;; -A023;YI SYLLABLE BUO;Lo;0;L;;;;;N;;;;; -A024;YI SYLLABLE BUOP;Lo;0;L;;;;;N;;;;; -A025;YI SYLLABLE BOT;Lo;0;L;;;;;N;;;;; -A026;YI SYLLABLE BOX;Lo;0;L;;;;;N;;;;; -A027;YI SYLLABLE BO;Lo;0;L;;;;;N;;;;; -A028;YI SYLLABLE BOP;Lo;0;L;;;;;N;;;;; -A029;YI SYLLABLE BEX;Lo;0;L;;;;;N;;;;; -A02A;YI SYLLABLE BE;Lo;0;L;;;;;N;;;;; -A02B;YI SYLLABLE BEP;Lo;0;L;;;;;N;;;;; -A02C;YI SYLLABLE BUT;Lo;0;L;;;;;N;;;;; -A02D;YI SYLLABLE BUX;Lo;0;L;;;;;N;;;;; -A02E;YI SYLLABLE BU;Lo;0;L;;;;;N;;;;; -A02F;YI SYLLABLE BUP;Lo;0;L;;;;;N;;;;; -A030;YI SYLLABLE BURX;Lo;0;L;;;;;N;;;;; -A031;YI SYLLABLE BUR;Lo;0;L;;;;;N;;;;; -A032;YI SYLLABLE BYT;Lo;0;L;;;;;N;;;;; -A033;YI SYLLABLE BYX;Lo;0;L;;;;;N;;;;; -A034;YI SYLLABLE BY;Lo;0;L;;;;;N;;;;; -A035;YI SYLLABLE BYP;Lo;0;L;;;;;N;;;;; -A036;YI SYLLABLE BYRX;Lo;0;L;;;;;N;;;;; -A037;YI SYLLABLE BYR;Lo;0;L;;;;;N;;;;; -A038;YI SYLLABLE PIT;Lo;0;L;;;;;N;;;;; -A039;YI SYLLABLE PIX;Lo;0;L;;;;;N;;;;; -A03A;YI SYLLABLE PI;Lo;0;L;;;;;N;;;;; -A03B;YI SYLLABLE PIP;Lo;0;L;;;;;N;;;;; -A03C;YI SYLLABLE PIEX;Lo;0;L;;;;;N;;;;; -A03D;YI SYLLABLE PIE;Lo;0;L;;;;;N;;;;; -A03E;YI SYLLABLE PIEP;Lo;0;L;;;;;N;;;;; -A03F;YI SYLLABLE PAT;Lo;0;L;;;;;N;;;;; -A040;YI SYLLABLE PAX;Lo;0;L;;;;;N;;;;; -A041;YI SYLLABLE PA;Lo;0;L;;;;;N;;;;; -A042;YI SYLLABLE PAP;Lo;0;L;;;;;N;;;;; -A043;YI SYLLABLE PUOX;Lo;0;L;;;;;N;;;;; -A044;YI SYLLABLE PUO;Lo;0;L;;;;;N;;;;; -A045;YI SYLLABLE PUOP;Lo;0;L;;;;;N;;;;; -A046;YI SYLLABLE POT;Lo;0;L;;;;;N;;;;; -A047;YI SYLLABLE POX;Lo;0;L;;;;;N;;;;; -A048;YI SYLLABLE PO;Lo;0;L;;;;;N;;;;; -A049;YI SYLLABLE POP;Lo;0;L;;;;;N;;;;; -A04A;YI SYLLABLE PUT;Lo;0;L;;;;;N;;;;; -A04B;YI SYLLABLE PUX;Lo;0;L;;;;;N;;;;; -A04C;YI SYLLABLE PU;Lo;0;L;;;;;N;;;;; -A04D;YI SYLLABLE PUP;Lo;0;L;;;;;N;;;;; -A04E;YI SYLLABLE PURX;Lo;0;L;;;;;N;;;;; -A04F;YI SYLLABLE PUR;Lo;0;L;;;;;N;;;;; -A050;YI SYLLABLE PYT;Lo;0;L;;;;;N;;;;; -A051;YI SYLLABLE PYX;Lo;0;L;;;;;N;;;;; -A052;YI SYLLABLE PY;Lo;0;L;;;;;N;;;;; -A053;YI SYLLABLE PYP;Lo;0;L;;;;;N;;;;; -A054;YI SYLLABLE PYRX;Lo;0;L;;;;;N;;;;; -A055;YI SYLLABLE PYR;Lo;0;L;;;;;N;;;;; -A056;YI SYLLABLE BBIT;Lo;0;L;;;;;N;;;;; -A057;YI SYLLABLE BBIX;Lo;0;L;;;;;N;;;;; -A058;YI SYLLABLE BBI;Lo;0;L;;;;;N;;;;; -A059;YI SYLLABLE BBIP;Lo;0;L;;;;;N;;;;; -A05A;YI SYLLABLE BBIET;Lo;0;L;;;;;N;;;;; -A05B;YI SYLLABLE BBIEX;Lo;0;L;;;;;N;;;;; -A05C;YI SYLLABLE BBIE;Lo;0;L;;;;;N;;;;; -A05D;YI SYLLABLE BBIEP;Lo;0;L;;;;;N;;;;; -A05E;YI SYLLABLE BBAT;Lo;0;L;;;;;N;;;;; -A05F;YI SYLLABLE BBAX;Lo;0;L;;;;;N;;;;; -A060;YI SYLLABLE BBA;Lo;0;L;;;;;N;;;;; -A061;YI SYLLABLE BBAP;Lo;0;L;;;;;N;;;;; -A062;YI SYLLABLE BBUOX;Lo;0;L;;;;;N;;;;; -A063;YI SYLLABLE BBUO;Lo;0;L;;;;;N;;;;; -A064;YI SYLLABLE BBUOP;Lo;0;L;;;;;N;;;;; -A065;YI SYLLABLE BBOT;Lo;0;L;;;;;N;;;;; -A066;YI SYLLABLE BBOX;Lo;0;L;;;;;N;;;;; -A067;YI SYLLABLE BBO;Lo;0;L;;;;;N;;;;; -A068;YI SYLLABLE BBOP;Lo;0;L;;;;;N;;;;; -A069;YI SYLLABLE BBEX;Lo;0;L;;;;;N;;;;; -A06A;YI SYLLABLE BBE;Lo;0;L;;;;;N;;;;; -A06B;YI SYLLABLE BBEP;Lo;0;L;;;;;N;;;;; -A06C;YI SYLLABLE BBUT;Lo;0;L;;;;;N;;;;; -A06D;YI SYLLABLE BBUX;Lo;0;L;;;;;N;;;;; -A06E;YI SYLLABLE BBU;Lo;0;L;;;;;N;;;;; -A06F;YI SYLLABLE BBUP;Lo;0;L;;;;;N;;;;; -A070;YI SYLLABLE BBURX;Lo;0;L;;;;;N;;;;; -A071;YI SYLLABLE BBUR;Lo;0;L;;;;;N;;;;; -A072;YI SYLLABLE BBYT;Lo;0;L;;;;;N;;;;; -A073;YI SYLLABLE BBYX;Lo;0;L;;;;;N;;;;; -A074;YI SYLLABLE BBY;Lo;0;L;;;;;N;;;;; -A075;YI SYLLABLE BBYP;Lo;0;L;;;;;N;;;;; -A076;YI SYLLABLE NBIT;Lo;0;L;;;;;N;;;;; -A077;YI SYLLABLE NBIX;Lo;0;L;;;;;N;;;;; -A078;YI SYLLABLE NBI;Lo;0;L;;;;;N;;;;; -A079;YI SYLLABLE NBIP;Lo;0;L;;;;;N;;;;; -A07A;YI SYLLABLE NBIEX;Lo;0;L;;;;;N;;;;; -A07B;YI SYLLABLE NBIE;Lo;0;L;;;;;N;;;;; -A07C;YI SYLLABLE NBIEP;Lo;0;L;;;;;N;;;;; -A07D;YI SYLLABLE NBAT;Lo;0;L;;;;;N;;;;; -A07E;YI SYLLABLE NBAX;Lo;0;L;;;;;N;;;;; -A07F;YI SYLLABLE NBA;Lo;0;L;;;;;N;;;;; -A080;YI SYLLABLE NBAP;Lo;0;L;;;;;N;;;;; -A081;YI SYLLABLE NBOT;Lo;0;L;;;;;N;;;;; -A082;YI SYLLABLE NBOX;Lo;0;L;;;;;N;;;;; -A083;YI SYLLABLE NBO;Lo;0;L;;;;;N;;;;; -A084;YI SYLLABLE NBOP;Lo;0;L;;;;;N;;;;; -A085;YI SYLLABLE NBUT;Lo;0;L;;;;;N;;;;; -A086;YI SYLLABLE NBUX;Lo;0;L;;;;;N;;;;; -A087;YI SYLLABLE NBU;Lo;0;L;;;;;N;;;;; -A088;YI SYLLABLE NBUP;Lo;0;L;;;;;N;;;;; -A089;YI SYLLABLE NBURX;Lo;0;L;;;;;N;;;;; -A08A;YI SYLLABLE NBUR;Lo;0;L;;;;;N;;;;; -A08B;YI SYLLABLE NBYT;Lo;0;L;;;;;N;;;;; -A08C;YI SYLLABLE NBYX;Lo;0;L;;;;;N;;;;; -A08D;YI SYLLABLE NBY;Lo;0;L;;;;;N;;;;; -A08E;YI SYLLABLE NBYP;Lo;0;L;;;;;N;;;;; -A08F;YI SYLLABLE NBYRX;Lo;0;L;;;;;N;;;;; -A090;YI SYLLABLE NBYR;Lo;0;L;;;;;N;;;;; -A091;YI SYLLABLE HMIT;Lo;0;L;;;;;N;;;;; -A092;YI SYLLABLE HMIX;Lo;0;L;;;;;N;;;;; -A093;YI SYLLABLE HMI;Lo;0;L;;;;;N;;;;; -A094;YI SYLLABLE HMIP;Lo;0;L;;;;;N;;;;; -A095;YI SYLLABLE HMIEX;Lo;0;L;;;;;N;;;;; -A096;YI SYLLABLE HMIE;Lo;0;L;;;;;N;;;;; -A097;YI SYLLABLE HMIEP;Lo;0;L;;;;;N;;;;; -A098;YI SYLLABLE HMAT;Lo;0;L;;;;;N;;;;; -A099;YI SYLLABLE HMAX;Lo;0;L;;;;;N;;;;; -A09A;YI SYLLABLE HMA;Lo;0;L;;;;;N;;;;; -A09B;YI SYLLABLE HMAP;Lo;0;L;;;;;N;;;;; -A09C;YI SYLLABLE HMUOX;Lo;0;L;;;;;N;;;;; -A09D;YI SYLLABLE HMUO;Lo;0;L;;;;;N;;;;; -A09E;YI SYLLABLE HMUOP;Lo;0;L;;;;;N;;;;; -A09F;YI SYLLABLE HMOT;Lo;0;L;;;;;N;;;;; -A0A0;YI SYLLABLE HMOX;Lo;0;L;;;;;N;;;;; -A0A1;YI SYLLABLE HMO;Lo;0;L;;;;;N;;;;; -A0A2;YI SYLLABLE HMOP;Lo;0;L;;;;;N;;;;; -A0A3;YI SYLLABLE HMUT;Lo;0;L;;;;;N;;;;; -A0A4;YI SYLLABLE HMUX;Lo;0;L;;;;;N;;;;; -A0A5;YI SYLLABLE HMU;Lo;0;L;;;;;N;;;;; -A0A6;YI SYLLABLE HMUP;Lo;0;L;;;;;N;;;;; -A0A7;YI SYLLABLE HMURX;Lo;0;L;;;;;N;;;;; -A0A8;YI SYLLABLE HMUR;Lo;0;L;;;;;N;;;;; -A0A9;YI SYLLABLE HMYX;Lo;0;L;;;;;N;;;;; -A0AA;YI SYLLABLE HMY;Lo;0;L;;;;;N;;;;; -A0AB;YI SYLLABLE HMYP;Lo;0;L;;;;;N;;;;; -A0AC;YI SYLLABLE HMYRX;Lo;0;L;;;;;N;;;;; -A0AD;YI SYLLABLE HMYR;Lo;0;L;;;;;N;;;;; -A0AE;YI SYLLABLE MIT;Lo;0;L;;;;;N;;;;; -A0AF;YI SYLLABLE MIX;Lo;0;L;;;;;N;;;;; -A0B0;YI SYLLABLE MI;Lo;0;L;;;;;N;;;;; -A0B1;YI SYLLABLE MIP;Lo;0;L;;;;;N;;;;; -A0B2;YI SYLLABLE MIEX;Lo;0;L;;;;;N;;;;; -A0B3;YI SYLLABLE MIE;Lo;0;L;;;;;N;;;;; -A0B4;YI SYLLABLE MIEP;Lo;0;L;;;;;N;;;;; -A0B5;YI SYLLABLE MAT;Lo;0;L;;;;;N;;;;; -A0B6;YI SYLLABLE MAX;Lo;0;L;;;;;N;;;;; -A0B7;YI SYLLABLE MA;Lo;0;L;;;;;N;;;;; -A0B8;YI SYLLABLE MAP;Lo;0;L;;;;;N;;;;; -A0B9;YI SYLLABLE MUOT;Lo;0;L;;;;;N;;;;; -A0BA;YI SYLLABLE MUOX;Lo;0;L;;;;;N;;;;; -A0BB;YI SYLLABLE MUO;Lo;0;L;;;;;N;;;;; -A0BC;YI SYLLABLE MUOP;Lo;0;L;;;;;N;;;;; -A0BD;YI SYLLABLE MOT;Lo;0;L;;;;;N;;;;; -A0BE;YI SYLLABLE MOX;Lo;0;L;;;;;N;;;;; -A0BF;YI SYLLABLE MO;Lo;0;L;;;;;N;;;;; -A0C0;YI SYLLABLE MOP;Lo;0;L;;;;;N;;;;; -A0C1;YI SYLLABLE MEX;Lo;0;L;;;;;N;;;;; -A0C2;YI SYLLABLE ME;Lo;0;L;;;;;N;;;;; -A0C3;YI SYLLABLE MUT;Lo;0;L;;;;;N;;;;; -A0C4;YI SYLLABLE MUX;Lo;0;L;;;;;N;;;;; -A0C5;YI SYLLABLE MU;Lo;0;L;;;;;N;;;;; -A0C6;YI SYLLABLE MUP;Lo;0;L;;;;;N;;;;; -A0C7;YI SYLLABLE MURX;Lo;0;L;;;;;N;;;;; -A0C8;YI SYLLABLE MUR;Lo;0;L;;;;;N;;;;; -A0C9;YI SYLLABLE MYT;Lo;0;L;;;;;N;;;;; -A0CA;YI SYLLABLE MYX;Lo;0;L;;;;;N;;;;; -A0CB;YI SYLLABLE MY;Lo;0;L;;;;;N;;;;; -A0CC;YI SYLLABLE MYP;Lo;0;L;;;;;N;;;;; -A0CD;YI SYLLABLE FIT;Lo;0;L;;;;;N;;;;; -A0CE;YI SYLLABLE FIX;Lo;0;L;;;;;N;;;;; -A0CF;YI SYLLABLE FI;Lo;0;L;;;;;N;;;;; -A0D0;YI SYLLABLE FIP;Lo;0;L;;;;;N;;;;; -A0D1;YI SYLLABLE FAT;Lo;0;L;;;;;N;;;;; -A0D2;YI SYLLABLE FAX;Lo;0;L;;;;;N;;;;; -A0D3;YI SYLLABLE FA;Lo;0;L;;;;;N;;;;; -A0D4;YI SYLLABLE FAP;Lo;0;L;;;;;N;;;;; -A0D5;YI SYLLABLE FOX;Lo;0;L;;;;;N;;;;; -A0D6;YI SYLLABLE FO;Lo;0;L;;;;;N;;;;; -A0D7;YI SYLLABLE FOP;Lo;0;L;;;;;N;;;;; -A0D8;YI SYLLABLE FUT;Lo;0;L;;;;;N;;;;; -A0D9;YI SYLLABLE FUX;Lo;0;L;;;;;N;;;;; -A0DA;YI SYLLABLE FU;Lo;0;L;;;;;N;;;;; -A0DB;YI SYLLABLE FUP;Lo;0;L;;;;;N;;;;; -A0DC;YI SYLLABLE FURX;Lo;0;L;;;;;N;;;;; -A0DD;YI SYLLABLE FUR;Lo;0;L;;;;;N;;;;; -A0DE;YI SYLLABLE FYT;Lo;0;L;;;;;N;;;;; -A0DF;YI SYLLABLE FYX;Lo;0;L;;;;;N;;;;; -A0E0;YI SYLLABLE FY;Lo;0;L;;;;;N;;;;; -A0E1;YI SYLLABLE FYP;Lo;0;L;;;;;N;;;;; -A0E2;YI SYLLABLE VIT;Lo;0;L;;;;;N;;;;; -A0E3;YI SYLLABLE VIX;Lo;0;L;;;;;N;;;;; -A0E4;YI SYLLABLE VI;Lo;0;L;;;;;N;;;;; -A0E5;YI SYLLABLE VIP;Lo;0;L;;;;;N;;;;; -A0E6;YI SYLLABLE VIET;Lo;0;L;;;;;N;;;;; -A0E7;YI SYLLABLE VIEX;Lo;0;L;;;;;N;;;;; -A0E8;YI SYLLABLE VIE;Lo;0;L;;;;;N;;;;; -A0E9;YI SYLLABLE VIEP;Lo;0;L;;;;;N;;;;; -A0EA;YI SYLLABLE VAT;Lo;0;L;;;;;N;;;;; -A0EB;YI SYLLABLE VAX;Lo;0;L;;;;;N;;;;; -A0EC;YI SYLLABLE VA;Lo;0;L;;;;;N;;;;; -A0ED;YI SYLLABLE VAP;Lo;0;L;;;;;N;;;;; -A0EE;YI SYLLABLE VOT;Lo;0;L;;;;;N;;;;; -A0EF;YI SYLLABLE VOX;Lo;0;L;;;;;N;;;;; -A0F0;YI SYLLABLE VO;Lo;0;L;;;;;N;;;;; -A0F1;YI SYLLABLE VOP;Lo;0;L;;;;;N;;;;; -A0F2;YI SYLLABLE VEX;Lo;0;L;;;;;N;;;;; -A0F3;YI SYLLABLE VEP;Lo;0;L;;;;;N;;;;; -A0F4;YI SYLLABLE VUT;Lo;0;L;;;;;N;;;;; -A0F5;YI SYLLABLE VUX;Lo;0;L;;;;;N;;;;; -A0F6;YI SYLLABLE VU;Lo;0;L;;;;;N;;;;; -A0F7;YI SYLLABLE VUP;Lo;0;L;;;;;N;;;;; -A0F8;YI SYLLABLE VURX;Lo;0;L;;;;;N;;;;; -A0F9;YI SYLLABLE VUR;Lo;0;L;;;;;N;;;;; -A0FA;YI SYLLABLE VYT;Lo;0;L;;;;;N;;;;; -A0FB;YI SYLLABLE VYX;Lo;0;L;;;;;N;;;;; -A0FC;YI SYLLABLE VY;Lo;0;L;;;;;N;;;;; -A0FD;YI SYLLABLE VYP;Lo;0;L;;;;;N;;;;; -A0FE;YI SYLLABLE VYRX;Lo;0;L;;;;;N;;;;; -A0FF;YI SYLLABLE VYR;Lo;0;L;;;;;N;;;;; -A100;YI SYLLABLE DIT;Lo;0;L;;;;;N;;;;; -A101;YI SYLLABLE DIX;Lo;0;L;;;;;N;;;;; -A102;YI SYLLABLE DI;Lo;0;L;;;;;N;;;;; -A103;YI SYLLABLE DIP;Lo;0;L;;;;;N;;;;; -A104;YI SYLLABLE DIEX;Lo;0;L;;;;;N;;;;; -A105;YI SYLLABLE DIE;Lo;0;L;;;;;N;;;;; -A106;YI SYLLABLE DIEP;Lo;0;L;;;;;N;;;;; -A107;YI SYLLABLE DAT;Lo;0;L;;;;;N;;;;; -A108;YI SYLLABLE DAX;Lo;0;L;;;;;N;;;;; -A109;YI SYLLABLE DA;Lo;0;L;;;;;N;;;;; -A10A;YI SYLLABLE DAP;Lo;0;L;;;;;N;;;;; -A10B;YI SYLLABLE DUOX;Lo;0;L;;;;;N;;;;; -A10C;YI SYLLABLE DUO;Lo;0;L;;;;;N;;;;; -A10D;YI SYLLABLE DOT;Lo;0;L;;;;;N;;;;; -A10E;YI SYLLABLE DOX;Lo;0;L;;;;;N;;;;; -A10F;YI SYLLABLE DO;Lo;0;L;;;;;N;;;;; -A110;YI SYLLABLE DOP;Lo;0;L;;;;;N;;;;; -A111;YI SYLLABLE DEX;Lo;0;L;;;;;N;;;;; -A112;YI SYLLABLE DE;Lo;0;L;;;;;N;;;;; -A113;YI SYLLABLE DEP;Lo;0;L;;;;;N;;;;; -A114;YI SYLLABLE DUT;Lo;0;L;;;;;N;;;;; -A115;YI SYLLABLE DUX;Lo;0;L;;;;;N;;;;; -A116;YI SYLLABLE DU;Lo;0;L;;;;;N;;;;; -A117;YI SYLLABLE DUP;Lo;0;L;;;;;N;;;;; -A118;YI SYLLABLE DURX;Lo;0;L;;;;;N;;;;; -A119;YI SYLLABLE DUR;Lo;0;L;;;;;N;;;;; -A11A;YI SYLLABLE TIT;Lo;0;L;;;;;N;;;;; -A11B;YI SYLLABLE TIX;Lo;0;L;;;;;N;;;;; -A11C;YI SYLLABLE TI;Lo;0;L;;;;;N;;;;; -A11D;YI SYLLABLE TIP;Lo;0;L;;;;;N;;;;; -A11E;YI SYLLABLE TIEX;Lo;0;L;;;;;N;;;;; -A11F;YI SYLLABLE TIE;Lo;0;L;;;;;N;;;;; -A120;YI SYLLABLE TIEP;Lo;0;L;;;;;N;;;;; -A121;YI SYLLABLE TAT;Lo;0;L;;;;;N;;;;; -A122;YI SYLLABLE TAX;Lo;0;L;;;;;N;;;;; -A123;YI SYLLABLE TA;Lo;0;L;;;;;N;;;;; -A124;YI SYLLABLE TAP;Lo;0;L;;;;;N;;;;; -A125;YI SYLLABLE TUOT;Lo;0;L;;;;;N;;;;; -A126;YI SYLLABLE TUOX;Lo;0;L;;;;;N;;;;; -A127;YI SYLLABLE TUO;Lo;0;L;;;;;N;;;;; -A128;YI SYLLABLE TUOP;Lo;0;L;;;;;N;;;;; -A129;YI SYLLABLE TOT;Lo;0;L;;;;;N;;;;; -A12A;YI SYLLABLE TOX;Lo;0;L;;;;;N;;;;; -A12B;YI SYLLABLE TO;Lo;0;L;;;;;N;;;;; -A12C;YI SYLLABLE TOP;Lo;0;L;;;;;N;;;;; -A12D;YI SYLLABLE TEX;Lo;0;L;;;;;N;;;;; -A12E;YI SYLLABLE TE;Lo;0;L;;;;;N;;;;; -A12F;YI SYLLABLE TEP;Lo;0;L;;;;;N;;;;; -A130;YI SYLLABLE TUT;Lo;0;L;;;;;N;;;;; -A131;YI SYLLABLE TUX;Lo;0;L;;;;;N;;;;; -A132;YI SYLLABLE TU;Lo;0;L;;;;;N;;;;; -A133;YI SYLLABLE TUP;Lo;0;L;;;;;N;;;;; -A134;YI SYLLABLE TURX;Lo;0;L;;;;;N;;;;; -A135;YI SYLLABLE TUR;Lo;0;L;;;;;N;;;;; -A136;YI SYLLABLE DDIT;Lo;0;L;;;;;N;;;;; -A137;YI SYLLABLE DDIX;Lo;0;L;;;;;N;;;;; -A138;YI SYLLABLE DDI;Lo;0;L;;;;;N;;;;; -A139;YI SYLLABLE DDIP;Lo;0;L;;;;;N;;;;; -A13A;YI SYLLABLE DDIEX;Lo;0;L;;;;;N;;;;; -A13B;YI SYLLABLE DDIE;Lo;0;L;;;;;N;;;;; -A13C;YI SYLLABLE DDIEP;Lo;0;L;;;;;N;;;;; -A13D;YI SYLLABLE DDAT;Lo;0;L;;;;;N;;;;; -A13E;YI SYLLABLE DDAX;Lo;0;L;;;;;N;;;;; -A13F;YI SYLLABLE DDA;Lo;0;L;;;;;N;;;;; -A140;YI SYLLABLE DDAP;Lo;0;L;;;;;N;;;;; -A141;YI SYLLABLE DDUOX;Lo;0;L;;;;;N;;;;; -A142;YI SYLLABLE DDUO;Lo;0;L;;;;;N;;;;; -A143;YI SYLLABLE DDUOP;Lo;0;L;;;;;N;;;;; -A144;YI SYLLABLE DDOT;Lo;0;L;;;;;N;;;;; -A145;YI SYLLABLE DDOX;Lo;0;L;;;;;N;;;;; -A146;YI SYLLABLE DDO;Lo;0;L;;;;;N;;;;; -A147;YI SYLLABLE DDOP;Lo;0;L;;;;;N;;;;; -A148;YI SYLLABLE DDEX;Lo;0;L;;;;;N;;;;; -A149;YI SYLLABLE DDE;Lo;0;L;;;;;N;;;;; -A14A;YI SYLLABLE DDEP;Lo;0;L;;;;;N;;;;; -A14B;YI SYLLABLE DDUT;Lo;0;L;;;;;N;;;;; -A14C;YI SYLLABLE DDUX;Lo;0;L;;;;;N;;;;; -A14D;YI SYLLABLE DDU;Lo;0;L;;;;;N;;;;; -A14E;YI SYLLABLE DDUP;Lo;0;L;;;;;N;;;;; -A14F;YI SYLLABLE DDURX;Lo;0;L;;;;;N;;;;; -A150;YI SYLLABLE DDUR;Lo;0;L;;;;;N;;;;; -A151;YI SYLLABLE NDIT;Lo;0;L;;;;;N;;;;; -A152;YI SYLLABLE NDIX;Lo;0;L;;;;;N;;;;; -A153;YI SYLLABLE NDI;Lo;0;L;;;;;N;;;;; -A154;YI SYLLABLE NDIP;Lo;0;L;;;;;N;;;;; -A155;YI SYLLABLE NDIEX;Lo;0;L;;;;;N;;;;; -A156;YI SYLLABLE NDIE;Lo;0;L;;;;;N;;;;; -A157;YI SYLLABLE NDAT;Lo;0;L;;;;;N;;;;; -A158;YI SYLLABLE NDAX;Lo;0;L;;;;;N;;;;; -A159;YI SYLLABLE NDA;Lo;0;L;;;;;N;;;;; -A15A;YI SYLLABLE NDAP;Lo;0;L;;;;;N;;;;; -A15B;YI SYLLABLE NDOT;Lo;0;L;;;;;N;;;;; -A15C;YI SYLLABLE NDOX;Lo;0;L;;;;;N;;;;; -A15D;YI SYLLABLE NDO;Lo;0;L;;;;;N;;;;; -A15E;YI SYLLABLE NDOP;Lo;0;L;;;;;N;;;;; -A15F;YI SYLLABLE NDEX;Lo;0;L;;;;;N;;;;; -A160;YI SYLLABLE NDE;Lo;0;L;;;;;N;;;;; -A161;YI SYLLABLE NDEP;Lo;0;L;;;;;N;;;;; -A162;YI SYLLABLE NDUT;Lo;0;L;;;;;N;;;;; -A163;YI SYLLABLE NDUX;Lo;0;L;;;;;N;;;;; -A164;YI SYLLABLE NDU;Lo;0;L;;;;;N;;;;; -A165;YI SYLLABLE NDUP;Lo;0;L;;;;;N;;;;; -A166;YI SYLLABLE NDURX;Lo;0;L;;;;;N;;;;; -A167;YI SYLLABLE NDUR;Lo;0;L;;;;;N;;;;; -A168;YI SYLLABLE HNIT;Lo;0;L;;;;;N;;;;; -A169;YI SYLLABLE HNIX;Lo;0;L;;;;;N;;;;; -A16A;YI SYLLABLE HNI;Lo;0;L;;;;;N;;;;; -A16B;YI SYLLABLE HNIP;Lo;0;L;;;;;N;;;;; -A16C;YI SYLLABLE HNIET;Lo;0;L;;;;;N;;;;; -A16D;YI SYLLABLE HNIEX;Lo;0;L;;;;;N;;;;; -A16E;YI SYLLABLE HNIE;Lo;0;L;;;;;N;;;;; -A16F;YI SYLLABLE HNIEP;Lo;0;L;;;;;N;;;;; -A170;YI SYLLABLE HNAT;Lo;0;L;;;;;N;;;;; -A171;YI SYLLABLE HNAX;Lo;0;L;;;;;N;;;;; -A172;YI SYLLABLE HNA;Lo;0;L;;;;;N;;;;; -A173;YI SYLLABLE HNAP;Lo;0;L;;;;;N;;;;; -A174;YI SYLLABLE HNUOX;Lo;0;L;;;;;N;;;;; -A175;YI SYLLABLE HNUO;Lo;0;L;;;;;N;;;;; -A176;YI SYLLABLE HNOT;Lo;0;L;;;;;N;;;;; -A177;YI SYLLABLE HNOX;Lo;0;L;;;;;N;;;;; -A178;YI SYLLABLE HNOP;Lo;0;L;;;;;N;;;;; -A179;YI SYLLABLE HNEX;Lo;0;L;;;;;N;;;;; -A17A;YI SYLLABLE HNE;Lo;0;L;;;;;N;;;;; -A17B;YI SYLLABLE HNEP;Lo;0;L;;;;;N;;;;; -A17C;YI SYLLABLE HNUT;Lo;0;L;;;;;N;;;;; -A17D;YI SYLLABLE NIT;Lo;0;L;;;;;N;;;;; -A17E;YI SYLLABLE NIX;Lo;0;L;;;;;N;;;;; -A17F;YI SYLLABLE NI;Lo;0;L;;;;;N;;;;; -A180;YI SYLLABLE NIP;Lo;0;L;;;;;N;;;;; -A181;YI SYLLABLE NIEX;Lo;0;L;;;;;N;;;;; -A182;YI SYLLABLE NIE;Lo;0;L;;;;;N;;;;; -A183;YI SYLLABLE NIEP;Lo;0;L;;;;;N;;;;; -A184;YI SYLLABLE NAX;Lo;0;L;;;;;N;;;;; -A185;YI SYLLABLE NA;Lo;0;L;;;;;N;;;;; -A186;YI SYLLABLE NAP;Lo;0;L;;;;;N;;;;; -A187;YI SYLLABLE NUOX;Lo;0;L;;;;;N;;;;; -A188;YI SYLLABLE NUO;Lo;0;L;;;;;N;;;;; -A189;YI SYLLABLE NUOP;Lo;0;L;;;;;N;;;;; -A18A;YI SYLLABLE NOT;Lo;0;L;;;;;N;;;;; -A18B;YI SYLLABLE NOX;Lo;0;L;;;;;N;;;;; -A18C;YI SYLLABLE NO;Lo;0;L;;;;;N;;;;; -A18D;YI SYLLABLE NOP;Lo;0;L;;;;;N;;;;; -A18E;YI SYLLABLE NEX;Lo;0;L;;;;;N;;;;; -A18F;YI SYLLABLE NE;Lo;0;L;;;;;N;;;;; -A190;YI SYLLABLE NEP;Lo;0;L;;;;;N;;;;; -A191;YI SYLLABLE NUT;Lo;0;L;;;;;N;;;;; -A192;YI SYLLABLE NUX;Lo;0;L;;;;;N;;;;; -A193;YI SYLLABLE NU;Lo;0;L;;;;;N;;;;; -A194;YI SYLLABLE NUP;Lo;0;L;;;;;N;;;;; -A195;YI SYLLABLE NURX;Lo;0;L;;;;;N;;;;; -A196;YI SYLLABLE NUR;Lo;0;L;;;;;N;;;;; -A197;YI SYLLABLE HLIT;Lo;0;L;;;;;N;;;;; -A198;YI SYLLABLE HLIX;Lo;0;L;;;;;N;;;;; -A199;YI SYLLABLE HLI;Lo;0;L;;;;;N;;;;; -A19A;YI SYLLABLE HLIP;Lo;0;L;;;;;N;;;;; -A19B;YI SYLLABLE HLIEX;Lo;0;L;;;;;N;;;;; -A19C;YI SYLLABLE HLIE;Lo;0;L;;;;;N;;;;; -A19D;YI SYLLABLE HLIEP;Lo;0;L;;;;;N;;;;; -A19E;YI SYLLABLE HLAT;Lo;0;L;;;;;N;;;;; -A19F;YI SYLLABLE HLAX;Lo;0;L;;;;;N;;;;; -A1A0;YI SYLLABLE HLA;Lo;0;L;;;;;N;;;;; -A1A1;YI SYLLABLE HLAP;Lo;0;L;;;;;N;;;;; -A1A2;YI SYLLABLE HLUOX;Lo;0;L;;;;;N;;;;; -A1A3;YI SYLLABLE HLUO;Lo;0;L;;;;;N;;;;; -A1A4;YI SYLLABLE HLUOP;Lo;0;L;;;;;N;;;;; -A1A5;YI SYLLABLE HLOX;Lo;0;L;;;;;N;;;;; -A1A6;YI SYLLABLE HLO;Lo;0;L;;;;;N;;;;; -A1A7;YI SYLLABLE HLOP;Lo;0;L;;;;;N;;;;; -A1A8;YI SYLLABLE HLEX;Lo;0;L;;;;;N;;;;; -A1A9;YI SYLLABLE HLE;Lo;0;L;;;;;N;;;;; -A1AA;YI SYLLABLE HLEP;Lo;0;L;;;;;N;;;;; -A1AB;YI SYLLABLE HLUT;Lo;0;L;;;;;N;;;;; -A1AC;YI SYLLABLE HLUX;Lo;0;L;;;;;N;;;;; -A1AD;YI SYLLABLE HLU;Lo;0;L;;;;;N;;;;; -A1AE;YI SYLLABLE HLUP;Lo;0;L;;;;;N;;;;; -A1AF;YI SYLLABLE HLURX;Lo;0;L;;;;;N;;;;; -A1B0;YI SYLLABLE HLUR;Lo;0;L;;;;;N;;;;; -A1B1;YI SYLLABLE HLYT;Lo;0;L;;;;;N;;;;; -A1B2;YI SYLLABLE HLYX;Lo;0;L;;;;;N;;;;; -A1B3;YI SYLLABLE HLY;Lo;0;L;;;;;N;;;;; -A1B4;YI SYLLABLE HLYP;Lo;0;L;;;;;N;;;;; -A1B5;YI SYLLABLE HLYRX;Lo;0;L;;;;;N;;;;; -A1B6;YI SYLLABLE HLYR;Lo;0;L;;;;;N;;;;; -A1B7;YI SYLLABLE LIT;Lo;0;L;;;;;N;;;;; -A1B8;YI SYLLABLE LIX;Lo;0;L;;;;;N;;;;; -A1B9;YI SYLLABLE LI;Lo;0;L;;;;;N;;;;; -A1BA;YI SYLLABLE LIP;Lo;0;L;;;;;N;;;;; -A1BB;YI SYLLABLE LIET;Lo;0;L;;;;;N;;;;; -A1BC;YI SYLLABLE LIEX;Lo;0;L;;;;;N;;;;; -A1BD;YI SYLLABLE LIE;Lo;0;L;;;;;N;;;;; -A1BE;YI SYLLABLE LIEP;Lo;0;L;;;;;N;;;;; -A1BF;YI SYLLABLE LAT;Lo;0;L;;;;;N;;;;; -A1C0;YI SYLLABLE LAX;Lo;0;L;;;;;N;;;;; -A1C1;YI SYLLABLE LA;Lo;0;L;;;;;N;;;;; -A1C2;YI SYLLABLE LAP;Lo;0;L;;;;;N;;;;; -A1C3;YI SYLLABLE LUOT;Lo;0;L;;;;;N;;;;; -A1C4;YI SYLLABLE LUOX;Lo;0;L;;;;;N;;;;; -A1C5;YI SYLLABLE LUO;Lo;0;L;;;;;N;;;;; -A1C6;YI SYLLABLE LUOP;Lo;0;L;;;;;N;;;;; -A1C7;YI SYLLABLE LOT;Lo;0;L;;;;;N;;;;; -A1C8;YI SYLLABLE LOX;Lo;0;L;;;;;N;;;;; -A1C9;YI SYLLABLE LO;Lo;0;L;;;;;N;;;;; -A1CA;YI SYLLABLE LOP;Lo;0;L;;;;;N;;;;; -A1CB;YI SYLLABLE LEX;Lo;0;L;;;;;N;;;;; -A1CC;YI SYLLABLE LE;Lo;0;L;;;;;N;;;;; -A1CD;YI SYLLABLE LEP;Lo;0;L;;;;;N;;;;; -A1CE;YI SYLLABLE LUT;Lo;0;L;;;;;N;;;;; -A1CF;YI SYLLABLE LUX;Lo;0;L;;;;;N;;;;; -A1D0;YI SYLLABLE LU;Lo;0;L;;;;;N;;;;; -A1D1;YI SYLLABLE LUP;Lo;0;L;;;;;N;;;;; -A1D2;YI SYLLABLE LURX;Lo;0;L;;;;;N;;;;; -A1D3;YI SYLLABLE LUR;Lo;0;L;;;;;N;;;;; -A1D4;YI SYLLABLE LYT;Lo;0;L;;;;;N;;;;; -A1D5;YI SYLLABLE LYX;Lo;0;L;;;;;N;;;;; -A1D6;YI SYLLABLE LY;Lo;0;L;;;;;N;;;;; -A1D7;YI SYLLABLE LYP;Lo;0;L;;;;;N;;;;; -A1D8;YI SYLLABLE LYRX;Lo;0;L;;;;;N;;;;; -A1D9;YI SYLLABLE LYR;Lo;0;L;;;;;N;;;;; -A1DA;YI SYLLABLE GIT;Lo;0;L;;;;;N;;;;; -A1DB;YI SYLLABLE GIX;Lo;0;L;;;;;N;;;;; -A1DC;YI SYLLABLE GI;Lo;0;L;;;;;N;;;;; -A1DD;YI SYLLABLE GIP;Lo;0;L;;;;;N;;;;; -A1DE;YI SYLLABLE GIET;Lo;0;L;;;;;N;;;;; -A1DF;YI SYLLABLE GIEX;Lo;0;L;;;;;N;;;;; -A1E0;YI SYLLABLE GIE;Lo;0;L;;;;;N;;;;; -A1E1;YI SYLLABLE GIEP;Lo;0;L;;;;;N;;;;; -A1E2;YI SYLLABLE GAT;Lo;0;L;;;;;N;;;;; -A1E3;YI SYLLABLE GAX;Lo;0;L;;;;;N;;;;; -A1E4;YI SYLLABLE GA;Lo;0;L;;;;;N;;;;; -A1E5;YI SYLLABLE GAP;Lo;0;L;;;;;N;;;;; -A1E6;YI SYLLABLE GUOT;Lo;0;L;;;;;N;;;;; -A1E7;YI SYLLABLE GUOX;Lo;0;L;;;;;N;;;;; -A1E8;YI SYLLABLE GUO;Lo;0;L;;;;;N;;;;; -A1E9;YI SYLLABLE GUOP;Lo;0;L;;;;;N;;;;; -A1EA;YI SYLLABLE GOT;Lo;0;L;;;;;N;;;;; -A1EB;YI SYLLABLE GOX;Lo;0;L;;;;;N;;;;; -A1EC;YI SYLLABLE GO;Lo;0;L;;;;;N;;;;; -A1ED;YI SYLLABLE GOP;Lo;0;L;;;;;N;;;;; -A1EE;YI SYLLABLE GET;Lo;0;L;;;;;N;;;;; -A1EF;YI SYLLABLE GEX;Lo;0;L;;;;;N;;;;; -A1F0;YI SYLLABLE GE;Lo;0;L;;;;;N;;;;; -A1F1;YI SYLLABLE GEP;Lo;0;L;;;;;N;;;;; -A1F2;YI SYLLABLE GUT;Lo;0;L;;;;;N;;;;; -A1F3;YI SYLLABLE GUX;Lo;0;L;;;;;N;;;;; -A1F4;YI SYLLABLE GU;Lo;0;L;;;;;N;;;;; -A1F5;YI SYLLABLE GUP;Lo;0;L;;;;;N;;;;; -A1F6;YI SYLLABLE GURX;Lo;0;L;;;;;N;;;;; -A1F7;YI SYLLABLE GUR;Lo;0;L;;;;;N;;;;; -A1F8;YI SYLLABLE KIT;Lo;0;L;;;;;N;;;;; -A1F9;YI SYLLABLE KIX;Lo;0;L;;;;;N;;;;; -A1FA;YI SYLLABLE KI;Lo;0;L;;;;;N;;;;; -A1FB;YI SYLLABLE KIP;Lo;0;L;;;;;N;;;;; -A1FC;YI SYLLABLE KIEX;Lo;0;L;;;;;N;;;;; -A1FD;YI SYLLABLE KIE;Lo;0;L;;;;;N;;;;; -A1FE;YI SYLLABLE KIEP;Lo;0;L;;;;;N;;;;; -A1FF;YI SYLLABLE KAT;Lo;0;L;;;;;N;;;;; -A200;YI SYLLABLE KAX;Lo;0;L;;;;;N;;;;; -A201;YI SYLLABLE KA;Lo;0;L;;;;;N;;;;; -A202;YI SYLLABLE KAP;Lo;0;L;;;;;N;;;;; -A203;YI SYLLABLE KUOX;Lo;0;L;;;;;N;;;;; -A204;YI SYLLABLE KUO;Lo;0;L;;;;;N;;;;; -A205;YI SYLLABLE KUOP;Lo;0;L;;;;;N;;;;; -A206;YI SYLLABLE KOT;Lo;0;L;;;;;N;;;;; -A207;YI SYLLABLE KOX;Lo;0;L;;;;;N;;;;; -A208;YI SYLLABLE KO;Lo;0;L;;;;;N;;;;; -A209;YI SYLLABLE KOP;Lo;0;L;;;;;N;;;;; -A20A;YI SYLLABLE KET;Lo;0;L;;;;;N;;;;; -A20B;YI SYLLABLE KEX;Lo;0;L;;;;;N;;;;; -A20C;YI SYLLABLE KE;Lo;0;L;;;;;N;;;;; -A20D;YI SYLLABLE KEP;Lo;0;L;;;;;N;;;;; -A20E;YI SYLLABLE KUT;Lo;0;L;;;;;N;;;;; -A20F;YI SYLLABLE KUX;Lo;0;L;;;;;N;;;;; -A210;YI SYLLABLE KU;Lo;0;L;;;;;N;;;;; -A211;YI SYLLABLE KUP;Lo;0;L;;;;;N;;;;; -A212;YI SYLLABLE KURX;Lo;0;L;;;;;N;;;;; -A213;YI SYLLABLE KUR;Lo;0;L;;;;;N;;;;; -A214;YI SYLLABLE GGIT;Lo;0;L;;;;;N;;;;; -A215;YI SYLLABLE GGIX;Lo;0;L;;;;;N;;;;; -A216;YI SYLLABLE GGI;Lo;0;L;;;;;N;;;;; -A217;YI SYLLABLE GGIEX;Lo;0;L;;;;;N;;;;; -A218;YI SYLLABLE GGIE;Lo;0;L;;;;;N;;;;; -A219;YI SYLLABLE GGIEP;Lo;0;L;;;;;N;;;;; -A21A;YI SYLLABLE GGAT;Lo;0;L;;;;;N;;;;; -A21B;YI SYLLABLE GGAX;Lo;0;L;;;;;N;;;;; -A21C;YI SYLLABLE GGA;Lo;0;L;;;;;N;;;;; -A21D;YI SYLLABLE GGAP;Lo;0;L;;;;;N;;;;; -A21E;YI SYLLABLE GGUOT;Lo;0;L;;;;;N;;;;; -A21F;YI SYLLABLE GGUOX;Lo;0;L;;;;;N;;;;; -A220;YI SYLLABLE GGUO;Lo;0;L;;;;;N;;;;; -A221;YI SYLLABLE GGUOP;Lo;0;L;;;;;N;;;;; -A222;YI SYLLABLE GGOT;Lo;0;L;;;;;N;;;;; -A223;YI SYLLABLE GGOX;Lo;0;L;;;;;N;;;;; -A224;YI SYLLABLE GGO;Lo;0;L;;;;;N;;;;; -A225;YI SYLLABLE GGOP;Lo;0;L;;;;;N;;;;; -A226;YI SYLLABLE GGET;Lo;0;L;;;;;N;;;;; -A227;YI SYLLABLE GGEX;Lo;0;L;;;;;N;;;;; -A228;YI SYLLABLE GGE;Lo;0;L;;;;;N;;;;; -A229;YI SYLLABLE GGEP;Lo;0;L;;;;;N;;;;; -A22A;YI SYLLABLE GGUT;Lo;0;L;;;;;N;;;;; -A22B;YI SYLLABLE GGUX;Lo;0;L;;;;;N;;;;; -A22C;YI SYLLABLE GGU;Lo;0;L;;;;;N;;;;; -A22D;YI SYLLABLE GGUP;Lo;0;L;;;;;N;;;;; -A22E;YI SYLLABLE GGURX;Lo;0;L;;;;;N;;;;; -A22F;YI SYLLABLE GGUR;Lo;0;L;;;;;N;;;;; -A230;YI SYLLABLE MGIEX;Lo;0;L;;;;;N;;;;; -A231;YI SYLLABLE MGIE;Lo;0;L;;;;;N;;;;; -A232;YI SYLLABLE MGAT;Lo;0;L;;;;;N;;;;; -A233;YI SYLLABLE MGAX;Lo;0;L;;;;;N;;;;; -A234;YI SYLLABLE MGA;Lo;0;L;;;;;N;;;;; -A235;YI SYLLABLE MGAP;Lo;0;L;;;;;N;;;;; -A236;YI SYLLABLE MGUOX;Lo;0;L;;;;;N;;;;; -A237;YI SYLLABLE MGUO;Lo;0;L;;;;;N;;;;; -A238;YI SYLLABLE MGUOP;Lo;0;L;;;;;N;;;;; -A239;YI SYLLABLE MGOT;Lo;0;L;;;;;N;;;;; -A23A;YI SYLLABLE MGOX;Lo;0;L;;;;;N;;;;; -A23B;YI SYLLABLE MGO;Lo;0;L;;;;;N;;;;; -A23C;YI SYLLABLE MGOP;Lo;0;L;;;;;N;;;;; -A23D;YI SYLLABLE MGEX;Lo;0;L;;;;;N;;;;; -A23E;YI SYLLABLE MGE;Lo;0;L;;;;;N;;;;; -A23F;YI SYLLABLE MGEP;Lo;0;L;;;;;N;;;;; -A240;YI SYLLABLE MGUT;Lo;0;L;;;;;N;;;;; -A241;YI SYLLABLE MGUX;Lo;0;L;;;;;N;;;;; -A242;YI SYLLABLE MGU;Lo;0;L;;;;;N;;;;; -A243;YI SYLLABLE MGUP;Lo;0;L;;;;;N;;;;; -A244;YI SYLLABLE MGURX;Lo;0;L;;;;;N;;;;; -A245;YI SYLLABLE MGUR;Lo;0;L;;;;;N;;;;; -A246;YI SYLLABLE HXIT;Lo;0;L;;;;;N;;;;; -A247;YI SYLLABLE HXIX;Lo;0;L;;;;;N;;;;; -A248;YI SYLLABLE HXI;Lo;0;L;;;;;N;;;;; -A249;YI SYLLABLE HXIP;Lo;0;L;;;;;N;;;;; -A24A;YI SYLLABLE HXIET;Lo;0;L;;;;;N;;;;; -A24B;YI SYLLABLE HXIEX;Lo;0;L;;;;;N;;;;; -A24C;YI SYLLABLE HXIE;Lo;0;L;;;;;N;;;;; -A24D;YI SYLLABLE HXIEP;Lo;0;L;;;;;N;;;;; -A24E;YI SYLLABLE HXAT;Lo;0;L;;;;;N;;;;; -A24F;YI SYLLABLE HXAX;Lo;0;L;;;;;N;;;;; -A250;YI SYLLABLE HXA;Lo;0;L;;;;;N;;;;; -A251;YI SYLLABLE HXAP;Lo;0;L;;;;;N;;;;; -A252;YI SYLLABLE HXUOT;Lo;0;L;;;;;N;;;;; -A253;YI SYLLABLE HXUOX;Lo;0;L;;;;;N;;;;; -A254;YI SYLLABLE HXUO;Lo;0;L;;;;;N;;;;; -A255;YI SYLLABLE HXUOP;Lo;0;L;;;;;N;;;;; -A256;YI SYLLABLE HXOT;Lo;0;L;;;;;N;;;;; -A257;YI SYLLABLE HXOX;Lo;0;L;;;;;N;;;;; -A258;YI SYLLABLE HXO;Lo;0;L;;;;;N;;;;; -A259;YI SYLLABLE HXOP;Lo;0;L;;;;;N;;;;; -A25A;YI SYLLABLE HXEX;Lo;0;L;;;;;N;;;;; -A25B;YI SYLLABLE HXE;Lo;0;L;;;;;N;;;;; -A25C;YI SYLLABLE HXEP;Lo;0;L;;;;;N;;;;; -A25D;YI SYLLABLE NGIEX;Lo;0;L;;;;;N;;;;; -A25E;YI SYLLABLE NGIE;Lo;0;L;;;;;N;;;;; -A25F;YI SYLLABLE NGIEP;Lo;0;L;;;;;N;;;;; -A260;YI SYLLABLE NGAT;Lo;0;L;;;;;N;;;;; -A261;YI SYLLABLE NGAX;Lo;0;L;;;;;N;;;;; -A262;YI SYLLABLE NGA;Lo;0;L;;;;;N;;;;; -A263;YI SYLLABLE NGAP;Lo;0;L;;;;;N;;;;; -A264;YI SYLLABLE NGUOT;Lo;0;L;;;;;N;;;;; -A265;YI SYLLABLE NGUOX;Lo;0;L;;;;;N;;;;; -A266;YI SYLLABLE NGUO;Lo;0;L;;;;;N;;;;; -A267;YI SYLLABLE NGOT;Lo;0;L;;;;;N;;;;; -A268;YI SYLLABLE NGOX;Lo;0;L;;;;;N;;;;; -A269;YI SYLLABLE NGO;Lo;0;L;;;;;N;;;;; -A26A;YI SYLLABLE NGOP;Lo;0;L;;;;;N;;;;; -A26B;YI SYLLABLE NGEX;Lo;0;L;;;;;N;;;;; -A26C;YI SYLLABLE NGE;Lo;0;L;;;;;N;;;;; -A26D;YI SYLLABLE NGEP;Lo;0;L;;;;;N;;;;; -A26E;YI SYLLABLE HIT;Lo;0;L;;;;;N;;;;; -A26F;YI SYLLABLE HIEX;Lo;0;L;;;;;N;;;;; -A270;YI SYLLABLE HIE;Lo;0;L;;;;;N;;;;; -A271;YI SYLLABLE HAT;Lo;0;L;;;;;N;;;;; -A272;YI SYLLABLE HAX;Lo;0;L;;;;;N;;;;; -A273;YI SYLLABLE HA;Lo;0;L;;;;;N;;;;; -A274;YI SYLLABLE HAP;Lo;0;L;;;;;N;;;;; -A275;YI SYLLABLE HUOT;Lo;0;L;;;;;N;;;;; -A276;YI SYLLABLE HUOX;Lo;0;L;;;;;N;;;;; -A277;YI SYLLABLE HUO;Lo;0;L;;;;;N;;;;; -A278;YI SYLLABLE HUOP;Lo;0;L;;;;;N;;;;; -A279;YI SYLLABLE HOT;Lo;0;L;;;;;N;;;;; -A27A;YI SYLLABLE HOX;Lo;0;L;;;;;N;;;;; -A27B;YI SYLLABLE HO;Lo;0;L;;;;;N;;;;; -A27C;YI SYLLABLE HOP;Lo;0;L;;;;;N;;;;; -A27D;YI SYLLABLE HEX;Lo;0;L;;;;;N;;;;; -A27E;YI SYLLABLE HE;Lo;0;L;;;;;N;;;;; -A27F;YI SYLLABLE HEP;Lo;0;L;;;;;N;;;;; -A280;YI SYLLABLE WAT;Lo;0;L;;;;;N;;;;; -A281;YI SYLLABLE WAX;Lo;0;L;;;;;N;;;;; -A282;YI SYLLABLE WA;Lo;0;L;;;;;N;;;;; -A283;YI SYLLABLE WAP;Lo;0;L;;;;;N;;;;; -A284;YI SYLLABLE WUOX;Lo;0;L;;;;;N;;;;; -A285;YI SYLLABLE WUO;Lo;0;L;;;;;N;;;;; -A286;YI SYLLABLE WUOP;Lo;0;L;;;;;N;;;;; -A287;YI SYLLABLE WOX;Lo;0;L;;;;;N;;;;; -A288;YI SYLLABLE WO;Lo;0;L;;;;;N;;;;; -A289;YI SYLLABLE WOP;Lo;0;L;;;;;N;;;;; -A28A;YI SYLLABLE WEX;Lo;0;L;;;;;N;;;;; -A28B;YI SYLLABLE WE;Lo;0;L;;;;;N;;;;; -A28C;YI SYLLABLE WEP;Lo;0;L;;;;;N;;;;; -A28D;YI SYLLABLE ZIT;Lo;0;L;;;;;N;;;;; -A28E;YI SYLLABLE ZIX;Lo;0;L;;;;;N;;;;; -A28F;YI SYLLABLE ZI;Lo;0;L;;;;;N;;;;; -A290;YI SYLLABLE ZIP;Lo;0;L;;;;;N;;;;; -A291;YI SYLLABLE ZIEX;Lo;0;L;;;;;N;;;;; -A292;YI SYLLABLE ZIE;Lo;0;L;;;;;N;;;;; -A293;YI SYLLABLE ZIEP;Lo;0;L;;;;;N;;;;; -A294;YI SYLLABLE ZAT;Lo;0;L;;;;;N;;;;; -A295;YI SYLLABLE ZAX;Lo;0;L;;;;;N;;;;; -A296;YI SYLLABLE ZA;Lo;0;L;;;;;N;;;;; -A297;YI SYLLABLE ZAP;Lo;0;L;;;;;N;;;;; -A298;YI SYLLABLE ZUOX;Lo;0;L;;;;;N;;;;; -A299;YI SYLLABLE ZUO;Lo;0;L;;;;;N;;;;; -A29A;YI SYLLABLE ZUOP;Lo;0;L;;;;;N;;;;; -A29B;YI SYLLABLE ZOT;Lo;0;L;;;;;N;;;;; -A29C;YI SYLLABLE ZOX;Lo;0;L;;;;;N;;;;; -A29D;YI SYLLABLE ZO;Lo;0;L;;;;;N;;;;; -A29E;YI SYLLABLE ZOP;Lo;0;L;;;;;N;;;;; -A29F;YI SYLLABLE ZEX;Lo;0;L;;;;;N;;;;; -A2A0;YI SYLLABLE ZE;Lo;0;L;;;;;N;;;;; -A2A1;YI SYLLABLE ZEP;Lo;0;L;;;;;N;;;;; -A2A2;YI SYLLABLE ZUT;Lo;0;L;;;;;N;;;;; -A2A3;YI SYLLABLE ZUX;Lo;0;L;;;;;N;;;;; -A2A4;YI SYLLABLE ZU;Lo;0;L;;;;;N;;;;; -A2A5;YI SYLLABLE ZUP;Lo;0;L;;;;;N;;;;; -A2A6;YI SYLLABLE ZURX;Lo;0;L;;;;;N;;;;; -A2A7;YI SYLLABLE ZUR;Lo;0;L;;;;;N;;;;; -A2A8;YI SYLLABLE ZYT;Lo;0;L;;;;;N;;;;; -A2A9;YI SYLLABLE ZYX;Lo;0;L;;;;;N;;;;; -A2AA;YI SYLLABLE ZY;Lo;0;L;;;;;N;;;;; -A2AB;YI SYLLABLE ZYP;Lo;0;L;;;;;N;;;;; -A2AC;YI SYLLABLE ZYRX;Lo;0;L;;;;;N;;;;; -A2AD;YI SYLLABLE ZYR;Lo;0;L;;;;;N;;;;; -A2AE;YI SYLLABLE CIT;Lo;0;L;;;;;N;;;;; -A2AF;YI SYLLABLE CIX;Lo;0;L;;;;;N;;;;; -A2B0;YI SYLLABLE CI;Lo;0;L;;;;;N;;;;; -A2B1;YI SYLLABLE CIP;Lo;0;L;;;;;N;;;;; -A2B2;YI SYLLABLE CIET;Lo;0;L;;;;;N;;;;; -A2B3;YI SYLLABLE CIEX;Lo;0;L;;;;;N;;;;; -A2B4;YI SYLLABLE CIE;Lo;0;L;;;;;N;;;;; -A2B5;YI SYLLABLE CIEP;Lo;0;L;;;;;N;;;;; -A2B6;YI SYLLABLE CAT;Lo;0;L;;;;;N;;;;; -A2B7;YI SYLLABLE CAX;Lo;0;L;;;;;N;;;;; -A2B8;YI SYLLABLE CA;Lo;0;L;;;;;N;;;;; -A2B9;YI SYLLABLE CAP;Lo;0;L;;;;;N;;;;; -A2BA;YI SYLLABLE CUOX;Lo;0;L;;;;;N;;;;; -A2BB;YI SYLLABLE CUO;Lo;0;L;;;;;N;;;;; -A2BC;YI SYLLABLE CUOP;Lo;0;L;;;;;N;;;;; -A2BD;YI SYLLABLE COT;Lo;0;L;;;;;N;;;;; -A2BE;YI SYLLABLE COX;Lo;0;L;;;;;N;;;;; -A2BF;YI SYLLABLE CO;Lo;0;L;;;;;N;;;;; -A2C0;YI SYLLABLE COP;Lo;0;L;;;;;N;;;;; -A2C1;YI SYLLABLE CEX;Lo;0;L;;;;;N;;;;; -A2C2;YI SYLLABLE CE;Lo;0;L;;;;;N;;;;; -A2C3;YI SYLLABLE CEP;Lo;0;L;;;;;N;;;;; -A2C4;YI SYLLABLE CUT;Lo;0;L;;;;;N;;;;; -A2C5;YI SYLLABLE CUX;Lo;0;L;;;;;N;;;;; -A2C6;YI SYLLABLE CU;Lo;0;L;;;;;N;;;;; -A2C7;YI SYLLABLE CUP;Lo;0;L;;;;;N;;;;; -A2C8;YI SYLLABLE CURX;Lo;0;L;;;;;N;;;;; -A2C9;YI SYLLABLE CUR;Lo;0;L;;;;;N;;;;; -A2CA;YI SYLLABLE CYT;Lo;0;L;;;;;N;;;;; -A2CB;YI SYLLABLE CYX;Lo;0;L;;;;;N;;;;; -A2CC;YI SYLLABLE CY;Lo;0;L;;;;;N;;;;; -A2CD;YI SYLLABLE CYP;Lo;0;L;;;;;N;;;;; -A2CE;YI SYLLABLE CYRX;Lo;0;L;;;;;N;;;;; -A2CF;YI SYLLABLE CYR;Lo;0;L;;;;;N;;;;; -A2D0;YI SYLLABLE ZZIT;Lo;0;L;;;;;N;;;;; -A2D1;YI SYLLABLE ZZIX;Lo;0;L;;;;;N;;;;; -A2D2;YI SYLLABLE ZZI;Lo;0;L;;;;;N;;;;; -A2D3;YI SYLLABLE ZZIP;Lo;0;L;;;;;N;;;;; -A2D4;YI SYLLABLE ZZIET;Lo;0;L;;;;;N;;;;; -A2D5;YI SYLLABLE ZZIEX;Lo;0;L;;;;;N;;;;; -A2D6;YI SYLLABLE ZZIE;Lo;0;L;;;;;N;;;;; -A2D7;YI SYLLABLE ZZIEP;Lo;0;L;;;;;N;;;;; -A2D8;YI SYLLABLE ZZAT;Lo;0;L;;;;;N;;;;; -A2D9;YI SYLLABLE ZZAX;Lo;0;L;;;;;N;;;;; -A2DA;YI SYLLABLE ZZA;Lo;0;L;;;;;N;;;;; -A2DB;YI SYLLABLE ZZAP;Lo;0;L;;;;;N;;;;; -A2DC;YI SYLLABLE ZZOX;Lo;0;L;;;;;N;;;;; -A2DD;YI SYLLABLE ZZO;Lo;0;L;;;;;N;;;;; -A2DE;YI SYLLABLE ZZOP;Lo;0;L;;;;;N;;;;; -A2DF;YI SYLLABLE ZZEX;Lo;0;L;;;;;N;;;;; -A2E0;YI SYLLABLE ZZE;Lo;0;L;;;;;N;;;;; -A2E1;YI SYLLABLE ZZEP;Lo;0;L;;;;;N;;;;; -A2E2;YI SYLLABLE ZZUX;Lo;0;L;;;;;N;;;;; -A2E3;YI SYLLABLE ZZU;Lo;0;L;;;;;N;;;;; -A2E4;YI SYLLABLE ZZUP;Lo;0;L;;;;;N;;;;; -A2E5;YI SYLLABLE ZZURX;Lo;0;L;;;;;N;;;;; -A2E6;YI SYLLABLE ZZUR;Lo;0;L;;;;;N;;;;; -A2E7;YI SYLLABLE ZZYT;Lo;0;L;;;;;N;;;;; -A2E8;YI SYLLABLE ZZYX;Lo;0;L;;;;;N;;;;; -A2E9;YI SYLLABLE ZZY;Lo;0;L;;;;;N;;;;; -A2EA;YI SYLLABLE ZZYP;Lo;0;L;;;;;N;;;;; -A2EB;YI SYLLABLE ZZYRX;Lo;0;L;;;;;N;;;;; -A2EC;YI SYLLABLE ZZYR;Lo;0;L;;;;;N;;;;; -A2ED;YI SYLLABLE NZIT;Lo;0;L;;;;;N;;;;; -A2EE;YI SYLLABLE NZIX;Lo;0;L;;;;;N;;;;; -A2EF;YI SYLLABLE NZI;Lo;0;L;;;;;N;;;;; -A2F0;YI SYLLABLE NZIP;Lo;0;L;;;;;N;;;;; -A2F1;YI SYLLABLE NZIEX;Lo;0;L;;;;;N;;;;; -A2F2;YI SYLLABLE NZIE;Lo;0;L;;;;;N;;;;; -A2F3;YI SYLLABLE NZIEP;Lo;0;L;;;;;N;;;;; -A2F4;YI SYLLABLE NZAT;Lo;0;L;;;;;N;;;;; -A2F5;YI SYLLABLE NZAX;Lo;0;L;;;;;N;;;;; -A2F6;YI SYLLABLE NZA;Lo;0;L;;;;;N;;;;; -A2F7;YI SYLLABLE NZAP;Lo;0;L;;;;;N;;;;; -A2F8;YI SYLLABLE NZUOX;Lo;0;L;;;;;N;;;;; -A2F9;YI SYLLABLE NZUO;Lo;0;L;;;;;N;;;;; -A2FA;YI SYLLABLE NZOX;Lo;0;L;;;;;N;;;;; -A2FB;YI SYLLABLE NZOP;Lo;0;L;;;;;N;;;;; -A2FC;YI SYLLABLE NZEX;Lo;0;L;;;;;N;;;;; -A2FD;YI SYLLABLE NZE;Lo;0;L;;;;;N;;;;; -A2FE;YI SYLLABLE NZUX;Lo;0;L;;;;;N;;;;; -A2FF;YI SYLLABLE NZU;Lo;0;L;;;;;N;;;;; -A300;YI SYLLABLE NZUP;Lo;0;L;;;;;N;;;;; -A301;YI SYLLABLE NZURX;Lo;0;L;;;;;N;;;;; -A302;YI SYLLABLE NZUR;Lo;0;L;;;;;N;;;;; -A303;YI SYLLABLE NZYT;Lo;0;L;;;;;N;;;;; -A304;YI SYLLABLE NZYX;Lo;0;L;;;;;N;;;;; -A305;YI SYLLABLE NZY;Lo;0;L;;;;;N;;;;; -A306;YI SYLLABLE NZYP;Lo;0;L;;;;;N;;;;; -A307;YI SYLLABLE NZYRX;Lo;0;L;;;;;N;;;;; -A308;YI SYLLABLE NZYR;Lo;0;L;;;;;N;;;;; -A309;YI SYLLABLE SIT;Lo;0;L;;;;;N;;;;; -A30A;YI SYLLABLE SIX;Lo;0;L;;;;;N;;;;; -A30B;YI SYLLABLE SI;Lo;0;L;;;;;N;;;;; -A30C;YI SYLLABLE SIP;Lo;0;L;;;;;N;;;;; -A30D;YI SYLLABLE SIEX;Lo;0;L;;;;;N;;;;; -A30E;YI SYLLABLE SIE;Lo;0;L;;;;;N;;;;; -A30F;YI SYLLABLE SIEP;Lo;0;L;;;;;N;;;;; -A310;YI SYLLABLE SAT;Lo;0;L;;;;;N;;;;; -A311;YI SYLLABLE SAX;Lo;0;L;;;;;N;;;;; -A312;YI SYLLABLE SA;Lo;0;L;;;;;N;;;;; -A313;YI SYLLABLE SAP;Lo;0;L;;;;;N;;;;; -A314;YI SYLLABLE SUOX;Lo;0;L;;;;;N;;;;; -A315;YI SYLLABLE SUO;Lo;0;L;;;;;N;;;;; -A316;YI SYLLABLE SUOP;Lo;0;L;;;;;N;;;;; -A317;YI SYLLABLE SOT;Lo;0;L;;;;;N;;;;; -A318;YI SYLLABLE SOX;Lo;0;L;;;;;N;;;;; -A319;YI SYLLABLE SO;Lo;0;L;;;;;N;;;;; -A31A;YI SYLLABLE SOP;Lo;0;L;;;;;N;;;;; -A31B;YI SYLLABLE SEX;Lo;0;L;;;;;N;;;;; -A31C;YI SYLLABLE SE;Lo;0;L;;;;;N;;;;; -A31D;YI SYLLABLE SEP;Lo;0;L;;;;;N;;;;; -A31E;YI SYLLABLE SUT;Lo;0;L;;;;;N;;;;; -A31F;YI SYLLABLE SUX;Lo;0;L;;;;;N;;;;; -A320;YI SYLLABLE SU;Lo;0;L;;;;;N;;;;; -A321;YI SYLLABLE SUP;Lo;0;L;;;;;N;;;;; -A322;YI SYLLABLE SURX;Lo;0;L;;;;;N;;;;; -A323;YI SYLLABLE SUR;Lo;0;L;;;;;N;;;;; -A324;YI SYLLABLE SYT;Lo;0;L;;;;;N;;;;; -A325;YI SYLLABLE SYX;Lo;0;L;;;;;N;;;;; -A326;YI SYLLABLE SY;Lo;0;L;;;;;N;;;;; -A327;YI SYLLABLE SYP;Lo;0;L;;;;;N;;;;; -A328;YI SYLLABLE SYRX;Lo;0;L;;;;;N;;;;; -A329;YI SYLLABLE SYR;Lo;0;L;;;;;N;;;;; -A32A;YI SYLLABLE SSIT;Lo;0;L;;;;;N;;;;; -A32B;YI SYLLABLE SSIX;Lo;0;L;;;;;N;;;;; -A32C;YI SYLLABLE SSI;Lo;0;L;;;;;N;;;;; -A32D;YI SYLLABLE SSIP;Lo;0;L;;;;;N;;;;; -A32E;YI SYLLABLE SSIEX;Lo;0;L;;;;;N;;;;; -A32F;YI SYLLABLE SSIE;Lo;0;L;;;;;N;;;;; -A330;YI SYLLABLE SSIEP;Lo;0;L;;;;;N;;;;; -A331;YI SYLLABLE SSAT;Lo;0;L;;;;;N;;;;; -A332;YI SYLLABLE SSAX;Lo;0;L;;;;;N;;;;; -A333;YI SYLLABLE SSA;Lo;0;L;;;;;N;;;;; -A334;YI SYLLABLE SSAP;Lo;0;L;;;;;N;;;;; -A335;YI SYLLABLE SSOT;Lo;0;L;;;;;N;;;;; -A336;YI SYLLABLE SSOX;Lo;0;L;;;;;N;;;;; -A337;YI SYLLABLE SSO;Lo;0;L;;;;;N;;;;; -A338;YI SYLLABLE SSOP;Lo;0;L;;;;;N;;;;; -A339;YI SYLLABLE SSEX;Lo;0;L;;;;;N;;;;; -A33A;YI SYLLABLE SSE;Lo;0;L;;;;;N;;;;; -A33B;YI SYLLABLE SSEP;Lo;0;L;;;;;N;;;;; -A33C;YI SYLLABLE SSUT;Lo;0;L;;;;;N;;;;; -A33D;YI SYLLABLE SSUX;Lo;0;L;;;;;N;;;;; -A33E;YI SYLLABLE SSU;Lo;0;L;;;;;N;;;;; -A33F;YI SYLLABLE SSUP;Lo;0;L;;;;;N;;;;; -A340;YI SYLLABLE SSYT;Lo;0;L;;;;;N;;;;; -A341;YI SYLLABLE SSYX;Lo;0;L;;;;;N;;;;; -A342;YI SYLLABLE SSY;Lo;0;L;;;;;N;;;;; -A343;YI SYLLABLE SSYP;Lo;0;L;;;;;N;;;;; -A344;YI SYLLABLE SSYRX;Lo;0;L;;;;;N;;;;; -A345;YI SYLLABLE SSYR;Lo;0;L;;;;;N;;;;; -A346;YI SYLLABLE ZHAT;Lo;0;L;;;;;N;;;;; -A347;YI SYLLABLE ZHAX;Lo;0;L;;;;;N;;;;; -A348;YI SYLLABLE ZHA;Lo;0;L;;;;;N;;;;; -A349;YI SYLLABLE ZHAP;Lo;0;L;;;;;N;;;;; -A34A;YI SYLLABLE ZHUOX;Lo;0;L;;;;;N;;;;; -A34B;YI SYLLABLE ZHUO;Lo;0;L;;;;;N;;;;; -A34C;YI SYLLABLE ZHUOP;Lo;0;L;;;;;N;;;;; -A34D;YI SYLLABLE ZHOT;Lo;0;L;;;;;N;;;;; -A34E;YI SYLLABLE ZHOX;Lo;0;L;;;;;N;;;;; -A34F;YI SYLLABLE ZHO;Lo;0;L;;;;;N;;;;; -A350;YI SYLLABLE ZHOP;Lo;0;L;;;;;N;;;;; -A351;YI SYLLABLE ZHET;Lo;0;L;;;;;N;;;;; -A352;YI SYLLABLE ZHEX;Lo;0;L;;;;;N;;;;; -A353;YI SYLLABLE ZHE;Lo;0;L;;;;;N;;;;; -A354;YI SYLLABLE ZHEP;Lo;0;L;;;;;N;;;;; -A355;YI SYLLABLE ZHUT;Lo;0;L;;;;;N;;;;; -A356;YI SYLLABLE ZHUX;Lo;0;L;;;;;N;;;;; -A357;YI SYLLABLE ZHU;Lo;0;L;;;;;N;;;;; -A358;YI SYLLABLE ZHUP;Lo;0;L;;;;;N;;;;; -A359;YI SYLLABLE ZHURX;Lo;0;L;;;;;N;;;;; -A35A;YI SYLLABLE ZHUR;Lo;0;L;;;;;N;;;;; -A35B;YI SYLLABLE ZHYT;Lo;0;L;;;;;N;;;;; -A35C;YI SYLLABLE ZHYX;Lo;0;L;;;;;N;;;;; -A35D;YI SYLLABLE ZHY;Lo;0;L;;;;;N;;;;; -A35E;YI SYLLABLE ZHYP;Lo;0;L;;;;;N;;;;; -A35F;YI SYLLABLE ZHYRX;Lo;0;L;;;;;N;;;;; -A360;YI SYLLABLE ZHYR;Lo;0;L;;;;;N;;;;; -A361;YI SYLLABLE CHAT;Lo;0;L;;;;;N;;;;; -A362;YI SYLLABLE CHAX;Lo;0;L;;;;;N;;;;; -A363;YI SYLLABLE CHA;Lo;0;L;;;;;N;;;;; -A364;YI SYLLABLE CHAP;Lo;0;L;;;;;N;;;;; -A365;YI SYLLABLE CHUOT;Lo;0;L;;;;;N;;;;; -A366;YI SYLLABLE CHUOX;Lo;0;L;;;;;N;;;;; -A367;YI SYLLABLE CHUO;Lo;0;L;;;;;N;;;;; -A368;YI SYLLABLE CHUOP;Lo;0;L;;;;;N;;;;; -A369;YI SYLLABLE CHOT;Lo;0;L;;;;;N;;;;; -A36A;YI SYLLABLE CHOX;Lo;0;L;;;;;N;;;;; -A36B;YI SYLLABLE CHO;Lo;0;L;;;;;N;;;;; -A36C;YI SYLLABLE CHOP;Lo;0;L;;;;;N;;;;; -A36D;YI SYLLABLE CHET;Lo;0;L;;;;;N;;;;; -A36E;YI SYLLABLE CHEX;Lo;0;L;;;;;N;;;;; -A36F;YI SYLLABLE CHE;Lo;0;L;;;;;N;;;;; -A370;YI SYLLABLE CHEP;Lo;0;L;;;;;N;;;;; -A371;YI SYLLABLE CHUX;Lo;0;L;;;;;N;;;;; -A372;YI SYLLABLE CHU;Lo;0;L;;;;;N;;;;; -A373;YI SYLLABLE CHUP;Lo;0;L;;;;;N;;;;; -A374;YI SYLLABLE CHURX;Lo;0;L;;;;;N;;;;; -A375;YI SYLLABLE CHUR;Lo;0;L;;;;;N;;;;; -A376;YI SYLLABLE CHYT;Lo;0;L;;;;;N;;;;; -A377;YI SYLLABLE CHYX;Lo;0;L;;;;;N;;;;; -A378;YI SYLLABLE CHY;Lo;0;L;;;;;N;;;;; -A379;YI SYLLABLE CHYP;Lo;0;L;;;;;N;;;;; -A37A;YI SYLLABLE CHYRX;Lo;0;L;;;;;N;;;;; -A37B;YI SYLLABLE CHYR;Lo;0;L;;;;;N;;;;; -A37C;YI SYLLABLE RRAX;Lo;0;L;;;;;N;;;;; -A37D;YI SYLLABLE RRA;Lo;0;L;;;;;N;;;;; -A37E;YI SYLLABLE RRUOX;Lo;0;L;;;;;N;;;;; -A37F;YI SYLLABLE RRUO;Lo;0;L;;;;;N;;;;; -A380;YI SYLLABLE RROT;Lo;0;L;;;;;N;;;;; -A381;YI SYLLABLE RROX;Lo;0;L;;;;;N;;;;; -A382;YI SYLLABLE RRO;Lo;0;L;;;;;N;;;;; -A383;YI SYLLABLE RROP;Lo;0;L;;;;;N;;;;; -A384;YI SYLLABLE RRET;Lo;0;L;;;;;N;;;;; -A385;YI SYLLABLE RREX;Lo;0;L;;;;;N;;;;; -A386;YI SYLLABLE RRE;Lo;0;L;;;;;N;;;;; -A387;YI SYLLABLE RREP;Lo;0;L;;;;;N;;;;; -A388;YI SYLLABLE RRUT;Lo;0;L;;;;;N;;;;; -A389;YI SYLLABLE RRUX;Lo;0;L;;;;;N;;;;; -A38A;YI SYLLABLE RRU;Lo;0;L;;;;;N;;;;; -A38B;YI SYLLABLE RRUP;Lo;0;L;;;;;N;;;;; -A38C;YI SYLLABLE RRURX;Lo;0;L;;;;;N;;;;; -A38D;YI SYLLABLE RRUR;Lo;0;L;;;;;N;;;;; -A38E;YI SYLLABLE RRYT;Lo;0;L;;;;;N;;;;; -A38F;YI SYLLABLE RRYX;Lo;0;L;;;;;N;;;;; -A390;YI SYLLABLE RRY;Lo;0;L;;;;;N;;;;; -A391;YI SYLLABLE RRYP;Lo;0;L;;;;;N;;;;; -A392;YI SYLLABLE RRYRX;Lo;0;L;;;;;N;;;;; -A393;YI SYLLABLE RRYR;Lo;0;L;;;;;N;;;;; -A394;YI SYLLABLE NRAT;Lo;0;L;;;;;N;;;;; -A395;YI SYLLABLE NRAX;Lo;0;L;;;;;N;;;;; -A396;YI SYLLABLE NRA;Lo;0;L;;;;;N;;;;; -A397;YI SYLLABLE NRAP;Lo;0;L;;;;;N;;;;; -A398;YI SYLLABLE NROX;Lo;0;L;;;;;N;;;;; -A399;YI SYLLABLE NRO;Lo;0;L;;;;;N;;;;; -A39A;YI SYLLABLE NROP;Lo;0;L;;;;;N;;;;; -A39B;YI SYLLABLE NRET;Lo;0;L;;;;;N;;;;; -A39C;YI SYLLABLE NREX;Lo;0;L;;;;;N;;;;; -A39D;YI SYLLABLE NRE;Lo;0;L;;;;;N;;;;; -A39E;YI SYLLABLE NREP;Lo;0;L;;;;;N;;;;; -A39F;YI SYLLABLE NRUT;Lo;0;L;;;;;N;;;;; -A3A0;YI SYLLABLE NRUX;Lo;0;L;;;;;N;;;;; -A3A1;YI SYLLABLE NRU;Lo;0;L;;;;;N;;;;; -A3A2;YI SYLLABLE NRUP;Lo;0;L;;;;;N;;;;; -A3A3;YI SYLLABLE NRURX;Lo;0;L;;;;;N;;;;; -A3A4;YI SYLLABLE NRUR;Lo;0;L;;;;;N;;;;; -A3A5;YI SYLLABLE NRYT;Lo;0;L;;;;;N;;;;; -A3A6;YI SYLLABLE NRYX;Lo;0;L;;;;;N;;;;; -A3A7;YI SYLLABLE NRY;Lo;0;L;;;;;N;;;;; -A3A8;YI SYLLABLE NRYP;Lo;0;L;;;;;N;;;;; -A3A9;YI SYLLABLE NRYRX;Lo;0;L;;;;;N;;;;; -A3AA;YI SYLLABLE NRYR;Lo;0;L;;;;;N;;;;; -A3AB;YI SYLLABLE SHAT;Lo;0;L;;;;;N;;;;; -A3AC;YI SYLLABLE SHAX;Lo;0;L;;;;;N;;;;; -A3AD;YI SYLLABLE SHA;Lo;0;L;;;;;N;;;;; -A3AE;YI SYLLABLE SHAP;Lo;0;L;;;;;N;;;;; -A3AF;YI SYLLABLE SHUOX;Lo;0;L;;;;;N;;;;; -A3B0;YI SYLLABLE SHUO;Lo;0;L;;;;;N;;;;; -A3B1;YI SYLLABLE SHUOP;Lo;0;L;;;;;N;;;;; -A3B2;YI SYLLABLE SHOT;Lo;0;L;;;;;N;;;;; -A3B3;YI SYLLABLE SHOX;Lo;0;L;;;;;N;;;;; -A3B4;YI SYLLABLE SHO;Lo;0;L;;;;;N;;;;; -A3B5;YI SYLLABLE SHOP;Lo;0;L;;;;;N;;;;; -A3B6;YI SYLLABLE SHET;Lo;0;L;;;;;N;;;;; -A3B7;YI SYLLABLE SHEX;Lo;0;L;;;;;N;;;;; -A3B8;YI SYLLABLE SHE;Lo;0;L;;;;;N;;;;; -A3B9;YI SYLLABLE SHEP;Lo;0;L;;;;;N;;;;; -A3BA;YI SYLLABLE SHUT;Lo;0;L;;;;;N;;;;; -A3BB;YI SYLLABLE SHUX;Lo;0;L;;;;;N;;;;; -A3BC;YI SYLLABLE SHU;Lo;0;L;;;;;N;;;;; -A3BD;YI SYLLABLE SHUP;Lo;0;L;;;;;N;;;;; -A3BE;YI SYLLABLE SHURX;Lo;0;L;;;;;N;;;;; -A3BF;YI SYLLABLE SHUR;Lo;0;L;;;;;N;;;;; -A3C0;YI SYLLABLE SHYT;Lo;0;L;;;;;N;;;;; -A3C1;YI SYLLABLE SHYX;Lo;0;L;;;;;N;;;;; -A3C2;YI SYLLABLE SHY;Lo;0;L;;;;;N;;;;; -A3C3;YI SYLLABLE SHYP;Lo;0;L;;;;;N;;;;; -A3C4;YI SYLLABLE SHYRX;Lo;0;L;;;;;N;;;;; -A3C5;YI SYLLABLE SHYR;Lo;0;L;;;;;N;;;;; -A3C6;YI SYLLABLE RAT;Lo;0;L;;;;;N;;;;; -A3C7;YI SYLLABLE RAX;Lo;0;L;;;;;N;;;;; -A3C8;YI SYLLABLE RA;Lo;0;L;;;;;N;;;;; -A3C9;YI SYLLABLE RAP;Lo;0;L;;;;;N;;;;; -A3CA;YI SYLLABLE RUOX;Lo;0;L;;;;;N;;;;; -A3CB;YI SYLLABLE RUO;Lo;0;L;;;;;N;;;;; -A3CC;YI SYLLABLE RUOP;Lo;0;L;;;;;N;;;;; -A3CD;YI SYLLABLE ROT;Lo;0;L;;;;;N;;;;; -A3CE;YI SYLLABLE ROX;Lo;0;L;;;;;N;;;;; -A3CF;YI SYLLABLE RO;Lo;0;L;;;;;N;;;;; -A3D0;YI SYLLABLE ROP;Lo;0;L;;;;;N;;;;; -A3D1;YI SYLLABLE REX;Lo;0;L;;;;;N;;;;; -A3D2;YI SYLLABLE RE;Lo;0;L;;;;;N;;;;; -A3D3;YI SYLLABLE REP;Lo;0;L;;;;;N;;;;; -A3D4;YI SYLLABLE RUT;Lo;0;L;;;;;N;;;;; -A3D5;YI SYLLABLE RUX;Lo;0;L;;;;;N;;;;; -A3D6;YI SYLLABLE RU;Lo;0;L;;;;;N;;;;; -A3D7;YI SYLLABLE RUP;Lo;0;L;;;;;N;;;;; -A3D8;YI SYLLABLE RURX;Lo;0;L;;;;;N;;;;; -A3D9;YI SYLLABLE RUR;Lo;0;L;;;;;N;;;;; -A3DA;YI SYLLABLE RYT;Lo;0;L;;;;;N;;;;; -A3DB;YI SYLLABLE RYX;Lo;0;L;;;;;N;;;;; -A3DC;YI SYLLABLE RY;Lo;0;L;;;;;N;;;;; -A3DD;YI SYLLABLE RYP;Lo;0;L;;;;;N;;;;; -A3DE;YI SYLLABLE RYRX;Lo;0;L;;;;;N;;;;; -A3DF;YI SYLLABLE RYR;Lo;0;L;;;;;N;;;;; -A3E0;YI SYLLABLE JIT;Lo;0;L;;;;;N;;;;; -A3E1;YI SYLLABLE JIX;Lo;0;L;;;;;N;;;;; -A3E2;YI SYLLABLE JI;Lo;0;L;;;;;N;;;;; -A3E3;YI SYLLABLE JIP;Lo;0;L;;;;;N;;;;; -A3E4;YI SYLLABLE JIET;Lo;0;L;;;;;N;;;;; -A3E5;YI SYLLABLE JIEX;Lo;0;L;;;;;N;;;;; -A3E6;YI SYLLABLE JIE;Lo;0;L;;;;;N;;;;; -A3E7;YI SYLLABLE JIEP;Lo;0;L;;;;;N;;;;; -A3E8;YI SYLLABLE JUOT;Lo;0;L;;;;;N;;;;; -A3E9;YI SYLLABLE JUOX;Lo;0;L;;;;;N;;;;; -A3EA;YI SYLLABLE JUO;Lo;0;L;;;;;N;;;;; -A3EB;YI SYLLABLE JUOP;Lo;0;L;;;;;N;;;;; -A3EC;YI SYLLABLE JOT;Lo;0;L;;;;;N;;;;; -A3ED;YI SYLLABLE JOX;Lo;0;L;;;;;N;;;;; -A3EE;YI SYLLABLE JO;Lo;0;L;;;;;N;;;;; -A3EF;YI SYLLABLE JOP;Lo;0;L;;;;;N;;;;; -A3F0;YI SYLLABLE JUT;Lo;0;L;;;;;N;;;;; -A3F1;YI SYLLABLE JUX;Lo;0;L;;;;;N;;;;; -A3F2;YI SYLLABLE JU;Lo;0;L;;;;;N;;;;; -A3F3;YI SYLLABLE JUP;Lo;0;L;;;;;N;;;;; -A3F4;YI SYLLABLE JURX;Lo;0;L;;;;;N;;;;; -A3F5;YI SYLLABLE JUR;Lo;0;L;;;;;N;;;;; -A3F6;YI SYLLABLE JYT;Lo;0;L;;;;;N;;;;; -A3F7;YI SYLLABLE JYX;Lo;0;L;;;;;N;;;;; -A3F8;YI SYLLABLE JY;Lo;0;L;;;;;N;;;;; -A3F9;YI SYLLABLE JYP;Lo;0;L;;;;;N;;;;; -A3FA;YI SYLLABLE JYRX;Lo;0;L;;;;;N;;;;; -A3FB;YI SYLLABLE JYR;Lo;0;L;;;;;N;;;;; -A3FC;YI SYLLABLE QIT;Lo;0;L;;;;;N;;;;; -A3FD;YI SYLLABLE QIX;Lo;0;L;;;;;N;;;;; -A3FE;YI SYLLABLE QI;Lo;0;L;;;;;N;;;;; -A3FF;YI SYLLABLE QIP;Lo;0;L;;;;;N;;;;; -A400;YI SYLLABLE QIET;Lo;0;L;;;;;N;;;;; -A401;YI SYLLABLE QIEX;Lo;0;L;;;;;N;;;;; -A402;YI SYLLABLE QIE;Lo;0;L;;;;;N;;;;; -A403;YI SYLLABLE QIEP;Lo;0;L;;;;;N;;;;; -A404;YI SYLLABLE QUOT;Lo;0;L;;;;;N;;;;; -A405;YI SYLLABLE QUOX;Lo;0;L;;;;;N;;;;; -A406;YI SYLLABLE QUO;Lo;0;L;;;;;N;;;;; -A407;YI SYLLABLE QUOP;Lo;0;L;;;;;N;;;;; -A408;YI SYLLABLE QOT;Lo;0;L;;;;;N;;;;; -A409;YI SYLLABLE QOX;Lo;0;L;;;;;N;;;;; -A40A;YI SYLLABLE QO;Lo;0;L;;;;;N;;;;; -A40B;YI SYLLABLE QOP;Lo;0;L;;;;;N;;;;; -A40C;YI SYLLABLE QUT;Lo;0;L;;;;;N;;;;; -A40D;YI SYLLABLE QUX;Lo;0;L;;;;;N;;;;; -A40E;YI SYLLABLE QU;Lo;0;L;;;;;N;;;;; -A40F;YI SYLLABLE QUP;Lo;0;L;;;;;N;;;;; -A410;YI SYLLABLE QURX;Lo;0;L;;;;;N;;;;; -A411;YI SYLLABLE QUR;Lo;0;L;;;;;N;;;;; -A412;YI SYLLABLE QYT;Lo;0;L;;;;;N;;;;; -A413;YI SYLLABLE QYX;Lo;0;L;;;;;N;;;;; -A414;YI SYLLABLE QY;Lo;0;L;;;;;N;;;;; -A415;YI SYLLABLE QYP;Lo;0;L;;;;;N;;;;; -A416;YI SYLLABLE QYRX;Lo;0;L;;;;;N;;;;; -A417;YI SYLLABLE QYR;Lo;0;L;;;;;N;;;;; -A418;YI SYLLABLE JJIT;Lo;0;L;;;;;N;;;;; -A419;YI SYLLABLE JJIX;Lo;0;L;;;;;N;;;;; -A41A;YI SYLLABLE JJI;Lo;0;L;;;;;N;;;;; -A41B;YI SYLLABLE JJIP;Lo;0;L;;;;;N;;;;; -A41C;YI SYLLABLE JJIET;Lo;0;L;;;;;N;;;;; -A41D;YI SYLLABLE JJIEX;Lo;0;L;;;;;N;;;;; -A41E;YI SYLLABLE JJIE;Lo;0;L;;;;;N;;;;; -A41F;YI SYLLABLE JJIEP;Lo;0;L;;;;;N;;;;; -A420;YI SYLLABLE JJUOX;Lo;0;L;;;;;N;;;;; -A421;YI SYLLABLE JJUO;Lo;0;L;;;;;N;;;;; -A422;YI SYLLABLE JJUOP;Lo;0;L;;;;;N;;;;; -A423;YI SYLLABLE JJOT;Lo;0;L;;;;;N;;;;; -A424;YI SYLLABLE JJOX;Lo;0;L;;;;;N;;;;; -A425;YI SYLLABLE JJO;Lo;0;L;;;;;N;;;;; -A426;YI SYLLABLE JJOP;Lo;0;L;;;;;N;;;;; -A427;YI SYLLABLE JJUT;Lo;0;L;;;;;N;;;;; -A428;YI SYLLABLE JJUX;Lo;0;L;;;;;N;;;;; -A429;YI SYLLABLE JJU;Lo;0;L;;;;;N;;;;; -A42A;YI SYLLABLE JJUP;Lo;0;L;;;;;N;;;;; -A42B;YI SYLLABLE JJURX;Lo;0;L;;;;;N;;;;; -A42C;YI SYLLABLE JJUR;Lo;0;L;;;;;N;;;;; -A42D;YI SYLLABLE JJYT;Lo;0;L;;;;;N;;;;; -A42E;YI SYLLABLE JJYX;Lo;0;L;;;;;N;;;;; -A42F;YI SYLLABLE JJY;Lo;0;L;;;;;N;;;;; -A430;YI SYLLABLE JJYP;Lo;0;L;;;;;N;;;;; -A431;YI SYLLABLE NJIT;Lo;0;L;;;;;N;;;;; -A432;YI SYLLABLE NJIX;Lo;0;L;;;;;N;;;;; -A433;YI SYLLABLE NJI;Lo;0;L;;;;;N;;;;; -A434;YI SYLLABLE NJIP;Lo;0;L;;;;;N;;;;; -A435;YI SYLLABLE NJIET;Lo;0;L;;;;;N;;;;; -A436;YI SYLLABLE NJIEX;Lo;0;L;;;;;N;;;;; -A437;YI SYLLABLE NJIE;Lo;0;L;;;;;N;;;;; -A438;YI SYLLABLE NJIEP;Lo;0;L;;;;;N;;;;; -A439;YI SYLLABLE NJUOX;Lo;0;L;;;;;N;;;;; -A43A;YI SYLLABLE NJUO;Lo;0;L;;;;;N;;;;; -A43B;YI SYLLABLE NJOT;Lo;0;L;;;;;N;;;;; -A43C;YI SYLLABLE NJOX;Lo;0;L;;;;;N;;;;; -A43D;YI SYLLABLE NJO;Lo;0;L;;;;;N;;;;; -A43E;YI SYLLABLE NJOP;Lo;0;L;;;;;N;;;;; -A43F;YI SYLLABLE NJUX;Lo;0;L;;;;;N;;;;; -A440;YI SYLLABLE NJU;Lo;0;L;;;;;N;;;;; -A441;YI SYLLABLE NJUP;Lo;0;L;;;;;N;;;;; -A442;YI SYLLABLE NJURX;Lo;0;L;;;;;N;;;;; -A443;YI SYLLABLE NJUR;Lo;0;L;;;;;N;;;;; -A444;YI SYLLABLE NJYT;Lo;0;L;;;;;N;;;;; -A445;YI SYLLABLE NJYX;Lo;0;L;;;;;N;;;;; -A446;YI SYLLABLE NJY;Lo;0;L;;;;;N;;;;; -A447;YI SYLLABLE NJYP;Lo;0;L;;;;;N;;;;; -A448;YI SYLLABLE NJYRX;Lo;0;L;;;;;N;;;;; -A449;YI SYLLABLE NJYR;Lo;0;L;;;;;N;;;;; -A44A;YI SYLLABLE NYIT;Lo;0;L;;;;;N;;;;; -A44B;YI SYLLABLE NYIX;Lo;0;L;;;;;N;;;;; -A44C;YI SYLLABLE NYI;Lo;0;L;;;;;N;;;;; -A44D;YI SYLLABLE NYIP;Lo;0;L;;;;;N;;;;; -A44E;YI SYLLABLE NYIET;Lo;0;L;;;;;N;;;;; -A44F;YI SYLLABLE NYIEX;Lo;0;L;;;;;N;;;;; -A450;YI SYLLABLE NYIE;Lo;0;L;;;;;N;;;;; -A451;YI SYLLABLE NYIEP;Lo;0;L;;;;;N;;;;; -A452;YI SYLLABLE NYUOX;Lo;0;L;;;;;N;;;;; -A453;YI SYLLABLE NYUO;Lo;0;L;;;;;N;;;;; -A454;YI SYLLABLE NYUOP;Lo;0;L;;;;;N;;;;; -A455;YI SYLLABLE NYOT;Lo;0;L;;;;;N;;;;; -A456;YI SYLLABLE NYOX;Lo;0;L;;;;;N;;;;; -A457;YI SYLLABLE NYO;Lo;0;L;;;;;N;;;;; -A458;YI SYLLABLE NYOP;Lo;0;L;;;;;N;;;;; -A459;YI SYLLABLE NYUT;Lo;0;L;;;;;N;;;;; -A45A;YI SYLLABLE NYUX;Lo;0;L;;;;;N;;;;; -A45B;YI SYLLABLE NYU;Lo;0;L;;;;;N;;;;; -A45C;YI SYLLABLE NYUP;Lo;0;L;;;;;N;;;;; -A45D;YI SYLLABLE XIT;Lo;0;L;;;;;N;;;;; -A45E;YI SYLLABLE XIX;Lo;0;L;;;;;N;;;;; -A45F;YI SYLLABLE XI;Lo;0;L;;;;;N;;;;; -A460;YI SYLLABLE XIP;Lo;0;L;;;;;N;;;;; -A461;YI SYLLABLE XIET;Lo;0;L;;;;;N;;;;; -A462;YI SYLLABLE XIEX;Lo;0;L;;;;;N;;;;; -A463;YI SYLLABLE XIE;Lo;0;L;;;;;N;;;;; -A464;YI SYLLABLE XIEP;Lo;0;L;;;;;N;;;;; -A465;YI SYLLABLE XUOX;Lo;0;L;;;;;N;;;;; -A466;YI SYLLABLE XUO;Lo;0;L;;;;;N;;;;; -A467;YI SYLLABLE XOT;Lo;0;L;;;;;N;;;;; -A468;YI SYLLABLE XOX;Lo;0;L;;;;;N;;;;; -A469;YI SYLLABLE XO;Lo;0;L;;;;;N;;;;; -A46A;YI SYLLABLE XOP;Lo;0;L;;;;;N;;;;; -A46B;YI SYLLABLE XYT;Lo;0;L;;;;;N;;;;; -A46C;YI SYLLABLE XYX;Lo;0;L;;;;;N;;;;; -A46D;YI SYLLABLE XY;Lo;0;L;;;;;N;;;;; -A46E;YI SYLLABLE XYP;Lo;0;L;;;;;N;;;;; -A46F;YI SYLLABLE XYRX;Lo;0;L;;;;;N;;;;; -A470;YI SYLLABLE XYR;Lo;0;L;;;;;N;;;;; -A471;YI SYLLABLE YIT;Lo;0;L;;;;;N;;;;; -A472;YI SYLLABLE YIX;Lo;0;L;;;;;N;;;;; -A473;YI SYLLABLE YI;Lo;0;L;;;;;N;;;;; -A474;YI SYLLABLE YIP;Lo;0;L;;;;;N;;;;; -A475;YI SYLLABLE YIET;Lo;0;L;;;;;N;;;;; -A476;YI SYLLABLE YIEX;Lo;0;L;;;;;N;;;;; -A477;YI SYLLABLE YIE;Lo;0;L;;;;;N;;;;; -A478;YI SYLLABLE YIEP;Lo;0;L;;;;;N;;;;; -A479;YI SYLLABLE YUOT;Lo;0;L;;;;;N;;;;; -A47A;YI SYLLABLE YUOX;Lo;0;L;;;;;N;;;;; -A47B;YI SYLLABLE YUO;Lo;0;L;;;;;N;;;;; -A47C;YI SYLLABLE YUOP;Lo;0;L;;;;;N;;;;; -A47D;YI SYLLABLE YOT;Lo;0;L;;;;;N;;;;; -A47E;YI SYLLABLE YOX;Lo;0;L;;;;;N;;;;; -A47F;YI SYLLABLE YO;Lo;0;L;;;;;N;;;;; -A480;YI SYLLABLE YOP;Lo;0;L;;;;;N;;;;; -A481;YI SYLLABLE YUT;Lo;0;L;;;;;N;;;;; -A482;YI SYLLABLE YUX;Lo;0;L;;;;;N;;;;; -A483;YI SYLLABLE YU;Lo;0;L;;;;;N;;;;; -A484;YI SYLLABLE YUP;Lo;0;L;;;;;N;;;;; -A485;YI SYLLABLE YURX;Lo;0;L;;;;;N;;;;; -A486;YI SYLLABLE YUR;Lo;0;L;;;;;N;;;;; -A487;YI SYLLABLE YYT;Lo;0;L;;;;;N;;;;; -A488;YI SYLLABLE YYX;Lo;0;L;;;;;N;;;;; -A489;YI SYLLABLE YY;Lo;0;L;;;;;N;;;;; -A48A;YI SYLLABLE YYP;Lo;0;L;;;;;N;;;;; -A48B;YI SYLLABLE YYRX;Lo;0;L;;;;;N;;;;; -A48C;YI SYLLABLE YYR;Lo;0;L;;;;;N;;;;; -A490;YI RADICAL QOT;So;0;ON;;;;;N;;;;; -A491;YI RADICAL LI;So;0;ON;;;;;N;;;;; -A492;YI RADICAL KIT;So;0;ON;;;;;N;;;;; -A493;YI RADICAL NYIP;So;0;ON;;;;;N;;;;; -A494;YI RADICAL CYP;So;0;ON;;;;;N;;;;; -A495;YI RADICAL SSI;So;0;ON;;;;;N;;;;; -A496;YI RADICAL GGOP;So;0;ON;;;;;N;;;;; -A497;YI RADICAL GEP;So;0;ON;;;;;N;;;;; -A498;YI RADICAL MI;So;0;ON;;;;;N;;;;; -A499;YI RADICAL HXIT;So;0;ON;;;;;N;;;;; -A49A;YI RADICAL LYR;So;0;ON;;;;;N;;;;; -A49B;YI RADICAL BBUT;So;0;ON;;;;;N;;;;; -A49C;YI RADICAL MOP;So;0;ON;;;;;N;;;;; -A49D;YI RADICAL YO;So;0;ON;;;;;N;;;;; -A49E;YI RADICAL PUT;So;0;ON;;;;;N;;;;; -A49F;YI RADICAL HXUO;So;0;ON;;;;;N;;;;; -A4A0;YI RADICAL TAT;So;0;ON;;;;;N;;;;; -A4A1;YI RADICAL GA;So;0;ON;;;;;N;;;;; -A4A2;YI RADICAL ZUP;So;0;ON;;;;;N;;;;; -A4A3;YI RADICAL CYT;So;0;ON;;;;;N;;;;; -A4A4;YI RADICAL DDUR;So;0;ON;;;;;N;;;;; -A4A5;YI RADICAL BUR;So;0;ON;;;;;N;;;;; -A4A6;YI RADICAL GGUO;So;0;ON;;;;;N;;;;; -A4A7;YI RADICAL NYOP;So;0;ON;;;;;N;;;;; -A4A8;YI RADICAL TU;So;0;ON;;;;;N;;;;; -A4A9;YI RADICAL OP;So;0;ON;;;;;N;;;;; -A4AA;YI RADICAL JJUT;So;0;ON;;;;;N;;;;; -A4AB;YI RADICAL ZOT;So;0;ON;;;;;N;;;;; -A4AC;YI RADICAL PYT;So;0;ON;;;;;N;;;;; -A4AD;YI RADICAL HMO;So;0;ON;;;;;N;;;;; -A4AE;YI RADICAL YIT;So;0;ON;;;;;N;;;;; -A4AF;YI RADICAL VUR;So;0;ON;;;;;N;;;;; -A4B0;YI RADICAL SHY;So;0;ON;;;;;N;;;;; -A4B1;YI RADICAL VEP;So;0;ON;;;;;N;;;;; -A4B2;YI RADICAL ZA;So;0;ON;;;;;N;;;;; -A4B3;YI RADICAL JO;So;0;ON;;;;;N;;;;; -A4B4;YI RADICAL NZUP;So;0;ON;;;;;N;;;;; -A4B5;YI RADICAL JJY;So;0;ON;;;;;N;;;;; -A4B6;YI RADICAL GOT;So;0;ON;;;;;N;;;;; -A4B7;YI RADICAL JJIE;So;0;ON;;;;;N;;;;; -A4B8;YI RADICAL WO;So;0;ON;;;;;N;;;;; -A4B9;YI RADICAL DU;So;0;ON;;;;;N;;;;; -A4BA;YI RADICAL SHUR;So;0;ON;;;;;N;;;;; -A4BB;YI RADICAL LIE;So;0;ON;;;;;N;;;;; -A4BC;YI RADICAL CY;So;0;ON;;;;;N;;;;; -A4BD;YI RADICAL CUOP;So;0;ON;;;;;N;;;;; -A4BE;YI RADICAL CIP;So;0;ON;;;;;N;;;;; -A4BF;YI RADICAL HXOP;So;0;ON;;;;;N;;;;; -A4C0;YI RADICAL SHAT;So;0;ON;;;;;N;;;;; -A4C1;YI RADICAL ZUR;So;0;ON;;;;;N;;;;; -A4C2;YI RADICAL SHOP;So;0;ON;;;;;N;;;;; -A4C3;YI RADICAL CHE;So;0;ON;;;;;N;;;;; -A4C4;YI RADICAL ZZIET;So;0;ON;;;;;N;;;;; -A4C5;YI RADICAL NBIE;So;0;ON;;;;;N;;;;; -A4C6;YI RADICAL KE;So;0;ON;;;;;N;;;;; -A4D0;LISU LETTER BA;Lo;0;L;;;;;N;;;;; -A4D1;LISU LETTER PA;Lo;0;L;;;;;N;;;;; -A4D2;LISU LETTER PHA;Lo;0;L;;;;;N;;;;; -A4D3;LISU LETTER DA;Lo;0;L;;;;;N;;;;; -A4D4;LISU LETTER TA;Lo;0;L;;;;;N;;;;; -A4D5;LISU LETTER THA;Lo;0;L;;;;;N;;;;; -A4D6;LISU LETTER GA;Lo;0;L;;;;;N;;;;; -A4D7;LISU LETTER KA;Lo;0;L;;;;;N;;;;; -A4D8;LISU LETTER KHA;Lo;0;L;;;;;N;;;;; -A4D9;LISU LETTER JA;Lo;0;L;;;;;N;;;;; -A4DA;LISU LETTER CA;Lo;0;L;;;;;N;;;;; -A4DB;LISU LETTER CHA;Lo;0;L;;;;;N;;;;; -A4DC;LISU LETTER DZA;Lo;0;L;;;;;N;;;;; -A4DD;LISU LETTER TSA;Lo;0;L;;;;;N;;;;; -A4DE;LISU LETTER TSHA;Lo;0;L;;;;;N;;;;; -A4DF;LISU LETTER MA;Lo;0;L;;;;;N;;;;; -A4E0;LISU LETTER NA;Lo;0;L;;;;;N;;;;; -A4E1;LISU LETTER LA;Lo;0;L;;;;;N;;;;; -A4E2;LISU LETTER SA;Lo;0;L;;;;;N;;;;; -A4E3;LISU LETTER ZHA;Lo;0;L;;;;;N;;;;; -A4E4;LISU LETTER ZA;Lo;0;L;;;;;N;;;;; -A4E5;LISU LETTER NGA;Lo;0;L;;;;;N;;;;; -A4E6;LISU LETTER HA;Lo;0;L;;;;;N;;;;; -A4E7;LISU LETTER XA;Lo;0;L;;;;;N;;;;; -A4E8;LISU LETTER HHA;Lo;0;L;;;;;N;;;;; -A4E9;LISU LETTER FA;Lo;0;L;;;;;N;;;;; -A4EA;LISU LETTER WA;Lo;0;L;;;;;N;;;;; -A4EB;LISU LETTER SHA;Lo;0;L;;;;;N;;;;; -A4EC;LISU LETTER YA;Lo;0;L;;;;;N;;;;; -A4ED;LISU LETTER GHA;Lo;0;L;;;;;N;;;;; -A4EE;LISU LETTER A;Lo;0;L;;;;;N;;;;; -A4EF;LISU LETTER AE;Lo;0;L;;;;;N;;;;; -A4F0;LISU LETTER E;Lo;0;L;;;;;N;;;;; -A4F1;LISU LETTER EU;Lo;0;L;;;;;N;;;;; -A4F2;LISU LETTER I;Lo;0;L;;;;;N;;;;; -A4F3;LISU LETTER O;Lo;0;L;;;;;N;;;;; -A4F4;LISU LETTER U;Lo;0;L;;;;;N;;;;; -A4F5;LISU LETTER UE;Lo;0;L;;;;;N;;;;; -A4F6;LISU LETTER UH;Lo;0;L;;;;;N;;;;; -A4F7;LISU LETTER OE;Lo;0;L;;;;;N;;;;; -A4F8;LISU LETTER TONE MYA TI;Lm;0;L;;;;;N;;;;; -A4F9;LISU LETTER TONE NA PO;Lm;0;L;;;;;N;;;;; -A4FA;LISU LETTER TONE MYA CYA;Lm;0;L;;;;;N;;;;; -A4FB;LISU LETTER TONE MYA BO;Lm;0;L;;;;;N;;;;; -A4FC;LISU LETTER TONE MYA NA;Lm;0;L;;;;;N;;;;; -A4FD;LISU LETTER TONE MYA JEU;Lm;0;L;;;;;N;;;;; -A4FE;LISU PUNCTUATION COMMA;Po;0;L;;;;;N;;;;; -A4FF;LISU PUNCTUATION FULL STOP;Po;0;L;;;;;N;;;;; -A500;VAI SYLLABLE EE;Lo;0;L;;;;;N;;;;; -A501;VAI SYLLABLE EEN;Lo;0;L;;;;;N;;;;; -A502;VAI SYLLABLE HEE;Lo;0;L;;;;;N;;;;; -A503;VAI SYLLABLE WEE;Lo;0;L;;;;;N;;;;; -A504;VAI SYLLABLE WEEN;Lo;0;L;;;;;N;;;;; -A505;VAI SYLLABLE PEE;Lo;0;L;;;;;N;;;;; -A506;VAI SYLLABLE BHEE;Lo;0;L;;;;;N;;;;; -A507;VAI SYLLABLE BEE;Lo;0;L;;;;;N;;;;; -A508;VAI SYLLABLE MBEE;Lo;0;L;;;;;N;;;;; -A509;VAI SYLLABLE KPEE;Lo;0;L;;;;;N;;;;; -A50A;VAI SYLLABLE MGBEE;Lo;0;L;;;;;N;;;;; -A50B;VAI SYLLABLE GBEE;Lo;0;L;;;;;N;;;;; -A50C;VAI SYLLABLE FEE;Lo;0;L;;;;;N;;;;; -A50D;VAI SYLLABLE VEE;Lo;0;L;;;;;N;;;;; -A50E;VAI SYLLABLE TEE;Lo;0;L;;;;;N;;;;; -A50F;VAI SYLLABLE THEE;Lo;0;L;;;;;N;;;;; -A510;VAI SYLLABLE DHEE;Lo;0;L;;;;;N;;;;; -A511;VAI SYLLABLE DHHEE;Lo;0;L;;;;;N;;;;; -A512;VAI SYLLABLE LEE;Lo;0;L;;;;;N;;;;; -A513;VAI SYLLABLE REE;Lo;0;L;;;;;N;;;;; -A514;VAI SYLLABLE DEE;Lo;0;L;;;;;N;;;;; -A515;VAI SYLLABLE NDEE;Lo;0;L;;;;;N;;;;; -A516;VAI SYLLABLE SEE;Lo;0;L;;;;;N;;;;; -A517;VAI SYLLABLE SHEE;Lo;0;L;;;;;N;;;;; -A518;VAI SYLLABLE ZEE;Lo;0;L;;;;;N;;;;; -A519;VAI SYLLABLE ZHEE;Lo;0;L;;;;;N;;;;; -A51A;VAI SYLLABLE CEE;Lo;0;L;;;;;N;;;;; -A51B;VAI SYLLABLE JEE;Lo;0;L;;;;;N;;;;; -A51C;VAI SYLLABLE NJEE;Lo;0;L;;;;;N;;;;; -A51D;VAI SYLLABLE YEE;Lo;0;L;;;;;N;;;;; -A51E;VAI SYLLABLE KEE;Lo;0;L;;;;;N;;;;; -A51F;VAI SYLLABLE NGGEE;Lo;0;L;;;;;N;;;;; -A520;VAI SYLLABLE GEE;Lo;0;L;;;;;N;;;;; -A521;VAI SYLLABLE MEE;Lo;0;L;;;;;N;;;;; -A522;VAI SYLLABLE NEE;Lo;0;L;;;;;N;;;;; -A523;VAI SYLLABLE NYEE;Lo;0;L;;;;;N;;;;; -A524;VAI SYLLABLE I;Lo;0;L;;;;;N;;;;; -A525;VAI SYLLABLE IN;Lo;0;L;;;;;N;;;;; -A526;VAI SYLLABLE HI;Lo;0;L;;;;;N;;;;; -A527;VAI SYLLABLE HIN;Lo;0;L;;;;;N;;;;; -A528;VAI SYLLABLE WI;Lo;0;L;;;;;N;;;;; -A529;VAI SYLLABLE WIN;Lo;0;L;;;;;N;;;;; -A52A;VAI SYLLABLE PI;Lo;0;L;;;;;N;;;;; -A52B;VAI SYLLABLE BHI;Lo;0;L;;;;;N;;;;; -A52C;VAI SYLLABLE BI;Lo;0;L;;;;;N;;;;; -A52D;VAI SYLLABLE MBI;Lo;0;L;;;;;N;;;;; -A52E;VAI SYLLABLE KPI;Lo;0;L;;;;;N;;;;; -A52F;VAI SYLLABLE MGBI;Lo;0;L;;;;;N;;;;; -A530;VAI SYLLABLE GBI;Lo;0;L;;;;;N;;;;; -A531;VAI SYLLABLE FI;Lo;0;L;;;;;N;;;;; -A532;VAI SYLLABLE VI;Lo;0;L;;;;;N;;;;; -A533;VAI SYLLABLE TI;Lo;0;L;;;;;N;;;;; -A534;VAI SYLLABLE THI;Lo;0;L;;;;;N;;;;; -A535;VAI SYLLABLE DHI;Lo;0;L;;;;;N;;;;; -A536;VAI SYLLABLE DHHI;Lo;0;L;;;;;N;;;;; -A537;VAI SYLLABLE LI;Lo;0;L;;;;;N;;;;; -A538;VAI SYLLABLE RI;Lo;0;L;;;;;N;;;;; -A539;VAI SYLLABLE DI;Lo;0;L;;;;;N;;;;; -A53A;VAI SYLLABLE NDI;Lo;0;L;;;;;N;;;;; -A53B;VAI SYLLABLE SI;Lo;0;L;;;;;N;;;;; -A53C;VAI SYLLABLE SHI;Lo;0;L;;;;;N;;;;; -A53D;VAI SYLLABLE ZI;Lo;0;L;;;;;N;;;;; -A53E;VAI SYLLABLE ZHI;Lo;0;L;;;;;N;;;;; -A53F;VAI SYLLABLE CI;Lo;0;L;;;;;N;;;;; -A540;VAI SYLLABLE JI;Lo;0;L;;;;;N;;;;; -A541;VAI SYLLABLE NJI;Lo;0;L;;;;;N;;;;; -A542;VAI SYLLABLE YI;Lo;0;L;;;;;N;;;;; -A543;VAI SYLLABLE KI;Lo;0;L;;;;;N;;;;; -A544;VAI SYLLABLE NGGI;Lo;0;L;;;;;N;;;;; -A545;VAI SYLLABLE GI;Lo;0;L;;;;;N;;;;; -A546;VAI SYLLABLE MI;Lo;0;L;;;;;N;;;;; -A547;VAI SYLLABLE NI;Lo;0;L;;;;;N;;;;; -A548;VAI SYLLABLE NYI;Lo;0;L;;;;;N;;;;; -A549;VAI SYLLABLE A;Lo;0;L;;;;;N;;;;; -A54A;VAI SYLLABLE AN;Lo;0;L;;;;;N;;;;; -A54B;VAI SYLLABLE NGAN;Lo;0;L;;;;;N;;;;; -A54C;VAI SYLLABLE HA;Lo;0;L;;;;;N;;;;; -A54D;VAI SYLLABLE HAN;Lo;0;L;;;;;N;;;;; -A54E;VAI SYLLABLE WA;Lo;0;L;;;;;N;;;;; -A54F;VAI SYLLABLE WAN;Lo;0;L;;;;;N;;;;; -A550;VAI SYLLABLE PA;Lo;0;L;;;;;N;;;;; -A551;VAI SYLLABLE BHA;Lo;0;L;;;;;N;;;;; -A552;VAI SYLLABLE BA;Lo;0;L;;;;;N;;;;; -A553;VAI SYLLABLE MBA;Lo;0;L;;;;;N;;;;; -A554;VAI SYLLABLE KPA;Lo;0;L;;;;;N;;;;; -A555;VAI SYLLABLE KPAN;Lo;0;L;;;;;N;;;;; -A556;VAI SYLLABLE MGBA;Lo;0;L;;;;;N;;;;; -A557;VAI SYLLABLE GBA;Lo;0;L;;;;;N;;;;; -A558;VAI SYLLABLE FA;Lo;0;L;;;;;N;;;;; -A559;VAI SYLLABLE VA;Lo;0;L;;;;;N;;;;; -A55A;VAI SYLLABLE TA;Lo;0;L;;;;;N;;;;; -A55B;VAI SYLLABLE THA;Lo;0;L;;;;;N;;;;; -A55C;VAI SYLLABLE DHA;Lo;0;L;;;;;N;;;;; -A55D;VAI SYLLABLE DHHA;Lo;0;L;;;;;N;;;;; -A55E;VAI SYLLABLE LA;Lo;0;L;;;;;N;;;;; -A55F;VAI SYLLABLE RA;Lo;0;L;;;;;N;;;;; -A560;VAI SYLLABLE DA;Lo;0;L;;;;;N;;;;; -A561;VAI SYLLABLE NDA;Lo;0;L;;;;;N;;;;; -A562;VAI SYLLABLE SA;Lo;0;L;;;;;N;;;;; -A563;VAI SYLLABLE SHA;Lo;0;L;;;;;N;;;;; -A564;VAI SYLLABLE ZA;Lo;0;L;;;;;N;;;;; -A565;VAI SYLLABLE ZHA;Lo;0;L;;;;;N;;;;; -A566;VAI SYLLABLE CA;Lo;0;L;;;;;N;;;;; -A567;VAI SYLLABLE JA;Lo;0;L;;;;;N;;;;; -A568;VAI SYLLABLE NJA;Lo;0;L;;;;;N;;;;; -A569;VAI SYLLABLE YA;Lo;0;L;;;;;N;;;;; -A56A;VAI SYLLABLE KA;Lo;0;L;;;;;N;;;;; -A56B;VAI SYLLABLE KAN;Lo;0;L;;;;;N;;;;; -A56C;VAI SYLLABLE NGGA;Lo;0;L;;;;;N;;;;; -A56D;VAI SYLLABLE GA;Lo;0;L;;;;;N;;;;; -A56E;VAI SYLLABLE MA;Lo;0;L;;;;;N;;;;; -A56F;VAI SYLLABLE NA;Lo;0;L;;;;;N;;;;; -A570;VAI SYLLABLE NYA;Lo;0;L;;;;;N;;;;; -A571;VAI SYLLABLE OO;Lo;0;L;;;;;N;;;;; -A572;VAI SYLLABLE OON;Lo;0;L;;;;;N;;;;; -A573;VAI SYLLABLE HOO;Lo;0;L;;;;;N;;;;; -A574;VAI SYLLABLE WOO;Lo;0;L;;;;;N;;;;; -A575;VAI SYLLABLE WOON;Lo;0;L;;;;;N;;;;; -A576;VAI SYLLABLE POO;Lo;0;L;;;;;N;;;;; -A577;VAI SYLLABLE BHOO;Lo;0;L;;;;;N;;;;; -A578;VAI SYLLABLE BOO;Lo;0;L;;;;;N;;;;; -A579;VAI SYLLABLE MBOO;Lo;0;L;;;;;N;;;;; -A57A;VAI SYLLABLE KPOO;Lo;0;L;;;;;N;;;;; -A57B;VAI SYLLABLE MGBOO;Lo;0;L;;;;;N;;;;; -A57C;VAI SYLLABLE GBOO;Lo;0;L;;;;;N;;;;; -A57D;VAI SYLLABLE FOO;Lo;0;L;;;;;N;;;;; -A57E;VAI SYLLABLE VOO;Lo;0;L;;;;;N;;;;; -A57F;VAI SYLLABLE TOO;Lo;0;L;;;;;N;;;;; -A580;VAI SYLLABLE THOO;Lo;0;L;;;;;N;;;;; -A581;VAI SYLLABLE DHOO;Lo;0;L;;;;;N;;;;; -A582;VAI SYLLABLE DHHOO;Lo;0;L;;;;;N;;;;; -A583;VAI SYLLABLE LOO;Lo;0;L;;;;;N;;;;; -A584;VAI SYLLABLE ROO;Lo;0;L;;;;;N;;;;; -A585;VAI SYLLABLE DOO;Lo;0;L;;;;;N;;;;; -A586;VAI SYLLABLE NDOO;Lo;0;L;;;;;N;;;;; -A587;VAI SYLLABLE SOO;Lo;0;L;;;;;N;;;;; -A588;VAI SYLLABLE SHOO;Lo;0;L;;;;;N;;;;; -A589;VAI SYLLABLE ZOO;Lo;0;L;;;;;N;;;;; -A58A;VAI SYLLABLE ZHOO;Lo;0;L;;;;;N;;;;; -A58B;VAI SYLLABLE COO;Lo;0;L;;;;;N;;;;; -A58C;VAI SYLLABLE JOO;Lo;0;L;;;;;N;;;;; -A58D;VAI SYLLABLE NJOO;Lo;0;L;;;;;N;;;;; -A58E;VAI SYLLABLE YOO;Lo;0;L;;;;;N;;;;; -A58F;VAI SYLLABLE KOO;Lo;0;L;;;;;N;;;;; -A590;VAI SYLLABLE NGGOO;Lo;0;L;;;;;N;;;;; -A591;VAI SYLLABLE GOO;Lo;0;L;;;;;N;;;;; -A592;VAI SYLLABLE MOO;Lo;0;L;;;;;N;;;;; -A593;VAI SYLLABLE NOO;Lo;0;L;;;;;N;;;;; -A594;VAI SYLLABLE NYOO;Lo;0;L;;;;;N;;;;; -A595;VAI SYLLABLE U;Lo;0;L;;;;;N;;;;; -A596;VAI SYLLABLE UN;Lo;0;L;;;;;N;;;;; -A597;VAI SYLLABLE HU;Lo;0;L;;;;;N;;;;; -A598;VAI SYLLABLE HUN;Lo;0;L;;;;;N;;;;; -A599;VAI SYLLABLE WU;Lo;0;L;;;;;N;;;;; -A59A;VAI SYLLABLE WUN;Lo;0;L;;;;;N;;;;; -A59B;VAI SYLLABLE PU;Lo;0;L;;;;;N;;;;; -A59C;VAI SYLLABLE BHU;Lo;0;L;;;;;N;;;;; -A59D;VAI SYLLABLE BU;Lo;0;L;;;;;N;;;;; -A59E;VAI SYLLABLE MBU;Lo;0;L;;;;;N;;;;; -A59F;VAI SYLLABLE KPU;Lo;0;L;;;;;N;;;;; -A5A0;VAI SYLLABLE MGBU;Lo;0;L;;;;;N;;;;; -A5A1;VAI SYLLABLE GBU;Lo;0;L;;;;;N;;;;; -A5A2;VAI SYLLABLE FU;Lo;0;L;;;;;N;;;;; -A5A3;VAI SYLLABLE VU;Lo;0;L;;;;;N;;;;; -A5A4;VAI SYLLABLE TU;Lo;0;L;;;;;N;;;;; -A5A5;VAI SYLLABLE THU;Lo;0;L;;;;;N;;;;; -A5A6;VAI SYLLABLE DHU;Lo;0;L;;;;;N;;;;; -A5A7;VAI SYLLABLE DHHU;Lo;0;L;;;;;N;;;;; -A5A8;VAI SYLLABLE LU;Lo;0;L;;;;;N;;;;; -A5A9;VAI SYLLABLE RU;Lo;0;L;;;;;N;;;;; -A5AA;VAI SYLLABLE DU;Lo;0;L;;;;;N;;;;; -A5AB;VAI SYLLABLE NDU;Lo;0;L;;;;;N;;;;; -A5AC;VAI SYLLABLE SU;Lo;0;L;;;;;N;;;;; -A5AD;VAI SYLLABLE SHU;Lo;0;L;;;;;N;;;;; -A5AE;VAI SYLLABLE ZU;Lo;0;L;;;;;N;;;;; -A5AF;VAI SYLLABLE ZHU;Lo;0;L;;;;;N;;;;; -A5B0;VAI SYLLABLE CU;Lo;0;L;;;;;N;;;;; -A5B1;VAI SYLLABLE JU;Lo;0;L;;;;;N;;;;; -A5B2;VAI SYLLABLE NJU;Lo;0;L;;;;;N;;;;; -A5B3;VAI SYLLABLE YU;Lo;0;L;;;;;N;;;;; -A5B4;VAI SYLLABLE KU;Lo;0;L;;;;;N;;;;; -A5B5;VAI SYLLABLE NGGU;Lo;0;L;;;;;N;;;;; -A5B6;VAI SYLLABLE GU;Lo;0;L;;;;;N;;;;; -A5B7;VAI SYLLABLE MU;Lo;0;L;;;;;N;;;;; -A5B8;VAI SYLLABLE NU;Lo;0;L;;;;;N;;;;; -A5B9;VAI SYLLABLE NYU;Lo;0;L;;;;;N;;;;; -A5BA;VAI SYLLABLE O;Lo;0;L;;;;;N;;;;; -A5BB;VAI SYLLABLE ON;Lo;0;L;;;;;N;;;;; -A5BC;VAI SYLLABLE NGON;Lo;0;L;;;;;N;;;;; -A5BD;VAI SYLLABLE HO;Lo;0;L;;;;;N;;;;; -A5BE;VAI SYLLABLE HON;Lo;0;L;;;;;N;;;;; -A5BF;VAI SYLLABLE WO;Lo;0;L;;;;;N;;;;; -A5C0;VAI SYLLABLE WON;Lo;0;L;;;;;N;;;;; -A5C1;VAI SYLLABLE PO;Lo;0;L;;;;;N;;;;; -A5C2;VAI SYLLABLE BHO;Lo;0;L;;;;;N;;;;; -A5C3;VAI SYLLABLE BO;Lo;0;L;;;;;N;;;;; -A5C4;VAI SYLLABLE MBO;Lo;0;L;;;;;N;;;;; -A5C5;VAI SYLLABLE KPO;Lo;0;L;;;;;N;;;;; -A5C6;VAI SYLLABLE MGBO;Lo;0;L;;;;;N;;;;; -A5C7;VAI SYLLABLE GBO;Lo;0;L;;;;;N;;;;; -A5C8;VAI SYLLABLE GBON;Lo;0;L;;;;;N;;;;; -A5C9;VAI SYLLABLE FO;Lo;0;L;;;;;N;;;;; -A5CA;VAI SYLLABLE VO;Lo;0;L;;;;;N;;;;; -A5CB;VAI SYLLABLE TO;Lo;0;L;;;;;N;;;;; -A5CC;VAI SYLLABLE THO;Lo;0;L;;;;;N;;;;; -A5CD;VAI SYLLABLE DHO;Lo;0;L;;;;;N;;;;; -A5CE;VAI SYLLABLE DHHO;Lo;0;L;;;;;N;;;;; -A5CF;VAI SYLLABLE LO;Lo;0;L;;;;;N;;;;; -A5D0;VAI SYLLABLE RO;Lo;0;L;;;;;N;;;;; -A5D1;VAI SYLLABLE DO;Lo;0;L;;;;;N;;;;; -A5D2;VAI SYLLABLE NDO;Lo;0;L;;;;;N;;;;; -A5D3;VAI SYLLABLE SO;Lo;0;L;;;;;N;;;;; -A5D4;VAI SYLLABLE SHO;Lo;0;L;;;;;N;;;;; -A5D5;VAI SYLLABLE ZO;Lo;0;L;;;;;N;;;;; -A5D6;VAI SYLLABLE ZHO;Lo;0;L;;;;;N;;;;; -A5D7;VAI SYLLABLE CO;Lo;0;L;;;;;N;;;;; -A5D8;VAI SYLLABLE JO;Lo;0;L;;;;;N;;;;; -A5D9;VAI SYLLABLE NJO;Lo;0;L;;;;;N;;;;; -A5DA;VAI SYLLABLE YO;Lo;0;L;;;;;N;;;;; -A5DB;VAI SYLLABLE KO;Lo;0;L;;;;;N;;;;; -A5DC;VAI SYLLABLE NGGO;Lo;0;L;;;;;N;;;;; -A5DD;VAI SYLLABLE GO;Lo;0;L;;;;;N;;;;; -A5DE;VAI SYLLABLE MO;Lo;0;L;;;;;N;;;;; -A5DF;VAI SYLLABLE NO;Lo;0;L;;;;;N;;;;; -A5E0;VAI SYLLABLE NYO;Lo;0;L;;;;;N;;;;; -A5E1;VAI SYLLABLE E;Lo;0;L;;;;;N;;;;; -A5E2;VAI SYLLABLE EN;Lo;0;L;;;;;N;;;;; -A5E3;VAI SYLLABLE NGEN;Lo;0;L;;;;;N;;;;; -A5E4;VAI SYLLABLE HE;Lo;0;L;;;;;N;;;;; -A5E5;VAI SYLLABLE HEN;Lo;0;L;;;;;N;;;;; -A5E6;VAI SYLLABLE WE;Lo;0;L;;;;;N;;;;; -A5E7;VAI SYLLABLE WEN;Lo;0;L;;;;;N;;;;; -A5E8;VAI SYLLABLE PE;Lo;0;L;;;;;N;;;;; -A5E9;VAI SYLLABLE BHE;Lo;0;L;;;;;N;;;;; -A5EA;VAI SYLLABLE BE;Lo;0;L;;;;;N;;;;; -A5EB;VAI SYLLABLE MBE;Lo;0;L;;;;;N;;;;; -A5EC;VAI SYLLABLE KPE;Lo;0;L;;;;;N;;;;; -A5ED;VAI SYLLABLE KPEN;Lo;0;L;;;;;N;;;;; -A5EE;VAI SYLLABLE MGBE;Lo;0;L;;;;;N;;;;; -A5EF;VAI SYLLABLE GBE;Lo;0;L;;;;;N;;;;; -A5F0;VAI SYLLABLE GBEN;Lo;0;L;;;;;N;;;;; -A5F1;VAI SYLLABLE FE;Lo;0;L;;;;;N;;;;; -A5F2;VAI SYLLABLE VE;Lo;0;L;;;;;N;;;;; -A5F3;VAI SYLLABLE TE;Lo;0;L;;;;;N;;;;; -A5F4;VAI SYLLABLE THE;Lo;0;L;;;;;N;;;;; -A5F5;VAI SYLLABLE DHE;Lo;0;L;;;;;N;;;;; -A5F6;VAI SYLLABLE DHHE;Lo;0;L;;;;;N;;;;; -A5F7;VAI SYLLABLE LE;Lo;0;L;;;;;N;;;;; -A5F8;VAI SYLLABLE RE;Lo;0;L;;;;;N;;;;; -A5F9;VAI SYLLABLE DE;Lo;0;L;;;;;N;;;;; -A5FA;VAI SYLLABLE NDE;Lo;0;L;;;;;N;;;;; -A5FB;VAI SYLLABLE SE;Lo;0;L;;;;;N;;;;; -A5FC;VAI SYLLABLE SHE;Lo;0;L;;;;;N;;;;; -A5FD;VAI SYLLABLE ZE;Lo;0;L;;;;;N;;;;; -A5FE;VAI SYLLABLE ZHE;Lo;0;L;;;;;N;;;;; -A5FF;VAI SYLLABLE CE;Lo;0;L;;;;;N;;;;; -A600;VAI SYLLABLE JE;Lo;0;L;;;;;N;;;;; -A601;VAI SYLLABLE NJE;Lo;0;L;;;;;N;;;;; -A602;VAI SYLLABLE YE;Lo;0;L;;;;;N;;;;; -A603;VAI SYLLABLE KE;Lo;0;L;;;;;N;;;;; -A604;VAI SYLLABLE NGGE;Lo;0;L;;;;;N;;;;; -A605;VAI SYLLABLE NGGEN;Lo;0;L;;;;;N;;;;; -A606;VAI SYLLABLE GE;Lo;0;L;;;;;N;;;;; -A607;VAI SYLLABLE GEN;Lo;0;L;;;;;N;;;;; -A608;VAI SYLLABLE ME;Lo;0;L;;;;;N;;;;; -A609;VAI SYLLABLE NE;Lo;0;L;;;;;N;;;;; -A60A;VAI SYLLABLE NYE;Lo;0;L;;;;;N;;;;; -A60B;VAI SYLLABLE NG;Lo;0;L;;;;;N;;;;; -A60C;VAI SYLLABLE LENGTHENER;Lm;0;L;;;;;N;;;;; -A60D;VAI COMMA;Po;0;ON;;;;;N;;;;; -A60E;VAI FULL STOP;Po;0;ON;;;;;N;;;;; -A60F;VAI QUESTION MARK;Po;0;ON;;;;;N;;;;; -A610;VAI SYLLABLE NDOLE FA;Lo;0;L;;;;;N;;;;; -A611;VAI SYLLABLE NDOLE KA;Lo;0;L;;;;;N;;;;; -A612;VAI SYLLABLE NDOLE SOO;Lo;0;L;;;;;N;;;;; -A613;VAI SYMBOL FEENG;Lo;0;L;;;;;N;;;;; -A614;VAI SYMBOL KEENG;Lo;0;L;;;;;N;;;;; -A615;VAI SYMBOL TING;Lo;0;L;;;;;N;;;;; -A616;VAI SYMBOL NII;Lo;0;L;;;;;N;;;;; -A617;VAI SYMBOL BANG;Lo;0;L;;;;;N;;;;; -A618;VAI SYMBOL FAA;Lo;0;L;;;;;N;;;;; -A619;VAI SYMBOL TAA;Lo;0;L;;;;;N;;;;; -A61A;VAI SYMBOL DANG;Lo;0;L;;;;;N;;;;; -A61B;VAI SYMBOL DOONG;Lo;0;L;;;;;N;;;;; -A61C;VAI SYMBOL KUNG;Lo;0;L;;;;;N;;;;; -A61D;VAI SYMBOL TONG;Lo;0;L;;;;;N;;;;; -A61E;VAI SYMBOL DO-O;Lo;0;L;;;;;N;;;;; -A61F;VAI SYMBOL JONG;Lo;0;L;;;;;N;;;;; -A620;VAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -A621;VAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -A622;VAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -A623;VAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -A624;VAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -A625;VAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -A626;VAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -A627;VAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -A628;VAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -A629;VAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -A62A;VAI SYLLABLE NDOLE MA;Lo;0;L;;;;;N;;;;; -A62B;VAI SYLLABLE NDOLE DO;Lo;0;L;;;;;N;;;;; -A640;CYRILLIC CAPITAL LETTER ZEMLYA;Lu;0;L;;;;;N;;;;A641; -A641;CYRILLIC SMALL LETTER ZEMLYA;Ll;0;L;;;;;N;;;A640;;A640 -A642;CYRILLIC CAPITAL LETTER DZELO;Lu;0;L;;;;;N;;;;A643; -A643;CYRILLIC SMALL LETTER DZELO;Ll;0;L;;;;;N;;;A642;;A642 -A644;CYRILLIC CAPITAL LETTER REVERSED DZE;Lu;0;L;;;;;N;;;;A645; -A645;CYRILLIC SMALL LETTER REVERSED DZE;Ll;0;L;;;;;N;;;A644;;A644 -A646;CYRILLIC CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;A647; -A647;CYRILLIC SMALL LETTER IOTA;Ll;0;L;;;;;N;;;A646;;A646 -A648;CYRILLIC CAPITAL LETTER DJERV;Lu;0;L;;;;;N;;;;A649; -A649;CYRILLIC SMALL LETTER DJERV;Ll;0;L;;;;;N;;;A648;;A648 -A64A;CYRILLIC CAPITAL LETTER MONOGRAPH UK;Lu;0;L;;;;;N;;;;A64B; -A64B;CYRILLIC SMALL LETTER MONOGRAPH UK;Ll;0;L;;;;;N;;;A64A;;A64A -A64C;CYRILLIC CAPITAL LETTER BROAD OMEGA;Lu;0;L;;;;;N;;;;A64D; -A64D;CYRILLIC SMALL LETTER BROAD OMEGA;Ll;0;L;;;;;N;;;A64C;;A64C -A64E;CYRILLIC CAPITAL LETTER NEUTRAL YER;Lu;0;L;;;;;N;;;;A64F; -A64F;CYRILLIC SMALL LETTER NEUTRAL YER;Ll;0;L;;;;;N;;;A64E;;A64E -A650;CYRILLIC CAPITAL LETTER YERU WITH BACK YER;Lu;0;L;;;;;N;;;;A651; -A651;CYRILLIC SMALL LETTER YERU WITH BACK YER;Ll;0;L;;;;;N;;;A650;;A650 -A652;CYRILLIC CAPITAL LETTER IOTIFIED YAT;Lu;0;L;;;;;N;;;;A653; -A653;CYRILLIC SMALL LETTER IOTIFIED YAT;Ll;0;L;;;;;N;;;A652;;A652 -A654;CYRILLIC CAPITAL LETTER REVERSED YU;Lu;0;L;;;;;N;;;;A655; -A655;CYRILLIC SMALL LETTER REVERSED YU;Ll;0;L;;;;;N;;;A654;;A654 -A656;CYRILLIC CAPITAL LETTER IOTIFIED A;Lu;0;L;;;;;N;;;;A657; -A657;CYRILLIC SMALL LETTER IOTIFIED A;Ll;0;L;;;;;N;;;A656;;A656 -A658;CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS;Lu;0;L;;;;;N;;;;A659; -A659;CYRILLIC SMALL LETTER CLOSED LITTLE YUS;Ll;0;L;;;;;N;;;A658;;A658 -A65A;CYRILLIC CAPITAL LETTER BLENDED YUS;Lu;0;L;;;;;N;;;;A65B; -A65B;CYRILLIC SMALL LETTER BLENDED YUS;Ll;0;L;;;;;N;;;A65A;;A65A -A65C;CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS;Lu;0;L;;;;;N;;;;A65D; -A65D;CYRILLIC SMALL LETTER IOTIFIED CLOSED LITTLE YUS;Ll;0;L;;;;;N;;;A65C;;A65C -A65E;CYRILLIC CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;A65F; -A65F;CYRILLIC SMALL LETTER YN;Ll;0;L;;;;;N;;;A65E;;A65E -A660;CYRILLIC CAPITAL LETTER REVERSED TSE;Lu;0;L;;;;;N;;;;A661; -A661;CYRILLIC SMALL LETTER REVERSED TSE;Ll;0;L;;;;;N;;;A660;;A660 -A662;CYRILLIC CAPITAL LETTER SOFT DE;Lu;0;L;;;;;N;;;;A663; -A663;CYRILLIC SMALL LETTER SOFT DE;Ll;0;L;;;;;N;;;A662;;A662 -A664;CYRILLIC CAPITAL LETTER SOFT EL;Lu;0;L;;;;;N;;;;A665; -A665;CYRILLIC SMALL LETTER SOFT EL;Ll;0;L;;;;;N;;;A664;;A664 -A666;CYRILLIC CAPITAL LETTER SOFT EM;Lu;0;L;;;;;N;;;;A667; -A667;CYRILLIC SMALL LETTER SOFT EM;Ll;0;L;;;;;N;;;A666;;A666 -A668;CYRILLIC CAPITAL LETTER MONOCULAR O;Lu;0;L;;;;;N;;;;A669; -A669;CYRILLIC SMALL LETTER MONOCULAR O;Ll;0;L;;;;;N;;;A668;;A668 -A66A;CYRILLIC CAPITAL LETTER BINOCULAR O;Lu;0;L;;;;;N;;;;A66B; -A66B;CYRILLIC SMALL LETTER BINOCULAR O;Ll;0;L;;;;;N;;;A66A;;A66A -A66C;CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O;Lu;0;L;;;;;N;;;;A66D; -A66D;CYRILLIC SMALL LETTER DOUBLE MONOCULAR O;Ll;0;L;;;;;N;;;A66C;;A66C -A66E;CYRILLIC LETTER MULTIOCULAR O;Lo;0;L;;;;;N;;;;; -A66F;COMBINING CYRILLIC VZMET;Mn;230;NSM;;;;;N;;;;; -A670;COMBINING CYRILLIC TEN MILLIONS SIGN;Me;0;NSM;;;;;N;;;;; -A671;COMBINING CYRILLIC HUNDRED MILLIONS SIGN;Me;0;NSM;;;;;N;;;;; -A672;COMBINING CYRILLIC THOUSAND MILLIONS SIGN;Me;0;NSM;;;;;N;;;;; -A673;SLAVONIC ASTERISK;Po;0;ON;;;;;N;;;;; -A674;COMBINING CYRILLIC LETTER UKRAINIAN IE;Mn;230;NSM;;;;;N;;;;; -A675;COMBINING CYRILLIC LETTER I;Mn;230;NSM;;;;;N;;;;; -A676;COMBINING CYRILLIC LETTER YI;Mn;230;NSM;;;;;N;;;;; -A677;COMBINING CYRILLIC LETTER U;Mn;230;NSM;;;;;N;;;;; -A678;COMBINING CYRILLIC LETTER HARD SIGN;Mn;230;NSM;;;;;N;;;;; -A679;COMBINING CYRILLIC LETTER YERU;Mn;230;NSM;;;;;N;;;;; -A67A;COMBINING CYRILLIC LETTER SOFT SIGN;Mn;230;NSM;;;;;N;;;;; -A67B;COMBINING CYRILLIC LETTER OMEGA;Mn;230;NSM;;;;;N;;;;; -A67C;COMBINING CYRILLIC KAVYKA;Mn;230;NSM;;;;;N;;;;; -A67D;COMBINING CYRILLIC PAYEROK;Mn;230;NSM;;;;;N;;;;; -A67E;CYRILLIC KAVYKA;Po;0;ON;;;;;N;;;;; -A67F;CYRILLIC PAYEROK;Lm;0;ON;;;;;N;;;;; -A680;CYRILLIC CAPITAL LETTER DWE;Lu;0;L;;;;;N;;;;A681; -A681;CYRILLIC SMALL LETTER DWE;Ll;0;L;;;;;N;;;A680;;A680 -A682;CYRILLIC CAPITAL LETTER DZWE;Lu;0;L;;;;;N;;;;A683; -A683;CYRILLIC SMALL LETTER DZWE;Ll;0;L;;;;;N;;;A682;;A682 -A684;CYRILLIC CAPITAL LETTER ZHWE;Lu;0;L;;;;;N;;;;A685; -A685;CYRILLIC SMALL LETTER ZHWE;Ll;0;L;;;;;N;;;A684;;A684 -A686;CYRILLIC CAPITAL LETTER CCHE;Lu;0;L;;;;;N;;;;A687; -A687;CYRILLIC SMALL LETTER CCHE;Ll;0;L;;;;;N;;;A686;;A686 -A688;CYRILLIC CAPITAL LETTER DZZE;Lu;0;L;;;;;N;;;;A689; -A689;CYRILLIC SMALL LETTER DZZE;Ll;0;L;;;;;N;;;A688;;A688 -A68A;CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK;Lu;0;L;;;;;N;;;;A68B; -A68B;CYRILLIC SMALL LETTER TE WITH MIDDLE HOOK;Ll;0;L;;;;;N;;;A68A;;A68A -A68C;CYRILLIC CAPITAL LETTER TWE;Lu;0;L;;;;;N;;;;A68D; -A68D;CYRILLIC SMALL LETTER TWE;Ll;0;L;;;;;N;;;A68C;;A68C -A68E;CYRILLIC CAPITAL LETTER TSWE;Lu;0;L;;;;;N;;;;A68F; -A68F;CYRILLIC SMALL LETTER TSWE;Ll;0;L;;;;;N;;;A68E;;A68E -A690;CYRILLIC CAPITAL LETTER TSSE;Lu;0;L;;;;;N;;;;A691; -A691;CYRILLIC SMALL LETTER TSSE;Ll;0;L;;;;;N;;;A690;;A690 -A692;CYRILLIC CAPITAL LETTER TCHE;Lu;0;L;;;;;N;;;;A693; -A693;CYRILLIC SMALL LETTER TCHE;Ll;0;L;;;;;N;;;A692;;A692 -A694;CYRILLIC CAPITAL LETTER HWE;Lu;0;L;;;;;N;;;;A695; -A695;CYRILLIC SMALL LETTER HWE;Ll;0;L;;;;;N;;;A694;;A694 -A696;CYRILLIC CAPITAL LETTER SHWE;Lu;0;L;;;;;N;;;;A697; -A697;CYRILLIC SMALL LETTER SHWE;Ll;0;L;;;;;N;;;A696;;A696 -A698;CYRILLIC CAPITAL LETTER DOUBLE O;Lu;0;L;;;;;N;;;;A699; -A699;CYRILLIC SMALL LETTER DOUBLE O;Ll;0;L;;;;;N;;;A698;;A698 -A69A;CYRILLIC CAPITAL LETTER CROSSED O;Lu;0;L;;;;;N;;;;A69B; -A69B;CYRILLIC SMALL LETTER CROSSED O;Ll;0;L;;;;;N;;;A69A;;A69A -A69C;MODIFIER LETTER CYRILLIC HARD SIGN;Lm;0;L;<super> 044A;;;;N;;;;; -A69D;MODIFIER LETTER CYRILLIC SOFT SIGN;Lm;0;L;<super> 044C;;;;N;;;;; -A69E;COMBINING CYRILLIC LETTER EF;Mn;230;NSM;;;;;N;;;;; -A69F;COMBINING CYRILLIC LETTER IOTIFIED E;Mn;230;NSM;;;;;N;;;;; -A6A0;BAMUM LETTER A;Lo;0;L;;;;;N;;;;; -A6A1;BAMUM LETTER KA;Lo;0;L;;;;;N;;;;; -A6A2;BAMUM LETTER U;Lo;0;L;;;;;N;;;;; -A6A3;BAMUM LETTER KU;Lo;0;L;;;;;N;;;;; -A6A4;BAMUM LETTER EE;Lo;0;L;;;;;N;;;;; -A6A5;BAMUM LETTER REE;Lo;0;L;;;;;N;;;;; -A6A6;BAMUM LETTER TAE;Lo;0;L;;;;;N;;;;; -A6A7;BAMUM LETTER O;Lo;0;L;;;;;N;;;;; -A6A8;BAMUM LETTER NYI;Lo;0;L;;;;;N;;;;; -A6A9;BAMUM LETTER I;Lo;0;L;;;;;N;;;;; -A6AA;BAMUM LETTER LA;Lo;0;L;;;;;N;;;;; -A6AB;BAMUM LETTER PA;Lo;0;L;;;;;N;;;;; -A6AC;BAMUM LETTER RII;Lo;0;L;;;;;N;;;;; -A6AD;BAMUM LETTER RIEE;Lo;0;L;;;;;N;;;;; -A6AE;BAMUM LETTER LEEEE;Lo;0;L;;;;;N;;;;; -A6AF;BAMUM LETTER MEEEE;Lo;0;L;;;;;N;;;;; -A6B0;BAMUM LETTER TAA;Lo;0;L;;;;;N;;;;; -A6B1;BAMUM LETTER NDAA;Lo;0;L;;;;;N;;;;; -A6B2;BAMUM LETTER NJAEM;Lo;0;L;;;;;N;;;;; -A6B3;BAMUM LETTER M;Lo;0;L;;;;;N;;;;; -A6B4;BAMUM LETTER SUU;Lo;0;L;;;;;N;;;;; -A6B5;BAMUM LETTER MU;Lo;0;L;;;;;N;;;;; -A6B6;BAMUM LETTER SHII;Lo;0;L;;;;;N;;;;; -A6B7;BAMUM LETTER SI;Lo;0;L;;;;;N;;;;; -A6B8;BAMUM LETTER SHEUX;Lo;0;L;;;;;N;;;;; -A6B9;BAMUM LETTER SEUX;Lo;0;L;;;;;N;;;;; -A6BA;BAMUM LETTER KYEE;Lo;0;L;;;;;N;;;;; -A6BB;BAMUM LETTER KET;Lo;0;L;;;;;N;;;;; -A6BC;BAMUM LETTER NUAE;Lo;0;L;;;;;N;;;;; -A6BD;BAMUM LETTER NU;Lo;0;L;;;;;N;;;;; -A6BE;BAMUM LETTER NJUAE;Lo;0;L;;;;;N;;;;; -A6BF;BAMUM LETTER YOQ;Lo;0;L;;;;;N;;;;; -A6C0;BAMUM LETTER SHU;Lo;0;L;;;;;N;;;;; -A6C1;BAMUM LETTER YUQ;Lo;0;L;;;;;N;;;;; -A6C2;BAMUM LETTER YA;Lo;0;L;;;;;N;;;;; -A6C3;BAMUM LETTER NSHA;Lo;0;L;;;;;N;;;;; -A6C4;BAMUM LETTER KEUX;Lo;0;L;;;;;N;;;;; -A6C5;BAMUM LETTER PEUX;Lo;0;L;;;;;N;;;;; -A6C6;BAMUM LETTER NJEE;Lo;0;L;;;;;N;;;;; -A6C7;BAMUM LETTER NTEE;Lo;0;L;;;;;N;;;;; -A6C8;BAMUM LETTER PUE;Lo;0;L;;;;;N;;;;; -A6C9;BAMUM LETTER WUE;Lo;0;L;;;;;N;;;;; -A6CA;BAMUM LETTER PEE;Lo;0;L;;;;;N;;;;; -A6CB;BAMUM LETTER FEE;Lo;0;L;;;;;N;;;;; -A6CC;BAMUM LETTER RU;Lo;0;L;;;;;N;;;;; -A6CD;BAMUM LETTER LU;Lo;0;L;;;;;N;;;;; -A6CE;BAMUM LETTER MI;Lo;0;L;;;;;N;;;;; -A6CF;BAMUM LETTER NI;Lo;0;L;;;;;N;;;;; -A6D0;BAMUM LETTER REUX;Lo;0;L;;;;;N;;;;; -A6D1;BAMUM LETTER RAE;Lo;0;L;;;;;N;;;;; -A6D2;BAMUM LETTER KEN;Lo;0;L;;;;;N;;;;; -A6D3;BAMUM LETTER NGKWAEN;Lo;0;L;;;;;N;;;;; -A6D4;BAMUM LETTER NGGA;Lo;0;L;;;;;N;;;;; -A6D5;BAMUM LETTER NGA;Lo;0;L;;;;;N;;;;; -A6D6;BAMUM LETTER SHO;Lo;0;L;;;;;N;;;;; -A6D7;BAMUM LETTER PUAE;Lo;0;L;;;;;N;;;;; -A6D8;BAMUM LETTER FU;Lo;0;L;;;;;N;;;;; -A6D9;BAMUM LETTER FOM;Lo;0;L;;;;;N;;;;; -A6DA;BAMUM LETTER WA;Lo;0;L;;;;;N;;;;; -A6DB;BAMUM LETTER NA;Lo;0;L;;;;;N;;;;; -A6DC;BAMUM LETTER LI;Lo;0;L;;;;;N;;;;; -A6DD;BAMUM LETTER PI;Lo;0;L;;;;;N;;;;; -A6DE;BAMUM LETTER LOQ;Lo;0;L;;;;;N;;;;; -A6DF;BAMUM LETTER KO;Lo;0;L;;;;;N;;;;; -A6E0;BAMUM LETTER MBEN;Lo;0;L;;;;;N;;;;; -A6E1;BAMUM LETTER REN;Lo;0;L;;;;;N;;;;; -A6E2;BAMUM LETTER MEN;Lo;0;L;;;;;N;;;;; -A6E3;BAMUM LETTER MA;Lo;0;L;;;;;N;;;;; -A6E4;BAMUM LETTER TI;Lo;0;L;;;;;N;;;;; -A6E5;BAMUM LETTER KI;Lo;0;L;;;;;N;;;;; -A6E6;BAMUM LETTER MO;Nl;0;L;;;;1;N;;;;; -A6E7;BAMUM LETTER MBAA;Nl;0;L;;;;2;N;;;;; -A6E8;BAMUM LETTER TET;Nl;0;L;;;;3;N;;;;; -A6E9;BAMUM LETTER KPA;Nl;0;L;;;;4;N;;;;; -A6EA;BAMUM LETTER TEN;Nl;0;L;;;;5;N;;;;; -A6EB;BAMUM LETTER NTUU;Nl;0;L;;;;6;N;;;;; -A6EC;BAMUM LETTER SAMBA;Nl;0;L;;;;7;N;;;;; -A6ED;BAMUM LETTER FAAMAE;Nl;0;L;;;;8;N;;;;; -A6EE;BAMUM LETTER KOVUU;Nl;0;L;;;;9;N;;;;; -A6EF;BAMUM LETTER KOGHOM;Nl;0;L;;;;0;N;;;;; -A6F0;BAMUM COMBINING MARK KOQNDON;Mn;230;NSM;;;;;N;;;;; -A6F1;BAMUM COMBINING MARK TUKWENTIS;Mn;230;NSM;;;;;N;;;;; -A6F2;BAMUM NJAEMLI;Po;0;L;;;;;N;;;;; -A6F3;BAMUM FULL STOP;Po;0;L;;;;;N;;;;; -A6F4;BAMUM COLON;Po;0;L;;;;;N;;;;; -A6F5;BAMUM COMMA;Po;0;L;;;;;N;;;;; -A6F6;BAMUM SEMICOLON;Po;0;L;;;;;N;;;;; -A6F7;BAMUM QUESTION MARK;Po;0;L;;;;;N;;;;; -A700;MODIFIER LETTER CHINESE TONE YIN PING;Sk;0;ON;;;;;N;;;;; -A701;MODIFIER LETTER CHINESE TONE YANG PING;Sk;0;ON;;;;;N;;;;; -A702;MODIFIER LETTER CHINESE TONE YIN SHANG;Sk;0;ON;;;;;N;;;;; -A703;MODIFIER LETTER CHINESE TONE YANG SHANG;Sk;0;ON;;;;;N;;;;; -A704;MODIFIER LETTER CHINESE TONE YIN QU;Sk;0;ON;;;;;N;;;;; -A705;MODIFIER LETTER CHINESE TONE YANG QU;Sk;0;ON;;;;;N;;;;; -A706;MODIFIER LETTER CHINESE TONE YIN RU;Sk;0;ON;;;;;N;;;;; -A707;MODIFIER LETTER CHINESE TONE YANG RU;Sk;0;ON;;;;;N;;;;; -A708;MODIFIER LETTER EXTRA-HIGH DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;; -A709;MODIFIER LETTER HIGH DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;; -A70A;MODIFIER LETTER MID DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;; -A70B;MODIFIER LETTER LOW DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;; -A70C;MODIFIER LETTER EXTRA-LOW DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;; -A70D;MODIFIER LETTER EXTRA-HIGH DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; -A70E;MODIFIER LETTER HIGH DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; -A70F;MODIFIER LETTER MID DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; -A710;MODIFIER LETTER LOW DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; -A711;MODIFIER LETTER EXTRA-LOW DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; -A712;MODIFIER LETTER EXTRA-HIGH LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; -A713;MODIFIER LETTER HIGH LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; -A714;MODIFIER LETTER MID LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; -A715;MODIFIER LETTER LOW LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; -A716;MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;; -A717;MODIFIER LETTER DOT VERTICAL BAR;Lm;0;ON;;;;;N;;;;; -A718;MODIFIER LETTER DOT SLASH;Lm;0;ON;;;;;N;;;;; -A719;MODIFIER LETTER DOT HORIZONTAL BAR;Lm;0;ON;;;;;N;;;;; -A71A;MODIFIER LETTER LOWER RIGHT CORNER ANGLE;Lm;0;ON;;;;;N;;;;; -A71B;MODIFIER LETTER RAISED UP ARROW;Lm;0;ON;;;;;N;;;;; -A71C;MODIFIER LETTER RAISED DOWN ARROW;Lm;0;ON;;;;;N;;;;; -A71D;MODIFIER LETTER RAISED EXCLAMATION MARK;Lm;0;ON;;;;;N;;;;; -A71E;MODIFIER LETTER RAISED INVERTED EXCLAMATION MARK;Lm;0;ON;;;;;N;;;;; -A71F;MODIFIER LETTER LOW INVERTED EXCLAMATION MARK;Lm;0;ON;;;;;N;;;;; -A720;MODIFIER LETTER STRESS AND HIGH TONE;Sk;0;ON;;;;;N;;;;; -A721;MODIFIER LETTER STRESS AND LOW TONE;Sk;0;ON;;;;;N;;;;; -A722;LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF;Lu;0;L;;;;;N;;;;A723; -A723;LATIN SMALL LETTER EGYPTOLOGICAL ALEF;Ll;0;L;;;;;N;;;A722;;A722 -A724;LATIN CAPITAL LETTER EGYPTOLOGICAL AIN;Lu;0;L;;;;;N;;;;A725; -A725;LATIN SMALL LETTER EGYPTOLOGICAL AIN;Ll;0;L;;;;;N;;;A724;;A724 -A726;LATIN CAPITAL LETTER HENG;Lu;0;L;;;;;N;;;;A727; -A727;LATIN SMALL LETTER HENG;Ll;0;L;;;;;N;;;A726;;A726 -A728;LATIN CAPITAL LETTER TZ;Lu;0;L;;;;;N;;;;A729; -A729;LATIN SMALL LETTER TZ;Ll;0;L;;;;;N;;;A728;;A728 -A72A;LATIN CAPITAL LETTER TRESILLO;Lu;0;L;;;;;N;;;;A72B; -A72B;LATIN SMALL LETTER TRESILLO;Ll;0;L;;;;;N;;;A72A;;A72A -A72C;LATIN CAPITAL LETTER CUATRILLO;Lu;0;L;;;;;N;;;;A72D; -A72D;LATIN SMALL LETTER CUATRILLO;Ll;0;L;;;;;N;;;A72C;;A72C -A72E;LATIN CAPITAL LETTER CUATRILLO WITH COMMA;Lu;0;L;;;;;N;;;;A72F; -A72F;LATIN SMALL LETTER CUATRILLO WITH COMMA;Ll;0;L;;;;;N;;;A72E;;A72E -A730;LATIN LETTER SMALL CAPITAL F;Ll;0;L;;;;;N;;;;; -A731;LATIN LETTER SMALL CAPITAL S;Ll;0;L;;;;;N;;;;; -A732;LATIN CAPITAL LETTER AA;Lu;0;L;;;;;N;;;;A733; -A733;LATIN SMALL LETTER AA;Ll;0;L;;;;;N;;;A732;;A732 -A734;LATIN CAPITAL LETTER AO;Lu;0;L;;;;;N;;;;A735; -A735;LATIN SMALL LETTER AO;Ll;0;L;;;;;N;;;A734;;A734 -A736;LATIN CAPITAL LETTER AU;Lu;0;L;;;;;N;;;;A737; -A737;LATIN SMALL LETTER AU;Ll;0;L;;;;;N;;;A736;;A736 -A738;LATIN CAPITAL LETTER AV;Lu;0;L;;;;;N;;;;A739; -A739;LATIN SMALL LETTER AV;Ll;0;L;;;;;N;;;A738;;A738 -A73A;LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR;Lu;0;L;;;;;N;;;;A73B; -A73B;LATIN SMALL LETTER AV WITH HORIZONTAL BAR;Ll;0;L;;;;;N;;;A73A;;A73A -A73C;LATIN CAPITAL LETTER AY;Lu;0;L;;;;;N;;;;A73D; -A73D;LATIN SMALL LETTER AY;Ll;0;L;;;;;N;;;A73C;;A73C -A73E;LATIN CAPITAL LETTER REVERSED C WITH DOT;Lu;0;L;;;;;N;;;;A73F; -A73F;LATIN SMALL LETTER REVERSED C WITH DOT;Ll;0;L;;;;;N;;;A73E;;A73E -A740;LATIN CAPITAL LETTER K WITH STROKE;Lu;0;L;;;;;N;;;;A741; -A741;LATIN SMALL LETTER K WITH STROKE;Ll;0;L;;;;;N;;;A740;;A740 -A742;LATIN CAPITAL LETTER K WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A743; -A743;LATIN SMALL LETTER K WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;A742;;A742 -A744;LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A745; -A745;LATIN SMALL LETTER K WITH STROKE AND DIAGONAL STROKE;Ll;0;L;;;;;N;;;A744;;A744 -A746;LATIN CAPITAL LETTER BROKEN L;Lu;0;L;;;;;N;;;;A747; -A747;LATIN SMALL LETTER BROKEN L;Ll;0;L;;;;;N;;;A746;;A746 -A748;LATIN CAPITAL LETTER L WITH HIGH STROKE;Lu;0;L;;;;;N;;;;A749; -A749;LATIN SMALL LETTER L WITH HIGH STROKE;Ll;0;L;;;;;N;;;A748;;A748 -A74A;LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY;Lu;0;L;;;;;N;;;;A74B; -A74B;LATIN SMALL LETTER O WITH LONG STROKE OVERLAY;Ll;0;L;;;;;N;;;A74A;;A74A -A74C;LATIN CAPITAL LETTER O WITH LOOP;Lu;0;L;;;;;N;;;;A74D; -A74D;LATIN SMALL LETTER O WITH LOOP;Ll;0;L;;;;;N;;;A74C;;A74C -A74E;LATIN CAPITAL LETTER OO;Lu;0;L;;;;;N;;;;A74F; -A74F;LATIN SMALL LETTER OO;Ll;0;L;;;;;N;;;A74E;;A74E -A750;LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER;Lu;0;L;;;;;N;;;;A751; -A751;LATIN SMALL LETTER P WITH STROKE THROUGH DESCENDER;Ll;0;L;;;;;N;;;A750;;A750 -A752;LATIN CAPITAL LETTER P WITH FLOURISH;Lu;0;L;;;;;N;;;;A753; -A753;LATIN SMALL LETTER P WITH FLOURISH;Ll;0;L;;;;;N;;;A752;;A752 -A754;LATIN CAPITAL LETTER P WITH SQUIRREL TAIL;Lu;0;L;;;;;N;;;;A755; -A755;LATIN SMALL LETTER P WITH SQUIRREL TAIL;Ll;0;L;;;;;N;;;A754;;A754 -A756;LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER;Lu;0;L;;;;;N;;;;A757; -A757;LATIN SMALL LETTER Q WITH STROKE THROUGH DESCENDER;Ll;0;L;;;;;N;;;A756;;A756 -A758;LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A759; -A759;LATIN SMALL LETTER Q WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;A758;;A758 -A75A;LATIN CAPITAL LETTER R ROTUNDA;Lu;0;L;;;;;N;;;;A75B; -A75B;LATIN SMALL LETTER R ROTUNDA;Ll;0;L;;;;;N;;;A75A;;A75A -A75C;LATIN CAPITAL LETTER RUM ROTUNDA;Lu;0;L;;;;;N;;;;A75D; -A75D;LATIN SMALL LETTER RUM ROTUNDA;Ll;0;L;;;;;N;;;A75C;;A75C -A75E;LATIN CAPITAL LETTER V WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A75F; -A75F;LATIN SMALL LETTER V WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;A75E;;A75E -A760;LATIN CAPITAL LETTER VY;Lu;0;L;;;;;N;;;;A761; -A761;LATIN SMALL LETTER VY;Ll;0;L;;;;;N;;;A760;;A760 -A762;LATIN CAPITAL LETTER VISIGOTHIC Z;Lu;0;L;;;;;N;;;;A763; -A763;LATIN SMALL LETTER VISIGOTHIC Z;Ll;0;L;;;;;N;;;A762;;A762 -A764;LATIN CAPITAL LETTER THORN WITH STROKE;Lu;0;L;;;;;N;;;;A765; -A765;LATIN SMALL LETTER THORN WITH STROKE;Ll;0;L;;;;;N;;;A764;;A764 -A766;LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER;Lu;0;L;;;;;N;;;;A767; -A767;LATIN SMALL LETTER THORN WITH STROKE THROUGH DESCENDER;Ll;0;L;;;;;N;;;A766;;A766 -A768;LATIN CAPITAL LETTER VEND;Lu;0;L;;;;;N;;;;A769; -A769;LATIN SMALL LETTER VEND;Ll;0;L;;;;;N;;;A768;;A768 -A76A;LATIN CAPITAL LETTER ET;Lu;0;L;;;;;N;;;;A76B; -A76B;LATIN SMALL LETTER ET;Ll;0;L;;;;;N;;;A76A;;A76A -A76C;LATIN CAPITAL LETTER IS;Lu;0;L;;;;;N;;;;A76D; -A76D;LATIN SMALL LETTER IS;Ll;0;L;;;;;N;;;A76C;;A76C -A76E;LATIN CAPITAL LETTER CON;Lu;0;L;;;;;N;;;;A76F; -A76F;LATIN SMALL LETTER CON;Ll;0;L;;;;;N;;;A76E;;A76E -A770;MODIFIER LETTER US;Lm;0;L;<super> A76F;;;;N;;;;; -A771;LATIN SMALL LETTER DUM;Ll;0;L;;;;;N;;;;; -A772;LATIN SMALL LETTER LUM;Ll;0;L;;;;;N;;;;; -A773;LATIN SMALL LETTER MUM;Ll;0;L;;;;;N;;;;; -A774;LATIN SMALL LETTER NUM;Ll;0;L;;;;;N;;;;; -A775;LATIN SMALL LETTER RUM;Ll;0;L;;;;;N;;;;; -A776;LATIN LETTER SMALL CAPITAL RUM;Ll;0;L;;;;;N;;;;; -A777;LATIN SMALL LETTER TUM;Ll;0;L;;;;;N;;;;; -A778;LATIN SMALL LETTER UM;Ll;0;L;;;;;N;;;;; -A779;LATIN CAPITAL LETTER INSULAR D;Lu;0;L;;;;;N;;;;A77A; -A77A;LATIN SMALL LETTER INSULAR D;Ll;0;L;;;;;N;;;A779;;A779 -A77B;LATIN CAPITAL LETTER INSULAR F;Lu;0;L;;;;;N;;;;A77C; -A77C;LATIN SMALL LETTER INSULAR F;Ll;0;L;;;;;N;;;A77B;;A77B -A77D;LATIN CAPITAL LETTER INSULAR G;Lu;0;L;;;;;N;;;;1D79; -A77E;LATIN CAPITAL LETTER TURNED INSULAR G;Lu;0;L;;;;;N;;;;A77F; -A77F;LATIN SMALL LETTER TURNED INSULAR G;Ll;0;L;;;;;N;;;A77E;;A77E -A780;LATIN CAPITAL LETTER TURNED L;Lu;0;L;;;;;N;;;;A781; -A781;LATIN SMALL LETTER TURNED L;Ll;0;L;;;;;N;;;A780;;A780 -A782;LATIN CAPITAL LETTER INSULAR R;Lu;0;L;;;;;N;;;;A783; -A783;LATIN SMALL LETTER INSULAR R;Ll;0;L;;;;;N;;;A782;;A782 -A784;LATIN CAPITAL LETTER INSULAR S;Lu;0;L;;;;;N;;;;A785; -A785;LATIN SMALL LETTER INSULAR S;Ll;0;L;;;;;N;;;A784;;A784 -A786;LATIN CAPITAL LETTER INSULAR T;Lu;0;L;;;;;N;;;;A787; -A787;LATIN SMALL LETTER INSULAR T;Ll;0;L;;;;;N;;;A786;;A786 -A788;MODIFIER LETTER LOW CIRCUMFLEX ACCENT;Lm;0;ON;;;;;N;;;;; -A789;MODIFIER LETTER COLON;Sk;0;L;;;;;N;;;;; -A78A;MODIFIER LETTER SHORT EQUALS SIGN;Sk;0;L;;;;;N;;;;; -A78B;LATIN CAPITAL LETTER SALTILLO;Lu;0;L;;;;;N;;;;A78C; -A78C;LATIN SMALL LETTER SALTILLO;Ll;0;L;;;;;N;;;A78B;;A78B -A78D;LATIN CAPITAL LETTER TURNED H;Lu;0;L;;;;;N;;;;0265; -A78E;LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT;Ll;0;L;;;;;N;;;;; -A78F;LATIN LETTER SINOLOGICAL DOT;Lo;0;L;;;;;N;;;;; -A790;LATIN CAPITAL LETTER N WITH DESCENDER;Lu;0;L;;;;;N;;;;A791; -A791;LATIN SMALL LETTER N WITH DESCENDER;Ll;0;L;;;;;N;;;A790;;A790 -A792;LATIN CAPITAL LETTER C WITH BAR;Lu;0;L;;;;;N;;;;A793; -A793;LATIN SMALL LETTER C WITH BAR;Ll;0;L;;;;;N;;;A792;;A792 -A794;LATIN SMALL LETTER C WITH PALATAL HOOK;Ll;0;L;;;;;N;;;A7C4;;A7C4 -A795;LATIN SMALL LETTER H WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -A796;LATIN CAPITAL LETTER B WITH FLOURISH;Lu;0;L;;;;;N;;;;A797; -A797;LATIN SMALL LETTER B WITH FLOURISH;Ll;0;L;;;;;N;;;A796;;A796 -A798;LATIN CAPITAL LETTER F WITH STROKE;Lu;0;L;;;;;N;;;;A799; -A799;LATIN SMALL LETTER F WITH STROKE;Ll;0;L;;;;;N;;;A798;;A798 -A79A;LATIN CAPITAL LETTER VOLAPUK AE;Lu;0;L;;;;;N;;;;A79B; -A79B;LATIN SMALL LETTER VOLAPUK AE;Ll;0;L;;;;;N;;;A79A;;A79A -A79C;LATIN CAPITAL LETTER VOLAPUK OE;Lu;0;L;;;;;N;;;;A79D; -A79D;LATIN SMALL LETTER VOLAPUK OE;Ll;0;L;;;;;N;;;A79C;;A79C -A79E;LATIN CAPITAL LETTER VOLAPUK UE;Lu;0;L;;;;;N;;;;A79F; -A79F;LATIN SMALL LETTER VOLAPUK UE;Ll;0;L;;;;;N;;;A79E;;A79E -A7A0;LATIN CAPITAL LETTER G WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A1; -A7A1;LATIN SMALL LETTER G WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A0;;A7A0 -A7A2;LATIN CAPITAL LETTER K WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A3; -A7A3;LATIN SMALL LETTER K WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A2;;A7A2 -A7A4;LATIN CAPITAL LETTER N WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A5; -A7A5;LATIN SMALL LETTER N WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A4;;A7A4 -A7A6;LATIN CAPITAL LETTER R WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A7; -A7A7;LATIN SMALL LETTER R WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A6;;A7A6 -A7A8;LATIN CAPITAL LETTER S WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A9; -A7A9;LATIN SMALL LETTER S WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A8;;A7A8 -A7AA;LATIN CAPITAL LETTER H WITH HOOK;Lu;0;L;;;;;N;;;;0266; -A7AB;LATIN CAPITAL LETTER REVERSED OPEN E;Lu;0;L;;;;;N;;;;025C; -A7AC;LATIN CAPITAL LETTER SCRIPT G;Lu;0;L;;;;;N;;;;0261; -A7AD;LATIN CAPITAL LETTER L WITH BELT;Lu;0;L;;;;;N;;;;026C; -A7AE;LATIN CAPITAL LETTER SMALL CAPITAL I;Lu;0;L;;;;;N;;;;026A; -A7AF;LATIN LETTER SMALL CAPITAL Q;Ll;0;L;;;;;N;;;;; -A7B0;LATIN CAPITAL LETTER TURNED K;Lu;0;L;;;;;N;;;;029E; -A7B1;LATIN CAPITAL LETTER TURNED T;Lu;0;L;;;;;N;;;;0287; -A7B2;LATIN CAPITAL LETTER J WITH CROSSED-TAIL;Lu;0;L;;;;;N;;;;029D; -A7B3;LATIN CAPITAL LETTER CHI;Lu;0;L;;;;;N;;;;AB53; -A7B4;LATIN CAPITAL LETTER BETA;Lu;0;L;;;;;N;;;;A7B5; -A7B5;LATIN SMALL LETTER BETA;Ll;0;L;;;;;N;;;A7B4;;A7B4 -A7B6;LATIN CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;A7B7; -A7B7;LATIN SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;A7B6;;A7B6 -A7B8;LATIN CAPITAL LETTER U WITH STROKE;Lu;0;L;;;;;N;;;;A7B9; -A7B9;LATIN SMALL LETTER U WITH STROKE;Ll;0;L;;;;;N;;;A7B8;;A7B8 -A7BA;LATIN CAPITAL LETTER GLOTTAL A;Lu;0;L;;;;;N;;;;A7BB; -A7BB;LATIN SMALL LETTER GLOTTAL A;Ll;0;L;;;;;N;;;A7BA;;A7BA -A7BC;LATIN CAPITAL LETTER GLOTTAL I;Lu;0;L;;;;;N;;;;A7BD; -A7BD;LATIN SMALL LETTER GLOTTAL I;Ll;0;L;;;;;N;;;A7BC;;A7BC -A7BE;LATIN CAPITAL LETTER GLOTTAL U;Lu;0;L;;;;;N;;;;A7BF; -A7BF;LATIN SMALL LETTER GLOTTAL U;Ll;0;L;;;;;N;;;A7BE;;A7BE -A7C0;LATIN CAPITAL LETTER OLD POLISH O;Lu;0;L;;;;;N;;;;A7C1; -A7C1;LATIN SMALL LETTER OLD POLISH O;Ll;0;L;;;;;N;;;A7C0;;A7C0 -A7C2;LATIN CAPITAL LETTER ANGLICANA W;Lu;0;L;;;;;N;;;;A7C3; -A7C3;LATIN SMALL LETTER ANGLICANA W;Ll;0;L;;;;;N;;;A7C2;;A7C2 -A7C4;LATIN CAPITAL LETTER C WITH PALATAL HOOK;Lu;0;L;;;;;N;;;;A794; -A7C5;LATIN CAPITAL LETTER S WITH HOOK;Lu;0;L;;;;;N;;;;0282; -A7C6;LATIN CAPITAL LETTER Z WITH PALATAL HOOK;Lu;0;L;;;;;N;;;;1D8E; -A7C7;LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY;Lu;0;L;;;;;N;;;;A7C8; -A7C8;LATIN SMALL LETTER D WITH SHORT STROKE OVERLAY;Ll;0;L;;;;;N;;;A7C7;;A7C7 -A7C9;LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY;Lu;0;L;;;;;N;;;;A7CA; -A7CA;LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY;Ll;0;L;;;;;N;;;A7C9;;A7C9 -A7D0;LATIN CAPITAL LETTER CLOSED INSULAR G;Lu;0;L;;;;;N;;;;A7D1; -A7D1;LATIN SMALL LETTER CLOSED INSULAR G;Ll;0;L;;;;;N;;;A7D0;;A7D0 -A7D3;LATIN SMALL LETTER DOUBLE THORN;Ll;0;L;;;;;N;;;;; -A7D5;LATIN SMALL LETTER DOUBLE WYNN;Ll;0;L;;;;;N;;;;; -A7D6;LATIN CAPITAL LETTER MIDDLE SCOTS S;Lu;0;L;;;;;N;;;;A7D7; -A7D7;LATIN SMALL LETTER MIDDLE SCOTS S;Ll;0;L;;;;;N;;;A7D6;;A7D6 -A7D8;LATIN CAPITAL LETTER SIGMOID S;Lu;0;L;;;;;N;;;;A7D9; -A7D9;LATIN SMALL LETTER SIGMOID S;Ll;0;L;;;;;N;;;A7D8;;A7D8 -A7F2;MODIFIER LETTER CAPITAL C;Lm;0;L;<super> 0043;;;;N;;;;; -A7F3;MODIFIER LETTER CAPITAL F;Lm;0;L;<super> 0046;;;;N;;;;; -A7F4;MODIFIER LETTER CAPITAL Q;Lm;0;L;<super> 0051;;;;N;;;;; -A7F5;LATIN CAPITAL LETTER REVERSED HALF H;Lu;0;L;;;;;N;;;;A7F6; -A7F6;LATIN SMALL LETTER REVERSED HALF H;Ll;0;L;;;;;N;;;A7F5;;A7F5 -A7F7;LATIN EPIGRAPHIC LETTER SIDEWAYS I;Lo;0;L;;;;;N;;;;; -A7F8;MODIFIER LETTER CAPITAL H WITH STROKE;Lm;0;L;<super> 0126;;;;N;;;;; -A7F9;MODIFIER LETTER SMALL LIGATURE OE;Lm;0;L;<super> 0153;;;;N;;;;; -A7FA;LATIN LETTER SMALL CAPITAL TURNED M;Ll;0;L;;;;;N;;;;; -A7FB;LATIN EPIGRAPHIC LETTER REVERSED F;Lo;0;L;;;;;N;;;;; -A7FC;LATIN EPIGRAPHIC LETTER REVERSED P;Lo;0;L;;;;;N;;;;; -A7FD;LATIN EPIGRAPHIC LETTER INVERTED M;Lo;0;L;;;;;N;;;;; -A7FE;LATIN EPIGRAPHIC LETTER I LONGA;Lo;0;L;;;;;N;;;;; -A7FF;LATIN EPIGRAPHIC LETTER ARCHAIC M;Lo;0;L;;;;;N;;;;; -A800;SYLOTI NAGRI LETTER A;Lo;0;L;;;;;N;;;;; -A801;SYLOTI NAGRI LETTER I;Lo;0;L;;;;;N;;;;; -A802;SYLOTI NAGRI SIGN DVISVARA;Mn;0;NSM;;;;;N;;;;; -A803;SYLOTI NAGRI LETTER U;Lo;0;L;;;;;N;;;;; -A804;SYLOTI NAGRI LETTER E;Lo;0;L;;;;;N;;;;; -A805;SYLOTI NAGRI LETTER O;Lo;0;L;;;;;N;;;;; -A806;SYLOTI NAGRI SIGN HASANTA;Mn;9;NSM;;;;;N;;;;; -A807;SYLOTI NAGRI LETTER KO;Lo;0;L;;;;;N;;;;; -A808;SYLOTI NAGRI LETTER KHO;Lo;0;L;;;;;N;;;;; -A809;SYLOTI NAGRI LETTER GO;Lo;0;L;;;;;N;;;;; -A80A;SYLOTI NAGRI LETTER GHO;Lo;0;L;;;;;N;;;;; -A80B;SYLOTI NAGRI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -A80C;SYLOTI NAGRI LETTER CO;Lo;0;L;;;;;N;;;;; -A80D;SYLOTI NAGRI LETTER CHO;Lo;0;L;;;;;N;;;;; -A80E;SYLOTI NAGRI LETTER JO;Lo;0;L;;;;;N;;;;; -A80F;SYLOTI NAGRI LETTER JHO;Lo;0;L;;;;;N;;;;; -A810;SYLOTI NAGRI LETTER TTO;Lo;0;L;;;;;N;;;;; -A811;SYLOTI NAGRI LETTER TTHO;Lo;0;L;;;;;N;;;;; -A812;SYLOTI NAGRI LETTER DDO;Lo;0;L;;;;;N;;;;; -A813;SYLOTI NAGRI LETTER DDHO;Lo;0;L;;;;;N;;;;; -A814;SYLOTI NAGRI LETTER TO;Lo;0;L;;;;;N;;;;; -A815;SYLOTI NAGRI LETTER THO;Lo;0;L;;;;;N;;;;; -A816;SYLOTI NAGRI LETTER DO;Lo;0;L;;;;;N;;;;; -A817;SYLOTI NAGRI LETTER DHO;Lo;0;L;;;;;N;;;;; -A818;SYLOTI NAGRI LETTER NO;Lo;0;L;;;;;N;;;;; -A819;SYLOTI NAGRI LETTER PO;Lo;0;L;;;;;N;;;;; -A81A;SYLOTI NAGRI LETTER PHO;Lo;0;L;;;;;N;;;;; -A81B;SYLOTI NAGRI LETTER BO;Lo;0;L;;;;;N;;;;; -A81C;SYLOTI NAGRI LETTER BHO;Lo;0;L;;;;;N;;;;; -A81D;SYLOTI NAGRI LETTER MO;Lo;0;L;;;;;N;;;;; -A81E;SYLOTI NAGRI LETTER RO;Lo;0;L;;;;;N;;;;; -A81F;SYLOTI NAGRI LETTER LO;Lo;0;L;;;;;N;;;;; -A820;SYLOTI NAGRI LETTER RRO;Lo;0;L;;;;;N;;;;; -A821;SYLOTI NAGRI LETTER SO;Lo;0;L;;;;;N;;;;; -A822;SYLOTI NAGRI LETTER HO;Lo;0;L;;;;;N;;;;; -A823;SYLOTI NAGRI VOWEL SIGN A;Mc;0;L;;;;;N;;;;; -A824;SYLOTI NAGRI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -A825;SYLOTI NAGRI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -A826;SYLOTI NAGRI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -A827;SYLOTI NAGRI VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; -A828;SYLOTI NAGRI POETRY MARK-1;So;0;ON;;;;;N;;;;; -A829;SYLOTI NAGRI POETRY MARK-2;So;0;ON;;;;;N;;;;; -A82A;SYLOTI NAGRI POETRY MARK-3;So;0;ON;;;;;N;;;;; -A82B;SYLOTI NAGRI POETRY MARK-4;So;0;ON;;;;;N;;;;; -A82C;SYLOTI NAGRI SIGN ALTERNATE HASANTA;Mn;9;NSM;;;;;N;;;;; -A830;NORTH INDIC FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;; -A831;NORTH INDIC FRACTION ONE HALF;No;0;L;;;;1/2;N;;;;; -A832;NORTH INDIC FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;; -A833;NORTH INDIC FRACTION ONE SIXTEENTH;No;0;L;;;;1/16;N;;;;; -A834;NORTH INDIC FRACTION ONE EIGHTH;No;0;L;;;;1/8;N;;;;; -A835;NORTH INDIC FRACTION THREE SIXTEENTHS;No;0;L;;;;3/16;N;;;;; -A836;NORTH INDIC QUARTER MARK;So;0;L;;;;;N;;;;; -A837;NORTH INDIC PLACEHOLDER MARK;So;0;L;;;;;N;;;;; -A838;NORTH INDIC RUPEE MARK;Sc;0;ET;;;;;N;;;;; -A839;NORTH INDIC QUANTITY MARK;So;0;ET;;;;;N;;;;; -A840;PHAGS-PA LETTER KA;Lo;0;L;;;;;N;;;;; -A841;PHAGS-PA LETTER KHA;Lo;0;L;;;;;N;;;;; -A842;PHAGS-PA LETTER GA;Lo;0;L;;;;;N;;;;; -A843;PHAGS-PA LETTER NGA;Lo;0;L;;;;;N;;;;; -A844;PHAGS-PA LETTER CA;Lo;0;L;;;;;N;;;;; -A845;PHAGS-PA LETTER CHA;Lo;0;L;;;;;N;;;;; -A846;PHAGS-PA LETTER JA;Lo;0;L;;;;;N;;;;; -A847;PHAGS-PA LETTER NYA;Lo;0;L;;;;;N;;;;; -A848;PHAGS-PA LETTER TA;Lo;0;L;;;;;N;;;;; -A849;PHAGS-PA LETTER THA;Lo;0;L;;;;;N;;;;; -A84A;PHAGS-PA LETTER DA;Lo;0;L;;;;;N;;;;; -A84B;PHAGS-PA LETTER NA;Lo;0;L;;;;;N;;;;; -A84C;PHAGS-PA LETTER PA;Lo;0;L;;;;;N;;;;; -A84D;PHAGS-PA LETTER PHA;Lo;0;L;;;;;N;;;;; -A84E;PHAGS-PA LETTER BA;Lo;0;L;;;;;N;;;;; -A84F;PHAGS-PA LETTER MA;Lo;0;L;;;;;N;;;;; -A850;PHAGS-PA LETTER TSA;Lo;0;L;;;;;N;;;;; -A851;PHAGS-PA LETTER TSHA;Lo;0;L;;;;;N;;;;; -A852;PHAGS-PA LETTER DZA;Lo;0;L;;;;;N;;;;; -A853;PHAGS-PA LETTER WA;Lo;0;L;;;;;N;;;;; -A854;PHAGS-PA LETTER ZHA;Lo;0;L;;;;;N;;;;; -A855;PHAGS-PA LETTER ZA;Lo;0;L;;;;;N;;;;; -A856;PHAGS-PA LETTER SMALL A;Lo;0;L;;;;;N;;;;; -A857;PHAGS-PA LETTER YA;Lo;0;L;;;;;N;;;;; -A858;PHAGS-PA LETTER RA;Lo;0;L;;;;;N;;;;; -A859;PHAGS-PA LETTER LA;Lo;0;L;;;;;N;;;;; -A85A;PHAGS-PA LETTER SHA;Lo;0;L;;;;;N;;;;; -A85B;PHAGS-PA LETTER SA;Lo;0;L;;;;;N;;;;; -A85C;PHAGS-PA LETTER HA;Lo;0;L;;;;;N;;;;; -A85D;PHAGS-PA LETTER A;Lo;0;L;;;;;N;;;;; -A85E;PHAGS-PA LETTER I;Lo;0;L;;;;;N;;;;; -A85F;PHAGS-PA LETTER U;Lo;0;L;;;;;N;;;;; -A860;PHAGS-PA LETTER E;Lo;0;L;;;;;N;;;;; -A861;PHAGS-PA LETTER O;Lo;0;L;;;;;N;;;;; -A862;PHAGS-PA LETTER QA;Lo;0;L;;;;;N;;;;; -A863;PHAGS-PA LETTER XA;Lo;0;L;;;;;N;;;;; -A864;PHAGS-PA LETTER FA;Lo;0;L;;;;;N;;;;; -A865;PHAGS-PA LETTER GGA;Lo;0;L;;;;;N;;;;; -A866;PHAGS-PA LETTER EE;Lo;0;L;;;;;N;;;;; -A867;PHAGS-PA SUBJOINED LETTER WA;Lo;0;L;;;;;N;;;;; -A868;PHAGS-PA SUBJOINED LETTER YA;Lo;0;L;;;;;N;;;;; -A869;PHAGS-PA LETTER TTA;Lo;0;L;;;;;N;;;;; -A86A;PHAGS-PA LETTER TTHA;Lo;0;L;;;;;N;;;;; -A86B;PHAGS-PA LETTER DDA;Lo;0;L;;;;;N;;;;; -A86C;PHAGS-PA LETTER NNA;Lo;0;L;;;;;N;;;;; -A86D;PHAGS-PA LETTER ALTERNATE YA;Lo;0;L;;;;;N;;;;; -A86E;PHAGS-PA LETTER VOICELESS SHA;Lo;0;L;;;;;N;;;;; -A86F;PHAGS-PA LETTER VOICED HA;Lo;0;L;;;;;N;;;;; -A870;PHAGS-PA LETTER ASPIRATED FA;Lo;0;L;;;;;N;;;;; -A871;PHAGS-PA SUBJOINED LETTER RA;Lo;0;L;;;;;N;;;;; -A872;PHAGS-PA SUPERFIXED LETTER RA;Lo;0;L;;;;;N;;;;; -A873;PHAGS-PA LETTER CANDRABINDU;Lo;0;L;;;;;N;;;;; -A874;PHAGS-PA SINGLE HEAD MARK;Po;0;ON;;;;;N;;;;; -A875;PHAGS-PA DOUBLE HEAD MARK;Po;0;ON;;;;;N;;;;; -A876;PHAGS-PA MARK SHAD;Po;0;ON;;;;;N;;;;; -A877;PHAGS-PA MARK DOUBLE SHAD;Po;0;ON;;;;;N;;;;; -A880;SAURASHTRA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; -A881;SAURASHTRA SIGN VISARGA;Mc;0;L;;;;;N;;;;; -A882;SAURASHTRA LETTER A;Lo;0;L;;;;;N;;;;; -A883;SAURASHTRA LETTER AA;Lo;0;L;;;;;N;;;;; -A884;SAURASHTRA LETTER I;Lo;0;L;;;;;N;;;;; -A885;SAURASHTRA LETTER II;Lo;0;L;;;;;N;;;;; -A886;SAURASHTRA LETTER U;Lo;0;L;;;;;N;;;;; -A887;SAURASHTRA LETTER UU;Lo;0;L;;;;;N;;;;; -A888;SAURASHTRA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; -A889;SAURASHTRA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; -A88A;SAURASHTRA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; -A88B;SAURASHTRA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; -A88C;SAURASHTRA LETTER E;Lo;0;L;;;;;N;;;;; -A88D;SAURASHTRA LETTER EE;Lo;0;L;;;;;N;;;;; -A88E;SAURASHTRA LETTER AI;Lo;0;L;;;;;N;;;;; -A88F;SAURASHTRA LETTER O;Lo;0;L;;;;;N;;;;; -A890;SAURASHTRA LETTER OO;Lo;0;L;;;;;N;;;;; -A891;SAURASHTRA LETTER AU;Lo;0;L;;;;;N;;;;; -A892;SAURASHTRA LETTER KA;Lo;0;L;;;;;N;;;;; -A893;SAURASHTRA LETTER KHA;Lo;0;L;;;;;N;;;;; -A894;SAURASHTRA LETTER GA;Lo;0;L;;;;;N;;;;; -A895;SAURASHTRA LETTER GHA;Lo;0;L;;;;;N;;;;; -A896;SAURASHTRA LETTER NGA;Lo;0;L;;;;;N;;;;; -A897;SAURASHTRA LETTER CA;Lo;0;L;;;;;N;;;;; -A898;SAURASHTRA LETTER CHA;Lo;0;L;;;;;N;;;;; -A899;SAURASHTRA LETTER JA;Lo;0;L;;;;;N;;;;; -A89A;SAURASHTRA LETTER JHA;Lo;0;L;;;;;N;;;;; -A89B;SAURASHTRA LETTER NYA;Lo;0;L;;;;;N;;;;; -A89C;SAURASHTRA LETTER TTA;Lo;0;L;;;;;N;;;;; -A89D;SAURASHTRA LETTER TTHA;Lo;0;L;;;;;N;;;;; -A89E;SAURASHTRA LETTER DDA;Lo;0;L;;;;;N;;;;; -A89F;SAURASHTRA LETTER DDHA;Lo;0;L;;;;;N;;;;; -A8A0;SAURASHTRA LETTER NNA;Lo;0;L;;;;;N;;;;; -A8A1;SAURASHTRA LETTER TA;Lo;0;L;;;;;N;;;;; -A8A2;SAURASHTRA LETTER THA;Lo;0;L;;;;;N;;;;; -A8A3;SAURASHTRA LETTER DA;Lo;0;L;;;;;N;;;;; -A8A4;SAURASHTRA LETTER DHA;Lo;0;L;;;;;N;;;;; -A8A5;SAURASHTRA LETTER NA;Lo;0;L;;;;;N;;;;; -A8A6;SAURASHTRA LETTER PA;Lo;0;L;;;;;N;;;;; -A8A7;SAURASHTRA LETTER PHA;Lo;0;L;;;;;N;;;;; -A8A8;SAURASHTRA LETTER BA;Lo;0;L;;;;;N;;;;; -A8A9;SAURASHTRA LETTER BHA;Lo;0;L;;;;;N;;;;; -A8AA;SAURASHTRA LETTER MA;Lo;0;L;;;;;N;;;;; -A8AB;SAURASHTRA LETTER YA;Lo;0;L;;;;;N;;;;; -A8AC;SAURASHTRA LETTER RA;Lo;0;L;;;;;N;;;;; -A8AD;SAURASHTRA LETTER LA;Lo;0;L;;;;;N;;;;; -A8AE;SAURASHTRA LETTER VA;Lo;0;L;;;;;N;;;;; -A8AF;SAURASHTRA LETTER SHA;Lo;0;L;;;;;N;;;;; -A8B0;SAURASHTRA LETTER SSA;Lo;0;L;;;;;N;;;;; -A8B1;SAURASHTRA LETTER SA;Lo;0;L;;;;;N;;;;; -A8B2;SAURASHTRA LETTER HA;Lo;0;L;;;;;N;;;;; -A8B3;SAURASHTRA LETTER LLA;Lo;0;L;;;;;N;;;;; -A8B4;SAURASHTRA CONSONANT SIGN HAARU;Mc;0;L;;;;;N;;;;; -A8B5;SAURASHTRA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -A8B6;SAURASHTRA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -A8B7;SAURASHTRA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -A8B8;SAURASHTRA VOWEL SIGN U;Mc;0;L;;;;;N;;;;; -A8B9;SAURASHTRA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; -A8BA;SAURASHTRA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; -A8BB;SAURASHTRA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; -A8BC;SAURASHTRA VOWEL SIGN VOCALIC L;Mc;0;L;;;;;N;;;;; -A8BD;SAURASHTRA VOWEL SIGN VOCALIC LL;Mc;0;L;;;;;N;;;;; -A8BE;SAURASHTRA VOWEL SIGN E;Mc;0;L;;;;;N;;;;; -A8BF;SAURASHTRA VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; -A8C0;SAURASHTRA VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; -A8C1;SAURASHTRA VOWEL SIGN O;Mc;0;L;;;;;N;;;;; -A8C2;SAURASHTRA VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; -A8C3;SAURASHTRA VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; -A8C4;SAURASHTRA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -A8C5;SAURASHTRA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -A8CE;SAURASHTRA DANDA;Po;0;L;;;;;N;;;;; -A8CF;SAURASHTRA DOUBLE DANDA;Po;0;L;;;;;N;;;;; -A8D0;SAURASHTRA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -A8D1;SAURASHTRA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -A8D2;SAURASHTRA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -A8D3;SAURASHTRA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -A8D4;SAURASHTRA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -A8D5;SAURASHTRA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -A8D6;SAURASHTRA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -A8D7;SAURASHTRA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -A8D8;SAURASHTRA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -A8D9;SAURASHTRA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -A8E0;COMBINING DEVANAGARI DIGIT ZERO;Mn;230;NSM;;;;;N;;;;; -A8E1;COMBINING DEVANAGARI DIGIT ONE;Mn;230;NSM;;;;;N;;;;; -A8E2;COMBINING DEVANAGARI DIGIT TWO;Mn;230;NSM;;;;;N;;;;; -A8E3;COMBINING DEVANAGARI DIGIT THREE;Mn;230;NSM;;;;;N;;;;; -A8E4;COMBINING DEVANAGARI DIGIT FOUR;Mn;230;NSM;;;;;N;;;;; -A8E5;COMBINING DEVANAGARI DIGIT FIVE;Mn;230;NSM;;;;;N;;;;; -A8E6;COMBINING DEVANAGARI DIGIT SIX;Mn;230;NSM;;;;;N;;;;; -A8E7;COMBINING DEVANAGARI DIGIT SEVEN;Mn;230;NSM;;;;;N;;;;; -A8E8;COMBINING DEVANAGARI DIGIT EIGHT;Mn;230;NSM;;;;;N;;;;; -A8E9;COMBINING DEVANAGARI DIGIT NINE;Mn;230;NSM;;;;;N;;;;; -A8EA;COMBINING DEVANAGARI LETTER A;Mn;230;NSM;;;;;N;;;;; -A8EB;COMBINING DEVANAGARI LETTER U;Mn;230;NSM;;;;;N;;;;; -A8EC;COMBINING DEVANAGARI LETTER KA;Mn;230;NSM;;;;;N;;;;; -A8ED;COMBINING DEVANAGARI LETTER NA;Mn;230;NSM;;;;;N;;;;; -A8EE;COMBINING DEVANAGARI LETTER PA;Mn;230;NSM;;;;;N;;;;; -A8EF;COMBINING DEVANAGARI LETTER RA;Mn;230;NSM;;;;;N;;;;; -A8F0;COMBINING DEVANAGARI LETTER VI;Mn;230;NSM;;;;;N;;;;; -A8F1;COMBINING DEVANAGARI SIGN AVAGRAHA;Mn;230;NSM;;;;;N;;;;; -A8F2;DEVANAGARI SIGN SPACING CANDRABINDU;Lo;0;L;;;;;N;;;;; -A8F3;DEVANAGARI SIGN CANDRABINDU VIRAMA;Lo;0;L;;;;;N;;;;; -A8F4;DEVANAGARI SIGN DOUBLE CANDRABINDU VIRAMA;Lo;0;L;;;;;N;;;;; -A8F5;DEVANAGARI SIGN CANDRABINDU TWO;Lo;0;L;;;;;N;;;;; -A8F6;DEVANAGARI SIGN CANDRABINDU THREE;Lo;0;L;;;;;N;;;;; -A8F7;DEVANAGARI SIGN CANDRABINDU AVAGRAHA;Lo;0;L;;;;;N;;;;; -A8F8;DEVANAGARI SIGN PUSHPIKA;Po;0;L;;;;;N;;;;; -A8F9;DEVANAGARI GAP FILLER;Po;0;L;;;;;N;;;;; -A8FA;DEVANAGARI CARET;Po;0;L;;;;;N;;;;; -A8FB;DEVANAGARI HEADSTROKE;Lo;0;L;;;;;N;;;;; -A8FC;DEVANAGARI SIGN SIDDHAM;Po;0;L;;;;;N;;;;; -A8FD;DEVANAGARI JAIN OM;Lo;0;L;;;;;N;;;;; -A8FE;DEVANAGARI LETTER AY;Lo;0;L;;;;;N;;;;; -A8FF;DEVANAGARI VOWEL SIGN AY;Mn;0;NSM;;;;;N;;;;; -A900;KAYAH LI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -A901;KAYAH LI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -A902;KAYAH LI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -A903;KAYAH LI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -A904;KAYAH LI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -A905;KAYAH LI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -A906;KAYAH LI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -A907;KAYAH LI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -A908;KAYAH LI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -A909;KAYAH LI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -A90A;KAYAH LI LETTER KA;Lo;0;L;;;;;N;;;;; -A90B;KAYAH LI LETTER KHA;Lo;0;L;;;;;N;;;;; -A90C;KAYAH LI LETTER GA;Lo;0;L;;;;;N;;;;; -A90D;KAYAH LI LETTER NGA;Lo;0;L;;;;;N;;;;; -A90E;KAYAH LI LETTER SA;Lo;0;L;;;;;N;;;;; -A90F;KAYAH LI LETTER SHA;Lo;0;L;;;;;N;;;;; -A910;KAYAH LI LETTER ZA;Lo;0;L;;;;;N;;;;; -A911;KAYAH LI LETTER NYA;Lo;0;L;;;;;N;;;;; -A912;KAYAH LI LETTER TA;Lo;0;L;;;;;N;;;;; -A913;KAYAH LI LETTER HTA;Lo;0;L;;;;;N;;;;; -A914;KAYAH LI LETTER NA;Lo;0;L;;;;;N;;;;; -A915;KAYAH LI LETTER PA;Lo;0;L;;;;;N;;;;; -A916;KAYAH LI LETTER PHA;Lo;0;L;;;;;N;;;;; -A917;KAYAH LI LETTER MA;Lo;0;L;;;;;N;;;;; -A918;KAYAH LI LETTER DA;Lo;0;L;;;;;N;;;;; -A919;KAYAH LI LETTER BA;Lo;0;L;;;;;N;;;;; -A91A;KAYAH LI LETTER RA;Lo;0;L;;;;;N;;;;; -A91B;KAYAH LI LETTER YA;Lo;0;L;;;;;N;;;;; -A91C;KAYAH LI LETTER LA;Lo;0;L;;;;;N;;;;; -A91D;KAYAH LI LETTER WA;Lo;0;L;;;;;N;;;;; -A91E;KAYAH LI LETTER THA;Lo;0;L;;;;;N;;;;; -A91F;KAYAH LI LETTER HA;Lo;0;L;;;;;N;;;;; -A920;KAYAH LI LETTER VA;Lo;0;L;;;;;N;;;;; -A921;KAYAH LI LETTER CA;Lo;0;L;;;;;N;;;;; -A922;KAYAH LI LETTER A;Lo;0;L;;;;;N;;;;; -A923;KAYAH LI LETTER OE;Lo;0;L;;;;;N;;;;; -A924;KAYAH LI LETTER I;Lo;0;L;;;;;N;;;;; -A925;KAYAH LI LETTER OO;Lo;0;L;;;;;N;;;;; -A926;KAYAH LI VOWEL UE;Mn;0;NSM;;;;;N;;;;; -A927;KAYAH LI VOWEL E;Mn;0;NSM;;;;;N;;;;; -A928;KAYAH LI VOWEL U;Mn;0;NSM;;;;;N;;;;; -A929;KAYAH LI VOWEL EE;Mn;0;NSM;;;;;N;;;;; -A92A;KAYAH LI VOWEL O;Mn;0;NSM;;;;;N;;;;; -A92B;KAYAH LI TONE PLOPHU;Mn;220;NSM;;;;;N;;;;; -A92C;KAYAH LI TONE CALYA;Mn;220;NSM;;;;;N;;;;; -A92D;KAYAH LI TONE CALYA PLOPHU;Mn;220;NSM;;;;;N;;;;; -A92E;KAYAH LI SIGN CWI;Po;0;L;;;;;N;;;;; -A92F;KAYAH LI SIGN SHYA;Po;0;L;;;;;N;;;;; -A930;REJANG LETTER KA;Lo;0;L;;;;;N;;;;; -A931;REJANG LETTER GA;Lo;0;L;;;;;N;;;;; -A932;REJANG LETTER NGA;Lo;0;L;;;;;N;;;;; -A933;REJANG LETTER TA;Lo;0;L;;;;;N;;;;; -A934;REJANG LETTER DA;Lo;0;L;;;;;N;;;;; -A935;REJANG LETTER NA;Lo;0;L;;;;;N;;;;; -A936;REJANG LETTER PA;Lo;0;L;;;;;N;;;;; -A937;REJANG LETTER BA;Lo;0;L;;;;;N;;;;; -A938;REJANG LETTER MA;Lo;0;L;;;;;N;;;;; -A939;REJANG LETTER CA;Lo;0;L;;;;;N;;;;; -A93A;REJANG LETTER JA;Lo;0;L;;;;;N;;;;; -A93B;REJANG LETTER NYA;Lo;0;L;;;;;N;;;;; -A93C;REJANG LETTER SA;Lo;0;L;;;;;N;;;;; -A93D;REJANG LETTER RA;Lo;0;L;;;;;N;;;;; -A93E;REJANG LETTER LA;Lo;0;L;;;;;N;;;;; -A93F;REJANG LETTER YA;Lo;0;L;;;;;N;;;;; -A940;REJANG LETTER WA;Lo;0;L;;;;;N;;;;; -A941;REJANG LETTER HA;Lo;0;L;;;;;N;;;;; -A942;REJANG LETTER MBA;Lo;0;L;;;;;N;;;;; -A943;REJANG LETTER NGGA;Lo;0;L;;;;;N;;;;; -A944;REJANG LETTER NDA;Lo;0;L;;;;;N;;;;; -A945;REJANG LETTER NYJA;Lo;0;L;;;;;N;;;;; -A946;REJANG LETTER A;Lo;0;L;;;;;N;;;;; -A947;REJANG VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -A948;REJANG VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -A949;REJANG VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -A94A;REJANG VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -A94B;REJANG VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; -A94C;REJANG VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; -A94D;REJANG VOWEL SIGN EU;Mn;0;NSM;;;;;N;;;;; -A94E;REJANG VOWEL SIGN EA;Mn;0;NSM;;;;;N;;;;; -A94F;REJANG CONSONANT SIGN NG;Mn;0;NSM;;;;;N;;;;; -A950;REJANG CONSONANT SIGN N;Mn;0;NSM;;;;;N;;;;; -A951;REJANG CONSONANT SIGN R;Mn;0;NSM;;;;;N;;;;; -A952;REJANG CONSONANT SIGN H;Mc;0;L;;;;;N;;;;; -A953;REJANG VIRAMA;Mc;9;L;;;;;N;;;;; -A95F;REJANG SECTION MARK;Po;0;L;;;;;N;;;;; -A960;HANGUL CHOSEONG TIKEUT-MIEUM;Lo;0;L;;;;;N;;;;; -A961;HANGUL CHOSEONG TIKEUT-PIEUP;Lo;0;L;;;;;N;;;;; -A962;HANGUL CHOSEONG TIKEUT-SIOS;Lo;0;L;;;;;N;;;;; -A963;HANGUL CHOSEONG TIKEUT-CIEUC;Lo;0;L;;;;;N;;;;; -A964;HANGUL CHOSEONG RIEUL-KIYEOK;Lo;0;L;;;;;N;;;;; -A965;HANGUL CHOSEONG RIEUL-SSANGKIYEOK;Lo;0;L;;;;;N;;;;; -A966;HANGUL CHOSEONG RIEUL-TIKEUT;Lo;0;L;;;;;N;;;;; -A967;HANGUL CHOSEONG RIEUL-SSANGTIKEUT;Lo;0;L;;;;;N;;;;; -A968;HANGUL CHOSEONG RIEUL-MIEUM;Lo;0;L;;;;;N;;;;; -A969;HANGUL CHOSEONG RIEUL-PIEUP;Lo;0;L;;;;;N;;;;; -A96A;HANGUL CHOSEONG RIEUL-SSANGPIEUP;Lo;0;L;;;;;N;;;;; -A96B;HANGUL CHOSEONG RIEUL-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; -A96C;HANGUL CHOSEONG RIEUL-SIOS;Lo;0;L;;;;;N;;;;; -A96D;HANGUL CHOSEONG RIEUL-CIEUC;Lo;0;L;;;;;N;;;;; -A96E;HANGUL CHOSEONG RIEUL-KHIEUKH;Lo;0;L;;;;;N;;;;; -A96F;HANGUL CHOSEONG MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;; -A970;HANGUL CHOSEONG MIEUM-TIKEUT;Lo;0;L;;;;;N;;;;; -A971;HANGUL CHOSEONG MIEUM-SIOS;Lo;0;L;;;;;N;;;;; -A972;HANGUL CHOSEONG PIEUP-SIOS-THIEUTH;Lo;0;L;;;;;N;;;;; -A973;HANGUL CHOSEONG PIEUP-KHIEUKH;Lo;0;L;;;;;N;;;;; -A974;HANGUL CHOSEONG PIEUP-HIEUH;Lo;0;L;;;;;N;;;;; -A975;HANGUL CHOSEONG SSANGSIOS-PIEUP;Lo;0;L;;;;;N;;;;; -A976;HANGUL CHOSEONG IEUNG-RIEUL;Lo;0;L;;;;;N;;;;; -A977;HANGUL CHOSEONG IEUNG-HIEUH;Lo;0;L;;;;;N;;;;; -A978;HANGUL CHOSEONG SSANGCIEUC-HIEUH;Lo;0;L;;;;;N;;;;; -A979;HANGUL CHOSEONG SSANGTHIEUTH;Lo;0;L;;;;;N;;;;; -A97A;HANGUL CHOSEONG PHIEUPH-HIEUH;Lo;0;L;;;;;N;;;;; -A97B;HANGUL CHOSEONG HIEUH-SIOS;Lo;0;L;;;;;N;;;;; -A97C;HANGUL CHOSEONG SSANGYEORINHIEUH;Lo;0;L;;;;;N;;;;; -A980;JAVANESE SIGN PANYANGGA;Mn;0;NSM;;;;;N;;;;; -A981;JAVANESE SIGN CECAK;Mn;0;NSM;;;;;N;;;;; -A982;JAVANESE SIGN LAYAR;Mn;0;NSM;;;;;N;;;;; -A983;JAVANESE SIGN WIGNYAN;Mc;0;L;;;;;N;;;;; -A984;JAVANESE LETTER A;Lo;0;L;;;;;N;;;;; -A985;JAVANESE LETTER I KAWI;Lo;0;L;;;;;N;;;;; -A986;JAVANESE LETTER I;Lo;0;L;;;;;N;;;;; -A987;JAVANESE LETTER II;Lo;0;L;;;;;N;;;;; -A988;JAVANESE LETTER U;Lo;0;L;;;;;N;;;;; -A989;JAVANESE LETTER PA CEREK;Lo;0;L;;;;;N;;;;; -A98A;JAVANESE LETTER NGA LELET;Lo;0;L;;;;;N;;;;; -A98B;JAVANESE LETTER NGA LELET RASWADI;Lo;0;L;;;;;N;;;;; -A98C;JAVANESE LETTER E;Lo;0;L;;;;;N;;;;; -A98D;JAVANESE LETTER AI;Lo;0;L;;;;;N;;;;; -A98E;JAVANESE LETTER O;Lo;0;L;;;;;N;;;;; -A98F;JAVANESE LETTER KA;Lo;0;L;;;;;N;;;;; -A990;JAVANESE LETTER KA SASAK;Lo;0;L;;;;;N;;;;; -A991;JAVANESE LETTER KA MURDA;Lo;0;L;;;;;N;;;;; -A992;JAVANESE LETTER GA;Lo;0;L;;;;;N;;;;; -A993;JAVANESE LETTER GA MURDA;Lo;0;L;;;;;N;;;;; -A994;JAVANESE LETTER NGA;Lo;0;L;;;;;N;;;;; -A995;JAVANESE LETTER CA;Lo;0;L;;;;;N;;;;; -A996;JAVANESE LETTER CA MURDA;Lo;0;L;;;;;N;;;;; -A997;JAVANESE LETTER JA;Lo;0;L;;;;;N;;;;; -A998;JAVANESE LETTER NYA MURDA;Lo;0;L;;;;;N;;;;; -A999;JAVANESE LETTER JA MAHAPRANA;Lo;0;L;;;;;N;;;;; -A99A;JAVANESE LETTER NYA;Lo;0;L;;;;;N;;;;; -A99B;JAVANESE LETTER TTA;Lo;0;L;;;;;N;;;;; -A99C;JAVANESE LETTER TTA MAHAPRANA;Lo;0;L;;;;;N;;;;; -A99D;JAVANESE LETTER DDA;Lo;0;L;;;;;N;;;;; -A99E;JAVANESE LETTER DDA MAHAPRANA;Lo;0;L;;;;;N;;;;; -A99F;JAVANESE LETTER NA MURDA;Lo;0;L;;;;;N;;;;; -A9A0;JAVANESE LETTER TA;Lo;0;L;;;;;N;;;;; -A9A1;JAVANESE LETTER TA MURDA;Lo;0;L;;;;;N;;;;; -A9A2;JAVANESE LETTER DA;Lo;0;L;;;;;N;;;;; -A9A3;JAVANESE LETTER DA MAHAPRANA;Lo;0;L;;;;;N;;;;; -A9A4;JAVANESE LETTER NA;Lo;0;L;;;;;N;;;;; -A9A5;JAVANESE LETTER PA;Lo;0;L;;;;;N;;;;; -A9A6;JAVANESE LETTER PA MURDA;Lo;0;L;;;;;N;;;;; -A9A7;JAVANESE LETTER BA;Lo;0;L;;;;;N;;;;; -A9A8;JAVANESE LETTER BA MURDA;Lo;0;L;;;;;N;;;;; -A9A9;JAVANESE LETTER MA;Lo;0;L;;;;;N;;;;; -A9AA;JAVANESE LETTER YA;Lo;0;L;;;;;N;;;;; -A9AB;JAVANESE LETTER RA;Lo;0;L;;;;;N;;;;; -A9AC;JAVANESE LETTER RA AGUNG;Lo;0;L;;;;;N;;;;; -A9AD;JAVANESE LETTER LA;Lo;0;L;;;;;N;;;;; -A9AE;JAVANESE LETTER WA;Lo;0;L;;;;;N;;;;; -A9AF;JAVANESE LETTER SA MURDA;Lo;0;L;;;;;N;;;;; -A9B0;JAVANESE LETTER SA MAHAPRANA;Lo;0;L;;;;;N;;;;; -A9B1;JAVANESE LETTER SA;Lo;0;L;;;;;N;;;;; -A9B2;JAVANESE LETTER HA;Lo;0;L;;;;;N;;;;; -A9B3;JAVANESE SIGN CECAK TELU;Mn;7;NSM;;;;;N;;;;; -A9B4;JAVANESE VOWEL SIGN TARUNG;Mc;0;L;;;;;N;;;;; -A9B5;JAVANESE VOWEL SIGN TOLONG;Mc;0;L;;;;;N;;;;; -A9B6;JAVANESE VOWEL SIGN WULU;Mn;0;NSM;;;;;N;;;;; -A9B7;JAVANESE VOWEL SIGN WULU MELIK;Mn;0;NSM;;;;;N;;;;; -A9B8;JAVANESE VOWEL SIGN SUKU;Mn;0;NSM;;;;;N;;;;; -A9B9;JAVANESE VOWEL SIGN SUKU MENDUT;Mn;0;NSM;;;;;N;;;;; -A9BA;JAVANESE VOWEL SIGN TALING;Mc;0;L;;;;;N;;;;; -A9BB;JAVANESE VOWEL SIGN DIRGA MURE;Mc;0;L;;;;;N;;;;; -A9BC;JAVANESE VOWEL SIGN PEPET;Mn;0;NSM;;;;;N;;;;; -A9BD;JAVANESE CONSONANT SIGN KERET;Mn;0;NSM;;;;;N;;;;; -A9BE;JAVANESE CONSONANT SIGN PENGKAL;Mc;0;L;;;;;N;;;;; -A9BF;JAVANESE CONSONANT SIGN CAKRA;Mc;0;L;;;;;N;;;;; -A9C0;JAVANESE PANGKON;Mc;9;L;;;;;N;;;;; -A9C1;JAVANESE LEFT RERENGGAN;Po;0;L;;;;;N;;;;; -A9C2;JAVANESE RIGHT RERENGGAN;Po;0;L;;;;;N;;;;; -A9C3;JAVANESE PADA ANDAP;Po;0;L;;;;;N;;;;; -A9C4;JAVANESE PADA MADYA;Po;0;L;;;;;N;;;;; -A9C5;JAVANESE PADA LUHUR;Po;0;L;;;;;N;;;;; -A9C6;JAVANESE PADA WINDU;Po;0;L;;;;;N;;;;; -A9C7;JAVANESE PADA PANGKAT;Po;0;L;;;;;N;;;;; -A9C8;JAVANESE PADA LINGSA;Po;0;L;;;;;N;;;;; -A9C9;JAVANESE PADA LUNGSI;Po;0;L;;;;;N;;;;; -A9CA;JAVANESE PADA ADEG;Po;0;L;;;;;N;;;;; -A9CB;JAVANESE PADA ADEG ADEG;Po;0;L;;;;;N;;;;; -A9CC;JAVANESE PADA PISELEH;Po;0;L;;;;;N;;;;; -A9CD;JAVANESE TURNED PADA PISELEH;Po;0;L;;;;;N;;;;; -A9CF;JAVANESE PANGRANGKEP;Lm;0;L;;;;;N;;;;; -A9D0;JAVANESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -A9D1;JAVANESE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -A9D2;JAVANESE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -A9D3;JAVANESE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -A9D4;JAVANESE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -A9D5;JAVANESE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -A9D6;JAVANESE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -A9D7;JAVANESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -A9D8;JAVANESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -A9D9;JAVANESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -A9DE;JAVANESE PADA TIRTA TUMETES;Po;0;L;;;;;N;;;;; -A9DF;JAVANESE PADA ISEN-ISEN;Po;0;L;;;;;N;;;;; -A9E0;MYANMAR LETTER SHAN GHA;Lo;0;L;;;;;N;;;;; -A9E1;MYANMAR LETTER SHAN CHA;Lo;0;L;;;;;N;;;;; -A9E2;MYANMAR LETTER SHAN JHA;Lo;0;L;;;;;N;;;;; -A9E3;MYANMAR LETTER SHAN NNA;Lo;0;L;;;;;N;;;;; -A9E4;MYANMAR LETTER SHAN BHA;Lo;0;L;;;;;N;;;;; -A9E5;MYANMAR SIGN SHAN SAW;Mn;0;NSM;;;;;N;;;;; -A9E6;MYANMAR MODIFIER LETTER SHAN REDUPLICATION;Lm;0;L;;;;;N;;;;; -A9E7;MYANMAR LETTER TAI LAING NYA;Lo;0;L;;;;;N;;;;; -A9E8;MYANMAR LETTER TAI LAING FA;Lo;0;L;;;;;N;;;;; -A9E9;MYANMAR LETTER TAI LAING GA;Lo;0;L;;;;;N;;;;; -A9EA;MYANMAR LETTER TAI LAING GHA;Lo;0;L;;;;;N;;;;; -A9EB;MYANMAR LETTER TAI LAING JA;Lo;0;L;;;;;N;;;;; -A9EC;MYANMAR LETTER TAI LAING JHA;Lo;0;L;;;;;N;;;;; -A9ED;MYANMAR LETTER TAI LAING DDA;Lo;0;L;;;;;N;;;;; -A9EE;MYANMAR LETTER TAI LAING DDHA;Lo;0;L;;;;;N;;;;; -A9EF;MYANMAR LETTER TAI LAING NNA;Lo;0;L;;;;;N;;;;; -A9F0;MYANMAR TAI LAING DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -A9F1;MYANMAR TAI LAING DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -A9F2;MYANMAR TAI LAING DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -A9F3;MYANMAR TAI LAING DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -A9F4;MYANMAR TAI LAING DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -A9F5;MYANMAR TAI LAING DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -A9F6;MYANMAR TAI LAING DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -A9F7;MYANMAR TAI LAING DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -A9F8;MYANMAR TAI LAING DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -A9F9;MYANMAR TAI LAING DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -A9FA;MYANMAR LETTER TAI LAING LLA;Lo;0;L;;;;;N;;;;; -A9FB;MYANMAR LETTER TAI LAING DA;Lo;0;L;;;;;N;;;;; -A9FC;MYANMAR LETTER TAI LAING DHA;Lo;0;L;;;;;N;;;;; -A9FD;MYANMAR LETTER TAI LAING BA;Lo;0;L;;;;;N;;;;; -A9FE;MYANMAR LETTER TAI LAING BHA;Lo;0;L;;;;;N;;;;; -AA00;CHAM LETTER A;Lo;0;L;;;;;N;;;;; -AA01;CHAM LETTER I;Lo;0;L;;;;;N;;;;; -AA02;CHAM LETTER U;Lo;0;L;;;;;N;;;;; -AA03;CHAM LETTER E;Lo;0;L;;;;;N;;;;; -AA04;CHAM LETTER AI;Lo;0;L;;;;;N;;;;; -AA05;CHAM LETTER O;Lo;0;L;;;;;N;;;;; -AA06;CHAM LETTER KA;Lo;0;L;;;;;N;;;;; -AA07;CHAM LETTER KHA;Lo;0;L;;;;;N;;;;; -AA08;CHAM LETTER GA;Lo;0;L;;;;;N;;;;; -AA09;CHAM LETTER GHA;Lo;0;L;;;;;N;;;;; -AA0A;CHAM LETTER NGUE;Lo;0;L;;;;;N;;;;; -AA0B;CHAM LETTER NGA;Lo;0;L;;;;;N;;;;; -AA0C;CHAM LETTER CHA;Lo;0;L;;;;;N;;;;; -AA0D;CHAM LETTER CHHA;Lo;0;L;;;;;N;;;;; -AA0E;CHAM LETTER JA;Lo;0;L;;;;;N;;;;; -AA0F;CHAM LETTER JHA;Lo;0;L;;;;;N;;;;; -AA10;CHAM LETTER NHUE;Lo;0;L;;;;;N;;;;; -AA11;CHAM LETTER NHA;Lo;0;L;;;;;N;;;;; -AA12;CHAM LETTER NHJA;Lo;0;L;;;;;N;;;;; -AA13;CHAM LETTER TA;Lo;0;L;;;;;N;;;;; -AA14;CHAM LETTER THA;Lo;0;L;;;;;N;;;;; -AA15;CHAM LETTER DA;Lo;0;L;;;;;N;;;;; -AA16;CHAM LETTER DHA;Lo;0;L;;;;;N;;;;; -AA17;CHAM LETTER NUE;Lo;0;L;;;;;N;;;;; -AA18;CHAM LETTER NA;Lo;0;L;;;;;N;;;;; -AA19;CHAM LETTER DDA;Lo;0;L;;;;;N;;;;; -AA1A;CHAM LETTER PA;Lo;0;L;;;;;N;;;;; -AA1B;CHAM LETTER PPA;Lo;0;L;;;;;N;;;;; -AA1C;CHAM LETTER PHA;Lo;0;L;;;;;N;;;;; -AA1D;CHAM LETTER BA;Lo;0;L;;;;;N;;;;; -AA1E;CHAM LETTER BHA;Lo;0;L;;;;;N;;;;; -AA1F;CHAM LETTER MUE;Lo;0;L;;;;;N;;;;; -AA20;CHAM LETTER MA;Lo;0;L;;;;;N;;;;; -AA21;CHAM LETTER BBA;Lo;0;L;;;;;N;;;;; -AA22;CHAM LETTER YA;Lo;0;L;;;;;N;;;;; -AA23;CHAM LETTER RA;Lo;0;L;;;;;N;;;;; -AA24;CHAM LETTER LA;Lo;0;L;;;;;N;;;;; -AA25;CHAM LETTER VA;Lo;0;L;;;;;N;;;;; -AA26;CHAM LETTER SSA;Lo;0;L;;;;;N;;;;; -AA27;CHAM LETTER SA;Lo;0;L;;;;;N;;;;; -AA28;CHAM LETTER HA;Lo;0;L;;;;;N;;;;; -AA29;CHAM VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; -AA2A;CHAM VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -AA2B;CHAM VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; -AA2C;CHAM VOWEL SIGN EI;Mn;0;NSM;;;;;N;;;;; -AA2D;CHAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -AA2E;CHAM VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;; -AA2F;CHAM VOWEL SIGN O;Mc;0;L;;;;;N;;;;; -AA30;CHAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; -AA31;CHAM VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; -AA32;CHAM VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;; -AA33;CHAM CONSONANT SIGN YA;Mc;0;L;;;;;N;;;;; -AA34;CHAM CONSONANT SIGN RA;Mc;0;L;;;;;N;;;;; -AA35;CHAM CONSONANT SIGN LA;Mn;0;NSM;;;;;N;;;;; -AA36;CHAM CONSONANT SIGN WA;Mn;0;NSM;;;;;N;;;;; -AA40;CHAM LETTER FINAL K;Lo;0;L;;;;;N;;;;; -AA41;CHAM LETTER FINAL G;Lo;0;L;;;;;N;;;;; -AA42;CHAM LETTER FINAL NG;Lo;0;L;;;;;N;;;;; -AA43;CHAM CONSONANT SIGN FINAL NG;Mn;0;NSM;;;;;N;;;;; -AA44;CHAM LETTER FINAL CH;Lo;0;L;;;;;N;;;;; -AA45;CHAM LETTER FINAL T;Lo;0;L;;;;;N;;;;; -AA46;CHAM LETTER FINAL N;Lo;0;L;;;;;N;;;;; -AA47;CHAM LETTER FINAL P;Lo;0;L;;;;;N;;;;; -AA48;CHAM LETTER FINAL Y;Lo;0;L;;;;;N;;;;; -AA49;CHAM LETTER FINAL R;Lo;0;L;;;;;N;;;;; -AA4A;CHAM LETTER FINAL L;Lo;0;L;;;;;N;;;;; -AA4B;CHAM LETTER FINAL SS;Lo;0;L;;;;;N;;;;; -AA4C;CHAM CONSONANT SIGN FINAL M;Mn;0;NSM;;;;;N;;;;; -AA4D;CHAM CONSONANT SIGN FINAL H;Mc;0;L;;;;;N;;;;; -AA50;CHAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -AA51;CHAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -AA52;CHAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -AA53;CHAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -AA54;CHAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -AA55;CHAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -AA56;CHAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -AA57;CHAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -AA58;CHAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -AA59;CHAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -AA5C;CHAM PUNCTUATION SPIRAL;Po;0;L;;;;;N;;;;; -AA5D;CHAM PUNCTUATION DANDA;Po;0;L;;;;;N;;;;; -AA5E;CHAM PUNCTUATION DOUBLE DANDA;Po;0;L;;;;;N;;;;; -AA5F;CHAM PUNCTUATION TRIPLE DANDA;Po;0;L;;;;;N;;;;; -AA60;MYANMAR LETTER KHAMTI GA;Lo;0;L;;;;;N;;;;; -AA61;MYANMAR LETTER KHAMTI CA;Lo;0;L;;;;;N;;;;; -AA62;MYANMAR LETTER KHAMTI CHA;Lo;0;L;;;;;N;;;;; -AA63;MYANMAR LETTER KHAMTI JA;Lo;0;L;;;;;N;;;;; -AA64;MYANMAR LETTER KHAMTI JHA;Lo;0;L;;;;;N;;;;; -AA65;MYANMAR LETTER KHAMTI NYA;Lo;0;L;;;;;N;;;;; -AA66;MYANMAR LETTER KHAMTI TTA;Lo;0;L;;;;;N;;;;; -AA67;MYANMAR LETTER KHAMTI TTHA;Lo;0;L;;;;;N;;;;; -AA68;MYANMAR LETTER KHAMTI DDA;Lo;0;L;;;;;N;;;;; -AA69;MYANMAR LETTER KHAMTI DDHA;Lo;0;L;;;;;N;;;;; -AA6A;MYANMAR LETTER KHAMTI DHA;Lo;0;L;;;;;N;;;;; -AA6B;MYANMAR LETTER KHAMTI NA;Lo;0;L;;;;;N;;;;; -AA6C;MYANMAR LETTER KHAMTI SA;Lo;0;L;;;;;N;;;;; -AA6D;MYANMAR LETTER KHAMTI HA;Lo;0;L;;;;;N;;;;; -AA6E;MYANMAR LETTER KHAMTI HHA;Lo;0;L;;;;;N;;;;; -AA6F;MYANMAR LETTER KHAMTI FA;Lo;0;L;;;;;N;;;;; -AA70;MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION;Lm;0;L;;;;;N;;;;; -AA71;MYANMAR LETTER KHAMTI XA;Lo;0;L;;;;;N;;;;; -AA72;MYANMAR LETTER KHAMTI ZA;Lo;0;L;;;;;N;;;;; -AA73;MYANMAR LETTER KHAMTI RA;Lo;0;L;;;;;N;;;;; -AA74;MYANMAR LOGOGRAM KHAMTI OAY;Lo;0;L;;;;;N;;;;; -AA75;MYANMAR LOGOGRAM KHAMTI QN;Lo;0;L;;;;;N;;;;; -AA76;MYANMAR LOGOGRAM KHAMTI HM;Lo;0;L;;;;;N;;;;; -AA77;MYANMAR SYMBOL AITON EXCLAMATION;So;0;L;;;;;N;;;;; -AA78;MYANMAR SYMBOL AITON ONE;So;0;L;;;;;N;;;;; -AA79;MYANMAR SYMBOL AITON TWO;So;0;L;;;;;N;;;;; -AA7A;MYANMAR LETTER AITON RA;Lo;0;L;;;;;N;;;;; -AA7B;MYANMAR SIGN PAO KAREN TONE;Mc;0;L;;;;;N;;;;; -AA7C;MYANMAR SIGN TAI LAING TONE-2;Mn;0;NSM;;;;;N;;;;; -AA7D;MYANMAR SIGN TAI LAING TONE-5;Mc;0;L;;;;;N;;;;; -AA7E;MYANMAR LETTER SHWE PALAUNG CHA;Lo;0;L;;;;;N;;;;; -AA7F;MYANMAR LETTER SHWE PALAUNG SHA;Lo;0;L;;;;;N;;;;; -AA80;TAI VIET LETTER LOW KO;Lo;0;L;;;;;N;;;;; -AA81;TAI VIET LETTER HIGH KO;Lo;0;L;;;;;N;;;;; -AA82;TAI VIET LETTER LOW KHO;Lo;0;L;;;;;N;;;;; -AA83;TAI VIET LETTER HIGH KHO;Lo;0;L;;;;;N;;;;; -AA84;TAI VIET LETTER LOW KHHO;Lo;0;L;;;;;N;;;;; -AA85;TAI VIET LETTER HIGH KHHO;Lo;0;L;;;;;N;;;;; -AA86;TAI VIET LETTER LOW GO;Lo;0;L;;;;;N;;;;; -AA87;TAI VIET LETTER HIGH GO;Lo;0;L;;;;;N;;;;; -AA88;TAI VIET LETTER LOW NGO;Lo;0;L;;;;;N;;;;; -AA89;TAI VIET LETTER HIGH NGO;Lo;0;L;;;;;N;;;;; -AA8A;TAI VIET LETTER LOW CO;Lo;0;L;;;;;N;;;;; -AA8B;TAI VIET LETTER HIGH CO;Lo;0;L;;;;;N;;;;; -AA8C;TAI VIET LETTER LOW CHO;Lo;0;L;;;;;N;;;;; -AA8D;TAI VIET LETTER HIGH CHO;Lo;0;L;;;;;N;;;;; -AA8E;TAI VIET LETTER LOW SO;Lo;0;L;;;;;N;;;;; -AA8F;TAI VIET LETTER HIGH SO;Lo;0;L;;;;;N;;;;; -AA90;TAI VIET LETTER LOW NYO;Lo;0;L;;;;;N;;;;; -AA91;TAI VIET LETTER HIGH NYO;Lo;0;L;;;;;N;;;;; -AA92;TAI VIET LETTER LOW DO;Lo;0;L;;;;;N;;;;; -AA93;TAI VIET LETTER HIGH DO;Lo;0;L;;;;;N;;;;; -AA94;TAI VIET LETTER LOW TO;Lo;0;L;;;;;N;;;;; -AA95;TAI VIET LETTER HIGH TO;Lo;0;L;;;;;N;;;;; -AA96;TAI VIET LETTER LOW THO;Lo;0;L;;;;;N;;;;; -AA97;TAI VIET LETTER HIGH THO;Lo;0;L;;;;;N;;;;; -AA98;TAI VIET LETTER LOW NO;Lo;0;L;;;;;N;;;;; -AA99;TAI VIET LETTER HIGH NO;Lo;0;L;;;;;N;;;;; -AA9A;TAI VIET LETTER LOW BO;Lo;0;L;;;;;N;;;;; -AA9B;TAI VIET LETTER HIGH BO;Lo;0;L;;;;;N;;;;; -AA9C;TAI VIET LETTER LOW PO;Lo;0;L;;;;;N;;;;; -AA9D;TAI VIET LETTER HIGH PO;Lo;0;L;;;;;N;;;;; -AA9E;TAI VIET LETTER LOW PHO;Lo;0;L;;;;;N;;;;; -AA9F;TAI VIET LETTER HIGH PHO;Lo;0;L;;;;;N;;;;; -AAA0;TAI VIET LETTER LOW FO;Lo;0;L;;;;;N;;;;; -AAA1;TAI VIET LETTER HIGH FO;Lo;0;L;;;;;N;;;;; -AAA2;TAI VIET LETTER LOW MO;Lo;0;L;;;;;N;;;;; -AAA3;TAI VIET LETTER HIGH MO;Lo;0;L;;;;;N;;;;; -AAA4;TAI VIET LETTER LOW YO;Lo;0;L;;;;;N;;;;; -AAA5;TAI VIET LETTER HIGH YO;Lo;0;L;;;;;N;;;;; -AAA6;TAI VIET LETTER LOW RO;Lo;0;L;;;;;N;;;;; -AAA7;TAI VIET LETTER HIGH RO;Lo;0;L;;;;;N;;;;; -AAA8;TAI VIET LETTER LOW LO;Lo;0;L;;;;;N;;;;; -AAA9;TAI VIET LETTER HIGH LO;Lo;0;L;;;;;N;;;;; -AAAA;TAI VIET LETTER LOW VO;Lo;0;L;;;;;N;;;;; -AAAB;TAI VIET LETTER HIGH VO;Lo;0;L;;;;;N;;;;; -AAAC;TAI VIET LETTER LOW HO;Lo;0;L;;;;;N;;;;; -AAAD;TAI VIET LETTER HIGH HO;Lo;0;L;;;;;N;;;;; -AAAE;TAI VIET LETTER LOW O;Lo;0;L;;;;;N;;;;; -AAAF;TAI VIET LETTER HIGH O;Lo;0;L;;;;;N;;;;; -AAB0;TAI VIET MAI KANG;Mn;230;NSM;;;;;N;;;;; -AAB1;TAI VIET VOWEL AA;Lo;0;L;;;;;N;;;;; -AAB2;TAI VIET VOWEL I;Mn;230;NSM;;;;;N;;;;; -AAB3;TAI VIET VOWEL UE;Mn;230;NSM;;;;;N;;;;; -AAB4;TAI VIET VOWEL U;Mn;220;NSM;;;;;N;;;;; -AAB5;TAI VIET VOWEL E;Lo;0;L;;;;;N;;;;; -AAB6;TAI VIET VOWEL O;Lo;0;L;;;;;N;;;;; -AAB7;TAI VIET MAI KHIT;Mn;230;NSM;;;;;N;;;;; -AAB8;TAI VIET VOWEL IA;Mn;230;NSM;;;;;N;;;;; -AAB9;TAI VIET VOWEL UEA;Lo;0;L;;;;;N;;;;; -AABA;TAI VIET VOWEL UA;Lo;0;L;;;;;N;;;;; -AABB;TAI VIET VOWEL AUE;Lo;0;L;;;;;N;;;;; -AABC;TAI VIET VOWEL AY;Lo;0;L;;;;;N;;;;; -AABD;TAI VIET VOWEL AN;Lo;0;L;;;;;N;;;;; -AABE;TAI VIET VOWEL AM;Mn;230;NSM;;;;;N;;;;; -AABF;TAI VIET TONE MAI EK;Mn;230;NSM;;;;;N;;;;; -AAC0;TAI VIET TONE MAI NUENG;Lo;0;L;;;;;N;;;;; -AAC1;TAI VIET TONE MAI THO;Mn;230;NSM;;;;;N;;;;; -AAC2;TAI VIET TONE MAI SONG;Lo;0;L;;;;;N;;;;; -AADB;TAI VIET SYMBOL KON;Lo;0;L;;;;;N;;;;; -AADC;TAI VIET SYMBOL NUENG;Lo;0;L;;;;;N;;;;; -AADD;TAI VIET SYMBOL SAM;Lm;0;L;;;;;N;;;;; -AADE;TAI VIET SYMBOL HO HOI;Po;0;L;;;;;N;;;;; -AADF;TAI VIET SYMBOL KOI KOI;Po;0;L;;;;;N;;;;; -AAE0;MEETEI MAYEK LETTER E;Lo;0;L;;;;;N;;;;; -AAE1;MEETEI MAYEK LETTER O;Lo;0;L;;;;;N;;;;; -AAE2;MEETEI MAYEK LETTER CHA;Lo;0;L;;;;;N;;;;; -AAE3;MEETEI MAYEK LETTER NYA;Lo;0;L;;;;;N;;;;; -AAE4;MEETEI MAYEK LETTER TTA;Lo;0;L;;;;;N;;;;; -AAE5;MEETEI MAYEK LETTER TTHA;Lo;0;L;;;;;N;;;;; -AAE6;MEETEI MAYEK LETTER DDA;Lo;0;L;;;;;N;;;;; -AAE7;MEETEI MAYEK LETTER DDHA;Lo;0;L;;;;;N;;;;; -AAE8;MEETEI MAYEK LETTER NNA;Lo;0;L;;;;;N;;;;; -AAE9;MEETEI MAYEK LETTER SHA;Lo;0;L;;;;;N;;;;; -AAEA;MEETEI MAYEK LETTER SSA;Lo;0;L;;;;;N;;;;; -AAEB;MEETEI MAYEK VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -AAEC;MEETEI MAYEK VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -AAED;MEETEI MAYEK VOWEL SIGN AAI;Mn;0;NSM;;;;;N;;;;; -AAEE;MEETEI MAYEK VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; -AAEF;MEETEI MAYEK VOWEL SIGN AAU;Mc;0;L;;;;;N;;;;; -AAF0;MEETEI MAYEK CHEIKHAN;Po;0;L;;;;;N;;;;; -AAF1;MEETEI MAYEK AHANG KHUDAM;Po;0;L;;;;;N;;;;; -AAF2;MEETEI MAYEK ANJI;Lo;0;L;;;;;N;;;;; -AAF3;MEETEI MAYEK SYLLABLE REPETITION MARK;Lm;0;L;;;;;N;;;;; -AAF4;MEETEI MAYEK WORD REPETITION MARK;Lm;0;L;;;;;N;;;;; -AAF5;MEETEI MAYEK VOWEL SIGN VISARGA;Mc;0;L;;;;;N;;;;; -AAF6;MEETEI MAYEK VIRAMA;Mn;9;NSM;;;;;N;;;;; -AB01;ETHIOPIC SYLLABLE TTHU;Lo;0;L;;;;;N;;;;; -AB02;ETHIOPIC SYLLABLE TTHI;Lo;0;L;;;;;N;;;;; -AB03;ETHIOPIC SYLLABLE TTHAA;Lo;0;L;;;;;N;;;;; -AB04;ETHIOPIC SYLLABLE TTHEE;Lo;0;L;;;;;N;;;;; -AB05;ETHIOPIC SYLLABLE TTHE;Lo;0;L;;;;;N;;;;; -AB06;ETHIOPIC SYLLABLE TTHO;Lo;0;L;;;;;N;;;;; -AB09;ETHIOPIC SYLLABLE DDHU;Lo;0;L;;;;;N;;;;; -AB0A;ETHIOPIC SYLLABLE DDHI;Lo;0;L;;;;;N;;;;; -AB0B;ETHIOPIC SYLLABLE DDHAA;Lo;0;L;;;;;N;;;;; -AB0C;ETHIOPIC SYLLABLE DDHEE;Lo;0;L;;;;;N;;;;; -AB0D;ETHIOPIC SYLLABLE DDHE;Lo;0;L;;;;;N;;;;; -AB0E;ETHIOPIC SYLLABLE DDHO;Lo;0;L;;;;;N;;;;; -AB11;ETHIOPIC SYLLABLE DZU;Lo;0;L;;;;;N;;;;; -AB12;ETHIOPIC SYLLABLE DZI;Lo;0;L;;;;;N;;;;; -AB13;ETHIOPIC SYLLABLE DZAA;Lo;0;L;;;;;N;;;;; -AB14;ETHIOPIC SYLLABLE DZEE;Lo;0;L;;;;;N;;;;; -AB15;ETHIOPIC SYLLABLE DZE;Lo;0;L;;;;;N;;;;; -AB16;ETHIOPIC SYLLABLE DZO;Lo;0;L;;;;;N;;;;; -AB20;ETHIOPIC SYLLABLE CCHHA;Lo;0;L;;;;;N;;;;; -AB21;ETHIOPIC SYLLABLE CCHHU;Lo;0;L;;;;;N;;;;; -AB22;ETHIOPIC SYLLABLE CCHHI;Lo;0;L;;;;;N;;;;; -AB23;ETHIOPIC SYLLABLE CCHHAA;Lo;0;L;;;;;N;;;;; -AB24;ETHIOPIC SYLLABLE CCHHEE;Lo;0;L;;;;;N;;;;; -AB25;ETHIOPIC SYLLABLE CCHHE;Lo;0;L;;;;;N;;;;; -AB26;ETHIOPIC SYLLABLE CCHHO;Lo;0;L;;;;;N;;;;; -AB28;ETHIOPIC SYLLABLE BBA;Lo;0;L;;;;;N;;;;; -AB29;ETHIOPIC SYLLABLE BBU;Lo;0;L;;;;;N;;;;; -AB2A;ETHIOPIC SYLLABLE BBI;Lo;0;L;;;;;N;;;;; -AB2B;ETHIOPIC SYLLABLE BBAA;Lo;0;L;;;;;N;;;;; -AB2C;ETHIOPIC SYLLABLE BBEE;Lo;0;L;;;;;N;;;;; -AB2D;ETHIOPIC SYLLABLE BBE;Lo;0;L;;;;;N;;;;; -AB2E;ETHIOPIC SYLLABLE BBO;Lo;0;L;;;;;N;;;;; -AB30;LATIN SMALL LETTER BARRED ALPHA;Ll;0;L;;;;;N;;;;; -AB31;LATIN SMALL LETTER A REVERSED-SCHWA;Ll;0;L;;;;;N;;;;; -AB32;LATIN SMALL LETTER BLACKLETTER E;Ll;0;L;;;;;N;;;;; -AB33;LATIN SMALL LETTER BARRED E;Ll;0;L;;;;;N;;;;; -AB34;LATIN SMALL LETTER E WITH FLOURISH;Ll;0;L;;;;;N;;;;; -AB35;LATIN SMALL LETTER LENIS F;Ll;0;L;;;;;N;;;;; -AB36;LATIN SMALL LETTER SCRIPT G WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;; -AB37;LATIN SMALL LETTER L WITH INVERTED LAZY S;Ll;0;L;;;;;N;;;;; -AB38;LATIN SMALL LETTER L WITH DOUBLE MIDDLE TILDE;Ll;0;L;;;;;N;;;;; -AB39;LATIN SMALL LETTER L WITH MIDDLE RING;Ll;0;L;;;;;N;;;;; -AB3A;LATIN SMALL LETTER M WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;; -AB3B;LATIN SMALL LETTER N WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;; -AB3C;LATIN SMALL LETTER ENG WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;; -AB3D;LATIN SMALL LETTER BLACKLETTER O;Ll;0;L;;;;;N;;;;; -AB3E;LATIN SMALL LETTER BLACKLETTER O WITH STROKE;Ll;0;L;;;;;N;;;;; -AB3F;LATIN SMALL LETTER OPEN O WITH STROKE;Ll;0;L;;;;;N;;;;; -AB40;LATIN SMALL LETTER INVERTED OE;Ll;0;L;;;;;N;;;;; -AB41;LATIN SMALL LETTER TURNED OE WITH STROKE;Ll;0;L;;;;;N;;;;; -AB42;LATIN SMALL LETTER TURNED OE WITH HORIZONTAL STROKE;Ll;0;L;;;;;N;;;;; -AB43;LATIN SMALL LETTER TURNED O OPEN-O;Ll;0;L;;;;;N;;;;; -AB44;LATIN SMALL LETTER TURNED O OPEN-O WITH STROKE;Ll;0;L;;;;;N;;;;; -AB45;LATIN SMALL LETTER STIRRUP R;Ll;0;L;;;;;N;;;;; -AB46;LATIN LETTER SMALL CAPITAL R WITH RIGHT LEG;Ll;0;L;;;;;N;;;;; -AB47;LATIN SMALL LETTER R WITHOUT HANDLE;Ll;0;L;;;;;N;;;;; -AB48;LATIN SMALL LETTER DOUBLE R;Ll;0;L;;;;;N;;;;; -AB49;LATIN SMALL LETTER R WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;; -AB4A;LATIN SMALL LETTER DOUBLE R WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;; -AB4B;LATIN SMALL LETTER SCRIPT R;Ll;0;L;;;;;N;;;;; -AB4C;LATIN SMALL LETTER SCRIPT R WITH RING;Ll;0;L;;;;;N;;;;; -AB4D;LATIN SMALL LETTER BASELINE ESH;Ll;0;L;;;;;N;;;;; -AB4E;LATIN SMALL LETTER U WITH SHORT RIGHT LEG;Ll;0;L;;;;;N;;;;; -AB4F;LATIN SMALL LETTER U BAR WITH SHORT RIGHT LEG;Ll;0;L;;;;;N;;;;; -AB50;LATIN SMALL LETTER UI;Ll;0;L;;;;;N;;;;; -AB51;LATIN SMALL LETTER TURNED UI;Ll;0;L;;;;;N;;;;; -AB52;LATIN SMALL LETTER U WITH LEFT HOOK;Ll;0;L;;;;;N;;;;; -AB53;LATIN SMALL LETTER CHI;Ll;0;L;;;;;N;;;A7B3;;A7B3 -AB54;LATIN SMALL LETTER CHI WITH LOW RIGHT RING;Ll;0;L;;;;;N;;;;; -AB55;LATIN SMALL LETTER CHI WITH LOW LEFT SERIF;Ll;0;L;;;;;N;;;;; -AB56;LATIN SMALL LETTER X WITH LOW RIGHT RING;Ll;0;L;;;;;N;;;;; -AB57;LATIN SMALL LETTER X WITH LONG LEFT LEG;Ll;0;L;;;;;N;;;;; -AB58;LATIN SMALL LETTER X WITH LONG LEFT LEG AND LOW RIGHT RING;Ll;0;L;;;;;N;;;;; -AB59;LATIN SMALL LETTER X WITH LONG LEFT LEG WITH SERIF;Ll;0;L;;;;;N;;;;; -AB5A;LATIN SMALL LETTER Y WITH SHORT RIGHT LEG;Ll;0;L;;;;;N;;;;; -AB5B;MODIFIER BREVE WITH INVERTED BREVE;Sk;0;L;;;;;N;;;;; -AB5C;MODIFIER LETTER SMALL HENG;Lm;0;L;<super> A727;;;;N;;;;; -AB5D;MODIFIER LETTER SMALL L WITH INVERTED LAZY S;Lm;0;L;<super> AB37;;;;N;;;;; -AB5E;MODIFIER LETTER SMALL L WITH MIDDLE TILDE;Lm;0;L;<super> 026B;;;;N;;;;; -AB5F;MODIFIER LETTER SMALL U WITH LEFT HOOK;Lm;0;L;<super> AB52;;;;N;;;;; -AB60;LATIN SMALL LETTER SAKHA YAT;Ll;0;L;;;;;N;;;;; -AB61;LATIN SMALL LETTER IOTIFIED E;Ll;0;L;;;;;N;;;;; -AB62;LATIN SMALL LETTER OPEN OE;Ll;0;L;;;;;N;;;;; -AB63;LATIN SMALL LETTER UO;Ll;0;L;;;;;N;;;;; -AB64;LATIN SMALL LETTER INVERTED ALPHA;Ll;0;L;;;;;N;;;;; -AB65;GREEK LETTER SMALL CAPITAL OMEGA;Ll;0;L;;;;;N;;;;; -AB66;LATIN SMALL LETTER DZ DIGRAPH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -AB67;LATIN SMALL LETTER TS DIGRAPH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -AB68;LATIN SMALL LETTER TURNED R WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; -AB69;MODIFIER LETTER SMALL TURNED W;Lm;0;L;<super> 028D;;;;N;;;;; -AB6A;MODIFIER LETTER LEFT TACK;Sk;0;ON;;;;;N;;;;; -AB6B;MODIFIER LETTER RIGHT TACK;Sk;0;ON;;;;;N;;;;; -AB70;CHEROKEE SMALL LETTER A;Ll;0;L;;;;;N;;;13A0;;13A0 -AB71;CHEROKEE SMALL LETTER E;Ll;0;L;;;;;N;;;13A1;;13A1 -AB72;CHEROKEE SMALL LETTER I;Ll;0;L;;;;;N;;;13A2;;13A2 -AB73;CHEROKEE SMALL LETTER O;Ll;0;L;;;;;N;;;13A3;;13A3 -AB74;CHEROKEE SMALL LETTER U;Ll;0;L;;;;;N;;;13A4;;13A4 -AB75;CHEROKEE SMALL LETTER V;Ll;0;L;;;;;N;;;13A5;;13A5 -AB76;CHEROKEE SMALL LETTER GA;Ll;0;L;;;;;N;;;13A6;;13A6 -AB77;CHEROKEE SMALL LETTER KA;Ll;0;L;;;;;N;;;13A7;;13A7 -AB78;CHEROKEE SMALL LETTER GE;Ll;0;L;;;;;N;;;13A8;;13A8 -AB79;CHEROKEE SMALL LETTER GI;Ll;0;L;;;;;N;;;13A9;;13A9 -AB7A;CHEROKEE SMALL LETTER GO;Ll;0;L;;;;;N;;;13AA;;13AA -AB7B;CHEROKEE SMALL LETTER GU;Ll;0;L;;;;;N;;;13AB;;13AB -AB7C;CHEROKEE SMALL LETTER GV;Ll;0;L;;;;;N;;;13AC;;13AC -AB7D;CHEROKEE SMALL LETTER HA;Ll;0;L;;;;;N;;;13AD;;13AD -AB7E;CHEROKEE SMALL LETTER HE;Ll;0;L;;;;;N;;;13AE;;13AE -AB7F;CHEROKEE SMALL LETTER HI;Ll;0;L;;;;;N;;;13AF;;13AF -AB80;CHEROKEE SMALL LETTER HO;Ll;0;L;;;;;N;;;13B0;;13B0 -AB81;CHEROKEE SMALL LETTER HU;Ll;0;L;;;;;N;;;13B1;;13B1 -AB82;CHEROKEE SMALL LETTER HV;Ll;0;L;;;;;N;;;13B2;;13B2 -AB83;CHEROKEE SMALL LETTER LA;Ll;0;L;;;;;N;;;13B3;;13B3 -AB84;CHEROKEE SMALL LETTER LE;Ll;0;L;;;;;N;;;13B4;;13B4 -AB85;CHEROKEE SMALL LETTER LI;Ll;0;L;;;;;N;;;13B5;;13B5 -AB86;CHEROKEE SMALL LETTER LO;Ll;0;L;;;;;N;;;13B6;;13B6 -AB87;CHEROKEE SMALL LETTER LU;Ll;0;L;;;;;N;;;13B7;;13B7 -AB88;CHEROKEE SMALL LETTER LV;Ll;0;L;;;;;N;;;13B8;;13B8 -AB89;CHEROKEE SMALL LETTER MA;Ll;0;L;;;;;N;;;13B9;;13B9 -AB8A;CHEROKEE SMALL LETTER ME;Ll;0;L;;;;;N;;;13BA;;13BA -AB8B;CHEROKEE SMALL LETTER MI;Ll;0;L;;;;;N;;;13BB;;13BB -AB8C;CHEROKEE SMALL LETTER MO;Ll;0;L;;;;;N;;;13BC;;13BC -AB8D;CHEROKEE SMALL LETTER MU;Ll;0;L;;;;;N;;;13BD;;13BD -AB8E;CHEROKEE SMALL LETTER NA;Ll;0;L;;;;;N;;;13BE;;13BE -AB8F;CHEROKEE SMALL LETTER HNA;Ll;0;L;;;;;N;;;13BF;;13BF -AB90;CHEROKEE SMALL LETTER NAH;Ll;0;L;;;;;N;;;13C0;;13C0 -AB91;CHEROKEE SMALL LETTER NE;Ll;0;L;;;;;N;;;13C1;;13C1 -AB92;CHEROKEE SMALL LETTER NI;Ll;0;L;;;;;N;;;13C2;;13C2 -AB93;CHEROKEE SMALL LETTER NO;Ll;0;L;;;;;N;;;13C3;;13C3 -AB94;CHEROKEE SMALL LETTER NU;Ll;0;L;;;;;N;;;13C4;;13C4 -AB95;CHEROKEE SMALL LETTER NV;Ll;0;L;;;;;N;;;13C5;;13C5 -AB96;CHEROKEE SMALL LETTER QUA;Ll;0;L;;;;;N;;;13C6;;13C6 -AB97;CHEROKEE SMALL LETTER QUE;Ll;0;L;;;;;N;;;13C7;;13C7 -AB98;CHEROKEE SMALL LETTER QUI;Ll;0;L;;;;;N;;;13C8;;13C8 -AB99;CHEROKEE SMALL LETTER QUO;Ll;0;L;;;;;N;;;13C9;;13C9 -AB9A;CHEROKEE SMALL LETTER QUU;Ll;0;L;;;;;N;;;13CA;;13CA -AB9B;CHEROKEE SMALL LETTER QUV;Ll;0;L;;;;;N;;;13CB;;13CB -AB9C;CHEROKEE SMALL LETTER SA;Ll;0;L;;;;;N;;;13CC;;13CC -AB9D;CHEROKEE SMALL LETTER S;Ll;0;L;;;;;N;;;13CD;;13CD -AB9E;CHEROKEE SMALL LETTER SE;Ll;0;L;;;;;N;;;13CE;;13CE -AB9F;CHEROKEE SMALL LETTER SI;Ll;0;L;;;;;N;;;13CF;;13CF -ABA0;CHEROKEE SMALL LETTER SO;Ll;0;L;;;;;N;;;13D0;;13D0 -ABA1;CHEROKEE SMALL LETTER SU;Ll;0;L;;;;;N;;;13D1;;13D1 -ABA2;CHEROKEE SMALL LETTER SV;Ll;0;L;;;;;N;;;13D2;;13D2 -ABA3;CHEROKEE SMALL LETTER DA;Ll;0;L;;;;;N;;;13D3;;13D3 -ABA4;CHEROKEE SMALL LETTER TA;Ll;0;L;;;;;N;;;13D4;;13D4 -ABA5;CHEROKEE SMALL LETTER DE;Ll;0;L;;;;;N;;;13D5;;13D5 -ABA6;CHEROKEE SMALL LETTER TE;Ll;0;L;;;;;N;;;13D6;;13D6 -ABA7;CHEROKEE SMALL LETTER DI;Ll;0;L;;;;;N;;;13D7;;13D7 -ABA8;CHEROKEE SMALL LETTER TI;Ll;0;L;;;;;N;;;13D8;;13D8 -ABA9;CHEROKEE SMALL LETTER DO;Ll;0;L;;;;;N;;;13D9;;13D9 -ABAA;CHEROKEE SMALL LETTER DU;Ll;0;L;;;;;N;;;13DA;;13DA -ABAB;CHEROKEE SMALL LETTER DV;Ll;0;L;;;;;N;;;13DB;;13DB -ABAC;CHEROKEE SMALL LETTER DLA;Ll;0;L;;;;;N;;;13DC;;13DC -ABAD;CHEROKEE SMALL LETTER TLA;Ll;0;L;;;;;N;;;13DD;;13DD -ABAE;CHEROKEE SMALL LETTER TLE;Ll;0;L;;;;;N;;;13DE;;13DE -ABAF;CHEROKEE SMALL LETTER TLI;Ll;0;L;;;;;N;;;13DF;;13DF -ABB0;CHEROKEE SMALL LETTER TLO;Ll;0;L;;;;;N;;;13E0;;13E0 -ABB1;CHEROKEE SMALL LETTER TLU;Ll;0;L;;;;;N;;;13E1;;13E1 -ABB2;CHEROKEE SMALL LETTER TLV;Ll;0;L;;;;;N;;;13E2;;13E2 -ABB3;CHEROKEE SMALL LETTER TSA;Ll;0;L;;;;;N;;;13E3;;13E3 -ABB4;CHEROKEE SMALL LETTER TSE;Ll;0;L;;;;;N;;;13E4;;13E4 -ABB5;CHEROKEE SMALL LETTER TSI;Ll;0;L;;;;;N;;;13E5;;13E5 -ABB6;CHEROKEE SMALL LETTER TSO;Ll;0;L;;;;;N;;;13E6;;13E6 -ABB7;CHEROKEE SMALL LETTER TSU;Ll;0;L;;;;;N;;;13E7;;13E7 -ABB8;CHEROKEE SMALL LETTER TSV;Ll;0;L;;;;;N;;;13E8;;13E8 -ABB9;CHEROKEE SMALL LETTER WA;Ll;0;L;;;;;N;;;13E9;;13E9 -ABBA;CHEROKEE SMALL LETTER WE;Ll;0;L;;;;;N;;;13EA;;13EA -ABBB;CHEROKEE SMALL LETTER WI;Ll;0;L;;;;;N;;;13EB;;13EB -ABBC;CHEROKEE SMALL LETTER WO;Ll;0;L;;;;;N;;;13EC;;13EC -ABBD;CHEROKEE SMALL LETTER WU;Ll;0;L;;;;;N;;;13ED;;13ED -ABBE;CHEROKEE SMALL LETTER WV;Ll;0;L;;;;;N;;;13EE;;13EE -ABBF;CHEROKEE SMALL LETTER YA;Ll;0;L;;;;;N;;;13EF;;13EF -ABC0;MEETEI MAYEK LETTER KOK;Lo;0;L;;;;;N;;;;; -ABC1;MEETEI MAYEK LETTER SAM;Lo;0;L;;;;;N;;;;; -ABC2;MEETEI MAYEK LETTER LAI;Lo;0;L;;;;;N;;;;; -ABC3;MEETEI MAYEK LETTER MIT;Lo;0;L;;;;;N;;;;; -ABC4;MEETEI MAYEK LETTER PA;Lo;0;L;;;;;N;;;;; -ABC5;MEETEI MAYEK LETTER NA;Lo;0;L;;;;;N;;;;; -ABC6;MEETEI MAYEK LETTER CHIL;Lo;0;L;;;;;N;;;;; -ABC7;MEETEI MAYEK LETTER TIL;Lo;0;L;;;;;N;;;;; -ABC8;MEETEI MAYEK LETTER KHOU;Lo;0;L;;;;;N;;;;; -ABC9;MEETEI MAYEK LETTER NGOU;Lo;0;L;;;;;N;;;;; -ABCA;MEETEI MAYEK LETTER THOU;Lo;0;L;;;;;N;;;;; -ABCB;MEETEI MAYEK LETTER WAI;Lo;0;L;;;;;N;;;;; -ABCC;MEETEI MAYEK LETTER YANG;Lo;0;L;;;;;N;;;;; -ABCD;MEETEI MAYEK LETTER HUK;Lo;0;L;;;;;N;;;;; -ABCE;MEETEI MAYEK LETTER UN;Lo;0;L;;;;;N;;;;; -ABCF;MEETEI MAYEK LETTER I;Lo;0;L;;;;;N;;;;; -ABD0;MEETEI MAYEK LETTER PHAM;Lo;0;L;;;;;N;;;;; -ABD1;MEETEI MAYEK LETTER ATIYA;Lo;0;L;;;;;N;;;;; -ABD2;MEETEI MAYEK LETTER GOK;Lo;0;L;;;;;N;;;;; -ABD3;MEETEI MAYEK LETTER JHAM;Lo;0;L;;;;;N;;;;; -ABD4;MEETEI MAYEK LETTER RAI;Lo;0;L;;;;;N;;;;; -ABD5;MEETEI MAYEK LETTER BA;Lo;0;L;;;;;N;;;;; -ABD6;MEETEI MAYEK LETTER JIL;Lo;0;L;;;;;N;;;;; -ABD7;MEETEI MAYEK LETTER DIL;Lo;0;L;;;;;N;;;;; -ABD8;MEETEI MAYEK LETTER GHOU;Lo;0;L;;;;;N;;;;; -ABD9;MEETEI MAYEK LETTER DHOU;Lo;0;L;;;;;N;;;;; -ABDA;MEETEI MAYEK LETTER BHAM;Lo;0;L;;;;;N;;;;; -ABDB;MEETEI MAYEK LETTER KOK LONSUM;Lo;0;L;;;;;N;;;;; -ABDC;MEETEI MAYEK LETTER LAI LONSUM;Lo;0;L;;;;;N;;;;; -ABDD;MEETEI MAYEK LETTER MIT LONSUM;Lo;0;L;;;;;N;;;;; -ABDE;MEETEI MAYEK LETTER PA LONSUM;Lo;0;L;;;;;N;;;;; -ABDF;MEETEI MAYEK LETTER NA LONSUM;Lo;0;L;;;;;N;;;;; -ABE0;MEETEI MAYEK LETTER TIL LONSUM;Lo;0;L;;;;;N;;;;; -ABE1;MEETEI MAYEK LETTER NGOU LONSUM;Lo;0;L;;;;;N;;;;; -ABE2;MEETEI MAYEK LETTER I LONSUM;Lo;0;L;;;;;N;;;;; -ABE3;MEETEI MAYEK VOWEL SIGN ONAP;Mc;0;L;;;;;N;;;;; -ABE4;MEETEI MAYEK VOWEL SIGN INAP;Mc;0;L;;;;;N;;;;; -ABE5;MEETEI MAYEK VOWEL SIGN ANAP;Mn;0;NSM;;;;;N;;;;; -ABE6;MEETEI MAYEK VOWEL SIGN YENAP;Mc;0;L;;;;;N;;;;; -ABE7;MEETEI MAYEK VOWEL SIGN SOUNAP;Mc;0;L;;;;;N;;;;; -ABE8;MEETEI MAYEK VOWEL SIGN UNAP;Mn;0;NSM;;;;;N;;;;; -ABE9;MEETEI MAYEK VOWEL SIGN CHEINAP;Mc;0;L;;;;;N;;;;; -ABEA;MEETEI MAYEK VOWEL SIGN NUNG;Mc;0;L;;;;;N;;;;; -ABEB;MEETEI MAYEK CHEIKHEI;Po;0;L;;;;;N;;;;; -ABEC;MEETEI MAYEK LUM IYEK;Mc;0;L;;;;;N;;;;; -ABED;MEETEI MAYEK APUN IYEK;Mn;9;NSM;;;;;N;;;;; -ABF0;MEETEI MAYEK DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -ABF1;MEETEI MAYEK DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -ABF2;MEETEI MAYEK DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -ABF3;MEETEI MAYEK DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -ABF4;MEETEI MAYEK DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -ABF5;MEETEI MAYEK DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -ABF6;MEETEI MAYEK DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -ABF7;MEETEI MAYEK DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -ABF8;MEETEI MAYEK DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -ABF9;MEETEI MAYEK DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -AC00;<Hangul Syllable, First>;Lo;0;L;;;;;N;;;;; -D7A3;<Hangul Syllable, Last>;Lo;0;L;;;;;N;;;;; -D7B0;HANGUL JUNGSEONG O-YEO;Lo;0;L;;;;;N;;;;; -D7B1;HANGUL JUNGSEONG O-O-I;Lo;0;L;;;;;N;;;;; -D7B2;HANGUL JUNGSEONG YO-A;Lo;0;L;;;;;N;;;;; -D7B3;HANGUL JUNGSEONG YO-AE;Lo;0;L;;;;;N;;;;; -D7B4;HANGUL JUNGSEONG YO-EO;Lo;0;L;;;;;N;;;;; -D7B5;HANGUL JUNGSEONG U-YEO;Lo;0;L;;;;;N;;;;; -D7B6;HANGUL JUNGSEONG U-I-I;Lo;0;L;;;;;N;;;;; -D7B7;HANGUL JUNGSEONG YU-AE;Lo;0;L;;;;;N;;;;; -D7B8;HANGUL JUNGSEONG YU-O;Lo;0;L;;;;;N;;;;; -D7B9;HANGUL JUNGSEONG EU-A;Lo;0;L;;;;;N;;;;; -D7BA;HANGUL JUNGSEONG EU-EO;Lo;0;L;;;;;N;;;;; -D7BB;HANGUL JUNGSEONG EU-E;Lo;0;L;;;;;N;;;;; -D7BC;HANGUL JUNGSEONG EU-O;Lo;0;L;;;;;N;;;;; -D7BD;HANGUL JUNGSEONG I-YA-O;Lo;0;L;;;;;N;;;;; -D7BE;HANGUL JUNGSEONG I-YAE;Lo;0;L;;;;;N;;;;; -D7BF;HANGUL JUNGSEONG I-YEO;Lo;0;L;;;;;N;;;;; -D7C0;HANGUL JUNGSEONG I-YE;Lo;0;L;;;;;N;;;;; -D7C1;HANGUL JUNGSEONG I-O-I;Lo;0;L;;;;;N;;;;; -D7C2;HANGUL JUNGSEONG I-YO;Lo;0;L;;;;;N;;;;; -D7C3;HANGUL JUNGSEONG I-YU;Lo;0;L;;;;;N;;;;; -D7C4;HANGUL JUNGSEONG I-I;Lo;0;L;;;;;N;;;;; -D7C5;HANGUL JUNGSEONG ARAEA-A;Lo;0;L;;;;;N;;;;; -D7C6;HANGUL JUNGSEONG ARAEA-E;Lo;0;L;;;;;N;;;;; -D7CB;HANGUL JONGSEONG NIEUN-RIEUL;Lo;0;L;;;;;N;;;;; -D7CC;HANGUL JONGSEONG NIEUN-CHIEUCH;Lo;0;L;;;;;N;;;;; -D7CD;HANGUL JONGSEONG SSANGTIKEUT;Lo;0;L;;;;;N;;;;; -D7CE;HANGUL JONGSEONG SSANGTIKEUT-PIEUP;Lo;0;L;;;;;N;;;;; -D7CF;HANGUL JONGSEONG TIKEUT-PIEUP;Lo;0;L;;;;;N;;;;; -D7D0;HANGUL JONGSEONG TIKEUT-SIOS;Lo;0;L;;;;;N;;;;; -D7D1;HANGUL JONGSEONG TIKEUT-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; -D7D2;HANGUL JONGSEONG TIKEUT-CIEUC;Lo;0;L;;;;;N;;;;; -D7D3;HANGUL JONGSEONG TIKEUT-CHIEUCH;Lo;0;L;;;;;N;;;;; -D7D4;HANGUL JONGSEONG TIKEUT-THIEUTH;Lo;0;L;;;;;N;;;;; -D7D5;HANGUL JONGSEONG RIEUL-SSANGKIYEOK;Lo;0;L;;;;;N;;;;; -D7D6;HANGUL JONGSEONG RIEUL-KIYEOK-HIEUH;Lo;0;L;;;;;N;;;;; -D7D7;HANGUL JONGSEONG SSANGRIEUL-KHIEUKH;Lo;0;L;;;;;N;;;;; -D7D8;HANGUL JONGSEONG RIEUL-MIEUM-HIEUH;Lo;0;L;;;;;N;;;;; -D7D9;HANGUL JONGSEONG RIEUL-PIEUP-TIKEUT;Lo;0;L;;;;;N;;;;; -D7DA;HANGUL JONGSEONG RIEUL-PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;; -D7DB;HANGUL JONGSEONG RIEUL-YESIEUNG;Lo;0;L;;;;;N;;;;; -D7DC;HANGUL JONGSEONG RIEUL-YEORINHIEUH-HIEUH;Lo;0;L;;;;;N;;;;; -D7DD;HANGUL JONGSEONG KAPYEOUNRIEUL;Lo;0;L;;;;;N;;;;; -D7DE;HANGUL JONGSEONG MIEUM-NIEUN;Lo;0;L;;;;;N;;;;; -D7DF;HANGUL JONGSEONG MIEUM-SSANGNIEUN;Lo;0;L;;;;;N;;;;; -D7E0;HANGUL JONGSEONG SSANGMIEUM;Lo;0;L;;;;;N;;;;; -D7E1;HANGUL JONGSEONG MIEUM-PIEUP-SIOS;Lo;0;L;;;;;N;;;;; -D7E2;HANGUL JONGSEONG MIEUM-CIEUC;Lo;0;L;;;;;N;;;;; -D7E3;HANGUL JONGSEONG PIEUP-TIKEUT;Lo;0;L;;;;;N;;;;; -D7E4;HANGUL JONGSEONG PIEUP-RIEUL-PHIEUPH;Lo;0;L;;;;;N;;;;; -D7E5;HANGUL JONGSEONG PIEUP-MIEUM;Lo;0;L;;;;;N;;;;; -D7E6;HANGUL JONGSEONG SSANGPIEUP;Lo;0;L;;;;;N;;;;; -D7E7;HANGUL JONGSEONG PIEUP-SIOS-TIKEUT;Lo;0;L;;;;;N;;;;; -D7E8;HANGUL JONGSEONG PIEUP-CIEUC;Lo;0;L;;;;;N;;;;; -D7E9;HANGUL JONGSEONG PIEUP-CHIEUCH;Lo;0;L;;;;;N;;;;; -D7EA;HANGUL JONGSEONG SIOS-MIEUM;Lo;0;L;;;;;N;;;;; -D7EB;HANGUL JONGSEONG SIOS-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; -D7EC;HANGUL JONGSEONG SSANGSIOS-KIYEOK;Lo;0;L;;;;;N;;;;; -D7ED;HANGUL JONGSEONG SSANGSIOS-TIKEUT;Lo;0;L;;;;;N;;;;; -D7EE;HANGUL JONGSEONG SIOS-PANSIOS;Lo;0;L;;;;;N;;;;; -D7EF;HANGUL JONGSEONG SIOS-CIEUC;Lo;0;L;;;;;N;;;;; -D7F0;HANGUL JONGSEONG SIOS-CHIEUCH;Lo;0;L;;;;;N;;;;; -D7F1;HANGUL JONGSEONG SIOS-THIEUTH;Lo;0;L;;;;;N;;;;; -D7F2;HANGUL JONGSEONG SIOS-HIEUH;Lo;0;L;;;;;N;;;;; -D7F3;HANGUL JONGSEONG PANSIOS-PIEUP;Lo;0;L;;;;;N;;;;; -D7F4;HANGUL JONGSEONG PANSIOS-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; -D7F5;HANGUL JONGSEONG YESIEUNG-MIEUM;Lo;0;L;;;;;N;;;;; -D7F6;HANGUL JONGSEONG YESIEUNG-HIEUH;Lo;0;L;;;;;N;;;;; -D7F7;HANGUL JONGSEONG CIEUC-PIEUP;Lo;0;L;;;;;N;;;;; -D7F8;HANGUL JONGSEONG CIEUC-SSANGPIEUP;Lo;0;L;;;;;N;;;;; -D7F9;HANGUL JONGSEONG SSANGCIEUC;Lo;0;L;;;;;N;;;;; -D7FA;HANGUL JONGSEONG PHIEUPH-SIOS;Lo;0;L;;;;;N;;;;; -D7FB;HANGUL JONGSEONG PHIEUPH-THIEUTH;Lo;0;L;;;;;N;;;;; -D800;<Non Private Use High Surrogate, First>;Cs;0;L;;;;;N;;;;; -DB7F;<Non Private Use High Surrogate, Last>;Cs;0;L;;;;;N;;;;; -DB80;<Private Use High Surrogate, First>;Cs;0;L;;;;;N;;;;; -DBFF;<Private Use High Surrogate, Last>;Cs;0;L;;;;;N;;;;; -DC00;<Low Surrogate, First>;Cs;0;L;;;;;N;;;;; -DFFF;<Low Surrogate, Last>;Cs;0;L;;;;;N;;;;; -E000;<Private Use, First>;Co;0;L;;;;;N;;;;; -F8FF;<Private Use, Last>;Co;0;L;;;;;N;;;;; -F900;CJK COMPATIBILITY IDEOGRAPH-F900;Lo;0;L;8C48;;;;N;;;;; -F901;CJK COMPATIBILITY IDEOGRAPH-F901;Lo;0;L;66F4;;;;N;;;;; -F902;CJK COMPATIBILITY IDEOGRAPH-F902;Lo;0;L;8ECA;;;;N;;;;; -F903;CJK COMPATIBILITY IDEOGRAPH-F903;Lo;0;L;8CC8;;;;N;;;;; -F904;CJK COMPATIBILITY IDEOGRAPH-F904;Lo;0;L;6ED1;;;;N;;;;; -F905;CJK COMPATIBILITY IDEOGRAPH-F905;Lo;0;L;4E32;;;;N;;;;; -F906;CJK COMPATIBILITY IDEOGRAPH-F906;Lo;0;L;53E5;;;;N;;;;; -F907;CJK COMPATIBILITY IDEOGRAPH-F907;Lo;0;L;9F9C;;;;N;;;;; -F908;CJK COMPATIBILITY IDEOGRAPH-F908;Lo;0;L;9F9C;;;;N;;;;; -F909;CJK COMPATIBILITY IDEOGRAPH-F909;Lo;0;L;5951;;;;N;;;;; -F90A;CJK COMPATIBILITY IDEOGRAPH-F90A;Lo;0;L;91D1;;;;N;;;;; -F90B;CJK COMPATIBILITY IDEOGRAPH-F90B;Lo;0;L;5587;;;;N;;;;; -F90C;CJK COMPATIBILITY IDEOGRAPH-F90C;Lo;0;L;5948;;;;N;;;;; -F90D;CJK COMPATIBILITY IDEOGRAPH-F90D;Lo;0;L;61F6;;;;N;;;;; -F90E;CJK COMPATIBILITY IDEOGRAPH-F90E;Lo;0;L;7669;;;;N;;;;; -F90F;CJK COMPATIBILITY IDEOGRAPH-F90F;Lo;0;L;7F85;;;;N;;;;; -F910;CJK COMPATIBILITY IDEOGRAPH-F910;Lo;0;L;863F;;;;N;;;;; -F911;CJK COMPATIBILITY IDEOGRAPH-F911;Lo;0;L;87BA;;;;N;;;;; -F912;CJK COMPATIBILITY IDEOGRAPH-F912;Lo;0;L;88F8;;;;N;;;;; -F913;CJK COMPATIBILITY IDEOGRAPH-F913;Lo;0;L;908F;;;;N;;;;; -F914;CJK COMPATIBILITY IDEOGRAPH-F914;Lo;0;L;6A02;;;;N;;;;; -F915;CJK COMPATIBILITY IDEOGRAPH-F915;Lo;0;L;6D1B;;;;N;;;;; -F916;CJK COMPATIBILITY IDEOGRAPH-F916;Lo;0;L;70D9;;;;N;;;;; -F917;CJK COMPATIBILITY IDEOGRAPH-F917;Lo;0;L;73DE;;;;N;;;;; -F918;CJK COMPATIBILITY IDEOGRAPH-F918;Lo;0;L;843D;;;;N;;;;; -F919;CJK COMPATIBILITY IDEOGRAPH-F919;Lo;0;L;916A;;;;N;;;;; -F91A;CJK COMPATIBILITY IDEOGRAPH-F91A;Lo;0;L;99F1;;;;N;;;;; -F91B;CJK COMPATIBILITY IDEOGRAPH-F91B;Lo;0;L;4E82;;;;N;;;;; -F91C;CJK COMPATIBILITY IDEOGRAPH-F91C;Lo;0;L;5375;;;;N;;;;; -F91D;CJK COMPATIBILITY IDEOGRAPH-F91D;Lo;0;L;6B04;;;;N;;;;; -F91E;CJK COMPATIBILITY IDEOGRAPH-F91E;Lo;0;L;721B;;;;N;;;;; -F91F;CJK COMPATIBILITY IDEOGRAPH-F91F;Lo;0;L;862D;;;;N;;;;; -F920;CJK COMPATIBILITY IDEOGRAPH-F920;Lo;0;L;9E1E;;;;N;;;;; -F921;CJK COMPATIBILITY IDEOGRAPH-F921;Lo;0;L;5D50;;;;N;;;;; -F922;CJK COMPATIBILITY IDEOGRAPH-F922;Lo;0;L;6FEB;;;;N;;;;; -F923;CJK COMPATIBILITY IDEOGRAPH-F923;Lo;0;L;85CD;;;;N;;;;; -F924;CJK COMPATIBILITY IDEOGRAPH-F924;Lo;0;L;8964;;;;N;;;;; -F925;CJK COMPATIBILITY IDEOGRAPH-F925;Lo;0;L;62C9;;;;N;;;;; -F926;CJK COMPATIBILITY IDEOGRAPH-F926;Lo;0;L;81D8;;;;N;;;;; -F927;CJK COMPATIBILITY IDEOGRAPH-F927;Lo;0;L;881F;;;;N;;;;; -F928;CJK COMPATIBILITY IDEOGRAPH-F928;Lo;0;L;5ECA;;;;N;;;;; -F929;CJK COMPATIBILITY IDEOGRAPH-F929;Lo;0;L;6717;;;;N;;;;; -F92A;CJK COMPATIBILITY IDEOGRAPH-F92A;Lo;0;L;6D6A;;;;N;;;;; -F92B;CJK COMPATIBILITY IDEOGRAPH-F92B;Lo;0;L;72FC;;;;N;;;;; -F92C;CJK COMPATIBILITY IDEOGRAPH-F92C;Lo;0;L;90CE;;;;N;;;;; -F92D;CJK COMPATIBILITY IDEOGRAPH-F92D;Lo;0;L;4F86;;;;N;;;;; -F92E;CJK COMPATIBILITY IDEOGRAPH-F92E;Lo;0;L;51B7;;;;N;;;;; -F92F;CJK COMPATIBILITY IDEOGRAPH-F92F;Lo;0;L;52DE;;;;N;;;;; -F930;CJK COMPATIBILITY IDEOGRAPH-F930;Lo;0;L;64C4;;;;N;;;;; -F931;CJK COMPATIBILITY IDEOGRAPH-F931;Lo;0;L;6AD3;;;;N;;;;; -F932;CJK COMPATIBILITY IDEOGRAPH-F932;Lo;0;L;7210;;;;N;;;;; -F933;CJK COMPATIBILITY IDEOGRAPH-F933;Lo;0;L;76E7;;;;N;;;;; -F934;CJK COMPATIBILITY IDEOGRAPH-F934;Lo;0;L;8001;;;;N;;;;; -F935;CJK COMPATIBILITY IDEOGRAPH-F935;Lo;0;L;8606;;;;N;;;;; -F936;CJK COMPATIBILITY IDEOGRAPH-F936;Lo;0;L;865C;;;;N;;;;; -F937;CJK COMPATIBILITY IDEOGRAPH-F937;Lo;0;L;8DEF;;;;N;;;;; -F938;CJK COMPATIBILITY IDEOGRAPH-F938;Lo;0;L;9732;;;;N;;;;; -F939;CJK COMPATIBILITY IDEOGRAPH-F939;Lo;0;L;9B6F;;;;N;;;;; -F93A;CJK COMPATIBILITY IDEOGRAPH-F93A;Lo;0;L;9DFA;;;;N;;;;; -F93B;CJK COMPATIBILITY IDEOGRAPH-F93B;Lo;0;L;788C;;;;N;;;;; -F93C;CJK COMPATIBILITY IDEOGRAPH-F93C;Lo;0;L;797F;;;;N;;;;; -F93D;CJK COMPATIBILITY IDEOGRAPH-F93D;Lo;0;L;7DA0;;;;N;;;;; -F93E;CJK COMPATIBILITY IDEOGRAPH-F93E;Lo;0;L;83C9;;;;N;;;;; -F93F;CJK COMPATIBILITY IDEOGRAPH-F93F;Lo;0;L;9304;;;;N;;;;; -F940;CJK COMPATIBILITY IDEOGRAPH-F940;Lo;0;L;9E7F;;;;N;;;;; -F941;CJK COMPATIBILITY IDEOGRAPH-F941;Lo;0;L;8AD6;;;;N;;;;; -F942;CJK COMPATIBILITY IDEOGRAPH-F942;Lo;0;L;58DF;;;;N;;;;; -F943;CJK COMPATIBILITY IDEOGRAPH-F943;Lo;0;L;5F04;;;;N;;;;; -F944;CJK COMPATIBILITY IDEOGRAPH-F944;Lo;0;L;7C60;;;;N;;;;; -F945;CJK COMPATIBILITY IDEOGRAPH-F945;Lo;0;L;807E;;;;N;;;;; -F946;CJK COMPATIBILITY IDEOGRAPH-F946;Lo;0;L;7262;;;;N;;;;; -F947;CJK COMPATIBILITY IDEOGRAPH-F947;Lo;0;L;78CA;;;;N;;;;; -F948;CJK COMPATIBILITY IDEOGRAPH-F948;Lo;0;L;8CC2;;;;N;;;;; -F949;CJK COMPATIBILITY IDEOGRAPH-F949;Lo;0;L;96F7;;;;N;;;;; -F94A;CJK COMPATIBILITY IDEOGRAPH-F94A;Lo;0;L;58D8;;;;N;;;;; -F94B;CJK COMPATIBILITY IDEOGRAPH-F94B;Lo;0;L;5C62;;;;N;;;;; -F94C;CJK COMPATIBILITY IDEOGRAPH-F94C;Lo;0;L;6A13;;;;N;;;;; -F94D;CJK COMPATIBILITY IDEOGRAPH-F94D;Lo;0;L;6DDA;;;;N;;;;; -F94E;CJK COMPATIBILITY IDEOGRAPH-F94E;Lo;0;L;6F0F;;;;N;;;;; -F94F;CJK COMPATIBILITY IDEOGRAPH-F94F;Lo;0;L;7D2F;;;;N;;;;; -F950;CJK COMPATIBILITY IDEOGRAPH-F950;Lo;0;L;7E37;;;;N;;;;; -F951;CJK COMPATIBILITY IDEOGRAPH-F951;Lo;0;L;964B;;;;N;;;;; -F952;CJK COMPATIBILITY IDEOGRAPH-F952;Lo;0;L;52D2;;;;N;;;;; -F953;CJK COMPATIBILITY IDEOGRAPH-F953;Lo;0;L;808B;;;;N;;;;; -F954;CJK COMPATIBILITY IDEOGRAPH-F954;Lo;0;L;51DC;;;;N;;;;; -F955;CJK COMPATIBILITY IDEOGRAPH-F955;Lo;0;L;51CC;;;;N;;;;; -F956;CJK COMPATIBILITY IDEOGRAPH-F956;Lo;0;L;7A1C;;;;N;;;;; -F957;CJK COMPATIBILITY IDEOGRAPH-F957;Lo;0;L;7DBE;;;;N;;;;; -F958;CJK COMPATIBILITY IDEOGRAPH-F958;Lo;0;L;83F1;;;;N;;;;; -F959;CJK COMPATIBILITY IDEOGRAPH-F959;Lo;0;L;9675;;;;N;;;;; -F95A;CJK COMPATIBILITY IDEOGRAPH-F95A;Lo;0;L;8B80;;;;N;;;;; -F95B;CJK COMPATIBILITY IDEOGRAPH-F95B;Lo;0;L;62CF;;;;N;;;;; -F95C;CJK COMPATIBILITY IDEOGRAPH-F95C;Lo;0;L;6A02;;;;N;;;;; -F95D;CJK COMPATIBILITY IDEOGRAPH-F95D;Lo;0;L;8AFE;;;;N;;;;; -F95E;CJK COMPATIBILITY IDEOGRAPH-F95E;Lo;0;L;4E39;;;;N;;;;; -F95F;CJK COMPATIBILITY IDEOGRAPH-F95F;Lo;0;L;5BE7;;;;N;;;;; -F960;CJK COMPATIBILITY IDEOGRAPH-F960;Lo;0;L;6012;;;;N;;;;; -F961;CJK COMPATIBILITY IDEOGRAPH-F961;Lo;0;L;7387;;;;N;;;;; -F962;CJK COMPATIBILITY IDEOGRAPH-F962;Lo;0;L;7570;;;;N;;;;; -F963;CJK COMPATIBILITY IDEOGRAPH-F963;Lo;0;L;5317;;;;N;;;;; -F964;CJK COMPATIBILITY IDEOGRAPH-F964;Lo;0;L;78FB;;;;N;;;;; -F965;CJK COMPATIBILITY IDEOGRAPH-F965;Lo;0;L;4FBF;;;;N;;;;; -F966;CJK COMPATIBILITY IDEOGRAPH-F966;Lo;0;L;5FA9;;;;N;;;;; -F967;CJK COMPATIBILITY IDEOGRAPH-F967;Lo;0;L;4E0D;;;;N;;;;; -F968;CJK COMPATIBILITY IDEOGRAPH-F968;Lo;0;L;6CCC;;;;N;;;;; -F969;CJK COMPATIBILITY IDEOGRAPH-F969;Lo;0;L;6578;;;;N;;;;; -F96A;CJK COMPATIBILITY IDEOGRAPH-F96A;Lo;0;L;7D22;;;;N;;;;; -F96B;CJK COMPATIBILITY IDEOGRAPH-F96B;Lo;0;L;53C3;;;3;N;;;;; -F96C;CJK COMPATIBILITY IDEOGRAPH-F96C;Lo;0;L;585E;;;;N;;;;; -F96D;CJK COMPATIBILITY IDEOGRAPH-F96D;Lo;0;L;7701;;;;N;;;;; -F96E;CJK COMPATIBILITY IDEOGRAPH-F96E;Lo;0;L;8449;;;;N;;;;; -F96F;CJK COMPATIBILITY IDEOGRAPH-F96F;Lo;0;L;8AAA;;;;N;;;;; -F970;CJK COMPATIBILITY IDEOGRAPH-F970;Lo;0;L;6BBA;;;;N;;;;; -F971;CJK COMPATIBILITY IDEOGRAPH-F971;Lo;0;L;8FB0;;;;N;;;;; -F972;CJK COMPATIBILITY IDEOGRAPH-F972;Lo;0;L;6C88;;;;N;;;;; -F973;CJK COMPATIBILITY IDEOGRAPH-F973;Lo;0;L;62FE;;;10;N;;;;; -F974;CJK COMPATIBILITY IDEOGRAPH-F974;Lo;0;L;82E5;;;;N;;;;; -F975;CJK COMPATIBILITY IDEOGRAPH-F975;Lo;0;L;63A0;;;;N;;;;; -F976;CJK COMPATIBILITY IDEOGRAPH-F976;Lo;0;L;7565;;;;N;;;;; -F977;CJK COMPATIBILITY IDEOGRAPH-F977;Lo;0;L;4EAE;;;;N;;;;; -F978;CJK COMPATIBILITY IDEOGRAPH-F978;Lo;0;L;5169;;;2;N;;;;; -F979;CJK COMPATIBILITY IDEOGRAPH-F979;Lo;0;L;51C9;;;;N;;;;; -F97A;CJK COMPATIBILITY IDEOGRAPH-F97A;Lo;0;L;6881;;;;N;;;;; -F97B;CJK COMPATIBILITY IDEOGRAPH-F97B;Lo;0;L;7CE7;;;;N;;;;; -F97C;CJK COMPATIBILITY IDEOGRAPH-F97C;Lo;0;L;826F;;;;N;;;;; -F97D;CJK COMPATIBILITY IDEOGRAPH-F97D;Lo;0;L;8AD2;;;;N;;;;; -F97E;CJK COMPATIBILITY IDEOGRAPH-F97E;Lo;0;L;91CF;;;;N;;;;; -F97F;CJK COMPATIBILITY IDEOGRAPH-F97F;Lo;0;L;52F5;;;;N;;;;; -F980;CJK COMPATIBILITY IDEOGRAPH-F980;Lo;0;L;5442;;;;N;;;;; -F981;CJK COMPATIBILITY IDEOGRAPH-F981;Lo;0;L;5973;;;;N;;;;; -F982;CJK COMPATIBILITY IDEOGRAPH-F982;Lo;0;L;5EEC;;;;N;;;;; -F983;CJK COMPATIBILITY IDEOGRAPH-F983;Lo;0;L;65C5;;;;N;;;;; -F984;CJK COMPATIBILITY IDEOGRAPH-F984;Lo;0;L;6FFE;;;;N;;;;; -F985;CJK COMPATIBILITY IDEOGRAPH-F985;Lo;0;L;792A;;;;N;;;;; -F986;CJK COMPATIBILITY IDEOGRAPH-F986;Lo;0;L;95AD;;;;N;;;;; -F987;CJK COMPATIBILITY IDEOGRAPH-F987;Lo;0;L;9A6A;;;;N;;;;; -F988;CJK COMPATIBILITY IDEOGRAPH-F988;Lo;0;L;9E97;;;;N;;;;; -F989;CJK COMPATIBILITY IDEOGRAPH-F989;Lo;0;L;9ECE;;;;N;;;;; -F98A;CJK COMPATIBILITY IDEOGRAPH-F98A;Lo;0;L;529B;;;;N;;;;; -F98B;CJK COMPATIBILITY IDEOGRAPH-F98B;Lo;0;L;66C6;;;;N;;;;; -F98C;CJK COMPATIBILITY IDEOGRAPH-F98C;Lo;0;L;6B77;;;;N;;;;; -F98D;CJK COMPATIBILITY IDEOGRAPH-F98D;Lo;0;L;8F62;;;;N;;;;; -F98E;CJK COMPATIBILITY IDEOGRAPH-F98E;Lo;0;L;5E74;;;;N;;;;; -F98F;CJK COMPATIBILITY IDEOGRAPH-F98F;Lo;0;L;6190;;;;N;;;;; -F990;CJK COMPATIBILITY IDEOGRAPH-F990;Lo;0;L;6200;;;;N;;;;; -F991;CJK COMPATIBILITY IDEOGRAPH-F991;Lo;0;L;649A;;;;N;;;;; -F992;CJK COMPATIBILITY IDEOGRAPH-F992;Lo;0;L;6F23;;;;N;;;;; -F993;CJK COMPATIBILITY IDEOGRAPH-F993;Lo;0;L;7149;;;;N;;;;; -F994;CJK COMPATIBILITY IDEOGRAPH-F994;Lo;0;L;7489;;;;N;;;;; -F995;CJK COMPATIBILITY IDEOGRAPH-F995;Lo;0;L;79CA;;;;N;;;;; -F996;CJK COMPATIBILITY IDEOGRAPH-F996;Lo;0;L;7DF4;;;;N;;;;; -F997;CJK COMPATIBILITY IDEOGRAPH-F997;Lo;0;L;806F;;;;N;;;;; -F998;CJK COMPATIBILITY IDEOGRAPH-F998;Lo;0;L;8F26;;;;N;;;;; -F999;CJK COMPATIBILITY IDEOGRAPH-F999;Lo;0;L;84EE;;;;N;;;;; -F99A;CJK COMPATIBILITY IDEOGRAPH-F99A;Lo;0;L;9023;;;;N;;;;; -F99B;CJK COMPATIBILITY IDEOGRAPH-F99B;Lo;0;L;934A;;;;N;;;;; -F99C;CJK COMPATIBILITY IDEOGRAPH-F99C;Lo;0;L;5217;;;;N;;;;; -F99D;CJK COMPATIBILITY IDEOGRAPH-F99D;Lo;0;L;52A3;;;;N;;;;; -F99E;CJK COMPATIBILITY IDEOGRAPH-F99E;Lo;0;L;54BD;;;;N;;;;; -F99F;CJK COMPATIBILITY IDEOGRAPH-F99F;Lo;0;L;70C8;;;;N;;;;; -F9A0;CJK COMPATIBILITY IDEOGRAPH-F9A0;Lo;0;L;88C2;;;;N;;;;; -F9A1;CJK COMPATIBILITY IDEOGRAPH-F9A1;Lo;0;L;8AAA;;;;N;;;;; -F9A2;CJK COMPATIBILITY IDEOGRAPH-F9A2;Lo;0;L;5EC9;;;;N;;;;; -F9A3;CJK COMPATIBILITY IDEOGRAPH-F9A3;Lo;0;L;5FF5;;;;N;;;;; -F9A4;CJK COMPATIBILITY IDEOGRAPH-F9A4;Lo;0;L;637B;;;;N;;;;; -F9A5;CJK COMPATIBILITY IDEOGRAPH-F9A5;Lo;0;L;6BAE;;;;N;;;;; -F9A6;CJK COMPATIBILITY IDEOGRAPH-F9A6;Lo;0;L;7C3E;;;;N;;;;; -F9A7;CJK COMPATIBILITY IDEOGRAPH-F9A7;Lo;0;L;7375;;;;N;;;;; -F9A8;CJK COMPATIBILITY IDEOGRAPH-F9A8;Lo;0;L;4EE4;;;;N;;;;; -F9A9;CJK COMPATIBILITY IDEOGRAPH-F9A9;Lo;0;L;56F9;;;;N;;;;; -F9AA;CJK COMPATIBILITY IDEOGRAPH-F9AA;Lo;0;L;5BE7;;;;N;;;;; -F9AB;CJK COMPATIBILITY IDEOGRAPH-F9AB;Lo;0;L;5DBA;;;;N;;;;; -F9AC;CJK COMPATIBILITY IDEOGRAPH-F9AC;Lo;0;L;601C;;;;N;;;;; -F9AD;CJK COMPATIBILITY IDEOGRAPH-F9AD;Lo;0;L;73B2;;;;N;;;;; -F9AE;CJK COMPATIBILITY IDEOGRAPH-F9AE;Lo;0;L;7469;;;;N;;;;; -F9AF;CJK COMPATIBILITY IDEOGRAPH-F9AF;Lo;0;L;7F9A;;;;N;;;;; -F9B0;CJK COMPATIBILITY IDEOGRAPH-F9B0;Lo;0;L;8046;;;;N;;;;; -F9B1;CJK COMPATIBILITY IDEOGRAPH-F9B1;Lo;0;L;9234;;;;N;;;;; -F9B2;CJK COMPATIBILITY IDEOGRAPH-F9B2;Lo;0;L;96F6;;;0;N;;;;; -F9B3;CJK COMPATIBILITY IDEOGRAPH-F9B3;Lo;0;L;9748;;;;N;;;;; -F9B4;CJK COMPATIBILITY IDEOGRAPH-F9B4;Lo;0;L;9818;;;;N;;;;; -F9B5;CJK COMPATIBILITY IDEOGRAPH-F9B5;Lo;0;L;4F8B;;;;N;;;;; -F9B6;CJK COMPATIBILITY IDEOGRAPH-F9B6;Lo;0;L;79AE;;;;N;;;;; -F9B7;CJK COMPATIBILITY IDEOGRAPH-F9B7;Lo;0;L;91B4;;;;N;;;;; -F9B8;CJK COMPATIBILITY IDEOGRAPH-F9B8;Lo;0;L;96B8;;;;N;;;;; -F9B9;CJK COMPATIBILITY IDEOGRAPH-F9B9;Lo;0;L;60E1;;;;N;;;;; -F9BA;CJK COMPATIBILITY IDEOGRAPH-F9BA;Lo;0;L;4E86;;;;N;;;;; -F9BB;CJK COMPATIBILITY IDEOGRAPH-F9BB;Lo;0;L;50DA;;;;N;;;;; -F9BC;CJK COMPATIBILITY IDEOGRAPH-F9BC;Lo;0;L;5BEE;;;;N;;;;; -F9BD;CJK COMPATIBILITY IDEOGRAPH-F9BD;Lo;0;L;5C3F;;;;N;;;;; -F9BE;CJK COMPATIBILITY IDEOGRAPH-F9BE;Lo;0;L;6599;;;;N;;;;; -F9BF;CJK COMPATIBILITY IDEOGRAPH-F9BF;Lo;0;L;6A02;;;;N;;;;; -F9C0;CJK COMPATIBILITY IDEOGRAPH-F9C0;Lo;0;L;71CE;;;;N;;;;; -F9C1;CJK COMPATIBILITY IDEOGRAPH-F9C1;Lo;0;L;7642;;;;N;;;;; -F9C2;CJK COMPATIBILITY IDEOGRAPH-F9C2;Lo;0;L;84FC;;;;N;;;;; -F9C3;CJK COMPATIBILITY IDEOGRAPH-F9C3;Lo;0;L;907C;;;;N;;;;; -F9C4;CJK COMPATIBILITY IDEOGRAPH-F9C4;Lo;0;L;9F8D;;;;N;;;;; -F9C5;CJK COMPATIBILITY IDEOGRAPH-F9C5;Lo;0;L;6688;;;;N;;;;; -F9C6;CJK COMPATIBILITY IDEOGRAPH-F9C6;Lo;0;L;962E;;;;N;;;;; -F9C7;CJK COMPATIBILITY IDEOGRAPH-F9C7;Lo;0;L;5289;;;;N;;;;; -F9C8;CJK COMPATIBILITY IDEOGRAPH-F9C8;Lo;0;L;677B;;;;N;;;;; -F9C9;CJK COMPATIBILITY IDEOGRAPH-F9C9;Lo;0;L;67F3;;;;N;;;;; -F9CA;CJK COMPATIBILITY IDEOGRAPH-F9CA;Lo;0;L;6D41;;;;N;;;;; -F9CB;CJK COMPATIBILITY IDEOGRAPH-F9CB;Lo;0;L;6E9C;;;;N;;;;; -F9CC;CJK COMPATIBILITY IDEOGRAPH-F9CC;Lo;0;L;7409;;;;N;;;;; -F9CD;CJK COMPATIBILITY IDEOGRAPH-F9CD;Lo;0;L;7559;;;;N;;;;; -F9CE;CJK COMPATIBILITY IDEOGRAPH-F9CE;Lo;0;L;786B;;;;N;;;;; -F9CF;CJK COMPATIBILITY IDEOGRAPH-F9CF;Lo;0;L;7D10;;;;N;;;;; -F9D0;CJK COMPATIBILITY IDEOGRAPH-F9D0;Lo;0;L;985E;;;;N;;;;; -F9D1;CJK COMPATIBILITY IDEOGRAPH-F9D1;Lo;0;L;516D;;;6;N;;;;; -F9D2;CJK COMPATIBILITY IDEOGRAPH-F9D2;Lo;0;L;622E;;;;N;;;;; -F9D3;CJK COMPATIBILITY IDEOGRAPH-F9D3;Lo;0;L;9678;;;6;N;;;;; -F9D4;CJK COMPATIBILITY IDEOGRAPH-F9D4;Lo;0;L;502B;;;;N;;;;; -F9D5;CJK COMPATIBILITY IDEOGRAPH-F9D5;Lo;0;L;5D19;;;;N;;;;; -F9D6;CJK COMPATIBILITY IDEOGRAPH-F9D6;Lo;0;L;6DEA;;;;N;;;;; -F9D7;CJK COMPATIBILITY IDEOGRAPH-F9D7;Lo;0;L;8F2A;;;;N;;;;; -F9D8;CJK COMPATIBILITY IDEOGRAPH-F9D8;Lo;0;L;5F8B;;;;N;;;;; -F9D9;CJK COMPATIBILITY IDEOGRAPH-F9D9;Lo;0;L;6144;;;;N;;;;; -F9DA;CJK COMPATIBILITY IDEOGRAPH-F9DA;Lo;0;L;6817;;;;N;;;;; -F9DB;CJK COMPATIBILITY IDEOGRAPH-F9DB;Lo;0;L;7387;;;;N;;;;; -F9DC;CJK COMPATIBILITY IDEOGRAPH-F9DC;Lo;0;L;9686;;;;N;;;;; -F9DD;CJK COMPATIBILITY IDEOGRAPH-F9DD;Lo;0;L;5229;;;;N;;;;; -F9DE;CJK COMPATIBILITY IDEOGRAPH-F9DE;Lo;0;L;540F;;;;N;;;;; -F9DF;CJK COMPATIBILITY IDEOGRAPH-F9DF;Lo;0;L;5C65;;;;N;;;;; -F9E0;CJK COMPATIBILITY IDEOGRAPH-F9E0;Lo;0;L;6613;;;;N;;;;; -F9E1;CJK COMPATIBILITY IDEOGRAPH-F9E1;Lo;0;L;674E;;;;N;;;;; -F9E2;CJK COMPATIBILITY IDEOGRAPH-F9E2;Lo;0;L;68A8;;;;N;;;;; -F9E3;CJK COMPATIBILITY IDEOGRAPH-F9E3;Lo;0;L;6CE5;;;;N;;;;; -F9E4;CJK COMPATIBILITY IDEOGRAPH-F9E4;Lo;0;L;7406;;;;N;;;;; -F9E5;CJK COMPATIBILITY IDEOGRAPH-F9E5;Lo;0;L;75E2;;;;N;;;;; -F9E6;CJK COMPATIBILITY IDEOGRAPH-F9E6;Lo;0;L;7F79;;;;N;;;;; -F9E7;CJK COMPATIBILITY IDEOGRAPH-F9E7;Lo;0;L;88CF;;;;N;;;;; -F9E8;CJK COMPATIBILITY IDEOGRAPH-F9E8;Lo;0;L;88E1;;;;N;;;;; -F9E9;CJK COMPATIBILITY IDEOGRAPH-F9E9;Lo;0;L;91CC;;;;N;;;;; -F9EA;CJK COMPATIBILITY IDEOGRAPH-F9EA;Lo;0;L;96E2;;;;N;;;;; -F9EB;CJK COMPATIBILITY IDEOGRAPH-F9EB;Lo;0;L;533F;;;;N;;;;; -F9EC;CJK COMPATIBILITY IDEOGRAPH-F9EC;Lo;0;L;6EBA;;;;N;;;;; -F9ED;CJK COMPATIBILITY IDEOGRAPH-F9ED;Lo;0;L;541D;;;;N;;;;; -F9EE;CJK COMPATIBILITY IDEOGRAPH-F9EE;Lo;0;L;71D0;;;;N;;;;; -F9EF;CJK COMPATIBILITY IDEOGRAPH-F9EF;Lo;0;L;7498;;;;N;;;;; -F9F0;CJK COMPATIBILITY IDEOGRAPH-F9F0;Lo;0;L;85FA;;;;N;;;;; -F9F1;CJK COMPATIBILITY IDEOGRAPH-F9F1;Lo;0;L;96A3;;;;N;;;;; -F9F2;CJK COMPATIBILITY IDEOGRAPH-F9F2;Lo;0;L;9C57;;;;N;;;;; -F9F3;CJK COMPATIBILITY IDEOGRAPH-F9F3;Lo;0;L;9E9F;;;;N;;;;; -F9F4;CJK COMPATIBILITY IDEOGRAPH-F9F4;Lo;0;L;6797;;;;N;;;;; -F9F5;CJK COMPATIBILITY IDEOGRAPH-F9F5;Lo;0;L;6DCB;;;;N;;;;; -F9F6;CJK COMPATIBILITY IDEOGRAPH-F9F6;Lo;0;L;81E8;;;;N;;;;; -F9F7;CJK COMPATIBILITY IDEOGRAPH-F9F7;Lo;0;L;7ACB;;;;N;;;;; -F9F8;CJK COMPATIBILITY IDEOGRAPH-F9F8;Lo;0;L;7B20;;;;N;;;;; -F9F9;CJK COMPATIBILITY IDEOGRAPH-F9F9;Lo;0;L;7C92;;;;N;;;;; -F9FA;CJK COMPATIBILITY IDEOGRAPH-F9FA;Lo;0;L;72C0;;;;N;;;;; -F9FB;CJK COMPATIBILITY IDEOGRAPH-F9FB;Lo;0;L;7099;;;;N;;;;; -F9FC;CJK COMPATIBILITY IDEOGRAPH-F9FC;Lo;0;L;8B58;;;;N;;;;; -F9FD;CJK COMPATIBILITY IDEOGRAPH-F9FD;Lo;0;L;4EC0;;;10;N;;;;; -F9FE;CJK COMPATIBILITY IDEOGRAPH-F9FE;Lo;0;L;8336;;;;N;;;;; -F9FF;CJK COMPATIBILITY IDEOGRAPH-F9FF;Lo;0;L;523A;;;;N;;;;; -FA00;CJK COMPATIBILITY IDEOGRAPH-FA00;Lo;0;L;5207;;;;N;;;;; -FA01;CJK COMPATIBILITY IDEOGRAPH-FA01;Lo;0;L;5EA6;;;;N;;;;; -FA02;CJK COMPATIBILITY IDEOGRAPH-FA02;Lo;0;L;62D3;;;;N;;;;; -FA03;CJK COMPATIBILITY IDEOGRAPH-FA03;Lo;0;L;7CD6;;;;N;;;;; -FA04;CJK COMPATIBILITY IDEOGRAPH-FA04;Lo;0;L;5B85;;;;N;;;;; -FA05;CJK COMPATIBILITY IDEOGRAPH-FA05;Lo;0;L;6D1E;;;;N;;;;; -FA06;CJK COMPATIBILITY IDEOGRAPH-FA06;Lo;0;L;66B4;;;;N;;;;; -FA07;CJK COMPATIBILITY IDEOGRAPH-FA07;Lo;0;L;8F3B;;;;N;;;;; -FA08;CJK COMPATIBILITY IDEOGRAPH-FA08;Lo;0;L;884C;;;;N;;;;; -FA09;CJK COMPATIBILITY IDEOGRAPH-FA09;Lo;0;L;964D;;;;N;;;;; -FA0A;CJK COMPATIBILITY IDEOGRAPH-FA0A;Lo;0;L;898B;;;;N;;;;; -FA0B;CJK COMPATIBILITY IDEOGRAPH-FA0B;Lo;0;L;5ED3;;;;N;;;;; -FA0C;CJK COMPATIBILITY IDEOGRAPH-FA0C;Lo;0;L;5140;;;;N;;;;; -FA0D;CJK COMPATIBILITY IDEOGRAPH-FA0D;Lo;0;L;55C0;;;;N;;;;; -FA0E;CJK COMPATIBILITY IDEOGRAPH-FA0E;Lo;0;L;;;;;N;;;;; -FA0F;CJK COMPATIBILITY IDEOGRAPH-FA0F;Lo;0;L;;;;;N;;;;; -FA10;CJK COMPATIBILITY IDEOGRAPH-FA10;Lo;0;L;585A;;;;N;;;;; -FA11;CJK COMPATIBILITY IDEOGRAPH-FA11;Lo;0;L;;;;;N;;;;; -FA12;CJK COMPATIBILITY IDEOGRAPH-FA12;Lo;0;L;6674;;;;N;;;;; -FA13;CJK COMPATIBILITY IDEOGRAPH-FA13;Lo;0;L;;;;;N;;;;; -FA14;CJK COMPATIBILITY IDEOGRAPH-FA14;Lo;0;L;;;;;N;;;;; -FA15;CJK COMPATIBILITY IDEOGRAPH-FA15;Lo;0;L;51DE;;;;N;;;;; -FA16;CJK COMPATIBILITY IDEOGRAPH-FA16;Lo;0;L;732A;;;;N;;;;; -FA17;CJK COMPATIBILITY IDEOGRAPH-FA17;Lo;0;L;76CA;;;;N;;;;; -FA18;CJK COMPATIBILITY IDEOGRAPH-FA18;Lo;0;L;793C;;;;N;;;;; -FA19;CJK COMPATIBILITY IDEOGRAPH-FA19;Lo;0;L;795E;;;;N;;;;; -FA1A;CJK COMPATIBILITY IDEOGRAPH-FA1A;Lo;0;L;7965;;;;N;;;;; -FA1B;CJK COMPATIBILITY IDEOGRAPH-FA1B;Lo;0;L;798F;;;;N;;;;; -FA1C;CJK COMPATIBILITY IDEOGRAPH-FA1C;Lo;0;L;9756;;;;N;;;;; -FA1D;CJK COMPATIBILITY IDEOGRAPH-FA1D;Lo;0;L;7CBE;;;;N;;;;; -FA1E;CJK COMPATIBILITY IDEOGRAPH-FA1E;Lo;0;L;7FBD;;;;N;;;;; -FA1F;CJK COMPATIBILITY IDEOGRAPH-FA1F;Lo;0;L;;;;;N;;;;; -FA20;CJK COMPATIBILITY IDEOGRAPH-FA20;Lo;0;L;8612;;;;N;;;;; -FA21;CJK COMPATIBILITY IDEOGRAPH-FA21;Lo;0;L;;;;;N;;;;; -FA22;CJK COMPATIBILITY IDEOGRAPH-FA22;Lo;0;L;8AF8;;;;N;;;;; -FA23;CJK COMPATIBILITY IDEOGRAPH-FA23;Lo;0;L;;;;;N;;;;; -FA24;CJK COMPATIBILITY IDEOGRAPH-FA24;Lo;0;L;;;;;N;;;;; -FA25;CJK COMPATIBILITY IDEOGRAPH-FA25;Lo;0;L;9038;;;;N;;;;; -FA26;CJK COMPATIBILITY IDEOGRAPH-FA26;Lo;0;L;90FD;;;;N;;;;; -FA27;CJK COMPATIBILITY IDEOGRAPH-FA27;Lo;0;L;;;;;N;;;;; -FA28;CJK COMPATIBILITY IDEOGRAPH-FA28;Lo;0;L;;;;;N;;;;; -FA29;CJK COMPATIBILITY IDEOGRAPH-FA29;Lo;0;L;;;;;N;;;;; -FA2A;CJK COMPATIBILITY IDEOGRAPH-FA2A;Lo;0;L;98EF;;;;N;;;;; -FA2B;CJK COMPATIBILITY IDEOGRAPH-FA2B;Lo;0;L;98FC;;;;N;;;;; -FA2C;CJK COMPATIBILITY IDEOGRAPH-FA2C;Lo;0;L;9928;;;;N;;;;; -FA2D;CJK COMPATIBILITY IDEOGRAPH-FA2D;Lo;0;L;9DB4;;;;N;;;;; -FA2E;CJK COMPATIBILITY IDEOGRAPH-FA2E;Lo;0;L;90DE;;;;N;;;;; -FA2F;CJK COMPATIBILITY IDEOGRAPH-FA2F;Lo;0;L;96B7;;;;N;;;;; -FA30;CJK COMPATIBILITY IDEOGRAPH-FA30;Lo;0;L;4FAE;;;;N;;;;; -FA31;CJK COMPATIBILITY IDEOGRAPH-FA31;Lo;0;L;50E7;;;;N;;;;; -FA32;CJK COMPATIBILITY IDEOGRAPH-FA32;Lo;0;L;514D;;;;N;;;;; -FA33;CJK COMPATIBILITY IDEOGRAPH-FA33;Lo;0;L;52C9;;;;N;;;;; -FA34;CJK COMPATIBILITY IDEOGRAPH-FA34;Lo;0;L;52E4;;;;N;;;;; -FA35;CJK COMPATIBILITY IDEOGRAPH-FA35;Lo;0;L;5351;;;;N;;;;; -FA36;CJK COMPATIBILITY IDEOGRAPH-FA36;Lo;0;L;559D;;;;N;;;;; -FA37;CJK COMPATIBILITY IDEOGRAPH-FA37;Lo;0;L;5606;;;;N;;;;; -FA38;CJK COMPATIBILITY IDEOGRAPH-FA38;Lo;0;L;5668;;;;N;;;;; -FA39;CJK COMPATIBILITY IDEOGRAPH-FA39;Lo;0;L;5840;;;;N;;;;; -FA3A;CJK COMPATIBILITY IDEOGRAPH-FA3A;Lo;0;L;58A8;;;;N;;;;; -FA3B;CJK COMPATIBILITY IDEOGRAPH-FA3B;Lo;0;L;5C64;;;;N;;;;; -FA3C;CJK COMPATIBILITY IDEOGRAPH-FA3C;Lo;0;L;5C6E;;;;N;;;;; -FA3D;CJK COMPATIBILITY IDEOGRAPH-FA3D;Lo;0;L;6094;;;;N;;;;; -FA3E;CJK COMPATIBILITY IDEOGRAPH-FA3E;Lo;0;L;6168;;;;N;;;;; -FA3F;CJK COMPATIBILITY IDEOGRAPH-FA3F;Lo;0;L;618E;;;;N;;;;; -FA40;CJK COMPATIBILITY IDEOGRAPH-FA40;Lo;0;L;61F2;;;;N;;;;; -FA41;CJK COMPATIBILITY IDEOGRAPH-FA41;Lo;0;L;654F;;;;N;;;;; -FA42;CJK COMPATIBILITY IDEOGRAPH-FA42;Lo;0;L;65E2;;;;N;;;;; -FA43;CJK COMPATIBILITY IDEOGRAPH-FA43;Lo;0;L;6691;;;;N;;;;; -FA44;CJK COMPATIBILITY IDEOGRAPH-FA44;Lo;0;L;6885;;;;N;;;;; -FA45;CJK COMPATIBILITY IDEOGRAPH-FA45;Lo;0;L;6D77;;;;N;;;;; -FA46;CJK COMPATIBILITY IDEOGRAPH-FA46;Lo;0;L;6E1A;;;;N;;;;; -FA47;CJK COMPATIBILITY IDEOGRAPH-FA47;Lo;0;L;6F22;;;;N;;;;; -FA48;CJK COMPATIBILITY IDEOGRAPH-FA48;Lo;0;L;716E;;;;N;;;;; -FA49;CJK COMPATIBILITY IDEOGRAPH-FA49;Lo;0;L;722B;;;;N;;;;; -FA4A;CJK COMPATIBILITY IDEOGRAPH-FA4A;Lo;0;L;7422;;;;N;;;;; -FA4B;CJK COMPATIBILITY IDEOGRAPH-FA4B;Lo;0;L;7891;;;;N;;;;; -FA4C;CJK COMPATIBILITY IDEOGRAPH-FA4C;Lo;0;L;793E;;;;N;;;;; -FA4D;CJK COMPATIBILITY IDEOGRAPH-FA4D;Lo;0;L;7949;;;;N;;;;; -FA4E;CJK COMPATIBILITY IDEOGRAPH-FA4E;Lo;0;L;7948;;;;N;;;;; -FA4F;CJK COMPATIBILITY IDEOGRAPH-FA4F;Lo;0;L;7950;;;;N;;;;; -FA50;CJK COMPATIBILITY IDEOGRAPH-FA50;Lo;0;L;7956;;;;N;;;;; -FA51;CJK COMPATIBILITY IDEOGRAPH-FA51;Lo;0;L;795D;;;;N;;;;; -FA52;CJK COMPATIBILITY IDEOGRAPH-FA52;Lo;0;L;798D;;;;N;;;;; -FA53;CJK COMPATIBILITY IDEOGRAPH-FA53;Lo;0;L;798E;;;;N;;;;; -FA54;CJK COMPATIBILITY IDEOGRAPH-FA54;Lo;0;L;7A40;;;;N;;;;; -FA55;CJK COMPATIBILITY IDEOGRAPH-FA55;Lo;0;L;7A81;;;;N;;;;; -FA56;CJK COMPATIBILITY IDEOGRAPH-FA56;Lo;0;L;7BC0;;;;N;;;;; -FA57;CJK COMPATIBILITY IDEOGRAPH-FA57;Lo;0;L;7DF4;;;;N;;;;; -FA58;CJK COMPATIBILITY IDEOGRAPH-FA58;Lo;0;L;7E09;;;;N;;;;; -FA59;CJK COMPATIBILITY IDEOGRAPH-FA59;Lo;0;L;7E41;;;;N;;;;; -FA5A;CJK COMPATIBILITY IDEOGRAPH-FA5A;Lo;0;L;7F72;;;;N;;;;; -FA5B;CJK COMPATIBILITY IDEOGRAPH-FA5B;Lo;0;L;8005;;;;N;;;;; -FA5C;CJK COMPATIBILITY IDEOGRAPH-FA5C;Lo;0;L;81ED;;;;N;;;;; -FA5D;CJK COMPATIBILITY IDEOGRAPH-FA5D;Lo;0;L;8279;;;;N;;;;; -FA5E;CJK COMPATIBILITY IDEOGRAPH-FA5E;Lo;0;L;8279;;;;N;;;;; -FA5F;CJK COMPATIBILITY IDEOGRAPH-FA5F;Lo;0;L;8457;;;;N;;;;; -FA60;CJK COMPATIBILITY IDEOGRAPH-FA60;Lo;0;L;8910;;;;N;;;;; -FA61;CJK COMPATIBILITY IDEOGRAPH-FA61;Lo;0;L;8996;;;;N;;;;; -FA62;CJK COMPATIBILITY IDEOGRAPH-FA62;Lo;0;L;8B01;;;;N;;;;; -FA63;CJK COMPATIBILITY IDEOGRAPH-FA63;Lo;0;L;8B39;;;;N;;;;; -FA64;CJK COMPATIBILITY IDEOGRAPH-FA64;Lo;0;L;8CD3;;;;N;;;;; -FA65;CJK COMPATIBILITY IDEOGRAPH-FA65;Lo;0;L;8D08;;;;N;;;;; -FA66;CJK COMPATIBILITY IDEOGRAPH-FA66;Lo;0;L;8FB6;;;;N;;;;; -FA67;CJK COMPATIBILITY IDEOGRAPH-FA67;Lo;0;L;9038;;;;N;;;;; -FA68;CJK COMPATIBILITY IDEOGRAPH-FA68;Lo;0;L;96E3;;;;N;;;;; -FA69;CJK COMPATIBILITY IDEOGRAPH-FA69;Lo;0;L;97FF;;;;N;;;;; -FA6A;CJK COMPATIBILITY IDEOGRAPH-FA6A;Lo;0;L;983B;;;;N;;;;; -FA6B;CJK COMPATIBILITY IDEOGRAPH-FA6B;Lo;0;L;6075;;;;N;;;;; -FA6C;CJK COMPATIBILITY IDEOGRAPH-FA6C;Lo;0;L;242EE;;;;N;;;;; -FA6D;CJK COMPATIBILITY IDEOGRAPH-FA6D;Lo;0;L;8218;;;;N;;;;; -FA70;CJK COMPATIBILITY IDEOGRAPH-FA70;Lo;0;L;4E26;;;;N;;;;; -FA71;CJK COMPATIBILITY IDEOGRAPH-FA71;Lo;0;L;51B5;;;;N;;;;; -FA72;CJK COMPATIBILITY IDEOGRAPH-FA72;Lo;0;L;5168;;;;N;;;;; -FA73;CJK COMPATIBILITY IDEOGRAPH-FA73;Lo;0;L;4F80;;;;N;;;;; -FA74;CJK COMPATIBILITY IDEOGRAPH-FA74;Lo;0;L;5145;;;;N;;;;; -FA75;CJK COMPATIBILITY IDEOGRAPH-FA75;Lo;0;L;5180;;;;N;;;;; -FA76;CJK COMPATIBILITY IDEOGRAPH-FA76;Lo;0;L;52C7;;;;N;;;;; -FA77;CJK COMPATIBILITY IDEOGRAPH-FA77;Lo;0;L;52FA;;;;N;;;;; -FA78;CJK COMPATIBILITY IDEOGRAPH-FA78;Lo;0;L;559D;;;;N;;;;; -FA79;CJK COMPATIBILITY IDEOGRAPH-FA79;Lo;0;L;5555;;;;N;;;;; -FA7A;CJK COMPATIBILITY IDEOGRAPH-FA7A;Lo;0;L;5599;;;;N;;;;; -FA7B;CJK COMPATIBILITY IDEOGRAPH-FA7B;Lo;0;L;55E2;;;;N;;;;; -FA7C;CJK COMPATIBILITY IDEOGRAPH-FA7C;Lo;0;L;585A;;;;N;;;;; -FA7D;CJK COMPATIBILITY IDEOGRAPH-FA7D;Lo;0;L;58B3;;;;N;;;;; -FA7E;CJK COMPATIBILITY IDEOGRAPH-FA7E;Lo;0;L;5944;;;;N;;;;; -FA7F;CJK COMPATIBILITY IDEOGRAPH-FA7F;Lo;0;L;5954;;;;N;;;;; -FA80;CJK COMPATIBILITY IDEOGRAPH-FA80;Lo;0;L;5A62;;;;N;;;;; -FA81;CJK COMPATIBILITY IDEOGRAPH-FA81;Lo;0;L;5B28;;;;N;;;;; -FA82;CJK COMPATIBILITY IDEOGRAPH-FA82;Lo;0;L;5ED2;;;;N;;;;; -FA83;CJK COMPATIBILITY IDEOGRAPH-FA83;Lo;0;L;5ED9;;;;N;;;;; -FA84;CJK COMPATIBILITY IDEOGRAPH-FA84;Lo;0;L;5F69;;;;N;;;;; -FA85;CJK COMPATIBILITY IDEOGRAPH-FA85;Lo;0;L;5FAD;;;;N;;;;; -FA86;CJK COMPATIBILITY IDEOGRAPH-FA86;Lo;0;L;60D8;;;;N;;;;; -FA87;CJK COMPATIBILITY IDEOGRAPH-FA87;Lo;0;L;614E;;;;N;;;;; -FA88;CJK COMPATIBILITY IDEOGRAPH-FA88;Lo;0;L;6108;;;;N;;;;; -FA89;CJK COMPATIBILITY IDEOGRAPH-FA89;Lo;0;L;618E;;;;N;;;;; -FA8A;CJK COMPATIBILITY IDEOGRAPH-FA8A;Lo;0;L;6160;;;;N;;;;; -FA8B;CJK COMPATIBILITY IDEOGRAPH-FA8B;Lo;0;L;61F2;;;;N;;;;; -FA8C;CJK COMPATIBILITY IDEOGRAPH-FA8C;Lo;0;L;6234;;;;N;;;;; -FA8D;CJK COMPATIBILITY IDEOGRAPH-FA8D;Lo;0;L;63C4;;;;N;;;;; -FA8E;CJK COMPATIBILITY IDEOGRAPH-FA8E;Lo;0;L;641C;;;;N;;;;; -FA8F;CJK COMPATIBILITY IDEOGRAPH-FA8F;Lo;0;L;6452;;;;N;;;;; -FA90;CJK COMPATIBILITY IDEOGRAPH-FA90;Lo;0;L;6556;;;;N;;;;; -FA91;CJK COMPATIBILITY IDEOGRAPH-FA91;Lo;0;L;6674;;;;N;;;;; -FA92;CJK COMPATIBILITY IDEOGRAPH-FA92;Lo;0;L;6717;;;;N;;;;; -FA93;CJK COMPATIBILITY IDEOGRAPH-FA93;Lo;0;L;671B;;;;N;;;;; -FA94;CJK COMPATIBILITY IDEOGRAPH-FA94;Lo;0;L;6756;;;;N;;;;; -FA95;CJK COMPATIBILITY IDEOGRAPH-FA95;Lo;0;L;6B79;;;;N;;;;; -FA96;CJK COMPATIBILITY IDEOGRAPH-FA96;Lo;0;L;6BBA;;;;N;;;;; -FA97;CJK COMPATIBILITY IDEOGRAPH-FA97;Lo;0;L;6D41;;;;N;;;;; -FA98;CJK COMPATIBILITY IDEOGRAPH-FA98;Lo;0;L;6EDB;;;;N;;;;; -FA99;CJK COMPATIBILITY IDEOGRAPH-FA99;Lo;0;L;6ECB;;;;N;;;;; -FA9A;CJK COMPATIBILITY IDEOGRAPH-FA9A;Lo;0;L;6F22;;;;N;;;;; -FA9B;CJK COMPATIBILITY IDEOGRAPH-FA9B;Lo;0;L;701E;;;;N;;;;; -FA9C;CJK COMPATIBILITY IDEOGRAPH-FA9C;Lo;0;L;716E;;;;N;;;;; -FA9D;CJK COMPATIBILITY IDEOGRAPH-FA9D;Lo;0;L;77A7;;;;N;;;;; -FA9E;CJK COMPATIBILITY IDEOGRAPH-FA9E;Lo;0;L;7235;;;;N;;;;; -FA9F;CJK COMPATIBILITY IDEOGRAPH-FA9F;Lo;0;L;72AF;;;;N;;;;; -FAA0;CJK COMPATIBILITY IDEOGRAPH-FAA0;Lo;0;L;732A;;;;N;;;;; -FAA1;CJK COMPATIBILITY IDEOGRAPH-FAA1;Lo;0;L;7471;;;;N;;;;; -FAA2;CJK COMPATIBILITY IDEOGRAPH-FAA2;Lo;0;L;7506;;;;N;;;;; -FAA3;CJK COMPATIBILITY IDEOGRAPH-FAA3;Lo;0;L;753B;;;;N;;;;; -FAA4;CJK COMPATIBILITY IDEOGRAPH-FAA4;Lo;0;L;761D;;;;N;;;;; -FAA5;CJK COMPATIBILITY IDEOGRAPH-FAA5;Lo;0;L;761F;;;;N;;;;; -FAA6;CJK COMPATIBILITY IDEOGRAPH-FAA6;Lo;0;L;76CA;;;;N;;;;; -FAA7;CJK COMPATIBILITY IDEOGRAPH-FAA7;Lo;0;L;76DB;;;;N;;;;; -FAA8;CJK COMPATIBILITY IDEOGRAPH-FAA8;Lo;0;L;76F4;;;;N;;;;; -FAA9;CJK COMPATIBILITY IDEOGRAPH-FAA9;Lo;0;L;774A;;;;N;;;;; -FAAA;CJK COMPATIBILITY IDEOGRAPH-FAAA;Lo;0;L;7740;;;;N;;;;; -FAAB;CJK COMPATIBILITY IDEOGRAPH-FAAB;Lo;0;L;78CC;;;;N;;;;; -FAAC;CJK COMPATIBILITY IDEOGRAPH-FAAC;Lo;0;L;7AB1;;;;N;;;;; -FAAD;CJK COMPATIBILITY IDEOGRAPH-FAAD;Lo;0;L;7BC0;;;;N;;;;; -FAAE;CJK COMPATIBILITY IDEOGRAPH-FAAE;Lo;0;L;7C7B;;;;N;;;;; -FAAF;CJK COMPATIBILITY IDEOGRAPH-FAAF;Lo;0;L;7D5B;;;;N;;;;; -FAB0;CJK COMPATIBILITY IDEOGRAPH-FAB0;Lo;0;L;7DF4;;;;N;;;;; -FAB1;CJK COMPATIBILITY IDEOGRAPH-FAB1;Lo;0;L;7F3E;;;;N;;;;; -FAB2;CJK COMPATIBILITY IDEOGRAPH-FAB2;Lo;0;L;8005;;;;N;;;;; -FAB3;CJK COMPATIBILITY IDEOGRAPH-FAB3;Lo;0;L;8352;;;;N;;;;; -FAB4;CJK COMPATIBILITY IDEOGRAPH-FAB4;Lo;0;L;83EF;;;;N;;;;; -FAB5;CJK COMPATIBILITY IDEOGRAPH-FAB5;Lo;0;L;8779;;;;N;;;;; -FAB6;CJK COMPATIBILITY IDEOGRAPH-FAB6;Lo;0;L;8941;;;;N;;;;; -FAB7;CJK COMPATIBILITY IDEOGRAPH-FAB7;Lo;0;L;8986;;;;N;;;;; -FAB8;CJK COMPATIBILITY IDEOGRAPH-FAB8;Lo;0;L;8996;;;;N;;;;; -FAB9;CJK COMPATIBILITY IDEOGRAPH-FAB9;Lo;0;L;8ABF;;;;N;;;;; -FABA;CJK COMPATIBILITY IDEOGRAPH-FABA;Lo;0;L;8AF8;;;;N;;;;; -FABB;CJK COMPATIBILITY IDEOGRAPH-FABB;Lo;0;L;8ACB;;;;N;;;;; -FABC;CJK COMPATIBILITY IDEOGRAPH-FABC;Lo;0;L;8B01;;;;N;;;;; -FABD;CJK COMPATIBILITY IDEOGRAPH-FABD;Lo;0;L;8AFE;;;;N;;;;; -FABE;CJK COMPATIBILITY IDEOGRAPH-FABE;Lo;0;L;8AED;;;;N;;;;; -FABF;CJK COMPATIBILITY IDEOGRAPH-FABF;Lo;0;L;8B39;;;;N;;;;; -FAC0;CJK COMPATIBILITY IDEOGRAPH-FAC0;Lo;0;L;8B8A;;;;N;;;;; -FAC1;CJK COMPATIBILITY IDEOGRAPH-FAC1;Lo;0;L;8D08;;;;N;;;;; -FAC2;CJK COMPATIBILITY IDEOGRAPH-FAC2;Lo;0;L;8F38;;;;N;;;;; -FAC3;CJK COMPATIBILITY IDEOGRAPH-FAC3;Lo;0;L;9072;;;;N;;;;; -FAC4;CJK COMPATIBILITY IDEOGRAPH-FAC4;Lo;0;L;9199;;;;N;;;;; -FAC5;CJK COMPATIBILITY IDEOGRAPH-FAC5;Lo;0;L;9276;;;;N;;;;; -FAC6;CJK COMPATIBILITY IDEOGRAPH-FAC6;Lo;0;L;967C;;;;N;;;;; -FAC7;CJK COMPATIBILITY IDEOGRAPH-FAC7;Lo;0;L;96E3;;;;N;;;;; -FAC8;CJK COMPATIBILITY IDEOGRAPH-FAC8;Lo;0;L;9756;;;;N;;;;; -FAC9;CJK COMPATIBILITY IDEOGRAPH-FAC9;Lo;0;L;97DB;;;;N;;;;; -FACA;CJK COMPATIBILITY IDEOGRAPH-FACA;Lo;0;L;97FF;;;;N;;;;; -FACB;CJK COMPATIBILITY IDEOGRAPH-FACB;Lo;0;L;980B;;;;N;;;;; -FACC;CJK COMPATIBILITY IDEOGRAPH-FACC;Lo;0;L;983B;;;;N;;;;; -FACD;CJK COMPATIBILITY IDEOGRAPH-FACD;Lo;0;L;9B12;;;;N;;;;; -FACE;CJK COMPATIBILITY IDEOGRAPH-FACE;Lo;0;L;9F9C;;;;N;;;;; -FACF;CJK COMPATIBILITY IDEOGRAPH-FACF;Lo;0;L;2284A;;;;N;;;;; -FAD0;CJK COMPATIBILITY IDEOGRAPH-FAD0;Lo;0;L;22844;;;;N;;;;; -FAD1;CJK COMPATIBILITY IDEOGRAPH-FAD1;Lo;0;L;233D5;;;;N;;;;; -FAD2;CJK COMPATIBILITY IDEOGRAPH-FAD2;Lo;0;L;3B9D;;;;N;;;;; -FAD3;CJK COMPATIBILITY IDEOGRAPH-FAD3;Lo;0;L;4018;;;;N;;;;; -FAD4;CJK COMPATIBILITY IDEOGRAPH-FAD4;Lo;0;L;4039;;;;N;;;;; -FAD5;CJK COMPATIBILITY IDEOGRAPH-FAD5;Lo;0;L;25249;;;;N;;;;; -FAD6;CJK COMPATIBILITY IDEOGRAPH-FAD6;Lo;0;L;25CD0;;;;N;;;;; -FAD7;CJK COMPATIBILITY IDEOGRAPH-FAD7;Lo;0;L;27ED3;;;;N;;;;; -FAD8;CJK COMPATIBILITY IDEOGRAPH-FAD8;Lo;0;L;9F43;;;;N;;;;; -FAD9;CJK COMPATIBILITY IDEOGRAPH-FAD9;Lo;0;L;9F8E;;;;N;;;;; -FB00;LATIN SMALL LIGATURE FF;Ll;0;L;<compat> 0066 0066;;;;N;;;;; -FB01;LATIN SMALL LIGATURE FI;Ll;0;L;<compat> 0066 0069;;;;N;;;;; -FB02;LATIN SMALL LIGATURE FL;Ll;0;L;<compat> 0066 006C;;;;N;;;;; -FB03;LATIN SMALL LIGATURE FFI;Ll;0;L;<compat> 0066 0066 0069;;;;N;;;;; -FB04;LATIN SMALL LIGATURE FFL;Ll;0;L;<compat> 0066 0066 006C;;;;N;;;;; -FB05;LATIN SMALL LIGATURE LONG S T;Ll;0;L;<compat> 017F 0074;;;;N;;;;; -FB06;LATIN SMALL LIGATURE ST;Ll;0;L;<compat> 0073 0074;;;;N;;;;; -FB13;ARMENIAN SMALL LIGATURE MEN NOW;Ll;0;L;<compat> 0574 0576;;;;N;;;;; -FB14;ARMENIAN SMALL LIGATURE MEN ECH;Ll;0;L;<compat> 0574 0565;;;;N;;;;; -FB15;ARMENIAN SMALL LIGATURE MEN INI;Ll;0;L;<compat> 0574 056B;;;;N;;;;; -FB16;ARMENIAN SMALL LIGATURE VEW NOW;Ll;0;L;<compat> 057E 0576;;;;N;;;;; -FB17;ARMENIAN SMALL LIGATURE MEN XEH;Ll;0;L;<compat> 0574 056D;;;;N;;;;; -FB1D;HEBREW LETTER YOD WITH HIRIQ;Lo;0;R;05D9 05B4;;;;N;;;;; -FB1E;HEBREW POINT JUDEO-SPANISH VARIKA;Mn;26;NSM;;;;;N;HEBREW POINT VARIKA;;;; -FB1F;HEBREW LIGATURE YIDDISH YOD YOD PATAH;Lo;0;R;05F2 05B7;;;;N;;;;; -FB20;HEBREW LETTER ALTERNATIVE AYIN;Lo;0;R;<font> 05E2;;;;N;;;;; -FB21;HEBREW LETTER WIDE ALEF;Lo;0;R;<font> 05D0;;;;N;;;;; -FB22;HEBREW LETTER WIDE DALET;Lo;0;R;<font> 05D3;;;;N;;;;; -FB23;HEBREW LETTER WIDE HE;Lo;0;R;<font> 05D4;;;;N;;;;; -FB24;HEBREW LETTER WIDE KAF;Lo;0;R;<font> 05DB;;;;N;;;;; -FB25;HEBREW LETTER WIDE LAMED;Lo;0;R;<font> 05DC;;;;N;;;;; -FB26;HEBREW LETTER WIDE FINAL MEM;Lo;0;R;<font> 05DD;;;;N;;;;; -FB27;HEBREW LETTER WIDE RESH;Lo;0;R;<font> 05E8;;;;N;;;;; -FB28;HEBREW LETTER WIDE TAV;Lo;0;R;<font> 05EA;;;;N;;;;; -FB29;HEBREW LETTER ALTERNATIVE PLUS SIGN;Sm;0;ES;<font> 002B;;;;N;;;;; -FB2A;HEBREW LETTER SHIN WITH SHIN DOT;Lo;0;R;05E9 05C1;;;;N;;;;; -FB2B;HEBREW LETTER SHIN WITH SIN DOT;Lo;0;R;05E9 05C2;;;;N;;;;; -FB2C;HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT;Lo;0;R;FB49 05C1;;;;N;;;;; -FB2D;HEBREW LETTER SHIN WITH DAGESH AND SIN DOT;Lo;0;R;FB49 05C2;;;;N;;;;; -FB2E;HEBREW LETTER ALEF WITH PATAH;Lo;0;R;05D0 05B7;;;;N;;;;; -FB2F;HEBREW LETTER ALEF WITH QAMATS;Lo;0;R;05D0 05B8;;;;N;;;;; -FB30;HEBREW LETTER ALEF WITH MAPIQ;Lo;0;R;05D0 05BC;;;;N;;;;; -FB31;HEBREW LETTER BET WITH DAGESH;Lo;0;R;05D1 05BC;;;;N;;;;; -FB32;HEBREW LETTER GIMEL WITH DAGESH;Lo;0;R;05D2 05BC;;;;N;;;;; -FB33;HEBREW LETTER DALET WITH DAGESH;Lo;0;R;05D3 05BC;;;;N;;;;; -FB34;HEBREW LETTER HE WITH MAPIQ;Lo;0;R;05D4 05BC;;;;N;;;;; -FB35;HEBREW LETTER VAV WITH DAGESH;Lo;0;R;05D5 05BC;;;;N;;;;; -FB36;HEBREW LETTER ZAYIN WITH DAGESH;Lo;0;R;05D6 05BC;;;;N;;;;; -FB38;HEBREW LETTER TET WITH DAGESH;Lo;0;R;05D8 05BC;;;;N;;;;; -FB39;HEBREW LETTER YOD WITH DAGESH;Lo;0;R;05D9 05BC;;;;N;;;;; -FB3A;HEBREW LETTER FINAL KAF WITH DAGESH;Lo;0;R;05DA 05BC;;;;N;;;;; -FB3B;HEBREW LETTER KAF WITH DAGESH;Lo;0;R;05DB 05BC;;;;N;;;;; -FB3C;HEBREW LETTER LAMED WITH DAGESH;Lo;0;R;05DC 05BC;;;;N;;;;; -FB3E;HEBREW LETTER MEM WITH DAGESH;Lo;0;R;05DE 05BC;;;;N;;;;; -FB40;HEBREW LETTER NUN WITH DAGESH;Lo;0;R;05E0 05BC;;;;N;;;;; -FB41;HEBREW LETTER SAMEKH WITH DAGESH;Lo;0;R;05E1 05BC;;;;N;;;;; -FB43;HEBREW LETTER FINAL PE WITH DAGESH;Lo;0;R;05E3 05BC;;;;N;;;;; -FB44;HEBREW LETTER PE WITH DAGESH;Lo;0;R;05E4 05BC;;;;N;;;;; -FB46;HEBREW LETTER TSADI WITH DAGESH;Lo;0;R;05E6 05BC;;;;N;;;;; -FB47;HEBREW LETTER QOF WITH DAGESH;Lo;0;R;05E7 05BC;;;;N;;;;; -FB48;HEBREW LETTER RESH WITH DAGESH;Lo;0;R;05E8 05BC;;;;N;;;;; -FB49;HEBREW LETTER SHIN WITH DAGESH;Lo;0;R;05E9 05BC;;;;N;;;;; -FB4A;HEBREW LETTER TAV WITH DAGESH;Lo;0;R;05EA 05BC;;;;N;;;;; -FB4B;HEBREW LETTER VAV WITH HOLAM;Lo;0;R;05D5 05B9;;;;N;;;;; -FB4C;HEBREW LETTER BET WITH RAFE;Lo;0;R;05D1 05BF;;;;N;;;;; -FB4D;HEBREW LETTER KAF WITH RAFE;Lo;0;R;05DB 05BF;;;;N;;;;; -FB4E;HEBREW LETTER PE WITH RAFE;Lo;0;R;05E4 05BF;;;;N;;;;; -FB4F;HEBREW LIGATURE ALEF LAMED;Lo;0;R;<compat> 05D0 05DC;;;;N;;;;; -FB50;ARABIC LETTER ALEF WASLA ISOLATED FORM;Lo;0;AL;<isolated> 0671;;;;N;;;;; -FB51;ARABIC LETTER ALEF WASLA FINAL FORM;Lo;0;AL;<final> 0671;;;;N;;;;; -FB52;ARABIC LETTER BEEH ISOLATED FORM;Lo;0;AL;<isolated> 067B;;;;N;;;;; -FB53;ARABIC LETTER BEEH FINAL FORM;Lo;0;AL;<final> 067B;;;;N;;;;; -FB54;ARABIC LETTER BEEH INITIAL FORM;Lo;0;AL;<initial> 067B;;;;N;;;;; -FB55;ARABIC LETTER BEEH MEDIAL FORM;Lo;0;AL;<medial> 067B;;;;N;;;;; -FB56;ARABIC LETTER PEH ISOLATED FORM;Lo;0;AL;<isolated> 067E;;;;N;;;;; -FB57;ARABIC LETTER PEH FINAL FORM;Lo;0;AL;<final> 067E;;;;N;;;;; -FB58;ARABIC LETTER PEH INITIAL FORM;Lo;0;AL;<initial> 067E;;;;N;;;;; -FB59;ARABIC LETTER PEH MEDIAL FORM;Lo;0;AL;<medial> 067E;;;;N;;;;; -FB5A;ARABIC LETTER BEHEH ISOLATED FORM;Lo;0;AL;<isolated> 0680;;;;N;;;;; -FB5B;ARABIC LETTER BEHEH FINAL FORM;Lo;0;AL;<final> 0680;;;;N;;;;; -FB5C;ARABIC LETTER BEHEH INITIAL FORM;Lo;0;AL;<initial> 0680;;;;N;;;;; -FB5D;ARABIC LETTER BEHEH MEDIAL FORM;Lo;0;AL;<medial> 0680;;;;N;;;;; -FB5E;ARABIC LETTER TTEHEH ISOLATED FORM;Lo;0;AL;<isolated> 067A;;;;N;;;;; -FB5F;ARABIC LETTER TTEHEH FINAL FORM;Lo;0;AL;<final> 067A;;;;N;;;;; -FB60;ARABIC LETTER TTEHEH INITIAL FORM;Lo;0;AL;<initial> 067A;;;;N;;;;; -FB61;ARABIC LETTER TTEHEH MEDIAL FORM;Lo;0;AL;<medial> 067A;;;;N;;;;; -FB62;ARABIC LETTER TEHEH ISOLATED FORM;Lo;0;AL;<isolated> 067F;;;;N;;;;; -FB63;ARABIC LETTER TEHEH FINAL FORM;Lo;0;AL;<final> 067F;;;;N;;;;; -FB64;ARABIC LETTER TEHEH INITIAL FORM;Lo;0;AL;<initial> 067F;;;;N;;;;; -FB65;ARABIC LETTER TEHEH MEDIAL FORM;Lo;0;AL;<medial> 067F;;;;N;;;;; -FB66;ARABIC LETTER TTEH ISOLATED FORM;Lo;0;AL;<isolated> 0679;;;;N;;;;; -FB67;ARABIC LETTER TTEH FINAL FORM;Lo;0;AL;<final> 0679;;;;N;;;;; -FB68;ARABIC LETTER TTEH INITIAL FORM;Lo;0;AL;<initial> 0679;;;;N;;;;; -FB69;ARABIC LETTER TTEH MEDIAL FORM;Lo;0;AL;<medial> 0679;;;;N;;;;; -FB6A;ARABIC LETTER VEH ISOLATED FORM;Lo;0;AL;<isolated> 06A4;;;;N;;;;; -FB6B;ARABIC LETTER VEH FINAL FORM;Lo;0;AL;<final> 06A4;;;;N;;;;; -FB6C;ARABIC LETTER VEH INITIAL FORM;Lo;0;AL;<initial> 06A4;;;;N;;;;; -FB6D;ARABIC LETTER VEH MEDIAL FORM;Lo;0;AL;<medial> 06A4;;;;N;;;;; -FB6E;ARABIC LETTER PEHEH ISOLATED FORM;Lo;0;AL;<isolated> 06A6;;;;N;;;;; -FB6F;ARABIC LETTER PEHEH FINAL FORM;Lo;0;AL;<final> 06A6;;;;N;;;;; -FB70;ARABIC LETTER PEHEH INITIAL FORM;Lo;0;AL;<initial> 06A6;;;;N;;;;; -FB71;ARABIC LETTER PEHEH MEDIAL FORM;Lo;0;AL;<medial> 06A6;;;;N;;;;; -FB72;ARABIC LETTER DYEH ISOLATED FORM;Lo;0;AL;<isolated> 0684;;;;N;;;;; -FB73;ARABIC LETTER DYEH FINAL FORM;Lo;0;AL;<final> 0684;;;;N;;;;; -FB74;ARABIC LETTER DYEH INITIAL FORM;Lo;0;AL;<initial> 0684;;;;N;;;;; -FB75;ARABIC LETTER DYEH MEDIAL FORM;Lo;0;AL;<medial> 0684;;;;N;;;;; -FB76;ARABIC LETTER NYEH ISOLATED FORM;Lo;0;AL;<isolated> 0683;;;;N;;;;; -FB77;ARABIC LETTER NYEH FINAL FORM;Lo;0;AL;<final> 0683;;;;N;;;;; -FB78;ARABIC LETTER NYEH INITIAL FORM;Lo;0;AL;<initial> 0683;;;;N;;;;; -FB79;ARABIC LETTER NYEH MEDIAL FORM;Lo;0;AL;<medial> 0683;;;;N;;;;; -FB7A;ARABIC LETTER TCHEH ISOLATED FORM;Lo;0;AL;<isolated> 0686;;;;N;;;;; -FB7B;ARABIC LETTER TCHEH FINAL FORM;Lo;0;AL;<final> 0686;;;;N;;;;; -FB7C;ARABIC LETTER TCHEH INITIAL FORM;Lo;0;AL;<initial> 0686;;;;N;;;;; -FB7D;ARABIC LETTER TCHEH MEDIAL FORM;Lo;0;AL;<medial> 0686;;;;N;;;;; -FB7E;ARABIC LETTER TCHEHEH ISOLATED FORM;Lo;0;AL;<isolated> 0687;;;;N;;;;; -FB7F;ARABIC LETTER TCHEHEH FINAL FORM;Lo;0;AL;<final> 0687;;;;N;;;;; -FB80;ARABIC LETTER TCHEHEH INITIAL FORM;Lo;0;AL;<initial> 0687;;;;N;;;;; -FB81;ARABIC LETTER TCHEHEH MEDIAL FORM;Lo;0;AL;<medial> 0687;;;;N;;;;; -FB82;ARABIC LETTER DDAHAL ISOLATED FORM;Lo;0;AL;<isolated> 068D;;;;N;;;;; -FB83;ARABIC LETTER DDAHAL FINAL FORM;Lo;0;AL;<final> 068D;;;;N;;;;; -FB84;ARABIC LETTER DAHAL ISOLATED FORM;Lo;0;AL;<isolated> 068C;;;;N;;;;; -FB85;ARABIC LETTER DAHAL FINAL FORM;Lo;0;AL;<final> 068C;;;;N;;;;; -FB86;ARABIC LETTER DUL ISOLATED FORM;Lo;0;AL;<isolated> 068E;;;;N;;;;; -FB87;ARABIC LETTER DUL FINAL FORM;Lo;0;AL;<final> 068E;;;;N;;;;; -FB88;ARABIC LETTER DDAL ISOLATED FORM;Lo;0;AL;<isolated> 0688;;;;N;;;;; -FB89;ARABIC LETTER DDAL FINAL FORM;Lo;0;AL;<final> 0688;;;;N;;;;; -FB8A;ARABIC LETTER JEH ISOLATED FORM;Lo;0;AL;<isolated> 0698;;;;N;;;;; -FB8B;ARABIC LETTER JEH FINAL FORM;Lo;0;AL;<final> 0698;;;;N;;;;; -FB8C;ARABIC LETTER RREH ISOLATED FORM;Lo;0;AL;<isolated> 0691;;;;N;;;;; -FB8D;ARABIC LETTER RREH FINAL FORM;Lo;0;AL;<final> 0691;;;;N;;;;; -FB8E;ARABIC LETTER KEHEH ISOLATED FORM;Lo;0;AL;<isolated> 06A9;;;;N;;;;; -FB8F;ARABIC LETTER KEHEH FINAL FORM;Lo;0;AL;<final> 06A9;;;;N;;;;; -FB90;ARABIC LETTER KEHEH INITIAL FORM;Lo;0;AL;<initial> 06A9;;;;N;;;;; -FB91;ARABIC LETTER KEHEH MEDIAL FORM;Lo;0;AL;<medial> 06A9;;;;N;;;;; -FB92;ARABIC LETTER GAF ISOLATED FORM;Lo;0;AL;<isolated> 06AF;;;;N;;;;; -FB93;ARABIC LETTER GAF FINAL FORM;Lo;0;AL;<final> 06AF;;;;N;;;;; -FB94;ARABIC LETTER GAF INITIAL FORM;Lo;0;AL;<initial> 06AF;;;;N;;;;; -FB95;ARABIC LETTER GAF MEDIAL FORM;Lo;0;AL;<medial> 06AF;;;;N;;;;; -FB96;ARABIC LETTER GUEH ISOLATED FORM;Lo;0;AL;<isolated> 06B3;;;;N;;;;; -FB97;ARABIC LETTER GUEH FINAL FORM;Lo;0;AL;<final> 06B3;;;;N;;;;; -FB98;ARABIC LETTER GUEH INITIAL FORM;Lo;0;AL;<initial> 06B3;;;;N;;;;; -FB99;ARABIC LETTER GUEH MEDIAL FORM;Lo;0;AL;<medial> 06B3;;;;N;;;;; -FB9A;ARABIC LETTER NGOEH ISOLATED FORM;Lo;0;AL;<isolated> 06B1;;;;N;;;;; -FB9B;ARABIC LETTER NGOEH FINAL FORM;Lo;0;AL;<final> 06B1;;;;N;;;;; -FB9C;ARABIC LETTER NGOEH INITIAL FORM;Lo;0;AL;<initial> 06B1;;;;N;;;;; -FB9D;ARABIC LETTER NGOEH MEDIAL FORM;Lo;0;AL;<medial> 06B1;;;;N;;;;; -FB9E;ARABIC LETTER NOON GHUNNA ISOLATED FORM;Lo;0;AL;<isolated> 06BA;;;;N;;;;; -FB9F;ARABIC LETTER NOON GHUNNA FINAL FORM;Lo;0;AL;<final> 06BA;;;;N;;;;; -FBA0;ARABIC LETTER RNOON ISOLATED FORM;Lo;0;AL;<isolated> 06BB;;;;N;;;;; -FBA1;ARABIC LETTER RNOON FINAL FORM;Lo;0;AL;<final> 06BB;;;;N;;;;; -FBA2;ARABIC LETTER RNOON INITIAL FORM;Lo;0;AL;<initial> 06BB;;;;N;;;;; -FBA3;ARABIC LETTER RNOON MEDIAL FORM;Lo;0;AL;<medial> 06BB;;;;N;;;;; -FBA4;ARABIC LETTER HEH WITH YEH ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 06C0;;;;N;;;;; -FBA5;ARABIC LETTER HEH WITH YEH ABOVE FINAL FORM;Lo;0;AL;<final> 06C0;;;;N;;;;; -FBA6;ARABIC LETTER HEH GOAL ISOLATED FORM;Lo;0;AL;<isolated> 06C1;;;;N;;;;; -FBA7;ARABIC LETTER HEH GOAL FINAL FORM;Lo;0;AL;<final> 06C1;;;;N;;;;; -FBA8;ARABIC LETTER HEH GOAL INITIAL FORM;Lo;0;AL;<initial> 06C1;;;;N;;;;; -FBA9;ARABIC LETTER HEH GOAL MEDIAL FORM;Lo;0;AL;<medial> 06C1;;;;N;;;;; -FBAA;ARABIC LETTER HEH DOACHASHMEE ISOLATED FORM;Lo;0;AL;<isolated> 06BE;;;;N;;;;; -FBAB;ARABIC LETTER HEH DOACHASHMEE FINAL FORM;Lo;0;AL;<final> 06BE;;;;N;;;;; -FBAC;ARABIC LETTER HEH DOACHASHMEE INITIAL FORM;Lo;0;AL;<initial> 06BE;;;;N;;;;; -FBAD;ARABIC LETTER HEH DOACHASHMEE MEDIAL FORM;Lo;0;AL;<medial> 06BE;;;;N;;;;; -FBAE;ARABIC LETTER YEH BARREE ISOLATED FORM;Lo;0;AL;<isolated> 06D2;;;;N;;;;; -FBAF;ARABIC LETTER YEH BARREE FINAL FORM;Lo;0;AL;<final> 06D2;;;;N;;;;; -FBB0;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 06D3;;;;N;;;;; -FBB1;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 06D3;;;;N;;;;; -FBB2;ARABIC SYMBOL DOT ABOVE;Sk;0;AL;;;;;N;;;;; -FBB3;ARABIC SYMBOL DOT BELOW;Sk;0;AL;;;;;N;;;;; -FBB4;ARABIC SYMBOL TWO DOTS ABOVE;Sk;0;AL;;;;;N;;;;; -FBB5;ARABIC SYMBOL TWO DOTS BELOW;Sk;0;AL;;;;;N;;;;; -FBB6;ARABIC SYMBOL THREE DOTS ABOVE;Sk;0;AL;;;;;N;;;;; -FBB7;ARABIC SYMBOL THREE DOTS BELOW;Sk;0;AL;;;;;N;;;;; -FBB8;ARABIC SYMBOL THREE DOTS POINTING DOWNWARDS ABOVE;Sk;0;AL;;;;;N;;;;; -FBB9;ARABIC SYMBOL THREE DOTS POINTING DOWNWARDS BELOW;Sk;0;AL;;;;;N;;;;; -FBBA;ARABIC SYMBOL FOUR DOTS ABOVE;Sk;0;AL;;;;;N;;;;; -FBBB;ARABIC SYMBOL FOUR DOTS BELOW;Sk;0;AL;;;;;N;;;;; -FBBC;ARABIC SYMBOL DOUBLE VERTICAL BAR BELOW;Sk;0;AL;;;;;N;;;;; -FBBD;ARABIC SYMBOL TWO DOTS VERTICALLY ABOVE;Sk;0;AL;;;;;N;;;;; -FBBE;ARABIC SYMBOL TWO DOTS VERTICALLY BELOW;Sk;0;AL;;;;;N;;;;; -FBBF;ARABIC SYMBOL RING;Sk;0;AL;;;;;N;;;;; -FBC0;ARABIC SYMBOL SMALL TAH ABOVE;Sk;0;AL;;;;;N;;;;; -FBC1;ARABIC SYMBOL SMALL TAH BELOW;Sk;0;AL;;;;;N;;;;; -FBC2;ARABIC SYMBOL WASLA ABOVE;Sk;0;AL;;;;;N;;;;; -FBD3;ARABIC LETTER NG ISOLATED FORM;Lo;0;AL;<isolated> 06AD;;;;N;;;;; -FBD4;ARABIC LETTER NG FINAL FORM;Lo;0;AL;<final> 06AD;;;;N;;;;; -FBD5;ARABIC LETTER NG INITIAL FORM;Lo;0;AL;<initial> 06AD;;;;N;;;;; -FBD6;ARABIC LETTER NG MEDIAL FORM;Lo;0;AL;<medial> 06AD;;;;N;;;;; -FBD7;ARABIC LETTER U ISOLATED FORM;Lo;0;AL;<isolated> 06C7;;;;N;;;;; -FBD8;ARABIC LETTER U FINAL FORM;Lo;0;AL;<final> 06C7;;;;N;;;;; -FBD9;ARABIC LETTER OE ISOLATED FORM;Lo;0;AL;<isolated> 06C6;;;;N;;;;; -FBDA;ARABIC LETTER OE FINAL FORM;Lo;0;AL;<final> 06C6;;;;N;;;;; -FBDB;ARABIC LETTER YU ISOLATED FORM;Lo;0;AL;<isolated> 06C8;;;;N;;;;; -FBDC;ARABIC LETTER YU FINAL FORM;Lo;0;AL;<final> 06C8;;;;N;;;;; -FBDD;ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0677;;;;N;;;;; -FBDE;ARABIC LETTER VE ISOLATED FORM;Lo;0;AL;<isolated> 06CB;;;;N;;;;; -FBDF;ARABIC LETTER VE FINAL FORM;Lo;0;AL;<final> 06CB;;;;N;;;;; -FBE0;ARABIC LETTER KIRGHIZ OE ISOLATED FORM;Lo;0;AL;<isolated> 06C5;;;;N;;;;; -FBE1;ARABIC LETTER KIRGHIZ OE FINAL FORM;Lo;0;AL;<final> 06C5;;;;N;;;;; -FBE2;ARABIC LETTER KIRGHIZ YU ISOLATED FORM;Lo;0;AL;<isolated> 06C9;;;;N;;;;; -FBE3;ARABIC LETTER KIRGHIZ YU FINAL FORM;Lo;0;AL;<final> 06C9;;;;N;;;;; -FBE4;ARABIC LETTER E ISOLATED FORM;Lo;0;AL;<isolated> 06D0;;;;N;;;;; -FBE5;ARABIC LETTER E FINAL FORM;Lo;0;AL;<final> 06D0;;;;N;;;;; -FBE6;ARABIC LETTER E INITIAL FORM;Lo;0;AL;<initial> 06D0;;;;N;;;;; -FBE7;ARABIC LETTER E MEDIAL FORM;Lo;0;AL;<medial> 06D0;;;;N;;;;; -FBE8;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM;Lo;0;AL;<initial> 0649;;;;N;;;;; -FBE9;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA MEDIAL FORM;Lo;0;AL;<medial> 0649;;;;N;;;;; -FBEA;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0626 0627;;;;N;;;;; -FBEB;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF FINAL FORM;Lo;0;AL;<final> 0626 0627;;;;N;;;;; -FBEC;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE ISOLATED FORM;Lo;0;AL;<isolated> 0626 06D5;;;;N;;;;; -FBED;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE FINAL FORM;Lo;0;AL;<final> 0626 06D5;;;;N;;;;; -FBEE;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW ISOLATED FORM;Lo;0;AL;<isolated> 0626 0648;;;;N;;;;; -FBEF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW FINAL FORM;Lo;0;AL;<final> 0626 0648;;;;N;;;;; -FBF0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C7;;;;N;;;;; -FBF1;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U FINAL FORM;Lo;0;AL;<final> 0626 06C7;;;;N;;;;; -FBF2;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C6;;;;N;;;;; -FBF3;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE FINAL FORM;Lo;0;AL;<final> 0626 06C6;;;;N;;;;; -FBF4;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C8;;;;N;;;;; -FBF5;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU FINAL FORM;Lo;0;AL;<final> 0626 06C8;;;;N;;;;; -FBF6;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E ISOLATED FORM;Lo;0;AL;<isolated> 0626 06D0;;;;N;;;;; -FBF7;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E FINAL FORM;Lo;0;AL;<final> 0626 06D0;;;;N;;;;; -FBF8;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E INITIAL FORM;Lo;0;AL;<initial> 0626 06D0;;;;N;;;;; -FBF9;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0626 0649;;;;N;;;;; -FBFA;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0626 0649;;;;N;;;;; -FBFB;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA INITIAL FORM;Lo;0;AL;<initial> 0626 0649;;;;N;;;;; -FBFC;ARABIC LETTER FARSI YEH ISOLATED FORM;Lo;0;AL;<isolated> 06CC;;;;N;;;;; -FBFD;ARABIC LETTER FARSI YEH FINAL FORM;Lo;0;AL;<final> 06CC;;;;N;;;;; -FBFE;ARABIC LETTER FARSI YEH INITIAL FORM;Lo;0;AL;<initial> 06CC;;;;N;;;;; -FBFF;ARABIC LETTER FARSI YEH MEDIAL FORM;Lo;0;AL;<medial> 06CC;;;;N;;;;; -FC00;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0626 062C;;;;N;;;;; -FC01;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0626 062D;;;;N;;;;; -FC02;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0626 0645;;;;N;;;;; -FC03;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0626 0649;;;;N;;;;; -FC04;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0626 064A;;;;N;;;;; -FC05;ARABIC LIGATURE BEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0628 062C;;;;N;;;;; -FC06;ARABIC LIGATURE BEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0628 062D;;;;N;;;;; -FC07;ARABIC LIGATURE BEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0628 062E;;;;N;;;;; -FC08;ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0628 0645;;;;N;;;;; -FC09;ARABIC LIGATURE BEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0628 0649;;;;N;;;;; -FC0A;ARABIC LIGATURE BEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0628 064A;;;;N;;;;; -FC0B;ARABIC LIGATURE TEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062A 062C;;;;N;;;;; -FC0C;ARABIC LIGATURE TEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062A 062D;;;;N;;;;; -FC0D;ARABIC LIGATURE TEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 062A 062E;;;;N;;;;; -FC0E;ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062A 0645;;;;N;;;;; -FC0F;ARABIC LIGATURE TEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062A 0649;;;;N;;;;; -FC10;ARABIC LIGATURE TEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062A 064A;;;;N;;;;; -FC11;ARABIC LIGATURE THEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062B 062C;;;;N;;;;; -FC12;ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062B 0645;;;;N;;;;; -FC13;ARABIC LIGATURE THEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062B 0649;;;;N;;;;; -FC14;ARABIC LIGATURE THEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062B 064A;;;;N;;;;; -FC15;ARABIC LIGATURE JEEM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062C 062D;;;;N;;;;; -FC16;ARABIC LIGATURE JEEM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062C 0645;;;;N;;;;; -FC17;ARABIC LIGATURE HAH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062D 062C;;;;N;;;;; -FC18;ARABIC LIGATURE HAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062D 0645;;;;N;;;;; -FC19;ARABIC LIGATURE KHAH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062E 062C;;;;N;;;;; -FC1A;ARABIC LIGATURE KHAH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062E 062D;;;;N;;;;; -FC1B;ARABIC LIGATURE KHAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062E 0645;;;;N;;;;; -FC1C;ARABIC LIGATURE SEEN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0633 062C;;;;N;;;;; -FC1D;ARABIC LIGATURE SEEN WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0633 062D;;;;N;;;;; -FC1E;ARABIC LIGATURE SEEN WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0633 062E;;;;N;;;;; -FC1F;ARABIC LIGATURE SEEN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0633 0645;;;;N;;;;; -FC20;ARABIC LIGATURE SAD WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0635 062D;;;;N;;;;; -FC21;ARABIC LIGATURE SAD WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0635 0645;;;;N;;;;; -FC22;ARABIC LIGATURE DAD WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0636 062C;;;;N;;;;; -FC23;ARABIC LIGATURE DAD WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0636 062D;;;;N;;;;; -FC24;ARABIC LIGATURE DAD WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0636 062E;;;;N;;;;; -FC25;ARABIC LIGATURE DAD WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0636 0645;;;;N;;;;; -FC26;ARABIC LIGATURE TAH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0637 062D;;;;N;;;;; -FC27;ARABIC LIGATURE TAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0637 0645;;;;N;;;;; -FC28;ARABIC LIGATURE ZAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0638 0645;;;;N;;;;; -FC29;ARABIC LIGATURE AIN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0639 062C;;;;N;;;;; -FC2A;ARABIC LIGATURE AIN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0639 0645;;;;N;;;;; -FC2B;ARABIC LIGATURE GHAIN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 063A 062C;;;;N;;;;; -FC2C;ARABIC LIGATURE GHAIN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 063A 0645;;;;N;;;;; -FC2D;ARABIC LIGATURE FEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0641 062C;;;;N;;;;; -FC2E;ARABIC LIGATURE FEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0641 062D;;;;N;;;;; -FC2F;ARABIC LIGATURE FEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0641 062E;;;;N;;;;; -FC30;ARABIC LIGATURE FEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0641 0645;;;;N;;;;; -FC31;ARABIC LIGATURE FEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0641 0649;;;;N;;;;; -FC32;ARABIC LIGATURE FEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0641 064A;;;;N;;;;; -FC33;ARABIC LIGATURE QAF WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0642 062D;;;;N;;;;; -FC34;ARABIC LIGATURE QAF WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0642 0645;;;;N;;;;; -FC35;ARABIC LIGATURE QAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0642 0649;;;;N;;;;; -FC36;ARABIC LIGATURE QAF WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0642 064A;;;;N;;;;; -FC37;ARABIC LIGATURE KAF WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0643 0627;;;;N;;;;; -FC38;ARABIC LIGATURE KAF WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0643 062C;;;;N;;;;; -FC39;ARABIC LIGATURE KAF WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0643 062D;;;;N;;;;; -FC3A;ARABIC LIGATURE KAF WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0643 062E;;;;N;;;;; -FC3B;ARABIC LIGATURE KAF WITH LAM ISOLATED FORM;Lo;0;AL;<isolated> 0643 0644;;;;N;;;;; -FC3C;ARABIC LIGATURE KAF WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0643 0645;;;;N;;;;; -FC3D;ARABIC LIGATURE KAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0643 0649;;;;N;;;;; -FC3E;ARABIC LIGATURE KAF WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0643 064A;;;;N;;;;; -FC3F;ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0644 062C;;;;N;;;;; -FC40;ARABIC LIGATURE LAM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0644 062D;;;;N;;;;; -FC41;ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0644 062E;;;;N;;;;; -FC42;ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0644 0645;;;;N;;;;; -FC43;ARABIC LIGATURE LAM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0644 0649;;;;N;;;;; -FC44;ARABIC LIGATURE LAM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0644 064A;;;;N;;;;; -FC45;ARABIC LIGATURE MEEM WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645 062C;;;;N;;;;; -FC46;ARABIC LIGATURE MEEM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0645 062D;;;;N;;;;; -FC47;ARABIC LIGATURE MEEM WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0645 062E;;;;N;;;;; -FC48;ARABIC LIGATURE MEEM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645 0645;;;;N;;;;; -FC49;ARABIC LIGATURE MEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0645 0649;;;;N;;;;; -FC4A;ARABIC LIGATURE MEEM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0645 064A;;;;N;;;;; -FC4B;ARABIC LIGATURE NOON WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0646 062C;;;;N;;;;; -FC4C;ARABIC LIGATURE NOON WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0646 062D;;;;N;;;;; -FC4D;ARABIC LIGATURE NOON WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0646 062E;;;;N;;;;; -FC4E;ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0646 0645;;;;N;;;;; -FC4F;ARABIC LIGATURE NOON WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0646 0649;;;;N;;;;; -FC50;ARABIC LIGATURE NOON WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0646 064A;;;;N;;;;; -FC51;ARABIC LIGATURE HEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0647 062C;;;;N;;;;; -FC52;ARABIC LIGATURE HEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0647 0645;;;;N;;;;; -FC53;ARABIC LIGATURE HEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0647 0649;;;;N;;;;; -FC54;ARABIC LIGATURE HEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0647 064A;;;;N;;;;; -FC55;ARABIC LIGATURE YEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 064A 062C;;;;N;;;;; -FC56;ARABIC LIGATURE YEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 064A 062D;;;;N;;;;; -FC57;ARABIC LIGATURE YEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 064A 062E;;;;N;;;;; -FC58;ARABIC LIGATURE YEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 064A 0645;;;;N;;;;; -FC59;ARABIC LIGATURE YEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 064A 0649;;;;N;;;;; -FC5A;ARABIC LIGATURE YEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 064A 064A;;;;N;;;;; -FC5B;ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0630 0670;;;;N;;;;; -FC5C;ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0631 0670;;;;N;;;;; -FC5D;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0649 0670;;;;N;;;;; -FC5E;ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064C 0651;;;;N;;;;; -FC5F;ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064D 0651;;;;N;;;;; -FC60;ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064E 0651;;;;N;;;;; -FC61;ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064F 0651;;;;N;;;;; -FC62;ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0650 0651;;;;N;;;;; -FC63;ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0020 0651 0670;;;;N;;;;; -FC64;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORM;Lo;0;AL;<final> 0626 0631;;;;N;;;;; -FC65;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0626 0632;;;;N;;;;; -FC66;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM FINAL FORM;Lo;0;AL;<final> 0626 0645;;;;N;;;;; -FC67;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON FINAL FORM;Lo;0;AL;<final> 0626 0646;;;;N;;;;; -FC68;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0626 0649;;;;N;;;;; -FC69;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH FINAL FORM;Lo;0;AL;<final> 0626 064A;;;;N;;;;; -FC6A;ARABIC LIGATURE BEH WITH REH FINAL FORM;Lo;0;AL;<final> 0628 0631;;;;N;;;;; -FC6B;ARABIC LIGATURE BEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0628 0632;;;;N;;;;; -FC6C;ARABIC LIGATURE BEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0628 0645;;;;N;;;;; -FC6D;ARABIC LIGATURE BEH WITH NOON FINAL FORM;Lo;0;AL;<final> 0628 0646;;;;N;;;;; -FC6E;ARABIC LIGATURE BEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0628 0649;;;;N;;;;; -FC6F;ARABIC LIGATURE BEH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 064A;;;;N;;;;; -FC70;ARABIC LIGATURE TEH WITH REH FINAL FORM;Lo;0;AL;<final> 062A 0631;;;;N;;;;; -FC71;ARABIC LIGATURE TEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 062A 0632;;;;N;;;;; -FC72;ARABIC LIGATURE TEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 062A 0645;;;;N;;;;; -FC73;ARABIC LIGATURE TEH WITH NOON FINAL FORM;Lo;0;AL;<final> 062A 0646;;;;N;;;;; -FC74;ARABIC LIGATURE TEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 0649;;;;N;;;;; -FC75;ARABIC LIGATURE TEH WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 064A;;;;N;;;;; -FC76;ARABIC LIGATURE THEH WITH REH FINAL FORM;Lo;0;AL;<final> 062B 0631;;;;N;;;;; -FC77;ARABIC LIGATURE THEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 062B 0632;;;;N;;;;; -FC78;ARABIC LIGATURE THEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 062B 0645;;;;N;;;;; -FC79;ARABIC LIGATURE THEH WITH NOON FINAL FORM;Lo;0;AL;<final> 062B 0646;;;;N;;;;; -FC7A;ARABIC LIGATURE THEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062B 0649;;;;N;;;;; -FC7B;ARABIC LIGATURE THEH WITH YEH FINAL FORM;Lo;0;AL;<final> 062B 064A;;;;N;;;;; -FC7C;ARABIC LIGATURE FEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0641 0649;;;;N;;;;; -FC7D;ARABIC LIGATURE FEH WITH YEH FINAL FORM;Lo;0;AL;<final> 0641 064A;;;;N;;;;; -FC7E;ARABIC LIGATURE QAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0642 0649;;;;N;;;;; -FC7F;ARABIC LIGATURE QAF WITH YEH FINAL FORM;Lo;0;AL;<final> 0642 064A;;;;N;;;;; -FC80;ARABIC LIGATURE KAF WITH ALEF FINAL FORM;Lo;0;AL;<final> 0643 0627;;;;N;;;;; -FC81;ARABIC LIGATURE KAF WITH LAM FINAL FORM;Lo;0;AL;<final> 0643 0644;;;;N;;;;; -FC82;ARABIC LIGATURE KAF WITH MEEM FINAL FORM;Lo;0;AL;<final> 0643 0645;;;;N;;;;; -FC83;ARABIC LIGATURE KAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0643 0649;;;;N;;;;; -FC84;ARABIC LIGATURE KAF WITH YEH FINAL FORM;Lo;0;AL;<final> 0643 064A;;;;N;;;;; -FC85;ARABIC LIGATURE LAM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 0645;;;;N;;;;; -FC86;ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0644 0649;;;;N;;;;; -FC87;ARABIC LIGATURE LAM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 064A;;;;N;;;;; -FC88;ARABIC LIGATURE MEEM WITH ALEF FINAL FORM;Lo;0;AL;<final> 0645 0627;;;;N;;;;; -FC89;ARABIC LIGATURE MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0645 0645;;;;N;;;;; -FC8A;ARABIC LIGATURE NOON WITH REH FINAL FORM;Lo;0;AL;<final> 0646 0631;;;;N;;;;; -FC8B;ARABIC LIGATURE NOON WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0646 0632;;;;N;;;;; -FC8C;ARABIC LIGATURE NOON WITH MEEM FINAL FORM;Lo;0;AL;<final> 0646 0645;;;;N;;;;; -FC8D;ARABIC LIGATURE NOON WITH NOON FINAL FORM;Lo;0;AL;<final> 0646 0646;;;;N;;;;; -FC8E;ARABIC LIGATURE NOON WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 0649;;;;N;;;;; -FC8F;ARABIC LIGATURE NOON WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 064A;;;;N;;;;; -FC90;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF FINAL FORM;Lo;0;AL;<final> 0649 0670;;;;N;;;;; -FC91;ARABIC LIGATURE YEH WITH REH FINAL FORM;Lo;0;AL;<final> 064A 0631;;;;N;;;;; -FC92;ARABIC LIGATURE YEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 064A 0632;;;;N;;;;; -FC93;ARABIC LIGATURE YEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 064A 0645;;;;N;;;;; -FC94;ARABIC LIGATURE YEH WITH NOON FINAL FORM;Lo;0;AL;<final> 064A 0646;;;;N;;;;; -FC95;ARABIC LIGATURE YEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 064A 0649;;;;N;;;;; -FC96;ARABIC LIGATURE YEH WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 064A;;;;N;;;;; -FC97;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0626 062C;;;;N;;;;; -FC98;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0626 062D;;;;N;;;;; -FC99;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0626 062E;;;;N;;;;; -FC9A;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0626 0645;;;;N;;;;; -FC9B;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0626 0647;;;;N;;;;; -FC9C;ARABIC LIGATURE BEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0628 062C;;;;N;;;;; -FC9D;ARABIC LIGATURE BEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0628 062D;;;;N;;;;; -FC9E;ARABIC LIGATURE BEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0628 062E;;;;N;;;;; -FC9F;ARABIC LIGATURE BEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0628 0645;;;;N;;;;; -FCA0;ARABIC LIGATURE BEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0628 0647;;;;N;;;;; -FCA1;ARABIC LIGATURE TEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062C;;;;N;;;;; -FCA2;ARABIC LIGATURE TEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062A 062D;;;;N;;;;; -FCA3;ARABIC LIGATURE TEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 062A 062E;;;;N;;;;; -FCA4;ARABIC LIGATURE TEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 0645;;;;N;;;;; -FCA5;ARABIC LIGATURE TEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 062A 0647;;;;N;;;;; -FCA6;ARABIC LIGATURE THEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062B 0645;;;;N;;;;; -FCA7;ARABIC LIGATURE JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062C 062D;;;;N;;;;; -FCA8;ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062C 0645;;;;N;;;;; -FCA9;ARABIC LIGATURE HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062D 062C;;;;N;;;;; -FCAA;ARABIC LIGATURE HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062D 0645;;;;N;;;;; -FCAB;ARABIC LIGATURE KHAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062E 062C;;;;N;;;;; -FCAC;ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062E 0645;;;;N;;;;; -FCAD;ARABIC LIGATURE SEEN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 062C;;;;N;;;;; -FCAE;ARABIC LIGATURE SEEN WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 062D;;;;N;;;;; -FCAF;ARABIC LIGATURE SEEN WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0633 062E;;;;N;;;;; -FCB0;ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645;;;;N;;;;; -FCB1;ARABIC LIGATURE SAD WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0635 062D;;;;N;;;;; -FCB2;ARABIC LIGATURE SAD WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0635 062E;;;;N;;;;; -FCB3;ARABIC LIGATURE SAD WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0635 0645;;;;N;;;;; -FCB4;ARABIC LIGATURE DAD WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0636 062C;;;;N;;;;; -FCB5;ARABIC LIGATURE DAD WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0636 062D;;;;N;;;;; -FCB6;ARABIC LIGATURE DAD WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0636 062E;;;;N;;;;; -FCB7;ARABIC LIGATURE DAD WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0636 0645;;;;N;;;;; -FCB8;ARABIC LIGATURE TAH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0637 062D;;;;N;;;;; -FCB9;ARABIC LIGATURE ZAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0638 0645;;;;N;;;;; -FCBA;ARABIC LIGATURE AIN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0639 062C;;;;N;;;;; -FCBB;ARABIC LIGATURE AIN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 0645;;;;N;;;;; -FCBC;ARABIC LIGATURE GHAIN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 063A 062C;;;;N;;;;; -FCBD;ARABIC LIGATURE GHAIN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 063A 0645;;;;N;;;;; -FCBE;ARABIC LIGATURE FEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0641 062C;;;;N;;;;; -FCBF;ARABIC LIGATURE FEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0641 062D;;;;N;;;;; -FCC0;ARABIC LIGATURE FEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0641 062E;;;;N;;;;; -FCC1;ARABIC LIGATURE FEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0641 0645;;;;N;;;;; -FCC2;ARABIC LIGATURE QAF WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0642 062D;;;;N;;;;; -FCC3;ARABIC LIGATURE QAF WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0642 0645;;;;N;;;;; -FCC4;ARABIC LIGATURE KAF WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0643 062C;;;;N;;;;; -FCC5;ARABIC LIGATURE KAF WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0643 062D;;;;N;;;;; -FCC6;ARABIC LIGATURE KAF WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0643 062E;;;;N;;;;; -FCC7;ARABIC LIGATURE KAF WITH LAM INITIAL FORM;Lo;0;AL;<initial> 0643 0644;;;;N;;;;; -FCC8;ARABIC LIGATURE KAF WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0643 0645;;;;N;;;;; -FCC9;ARABIC LIGATURE LAM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C;;;;N;;;;; -FCCA;ARABIC LIGATURE LAM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0644 062D;;;;N;;;;; -FCCB;ARABIC LIGATURE LAM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0644 062E;;;;N;;;;; -FCCC;ARABIC LIGATURE LAM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 0645;;;;N;;;;; -FCCD;ARABIC LIGATURE LAM WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0644 0647;;;;N;;;;; -FCCE;ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062C;;;;N;;;;; -FCCF;ARABIC LIGATURE MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0645 062D;;;;N;;;;; -FCD0;ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0645 062E;;;;N;;;;; -FCD1;ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 0645;;;;N;;;;; -FCD2;ARABIC LIGATURE NOON WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062C;;;;N;;;;; -FCD3;ARABIC LIGATURE NOON WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0646 062D;;;;N;;;;; -FCD4;ARABIC LIGATURE NOON WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0646 062E;;;;N;;;;; -FCD5;ARABIC LIGATURE NOON WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 0645;;;;N;;;;; -FCD6;ARABIC LIGATURE NOON WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0646 0647;;;;N;;;;; -FCD7;ARABIC LIGATURE HEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0647 062C;;;;N;;;;; -FCD8;ARABIC LIGATURE HEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645;;;;N;;;;; -FCD9;ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF INITIAL FORM;Lo;0;AL;<initial> 0647 0670;;;;N;;;;; -FCDA;ARABIC LIGATURE YEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 064A 062C;;;;N;;;;; -FCDB;ARABIC LIGATURE YEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 064A 062D;;;;N;;;;; -FCDC;ARABIC LIGATURE YEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 064A 062E;;;;N;;;;; -FCDD;ARABIC LIGATURE YEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 064A 0645;;;;N;;;;; -FCDE;ARABIC LIGATURE YEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 064A 0647;;;;N;;;;; -FCDF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0626 0645;;;;N;;;;; -FCE0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0626 0647;;;;N;;;;; -FCE1;ARABIC LIGATURE BEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0628 0645;;;;N;;;;; -FCE2;ARABIC LIGATURE BEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0628 0647;;;;N;;;;; -FCE3;ARABIC LIGATURE TEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 062A 0645;;;;N;;;;; -FCE4;ARABIC LIGATURE TEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 062A 0647;;;;N;;;;; -FCE5;ARABIC LIGATURE THEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 062B 0645;;;;N;;;;; -FCE6;ARABIC LIGATURE THEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 062B 0647;;;;N;;;;; -FCE7;ARABIC LIGATURE SEEN WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0633 0645;;;;N;;;;; -FCE8;ARABIC LIGATURE SEEN WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0633 0647;;;;N;;;;; -FCE9;ARABIC LIGATURE SHEEN WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0634 0645;;;;N;;;;; -FCEA;ARABIC LIGATURE SHEEN WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0634 0647;;;;N;;;;; -FCEB;ARABIC LIGATURE KAF WITH LAM MEDIAL FORM;Lo;0;AL;<medial> 0643 0644;;;;N;;;;; -FCEC;ARABIC LIGATURE KAF WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0643 0645;;;;N;;;;; -FCED;ARABIC LIGATURE LAM WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0644 0645;;;;N;;;;; -FCEE;ARABIC LIGATURE NOON WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0646 0645;;;;N;;;;; -FCEF;ARABIC LIGATURE NOON WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0646 0647;;;;N;;;;; -FCF0;ARABIC LIGATURE YEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 064A 0645;;;;N;;;;; -FCF1;ARABIC LIGATURE YEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 064A 0647;;;;N;;;;; -FCF2;ARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORM;Lo;0;AL;<medial> 0640 064E 0651;;;;N;;;;; -FCF3;ARABIC LIGATURE SHADDA WITH DAMMA MEDIAL FORM;Lo;0;AL;<medial> 0640 064F 0651;;;;N;;;;; -FCF4;ARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORM;Lo;0;AL;<medial> 0640 0650 0651;;;;N;;;;; -FCF5;ARABIC LIGATURE TAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0637 0649;;;;N;;;;; -FCF6;ARABIC LIGATURE TAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0637 064A;;;;N;;;;; -FCF7;ARABIC LIGATURE AIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0639 0649;;;;N;;;;; -FCF8;ARABIC LIGATURE AIN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0639 064A;;;;N;;;;; -FCF9;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 063A 0649;;;;N;;;;; -FCFA;ARABIC LIGATURE GHAIN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 063A 064A;;;;N;;;;; -FCFB;ARABIC LIGATURE SEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0633 0649;;;;N;;;;; -FCFC;ARABIC LIGATURE SEEN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0633 064A;;;;N;;;;; -FCFD;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0634 0649;;;;N;;;;; -FCFE;ARABIC LIGATURE SHEEN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0634 064A;;;;N;;;;; -FCFF;ARABIC LIGATURE HAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062D 0649;;;;N;;;;; -FD00;ARABIC LIGATURE HAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062D 064A;;;;N;;;;; -FD01;ARABIC LIGATURE JEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062C 0649;;;;N;;;;; -FD02;ARABIC LIGATURE JEEM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062C 064A;;;;N;;;;; -FD03;ARABIC LIGATURE KHAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062E 0649;;;;N;;;;; -FD04;ARABIC LIGATURE KHAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062E 064A;;;;N;;;;; -FD05;ARABIC LIGATURE SAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0635 0649;;;;N;;;;; -FD06;ARABIC LIGATURE SAD WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0635 064A;;;;N;;;;; -FD07;ARABIC LIGATURE DAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0636 0649;;;;N;;;;; -FD08;ARABIC LIGATURE DAD WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0636 064A;;;;N;;;;; -FD09;ARABIC LIGATURE SHEEN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0634 062C;;;;N;;;;; -FD0A;ARABIC LIGATURE SHEEN WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0634 062D;;;;N;;;;; -FD0B;ARABIC LIGATURE SHEEN WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0634 062E;;;;N;;;;; -FD0C;ARABIC LIGATURE SHEEN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0634 0645;;;;N;;;;; -FD0D;ARABIC LIGATURE SHEEN WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0634 0631;;;;N;;;;; -FD0E;ARABIC LIGATURE SEEN WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0633 0631;;;;N;;;;; -FD0F;ARABIC LIGATURE SAD WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0635 0631;;;;N;;;;; -FD10;ARABIC LIGATURE DAD WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0636 0631;;;;N;;;;; -FD11;ARABIC LIGATURE TAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0637 0649;;;;N;;;;; -FD12;ARABIC LIGATURE TAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0637 064A;;;;N;;;;; -FD13;ARABIC LIGATURE AIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0639 0649;;;;N;;;;; -FD14;ARABIC LIGATURE AIN WITH YEH FINAL FORM;Lo;0;AL;<final> 0639 064A;;;;N;;;;; -FD15;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 063A 0649;;;;N;;;;; -FD16;ARABIC LIGATURE GHAIN WITH YEH FINAL FORM;Lo;0;AL;<final> 063A 064A;;;;N;;;;; -FD17;ARABIC LIGATURE SEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 0649;;;;N;;;;; -FD18;ARABIC LIGATURE SEEN WITH YEH FINAL FORM;Lo;0;AL;<final> 0633 064A;;;;N;;;;; -FD19;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0634 0649;;;;N;;;;; -FD1A;ARABIC LIGATURE SHEEN WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 064A;;;;N;;;;; -FD1B;ARABIC LIGATURE HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062D 0649;;;;N;;;;; -FD1C;ARABIC LIGATURE HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 064A;;;;N;;;;; -FD1D;ARABIC LIGATURE JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 0649;;;;N;;;;; -FD1E;ARABIC LIGATURE JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 064A;;;;N;;;;; -FD1F;ARABIC LIGATURE KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062E 0649;;;;N;;;;; -FD20;ARABIC LIGATURE KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062E 064A;;;;N;;;;; -FD21;ARABIC LIGATURE SAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0635 0649;;;;N;;;;; -FD22;ARABIC LIGATURE SAD WITH YEH FINAL FORM;Lo;0;AL;<final> 0635 064A;;;;N;;;;; -FD23;ARABIC LIGATURE DAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0636 0649;;;;N;;;;; -FD24;ARABIC LIGATURE DAD WITH YEH FINAL FORM;Lo;0;AL;<final> 0636 064A;;;;N;;;;; -FD25;ARABIC LIGATURE SHEEN WITH JEEM FINAL FORM;Lo;0;AL;<final> 0634 062C;;;;N;;;;; -FD26;ARABIC LIGATURE SHEEN WITH HAH FINAL FORM;Lo;0;AL;<final> 0634 062D;;;;N;;;;; -FD27;ARABIC LIGATURE SHEEN WITH KHAH FINAL FORM;Lo;0;AL;<final> 0634 062E;;;;N;;;;; -FD28;ARABIC LIGATURE SHEEN WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 0645;;;;N;;;;; -FD29;ARABIC LIGATURE SHEEN WITH REH FINAL FORM;Lo;0;AL;<final> 0634 0631;;;;N;;;;; -FD2A;ARABIC LIGATURE SEEN WITH REH FINAL FORM;Lo;0;AL;<final> 0633 0631;;;;N;;;;; -FD2B;ARABIC LIGATURE SAD WITH REH FINAL FORM;Lo;0;AL;<final> 0635 0631;;;;N;;;;; -FD2C;ARABIC LIGATURE DAD WITH REH FINAL FORM;Lo;0;AL;<final> 0636 0631;;;;N;;;;; -FD2D;ARABIC LIGATURE SHEEN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0634 062C;;;;N;;;;; -FD2E;ARABIC LIGATURE SHEEN WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0634 062D;;;;N;;;;; -FD2F;ARABIC LIGATURE SHEEN WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0634 062E;;;;N;;;;; -FD30;ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 0645;;;;N;;;;; -FD31;ARABIC LIGATURE SEEN WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0633 0647;;;;N;;;;; -FD32;ARABIC LIGATURE SHEEN WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0634 0647;;;;N;;;;; -FD33;ARABIC LIGATURE TAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0637 0645;;;;N;;;;; -FD34;ARABIC LIGATURE SEEN WITH JEEM MEDIAL FORM;Lo;0;AL;<medial> 0633 062C;;;;N;;;;; -FD35;ARABIC LIGATURE SEEN WITH HAH MEDIAL FORM;Lo;0;AL;<medial> 0633 062D;;;;N;;;;; -FD36;ARABIC LIGATURE SEEN WITH KHAH MEDIAL FORM;Lo;0;AL;<medial> 0633 062E;;;;N;;;;; -FD37;ARABIC LIGATURE SHEEN WITH JEEM MEDIAL FORM;Lo;0;AL;<medial> 0634 062C;;;;N;;;;; -FD38;ARABIC LIGATURE SHEEN WITH HAH MEDIAL FORM;Lo;0;AL;<medial> 0634 062D;;;;N;;;;; -FD39;ARABIC LIGATURE SHEEN WITH KHAH MEDIAL FORM;Lo;0;AL;<medial> 0634 062E;;;;N;;;;; -FD3A;ARABIC LIGATURE TAH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0637 0645;;;;N;;;;; -FD3B;ARABIC LIGATURE ZAH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0638 0645;;;;N;;;;; -FD3C;ARABIC LIGATURE ALEF WITH FATHATAN FINAL FORM;Lo;0;AL;<final> 0627 064B;;;;N;;;;; -FD3D;ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM;Lo;0;AL;<isolated> 0627 064B;;;;N;;;;; -FD3E;ORNATE LEFT PARENTHESIS;Pe;0;ON;;;;;N;;;;; -FD3F;ORNATE RIGHT PARENTHESIS;Ps;0;ON;;;;;N;;;;; -FD40;ARABIC LIGATURE RAHIMAHU ALLAAH;So;0;ON;;;;;N;;;;; -FD41;ARABIC LIGATURE RADI ALLAAHU ANH;So;0;ON;;;;;N;;;;; -FD42;ARABIC LIGATURE RADI ALLAAHU ANHAA;So;0;ON;;;;;N;;;;; -FD43;ARABIC LIGATURE RADI ALLAAHU ANHUM;So;0;ON;;;;;N;;;;; -FD44;ARABIC LIGATURE RADI ALLAAHU ANHUMAA;So;0;ON;;;;;N;;;;; -FD45;ARABIC LIGATURE RADI ALLAAHU ANHUNNA;So;0;ON;;;;;N;;;;; -FD46;ARABIC LIGATURE SALLALLAAHU ALAYHI WA-AALIH;So;0;ON;;;;;N;;;;; -FD47;ARABIC LIGATURE ALAYHI AS-SALAAM;So;0;ON;;;;;N;;;;; -FD48;ARABIC LIGATURE ALAYHIM AS-SALAAM;So;0;ON;;;;;N;;;;; -FD49;ARABIC LIGATURE ALAYHIMAA AS-SALAAM;So;0;ON;;;;;N;;;;; -FD4A;ARABIC LIGATURE ALAYHI AS-SALAATU WAS-SALAAM;So;0;ON;;;;;N;;;;; -FD4B;ARABIC LIGATURE QUDDISA SIRRAH;So;0;ON;;;;;N;;;;; -FD4C;ARABIC LIGATURE SALLALLAHU ALAYHI WAAALIHEE WA-SALLAM;So;0;ON;;;;;N;;;;; -FD4D;ARABIC LIGATURE ALAYHAA AS-SALAAM;So;0;ON;;;;;N;;;;; -FD4E;ARABIC LIGATURE TABAARAKA WA-TAAALAA;So;0;ON;;;;;N;;;;; -FD4F;ARABIC LIGATURE RAHIMAHUM ALLAAH;So;0;ON;;;;;N;;;;; -FD50;ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062C 0645;;;;N;;;;; -FD51;ARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM;Lo;0;AL;<final> 062A 062D 062C;;;;N;;;;; -FD52;ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062D 062C;;;;N;;;;; -FD53;ARABIC LIGATURE TEH WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062D 0645;;;;N;;;;; -FD54;ARABIC LIGATURE TEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062E 0645;;;;N;;;;; -FD55;ARABIC LIGATURE TEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062C;;;;N;;;;; -FD56;ARABIC LIGATURE TEH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062D;;;;N;;;;; -FD57;ARABIC LIGATURE TEH WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062E;;;;N;;;;; -FD58;ARABIC LIGATURE JEEM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 062C 0645 062D;;;;N;;;;; -FD59;ARABIC LIGATURE JEEM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062C 0645 062D;;;;N;;;;; -FD5A;ARABIC LIGATURE HAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 0645 064A;;;;N;;;;; -FD5B;ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062D 0645 0649;;;;N;;;;; -FD5C;ARABIC LIGATURE SEEN WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 062D 062C;;;;N;;;;; -FD5D;ARABIC LIGATURE SEEN WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 062C 062D;;;;N;;;;; -FD5E;ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 062C 0649;;;;N;;;;; -FD5F;ARABIC LIGATURE SEEN WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0633 0645 062D;;;;N;;;;; -FD60;ARABIC LIGATURE SEEN WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 0645 062D;;;;N;;;;; -FD61;ARABIC LIGATURE SEEN WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645 062C;;;;N;;;;; -FD62;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0633 0645 0645;;;;N;;;;; -FD63;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645 0645;;;;N;;;;; -FD64;ARABIC LIGATURE SAD WITH HAH WITH HAH FINAL FORM;Lo;0;AL;<final> 0635 062D 062D;;;;N;;;;; -FD65;ARABIC LIGATURE SAD WITH HAH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0635 062D 062D;;;;N;;;;; -FD66;ARABIC LIGATURE SAD WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0635 0645 0645;;;;N;;;;; -FD67;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 062D 0645;;;;N;;;;; -FD68;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 062D 0645;;;;N;;;;; -FD69;ARABIC LIGATURE SHEEN WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 062C 064A;;;;N;;;;; -FD6A;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH FINAL FORM;Lo;0;AL;<final> 0634 0645 062E;;;;N;;;;; -FD6B;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0634 0645 062E;;;;N;;;;; -FD6C;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 0645 0645;;;;N;;;;; -FD6D;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 0645 0645;;;;N;;;;; -FD6E;ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0636 062D 0649;;;;N;;;;; -FD6F;ARABIC LIGATURE DAD WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0636 062E 0645;;;;N;;;;; -FD70;ARABIC LIGATURE DAD WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0636 062E 0645;;;;N;;;;; -FD71;ARABIC LIGATURE TAH WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0637 0645 062D;;;;N;;;;; -FD72;ARABIC LIGATURE TAH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0637 0645 062D;;;;N;;;;; -FD73;ARABIC LIGATURE TAH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0637 0645 0645;;;;N;;;;; -FD74;ARABIC LIGATURE TAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0637 0645 064A;;;;N;;;;; -FD75;ARABIC LIGATURE AIN WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0639 062C 0645;;;;N;;;;; -FD76;ARABIC LIGATURE AIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0639 0645 0645;;;;N;;;;; -FD77;ARABIC LIGATURE AIN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 0645 0645;;;;N;;;;; -FD78;ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0639 0645 0649;;;;N;;;;; -FD79;ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 063A 0645 0645;;;;N;;;;; -FD7A;ARABIC LIGATURE GHAIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 063A 0645 064A;;;;N;;;;; -FD7B;ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 063A 0645 0649;;;;N;;;;; -FD7C;ARABIC LIGATURE FEH WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0641 062E 0645;;;;N;;;;; -FD7D;ARABIC LIGATURE FEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0641 062E 0645;;;;N;;;;; -FD7E;ARABIC LIGATURE QAF WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0642 0645 062D;;;;N;;;;; -FD7F;ARABIC LIGATURE QAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0642 0645 0645;;;;N;;;;; -FD80;ARABIC LIGATURE LAM WITH HAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062D 0645;;;;N;;;;; -FD81;ARABIC LIGATURE LAM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 062D 064A;;;;N;;;;; -FD82;ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0644 062D 0649;;;;N;;;;; -FD83;ARABIC LIGATURE LAM WITH JEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C 062C;;;;N;;;;; -FD84;ARABIC LIGATURE LAM WITH JEEM WITH JEEM FINAL FORM;Lo;0;AL;<final> 0644 062C 062C;;;;N;;;;; -FD85;ARABIC LIGATURE LAM WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062E 0645;;;;N;;;;; -FD86;ARABIC LIGATURE LAM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062E 0645;;;;N;;;;; -FD87;ARABIC LIGATURE LAM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0644 0645 062D;;;;N;;;;; -FD88;ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0644 0645 062D;;;;N;;;;; -FD89;ARABIC LIGATURE MEEM WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062D 062C;;;;N;;;;; -FD8A;ARABIC LIGATURE MEEM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062D 0645;;;;N;;;;; -FD8B;ARABIC LIGATURE MEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062D 064A;;;;N;;;;; -FD8C;ARABIC LIGATURE MEEM WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0645 062C 062D;;;;N;;;;; -FD8D;ARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062C 0645;;;;N;;;;; -FD8E;ARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062E 062C;;;;N;;;;; -FD8F;ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062E 0645;;;;N;;;;; -FD92;ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0645 062C 062E;;;;N;;;;; -FD93;ARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645 062C;;;;N;;;;; -FD94;ARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645 0645;;;;N;;;;; -FD95;ARABIC LIGATURE NOON WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062D 0645;;;;N;;;;; -FD96;ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 062D 0649;;;;N;;;;; -FD97;ARABIC LIGATURE NOON WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0646 062C 0645;;;;N;;;;; -FD98;ARABIC LIGATURE NOON WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062C 0645;;;;N;;;;; -FD99;ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 062C 0649;;;;N;;;;; -FD9A;ARABIC LIGATURE NOON WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 0645 064A;;;;N;;;;; -FD9B;ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 0645 0649;;;;N;;;;; -FD9C;ARABIC LIGATURE YEH WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 064A 0645 0645;;;;N;;;;; -FD9D;ARABIC LIGATURE YEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 064A 0645 0645;;;;N;;;;; -FD9E;ARABIC LIGATURE BEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 062E 064A;;;;N;;;;; -FD9F;ARABIC LIGATURE TEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 062C 064A;;;;N;;;;; -FDA0;ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 062C 0649;;;;N;;;;; -FDA1;ARABIC LIGATURE TEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 062E 064A;;;;N;;;;; -FDA2;ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 062E 0649;;;;N;;;;; -FDA3;ARABIC LIGATURE TEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 0645 064A;;;;N;;;;; -FDA4;ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 0645 0649;;;;N;;;;; -FDA5;ARABIC LIGATURE JEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 0645 064A;;;;N;;;;; -FDA6;ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 062D 0649;;;;N;;;;; -FDA7;ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 0645 0649;;;;N;;;;; -FDA8;ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 062E 0649;;;;N;;;;; -FDA9;ARABIC LIGATURE SAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0635 062D 064A;;;;N;;;;; -FDAA;ARABIC LIGATURE SHEEN WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 062D 064A;;;;N;;;;; -FDAB;ARABIC LIGATURE DAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0636 062D 064A;;;;N;;;;; -FDAC;ARABIC LIGATURE LAM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 062C 064A;;;;N;;;;; -FDAD;ARABIC LIGATURE LAM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 0645 064A;;;;N;;;;; -FDAE;ARABIC LIGATURE YEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 062D 064A;;;;N;;;;; -FDAF;ARABIC LIGATURE YEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 062C 064A;;;;N;;;;; -FDB0;ARABIC LIGATURE YEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 0645 064A;;;;N;;;;; -FDB1;ARABIC LIGATURE MEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 0645 064A;;;;N;;;;; -FDB2;ARABIC LIGATURE QAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0642 0645 064A;;;;N;;;;; -FDB3;ARABIC LIGATURE NOON WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 062D 064A;;;;N;;;;; -FDB4;ARABIC LIGATURE QAF WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0642 0645 062D;;;;N;;;;; -FDB5;ARABIC LIGATURE LAM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062D 0645;;;;N;;;;; -FDB6;ARABIC LIGATURE AIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0639 0645 064A;;;;N;;;;; -FDB7;ARABIC LIGATURE KAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0643 0645 064A;;;;N;;;;; -FDB8;ARABIC LIGATURE NOON WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0646 062C 062D;;;;N;;;;; -FDB9;ARABIC LIGATURE MEEM WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062E 064A;;;;N;;;;; -FDBA;ARABIC LIGATURE LAM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C 0645;;;;N;;;;; -FDBB;ARABIC LIGATURE KAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0643 0645 0645;;;;N;;;;; -FDBC;ARABIC LIGATURE LAM WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062C 0645;;;;N;;;;; -FDBD;ARABIC LIGATURE NOON WITH JEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0646 062C 062D;;;;N;;;;; -FDBE;ARABIC LIGATURE JEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 062D 064A;;;;N;;;;; -FDBF;ARABIC LIGATURE HAH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 062C 064A;;;;N;;;;; -FDC0;ARABIC LIGATURE MEEM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062C 064A;;;;N;;;;; -FDC1;ARABIC LIGATURE FEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0641 0645 064A;;;;N;;;;; -FDC2;ARABIC LIGATURE BEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 062D 064A;;;;N;;;;; -FDC3;ARABIC LIGATURE KAF WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0643 0645 0645;;;;N;;;;; -FDC4;ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 062C 0645;;;;N;;;;; -FDC5;ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0635 0645 0645;;;;N;;;;; -FDC6;ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0633 062E 064A;;;;N;;;;; -FDC7;ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 062C 064A;;;;N;;;;; -FDCF;ARABIC LIGATURE SALAAMUHU ALAYNAA;So;0;ON;;;;;N;;;;; -FDF0;ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 06D2;;;;N;;;;; -FDF1;ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL;<isolated> 0642 0644 06D2;;;;N;;;;; -FDF2;ARABIC LIGATURE ALLAH ISOLATED FORM;Lo;0;AL;<isolated> 0627 0644 0644 0647;;;;N;;;;; -FDF3;ARABIC LIGATURE AKBAR ISOLATED FORM;Lo;0;AL;<isolated> 0627 0643 0628 0631;;;;N;;;;; -FDF4;ARABIC LIGATURE MOHAMMAD ISOLATED FORM;Lo;0;AL;<isolated> 0645 062D 0645 062F;;;;N;;;;; -FDF5;ARABIC LIGATURE SALAM ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 0639 0645;;;;N;;;;; -FDF6;ARABIC LIGATURE RASOUL ISOLATED FORM;Lo;0;AL;<isolated> 0631 0633 0648 0644;;;;N;;;;; -FDF7;ARABIC LIGATURE ALAYHE ISOLATED FORM;Lo;0;AL;<isolated> 0639 0644 064A 0647;;;;N;;;;; -FDF8;ARABIC LIGATURE WASALLAM ISOLATED FORM;Lo;0;AL;<isolated> 0648 0633 0644 0645;;;;N;;;;; -FDF9;ARABIC LIGATURE SALLA ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 0649;;;;N;;;;; -FDFA;ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM;Lo;0;AL;<isolated> 0635 0644 0649 0020 0627 0644 0644 0647 0020 0639 0644 064A 0647 0020 0648 0633 0644 0645;;;;N;ARABIC LETTER SALLALLAHOU ALAYHE WASALLAM;;;; -FDFB;ARABIC LIGATURE JALLAJALALOUHOU;Lo;0;AL;<isolated> 062C 0644 0020 062C 0644 0627 0644 0647;;;;N;ARABIC LETTER JALLAJALALOUHOU;;;; -FDFC;RIAL SIGN;Sc;0;AL;<isolated> 0631 06CC 0627 0644;;;;N;;;;; -FDFD;ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM;So;0;ON;;;;;N;;;;; -FDFE;ARABIC LIGATURE SUBHAANAHU WA TAAALAA;So;0;ON;;;;;N;;;;; -FDFF;ARABIC LIGATURE AZZA WA JALL;So;0;ON;;;;;N;;;;; -FE00;VARIATION SELECTOR-1;Mn;0;NSM;;;;;N;;;;; -FE01;VARIATION SELECTOR-2;Mn;0;NSM;;;;;N;;;;; -FE02;VARIATION SELECTOR-3;Mn;0;NSM;;;;;N;;;;; -FE03;VARIATION SELECTOR-4;Mn;0;NSM;;;;;N;;;;; -FE04;VARIATION SELECTOR-5;Mn;0;NSM;;;;;N;;;;; -FE05;VARIATION SELECTOR-6;Mn;0;NSM;;;;;N;;;;; -FE06;VARIATION SELECTOR-7;Mn;0;NSM;;;;;N;;;;; -FE07;VARIATION SELECTOR-8;Mn;0;NSM;;;;;N;;;;; -FE08;VARIATION SELECTOR-9;Mn;0;NSM;;;;;N;;;;; -FE09;VARIATION SELECTOR-10;Mn;0;NSM;;;;;N;;;;; -FE0A;VARIATION SELECTOR-11;Mn;0;NSM;;;;;N;;;;; -FE0B;VARIATION SELECTOR-12;Mn;0;NSM;;;;;N;;;;; -FE0C;VARIATION SELECTOR-13;Mn;0;NSM;;;;;N;;;;; -FE0D;VARIATION SELECTOR-14;Mn;0;NSM;;;;;N;;;;; -FE0E;VARIATION SELECTOR-15;Mn;0;NSM;;;;;N;;;;; -FE0F;VARIATION SELECTOR-16;Mn;0;NSM;;;;;N;;;;; -FE10;PRESENTATION FORM FOR VERTICAL COMMA;Po;0;ON;<vertical> 002C;;;;N;;;;; -FE11;PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC COMMA;Po;0;ON;<vertical> 3001;;;;N;;;;; -FE12;PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP;Po;0;ON;<vertical> 3002;;;;N;;;;; -FE13;PRESENTATION FORM FOR VERTICAL COLON;Po;0;ON;<vertical> 003A;;;;N;;;;; -FE14;PRESENTATION FORM FOR VERTICAL SEMICOLON;Po;0;ON;<vertical> 003B;;;;N;;;;; -FE15;PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK;Po;0;ON;<vertical> 0021;;;;N;;;;; -FE16;PRESENTATION FORM FOR VERTICAL QUESTION MARK;Po;0;ON;<vertical> 003F;;;;N;;;;; -FE17;PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET;Ps;0;ON;<vertical> 3016;;;;N;;;;; -FE18;PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET;Pe;0;ON;<vertical> 3017;;;;N;;;;; -FE19;PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS;Po;0;ON;<vertical> 2026;;;;N;;;;; -FE20;COMBINING LIGATURE LEFT HALF;Mn;230;NSM;;;;;N;;;;; -FE21;COMBINING LIGATURE RIGHT HALF;Mn;230;NSM;;;;;N;;;;; -FE22;COMBINING DOUBLE TILDE LEFT HALF;Mn;230;NSM;;;;;N;;;;; -FE23;COMBINING DOUBLE TILDE RIGHT HALF;Mn;230;NSM;;;;;N;;;;; -FE24;COMBINING MACRON LEFT HALF;Mn;230;NSM;;;;;N;;;;; -FE25;COMBINING MACRON RIGHT HALF;Mn;230;NSM;;;;;N;;;;; -FE26;COMBINING CONJOINING MACRON;Mn;230;NSM;;;;;N;;;;; -FE27;COMBINING LIGATURE LEFT HALF BELOW;Mn;220;NSM;;;;;N;;;;; -FE28;COMBINING LIGATURE RIGHT HALF BELOW;Mn;220;NSM;;;;;N;;;;; -FE29;COMBINING TILDE LEFT HALF BELOW;Mn;220;NSM;;;;;N;;;;; -FE2A;COMBINING TILDE RIGHT HALF BELOW;Mn;220;NSM;;;;;N;;;;; -FE2B;COMBINING MACRON LEFT HALF BELOW;Mn;220;NSM;;;;;N;;;;; -FE2C;COMBINING MACRON RIGHT HALF BELOW;Mn;220;NSM;;;;;N;;;;; -FE2D;COMBINING CONJOINING MACRON BELOW;Mn;220;NSM;;;;;N;;;;; -FE2E;COMBINING CYRILLIC TITLO LEFT HALF;Mn;230;NSM;;;;;N;;;;; -FE2F;COMBINING CYRILLIC TITLO RIGHT HALF;Mn;230;NSM;;;;;N;;;;; -FE30;PRESENTATION FORM FOR VERTICAL TWO DOT LEADER;Po;0;ON;<vertical> 2025;;;;N;GLYPH FOR VERTICAL TWO DOT LEADER;;;; -FE31;PRESENTATION FORM FOR VERTICAL EM DASH;Pd;0;ON;<vertical> 2014;;;;N;GLYPH FOR VERTICAL EM DASH;;;; -FE32;PRESENTATION FORM FOR VERTICAL EN DASH;Pd;0;ON;<vertical> 2013;;;;N;GLYPH FOR VERTICAL EN DASH;;;; -FE33;PRESENTATION FORM FOR VERTICAL LOW LINE;Pc;0;ON;<vertical> 005F;;;;N;GLYPH FOR VERTICAL SPACING UNDERSCORE;;;; -FE34;PRESENTATION FORM FOR VERTICAL WAVY LOW LINE;Pc;0;ON;<vertical> 005F;;;;N;GLYPH FOR VERTICAL SPACING WAVY UNDERSCORE;;;; -FE35;PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS;Ps;0;ON;<vertical> 0028;;;;N;GLYPH FOR VERTICAL OPENING PARENTHESIS;;;; -FE36;PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS;Pe;0;ON;<vertical> 0029;;;;N;GLYPH FOR VERTICAL CLOSING PARENTHESIS;;;; -FE37;PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET;Ps;0;ON;<vertical> 007B;;;;N;GLYPH FOR VERTICAL OPENING CURLY BRACKET;;;; -FE38;PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET;Pe;0;ON;<vertical> 007D;;;;N;GLYPH FOR VERTICAL CLOSING CURLY BRACKET;;;; -FE39;PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET;Ps;0;ON;<vertical> 3014;;;;N;GLYPH FOR VERTICAL OPENING TORTOISE SHELL BRACKET;;;; -FE3A;PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;<vertical> 3015;;;;N;GLYPH FOR VERTICAL CLOSING TORTOISE SHELL BRACKET;;;; -FE3B;PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET;Ps;0;ON;<vertical> 3010;;;;N;GLYPH FOR VERTICAL OPENING BLACK LENTICULAR BRACKET;;;; -FE3C;PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON;<vertical> 3011;;;;N;GLYPH FOR VERTICAL CLOSING BLACK LENTICULAR BRACKET;;;; -FE3D;PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;<vertical> 300A;;;;N;GLYPH FOR VERTICAL OPENING DOUBLE ANGLE BRACKET;;;; -FE3E;PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;<vertical> 300B;;;;N;GLYPH FOR VERTICAL CLOSING DOUBLE ANGLE BRACKET;;;; -FE3F;PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET;Ps;0;ON;<vertical> 3008;;;;N;GLYPH FOR VERTICAL OPENING ANGLE BRACKET;;;; -FE40;PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET;Pe;0;ON;<vertical> 3009;;;;N;GLYPH FOR VERTICAL CLOSING ANGLE BRACKET;;;; -FE41;PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET;Ps;0;ON;<vertical> 300C;;;;N;GLYPH FOR VERTICAL OPENING CORNER BRACKET;;;; -FE42;PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET;Pe;0;ON;<vertical> 300D;;;;N;GLYPH FOR VERTICAL CLOSING CORNER BRACKET;;;; -FE43;PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET;Ps;0;ON;<vertical> 300E;;;;N;GLYPH FOR VERTICAL OPENING WHITE CORNER BRACKET;;;; -FE44;PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET;Pe;0;ON;<vertical> 300F;;;;N;GLYPH FOR VERTICAL CLOSING WHITE CORNER BRACKET;;;; -FE45;SESAME DOT;Po;0;ON;;;;;N;;;;; -FE46;WHITE SESAME DOT;Po;0;ON;;;;;N;;;;; -FE47;PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET;Ps;0;ON;<vertical> 005B;;;;N;;;;; -FE48;PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET;Pe;0;ON;<vertical> 005D;;;;N;;;;; -FE49;DASHED OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING DASHED OVERSCORE;;;; -FE4A;CENTRELINE OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING CENTERLINE OVERSCORE;;;; -FE4B;WAVY OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING WAVY OVERSCORE;;;; -FE4C;DOUBLE WAVY OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING DOUBLE WAVY OVERSCORE;;;; -FE4D;DASHED LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING DASHED UNDERSCORE;;;; -FE4E;CENTRELINE LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING CENTERLINE UNDERSCORE;;;; -FE4F;WAVY LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING WAVY UNDERSCORE;;;; -FE50;SMALL COMMA;Po;0;CS;<small> 002C;;;;N;;;;; -FE51;SMALL IDEOGRAPHIC COMMA;Po;0;ON;<small> 3001;;;;N;;;;; -FE52;SMALL FULL STOP;Po;0;CS;<small> 002E;;;;N;SMALL PERIOD;;;; -FE54;SMALL SEMICOLON;Po;0;ON;<small> 003B;;;;N;;;;; -FE55;SMALL COLON;Po;0;CS;<small> 003A;;;;N;;;;; -FE56;SMALL QUESTION MARK;Po;0;ON;<small> 003F;;;;N;;;;; -FE57;SMALL EXCLAMATION MARK;Po;0;ON;<small> 0021;;;;N;;;;; -FE58;SMALL EM DASH;Pd;0;ON;<small> 2014;;;;N;;;;; -FE59;SMALL LEFT PARENTHESIS;Ps;0;ON;<small> 0028;;;;Y;SMALL OPENING PARENTHESIS;;;; -FE5A;SMALL RIGHT PARENTHESIS;Pe;0;ON;<small> 0029;;;;Y;SMALL CLOSING PARENTHESIS;;;; -FE5B;SMALL LEFT CURLY BRACKET;Ps;0;ON;<small> 007B;;;;Y;SMALL OPENING CURLY BRACKET;;;; -FE5C;SMALL RIGHT CURLY BRACKET;Pe;0;ON;<small> 007D;;;;Y;SMALL CLOSING CURLY BRACKET;;;; -FE5D;SMALL LEFT TORTOISE SHELL BRACKET;Ps;0;ON;<small> 3014;;;;Y;SMALL OPENING TORTOISE SHELL BRACKET;;;; -FE5E;SMALL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;<small> 3015;;;;Y;SMALL CLOSING TORTOISE SHELL BRACKET;;;; -FE5F;SMALL NUMBER SIGN;Po;0;ET;<small> 0023;;;;N;;;;; -FE60;SMALL AMPERSAND;Po;0;ON;<small> 0026;;;;N;;;;; -FE61;SMALL ASTERISK;Po;0;ON;<small> 002A;;;;N;;;;; -FE62;SMALL PLUS SIGN;Sm;0;ES;<small> 002B;;;;N;;;;; -FE63;SMALL HYPHEN-MINUS;Pd;0;ES;<small> 002D;;;;N;;;;; -FE64;SMALL LESS-THAN SIGN;Sm;0;ON;<small> 003C;;;;Y;;;;; -FE65;SMALL GREATER-THAN SIGN;Sm;0;ON;<small> 003E;;;;Y;;;;; -FE66;SMALL EQUALS SIGN;Sm;0;ON;<small> 003D;;;;N;;;;; -FE68;SMALL REVERSE SOLIDUS;Po;0;ON;<small> 005C;;;;N;SMALL BACKSLASH;;;; -FE69;SMALL DOLLAR SIGN;Sc;0;ET;<small> 0024;;;;N;;;;; -FE6A;SMALL PERCENT SIGN;Po;0;ET;<small> 0025;;;;N;;;;; -FE6B;SMALL COMMERCIAL AT;Po;0;ON;<small> 0040;;;;N;;;;; -FE70;ARABIC FATHATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064B;;;;N;ARABIC SPACING FATHATAN;;;; -FE71;ARABIC TATWEEL WITH FATHATAN ABOVE;Lo;0;AL;<medial> 0640 064B;;;;N;ARABIC FATHATAN ON TATWEEL;;;; -FE72;ARABIC DAMMATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064C;;;;N;ARABIC SPACING DAMMATAN;;;; -FE73;ARABIC TAIL FRAGMENT;Lo;0;AL;;;;;N;;;;; -FE74;ARABIC KASRATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064D;;;;N;ARABIC SPACING KASRATAN;;;; -FE76;ARABIC FATHA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064E;;;;N;ARABIC SPACING FATHAH;;;; -FE77;ARABIC FATHA MEDIAL FORM;Lo;0;AL;<medial> 0640 064E;;;;N;ARABIC FATHAH ON TATWEEL;;;; -FE78;ARABIC DAMMA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064F;;;;N;ARABIC SPACING DAMMAH;;;; -FE79;ARABIC DAMMA MEDIAL FORM;Lo;0;AL;<medial> 0640 064F;;;;N;ARABIC DAMMAH ON TATWEEL;;;; -FE7A;ARABIC KASRA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0650;;;;N;ARABIC SPACING KASRAH;;;; -FE7B;ARABIC KASRA MEDIAL FORM;Lo;0;AL;<medial> 0640 0650;;;;N;ARABIC KASRAH ON TATWEEL;;;; -FE7C;ARABIC SHADDA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0651;;;;N;ARABIC SPACING SHADDAH;;;; -FE7D;ARABIC SHADDA MEDIAL FORM;Lo;0;AL;<medial> 0640 0651;;;;N;ARABIC SHADDAH ON TATWEEL;;;; -FE7E;ARABIC SUKUN ISOLATED FORM;Lo;0;AL;<isolated> 0020 0652;;;;N;ARABIC SPACING SUKUN;;;; -FE7F;ARABIC SUKUN MEDIAL FORM;Lo;0;AL;<medial> 0640 0652;;;;N;ARABIC SUKUN ON TATWEEL;;;; -FE80;ARABIC LETTER HAMZA ISOLATED FORM;Lo;0;AL;<isolated> 0621;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH;;;; -FE81;ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON ALEF;;;; -FE82;ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL;<final> 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON ALEF;;;; -FE83;ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON ALEF;;;; -FE84;ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON ALEF;;;; -FE85;ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0624;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON WAW;;;; -FE86;ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0624;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON WAW;;;; -FE87;ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL;<isolated> 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER ALEF;;;; -FE88;ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL;<final> 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER ALEF;;;; -FE89;ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0626;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON YA;;;; -FE8A;ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0626;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON YA;;;; -FE8B;ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM;Lo;0;AL;<initial> 0626;;;;N;GLYPH FOR INITIAL ARABIC HAMZAH ON YA;;;; -FE8C;ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM;Lo;0;AL;<medial> 0626;;;;N;GLYPH FOR MEDIAL ARABIC HAMZAH ON YA;;;; -FE8D;ARABIC LETTER ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0627;;;;N;GLYPH FOR ISOLATE ARABIC ALEF;;;; -FE8E;ARABIC LETTER ALEF FINAL FORM;Lo;0;AL;<final> 0627;;;;N;GLYPH FOR FINAL ARABIC ALEF;;;; -FE8F;ARABIC LETTER BEH ISOLATED FORM;Lo;0;AL;<isolated> 0628;;;;N;GLYPH FOR ISOLATE ARABIC BAA;;;; -FE90;ARABIC LETTER BEH FINAL FORM;Lo;0;AL;<final> 0628;;;;N;GLYPH FOR FINAL ARABIC BAA;;;; -FE91;ARABIC LETTER BEH INITIAL FORM;Lo;0;AL;<initial> 0628;;;;N;GLYPH FOR INITIAL ARABIC BAA;;;; -FE92;ARABIC LETTER BEH MEDIAL FORM;Lo;0;AL;<medial> 0628;;;;N;GLYPH FOR MEDIAL ARABIC BAA;;;; -FE93;ARABIC LETTER TEH MARBUTA ISOLATED FORM;Lo;0;AL;<isolated> 0629;;;;N;GLYPH FOR ISOLATE ARABIC TAA MARBUTAH;;;; -FE94;ARABIC LETTER TEH MARBUTA FINAL FORM;Lo;0;AL;<final> 0629;;;;N;GLYPH FOR FINAL ARABIC TAA MARBUTAH;;;; -FE95;ARABIC LETTER TEH ISOLATED FORM;Lo;0;AL;<isolated> 062A;;;;N;GLYPH FOR ISOLATE ARABIC TAA;;;; -FE96;ARABIC LETTER TEH FINAL FORM;Lo;0;AL;<final> 062A;;;;N;GLYPH FOR FINAL ARABIC TAA;;;; -FE97;ARABIC LETTER TEH INITIAL FORM;Lo;0;AL;<initial> 062A;;;;N;GLYPH FOR INITIAL ARABIC TAA;;;; -FE98;ARABIC LETTER TEH MEDIAL FORM;Lo;0;AL;<medial> 062A;;;;N;GLYPH FOR MEDIAL ARABIC TAA;;;; -FE99;ARABIC LETTER THEH ISOLATED FORM;Lo;0;AL;<isolated> 062B;;;;N;GLYPH FOR ISOLATE ARABIC THAA;;;; -FE9A;ARABIC LETTER THEH FINAL FORM;Lo;0;AL;<final> 062B;;;;N;GLYPH FOR FINAL ARABIC THAA;;;; -FE9B;ARABIC LETTER THEH INITIAL FORM;Lo;0;AL;<initial> 062B;;;;N;GLYPH FOR INITIAL ARABIC THAA;;;; -FE9C;ARABIC LETTER THEH MEDIAL FORM;Lo;0;AL;<medial> 062B;;;;N;GLYPH FOR MEDIAL ARABIC THAA;;;; -FE9D;ARABIC LETTER JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062C;;;;N;GLYPH FOR ISOLATE ARABIC JEEM;;;; -FE9E;ARABIC LETTER JEEM FINAL FORM;Lo;0;AL;<final> 062C;;;;N;GLYPH FOR FINAL ARABIC JEEM;;;; -FE9F;ARABIC LETTER JEEM INITIAL FORM;Lo;0;AL;<initial> 062C;;;;N;GLYPH FOR INITIAL ARABIC JEEM;;;; -FEA0;ARABIC LETTER JEEM MEDIAL FORM;Lo;0;AL;<medial> 062C;;;;N;GLYPH FOR MEDIAL ARABIC JEEM;;;; -FEA1;ARABIC LETTER HAH ISOLATED FORM;Lo;0;AL;<isolated> 062D;;;;N;GLYPH FOR ISOLATE ARABIC HAA;;;; -FEA2;ARABIC LETTER HAH FINAL FORM;Lo;0;AL;<final> 062D;;;;N;GLYPH FOR FINAL ARABIC HAA;;;; -FEA3;ARABIC LETTER HAH INITIAL FORM;Lo;0;AL;<initial> 062D;;;;N;GLYPH FOR INITIAL ARABIC HAA;;;; -FEA4;ARABIC LETTER HAH MEDIAL FORM;Lo;0;AL;<medial> 062D;;;;N;GLYPH FOR MEDIAL ARABIC HAA;;;; -FEA5;ARABIC LETTER KHAH ISOLATED FORM;Lo;0;AL;<isolated> 062E;;;;N;GLYPH FOR ISOLATE ARABIC KHAA;;;; -FEA6;ARABIC LETTER KHAH FINAL FORM;Lo;0;AL;<final> 062E;;;;N;GLYPH FOR FINAL ARABIC KHAA;;;; -FEA7;ARABIC LETTER KHAH INITIAL FORM;Lo;0;AL;<initial> 062E;;;;N;GLYPH FOR INITIAL ARABIC KHAA;;;; -FEA8;ARABIC LETTER KHAH MEDIAL FORM;Lo;0;AL;<medial> 062E;;;;N;GLYPH FOR MEDIAL ARABIC KHAA;;;; -FEA9;ARABIC LETTER DAL ISOLATED FORM;Lo;0;AL;<isolated> 062F;;;;N;GLYPH FOR ISOLATE ARABIC DAL;;;; -FEAA;ARABIC LETTER DAL FINAL FORM;Lo;0;AL;<final> 062F;;;;N;GLYPH FOR FINAL ARABIC DAL;;;; -FEAB;ARABIC LETTER THAL ISOLATED FORM;Lo;0;AL;<isolated> 0630;;;;N;GLYPH FOR ISOLATE ARABIC THAL;;;; -FEAC;ARABIC LETTER THAL FINAL FORM;Lo;0;AL;<final> 0630;;;;N;GLYPH FOR FINAL ARABIC THAL;;;; -FEAD;ARABIC LETTER REH ISOLATED FORM;Lo;0;AL;<isolated> 0631;;;;N;GLYPH FOR ISOLATE ARABIC RA;;;; -FEAE;ARABIC LETTER REH FINAL FORM;Lo;0;AL;<final> 0631;;;;N;GLYPH FOR FINAL ARABIC RA;;;; -FEAF;ARABIC LETTER ZAIN ISOLATED FORM;Lo;0;AL;<isolated> 0632;;;;N;GLYPH FOR ISOLATE ARABIC ZAIN;;;; -FEB0;ARABIC LETTER ZAIN FINAL FORM;Lo;0;AL;<final> 0632;;;;N;GLYPH FOR FINAL ARABIC ZAIN;;;; -FEB1;ARABIC LETTER SEEN ISOLATED FORM;Lo;0;AL;<isolated> 0633;;;;N;GLYPH FOR ISOLATE ARABIC SEEN;;;; -FEB2;ARABIC LETTER SEEN FINAL FORM;Lo;0;AL;<final> 0633;;;;N;GLYPH FOR FINAL ARABIC SEEN;;;; -FEB3;ARABIC LETTER SEEN INITIAL FORM;Lo;0;AL;<initial> 0633;;;;N;GLYPH FOR INITIAL ARABIC SEEN;;;; -FEB4;ARABIC LETTER SEEN MEDIAL FORM;Lo;0;AL;<medial> 0633;;;;N;GLYPH FOR MEDIAL ARABIC SEEN;;;; -FEB5;ARABIC LETTER SHEEN ISOLATED FORM;Lo;0;AL;<isolated> 0634;;;;N;GLYPH FOR ISOLATE ARABIC SHEEN;;;; -FEB6;ARABIC LETTER SHEEN FINAL FORM;Lo;0;AL;<final> 0634;;;;N;GLYPH FOR FINAL ARABIC SHEEN;;;; -FEB7;ARABIC LETTER SHEEN INITIAL FORM;Lo;0;AL;<initial> 0634;;;;N;GLYPH FOR INITIAL ARABIC SHEEN;;;; -FEB8;ARABIC LETTER SHEEN MEDIAL FORM;Lo;0;AL;<medial> 0634;;;;N;GLYPH FOR MEDIAL ARABIC SHEEN;;;; -FEB9;ARABIC LETTER SAD ISOLATED FORM;Lo;0;AL;<isolated> 0635;;;;N;GLYPH FOR ISOLATE ARABIC SAD;;;; -FEBA;ARABIC LETTER SAD FINAL FORM;Lo;0;AL;<final> 0635;;;;N;GLYPH FOR FINAL ARABIC SAD;;;; -FEBB;ARABIC LETTER SAD INITIAL FORM;Lo;0;AL;<initial> 0635;;;;N;GLYPH FOR INITIAL ARABIC SAD;;;; -FEBC;ARABIC LETTER SAD MEDIAL FORM;Lo;0;AL;<medial> 0635;;;;N;GLYPH FOR MEDIAL ARABIC SAD;;;; -FEBD;ARABIC LETTER DAD ISOLATED FORM;Lo;0;AL;<isolated> 0636;;;;N;GLYPH FOR ISOLATE ARABIC DAD;;;; -FEBE;ARABIC LETTER DAD FINAL FORM;Lo;0;AL;<final> 0636;;;;N;GLYPH FOR FINAL ARABIC DAD;;;; -FEBF;ARABIC LETTER DAD INITIAL FORM;Lo;0;AL;<initial> 0636;;;;N;GLYPH FOR INITIAL ARABIC DAD;;;; -FEC0;ARABIC LETTER DAD MEDIAL FORM;Lo;0;AL;<medial> 0636;;;;N;GLYPH FOR MEDIAL ARABIC DAD;;;; -FEC1;ARABIC LETTER TAH ISOLATED FORM;Lo;0;AL;<isolated> 0637;;;;N;GLYPH FOR ISOLATE ARABIC TAH;;;; -FEC2;ARABIC LETTER TAH FINAL FORM;Lo;0;AL;<final> 0637;;;;N;GLYPH FOR FINAL ARABIC TAH;;;; -FEC3;ARABIC LETTER TAH INITIAL FORM;Lo;0;AL;<initial> 0637;;;;N;GLYPH FOR INITIAL ARABIC TAH;;;; -FEC4;ARABIC LETTER TAH MEDIAL FORM;Lo;0;AL;<medial> 0637;;;;N;GLYPH FOR MEDIAL ARABIC TAH;;;; -FEC5;ARABIC LETTER ZAH ISOLATED FORM;Lo;0;AL;<isolated> 0638;;;;N;GLYPH FOR ISOLATE ARABIC DHAH;;;; -FEC6;ARABIC LETTER ZAH FINAL FORM;Lo;0;AL;<final> 0638;;;;N;GLYPH FOR FINAL ARABIC DHAH;;;; -FEC7;ARABIC LETTER ZAH INITIAL FORM;Lo;0;AL;<initial> 0638;;;;N;GLYPH FOR INITIAL ARABIC DHAH;;;; -FEC8;ARABIC LETTER ZAH MEDIAL FORM;Lo;0;AL;<medial> 0638;;;;N;GLYPH FOR MEDIAL ARABIC DHAH;;;; -FEC9;ARABIC LETTER AIN ISOLATED FORM;Lo;0;AL;<isolated> 0639;;;;N;GLYPH FOR ISOLATE ARABIC AIN;;;; -FECA;ARABIC LETTER AIN FINAL FORM;Lo;0;AL;<final> 0639;;;;N;GLYPH FOR FINAL ARABIC AIN;;;; -FECB;ARABIC LETTER AIN INITIAL FORM;Lo;0;AL;<initial> 0639;;;;N;GLYPH FOR INITIAL ARABIC AIN;;;; -FECC;ARABIC LETTER AIN MEDIAL FORM;Lo;0;AL;<medial> 0639;;;;N;GLYPH FOR MEDIAL ARABIC AIN;;;; -FECD;ARABIC LETTER GHAIN ISOLATED FORM;Lo;0;AL;<isolated> 063A;;;;N;GLYPH FOR ISOLATE ARABIC GHAIN;;;; -FECE;ARABIC LETTER GHAIN FINAL FORM;Lo;0;AL;<final> 063A;;;;N;GLYPH FOR FINAL ARABIC GHAIN;;;; -FECF;ARABIC LETTER GHAIN INITIAL FORM;Lo;0;AL;<initial> 063A;;;;N;GLYPH FOR INITIAL ARABIC GHAIN;;;; -FED0;ARABIC LETTER GHAIN MEDIAL FORM;Lo;0;AL;<medial> 063A;;;;N;GLYPH FOR MEDIAL ARABIC GHAIN;;;; -FED1;ARABIC LETTER FEH ISOLATED FORM;Lo;0;AL;<isolated> 0641;;;;N;GLYPH FOR ISOLATE ARABIC FA;;;; -FED2;ARABIC LETTER FEH FINAL FORM;Lo;0;AL;<final> 0641;;;;N;GLYPH FOR FINAL ARABIC FA;;;; -FED3;ARABIC LETTER FEH INITIAL FORM;Lo;0;AL;<initial> 0641;;;;N;GLYPH FOR INITIAL ARABIC FA;;;; -FED4;ARABIC LETTER FEH MEDIAL FORM;Lo;0;AL;<medial> 0641;;;;N;GLYPH FOR MEDIAL ARABIC FA;;;; -FED5;ARABIC LETTER QAF ISOLATED FORM;Lo;0;AL;<isolated> 0642;;;;N;GLYPH FOR ISOLATE ARABIC QAF;;;; -FED6;ARABIC LETTER QAF FINAL FORM;Lo;0;AL;<final> 0642;;;;N;GLYPH FOR FINAL ARABIC QAF;;;; -FED7;ARABIC LETTER QAF INITIAL FORM;Lo;0;AL;<initial> 0642;;;;N;GLYPH FOR INITIAL ARABIC QAF;;;; -FED8;ARABIC LETTER QAF MEDIAL FORM;Lo;0;AL;<medial> 0642;;;;N;GLYPH FOR MEDIAL ARABIC QAF;;;; -FED9;ARABIC LETTER KAF ISOLATED FORM;Lo;0;AL;<isolated> 0643;;;;N;GLYPH FOR ISOLATE ARABIC CAF;;;; -FEDA;ARABIC LETTER KAF FINAL FORM;Lo;0;AL;<final> 0643;;;;N;GLYPH FOR FINAL ARABIC CAF;;;; -FEDB;ARABIC LETTER KAF INITIAL FORM;Lo;0;AL;<initial> 0643;;;;N;GLYPH FOR INITIAL ARABIC CAF;;;; -FEDC;ARABIC LETTER KAF MEDIAL FORM;Lo;0;AL;<medial> 0643;;;;N;GLYPH FOR MEDIAL ARABIC CAF;;;; -FEDD;ARABIC LETTER LAM ISOLATED FORM;Lo;0;AL;<isolated> 0644;;;;N;GLYPH FOR ISOLATE ARABIC LAM;;;; -FEDE;ARABIC LETTER LAM FINAL FORM;Lo;0;AL;<final> 0644;;;;N;GLYPH FOR FINAL ARABIC LAM;;;; -FEDF;ARABIC LETTER LAM INITIAL FORM;Lo;0;AL;<initial> 0644;;;;N;GLYPH FOR INITIAL ARABIC LAM;;;; -FEE0;ARABIC LETTER LAM MEDIAL FORM;Lo;0;AL;<medial> 0644;;;;N;GLYPH FOR MEDIAL ARABIC LAM;;;; -FEE1;ARABIC LETTER MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645;;;;N;GLYPH FOR ISOLATE ARABIC MEEM;;;; -FEE2;ARABIC LETTER MEEM FINAL FORM;Lo;0;AL;<final> 0645;;;;N;GLYPH FOR FINAL ARABIC MEEM;;;; -FEE3;ARABIC LETTER MEEM INITIAL FORM;Lo;0;AL;<initial> 0645;;;;N;GLYPH FOR INITIAL ARABIC MEEM;;;; -FEE4;ARABIC LETTER MEEM MEDIAL FORM;Lo;0;AL;<medial> 0645;;;;N;GLYPH FOR MEDIAL ARABIC MEEM;;;; -FEE5;ARABIC LETTER NOON ISOLATED FORM;Lo;0;AL;<isolated> 0646;;;;N;GLYPH FOR ISOLATE ARABIC NOON;;;; -FEE6;ARABIC LETTER NOON FINAL FORM;Lo;0;AL;<final> 0646;;;;N;GLYPH FOR FINAL ARABIC NOON;;;; -FEE7;ARABIC LETTER NOON INITIAL FORM;Lo;0;AL;<initial> 0646;;;;N;GLYPH FOR INITIAL ARABIC NOON;;;; -FEE8;ARABIC LETTER NOON MEDIAL FORM;Lo;0;AL;<medial> 0646;;;;N;GLYPH FOR MEDIAL ARABIC NOON;;;; -FEE9;ARABIC LETTER HEH ISOLATED FORM;Lo;0;AL;<isolated> 0647;;;;N;GLYPH FOR ISOLATE ARABIC HA;;;; -FEEA;ARABIC LETTER HEH FINAL FORM;Lo;0;AL;<final> 0647;;;;N;GLYPH FOR FINAL ARABIC HA;;;; -FEEB;ARABIC LETTER HEH INITIAL FORM;Lo;0;AL;<initial> 0647;;;;N;GLYPH FOR INITIAL ARABIC HA;;;; -FEEC;ARABIC LETTER HEH MEDIAL FORM;Lo;0;AL;<medial> 0647;;;;N;GLYPH FOR MEDIAL ARABIC HA;;;; -FEED;ARABIC LETTER WAW ISOLATED FORM;Lo;0;AL;<isolated> 0648;;;;N;GLYPH FOR ISOLATE ARABIC WAW;;;; -FEEE;ARABIC LETTER WAW FINAL FORM;Lo;0;AL;<final> 0648;;;;N;GLYPH FOR FINAL ARABIC WAW;;;; -FEEF;ARABIC LETTER ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0649;;;;N;GLYPH FOR ISOLATE ARABIC ALEF MAQSURAH;;;; -FEF0;ARABIC LETTER ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0649;;;;N;GLYPH FOR FINAL ARABIC ALEF MAQSURAH;;;; -FEF1;ARABIC LETTER YEH ISOLATED FORM;Lo;0;AL;<isolated> 064A;;;;N;GLYPH FOR ISOLATE ARABIC YA;;;; -FEF2;ARABIC LETTER YEH FINAL FORM;Lo;0;AL;<final> 064A;;;;N;GLYPH FOR FINAL ARABIC YA;;;; -FEF3;ARABIC LETTER YEH INITIAL FORM;Lo;0;AL;<initial> 064A;;;;N;GLYPH FOR INITIAL ARABIC YA;;;; -FEF4;ARABIC LETTER YEH MEDIAL FORM;Lo;0;AL;<medial> 064A;;;;N;GLYPH FOR MEDIAL ARABIC YA;;;; -FEF5;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0644 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON LIGATURE LAM ALEF;;;; -FEF6;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL;<final> 0644 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON LIGATURE LAM ALEF;;;; -FEF7;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0644 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON LIGATURE LAM ALEF;;;; -FEF8;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0644 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON LIGATURE LAM ALEF;;;; -FEF9;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL;<isolated> 0644 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;; -FEFA;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL;<final> 0644 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;; -FEFB;ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0644 0627;;;;N;GLYPH FOR ISOLATE ARABIC LIGATURE LAM ALEF;;;; -FEFC;ARABIC LIGATURE LAM WITH ALEF FINAL FORM;Lo;0;AL;<final> 0644 0627;;;;N;GLYPH FOR FINAL ARABIC LIGATURE LAM ALEF;;;; -FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; -FF01;FULLWIDTH EXCLAMATION MARK;Po;0;ON;<wide> 0021;;;;N;;;;; -FF02;FULLWIDTH QUOTATION MARK;Po;0;ON;<wide> 0022;;;;N;;;;; -FF03;FULLWIDTH NUMBER SIGN;Po;0;ET;<wide> 0023;;;;N;;;;; -FF04;FULLWIDTH DOLLAR SIGN;Sc;0;ET;<wide> 0024;;;;N;;;;; -FF05;FULLWIDTH PERCENT SIGN;Po;0;ET;<wide> 0025;;;;N;;;;; -FF06;FULLWIDTH AMPERSAND;Po;0;ON;<wide> 0026;;;;N;;;;; -FF07;FULLWIDTH APOSTROPHE;Po;0;ON;<wide> 0027;;;;N;;;;; -FF08;FULLWIDTH LEFT PARENTHESIS;Ps;0;ON;<wide> 0028;;;;Y;FULLWIDTH OPENING PARENTHESIS;;;; -FF09;FULLWIDTH RIGHT PARENTHESIS;Pe;0;ON;<wide> 0029;;;;Y;FULLWIDTH CLOSING PARENTHESIS;;;; -FF0A;FULLWIDTH ASTERISK;Po;0;ON;<wide> 002A;;;;N;;;;; -FF0B;FULLWIDTH PLUS SIGN;Sm;0;ES;<wide> 002B;;;;N;;;;; -FF0C;FULLWIDTH COMMA;Po;0;CS;<wide> 002C;;;;N;;;;; -FF0D;FULLWIDTH HYPHEN-MINUS;Pd;0;ES;<wide> 002D;;;;N;;;;; -FF0E;FULLWIDTH FULL STOP;Po;0;CS;<wide> 002E;;;;N;FULLWIDTH PERIOD;;;; -FF0F;FULLWIDTH SOLIDUS;Po;0;CS;<wide> 002F;;;;N;FULLWIDTH SLASH;;;; -FF10;FULLWIDTH DIGIT ZERO;Nd;0;EN;<wide> 0030;0;0;0;N;;;;; -FF11;FULLWIDTH DIGIT ONE;Nd;0;EN;<wide> 0031;1;1;1;N;;;;; -FF12;FULLWIDTH DIGIT TWO;Nd;0;EN;<wide> 0032;2;2;2;N;;;;; -FF13;FULLWIDTH DIGIT THREE;Nd;0;EN;<wide> 0033;3;3;3;N;;;;; -FF14;FULLWIDTH DIGIT FOUR;Nd;0;EN;<wide> 0034;4;4;4;N;;;;; -FF15;FULLWIDTH DIGIT FIVE;Nd;0;EN;<wide> 0035;5;5;5;N;;;;; -FF16;FULLWIDTH DIGIT SIX;Nd;0;EN;<wide> 0036;6;6;6;N;;;;; -FF17;FULLWIDTH DIGIT SEVEN;Nd;0;EN;<wide> 0037;7;7;7;N;;;;; -FF18;FULLWIDTH DIGIT EIGHT;Nd;0;EN;<wide> 0038;8;8;8;N;;;;; -FF19;FULLWIDTH DIGIT NINE;Nd;0;EN;<wide> 0039;9;9;9;N;;;;; -FF1A;FULLWIDTH COLON;Po;0;CS;<wide> 003A;;;;N;;;;; -FF1B;FULLWIDTH SEMICOLON;Po;0;ON;<wide> 003B;;;;N;;;;; -FF1C;FULLWIDTH LESS-THAN SIGN;Sm;0;ON;<wide> 003C;;;;Y;;;;; -FF1D;FULLWIDTH EQUALS SIGN;Sm;0;ON;<wide> 003D;;;;N;;;;; -FF1E;FULLWIDTH GREATER-THAN SIGN;Sm;0;ON;<wide> 003E;;;;Y;;;;; -FF1F;FULLWIDTH QUESTION MARK;Po;0;ON;<wide> 003F;;;;N;;;;; -FF20;FULLWIDTH COMMERCIAL AT;Po;0;ON;<wide> 0040;;;;N;;;;; -FF21;FULLWIDTH LATIN CAPITAL LETTER A;Lu;0;L;<wide> 0041;;;;N;;;;FF41; -FF22;FULLWIDTH LATIN CAPITAL LETTER B;Lu;0;L;<wide> 0042;;;;N;;;;FF42; -FF23;FULLWIDTH LATIN CAPITAL LETTER C;Lu;0;L;<wide> 0043;;;;N;;;;FF43; -FF24;FULLWIDTH LATIN CAPITAL LETTER D;Lu;0;L;<wide> 0044;;;;N;;;;FF44; -FF25;FULLWIDTH LATIN CAPITAL LETTER E;Lu;0;L;<wide> 0045;;;;N;;;;FF45; -FF26;FULLWIDTH LATIN CAPITAL LETTER F;Lu;0;L;<wide> 0046;;;;N;;;;FF46; -FF27;FULLWIDTH LATIN CAPITAL LETTER G;Lu;0;L;<wide> 0047;;;;N;;;;FF47; -FF28;FULLWIDTH LATIN CAPITAL LETTER H;Lu;0;L;<wide> 0048;;;;N;;;;FF48; -FF29;FULLWIDTH LATIN CAPITAL LETTER I;Lu;0;L;<wide> 0049;;;;N;;;;FF49; -FF2A;FULLWIDTH LATIN CAPITAL LETTER J;Lu;0;L;<wide> 004A;;;;N;;;;FF4A; -FF2B;FULLWIDTH LATIN CAPITAL LETTER K;Lu;0;L;<wide> 004B;;;;N;;;;FF4B; -FF2C;FULLWIDTH LATIN CAPITAL LETTER L;Lu;0;L;<wide> 004C;;;;N;;;;FF4C; -FF2D;FULLWIDTH LATIN CAPITAL LETTER M;Lu;0;L;<wide> 004D;;;;N;;;;FF4D; -FF2E;FULLWIDTH LATIN CAPITAL LETTER N;Lu;0;L;<wide> 004E;;;;N;;;;FF4E; -FF2F;FULLWIDTH LATIN CAPITAL LETTER O;Lu;0;L;<wide> 004F;;;;N;;;;FF4F; -FF30;FULLWIDTH LATIN CAPITAL LETTER P;Lu;0;L;<wide> 0050;;;;N;;;;FF50; -FF31;FULLWIDTH LATIN CAPITAL LETTER Q;Lu;0;L;<wide> 0051;;;;N;;;;FF51; -FF32;FULLWIDTH LATIN CAPITAL LETTER R;Lu;0;L;<wide> 0052;;;;N;;;;FF52; -FF33;FULLWIDTH LATIN CAPITAL LETTER S;Lu;0;L;<wide> 0053;;;;N;;;;FF53; -FF34;FULLWIDTH LATIN CAPITAL LETTER T;Lu;0;L;<wide> 0054;;;;N;;;;FF54; -FF35;FULLWIDTH LATIN CAPITAL LETTER U;Lu;0;L;<wide> 0055;;;;N;;;;FF55; -FF36;FULLWIDTH LATIN CAPITAL LETTER V;Lu;0;L;<wide> 0056;;;;N;;;;FF56; -FF37;FULLWIDTH LATIN CAPITAL LETTER W;Lu;0;L;<wide> 0057;;;;N;;;;FF57; -FF38;FULLWIDTH LATIN CAPITAL LETTER X;Lu;0;L;<wide> 0058;;;;N;;;;FF58; -FF39;FULLWIDTH LATIN CAPITAL LETTER Y;Lu;0;L;<wide> 0059;;;;N;;;;FF59; -FF3A;FULLWIDTH LATIN CAPITAL LETTER Z;Lu;0;L;<wide> 005A;;;;N;;;;FF5A; -FF3B;FULLWIDTH LEFT SQUARE BRACKET;Ps;0;ON;<wide> 005B;;;;Y;FULLWIDTH OPENING SQUARE BRACKET;;;; -FF3C;FULLWIDTH REVERSE SOLIDUS;Po;0;ON;<wide> 005C;;;;N;FULLWIDTH BACKSLASH;;;; -FF3D;FULLWIDTH RIGHT SQUARE BRACKET;Pe;0;ON;<wide> 005D;;;;Y;FULLWIDTH CLOSING SQUARE BRACKET;;;; -FF3E;FULLWIDTH CIRCUMFLEX ACCENT;Sk;0;ON;<wide> 005E;;;;N;FULLWIDTH SPACING CIRCUMFLEX;;;; -FF3F;FULLWIDTH LOW LINE;Pc;0;ON;<wide> 005F;;;;N;FULLWIDTH SPACING UNDERSCORE;;;; -FF40;FULLWIDTH GRAVE ACCENT;Sk;0;ON;<wide> 0060;;;;N;FULLWIDTH SPACING GRAVE;;;; -FF41;FULLWIDTH LATIN SMALL LETTER A;Ll;0;L;<wide> 0061;;;;N;;;FF21;;FF21 -FF42;FULLWIDTH LATIN SMALL LETTER B;Ll;0;L;<wide> 0062;;;;N;;;FF22;;FF22 -FF43;FULLWIDTH LATIN SMALL LETTER C;Ll;0;L;<wide> 0063;;;;N;;;FF23;;FF23 -FF44;FULLWIDTH LATIN SMALL LETTER D;Ll;0;L;<wide> 0064;;;;N;;;FF24;;FF24 -FF45;FULLWIDTH LATIN SMALL LETTER E;Ll;0;L;<wide> 0065;;;;N;;;FF25;;FF25 -FF46;FULLWIDTH LATIN SMALL LETTER F;Ll;0;L;<wide> 0066;;;;N;;;FF26;;FF26 -FF47;FULLWIDTH LATIN SMALL LETTER G;Ll;0;L;<wide> 0067;;;;N;;;FF27;;FF27 -FF48;FULLWIDTH LATIN SMALL LETTER H;Ll;0;L;<wide> 0068;;;;N;;;FF28;;FF28 -FF49;FULLWIDTH LATIN SMALL LETTER I;Ll;0;L;<wide> 0069;;;;N;;;FF29;;FF29 -FF4A;FULLWIDTH LATIN SMALL LETTER J;Ll;0;L;<wide> 006A;;;;N;;;FF2A;;FF2A -FF4B;FULLWIDTH LATIN SMALL LETTER K;Ll;0;L;<wide> 006B;;;;N;;;FF2B;;FF2B -FF4C;FULLWIDTH LATIN SMALL LETTER L;Ll;0;L;<wide> 006C;;;;N;;;FF2C;;FF2C -FF4D;FULLWIDTH LATIN SMALL LETTER M;Ll;0;L;<wide> 006D;;;;N;;;FF2D;;FF2D -FF4E;FULLWIDTH LATIN SMALL LETTER N;Ll;0;L;<wide> 006E;;;;N;;;FF2E;;FF2E -FF4F;FULLWIDTH LATIN SMALL LETTER O;Ll;0;L;<wide> 006F;;;;N;;;FF2F;;FF2F -FF50;FULLWIDTH LATIN SMALL LETTER P;Ll;0;L;<wide> 0070;;;;N;;;FF30;;FF30 -FF51;FULLWIDTH LATIN SMALL LETTER Q;Ll;0;L;<wide> 0071;;;;N;;;FF31;;FF31 -FF52;FULLWIDTH LATIN SMALL LETTER R;Ll;0;L;<wide> 0072;;;;N;;;FF32;;FF32 -FF53;FULLWIDTH LATIN SMALL LETTER S;Ll;0;L;<wide> 0073;;;;N;;;FF33;;FF33 -FF54;FULLWIDTH LATIN SMALL LETTER T;Ll;0;L;<wide> 0074;;;;N;;;FF34;;FF34 -FF55;FULLWIDTH LATIN SMALL LETTER U;Ll;0;L;<wide> 0075;;;;N;;;FF35;;FF35 -FF56;FULLWIDTH LATIN SMALL LETTER V;Ll;0;L;<wide> 0076;;;;N;;;FF36;;FF36 -FF57;FULLWIDTH LATIN SMALL LETTER W;Ll;0;L;<wide> 0077;;;;N;;;FF37;;FF37 -FF58;FULLWIDTH LATIN SMALL LETTER X;Ll;0;L;<wide> 0078;;;;N;;;FF38;;FF38 -FF59;FULLWIDTH LATIN SMALL LETTER Y;Ll;0;L;<wide> 0079;;;;N;;;FF39;;FF39 -FF5A;FULLWIDTH LATIN SMALL LETTER Z;Ll;0;L;<wide> 007A;;;;N;;;FF3A;;FF3A -FF5B;FULLWIDTH LEFT CURLY BRACKET;Ps;0;ON;<wide> 007B;;;;Y;FULLWIDTH OPENING CURLY BRACKET;;;; -FF5C;FULLWIDTH VERTICAL LINE;Sm;0;ON;<wide> 007C;;;;N;FULLWIDTH VERTICAL BAR;;;; -FF5D;FULLWIDTH RIGHT CURLY BRACKET;Pe;0;ON;<wide> 007D;;;;Y;FULLWIDTH CLOSING CURLY BRACKET;;;; -FF5E;FULLWIDTH TILDE;Sm;0;ON;<wide> 007E;;;;N;FULLWIDTH SPACING TILDE;;;; -FF5F;FULLWIDTH LEFT WHITE PARENTHESIS;Ps;0;ON;<wide> 2985;;;;Y;;;;; -FF60;FULLWIDTH RIGHT WHITE PARENTHESIS;Pe;0;ON;<wide> 2986;;;;Y;;;;; -FF61;HALFWIDTH IDEOGRAPHIC FULL STOP;Po;0;ON;<narrow> 3002;;;;N;HALFWIDTH IDEOGRAPHIC PERIOD;;;; -FF62;HALFWIDTH LEFT CORNER BRACKET;Ps;0;ON;<narrow> 300C;;;;Y;HALFWIDTH OPENING CORNER BRACKET;;;; -FF63;HALFWIDTH RIGHT CORNER BRACKET;Pe;0;ON;<narrow> 300D;;;;Y;HALFWIDTH CLOSING CORNER BRACKET;;;; -FF64;HALFWIDTH IDEOGRAPHIC COMMA;Po;0;ON;<narrow> 3001;;;;N;;;;; -FF65;HALFWIDTH KATAKANA MIDDLE DOT;Po;0;ON;<narrow> 30FB;;;;N;;;;; -FF66;HALFWIDTH KATAKANA LETTER WO;Lo;0;L;<narrow> 30F2;;;;N;;;;; -FF67;HALFWIDTH KATAKANA LETTER SMALL A;Lo;0;L;<narrow> 30A1;;;;N;;;;; -FF68;HALFWIDTH KATAKANA LETTER SMALL I;Lo;0;L;<narrow> 30A3;;;;N;;;;; -FF69;HALFWIDTH KATAKANA LETTER SMALL U;Lo;0;L;<narrow> 30A5;;;;N;;;;; -FF6A;HALFWIDTH KATAKANA LETTER SMALL E;Lo;0;L;<narrow> 30A7;;;;N;;;;; -FF6B;HALFWIDTH KATAKANA LETTER SMALL O;Lo;0;L;<narrow> 30A9;;;;N;;;;; -FF6C;HALFWIDTH KATAKANA LETTER SMALL YA;Lo;0;L;<narrow> 30E3;;;;N;;;;; -FF6D;HALFWIDTH KATAKANA LETTER SMALL YU;Lo;0;L;<narrow> 30E5;;;;N;;;;; -FF6E;HALFWIDTH KATAKANA LETTER SMALL YO;Lo;0;L;<narrow> 30E7;;;;N;;;;; -FF6F;HALFWIDTH KATAKANA LETTER SMALL TU;Lo;0;L;<narrow> 30C3;;;;N;;;;; -FF70;HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L;<narrow> 30FC;;;;N;;;;; -FF71;HALFWIDTH KATAKANA LETTER A;Lo;0;L;<narrow> 30A2;;;;N;;;;; -FF72;HALFWIDTH KATAKANA LETTER I;Lo;0;L;<narrow> 30A4;;;;N;;;;; -FF73;HALFWIDTH KATAKANA LETTER U;Lo;0;L;<narrow> 30A6;;;;N;;;;; -FF74;HALFWIDTH KATAKANA LETTER E;Lo;0;L;<narrow> 30A8;;;;N;;;;; -FF75;HALFWIDTH KATAKANA LETTER O;Lo;0;L;<narrow> 30AA;;;;N;;;;; -FF76;HALFWIDTH KATAKANA LETTER KA;Lo;0;L;<narrow> 30AB;;;;N;;;;; -FF77;HALFWIDTH KATAKANA LETTER KI;Lo;0;L;<narrow> 30AD;;;;N;;;;; -FF78;HALFWIDTH KATAKANA LETTER KU;Lo;0;L;<narrow> 30AF;;;;N;;;;; -FF79;HALFWIDTH KATAKANA LETTER KE;Lo;0;L;<narrow> 30B1;;;;N;;;;; -FF7A;HALFWIDTH KATAKANA LETTER KO;Lo;0;L;<narrow> 30B3;;;;N;;;;; -FF7B;HALFWIDTH KATAKANA LETTER SA;Lo;0;L;<narrow> 30B5;;;;N;;;;; -FF7C;HALFWIDTH KATAKANA LETTER SI;Lo;0;L;<narrow> 30B7;;;;N;;;;; -FF7D;HALFWIDTH KATAKANA LETTER SU;Lo;0;L;<narrow> 30B9;;;;N;;;;; -FF7E;HALFWIDTH KATAKANA LETTER SE;Lo;0;L;<narrow> 30BB;;;;N;;;;; -FF7F;HALFWIDTH KATAKANA LETTER SO;Lo;0;L;<narrow> 30BD;;;;N;;;;; -FF80;HALFWIDTH KATAKANA LETTER TA;Lo;0;L;<narrow> 30BF;;;;N;;;;; -FF81;HALFWIDTH KATAKANA LETTER TI;Lo;0;L;<narrow> 30C1;;;;N;;;;; -FF82;HALFWIDTH KATAKANA LETTER TU;Lo;0;L;<narrow> 30C4;;;;N;;;;; -FF83;HALFWIDTH KATAKANA LETTER TE;Lo;0;L;<narrow> 30C6;;;;N;;;;; -FF84;HALFWIDTH KATAKANA LETTER TO;Lo;0;L;<narrow> 30C8;;;;N;;;;; -FF85;HALFWIDTH KATAKANA LETTER NA;Lo;0;L;<narrow> 30CA;;;;N;;;;; -FF86;HALFWIDTH KATAKANA LETTER NI;Lo;0;L;<narrow> 30CB;;;;N;;;;; -FF87;HALFWIDTH KATAKANA LETTER NU;Lo;0;L;<narrow> 30CC;;;;N;;;;; -FF88;HALFWIDTH KATAKANA LETTER NE;Lo;0;L;<narrow> 30CD;;;;N;;;;; -FF89;HALFWIDTH KATAKANA LETTER NO;Lo;0;L;<narrow> 30CE;;;;N;;;;; -FF8A;HALFWIDTH KATAKANA LETTER HA;Lo;0;L;<narrow> 30CF;;;;N;;;;; -FF8B;HALFWIDTH KATAKANA LETTER HI;Lo;0;L;<narrow> 30D2;;;;N;;;;; -FF8C;HALFWIDTH KATAKANA LETTER HU;Lo;0;L;<narrow> 30D5;;;;N;;;;; -FF8D;HALFWIDTH KATAKANA LETTER HE;Lo;0;L;<narrow> 30D8;;;;N;;;;; -FF8E;HALFWIDTH KATAKANA LETTER HO;Lo;0;L;<narrow> 30DB;;;;N;;;;; -FF8F;HALFWIDTH KATAKANA LETTER MA;Lo;0;L;<narrow> 30DE;;;;N;;;;; -FF90;HALFWIDTH KATAKANA LETTER MI;Lo;0;L;<narrow> 30DF;;;;N;;;;; -FF91;HALFWIDTH KATAKANA LETTER MU;Lo;0;L;<narrow> 30E0;;;;N;;;;; -FF92;HALFWIDTH KATAKANA LETTER ME;Lo;0;L;<narrow> 30E1;;;;N;;;;; -FF93;HALFWIDTH KATAKANA LETTER MO;Lo;0;L;<narrow> 30E2;;;;N;;;;; -FF94;HALFWIDTH KATAKANA LETTER YA;Lo;0;L;<narrow> 30E4;;;;N;;;;; -FF95;HALFWIDTH KATAKANA LETTER YU;Lo;0;L;<narrow> 30E6;;;;N;;;;; -FF96;HALFWIDTH KATAKANA LETTER YO;Lo;0;L;<narrow> 30E8;;;;N;;;;; -FF97;HALFWIDTH KATAKANA LETTER RA;Lo;0;L;<narrow> 30E9;;;;N;;;;; -FF98;HALFWIDTH KATAKANA LETTER RI;Lo;0;L;<narrow> 30EA;;;;N;;;;; -FF99;HALFWIDTH KATAKANA LETTER RU;Lo;0;L;<narrow> 30EB;;;;N;;;;; -FF9A;HALFWIDTH KATAKANA LETTER RE;Lo;0;L;<narrow> 30EC;;;;N;;;;; -FF9B;HALFWIDTH KATAKANA LETTER RO;Lo;0;L;<narrow> 30ED;;;;N;;;;; -FF9C;HALFWIDTH KATAKANA LETTER WA;Lo;0;L;<narrow> 30EF;;;;N;;;;; -FF9D;HALFWIDTH KATAKANA LETTER N;Lo;0;L;<narrow> 30F3;;;;N;;;;; -FF9E;HALFWIDTH KATAKANA VOICED SOUND MARK;Lm;0;L;<narrow> 3099;;;;N;;;;; -FF9F;HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK;Lm;0;L;<narrow> 309A;;;;N;;;;; -FFA0;HALFWIDTH HANGUL FILLER;Lo;0;L;<narrow> 3164;;;;N;HALFWIDTH HANGUL CAE OM;;;; -FFA1;HALFWIDTH HANGUL LETTER KIYEOK;Lo;0;L;<narrow> 3131;;;;N;HALFWIDTH HANGUL LETTER GIYEOG;;;; -FFA2;HALFWIDTH HANGUL LETTER SSANGKIYEOK;Lo;0;L;<narrow> 3132;;;;N;HALFWIDTH HANGUL LETTER SSANG GIYEOG;;;; -FFA3;HALFWIDTH HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<narrow> 3133;;;;N;HALFWIDTH HANGUL LETTER GIYEOG SIOS;;;; -FFA4;HALFWIDTH HANGUL LETTER NIEUN;Lo;0;L;<narrow> 3134;;;;N;;;;; -FFA5;HALFWIDTH HANGUL LETTER NIEUN-CIEUC;Lo;0;L;<narrow> 3135;;;;N;HALFWIDTH HANGUL LETTER NIEUN JIEUJ;;;; -FFA6;HALFWIDTH HANGUL LETTER NIEUN-HIEUH;Lo;0;L;<narrow> 3136;;;;N;HALFWIDTH HANGUL LETTER NIEUN HIEUH;;;; -FFA7;HALFWIDTH HANGUL LETTER TIKEUT;Lo;0;L;<narrow> 3137;;;;N;HALFWIDTH HANGUL LETTER DIGEUD;;;; -FFA8;HALFWIDTH HANGUL LETTER SSANGTIKEUT;Lo;0;L;<narrow> 3138;;;;N;HALFWIDTH HANGUL LETTER SSANG DIGEUD;;;; -FFA9;HALFWIDTH HANGUL LETTER RIEUL;Lo;0;L;<narrow> 3139;;;;N;HALFWIDTH HANGUL LETTER LIEUL;;;; -FFAA;HALFWIDTH HANGUL LETTER RIEUL-KIYEOK;Lo;0;L;<narrow> 313A;;;;N;HALFWIDTH HANGUL LETTER LIEUL GIYEOG;;;; -FFAB;HALFWIDTH HANGUL LETTER RIEUL-MIEUM;Lo;0;L;<narrow> 313B;;;;N;HALFWIDTH HANGUL LETTER LIEUL MIEUM;;;; -FFAC;HALFWIDTH HANGUL LETTER RIEUL-PIEUP;Lo;0;L;<narrow> 313C;;;;N;HALFWIDTH HANGUL LETTER LIEUL BIEUB;;;; -FFAD;HALFWIDTH HANGUL LETTER RIEUL-SIOS;Lo;0;L;<narrow> 313D;;;;N;HALFWIDTH HANGUL LETTER LIEUL SIOS;;;; -FFAE;HALFWIDTH HANGUL LETTER RIEUL-THIEUTH;Lo;0;L;<narrow> 313E;;;;N;HALFWIDTH HANGUL LETTER LIEUL TIEUT;;;; -FFAF;HALFWIDTH HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L;<narrow> 313F;;;;N;HALFWIDTH HANGUL LETTER LIEUL PIEUP;;;; -FFB0;HALFWIDTH HANGUL LETTER RIEUL-HIEUH;Lo;0;L;<narrow> 3140;;;;N;HALFWIDTH HANGUL LETTER LIEUL HIEUH;;;; -FFB1;HALFWIDTH HANGUL LETTER MIEUM;Lo;0;L;<narrow> 3141;;;;N;;;;; -FFB2;HALFWIDTH HANGUL LETTER PIEUP;Lo;0;L;<narrow> 3142;;;;N;HALFWIDTH HANGUL LETTER BIEUB;;;; -FFB3;HALFWIDTH HANGUL LETTER SSANGPIEUP;Lo;0;L;<narrow> 3143;;;;N;HALFWIDTH HANGUL LETTER SSANG BIEUB;;;; -FFB4;HALFWIDTH HANGUL LETTER PIEUP-SIOS;Lo;0;L;<narrow> 3144;;;;N;HALFWIDTH HANGUL LETTER BIEUB SIOS;;;; -FFB5;HALFWIDTH HANGUL LETTER SIOS;Lo;0;L;<narrow> 3145;;;;N;;;;; -FFB6;HALFWIDTH HANGUL LETTER SSANGSIOS;Lo;0;L;<narrow> 3146;;;;N;HALFWIDTH HANGUL LETTER SSANG SIOS;;;; -FFB7;HALFWIDTH HANGUL LETTER IEUNG;Lo;0;L;<narrow> 3147;;;;N;;;;; -FFB8;HALFWIDTH HANGUL LETTER CIEUC;Lo;0;L;<narrow> 3148;;;;N;HALFWIDTH HANGUL LETTER JIEUJ;;;; -FFB9;HALFWIDTH HANGUL LETTER SSANGCIEUC;Lo;0;L;<narrow> 3149;;;;N;HALFWIDTH HANGUL LETTER SSANG JIEUJ;;;; -FFBA;HALFWIDTH HANGUL LETTER CHIEUCH;Lo;0;L;<narrow> 314A;;;;N;HALFWIDTH HANGUL LETTER CIEUC;;;; -FFBB;HALFWIDTH HANGUL LETTER KHIEUKH;Lo;0;L;<narrow> 314B;;;;N;HALFWIDTH HANGUL LETTER KIYEOK;;;; -FFBC;HALFWIDTH HANGUL LETTER THIEUTH;Lo;0;L;<narrow> 314C;;;;N;HALFWIDTH HANGUL LETTER TIEUT;;;; -FFBD;HALFWIDTH HANGUL LETTER PHIEUPH;Lo;0;L;<narrow> 314D;;;;N;HALFWIDTH HANGUL LETTER PIEUP;;;; -FFBE;HALFWIDTH HANGUL LETTER HIEUH;Lo;0;L;<narrow> 314E;;;;N;;;;; -FFC2;HALFWIDTH HANGUL LETTER A;Lo;0;L;<narrow> 314F;;;;N;;;;; -FFC3;HALFWIDTH HANGUL LETTER AE;Lo;0;L;<narrow> 3150;;;;N;;;;; -FFC4;HALFWIDTH HANGUL LETTER YA;Lo;0;L;<narrow> 3151;;;;N;;;;; -FFC5;HALFWIDTH HANGUL LETTER YAE;Lo;0;L;<narrow> 3152;;;;N;;;;; -FFC6;HALFWIDTH HANGUL LETTER EO;Lo;0;L;<narrow> 3153;;;;N;;;;; -FFC7;HALFWIDTH HANGUL LETTER E;Lo;0;L;<narrow> 3154;;;;N;;;;; -FFCA;HALFWIDTH HANGUL LETTER YEO;Lo;0;L;<narrow> 3155;;;;N;;;;; -FFCB;HALFWIDTH HANGUL LETTER YE;Lo;0;L;<narrow> 3156;;;;N;;;;; -FFCC;HALFWIDTH HANGUL LETTER O;Lo;0;L;<narrow> 3157;;;;N;;;;; -FFCD;HALFWIDTH HANGUL LETTER WA;Lo;0;L;<narrow> 3158;;;;N;;;;; -FFCE;HALFWIDTH HANGUL LETTER WAE;Lo;0;L;<narrow> 3159;;;;N;;;;; -FFCF;HALFWIDTH HANGUL LETTER OE;Lo;0;L;<narrow> 315A;;;;N;;;;; -FFD2;HALFWIDTH HANGUL LETTER YO;Lo;0;L;<narrow> 315B;;;;N;;;;; -FFD3;HALFWIDTH HANGUL LETTER U;Lo;0;L;<narrow> 315C;;;;N;;;;; -FFD4;HALFWIDTH HANGUL LETTER WEO;Lo;0;L;<narrow> 315D;;;;N;;;;; -FFD5;HALFWIDTH HANGUL LETTER WE;Lo;0;L;<narrow> 315E;;;;N;;;;; -FFD6;HALFWIDTH HANGUL LETTER WI;Lo;0;L;<narrow> 315F;;;;N;;;;; -FFD7;HALFWIDTH HANGUL LETTER YU;Lo;0;L;<narrow> 3160;;;;N;;;;; -FFDA;HALFWIDTH HANGUL LETTER EU;Lo;0;L;<narrow> 3161;;;;N;;;;; -FFDB;HALFWIDTH HANGUL LETTER YI;Lo;0;L;<narrow> 3162;;;;N;;;;; -FFDC;HALFWIDTH HANGUL LETTER I;Lo;0;L;<narrow> 3163;;;;N;;;;; -FFE0;FULLWIDTH CENT SIGN;Sc;0;ET;<wide> 00A2;;;;N;;;;; -FFE1;FULLWIDTH POUND SIGN;Sc;0;ET;<wide> 00A3;;;;N;;;;; -FFE2;FULLWIDTH NOT SIGN;Sm;0;ON;<wide> 00AC;;;;N;;;;; -FFE3;FULLWIDTH MACRON;Sk;0;ON;<wide> 00AF;;;;N;FULLWIDTH SPACING MACRON;;;; -FFE4;FULLWIDTH BROKEN BAR;So;0;ON;<wide> 00A6;;;;N;FULLWIDTH BROKEN VERTICAL BAR;;;; -FFE5;FULLWIDTH YEN SIGN;Sc;0;ET;<wide> 00A5;;;;N;;;;; -FFE6;FULLWIDTH WON SIGN;Sc;0;ET;<wide> 20A9;;;;N;;;;; -FFE8;HALFWIDTH FORMS LIGHT VERTICAL;So;0;ON;<narrow> 2502;;;;N;;;;; -FFE9;HALFWIDTH LEFTWARDS ARROW;Sm;0;ON;<narrow> 2190;;;;N;;;;; -FFEA;HALFWIDTH UPWARDS ARROW;Sm;0;ON;<narrow> 2191;;;;N;;;;; -FFEB;HALFWIDTH RIGHTWARDS ARROW;Sm;0;ON;<narrow> 2192;;;;N;;;;; -FFEC;HALFWIDTH DOWNWARDS ARROW;Sm;0;ON;<narrow> 2193;;;;N;;;;; -FFED;HALFWIDTH BLACK SQUARE;So;0;ON;<narrow> 25A0;;;;N;;;;; -FFEE;HALFWIDTH WHITE CIRCLE;So;0;ON;<narrow> 25CB;;;;N;;;;; -FFF9;INTERLINEAR ANNOTATION ANCHOR;Cf;0;ON;;;;;N;;;;; -FFFA;INTERLINEAR ANNOTATION SEPARATOR;Cf;0;ON;;;;;N;;;;; -FFFB;INTERLINEAR ANNOTATION TERMINATOR;Cf;0;ON;;;;;N;;;;; -FFFC;OBJECT REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; -FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; -10000;LINEAR B SYLLABLE B008 A;Lo;0;L;;;;;N;;;;; -10001;LINEAR B SYLLABLE B038 E;Lo;0;L;;;;;N;;;;; -10002;LINEAR B SYLLABLE B028 I;Lo;0;L;;;;;N;;;;; -10003;LINEAR B SYLLABLE B061 O;Lo;0;L;;;;;N;;;;; -10004;LINEAR B SYLLABLE B010 U;Lo;0;L;;;;;N;;;;; -10005;LINEAR B SYLLABLE B001 DA;Lo;0;L;;;;;N;;;;; -10006;LINEAR B SYLLABLE B045 DE;Lo;0;L;;;;;N;;;;; -10007;LINEAR B SYLLABLE B007 DI;Lo;0;L;;;;;N;;;;; -10008;LINEAR B SYLLABLE B014 DO;Lo;0;L;;;;;N;;;;; -10009;LINEAR B SYLLABLE B051 DU;Lo;0;L;;;;;N;;;;; -1000A;LINEAR B SYLLABLE B057 JA;Lo;0;L;;;;;N;;;;; -1000B;LINEAR B SYLLABLE B046 JE;Lo;0;L;;;;;N;;;;; -1000D;LINEAR B SYLLABLE B036 JO;Lo;0;L;;;;;N;;;;; -1000E;LINEAR B SYLLABLE B065 JU;Lo;0;L;;;;;N;;;;; -1000F;LINEAR B SYLLABLE B077 KA;Lo;0;L;;;;;N;;;;; -10010;LINEAR B SYLLABLE B044 KE;Lo;0;L;;;;;N;;;;; -10011;LINEAR B SYLLABLE B067 KI;Lo;0;L;;;;;N;;;;; -10012;LINEAR B SYLLABLE B070 KO;Lo;0;L;;;;;N;;;;; -10013;LINEAR B SYLLABLE B081 KU;Lo;0;L;;;;;N;;;;; -10014;LINEAR B SYLLABLE B080 MA;Lo;0;L;;;;;N;;;;; -10015;LINEAR B SYLLABLE B013 ME;Lo;0;L;;;;;N;;;;; -10016;LINEAR B SYLLABLE B073 MI;Lo;0;L;;;;;N;;;;; -10017;LINEAR B SYLLABLE B015 MO;Lo;0;L;;;;;N;;;;; -10018;LINEAR B SYLLABLE B023 MU;Lo;0;L;;;;;N;;;;; -10019;LINEAR B SYLLABLE B006 NA;Lo;0;L;;;;;N;;;;; -1001A;LINEAR B SYLLABLE B024 NE;Lo;0;L;;;;;N;;;;; -1001B;LINEAR B SYLLABLE B030 NI;Lo;0;L;;;;;N;;;;; -1001C;LINEAR B SYLLABLE B052 NO;Lo;0;L;;;;;N;;;;; -1001D;LINEAR B SYLLABLE B055 NU;Lo;0;L;;;;;N;;;;; -1001E;LINEAR B SYLLABLE B003 PA;Lo;0;L;;;;;N;;;;; -1001F;LINEAR B SYLLABLE B072 PE;Lo;0;L;;;;;N;;;;; -10020;LINEAR B SYLLABLE B039 PI;Lo;0;L;;;;;N;;;;; -10021;LINEAR B SYLLABLE B011 PO;Lo;0;L;;;;;N;;;;; -10022;LINEAR B SYLLABLE B050 PU;Lo;0;L;;;;;N;;;;; -10023;LINEAR B SYLLABLE B016 QA;Lo;0;L;;;;;N;;;;; -10024;LINEAR B SYLLABLE B078 QE;Lo;0;L;;;;;N;;;;; -10025;LINEAR B SYLLABLE B021 QI;Lo;0;L;;;;;N;;;;; -10026;LINEAR B SYLLABLE B032 QO;Lo;0;L;;;;;N;;;;; -10028;LINEAR B SYLLABLE B060 RA;Lo;0;L;;;;;N;;;;; -10029;LINEAR B SYLLABLE B027 RE;Lo;0;L;;;;;N;;;;; -1002A;LINEAR B SYLLABLE B053 RI;Lo;0;L;;;;;N;;;;; -1002B;LINEAR B SYLLABLE B002 RO;Lo;0;L;;;;;N;;;;; -1002C;LINEAR B SYLLABLE B026 RU;Lo;0;L;;;;;N;;;;; -1002D;LINEAR B SYLLABLE B031 SA;Lo;0;L;;;;;N;;;;; -1002E;LINEAR B SYLLABLE B009 SE;Lo;0;L;;;;;N;;;;; -1002F;LINEAR B SYLLABLE B041 SI;Lo;0;L;;;;;N;;;;; -10030;LINEAR B SYLLABLE B012 SO;Lo;0;L;;;;;N;;;;; -10031;LINEAR B SYLLABLE B058 SU;Lo;0;L;;;;;N;;;;; -10032;LINEAR B SYLLABLE B059 TA;Lo;0;L;;;;;N;;;;; -10033;LINEAR B SYLLABLE B004 TE;Lo;0;L;;;;;N;;;;; -10034;LINEAR B SYLLABLE B037 TI;Lo;0;L;;;;;N;;;;; -10035;LINEAR B SYLLABLE B005 TO;Lo;0;L;;;;;N;;;;; -10036;LINEAR B SYLLABLE B069 TU;Lo;0;L;;;;;N;;;;; -10037;LINEAR B SYLLABLE B054 WA;Lo;0;L;;;;;N;;;;; -10038;LINEAR B SYLLABLE B075 WE;Lo;0;L;;;;;N;;;;; -10039;LINEAR B SYLLABLE B040 WI;Lo;0;L;;;;;N;;;;; -1003A;LINEAR B SYLLABLE B042 WO;Lo;0;L;;;;;N;;;;; -1003C;LINEAR B SYLLABLE B017 ZA;Lo;0;L;;;;;N;;;;; -1003D;LINEAR B SYLLABLE B074 ZE;Lo;0;L;;;;;N;;;;; -1003F;LINEAR B SYLLABLE B020 ZO;Lo;0;L;;;;;N;;;;; -10040;LINEAR B SYLLABLE B025 A2;Lo;0;L;;;;;N;;;;; -10041;LINEAR B SYLLABLE B043 A3;Lo;0;L;;;;;N;;;;; -10042;LINEAR B SYLLABLE B085 AU;Lo;0;L;;;;;N;;;;; -10043;LINEAR B SYLLABLE B071 DWE;Lo;0;L;;;;;N;;;;; -10044;LINEAR B SYLLABLE B090 DWO;Lo;0;L;;;;;N;;;;; -10045;LINEAR B SYLLABLE B048 NWA;Lo;0;L;;;;;N;;;;; -10046;LINEAR B SYLLABLE B029 PU2;Lo;0;L;;;;;N;;;;; -10047;LINEAR B SYLLABLE B062 PTE;Lo;0;L;;;;;N;;;;; -10048;LINEAR B SYLLABLE B076 RA2;Lo;0;L;;;;;N;;;;; -10049;LINEAR B SYLLABLE B033 RA3;Lo;0;L;;;;;N;;;;; -1004A;LINEAR B SYLLABLE B068 RO2;Lo;0;L;;;;;N;;;;; -1004B;LINEAR B SYLLABLE B066 TA2;Lo;0;L;;;;;N;;;;; -1004C;LINEAR B SYLLABLE B087 TWE;Lo;0;L;;;;;N;;;;; -1004D;LINEAR B SYLLABLE B091 TWO;Lo;0;L;;;;;N;;;;; -10050;LINEAR B SYMBOL B018;Lo;0;L;;;;;N;;;;; -10051;LINEAR B SYMBOL B019;Lo;0;L;;;;;N;;;;; -10052;LINEAR B SYMBOL B022;Lo;0;L;;;;;N;;;;; -10053;LINEAR B SYMBOL B034;Lo;0;L;;;;;N;;;;; -10054;LINEAR B SYMBOL B047;Lo;0;L;;;;;N;;;;; -10055;LINEAR B SYMBOL B049;Lo;0;L;;;;;N;;;;; -10056;LINEAR B SYMBOL B056;Lo;0;L;;;;;N;;;;; -10057;LINEAR B SYMBOL B063;Lo;0;L;;;;;N;;;;; -10058;LINEAR B SYMBOL B064;Lo;0;L;;;;;N;;;;; -10059;LINEAR B SYMBOL B079;Lo;0;L;;;;;N;;;;; -1005A;LINEAR B SYMBOL B082;Lo;0;L;;;;;N;;;;; -1005B;LINEAR B SYMBOL B083;Lo;0;L;;;;;N;;;;; -1005C;LINEAR B SYMBOL B086;Lo;0;L;;;;;N;;;;; -1005D;LINEAR B SYMBOL B089;Lo;0;L;;;;;N;;;;; -10080;LINEAR B IDEOGRAM B100 MAN;Lo;0;L;;;;;N;;;;; -10081;LINEAR B IDEOGRAM B102 WOMAN;Lo;0;L;;;;;N;;;;; -10082;LINEAR B IDEOGRAM B104 DEER;Lo;0;L;;;;;N;;;;; -10083;LINEAR B IDEOGRAM B105 EQUID;Lo;0;L;;;;;N;;;;; -10084;LINEAR B IDEOGRAM B105F MARE;Lo;0;L;;;;;N;;;;; -10085;LINEAR B IDEOGRAM B105M STALLION;Lo;0;L;;;;;N;;;;; -10086;LINEAR B IDEOGRAM B106F EWE;Lo;0;L;;;;;N;;;;; -10087;LINEAR B IDEOGRAM B106M RAM;Lo;0;L;;;;;N;;;;; -10088;LINEAR B IDEOGRAM B107F SHE-GOAT;Lo;0;L;;;;;N;;;;; -10089;LINEAR B IDEOGRAM B107M HE-GOAT;Lo;0;L;;;;;N;;;;; -1008A;LINEAR B IDEOGRAM B108F SOW;Lo;0;L;;;;;N;;;;; -1008B;LINEAR B IDEOGRAM B108M BOAR;Lo;0;L;;;;;N;;;;; -1008C;LINEAR B IDEOGRAM B109F COW;Lo;0;L;;;;;N;;;;; -1008D;LINEAR B IDEOGRAM B109M BULL;Lo;0;L;;;;;N;;;;; -1008E;LINEAR B IDEOGRAM B120 WHEAT;Lo;0;L;;;;;N;;;;; -1008F;LINEAR B IDEOGRAM B121 BARLEY;Lo;0;L;;;;;N;;;;; -10090;LINEAR B IDEOGRAM B122 OLIVE;Lo;0;L;;;;;N;;;;; -10091;LINEAR B IDEOGRAM B123 SPICE;Lo;0;L;;;;;N;;;;; -10092;LINEAR B IDEOGRAM B125 CYPERUS;Lo;0;L;;;;;N;;;;; -10093;LINEAR B MONOGRAM B127 KAPO;Lo;0;L;;;;;N;;;;; -10094;LINEAR B MONOGRAM B128 KANAKO;Lo;0;L;;;;;N;;;;; -10095;LINEAR B IDEOGRAM B130 OIL;Lo;0;L;;;;;N;;;;; -10096;LINEAR B IDEOGRAM B131 WINE;Lo;0;L;;;;;N;;;;; -10097;LINEAR B IDEOGRAM B132;Lo;0;L;;;;;N;;;;; -10098;LINEAR B MONOGRAM B133 AREPA;Lo;0;L;;;;;N;;;;; -10099;LINEAR B MONOGRAM B135 MERI;Lo;0;L;;;;;N;;;;; -1009A;LINEAR B IDEOGRAM B140 BRONZE;Lo;0;L;;;;;N;;;;; -1009B;LINEAR B IDEOGRAM B141 GOLD;Lo;0;L;;;;;N;;;;; -1009C;LINEAR B IDEOGRAM B142;Lo;0;L;;;;;N;;;;; -1009D;LINEAR B IDEOGRAM B145 WOOL;Lo;0;L;;;;;N;;;;; -1009E;LINEAR B IDEOGRAM B146;Lo;0;L;;;;;N;;;;; -1009F;LINEAR B IDEOGRAM B150;Lo;0;L;;;;;N;;;;; -100A0;LINEAR B IDEOGRAM B151 HORN;Lo;0;L;;;;;N;;;;; -100A1;LINEAR B IDEOGRAM B152;Lo;0;L;;;;;N;;;;; -100A2;LINEAR B IDEOGRAM B153;Lo;0;L;;;;;N;;;;; -100A3;LINEAR B IDEOGRAM B154;Lo;0;L;;;;;N;;;;; -100A4;LINEAR B MONOGRAM B156 TURO2;Lo;0;L;;;;;N;;;;; -100A5;LINEAR B IDEOGRAM B157;Lo;0;L;;;;;N;;;;; -100A6;LINEAR B IDEOGRAM B158;Lo;0;L;;;;;N;;;;; -100A7;LINEAR B IDEOGRAM B159 CLOTH;Lo;0;L;;;;;N;;;;; -100A8;LINEAR B IDEOGRAM B160;Lo;0;L;;;;;N;;;;; -100A9;LINEAR B IDEOGRAM B161;Lo;0;L;;;;;N;;;;; -100AA;LINEAR B IDEOGRAM B162 GARMENT;Lo;0;L;;;;;N;;;;; -100AB;LINEAR B IDEOGRAM B163 ARMOUR;Lo;0;L;;;;;N;;;;; -100AC;LINEAR B IDEOGRAM B164;Lo;0;L;;;;;N;;;;; -100AD;LINEAR B IDEOGRAM B165;Lo;0;L;;;;;N;;;;; -100AE;LINEAR B IDEOGRAM B166;Lo;0;L;;;;;N;;;;; -100AF;LINEAR B IDEOGRAM B167;Lo;0;L;;;;;N;;;;; -100B0;LINEAR B IDEOGRAM B168;Lo;0;L;;;;;N;;;;; -100B1;LINEAR B IDEOGRAM B169;Lo;0;L;;;;;N;;;;; -100B2;LINEAR B IDEOGRAM B170;Lo;0;L;;;;;N;;;;; -100B3;LINEAR B IDEOGRAM B171;Lo;0;L;;;;;N;;;;; -100B4;LINEAR B IDEOGRAM B172;Lo;0;L;;;;;N;;;;; -100B5;LINEAR B IDEOGRAM B173 MONTH;Lo;0;L;;;;;N;;;;; -100B6;LINEAR B IDEOGRAM B174;Lo;0;L;;;;;N;;;;; -100B7;LINEAR B IDEOGRAM B176 TREE;Lo;0;L;;;;;N;;;;; -100B8;LINEAR B IDEOGRAM B177;Lo;0;L;;;;;N;;;;; -100B9;LINEAR B IDEOGRAM B178;Lo;0;L;;;;;N;;;;; -100BA;LINEAR B IDEOGRAM B179;Lo;0;L;;;;;N;;;;; -100BB;LINEAR B IDEOGRAM B180;Lo;0;L;;;;;N;;;;; -100BC;LINEAR B IDEOGRAM B181;Lo;0;L;;;;;N;;;;; -100BD;LINEAR B IDEOGRAM B182;Lo;0;L;;;;;N;;;;; -100BE;LINEAR B IDEOGRAM B183;Lo;0;L;;;;;N;;;;; -100BF;LINEAR B IDEOGRAM B184;Lo;0;L;;;;;N;;;;; -100C0;LINEAR B IDEOGRAM B185;Lo;0;L;;;;;N;;;;; -100C1;LINEAR B IDEOGRAM B189;Lo;0;L;;;;;N;;;;; -100C2;LINEAR B IDEOGRAM B190;Lo;0;L;;;;;N;;;;; -100C3;LINEAR B IDEOGRAM B191 HELMET;Lo;0;L;;;;;N;;;;; -100C4;LINEAR B IDEOGRAM B220 FOOTSTOOL;Lo;0;L;;;;;N;;;;; -100C5;LINEAR B IDEOGRAM B225 BATHTUB;Lo;0;L;;;;;N;;;;; -100C6;LINEAR B IDEOGRAM B230 SPEAR;Lo;0;L;;;;;N;;;;; -100C7;LINEAR B IDEOGRAM B231 ARROW;Lo;0;L;;;;;N;;;;; -100C8;LINEAR B IDEOGRAM B232;Lo;0;L;;;;;N;;;;; -100C9;LINEAR B IDEOGRAM B233 SWORD;Lo;0;L;;;;;N;;;;; -100CA;LINEAR B IDEOGRAM B234;Lo;0;L;;;;;N;;;;; -100CB;LINEAR B IDEOGRAM B236;Lo;0;L;;;;;N;;;;; -100CC;LINEAR B IDEOGRAM B240 WHEELED CHARIOT;Lo;0;L;;;;;N;;;;; -100CD;LINEAR B IDEOGRAM B241 CHARIOT;Lo;0;L;;;;;N;;;;; -100CE;LINEAR B IDEOGRAM B242 CHARIOT FRAME;Lo;0;L;;;;;N;;;;; -100CF;LINEAR B IDEOGRAM B243 WHEEL;Lo;0;L;;;;;N;;;;; -100D0;LINEAR B IDEOGRAM B245;Lo;0;L;;;;;N;;;;; -100D1;LINEAR B IDEOGRAM B246;Lo;0;L;;;;;N;;;;; -100D2;LINEAR B MONOGRAM B247 DIPTE;Lo;0;L;;;;;N;;;;; -100D3;LINEAR B IDEOGRAM B248;Lo;0;L;;;;;N;;;;; -100D4;LINEAR B IDEOGRAM B249;Lo;0;L;;;;;N;;;;; -100D5;LINEAR B IDEOGRAM B251;Lo;0;L;;;;;N;;;;; -100D6;LINEAR B IDEOGRAM B252;Lo;0;L;;;;;N;;;;; -100D7;LINEAR B IDEOGRAM B253;Lo;0;L;;;;;N;;;;; -100D8;LINEAR B IDEOGRAM B254 DART;Lo;0;L;;;;;N;;;;; -100D9;LINEAR B IDEOGRAM B255;Lo;0;L;;;;;N;;;;; -100DA;LINEAR B IDEOGRAM B256;Lo;0;L;;;;;N;;;;; -100DB;LINEAR B IDEOGRAM B257;Lo;0;L;;;;;N;;;;; -100DC;LINEAR B IDEOGRAM B258;Lo;0;L;;;;;N;;;;; -100DD;LINEAR B IDEOGRAM B259;Lo;0;L;;;;;N;;;;; -100DE;LINEAR B IDEOGRAM VESSEL B155;Lo;0;L;;;;;N;;;;; -100DF;LINEAR B IDEOGRAM VESSEL B200;Lo;0;L;;;;;N;;;;; -100E0;LINEAR B IDEOGRAM VESSEL B201;Lo;0;L;;;;;N;;;;; -100E1;LINEAR B IDEOGRAM VESSEL B202;Lo;0;L;;;;;N;;;;; -100E2;LINEAR B IDEOGRAM VESSEL B203;Lo;0;L;;;;;N;;;;; -100E3;LINEAR B IDEOGRAM VESSEL B204;Lo;0;L;;;;;N;;;;; -100E4;LINEAR B IDEOGRAM VESSEL B205;Lo;0;L;;;;;N;;;;; -100E5;LINEAR B IDEOGRAM VESSEL B206;Lo;0;L;;;;;N;;;;; -100E6;LINEAR B IDEOGRAM VESSEL B207;Lo;0;L;;;;;N;;;;; -100E7;LINEAR B IDEOGRAM VESSEL B208;Lo;0;L;;;;;N;;;;; -100E8;LINEAR B IDEOGRAM VESSEL B209;Lo;0;L;;;;;N;;;;; -100E9;LINEAR B IDEOGRAM VESSEL B210;Lo;0;L;;;;;N;;;;; -100EA;LINEAR B IDEOGRAM VESSEL B211;Lo;0;L;;;;;N;;;;; -100EB;LINEAR B IDEOGRAM VESSEL B212;Lo;0;L;;;;;N;;;;; -100EC;LINEAR B IDEOGRAM VESSEL B213;Lo;0;L;;;;;N;;;;; -100ED;LINEAR B IDEOGRAM VESSEL B214;Lo;0;L;;;;;N;;;;; -100EE;LINEAR B IDEOGRAM VESSEL B215;Lo;0;L;;;;;N;;;;; -100EF;LINEAR B IDEOGRAM VESSEL B216;Lo;0;L;;;;;N;;;;; -100F0;LINEAR B IDEOGRAM VESSEL B217;Lo;0;L;;;;;N;;;;; -100F1;LINEAR B IDEOGRAM VESSEL B218;Lo;0;L;;;;;N;;;;; -100F2;LINEAR B IDEOGRAM VESSEL B219;Lo;0;L;;;;;N;;;;; -100F3;LINEAR B IDEOGRAM VESSEL B221;Lo;0;L;;;;;N;;;;; -100F4;LINEAR B IDEOGRAM VESSEL B222;Lo;0;L;;;;;N;;;;; -100F5;LINEAR B IDEOGRAM VESSEL B226;Lo;0;L;;;;;N;;;;; -100F6;LINEAR B IDEOGRAM VESSEL B227;Lo;0;L;;;;;N;;;;; -100F7;LINEAR B IDEOGRAM VESSEL B228;Lo;0;L;;;;;N;;;;; -100F8;LINEAR B IDEOGRAM VESSEL B229;Lo;0;L;;;;;N;;;;; -100F9;LINEAR B IDEOGRAM VESSEL B250;Lo;0;L;;;;;N;;;;; -100FA;LINEAR B IDEOGRAM VESSEL B305;Lo;0;L;;;;;N;;;;; -10100;AEGEAN WORD SEPARATOR LINE;Po;0;L;;;;;N;;;;; -10101;AEGEAN WORD SEPARATOR DOT;Po;0;ON;;;;;N;;;;; -10102;AEGEAN CHECK MARK;Po;0;L;;;;;N;;;;; -10107;AEGEAN NUMBER ONE;No;0;L;;;;1;N;;;;; -10108;AEGEAN NUMBER TWO;No;0;L;;;;2;N;;;;; -10109;AEGEAN NUMBER THREE;No;0;L;;;;3;N;;;;; -1010A;AEGEAN NUMBER FOUR;No;0;L;;;;4;N;;;;; -1010B;AEGEAN NUMBER FIVE;No;0;L;;;;5;N;;;;; -1010C;AEGEAN NUMBER SIX;No;0;L;;;;6;N;;;;; -1010D;AEGEAN NUMBER SEVEN;No;0;L;;;;7;N;;;;; -1010E;AEGEAN NUMBER EIGHT;No;0;L;;;;8;N;;;;; -1010F;AEGEAN NUMBER NINE;No;0;L;;;;9;N;;;;; -10110;AEGEAN NUMBER TEN;No;0;L;;;;10;N;;;;; -10111;AEGEAN NUMBER TWENTY;No;0;L;;;;20;N;;;;; -10112;AEGEAN NUMBER THIRTY;No;0;L;;;;30;N;;;;; -10113;AEGEAN NUMBER FORTY;No;0;L;;;;40;N;;;;; -10114;AEGEAN NUMBER FIFTY;No;0;L;;;;50;N;;;;; -10115;AEGEAN NUMBER SIXTY;No;0;L;;;;60;N;;;;; -10116;AEGEAN NUMBER SEVENTY;No;0;L;;;;70;N;;;;; -10117;AEGEAN NUMBER EIGHTY;No;0;L;;;;80;N;;;;; -10118;AEGEAN NUMBER NINETY;No;0;L;;;;90;N;;;;; -10119;AEGEAN NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;; -1011A;AEGEAN NUMBER TWO HUNDRED;No;0;L;;;;200;N;;;;; -1011B;AEGEAN NUMBER THREE HUNDRED;No;0;L;;;;300;N;;;;; -1011C;AEGEAN NUMBER FOUR HUNDRED;No;0;L;;;;400;N;;;;; -1011D;AEGEAN NUMBER FIVE HUNDRED;No;0;L;;;;500;N;;;;; -1011E;AEGEAN NUMBER SIX HUNDRED;No;0;L;;;;600;N;;;;; -1011F;AEGEAN NUMBER SEVEN HUNDRED;No;0;L;;;;700;N;;;;; -10120;AEGEAN NUMBER EIGHT HUNDRED;No;0;L;;;;800;N;;;;; -10121;AEGEAN NUMBER NINE HUNDRED;No;0;L;;;;900;N;;;;; -10122;AEGEAN NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;; -10123;AEGEAN NUMBER TWO THOUSAND;No;0;L;;;;2000;N;;;;; -10124;AEGEAN NUMBER THREE THOUSAND;No;0;L;;;;3000;N;;;;; -10125;AEGEAN NUMBER FOUR THOUSAND;No;0;L;;;;4000;N;;;;; -10126;AEGEAN NUMBER FIVE THOUSAND;No;0;L;;;;5000;N;;;;; -10127;AEGEAN NUMBER SIX THOUSAND;No;0;L;;;;6000;N;;;;; -10128;AEGEAN NUMBER SEVEN THOUSAND;No;0;L;;;;7000;N;;;;; -10129;AEGEAN NUMBER EIGHT THOUSAND;No;0;L;;;;8000;N;;;;; -1012A;AEGEAN NUMBER NINE THOUSAND;No;0;L;;;;9000;N;;;;; -1012B;AEGEAN NUMBER TEN THOUSAND;No;0;L;;;;10000;N;;;;; -1012C;AEGEAN NUMBER TWENTY THOUSAND;No;0;L;;;;20000;N;;;;; -1012D;AEGEAN NUMBER THIRTY THOUSAND;No;0;L;;;;30000;N;;;;; -1012E;AEGEAN NUMBER FORTY THOUSAND;No;0;L;;;;40000;N;;;;; -1012F;AEGEAN NUMBER FIFTY THOUSAND;No;0;L;;;;50000;N;;;;; -10130;AEGEAN NUMBER SIXTY THOUSAND;No;0;L;;;;60000;N;;;;; -10131;AEGEAN NUMBER SEVENTY THOUSAND;No;0;L;;;;70000;N;;;;; -10132;AEGEAN NUMBER EIGHTY THOUSAND;No;0;L;;;;80000;N;;;;; -10133;AEGEAN NUMBER NINETY THOUSAND;No;0;L;;;;90000;N;;;;; -10137;AEGEAN WEIGHT BASE UNIT;So;0;L;;;;;N;;;;; -10138;AEGEAN WEIGHT FIRST SUBUNIT;So;0;L;;;;;N;;;;; -10139;AEGEAN WEIGHT SECOND SUBUNIT;So;0;L;;;;;N;;;;; -1013A;AEGEAN WEIGHT THIRD SUBUNIT;So;0;L;;;;;N;;;;; -1013B;AEGEAN WEIGHT FOURTH SUBUNIT;So;0;L;;;;;N;;;;; -1013C;AEGEAN DRY MEASURE FIRST SUBUNIT;So;0;L;;;;;N;;;;; -1013D;AEGEAN LIQUID MEASURE FIRST SUBUNIT;So;0;L;;;;;N;;;;; -1013E;AEGEAN MEASURE SECOND SUBUNIT;So;0;L;;;;;N;;;;; -1013F;AEGEAN MEASURE THIRD SUBUNIT;So;0;L;;;;;N;;;;; -10140;GREEK ACROPHONIC ATTIC ONE QUARTER;Nl;0;ON;;;;1/4;N;;;;; -10141;GREEK ACROPHONIC ATTIC ONE HALF;Nl;0;ON;;;;1/2;N;;;;; -10142;GREEK ACROPHONIC ATTIC ONE DRACHMA;Nl;0;ON;;;;1;N;;;;; -10143;GREEK ACROPHONIC ATTIC FIVE;Nl;0;ON;;;;5;N;;;;; -10144;GREEK ACROPHONIC ATTIC FIFTY;Nl;0;ON;;;;50;N;;;;; -10145;GREEK ACROPHONIC ATTIC FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;; -10146;GREEK ACROPHONIC ATTIC FIVE THOUSAND;Nl;0;ON;;;;5000;N;;;;; -10147;GREEK ACROPHONIC ATTIC FIFTY THOUSAND;Nl;0;ON;;;;50000;N;;;;; -10148;GREEK ACROPHONIC ATTIC FIVE TALENTS;Nl;0;ON;;;;5;N;;;;; -10149;GREEK ACROPHONIC ATTIC TEN TALENTS;Nl;0;ON;;;;10;N;;;;; -1014A;GREEK ACROPHONIC ATTIC FIFTY TALENTS;Nl;0;ON;;;;50;N;;;;; -1014B;GREEK ACROPHONIC ATTIC ONE HUNDRED TALENTS;Nl;0;ON;;;;100;N;;;;; -1014C;GREEK ACROPHONIC ATTIC FIVE HUNDRED TALENTS;Nl;0;ON;;;;500;N;;;;; -1014D;GREEK ACROPHONIC ATTIC ONE THOUSAND TALENTS;Nl;0;ON;;;;1000;N;;;;; -1014E;GREEK ACROPHONIC ATTIC FIVE THOUSAND TALENTS;Nl;0;ON;;;;5000;N;;;;; -1014F;GREEK ACROPHONIC ATTIC FIVE STATERS;Nl;0;ON;;;;5;N;;;;; -10150;GREEK ACROPHONIC ATTIC TEN STATERS;Nl;0;ON;;;;10;N;;;;; -10151;GREEK ACROPHONIC ATTIC FIFTY STATERS;Nl;0;ON;;;;50;N;;;;; -10152;GREEK ACROPHONIC ATTIC ONE HUNDRED STATERS;Nl;0;ON;;;;100;N;;;;; -10153;GREEK ACROPHONIC ATTIC FIVE HUNDRED STATERS;Nl;0;ON;;;;500;N;;;;; -10154;GREEK ACROPHONIC ATTIC ONE THOUSAND STATERS;Nl;0;ON;;;;1000;N;;;;; -10155;GREEK ACROPHONIC ATTIC TEN THOUSAND STATERS;Nl;0;ON;;;;10000;N;;;;; -10156;GREEK ACROPHONIC ATTIC FIFTY THOUSAND STATERS;Nl;0;ON;;;;50000;N;;;;; -10157;GREEK ACROPHONIC ATTIC TEN MNAS;Nl;0;ON;;;;10;N;;;;; -10158;GREEK ACROPHONIC HERAEUM ONE PLETHRON;Nl;0;ON;;;;1;N;;;;; -10159;GREEK ACROPHONIC THESPIAN ONE;Nl;0;ON;;;;1;N;;;;; -1015A;GREEK ACROPHONIC HERMIONIAN ONE;Nl;0;ON;;;;1;N;;;;; -1015B;GREEK ACROPHONIC EPIDAUREAN TWO;Nl;0;ON;;;;2;N;;;;; -1015C;GREEK ACROPHONIC THESPIAN TWO;Nl;0;ON;;;;2;N;;;;; -1015D;GREEK ACROPHONIC CYRENAIC TWO DRACHMAS;Nl;0;ON;;;;2;N;;;;; -1015E;GREEK ACROPHONIC EPIDAUREAN TWO DRACHMAS;Nl;0;ON;;;;2;N;;;;; -1015F;GREEK ACROPHONIC TROEZENIAN FIVE;Nl;0;ON;;;;5;N;;;;; -10160;GREEK ACROPHONIC TROEZENIAN TEN;Nl;0;ON;;;;10;N;;;;; -10161;GREEK ACROPHONIC TROEZENIAN TEN ALTERNATE FORM;Nl;0;ON;;;;10;N;;;;; -10162;GREEK ACROPHONIC HERMIONIAN TEN;Nl;0;ON;;;;10;N;;;;; -10163;GREEK ACROPHONIC MESSENIAN TEN;Nl;0;ON;;;;10;N;;;;; -10164;GREEK ACROPHONIC THESPIAN TEN;Nl;0;ON;;;;10;N;;;;; -10165;GREEK ACROPHONIC THESPIAN THIRTY;Nl;0;ON;;;;30;N;;;;; -10166;GREEK ACROPHONIC TROEZENIAN FIFTY;Nl;0;ON;;;;50;N;;;;; -10167;GREEK ACROPHONIC TROEZENIAN FIFTY ALTERNATE FORM;Nl;0;ON;;;;50;N;;;;; -10168;GREEK ACROPHONIC HERMIONIAN FIFTY;Nl;0;ON;;;;50;N;;;;; -10169;GREEK ACROPHONIC THESPIAN FIFTY;Nl;0;ON;;;;50;N;;;;; -1016A;GREEK ACROPHONIC THESPIAN ONE HUNDRED;Nl;0;ON;;;;100;N;;;;; -1016B;GREEK ACROPHONIC THESPIAN THREE HUNDRED;Nl;0;ON;;;;300;N;;;;; -1016C;GREEK ACROPHONIC EPIDAUREAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;; -1016D;GREEK ACROPHONIC TROEZENIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;; -1016E;GREEK ACROPHONIC THESPIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;; -1016F;GREEK ACROPHONIC CARYSTIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;; -10170;GREEK ACROPHONIC NAXIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;; -10171;GREEK ACROPHONIC THESPIAN ONE THOUSAND;Nl;0;ON;;;;1000;N;;;;; -10172;GREEK ACROPHONIC THESPIAN FIVE THOUSAND;Nl;0;ON;;;;5000;N;;;;; -10173;GREEK ACROPHONIC DELPHIC FIVE MNAS;Nl;0;ON;;;;5;N;;;;; -10174;GREEK ACROPHONIC STRATIAN FIFTY MNAS;Nl;0;ON;;;;50;N;;;;; -10175;GREEK ONE HALF SIGN;No;0;ON;;;;1/2;N;;;;; -10176;GREEK ONE HALF SIGN ALTERNATE FORM;No;0;ON;;;;1/2;N;;;;; -10177;GREEK TWO THIRDS SIGN;No;0;ON;;;;2/3;N;;;;; -10178;GREEK THREE QUARTERS SIGN;No;0;ON;;;;3/4;N;;;;; -10179;GREEK YEAR SIGN;So;0;ON;;;;;N;;;;; -1017A;GREEK TALENT SIGN;So;0;ON;;;;;N;;;;; -1017B;GREEK DRACHMA SIGN;So;0;ON;;;;;N;;;;; -1017C;GREEK OBOL SIGN;So;0;ON;;;;;N;;;;; -1017D;GREEK TWO OBOLS SIGN;So;0;ON;;;;;N;;;;; -1017E;GREEK THREE OBOLS SIGN;So;0;ON;;;;;N;;;;; -1017F;GREEK FOUR OBOLS SIGN;So;0;ON;;;;;N;;;;; -10180;GREEK FIVE OBOLS SIGN;So;0;ON;;;;;N;;;;; -10181;GREEK METRETES SIGN;So;0;ON;;;;;N;;;;; -10182;GREEK KYATHOS BASE SIGN;So;0;ON;;;;;N;;;;; -10183;GREEK LITRA SIGN;So;0;ON;;;;;N;;;;; -10184;GREEK OUNKIA SIGN;So;0;ON;;;;;N;;;;; -10185;GREEK XESTES SIGN;So;0;ON;;;;;N;;;;; -10186;GREEK ARTABE SIGN;So;0;ON;;;;;N;;;;; -10187;GREEK AROURA SIGN;So;0;ON;;;;;N;;;;; -10188;GREEK GRAMMA SIGN;So;0;ON;;;;;N;;;;; -10189;GREEK TRYBLION BASE SIGN;So;0;ON;;;;;N;;;;; -1018A;GREEK ZERO SIGN;No;0;ON;;;;0;N;;;;; -1018B;GREEK ONE QUARTER SIGN;No;0;ON;;;;1/4;N;;;;; -1018C;GREEK SINUSOID SIGN;So;0;ON;;;;;N;;;;; -1018D;GREEK INDICTION SIGN;So;0;L;;;;;N;;;;; -1018E;NOMISMA SIGN;So;0;L;;;;;N;;;;; -10190;ROMAN SEXTANS SIGN;So;0;ON;;;;;N;;;;; -10191;ROMAN UNCIA SIGN;So;0;ON;;;;;N;;;;; -10192;ROMAN SEMUNCIA SIGN;So;0;ON;;;;;N;;;;; -10193;ROMAN SEXTULA SIGN;So;0;ON;;;;;N;;;;; -10194;ROMAN DIMIDIA SEXTULA SIGN;So;0;ON;;;;;N;;;;; -10195;ROMAN SILIQUA SIGN;So;0;ON;;;;;N;;;;; -10196;ROMAN DENARIUS SIGN;So;0;ON;;;;;N;;;;; -10197;ROMAN QUINARIUS SIGN;So;0;ON;;;;;N;;;;; -10198;ROMAN SESTERTIUS SIGN;So;0;ON;;;;;N;;;;; -10199;ROMAN DUPONDIUS SIGN;So;0;ON;;;;;N;;;;; -1019A;ROMAN AS SIGN;So;0;ON;;;;;N;;;;; -1019B;ROMAN CENTURIAL SIGN;So;0;ON;;;;;N;;;;; -1019C;ASCIA SYMBOL;So;0;ON;;;;;N;;;;; -101A0;GREEK SYMBOL TAU RHO;So;0;ON;;;;;N;;;;; -101D0;PHAISTOS DISC SIGN PEDESTRIAN;So;0;L;;;;;N;;;;; -101D1;PHAISTOS DISC SIGN PLUMED HEAD;So;0;L;;;;;N;;;;; -101D2;PHAISTOS DISC SIGN TATTOOED HEAD;So;0;L;;;;;N;;;;; -101D3;PHAISTOS DISC SIGN CAPTIVE;So;0;L;;;;;N;;;;; -101D4;PHAISTOS DISC SIGN CHILD;So;0;L;;;;;N;;;;; -101D5;PHAISTOS DISC SIGN WOMAN;So;0;L;;;;;N;;;;; -101D6;PHAISTOS DISC SIGN HELMET;So;0;L;;;;;N;;;;; -101D7;PHAISTOS DISC SIGN GAUNTLET;So;0;L;;;;;N;;;;; -101D8;PHAISTOS DISC SIGN TIARA;So;0;L;;;;;N;;;;; -101D9;PHAISTOS DISC SIGN ARROW;So;0;L;;;;;N;;;;; -101DA;PHAISTOS DISC SIGN BOW;So;0;L;;;;;N;;;;; -101DB;PHAISTOS DISC SIGN SHIELD;So;0;L;;;;;N;;;;; -101DC;PHAISTOS DISC SIGN CLUB;So;0;L;;;;;N;;;;; -101DD;PHAISTOS DISC SIGN MANACLES;So;0;L;;;;;N;;;;; -101DE;PHAISTOS DISC SIGN MATTOCK;So;0;L;;;;;N;;;;; -101DF;PHAISTOS DISC SIGN SAW;So;0;L;;;;;N;;;;; -101E0;PHAISTOS DISC SIGN LID;So;0;L;;;;;N;;;;; -101E1;PHAISTOS DISC SIGN BOOMERANG;So;0;L;;;;;N;;;;; -101E2;PHAISTOS DISC SIGN CARPENTRY PLANE;So;0;L;;;;;N;;;;; -101E3;PHAISTOS DISC SIGN DOLIUM;So;0;L;;;;;N;;;;; -101E4;PHAISTOS DISC SIGN COMB;So;0;L;;;;;N;;;;; -101E5;PHAISTOS DISC SIGN SLING;So;0;L;;;;;N;;;;; -101E6;PHAISTOS DISC SIGN COLUMN;So;0;L;;;;;N;;;;; -101E7;PHAISTOS DISC SIGN BEEHIVE;So;0;L;;;;;N;;;;; -101E8;PHAISTOS DISC SIGN SHIP;So;0;L;;;;;N;;;;; -101E9;PHAISTOS DISC SIGN HORN;So;0;L;;;;;N;;;;; -101EA;PHAISTOS DISC SIGN HIDE;So;0;L;;;;;N;;;;; -101EB;PHAISTOS DISC SIGN BULLS LEG;So;0;L;;;;;N;;;;; -101EC;PHAISTOS DISC SIGN CAT;So;0;L;;;;;N;;;;; -101ED;PHAISTOS DISC SIGN RAM;So;0;L;;;;;N;;;;; -101EE;PHAISTOS DISC SIGN EAGLE;So;0;L;;;;;N;;;;; -101EF;PHAISTOS DISC SIGN DOVE;So;0;L;;;;;N;;;;; -101F0;PHAISTOS DISC SIGN TUNNY;So;0;L;;;;;N;;;;; -101F1;PHAISTOS DISC SIGN BEE;So;0;L;;;;;N;;;;; -101F2;PHAISTOS DISC SIGN PLANE TREE;So;0;L;;;;;N;;;;; -101F3;PHAISTOS DISC SIGN VINE;So;0;L;;;;;N;;;;; -101F4;PHAISTOS DISC SIGN PAPYRUS;So;0;L;;;;;N;;;;; -101F5;PHAISTOS DISC SIGN ROSETTE;So;0;L;;;;;N;;;;; -101F6;PHAISTOS DISC SIGN LILY;So;0;L;;;;;N;;;;; -101F7;PHAISTOS DISC SIGN OX BACK;So;0;L;;;;;N;;;;; -101F8;PHAISTOS DISC SIGN FLUTE;So;0;L;;;;;N;;;;; -101F9;PHAISTOS DISC SIGN GRATER;So;0;L;;;;;N;;;;; -101FA;PHAISTOS DISC SIGN STRAINER;So;0;L;;;;;N;;;;; -101FB;PHAISTOS DISC SIGN SMALL AXE;So;0;L;;;;;N;;;;; -101FC;PHAISTOS DISC SIGN WAVY BAND;So;0;L;;;;;N;;;;; -101FD;PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE;Mn;220;NSM;;;;;N;;;;; -10280;LYCIAN LETTER A;Lo;0;L;;;;;N;;;;; -10281;LYCIAN LETTER E;Lo;0;L;;;;;N;;;;; -10282;LYCIAN LETTER B;Lo;0;L;;;;;N;;;;; -10283;LYCIAN LETTER BH;Lo;0;L;;;;;N;;;;; -10284;LYCIAN LETTER G;Lo;0;L;;;;;N;;;;; -10285;LYCIAN LETTER D;Lo;0;L;;;;;N;;;;; -10286;LYCIAN LETTER I;Lo;0;L;;;;;N;;;;; -10287;LYCIAN LETTER W;Lo;0;L;;;;;N;;;;; -10288;LYCIAN LETTER Z;Lo;0;L;;;;;N;;;;; -10289;LYCIAN LETTER TH;Lo;0;L;;;;;N;;;;; -1028A;LYCIAN LETTER J;Lo;0;L;;;;;N;;;;; -1028B;LYCIAN LETTER K;Lo;0;L;;;;;N;;;;; -1028C;LYCIAN LETTER Q;Lo;0;L;;;;;N;;;;; -1028D;LYCIAN LETTER L;Lo;0;L;;;;;N;;;;; -1028E;LYCIAN LETTER M;Lo;0;L;;;;;N;;;;; -1028F;LYCIAN LETTER N;Lo;0;L;;;;;N;;;;; -10290;LYCIAN LETTER MM;Lo;0;L;;;;;N;;;;; -10291;LYCIAN LETTER NN;Lo;0;L;;;;;N;;;;; -10292;LYCIAN LETTER U;Lo;0;L;;;;;N;;;;; -10293;LYCIAN LETTER P;Lo;0;L;;;;;N;;;;; -10294;LYCIAN LETTER KK;Lo;0;L;;;;;N;;;;; -10295;LYCIAN LETTER R;Lo;0;L;;;;;N;;;;; -10296;LYCIAN LETTER S;Lo;0;L;;;;;N;;;;; -10297;LYCIAN LETTER T;Lo;0;L;;;;;N;;;;; -10298;LYCIAN LETTER TT;Lo;0;L;;;;;N;;;;; -10299;LYCIAN LETTER AN;Lo;0;L;;;;;N;;;;; -1029A;LYCIAN LETTER EN;Lo;0;L;;;;;N;;;;; -1029B;LYCIAN LETTER H;Lo;0;L;;;;;N;;;;; -1029C;LYCIAN LETTER X;Lo;0;L;;;;;N;;;;; -102A0;CARIAN LETTER A;Lo;0;L;;;;;N;;;;; -102A1;CARIAN LETTER P2;Lo;0;L;;;;;N;;;;; -102A2;CARIAN LETTER D;Lo;0;L;;;;;N;;;;; -102A3;CARIAN LETTER L;Lo;0;L;;;;;N;;;;; -102A4;CARIAN LETTER UUU;Lo;0;L;;;;;N;;;;; -102A5;CARIAN LETTER R;Lo;0;L;;;;;N;;;;; -102A6;CARIAN LETTER LD;Lo;0;L;;;;;N;;;;; -102A7;CARIAN LETTER A2;Lo;0;L;;;;;N;;;;; -102A8;CARIAN LETTER Q;Lo;0;L;;;;;N;;;;; -102A9;CARIAN LETTER B;Lo;0;L;;;;;N;;;;; -102AA;CARIAN LETTER M;Lo;0;L;;;;;N;;;;; -102AB;CARIAN LETTER O;Lo;0;L;;;;;N;;;;; -102AC;CARIAN LETTER D2;Lo;0;L;;;;;N;;;;; -102AD;CARIAN LETTER T;Lo;0;L;;;;;N;;;;; -102AE;CARIAN LETTER SH;Lo;0;L;;;;;N;;;;; -102AF;CARIAN LETTER SH2;Lo;0;L;;;;;N;;;;; -102B0;CARIAN LETTER S;Lo;0;L;;;;;N;;;;; -102B1;CARIAN LETTER C-18;Lo;0;L;;;;;N;;;;; -102B2;CARIAN LETTER U;Lo;0;L;;;;;N;;;;; -102B3;CARIAN LETTER NN;Lo;0;L;;;;;N;;;;; -102B4;CARIAN LETTER X;Lo;0;L;;;;;N;;;;; -102B5;CARIAN LETTER N;Lo;0;L;;;;;N;;;;; -102B6;CARIAN LETTER TT2;Lo;0;L;;;;;N;;;;; -102B7;CARIAN LETTER P;Lo;0;L;;;;;N;;;;; -102B8;CARIAN LETTER SS;Lo;0;L;;;;;N;;;;; -102B9;CARIAN LETTER I;Lo;0;L;;;;;N;;;;; -102BA;CARIAN LETTER E;Lo;0;L;;;;;N;;;;; -102BB;CARIAN LETTER UUUU;Lo;0;L;;;;;N;;;;; -102BC;CARIAN LETTER K;Lo;0;L;;;;;N;;;;; -102BD;CARIAN LETTER K2;Lo;0;L;;;;;N;;;;; -102BE;CARIAN LETTER ND;Lo;0;L;;;;;N;;;;; -102BF;CARIAN LETTER UU;Lo;0;L;;;;;N;;;;; -102C0;CARIAN LETTER G;Lo;0;L;;;;;N;;;;; -102C1;CARIAN LETTER G2;Lo;0;L;;;;;N;;;;; -102C2;CARIAN LETTER ST;Lo;0;L;;;;;N;;;;; -102C3;CARIAN LETTER ST2;Lo;0;L;;;;;N;;;;; -102C4;CARIAN LETTER NG;Lo;0;L;;;;;N;;;;; -102C5;CARIAN LETTER II;Lo;0;L;;;;;N;;;;; -102C6;CARIAN LETTER C-39;Lo;0;L;;;;;N;;;;; -102C7;CARIAN LETTER TT;Lo;0;L;;;;;N;;;;; -102C8;CARIAN LETTER UUU2;Lo;0;L;;;;;N;;;;; -102C9;CARIAN LETTER RR;Lo;0;L;;;;;N;;;;; -102CA;CARIAN LETTER MB;Lo;0;L;;;;;N;;;;; -102CB;CARIAN LETTER MB2;Lo;0;L;;;;;N;;;;; -102CC;CARIAN LETTER MB3;Lo;0;L;;;;;N;;;;; -102CD;CARIAN LETTER MB4;Lo;0;L;;;;;N;;;;; -102CE;CARIAN LETTER LD2;Lo;0;L;;;;;N;;;;; -102CF;CARIAN LETTER E2;Lo;0;L;;;;;N;;;;; -102D0;CARIAN LETTER UUU3;Lo;0;L;;;;;N;;;;; -102E0;COPTIC EPACT THOUSANDS MARK;Mn;220;NSM;;;;;N;;;;; -102E1;COPTIC EPACT DIGIT ONE;No;0;EN;;;;1;N;;;;; -102E2;COPTIC EPACT DIGIT TWO;No;0;EN;;;;2;N;;;;; -102E3;COPTIC EPACT DIGIT THREE;No;0;EN;;;;3;N;;;;; -102E4;COPTIC EPACT DIGIT FOUR;No;0;EN;;;;4;N;;;;; -102E5;COPTIC EPACT DIGIT FIVE;No;0;EN;;;;5;N;;;;; -102E6;COPTIC EPACT DIGIT SIX;No;0;EN;;;;6;N;;;;; -102E7;COPTIC EPACT DIGIT SEVEN;No;0;EN;;;;7;N;;;;; -102E8;COPTIC EPACT DIGIT EIGHT;No;0;EN;;;;8;N;;;;; -102E9;COPTIC EPACT DIGIT NINE;No;0;EN;;;;9;N;;;;; -102EA;COPTIC EPACT NUMBER TEN;No;0;EN;;;;10;N;;;;; -102EB;COPTIC EPACT NUMBER TWENTY;No;0;EN;;;;20;N;;;;; -102EC;COPTIC EPACT NUMBER THIRTY;No;0;EN;;;;30;N;;;;; -102ED;COPTIC EPACT NUMBER FORTY;No;0;EN;;;;40;N;;;;; -102EE;COPTIC EPACT NUMBER FIFTY;No;0;EN;;;;50;N;;;;; -102EF;COPTIC EPACT NUMBER SIXTY;No;0;EN;;;;60;N;;;;; -102F0;COPTIC EPACT NUMBER SEVENTY;No;0;EN;;;;70;N;;;;; -102F1;COPTIC EPACT NUMBER EIGHTY;No;0;EN;;;;80;N;;;;; -102F2;COPTIC EPACT NUMBER NINETY;No;0;EN;;;;90;N;;;;; -102F3;COPTIC EPACT NUMBER ONE HUNDRED;No;0;EN;;;;100;N;;;;; -102F4;COPTIC EPACT NUMBER TWO HUNDRED;No;0;EN;;;;200;N;;;;; -102F5;COPTIC EPACT NUMBER THREE HUNDRED;No;0;EN;;;;300;N;;;;; -102F6;COPTIC EPACT NUMBER FOUR HUNDRED;No;0;EN;;;;400;N;;;;; -102F7;COPTIC EPACT NUMBER FIVE HUNDRED;No;0;EN;;;;500;N;;;;; -102F8;COPTIC EPACT NUMBER SIX HUNDRED;No;0;EN;;;;600;N;;;;; -102F9;COPTIC EPACT NUMBER SEVEN HUNDRED;No;0;EN;;;;700;N;;;;; -102FA;COPTIC EPACT NUMBER EIGHT HUNDRED;No;0;EN;;;;800;N;;;;; -102FB;COPTIC EPACT NUMBER NINE HUNDRED;No;0;EN;;;;900;N;;;;; -10300;OLD ITALIC LETTER A;Lo;0;L;;;;;N;;;;; -10301;OLD ITALIC LETTER BE;Lo;0;L;;;;;N;;;;; -10302;OLD ITALIC LETTER KE;Lo;0;L;;;;;N;;;;; -10303;OLD ITALIC LETTER DE;Lo;0;L;;;;;N;;;;; -10304;OLD ITALIC LETTER E;Lo;0;L;;;;;N;;;;; -10305;OLD ITALIC LETTER VE;Lo;0;L;;;;;N;;;;; -10306;OLD ITALIC LETTER ZE;Lo;0;L;;;;;N;;;;; -10307;OLD ITALIC LETTER HE;Lo;0;L;;;;;N;;;;; -10308;OLD ITALIC LETTER THE;Lo;0;L;;;;;N;;;;; -10309;OLD ITALIC LETTER I;Lo;0;L;;;;;N;;;;; -1030A;OLD ITALIC LETTER KA;Lo;0;L;;;;;N;;;;; -1030B;OLD ITALIC LETTER EL;Lo;0;L;;;;;N;;;;; -1030C;OLD ITALIC LETTER EM;Lo;0;L;;;;;N;;;;; -1030D;OLD ITALIC LETTER EN;Lo;0;L;;;;;N;;;;; -1030E;OLD ITALIC LETTER ESH;Lo;0;L;;;;;N;;;;; -1030F;OLD ITALIC LETTER O;Lo;0;L;;;;;N;;;;; -10310;OLD ITALIC LETTER PE;Lo;0;L;;;;;N;;;;; -10311;OLD ITALIC LETTER SHE;Lo;0;L;;;;;N;;;;; -10312;OLD ITALIC LETTER KU;Lo;0;L;;;;;N;;;;; -10313;OLD ITALIC LETTER ER;Lo;0;L;;;;;N;;;;; -10314;OLD ITALIC LETTER ES;Lo;0;L;;;;;N;;;;; -10315;OLD ITALIC LETTER TE;Lo;0;L;;;;;N;;;;; -10316;OLD ITALIC LETTER U;Lo;0;L;;;;;N;;;;; -10317;OLD ITALIC LETTER EKS;Lo;0;L;;;;;N;;;;; -10318;OLD ITALIC LETTER PHE;Lo;0;L;;;;;N;;;;; -10319;OLD ITALIC LETTER KHE;Lo;0;L;;;;;N;;;;; -1031A;OLD ITALIC LETTER EF;Lo;0;L;;;;;N;;;;; -1031B;OLD ITALIC LETTER ERS;Lo;0;L;;;;;N;;;;; -1031C;OLD ITALIC LETTER CHE;Lo;0;L;;;;;N;;;;; -1031D;OLD ITALIC LETTER II;Lo;0;L;;;;;N;;;;; -1031E;OLD ITALIC LETTER UU;Lo;0;L;;;;;N;;;;; -1031F;OLD ITALIC LETTER ESS;Lo;0;L;;;;;N;;;;; -10320;OLD ITALIC NUMERAL ONE;No;0;L;;;;1;N;;;;; -10321;OLD ITALIC NUMERAL FIVE;No;0;L;;;;5;N;;;;; -10322;OLD ITALIC NUMERAL TEN;No;0;L;;;;10;N;;;;; -10323;OLD ITALIC NUMERAL FIFTY;No;0;L;;;;50;N;;;;; -1032D;OLD ITALIC LETTER YE;Lo;0;L;;;;;N;;;;; -1032E;OLD ITALIC LETTER NORTHERN TSE;Lo;0;L;;;;;N;;;;; -1032F;OLD ITALIC LETTER SOUTHERN TSE;Lo;0;L;;;;;N;;;;; -10330;GOTHIC LETTER AHSA;Lo;0;L;;;;;N;;;;; -10331;GOTHIC LETTER BAIRKAN;Lo;0;L;;;;;N;;;;; -10332;GOTHIC LETTER GIBA;Lo;0;L;;;;;N;;;;; -10333;GOTHIC LETTER DAGS;Lo;0;L;;;;;N;;;;; -10334;GOTHIC LETTER AIHVUS;Lo;0;L;;;;;N;;;;; -10335;GOTHIC LETTER QAIRTHRA;Lo;0;L;;;;;N;;;;; -10336;GOTHIC LETTER IUJA;Lo;0;L;;;;;N;;;;; -10337;GOTHIC LETTER HAGL;Lo;0;L;;;;;N;;;;; -10338;GOTHIC LETTER THIUTH;Lo;0;L;;;;;N;;;;; -10339;GOTHIC LETTER EIS;Lo;0;L;;;;;N;;;;; -1033A;GOTHIC LETTER KUSMA;Lo;0;L;;;;;N;;;;; -1033B;GOTHIC LETTER LAGUS;Lo;0;L;;;;;N;;;;; -1033C;GOTHIC LETTER MANNA;Lo;0;L;;;;;N;;;;; -1033D;GOTHIC LETTER NAUTHS;Lo;0;L;;;;;N;;;;; -1033E;GOTHIC LETTER JER;Lo;0;L;;;;;N;;;;; -1033F;GOTHIC LETTER URUS;Lo;0;L;;;;;N;;;;; -10340;GOTHIC LETTER PAIRTHRA;Lo;0;L;;;;;N;;;;; -10341;GOTHIC LETTER NINETY;Nl;0;L;;;;90;N;;;;; -10342;GOTHIC LETTER RAIDA;Lo;0;L;;;;;N;;;;; -10343;GOTHIC LETTER SAUIL;Lo;0;L;;;;;N;;;;; -10344;GOTHIC LETTER TEIWS;Lo;0;L;;;;;N;;;;; -10345;GOTHIC LETTER WINJA;Lo;0;L;;;;;N;;;;; -10346;GOTHIC LETTER FAIHU;Lo;0;L;;;;;N;;;;; -10347;GOTHIC LETTER IGGWS;Lo;0;L;;;;;N;;;;; -10348;GOTHIC LETTER HWAIR;Lo;0;L;;;;;N;;;;; -10349;GOTHIC LETTER OTHAL;Lo;0;L;;;;;N;;;;; -1034A;GOTHIC LETTER NINE HUNDRED;Nl;0;L;;;;900;N;;;;; -10350;OLD PERMIC LETTER AN;Lo;0;L;;;;;N;;;;; -10351;OLD PERMIC LETTER BUR;Lo;0;L;;;;;N;;;;; -10352;OLD PERMIC LETTER GAI;Lo;0;L;;;;;N;;;;; -10353;OLD PERMIC LETTER DOI;Lo;0;L;;;;;N;;;;; -10354;OLD PERMIC LETTER E;Lo;0;L;;;;;N;;;;; -10355;OLD PERMIC LETTER ZHOI;Lo;0;L;;;;;N;;;;; -10356;OLD PERMIC LETTER DZHOI;Lo;0;L;;;;;N;;;;; -10357;OLD PERMIC LETTER ZATA;Lo;0;L;;;;;N;;;;; -10358;OLD PERMIC LETTER DZITA;Lo;0;L;;;;;N;;;;; -10359;OLD PERMIC LETTER I;Lo;0;L;;;;;N;;;;; -1035A;OLD PERMIC LETTER KOKE;Lo;0;L;;;;;N;;;;; -1035B;OLD PERMIC LETTER LEI;Lo;0;L;;;;;N;;;;; -1035C;OLD PERMIC LETTER MENOE;Lo;0;L;;;;;N;;;;; -1035D;OLD PERMIC LETTER NENOE;Lo;0;L;;;;;N;;;;; -1035E;OLD PERMIC LETTER VOOI;Lo;0;L;;;;;N;;;;; -1035F;OLD PERMIC LETTER PEEI;Lo;0;L;;;;;N;;;;; -10360;OLD PERMIC LETTER REI;Lo;0;L;;;;;N;;;;; -10361;OLD PERMIC LETTER SII;Lo;0;L;;;;;N;;;;; -10362;OLD PERMIC LETTER TAI;Lo;0;L;;;;;N;;;;; -10363;OLD PERMIC LETTER U;Lo;0;L;;;;;N;;;;; -10364;OLD PERMIC LETTER CHERY;Lo;0;L;;;;;N;;;;; -10365;OLD PERMIC LETTER SHOOI;Lo;0;L;;;;;N;;;;; -10366;OLD PERMIC LETTER SHCHOOI;Lo;0;L;;;;;N;;;;; -10367;OLD PERMIC LETTER YRY;Lo;0;L;;;;;N;;;;; -10368;OLD PERMIC LETTER YERU;Lo;0;L;;;;;N;;;;; -10369;OLD PERMIC LETTER O;Lo;0;L;;;;;N;;;;; -1036A;OLD PERMIC LETTER OO;Lo;0;L;;;;;N;;;;; -1036B;OLD PERMIC LETTER EF;Lo;0;L;;;;;N;;;;; -1036C;OLD PERMIC LETTER HA;Lo;0;L;;;;;N;;;;; -1036D;OLD PERMIC LETTER TSIU;Lo;0;L;;;;;N;;;;; -1036E;OLD PERMIC LETTER VER;Lo;0;L;;;;;N;;;;; -1036F;OLD PERMIC LETTER YER;Lo;0;L;;;;;N;;;;; -10370;OLD PERMIC LETTER YERI;Lo;0;L;;;;;N;;;;; -10371;OLD PERMIC LETTER YAT;Lo;0;L;;;;;N;;;;; -10372;OLD PERMIC LETTER IE;Lo;0;L;;;;;N;;;;; -10373;OLD PERMIC LETTER YU;Lo;0;L;;;;;N;;;;; -10374;OLD PERMIC LETTER YA;Lo;0;L;;;;;N;;;;; -10375;OLD PERMIC LETTER IA;Lo;0;L;;;;;N;;;;; -10376;COMBINING OLD PERMIC LETTER AN;Mn;230;NSM;;;;;N;;;;; -10377;COMBINING OLD PERMIC LETTER DOI;Mn;230;NSM;;;;;N;;;;; -10378;COMBINING OLD PERMIC LETTER ZATA;Mn;230;NSM;;;;;N;;;;; -10379;COMBINING OLD PERMIC LETTER NENOE;Mn;230;NSM;;;;;N;;;;; -1037A;COMBINING OLD PERMIC LETTER SII;Mn;230;NSM;;;;;N;;;;; -10380;UGARITIC LETTER ALPA;Lo;0;L;;;;;N;;;;; -10381;UGARITIC LETTER BETA;Lo;0;L;;;;;N;;;;; -10382;UGARITIC LETTER GAMLA;Lo;0;L;;;;;N;;;;; -10383;UGARITIC LETTER KHA;Lo;0;L;;;;;N;;;;; -10384;UGARITIC LETTER DELTA;Lo;0;L;;;;;N;;;;; -10385;UGARITIC LETTER HO;Lo;0;L;;;;;N;;;;; -10386;UGARITIC LETTER WO;Lo;0;L;;;;;N;;;;; -10387;UGARITIC LETTER ZETA;Lo;0;L;;;;;N;;;;; -10388;UGARITIC LETTER HOTA;Lo;0;L;;;;;N;;;;; -10389;UGARITIC LETTER TET;Lo;0;L;;;;;N;;;;; -1038A;UGARITIC LETTER YOD;Lo;0;L;;;;;N;;;;; -1038B;UGARITIC LETTER KAF;Lo;0;L;;;;;N;;;;; -1038C;UGARITIC LETTER SHIN;Lo;0;L;;;;;N;;;;; -1038D;UGARITIC LETTER LAMDA;Lo;0;L;;;;;N;;;;; -1038E;UGARITIC LETTER MEM;Lo;0;L;;;;;N;;;;; -1038F;UGARITIC LETTER DHAL;Lo;0;L;;;;;N;;;;; -10390;UGARITIC LETTER NUN;Lo;0;L;;;;;N;;;;; -10391;UGARITIC LETTER ZU;Lo;0;L;;;;;N;;;;; -10392;UGARITIC LETTER SAMKA;Lo;0;L;;;;;N;;;;; -10393;UGARITIC LETTER AIN;Lo;0;L;;;;;N;;;;; -10394;UGARITIC LETTER PU;Lo;0;L;;;;;N;;;;; -10395;UGARITIC LETTER SADE;Lo;0;L;;;;;N;;;;; -10396;UGARITIC LETTER QOPA;Lo;0;L;;;;;N;;;;; -10397;UGARITIC LETTER RASHA;Lo;0;L;;;;;N;;;;; -10398;UGARITIC LETTER THANNA;Lo;0;L;;;;;N;;;;; -10399;UGARITIC LETTER GHAIN;Lo;0;L;;;;;N;;;;; -1039A;UGARITIC LETTER TO;Lo;0;L;;;;;N;;;;; -1039B;UGARITIC LETTER I;Lo;0;L;;;;;N;;;;; -1039C;UGARITIC LETTER U;Lo;0;L;;;;;N;;;;; -1039D;UGARITIC LETTER SSU;Lo;0;L;;;;;N;;;;; -1039F;UGARITIC WORD DIVIDER;Po;0;L;;;;;N;;;;; -103A0;OLD PERSIAN SIGN A;Lo;0;L;;;;;N;;;;; -103A1;OLD PERSIAN SIGN I;Lo;0;L;;;;;N;;;;; -103A2;OLD PERSIAN SIGN U;Lo;0;L;;;;;N;;;;; -103A3;OLD PERSIAN SIGN KA;Lo;0;L;;;;;N;;;;; -103A4;OLD PERSIAN SIGN KU;Lo;0;L;;;;;N;;;;; -103A5;OLD PERSIAN SIGN GA;Lo;0;L;;;;;N;;;;; -103A6;OLD PERSIAN SIGN GU;Lo;0;L;;;;;N;;;;; -103A7;OLD PERSIAN SIGN XA;Lo;0;L;;;;;N;;;;; -103A8;OLD PERSIAN SIGN CA;Lo;0;L;;;;;N;;;;; -103A9;OLD PERSIAN SIGN JA;Lo;0;L;;;;;N;;;;; -103AA;OLD PERSIAN SIGN JI;Lo;0;L;;;;;N;;;;; -103AB;OLD PERSIAN SIGN TA;Lo;0;L;;;;;N;;;;; -103AC;OLD PERSIAN SIGN TU;Lo;0;L;;;;;N;;;;; -103AD;OLD PERSIAN SIGN DA;Lo;0;L;;;;;N;;;;; -103AE;OLD PERSIAN SIGN DI;Lo;0;L;;;;;N;;;;; -103AF;OLD PERSIAN SIGN DU;Lo;0;L;;;;;N;;;;; -103B0;OLD PERSIAN SIGN THA;Lo;0;L;;;;;N;;;;; -103B1;OLD PERSIAN SIGN PA;Lo;0;L;;;;;N;;;;; -103B2;OLD PERSIAN SIGN BA;Lo;0;L;;;;;N;;;;; -103B3;OLD PERSIAN SIGN FA;Lo;0;L;;;;;N;;;;; -103B4;OLD PERSIAN SIGN NA;Lo;0;L;;;;;N;;;;; -103B5;OLD PERSIAN SIGN NU;Lo;0;L;;;;;N;;;;; -103B6;OLD PERSIAN SIGN MA;Lo;0;L;;;;;N;;;;; -103B7;OLD PERSIAN SIGN MI;Lo;0;L;;;;;N;;;;; -103B8;OLD PERSIAN SIGN MU;Lo;0;L;;;;;N;;;;; -103B9;OLD PERSIAN SIGN YA;Lo;0;L;;;;;N;;;;; -103BA;OLD PERSIAN SIGN VA;Lo;0;L;;;;;N;;;;; -103BB;OLD PERSIAN SIGN VI;Lo;0;L;;;;;N;;;;; -103BC;OLD PERSIAN SIGN RA;Lo;0;L;;;;;N;;;;; -103BD;OLD PERSIAN SIGN RU;Lo;0;L;;;;;N;;;;; -103BE;OLD PERSIAN SIGN LA;Lo;0;L;;;;;N;;;;; -103BF;OLD PERSIAN SIGN SA;Lo;0;L;;;;;N;;;;; -103C0;OLD PERSIAN SIGN ZA;Lo;0;L;;;;;N;;;;; -103C1;OLD PERSIAN SIGN SHA;Lo;0;L;;;;;N;;;;; -103C2;OLD PERSIAN SIGN SSA;Lo;0;L;;;;;N;;;;; -103C3;OLD PERSIAN SIGN HA;Lo;0;L;;;;;N;;;;; -103C8;OLD PERSIAN SIGN AURAMAZDAA;Lo;0;L;;;;;N;;;;; -103C9;OLD PERSIAN SIGN AURAMAZDAA-2;Lo;0;L;;;;;N;;;;; -103CA;OLD PERSIAN SIGN AURAMAZDAAHA;Lo;0;L;;;;;N;;;;; -103CB;OLD PERSIAN SIGN XSHAAYATHIYA;Lo;0;L;;;;;N;;;;; -103CC;OLD PERSIAN SIGN DAHYAAUSH;Lo;0;L;;;;;N;;;;; -103CD;OLD PERSIAN SIGN DAHYAAUSH-2;Lo;0;L;;;;;N;;;;; -103CE;OLD PERSIAN SIGN BAGA;Lo;0;L;;;;;N;;;;; -103CF;OLD PERSIAN SIGN BUUMISH;Lo;0;L;;;;;N;;;;; -103D0;OLD PERSIAN WORD DIVIDER;Po;0;L;;;;;N;;;;; -103D1;OLD PERSIAN NUMBER ONE;Nl;0;L;;;;1;N;;;;; -103D2;OLD PERSIAN NUMBER TWO;Nl;0;L;;;;2;N;;;;; -103D3;OLD PERSIAN NUMBER TEN;Nl;0;L;;;;10;N;;;;; -103D4;OLD PERSIAN NUMBER TWENTY;Nl;0;L;;;;20;N;;;;; -103D5;OLD PERSIAN NUMBER HUNDRED;Nl;0;L;;;;100;N;;;;; -10400;DESERET CAPITAL LETTER LONG I;Lu;0;L;;;;;N;;;;10428; -10401;DESERET CAPITAL LETTER LONG E;Lu;0;L;;;;;N;;;;10429; -10402;DESERET CAPITAL LETTER LONG A;Lu;0;L;;;;;N;;;;1042A; -10403;DESERET CAPITAL LETTER LONG AH;Lu;0;L;;;;;N;;;;1042B; -10404;DESERET CAPITAL LETTER LONG O;Lu;0;L;;;;;N;;;;1042C; -10405;DESERET CAPITAL LETTER LONG OO;Lu;0;L;;;;;N;;;;1042D; -10406;DESERET CAPITAL LETTER SHORT I;Lu;0;L;;;;;N;;;;1042E; -10407;DESERET CAPITAL LETTER SHORT E;Lu;0;L;;;;;N;;;;1042F; -10408;DESERET CAPITAL LETTER SHORT A;Lu;0;L;;;;;N;;;;10430; -10409;DESERET CAPITAL LETTER SHORT AH;Lu;0;L;;;;;N;;;;10431; -1040A;DESERET CAPITAL LETTER SHORT O;Lu;0;L;;;;;N;;;;10432; -1040B;DESERET CAPITAL LETTER SHORT OO;Lu;0;L;;;;;N;;;;10433; -1040C;DESERET CAPITAL LETTER AY;Lu;0;L;;;;;N;;;;10434; -1040D;DESERET CAPITAL LETTER OW;Lu;0;L;;;;;N;;;;10435; -1040E;DESERET CAPITAL LETTER WU;Lu;0;L;;;;;N;;;;10436; -1040F;DESERET CAPITAL LETTER YEE;Lu;0;L;;;;;N;;;;10437; -10410;DESERET CAPITAL LETTER H;Lu;0;L;;;;;N;;;;10438; -10411;DESERET CAPITAL LETTER PEE;Lu;0;L;;;;;N;;;;10439; -10412;DESERET CAPITAL LETTER BEE;Lu;0;L;;;;;N;;;;1043A; -10413;DESERET CAPITAL LETTER TEE;Lu;0;L;;;;;N;;;;1043B; -10414;DESERET CAPITAL LETTER DEE;Lu;0;L;;;;;N;;;;1043C; -10415;DESERET CAPITAL LETTER CHEE;Lu;0;L;;;;;N;;;;1043D; -10416;DESERET CAPITAL LETTER JEE;Lu;0;L;;;;;N;;;;1043E; -10417;DESERET CAPITAL LETTER KAY;Lu;0;L;;;;;N;;;;1043F; -10418;DESERET CAPITAL LETTER GAY;Lu;0;L;;;;;N;;;;10440; -10419;DESERET CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;10441; -1041A;DESERET CAPITAL LETTER VEE;Lu;0;L;;;;;N;;;;10442; -1041B;DESERET CAPITAL LETTER ETH;Lu;0;L;;;;;N;;;;10443; -1041C;DESERET CAPITAL LETTER THEE;Lu;0;L;;;;;N;;;;10444; -1041D;DESERET CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;10445; -1041E;DESERET CAPITAL LETTER ZEE;Lu;0;L;;;;;N;;;;10446; -1041F;DESERET CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;10447; -10420;DESERET CAPITAL LETTER ZHEE;Lu;0;L;;;;;N;;;;10448; -10421;DESERET CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;10449; -10422;DESERET CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;1044A; -10423;DESERET CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;1044B; -10424;DESERET CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;1044C; -10425;DESERET CAPITAL LETTER ENG;Lu;0;L;;;;;N;;;;1044D; -10426;DESERET CAPITAL LETTER OI;Lu;0;L;;;;;N;;;;1044E; -10427;DESERET CAPITAL LETTER EW;Lu;0;L;;;;;N;;;;1044F; -10428;DESERET SMALL LETTER LONG I;Ll;0;L;;;;;N;;;10400;;10400 -10429;DESERET SMALL LETTER LONG E;Ll;0;L;;;;;N;;;10401;;10401 -1042A;DESERET SMALL LETTER LONG A;Ll;0;L;;;;;N;;;10402;;10402 -1042B;DESERET SMALL LETTER LONG AH;Ll;0;L;;;;;N;;;10403;;10403 -1042C;DESERET SMALL LETTER LONG O;Ll;0;L;;;;;N;;;10404;;10404 -1042D;DESERET SMALL LETTER LONG OO;Ll;0;L;;;;;N;;;10405;;10405 -1042E;DESERET SMALL LETTER SHORT I;Ll;0;L;;;;;N;;;10406;;10406 -1042F;DESERET SMALL LETTER SHORT E;Ll;0;L;;;;;N;;;10407;;10407 -10430;DESERET SMALL LETTER SHORT A;Ll;0;L;;;;;N;;;10408;;10408 -10431;DESERET SMALL LETTER SHORT AH;Ll;0;L;;;;;N;;;10409;;10409 -10432;DESERET SMALL LETTER SHORT O;Ll;0;L;;;;;N;;;1040A;;1040A -10433;DESERET SMALL LETTER SHORT OO;Ll;0;L;;;;;N;;;1040B;;1040B -10434;DESERET SMALL LETTER AY;Ll;0;L;;;;;N;;;1040C;;1040C -10435;DESERET SMALL LETTER OW;Ll;0;L;;;;;N;;;1040D;;1040D -10436;DESERET SMALL LETTER WU;Ll;0;L;;;;;N;;;1040E;;1040E -10437;DESERET SMALL LETTER YEE;Ll;0;L;;;;;N;;;1040F;;1040F -10438;DESERET SMALL LETTER H;Ll;0;L;;;;;N;;;10410;;10410 -10439;DESERET SMALL LETTER PEE;Ll;0;L;;;;;N;;;10411;;10411 -1043A;DESERET SMALL LETTER BEE;Ll;0;L;;;;;N;;;10412;;10412 -1043B;DESERET SMALL LETTER TEE;Ll;0;L;;;;;N;;;10413;;10413 -1043C;DESERET SMALL LETTER DEE;Ll;0;L;;;;;N;;;10414;;10414 -1043D;DESERET SMALL LETTER CHEE;Ll;0;L;;;;;N;;;10415;;10415 -1043E;DESERET SMALL LETTER JEE;Ll;0;L;;;;;N;;;10416;;10416 -1043F;DESERET SMALL LETTER KAY;Ll;0;L;;;;;N;;;10417;;10417 -10440;DESERET SMALL LETTER GAY;Ll;0;L;;;;;N;;;10418;;10418 -10441;DESERET SMALL LETTER EF;Ll;0;L;;;;;N;;;10419;;10419 -10442;DESERET SMALL LETTER VEE;Ll;0;L;;;;;N;;;1041A;;1041A -10443;DESERET SMALL LETTER ETH;Ll;0;L;;;;;N;;;1041B;;1041B -10444;DESERET SMALL LETTER THEE;Ll;0;L;;;;;N;;;1041C;;1041C -10445;DESERET SMALL LETTER ES;Ll;0;L;;;;;N;;;1041D;;1041D -10446;DESERET SMALL LETTER ZEE;Ll;0;L;;;;;N;;;1041E;;1041E -10447;DESERET SMALL LETTER ESH;Ll;0;L;;;;;N;;;1041F;;1041F -10448;DESERET SMALL LETTER ZHEE;Ll;0;L;;;;;N;;;10420;;10420 -10449;DESERET SMALL LETTER ER;Ll;0;L;;;;;N;;;10421;;10421 -1044A;DESERET SMALL LETTER EL;Ll;0;L;;;;;N;;;10422;;10422 -1044B;DESERET SMALL LETTER EM;Ll;0;L;;;;;N;;;10423;;10423 -1044C;DESERET SMALL LETTER EN;Ll;0;L;;;;;N;;;10424;;10424 -1044D;DESERET SMALL LETTER ENG;Ll;0;L;;;;;N;;;10425;;10425 -1044E;DESERET SMALL LETTER OI;Ll;0;L;;;;;N;;;10426;;10426 -1044F;DESERET SMALL LETTER EW;Ll;0;L;;;;;N;;;10427;;10427 -10450;SHAVIAN LETTER PEEP;Lo;0;L;;;;;N;;;;; -10451;SHAVIAN LETTER TOT;Lo;0;L;;;;;N;;;;; -10452;SHAVIAN LETTER KICK;Lo;0;L;;;;;N;;;;; -10453;SHAVIAN LETTER FEE;Lo;0;L;;;;;N;;;;; -10454;SHAVIAN LETTER THIGH;Lo;0;L;;;;;N;;;;; -10455;SHAVIAN LETTER SO;Lo;0;L;;;;;N;;;;; -10456;SHAVIAN LETTER SURE;Lo;0;L;;;;;N;;;;; -10457;SHAVIAN LETTER CHURCH;Lo;0;L;;;;;N;;;;; -10458;SHAVIAN LETTER YEA;Lo;0;L;;;;;N;;;;; -10459;SHAVIAN LETTER HUNG;Lo;0;L;;;;;N;;;;; -1045A;SHAVIAN LETTER BIB;Lo;0;L;;;;;N;;;;; -1045B;SHAVIAN LETTER DEAD;Lo;0;L;;;;;N;;;;; -1045C;SHAVIAN LETTER GAG;Lo;0;L;;;;;N;;;;; -1045D;SHAVIAN LETTER VOW;Lo;0;L;;;;;N;;;;; -1045E;SHAVIAN LETTER THEY;Lo;0;L;;;;;N;;;;; -1045F;SHAVIAN LETTER ZOO;Lo;0;L;;;;;N;;;;; -10460;SHAVIAN LETTER MEASURE;Lo;0;L;;;;;N;;;;; -10461;SHAVIAN LETTER JUDGE;Lo;0;L;;;;;N;;;;; -10462;SHAVIAN LETTER WOE;Lo;0;L;;;;;N;;;;; -10463;SHAVIAN LETTER HA-HA;Lo;0;L;;;;;N;;;;; -10464;SHAVIAN LETTER LOLL;Lo;0;L;;;;;N;;;;; -10465;SHAVIAN LETTER MIME;Lo;0;L;;;;;N;;;;; -10466;SHAVIAN LETTER IF;Lo;0;L;;;;;N;;;;; -10467;SHAVIAN LETTER EGG;Lo;0;L;;;;;N;;;;; -10468;SHAVIAN LETTER ASH;Lo;0;L;;;;;N;;;;; -10469;SHAVIAN LETTER ADO;Lo;0;L;;;;;N;;;;; -1046A;SHAVIAN LETTER ON;Lo;0;L;;;;;N;;;;; -1046B;SHAVIAN LETTER WOOL;Lo;0;L;;;;;N;;;;; -1046C;SHAVIAN LETTER OUT;Lo;0;L;;;;;N;;;;; -1046D;SHAVIAN LETTER AH;Lo;0;L;;;;;N;;;;; -1046E;SHAVIAN LETTER ROAR;Lo;0;L;;;;;N;;;;; -1046F;SHAVIAN LETTER NUN;Lo;0;L;;;;;N;;;;; -10470;SHAVIAN LETTER EAT;Lo;0;L;;;;;N;;;;; -10471;SHAVIAN LETTER AGE;Lo;0;L;;;;;N;;;;; -10472;SHAVIAN LETTER ICE;Lo;0;L;;;;;N;;;;; -10473;SHAVIAN LETTER UP;Lo;0;L;;;;;N;;;;; -10474;SHAVIAN LETTER OAK;Lo;0;L;;;;;N;;;;; -10475;SHAVIAN LETTER OOZE;Lo;0;L;;;;;N;;;;; -10476;SHAVIAN LETTER OIL;Lo;0;L;;;;;N;;;;; -10477;SHAVIAN LETTER AWE;Lo;0;L;;;;;N;;;;; -10478;SHAVIAN LETTER ARE;Lo;0;L;;;;;N;;;;; -10479;SHAVIAN LETTER OR;Lo;0;L;;;;;N;;;;; -1047A;SHAVIAN LETTER AIR;Lo;0;L;;;;;N;;;;; -1047B;SHAVIAN LETTER ERR;Lo;0;L;;;;;N;;;;; -1047C;SHAVIAN LETTER ARRAY;Lo;0;L;;;;;N;;;;; -1047D;SHAVIAN LETTER EAR;Lo;0;L;;;;;N;;;;; -1047E;SHAVIAN LETTER IAN;Lo;0;L;;;;;N;;;;; -1047F;SHAVIAN LETTER YEW;Lo;0;L;;;;;N;;;;; -10480;OSMANYA LETTER ALEF;Lo;0;L;;;;;N;;;;; -10481;OSMANYA LETTER BA;Lo;0;L;;;;;N;;;;; -10482;OSMANYA LETTER TA;Lo;0;L;;;;;N;;;;; -10483;OSMANYA LETTER JA;Lo;0;L;;;;;N;;;;; -10484;OSMANYA LETTER XA;Lo;0;L;;;;;N;;;;; -10485;OSMANYA LETTER KHA;Lo;0;L;;;;;N;;;;; -10486;OSMANYA LETTER DEEL;Lo;0;L;;;;;N;;;;; -10487;OSMANYA LETTER RA;Lo;0;L;;;;;N;;;;; -10488;OSMANYA LETTER SA;Lo;0;L;;;;;N;;;;; -10489;OSMANYA LETTER SHIIN;Lo;0;L;;;;;N;;;;; -1048A;OSMANYA LETTER DHA;Lo;0;L;;;;;N;;;;; -1048B;OSMANYA LETTER CAYN;Lo;0;L;;;;;N;;;;; -1048C;OSMANYA LETTER GA;Lo;0;L;;;;;N;;;;; -1048D;OSMANYA LETTER FA;Lo;0;L;;;;;N;;;;; -1048E;OSMANYA LETTER QAAF;Lo;0;L;;;;;N;;;;; -1048F;OSMANYA LETTER KAAF;Lo;0;L;;;;;N;;;;; -10490;OSMANYA LETTER LAAN;Lo;0;L;;;;;N;;;;; -10491;OSMANYA LETTER MIIN;Lo;0;L;;;;;N;;;;; -10492;OSMANYA LETTER NUUN;Lo;0;L;;;;;N;;;;; -10493;OSMANYA LETTER WAW;Lo;0;L;;;;;N;;;;; -10494;OSMANYA LETTER HA;Lo;0;L;;;;;N;;;;; -10495;OSMANYA LETTER YA;Lo;0;L;;;;;N;;;;; -10496;OSMANYA LETTER A;Lo;0;L;;;;;N;;;;; -10497;OSMANYA LETTER E;Lo;0;L;;;;;N;;;;; -10498;OSMANYA LETTER I;Lo;0;L;;;;;N;;;;; -10499;OSMANYA LETTER O;Lo;0;L;;;;;N;;;;; -1049A;OSMANYA LETTER U;Lo;0;L;;;;;N;;;;; -1049B;OSMANYA LETTER AA;Lo;0;L;;;;;N;;;;; -1049C;OSMANYA LETTER EE;Lo;0;L;;;;;N;;;;; -1049D;OSMANYA LETTER OO;Lo;0;L;;;;;N;;;;; -104A0;OSMANYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -104A1;OSMANYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -104A2;OSMANYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -104A3;OSMANYA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -104A4;OSMANYA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -104A5;OSMANYA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -104A6;OSMANYA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -104A7;OSMANYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -104A8;OSMANYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -104A9;OSMANYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -104B0;OSAGE CAPITAL LETTER A;Lu;0;L;;;;;N;;;;104D8; -104B1;OSAGE CAPITAL LETTER AI;Lu;0;L;;;;;N;;;;104D9; -104B2;OSAGE CAPITAL LETTER AIN;Lu;0;L;;;;;N;;;;104DA; -104B3;OSAGE CAPITAL LETTER AH;Lu;0;L;;;;;N;;;;104DB; -104B4;OSAGE CAPITAL LETTER BRA;Lu;0;L;;;;;N;;;;104DC; -104B5;OSAGE CAPITAL LETTER CHA;Lu;0;L;;;;;N;;;;104DD; -104B6;OSAGE CAPITAL LETTER EHCHA;Lu;0;L;;;;;N;;;;104DE; -104B7;OSAGE CAPITAL LETTER E;Lu;0;L;;;;;N;;;;104DF; -104B8;OSAGE CAPITAL LETTER EIN;Lu;0;L;;;;;N;;;;104E0; -104B9;OSAGE CAPITAL LETTER HA;Lu;0;L;;;;;N;;;;104E1; -104BA;OSAGE CAPITAL LETTER HYA;Lu;0;L;;;;;N;;;;104E2; -104BB;OSAGE CAPITAL LETTER I;Lu;0;L;;;;;N;;;;104E3; -104BC;OSAGE CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;104E4; -104BD;OSAGE CAPITAL LETTER EHKA;Lu;0;L;;;;;N;;;;104E5; -104BE;OSAGE CAPITAL LETTER KYA;Lu;0;L;;;;;N;;;;104E6; -104BF;OSAGE CAPITAL LETTER LA;Lu;0;L;;;;;N;;;;104E7; -104C0;OSAGE CAPITAL LETTER MA;Lu;0;L;;;;;N;;;;104E8; -104C1;OSAGE CAPITAL LETTER NA;Lu;0;L;;;;;N;;;;104E9; -104C2;OSAGE CAPITAL LETTER O;Lu;0;L;;;;;N;;;;104EA; -104C3;OSAGE CAPITAL LETTER OIN;Lu;0;L;;;;;N;;;;104EB; -104C4;OSAGE CAPITAL LETTER PA;Lu;0;L;;;;;N;;;;104EC; -104C5;OSAGE CAPITAL LETTER EHPA;Lu;0;L;;;;;N;;;;104ED; -104C6;OSAGE CAPITAL LETTER SA;Lu;0;L;;;;;N;;;;104EE; -104C7;OSAGE CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;104EF; -104C8;OSAGE CAPITAL LETTER TA;Lu;0;L;;;;;N;;;;104F0; -104C9;OSAGE CAPITAL LETTER EHTA;Lu;0;L;;;;;N;;;;104F1; -104CA;OSAGE CAPITAL LETTER TSA;Lu;0;L;;;;;N;;;;104F2; -104CB;OSAGE CAPITAL LETTER EHTSA;Lu;0;L;;;;;N;;;;104F3; -104CC;OSAGE CAPITAL LETTER TSHA;Lu;0;L;;;;;N;;;;104F4; -104CD;OSAGE CAPITAL LETTER DHA;Lu;0;L;;;;;N;;;;104F5; -104CE;OSAGE CAPITAL LETTER U;Lu;0;L;;;;;N;;;;104F6; -104CF;OSAGE CAPITAL LETTER WA;Lu;0;L;;;;;N;;;;104F7; -104D0;OSAGE CAPITAL LETTER KHA;Lu;0;L;;;;;N;;;;104F8; -104D1;OSAGE CAPITAL LETTER GHA;Lu;0;L;;;;;N;;;;104F9; -104D2;OSAGE CAPITAL LETTER ZA;Lu;0;L;;;;;N;;;;104FA; -104D3;OSAGE CAPITAL LETTER ZHA;Lu;0;L;;;;;N;;;;104FB; -104D8;OSAGE SMALL LETTER A;Ll;0;L;;;;;N;;;104B0;;104B0 -104D9;OSAGE SMALL LETTER AI;Ll;0;L;;;;;N;;;104B1;;104B1 -104DA;OSAGE SMALL LETTER AIN;Ll;0;L;;;;;N;;;104B2;;104B2 -104DB;OSAGE SMALL LETTER AH;Ll;0;L;;;;;N;;;104B3;;104B3 -104DC;OSAGE SMALL LETTER BRA;Ll;0;L;;;;;N;;;104B4;;104B4 -104DD;OSAGE SMALL LETTER CHA;Ll;0;L;;;;;N;;;104B5;;104B5 -104DE;OSAGE SMALL LETTER EHCHA;Ll;0;L;;;;;N;;;104B6;;104B6 -104DF;OSAGE SMALL LETTER E;Ll;0;L;;;;;N;;;104B7;;104B7 -104E0;OSAGE SMALL LETTER EIN;Ll;0;L;;;;;N;;;104B8;;104B8 -104E1;OSAGE SMALL LETTER HA;Ll;0;L;;;;;N;;;104B9;;104B9 -104E2;OSAGE SMALL LETTER HYA;Ll;0;L;;;;;N;;;104BA;;104BA -104E3;OSAGE SMALL LETTER I;Ll;0;L;;;;;N;;;104BB;;104BB -104E4;OSAGE SMALL LETTER KA;Ll;0;L;;;;;N;;;104BC;;104BC -104E5;OSAGE SMALL LETTER EHKA;Ll;0;L;;;;;N;;;104BD;;104BD -104E6;OSAGE SMALL LETTER KYA;Ll;0;L;;;;;N;;;104BE;;104BE -104E7;OSAGE SMALL LETTER LA;Ll;0;L;;;;;N;;;104BF;;104BF -104E8;OSAGE SMALL LETTER MA;Ll;0;L;;;;;N;;;104C0;;104C0 -104E9;OSAGE SMALL LETTER NA;Ll;0;L;;;;;N;;;104C1;;104C1 -104EA;OSAGE SMALL LETTER O;Ll;0;L;;;;;N;;;104C2;;104C2 -104EB;OSAGE SMALL LETTER OIN;Ll;0;L;;;;;N;;;104C3;;104C3 -104EC;OSAGE SMALL LETTER PA;Ll;0;L;;;;;N;;;104C4;;104C4 -104ED;OSAGE SMALL LETTER EHPA;Ll;0;L;;;;;N;;;104C5;;104C5 -104EE;OSAGE SMALL LETTER SA;Ll;0;L;;;;;N;;;104C6;;104C6 -104EF;OSAGE SMALL LETTER SHA;Ll;0;L;;;;;N;;;104C7;;104C7 -104F0;OSAGE SMALL LETTER TA;Ll;0;L;;;;;N;;;104C8;;104C8 -104F1;OSAGE SMALL LETTER EHTA;Ll;0;L;;;;;N;;;104C9;;104C9 -104F2;OSAGE SMALL LETTER TSA;Ll;0;L;;;;;N;;;104CA;;104CA -104F3;OSAGE SMALL LETTER EHTSA;Ll;0;L;;;;;N;;;104CB;;104CB -104F4;OSAGE SMALL LETTER TSHA;Ll;0;L;;;;;N;;;104CC;;104CC -104F5;OSAGE SMALL LETTER DHA;Ll;0;L;;;;;N;;;104CD;;104CD -104F6;OSAGE SMALL LETTER U;Ll;0;L;;;;;N;;;104CE;;104CE -104F7;OSAGE SMALL LETTER WA;Ll;0;L;;;;;N;;;104CF;;104CF -104F8;OSAGE SMALL LETTER KHA;Ll;0;L;;;;;N;;;104D0;;104D0 -104F9;OSAGE SMALL LETTER GHA;Ll;0;L;;;;;N;;;104D1;;104D1 -104FA;OSAGE SMALL LETTER ZA;Ll;0;L;;;;;N;;;104D2;;104D2 -104FB;OSAGE SMALL LETTER ZHA;Ll;0;L;;;;;N;;;104D3;;104D3 -10500;ELBASAN LETTER A;Lo;0;L;;;;;N;;;;; -10501;ELBASAN LETTER BE;Lo;0;L;;;;;N;;;;; -10502;ELBASAN LETTER CE;Lo;0;L;;;;;N;;;;; -10503;ELBASAN LETTER CHE;Lo;0;L;;;;;N;;;;; -10504;ELBASAN LETTER DE;Lo;0;L;;;;;N;;;;; -10505;ELBASAN LETTER NDE;Lo;0;L;;;;;N;;;;; -10506;ELBASAN LETTER DHE;Lo;0;L;;;;;N;;;;; -10507;ELBASAN LETTER EI;Lo;0;L;;;;;N;;;;; -10508;ELBASAN LETTER E;Lo;0;L;;;;;N;;;;; -10509;ELBASAN LETTER FE;Lo;0;L;;;;;N;;;;; -1050A;ELBASAN LETTER GE;Lo;0;L;;;;;N;;;;; -1050B;ELBASAN LETTER GJE;Lo;0;L;;;;;N;;;;; -1050C;ELBASAN LETTER HE;Lo;0;L;;;;;N;;;;; -1050D;ELBASAN LETTER I;Lo;0;L;;;;;N;;;;; -1050E;ELBASAN LETTER JE;Lo;0;L;;;;;N;;;;; -1050F;ELBASAN LETTER KE;Lo;0;L;;;;;N;;;;; -10510;ELBASAN LETTER LE;Lo;0;L;;;;;N;;;;; -10511;ELBASAN LETTER LLE;Lo;0;L;;;;;N;;;;; -10512;ELBASAN LETTER ME;Lo;0;L;;;;;N;;;;; -10513;ELBASAN LETTER NE;Lo;0;L;;;;;N;;;;; -10514;ELBASAN LETTER NA;Lo;0;L;;;;;N;;;;; -10515;ELBASAN LETTER NJE;Lo;0;L;;;;;N;;;;; -10516;ELBASAN LETTER O;Lo;0;L;;;;;N;;;;; -10517;ELBASAN LETTER PE;Lo;0;L;;;;;N;;;;; -10518;ELBASAN LETTER QE;Lo;0;L;;;;;N;;;;; -10519;ELBASAN LETTER RE;Lo;0;L;;;;;N;;;;; -1051A;ELBASAN LETTER RRE;Lo;0;L;;;;;N;;;;; -1051B;ELBASAN LETTER SE;Lo;0;L;;;;;N;;;;; -1051C;ELBASAN LETTER SHE;Lo;0;L;;;;;N;;;;; -1051D;ELBASAN LETTER TE;Lo;0;L;;;;;N;;;;; -1051E;ELBASAN LETTER THE;Lo;0;L;;;;;N;;;;; -1051F;ELBASAN LETTER U;Lo;0;L;;;;;N;;;;; -10520;ELBASAN LETTER VE;Lo;0;L;;;;;N;;;;; -10521;ELBASAN LETTER XE;Lo;0;L;;;;;N;;;;; -10522;ELBASAN LETTER Y;Lo;0;L;;;;;N;;;;; -10523;ELBASAN LETTER ZE;Lo;0;L;;;;;N;;;;; -10524;ELBASAN LETTER ZHE;Lo;0;L;;;;;N;;;;; -10525;ELBASAN LETTER GHE;Lo;0;L;;;;;N;;;;; -10526;ELBASAN LETTER GHAMMA;Lo;0;L;;;;;N;;;;; -10527;ELBASAN LETTER KHE;Lo;0;L;;;;;N;;;;; -10530;CAUCASIAN ALBANIAN LETTER ALT;Lo;0;L;;;;;N;;;;; -10531;CAUCASIAN ALBANIAN LETTER BET;Lo;0;L;;;;;N;;;;; -10532;CAUCASIAN ALBANIAN LETTER GIM;Lo;0;L;;;;;N;;;;; -10533;CAUCASIAN ALBANIAN LETTER DAT;Lo;0;L;;;;;N;;;;; -10534;CAUCASIAN ALBANIAN LETTER EB;Lo;0;L;;;;;N;;;;; -10535;CAUCASIAN ALBANIAN LETTER ZARL;Lo;0;L;;;;;N;;;;; -10536;CAUCASIAN ALBANIAN LETTER EYN;Lo;0;L;;;;;N;;;;; -10537;CAUCASIAN ALBANIAN LETTER ZHIL;Lo;0;L;;;;;N;;;;; -10538;CAUCASIAN ALBANIAN LETTER TAS;Lo;0;L;;;;;N;;;;; -10539;CAUCASIAN ALBANIAN LETTER CHA;Lo;0;L;;;;;N;;;;; -1053A;CAUCASIAN ALBANIAN LETTER YOWD;Lo;0;L;;;;;N;;;;; -1053B;CAUCASIAN ALBANIAN LETTER ZHA;Lo;0;L;;;;;N;;;;; -1053C;CAUCASIAN ALBANIAN LETTER IRB;Lo;0;L;;;;;N;;;;; -1053D;CAUCASIAN ALBANIAN LETTER SHA;Lo;0;L;;;;;N;;;;; -1053E;CAUCASIAN ALBANIAN LETTER LAN;Lo;0;L;;;;;N;;;;; -1053F;CAUCASIAN ALBANIAN LETTER INYA;Lo;0;L;;;;;N;;;;; -10540;CAUCASIAN ALBANIAN LETTER XEYN;Lo;0;L;;;;;N;;;;; -10541;CAUCASIAN ALBANIAN LETTER DYAN;Lo;0;L;;;;;N;;;;; -10542;CAUCASIAN ALBANIAN LETTER CAR;Lo;0;L;;;;;N;;;;; -10543;CAUCASIAN ALBANIAN LETTER JHOX;Lo;0;L;;;;;N;;;;; -10544;CAUCASIAN ALBANIAN LETTER KAR;Lo;0;L;;;;;N;;;;; -10545;CAUCASIAN ALBANIAN LETTER LYIT;Lo;0;L;;;;;N;;;;; -10546;CAUCASIAN ALBANIAN LETTER HEYT;Lo;0;L;;;;;N;;;;; -10547;CAUCASIAN ALBANIAN LETTER QAY;Lo;0;L;;;;;N;;;;; -10548;CAUCASIAN ALBANIAN LETTER AOR;Lo;0;L;;;;;N;;;;; -10549;CAUCASIAN ALBANIAN LETTER CHOY;Lo;0;L;;;;;N;;;;; -1054A;CAUCASIAN ALBANIAN LETTER CHI;Lo;0;L;;;;;N;;;;; -1054B;CAUCASIAN ALBANIAN LETTER CYAY;Lo;0;L;;;;;N;;;;; -1054C;CAUCASIAN ALBANIAN LETTER MAQ;Lo;0;L;;;;;N;;;;; -1054D;CAUCASIAN ALBANIAN LETTER QAR;Lo;0;L;;;;;N;;;;; -1054E;CAUCASIAN ALBANIAN LETTER NOWC;Lo;0;L;;;;;N;;;;; -1054F;CAUCASIAN ALBANIAN LETTER DZYAY;Lo;0;L;;;;;N;;;;; -10550;CAUCASIAN ALBANIAN LETTER SHAK;Lo;0;L;;;;;N;;;;; -10551;CAUCASIAN ALBANIAN LETTER JAYN;Lo;0;L;;;;;N;;;;; -10552;CAUCASIAN ALBANIAN LETTER ON;Lo;0;L;;;;;N;;;;; -10553;CAUCASIAN ALBANIAN LETTER TYAY;Lo;0;L;;;;;N;;;;; -10554;CAUCASIAN ALBANIAN LETTER FAM;Lo;0;L;;;;;N;;;;; -10555;CAUCASIAN ALBANIAN LETTER DZAY;Lo;0;L;;;;;N;;;;; -10556;CAUCASIAN ALBANIAN LETTER CHAT;Lo;0;L;;;;;N;;;;; -10557;CAUCASIAN ALBANIAN LETTER PEN;Lo;0;L;;;;;N;;;;; -10558;CAUCASIAN ALBANIAN LETTER GHEYS;Lo;0;L;;;;;N;;;;; -10559;CAUCASIAN ALBANIAN LETTER RAT;Lo;0;L;;;;;N;;;;; -1055A;CAUCASIAN ALBANIAN LETTER SEYK;Lo;0;L;;;;;N;;;;; -1055B;CAUCASIAN ALBANIAN LETTER VEYZ;Lo;0;L;;;;;N;;;;; -1055C;CAUCASIAN ALBANIAN LETTER TIWR;Lo;0;L;;;;;N;;;;; -1055D;CAUCASIAN ALBANIAN LETTER SHOY;Lo;0;L;;;;;N;;;;; -1055E;CAUCASIAN ALBANIAN LETTER IWN;Lo;0;L;;;;;N;;;;; -1055F;CAUCASIAN ALBANIAN LETTER CYAW;Lo;0;L;;;;;N;;;;; -10560;CAUCASIAN ALBANIAN LETTER CAYN;Lo;0;L;;;;;N;;;;; -10561;CAUCASIAN ALBANIAN LETTER YAYD;Lo;0;L;;;;;N;;;;; -10562;CAUCASIAN ALBANIAN LETTER PIWR;Lo;0;L;;;;;N;;;;; -10563;CAUCASIAN ALBANIAN LETTER KIW;Lo;0;L;;;;;N;;;;; -1056F;CAUCASIAN ALBANIAN CITATION MARK;Po;0;L;;;;;N;;;;; -10570;VITHKUQI CAPITAL LETTER A;Lu;0;L;;;;;N;;;;10597; -10571;VITHKUQI CAPITAL LETTER BBE;Lu;0;L;;;;;N;;;;10598; -10572;VITHKUQI CAPITAL LETTER BE;Lu;0;L;;;;;N;;;;10599; -10573;VITHKUQI CAPITAL LETTER CE;Lu;0;L;;;;;N;;;;1059A; -10574;VITHKUQI CAPITAL LETTER CHE;Lu;0;L;;;;;N;;;;1059B; -10575;VITHKUQI CAPITAL LETTER DE;Lu;0;L;;;;;N;;;;1059C; -10576;VITHKUQI CAPITAL LETTER DHE;Lu;0;L;;;;;N;;;;1059D; -10577;VITHKUQI CAPITAL LETTER EI;Lu;0;L;;;;;N;;;;1059E; -10578;VITHKUQI CAPITAL LETTER E;Lu;0;L;;;;;N;;;;1059F; -10579;VITHKUQI CAPITAL LETTER FE;Lu;0;L;;;;;N;;;;105A0; -1057A;VITHKUQI CAPITAL LETTER GA;Lu;0;L;;;;;N;;;;105A1; -1057C;VITHKUQI CAPITAL LETTER HA;Lu;0;L;;;;;N;;;;105A3; -1057D;VITHKUQI CAPITAL LETTER HHA;Lu;0;L;;;;;N;;;;105A4; -1057E;VITHKUQI CAPITAL LETTER I;Lu;0;L;;;;;N;;;;105A5; -1057F;VITHKUQI CAPITAL LETTER IJE;Lu;0;L;;;;;N;;;;105A6; -10580;VITHKUQI CAPITAL LETTER JE;Lu;0;L;;;;;N;;;;105A7; -10581;VITHKUQI CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;105A8; -10582;VITHKUQI CAPITAL LETTER LA;Lu;0;L;;;;;N;;;;105A9; -10583;VITHKUQI CAPITAL LETTER LLA;Lu;0;L;;;;;N;;;;105AA; -10584;VITHKUQI CAPITAL LETTER ME;Lu;0;L;;;;;N;;;;105AB; -10585;VITHKUQI CAPITAL LETTER NE;Lu;0;L;;;;;N;;;;105AC; -10586;VITHKUQI CAPITAL LETTER NJE;Lu;0;L;;;;;N;;;;105AD; -10587;VITHKUQI CAPITAL LETTER O;Lu;0;L;;;;;N;;;;105AE; -10588;VITHKUQI CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;105AF; -10589;VITHKUQI CAPITAL LETTER QA;Lu;0;L;;;;;N;;;;105B0; -1058A;VITHKUQI CAPITAL LETTER RE;Lu;0;L;;;;;N;;;;105B1; -1058C;VITHKUQI CAPITAL LETTER SE;Lu;0;L;;;;;N;;;;105B3; -1058D;VITHKUQI CAPITAL LETTER SHE;Lu;0;L;;;;;N;;;;105B4; -1058E;VITHKUQI CAPITAL LETTER TE;Lu;0;L;;;;;N;;;;105B5; -1058F;VITHKUQI CAPITAL LETTER THE;Lu;0;L;;;;;N;;;;105B6; -10590;VITHKUQI CAPITAL LETTER U;Lu;0;L;;;;;N;;;;105B7; -10591;VITHKUQI CAPITAL LETTER VE;Lu;0;L;;;;;N;;;;105B8; -10592;VITHKUQI CAPITAL LETTER XE;Lu;0;L;;;;;N;;;;105B9; -10594;VITHKUQI CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;105BB; -10595;VITHKUQI CAPITAL LETTER ZE;Lu;0;L;;;;;N;;;;105BC; -10597;VITHKUQI SMALL LETTER A;Ll;0;L;;;;;N;;;10570;;10570 -10598;VITHKUQI SMALL LETTER BBE;Ll;0;L;;;;;N;;;10571;;10571 -10599;VITHKUQI SMALL LETTER BE;Ll;0;L;;;;;N;;;10572;;10572 -1059A;VITHKUQI SMALL LETTER CE;Ll;0;L;;;;;N;;;10573;;10573 -1059B;VITHKUQI SMALL LETTER CHE;Ll;0;L;;;;;N;;;10574;;10574 -1059C;VITHKUQI SMALL LETTER DE;Ll;0;L;;;;;N;;;10575;;10575 -1059D;VITHKUQI SMALL LETTER DHE;Ll;0;L;;;;;N;;;10576;;10576 -1059E;VITHKUQI SMALL LETTER EI;Ll;0;L;;;;;N;;;10577;;10577 -1059F;VITHKUQI SMALL LETTER E;Ll;0;L;;;;;N;;;10578;;10578 -105A0;VITHKUQI SMALL LETTER FE;Ll;0;L;;;;;N;;;10579;;10579 -105A1;VITHKUQI SMALL LETTER GA;Ll;0;L;;;;;N;;;1057A;;1057A -105A3;VITHKUQI SMALL LETTER HA;Ll;0;L;;;;;N;;;1057C;;1057C -105A4;VITHKUQI SMALL LETTER HHA;Ll;0;L;;;;;N;;;1057D;;1057D -105A5;VITHKUQI SMALL LETTER I;Ll;0;L;;;;;N;;;1057E;;1057E -105A6;VITHKUQI SMALL LETTER IJE;Ll;0;L;;;;;N;;;1057F;;1057F -105A7;VITHKUQI SMALL LETTER JE;Ll;0;L;;;;;N;;;10580;;10580 -105A8;VITHKUQI SMALL LETTER KA;Ll;0;L;;;;;N;;;10581;;10581 -105A9;VITHKUQI SMALL LETTER LA;Ll;0;L;;;;;N;;;10582;;10582 -105AA;VITHKUQI SMALL LETTER LLA;Ll;0;L;;;;;N;;;10583;;10583 -105AB;VITHKUQI SMALL LETTER ME;Ll;0;L;;;;;N;;;10584;;10584 -105AC;VITHKUQI SMALL LETTER NE;Ll;0;L;;;;;N;;;10585;;10585 -105AD;VITHKUQI SMALL LETTER NJE;Ll;0;L;;;;;N;;;10586;;10586 -105AE;VITHKUQI SMALL LETTER O;Ll;0;L;;;;;N;;;10587;;10587 -105AF;VITHKUQI SMALL LETTER PE;Ll;0;L;;;;;N;;;10588;;10588 -105B0;VITHKUQI SMALL LETTER QA;Ll;0;L;;;;;N;;;10589;;10589 -105B1;VITHKUQI SMALL LETTER RE;Ll;0;L;;;;;N;;;1058A;;1058A -105B3;VITHKUQI SMALL LETTER SE;Ll;0;L;;;;;N;;;1058C;;1058C -105B4;VITHKUQI SMALL LETTER SHE;Ll;0;L;;;;;N;;;1058D;;1058D -105B5;VITHKUQI SMALL LETTER TE;Ll;0;L;;;;;N;;;1058E;;1058E -105B6;VITHKUQI SMALL LETTER THE;Ll;0;L;;;;;N;;;1058F;;1058F -105B7;VITHKUQI SMALL LETTER U;Ll;0;L;;;;;N;;;10590;;10590 -105B8;VITHKUQI SMALL LETTER VE;Ll;0;L;;;;;N;;;10591;;10591 -105B9;VITHKUQI SMALL LETTER XE;Ll;0;L;;;;;N;;;10592;;10592 -105BB;VITHKUQI SMALL LETTER Y;Ll;0;L;;;;;N;;;10594;;10594 -105BC;VITHKUQI SMALL LETTER ZE;Ll;0;L;;;;;N;;;10595;;10595 -10600;LINEAR A SIGN AB001;Lo;0;L;;;;;N;;;;; -10601;LINEAR A SIGN AB002;Lo;0;L;;;;;N;;;;; -10602;LINEAR A SIGN AB003;Lo;0;L;;;;;N;;;;; -10603;LINEAR A SIGN AB004;Lo;0;L;;;;;N;;;;; -10604;LINEAR A SIGN AB005;Lo;0;L;;;;;N;;;;; -10605;LINEAR A SIGN AB006;Lo;0;L;;;;;N;;;;; -10606;LINEAR A SIGN AB007;Lo;0;L;;;;;N;;;;; -10607;LINEAR A SIGN AB008;Lo;0;L;;;;;N;;;;; -10608;LINEAR A SIGN AB009;Lo;0;L;;;;;N;;;;; -10609;LINEAR A SIGN AB010;Lo;0;L;;;;;N;;;;; -1060A;LINEAR A SIGN AB011;Lo;0;L;;;;;N;;;;; -1060B;LINEAR A SIGN AB013;Lo;0;L;;;;;N;;;;; -1060C;LINEAR A SIGN AB016;Lo;0;L;;;;;N;;;;; -1060D;LINEAR A SIGN AB017;Lo;0;L;;;;;N;;;;; -1060E;LINEAR A SIGN AB020;Lo;0;L;;;;;N;;;;; -1060F;LINEAR A SIGN AB021;Lo;0;L;;;;;N;;;;; -10610;LINEAR A SIGN AB021F;Lo;0;L;;;;;N;;;;; -10611;LINEAR A SIGN AB021M;Lo;0;L;;;;;N;;;;; -10612;LINEAR A SIGN AB022;Lo;0;L;;;;;N;;;;; -10613;LINEAR A SIGN AB022F;Lo;0;L;;;;;N;;;;; -10614;LINEAR A SIGN AB022M;Lo;0;L;;;;;N;;;;; -10615;LINEAR A SIGN AB023;Lo;0;L;;;;;N;;;;; -10616;LINEAR A SIGN AB023M;Lo;0;L;;;;;N;;;;; -10617;LINEAR A SIGN AB024;Lo;0;L;;;;;N;;;;; -10618;LINEAR A SIGN AB026;Lo;0;L;;;;;N;;;;; -10619;LINEAR A SIGN AB027;Lo;0;L;;;;;N;;;;; -1061A;LINEAR A SIGN AB028;Lo;0;L;;;;;N;;;;; -1061B;LINEAR A SIGN A028B;Lo;0;L;;;;;N;;;;; -1061C;LINEAR A SIGN AB029;Lo;0;L;;;;;N;;;;; -1061D;LINEAR A SIGN AB030;Lo;0;L;;;;;N;;;;; -1061E;LINEAR A SIGN AB031;Lo;0;L;;;;;N;;;;; -1061F;LINEAR A SIGN AB034;Lo;0;L;;;;;N;;;;; -10620;LINEAR A SIGN AB037;Lo;0;L;;;;;N;;;;; -10621;LINEAR A SIGN AB038;Lo;0;L;;;;;N;;;;; -10622;LINEAR A SIGN AB039;Lo;0;L;;;;;N;;;;; -10623;LINEAR A SIGN AB040;Lo;0;L;;;;;N;;;;; -10624;LINEAR A SIGN AB041;Lo;0;L;;;;;N;;;;; -10625;LINEAR A SIGN AB044;Lo;0;L;;;;;N;;;;; -10626;LINEAR A SIGN AB045;Lo;0;L;;;;;N;;;;; -10627;LINEAR A SIGN AB046;Lo;0;L;;;;;N;;;;; -10628;LINEAR A SIGN AB047;Lo;0;L;;;;;N;;;;; -10629;LINEAR A SIGN AB048;Lo;0;L;;;;;N;;;;; -1062A;LINEAR A SIGN AB049;Lo;0;L;;;;;N;;;;; -1062B;LINEAR A SIGN AB050;Lo;0;L;;;;;N;;;;; -1062C;LINEAR A SIGN AB051;Lo;0;L;;;;;N;;;;; -1062D;LINEAR A SIGN AB053;Lo;0;L;;;;;N;;;;; -1062E;LINEAR A SIGN AB054;Lo;0;L;;;;;N;;;;; -1062F;LINEAR A SIGN AB055;Lo;0;L;;;;;N;;;;; -10630;LINEAR A SIGN AB056;Lo;0;L;;;;;N;;;;; -10631;LINEAR A SIGN AB057;Lo;0;L;;;;;N;;;;; -10632;LINEAR A SIGN AB058;Lo;0;L;;;;;N;;;;; -10633;LINEAR A SIGN AB059;Lo;0;L;;;;;N;;;;; -10634;LINEAR A SIGN AB060;Lo;0;L;;;;;N;;;;; -10635;LINEAR A SIGN AB061;Lo;0;L;;;;;N;;;;; -10636;LINEAR A SIGN AB065;Lo;0;L;;;;;N;;;;; -10637;LINEAR A SIGN AB066;Lo;0;L;;;;;N;;;;; -10638;LINEAR A SIGN AB067;Lo;0;L;;;;;N;;;;; -10639;LINEAR A SIGN AB069;Lo;0;L;;;;;N;;;;; -1063A;LINEAR A SIGN AB070;Lo;0;L;;;;;N;;;;; -1063B;LINEAR A SIGN AB073;Lo;0;L;;;;;N;;;;; -1063C;LINEAR A SIGN AB074;Lo;0;L;;;;;N;;;;; -1063D;LINEAR A SIGN AB076;Lo;0;L;;;;;N;;;;; -1063E;LINEAR A SIGN AB077;Lo;0;L;;;;;N;;;;; -1063F;LINEAR A SIGN AB078;Lo;0;L;;;;;N;;;;; -10640;LINEAR A SIGN AB079;Lo;0;L;;;;;N;;;;; -10641;LINEAR A SIGN AB080;Lo;0;L;;;;;N;;;;; -10642;LINEAR A SIGN AB081;Lo;0;L;;;;;N;;;;; -10643;LINEAR A SIGN AB082;Lo;0;L;;;;;N;;;;; -10644;LINEAR A SIGN AB085;Lo;0;L;;;;;N;;;;; -10645;LINEAR A SIGN AB086;Lo;0;L;;;;;N;;;;; -10646;LINEAR A SIGN AB087;Lo;0;L;;;;;N;;;;; -10647;LINEAR A SIGN A100-102;Lo;0;L;;;;;N;;;;; -10648;LINEAR A SIGN AB118;Lo;0;L;;;;;N;;;;; -10649;LINEAR A SIGN AB120;Lo;0;L;;;;;N;;;;; -1064A;LINEAR A SIGN A120B;Lo;0;L;;;;;N;;;;; -1064B;LINEAR A SIGN AB122;Lo;0;L;;;;;N;;;;; -1064C;LINEAR A SIGN AB123;Lo;0;L;;;;;N;;;;; -1064D;LINEAR A SIGN AB131A;Lo;0;L;;;;;N;;;;; -1064E;LINEAR A SIGN AB131B;Lo;0;L;;;;;N;;;;; -1064F;LINEAR A SIGN A131C;Lo;0;L;;;;;N;;;;; -10650;LINEAR A SIGN AB164;Lo;0;L;;;;;N;;;;; -10651;LINEAR A SIGN AB171;Lo;0;L;;;;;N;;;;; -10652;LINEAR A SIGN AB180;Lo;0;L;;;;;N;;;;; -10653;LINEAR A SIGN AB188;Lo;0;L;;;;;N;;;;; -10654;LINEAR A SIGN AB191;Lo;0;L;;;;;N;;;;; -10655;LINEAR A SIGN A301;Lo;0;L;;;;;N;;;;; -10656;LINEAR A SIGN A302;Lo;0;L;;;;;N;;;;; -10657;LINEAR A SIGN A303;Lo;0;L;;;;;N;;;;; -10658;LINEAR A SIGN A304;Lo;0;L;;;;;N;;;;; -10659;LINEAR A SIGN A305;Lo;0;L;;;;;N;;;;; -1065A;LINEAR A SIGN A306;Lo;0;L;;;;;N;;;;; -1065B;LINEAR A SIGN A307;Lo;0;L;;;;;N;;;;; -1065C;LINEAR A SIGN A308;Lo;0;L;;;;;N;;;;; -1065D;LINEAR A SIGN A309A;Lo;0;L;;;;;N;;;;; -1065E;LINEAR A SIGN A309B;Lo;0;L;;;;;N;;;;; -1065F;LINEAR A SIGN A309C;Lo;0;L;;;;;N;;;;; -10660;LINEAR A SIGN A310;Lo;0;L;;;;;N;;;;; -10661;LINEAR A SIGN A311;Lo;0;L;;;;;N;;;;; -10662;LINEAR A SIGN A312;Lo;0;L;;;;;N;;;;; -10663;LINEAR A SIGN A313A;Lo;0;L;;;;;N;;;;; -10664;LINEAR A SIGN A313B;Lo;0;L;;;;;N;;;;; -10665;LINEAR A SIGN A313C;Lo;0;L;;;;;N;;;;; -10666;LINEAR A SIGN A314;Lo;0;L;;;;;N;;;;; -10667;LINEAR A SIGN A315;Lo;0;L;;;;;N;;;;; -10668;LINEAR A SIGN A316;Lo;0;L;;;;;N;;;;; -10669;LINEAR A SIGN A317;Lo;0;L;;;;;N;;;;; -1066A;LINEAR A SIGN A318;Lo;0;L;;;;;N;;;;; -1066B;LINEAR A SIGN A319;Lo;0;L;;;;;N;;;;; -1066C;LINEAR A SIGN A320;Lo;0;L;;;;;N;;;;; -1066D;LINEAR A SIGN A321;Lo;0;L;;;;;N;;;;; -1066E;LINEAR A SIGN A322;Lo;0;L;;;;;N;;;;; -1066F;LINEAR A SIGN A323;Lo;0;L;;;;;N;;;;; -10670;LINEAR A SIGN A324;Lo;0;L;;;;;N;;;;; -10671;LINEAR A SIGN A325;Lo;0;L;;;;;N;;;;; -10672;LINEAR A SIGN A326;Lo;0;L;;;;;N;;;;; -10673;LINEAR A SIGN A327;Lo;0;L;;;;;N;;;;; -10674;LINEAR A SIGN A328;Lo;0;L;;;;;N;;;;; -10675;LINEAR A SIGN A329;Lo;0;L;;;;;N;;;;; -10676;LINEAR A SIGN A330;Lo;0;L;;;;;N;;;;; -10677;LINEAR A SIGN A331;Lo;0;L;;;;;N;;;;; -10678;LINEAR A SIGN A332;Lo;0;L;;;;;N;;;;; -10679;LINEAR A SIGN A333;Lo;0;L;;;;;N;;;;; -1067A;LINEAR A SIGN A334;Lo;0;L;;;;;N;;;;; -1067B;LINEAR A SIGN A335;Lo;0;L;;;;;N;;;;; -1067C;LINEAR A SIGN A336;Lo;0;L;;;;;N;;;;; -1067D;LINEAR A SIGN A337;Lo;0;L;;;;;N;;;;; -1067E;LINEAR A SIGN A338;Lo;0;L;;;;;N;;;;; -1067F;LINEAR A SIGN A339;Lo;0;L;;;;;N;;;;; -10680;LINEAR A SIGN A340;Lo;0;L;;;;;N;;;;; -10681;LINEAR A SIGN A341;Lo;0;L;;;;;N;;;;; -10682;LINEAR A SIGN A342;Lo;0;L;;;;;N;;;;; -10683;LINEAR A SIGN A343;Lo;0;L;;;;;N;;;;; -10684;LINEAR A SIGN A344;Lo;0;L;;;;;N;;;;; -10685;LINEAR A SIGN A345;Lo;0;L;;;;;N;;;;; -10686;LINEAR A SIGN A346;Lo;0;L;;;;;N;;;;; -10687;LINEAR A SIGN A347;Lo;0;L;;;;;N;;;;; -10688;LINEAR A SIGN A348;Lo;0;L;;;;;N;;;;; -10689;LINEAR A SIGN A349;Lo;0;L;;;;;N;;;;; -1068A;LINEAR A SIGN A350;Lo;0;L;;;;;N;;;;; -1068B;LINEAR A SIGN A351;Lo;0;L;;;;;N;;;;; -1068C;LINEAR A SIGN A352;Lo;0;L;;;;;N;;;;; -1068D;LINEAR A SIGN A353;Lo;0;L;;;;;N;;;;; -1068E;LINEAR A SIGN A354;Lo;0;L;;;;;N;;;;; -1068F;LINEAR A SIGN A355;Lo;0;L;;;;;N;;;;; -10690;LINEAR A SIGN A356;Lo;0;L;;;;;N;;;;; -10691;LINEAR A SIGN A357;Lo;0;L;;;;;N;;;;; -10692;LINEAR A SIGN A358;Lo;0;L;;;;;N;;;;; -10693;LINEAR A SIGN A359;Lo;0;L;;;;;N;;;;; -10694;LINEAR A SIGN A360;Lo;0;L;;;;;N;;;;; -10695;LINEAR A SIGN A361;Lo;0;L;;;;;N;;;;; -10696;LINEAR A SIGN A362;Lo;0;L;;;;;N;;;;; -10697;LINEAR A SIGN A363;Lo;0;L;;;;;N;;;;; -10698;LINEAR A SIGN A364;Lo;0;L;;;;;N;;;;; -10699;LINEAR A SIGN A365;Lo;0;L;;;;;N;;;;; -1069A;LINEAR A SIGN A366;Lo;0;L;;;;;N;;;;; -1069B;LINEAR A SIGN A367;Lo;0;L;;;;;N;;;;; -1069C;LINEAR A SIGN A368;Lo;0;L;;;;;N;;;;; -1069D;LINEAR A SIGN A369;Lo;0;L;;;;;N;;;;; -1069E;LINEAR A SIGN A370;Lo;0;L;;;;;N;;;;; -1069F;LINEAR A SIGN A371;Lo;0;L;;;;;N;;;;; -106A0;LINEAR A SIGN A400-VAS;Lo;0;L;;;;;N;;;;; -106A1;LINEAR A SIGN A401-VAS;Lo;0;L;;;;;N;;;;; -106A2;LINEAR A SIGN A402-VAS;Lo;0;L;;;;;N;;;;; -106A3;LINEAR A SIGN A403-VAS;Lo;0;L;;;;;N;;;;; -106A4;LINEAR A SIGN A404-VAS;Lo;0;L;;;;;N;;;;; -106A5;LINEAR A SIGN A405-VAS;Lo;0;L;;;;;N;;;;; -106A6;LINEAR A SIGN A406-VAS;Lo;0;L;;;;;N;;;;; -106A7;LINEAR A SIGN A407-VAS;Lo;0;L;;;;;N;;;;; -106A8;LINEAR A SIGN A408-VAS;Lo;0;L;;;;;N;;;;; -106A9;LINEAR A SIGN A409-VAS;Lo;0;L;;;;;N;;;;; -106AA;LINEAR A SIGN A410-VAS;Lo;0;L;;;;;N;;;;; -106AB;LINEAR A SIGN A411-VAS;Lo;0;L;;;;;N;;;;; -106AC;LINEAR A SIGN A412-VAS;Lo;0;L;;;;;N;;;;; -106AD;LINEAR A SIGN A413-VAS;Lo;0;L;;;;;N;;;;; -106AE;LINEAR A SIGN A414-VAS;Lo;0;L;;;;;N;;;;; -106AF;LINEAR A SIGN A415-VAS;Lo;0;L;;;;;N;;;;; -106B0;LINEAR A SIGN A416-VAS;Lo;0;L;;;;;N;;;;; -106B1;LINEAR A SIGN A417-VAS;Lo;0;L;;;;;N;;;;; -106B2;LINEAR A SIGN A418-VAS;Lo;0;L;;;;;N;;;;; -106B3;LINEAR A SIGN A501;Lo;0;L;;;;;N;;;;; -106B4;LINEAR A SIGN A502;Lo;0;L;;;;;N;;;;; -106B5;LINEAR A SIGN A503;Lo;0;L;;;;;N;;;;; -106B6;LINEAR A SIGN A504;Lo;0;L;;;;;N;;;;; -106B7;LINEAR A SIGN A505;Lo;0;L;;;;;N;;;;; -106B8;LINEAR A SIGN A506;Lo;0;L;;;;;N;;;;; -106B9;LINEAR A SIGN A508;Lo;0;L;;;;;N;;;;; -106BA;LINEAR A SIGN A509;Lo;0;L;;;;;N;;;;; -106BB;LINEAR A SIGN A510;Lo;0;L;;;;;N;;;;; -106BC;LINEAR A SIGN A511;Lo;0;L;;;;;N;;;;; -106BD;LINEAR A SIGN A512;Lo;0;L;;;;;N;;;;; -106BE;LINEAR A SIGN A513;Lo;0;L;;;;;N;;;;; -106BF;LINEAR A SIGN A515;Lo;0;L;;;;;N;;;;; -106C0;LINEAR A SIGN A516;Lo;0;L;;;;;N;;;;; -106C1;LINEAR A SIGN A520;Lo;0;L;;;;;N;;;;; -106C2;LINEAR A SIGN A521;Lo;0;L;;;;;N;;;;; -106C3;LINEAR A SIGN A523;Lo;0;L;;;;;N;;;;; -106C4;LINEAR A SIGN A524;Lo;0;L;;;;;N;;;;; -106C5;LINEAR A SIGN A525;Lo;0;L;;;;;N;;;;; -106C6;LINEAR A SIGN A526;Lo;0;L;;;;;N;;;;; -106C7;LINEAR A SIGN A527;Lo;0;L;;;;;N;;;;; -106C8;LINEAR A SIGN A528;Lo;0;L;;;;;N;;;;; -106C9;LINEAR A SIGN A529;Lo;0;L;;;;;N;;;;; -106CA;LINEAR A SIGN A530;Lo;0;L;;;;;N;;;;; -106CB;LINEAR A SIGN A531;Lo;0;L;;;;;N;;;;; -106CC;LINEAR A SIGN A532;Lo;0;L;;;;;N;;;;; -106CD;LINEAR A SIGN A534;Lo;0;L;;;;;N;;;;; -106CE;LINEAR A SIGN A535;Lo;0;L;;;;;N;;;;; -106CF;LINEAR A SIGN A536;Lo;0;L;;;;;N;;;;; -106D0;LINEAR A SIGN A537;Lo;0;L;;;;;N;;;;; -106D1;LINEAR A SIGN A538;Lo;0;L;;;;;N;;;;; -106D2;LINEAR A SIGN A539;Lo;0;L;;;;;N;;;;; -106D3;LINEAR A SIGN A540;Lo;0;L;;;;;N;;;;; -106D4;LINEAR A SIGN A541;Lo;0;L;;;;;N;;;;; -106D5;LINEAR A SIGN A542;Lo;0;L;;;;;N;;;;; -106D6;LINEAR A SIGN A545;Lo;0;L;;;;;N;;;;; -106D7;LINEAR A SIGN A547;Lo;0;L;;;;;N;;;;; -106D8;LINEAR A SIGN A548;Lo;0;L;;;;;N;;;;; -106D9;LINEAR A SIGN A549;Lo;0;L;;;;;N;;;;; -106DA;LINEAR A SIGN A550;Lo;0;L;;;;;N;;;;; -106DB;LINEAR A SIGN A551;Lo;0;L;;;;;N;;;;; -106DC;LINEAR A SIGN A552;Lo;0;L;;;;;N;;;;; -106DD;LINEAR A SIGN A553;Lo;0;L;;;;;N;;;;; -106DE;LINEAR A SIGN A554;Lo;0;L;;;;;N;;;;; -106DF;LINEAR A SIGN A555;Lo;0;L;;;;;N;;;;; -106E0;LINEAR A SIGN A556;Lo;0;L;;;;;N;;;;; -106E1;LINEAR A SIGN A557;Lo;0;L;;;;;N;;;;; -106E2;LINEAR A SIGN A559;Lo;0;L;;;;;N;;;;; -106E3;LINEAR A SIGN A563;Lo;0;L;;;;;N;;;;; -106E4;LINEAR A SIGN A564;Lo;0;L;;;;;N;;;;; -106E5;LINEAR A SIGN A565;Lo;0;L;;;;;N;;;;; -106E6;LINEAR A SIGN A566;Lo;0;L;;;;;N;;;;; -106E7;LINEAR A SIGN A568;Lo;0;L;;;;;N;;;;; -106E8;LINEAR A SIGN A569;Lo;0;L;;;;;N;;;;; -106E9;LINEAR A SIGN A570;Lo;0;L;;;;;N;;;;; -106EA;LINEAR A SIGN A571;Lo;0;L;;;;;N;;;;; -106EB;LINEAR A SIGN A572;Lo;0;L;;;;;N;;;;; -106EC;LINEAR A SIGN A573;Lo;0;L;;;;;N;;;;; -106ED;LINEAR A SIGN A574;Lo;0;L;;;;;N;;;;; -106EE;LINEAR A SIGN A575;Lo;0;L;;;;;N;;;;; -106EF;LINEAR A SIGN A576;Lo;0;L;;;;;N;;;;; -106F0;LINEAR A SIGN A577;Lo;0;L;;;;;N;;;;; -106F1;LINEAR A SIGN A578;Lo;0;L;;;;;N;;;;; -106F2;LINEAR A SIGN A579;Lo;0;L;;;;;N;;;;; -106F3;LINEAR A SIGN A580;Lo;0;L;;;;;N;;;;; -106F4;LINEAR A SIGN A581;Lo;0;L;;;;;N;;;;; -106F5;LINEAR A SIGN A582;Lo;0;L;;;;;N;;;;; -106F6;LINEAR A SIGN A583;Lo;0;L;;;;;N;;;;; -106F7;LINEAR A SIGN A584;Lo;0;L;;;;;N;;;;; -106F8;LINEAR A SIGN A585;Lo;0;L;;;;;N;;;;; -106F9;LINEAR A SIGN A586;Lo;0;L;;;;;N;;;;; -106FA;LINEAR A SIGN A587;Lo;0;L;;;;;N;;;;; -106FB;LINEAR A SIGN A588;Lo;0;L;;;;;N;;;;; -106FC;LINEAR A SIGN A589;Lo;0;L;;;;;N;;;;; -106FD;LINEAR A SIGN A591;Lo;0;L;;;;;N;;;;; -106FE;LINEAR A SIGN A592;Lo;0;L;;;;;N;;;;; -106FF;LINEAR A SIGN A594;Lo;0;L;;;;;N;;;;; -10700;LINEAR A SIGN A595;Lo;0;L;;;;;N;;;;; -10701;LINEAR A SIGN A596;Lo;0;L;;;;;N;;;;; -10702;LINEAR A SIGN A598;Lo;0;L;;;;;N;;;;; -10703;LINEAR A SIGN A600;Lo;0;L;;;;;N;;;;; -10704;LINEAR A SIGN A601;Lo;0;L;;;;;N;;;;; -10705;LINEAR A SIGN A602;Lo;0;L;;;;;N;;;;; -10706;LINEAR A SIGN A603;Lo;0;L;;;;;N;;;;; -10707;LINEAR A SIGN A604;Lo;0;L;;;;;N;;;;; -10708;LINEAR A SIGN A606;Lo;0;L;;;;;N;;;;; -10709;LINEAR A SIGN A608;Lo;0;L;;;;;N;;;;; -1070A;LINEAR A SIGN A609;Lo;0;L;;;;;N;;;;; -1070B;LINEAR A SIGN A610;Lo;0;L;;;;;N;;;;; -1070C;LINEAR A SIGN A611;Lo;0;L;;;;;N;;;;; -1070D;LINEAR A SIGN A612;Lo;0;L;;;;;N;;;;; -1070E;LINEAR A SIGN A613;Lo;0;L;;;;;N;;;;; -1070F;LINEAR A SIGN A614;Lo;0;L;;;;;N;;;;; -10710;LINEAR A SIGN A615;Lo;0;L;;;;;N;;;;; -10711;LINEAR A SIGN A616;Lo;0;L;;;;;N;;;;; -10712;LINEAR A SIGN A617;Lo;0;L;;;;;N;;;;; -10713;LINEAR A SIGN A618;Lo;0;L;;;;;N;;;;; -10714;LINEAR A SIGN A619;Lo;0;L;;;;;N;;;;; -10715;LINEAR A SIGN A620;Lo;0;L;;;;;N;;;;; -10716;LINEAR A SIGN A621;Lo;0;L;;;;;N;;;;; -10717;LINEAR A SIGN A622;Lo;0;L;;;;;N;;;;; -10718;LINEAR A SIGN A623;Lo;0;L;;;;;N;;;;; -10719;LINEAR A SIGN A624;Lo;0;L;;;;;N;;;;; -1071A;LINEAR A SIGN A626;Lo;0;L;;;;;N;;;;; -1071B;LINEAR A SIGN A627;Lo;0;L;;;;;N;;;;; -1071C;LINEAR A SIGN A628;Lo;0;L;;;;;N;;;;; -1071D;LINEAR A SIGN A629;Lo;0;L;;;;;N;;;;; -1071E;LINEAR A SIGN A634;Lo;0;L;;;;;N;;;;; -1071F;LINEAR A SIGN A637;Lo;0;L;;;;;N;;;;; -10720;LINEAR A SIGN A638;Lo;0;L;;;;;N;;;;; -10721;LINEAR A SIGN A640;Lo;0;L;;;;;N;;;;; -10722;LINEAR A SIGN A642;Lo;0;L;;;;;N;;;;; -10723;LINEAR A SIGN A643;Lo;0;L;;;;;N;;;;; -10724;LINEAR A SIGN A644;Lo;0;L;;;;;N;;;;; -10725;LINEAR A SIGN A645;Lo;0;L;;;;;N;;;;; -10726;LINEAR A SIGN A646;Lo;0;L;;;;;N;;;;; -10727;LINEAR A SIGN A648;Lo;0;L;;;;;N;;;;; -10728;LINEAR A SIGN A649;Lo;0;L;;;;;N;;;;; -10729;LINEAR A SIGN A651;Lo;0;L;;;;;N;;;;; -1072A;LINEAR A SIGN A652;Lo;0;L;;;;;N;;;;; -1072B;LINEAR A SIGN A653;Lo;0;L;;;;;N;;;;; -1072C;LINEAR A SIGN A654;Lo;0;L;;;;;N;;;;; -1072D;LINEAR A SIGN A655;Lo;0;L;;;;;N;;;;; -1072E;LINEAR A SIGN A656;Lo;0;L;;;;;N;;;;; -1072F;LINEAR A SIGN A657;Lo;0;L;;;;;N;;;;; -10730;LINEAR A SIGN A658;Lo;0;L;;;;;N;;;;; -10731;LINEAR A SIGN A659;Lo;0;L;;;;;N;;;;; -10732;LINEAR A SIGN A660;Lo;0;L;;;;;N;;;;; -10733;LINEAR A SIGN A661;Lo;0;L;;;;;N;;;;; -10734;LINEAR A SIGN A662;Lo;0;L;;;;;N;;;;; -10735;LINEAR A SIGN A663;Lo;0;L;;;;;N;;;;; -10736;LINEAR A SIGN A664;Lo;0;L;;;;;N;;;;; -10740;LINEAR A SIGN A701 A;Lo;0;L;;;;;N;;;;; -10741;LINEAR A SIGN A702 B;Lo;0;L;;;;;N;;;;; -10742;LINEAR A SIGN A703 D;Lo;0;L;;;;;N;;;;; -10743;LINEAR A SIGN A704 E;Lo;0;L;;;;;N;;;;; -10744;LINEAR A SIGN A705 F;Lo;0;L;;;;;N;;;;; -10745;LINEAR A SIGN A706 H;Lo;0;L;;;;;N;;;;; -10746;LINEAR A SIGN A707 J;Lo;0;L;;;;;N;;;;; -10747;LINEAR A SIGN A708 K;Lo;0;L;;;;;N;;;;; -10748;LINEAR A SIGN A709 L;Lo;0;L;;;;;N;;;;; -10749;LINEAR A SIGN A709-2 L2;Lo;0;L;;;;;N;;;;; -1074A;LINEAR A SIGN A709-3 L3;Lo;0;L;;;;;N;;;;; -1074B;LINEAR A SIGN A709-4 L4;Lo;0;L;;;;;N;;;;; -1074C;LINEAR A SIGN A709-6 L6;Lo;0;L;;;;;N;;;;; -1074D;LINEAR A SIGN A710 W;Lo;0;L;;;;;N;;;;; -1074E;LINEAR A SIGN A711 X;Lo;0;L;;;;;N;;;;; -1074F;LINEAR A SIGN A712 Y;Lo;0;L;;;;;N;;;;; -10750;LINEAR A SIGN A713 OMEGA;Lo;0;L;;;;;N;;;;; -10751;LINEAR A SIGN A714 ABB;Lo;0;L;;;;;N;;;;; -10752;LINEAR A SIGN A715 BB;Lo;0;L;;;;;N;;;;; -10753;LINEAR A SIGN A717 DD;Lo;0;L;;;;;N;;;;; -10754;LINEAR A SIGN A726 EYYY;Lo;0;L;;;;;N;;;;; -10755;LINEAR A SIGN A732 JE;Lo;0;L;;;;;N;;;;; -10760;LINEAR A SIGN A800;Lo;0;L;;;;;N;;;;; -10761;LINEAR A SIGN A801;Lo;0;L;;;;;N;;;;; -10762;LINEAR A SIGN A802;Lo;0;L;;;;;N;;;;; -10763;LINEAR A SIGN A803;Lo;0;L;;;;;N;;;;; -10764;LINEAR A SIGN A804;Lo;0;L;;;;;N;;;;; -10765;LINEAR A SIGN A805;Lo;0;L;;;;;N;;;;; -10766;LINEAR A SIGN A806;Lo;0;L;;;;;N;;;;; -10767;LINEAR A SIGN A807;Lo;0;L;;;;;N;;;;; -10780;MODIFIER LETTER SMALL CAPITAL AA;Lm;0;L;;;;;N;;;;; -10781;MODIFIER LETTER SUPERSCRIPT TRIANGULAR COLON;Lm;0;L;<super> 02D0;;;;N;;;;; -10782;MODIFIER LETTER SUPERSCRIPT HALF TRIANGULAR COLON;Lm;0;L;<super> 02D1;;;;N;;;;; -10783;MODIFIER LETTER SMALL AE;Lm;0;L;<super> 00E6;;;;N;;;;; -10784;MODIFIER LETTER SMALL CAPITAL B;Lm;0;L;<super> 0299;;;;N;;;;; -10785;MODIFIER LETTER SMALL B WITH HOOK;Lm;0;L;<super> 0253;;;;N;;;;; -10787;MODIFIER LETTER SMALL DZ DIGRAPH;Lm;0;L;<super> 02A3;;;;N;;;;; -10788;MODIFIER LETTER SMALL DZ DIGRAPH WITH RETROFLEX HOOK;Lm;0;L;<super> AB66;;;;N;;;;; -10789;MODIFIER LETTER SMALL DZ DIGRAPH WITH CURL;Lm;0;L;<super> 02A5;;;;N;;;;; -1078A;MODIFIER LETTER SMALL DEZH DIGRAPH;Lm;0;L;<super> 02A4;;;;N;;;;; -1078B;MODIFIER LETTER SMALL D WITH TAIL;Lm;0;L;<super> 0256;;;;N;;;;; -1078C;MODIFIER LETTER SMALL D WITH HOOK;Lm;0;L;<super> 0257;;;;N;;;;; -1078D;MODIFIER LETTER SMALL D WITH HOOK AND TAIL;Lm;0;L;<super> 1D91;;;;N;;;;; -1078E;MODIFIER LETTER SMALL REVERSED E;Lm;0;L;<super> 0258;;;;N;;;;; -1078F;MODIFIER LETTER SMALL CLOSED REVERSED OPEN E;Lm;0;L;<super> 025E;;;;N;;;;; -10790;MODIFIER LETTER SMALL FENG DIGRAPH;Lm;0;L;<super> 02A9;;;;N;;;;; -10791;MODIFIER LETTER SMALL RAMS HORN;Lm;0;L;<super> 0264;;;;N;;;;; -10792;MODIFIER LETTER SMALL CAPITAL G;Lm;0;L;<super> 0262;;;;N;;;;; -10793;MODIFIER LETTER SMALL G WITH HOOK;Lm;0;L;<super> 0260;;;;N;;;;; -10794;MODIFIER LETTER SMALL CAPITAL G WITH HOOK;Lm;0;L;<super> 029B;;;;N;;;;; -10795;MODIFIER LETTER SMALL H WITH STROKE;Lm;0;L;<super> 0127;;;;N;;;;; -10796;MODIFIER LETTER SMALL CAPITAL H;Lm;0;L;<super> 029C;;;;N;;;;; -10797;MODIFIER LETTER SMALL HENG WITH HOOK;Lm;0;L;<super> 0267;;;;N;;;;; -10798;MODIFIER LETTER SMALL DOTLESS J WITH STROKE AND HOOK;Lm;0;L;<super> 0284;;;;N;;;;; -10799;MODIFIER LETTER SMALL LS DIGRAPH;Lm;0;L;<super> 02AA;;;;N;;;;; -1079A;MODIFIER LETTER SMALL LZ DIGRAPH;Lm;0;L;<super> 02AB;;;;N;;;;; -1079B;MODIFIER LETTER SMALL L WITH BELT;Lm;0;L;<super> 026C;;;;N;;;;; -1079C;MODIFIER LETTER SMALL CAPITAL L WITH BELT;Lm;0;L;<super> 1DF04;;;;N;;;;; -1079D;MODIFIER LETTER SMALL L WITH RETROFLEX HOOK AND BELT;Lm;0;L;<super> A78E;;;;N;;;;; -1079E;MODIFIER LETTER SMALL LEZH;Lm;0;L;<super> 026E;;;;N;;;;; -1079F;MODIFIER LETTER SMALL LEZH WITH RETROFLEX HOOK;Lm;0;L;<super> 1DF05;;;;N;;;;; -107A0;MODIFIER LETTER SMALL TURNED Y;Lm;0;L;<super> 028E;;;;N;;;;; -107A1;MODIFIER LETTER SMALL TURNED Y WITH BELT;Lm;0;L;<super> 1DF06;;;;N;;;;; -107A2;MODIFIER LETTER SMALL O WITH STROKE;Lm;0;L;<super> 00F8;;;;N;;;;; -107A3;MODIFIER LETTER SMALL CAPITAL OE;Lm;0;L;<super> 0276;;;;N;;;;; -107A4;MODIFIER LETTER SMALL CLOSED OMEGA;Lm;0;L;<super> 0277;;;;N;;;;; -107A5;MODIFIER LETTER SMALL Q;Lm;0;L;<super> 0071;;;;N;;;;; -107A6;MODIFIER LETTER SMALL TURNED R WITH LONG LEG;Lm;0;L;<super> 027A;;;;N;;;;; -107A7;MODIFIER LETTER SMALL TURNED R WITH LONG LEG AND RETROFLEX HOOK;Lm;0;L;<super> 1DF08;;;;N;;;;; -107A8;MODIFIER LETTER SMALL R WITH TAIL;Lm;0;L;<super> 027D;;;;N;;;;; -107A9;MODIFIER LETTER SMALL R WITH FISHHOOK;Lm;0;L;<super> 027E;;;;N;;;;; -107AA;MODIFIER LETTER SMALL CAPITAL R;Lm;0;L;<super> 0280;;;;N;;;;; -107AB;MODIFIER LETTER SMALL TC DIGRAPH WITH CURL;Lm;0;L;<super> 02A8;;;;N;;;;; -107AC;MODIFIER LETTER SMALL TS DIGRAPH;Lm;0;L;<super> 02A6;;;;N;;;;; -107AD;MODIFIER LETTER SMALL TS DIGRAPH WITH RETROFLEX HOOK;Lm;0;L;<super> AB67;;;;N;;;;; -107AE;MODIFIER LETTER SMALL TESH DIGRAPH;Lm;0;L;<super> 02A7;;;;N;;;;; -107AF;MODIFIER LETTER SMALL T WITH RETROFLEX HOOK;Lm;0;L;<super> 0288;;;;N;;;;; -107B0;MODIFIER LETTER SMALL V WITH RIGHT HOOK;Lm;0;L;<super> 2C71;;;;N;;;;; -107B2;MODIFIER LETTER SMALL CAPITAL Y;Lm;0;L;<super> 028F;;;;N;;;;; -107B3;MODIFIER LETTER GLOTTAL STOP WITH STROKE;Lm;0;L;<super> 02A1;;;;N;;;;; -107B4;MODIFIER LETTER REVERSED GLOTTAL STOP WITH STROKE;Lm;0;L;<super> 02A2;;;;N;;;;; -107B5;MODIFIER LETTER BILABIAL CLICK;Lm;0;L;<super> 0298;;;;N;;;;; -107B6;MODIFIER LETTER DENTAL CLICK;Lm;0;L;<super> 01C0;;;;N;;;;; -107B7;MODIFIER LETTER LATERAL CLICK;Lm;0;L;<super> 01C1;;;;N;;;;; -107B8;MODIFIER LETTER ALVEOLAR CLICK;Lm;0;L;<super> 01C2;;;;N;;;;; -107B9;MODIFIER LETTER RETROFLEX CLICK WITH RETROFLEX HOOK;Lm;0;L;<super> 1DF0A;;;;N;;;;; -107BA;MODIFIER LETTER SMALL S WITH CURL;Lm;0;L;<super> 1DF1E;;;;N;;;;; -10800;CYPRIOT SYLLABLE A;Lo;0;R;;;;;N;;;;; -10801;CYPRIOT SYLLABLE E;Lo;0;R;;;;;N;;;;; -10802;CYPRIOT SYLLABLE I;Lo;0;R;;;;;N;;;;; -10803;CYPRIOT SYLLABLE O;Lo;0;R;;;;;N;;;;; -10804;CYPRIOT SYLLABLE U;Lo;0;R;;;;;N;;;;; -10805;CYPRIOT SYLLABLE JA;Lo;0;R;;;;;N;;;;; -10808;CYPRIOT SYLLABLE JO;Lo;0;R;;;;;N;;;;; -1080A;CYPRIOT SYLLABLE KA;Lo;0;R;;;;;N;;;;; -1080B;CYPRIOT SYLLABLE KE;Lo;0;R;;;;;N;;;;; -1080C;CYPRIOT SYLLABLE KI;Lo;0;R;;;;;N;;;;; -1080D;CYPRIOT SYLLABLE KO;Lo;0;R;;;;;N;;;;; -1080E;CYPRIOT SYLLABLE KU;Lo;0;R;;;;;N;;;;; -1080F;CYPRIOT SYLLABLE LA;Lo;0;R;;;;;N;;;;; -10810;CYPRIOT SYLLABLE LE;Lo;0;R;;;;;N;;;;; -10811;CYPRIOT SYLLABLE LI;Lo;0;R;;;;;N;;;;; -10812;CYPRIOT SYLLABLE LO;Lo;0;R;;;;;N;;;;; -10813;CYPRIOT SYLLABLE LU;Lo;0;R;;;;;N;;;;; -10814;CYPRIOT SYLLABLE MA;Lo;0;R;;;;;N;;;;; -10815;CYPRIOT SYLLABLE ME;Lo;0;R;;;;;N;;;;; -10816;CYPRIOT SYLLABLE MI;Lo;0;R;;;;;N;;;;; -10817;CYPRIOT SYLLABLE MO;Lo;0;R;;;;;N;;;;; -10818;CYPRIOT SYLLABLE MU;Lo;0;R;;;;;N;;;;; -10819;CYPRIOT SYLLABLE NA;Lo;0;R;;;;;N;;;;; -1081A;CYPRIOT SYLLABLE NE;Lo;0;R;;;;;N;;;;; -1081B;CYPRIOT SYLLABLE NI;Lo;0;R;;;;;N;;;;; -1081C;CYPRIOT SYLLABLE NO;Lo;0;R;;;;;N;;;;; -1081D;CYPRIOT SYLLABLE NU;Lo;0;R;;;;;N;;;;; -1081E;CYPRIOT SYLLABLE PA;Lo;0;R;;;;;N;;;;; -1081F;CYPRIOT SYLLABLE PE;Lo;0;R;;;;;N;;;;; -10820;CYPRIOT SYLLABLE PI;Lo;0;R;;;;;N;;;;; -10821;CYPRIOT SYLLABLE PO;Lo;0;R;;;;;N;;;;; -10822;CYPRIOT SYLLABLE PU;Lo;0;R;;;;;N;;;;; -10823;CYPRIOT SYLLABLE RA;Lo;0;R;;;;;N;;;;; -10824;CYPRIOT SYLLABLE RE;Lo;0;R;;;;;N;;;;; -10825;CYPRIOT SYLLABLE RI;Lo;0;R;;;;;N;;;;; -10826;CYPRIOT SYLLABLE RO;Lo;0;R;;;;;N;;;;; -10827;CYPRIOT SYLLABLE RU;Lo;0;R;;;;;N;;;;; -10828;CYPRIOT SYLLABLE SA;Lo;0;R;;;;;N;;;;; -10829;CYPRIOT SYLLABLE SE;Lo;0;R;;;;;N;;;;; -1082A;CYPRIOT SYLLABLE SI;Lo;0;R;;;;;N;;;;; -1082B;CYPRIOT SYLLABLE SO;Lo;0;R;;;;;N;;;;; -1082C;CYPRIOT SYLLABLE SU;Lo;0;R;;;;;N;;;;; -1082D;CYPRIOT SYLLABLE TA;Lo;0;R;;;;;N;;;;; -1082E;CYPRIOT SYLLABLE TE;Lo;0;R;;;;;N;;;;; -1082F;CYPRIOT SYLLABLE TI;Lo;0;R;;;;;N;;;;; -10830;CYPRIOT SYLLABLE TO;Lo;0;R;;;;;N;;;;; -10831;CYPRIOT SYLLABLE TU;Lo;0;R;;;;;N;;;;; -10832;CYPRIOT SYLLABLE WA;Lo;0;R;;;;;N;;;;; -10833;CYPRIOT SYLLABLE WE;Lo;0;R;;;;;N;;;;; -10834;CYPRIOT SYLLABLE WI;Lo;0;R;;;;;N;;;;; -10835;CYPRIOT SYLLABLE WO;Lo;0;R;;;;;N;;;;; -10837;CYPRIOT SYLLABLE XA;Lo;0;R;;;;;N;;;;; -10838;CYPRIOT SYLLABLE XE;Lo;0;R;;;;;N;;;;; -1083C;CYPRIOT SYLLABLE ZA;Lo;0;R;;;;;N;;;;; -1083F;CYPRIOT SYLLABLE ZO;Lo;0;R;;;;;N;;;;; -10840;IMPERIAL ARAMAIC LETTER ALEPH;Lo;0;R;;;;;N;;;;; -10841;IMPERIAL ARAMAIC LETTER BETH;Lo;0;R;;;;;N;;;;; -10842;IMPERIAL ARAMAIC LETTER GIMEL;Lo;0;R;;;;;N;;;;; -10843;IMPERIAL ARAMAIC LETTER DALETH;Lo;0;R;;;;;N;;;;; -10844;IMPERIAL ARAMAIC LETTER HE;Lo;0;R;;;;;N;;;;; -10845;IMPERIAL ARAMAIC LETTER WAW;Lo;0;R;;;;;N;;;;; -10846;IMPERIAL ARAMAIC LETTER ZAYIN;Lo;0;R;;;;;N;;;;; -10847;IMPERIAL ARAMAIC LETTER HETH;Lo;0;R;;;;;N;;;;; -10848;IMPERIAL ARAMAIC LETTER TETH;Lo;0;R;;;;;N;;;;; -10849;IMPERIAL ARAMAIC LETTER YODH;Lo;0;R;;;;;N;;;;; -1084A;IMPERIAL ARAMAIC LETTER KAPH;Lo;0;R;;;;;N;;;;; -1084B;IMPERIAL ARAMAIC LETTER LAMEDH;Lo;0;R;;;;;N;;;;; -1084C;IMPERIAL ARAMAIC LETTER MEM;Lo;0;R;;;;;N;;;;; -1084D;IMPERIAL ARAMAIC LETTER NUN;Lo;0;R;;;;;N;;;;; -1084E;IMPERIAL ARAMAIC LETTER SAMEKH;Lo;0;R;;;;;N;;;;; -1084F;IMPERIAL ARAMAIC LETTER AYIN;Lo;0;R;;;;;N;;;;; -10850;IMPERIAL ARAMAIC LETTER PE;Lo;0;R;;;;;N;;;;; -10851;IMPERIAL ARAMAIC LETTER SADHE;Lo;0;R;;;;;N;;;;; -10852;IMPERIAL ARAMAIC LETTER QOPH;Lo;0;R;;;;;N;;;;; -10853;IMPERIAL ARAMAIC LETTER RESH;Lo;0;R;;;;;N;;;;; -10854;IMPERIAL ARAMAIC LETTER SHIN;Lo;0;R;;;;;N;;;;; -10855;IMPERIAL ARAMAIC LETTER TAW;Lo;0;R;;;;;N;;;;; -10857;IMPERIAL ARAMAIC SECTION SIGN;Po;0;R;;;;;N;;;;; -10858;IMPERIAL ARAMAIC NUMBER ONE;No;0;R;;;;1;N;;;;; -10859;IMPERIAL ARAMAIC NUMBER TWO;No;0;R;;;;2;N;;;;; -1085A;IMPERIAL ARAMAIC NUMBER THREE;No;0;R;;;;3;N;;;;; -1085B;IMPERIAL ARAMAIC NUMBER TEN;No;0;R;;;;10;N;;;;; -1085C;IMPERIAL ARAMAIC NUMBER TWENTY;No;0;R;;;;20;N;;;;; -1085D;IMPERIAL ARAMAIC NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; -1085E;IMPERIAL ARAMAIC NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;; -1085F;IMPERIAL ARAMAIC NUMBER TEN THOUSAND;No;0;R;;;;10000;N;;;;; -10860;PALMYRENE LETTER ALEPH;Lo;0;R;;;;;N;;;;; -10861;PALMYRENE LETTER BETH;Lo;0;R;;;;;N;;;;; -10862;PALMYRENE LETTER GIMEL;Lo;0;R;;;;;N;;;;; -10863;PALMYRENE LETTER DALETH;Lo;0;R;;;;;N;;;;; -10864;PALMYRENE LETTER HE;Lo;0;R;;;;;N;;;;; -10865;PALMYRENE LETTER WAW;Lo;0;R;;;;;N;;;;; -10866;PALMYRENE LETTER ZAYIN;Lo;0;R;;;;;N;;;;; -10867;PALMYRENE LETTER HETH;Lo;0;R;;;;;N;;;;; -10868;PALMYRENE LETTER TETH;Lo;0;R;;;;;N;;;;; -10869;PALMYRENE LETTER YODH;Lo;0;R;;;;;N;;;;; -1086A;PALMYRENE LETTER KAPH;Lo;0;R;;;;;N;;;;; -1086B;PALMYRENE LETTER LAMEDH;Lo;0;R;;;;;N;;;;; -1086C;PALMYRENE LETTER MEM;Lo;0;R;;;;;N;;;;; -1086D;PALMYRENE LETTER FINAL NUN;Lo;0;R;;;;;N;;;;; -1086E;PALMYRENE LETTER NUN;Lo;0;R;;;;;N;;;;; -1086F;PALMYRENE LETTER SAMEKH;Lo;0;R;;;;;N;;;;; -10870;PALMYRENE LETTER AYIN;Lo;0;R;;;;;N;;;;; -10871;PALMYRENE LETTER PE;Lo;0;R;;;;;N;;;;; -10872;PALMYRENE LETTER SADHE;Lo;0;R;;;;;N;;;;; -10873;PALMYRENE LETTER QOPH;Lo;0;R;;;;;N;;;;; -10874;PALMYRENE LETTER RESH;Lo;0;R;;;;;N;;;;; -10875;PALMYRENE LETTER SHIN;Lo;0;R;;;;;N;;;;; -10876;PALMYRENE LETTER TAW;Lo;0;R;;;;;N;;;;; -10877;PALMYRENE LEFT-POINTING FLEURON;So;0;R;;;;;N;;;;; -10878;PALMYRENE RIGHT-POINTING FLEURON;So;0;R;;;;;N;;;;; -10879;PALMYRENE NUMBER ONE;No;0;R;;;;1;N;;;;; -1087A;PALMYRENE NUMBER TWO;No;0;R;;;;2;N;;;;; -1087B;PALMYRENE NUMBER THREE;No;0;R;;;;3;N;;;;; -1087C;PALMYRENE NUMBER FOUR;No;0;R;;;;4;N;;;;; -1087D;PALMYRENE NUMBER FIVE;No;0;R;;;;5;N;;;;; -1087E;PALMYRENE NUMBER TEN;No;0;R;;;;10;N;;;;; -1087F;PALMYRENE NUMBER TWENTY;No;0;R;;;;20;N;;;;; -10880;NABATAEAN LETTER FINAL ALEPH;Lo;0;R;;;;;N;;;;; -10881;NABATAEAN LETTER ALEPH;Lo;0;R;;;;;N;;;;; -10882;NABATAEAN LETTER FINAL BETH;Lo;0;R;;;;;N;;;;; -10883;NABATAEAN LETTER BETH;Lo;0;R;;;;;N;;;;; -10884;NABATAEAN LETTER GIMEL;Lo;0;R;;;;;N;;;;; -10885;NABATAEAN LETTER DALETH;Lo;0;R;;;;;N;;;;; -10886;NABATAEAN LETTER FINAL HE;Lo;0;R;;;;;N;;;;; -10887;NABATAEAN LETTER HE;Lo;0;R;;;;;N;;;;; -10888;NABATAEAN LETTER WAW;Lo;0;R;;;;;N;;;;; -10889;NABATAEAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;; -1088A;NABATAEAN LETTER HETH;Lo;0;R;;;;;N;;;;; -1088B;NABATAEAN LETTER TETH;Lo;0;R;;;;;N;;;;; -1088C;NABATAEAN LETTER FINAL YODH;Lo;0;R;;;;;N;;;;; -1088D;NABATAEAN LETTER YODH;Lo;0;R;;;;;N;;;;; -1088E;NABATAEAN LETTER FINAL KAPH;Lo;0;R;;;;;N;;;;; -1088F;NABATAEAN LETTER KAPH;Lo;0;R;;;;;N;;;;; -10890;NABATAEAN LETTER FINAL LAMEDH;Lo;0;R;;;;;N;;;;; -10891;NABATAEAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;; -10892;NABATAEAN LETTER FINAL MEM;Lo;0;R;;;;;N;;;;; -10893;NABATAEAN LETTER MEM;Lo;0;R;;;;;N;;;;; -10894;NABATAEAN LETTER FINAL NUN;Lo;0;R;;;;;N;;;;; -10895;NABATAEAN LETTER NUN;Lo;0;R;;;;;N;;;;; -10896;NABATAEAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;; -10897;NABATAEAN LETTER AYIN;Lo;0;R;;;;;N;;;;; -10898;NABATAEAN LETTER PE;Lo;0;R;;;;;N;;;;; -10899;NABATAEAN LETTER SADHE;Lo;0;R;;;;;N;;;;; -1089A;NABATAEAN LETTER QOPH;Lo;0;R;;;;;N;;;;; -1089B;NABATAEAN LETTER RESH;Lo;0;R;;;;;N;;;;; -1089C;NABATAEAN LETTER FINAL SHIN;Lo;0;R;;;;;N;;;;; -1089D;NABATAEAN LETTER SHIN;Lo;0;R;;;;;N;;;;; -1089E;NABATAEAN LETTER TAW;Lo;0;R;;;;;N;;;;; -108A7;NABATAEAN NUMBER ONE;No;0;R;;;;1;N;;;;; -108A8;NABATAEAN NUMBER TWO;No;0;R;;;;2;N;;;;; -108A9;NABATAEAN NUMBER THREE;No;0;R;;;;3;N;;;;; -108AA;NABATAEAN NUMBER FOUR;No;0;R;;;;4;N;;;;; -108AB;NABATAEAN CRUCIFORM NUMBER FOUR;No;0;R;;;;4;N;;;;; -108AC;NABATAEAN NUMBER FIVE;No;0;R;;;;5;N;;;;; -108AD;NABATAEAN NUMBER TEN;No;0;R;;;;10;N;;;;; -108AE;NABATAEAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; -108AF;NABATAEAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; -108E0;HATRAN LETTER ALEPH;Lo;0;R;;;;;N;;;;; -108E1;HATRAN LETTER BETH;Lo;0;R;;;;;N;;;;; -108E2;HATRAN LETTER GIMEL;Lo;0;R;;;;;N;;;;; -108E3;HATRAN LETTER DALETH-RESH;Lo;0;R;;;;;N;;;;; -108E4;HATRAN LETTER HE;Lo;0;R;;;;;N;;;;; -108E5;HATRAN LETTER WAW;Lo;0;R;;;;;N;;;;; -108E6;HATRAN LETTER ZAYN;Lo;0;R;;;;;N;;;;; -108E7;HATRAN LETTER HETH;Lo;0;R;;;;;N;;;;; -108E8;HATRAN LETTER TETH;Lo;0;R;;;;;N;;;;; -108E9;HATRAN LETTER YODH;Lo;0;R;;;;;N;;;;; -108EA;HATRAN LETTER KAPH;Lo;0;R;;;;;N;;;;; -108EB;HATRAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;; -108EC;HATRAN LETTER MEM;Lo;0;R;;;;;N;;;;; -108ED;HATRAN LETTER NUN;Lo;0;R;;;;;N;;;;; -108EE;HATRAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;; -108EF;HATRAN LETTER AYN;Lo;0;R;;;;;N;;;;; -108F0;HATRAN LETTER PE;Lo;0;R;;;;;N;;;;; -108F1;HATRAN LETTER SADHE;Lo;0;R;;;;;N;;;;; -108F2;HATRAN LETTER QOPH;Lo;0;R;;;;;N;;;;; -108F4;HATRAN LETTER SHIN;Lo;0;R;;;;;N;;;;; -108F5;HATRAN LETTER TAW;Lo;0;R;;;;;N;;;;; -108FB;HATRAN NUMBER ONE;No;0;R;;;;1;N;;;;; -108FC;HATRAN NUMBER FIVE;No;0;R;;;;5;N;;;;; -108FD;HATRAN NUMBER TEN;No;0;R;;;;10;N;;;;; -108FE;HATRAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; -108FF;HATRAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; -10900;PHOENICIAN LETTER ALF;Lo;0;R;;;;;N;;;;; -10901;PHOENICIAN LETTER BET;Lo;0;R;;;;;N;;;;; -10902;PHOENICIAN LETTER GAML;Lo;0;R;;;;;N;;;;; -10903;PHOENICIAN LETTER DELT;Lo;0;R;;;;;N;;;;; -10904;PHOENICIAN LETTER HE;Lo;0;R;;;;;N;;;;; -10905;PHOENICIAN LETTER WAU;Lo;0;R;;;;;N;;;;; -10906;PHOENICIAN LETTER ZAI;Lo;0;R;;;;;N;;;;; -10907;PHOENICIAN LETTER HET;Lo;0;R;;;;;N;;;;; -10908;PHOENICIAN LETTER TET;Lo;0;R;;;;;N;;;;; -10909;PHOENICIAN LETTER YOD;Lo;0;R;;;;;N;;;;; -1090A;PHOENICIAN LETTER KAF;Lo;0;R;;;;;N;;;;; -1090B;PHOENICIAN LETTER LAMD;Lo;0;R;;;;;N;;;;; -1090C;PHOENICIAN LETTER MEM;Lo;0;R;;;;;N;;;;; -1090D;PHOENICIAN LETTER NUN;Lo;0;R;;;;;N;;;;; -1090E;PHOENICIAN LETTER SEMK;Lo;0;R;;;;;N;;;;; -1090F;PHOENICIAN LETTER AIN;Lo;0;R;;;;;N;;;;; -10910;PHOENICIAN LETTER PE;Lo;0;R;;;;;N;;;;; -10911;PHOENICIAN LETTER SADE;Lo;0;R;;;;;N;;;;; -10912;PHOENICIAN LETTER QOF;Lo;0;R;;;;;N;;;;; -10913;PHOENICIAN LETTER ROSH;Lo;0;R;;;;;N;;;;; -10914;PHOENICIAN LETTER SHIN;Lo;0;R;;;;;N;;;;; -10915;PHOENICIAN LETTER TAU;Lo;0;R;;;;;N;;;;; -10916;PHOENICIAN NUMBER ONE;No;0;R;;;;1;N;;;;; -10917;PHOENICIAN NUMBER TEN;No;0;R;;;;10;N;;;;; -10918;PHOENICIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; -10919;PHOENICIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; -1091A;PHOENICIAN NUMBER TWO;No;0;R;;;;2;N;;;;; -1091B;PHOENICIAN NUMBER THREE;No;0;R;;;;3;N;;;;; -1091F;PHOENICIAN WORD SEPARATOR;Po;0;ON;;;;;N;;;;; -10920;LYDIAN LETTER A;Lo;0;R;;;;;N;;;;; -10921;LYDIAN LETTER B;Lo;0;R;;;;;N;;;;; -10922;LYDIAN LETTER G;Lo;0;R;;;;;N;;;;; -10923;LYDIAN LETTER D;Lo;0;R;;;;;N;;;;; -10924;LYDIAN LETTER E;Lo;0;R;;;;;N;;;;; -10925;LYDIAN LETTER V;Lo;0;R;;;;;N;;;;; -10926;LYDIAN LETTER I;Lo;0;R;;;;;N;;;;; -10927;LYDIAN LETTER Y;Lo;0;R;;;;;N;;;;; -10928;LYDIAN LETTER K;Lo;0;R;;;;;N;;;;; -10929;LYDIAN LETTER L;Lo;0;R;;;;;N;;;;; -1092A;LYDIAN LETTER M;Lo;0;R;;;;;N;;;;; -1092B;LYDIAN LETTER N;Lo;0;R;;;;;N;;;;; -1092C;LYDIAN LETTER O;Lo;0;R;;;;;N;;;;; -1092D;LYDIAN LETTER R;Lo;0;R;;;;;N;;;;; -1092E;LYDIAN LETTER SS;Lo;0;R;;;;;N;;;;; -1092F;LYDIAN LETTER T;Lo;0;R;;;;;N;;;;; -10930;LYDIAN LETTER U;Lo;0;R;;;;;N;;;;; -10931;LYDIAN LETTER F;Lo;0;R;;;;;N;;;;; -10932;LYDIAN LETTER Q;Lo;0;R;;;;;N;;;;; -10933;LYDIAN LETTER S;Lo;0;R;;;;;N;;;;; -10934;LYDIAN LETTER TT;Lo;0;R;;;;;N;;;;; -10935;LYDIAN LETTER AN;Lo;0;R;;;;;N;;;;; -10936;LYDIAN LETTER EN;Lo;0;R;;;;;N;;;;; -10937;LYDIAN LETTER LY;Lo;0;R;;;;;N;;;;; -10938;LYDIAN LETTER NN;Lo;0;R;;;;;N;;;;; -10939;LYDIAN LETTER C;Lo;0;R;;;;;N;;;;; -1093F;LYDIAN TRIANGULAR MARK;Po;0;R;;;;;N;;;;; -10980;MEROITIC HIEROGLYPHIC LETTER A;Lo;0;R;;;;;N;;;;; -10981;MEROITIC HIEROGLYPHIC LETTER E;Lo;0;R;;;;;N;;;;; -10982;MEROITIC HIEROGLYPHIC LETTER I;Lo;0;R;;;;;N;;;;; -10983;MEROITIC HIEROGLYPHIC LETTER O;Lo;0;R;;;;;N;;;;; -10984;MEROITIC HIEROGLYPHIC LETTER YA;Lo;0;R;;;;;N;;;;; -10985;MEROITIC HIEROGLYPHIC LETTER WA;Lo;0;R;;;;;N;;;;; -10986;MEROITIC HIEROGLYPHIC LETTER BA;Lo;0;R;;;;;N;;;;; -10987;MEROITIC HIEROGLYPHIC LETTER BA-2;Lo;0;R;;;;;N;;;;; -10988;MEROITIC HIEROGLYPHIC LETTER PA;Lo;0;R;;;;;N;;;;; -10989;MEROITIC HIEROGLYPHIC LETTER MA;Lo;0;R;;;;;N;;;;; -1098A;MEROITIC HIEROGLYPHIC LETTER NA;Lo;0;R;;;;;N;;;;; -1098B;MEROITIC HIEROGLYPHIC LETTER NA-2;Lo;0;R;;;;;N;;;;; -1098C;MEROITIC HIEROGLYPHIC LETTER NE;Lo;0;R;;;;;N;;;;; -1098D;MEROITIC HIEROGLYPHIC LETTER NE-2;Lo;0;R;;;;;N;;;;; -1098E;MEROITIC HIEROGLYPHIC LETTER RA;Lo;0;R;;;;;N;;;;; -1098F;MEROITIC HIEROGLYPHIC LETTER RA-2;Lo;0;R;;;;;N;;;;; -10990;MEROITIC HIEROGLYPHIC LETTER LA;Lo;0;R;;;;;N;;;;; -10991;MEROITIC HIEROGLYPHIC LETTER KHA;Lo;0;R;;;;;N;;;;; -10992;MEROITIC HIEROGLYPHIC LETTER HHA;Lo;0;R;;;;;N;;;;; -10993;MEROITIC HIEROGLYPHIC LETTER SA;Lo;0;R;;;;;N;;;;; -10994;MEROITIC HIEROGLYPHIC LETTER SA-2;Lo;0;R;;;;;N;;;;; -10995;MEROITIC HIEROGLYPHIC LETTER SE;Lo;0;R;;;;;N;;;;; -10996;MEROITIC HIEROGLYPHIC LETTER KA;Lo;0;R;;;;;N;;;;; -10997;MEROITIC HIEROGLYPHIC LETTER QA;Lo;0;R;;;;;N;;;;; -10998;MEROITIC HIEROGLYPHIC LETTER TA;Lo;0;R;;;;;N;;;;; -10999;MEROITIC HIEROGLYPHIC LETTER TA-2;Lo;0;R;;;;;N;;;;; -1099A;MEROITIC HIEROGLYPHIC LETTER TE;Lo;0;R;;;;;N;;;;; -1099B;MEROITIC HIEROGLYPHIC LETTER TE-2;Lo;0;R;;;;;N;;;;; -1099C;MEROITIC HIEROGLYPHIC LETTER TO;Lo;0;R;;;;;N;;;;; -1099D;MEROITIC HIEROGLYPHIC LETTER DA;Lo;0;R;;;;;N;;;;; -1099E;MEROITIC HIEROGLYPHIC SYMBOL VIDJ;Lo;0;R;;;;;N;;;;; -1099F;MEROITIC HIEROGLYPHIC SYMBOL VIDJ-2;Lo;0;R;;;;;N;;;;; -109A0;MEROITIC CURSIVE LETTER A;Lo;0;R;;;;;N;;;;; -109A1;MEROITIC CURSIVE LETTER E;Lo;0;R;;;;;N;;;;; -109A2;MEROITIC CURSIVE LETTER I;Lo;0;R;;;;;N;;;;; -109A3;MEROITIC CURSIVE LETTER O;Lo;0;R;;;;;N;;;;; -109A4;MEROITIC CURSIVE LETTER YA;Lo;0;R;;;;;N;;;;; -109A5;MEROITIC CURSIVE LETTER WA;Lo;0;R;;;;;N;;;;; -109A6;MEROITIC CURSIVE LETTER BA;Lo;0;R;;;;;N;;;;; -109A7;MEROITIC CURSIVE LETTER PA;Lo;0;R;;;;;N;;;;; -109A8;MEROITIC CURSIVE LETTER MA;Lo;0;R;;;;;N;;;;; -109A9;MEROITIC CURSIVE LETTER NA;Lo;0;R;;;;;N;;;;; -109AA;MEROITIC CURSIVE LETTER NE;Lo;0;R;;;;;N;;;;; -109AB;MEROITIC CURSIVE LETTER RA;Lo;0;R;;;;;N;;;;; -109AC;MEROITIC CURSIVE LETTER LA;Lo;0;R;;;;;N;;;;; -109AD;MEROITIC CURSIVE LETTER KHA;Lo;0;R;;;;;N;;;;; -109AE;MEROITIC CURSIVE LETTER HHA;Lo;0;R;;;;;N;;;;; -109AF;MEROITIC CURSIVE LETTER SA;Lo;0;R;;;;;N;;;;; -109B0;MEROITIC CURSIVE LETTER ARCHAIC SA;Lo;0;R;;;;;N;;;;; -109B1;MEROITIC CURSIVE LETTER SE;Lo;0;R;;;;;N;;;;; -109B2;MEROITIC CURSIVE LETTER KA;Lo;0;R;;;;;N;;;;; -109B3;MEROITIC CURSIVE LETTER QA;Lo;0;R;;;;;N;;;;; -109B4;MEROITIC CURSIVE LETTER TA;Lo;0;R;;;;;N;;;;; -109B5;MEROITIC CURSIVE LETTER TE;Lo;0;R;;;;;N;;;;; -109B6;MEROITIC CURSIVE LETTER TO;Lo;0;R;;;;;N;;;;; -109B7;MEROITIC CURSIVE LETTER DA;Lo;0;R;;;;;N;;;;; -109BC;MEROITIC CURSIVE FRACTION ELEVEN TWELFTHS;No;0;R;;;;11/12;N;;;;; -109BD;MEROITIC CURSIVE FRACTION ONE HALF;No;0;R;;;;1/2;N;;;;; -109BE;MEROITIC CURSIVE LOGOGRAM RMT;Lo;0;R;;;;;N;;;;; -109BF;MEROITIC CURSIVE LOGOGRAM IMN;Lo;0;R;;;;;N;;;;; -109C0;MEROITIC CURSIVE NUMBER ONE;No;0;R;;;;1;N;;;;; -109C1;MEROITIC CURSIVE NUMBER TWO;No;0;R;;;;2;N;;;;; -109C2;MEROITIC CURSIVE NUMBER THREE;No;0;R;;;;3;N;;;;; -109C3;MEROITIC CURSIVE NUMBER FOUR;No;0;R;;;;4;N;;;;; -109C4;MEROITIC CURSIVE NUMBER FIVE;No;0;R;;;;5;N;;;;; -109C5;MEROITIC CURSIVE NUMBER SIX;No;0;R;;;;6;N;;;;; -109C6;MEROITIC CURSIVE NUMBER SEVEN;No;0;R;;;;7;N;;;;; -109C7;MEROITIC CURSIVE NUMBER EIGHT;No;0;R;;;;8;N;;;;; -109C8;MEROITIC CURSIVE NUMBER NINE;No;0;R;;;;9;N;;;;; -109C9;MEROITIC CURSIVE NUMBER TEN;No;0;R;;;;10;N;;;;; -109CA;MEROITIC CURSIVE NUMBER TWENTY;No;0;R;;;;20;N;;;;; -109CB;MEROITIC CURSIVE NUMBER THIRTY;No;0;R;;;;30;N;;;;; -109CC;MEROITIC CURSIVE NUMBER FORTY;No;0;R;;;;40;N;;;;; -109CD;MEROITIC CURSIVE NUMBER FIFTY;No;0;R;;;;50;N;;;;; -109CE;MEROITIC CURSIVE NUMBER SIXTY;No;0;R;;;;60;N;;;;; -109CF;MEROITIC CURSIVE NUMBER SEVENTY;No;0;R;;;;70;N;;;;; -109D2;MEROITIC CURSIVE NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; -109D3;MEROITIC CURSIVE NUMBER TWO HUNDRED;No;0;R;;;;200;N;;;;; -109D4;MEROITIC CURSIVE NUMBER THREE HUNDRED;No;0;R;;;;300;N;;;;; -109D5;MEROITIC CURSIVE NUMBER FOUR HUNDRED;No;0;R;;;;400;N;;;;; -109D6;MEROITIC CURSIVE NUMBER FIVE HUNDRED;No;0;R;;;;500;N;;;;; -109D7;MEROITIC CURSIVE NUMBER SIX HUNDRED;No;0;R;;;;600;N;;;;; -109D8;MEROITIC CURSIVE NUMBER SEVEN HUNDRED;No;0;R;;;;700;N;;;;; -109D9;MEROITIC CURSIVE NUMBER EIGHT HUNDRED;No;0;R;;;;800;N;;;;; -109DA;MEROITIC CURSIVE NUMBER NINE HUNDRED;No;0;R;;;;900;N;;;;; -109DB;MEROITIC CURSIVE NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;; -109DC;MEROITIC CURSIVE NUMBER TWO THOUSAND;No;0;R;;;;2000;N;;;;; -109DD;MEROITIC CURSIVE NUMBER THREE THOUSAND;No;0;R;;;;3000;N;;;;; -109DE;MEROITIC CURSIVE NUMBER FOUR THOUSAND;No;0;R;;;;4000;N;;;;; -109DF;MEROITIC CURSIVE NUMBER FIVE THOUSAND;No;0;R;;;;5000;N;;;;; -109E0;MEROITIC CURSIVE NUMBER SIX THOUSAND;No;0;R;;;;6000;N;;;;; -109E1;MEROITIC CURSIVE NUMBER SEVEN THOUSAND;No;0;R;;;;7000;N;;;;; -109E2;MEROITIC CURSIVE NUMBER EIGHT THOUSAND;No;0;R;;;;8000;N;;;;; -109E3;MEROITIC CURSIVE NUMBER NINE THOUSAND;No;0;R;;;;9000;N;;;;; -109E4;MEROITIC CURSIVE NUMBER TEN THOUSAND;No;0;R;;;;10000;N;;;;; -109E5;MEROITIC CURSIVE NUMBER TWENTY THOUSAND;No;0;R;;;;20000;N;;;;; -109E6;MEROITIC CURSIVE NUMBER THIRTY THOUSAND;No;0;R;;;;30000;N;;;;; -109E7;MEROITIC CURSIVE NUMBER FORTY THOUSAND;No;0;R;;;;40000;N;;;;; -109E8;MEROITIC CURSIVE NUMBER FIFTY THOUSAND;No;0;R;;;;50000;N;;;;; -109E9;MEROITIC CURSIVE NUMBER SIXTY THOUSAND;No;0;R;;;;60000;N;;;;; -109EA;MEROITIC CURSIVE NUMBER SEVENTY THOUSAND;No;0;R;;;;70000;N;;;;; -109EB;MEROITIC CURSIVE NUMBER EIGHTY THOUSAND;No;0;R;;;;80000;N;;;;; -109EC;MEROITIC CURSIVE NUMBER NINETY THOUSAND;No;0;R;;;;90000;N;;;;; -109ED;MEROITIC CURSIVE NUMBER ONE HUNDRED THOUSAND;No;0;R;;;;100000;N;;;;; -109EE;MEROITIC CURSIVE NUMBER TWO HUNDRED THOUSAND;No;0;R;;;;200000;N;;;;; -109EF;MEROITIC CURSIVE NUMBER THREE HUNDRED THOUSAND;No;0;R;;;;300000;N;;;;; -109F0;MEROITIC CURSIVE NUMBER FOUR HUNDRED THOUSAND;No;0;R;;;;400000;N;;;;; -109F1;MEROITIC CURSIVE NUMBER FIVE HUNDRED THOUSAND;No;0;R;;;;500000;N;;;;; -109F2;MEROITIC CURSIVE NUMBER SIX HUNDRED THOUSAND;No;0;R;;;;600000;N;;;;; -109F3;MEROITIC CURSIVE NUMBER SEVEN HUNDRED THOUSAND;No;0;R;;;;700000;N;;;;; -109F4;MEROITIC CURSIVE NUMBER EIGHT HUNDRED THOUSAND;No;0;R;;;;800000;N;;;;; -109F5;MEROITIC CURSIVE NUMBER NINE HUNDRED THOUSAND;No;0;R;;;;900000;N;;;;; -109F6;MEROITIC CURSIVE FRACTION ONE TWELFTH;No;0;R;;;;1/12;N;;;;; -109F7;MEROITIC CURSIVE FRACTION TWO TWELFTHS;No;0;R;;;;2/12;N;;;;; -109F8;MEROITIC CURSIVE FRACTION THREE TWELFTHS;No;0;R;;;;3/12;N;;;;; -109F9;MEROITIC CURSIVE FRACTION FOUR TWELFTHS;No;0;R;;;;4/12;N;;;;; -109FA;MEROITIC CURSIVE FRACTION FIVE TWELFTHS;No;0;R;;;;5/12;N;;;;; -109FB;MEROITIC CURSIVE FRACTION SIX TWELFTHS;No;0;R;;;;6/12;N;;;;; -109FC;MEROITIC CURSIVE FRACTION SEVEN TWELFTHS;No;0;R;;;;7/12;N;;;;; -109FD;MEROITIC CURSIVE FRACTION EIGHT TWELFTHS;No;0;R;;;;8/12;N;;;;; -109FE;MEROITIC CURSIVE FRACTION NINE TWELFTHS;No;0;R;;;;9/12;N;;;;; -109FF;MEROITIC CURSIVE FRACTION TEN TWELFTHS;No;0;R;;;;10/12;N;;;;; -10A00;KHAROSHTHI LETTER A;Lo;0;R;;;;;N;;;;; -10A01;KHAROSHTHI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -10A02;KHAROSHTHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -10A03;KHAROSHTHI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -10A05;KHAROSHTHI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -10A06;KHAROSHTHI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; -10A0C;KHAROSHTHI VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;; -10A0D;KHAROSHTHI SIGN DOUBLE RING BELOW;Mn;220;NSM;;;;;N;;;;; -10A0E;KHAROSHTHI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -10A0F;KHAROSHTHI SIGN VISARGA;Mn;230;NSM;;;;;N;;;;; -10A10;KHAROSHTHI LETTER KA;Lo;0;R;;;;;N;;;;; -10A11;KHAROSHTHI LETTER KHA;Lo;0;R;;;;;N;;;;; -10A12;KHAROSHTHI LETTER GA;Lo;0;R;;;;;N;;;;; -10A13;KHAROSHTHI LETTER GHA;Lo;0;R;;;;;N;;;;; -10A15;KHAROSHTHI LETTER CA;Lo;0;R;;;;;N;;;;; -10A16;KHAROSHTHI LETTER CHA;Lo;0;R;;;;;N;;;;; -10A17;KHAROSHTHI LETTER JA;Lo;0;R;;;;;N;;;;; -10A19;KHAROSHTHI LETTER NYA;Lo;0;R;;;;;N;;;;; -10A1A;KHAROSHTHI LETTER TTA;Lo;0;R;;;;;N;;;;; -10A1B;KHAROSHTHI LETTER TTHA;Lo;0;R;;;;;N;;;;; -10A1C;KHAROSHTHI LETTER DDA;Lo;0;R;;;;;N;;;;; -10A1D;KHAROSHTHI LETTER DDHA;Lo;0;R;;;;;N;;;;; -10A1E;KHAROSHTHI LETTER NNA;Lo;0;R;;;;;N;;;;; -10A1F;KHAROSHTHI LETTER TA;Lo;0;R;;;;;N;;;;; -10A20;KHAROSHTHI LETTER THA;Lo;0;R;;;;;N;;;;; -10A21;KHAROSHTHI LETTER DA;Lo;0;R;;;;;N;;;;; -10A22;KHAROSHTHI LETTER DHA;Lo;0;R;;;;;N;;;;; -10A23;KHAROSHTHI LETTER NA;Lo;0;R;;;;;N;;;;; -10A24;KHAROSHTHI LETTER PA;Lo;0;R;;;;;N;;;;; -10A25;KHAROSHTHI LETTER PHA;Lo;0;R;;;;;N;;;;; -10A26;KHAROSHTHI LETTER BA;Lo;0;R;;;;;N;;;;; -10A27;KHAROSHTHI LETTER BHA;Lo;0;R;;;;;N;;;;; -10A28;KHAROSHTHI LETTER MA;Lo;0;R;;;;;N;;;;; -10A29;KHAROSHTHI LETTER YA;Lo;0;R;;;;;N;;;;; -10A2A;KHAROSHTHI LETTER RA;Lo;0;R;;;;;N;;;;; -10A2B;KHAROSHTHI LETTER LA;Lo;0;R;;;;;N;;;;; -10A2C;KHAROSHTHI LETTER VA;Lo;0;R;;;;;N;;;;; -10A2D;KHAROSHTHI LETTER SHA;Lo;0;R;;;;;N;;;;; -10A2E;KHAROSHTHI LETTER SSA;Lo;0;R;;;;;N;;;;; -10A2F;KHAROSHTHI LETTER SA;Lo;0;R;;;;;N;;;;; -10A30;KHAROSHTHI LETTER ZA;Lo;0;R;;;;;N;;;;; -10A31;KHAROSHTHI LETTER HA;Lo;0;R;;;;;N;;;;; -10A32;KHAROSHTHI LETTER KKA;Lo;0;R;;;;;N;;;;; -10A33;KHAROSHTHI LETTER TTTHA;Lo;0;R;;;;;N;;;;; -10A34;KHAROSHTHI LETTER TTTA;Lo;0;R;;;;;N;;;;; -10A35;KHAROSHTHI LETTER VHA;Lo;0;R;;;;;N;;;;; -10A38;KHAROSHTHI SIGN BAR ABOVE;Mn;230;NSM;;;;;N;;;;; -10A39;KHAROSHTHI SIGN CAUDA;Mn;1;NSM;;;;;N;;;;; -10A3A;KHAROSHTHI SIGN DOT BELOW;Mn;220;NSM;;;;;N;;;;; -10A3F;KHAROSHTHI VIRAMA;Mn;9;NSM;;;;;N;;;;; -10A40;KHAROSHTHI DIGIT ONE;No;0;R;;;1;1;N;;;;; -10A41;KHAROSHTHI DIGIT TWO;No;0;R;;;2;2;N;;;;; -10A42;KHAROSHTHI DIGIT THREE;No;0;R;;;3;3;N;;;;; -10A43;KHAROSHTHI DIGIT FOUR;No;0;R;;;4;4;N;;;;; -10A44;KHAROSHTHI NUMBER TEN;No;0;R;;;;10;N;;;;; -10A45;KHAROSHTHI NUMBER TWENTY;No;0;R;;;;20;N;;;;; -10A46;KHAROSHTHI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; -10A47;KHAROSHTHI NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;; -10A48;KHAROSHTHI FRACTION ONE HALF;No;0;R;;;;1/2;N;;;;; -10A50;KHAROSHTHI PUNCTUATION DOT;Po;0;R;;;;;N;;;;; -10A51;KHAROSHTHI PUNCTUATION SMALL CIRCLE;Po;0;R;;;;;N;;;;; -10A52;KHAROSHTHI PUNCTUATION CIRCLE;Po;0;R;;;;;N;;;;; -10A53;KHAROSHTHI PUNCTUATION CRESCENT BAR;Po;0;R;;;;;N;;;;; -10A54;KHAROSHTHI PUNCTUATION MANGALAM;Po;0;R;;;;;N;;;;; -10A55;KHAROSHTHI PUNCTUATION LOTUS;Po;0;R;;;;;N;;;;; -10A56;KHAROSHTHI PUNCTUATION DANDA;Po;0;R;;;;;N;;;;; -10A57;KHAROSHTHI PUNCTUATION DOUBLE DANDA;Po;0;R;;;;;N;;;;; -10A58;KHAROSHTHI PUNCTUATION LINES;Po;0;R;;;;;N;;;;; -10A60;OLD SOUTH ARABIAN LETTER HE;Lo;0;R;;;;;N;;;;; -10A61;OLD SOUTH ARABIAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;; -10A62;OLD SOUTH ARABIAN LETTER HETH;Lo;0;R;;;;;N;;;;; -10A63;OLD SOUTH ARABIAN LETTER MEM;Lo;0;R;;;;;N;;;;; -10A64;OLD SOUTH ARABIAN LETTER QOPH;Lo;0;R;;;;;N;;;;; -10A65;OLD SOUTH ARABIAN LETTER WAW;Lo;0;R;;;;;N;;;;; -10A66;OLD SOUTH ARABIAN LETTER SHIN;Lo;0;R;;;;;N;;;;; -10A67;OLD SOUTH ARABIAN LETTER RESH;Lo;0;R;;;;;N;;;;; -10A68;OLD SOUTH ARABIAN LETTER BETH;Lo;0;R;;;;;N;;;;; -10A69;OLD SOUTH ARABIAN LETTER TAW;Lo;0;R;;;;;N;;;;; -10A6A;OLD SOUTH ARABIAN LETTER SAT;Lo;0;R;;;;;N;;;;; -10A6B;OLD SOUTH ARABIAN LETTER KAPH;Lo;0;R;;;;;N;;;;; -10A6C;OLD SOUTH ARABIAN LETTER NUN;Lo;0;R;;;;;N;;;;; -10A6D;OLD SOUTH ARABIAN LETTER KHETH;Lo;0;R;;;;;N;;;;; -10A6E;OLD SOUTH ARABIAN LETTER SADHE;Lo;0;R;;;;;N;;;;; -10A6F;OLD SOUTH ARABIAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;; -10A70;OLD SOUTH ARABIAN LETTER FE;Lo;0;R;;;;;N;;;;; -10A71;OLD SOUTH ARABIAN LETTER ALEF;Lo;0;R;;;;;N;;;;; -10A72;OLD SOUTH ARABIAN LETTER AYN;Lo;0;R;;;;;N;;;;; -10A73;OLD SOUTH ARABIAN LETTER DHADHE;Lo;0;R;;;;;N;;;;; -10A74;OLD SOUTH ARABIAN LETTER GIMEL;Lo;0;R;;;;;N;;;;; -10A75;OLD SOUTH ARABIAN LETTER DALETH;Lo;0;R;;;;;N;;;;; -10A76;OLD SOUTH ARABIAN LETTER GHAYN;Lo;0;R;;;;;N;;;;; -10A77;OLD SOUTH ARABIAN LETTER TETH;Lo;0;R;;;;;N;;;;; -10A78;OLD SOUTH ARABIAN LETTER ZAYN;Lo;0;R;;;;;N;;;;; -10A79;OLD SOUTH ARABIAN LETTER DHALETH;Lo;0;R;;;;;N;;;;; -10A7A;OLD SOUTH ARABIAN LETTER YODH;Lo;0;R;;;;;N;;;;; -10A7B;OLD SOUTH ARABIAN LETTER THAW;Lo;0;R;;;;;N;;;;; -10A7C;OLD SOUTH ARABIAN LETTER THETH;Lo;0;R;;;;;N;;;;; -10A7D;OLD SOUTH ARABIAN NUMBER ONE;No;0;R;;;;1;N;;;;; -10A7E;OLD SOUTH ARABIAN NUMBER FIFTY;No;0;R;;;;50;N;;;;; -10A7F;OLD SOUTH ARABIAN NUMERIC INDICATOR;Po;0;R;;;;;N;;;;; -10A80;OLD NORTH ARABIAN LETTER HEH;Lo;0;R;;;;;N;;;;; -10A81;OLD NORTH ARABIAN LETTER LAM;Lo;0;R;;;;;N;;;;; -10A82;OLD NORTH ARABIAN LETTER HAH;Lo;0;R;;;;;N;;;;; -10A83;OLD NORTH ARABIAN LETTER MEEM;Lo;0;R;;;;;N;;;;; -10A84;OLD NORTH ARABIAN LETTER QAF;Lo;0;R;;;;;N;;;;; -10A85;OLD NORTH ARABIAN LETTER WAW;Lo;0;R;;;;;N;;;;; -10A86;OLD NORTH ARABIAN LETTER ES-2;Lo;0;R;;;;;N;;;;; -10A87;OLD NORTH ARABIAN LETTER REH;Lo;0;R;;;;;N;;;;; -10A88;OLD NORTH ARABIAN LETTER BEH;Lo;0;R;;;;;N;;;;; -10A89;OLD NORTH ARABIAN LETTER TEH;Lo;0;R;;;;;N;;;;; -10A8A;OLD NORTH ARABIAN LETTER ES-1;Lo;0;R;;;;;N;;;;; -10A8B;OLD NORTH ARABIAN LETTER KAF;Lo;0;R;;;;;N;;;;; -10A8C;OLD NORTH ARABIAN LETTER NOON;Lo;0;R;;;;;N;;;;; -10A8D;OLD NORTH ARABIAN LETTER KHAH;Lo;0;R;;;;;N;;;;; -10A8E;OLD NORTH ARABIAN LETTER SAD;Lo;0;R;;;;;N;;;;; -10A8F;OLD NORTH ARABIAN LETTER ES-3;Lo;0;R;;;;;N;;;;; -10A90;OLD NORTH ARABIAN LETTER FEH;Lo;0;R;;;;;N;;;;; -10A91;OLD NORTH ARABIAN LETTER ALEF;Lo;0;R;;;;;N;;;;; -10A92;OLD NORTH ARABIAN LETTER AIN;Lo;0;R;;;;;N;;;;; -10A93;OLD NORTH ARABIAN LETTER DAD;Lo;0;R;;;;;N;;;;; -10A94;OLD NORTH ARABIAN LETTER GEEM;Lo;0;R;;;;;N;;;;; -10A95;OLD NORTH ARABIAN LETTER DAL;Lo;0;R;;;;;N;;;;; -10A96;OLD NORTH ARABIAN LETTER GHAIN;Lo;0;R;;;;;N;;;;; -10A97;OLD NORTH ARABIAN LETTER TAH;Lo;0;R;;;;;N;;;;; -10A98;OLD NORTH ARABIAN LETTER ZAIN;Lo;0;R;;;;;N;;;;; -10A99;OLD NORTH ARABIAN LETTER THAL;Lo;0;R;;;;;N;;;;; -10A9A;OLD NORTH ARABIAN LETTER YEH;Lo;0;R;;;;;N;;;;; -10A9B;OLD NORTH ARABIAN LETTER THEH;Lo;0;R;;;;;N;;;;; -10A9C;OLD NORTH ARABIAN LETTER ZAH;Lo;0;R;;;;;N;;;;; -10A9D;OLD NORTH ARABIAN NUMBER ONE;No;0;R;;;;1;N;;;;; -10A9E;OLD NORTH ARABIAN NUMBER TEN;No;0;R;;;;10;N;;;;; -10A9F;OLD NORTH ARABIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; -10AC0;MANICHAEAN LETTER ALEPH;Lo;0;R;;;;;N;;;;; -10AC1;MANICHAEAN LETTER BETH;Lo;0;R;;;;;N;;;;; -10AC2;MANICHAEAN LETTER BHETH;Lo;0;R;;;;;N;;;;; -10AC3;MANICHAEAN LETTER GIMEL;Lo;0;R;;;;;N;;;;; -10AC4;MANICHAEAN LETTER GHIMEL;Lo;0;R;;;;;N;;;;; -10AC5;MANICHAEAN LETTER DALETH;Lo;0;R;;;;;N;;;;; -10AC6;MANICHAEAN LETTER HE;Lo;0;R;;;;;N;;;;; -10AC7;MANICHAEAN LETTER WAW;Lo;0;R;;;;;N;;;;; -10AC8;MANICHAEAN SIGN UD;So;0;R;;;;;N;;;;; -10AC9;MANICHAEAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;; -10ACA;MANICHAEAN LETTER ZHAYIN;Lo;0;R;;;;;N;;;;; -10ACB;MANICHAEAN LETTER JAYIN;Lo;0;R;;;;;N;;;;; -10ACC;MANICHAEAN LETTER JHAYIN;Lo;0;R;;;;;N;;;;; -10ACD;MANICHAEAN LETTER HETH;Lo;0;R;;;;;N;;;;; -10ACE;MANICHAEAN LETTER TETH;Lo;0;R;;;;;N;;;;; -10ACF;MANICHAEAN LETTER YODH;Lo;0;R;;;;;N;;;;; -10AD0;MANICHAEAN LETTER KAPH;Lo;0;R;;;;;N;;;;; -10AD1;MANICHAEAN LETTER XAPH;Lo;0;R;;;;;N;;;;; -10AD2;MANICHAEAN LETTER KHAPH;Lo;0;R;;;;;N;;;;; -10AD3;MANICHAEAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;; -10AD4;MANICHAEAN LETTER DHAMEDH;Lo;0;R;;;;;N;;;;; -10AD5;MANICHAEAN LETTER THAMEDH;Lo;0;R;;;;;N;;;;; -10AD6;MANICHAEAN LETTER MEM;Lo;0;R;;;;;N;;;;; -10AD7;MANICHAEAN LETTER NUN;Lo;0;R;;;;;N;;;;; -10AD8;MANICHAEAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;; -10AD9;MANICHAEAN LETTER AYIN;Lo;0;R;;;;;N;;;;; -10ADA;MANICHAEAN LETTER AAYIN;Lo;0;R;;;;;N;;;;; -10ADB;MANICHAEAN LETTER PE;Lo;0;R;;;;;N;;;;; -10ADC;MANICHAEAN LETTER FE;Lo;0;R;;;;;N;;;;; -10ADD;MANICHAEAN LETTER SADHE;Lo;0;R;;;;;N;;;;; -10ADE;MANICHAEAN LETTER QOPH;Lo;0;R;;;;;N;;;;; -10ADF;MANICHAEAN LETTER XOPH;Lo;0;R;;;;;N;;;;; -10AE0;MANICHAEAN LETTER QHOPH;Lo;0;R;;;;;N;;;;; -10AE1;MANICHAEAN LETTER RESH;Lo;0;R;;;;;N;;;;; -10AE2;MANICHAEAN LETTER SHIN;Lo;0;R;;;;;N;;;;; -10AE3;MANICHAEAN LETTER SSHIN;Lo;0;R;;;;;N;;;;; -10AE4;MANICHAEAN LETTER TAW;Lo;0;R;;;;;N;;;;; -10AE5;MANICHAEAN ABBREVIATION MARK ABOVE;Mn;230;NSM;;;;;N;;;;; -10AE6;MANICHAEAN ABBREVIATION MARK BELOW;Mn;220;NSM;;;;;N;;;;; -10AEB;MANICHAEAN NUMBER ONE;No;0;R;;;;1;N;;;;; -10AEC;MANICHAEAN NUMBER FIVE;No;0;R;;;;5;N;;;;; -10AED;MANICHAEAN NUMBER TEN;No;0;R;;;;10;N;;;;; -10AEE;MANICHAEAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; -10AEF;MANICHAEAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; -10AF0;MANICHAEAN PUNCTUATION STAR;Po;0;R;;;;;N;;;;; -10AF1;MANICHAEAN PUNCTUATION FLEURON;Po;0;R;;;;;N;;;;; -10AF2;MANICHAEAN PUNCTUATION DOUBLE DOT WITHIN DOT;Po;0;R;;;;;N;;;;; -10AF3;MANICHAEAN PUNCTUATION DOT WITHIN DOT;Po;0;R;;;;;N;;;;; -10AF4;MANICHAEAN PUNCTUATION DOT;Po;0;R;;;;;N;;;;; -10AF5;MANICHAEAN PUNCTUATION TWO DOTS;Po;0;R;;;;;N;;;;; -10AF6;MANICHAEAN PUNCTUATION LINE FILLER;Po;0;R;;;;;N;;;;; -10B00;AVESTAN LETTER A;Lo;0;R;;;;;N;;;;; -10B01;AVESTAN LETTER AA;Lo;0;R;;;;;N;;;;; -10B02;AVESTAN LETTER AO;Lo;0;R;;;;;N;;;;; -10B03;AVESTAN LETTER AAO;Lo;0;R;;;;;N;;;;; -10B04;AVESTAN LETTER AN;Lo;0;R;;;;;N;;;;; -10B05;AVESTAN LETTER AAN;Lo;0;R;;;;;N;;;;; -10B06;AVESTAN LETTER AE;Lo;0;R;;;;;N;;;;; -10B07;AVESTAN LETTER AEE;Lo;0;R;;;;;N;;;;; -10B08;AVESTAN LETTER E;Lo;0;R;;;;;N;;;;; -10B09;AVESTAN LETTER EE;Lo;0;R;;;;;N;;;;; -10B0A;AVESTAN LETTER O;Lo;0;R;;;;;N;;;;; -10B0B;AVESTAN LETTER OO;Lo;0;R;;;;;N;;;;; -10B0C;AVESTAN LETTER I;Lo;0;R;;;;;N;;;;; -10B0D;AVESTAN LETTER II;Lo;0;R;;;;;N;;;;; -10B0E;AVESTAN LETTER U;Lo;0;R;;;;;N;;;;; -10B0F;AVESTAN LETTER UU;Lo;0;R;;;;;N;;;;; -10B10;AVESTAN LETTER KE;Lo;0;R;;;;;N;;;;; -10B11;AVESTAN LETTER XE;Lo;0;R;;;;;N;;;;; -10B12;AVESTAN LETTER XYE;Lo;0;R;;;;;N;;;;; -10B13;AVESTAN LETTER XVE;Lo;0;R;;;;;N;;;;; -10B14;AVESTAN LETTER GE;Lo;0;R;;;;;N;;;;; -10B15;AVESTAN LETTER GGE;Lo;0;R;;;;;N;;;;; -10B16;AVESTAN LETTER GHE;Lo;0;R;;;;;N;;;;; -10B17;AVESTAN LETTER CE;Lo;0;R;;;;;N;;;;; -10B18;AVESTAN LETTER JE;Lo;0;R;;;;;N;;;;; -10B19;AVESTAN LETTER TE;Lo;0;R;;;;;N;;;;; -10B1A;AVESTAN LETTER THE;Lo;0;R;;;;;N;;;;; -10B1B;AVESTAN LETTER DE;Lo;0;R;;;;;N;;;;; -10B1C;AVESTAN LETTER DHE;Lo;0;R;;;;;N;;;;; -10B1D;AVESTAN LETTER TTE;Lo;0;R;;;;;N;;;;; -10B1E;AVESTAN LETTER PE;Lo;0;R;;;;;N;;;;; -10B1F;AVESTAN LETTER FE;Lo;0;R;;;;;N;;;;; -10B20;AVESTAN LETTER BE;Lo;0;R;;;;;N;;;;; -10B21;AVESTAN LETTER BHE;Lo;0;R;;;;;N;;;;; -10B22;AVESTAN LETTER NGE;Lo;0;R;;;;;N;;;;; -10B23;AVESTAN LETTER NGYE;Lo;0;R;;;;;N;;;;; -10B24;AVESTAN LETTER NGVE;Lo;0;R;;;;;N;;;;; -10B25;AVESTAN LETTER NE;Lo;0;R;;;;;N;;;;; -10B26;AVESTAN LETTER NYE;Lo;0;R;;;;;N;;;;; -10B27;AVESTAN LETTER NNE;Lo;0;R;;;;;N;;;;; -10B28;AVESTAN LETTER ME;Lo;0;R;;;;;N;;;;; -10B29;AVESTAN LETTER HME;Lo;0;R;;;;;N;;;;; -10B2A;AVESTAN LETTER YYE;Lo;0;R;;;;;N;;;;; -10B2B;AVESTAN LETTER YE;Lo;0;R;;;;;N;;;;; -10B2C;AVESTAN LETTER VE;Lo;0;R;;;;;N;;;;; -10B2D;AVESTAN LETTER RE;Lo;0;R;;;;;N;;;;; -10B2E;AVESTAN LETTER LE;Lo;0;R;;;;;N;;;;; -10B2F;AVESTAN LETTER SE;Lo;0;R;;;;;N;;;;; -10B30;AVESTAN LETTER ZE;Lo;0;R;;;;;N;;;;; -10B31;AVESTAN LETTER SHE;Lo;0;R;;;;;N;;;;; -10B32;AVESTAN LETTER ZHE;Lo;0;R;;;;;N;;;;; -10B33;AVESTAN LETTER SHYE;Lo;0;R;;;;;N;;;;; -10B34;AVESTAN LETTER SSHE;Lo;0;R;;;;;N;;;;; -10B35;AVESTAN LETTER HE;Lo;0;R;;;;;N;;;;; -10B39;AVESTAN ABBREVIATION MARK;Po;0;ON;;;;;N;;;;; -10B3A;TINY TWO DOTS OVER ONE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; -10B3B;SMALL TWO DOTS OVER ONE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; -10B3C;LARGE TWO DOTS OVER ONE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;; -10B3D;LARGE ONE DOT OVER TWO DOTS PUNCTUATION;Po;0;ON;;;;;N;;;;; -10B3E;LARGE TWO RINGS OVER ONE RING PUNCTUATION;Po;0;ON;;;;;N;;;;; -10B3F;LARGE ONE RING OVER TWO RINGS PUNCTUATION;Po;0;ON;;;;;N;;;;; -10B40;INSCRIPTIONAL PARTHIAN LETTER ALEPH;Lo;0;R;;;;;N;;;;; -10B41;INSCRIPTIONAL PARTHIAN LETTER BETH;Lo;0;R;;;;;N;;;;; -10B42;INSCRIPTIONAL PARTHIAN LETTER GIMEL;Lo;0;R;;;;;N;;;;; -10B43;INSCRIPTIONAL PARTHIAN LETTER DALETH;Lo;0;R;;;;;N;;;;; -10B44;INSCRIPTIONAL PARTHIAN LETTER HE;Lo;0;R;;;;;N;;;;; -10B45;INSCRIPTIONAL PARTHIAN LETTER WAW;Lo;0;R;;;;;N;;;;; -10B46;INSCRIPTIONAL PARTHIAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;; -10B47;INSCRIPTIONAL PARTHIAN LETTER HETH;Lo;0;R;;;;;N;;;;; -10B48;INSCRIPTIONAL PARTHIAN LETTER TETH;Lo;0;R;;;;;N;;;;; -10B49;INSCRIPTIONAL PARTHIAN LETTER YODH;Lo;0;R;;;;;N;;;;; -10B4A;INSCRIPTIONAL PARTHIAN LETTER KAPH;Lo;0;R;;;;;N;;;;; -10B4B;INSCRIPTIONAL PARTHIAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;; -10B4C;INSCRIPTIONAL PARTHIAN LETTER MEM;Lo;0;R;;;;;N;;;;; -10B4D;INSCRIPTIONAL PARTHIAN LETTER NUN;Lo;0;R;;;;;N;;;;; -10B4E;INSCRIPTIONAL PARTHIAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;; -10B4F;INSCRIPTIONAL PARTHIAN LETTER AYIN;Lo;0;R;;;;;N;;;;; -10B50;INSCRIPTIONAL PARTHIAN LETTER PE;Lo;0;R;;;;;N;;;;; -10B51;INSCRIPTIONAL PARTHIAN LETTER SADHE;Lo;0;R;;;;;N;;;;; -10B52;INSCRIPTIONAL PARTHIAN LETTER QOPH;Lo;0;R;;;;;N;;;;; -10B53;INSCRIPTIONAL PARTHIAN LETTER RESH;Lo;0;R;;;;;N;;;;; -10B54;INSCRIPTIONAL PARTHIAN LETTER SHIN;Lo;0;R;;;;;N;;;;; -10B55;INSCRIPTIONAL PARTHIAN LETTER TAW;Lo;0;R;;;;;N;;;;; -10B58;INSCRIPTIONAL PARTHIAN NUMBER ONE;No;0;R;;;;1;N;;;;; -10B59;INSCRIPTIONAL PARTHIAN NUMBER TWO;No;0;R;;;;2;N;;;;; -10B5A;INSCRIPTIONAL PARTHIAN NUMBER THREE;No;0;R;;;;3;N;;;;; -10B5B;INSCRIPTIONAL PARTHIAN NUMBER FOUR;No;0;R;;;;4;N;;;;; -10B5C;INSCRIPTIONAL PARTHIAN NUMBER TEN;No;0;R;;;;10;N;;;;; -10B5D;INSCRIPTIONAL PARTHIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; -10B5E;INSCRIPTIONAL PARTHIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; -10B5F;INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;; -10B60;INSCRIPTIONAL PAHLAVI LETTER ALEPH;Lo;0;R;;;;;N;;;;; -10B61;INSCRIPTIONAL PAHLAVI LETTER BETH;Lo;0;R;;;;;N;;;;; -10B62;INSCRIPTIONAL PAHLAVI LETTER GIMEL;Lo;0;R;;;;;N;;;;; -10B63;INSCRIPTIONAL PAHLAVI LETTER DALETH;Lo;0;R;;;;;N;;;;; -10B64;INSCRIPTIONAL PAHLAVI LETTER HE;Lo;0;R;;;;;N;;;;; -10B65;INSCRIPTIONAL PAHLAVI LETTER WAW-AYIN-RESH;Lo;0;R;;;;;N;;;;; -10B66;INSCRIPTIONAL PAHLAVI LETTER ZAYIN;Lo;0;R;;;;;N;;;;; -10B67;INSCRIPTIONAL PAHLAVI LETTER HETH;Lo;0;R;;;;;N;;;;; -10B68;INSCRIPTIONAL PAHLAVI LETTER TETH;Lo;0;R;;;;;N;;;;; -10B69;INSCRIPTIONAL PAHLAVI LETTER YODH;Lo;0;R;;;;;N;;;;; -10B6A;INSCRIPTIONAL PAHLAVI LETTER KAPH;Lo;0;R;;;;;N;;;;; -10B6B;INSCRIPTIONAL PAHLAVI LETTER LAMEDH;Lo;0;R;;;;;N;;;;; -10B6C;INSCRIPTIONAL PAHLAVI LETTER MEM-QOPH;Lo;0;R;;;;;N;;;;; -10B6D;INSCRIPTIONAL PAHLAVI LETTER NUN;Lo;0;R;;;;;N;;;;; -10B6E;INSCRIPTIONAL PAHLAVI LETTER SAMEKH;Lo;0;R;;;;;N;;;;; -10B6F;INSCRIPTIONAL PAHLAVI LETTER PE;Lo;0;R;;;;;N;;;;; -10B70;INSCRIPTIONAL PAHLAVI LETTER SADHE;Lo;0;R;;;;;N;;;;; -10B71;INSCRIPTIONAL PAHLAVI LETTER SHIN;Lo;0;R;;;;;N;;;;; -10B72;INSCRIPTIONAL PAHLAVI LETTER TAW;Lo;0;R;;;;;N;;;;; -10B78;INSCRIPTIONAL PAHLAVI NUMBER ONE;No;0;R;;;;1;N;;;;; -10B79;INSCRIPTIONAL PAHLAVI NUMBER TWO;No;0;R;;;;2;N;;;;; -10B7A;INSCRIPTIONAL PAHLAVI NUMBER THREE;No;0;R;;;;3;N;;;;; -10B7B;INSCRIPTIONAL PAHLAVI NUMBER FOUR;No;0;R;;;;4;N;;;;; -10B7C;INSCRIPTIONAL PAHLAVI NUMBER TEN;No;0;R;;;;10;N;;;;; -10B7D;INSCRIPTIONAL PAHLAVI NUMBER TWENTY;No;0;R;;;;20;N;;;;; -10B7E;INSCRIPTIONAL PAHLAVI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; -10B7F;INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;; -10B80;PSALTER PAHLAVI LETTER ALEPH;Lo;0;R;;;;;N;;;;; -10B81;PSALTER PAHLAVI LETTER BETH;Lo;0;R;;;;;N;;;;; -10B82;PSALTER PAHLAVI LETTER GIMEL;Lo;0;R;;;;;N;;;;; -10B83;PSALTER PAHLAVI LETTER DALETH;Lo;0;R;;;;;N;;;;; -10B84;PSALTER PAHLAVI LETTER HE;Lo;0;R;;;;;N;;;;; -10B85;PSALTER PAHLAVI LETTER WAW-AYIN-RESH;Lo;0;R;;;;;N;;;;; -10B86;PSALTER PAHLAVI LETTER ZAYIN;Lo;0;R;;;;;N;;;;; -10B87;PSALTER PAHLAVI LETTER HETH;Lo;0;R;;;;;N;;;;; -10B88;PSALTER PAHLAVI LETTER YODH;Lo;0;R;;;;;N;;;;; -10B89;PSALTER PAHLAVI LETTER KAPH;Lo;0;R;;;;;N;;;;; -10B8A;PSALTER PAHLAVI LETTER LAMEDH;Lo;0;R;;;;;N;;;;; -10B8B;PSALTER PAHLAVI LETTER MEM-QOPH;Lo;0;R;;;;;N;;;;; -10B8C;PSALTER PAHLAVI LETTER NUN;Lo;0;R;;;;;N;;;;; -10B8D;PSALTER PAHLAVI LETTER SAMEKH;Lo;0;R;;;;;N;;;;; -10B8E;PSALTER PAHLAVI LETTER PE;Lo;0;R;;;;;N;;;;; -10B8F;PSALTER PAHLAVI LETTER SADHE;Lo;0;R;;;;;N;;;;; -10B90;PSALTER PAHLAVI LETTER SHIN;Lo;0;R;;;;;N;;;;; -10B91;PSALTER PAHLAVI LETTER TAW;Lo;0;R;;;;;N;;;;; -10B99;PSALTER PAHLAVI SECTION MARK;Po;0;R;;;;;N;;;;; -10B9A;PSALTER PAHLAVI TURNED SECTION MARK;Po;0;R;;;;;N;;;;; -10B9B;PSALTER PAHLAVI FOUR DOTS WITH CROSS;Po;0;R;;;;;N;;;;; -10B9C;PSALTER PAHLAVI FOUR DOTS WITH DOT;Po;0;R;;;;;N;;;;; -10BA9;PSALTER PAHLAVI NUMBER ONE;No;0;R;;;;1;N;;;;; -10BAA;PSALTER PAHLAVI NUMBER TWO;No;0;R;;;;2;N;;;;; -10BAB;PSALTER PAHLAVI NUMBER THREE;No;0;R;;;;3;N;;;;; -10BAC;PSALTER PAHLAVI NUMBER FOUR;No;0;R;;;;4;N;;;;; -10BAD;PSALTER PAHLAVI NUMBER TEN;No;0;R;;;;10;N;;;;; -10BAE;PSALTER PAHLAVI NUMBER TWENTY;No;0;R;;;;20;N;;;;; -10BAF;PSALTER PAHLAVI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; -10C00;OLD TURKIC LETTER ORKHON A;Lo;0;R;;;;;N;;;;; -10C01;OLD TURKIC LETTER YENISEI A;Lo;0;R;;;;;N;;;;; -10C02;OLD TURKIC LETTER YENISEI AE;Lo;0;R;;;;;N;;;;; -10C03;OLD TURKIC LETTER ORKHON I;Lo;0;R;;;;;N;;;;; -10C04;OLD TURKIC LETTER YENISEI I;Lo;0;R;;;;;N;;;;; -10C05;OLD TURKIC LETTER YENISEI E;Lo;0;R;;;;;N;;;;; -10C06;OLD TURKIC LETTER ORKHON O;Lo;0;R;;;;;N;;;;; -10C07;OLD TURKIC LETTER ORKHON OE;Lo;0;R;;;;;N;;;;; -10C08;OLD TURKIC LETTER YENISEI OE;Lo;0;R;;;;;N;;;;; -10C09;OLD TURKIC LETTER ORKHON AB;Lo;0;R;;;;;N;;;;; -10C0A;OLD TURKIC LETTER YENISEI AB;Lo;0;R;;;;;N;;;;; -10C0B;OLD TURKIC LETTER ORKHON AEB;Lo;0;R;;;;;N;;;;; -10C0C;OLD TURKIC LETTER YENISEI AEB;Lo;0;R;;;;;N;;;;; -10C0D;OLD TURKIC LETTER ORKHON AG;Lo;0;R;;;;;N;;;;; -10C0E;OLD TURKIC LETTER YENISEI AG;Lo;0;R;;;;;N;;;;; -10C0F;OLD TURKIC LETTER ORKHON AEG;Lo;0;R;;;;;N;;;;; -10C10;OLD TURKIC LETTER YENISEI AEG;Lo;0;R;;;;;N;;;;; -10C11;OLD TURKIC LETTER ORKHON AD;Lo;0;R;;;;;N;;;;; -10C12;OLD TURKIC LETTER YENISEI AD;Lo;0;R;;;;;N;;;;; -10C13;OLD TURKIC LETTER ORKHON AED;Lo;0;R;;;;;N;;;;; -10C14;OLD TURKIC LETTER ORKHON EZ;Lo;0;R;;;;;N;;;;; -10C15;OLD TURKIC LETTER YENISEI EZ;Lo;0;R;;;;;N;;;;; -10C16;OLD TURKIC LETTER ORKHON AY;Lo;0;R;;;;;N;;;;; -10C17;OLD TURKIC LETTER YENISEI AY;Lo;0;R;;;;;N;;;;; -10C18;OLD TURKIC LETTER ORKHON AEY;Lo;0;R;;;;;N;;;;; -10C19;OLD TURKIC LETTER YENISEI AEY;Lo;0;R;;;;;N;;;;; -10C1A;OLD TURKIC LETTER ORKHON AEK;Lo;0;R;;;;;N;;;;; -10C1B;OLD TURKIC LETTER YENISEI AEK;Lo;0;R;;;;;N;;;;; -10C1C;OLD TURKIC LETTER ORKHON OEK;Lo;0;R;;;;;N;;;;; -10C1D;OLD TURKIC LETTER YENISEI OEK;Lo;0;R;;;;;N;;;;; -10C1E;OLD TURKIC LETTER ORKHON AL;Lo;0;R;;;;;N;;;;; -10C1F;OLD TURKIC LETTER YENISEI AL;Lo;0;R;;;;;N;;;;; -10C20;OLD TURKIC LETTER ORKHON AEL;Lo;0;R;;;;;N;;;;; -10C21;OLD TURKIC LETTER ORKHON ELT;Lo;0;R;;;;;N;;;;; -10C22;OLD TURKIC LETTER ORKHON EM;Lo;0;R;;;;;N;;;;; -10C23;OLD TURKIC LETTER ORKHON AN;Lo;0;R;;;;;N;;;;; -10C24;OLD TURKIC LETTER ORKHON AEN;Lo;0;R;;;;;N;;;;; -10C25;OLD TURKIC LETTER YENISEI AEN;Lo;0;R;;;;;N;;;;; -10C26;OLD TURKIC LETTER ORKHON ENT;Lo;0;R;;;;;N;;;;; -10C27;OLD TURKIC LETTER YENISEI ENT;Lo;0;R;;;;;N;;;;; -10C28;OLD TURKIC LETTER ORKHON ENC;Lo;0;R;;;;;N;;;;; -10C29;OLD TURKIC LETTER YENISEI ENC;Lo;0;R;;;;;N;;;;; -10C2A;OLD TURKIC LETTER ORKHON ENY;Lo;0;R;;;;;N;;;;; -10C2B;OLD TURKIC LETTER YENISEI ENY;Lo;0;R;;;;;N;;;;; -10C2C;OLD TURKIC LETTER YENISEI ANG;Lo;0;R;;;;;N;;;;; -10C2D;OLD TURKIC LETTER ORKHON ENG;Lo;0;R;;;;;N;;;;; -10C2E;OLD TURKIC LETTER YENISEI AENG;Lo;0;R;;;;;N;;;;; -10C2F;OLD TURKIC LETTER ORKHON EP;Lo;0;R;;;;;N;;;;; -10C30;OLD TURKIC LETTER ORKHON OP;Lo;0;R;;;;;N;;;;; -10C31;OLD TURKIC LETTER ORKHON IC;Lo;0;R;;;;;N;;;;; -10C32;OLD TURKIC LETTER ORKHON EC;Lo;0;R;;;;;N;;;;; -10C33;OLD TURKIC LETTER YENISEI EC;Lo;0;R;;;;;N;;;;; -10C34;OLD TURKIC LETTER ORKHON AQ;Lo;0;R;;;;;N;;;;; -10C35;OLD TURKIC LETTER YENISEI AQ;Lo;0;R;;;;;N;;;;; -10C36;OLD TURKIC LETTER ORKHON IQ;Lo;0;R;;;;;N;;;;; -10C37;OLD TURKIC LETTER YENISEI IQ;Lo;0;R;;;;;N;;;;; -10C38;OLD TURKIC LETTER ORKHON OQ;Lo;0;R;;;;;N;;;;; -10C39;OLD TURKIC LETTER YENISEI OQ;Lo;0;R;;;;;N;;;;; -10C3A;OLD TURKIC LETTER ORKHON AR;Lo;0;R;;;;;N;;;;; -10C3B;OLD TURKIC LETTER YENISEI AR;Lo;0;R;;;;;N;;;;; -10C3C;OLD TURKIC LETTER ORKHON AER;Lo;0;R;;;;;N;;;;; -10C3D;OLD TURKIC LETTER ORKHON AS;Lo;0;R;;;;;N;;;;; -10C3E;OLD TURKIC LETTER ORKHON AES;Lo;0;R;;;;;N;;;;; -10C3F;OLD TURKIC LETTER ORKHON ASH;Lo;0;R;;;;;N;;;;; -10C40;OLD TURKIC LETTER YENISEI ASH;Lo;0;R;;;;;N;;;;; -10C41;OLD TURKIC LETTER ORKHON ESH;Lo;0;R;;;;;N;;;;; -10C42;OLD TURKIC LETTER YENISEI ESH;Lo;0;R;;;;;N;;;;; -10C43;OLD TURKIC LETTER ORKHON AT;Lo;0;R;;;;;N;;;;; -10C44;OLD TURKIC LETTER YENISEI AT;Lo;0;R;;;;;N;;;;; -10C45;OLD TURKIC LETTER ORKHON AET;Lo;0;R;;;;;N;;;;; -10C46;OLD TURKIC LETTER YENISEI AET;Lo;0;R;;;;;N;;;;; -10C47;OLD TURKIC LETTER ORKHON OT;Lo;0;R;;;;;N;;;;; -10C48;OLD TURKIC LETTER ORKHON BASH;Lo;0;R;;;;;N;;;;; -10C80;OLD HUNGARIAN CAPITAL LETTER A;Lu;0;R;;;;;N;;;;10CC0; -10C81;OLD HUNGARIAN CAPITAL LETTER AA;Lu;0;R;;;;;N;;;;10CC1; -10C82;OLD HUNGARIAN CAPITAL LETTER EB;Lu;0;R;;;;;N;;;;10CC2; -10C83;OLD HUNGARIAN CAPITAL LETTER AMB;Lu;0;R;;;;;N;;;;10CC3; -10C84;OLD HUNGARIAN CAPITAL LETTER EC;Lu;0;R;;;;;N;;;;10CC4; -10C85;OLD HUNGARIAN CAPITAL LETTER ENC;Lu;0;R;;;;;N;;;;10CC5; -10C86;OLD HUNGARIAN CAPITAL LETTER ECS;Lu;0;R;;;;;N;;;;10CC6; -10C87;OLD HUNGARIAN CAPITAL LETTER ED;Lu;0;R;;;;;N;;;;10CC7; -10C88;OLD HUNGARIAN CAPITAL LETTER AND;Lu;0;R;;;;;N;;;;10CC8; -10C89;OLD HUNGARIAN CAPITAL LETTER E;Lu;0;R;;;;;N;;;;10CC9; -10C8A;OLD HUNGARIAN CAPITAL LETTER CLOSE E;Lu;0;R;;;;;N;;;;10CCA; -10C8B;OLD HUNGARIAN CAPITAL LETTER EE;Lu;0;R;;;;;N;;;;10CCB; -10C8C;OLD HUNGARIAN CAPITAL LETTER EF;Lu;0;R;;;;;N;;;;10CCC; -10C8D;OLD HUNGARIAN CAPITAL LETTER EG;Lu;0;R;;;;;N;;;;10CCD; -10C8E;OLD HUNGARIAN CAPITAL LETTER EGY;Lu;0;R;;;;;N;;;;10CCE; -10C8F;OLD HUNGARIAN CAPITAL LETTER EH;Lu;0;R;;;;;N;;;;10CCF; -10C90;OLD HUNGARIAN CAPITAL LETTER I;Lu;0;R;;;;;N;;;;10CD0; -10C91;OLD HUNGARIAN CAPITAL LETTER II;Lu;0;R;;;;;N;;;;10CD1; -10C92;OLD HUNGARIAN CAPITAL LETTER EJ;Lu;0;R;;;;;N;;;;10CD2; -10C93;OLD HUNGARIAN CAPITAL LETTER EK;Lu;0;R;;;;;N;;;;10CD3; -10C94;OLD HUNGARIAN CAPITAL LETTER AK;Lu;0;R;;;;;N;;;;10CD4; -10C95;OLD HUNGARIAN CAPITAL LETTER UNK;Lu;0;R;;;;;N;;;;10CD5; -10C96;OLD HUNGARIAN CAPITAL LETTER EL;Lu;0;R;;;;;N;;;;10CD6; -10C97;OLD HUNGARIAN CAPITAL LETTER ELY;Lu;0;R;;;;;N;;;;10CD7; -10C98;OLD HUNGARIAN CAPITAL LETTER EM;Lu;0;R;;;;;N;;;;10CD8; -10C99;OLD HUNGARIAN CAPITAL LETTER EN;Lu;0;R;;;;;N;;;;10CD9; -10C9A;OLD HUNGARIAN CAPITAL LETTER ENY;Lu;0;R;;;;;N;;;;10CDA; -10C9B;OLD HUNGARIAN CAPITAL LETTER O;Lu;0;R;;;;;N;;;;10CDB; -10C9C;OLD HUNGARIAN CAPITAL LETTER OO;Lu;0;R;;;;;N;;;;10CDC; -10C9D;OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG OE;Lu;0;R;;;;;N;;;;10CDD; -10C9E;OLD HUNGARIAN CAPITAL LETTER RUDIMENTA OE;Lu;0;R;;;;;N;;;;10CDE; -10C9F;OLD HUNGARIAN CAPITAL LETTER OEE;Lu;0;R;;;;;N;;;;10CDF; -10CA0;OLD HUNGARIAN CAPITAL LETTER EP;Lu;0;R;;;;;N;;;;10CE0; -10CA1;OLD HUNGARIAN CAPITAL LETTER EMP;Lu;0;R;;;;;N;;;;10CE1; -10CA2;OLD HUNGARIAN CAPITAL LETTER ER;Lu;0;R;;;;;N;;;;10CE2; -10CA3;OLD HUNGARIAN CAPITAL LETTER SHORT ER;Lu;0;R;;;;;N;;;;10CE3; -10CA4;OLD HUNGARIAN CAPITAL LETTER ES;Lu;0;R;;;;;N;;;;10CE4; -10CA5;OLD HUNGARIAN CAPITAL LETTER ESZ;Lu;0;R;;;;;N;;;;10CE5; -10CA6;OLD HUNGARIAN CAPITAL LETTER ET;Lu;0;R;;;;;N;;;;10CE6; -10CA7;OLD HUNGARIAN CAPITAL LETTER ENT;Lu;0;R;;;;;N;;;;10CE7; -10CA8;OLD HUNGARIAN CAPITAL LETTER ETY;Lu;0;R;;;;;N;;;;10CE8; -10CA9;OLD HUNGARIAN CAPITAL LETTER ECH;Lu;0;R;;;;;N;;;;10CE9; -10CAA;OLD HUNGARIAN CAPITAL LETTER U;Lu;0;R;;;;;N;;;;10CEA; -10CAB;OLD HUNGARIAN CAPITAL LETTER UU;Lu;0;R;;;;;N;;;;10CEB; -10CAC;OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG UE;Lu;0;R;;;;;N;;;;10CEC; -10CAD;OLD HUNGARIAN CAPITAL LETTER RUDIMENTA UE;Lu;0;R;;;;;N;;;;10CED; -10CAE;OLD HUNGARIAN CAPITAL LETTER EV;Lu;0;R;;;;;N;;;;10CEE; -10CAF;OLD HUNGARIAN CAPITAL LETTER EZ;Lu;0;R;;;;;N;;;;10CEF; -10CB0;OLD HUNGARIAN CAPITAL LETTER EZS;Lu;0;R;;;;;N;;;;10CF0; -10CB1;OLD HUNGARIAN CAPITAL LETTER ENT-SHAPED SIGN;Lu;0;R;;;;;N;;;;10CF1; -10CB2;OLD HUNGARIAN CAPITAL LETTER US;Lu;0;R;;;;;N;;;;10CF2; -10CC0;OLD HUNGARIAN SMALL LETTER A;Ll;0;R;;;;;N;;;10C80;;10C80 -10CC1;OLD HUNGARIAN SMALL LETTER AA;Ll;0;R;;;;;N;;;10C81;;10C81 -10CC2;OLD HUNGARIAN SMALL LETTER EB;Ll;0;R;;;;;N;;;10C82;;10C82 -10CC3;OLD HUNGARIAN SMALL LETTER AMB;Ll;0;R;;;;;N;;;10C83;;10C83 -10CC4;OLD HUNGARIAN SMALL LETTER EC;Ll;0;R;;;;;N;;;10C84;;10C84 -10CC5;OLD HUNGARIAN SMALL LETTER ENC;Ll;0;R;;;;;N;;;10C85;;10C85 -10CC6;OLD HUNGARIAN SMALL LETTER ECS;Ll;0;R;;;;;N;;;10C86;;10C86 -10CC7;OLD HUNGARIAN SMALL LETTER ED;Ll;0;R;;;;;N;;;10C87;;10C87 -10CC8;OLD HUNGARIAN SMALL LETTER AND;Ll;0;R;;;;;N;;;10C88;;10C88 -10CC9;OLD HUNGARIAN SMALL LETTER E;Ll;0;R;;;;;N;;;10C89;;10C89 -10CCA;OLD HUNGARIAN SMALL LETTER CLOSE E;Ll;0;R;;;;;N;;;10C8A;;10C8A -10CCB;OLD HUNGARIAN SMALL LETTER EE;Ll;0;R;;;;;N;;;10C8B;;10C8B -10CCC;OLD HUNGARIAN SMALL LETTER EF;Ll;0;R;;;;;N;;;10C8C;;10C8C -10CCD;OLD HUNGARIAN SMALL LETTER EG;Ll;0;R;;;;;N;;;10C8D;;10C8D -10CCE;OLD HUNGARIAN SMALL LETTER EGY;Ll;0;R;;;;;N;;;10C8E;;10C8E -10CCF;OLD HUNGARIAN SMALL LETTER EH;Ll;0;R;;;;;N;;;10C8F;;10C8F -10CD0;OLD HUNGARIAN SMALL LETTER I;Ll;0;R;;;;;N;;;10C90;;10C90 -10CD1;OLD HUNGARIAN SMALL LETTER II;Ll;0;R;;;;;N;;;10C91;;10C91 -10CD2;OLD HUNGARIAN SMALL LETTER EJ;Ll;0;R;;;;;N;;;10C92;;10C92 -10CD3;OLD HUNGARIAN SMALL LETTER EK;Ll;0;R;;;;;N;;;10C93;;10C93 -10CD4;OLD HUNGARIAN SMALL LETTER AK;Ll;0;R;;;;;N;;;10C94;;10C94 -10CD5;OLD HUNGARIAN SMALL LETTER UNK;Ll;0;R;;;;;N;;;10C95;;10C95 -10CD6;OLD HUNGARIAN SMALL LETTER EL;Ll;0;R;;;;;N;;;10C96;;10C96 -10CD7;OLD HUNGARIAN SMALL LETTER ELY;Ll;0;R;;;;;N;;;10C97;;10C97 -10CD8;OLD HUNGARIAN SMALL LETTER EM;Ll;0;R;;;;;N;;;10C98;;10C98 -10CD9;OLD HUNGARIAN SMALL LETTER EN;Ll;0;R;;;;;N;;;10C99;;10C99 -10CDA;OLD HUNGARIAN SMALL LETTER ENY;Ll;0;R;;;;;N;;;10C9A;;10C9A -10CDB;OLD HUNGARIAN SMALL LETTER O;Ll;0;R;;;;;N;;;10C9B;;10C9B -10CDC;OLD HUNGARIAN SMALL LETTER OO;Ll;0;R;;;;;N;;;10C9C;;10C9C -10CDD;OLD HUNGARIAN SMALL LETTER NIKOLSBURG OE;Ll;0;R;;;;;N;;;10C9D;;10C9D -10CDE;OLD HUNGARIAN SMALL LETTER RUDIMENTA OE;Ll;0;R;;;;;N;;;10C9E;;10C9E -10CDF;OLD HUNGARIAN SMALL LETTER OEE;Ll;0;R;;;;;N;;;10C9F;;10C9F -10CE0;OLD HUNGARIAN SMALL LETTER EP;Ll;0;R;;;;;N;;;10CA0;;10CA0 -10CE1;OLD HUNGARIAN SMALL LETTER EMP;Ll;0;R;;;;;N;;;10CA1;;10CA1 -10CE2;OLD HUNGARIAN SMALL LETTER ER;Ll;0;R;;;;;N;;;10CA2;;10CA2 -10CE3;OLD HUNGARIAN SMALL LETTER SHORT ER;Ll;0;R;;;;;N;;;10CA3;;10CA3 -10CE4;OLD HUNGARIAN SMALL LETTER ES;Ll;0;R;;;;;N;;;10CA4;;10CA4 -10CE5;OLD HUNGARIAN SMALL LETTER ESZ;Ll;0;R;;;;;N;;;10CA5;;10CA5 -10CE6;OLD HUNGARIAN SMALL LETTER ET;Ll;0;R;;;;;N;;;10CA6;;10CA6 -10CE7;OLD HUNGARIAN SMALL LETTER ENT;Ll;0;R;;;;;N;;;10CA7;;10CA7 -10CE8;OLD HUNGARIAN SMALL LETTER ETY;Ll;0;R;;;;;N;;;10CA8;;10CA8 -10CE9;OLD HUNGARIAN SMALL LETTER ECH;Ll;0;R;;;;;N;;;10CA9;;10CA9 -10CEA;OLD HUNGARIAN SMALL LETTER U;Ll;0;R;;;;;N;;;10CAA;;10CAA -10CEB;OLD HUNGARIAN SMALL LETTER UU;Ll;0;R;;;;;N;;;10CAB;;10CAB -10CEC;OLD HUNGARIAN SMALL LETTER NIKOLSBURG UE;Ll;0;R;;;;;N;;;10CAC;;10CAC -10CED;OLD HUNGARIAN SMALL LETTER RUDIMENTA UE;Ll;0;R;;;;;N;;;10CAD;;10CAD -10CEE;OLD HUNGARIAN SMALL LETTER EV;Ll;0;R;;;;;N;;;10CAE;;10CAE -10CEF;OLD HUNGARIAN SMALL LETTER EZ;Ll;0;R;;;;;N;;;10CAF;;10CAF -10CF0;OLD HUNGARIAN SMALL LETTER EZS;Ll;0;R;;;;;N;;;10CB0;;10CB0 -10CF1;OLD HUNGARIAN SMALL LETTER ENT-SHAPED SIGN;Ll;0;R;;;;;N;;;10CB1;;10CB1 -10CF2;OLD HUNGARIAN SMALL LETTER US;Ll;0;R;;;;;N;;;10CB2;;10CB2 -10CFA;OLD HUNGARIAN NUMBER ONE;No;0;R;;;;1;N;;;;; -10CFB;OLD HUNGARIAN NUMBER FIVE;No;0;R;;;;5;N;;;;; -10CFC;OLD HUNGARIAN NUMBER TEN;No;0;R;;;;10;N;;;;; -10CFD;OLD HUNGARIAN NUMBER FIFTY;No;0;R;;;;50;N;;;;; -10CFE;OLD HUNGARIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; -10CFF;OLD HUNGARIAN NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;; -10D00;HANIFI ROHINGYA LETTER A;Lo;0;AL;;;;;N;;;;; -10D01;HANIFI ROHINGYA LETTER BA;Lo;0;AL;;;;;N;;;;; -10D02;HANIFI ROHINGYA LETTER PA;Lo;0;AL;;;;;N;;;;; -10D03;HANIFI ROHINGYA LETTER TA;Lo;0;AL;;;;;N;;;;; -10D04;HANIFI ROHINGYA LETTER TTA;Lo;0;AL;;;;;N;;;;; -10D05;HANIFI ROHINGYA LETTER JA;Lo;0;AL;;;;;N;;;;; -10D06;HANIFI ROHINGYA LETTER CA;Lo;0;AL;;;;;N;;;;; -10D07;HANIFI ROHINGYA LETTER HA;Lo;0;AL;;;;;N;;;;; -10D08;HANIFI ROHINGYA LETTER KHA;Lo;0;AL;;;;;N;;;;; -10D09;HANIFI ROHINGYA LETTER FA;Lo;0;AL;;;;;N;;;;; -10D0A;HANIFI ROHINGYA LETTER DA;Lo;0;AL;;;;;N;;;;; -10D0B;HANIFI ROHINGYA LETTER DDA;Lo;0;AL;;;;;N;;;;; -10D0C;HANIFI ROHINGYA LETTER RA;Lo;0;AL;;;;;N;;;;; -10D0D;HANIFI ROHINGYA LETTER RRA;Lo;0;AL;;;;;N;;;;; -10D0E;HANIFI ROHINGYA LETTER ZA;Lo;0;AL;;;;;N;;;;; -10D0F;HANIFI ROHINGYA LETTER SA;Lo;0;AL;;;;;N;;;;; -10D10;HANIFI ROHINGYA LETTER SHA;Lo;0;AL;;;;;N;;;;; -10D11;HANIFI ROHINGYA LETTER KA;Lo;0;AL;;;;;N;;;;; -10D12;HANIFI ROHINGYA LETTER GA;Lo;0;AL;;;;;N;;;;; -10D13;HANIFI ROHINGYA LETTER LA;Lo;0;AL;;;;;N;;;;; -10D14;HANIFI ROHINGYA LETTER MA;Lo;0;AL;;;;;N;;;;; -10D15;HANIFI ROHINGYA LETTER NA;Lo;0;AL;;;;;N;;;;; -10D16;HANIFI ROHINGYA LETTER WA;Lo;0;AL;;;;;N;;;;; -10D17;HANIFI ROHINGYA LETTER KINNA WA;Lo;0;AL;;;;;N;;;;; -10D18;HANIFI ROHINGYA LETTER YA;Lo;0;AL;;;;;N;;;;; -10D19;HANIFI ROHINGYA LETTER KINNA YA;Lo;0;AL;;;;;N;;;;; -10D1A;HANIFI ROHINGYA LETTER NGA;Lo;0;AL;;;;;N;;;;; -10D1B;HANIFI ROHINGYA LETTER NYA;Lo;0;AL;;;;;N;;;;; -10D1C;HANIFI ROHINGYA LETTER VA;Lo;0;AL;;;;;N;;;;; -10D1D;HANIFI ROHINGYA VOWEL A;Lo;0;AL;;;;;N;;;;; -10D1E;HANIFI ROHINGYA VOWEL I;Lo;0;AL;;;;;N;;;;; -10D1F;HANIFI ROHINGYA VOWEL U;Lo;0;AL;;;;;N;;;;; -10D20;HANIFI ROHINGYA VOWEL E;Lo;0;AL;;;;;N;;;;; -10D21;HANIFI ROHINGYA VOWEL O;Lo;0;AL;;;;;N;;;;; -10D22;HANIFI ROHINGYA MARK SAKIN;Lo;0;AL;;;;;N;;;;; -10D23;HANIFI ROHINGYA MARK NA KHONNA;Lo;0;AL;;;;;N;;;;; -10D24;HANIFI ROHINGYA SIGN HARBAHAY;Mn;230;NSM;;;;;N;;;;; -10D25;HANIFI ROHINGYA SIGN TAHALA;Mn;230;NSM;;;;;N;;;;; -10D26;HANIFI ROHINGYA SIGN TANA;Mn;230;NSM;;;;;N;;;;; -10D27;HANIFI ROHINGYA SIGN TASSI;Mn;230;NSM;;;;;N;;;;; -10D30;HANIFI ROHINGYA DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;; -10D31;HANIFI ROHINGYA DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;; -10D32;HANIFI ROHINGYA DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;; -10D33;HANIFI ROHINGYA DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;; -10D34;HANIFI ROHINGYA DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;; -10D35;HANIFI ROHINGYA DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;; -10D36;HANIFI ROHINGYA DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;; -10D37;HANIFI ROHINGYA DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;; -10D38;HANIFI ROHINGYA DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;; -10D39;HANIFI ROHINGYA DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;; -10E60;RUMI DIGIT ONE;No;0;AN;;;1;1;N;;;;; -10E61;RUMI DIGIT TWO;No;0;AN;;;2;2;N;;;;; -10E62;RUMI DIGIT THREE;No;0;AN;;;3;3;N;;;;; -10E63;RUMI DIGIT FOUR;No;0;AN;;;4;4;N;;;;; -10E64;RUMI DIGIT FIVE;No;0;AN;;;5;5;N;;;;; -10E65;RUMI DIGIT SIX;No;0;AN;;;6;6;N;;;;; -10E66;RUMI DIGIT SEVEN;No;0;AN;;;7;7;N;;;;; -10E67;RUMI DIGIT EIGHT;No;0;AN;;;8;8;N;;;;; -10E68;RUMI DIGIT NINE;No;0;AN;;;9;9;N;;;;; -10E69;RUMI NUMBER TEN;No;0;AN;;;;10;N;;;;; -10E6A;RUMI NUMBER TWENTY;No;0;AN;;;;20;N;;;;; -10E6B;RUMI NUMBER THIRTY;No;0;AN;;;;30;N;;;;; -10E6C;RUMI NUMBER FORTY;No;0;AN;;;;40;N;;;;; -10E6D;RUMI NUMBER FIFTY;No;0;AN;;;;50;N;;;;; -10E6E;RUMI NUMBER SIXTY;No;0;AN;;;;60;N;;;;; -10E6F;RUMI NUMBER SEVENTY;No;0;AN;;;;70;N;;;;; -10E70;RUMI NUMBER EIGHTY;No;0;AN;;;;80;N;;;;; -10E71;RUMI NUMBER NINETY;No;0;AN;;;;90;N;;;;; -10E72;RUMI NUMBER ONE HUNDRED;No;0;AN;;;;100;N;;;;; -10E73;RUMI NUMBER TWO HUNDRED;No;0;AN;;;;200;N;;;;; -10E74;RUMI NUMBER THREE HUNDRED;No;0;AN;;;;300;N;;;;; -10E75;RUMI NUMBER FOUR HUNDRED;No;0;AN;;;;400;N;;;;; -10E76;RUMI NUMBER FIVE HUNDRED;No;0;AN;;;;500;N;;;;; -10E77;RUMI NUMBER SIX HUNDRED;No;0;AN;;;;600;N;;;;; -10E78;RUMI NUMBER SEVEN HUNDRED;No;0;AN;;;;700;N;;;;; -10E79;RUMI NUMBER EIGHT HUNDRED;No;0;AN;;;;800;N;;;;; -10E7A;RUMI NUMBER NINE HUNDRED;No;0;AN;;;;900;N;;;;; -10E7B;RUMI FRACTION ONE HALF;No;0;AN;;;;1/2;N;;;;; -10E7C;RUMI FRACTION ONE QUARTER;No;0;AN;;;;1/4;N;;;;; -10E7D;RUMI FRACTION ONE THIRD;No;0;AN;;;;1/3;N;;;;; -10E7E;RUMI FRACTION TWO THIRDS;No;0;AN;;;;2/3;N;;;;; -10E80;YEZIDI LETTER ELIF;Lo;0;R;;;;;N;;;;; -10E81;YEZIDI LETTER BE;Lo;0;R;;;;;N;;;;; -10E82;YEZIDI LETTER PE;Lo;0;R;;;;;N;;;;; -10E83;YEZIDI LETTER PHE;Lo;0;R;;;;;N;;;;; -10E84;YEZIDI LETTER THE;Lo;0;R;;;;;N;;;;; -10E85;YEZIDI LETTER SE;Lo;0;R;;;;;N;;;;; -10E86;YEZIDI LETTER CIM;Lo;0;R;;;;;N;;;;; -10E87;YEZIDI LETTER CHIM;Lo;0;R;;;;;N;;;;; -10E88;YEZIDI LETTER CHHIM;Lo;0;R;;;;;N;;;;; -10E89;YEZIDI LETTER HHA;Lo;0;R;;;;;N;;;;; -10E8A;YEZIDI LETTER XA;Lo;0;R;;;;;N;;;;; -10E8B;YEZIDI LETTER DAL;Lo;0;R;;;;;N;;;;; -10E8C;YEZIDI LETTER ZAL;Lo;0;R;;;;;N;;;;; -10E8D;YEZIDI LETTER RA;Lo;0;R;;;;;N;;;;; -10E8E;YEZIDI LETTER RHA;Lo;0;R;;;;;N;;;;; -10E8F;YEZIDI LETTER ZA;Lo;0;R;;;;;N;;;;; -10E90;YEZIDI LETTER JA;Lo;0;R;;;;;N;;;;; -10E91;YEZIDI LETTER SIN;Lo;0;R;;;;;N;;;;; -10E92;YEZIDI LETTER SHIN;Lo;0;R;;;;;N;;;;; -10E93;YEZIDI LETTER SAD;Lo;0;R;;;;;N;;;;; -10E94;YEZIDI LETTER DAD;Lo;0;R;;;;;N;;;;; -10E95;YEZIDI LETTER TA;Lo;0;R;;;;;N;;;;; -10E96;YEZIDI LETTER ZE;Lo;0;R;;;;;N;;;;; -10E97;YEZIDI LETTER EYN;Lo;0;R;;;;;N;;;;; -10E98;YEZIDI LETTER XHEYN;Lo;0;R;;;;;N;;;;; -10E99;YEZIDI LETTER FA;Lo;0;R;;;;;N;;;;; -10E9A;YEZIDI LETTER VA;Lo;0;R;;;;;N;;;;; -10E9B;YEZIDI LETTER VA ALTERNATE FORM;Lo;0;R;;;;;N;;;;; -10E9C;YEZIDI LETTER QAF;Lo;0;R;;;;;N;;;;; -10E9D;YEZIDI LETTER KAF;Lo;0;R;;;;;N;;;;; -10E9E;YEZIDI LETTER KHAF;Lo;0;R;;;;;N;;;;; -10E9F;YEZIDI LETTER GAF;Lo;0;R;;;;;N;;;;; -10EA0;YEZIDI LETTER LAM;Lo;0;R;;;;;N;;;;; -10EA1;YEZIDI LETTER MIM;Lo;0;R;;;;;N;;;;; -10EA2;YEZIDI LETTER NUN;Lo;0;R;;;;;N;;;;; -10EA3;YEZIDI LETTER UM;Lo;0;R;;;;;N;;;;; -10EA4;YEZIDI LETTER WAW;Lo;0;R;;;;;N;;;;; -10EA5;YEZIDI LETTER OW;Lo;0;R;;;;;N;;;;; -10EA6;YEZIDI LETTER EW;Lo;0;R;;;;;N;;;;; -10EA7;YEZIDI LETTER HAY;Lo;0;R;;;;;N;;;;; -10EA8;YEZIDI LETTER YOT;Lo;0;R;;;;;N;;;;; -10EA9;YEZIDI LETTER ET;Lo;0;R;;;;;N;;;;; -10EAB;YEZIDI COMBINING HAMZA MARK;Mn;230;NSM;;;;;N;;;;; -10EAC;YEZIDI COMBINING MADDA MARK;Mn;230;NSM;;;;;N;;;;; -10EAD;YEZIDI HYPHENATION MARK;Pd;0;R;;;;;N;;;;; -10EB0;YEZIDI LETTER LAM WITH DOT ABOVE;Lo;0;R;;;;;N;;;;; -10EB1;YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE;Lo;0;R;;;;;N;;;;; -10EFD;ARABIC SMALL LOW WORD SAKTA;Mn;220;NSM;;;;;N;;;;; -10EFE;ARABIC SMALL LOW WORD QASR;Mn;220;NSM;;;;;N;;;;; -10EFF;ARABIC SMALL LOW WORD MADDA;Mn;220;NSM;;;;;N;;;;; -10F00;OLD SOGDIAN LETTER ALEPH;Lo;0;R;;;;;N;;;;; -10F01;OLD SOGDIAN LETTER FINAL ALEPH;Lo;0;R;;;;;N;;;;; -10F02;OLD SOGDIAN LETTER BETH;Lo;0;R;;;;;N;;;;; -10F03;OLD SOGDIAN LETTER FINAL BETH;Lo;0;R;;;;;N;;;;; -10F04;OLD SOGDIAN LETTER GIMEL;Lo;0;R;;;;;N;;;;; -10F05;OLD SOGDIAN LETTER HE;Lo;0;R;;;;;N;;;;; -10F06;OLD SOGDIAN LETTER FINAL HE;Lo;0;R;;;;;N;;;;; -10F07;OLD SOGDIAN LETTER WAW;Lo;0;R;;;;;N;;;;; -10F08;OLD SOGDIAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;; -10F09;OLD SOGDIAN LETTER HETH;Lo;0;R;;;;;N;;;;; -10F0A;OLD SOGDIAN LETTER YODH;Lo;0;R;;;;;N;;;;; -10F0B;OLD SOGDIAN LETTER KAPH;Lo;0;R;;;;;N;;;;; -10F0C;OLD SOGDIAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;; -10F0D;OLD SOGDIAN LETTER MEM;Lo;0;R;;;;;N;;;;; -10F0E;OLD SOGDIAN LETTER NUN;Lo;0;R;;;;;N;;;;; -10F0F;OLD SOGDIAN LETTER FINAL NUN;Lo;0;R;;;;;N;;;;; -10F10;OLD SOGDIAN LETTER FINAL NUN WITH VERTICAL TAIL;Lo;0;R;;;;;N;;;;; -10F11;OLD SOGDIAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;; -10F12;OLD SOGDIAN LETTER AYIN;Lo;0;R;;;;;N;;;;; -10F13;OLD SOGDIAN LETTER ALTERNATE AYIN;Lo;0;R;;;;;N;;;;; -10F14;OLD SOGDIAN LETTER PE;Lo;0;R;;;;;N;;;;; -10F15;OLD SOGDIAN LETTER SADHE;Lo;0;R;;;;;N;;;;; -10F16;OLD SOGDIAN LETTER FINAL SADHE;Lo;0;R;;;;;N;;;;; -10F17;OLD SOGDIAN LETTER FINAL SADHE WITH VERTICAL TAIL;Lo;0;R;;;;;N;;;;; -10F18;OLD SOGDIAN LETTER RESH-AYIN-DALETH;Lo;0;R;;;;;N;;;;; -10F19;OLD SOGDIAN LETTER SHIN;Lo;0;R;;;;;N;;;;; -10F1A;OLD SOGDIAN LETTER TAW;Lo;0;R;;;;;N;;;;; -10F1B;OLD SOGDIAN LETTER FINAL TAW;Lo;0;R;;;;;N;;;;; -10F1C;OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL;Lo;0;R;;;;;N;;;;; -10F1D;OLD SOGDIAN NUMBER ONE;No;0;R;;;;1;N;;;;; -10F1E;OLD SOGDIAN NUMBER TWO;No;0;R;;;;2;N;;;;; -10F1F;OLD SOGDIAN NUMBER THREE;No;0;R;;;;3;N;;;;; -10F20;OLD SOGDIAN NUMBER FOUR;No;0;R;;;;4;N;;;;; -10F21;OLD SOGDIAN NUMBER FIVE;No;0;R;;;;5;N;;;;; -10F22;OLD SOGDIAN NUMBER TEN;No;0;R;;;;10;N;;;;; -10F23;OLD SOGDIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; -10F24;OLD SOGDIAN NUMBER THIRTY;No;0;R;;;;30;N;;;;; -10F25;OLD SOGDIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; -10F26;OLD SOGDIAN FRACTION ONE HALF;No;0;R;;;;1/2;N;;;;; -10F27;OLD SOGDIAN LIGATURE AYIN-DALETH;Lo;0;R;;;;;N;;;;; -10F30;SOGDIAN LETTER ALEPH;Lo;0;AL;;;;;N;;;;; -10F31;SOGDIAN LETTER BETH;Lo;0;AL;;;;;N;;;;; -10F32;SOGDIAN LETTER GIMEL;Lo;0;AL;;;;;N;;;;; -10F33;SOGDIAN LETTER HE;Lo;0;AL;;;;;N;;;;; -10F34;SOGDIAN LETTER WAW;Lo;0;AL;;;;;N;;;;; -10F35;SOGDIAN LETTER ZAYIN;Lo;0;AL;;;;;N;;;;; -10F36;SOGDIAN LETTER HETH;Lo;0;AL;;;;;N;;;;; -10F37;SOGDIAN LETTER YODH;Lo;0;AL;;;;;N;;;;; -10F38;SOGDIAN LETTER KAPH;Lo;0;AL;;;;;N;;;;; -10F39;SOGDIAN LETTER LAMEDH;Lo;0;AL;;;;;N;;;;; -10F3A;SOGDIAN LETTER MEM;Lo;0;AL;;;;;N;;;;; -10F3B;SOGDIAN LETTER NUN;Lo;0;AL;;;;;N;;;;; -10F3C;SOGDIAN LETTER SAMEKH;Lo;0;AL;;;;;N;;;;; -10F3D;SOGDIAN LETTER AYIN;Lo;0;AL;;;;;N;;;;; -10F3E;SOGDIAN LETTER PE;Lo;0;AL;;;;;N;;;;; -10F3F;SOGDIAN LETTER SADHE;Lo;0;AL;;;;;N;;;;; -10F40;SOGDIAN LETTER RESH-AYIN;Lo;0;AL;;;;;N;;;;; -10F41;SOGDIAN LETTER SHIN;Lo;0;AL;;;;;N;;;;; -10F42;SOGDIAN LETTER TAW;Lo;0;AL;;;;;N;;;;; -10F43;SOGDIAN LETTER FETH;Lo;0;AL;;;;;N;;;;; -10F44;SOGDIAN LETTER LESH;Lo;0;AL;;;;;N;;;;; -10F45;SOGDIAN INDEPENDENT SHIN;Lo;0;AL;;;;;N;;;;; -10F46;SOGDIAN COMBINING DOT BELOW;Mn;220;NSM;;;;;N;;;;; -10F47;SOGDIAN COMBINING TWO DOTS BELOW;Mn;220;NSM;;;;;N;;;;; -10F48;SOGDIAN COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;;;;; -10F49;SOGDIAN COMBINING TWO DOTS ABOVE;Mn;230;NSM;;;;;N;;;;; -10F4A;SOGDIAN COMBINING CURVE ABOVE;Mn;230;NSM;;;;;N;;;;; -10F4B;SOGDIAN COMBINING CURVE BELOW;Mn;220;NSM;;;;;N;;;;; -10F4C;SOGDIAN COMBINING HOOK ABOVE;Mn;230;NSM;;;;;N;;;;; -10F4D;SOGDIAN COMBINING HOOK BELOW;Mn;220;NSM;;;;;N;;;;; -10F4E;SOGDIAN COMBINING LONG HOOK BELOW;Mn;220;NSM;;;;;N;;;;; -10F4F;SOGDIAN COMBINING RESH BELOW;Mn;220;NSM;;;;;N;;;;; -10F50;SOGDIAN COMBINING STROKE BELOW;Mn;220;NSM;;;;;N;;;;; -10F51;SOGDIAN NUMBER ONE;No;0;AL;;;;1;N;;;;; -10F52;SOGDIAN NUMBER TEN;No;0;AL;;;;10;N;;;;; -10F53;SOGDIAN NUMBER TWENTY;No;0;AL;;;;20;N;;;;; -10F54;SOGDIAN NUMBER ONE HUNDRED;No;0;AL;;;;100;N;;;;; -10F55;SOGDIAN PUNCTUATION TWO VERTICAL BARS;Po;0;AL;;;;;N;;;;; -10F56;SOGDIAN PUNCTUATION TWO VERTICAL BARS WITH DOTS;Po;0;AL;;;;;N;;;;; -10F57;SOGDIAN PUNCTUATION CIRCLE WITH DOT;Po;0;AL;;;;;N;;;;; -10F58;SOGDIAN PUNCTUATION TWO CIRCLES WITH DOTS;Po;0;AL;;;;;N;;;;; -10F59;SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT;Po;0;AL;;;;;N;;;;; -10F70;OLD UYGHUR LETTER ALEPH;Lo;0;R;;;;;N;;;;; -10F71;OLD UYGHUR LETTER BETH;Lo;0;R;;;;;N;;;;; -10F72;OLD UYGHUR LETTER GIMEL-HETH;Lo;0;R;;;;;N;;;;; -10F73;OLD UYGHUR LETTER WAW;Lo;0;R;;;;;N;;;;; -10F74;OLD UYGHUR LETTER ZAYIN;Lo;0;R;;;;;N;;;;; -10F75;OLD UYGHUR LETTER FINAL HETH;Lo;0;R;;;;;N;;;;; -10F76;OLD UYGHUR LETTER YODH;Lo;0;R;;;;;N;;;;; -10F77;OLD UYGHUR LETTER KAPH;Lo;0;R;;;;;N;;;;; -10F78;OLD UYGHUR LETTER LAMEDH;Lo;0;R;;;;;N;;;;; -10F79;OLD UYGHUR LETTER MEM;Lo;0;R;;;;;N;;;;; -10F7A;OLD UYGHUR LETTER NUN;Lo;0;R;;;;;N;;;;; -10F7B;OLD UYGHUR LETTER SAMEKH;Lo;0;R;;;;;N;;;;; -10F7C;OLD UYGHUR LETTER PE;Lo;0;R;;;;;N;;;;; -10F7D;OLD UYGHUR LETTER SADHE;Lo;0;R;;;;;N;;;;; -10F7E;OLD UYGHUR LETTER RESH;Lo;0;R;;;;;N;;;;; -10F7F;OLD UYGHUR LETTER SHIN;Lo;0;R;;;;;N;;;;; -10F80;OLD UYGHUR LETTER TAW;Lo;0;R;;;;;N;;;;; -10F81;OLD UYGHUR LETTER LESH;Lo;0;R;;;;;N;;;;; -10F82;OLD UYGHUR COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;;;;; -10F83;OLD UYGHUR COMBINING DOT BELOW;Mn;220;NSM;;;;;N;;;;; -10F84;OLD UYGHUR COMBINING TWO DOTS ABOVE;Mn;230;NSM;;;;;N;;;;; -10F85;OLD UYGHUR COMBINING TWO DOTS BELOW;Mn;220;NSM;;;;;N;;;;; -10F86;OLD UYGHUR PUNCTUATION BAR;Po;0;R;;;;;N;;;;; -10F87;OLD UYGHUR PUNCTUATION TWO BARS;Po;0;R;;;;;N;;;;; -10F88;OLD UYGHUR PUNCTUATION TWO DOTS;Po;0;R;;;;;N;;;;; -10F89;OLD UYGHUR PUNCTUATION FOUR DOTS;Po;0;R;;;;;N;;;;; -10FB0;CHORASMIAN LETTER ALEPH;Lo;0;R;;;;;N;;;;; -10FB1;CHORASMIAN LETTER SMALL ALEPH;Lo;0;R;;;;;N;;;;; -10FB2;CHORASMIAN LETTER BETH;Lo;0;R;;;;;N;;;;; -10FB3;CHORASMIAN LETTER GIMEL;Lo;0;R;;;;;N;;;;; -10FB4;CHORASMIAN LETTER DALETH;Lo;0;R;;;;;N;;;;; -10FB5;CHORASMIAN LETTER HE;Lo;0;R;;;;;N;;;;; -10FB6;CHORASMIAN LETTER WAW;Lo;0;R;;;;;N;;;;; -10FB7;CHORASMIAN LETTER CURLED WAW;Lo;0;R;;;;;N;;;;; -10FB8;CHORASMIAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;; -10FB9;CHORASMIAN LETTER HETH;Lo;0;R;;;;;N;;;;; -10FBA;CHORASMIAN LETTER YODH;Lo;0;R;;;;;N;;;;; -10FBB;CHORASMIAN LETTER KAPH;Lo;0;R;;;;;N;;;;; -10FBC;CHORASMIAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;; -10FBD;CHORASMIAN LETTER MEM;Lo;0;R;;;;;N;;;;; -10FBE;CHORASMIAN LETTER NUN;Lo;0;R;;;;;N;;;;; -10FBF;CHORASMIAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;; -10FC0;CHORASMIAN LETTER AYIN;Lo;0;R;;;;;N;;;;; -10FC1;CHORASMIAN LETTER PE;Lo;0;R;;;;;N;;;;; -10FC2;CHORASMIAN LETTER RESH;Lo;0;R;;;;;N;;;;; -10FC3;CHORASMIAN LETTER SHIN;Lo;0;R;;;;;N;;;;; -10FC4;CHORASMIAN LETTER TAW;Lo;0;R;;;;;N;;;;; -10FC5;CHORASMIAN NUMBER ONE;No;0;R;;;;1;N;;;;; -10FC6;CHORASMIAN NUMBER TWO;No;0;R;;;;2;N;;;;; -10FC7;CHORASMIAN NUMBER THREE;No;0;R;;;;3;N;;;;; -10FC8;CHORASMIAN NUMBER FOUR;No;0;R;;;;4;N;;;;; -10FC9;CHORASMIAN NUMBER TEN;No;0;R;;;;10;N;;;;; -10FCA;CHORASMIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; -10FCB;CHORASMIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; -10FE0;ELYMAIC LETTER ALEPH;Lo;0;R;;;;;N;;;;; -10FE1;ELYMAIC LETTER BETH;Lo;0;R;;;;;N;;;;; -10FE2;ELYMAIC LETTER GIMEL;Lo;0;R;;;;;N;;;;; -10FE3;ELYMAIC LETTER DALETH;Lo;0;R;;;;;N;;;;; -10FE4;ELYMAIC LETTER HE;Lo;0;R;;;;;N;;;;; -10FE5;ELYMAIC LETTER WAW;Lo;0;R;;;;;N;;;;; -10FE6;ELYMAIC LETTER ZAYIN;Lo;0;R;;;;;N;;;;; -10FE7;ELYMAIC LETTER HETH;Lo;0;R;;;;;N;;;;; -10FE8;ELYMAIC LETTER TETH;Lo;0;R;;;;;N;;;;; -10FE9;ELYMAIC LETTER YODH;Lo;0;R;;;;;N;;;;; -10FEA;ELYMAIC LETTER KAPH;Lo;0;R;;;;;N;;;;; -10FEB;ELYMAIC LETTER LAMEDH;Lo;0;R;;;;;N;;;;; -10FEC;ELYMAIC LETTER MEM;Lo;0;R;;;;;N;;;;; -10FED;ELYMAIC LETTER NUN;Lo;0;R;;;;;N;;;;; -10FEE;ELYMAIC LETTER SAMEKH;Lo;0;R;;;;;N;;;;; -10FEF;ELYMAIC LETTER AYIN;Lo;0;R;;;;;N;;;;; -10FF0;ELYMAIC LETTER PE;Lo;0;R;;;;;N;;;;; -10FF1;ELYMAIC LETTER SADHE;Lo;0;R;;;;;N;;;;; -10FF2;ELYMAIC LETTER QOPH;Lo;0;R;;;;;N;;;;; -10FF3;ELYMAIC LETTER RESH;Lo;0;R;;;;;N;;;;; -10FF4;ELYMAIC LETTER SHIN;Lo;0;R;;;;;N;;;;; -10FF5;ELYMAIC LETTER TAW;Lo;0;R;;;;;N;;;;; -10FF6;ELYMAIC LIGATURE ZAYIN-YODH;Lo;0;R;;;;;N;;;;; -11000;BRAHMI SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;; -11001;BRAHMI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -11002;BRAHMI SIGN VISARGA;Mc;0;L;;;;;N;;;;; -11003;BRAHMI SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; -11004;BRAHMI SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; -11005;BRAHMI LETTER A;Lo;0;L;;;;;N;;;;; -11006;BRAHMI LETTER AA;Lo;0;L;;;;;N;;;;; -11007;BRAHMI LETTER I;Lo;0;L;;;;;N;;;;; -11008;BRAHMI LETTER II;Lo;0;L;;;;;N;;;;; -11009;BRAHMI LETTER U;Lo;0;L;;;;;N;;;;; -1100A;BRAHMI LETTER UU;Lo;0;L;;;;;N;;;;; -1100B;BRAHMI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; -1100C;BRAHMI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; -1100D;BRAHMI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; -1100E;BRAHMI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; -1100F;BRAHMI LETTER E;Lo;0;L;;;;;N;;;;; -11010;BRAHMI LETTER AI;Lo;0;L;;;;;N;;;;; -11011;BRAHMI LETTER O;Lo;0;L;;;;;N;;;;; -11012;BRAHMI LETTER AU;Lo;0;L;;;;;N;;;;; -11013;BRAHMI LETTER KA;Lo;0;L;;;;;N;;;;; -11014;BRAHMI LETTER KHA;Lo;0;L;;;;;N;;;;; -11015;BRAHMI LETTER GA;Lo;0;L;;;;;N;;;;; -11016;BRAHMI LETTER GHA;Lo;0;L;;;;;N;;;;; -11017;BRAHMI LETTER NGA;Lo;0;L;;;;;N;;;;; -11018;BRAHMI LETTER CA;Lo;0;L;;;;;N;;;;; -11019;BRAHMI LETTER CHA;Lo;0;L;;;;;N;;;;; -1101A;BRAHMI LETTER JA;Lo;0;L;;;;;N;;;;; -1101B;BRAHMI LETTER JHA;Lo;0;L;;;;;N;;;;; -1101C;BRAHMI LETTER NYA;Lo;0;L;;;;;N;;;;; -1101D;BRAHMI LETTER TTA;Lo;0;L;;;;;N;;;;; -1101E;BRAHMI LETTER TTHA;Lo;0;L;;;;;N;;;;; -1101F;BRAHMI LETTER DDA;Lo;0;L;;;;;N;;;;; -11020;BRAHMI LETTER DDHA;Lo;0;L;;;;;N;;;;; -11021;BRAHMI LETTER NNA;Lo;0;L;;;;;N;;;;; -11022;BRAHMI LETTER TA;Lo;0;L;;;;;N;;;;; -11023;BRAHMI LETTER THA;Lo;0;L;;;;;N;;;;; -11024;BRAHMI LETTER DA;Lo;0;L;;;;;N;;;;; -11025;BRAHMI LETTER DHA;Lo;0;L;;;;;N;;;;; -11026;BRAHMI LETTER NA;Lo;0;L;;;;;N;;;;; -11027;BRAHMI LETTER PA;Lo;0;L;;;;;N;;;;; -11028;BRAHMI LETTER PHA;Lo;0;L;;;;;N;;;;; -11029;BRAHMI LETTER BA;Lo;0;L;;;;;N;;;;; -1102A;BRAHMI LETTER BHA;Lo;0;L;;;;;N;;;;; -1102B;BRAHMI LETTER MA;Lo;0;L;;;;;N;;;;; -1102C;BRAHMI LETTER YA;Lo;0;L;;;;;N;;;;; -1102D;BRAHMI LETTER RA;Lo;0;L;;;;;N;;;;; -1102E;BRAHMI LETTER LA;Lo;0;L;;;;;N;;;;; -1102F;BRAHMI LETTER VA;Lo;0;L;;;;;N;;;;; -11030;BRAHMI LETTER SHA;Lo;0;L;;;;;N;;;;; -11031;BRAHMI LETTER SSA;Lo;0;L;;;;;N;;;;; -11032;BRAHMI LETTER SA;Lo;0;L;;;;;N;;;;; -11033;BRAHMI LETTER HA;Lo;0;L;;;;;N;;;;; -11034;BRAHMI LETTER LLA;Lo;0;L;;;;;N;;;;; -11035;BRAHMI LETTER OLD TAMIL LLLA;Lo;0;L;;;;;N;;;;; -11036;BRAHMI LETTER OLD TAMIL RRA;Lo;0;L;;;;;N;;;;; -11037;BRAHMI LETTER OLD TAMIL NNNA;Lo;0;L;;;;;N;;;;; -11038;BRAHMI VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; -11039;BRAHMI VOWEL SIGN BHATTIPROLU AA;Mn;0;NSM;;;;;N;;;;; -1103A;BRAHMI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -1103B;BRAHMI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; -1103C;BRAHMI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -1103D;BRAHMI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -1103E;BRAHMI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -1103F;BRAHMI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; -11040;BRAHMI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; -11041;BRAHMI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; -11042;BRAHMI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -11043;BRAHMI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -11044;BRAHMI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; -11045;BRAHMI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; -11046;BRAHMI VIRAMA;Mn;9;NSM;;;;;N;;;;; -11047;BRAHMI DANDA;Po;0;L;;;;;N;;;;; -11048;BRAHMI DOUBLE DANDA;Po;0;L;;;;;N;;;;; -11049;BRAHMI PUNCTUATION DOT;Po;0;L;;;;;N;;;;; -1104A;BRAHMI PUNCTUATION DOUBLE DOT;Po;0;L;;;;;N;;;;; -1104B;BRAHMI PUNCTUATION LINE;Po;0;L;;;;;N;;;;; -1104C;BRAHMI PUNCTUATION CRESCENT BAR;Po;0;L;;;;;N;;;;; -1104D;BRAHMI PUNCTUATION LOTUS;Po;0;L;;;;;N;;;;; -11052;BRAHMI NUMBER ONE;No;0;ON;;;1;1;N;;;;; -11053;BRAHMI NUMBER TWO;No;0;ON;;;2;2;N;;;;; -11054;BRAHMI NUMBER THREE;No;0;ON;;;3;3;N;;;;; -11055;BRAHMI NUMBER FOUR;No;0;ON;;;4;4;N;;;;; -11056;BRAHMI NUMBER FIVE;No;0;ON;;;5;5;N;;;;; -11057;BRAHMI NUMBER SIX;No;0;ON;;;6;6;N;;;;; -11058;BRAHMI NUMBER SEVEN;No;0;ON;;;7;7;N;;;;; -11059;BRAHMI NUMBER EIGHT;No;0;ON;;;8;8;N;;;;; -1105A;BRAHMI NUMBER NINE;No;0;ON;;;9;9;N;;;;; -1105B;BRAHMI NUMBER TEN;No;0;ON;;;;10;N;;;;; -1105C;BRAHMI NUMBER TWENTY;No;0;ON;;;;20;N;;;;; -1105D;BRAHMI NUMBER THIRTY;No;0;ON;;;;30;N;;;;; -1105E;BRAHMI NUMBER FORTY;No;0;ON;;;;40;N;;;;; -1105F;BRAHMI NUMBER FIFTY;No;0;ON;;;;50;N;;;;; -11060;BRAHMI NUMBER SIXTY;No;0;ON;;;;60;N;;;;; -11061;BRAHMI NUMBER SEVENTY;No;0;ON;;;;70;N;;;;; -11062;BRAHMI NUMBER EIGHTY;No;0;ON;;;;80;N;;;;; -11063;BRAHMI NUMBER NINETY;No;0;ON;;;;90;N;;;;; -11064;BRAHMI NUMBER ONE HUNDRED;No;0;ON;;;;100;N;;;;; -11065;BRAHMI NUMBER ONE THOUSAND;No;0;ON;;;;1000;N;;;;; -11066;BRAHMI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -11067;BRAHMI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -11068;BRAHMI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -11069;BRAHMI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -1106A;BRAHMI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -1106B;BRAHMI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -1106C;BRAHMI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -1106D;BRAHMI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -1106E;BRAHMI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -1106F;BRAHMI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -11070;BRAHMI SIGN OLD TAMIL VIRAMA;Mn;9;NSM;;;;;N;;;;; -11071;BRAHMI LETTER OLD TAMIL SHORT E;Lo;0;L;;;;;N;;;;; -11072;BRAHMI LETTER OLD TAMIL SHORT O;Lo;0;L;;;;;N;;;;; -11073;BRAHMI VOWEL SIGN OLD TAMIL SHORT E;Mn;0;NSM;;;;;N;;;;; -11074;BRAHMI VOWEL SIGN OLD TAMIL SHORT O;Mn;0;NSM;;;;;N;;;;; -11075;BRAHMI LETTER OLD TAMIL LLA;Lo;0;L;;;;;N;;;;; -1107F;BRAHMI NUMBER JOINER;Mn;9;NSM;;;;;N;;;;; -11080;KAITHI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -11081;KAITHI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -11082;KAITHI SIGN VISARGA;Mc;0;L;;;;;N;;;;; -11083;KAITHI LETTER A;Lo;0;L;;;;;N;;;;; -11084;KAITHI LETTER AA;Lo;0;L;;;;;N;;;;; -11085;KAITHI LETTER I;Lo;0;L;;;;;N;;;;; -11086;KAITHI LETTER II;Lo;0;L;;;;;N;;;;; -11087;KAITHI LETTER U;Lo;0;L;;;;;N;;;;; -11088;KAITHI LETTER UU;Lo;0;L;;;;;N;;;;; -11089;KAITHI LETTER E;Lo;0;L;;;;;N;;;;; -1108A;KAITHI LETTER AI;Lo;0;L;;;;;N;;;;; -1108B;KAITHI LETTER O;Lo;0;L;;;;;N;;;;; -1108C;KAITHI LETTER AU;Lo;0;L;;;;;N;;;;; -1108D;KAITHI LETTER KA;Lo;0;L;;;;;N;;;;; -1108E;KAITHI LETTER KHA;Lo;0;L;;;;;N;;;;; -1108F;KAITHI LETTER GA;Lo;0;L;;;;;N;;;;; -11090;KAITHI LETTER GHA;Lo;0;L;;;;;N;;;;; -11091;KAITHI LETTER NGA;Lo;0;L;;;;;N;;;;; -11092;KAITHI LETTER CA;Lo;0;L;;;;;N;;;;; -11093;KAITHI LETTER CHA;Lo;0;L;;;;;N;;;;; -11094;KAITHI LETTER JA;Lo;0;L;;;;;N;;;;; -11095;KAITHI LETTER JHA;Lo;0;L;;;;;N;;;;; -11096;KAITHI LETTER NYA;Lo;0;L;;;;;N;;;;; -11097;KAITHI LETTER TTA;Lo;0;L;;;;;N;;;;; -11098;KAITHI LETTER TTHA;Lo;0;L;;;;;N;;;;; -11099;KAITHI LETTER DDA;Lo;0;L;;;;;N;;;;; -1109A;KAITHI LETTER DDDHA;Lo;0;L;11099 110BA;;;;N;;;;; -1109B;KAITHI LETTER DDHA;Lo;0;L;;;;;N;;;;; -1109C;KAITHI LETTER RHA;Lo;0;L;1109B 110BA;;;;N;;;;; -1109D;KAITHI LETTER NNA;Lo;0;L;;;;;N;;;;; -1109E;KAITHI LETTER TA;Lo;0;L;;;;;N;;;;; -1109F;KAITHI LETTER THA;Lo;0;L;;;;;N;;;;; -110A0;KAITHI LETTER DA;Lo;0;L;;;;;N;;;;; -110A1;KAITHI LETTER DHA;Lo;0;L;;;;;N;;;;; -110A2;KAITHI LETTER NA;Lo;0;L;;;;;N;;;;; -110A3;KAITHI LETTER PA;Lo;0;L;;;;;N;;;;; -110A4;KAITHI LETTER PHA;Lo;0;L;;;;;N;;;;; -110A5;KAITHI LETTER BA;Lo;0;L;;;;;N;;;;; -110A6;KAITHI LETTER BHA;Lo;0;L;;;;;N;;;;; -110A7;KAITHI LETTER MA;Lo;0;L;;;;;N;;;;; -110A8;KAITHI LETTER YA;Lo;0;L;;;;;N;;;;; -110A9;KAITHI LETTER RA;Lo;0;L;;;;;N;;;;; -110AA;KAITHI LETTER LA;Lo;0;L;;;;;N;;;;; -110AB;KAITHI LETTER VA;Lo;0;L;110A5 110BA;;;;N;;;;; -110AC;KAITHI LETTER SHA;Lo;0;L;;;;;N;;;;; -110AD;KAITHI LETTER SSA;Lo;0;L;;;;;N;;;;; -110AE;KAITHI LETTER SA;Lo;0;L;;;;;N;;;;; -110AF;KAITHI LETTER HA;Lo;0;L;;;;;N;;;;; -110B0;KAITHI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -110B1;KAITHI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -110B2;KAITHI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -110B3;KAITHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -110B4;KAITHI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -110B5;KAITHI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -110B6;KAITHI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -110B7;KAITHI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; -110B8;KAITHI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; -110B9;KAITHI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -110BA;KAITHI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -110BB;KAITHI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; -110BC;KAITHI ENUMERATION SIGN;Po;0;L;;;;;N;;;;; -110BD;KAITHI NUMBER SIGN;Cf;0;L;;;;;N;;;;; -110BE;KAITHI SECTION MARK;Po;0;L;;;;;N;;;;; -110BF;KAITHI DOUBLE SECTION MARK;Po;0;L;;;;;N;;;;; -110C0;KAITHI DANDA;Po;0;L;;;;;N;;;;; -110C1;KAITHI DOUBLE DANDA;Po;0;L;;;;;N;;;;; -110C2;KAITHI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -110CD;KAITHI NUMBER SIGN ABOVE;Cf;0;L;;;;;N;;;;; -110D0;SORA SOMPENG LETTER SAH;Lo;0;L;;;;;N;;;;; -110D1;SORA SOMPENG LETTER TAH;Lo;0;L;;;;;N;;;;; -110D2;SORA SOMPENG LETTER BAH;Lo;0;L;;;;;N;;;;; -110D3;SORA SOMPENG LETTER CAH;Lo;0;L;;;;;N;;;;; -110D4;SORA SOMPENG LETTER DAH;Lo;0;L;;;;;N;;;;; -110D5;SORA SOMPENG LETTER GAH;Lo;0;L;;;;;N;;;;; -110D6;SORA SOMPENG LETTER MAH;Lo;0;L;;;;;N;;;;; -110D7;SORA SOMPENG LETTER NGAH;Lo;0;L;;;;;N;;;;; -110D8;SORA SOMPENG LETTER LAH;Lo;0;L;;;;;N;;;;; -110D9;SORA SOMPENG LETTER NAH;Lo;0;L;;;;;N;;;;; -110DA;SORA SOMPENG LETTER VAH;Lo;0;L;;;;;N;;;;; -110DB;SORA SOMPENG LETTER PAH;Lo;0;L;;;;;N;;;;; -110DC;SORA SOMPENG LETTER YAH;Lo;0;L;;;;;N;;;;; -110DD;SORA SOMPENG LETTER RAH;Lo;0;L;;;;;N;;;;; -110DE;SORA SOMPENG LETTER HAH;Lo;0;L;;;;;N;;;;; -110DF;SORA SOMPENG LETTER KAH;Lo;0;L;;;;;N;;;;; -110E0;SORA SOMPENG LETTER JAH;Lo;0;L;;;;;N;;;;; -110E1;SORA SOMPENG LETTER NYAH;Lo;0;L;;;;;N;;;;; -110E2;SORA SOMPENG LETTER AH;Lo;0;L;;;;;N;;;;; -110E3;SORA SOMPENG LETTER EEH;Lo;0;L;;;;;N;;;;; -110E4;SORA SOMPENG LETTER IH;Lo;0;L;;;;;N;;;;; -110E5;SORA SOMPENG LETTER UH;Lo;0;L;;;;;N;;;;; -110E6;SORA SOMPENG LETTER OH;Lo;0;L;;;;;N;;;;; -110E7;SORA SOMPENG LETTER EH;Lo;0;L;;;;;N;;;;; -110E8;SORA SOMPENG LETTER MAE;Lo;0;L;;;;;N;;;;; -110F0;SORA SOMPENG DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -110F1;SORA SOMPENG DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -110F2;SORA SOMPENG DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -110F3;SORA SOMPENG DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -110F4;SORA SOMPENG DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -110F5;SORA SOMPENG DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -110F6;SORA SOMPENG DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -110F7;SORA SOMPENG DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -110F8;SORA SOMPENG DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -110F9;SORA SOMPENG DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -11100;CHAKMA SIGN CANDRABINDU;Mn;230;NSM;;;;;N;;;;; -11101;CHAKMA SIGN ANUSVARA;Mn;230;NSM;;;;;N;;;;; -11102;CHAKMA SIGN VISARGA;Mn;230;NSM;;;;;N;;;;; -11103;CHAKMA LETTER AA;Lo;0;L;;;;;N;;;;; -11104;CHAKMA LETTER I;Lo;0;L;;;;;N;;;;; -11105;CHAKMA LETTER U;Lo;0;L;;;;;N;;;;; -11106;CHAKMA LETTER E;Lo;0;L;;;;;N;;;;; -11107;CHAKMA LETTER KAA;Lo;0;L;;;;;N;;;;; -11108;CHAKMA LETTER KHAA;Lo;0;L;;;;;N;;;;; -11109;CHAKMA LETTER GAA;Lo;0;L;;;;;N;;;;; -1110A;CHAKMA LETTER GHAA;Lo;0;L;;;;;N;;;;; -1110B;CHAKMA LETTER NGAA;Lo;0;L;;;;;N;;;;; -1110C;CHAKMA LETTER CAA;Lo;0;L;;;;;N;;;;; -1110D;CHAKMA LETTER CHAA;Lo;0;L;;;;;N;;;;; -1110E;CHAKMA LETTER JAA;Lo;0;L;;;;;N;;;;; -1110F;CHAKMA LETTER JHAA;Lo;0;L;;;;;N;;;;; -11110;CHAKMA LETTER NYAA;Lo;0;L;;;;;N;;;;; -11111;CHAKMA LETTER TTAA;Lo;0;L;;;;;N;;;;; -11112;CHAKMA LETTER TTHAA;Lo;0;L;;;;;N;;;;; -11113;CHAKMA LETTER DDAA;Lo;0;L;;;;;N;;;;; -11114;CHAKMA LETTER DDHAA;Lo;0;L;;;;;N;;;;; -11115;CHAKMA LETTER NNAA;Lo;0;L;;;;;N;;;;; -11116;CHAKMA LETTER TAA;Lo;0;L;;;;;N;;;;; -11117;CHAKMA LETTER THAA;Lo;0;L;;;;;N;;;;; -11118;CHAKMA LETTER DAA;Lo;0;L;;;;;N;;;;; -11119;CHAKMA LETTER DHAA;Lo;0;L;;;;;N;;;;; -1111A;CHAKMA LETTER NAA;Lo;0;L;;;;;N;;;;; -1111B;CHAKMA LETTER PAA;Lo;0;L;;;;;N;;;;; -1111C;CHAKMA LETTER PHAA;Lo;0;L;;;;;N;;;;; -1111D;CHAKMA LETTER BAA;Lo;0;L;;;;;N;;;;; -1111E;CHAKMA LETTER BHAA;Lo;0;L;;;;;N;;;;; -1111F;CHAKMA LETTER MAA;Lo;0;L;;;;;N;;;;; -11120;CHAKMA LETTER YYAA;Lo;0;L;;;;;N;;;;; -11121;CHAKMA LETTER YAA;Lo;0;L;;;;;N;;;;; -11122;CHAKMA LETTER RAA;Lo;0;L;;;;;N;;;;; -11123;CHAKMA LETTER LAA;Lo;0;L;;;;;N;;;;; -11124;CHAKMA LETTER WAA;Lo;0;L;;;;;N;;;;; -11125;CHAKMA LETTER SAA;Lo;0;L;;;;;N;;;;; -11126;CHAKMA LETTER HAA;Lo;0;L;;;;;N;;;;; -11127;CHAKMA VOWEL SIGN A;Mn;0;NSM;;;;;N;;;;; -11128;CHAKMA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -11129;CHAKMA VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; -1112A;CHAKMA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -1112B;CHAKMA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -1112C;CHAKMA VOWEL SIGN E;Mc;0;L;;;;;N;;;;; -1112D;CHAKMA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -1112E;CHAKMA VOWEL SIGN O;Mn;0;NSM;11131 11127;;;;N;;;;; -1112F;CHAKMA VOWEL SIGN AU;Mn;0;NSM;11132 11127;;;;N;;;;; -11130;CHAKMA VOWEL SIGN OI;Mn;0;NSM;;;;;N;;;;; -11131;CHAKMA O MARK;Mn;0;NSM;;;;;N;;;;; -11132;CHAKMA AU MARK;Mn;0;NSM;;;;;N;;;;; -11133;CHAKMA VIRAMA;Mn;9;NSM;;;;;N;;;;; -11134;CHAKMA MAAYYAA;Mn;9;NSM;;;;;N;;;;; -11136;CHAKMA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -11137;CHAKMA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -11138;CHAKMA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -11139;CHAKMA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -1113A;CHAKMA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -1113B;CHAKMA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -1113C;CHAKMA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -1113D;CHAKMA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -1113E;CHAKMA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -1113F;CHAKMA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -11140;CHAKMA SECTION MARK;Po;0;L;;;;;N;;;;; -11141;CHAKMA DANDA;Po;0;L;;;;;N;;;;; -11142;CHAKMA DOUBLE DANDA;Po;0;L;;;;;N;;;;; -11143;CHAKMA QUESTION MARK;Po;0;L;;;;;N;;;;; -11144;CHAKMA LETTER LHAA;Lo;0;L;;;;;N;;;;; -11145;CHAKMA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -11146;CHAKMA VOWEL SIGN EI;Mc;0;L;;;;;N;;;;; -11147;CHAKMA LETTER VAA;Lo;0;L;;;;;N;;;;; -11150;MAHAJANI LETTER A;Lo;0;L;;;;;N;;;;; -11151;MAHAJANI LETTER I;Lo;0;L;;;;;N;;;;; -11152;MAHAJANI LETTER U;Lo;0;L;;;;;N;;;;; -11153;MAHAJANI LETTER E;Lo;0;L;;;;;N;;;;; -11154;MAHAJANI LETTER O;Lo;0;L;;;;;N;;;;; -11155;MAHAJANI LETTER KA;Lo;0;L;;;;;N;;;;; -11156;MAHAJANI LETTER KHA;Lo;0;L;;;;;N;;;;; -11157;MAHAJANI LETTER GA;Lo;0;L;;;;;N;;;;; -11158;MAHAJANI LETTER GHA;Lo;0;L;;;;;N;;;;; -11159;MAHAJANI LETTER CA;Lo;0;L;;;;;N;;;;; -1115A;MAHAJANI LETTER CHA;Lo;0;L;;;;;N;;;;; -1115B;MAHAJANI LETTER JA;Lo;0;L;;;;;N;;;;; -1115C;MAHAJANI LETTER JHA;Lo;0;L;;;;;N;;;;; -1115D;MAHAJANI LETTER NYA;Lo;0;L;;;;;N;;;;; -1115E;MAHAJANI LETTER TTA;Lo;0;L;;;;;N;;;;; -1115F;MAHAJANI LETTER TTHA;Lo;0;L;;;;;N;;;;; -11160;MAHAJANI LETTER DDA;Lo;0;L;;;;;N;;;;; -11161;MAHAJANI LETTER DDHA;Lo;0;L;;;;;N;;;;; -11162;MAHAJANI LETTER NNA;Lo;0;L;;;;;N;;;;; -11163;MAHAJANI LETTER TA;Lo;0;L;;;;;N;;;;; -11164;MAHAJANI LETTER THA;Lo;0;L;;;;;N;;;;; -11165;MAHAJANI LETTER DA;Lo;0;L;;;;;N;;;;; -11166;MAHAJANI LETTER DHA;Lo;0;L;;;;;N;;;;; -11167;MAHAJANI LETTER NA;Lo;0;L;;;;;N;;;;; -11168;MAHAJANI LETTER PA;Lo;0;L;;;;;N;;;;; -11169;MAHAJANI LETTER PHA;Lo;0;L;;;;;N;;;;; -1116A;MAHAJANI LETTER BA;Lo;0;L;;;;;N;;;;; -1116B;MAHAJANI LETTER BHA;Lo;0;L;;;;;N;;;;; -1116C;MAHAJANI LETTER MA;Lo;0;L;;;;;N;;;;; -1116D;MAHAJANI LETTER RA;Lo;0;L;;;;;N;;;;; -1116E;MAHAJANI LETTER LA;Lo;0;L;;;;;N;;;;; -1116F;MAHAJANI LETTER VA;Lo;0;L;;;;;N;;;;; -11170;MAHAJANI LETTER SA;Lo;0;L;;;;;N;;;;; -11171;MAHAJANI LETTER HA;Lo;0;L;;;;;N;;;;; -11172;MAHAJANI LETTER RRA;Lo;0;L;;;;;N;;;;; -11173;MAHAJANI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -11174;MAHAJANI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; -11175;MAHAJANI SECTION MARK;Po;0;L;;;;;N;;;;; -11176;MAHAJANI LIGATURE SHRI;Lo;0;L;;;;;N;;;;; -11180;SHARADA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -11181;SHARADA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -11182;SHARADA SIGN VISARGA;Mc;0;L;;;;;N;;;;; -11183;SHARADA LETTER A;Lo;0;L;;;;;N;;;;; -11184;SHARADA LETTER AA;Lo;0;L;;;;;N;;;;; -11185;SHARADA LETTER I;Lo;0;L;;;;;N;;;;; -11186;SHARADA LETTER II;Lo;0;L;;;;;N;;;;; -11187;SHARADA LETTER U;Lo;0;L;;;;;N;;;;; -11188;SHARADA LETTER UU;Lo;0;L;;;;;N;;;;; -11189;SHARADA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; -1118A;SHARADA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; -1118B;SHARADA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; -1118C;SHARADA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; -1118D;SHARADA LETTER E;Lo;0;L;;;;;N;;;;; -1118E;SHARADA LETTER AI;Lo;0;L;;;;;N;;;;; -1118F;SHARADA LETTER O;Lo;0;L;;;;;N;;;;; -11190;SHARADA LETTER AU;Lo;0;L;;;;;N;;;;; -11191;SHARADA LETTER KA;Lo;0;L;;;;;N;;;;; -11192;SHARADA LETTER KHA;Lo;0;L;;;;;N;;;;; -11193;SHARADA LETTER GA;Lo;0;L;;;;;N;;;;; -11194;SHARADA LETTER GHA;Lo;0;L;;;;;N;;;;; -11195;SHARADA LETTER NGA;Lo;0;L;;;;;N;;;;; -11196;SHARADA LETTER CA;Lo;0;L;;;;;N;;;;; -11197;SHARADA LETTER CHA;Lo;0;L;;;;;N;;;;; -11198;SHARADA LETTER JA;Lo;0;L;;;;;N;;;;; -11199;SHARADA LETTER JHA;Lo;0;L;;;;;N;;;;; -1119A;SHARADA LETTER NYA;Lo;0;L;;;;;N;;;;; -1119B;SHARADA LETTER TTA;Lo;0;L;;;;;N;;;;; -1119C;SHARADA LETTER TTHA;Lo;0;L;;;;;N;;;;; -1119D;SHARADA LETTER DDA;Lo;0;L;;;;;N;;;;; -1119E;SHARADA LETTER DDHA;Lo;0;L;;;;;N;;;;; -1119F;SHARADA LETTER NNA;Lo;0;L;;;;;N;;;;; -111A0;SHARADA LETTER TA;Lo;0;L;;;;;N;;;;; -111A1;SHARADA LETTER THA;Lo;0;L;;;;;N;;;;; -111A2;SHARADA LETTER DA;Lo;0;L;;;;;N;;;;; -111A3;SHARADA LETTER DHA;Lo;0;L;;;;;N;;;;; -111A4;SHARADA LETTER NA;Lo;0;L;;;;;N;;;;; -111A5;SHARADA LETTER PA;Lo;0;L;;;;;N;;;;; -111A6;SHARADA LETTER PHA;Lo;0;L;;;;;N;;;;; -111A7;SHARADA LETTER BA;Lo;0;L;;;;;N;;;;; -111A8;SHARADA LETTER BHA;Lo;0;L;;;;;N;;;;; -111A9;SHARADA LETTER MA;Lo;0;L;;;;;N;;;;; -111AA;SHARADA LETTER YA;Lo;0;L;;;;;N;;;;; -111AB;SHARADA LETTER RA;Lo;0;L;;;;;N;;;;; -111AC;SHARADA LETTER LA;Lo;0;L;;;;;N;;;;; -111AD;SHARADA LETTER LLA;Lo;0;L;;;;;N;;;;; -111AE;SHARADA LETTER VA;Lo;0;L;;;;;N;;;;; -111AF;SHARADA LETTER SHA;Lo;0;L;;;;;N;;;;; -111B0;SHARADA LETTER SSA;Lo;0;L;;;;;N;;;;; -111B1;SHARADA LETTER SA;Lo;0;L;;;;;N;;;;; -111B2;SHARADA LETTER HA;Lo;0;L;;;;;N;;;;; -111B3;SHARADA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -111B4;SHARADA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -111B5;SHARADA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -111B6;SHARADA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -111B7;SHARADA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -111B8;SHARADA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -111B9;SHARADA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; -111BA;SHARADA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; -111BB;SHARADA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; -111BC;SHARADA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -111BD;SHARADA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -111BE;SHARADA VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; -111BF;SHARADA VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; -111C0;SHARADA SIGN VIRAMA;Mc;9;L;;;;;N;;;;; -111C1;SHARADA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; -111C2;SHARADA SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; -111C3;SHARADA SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; -111C4;SHARADA OM;Lo;0;L;;;;;N;;;;; -111C5;SHARADA DANDA;Po;0;L;;;;;N;;;;; -111C6;SHARADA DOUBLE DANDA;Po;0;L;;;;;N;;;;; -111C7;SHARADA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; -111C8;SHARADA SEPARATOR;Po;0;L;;;;;N;;;;; -111C9;SHARADA SANDHI MARK;Mn;0;NSM;;;;;N;;;;; -111CA;SHARADA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -111CB;SHARADA VOWEL MODIFIER MARK;Mn;0;NSM;;;;;N;;;;; -111CC;SHARADA EXTRA SHORT VOWEL MARK;Mn;0;NSM;;;;;N;;;;; -111CD;SHARADA SUTRA MARK;Po;0;L;;;;;N;;;;; -111CE;SHARADA VOWEL SIGN PRISHTHAMATRA E;Mc;0;L;;;;;N;;;;; -111CF;SHARADA SIGN INVERTED CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -111D0;SHARADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -111D1;SHARADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -111D2;SHARADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -111D3;SHARADA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -111D4;SHARADA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -111D5;SHARADA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -111D6;SHARADA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -111D7;SHARADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -111D8;SHARADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -111D9;SHARADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -111DA;SHARADA EKAM;Lo;0;L;;;;;N;;;;; -111DB;SHARADA SIGN SIDDHAM;Po;0;L;;;;;N;;;;; -111DC;SHARADA HEADSTROKE;Lo;0;L;;;;;N;;;;; -111DD;SHARADA CONTINUATION SIGN;Po;0;L;;;;;N;;;;; -111DE;SHARADA SECTION MARK-1;Po;0;L;;;;;N;;;;; -111DF;SHARADA SECTION MARK-2;Po;0;L;;;;;N;;;;; -111E1;SINHALA ARCHAIC DIGIT ONE;No;0;L;;;;1;N;;;;; -111E2;SINHALA ARCHAIC DIGIT TWO;No;0;L;;;;2;N;;;;; -111E3;SINHALA ARCHAIC DIGIT THREE;No;0;L;;;;3;N;;;;; -111E4;SINHALA ARCHAIC DIGIT FOUR;No;0;L;;;;4;N;;;;; -111E5;SINHALA ARCHAIC DIGIT FIVE;No;0;L;;;;5;N;;;;; -111E6;SINHALA ARCHAIC DIGIT SIX;No;0;L;;;;6;N;;;;; -111E7;SINHALA ARCHAIC DIGIT SEVEN;No;0;L;;;;7;N;;;;; -111E8;SINHALA ARCHAIC DIGIT EIGHT;No;0;L;;;;8;N;;;;; -111E9;SINHALA ARCHAIC DIGIT NINE;No;0;L;;;;9;N;;;;; -111EA;SINHALA ARCHAIC NUMBER TEN;No;0;L;;;;10;N;;;;; -111EB;SINHALA ARCHAIC NUMBER TWENTY;No;0;L;;;;20;N;;;;; -111EC;SINHALA ARCHAIC NUMBER THIRTY;No;0;L;;;;30;N;;;;; -111ED;SINHALA ARCHAIC NUMBER FORTY;No;0;L;;;;40;N;;;;; -111EE;SINHALA ARCHAIC NUMBER FIFTY;No;0;L;;;;50;N;;;;; -111EF;SINHALA ARCHAIC NUMBER SIXTY;No;0;L;;;;60;N;;;;; -111F0;SINHALA ARCHAIC NUMBER SEVENTY;No;0;L;;;;70;N;;;;; -111F1;SINHALA ARCHAIC NUMBER EIGHTY;No;0;L;;;;80;N;;;;; -111F2;SINHALA ARCHAIC NUMBER NINETY;No;0;L;;;;90;N;;;;; -111F3;SINHALA ARCHAIC NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;; -111F4;SINHALA ARCHAIC NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;; -11200;KHOJKI LETTER A;Lo;0;L;;;;;N;;;;; -11201;KHOJKI LETTER AA;Lo;0;L;;;;;N;;;;; -11202;KHOJKI LETTER I;Lo;0;L;;;;;N;;;;; -11203;KHOJKI LETTER U;Lo;0;L;;;;;N;;;;; -11204;KHOJKI LETTER E;Lo;0;L;;;;;N;;;;; -11205;KHOJKI LETTER AI;Lo;0;L;;;;;N;;;;; -11206;KHOJKI LETTER O;Lo;0;L;;;;;N;;;;; -11207;KHOJKI LETTER AU;Lo;0;L;;;;;N;;;;; -11208;KHOJKI LETTER KA;Lo;0;L;;;;;N;;;;; -11209;KHOJKI LETTER KHA;Lo;0;L;;;;;N;;;;; -1120A;KHOJKI LETTER GA;Lo;0;L;;;;;N;;;;; -1120B;KHOJKI LETTER GGA;Lo;0;L;;;;;N;;;;; -1120C;KHOJKI LETTER GHA;Lo;0;L;;;;;N;;;;; -1120D;KHOJKI LETTER NGA;Lo;0;L;;;;;N;;;;; -1120E;KHOJKI LETTER CA;Lo;0;L;;;;;N;;;;; -1120F;KHOJKI LETTER CHA;Lo;0;L;;;;;N;;;;; -11210;KHOJKI LETTER JA;Lo;0;L;;;;;N;;;;; -11211;KHOJKI LETTER JJA;Lo;0;L;;;;;N;;;;; -11213;KHOJKI LETTER NYA;Lo;0;L;;;;;N;;;;; -11214;KHOJKI LETTER TTA;Lo;0;L;;;;;N;;;;; -11215;KHOJKI LETTER TTHA;Lo;0;L;;;;;N;;;;; -11216;KHOJKI LETTER DDA;Lo;0;L;;;;;N;;;;; -11217;KHOJKI LETTER DDHA;Lo;0;L;;;;;N;;;;; -11218;KHOJKI LETTER NNA;Lo;0;L;;;;;N;;;;; -11219;KHOJKI LETTER TA;Lo;0;L;;;;;N;;;;; -1121A;KHOJKI LETTER THA;Lo;0;L;;;;;N;;;;; -1121B;KHOJKI LETTER DA;Lo;0;L;;;;;N;;;;; -1121C;KHOJKI LETTER DDDA;Lo;0;L;;;;;N;;;;; -1121D;KHOJKI LETTER DHA;Lo;0;L;;;;;N;;;;; -1121E;KHOJKI LETTER NA;Lo;0;L;;;;;N;;;;; -1121F;KHOJKI LETTER PA;Lo;0;L;;;;;N;;;;; -11220;KHOJKI LETTER PHA;Lo;0;L;;;;;N;;;;; -11221;KHOJKI LETTER BA;Lo;0;L;;;;;N;;;;; -11222;KHOJKI LETTER BBA;Lo;0;L;;;;;N;;;;; -11223;KHOJKI LETTER BHA;Lo;0;L;;;;;N;;;;; -11224;KHOJKI LETTER MA;Lo;0;L;;;;;N;;;;; -11225;KHOJKI LETTER YA;Lo;0;L;;;;;N;;;;; -11226;KHOJKI LETTER RA;Lo;0;L;;;;;N;;;;; -11227;KHOJKI LETTER LA;Lo;0;L;;;;;N;;;;; -11228;KHOJKI LETTER VA;Lo;0;L;;;;;N;;;;; -11229;KHOJKI LETTER SA;Lo;0;L;;;;;N;;;;; -1122A;KHOJKI LETTER HA;Lo;0;L;;;;;N;;;;; -1122B;KHOJKI LETTER LLA;Lo;0;L;;;;;N;;;;; -1122C;KHOJKI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -1122D;KHOJKI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -1122E;KHOJKI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -1122F;KHOJKI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -11230;KHOJKI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -11231;KHOJKI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -11232;KHOJKI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; -11233;KHOJKI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; -11234;KHOJKI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -11235;KHOJKI SIGN VIRAMA;Mc;9;L;;;;;N;;;;; -11236;KHOJKI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -11237;KHOJKI SIGN SHADDA;Mn;0;NSM;;;;;N;;;;; -11238;KHOJKI DANDA;Po;0;L;;;;;N;;;;; -11239;KHOJKI DOUBLE DANDA;Po;0;L;;;;;N;;;;; -1123A;KHOJKI WORD SEPARATOR;Po;0;L;;;;;N;;;;; -1123B;KHOJKI SECTION MARK;Po;0;L;;;;;N;;;;; -1123C;KHOJKI DOUBLE SECTION MARK;Po;0;L;;;;;N;;;;; -1123D;KHOJKI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; -1123E;KHOJKI SIGN SUKUN;Mn;0;NSM;;;;;N;;;;; -1123F;KHOJKI LETTER QA;Lo;0;L;;;;;N;;;;; -11240;KHOJKI LETTER SHORT I;Lo;0;L;;;;;N;;;;; -11241;KHOJKI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -11280;MULTANI LETTER A;Lo;0;L;;;;;N;;;;; -11281;MULTANI LETTER I;Lo;0;L;;;;;N;;;;; -11282;MULTANI LETTER U;Lo;0;L;;;;;N;;;;; -11283;MULTANI LETTER E;Lo;0;L;;;;;N;;;;; -11284;MULTANI LETTER KA;Lo;0;L;;;;;N;;;;; -11285;MULTANI LETTER KHA;Lo;0;L;;;;;N;;;;; -11286;MULTANI LETTER GA;Lo;0;L;;;;;N;;;;; -11288;MULTANI LETTER GHA;Lo;0;L;;;;;N;;;;; -1128A;MULTANI LETTER CA;Lo;0;L;;;;;N;;;;; -1128B;MULTANI LETTER CHA;Lo;0;L;;;;;N;;;;; -1128C;MULTANI LETTER JA;Lo;0;L;;;;;N;;;;; -1128D;MULTANI LETTER JJA;Lo;0;L;;;;;N;;;;; -1128F;MULTANI LETTER NYA;Lo;0;L;;;;;N;;;;; -11290;MULTANI LETTER TTA;Lo;0;L;;;;;N;;;;; -11291;MULTANI LETTER TTHA;Lo;0;L;;;;;N;;;;; -11292;MULTANI LETTER DDA;Lo;0;L;;;;;N;;;;; -11293;MULTANI LETTER DDDA;Lo;0;L;;;;;N;;;;; -11294;MULTANI LETTER DDHA;Lo;0;L;;;;;N;;;;; -11295;MULTANI LETTER NNA;Lo;0;L;;;;;N;;;;; -11296;MULTANI LETTER TA;Lo;0;L;;;;;N;;;;; -11297;MULTANI LETTER THA;Lo;0;L;;;;;N;;;;; -11298;MULTANI LETTER DA;Lo;0;L;;;;;N;;;;; -11299;MULTANI LETTER DHA;Lo;0;L;;;;;N;;;;; -1129A;MULTANI LETTER NA;Lo;0;L;;;;;N;;;;; -1129B;MULTANI LETTER PA;Lo;0;L;;;;;N;;;;; -1129C;MULTANI LETTER PHA;Lo;0;L;;;;;N;;;;; -1129D;MULTANI LETTER BA;Lo;0;L;;;;;N;;;;; -1129F;MULTANI LETTER BHA;Lo;0;L;;;;;N;;;;; -112A0;MULTANI LETTER MA;Lo;0;L;;;;;N;;;;; -112A1;MULTANI LETTER YA;Lo;0;L;;;;;N;;;;; -112A2;MULTANI LETTER RA;Lo;0;L;;;;;N;;;;; -112A3;MULTANI LETTER LA;Lo;0;L;;;;;N;;;;; -112A4;MULTANI LETTER VA;Lo;0;L;;;;;N;;;;; -112A5;MULTANI LETTER SA;Lo;0;L;;;;;N;;;;; -112A6;MULTANI LETTER HA;Lo;0;L;;;;;N;;;;; -112A7;MULTANI LETTER RRA;Lo;0;L;;;;;N;;;;; -112A8;MULTANI LETTER RHA;Lo;0;L;;;;;N;;;;; -112A9;MULTANI SECTION MARK;Po;0;L;;;;;N;;;;; -112B0;KHUDAWADI LETTER A;Lo;0;L;;;;;N;;;;; -112B1;KHUDAWADI LETTER AA;Lo;0;L;;;;;N;;;;; -112B2;KHUDAWADI LETTER I;Lo;0;L;;;;;N;;;;; -112B3;KHUDAWADI LETTER II;Lo;0;L;;;;;N;;;;; -112B4;KHUDAWADI LETTER U;Lo;0;L;;;;;N;;;;; -112B5;KHUDAWADI LETTER UU;Lo;0;L;;;;;N;;;;; -112B6;KHUDAWADI LETTER E;Lo;0;L;;;;;N;;;;; -112B7;KHUDAWADI LETTER AI;Lo;0;L;;;;;N;;;;; -112B8;KHUDAWADI LETTER O;Lo;0;L;;;;;N;;;;; -112B9;KHUDAWADI LETTER AU;Lo;0;L;;;;;N;;;;; -112BA;KHUDAWADI LETTER KA;Lo;0;L;;;;;N;;;;; -112BB;KHUDAWADI LETTER KHA;Lo;0;L;;;;;N;;;;; -112BC;KHUDAWADI LETTER GA;Lo;0;L;;;;;N;;;;; -112BD;KHUDAWADI LETTER GGA;Lo;0;L;;;;;N;;;;; -112BE;KHUDAWADI LETTER GHA;Lo;0;L;;;;;N;;;;; -112BF;KHUDAWADI LETTER NGA;Lo;0;L;;;;;N;;;;; -112C0;KHUDAWADI LETTER CA;Lo;0;L;;;;;N;;;;; -112C1;KHUDAWADI LETTER CHA;Lo;0;L;;;;;N;;;;; -112C2;KHUDAWADI LETTER JA;Lo;0;L;;;;;N;;;;; -112C3;KHUDAWADI LETTER JJA;Lo;0;L;;;;;N;;;;; -112C4;KHUDAWADI LETTER JHA;Lo;0;L;;;;;N;;;;; -112C5;KHUDAWADI LETTER NYA;Lo;0;L;;;;;N;;;;; -112C6;KHUDAWADI LETTER TTA;Lo;0;L;;;;;N;;;;; -112C7;KHUDAWADI LETTER TTHA;Lo;0;L;;;;;N;;;;; -112C8;KHUDAWADI LETTER DDA;Lo;0;L;;;;;N;;;;; -112C9;KHUDAWADI LETTER DDDA;Lo;0;L;;;;;N;;;;; -112CA;KHUDAWADI LETTER RRA;Lo;0;L;;;;;N;;;;; -112CB;KHUDAWADI LETTER DDHA;Lo;0;L;;;;;N;;;;; -112CC;KHUDAWADI LETTER NNA;Lo;0;L;;;;;N;;;;; -112CD;KHUDAWADI LETTER TA;Lo;0;L;;;;;N;;;;; -112CE;KHUDAWADI LETTER THA;Lo;0;L;;;;;N;;;;; -112CF;KHUDAWADI LETTER DA;Lo;0;L;;;;;N;;;;; -112D0;KHUDAWADI LETTER DHA;Lo;0;L;;;;;N;;;;; -112D1;KHUDAWADI LETTER NA;Lo;0;L;;;;;N;;;;; -112D2;KHUDAWADI LETTER PA;Lo;0;L;;;;;N;;;;; -112D3;KHUDAWADI LETTER PHA;Lo;0;L;;;;;N;;;;; -112D4;KHUDAWADI LETTER BA;Lo;0;L;;;;;N;;;;; -112D5;KHUDAWADI LETTER BBA;Lo;0;L;;;;;N;;;;; -112D6;KHUDAWADI LETTER BHA;Lo;0;L;;;;;N;;;;; -112D7;KHUDAWADI LETTER MA;Lo;0;L;;;;;N;;;;; -112D8;KHUDAWADI LETTER YA;Lo;0;L;;;;;N;;;;; -112D9;KHUDAWADI LETTER RA;Lo;0;L;;;;;N;;;;; -112DA;KHUDAWADI LETTER LA;Lo;0;L;;;;;N;;;;; -112DB;KHUDAWADI LETTER VA;Lo;0;L;;;;;N;;;;; -112DC;KHUDAWADI LETTER SHA;Lo;0;L;;;;;N;;;;; -112DD;KHUDAWADI LETTER SA;Lo;0;L;;;;;N;;;;; -112DE;KHUDAWADI LETTER HA;Lo;0;L;;;;;N;;;;; -112DF;KHUDAWADI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -112E0;KHUDAWADI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -112E1;KHUDAWADI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -112E2;KHUDAWADI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -112E3;KHUDAWADI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -112E4;KHUDAWADI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -112E5;KHUDAWADI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -112E6;KHUDAWADI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -112E7;KHUDAWADI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; -112E8;KHUDAWADI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; -112E9;KHUDAWADI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -112EA;KHUDAWADI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -112F0;KHUDAWADI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -112F1;KHUDAWADI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -112F2;KHUDAWADI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -112F3;KHUDAWADI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -112F4;KHUDAWADI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -112F5;KHUDAWADI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -112F6;KHUDAWADI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -112F7;KHUDAWADI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -112F8;KHUDAWADI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -112F9;KHUDAWADI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -11300;GRANTHA SIGN COMBINING ANUSVARA ABOVE;Mn;0;NSM;;;;;N;;;;; -11301;GRANTHA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -11302;GRANTHA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; -11303;GRANTHA SIGN VISARGA;Mc;0;L;;;;;N;;;;; -11305;GRANTHA LETTER A;Lo;0;L;;;;;N;;;;; -11306;GRANTHA LETTER AA;Lo;0;L;;;;;N;;;;; -11307;GRANTHA LETTER I;Lo;0;L;;;;;N;;;;; -11308;GRANTHA LETTER II;Lo;0;L;;;;;N;;;;; -11309;GRANTHA LETTER U;Lo;0;L;;;;;N;;;;; -1130A;GRANTHA LETTER UU;Lo;0;L;;;;;N;;;;; -1130B;GRANTHA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; -1130C;GRANTHA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; -1130F;GRANTHA LETTER EE;Lo;0;L;;;;;N;;;;; -11310;GRANTHA LETTER AI;Lo;0;L;;;;;N;;;;; -11313;GRANTHA LETTER OO;Lo;0;L;;;;;N;;;;; -11314;GRANTHA LETTER AU;Lo;0;L;;;;;N;;;;; -11315;GRANTHA LETTER KA;Lo;0;L;;;;;N;;;;; -11316;GRANTHA LETTER KHA;Lo;0;L;;;;;N;;;;; -11317;GRANTHA LETTER GA;Lo;0;L;;;;;N;;;;; -11318;GRANTHA LETTER GHA;Lo;0;L;;;;;N;;;;; -11319;GRANTHA LETTER NGA;Lo;0;L;;;;;N;;;;; -1131A;GRANTHA LETTER CA;Lo;0;L;;;;;N;;;;; -1131B;GRANTHA LETTER CHA;Lo;0;L;;;;;N;;;;; -1131C;GRANTHA LETTER JA;Lo;0;L;;;;;N;;;;; -1131D;GRANTHA LETTER JHA;Lo;0;L;;;;;N;;;;; -1131E;GRANTHA LETTER NYA;Lo;0;L;;;;;N;;;;; -1131F;GRANTHA LETTER TTA;Lo;0;L;;;;;N;;;;; -11320;GRANTHA LETTER TTHA;Lo;0;L;;;;;N;;;;; -11321;GRANTHA LETTER DDA;Lo;0;L;;;;;N;;;;; -11322;GRANTHA LETTER DDHA;Lo;0;L;;;;;N;;;;; -11323;GRANTHA LETTER NNA;Lo;0;L;;;;;N;;;;; -11324;GRANTHA LETTER TA;Lo;0;L;;;;;N;;;;; -11325;GRANTHA LETTER THA;Lo;0;L;;;;;N;;;;; -11326;GRANTHA LETTER DA;Lo;0;L;;;;;N;;;;; -11327;GRANTHA LETTER DHA;Lo;0;L;;;;;N;;;;; -11328;GRANTHA LETTER NA;Lo;0;L;;;;;N;;;;; -1132A;GRANTHA LETTER PA;Lo;0;L;;;;;N;;;;; -1132B;GRANTHA LETTER PHA;Lo;0;L;;;;;N;;;;; -1132C;GRANTHA LETTER BA;Lo;0;L;;;;;N;;;;; -1132D;GRANTHA LETTER BHA;Lo;0;L;;;;;N;;;;; -1132E;GRANTHA LETTER MA;Lo;0;L;;;;;N;;;;; -1132F;GRANTHA LETTER YA;Lo;0;L;;;;;N;;;;; -11330;GRANTHA LETTER RA;Lo;0;L;;;;;N;;;;; -11332;GRANTHA LETTER LA;Lo;0;L;;;;;N;;;;; -11333;GRANTHA LETTER LLA;Lo;0;L;;;;;N;;;;; -11335;GRANTHA LETTER VA;Lo;0;L;;;;;N;;;;; -11336;GRANTHA LETTER SHA;Lo;0;L;;;;;N;;;;; -11337;GRANTHA LETTER SSA;Lo;0;L;;;;;N;;;;; -11338;GRANTHA LETTER SA;Lo;0;L;;;;;N;;;;; -11339;GRANTHA LETTER HA;Lo;0;L;;;;;N;;;;; -1133B;COMBINING BINDU BELOW;Mn;7;NSM;;;;;N;;;;; -1133C;GRANTHA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -1133D;GRANTHA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; -1133E;GRANTHA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -1133F;GRANTHA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -11340;GRANTHA VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; -11341;GRANTHA VOWEL SIGN U;Mc;0;L;;;;;N;;;;; -11342;GRANTHA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; -11343;GRANTHA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; -11344;GRANTHA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; -11347;GRANTHA VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; -11348;GRANTHA VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; -1134B;GRANTHA VOWEL SIGN OO;Mc;0;L;11347 1133E;;;;N;;;;; -1134C;GRANTHA VOWEL SIGN AU;Mc;0;L;11347 11357;;;;N;;;;; -1134D;GRANTHA SIGN VIRAMA;Mc;9;L;;;;;N;;;;; -11350;GRANTHA OM;Lo;0;L;;;;;N;;;;; -11357;GRANTHA AU LENGTH MARK;Mc;0;L;;;;;N;;;;; -1135D;GRANTHA SIGN PLUTA;Lo;0;L;;;;;N;;;;; -1135E;GRANTHA LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;; -1135F;GRANTHA LETTER VEDIC DOUBLE ANUSVARA;Lo;0;L;;;;;N;;;;; -11360;GRANTHA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; -11361;GRANTHA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; -11362;GRANTHA VOWEL SIGN VOCALIC L;Mc;0;L;;;;;N;;;;; -11363;GRANTHA VOWEL SIGN VOCALIC LL;Mc;0;L;;;;;N;;;;; -11366;COMBINING GRANTHA DIGIT ZERO;Mn;230;NSM;;;;;N;;;;; -11367;COMBINING GRANTHA DIGIT ONE;Mn;230;NSM;;;;;N;;;;; -11368;COMBINING GRANTHA DIGIT TWO;Mn;230;NSM;;;;;N;;;;; -11369;COMBINING GRANTHA DIGIT THREE;Mn;230;NSM;;;;;N;;;;; -1136A;COMBINING GRANTHA DIGIT FOUR;Mn;230;NSM;;;;;N;;;;; -1136B;COMBINING GRANTHA DIGIT FIVE;Mn;230;NSM;;;;;N;;;;; -1136C;COMBINING GRANTHA DIGIT SIX;Mn;230;NSM;;;;;N;;;;; -11370;COMBINING GRANTHA LETTER A;Mn;230;NSM;;;;;N;;;;; -11371;COMBINING GRANTHA LETTER KA;Mn;230;NSM;;;;;N;;;;; -11372;COMBINING GRANTHA LETTER NA;Mn;230;NSM;;;;;N;;;;; -11373;COMBINING GRANTHA LETTER VI;Mn;230;NSM;;;;;N;;;;; -11374;COMBINING GRANTHA LETTER PA;Mn;230;NSM;;;;;N;;;;; -11400;NEWA LETTER A;Lo;0;L;;;;;N;;;;; -11401;NEWA LETTER AA;Lo;0;L;;;;;N;;;;; -11402;NEWA LETTER I;Lo;0;L;;;;;N;;;;; -11403;NEWA LETTER II;Lo;0;L;;;;;N;;;;; -11404;NEWA LETTER U;Lo;0;L;;;;;N;;;;; -11405;NEWA LETTER UU;Lo;0;L;;;;;N;;;;; -11406;NEWA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; -11407;NEWA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; -11408;NEWA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; -11409;NEWA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; -1140A;NEWA LETTER E;Lo;0;L;;;;;N;;;;; -1140B;NEWA LETTER AI;Lo;0;L;;;;;N;;;;; -1140C;NEWA LETTER O;Lo;0;L;;;;;N;;;;; -1140D;NEWA LETTER AU;Lo;0;L;;;;;N;;;;; -1140E;NEWA LETTER KA;Lo;0;L;;;;;N;;;;; -1140F;NEWA LETTER KHA;Lo;0;L;;;;;N;;;;; -11410;NEWA LETTER GA;Lo;0;L;;;;;N;;;;; -11411;NEWA LETTER GHA;Lo;0;L;;;;;N;;;;; -11412;NEWA LETTER NGA;Lo;0;L;;;;;N;;;;; -11413;NEWA LETTER NGHA;Lo;0;L;;;;;N;;;;; -11414;NEWA LETTER CA;Lo;0;L;;;;;N;;;;; -11415;NEWA LETTER CHA;Lo;0;L;;;;;N;;;;; -11416;NEWA LETTER JA;Lo;0;L;;;;;N;;;;; -11417;NEWA LETTER JHA;Lo;0;L;;;;;N;;;;; -11418;NEWA LETTER NYA;Lo;0;L;;;;;N;;;;; -11419;NEWA LETTER NYHA;Lo;0;L;;;;;N;;;;; -1141A;NEWA LETTER TTA;Lo;0;L;;;;;N;;;;; -1141B;NEWA LETTER TTHA;Lo;0;L;;;;;N;;;;; -1141C;NEWA LETTER DDA;Lo;0;L;;;;;N;;;;; -1141D;NEWA LETTER DDHA;Lo;0;L;;;;;N;;;;; -1141E;NEWA LETTER NNA;Lo;0;L;;;;;N;;;;; -1141F;NEWA LETTER TA;Lo;0;L;;;;;N;;;;; -11420;NEWA LETTER THA;Lo;0;L;;;;;N;;;;; -11421;NEWA LETTER DA;Lo;0;L;;;;;N;;;;; -11422;NEWA LETTER DHA;Lo;0;L;;;;;N;;;;; -11423;NEWA LETTER NA;Lo;0;L;;;;;N;;;;; -11424;NEWA LETTER NHA;Lo;0;L;;;;;N;;;;; -11425;NEWA LETTER PA;Lo;0;L;;;;;N;;;;; -11426;NEWA LETTER PHA;Lo;0;L;;;;;N;;;;; -11427;NEWA LETTER BA;Lo;0;L;;;;;N;;;;; -11428;NEWA LETTER BHA;Lo;0;L;;;;;N;;;;; -11429;NEWA LETTER MA;Lo;0;L;;;;;N;;;;; -1142A;NEWA LETTER MHA;Lo;0;L;;;;;N;;;;; -1142B;NEWA LETTER YA;Lo;0;L;;;;;N;;;;; -1142C;NEWA LETTER RA;Lo;0;L;;;;;N;;;;; -1142D;NEWA LETTER RHA;Lo;0;L;;;;;N;;;;; -1142E;NEWA LETTER LA;Lo;0;L;;;;;N;;;;; -1142F;NEWA LETTER LHA;Lo;0;L;;;;;N;;;;; -11430;NEWA LETTER WA;Lo;0;L;;;;;N;;;;; -11431;NEWA LETTER SHA;Lo;0;L;;;;;N;;;;; -11432;NEWA LETTER SSA;Lo;0;L;;;;;N;;;;; -11433;NEWA LETTER SA;Lo;0;L;;;;;N;;;;; -11434;NEWA LETTER HA;Lo;0;L;;;;;N;;;;; -11435;NEWA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -11436;NEWA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -11437;NEWA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -11438;NEWA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -11439;NEWA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -1143A;NEWA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -1143B;NEWA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; -1143C;NEWA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; -1143D;NEWA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; -1143E;NEWA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -1143F;NEWA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -11440;NEWA VOWEL SIGN O;Mc;0;L;;;;;N;;;;; -11441;NEWA VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; -11442;NEWA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -11443;NEWA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -11444;NEWA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -11445;NEWA SIGN VISARGA;Mc;0;L;;;;;N;;;;; -11446;NEWA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -11447;NEWA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; -11448;NEWA SIGN FINAL ANUSVARA;Lo;0;L;;;;;N;;;;; -11449;NEWA OM;Lo;0;L;;;;;N;;;;; -1144A;NEWA SIDDHI;Lo;0;L;;;;;N;;;;; -1144B;NEWA DANDA;Po;0;L;;;;;N;;;;; -1144C;NEWA DOUBLE DANDA;Po;0;L;;;;;N;;;;; -1144D;NEWA COMMA;Po;0;L;;;;;N;;;;; -1144E;NEWA GAP FILLER;Po;0;L;;;;;N;;;;; -1144F;NEWA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; -11450;NEWA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -11451;NEWA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -11452;NEWA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -11453;NEWA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -11454;NEWA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -11455;NEWA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -11456;NEWA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -11457;NEWA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -11458;NEWA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -11459;NEWA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -1145A;NEWA DOUBLE COMMA;Po;0;L;;;;;N;;;;; -1145B;NEWA PLACEHOLDER MARK;Po;0;L;;;;;N;;;;; -1145D;NEWA INSERTION SIGN;Po;0;L;;;;;N;;;;; -1145E;NEWA SANDHI MARK;Mn;230;NSM;;;;;N;;;;; -1145F;NEWA LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;; -11460;NEWA SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; -11461;NEWA SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; -11480;TIRHUTA ANJI;Lo;0;L;;;;;N;;;;; -11481;TIRHUTA LETTER A;Lo;0;L;;;;;N;;;;; -11482;TIRHUTA LETTER AA;Lo;0;L;;;;;N;;;;; -11483;TIRHUTA LETTER I;Lo;0;L;;;;;N;;;;; -11484;TIRHUTA LETTER II;Lo;0;L;;;;;N;;;;; -11485;TIRHUTA LETTER U;Lo;0;L;;;;;N;;;;; -11486;TIRHUTA LETTER UU;Lo;0;L;;;;;N;;;;; -11487;TIRHUTA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; -11488;TIRHUTA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; -11489;TIRHUTA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; -1148A;TIRHUTA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; -1148B;TIRHUTA LETTER E;Lo;0;L;;;;;N;;;;; -1148C;TIRHUTA LETTER AI;Lo;0;L;;;;;N;;;;; -1148D;TIRHUTA LETTER O;Lo;0;L;;;;;N;;;;; -1148E;TIRHUTA LETTER AU;Lo;0;L;;;;;N;;;;; -1148F;TIRHUTA LETTER KA;Lo;0;L;;;;;N;;;;; -11490;TIRHUTA LETTER KHA;Lo;0;L;;;;;N;;;;; -11491;TIRHUTA LETTER GA;Lo;0;L;;;;;N;;;;; -11492;TIRHUTA LETTER GHA;Lo;0;L;;;;;N;;;;; -11493;TIRHUTA LETTER NGA;Lo;0;L;;;;;N;;;;; -11494;TIRHUTA LETTER CA;Lo;0;L;;;;;N;;;;; -11495;TIRHUTA LETTER CHA;Lo;0;L;;;;;N;;;;; -11496;TIRHUTA LETTER JA;Lo;0;L;;;;;N;;;;; -11497;TIRHUTA LETTER JHA;Lo;0;L;;;;;N;;;;; -11498;TIRHUTA LETTER NYA;Lo;0;L;;;;;N;;;;; -11499;TIRHUTA LETTER TTA;Lo;0;L;;;;;N;;;;; -1149A;TIRHUTA LETTER TTHA;Lo;0;L;;;;;N;;;;; -1149B;TIRHUTA LETTER DDA;Lo;0;L;;;;;N;;;;; -1149C;TIRHUTA LETTER DDHA;Lo;0;L;;;;;N;;;;; -1149D;TIRHUTA LETTER NNA;Lo;0;L;;;;;N;;;;; -1149E;TIRHUTA LETTER TA;Lo;0;L;;;;;N;;;;; -1149F;TIRHUTA LETTER THA;Lo;0;L;;;;;N;;;;; -114A0;TIRHUTA LETTER DA;Lo;0;L;;;;;N;;;;; -114A1;TIRHUTA LETTER DHA;Lo;0;L;;;;;N;;;;; -114A2;TIRHUTA LETTER NA;Lo;0;L;;;;;N;;;;; -114A3;TIRHUTA LETTER PA;Lo;0;L;;;;;N;;;;; -114A4;TIRHUTA LETTER PHA;Lo;0;L;;;;;N;;;;; -114A5;TIRHUTA LETTER BA;Lo;0;L;;;;;N;;;;; -114A6;TIRHUTA LETTER BHA;Lo;0;L;;;;;N;;;;; -114A7;TIRHUTA LETTER MA;Lo;0;L;;;;;N;;;;; -114A8;TIRHUTA LETTER YA;Lo;0;L;;;;;N;;;;; -114A9;TIRHUTA LETTER RA;Lo;0;L;;;;;N;;;;; -114AA;TIRHUTA LETTER LA;Lo;0;L;;;;;N;;;;; -114AB;TIRHUTA LETTER VA;Lo;0;L;;;;;N;;;;; -114AC;TIRHUTA LETTER SHA;Lo;0;L;;;;;N;;;;; -114AD;TIRHUTA LETTER SSA;Lo;0;L;;;;;N;;;;; -114AE;TIRHUTA LETTER SA;Lo;0;L;;;;;N;;;;; -114AF;TIRHUTA LETTER HA;Lo;0;L;;;;;N;;;;; -114B0;TIRHUTA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -114B1;TIRHUTA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -114B2;TIRHUTA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -114B3;TIRHUTA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -114B4;TIRHUTA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -114B5;TIRHUTA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -114B6;TIRHUTA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; -114B7;TIRHUTA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; -114B8;TIRHUTA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; -114B9;TIRHUTA VOWEL SIGN E;Mc;0;L;;;;;N;;;;; -114BA;TIRHUTA VOWEL SIGN SHORT E;Mn;0;NSM;;;;;N;;;;; -114BB;TIRHUTA VOWEL SIGN AI;Mc;0;L;114B9 114BA;;;;N;;;;; -114BC;TIRHUTA VOWEL SIGN O;Mc;0;L;114B9 114B0;;;;N;;;;; -114BD;TIRHUTA VOWEL SIGN SHORT O;Mc;0;L;;;;;N;;;;; -114BE;TIRHUTA VOWEL SIGN AU;Mc;0;L;114B9 114BD;;;;N;;;;; -114BF;TIRHUTA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -114C0;TIRHUTA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -114C1;TIRHUTA SIGN VISARGA;Mc;0;L;;;;;N;;;;; -114C2;TIRHUTA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -114C3;TIRHUTA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -114C4;TIRHUTA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; -114C5;TIRHUTA GVANG;Lo;0;L;;;;;N;;;;; -114C6;TIRHUTA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; -114C7;TIRHUTA OM;Lo;0;L;;;;;N;;;;; -114D0;TIRHUTA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -114D1;TIRHUTA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -114D2;TIRHUTA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -114D3;TIRHUTA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -114D4;TIRHUTA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -114D5;TIRHUTA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -114D6;TIRHUTA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -114D7;TIRHUTA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -114D8;TIRHUTA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -114D9;TIRHUTA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -11580;SIDDHAM LETTER A;Lo;0;L;;;;;N;;;;; -11581;SIDDHAM LETTER AA;Lo;0;L;;;;;N;;;;; -11582;SIDDHAM LETTER I;Lo;0;L;;;;;N;;;;; -11583;SIDDHAM LETTER II;Lo;0;L;;;;;N;;;;; -11584;SIDDHAM LETTER U;Lo;0;L;;;;;N;;;;; -11585;SIDDHAM LETTER UU;Lo;0;L;;;;;N;;;;; -11586;SIDDHAM LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; -11587;SIDDHAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; -11588;SIDDHAM LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; -11589;SIDDHAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; -1158A;SIDDHAM LETTER E;Lo;0;L;;;;;N;;;;; -1158B;SIDDHAM LETTER AI;Lo;0;L;;;;;N;;;;; -1158C;SIDDHAM LETTER O;Lo;0;L;;;;;N;;;;; -1158D;SIDDHAM LETTER AU;Lo;0;L;;;;;N;;;;; -1158E;SIDDHAM LETTER KA;Lo;0;L;;;;;N;;;;; -1158F;SIDDHAM LETTER KHA;Lo;0;L;;;;;N;;;;; -11590;SIDDHAM LETTER GA;Lo;0;L;;;;;N;;;;; -11591;SIDDHAM LETTER GHA;Lo;0;L;;;;;N;;;;; -11592;SIDDHAM LETTER NGA;Lo;0;L;;;;;N;;;;; -11593;SIDDHAM LETTER CA;Lo;0;L;;;;;N;;;;; -11594;SIDDHAM LETTER CHA;Lo;0;L;;;;;N;;;;; -11595;SIDDHAM LETTER JA;Lo;0;L;;;;;N;;;;; -11596;SIDDHAM LETTER JHA;Lo;0;L;;;;;N;;;;; -11597;SIDDHAM LETTER NYA;Lo;0;L;;;;;N;;;;; -11598;SIDDHAM LETTER TTA;Lo;0;L;;;;;N;;;;; -11599;SIDDHAM LETTER TTHA;Lo;0;L;;;;;N;;;;; -1159A;SIDDHAM LETTER DDA;Lo;0;L;;;;;N;;;;; -1159B;SIDDHAM LETTER DDHA;Lo;0;L;;;;;N;;;;; -1159C;SIDDHAM LETTER NNA;Lo;0;L;;;;;N;;;;; -1159D;SIDDHAM LETTER TA;Lo;0;L;;;;;N;;;;; -1159E;SIDDHAM LETTER THA;Lo;0;L;;;;;N;;;;; -1159F;SIDDHAM LETTER DA;Lo;0;L;;;;;N;;;;; -115A0;SIDDHAM LETTER DHA;Lo;0;L;;;;;N;;;;; -115A1;SIDDHAM LETTER NA;Lo;0;L;;;;;N;;;;; -115A2;SIDDHAM LETTER PA;Lo;0;L;;;;;N;;;;; -115A3;SIDDHAM LETTER PHA;Lo;0;L;;;;;N;;;;; -115A4;SIDDHAM LETTER BA;Lo;0;L;;;;;N;;;;; -115A5;SIDDHAM LETTER BHA;Lo;0;L;;;;;N;;;;; -115A6;SIDDHAM LETTER MA;Lo;0;L;;;;;N;;;;; -115A7;SIDDHAM LETTER YA;Lo;0;L;;;;;N;;;;; -115A8;SIDDHAM LETTER RA;Lo;0;L;;;;;N;;;;; -115A9;SIDDHAM LETTER LA;Lo;0;L;;;;;N;;;;; -115AA;SIDDHAM LETTER VA;Lo;0;L;;;;;N;;;;; -115AB;SIDDHAM LETTER SHA;Lo;0;L;;;;;N;;;;; -115AC;SIDDHAM LETTER SSA;Lo;0;L;;;;;N;;;;; -115AD;SIDDHAM LETTER SA;Lo;0;L;;;;;N;;;;; -115AE;SIDDHAM LETTER HA;Lo;0;L;;;;;N;;;;; -115AF;SIDDHAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -115B0;SIDDHAM VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -115B1;SIDDHAM VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -115B2;SIDDHAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -115B3;SIDDHAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -115B4;SIDDHAM VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -115B5;SIDDHAM VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; -115B8;SIDDHAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;; -115B9;SIDDHAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; -115BA;SIDDHAM VOWEL SIGN O;Mc;0;L;115B8 115AF;;;;N;;;;; -115BB;SIDDHAM VOWEL SIGN AU;Mc;0;L;115B9 115AF;;;;N;;;;; -115BC;SIDDHAM SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -115BD;SIDDHAM SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -115BE;SIDDHAM SIGN VISARGA;Mc;0;L;;;;;N;;;;; -115BF;SIDDHAM SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -115C0;SIDDHAM SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -115C1;SIDDHAM SIGN SIDDHAM;Po;0;L;;;;;N;;;;; -115C2;SIDDHAM DANDA;Po;0;L;;;;;N;;;;; -115C3;SIDDHAM DOUBLE DANDA;Po;0;L;;;;;N;;;;; -115C4;SIDDHAM SEPARATOR DOT;Po;0;L;;;;;N;;;;; -115C5;SIDDHAM SEPARATOR BAR;Po;0;L;;;;;N;;;;; -115C6;SIDDHAM REPETITION MARK-1;Po;0;L;;;;;N;;;;; -115C7;SIDDHAM REPETITION MARK-2;Po;0;L;;;;;N;;;;; -115C8;SIDDHAM REPETITION MARK-3;Po;0;L;;;;;N;;;;; -115C9;SIDDHAM END OF TEXT MARK;Po;0;L;;;;;N;;;;; -115CA;SIDDHAM SECTION MARK WITH TRIDENT AND U-SHAPED ORNAMENTS;Po;0;L;;;;;N;;;;; -115CB;SIDDHAM SECTION MARK WITH TRIDENT AND DOTTED CRESCENTS;Po;0;L;;;;;N;;;;; -115CC;SIDDHAM SECTION MARK WITH RAYS AND DOTTED CRESCENTS;Po;0;L;;;;;N;;;;; -115CD;SIDDHAM SECTION MARK WITH RAYS AND DOTTED DOUBLE CRESCENTS;Po;0;L;;;;;N;;;;; -115CE;SIDDHAM SECTION MARK WITH RAYS AND DOTTED TRIPLE CRESCENTS;Po;0;L;;;;;N;;;;; -115CF;SIDDHAM SECTION MARK DOUBLE RING;Po;0;L;;;;;N;;;;; -115D0;SIDDHAM SECTION MARK DOUBLE RING WITH RAYS;Po;0;L;;;;;N;;;;; -115D1;SIDDHAM SECTION MARK WITH DOUBLE CRESCENTS;Po;0;L;;;;;N;;;;; -115D2;SIDDHAM SECTION MARK WITH TRIPLE CRESCENTS;Po;0;L;;;;;N;;;;; -115D3;SIDDHAM SECTION MARK WITH QUADRUPLE CRESCENTS;Po;0;L;;;;;N;;;;; -115D4;SIDDHAM SECTION MARK WITH SEPTUPLE CRESCENTS;Po;0;L;;;;;N;;;;; -115D5;SIDDHAM SECTION MARK WITH CIRCLES AND RAYS;Po;0;L;;;;;N;;;;; -115D6;SIDDHAM SECTION MARK WITH CIRCLES AND TWO ENCLOSURES;Po;0;L;;;;;N;;;;; -115D7;SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES;Po;0;L;;;;;N;;;;; -115D8;SIDDHAM LETTER THREE-CIRCLE ALTERNATE I;Lo;0;L;;;;;N;;;;; -115D9;SIDDHAM LETTER TWO-CIRCLE ALTERNATE I;Lo;0;L;;;;;N;;;;; -115DA;SIDDHAM LETTER TWO-CIRCLE ALTERNATE II;Lo;0;L;;;;;N;;;;; -115DB;SIDDHAM LETTER ALTERNATE U;Lo;0;L;;;;;N;;;;; -115DC;SIDDHAM VOWEL SIGN ALTERNATE U;Mn;0;NSM;;;;;N;;;;; -115DD;SIDDHAM VOWEL SIGN ALTERNATE UU;Mn;0;NSM;;;;;N;;;;; -11600;MODI LETTER A;Lo;0;L;;;;;N;;;;; -11601;MODI LETTER AA;Lo;0;L;;;;;N;;;;; -11602;MODI LETTER I;Lo;0;L;;;;;N;;;;; -11603;MODI LETTER II;Lo;0;L;;;;;N;;;;; -11604;MODI LETTER U;Lo;0;L;;;;;N;;;;; -11605;MODI LETTER UU;Lo;0;L;;;;;N;;;;; -11606;MODI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; -11607;MODI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; -11608;MODI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; -11609;MODI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; -1160A;MODI LETTER E;Lo;0;L;;;;;N;;;;; -1160B;MODI LETTER AI;Lo;0;L;;;;;N;;;;; -1160C;MODI LETTER O;Lo;0;L;;;;;N;;;;; -1160D;MODI LETTER AU;Lo;0;L;;;;;N;;;;; -1160E;MODI LETTER KA;Lo;0;L;;;;;N;;;;; -1160F;MODI LETTER KHA;Lo;0;L;;;;;N;;;;; -11610;MODI LETTER GA;Lo;0;L;;;;;N;;;;; -11611;MODI LETTER GHA;Lo;0;L;;;;;N;;;;; -11612;MODI LETTER NGA;Lo;0;L;;;;;N;;;;; -11613;MODI LETTER CA;Lo;0;L;;;;;N;;;;; -11614;MODI LETTER CHA;Lo;0;L;;;;;N;;;;; -11615;MODI LETTER JA;Lo;0;L;;;;;N;;;;; -11616;MODI LETTER JHA;Lo;0;L;;;;;N;;;;; -11617;MODI LETTER NYA;Lo;0;L;;;;;N;;;;; -11618;MODI LETTER TTA;Lo;0;L;;;;;N;;;;; -11619;MODI LETTER TTHA;Lo;0;L;;;;;N;;;;; -1161A;MODI LETTER DDA;Lo;0;L;;;;;N;;;;; -1161B;MODI LETTER DDHA;Lo;0;L;;;;;N;;;;; -1161C;MODI LETTER NNA;Lo;0;L;;;;;N;;;;; -1161D;MODI LETTER TA;Lo;0;L;;;;;N;;;;; -1161E;MODI LETTER THA;Lo;0;L;;;;;N;;;;; -1161F;MODI LETTER DA;Lo;0;L;;;;;N;;;;; -11620;MODI LETTER DHA;Lo;0;L;;;;;N;;;;; -11621;MODI LETTER NA;Lo;0;L;;;;;N;;;;; -11622;MODI LETTER PA;Lo;0;L;;;;;N;;;;; -11623;MODI LETTER PHA;Lo;0;L;;;;;N;;;;; -11624;MODI LETTER BA;Lo;0;L;;;;;N;;;;; -11625;MODI LETTER BHA;Lo;0;L;;;;;N;;;;; -11626;MODI LETTER MA;Lo;0;L;;;;;N;;;;; -11627;MODI LETTER YA;Lo;0;L;;;;;N;;;;; -11628;MODI LETTER RA;Lo;0;L;;;;;N;;;;; -11629;MODI LETTER LA;Lo;0;L;;;;;N;;;;; -1162A;MODI LETTER VA;Lo;0;L;;;;;N;;;;; -1162B;MODI LETTER SHA;Lo;0;L;;;;;N;;;;; -1162C;MODI LETTER SSA;Lo;0;L;;;;;N;;;;; -1162D;MODI LETTER SA;Lo;0;L;;;;;N;;;;; -1162E;MODI LETTER HA;Lo;0;L;;;;;N;;;;; -1162F;MODI LETTER LLA;Lo;0;L;;;;;N;;;;; -11630;MODI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -11631;MODI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -11632;MODI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -11633;MODI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -11634;MODI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -11635;MODI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -11636;MODI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; -11637;MODI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; -11638;MODI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; -11639;MODI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -1163A;MODI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -1163B;MODI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; -1163C;MODI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; -1163D;MODI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -1163E;MODI SIGN VISARGA;Mc;0;L;;;;;N;;;;; -1163F;MODI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -11640;MODI SIGN ARDHACANDRA;Mn;0;NSM;;;;;N;;;;; -11641;MODI DANDA;Po;0;L;;;;;N;;;;; -11642;MODI DOUBLE DANDA;Po;0;L;;;;;N;;;;; -11643;MODI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; -11644;MODI SIGN HUVA;Lo;0;L;;;;;N;;;;; -11650;MODI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -11651;MODI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -11652;MODI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -11653;MODI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -11654;MODI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -11655;MODI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -11656;MODI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -11657;MODI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -11658;MODI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -11659;MODI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -11660;MONGOLIAN BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; -11661;MONGOLIAN ROTATED BIRGA;Po;0;ON;;;;;N;;;;; -11662;MONGOLIAN DOUBLE BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; -11663;MONGOLIAN TRIPLE BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; -11664;MONGOLIAN BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; -11665;MONGOLIAN ROTATED BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; -11666;MONGOLIAN ROTATED BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; -11667;MONGOLIAN INVERTED BIRGA;Po;0;ON;;;;;N;;;;; -11668;MONGOLIAN INVERTED BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; -11669;MONGOLIAN SWIRL BIRGA;Po;0;ON;;;;;N;;;;; -1166A;MONGOLIAN SWIRL BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; -1166B;MONGOLIAN SWIRL BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; -1166C;MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; -11680;TAKRI LETTER A;Lo;0;L;;;;;N;;;;; -11681;TAKRI LETTER AA;Lo;0;L;;;;;N;;;;; -11682;TAKRI LETTER I;Lo;0;L;;;;;N;;;;; -11683;TAKRI LETTER II;Lo;0;L;;;;;N;;;;; -11684;TAKRI LETTER U;Lo;0;L;;;;;N;;;;; -11685;TAKRI LETTER UU;Lo;0;L;;;;;N;;;;; -11686;TAKRI LETTER E;Lo;0;L;;;;;N;;;;; -11687;TAKRI LETTER AI;Lo;0;L;;;;;N;;;;; -11688;TAKRI LETTER O;Lo;0;L;;;;;N;;;;; -11689;TAKRI LETTER AU;Lo;0;L;;;;;N;;;;; -1168A;TAKRI LETTER KA;Lo;0;L;;;;;N;;;;; -1168B;TAKRI LETTER KHA;Lo;0;L;;;;;N;;;;; -1168C;TAKRI LETTER GA;Lo;0;L;;;;;N;;;;; -1168D;TAKRI LETTER GHA;Lo;0;L;;;;;N;;;;; -1168E;TAKRI LETTER NGA;Lo;0;L;;;;;N;;;;; -1168F;TAKRI LETTER CA;Lo;0;L;;;;;N;;;;; -11690;TAKRI LETTER CHA;Lo;0;L;;;;;N;;;;; -11691;TAKRI LETTER JA;Lo;0;L;;;;;N;;;;; -11692;TAKRI LETTER JHA;Lo;0;L;;;;;N;;;;; -11693;TAKRI LETTER NYA;Lo;0;L;;;;;N;;;;; -11694;TAKRI LETTER TTA;Lo;0;L;;;;;N;;;;; -11695;TAKRI LETTER TTHA;Lo;0;L;;;;;N;;;;; -11696;TAKRI LETTER DDA;Lo;0;L;;;;;N;;;;; -11697;TAKRI LETTER DDHA;Lo;0;L;;;;;N;;;;; -11698;TAKRI LETTER NNA;Lo;0;L;;;;;N;;;;; -11699;TAKRI LETTER TA;Lo;0;L;;;;;N;;;;; -1169A;TAKRI LETTER THA;Lo;0;L;;;;;N;;;;; -1169B;TAKRI LETTER DA;Lo;0;L;;;;;N;;;;; -1169C;TAKRI LETTER DHA;Lo;0;L;;;;;N;;;;; -1169D;TAKRI LETTER NA;Lo;0;L;;;;;N;;;;; -1169E;TAKRI LETTER PA;Lo;0;L;;;;;N;;;;; -1169F;TAKRI LETTER PHA;Lo;0;L;;;;;N;;;;; -116A0;TAKRI LETTER BA;Lo;0;L;;;;;N;;;;; -116A1;TAKRI LETTER BHA;Lo;0;L;;;;;N;;;;; -116A2;TAKRI LETTER MA;Lo;0;L;;;;;N;;;;; -116A3;TAKRI LETTER YA;Lo;0;L;;;;;N;;;;; -116A4;TAKRI LETTER RA;Lo;0;L;;;;;N;;;;; -116A5;TAKRI LETTER LA;Lo;0;L;;;;;N;;;;; -116A6;TAKRI LETTER VA;Lo;0;L;;;;;N;;;;; -116A7;TAKRI LETTER SHA;Lo;0;L;;;;;N;;;;; -116A8;TAKRI LETTER SA;Lo;0;L;;;;;N;;;;; -116A9;TAKRI LETTER HA;Lo;0;L;;;;;N;;;;; -116AA;TAKRI LETTER RRA;Lo;0;L;;;;;N;;;;; -116AB;TAKRI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -116AC;TAKRI SIGN VISARGA;Mc;0;L;;;;;N;;;;; -116AD;TAKRI VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; -116AE;TAKRI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -116AF;TAKRI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -116B0;TAKRI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -116B1;TAKRI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -116B2;TAKRI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -116B3;TAKRI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -116B4;TAKRI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; -116B5;TAKRI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; -116B6;TAKRI SIGN VIRAMA;Mc;9;L;;;;;N;;;;; -116B7;TAKRI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -116B8;TAKRI LETTER ARCHAIC KHA;Lo;0;L;;;;;N;;;;; -116B9;TAKRI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; -116C0;TAKRI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -116C1;TAKRI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -116C2;TAKRI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -116C3;TAKRI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -116C4;TAKRI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -116C5;TAKRI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -116C6;TAKRI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -116C7;TAKRI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -116C8;TAKRI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -116C9;TAKRI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -11700;AHOM LETTER KA;Lo;0;L;;;;;N;;;;; -11701;AHOM LETTER KHA;Lo;0;L;;;;;N;;;;; -11702;AHOM LETTER NGA;Lo;0;L;;;;;N;;;;; -11703;AHOM LETTER NA;Lo;0;L;;;;;N;;;;; -11704;AHOM LETTER TA;Lo;0;L;;;;;N;;;;; -11705;AHOM LETTER ALTERNATE TA;Lo;0;L;;;;;N;;;;; -11706;AHOM LETTER PA;Lo;0;L;;;;;N;;;;; -11707;AHOM LETTER PHA;Lo;0;L;;;;;N;;;;; -11708;AHOM LETTER BA;Lo;0;L;;;;;N;;;;; -11709;AHOM LETTER MA;Lo;0;L;;;;;N;;;;; -1170A;AHOM LETTER JA;Lo;0;L;;;;;N;;;;; -1170B;AHOM LETTER CHA;Lo;0;L;;;;;N;;;;; -1170C;AHOM LETTER THA;Lo;0;L;;;;;N;;;;; -1170D;AHOM LETTER RA;Lo;0;L;;;;;N;;;;; -1170E;AHOM LETTER LA;Lo;0;L;;;;;N;;;;; -1170F;AHOM LETTER SA;Lo;0;L;;;;;N;;;;; -11710;AHOM LETTER NYA;Lo;0;L;;;;;N;;;;; -11711;AHOM LETTER HA;Lo;0;L;;;;;N;;;;; -11712;AHOM LETTER A;Lo;0;L;;;;;N;;;;; -11713;AHOM LETTER DA;Lo;0;L;;;;;N;;;;; -11714;AHOM LETTER DHA;Lo;0;L;;;;;N;;;;; -11715;AHOM LETTER GA;Lo;0;L;;;;;N;;;;; -11716;AHOM LETTER ALTERNATE GA;Lo;0;L;;;;;N;;;;; -11717;AHOM LETTER GHA;Lo;0;L;;;;;N;;;;; -11718;AHOM LETTER BHA;Lo;0;L;;;;;N;;;;; -11719;AHOM LETTER JHA;Lo;0;L;;;;;N;;;;; -1171A;AHOM LETTER ALTERNATE BA;Lo;0;L;;;;;N;;;;; -1171D;AHOM CONSONANT SIGN MEDIAL LA;Mn;0;NSM;;;;;N;;;;; -1171E;AHOM CONSONANT SIGN MEDIAL RA;Mn;0;NSM;;;;;N;;;;; -1171F;AHOM CONSONANT SIGN MEDIAL LIGATING RA;Mn;0;NSM;;;;;N;;;;; -11720;AHOM VOWEL SIGN A;Mc;0;L;;;;;N;;;;; -11721;AHOM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -11722;AHOM VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -11723;AHOM VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; -11724;AHOM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -11725;AHOM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -11726;AHOM VOWEL SIGN E;Mc;0;L;;;;;N;;;;; -11727;AHOM VOWEL SIGN AW;Mn;0;NSM;;;;;N;;;;; -11728;AHOM VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; -11729;AHOM VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -1172A;AHOM VOWEL SIGN AM;Mn;0;NSM;;;;;N;;;;; -1172B;AHOM SIGN KILLER;Mn;9;NSM;;;;;N;;;;; -11730;AHOM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -11731;AHOM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -11732;AHOM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -11733;AHOM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -11734;AHOM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -11735;AHOM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -11736;AHOM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -11737;AHOM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -11738;AHOM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -11739;AHOM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -1173A;AHOM NUMBER TEN;No;0;L;;;;10;N;;;;; -1173B;AHOM NUMBER TWENTY;No;0;L;;;;20;N;;;;; -1173C;AHOM SIGN SMALL SECTION;Po;0;L;;;;;N;;;;; -1173D;AHOM SIGN SECTION;Po;0;L;;;;;N;;;;; -1173E;AHOM SIGN RULAI;Po;0;L;;;;;N;;;;; -1173F;AHOM SYMBOL VI;So;0;L;;;;;N;;;;; -11740;AHOM LETTER CA;Lo;0;L;;;;;N;;;;; -11741;AHOM LETTER TTA;Lo;0;L;;;;;N;;;;; -11742;AHOM LETTER TTHA;Lo;0;L;;;;;N;;;;; -11743;AHOM LETTER DDA;Lo;0;L;;;;;N;;;;; -11744;AHOM LETTER DDHA;Lo;0;L;;;;;N;;;;; -11745;AHOM LETTER NNA;Lo;0;L;;;;;N;;;;; -11746;AHOM LETTER LLA;Lo;0;L;;;;;N;;;;; -11800;DOGRA LETTER A;Lo;0;L;;;;;N;;;;; -11801;DOGRA LETTER AA;Lo;0;L;;;;;N;;;;; -11802;DOGRA LETTER I;Lo;0;L;;;;;N;;;;; -11803;DOGRA LETTER II;Lo;0;L;;;;;N;;;;; -11804;DOGRA LETTER U;Lo;0;L;;;;;N;;;;; -11805;DOGRA LETTER UU;Lo;0;L;;;;;N;;;;; -11806;DOGRA LETTER E;Lo;0;L;;;;;N;;;;; -11807;DOGRA LETTER AI;Lo;0;L;;;;;N;;;;; -11808;DOGRA LETTER O;Lo;0;L;;;;;N;;;;; -11809;DOGRA LETTER AU;Lo;0;L;;;;;N;;;;; -1180A;DOGRA LETTER KA;Lo;0;L;;;;;N;;;;; -1180B;DOGRA LETTER KHA;Lo;0;L;;;;;N;;;;; -1180C;DOGRA LETTER GA;Lo;0;L;;;;;N;;;;; -1180D;DOGRA LETTER GHA;Lo;0;L;;;;;N;;;;; -1180E;DOGRA LETTER NGA;Lo;0;L;;;;;N;;;;; -1180F;DOGRA LETTER CA;Lo;0;L;;;;;N;;;;; -11810;DOGRA LETTER CHA;Lo;0;L;;;;;N;;;;; -11811;DOGRA LETTER JA;Lo;0;L;;;;;N;;;;; -11812;DOGRA LETTER JHA;Lo;0;L;;;;;N;;;;; -11813;DOGRA LETTER NYA;Lo;0;L;;;;;N;;;;; -11814;DOGRA LETTER TTA;Lo;0;L;;;;;N;;;;; -11815;DOGRA LETTER TTHA;Lo;0;L;;;;;N;;;;; -11816;DOGRA LETTER DDA;Lo;0;L;;;;;N;;;;; -11817;DOGRA LETTER DDHA;Lo;0;L;;;;;N;;;;; -11818;DOGRA LETTER NNA;Lo;0;L;;;;;N;;;;; -11819;DOGRA LETTER TA;Lo;0;L;;;;;N;;;;; -1181A;DOGRA LETTER THA;Lo;0;L;;;;;N;;;;; -1181B;DOGRA LETTER DA;Lo;0;L;;;;;N;;;;; -1181C;DOGRA LETTER DHA;Lo;0;L;;;;;N;;;;; -1181D;DOGRA LETTER NA;Lo;0;L;;;;;N;;;;; -1181E;DOGRA LETTER PA;Lo;0;L;;;;;N;;;;; -1181F;DOGRA LETTER PHA;Lo;0;L;;;;;N;;;;; -11820;DOGRA LETTER BA;Lo;0;L;;;;;N;;;;; -11821;DOGRA LETTER BHA;Lo;0;L;;;;;N;;;;; -11822;DOGRA LETTER MA;Lo;0;L;;;;;N;;;;; -11823;DOGRA LETTER YA;Lo;0;L;;;;;N;;;;; -11824;DOGRA LETTER RA;Lo;0;L;;;;;N;;;;; -11825;DOGRA LETTER LA;Lo;0;L;;;;;N;;;;; -11826;DOGRA LETTER VA;Lo;0;L;;;;;N;;;;; -11827;DOGRA LETTER SHA;Lo;0;L;;;;;N;;;;; -11828;DOGRA LETTER SSA;Lo;0;L;;;;;N;;;;; -11829;DOGRA LETTER SA;Lo;0;L;;;;;N;;;;; -1182A;DOGRA LETTER HA;Lo;0;L;;;;;N;;;;; -1182B;DOGRA LETTER RRA;Lo;0;L;;;;;N;;;;; -1182C;DOGRA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -1182D;DOGRA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -1182E;DOGRA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -1182F;DOGRA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -11830;DOGRA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -11831;DOGRA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -11832;DOGRA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; -11833;DOGRA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -11834;DOGRA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -11835;DOGRA VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; -11836;DOGRA VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; -11837;DOGRA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -11838;DOGRA SIGN VISARGA;Mc;0;L;;;;;N;;;;; -11839;DOGRA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -1183A;DOGRA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -1183B;DOGRA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; -118A0;WARANG CITI CAPITAL LETTER NGAA;Lu;0;L;;;;;N;;;;118C0; -118A1;WARANG CITI CAPITAL LETTER A;Lu;0;L;;;;;N;;;;118C1; -118A2;WARANG CITI CAPITAL LETTER WI;Lu;0;L;;;;;N;;;;118C2; -118A3;WARANG CITI CAPITAL LETTER YU;Lu;0;L;;;;;N;;;;118C3; -118A4;WARANG CITI CAPITAL LETTER YA;Lu;0;L;;;;;N;;;;118C4; -118A5;WARANG CITI CAPITAL LETTER YO;Lu;0;L;;;;;N;;;;118C5; -118A6;WARANG CITI CAPITAL LETTER II;Lu;0;L;;;;;N;;;;118C6; -118A7;WARANG CITI CAPITAL LETTER UU;Lu;0;L;;;;;N;;;;118C7; -118A8;WARANG CITI CAPITAL LETTER E;Lu;0;L;;;;;N;;;;118C8; -118A9;WARANG CITI CAPITAL LETTER O;Lu;0;L;;;;;N;;;;118C9; -118AA;WARANG CITI CAPITAL LETTER ANG;Lu;0;L;;;;;N;;;;118CA; -118AB;WARANG CITI CAPITAL LETTER GA;Lu;0;L;;;;;N;;;;118CB; -118AC;WARANG CITI CAPITAL LETTER KO;Lu;0;L;;;;;N;;;;118CC; -118AD;WARANG CITI CAPITAL LETTER ENY;Lu;0;L;;;;;N;;;;118CD; -118AE;WARANG CITI CAPITAL LETTER YUJ;Lu;0;L;;;;;N;;;;118CE; -118AF;WARANG CITI CAPITAL LETTER UC;Lu;0;L;;;;;N;;;;118CF; -118B0;WARANG CITI CAPITAL LETTER ENN;Lu;0;L;;;;;N;;;;118D0; -118B1;WARANG CITI CAPITAL LETTER ODD;Lu;0;L;;;;;N;;;;118D1; -118B2;WARANG CITI CAPITAL LETTER TTE;Lu;0;L;;;;;N;;;;118D2; -118B3;WARANG CITI CAPITAL LETTER NUNG;Lu;0;L;;;;;N;;;;118D3; -118B4;WARANG CITI CAPITAL LETTER DA;Lu;0;L;;;;;N;;;;118D4; -118B5;WARANG CITI CAPITAL LETTER AT;Lu;0;L;;;;;N;;;;118D5; -118B6;WARANG CITI CAPITAL LETTER AM;Lu;0;L;;;;;N;;;;118D6; -118B7;WARANG CITI CAPITAL LETTER BU;Lu;0;L;;;;;N;;;;118D7; -118B8;WARANG CITI CAPITAL LETTER PU;Lu;0;L;;;;;N;;;;118D8; -118B9;WARANG CITI CAPITAL LETTER HIYO;Lu;0;L;;;;;N;;;;118D9; -118BA;WARANG CITI CAPITAL LETTER HOLO;Lu;0;L;;;;;N;;;;118DA; -118BB;WARANG CITI CAPITAL LETTER HORR;Lu;0;L;;;;;N;;;;118DB; -118BC;WARANG CITI CAPITAL LETTER HAR;Lu;0;L;;;;;N;;;;118DC; -118BD;WARANG CITI CAPITAL LETTER SSUU;Lu;0;L;;;;;N;;;;118DD; -118BE;WARANG CITI CAPITAL LETTER SII;Lu;0;L;;;;;N;;;;118DE; -118BF;WARANG CITI CAPITAL LETTER VIYO;Lu;0;L;;;;;N;;;;118DF; -118C0;WARANG CITI SMALL LETTER NGAA;Ll;0;L;;;;;N;;;118A0;;118A0 -118C1;WARANG CITI SMALL LETTER A;Ll;0;L;;;;;N;;;118A1;;118A1 -118C2;WARANG CITI SMALL LETTER WI;Ll;0;L;;;;;N;;;118A2;;118A2 -118C3;WARANG CITI SMALL LETTER YU;Ll;0;L;;;;;N;;;118A3;;118A3 -118C4;WARANG CITI SMALL LETTER YA;Ll;0;L;;;;;N;;;118A4;;118A4 -118C5;WARANG CITI SMALL LETTER YO;Ll;0;L;;;;;N;;;118A5;;118A5 -118C6;WARANG CITI SMALL LETTER II;Ll;0;L;;;;;N;;;118A6;;118A6 -118C7;WARANG CITI SMALL LETTER UU;Ll;0;L;;;;;N;;;118A7;;118A7 -118C8;WARANG CITI SMALL LETTER E;Ll;0;L;;;;;N;;;118A8;;118A8 -118C9;WARANG CITI SMALL LETTER O;Ll;0;L;;;;;N;;;118A9;;118A9 -118CA;WARANG CITI SMALL LETTER ANG;Ll;0;L;;;;;N;;;118AA;;118AA -118CB;WARANG CITI SMALL LETTER GA;Ll;0;L;;;;;N;;;118AB;;118AB -118CC;WARANG CITI SMALL LETTER KO;Ll;0;L;;;;;N;;;118AC;;118AC -118CD;WARANG CITI SMALL LETTER ENY;Ll;0;L;;;;;N;;;118AD;;118AD -118CE;WARANG CITI SMALL LETTER YUJ;Ll;0;L;;;;;N;;;118AE;;118AE -118CF;WARANG CITI SMALL LETTER UC;Ll;0;L;;;;;N;;;118AF;;118AF -118D0;WARANG CITI SMALL LETTER ENN;Ll;0;L;;;;;N;;;118B0;;118B0 -118D1;WARANG CITI SMALL LETTER ODD;Ll;0;L;;;;;N;;;118B1;;118B1 -118D2;WARANG CITI SMALL LETTER TTE;Ll;0;L;;;;;N;;;118B2;;118B2 -118D3;WARANG CITI SMALL LETTER NUNG;Ll;0;L;;;;;N;;;118B3;;118B3 -118D4;WARANG CITI SMALL LETTER DA;Ll;0;L;;;;;N;;;118B4;;118B4 -118D5;WARANG CITI SMALL LETTER AT;Ll;0;L;;;;;N;;;118B5;;118B5 -118D6;WARANG CITI SMALL LETTER AM;Ll;0;L;;;;;N;;;118B6;;118B6 -118D7;WARANG CITI SMALL LETTER BU;Ll;0;L;;;;;N;;;118B7;;118B7 -118D8;WARANG CITI SMALL LETTER PU;Ll;0;L;;;;;N;;;118B8;;118B8 -118D9;WARANG CITI SMALL LETTER HIYO;Ll;0;L;;;;;N;;;118B9;;118B9 -118DA;WARANG CITI SMALL LETTER HOLO;Ll;0;L;;;;;N;;;118BA;;118BA -118DB;WARANG CITI SMALL LETTER HORR;Ll;0;L;;;;;N;;;118BB;;118BB -118DC;WARANG CITI SMALL LETTER HAR;Ll;0;L;;;;;N;;;118BC;;118BC -118DD;WARANG CITI SMALL LETTER SSUU;Ll;0;L;;;;;N;;;118BD;;118BD -118DE;WARANG CITI SMALL LETTER SII;Ll;0;L;;;;;N;;;118BE;;118BE -118DF;WARANG CITI SMALL LETTER VIYO;Ll;0;L;;;;;N;;;118BF;;118BF -118E0;WARANG CITI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -118E1;WARANG CITI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -118E2;WARANG CITI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -118E3;WARANG CITI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -118E4;WARANG CITI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -118E5;WARANG CITI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -118E6;WARANG CITI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -118E7;WARANG CITI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -118E8;WARANG CITI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -118E9;WARANG CITI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -118EA;WARANG CITI NUMBER TEN;No;0;L;;;;10;N;;;;; -118EB;WARANG CITI NUMBER TWENTY;No;0;L;;;;20;N;;;;; -118EC;WARANG CITI NUMBER THIRTY;No;0;L;;;;30;N;;;;; -118ED;WARANG CITI NUMBER FORTY;No;0;L;;;;40;N;;;;; -118EE;WARANG CITI NUMBER FIFTY;No;0;L;;;;50;N;;;;; -118EF;WARANG CITI NUMBER SIXTY;No;0;L;;;;60;N;;;;; -118F0;WARANG CITI NUMBER SEVENTY;No;0;L;;;;70;N;;;;; -118F1;WARANG CITI NUMBER EIGHTY;No;0;L;;;;80;N;;;;; -118F2;WARANG CITI NUMBER NINETY;No;0;L;;;;90;N;;;;; -118FF;WARANG CITI OM;Lo;0;L;;;;;N;;;;; -11900;DIVES AKURU LETTER A;Lo;0;L;;;;;N;;;;; -11901;DIVES AKURU LETTER AA;Lo;0;L;;;;;N;;;;; -11902;DIVES AKURU LETTER I;Lo;0;L;;;;;N;;;;; -11903;DIVES AKURU LETTER II;Lo;0;L;;;;;N;;;;; -11904;DIVES AKURU LETTER U;Lo;0;L;;;;;N;;;;; -11905;DIVES AKURU LETTER UU;Lo;0;L;;;;;N;;;;; -11906;DIVES AKURU LETTER E;Lo;0;L;;;;;N;;;;; -11909;DIVES AKURU LETTER O;Lo;0;L;;;;;N;;;;; -1190C;DIVES AKURU LETTER KA;Lo;0;L;;;;;N;;;;; -1190D;DIVES AKURU LETTER KHA;Lo;0;L;;;;;N;;;;; -1190E;DIVES AKURU LETTER GA;Lo;0;L;;;;;N;;;;; -1190F;DIVES AKURU LETTER GHA;Lo;0;L;;;;;N;;;;; -11910;DIVES AKURU LETTER NGA;Lo;0;L;;;;;N;;;;; -11911;DIVES AKURU LETTER CA;Lo;0;L;;;;;N;;;;; -11912;DIVES AKURU LETTER CHA;Lo;0;L;;;;;N;;;;; -11913;DIVES AKURU LETTER JA;Lo;0;L;;;;;N;;;;; -11915;DIVES AKURU LETTER NYA;Lo;0;L;;;;;N;;;;; -11916;DIVES AKURU LETTER TTA;Lo;0;L;;;;;N;;;;; -11918;DIVES AKURU LETTER DDA;Lo;0;L;;;;;N;;;;; -11919;DIVES AKURU LETTER DDHA;Lo;0;L;;;;;N;;;;; -1191A;DIVES AKURU LETTER NNA;Lo;0;L;;;;;N;;;;; -1191B;DIVES AKURU LETTER TA;Lo;0;L;;;;;N;;;;; -1191C;DIVES AKURU LETTER THA;Lo;0;L;;;;;N;;;;; -1191D;DIVES AKURU LETTER DA;Lo;0;L;;;;;N;;;;; -1191E;DIVES AKURU LETTER DHA;Lo;0;L;;;;;N;;;;; -1191F;DIVES AKURU LETTER NA;Lo;0;L;;;;;N;;;;; -11920;DIVES AKURU LETTER PA;Lo;0;L;;;;;N;;;;; -11921;DIVES AKURU LETTER PHA;Lo;0;L;;;;;N;;;;; -11922;DIVES AKURU LETTER BA;Lo;0;L;;;;;N;;;;; -11923;DIVES AKURU LETTER BHA;Lo;0;L;;;;;N;;;;; -11924;DIVES AKURU LETTER MA;Lo;0;L;;;;;N;;;;; -11925;DIVES AKURU LETTER YA;Lo;0;L;;;;;N;;;;; -11926;DIVES AKURU LETTER YYA;Lo;0;L;;;;;N;;;;; -11927;DIVES AKURU LETTER RA;Lo;0;L;;;;;N;;;;; -11928;DIVES AKURU LETTER LA;Lo;0;L;;;;;N;;;;; -11929;DIVES AKURU LETTER VA;Lo;0;L;;;;;N;;;;; -1192A;DIVES AKURU LETTER SHA;Lo;0;L;;;;;N;;;;; -1192B;DIVES AKURU LETTER SSA;Lo;0;L;;;;;N;;;;; -1192C;DIVES AKURU LETTER SA;Lo;0;L;;;;;N;;;;; -1192D;DIVES AKURU LETTER HA;Lo;0;L;;;;;N;;;;; -1192E;DIVES AKURU LETTER LLA;Lo;0;L;;;;;N;;;;; -1192F;DIVES AKURU LETTER ZA;Lo;0;L;;;;;N;;;;; -11930;DIVES AKURU VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -11931;DIVES AKURU VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -11932;DIVES AKURU VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -11933;DIVES AKURU VOWEL SIGN U;Mc;0;L;;;;;N;;;;; -11934;DIVES AKURU VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; -11935;DIVES AKURU VOWEL SIGN E;Mc;0;L;;;;;N;;;;; -11937;DIVES AKURU VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; -11938;DIVES AKURU VOWEL SIGN O;Mc;0;L;11935 11930;;;;N;;;;; -1193B;DIVES AKURU SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -1193C;DIVES AKURU SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -1193D;DIVES AKURU SIGN HALANTA;Mc;9;L;;;;;N;;;;; -1193E;DIVES AKURU VIRAMA;Mn;9;NSM;;;;;N;;;;; -1193F;DIVES AKURU PREFIXED NASAL SIGN;Lo;0;L;;;;;N;;;;; -11940;DIVES AKURU MEDIAL YA;Mc;0;L;;;;;N;;;;; -11941;DIVES AKURU INITIAL RA;Lo;0;L;;;;;N;;;;; -11942;DIVES AKURU MEDIAL RA;Mc;0;L;;;;;N;;;;; -11943;DIVES AKURU SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -11944;DIVES AKURU DOUBLE DANDA;Po;0;L;;;;;N;;;;; -11945;DIVES AKURU GAP FILLER;Po;0;L;;;;;N;;;;; -11946;DIVES AKURU END OF TEXT MARK;Po;0;L;;;;;N;;;;; -11950;DIVES AKURU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -11951;DIVES AKURU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -11952;DIVES AKURU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -11953;DIVES AKURU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -11954;DIVES AKURU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -11955;DIVES AKURU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -11956;DIVES AKURU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -11957;DIVES AKURU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -11958;DIVES AKURU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -11959;DIVES AKURU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -119A0;NANDINAGARI LETTER A;Lo;0;L;;;;;N;;;;; -119A1;NANDINAGARI LETTER AA;Lo;0;L;;;;;N;;;;; -119A2;NANDINAGARI LETTER I;Lo;0;L;;;;;N;;;;; -119A3;NANDINAGARI LETTER II;Lo;0;L;;;;;N;;;;; -119A4;NANDINAGARI LETTER U;Lo;0;L;;;;;N;;;;; -119A5;NANDINAGARI LETTER UU;Lo;0;L;;;;;N;;;;; -119A6;NANDINAGARI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; -119A7;NANDINAGARI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; -119AA;NANDINAGARI LETTER E;Lo;0;L;;;;;N;;;;; -119AB;NANDINAGARI LETTER AI;Lo;0;L;;;;;N;;;;; -119AC;NANDINAGARI LETTER O;Lo;0;L;;;;;N;;;;; -119AD;NANDINAGARI LETTER AU;Lo;0;L;;;;;N;;;;; -119AE;NANDINAGARI LETTER KA;Lo;0;L;;;;;N;;;;; -119AF;NANDINAGARI LETTER KHA;Lo;0;L;;;;;N;;;;; -119B0;NANDINAGARI LETTER GA;Lo;0;L;;;;;N;;;;; -119B1;NANDINAGARI LETTER GHA;Lo;0;L;;;;;N;;;;; -119B2;NANDINAGARI LETTER NGA;Lo;0;L;;;;;N;;;;; -119B3;NANDINAGARI LETTER CA;Lo;0;L;;;;;N;;;;; -119B4;NANDINAGARI LETTER CHA;Lo;0;L;;;;;N;;;;; -119B5;NANDINAGARI LETTER JA;Lo;0;L;;;;;N;;;;; -119B6;NANDINAGARI LETTER JHA;Lo;0;L;;;;;N;;;;; -119B7;NANDINAGARI LETTER NYA;Lo;0;L;;;;;N;;;;; -119B8;NANDINAGARI LETTER TTA;Lo;0;L;;;;;N;;;;; -119B9;NANDINAGARI LETTER TTHA;Lo;0;L;;;;;N;;;;; -119BA;NANDINAGARI LETTER DDA;Lo;0;L;;;;;N;;;;; -119BB;NANDINAGARI LETTER DDHA;Lo;0;L;;;;;N;;;;; -119BC;NANDINAGARI LETTER NNA;Lo;0;L;;;;;N;;;;; -119BD;NANDINAGARI LETTER TA;Lo;0;L;;;;;N;;;;; -119BE;NANDINAGARI LETTER THA;Lo;0;L;;;;;N;;;;; -119BF;NANDINAGARI LETTER DA;Lo;0;L;;;;;N;;;;; -119C0;NANDINAGARI LETTER DHA;Lo;0;L;;;;;N;;;;; -119C1;NANDINAGARI LETTER NA;Lo;0;L;;;;;N;;;;; -119C2;NANDINAGARI LETTER PA;Lo;0;L;;;;;N;;;;; -119C3;NANDINAGARI LETTER PHA;Lo;0;L;;;;;N;;;;; -119C4;NANDINAGARI LETTER BA;Lo;0;L;;;;;N;;;;; -119C5;NANDINAGARI LETTER BHA;Lo;0;L;;;;;N;;;;; -119C6;NANDINAGARI LETTER MA;Lo;0;L;;;;;N;;;;; -119C7;NANDINAGARI LETTER YA;Lo;0;L;;;;;N;;;;; -119C8;NANDINAGARI LETTER RA;Lo;0;L;;;;;N;;;;; -119C9;NANDINAGARI LETTER LA;Lo;0;L;;;;;N;;;;; -119CA;NANDINAGARI LETTER VA;Lo;0;L;;;;;N;;;;; -119CB;NANDINAGARI LETTER SHA;Lo;0;L;;;;;N;;;;; -119CC;NANDINAGARI LETTER SSA;Lo;0;L;;;;;N;;;;; -119CD;NANDINAGARI LETTER SA;Lo;0;L;;;;;N;;;;; -119CE;NANDINAGARI LETTER HA;Lo;0;L;;;;;N;;;;; -119CF;NANDINAGARI LETTER LLA;Lo;0;L;;;;;N;;;;; -119D0;NANDINAGARI LETTER RRA;Lo;0;L;;;;;N;;;;; -119D1;NANDINAGARI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -119D2;NANDINAGARI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -119D3;NANDINAGARI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -119D4;NANDINAGARI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -119D5;NANDINAGARI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -119D6;NANDINAGARI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -119D7;NANDINAGARI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; -119DA;NANDINAGARI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -119DB;NANDINAGARI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -119DC;NANDINAGARI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; -119DD;NANDINAGARI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; -119DE;NANDINAGARI SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; -119DF;NANDINAGARI SIGN VISARGA;Mc;0;L;;;;;N;;;;; -119E0;NANDINAGARI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -119E1;NANDINAGARI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; -119E2;NANDINAGARI SIGN SIDDHAM;Po;0;L;;;;;N;;;;; -119E3;NANDINAGARI HEADSTROKE;Lo;0;L;;;;;N;;;;; -119E4;NANDINAGARI VOWEL SIGN PRISHTHAMATRA E;Mc;0;L;;;;;N;;;;; -11A00;ZANABAZAR SQUARE LETTER A;Lo;0;L;;;;;N;;;;; -11A01;ZANABAZAR SQUARE VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -11A02;ZANABAZAR SQUARE VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;; -11A03;ZANABAZAR SQUARE VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -11A04;ZANABAZAR SQUARE VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -11A05;ZANABAZAR SQUARE VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;; -11A06;ZANABAZAR SQUARE VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; -11A07;ZANABAZAR SQUARE VOWEL SIGN AI;Mn;0;L;;;;;N;;;;; -11A08;ZANABAZAR SQUARE VOWEL SIGN AU;Mn;0;L;;;;;N;;;;; -11A09;ZANABAZAR SQUARE VOWEL SIGN REVERSED I;Mn;0;NSM;;;;;N;;;;; -11A0A;ZANABAZAR SQUARE VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;; -11A0B;ZANABAZAR SQUARE LETTER KA;Lo;0;L;;;;;N;;;;; -11A0C;ZANABAZAR SQUARE LETTER KHA;Lo;0;L;;;;;N;;;;; -11A0D;ZANABAZAR SQUARE LETTER GA;Lo;0;L;;;;;N;;;;; -11A0E;ZANABAZAR SQUARE LETTER GHA;Lo;0;L;;;;;N;;;;; -11A0F;ZANABAZAR SQUARE LETTER NGA;Lo;0;L;;;;;N;;;;; -11A10;ZANABAZAR SQUARE LETTER CA;Lo;0;L;;;;;N;;;;; -11A11;ZANABAZAR SQUARE LETTER CHA;Lo;0;L;;;;;N;;;;; -11A12;ZANABAZAR SQUARE LETTER JA;Lo;0;L;;;;;N;;;;; -11A13;ZANABAZAR SQUARE LETTER NYA;Lo;0;L;;;;;N;;;;; -11A14;ZANABAZAR SQUARE LETTER TTA;Lo;0;L;;;;;N;;;;; -11A15;ZANABAZAR SQUARE LETTER TTHA;Lo;0;L;;;;;N;;;;; -11A16;ZANABAZAR SQUARE LETTER DDA;Lo;0;L;;;;;N;;;;; -11A17;ZANABAZAR SQUARE LETTER DDHA;Lo;0;L;;;;;N;;;;; -11A18;ZANABAZAR SQUARE LETTER NNA;Lo;0;L;;;;;N;;;;; -11A19;ZANABAZAR SQUARE LETTER TA;Lo;0;L;;;;;N;;;;; -11A1A;ZANABAZAR SQUARE LETTER THA;Lo;0;L;;;;;N;;;;; -11A1B;ZANABAZAR SQUARE LETTER DA;Lo;0;L;;;;;N;;;;; -11A1C;ZANABAZAR SQUARE LETTER DHA;Lo;0;L;;;;;N;;;;; -11A1D;ZANABAZAR SQUARE LETTER NA;Lo;0;L;;;;;N;;;;; -11A1E;ZANABAZAR SQUARE LETTER PA;Lo;0;L;;;;;N;;;;; -11A1F;ZANABAZAR SQUARE LETTER PHA;Lo;0;L;;;;;N;;;;; -11A20;ZANABAZAR SQUARE LETTER BA;Lo;0;L;;;;;N;;;;; -11A21;ZANABAZAR SQUARE LETTER BHA;Lo;0;L;;;;;N;;;;; -11A22;ZANABAZAR SQUARE LETTER MA;Lo;0;L;;;;;N;;;;; -11A23;ZANABAZAR SQUARE LETTER TSA;Lo;0;L;;;;;N;;;;; -11A24;ZANABAZAR SQUARE LETTER TSHA;Lo;0;L;;;;;N;;;;; -11A25;ZANABAZAR SQUARE LETTER DZA;Lo;0;L;;;;;N;;;;; -11A26;ZANABAZAR SQUARE LETTER DZHA;Lo;0;L;;;;;N;;;;; -11A27;ZANABAZAR SQUARE LETTER ZHA;Lo;0;L;;;;;N;;;;; -11A28;ZANABAZAR SQUARE LETTER ZA;Lo;0;L;;;;;N;;;;; -11A29;ZANABAZAR SQUARE LETTER -A;Lo;0;L;;;;;N;;;;; -11A2A;ZANABAZAR SQUARE LETTER YA;Lo;0;L;;;;;N;;;;; -11A2B;ZANABAZAR SQUARE LETTER RA;Lo;0;L;;;;;N;;;;; -11A2C;ZANABAZAR SQUARE LETTER LA;Lo;0;L;;;;;N;;;;; -11A2D;ZANABAZAR SQUARE LETTER VA;Lo;0;L;;;;;N;;;;; -11A2E;ZANABAZAR SQUARE LETTER SHA;Lo;0;L;;;;;N;;;;; -11A2F;ZANABAZAR SQUARE LETTER SSA;Lo;0;L;;;;;N;;;;; -11A30;ZANABAZAR SQUARE LETTER SA;Lo;0;L;;;;;N;;;;; -11A31;ZANABAZAR SQUARE LETTER HA;Lo;0;L;;;;;N;;;;; -11A32;ZANABAZAR SQUARE LETTER KSSA;Lo;0;L;;;;;N;;;;; -11A33;ZANABAZAR SQUARE FINAL CONSONANT MARK;Mn;0;NSM;;;;;N;;;;; -11A34;ZANABAZAR SQUARE SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -11A35;ZANABAZAR SQUARE SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -11A36;ZANABAZAR SQUARE SIGN CANDRABINDU WITH ORNAMENT;Mn;0;NSM;;;;;N;;;;; -11A37;ZANABAZAR SQUARE SIGN CANDRA WITH ORNAMENT;Mn;0;NSM;;;;;N;;;;; -11A38;ZANABAZAR SQUARE SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -11A39;ZANABAZAR SQUARE SIGN VISARGA;Mc;0;L;;;;;N;;;;; -11A3A;ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA;Lo;0;L;;;;;N;;;;; -11A3B;ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA;Mn;0;NSM;;;;;N;;;;; -11A3C;ZANABAZAR SQUARE CLUSTER-FINAL LETTER RA;Mn;0;NSM;;;;;N;;;;; -11A3D;ZANABAZAR SQUARE CLUSTER-FINAL LETTER LA;Mn;0;NSM;;;;;N;;;;; -11A3E;ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA;Mn;0;NSM;;;;;N;;;;; -11A3F;ZANABAZAR SQUARE INITIAL HEAD MARK;Po;0;L;;;;;N;;;;; -11A40;ZANABAZAR SQUARE CLOSING HEAD MARK;Po;0;L;;;;;N;;;;; -11A41;ZANABAZAR SQUARE MARK TSHEG;Po;0;L;;;;;N;;;;; -11A42;ZANABAZAR SQUARE MARK SHAD;Po;0;L;;;;;N;;;;; -11A43;ZANABAZAR SQUARE MARK DOUBLE SHAD;Po;0;L;;;;;N;;;;; -11A44;ZANABAZAR SQUARE MARK LONG TSHEG;Po;0;L;;;;;N;;;;; -11A45;ZANABAZAR SQUARE INITIAL DOUBLE-LINED HEAD MARK;Po;0;L;;;;;N;;;;; -11A46;ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK;Po;0;L;;;;;N;;;;; -11A47;ZANABAZAR SQUARE SUBJOINER;Mn;9;NSM;;;;;N;;;;; -11A50;SOYOMBO LETTER A;Lo;0;L;;;;;N;;;;; -11A51;SOYOMBO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -11A52;SOYOMBO VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;; -11A53;SOYOMBO VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -11A54;SOYOMBO VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -11A55;SOYOMBO VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; -11A56;SOYOMBO VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;; -11A57;SOYOMBO VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; -11A58;SOYOMBO VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; -11A59;SOYOMBO VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -11A5A;SOYOMBO VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; -11A5B;SOYOMBO VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;; -11A5C;SOYOMBO LETTER KA;Lo;0;L;;;;;N;;;;; -11A5D;SOYOMBO LETTER KHA;Lo;0;L;;;;;N;;;;; -11A5E;SOYOMBO LETTER GA;Lo;0;L;;;;;N;;;;; -11A5F;SOYOMBO LETTER GHA;Lo;0;L;;;;;N;;;;; -11A60;SOYOMBO LETTER NGA;Lo;0;L;;;;;N;;;;; -11A61;SOYOMBO LETTER CA;Lo;0;L;;;;;N;;;;; -11A62;SOYOMBO LETTER CHA;Lo;0;L;;;;;N;;;;; -11A63;SOYOMBO LETTER JA;Lo;0;L;;;;;N;;;;; -11A64;SOYOMBO LETTER JHA;Lo;0;L;;;;;N;;;;; -11A65;SOYOMBO LETTER NYA;Lo;0;L;;;;;N;;;;; -11A66;SOYOMBO LETTER TTA;Lo;0;L;;;;;N;;;;; -11A67;SOYOMBO LETTER TTHA;Lo;0;L;;;;;N;;;;; -11A68;SOYOMBO LETTER DDA;Lo;0;L;;;;;N;;;;; -11A69;SOYOMBO LETTER DDHA;Lo;0;L;;;;;N;;;;; -11A6A;SOYOMBO LETTER NNA;Lo;0;L;;;;;N;;;;; -11A6B;SOYOMBO LETTER TA;Lo;0;L;;;;;N;;;;; -11A6C;SOYOMBO LETTER THA;Lo;0;L;;;;;N;;;;; -11A6D;SOYOMBO LETTER DA;Lo;0;L;;;;;N;;;;; -11A6E;SOYOMBO LETTER DHA;Lo;0;L;;;;;N;;;;; -11A6F;SOYOMBO LETTER NA;Lo;0;L;;;;;N;;;;; -11A70;SOYOMBO LETTER PA;Lo;0;L;;;;;N;;;;; -11A71;SOYOMBO LETTER PHA;Lo;0;L;;;;;N;;;;; -11A72;SOYOMBO LETTER BA;Lo;0;L;;;;;N;;;;; -11A73;SOYOMBO LETTER BHA;Lo;0;L;;;;;N;;;;; -11A74;SOYOMBO LETTER MA;Lo;0;L;;;;;N;;;;; -11A75;SOYOMBO LETTER TSA;Lo;0;L;;;;;N;;;;; -11A76;SOYOMBO LETTER TSHA;Lo;0;L;;;;;N;;;;; -11A77;SOYOMBO LETTER DZA;Lo;0;L;;;;;N;;;;; -11A78;SOYOMBO LETTER ZHA;Lo;0;L;;;;;N;;;;; -11A79;SOYOMBO LETTER ZA;Lo;0;L;;;;;N;;;;; -11A7A;SOYOMBO LETTER -A;Lo;0;L;;;;;N;;;;; -11A7B;SOYOMBO LETTER YA;Lo;0;L;;;;;N;;;;; -11A7C;SOYOMBO LETTER RA;Lo;0;L;;;;;N;;;;; -11A7D;SOYOMBO LETTER LA;Lo;0;L;;;;;N;;;;; -11A7E;SOYOMBO LETTER VA;Lo;0;L;;;;;N;;;;; -11A7F;SOYOMBO LETTER SHA;Lo;0;L;;;;;N;;;;; -11A80;SOYOMBO LETTER SSA;Lo;0;L;;;;;N;;;;; -11A81;SOYOMBO LETTER SA;Lo;0;L;;;;;N;;;;; -11A82;SOYOMBO LETTER HA;Lo;0;L;;;;;N;;;;; -11A83;SOYOMBO LETTER KSSA;Lo;0;L;;;;;N;;;;; -11A84;SOYOMBO SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; -11A85;SOYOMBO SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; -11A86;SOYOMBO CLUSTER-INITIAL LETTER RA;Lo;0;L;;;;;N;;;;; -11A87;SOYOMBO CLUSTER-INITIAL LETTER LA;Lo;0;L;;;;;N;;;;; -11A88;SOYOMBO CLUSTER-INITIAL LETTER SHA;Lo;0;L;;;;;N;;;;; -11A89;SOYOMBO CLUSTER-INITIAL LETTER SA;Lo;0;L;;;;;N;;;;; -11A8A;SOYOMBO FINAL CONSONANT SIGN G;Mn;0;NSM;;;;;N;;;;; -11A8B;SOYOMBO FINAL CONSONANT SIGN K;Mn;0;NSM;;;;;N;;;;; -11A8C;SOYOMBO FINAL CONSONANT SIGN NG;Mn;0;NSM;;;;;N;;;;; -11A8D;SOYOMBO FINAL CONSONANT SIGN D;Mn;0;NSM;;;;;N;;;;; -11A8E;SOYOMBO FINAL CONSONANT SIGN N;Mn;0;NSM;;;;;N;;;;; -11A8F;SOYOMBO FINAL CONSONANT SIGN B;Mn;0;NSM;;;;;N;;;;; -11A90;SOYOMBO FINAL CONSONANT SIGN M;Mn;0;NSM;;;;;N;;;;; -11A91;SOYOMBO FINAL CONSONANT SIGN R;Mn;0;NSM;;;;;N;;;;; -11A92;SOYOMBO FINAL CONSONANT SIGN L;Mn;0;NSM;;;;;N;;;;; -11A93;SOYOMBO FINAL CONSONANT SIGN SH;Mn;0;NSM;;;;;N;;;;; -11A94;SOYOMBO FINAL CONSONANT SIGN S;Mn;0;NSM;;;;;N;;;;; -11A95;SOYOMBO FINAL CONSONANT SIGN -A;Mn;0;NSM;;;;;N;;;;; -11A96;SOYOMBO SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -11A97;SOYOMBO SIGN VISARGA;Mc;0;L;;;;;N;;;;; -11A98;SOYOMBO GEMINATION MARK;Mn;0;NSM;;;;;N;;;;; -11A99;SOYOMBO SUBJOINER;Mn;9;NSM;;;;;N;;;;; -11A9A;SOYOMBO MARK TSHEG;Po;0;L;;;;;N;;;;; -11A9B;SOYOMBO MARK SHAD;Po;0;L;;;;;N;;;;; -11A9C;SOYOMBO MARK DOUBLE SHAD;Po;0;L;;;;;N;;;;; -11A9D;SOYOMBO MARK PLUTA;Lo;0;L;;;;;N;;;;; -11A9E;SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME;Po;0;L;;;;;N;;;;; -11A9F;SOYOMBO HEAD MARK WITH MOON AND SUN AND FLAME;Po;0;L;;;;;N;;;;; -11AA0;SOYOMBO HEAD MARK WITH MOON AND SUN;Po;0;L;;;;;N;;;;; -11AA1;SOYOMBO TERMINAL MARK-1;Po;0;L;;;;;N;;;;; -11AA2;SOYOMBO TERMINAL MARK-2;Po;0;L;;;;;N;;;;; -11AB0;CANADIAN SYLLABICS NATTILIK HI;Lo;0;L;;;;;N;;;;; -11AB1;CANADIAN SYLLABICS NATTILIK HII;Lo;0;L;;;;;N;;;;; -11AB2;CANADIAN SYLLABICS NATTILIK HO;Lo;0;L;;;;;N;;;;; -11AB3;CANADIAN SYLLABICS NATTILIK HOO;Lo;0;L;;;;;N;;;;; -11AB4;CANADIAN SYLLABICS NATTILIK HA;Lo;0;L;;;;;N;;;;; -11AB5;CANADIAN SYLLABICS NATTILIK HAA;Lo;0;L;;;;;N;;;;; -11AB6;CANADIAN SYLLABICS NATTILIK SHRI;Lo;0;L;;;;;N;;;;; -11AB7;CANADIAN SYLLABICS NATTILIK SHRII;Lo;0;L;;;;;N;;;;; -11AB8;CANADIAN SYLLABICS NATTILIK SHRO;Lo;0;L;;;;;N;;;;; -11AB9;CANADIAN SYLLABICS NATTILIK SHROO;Lo;0;L;;;;;N;;;;; -11ABA;CANADIAN SYLLABICS NATTILIK SHRA;Lo;0;L;;;;;N;;;;; -11ABB;CANADIAN SYLLABICS NATTILIK SHRAA;Lo;0;L;;;;;N;;;;; -11ABC;CANADIAN SYLLABICS SPE;Lo;0;L;;;;;N;;;;; -11ABD;CANADIAN SYLLABICS SPI;Lo;0;L;;;;;N;;;;; -11ABE;CANADIAN SYLLABICS SPO;Lo;0;L;;;;;N;;;;; -11ABF;CANADIAN SYLLABICS SPA;Lo;0;L;;;;;N;;;;; -11AC0;PAU CIN HAU LETTER PA;Lo;0;L;;;;;N;;;;; -11AC1;PAU CIN HAU LETTER KA;Lo;0;L;;;;;N;;;;; -11AC2;PAU CIN HAU LETTER LA;Lo;0;L;;;;;N;;;;; -11AC3;PAU CIN HAU LETTER MA;Lo;0;L;;;;;N;;;;; -11AC4;PAU CIN HAU LETTER DA;Lo;0;L;;;;;N;;;;; -11AC5;PAU CIN HAU LETTER ZA;Lo;0;L;;;;;N;;;;; -11AC6;PAU CIN HAU LETTER VA;Lo;0;L;;;;;N;;;;; -11AC7;PAU CIN HAU LETTER NGA;Lo;0;L;;;;;N;;;;; -11AC8;PAU CIN HAU LETTER HA;Lo;0;L;;;;;N;;;;; -11AC9;PAU CIN HAU LETTER GA;Lo;0;L;;;;;N;;;;; -11ACA;PAU CIN HAU LETTER KHA;Lo;0;L;;;;;N;;;;; -11ACB;PAU CIN HAU LETTER SA;Lo;0;L;;;;;N;;;;; -11ACC;PAU CIN HAU LETTER BA;Lo;0;L;;;;;N;;;;; -11ACD;PAU CIN HAU LETTER CA;Lo;0;L;;;;;N;;;;; -11ACE;PAU CIN HAU LETTER TA;Lo;0;L;;;;;N;;;;; -11ACF;PAU CIN HAU LETTER THA;Lo;0;L;;;;;N;;;;; -11AD0;PAU CIN HAU LETTER NA;Lo;0;L;;;;;N;;;;; -11AD1;PAU CIN HAU LETTER PHA;Lo;0;L;;;;;N;;;;; -11AD2;PAU CIN HAU LETTER RA;Lo;0;L;;;;;N;;;;; -11AD3;PAU CIN HAU LETTER FA;Lo;0;L;;;;;N;;;;; -11AD4;PAU CIN HAU LETTER CHA;Lo;0;L;;;;;N;;;;; -11AD5;PAU CIN HAU LETTER A;Lo;0;L;;;;;N;;;;; -11AD6;PAU CIN HAU LETTER E;Lo;0;L;;;;;N;;;;; -11AD7;PAU CIN HAU LETTER I;Lo;0;L;;;;;N;;;;; -11AD8;PAU CIN HAU LETTER O;Lo;0;L;;;;;N;;;;; -11AD9;PAU CIN HAU LETTER U;Lo;0;L;;;;;N;;;;; -11ADA;PAU CIN HAU LETTER UA;Lo;0;L;;;;;N;;;;; -11ADB;PAU CIN HAU LETTER IA;Lo;0;L;;;;;N;;;;; -11ADC;PAU CIN HAU LETTER FINAL P;Lo;0;L;;;;;N;;;;; -11ADD;PAU CIN HAU LETTER FINAL K;Lo;0;L;;;;;N;;;;; -11ADE;PAU CIN HAU LETTER FINAL T;Lo;0;L;;;;;N;;;;; -11ADF;PAU CIN HAU LETTER FINAL M;Lo;0;L;;;;;N;;;;; -11AE0;PAU CIN HAU LETTER FINAL N;Lo;0;L;;;;;N;;;;; -11AE1;PAU CIN HAU LETTER FINAL L;Lo;0;L;;;;;N;;;;; -11AE2;PAU CIN HAU LETTER FINAL W;Lo;0;L;;;;;N;;;;; -11AE3;PAU CIN HAU LETTER FINAL NG;Lo;0;L;;;;;N;;;;; -11AE4;PAU CIN HAU LETTER FINAL Y;Lo;0;L;;;;;N;;;;; -11AE5;PAU CIN HAU RISING TONE LONG;Lo;0;L;;;;;N;;;;; -11AE6;PAU CIN HAU RISING TONE;Lo;0;L;;;;;N;;;;; -11AE7;PAU CIN HAU SANDHI GLOTTAL STOP;Lo;0;L;;;;;N;;;;; -11AE8;PAU CIN HAU RISING TONE LONG FINAL;Lo;0;L;;;;;N;;;;; -11AE9;PAU CIN HAU RISING TONE FINAL;Lo;0;L;;;;;N;;;;; -11AEA;PAU CIN HAU SANDHI GLOTTAL STOP FINAL;Lo;0;L;;;;;N;;;;; -11AEB;PAU CIN HAU SANDHI TONE LONG;Lo;0;L;;;;;N;;;;; -11AEC;PAU CIN HAU SANDHI TONE;Lo;0;L;;;;;N;;;;; -11AED;PAU CIN HAU SANDHI TONE LONG FINAL;Lo;0;L;;;;;N;;;;; -11AEE;PAU CIN HAU SANDHI TONE FINAL;Lo;0;L;;;;;N;;;;; -11AEF;PAU CIN HAU MID-LEVEL TONE;Lo;0;L;;;;;N;;;;; -11AF0;PAU CIN HAU GLOTTAL STOP VARIANT;Lo;0;L;;;;;N;;;;; -11AF1;PAU CIN HAU MID-LEVEL TONE LONG FINAL;Lo;0;L;;;;;N;;;;; -11AF2;PAU CIN HAU MID-LEVEL TONE FINAL;Lo;0;L;;;;;N;;;;; -11AF3;PAU CIN HAU LOW-FALLING TONE LONG;Lo;0;L;;;;;N;;;;; -11AF4;PAU CIN HAU LOW-FALLING TONE;Lo;0;L;;;;;N;;;;; -11AF5;PAU CIN HAU GLOTTAL STOP;Lo;0;L;;;;;N;;;;; -11AF6;PAU CIN HAU LOW-FALLING TONE LONG FINAL;Lo;0;L;;;;;N;;;;; -11AF7;PAU CIN HAU LOW-FALLING TONE FINAL;Lo;0;L;;;;;N;;;;; -11AF8;PAU CIN HAU GLOTTAL STOP FINAL;Lo;0;L;;;;;N;;;;; -11B00;DEVANAGARI HEAD MARK;Po;0;L;;;;;N;;;;; -11B01;DEVANAGARI HEAD MARK WITH HEADSTROKE;Po;0;L;;;;;N;;;;; -11B02;DEVANAGARI SIGN BHALE;Po;0;L;;;;;N;;;;; -11B03;DEVANAGARI SIGN BHALE WITH HOOK;Po;0;L;;;;;N;;;;; -11B04;DEVANAGARI SIGN EXTENDED BHALE;Po;0;L;;;;;N;;;;; -11B05;DEVANAGARI SIGN EXTENDED BHALE WITH HOOK;Po;0;L;;;;;N;;;;; -11B06;DEVANAGARI SIGN WESTERN FIVE-LIKE BHALE;Po;0;L;;;;;N;;;;; -11B07;DEVANAGARI SIGN WESTERN NINE-LIKE BHALE;Po;0;L;;;;;N;;;;; -11B08;DEVANAGARI SIGN REVERSED NINE-LIKE BHALE;Po;0;L;;;;;N;;;;; -11B09;DEVANAGARI SIGN MINDU;Po;0;L;;;;;N;;;;; -11C00;BHAIKSUKI LETTER A;Lo;0;L;;;;;N;;;;; -11C01;BHAIKSUKI LETTER AA;Lo;0;L;;;;;N;;;;; -11C02;BHAIKSUKI LETTER I;Lo;0;L;;;;;N;;;;; -11C03;BHAIKSUKI LETTER II;Lo;0;L;;;;;N;;;;; -11C04;BHAIKSUKI LETTER U;Lo;0;L;;;;;N;;;;; -11C05;BHAIKSUKI LETTER UU;Lo;0;L;;;;;N;;;;; -11C06;BHAIKSUKI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; -11C07;BHAIKSUKI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; -11C08;BHAIKSUKI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; -11C0A;BHAIKSUKI LETTER E;Lo;0;L;;;;;N;;;;; -11C0B;BHAIKSUKI LETTER AI;Lo;0;L;;;;;N;;;;; -11C0C;BHAIKSUKI LETTER O;Lo;0;L;;;;;N;;;;; -11C0D;BHAIKSUKI LETTER AU;Lo;0;L;;;;;N;;;;; -11C0E;BHAIKSUKI LETTER KA;Lo;0;L;;;;;N;;;;; -11C0F;BHAIKSUKI LETTER KHA;Lo;0;L;;;;;N;;;;; -11C10;BHAIKSUKI LETTER GA;Lo;0;L;;;;;N;;;;; -11C11;BHAIKSUKI LETTER GHA;Lo;0;L;;;;;N;;;;; -11C12;BHAIKSUKI LETTER NGA;Lo;0;L;;;;;N;;;;; -11C13;BHAIKSUKI LETTER CA;Lo;0;L;;;;;N;;;;; -11C14;BHAIKSUKI LETTER CHA;Lo;0;L;;;;;N;;;;; -11C15;BHAIKSUKI LETTER JA;Lo;0;L;;;;;N;;;;; -11C16;BHAIKSUKI LETTER JHA;Lo;0;L;;;;;N;;;;; -11C17;BHAIKSUKI LETTER NYA;Lo;0;L;;;;;N;;;;; -11C18;BHAIKSUKI LETTER TTA;Lo;0;L;;;;;N;;;;; -11C19;BHAIKSUKI LETTER TTHA;Lo;0;L;;;;;N;;;;; -11C1A;BHAIKSUKI LETTER DDA;Lo;0;L;;;;;N;;;;; -11C1B;BHAIKSUKI LETTER DDHA;Lo;0;L;;;;;N;;;;; -11C1C;BHAIKSUKI LETTER NNA;Lo;0;L;;;;;N;;;;; -11C1D;BHAIKSUKI LETTER TA;Lo;0;L;;;;;N;;;;; -11C1E;BHAIKSUKI LETTER THA;Lo;0;L;;;;;N;;;;; -11C1F;BHAIKSUKI LETTER DA;Lo;0;L;;;;;N;;;;; -11C20;BHAIKSUKI LETTER DHA;Lo;0;L;;;;;N;;;;; -11C21;BHAIKSUKI LETTER NA;Lo;0;L;;;;;N;;;;; -11C22;BHAIKSUKI LETTER PA;Lo;0;L;;;;;N;;;;; -11C23;BHAIKSUKI LETTER PHA;Lo;0;L;;;;;N;;;;; -11C24;BHAIKSUKI LETTER BA;Lo;0;L;;;;;N;;;;; -11C25;BHAIKSUKI LETTER BHA;Lo;0;L;;;;;N;;;;; -11C26;BHAIKSUKI LETTER MA;Lo;0;L;;;;;N;;;;; -11C27;BHAIKSUKI LETTER YA;Lo;0;L;;;;;N;;;;; -11C28;BHAIKSUKI LETTER RA;Lo;0;L;;;;;N;;;;; -11C29;BHAIKSUKI LETTER LA;Lo;0;L;;;;;N;;;;; -11C2A;BHAIKSUKI LETTER VA;Lo;0;L;;;;;N;;;;; -11C2B;BHAIKSUKI LETTER SHA;Lo;0;L;;;;;N;;;;; -11C2C;BHAIKSUKI LETTER SSA;Lo;0;L;;;;;N;;;;; -11C2D;BHAIKSUKI LETTER SA;Lo;0;L;;;;;N;;;;; -11C2E;BHAIKSUKI LETTER HA;Lo;0;L;;;;;N;;;;; -11C2F;BHAIKSUKI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -11C30;BHAIKSUKI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -11C31;BHAIKSUKI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; -11C32;BHAIKSUKI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -11C33;BHAIKSUKI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -11C34;BHAIKSUKI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -11C35;BHAIKSUKI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; -11C36;BHAIKSUKI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; -11C38;BHAIKSUKI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -11C39;BHAIKSUKI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -11C3A;BHAIKSUKI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; -11C3B;BHAIKSUKI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; -11C3C;BHAIKSUKI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -11C3D;BHAIKSUKI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -11C3E;BHAIKSUKI SIGN VISARGA;Mc;0;L;;;;;N;;;;; -11C3F;BHAIKSUKI SIGN VIRAMA;Mn;9;L;;;;;N;;;;; -11C40;BHAIKSUKI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; -11C41;BHAIKSUKI DANDA;Po;0;L;;;;;N;;;;; -11C42;BHAIKSUKI DOUBLE DANDA;Po;0;L;;;;;N;;;;; -11C43;BHAIKSUKI WORD SEPARATOR;Po;0;L;;;;;N;;;;; -11C44;BHAIKSUKI GAP FILLER-1;Po;0;L;;;;;N;;;;; -11C45;BHAIKSUKI GAP FILLER-2;Po;0;L;;;;;N;;;;; -11C50;BHAIKSUKI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -11C51;BHAIKSUKI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -11C52;BHAIKSUKI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -11C53;BHAIKSUKI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -11C54;BHAIKSUKI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -11C55;BHAIKSUKI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -11C56;BHAIKSUKI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -11C57;BHAIKSUKI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -11C58;BHAIKSUKI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -11C59;BHAIKSUKI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -11C5A;BHAIKSUKI NUMBER ONE;No;0;L;;;;1;N;;;;; -11C5B;BHAIKSUKI NUMBER TWO;No;0;L;;;;2;N;;;;; -11C5C;BHAIKSUKI NUMBER THREE;No;0;L;;;;3;N;;;;; -11C5D;BHAIKSUKI NUMBER FOUR;No;0;L;;;;4;N;;;;; -11C5E;BHAIKSUKI NUMBER FIVE;No;0;L;;;;5;N;;;;; -11C5F;BHAIKSUKI NUMBER SIX;No;0;L;;;;6;N;;;;; -11C60;BHAIKSUKI NUMBER SEVEN;No;0;L;;;;7;N;;;;; -11C61;BHAIKSUKI NUMBER EIGHT;No;0;L;;;;8;N;;;;; -11C62;BHAIKSUKI NUMBER NINE;No;0;L;;;;9;N;;;;; -11C63;BHAIKSUKI NUMBER TEN;No;0;L;;;;10;N;;;;; -11C64;BHAIKSUKI NUMBER TWENTY;No;0;L;;;;20;N;;;;; -11C65;BHAIKSUKI NUMBER THIRTY;No;0;L;;;;30;N;;;;; -11C66;BHAIKSUKI NUMBER FORTY;No;0;L;;;;40;N;;;;; -11C67;BHAIKSUKI NUMBER FIFTY;No;0;L;;;;50;N;;;;; -11C68;BHAIKSUKI NUMBER SIXTY;No;0;L;;;;60;N;;;;; -11C69;BHAIKSUKI NUMBER SEVENTY;No;0;L;;;;70;N;;;;; -11C6A;BHAIKSUKI NUMBER EIGHTY;No;0;L;;;;80;N;;;;; -11C6B;BHAIKSUKI NUMBER NINETY;No;0;L;;;;90;N;;;;; -11C6C;BHAIKSUKI HUNDREDS UNIT MARK;No;0;L;;;;100;N;;;;; -11C70;MARCHEN HEAD MARK;Po;0;L;;;;;N;;;;; -11C71;MARCHEN MARK SHAD;Po;0;L;;;;;N;;;;; -11C72;MARCHEN LETTER KA;Lo;0;L;;;;;N;;;;; -11C73;MARCHEN LETTER KHA;Lo;0;L;;;;;N;;;;; -11C74;MARCHEN LETTER GA;Lo;0;L;;;;;N;;;;; -11C75;MARCHEN LETTER NGA;Lo;0;L;;;;;N;;;;; -11C76;MARCHEN LETTER CA;Lo;0;L;;;;;N;;;;; -11C77;MARCHEN LETTER CHA;Lo;0;L;;;;;N;;;;; -11C78;MARCHEN LETTER JA;Lo;0;L;;;;;N;;;;; -11C79;MARCHEN LETTER NYA;Lo;0;L;;;;;N;;;;; -11C7A;MARCHEN LETTER TA;Lo;0;L;;;;;N;;;;; -11C7B;MARCHEN LETTER THA;Lo;0;L;;;;;N;;;;; -11C7C;MARCHEN LETTER DA;Lo;0;L;;;;;N;;;;; -11C7D;MARCHEN LETTER NA;Lo;0;L;;;;;N;;;;; -11C7E;MARCHEN LETTER PA;Lo;0;L;;;;;N;;;;; -11C7F;MARCHEN LETTER PHA;Lo;0;L;;;;;N;;;;; -11C80;MARCHEN LETTER BA;Lo;0;L;;;;;N;;;;; -11C81;MARCHEN LETTER MA;Lo;0;L;;;;;N;;;;; -11C82;MARCHEN LETTER TSA;Lo;0;L;;;;;N;;;;; -11C83;MARCHEN LETTER TSHA;Lo;0;L;;;;;N;;;;; -11C84;MARCHEN LETTER DZA;Lo;0;L;;;;;N;;;;; -11C85;MARCHEN LETTER WA;Lo;0;L;;;;;N;;;;; -11C86;MARCHEN LETTER ZHA;Lo;0;L;;;;;N;;;;; -11C87;MARCHEN LETTER ZA;Lo;0;L;;;;;N;;;;; -11C88;MARCHEN LETTER -A;Lo;0;L;;;;;N;;;;; -11C89;MARCHEN LETTER YA;Lo;0;L;;;;;N;;;;; -11C8A;MARCHEN LETTER RA;Lo;0;L;;;;;N;;;;; -11C8B;MARCHEN LETTER LA;Lo;0;L;;;;;N;;;;; -11C8C;MARCHEN LETTER SHA;Lo;0;L;;;;;N;;;;; -11C8D;MARCHEN LETTER SA;Lo;0;L;;;;;N;;;;; -11C8E;MARCHEN LETTER HA;Lo;0;L;;;;;N;;;;; -11C8F;MARCHEN LETTER A;Lo;0;L;;;;;N;;;;; -11C92;MARCHEN SUBJOINED LETTER KA;Mn;0;NSM;;;;;N;;;;; -11C93;MARCHEN SUBJOINED LETTER KHA;Mn;0;NSM;;;;;N;;;;; -11C94;MARCHEN SUBJOINED LETTER GA;Mn;0;NSM;;;;;N;;;;; -11C95;MARCHEN SUBJOINED LETTER NGA;Mn;0;NSM;;;;;N;;;;; -11C96;MARCHEN SUBJOINED LETTER CA;Mn;0;NSM;;;;;N;;;;; -11C97;MARCHEN SUBJOINED LETTER CHA;Mn;0;NSM;;;;;N;;;;; -11C98;MARCHEN SUBJOINED LETTER JA;Mn;0;NSM;;;;;N;;;;; -11C99;MARCHEN SUBJOINED LETTER NYA;Mn;0;NSM;;;;;N;;;;; -11C9A;MARCHEN SUBJOINED LETTER TA;Mn;0;NSM;;;;;N;;;;; -11C9B;MARCHEN SUBJOINED LETTER THA;Mn;0;NSM;;;;;N;;;;; -11C9C;MARCHEN SUBJOINED LETTER DA;Mn;0;NSM;;;;;N;;;;; -11C9D;MARCHEN SUBJOINED LETTER NA;Mn;0;NSM;;;;;N;;;;; -11C9E;MARCHEN SUBJOINED LETTER PA;Mn;0;NSM;;;;;N;;;;; -11C9F;MARCHEN SUBJOINED LETTER PHA;Mn;0;NSM;;;;;N;;;;; -11CA0;MARCHEN SUBJOINED LETTER BA;Mn;0;NSM;;;;;N;;;;; -11CA1;MARCHEN SUBJOINED LETTER MA;Mn;0;NSM;;;;;N;;;;; -11CA2;MARCHEN SUBJOINED LETTER TSA;Mn;0;NSM;;;;;N;;;;; -11CA3;MARCHEN SUBJOINED LETTER TSHA;Mn;0;NSM;;;;;N;;;;; -11CA4;MARCHEN SUBJOINED LETTER DZA;Mn;0;NSM;;;;;N;;;;; -11CA5;MARCHEN SUBJOINED LETTER WA;Mn;0;NSM;;;;;N;;;;; -11CA6;MARCHEN SUBJOINED LETTER ZHA;Mn;0;NSM;;;;;N;;;;; -11CA7;MARCHEN SUBJOINED LETTER ZA;Mn;0;NSM;;;;;N;;;;; -11CA9;MARCHEN SUBJOINED LETTER YA;Mc;0;L;;;;;N;;;;; -11CAA;MARCHEN SUBJOINED LETTER RA;Mn;0;NSM;;;;;N;;;;; -11CAB;MARCHEN SUBJOINED LETTER LA;Mn;0;NSM;;;;;N;;;;; -11CAC;MARCHEN SUBJOINED LETTER SHA;Mn;0;NSM;;;;;N;;;;; -11CAD;MARCHEN SUBJOINED LETTER SA;Mn;0;NSM;;;;;N;;;;; -11CAE;MARCHEN SUBJOINED LETTER HA;Mn;0;NSM;;;;;N;;;;; -11CAF;MARCHEN SUBJOINED LETTER A;Mn;0;NSM;;;;;N;;;;; -11CB0;MARCHEN VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; -11CB1;MARCHEN VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -11CB2;MARCHEN VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -11CB3;MARCHEN VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -11CB4;MARCHEN VOWEL SIGN O;Mc;0;L;;;;;N;;;;; -11CB5;MARCHEN SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -11CB6;MARCHEN SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -11D00;MASARAM GONDI LETTER A;Lo;0;L;;;;;N;;;;; -11D01;MASARAM GONDI LETTER AA;Lo;0;L;;;;;N;;;;; -11D02;MASARAM GONDI LETTER I;Lo;0;L;;;;;N;;;;; -11D03;MASARAM GONDI LETTER II;Lo;0;L;;;;;N;;;;; -11D04;MASARAM GONDI LETTER U;Lo;0;L;;;;;N;;;;; -11D05;MASARAM GONDI LETTER UU;Lo;0;L;;;;;N;;;;; -11D06;MASARAM GONDI LETTER E;Lo;0;L;;;;;N;;;;; -11D08;MASARAM GONDI LETTER AI;Lo;0;L;;;;;N;;;;; -11D09;MASARAM GONDI LETTER O;Lo;0;L;;;;;N;;;;; -11D0B;MASARAM GONDI LETTER AU;Lo;0;L;;;;;N;;;;; -11D0C;MASARAM GONDI LETTER KA;Lo;0;L;;;;;N;;;;; -11D0D;MASARAM GONDI LETTER KHA;Lo;0;L;;;;;N;;;;; -11D0E;MASARAM GONDI LETTER GA;Lo;0;L;;;;;N;;;;; -11D0F;MASARAM GONDI LETTER GHA;Lo;0;L;;;;;N;;;;; -11D10;MASARAM GONDI LETTER NGA;Lo;0;L;;;;;N;;;;; -11D11;MASARAM GONDI LETTER CA;Lo;0;L;;;;;N;;;;; -11D12;MASARAM GONDI LETTER CHA;Lo;0;L;;;;;N;;;;; -11D13;MASARAM GONDI LETTER JA;Lo;0;L;;;;;N;;;;; -11D14;MASARAM GONDI LETTER JHA;Lo;0;L;;;;;N;;;;; -11D15;MASARAM GONDI LETTER NYA;Lo;0;L;;;;;N;;;;; -11D16;MASARAM GONDI LETTER TTA;Lo;0;L;;;;;N;;;;; -11D17;MASARAM GONDI LETTER TTHA;Lo;0;L;;;;;N;;;;; -11D18;MASARAM GONDI LETTER DDA;Lo;0;L;;;;;N;;;;; -11D19;MASARAM GONDI LETTER DDHA;Lo;0;L;;;;;N;;;;; -11D1A;MASARAM GONDI LETTER NNA;Lo;0;L;;;;;N;;;;; -11D1B;MASARAM GONDI LETTER TA;Lo;0;L;;;;;N;;;;; -11D1C;MASARAM GONDI LETTER THA;Lo;0;L;;;;;N;;;;; -11D1D;MASARAM GONDI LETTER DA;Lo;0;L;;;;;N;;;;; -11D1E;MASARAM GONDI LETTER DHA;Lo;0;L;;;;;N;;;;; -11D1F;MASARAM GONDI LETTER NA;Lo;0;L;;;;;N;;;;; -11D20;MASARAM GONDI LETTER PA;Lo;0;L;;;;;N;;;;; -11D21;MASARAM GONDI LETTER PHA;Lo;0;L;;;;;N;;;;; -11D22;MASARAM GONDI LETTER BA;Lo;0;L;;;;;N;;;;; -11D23;MASARAM GONDI LETTER BHA;Lo;0;L;;;;;N;;;;; -11D24;MASARAM GONDI LETTER MA;Lo;0;L;;;;;N;;;;; -11D25;MASARAM GONDI LETTER YA;Lo;0;L;;;;;N;;;;; -11D26;MASARAM GONDI LETTER RA;Lo;0;L;;;;;N;;;;; -11D27;MASARAM GONDI LETTER LA;Lo;0;L;;;;;N;;;;; -11D28;MASARAM GONDI LETTER VA;Lo;0;L;;;;;N;;;;; -11D29;MASARAM GONDI LETTER SHA;Lo;0;L;;;;;N;;;;; -11D2A;MASARAM GONDI LETTER SSA;Lo;0;L;;;;;N;;;;; -11D2B;MASARAM GONDI LETTER SA;Lo;0;L;;;;;N;;;;; -11D2C;MASARAM GONDI LETTER HA;Lo;0;L;;;;;N;;;;; -11D2D;MASARAM GONDI LETTER LLA;Lo;0;L;;;;;N;;;;; -11D2E;MASARAM GONDI LETTER KSSA;Lo;0;L;;;;;N;;;;; -11D2F;MASARAM GONDI LETTER JNYA;Lo;0;L;;;;;N;;;;; -11D30;MASARAM GONDI LETTER TRA;Lo;0;L;;;;;N;;;;; -11D31;MASARAM GONDI VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; -11D32;MASARAM GONDI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -11D33;MASARAM GONDI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; -11D34;MASARAM GONDI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -11D35;MASARAM GONDI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -11D36;MASARAM GONDI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -11D3A;MASARAM GONDI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; -11D3C;MASARAM GONDI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -11D3D;MASARAM GONDI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; -11D3F;MASARAM GONDI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; -11D40;MASARAM GONDI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -11D41;MASARAM GONDI SIGN VISARGA;Mn;0;NSM;;;;;N;;;;; -11D42;MASARAM GONDI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; -11D43;MASARAM GONDI SIGN CANDRA;Mn;0;NSM;;;;;N;;;;; -11D44;MASARAM GONDI SIGN HALANTA;Mn;9;NSM;;;;;N;;;;; -11D45;MASARAM GONDI VIRAMA;Mn;9;NSM;;;;;N;;;;; -11D46;MASARAM GONDI REPHA;Lo;0;L;;;;;N;;;;; -11D47;MASARAM GONDI RA-KARA;Mn;0;NSM;;;;;N;;;;; -11D50;MASARAM GONDI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -11D51;MASARAM GONDI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -11D52;MASARAM GONDI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -11D53;MASARAM GONDI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -11D54;MASARAM GONDI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -11D55;MASARAM GONDI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -11D56;MASARAM GONDI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -11D57;MASARAM GONDI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -11D58;MASARAM GONDI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -11D59;MASARAM GONDI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -11D60;GUNJALA GONDI LETTER A;Lo;0;L;;;;;N;;;;; -11D61;GUNJALA GONDI LETTER AA;Lo;0;L;;;;;N;;;;; -11D62;GUNJALA GONDI LETTER I;Lo;0;L;;;;;N;;;;; -11D63;GUNJALA GONDI LETTER II;Lo;0;L;;;;;N;;;;; -11D64;GUNJALA GONDI LETTER U;Lo;0;L;;;;;N;;;;; -11D65;GUNJALA GONDI LETTER UU;Lo;0;L;;;;;N;;;;; -11D67;GUNJALA GONDI LETTER EE;Lo;0;L;;;;;N;;;;; -11D68;GUNJALA GONDI LETTER AI;Lo;0;L;;;;;N;;;;; -11D6A;GUNJALA GONDI LETTER OO;Lo;0;L;;;;;N;;;;; -11D6B;GUNJALA GONDI LETTER AU;Lo;0;L;;;;;N;;;;; -11D6C;GUNJALA GONDI LETTER YA;Lo;0;L;;;;;N;;;;; -11D6D;GUNJALA GONDI LETTER VA;Lo;0;L;;;;;N;;;;; -11D6E;GUNJALA GONDI LETTER BA;Lo;0;L;;;;;N;;;;; -11D6F;GUNJALA GONDI LETTER BHA;Lo;0;L;;;;;N;;;;; -11D70;GUNJALA GONDI LETTER MA;Lo;0;L;;;;;N;;;;; -11D71;GUNJALA GONDI LETTER KA;Lo;0;L;;;;;N;;;;; -11D72;GUNJALA GONDI LETTER KHA;Lo;0;L;;;;;N;;;;; -11D73;GUNJALA GONDI LETTER TA;Lo;0;L;;;;;N;;;;; -11D74;GUNJALA GONDI LETTER THA;Lo;0;L;;;;;N;;;;; -11D75;GUNJALA GONDI LETTER LA;Lo;0;L;;;;;N;;;;; -11D76;GUNJALA GONDI LETTER GA;Lo;0;L;;;;;N;;;;; -11D77;GUNJALA GONDI LETTER GHA;Lo;0;L;;;;;N;;;;; -11D78;GUNJALA GONDI LETTER DA;Lo;0;L;;;;;N;;;;; -11D79;GUNJALA GONDI LETTER DHA;Lo;0;L;;;;;N;;;;; -11D7A;GUNJALA GONDI LETTER NA;Lo;0;L;;;;;N;;;;; -11D7B;GUNJALA GONDI LETTER CA;Lo;0;L;;;;;N;;;;; -11D7C;GUNJALA GONDI LETTER CHA;Lo;0;L;;;;;N;;;;; -11D7D;GUNJALA GONDI LETTER TTA;Lo;0;L;;;;;N;;;;; -11D7E;GUNJALA GONDI LETTER TTHA;Lo;0;L;;;;;N;;;;; -11D7F;GUNJALA GONDI LETTER LLA;Lo;0;L;;;;;N;;;;; -11D80;GUNJALA GONDI LETTER JA;Lo;0;L;;;;;N;;;;; -11D81;GUNJALA GONDI LETTER JHA;Lo;0;L;;;;;N;;;;; -11D82;GUNJALA GONDI LETTER DDA;Lo;0;L;;;;;N;;;;; -11D83;GUNJALA GONDI LETTER DDHA;Lo;0;L;;;;;N;;;;; -11D84;GUNJALA GONDI LETTER NGA;Lo;0;L;;;;;N;;;;; -11D85;GUNJALA GONDI LETTER PA;Lo;0;L;;;;;N;;;;; -11D86;GUNJALA GONDI LETTER PHA;Lo;0;L;;;;;N;;;;; -11D87;GUNJALA GONDI LETTER HA;Lo;0;L;;;;;N;;;;; -11D88;GUNJALA GONDI LETTER RA;Lo;0;L;;;;;N;;;;; -11D89;GUNJALA GONDI LETTER SA;Lo;0;L;;;;;N;;;;; -11D8A;GUNJALA GONDI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -11D8B;GUNJALA GONDI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -11D8C;GUNJALA GONDI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -11D8D;GUNJALA GONDI VOWEL SIGN U;Mc;0;L;;;;;N;;;;; -11D8E;GUNJALA GONDI VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; -11D90;GUNJALA GONDI VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;; -11D91;GUNJALA GONDI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; -11D93;GUNJALA GONDI VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; -11D94;GUNJALA GONDI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; -11D95;GUNJALA GONDI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -11D96;GUNJALA GONDI SIGN VISARGA;Mc;0;L;;;;;N;;;;; -11D97;GUNJALA GONDI VIRAMA;Mn;9;NSM;;;;;N;;;;; -11D98;GUNJALA GONDI OM;Lo;0;L;;;;;N;;;;; -11DA0;GUNJALA GONDI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -11DA1;GUNJALA GONDI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -11DA2;GUNJALA GONDI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -11DA3;GUNJALA GONDI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -11DA4;GUNJALA GONDI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -11DA5;GUNJALA GONDI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -11DA6;GUNJALA GONDI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -11DA7;GUNJALA GONDI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -11DA8;GUNJALA GONDI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -11DA9;GUNJALA GONDI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -11EE0;MAKASAR LETTER KA;Lo;0;L;;;;;N;;;;; -11EE1;MAKASAR LETTER GA;Lo;0;L;;;;;N;;;;; -11EE2;MAKASAR LETTER NGA;Lo;0;L;;;;;N;;;;; -11EE3;MAKASAR LETTER PA;Lo;0;L;;;;;N;;;;; -11EE4;MAKASAR LETTER BA;Lo;0;L;;;;;N;;;;; -11EE5;MAKASAR LETTER MA;Lo;0;L;;;;;N;;;;; -11EE6;MAKASAR LETTER TA;Lo;0;L;;;;;N;;;;; -11EE7;MAKASAR LETTER DA;Lo;0;L;;;;;N;;;;; -11EE8;MAKASAR LETTER NA;Lo;0;L;;;;;N;;;;; -11EE9;MAKASAR LETTER CA;Lo;0;L;;;;;N;;;;; -11EEA;MAKASAR LETTER JA;Lo;0;L;;;;;N;;;;; -11EEB;MAKASAR LETTER NYA;Lo;0;L;;;;;N;;;;; -11EEC;MAKASAR LETTER YA;Lo;0;L;;;;;N;;;;; -11EED;MAKASAR LETTER RA;Lo;0;L;;;;;N;;;;; -11EEE;MAKASAR LETTER LA;Lo;0;L;;;;;N;;;;; -11EEF;MAKASAR LETTER VA;Lo;0;L;;;;;N;;;;; -11EF0;MAKASAR LETTER SA;Lo;0;L;;;;;N;;;;; -11EF1;MAKASAR LETTER A;Lo;0;L;;;;;N;;;;; -11EF2;MAKASAR ANGKA;Lo;0;L;;;;;N;;;;; -11EF3;MAKASAR VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -11EF4;MAKASAR VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -11EF5;MAKASAR VOWEL SIGN E;Mc;0;L;;;;;N;;;;; -11EF6;MAKASAR VOWEL SIGN O;Mc;0;L;;;;;N;;;;; -11EF7;MAKASAR PASSIMBANG;Po;0;L;;;;;N;;;;; -11EF8;MAKASAR END OF SECTION;Po;0;L;;;;;N;;;;; -11F00;KAWI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; -11F01;KAWI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; -11F02;KAWI SIGN REPHA;Lo;0;L;;;;;N;;;;; -11F03;KAWI SIGN VISARGA;Mc;0;L;;;;;N;;;;; -11F04;KAWI LETTER A;Lo;0;L;;;;;N;;;;; -11F05;KAWI LETTER AA;Lo;0;L;;;;;N;;;;; -11F06;KAWI LETTER I;Lo;0;L;;;;;N;;;;; -11F07;KAWI LETTER II;Lo;0;L;;;;;N;;;;; -11F08;KAWI LETTER U;Lo;0;L;;;;;N;;;;; -11F09;KAWI LETTER UU;Lo;0;L;;;;;N;;;;; -11F0A;KAWI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; -11F0B;KAWI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; -11F0C;KAWI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; -11F0D;KAWI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; -11F0E;KAWI LETTER E;Lo;0;L;;;;;N;;;;; -11F0F;KAWI LETTER AI;Lo;0;L;;;;;N;;;;; -11F10;KAWI LETTER O;Lo;0;L;;;;;N;;;;; -11F12;KAWI LETTER KA;Lo;0;L;;;;;N;;;;; -11F13;KAWI LETTER KHA;Lo;0;L;;;;;N;;;;; -11F14;KAWI LETTER GA;Lo;0;L;;;;;N;;;;; -11F15;KAWI LETTER GHA;Lo;0;L;;;;;N;;;;; -11F16;KAWI LETTER NGA;Lo;0;L;;;;;N;;;;; -11F17;KAWI LETTER CA;Lo;0;L;;;;;N;;;;; -11F18;KAWI LETTER CHA;Lo;0;L;;;;;N;;;;; -11F19;KAWI LETTER JA;Lo;0;L;;;;;N;;;;; -11F1A;KAWI LETTER JHA;Lo;0;L;;;;;N;;;;; -11F1B;KAWI LETTER NYA;Lo;0;L;;;;;N;;;;; -11F1C;KAWI LETTER TTA;Lo;0;L;;;;;N;;;;; -11F1D;KAWI LETTER TTHA;Lo;0;L;;;;;N;;;;; -11F1E;KAWI LETTER DDA;Lo;0;L;;;;;N;;;;; -11F1F;KAWI LETTER DDHA;Lo;0;L;;;;;N;;;;; -11F20;KAWI LETTER NNA;Lo;0;L;;;;;N;;;;; -11F21;KAWI LETTER TA;Lo;0;L;;;;;N;;;;; -11F22;KAWI LETTER THA;Lo;0;L;;;;;N;;;;; -11F23;KAWI LETTER DA;Lo;0;L;;;;;N;;;;; -11F24;KAWI LETTER DHA;Lo;0;L;;;;;N;;;;; -11F25;KAWI LETTER NA;Lo;0;L;;;;;N;;;;; -11F26;KAWI LETTER PA;Lo;0;L;;;;;N;;;;; -11F27;KAWI LETTER PHA;Lo;0;L;;;;;N;;;;; -11F28;KAWI LETTER BA;Lo;0;L;;;;;N;;;;; -11F29;KAWI LETTER BHA;Lo;0;L;;;;;N;;;;; -11F2A;KAWI LETTER MA;Lo;0;L;;;;;N;;;;; -11F2B;KAWI LETTER YA;Lo;0;L;;;;;N;;;;; -11F2C;KAWI LETTER RA;Lo;0;L;;;;;N;;;;; -11F2D;KAWI LETTER LA;Lo;0;L;;;;;N;;;;; -11F2E;KAWI LETTER WA;Lo;0;L;;;;;N;;;;; -11F2F;KAWI LETTER SHA;Lo;0;L;;;;;N;;;;; -11F30;KAWI LETTER SSA;Lo;0;L;;;;;N;;;;; -11F31;KAWI LETTER SA;Lo;0;L;;;;;N;;;;; -11F32;KAWI LETTER HA;Lo;0;L;;;;;N;;;;; -11F33;KAWI LETTER JNYA;Lo;0;L;;;;;N;;;;; -11F34;KAWI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -11F35;KAWI VOWEL SIGN ALTERNATE AA;Mc;0;L;;;;;N;;;;; -11F36;KAWI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; -11F37;KAWI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; -11F38;KAWI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -11F39;KAWI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; -11F3A;KAWI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; -11F3E;KAWI VOWEL SIGN E;Mc;0;L;;;;;N;;;;; -11F3F;KAWI VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; -11F40;KAWI VOWEL SIGN EU;Mn;0;NSM;;;;;N;;;;; -11F41;KAWI SIGN KILLER;Mc;9;L;;;;;N;;;;; -11F42;KAWI CONJOINER;Mn;9;NSM;;;;;N;;;;; -11F43;KAWI DANDA;Po;0;L;;;;;N;;;;; -11F44;KAWI DOUBLE DANDA;Po;0;L;;;;;N;;;;; -11F45;KAWI PUNCTUATION SECTION MARKER;Po;0;L;;;;;N;;;;; -11F46;KAWI PUNCTUATION ALTERNATE SECTION MARKER;Po;0;L;;;;;N;;;;; -11F47;KAWI PUNCTUATION FLOWER;Po;0;L;;;;;N;;;;; -11F48;KAWI PUNCTUATION SPACE FILLER;Po;0;L;;;;;N;;;;; -11F49;KAWI PUNCTUATION DOT;Po;0;L;;;;;N;;;;; -11F4A;KAWI PUNCTUATION DOUBLE DOT;Po;0;L;;;;;N;;;;; -11F4B;KAWI PUNCTUATION TRIPLE DOT;Po;0;L;;;;;N;;;;; -11F4C;KAWI PUNCTUATION CIRCLE;Po;0;L;;;;;N;;;;; -11F4D;KAWI PUNCTUATION FILLED CIRCLE;Po;0;L;;;;;N;;;;; -11F4E;KAWI PUNCTUATION SPIRAL;Po;0;L;;;;;N;;;;; -11F4F;KAWI PUNCTUATION CLOSING SPIRAL;Po;0;L;;;;;N;;;;; -11F50;KAWI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -11F51;KAWI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -11F52;KAWI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -11F53;KAWI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -11F54;KAWI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -11F55;KAWI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -11F56;KAWI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -11F57;KAWI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -11F58;KAWI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -11F59;KAWI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -11FB0;LISU LETTER YHA;Lo;0;L;;;;;N;;;;; -11FC0;TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH;No;0;L;;;;1/320;N;;;;; -11FC1;TAMIL FRACTION ONE ONE-HUNDRED-AND-SIXTIETH;No;0;L;;;;1/160;N;;;;; -11FC2;TAMIL FRACTION ONE EIGHTIETH;No;0;L;;;;1/80;N;;;;; -11FC3;TAMIL FRACTION ONE SIXTY-FOURTH;No;0;L;;;;1/64;N;;;;; -11FC4;TAMIL FRACTION ONE FORTIETH;No;0;L;;;;1/40;N;;;;; -11FC5;TAMIL FRACTION ONE THIRTY-SECOND;No;0;L;;;;1/32;N;;;;; -11FC6;TAMIL FRACTION THREE EIGHTIETHS;No;0;L;;;;3/80;N;;;;; -11FC7;TAMIL FRACTION THREE SIXTY-FOURTHS;No;0;L;;;;3/64;N;;;;; -11FC8;TAMIL FRACTION ONE TWENTIETH;No;0;L;;;;1/20;N;;;;; -11FC9;TAMIL FRACTION ONE SIXTEENTH-1;No;0;L;;;;1/16;N;;;;; -11FCA;TAMIL FRACTION ONE SIXTEENTH-2;No;0;L;;;;1/16;N;;;;; -11FCB;TAMIL FRACTION ONE TENTH;No;0;L;;;;1/10;N;;;;; -11FCC;TAMIL FRACTION ONE EIGHTH;No;0;L;;;;1/8;N;;;;; -11FCD;TAMIL FRACTION THREE TWENTIETHS;No;0;L;;;;3/20;N;;;;; -11FCE;TAMIL FRACTION THREE SIXTEENTHS;No;0;L;;;;3/16;N;;;;; -11FCF;TAMIL FRACTION ONE FIFTH;No;0;L;;;;1/5;N;;;;; -11FD0;TAMIL FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;; -11FD1;TAMIL FRACTION ONE HALF-1;No;0;L;;;;1/2;N;;;;; -11FD2;TAMIL FRACTION ONE HALF-2;No;0;L;;;;1/2;N;;;;; -11FD3;TAMIL FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;; -11FD4;TAMIL FRACTION DOWNSCALING FACTOR KIIZH;No;0;L;;;;1/320;N;;;;; -11FD5;TAMIL SIGN NEL;So;0;ON;;;;;N;;;;; -11FD6;TAMIL SIGN CEVITU;So;0;ON;;;;;N;;;;; -11FD7;TAMIL SIGN AAZHAAKKU;So;0;ON;;;;;N;;;;; -11FD8;TAMIL SIGN UZHAKKU;So;0;ON;;;;;N;;;;; -11FD9;TAMIL SIGN MUUVUZHAKKU;So;0;ON;;;;;N;;;;; -11FDA;TAMIL SIGN KURUNI;So;0;ON;;;;;N;;;;; -11FDB;TAMIL SIGN PATHAKKU;So;0;ON;;;;;N;;;;; -11FDC;TAMIL SIGN MUKKURUNI;So;0;ON;;;;;N;;;;; -11FDD;TAMIL SIGN KAACU;Sc;0;ET;;;;;N;;;;; -11FDE;TAMIL SIGN PANAM;Sc;0;ET;;;;;N;;;;; -11FDF;TAMIL SIGN PON;Sc;0;ET;;;;;N;;;;; -11FE0;TAMIL SIGN VARAAKAN;Sc;0;ET;;;;;N;;;;; -11FE1;TAMIL SIGN PAARAM;So;0;ON;;;;;N;;;;; -11FE2;TAMIL SIGN KUZHI;So;0;ON;;;;;N;;;;; -11FE3;TAMIL SIGN VELI;So;0;ON;;;;;N;;;;; -11FE4;TAMIL WET CULTIVATION SIGN;So;0;ON;;;;;N;;;;; -11FE5;TAMIL DRY CULTIVATION SIGN;So;0;ON;;;;;N;;;;; -11FE6;TAMIL LAND SIGN;So;0;ON;;;;;N;;;;; -11FE7;TAMIL SALT PAN SIGN;So;0;ON;;;;;N;;;;; -11FE8;TAMIL TRADITIONAL CREDIT SIGN;So;0;ON;;;;;N;;;;; -11FE9;TAMIL TRADITIONAL NUMBER SIGN;So;0;ON;;;;;N;;;;; -11FEA;TAMIL CURRENT SIGN;So;0;ON;;;;;N;;;;; -11FEB;TAMIL AND ODD SIGN;So;0;ON;;;;;N;;;;; -11FEC;TAMIL SPENT SIGN;So;0;ON;;;;;N;;;;; -11FED;TAMIL TOTAL SIGN;So;0;ON;;;;;N;;;;; -11FEE;TAMIL IN POSSESSION SIGN;So;0;ON;;;;;N;;;;; -11FEF;TAMIL STARTING FROM SIGN;So;0;ON;;;;;N;;;;; -11FF0;TAMIL SIGN MUTHALIYA;So;0;ON;;;;;N;;;;; -11FF1;TAMIL SIGN VAKAIYARAA;So;0;ON;;;;;N;;;;; -11FFF;TAMIL PUNCTUATION END OF TEXT;Po;0;L;;;;;N;;;;; -12000;CUNEIFORM SIGN A;Lo;0;L;;;;;N;;;;; -12001;CUNEIFORM SIGN A TIMES A;Lo;0;L;;;;;N;;;;; -12002;CUNEIFORM SIGN A TIMES BAD;Lo;0;L;;;;;N;;;;; -12003;CUNEIFORM SIGN A TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; -12004;CUNEIFORM SIGN A TIMES HA;Lo;0;L;;;;;N;;;;; -12005;CUNEIFORM SIGN A TIMES IGI;Lo;0;L;;;;;N;;;;; -12006;CUNEIFORM SIGN A TIMES LAGAR GUNU;Lo;0;L;;;;;N;;;;; -12007;CUNEIFORM SIGN A TIMES MUSH;Lo;0;L;;;;;N;;;;; -12008;CUNEIFORM SIGN A TIMES SAG;Lo;0;L;;;;;N;;;;; -12009;CUNEIFORM SIGN A2;Lo;0;L;;;;;N;;;;; -1200A;CUNEIFORM SIGN AB;Lo;0;L;;;;;N;;;;; -1200B;CUNEIFORM SIGN AB TIMES ASH2;Lo;0;L;;;;;N;;;;; -1200C;CUNEIFORM SIGN AB TIMES DUN3 GUNU;Lo;0;L;;;;;N;;;;; -1200D;CUNEIFORM SIGN AB TIMES GAL;Lo;0;L;;;;;N;;;;; -1200E;CUNEIFORM SIGN AB TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; -1200F;CUNEIFORM SIGN AB TIMES HA;Lo;0;L;;;;;N;;;;; -12010;CUNEIFORM SIGN AB TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; -12011;CUNEIFORM SIGN AB TIMES IMIN;Lo;0;L;;;;;N;;;;; -12012;CUNEIFORM SIGN AB TIMES LAGAB;Lo;0;L;;;;;N;;;;; -12013;CUNEIFORM SIGN AB TIMES SHESH;Lo;0;L;;;;;N;;;;; -12014;CUNEIFORM SIGN AB TIMES U PLUS U PLUS U;Lo;0;L;;;;;N;;;;; -12015;CUNEIFORM SIGN AB GUNU;Lo;0;L;;;;;N;;;;; -12016;CUNEIFORM SIGN AB2;Lo;0;L;;;;;N;;;;; -12017;CUNEIFORM SIGN AB2 TIMES BALAG;Lo;0;L;;;;;N;;;;; -12018;CUNEIFORM SIGN AB2 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; -12019;CUNEIFORM SIGN AB2 TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;; -1201A;CUNEIFORM SIGN AB2 TIMES SHA3;Lo;0;L;;;;;N;;;;; -1201B;CUNEIFORM SIGN AB2 TIMES TAK4;Lo;0;L;;;;;N;;;;; -1201C;CUNEIFORM SIGN AD;Lo;0;L;;;;;N;;;;; -1201D;CUNEIFORM SIGN AK;Lo;0;L;;;;;N;;;;; -1201E;CUNEIFORM SIGN AK TIMES ERIN2;Lo;0;L;;;;;N;;;;; -1201F;CUNEIFORM SIGN AK TIMES SHITA PLUS GISH;Lo;0;L;;;;;N;;;;; -12020;CUNEIFORM SIGN AL;Lo;0;L;;;;;N;;;;; -12021;CUNEIFORM SIGN AL TIMES AL;Lo;0;L;;;;;N;;;;; -12022;CUNEIFORM SIGN AL TIMES DIM2;Lo;0;L;;;;;N;;;;; -12023;CUNEIFORM SIGN AL TIMES GISH;Lo;0;L;;;;;N;;;;; -12024;CUNEIFORM SIGN AL TIMES HA;Lo;0;L;;;;;N;;;;; -12025;CUNEIFORM SIGN AL TIMES KAD3;Lo;0;L;;;;;N;;;;; -12026;CUNEIFORM SIGN AL TIMES KI;Lo;0;L;;;;;N;;;;; -12027;CUNEIFORM SIGN AL TIMES SHE;Lo;0;L;;;;;N;;;;; -12028;CUNEIFORM SIGN AL TIMES USH;Lo;0;L;;;;;N;;;;; -12029;CUNEIFORM SIGN ALAN;Lo;0;L;;;;;N;;;;; -1202A;CUNEIFORM SIGN ALEPH;Lo;0;L;;;;;N;;;;; -1202B;CUNEIFORM SIGN AMAR;Lo;0;L;;;;;N;;;;; -1202C;CUNEIFORM SIGN AMAR TIMES SHE;Lo;0;L;;;;;N;;;;; -1202D;CUNEIFORM SIGN AN;Lo;0;L;;;;;N;;;;; -1202E;CUNEIFORM SIGN AN OVER AN;Lo;0;L;;;;;N;;;;; -1202F;CUNEIFORM SIGN AN THREE TIMES;Lo;0;L;;;;;N;;;;; -12030;CUNEIFORM SIGN AN PLUS NAGA OPPOSING AN PLUS NAGA;Lo;0;L;;;;;N;;;;; -12031;CUNEIFORM SIGN AN PLUS NAGA SQUARED;Lo;0;L;;;;;N;;;;; -12032;CUNEIFORM SIGN ANSHE;Lo;0;L;;;;;N;;;;; -12033;CUNEIFORM SIGN APIN;Lo;0;L;;;;;N;;;;; -12034;CUNEIFORM SIGN ARAD;Lo;0;L;;;;;N;;;;; -12035;CUNEIFORM SIGN ARAD TIMES KUR;Lo;0;L;;;;;N;;;;; -12036;CUNEIFORM SIGN ARKAB;Lo;0;L;;;;;N;;;;; -12037;CUNEIFORM SIGN ASAL2;Lo;0;L;;;;;N;;;;; -12038;CUNEIFORM SIGN ASH;Lo;0;L;;;;;N;;;;; -12039;CUNEIFORM SIGN ASH ZIDA TENU;Lo;0;L;;;;;N;;;;; -1203A;CUNEIFORM SIGN ASH KABA TENU;Lo;0;L;;;;;N;;;;; -1203B;CUNEIFORM SIGN ASH OVER ASH TUG2 OVER TUG2 TUG2 OVER TUG2 PAP;Lo;0;L;;;;;N;;;;; -1203C;CUNEIFORM SIGN ASH OVER ASH OVER ASH;Lo;0;L;;;;;N;;;;; -1203D;CUNEIFORM SIGN ASH OVER ASH OVER ASH CROSSING ASH OVER ASH OVER ASH;Lo;0;L;;;;;N;;;;; -1203E;CUNEIFORM SIGN ASH2;Lo;0;L;;;;;N;;;;; -1203F;CUNEIFORM SIGN ASHGAB;Lo;0;L;;;;;N;;;;; -12040;CUNEIFORM SIGN BA;Lo;0;L;;;;;N;;;;; -12041;CUNEIFORM SIGN BAD;Lo;0;L;;;;;N;;;;; -12042;CUNEIFORM SIGN BAG3;Lo;0;L;;;;;N;;;;; -12043;CUNEIFORM SIGN BAHAR2;Lo;0;L;;;;;N;;;;; -12044;CUNEIFORM SIGN BAL;Lo;0;L;;;;;N;;;;; -12045;CUNEIFORM SIGN BAL OVER BAL;Lo;0;L;;;;;N;;;;; -12046;CUNEIFORM SIGN BALAG;Lo;0;L;;;;;N;;;;; -12047;CUNEIFORM SIGN BAR;Lo;0;L;;;;;N;;;;; -12048;CUNEIFORM SIGN BARA2;Lo;0;L;;;;;N;;;;; -12049;CUNEIFORM SIGN BI;Lo;0;L;;;;;N;;;;; -1204A;CUNEIFORM SIGN BI TIMES A;Lo;0;L;;;;;N;;;;; -1204B;CUNEIFORM SIGN BI TIMES GAR;Lo;0;L;;;;;N;;;;; -1204C;CUNEIFORM SIGN BI TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; -1204D;CUNEIFORM SIGN BU;Lo;0;L;;;;;N;;;;; -1204E;CUNEIFORM SIGN BU OVER BU AB;Lo;0;L;;;;;N;;;;; -1204F;CUNEIFORM SIGN BU OVER BU UN;Lo;0;L;;;;;N;;;;; -12050;CUNEIFORM SIGN BU CROSSING BU;Lo;0;L;;;;;N;;;;; -12051;CUNEIFORM SIGN BULUG;Lo;0;L;;;;;N;;;;; -12052;CUNEIFORM SIGN BULUG OVER BULUG;Lo;0;L;;;;;N;;;;; -12053;CUNEIFORM SIGN BUR;Lo;0;L;;;;;N;;;;; -12054;CUNEIFORM SIGN BUR2;Lo;0;L;;;;;N;;;;; -12055;CUNEIFORM SIGN DA;Lo;0;L;;;;;N;;;;; -12056;CUNEIFORM SIGN DAG;Lo;0;L;;;;;N;;;;; -12057;CUNEIFORM SIGN DAG KISIM5 TIMES A PLUS MASH;Lo;0;L;;;;;N;;;;; -12058;CUNEIFORM SIGN DAG KISIM5 TIMES AMAR;Lo;0;L;;;;;N;;;;; -12059;CUNEIFORM SIGN DAG KISIM5 TIMES BALAG;Lo;0;L;;;;;N;;;;; -1205A;CUNEIFORM SIGN DAG KISIM5 TIMES BI;Lo;0;L;;;;;N;;;;; -1205B;CUNEIFORM SIGN DAG KISIM5 TIMES GA;Lo;0;L;;;;;N;;;;; -1205C;CUNEIFORM SIGN DAG KISIM5 TIMES GA PLUS MASH;Lo;0;L;;;;;N;;;;; -1205D;CUNEIFORM SIGN DAG KISIM5 TIMES GI;Lo;0;L;;;;;N;;;;; -1205E;CUNEIFORM SIGN DAG KISIM5 TIMES GIR2;Lo;0;L;;;;;N;;;;; -1205F;CUNEIFORM SIGN DAG KISIM5 TIMES GUD;Lo;0;L;;;;;N;;;;; -12060;CUNEIFORM SIGN DAG KISIM5 TIMES HA;Lo;0;L;;;;;N;;;;; -12061;CUNEIFORM SIGN DAG KISIM5 TIMES IR;Lo;0;L;;;;;N;;;;; -12062;CUNEIFORM SIGN DAG KISIM5 TIMES IR PLUS LU;Lo;0;L;;;;;N;;;;; -12063;CUNEIFORM SIGN DAG KISIM5 TIMES KAK;Lo;0;L;;;;;N;;;;; -12064;CUNEIFORM SIGN DAG KISIM5 TIMES LA;Lo;0;L;;;;;N;;;;; -12065;CUNEIFORM SIGN DAG KISIM5 TIMES LU;Lo;0;L;;;;;N;;;;; -12066;CUNEIFORM SIGN DAG KISIM5 TIMES LU PLUS MASH2;Lo;0;L;;;;;N;;;;; -12067;CUNEIFORM SIGN DAG KISIM5 TIMES LUM;Lo;0;L;;;;;N;;;;; -12068;CUNEIFORM SIGN DAG KISIM5 TIMES NE;Lo;0;L;;;;;N;;;;; -12069;CUNEIFORM SIGN DAG KISIM5 TIMES PAP PLUS PAP;Lo;0;L;;;;;N;;;;; -1206A;CUNEIFORM SIGN DAG KISIM5 TIMES SI;Lo;0;L;;;;;N;;;;; -1206B;CUNEIFORM SIGN DAG KISIM5 TIMES TAK4;Lo;0;L;;;;;N;;;;; -1206C;CUNEIFORM SIGN DAG KISIM5 TIMES U2 PLUS GIR2;Lo;0;L;;;;;N;;;;; -1206D;CUNEIFORM SIGN DAG KISIM5 TIMES USH;Lo;0;L;;;;;N;;;;; -1206E;CUNEIFORM SIGN DAM;Lo;0;L;;;;;N;;;;; -1206F;CUNEIFORM SIGN DAR;Lo;0;L;;;;;N;;;;; -12070;CUNEIFORM SIGN DARA3;Lo;0;L;;;;;N;;;;; -12071;CUNEIFORM SIGN DARA4;Lo;0;L;;;;;N;;;;; -12072;CUNEIFORM SIGN DI;Lo;0;L;;;;;N;;;;; -12073;CUNEIFORM SIGN DIB;Lo;0;L;;;;;N;;;;; -12074;CUNEIFORM SIGN DIM;Lo;0;L;;;;;N;;;;; -12075;CUNEIFORM SIGN DIM TIMES SHE;Lo;0;L;;;;;N;;;;; -12076;CUNEIFORM SIGN DIM2;Lo;0;L;;;;;N;;;;; -12077;CUNEIFORM SIGN DIN;Lo;0;L;;;;;N;;;;; -12078;CUNEIFORM SIGN DIN KASKAL U GUNU DISH;Lo;0;L;;;;;N;;;;; -12079;CUNEIFORM SIGN DISH;Lo;0;L;;;;;N;;;;; -1207A;CUNEIFORM SIGN DU;Lo;0;L;;;;;N;;;;; -1207B;CUNEIFORM SIGN DU OVER DU;Lo;0;L;;;;;N;;;;; -1207C;CUNEIFORM SIGN DU GUNU;Lo;0;L;;;;;N;;;;; -1207D;CUNEIFORM SIGN DU SHESHIG;Lo;0;L;;;;;N;;;;; -1207E;CUNEIFORM SIGN DUB;Lo;0;L;;;;;N;;;;; -1207F;CUNEIFORM SIGN DUB TIMES ESH2;Lo;0;L;;;;;N;;;;; -12080;CUNEIFORM SIGN DUB2;Lo;0;L;;;;;N;;;;; -12081;CUNEIFORM SIGN DUG;Lo;0;L;;;;;N;;;;; -12082;CUNEIFORM SIGN DUGUD;Lo;0;L;;;;;N;;;;; -12083;CUNEIFORM SIGN DUH;Lo;0;L;;;;;N;;;;; -12084;CUNEIFORM SIGN DUN;Lo;0;L;;;;;N;;;;; -12085;CUNEIFORM SIGN DUN3;Lo;0;L;;;;;N;;;;; -12086;CUNEIFORM SIGN DUN3 GUNU;Lo;0;L;;;;;N;;;;; -12087;CUNEIFORM SIGN DUN3 GUNU GUNU;Lo;0;L;;;;;N;;;;; -12088;CUNEIFORM SIGN DUN4;Lo;0;L;;;;;N;;;;; -12089;CUNEIFORM SIGN DUR2;Lo;0;L;;;;;N;;;;; -1208A;CUNEIFORM SIGN E;Lo;0;L;;;;;N;;;;; -1208B;CUNEIFORM SIGN E TIMES PAP;Lo;0;L;;;;;N;;;;; -1208C;CUNEIFORM SIGN E OVER E NUN OVER NUN;Lo;0;L;;;;;N;;;;; -1208D;CUNEIFORM SIGN E2;Lo;0;L;;;;;N;;;;; -1208E;CUNEIFORM SIGN E2 TIMES A PLUS HA PLUS DA;Lo;0;L;;;;;N;;;;; -1208F;CUNEIFORM SIGN E2 TIMES GAR;Lo;0;L;;;;;N;;;;; -12090;CUNEIFORM SIGN E2 TIMES MI;Lo;0;L;;;;;N;;;;; -12091;CUNEIFORM SIGN E2 TIMES SAL;Lo;0;L;;;;;N;;;;; -12092;CUNEIFORM SIGN E2 TIMES SHE;Lo;0;L;;;;;N;;;;; -12093;CUNEIFORM SIGN E2 TIMES U;Lo;0;L;;;;;N;;;;; -12094;CUNEIFORM SIGN EDIN;Lo;0;L;;;;;N;;;;; -12095;CUNEIFORM SIGN EGIR;Lo;0;L;;;;;N;;;;; -12096;CUNEIFORM SIGN EL;Lo;0;L;;;;;N;;;;; -12097;CUNEIFORM SIGN EN;Lo;0;L;;;;;N;;;;; -12098;CUNEIFORM SIGN EN TIMES GAN2;Lo;0;L;;;;;N;;;;; -12099;CUNEIFORM SIGN EN TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; -1209A;CUNEIFORM SIGN EN TIMES ME;Lo;0;L;;;;;N;;;;; -1209B;CUNEIFORM SIGN EN CROSSING EN;Lo;0;L;;;;;N;;;;; -1209C;CUNEIFORM SIGN EN OPPOSING EN;Lo;0;L;;;;;N;;;;; -1209D;CUNEIFORM SIGN EN SQUARED;Lo;0;L;;;;;N;;;;; -1209E;CUNEIFORM SIGN EREN;Lo;0;L;;;;;N;;;;; -1209F;CUNEIFORM SIGN ERIN2;Lo;0;L;;;;;N;;;;; -120A0;CUNEIFORM SIGN ESH2;Lo;0;L;;;;;N;;;;; -120A1;CUNEIFORM SIGN EZEN;Lo;0;L;;;;;N;;;;; -120A2;CUNEIFORM SIGN EZEN TIMES A;Lo;0;L;;;;;N;;;;; -120A3;CUNEIFORM SIGN EZEN TIMES A PLUS LAL;Lo;0;L;;;;;N;;;;; -120A4;CUNEIFORM SIGN EZEN TIMES A PLUS LAL TIMES LAL;Lo;0;L;;;;;N;;;;; -120A5;CUNEIFORM SIGN EZEN TIMES AN;Lo;0;L;;;;;N;;;;; -120A6;CUNEIFORM SIGN EZEN TIMES BAD;Lo;0;L;;;;;N;;;;; -120A7;CUNEIFORM SIGN EZEN TIMES DUN3 GUNU;Lo;0;L;;;;;N;;;;; -120A8;CUNEIFORM SIGN EZEN TIMES DUN3 GUNU GUNU;Lo;0;L;;;;;N;;;;; -120A9;CUNEIFORM SIGN EZEN TIMES HA;Lo;0;L;;;;;N;;;;; -120AA;CUNEIFORM SIGN EZEN TIMES HA GUNU;Lo;0;L;;;;;N;;;;; -120AB;CUNEIFORM SIGN EZEN TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; -120AC;CUNEIFORM SIGN EZEN TIMES KASKAL;Lo;0;L;;;;;N;;;;; -120AD;CUNEIFORM SIGN EZEN TIMES KASKAL SQUARED;Lo;0;L;;;;;N;;;;; -120AE;CUNEIFORM SIGN EZEN TIMES KU3;Lo;0;L;;;;;N;;;;; -120AF;CUNEIFORM SIGN EZEN TIMES LA;Lo;0;L;;;;;N;;;;; -120B0;CUNEIFORM SIGN EZEN TIMES LAL TIMES LAL;Lo;0;L;;;;;N;;;;; -120B1;CUNEIFORM SIGN EZEN TIMES LI;Lo;0;L;;;;;N;;;;; -120B2;CUNEIFORM SIGN EZEN TIMES LU;Lo;0;L;;;;;N;;;;; -120B3;CUNEIFORM SIGN EZEN TIMES U2;Lo;0;L;;;;;N;;;;; -120B4;CUNEIFORM SIGN EZEN TIMES UD;Lo;0;L;;;;;N;;;;; -120B5;CUNEIFORM SIGN GA;Lo;0;L;;;;;N;;;;; -120B6;CUNEIFORM SIGN GA GUNU;Lo;0;L;;;;;N;;;;; -120B7;CUNEIFORM SIGN GA2;Lo;0;L;;;;;N;;;;; -120B8;CUNEIFORM SIGN GA2 TIMES A PLUS DA PLUS HA;Lo;0;L;;;;;N;;;;; -120B9;CUNEIFORM SIGN GA2 TIMES A PLUS HA;Lo;0;L;;;;;N;;;;; -120BA;CUNEIFORM SIGN GA2 TIMES A PLUS IGI;Lo;0;L;;;;;N;;;;; -120BB;CUNEIFORM SIGN GA2 TIMES AB2 TENU PLUS TAB;Lo;0;L;;;;;N;;;;; -120BC;CUNEIFORM SIGN GA2 TIMES AN;Lo;0;L;;;;;N;;;;; -120BD;CUNEIFORM SIGN GA2 TIMES ASH;Lo;0;L;;;;;N;;;;; -120BE;CUNEIFORM SIGN GA2 TIMES ASH2 PLUS GAL;Lo;0;L;;;;;N;;;;; -120BF;CUNEIFORM SIGN GA2 TIMES BAD;Lo;0;L;;;;;N;;;;; -120C0;CUNEIFORM SIGN GA2 TIMES BAR PLUS RA;Lo;0;L;;;;;N;;;;; -120C1;CUNEIFORM SIGN GA2 TIMES BUR;Lo;0;L;;;;;N;;;;; -120C2;CUNEIFORM SIGN GA2 TIMES BUR PLUS RA;Lo;0;L;;;;;N;;;;; -120C3;CUNEIFORM SIGN GA2 TIMES DA;Lo;0;L;;;;;N;;;;; -120C4;CUNEIFORM SIGN GA2 TIMES DI;Lo;0;L;;;;;N;;;;; -120C5;CUNEIFORM SIGN GA2 TIMES DIM TIMES SHE;Lo;0;L;;;;;N;;;;; -120C6;CUNEIFORM SIGN GA2 TIMES DUB;Lo;0;L;;;;;N;;;;; -120C7;CUNEIFORM SIGN GA2 TIMES EL;Lo;0;L;;;;;N;;;;; -120C8;CUNEIFORM SIGN GA2 TIMES EL PLUS LA;Lo;0;L;;;;;N;;;;; -120C9;CUNEIFORM SIGN GA2 TIMES EN;Lo;0;L;;;;;N;;;;; -120CA;CUNEIFORM SIGN GA2 TIMES EN TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; -120CB;CUNEIFORM SIGN GA2 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; -120CC;CUNEIFORM SIGN GA2 TIMES GAR;Lo;0;L;;;;;N;;;;; -120CD;CUNEIFORM SIGN GA2 TIMES GI;Lo;0;L;;;;;N;;;;; -120CE;CUNEIFORM SIGN GA2 TIMES GI4;Lo;0;L;;;;;N;;;;; -120CF;CUNEIFORM SIGN GA2 TIMES GI4 PLUS A;Lo;0;L;;;;;N;;;;; -120D0;CUNEIFORM SIGN GA2 TIMES GIR2 PLUS SU;Lo;0;L;;;;;N;;;;; -120D1;CUNEIFORM SIGN GA2 TIMES HA PLUS LU PLUS ESH2;Lo;0;L;;;;;N;;;;; -120D2;CUNEIFORM SIGN GA2 TIMES HAL;Lo;0;L;;;;;N;;;;; -120D3;CUNEIFORM SIGN GA2 TIMES HAL PLUS LA;Lo;0;L;;;;;N;;;;; -120D4;CUNEIFORM SIGN GA2 TIMES HI PLUS LI;Lo;0;L;;;;;N;;;;; -120D5;CUNEIFORM SIGN GA2 TIMES HUB2;Lo;0;L;;;;;N;;;;; -120D6;CUNEIFORM SIGN GA2 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; -120D7;CUNEIFORM SIGN GA2 TIMES ISH PLUS HU PLUS ASH;Lo;0;L;;;;;N;;;;; -120D8;CUNEIFORM SIGN GA2 TIMES KAK;Lo;0;L;;;;;N;;;;; -120D9;CUNEIFORM SIGN GA2 TIMES KASKAL;Lo;0;L;;;;;N;;;;; -120DA;CUNEIFORM SIGN GA2 TIMES KID;Lo;0;L;;;;;N;;;;; -120DB;CUNEIFORM SIGN GA2 TIMES KID PLUS LAL;Lo;0;L;;;;;N;;;;; -120DC;CUNEIFORM SIGN GA2 TIMES KU3 PLUS AN;Lo;0;L;;;;;N;;;;; -120DD;CUNEIFORM SIGN GA2 TIMES LA;Lo;0;L;;;;;N;;;;; -120DE;CUNEIFORM SIGN GA2 TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;; -120DF;CUNEIFORM SIGN GA2 TIMES MI;Lo;0;L;;;;;N;;;;; -120E0;CUNEIFORM SIGN GA2 TIMES NUN;Lo;0;L;;;;;N;;;;; -120E1;CUNEIFORM SIGN GA2 TIMES NUN OVER NUN;Lo;0;L;;;;;N;;;;; -120E2;CUNEIFORM SIGN GA2 TIMES PA;Lo;0;L;;;;;N;;;;; -120E3;CUNEIFORM SIGN GA2 TIMES SAL;Lo;0;L;;;;;N;;;;; -120E4;CUNEIFORM SIGN GA2 TIMES SAR;Lo;0;L;;;;;N;;;;; -120E5;CUNEIFORM SIGN GA2 TIMES SHE;Lo;0;L;;;;;N;;;;; -120E6;CUNEIFORM SIGN GA2 TIMES SHE PLUS TUR;Lo;0;L;;;;;N;;;;; -120E7;CUNEIFORM SIGN GA2 TIMES SHID;Lo;0;L;;;;;N;;;;; -120E8;CUNEIFORM SIGN GA2 TIMES SUM;Lo;0;L;;;;;N;;;;; -120E9;CUNEIFORM SIGN GA2 TIMES TAK4;Lo;0;L;;;;;N;;;;; -120EA;CUNEIFORM SIGN GA2 TIMES U;Lo;0;L;;;;;N;;;;; -120EB;CUNEIFORM SIGN GA2 TIMES UD;Lo;0;L;;;;;N;;;;; -120EC;CUNEIFORM SIGN GA2 TIMES UD PLUS DU;Lo;0;L;;;;;N;;;;; -120ED;CUNEIFORM SIGN GA2 OVER GA2;Lo;0;L;;;;;N;;;;; -120EE;CUNEIFORM SIGN GABA;Lo;0;L;;;;;N;;;;; -120EF;CUNEIFORM SIGN GABA CROSSING GABA;Lo;0;L;;;;;N;;;;; -120F0;CUNEIFORM SIGN GAD;Lo;0;L;;;;;N;;;;; -120F1;CUNEIFORM SIGN GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;; -120F2;CUNEIFORM SIGN GAL;Lo;0;L;;;;;N;;;;; -120F3;CUNEIFORM SIGN GAL GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;; -120F4;CUNEIFORM SIGN GALAM;Lo;0;L;;;;;N;;;;; -120F5;CUNEIFORM SIGN GAM;Lo;0;L;;;;;N;;;;; -120F6;CUNEIFORM SIGN GAN;Lo;0;L;;;;;N;;;;; -120F7;CUNEIFORM SIGN GAN2;Lo;0;L;;;;;N;;;;; -120F8;CUNEIFORM SIGN GAN2 TENU;Lo;0;L;;;;;N;;;;; -120F9;CUNEIFORM SIGN GAN2 OVER GAN2;Lo;0;L;;;;;N;;;;; -120FA;CUNEIFORM SIGN GAN2 CROSSING GAN2;Lo;0;L;;;;;N;;;;; -120FB;CUNEIFORM SIGN GAR;Lo;0;L;;;;;N;;;;; -120FC;CUNEIFORM SIGN GAR3;Lo;0;L;;;;;N;;;;; -120FD;CUNEIFORM SIGN GASHAN;Lo;0;L;;;;;N;;;;; -120FE;CUNEIFORM SIGN GESHTIN;Lo;0;L;;;;;N;;;;; -120FF;CUNEIFORM SIGN GESHTIN TIMES KUR;Lo;0;L;;;;;N;;;;; -12100;CUNEIFORM SIGN GI;Lo;0;L;;;;;N;;;;; -12101;CUNEIFORM SIGN GI TIMES E;Lo;0;L;;;;;N;;;;; -12102;CUNEIFORM SIGN GI TIMES U;Lo;0;L;;;;;N;;;;; -12103;CUNEIFORM SIGN GI CROSSING GI;Lo;0;L;;;;;N;;;;; -12104;CUNEIFORM SIGN GI4;Lo;0;L;;;;;N;;;;; -12105;CUNEIFORM SIGN GI4 OVER GI4;Lo;0;L;;;;;N;;;;; -12106;CUNEIFORM SIGN GI4 CROSSING GI4;Lo;0;L;;;;;N;;;;; -12107;CUNEIFORM SIGN GIDIM;Lo;0;L;;;;;N;;;;; -12108;CUNEIFORM SIGN GIR2;Lo;0;L;;;;;N;;;;; -12109;CUNEIFORM SIGN GIR2 GUNU;Lo;0;L;;;;;N;;;;; -1210A;CUNEIFORM SIGN GIR3;Lo;0;L;;;;;N;;;;; -1210B;CUNEIFORM SIGN GIR3 TIMES A PLUS IGI;Lo;0;L;;;;;N;;;;; -1210C;CUNEIFORM SIGN GIR3 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; -1210D;CUNEIFORM SIGN GIR3 TIMES IGI;Lo;0;L;;;;;N;;;;; -1210E;CUNEIFORM SIGN GIR3 TIMES LU PLUS IGI;Lo;0;L;;;;;N;;;;; -1210F;CUNEIFORM SIGN GIR3 TIMES PA;Lo;0;L;;;;;N;;;;; -12110;CUNEIFORM SIGN GISAL;Lo;0;L;;;;;N;;;;; -12111;CUNEIFORM SIGN GISH;Lo;0;L;;;;;N;;;;; -12112;CUNEIFORM SIGN GISH CROSSING GISH;Lo;0;L;;;;;N;;;;; -12113;CUNEIFORM SIGN GISH TIMES BAD;Lo;0;L;;;;;N;;;;; -12114;CUNEIFORM SIGN GISH TIMES TAK4;Lo;0;L;;;;;N;;;;; -12115;CUNEIFORM SIGN GISH TENU;Lo;0;L;;;;;N;;;;; -12116;CUNEIFORM SIGN GU;Lo;0;L;;;;;N;;;;; -12117;CUNEIFORM SIGN GU CROSSING GU;Lo;0;L;;;;;N;;;;; -12118;CUNEIFORM SIGN GU2;Lo;0;L;;;;;N;;;;; -12119;CUNEIFORM SIGN GU2 TIMES KAK;Lo;0;L;;;;;N;;;;; -1211A;CUNEIFORM SIGN GU2 TIMES KAK TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; -1211B;CUNEIFORM SIGN GU2 TIMES NUN;Lo;0;L;;;;;N;;;;; -1211C;CUNEIFORM SIGN GU2 TIMES SAL PLUS TUG2;Lo;0;L;;;;;N;;;;; -1211D;CUNEIFORM SIGN GU2 GUNU;Lo;0;L;;;;;N;;;;; -1211E;CUNEIFORM SIGN GUD;Lo;0;L;;;;;N;;;;; -1211F;CUNEIFORM SIGN GUD TIMES A PLUS KUR;Lo;0;L;;;;;N;;;;; -12120;CUNEIFORM SIGN GUD TIMES KUR;Lo;0;L;;;;;N;;;;; -12121;CUNEIFORM SIGN GUD OVER GUD LUGAL;Lo;0;L;;;;;N;;;;; -12122;CUNEIFORM SIGN GUL;Lo;0;L;;;;;N;;;;; -12123;CUNEIFORM SIGN GUM;Lo;0;L;;;;;N;;;;; -12124;CUNEIFORM SIGN GUM TIMES SHE;Lo;0;L;;;;;N;;;;; -12125;CUNEIFORM SIGN GUR;Lo;0;L;;;;;N;;;;; -12126;CUNEIFORM SIGN GUR7;Lo;0;L;;;;;N;;;;; -12127;CUNEIFORM SIGN GURUN;Lo;0;L;;;;;N;;;;; -12128;CUNEIFORM SIGN GURUSH;Lo;0;L;;;;;N;;;;; -12129;CUNEIFORM SIGN HA;Lo;0;L;;;;;N;;;;; -1212A;CUNEIFORM SIGN HA TENU;Lo;0;L;;;;;N;;;;; -1212B;CUNEIFORM SIGN HA GUNU;Lo;0;L;;;;;N;;;;; -1212C;CUNEIFORM SIGN HAL;Lo;0;L;;;;;N;;;;; -1212D;CUNEIFORM SIGN HI;Lo;0;L;;;;;N;;;;; -1212E;CUNEIFORM SIGN HI TIMES ASH;Lo;0;L;;;;;N;;;;; -1212F;CUNEIFORM SIGN HI TIMES ASH2;Lo;0;L;;;;;N;;;;; -12130;CUNEIFORM SIGN HI TIMES BAD;Lo;0;L;;;;;N;;;;; -12131;CUNEIFORM SIGN HI TIMES DISH;Lo;0;L;;;;;N;;;;; -12132;CUNEIFORM SIGN HI TIMES GAD;Lo;0;L;;;;;N;;;;; -12133;CUNEIFORM SIGN HI TIMES KIN;Lo;0;L;;;;;N;;;;; -12134;CUNEIFORM SIGN HI TIMES NUN;Lo;0;L;;;;;N;;;;; -12135;CUNEIFORM SIGN HI TIMES SHE;Lo;0;L;;;;;N;;;;; -12136;CUNEIFORM SIGN HI TIMES U;Lo;0;L;;;;;N;;;;; -12137;CUNEIFORM SIGN HU;Lo;0;L;;;;;N;;;;; -12138;CUNEIFORM SIGN HUB2;Lo;0;L;;;;;N;;;;; -12139;CUNEIFORM SIGN HUB2 TIMES AN;Lo;0;L;;;;;N;;;;; -1213A;CUNEIFORM SIGN HUB2 TIMES HAL;Lo;0;L;;;;;N;;;;; -1213B;CUNEIFORM SIGN HUB2 TIMES KASKAL;Lo;0;L;;;;;N;;;;; -1213C;CUNEIFORM SIGN HUB2 TIMES LISH;Lo;0;L;;;;;N;;;;; -1213D;CUNEIFORM SIGN HUB2 TIMES UD;Lo;0;L;;;;;N;;;;; -1213E;CUNEIFORM SIGN HUL2;Lo;0;L;;;;;N;;;;; -1213F;CUNEIFORM SIGN I;Lo;0;L;;;;;N;;;;; -12140;CUNEIFORM SIGN I A;Lo;0;L;;;;;N;;;;; -12141;CUNEIFORM SIGN IB;Lo;0;L;;;;;N;;;;; -12142;CUNEIFORM SIGN IDIM;Lo;0;L;;;;;N;;;;; -12143;CUNEIFORM SIGN IDIM OVER IDIM BUR;Lo;0;L;;;;;N;;;;; -12144;CUNEIFORM SIGN IDIM OVER IDIM SQUARED;Lo;0;L;;;;;N;;;;; -12145;CUNEIFORM SIGN IG;Lo;0;L;;;;;N;;;;; -12146;CUNEIFORM SIGN IGI;Lo;0;L;;;;;N;;;;; -12147;CUNEIFORM SIGN IGI DIB;Lo;0;L;;;;;N;;;;; -12148;CUNEIFORM SIGN IGI RI;Lo;0;L;;;;;N;;;;; -12149;CUNEIFORM SIGN IGI OVER IGI SHIR OVER SHIR UD OVER UD;Lo;0;L;;;;;N;;;;; -1214A;CUNEIFORM SIGN IGI GUNU;Lo;0;L;;;;;N;;;;; -1214B;CUNEIFORM SIGN IL;Lo;0;L;;;;;N;;;;; -1214C;CUNEIFORM SIGN IL TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; -1214D;CUNEIFORM SIGN IL2;Lo;0;L;;;;;N;;;;; -1214E;CUNEIFORM SIGN IM;Lo;0;L;;;;;N;;;;; -1214F;CUNEIFORM SIGN IM TIMES TAK4;Lo;0;L;;;;;N;;;;; -12150;CUNEIFORM SIGN IM CROSSING IM;Lo;0;L;;;;;N;;;;; -12151;CUNEIFORM SIGN IM OPPOSING IM;Lo;0;L;;;;;N;;;;; -12152;CUNEIFORM SIGN IM SQUARED;Lo;0;L;;;;;N;;;;; -12153;CUNEIFORM SIGN IMIN;Lo;0;L;;;;;N;;;;; -12154;CUNEIFORM SIGN IN;Lo;0;L;;;;;N;;;;; -12155;CUNEIFORM SIGN IR;Lo;0;L;;;;;N;;;;; -12156;CUNEIFORM SIGN ISH;Lo;0;L;;;;;N;;;;; -12157;CUNEIFORM SIGN KA;Lo;0;L;;;;;N;;;;; -12158;CUNEIFORM SIGN KA TIMES A;Lo;0;L;;;;;N;;;;; -12159;CUNEIFORM SIGN KA TIMES AD;Lo;0;L;;;;;N;;;;; -1215A;CUNEIFORM SIGN KA TIMES AD PLUS KU3;Lo;0;L;;;;;N;;;;; -1215B;CUNEIFORM SIGN KA TIMES ASH2;Lo;0;L;;;;;N;;;;; -1215C;CUNEIFORM SIGN KA TIMES BAD;Lo;0;L;;;;;N;;;;; -1215D;CUNEIFORM SIGN KA TIMES BALAG;Lo;0;L;;;;;N;;;;; -1215E;CUNEIFORM SIGN KA TIMES BAR;Lo;0;L;;;;;N;;;;; -1215F;CUNEIFORM SIGN KA TIMES BI;Lo;0;L;;;;;N;;;;; -12160;CUNEIFORM SIGN KA TIMES ERIN2;Lo;0;L;;;;;N;;;;; -12161;CUNEIFORM SIGN KA TIMES ESH2;Lo;0;L;;;;;N;;;;; -12162;CUNEIFORM SIGN KA TIMES GA;Lo;0;L;;;;;N;;;;; -12163;CUNEIFORM SIGN KA TIMES GAL;Lo;0;L;;;;;N;;;;; -12164;CUNEIFORM SIGN KA TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; -12165;CUNEIFORM SIGN KA TIMES GAR;Lo;0;L;;;;;N;;;;; -12166;CUNEIFORM SIGN KA TIMES GAR PLUS SHA3 PLUS A;Lo;0;L;;;;;N;;;;; -12167;CUNEIFORM SIGN KA TIMES GI;Lo;0;L;;;;;N;;;;; -12168;CUNEIFORM SIGN KA TIMES GIR2;Lo;0;L;;;;;N;;;;; -12169;CUNEIFORM SIGN KA TIMES GISH PLUS SAR;Lo;0;L;;;;;N;;;;; -1216A;CUNEIFORM SIGN KA TIMES GISH CROSSING GISH;Lo;0;L;;;;;N;;;;; -1216B;CUNEIFORM SIGN KA TIMES GU;Lo;0;L;;;;;N;;;;; -1216C;CUNEIFORM SIGN KA TIMES GUR7;Lo;0;L;;;;;N;;;;; -1216D;CUNEIFORM SIGN KA TIMES IGI;Lo;0;L;;;;;N;;;;; -1216E;CUNEIFORM SIGN KA TIMES IM;Lo;0;L;;;;;N;;;;; -1216F;CUNEIFORM SIGN KA TIMES KAK;Lo;0;L;;;;;N;;;;; -12170;CUNEIFORM SIGN KA TIMES KI;Lo;0;L;;;;;N;;;;; -12171;CUNEIFORM SIGN KA TIMES KID;Lo;0;L;;;;;N;;;;; -12172;CUNEIFORM SIGN KA TIMES LI;Lo;0;L;;;;;N;;;;; -12173;CUNEIFORM SIGN KA TIMES LU;Lo;0;L;;;;;N;;;;; -12174;CUNEIFORM SIGN KA TIMES ME;Lo;0;L;;;;;N;;;;; -12175;CUNEIFORM SIGN KA TIMES ME PLUS DU;Lo;0;L;;;;;N;;;;; -12176;CUNEIFORM SIGN KA TIMES ME PLUS GI;Lo;0;L;;;;;N;;;;; -12177;CUNEIFORM SIGN KA TIMES ME PLUS TE;Lo;0;L;;;;;N;;;;; -12178;CUNEIFORM SIGN KA TIMES MI;Lo;0;L;;;;;N;;;;; -12179;CUNEIFORM SIGN KA TIMES MI PLUS NUNUZ;Lo;0;L;;;;;N;;;;; -1217A;CUNEIFORM SIGN KA TIMES NE;Lo;0;L;;;;;N;;;;; -1217B;CUNEIFORM SIGN KA TIMES NUN;Lo;0;L;;;;;N;;;;; -1217C;CUNEIFORM SIGN KA TIMES PI;Lo;0;L;;;;;N;;;;; -1217D;CUNEIFORM SIGN KA TIMES RU;Lo;0;L;;;;;N;;;;; -1217E;CUNEIFORM SIGN KA TIMES SA;Lo;0;L;;;;;N;;;;; -1217F;CUNEIFORM SIGN KA TIMES SAR;Lo;0;L;;;;;N;;;;; -12180;CUNEIFORM SIGN KA TIMES SHA;Lo;0;L;;;;;N;;;;; -12181;CUNEIFORM SIGN KA TIMES SHE;Lo;0;L;;;;;N;;;;; -12182;CUNEIFORM SIGN KA TIMES SHID;Lo;0;L;;;;;N;;;;; -12183;CUNEIFORM SIGN KA TIMES SHU;Lo;0;L;;;;;N;;;;; -12184;CUNEIFORM SIGN KA TIMES SIG;Lo;0;L;;;;;N;;;;; -12185;CUNEIFORM SIGN KA TIMES SUHUR;Lo;0;L;;;;;N;;;;; -12186;CUNEIFORM SIGN KA TIMES TAR;Lo;0;L;;;;;N;;;;; -12187;CUNEIFORM SIGN KA TIMES U;Lo;0;L;;;;;N;;;;; -12188;CUNEIFORM SIGN KA TIMES U2;Lo;0;L;;;;;N;;;;; -12189;CUNEIFORM SIGN KA TIMES UD;Lo;0;L;;;;;N;;;;; -1218A;CUNEIFORM SIGN KA TIMES UMUM TIMES PA;Lo;0;L;;;;;N;;;;; -1218B;CUNEIFORM SIGN KA TIMES USH;Lo;0;L;;;;;N;;;;; -1218C;CUNEIFORM SIGN KA TIMES ZI;Lo;0;L;;;;;N;;;;; -1218D;CUNEIFORM SIGN KA2;Lo;0;L;;;;;N;;;;; -1218E;CUNEIFORM SIGN KA2 CROSSING KA2;Lo;0;L;;;;;N;;;;; -1218F;CUNEIFORM SIGN KAB;Lo;0;L;;;;;N;;;;; -12190;CUNEIFORM SIGN KAD2;Lo;0;L;;;;;N;;;;; -12191;CUNEIFORM SIGN KAD3;Lo;0;L;;;;;N;;;;; -12192;CUNEIFORM SIGN KAD4;Lo;0;L;;;;;N;;;;; -12193;CUNEIFORM SIGN KAD5;Lo;0;L;;;;;N;;;;; -12194;CUNEIFORM SIGN KAD5 OVER KAD5;Lo;0;L;;;;;N;;;;; -12195;CUNEIFORM SIGN KAK;Lo;0;L;;;;;N;;;;; -12196;CUNEIFORM SIGN KAK TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; -12197;CUNEIFORM SIGN KAL;Lo;0;L;;;;;N;;;;; -12198;CUNEIFORM SIGN KAL TIMES BAD;Lo;0;L;;;;;N;;;;; -12199;CUNEIFORM SIGN KAL CROSSING KAL;Lo;0;L;;;;;N;;;;; -1219A;CUNEIFORM SIGN KAM2;Lo;0;L;;;;;N;;;;; -1219B;CUNEIFORM SIGN KAM4;Lo;0;L;;;;;N;;;;; -1219C;CUNEIFORM SIGN KASKAL;Lo;0;L;;;;;N;;;;; -1219D;CUNEIFORM SIGN KASKAL LAGAB TIMES U OVER LAGAB TIMES U;Lo;0;L;;;;;N;;;;; -1219E;CUNEIFORM SIGN KASKAL OVER KASKAL LAGAB TIMES U OVER LAGAB TIMES U;Lo;0;L;;;;;N;;;;; -1219F;CUNEIFORM SIGN KESH2;Lo;0;L;;;;;N;;;;; -121A0;CUNEIFORM SIGN KI;Lo;0;L;;;;;N;;;;; -121A1;CUNEIFORM SIGN KI TIMES BAD;Lo;0;L;;;;;N;;;;; -121A2;CUNEIFORM SIGN KI TIMES U;Lo;0;L;;;;;N;;;;; -121A3;CUNEIFORM SIGN KI TIMES UD;Lo;0;L;;;;;N;;;;; -121A4;CUNEIFORM SIGN KID;Lo;0;L;;;;;N;;;;; -121A5;CUNEIFORM SIGN KIN;Lo;0;L;;;;;N;;;;; -121A6;CUNEIFORM SIGN KISAL;Lo;0;L;;;;;N;;;;; -121A7;CUNEIFORM SIGN KISH;Lo;0;L;;;;;N;;;;; -121A8;CUNEIFORM SIGN KISIM5;Lo;0;L;;;;;N;;;;; -121A9;CUNEIFORM SIGN KISIM5 OVER KISIM5;Lo;0;L;;;;;N;;;;; -121AA;CUNEIFORM SIGN KU;Lo;0;L;;;;;N;;;;; -121AB;CUNEIFORM SIGN KU OVER HI TIMES ASH2 KU OVER HI TIMES ASH2;Lo;0;L;;;;;N;;;;; -121AC;CUNEIFORM SIGN KU3;Lo;0;L;;;;;N;;;;; -121AD;CUNEIFORM SIGN KU4;Lo;0;L;;;;;N;;;;; -121AE;CUNEIFORM SIGN KU4 VARIANT FORM;Lo;0;L;;;;;N;;;;; -121AF;CUNEIFORM SIGN KU7;Lo;0;L;;;;;N;;;;; -121B0;CUNEIFORM SIGN KUL;Lo;0;L;;;;;N;;;;; -121B1;CUNEIFORM SIGN KUL GUNU;Lo;0;L;;;;;N;;;;; -121B2;CUNEIFORM SIGN KUN;Lo;0;L;;;;;N;;;;; -121B3;CUNEIFORM SIGN KUR;Lo;0;L;;;;;N;;;;; -121B4;CUNEIFORM SIGN KUR OPPOSING KUR;Lo;0;L;;;;;N;;;;; -121B5;CUNEIFORM SIGN KUSHU2;Lo;0;L;;;;;N;;;;; -121B6;CUNEIFORM SIGN KWU318;Lo;0;L;;;;;N;;;;; -121B7;CUNEIFORM SIGN LA;Lo;0;L;;;;;N;;;;; -121B8;CUNEIFORM SIGN LAGAB;Lo;0;L;;;;;N;;;;; -121B9;CUNEIFORM SIGN LAGAB TIMES A;Lo;0;L;;;;;N;;;;; -121BA;CUNEIFORM SIGN LAGAB TIMES A PLUS DA PLUS HA;Lo;0;L;;;;;N;;;;; -121BB;CUNEIFORM SIGN LAGAB TIMES A PLUS GAR;Lo;0;L;;;;;N;;;;; -121BC;CUNEIFORM SIGN LAGAB TIMES A PLUS LAL;Lo;0;L;;;;;N;;;;; -121BD;CUNEIFORM SIGN LAGAB TIMES AL;Lo;0;L;;;;;N;;;;; -121BE;CUNEIFORM SIGN LAGAB TIMES AN;Lo;0;L;;;;;N;;;;; -121BF;CUNEIFORM SIGN LAGAB TIMES ASH ZIDA TENU;Lo;0;L;;;;;N;;;;; -121C0;CUNEIFORM SIGN LAGAB TIMES BAD;Lo;0;L;;;;;N;;;;; -121C1;CUNEIFORM SIGN LAGAB TIMES BI;Lo;0;L;;;;;N;;;;; -121C2;CUNEIFORM SIGN LAGAB TIMES DAR;Lo;0;L;;;;;N;;;;; -121C3;CUNEIFORM SIGN LAGAB TIMES EN;Lo;0;L;;;;;N;;;;; -121C4;CUNEIFORM SIGN LAGAB TIMES GA;Lo;0;L;;;;;N;;;;; -121C5;CUNEIFORM SIGN LAGAB TIMES GAR;Lo;0;L;;;;;N;;;;; -121C6;CUNEIFORM SIGN LAGAB TIMES GUD;Lo;0;L;;;;;N;;;;; -121C7;CUNEIFORM SIGN LAGAB TIMES GUD PLUS GUD;Lo;0;L;;;;;N;;;;; -121C8;CUNEIFORM SIGN LAGAB TIMES HA;Lo;0;L;;;;;N;;;;; -121C9;CUNEIFORM SIGN LAGAB TIMES HAL;Lo;0;L;;;;;N;;;;; -121CA;CUNEIFORM SIGN LAGAB TIMES HI TIMES NUN;Lo;0;L;;;;;N;;;;; -121CB;CUNEIFORM SIGN LAGAB TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; -121CC;CUNEIFORM SIGN LAGAB TIMES IM;Lo;0;L;;;;;N;;;;; -121CD;CUNEIFORM SIGN LAGAB TIMES IM PLUS HA;Lo;0;L;;;;;N;;;;; -121CE;CUNEIFORM SIGN LAGAB TIMES IM PLUS LU;Lo;0;L;;;;;N;;;;; -121CF;CUNEIFORM SIGN LAGAB TIMES KI;Lo;0;L;;;;;N;;;;; -121D0;CUNEIFORM SIGN LAGAB TIMES KIN;Lo;0;L;;;;;N;;;;; -121D1;CUNEIFORM SIGN LAGAB TIMES KU3;Lo;0;L;;;;;N;;;;; -121D2;CUNEIFORM SIGN LAGAB TIMES KUL;Lo;0;L;;;;;N;;;;; -121D3;CUNEIFORM SIGN LAGAB TIMES KUL PLUS HI PLUS A;Lo;0;L;;;;;N;;;;; -121D4;CUNEIFORM SIGN LAGAB TIMES LAGAB;Lo;0;L;;;;;N;;;;; -121D5;CUNEIFORM SIGN LAGAB TIMES LISH;Lo;0;L;;;;;N;;;;; -121D6;CUNEIFORM SIGN LAGAB TIMES LU;Lo;0;L;;;;;N;;;;; -121D7;CUNEIFORM SIGN LAGAB TIMES LUL;Lo;0;L;;;;;N;;;;; -121D8;CUNEIFORM SIGN LAGAB TIMES ME;Lo;0;L;;;;;N;;;;; -121D9;CUNEIFORM SIGN LAGAB TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;; -121DA;CUNEIFORM SIGN LAGAB TIMES MUSH;Lo;0;L;;;;;N;;;;; -121DB;CUNEIFORM SIGN LAGAB TIMES NE;Lo;0;L;;;;;N;;;;; -121DC;CUNEIFORM SIGN LAGAB TIMES SHE PLUS SUM;Lo;0;L;;;;;N;;;;; -121DD;CUNEIFORM SIGN LAGAB TIMES SHITA PLUS GISH PLUS ERIN2;Lo;0;L;;;;;N;;;;; -121DE;CUNEIFORM SIGN LAGAB TIMES SHITA PLUS GISH TENU;Lo;0;L;;;;;N;;;;; -121DF;CUNEIFORM SIGN LAGAB TIMES SHU2;Lo;0;L;;;;;N;;;;; -121E0;CUNEIFORM SIGN LAGAB TIMES SHU2 PLUS SHU2;Lo;0;L;;;;;N;;;;; -121E1;CUNEIFORM SIGN LAGAB TIMES SUM;Lo;0;L;;;;;N;;;;; -121E2;CUNEIFORM SIGN LAGAB TIMES TAG;Lo;0;L;;;;;N;;;;; -121E3;CUNEIFORM SIGN LAGAB TIMES TAK4;Lo;0;L;;;;;N;;;;; -121E4;CUNEIFORM SIGN LAGAB TIMES TE PLUS A PLUS SU PLUS NA;Lo;0;L;;;;;N;;;;; -121E5;CUNEIFORM SIGN LAGAB TIMES U;Lo;0;L;;;;;N;;;;; -121E6;CUNEIFORM SIGN LAGAB TIMES U PLUS A;Lo;0;L;;;;;N;;;;; -121E7;CUNEIFORM SIGN LAGAB TIMES U PLUS U PLUS U;Lo;0;L;;;;;N;;;;; -121E8;CUNEIFORM SIGN LAGAB TIMES U2 PLUS ASH;Lo;0;L;;;;;N;;;;; -121E9;CUNEIFORM SIGN LAGAB TIMES UD;Lo;0;L;;;;;N;;;;; -121EA;CUNEIFORM SIGN LAGAB TIMES USH;Lo;0;L;;;;;N;;;;; -121EB;CUNEIFORM SIGN LAGAB SQUARED;Lo;0;L;;;;;N;;;;; -121EC;CUNEIFORM SIGN LAGAR;Lo;0;L;;;;;N;;;;; -121ED;CUNEIFORM SIGN LAGAR TIMES SHE;Lo;0;L;;;;;N;;;;; -121EE;CUNEIFORM SIGN LAGAR TIMES SHE PLUS SUM;Lo;0;L;;;;;N;;;;; -121EF;CUNEIFORM SIGN LAGAR GUNU;Lo;0;L;;;;;N;;;;; -121F0;CUNEIFORM SIGN LAGAR GUNU OVER LAGAR GUNU SHE;Lo;0;L;;;;;N;;;;; -121F1;CUNEIFORM SIGN LAHSHU;Lo;0;L;;;;;N;;;;; -121F2;CUNEIFORM SIGN LAL;Lo;0;L;;;;;N;;;;; -121F3;CUNEIFORM SIGN LAL TIMES LAL;Lo;0;L;;;;;N;;;;; -121F4;CUNEIFORM SIGN LAM;Lo;0;L;;;;;N;;;;; -121F5;CUNEIFORM SIGN LAM TIMES KUR;Lo;0;L;;;;;N;;;;; -121F6;CUNEIFORM SIGN LAM TIMES KUR PLUS RU;Lo;0;L;;;;;N;;;;; -121F7;CUNEIFORM SIGN LI;Lo;0;L;;;;;N;;;;; -121F8;CUNEIFORM SIGN LIL;Lo;0;L;;;;;N;;;;; -121F9;CUNEIFORM SIGN LIMMU2;Lo;0;L;;;;;N;;;;; -121FA;CUNEIFORM SIGN LISH;Lo;0;L;;;;;N;;;;; -121FB;CUNEIFORM SIGN LU;Lo;0;L;;;;;N;;;;; -121FC;CUNEIFORM SIGN LU TIMES BAD;Lo;0;L;;;;;N;;;;; -121FD;CUNEIFORM SIGN LU2;Lo;0;L;;;;;N;;;;; -121FE;CUNEIFORM SIGN LU2 TIMES AL;Lo;0;L;;;;;N;;;;; -121FF;CUNEIFORM SIGN LU2 TIMES BAD;Lo;0;L;;;;;N;;;;; -12200;CUNEIFORM SIGN LU2 TIMES ESH2;Lo;0;L;;;;;N;;;;; -12201;CUNEIFORM SIGN LU2 TIMES ESH2 TENU;Lo;0;L;;;;;N;;;;; -12202;CUNEIFORM SIGN LU2 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; -12203;CUNEIFORM SIGN LU2 TIMES HI TIMES BAD;Lo;0;L;;;;;N;;;;; -12204;CUNEIFORM SIGN LU2 TIMES IM;Lo;0;L;;;;;N;;;;; -12205;CUNEIFORM SIGN LU2 TIMES KAD2;Lo;0;L;;;;;N;;;;; -12206;CUNEIFORM SIGN LU2 TIMES KAD3;Lo;0;L;;;;;N;;;;; -12207;CUNEIFORM SIGN LU2 TIMES KAD3 PLUS ASH;Lo;0;L;;;;;N;;;;; -12208;CUNEIFORM SIGN LU2 TIMES KI;Lo;0;L;;;;;N;;;;; -12209;CUNEIFORM SIGN LU2 TIMES LA PLUS ASH;Lo;0;L;;;;;N;;;;; -1220A;CUNEIFORM SIGN LU2 TIMES LAGAB;Lo;0;L;;;;;N;;;;; -1220B;CUNEIFORM SIGN LU2 TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;; -1220C;CUNEIFORM SIGN LU2 TIMES NE;Lo;0;L;;;;;N;;;;; -1220D;CUNEIFORM SIGN LU2 TIMES NU;Lo;0;L;;;;;N;;;;; -1220E;CUNEIFORM SIGN LU2 TIMES SI PLUS ASH;Lo;0;L;;;;;N;;;;; -1220F;CUNEIFORM SIGN LU2 TIMES SIK2 PLUS BU;Lo;0;L;;;;;N;;;;; -12210;CUNEIFORM SIGN LU2 TIMES TUG2;Lo;0;L;;;;;N;;;;; -12211;CUNEIFORM SIGN LU2 TENU;Lo;0;L;;;;;N;;;;; -12212;CUNEIFORM SIGN LU2 CROSSING LU2;Lo;0;L;;;;;N;;;;; -12213;CUNEIFORM SIGN LU2 OPPOSING LU2;Lo;0;L;;;;;N;;;;; -12214;CUNEIFORM SIGN LU2 SQUARED;Lo;0;L;;;;;N;;;;; -12215;CUNEIFORM SIGN LU2 SHESHIG;Lo;0;L;;;;;N;;;;; -12216;CUNEIFORM SIGN LU3;Lo;0;L;;;;;N;;;;; -12217;CUNEIFORM SIGN LUGAL;Lo;0;L;;;;;N;;;;; -12218;CUNEIFORM SIGN LUGAL OVER LUGAL;Lo;0;L;;;;;N;;;;; -12219;CUNEIFORM SIGN LUGAL OPPOSING LUGAL;Lo;0;L;;;;;N;;;;; -1221A;CUNEIFORM SIGN LUGAL SHESHIG;Lo;0;L;;;;;N;;;;; -1221B;CUNEIFORM SIGN LUH;Lo;0;L;;;;;N;;;;; -1221C;CUNEIFORM SIGN LUL;Lo;0;L;;;;;N;;;;; -1221D;CUNEIFORM SIGN LUM;Lo;0;L;;;;;N;;;;; -1221E;CUNEIFORM SIGN LUM OVER LUM;Lo;0;L;;;;;N;;;;; -1221F;CUNEIFORM SIGN LUM OVER LUM GAR OVER GAR;Lo;0;L;;;;;N;;;;; -12220;CUNEIFORM SIGN MA;Lo;0;L;;;;;N;;;;; -12221;CUNEIFORM SIGN MA TIMES TAK4;Lo;0;L;;;;;N;;;;; -12222;CUNEIFORM SIGN MA GUNU;Lo;0;L;;;;;N;;;;; -12223;CUNEIFORM SIGN MA2;Lo;0;L;;;;;N;;;;; -12224;CUNEIFORM SIGN MAH;Lo;0;L;;;;;N;;;;; -12225;CUNEIFORM SIGN MAR;Lo;0;L;;;;;N;;;;; -12226;CUNEIFORM SIGN MASH;Lo;0;L;;;;;N;;;;; -12227;CUNEIFORM SIGN MASH2;Lo;0;L;;;;;N;;;;; -12228;CUNEIFORM SIGN ME;Lo;0;L;;;;;N;;;;; -12229;CUNEIFORM SIGN MES;Lo;0;L;;;;;N;;;;; -1222A;CUNEIFORM SIGN MI;Lo;0;L;;;;;N;;;;; -1222B;CUNEIFORM SIGN MIN;Lo;0;L;;;;;N;;;;; -1222C;CUNEIFORM SIGN MU;Lo;0;L;;;;;N;;;;; -1222D;CUNEIFORM SIGN MU OVER MU;Lo;0;L;;;;;N;;;;; -1222E;CUNEIFORM SIGN MUG;Lo;0;L;;;;;N;;;;; -1222F;CUNEIFORM SIGN MUG GUNU;Lo;0;L;;;;;N;;;;; -12230;CUNEIFORM SIGN MUNSUB;Lo;0;L;;;;;N;;;;; -12231;CUNEIFORM SIGN MURGU2;Lo;0;L;;;;;N;;;;; -12232;CUNEIFORM SIGN MUSH;Lo;0;L;;;;;N;;;;; -12233;CUNEIFORM SIGN MUSH TIMES A;Lo;0;L;;;;;N;;;;; -12234;CUNEIFORM SIGN MUSH TIMES KUR;Lo;0;L;;;;;N;;;;; -12235;CUNEIFORM SIGN MUSH TIMES ZA;Lo;0;L;;;;;N;;;;; -12236;CUNEIFORM SIGN MUSH OVER MUSH;Lo;0;L;;;;;N;;;;; -12237;CUNEIFORM SIGN MUSH OVER MUSH TIMES A PLUS NA;Lo;0;L;;;;;N;;;;; -12238;CUNEIFORM SIGN MUSH CROSSING MUSH;Lo;0;L;;;;;N;;;;; -12239;CUNEIFORM SIGN MUSH3;Lo;0;L;;;;;N;;;;; -1223A;CUNEIFORM SIGN MUSH3 TIMES A;Lo;0;L;;;;;N;;;;; -1223B;CUNEIFORM SIGN MUSH3 TIMES A PLUS DI;Lo;0;L;;;;;N;;;;; -1223C;CUNEIFORM SIGN MUSH3 TIMES DI;Lo;0;L;;;;;N;;;;; -1223D;CUNEIFORM SIGN MUSH3 GUNU;Lo;0;L;;;;;N;;;;; -1223E;CUNEIFORM SIGN NA;Lo;0;L;;;;;N;;;;; -1223F;CUNEIFORM SIGN NA2;Lo;0;L;;;;;N;;;;; -12240;CUNEIFORM SIGN NAGA;Lo;0;L;;;;;N;;;;; -12241;CUNEIFORM SIGN NAGA INVERTED;Lo;0;L;;;;;N;;;;; -12242;CUNEIFORM SIGN NAGA TIMES SHU TENU;Lo;0;L;;;;;N;;;;; -12243;CUNEIFORM SIGN NAGA OPPOSING NAGA;Lo;0;L;;;;;N;;;;; -12244;CUNEIFORM SIGN NAGAR;Lo;0;L;;;;;N;;;;; -12245;CUNEIFORM SIGN NAM NUTILLU;Lo;0;L;;;;;N;;;;; -12246;CUNEIFORM SIGN NAM;Lo;0;L;;;;;N;;;;; -12247;CUNEIFORM SIGN NAM2;Lo;0;L;;;;;N;;;;; -12248;CUNEIFORM SIGN NE;Lo;0;L;;;;;N;;;;; -12249;CUNEIFORM SIGN NE TIMES A;Lo;0;L;;;;;N;;;;; -1224A;CUNEIFORM SIGN NE TIMES UD;Lo;0;L;;;;;N;;;;; -1224B;CUNEIFORM SIGN NE SHESHIG;Lo;0;L;;;;;N;;;;; -1224C;CUNEIFORM SIGN NI;Lo;0;L;;;;;N;;;;; -1224D;CUNEIFORM SIGN NI TIMES E;Lo;0;L;;;;;N;;;;; -1224E;CUNEIFORM SIGN NI2;Lo;0;L;;;;;N;;;;; -1224F;CUNEIFORM SIGN NIM;Lo;0;L;;;;;N;;;;; -12250;CUNEIFORM SIGN NIM TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; -12251;CUNEIFORM SIGN NIM TIMES GAR PLUS GAN2 TENU;Lo;0;L;;;;;N;;;;; -12252;CUNEIFORM SIGN NINDA2;Lo;0;L;;;;;N;;;;; -12253;CUNEIFORM SIGN NINDA2 TIMES AN;Lo;0;L;;;;;N;;;;; -12254;CUNEIFORM SIGN NINDA2 TIMES ASH;Lo;0;L;;;;;N;;;;; -12255;CUNEIFORM SIGN NINDA2 TIMES ASH PLUS ASH;Lo;0;L;;;;;N;;;;; -12256;CUNEIFORM SIGN NINDA2 TIMES GUD;Lo;0;L;;;;;N;;;;; -12257;CUNEIFORM SIGN NINDA2 TIMES ME PLUS GAN2 TENU;Lo;0;L;;;;;N;;;;; -12258;CUNEIFORM SIGN NINDA2 TIMES NE;Lo;0;L;;;;;N;;;;; -12259;CUNEIFORM SIGN NINDA2 TIMES NUN;Lo;0;L;;;;;N;;;;; -1225A;CUNEIFORM SIGN NINDA2 TIMES SHE;Lo;0;L;;;;;N;;;;; -1225B;CUNEIFORM SIGN NINDA2 TIMES SHE PLUS A AN;Lo;0;L;;;;;N;;;;; -1225C;CUNEIFORM SIGN NINDA2 TIMES SHE PLUS ASH;Lo;0;L;;;;;N;;;;; -1225D;CUNEIFORM SIGN NINDA2 TIMES SHE PLUS ASH PLUS ASH;Lo;0;L;;;;;N;;;;; -1225E;CUNEIFORM SIGN NINDA2 TIMES U2 PLUS ASH;Lo;0;L;;;;;N;;;;; -1225F;CUNEIFORM SIGN NINDA2 TIMES USH;Lo;0;L;;;;;N;;;;; -12260;CUNEIFORM SIGN NISAG;Lo;0;L;;;;;N;;;;; -12261;CUNEIFORM SIGN NU;Lo;0;L;;;;;N;;;;; -12262;CUNEIFORM SIGN NU11;Lo;0;L;;;;;N;;;;; -12263;CUNEIFORM SIGN NUN;Lo;0;L;;;;;N;;;;; -12264;CUNEIFORM SIGN NUN LAGAR TIMES GAR;Lo;0;L;;;;;N;;;;; -12265;CUNEIFORM SIGN NUN LAGAR TIMES MASH;Lo;0;L;;;;;N;;;;; -12266;CUNEIFORM SIGN NUN LAGAR TIMES SAL;Lo;0;L;;;;;N;;;;; -12267;CUNEIFORM SIGN NUN LAGAR TIMES SAL OVER NUN LAGAR TIMES SAL;Lo;0;L;;;;;N;;;;; -12268;CUNEIFORM SIGN NUN LAGAR TIMES USH;Lo;0;L;;;;;N;;;;; -12269;CUNEIFORM SIGN NUN TENU;Lo;0;L;;;;;N;;;;; -1226A;CUNEIFORM SIGN NUN OVER NUN;Lo;0;L;;;;;N;;;;; -1226B;CUNEIFORM SIGN NUN CROSSING NUN;Lo;0;L;;;;;N;;;;; -1226C;CUNEIFORM SIGN NUN CROSSING NUN LAGAR OVER LAGAR;Lo;0;L;;;;;N;;;;; -1226D;CUNEIFORM SIGN NUNUZ;Lo;0;L;;;;;N;;;;; -1226E;CUNEIFORM SIGN NUNUZ AB2 TIMES ASHGAB;Lo;0;L;;;;;N;;;;; -1226F;CUNEIFORM SIGN NUNUZ AB2 TIMES BI;Lo;0;L;;;;;N;;;;; -12270;CUNEIFORM SIGN NUNUZ AB2 TIMES DUG;Lo;0;L;;;;;N;;;;; -12271;CUNEIFORM SIGN NUNUZ AB2 TIMES GUD;Lo;0;L;;;;;N;;;;; -12272;CUNEIFORM SIGN NUNUZ AB2 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; -12273;CUNEIFORM SIGN NUNUZ AB2 TIMES KAD3;Lo;0;L;;;;;N;;;;; -12274;CUNEIFORM SIGN NUNUZ AB2 TIMES LA;Lo;0;L;;;;;N;;;;; -12275;CUNEIFORM SIGN NUNUZ AB2 TIMES NE;Lo;0;L;;;;;N;;;;; -12276;CUNEIFORM SIGN NUNUZ AB2 TIMES SILA3;Lo;0;L;;;;;N;;;;; -12277;CUNEIFORM SIGN NUNUZ AB2 TIMES U2;Lo;0;L;;;;;N;;;;; -12278;CUNEIFORM SIGN NUNUZ KISIM5 TIMES BI;Lo;0;L;;;;;N;;;;; -12279;CUNEIFORM SIGN NUNUZ KISIM5 TIMES BI U;Lo;0;L;;;;;N;;;;; -1227A;CUNEIFORM SIGN PA;Lo;0;L;;;;;N;;;;; -1227B;CUNEIFORM SIGN PAD;Lo;0;L;;;;;N;;;;; -1227C;CUNEIFORM SIGN PAN;Lo;0;L;;;;;N;;;;; -1227D;CUNEIFORM SIGN PAP;Lo;0;L;;;;;N;;;;; -1227E;CUNEIFORM SIGN PESH2;Lo;0;L;;;;;N;;;;; -1227F;CUNEIFORM SIGN PI;Lo;0;L;;;;;N;;;;; -12280;CUNEIFORM SIGN PI TIMES A;Lo;0;L;;;;;N;;;;; -12281;CUNEIFORM SIGN PI TIMES AB;Lo;0;L;;;;;N;;;;; -12282;CUNEIFORM SIGN PI TIMES BI;Lo;0;L;;;;;N;;;;; -12283;CUNEIFORM SIGN PI TIMES BU;Lo;0;L;;;;;N;;;;; -12284;CUNEIFORM SIGN PI TIMES E;Lo;0;L;;;;;N;;;;; -12285;CUNEIFORM SIGN PI TIMES I;Lo;0;L;;;;;N;;;;; -12286;CUNEIFORM SIGN PI TIMES IB;Lo;0;L;;;;;N;;;;; -12287;CUNEIFORM SIGN PI TIMES U;Lo;0;L;;;;;N;;;;; -12288;CUNEIFORM SIGN PI TIMES U2;Lo;0;L;;;;;N;;;;; -12289;CUNEIFORM SIGN PI CROSSING PI;Lo;0;L;;;;;N;;;;; -1228A;CUNEIFORM SIGN PIRIG;Lo;0;L;;;;;N;;;;; -1228B;CUNEIFORM SIGN PIRIG TIMES KAL;Lo;0;L;;;;;N;;;;; -1228C;CUNEIFORM SIGN PIRIG TIMES UD;Lo;0;L;;;;;N;;;;; -1228D;CUNEIFORM SIGN PIRIG TIMES ZA;Lo;0;L;;;;;N;;;;; -1228E;CUNEIFORM SIGN PIRIG OPPOSING PIRIG;Lo;0;L;;;;;N;;;;; -1228F;CUNEIFORM SIGN RA;Lo;0;L;;;;;N;;;;; -12290;CUNEIFORM SIGN RAB;Lo;0;L;;;;;N;;;;; -12291;CUNEIFORM SIGN RI;Lo;0;L;;;;;N;;;;; -12292;CUNEIFORM SIGN RU;Lo;0;L;;;;;N;;;;; -12293;CUNEIFORM SIGN SA;Lo;0;L;;;;;N;;;;; -12294;CUNEIFORM SIGN SAG NUTILLU;Lo;0;L;;;;;N;;;;; -12295;CUNEIFORM SIGN SAG;Lo;0;L;;;;;N;;;;; -12296;CUNEIFORM SIGN SAG TIMES A;Lo;0;L;;;;;N;;;;; -12297;CUNEIFORM SIGN SAG TIMES DU;Lo;0;L;;;;;N;;;;; -12298;CUNEIFORM SIGN SAG TIMES DUB;Lo;0;L;;;;;N;;;;; -12299;CUNEIFORM SIGN SAG TIMES HA;Lo;0;L;;;;;N;;;;; -1229A;CUNEIFORM SIGN SAG TIMES KAK;Lo;0;L;;;;;N;;;;; -1229B;CUNEIFORM SIGN SAG TIMES KUR;Lo;0;L;;;;;N;;;;; -1229C;CUNEIFORM SIGN SAG TIMES LUM;Lo;0;L;;;;;N;;;;; -1229D;CUNEIFORM SIGN SAG TIMES MI;Lo;0;L;;;;;N;;;;; -1229E;CUNEIFORM SIGN SAG TIMES NUN;Lo;0;L;;;;;N;;;;; -1229F;CUNEIFORM SIGN SAG TIMES SAL;Lo;0;L;;;;;N;;;;; -122A0;CUNEIFORM SIGN SAG TIMES SHID;Lo;0;L;;;;;N;;;;; -122A1;CUNEIFORM SIGN SAG TIMES TAB;Lo;0;L;;;;;N;;;;; -122A2;CUNEIFORM SIGN SAG TIMES U2;Lo;0;L;;;;;N;;;;; -122A3;CUNEIFORM SIGN SAG TIMES UB;Lo;0;L;;;;;N;;;;; -122A4;CUNEIFORM SIGN SAG TIMES UM;Lo;0;L;;;;;N;;;;; -122A5;CUNEIFORM SIGN SAG TIMES UR;Lo;0;L;;;;;N;;;;; -122A6;CUNEIFORM SIGN SAG TIMES USH;Lo;0;L;;;;;N;;;;; -122A7;CUNEIFORM SIGN SAG OVER SAG;Lo;0;L;;;;;N;;;;; -122A8;CUNEIFORM SIGN SAG GUNU;Lo;0;L;;;;;N;;;;; -122A9;CUNEIFORM SIGN SAL;Lo;0;L;;;;;N;;;;; -122AA;CUNEIFORM SIGN SAL LAGAB TIMES ASH2;Lo;0;L;;;;;N;;;;; -122AB;CUNEIFORM SIGN SANGA2;Lo;0;L;;;;;N;;;;; -122AC;CUNEIFORM SIGN SAR;Lo;0;L;;;;;N;;;;; -122AD;CUNEIFORM SIGN SHA;Lo;0;L;;;;;N;;;;; -122AE;CUNEIFORM SIGN SHA3;Lo;0;L;;;;;N;;;;; -122AF;CUNEIFORM SIGN SHA3 TIMES A;Lo;0;L;;;;;N;;;;; -122B0;CUNEIFORM SIGN SHA3 TIMES BAD;Lo;0;L;;;;;N;;;;; -122B1;CUNEIFORM SIGN SHA3 TIMES GISH;Lo;0;L;;;;;N;;;;; -122B2;CUNEIFORM SIGN SHA3 TIMES NE;Lo;0;L;;;;;N;;;;; -122B3;CUNEIFORM SIGN SHA3 TIMES SHU2;Lo;0;L;;;;;N;;;;; -122B4;CUNEIFORM SIGN SHA3 TIMES TUR;Lo;0;L;;;;;N;;;;; -122B5;CUNEIFORM SIGN SHA3 TIMES U;Lo;0;L;;;;;N;;;;; -122B6;CUNEIFORM SIGN SHA3 TIMES U PLUS A;Lo;0;L;;;;;N;;;;; -122B7;CUNEIFORM SIGN SHA6;Lo;0;L;;;;;N;;;;; -122B8;CUNEIFORM SIGN SHAB6;Lo;0;L;;;;;N;;;;; -122B9;CUNEIFORM SIGN SHAR2;Lo;0;L;;;;;N;;;;; -122BA;CUNEIFORM SIGN SHE;Lo;0;L;;;;;N;;;;; -122BB;CUNEIFORM SIGN SHE HU;Lo;0;L;;;;;N;;;;; -122BC;CUNEIFORM SIGN SHE OVER SHE GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;; -122BD;CUNEIFORM SIGN SHE OVER SHE TAB OVER TAB GAR OVER GAR;Lo;0;L;;;;;N;;;;; -122BE;CUNEIFORM SIGN SHEG9;Lo;0;L;;;;;N;;;;; -122BF;CUNEIFORM SIGN SHEN;Lo;0;L;;;;;N;;;;; -122C0;CUNEIFORM SIGN SHESH;Lo;0;L;;;;;N;;;;; -122C1;CUNEIFORM SIGN SHESH2;Lo;0;L;;;;;N;;;;; -122C2;CUNEIFORM SIGN SHESHLAM;Lo;0;L;;;;;N;;;;; -122C3;CUNEIFORM SIGN SHID;Lo;0;L;;;;;N;;;;; -122C4;CUNEIFORM SIGN SHID TIMES A;Lo;0;L;;;;;N;;;;; -122C5;CUNEIFORM SIGN SHID TIMES IM;Lo;0;L;;;;;N;;;;; -122C6;CUNEIFORM SIGN SHIM;Lo;0;L;;;;;N;;;;; -122C7;CUNEIFORM SIGN SHIM TIMES A;Lo;0;L;;;;;N;;;;; -122C8;CUNEIFORM SIGN SHIM TIMES BAL;Lo;0;L;;;;;N;;;;; -122C9;CUNEIFORM SIGN SHIM TIMES BULUG;Lo;0;L;;;;;N;;;;; -122CA;CUNEIFORM SIGN SHIM TIMES DIN;Lo;0;L;;;;;N;;;;; -122CB;CUNEIFORM SIGN SHIM TIMES GAR;Lo;0;L;;;;;N;;;;; -122CC;CUNEIFORM SIGN SHIM TIMES IGI;Lo;0;L;;;;;N;;;;; -122CD;CUNEIFORM SIGN SHIM TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; -122CE;CUNEIFORM SIGN SHIM TIMES KUSHU2;Lo;0;L;;;;;N;;;;; -122CF;CUNEIFORM SIGN SHIM TIMES LUL;Lo;0;L;;;;;N;;;;; -122D0;CUNEIFORM SIGN SHIM TIMES MUG;Lo;0;L;;;;;N;;;;; -122D1;CUNEIFORM SIGN SHIM TIMES SAL;Lo;0;L;;;;;N;;;;; -122D2;CUNEIFORM SIGN SHINIG;Lo;0;L;;;;;N;;;;; -122D3;CUNEIFORM SIGN SHIR;Lo;0;L;;;;;N;;;;; -122D4;CUNEIFORM SIGN SHIR TENU;Lo;0;L;;;;;N;;;;; -122D5;CUNEIFORM SIGN SHIR OVER SHIR BUR OVER BUR;Lo;0;L;;;;;N;;;;; -122D6;CUNEIFORM SIGN SHITA;Lo;0;L;;;;;N;;;;; -122D7;CUNEIFORM SIGN SHU;Lo;0;L;;;;;N;;;;; -122D8;CUNEIFORM SIGN SHU OVER INVERTED SHU;Lo;0;L;;;;;N;;;;; -122D9;CUNEIFORM SIGN SHU2;Lo;0;L;;;;;N;;;;; -122DA;CUNEIFORM SIGN SHUBUR;Lo;0;L;;;;;N;;;;; -122DB;CUNEIFORM SIGN SI;Lo;0;L;;;;;N;;;;; -122DC;CUNEIFORM SIGN SI GUNU;Lo;0;L;;;;;N;;;;; -122DD;CUNEIFORM SIGN SIG;Lo;0;L;;;;;N;;;;; -122DE;CUNEIFORM SIGN SIG4;Lo;0;L;;;;;N;;;;; -122DF;CUNEIFORM SIGN SIG4 OVER SIG4 SHU2;Lo;0;L;;;;;N;;;;; -122E0;CUNEIFORM SIGN SIK2;Lo;0;L;;;;;N;;;;; -122E1;CUNEIFORM SIGN SILA3;Lo;0;L;;;;;N;;;;; -122E2;CUNEIFORM SIGN SU;Lo;0;L;;;;;N;;;;; -122E3;CUNEIFORM SIGN SU OVER SU;Lo;0;L;;;;;N;;;;; -122E4;CUNEIFORM SIGN SUD;Lo;0;L;;;;;N;;;;; -122E5;CUNEIFORM SIGN SUD2;Lo;0;L;;;;;N;;;;; -122E6;CUNEIFORM SIGN SUHUR;Lo;0;L;;;;;N;;;;; -122E7;CUNEIFORM SIGN SUM;Lo;0;L;;;;;N;;;;; -122E8;CUNEIFORM SIGN SUMASH;Lo;0;L;;;;;N;;;;; -122E9;CUNEIFORM SIGN SUR;Lo;0;L;;;;;N;;;;; -122EA;CUNEIFORM SIGN SUR9;Lo;0;L;;;;;N;;;;; -122EB;CUNEIFORM SIGN TA;Lo;0;L;;;;;N;;;;; -122EC;CUNEIFORM SIGN TA ASTERISK;Lo;0;L;;;;;N;;;;; -122ED;CUNEIFORM SIGN TA TIMES HI;Lo;0;L;;;;;N;;;;; -122EE;CUNEIFORM SIGN TA TIMES MI;Lo;0;L;;;;;N;;;;; -122EF;CUNEIFORM SIGN TA GUNU;Lo;0;L;;;;;N;;;;; -122F0;CUNEIFORM SIGN TAB;Lo;0;L;;;;;N;;;;; -122F1;CUNEIFORM SIGN TAB OVER TAB NI OVER NI DISH OVER DISH;Lo;0;L;;;;;N;;;;; -122F2;CUNEIFORM SIGN TAB SQUARED;Lo;0;L;;;;;N;;;;; -122F3;CUNEIFORM SIGN TAG;Lo;0;L;;;;;N;;;;; -122F4;CUNEIFORM SIGN TAG TIMES BI;Lo;0;L;;;;;N;;;;; -122F5;CUNEIFORM SIGN TAG TIMES GUD;Lo;0;L;;;;;N;;;;; -122F6;CUNEIFORM SIGN TAG TIMES SHE;Lo;0;L;;;;;N;;;;; -122F7;CUNEIFORM SIGN TAG TIMES SHU;Lo;0;L;;;;;N;;;;; -122F8;CUNEIFORM SIGN TAG TIMES TUG2;Lo;0;L;;;;;N;;;;; -122F9;CUNEIFORM SIGN TAG TIMES UD;Lo;0;L;;;;;N;;;;; -122FA;CUNEIFORM SIGN TAK4;Lo;0;L;;;;;N;;;;; -122FB;CUNEIFORM SIGN TAR;Lo;0;L;;;;;N;;;;; -122FC;CUNEIFORM SIGN TE;Lo;0;L;;;;;N;;;;; -122FD;CUNEIFORM SIGN TE GUNU;Lo;0;L;;;;;N;;;;; -122FE;CUNEIFORM SIGN TI;Lo;0;L;;;;;N;;;;; -122FF;CUNEIFORM SIGN TI TENU;Lo;0;L;;;;;N;;;;; -12300;CUNEIFORM SIGN TIL;Lo;0;L;;;;;N;;;;; -12301;CUNEIFORM SIGN TIR;Lo;0;L;;;;;N;;;;; -12302;CUNEIFORM SIGN TIR TIMES TAK4;Lo;0;L;;;;;N;;;;; -12303;CUNEIFORM SIGN TIR OVER TIR;Lo;0;L;;;;;N;;;;; -12304;CUNEIFORM SIGN TIR OVER TIR GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;; -12305;CUNEIFORM SIGN TU;Lo;0;L;;;;;N;;;;; -12306;CUNEIFORM SIGN TUG2;Lo;0;L;;;;;N;;;;; -12307;CUNEIFORM SIGN TUK;Lo;0;L;;;;;N;;;;; -12308;CUNEIFORM SIGN TUM;Lo;0;L;;;;;N;;;;; -12309;CUNEIFORM SIGN TUR;Lo;0;L;;;;;N;;;;; -1230A;CUNEIFORM SIGN TUR OVER TUR ZA OVER ZA;Lo;0;L;;;;;N;;;;; -1230B;CUNEIFORM SIGN U;Lo;0;L;;;;;N;;;;; -1230C;CUNEIFORM SIGN U GUD;Lo;0;L;;;;;N;;;;; -1230D;CUNEIFORM SIGN U U U;Lo;0;L;;;;;N;;;;; -1230E;CUNEIFORM SIGN U OVER U PA OVER PA GAR OVER GAR;Lo;0;L;;;;;N;;;;; -1230F;CUNEIFORM SIGN U OVER U SUR OVER SUR;Lo;0;L;;;;;N;;;;; -12310;CUNEIFORM SIGN U OVER U U REVERSED OVER U REVERSED;Lo;0;L;;;;;N;;;;; -12311;CUNEIFORM SIGN U2;Lo;0;L;;;;;N;;;;; -12312;CUNEIFORM SIGN UB;Lo;0;L;;;;;N;;;;; -12313;CUNEIFORM SIGN UD;Lo;0;L;;;;;N;;;;; -12314;CUNEIFORM SIGN UD KUSHU2;Lo;0;L;;;;;N;;;;; -12315;CUNEIFORM SIGN UD TIMES BAD;Lo;0;L;;;;;N;;;;; -12316;CUNEIFORM SIGN UD TIMES MI;Lo;0;L;;;;;N;;;;; -12317;CUNEIFORM SIGN UD TIMES U PLUS U PLUS U;Lo;0;L;;;;;N;;;;; -12318;CUNEIFORM SIGN UD TIMES U PLUS U PLUS U GUNU;Lo;0;L;;;;;N;;;;; -12319;CUNEIFORM SIGN UD GUNU;Lo;0;L;;;;;N;;;;; -1231A;CUNEIFORM SIGN UD SHESHIG;Lo;0;L;;;;;N;;;;; -1231B;CUNEIFORM SIGN UD SHESHIG TIMES BAD;Lo;0;L;;;;;N;;;;; -1231C;CUNEIFORM SIGN UDUG;Lo;0;L;;;;;N;;;;; -1231D;CUNEIFORM SIGN UM;Lo;0;L;;;;;N;;;;; -1231E;CUNEIFORM SIGN UM TIMES LAGAB;Lo;0;L;;;;;N;;;;; -1231F;CUNEIFORM SIGN UM TIMES ME PLUS DA;Lo;0;L;;;;;N;;;;; -12320;CUNEIFORM SIGN UM TIMES SHA3;Lo;0;L;;;;;N;;;;; -12321;CUNEIFORM SIGN UM TIMES U;Lo;0;L;;;;;N;;;;; -12322;CUNEIFORM SIGN UMBIN;Lo;0;L;;;;;N;;;;; -12323;CUNEIFORM SIGN UMUM;Lo;0;L;;;;;N;;;;; -12324;CUNEIFORM SIGN UMUM TIMES KASKAL;Lo;0;L;;;;;N;;;;; -12325;CUNEIFORM SIGN UMUM TIMES PA;Lo;0;L;;;;;N;;;;; -12326;CUNEIFORM SIGN UN;Lo;0;L;;;;;N;;;;; -12327;CUNEIFORM SIGN UN GUNU;Lo;0;L;;;;;N;;;;; -12328;CUNEIFORM SIGN UR;Lo;0;L;;;;;N;;;;; -12329;CUNEIFORM SIGN UR CROSSING UR;Lo;0;L;;;;;N;;;;; -1232A;CUNEIFORM SIGN UR SHESHIG;Lo;0;L;;;;;N;;;;; -1232B;CUNEIFORM SIGN UR2;Lo;0;L;;;;;N;;;;; -1232C;CUNEIFORM SIGN UR2 TIMES A PLUS HA;Lo;0;L;;;;;N;;;;; -1232D;CUNEIFORM SIGN UR2 TIMES A PLUS NA;Lo;0;L;;;;;N;;;;; -1232E;CUNEIFORM SIGN UR2 TIMES AL;Lo;0;L;;;;;N;;;;; -1232F;CUNEIFORM SIGN UR2 TIMES HA;Lo;0;L;;;;;N;;;;; -12330;CUNEIFORM SIGN UR2 TIMES NUN;Lo;0;L;;;;;N;;;;; -12331;CUNEIFORM SIGN UR2 TIMES U2;Lo;0;L;;;;;N;;;;; -12332;CUNEIFORM SIGN UR2 TIMES U2 PLUS ASH;Lo;0;L;;;;;N;;;;; -12333;CUNEIFORM SIGN UR2 TIMES U2 PLUS BI;Lo;0;L;;;;;N;;;;; -12334;CUNEIFORM SIGN UR4;Lo;0;L;;;;;N;;;;; -12335;CUNEIFORM SIGN URI;Lo;0;L;;;;;N;;;;; -12336;CUNEIFORM SIGN URI3;Lo;0;L;;;;;N;;;;; -12337;CUNEIFORM SIGN URU;Lo;0;L;;;;;N;;;;; -12338;CUNEIFORM SIGN URU TIMES A;Lo;0;L;;;;;N;;;;; -12339;CUNEIFORM SIGN URU TIMES ASHGAB;Lo;0;L;;;;;N;;;;; -1233A;CUNEIFORM SIGN URU TIMES BAR;Lo;0;L;;;;;N;;;;; -1233B;CUNEIFORM SIGN URU TIMES DUN;Lo;0;L;;;;;N;;;;; -1233C;CUNEIFORM SIGN URU TIMES GA;Lo;0;L;;;;;N;;;;; -1233D;CUNEIFORM SIGN URU TIMES GAL;Lo;0;L;;;;;N;;;;; -1233E;CUNEIFORM SIGN URU TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; -1233F;CUNEIFORM SIGN URU TIMES GAR;Lo;0;L;;;;;N;;;;; -12340;CUNEIFORM SIGN URU TIMES GU;Lo;0;L;;;;;N;;;;; -12341;CUNEIFORM SIGN URU TIMES HA;Lo;0;L;;;;;N;;;;; -12342;CUNEIFORM SIGN URU TIMES IGI;Lo;0;L;;;;;N;;;;; -12343;CUNEIFORM SIGN URU TIMES IM;Lo;0;L;;;;;N;;;;; -12344;CUNEIFORM SIGN URU TIMES ISH;Lo;0;L;;;;;N;;;;; -12345;CUNEIFORM SIGN URU TIMES KI;Lo;0;L;;;;;N;;;;; -12346;CUNEIFORM SIGN URU TIMES LUM;Lo;0;L;;;;;N;;;;; -12347;CUNEIFORM SIGN URU TIMES MIN;Lo;0;L;;;;;N;;;;; -12348;CUNEIFORM SIGN URU TIMES PA;Lo;0;L;;;;;N;;;;; -12349;CUNEIFORM SIGN URU TIMES SHE;Lo;0;L;;;;;N;;;;; -1234A;CUNEIFORM SIGN URU TIMES SIG4;Lo;0;L;;;;;N;;;;; -1234B;CUNEIFORM SIGN URU TIMES TU;Lo;0;L;;;;;N;;;;; -1234C;CUNEIFORM SIGN URU TIMES U PLUS GUD;Lo;0;L;;;;;N;;;;; -1234D;CUNEIFORM SIGN URU TIMES UD;Lo;0;L;;;;;N;;;;; -1234E;CUNEIFORM SIGN URU TIMES URUDA;Lo;0;L;;;;;N;;;;; -1234F;CUNEIFORM SIGN URUDA;Lo;0;L;;;;;N;;;;; -12350;CUNEIFORM SIGN URUDA TIMES U;Lo;0;L;;;;;N;;;;; -12351;CUNEIFORM SIGN USH;Lo;0;L;;;;;N;;;;; -12352;CUNEIFORM SIGN USH TIMES A;Lo;0;L;;;;;N;;;;; -12353;CUNEIFORM SIGN USH TIMES KU;Lo;0;L;;;;;N;;;;; -12354;CUNEIFORM SIGN USH TIMES KUR;Lo;0;L;;;;;N;;;;; -12355;CUNEIFORM SIGN USH TIMES TAK4;Lo;0;L;;;;;N;;;;; -12356;CUNEIFORM SIGN USHX;Lo;0;L;;;;;N;;;;; -12357;CUNEIFORM SIGN USH2;Lo;0;L;;;;;N;;;;; -12358;CUNEIFORM SIGN USHUMX;Lo;0;L;;;;;N;;;;; -12359;CUNEIFORM SIGN UTUKI;Lo;0;L;;;;;N;;;;; -1235A;CUNEIFORM SIGN UZ3;Lo;0;L;;;;;N;;;;; -1235B;CUNEIFORM SIGN UZ3 TIMES KASKAL;Lo;0;L;;;;;N;;;;; -1235C;CUNEIFORM SIGN UZU;Lo;0;L;;;;;N;;;;; -1235D;CUNEIFORM SIGN ZA;Lo;0;L;;;;;N;;;;; -1235E;CUNEIFORM SIGN ZA TENU;Lo;0;L;;;;;N;;;;; -1235F;CUNEIFORM SIGN ZA SQUARED TIMES KUR;Lo;0;L;;;;;N;;;;; -12360;CUNEIFORM SIGN ZAG;Lo;0;L;;;;;N;;;;; -12361;CUNEIFORM SIGN ZAMX;Lo;0;L;;;;;N;;;;; -12362;CUNEIFORM SIGN ZE2;Lo;0;L;;;;;N;;;;; -12363;CUNEIFORM SIGN ZI;Lo;0;L;;;;;N;;;;; -12364;CUNEIFORM SIGN ZI OVER ZI;Lo;0;L;;;;;N;;;;; -12365;CUNEIFORM SIGN ZI3;Lo;0;L;;;;;N;;;;; -12366;CUNEIFORM SIGN ZIB;Lo;0;L;;;;;N;;;;; -12367;CUNEIFORM SIGN ZIB KABA TENU;Lo;0;L;;;;;N;;;;; -12368;CUNEIFORM SIGN ZIG;Lo;0;L;;;;;N;;;;; -12369;CUNEIFORM SIGN ZIZ2;Lo;0;L;;;;;N;;;;; -1236A;CUNEIFORM SIGN ZU;Lo;0;L;;;;;N;;;;; -1236B;CUNEIFORM SIGN ZU5;Lo;0;L;;;;;N;;;;; -1236C;CUNEIFORM SIGN ZU5 TIMES A;Lo;0;L;;;;;N;;;;; -1236D;CUNEIFORM SIGN ZUBUR;Lo;0;L;;;;;N;;;;; -1236E;CUNEIFORM SIGN ZUM;Lo;0;L;;;;;N;;;;; -1236F;CUNEIFORM SIGN KAP ELAMITE;Lo;0;L;;;;;N;;;;; -12370;CUNEIFORM SIGN AB TIMES NUN;Lo;0;L;;;;;N;;;;; -12371;CUNEIFORM SIGN AB2 TIMES A;Lo;0;L;;;;;N;;;;; -12372;CUNEIFORM SIGN AMAR TIMES KUG;Lo;0;L;;;;;N;;;;; -12373;CUNEIFORM SIGN DAG KISIM5 TIMES U2 PLUS MASH;Lo;0;L;;;;;N;;;;; -12374;CUNEIFORM SIGN DAG3;Lo;0;L;;;;;N;;;;; -12375;CUNEIFORM SIGN DISH PLUS SHU;Lo;0;L;;;;;N;;;;; -12376;CUNEIFORM SIGN DUB TIMES SHE;Lo;0;L;;;;;N;;;;; -12377;CUNEIFORM SIGN EZEN TIMES GUD;Lo;0;L;;;;;N;;;;; -12378;CUNEIFORM SIGN EZEN TIMES SHE;Lo;0;L;;;;;N;;;;; -12379;CUNEIFORM SIGN GA2 TIMES AN PLUS KAK PLUS A;Lo;0;L;;;;;N;;;;; -1237A;CUNEIFORM SIGN GA2 TIMES ASH2;Lo;0;L;;;;;N;;;;; -1237B;CUNEIFORM SIGN GE22;Lo;0;L;;;;;N;;;;; -1237C;CUNEIFORM SIGN GIG;Lo;0;L;;;;;N;;;;; -1237D;CUNEIFORM SIGN HUSH;Lo;0;L;;;;;N;;;;; -1237E;CUNEIFORM SIGN KA TIMES ANSHE;Lo;0;L;;;;;N;;;;; -1237F;CUNEIFORM SIGN KA TIMES ASH3;Lo;0;L;;;;;N;;;;; -12380;CUNEIFORM SIGN KA TIMES GISH;Lo;0;L;;;;;N;;;;; -12381;CUNEIFORM SIGN KA TIMES GUD;Lo;0;L;;;;;N;;;;; -12382;CUNEIFORM SIGN KA TIMES HI TIMES ASH2;Lo;0;L;;;;;N;;;;; -12383;CUNEIFORM SIGN KA TIMES LUM;Lo;0;L;;;;;N;;;;; -12384;CUNEIFORM SIGN KA TIMES PA;Lo;0;L;;;;;N;;;;; -12385;CUNEIFORM SIGN KA TIMES SHUL;Lo;0;L;;;;;N;;;;; -12386;CUNEIFORM SIGN KA TIMES TU;Lo;0;L;;;;;N;;;;; -12387;CUNEIFORM SIGN KA TIMES UR2;Lo;0;L;;;;;N;;;;; -12388;CUNEIFORM SIGN LAGAB TIMES GI;Lo;0;L;;;;;N;;;;; -12389;CUNEIFORM SIGN LU2 SHESHIG TIMES BAD;Lo;0;L;;;;;N;;;;; -1238A;CUNEIFORM SIGN LU2 TIMES ESH2 PLUS LAL;Lo;0;L;;;;;N;;;;; -1238B;CUNEIFORM SIGN LU2 TIMES SHU;Lo;0;L;;;;;N;;;;; -1238C;CUNEIFORM SIGN MESH;Lo;0;L;;;;;N;;;;; -1238D;CUNEIFORM SIGN MUSH3 TIMES ZA;Lo;0;L;;;;;N;;;;; -1238E;CUNEIFORM SIGN NA4;Lo;0;L;;;;;N;;;;; -1238F;CUNEIFORM SIGN NIN;Lo;0;L;;;;;N;;;;; -12390;CUNEIFORM SIGN NIN9;Lo;0;L;;;;;N;;;;; -12391;CUNEIFORM SIGN NINDA2 TIMES BAL;Lo;0;L;;;;;N;;;;; -12392;CUNEIFORM SIGN NINDA2 TIMES GI;Lo;0;L;;;;;N;;;;; -12393;CUNEIFORM SIGN NU11 ROTATED NINETY DEGREES;Lo;0;L;;;;;N;;;;; -12394;CUNEIFORM SIGN PESH2 ASTERISK;Lo;0;L;;;;;N;;;;; -12395;CUNEIFORM SIGN PIR2;Lo;0;L;;;;;N;;;;; -12396;CUNEIFORM SIGN SAG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; -12397;CUNEIFORM SIGN TI2;Lo;0;L;;;;;N;;;;; -12398;CUNEIFORM SIGN UM TIMES ME;Lo;0;L;;;;;N;;;;; -12399;CUNEIFORM SIGN U U;Lo;0;L;;;;;N;;;;; -12400;CUNEIFORM NUMERIC SIGN TWO ASH;Nl;0;L;;;;2;N;;;;; -12401;CUNEIFORM NUMERIC SIGN THREE ASH;Nl;0;L;;;;3;N;;;;; -12402;CUNEIFORM NUMERIC SIGN FOUR ASH;Nl;0;L;;;;4;N;;;;; -12403;CUNEIFORM NUMERIC SIGN FIVE ASH;Nl;0;L;;;;5;N;;;;; -12404;CUNEIFORM NUMERIC SIGN SIX ASH;Nl;0;L;;;;6;N;;;;; -12405;CUNEIFORM NUMERIC SIGN SEVEN ASH;Nl;0;L;;;;7;N;;;;; -12406;CUNEIFORM NUMERIC SIGN EIGHT ASH;Nl;0;L;;;;8;N;;;;; -12407;CUNEIFORM NUMERIC SIGN NINE ASH;Nl;0;L;;;;9;N;;;;; -12408;CUNEIFORM NUMERIC SIGN THREE DISH;Nl;0;L;;;;3;N;;;;; -12409;CUNEIFORM NUMERIC SIGN FOUR DISH;Nl;0;L;;;;4;N;;;;; -1240A;CUNEIFORM NUMERIC SIGN FIVE DISH;Nl;0;L;;;;5;N;;;;; -1240B;CUNEIFORM NUMERIC SIGN SIX DISH;Nl;0;L;;;;6;N;;;;; -1240C;CUNEIFORM NUMERIC SIGN SEVEN DISH;Nl;0;L;;;;7;N;;;;; -1240D;CUNEIFORM NUMERIC SIGN EIGHT DISH;Nl;0;L;;;;8;N;;;;; -1240E;CUNEIFORM NUMERIC SIGN NINE DISH;Nl;0;L;;;;9;N;;;;; -1240F;CUNEIFORM NUMERIC SIGN FOUR U;Nl;0;L;;;;4;N;;;;; -12410;CUNEIFORM NUMERIC SIGN FIVE U;Nl;0;L;;;;5;N;;;;; -12411;CUNEIFORM NUMERIC SIGN SIX U;Nl;0;L;;;;6;N;;;;; -12412;CUNEIFORM NUMERIC SIGN SEVEN U;Nl;0;L;;;;7;N;;;;; -12413;CUNEIFORM NUMERIC SIGN EIGHT U;Nl;0;L;;;;8;N;;;;; -12414;CUNEIFORM NUMERIC SIGN NINE U;Nl;0;L;;;;9;N;;;;; -12415;CUNEIFORM NUMERIC SIGN ONE GESH2;Nl;0;L;;;;1;N;;;;; -12416;CUNEIFORM NUMERIC SIGN TWO GESH2;Nl;0;L;;;;2;N;;;;; -12417;CUNEIFORM NUMERIC SIGN THREE GESH2;Nl;0;L;;;;3;N;;;;; -12418;CUNEIFORM NUMERIC SIGN FOUR GESH2;Nl;0;L;;;;4;N;;;;; -12419;CUNEIFORM NUMERIC SIGN FIVE GESH2;Nl;0;L;;;;5;N;;;;; -1241A;CUNEIFORM NUMERIC SIGN SIX GESH2;Nl;0;L;;;;6;N;;;;; -1241B;CUNEIFORM NUMERIC SIGN SEVEN GESH2;Nl;0;L;;;;7;N;;;;; -1241C;CUNEIFORM NUMERIC SIGN EIGHT GESH2;Nl;0;L;;;;8;N;;;;; -1241D;CUNEIFORM NUMERIC SIGN NINE GESH2;Nl;0;L;;;;9;N;;;;; -1241E;CUNEIFORM NUMERIC SIGN ONE GESHU;Nl;0;L;;;;1;N;;;;; -1241F;CUNEIFORM NUMERIC SIGN TWO GESHU;Nl;0;L;;;;2;N;;;;; -12420;CUNEIFORM NUMERIC SIGN THREE GESHU;Nl;0;L;;;;3;N;;;;; -12421;CUNEIFORM NUMERIC SIGN FOUR GESHU;Nl;0;L;;;;4;N;;;;; -12422;CUNEIFORM NUMERIC SIGN FIVE GESHU;Nl;0;L;;;;5;N;;;;; -12423;CUNEIFORM NUMERIC SIGN TWO SHAR2;Nl;0;L;;;;2;N;;;;; -12424;CUNEIFORM NUMERIC SIGN THREE SHAR2;Nl;0;L;;;;3;N;;;;; -12425;CUNEIFORM NUMERIC SIGN THREE SHAR2 VARIANT FORM;Nl;0;L;;;;3;N;;;;; -12426;CUNEIFORM NUMERIC SIGN FOUR SHAR2;Nl;0;L;;;;4;N;;;;; -12427;CUNEIFORM NUMERIC SIGN FIVE SHAR2;Nl;0;L;;;;5;N;;;;; -12428;CUNEIFORM NUMERIC SIGN SIX SHAR2;Nl;0;L;;;;6;N;;;;; -12429;CUNEIFORM NUMERIC SIGN SEVEN SHAR2;Nl;0;L;;;;7;N;;;;; -1242A;CUNEIFORM NUMERIC SIGN EIGHT SHAR2;Nl;0;L;;;;8;N;;;;; -1242B;CUNEIFORM NUMERIC SIGN NINE SHAR2;Nl;0;L;;;;9;N;;;;; -1242C;CUNEIFORM NUMERIC SIGN ONE SHARU;Nl;0;L;;;;1;N;;;;; -1242D;CUNEIFORM NUMERIC SIGN TWO SHARU;Nl;0;L;;;;2;N;;;;; -1242E;CUNEIFORM NUMERIC SIGN THREE SHARU;Nl;0;L;;;;3;N;;;;; -1242F;CUNEIFORM NUMERIC SIGN THREE SHARU VARIANT FORM;Nl;0;L;;;;3;N;;;;; -12430;CUNEIFORM NUMERIC SIGN FOUR SHARU;Nl;0;L;;;;4;N;;;;; -12431;CUNEIFORM NUMERIC SIGN FIVE SHARU;Nl;0;L;;;;5;N;;;;; -12432;CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS DISH;Nl;0;L;;;;216000;N;;;;; -12433;CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS MIN;Nl;0;L;;;;432000;N;;;;; -12434;CUNEIFORM NUMERIC SIGN ONE BURU;Nl;0;L;;;;1;N;;;;; -12435;CUNEIFORM NUMERIC SIGN TWO BURU;Nl;0;L;;;;2;N;;;;; -12436;CUNEIFORM NUMERIC SIGN THREE BURU;Nl;0;L;;;;3;N;;;;; -12437;CUNEIFORM NUMERIC SIGN THREE BURU VARIANT FORM;Nl;0;L;;;;3;N;;;;; -12438;CUNEIFORM NUMERIC SIGN FOUR BURU;Nl;0;L;;;;4;N;;;;; -12439;CUNEIFORM NUMERIC SIGN FIVE BURU;Nl;0;L;;;;5;N;;;;; -1243A;CUNEIFORM NUMERIC SIGN THREE VARIANT FORM ESH16;Nl;0;L;;;;3;N;;;;; -1243B;CUNEIFORM NUMERIC SIGN THREE VARIANT FORM ESH21;Nl;0;L;;;;3;N;;;;; -1243C;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU;Nl;0;L;;;;4;N;;;;; -1243D;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU4;Nl;0;L;;;;4;N;;;;; -1243E;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU A;Nl;0;L;;;;4;N;;;;; -1243F;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU B;Nl;0;L;;;;4;N;;;;; -12440;CUNEIFORM NUMERIC SIGN SIX VARIANT FORM ASH9;Nl;0;L;;;;6;N;;;;; -12441;CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN3;Nl;0;L;;;;7;N;;;;; -12442;CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN A;Nl;0;L;;;;7;N;;;;; -12443;CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN B;Nl;0;L;;;;7;N;;;;; -12444;CUNEIFORM NUMERIC SIGN EIGHT VARIANT FORM USSU;Nl;0;L;;;;8;N;;;;; -12445;CUNEIFORM NUMERIC SIGN EIGHT VARIANT FORM USSU3;Nl;0;L;;;;8;N;;;;; -12446;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU;Nl;0;L;;;;9;N;;;;; -12447;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU3;Nl;0;L;;;;9;N;;;;; -12448;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU4;Nl;0;L;;;;9;N;;;;; -12449;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU A;Nl;0;L;;;;9;N;;;;; -1244A;CUNEIFORM NUMERIC SIGN TWO ASH TENU;Nl;0;L;;;;2;N;;;;; -1244B;CUNEIFORM NUMERIC SIGN THREE ASH TENU;Nl;0;L;;;;3;N;;;;; -1244C;CUNEIFORM NUMERIC SIGN FOUR ASH TENU;Nl;0;L;;;;4;N;;;;; -1244D;CUNEIFORM NUMERIC SIGN FIVE ASH TENU;Nl;0;L;;;;5;N;;;;; -1244E;CUNEIFORM NUMERIC SIGN SIX ASH TENU;Nl;0;L;;;;6;N;;;;; -1244F;CUNEIFORM NUMERIC SIGN ONE BAN2;Nl;0;L;;;;1;N;;;;; -12450;CUNEIFORM NUMERIC SIGN TWO BAN2;Nl;0;L;;;;2;N;;;;; -12451;CUNEIFORM NUMERIC SIGN THREE BAN2;Nl;0;L;;;;3;N;;;;; -12452;CUNEIFORM NUMERIC SIGN FOUR BAN2;Nl;0;L;;;;4;N;;;;; -12453;CUNEIFORM NUMERIC SIGN FOUR BAN2 VARIANT FORM;Nl;0;L;;;;4;N;;;;; -12454;CUNEIFORM NUMERIC SIGN FIVE BAN2;Nl;0;L;;;;5;N;;;;; -12455;CUNEIFORM NUMERIC SIGN FIVE BAN2 VARIANT FORM;Nl;0;L;;;;5;N;;;;; -12456;CUNEIFORM NUMERIC SIGN NIGIDAMIN;Nl;0;L;;;;2;N;;;;; -12457;CUNEIFORM NUMERIC SIGN NIGIDAESH;Nl;0;L;;;;3;N;;;;; -12458;CUNEIFORM NUMERIC SIGN ONE ESHE3;Nl;0;L;;;;1;N;;;;; -12459;CUNEIFORM NUMERIC SIGN TWO ESHE3;Nl;0;L;;;;2;N;;;;; -1245A;CUNEIFORM NUMERIC SIGN ONE THIRD DISH;Nl;0;L;;;;1/3;N;;;;; -1245B;CUNEIFORM NUMERIC SIGN TWO THIRDS DISH;Nl;0;L;;;;2/3;N;;;;; -1245C;CUNEIFORM NUMERIC SIGN FIVE SIXTHS DISH;Nl;0;L;;;;5/6;N;;;;; -1245D;CUNEIFORM NUMERIC SIGN ONE THIRD VARIANT FORM A;Nl;0;L;;;;1/3;N;;;;; -1245E;CUNEIFORM NUMERIC SIGN TWO THIRDS VARIANT FORM A;Nl;0;L;;;;2/3;N;;;;; -1245F;CUNEIFORM NUMERIC SIGN ONE EIGHTH ASH;Nl;0;L;;;;1/8;N;;;;; -12460;CUNEIFORM NUMERIC SIGN ONE QUARTER ASH;Nl;0;L;;;;1/4;N;;;;; -12461;CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE SIXTH;Nl;0;L;;;;1/6;N;;;;; -12462;CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE QUARTER;Nl;0;L;;;;1/4;N;;;;; -12463;CUNEIFORM NUMERIC SIGN ONE QUARTER GUR;Nl;0;L;;;;1/4;N;;;;; -12464;CUNEIFORM NUMERIC SIGN ONE HALF GUR;Nl;0;L;;;;1/2;N;;;;; -12465;CUNEIFORM NUMERIC SIGN ELAMITE ONE THIRD;Nl;0;L;;;;1/3;N;;;;; -12466;CUNEIFORM NUMERIC SIGN ELAMITE TWO THIRDS;Nl;0;L;;;;2/3;N;;;;; -12467;CUNEIFORM NUMERIC SIGN ELAMITE FORTY;Nl;0;L;;;;40;N;;;;; -12468;CUNEIFORM NUMERIC SIGN ELAMITE FIFTY;Nl;0;L;;;;50;N;;;;; -12469;CUNEIFORM NUMERIC SIGN FOUR U VARIANT FORM;Nl;0;L;;;;4;N;;;;; -1246A;CUNEIFORM NUMERIC SIGN FIVE U VARIANT FORM;Nl;0;L;;;;5;N;;;;; -1246B;CUNEIFORM NUMERIC SIGN SIX U VARIANT FORM;Nl;0;L;;;;6;N;;;;; -1246C;CUNEIFORM NUMERIC SIGN SEVEN U VARIANT FORM;Nl;0;L;;;;7;N;;;;; -1246D;CUNEIFORM NUMERIC SIGN EIGHT U VARIANT FORM;Nl;0;L;;;;8;N;;;;; -1246E;CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM;Nl;0;L;;;;9;N;;;;; -12470;CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER;Po;0;L;;;;;N;;;;; -12471;CUNEIFORM PUNCTUATION SIGN VERTICAL COLON;Po;0;L;;;;;N;;;;; -12472;CUNEIFORM PUNCTUATION SIGN DIAGONAL COLON;Po;0;L;;;;;N;;;;; -12473;CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON;Po;0;L;;;;;N;;;;; -12474;CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON;Po;0;L;;;;;N;;;;; -12480;CUNEIFORM SIGN AB TIMES NUN TENU;Lo;0;L;;;;;N;;;;; -12481;CUNEIFORM SIGN AB TIMES SHU2;Lo;0;L;;;;;N;;;;; -12482;CUNEIFORM SIGN AD TIMES ESH2;Lo;0;L;;;;;N;;;;; -12483;CUNEIFORM SIGN BAD TIMES DISH TENU;Lo;0;L;;;;;N;;;;; -12484;CUNEIFORM SIGN BAHAR2 TIMES AB2;Lo;0;L;;;;;N;;;;; -12485;CUNEIFORM SIGN BAHAR2 TIMES NI;Lo;0;L;;;;;N;;;;; -12486;CUNEIFORM SIGN BAHAR2 TIMES ZA;Lo;0;L;;;;;N;;;;; -12487;CUNEIFORM SIGN BU OVER BU TIMES NA2;Lo;0;L;;;;;N;;;;; -12488;CUNEIFORM SIGN DA TIMES TAK4;Lo;0;L;;;;;N;;;;; -12489;CUNEIFORM SIGN DAG TIMES KUR;Lo;0;L;;;;;N;;;;; -1248A;CUNEIFORM SIGN DIM TIMES IGI;Lo;0;L;;;;;N;;;;; -1248B;CUNEIFORM SIGN DIM TIMES U U U;Lo;0;L;;;;;N;;;;; -1248C;CUNEIFORM SIGN DIM2 TIMES UD;Lo;0;L;;;;;N;;;;; -1248D;CUNEIFORM SIGN DUG TIMES ANSHE;Lo;0;L;;;;;N;;;;; -1248E;CUNEIFORM SIGN DUG TIMES ASH;Lo;0;L;;;;;N;;;;; -1248F;CUNEIFORM SIGN DUG TIMES ASH AT LEFT;Lo;0;L;;;;;N;;;;; -12490;CUNEIFORM SIGN DUG TIMES DIN;Lo;0;L;;;;;N;;;;; -12491;CUNEIFORM SIGN DUG TIMES DUN;Lo;0;L;;;;;N;;;;; -12492;CUNEIFORM SIGN DUG TIMES ERIN2;Lo;0;L;;;;;N;;;;; -12493;CUNEIFORM SIGN DUG TIMES GA;Lo;0;L;;;;;N;;;;; -12494;CUNEIFORM SIGN DUG TIMES GI;Lo;0;L;;;;;N;;;;; -12495;CUNEIFORM SIGN DUG TIMES GIR2 GUNU;Lo;0;L;;;;;N;;;;; -12496;CUNEIFORM SIGN DUG TIMES GISH;Lo;0;L;;;;;N;;;;; -12497;CUNEIFORM SIGN DUG TIMES HA;Lo;0;L;;;;;N;;;;; -12498;CUNEIFORM SIGN DUG TIMES HI;Lo;0;L;;;;;N;;;;; -12499;CUNEIFORM SIGN DUG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; -1249A;CUNEIFORM SIGN DUG TIMES KASKAL;Lo;0;L;;;;;N;;;;; -1249B;CUNEIFORM SIGN DUG TIMES KUR;Lo;0;L;;;;;N;;;;; -1249C;CUNEIFORM SIGN DUG TIMES KUSHU2;Lo;0;L;;;;;N;;;;; -1249D;CUNEIFORM SIGN DUG TIMES KUSHU2 PLUS KASKAL;Lo;0;L;;;;;N;;;;; -1249E;CUNEIFORM SIGN DUG TIMES LAK-020;Lo;0;L;;;;;N;;;;; -1249F;CUNEIFORM SIGN DUG TIMES LAM;Lo;0;L;;;;;N;;;;; -124A0;CUNEIFORM SIGN DUG TIMES LAM TIMES KUR;Lo;0;L;;;;;N;;;;; -124A1;CUNEIFORM SIGN DUG TIMES LUH PLUS GISH;Lo;0;L;;;;;N;;;;; -124A2;CUNEIFORM SIGN DUG TIMES MASH;Lo;0;L;;;;;N;;;;; -124A3;CUNEIFORM SIGN DUG TIMES MES;Lo;0;L;;;;;N;;;;; -124A4;CUNEIFORM SIGN DUG TIMES MI;Lo;0;L;;;;;N;;;;; -124A5;CUNEIFORM SIGN DUG TIMES NI;Lo;0;L;;;;;N;;;;; -124A6;CUNEIFORM SIGN DUG TIMES PI;Lo;0;L;;;;;N;;;;; -124A7;CUNEIFORM SIGN DUG TIMES SHE;Lo;0;L;;;;;N;;;;; -124A8;CUNEIFORM SIGN DUG TIMES SI GUNU;Lo;0;L;;;;;N;;;;; -124A9;CUNEIFORM SIGN E2 TIMES KUR;Lo;0;L;;;;;N;;;;; -124AA;CUNEIFORM SIGN E2 TIMES PAP;Lo;0;L;;;;;N;;;;; -124AB;CUNEIFORM SIGN ERIN2 X;Lo;0;L;;;;;N;;;;; -124AC;CUNEIFORM SIGN ESH2 CROSSING ESH2;Lo;0;L;;;;;N;;;;; -124AD;CUNEIFORM SIGN EZEN SHESHIG TIMES ASH;Lo;0;L;;;;;N;;;;; -124AE;CUNEIFORM SIGN EZEN SHESHIG TIMES HI;Lo;0;L;;;;;N;;;;; -124AF;CUNEIFORM SIGN EZEN SHESHIG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; -124B0;CUNEIFORM SIGN EZEN SHESHIG TIMES LA;Lo;0;L;;;;;N;;;;; -124B1;CUNEIFORM SIGN EZEN SHESHIG TIMES LAL;Lo;0;L;;;;;N;;;;; -124B2;CUNEIFORM SIGN EZEN SHESHIG TIMES ME;Lo;0;L;;;;;N;;;;; -124B3;CUNEIFORM SIGN EZEN SHESHIG TIMES MES;Lo;0;L;;;;;N;;;;; -124B4;CUNEIFORM SIGN EZEN SHESHIG TIMES SU;Lo;0;L;;;;;N;;;;; -124B5;CUNEIFORM SIGN EZEN TIMES SU;Lo;0;L;;;;;N;;;;; -124B6;CUNEIFORM SIGN GA2 TIMES BAHAR2;Lo;0;L;;;;;N;;;;; -124B7;CUNEIFORM SIGN GA2 TIMES DIM GUNU;Lo;0;L;;;;;N;;;;; -124B8;CUNEIFORM SIGN GA2 TIMES DUG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; -124B9;CUNEIFORM SIGN GA2 TIMES DUG TIMES KASKAL;Lo;0;L;;;;;N;;;;; -124BA;CUNEIFORM SIGN GA2 TIMES EREN;Lo;0;L;;;;;N;;;;; -124BB;CUNEIFORM SIGN GA2 TIMES GA;Lo;0;L;;;;;N;;;;; -124BC;CUNEIFORM SIGN GA2 TIMES GAR PLUS DI;Lo;0;L;;;;;N;;;;; -124BD;CUNEIFORM SIGN GA2 TIMES GAR PLUS NE;Lo;0;L;;;;;N;;;;; -124BE;CUNEIFORM SIGN GA2 TIMES HA PLUS A;Lo;0;L;;;;;N;;;;; -124BF;CUNEIFORM SIGN GA2 TIMES KUSHU2 PLUS KASKAL;Lo;0;L;;;;;N;;;;; -124C0;CUNEIFORM SIGN GA2 TIMES LAM;Lo;0;L;;;;;N;;;;; -124C1;CUNEIFORM SIGN GA2 TIMES LAM TIMES KUR;Lo;0;L;;;;;N;;;;; -124C2;CUNEIFORM SIGN GA2 TIMES LUH;Lo;0;L;;;;;N;;;;; -124C3;CUNEIFORM SIGN GA2 TIMES MUSH;Lo;0;L;;;;;N;;;;; -124C4;CUNEIFORM SIGN GA2 TIMES NE;Lo;0;L;;;;;N;;;;; -124C5;CUNEIFORM SIGN GA2 TIMES NE PLUS E2;Lo;0;L;;;;;N;;;;; -124C6;CUNEIFORM SIGN GA2 TIMES NE PLUS GI;Lo;0;L;;;;;N;;;;; -124C7;CUNEIFORM SIGN GA2 TIMES SHIM;Lo;0;L;;;;;N;;;;; -124C8;CUNEIFORM SIGN GA2 TIMES ZIZ2;Lo;0;L;;;;;N;;;;; -124C9;CUNEIFORM SIGN GABA ROTATED NINETY DEGREES;Lo;0;L;;;;;N;;;;; -124CA;CUNEIFORM SIGN GESHTIN TIMES U;Lo;0;L;;;;;N;;;;; -124CB;CUNEIFORM SIGN GISH TIMES GISH CROSSING GISH;Lo;0;L;;;;;N;;;;; -124CC;CUNEIFORM SIGN GU2 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; -124CD;CUNEIFORM SIGN GUD PLUS GISH TIMES TAK4;Lo;0;L;;;;;N;;;;; -124CE;CUNEIFORM SIGN HA TENU GUNU;Lo;0;L;;;;;N;;;;; -124CF;CUNEIFORM SIGN HI TIMES ASH OVER HI TIMES ASH;Lo;0;L;;;;;N;;;;; -124D0;CUNEIFORM SIGN KA TIMES BU;Lo;0;L;;;;;N;;;;; -124D1;CUNEIFORM SIGN KA TIMES KA;Lo;0;L;;;;;N;;;;; -124D2;CUNEIFORM SIGN KA TIMES U U U;Lo;0;L;;;;;N;;;;; -124D3;CUNEIFORM SIGN KA TIMES UR;Lo;0;L;;;;;N;;;;; -124D4;CUNEIFORM SIGN LAGAB TIMES ZU OVER ZU;Lo;0;L;;;;;N;;;;; -124D5;CUNEIFORM SIGN LAK-003;Lo;0;L;;;;;N;;;;; -124D6;CUNEIFORM SIGN LAK-021;Lo;0;L;;;;;N;;;;; -124D7;CUNEIFORM SIGN LAK-025;Lo;0;L;;;;;N;;;;; -124D8;CUNEIFORM SIGN LAK-030;Lo;0;L;;;;;N;;;;; -124D9;CUNEIFORM SIGN LAK-050;Lo;0;L;;;;;N;;;;; -124DA;CUNEIFORM SIGN LAK-051;Lo;0;L;;;;;N;;;;; -124DB;CUNEIFORM SIGN LAK-062;Lo;0;L;;;;;N;;;;; -124DC;CUNEIFORM SIGN LAK-079 OVER LAK-079 GUNU;Lo;0;L;;;;;N;;;;; -124DD;CUNEIFORM SIGN LAK-080;Lo;0;L;;;;;N;;;;; -124DE;CUNEIFORM SIGN LAK-081 OVER LAK-081;Lo;0;L;;;;;N;;;;; -124DF;CUNEIFORM SIGN LAK-092;Lo;0;L;;;;;N;;;;; -124E0;CUNEIFORM SIGN LAK-130;Lo;0;L;;;;;N;;;;; -124E1;CUNEIFORM SIGN LAK-142;Lo;0;L;;;;;N;;;;; -124E2;CUNEIFORM SIGN LAK-210;Lo;0;L;;;;;N;;;;; -124E3;CUNEIFORM SIGN LAK-219;Lo;0;L;;;;;N;;;;; -124E4;CUNEIFORM SIGN LAK-220;Lo;0;L;;;;;N;;;;; -124E5;CUNEIFORM SIGN LAK-225;Lo;0;L;;;;;N;;;;; -124E6;CUNEIFORM SIGN LAK-228;Lo;0;L;;;;;N;;;;; -124E7;CUNEIFORM SIGN LAK-238;Lo;0;L;;;;;N;;;;; -124E8;CUNEIFORM SIGN LAK-265;Lo;0;L;;;;;N;;;;; -124E9;CUNEIFORM SIGN LAK-266;Lo;0;L;;;;;N;;;;; -124EA;CUNEIFORM SIGN LAK-343;Lo;0;L;;;;;N;;;;; -124EB;CUNEIFORM SIGN LAK-347;Lo;0;L;;;;;N;;;;; -124EC;CUNEIFORM SIGN LAK-348;Lo;0;L;;;;;N;;;;; -124ED;CUNEIFORM SIGN LAK-383;Lo;0;L;;;;;N;;;;; -124EE;CUNEIFORM SIGN LAK-384;Lo;0;L;;;;;N;;;;; -124EF;CUNEIFORM SIGN LAK-390;Lo;0;L;;;;;N;;;;; -124F0;CUNEIFORM SIGN LAK-441;Lo;0;L;;;;;N;;;;; -124F1;CUNEIFORM SIGN LAK-449;Lo;0;L;;;;;N;;;;; -124F2;CUNEIFORM SIGN LAK-449 TIMES GU;Lo;0;L;;;;;N;;;;; -124F3;CUNEIFORM SIGN LAK-449 TIMES IGI;Lo;0;L;;;;;N;;;;; -124F4;CUNEIFORM SIGN LAK-449 TIMES PAP PLUS LU3;Lo;0;L;;;;;N;;;;; -124F5;CUNEIFORM SIGN LAK-449 TIMES PAP PLUS PAP PLUS LU3;Lo;0;L;;;;;N;;;;; -124F6;CUNEIFORM SIGN LAK-449 TIMES U2 PLUS BA;Lo;0;L;;;;;N;;;;; -124F7;CUNEIFORM SIGN LAK-450;Lo;0;L;;;;;N;;;;; -124F8;CUNEIFORM SIGN LAK-457;Lo;0;L;;;;;N;;;;; -124F9;CUNEIFORM SIGN LAK-470;Lo;0;L;;;;;N;;;;; -124FA;CUNEIFORM SIGN LAK-483;Lo;0;L;;;;;N;;;;; -124FB;CUNEIFORM SIGN LAK-490;Lo;0;L;;;;;N;;;;; -124FC;CUNEIFORM SIGN LAK-492;Lo;0;L;;;;;N;;;;; -124FD;CUNEIFORM SIGN LAK-493;Lo;0;L;;;;;N;;;;; -124FE;CUNEIFORM SIGN LAK-495;Lo;0;L;;;;;N;;;;; -124FF;CUNEIFORM SIGN LAK-550;Lo;0;L;;;;;N;;;;; -12500;CUNEIFORM SIGN LAK-608;Lo;0;L;;;;;N;;;;; -12501;CUNEIFORM SIGN LAK-617;Lo;0;L;;;;;N;;;;; -12502;CUNEIFORM SIGN LAK-617 TIMES ASH;Lo;0;L;;;;;N;;;;; -12503;CUNEIFORM SIGN LAK-617 TIMES BAD;Lo;0;L;;;;;N;;;;; -12504;CUNEIFORM SIGN LAK-617 TIMES DUN3 GUNU GUNU;Lo;0;L;;;;;N;;;;; -12505;CUNEIFORM SIGN LAK-617 TIMES KU3;Lo;0;L;;;;;N;;;;; -12506;CUNEIFORM SIGN LAK-617 TIMES LA;Lo;0;L;;;;;N;;;;; -12507;CUNEIFORM SIGN LAK-617 TIMES TAR;Lo;0;L;;;;;N;;;;; -12508;CUNEIFORM SIGN LAK-617 TIMES TE;Lo;0;L;;;;;N;;;;; -12509;CUNEIFORM SIGN LAK-617 TIMES U2;Lo;0;L;;;;;N;;;;; -1250A;CUNEIFORM SIGN LAK-617 TIMES UD;Lo;0;L;;;;;N;;;;; -1250B;CUNEIFORM SIGN LAK-617 TIMES URUDA;Lo;0;L;;;;;N;;;;; -1250C;CUNEIFORM SIGN LAK-636;Lo;0;L;;;;;N;;;;; -1250D;CUNEIFORM SIGN LAK-648;Lo;0;L;;;;;N;;;;; -1250E;CUNEIFORM SIGN LAK-648 TIMES DUB;Lo;0;L;;;;;N;;;;; -1250F;CUNEIFORM SIGN LAK-648 TIMES GA;Lo;0;L;;;;;N;;;;; -12510;CUNEIFORM SIGN LAK-648 TIMES IGI;Lo;0;L;;;;;N;;;;; -12511;CUNEIFORM SIGN LAK-648 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; -12512;CUNEIFORM SIGN LAK-648 TIMES NI;Lo;0;L;;;;;N;;;;; -12513;CUNEIFORM SIGN LAK-648 TIMES PAP PLUS PAP PLUS LU3;Lo;0;L;;;;;N;;;;; -12514;CUNEIFORM SIGN LAK-648 TIMES SHESH PLUS KI;Lo;0;L;;;;;N;;;;; -12515;CUNEIFORM SIGN LAK-648 TIMES UD;Lo;0;L;;;;;N;;;;; -12516;CUNEIFORM SIGN LAK-648 TIMES URUDA;Lo;0;L;;;;;N;;;;; -12517;CUNEIFORM SIGN LAK-724;Lo;0;L;;;;;N;;;;; -12518;CUNEIFORM SIGN LAK-749;Lo;0;L;;;;;N;;;;; -12519;CUNEIFORM SIGN LU2 GUNU TIMES ASH;Lo;0;L;;;;;N;;;;; -1251A;CUNEIFORM SIGN LU2 TIMES DISH;Lo;0;L;;;;;N;;;;; -1251B;CUNEIFORM SIGN LU2 TIMES HAL;Lo;0;L;;;;;N;;;;; -1251C;CUNEIFORM SIGN LU2 TIMES PAP;Lo;0;L;;;;;N;;;;; -1251D;CUNEIFORM SIGN LU2 TIMES PAP PLUS PAP PLUS LU3;Lo;0;L;;;;;N;;;;; -1251E;CUNEIFORM SIGN LU2 TIMES TAK4;Lo;0;L;;;;;N;;;;; -1251F;CUNEIFORM SIGN MI PLUS ZA7;Lo;0;L;;;;;N;;;;; -12520;CUNEIFORM SIGN MUSH OVER MUSH TIMES GA;Lo;0;L;;;;;N;;;;; -12521;CUNEIFORM SIGN MUSH OVER MUSH TIMES KAK;Lo;0;L;;;;;N;;;;; -12522;CUNEIFORM SIGN NINDA2 TIMES DIM GUNU;Lo;0;L;;;;;N;;;;; -12523;CUNEIFORM SIGN NINDA2 TIMES GISH;Lo;0;L;;;;;N;;;;; -12524;CUNEIFORM SIGN NINDA2 TIMES GUL;Lo;0;L;;;;;N;;;;; -12525;CUNEIFORM SIGN NINDA2 TIMES HI;Lo;0;L;;;;;N;;;;; -12526;CUNEIFORM SIGN NINDA2 TIMES KESH2;Lo;0;L;;;;;N;;;;; -12527;CUNEIFORM SIGN NINDA2 TIMES LAK-050;Lo;0;L;;;;;N;;;;; -12528;CUNEIFORM SIGN NINDA2 TIMES MASH;Lo;0;L;;;;;N;;;;; -12529;CUNEIFORM SIGN NINDA2 TIMES PAP PLUS PAP;Lo;0;L;;;;;N;;;;; -1252A;CUNEIFORM SIGN NINDA2 TIMES U;Lo;0;L;;;;;N;;;;; -1252B;CUNEIFORM SIGN NINDA2 TIMES U PLUS U;Lo;0;L;;;;;N;;;;; -1252C;CUNEIFORM SIGN NINDA2 TIMES URUDA;Lo;0;L;;;;;N;;;;; -1252D;CUNEIFORM SIGN SAG GUNU TIMES HA;Lo;0;L;;;;;N;;;;; -1252E;CUNEIFORM SIGN SAG TIMES EN;Lo;0;L;;;;;N;;;;; -1252F;CUNEIFORM SIGN SAG TIMES SHE AT LEFT;Lo;0;L;;;;;N;;;;; -12530;CUNEIFORM SIGN SAG TIMES TAK4;Lo;0;L;;;;;N;;;;; -12531;CUNEIFORM SIGN SHA6 TENU;Lo;0;L;;;;;N;;;;; -12532;CUNEIFORM SIGN SHE OVER SHE;Lo;0;L;;;;;N;;;;; -12533;CUNEIFORM SIGN SHE PLUS HUB2;Lo;0;L;;;;;N;;;;; -12534;CUNEIFORM SIGN SHE PLUS NAM2;Lo;0;L;;;;;N;;;;; -12535;CUNEIFORM SIGN SHE PLUS SAR;Lo;0;L;;;;;N;;;;; -12536;CUNEIFORM SIGN SHU2 PLUS DUG TIMES NI;Lo;0;L;;;;;N;;;;; -12537;CUNEIFORM SIGN SHU2 PLUS E2 TIMES AN;Lo;0;L;;;;;N;;;;; -12538;CUNEIFORM SIGN SI TIMES TAK4;Lo;0;L;;;;;N;;;;; -12539;CUNEIFORM SIGN TAK4 PLUS SAG;Lo;0;L;;;;;N;;;;; -1253A;CUNEIFORM SIGN TUM TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;; -1253B;CUNEIFORM SIGN TUM TIMES THREE DISH;Lo;0;L;;;;;N;;;;; -1253C;CUNEIFORM SIGN UR2 INVERTED;Lo;0;L;;;;;N;;;;; -1253D;CUNEIFORM SIGN UR2 TIMES UD;Lo;0;L;;;;;N;;;;; -1253E;CUNEIFORM SIGN URU TIMES DARA3;Lo;0;L;;;;;N;;;;; -1253F;CUNEIFORM SIGN URU TIMES LAK-668;Lo;0;L;;;;;N;;;;; -12540;CUNEIFORM SIGN URU TIMES LU3;Lo;0;L;;;;;N;;;;; -12541;CUNEIFORM SIGN ZA7;Lo;0;L;;;;;N;;;;; -12542;CUNEIFORM SIGN ZU OVER ZU PLUS SAR;Lo;0;L;;;;;N;;;;; -12543;CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU;Lo;0;L;;;;;N;;;;; -12F90;CYPRO-MINOAN SIGN CM001;Lo;0;L;;;;;N;;;;; -12F91;CYPRO-MINOAN SIGN CM002;Lo;0;L;;;;;N;;;;; -12F92;CYPRO-MINOAN SIGN CM004;Lo;0;L;;;;;N;;;;; -12F93;CYPRO-MINOAN SIGN CM005;Lo;0;L;;;;;N;;;;; -12F94;CYPRO-MINOAN SIGN CM006;Lo;0;L;;;;;N;;;;; -12F95;CYPRO-MINOAN SIGN CM007;Lo;0;L;;;;;N;;;;; -12F96;CYPRO-MINOAN SIGN CM008;Lo;0;L;;;;;N;;;;; -12F97;CYPRO-MINOAN SIGN CM009;Lo;0;L;;;;;N;;;;; -12F98;CYPRO-MINOAN SIGN CM010;Lo;0;L;;;;;N;;;;; -12F99;CYPRO-MINOAN SIGN CM011;Lo;0;L;;;;;N;;;;; -12F9A;CYPRO-MINOAN SIGN CM012;Lo;0;L;;;;;N;;;;; -12F9B;CYPRO-MINOAN SIGN CM012B;Lo;0;L;;;;;N;;;;; -12F9C;CYPRO-MINOAN SIGN CM013;Lo;0;L;;;;;N;;;;; -12F9D;CYPRO-MINOAN SIGN CM015;Lo;0;L;;;;;N;;;;; -12F9E;CYPRO-MINOAN SIGN CM017;Lo;0;L;;;;;N;;;;; -12F9F;CYPRO-MINOAN SIGN CM019;Lo;0;L;;;;;N;;;;; -12FA0;CYPRO-MINOAN SIGN CM021;Lo;0;L;;;;;N;;;;; -12FA1;CYPRO-MINOAN SIGN CM023;Lo;0;L;;;;;N;;;;; -12FA2;CYPRO-MINOAN SIGN CM024;Lo;0;L;;;;;N;;;;; -12FA3;CYPRO-MINOAN SIGN CM025;Lo;0;L;;;;;N;;;;; -12FA4;CYPRO-MINOAN SIGN CM026;Lo;0;L;;;;;N;;;;; -12FA5;CYPRO-MINOAN SIGN CM027;Lo;0;L;;;;;N;;;;; -12FA6;CYPRO-MINOAN SIGN CM028;Lo;0;L;;;;;N;;;;; -12FA7;CYPRO-MINOAN SIGN CM029;Lo;0;L;;;;;N;;;;; -12FA8;CYPRO-MINOAN SIGN CM030;Lo;0;L;;;;;N;;;;; -12FA9;CYPRO-MINOAN SIGN CM033;Lo;0;L;;;;;N;;;;; -12FAA;CYPRO-MINOAN SIGN CM034;Lo;0;L;;;;;N;;;;; -12FAB;CYPRO-MINOAN SIGN CM035;Lo;0;L;;;;;N;;;;; -12FAC;CYPRO-MINOAN SIGN CM036;Lo;0;L;;;;;N;;;;; -12FAD;CYPRO-MINOAN SIGN CM037;Lo;0;L;;;;;N;;;;; -12FAE;CYPRO-MINOAN SIGN CM038;Lo;0;L;;;;;N;;;;; -12FAF;CYPRO-MINOAN SIGN CM039;Lo;0;L;;;;;N;;;;; -12FB0;CYPRO-MINOAN SIGN CM040;Lo;0;L;;;;;N;;;;; -12FB1;CYPRO-MINOAN SIGN CM041;Lo;0;L;;;;;N;;;;; -12FB2;CYPRO-MINOAN SIGN CM044;Lo;0;L;;;;;N;;;;; -12FB3;CYPRO-MINOAN SIGN CM046;Lo;0;L;;;;;N;;;;; -12FB4;CYPRO-MINOAN SIGN CM047;Lo;0;L;;;;;N;;;;; -12FB5;CYPRO-MINOAN SIGN CM049;Lo;0;L;;;;;N;;;;; -12FB6;CYPRO-MINOAN SIGN CM050;Lo;0;L;;;;;N;;;;; -12FB7;CYPRO-MINOAN SIGN CM051;Lo;0;L;;;;;N;;;;; -12FB8;CYPRO-MINOAN SIGN CM052;Lo;0;L;;;;;N;;;;; -12FB9;CYPRO-MINOAN SIGN CM053;Lo;0;L;;;;;N;;;;; -12FBA;CYPRO-MINOAN SIGN CM054;Lo;0;L;;;;;N;;;;; -12FBB;CYPRO-MINOAN SIGN CM055;Lo;0;L;;;;;N;;;;; -12FBC;CYPRO-MINOAN SIGN CM056;Lo;0;L;;;;;N;;;;; -12FBD;CYPRO-MINOAN SIGN CM058;Lo;0;L;;;;;N;;;;; -12FBE;CYPRO-MINOAN SIGN CM059;Lo;0;L;;;;;N;;;;; -12FBF;CYPRO-MINOAN SIGN CM060;Lo;0;L;;;;;N;;;;; -12FC0;CYPRO-MINOAN SIGN CM061;Lo;0;L;;;;;N;;;;; -12FC1;CYPRO-MINOAN SIGN CM062;Lo;0;L;;;;;N;;;;; -12FC2;CYPRO-MINOAN SIGN CM063;Lo;0;L;;;;;N;;;;; -12FC3;CYPRO-MINOAN SIGN CM064;Lo;0;L;;;;;N;;;;; -12FC4;CYPRO-MINOAN SIGN CM066;Lo;0;L;;;;;N;;;;; -12FC5;CYPRO-MINOAN SIGN CM067;Lo;0;L;;;;;N;;;;; -12FC6;CYPRO-MINOAN SIGN CM068;Lo;0;L;;;;;N;;;;; -12FC7;CYPRO-MINOAN SIGN CM069;Lo;0;L;;;;;N;;;;; -12FC8;CYPRO-MINOAN SIGN CM070;Lo;0;L;;;;;N;;;;; -12FC9;CYPRO-MINOAN SIGN CM071;Lo;0;L;;;;;N;;;;; -12FCA;CYPRO-MINOAN SIGN CM072;Lo;0;L;;;;;N;;;;; -12FCB;CYPRO-MINOAN SIGN CM073;Lo;0;L;;;;;N;;;;; -12FCC;CYPRO-MINOAN SIGN CM074;Lo;0;L;;;;;N;;;;; -12FCD;CYPRO-MINOAN SIGN CM075;Lo;0;L;;;;;N;;;;; -12FCE;CYPRO-MINOAN SIGN CM075B;Lo;0;L;;;;;N;;;;; -12FCF;CYPRO-MINOAN SIGN CM076;Lo;0;L;;;;;N;;;;; -12FD0;CYPRO-MINOAN SIGN CM078;Lo;0;L;;;;;N;;;;; -12FD1;CYPRO-MINOAN SIGN CM079;Lo;0;L;;;;;N;;;;; -12FD2;CYPRO-MINOAN SIGN CM080;Lo;0;L;;;;;N;;;;; -12FD3;CYPRO-MINOAN SIGN CM081;Lo;0;L;;;;;N;;;;; -12FD4;CYPRO-MINOAN SIGN CM082;Lo;0;L;;;;;N;;;;; -12FD5;CYPRO-MINOAN SIGN CM083;Lo;0;L;;;;;N;;;;; -12FD6;CYPRO-MINOAN SIGN CM084;Lo;0;L;;;;;N;;;;; -12FD7;CYPRO-MINOAN SIGN CM085;Lo;0;L;;;;;N;;;;; -12FD8;CYPRO-MINOAN SIGN CM086;Lo;0;L;;;;;N;;;;; -12FD9;CYPRO-MINOAN SIGN CM087;Lo;0;L;;;;;N;;;;; -12FDA;CYPRO-MINOAN SIGN CM088;Lo;0;L;;;;;N;;;;; -12FDB;CYPRO-MINOAN SIGN CM089;Lo;0;L;;;;;N;;;;; -12FDC;CYPRO-MINOAN SIGN CM090;Lo;0;L;;;;;N;;;;; -12FDD;CYPRO-MINOAN SIGN CM091;Lo;0;L;;;;;N;;;;; -12FDE;CYPRO-MINOAN SIGN CM092;Lo;0;L;;;;;N;;;;; -12FDF;CYPRO-MINOAN SIGN CM094;Lo;0;L;;;;;N;;;;; -12FE0;CYPRO-MINOAN SIGN CM095;Lo;0;L;;;;;N;;;;; -12FE1;CYPRO-MINOAN SIGN CM096;Lo;0;L;;;;;N;;;;; -12FE2;CYPRO-MINOAN SIGN CM097;Lo;0;L;;;;;N;;;;; -12FE3;CYPRO-MINOAN SIGN CM098;Lo;0;L;;;;;N;;;;; -12FE4;CYPRO-MINOAN SIGN CM099;Lo;0;L;;;;;N;;;;; -12FE5;CYPRO-MINOAN SIGN CM100;Lo;0;L;;;;;N;;;;; -12FE6;CYPRO-MINOAN SIGN CM101;Lo;0;L;;;;;N;;;;; -12FE7;CYPRO-MINOAN SIGN CM102;Lo;0;L;;;;;N;;;;; -12FE8;CYPRO-MINOAN SIGN CM103;Lo;0;L;;;;;N;;;;; -12FE9;CYPRO-MINOAN SIGN CM104;Lo;0;L;;;;;N;;;;; -12FEA;CYPRO-MINOAN SIGN CM105;Lo;0;L;;;;;N;;;;; -12FEB;CYPRO-MINOAN SIGN CM107;Lo;0;L;;;;;N;;;;; -12FEC;CYPRO-MINOAN SIGN CM108;Lo;0;L;;;;;N;;;;; -12FED;CYPRO-MINOAN SIGN CM109;Lo;0;L;;;;;N;;;;; -12FEE;CYPRO-MINOAN SIGN CM110;Lo;0;L;;;;;N;;;;; -12FEF;CYPRO-MINOAN SIGN CM112;Lo;0;L;;;;;N;;;;; -12FF0;CYPRO-MINOAN SIGN CM114;Lo;0;L;;;;;N;;;;; -12FF1;CYPRO-MINOAN SIGN CM301;Po;0;L;;;;;N;;;;; -12FF2;CYPRO-MINOAN SIGN CM302;Po;0;L;;;;;N;;;;; -13000;EGYPTIAN HIEROGLYPH A001;Lo;0;L;;;;;N;;;;; -13001;EGYPTIAN HIEROGLYPH A002;Lo;0;L;;;;;N;;;;; -13002;EGYPTIAN HIEROGLYPH A003;Lo;0;L;;;;;N;;;;; -13003;EGYPTIAN HIEROGLYPH A004;Lo;0;L;;;;;N;;;;; -13004;EGYPTIAN HIEROGLYPH A005;Lo;0;L;;;;;N;;;;; -13005;EGYPTIAN HIEROGLYPH A005A;Lo;0;L;;;;;N;;;;; -13006;EGYPTIAN HIEROGLYPH A006;Lo;0;L;;;;;N;;;;; -13007;EGYPTIAN HIEROGLYPH A006A;Lo;0;L;;;;;N;;;;; -13008;EGYPTIAN HIEROGLYPH A006B;Lo;0;L;;;;;N;;;;; -13009;EGYPTIAN HIEROGLYPH A007;Lo;0;L;;;;;N;;;;; -1300A;EGYPTIAN HIEROGLYPH A008;Lo;0;L;;;;;N;;;;; -1300B;EGYPTIAN HIEROGLYPH A009;Lo;0;L;;;;;N;;;;; -1300C;EGYPTIAN HIEROGLYPH A010;Lo;0;L;;;;;N;;;;; -1300D;EGYPTIAN HIEROGLYPH A011;Lo;0;L;;;;;N;;;;; -1300E;EGYPTIAN HIEROGLYPH A012;Lo;0;L;;;;;N;;;;; -1300F;EGYPTIAN HIEROGLYPH A013;Lo;0;L;;;;;N;;;;; -13010;EGYPTIAN HIEROGLYPH A014;Lo;0;L;;;;;N;;;;; -13011;EGYPTIAN HIEROGLYPH A014A;Lo;0;L;;;;;N;;;;; -13012;EGYPTIAN HIEROGLYPH A015;Lo;0;L;;;;;N;;;;; -13013;EGYPTIAN HIEROGLYPH A016;Lo;0;L;;;;;N;;;;; -13014;EGYPTIAN HIEROGLYPH A017;Lo;0;L;;;;;N;;;;; -13015;EGYPTIAN HIEROGLYPH A017A;Lo;0;L;;;;;N;;;;; -13016;EGYPTIAN HIEROGLYPH A018;Lo;0;L;;;;;N;;;;; -13017;EGYPTIAN HIEROGLYPH A019;Lo;0;L;;;;;N;;;;; -13018;EGYPTIAN HIEROGLYPH A020;Lo;0;L;;;;;N;;;;; -13019;EGYPTIAN HIEROGLYPH A021;Lo;0;L;;;;;N;;;;; -1301A;EGYPTIAN HIEROGLYPH A022;Lo;0;L;;;;;N;;;;; -1301B;EGYPTIAN HIEROGLYPH A023;Lo;0;L;;;;;N;;;;; -1301C;EGYPTIAN HIEROGLYPH A024;Lo;0;L;;;;;N;;;;; -1301D;EGYPTIAN HIEROGLYPH A025;Lo;0;L;;;;;N;;;;; -1301E;EGYPTIAN HIEROGLYPH A026;Lo;0;L;;;;;N;;;;; -1301F;EGYPTIAN HIEROGLYPH A027;Lo;0;L;;;;;N;;;;; -13020;EGYPTIAN HIEROGLYPH A028;Lo;0;L;;;;;N;;;;; -13021;EGYPTIAN HIEROGLYPH A029;Lo;0;L;;;;;N;;;;; -13022;EGYPTIAN HIEROGLYPH A030;Lo;0;L;;;;;N;;;;; -13023;EGYPTIAN HIEROGLYPH A031;Lo;0;L;;;;;N;;;;; -13024;EGYPTIAN HIEROGLYPH A032;Lo;0;L;;;;;N;;;;; -13025;EGYPTIAN HIEROGLYPH A032A;Lo;0;L;;;;;N;;;;; -13026;EGYPTIAN HIEROGLYPH A033;Lo;0;L;;;;;N;;;;; -13027;EGYPTIAN HIEROGLYPH A034;Lo;0;L;;;;;N;;;;; -13028;EGYPTIAN HIEROGLYPH A035;Lo;0;L;;;;;N;;;;; -13029;EGYPTIAN HIEROGLYPH A036;Lo;0;L;;;;;N;;;;; -1302A;EGYPTIAN HIEROGLYPH A037;Lo;0;L;;;;;N;;;;; -1302B;EGYPTIAN HIEROGLYPH A038;Lo;0;L;;;;;N;;;;; -1302C;EGYPTIAN HIEROGLYPH A039;Lo;0;L;;;;;N;;;;; -1302D;EGYPTIAN HIEROGLYPH A040;Lo;0;L;;;;;N;;;;; -1302E;EGYPTIAN HIEROGLYPH A040A;Lo;0;L;;;;;N;;;;; -1302F;EGYPTIAN HIEROGLYPH A041;Lo;0;L;;;;;N;;;;; -13030;EGYPTIAN HIEROGLYPH A042;Lo;0;L;;;;;N;;;;; -13031;EGYPTIAN HIEROGLYPH A042A;Lo;0;L;;;;;N;;;;; -13032;EGYPTIAN HIEROGLYPH A043;Lo;0;L;;;;;N;;;;; -13033;EGYPTIAN HIEROGLYPH A043A;Lo;0;L;;;;;N;;;;; -13034;EGYPTIAN HIEROGLYPH A044;Lo;0;L;;;;;N;;;;; -13035;EGYPTIAN HIEROGLYPH A045;Lo;0;L;;;;;N;;;;; -13036;EGYPTIAN HIEROGLYPH A045A;Lo;0;L;;;;;N;;;;; -13037;EGYPTIAN HIEROGLYPH A046;Lo;0;L;;;;;N;;;;; -13038;EGYPTIAN HIEROGLYPH A047;Lo;0;L;;;;;N;;;;; -13039;EGYPTIAN HIEROGLYPH A048;Lo;0;L;;;;;N;;;;; -1303A;EGYPTIAN HIEROGLYPH A049;Lo;0;L;;;;;N;;;;; -1303B;EGYPTIAN HIEROGLYPH A050;Lo;0;L;;;;;N;;;;; -1303C;EGYPTIAN HIEROGLYPH A051;Lo;0;L;;;;;N;;;;; -1303D;EGYPTIAN HIEROGLYPH A052;Lo;0;L;;;;;N;;;;; -1303E;EGYPTIAN HIEROGLYPH A053;Lo;0;L;;;;;N;;;;; -1303F;EGYPTIAN HIEROGLYPH A054;Lo;0;L;;;;;N;;;;; -13040;EGYPTIAN HIEROGLYPH A055;Lo;0;L;;;;;N;;;;; -13041;EGYPTIAN HIEROGLYPH A056;Lo;0;L;;;;;N;;;;; -13042;EGYPTIAN HIEROGLYPH A057;Lo;0;L;;;;;N;;;;; -13043;EGYPTIAN HIEROGLYPH A058;Lo;0;L;;;;;N;;;;; -13044;EGYPTIAN HIEROGLYPH A059;Lo;0;L;;;;;N;;;;; -13045;EGYPTIAN HIEROGLYPH A060;Lo;0;L;;;;;N;;;;; -13046;EGYPTIAN HIEROGLYPH A061;Lo;0;L;;;;;N;;;;; -13047;EGYPTIAN HIEROGLYPH A062;Lo;0;L;;;;;N;;;;; -13048;EGYPTIAN HIEROGLYPH A063;Lo;0;L;;;;;N;;;;; -13049;EGYPTIAN HIEROGLYPH A064;Lo;0;L;;;;;N;;;;; -1304A;EGYPTIAN HIEROGLYPH A065;Lo;0;L;;;;;N;;;;; -1304B;EGYPTIAN HIEROGLYPH A066;Lo;0;L;;;;;N;;;;; -1304C;EGYPTIAN HIEROGLYPH A067;Lo;0;L;;;;;N;;;;; -1304D;EGYPTIAN HIEROGLYPH A068;Lo;0;L;;;;;N;;;;; -1304E;EGYPTIAN HIEROGLYPH A069;Lo;0;L;;;;;N;;;;; -1304F;EGYPTIAN HIEROGLYPH A070;Lo;0;L;;;;;N;;;;; -13050;EGYPTIAN HIEROGLYPH B001;Lo;0;L;;;;;N;;;;; -13051;EGYPTIAN HIEROGLYPH B002;Lo;0;L;;;;;N;;;;; -13052;EGYPTIAN HIEROGLYPH B003;Lo;0;L;;;;;N;;;;; -13053;EGYPTIAN HIEROGLYPH B004;Lo;0;L;;;;;N;;;;; -13054;EGYPTIAN HIEROGLYPH B005;Lo;0;L;;;;;N;;;;; -13055;EGYPTIAN HIEROGLYPH B005A;Lo;0;L;;;;;N;;;;; -13056;EGYPTIAN HIEROGLYPH B006;Lo;0;L;;;;;N;;;;; -13057;EGYPTIAN HIEROGLYPH B007;Lo;0;L;;;;;N;;;;; -13058;EGYPTIAN HIEROGLYPH B008;Lo;0;L;;;;;N;;;;; -13059;EGYPTIAN HIEROGLYPH B009;Lo;0;L;;;;;N;;;;; -1305A;EGYPTIAN HIEROGLYPH C001;Lo;0;L;;;;;N;;;;; -1305B;EGYPTIAN HIEROGLYPH C002;Lo;0;L;;;;;N;;;;; -1305C;EGYPTIAN HIEROGLYPH C002A;Lo;0;L;;;;;N;;;;; -1305D;EGYPTIAN HIEROGLYPH C002B;Lo;0;L;;;;;N;;;;; -1305E;EGYPTIAN HIEROGLYPH C002C;Lo;0;L;;;;;N;;;;; -1305F;EGYPTIAN HIEROGLYPH C003;Lo;0;L;;;;;N;;;;; -13060;EGYPTIAN HIEROGLYPH C004;Lo;0;L;;;;;N;;;;; -13061;EGYPTIAN HIEROGLYPH C005;Lo;0;L;;;;;N;;;;; -13062;EGYPTIAN HIEROGLYPH C006;Lo;0;L;;;;;N;;;;; -13063;EGYPTIAN HIEROGLYPH C007;Lo;0;L;;;;;N;;;;; -13064;EGYPTIAN HIEROGLYPH C008;Lo;0;L;;;;;N;;;;; -13065;EGYPTIAN HIEROGLYPH C009;Lo;0;L;;;;;N;;;;; -13066;EGYPTIAN HIEROGLYPH C010;Lo;0;L;;;;;N;;;;; -13067;EGYPTIAN HIEROGLYPH C010A;Lo;0;L;;;;;N;;;;; -13068;EGYPTIAN HIEROGLYPH C011;Lo;0;L;;;;;N;;;;; -13069;EGYPTIAN HIEROGLYPH C012;Lo;0;L;;;;;N;;;;; -1306A;EGYPTIAN HIEROGLYPH C013;Lo;0;L;;;;;N;;;;; -1306B;EGYPTIAN HIEROGLYPH C014;Lo;0;L;;;;;N;;;;; -1306C;EGYPTIAN HIEROGLYPH C015;Lo;0;L;;;;;N;;;;; -1306D;EGYPTIAN HIEROGLYPH C016;Lo;0;L;;;;;N;;;;; -1306E;EGYPTIAN HIEROGLYPH C017;Lo;0;L;;;;;N;;;;; -1306F;EGYPTIAN HIEROGLYPH C018;Lo;0;L;;;;;N;;;;; -13070;EGYPTIAN HIEROGLYPH C019;Lo;0;L;;;;;N;;;;; -13071;EGYPTIAN HIEROGLYPH C020;Lo;0;L;;;;;N;;;;; -13072;EGYPTIAN HIEROGLYPH C021;Lo;0;L;;;;;N;;;;; -13073;EGYPTIAN HIEROGLYPH C022;Lo;0;L;;;;;N;;;;; -13074;EGYPTIAN HIEROGLYPH C023;Lo;0;L;;;;;N;;;;; -13075;EGYPTIAN HIEROGLYPH C024;Lo;0;L;;;;;N;;;;; -13076;EGYPTIAN HIEROGLYPH D001;Lo;0;L;;;;;N;;;;; -13077;EGYPTIAN HIEROGLYPH D002;Lo;0;L;;;;;N;;;;; -13078;EGYPTIAN HIEROGLYPH D003;Lo;0;L;;;;;N;;;;; -13079;EGYPTIAN HIEROGLYPH D004;Lo;0;L;;;;;N;;;;; -1307A;EGYPTIAN HIEROGLYPH D005;Lo;0;L;;;;;N;;;;; -1307B;EGYPTIAN HIEROGLYPH D006;Lo;0;L;;;;;N;;;;; -1307C;EGYPTIAN HIEROGLYPH D007;Lo;0;L;;;;;N;;;;; -1307D;EGYPTIAN HIEROGLYPH D008;Lo;0;L;;;;;N;;;;; -1307E;EGYPTIAN HIEROGLYPH D008A;Lo;0;L;;;;;N;;;;; -1307F;EGYPTIAN HIEROGLYPH D009;Lo;0;L;;;;;N;;;;; -13080;EGYPTIAN HIEROGLYPH D010;Lo;0;L;;;;;N;;;;; -13081;EGYPTIAN HIEROGLYPH D011;Lo;0;L;;;;;N;;;;; -13082;EGYPTIAN HIEROGLYPH D012;Lo;0;L;;;;;N;;;;; -13083;EGYPTIAN HIEROGLYPH D013;Lo;0;L;;;;;N;;;;; -13084;EGYPTIAN HIEROGLYPH D014;Lo;0;L;;;;;N;;;;; -13085;EGYPTIAN HIEROGLYPH D015;Lo;0;L;;;;;N;;;;; -13086;EGYPTIAN HIEROGLYPH D016;Lo;0;L;;;;;N;;;;; -13087;EGYPTIAN HIEROGLYPH D017;Lo;0;L;;;;;N;;;;; -13088;EGYPTIAN HIEROGLYPH D018;Lo;0;L;;;;;N;;;;; -13089;EGYPTIAN HIEROGLYPH D019;Lo;0;L;;;;;N;;;;; -1308A;EGYPTIAN HIEROGLYPH D020;Lo;0;L;;;;;N;;;;; -1308B;EGYPTIAN HIEROGLYPH D021;Lo;0;L;;;;;N;;;;; -1308C;EGYPTIAN HIEROGLYPH D022;Lo;0;L;;;;;N;;;;; -1308D;EGYPTIAN HIEROGLYPH D023;Lo;0;L;;;;;N;;;;; -1308E;EGYPTIAN HIEROGLYPH D024;Lo;0;L;;;;;N;;;;; -1308F;EGYPTIAN HIEROGLYPH D025;Lo;0;L;;;;;N;;;;; -13090;EGYPTIAN HIEROGLYPH D026;Lo;0;L;;;;;N;;;;; -13091;EGYPTIAN HIEROGLYPH D027;Lo;0;L;;;;;N;;;;; -13092;EGYPTIAN HIEROGLYPH D027A;Lo;0;L;;;;;N;;;;; -13093;EGYPTIAN HIEROGLYPH D028;Lo;0;L;;;;;N;;;;; -13094;EGYPTIAN HIEROGLYPH D029;Lo;0;L;;;;;N;;;;; -13095;EGYPTIAN HIEROGLYPH D030;Lo;0;L;;;;;N;;;;; -13096;EGYPTIAN HIEROGLYPH D031;Lo;0;L;;;;;N;;;;; -13097;EGYPTIAN HIEROGLYPH D031A;Lo;0;L;;;;;N;;;;; -13098;EGYPTIAN HIEROGLYPH D032;Lo;0;L;;;;;N;;;;; -13099;EGYPTIAN HIEROGLYPH D033;Lo;0;L;;;;;N;;;;; -1309A;EGYPTIAN HIEROGLYPH D034;Lo;0;L;;;;;N;;;;; -1309B;EGYPTIAN HIEROGLYPH D034A;Lo;0;L;;;;;N;;;;; -1309C;EGYPTIAN HIEROGLYPH D035;Lo;0;L;;;;;N;;;;; -1309D;EGYPTIAN HIEROGLYPH D036;Lo;0;L;;;;;N;;;;; -1309E;EGYPTIAN HIEROGLYPH D037;Lo;0;L;;;;;N;;;;; -1309F;EGYPTIAN HIEROGLYPH D038;Lo;0;L;;;;;N;;;;; -130A0;EGYPTIAN HIEROGLYPH D039;Lo;0;L;;;;;N;;;;; -130A1;EGYPTIAN HIEROGLYPH D040;Lo;0;L;;;;;N;;;;; -130A2;EGYPTIAN HIEROGLYPH D041;Lo;0;L;;;;;N;;;;; -130A3;EGYPTIAN HIEROGLYPH D042;Lo;0;L;;;;;N;;;;; -130A4;EGYPTIAN HIEROGLYPH D043;Lo;0;L;;;;;N;;;;; -130A5;EGYPTIAN HIEROGLYPH D044;Lo;0;L;;;;;N;;;;; -130A6;EGYPTIAN HIEROGLYPH D045;Lo;0;L;;;;;N;;;;; -130A7;EGYPTIAN HIEROGLYPH D046;Lo;0;L;;;;;N;;;;; -130A8;EGYPTIAN HIEROGLYPH D046A;Lo;0;L;;;;;N;;;;; -130A9;EGYPTIAN HIEROGLYPH D047;Lo;0;L;;;;;N;;;;; -130AA;EGYPTIAN HIEROGLYPH D048;Lo;0;L;;;;;N;;;;; -130AB;EGYPTIAN HIEROGLYPH D048A;Lo;0;L;;;;;N;;;;; -130AC;EGYPTIAN HIEROGLYPH D049;Lo;0;L;;;;;N;;;;; -130AD;EGYPTIAN HIEROGLYPH D050;Lo;0;L;;;;;N;;;;; -130AE;EGYPTIAN HIEROGLYPH D050A;Lo;0;L;;;;;N;;;;; -130AF;EGYPTIAN HIEROGLYPH D050B;Lo;0;L;;;;;N;;;;; -130B0;EGYPTIAN HIEROGLYPH D050C;Lo;0;L;;;;;N;;;;; -130B1;EGYPTIAN HIEROGLYPH D050D;Lo;0;L;;;;;N;;;;; -130B2;EGYPTIAN HIEROGLYPH D050E;Lo;0;L;;;;;N;;;;; -130B3;EGYPTIAN HIEROGLYPH D050F;Lo;0;L;;;;;N;;;;; -130B4;EGYPTIAN HIEROGLYPH D050G;Lo;0;L;;;;;N;;;;; -130B5;EGYPTIAN HIEROGLYPH D050H;Lo;0;L;;;;;N;;;;; -130B6;EGYPTIAN HIEROGLYPH D050I;Lo;0;L;;;;;N;;;;; -130B7;EGYPTIAN HIEROGLYPH D051;Lo;0;L;;;;;N;;;;; -130B8;EGYPTIAN HIEROGLYPH D052;Lo;0;L;;;;;N;;;;; -130B9;EGYPTIAN HIEROGLYPH D052A;Lo;0;L;;;;;N;;;;; -130BA;EGYPTIAN HIEROGLYPH D053;Lo;0;L;;;;;N;;;;; -130BB;EGYPTIAN HIEROGLYPH D054;Lo;0;L;;;;;N;;;;; -130BC;EGYPTIAN HIEROGLYPH D054A;Lo;0;L;;;;;N;;;;; -130BD;EGYPTIAN HIEROGLYPH D055;Lo;0;L;;;;;N;;;;; -130BE;EGYPTIAN HIEROGLYPH D056;Lo;0;L;;;;;N;;;;; -130BF;EGYPTIAN HIEROGLYPH D057;Lo;0;L;;;;;N;;;;; -130C0;EGYPTIAN HIEROGLYPH D058;Lo;0;L;;;;;N;;;;; -130C1;EGYPTIAN HIEROGLYPH D059;Lo;0;L;;;;;N;;;;; -130C2;EGYPTIAN HIEROGLYPH D060;Lo;0;L;;;;;N;;;;; -130C3;EGYPTIAN HIEROGLYPH D061;Lo;0;L;;;;;N;;;;; -130C4;EGYPTIAN HIEROGLYPH D062;Lo;0;L;;;;;N;;;;; -130C5;EGYPTIAN HIEROGLYPH D063;Lo;0;L;;;;;N;;;;; -130C6;EGYPTIAN HIEROGLYPH D064;Lo;0;L;;;;;N;;;;; -130C7;EGYPTIAN HIEROGLYPH D065;Lo;0;L;;;;;N;;;;; -130C8;EGYPTIAN HIEROGLYPH D066;Lo;0;L;;;;;N;;;;; -130C9;EGYPTIAN HIEROGLYPH D067;Lo;0;L;;;;;N;;;;; -130CA;EGYPTIAN HIEROGLYPH D067A;Lo;0;L;;;;;N;;;;; -130CB;EGYPTIAN HIEROGLYPH D067B;Lo;0;L;;;;;N;;;;; -130CC;EGYPTIAN HIEROGLYPH D067C;Lo;0;L;;;;;N;;;;; -130CD;EGYPTIAN HIEROGLYPH D067D;Lo;0;L;;;;;N;;;;; -130CE;EGYPTIAN HIEROGLYPH D067E;Lo;0;L;;;;;N;;;;; -130CF;EGYPTIAN HIEROGLYPH D067F;Lo;0;L;;;;;N;;;;; -130D0;EGYPTIAN HIEROGLYPH D067G;Lo;0;L;;;;;N;;;;; -130D1;EGYPTIAN HIEROGLYPH D067H;Lo;0;L;;;;;N;;;;; -130D2;EGYPTIAN HIEROGLYPH E001;Lo;0;L;;;;;N;;;;; -130D3;EGYPTIAN HIEROGLYPH E002;Lo;0;L;;;;;N;;;;; -130D4;EGYPTIAN HIEROGLYPH E003;Lo;0;L;;;;;N;;;;; -130D5;EGYPTIAN HIEROGLYPH E004;Lo;0;L;;;;;N;;;;; -130D6;EGYPTIAN HIEROGLYPH E005;Lo;0;L;;;;;N;;;;; -130D7;EGYPTIAN HIEROGLYPH E006;Lo;0;L;;;;;N;;;;; -130D8;EGYPTIAN HIEROGLYPH E007;Lo;0;L;;;;;N;;;;; -130D9;EGYPTIAN HIEROGLYPH E008;Lo;0;L;;;;;N;;;;; -130DA;EGYPTIAN HIEROGLYPH E008A;Lo;0;L;;;;;N;;;;; -130DB;EGYPTIAN HIEROGLYPH E009;Lo;0;L;;;;;N;;;;; -130DC;EGYPTIAN HIEROGLYPH E009A;Lo;0;L;;;;;N;;;;; -130DD;EGYPTIAN HIEROGLYPH E010;Lo;0;L;;;;;N;;;;; -130DE;EGYPTIAN HIEROGLYPH E011;Lo;0;L;;;;;N;;;;; -130DF;EGYPTIAN HIEROGLYPH E012;Lo;0;L;;;;;N;;;;; -130E0;EGYPTIAN HIEROGLYPH E013;Lo;0;L;;;;;N;;;;; -130E1;EGYPTIAN HIEROGLYPH E014;Lo;0;L;;;;;N;;;;; -130E2;EGYPTIAN HIEROGLYPH E015;Lo;0;L;;;;;N;;;;; -130E3;EGYPTIAN HIEROGLYPH E016;Lo;0;L;;;;;N;;;;; -130E4;EGYPTIAN HIEROGLYPH E016A;Lo;0;L;;;;;N;;;;; -130E5;EGYPTIAN HIEROGLYPH E017;Lo;0;L;;;;;N;;;;; -130E6;EGYPTIAN HIEROGLYPH E017A;Lo;0;L;;;;;N;;;;; -130E7;EGYPTIAN HIEROGLYPH E018;Lo;0;L;;;;;N;;;;; -130E8;EGYPTIAN HIEROGLYPH E019;Lo;0;L;;;;;N;;;;; -130E9;EGYPTIAN HIEROGLYPH E020;Lo;0;L;;;;;N;;;;; -130EA;EGYPTIAN HIEROGLYPH E020A;Lo;0;L;;;;;N;;;;; -130EB;EGYPTIAN HIEROGLYPH E021;Lo;0;L;;;;;N;;;;; -130EC;EGYPTIAN HIEROGLYPH E022;Lo;0;L;;;;;N;;;;; -130ED;EGYPTIAN HIEROGLYPH E023;Lo;0;L;;;;;N;;;;; -130EE;EGYPTIAN HIEROGLYPH E024;Lo;0;L;;;;;N;;;;; -130EF;EGYPTIAN HIEROGLYPH E025;Lo;0;L;;;;;N;;;;; -130F0;EGYPTIAN HIEROGLYPH E026;Lo;0;L;;;;;N;;;;; -130F1;EGYPTIAN HIEROGLYPH E027;Lo;0;L;;;;;N;;;;; -130F2;EGYPTIAN HIEROGLYPH E028;Lo;0;L;;;;;N;;;;; -130F3;EGYPTIAN HIEROGLYPH E028A;Lo;0;L;;;;;N;;;;; -130F4;EGYPTIAN HIEROGLYPH E029;Lo;0;L;;;;;N;;;;; -130F5;EGYPTIAN HIEROGLYPH E030;Lo;0;L;;;;;N;;;;; -130F6;EGYPTIAN HIEROGLYPH E031;Lo;0;L;;;;;N;;;;; -130F7;EGYPTIAN HIEROGLYPH E032;Lo;0;L;;;;;N;;;;; -130F8;EGYPTIAN HIEROGLYPH E033;Lo;0;L;;;;;N;;;;; -130F9;EGYPTIAN HIEROGLYPH E034;Lo;0;L;;;;;N;;;;; -130FA;EGYPTIAN HIEROGLYPH E034A;Lo;0;L;;;;;N;;;;; -130FB;EGYPTIAN HIEROGLYPH E036;Lo;0;L;;;;;N;;;;; -130FC;EGYPTIAN HIEROGLYPH E037;Lo;0;L;;;;;N;;;;; -130FD;EGYPTIAN HIEROGLYPH E038;Lo;0;L;;;;;N;;;;; -130FE;EGYPTIAN HIEROGLYPH F001;Lo;0;L;;;;;N;;;;; -130FF;EGYPTIAN HIEROGLYPH F001A;Lo;0;L;;;;;N;;;;; -13100;EGYPTIAN HIEROGLYPH F002;Lo;0;L;;;;;N;;;;; -13101;EGYPTIAN HIEROGLYPH F003;Lo;0;L;;;;;N;;;;; -13102;EGYPTIAN HIEROGLYPH F004;Lo;0;L;;;;;N;;;;; -13103;EGYPTIAN HIEROGLYPH F005;Lo;0;L;;;;;N;;;;; -13104;EGYPTIAN HIEROGLYPH F006;Lo;0;L;;;;;N;;;;; -13105;EGYPTIAN HIEROGLYPH F007;Lo;0;L;;;;;N;;;;; -13106;EGYPTIAN HIEROGLYPH F008;Lo;0;L;;;;;N;;;;; -13107;EGYPTIAN HIEROGLYPH F009;Lo;0;L;;;;;N;;;;; -13108;EGYPTIAN HIEROGLYPH F010;Lo;0;L;;;;;N;;;;; -13109;EGYPTIAN HIEROGLYPH F011;Lo;0;L;;;;;N;;;;; -1310A;EGYPTIAN HIEROGLYPH F012;Lo;0;L;;;;;N;;;;; -1310B;EGYPTIAN HIEROGLYPH F013;Lo;0;L;;;;;N;;;;; -1310C;EGYPTIAN HIEROGLYPH F013A;Lo;0;L;;;;;N;;;;; -1310D;EGYPTIAN HIEROGLYPH F014;Lo;0;L;;;;;N;;;;; -1310E;EGYPTIAN HIEROGLYPH F015;Lo;0;L;;;;;N;;;;; -1310F;EGYPTIAN HIEROGLYPH F016;Lo;0;L;;;;;N;;;;; -13110;EGYPTIAN HIEROGLYPH F017;Lo;0;L;;;;;N;;;;; -13111;EGYPTIAN HIEROGLYPH F018;Lo;0;L;;;;;N;;;;; -13112;EGYPTIAN HIEROGLYPH F019;Lo;0;L;;;;;N;;;;; -13113;EGYPTIAN HIEROGLYPH F020;Lo;0;L;;;;;N;;;;; -13114;EGYPTIAN HIEROGLYPH F021;Lo;0;L;;;;;N;;;;; -13115;EGYPTIAN HIEROGLYPH F021A;Lo;0;L;;;;;N;;;;; -13116;EGYPTIAN HIEROGLYPH F022;Lo;0;L;;;;;N;;;;; -13117;EGYPTIAN HIEROGLYPH F023;Lo;0;L;;;;;N;;;;; -13118;EGYPTIAN HIEROGLYPH F024;Lo;0;L;;;;;N;;;;; -13119;EGYPTIAN HIEROGLYPH F025;Lo;0;L;;;;;N;;;;; -1311A;EGYPTIAN HIEROGLYPH F026;Lo;0;L;;;;;N;;;;; -1311B;EGYPTIAN HIEROGLYPH F027;Lo;0;L;;;;;N;;;;; -1311C;EGYPTIAN HIEROGLYPH F028;Lo;0;L;;;;;N;;;;; -1311D;EGYPTIAN HIEROGLYPH F029;Lo;0;L;;;;;N;;;;; -1311E;EGYPTIAN HIEROGLYPH F030;Lo;0;L;;;;;N;;;;; -1311F;EGYPTIAN HIEROGLYPH F031;Lo;0;L;;;;;N;;;;; -13120;EGYPTIAN HIEROGLYPH F031A;Lo;0;L;;;;;N;;;;; -13121;EGYPTIAN HIEROGLYPH F032;Lo;0;L;;;;;N;;;;; -13122;EGYPTIAN HIEROGLYPH F033;Lo;0;L;;;;;N;;;;; -13123;EGYPTIAN HIEROGLYPH F034;Lo;0;L;;;;;N;;;;; -13124;EGYPTIAN HIEROGLYPH F035;Lo;0;L;;;;;N;;;;; -13125;EGYPTIAN HIEROGLYPH F036;Lo;0;L;;;;;N;;;;; -13126;EGYPTIAN HIEROGLYPH F037;Lo;0;L;;;;;N;;;;; -13127;EGYPTIAN HIEROGLYPH F037A;Lo;0;L;;;;;N;;;;; -13128;EGYPTIAN HIEROGLYPH F038;Lo;0;L;;;;;N;;;;; -13129;EGYPTIAN HIEROGLYPH F038A;Lo;0;L;;;;;N;;;;; -1312A;EGYPTIAN HIEROGLYPH F039;Lo;0;L;;;;;N;;;;; -1312B;EGYPTIAN HIEROGLYPH F040;Lo;0;L;;;;;N;;;;; -1312C;EGYPTIAN HIEROGLYPH F041;Lo;0;L;;;;;N;;;;; -1312D;EGYPTIAN HIEROGLYPH F042;Lo;0;L;;;;;N;;;;; -1312E;EGYPTIAN HIEROGLYPH F043;Lo;0;L;;;;;N;;;;; -1312F;EGYPTIAN HIEROGLYPH F044;Lo;0;L;;;;;N;;;;; -13130;EGYPTIAN HIEROGLYPH F045;Lo;0;L;;;;;N;;;;; -13131;EGYPTIAN HIEROGLYPH F045A;Lo;0;L;;;;;N;;;;; -13132;EGYPTIAN HIEROGLYPH F046;Lo;0;L;;;;;N;;;;; -13133;EGYPTIAN HIEROGLYPH F046A;Lo;0;L;;;;;N;;;;; -13134;EGYPTIAN HIEROGLYPH F047;Lo;0;L;;;;;N;;;;; -13135;EGYPTIAN HIEROGLYPH F047A;Lo;0;L;;;;;N;;;;; -13136;EGYPTIAN HIEROGLYPH F048;Lo;0;L;;;;;N;;;;; -13137;EGYPTIAN HIEROGLYPH F049;Lo;0;L;;;;;N;;;;; -13138;EGYPTIAN HIEROGLYPH F050;Lo;0;L;;;;;N;;;;; -13139;EGYPTIAN HIEROGLYPH F051;Lo;0;L;;;;;N;;;;; -1313A;EGYPTIAN HIEROGLYPH F051A;Lo;0;L;;;;;N;;;;; -1313B;EGYPTIAN HIEROGLYPH F051B;Lo;0;L;;;;;N;;;;; -1313C;EGYPTIAN HIEROGLYPH F051C;Lo;0;L;;;;;N;;;;; -1313D;EGYPTIAN HIEROGLYPH F052;Lo;0;L;;;;;N;;;;; -1313E;EGYPTIAN HIEROGLYPH F053;Lo;0;L;;;;;N;;;;; -1313F;EGYPTIAN HIEROGLYPH G001;Lo;0;L;;;;;N;;;;; -13140;EGYPTIAN HIEROGLYPH G002;Lo;0;L;;;;;N;;;;; -13141;EGYPTIAN HIEROGLYPH G003;Lo;0;L;;;;;N;;;;; -13142;EGYPTIAN HIEROGLYPH G004;Lo;0;L;;;;;N;;;;; -13143;EGYPTIAN HIEROGLYPH G005;Lo;0;L;;;;;N;;;;; -13144;EGYPTIAN HIEROGLYPH G006;Lo;0;L;;;;;N;;;;; -13145;EGYPTIAN HIEROGLYPH G006A;Lo;0;L;;;;;N;;;;; -13146;EGYPTIAN HIEROGLYPH G007;Lo;0;L;;;;;N;;;;; -13147;EGYPTIAN HIEROGLYPH G007A;Lo;0;L;;;;;N;;;;; -13148;EGYPTIAN HIEROGLYPH G007B;Lo;0;L;;;;;N;;;;; -13149;EGYPTIAN HIEROGLYPH G008;Lo;0;L;;;;;N;;;;; -1314A;EGYPTIAN HIEROGLYPH G009;Lo;0;L;;;;;N;;;;; -1314B;EGYPTIAN HIEROGLYPH G010;Lo;0;L;;;;;N;;;;; -1314C;EGYPTIAN HIEROGLYPH G011;Lo;0;L;;;;;N;;;;; -1314D;EGYPTIAN HIEROGLYPH G011A;Lo;0;L;;;;;N;;;;; -1314E;EGYPTIAN HIEROGLYPH G012;Lo;0;L;;;;;N;;;;; -1314F;EGYPTIAN HIEROGLYPH G013;Lo;0;L;;;;;N;;;;; -13150;EGYPTIAN HIEROGLYPH G014;Lo;0;L;;;;;N;;;;; -13151;EGYPTIAN HIEROGLYPH G015;Lo;0;L;;;;;N;;;;; -13152;EGYPTIAN HIEROGLYPH G016;Lo;0;L;;;;;N;;;;; -13153;EGYPTIAN HIEROGLYPH G017;Lo;0;L;;;;;N;;;;; -13154;EGYPTIAN HIEROGLYPH G018;Lo;0;L;;;;;N;;;;; -13155;EGYPTIAN HIEROGLYPH G019;Lo;0;L;;;;;N;;;;; -13156;EGYPTIAN HIEROGLYPH G020;Lo;0;L;;;;;N;;;;; -13157;EGYPTIAN HIEROGLYPH G020A;Lo;0;L;;;;;N;;;;; -13158;EGYPTIAN HIEROGLYPH G021;Lo;0;L;;;;;N;;;;; -13159;EGYPTIAN HIEROGLYPH G022;Lo;0;L;;;;;N;;;;; -1315A;EGYPTIAN HIEROGLYPH G023;Lo;0;L;;;;;N;;;;; -1315B;EGYPTIAN HIEROGLYPH G024;Lo;0;L;;;;;N;;;;; -1315C;EGYPTIAN HIEROGLYPH G025;Lo;0;L;;;;;N;;;;; -1315D;EGYPTIAN HIEROGLYPH G026;Lo;0;L;;;;;N;;;;; -1315E;EGYPTIAN HIEROGLYPH G026A;Lo;0;L;;;;;N;;;;; -1315F;EGYPTIAN HIEROGLYPH G027;Lo;0;L;;;;;N;;;;; -13160;EGYPTIAN HIEROGLYPH G028;Lo;0;L;;;;;N;;;;; -13161;EGYPTIAN HIEROGLYPH G029;Lo;0;L;;;;;N;;;;; -13162;EGYPTIAN HIEROGLYPH G030;Lo;0;L;;;;;N;;;;; -13163;EGYPTIAN HIEROGLYPH G031;Lo;0;L;;;;;N;;;;; -13164;EGYPTIAN HIEROGLYPH G032;Lo;0;L;;;;;N;;;;; -13165;EGYPTIAN HIEROGLYPH G033;Lo;0;L;;;;;N;;;;; -13166;EGYPTIAN HIEROGLYPH G034;Lo;0;L;;;;;N;;;;; -13167;EGYPTIAN HIEROGLYPH G035;Lo;0;L;;;;;N;;;;; -13168;EGYPTIAN HIEROGLYPH G036;Lo;0;L;;;;;N;;;;; -13169;EGYPTIAN HIEROGLYPH G036A;Lo;0;L;;;;;N;;;;; -1316A;EGYPTIAN HIEROGLYPH G037;Lo;0;L;;;;;N;;;;; -1316B;EGYPTIAN HIEROGLYPH G037A;Lo;0;L;;;;;N;;;;; -1316C;EGYPTIAN HIEROGLYPH G038;Lo;0;L;;;;;N;;;;; -1316D;EGYPTIAN HIEROGLYPH G039;Lo;0;L;;;;;N;;;;; -1316E;EGYPTIAN HIEROGLYPH G040;Lo;0;L;;;;;N;;;;; -1316F;EGYPTIAN HIEROGLYPH G041;Lo;0;L;;;;;N;;;;; -13170;EGYPTIAN HIEROGLYPH G042;Lo;0;L;;;;;N;;;;; -13171;EGYPTIAN HIEROGLYPH G043;Lo;0;L;;;;;N;;;;; -13172;EGYPTIAN HIEROGLYPH G043A;Lo;0;L;;;;;N;;;;; -13173;EGYPTIAN HIEROGLYPH G044;Lo;0;L;;;;;N;;;;; -13174;EGYPTIAN HIEROGLYPH G045;Lo;0;L;;;;;N;;;;; -13175;EGYPTIAN HIEROGLYPH G045A;Lo;0;L;;;;;N;;;;; -13176;EGYPTIAN HIEROGLYPH G046;Lo;0;L;;;;;N;;;;; -13177;EGYPTIAN HIEROGLYPH G047;Lo;0;L;;;;;N;;;;; -13178;EGYPTIAN HIEROGLYPH G048;Lo;0;L;;;;;N;;;;; -13179;EGYPTIAN HIEROGLYPH G049;Lo;0;L;;;;;N;;;;; -1317A;EGYPTIAN HIEROGLYPH G050;Lo;0;L;;;;;N;;;;; -1317B;EGYPTIAN HIEROGLYPH G051;Lo;0;L;;;;;N;;;;; -1317C;EGYPTIAN HIEROGLYPH G052;Lo;0;L;;;;;N;;;;; -1317D;EGYPTIAN HIEROGLYPH G053;Lo;0;L;;;;;N;;;;; -1317E;EGYPTIAN HIEROGLYPH G054;Lo;0;L;;;;;N;;;;; -1317F;EGYPTIAN HIEROGLYPH H001;Lo;0;L;;;;;N;;;;; -13180;EGYPTIAN HIEROGLYPH H002;Lo;0;L;;;;;N;;;;; -13181;EGYPTIAN HIEROGLYPH H003;Lo;0;L;;;;;N;;;;; -13182;EGYPTIAN HIEROGLYPH H004;Lo;0;L;;;;;N;;;;; -13183;EGYPTIAN HIEROGLYPH H005;Lo;0;L;;;;;N;;;;; -13184;EGYPTIAN HIEROGLYPH H006;Lo;0;L;;;;;N;;;;; -13185;EGYPTIAN HIEROGLYPH H006A;Lo;0;L;;;;;N;;;;; -13186;EGYPTIAN HIEROGLYPH H007;Lo;0;L;;;;;N;;;;; -13187;EGYPTIAN HIEROGLYPH H008;Lo;0;L;;;;;N;;;;; -13188;EGYPTIAN HIEROGLYPH I001;Lo;0;L;;;;;N;;;;; -13189;EGYPTIAN HIEROGLYPH I002;Lo;0;L;;;;;N;;;;; -1318A;EGYPTIAN HIEROGLYPH I003;Lo;0;L;;;;;N;;;;; -1318B;EGYPTIAN HIEROGLYPH I004;Lo;0;L;;;;;N;;;;; -1318C;EGYPTIAN HIEROGLYPH I005;Lo;0;L;;;;;N;;;;; -1318D;EGYPTIAN HIEROGLYPH I005A;Lo;0;L;;;;;N;;;;; -1318E;EGYPTIAN HIEROGLYPH I006;Lo;0;L;;;;;N;;;;; -1318F;EGYPTIAN HIEROGLYPH I007;Lo;0;L;;;;;N;;;;; -13190;EGYPTIAN HIEROGLYPH I008;Lo;0;L;;;;;N;;;;; -13191;EGYPTIAN HIEROGLYPH I009;Lo;0;L;;;;;N;;;;; -13192;EGYPTIAN HIEROGLYPH I009A;Lo;0;L;;;;;N;;;;; -13193;EGYPTIAN HIEROGLYPH I010;Lo;0;L;;;;;N;;;;; -13194;EGYPTIAN HIEROGLYPH I010A;Lo;0;L;;;;;N;;;;; -13195;EGYPTIAN HIEROGLYPH I011;Lo;0;L;;;;;N;;;;; -13196;EGYPTIAN HIEROGLYPH I011A;Lo;0;L;;;;;N;;;;; -13197;EGYPTIAN HIEROGLYPH I012;Lo;0;L;;;;;N;;;;; -13198;EGYPTIAN HIEROGLYPH I013;Lo;0;L;;;;;N;;;;; -13199;EGYPTIAN HIEROGLYPH I014;Lo;0;L;;;;;N;;;;; -1319A;EGYPTIAN HIEROGLYPH I015;Lo;0;L;;;;;N;;;;; -1319B;EGYPTIAN HIEROGLYPH K001;Lo;0;L;;;;;N;;;;; -1319C;EGYPTIAN HIEROGLYPH K002;Lo;0;L;;;;;N;;;;; -1319D;EGYPTIAN HIEROGLYPH K003;Lo;0;L;;;;;N;;;;; -1319E;EGYPTIAN HIEROGLYPH K004;Lo;0;L;;;;;N;;;;; -1319F;EGYPTIAN HIEROGLYPH K005;Lo;0;L;;;;;N;;;;; -131A0;EGYPTIAN HIEROGLYPH K006;Lo;0;L;;;;;N;;;;; -131A1;EGYPTIAN HIEROGLYPH K007;Lo;0;L;;;;;N;;;;; -131A2;EGYPTIAN HIEROGLYPH K008;Lo;0;L;;;;;N;;;;; -131A3;EGYPTIAN HIEROGLYPH L001;Lo;0;L;;;;;N;;;;; -131A4;EGYPTIAN HIEROGLYPH L002;Lo;0;L;;;;;N;;;;; -131A5;EGYPTIAN HIEROGLYPH L002A;Lo;0;L;;;;;N;;;;; -131A6;EGYPTIAN HIEROGLYPH L003;Lo;0;L;;;;;N;;;;; -131A7;EGYPTIAN HIEROGLYPH L004;Lo;0;L;;;;;N;;;;; -131A8;EGYPTIAN HIEROGLYPH L005;Lo;0;L;;;;;N;;;;; -131A9;EGYPTIAN HIEROGLYPH L006;Lo;0;L;;;;;N;;;;; -131AA;EGYPTIAN HIEROGLYPH L006A;Lo;0;L;;;;;N;;;;; -131AB;EGYPTIAN HIEROGLYPH L007;Lo;0;L;;;;;N;;;;; -131AC;EGYPTIAN HIEROGLYPH L008;Lo;0;L;;;;;N;;;;; -131AD;EGYPTIAN HIEROGLYPH M001;Lo;0;L;;;;;N;;;;; -131AE;EGYPTIAN HIEROGLYPH M001A;Lo;0;L;;;;;N;;;;; -131AF;EGYPTIAN HIEROGLYPH M001B;Lo;0;L;;;;;N;;;;; -131B0;EGYPTIAN HIEROGLYPH M002;Lo;0;L;;;;;N;;;;; -131B1;EGYPTIAN HIEROGLYPH M003;Lo;0;L;;;;;N;;;;; -131B2;EGYPTIAN HIEROGLYPH M003A;Lo;0;L;;;;;N;;;;; -131B3;EGYPTIAN HIEROGLYPH M004;Lo;0;L;;;;;N;;;;; -131B4;EGYPTIAN HIEROGLYPH M005;Lo;0;L;;;;;N;;;;; -131B5;EGYPTIAN HIEROGLYPH M006;Lo;0;L;;;;;N;;;;; -131B6;EGYPTIAN HIEROGLYPH M007;Lo;0;L;;;;;N;;;;; -131B7;EGYPTIAN HIEROGLYPH M008;Lo;0;L;;;;;N;;;;; -131B8;EGYPTIAN HIEROGLYPH M009;Lo;0;L;;;;;N;;;;; -131B9;EGYPTIAN HIEROGLYPH M010;Lo;0;L;;;;;N;;;;; -131BA;EGYPTIAN HIEROGLYPH M010A;Lo;0;L;;;;;N;;;;; -131BB;EGYPTIAN HIEROGLYPH M011;Lo;0;L;;;;;N;;;;; -131BC;EGYPTIAN HIEROGLYPH M012;Lo;0;L;;;;;N;;;;; -131BD;EGYPTIAN HIEROGLYPH M012A;Lo;0;L;;;;;N;;;;; -131BE;EGYPTIAN HIEROGLYPH M012B;Lo;0;L;;;;;N;;;;; -131BF;EGYPTIAN HIEROGLYPH M012C;Lo;0;L;;;;;N;;;;; -131C0;EGYPTIAN HIEROGLYPH M012D;Lo;0;L;;;;;N;;;;; -131C1;EGYPTIAN HIEROGLYPH M012E;Lo;0;L;;;;;N;;;;; -131C2;EGYPTIAN HIEROGLYPH M012F;Lo;0;L;;;;;N;;;;; -131C3;EGYPTIAN HIEROGLYPH M012G;Lo;0;L;;;;;N;;;;; -131C4;EGYPTIAN HIEROGLYPH M012H;Lo;0;L;;;;;N;;;;; -131C5;EGYPTIAN HIEROGLYPH M013;Lo;0;L;;;;;N;;;;; -131C6;EGYPTIAN HIEROGLYPH M014;Lo;0;L;;;;;N;;;;; -131C7;EGYPTIAN HIEROGLYPH M015;Lo;0;L;;;;;N;;;;; -131C8;EGYPTIAN HIEROGLYPH M015A;Lo;0;L;;;;;N;;;;; -131C9;EGYPTIAN HIEROGLYPH M016;Lo;0;L;;;;;N;;;;; -131CA;EGYPTIAN HIEROGLYPH M016A;Lo;0;L;;;;;N;;;;; -131CB;EGYPTIAN HIEROGLYPH M017;Lo;0;L;;;;;N;;;;; -131CC;EGYPTIAN HIEROGLYPH M017A;Lo;0;L;;;;;N;;;;; -131CD;EGYPTIAN HIEROGLYPH M018;Lo;0;L;;;;;N;;;;; -131CE;EGYPTIAN HIEROGLYPH M019;Lo;0;L;;;;;N;;;;; -131CF;EGYPTIAN HIEROGLYPH M020;Lo;0;L;;;;;N;;;;; -131D0;EGYPTIAN HIEROGLYPH M021;Lo;0;L;;;;;N;;;;; -131D1;EGYPTIAN HIEROGLYPH M022;Lo;0;L;;;;;N;;;;; -131D2;EGYPTIAN HIEROGLYPH M022A;Lo;0;L;;;;;N;;;;; -131D3;EGYPTIAN HIEROGLYPH M023;Lo;0;L;;;;;N;;;;; -131D4;EGYPTIAN HIEROGLYPH M024;Lo;0;L;;;;;N;;;;; -131D5;EGYPTIAN HIEROGLYPH M024A;Lo;0;L;;;;;N;;;;; -131D6;EGYPTIAN HIEROGLYPH M025;Lo;0;L;;;;;N;;;;; -131D7;EGYPTIAN HIEROGLYPH M026;Lo;0;L;;;;;N;;;;; -131D8;EGYPTIAN HIEROGLYPH M027;Lo;0;L;;;;;N;;;;; -131D9;EGYPTIAN HIEROGLYPH M028;Lo;0;L;;;;;N;;;;; -131DA;EGYPTIAN HIEROGLYPH M028A;Lo;0;L;;;;;N;;;;; -131DB;EGYPTIAN HIEROGLYPH M029;Lo;0;L;;;;;N;;;;; -131DC;EGYPTIAN HIEROGLYPH M030;Lo;0;L;;;;;N;;;;; -131DD;EGYPTIAN HIEROGLYPH M031;Lo;0;L;;;;;N;;;;; -131DE;EGYPTIAN HIEROGLYPH M031A;Lo;0;L;;;;;N;;;;; -131DF;EGYPTIAN HIEROGLYPH M032;Lo;0;L;;;;;N;;;;; -131E0;EGYPTIAN HIEROGLYPH M033;Lo;0;L;;;;;N;;;;; -131E1;EGYPTIAN HIEROGLYPH M033A;Lo;0;L;;;;;N;;;;; -131E2;EGYPTIAN HIEROGLYPH M033B;Lo;0;L;;;;;N;;;;; -131E3;EGYPTIAN HIEROGLYPH M034;Lo;0;L;;;;;N;;;;; -131E4;EGYPTIAN HIEROGLYPH M035;Lo;0;L;;;;;N;;;;; -131E5;EGYPTIAN HIEROGLYPH M036;Lo;0;L;;;;;N;;;;; -131E6;EGYPTIAN HIEROGLYPH M037;Lo;0;L;;;;;N;;;;; -131E7;EGYPTIAN HIEROGLYPH M038;Lo;0;L;;;;;N;;;;; -131E8;EGYPTIAN HIEROGLYPH M039;Lo;0;L;;;;;N;;;;; -131E9;EGYPTIAN HIEROGLYPH M040;Lo;0;L;;;;;N;;;;; -131EA;EGYPTIAN HIEROGLYPH M040A;Lo;0;L;;;;;N;;;;; -131EB;EGYPTIAN HIEROGLYPH M041;Lo;0;L;;;;;N;;;;; -131EC;EGYPTIAN HIEROGLYPH M042;Lo;0;L;;;;;N;;;;; -131ED;EGYPTIAN HIEROGLYPH M043;Lo;0;L;;;;;N;;;;; -131EE;EGYPTIAN HIEROGLYPH M044;Lo;0;L;;;;;N;;;;; -131EF;EGYPTIAN HIEROGLYPH N001;Lo;0;L;;;;;N;;;;; -131F0;EGYPTIAN HIEROGLYPH N002;Lo;0;L;;;;;N;;;;; -131F1;EGYPTIAN HIEROGLYPH N003;Lo;0;L;;;;;N;;;;; -131F2;EGYPTIAN HIEROGLYPH N004;Lo;0;L;;;;;N;;;;; -131F3;EGYPTIAN HIEROGLYPH N005;Lo;0;L;;;;;N;;;;; -131F4;EGYPTIAN HIEROGLYPH N006;Lo;0;L;;;;;N;;;;; -131F5;EGYPTIAN HIEROGLYPH N007;Lo;0;L;;;;;N;;;;; -131F6;EGYPTIAN HIEROGLYPH N008;Lo;0;L;;;;;N;;;;; -131F7;EGYPTIAN HIEROGLYPH N009;Lo;0;L;;;;;N;;;;; -131F8;EGYPTIAN HIEROGLYPH N010;Lo;0;L;;;;;N;;;;; -131F9;EGYPTIAN HIEROGLYPH N011;Lo;0;L;;;;;N;;;;; -131FA;EGYPTIAN HIEROGLYPH N012;Lo;0;L;;;;;N;;;;; -131FB;EGYPTIAN HIEROGLYPH N013;Lo;0;L;;;;;N;;;;; -131FC;EGYPTIAN HIEROGLYPH N014;Lo;0;L;;;;;N;;;;; -131FD;EGYPTIAN HIEROGLYPH N015;Lo;0;L;;;;;N;;;;; -131FE;EGYPTIAN HIEROGLYPH N016;Lo;0;L;;;;;N;;;;; -131FF;EGYPTIAN HIEROGLYPH N017;Lo;0;L;;;;;N;;;;; -13200;EGYPTIAN HIEROGLYPH N018;Lo;0;L;;;;;N;;;;; -13201;EGYPTIAN HIEROGLYPH N018A;Lo;0;L;;;;;N;;;;; -13202;EGYPTIAN HIEROGLYPH N018B;Lo;0;L;;;;;N;;;;; -13203;EGYPTIAN HIEROGLYPH N019;Lo;0;L;;;;;N;;;;; -13204;EGYPTIAN HIEROGLYPH N020;Lo;0;L;;;;;N;;;;; -13205;EGYPTIAN HIEROGLYPH N021;Lo;0;L;;;;;N;;;;; -13206;EGYPTIAN HIEROGLYPH N022;Lo;0;L;;;;;N;;;;; -13207;EGYPTIAN HIEROGLYPH N023;Lo;0;L;;;;;N;;;;; -13208;EGYPTIAN HIEROGLYPH N024;Lo;0;L;;;;;N;;;;; -13209;EGYPTIAN HIEROGLYPH N025;Lo;0;L;;;;;N;;;;; -1320A;EGYPTIAN HIEROGLYPH N025A;Lo;0;L;;;;;N;;;;; -1320B;EGYPTIAN HIEROGLYPH N026;Lo;0;L;;;;;N;;;;; -1320C;EGYPTIAN HIEROGLYPH N027;Lo;0;L;;;;;N;;;;; -1320D;EGYPTIAN HIEROGLYPH N028;Lo;0;L;;;;;N;;;;; -1320E;EGYPTIAN HIEROGLYPH N029;Lo;0;L;;;;;N;;;;; -1320F;EGYPTIAN HIEROGLYPH N030;Lo;0;L;;;;;N;;;;; -13210;EGYPTIAN HIEROGLYPH N031;Lo;0;L;;;;;N;;;;; -13211;EGYPTIAN HIEROGLYPH N032;Lo;0;L;;;;;N;;;;; -13212;EGYPTIAN HIEROGLYPH N033;Lo;0;L;;;;;N;;;;; -13213;EGYPTIAN HIEROGLYPH N033A;Lo;0;L;;;;;N;;;;; -13214;EGYPTIAN HIEROGLYPH N034;Lo;0;L;;;;;N;;;;; -13215;EGYPTIAN HIEROGLYPH N034A;Lo;0;L;;;;;N;;;;; -13216;EGYPTIAN HIEROGLYPH N035;Lo;0;L;;;;;N;;;;; -13217;EGYPTIAN HIEROGLYPH N035A;Lo;0;L;;;;;N;;;;; -13218;EGYPTIAN HIEROGLYPH N036;Lo;0;L;;;;;N;;;;; -13219;EGYPTIAN HIEROGLYPH N037;Lo;0;L;;;;;N;;;;; -1321A;EGYPTIAN HIEROGLYPH N037A;Lo;0;L;;;;;N;;;;; -1321B;EGYPTIAN HIEROGLYPH N038;Lo;0;L;;;;;N;;;;; -1321C;EGYPTIAN HIEROGLYPH N039;Lo;0;L;;;;;N;;;;; -1321D;EGYPTIAN HIEROGLYPH N040;Lo;0;L;;;;;N;;;;; -1321E;EGYPTIAN HIEROGLYPH N041;Lo;0;L;;;;;N;;;;; -1321F;EGYPTIAN HIEROGLYPH N042;Lo;0;L;;;;;N;;;;; -13220;EGYPTIAN HIEROGLYPH NL001;Lo;0;L;;;;;N;;;;; -13221;EGYPTIAN HIEROGLYPH NL002;Lo;0;L;;;;;N;;;;; -13222;EGYPTIAN HIEROGLYPH NL003;Lo;0;L;;;;;N;;;;; -13223;EGYPTIAN HIEROGLYPH NL004;Lo;0;L;;;;;N;;;;; -13224;EGYPTIAN HIEROGLYPH NL005;Lo;0;L;;;;;N;;;;; -13225;EGYPTIAN HIEROGLYPH NL005A;Lo;0;L;;;;;N;;;;; -13226;EGYPTIAN HIEROGLYPH NL006;Lo;0;L;;;;;N;;;;; -13227;EGYPTIAN HIEROGLYPH NL007;Lo;0;L;;;;;N;;;;; -13228;EGYPTIAN HIEROGLYPH NL008;Lo;0;L;;;;;N;;;;; -13229;EGYPTIAN HIEROGLYPH NL009;Lo;0;L;;;;;N;;;;; -1322A;EGYPTIAN HIEROGLYPH NL010;Lo;0;L;;;;;N;;;;; -1322B;EGYPTIAN HIEROGLYPH NL011;Lo;0;L;;;;;N;;;;; -1322C;EGYPTIAN HIEROGLYPH NL012;Lo;0;L;;;;;N;;;;; -1322D;EGYPTIAN HIEROGLYPH NL013;Lo;0;L;;;;;N;;;;; -1322E;EGYPTIAN HIEROGLYPH NL014;Lo;0;L;;;;;N;;;;; -1322F;EGYPTIAN HIEROGLYPH NL015;Lo;0;L;;;;;N;;;;; -13230;EGYPTIAN HIEROGLYPH NL016;Lo;0;L;;;;;N;;;;; -13231;EGYPTIAN HIEROGLYPH NL017;Lo;0;L;;;;;N;;;;; -13232;EGYPTIAN HIEROGLYPH NL017A;Lo;0;L;;;;;N;;;;; -13233;EGYPTIAN HIEROGLYPH NL018;Lo;0;L;;;;;N;;;;; -13234;EGYPTIAN HIEROGLYPH NL019;Lo;0;L;;;;;N;;;;; -13235;EGYPTIAN HIEROGLYPH NL020;Lo;0;L;;;;;N;;;;; -13236;EGYPTIAN HIEROGLYPH NU001;Lo;0;L;;;;;N;;;;; -13237;EGYPTIAN HIEROGLYPH NU002;Lo;0;L;;;;;N;;;;; -13238;EGYPTIAN HIEROGLYPH NU003;Lo;0;L;;;;;N;;;;; -13239;EGYPTIAN HIEROGLYPH NU004;Lo;0;L;;;;;N;;;;; -1323A;EGYPTIAN HIEROGLYPH NU005;Lo;0;L;;;;;N;;;;; -1323B;EGYPTIAN HIEROGLYPH NU006;Lo;0;L;;;;;N;;;;; -1323C;EGYPTIAN HIEROGLYPH NU007;Lo;0;L;;;;;N;;;;; -1323D;EGYPTIAN HIEROGLYPH NU008;Lo;0;L;;;;;N;;;;; -1323E;EGYPTIAN HIEROGLYPH NU009;Lo;0;L;;;;;N;;;;; -1323F;EGYPTIAN HIEROGLYPH NU010;Lo;0;L;;;;;N;;;;; -13240;EGYPTIAN HIEROGLYPH NU010A;Lo;0;L;;;;;N;;;;; -13241;EGYPTIAN HIEROGLYPH NU011;Lo;0;L;;;;;N;;;;; -13242;EGYPTIAN HIEROGLYPH NU011A;Lo;0;L;;;;;N;;;;; -13243;EGYPTIAN HIEROGLYPH NU012;Lo;0;L;;;;;N;;;;; -13244;EGYPTIAN HIEROGLYPH NU013;Lo;0;L;;;;;N;;;;; -13245;EGYPTIAN HIEROGLYPH NU014;Lo;0;L;;;;;N;;;;; -13246;EGYPTIAN HIEROGLYPH NU015;Lo;0;L;;;;;N;;;;; -13247;EGYPTIAN HIEROGLYPH NU016;Lo;0;L;;;;;N;;;;; -13248;EGYPTIAN HIEROGLYPH NU017;Lo;0;L;;;;;N;;;;; -13249;EGYPTIAN HIEROGLYPH NU018;Lo;0;L;;;;;N;;;;; -1324A;EGYPTIAN HIEROGLYPH NU018A;Lo;0;L;;;;;N;;;;; -1324B;EGYPTIAN HIEROGLYPH NU019;Lo;0;L;;;;;N;;;;; -1324C;EGYPTIAN HIEROGLYPH NU020;Lo;0;L;;;;;N;;;;; -1324D;EGYPTIAN HIEROGLYPH NU021;Lo;0;L;;;;;N;;;;; -1324E;EGYPTIAN HIEROGLYPH NU022;Lo;0;L;;;;;N;;;;; -1324F;EGYPTIAN HIEROGLYPH NU022A;Lo;0;L;;;;;N;;;;; -13250;EGYPTIAN HIEROGLYPH O001;Lo;0;L;;;;;N;;;;; -13251;EGYPTIAN HIEROGLYPH O001A;Lo;0;L;;;;;N;;;;; -13252;EGYPTIAN HIEROGLYPH O002;Lo;0;L;;;;;N;;;;; -13253;EGYPTIAN HIEROGLYPH O003;Lo;0;L;;;;;N;;;;; -13254;EGYPTIAN HIEROGLYPH O004;Lo;0;L;;;;;N;;;;; -13255;EGYPTIAN HIEROGLYPH O005;Lo;0;L;;;;;N;;;;; -13256;EGYPTIAN HIEROGLYPH O005A;Lo;0;L;;;;;N;;;;; -13257;EGYPTIAN HIEROGLYPH O006;Lo;0;L;;;;;N;;;;; -13258;EGYPTIAN HIEROGLYPH O006A;Lo;0;L;;;;;N;;;;; -13259;EGYPTIAN HIEROGLYPH O006B;Lo;0;L;;;;;N;;;;; -1325A;EGYPTIAN HIEROGLYPH O006C;Lo;0;L;;;;;N;;;;; -1325B;EGYPTIAN HIEROGLYPH O006D;Lo;0;L;;;;;N;;;;; -1325C;EGYPTIAN HIEROGLYPH O006E;Lo;0;L;;;;;N;;;;; -1325D;EGYPTIAN HIEROGLYPH O006F;Lo;0;L;;;;;N;;;;; -1325E;EGYPTIAN HIEROGLYPH O007;Lo;0;L;;;;;N;;;;; -1325F;EGYPTIAN HIEROGLYPH O008;Lo;0;L;;;;;N;;;;; -13260;EGYPTIAN HIEROGLYPH O009;Lo;0;L;;;;;N;;;;; -13261;EGYPTIAN HIEROGLYPH O010;Lo;0;L;;;;;N;;;;; -13262;EGYPTIAN HIEROGLYPH O010A;Lo;0;L;;;;;N;;;;; -13263;EGYPTIAN HIEROGLYPH O010B;Lo;0;L;;;;;N;;;;; -13264;EGYPTIAN HIEROGLYPH O010C;Lo;0;L;;;;;N;;;;; -13265;EGYPTIAN HIEROGLYPH O011;Lo;0;L;;;;;N;;;;; -13266;EGYPTIAN HIEROGLYPH O012;Lo;0;L;;;;;N;;;;; -13267;EGYPTIAN HIEROGLYPH O013;Lo;0;L;;;;;N;;;;; -13268;EGYPTIAN HIEROGLYPH O014;Lo;0;L;;;;;N;;;;; -13269;EGYPTIAN HIEROGLYPH O015;Lo;0;L;;;;;N;;;;; -1326A;EGYPTIAN HIEROGLYPH O016;Lo;0;L;;;;;N;;;;; -1326B;EGYPTIAN HIEROGLYPH O017;Lo;0;L;;;;;N;;;;; -1326C;EGYPTIAN HIEROGLYPH O018;Lo;0;L;;;;;N;;;;; -1326D;EGYPTIAN HIEROGLYPH O019;Lo;0;L;;;;;N;;;;; -1326E;EGYPTIAN HIEROGLYPH O019A;Lo;0;L;;;;;N;;;;; -1326F;EGYPTIAN HIEROGLYPH O020;Lo;0;L;;;;;N;;;;; -13270;EGYPTIAN HIEROGLYPH O020A;Lo;0;L;;;;;N;;;;; -13271;EGYPTIAN HIEROGLYPH O021;Lo;0;L;;;;;N;;;;; -13272;EGYPTIAN HIEROGLYPH O022;Lo;0;L;;;;;N;;;;; -13273;EGYPTIAN HIEROGLYPH O023;Lo;0;L;;;;;N;;;;; -13274;EGYPTIAN HIEROGLYPH O024;Lo;0;L;;;;;N;;;;; -13275;EGYPTIAN HIEROGLYPH O024A;Lo;0;L;;;;;N;;;;; -13276;EGYPTIAN HIEROGLYPH O025;Lo;0;L;;;;;N;;;;; -13277;EGYPTIAN HIEROGLYPH O025A;Lo;0;L;;;;;N;;;;; -13278;EGYPTIAN HIEROGLYPH O026;Lo;0;L;;;;;N;;;;; -13279;EGYPTIAN HIEROGLYPH O027;Lo;0;L;;;;;N;;;;; -1327A;EGYPTIAN HIEROGLYPH O028;Lo;0;L;;;;;N;;;;; -1327B;EGYPTIAN HIEROGLYPH O029;Lo;0;L;;;;;N;;;;; -1327C;EGYPTIAN HIEROGLYPH O029A;Lo;0;L;;;;;N;;;;; -1327D;EGYPTIAN HIEROGLYPH O030;Lo;0;L;;;;;N;;;;; -1327E;EGYPTIAN HIEROGLYPH O030A;Lo;0;L;;;;;N;;;;; -1327F;EGYPTIAN HIEROGLYPH O031;Lo;0;L;;;;;N;;;;; -13280;EGYPTIAN HIEROGLYPH O032;Lo;0;L;;;;;N;;;;; -13281;EGYPTIAN HIEROGLYPH O033;Lo;0;L;;;;;N;;;;; -13282;EGYPTIAN HIEROGLYPH O033A;Lo;0;L;;;;;N;;;;; -13283;EGYPTIAN HIEROGLYPH O034;Lo;0;L;;;;;N;;;;; -13284;EGYPTIAN HIEROGLYPH O035;Lo;0;L;;;;;N;;;;; -13285;EGYPTIAN HIEROGLYPH O036;Lo;0;L;;;;;N;;;;; -13286;EGYPTIAN HIEROGLYPH O036A;Lo;0;L;;;;;N;;;;; -13287;EGYPTIAN HIEROGLYPH O036B;Lo;0;L;;;;;N;;;;; -13288;EGYPTIAN HIEROGLYPH O036C;Lo;0;L;;;;;N;;;;; -13289;EGYPTIAN HIEROGLYPH O036D;Lo;0;L;;;;;N;;;;; -1328A;EGYPTIAN HIEROGLYPH O037;Lo;0;L;;;;;N;;;;; -1328B;EGYPTIAN HIEROGLYPH O038;Lo;0;L;;;;;N;;;;; -1328C;EGYPTIAN HIEROGLYPH O039;Lo;0;L;;;;;N;;;;; -1328D;EGYPTIAN HIEROGLYPH O040;Lo;0;L;;;;;N;;;;; -1328E;EGYPTIAN HIEROGLYPH O041;Lo;0;L;;;;;N;;;;; -1328F;EGYPTIAN HIEROGLYPH O042;Lo;0;L;;;;;N;;;;; -13290;EGYPTIAN HIEROGLYPH O043;Lo;0;L;;;;;N;;;;; -13291;EGYPTIAN HIEROGLYPH O044;Lo;0;L;;;;;N;;;;; -13292;EGYPTIAN HIEROGLYPH O045;Lo;0;L;;;;;N;;;;; -13293;EGYPTIAN HIEROGLYPH O046;Lo;0;L;;;;;N;;;;; -13294;EGYPTIAN HIEROGLYPH O047;Lo;0;L;;;;;N;;;;; -13295;EGYPTIAN HIEROGLYPH O048;Lo;0;L;;;;;N;;;;; -13296;EGYPTIAN HIEROGLYPH O049;Lo;0;L;;;;;N;;;;; -13297;EGYPTIAN HIEROGLYPH O050;Lo;0;L;;;;;N;;;;; -13298;EGYPTIAN HIEROGLYPH O050A;Lo;0;L;;;;;N;;;;; -13299;EGYPTIAN HIEROGLYPH O050B;Lo;0;L;;;;;N;;;;; -1329A;EGYPTIAN HIEROGLYPH O051;Lo;0;L;;;;;N;;;;; -1329B;EGYPTIAN HIEROGLYPH P001;Lo;0;L;;;;;N;;;;; -1329C;EGYPTIAN HIEROGLYPH P001A;Lo;0;L;;;;;N;;;;; -1329D;EGYPTIAN HIEROGLYPH P002;Lo;0;L;;;;;N;;;;; -1329E;EGYPTIAN HIEROGLYPH P003;Lo;0;L;;;;;N;;;;; -1329F;EGYPTIAN HIEROGLYPH P003A;Lo;0;L;;;;;N;;;;; -132A0;EGYPTIAN HIEROGLYPH P004;Lo;0;L;;;;;N;;;;; -132A1;EGYPTIAN HIEROGLYPH P005;Lo;0;L;;;;;N;;;;; -132A2;EGYPTIAN HIEROGLYPH P006;Lo;0;L;;;;;N;;;;; -132A3;EGYPTIAN HIEROGLYPH P007;Lo;0;L;;;;;N;;;;; -132A4;EGYPTIAN HIEROGLYPH P008;Lo;0;L;;;;;N;;;;; -132A5;EGYPTIAN HIEROGLYPH P009;Lo;0;L;;;;;N;;;;; -132A6;EGYPTIAN HIEROGLYPH P010;Lo;0;L;;;;;N;;;;; -132A7;EGYPTIAN HIEROGLYPH P011;Lo;0;L;;;;;N;;;;; -132A8;EGYPTIAN HIEROGLYPH Q001;Lo;0;L;;;;;N;;;;; -132A9;EGYPTIAN HIEROGLYPH Q002;Lo;0;L;;;;;N;;;;; -132AA;EGYPTIAN HIEROGLYPH Q003;Lo;0;L;;;;;N;;;;; -132AB;EGYPTIAN HIEROGLYPH Q004;Lo;0;L;;;;;N;;;;; -132AC;EGYPTIAN HIEROGLYPH Q005;Lo;0;L;;;;;N;;;;; -132AD;EGYPTIAN HIEROGLYPH Q006;Lo;0;L;;;;;N;;;;; -132AE;EGYPTIAN HIEROGLYPH Q007;Lo;0;L;;;;;N;;;;; -132AF;EGYPTIAN HIEROGLYPH R001;Lo;0;L;;;;;N;;;;; -132B0;EGYPTIAN HIEROGLYPH R002;Lo;0;L;;;;;N;;;;; -132B1;EGYPTIAN HIEROGLYPH R002A;Lo;0;L;;;;;N;;;;; -132B2;EGYPTIAN HIEROGLYPH R003;Lo;0;L;;;;;N;;;;; -132B3;EGYPTIAN HIEROGLYPH R003A;Lo;0;L;;;;;N;;;;; -132B4;EGYPTIAN HIEROGLYPH R003B;Lo;0;L;;;;;N;;;;; -132B5;EGYPTIAN HIEROGLYPH R004;Lo;0;L;;;;;N;;;;; -132B6;EGYPTIAN HIEROGLYPH R005;Lo;0;L;;;;;N;;;;; -132B7;EGYPTIAN HIEROGLYPH R006;Lo;0;L;;;;;N;;;;; -132B8;EGYPTIAN HIEROGLYPH R007;Lo;0;L;;;;;N;;;;; -132B9;EGYPTIAN HIEROGLYPH R008;Lo;0;L;;;;;N;;;;; -132BA;EGYPTIAN HIEROGLYPH R009;Lo;0;L;;;;;N;;;;; -132BB;EGYPTIAN HIEROGLYPH R010;Lo;0;L;;;;;N;;;;; -132BC;EGYPTIAN HIEROGLYPH R010A;Lo;0;L;;;;;N;;;;; -132BD;EGYPTIAN HIEROGLYPH R011;Lo;0;L;;;;;N;;;;; -132BE;EGYPTIAN HIEROGLYPH R012;Lo;0;L;;;;;N;;;;; -132BF;EGYPTIAN HIEROGLYPH R013;Lo;0;L;;;;;N;;;;; -132C0;EGYPTIAN HIEROGLYPH R014;Lo;0;L;;;;;N;;;;; -132C1;EGYPTIAN HIEROGLYPH R015;Lo;0;L;;;;;N;;;;; -132C2;EGYPTIAN HIEROGLYPH R016;Lo;0;L;;;;;N;;;;; -132C3;EGYPTIAN HIEROGLYPH R016A;Lo;0;L;;;;;N;;;;; -132C4;EGYPTIAN HIEROGLYPH R017;Lo;0;L;;;;;N;;;;; -132C5;EGYPTIAN HIEROGLYPH R018;Lo;0;L;;;;;N;;;;; -132C6;EGYPTIAN HIEROGLYPH R019;Lo;0;L;;;;;N;;;;; -132C7;EGYPTIAN HIEROGLYPH R020;Lo;0;L;;;;;N;;;;; -132C8;EGYPTIAN HIEROGLYPH R021;Lo;0;L;;;;;N;;;;; -132C9;EGYPTIAN HIEROGLYPH R022;Lo;0;L;;;;;N;;;;; -132CA;EGYPTIAN HIEROGLYPH R023;Lo;0;L;;;;;N;;;;; -132CB;EGYPTIAN HIEROGLYPH R024;Lo;0;L;;;;;N;;;;; -132CC;EGYPTIAN HIEROGLYPH R025;Lo;0;L;;;;;N;;;;; -132CD;EGYPTIAN HIEROGLYPH R026;Lo;0;L;;;;;N;;;;; -132CE;EGYPTIAN HIEROGLYPH R027;Lo;0;L;;;;;N;;;;; -132CF;EGYPTIAN HIEROGLYPH R028;Lo;0;L;;;;;N;;;;; -132D0;EGYPTIAN HIEROGLYPH R029;Lo;0;L;;;;;N;;;;; -132D1;EGYPTIAN HIEROGLYPH S001;Lo;0;L;;;;;N;;;;; -132D2;EGYPTIAN HIEROGLYPH S002;Lo;0;L;;;;;N;;;;; -132D3;EGYPTIAN HIEROGLYPH S002A;Lo;0;L;;;;;N;;;;; -132D4;EGYPTIAN HIEROGLYPH S003;Lo;0;L;;;;;N;;;;; -132D5;EGYPTIAN HIEROGLYPH S004;Lo;0;L;;;;;N;;;;; -132D6;EGYPTIAN HIEROGLYPH S005;Lo;0;L;;;;;N;;;;; -132D7;EGYPTIAN HIEROGLYPH S006;Lo;0;L;;;;;N;;;;; -132D8;EGYPTIAN HIEROGLYPH S006A;Lo;0;L;;;;;N;;;;; -132D9;EGYPTIAN HIEROGLYPH S007;Lo;0;L;;;;;N;;;;; -132DA;EGYPTIAN HIEROGLYPH S008;Lo;0;L;;;;;N;;;;; -132DB;EGYPTIAN HIEROGLYPH S009;Lo;0;L;;;;;N;;;;; -132DC;EGYPTIAN HIEROGLYPH S010;Lo;0;L;;;;;N;;;;; -132DD;EGYPTIAN HIEROGLYPH S011;Lo;0;L;;;;;N;;;;; -132DE;EGYPTIAN HIEROGLYPH S012;Lo;0;L;;;;;N;;;;; -132DF;EGYPTIAN HIEROGLYPH S013;Lo;0;L;;;;;N;;;;; -132E0;EGYPTIAN HIEROGLYPH S014;Lo;0;L;;;;;N;;;;; -132E1;EGYPTIAN HIEROGLYPH S014A;Lo;0;L;;;;;N;;;;; -132E2;EGYPTIAN HIEROGLYPH S014B;Lo;0;L;;;;;N;;;;; -132E3;EGYPTIAN HIEROGLYPH S015;Lo;0;L;;;;;N;;;;; -132E4;EGYPTIAN HIEROGLYPH S016;Lo;0;L;;;;;N;;;;; -132E5;EGYPTIAN HIEROGLYPH S017;Lo;0;L;;;;;N;;;;; -132E6;EGYPTIAN HIEROGLYPH S017A;Lo;0;L;;;;;N;;;;; -132E7;EGYPTIAN HIEROGLYPH S018;Lo;0;L;;;;;N;;;;; -132E8;EGYPTIAN HIEROGLYPH S019;Lo;0;L;;;;;N;;;;; -132E9;EGYPTIAN HIEROGLYPH S020;Lo;0;L;;;;;N;;;;; -132EA;EGYPTIAN HIEROGLYPH S021;Lo;0;L;;;;;N;;;;; -132EB;EGYPTIAN HIEROGLYPH S022;Lo;0;L;;;;;N;;;;; -132EC;EGYPTIAN HIEROGLYPH S023;Lo;0;L;;;;;N;;;;; -132ED;EGYPTIAN HIEROGLYPH S024;Lo;0;L;;;;;N;;;;; -132EE;EGYPTIAN HIEROGLYPH S025;Lo;0;L;;;;;N;;;;; -132EF;EGYPTIAN HIEROGLYPH S026;Lo;0;L;;;;;N;;;;; -132F0;EGYPTIAN HIEROGLYPH S026A;Lo;0;L;;;;;N;;;;; -132F1;EGYPTIAN HIEROGLYPH S026B;Lo;0;L;;;;;N;;;;; -132F2;EGYPTIAN HIEROGLYPH S027;Lo;0;L;;;;;N;;;;; -132F3;EGYPTIAN HIEROGLYPH S028;Lo;0;L;;;;;N;;;;; -132F4;EGYPTIAN HIEROGLYPH S029;Lo;0;L;;;;;N;;;;; -132F5;EGYPTIAN HIEROGLYPH S030;Lo;0;L;;;;;N;;;;; -132F6;EGYPTIAN HIEROGLYPH S031;Lo;0;L;;;;;N;;;;; -132F7;EGYPTIAN HIEROGLYPH S032;Lo;0;L;;;;;N;;;;; -132F8;EGYPTIAN HIEROGLYPH S033;Lo;0;L;;;;;N;;;;; -132F9;EGYPTIAN HIEROGLYPH S034;Lo;0;L;;;;;N;;;;; -132FA;EGYPTIAN HIEROGLYPH S035;Lo;0;L;;;;;N;;;;; -132FB;EGYPTIAN HIEROGLYPH S035A;Lo;0;L;;;;;N;;;;; -132FC;EGYPTIAN HIEROGLYPH S036;Lo;0;L;;;;;N;;;;; -132FD;EGYPTIAN HIEROGLYPH S037;Lo;0;L;;;;;N;;;;; -132FE;EGYPTIAN HIEROGLYPH S038;Lo;0;L;;;;;N;;;;; -132FF;EGYPTIAN HIEROGLYPH S039;Lo;0;L;;;;;N;;;;; -13300;EGYPTIAN HIEROGLYPH S040;Lo;0;L;;;;;N;;;;; -13301;EGYPTIAN HIEROGLYPH S041;Lo;0;L;;;;;N;;;;; -13302;EGYPTIAN HIEROGLYPH S042;Lo;0;L;;;;;N;;;;; -13303;EGYPTIAN HIEROGLYPH S043;Lo;0;L;;;;;N;;;;; -13304;EGYPTIAN HIEROGLYPH S044;Lo;0;L;;;;;N;;;;; -13305;EGYPTIAN HIEROGLYPH S045;Lo;0;L;;;;;N;;;;; -13306;EGYPTIAN HIEROGLYPH S046;Lo;0;L;;;;;N;;;;; -13307;EGYPTIAN HIEROGLYPH T001;Lo;0;L;;;;;N;;;;; -13308;EGYPTIAN HIEROGLYPH T002;Lo;0;L;;;;;N;;;;; -13309;EGYPTIAN HIEROGLYPH T003;Lo;0;L;;;;;N;;;;; -1330A;EGYPTIAN HIEROGLYPH T003A;Lo;0;L;;;;;N;;;;; -1330B;EGYPTIAN HIEROGLYPH T004;Lo;0;L;;;;;N;;;;; -1330C;EGYPTIAN HIEROGLYPH T005;Lo;0;L;;;;;N;;;;; -1330D;EGYPTIAN HIEROGLYPH T006;Lo;0;L;;;;;N;;;;; -1330E;EGYPTIAN HIEROGLYPH T007;Lo;0;L;;;;;N;;;;; -1330F;EGYPTIAN HIEROGLYPH T007A;Lo;0;L;;;;;N;;;;; -13310;EGYPTIAN HIEROGLYPH T008;Lo;0;L;;;;;N;;;;; -13311;EGYPTIAN HIEROGLYPH T008A;Lo;0;L;;;;;N;;;;; -13312;EGYPTIAN HIEROGLYPH T009;Lo;0;L;;;;;N;;;;; -13313;EGYPTIAN HIEROGLYPH T009A;Lo;0;L;;;;;N;;;;; -13314;EGYPTIAN HIEROGLYPH T010;Lo;0;L;;;;;N;;;;; -13315;EGYPTIAN HIEROGLYPH T011;Lo;0;L;;;;;N;;;;; -13316;EGYPTIAN HIEROGLYPH T011A;Lo;0;L;;;;;N;;;;; -13317;EGYPTIAN HIEROGLYPH T012;Lo;0;L;;;;;N;;;;; -13318;EGYPTIAN HIEROGLYPH T013;Lo;0;L;;;;;N;;;;; -13319;EGYPTIAN HIEROGLYPH T014;Lo;0;L;;;;;N;;;;; -1331A;EGYPTIAN HIEROGLYPH T015;Lo;0;L;;;;;N;;;;; -1331B;EGYPTIAN HIEROGLYPH T016;Lo;0;L;;;;;N;;;;; -1331C;EGYPTIAN HIEROGLYPH T016A;Lo;0;L;;;;;N;;;;; -1331D;EGYPTIAN HIEROGLYPH T017;Lo;0;L;;;;;N;;;;; -1331E;EGYPTIAN HIEROGLYPH T018;Lo;0;L;;;;;N;;;;; -1331F;EGYPTIAN HIEROGLYPH T019;Lo;0;L;;;;;N;;;;; -13320;EGYPTIAN HIEROGLYPH T020;Lo;0;L;;;;;N;;;;; -13321;EGYPTIAN HIEROGLYPH T021;Lo;0;L;;;;;N;;;;; -13322;EGYPTIAN HIEROGLYPH T022;Lo;0;L;;;;;N;;;;; -13323;EGYPTIAN HIEROGLYPH T023;Lo;0;L;;;;;N;;;;; -13324;EGYPTIAN HIEROGLYPH T024;Lo;0;L;;;;;N;;;;; -13325;EGYPTIAN HIEROGLYPH T025;Lo;0;L;;;;;N;;;;; -13326;EGYPTIAN HIEROGLYPH T026;Lo;0;L;;;;;N;;;;; -13327;EGYPTIAN HIEROGLYPH T027;Lo;0;L;;;;;N;;;;; -13328;EGYPTIAN HIEROGLYPH T028;Lo;0;L;;;;;N;;;;; -13329;EGYPTIAN HIEROGLYPH T029;Lo;0;L;;;;;N;;;;; -1332A;EGYPTIAN HIEROGLYPH T030;Lo;0;L;;;;;N;;;;; -1332B;EGYPTIAN HIEROGLYPH T031;Lo;0;L;;;;;N;;;;; -1332C;EGYPTIAN HIEROGLYPH T032;Lo;0;L;;;;;N;;;;; -1332D;EGYPTIAN HIEROGLYPH T032A;Lo;0;L;;;;;N;;;;; -1332E;EGYPTIAN HIEROGLYPH T033;Lo;0;L;;;;;N;;;;; -1332F;EGYPTIAN HIEROGLYPH T033A;Lo;0;L;;;;;N;;;;; -13330;EGYPTIAN HIEROGLYPH T034;Lo;0;L;;;;;N;;;;; -13331;EGYPTIAN HIEROGLYPH T035;Lo;0;L;;;;;N;;;;; -13332;EGYPTIAN HIEROGLYPH T036;Lo;0;L;;;;;N;;;;; -13333;EGYPTIAN HIEROGLYPH U001;Lo;0;L;;;;;N;;;;; -13334;EGYPTIAN HIEROGLYPH U002;Lo;0;L;;;;;N;;;;; -13335;EGYPTIAN HIEROGLYPH U003;Lo;0;L;;;;;N;;;;; -13336;EGYPTIAN HIEROGLYPH U004;Lo;0;L;;;;;N;;;;; -13337;EGYPTIAN HIEROGLYPH U005;Lo;0;L;;;;;N;;;;; -13338;EGYPTIAN HIEROGLYPH U006;Lo;0;L;;;;;N;;;;; -13339;EGYPTIAN HIEROGLYPH U006A;Lo;0;L;;;;;N;;;;; -1333A;EGYPTIAN HIEROGLYPH U006B;Lo;0;L;;;;;N;;;;; -1333B;EGYPTIAN HIEROGLYPH U007;Lo;0;L;;;;;N;;;;; -1333C;EGYPTIAN HIEROGLYPH U008;Lo;0;L;;;;;N;;;;; -1333D;EGYPTIAN HIEROGLYPH U009;Lo;0;L;;;;;N;;;;; -1333E;EGYPTIAN HIEROGLYPH U010;Lo;0;L;;;;;N;;;;; -1333F;EGYPTIAN HIEROGLYPH U011;Lo;0;L;;;;;N;;;;; -13340;EGYPTIAN HIEROGLYPH U012;Lo;0;L;;;;;N;;;;; -13341;EGYPTIAN HIEROGLYPH U013;Lo;0;L;;;;;N;;;;; -13342;EGYPTIAN HIEROGLYPH U014;Lo;0;L;;;;;N;;;;; -13343;EGYPTIAN HIEROGLYPH U015;Lo;0;L;;;;;N;;;;; -13344;EGYPTIAN HIEROGLYPH U016;Lo;0;L;;;;;N;;;;; -13345;EGYPTIAN HIEROGLYPH U017;Lo;0;L;;;;;N;;;;; -13346;EGYPTIAN HIEROGLYPH U018;Lo;0;L;;;;;N;;;;; -13347;EGYPTIAN HIEROGLYPH U019;Lo;0;L;;;;;N;;;;; -13348;EGYPTIAN HIEROGLYPH U020;Lo;0;L;;;;;N;;;;; -13349;EGYPTIAN HIEROGLYPH U021;Lo;0;L;;;;;N;;;;; -1334A;EGYPTIAN HIEROGLYPH U022;Lo;0;L;;;;;N;;;;; -1334B;EGYPTIAN HIEROGLYPH U023;Lo;0;L;;;;;N;;;;; -1334C;EGYPTIAN HIEROGLYPH U023A;Lo;0;L;;;;;N;;;;; -1334D;EGYPTIAN HIEROGLYPH U024;Lo;0;L;;;;;N;;;;; -1334E;EGYPTIAN HIEROGLYPH U025;Lo;0;L;;;;;N;;;;; -1334F;EGYPTIAN HIEROGLYPH U026;Lo;0;L;;;;;N;;;;; -13350;EGYPTIAN HIEROGLYPH U027;Lo;0;L;;;;;N;;;;; -13351;EGYPTIAN HIEROGLYPH U028;Lo;0;L;;;;;N;;;;; -13352;EGYPTIAN HIEROGLYPH U029;Lo;0;L;;;;;N;;;;; -13353;EGYPTIAN HIEROGLYPH U029A;Lo;0;L;;;;;N;;;;; -13354;EGYPTIAN HIEROGLYPH U030;Lo;0;L;;;;;N;;;;; -13355;EGYPTIAN HIEROGLYPH U031;Lo;0;L;;;;;N;;;;; -13356;EGYPTIAN HIEROGLYPH U032;Lo;0;L;;;;;N;;;;; -13357;EGYPTIAN HIEROGLYPH U032A;Lo;0;L;;;;;N;;;;; -13358;EGYPTIAN HIEROGLYPH U033;Lo;0;L;;;;;N;;;;; -13359;EGYPTIAN HIEROGLYPH U034;Lo;0;L;;;;;N;;;;; -1335A;EGYPTIAN HIEROGLYPH U035;Lo;0;L;;;;;N;;;;; -1335B;EGYPTIAN HIEROGLYPH U036;Lo;0;L;;;;;N;;;;; -1335C;EGYPTIAN HIEROGLYPH U037;Lo;0;L;;;;;N;;;;; -1335D;EGYPTIAN HIEROGLYPH U038;Lo;0;L;;;;;N;;;;; -1335E;EGYPTIAN HIEROGLYPH U039;Lo;0;L;;;;;N;;;;; -1335F;EGYPTIAN HIEROGLYPH U040;Lo;0;L;;;;;N;;;;; -13360;EGYPTIAN HIEROGLYPH U041;Lo;0;L;;;;;N;;;;; -13361;EGYPTIAN HIEROGLYPH U042;Lo;0;L;;;;;N;;;;; -13362;EGYPTIAN HIEROGLYPH V001;Lo;0;L;;;;;N;;;;; -13363;EGYPTIAN HIEROGLYPH V001A;Lo;0;L;;;;;N;;;;; -13364;EGYPTIAN HIEROGLYPH V001B;Lo;0;L;;;;;N;;;;; -13365;EGYPTIAN HIEROGLYPH V001C;Lo;0;L;;;;;N;;;;; -13366;EGYPTIAN HIEROGLYPH V001D;Lo;0;L;;;;;N;;;;; -13367;EGYPTIAN HIEROGLYPH V001E;Lo;0;L;;;;;N;;;;; -13368;EGYPTIAN HIEROGLYPH V001F;Lo;0;L;;;;;N;;;;; -13369;EGYPTIAN HIEROGLYPH V001G;Lo;0;L;;;;;N;;;;; -1336A;EGYPTIAN HIEROGLYPH V001H;Lo;0;L;;;;;N;;;;; -1336B;EGYPTIAN HIEROGLYPH V001I;Lo;0;L;;;;;N;;;;; -1336C;EGYPTIAN HIEROGLYPH V002;Lo;0;L;;;;;N;;;;; -1336D;EGYPTIAN HIEROGLYPH V002A;Lo;0;L;;;;;N;;;;; -1336E;EGYPTIAN HIEROGLYPH V003;Lo;0;L;;;;;N;;;;; -1336F;EGYPTIAN HIEROGLYPH V004;Lo;0;L;;;;;N;;;;; -13370;EGYPTIAN HIEROGLYPH V005;Lo;0;L;;;;;N;;;;; -13371;EGYPTIAN HIEROGLYPH V006;Lo;0;L;;;;;N;;;;; -13372;EGYPTIAN HIEROGLYPH V007;Lo;0;L;;;;;N;;;;; -13373;EGYPTIAN HIEROGLYPH V007A;Lo;0;L;;;;;N;;;;; -13374;EGYPTIAN HIEROGLYPH V007B;Lo;0;L;;;;;N;;;;; -13375;EGYPTIAN HIEROGLYPH V008;Lo;0;L;;;;;N;;;;; -13376;EGYPTIAN HIEROGLYPH V009;Lo;0;L;;;;;N;;;;; -13377;EGYPTIAN HIEROGLYPH V010;Lo;0;L;;;;;N;;;;; -13378;EGYPTIAN HIEROGLYPH V011;Lo;0;L;;;;;N;;;;; -13379;EGYPTIAN HIEROGLYPH V011A;Lo;0;L;;;;;N;;;;; -1337A;EGYPTIAN HIEROGLYPH V011B;Lo;0;L;;;;;N;;;;; -1337B;EGYPTIAN HIEROGLYPH V011C;Lo;0;L;;;;;N;;;;; -1337C;EGYPTIAN HIEROGLYPH V012;Lo;0;L;;;;;N;;;;; -1337D;EGYPTIAN HIEROGLYPH V012A;Lo;0;L;;;;;N;;;;; -1337E;EGYPTIAN HIEROGLYPH V012B;Lo;0;L;;;;;N;;;;; -1337F;EGYPTIAN HIEROGLYPH V013;Lo;0;L;;;;;N;;;;; -13380;EGYPTIAN HIEROGLYPH V014;Lo;0;L;;;;;N;;;;; -13381;EGYPTIAN HIEROGLYPH V015;Lo;0;L;;;;;N;;;;; -13382;EGYPTIAN HIEROGLYPH V016;Lo;0;L;;;;;N;;;;; -13383;EGYPTIAN HIEROGLYPH V017;Lo;0;L;;;;;N;;;;; -13384;EGYPTIAN HIEROGLYPH V018;Lo;0;L;;;;;N;;;;; -13385;EGYPTIAN HIEROGLYPH V019;Lo;0;L;;;;;N;;;;; -13386;EGYPTIAN HIEROGLYPH V020;Lo;0;L;;;;;N;;;;; -13387;EGYPTIAN HIEROGLYPH V020A;Lo;0;L;;;;;N;;;;; -13388;EGYPTIAN HIEROGLYPH V020B;Lo;0;L;;;;;N;;;;; -13389;EGYPTIAN HIEROGLYPH V020C;Lo;0;L;;;;;N;;;;; -1338A;EGYPTIAN HIEROGLYPH V020D;Lo;0;L;;;;;N;;;;; -1338B;EGYPTIAN HIEROGLYPH V020E;Lo;0;L;;;;;N;;;;; -1338C;EGYPTIAN HIEROGLYPH V020F;Lo;0;L;;;;;N;;;;; -1338D;EGYPTIAN HIEROGLYPH V020G;Lo;0;L;;;;;N;;;;; -1338E;EGYPTIAN HIEROGLYPH V020H;Lo;0;L;;;;;N;;;;; -1338F;EGYPTIAN HIEROGLYPH V020I;Lo;0;L;;;;;N;;;;; -13390;EGYPTIAN HIEROGLYPH V020J;Lo;0;L;;;;;N;;;;; -13391;EGYPTIAN HIEROGLYPH V020K;Lo;0;L;;;;;N;;;;; -13392;EGYPTIAN HIEROGLYPH V020L;Lo;0;L;;;;;N;;;;; -13393;EGYPTIAN HIEROGLYPH V021;Lo;0;L;;;;;N;;;;; -13394;EGYPTIAN HIEROGLYPH V022;Lo;0;L;;;;;N;;;;; -13395;EGYPTIAN HIEROGLYPH V023;Lo;0;L;;;;;N;;;;; -13396;EGYPTIAN HIEROGLYPH V023A;Lo;0;L;;;;;N;;;;; -13397;EGYPTIAN HIEROGLYPH V024;Lo;0;L;;;;;N;;;;; -13398;EGYPTIAN HIEROGLYPH V025;Lo;0;L;;;;;N;;;;; -13399;EGYPTIAN HIEROGLYPH V026;Lo;0;L;;;;;N;;;;; -1339A;EGYPTIAN HIEROGLYPH V027;Lo;0;L;;;;;N;;;;; -1339B;EGYPTIAN HIEROGLYPH V028;Lo;0;L;;;;;N;;;;; -1339C;EGYPTIAN HIEROGLYPH V028A;Lo;0;L;;;;;N;;;;; -1339D;EGYPTIAN HIEROGLYPH V029;Lo;0;L;;;;;N;;;;; -1339E;EGYPTIAN HIEROGLYPH V029A;Lo;0;L;;;;;N;;;;; -1339F;EGYPTIAN HIEROGLYPH V030;Lo;0;L;;;;;N;;;;; -133A0;EGYPTIAN HIEROGLYPH V030A;Lo;0;L;;;;;N;;;;; -133A1;EGYPTIAN HIEROGLYPH V031;Lo;0;L;;;;;N;;;;; -133A2;EGYPTIAN HIEROGLYPH V031A;Lo;0;L;;;;;N;;;;; -133A3;EGYPTIAN HIEROGLYPH V032;Lo;0;L;;;;;N;;;;; -133A4;EGYPTIAN HIEROGLYPH V033;Lo;0;L;;;;;N;;;;; -133A5;EGYPTIAN HIEROGLYPH V033A;Lo;0;L;;;;;N;;;;; -133A6;EGYPTIAN HIEROGLYPH V034;Lo;0;L;;;;;N;;;;; -133A7;EGYPTIAN HIEROGLYPH V035;Lo;0;L;;;;;N;;;;; -133A8;EGYPTIAN HIEROGLYPH V036;Lo;0;L;;;;;N;;;;; -133A9;EGYPTIAN HIEROGLYPH V037;Lo;0;L;;;;;N;;;;; -133AA;EGYPTIAN HIEROGLYPH V037A;Lo;0;L;;;;;N;;;;; -133AB;EGYPTIAN HIEROGLYPH V038;Lo;0;L;;;;;N;;;;; -133AC;EGYPTIAN HIEROGLYPH V039;Lo;0;L;;;;;N;;;;; -133AD;EGYPTIAN HIEROGLYPH V040;Lo;0;L;;;;;N;;;;; -133AE;EGYPTIAN HIEROGLYPH V040A;Lo;0;L;;;;;N;;;;; -133AF;EGYPTIAN HIEROGLYPH W001;Lo;0;L;;;;;N;;;;; -133B0;EGYPTIAN HIEROGLYPH W002;Lo;0;L;;;;;N;;;;; -133B1;EGYPTIAN HIEROGLYPH W003;Lo;0;L;;;;;N;;;;; -133B2;EGYPTIAN HIEROGLYPH W003A;Lo;0;L;;;;;N;;;;; -133B3;EGYPTIAN HIEROGLYPH W004;Lo;0;L;;;;;N;;;;; -133B4;EGYPTIAN HIEROGLYPH W005;Lo;0;L;;;;;N;;;;; -133B5;EGYPTIAN HIEROGLYPH W006;Lo;0;L;;;;;N;;;;; -133B6;EGYPTIAN HIEROGLYPH W007;Lo;0;L;;;;;N;;;;; -133B7;EGYPTIAN HIEROGLYPH W008;Lo;0;L;;;;;N;;;;; -133B8;EGYPTIAN HIEROGLYPH W009;Lo;0;L;;;;;N;;;;; -133B9;EGYPTIAN HIEROGLYPH W009A;Lo;0;L;;;;;N;;;;; -133BA;EGYPTIAN HIEROGLYPH W010;Lo;0;L;;;;;N;;;;; -133BB;EGYPTIAN HIEROGLYPH W010A;Lo;0;L;;;;;N;;;;; -133BC;EGYPTIAN HIEROGLYPH W011;Lo;0;L;;;;;N;;;;; -133BD;EGYPTIAN HIEROGLYPH W012;Lo;0;L;;;;;N;;;;; -133BE;EGYPTIAN HIEROGLYPH W013;Lo;0;L;;;;;N;;;;; -133BF;EGYPTIAN HIEROGLYPH W014;Lo;0;L;;;;;N;;;;; -133C0;EGYPTIAN HIEROGLYPH W014A;Lo;0;L;;;;;N;;;;; -133C1;EGYPTIAN HIEROGLYPH W015;Lo;0;L;;;;;N;;;;; -133C2;EGYPTIAN HIEROGLYPH W016;Lo;0;L;;;;;N;;;;; -133C3;EGYPTIAN HIEROGLYPH W017;Lo;0;L;;;;;N;;;;; -133C4;EGYPTIAN HIEROGLYPH W017A;Lo;0;L;;;;;N;;;;; -133C5;EGYPTIAN HIEROGLYPH W018;Lo;0;L;;;;;N;;;;; -133C6;EGYPTIAN HIEROGLYPH W018A;Lo;0;L;;;;;N;;;;; -133C7;EGYPTIAN HIEROGLYPH W019;Lo;0;L;;;;;N;;;;; -133C8;EGYPTIAN HIEROGLYPH W020;Lo;0;L;;;;;N;;;;; -133C9;EGYPTIAN HIEROGLYPH W021;Lo;0;L;;;;;N;;;;; -133CA;EGYPTIAN HIEROGLYPH W022;Lo;0;L;;;;;N;;;;; -133CB;EGYPTIAN HIEROGLYPH W023;Lo;0;L;;;;;N;;;;; -133CC;EGYPTIAN HIEROGLYPH W024;Lo;0;L;;;;;N;;;;; -133CD;EGYPTIAN HIEROGLYPH W024A;Lo;0;L;;;;;N;;;;; -133CE;EGYPTIAN HIEROGLYPH W025;Lo;0;L;;;;;N;;;;; -133CF;EGYPTIAN HIEROGLYPH X001;Lo;0;L;;;;;N;;;;; -133D0;EGYPTIAN HIEROGLYPH X002;Lo;0;L;;;;;N;;;;; -133D1;EGYPTIAN HIEROGLYPH X003;Lo;0;L;;;;;N;;;;; -133D2;EGYPTIAN HIEROGLYPH X004;Lo;0;L;;;;;N;;;;; -133D3;EGYPTIAN HIEROGLYPH X004A;Lo;0;L;;;;;N;;;;; -133D4;EGYPTIAN HIEROGLYPH X004B;Lo;0;L;;;;;N;;;;; -133D5;EGYPTIAN HIEROGLYPH X005;Lo;0;L;;;;;N;;;;; -133D6;EGYPTIAN HIEROGLYPH X006;Lo;0;L;;;;;N;;;;; -133D7;EGYPTIAN HIEROGLYPH X006A;Lo;0;L;;;;;N;;;;; -133D8;EGYPTIAN HIEROGLYPH X007;Lo;0;L;;;;;N;;;;; -133D9;EGYPTIAN HIEROGLYPH X008;Lo;0;L;;;;;N;;;;; -133DA;EGYPTIAN HIEROGLYPH X008A;Lo;0;L;;;;;N;;;;; -133DB;EGYPTIAN HIEROGLYPH Y001;Lo;0;L;;;;;N;;;;; -133DC;EGYPTIAN HIEROGLYPH Y001A;Lo;0;L;;;;;N;;;;; -133DD;EGYPTIAN HIEROGLYPH Y002;Lo;0;L;;;;;N;;;;; -133DE;EGYPTIAN HIEROGLYPH Y003;Lo;0;L;;;;;N;;;;; -133DF;EGYPTIAN HIEROGLYPH Y004;Lo;0;L;;;;;N;;;;; -133E0;EGYPTIAN HIEROGLYPH Y005;Lo;0;L;;;;;N;;;;; -133E1;EGYPTIAN HIEROGLYPH Y006;Lo;0;L;;;;;N;;;;; -133E2;EGYPTIAN HIEROGLYPH Y007;Lo;0;L;;;;;N;;;;; -133E3;EGYPTIAN HIEROGLYPH Y008;Lo;0;L;;;;;N;;;;; -133E4;EGYPTIAN HIEROGLYPH Z001;Lo;0;L;;;;;N;;;;; -133E5;EGYPTIAN HIEROGLYPH Z002;Lo;0;L;;;;;N;;;;; -133E6;EGYPTIAN HIEROGLYPH Z002A;Lo;0;L;;;;;N;;;;; -133E7;EGYPTIAN HIEROGLYPH Z002B;Lo;0;L;;;;;N;;;;; -133E8;EGYPTIAN HIEROGLYPH Z002C;Lo;0;L;;;;;N;;;;; -133E9;EGYPTIAN HIEROGLYPH Z002D;Lo;0;L;;;;;N;;;;; -133EA;EGYPTIAN HIEROGLYPH Z003;Lo;0;L;;;;;N;;;;; -133EB;EGYPTIAN HIEROGLYPH Z003A;Lo;0;L;;;;;N;;;;; -133EC;EGYPTIAN HIEROGLYPH Z003B;Lo;0;L;;;;;N;;;;; -133ED;EGYPTIAN HIEROGLYPH Z004;Lo;0;L;;;;;N;;;;; -133EE;EGYPTIAN HIEROGLYPH Z004A;Lo;0;L;;;;;N;;;;; -133EF;EGYPTIAN HIEROGLYPH Z005;Lo;0;L;;;;;N;;;;; -133F0;EGYPTIAN HIEROGLYPH Z005A;Lo;0;L;;;;;N;;;;; -133F1;EGYPTIAN HIEROGLYPH Z006;Lo;0;L;;;;;N;;;;; -133F2;EGYPTIAN HIEROGLYPH Z007;Lo;0;L;;;;;N;;;;; -133F3;EGYPTIAN HIEROGLYPH Z008;Lo;0;L;;;;;N;;;;; -133F4;EGYPTIAN HIEROGLYPH Z009;Lo;0;L;;;;;N;;;;; -133F5;EGYPTIAN HIEROGLYPH Z010;Lo;0;L;;;;;N;;;;; -133F6;EGYPTIAN HIEROGLYPH Z011;Lo;0;L;;;;;N;;;;; -133F7;EGYPTIAN HIEROGLYPH Z012;Lo;0;L;;;;;N;;;;; -133F8;EGYPTIAN HIEROGLYPH Z013;Lo;0;L;;;;;N;;;;; -133F9;EGYPTIAN HIEROGLYPH Z014;Lo;0;L;;;;;N;;;;; -133FA;EGYPTIAN HIEROGLYPH Z015;Lo;0;L;;;;;N;;;;; -133FB;EGYPTIAN HIEROGLYPH Z015A;Lo;0;L;;;;;N;;;;; -133FC;EGYPTIAN HIEROGLYPH Z015B;Lo;0;L;;;;;N;;;;; -133FD;EGYPTIAN HIEROGLYPH Z015C;Lo;0;L;;;;;N;;;;; -133FE;EGYPTIAN HIEROGLYPH Z015D;Lo;0;L;;;;;N;;;;; -133FF;EGYPTIAN HIEROGLYPH Z015E;Lo;0;L;;;;;N;;;;; -13400;EGYPTIAN HIEROGLYPH Z015F;Lo;0;L;;;;;N;;;;; -13401;EGYPTIAN HIEROGLYPH Z015G;Lo;0;L;;;;;N;;;;; -13402;EGYPTIAN HIEROGLYPH Z015H;Lo;0;L;;;;;N;;;;; -13403;EGYPTIAN HIEROGLYPH Z015I;Lo;0;L;;;;;N;;;;; -13404;EGYPTIAN HIEROGLYPH Z016;Lo;0;L;;;;;N;;;;; -13405;EGYPTIAN HIEROGLYPH Z016A;Lo;0;L;;;;;N;;;;; -13406;EGYPTIAN HIEROGLYPH Z016B;Lo;0;L;;;;;N;;;;; -13407;EGYPTIAN HIEROGLYPH Z016C;Lo;0;L;;;;;N;;;;; -13408;EGYPTIAN HIEROGLYPH Z016D;Lo;0;L;;;;;N;;;;; -13409;EGYPTIAN HIEROGLYPH Z016E;Lo;0;L;;;;;N;;;;; -1340A;EGYPTIAN HIEROGLYPH Z016F;Lo;0;L;;;;;N;;;;; -1340B;EGYPTIAN HIEROGLYPH Z016G;Lo;0;L;;;;;N;;;;; -1340C;EGYPTIAN HIEROGLYPH Z016H;Lo;0;L;;;;;N;;;;; -1340D;EGYPTIAN HIEROGLYPH AA001;Lo;0;L;;;;;N;;;;; -1340E;EGYPTIAN HIEROGLYPH AA002;Lo;0;L;;;;;N;;;;; -1340F;EGYPTIAN HIEROGLYPH AA003;Lo;0;L;;;;;N;;;;; -13410;EGYPTIAN HIEROGLYPH AA004;Lo;0;L;;;;;N;;;;; -13411;EGYPTIAN HIEROGLYPH AA005;Lo;0;L;;;;;N;;;;; -13412;EGYPTIAN HIEROGLYPH AA006;Lo;0;L;;;;;N;;;;; -13413;EGYPTIAN HIEROGLYPH AA007;Lo;0;L;;;;;N;;;;; -13414;EGYPTIAN HIEROGLYPH AA007A;Lo;0;L;;;;;N;;;;; -13415;EGYPTIAN HIEROGLYPH AA007B;Lo;0;L;;;;;N;;;;; -13416;EGYPTIAN HIEROGLYPH AA008;Lo;0;L;;;;;N;;;;; -13417;EGYPTIAN HIEROGLYPH AA009;Lo;0;L;;;;;N;;;;; -13418;EGYPTIAN HIEROGLYPH AA010;Lo;0;L;;;;;N;;;;; -13419;EGYPTIAN HIEROGLYPH AA011;Lo;0;L;;;;;N;;;;; -1341A;EGYPTIAN HIEROGLYPH AA012;Lo;0;L;;;;;N;;;;; -1341B;EGYPTIAN HIEROGLYPH AA013;Lo;0;L;;;;;N;;;;; -1341C;EGYPTIAN HIEROGLYPH AA014;Lo;0;L;;;;;N;;;;; -1341D;EGYPTIAN HIEROGLYPH AA015;Lo;0;L;;;;;N;;;;; -1341E;EGYPTIAN HIEROGLYPH AA016;Lo;0;L;;;;;N;;;;; -1341F;EGYPTIAN HIEROGLYPH AA017;Lo;0;L;;;;;N;;;;; -13420;EGYPTIAN HIEROGLYPH AA018;Lo;0;L;;;;;N;;;;; -13421;EGYPTIAN HIEROGLYPH AA019;Lo;0;L;;;;;N;;;;; -13422;EGYPTIAN HIEROGLYPH AA020;Lo;0;L;;;;;N;;;;; -13423;EGYPTIAN HIEROGLYPH AA021;Lo;0;L;;;;;N;;;;; -13424;EGYPTIAN HIEROGLYPH AA022;Lo;0;L;;;;;N;;;;; -13425;EGYPTIAN HIEROGLYPH AA023;Lo;0;L;;;;;N;;;;; -13426;EGYPTIAN HIEROGLYPH AA024;Lo;0;L;;;;;N;;;;; -13427;EGYPTIAN HIEROGLYPH AA025;Lo;0;L;;;;;N;;;;; -13428;EGYPTIAN HIEROGLYPH AA026;Lo;0;L;;;;;N;;;;; -13429;EGYPTIAN HIEROGLYPH AA027;Lo;0;L;;;;;N;;;;; -1342A;EGYPTIAN HIEROGLYPH AA028;Lo;0;L;;;;;N;;;;; -1342B;EGYPTIAN HIEROGLYPH AA029;Lo;0;L;;;;;N;;;;; -1342C;EGYPTIAN HIEROGLYPH AA030;Lo;0;L;;;;;N;;;;; -1342D;EGYPTIAN HIEROGLYPH AA031;Lo;0;L;;;;;N;;;;; -1342E;EGYPTIAN HIEROGLYPH AA032;Lo;0;L;;;;;N;;;;; -1342F;EGYPTIAN HIEROGLYPH V011D;Lo;0;L;;;;;N;;;;; -13430;EGYPTIAN HIEROGLYPH VERTICAL JOINER;Cf;0;L;;;;;N;;;;; -13431;EGYPTIAN HIEROGLYPH HORIZONTAL JOINER;Cf;0;L;;;;;N;;;;; -13432;EGYPTIAN HIEROGLYPH INSERT AT TOP START;Cf;0;L;;;;;N;;;;; -13433;EGYPTIAN HIEROGLYPH INSERT AT BOTTOM START;Cf;0;L;;;;;N;;;;; -13434;EGYPTIAN HIEROGLYPH INSERT AT TOP END;Cf;0;L;;;;;N;;;;; -13435;EGYPTIAN HIEROGLYPH INSERT AT BOTTOM END;Cf;0;L;;;;;N;;;;; -13436;EGYPTIAN HIEROGLYPH OVERLAY MIDDLE;Cf;0;L;;;;;N;;;;; -13437;EGYPTIAN HIEROGLYPH BEGIN SEGMENT;Cf;0;L;;;;;N;;;;; -13438;EGYPTIAN HIEROGLYPH END SEGMENT;Cf;0;L;;;;;N;;;;; -13439;EGYPTIAN HIEROGLYPH INSERT AT MIDDLE;Cf;0;L;;;;;N;;;;; -1343A;EGYPTIAN HIEROGLYPH INSERT AT TOP;Cf;0;L;;;;;N;;;;; -1343B;EGYPTIAN HIEROGLYPH INSERT AT BOTTOM;Cf;0;L;;;;;N;;;;; -1343C;EGYPTIAN HIEROGLYPH BEGIN ENCLOSURE;Cf;0;L;;;;;N;;;;; -1343D;EGYPTIAN HIEROGLYPH END ENCLOSURE;Cf;0;L;;;;;N;;;;; -1343E;EGYPTIAN HIEROGLYPH BEGIN WALLED ENCLOSURE;Cf;0;L;;;;;N;;;;; -1343F;EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE;Cf;0;L;;;;;N;;;;; -13440;EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY;Mn;0;NSM;;;;;N;;;;; -13441;EGYPTIAN HIEROGLYPH FULL BLANK;Lo;0;L;;;;;N;;;;; -13442;EGYPTIAN HIEROGLYPH HALF BLANK;Lo;0;L;;;;;N;;;;; -13443;EGYPTIAN HIEROGLYPH LOST SIGN;Lo;0;L;;;;;N;;;;; -13444;EGYPTIAN HIEROGLYPH HALF LOST SIGN;Lo;0;L;;;;;N;;;;; -13445;EGYPTIAN HIEROGLYPH TALL LOST SIGN;Lo;0;L;;;;;N;;;;; -13446;EGYPTIAN HIEROGLYPH WIDE LOST SIGN;Lo;0;L;;;;;N;;;;; -13447;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START;Mn;0;NSM;;;;;N;;;;; -13448;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM START;Mn;0;NSM;;;;;N;;;;; -13449;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT START;Mn;0;NSM;;;;;N;;;;; -1344A;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP END;Mn;0;NSM;;;;;N;;;;; -1344B;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP;Mn;0;NSM;;;;;N;;;;; -1344C;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM START AND TOP END;Mn;0;NSM;;;;;N;;;;; -1344D;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT START AND TOP;Mn;0;NSM;;;;;N;;;;; -1344E;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM END;Mn;0;NSM;;;;;N;;;;; -1344F;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START AND BOTTOM END;Mn;0;NSM;;;;;N;;;;; -13450;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM;Mn;0;NSM;;;;;N;;;;; -13451;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT START AND BOTTOM;Mn;0;NSM;;;;;N;;;;; -13452;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT END;Mn;0;NSM;;;;;N;;;;; -13453;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP AND END;Mn;0;NSM;;;;;N;;;;; -13454;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM AND END;Mn;0;NSM;;;;;N;;;;; -13455;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED;Mn;0;NSM;;;;;N;;;;; -14400;ANATOLIAN HIEROGLYPH A001;Lo;0;L;;;;;N;;;;; -14401;ANATOLIAN HIEROGLYPH A002;Lo;0;L;;;;;N;;;;; -14402;ANATOLIAN HIEROGLYPH A003;Lo;0;L;;;;;N;;;;; -14403;ANATOLIAN HIEROGLYPH A004;Lo;0;L;;;;;N;;;;; -14404;ANATOLIAN HIEROGLYPH A005;Lo;0;L;;;;;N;;;;; -14405;ANATOLIAN HIEROGLYPH A006;Lo;0;L;;;;;N;;;;; -14406;ANATOLIAN HIEROGLYPH A007;Lo;0;L;;;;;N;;;;; -14407;ANATOLIAN HIEROGLYPH A008;Lo;0;L;;;;;N;;;;; -14408;ANATOLIAN HIEROGLYPH A009;Lo;0;L;;;;;N;;;;; -14409;ANATOLIAN HIEROGLYPH A010;Lo;0;L;;;;;N;;;;; -1440A;ANATOLIAN HIEROGLYPH A010A;Lo;0;L;;;;;N;;;;; -1440B;ANATOLIAN HIEROGLYPH A011;Lo;0;L;;;;;N;;;;; -1440C;ANATOLIAN HIEROGLYPH A012;Lo;0;L;;;;;N;;;;; -1440D;ANATOLIAN HIEROGLYPH A013;Lo;0;L;;;;;N;;;;; -1440E;ANATOLIAN HIEROGLYPH A014;Lo;0;L;;;;;N;;;;; -1440F;ANATOLIAN HIEROGLYPH A015;Lo;0;L;;;;;N;;;;; -14410;ANATOLIAN HIEROGLYPH A016;Lo;0;L;;;;;N;;;;; -14411;ANATOLIAN HIEROGLYPH A017;Lo;0;L;;;;;N;;;;; -14412;ANATOLIAN HIEROGLYPH A018;Lo;0;L;;;;;N;;;;; -14413;ANATOLIAN HIEROGLYPH A019;Lo;0;L;;;;;N;;;;; -14414;ANATOLIAN HIEROGLYPH A020;Lo;0;L;;;;;N;;;;; -14415;ANATOLIAN HIEROGLYPH A021;Lo;0;L;;;;;N;;;;; -14416;ANATOLIAN HIEROGLYPH A022;Lo;0;L;;;;;N;;;;; -14417;ANATOLIAN HIEROGLYPH A023;Lo;0;L;;;;;N;;;;; -14418;ANATOLIAN HIEROGLYPH A024;Lo;0;L;;;;;N;;;;; -14419;ANATOLIAN HIEROGLYPH A025;Lo;0;L;;;;;N;;;;; -1441A;ANATOLIAN HIEROGLYPH A026;Lo;0;L;;;;;N;;;;; -1441B;ANATOLIAN HIEROGLYPH A026A;Lo;0;L;;;;;N;;;;; -1441C;ANATOLIAN HIEROGLYPH A027;Lo;0;L;;;;;N;;;;; -1441D;ANATOLIAN HIEROGLYPH A028;Lo;0;L;;;;;N;;;;; -1441E;ANATOLIAN HIEROGLYPH A029;Lo;0;L;;;;;N;;;;; -1441F;ANATOLIAN HIEROGLYPH A030;Lo;0;L;;;;;N;;;;; -14420;ANATOLIAN HIEROGLYPH A031;Lo;0;L;;;;;N;;;;; -14421;ANATOLIAN HIEROGLYPH A032;Lo;0;L;;;;;N;;;;; -14422;ANATOLIAN HIEROGLYPH A033;Lo;0;L;;;;;N;;;;; -14423;ANATOLIAN HIEROGLYPH A034;Lo;0;L;;;;;N;;;;; -14424;ANATOLIAN HIEROGLYPH A035;Lo;0;L;;;;;N;;;;; -14425;ANATOLIAN HIEROGLYPH A036;Lo;0;L;;;;;N;;;;; -14426;ANATOLIAN HIEROGLYPH A037;Lo;0;L;;;;;N;;;;; -14427;ANATOLIAN HIEROGLYPH A038;Lo;0;L;;;;;N;;;;; -14428;ANATOLIAN HIEROGLYPH A039;Lo;0;L;;;;;N;;;;; -14429;ANATOLIAN HIEROGLYPH A039A;Lo;0;L;;;;;N;;;;; -1442A;ANATOLIAN HIEROGLYPH A040;Lo;0;L;;;;;N;;;;; -1442B;ANATOLIAN HIEROGLYPH A041;Lo;0;L;;;;;N;;;;; -1442C;ANATOLIAN HIEROGLYPH A041A;Lo;0;L;;;;;N;;;;; -1442D;ANATOLIAN HIEROGLYPH A042;Lo;0;L;;;;;N;;;;; -1442E;ANATOLIAN HIEROGLYPH A043;Lo;0;L;;;;;N;;;;; -1442F;ANATOLIAN HIEROGLYPH A044;Lo;0;L;;;;;N;;;;; -14430;ANATOLIAN HIEROGLYPH A045;Lo;0;L;;;;;N;;;;; -14431;ANATOLIAN HIEROGLYPH A045A;Lo;0;L;;;;;N;;;;; -14432;ANATOLIAN HIEROGLYPH A046;Lo;0;L;;;;;N;;;;; -14433;ANATOLIAN HIEROGLYPH A046A;Lo;0;L;;;;;N;;;;; -14434;ANATOLIAN HIEROGLYPH A046B;Lo;0;L;;;;;N;;;;; -14435;ANATOLIAN HIEROGLYPH A047;Lo;0;L;;;;;N;;;;; -14436;ANATOLIAN HIEROGLYPH A048;Lo;0;L;;;;;N;;;;; -14437;ANATOLIAN HIEROGLYPH A049;Lo;0;L;;;;;N;;;;; -14438;ANATOLIAN HIEROGLYPH A050;Lo;0;L;;;;;N;;;;; -14439;ANATOLIAN HIEROGLYPH A051;Lo;0;L;;;;;N;;;;; -1443A;ANATOLIAN HIEROGLYPH A052;Lo;0;L;;;;;N;;;;; -1443B;ANATOLIAN HIEROGLYPH A053;Lo;0;L;;;;;N;;;;; -1443C;ANATOLIAN HIEROGLYPH A054;Lo;0;L;;;;;N;;;;; -1443D;ANATOLIAN HIEROGLYPH A055;Lo;0;L;;;;;N;;;;; -1443E;ANATOLIAN HIEROGLYPH A056;Lo;0;L;;;;;N;;;;; -1443F;ANATOLIAN HIEROGLYPH A057;Lo;0;L;;;;;N;;;;; -14440;ANATOLIAN HIEROGLYPH A058;Lo;0;L;;;;;N;;;;; -14441;ANATOLIAN HIEROGLYPH A059;Lo;0;L;;;;;N;;;;; -14442;ANATOLIAN HIEROGLYPH A060;Lo;0;L;;;;;N;;;;; -14443;ANATOLIAN HIEROGLYPH A061;Lo;0;L;;;;;N;;;;; -14444;ANATOLIAN HIEROGLYPH A062;Lo;0;L;;;;;N;;;;; -14445;ANATOLIAN HIEROGLYPH A063;Lo;0;L;;;;;N;;;;; -14446;ANATOLIAN HIEROGLYPH A064;Lo;0;L;;;;;N;;;;; -14447;ANATOLIAN HIEROGLYPH A065;Lo;0;L;;;;;N;;;;; -14448;ANATOLIAN HIEROGLYPH A066;Lo;0;L;;;;;N;;;;; -14449;ANATOLIAN HIEROGLYPH A066A;Lo;0;L;;;;;N;;;;; -1444A;ANATOLIAN HIEROGLYPH A066B;Lo;0;L;;;;;N;;;;; -1444B;ANATOLIAN HIEROGLYPH A066C;Lo;0;L;;;;;N;;;;; -1444C;ANATOLIAN HIEROGLYPH A067;Lo;0;L;;;;;N;;;;; -1444D;ANATOLIAN HIEROGLYPH A068;Lo;0;L;;;;;N;;;;; -1444E;ANATOLIAN HIEROGLYPH A069;Lo;0;L;;;;;N;;;;; -1444F;ANATOLIAN HIEROGLYPH A070;Lo;0;L;;;;;N;;;;; -14450;ANATOLIAN HIEROGLYPH A071;Lo;0;L;;;;;N;;;;; -14451;ANATOLIAN HIEROGLYPH A072;Lo;0;L;;;;;N;;;;; -14452;ANATOLIAN HIEROGLYPH A073;Lo;0;L;;;;;N;;;;; -14453;ANATOLIAN HIEROGLYPH A074;Lo;0;L;;;;;N;;;;; -14454;ANATOLIAN HIEROGLYPH A075;Lo;0;L;;;;;N;;;;; -14455;ANATOLIAN HIEROGLYPH A076;Lo;0;L;;;;;N;;;;; -14456;ANATOLIAN HIEROGLYPH A077;Lo;0;L;;;;;N;;;;; -14457;ANATOLIAN HIEROGLYPH A078;Lo;0;L;;;;;N;;;;; -14458;ANATOLIAN HIEROGLYPH A079;Lo;0;L;;;;;N;;;;; -14459;ANATOLIAN HIEROGLYPH A080;Lo;0;L;;;;;N;;;;; -1445A;ANATOLIAN HIEROGLYPH A081;Lo;0;L;;;;;N;;;;; -1445B;ANATOLIAN HIEROGLYPH A082;Lo;0;L;;;;;N;;;;; -1445C;ANATOLIAN HIEROGLYPH A083;Lo;0;L;;;;;N;;;;; -1445D;ANATOLIAN HIEROGLYPH A084;Lo;0;L;;;;;N;;;;; -1445E;ANATOLIAN HIEROGLYPH A085;Lo;0;L;;;;;N;;;;; -1445F;ANATOLIAN HIEROGLYPH A086;Lo;0;L;;;;;N;;;;; -14460;ANATOLIAN HIEROGLYPH A087;Lo;0;L;;;;;N;;;;; -14461;ANATOLIAN HIEROGLYPH A088;Lo;0;L;;;;;N;;;;; -14462;ANATOLIAN HIEROGLYPH A089;Lo;0;L;;;;;N;;;;; -14463;ANATOLIAN HIEROGLYPH A090;Lo;0;L;;;;;N;;;;; -14464;ANATOLIAN HIEROGLYPH A091;Lo;0;L;;;;;N;;;;; -14465;ANATOLIAN HIEROGLYPH A092;Lo;0;L;;;;;N;;;;; -14466;ANATOLIAN HIEROGLYPH A093;Lo;0;L;;;;;N;;;;; -14467;ANATOLIAN HIEROGLYPH A094;Lo;0;L;;;;;N;;;;; -14468;ANATOLIAN HIEROGLYPH A095;Lo;0;L;;;;;N;;;;; -14469;ANATOLIAN HIEROGLYPH A096;Lo;0;L;;;;;N;;;;; -1446A;ANATOLIAN HIEROGLYPH A097;Lo;0;L;;;;;N;;;;; -1446B;ANATOLIAN HIEROGLYPH A097A;Lo;0;L;;;;;N;;;;; -1446C;ANATOLIAN HIEROGLYPH A098;Lo;0;L;;;;;N;;;;; -1446D;ANATOLIAN HIEROGLYPH A098A;Lo;0;L;;;;;N;;;;; -1446E;ANATOLIAN HIEROGLYPH A099;Lo;0;L;;;;;N;;;;; -1446F;ANATOLIAN HIEROGLYPH A100;Lo;0;L;;;;;N;;;;; -14470;ANATOLIAN HIEROGLYPH A100A;Lo;0;L;;;;;N;;;;; -14471;ANATOLIAN HIEROGLYPH A101;Lo;0;L;;;;;N;;;;; -14472;ANATOLIAN HIEROGLYPH A101A;Lo;0;L;;;;;N;;;;; -14473;ANATOLIAN HIEROGLYPH A102;Lo;0;L;;;;;N;;;;; -14474;ANATOLIAN HIEROGLYPH A102A;Lo;0;L;;;;;N;;;;; -14475;ANATOLIAN HIEROGLYPH A103;Lo;0;L;;;;;N;;;;; -14476;ANATOLIAN HIEROGLYPH A104;Lo;0;L;;;;;N;;;;; -14477;ANATOLIAN HIEROGLYPH A104A;Lo;0;L;;;;;N;;;;; -14478;ANATOLIAN HIEROGLYPH A104B;Lo;0;L;;;;;N;;;;; -14479;ANATOLIAN HIEROGLYPH A104C;Lo;0;L;;;;;N;;;;; -1447A;ANATOLIAN HIEROGLYPH A105;Lo;0;L;;;;;N;;;;; -1447B;ANATOLIAN HIEROGLYPH A105A;Lo;0;L;;;;;N;;;;; -1447C;ANATOLIAN HIEROGLYPH A105B;Lo;0;L;;;;;N;;;;; -1447D;ANATOLIAN HIEROGLYPH A106;Lo;0;L;;;;;N;;;;; -1447E;ANATOLIAN HIEROGLYPH A107;Lo;0;L;;;;;N;;;;; -1447F;ANATOLIAN HIEROGLYPH A107A;Lo;0;L;;;;;N;;;;; -14480;ANATOLIAN HIEROGLYPH A107B;Lo;0;L;;;;;N;;;;; -14481;ANATOLIAN HIEROGLYPH A107C;Lo;0;L;;;;;N;;;;; -14482;ANATOLIAN HIEROGLYPH A108;Lo;0;L;;;;;N;;;;; -14483;ANATOLIAN HIEROGLYPH A109;Lo;0;L;;;;;N;;;;; -14484;ANATOLIAN HIEROGLYPH A110;Lo;0;L;;;;;N;;;;; -14485;ANATOLIAN HIEROGLYPH A110A;Lo;0;L;;;;;N;;;;; -14486;ANATOLIAN HIEROGLYPH A110B;Lo;0;L;;;;;N;;;;; -14487;ANATOLIAN HIEROGLYPH A111;Lo;0;L;;;;;N;;;;; -14488;ANATOLIAN HIEROGLYPH A112;Lo;0;L;;;;;N;;;;; -14489;ANATOLIAN HIEROGLYPH A113;Lo;0;L;;;;;N;;;;; -1448A;ANATOLIAN HIEROGLYPH A114;Lo;0;L;;;;;N;;;;; -1448B;ANATOLIAN HIEROGLYPH A115;Lo;0;L;;;;;N;;;;; -1448C;ANATOLIAN HIEROGLYPH A115A;Lo;0;L;;;;;N;;;;; -1448D;ANATOLIAN HIEROGLYPH A116;Lo;0;L;;;;;N;;;;; -1448E;ANATOLIAN HIEROGLYPH A117;Lo;0;L;;;;;N;;;;; -1448F;ANATOLIAN HIEROGLYPH A118;Lo;0;L;;;;;N;;;;; -14490;ANATOLIAN HIEROGLYPH A119;Lo;0;L;;;;;N;;;;; -14491;ANATOLIAN HIEROGLYPH A120;Lo;0;L;;;;;N;;;;; -14492;ANATOLIAN HIEROGLYPH A121;Lo;0;L;;;;;N;;;;; -14493;ANATOLIAN HIEROGLYPH A122;Lo;0;L;;;;;N;;;;; -14494;ANATOLIAN HIEROGLYPH A123;Lo;0;L;;;;;N;;;;; -14495;ANATOLIAN HIEROGLYPH A124;Lo;0;L;;;;;N;;;;; -14496;ANATOLIAN HIEROGLYPH A125;Lo;0;L;;;;;N;;;;; -14497;ANATOLIAN HIEROGLYPH A125A;Lo;0;L;;;;;N;;;;; -14498;ANATOLIAN HIEROGLYPH A126;Lo;0;L;;;;;N;;;;; -14499;ANATOLIAN HIEROGLYPH A127;Lo;0;L;;;;;N;;;;; -1449A;ANATOLIAN HIEROGLYPH A128;Lo;0;L;;;;;N;;;;; -1449B;ANATOLIAN HIEROGLYPH A129;Lo;0;L;;;;;N;;;;; -1449C;ANATOLIAN HIEROGLYPH A130;Lo;0;L;;;;;N;;;;; -1449D;ANATOLIAN HIEROGLYPH A131;Lo;0;L;;;;;N;;;;; -1449E;ANATOLIAN HIEROGLYPH A132;Lo;0;L;;;;;N;;;;; -1449F;ANATOLIAN HIEROGLYPH A133;Lo;0;L;;;;;N;;;;; -144A0;ANATOLIAN HIEROGLYPH A134;Lo;0;L;;;;;N;;;;; -144A1;ANATOLIAN HIEROGLYPH A135;Lo;0;L;;;;;N;;;;; -144A2;ANATOLIAN HIEROGLYPH A135A;Lo;0;L;;;;;N;;;;; -144A3;ANATOLIAN HIEROGLYPH A136;Lo;0;L;;;;;N;;;;; -144A4;ANATOLIAN HIEROGLYPH A137;Lo;0;L;;;;;N;;;;; -144A5;ANATOLIAN HIEROGLYPH A138;Lo;0;L;;;;;N;;;;; -144A6;ANATOLIAN HIEROGLYPH A139;Lo;0;L;;;;;N;;;;; -144A7;ANATOLIAN HIEROGLYPH A140;Lo;0;L;;;;;N;;;;; -144A8;ANATOLIAN HIEROGLYPH A141;Lo;0;L;;;;;N;;;;; -144A9;ANATOLIAN HIEROGLYPH A142;Lo;0;L;;;;;N;;;;; -144AA;ANATOLIAN HIEROGLYPH A143;Lo;0;L;;;;;N;;;;; -144AB;ANATOLIAN HIEROGLYPH A144;Lo;0;L;;;;;N;;;;; -144AC;ANATOLIAN HIEROGLYPH A145;Lo;0;L;;;;;N;;;;; -144AD;ANATOLIAN HIEROGLYPH A146;Lo;0;L;;;;;N;;;;; -144AE;ANATOLIAN HIEROGLYPH A147;Lo;0;L;;;;;N;;;;; -144AF;ANATOLIAN HIEROGLYPH A148;Lo;0;L;;;;;N;;;;; -144B0;ANATOLIAN HIEROGLYPH A149;Lo;0;L;;;;;N;;;;; -144B1;ANATOLIAN HIEROGLYPH A150;Lo;0;L;;;;;N;;;;; -144B2;ANATOLIAN HIEROGLYPH A151;Lo;0;L;;;;;N;;;;; -144B3;ANATOLIAN HIEROGLYPH A152;Lo;0;L;;;;;N;;;;; -144B4;ANATOLIAN HIEROGLYPH A153;Lo;0;L;;;;;N;;;;; -144B5;ANATOLIAN HIEROGLYPH A154;Lo;0;L;;;;;N;;;;; -144B6;ANATOLIAN HIEROGLYPH A155;Lo;0;L;;;;;N;;;;; -144B7;ANATOLIAN HIEROGLYPH A156;Lo;0;L;;;;;N;;;;; -144B8;ANATOLIAN HIEROGLYPH A157;Lo;0;L;;;;;N;;;;; -144B9;ANATOLIAN HIEROGLYPH A158;Lo;0;L;;;;;N;;;;; -144BA;ANATOLIAN HIEROGLYPH A159;Lo;0;L;;;;;N;;;;; -144BB;ANATOLIAN HIEROGLYPH A160;Lo;0;L;;;;;N;;;;; -144BC;ANATOLIAN HIEROGLYPH A161;Lo;0;L;;;;;N;;;;; -144BD;ANATOLIAN HIEROGLYPH A162;Lo;0;L;;;;;N;;;;; -144BE;ANATOLIAN HIEROGLYPH A163;Lo;0;L;;;;;N;;;;; -144BF;ANATOLIAN HIEROGLYPH A164;Lo;0;L;;;;;N;;;;; -144C0;ANATOLIAN HIEROGLYPH A165;Lo;0;L;;;;;N;;;;; -144C1;ANATOLIAN HIEROGLYPH A166;Lo;0;L;;;;;N;;;;; -144C2;ANATOLIAN HIEROGLYPH A167;Lo;0;L;;;;;N;;;;; -144C3;ANATOLIAN HIEROGLYPH A168;Lo;0;L;;;;;N;;;;; -144C4;ANATOLIAN HIEROGLYPH A169;Lo;0;L;;;;;N;;;;; -144C5;ANATOLIAN HIEROGLYPH A170;Lo;0;L;;;;;N;;;;; -144C6;ANATOLIAN HIEROGLYPH A171;Lo;0;L;;;;;N;;;;; -144C7;ANATOLIAN HIEROGLYPH A172;Lo;0;L;;;;;N;;;;; -144C8;ANATOLIAN HIEROGLYPH A173;Lo;0;L;;;;;N;;;;; -144C9;ANATOLIAN HIEROGLYPH A174;Lo;0;L;;;;;N;;;;; -144CA;ANATOLIAN HIEROGLYPH A175;Lo;0;L;;;;;N;;;;; -144CB;ANATOLIAN HIEROGLYPH A176;Lo;0;L;;;;;N;;;;; -144CC;ANATOLIAN HIEROGLYPH A177;Lo;0;L;;;;;N;;;;; -144CD;ANATOLIAN HIEROGLYPH A178;Lo;0;L;;;;;N;;;;; -144CE;ANATOLIAN HIEROGLYPH A179;Lo;0;L;;;;;N;;;;; -144CF;ANATOLIAN HIEROGLYPH A180;Lo;0;L;;;;;N;;;;; -144D0;ANATOLIAN HIEROGLYPH A181;Lo;0;L;;;;;N;;;;; -144D1;ANATOLIAN HIEROGLYPH A182;Lo;0;L;;;;;N;;;;; -144D2;ANATOLIAN HIEROGLYPH A183;Lo;0;L;;;;;N;;;;; -144D3;ANATOLIAN HIEROGLYPH A184;Lo;0;L;;;;;N;;;;; -144D4;ANATOLIAN HIEROGLYPH A185;Lo;0;L;;;;;N;;;;; -144D5;ANATOLIAN HIEROGLYPH A186;Lo;0;L;;;;;N;;;;; -144D6;ANATOLIAN HIEROGLYPH A187;Lo;0;L;;;;;N;;;;; -144D7;ANATOLIAN HIEROGLYPH A188;Lo;0;L;;;;;N;;;;; -144D8;ANATOLIAN HIEROGLYPH A189;Lo;0;L;;;;;N;;;;; -144D9;ANATOLIAN HIEROGLYPH A190;Lo;0;L;;;;;N;;;;; -144DA;ANATOLIAN HIEROGLYPH A191;Lo;0;L;;;;;N;;;;; -144DB;ANATOLIAN HIEROGLYPH A192;Lo;0;L;;;;;N;;;;; -144DC;ANATOLIAN HIEROGLYPH A193;Lo;0;L;;;;;N;;;;; -144DD;ANATOLIAN HIEROGLYPH A194;Lo;0;L;;;;;N;;;;; -144DE;ANATOLIAN HIEROGLYPH A195;Lo;0;L;;;;;N;;;;; -144DF;ANATOLIAN HIEROGLYPH A196;Lo;0;L;;;;;N;;;;; -144E0;ANATOLIAN HIEROGLYPH A197;Lo;0;L;;;;;N;;;;; -144E1;ANATOLIAN HIEROGLYPH A198;Lo;0;L;;;;;N;;;;; -144E2;ANATOLIAN HIEROGLYPH A199;Lo;0;L;;;;;N;;;;; -144E3;ANATOLIAN HIEROGLYPH A200;Lo;0;L;;;;;N;;;;; -144E4;ANATOLIAN HIEROGLYPH A201;Lo;0;L;;;;;N;;;;; -144E5;ANATOLIAN HIEROGLYPH A202;Lo;0;L;;;;;N;;;;; -144E6;ANATOLIAN HIEROGLYPH A202A;Lo;0;L;;;;;N;;;;; -144E7;ANATOLIAN HIEROGLYPH A202B;Lo;0;L;;;;;N;;;;; -144E8;ANATOLIAN HIEROGLYPH A203;Lo;0;L;;;;;N;;;;; -144E9;ANATOLIAN HIEROGLYPH A204;Lo;0;L;;;;;N;;;;; -144EA;ANATOLIAN HIEROGLYPH A205;Lo;0;L;;;;;N;;;;; -144EB;ANATOLIAN HIEROGLYPH A206;Lo;0;L;;;;;N;;;;; -144EC;ANATOLIAN HIEROGLYPH A207;Lo;0;L;;;;;N;;;;; -144ED;ANATOLIAN HIEROGLYPH A207A;Lo;0;L;;;;;N;;;;; -144EE;ANATOLIAN HIEROGLYPH A208;Lo;0;L;;;;;N;;;;; -144EF;ANATOLIAN HIEROGLYPH A209;Lo;0;L;;;;;N;;;;; -144F0;ANATOLIAN HIEROGLYPH A209A;Lo;0;L;;;;;N;;;;; -144F1;ANATOLIAN HIEROGLYPH A210;Lo;0;L;;;;;N;;;;; -144F2;ANATOLIAN HIEROGLYPH A211;Lo;0;L;;;;;N;;;;; -144F3;ANATOLIAN HIEROGLYPH A212;Lo;0;L;;;;;N;;;;; -144F4;ANATOLIAN HIEROGLYPH A213;Lo;0;L;;;;;N;;;;; -144F5;ANATOLIAN HIEROGLYPH A214;Lo;0;L;;;;;N;;;;; -144F6;ANATOLIAN HIEROGLYPH A215;Lo;0;L;;;;;N;;;;; -144F7;ANATOLIAN HIEROGLYPH A215A;Lo;0;L;;;;;N;;;;; -144F8;ANATOLIAN HIEROGLYPH A216;Lo;0;L;;;;;N;;;;; -144F9;ANATOLIAN HIEROGLYPH A216A;Lo;0;L;;;;;N;;;;; -144FA;ANATOLIAN HIEROGLYPH A217;Lo;0;L;;;;;N;;;;; -144FB;ANATOLIAN HIEROGLYPH A218;Lo;0;L;;;;;N;;;;; -144FC;ANATOLIAN HIEROGLYPH A219;Lo;0;L;;;;;N;;;;; -144FD;ANATOLIAN HIEROGLYPH A220;Lo;0;L;;;;;N;;;;; -144FE;ANATOLIAN HIEROGLYPH A221;Lo;0;L;;;;;N;;;;; -144FF;ANATOLIAN HIEROGLYPH A222;Lo;0;L;;;;;N;;;;; -14500;ANATOLIAN HIEROGLYPH A223;Lo;0;L;;;;;N;;;;; -14501;ANATOLIAN HIEROGLYPH A224;Lo;0;L;;;;;N;;;;; -14502;ANATOLIAN HIEROGLYPH A225;Lo;0;L;;;;;N;;;;; -14503;ANATOLIAN HIEROGLYPH A226;Lo;0;L;;;;;N;;;;; -14504;ANATOLIAN HIEROGLYPH A227;Lo;0;L;;;;;N;;;;; -14505;ANATOLIAN HIEROGLYPH A227A;Lo;0;L;;;;;N;;;;; -14506;ANATOLIAN HIEROGLYPH A228;Lo;0;L;;;;;N;;;;; -14507;ANATOLIAN HIEROGLYPH A229;Lo;0;L;;;;;N;;;;; -14508;ANATOLIAN HIEROGLYPH A230;Lo;0;L;;;;;N;;;;; -14509;ANATOLIAN HIEROGLYPH A231;Lo;0;L;;;;;N;;;;; -1450A;ANATOLIAN HIEROGLYPH A232;Lo;0;L;;;;;N;;;;; -1450B;ANATOLIAN HIEROGLYPH A233;Lo;0;L;;;;;N;;;;; -1450C;ANATOLIAN HIEROGLYPH A234;Lo;0;L;;;;;N;;;;; -1450D;ANATOLIAN HIEROGLYPH A235;Lo;0;L;;;;;N;;;;; -1450E;ANATOLIAN HIEROGLYPH A236;Lo;0;L;;;;;N;;;;; -1450F;ANATOLIAN HIEROGLYPH A237;Lo;0;L;;;;;N;;;;; -14510;ANATOLIAN HIEROGLYPH A238;Lo;0;L;;;;;N;;;;; -14511;ANATOLIAN HIEROGLYPH A239;Lo;0;L;;;;;N;;;;; -14512;ANATOLIAN HIEROGLYPH A240;Lo;0;L;;;;;N;;;;; -14513;ANATOLIAN HIEROGLYPH A241;Lo;0;L;;;;;N;;;;; -14514;ANATOLIAN HIEROGLYPH A242;Lo;0;L;;;;;N;;;;; -14515;ANATOLIAN HIEROGLYPH A243;Lo;0;L;;;;;N;;;;; -14516;ANATOLIAN HIEROGLYPH A244;Lo;0;L;;;;;N;;;;; -14517;ANATOLIAN HIEROGLYPH A245;Lo;0;L;;;;;N;;;;; -14518;ANATOLIAN HIEROGLYPH A246;Lo;0;L;;;;;N;;;;; -14519;ANATOLIAN HIEROGLYPH A247;Lo;0;L;;;;;N;;;;; -1451A;ANATOLIAN HIEROGLYPH A248;Lo;0;L;;;;;N;;;;; -1451B;ANATOLIAN HIEROGLYPH A249;Lo;0;L;;;;;N;;;;; -1451C;ANATOLIAN HIEROGLYPH A250;Lo;0;L;;;;;N;;;;; -1451D;ANATOLIAN HIEROGLYPH A251;Lo;0;L;;;;;N;;;;; -1451E;ANATOLIAN HIEROGLYPH A252;Lo;0;L;;;;;N;;;;; -1451F;ANATOLIAN HIEROGLYPH A253;Lo;0;L;;;;;N;;;;; -14520;ANATOLIAN HIEROGLYPH A254;Lo;0;L;;;;;N;;;;; -14521;ANATOLIAN HIEROGLYPH A255;Lo;0;L;;;;;N;;;;; -14522;ANATOLIAN HIEROGLYPH A256;Lo;0;L;;;;;N;;;;; -14523;ANATOLIAN HIEROGLYPH A257;Lo;0;L;;;;;N;;;;; -14524;ANATOLIAN HIEROGLYPH A258;Lo;0;L;;;;;N;;;;; -14525;ANATOLIAN HIEROGLYPH A259;Lo;0;L;;;;;N;;;;; -14526;ANATOLIAN HIEROGLYPH A260;Lo;0;L;;;;;N;;;;; -14527;ANATOLIAN HIEROGLYPH A261;Lo;0;L;;;;;N;;;;; -14528;ANATOLIAN HIEROGLYPH A262;Lo;0;L;;;;;N;;;;; -14529;ANATOLIAN HIEROGLYPH A263;Lo;0;L;;;;;N;;;;; -1452A;ANATOLIAN HIEROGLYPH A264;Lo;0;L;;;;;N;;;;; -1452B;ANATOLIAN HIEROGLYPH A265;Lo;0;L;;;;;N;;;;; -1452C;ANATOLIAN HIEROGLYPH A266;Lo;0;L;;;;;N;;;;; -1452D;ANATOLIAN HIEROGLYPH A267;Lo;0;L;;;;;N;;;;; -1452E;ANATOLIAN HIEROGLYPH A267A;Lo;0;L;;;;;N;;;;; -1452F;ANATOLIAN HIEROGLYPH A268;Lo;0;L;;;;;N;;;;; -14530;ANATOLIAN HIEROGLYPH A269;Lo;0;L;;;;;N;;;;; -14531;ANATOLIAN HIEROGLYPH A270;Lo;0;L;;;;;N;;;;; -14532;ANATOLIAN HIEROGLYPH A271;Lo;0;L;;;;;N;;;;; -14533;ANATOLIAN HIEROGLYPH A272;Lo;0;L;;;;;N;;;;; -14534;ANATOLIAN HIEROGLYPH A273;Lo;0;L;;;;;N;;;;; -14535;ANATOLIAN HIEROGLYPH A274;Lo;0;L;;;;;N;;;;; -14536;ANATOLIAN HIEROGLYPH A275;Lo;0;L;;;;;N;;;;; -14537;ANATOLIAN HIEROGLYPH A276;Lo;0;L;;;;;N;;;;; -14538;ANATOLIAN HIEROGLYPH A277;Lo;0;L;;;;;N;;;;; -14539;ANATOLIAN HIEROGLYPH A278;Lo;0;L;;;;;N;;;;; -1453A;ANATOLIAN HIEROGLYPH A279;Lo;0;L;;;;;N;;;;; -1453B;ANATOLIAN HIEROGLYPH A280;Lo;0;L;;;;;N;;;;; -1453C;ANATOLIAN HIEROGLYPH A281;Lo;0;L;;;;;N;;;;; -1453D;ANATOLIAN HIEROGLYPH A282;Lo;0;L;;;;;N;;;;; -1453E;ANATOLIAN HIEROGLYPH A283;Lo;0;L;;;;;N;;;;; -1453F;ANATOLIAN HIEROGLYPH A284;Lo;0;L;;;;;N;;;;; -14540;ANATOLIAN HIEROGLYPH A285;Lo;0;L;;;;;N;;;;; -14541;ANATOLIAN HIEROGLYPH A286;Lo;0;L;;;;;N;;;;; -14542;ANATOLIAN HIEROGLYPH A287;Lo;0;L;;;;;N;;;;; -14543;ANATOLIAN HIEROGLYPH A288;Lo;0;L;;;;;N;;;;; -14544;ANATOLIAN HIEROGLYPH A289;Lo;0;L;;;;;N;;;;; -14545;ANATOLIAN HIEROGLYPH A289A;Lo;0;L;;;;;N;;;;; -14546;ANATOLIAN HIEROGLYPH A290;Lo;0;L;;;;;N;;;;; -14547;ANATOLIAN HIEROGLYPH A291;Lo;0;L;;;;;N;;;;; -14548;ANATOLIAN HIEROGLYPH A292;Lo;0;L;;;;;N;;;;; -14549;ANATOLIAN HIEROGLYPH A293;Lo;0;L;;;;;N;;;;; -1454A;ANATOLIAN HIEROGLYPH A294;Lo;0;L;;;;;N;;;;; -1454B;ANATOLIAN HIEROGLYPH A294A;Lo;0;L;;;;;N;;;;; -1454C;ANATOLIAN HIEROGLYPH A295;Lo;0;L;;;;;N;;;;; -1454D;ANATOLIAN HIEROGLYPH A296;Lo;0;L;;;;;N;;;;; -1454E;ANATOLIAN HIEROGLYPH A297;Lo;0;L;;;;;N;;;;; -1454F;ANATOLIAN HIEROGLYPH A298;Lo;0;L;;;;;N;;;;; -14550;ANATOLIAN HIEROGLYPH A299;Lo;0;L;;;;;N;;;;; -14551;ANATOLIAN HIEROGLYPH A299A;Lo;0;L;;;;;N;;;;; -14552;ANATOLIAN HIEROGLYPH A300;Lo;0;L;;;;;N;;;;; -14553;ANATOLIAN HIEROGLYPH A301;Lo;0;L;;;;;N;;;;; -14554;ANATOLIAN HIEROGLYPH A302;Lo;0;L;;;;;N;;;;; -14555;ANATOLIAN HIEROGLYPH A303;Lo;0;L;;;;;N;;;;; -14556;ANATOLIAN HIEROGLYPH A304;Lo;0;L;;;;;N;;;;; -14557;ANATOLIAN HIEROGLYPH A305;Lo;0;L;;;;;N;;;;; -14558;ANATOLIAN HIEROGLYPH A306;Lo;0;L;;;;;N;;;;; -14559;ANATOLIAN HIEROGLYPH A307;Lo;0;L;;;;;N;;;;; -1455A;ANATOLIAN HIEROGLYPH A308;Lo;0;L;;;;;N;;;;; -1455B;ANATOLIAN HIEROGLYPH A309;Lo;0;L;;;;;N;;;;; -1455C;ANATOLIAN HIEROGLYPH A309A;Lo;0;L;;;;;N;;;;; -1455D;ANATOLIAN HIEROGLYPH A310;Lo;0;L;;;;;N;;;;; -1455E;ANATOLIAN HIEROGLYPH A311;Lo;0;L;;;;;N;;;;; -1455F;ANATOLIAN HIEROGLYPH A312;Lo;0;L;;;;;N;;;;; -14560;ANATOLIAN HIEROGLYPH A313;Lo;0;L;;;;;N;;;;; -14561;ANATOLIAN HIEROGLYPH A314;Lo;0;L;;;;;N;;;;; -14562;ANATOLIAN HIEROGLYPH A315;Lo;0;L;;;;;N;;;;; -14563;ANATOLIAN HIEROGLYPH A316;Lo;0;L;;;;;N;;;;; -14564;ANATOLIAN HIEROGLYPH A317;Lo;0;L;;;;;N;;;;; -14565;ANATOLIAN HIEROGLYPH A318;Lo;0;L;;;;;N;;;;; -14566;ANATOLIAN HIEROGLYPH A319;Lo;0;L;;;;;N;;;;; -14567;ANATOLIAN HIEROGLYPH A320;Lo;0;L;;;;;N;;;;; -14568;ANATOLIAN HIEROGLYPH A321;Lo;0;L;;;;;N;;;;; -14569;ANATOLIAN HIEROGLYPH A322;Lo;0;L;;;;;N;;;;; -1456A;ANATOLIAN HIEROGLYPH A323;Lo;0;L;;;;;N;;;;; -1456B;ANATOLIAN HIEROGLYPH A324;Lo;0;L;;;;;N;;;;; -1456C;ANATOLIAN HIEROGLYPH A325;Lo;0;L;;;;;N;;;;; -1456D;ANATOLIAN HIEROGLYPH A326;Lo;0;L;;;;;N;;;;; -1456E;ANATOLIAN HIEROGLYPH A327;Lo;0;L;;;;;N;;;;; -1456F;ANATOLIAN HIEROGLYPH A328;Lo;0;L;;;;;N;;;;; -14570;ANATOLIAN HIEROGLYPH A329;Lo;0;L;;;;;N;;;;; -14571;ANATOLIAN HIEROGLYPH A329A;Lo;0;L;;;;;N;;;;; -14572;ANATOLIAN HIEROGLYPH A330;Lo;0;L;;;;;N;;;;; -14573;ANATOLIAN HIEROGLYPH A331;Lo;0;L;;;;;N;;;;; -14574;ANATOLIAN HIEROGLYPH A332A;Lo;0;L;;;;;N;;;;; -14575;ANATOLIAN HIEROGLYPH A332B;Lo;0;L;;;;;N;;;;; -14576;ANATOLIAN HIEROGLYPH A332C;Lo;0;L;;;;;N;;;;; -14577;ANATOLIAN HIEROGLYPH A333;Lo;0;L;;;;;N;;;;; -14578;ANATOLIAN HIEROGLYPH A334;Lo;0;L;;;;;N;;;;; -14579;ANATOLIAN HIEROGLYPH A335;Lo;0;L;;;;;N;;;;; -1457A;ANATOLIAN HIEROGLYPH A336;Lo;0;L;;;;;N;;;;; -1457B;ANATOLIAN HIEROGLYPH A336A;Lo;0;L;;;;;N;;;;; -1457C;ANATOLIAN HIEROGLYPH A336B;Lo;0;L;;;;;N;;;;; -1457D;ANATOLIAN HIEROGLYPH A336C;Lo;0;L;;;;;N;;;;; -1457E;ANATOLIAN HIEROGLYPH A337;Lo;0;L;;;;;N;;;;; -1457F;ANATOLIAN HIEROGLYPH A338;Lo;0;L;;;;;N;;;;; -14580;ANATOLIAN HIEROGLYPH A339;Lo;0;L;;;;;N;;;;; -14581;ANATOLIAN HIEROGLYPH A340;Lo;0;L;;;;;N;;;;; -14582;ANATOLIAN HIEROGLYPH A341;Lo;0;L;;;;;N;;;;; -14583;ANATOLIAN HIEROGLYPH A342;Lo;0;L;;;;;N;;;;; -14584;ANATOLIAN HIEROGLYPH A343;Lo;0;L;;;;;N;;;;; -14585;ANATOLIAN HIEROGLYPH A344;Lo;0;L;;;;;N;;;;; -14586;ANATOLIAN HIEROGLYPH A345;Lo;0;L;;;;;N;;;;; -14587;ANATOLIAN HIEROGLYPH A346;Lo;0;L;;;;;N;;;;; -14588;ANATOLIAN HIEROGLYPH A347;Lo;0;L;;;;;N;;;;; -14589;ANATOLIAN HIEROGLYPH A348;Lo;0;L;;;;;N;;;;; -1458A;ANATOLIAN HIEROGLYPH A349;Lo;0;L;;;;;N;;;;; -1458B;ANATOLIAN HIEROGLYPH A350;Lo;0;L;;;;;N;;;;; -1458C;ANATOLIAN HIEROGLYPH A351;Lo;0;L;;;;;N;;;;; -1458D;ANATOLIAN HIEROGLYPH A352;Lo;0;L;;;;;N;;;;; -1458E;ANATOLIAN HIEROGLYPH A353;Lo;0;L;;;;;N;;;;; -1458F;ANATOLIAN HIEROGLYPH A354;Lo;0;L;;;;;N;;;;; -14590;ANATOLIAN HIEROGLYPH A355;Lo;0;L;;;;;N;;;;; -14591;ANATOLIAN HIEROGLYPH A356;Lo;0;L;;;;;N;;;;; -14592;ANATOLIAN HIEROGLYPH A357;Lo;0;L;;;;;N;;;;; -14593;ANATOLIAN HIEROGLYPH A358;Lo;0;L;;;;;N;;;;; -14594;ANATOLIAN HIEROGLYPH A359;Lo;0;L;;;;;N;;;;; -14595;ANATOLIAN HIEROGLYPH A359A;Lo;0;L;;;;;N;;;;; -14596;ANATOLIAN HIEROGLYPH A360;Lo;0;L;;;;;N;;;;; -14597;ANATOLIAN HIEROGLYPH A361;Lo;0;L;;;;;N;;;;; -14598;ANATOLIAN HIEROGLYPH A362;Lo;0;L;;;;;N;;;;; -14599;ANATOLIAN HIEROGLYPH A363;Lo;0;L;;;;;N;;;;; -1459A;ANATOLIAN HIEROGLYPH A364;Lo;0;L;;;;;N;;;;; -1459B;ANATOLIAN HIEROGLYPH A364A;Lo;0;L;;;;;N;;;;; -1459C;ANATOLIAN HIEROGLYPH A365;Lo;0;L;;;;;N;;;;; -1459D;ANATOLIAN HIEROGLYPH A366;Lo;0;L;;;;;N;;;;; -1459E;ANATOLIAN HIEROGLYPH A367;Lo;0;L;;;;;N;;;;; -1459F;ANATOLIAN HIEROGLYPH A368;Lo;0;L;;;;;N;;;;; -145A0;ANATOLIAN HIEROGLYPH A368A;Lo;0;L;;;;;N;;;;; -145A1;ANATOLIAN HIEROGLYPH A369;Lo;0;L;;;;;N;;;;; -145A2;ANATOLIAN HIEROGLYPH A370;Lo;0;L;;;;;N;;;;; -145A3;ANATOLIAN HIEROGLYPH A371;Lo;0;L;;;;;N;;;;; -145A4;ANATOLIAN HIEROGLYPH A371A;Lo;0;L;;;;;N;;;;; -145A5;ANATOLIAN HIEROGLYPH A372;Lo;0;L;;;;;N;;;;; -145A6;ANATOLIAN HIEROGLYPH A373;Lo;0;L;;;;;N;;;;; -145A7;ANATOLIAN HIEROGLYPH A374;Lo;0;L;;;;;N;;;;; -145A8;ANATOLIAN HIEROGLYPH A375;Lo;0;L;;;;;N;;;;; -145A9;ANATOLIAN HIEROGLYPH A376;Lo;0;L;;;;;N;;;;; -145AA;ANATOLIAN HIEROGLYPH A377;Lo;0;L;;;;;N;;;;; -145AB;ANATOLIAN HIEROGLYPH A378;Lo;0;L;;;;;N;;;;; -145AC;ANATOLIAN HIEROGLYPH A379;Lo;0;L;;;;;N;;;;; -145AD;ANATOLIAN HIEROGLYPH A380;Lo;0;L;;;;;N;;;;; -145AE;ANATOLIAN HIEROGLYPH A381;Lo;0;L;;;;;N;;;;; -145AF;ANATOLIAN HIEROGLYPH A381A;Lo;0;L;;;;;N;;;;; -145B0;ANATOLIAN HIEROGLYPH A382;Lo;0;L;;;;;N;;;;; -145B1;ANATOLIAN HIEROGLYPH A383 RA OR RI;Lo;0;L;;;;;N;;;;; -145B2;ANATOLIAN HIEROGLYPH A383A;Lo;0;L;;;;;N;;;;; -145B3;ANATOLIAN HIEROGLYPH A384;Lo;0;L;;;;;N;;;;; -145B4;ANATOLIAN HIEROGLYPH A385;Lo;0;L;;;;;N;;;;; -145B5;ANATOLIAN HIEROGLYPH A386;Lo;0;L;;;;;N;;;;; -145B6;ANATOLIAN HIEROGLYPH A386A;Lo;0;L;;;;;N;;;;; -145B7;ANATOLIAN HIEROGLYPH A387;Lo;0;L;;;;;N;;;;; -145B8;ANATOLIAN HIEROGLYPH A388;Lo;0;L;;;;;N;;;;; -145B9;ANATOLIAN HIEROGLYPH A389;Lo;0;L;;;;;N;;;;; -145BA;ANATOLIAN HIEROGLYPH A390;Lo;0;L;;;;;N;;;;; -145BB;ANATOLIAN HIEROGLYPH A391;Lo;0;L;;;;;N;;;;; -145BC;ANATOLIAN HIEROGLYPH A392;Lo;0;L;;;;;N;;;;; -145BD;ANATOLIAN HIEROGLYPH A393 EIGHT;Lo;0;L;;;;;N;;;;; -145BE;ANATOLIAN HIEROGLYPH A394;Lo;0;L;;;;;N;;;;; -145BF;ANATOLIAN HIEROGLYPH A395;Lo;0;L;;;;;N;;;;; -145C0;ANATOLIAN HIEROGLYPH A396;Lo;0;L;;;;;N;;;;; -145C1;ANATOLIAN HIEROGLYPH A397;Lo;0;L;;;;;N;;;;; -145C2;ANATOLIAN HIEROGLYPH A398;Lo;0;L;;;;;N;;;;; -145C3;ANATOLIAN HIEROGLYPH A399;Lo;0;L;;;;;N;;;;; -145C4;ANATOLIAN HIEROGLYPH A400;Lo;0;L;;;;;N;;;;; -145C5;ANATOLIAN HIEROGLYPH A401;Lo;0;L;;;;;N;;;;; -145C6;ANATOLIAN HIEROGLYPH A402;Lo;0;L;;;;;N;;;;; -145C7;ANATOLIAN HIEROGLYPH A403;Lo;0;L;;;;;N;;;;; -145C8;ANATOLIAN HIEROGLYPH A404;Lo;0;L;;;;;N;;;;; -145C9;ANATOLIAN HIEROGLYPH A405;Lo;0;L;;;;;N;;;;; -145CA;ANATOLIAN HIEROGLYPH A406;Lo;0;L;;;;;N;;;;; -145CB;ANATOLIAN HIEROGLYPH A407;Lo;0;L;;;;;N;;;;; -145CC;ANATOLIAN HIEROGLYPH A408;Lo;0;L;;;;;N;;;;; -145CD;ANATOLIAN HIEROGLYPH A409;Lo;0;L;;;;;N;;;;; -145CE;ANATOLIAN HIEROGLYPH A410 BEGIN LOGOGRAM MARK;Lo;0;L;;;;;N;;;;; -145CF;ANATOLIAN HIEROGLYPH A410A END LOGOGRAM MARK;Lo;0;L;;;;;N;;;;; -145D0;ANATOLIAN HIEROGLYPH A411;Lo;0;L;;;;;N;;;;; -145D1;ANATOLIAN HIEROGLYPH A412;Lo;0;L;;;;;N;;;;; -145D2;ANATOLIAN HIEROGLYPH A413;Lo;0;L;;;;;N;;;;; -145D3;ANATOLIAN HIEROGLYPH A414;Lo;0;L;;;;;N;;;;; -145D4;ANATOLIAN HIEROGLYPH A415;Lo;0;L;;;;;N;;;;; -145D5;ANATOLIAN HIEROGLYPH A416;Lo;0;L;;;;;N;;;;; -145D6;ANATOLIAN HIEROGLYPH A417;Lo;0;L;;;;;N;;;;; -145D7;ANATOLIAN HIEROGLYPH A418;Lo;0;L;;;;;N;;;;; -145D8;ANATOLIAN HIEROGLYPH A419;Lo;0;L;;;;;N;;;;; -145D9;ANATOLIAN HIEROGLYPH A420;Lo;0;L;;;;;N;;;;; -145DA;ANATOLIAN HIEROGLYPH A421;Lo;0;L;;;;;N;;;;; -145DB;ANATOLIAN HIEROGLYPH A422;Lo;0;L;;;;;N;;;;; -145DC;ANATOLIAN HIEROGLYPH A423;Lo;0;L;;;;;N;;;;; -145DD;ANATOLIAN HIEROGLYPH A424;Lo;0;L;;;;;N;;;;; -145DE;ANATOLIAN HIEROGLYPH A425;Lo;0;L;;;;;N;;;;; -145DF;ANATOLIAN HIEROGLYPH A426;Lo;0;L;;;;;N;;;;; -145E0;ANATOLIAN HIEROGLYPH A427;Lo;0;L;;;;;N;;;;; -145E1;ANATOLIAN HIEROGLYPH A428;Lo;0;L;;;;;N;;;;; -145E2;ANATOLIAN HIEROGLYPH A429;Lo;0;L;;;;;N;;;;; -145E3;ANATOLIAN HIEROGLYPH A430;Lo;0;L;;;;;N;;;;; -145E4;ANATOLIAN HIEROGLYPH A431;Lo;0;L;;;;;N;;;;; -145E5;ANATOLIAN HIEROGLYPH A432;Lo;0;L;;;;;N;;;;; -145E6;ANATOLIAN HIEROGLYPH A433;Lo;0;L;;;;;N;;;;; -145E7;ANATOLIAN HIEROGLYPH A434;Lo;0;L;;;;;N;;;;; -145E8;ANATOLIAN HIEROGLYPH A435;Lo;0;L;;;;;N;;;;; -145E9;ANATOLIAN HIEROGLYPH A436;Lo;0;L;;;;;N;;;;; -145EA;ANATOLIAN HIEROGLYPH A437;Lo;0;L;;;;;N;;;;; -145EB;ANATOLIAN HIEROGLYPH A438;Lo;0;L;;;;;N;;;;; -145EC;ANATOLIAN HIEROGLYPH A439;Lo;0;L;;;;;N;;;;; -145ED;ANATOLIAN HIEROGLYPH A440;Lo;0;L;;;;;N;;;;; -145EE;ANATOLIAN HIEROGLYPH A441;Lo;0;L;;;;;N;;;;; -145EF;ANATOLIAN HIEROGLYPH A442;Lo;0;L;;;;;N;;;;; -145F0;ANATOLIAN HIEROGLYPH A443;Lo;0;L;;;;;N;;;;; -145F1;ANATOLIAN HIEROGLYPH A444;Lo;0;L;;;;;N;;;;; -145F2;ANATOLIAN HIEROGLYPH A445;Lo;0;L;;;;;N;;;;; -145F3;ANATOLIAN HIEROGLYPH A446;Lo;0;L;;;;;N;;;;; -145F4;ANATOLIAN HIEROGLYPH A447;Lo;0;L;;;;;N;;;;; -145F5;ANATOLIAN HIEROGLYPH A448;Lo;0;L;;;;;N;;;;; -145F6;ANATOLIAN HIEROGLYPH A449;Lo;0;L;;;;;N;;;;; -145F7;ANATOLIAN HIEROGLYPH A450;Lo;0;L;;;;;N;;;;; -145F8;ANATOLIAN HIEROGLYPH A450A;Lo;0;L;;;;;N;;;;; -145F9;ANATOLIAN HIEROGLYPH A451;Lo;0;L;;;;;N;;;;; -145FA;ANATOLIAN HIEROGLYPH A452;Lo;0;L;;;;;N;;;;; -145FB;ANATOLIAN HIEROGLYPH A453;Lo;0;L;;;;;N;;;;; -145FC;ANATOLIAN HIEROGLYPH A454;Lo;0;L;;;;;N;;;;; -145FD;ANATOLIAN HIEROGLYPH A455;Lo;0;L;;;;;N;;;;; -145FE;ANATOLIAN HIEROGLYPH A456;Lo;0;L;;;;;N;;;;; -145FF;ANATOLIAN HIEROGLYPH A457;Lo;0;L;;;;;N;;;;; -14600;ANATOLIAN HIEROGLYPH A457A;Lo;0;L;;;;;N;;;;; -14601;ANATOLIAN HIEROGLYPH A458;Lo;0;L;;;;;N;;;;; -14602;ANATOLIAN HIEROGLYPH A459;Lo;0;L;;;;;N;;;;; -14603;ANATOLIAN HIEROGLYPH A460;Lo;0;L;;;;;N;;;;; -14604;ANATOLIAN HIEROGLYPH A461;Lo;0;L;;;;;N;;;;; -14605;ANATOLIAN HIEROGLYPH A462;Lo;0;L;;;;;N;;;;; -14606;ANATOLIAN HIEROGLYPH A463;Lo;0;L;;;;;N;;;;; -14607;ANATOLIAN HIEROGLYPH A464;Lo;0;L;;;;;N;;;;; -14608;ANATOLIAN HIEROGLYPH A465;Lo;0;L;;;;;N;;;;; -14609;ANATOLIAN HIEROGLYPH A466;Lo;0;L;;;;;N;;;;; -1460A;ANATOLIAN HIEROGLYPH A467;Lo;0;L;;;;;N;;;;; -1460B;ANATOLIAN HIEROGLYPH A468;Lo;0;L;;;;;N;;;;; -1460C;ANATOLIAN HIEROGLYPH A469;Lo;0;L;;;;;N;;;;; -1460D;ANATOLIAN HIEROGLYPH A470;Lo;0;L;;;;;N;;;;; -1460E;ANATOLIAN HIEROGLYPH A471;Lo;0;L;;;;;N;;;;; -1460F;ANATOLIAN HIEROGLYPH A472;Lo;0;L;;;;;N;;;;; -14610;ANATOLIAN HIEROGLYPH A473;Lo;0;L;;;;;N;;;;; -14611;ANATOLIAN HIEROGLYPH A474;Lo;0;L;;;;;N;;;;; -14612;ANATOLIAN HIEROGLYPH A475;Lo;0;L;;;;;N;;;;; -14613;ANATOLIAN HIEROGLYPH A476;Lo;0;L;;;;;N;;;;; -14614;ANATOLIAN HIEROGLYPH A477;Lo;0;L;;;;;N;;;;; -14615;ANATOLIAN HIEROGLYPH A478;Lo;0;L;;;;;N;;;;; -14616;ANATOLIAN HIEROGLYPH A479;Lo;0;L;;;;;N;;;;; -14617;ANATOLIAN HIEROGLYPH A480;Lo;0;L;;;;;N;;;;; -14618;ANATOLIAN HIEROGLYPH A481;Lo;0;L;;;;;N;;;;; -14619;ANATOLIAN HIEROGLYPH A482;Lo;0;L;;;;;N;;;;; -1461A;ANATOLIAN HIEROGLYPH A483;Lo;0;L;;;;;N;;;;; -1461B;ANATOLIAN HIEROGLYPH A484;Lo;0;L;;;;;N;;;;; -1461C;ANATOLIAN HIEROGLYPH A485;Lo;0;L;;;;;N;;;;; -1461D;ANATOLIAN HIEROGLYPH A486;Lo;0;L;;;;;N;;;;; -1461E;ANATOLIAN HIEROGLYPH A487;Lo;0;L;;;;;N;;;;; -1461F;ANATOLIAN HIEROGLYPH A488;Lo;0;L;;;;;N;;;;; -14620;ANATOLIAN HIEROGLYPH A489;Lo;0;L;;;;;N;;;;; -14621;ANATOLIAN HIEROGLYPH A490;Lo;0;L;;;;;N;;;;; -14622;ANATOLIAN HIEROGLYPH A491;Lo;0;L;;;;;N;;;;; -14623;ANATOLIAN HIEROGLYPH A492;Lo;0;L;;;;;N;;;;; -14624;ANATOLIAN HIEROGLYPH A493;Lo;0;L;;;;;N;;;;; -14625;ANATOLIAN HIEROGLYPH A494;Lo;0;L;;;;;N;;;;; -14626;ANATOLIAN HIEROGLYPH A495;Lo;0;L;;;;;N;;;;; -14627;ANATOLIAN HIEROGLYPH A496;Lo;0;L;;;;;N;;;;; -14628;ANATOLIAN HIEROGLYPH A497;Lo;0;L;;;;;N;;;;; -14629;ANATOLIAN HIEROGLYPH A501;Lo;0;L;;;;;N;;;;; -1462A;ANATOLIAN HIEROGLYPH A502;Lo;0;L;;;;;N;;;;; -1462B;ANATOLIAN HIEROGLYPH A503;Lo;0;L;;;;;N;;;;; -1462C;ANATOLIAN HIEROGLYPH A504;Lo;0;L;;;;;N;;;;; -1462D;ANATOLIAN HIEROGLYPH A505;Lo;0;L;;;;;N;;;;; -1462E;ANATOLIAN HIEROGLYPH A506;Lo;0;L;;;;;N;;;;; -1462F;ANATOLIAN HIEROGLYPH A507;Lo;0;L;;;;;N;;;;; -14630;ANATOLIAN HIEROGLYPH A508;Lo;0;L;;;;;N;;;;; -14631;ANATOLIAN HIEROGLYPH A509;Lo;0;L;;;;;N;;;;; -14632;ANATOLIAN HIEROGLYPH A510;Lo;0;L;;;;;N;;;;; -14633;ANATOLIAN HIEROGLYPH A511;Lo;0;L;;;;;N;;;;; -14634;ANATOLIAN HIEROGLYPH A512;Lo;0;L;;;;;N;;;;; -14635;ANATOLIAN HIEROGLYPH A513;Lo;0;L;;;;;N;;;;; -14636;ANATOLIAN HIEROGLYPH A514;Lo;0;L;;;;;N;;;;; -14637;ANATOLIAN HIEROGLYPH A515;Lo;0;L;;;;;N;;;;; -14638;ANATOLIAN HIEROGLYPH A516;Lo;0;L;;;;;N;;;;; -14639;ANATOLIAN HIEROGLYPH A517;Lo;0;L;;;;;N;;;;; -1463A;ANATOLIAN HIEROGLYPH A518;Lo;0;L;;;;;N;;;;; -1463B;ANATOLIAN HIEROGLYPH A519;Lo;0;L;;;;;N;;;;; -1463C;ANATOLIAN HIEROGLYPH A520;Lo;0;L;;;;;N;;;;; -1463D;ANATOLIAN HIEROGLYPH A521;Lo;0;L;;;;;N;;;;; -1463E;ANATOLIAN HIEROGLYPH A522;Lo;0;L;;;;;N;;;;; -1463F;ANATOLIAN HIEROGLYPH A523;Lo;0;L;;;;;N;;;;; -14640;ANATOLIAN HIEROGLYPH A524;Lo;0;L;;;;;N;;;;; -14641;ANATOLIAN HIEROGLYPH A525;Lo;0;L;;;;;N;;;;; -14642;ANATOLIAN HIEROGLYPH A526;Lo;0;L;;;;;N;;;;; -14643;ANATOLIAN HIEROGLYPH A527;Lo;0;L;;;;;N;;;;; -14644;ANATOLIAN HIEROGLYPH A528;Lo;0;L;;;;;N;;;;; -14645;ANATOLIAN HIEROGLYPH A529;Lo;0;L;;;;;N;;;;; -14646;ANATOLIAN HIEROGLYPH A530;Lo;0;L;;;;;N;;;;; -16800;BAMUM LETTER PHASE-A NGKUE MFON;Lo;0;L;;;;;N;;;;; -16801;BAMUM LETTER PHASE-A GBIEE FON;Lo;0;L;;;;;N;;;;; -16802;BAMUM LETTER PHASE-A PON MFON PIPAEMGBIEE;Lo;0;L;;;;;N;;;;; -16803;BAMUM LETTER PHASE-A PON MFON PIPAEMBA;Lo;0;L;;;;;N;;;;; -16804;BAMUM LETTER PHASE-A NAA MFON;Lo;0;L;;;;;N;;;;; -16805;BAMUM LETTER PHASE-A SHUENSHUET;Lo;0;L;;;;;N;;;;; -16806;BAMUM LETTER PHASE-A TITA MFON;Lo;0;L;;;;;N;;;;; -16807;BAMUM LETTER PHASE-A NZA MFON;Lo;0;L;;;;;N;;;;; -16808;BAMUM LETTER PHASE-A SHINDA PA NJI;Lo;0;L;;;;;N;;;;; -16809;BAMUM LETTER PHASE-A PON PA NJI PIPAEMGBIEE;Lo;0;L;;;;;N;;;;; -1680A;BAMUM LETTER PHASE-A PON PA NJI PIPAEMBA;Lo;0;L;;;;;N;;;;; -1680B;BAMUM LETTER PHASE-A MAEMBGBIEE;Lo;0;L;;;;;N;;;;; -1680C;BAMUM LETTER PHASE-A TU MAEMBA;Lo;0;L;;;;;N;;;;; -1680D;BAMUM LETTER PHASE-A NGANGU;Lo;0;L;;;;;N;;;;; -1680E;BAMUM LETTER PHASE-A MAEMVEUX;Lo;0;L;;;;;N;;;;; -1680F;BAMUM LETTER PHASE-A MANSUAE;Lo;0;L;;;;;N;;;;; -16810;BAMUM LETTER PHASE-A MVEUAENGAM;Lo;0;L;;;;;N;;;;; -16811;BAMUM LETTER PHASE-A SEUNYAM;Lo;0;L;;;;;N;;;;; -16812;BAMUM LETTER PHASE-A NTOQPEN;Lo;0;L;;;;;N;;;;; -16813;BAMUM LETTER PHASE-A KEUKEUTNDA;Lo;0;L;;;;;N;;;;; -16814;BAMUM LETTER PHASE-A NKINDI;Lo;0;L;;;;;N;;;;; -16815;BAMUM LETTER PHASE-A SUU;Lo;0;L;;;;;N;;;;; -16816;BAMUM LETTER PHASE-A NGKUENZEUM;Lo;0;L;;;;;N;;;;; -16817;BAMUM LETTER PHASE-A LAPAQ;Lo;0;L;;;;;N;;;;; -16818;BAMUM LETTER PHASE-A LET KUT;Lo;0;L;;;;;N;;;;; -16819;BAMUM LETTER PHASE-A NTAP MFAA;Lo;0;L;;;;;N;;;;; -1681A;BAMUM LETTER PHASE-A MAEKEUP;Lo;0;L;;;;;N;;;;; -1681B;BAMUM LETTER PHASE-A PASHAE;Lo;0;L;;;;;N;;;;; -1681C;BAMUM LETTER PHASE-A GHEUAERAE;Lo;0;L;;;;;N;;;;; -1681D;BAMUM LETTER PHASE-A PAMSHAE;Lo;0;L;;;;;N;;;;; -1681E;BAMUM LETTER PHASE-A MON NGGEUAET;Lo;0;L;;;;;N;;;;; -1681F;BAMUM LETTER PHASE-A NZUN MEUT;Lo;0;L;;;;;N;;;;; -16820;BAMUM LETTER PHASE-A U YUQ NAE;Lo;0;L;;;;;N;;;;; -16821;BAMUM LETTER PHASE-A GHEUAEGHEUAE;Lo;0;L;;;;;N;;;;; -16822;BAMUM LETTER PHASE-A NTAP NTAA;Lo;0;L;;;;;N;;;;; -16823;BAMUM LETTER PHASE-A SISA;Lo;0;L;;;;;N;;;;; -16824;BAMUM LETTER PHASE-A MGBASA;Lo;0;L;;;;;N;;;;; -16825;BAMUM LETTER PHASE-A MEUNJOMNDEUQ;Lo;0;L;;;;;N;;;;; -16826;BAMUM LETTER PHASE-A MOOMPUQ;Lo;0;L;;;;;N;;;;; -16827;BAMUM LETTER PHASE-A KAFA;Lo;0;L;;;;;N;;;;; -16828;BAMUM LETTER PHASE-A PA LEERAEWA;Lo;0;L;;;;;N;;;;; -16829;BAMUM LETTER PHASE-A NDA LEERAEWA;Lo;0;L;;;;;N;;;;; -1682A;BAMUM LETTER PHASE-A PET;Lo;0;L;;;;;N;;;;; -1682B;BAMUM LETTER PHASE-A MAEMKPEN;Lo;0;L;;;;;N;;;;; -1682C;BAMUM LETTER PHASE-A NIKA;Lo;0;L;;;;;N;;;;; -1682D;BAMUM LETTER PHASE-A PUP;Lo;0;L;;;;;N;;;;; -1682E;BAMUM LETTER PHASE-A TUAEP;Lo;0;L;;;;;N;;;;; -1682F;BAMUM LETTER PHASE-A LUAEP;Lo;0;L;;;;;N;;;;; -16830;BAMUM LETTER PHASE-A SONJAM;Lo;0;L;;;;;N;;;;; -16831;BAMUM LETTER PHASE-A TEUTEUWEN;Lo;0;L;;;;;N;;;;; -16832;BAMUM LETTER PHASE-A MAENYI;Lo;0;L;;;;;N;;;;; -16833;BAMUM LETTER PHASE-A KET;Lo;0;L;;;;;N;;;;; -16834;BAMUM LETTER PHASE-A NDAANGGEUAET;Lo;0;L;;;;;N;;;;; -16835;BAMUM LETTER PHASE-A KUOQ;Lo;0;L;;;;;N;;;;; -16836;BAMUM LETTER PHASE-A MOOMEUT;Lo;0;L;;;;;N;;;;; -16837;BAMUM LETTER PHASE-A SHUM;Lo;0;L;;;;;N;;;;; -16838;BAMUM LETTER PHASE-A LOMMAE;Lo;0;L;;;;;N;;;;; -16839;BAMUM LETTER PHASE-A FIRI;Lo;0;L;;;;;N;;;;; -1683A;BAMUM LETTER PHASE-A ROM;Lo;0;L;;;;;N;;;;; -1683B;BAMUM LETTER PHASE-A KPOQ;Lo;0;L;;;;;N;;;;; -1683C;BAMUM LETTER PHASE-A SOQ;Lo;0;L;;;;;N;;;;; -1683D;BAMUM LETTER PHASE-A MAP PIEET;Lo;0;L;;;;;N;;;;; -1683E;BAMUM LETTER PHASE-A SHIRAE;Lo;0;L;;;;;N;;;;; -1683F;BAMUM LETTER PHASE-A NTAP;Lo;0;L;;;;;N;;;;; -16840;BAMUM LETTER PHASE-A SHOQ NSHUT YUM;Lo;0;L;;;;;N;;;;; -16841;BAMUM LETTER PHASE-A NYIT MONGKEUAEQ;Lo;0;L;;;;;N;;;;; -16842;BAMUM LETTER PHASE-A PAARAE;Lo;0;L;;;;;N;;;;; -16843;BAMUM LETTER PHASE-A NKAARAE;Lo;0;L;;;;;N;;;;; -16844;BAMUM LETTER PHASE-A UNKNOWN;Lo;0;L;;;;;N;;;;; -16845;BAMUM LETTER PHASE-A NGGEN;Lo;0;L;;;;;N;;;;; -16846;BAMUM LETTER PHASE-A MAESI;Lo;0;L;;;;;N;;;;; -16847;BAMUM LETTER PHASE-A NJAM;Lo;0;L;;;;;N;;;;; -16848;BAMUM LETTER PHASE-A MBANYI;Lo;0;L;;;;;N;;;;; -16849;BAMUM LETTER PHASE-A NYET;Lo;0;L;;;;;N;;;;; -1684A;BAMUM LETTER PHASE-A TEUAEN;Lo;0;L;;;;;N;;;;; -1684B;BAMUM LETTER PHASE-A SOT;Lo;0;L;;;;;N;;;;; -1684C;BAMUM LETTER PHASE-A PAAM;Lo;0;L;;;;;N;;;;; -1684D;BAMUM LETTER PHASE-A NSHIEE;Lo;0;L;;;;;N;;;;; -1684E;BAMUM LETTER PHASE-A MAEM;Lo;0;L;;;;;N;;;;; -1684F;BAMUM LETTER PHASE-A NYI;Lo;0;L;;;;;N;;;;; -16850;BAMUM LETTER PHASE-A KAQ;Lo;0;L;;;;;N;;;;; -16851;BAMUM LETTER PHASE-A NSHA;Lo;0;L;;;;;N;;;;; -16852;BAMUM LETTER PHASE-A VEE;Lo;0;L;;;;;N;;;;; -16853;BAMUM LETTER PHASE-A LU;Lo;0;L;;;;;N;;;;; -16854;BAMUM LETTER PHASE-A NEN;Lo;0;L;;;;;N;;;;; -16855;BAMUM LETTER PHASE-A NAQ;Lo;0;L;;;;;N;;;;; -16856;BAMUM LETTER PHASE-A MBAQ;Lo;0;L;;;;;N;;;;; -16857;BAMUM LETTER PHASE-B NSHUET;Lo;0;L;;;;;N;;;;; -16858;BAMUM LETTER PHASE-B TU MAEMGBIEE;Lo;0;L;;;;;N;;;;; -16859;BAMUM LETTER PHASE-B SIEE;Lo;0;L;;;;;N;;;;; -1685A;BAMUM LETTER PHASE-B SET TU;Lo;0;L;;;;;N;;;;; -1685B;BAMUM LETTER PHASE-B LOM NTEUM;Lo;0;L;;;;;N;;;;; -1685C;BAMUM LETTER PHASE-B MBA MAELEE;Lo;0;L;;;;;N;;;;; -1685D;BAMUM LETTER PHASE-B KIEEM;Lo;0;L;;;;;N;;;;; -1685E;BAMUM LETTER PHASE-B YEURAE;Lo;0;L;;;;;N;;;;; -1685F;BAMUM LETTER PHASE-B MBAARAE;Lo;0;L;;;;;N;;;;; -16860;BAMUM LETTER PHASE-B KAM;Lo;0;L;;;;;N;;;;; -16861;BAMUM LETTER PHASE-B PEESHI;Lo;0;L;;;;;N;;;;; -16862;BAMUM LETTER PHASE-B YAFU LEERAEWA;Lo;0;L;;;;;N;;;;; -16863;BAMUM LETTER PHASE-B LAM NSHUT NYAM;Lo;0;L;;;;;N;;;;; -16864;BAMUM LETTER PHASE-B NTIEE SHEUOQ;Lo;0;L;;;;;N;;;;; -16865;BAMUM LETTER PHASE-B NDU NJAA;Lo;0;L;;;;;N;;;;; -16866;BAMUM LETTER PHASE-B GHEUGHEUAEM;Lo;0;L;;;;;N;;;;; -16867;BAMUM LETTER PHASE-B PIT;Lo;0;L;;;;;N;;;;; -16868;BAMUM LETTER PHASE-B TU NSIEE;Lo;0;L;;;;;N;;;;; -16869;BAMUM LETTER PHASE-B SHET NJAQ;Lo;0;L;;;;;N;;;;; -1686A;BAMUM LETTER PHASE-B SHEUAEQTU;Lo;0;L;;;;;N;;;;; -1686B;BAMUM LETTER PHASE-B MFON TEUAEQ;Lo;0;L;;;;;N;;;;; -1686C;BAMUM LETTER PHASE-B MBIT MBAAKET;Lo;0;L;;;;;N;;;;; -1686D;BAMUM LETTER PHASE-B NYI NTEUM;Lo;0;L;;;;;N;;;;; -1686E;BAMUM LETTER PHASE-B KEUPUQ;Lo;0;L;;;;;N;;;;; -1686F;BAMUM LETTER PHASE-B GHEUGHEN;Lo;0;L;;;;;N;;;;; -16870;BAMUM LETTER PHASE-B KEUYEUX;Lo;0;L;;;;;N;;;;; -16871;BAMUM LETTER PHASE-B LAANAE;Lo;0;L;;;;;N;;;;; -16872;BAMUM LETTER PHASE-B PARUM;Lo;0;L;;;;;N;;;;; -16873;BAMUM LETTER PHASE-B VEUM;Lo;0;L;;;;;N;;;;; -16874;BAMUM LETTER PHASE-B NGKINDI MVOP;Lo;0;L;;;;;N;;;;; -16875;BAMUM LETTER PHASE-B NGGEU MBU;Lo;0;L;;;;;N;;;;; -16876;BAMUM LETTER PHASE-B WUAET;Lo;0;L;;;;;N;;;;; -16877;BAMUM LETTER PHASE-B SAKEUAE;Lo;0;L;;;;;N;;;;; -16878;BAMUM LETTER PHASE-B TAAM;Lo;0;L;;;;;N;;;;; -16879;BAMUM LETTER PHASE-B MEUQ;Lo;0;L;;;;;N;;;;; -1687A;BAMUM LETTER PHASE-B NGGUOQ;Lo;0;L;;;;;N;;;;; -1687B;BAMUM LETTER PHASE-B NGGUOQ LARGE;Lo;0;L;;;;;N;;;;; -1687C;BAMUM LETTER PHASE-B MFIYAQ;Lo;0;L;;;;;N;;;;; -1687D;BAMUM LETTER PHASE-B SUE;Lo;0;L;;;;;N;;;;; -1687E;BAMUM LETTER PHASE-B MBEURI;Lo;0;L;;;;;N;;;;; -1687F;BAMUM LETTER PHASE-B MONTIEEN;Lo;0;L;;;;;N;;;;; -16880;BAMUM LETTER PHASE-B NYAEMAE;Lo;0;L;;;;;N;;;;; -16881;BAMUM LETTER PHASE-B PUNGAAM;Lo;0;L;;;;;N;;;;; -16882;BAMUM LETTER PHASE-B MEUT NGGEET;Lo;0;L;;;;;N;;;;; -16883;BAMUM LETTER PHASE-B FEUX;Lo;0;L;;;;;N;;;;; -16884;BAMUM LETTER PHASE-B MBUOQ;Lo;0;L;;;;;N;;;;; -16885;BAMUM LETTER PHASE-B FEE;Lo;0;L;;;;;N;;;;; -16886;BAMUM LETTER PHASE-B KEUAEM;Lo;0;L;;;;;N;;;;; -16887;BAMUM LETTER PHASE-B MA NJEUAENA;Lo;0;L;;;;;N;;;;; -16888;BAMUM LETTER PHASE-B MA NJUQA;Lo;0;L;;;;;N;;;;; -16889;BAMUM LETTER PHASE-B LET;Lo;0;L;;;;;N;;;;; -1688A;BAMUM LETTER PHASE-B NGGAAM;Lo;0;L;;;;;N;;;;; -1688B;BAMUM LETTER PHASE-B NSEN;Lo;0;L;;;;;N;;;;; -1688C;BAMUM LETTER PHASE-B MA;Lo;0;L;;;;;N;;;;; -1688D;BAMUM LETTER PHASE-B KIQ;Lo;0;L;;;;;N;;;;; -1688E;BAMUM LETTER PHASE-B NGOM;Lo;0;L;;;;;N;;;;; -1688F;BAMUM LETTER PHASE-C NGKUE MAEMBA;Lo;0;L;;;;;N;;;;; -16890;BAMUM LETTER PHASE-C NZA;Lo;0;L;;;;;N;;;;; -16891;BAMUM LETTER PHASE-C YUM;Lo;0;L;;;;;N;;;;; -16892;BAMUM LETTER PHASE-C WANGKUOQ;Lo;0;L;;;;;N;;;;; -16893;BAMUM LETTER PHASE-C NGGEN;Lo;0;L;;;;;N;;;;; -16894;BAMUM LETTER PHASE-C NDEUAEREE;Lo;0;L;;;;;N;;;;; -16895;BAMUM LETTER PHASE-C NGKAQ;Lo;0;L;;;;;N;;;;; -16896;BAMUM LETTER PHASE-C GHARAE;Lo;0;L;;;;;N;;;;; -16897;BAMUM LETTER PHASE-C MBEEKEET;Lo;0;L;;;;;N;;;;; -16898;BAMUM LETTER PHASE-C GBAYI;Lo;0;L;;;;;N;;;;; -16899;BAMUM LETTER PHASE-C NYIR MKPARAQ MEUN;Lo;0;L;;;;;N;;;;; -1689A;BAMUM LETTER PHASE-C NTU MBIT;Lo;0;L;;;;;N;;;;; -1689B;BAMUM LETTER PHASE-C MBEUM;Lo;0;L;;;;;N;;;;; -1689C;BAMUM LETTER PHASE-C PIRIEEN;Lo;0;L;;;;;N;;;;; -1689D;BAMUM LETTER PHASE-C NDOMBU;Lo;0;L;;;;;N;;;;; -1689E;BAMUM LETTER PHASE-C MBAA CABBAGE-TREE;Lo;0;L;;;;;N;;;;; -1689F;BAMUM LETTER PHASE-C KEUSHEUAEP;Lo;0;L;;;;;N;;;;; -168A0;BAMUM LETTER PHASE-C GHAP;Lo;0;L;;;;;N;;;;; -168A1;BAMUM LETTER PHASE-C KEUKAQ;Lo;0;L;;;;;N;;;;; -168A2;BAMUM LETTER PHASE-C YU MUOMAE;Lo;0;L;;;;;N;;;;; -168A3;BAMUM LETTER PHASE-C NZEUM;Lo;0;L;;;;;N;;;;; -168A4;BAMUM LETTER PHASE-C MBUE;Lo;0;L;;;;;N;;;;; -168A5;BAMUM LETTER PHASE-C NSEUAEN;Lo;0;L;;;;;N;;;;; -168A6;BAMUM LETTER PHASE-C MBIT;Lo;0;L;;;;;N;;;;; -168A7;BAMUM LETTER PHASE-C YEUQ;Lo;0;L;;;;;N;;;;; -168A8;BAMUM LETTER PHASE-C KPARAQ;Lo;0;L;;;;;N;;;;; -168A9;BAMUM LETTER PHASE-C KAA;Lo;0;L;;;;;N;;;;; -168AA;BAMUM LETTER PHASE-C SEUX;Lo;0;L;;;;;N;;;;; -168AB;BAMUM LETTER PHASE-C NDIDA;Lo;0;L;;;;;N;;;;; -168AC;BAMUM LETTER PHASE-C TAASHAE;Lo;0;L;;;;;N;;;;; -168AD;BAMUM LETTER PHASE-C NJUEQ;Lo;0;L;;;;;N;;;;; -168AE;BAMUM LETTER PHASE-C TITA YUE;Lo;0;L;;;;;N;;;;; -168AF;BAMUM LETTER PHASE-C SUAET;Lo;0;L;;;;;N;;;;; -168B0;BAMUM LETTER PHASE-C NGGUAEN NYAM;Lo;0;L;;;;;N;;;;; -168B1;BAMUM LETTER PHASE-C VEUX;Lo;0;L;;;;;N;;;;; -168B2;BAMUM LETTER PHASE-C NANSANAQ;Lo;0;L;;;;;N;;;;; -168B3;BAMUM LETTER PHASE-C MA KEUAERI;Lo;0;L;;;;;N;;;;; -168B4;BAMUM LETTER PHASE-C NTAA;Lo;0;L;;;;;N;;;;; -168B5;BAMUM LETTER PHASE-C NGGUON;Lo;0;L;;;;;N;;;;; -168B6;BAMUM LETTER PHASE-C LAP;Lo;0;L;;;;;N;;;;; -168B7;BAMUM LETTER PHASE-C MBIRIEEN;Lo;0;L;;;;;N;;;;; -168B8;BAMUM LETTER PHASE-C MGBASAQ;Lo;0;L;;;;;N;;;;; -168B9;BAMUM LETTER PHASE-C NTEUNGBA;Lo;0;L;;;;;N;;;;; -168BA;BAMUM LETTER PHASE-C TEUTEUX;Lo;0;L;;;;;N;;;;; -168BB;BAMUM LETTER PHASE-C NGGUM;Lo;0;L;;;;;N;;;;; -168BC;BAMUM LETTER PHASE-C FUE;Lo;0;L;;;;;N;;;;; -168BD;BAMUM LETTER PHASE-C NDEUT;Lo;0;L;;;;;N;;;;; -168BE;BAMUM LETTER PHASE-C NSA;Lo;0;L;;;;;N;;;;; -168BF;BAMUM LETTER PHASE-C NSHAQ;Lo;0;L;;;;;N;;;;; -168C0;BAMUM LETTER PHASE-C BUNG;Lo;0;L;;;;;N;;;;; -168C1;BAMUM LETTER PHASE-C VEUAEPEN;Lo;0;L;;;;;N;;;;; -168C2;BAMUM LETTER PHASE-C MBERAE;Lo;0;L;;;;;N;;;;; -168C3;BAMUM LETTER PHASE-C RU;Lo;0;L;;;;;N;;;;; -168C4;BAMUM LETTER PHASE-C NJAEM;Lo;0;L;;;;;N;;;;; -168C5;BAMUM LETTER PHASE-C LAM;Lo;0;L;;;;;N;;;;; -168C6;BAMUM LETTER PHASE-C TITUAEP;Lo;0;L;;;;;N;;;;; -168C7;BAMUM LETTER PHASE-C NSUOT NGOM;Lo;0;L;;;;;N;;;;; -168C8;BAMUM LETTER PHASE-C NJEEEE;Lo;0;L;;;;;N;;;;; -168C9;BAMUM LETTER PHASE-C KET;Lo;0;L;;;;;N;;;;; -168CA;BAMUM LETTER PHASE-C NGGU;Lo;0;L;;;;;N;;;;; -168CB;BAMUM LETTER PHASE-C MAESI;Lo;0;L;;;;;N;;;;; -168CC;BAMUM LETTER PHASE-C MBUAEM;Lo;0;L;;;;;N;;;;; -168CD;BAMUM LETTER PHASE-C LU;Lo;0;L;;;;;N;;;;; -168CE;BAMUM LETTER PHASE-C KUT;Lo;0;L;;;;;N;;;;; -168CF;BAMUM LETTER PHASE-C NJAM;Lo;0;L;;;;;N;;;;; -168D0;BAMUM LETTER PHASE-C NGOM;Lo;0;L;;;;;N;;;;; -168D1;BAMUM LETTER PHASE-C WUP;Lo;0;L;;;;;N;;;;; -168D2;BAMUM LETTER PHASE-C NGGUEET;Lo;0;L;;;;;N;;;;; -168D3;BAMUM LETTER PHASE-C NSOM;Lo;0;L;;;;;N;;;;; -168D4;BAMUM LETTER PHASE-C NTEN;Lo;0;L;;;;;N;;;;; -168D5;BAMUM LETTER PHASE-C KUOP NKAARAE;Lo;0;L;;;;;N;;;;; -168D6;BAMUM LETTER PHASE-C NSUN;Lo;0;L;;;;;N;;;;; -168D7;BAMUM LETTER PHASE-C NDAM;Lo;0;L;;;;;N;;;;; -168D8;BAMUM LETTER PHASE-C MA NSIEE;Lo;0;L;;;;;N;;;;; -168D9;BAMUM LETTER PHASE-C YAA;Lo;0;L;;;;;N;;;;; -168DA;BAMUM LETTER PHASE-C NDAP;Lo;0;L;;;;;N;;;;; -168DB;BAMUM LETTER PHASE-C SHUEQ;Lo;0;L;;;;;N;;;;; -168DC;BAMUM LETTER PHASE-C SETFON;Lo;0;L;;;;;N;;;;; -168DD;BAMUM LETTER PHASE-C MBI;Lo;0;L;;;;;N;;;;; -168DE;BAMUM LETTER PHASE-C MAEMBA;Lo;0;L;;;;;N;;;;; -168DF;BAMUM LETTER PHASE-C MBANYI;Lo;0;L;;;;;N;;;;; -168E0;BAMUM LETTER PHASE-C KEUSEUX;Lo;0;L;;;;;N;;;;; -168E1;BAMUM LETTER PHASE-C MBEUX;Lo;0;L;;;;;N;;;;; -168E2;BAMUM LETTER PHASE-C KEUM;Lo;0;L;;;;;N;;;;; -168E3;BAMUM LETTER PHASE-C MBAA PICKET;Lo;0;L;;;;;N;;;;; -168E4;BAMUM LETTER PHASE-C YUWOQ;Lo;0;L;;;;;N;;;;; -168E5;BAMUM LETTER PHASE-C NJEUX;Lo;0;L;;;;;N;;;;; -168E6;BAMUM LETTER PHASE-C MIEE;Lo;0;L;;;;;N;;;;; -168E7;BAMUM LETTER PHASE-C MUAE;Lo;0;L;;;;;N;;;;; -168E8;BAMUM LETTER PHASE-C SHIQ;Lo;0;L;;;;;N;;;;; -168E9;BAMUM LETTER PHASE-C KEN LAW;Lo;0;L;;;;;N;;;;; -168EA;BAMUM LETTER PHASE-C KEN FATIGUE;Lo;0;L;;;;;N;;;;; -168EB;BAMUM LETTER PHASE-C NGAQ;Lo;0;L;;;;;N;;;;; -168EC;BAMUM LETTER PHASE-C NAQ;Lo;0;L;;;;;N;;;;; -168ED;BAMUM LETTER PHASE-C LIQ;Lo;0;L;;;;;N;;;;; -168EE;BAMUM LETTER PHASE-C PIN;Lo;0;L;;;;;N;;;;; -168EF;BAMUM LETTER PHASE-C PEN;Lo;0;L;;;;;N;;;;; -168F0;BAMUM LETTER PHASE-C TET;Lo;0;L;;;;;N;;;;; -168F1;BAMUM LETTER PHASE-D MBUO;Lo;0;L;;;;;N;;;;; -168F2;BAMUM LETTER PHASE-D WAP;Lo;0;L;;;;;N;;;;; -168F3;BAMUM LETTER PHASE-D NJI;Lo;0;L;;;;;N;;;;; -168F4;BAMUM LETTER PHASE-D MFON;Lo;0;L;;;;;N;;;;; -168F5;BAMUM LETTER PHASE-D NJIEE;Lo;0;L;;;;;N;;;;; -168F6;BAMUM LETTER PHASE-D LIEE;Lo;0;L;;;;;N;;;;; -168F7;BAMUM LETTER PHASE-D NJEUT;Lo;0;L;;;;;N;;;;; -168F8;BAMUM LETTER PHASE-D NSHEE;Lo;0;L;;;;;N;;;;; -168F9;BAMUM LETTER PHASE-D NGGAAMAE;Lo;0;L;;;;;N;;;;; -168FA;BAMUM LETTER PHASE-D NYAM;Lo;0;L;;;;;N;;;;; -168FB;BAMUM LETTER PHASE-D WUAEN;Lo;0;L;;;;;N;;;;; -168FC;BAMUM LETTER PHASE-D NGKUN;Lo;0;L;;;;;N;;;;; -168FD;BAMUM LETTER PHASE-D SHEE;Lo;0;L;;;;;N;;;;; -168FE;BAMUM LETTER PHASE-D NGKAP;Lo;0;L;;;;;N;;;;; -168FF;BAMUM LETTER PHASE-D KEUAETMEUN;Lo;0;L;;;;;N;;;;; -16900;BAMUM LETTER PHASE-D TEUT;Lo;0;L;;;;;N;;;;; -16901;BAMUM LETTER PHASE-D SHEUAE;Lo;0;L;;;;;N;;;;; -16902;BAMUM LETTER PHASE-D NJAP;Lo;0;L;;;;;N;;;;; -16903;BAMUM LETTER PHASE-D SUE;Lo;0;L;;;;;N;;;;; -16904;BAMUM LETTER PHASE-D KET;Lo;0;L;;;;;N;;;;; -16905;BAMUM LETTER PHASE-D YAEMMAE;Lo;0;L;;;;;N;;;;; -16906;BAMUM LETTER PHASE-D KUOM;Lo;0;L;;;;;N;;;;; -16907;BAMUM LETTER PHASE-D SAP;Lo;0;L;;;;;N;;;;; -16908;BAMUM LETTER PHASE-D MFEUT;Lo;0;L;;;;;N;;;;; -16909;BAMUM LETTER PHASE-D NDEUX;Lo;0;L;;;;;N;;;;; -1690A;BAMUM LETTER PHASE-D MALEERI;Lo;0;L;;;;;N;;;;; -1690B;BAMUM LETTER PHASE-D MEUT;Lo;0;L;;;;;N;;;;; -1690C;BAMUM LETTER PHASE-D SEUAEQ;Lo;0;L;;;;;N;;;;; -1690D;BAMUM LETTER PHASE-D YEN;Lo;0;L;;;;;N;;;;; -1690E;BAMUM LETTER PHASE-D NJEUAEM;Lo;0;L;;;;;N;;;;; -1690F;BAMUM LETTER PHASE-D KEUOT MBUAE;Lo;0;L;;;;;N;;;;; -16910;BAMUM LETTER PHASE-D NGKEURI;Lo;0;L;;;;;N;;;;; -16911;BAMUM LETTER PHASE-D TU;Lo;0;L;;;;;N;;;;; -16912;BAMUM LETTER PHASE-D GHAA;Lo;0;L;;;;;N;;;;; -16913;BAMUM LETTER PHASE-D NGKYEE;Lo;0;L;;;;;N;;;;; -16914;BAMUM LETTER PHASE-D FEUFEUAET;Lo;0;L;;;;;N;;;;; -16915;BAMUM LETTER PHASE-D NDEE;Lo;0;L;;;;;N;;;;; -16916;BAMUM LETTER PHASE-D MGBOFUM;Lo;0;L;;;;;N;;;;; -16917;BAMUM LETTER PHASE-D LEUAEP;Lo;0;L;;;;;N;;;;; -16918;BAMUM LETTER PHASE-D NDON;Lo;0;L;;;;;N;;;;; -16919;BAMUM LETTER PHASE-D MONI;Lo;0;L;;;;;N;;;;; -1691A;BAMUM LETTER PHASE-D MGBEUN;Lo;0;L;;;;;N;;;;; -1691B;BAMUM LETTER PHASE-D PUUT;Lo;0;L;;;;;N;;;;; -1691C;BAMUM LETTER PHASE-D MGBIEE;Lo;0;L;;;;;N;;;;; -1691D;BAMUM LETTER PHASE-D MFO;Lo;0;L;;;;;N;;;;; -1691E;BAMUM LETTER PHASE-D LUM;Lo;0;L;;;;;N;;;;; -1691F;BAMUM LETTER PHASE-D NSIEEP;Lo;0;L;;;;;N;;;;; -16920;BAMUM LETTER PHASE-D MBAA;Lo;0;L;;;;;N;;;;; -16921;BAMUM LETTER PHASE-D KWAET;Lo;0;L;;;;;N;;;;; -16922;BAMUM LETTER PHASE-D NYET;Lo;0;L;;;;;N;;;;; -16923;BAMUM LETTER PHASE-D TEUAEN;Lo;0;L;;;;;N;;;;; -16924;BAMUM LETTER PHASE-D SOT;Lo;0;L;;;;;N;;;;; -16925;BAMUM LETTER PHASE-D YUWOQ;Lo;0;L;;;;;N;;;;; -16926;BAMUM LETTER PHASE-D KEUM;Lo;0;L;;;;;N;;;;; -16927;BAMUM LETTER PHASE-D RAEM;Lo;0;L;;;;;N;;;;; -16928;BAMUM LETTER PHASE-D TEEEE;Lo;0;L;;;;;N;;;;; -16929;BAMUM LETTER PHASE-D NGKEUAEQ;Lo;0;L;;;;;N;;;;; -1692A;BAMUM LETTER PHASE-D MFEUAE;Lo;0;L;;;;;N;;;;; -1692B;BAMUM LETTER PHASE-D NSIEET;Lo;0;L;;;;;N;;;;; -1692C;BAMUM LETTER PHASE-D KEUP;Lo;0;L;;;;;N;;;;; -1692D;BAMUM LETTER PHASE-D PIP;Lo;0;L;;;;;N;;;;; -1692E;BAMUM LETTER PHASE-D PEUTAE;Lo;0;L;;;;;N;;;;; -1692F;BAMUM LETTER PHASE-D NYUE;Lo;0;L;;;;;N;;;;; -16930;BAMUM LETTER PHASE-D LET;Lo;0;L;;;;;N;;;;; -16931;BAMUM LETTER PHASE-D NGGAAM;Lo;0;L;;;;;N;;;;; -16932;BAMUM LETTER PHASE-D MFIEE;Lo;0;L;;;;;N;;;;; -16933;BAMUM LETTER PHASE-D NGGWAEN;Lo;0;L;;;;;N;;;;; -16934;BAMUM LETTER PHASE-D YUOM;Lo;0;L;;;;;N;;;;; -16935;BAMUM LETTER PHASE-D PAP;Lo;0;L;;;;;N;;;;; -16936;BAMUM LETTER PHASE-D YUOP;Lo;0;L;;;;;N;;;;; -16937;BAMUM LETTER PHASE-D NDAM;Lo;0;L;;;;;N;;;;; -16938;BAMUM LETTER PHASE-D NTEUM;Lo;0;L;;;;;N;;;;; -16939;BAMUM LETTER PHASE-D SUAE;Lo;0;L;;;;;N;;;;; -1693A;BAMUM LETTER PHASE-D KUN;Lo;0;L;;;;;N;;;;; -1693B;BAMUM LETTER PHASE-D NGGEUX;Lo;0;L;;;;;N;;;;; -1693C;BAMUM LETTER PHASE-D NGKIEE;Lo;0;L;;;;;N;;;;; -1693D;BAMUM LETTER PHASE-D TUOT;Lo;0;L;;;;;N;;;;; -1693E;BAMUM LETTER PHASE-D MEUN;Lo;0;L;;;;;N;;;;; -1693F;BAMUM LETTER PHASE-D KUQ;Lo;0;L;;;;;N;;;;; -16940;BAMUM LETTER PHASE-D NSUM;Lo;0;L;;;;;N;;;;; -16941;BAMUM LETTER PHASE-D TEUN;Lo;0;L;;;;;N;;;;; -16942;BAMUM LETTER PHASE-D MAENJET;Lo;0;L;;;;;N;;;;; -16943;BAMUM LETTER PHASE-D NGGAP;Lo;0;L;;;;;N;;;;; -16944;BAMUM LETTER PHASE-D LEUM;Lo;0;L;;;;;N;;;;; -16945;BAMUM LETTER PHASE-D NGGUOM;Lo;0;L;;;;;N;;;;; -16946;BAMUM LETTER PHASE-D NSHUT;Lo;0;L;;;;;N;;;;; -16947;BAMUM LETTER PHASE-D NJUEQ;Lo;0;L;;;;;N;;;;; -16948;BAMUM LETTER PHASE-D GHEUAE;Lo;0;L;;;;;N;;;;; -16949;BAMUM LETTER PHASE-D KU;Lo;0;L;;;;;N;;;;; -1694A;BAMUM LETTER PHASE-D REN OLD;Lo;0;L;;;;;N;;;;; -1694B;BAMUM LETTER PHASE-D TAE;Lo;0;L;;;;;N;;;;; -1694C;BAMUM LETTER PHASE-D TOQ;Lo;0;L;;;;;N;;;;; -1694D;BAMUM LETTER PHASE-D NYI;Lo;0;L;;;;;N;;;;; -1694E;BAMUM LETTER PHASE-D RII;Lo;0;L;;;;;N;;;;; -1694F;BAMUM LETTER PHASE-D LEEEE;Lo;0;L;;;;;N;;;;; -16950;BAMUM LETTER PHASE-D MEEEE;Lo;0;L;;;;;N;;;;; -16951;BAMUM LETTER PHASE-D M;Lo;0;L;;;;;N;;;;; -16952;BAMUM LETTER PHASE-D SUU;Lo;0;L;;;;;N;;;;; -16953;BAMUM LETTER PHASE-D MU;Lo;0;L;;;;;N;;;;; -16954;BAMUM LETTER PHASE-D SHII;Lo;0;L;;;;;N;;;;; -16955;BAMUM LETTER PHASE-D SHEUX;Lo;0;L;;;;;N;;;;; -16956;BAMUM LETTER PHASE-D KYEE;Lo;0;L;;;;;N;;;;; -16957;BAMUM LETTER PHASE-D NU;Lo;0;L;;;;;N;;;;; -16958;BAMUM LETTER PHASE-D SHU;Lo;0;L;;;;;N;;;;; -16959;BAMUM LETTER PHASE-D NTEE;Lo;0;L;;;;;N;;;;; -1695A;BAMUM LETTER PHASE-D PEE;Lo;0;L;;;;;N;;;;; -1695B;BAMUM LETTER PHASE-D NI;Lo;0;L;;;;;N;;;;; -1695C;BAMUM LETTER PHASE-D SHOQ;Lo;0;L;;;;;N;;;;; -1695D;BAMUM LETTER PHASE-D PUQ;Lo;0;L;;;;;N;;;;; -1695E;BAMUM LETTER PHASE-D MVOP;Lo;0;L;;;;;N;;;;; -1695F;BAMUM LETTER PHASE-D LOQ;Lo;0;L;;;;;N;;;;; -16960;BAMUM LETTER PHASE-D REN MUCH;Lo;0;L;;;;;N;;;;; -16961;BAMUM LETTER PHASE-D TI;Lo;0;L;;;;;N;;;;; -16962;BAMUM LETTER PHASE-D NTUU;Lo;0;L;;;;;N;;;;; -16963;BAMUM LETTER PHASE-D MBAA SEVEN;Lo;0;L;;;;;N;;;;; -16964;BAMUM LETTER PHASE-D SAQ;Lo;0;L;;;;;N;;;;; -16965;BAMUM LETTER PHASE-D FAA;Lo;0;L;;;;;N;;;;; -16966;BAMUM LETTER PHASE-E NDAP;Lo;0;L;;;;;N;;;;; -16967;BAMUM LETTER PHASE-E TOON;Lo;0;L;;;;;N;;;;; -16968;BAMUM LETTER PHASE-E MBEUM;Lo;0;L;;;;;N;;;;; -16969;BAMUM LETTER PHASE-E LAP;Lo;0;L;;;;;N;;;;; -1696A;BAMUM LETTER PHASE-E VOM;Lo;0;L;;;;;N;;;;; -1696B;BAMUM LETTER PHASE-E LOON;Lo;0;L;;;;;N;;;;; -1696C;BAMUM LETTER PHASE-E PAA;Lo;0;L;;;;;N;;;;; -1696D;BAMUM LETTER PHASE-E SOM;Lo;0;L;;;;;N;;;;; -1696E;BAMUM LETTER PHASE-E RAQ;Lo;0;L;;;;;N;;;;; -1696F;BAMUM LETTER PHASE-E NSHUOP;Lo;0;L;;;;;N;;;;; -16970;BAMUM LETTER PHASE-E NDUN;Lo;0;L;;;;;N;;;;; -16971;BAMUM LETTER PHASE-E PUAE;Lo;0;L;;;;;N;;;;; -16972;BAMUM LETTER PHASE-E TAM;Lo;0;L;;;;;N;;;;; -16973;BAMUM LETTER PHASE-E NGKA;Lo;0;L;;;;;N;;;;; -16974;BAMUM LETTER PHASE-E KPEUX;Lo;0;L;;;;;N;;;;; -16975;BAMUM LETTER PHASE-E WUO;Lo;0;L;;;;;N;;;;; -16976;BAMUM LETTER PHASE-E SEE;Lo;0;L;;;;;N;;;;; -16977;BAMUM LETTER PHASE-E NGGEUAET;Lo;0;L;;;;;N;;;;; -16978;BAMUM LETTER PHASE-E PAAM;Lo;0;L;;;;;N;;;;; -16979;BAMUM LETTER PHASE-E TOO;Lo;0;L;;;;;N;;;;; -1697A;BAMUM LETTER PHASE-E KUOP;Lo;0;L;;;;;N;;;;; -1697B;BAMUM LETTER PHASE-E LOM;Lo;0;L;;;;;N;;;;; -1697C;BAMUM LETTER PHASE-E NSHIEE;Lo;0;L;;;;;N;;;;; -1697D;BAMUM LETTER PHASE-E NGOP;Lo;0;L;;;;;N;;;;; -1697E;BAMUM LETTER PHASE-E MAEM;Lo;0;L;;;;;N;;;;; -1697F;BAMUM LETTER PHASE-E NGKEUX;Lo;0;L;;;;;N;;;;; -16980;BAMUM LETTER PHASE-E NGOQ;Lo;0;L;;;;;N;;;;; -16981;BAMUM LETTER PHASE-E NSHUE;Lo;0;L;;;;;N;;;;; -16982;BAMUM LETTER PHASE-E RIMGBA;Lo;0;L;;;;;N;;;;; -16983;BAMUM LETTER PHASE-E NJEUX;Lo;0;L;;;;;N;;;;; -16984;BAMUM LETTER PHASE-E PEEM;Lo;0;L;;;;;N;;;;; -16985;BAMUM LETTER PHASE-E SAA;Lo;0;L;;;;;N;;;;; -16986;BAMUM LETTER PHASE-E NGGURAE;Lo;0;L;;;;;N;;;;; -16987;BAMUM LETTER PHASE-E MGBA;Lo;0;L;;;;;N;;;;; -16988;BAMUM LETTER PHASE-E GHEUX;Lo;0;L;;;;;N;;;;; -16989;BAMUM LETTER PHASE-E NGKEUAEM;Lo;0;L;;;;;N;;;;; -1698A;BAMUM LETTER PHASE-E NJAEMLI;Lo;0;L;;;;;N;;;;; -1698B;BAMUM LETTER PHASE-E MAP;Lo;0;L;;;;;N;;;;; -1698C;BAMUM LETTER PHASE-E LOOT;Lo;0;L;;;;;N;;;;; -1698D;BAMUM LETTER PHASE-E NGGEEEE;Lo;0;L;;;;;N;;;;; -1698E;BAMUM LETTER PHASE-E NDIQ;Lo;0;L;;;;;N;;;;; -1698F;BAMUM LETTER PHASE-E TAEN NTEUM;Lo;0;L;;;;;N;;;;; -16990;BAMUM LETTER PHASE-E SET;Lo;0;L;;;;;N;;;;; -16991;BAMUM LETTER PHASE-E PUM;Lo;0;L;;;;;N;;;;; -16992;BAMUM LETTER PHASE-E NDAA SOFTNESS;Lo;0;L;;;;;N;;;;; -16993;BAMUM LETTER PHASE-E NGGUAESHAE NYAM;Lo;0;L;;;;;N;;;;; -16994;BAMUM LETTER PHASE-E YIEE;Lo;0;L;;;;;N;;;;; -16995;BAMUM LETTER PHASE-E GHEUN;Lo;0;L;;;;;N;;;;; -16996;BAMUM LETTER PHASE-E TUAE;Lo;0;L;;;;;N;;;;; -16997;BAMUM LETTER PHASE-E YEUAE;Lo;0;L;;;;;N;;;;; -16998;BAMUM LETTER PHASE-E PO;Lo;0;L;;;;;N;;;;; -16999;BAMUM LETTER PHASE-E TUMAE;Lo;0;L;;;;;N;;;;; -1699A;BAMUM LETTER PHASE-E KEUAE;Lo;0;L;;;;;N;;;;; -1699B;BAMUM LETTER PHASE-E SUAEN;Lo;0;L;;;;;N;;;;; -1699C;BAMUM LETTER PHASE-E TEUAEQ;Lo;0;L;;;;;N;;;;; -1699D;BAMUM LETTER PHASE-E VEUAE;Lo;0;L;;;;;N;;;;; -1699E;BAMUM LETTER PHASE-E WEUX;Lo;0;L;;;;;N;;;;; -1699F;BAMUM LETTER PHASE-E LAAM;Lo;0;L;;;;;N;;;;; -169A0;BAMUM LETTER PHASE-E PU;Lo;0;L;;;;;N;;;;; -169A1;BAMUM LETTER PHASE-E TAAQ;Lo;0;L;;;;;N;;;;; -169A2;BAMUM LETTER PHASE-E GHAAMAE;Lo;0;L;;;;;N;;;;; -169A3;BAMUM LETTER PHASE-E NGEUREUT;Lo;0;L;;;;;N;;;;; -169A4;BAMUM LETTER PHASE-E SHEUAEQ;Lo;0;L;;;;;N;;;;; -169A5;BAMUM LETTER PHASE-E MGBEN;Lo;0;L;;;;;N;;;;; -169A6;BAMUM LETTER PHASE-E MBEE;Lo;0;L;;;;;N;;;;; -169A7;BAMUM LETTER PHASE-E NZAQ;Lo;0;L;;;;;N;;;;; -169A8;BAMUM LETTER PHASE-E NKOM;Lo;0;L;;;;;N;;;;; -169A9;BAMUM LETTER PHASE-E GBET;Lo;0;L;;;;;N;;;;; -169AA;BAMUM LETTER PHASE-E TUM;Lo;0;L;;;;;N;;;;; -169AB;BAMUM LETTER PHASE-E KUET;Lo;0;L;;;;;N;;;;; -169AC;BAMUM LETTER PHASE-E YAP;Lo;0;L;;;;;N;;;;; -169AD;BAMUM LETTER PHASE-E NYI CLEAVER;Lo;0;L;;;;;N;;;;; -169AE;BAMUM LETTER PHASE-E YIT;Lo;0;L;;;;;N;;;;; -169AF;BAMUM LETTER PHASE-E MFEUQ;Lo;0;L;;;;;N;;;;; -169B0;BAMUM LETTER PHASE-E NDIAQ;Lo;0;L;;;;;N;;;;; -169B1;BAMUM LETTER PHASE-E PIEEQ;Lo;0;L;;;;;N;;;;; -169B2;BAMUM LETTER PHASE-E YUEQ;Lo;0;L;;;;;N;;;;; -169B3;BAMUM LETTER PHASE-E LEUAEM;Lo;0;L;;;;;N;;;;; -169B4;BAMUM LETTER PHASE-E FUE;Lo;0;L;;;;;N;;;;; -169B5;BAMUM LETTER PHASE-E GBEUX;Lo;0;L;;;;;N;;;;; -169B6;BAMUM LETTER PHASE-E NGKUP;Lo;0;L;;;;;N;;;;; -169B7;BAMUM LETTER PHASE-E KET;Lo;0;L;;;;;N;;;;; -169B8;BAMUM LETTER PHASE-E MAE;Lo;0;L;;;;;N;;;;; -169B9;BAMUM LETTER PHASE-E NGKAAMI;Lo;0;L;;;;;N;;;;; -169BA;BAMUM LETTER PHASE-E GHET;Lo;0;L;;;;;N;;;;; -169BB;BAMUM LETTER PHASE-E FA;Lo;0;L;;;;;N;;;;; -169BC;BAMUM LETTER PHASE-E NTUM;Lo;0;L;;;;;N;;;;; -169BD;BAMUM LETTER PHASE-E PEUT;Lo;0;L;;;;;N;;;;; -169BE;BAMUM LETTER PHASE-E YEUM;Lo;0;L;;;;;N;;;;; -169BF;BAMUM LETTER PHASE-E NGGEUAE;Lo;0;L;;;;;N;;;;; -169C0;BAMUM LETTER PHASE-E NYI BETWEEN;Lo;0;L;;;;;N;;;;; -169C1;BAMUM LETTER PHASE-E NZUQ;Lo;0;L;;;;;N;;;;; -169C2;BAMUM LETTER PHASE-E POON;Lo;0;L;;;;;N;;;;; -169C3;BAMUM LETTER PHASE-E MIEE;Lo;0;L;;;;;N;;;;; -169C4;BAMUM LETTER PHASE-E FUET;Lo;0;L;;;;;N;;;;; -169C5;BAMUM LETTER PHASE-E NAE;Lo;0;L;;;;;N;;;;; -169C6;BAMUM LETTER PHASE-E MUAE;Lo;0;L;;;;;N;;;;; -169C7;BAMUM LETTER PHASE-E GHEUAE;Lo;0;L;;;;;N;;;;; -169C8;BAMUM LETTER PHASE-E FU I;Lo;0;L;;;;;N;;;;; -169C9;BAMUM LETTER PHASE-E MVI;Lo;0;L;;;;;N;;;;; -169CA;BAMUM LETTER PHASE-E PUAQ;Lo;0;L;;;;;N;;;;; -169CB;BAMUM LETTER PHASE-E NGKUM;Lo;0;L;;;;;N;;;;; -169CC;BAMUM LETTER PHASE-E KUT;Lo;0;L;;;;;N;;;;; -169CD;BAMUM LETTER PHASE-E PIET;Lo;0;L;;;;;N;;;;; -169CE;BAMUM LETTER PHASE-E NTAP;Lo;0;L;;;;;N;;;;; -169CF;BAMUM LETTER PHASE-E YEUAET;Lo;0;L;;;;;N;;;;; -169D0;BAMUM LETTER PHASE-E NGGUP;Lo;0;L;;;;;N;;;;; -169D1;BAMUM LETTER PHASE-E PA PEOPLE;Lo;0;L;;;;;N;;;;; -169D2;BAMUM LETTER PHASE-E FU CALL;Lo;0;L;;;;;N;;;;; -169D3;BAMUM LETTER PHASE-E FOM;Lo;0;L;;;;;N;;;;; -169D4;BAMUM LETTER PHASE-E NJEE;Lo;0;L;;;;;N;;;;; -169D5;BAMUM LETTER PHASE-E A;Lo;0;L;;;;;N;;;;; -169D6;BAMUM LETTER PHASE-E TOQ;Lo;0;L;;;;;N;;;;; -169D7;BAMUM LETTER PHASE-E O;Lo;0;L;;;;;N;;;;; -169D8;BAMUM LETTER PHASE-E I;Lo;0;L;;;;;N;;;;; -169D9;BAMUM LETTER PHASE-E LAQ;Lo;0;L;;;;;N;;;;; -169DA;BAMUM LETTER PHASE-E PA PLURAL;Lo;0;L;;;;;N;;;;; -169DB;BAMUM LETTER PHASE-E TAA;Lo;0;L;;;;;N;;;;; -169DC;BAMUM LETTER PHASE-E TAQ;Lo;0;L;;;;;N;;;;; -169DD;BAMUM LETTER PHASE-E NDAA MY HOUSE;Lo;0;L;;;;;N;;;;; -169DE;BAMUM LETTER PHASE-E SHIQ;Lo;0;L;;;;;N;;;;; -169DF;BAMUM LETTER PHASE-E YEUX;Lo;0;L;;;;;N;;;;; -169E0;BAMUM LETTER PHASE-E NGUAE;Lo;0;L;;;;;N;;;;; -169E1;BAMUM LETTER PHASE-E YUAEN;Lo;0;L;;;;;N;;;;; -169E2;BAMUM LETTER PHASE-E YOQ SWIMMING;Lo;0;L;;;;;N;;;;; -169E3;BAMUM LETTER PHASE-E YOQ COVER;Lo;0;L;;;;;N;;;;; -169E4;BAMUM LETTER PHASE-E YUQ;Lo;0;L;;;;;N;;;;; -169E5;BAMUM LETTER PHASE-E YUN;Lo;0;L;;;;;N;;;;; -169E6;BAMUM LETTER PHASE-E KEUX;Lo;0;L;;;;;N;;;;; -169E7;BAMUM LETTER PHASE-E PEUX;Lo;0;L;;;;;N;;;;; -169E8;BAMUM LETTER PHASE-E NJEE EPOCH;Lo;0;L;;;;;N;;;;; -169E9;BAMUM LETTER PHASE-E PUE;Lo;0;L;;;;;N;;;;; -169EA;BAMUM LETTER PHASE-E WUE;Lo;0;L;;;;;N;;;;; -169EB;BAMUM LETTER PHASE-E FEE;Lo;0;L;;;;;N;;;;; -169EC;BAMUM LETTER PHASE-E VEE;Lo;0;L;;;;;N;;;;; -169ED;BAMUM LETTER PHASE-E LU;Lo;0;L;;;;;N;;;;; -169EE;BAMUM LETTER PHASE-E MI;Lo;0;L;;;;;N;;;;; -169EF;BAMUM LETTER PHASE-E REUX;Lo;0;L;;;;;N;;;;; -169F0;BAMUM LETTER PHASE-E RAE;Lo;0;L;;;;;N;;;;; -169F1;BAMUM LETTER PHASE-E NGUAET;Lo;0;L;;;;;N;;;;; -169F2;BAMUM LETTER PHASE-E NGA;Lo;0;L;;;;;N;;;;; -169F3;BAMUM LETTER PHASE-E SHO;Lo;0;L;;;;;N;;;;; -169F4;BAMUM LETTER PHASE-E SHOQ;Lo;0;L;;;;;N;;;;; -169F5;BAMUM LETTER PHASE-E FU REMEDY;Lo;0;L;;;;;N;;;;; -169F6;BAMUM LETTER PHASE-E NA;Lo;0;L;;;;;N;;;;; -169F7;BAMUM LETTER PHASE-E PI;Lo;0;L;;;;;N;;;;; -169F8;BAMUM LETTER PHASE-E LOQ;Lo;0;L;;;;;N;;;;; -169F9;BAMUM LETTER PHASE-E KO;Lo;0;L;;;;;N;;;;; -169FA;BAMUM LETTER PHASE-E MEN;Lo;0;L;;;;;N;;;;; -169FB;BAMUM LETTER PHASE-E MA;Lo;0;L;;;;;N;;;;; -169FC;BAMUM LETTER PHASE-E MAQ;Lo;0;L;;;;;N;;;;; -169FD;BAMUM LETTER PHASE-E TEU;Lo;0;L;;;;;N;;;;; -169FE;BAMUM LETTER PHASE-E KI;Lo;0;L;;;;;N;;;;; -169FF;BAMUM LETTER PHASE-E MON;Lo;0;L;;;;;N;;;;; -16A00;BAMUM LETTER PHASE-E TEN;Lo;0;L;;;;;N;;;;; -16A01;BAMUM LETTER PHASE-E FAQ;Lo;0;L;;;;;N;;;;; -16A02;BAMUM LETTER PHASE-E GHOM;Lo;0;L;;;;;N;;;;; -16A03;BAMUM LETTER PHASE-F KA;Lo;0;L;;;;;N;;;;; -16A04;BAMUM LETTER PHASE-F U;Lo;0;L;;;;;N;;;;; -16A05;BAMUM LETTER PHASE-F KU;Lo;0;L;;;;;N;;;;; -16A06;BAMUM LETTER PHASE-F EE;Lo;0;L;;;;;N;;;;; -16A07;BAMUM LETTER PHASE-F REE;Lo;0;L;;;;;N;;;;; -16A08;BAMUM LETTER PHASE-F TAE;Lo;0;L;;;;;N;;;;; -16A09;BAMUM LETTER PHASE-F NYI;Lo;0;L;;;;;N;;;;; -16A0A;BAMUM LETTER PHASE-F LA;Lo;0;L;;;;;N;;;;; -16A0B;BAMUM LETTER PHASE-F RII;Lo;0;L;;;;;N;;;;; -16A0C;BAMUM LETTER PHASE-F RIEE;Lo;0;L;;;;;N;;;;; -16A0D;BAMUM LETTER PHASE-F MEEEE;Lo;0;L;;;;;N;;;;; -16A0E;BAMUM LETTER PHASE-F TAA;Lo;0;L;;;;;N;;;;; -16A0F;BAMUM LETTER PHASE-F NDAA;Lo;0;L;;;;;N;;;;; -16A10;BAMUM LETTER PHASE-F NJAEM;Lo;0;L;;;;;N;;;;; -16A11;BAMUM LETTER PHASE-F M;Lo;0;L;;;;;N;;;;; -16A12;BAMUM LETTER PHASE-F SUU;Lo;0;L;;;;;N;;;;; -16A13;BAMUM LETTER PHASE-F SHII;Lo;0;L;;;;;N;;;;; -16A14;BAMUM LETTER PHASE-F SI;Lo;0;L;;;;;N;;;;; -16A15;BAMUM LETTER PHASE-F SEUX;Lo;0;L;;;;;N;;;;; -16A16;BAMUM LETTER PHASE-F KYEE;Lo;0;L;;;;;N;;;;; -16A17;BAMUM LETTER PHASE-F KET;Lo;0;L;;;;;N;;;;; -16A18;BAMUM LETTER PHASE-F NUAE;Lo;0;L;;;;;N;;;;; -16A19;BAMUM LETTER PHASE-F NU;Lo;0;L;;;;;N;;;;; -16A1A;BAMUM LETTER PHASE-F NJUAE;Lo;0;L;;;;;N;;;;; -16A1B;BAMUM LETTER PHASE-F YOQ;Lo;0;L;;;;;N;;;;; -16A1C;BAMUM LETTER PHASE-F SHU;Lo;0;L;;;;;N;;;;; -16A1D;BAMUM LETTER PHASE-F YA;Lo;0;L;;;;;N;;;;; -16A1E;BAMUM LETTER PHASE-F NSHA;Lo;0;L;;;;;N;;;;; -16A1F;BAMUM LETTER PHASE-F PEUX;Lo;0;L;;;;;N;;;;; -16A20;BAMUM LETTER PHASE-F NTEE;Lo;0;L;;;;;N;;;;; -16A21;BAMUM LETTER PHASE-F WUE;Lo;0;L;;;;;N;;;;; -16A22;BAMUM LETTER PHASE-F PEE;Lo;0;L;;;;;N;;;;; -16A23;BAMUM LETTER PHASE-F RU;Lo;0;L;;;;;N;;;;; -16A24;BAMUM LETTER PHASE-F NI;Lo;0;L;;;;;N;;;;; -16A25;BAMUM LETTER PHASE-F REUX;Lo;0;L;;;;;N;;;;; -16A26;BAMUM LETTER PHASE-F KEN;Lo;0;L;;;;;N;;;;; -16A27;BAMUM LETTER PHASE-F NGKWAEN;Lo;0;L;;;;;N;;;;; -16A28;BAMUM LETTER PHASE-F NGGA;Lo;0;L;;;;;N;;;;; -16A29;BAMUM LETTER PHASE-F SHO;Lo;0;L;;;;;N;;;;; -16A2A;BAMUM LETTER PHASE-F PUAE;Lo;0;L;;;;;N;;;;; -16A2B;BAMUM LETTER PHASE-F FOM;Lo;0;L;;;;;N;;;;; -16A2C;BAMUM LETTER PHASE-F WA;Lo;0;L;;;;;N;;;;; -16A2D;BAMUM LETTER PHASE-F LI;Lo;0;L;;;;;N;;;;; -16A2E;BAMUM LETTER PHASE-F LOQ;Lo;0;L;;;;;N;;;;; -16A2F;BAMUM LETTER PHASE-F KO;Lo;0;L;;;;;N;;;;; -16A30;BAMUM LETTER PHASE-F MBEN;Lo;0;L;;;;;N;;;;; -16A31;BAMUM LETTER PHASE-F REN;Lo;0;L;;;;;N;;;;; -16A32;BAMUM LETTER PHASE-F MA;Lo;0;L;;;;;N;;;;; -16A33;BAMUM LETTER PHASE-F MO;Lo;0;L;;;;;N;;;;; -16A34;BAMUM LETTER PHASE-F MBAA;Lo;0;L;;;;;N;;;;; -16A35;BAMUM LETTER PHASE-F TET;Lo;0;L;;;;;N;;;;; -16A36;BAMUM LETTER PHASE-F KPA;Lo;0;L;;;;;N;;;;; -16A37;BAMUM LETTER PHASE-F SAMBA;Lo;0;L;;;;;N;;;;; -16A38;BAMUM LETTER PHASE-F VUEQ;Lo;0;L;;;;;N;;;;; -16A40;MRO LETTER TA;Lo;0;L;;;;;N;;;;; -16A41;MRO LETTER NGI;Lo;0;L;;;;;N;;;;; -16A42;MRO LETTER YO;Lo;0;L;;;;;N;;;;; -16A43;MRO LETTER MIM;Lo;0;L;;;;;N;;;;; -16A44;MRO LETTER BA;Lo;0;L;;;;;N;;;;; -16A45;MRO LETTER DA;Lo;0;L;;;;;N;;;;; -16A46;MRO LETTER A;Lo;0;L;;;;;N;;;;; -16A47;MRO LETTER PHI;Lo;0;L;;;;;N;;;;; -16A48;MRO LETTER KHAI;Lo;0;L;;;;;N;;;;; -16A49;MRO LETTER HAO;Lo;0;L;;;;;N;;;;; -16A4A;MRO LETTER DAI;Lo;0;L;;;;;N;;;;; -16A4B;MRO LETTER CHU;Lo;0;L;;;;;N;;;;; -16A4C;MRO LETTER KEAAE;Lo;0;L;;;;;N;;;;; -16A4D;MRO LETTER OL;Lo;0;L;;;;;N;;;;; -16A4E;MRO LETTER MAEM;Lo;0;L;;;;;N;;;;; -16A4F;MRO LETTER NIN;Lo;0;L;;;;;N;;;;; -16A50;MRO LETTER PA;Lo;0;L;;;;;N;;;;; -16A51;MRO LETTER OO;Lo;0;L;;;;;N;;;;; -16A52;MRO LETTER O;Lo;0;L;;;;;N;;;;; -16A53;MRO LETTER RO;Lo;0;L;;;;;N;;;;; -16A54;MRO LETTER SHI;Lo;0;L;;;;;N;;;;; -16A55;MRO LETTER THEA;Lo;0;L;;;;;N;;;;; -16A56;MRO LETTER EA;Lo;0;L;;;;;N;;;;; -16A57;MRO LETTER WA;Lo;0;L;;;;;N;;;;; -16A58;MRO LETTER E;Lo;0;L;;;;;N;;;;; -16A59;MRO LETTER KO;Lo;0;L;;;;;N;;;;; -16A5A;MRO LETTER LAN;Lo;0;L;;;;;N;;;;; -16A5B;MRO LETTER LA;Lo;0;L;;;;;N;;;;; -16A5C;MRO LETTER HAI;Lo;0;L;;;;;N;;;;; -16A5D;MRO LETTER RI;Lo;0;L;;;;;N;;;;; -16A5E;MRO LETTER TEK;Lo;0;L;;;;;N;;;;; -16A60;MRO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -16A61;MRO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -16A62;MRO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -16A63;MRO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -16A64;MRO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -16A65;MRO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -16A66;MRO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -16A67;MRO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -16A68;MRO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -16A69;MRO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -16A6E;MRO DANDA;Po;0;L;;;;;N;;;;; -16A6F;MRO DOUBLE DANDA;Po;0;L;;;;;N;;;;; -16A70;TANGSA LETTER OZ;Lo;0;L;;;;;N;;;;; -16A71;TANGSA LETTER OC;Lo;0;L;;;;;N;;;;; -16A72;TANGSA LETTER OQ;Lo;0;L;;;;;N;;;;; -16A73;TANGSA LETTER OX;Lo;0;L;;;;;N;;;;; -16A74;TANGSA LETTER AZ;Lo;0;L;;;;;N;;;;; -16A75;TANGSA LETTER AC;Lo;0;L;;;;;N;;;;; -16A76;TANGSA LETTER AQ;Lo;0;L;;;;;N;;;;; -16A77;TANGSA LETTER AX;Lo;0;L;;;;;N;;;;; -16A78;TANGSA LETTER VZ;Lo;0;L;;;;;N;;;;; -16A79;TANGSA LETTER VC;Lo;0;L;;;;;N;;;;; -16A7A;TANGSA LETTER VQ;Lo;0;L;;;;;N;;;;; -16A7B;TANGSA LETTER VX;Lo;0;L;;;;;N;;;;; -16A7C;TANGSA LETTER EZ;Lo;0;L;;;;;N;;;;; -16A7D;TANGSA LETTER EC;Lo;0;L;;;;;N;;;;; -16A7E;TANGSA LETTER EQ;Lo;0;L;;;;;N;;;;; -16A7F;TANGSA LETTER EX;Lo;0;L;;;;;N;;;;; -16A80;TANGSA LETTER IZ;Lo;0;L;;;;;N;;;;; -16A81;TANGSA LETTER IC;Lo;0;L;;;;;N;;;;; -16A82;TANGSA LETTER IQ;Lo;0;L;;;;;N;;;;; -16A83;TANGSA LETTER IX;Lo;0;L;;;;;N;;;;; -16A84;TANGSA LETTER UZ;Lo;0;L;;;;;N;;;;; -16A85;TANGSA LETTER UC;Lo;0;L;;;;;N;;;;; -16A86;TANGSA LETTER UQ;Lo;0;L;;;;;N;;;;; -16A87;TANGSA LETTER UX;Lo;0;L;;;;;N;;;;; -16A88;TANGSA LETTER AWZ;Lo;0;L;;;;;N;;;;; -16A89;TANGSA LETTER AWC;Lo;0;L;;;;;N;;;;; -16A8A;TANGSA LETTER AWQ;Lo;0;L;;;;;N;;;;; -16A8B;TANGSA LETTER AWX;Lo;0;L;;;;;N;;;;; -16A8C;TANGSA LETTER UIZ;Lo;0;L;;;;;N;;;;; -16A8D;TANGSA LETTER UIC;Lo;0;L;;;;;N;;;;; -16A8E;TANGSA LETTER UIQ;Lo;0;L;;;;;N;;;;; -16A8F;TANGSA LETTER UIX;Lo;0;L;;;;;N;;;;; -16A90;TANGSA LETTER FINAL NG;Lo;0;L;;;;;N;;;;; -16A91;TANGSA LETTER LONG UEX;Lo;0;L;;;;;N;;;;; -16A92;TANGSA LETTER SHORT UEZ;Lo;0;L;;;;;N;;;;; -16A93;TANGSA LETTER SHORT AWX;Lo;0;L;;;;;N;;;;; -16A94;TANGSA LETTER UEC;Lo;0;L;;;;;N;;;;; -16A95;TANGSA LETTER UEZ;Lo;0;L;;;;;N;;;;; -16A96;TANGSA LETTER UEQ;Lo;0;L;;;;;N;;;;; -16A97;TANGSA LETTER UEX;Lo;0;L;;;;;N;;;;; -16A98;TANGSA LETTER UIUZ;Lo;0;L;;;;;N;;;;; -16A99;TANGSA LETTER UIUC;Lo;0;L;;;;;N;;;;; -16A9A;TANGSA LETTER UIUQ;Lo;0;L;;;;;N;;;;; -16A9B;TANGSA LETTER UIUX;Lo;0;L;;;;;N;;;;; -16A9C;TANGSA LETTER MZ;Lo;0;L;;;;;N;;;;; -16A9D;TANGSA LETTER MC;Lo;0;L;;;;;N;;;;; -16A9E;TANGSA LETTER MQ;Lo;0;L;;;;;N;;;;; -16A9F;TANGSA LETTER MX;Lo;0;L;;;;;N;;;;; -16AA0;TANGSA LETTER KA;Lo;0;L;;;;;N;;;;; -16AA1;TANGSA LETTER KHA;Lo;0;L;;;;;N;;;;; -16AA2;TANGSA LETTER GA;Lo;0;L;;;;;N;;;;; -16AA3;TANGSA LETTER NGA;Lo;0;L;;;;;N;;;;; -16AA4;TANGSA LETTER SA;Lo;0;L;;;;;N;;;;; -16AA5;TANGSA LETTER YA;Lo;0;L;;;;;N;;;;; -16AA6;TANGSA LETTER WA;Lo;0;L;;;;;N;;;;; -16AA7;TANGSA LETTER PA;Lo;0;L;;;;;N;;;;; -16AA8;TANGSA LETTER NYA;Lo;0;L;;;;;N;;;;; -16AA9;TANGSA LETTER PHA;Lo;0;L;;;;;N;;;;; -16AAA;TANGSA LETTER BA;Lo;0;L;;;;;N;;;;; -16AAB;TANGSA LETTER MA;Lo;0;L;;;;;N;;;;; -16AAC;TANGSA LETTER NA;Lo;0;L;;;;;N;;;;; -16AAD;TANGSA LETTER HA;Lo;0;L;;;;;N;;;;; -16AAE;TANGSA LETTER LA;Lo;0;L;;;;;N;;;;; -16AAF;TANGSA LETTER HTA;Lo;0;L;;;;;N;;;;; -16AB0;TANGSA LETTER TA;Lo;0;L;;;;;N;;;;; -16AB1;TANGSA LETTER DA;Lo;0;L;;;;;N;;;;; -16AB2;TANGSA LETTER RA;Lo;0;L;;;;;N;;;;; -16AB3;TANGSA LETTER NHA;Lo;0;L;;;;;N;;;;; -16AB4;TANGSA LETTER SHA;Lo;0;L;;;;;N;;;;; -16AB5;TANGSA LETTER CA;Lo;0;L;;;;;N;;;;; -16AB6;TANGSA LETTER TSA;Lo;0;L;;;;;N;;;;; -16AB7;TANGSA LETTER GHA;Lo;0;L;;;;;N;;;;; -16AB8;TANGSA LETTER HTTA;Lo;0;L;;;;;N;;;;; -16AB9;TANGSA LETTER THA;Lo;0;L;;;;;N;;;;; -16ABA;TANGSA LETTER XA;Lo;0;L;;;;;N;;;;; -16ABB;TANGSA LETTER FA;Lo;0;L;;;;;N;;;;; -16ABC;TANGSA LETTER DHA;Lo;0;L;;;;;N;;;;; -16ABD;TANGSA LETTER CHA;Lo;0;L;;;;;N;;;;; -16ABE;TANGSA LETTER ZA;Lo;0;L;;;;;N;;;;; -16AC0;TANGSA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -16AC1;TANGSA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -16AC2;TANGSA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -16AC3;TANGSA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -16AC4;TANGSA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -16AC5;TANGSA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -16AC6;TANGSA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -16AC7;TANGSA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -16AC8;TANGSA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -16AC9;TANGSA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -16AD0;BASSA VAH LETTER ENNI;Lo;0;L;;;;;N;;;;; -16AD1;BASSA VAH LETTER KA;Lo;0;L;;;;;N;;;;; -16AD2;BASSA VAH LETTER SE;Lo;0;L;;;;;N;;;;; -16AD3;BASSA VAH LETTER FA;Lo;0;L;;;;;N;;;;; -16AD4;BASSA VAH LETTER MBE;Lo;0;L;;;;;N;;;;; -16AD5;BASSA VAH LETTER YIE;Lo;0;L;;;;;N;;;;; -16AD6;BASSA VAH LETTER GAH;Lo;0;L;;;;;N;;;;; -16AD7;BASSA VAH LETTER DHII;Lo;0;L;;;;;N;;;;; -16AD8;BASSA VAH LETTER KPAH;Lo;0;L;;;;;N;;;;; -16AD9;BASSA VAH LETTER JO;Lo;0;L;;;;;N;;;;; -16ADA;BASSA VAH LETTER HWAH;Lo;0;L;;;;;N;;;;; -16ADB;BASSA VAH LETTER WA;Lo;0;L;;;;;N;;;;; -16ADC;BASSA VAH LETTER ZO;Lo;0;L;;;;;N;;;;; -16ADD;BASSA VAH LETTER GBU;Lo;0;L;;;;;N;;;;; -16ADE;BASSA VAH LETTER DO;Lo;0;L;;;;;N;;;;; -16ADF;BASSA VAH LETTER CE;Lo;0;L;;;;;N;;;;; -16AE0;BASSA VAH LETTER UWU;Lo;0;L;;;;;N;;;;; -16AE1;BASSA VAH LETTER TO;Lo;0;L;;;;;N;;;;; -16AE2;BASSA VAH LETTER BA;Lo;0;L;;;;;N;;;;; -16AE3;BASSA VAH LETTER VU;Lo;0;L;;;;;N;;;;; -16AE4;BASSA VAH LETTER YEIN;Lo;0;L;;;;;N;;;;; -16AE5;BASSA VAH LETTER PA;Lo;0;L;;;;;N;;;;; -16AE6;BASSA VAH LETTER WADDA;Lo;0;L;;;;;N;;;;; -16AE7;BASSA VAH LETTER A;Lo;0;L;;;;;N;;;;; -16AE8;BASSA VAH LETTER O;Lo;0;L;;;;;N;;;;; -16AE9;BASSA VAH LETTER OO;Lo;0;L;;;;;N;;;;; -16AEA;BASSA VAH LETTER U;Lo;0;L;;;;;N;;;;; -16AEB;BASSA VAH LETTER EE;Lo;0;L;;;;;N;;;;; -16AEC;BASSA VAH LETTER E;Lo;0;L;;;;;N;;;;; -16AED;BASSA VAH LETTER I;Lo;0;L;;;;;N;;;;; -16AF0;BASSA VAH COMBINING HIGH TONE;Mn;1;NSM;;;;;N;;;;; -16AF1;BASSA VAH COMBINING LOW TONE;Mn;1;NSM;;;;;N;;;;; -16AF2;BASSA VAH COMBINING MID TONE;Mn;1;NSM;;;;;N;;;;; -16AF3;BASSA VAH COMBINING LOW-MID TONE;Mn;1;NSM;;;;;N;;;;; -16AF4;BASSA VAH COMBINING HIGH-LOW TONE;Mn;1;NSM;;;;;N;;;;; -16AF5;BASSA VAH FULL STOP;Po;0;L;;;;;N;;;;; -16B00;PAHAWH HMONG VOWEL KEEB;Lo;0;L;;;;;N;;;;; -16B01;PAHAWH HMONG VOWEL KEEV;Lo;0;L;;;;;N;;;;; -16B02;PAHAWH HMONG VOWEL KIB;Lo;0;L;;;;;N;;;;; -16B03;PAHAWH HMONG VOWEL KIV;Lo;0;L;;;;;N;;;;; -16B04;PAHAWH HMONG VOWEL KAUB;Lo;0;L;;;;;N;;;;; -16B05;PAHAWH HMONG VOWEL KAUV;Lo;0;L;;;;;N;;;;; -16B06;PAHAWH HMONG VOWEL KUB;Lo;0;L;;;;;N;;;;; -16B07;PAHAWH HMONG VOWEL KUV;Lo;0;L;;;;;N;;;;; -16B08;PAHAWH HMONG VOWEL KEB;Lo;0;L;;;;;N;;;;; -16B09;PAHAWH HMONG VOWEL KEV;Lo;0;L;;;;;N;;;;; -16B0A;PAHAWH HMONG VOWEL KAIB;Lo;0;L;;;;;N;;;;; -16B0B;PAHAWH HMONG VOWEL KAIV;Lo;0;L;;;;;N;;;;; -16B0C;PAHAWH HMONG VOWEL KOOB;Lo;0;L;;;;;N;;;;; -16B0D;PAHAWH HMONG VOWEL KOOV;Lo;0;L;;;;;N;;;;; -16B0E;PAHAWH HMONG VOWEL KAWB;Lo;0;L;;;;;N;;;;; -16B0F;PAHAWH HMONG VOWEL KAWV;Lo;0;L;;;;;N;;;;; -16B10;PAHAWH HMONG VOWEL KUAB;Lo;0;L;;;;;N;;;;; -16B11;PAHAWH HMONG VOWEL KUAV;Lo;0;L;;;;;N;;;;; -16B12;PAHAWH HMONG VOWEL KOB;Lo;0;L;;;;;N;;;;; -16B13;PAHAWH HMONG VOWEL KOV;Lo;0;L;;;;;N;;;;; -16B14;PAHAWH HMONG VOWEL KIAB;Lo;0;L;;;;;N;;;;; -16B15;PAHAWH HMONG VOWEL KIAV;Lo;0;L;;;;;N;;;;; -16B16;PAHAWH HMONG VOWEL KAB;Lo;0;L;;;;;N;;;;; -16B17;PAHAWH HMONG VOWEL KAV;Lo;0;L;;;;;N;;;;; -16B18;PAHAWH HMONG VOWEL KWB;Lo;0;L;;;;;N;;;;; -16B19;PAHAWH HMONG VOWEL KWV;Lo;0;L;;;;;N;;;;; -16B1A;PAHAWH HMONG VOWEL KAAB;Lo;0;L;;;;;N;;;;; -16B1B;PAHAWH HMONG VOWEL KAAV;Lo;0;L;;;;;N;;;;; -16B1C;PAHAWH HMONG CONSONANT VAU;Lo;0;L;;;;;N;;;;; -16B1D;PAHAWH HMONG CONSONANT NTSAU;Lo;0;L;;;;;N;;;;; -16B1E;PAHAWH HMONG CONSONANT LAU;Lo;0;L;;;;;N;;;;; -16B1F;PAHAWH HMONG CONSONANT HAU;Lo;0;L;;;;;N;;;;; -16B20;PAHAWH HMONG CONSONANT NLAU;Lo;0;L;;;;;N;;;;; -16B21;PAHAWH HMONG CONSONANT RAU;Lo;0;L;;;;;N;;;;; -16B22;PAHAWH HMONG CONSONANT NKAU;Lo;0;L;;;;;N;;;;; -16B23;PAHAWH HMONG CONSONANT QHAU;Lo;0;L;;;;;N;;;;; -16B24;PAHAWH HMONG CONSONANT YAU;Lo;0;L;;;;;N;;;;; -16B25;PAHAWH HMONG CONSONANT HLAU;Lo;0;L;;;;;N;;;;; -16B26;PAHAWH HMONG CONSONANT MAU;Lo;0;L;;;;;N;;;;; -16B27;PAHAWH HMONG CONSONANT CHAU;Lo;0;L;;;;;N;;;;; -16B28;PAHAWH HMONG CONSONANT NCHAU;Lo;0;L;;;;;N;;;;; -16B29;PAHAWH HMONG CONSONANT HNAU;Lo;0;L;;;;;N;;;;; -16B2A;PAHAWH HMONG CONSONANT PLHAU;Lo;0;L;;;;;N;;;;; -16B2B;PAHAWH HMONG CONSONANT NTHAU;Lo;0;L;;;;;N;;;;; -16B2C;PAHAWH HMONG CONSONANT NAU;Lo;0;L;;;;;N;;;;; -16B2D;PAHAWH HMONG CONSONANT AU;Lo;0;L;;;;;N;;;;; -16B2E;PAHAWH HMONG CONSONANT XAU;Lo;0;L;;;;;N;;;;; -16B2F;PAHAWH HMONG CONSONANT CAU;Lo;0;L;;;;;N;;;;; -16B30;PAHAWH HMONG MARK CIM TUB;Mn;230;NSM;;;;;N;;;;; -16B31;PAHAWH HMONG MARK CIM SO;Mn;230;NSM;;;;;N;;;;; -16B32;PAHAWH HMONG MARK CIM KES;Mn;230;NSM;;;;;N;;;;; -16B33;PAHAWH HMONG MARK CIM KHAV;Mn;230;NSM;;;;;N;;;;; -16B34;PAHAWH HMONG MARK CIM SUAM;Mn;230;NSM;;;;;N;;;;; -16B35;PAHAWH HMONG MARK CIM HOM;Mn;230;NSM;;;;;N;;;;; -16B36;PAHAWH HMONG MARK CIM TAUM;Mn;230;NSM;;;;;N;;;;; -16B37;PAHAWH HMONG SIGN VOS THOM;Po;0;L;;;;;N;;;;; -16B38;PAHAWH HMONG SIGN VOS TSHAB CEEB;Po;0;L;;;;;N;;;;; -16B39;PAHAWH HMONG SIGN CIM CHEEM;Po;0;L;;;;;N;;;;; -16B3A;PAHAWH HMONG SIGN VOS THIAB;Po;0;L;;;;;N;;;;; -16B3B;PAHAWH HMONG SIGN VOS FEEM;Po;0;L;;;;;N;;;;; -16B3C;PAHAWH HMONG SIGN XYEEM NTXIV;So;0;L;;;;;N;;;;; -16B3D;PAHAWH HMONG SIGN XYEEM RHO;So;0;L;;;;;N;;;;; -16B3E;PAHAWH HMONG SIGN XYEEM TOV;So;0;L;;;;;N;;;;; -16B3F;PAHAWH HMONG SIGN XYEEM FAIB;So;0;L;;;;;N;;;;; -16B40;PAHAWH HMONG SIGN VOS SEEV;Lm;0;L;;;;;N;;;;; -16B41;PAHAWH HMONG SIGN MEEJ SUAB;Lm;0;L;;;;;N;;;;; -16B42;PAHAWH HMONG SIGN VOS NRUA;Lm;0;L;;;;;N;;;;; -16B43;PAHAWH HMONG SIGN IB YAM;Lm;0;L;;;;;N;;;;; -16B44;PAHAWH HMONG SIGN XAUS;Po;0;L;;;;;N;;;;; -16B45;PAHAWH HMONG SIGN CIM TSOV ROG;So;0;L;;;;;N;;;;; -16B50;PAHAWH HMONG DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -16B51;PAHAWH HMONG DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -16B52;PAHAWH HMONG DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -16B53;PAHAWH HMONG DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -16B54;PAHAWH HMONG DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -16B55;PAHAWH HMONG DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -16B56;PAHAWH HMONG DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -16B57;PAHAWH HMONG DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -16B58;PAHAWH HMONG DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -16B59;PAHAWH HMONG DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -16B5B;PAHAWH HMONG NUMBER TENS;No;0;L;;;;10;N;;;;; -16B5C;PAHAWH HMONG NUMBER HUNDREDS;No;0;L;;;;100;N;;;;; -16B5D;PAHAWH HMONG NUMBER TEN THOUSANDS;No;0;L;;;;10000;N;;;;; -16B5E;PAHAWH HMONG NUMBER MILLIONS;No;0;L;;;;1000000;N;;;;; -16B5F;PAHAWH HMONG NUMBER HUNDRED MILLIONS;No;0;L;;;;100000000;N;;;;; -16B60;PAHAWH HMONG NUMBER TEN BILLIONS;No;0;L;;;;10000000000;N;;;;; -16B61;PAHAWH HMONG NUMBER TRILLIONS;No;0;L;;;;1000000000000;N;;;;; -16B63;PAHAWH HMONG SIGN VOS LUB;Lo;0;L;;;;;N;;;;; -16B64;PAHAWH HMONG SIGN XYOO;Lo;0;L;;;;;N;;;;; -16B65;PAHAWH HMONG SIGN HLI;Lo;0;L;;;;;N;;;;; -16B66;PAHAWH HMONG SIGN THIRD-STAGE HLI;Lo;0;L;;;;;N;;;;; -16B67;PAHAWH HMONG SIGN ZWJ THAJ;Lo;0;L;;;;;N;;;;; -16B68;PAHAWH HMONG SIGN HNUB;Lo;0;L;;;;;N;;;;; -16B69;PAHAWH HMONG SIGN NQIG;Lo;0;L;;;;;N;;;;; -16B6A;PAHAWH HMONG SIGN XIAB;Lo;0;L;;;;;N;;;;; -16B6B;PAHAWH HMONG SIGN NTUJ;Lo;0;L;;;;;N;;;;; -16B6C;PAHAWH HMONG SIGN AV;Lo;0;L;;;;;N;;;;; -16B6D;PAHAWH HMONG SIGN TXHEEJ CEEV;Lo;0;L;;;;;N;;;;; -16B6E;PAHAWH HMONG SIGN MEEJ TSEEB;Lo;0;L;;;;;N;;;;; -16B6F;PAHAWH HMONG SIGN TAU;Lo;0;L;;;;;N;;;;; -16B70;PAHAWH HMONG SIGN LOS;Lo;0;L;;;;;N;;;;; -16B71;PAHAWH HMONG SIGN MUS;Lo;0;L;;;;;N;;;;; -16B72;PAHAWH HMONG SIGN CIM HAIS LUS NTOG NTOG;Lo;0;L;;;;;N;;;;; -16B73;PAHAWH HMONG SIGN CIM CUAM TSHOOJ;Lo;0;L;;;;;N;;;;; -16B74;PAHAWH HMONG SIGN CIM TXWV;Lo;0;L;;;;;N;;;;; -16B75;PAHAWH HMONG SIGN CIM TXWV CHWV;Lo;0;L;;;;;N;;;;; -16B76;PAHAWH HMONG SIGN CIM PUB DAWB;Lo;0;L;;;;;N;;;;; -16B77;PAHAWH HMONG SIGN CIM NRES TOS;Lo;0;L;;;;;N;;;;; -16B7D;PAHAWH HMONG CLAN SIGN TSHEEJ;Lo;0;L;;;;;N;;;;; -16B7E;PAHAWH HMONG CLAN SIGN YEEG;Lo;0;L;;;;;N;;;;; -16B7F;PAHAWH HMONG CLAN SIGN LIS;Lo;0;L;;;;;N;;;;; -16B80;PAHAWH HMONG CLAN SIGN LAUJ;Lo;0;L;;;;;N;;;;; -16B81;PAHAWH HMONG CLAN SIGN XYOOJ;Lo;0;L;;;;;N;;;;; -16B82;PAHAWH HMONG CLAN SIGN KOO;Lo;0;L;;;;;N;;;;; -16B83;PAHAWH HMONG CLAN SIGN HAWJ;Lo;0;L;;;;;N;;;;; -16B84;PAHAWH HMONG CLAN SIGN MUAS;Lo;0;L;;;;;N;;;;; -16B85;PAHAWH HMONG CLAN SIGN THOJ;Lo;0;L;;;;;N;;;;; -16B86;PAHAWH HMONG CLAN SIGN TSAB;Lo;0;L;;;;;N;;;;; -16B87;PAHAWH HMONG CLAN SIGN PHAB;Lo;0;L;;;;;N;;;;; -16B88;PAHAWH HMONG CLAN SIGN KHAB;Lo;0;L;;;;;N;;;;; -16B89;PAHAWH HMONG CLAN SIGN HAM;Lo;0;L;;;;;N;;;;; -16B8A;PAHAWH HMONG CLAN SIGN VAJ;Lo;0;L;;;;;N;;;;; -16B8B;PAHAWH HMONG CLAN SIGN FAJ;Lo;0;L;;;;;N;;;;; -16B8C;PAHAWH HMONG CLAN SIGN YAJ;Lo;0;L;;;;;N;;;;; -16B8D;PAHAWH HMONG CLAN SIGN TSWB;Lo;0;L;;;;;N;;;;; -16B8E;PAHAWH HMONG CLAN SIGN KWM;Lo;0;L;;;;;N;;;;; -16B8F;PAHAWH HMONG CLAN SIGN VWJ;Lo;0;L;;;;;N;;;;; -16E40;MEDEFAIDRIN CAPITAL LETTER M;Lu;0;L;;;;;N;;;;16E60; -16E41;MEDEFAIDRIN CAPITAL LETTER S;Lu;0;L;;;;;N;;;;16E61; -16E42;MEDEFAIDRIN CAPITAL LETTER V;Lu;0;L;;;;;N;;;;16E62; -16E43;MEDEFAIDRIN CAPITAL LETTER W;Lu;0;L;;;;;N;;;;16E63; -16E44;MEDEFAIDRIN CAPITAL LETTER ATIU;Lu;0;L;;;;;N;;;;16E64; -16E45;MEDEFAIDRIN CAPITAL LETTER Z;Lu;0;L;;;;;N;;;;16E65; -16E46;MEDEFAIDRIN CAPITAL LETTER KP;Lu;0;L;;;;;N;;;;16E66; -16E47;MEDEFAIDRIN CAPITAL LETTER P;Lu;0;L;;;;;N;;;;16E67; -16E48;MEDEFAIDRIN CAPITAL LETTER T;Lu;0;L;;;;;N;;;;16E68; -16E49;MEDEFAIDRIN CAPITAL LETTER G;Lu;0;L;;;;;N;;;;16E69; -16E4A;MEDEFAIDRIN CAPITAL LETTER F;Lu;0;L;;;;;N;;;;16E6A; -16E4B;MEDEFAIDRIN CAPITAL LETTER I;Lu;0;L;;;;;N;;;;16E6B; -16E4C;MEDEFAIDRIN CAPITAL LETTER K;Lu;0;L;;;;;N;;;;16E6C; -16E4D;MEDEFAIDRIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;16E6D; -16E4E;MEDEFAIDRIN CAPITAL LETTER J;Lu;0;L;;;;;N;;;;16E6E; -16E4F;MEDEFAIDRIN CAPITAL LETTER E;Lu;0;L;;;;;N;;;;16E6F; -16E50;MEDEFAIDRIN CAPITAL LETTER B;Lu;0;L;;;;;N;;;;16E70; -16E51;MEDEFAIDRIN CAPITAL LETTER C;Lu;0;L;;;;;N;;;;16E71; -16E52;MEDEFAIDRIN CAPITAL LETTER U;Lu;0;L;;;;;N;;;;16E72; -16E53;MEDEFAIDRIN CAPITAL LETTER YU;Lu;0;L;;;;;N;;;;16E73; -16E54;MEDEFAIDRIN CAPITAL LETTER L;Lu;0;L;;;;;N;;;;16E74; -16E55;MEDEFAIDRIN CAPITAL LETTER Q;Lu;0;L;;;;;N;;;;16E75; -16E56;MEDEFAIDRIN CAPITAL LETTER HP;Lu;0;L;;;;;N;;;;16E76; -16E57;MEDEFAIDRIN CAPITAL LETTER NY;Lu;0;L;;;;;N;;;;16E77; -16E58;MEDEFAIDRIN CAPITAL LETTER X;Lu;0;L;;;;;N;;;;16E78; -16E59;MEDEFAIDRIN CAPITAL LETTER D;Lu;0;L;;;;;N;;;;16E79; -16E5A;MEDEFAIDRIN CAPITAL LETTER OE;Lu;0;L;;;;;N;;;;16E7A; -16E5B;MEDEFAIDRIN CAPITAL LETTER N;Lu;0;L;;;;;N;;;;16E7B; -16E5C;MEDEFAIDRIN CAPITAL LETTER R;Lu;0;L;;;;;N;;;;16E7C; -16E5D;MEDEFAIDRIN CAPITAL LETTER O;Lu;0;L;;;;;N;;;;16E7D; -16E5E;MEDEFAIDRIN CAPITAL LETTER AI;Lu;0;L;;;;;N;;;;16E7E; -16E5F;MEDEFAIDRIN CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;16E7F; -16E60;MEDEFAIDRIN SMALL LETTER M;Ll;0;L;;;;;N;;;16E40;;16E40 -16E61;MEDEFAIDRIN SMALL LETTER S;Ll;0;L;;;;;N;;;16E41;;16E41 -16E62;MEDEFAIDRIN SMALL LETTER V;Ll;0;L;;;;;N;;;16E42;;16E42 -16E63;MEDEFAIDRIN SMALL LETTER W;Ll;0;L;;;;;N;;;16E43;;16E43 -16E64;MEDEFAIDRIN SMALL LETTER ATIU;Ll;0;L;;;;;N;;;16E44;;16E44 -16E65;MEDEFAIDRIN SMALL LETTER Z;Ll;0;L;;;;;N;;;16E45;;16E45 -16E66;MEDEFAIDRIN SMALL LETTER KP;Ll;0;L;;;;;N;;;16E46;;16E46 -16E67;MEDEFAIDRIN SMALL LETTER P;Ll;0;L;;;;;N;;;16E47;;16E47 -16E68;MEDEFAIDRIN SMALL LETTER T;Ll;0;L;;;;;N;;;16E48;;16E48 -16E69;MEDEFAIDRIN SMALL LETTER G;Ll;0;L;;;;;N;;;16E49;;16E49 -16E6A;MEDEFAIDRIN SMALL LETTER F;Ll;0;L;;;;;N;;;16E4A;;16E4A -16E6B;MEDEFAIDRIN SMALL LETTER I;Ll;0;L;;;;;N;;;16E4B;;16E4B -16E6C;MEDEFAIDRIN SMALL LETTER K;Ll;0;L;;;;;N;;;16E4C;;16E4C -16E6D;MEDEFAIDRIN SMALL LETTER A;Ll;0;L;;;;;N;;;16E4D;;16E4D -16E6E;MEDEFAIDRIN SMALL LETTER J;Ll;0;L;;;;;N;;;16E4E;;16E4E -16E6F;MEDEFAIDRIN SMALL LETTER E;Ll;0;L;;;;;N;;;16E4F;;16E4F -16E70;MEDEFAIDRIN SMALL LETTER B;Ll;0;L;;;;;N;;;16E50;;16E50 -16E71;MEDEFAIDRIN SMALL LETTER C;Ll;0;L;;;;;N;;;16E51;;16E51 -16E72;MEDEFAIDRIN SMALL LETTER U;Ll;0;L;;;;;N;;;16E52;;16E52 -16E73;MEDEFAIDRIN SMALL LETTER YU;Ll;0;L;;;;;N;;;16E53;;16E53 -16E74;MEDEFAIDRIN SMALL LETTER L;Ll;0;L;;;;;N;;;16E54;;16E54 -16E75;MEDEFAIDRIN SMALL LETTER Q;Ll;0;L;;;;;N;;;16E55;;16E55 -16E76;MEDEFAIDRIN SMALL LETTER HP;Ll;0;L;;;;;N;;;16E56;;16E56 -16E77;MEDEFAIDRIN SMALL LETTER NY;Ll;0;L;;;;;N;;;16E57;;16E57 -16E78;MEDEFAIDRIN SMALL LETTER X;Ll;0;L;;;;;N;;;16E58;;16E58 -16E79;MEDEFAIDRIN SMALL LETTER D;Ll;0;L;;;;;N;;;16E59;;16E59 -16E7A;MEDEFAIDRIN SMALL LETTER OE;Ll;0;L;;;;;N;;;16E5A;;16E5A -16E7B;MEDEFAIDRIN SMALL LETTER N;Ll;0;L;;;;;N;;;16E5B;;16E5B -16E7C;MEDEFAIDRIN SMALL LETTER R;Ll;0;L;;;;;N;;;16E5C;;16E5C -16E7D;MEDEFAIDRIN SMALL LETTER O;Ll;0;L;;;;;N;;;16E5D;;16E5D -16E7E;MEDEFAIDRIN SMALL LETTER AI;Ll;0;L;;;;;N;;;16E5E;;16E5E -16E7F;MEDEFAIDRIN SMALL LETTER Y;Ll;0;L;;;;;N;;;16E5F;;16E5F -16E80;MEDEFAIDRIN DIGIT ZERO;No;0;L;;;;0;N;;;;; -16E81;MEDEFAIDRIN DIGIT ONE;No;0;L;;;;1;N;;;;; -16E82;MEDEFAIDRIN DIGIT TWO;No;0;L;;;;2;N;;;;; -16E83;MEDEFAIDRIN DIGIT THREE;No;0;L;;;;3;N;;;;; -16E84;MEDEFAIDRIN DIGIT FOUR;No;0;L;;;;4;N;;;;; -16E85;MEDEFAIDRIN DIGIT FIVE;No;0;L;;;;5;N;;;;; -16E86;MEDEFAIDRIN DIGIT SIX;No;0;L;;;;6;N;;;;; -16E87;MEDEFAIDRIN DIGIT SEVEN;No;0;L;;;;7;N;;;;; -16E88;MEDEFAIDRIN DIGIT EIGHT;No;0;L;;;;8;N;;;;; -16E89;MEDEFAIDRIN DIGIT NINE;No;0;L;;;;9;N;;;;; -16E8A;MEDEFAIDRIN NUMBER TEN;No;0;L;;;;10;N;;;;; -16E8B;MEDEFAIDRIN NUMBER ELEVEN;No;0;L;;;;11;N;;;;; -16E8C;MEDEFAIDRIN NUMBER TWELVE;No;0;L;;;;12;N;;;;; -16E8D;MEDEFAIDRIN NUMBER THIRTEEN;No;0;L;;;;13;N;;;;; -16E8E;MEDEFAIDRIN NUMBER FOURTEEN;No;0;L;;;;14;N;;;;; -16E8F;MEDEFAIDRIN NUMBER FIFTEEN;No;0;L;;;;15;N;;;;; -16E90;MEDEFAIDRIN NUMBER SIXTEEN;No;0;L;;;;16;N;;;;; -16E91;MEDEFAIDRIN NUMBER SEVENTEEN;No;0;L;;;;17;N;;;;; -16E92;MEDEFAIDRIN NUMBER EIGHTEEN;No;0;L;;;;18;N;;;;; -16E93;MEDEFAIDRIN NUMBER NINETEEN;No;0;L;;;;19;N;;;;; -16E94;MEDEFAIDRIN DIGIT ONE ALTERNATE FORM;No;0;L;;;;1;N;;;;; -16E95;MEDEFAIDRIN DIGIT TWO ALTERNATE FORM;No;0;L;;;;2;N;;;;; -16E96;MEDEFAIDRIN DIGIT THREE ALTERNATE FORM;No;0;L;;;;3;N;;;;; -16E97;MEDEFAIDRIN COMMA;Po;0;L;;;;;N;;;;; -16E98;MEDEFAIDRIN FULL STOP;Po;0;L;;;;;N;;;;; -16E99;MEDEFAIDRIN SYMBOL AIVA;Po;0;L;;;;;N;;;;; -16E9A;MEDEFAIDRIN EXCLAMATION OH;Po;0;L;;;;;N;;;;; -16F00;MIAO LETTER PA;Lo;0;L;;;;;N;;;;; -16F01;MIAO LETTER BA;Lo;0;L;;;;;N;;;;; -16F02;MIAO LETTER YI PA;Lo;0;L;;;;;N;;;;; -16F03;MIAO LETTER PLA;Lo;0;L;;;;;N;;;;; -16F04;MIAO LETTER MA;Lo;0;L;;;;;N;;;;; -16F05;MIAO LETTER MHA;Lo;0;L;;;;;N;;;;; -16F06;MIAO LETTER ARCHAIC MA;Lo;0;L;;;;;N;;;;; -16F07;MIAO LETTER FA;Lo;0;L;;;;;N;;;;; -16F08;MIAO LETTER VA;Lo;0;L;;;;;N;;;;; -16F09;MIAO LETTER VFA;Lo;0;L;;;;;N;;;;; -16F0A;MIAO LETTER TA;Lo;0;L;;;;;N;;;;; -16F0B;MIAO LETTER DA;Lo;0;L;;;;;N;;;;; -16F0C;MIAO LETTER YI TTA;Lo;0;L;;;;;N;;;;; -16F0D;MIAO LETTER YI TA;Lo;0;L;;;;;N;;;;; -16F0E;MIAO LETTER TTA;Lo;0;L;;;;;N;;;;; -16F0F;MIAO LETTER DDA;Lo;0;L;;;;;N;;;;; -16F10;MIAO LETTER NA;Lo;0;L;;;;;N;;;;; -16F11;MIAO LETTER NHA;Lo;0;L;;;;;N;;;;; -16F12;MIAO LETTER YI NNA;Lo;0;L;;;;;N;;;;; -16F13;MIAO LETTER ARCHAIC NA;Lo;0;L;;;;;N;;;;; -16F14;MIAO LETTER NNA;Lo;0;L;;;;;N;;;;; -16F15;MIAO LETTER NNHA;Lo;0;L;;;;;N;;;;; -16F16;MIAO LETTER LA;Lo;0;L;;;;;N;;;;; -16F17;MIAO LETTER LYA;Lo;0;L;;;;;N;;;;; -16F18;MIAO LETTER LHA;Lo;0;L;;;;;N;;;;; -16F19;MIAO LETTER LHYA;Lo;0;L;;;;;N;;;;; -16F1A;MIAO LETTER TLHA;Lo;0;L;;;;;N;;;;; -16F1B;MIAO LETTER DLHA;Lo;0;L;;;;;N;;;;; -16F1C;MIAO LETTER TLHYA;Lo;0;L;;;;;N;;;;; -16F1D;MIAO LETTER DLHYA;Lo;0;L;;;;;N;;;;; -16F1E;MIAO LETTER KA;Lo;0;L;;;;;N;;;;; -16F1F;MIAO LETTER GA;Lo;0;L;;;;;N;;;;; -16F20;MIAO LETTER YI KA;Lo;0;L;;;;;N;;;;; -16F21;MIAO LETTER QA;Lo;0;L;;;;;N;;;;; -16F22;MIAO LETTER QGA;Lo;0;L;;;;;N;;;;; -16F23;MIAO LETTER NGA;Lo;0;L;;;;;N;;;;; -16F24;MIAO LETTER NGHA;Lo;0;L;;;;;N;;;;; -16F25;MIAO LETTER ARCHAIC NGA;Lo;0;L;;;;;N;;;;; -16F26;MIAO LETTER HA;Lo;0;L;;;;;N;;;;; -16F27;MIAO LETTER XA;Lo;0;L;;;;;N;;;;; -16F28;MIAO LETTER GHA;Lo;0;L;;;;;N;;;;; -16F29;MIAO LETTER GHHA;Lo;0;L;;;;;N;;;;; -16F2A;MIAO LETTER TSSA;Lo;0;L;;;;;N;;;;; -16F2B;MIAO LETTER DZZA;Lo;0;L;;;;;N;;;;; -16F2C;MIAO LETTER NYA;Lo;0;L;;;;;N;;;;; -16F2D;MIAO LETTER NYHA;Lo;0;L;;;;;N;;;;; -16F2E;MIAO LETTER TSHA;Lo;0;L;;;;;N;;;;; -16F2F;MIAO LETTER DZHA;Lo;0;L;;;;;N;;;;; -16F30;MIAO LETTER YI TSHA;Lo;0;L;;;;;N;;;;; -16F31;MIAO LETTER YI DZHA;Lo;0;L;;;;;N;;;;; -16F32;MIAO LETTER REFORMED TSHA;Lo;0;L;;;;;N;;;;; -16F33;MIAO LETTER SHA;Lo;0;L;;;;;N;;;;; -16F34;MIAO LETTER SSA;Lo;0;L;;;;;N;;;;; -16F35;MIAO LETTER ZHA;Lo;0;L;;;;;N;;;;; -16F36;MIAO LETTER ZSHA;Lo;0;L;;;;;N;;;;; -16F37;MIAO LETTER TSA;Lo;0;L;;;;;N;;;;; -16F38;MIAO LETTER DZA;Lo;0;L;;;;;N;;;;; -16F39;MIAO LETTER YI TSA;Lo;0;L;;;;;N;;;;; -16F3A;MIAO LETTER SA;Lo;0;L;;;;;N;;;;; -16F3B;MIAO LETTER ZA;Lo;0;L;;;;;N;;;;; -16F3C;MIAO LETTER ZSA;Lo;0;L;;;;;N;;;;; -16F3D;MIAO LETTER ZZA;Lo;0;L;;;;;N;;;;; -16F3E;MIAO LETTER ZZSA;Lo;0;L;;;;;N;;;;; -16F3F;MIAO LETTER ARCHAIC ZZA;Lo;0;L;;;;;N;;;;; -16F40;MIAO LETTER ZZYA;Lo;0;L;;;;;N;;;;; -16F41;MIAO LETTER ZZSYA;Lo;0;L;;;;;N;;;;; -16F42;MIAO LETTER WA;Lo;0;L;;;;;N;;;;; -16F43;MIAO LETTER AH;Lo;0;L;;;;;N;;;;; -16F44;MIAO LETTER HHA;Lo;0;L;;;;;N;;;;; -16F45;MIAO LETTER BRI;Lo;0;L;;;;;N;;;;; -16F46;MIAO LETTER SYI;Lo;0;L;;;;;N;;;;; -16F47;MIAO LETTER DZYI;Lo;0;L;;;;;N;;;;; -16F48;MIAO LETTER TE;Lo;0;L;;;;;N;;;;; -16F49;MIAO LETTER TSE;Lo;0;L;;;;;N;;;;; -16F4A;MIAO LETTER RTE;Lo;0;L;;;;;N;;;;; -16F4F;MIAO SIGN CONSONANT MODIFIER BAR;Mn;0;NSM;;;;;N;;;;; -16F50;MIAO LETTER NASALIZATION;Lo;0;L;;;;;N;;;;; -16F51;MIAO SIGN ASPIRATION;Mc;0;L;;;;;N;;;;; -16F52;MIAO SIGN REFORMED VOICING;Mc;0;L;;;;;N;;;;; -16F53;MIAO SIGN REFORMED ASPIRATION;Mc;0;L;;;;;N;;;;; -16F54;MIAO VOWEL SIGN A;Mc;0;L;;;;;N;;;;; -16F55;MIAO VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; -16F56;MIAO VOWEL SIGN AHH;Mc;0;L;;;;;N;;;;; -16F57;MIAO VOWEL SIGN AN;Mc;0;L;;;;;N;;;;; -16F58;MIAO VOWEL SIGN ANG;Mc;0;L;;;;;N;;;;; -16F59;MIAO VOWEL SIGN O;Mc;0;L;;;;;N;;;;; -16F5A;MIAO VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; -16F5B;MIAO VOWEL SIGN WO;Mc;0;L;;;;;N;;;;; -16F5C;MIAO VOWEL SIGN W;Mc;0;L;;;;;N;;;;; -16F5D;MIAO VOWEL SIGN E;Mc;0;L;;;;;N;;;;; -16F5E;MIAO VOWEL SIGN EN;Mc;0;L;;;;;N;;;;; -16F5F;MIAO VOWEL SIGN ENG;Mc;0;L;;;;;N;;;;; -16F60;MIAO VOWEL SIGN OEY;Mc;0;L;;;;;N;;;;; -16F61;MIAO VOWEL SIGN I;Mc;0;L;;;;;N;;;;; -16F62;MIAO VOWEL SIGN IA;Mc;0;L;;;;;N;;;;; -16F63;MIAO VOWEL SIGN IAN;Mc;0;L;;;;;N;;;;; -16F64;MIAO VOWEL SIGN IANG;Mc;0;L;;;;;N;;;;; -16F65;MIAO VOWEL SIGN IO;Mc;0;L;;;;;N;;;;; -16F66;MIAO VOWEL SIGN IE;Mc;0;L;;;;;N;;;;; -16F67;MIAO VOWEL SIGN II;Mc;0;L;;;;;N;;;;; -16F68;MIAO VOWEL SIGN IU;Mc;0;L;;;;;N;;;;; -16F69;MIAO VOWEL SIGN ING;Mc;0;L;;;;;N;;;;; -16F6A;MIAO VOWEL SIGN U;Mc;0;L;;;;;N;;;;; -16F6B;MIAO VOWEL SIGN UA;Mc;0;L;;;;;N;;;;; -16F6C;MIAO VOWEL SIGN UAN;Mc;0;L;;;;;N;;;;; -16F6D;MIAO VOWEL SIGN UANG;Mc;0;L;;;;;N;;;;; -16F6E;MIAO VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; -16F6F;MIAO VOWEL SIGN UEI;Mc;0;L;;;;;N;;;;; -16F70;MIAO VOWEL SIGN UNG;Mc;0;L;;;;;N;;;;; -16F71;MIAO VOWEL SIGN Y;Mc;0;L;;;;;N;;;;; -16F72;MIAO VOWEL SIGN YI;Mc;0;L;;;;;N;;;;; -16F73;MIAO VOWEL SIGN AE;Mc;0;L;;;;;N;;;;; -16F74;MIAO VOWEL SIGN AEE;Mc;0;L;;;;;N;;;;; -16F75;MIAO VOWEL SIGN ERR;Mc;0;L;;;;;N;;;;; -16F76;MIAO VOWEL SIGN ROUNDED ERR;Mc;0;L;;;;;N;;;;; -16F77;MIAO VOWEL SIGN ER;Mc;0;L;;;;;N;;;;; -16F78;MIAO VOWEL SIGN ROUNDED ER;Mc;0;L;;;;;N;;;;; -16F79;MIAO VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; -16F7A;MIAO VOWEL SIGN EI;Mc;0;L;;;;;N;;;;; -16F7B;MIAO VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; -16F7C;MIAO VOWEL SIGN OU;Mc;0;L;;;;;N;;;;; -16F7D;MIAO VOWEL SIGN N;Mc;0;L;;;;;N;;;;; -16F7E;MIAO VOWEL SIGN NG;Mc;0;L;;;;;N;;;;; -16F7F;MIAO VOWEL SIGN UOG;Mc;0;L;;;;;N;;;;; -16F80;MIAO VOWEL SIGN YUI;Mc;0;L;;;;;N;;;;; -16F81;MIAO VOWEL SIGN OG;Mc;0;L;;;;;N;;;;; -16F82;MIAO VOWEL SIGN OER;Mc;0;L;;;;;N;;;;; -16F83;MIAO VOWEL SIGN VW;Mc;0;L;;;;;N;;;;; -16F84;MIAO VOWEL SIGN IG;Mc;0;L;;;;;N;;;;; -16F85;MIAO VOWEL SIGN EA;Mc;0;L;;;;;N;;;;; -16F86;MIAO VOWEL SIGN IONG;Mc;0;L;;;;;N;;;;; -16F87;MIAO VOWEL SIGN UI;Mc;0;L;;;;;N;;;;; -16F8F;MIAO TONE RIGHT;Mn;0;NSM;;;;;N;;;;; -16F90;MIAO TONE TOP RIGHT;Mn;0;NSM;;;;;N;;;;; -16F91;MIAO TONE ABOVE;Mn;0;NSM;;;;;N;;;;; -16F92;MIAO TONE BELOW;Mn;0;NSM;;;;;N;;;;; -16F93;MIAO LETTER TONE-2;Lm;0;L;;;;;N;;;;; -16F94;MIAO LETTER TONE-3;Lm;0;L;;;;;N;;;;; -16F95;MIAO LETTER TONE-4;Lm;0;L;;;;;N;;;;; -16F96;MIAO LETTER TONE-5;Lm;0;L;;;;;N;;;;; -16F97;MIAO LETTER TONE-6;Lm;0;L;;;;;N;;;;; -16F98;MIAO LETTER TONE-7;Lm;0;L;;;;;N;;;;; -16F99;MIAO LETTER TONE-8;Lm;0;L;;;;;N;;;;; -16F9A;MIAO LETTER REFORMED TONE-1;Lm;0;L;;;;;N;;;;; -16F9B;MIAO LETTER REFORMED TONE-2;Lm;0;L;;;;;N;;;;; -16F9C;MIAO LETTER REFORMED TONE-4;Lm;0;L;;;;;N;;;;; -16F9D;MIAO LETTER REFORMED TONE-5;Lm;0;L;;;;;N;;;;; -16F9E;MIAO LETTER REFORMED TONE-6;Lm;0;L;;;;;N;;;;; -16F9F;MIAO LETTER REFORMED TONE-8;Lm;0;L;;;;;N;;;;; -16FE0;TANGUT ITERATION MARK;Lm;0;L;;;;;N;;;;; -16FE1;NUSHU ITERATION MARK;Lm;0;L;;;;;N;;;;; -16FE2;OLD CHINESE HOOK MARK;Po;0;ON;;;;;N;;;;; -16FE3;OLD CHINESE ITERATION MARK;Lm;0;L;;;;;N;;;;; -16FE4;KHITAN SMALL SCRIPT FILLER;Mn;0;NSM;;;;;N;;;;; -16FF0;VIETNAMESE ALTERNATE READING MARK CA;Mc;6;L;;;;;N;;;;; -16FF1;VIETNAMESE ALTERNATE READING MARK NHAY;Mc;6;L;;;;;N;;;;; -17000;<Tangut Ideograph, First>;Lo;0;L;;;;;N;;;;; -187F7;<Tangut Ideograph, Last>;Lo;0;L;;;;;N;;;;; -18800;TANGUT COMPONENT-001;Lo;0;L;;;;;N;;;;; -18801;TANGUT COMPONENT-002;Lo;0;L;;;;;N;;;;; -18802;TANGUT COMPONENT-003;Lo;0;L;;;;;N;;;;; -18803;TANGUT COMPONENT-004;Lo;0;L;;;;;N;;;;; -18804;TANGUT COMPONENT-005;Lo;0;L;;;;;N;;;;; -18805;TANGUT COMPONENT-006;Lo;0;L;;;;;N;;;;; -18806;TANGUT COMPONENT-007;Lo;0;L;;;;;N;;;;; -18807;TANGUT COMPONENT-008;Lo;0;L;;;;;N;;;;; -18808;TANGUT COMPONENT-009;Lo;0;L;;;;;N;;;;; -18809;TANGUT COMPONENT-010;Lo;0;L;;;;;N;;;;; -1880A;TANGUT COMPONENT-011;Lo;0;L;;;;;N;;;;; -1880B;TANGUT COMPONENT-012;Lo;0;L;;;;;N;;;;; -1880C;TANGUT COMPONENT-013;Lo;0;L;;;;;N;;;;; -1880D;TANGUT COMPONENT-014;Lo;0;L;;;;;N;;;;; -1880E;TANGUT COMPONENT-015;Lo;0;L;;;;;N;;;;; -1880F;TANGUT COMPONENT-016;Lo;0;L;;;;;N;;;;; -18810;TANGUT COMPONENT-017;Lo;0;L;;;;;N;;;;; -18811;TANGUT COMPONENT-018;Lo;0;L;;;;;N;;;;; -18812;TANGUT COMPONENT-019;Lo;0;L;;;;;N;;;;; -18813;TANGUT COMPONENT-020;Lo;0;L;;;;;N;;;;; -18814;TANGUT COMPONENT-021;Lo;0;L;;;;;N;;;;; -18815;TANGUT COMPONENT-022;Lo;0;L;;;;;N;;;;; -18816;TANGUT COMPONENT-023;Lo;0;L;;;;;N;;;;; -18817;TANGUT COMPONENT-024;Lo;0;L;;;;;N;;;;; -18818;TANGUT COMPONENT-025;Lo;0;L;;;;;N;;;;; -18819;TANGUT COMPONENT-026;Lo;0;L;;;;;N;;;;; -1881A;TANGUT COMPONENT-027;Lo;0;L;;;;;N;;;;; -1881B;TANGUT COMPONENT-028;Lo;0;L;;;;;N;;;;; -1881C;TANGUT COMPONENT-029;Lo;0;L;;;;;N;;;;; -1881D;TANGUT COMPONENT-030;Lo;0;L;;;;;N;;;;; -1881E;TANGUT COMPONENT-031;Lo;0;L;;;;;N;;;;; -1881F;TANGUT COMPONENT-032;Lo;0;L;;;;;N;;;;; -18820;TANGUT COMPONENT-033;Lo;0;L;;;;;N;;;;; -18821;TANGUT COMPONENT-034;Lo;0;L;;;;;N;;;;; -18822;TANGUT COMPONENT-035;Lo;0;L;;;;;N;;;;; -18823;TANGUT COMPONENT-036;Lo;0;L;;;;;N;;;;; -18824;TANGUT COMPONENT-037;Lo;0;L;;;;;N;;;;; -18825;TANGUT COMPONENT-038;Lo;0;L;;;;;N;;;;; -18826;TANGUT COMPONENT-039;Lo;0;L;;;;;N;;;;; -18827;TANGUT COMPONENT-040;Lo;0;L;;;;;N;;;;; -18828;TANGUT COMPONENT-041;Lo;0;L;;;;;N;;;;; -18829;TANGUT COMPONENT-042;Lo;0;L;;;;;N;;;;; -1882A;TANGUT COMPONENT-043;Lo;0;L;;;;;N;;;;; -1882B;TANGUT COMPONENT-044;Lo;0;L;;;;;N;;;;; -1882C;TANGUT COMPONENT-045;Lo;0;L;;;;;N;;;;; -1882D;TANGUT COMPONENT-046;Lo;0;L;;;;;N;;;;; -1882E;TANGUT COMPONENT-047;Lo;0;L;;;;;N;;;;; -1882F;TANGUT COMPONENT-048;Lo;0;L;;;;;N;;;;; -18830;TANGUT COMPONENT-049;Lo;0;L;;;;;N;;;;; -18831;TANGUT COMPONENT-050;Lo;0;L;;;;;N;;;;; -18832;TANGUT COMPONENT-051;Lo;0;L;;;;;N;;;;; -18833;TANGUT COMPONENT-052;Lo;0;L;;;;;N;;;;; -18834;TANGUT COMPONENT-053;Lo;0;L;;;;;N;;;;; -18835;TANGUT COMPONENT-054;Lo;0;L;;;;;N;;;;; -18836;TANGUT COMPONENT-055;Lo;0;L;;;;;N;;;;; -18837;TANGUT COMPONENT-056;Lo;0;L;;;;;N;;;;; -18838;TANGUT COMPONENT-057;Lo;0;L;;;;;N;;;;; -18839;TANGUT COMPONENT-058;Lo;0;L;;;;;N;;;;; -1883A;TANGUT COMPONENT-059;Lo;0;L;;;;;N;;;;; -1883B;TANGUT COMPONENT-060;Lo;0;L;;;;;N;;;;; -1883C;TANGUT COMPONENT-061;Lo;0;L;;;;;N;;;;; -1883D;TANGUT COMPONENT-062;Lo;0;L;;;;;N;;;;; -1883E;TANGUT COMPONENT-063;Lo;0;L;;;;;N;;;;; -1883F;TANGUT COMPONENT-064;Lo;0;L;;;;;N;;;;; -18840;TANGUT COMPONENT-065;Lo;0;L;;;;;N;;;;; -18841;TANGUT COMPONENT-066;Lo;0;L;;;;;N;;;;; -18842;TANGUT COMPONENT-067;Lo;0;L;;;;;N;;;;; -18843;TANGUT COMPONENT-068;Lo;0;L;;;;;N;;;;; -18844;TANGUT COMPONENT-069;Lo;0;L;;;;;N;;;;; -18845;TANGUT COMPONENT-070;Lo;0;L;;;;;N;;;;; -18846;TANGUT COMPONENT-071;Lo;0;L;;;;;N;;;;; -18847;TANGUT COMPONENT-072;Lo;0;L;;;;;N;;;;; -18848;TANGUT COMPONENT-073;Lo;0;L;;;;;N;;;;; -18849;TANGUT COMPONENT-074;Lo;0;L;;;;;N;;;;; -1884A;TANGUT COMPONENT-075;Lo;0;L;;;;;N;;;;; -1884B;TANGUT COMPONENT-076;Lo;0;L;;;;;N;;;;; -1884C;TANGUT COMPONENT-077;Lo;0;L;;;;;N;;;;; -1884D;TANGUT COMPONENT-078;Lo;0;L;;;;;N;;;;; -1884E;TANGUT COMPONENT-079;Lo;0;L;;;;;N;;;;; -1884F;TANGUT COMPONENT-080;Lo;0;L;;;;;N;;;;; -18850;TANGUT COMPONENT-081;Lo;0;L;;;;;N;;;;; -18851;TANGUT COMPONENT-082;Lo;0;L;;;;;N;;;;; -18852;TANGUT COMPONENT-083;Lo;0;L;;;;;N;;;;; -18853;TANGUT COMPONENT-084;Lo;0;L;;;;;N;;;;; -18854;TANGUT COMPONENT-085;Lo;0;L;;;;;N;;;;; -18855;TANGUT COMPONENT-086;Lo;0;L;;;;;N;;;;; -18856;TANGUT COMPONENT-087;Lo;0;L;;;;;N;;;;; -18857;TANGUT COMPONENT-088;Lo;0;L;;;;;N;;;;; -18858;TANGUT COMPONENT-089;Lo;0;L;;;;;N;;;;; -18859;TANGUT COMPONENT-090;Lo;0;L;;;;;N;;;;; -1885A;TANGUT COMPONENT-091;Lo;0;L;;;;;N;;;;; -1885B;TANGUT COMPONENT-092;Lo;0;L;;;;;N;;;;; -1885C;TANGUT COMPONENT-093;Lo;0;L;;;;;N;;;;; -1885D;TANGUT COMPONENT-094;Lo;0;L;;;;;N;;;;; -1885E;TANGUT COMPONENT-095;Lo;0;L;;;;;N;;;;; -1885F;TANGUT COMPONENT-096;Lo;0;L;;;;;N;;;;; -18860;TANGUT COMPONENT-097;Lo;0;L;;;;;N;;;;; -18861;TANGUT COMPONENT-098;Lo;0;L;;;;;N;;;;; -18862;TANGUT COMPONENT-099;Lo;0;L;;;;;N;;;;; -18863;TANGUT COMPONENT-100;Lo;0;L;;;;;N;;;;; -18864;TANGUT COMPONENT-101;Lo;0;L;;;;;N;;;;; -18865;TANGUT COMPONENT-102;Lo;0;L;;;;;N;;;;; -18866;TANGUT COMPONENT-103;Lo;0;L;;;;;N;;;;; -18867;TANGUT COMPONENT-104;Lo;0;L;;;;;N;;;;; -18868;TANGUT COMPONENT-105;Lo;0;L;;;;;N;;;;; -18869;TANGUT COMPONENT-106;Lo;0;L;;;;;N;;;;; -1886A;TANGUT COMPONENT-107;Lo;0;L;;;;;N;;;;; -1886B;TANGUT COMPONENT-108;Lo;0;L;;;;;N;;;;; -1886C;TANGUT COMPONENT-109;Lo;0;L;;;;;N;;;;; -1886D;TANGUT COMPONENT-110;Lo;0;L;;;;;N;;;;; -1886E;TANGUT COMPONENT-111;Lo;0;L;;;;;N;;;;; -1886F;TANGUT COMPONENT-112;Lo;0;L;;;;;N;;;;; -18870;TANGUT COMPONENT-113;Lo;0;L;;;;;N;;;;; -18871;TANGUT COMPONENT-114;Lo;0;L;;;;;N;;;;; -18872;TANGUT COMPONENT-115;Lo;0;L;;;;;N;;;;; -18873;TANGUT COMPONENT-116;Lo;0;L;;;;;N;;;;; -18874;TANGUT COMPONENT-117;Lo;0;L;;;;;N;;;;; -18875;TANGUT COMPONENT-118;Lo;0;L;;;;;N;;;;; -18876;TANGUT COMPONENT-119;Lo;0;L;;;;;N;;;;; -18877;TANGUT COMPONENT-120;Lo;0;L;;;;;N;;;;; -18878;TANGUT COMPONENT-121;Lo;0;L;;;;;N;;;;; -18879;TANGUT COMPONENT-122;Lo;0;L;;;;;N;;;;; -1887A;TANGUT COMPONENT-123;Lo;0;L;;;;;N;;;;; -1887B;TANGUT COMPONENT-124;Lo;0;L;;;;;N;;;;; -1887C;TANGUT COMPONENT-125;Lo;0;L;;;;;N;;;;; -1887D;TANGUT COMPONENT-126;Lo;0;L;;;;;N;;;;; -1887E;TANGUT COMPONENT-127;Lo;0;L;;;;;N;;;;; -1887F;TANGUT COMPONENT-128;Lo;0;L;;;;;N;;;;; -18880;TANGUT COMPONENT-129;Lo;0;L;;;;;N;;;;; -18881;TANGUT COMPONENT-130;Lo;0;L;;;;;N;;;;; -18882;TANGUT COMPONENT-131;Lo;0;L;;;;;N;;;;; -18883;TANGUT COMPONENT-132;Lo;0;L;;;;;N;;;;; -18884;TANGUT COMPONENT-133;Lo;0;L;;;;;N;;;;; -18885;TANGUT COMPONENT-134;Lo;0;L;;;;;N;;;;; -18886;TANGUT COMPONENT-135;Lo;0;L;;;;;N;;;;; -18887;TANGUT COMPONENT-136;Lo;0;L;;;;;N;;;;; -18888;TANGUT COMPONENT-137;Lo;0;L;;;;;N;;;;; -18889;TANGUT COMPONENT-138;Lo;0;L;;;;;N;;;;; -1888A;TANGUT COMPONENT-139;Lo;0;L;;;;;N;;;;; -1888B;TANGUT COMPONENT-140;Lo;0;L;;;;;N;;;;; -1888C;TANGUT COMPONENT-141;Lo;0;L;;;;;N;;;;; -1888D;TANGUT COMPONENT-142;Lo;0;L;;;;;N;;;;; -1888E;TANGUT COMPONENT-143;Lo;0;L;;;;;N;;;;; -1888F;TANGUT COMPONENT-144;Lo;0;L;;;;;N;;;;; -18890;TANGUT COMPONENT-145;Lo;0;L;;;;;N;;;;; -18891;TANGUT COMPONENT-146;Lo;0;L;;;;;N;;;;; -18892;TANGUT COMPONENT-147;Lo;0;L;;;;;N;;;;; -18893;TANGUT COMPONENT-148;Lo;0;L;;;;;N;;;;; -18894;TANGUT COMPONENT-149;Lo;0;L;;;;;N;;;;; -18895;TANGUT COMPONENT-150;Lo;0;L;;;;;N;;;;; -18896;TANGUT COMPONENT-151;Lo;0;L;;;;;N;;;;; -18897;TANGUT COMPONENT-152;Lo;0;L;;;;;N;;;;; -18898;TANGUT COMPONENT-153;Lo;0;L;;;;;N;;;;; -18899;TANGUT COMPONENT-154;Lo;0;L;;;;;N;;;;; -1889A;TANGUT COMPONENT-155;Lo;0;L;;;;;N;;;;; -1889B;TANGUT COMPONENT-156;Lo;0;L;;;;;N;;;;; -1889C;TANGUT COMPONENT-157;Lo;0;L;;;;;N;;;;; -1889D;TANGUT COMPONENT-158;Lo;0;L;;;;;N;;;;; -1889E;TANGUT COMPONENT-159;Lo;0;L;;;;;N;;;;; -1889F;TANGUT COMPONENT-160;Lo;0;L;;;;;N;;;;; -188A0;TANGUT COMPONENT-161;Lo;0;L;;;;;N;;;;; -188A1;TANGUT COMPONENT-162;Lo;0;L;;;;;N;;;;; -188A2;TANGUT COMPONENT-163;Lo;0;L;;;;;N;;;;; -188A3;TANGUT COMPONENT-164;Lo;0;L;;;;;N;;;;; -188A4;TANGUT COMPONENT-165;Lo;0;L;;;;;N;;;;; -188A5;TANGUT COMPONENT-166;Lo;0;L;;;;;N;;;;; -188A6;TANGUT COMPONENT-167;Lo;0;L;;;;;N;;;;; -188A7;TANGUT COMPONENT-168;Lo;0;L;;;;;N;;;;; -188A8;TANGUT COMPONENT-169;Lo;0;L;;;;;N;;;;; -188A9;TANGUT COMPONENT-170;Lo;0;L;;;;;N;;;;; -188AA;TANGUT COMPONENT-171;Lo;0;L;;;;;N;;;;; -188AB;TANGUT COMPONENT-172;Lo;0;L;;;;;N;;;;; -188AC;TANGUT COMPONENT-173;Lo;0;L;;;;;N;;;;; -188AD;TANGUT COMPONENT-174;Lo;0;L;;;;;N;;;;; -188AE;TANGUT COMPONENT-175;Lo;0;L;;;;;N;;;;; -188AF;TANGUT COMPONENT-176;Lo;0;L;;;;;N;;;;; -188B0;TANGUT COMPONENT-177;Lo;0;L;;;;;N;;;;; -188B1;TANGUT COMPONENT-178;Lo;0;L;;;;;N;;;;; -188B2;TANGUT COMPONENT-179;Lo;0;L;;;;;N;;;;; -188B3;TANGUT COMPONENT-180;Lo;0;L;;;;;N;;;;; -188B4;TANGUT COMPONENT-181;Lo;0;L;;;;;N;;;;; -188B5;TANGUT COMPONENT-182;Lo;0;L;;;;;N;;;;; -188B6;TANGUT COMPONENT-183;Lo;0;L;;;;;N;;;;; -188B7;TANGUT COMPONENT-184;Lo;0;L;;;;;N;;;;; -188B8;TANGUT COMPONENT-185;Lo;0;L;;;;;N;;;;; -188B9;TANGUT COMPONENT-186;Lo;0;L;;;;;N;;;;; -188BA;TANGUT COMPONENT-187;Lo;0;L;;;;;N;;;;; -188BB;TANGUT COMPONENT-188;Lo;0;L;;;;;N;;;;; -188BC;TANGUT COMPONENT-189;Lo;0;L;;;;;N;;;;; -188BD;TANGUT COMPONENT-190;Lo;0;L;;;;;N;;;;; -188BE;TANGUT COMPONENT-191;Lo;0;L;;;;;N;;;;; -188BF;TANGUT COMPONENT-192;Lo;0;L;;;;;N;;;;; -188C0;TANGUT COMPONENT-193;Lo;0;L;;;;;N;;;;; -188C1;TANGUT COMPONENT-194;Lo;0;L;;;;;N;;;;; -188C2;TANGUT COMPONENT-195;Lo;0;L;;;;;N;;;;; -188C3;TANGUT COMPONENT-196;Lo;0;L;;;;;N;;;;; -188C4;TANGUT COMPONENT-197;Lo;0;L;;;;;N;;;;; -188C5;TANGUT COMPONENT-198;Lo;0;L;;;;;N;;;;; -188C6;TANGUT COMPONENT-199;Lo;0;L;;;;;N;;;;; -188C7;TANGUT COMPONENT-200;Lo;0;L;;;;;N;;;;; -188C8;TANGUT COMPONENT-201;Lo;0;L;;;;;N;;;;; -188C9;TANGUT COMPONENT-202;Lo;0;L;;;;;N;;;;; -188CA;TANGUT COMPONENT-203;Lo;0;L;;;;;N;;;;; -188CB;TANGUT COMPONENT-204;Lo;0;L;;;;;N;;;;; -188CC;TANGUT COMPONENT-205;Lo;0;L;;;;;N;;;;; -188CD;TANGUT COMPONENT-206;Lo;0;L;;;;;N;;;;; -188CE;TANGUT COMPONENT-207;Lo;0;L;;;;;N;;;;; -188CF;TANGUT COMPONENT-208;Lo;0;L;;;;;N;;;;; -188D0;TANGUT COMPONENT-209;Lo;0;L;;;;;N;;;;; -188D1;TANGUT COMPONENT-210;Lo;0;L;;;;;N;;;;; -188D2;TANGUT COMPONENT-211;Lo;0;L;;;;;N;;;;; -188D3;TANGUT COMPONENT-212;Lo;0;L;;;;;N;;;;; -188D4;TANGUT COMPONENT-213;Lo;0;L;;;;;N;;;;; -188D5;TANGUT COMPONENT-214;Lo;0;L;;;;;N;;;;; -188D6;TANGUT COMPONENT-215;Lo;0;L;;;;;N;;;;; -188D7;TANGUT COMPONENT-216;Lo;0;L;;;;;N;;;;; -188D8;TANGUT COMPONENT-217;Lo;0;L;;;;;N;;;;; -188D9;TANGUT COMPONENT-218;Lo;0;L;;;;;N;;;;; -188DA;TANGUT COMPONENT-219;Lo;0;L;;;;;N;;;;; -188DB;TANGUT COMPONENT-220;Lo;0;L;;;;;N;;;;; -188DC;TANGUT COMPONENT-221;Lo;0;L;;;;;N;;;;; -188DD;TANGUT COMPONENT-222;Lo;0;L;;;;;N;;;;; -188DE;TANGUT COMPONENT-223;Lo;0;L;;;;;N;;;;; -188DF;TANGUT COMPONENT-224;Lo;0;L;;;;;N;;;;; -188E0;TANGUT COMPONENT-225;Lo;0;L;;;;;N;;;;; -188E1;TANGUT COMPONENT-226;Lo;0;L;;;;;N;;;;; -188E2;TANGUT COMPONENT-227;Lo;0;L;;;;;N;;;;; -188E3;TANGUT COMPONENT-228;Lo;0;L;;;;;N;;;;; -188E4;TANGUT COMPONENT-229;Lo;0;L;;;;;N;;;;; -188E5;TANGUT COMPONENT-230;Lo;0;L;;;;;N;;;;; -188E6;TANGUT COMPONENT-231;Lo;0;L;;;;;N;;;;; -188E7;TANGUT COMPONENT-232;Lo;0;L;;;;;N;;;;; -188E8;TANGUT COMPONENT-233;Lo;0;L;;;;;N;;;;; -188E9;TANGUT COMPONENT-234;Lo;0;L;;;;;N;;;;; -188EA;TANGUT COMPONENT-235;Lo;0;L;;;;;N;;;;; -188EB;TANGUT COMPONENT-236;Lo;0;L;;;;;N;;;;; -188EC;TANGUT COMPONENT-237;Lo;0;L;;;;;N;;;;; -188ED;TANGUT COMPONENT-238;Lo;0;L;;;;;N;;;;; -188EE;TANGUT COMPONENT-239;Lo;0;L;;;;;N;;;;; -188EF;TANGUT COMPONENT-240;Lo;0;L;;;;;N;;;;; -188F0;TANGUT COMPONENT-241;Lo;0;L;;;;;N;;;;; -188F1;TANGUT COMPONENT-242;Lo;0;L;;;;;N;;;;; -188F2;TANGUT COMPONENT-243;Lo;0;L;;;;;N;;;;; -188F3;TANGUT COMPONENT-244;Lo;0;L;;;;;N;;;;; -188F4;TANGUT COMPONENT-245;Lo;0;L;;;;;N;;;;; -188F5;TANGUT COMPONENT-246;Lo;0;L;;;;;N;;;;; -188F6;TANGUT COMPONENT-247;Lo;0;L;;;;;N;;;;; -188F7;TANGUT COMPONENT-248;Lo;0;L;;;;;N;;;;; -188F8;TANGUT COMPONENT-249;Lo;0;L;;;;;N;;;;; -188F9;TANGUT COMPONENT-250;Lo;0;L;;;;;N;;;;; -188FA;TANGUT COMPONENT-251;Lo;0;L;;;;;N;;;;; -188FB;TANGUT COMPONENT-252;Lo;0;L;;;;;N;;;;; -188FC;TANGUT COMPONENT-253;Lo;0;L;;;;;N;;;;; -188FD;TANGUT COMPONENT-254;Lo;0;L;;;;;N;;;;; -188FE;TANGUT COMPONENT-255;Lo;0;L;;;;;N;;;;; -188FF;TANGUT COMPONENT-256;Lo;0;L;;;;;N;;;;; -18900;TANGUT COMPONENT-257;Lo;0;L;;;;;N;;;;; -18901;TANGUT COMPONENT-258;Lo;0;L;;;;;N;;;;; -18902;TANGUT COMPONENT-259;Lo;0;L;;;;;N;;;;; -18903;TANGUT COMPONENT-260;Lo;0;L;;;;;N;;;;; -18904;TANGUT COMPONENT-261;Lo;0;L;;;;;N;;;;; -18905;TANGUT COMPONENT-262;Lo;0;L;;;;;N;;;;; -18906;TANGUT COMPONENT-263;Lo;0;L;;;;;N;;;;; -18907;TANGUT COMPONENT-264;Lo;0;L;;;;;N;;;;; -18908;TANGUT COMPONENT-265;Lo;0;L;;;;;N;;;;; -18909;TANGUT COMPONENT-266;Lo;0;L;;;;;N;;;;; -1890A;TANGUT COMPONENT-267;Lo;0;L;;;;;N;;;;; -1890B;TANGUT COMPONENT-268;Lo;0;L;;;;;N;;;;; -1890C;TANGUT COMPONENT-269;Lo;0;L;;;;;N;;;;; -1890D;TANGUT COMPONENT-270;Lo;0;L;;;;;N;;;;; -1890E;TANGUT COMPONENT-271;Lo;0;L;;;;;N;;;;; -1890F;TANGUT COMPONENT-272;Lo;0;L;;;;;N;;;;; -18910;TANGUT COMPONENT-273;Lo;0;L;;;;;N;;;;; -18911;TANGUT COMPONENT-274;Lo;0;L;;;;;N;;;;; -18912;TANGUT COMPONENT-275;Lo;0;L;;;;;N;;;;; -18913;TANGUT COMPONENT-276;Lo;0;L;;;;;N;;;;; -18914;TANGUT COMPONENT-277;Lo;0;L;;;;;N;;;;; -18915;TANGUT COMPONENT-278;Lo;0;L;;;;;N;;;;; -18916;TANGUT COMPONENT-279;Lo;0;L;;;;;N;;;;; -18917;TANGUT COMPONENT-280;Lo;0;L;;;;;N;;;;; -18918;TANGUT COMPONENT-281;Lo;0;L;;;;;N;;;;; -18919;TANGUT COMPONENT-282;Lo;0;L;;;;;N;;;;; -1891A;TANGUT COMPONENT-283;Lo;0;L;;;;;N;;;;; -1891B;TANGUT COMPONENT-284;Lo;0;L;;;;;N;;;;; -1891C;TANGUT COMPONENT-285;Lo;0;L;;;;;N;;;;; -1891D;TANGUT COMPONENT-286;Lo;0;L;;;;;N;;;;; -1891E;TANGUT COMPONENT-287;Lo;0;L;;;;;N;;;;; -1891F;TANGUT COMPONENT-288;Lo;0;L;;;;;N;;;;; -18920;TANGUT COMPONENT-289;Lo;0;L;;;;;N;;;;; -18921;TANGUT COMPONENT-290;Lo;0;L;;;;;N;;;;; -18922;TANGUT COMPONENT-291;Lo;0;L;;;;;N;;;;; -18923;TANGUT COMPONENT-292;Lo;0;L;;;;;N;;;;; -18924;TANGUT COMPONENT-293;Lo;0;L;;;;;N;;;;; -18925;TANGUT COMPONENT-294;Lo;0;L;;;;;N;;;;; -18926;TANGUT COMPONENT-295;Lo;0;L;;;;;N;;;;; -18927;TANGUT COMPONENT-296;Lo;0;L;;;;;N;;;;; -18928;TANGUT COMPONENT-297;Lo;0;L;;;;;N;;;;; -18929;TANGUT COMPONENT-298;Lo;0;L;;;;;N;;;;; -1892A;TANGUT COMPONENT-299;Lo;0;L;;;;;N;;;;; -1892B;TANGUT COMPONENT-300;Lo;0;L;;;;;N;;;;; -1892C;TANGUT COMPONENT-301;Lo;0;L;;;;;N;;;;; -1892D;TANGUT COMPONENT-302;Lo;0;L;;;;;N;;;;; -1892E;TANGUT COMPONENT-303;Lo;0;L;;;;;N;;;;; -1892F;TANGUT COMPONENT-304;Lo;0;L;;;;;N;;;;; -18930;TANGUT COMPONENT-305;Lo;0;L;;;;;N;;;;; -18931;TANGUT COMPONENT-306;Lo;0;L;;;;;N;;;;; -18932;TANGUT COMPONENT-307;Lo;0;L;;;;;N;;;;; -18933;TANGUT COMPONENT-308;Lo;0;L;;;;;N;;;;; -18934;TANGUT COMPONENT-309;Lo;0;L;;;;;N;;;;; -18935;TANGUT COMPONENT-310;Lo;0;L;;;;;N;;;;; -18936;TANGUT COMPONENT-311;Lo;0;L;;;;;N;;;;; -18937;TANGUT COMPONENT-312;Lo;0;L;;;;;N;;;;; -18938;TANGUT COMPONENT-313;Lo;0;L;;;;;N;;;;; -18939;TANGUT COMPONENT-314;Lo;0;L;;;;;N;;;;; -1893A;TANGUT COMPONENT-315;Lo;0;L;;;;;N;;;;; -1893B;TANGUT COMPONENT-316;Lo;0;L;;;;;N;;;;; -1893C;TANGUT COMPONENT-317;Lo;0;L;;;;;N;;;;; -1893D;TANGUT COMPONENT-318;Lo;0;L;;;;;N;;;;; -1893E;TANGUT COMPONENT-319;Lo;0;L;;;;;N;;;;; -1893F;TANGUT COMPONENT-320;Lo;0;L;;;;;N;;;;; -18940;TANGUT COMPONENT-321;Lo;0;L;;;;;N;;;;; -18941;TANGUT COMPONENT-322;Lo;0;L;;;;;N;;;;; -18942;TANGUT COMPONENT-323;Lo;0;L;;;;;N;;;;; -18943;TANGUT COMPONENT-324;Lo;0;L;;;;;N;;;;; -18944;TANGUT COMPONENT-325;Lo;0;L;;;;;N;;;;; -18945;TANGUT COMPONENT-326;Lo;0;L;;;;;N;;;;; -18946;TANGUT COMPONENT-327;Lo;0;L;;;;;N;;;;; -18947;TANGUT COMPONENT-328;Lo;0;L;;;;;N;;;;; -18948;TANGUT COMPONENT-329;Lo;0;L;;;;;N;;;;; -18949;TANGUT COMPONENT-330;Lo;0;L;;;;;N;;;;; -1894A;TANGUT COMPONENT-331;Lo;0;L;;;;;N;;;;; -1894B;TANGUT COMPONENT-332;Lo;0;L;;;;;N;;;;; -1894C;TANGUT COMPONENT-333;Lo;0;L;;;;;N;;;;; -1894D;TANGUT COMPONENT-334;Lo;0;L;;;;;N;;;;; -1894E;TANGUT COMPONENT-335;Lo;0;L;;;;;N;;;;; -1894F;TANGUT COMPONENT-336;Lo;0;L;;;;;N;;;;; -18950;TANGUT COMPONENT-337;Lo;0;L;;;;;N;;;;; -18951;TANGUT COMPONENT-338;Lo;0;L;;;;;N;;;;; -18952;TANGUT COMPONENT-339;Lo;0;L;;;;;N;;;;; -18953;TANGUT COMPONENT-340;Lo;0;L;;;;;N;;;;; -18954;TANGUT COMPONENT-341;Lo;0;L;;;;;N;;;;; -18955;TANGUT COMPONENT-342;Lo;0;L;;;;;N;;;;; -18956;TANGUT COMPONENT-343;Lo;0;L;;;;;N;;;;; -18957;TANGUT COMPONENT-344;Lo;0;L;;;;;N;;;;; -18958;TANGUT COMPONENT-345;Lo;0;L;;;;;N;;;;; -18959;TANGUT COMPONENT-346;Lo;0;L;;;;;N;;;;; -1895A;TANGUT COMPONENT-347;Lo;0;L;;;;;N;;;;; -1895B;TANGUT COMPONENT-348;Lo;0;L;;;;;N;;;;; -1895C;TANGUT COMPONENT-349;Lo;0;L;;;;;N;;;;; -1895D;TANGUT COMPONENT-350;Lo;0;L;;;;;N;;;;; -1895E;TANGUT COMPONENT-351;Lo;0;L;;;;;N;;;;; -1895F;TANGUT COMPONENT-352;Lo;0;L;;;;;N;;;;; -18960;TANGUT COMPONENT-353;Lo;0;L;;;;;N;;;;; -18961;TANGUT COMPONENT-354;Lo;0;L;;;;;N;;;;; -18962;TANGUT COMPONENT-355;Lo;0;L;;;;;N;;;;; -18963;TANGUT COMPONENT-356;Lo;0;L;;;;;N;;;;; -18964;TANGUT COMPONENT-357;Lo;0;L;;;;;N;;;;; -18965;TANGUT COMPONENT-358;Lo;0;L;;;;;N;;;;; -18966;TANGUT COMPONENT-359;Lo;0;L;;;;;N;;;;; -18967;TANGUT COMPONENT-360;Lo;0;L;;;;;N;;;;; -18968;TANGUT COMPONENT-361;Lo;0;L;;;;;N;;;;; -18969;TANGUT COMPONENT-362;Lo;0;L;;;;;N;;;;; -1896A;TANGUT COMPONENT-363;Lo;0;L;;;;;N;;;;; -1896B;TANGUT COMPONENT-364;Lo;0;L;;;;;N;;;;; -1896C;TANGUT COMPONENT-365;Lo;0;L;;;;;N;;;;; -1896D;TANGUT COMPONENT-366;Lo;0;L;;;;;N;;;;; -1896E;TANGUT COMPONENT-367;Lo;0;L;;;;;N;;;;; -1896F;TANGUT COMPONENT-368;Lo;0;L;;;;;N;;;;; -18970;TANGUT COMPONENT-369;Lo;0;L;;;;;N;;;;; -18971;TANGUT COMPONENT-370;Lo;0;L;;;;;N;;;;; -18972;TANGUT COMPONENT-371;Lo;0;L;;;;;N;;;;; -18973;TANGUT COMPONENT-372;Lo;0;L;;;;;N;;;;; -18974;TANGUT COMPONENT-373;Lo;0;L;;;;;N;;;;; -18975;TANGUT COMPONENT-374;Lo;0;L;;;;;N;;;;; -18976;TANGUT COMPONENT-375;Lo;0;L;;;;;N;;;;; -18977;TANGUT COMPONENT-376;Lo;0;L;;;;;N;;;;; -18978;TANGUT COMPONENT-377;Lo;0;L;;;;;N;;;;; -18979;TANGUT COMPONENT-378;Lo;0;L;;;;;N;;;;; -1897A;TANGUT COMPONENT-379;Lo;0;L;;;;;N;;;;; -1897B;TANGUT COMPONENT-380;Lo;0;L;;;;;N;;;;; -1897C;TANGUT COMPONENT-381;Lo;0;L;;;;;N;;;;; -1897D;TANGUT COMPONENT-382;Lo;0;L;;;;;N;;;;; -1897E;TANGUT COMPONENT-383;Lo;0;L;;;;;N;;;;; -1897F;TANGUT COMPONENT-384;Lo;0;L;;;;;N;;;;; -18980;TANGUT COMPONENT-385;Lo;0;L;;;;;N;;;;; -18981;TANGUT COMPONENT-386;Lo;0;L;;;;;N;;;;; -18982;TANGUT COMPONENT-387;Lo;0;L;;;;;N;;;;; -18983;TANGUT COMPONENT-388;Lo;0;L;;;;;N;;;;; -18984;TANGUT COMPONENT-389;Lo;0;L;;;;;N;;;;; -18985;TANGUT COMPONENT-390;Lo;0;L;;;;;N;;;;; -18986;TANGUT COMPONENT-391;Lo;0;L;;;;;N;;;;; -18987;TANGUT COMPONENT-392;Lo;0;L;;;;;N;;;;; -18988;TANGUT COMPONENT-393;Lo;0;L;;;;;N;;;;; -18989;TANGUT COMPONENT-394;Lo;0;L;;;;;N;;;;; -1898A;TANGUT COMPONENT-395;Lo;0;L;;;;;N;;;;; -1898B;TANGUT COMPONENT-396;Lo;0;L;;;;;N;;;;; -1898C;TANGUT COMPONENT-397;Lo;0;L;;;;;N;;;;; -1898D;TANGUT COMPONENT-398;Lo;0;L;;;;;N;;;;; -1898E;TANGUT COMPONENT-399;Lo;0;L;;;;;N;;;;; -1898F;TANGUT COMPONENT-400;Lo;0;L;;;;;N;;;;; -18990;TANGUT COMPONENT-401;Lo;0;L;;;;;N;;;;; -18991;TANGUT COMPONENT-402;Lo;0;L;;;;;N;;;;; -18992;TANGUT COMPONENT-403;Lo;0;L;;;;;N;;;;; -18993;TANGUT COMPONENT-404;Lo;0;L;;;;;N;;;;; -18994;TANGUT COMPONENT-405;Lo;0;L;;;;;N;;;;; -18995;TANGUT COMPONENT-406;Lo;0;L;;;;;N;;;;; -18996;TANGUT COMPONENT-407;Lo;0;L;;;;;N;;;;; -18997;TANGUT COMPONENT-408;Lo;0;L;;;;;N;;;;; -18998;TANGUT COMPONENT-409;Lo;0;L;;;;;N;;;;; -18999;TANGUT COMPONENT-410;Lo;0;L;;;;;N;;;;; -1899A;TANGUT COMPONENT-411;Lo;0;L;;;;;N;;;;; -1899B;TANGUT COMPONENT-412;Lo;0;L;;;;;N;;;;; -1899C;TANGUT COMPONENT-413;Lo;0;L;;;;;N;;;;; -1899D;TANGUT COMPONENT-414;Lo;0;L;;;;;N;;;;; -1899E;TANGUT COMPONENT-415;Lo;0;L;;;;;N;;;;; -1899F;TANGUT COMPONENT-416;Lo;0;L;;;;;N;;;;; -189A0;TANGUT COMPONENT-417;Lo;0;L;;;;;N;;;;; -189A1;TANGUT COMPONENT-418;Lo;0;L;;;;;N;;;;; -189A2;TANGUT COMPONENT-419;Lo;0;L;;;;;N;;;;; -189A3;TANGUT COMPONENT-420;Lo;0;L;;;;;N;;;;; -189A4;TANGUT COMPONENT-421;Lo;0;L;;;;;N;;;;; -189A5;TANGUT COMPONENT-422;Lo;0;L;;;;;N;;;;; -189A6;TANGUT COMPONENT-423;Lo;0;L;;;;;N;;;;; -189A7;TANGUT COMPONENT-424;Lo;0;L;;;;;N;;;;; -189A8;TANGUT COMPONENT-425;Lo;0;L;;;;;N;;;;; -189A9;TANGUT COMPONENT-426;Lo;0;L;;;;;N;;;;; -189AA;TANGUT COMPONENT-427;Lo;0;L;;;;;N;;;;; -189AB;TANGUT COMPONENT-428;Lo;0;L;;;;;N;;;;; -189AC;TANGUT COMPONENT-429;Lo;0;L;;;;;N;;;;; -189AD;TANGUT COMPONENT-430;Lo;0;L;;;;;N;;;;; -189AE;TANGUT COMPONENT-431;Lo;0;L;;;;;N;;;;; -189AF;TANGUT COMPONENT-432;Lo;0;L;;;;;N;;;;; -189B0;TANGUT COMPONENT-433;Lo;0;L;;;;;N;;;;; -189B1;TANGUT COMPONENT-434;Lo;0;L;;;;;N;;;;; -189B2;TANGUT COMPONENT-435;Lo;0;L;;;;;N;;;;; -189B3;TANGUT COMPONENT-436;Lo;0;L;;;;;N;;;;; -189B4;TANGUT COMPONENT-437;Lo;0;L;;;;;N;;;;; -189B5;TANGUT COMPONENT-438;Lo;0;L;;;;;N;;;;; -189B6;TANGUT COMPONENT-439;Lo;0;L;;;;;N;;;;; -189B7;TANGUT COMPONENT-440;Lo;0;L;;;;;N;;;;; -189B8;TANGUT COMPONENT-441;Lo;0;L;;;;;N;;;;; -189B9;TANGUT COMPONENT-442;Lo;0;L;;;;;N;;;;; -189BA;TANGUT COMPONENT-443;Lo;0;L;;;;;N;;;;; -189BB;TANGUT COMPONENT-444;Lo;0;L;;;;;N;;;;; -189BC;TANGUT COMPONENT-445;Lo;0;L;;;;;N;;;;; -189BD;TANGUT COMPONENT-446;Lo;0;L;;;;;N;;;;; -189BE;TANGUT COMPONENT-447;Lo;0;L;;;;;N;;;;; -189BF;TANGUT COMPONENT-448;Lo;0;L;;;;;N;;;;; -189C0;TANGUT COMPONENT-449;Lo;0;L;;;;;N;;;;; -189C1;TANGUT COMPONENT-450;Lo;0;L;;;;;N;;;;; -189C2;TANGUT COMPONENT-451;Lo;0;L;;;;;N;;;;; -189C3;TANGUT COMPONENT-452;Lo;0;L;;;;;N;;;;; -189C4;TANGUT COMPONENT-453;Lo;0;L;;;;;N;;;;; -189C5;TANGUT COMPONENT-454;Lo;0;L;;;;;N;;;;; -189C6;TANGUT COMPONENT-455;Lo;0;L;;;;;N;;;;; -189C7;TANGUT COMPONENT-456;Lo;0;L;;;;;N;;;;; -189C8;TANGUT COMPONENT-457;Lo;0;L;;;;;N;;;;; -189C9;TANGUT COMPONENT-458;Lo;0;L;;;;;N;;;;; -189CA;TANGUT COMPONENT-459;Lo;0;L;;;;;N;;;;; -189CB;TANGUT COMPONENT-460;Lo;0;L;;;;;N;;;;; -189CC;TANGUT COMPONENT-461;Lo;0;L;;;;;N;;;;; -189CD;TANGUT COMPONENT-462;Lo;0;L;;;;;N;;;;; -189CE;TANGUT COMPONENT-463;Lo;0;L;;;;;N;;;;; -189CF;TANGUT COMPONENT-464;Lo;0;L;;;;;N;;;;; -189D0;TANGUT COMPONENT-465;Lo;0;L;;;;;N;;;;; -189D1;TANGUT COMPONENT-466;Lo;0;L;;;;;N;;;;; -189D2;TANGUT COMPONENT-467;Lo;0;L;;;;;N;;;;; -189D3;TANGUT COMPONENT-468;Lo;0;L;;;;;N;;;;; -189D4;TANGUT COMPONENT-469;Lo;0;L;;;;;N;;;;; -189D5;TANGUT COMPONENT-470;Lo;0;L;;;;;N;;;;; -189D6;TANGUT COMPONENT-471;Lo;0;L;;;;;N;;;;; -189D7;TANGUT COMPONENT-472;Lo;0;L;;;;;N;;;;; -189D8;TANGUT COMPONENT-473;Lo;0;L;;;;;N;;;;; -189D9;TANGUT COMPONENT-474;Lo;0;L;;;;;N;;;;; -189DA;TANGUT COMPONENT-475;Lo;0;L;;;;;N;;;;; -189DB;TANGUT COMPONENT-476;Lo;0;L;;;;;N;;;;; -189DC;TANGUT COMPONENT-477;Lo;0;L;;;;;N;;;;; -189DD;TANGUT COMPONENT-478;Lo;0;L;;;;;N;;;;; -189DE;TANGUT COMPONENT-479;Lo;0;L;;;;;N;;;;; -189DF;TANGUT COMPONENT-480;Lo;0;L;;;;;N;;;;; -189E0;TANGUT COMPONENT-481;Lo;0;L;;;;;N;;;;; -189E1;TANGUT COMPONENT-482;Lo;0;L;;;;;N;;;;; -189E2;TANGUT COMPONENT-483;Lo;0;L;;;;;N;;;;; -189E3;TANGUT COMPONENT-484;Lo;0;L;;;;;N;;;;; -189E4;TANGUT COMPONENT-485;Lo;0;L;;;;;N;;;;; -189E5;TANGUT COMPONENT-486;Lo;0;L;;;;;N;;;;; -189E6;TANGUT COMPONENT-487;Lo;0;L;;;;;N;;;;; -189E7;TANGUT COMPONENT-488;Lo;0;L;;;;;N;;;;; -189E8;TANGUT COMPONENT-489;Lo;0;L;;;;;N;;;;; -189E9;TANGUT COMPONENT-490;Lo;0;L;;;;;N;;;;; -189EA;TANGUT COMPONENT-491;Lo;0;L;;;;;N;;;;; -189EB;TANGUT COMPONENT-492;Lo;0;L;;;;;N;;;;; -189EC;TANGUT COMPONENT-493;Lo;0;L;;;;;N;;;;; -189ED;TANGUT COMPONENT-494;Lo;0;L;;;;;N;;;;; -189EE;TANGUT COMPONENT-495;Lo;0;L;;;;;N;;;;; -189EF;TANGUT COMPONENT-496;Lo;0;L;;;;;N;;;;; -189F0;TANGUT COMPONENT-497;Lo;0;L;;;;;N;;;;; -189F1;TANGUT COMPONENT-498;Lo;0;L;;;;;N;;;;; -189F2;TANGUT COMPONENT-499;Lo;0;L;;;;;N;;;;; -189F3;TANGUT COMPONENT-500;Lo;0;L;;;;;N;;;;; -189F4;TANGUT COMPONENT-501;Lo;0;L;;;;;N;;;;; -189F5;TANGUT COMPONENT-502;Lo;0;L;;;;;N;;;;; -189F6;TANGUT COMPONENT-503;Lo;0;L;;;;;N;;;;; -189F7;TANGUT COMPONENT-504;Lo;0;L;;;;;N;;;;; -189F8;TANGUT COMPONENT-505;Lo;0;L;;;;;N;;;;; -189F9;TANGUT COMPONENT-506;Lo;0;L;;;;;N;;;;; -189FA;TANGUT COMPONENT-507;Lo;0;L;;;;;N;;;;; -189FB;TANGUT COMPONENT-508;Lo;0;L;;;;;N;;;;; -189FC;TANGUT COMPONENT-509;Lo;0;L;;;;;N;;;;; -189FD;TANGUT COMPONENT-510;Lo;0;L;;;;;N;;;;; -189FE;TANGUT COMPONENT-511;Lo;0;L;;;;;N;;;;; -189FF;TANGUT COMPONENT-512;Lo;0;L;;;;;N;;;;; -18A00;TANGUT COMPONENT-513;Lo;0;L;;;;;N;;;;; -18A01;TANGUT COMPONENT-514;Lo;0;L;;;;;N;;;;; -18A02;TANGUT COMPONENT-515;Lo;0;L;;;;;N;;;;; -18A03;TANGUT COMPONENT-516;Lo;0;L;;;;;N;;;;; -18A04;TANGUT COMPONENT-517;Lo;0;L;;;;;N;;;;; -18A05;TANGUT COMPONENT-518;Lo;0;L;;;;;N;;;;; -18A06;TANGUT COMPONENT-519;Lo;0;L;;;;;N;;;;; -18A07;TANGUT COMPONENT-520;Lo;0;L;;;;;N;;;;; -18A08;TANGUT COMPONENT-521;Lo;0;L;;;;;N;;;;; -18A09;TANGUT COMPONENT-522;Lo;0;L;;;;;N;;;;; -18A0A;TANGUT COMPONENT-523;Lo;0;L;;;;;N;;;;; -18A0B;TANGUT COMPONENT-524;Lo;0;L;;;;;N;;;;; -18A0C;TANGUT COMPONENT-525;Lo;0;L;;;;;N;;;;; -18A0D;TANGUT COMPONENT-526;Lo;0;L;;;;;N;;;;; -18A0E;TANGUT COMPONENT-527;Lo;0;L;;;;;N;;;;; -18A0F;TANGUT COMPONENT-528;Lo;0;L;;;;;N;;;;; -18A10;TANGUT COMPONENT-529;Lo;0;L;;;;;N;;;;; -18A11;TANGUT COMPONENT-530;Lo;0;L;;;;;N;;;;; -18A12;TANGUT COMPONENT-531;Lo;0;L;;;;;N;;;;; -18A13;TANGUT COMPONENT-532;Lo;0;L;;;;;N;;;;; -18A14;TANGUT COMPONENT-533;Lo;0;L;;;;;N;;;;; -18A15;TANGUT COMPONENT-534;Lo;0;L;;;;;N;;;;; -18A16;TANGUT COMPONENT-535;Lo;0;L;;;;;N;;;;; -18A17;TANGUT COMPONENT-536;Lo;0;L;;;;;N;;;;; -18A18;TANGUT COMPONENT-537;Lo;0;L;;;;;N;;;;; -18A19;TANGUT COMPONENT-538;Lo;0;L;;;;;N;;;;; -18A1A;TANGUT COMPONENT-539;Lo;0;L;;;;;N;;;;; -18A1B;TANGUT COMPONENT-540;Lo;0;L;;;;;N;;;;; -18A1C;TANGUT COMPONENT-541;Lo;0;L;;;;;N;;;;; -18A1D;TANGUT COMPONENT-542;Lo;0;L;;;;;N;;;;; -18A1E;TANGUT COMPONENT-543;Lo;0;L;;;;;N;;;;; -18A1F;TANGUT COMPONENT-544;Lo;0;L;;;;;N;;;;; -18A20;TANGUT COMPONENT-545;Lo;0;L;;;;;N;;;;; -18A21;TANGUT COMPONENT-546;Lo;0;L;;;;;N;;;;; -18A22;TANGUT COMPONENT-547;Lo;0;L;;;;;N;;;;; -18A23;TANGUT COMPONENT-548;Lo;0;L;;;;;N;;;;; -18A24;TANGUT COMPONENT-549;Lo;0;L;;;;;N;;;;; -18A25;TANGUT COMPONENT-550;Lo;0;L;;;;;N;;;;; -18A26;TANGUT COMPONENT-551;Lo;0;L;;;;;N;;;;; -18A27;TANGUT COMPONENT-552;Lo;0;L;;;;;N;;;;; -18A28;TANGUT COMPONENT-553;Lo;0;L;;;;;N;;;;; -18A29;TANGUT COMPONENT-554;Lo;0;L;;;;;N;;;;; -18A2A;TANGUT COMPONENT-555;Lo;0;L;;;;;N;;;;; -18A2B;TANGUT COMPONENT-556;Lo;0;L;;;;;N;;;;; -18A2C;TANGUT COMPONENT-557;Lo;0;L;;;;;N;;;;; -18A2D;TANGUT COMPONENT-558;Lo;0;L;;;;;N;;;;; -18A2E;TANGUT COMPONENT-559;Lo;0;L;;;;;N;;;;; -18A2F;TANGUT COMPONENT-560;Lo;0;L;;;;;N;;;;; -18A30;TANGUT COMPONENT-561;Lo;0;L;;;;;N;;;;; -18A31;TANGUT COMPONENT-562;Lo;0;L;;;;;N;;;;; -18A32;TANGUT COMPONENT-563;Lo;0;L;;;;;N;;;;; -18A33;TANGUT COMPONENT-564;Lo;0;L;;;;;N;;;;; -18A34;TANGUT COMPONENT-565;Lo;0;L;;;;;N;;;;; -18A35;TANGUT COMPONENT-566;Lo;0;L;;;;;N;;;;; -18A36;TANGUT COMPONENT-567;Lo;0;L;;;;;N;;;;; -18A37;TANGUT COMPONENT-568;Lo;0;L;;;;;N;;;;; -18A38;TANGUT COMPONENT-569;Lo;0;L;;;;;N;;;;; -18A39;TANGUT COMPONENT-570;Lo;0;L;;;;;N;;;;; -18A3A;TANGUT COMPONENT-571;Lo;0;L;;;;;N;;;;; -18A3B;TANGUT COMPONENT-572;Lo;0;L;;;;;N;;;;; -18A3C;TANGUT COMPONENT-573;Lo;0;L;;;;;N;;;;; -18A3D;TANGUT COMPONENT-574;Lo;0;L;;;;;N;;;;; -18A3E;TANGUT COMPONENT-575;Lo;0;L;;;;;N;;;;; -18A3F;TANGUT COMPONENT-576;Lo;0;L;;;;;N;;;;; -18A40;TANGUT COMPONENT-577;Lo;0;L;;;;;N;;;;; -18A41;TANGUT COMPONENT-578;Lo;0;L;;;;;N;;;;; -18A42;TANGUT COMPONENT-579;Lo;0;L;;;;;N;;;;; -18A43;TANGUT COMPONENT-580;Lo;0;L;;;;;N;;;;; -18A44;TANGUT COMPONENT-581;Lo;0;L;;;;;N;;;;; -18A45;TANGUT COMPONENT-582;Lo;0;L;;;;;N;;;;; -18A46;TANGUT COMPONENT-583;Lo;0;L;;;;;N;;;;; -18A47;TANGUT COMPONENT-584;Lo;0;L;;;;;N;;;;; -18A48;TANGUT COMPONENT-585;Lo;0;L;;;;;N;;;;; -18A49;TANGUT COMPONENT-586;Lo;0;L;;;;;N;;;;; -18A4A;TANGUT COMPONENT-587;Lo;0;L;;;;;N;;;;; -18A4B;TANGUT COMPONENT-588;Lo;0;L;;;;;N;;;;; -18A4C;TANGUT COMPONENT-589;Lo;0;L;;;;;N;;;;; -18A4D;TANGUT COMPONENT-590;Lo;0;L;;;;;N;;;;; -18A4E;TANGUT COMPONENT-591;Lo;0;L;;;;;N;;;;; -18A4F;TANGUT COMPONENT-592;Lo;0;L;;;;;N;;;;; -18A50;TANGUT COMPONENT-593;Lo;0;L;;;;;N;;;;; -18A51;TANGUT COMPONENT-594;Lo;0;L;;;;;N;;;;; -18A52;TANGUT COMPONENT-595;Lo;0;L;;;;;N;;;;; -18A53;TANGUT COMPONENT-596;Lo;0;L;;;;;N;;;;; -18A54;TANGUT COMPONENT-597;Lo;0;L;;;;;N;;;;; -18A55;TANGUT COMPONENT-598;Lo;0;L;;;;;N;;;;; -18A56;TANGUT COMPONENT-599;Lo;0;L;;;;;N;;;;; -18A57;TANGUT COMPONENT-600;Lo;0;L;;;;;N;;;;; -18A58;TANGUT COMPONENT-601;Lo;0;L;;;;;N;;;;; -18A59;TANGUT COMPONENT-602;Lo;0;L;;;;;N;;;;; -18A5A;TANGUT COMPONENT-603;Lo;0;L;;;;;N;;;;; -18A5B;TANGUT COMPONENT-604;Lo;0;L;;;;;N;;;;; -18A5C;TANGUT COMPONENT-605;Lo;0;L;;;;;N;;;;; -18A5D;TANGUT COMPONENT-606;Lo;0;L;;;;;N;;;;; -18A5E;TANGUT COMPONENT-607;Lo;0;L;;;;;N;;;;; -18A5F;TANGUT COMPONENT-608;Lo;0;L;;;;;N;;;;; -18A60;TANGUT COMPONENT-609;Lo;0;L;;;;;N;;;;; -18A61;TANGUT COMPONENT-610;Lo;0;L;;;;;N;;;;; -18A62;TANGUT COMPONENT-611;Lo;0;L;;;;;N;;;;; -18A63;TANGUT COMPONENT-612;Lo;0;L;;;;;N;;;;; -18A64;TANGUT COMPONENT-613;Lo;0;L;;;;;N;;;;; -18A65;TANGUT COMPONENT-614;Lo;0;L;;;;;N;;;;; -18A66;TANGUT COMPONENT-615;Lo;0;L;;;;;N;;;;; -18A67;TANGUT COMPONENT-616;Lo;0;L;;;;;N;;;;; -18A68;TANGUT COMPONENT-617;Lo;0;L;;;;;N;;;;; -18A69;TANGUT COMPONENT-618;Lo;0;L;;;;;N;;;;; -18A6A;TANGUT COMPONENT-619;Lo;0;L;;;;;N;;;;; -18A6B;TANGUT COMPONENT-620;Lo;0;L;;;;;N;;;;; -18A6C;TANGUT COMPONENT-621;Lo;0;L;;;;;N;;;;; -18A6D;TANGUT COMPONENT-622;Lo;0;L;;;;;N;;;;; -18A6E;TANGUT COMPONENT-623;Lo;0;L;;;;;N;;;;; -18A6F;TANGUT COMPONENT-624;Lo;0;L;;;;;N;;;;; -18A70;TANGUT COMPONENT-625;Lo;0;L;;;;;N;;;;; -18A71;TANGUT COMPONENT-626;Lo;0;L;;;;;N;;;;; -18A72;TANGUT COMPONENT-627;Lo;0;L;;;;;N;;;;; -18A73;TANGUT COMPONENT-628;Lo;0;L;;;;;N;;;;; -18A74;TANGUT COMPONENT-629;Lo;0;L;;;;;N;;;;; -18A75;TANGUT COMPONENT-630;Lo;0;L;;;;;N;;;;; -18A76;TANGUT COMPONENT-631;Lo;0;L;;;;;N;;;;; -18A77;TANGUT COMPONENT-632;Lo;0;L;;;;;N;;;;; -18A78;TANGUT COMPONENT-633;Lo;0;L;;;;;N;;;;; -18A79;TANGUT COMPONENT-634;Lo;0;L;;;;;N;;;;; -18A7A;TANGUT COMPONENT-635;Lo;0;L;;;;;N;;;;; -18A7B;TANGUT COMPONENT-636;Lo;0;L;;;;;N;;;;; -18A7C;TANGUT COMPONENT-637;Lo;0;L;;;;;N;;;;; -18A7D;TANGUT COMPONENT-638;Lo;0;L;;;;;N;;;;; -18A7E;TANGUT COMPONENT-639;Lo;0;L;;;;;N;;;;; -18A7F;TANGUT COMPONENT-640;Lo;0;L;;;;;N;;;;; -18A80;TANGUT COMPONENT-641;Lo;0;L;;;;;N;;;;; -18A81;TANGUT COMPONENT-642;Lo;0;L;;;;;N;;;;; -18A82;TANGUT COMPONENT-643;Lo;0;L;;;;;N;;;;; -18A83;TANGUT COMPONENT-644;Lo;0;L;;;;;N;;;;; -18A84;TANGUT COMPONENT-645;Lo;0;L;;;;;N;;;;; -18A85;TANGUT COMPONENT-646;Lo;0;L;;;;;N;;;;; -18A86;TANGUT COMPONENT-647;Lo;0;L;;;;;N;;;;; -18A87;TANGUT COMPONENT-648;Lo;0;L;;;;;N;;;;; -18A88;TANGUT COMPONENT-649;Lo;0;L;;;;;N;;;;; -18A89;TANGUT COMPONENT-650;Lo;0;L;;;;;N;;;;; -18A8A;TANGUT COMPONENT-651;Lo;0;L;;;;;N;;;;; -18A8B;TANGUT COMPONENT-652;Lo;0;L;;;;;N;;;;; -18A8C;TANGUT COMPONENT-653;Lo;0;L;;;;;N;;;;; -18A8D;TANGUT COMPONENT-654;Lo;0;L;;;;;N;;;;; -18A8E;TANGUT COMPONENT-655;Lo;0;L;;;;;N;;;;; -18A8F;TANGUT COMPONENT-656;Lo;0;L;;;;;N;;;;; -18A90;TANGUT COMPONENT-657;Lo;0;L;;;;;N;;;;; -18A91;TANGUT COMPONENT-658;Lo;0;L;;;;;N;;;;; -18A92;TANGUT COMPONENT-659;Lo;0;L;;;;;N;;;;; -18A93;TANGUT COMPONENT-660;Lo;0;L;;;;;N;;;;; -18A94;TANGUT COMPONENT-661;Lo;0;L;;;;;N;;;;; -18A95;TANGUT COMPONENT-662;Lo;0;L;;;;;N;;;;; -18A96;TANGUT COMPONENT-663;Lo;0;L;;;;;N;;;;; -18A97;TANGUT COMPONENT-664;Lo;0;L;;;;;N;;;;; -18A98;TANGUT COMPONENT-665;Lo;0;L;;;;;N;;;;; -18A99;TANGUT COMPONENT-666;Lo;0;L;;;;;N;;;;; -18A9A;TANGUT COMPONENT-667;Lo;0;L;;;;;N;;;;; -18A9B;TANGUT COMPONENT-668;Lo;0;L;;;;;N;;;;; -18A9C;TANGUT COMPONENT-669;Lo;0;L;;;;;N;;;;; -18A9D;TANGUT COMPONENT-670;Lo;0;L;;;;;N;;;;; -18A9E;TANGUT COMPONENT-671;Lo;0;L;;;;;N;;;;; -18A9F;TANGUT COMPONENT-672;Lo;0;L;;;;;N;;;;; -18AA0;TANGUT COMPONENT-673;Lo;0;L;;;;;N;;;;; -18AA1;TANGUT COMPONENT-674;Lo;0;L;;;;;N;;;;; -18AA2;TANGUT COMPONENT-675;Lo;0;L;;;;;N;;;;; -18AA3;TANGUT COMPONENT-676;Lo;0;L;;;;;N;;;;; -18AA4;TANGUT COMPONENT-677;Lo;0;L;;;;;N;;;;; -18AA5;TANGUT COMPONENT-678;Lo;0;L;;;;;N;;;;; -18AA6;TANGUT COMPONENT-679;Lo;0;L;;;;;N;;;;; -18AA7;TANGUT COMPONENT-680;Lo;0;L;;;;;N;;;;; -18AA8;TANGUT COMPONENT-681;Lo;0;L;;;;;N;;;;; -18AA9;TANGUT COMPONENT-682;Lo;0;L;;;;;N;;;;; -18AAA;TANGUT COMPONENT-683;Lo;0;L;;;;;N;;;;; -18AAB;TANGUT COMPONENT-684;Lo;0;L;;;;;N;;;;; -18AAC;TANGUT COMPONENT-685;Lo;0;L;;;;;N;;;;; -18AAD;TANGUT COMPONENT-686;Lo;0;L;;;;;N;;;;; -18AAE;TANGUT COMPONENT-687;Lo;0;L;;;;;N;;;;; -18AAF;TANGUT COMPONENT-688;Lo;0;L;;;;;N;;;;; -18AB0;TANGUT COMPONENT-689;Lo;0;L;;;;;N;;;;; -18AB1;TANGUT COMPONENT-690;Lo;0;L;;;;;N;;;;; -18AB2;TANGUT COMPONENT-691;Lo;0;L;;;;;N;;;;; -18AB3;TANGUT COMPONENT-692;Lo;0;L;;;;;N;;;;; -18AB4;TANGUT COMPONENT-693;Lo;0;L;;;;;N;;;;; -18AB5;TANGUT COMPONENT-694;Lo;0;L;;;;;N;;;;; -18AB6;TANGUT COMPONENT-695;Lo;0;L;;;;;N;;;;; -18AB7;TANGUT COMPONENT-696;Lo;0;L;;;;;N;;;;; -18AB8;TANGUT COMPONENT-697;Lo;0;L;;;;;N;;;;; -18AB9;TANGUT COMPONENT-698;Lo;0;L;;;;;N;;;;; -18ABA;TANGUT COMPONENT-699;Lo;0;L;;;;;N;;;;; -18ABB;TANGUT COMPONENT-700;Lo;0;L;;;;;N;;;;; -18ABC;TANGUT COMPONENT-701;Lo;0;L;;;;;N;;;;; -18ABD;TANGUT COMPONENT-702;Lo;0;L;;;;;N;;;;; -18ABE;TANGUT COMPONENT-703;Lo;0;L;;;;;N;;;;; -18ABF;TANGUT COMPONENT-704;Lo;0;L;;;;;N;;;;; -18AC0;TANGUT COMPONENT-705;Lo;0;L;;;;;N;;;;; -18AC1;TANGUT COMPONENT-706;Lo;0;L;;;;;N;;;;; -18AC2;TANGUT COMPONENT-707;Lo;0;L;;;;;N;;;;; -18AC3;TANGUT COMPONENT-708;Lo;0;L;;;;;N;;;;; -18AC4;TANGUT COMPONENT-709;Lo;0;L;;;;;N;;;;; -18AC5;TANGUT COMPONENT-710;Lo;0;L;;;;;N;;;;; -18AC6;TANGUT COMPONENT-711;Lo;0;L;;;;;N;;;;; -18AC7;TANGUT COMPONENT-712;Lo;0;L;;;;;N;;;;; -18AC8;TANGUT COMPONENT-713;Lo;0;L;;;;;N;;;;; -18AC9;TANGUT COMPONENT-714;Lo;0;L;;;;;N;;;;; -18ACA;TANGUT COMPONENT-715;Lo;0;L;;;;;N;;;;; -18ACB;TANGUT COMPONENT-716;Lo;0;L;;;;;N;;;;; -18ACC;TANGUT COMPONENT-717;Lo;0;L;;;;;N;;;;; -18ACD;TANGUT COMPONENT-718;Lo;0;L;;;;;N;;;;; -18ACE;TANGUT COMPONENT-719;Lo;0;L;;;;;N;;;;; -18ACF;TANGUT COMPONENT-720;Lo;0;L;;;;;N;;;;; -18AD0;TANGUT COMPONENT-721;Lo;0;L;;;;;N;;;;; -18AD1;TANGUT COMPONENT-722;Lo;0;L;;;;;N;;;;; -18AD2;TANGUT COMPONENT-723;Lo;0;L;;;;;N;;;;; -18AD3;TANGUT COMPONENT-724;Lo;0;L;;;;;N;;;;; -18AD4;TANGUT COMPONENT-725;Lo;0;L;;;;;N;;;;; -18AD5;TANGUT COMPONENT-726;Lo;0;L;;;;;N;;;;; -18AD6;TANGUT COMPONENT-727;Lo;0;L;;;;;N;;;;; -18AD7;TANGUT COMPONENT-728;Lo;0;L;;;;;N;;;;; -18AD8;TANGUT COMPONENT-729;Lo;0;L;;;;;N;;;;; -18AD9;TANGUT COMPONENT-730;Lo;0;L;;;;;N;;;;; -18ADA;TANGUT COMPONENT-731;Lo;0;L;;;;;N;;;;; -18ADB;TANGUT COMPONENT-732;Lo;0;L;;;;;N;;;;; -18ADC;TANGUT COMPONENT-733;Lo;0;L;;;;;N;;;;; -18ADD;TANGUT COMPONENT-734;Lo;0;L;;;;;N;;;;; -18ADE;TANGUT COMPONENT-735;Lo;0;L;;;;;N;;;;; -18ADF;TANGUT COMPONENT-736;Lo;0;L;;;;;N;;;;; -18AE0;TANGUT COMPONENT-737;Lo;0;L;;;;;N;;;;; -18AE1;TANGUT COMPONENT-738;Lo;0;L;;;;;N;;;;; -18AE2;TANGUT COMPONENT-739;Lo;0;L;;;;;N;;;;; -18AE3;TANGUT COMPONENT-740;Lo;0;L;;;;;N;;;;; -18AE4;TANGUT COMPONENT-741;Lo;0;L;;;;;N;;;;; -18AE5;TANGUT COMPONENT-742;Lo;0;L;;;;;N;;;;; -18AE6;TANGUT COMPONENT-743;Lo;0;L;;;;;N;;;;; -18AE7;TANGUT COMPONENT-744;Lo;0;L;;;;;N;;;;; -18AE8;TANGUT COMPONENT-745;Lo;0;L;;;;;N;;;;; -18AE9;TANGUT COMPONENT-746;Lo;0;L;;;;;N;;;;; -18AEA;TANGUT COMPONENT-747;Lo;0;L;;;;;N;;;;; -18AEB;TANGUT COMPONENT-748;Lo;0;L;;;;;N;;;;; -18AEC;TANGUT COMPONENT-749;Lo;0;L;;;;;N;;;;; -18AED;TANGUT COMPONENT-750;Lo;0;L;;;;;N;;;;; -18AEE;TANGUT COMPONENT-751;Lo;0;L;;;;;N;;;;; -18AEF;TANGUT COMPONENT-752;Lo;0;L;;;;;N;;;;; -18AF0;TANGUT COMPONENT-753;Lo;0;L;;;;;N;;;;; -18AF1;TANGUT COMPONENT-754;Lo;0;L;;;;;N;;;;; -18AF2;TANGUT COMPONENT-755;Lo;0;L;;;;;N;;;;; -18AF3;TANGUT COMPONENT-756;Lo;0;L;;;;;N;;;;; -18AF4;TANGUT COMPONENT-757;Lo;0;L;;;;;N;;;;; -18AF5;TANGUT COMPONENT-758;Lo;0;L;;;;;N;;;;; -18AF6;TANGUT COMPONENT-759;Lo;0;L;;;;;N;;;;; -18AF7;TANGUT COMPONENT-760;Lo;0;L;;;;;N;;;;; -18AF8;TANGUT COMPONENT-761;Lo;0;L;;;;;N;;;;; -18AF9;TANGUT COMPONENT-762;Lo;0;L;;;;;N;;;;; -18AFA;TANGUT COMPONENT-763;Lo;0;L;;;;;N;;;;; -18AFB;TANGUT COMPONENT-764;Lo;0;L;;;;;N;;;;; -18AFC;TANGUT COMPONENT-765;Lo;0;L;;;;;N;;;;; -18AFD;TANGUT COMPONENT-766;Lo;0;L;;;;;N;;;;; -18AFE;TANGUT COMPONENT-767;Lo;0;L;;;;;N;;;;; -18AFF;TANGUT COMPONENT-768;Lo;0;L;;;;;N;;;;; -18B00;KHITAN SMALL SCRIPT CHARACTER-18B00;Lo;0;L;;;;;N;;;;; -18B01;KHITAN SMALL SCRIPT CHARACTER-18B01;Lo;0;L;;;;;N;;;;; -18B02;KHITAN SMALL SCRIPT CHARACTER-18B02;Lo;0;L;;;;;N;;;;; -18B03;KHITAN SMALL SCRIPT CHARACTER-18B03;Lo;0;L;;;;;N;;;;; -18B04;KHITAN SMALL SCRIPT CHARACTER-18B04;Lo;0;L;;;;;N;;;;; -18B05;KHITAN SMALL SCRIPT CHARACTER-18B05;Lo;0;L;;;;;N;;;;; -18B06;KHITAN SMALL SCRIPT CHARACTER-18B06;Lo;0;L;;;;;N;;;;; -18B07;KHITAN SMALL SCRIPT CHARACTER-18B07;Lo;0;L;;;;;N;;;;; -18B08;KHITAN SMALL SCRIPT CHARACTER-18B08;Lo;0;L;;;;;N;;;;; -18B09;KHITAN SMALL SCRIPT CHARACTER-18B09;Lo;0;L;;;;;N;;;;; -18B0A;KHITAN SMALL SCRIPT CHARACTER-18B0A;Lo;0;L;;;;;N;;;;; -18B0B;KHITAN SMALL SCRIPT CHARACTER-18B0B;Lo;0;L;;;;;N;;;;; -18B0C;KHITAN SMALL SCRIPT CHARACTER-18B0C;Lo;0;L;;;;;N;;;;; -18B0D;KHITAN SMALL SCRIPT CHARACTER-18B0D;Lo;0;L;;;;;N;;;;; -18B0E;KHITAN SMALL SCRIPT CHARACTER-18B0E;Lo;0;L;;;;;N;;;;; -18B0F;KHITAN SMALL SCRIPT CHARACTER-18B0F;Lo;0;L;;;;;N;;;;; -18B10;KHITAN SMALL SCRIPT CHARACTER-18B10;Lo;0;L;;;;;N;;;;; -18B11;KHITAN SMALL SCRIPT CHARACTER-18B11;Lo;0;L;;;;;N;;;;; -18B12;KHITAN SMALL SCRIPT CHARACTER-18B12;Lo;0;L;;;;;N;;;;; -18B13;KHITAN SMALL SCRIPT CHARACTER-18B13;Lo;0;L;;;;;N;;;;; -18B14;KHITAN SMALL SCRIPT CHARACTER-18B14;Lo;0;L;;;;;N;;;;; -18B15;KHITAN SMALL SCRIPT CHARACTER-18B15;Lo;0;L;;;;;N;;;;; -18B16;KHITAN SMALL SCRIPT CHARACTER-18B16;Lo;0;L;;;;;N;;;;; -18B17;KHITAN SMALL SCRIPT CHARACTER-18B17;Lo;0;L;;;;;N;;;;; -18B18;KHITAN SMALL SCRIPT CHARACTER-18B18;Lo;0;L;;;;;N;;;;; -18B19;KHITAN SMALL SCRIPT CHARACTER-18B19;Lo;0;L;;;;;N;;;;; -18B1A;KHITAN SMALL SCRIPT CHARACTER-18B1A;Lo;0;L;;;;;N;;;;; -18B1B;KHITAN SMALL SCRIPT CHARACTER-18B1B;Lo;0;L;;;;;N;;;;; -18B1C;KHITAN SMALL SCRIPT CHARACTER-18B1C;Lo;0;L;;;;;N;;;;; -18B1D;KHITAN SMALL SCRIPT CHARACTER-18B1D;Lo;0;L;;;;;N;;;;; -18B1E;KHITAN SMALL SCRIPT CHARACTER-18B1E;Lo;0;L;;;;;N;;;;; -18B1F;KHITAN SMALL SCRIPT CHARACTER-18B1F;Lo;0;L;;;;;N;;;;; -18B20;KHITAN SMALL SCRIPT CHARACTER-18B20;Lo;0;L;;;;;N;;;;; -18B21;KHITAN SMALL SCRIPT CHARACTER-18B21;Lo;0;L;;;;;N;;;;; -18B22;KHITAN SMALL SCRIPT CHARACTER-18B22;Lo;0;L;;;;;N;;;;; -18B23;KHITAN SMALL SCRIPT CHARACTER-18B23;Lo;0;L;;;;;N;;;;; -18B24;KHITAN SMALL SCRIPT CHARACTER-18B24;Lo;0;L;;;;;N;;;;; -18B25;KHITAN SMALL SCRIPT CHARACTER-18B25;Lo;0;L;;;;;N;;;;; -18B26;KHITAN SMALL SCRIPT CHARACTER-18B26;Lo;0;L;;;;;N;;;;; -18B27;KHITAN SMALL SCRIPT CHARACTER-18B27;Lo;0;L;;;;;N;;;;; -18B28;KHITAN SMALL SCRIPT CHARACTER-18B28;Lo;0;L;;;;;N;;;;; -18B29;KHITAN SMALL SCRIPT CHARACTER-18B29;Lo;0;L;;;;;N;;;;; -18B2A;KHITAN SMALL SCRIPT CHARACTER-18B2A;Lo;0;L;;;;;N;;;;; -18B2B;KHITAN SMALL SCRIPT CHARACTER-18B2B;Lo;0;L;;;;;N;;;;; -18B2C;KHITAN SMALL SCRIPT CHARACTER-18B2C;Lo;0;L;;;;;N;;;;; -18B2D;KHITAN SMALL SCRIPT CHARACTER-18B2D;Lo;0;L;;;;;N;;;;; -18B2E;KHITAN SMALL SCRIPT CHARACTER-18B2E;Lo;0;L;;;;;N;;;;; -18B2F;KHITAN SMALL SCRIPT CHARACTER-18B2F;Lo;0;L;;;;;N;;;;; -18B30;KHITAN SMALL SCRIPT CHARACTER-18B30;Lo;0;L;;;;;N;;;;; -18B31;KHITAN SMALL SCRIPT CHARACTER-18B31;Lo;0;L;;;;;N;;;;; -18B32;KHITAN SMALL SCRIPT CHARACTER-18B32;Lo;0;L;;;;;N;;;;; -18B33;KHITAN SMALL SCRIPT CHARACTER-18B33;Lo;0;L;;;;;N;;;;; -18B34;KHITAN SMALL SCRIPT CHARACTER-18B34;Lo;0;L;;;;;N;;;;; -18B35;KHITAN SMALL SCRIPT CHARACTER-18B35;Lo;0;L;;;;;N;;;;; -18B36;KHITAN SMALL SCRIPT CHARACTER-18B36;Lo;0;L;;;;;N;;;;; -18B37;KHITAN SMALL SCRIPT CHARACTER-18B37;Lo;0;L;;;;;N;;;;; -18B38;KHITAN SMALL SCRIPT CHARACTER-18B38;Lo;0;L;;;;;N;;;;; -18B39;KHITAN SMALL SCRIPT CHARACTER-18B39;Lo;0;L;;;;;N;;;;; -18B3A;KHITAN SMALL SCRIPT CHARACTER-18B3A;Lo;0;L;;;;;N;;;;; -18B3B;KHITAN SMALL SCRIPT CHARACTER-18B3B;Lo;0;L;;;;;N;;;;; -18B3C;KHITAN SMALL SCRIPT CHARACTER-18B3C;Lo;0;L;;;;;N;;;;; -18B3D;KHITAN SMALL SCRIPT CHARACTER-18B3D;Lo;0;L;;;;;N;;;;; -18B3E;KHITAN SMALL SCRIPT CHARACTER-18B3E;Lo;0;L;;;;;N;;;;; -18B3F;KHITAN SMALL SCRIPT CHARACTER-18B3F;Lo;0;L;;;;;N;;;;; -18B40;KHITAN SMALL SCRIPT CHARACTER-18B40;Lo;0;L;;;;;N;;;;; -18B41;KHITAN SMALL SCRIPT CHARACTER-18B41;Lo;0;L;;;;;N;;;;; -18B42;KHITAN SMALL SCRIPT CHARACTER-18B42;Lo;0;L;;;;;N;;;;; -18B43;KHITAN SMALL SCRIPT CHARACTER-18B43;Lo;0;L;;;;;N;;;;; -18B44;KHITAN SMALL SCRIPT CHARACTER-18B44;Lo;0;L;;;;;N;;;;; -18B45;KHITAN SMALL SCRIPT CHARACTER-18B45;Lo;0;L;;;;;N;;;;; -18B46;KHITAN SMALL SCRIPT CHARACTER-18B46;Lo;0;L;;;;;N;;;;; -18B47;KHITAN SMALL SCRIPT CHARACTER-18B47;Lo;0;L;;;;;N;;;;; -18B48;KHITAN SMALL SCRIPT CHARACTER-18B48;Lo;0;L;;;;;N;;;;; -18B49;KHITAN SMALL SCRIPT CHARACTER-18B49;Lo;0;L;;;;;N;;;;; -18B4A;KHITAN SMALL SCRIPT CHARACTER-18B4A;Lo;0;L;;;;;N;;;;; -18B4B;KHITAN SMALL SCRIPT CHARACTER-18B4B;Lo;0;L;;;;;N;;;;; -18B4C;KHITAN SMALL SCRIPT CHARACTER-18B4C;Lo;0;L;;;;;N;;;;; -18B4D;KHITAN SMALL SCRIPT CHARACTER-18B4D;Lo;0;L;;;;;N;;;;; -18B4E;KHITAN SMALL SCRIPT CHARACTER-18B4E;Lo;0;L;;;;;N;;;;; -18B4F;KHITAN SMALL SCRIPT CHARACTER-18B4F;Lo;0;L;;;;;N;;;;; -18B50;KHITAN SMALL SCRIPT CHARACTER-18B50;Lo;0;L;;;;;N;;;;; -18B51;KHITAN SMALL SCRIPT CHARACTER-18B51;Lo;0;L;;;;;N;;;;; -18B52;KHITAN SMALL SCRIPT CHARACTER-18B52;Lo;0;L;;;;;N;;;;; -18B53;KHITAN SMALL SCRIPT CHARACTER-18B53;Lo;0;L;;;;;N;;;;; -18B54;KHITAN SMALL SCRIPT CHARACTER-18B54;Lo;0;L;;;;;N;;;;; -18B55;KHITAN SMALL SCRIPT CHARACTER-18B55;Lo;0;L;;;;;N;;;;; -18B56;KHITAN SMALL SCRIPT CHARACTER-18B56;Lo;0;L;;;;;N;;;;; -18B57;KHITAN SMALL SCRIPT CHARACTER-18B57;Lo;0;L;;;;;N;;;;; -18B58;KHITAN SMALL SCRIPT CHARACTER-18B58;Lo;0;L;;;;;N;;;;; -18B59;KHITAN SMALL SCRIPT CHARACTER-18B59;Lo;0;L;;;;;N;;;;; -18B5A;KHITAN SMALL SCRIPT CHARACTER-18B5A;Lo;0;L;;;;;N;;;;; -18B5B;KHITAN SMALL SCRIPT CHARACTER-18B5B;Lo;0;L;;;;;N;;;;; -18B5C;KHITAN SMALL SCRIPT CHARACTER-18B5C;Lo;0;L;;;;;N;;;;; -18B5D;KHITAN SMALL SCRIPT CHARACTER-18B5D;Lo;0;L;;;;;N;;;;; -18B5E;KHITAN SMALL SCRIPT CHARACTER-18B5E;Lo;0;L;;;;;N;;;;; -18B5F;KHITAN SMALL SCRIPT CHARACTER-18B5F;Lo;0;L;;;;;N;;;;; -18B60;KHITAN SMALL SCRIPT CHARACTER-18B60;Lo;0;L;;;;;N;;;;; -18B61;KHITAN SMALL SCRIPT CHARACTER-18B61;Lo;0;L;;;;;N;;;;; -18B62;KHITAN SMALL SCRIPT CHARACTER-18B62;Lo;0;L;;;;;N;;;;; -18B63;KHITAN SMALL SCRIPT CHARACTER-18B63;Lo;0;L;;;;;N;;;;; -18B64;KHITAN SMALL SCRIPT CHARACTER-18B64;Lo;0;L;;;;;N;;;;; -18B65;KHITAN SMALL SCRIPT CHARACTER-18B65;Lo;0;L;;;;;N;;;;; -18B66;KHITAN SMALL SCRIPT CHARACTER-18B66;Lo;0;L;;;;;N;;;;; -18B67;KHITAN SMALL SCRIPT CHARACTER-18B67;Lo;0;L;;;;;N;;;;; -18B68;KHITAN SMALL SCRIPT CHARACTER-18B68;Lo;0;L;;;;;N;;;;; -18B69;KHITAN SMALL SCRIPT CHARACTER-18B69;Lo;0;L;;;;;N;;;;; -18B6A;KHITAN SMALL SCRIPT CHARACTER-18B6A;Lo;0;L;;;;;N;;;;; -18B6B;KHITAN SMALL SCRIPT CHARACTER-18B6B;Lo;0;L;;;;;N;;;;; -18B6C;KHITAN SMALL SCRIPT CHARACTER-18B6C;Lo;0;L;;;;;N;;;;; -18B6D;KHITAN SMALL SCRIPT CHARACTER-18B6D;Lo;0;L;;;;;N;;;;; -18B6E;KHITAN SMALL SCRIPT CHARACTER-18B6E;Lo;0;L;;;;;N;;;;; -18B6F;KHITAN SMALL SCRIPT CHARACTER-18B6F;Lo;0;L;;;;;N;;;;; -18B70;KHITAN SMALL SCRIPT CHARACTER-18B70;Lo;0;L;;;;;N;;;;; -18B71;KHITAN SMALL SCRIPT CHARACTER-18B71;Lo;0;L;;;;;N;;;;; -18B72;KHITAN SMALL SCRIPT CHARACTER-18B72;Lo;0;L;;;;;N;;;;; -18B73;KHITAN SMALL SCRIPT CHARACTER-18B73;Lo;0;L;;;;;N;;;;; -18B74;KHITAN SMALL SCRIPT CHARACTER-18B74;Lo;0;L;;;;;N;;;;; -18B75;KHITAN SMALL SCRIPT CHARACTER-18B75;Lo;0;L;;;;;N;;;;; -18B76;KHITAN SMALL SCRIPT CHARACTER-18B76;Lo;0;L;;;;;N;;;;; -18B77;KHITAN SMALL SCRIPT CHARACTER-18B77;Lo;0;L;;;;;N;;;;; -18B78;KHITAN SMALL SCRIPT CHARACTER-18B78;Lo;0;L;;;;;N;;;;; -18B79;KHITAN SMALL SCRIPT CHARACTER-18B79;Lo;0;L;;;;;N;;;;; -18B7A;KHITAN SMALL SCRIPT CHARACTER-18B7A;Lo;0;L;;;;;N;;;;; -18B7B;KHITAN SMALL SCRIPT CHARACTER-18B7B;Lo;0;L;;;;;N;;;;; -18B7C;KHITAN SMALL SCRIPT CHARACTER-18B7C;Lo;0;L;;;;;N;;;;; -18B7D;KHITAN SMALL SCRIPT CHARACTER-18B7D;Lo;0;L;;;;;N;;;;; -18B7E;KHITAN SMALL SCRIPT CHARACTER-18B7E;Lo;0;L;;;;;N;;;;; -18B7F;KHITAN SMALL SCRIPT CHARACTER-18B7F;Lo;0;L;;;;;N;;;;; -18B80;KHITAN SMALL SCRIPT CHARACTER-18B80;Lo;0;L;;;;;N;;;;; -18B81;KHITAN SMALL SCRIPT CHARACTER-18B81;Lo;0;L;;;;;N;;;;; -18B82;KHITAN SMALL SCRIPT CHARACTER-18B82;Lo;0;L;;;;;N;;;;; -18B83;KHITAN SMALL SCRIPT CHARACTER-18B83;Lo;0;L;;;;;N;;;;; -18B84;KHITAN SMALL SCRIPT CHARACTER-18B84;Lo;0;L;;;;;N;;;;; -18B85;KHITAN SMALL SCRIPT CHARACTER-18B85;Lo;0;L;;;;;N;;;;; -18B86;KHITAN SMALL SCRIPT CHARACTER-18B86;Lo;0;L;;;;;N;;;;; -18B87;KHITAN SMALL SCRIPT CHARACTER-18B87;Lo;0;L;;;;;N;;;;; -18B88;KHITAN SMALL SCRIPT CHARACTER-18B88;Lo;0;L;;;;;N;;;;; -18B89;KHITAN SMALL SCRIPT CHARACTER-18B89;Lo;0;L;;;;;N;;;;; -18B8A;KHITAN SMALL SCRIPT CHARACTER-18B8A;Lo;0;L;;;;;N;;;;; -18B8B;KHITAN SMALL SCRIPT CHARACTER-18B8B;Lo;0;L;;;;;N;;;;; -18B8C;KHITAN SMALL SCRIPT CHARACTER-18B8C;Lo;0;L;;;;;N;;;;; -18B8D;KHITAN SMALL SCRIPT CHARACTER-18B8D;Lo;0;L;;;;;N;;;;; -18B8E;KHITAN SMALL SCRIPT CHARACTER-18B8E;Lo;0;L;;;;;N;;;;; -18B8F;KHITAN SMALL SCRIPT CHARACTER-18B8F;Lo;0;L;;;;;N;;;;; -18B90;KHITAN SMALL SCRIPT CHARACTER-18B90;Lo;0;L;;;;;N;;;;; -18B91;KHITAN SMALL SCRIPT CHARACTER-18B91;Lo;0;L;;;;;N;;;;; -18B92;KHITAN SMALL SCRIPT CHARACTER-18B92;Lo;0;L;;;;;N;;;;; -18B93;KHITAN SMALL SCRIPT CHARACTER-18B93;Lo;0;L;;;;;N;;;;; -18B94;KHITAN SMALL SCRIPT CHARACTER-18B94;Lo;0;L;;;;;N;;;;; -18B95;KHITAN SMALL SCRIPT CHARACTER-18B95;Lo;0;L;;;;;N;;;;; -18B96;KHITAN SMALL SCRIPT CHARACTER-18B96;Lo;0;L;;;;;N;;;;; -18B97;KHITAN SMALL SCRIPT CHARACTER-18B97;Lo;0;L;;;;;N;;;;; -18B98;KHITAN SMALL SCRIPT CHARACTER-18B98;Lo;0;L;;;;;N;;;;; -18B99;KHITAN SMALL SCRIPT CHARACTER-18B99;Lo;0;L;;;;;N;;;;; -18B9A;KHITAN SMALL SCRIPT CHARACTER-18B9A;Lo;0;L;;;;;N;;;;; -18B9B;KHITAN SMALL SCRIPT CHARACTER-18B9B;Lo;0;L;;;;;N;;;;; -18B9C;KHITAN SMALL SCRIPT CHARACTER-18B9C;Lo;0;L;;;;;N;;;;; -18B9D;KHITAN SMALL SCRIPT CHARACTER-18B9D;Lo;0;L;;;;;N;;;;; -18B9E;KHITAN SMALL SCRIPT CHARACTER-18B9E;Lo;0;L;;;;;N;;;;; -18B9F;KHITAN SMALL SCRIPT CHARACTER-18B9F;Lo;0;L;;;;;N;;;;; -18BA0;KHITAN SMALL SCRIPT CHARACTER-18BA0;Lo;0;L;;;;;N;;;;; -18BA1;KHITAN SMALL SCRIPT CHARACTER-18BA1;Lo;0;L;;;;;N;;;;; -18BA2;KHITAN SMALL SCRIPT CHARACTER-18BA2;Lo;0;L;;;;;N;;;;; -18BA3;KHITAN SMALL SCRIPT CHARACTER-18BA3;Lo;0;L;;;;;N;;;;; -18BA4;KHITAN SMALL SCRIPT CHARACTER-18BA4;Lo;0;L;;;;;N;;;;; -18BA5;KHITAN SMALL SCRIPT CHARACTER-18BA5;Lo;0;L;;;;;N;;;;; -18BA6;KHITAN SMALL SCRIPT CHARACTER-18BA6;Lo;0;L;;;;;N;;;;; -18BA7;KHITAN SMALL SCRIPT CHARACTER-18BA7;Lo;0;L;;;;;N;;;;; -18BA8;KHITAN SMALL SCRIPT CHARACTER-18BA8;Lo;0;L;;;;;N;;;;; -18BA9;KHITAN SMALL SCRIPT CHARACTER-18BA9;Lo;0;L;;;;;N;;;;; -18BAA;KHITAN SMALL SCRIPT CHARACTER-18BAA;Lo;0;L;;;;;N;;;;; -18BAB;KHITAN SMALL SCRIPT CHARACTER-18BAB;Lo;0;L;;;;;N;;;;; -18BAC;KHITAN SMALL SCRIPT CHARACTER-18BAC;Lo;0;L;;;;;N;;;;; -18BAD;KHITAN SMALL SCRIPT CHARACTER-18BAD;Lo;0;L;;;;;N;;;;; -18BAE;KHITAN SMALL SCRIPT CHARACTER-18BAE;Lo;0;L;;;;;N;;;;; -18BAF;KHITAN SMALL SCRIPT CHARACTER-18BAF;Lo;0;L;;;;;N;;;;; -18BB0;KHITAN SMALL SCRIPT CHARACTER-18BB0;Lo;0;L;;;;;N;;;;; -18BB1;KHITAN SMALL SCRIPT CHARACTER-18BB1;Lo;0;L;;;;;N;;;;; -18BB2;KHITAN SMALL SCRIPT CHARACTER-18BB2;Lo;0;L;;;;;N;;;;; -18BB3;KHITAN SMALL SCRIPT CHARACTER-18BB3;Lo;0;L;;;;;N;;;;; -18BB4;KHITAN SMALL SCRIPT CHARACTER-18BB4;Lo;0;L;;;;;N;;;;; -18BB5;KHITAN SMALL SCRIPT CHARACTER-18BB5;Lo;0;L;;;;;N;;;;; -18BB6;KHITAN SMALL SCRIPT CHARACTER-18BB6;Lo;0;L;;;;;N;;;;; -18BB7;KHITAN SMALL SCRIPT CHARACTER-18BB7;Lo;0;L;;;;;N;;;;; -18BB8;KHITAN SMALL SCRIPT CHARACTER-18BB8;Lo;0;L;;;;;N;;;;; -18BB9;KHITAN SMALL SCRIPT CHARACTER-18BB9;Lo;0;L;;;;;N;;;;; -18BBA;KHITAN SMALL SCRIPT CHARACTER-18BBA;Lo;0;L;;;;;N;;;;; -18BBB;KHITAN SMALL SCRIPT CHARACTER-18BBB;Lo;0;L;;;;;N;;;;; -18BBC;KHITAN SMALL SCRIPT CHARACTER-18BBC;Lo;0;L;;;;;N;;;;; -18BBD;KHITAN SMALL SCRIPT CHARACTER-18BBD;Lo;0;L;;;;;N;;;;; -18BBE;KHITAN SMALL SCRIPT CHARACTER-18BBE;Lo;0;L;;;;;N;;;;; -18BBF;KHITAN SMALL SCRIPT CHARACTER-18BBF;Lo;0;L;;;;;N;;;;; -18BC0;KHITAN SMALL SCRIPT CHARACTER-18BC0;Lo;0;L;;;;;N;;;;; -18BC1;KHITAN SMALL SCRIPT CHARACTER-18BC1;Lo;0;L;;;;;N;;;;; -18BC2;KHITAN SMALL SCRIPT CHARACTER-18BC2;Lo;0;L;;;;;N;;;;; -18BC3;KHITAN SMALL SCRIPT CHARACTER-18BC3;Lo;0;L;;;;;N;;;;; -18BC4;KHITAN SMALL SCRIPT CHARACTER-18BC4;Lo;0;L;;;;;N;;;;; -18BC5;KHITAN SMALL SCRIPT CHARACTER-18BC5;Lo;0;L;;;;;N;;;;; -18BC6;KHITAN SMALL SCRIPT CHARACTER-18BC6;Lo;0;L;;;;;N;;;;; -18BC7;KHITAN SMALL SCRIPT CHARACTER-18BC7;Lo;0;L;;;;;N;;;;; -18BC8;KHITAN SMALL SCRIPT CHARACTER-18BC8;Lo;0;L;;;;;N;;;;; -18BC9;KHITAN SMALL SCRIPT CHARACTER-18BC9;Lo;0;L;;;;;N;;;;; -18BCA;KHITAN SMALL SCRIPT CHARACTER-18BCA;Lo;0;L;;;;;N;;;;; -18BCB;KHITAN SMALL SCRIPT CHARACTER-18BCB;Lo;0;L;;;;;N;;;;; -18BCC;KHITAN SMALL SCRIPT CHARACTER-18BCC;Lo;0;L;;;;;N;;;;; -18BCD;KHITAN SMALL SCRIPT CHARACTER-18BCD;Lo;0;L;;;;;N;;;;; -18BCE;KHITAN SMALL SCRIPT CHARACTER-18BCE;Lo;0;L;;;;;N;;;;; -18BCF;KHITAN SMALL SCRIPT CHARACTER-18BCF;Lo;0;L;;;;;N;;;;; -18BD0;KHITAN SMALL SCRIPT CHARACTER-18BD0;Lo;0;L;;;;;N;;;;; -18BD1;KHITAN SMALL SCRIPT CHARACTER-18BD1;Lo;0;L;;;;;N;;;;; -18BD2;KHITAN SMALL SCRIPT CHARACTER-18BD2;Lo;0;L;;;;;N;;;;; -18BD3;KHITAN SMALL SCRIPT CHARACTER-18BD3;Lo;0;L;;;;;N;;;;; -18BD4;KHITAN SMALL SCRIPT CHARACTER-18BD4;Lo;0;L;;;;;N;;;;; -18BD5;KHITAN SMALL SCRIPT CHARACTER-18BD5;Lo;0;L;;;;;N;;;;; -18BD6;KHITAN SMALL SCRIPT CHARACTER-18BD6;Lo;0;L;;;;;N;;;;; -18BD7;KHITAN SMALL SCRIPT CHARACTER-18BD7;Lo;0;L;;;;;N;;;;; -18BD8;KHITAN SMALL SCRIPT CHARACTER-18BD8;Lo;0;L;;;;;N;;;;; -18BD9;KHITAN SMALL SCRIPT CHARACTER-18BD9;Lo;0;L;;;;;N;;;;; -18BDA;KHITAN SMALL SCRIPT CHARACTER-18BDA;Lo;0;L;;;;;N;;;;; -18BDB;KHITAN SMALL SCRIPT CHARACTER-18BDB;Lo;0;L;;;;;N;;;;; -18BDC;KHITAN SMALL SCRIPT CHARACTER-18BDC;Lo;0;L;;;;;N;;;;; -18BDD;KHITAN SMALL SCRIPT CHARACTER-18BDD;Lo;0;L;;;;;N;;;;; -18BDE;KHITAN SMALL SCRIPT CHARACTER-18BDE;Lo;0;L;;;;;N;;;;; -18BDF;KHITAN SMALL SCRIPT CHARACTER-18BDF;Lo;0;L;;;;;N;;;;; -18BE0;KHITAN SMALL SCRIPT CHARACTER-18BE0;Lo;0;L;;;;;N;;;;; -18BE1;KHITAN SMALL SCRIPT CHARACTER-18BE1;Lo;0;L;;;;;N;;;;; -18BE2;KHITAN SMALL SCRIPT CHARACTER-18BE2;Lo;0;L;;;;;N;;;;; -18BE3;KHITAN SMALL SCRIPT CHARACTER-18BE3;Lo;0;L;;;;;N;;;;; -18BE4;KHITAN SMALL SCRIPT CHARACTER-18BE4;Lo;0;L;;;;;N;;;;; -18BE5;KHITAN SMALL SCRIPT CHARACTER-18BE5;Lo;0;L;;;;;N;;;;; -18BE6;KHITAN SMALL SCRIPT CHARACTER-18BE6;Lo;0;L;;;;;N;;;;; -18BE7;KHITAN SMALL SCRIPT CHARACTER-18BE7;Lo;0;L;;;;;N;;;;; -18BE8;KHITAN SMALL SCRIPT CHARACTER-18BE8;Lo;0;L;;;;;N;;;;; -18BE9;KHITAN SMALL SCRIPT CHARACTER-18BE9;Lo;0;L;;;;;N;;;;; -18BEA;KHITAN SMALL SCRIPT CHARACTER-18BEA;Lo;0;L;;;;;N;;;;; -18BEB;KHITAN SMALL SCRIPT CHARACTER-18BEB;Lo;0;L;;;;;N;;;;; -18BEC;KHITAN SMALL SCRIPT CHARACTER-18BEC;Lo;0;L;;;;;N;;;;; -18BED;KHITAN SMALL SCRIPT CHARACTER-18BED;Lo;0;L;;;;;N;;;;; -18BEE;KHITAN SMALL SCRIPT CHARACTER-18BEE;Lo;0;L;;;;;N;;;;; -18BEF;KHITAN SMALL SCRIPT CHARACTER-18BEF;Lo;0;L;;;;;N;;;;; -18BF0;KHITAN SMALL SCRIPT CHARACTER-18BF0;Lo;0;L;;;;;N;;;;; -18BF1;KHITAN SMALL SCRIPT CHARACTER-18BF1;Lo;0;L;;;;;N;;;;; -18BF2;KHITAN SMALL SCRIPT CHARACTER-18BF2;Lo;0;L;;;;;N;;;;; -18BF3;KHITAN SMALL SCRIPT CHARACTER-18BF3;Lo;0;L;;;;;N;;;;; -18BF4;KHITAN SMALL SCRIPT CHARACTER-18BF4;Lo;0;L;;;;;N;;;;; -18BF5;KHITAN SMALL SCRIPT CHARACTER-18BF5;Lo;0;L;;;;;N;;;;; -18BF6;KHITAN SMALL SCRIPT CHARACTER-18BF6;Lo;0;L;;;;;N;;;;; -18BF7;KHITAN SMALL SCRIPT CHARACTER-18BF7;Lo;0;L;;;;;N;;;;; -18BF8;KHITAN SMALL SCRIPT CHARACTER-18BF8;Lo;0;L;;;;;N;;;;; -18BF9;KHITAN SMALL SCRIPT CHARACTER-18BF9;Lo;0;L;;;;;N;;;;; -18BFA;KHITAN SMALL SCRIPT CHARACTER-18BFA;Lo;0;L;;;;;N;;;;; -18BFB;KHITAN SMALL SCRIPT CHARACTER-18BFB;Lo;0;L;;;;;N;;;;; -18BFC;KHITAN SMALL SCRIPT CHARACTER-18BFC;Lo;0;L;;;;;N;;;;; -18BFD;KHITAN SMALL SCRIPT CHARACTER-18BFD;Lo;0;L;;;;;N;;;;; -18BFE;KHITAN SMALL SCRIPT CHARACTER-18BFE;Lo;0;L;;;;;N;;;;; -18BFF;KHITAN SMALL SCRIPT CHARACTER-18BFF;Lo;0;L;;;;;N;;;;; -18C00;KHITAN SMALL SCRIPT CHARACTER-18C00;Lo;0;L;;;;;N;;;;; -18C01;KHITAN SMALL SCRIPT CHARACTER-18C01;Lo;0;L;;;;;N;;;;; -18C02;KHITAN SMALL SCRIPT CHARACTER-18C02;Lo;0;L;;;;;N;;;;; -18C03;KHITAN SMALL SCRIPT CHARACTER-18C03;Lo;0;L;;;;;N;;;;; -18C04;KHITAN SMALL SCRIPT CHARACTER-18C04;Lo;0;L;;;;;N;;;;; -18C05;KHITAN SMALL SCRIPT CHARACTER-18C05;Lo;0;L;;;;;N;;;;; -18C06;KHITAN SMALL SCRIPT CHARACTER-18C06;Lo;0;L;;;;;N;;;;; -18C07;KHITAN SMALL SCRIPT CHARACTER-18C07;Lo;0;L;;;;;N;;;;; -18C08;KHITAN SMALL SCRIPT CHARACTER-18C08;Lo;0;L;;;;;N;;;;; -18C09;KHITAN SMALL SCRIPT CHARACTER-18C09;Lo;0;L;;;;;N;;;;; -18C0A;KHITAN SMALL SCRIPT CHARACTER-18C0A;Lo;0;L;;;;;N;;;;; -18C0B;KHITAN SMALL SCRIPT CHARACTER-18C0B;Lo;0;L;;;;;N;;;;; -18C0C;KHITAN SMALL SCRIPT CHARACTER-18C0C;Lo;0;L;;;;;N;;;;; -18C0D;KHITAN SMALL SCRIPT CHARACTER-18C0D;Lo;0;L;;;;;N;;;;; -18C0E;KHITAN SMALL SCRIPT CHARACTER-18C0E;Lo;0;L;;;;;N;;;;; -18C0F;KHITAN SMALL SCRIPT CHARACTER-18C0F;Lo;0;L;;;;;N;;;;; -18C10;KHITAN SMALL SCRIPT CHARACTER-18C10;Lo;0;L;;;;;N;;;;; -18C11;KHITAN SMALL SCRIPT CHARACTER-18C11;Lo;0;L;;;;;N;;;;; -18C12;KHITAN SMALL SCRIPT CHARACTER-18C12;Lo;0;L;;;;;N;;;;; -18C13;KHITAN SMALL SCRIPT CHARACTER-18C13;Lo;0;L;;;;;N;;;;; -18C14;KHITAN SMALL SCRIPT CHARACTER-18C14;Lo;0;L;;;;;N;;;;; -18C15;KHITAN SMALL SCRIPT CHARACTER-18C15;Lo;0;L;;;;;N;;;;; -18C16;KHITAN SMALL SCRIPT CHARACTER-18C16;Lo;0;L;;;;;N;;;;; -18C17;KHITAN SMALL SCRIPT CHARACTER-18C17;Lo;0;L;;;;;N;;;;; -18C18;KHITAN SMALL SCRIPT CHARACTER-18C18;Lo;0;L;;;;;N;;;;; -18C19;KHITAN SMALL SCRIPT CHARACTER-18C19;Lo;0;L;;;;;N;;;;; -18C1A;KHITAN SMALL SCRIPT CHARACTER-18C1A;Lo;0;L;;;;;N;;;;; -18C1B;KHITAN SMALL SCRIPT CHARACTER-18C1B;Lo;0;L;;;;;N;;;;; -18C1C;KHITAN SMALL SCRIPT CHARACTER-18C1C;Lo;0;L;;;;;N;;;;; -18C1D;KHITAN SMALL SCRIPT CHARACTER-18C1D;Lo;0;L;;;;;N;;;;; -18C1E;KHITAN SMALL SCRIPT CHARACTER-18C1E;Lo;0;L;;;;;N;;;;; -18C1F;KHITAN SMALL SCRIPT CHARACTER-18C1F;Lo;0;L;;;;;N;;;;; -18C20;KHITAN SMALL SCRIPT CHARACTER-18C20;Lo;0;L;;;;;N;;;;; -18C21;KHITAN SMALL SCRIPT CHARACTER-18C21;Lo;0;L;;;;;N;;;;; -18C22;KHITAN SMALL SCRIPT CHARACTER-18C22;Lo;0;L;;;;;N;;;;; -18C23;KHITAN SMALL SCRIPT CHARACTER-18C23;Lo;0;L;;;;;N;;;;; -18C24;KHITAN SMALL SCRIPT CHARACTER-18C24;Lo;0;L;;;;;N;;;;; -18C25;KHITAN SMALL SCRIPT CHARACTER-18C25;Lo;0;L;;;;;N;;;;; -18C26;KHITAN SMALL SCRIPT CHARACTER-18C26;Lo;0;L;;;;;N;;;;; -18C27;KHITAN SMALL SCRIPT CHARACTER-18C27;Lo;0;L;;;;;N;;;;; -18C28;KHITAN SMALL SCRIPT CHARACTER-18C28;Lo;0;L;;;;;N;;;;; -18C29;KHITAN SMALL SCRIPT CHARACTER-18C29;Lo;0;L;;;;;N;;;;; -18C2A;KHITAN SMALL SCRIPT CHARACTER-18C2A;Lo;0;L;;;;;N;;;;; -18C2B;KHITAN SMALL SCRIPT CHARACTER-18C2B;Lo;0;L;;;;;N;;;;; -18C2C;KHITAN SMALL SCRIPT CHARACTER-18C2C;Lo;0;L;;;;;N;;;;; -18C2D;KHITAN SMALL SCRIPT CHARACTER-18C2D;Lo;0;L;;;;;N;;;;; -18C2E;KHITAN SMALL SCRIPT CHARACTER-18C2E;Lo;0;L;;;;;N;;;;; -18C2F;KHITAN SMALL SCRIPT CHARACTER-18C2F;Lo;0;L;;;;;N;;;;; -18C30;KHITAN SMALL SCRIPT CHARACTER-18C30;Lo;0;L;;;;;N;;;;; -18C31;KHITAN SMALL SCRIPT CHARACTER-18C31;Lo;0;L;;;;;N;;;;; -18C32;KHITAN SMALL SCRIPT CHARACTER-18C32;Lo;0;L;;;;;N;;;;; -18C33;KHITAN SMALL SCRIPT CHARACTER-18C33;Lo;0;L;;;;;N;;;;; -18C34;KHITAN SMALL SCRIPT CHARACTER-18C34;Lo;0;L;;;;;N;;;;; -18C35;KHITAN SMALL SCRIPT CHARACTER-18C35;Lo;0;L;;;;;N;;;;; -18C36;KHITAN SMALL SCRIPT CHARACTER-18C36;Lo;0;L;;;;;N;;;;; -18C37;KHITAN SMALL SCRIPT CHARACTER-18C37;Lo;0;L;;;;;N;;;;; -18C38;KHITAN SMALL SCRIPT CHARACTER-18C38;Lo;0;L;;;;;N;;;;; -18C39;KHITAN SMALL SCRIPT CHARACTER-18C39;Lo;0;L;;;;;N;;;;; -18C3A;KHITAN SMALL SCRIPT CHARACTER-18C3A;Lo;0;L;;;;;N;;;;; -18C3B;KHITAN SMALL SCRIPT CHARACTER-18C3B;Lo;0;L;;;;;N;;;;; -18C3C;KHITAN SMALL SCRIPT CHARACTER-18C3C;Lo;0;L;;;;;N;;;;; -18C3D;KHITAN SMALL SCRIPT CHARACTER-18C3D;Lo;0;L;;;;;N;;;;; -18C3E;KHITAN SMALL SCRIPT CHARACTER-18C3E;Lo;0;L;;;;;N;;;;; -18C3F;KHITAN SMALL SCRIPT CHARACTER-18C3F;Lo;0;L;;;;;N;;;;; -18C40;KHITAN SMALL SCRIPT CHARACTER-18C40;Lo;0;L;;;;;N;;;;; -18C41;KHITAN SMALL SCRIPT CHARACTER-18C41;Lo;0;L;;;;;N;;;;; -18C42;KHITAN SMALL SCRIPT CHARACTER-18C42;Lo;0;L;;;;;N;;;;; -18C43;KHITAN SMALL SCRIPT CHARACTER-18C43;Lo;0;L;;;;;N;;;;; -18C44;KHITAN SMALL SCRIPT CHARACTER-18C44;Lo;0;L;;;;;N;;;;; -18C45;KHITAN SMALL SCRIPT CHARACTER-18C45;Lo;0;L;;;;;N;;;;; -18C46;KHITAN SMALL SCRIPT CHARACTER-18C46;Lo;0;L;;;;;N;;;;; -18C47;KHITAN SMALL SCRIPT CHARACTER-18C47;Lo;0;L;;;;;N;;;;; -18C48;KHITAN SMALL SCRIPT CHARACTER-18C48;Lo;0;L;;;;;N;;;;; -18C49;KHITAN SMALL SCRIPT CHARACTER-18C49;Lo;0;L;;;;;N;;;;; -18C4A;KHITAN SMALL SCRIPT CHARACTER-18C4A;Lo;0;L;;;;;N;;;;; -18C4B;KHITAN SMALL SCRIPT CHARACTER-18C4B;Lo;0;L;;;;;N;;;;; -18C4C;KHITAN SMALL SCRIPT CHARACTER-18C4C;Lo;0;L;;;;;N;;;;; -18C4D;KHITAN SMALL SCRIPT CHARACTER-18C4D;Lo;0;L;;;;;N;;;;; -18C4E;KHITAN SMALL SCRIPT CHARACTER-18C4E;Lo;0;L;;;;;N;;;;; -18C4F;KHITAN SMALL SCRIPT CHARACTER-18C4F;Lo;0;L;;;;;N;;;;; -18C50;KHITAN SMALL SCRIPT CHARACTER-18C50;Lo;0;L;;;;;N;;;;; -18C51;KHITAN SMALL SCRIPT CHARACTER-18C51;Lo;0;L;;;;;N;;;;; -18C52;KHITAN SMALL SCRIPT CHARACTER-18C52;Lo;0;L;;;;;N;;;;; -18C53;KHITAN SMALL SCRIPT CHARACTER-18C53;Lo;0;L;;;;;N;;;;; -18C54;KHITAN SMALL SCRIPT CHARACTER-18C54;Lo;0;L;;;;;N;;;;; -18C55;KHITAN SMALL SCRIPT CHARACTER-18C55;Lo;0;L;;;;;N;;;;; -18C56;KHITAN SMALL SCRIPT CHARACTER-18C56;Lo;0;L;;;;;N;;;;; -18C57;KHITAN SMALL SCRIPT CHARACTER-18C57;Lo;0;L;;;;;N;;;;; -18C58;KHITAN SMALL SCRIPT CHARACTER-18C58;Lo;0;L;;;;;N;;;;; -18C59;KHITAN SMALL SCRIPT CHARACTER-18C59;Lo;0;L;;;;;N;;;;; -18C5A;KHITAN SMALL SCRIPT CHARACTER-18C5A;Lo;0;L;;;;;N;;;;; -18C5B;KHITAN SMALL SCRIPT CHARACTER-18C5B;Lo;0;L;;;;;N;;;;; -18C5C;KHITAN SMALL SCRIPT CHARACTER-18C5C;Lo;0;L;;;;;N;;;;; -18C5D;KHITAN SMALL SCRIPT CHARACTER-18C5D;Lo;0;L;;;;;N;;;;; -18C5E;KHITAN SMALL SCRIPT CHARACTER-18C5E;Lo;0;L;;;;;N;;;;; -18C5F;KHITAN SMALL SCRIPT CHARACTER-18C5F;Lo;0;L;;;;;N;;;;; -18C60;KHITAN SMALL SCRIPT CHARACTER-18C60;Lo;0;L;;;;;N;;;;; -18C61;KHITAN SMALL SCRIPT CHARACTER-18C61;Lo;0;L;;;;;N;;;;; -18C62;KHITAN SMALL SCRIPT CHARACTER-18C62;Lo;0;L;;;;;N;;;;; -18C63;KHITAN SMALL SCRIPT CHARACTER-18C63;Lo;0;L;;;;;N;;;;; -18C64;KHITAN SMALL SCRIPT CHARACTER-18C64;Lo;0;L;;;;;N;;;;; -18C65;KHITAN SMALL SCRIPT CHARACTER-18C65;Lo;0;L;;;;;N;;;;; -18C66;KHITAN SMALL SCRIPT CHARACTER-18C66;Lo;0;L;;;;;N;;;;; -18C67;KHITAN SMALL SCRIPT CHARACTER-18C67;Lo;0;L;;;;;N;;;;; -18C68;KHITAN SMALL SCRIPT CHARACTER-18C68;Lo;0;L;;;;;N;;;;; -18C69;KHITAN SMALL SCRIPT CHARACTER-18C69;Lo;0;L;;;;;N;;;;; -18C6A;KHITAN SMALL SCRIPT CHARACTER-18C6A;Lo;0;L;;;;;N;;;;; -18C6B;KHITAN SMALL SCRIPT CHARACTER-18C6B;Lo;0;L;;;;;N;;;;; -18C6C;KHITAN SMALL SCRIPT CHARACTER-18C6C;Lo;0;L;;;;;N;;;;; -18C6D;KHITAN SMALL SCRIPT CHARACTER-18C6D;Lo;0;L;;;;;N;;;;; -18C6E;KHITAN SMALL SCRIPT CHARACTER-18C6E;Lo;0;L;;;;;N;;;;; -18C6F;KHITAN SMALL SCRIPT CHARACTER-18C6F;Lo;0;L;;;;;N;;;;; -18C70;KHITAN SMALL SCRIPT CHARACTER-18C70;Lo;0;L;;;;;N;;;;; -18C71;KHITAN SMALL SCRIPT CHARACTER-18C71;Lo;0;L;;;;;N;;;;; -18C72;KHITAN SMALL SCRIPT CHARACTER-18C72;Lo;0;L;;;;;N;;;;; -18C73;KHITAN SMALL SCRIPT CHARACTER-18C73;Lo;0;L;;;;;N;;;;; -18C74;KHITAN SMALL SCRIPT CHARACTER-18C74;Lo;0;L;;;;;N;;;;; -18C75;KHITAN SMALL SCRIPT CHARACTER-18C75;Lo;0;L;;;;;N;;;;; -18C76;KHITAN SMALL SCRIPT CHARACTER-18C76;Lo;0;L;;;;;N;;;;; -18C77;KHITAN SMALL SCRIPT CHARACTER-18C77;Lo;0;L;;;;;N;;;;; -18C78;KHITAN SMALL SCRIPT CHARACTER-18C78;Lo;0;L;;;;;N;;;;; -18C79;KHITAN SMALL SCRIPT CHARACTER-18C79;Lo;0;L;;;;;N;;;;; -18C7A;KHITAN SMALL SCRIPT CHARACTER-18C7A;Lo;0;L;;;;;N;;;;; -18C7B;KHITAN SMALL SCRIPT CHARACTER-18C7B;Lo;0;L;;;;;N;;;;; -18C7C;KHITAN SMALL SCRIPT CHARACTER-18C7C;Lo;0;L;;;;;N;;;;; -18C7D;KHITAN SMALL SCRIPT CHARACTER-18C7D;Lo;0;L;;;;;N;;;;; -18C7E;KHITAN SMALL SCRIPT CHARACTER-18C7E;Lo;0;L;;;;;N;;;;; -18C7F;KHITAN SMALL SCRIPT CHARACTER-18C7F;Lo;0;L;;;;;N;;;;; -18C80;KHITAN SMALL SCRIPT CHARACTER-18C80;Lo;0;L;;;;;N;;;;; -18C81;KHITAN SMALL SCRIPT CHARACTER-18C81;Lo;0;L;;;;;N;;;;; -18C82;KHITAN SMALL SCRIPT CHARACTER-18C82;Lo;0;L;;;;;N;;;;; -18C83;KHITAN SMALL SCRIPT CHARACTER-18C83;Lo;0;L;;;;;N;;;;; -18C84;KHITAN SMALL SCRIPT CHARACTER-18C84;Lo;0;L;;;;;N;;;;; -18C85;KHITAN SMALL SCRIPT CHARACTER-18C85;Lo;0;L;;;;;N;;;;; -18C86;KHITAN SMALL SCRIPT CHARACTER-18C86;Lo;0;L;;;;;N;;;;; -18C87;KHITAN SMALL SCRIPT CHARACTER-18C87;Lo;0;L;;;;;N;;;;; -18C88;KHITAN SMALL SCRIPT CHARACTER-18C88;Lo;0;L;;;;;N;;;;; -18C89;KHITAN SMALL SCRIPT CHARACTER-18C89;Lo;0;L;;;;;N;;;;; -18C8A;KHITAN SMALL SCRIPT CHARACTER-18C8A;Lo;0;L;;;;;N;;;;; -18C8B;KHITAN SMALL SCRIPT CHARACTER-18C8B;Lo;0;L;;;;;N;;;;; -18C8C;KHITAN SMALL SCRIPT CHARACTER-18C8C;Lo;0;L;;;;;N;;;;; -18C8D;KHITAN SMALL SCRIPT CHARACTER-18C8D;Lo;0;L;;;;;N;;;;; -18C8E;KHITAN SMALL SCRIPT CHARACTER-18C8E;Lo;0;L;;;;;N;;;;; -18C8F;KHITAN SMALL SCRIPT CHARACTER-18C8F;Lo;0;L;;;;;N;;;;; -18C90;KHITAN SMALL SCRIPT CHARACTER-18C90;Lo;0;L;;;;;N;;;;; -18C91;KHITAN SMALL SCRIPT CHARACTER-18C91;Lo;0;L;;;;;N;;;;; -18C92;KHITAN SMALL SCRIPT CHARACTER-18C92;Lo;0;L;;;;;N;;;;; -18C93;KHITAN SMALL SCRIPT CHARACTER-18C93;Lo;0;L;;;;;N;;;;; -18C94;KHITAN SMALL SCRIPT CHARACTER-18C94;Lo;0;L;;;;;N;;;;; -18C95;KHITAN SMALL SCRIPT CHARACTER-18C95;Lo;0;L;;;;;N;;;;; -18C96;KHITAN SMALL SCRIPT CHARACTER-18C96;Lo;0;L;;;;;N;;;;; -18C97;KHITAN SMALL SCRIPT CHARACTER-18C97;Lo;0;L;;;;;N;;;;; -18C98;KHITAN SMALL SCRIPT CHARACTER-18C98;Lo;0;L;;;;;N;;;;; -18C99;KHITAN SMALL SCRIPT CHARACTER-18C99;Lo;0;L;;;;;N;;;;; -18C9A;KHITAN SMALL SCRIPT CHARACTER-18C9A;Lo;0;L;;;;;N;;;;; -18C9B;KHITAN SMALL SCRIPT CHARACTER-18C9B;Lo;0;L;;;;;N;;;;; -18C9C;KHITAN SMALL SCRIPT CHARACTER-18C9C;Lo;0;L;;;;;N;;;;; -18C9D;KHITAN SMALL SCRIPT CHARACTER-18C9D;Lo;0;L;;;;;N;;;;; -18C9E;KHITAN SMALL SCRIPT CHARACTER-18C9E;Lo;0;L;;;;;N;;;;; -18C9F;KHITAN SMALL SCRIPT CHARACTER-18C9F;Lo;0;L;;;;;N;;;;; -18CA0;KHITAN SMALL SCRIPT CHARACTER-18CA0;Lo;0;L;;;;;N;;;;; -18CA1;KHITAN SMALL SCRIPT CHARACTER-18CA1;Lo;0;L;;;;;N;;;;; -18CA2;KHITAN SMALL SCRIPT CHARACTER-18CA2;Lo;0;L;;;;;N;;;;; -18CA3;KHITAN SMALL SCRIPT CHARACTER-18CA3;Lo;0;L;;;;;N;;;;; -18CA4;KHITAN SMALL SCRIPT CHARACTER-18CA4;Lo;0;L;;;;;N;;;;; -18CA5;KHITAN SMALL SCRIPT CHARACTER-18CA5;Lo;0;L;;;;;N;;;;; -18CA6;KHITAN SMALL SCRIPT CHARACTER-18CA6;Lo;0;L;;;;;N;;;;; -18CA7;KHITAN SMALL SCRIPT CHARACTER-18CA7;Lo;0;L;;;;;N;;;;; -18CA8;KHITAN SMALL SCRIPT CHARACTER-18CA8;Lo;0;L;;;;;N;;;;; -18CA9;KHITAN SMALL SCRIPT CHARACTER-18CA9;Lo;0;L;;;;;N;;;;; -18CAA;KHITAN SMALL SCRIPT CHARACTER-18CAA;Lo;0;L;;;;;N;;;;; -18CAB;KHITAN SMALL SCRIPT CHARACTER-18CAB;Lo;0;L;;;;;N;;;;; -18CAC;KHITAN SMALL SCRIPT CHARACTER-18CAC;Lo;0;L;;;;;N;;;;; -18CAD;KHITAN SMALL SCRIPT CHARACTER-18CAD;Lo;0;L;;;;;N;;;;; -18CAE;KHITAN SMALL SCRIPT CHARACTER-18CAE;Lo;0;L;;;;;N;;;;; -18CAF;KHITAN SMALL SCRIPT CHARACTER-18CAF;Lo;0;L;;;;;N;;;;; -18CB0;KHITAN SMALL SCRIPT CHARACTER-18CB0;Lo;0;L;;;;;N;;;;; -18CB1;KHITAN SMALL SCRIPT CHARACTER-18CB1;Lo;0;L;;;;;N;;;;; -18CB2;KHITAN SMALL SCRIPT CHARACTER-18CB2;Lo;0;L;;;;;N;;;;; -18CB3;KHITAN SMALL SCRIPT CHARACTER-18CB3;Lo;0;L;;;;;N;;;;; -18CB4;KHITAN SMALL SCRIPT CHARACTER-18CB4;Lo;0;L;;;;;N;;;;; -18CB5;KHITAN SMALL SCRIPT CHARACTER-18CB5;Lo;0;L;;;;;N;;;;; -18CB6;KHITAN SMALL SCRIPT CHARACTER-18CB6;Lo;0;L;;;;;N;;;;; -18CB7;KHITAN SMALL SCRIPT CHARACTER-18CB7;Lo;0;L;;;;;N;;;;; -18CB8;KHITAN SMALL SCRIPT CHARACTER-18CB8;Lo;0;L;;;;;N;;;;; -18CB9;KHITAN SMALL SCRIPT CHARACTER-18CB9;Lo;0;L;;;;;N;;;;; -18CBA;KHITAN SMALL SCRIPT CHARACTER-18CBA;Lo;0;L;;;;;N;;;;; -18CBB;KHITAN SMALL SCRIPT CHARACTER-18CBB;Lo;0;L;;;;;N;;;;; -18CBC;KHITAN SMALL SCRIPT CHARACTER-18CBC;Lo;0;L;;;;;N;;;;; -18CBD;KHITAN SMALL SCRIPT CHARACTER-18CBD;Lo;0;L;;;;;N;;;;; -18CBE;KHITAN SMALL SCRIPT CHARACTER-18CBE;Lo;0;L;;;;;N;;;;; -18CBF;KHITAN SMALL SCRIPT CHARACTER-18CBF;Lo;0;L;;;;;N;;;;; -18CC0;KHITAN SMALL SCRIPT CHARACTER-18CC0;Lo;0;L;;;;;N;;;;; -18CC1;KHITAN SMALL SCRIPT CHARACTER-18CC1;Lo;0;L;;;;;N;;;;; -18CC2;KHITAN SMALL SCRIPT CHARACTER-18CC2;Lo;0;L;;;;;N;;;;; -18CC3;KHITAN SMALL SCRIPT CHARACTER-18CC3;Lo;0;L;;;;;N;;;;; -18CC4;KHITAN SMALL SCRIPT CHARACTER-18CC4;Lo;0;L;;;;;N;;;;; -18CC5;KHITAN SMALL SCRIPT CHARACTER-18CC5;Lo;0;L;;;;;N;;;;; -18CC6;KHITAN SMALL SCRIPT CHARACTER-18CC6;Lo;0;L;;;;;N;;;;; -18CC7;KHITAN SMALL SCRIPT CHARACTER-18CC7;Lo;0;L;;;;;N;;;;; -18CC8;KHITAN SMALL SCRIPT CHARACTER-18CC8;Lo;0;L;;;;;N;;;;; -18CC9;KHITAN SMALL SCRIPT CHARACTER-18CC9;Lo;0;L;;;;;N;;;;; -18CCA;KHITAN SMALL SCRIPT CHARACTER-18CCA;Lo;0;L;;;;;N;;;;; -18CCB;KHITAN SMALL SCRIPT CHARACTER-18CCB;Lo;0;L;;;;;N;;;;; -18CCC;KHITAN SMALL SCRIPT CHARACTER-18CCC;Lo;0;L;;;;;N;;;;; -18CCD;KHITAN SMALL SCRIPT CHARACTER-18CCD;Lo;0;L;;;;;N;;;;; -18CCE;KHITAN SMALL SCRIPT CHARACTER-18CCE;Lo;0;L;;;;;N;;;;; -18CCF;KHITAN SMALL SCRIPT CHARACTER-18CCF;Lo;0;L;;;;;N;;;;; -18CD0;KHITAN SMALL SCRIPT CHARACTER-18CD0;Lo;0;L;;;;;N;;;;; -18CD1;KHITAN SMALL SCRIPT CHARACTER-18CD1;Lo;0;L;;;;;N;;;;; -18CD2;KHITAN SMALL SCRIPT CHARACTER-18CD2;Lo;0;L;;;;;N;;;;; -18CD3;KHITAN SMALL SCRIPT CHARACTER-18CD3;Lo;0;L;;;;;N;;;;; -18CD4;KHITAN SMALL SCRIPT CHARACTER-18CD4;Lo;0;L;;;;;N;;;;; -18CD5;KHITAN SMALL SCRIPT CHARACTER-18CD5;Lo;0;L;;;;;N;;;;; -18D00;<Tangut Ideograph Supplement, First>;Lo;0;L;;;;;N;;;;; -18D08;<Tangut Ideograph Supplement, Last>;Lo;0;L;;;;;N;;;;; -1AFF0;KATAKANA LETTER MINNAN TONE-2;Lm;0;L;;;;;N;;;;; -1AFF1;KATAKANA LETTER MINNAN TONE-3;Lm;0;L;;;;;N;;;;; -1AFF2;KATAKANA LETTER MINNAN TONE-4;Lm;0;L;;;;;N;;;;; -1AFF3;KATAKANA LETTER MINNAN TONE-5;Lm;0;L;;;;;N;;;;; -1AFF5;KATAKANA LETTER MINNAN TONE-7;Lm;0;L;;;;;N;;;;; -1AFF6;KATAKANA LETTER MINNAN TONE-8;Lm;0;L;;;;;N;;;;; -1AFF7;KATAKANA LETTER MINNAN NASALIZED TONE-1;Lm;0;L;;;;;N;;;;; -1AFF8;KATAKANA LETTER MINNAN NASALIZED TONE-2;Lm;0;L;;;;;N;;;;; -1AFF9;KATAKANA LETTER MINNAN NASALIZED TONE-3;Lm;0;L;;;;;N;;;;; -1AFFA;KATAKANA LETTER MINNAN NASALIZED TONE-4;Lm;0;L;;;;;N;;;;; -1AFFB;KATAKANA LETTER MINNAN NASALIZED TONE-5;Lm;0;L;;;;;N;;;;; -1AFFD;KATAKANA LETTER MINNAN NASALIZED TONE-7;Lm;0;L;;;;;N;;;;; -1AFFE;KATAKANA LETTER MINNAN NASALIZED TONE-8;Lm;0;L;;;;;N;;;;; -1B000;KATAKANA LETTER ARCHAIC E;Lo;0;L;;;;;N;;;;; -1B001;HIRAGANA LETTER ARCHAIC YE;Lo;0;L;;;;;N;;;;; -1B002;HENTAIGANA LETTER A-1;Lo;0;L;;;;;N;;;;; -1B003;HENTAIGANA LETTER A-2;Lo;0;L;;;;;N;;;;; -1B004;HENTAIGANA LETTER A-3;Lo;0;L;;;;;N;;;;; -1B005;HENTAIGANA LETTER A-WO;Lo;0;L;;;;;N;;;;; -1B006;HENTAIGANA LETTER I-1;Lo;0;L;;;;;N;;;;; -1B007;HENTAIGANA LETTER I-2;Lo;0;L;;;;;N;;;;; -1B008;HENTAIGANA LETTER I-3;Lo;0;L;;;;;N;;;;; -1B009;HENTAIGANA LETTER I-4;Lo;0;L;;;;;N;;;;; -1B00A;HENTAIGANA LETTER U-1;Lo;0;L;;;;;N;;;;; -1B00B;HENTAIGANA LETTER U-2;Lo;0;L;;;;;N;;;;; -1B00C;HENTAIGANA LETTER U-3;Lo;0;L;;;;;N;;;;; -1B00D;HENTAIGANA LETTER U-4;Lo;0;L;;;;;N;;;;; -1B00E;HENTAIGANA LETTER U-5;Lo;0;L;;;;;N;;;;; -1B00F;HENTAIGANA LETTER E-2;Lo;0;L;;;;;N;;;;; -1B010;HENTAIGANA LETTER E-3;Lo;0;L;;;;;N;;;;; -1B011;HENTAIGANA LETTER E-4;Lo;0;L;;;;;N;;;;; -1B012;HENTAIGANA LETTER E-5;Lo;0;L;;;;;N;;;;; -1B013;HENTAIGANA LETTER E-6;Lo;0;L;;;;;N;;;;; -1B014;HENTAIGANA LETTER O-1;Lo;0;L;;;;;N;;;;; -1B015;HENTAIGANA LETTER O-2;Lo;0;L;;;;;N;;;;; -1B016;HENTAIGANA LETTER O-3;Lo;0;L;;;;;N;;;;; -1B017;HENTAIGANA LETTER KA-1;Lo;0;L;;;;;N;;;;; -1B018;HENTAIGANA LETTER KA-2;Lo;0;L;;;;;N;;;;; -1B019;HENTAIGANA LETTER KA-3;Lo;0;L;;;;;N;;;;; -1B01A;HENTAIGANA LETTER KA-4;Lo;0;L;;;;;N;;;;; -1B01B;HENTAIGANA LETTER KA-5;Lo;0;L;;;;;N;;;;; -1B01C;HENTAIGANA LETTER KA-6;Lo;0;L;;;;;N;;;;; -1B01D;HENTAIGANA LETTER KA-7;Lo;0;L;;;;;N;;;;; -1B01E;HENTAIGANA LETTER KA-8;Lo;0;L;;;;;N;;;;; -1B01F;HENTAIGANA LETTER KA-9;Lo;0;L;;;;;N;;;;; -1B020;HENTAIGANA LETTER KA-10;Lo;0;L;;;;;N;;;;; -1B021;HENTAIGANA LETTER KA-11;Lo;0;L;;;;;N;;;;; -1B022;HENTAIGANA LETTER KA-KE;Lo;0;L;;;;;N;;;;; -1B023;HENTAIGANA LETTER KI-1;Lo;0;L;;;;;N;;;;; -1B024;HENTAIGANA LETTER KI-2;Lo;0;L;;;;;N;;;;; -1B025;HENTAIGANA LETTER KI-3;Lo;0;L;;;;;N;;;;; -1B026;HENTAIGANA LETTER KI-4;Lo;0;L;;;;;N;;;;; -1B027;HENTAIGANA LETTER KI-5;Lo;0;L;;;;;N;;;;; -1B028;HENTAIGANA LETTER KI-6;Lo;0;L;;;;;N;;;;; -1B029;HENTAIGANA LETTER KI-7;Lo;0;L;;;;;N;;;;; -1B02A;HENTAIGANA LETTER KI-8;Lo;0;L;;;;;N;;;;; -1B02B;HENTAIGANA LETTER KU-1;Lo;0;L;;;;;N;;;;; -1B02C;HENTAIGANA LETTER KU-2;Lo;0;L;;;;;N;;;;; -1B02D;HENTAIGANA LETTER KU-3;Lo;0;L;;;;;N;;;;; -1B02E;HENTAIGANA LETTER KU-4;Lo;0;L;;;;;N;;;;; -1B02F;HENTAIGANA LETTER KU-5;Lo;0;L;;;;;N;;;;; -1B030;HENTAIGANA LETTER KU-6;Lo;0;L;;;;;N;;;;; -1B031;HENTAIGANA LETTER KU-7;Lo;0;L;;;;;N;;;;; -1B032;HENTAIGANA LETTER KE-1;Lo;0;L;;;;;N;;;;; -1B033;HENTAIGANA LETTER KE-2;Lo;0;L;;;;;N;;;;; -1B034;HENTAIGANA LETTER KE-3;Lo;0;L;;;;;N;;;;; -1B035;HENTAIGANA LETTER KE-4;Lo;0;L;;;;;N;;;;; -1B036;HENTAIGANA LETTER KE-5;Lo;0;L;;;;;N;;;;; -1B037;HENTAIGANA LETTER KE-6;Lo;0;L;;;;;N;;;;; -1B038;HENTAIGANA LETTER KO-1;Lo;0;L;;;;;N;;;;; -1B039;HENTAIGANA LETTER KO-2;Lo;0;L;;;;;N;;;;; -1B03A;HENTAIGANA LETTER KO-3;Lo;0;L;;;;;N;;;;; -1B03B;HENTAIGANA LETTER KO-KI;Lo;0;L;;;;;N;;;;; -1B03C;HENTAIGANA LETTER SA-1;Lo;0;L;;;;;N;;;;; -1B03D;HENTAIGANA LETTER SA-2;Lo;0;L;;;;;N;;;;; -1B03E;HENTAIGANA LETTER SA-3;Lo;0;L;;;;;N;;;;; -1B03F;HENTAIGANA LETTER SA-4;Lo;0;L;;;;;N;;;;; -1B040;HENTAIGANA LETTER SA-5;Lo;0;L;;;;;N;;;;; -1B041;HENTAIGANA LETTER SA-6;Lo;0;L;;;;;N;;;;; -1B042;HENTAIGANA LETTER SA-7;Lo;0;L;;;;;N;;;;; -1B043;HENTAIGANA LETTER SA-8;Lo;0;L;;;;;N;;;;; -1B044;HENTAIGANA LETTER SI-1;Lo;0;L;;;;;N;;;;; -1B045;HENTAIGANA LETTER SI-2;Lo;0;L;;;;;N;;;;; -1B046;HENTAIGANA LETTER SI-3;Lo;0;L;;;;;N;;;;; -1B047;HENTAIGANA LETTER SI-4;Lo;0;L;;;;;N;;;;; -1B048;HENTAIGANA LETTER SI-5;Lo;0;L;;;;;N;;;;; -1B049;HENTAIGANA LETTER SI-6;Lo;0;L;;;;;N;;;;; -1B04A;HENTAIGANA LETTER SU-1;Lo;0;L;;;;;N;;;;; -1B04B;HENTAIGANA LETTER SU-2;Lo;0;L;;;;;N;;;;; -1B04C;HENTAIGANA LETTER SU-3;Lo;0;L;;;;;N;;;;; -1B04D;HENTAIGANA LETTER SU-4;Lo;0;L;;;;;N;;;;; -1B04E;HENTAIGANA LETTER SU-5;Lo;0;L;;;;;N;;;;; -1B04F;HENTAIGANA LETTER SU-6;Lo;0;L;;;;;N;;;;; -1B050;HENTAIGANA LETTER SU-7;Lo;0;L;;;;;N;;;;; -1B051;HENTAIGANA LETTER SU-8;Lo;0;L;;;;;N;;;;; -1B052;HENTAIGANA LETTER SE-1;Lo;0;L;;;;;N;;;;; -1B053;HENTAIGANA LETTER SE-2;Lo;0;L;;;;;N;;;;; -1B054;HENTAIGANA LETTER SE-3;Lo;0;L;;;;;N;;;;; -1B055;HENTAIGANA LETTER SE-4;Lo;0;L;;;;;N;;;;; -1B056;HENTAIGANA LETTER SE-5;Lo;0;L;;;;;N;;;;; -1B057;HENTAIGANA LETTER SO-1;Lo;0;L;;;;;N;;;;; -1B058;HENTAIGANA LETTER SO-2;Lo;0;L;;;;;N;;;;; -1B059;HENTAIGANA LETTER SO-3;Lo;0;L;;;;;N;;;;; -1B05A;HENTAIGANA LETTER SO-4;Lo;0;L;;;;;N;;;;; -1B05B;HENTAIGANA LETTER SO-5;Lo;0;L;;;;;N;;;;; -1B05C;HENTAIGANA LETTER SO-6;Lo;0;L;;;;;N;;;;; -1B05D;HENTAIGANA LETTER SO-7;Lo;0;L;;;;;N;;;;; -1B05E;HENTAIGANA LETTER TA-1;Lo;0;L;;;;;N;;;;; -1B05F;HENTAIGANA LETTER TA-2;Lo;0;L;;;;;N;;;;; -1B060;HENTAIGANA LETTER TA-3;Lo;0;L;;;;;N;;;;; -1B061;HENTAIGANA LETTER TA-4;Lo;0;L;;;;;N;;;;; -1B062;HENTAIGANA LETTER TI-1;Lo;0;L;;;;;N;;;;; -1B063;HENTAIGANA LETTER TI-2;Lo;0;L;;;;;N;;;;; -1B064;HENTAIGANA LETTER TI-3;Lo;0;L;;;;;N;;;;; -1B065;HENTAIGANA LETTER TI-4;Lo;0;L;;;;;N;;;;; -1B066;HENTAIGANA LETTER TI-5;Lo;0;L;;;;;N;;;;; -1B067;HENTAIGANA LETTER TI-6;Lo;0;L;;;;;N;;;;; -1B068;HENTAIGANA LETTER TI-7;Lo;0;L;;;;;N;;;;; -1B069;HENTAIGANA LETTER TU-1;Lo;0;L;;;;;N;;;;; -1B06A;HENTAIGANA LETTER TU-2;Lo;0;L;;;;;N;;;;; -1B06B;HENTAIGANA LETTER TU-3;Lo;0;L;;;;;N;;;;; -1B06C;HENTAIGANA LETTER TU-4;Lo;0;L;;;;;N;;;;; -1B06D;HENTAIGANA LETTER TU-TO;Lo;0;L;;;;;N;;;;; -1B06E;HENTAIGANA LETTER TE-1;Lo;0;L;;;;;N;;;;; -1B06F;HENTAIGANA LETTER TE-2;Lo;0;L;;;;;N;;;;; -1B070;HENTAIGANA LETTER TE-3;Lo;0;L;;;;;N;;;;; -1B071;HENTAIGANA LETTER TE-4;Lo;0;L;;;;;N;;;;; -1B072;HENTAIGANA LETTER TE-5;Lo;0;L;;;;;N;;;;; -1B073;HENTAIGANA LETTER TE-6;Lo;0;L;;;;;N;;;;; -1B074;HENTAIGANA LETTER TE-7;Lo;0;L;;;;;N;;;;; -1B075;HENTAIGANA LETTER TE-8;Lo;0;L;;;;;N;;;;; -1B076;HENTAIGANA LETTER TE-9;Lo;0;L;;;;;N;;;;; -1B077;HENTAIGANA LETTER TO-1;Lo;0;L;;;;;N;;;;; -1B078;HENTAIGANA LETTER TO-2;Lo;0;L;;;;;N;;;;; -1B079;HENTAIGANA LETTER TO-3;Lo;0;L;;;;;N;;;;; -1B07A;HENTAIGANA LETTER TO-4;Lo;0;L;;;;;N;;;;; -1B07B;HENTAIGANA LETTER TO-5;Lo;0;L;;;;;N;;;;; -1B07C;HENTAIGANA LETTER TO-6;Lo;0;L;;;;;N;;;;; -1B07D;HENTAIGANA LETTER TO-RA;Lo;0;L;;;;;N;;;;; -1B07E;HENTAIGANA LETTER NA-1;Lo;0;L;;;;;N;;;;; -1B07F;HENTAIGANA LETTER NA-2;Lo;0;L;;;;;N;;;;; -1B080;HENTAIGANA LETTER NA-3;Lo;0;L;;;;;N;;;;; -1B081;HENTAIGANA LETTER NA-4;Lo;0;L;;;;;N;;;;; -1B082;HENTAIGANA LETTER NA-5;Lo;0;L;;;;;N;;;;; -1B083;HENTAIGANA LETTER NA-6;Lo;0;L;;;;;N;;;;; -1B084;HENTAIGANA LETTER NA-7;Lo;0;L;;;;;N;;;;; -1B085;HENTAIGANA LETTER NA-8;Lo;0;L;;;;;N;;;;; -1B086;HENTAIGANA LETTER NA-9;Lo;0;L;;;;;N;;;;; -1B087;HENTAIGANA LETTER NI-1;Lo;0;L;;;;;N;;;;; -1B088;HENTAIGANA LETTER NI-2;Lo;0;L;;;;;N;;;;; -1B089;HENTAIGANA LETTER NI-3;Lo;0;L;;;;;N;;;;; -1B08A;HENTAIGANA LETTER NI-4;Lo;0;L;;;;;N;;;;; -1B08B;HENTAIGANA LETTER NI-5;Lo;0;L;;;;;N;;;;; -1B08C;HENTAIGANA LETTER NI-6;Lo;0;L;;;;;N;;;;; -1B08D;HENTAIGANA LETTER NI-7;Lo;0;L;;;;;N;;;;; -1B08E;HENTAIGANA LETTER NI-TE;Lo;0;L;;;;;N;;;;; -1B08F;HENTAIGANA LETTER NU-1;Lo;0;L;;;;;N;;;;; -1B090;HENTAIGANA LETTER NU-2;Lo;0;L;;;;;N;;;;; -1B091;HENTAIGANA LETTER NU-3;Lo;0;L;;;;;N;;;;; -1B092;HENTAIGANA LETTER NE-1;Lo;0;L;;;;;N;;;;; -1B093;HENTAIGANA LETTER NE-2;Lo;0;L;;;;;N;;;;; -1B094;HENTAIGANA LETTER NE-3;Lo;0;L;;;;;N;;;;; -1B095;HENTAIGANA LETTER NE-4;Lo;0;L;;;;;N;;;;; -1B096;HENTAIGANA LETTER NE-5;Lo;0;L;;;;;N;;;;; -1B097;HENTAIGANA LETTER NE-6;Lo;0;L;;;;;N;;;;; -1B098;HENTAIGANA LETTER NE-KO;Lo;0;L;;;;;N;;;;; -1B099;HENTAIGANA LETTER NO-1;Lo;0;L;;;;;N;;;;; -1B09A;HENTAIGANA LETTER NO-2;Lo;0;L;;;;;N;;;;; -1B09B;HENTAIGANA LETTER NO-3;Lo;0;L;;;;;N;;;;; -1B09C;HENTAIGANA LETTER NO-4;Lo;0;L;;;;;N;;;;; -1B09D;HENTAIGANA LETTER NO-5;Lo;0;L;;;;;N;;;;; -1B09E;HENTAIGANA LETTER HA-1;Lo;0;L;;;;;N;;;;; -1B09F;HENTAIGANA LETTER HA-2;Lo;0;L;;;;;N;;;;; -1B0A0;HENTAIGANA LETTER HA-3;Lo;0;L;;;;;N;;;;; -1B0A1;HENTAIGANA LETTER HA-4;Lo;0;L;;;;;N;;;;; -1B0A2;HENTAIGANA LETTER HA-5;Lo;0;L;;;;;N;;;;; -1B0A3;HENTAIGANA LETTER HA-6;Lo;0;L;;;;;N;;;;; -1B0A4;HENTAIGANA LETTER HA-7;Lo;0;L;;;;;N;;;;; -1B0A5;HENTAIGANA LETTER HA-8;Lo;0;L;;;;;N;;;;; -1B0A6;HENTAIGANA LETTER HA-9;Lo;0;L;;;;;N;;;;; -1B0A7;HENTAIGANA LETTER HA-10;Lo;0;L;;;;;N;;;;; -1B0A8;HENTAIGANA LETTER HA-11;Lo;0;L;;;;;N;;;;; -1B0A9;HENTAIGANA LETTER HI-1;Lo;0;L;;;;;N;;;;; -1B0AA;HENTAIGANA LETTER HI-2;Lo;0;L;;;;;N;;;;; -1B0AB;HENTAIGANA LETTER HI-3;Lo;0;L;;;;;N;;;;; -1B0AC;HENTAIGANA LETTER HI-4;Lo;0;L;;;;;N;;;;; -1B0AD;HENTAIGANA LETTER HI-5;Lo;0;L;;;;;N;;;;; -1B0AE;HENTAIGANA LETTER HI-6;Lo;0;L;;;;;N;;;;; -1B0AF;HENTAIGANA LETTER HI-7;Lo;0;L;;;;;N;;;;; -1B0B0;HENTAIGANA LETTER HU-1;Lo;0;L;;;;;N;;;;; -1B0B1;HENTAIGANA LETTER HU-2;Lo;0;L;;;;;N;;;;; -1B0B2;HENTAIGANA LETTER HU-3;Lo;0;L;;;;;N;;;;; -1B0B3;HENTAIGANA LETTER HE-1;Lo;0;L;;;;;N;;;;; -1B0B4;HENTAIGANA LETTER HE-2;Lo;0;L;;;;;N;;;;; -1B0B5;HENTAIGANA LETTER HE-3;Lo;0;L;;;;;N;;;;; -1B0B6;HENTAIGANA LETTER HE-4;Lo;0;L;;;;;N;;;;; -1B0B7;HENTAIGANA LETTER HE-5;Lo;0;L;;;;;N;;;;; -1B0B8;HENTAIGANA LETTER HE-6;Lo;0;L;;;;;N;;;;; -1B0B9;HENTAIGANA LETTER HE-7;Lo;0;L;;;;;N;;;;; -1B0BA;HENTAIGANA LETTER HO-1;Lo;0;L;;;;;N;;;;; -1B0BB;HENTAIGANA LETTER HO-2;Lo;0;L;;;;;N;;;;; -1B0BC;HENTAIGANA LETTER HO-3;Lo;0;L;;;;;N;;;;; -1B0BD;HENTAIGANA LETTER HO-4;Lo;0;L;;;;;N;;;;; -1B0BE;HENTAIGANA LETTER HO-5;Lo;0;L;;;;;N;;;;; -1B0BF;HENTAIGANA LETTER HO-6;Lo;0;L;;;;;N;;;;; -1B0C0;HENTAIGANA LETTER HO-7;Lo;0;L;;;;;N;;;;; -1B0C1;HENTAIGANA LETTER HO-8;Lo;0;L;;;;;N;;;;; -1B0C2;HENTAIGANA LETTER MA-1;Lo;0;L;;;;;N;;;;; -1B0C3;HENTAIGANA LETTER MA-2;Lo;0;L;;;;;N;;;;; -1B0C4;HENTAIGANA LETTER MA-3;Lo;0;L;;;;;N;;;;; -1B0C5;HENTAIGANA LETTER MA-4;Lo;0;L;;;;;N;;;;; -1B0C6;HENTAIGANA LETTER MA-5;Lo;0;L;;;;;N;;;;; -1B0C7;HENTAIGANA LETTER MA-6;Lo;0;L;;;;;N;;;;; -1B0C8;HENTAIGANA LETTER MA-7;Lo;0;L;;;;;N;;;;; -1B0C9;HENTAIGANA LETTER MI-1;Lo;0;L;;;;;N;;;;; -1B0CA;HENTAIGANA LETTER MI-2;Lo;0;L;;;;;N;;;;; -1B0CB;HENTAIGANA LETTER MI-3;Lo;0;L;;;;;N;;;;; -1B0CC;HENTAIGANA LETTER MI-4;Lo;0;L;;;;;N;;;;; -1B0CD;HENTAIGANA LETTER MI-5;Lo;0;L;;;;;N;;;;; -1B0CE;HENTAIGANA LETTER MI-6;Lo;0;L;;;;;N;;;;; -1B0CF;HENTAIGANA LETTER MI-7;Lo;0;L;;;;;N;;;;; -1B0D0;HENTAIGANA LETTER MU-1;Lo;0;L;;;;;N;;;;; -1B0D1;HENTAIGANA LETTER MU-2;Lo;0;L;;;;;N;;;;; -1B0D2;HENTAIGANA LETTER MU-3;Lo;0;L;;;;;N;;;;; -1B0D3;HENTAIGANA LETTER MU-4;Lo;0;L;;;;;N;;;;; -1B0D4;HENTAIGANA LETTER ME-1;Lo;0;L;;;;;N;;;;; -1B0D5;HENTAIGANA LETTER ME-2;Lo;0;L;;;;;N;;;;; -1B0D6;HENTAIGANA LETTER ME-MA;Lo;0;L;;;;;N;;;;; -1B0D7;HENTAIGANA LETTER MO-1;Lo;0;L;;;;;N;;;;; -1B0D8;HENTAIGANA LETTER MO-2;Lo;0;L;;;;;N;;;;; -1B0D9;HENTAIGANA LETTER MO-3;Lo;0;L;;;;;N;;;;; -1B0DA;HENTAIGANA LETTER MO-4;Lo;0;L;;;;;N;;;;; -1B0DB;HENTAIGANA LETTER MO-5;Lo;0;L;;;;;N;;;;; -1B0DC;HENTAIGANA LETTER MO-6;Lo;0;L;;;;;N;;;;; -1B0DD;HENTAIGANA LETTER YA-1;Lo;0;L;;;;;N;;;;; -1B0DE;HENTAIGANA LETTER YA-2;Lo;0;L;;;;;N;;;;; -1B0DF;HENTAIGANA LETTER YA-3;Lo;0;L;;;;;N;;;;; -1B0E0;HENTAIGANA LETTER YA-4;Lo;0;L;;;;;N;;;;; -1B0E1;HENTAIGANA LETTER YA-5;Lo;0;L;;;;;N;;;;; -1B0E2;HENTAIGANA LETTER YA-YO;Lo;0;L;;;;;N;;;;; -1B0E3;HENTAIGANA LETTER YU-1;Lo;0;L;;;;;N;;;;; -1B0E4;HENTAIGANA LETTER YU-2;Lo;0;L;;;;;N;;;;; -1B0E5;HENTAIGANA LETTER YU-3;Lo;0;L;;;;;N;;;;; -1B0E6;HENTAIGANA LETTER YU-4;Lo;0;L;;;;;N;;;;; -1B0E7;HENTAIGANA LETTER YO-1;Lo;0;L;;;;;N;;;;; -1B0E8;HENTAIGANA LETTER YO-2;Lo;0;L;;;;;N;;;;; -1B0E9;HENTAIGANA LETTER YO-3;Lo;0;L;;;;;N;;;;; -1B0EA;HENTAIGANA LETTER YO-4;Lo;0;L;;;;;N;;;;; -1B0EB;HENTAIGANA LETTER YO-5;Lo;0;L;;;;;N;;;;; -1B0EC;HENTAIGANA LETTER YO-6;Lo;0;L;;;;;N;;;;; -1B0ED;HENTAIGANA LETTER RA-1;Lo;0;L;;;;;N;;;;; -1B0EE;HENTAIGANA LETTER RA-2;Lo;0;L;;;;;N;;;;; -1B0EF;HENTAIGANA LETTER RA-3;Lo;0;L;;;;;N;;;;; -1B0F0;HENTAIGANA LETTER RA-4;Lo;0;L;;;;;N;;;;; -1B0F1;HENTAIGANA LETTER RI-1;Lo;0;L;;;;;N;;;;; -1B0F2;HENTAIGANA LETTER RI-2;Lo;0;L;;;;;N;;;;; -1B0F3;HENTAIGANA LETTER RI-3;Lo;0;L;;;;;N;;;;; -1B0F4;HENTAIGANA LETTER RI-4;Lo;0;L;;;;;N;;;;; -1B0F5;HENTAIGANA LETTER RI-5;Lo;0;L;;;;;N;;;;; -1B0F6;HENTAIGANA LETTER RI-6;Lo;0;L;;;;;N;;;;; -1B0F7;HENTAIGANA LETTER RI-7;Lo;0;L;;;;;N;;;;; -1B0F8;HENTAIGANA LETTER RU-1;Lo;0;L;;;;;N;;;;; -1B0F9;HENTAIGANA LETTER RU-2;Lo;0;L;;;;;N;;;;; -1B0FA;HENTAIGANA LETTER RU-3;Lo;0;L;;;;;N;;;;; -1B0FB;HENTAIGANA LETTER RU-4;Lo;0;L;;;;;N;;;;; -1B0FC;HENTAIGANA LETTER RU-5;Lo;0;L;;;;;N;;;;; -1B0FD;HENTAIGANA LETTER RU-6;Lo;0;L;;;;;N;;;;; -1B0FE;HENTAIGANA LETTER RE-1;Lo;0;L;;;;;N;;;;; -1B0FF;HENTAIGANA LETTER RE-2;Lo;0;L;;;;;N;;;;; -1B100;HENTAIGANA LETTER RE-3;Lo;0;L;;;;;N;;;;; -1B101;HENTAIGANA LETTER RE-4;Lo;0;L;;;;;N;;;;; -1B102;HENTAIGANA LETTER RO-1;Lo;0;L;;;;;N;;;;; -1B103;HENTAIGANA LETTER RO-2;Lo;0;L;;;;;N;;;;; -1B104;HENTAIGANA LETTER RO-3;Lo;0;L;;;;;N;;;;; -1B105;HENTAIGANA LETTER RO-4;Lo;0;L;;;;;N;;;;; -1B106;HENTAIGANA LETTER RO-5;Lo;0;L;;;;;N;;;;; -1B107;HENTAIGANA LETTER RO-6;Lo;0;L;;;;;N;;;;; -1B108;HENTAIGANA LETTER WA-1;Lo;0;L;;;;;N;;;;; -1B109;HENTAIGANA LETTER WA-2;Lo;0;L;;;;;N;;;;; -1B10A;HENTAIGANA LETTER WA-3;Lo;0;L;;;;;N;;;;; -1B10B;HENTAIGANA LETTER WA-4;Lo;0;L;;;;;N;;;;; -1B10C;HENTAIGANA LETTER WA-5;Lo;0;L;;;;;N;;;;; -1B10D;HENTAIGANA LETTER WI-1;Lo;0;L;;;;;N;;;;; -1B10E;HENTAIGANA LETTER WI-2;Lo;0;L;;;;;N;;;;; -1B10F;HENTAIGANA LETTER WI-3;Lo;0;L;;;;;N;;;;; -1B110;HENTAIGANA LETTER WI-4;Lo;0;L;;;;;N;;;;; -1B111;HENTAIGANA LETTER WI-5;Lo;0;L;;;;;N;;;;; -1B112;HENTAIGANA LETTER WE-1;Lo;0;L;;;;;N;;;;; -1B113;HENTAIGANA LETTER WE-2;Lo;0;L;;;;;N;;;;; -1B114;HENTAIGANA LETTER WE-3;Lo;0;L;;;;;N;;;;; -1B115;HENTAIGANA LETTER WE-4;Lo;0;L;;;;;N;;;;; -1B116;HENTAIGANA LETTER WO-1;Lo;0;L;;;;;N;;;;; -1B117;HENTAIGANA LETTER WO-2;Lo;0;L;;;;;N;;;;; -1B118;HENTAIGANA LETTER WO-3;Lo;0;L;;;;;N;;;;; -1B119;HENTAIGANA LETTER WO-4;Lo;0;L;;;;;N;;;;; -1B11A;HENTAIGANA LETTER WO-5;Lo;0;L;;;;;N;;;;; -1B11B;HENTAIGANA LETTER WO-6;Lo;0;L;;;;;N;;;;; -1B11C;HENTAIGANA LETTER WO-7;Lo;0;L;;;;;N;;;;; -1B11D;HENTAIGANA LETTER N-MU-MO-1;Lo;0;L;;;;;N;;;;; -1B11E;HENTAIGANA LETTER N-MU-MO-2;Lo;0;L;;;;;N;;;;; -1B11F;HIRAGANA LETTER ARCHAIC WU;Lo;0;L;;;;;N;;;;; -1B120;KATAKANA LETTER ARCHAIC YI;Lo;0;L;;;;;N;;;;; -1B121;KATAKANA LETTER ARCHAIC YE;Lo;0;L;;;;;N;;;;; -1B122;KATAKANA LETTER ARCHAIC WU;Lo;0;L;;;;;N;;;;; -1B132;HIRAGANA LETTER SMALL KO;Lo;0;L;;;;;N;;;;; -1B150;HIRAGANA LETTER SMALL WI;Lo;0;L;;;;;N;;;;; -1B151;HIRAGANA LETTER SMALL WE;Lo;0;L;;;;;N;;;;; -1B152;HIRAGANA LETTER SMALL WO;Lo;0;L;;;;;N;;;;; -1B155;KATAKANA LETTER SMALL KO;Lo;0;L;;;;;N;;;;; -1B164;KATAKANA LETTER SMALL WI;Lo;0;L;;;;;N;;;;; -1B165;KATAKANA LETTER SMALL WE;Lo;0;L;;;;;N;;;;; -1B166;KATAKANA LETTER SMALL WO;Lo;0;L;;;;;N;;;;; -1B167;KATAKANA LETTER SMALL N;Lo;0;L;;;;;N;;;;; -1B170;NUSHU CHARACTER-1B170;Lo;0;L;;;;;N;;;;; -1B171;NUSHU CHARACTER-1B171;Lo;0;L;;;;;N;;;;; -1B172;NUSHU CHARACTER-1B172;Lo;0;L;;;;;N;;;;; -1B173;NUSHU CHARACTER-1B173;Lo;0;L;;;;;N;;;;; -1B174;NUSHU CHARACTER-1B174;Lo;0;L;;;;;N;;;;; -1B175;NUSHU CHARACTER-1B175;Lo;0;L;;;;;N;;;;; -1B176;NUSHU CHARACTER-1B176;Lo;0;L;;;;;N;;;;; -1B177;NUSHU CHARACTER-1B177;Lo;0;L;;;;;N;;;;; -1B178;NUSHU CHARACTER-1B178;Lo;0;L;;;;;N;;;;; -1B179;NUSHU CHARACTER-1B179;Lo;0;L;;;;;N;;;;; -1B17A;NUSHU CHARACTER-1B17A;Lo;0;L;;;;;N;;;;; -1B17B;NUSHU CHARACTER-1B17B;Lo;0;L;;;;;N;;;;; -1B17C;NUSHU CHARACTER-1B17C;Lo;0;L;;;;;N;;;;; -1B17D;NUSHU CHARACTER-1B17D;Lo;0;L;;;;;N;;;;; -1B17E;NUSHU CHARACTER-1B17E;Lo;0;L;;;;;N;;;;; -1B17F;NUSHU CHARACTER-1B17F;Lo;0;L;;;;;N;;;;; -1B180;NUSHU CHARACTER-1B180;Lo;0;L;;;;;N;;;;; -1B181;NUSHU CHARACTER-1B181;Lo;0;L;;;;;N;;;;; -1B182;NUSHU CHARACTER-1B182;Lo;0;L;;;;;N;;;;; -1B183;NUSHU CHARACTER-1B183;Lo;0;L;;;;;N;;;;; -1B184;NUSHU CHARACTER-1B184;Lo;0;L;;;;;N;;;;; -1B185;NUSHU CHARACTER-1B185;Lo;0;L;;;;;N;;;;; -1B186;NUSHU CHARACTER-1B186;Lo;0;L;;;;;N;;;;; -1B187;NUSHU CHARACTER-1B187;Lo;0;L;;;;;N;;;;; -1B188;NUSHU CHARACTER-1B188;Lo;0;L;;;;;N;;;;; -1B189;NUSHU CHARACTER-1B189;Lo;0;L;;;;;N;;;;; -1B18A;NUSHU CHARACTER-1B18A;Lo;0;L;;;;;N;;;;; -1B18B;NUSHU CHARACTER-1B18B;Lo;0;L;;;;;N;;;;; -1B18C;NUSHU CHARACTER-1B18C;Lo;0;L;;;;;N;;;;; -1B18D;NUSHU CHARACTER-1B18D;Lo;0;L;;;;;N;;;;; -1B18E;NUSHU CHARACTER-1B18E;Lo;0;L;;;;;N;;;;; -1B18F;NUSHU CHARACTER-1B18F;Lo;0;L;;;;;N;;;;; -1B190;NUSHU CHARACTER-1B190;Lo;0;L;;;;;N;;;;; -1B191;NUSHU CHARACTER-1B191;Lo;0;L;;;;;N;;;;; -1B192;NUSHU CHARACTER-1B192;Lo;0;L;;;;;N;;;;; -1B193;NUSHU CHARACTER-1B193;Lo;0;L;;;;;N;;;;; -1B194;NUSHU CHARACTER-1B194;Lo;0;L;;;;;N;;;;; -1B195;NUSHU CHARACTER-1B195;Lo;0;L;;;;;N;;;;; -1B196;NUSHU CHARACTER-1B196;Lo;0;L;;;;;N;;;;; -1B197;NUSHU CHARACTER-1B197;Lo;0;L;;;;;N;;;;; -1B198;NUSHU CHARACTER-1B198;Lo;0;L;;;;;N;;;;; -1B199;NUSHU CHARACTER-1B199;Lo;0;L;;;;;N;;;;; -1B19A;NUSHU CHARACTER-1B19A;Lo;0;L;;;;;N;;;;; -1B19B;NUSHU CHARACTER-1B19B;Lo;0;L;;;;;N;;;;; -1B19C;NUSHU CHARACTER-1B19C;Lo;0;L;;;;;N;;;;; -1B19D;NUSHU CHARACTER-1B19D;Lo;0;L;;;;;N;;;;; -1B19E;NUSHU CHARACTER-1B19E;Lo;0;L;;;;;N;;;;; -1B19F;NUSHU CHARACTER-1B19F;Lo;0;L;;;;;N;;;;; -1B1A0;NUSHU CHARACTER-1B1A0;Lo;0;L;;;;;N;;;;; -1B1A1;NUSHU CHARACTER-1B1A1;Lo;0;L;;;;;N;;;;; -1B1A2;NUSHU CHARACTER-1B1A2;Lo;0;L;;;;;N;;;;; -1B1A3;NUSHU CHARACTER-1B1A3;Lo;0;L;;;;;N;;;;; -1B1A4;NUSHU CHARACTER-1B1A4;Lo;0;L;;;;;N;;;;; -1B1A5;NUSHU CHARACTER-1B1A5;Lo;0;L;;;;;N;;;;; -1B1A6;NUSHU CHARACTER-1B1A6;Lo;0;L;;;;;N;;;;; -1B1A7;NUSHU CHARACTER-1B1A7;Lo;0;L;;;;;N;;;;; -1B1A8;NUSHU CHARACTER-1B1A8;Lo;0;L;;;;;N;;;;; -1B1A9;NUSHU CHARACTER-1B1A9;Lo;0;L;;;;;N;;;;; -1B1AA;NUSHU CHARACTER-1B1AA;Lo;0;L;;;;;N;;;;; -1B1AB;NUSHU CHARACTER-1B1AB;Lo;0;L;;;;;N;;;;; -1B1AC;NUSHU CHARACTER-1B1AC;Lo;0;L;;;;;N;;;;; -1B1AD;NUSHU CHARACTER-1B1AD;Lo;0;L;;;;;N;;;;; -1B1AE;NUSHU CHARACTER-1B1AE;Lo;0;L;;;;;N;;;;; -1B1AF;NUSHU CHARACTER-1B1AF;Lo;0;L;;;;;N;;;;; -1B1B0;NUSHU CHARACTER-1B1B0;Lo;0;L;;;;;N;;;;; -1B1B1;NUSHU CHARACTER-1B1B1;Lo;0;L;;;;;N;;;;; -1B1B2;NUSHU CHARACTER-1B1B2;Lo;0;L;;;;;N;;;;; -1B1B3;NUSHU CHARACTER-1B1B3;Lo;0;L;;;;;N;;;;; -1B1B4;NUSHU CHARACTER-1B1B4;Lo;0;L;;;;;N;;;;; -1B1B5;NUSHU CHARACTER-1B1B5;Lo;0;L;;;;;N;;;;; -1B1B6;NUSHU CHARACTER-1B1B6;Lo;0;L;;;;;N;;;;; -1B1B7;NUSHU CHARACTER-1B1B7;Lo;0;L;;;;;N;;;;; -1B1B8;NUSHU CHARACTER-1B1B8;Lo;0;L;;;;;N;;;;; -1B1B9;NUSHU CHARACTER-1B1B9;Lo;0;L;;;;;N;;;;; -1B1BA;NUSHU CHARACTER-1B1BA;Lo;0;L;;;;;N;;;;; -1B1BB;NUSHU CHARACTER-1B1BB;Lo;0;L;;;;;N;;;;; -1B1BC;NUSHU CHARACTER-1B1BC;Lo;0;L;;;;;N;;;;; -1B1BD;NUSHU CHARACTER-1B1BD;Lo;0;L;;;;;N;;;;; -1B1BE;NUSHU CHARACTER-1B1BE;Lo;0;L;;;;;N;;;;; -1B1BF;NUSHU CHARACTER-1B1BF;Lo;0;L;;;;;N;;;;; -1B1C0;NUSHU CHARACTER-1B1C0;Lo;0;L;;;;;N;;;;; -1B1C1;NUSHU CHARACTER-1B1C1;Lo;0;L;;;;;N;;;;; -1B1C2;NUSHU CHARACTER-1B1C2;Lo;0;L;;;;;N;;;;; -1B1C3;NUSHU CHARACTER-1B1C3;Lo;0;L;;;;;N;;;;; -1B1C4;NUSHU CHARACTER-1B1C4;Lo;0;L;;;;;N;;;;; -1B1C5;NUSHU CHARACTER-1B1C5;Lo;0;L;;;;;N;;;;; -1B1C6;NUSHU CHARACTER-1B1C6;Lo;0;L;;;;;N;;;;; -1B1C7;NUSHU CHARACTER-1B1C7;Lo;0;L;;;;;N;;;;; -1B1C8;NUSHU CHARACTER-1B1C8;Lo;0;L;;;;;N;;;;; -1B1C9;NUSHU CHARACTER-1B1C9;Lo;0;L;;;;;N;;;;; -1B1CA;NUSHU CHARACTER-1B1CA;Lo;0;L;;;;;N;;;;; -1B1CB;NUSHU CHARACTER-1B1CB;Lo;0;L;;;;;N;;;;; -1B1CC;NUSHU CHARACTER-1B1CC;Lo;0;L;;;;;N;;;;; -1B1CD;NUSHU CHARACTER-1B1CD;Lo;0;L;;;;;N;;;;; -1B1CE;NUSHU CHARACTER-1B1CE;Lo;0;L;;;;;N;;;;; -1B1CF;NUSHU CHARACTER-1B1CF;Lo;0;L;;;;;N;;;;; -1B1D0;NUSHU CHARACTER-1B1D0;Lo;0;L;;;;;N;;;;; -1B1D1;NUSHU CHARACTER-1B1D1;Lo;0;L;;;;;N;;;;; -1B1D2;NUSHU CHARACTER-1B1D2;Lo;0;L;;;;;N;;;;; -1B1D3;NUSHU CHARACTER-1B1D3;Lo;0;L;;;;;N;;;;; -1B1D4;NUSHU CHARACTER-1B1D4;Lo;0;L;;;;;N;;;;; -1B1D5;NUSHU CHARACTER-1B1D5;Lo;0;L;;;;;N;;;;; -1B1D6;NUSHU CHARACTER-1B1D6;Lo;0;L;;;;;N;;;;; -1B1D7;NUSHU CHARACTER-1B1D7;Lo;0;L;;;;;N;;;;; -1B1D8;NUSHU CHARACTER-1B1D8;Lo;0;L;;;;;N;;;;; -1B1D9;NUSHU CHARACTER-1B1D9;Lo;0;L;;;;;N;;;;; -1B1DA;NUSHU CHARACTER-1B1DA;Lo;0;L;;;;;N;;;;; -1B1DB;NUSHU CHARACTER-1B1DB;Lo;0;L;;;;;N;;;;; -1B1DC;NUSHU CHARACTER-1B1DC;Lo;0;L;;;;;N;;;;; -1B1DD;NUSHU CHARACTER-1B1DD;Lo;0;L;;;;;N;;;;; -1B1DE;NUSHU CHARACTER-1B1DE;Lo;0;L;;;;;N;;;;; -1B1DF;NUSHU CHARACTER-1B1DF;Lo;0;L;;;;;N;;;;; -1B1E0;NUSHU CHARACTER-1B1E0;Lo;0;L;;;;;N;;;;; -1B1E1;NUSHU CHARACTER-1B1E1;Lo;0;L;;;;;N;;;;; -1B1E2;NUSHU CHARACTER-1B1E2;Lo;0;L;;;;;N;;;;; -1B1E3;NUSHU CHARACTER-1B1E3;Lo;0;L;;;;;N;;;;; -1B1E4;NUSHU CHARACTER-1B1E4;Lo;0;L;;;;;N;;;;; -1B1E5;NUSHU CHARACTER-1B1E5;Lo;0;L;;;;;N;;;;; -1B1E6;NUSHU CHARACTER-1B1E6;Lo;0;L;;;;;N;;;;; -1B1E7;NUSHU CHARACTER-1B1E7;Lo;0;L;;;;;N;;;;; -1B1E8;NUSHU CHARACTER-1B1E8;Lo;0;L;;;;;N;;;;; -1B1E9;NUSHU CHARACTER-1B1E9;Lo;0;L;;;;;N;;;;; -1B1EA;NUSHU CHARACTER-1B1EA;Lo;0;L;;;;;N;;;;; -1B1EB;NUSHU CHARACTER-1B1EB;Lo;0;L;;;;;N;;;;; -1B1EC;NUSHU CHARACTER-1B1EC;Lo;0;L;;;;;N;;;;; -1B1ED;NUSHU CHARACTER-1B1ED;Lo;0;L;;;;;N;;;;; -1B1EE;NUSHU CHARACTER-1B1EE;Lo;0;L;;;;;N;;;;; -1B1EF;NUSHU CHARACTER-1B1EF;Lo;0;L;;;;;N;;;;; -1B1F0;NUSHU CHARACTER-1B1F0;Lo;0;L;;;;;N;;;;; -1B1F1;NUSHU CHARACTER-1B1F1;Lo;0;L;;;;;N;;;;; -1B1F2;NUSHU CHARACTER-1B1F2;Lo;0;L;;;;;N;;;;; -1B1F3;NUSHU CHARACTER-1B1F3;Lo;0;L;;;;;N;;;;; -1B1F4;NUSHU CHARACTER-1B1F4;Lo;0;L;;;;;N;;;;; -1B1F5;NUSHU CHARACTER-1B1F5;Lo;0;L;;;;;N;;;;; -1B1F6;NUSHU CHARACTER-1B1F6;Lo;0;L;;;;;N;;;;; -1B1F7;NUSHU CHARACTER-1B1F7;Lo;0;L;;;;;N;;;;; -1B1F8;NUSHU CHARACTER-1B1F8;Lo;0;L;;;;;N;;;;; -1B1F9;NUSHU CHARACTER-1B1F9;Lo;0;L;;;;;N;;;;; -1B1FA;NUSHU CHARACTER-1B1FA;Lo;0;L;;;;;N;;;;; -1B1FB;NUSHU CHARACTER-1B1FB;Lo;0;L;;;;;N;;;;; -1B1FC;NUSHU CHARACTER-1B1FC;Lo;0;L;;;;;N;;;;; -1B1FD;NUSHU CHARACTER-1B1FD;Lo;0;L;;;;;N;;;;; -1B1FE;NUSHU CHARACTER-1B1FE;Lo;0;L;;;;;N;;;;; -1B1FF;NUSHU CHARACTER-1B1FF;Lo;0;L;;;;;N;;;;; -1B200;NUSHU CHARACTER-1B200;Lo;0;L;;;;;N;;;;; -1B201;NUSHU CHARACTER-1B201;Lo;0;L;;;;;N;;;;; -1B202;NUSHU CHARACTER-1B202;Lo;0;L;;;;;N;;;;; -1B203;NUSHU CHARACTER-1B203;Lo;0;L;;;;;N;;;;; -1B204;NUSHU CHARACTER-1B204;Lo;0;L;;;;;N;;;;; -1B205;NUSHU CHARACTER-1B205;Lo;0;L;;;;;N;;;;; -1B206;NUSHU CHARACTER-1B206;Lo;0;L;;;;;N;;;;; -1B207;NUSHU CHARACTER-1B207;Lo;0;L;;;;;N;;;;; -1B208;NUSHU CHARACTER-1B208;Lo;0;L;;;;;N;;;;; -1B209;NUSHU CHARACTER-1B209;Lo;0;L;;;;;N;;;;; -1B20A;NUSHU CHARACTER-1B20A;Lo;0;L;;;;;N;;;;; -1B20B;NUSHU CHARACTER-1B20B;Lo;0;L;;;;;N;;;;; -1B20C;NUSHU CHARACTER-1B20C;Lo;0;L;;;;;N;;;;; -1B20D;NUSHU CHARACTER-1B20D;Lo;0;L;;;;;N;;;;; -1B20E;NUSHU CHARACTER-1B20E;Lo;0;L;;;;;N;;;;; -1B20F;NUSHU CHARACTER-1B20F;Lo;0;L;;;;;N;;;;; -1B210;NUSHU CHARACTER-1B210;Lo;0;L;;;;;N;;;;; -1B211;NUSHU CHARACTER-1B211;Lo;0;L;;;;;N;;;;; -1B212;NUSHU CHARACTER-1B212;Lo;0;L;;;;;N;;;;; -1B213;NUSHU CHARACTER-1B213;Lo;0;L;;;;;N;;;;; -1B214;NUSHU CHARACTER-1B214;Lo;0;L;;;;;N;;;;; -1B215;NUSHU CHARACTER-1B215;Lo;0;L;;;;;N;;;;; -1B216;NUSHU CHARACTER-1B216;Lo;0;L;;;;;N;;;;; -1B217;NUSHU CHARACTER-1B217;Lo;0;L;;;;;N;;;;; -1B218;NUSHU CHARACTER-1B218;Lo;0;L;;;;;N;;;;; -1B219;NUSHU CHARACTER-1B219;Lo;0;L;;;;;N;;;;; -1B21A;NUSHU CHARACTER-1B21A;Lo;0;L;;;;;N;;;;; -1B21B;NUSHU CHARACTER-1B21B;Lo;0;L;;;;;N;;;;; -1B21C;NUSHU CHARACTER-1B21C;Lo;0;L;;;;;N;;;;; -1B21D;NUSHU CHARACTER-1B21D;Lo;0;L;;;;;N;;;;; -1B21E;NUSHU CHARACTER-1B21E;Lo;0;L;;;;;N;;;;; -1B21F;NUSHU CHARACTER-1B21F;Lo;0;L;;;;;N;;;;; -1B220;NUSHU CHARACTER-1B220;Lo;0;L;;;;;N;;;;; -1B221;NUSHU CHARACTER-1B221;Lo;0;L;;;;;N;;;;; -1B222;NUSHU CHARACTER-1B222;Lo;0;L;;;;;N;;;;; -1B223;NUSHU CHARACTER-1B223;Lo;0;L;;;;;N;;;;; -1B224;NUSHU CHARACTER-1B224;Lo;0;L;;;;;N;;;;; -1B225;NUSHU CHARACTER-1B225;Lo;0;L;;;;;N;;;;; -1B226;NUSHU CHARACTER-1B226;Lo;0;L;;;;;N;;;;; -1B227;NUSHU CHARACTER-1B227;Lo;0;L;;;;;N;;;;; -1B228;NUSHU CHARACTER-1B228;Lo;0;L;;;;;N;;;;; -1B229;NUSHU CHARACTER-1B229;Lo;0;L;;;;;N;;;;; -1B22A;NUSHU CHARACTER-1B22A;Lo;0;L;;;;;N;;;;; -1B22B;NUSHU CHARACTER-1B22B;Lo;0;L;;;;;N;;;;; -1B22C;NUSHU CHARACTER-1B22C;Lo;0;L;;;;;N;;;;; -1B22D;NUSHU CHARACTER-1B22D;Lo;0;L;;;;;N;;;;; -1B22E;NUSHU CHARACTER-1B22E;Lo;0;L;;;;;N;;;;; -1B22F;NUSHU CHARACTER-1B22F;Lo;0;L;;;;;N;;;;; -1B230;NUSHU CHARACTER-1B230;Lo;0;L;;;;;N;;;;; -1B231;NUSHU CHARACTER-1B231;Lo;0;L;;;;;N;;;;; -1B232;NUSHU CHARACTER-1B232;Lo;0;L;;;;;N;;;;; -1B233;NUSHU CHARACTER-1B233;Lo;0;L;;;;;N;;;;; -1B234;NUSHU CHARACTER-1B234;Lo;0;L;;;;;N;;;;; -1B235;NUSHU CHARACTER-1B235;Lo;0;L;;;;;N;;;;; -1B236;NUSHU CHARACTER-1B236;Lo;0;L;;;;;N;;;;; -1B237;NUSHU CHARACTER-1B237;Lo;0;L;;;;;N;;;;; -1B238;NUSHU CHARACTER-1B238;Lo;0;L;;;;;N;;;;; -1B239;NUSHU CHARACTER-1B239;Lo;0;L;;;;;N;;;;; -1B23A;NUSHU CHARACTER-1B23A;Lo;0;L;;;;;N;;;;; -1B23B;NUSHU CHARACTER-1B23B;Lo;0;L;;;;;N;;;;; -1B23C;NUSHU CHARACTER-1B23C;Lo;0;L;;;;;N;;;;; -1B23D;NUSHU CHARACTER-1B23D;Lo;0;L;;;;;N;;;;; -1B23E;NUSHU CHARACTER-1B23E;Lo;0;L;;;;;N;;;;; -1B23F;NUSHU CHARACTER-1B23F;Lo;0;L;;;;;N;;;;; -1B240;NUSHU CHARACTER-1B240;Lo;0;L;;;;;N;;;;; -1B241;NUSHU CHARACTER-1B241;Lo;0;L;;;;;N;;;;; -1B242;NUSHU CHARACTER-1B242;Lo;0;L;;;;;N;;;;; -1B243;NUSHU CHARACTER-1B243;Lo;0;L;;;;;N;;;;; -1B244;NUSHU CHARACTER-1B244;Lo;0;L;;;;;N;;;;; -1B245;NUSHU CHARACTER-1B245;Lo;0;L;;;;;N;;;;; -1B246;NUSHU CHARACTER-1B246;Lo;0;L;;;;;N;;;;; -1B247;NUSHU CHARACTER-1B247;Lo;0;L;;;;;N;;;;; -1B248;NUSHU CHARACTER-1B248;Lo;0;L;;;;;N;;;;; -1B249;NUSHU CHARACTER-1B249;Lo;0;L;;;;;N;;;;; -1B24A;NUSHU CHARACTER-1B24A;Lo;0;L;;;;;N;;;;; -1B24B;NUSHU CHARACTER-1B24B;Lo;0;L;;;;;N;;;;; -1B24C;NUSHU CHARACTER-1B24C;Lo;0;L;;;;;N;;;;; -1B24D;NUSHU CHARACTER-1B24D;Lo;0;L;;;;;N;;;;; -1B24E;NUSHU CHARACTER-1B24E;Lo;0;L;;;;;N;;;;; -1B24F;NUSHU CHARACTER-1B24F;Lo;0;L;;;;;N;;;;; -1B250;NUSHU CHARACTER-1B250;Lo;0;L;;;;;N;;;;; -1B251;NUSHU CHARACTER-1B251;Lo;0;L;;;;;N;;;;; -1B252;NUSHU CHARACTER-1B252;Lo;0;L;;;;;N;;;;; -1B253;NUSHU CHARACTER-1B253;Lo;0;L;;;;;N;;;;; -1B254;NUSHU CHARACTER-1B254;Lo;0;L;;;;;N;;;;; -1B255;NUSHU CHARACTER-1B255;Lo;0;L;;;;;N;;;;; -1B256;NUSHU CHARACTER-1B256;Lo;0;L;;;;;N;;;;; -1B257;NUSHU CHARACTER-1B257;Lo;0;L;;;;;N;;;;; -1B258;NUSHU CHARACTER-1B258;Lo;0;L;;;;;N;;;;; -1B259;NUSHU CHARACTER-1B259;Lo;0;L;;;;;N;;;;; -1B25A;NUSHU CHARACTER-1B25A;Lo;0;L;;;;;N;;;;; -1B25B;NUSHU CHARACTER-1B25B;Lo;0;L;;;;;N;;;;; -1B25C;NUSHU CHARACTER-1B25C;Lo;0;L;;;;;N;;;;; -1B25D;NUSHU CHARACTER-1B25D;Lo;0;L;;;;;N;;;;; -1B25E;NUSHU CHARACTER-1B25E;Lo;0;L;;;;;N;;;;; -1B25F;NUSHU CHARACTER-1B25F;Lo;0;L;;;;;N;;;;; -1B260;NUSHU CHARACTER-1B260;Lo;0;L;;;;;N;;;;; -1B261;NUSHU CHARACTER-1B261;Lo;0;L;;;;;N;;;;; -1B262;NUSHU CHARACTER-1B262;Lo;0;L;;;;;N;;;;; -1B263;NUSHU CHARACTER-1B263;Lo;0;L;;;;;N;;;;; -1B264;NUSHU CHARACTER-1B264;Lo;0;L;;;;;N;;;;; -1B265;NUSHU CHARACTER-1B265;Lo;0;L;;;;;N;;;;; -1B266;NUSHU CHARACTER-1B266;Lo;0;L;;;;;N;;;;; -1B267;NUSHU CHARACTER-1B267;Lo;0;L;;;;;N;;;;; -1B268;NUSHU CHARACTER-1B268;Lo;0;L;;;;;N;;;;; -1B269;NUSHU CHARACTER-1B269;Lo;0;L;;;;;N;;;;; -1B26A;NUSHU CHARACTER-1B26A;Lo;0;L;;;;;N;;;;; -1B26B;NUSHU CHARACTER-1B26B;Lo;0;L;;;;;N;;;;; -1B26C;NUSHU CHARACTER-1B26C;Lo;0;L;;;;;N;;;;; -1B26D;NUSHU CHARACTER-1B26D;Lo;0;L;;;;;N;;;;; -1B26E;NUSHU CHARACTER-1B26E;Lo;0;L;;;;;N;;;;; -1B26F;NUSHU CHARACTER-1B26F;Lo;0;L;;;;;N;;;;; -1B270;NUSHU CHARACTER-1B270;Lo;0;L;;;;;N;;;;; -1B271;NUSHU CHARACTER-1B271;Lo;0;L;;;;;N;;;;; -1B272;NUSHU CHARACTER-1B272;Lo;0;L;;;;;N;;;;; -1B273;NUSHU CHARACTER-1B273;Lo;0;L;;;;;N;;;;; -1B274;NUSHU CHARACTER-1B274;Lo;0;L;;;;;N;;;;; -1B275;NUSHU CHARACTER-1B275;Lo;0;L;;;;;N;;;;; -1B276;NUSHU CHARACTER-1B276;Lo;0;L;;;;;N;;;;; -1B277;NUSHU CHARACTER-1B277;Lo;0;L;;;;;N;;;;; -1B278;NUSHU CHARACTER-1B278;Lo;0;L;;;;;N;;;;; -1B279;NUSHU CHARACTER-1B279;Lo;0;L;;;;;N;;;;; -1B27A;NUSHU CHARACTER-1B27A;Lo;0;L;;;;;N;;;;; -1B27B;NUSHU CHARACTER-1B27B;Lo;0;L;;;;;N;;;;; -1B27C;NUSHU CHARACTER-1B27C;Lo;0;L;;;;;N;;;;; -1B27D;NUSHU CHARACTER-1B27D;Lo;0;L;;;;;N;;;;; -1B27E;NUSHU CHARACTER-1B27E;Lo;0;L;;;;;N;;;;; -1B27F;NUSHU CHARACTER-1B27F;Lo;0;L;;;;;N;;;;; -1B280;NUSHU CHARACTER-1B280;Lo;0;L;;;;;N;;;;; -1B281;NUSHU CHARACTER-1B281;Lo;0;L;;;;;N;;;;; -1B282;NUSHU CHARACTER-1B282;Lo;0;L;;;;;N;;;;; -1B283;NUSHU CHARACTER-1B283;Lo;0;L;;;;;N;;;;; -1B284;NUSHU CHARACTER-1B284;Lo;0;L;;;;;N;;;;; -1B285;NUSHU CHARACTER-1B285;Lo;0;L;;;;;N;;;;; -1B286;NUSHU CHARACTER-1B286;Lo;0;L;;;;;N;;;;; -1B287;NUSHU CHARACTER-1B287;Lo;0;L;;;;;N;;;;; -1B288;NUSHU CHARACTER-1B288;Lo;0;L;;;;;N;;;;; -1B289;NUSHU CHARACTER-1B289;Lo;0;L;;;;;N;;;;; -1B28A;NUSHU CHARACTER-1B28A;Lo;0;L;;;;;N;;;;; -1B28B;NUSHU CHARACTER-1B28B;Lo;0;L;;;;;N;;;;; -1B28C;NUSHU CHARACTER-1B28C;Lo;0;L;;;;;N;;;;; -1B28D;NUSHU CHARACTER-1B28D;Lo;0;L;;;;;N;;;;; -1B28E;NUSHU CHARACTER-1B28E;Lo;0;L;;;;;N;;;;; -1B28F;NUSHU CHARACTER-1B28F;Lo;0;L;;;;;N;;;;; -1B290;NUSHU CHARACTER-1B290;Lo;0;L;;;;;N;;;;; -1B291;NUSHU CHARACTER-1B291;Lo;0;L;;;;;N;;;;; -1B292;NUSHU CHARACTER-1B292;Lo;0;L;;;;;N;;;;; -1B293;NUSHU CHARACTER-1B293;Lo;0;L;;;;;N;;;;; -1B294;NUSHU CHARACTER-1B294;Lo;0;L;;;;;N;;;;; -1B295;NUSHU CHARACTER-1B295;Lo;0;L;;;;;N;;;;; -1B296;NUSHU CHARACTER-1B296;Lo;0;L;;;;;N;;;;; -1B297;NUSHU CHARACTER-1B297;Lo;0;L;;;;;N;;;;; -1B298;NUSHU CHARACTER-1B298;Lo;0;L;;;;;N;;;;; -1B299;NUSHU CHARACTER-1B299;Lo;0;L;;;;;N;;;;; -1B29A;NUSHU CHARACTER-1B29A;Lo;0;L;;;;;N;;;;; -1B29B;NUSHU CHARACTER-1B29B;Lo;0;L;;;;;N;;;;; -1B29C;NUSHU CHARACTER-1B29C;Lo;0;L;;;;;N;;;;; -1B29D;NUSHU CHARACTER-1B29D;Lo;0;L;;;;;N;;;;; -1B29E;NUSHU CHARACTER-1B29E;Lo;0;L;;;;;N;;;;; -1B29F;NUSHU CHARACTER-1B29F;Lo;0;L;;;;;N;;;;; -1B2A0;NUSHU CHARACTER-1B2A0;Lo;0;L;;;;;N;;;;; -1B2A1;NUSHU CHARACTER-1B2A1;Lo;0;L;;;;;N;;;;; -1B2A2;NUSHU CHARACTER-1B2A2;Lo;0;L;;;;;N;;;;; -1B2A3;NUSHU CHARACTER-1B2A3;Lo;0;L;;;;;N;;;;; -1B2A4;NUSHU CHARACTER-1B2A4;Lo;0;L;;;;;N;;;;; -1B2A5;NUSHU CHARACTER-1B2A5;Lo;0;L;;;;;N;;;;; -1B2A6;NUSHU CHARACTER-1B2A6;Lo;0;L;;;;;N;;;;; -1B2A7;NUSHU CHARACTER-1B2A7;Lo;0;L;;;;;N;;;;; -1B2A8;NUSHU CHARACTER-1B2A8;Lo;0;L;;;;;N;;;;; -1B2A9;NUSHU CHARACTER-1B2A9;Lo;0;L;;;;;N;;;;; -1B2AA;NUSHU CHARACTER-1B2AA;Lo;0;L;;;;;N;;;;; -1B2AB;NUSHU CHARACTER-1B2AB;Lo;0;L;;;;;N;;;;; -1B2AC;NUSHU CHARACTER-1B2AC;Lo;0;L;;;;;N;;;;; -1B2AD;NUSHU CHARACTER-1B2AD;Lo;0;L;;;;;N;;;;; -1B2AE;NUSHU CHARACTER-1B2AE;Lo;0;L;;;;;N;;;;; -1B2AF;NUSHU CHARACTER-1B2AF;Lo;0;L;;;;;N;;;;; -1B2B0;NUSHU CHARACTER-1B2B0;Lo;0;L;;;;;N;;;;; -1B2B1;NUSHU CHARACTER-1B2B1;Lo;0;L;;;;;N;;;;; -1B2B2;NUSHU CHARACTER-1B2B2;Lo;0;L;;;;;N;;;;; -1B2B3;NUSHU CHARACTER-1B2B3;Lo;0;L;;;;;N;;;;; -1B2B4;NUSHU CHARACTER-1B2B4;Lo;0;L;;;;;N;;;;; -1B2B5;NUSHU CHARACTER-1B2B5;Lo;0;L;;;;;N;;;;; -1B2B6;NUSHU CHARACTER-1B2B6;Lo;0;L;;;;;N;;;;; -1B2B7;NUSHU CHARACTER-1B2B7;Lo;0;L;;;;;N;;;;; -1B2B8;NUSHU CHARACTER-1B2B8;Lo;0;L;;;;;N;;;;; -1B2B9;NUSHU CHARACTER-1B2B9;Lo;0;L;;;;;N;;;;; -1B2BA;NUSHU CHARACTER-1B2BA;Lo;0;L;;;;;N;;;;; -1B2BB;NUSHU CHARACTER-1B2BB;Lo;0;L;;;;;N;;;;; -1B2BC;NUSHU CHARACTER-1B2BC;Lo;0;L;;;;;N;;;;; -1B2BD;NUSHU CHARACTER-1B2BD;Lo;0;L;;;;;N;;;;; -1B2BE;NUSHU CHARACTER-1B2BE;Lo;0;L;;;;;N;;;;; -1B2BF;NUSHU CHARACTER-1B2BF;Lo;0;L;;;;;N;;;;; -1B2C0;NUSHU CHARACTER-1B2C0;Lo;0;L;;;;;N;;;;; -1B2C1;NUSHU CHARACTER-1B2C1;Lo;0;L;;;;;N;;;;; -1B2C2;NUSHU CHARACTER-1B2C2;Lo;0;L;;;;;N;;;;; -1B2C3;NUSHU CHARACTER-1B2C3;Lo;0;L;;;;;N;;;;; -1B2C4;NUSHU CHARACTER-1B2C4;Lo;0;L;;;;;N;;;;; -1B2C5;NUSHU CHARACTER-1B2C5;Lo;0;L;;;;;N;;;;; -1B2C6;NUSHU CHARACTER-1B2C6;Lo;0;L;;;;;N;;;;; -1B2C7;NUSHU CHARACTER-1B2C7;Lo;0;L;;;;;N;;;;; -1B2C8;NUSHU CHARACTER-1B2C8;Lo;0;L;;;;;N;;;;; -1B2C9;NUSHU CHARACTER-1B2C9;Lo;0;L;;;;;N;;;;; -1B2CA;NUSHU CHARACTER-1B2CA;Lo;0;L;;;;;N;;;;; -1B2CB;NUSHU CHARACTER-1B2CB;Lo;0;L;;;;;N;;;;; -1B2CC;NUSHU CHARACTER-1B2CC;Lo;0;L;;;;;N;;;;; -1B2CD;NUSHU CHARACTER-1B2CD;Lo;0;L;;;;;N;;;;; -1B2CE;NUSHU CHARACTER-1B2CE;Lo;0;L;;;;;N;;;;; -1B2CF;NUSHU CHARACTER-1B2CF;Lo;0;L;;;;;N;;;;; -1B2D0;NUSHU CHARACTER-1B2D0;Lo;0;L;;;;;N;;;;; -1B2D1;NUSHU CHARACTER-1B2D1;Lo;0;L;;;;;N;;;;; -1B2D2;NUSHU CHARACTER-1B2D2;Lo;0;L;;;;;N;;;;; -1B2D3;NUSHU CHARACTER-1B2D3;Lo;0;L;;;;;N;;;;; -1B2D4;NUSHU CHARACTER-1B2D4;Lo;0;L;;;;;N;;;;; -1B2D5;NUSHU CHARACTER-1B2D5;Lo;0;L;;;;;N;;;;; -1B2D6;NUSHU CHARACTER-1B2D6;Lo;0;L;;;;;N;;;;; -1B2D7;NUSHU CHARACTER-1B2D7;Lo;0;L;;;;;N;;;;; -1B2D8;NUSHU CHARACTER-1B2D8;Lo;0;L;;;;;N;;;;; -1B2D9;NUSHU CHARACTER-1B2D9;Lo;0;L;;;;;N;;;;; -1B2DA;NUSHU CHARACTER-1B2DA;Lo;0;L;;;;;N;;;;; -1B2DB;NUSHU CHARACTER-1B2DB;Lo;0;L;;;;;N;;;;; -1B2DC;NUSHU CHARACTER-1B2DC;Lo;0;L;;;;;N;;;;; -1B2DD;NUSHU CHARACTER-1B2DD;Lo;0;L;;;;;N;;;;; -1B2DE;NUSHU CHARACTER-1B2DE;Lo;0;L;;;;;N;;;;; -1B2DF;NUSHU CHARACTER-1B2DF;Lo;0;L;;;;;N;;;;; -1B2E0;NUSHU CHARACTER-1B2E0;Lo;0;L;;;;;N;;;;; -1B2E1;NUSHU CHARACTER-1B2E1;Lo;0;L;;;;;N;;;;; -1B2E2;NUSHU CHARACTER-1B2E2;Lo;0;L;;;;;N;;;;; -1B2E3;NUSHU CHARACTER-1B2E3;Lo;0;L;;;;;N;;;;; -1B2E4;NUSHU CHARACTER-1B2E4;Lo;0;L;;;;;N;;;;; -1B2E5;NUSHU CHARACTER-1B2E5;Lo;0;L;;;;;N;;;;; -1B2E6;NUSHU CHARACTER-1B2E6;Lo;0;L;;;;;N;;;;; -1B2E7;NUSHU CHARACTER-1B2E7;Lo;0;L;;;;;N;;;;; -1B2E8;NUSHU CHARACTER-1B2E8;Lo;0;L;;;;;N;;;;; -1B2E9;NUSHU CHARACTER-1B2E9;Lo;0;L;;;;;N;;;;; -1B2EA;NUSHU CHARACTER-1B2EA;Lo;0;L;;;;;N;;;;; -1B2EB;NUSHU CHARACTER-1B2EB;Lo;0;L;;;;;N;;;;; -1B2EC;NUSHU CHARACTER-1B2EC;Lo;0;L;;;;;N;;;;; -1B2ED;NUSHU CHARACTER-1B2ED;Lo;0;L;;;;;N;;;;; -1B2EE;NUSHU CHARACTER-1B2EE;Lo;0;L;;;;;N;;;;; -1B2EF;NUSHU CHARACTER-1B2EF;Lo;0;L;;;;;N;;;;; -1B2F0;NUSHU CHARACTER-1B2F0;Lo;0;L;;;;;N;;;;; -1B2F1;NUSHU CHARACTER-1B2F1;Lo;0;L;;;;;N;;;;; -1B2F2;NUSHU CHARACTER-1B2F2;Lo;0;L;;;;;N;;;;; -1B2F3;NUSHU CHARACTER-1B2F3;Lo;0;L;;;;;N;;;;; -1B2F4;NUSHU CHARACTER-1B2F4;Lo;0;L;;;;;N;;;;; -1B2F5;NUSHU CHARACTER-1B2F5;Lo;0;L;;;;;N;;;;; -1B2F6;NUSHU CHARACTER-1B2F6;Lo;0;L;;;;;N;;;;; -1B2F7;NUSHU CHARACTER-1B2F7;Lo;0;L;;;;;N;;;;; -1B2F8;NUSHU CHARACTER-1B2F8;Lo;0;L;;;;;N;;;;; -1B2F9;NUSHU CHARACTER-1B2F9;Lo;0;L;;;;;N;;;;; -1B2FA;NUSHU CHARACTER-1B2FA;Lo;0;L;;;;;N;;;;; -1B2FB;NUSHU CHARACTER-1B2FB;Lo;0;L;;;;;N;;;;; -1BC00;DUPLOYAN LETTER H;Lo;0;L;;;;;N;;;;; -1BC01;DUPLOYAN LETTER X;Lo;0;L;;;;;N;;;;; -1BC02;DUPLOYAN LETTER P;Lo;0;L;;;;;N;;;;; -1BC03;DUPLOYAN LETTER T;Lo;0;L;;;;;N;;;;; -1BC04;DUPLOYAN LETTER F;Lo;0;L;;;;;N;;;;; -1BC05;DUPLOYAN LETTER K;Lo;0;L;;;;;N;;;;; -1BC06;DUPLOYAN LETTER L;Lo;0;L;;;;;N;;;;; -1BC07;DUPLOYAN LETTER B;Lo;0;L;;;;;N;;;;; -1BC08;DUPLOYAN LETTER D;Lo;0;L;;;;;N;;;;; -1BC09;DUPLOYAN LETTER V;Lo;0;L;;;;;N;;;;; -1BC0A;DUPLOYAN LETTER G;Lo;0;L;;;;;N;;;;; -1BC0B;DUPLOYAN LETTER R;Lo;0;L;;;;;N;;;;; -1BC0C;DUPLOYAN LETTER P N;Lo;0;L;;;;;N;;;;; -1BC0D;DUPLOYAN LETTER D S;Lo;0;L;;;;;N;;;;; -1BC0E;DUPLOYAN LETTER F N;Lo;0;L;;;;;N;;;;; -1BC0F;DUPLOYAN LETTER K M;Lo;0;L;;;;;N;;;;; -1BC10;DUPLOYAN LETTER R S;Lo;0;L;;;;;N;;;;; -1BC11;DUPLOYAN LETTER TH;Lo;0;L;;;;;N;;;;; -1BC12;DUPLOYAN LETTER SLOAN DH;Lo;0;L;;;;;N;;;;; -1BC13;DUPLOYAN LETTER DH;Lo;0;L;;;;;N;;;;; -1BC14;DUPLOYAN LETTER KK;Lo;0;L;;;;;N;;;;; -1BC15;DUPLOYAN LETTER SLOAN J;Lo;0;L;;;;;N;;;;; -1BC16;DUPLOYAN LETTER HL;Lo;0;L;;;;;N;;;;; -1BC17;DUPLOYAN LETTER LH;Lo;0;L;;;;;N;;;;; -1BC18;DUPLOYAN LETTER RH;Lo;0;L;;;;;N;;;;; -1BC19;DUPLOYAN LETTER M;Lo;0;L;;;;;N;;;;; -1BC1A;DUPLOYAN LETTER N;Lo;0;L;;;;;N;;;;; -1BC1B;DUPLOYAN LETTER J;Lo;0;L;;;;;N;;;;; -1BC1C;DUPLOYAN LETTER S;Lo;0;L;;;;;N;;;;; -1BC1D;DUPLOYAN LETTER M N;Lo;0;L;;;;;N;;;;; -1BC1E;DUPLOYAN LETTER N M;Lo;0;L;;;;;N;;;;; -1BC1F;DUPLOYAN LETTER J M;Lo;0;L;;;;;N;;;;; -1BC20;DUPLOYAN LETTER S J;Lo;0;L;;;;;N;;;;; -1BC21;DUPLOYAN LETTER M WITH DOT;Lo;0;L;;;;;N;;;;; -1BC22;DUPLOYAN LETTER N WITH DOT;Lo;0;L;;;;;N;;;;; -1BC23;DUPLOYAN LETTER J WITH DOT;Lo;0;L;;;;;N;;;;; -1BC24;DUPLOYAN LETTER J WITH DOTS INSIDE AND ABOVE;Lo;0;L;;;;;N;;;;; -1BC25;DUPLOYAN LETTER S WITH DOT;Lo;0;L;;;;;N;;;;; -1BC26;DUPLOYAN LETTER S WITH DOT BELOW;Lo;0;L;;;;;N;;;;; -1BC27;DUPLOYAN LETTER M S;Lo;0;L;;;;;N;;;;; -1BC28;DUPLOYAN LETTER N S;Lo;0;L;;;;;N;;;;; -1BC29;DUPLOYAN LETTER J S;Lo;0;L;;;;;N;;;;; -1BC2A;DUPLOYAN LETTER S S;Lo;0;L;;;;;N;;;;; -1BC2B;DUPLOYAN LETTER M N S;Lo;0;L;;;;;N;;;;; -1BC2C;DUPLOYAN LETTER N M S;Lo;0;L;;;;;N;;;;; -1BC2D;DUPLOYAN LETTER J M S;Lo;0;L;;;;;N;;;;; -1BC2E;DUPLOYAN LETTER S J S;Lo;0;L;;;;;N;;;;; -1BC2F;DUPLOYAN LETTER J S WITH DOT;Lo;0;L;;;;;N;;;;; -1BC30;DUPLOYAN LETTER J N;Lo;0;L;;;;;N;;;;; -1BC31;DUPLOYAN LETTER J N S;Lo;0;L;;;;;N;;;;; -1BC32;DUPLOYAN LETTER S T;Lo;0;L;;;;;N;;;;; -1BC33;DUPLOYAN LETTER S T R;Lo;0;L;;;;;N;;;;; -1BC34;DUPLOYAN LETTER S P;Lo;0;L;;;;;N;;;;; -1BC35;DUPLOYAN LETTER S P R;Lo;0;L;;;;;N;;;;; -1BC36;DUPLOYAN LETTER T S;Lo;0;L;;;;;N;;;;; -1BC37;DUPLOYAN LETTER T R S;Lo;0;L;;;;;N;;;;; -1BC38;DUPLOYAN LETTER W;Lo;0;L;;;;;N;;;;; -1BC39;DUPLOYAN LETTER WH;Lo;0;L;;;;;N;;;;; -1BC3A;DUPLOYAN LETTER W R;Lo;0;L;;;;;N;;;;; -1BC3B;DUPLOYAN LETTER S N;Lo;0;L;;;;;N;;;;; -1BC3C;DUPLOYAN LETTER S M;Lo;0;L;;;;;N;;;;; -1BC3D;DUPLOYAN LETTER K R S;Lo;0;L;;;;;N;;;;; -1BC3E;DUPLOYAN LETTER G R S;Lo;0;L;;;;;N;;;;; -1BC3F;DUPLOYAN LETTER S K;Lo;0;L;;;;;N;;;;; -1BC40;DUPLOYAN LETTER S K R;Lo;0;L;;;;;N;;;;; -1BC41;DUPLOYAN LETTER A;Lo;0;L;;;;;N;;;;; -1BC42;DUPLOYAN LETTER SLOAN OW;Lo;0;L;;;;;N;;;;; -1BC43;DUPLOYAN LETTER OA;Lo;0;L;;;;;N;;;;; -1BC44;DUPLOYAN LETTER O;Lo;0;L;;;;;N;;;;; -1BC45;DUPLOYAN LETTER AOU;Lo;0;L;;;;;N;;;;; -1BC46;DUPLOYAN LETTER I;Lo;0;L;;;;;N;;;;; -1BC47;DUPLOYAN LETTER E;Lo;0;L;;;;;N;;;;; -1BC48;DUPLOYAN LETTER IE;Lo;0;L;;;;;N;;;;; -1BC49;DUPLOYAN LETTER SHORT I;Lo;0;L;;;;;N;;;;; -1BC4A;DUPLOYAN LETTER UI;Lo;0;L;;;;;N;;;;; -1BC4B;DUPLOYAN LETTER EE;Lo;0;L;;;;;N;;;;; -1BC4C;DUPLOYAN LETTER SLOAN EH;Lo;0;L;;;;;N;;;;; -1BC4D;DUPLOYAN LETTER ROMANIAN I;Lo;0;L;;;;;N;;;;; -1BC4E;DUPLOYAN LETTER SLOAN EE;Lo;0;L;;;;;N;;;;; -1BC4F;DUPLOYAN LETTER LONG I;Lo;0;L;;;;;N;;;;; -1BC50;DUPLOYAN LETTER YE;Lo;0;L;;;;;N;;;;; -1BC51;DUPLOYAN LETTER U;Lo;0;L;;;;;N;;;;; -1BC52;DUPLOYAN LETTER EU;Lo;0;L;;;;;N;;;;; -1BC53;DUPLOYAN LETTER XW;Lo;0;L;;;;;N;;;;; -1BC54;DUPLOYAN LETTER U N;Lo;0;L;;;;;N;;;;; -1BC55;DUPLOYAN LETTER LONG U;Lo;0;L;;;;;N;;;;; -1BC56;DUPLOYAN LETTER ROMANIAN U;Lo;0;L;;;;;N;;;;; -1BC57;DUPLOYAN LETTER UH;Lo;0;L;;;;;N;;;;; -1BC58;DUPLOYAN LETTER SLOAN U;Lo;0;L;;;;;N;;;;; -1BC59;DUPLOYAN LETTER OOH;Lo;0;L;;;;;N;;;;; -1BC5A;DUPLOYAN LETTER OW;Lo;0;L;;;;;N;;;;; -1BC5B;DUPLOYAN LETTER OU;Lo;0;L;;;;;N;;;;; -1BC5C;DUPLOYAN LETTER WA;Lo;0;L;;;;;N;;;;; -1BC5D;DUPLOYAN LETTER WO;Lo;0;L;;;;;N;;;;; -1BC5E;DUPLOYAN LETTER WI;Lo;0;L;;;;;N;;;;; -1BC5F;DUPLOYAN LETTER WEI;Lo;0;L;;;;;N;;;;; -1BC60;DUPLOYAN LETTER WOW;Lo;0;L;;;;;N;;;;; -1BC61;DUPLOYAN LETTER NASAL U;Lo;0;L;;;;;N;;;;; -1BC62;DUPLOYAN LETTER NASAL O;Lo;0;L;;;;;N;;;;; -1BC63;DUPLOYAN LETTER NASAL I;Lo;0;L;;;;;N;;;;; -1BC64;DUPLOYAN LETTER NASAL A;Lo;0;L;;;;;N;;;;; -1BC65;DUPLOYAN LETTER PERNIN AN;Lo;0;L;;;;;N;;;;; -1BC66;DUPLOYAN LETTER PERNIN AM;Lo;0;L;;;;;N;;;;; -1BC67;DUPLOYAN LETTER SLOAN EN;Lo;0;L;;;;;N;;;;; -1BC68;DUPLOYAN LETTER SLOAN AN;Lo;0;L;;;;;N;;;;; -1BC69;DUPLOYAN LETTER SLOAN ON;Lo;0;L;;;;;N;;;;; -1BC6A;DUPLOYAN LETTER VOCALIC M;Lo;0;L;;;;;N;;;;; -1BC70;DUPLOYAN AFFIX LEFT HORIZONTAL SECANT;Lo;0;L;;;;;N;;;;; -1BC71;DUPLOYAN AFFIX MID HORIZONTAL SECANT;Lo;0;L;;;;;N;;;;; -1BC72;DUPLOYAN AFFIX RIGHT HORIZONTAL SECANT;Lo;0;L;;;;;N;;;;; -1BC73;DUPLOYAN AFFIX LOW VERTICAL SECANT;Lo;0;L;;;;;N;;;;; -1BC74;DUPLOYAN AFFIX MID VERTICAL SECANT;Lo;0;L;;;;;N;;;;; -1BC75;DUPLOYAN AFFIX HIGH VERTICAL SECANT;Lo;0;L;;;;;N;;;;; -1BC76;DUPLOYAN AFFIX ATTACHED SECANT;Lo;0;L;;;;;N;;;;; -1BC77;DUPLOYAN AFFIX ATTACHED LEFT-TO-RIGHT SECANT;Lo;0;L;;;;;N;;;;; -1BC78;DUPLOYAN AFFIX ATTACHED TANGENT;Lo;0;L;;;;;N;;;;; -1BC79;DUPLOYAN AFFIX ATTACHED TAIL;Lo;0;L;;;;;N;;;;; -1BC7A;DUPLOYAN AFFIX ATTACHED E HOOK;Lo;0;L;;;;;N;;;;; -1BC7B;DUPLOYAN AFFIX ATTACHED I HOOK;Lo;0;L;;;;;N;;;;; -1BC7C;DUPLOYAN AFFIX ATTACHED TANGENT HOOK;Lo;0;L;;;;;N;;;;; -1BC80;DUPLOYAN AFFIX HIGH ACUTE;Lo;0;L;;;;;N;;;;; -1BC81;DUPLOYAN AFFIX HIGH TIGHT ACUTE;Lo;0;L;;;;;N;;;;; -1BC82;DUPLOYAN AFFIX HIGH GRAVE;Lo;0;L;;;;;N;;;;; -1BC83;DUPLOYAN AFFIX HIGH LONG GRAVE;Lo;0;L;;;;;N;;;;; -1BC84;DUPLOYAN AFFIX HIGH DOT;Lo;0;L;;;;;N;;;;; -1BC85;DUPLOYAN AFFIX HIGH CIRCLE;Lo;0;L;;;;;N;;;;; -1BC86;DUPLOYAN AFFIX HIGH LINE;Lo;0;L;;;;;N;;;;; -1BC87;DUPLOYAN AFFIX HIGH WAVE;Lo;0;L;;;;;N;;;;; -1BC88;DUPLOYAN AFFIX HIGH VERTICAL;Lo;0;L;;;;;N;;;;; -1BC90;DUPLOYAN AFFIX LOW ACUTE;Lo;0;L;;;;;N;;;;; -1BC91;DUPLOYAN AFFIX LOW TIGHT ACUTE;Lo;0;L;;;;;N;;;;; -1BC92;DUPLOYAN AFFIX LOW GRAVE;Lo;0;L;;;;;N;;;;; -1BC93;DUPLOYAN AFFIX LOW LONG GRAVE;Lo;0;L;;;;;N;;;;; -1BC94;DUPLOYAN AFFIX LOW DOT;Lo;0;L;;;;;N;;;;; -1BC95;DUPLOYAN AFFIX LOW CIRCLE;Lo;0;L;;;;;N;;;;; -1BC96;DUPLOYAN AFFIX LOW LINE;Lo;0;L;;;;;N;;;;; -1BC97;DUPLOYAN AFFIX LOW WAVE;Lo;0;L;;;;;N;;;;; -1BC98;DUPLOYAN AFFIX LOW VERTICAL;Lo;0;L;;;;;N;;;;; -1BC99;DUPLOYAN AFFIX LOW ARROW;Lo;0;L;;;;;N;;;;; -1BC9C;DUPLOYAN SIGN O WITH CROSS;So;0;L;;;;;N;;;;; -1BC9D;DUPLOYAN THICK LETTER SELECTOR;Mn;0;NSM;;;;;N;;;;; -1BC9E;DUPLOYAN DOUBLE MARK;Mn;1;NSM;;;;;N;;;;; -1BC9F;DUPLOYAN PUNCTUATION CHINOOK FULL STOP;Po;0;L;;;;;N;;;;; -1BCA0;SHORTHAND FORMAT LETTER OVERLAP;Cf;0;BN;;;;;N;;;;; -1BCA1;SHORTHAND FORMAT CONTINUING OVERLAP;Cf;0;BN;;;;;N;;;;; -1BCA2;SHORTHAND FORMAT DOWN STEP;Cf;0;BN;;;;;N;;;;; -1BCA3;SHORTHAND FORMAT UP STEP;Cf;0;BN;;;;;N;;;;; -1CF00;ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT;Mn;0;NSM;;;;;N;;;;; -1CF01;ZNAMENNY COMBINING MARK NIZKO S KRYZHEM ON LEFT;Mn;0;NSM;;;;;N;;;;; -1CF02;ZNAMENNY COMBINING MARK TSATA ON LEFT;Mn;0;NSM;;;;;N;;;;; -1CF03;ZNAMENNY COMBINING MARK GORAZDO NIZKO ON LEFT;Mn;0;NSM;;;;;N;;;;; -1CF04;ZNAMENNY COMBINING MARK NIZKO ON LEFT;Mn;0;NSM;;;;;N;;;;; -1CF05;ZNAMENNY COMBINING MARK SREDNE ON LEFT;Mn;0;NSM;;;;;N;;;;; -1CF06;ZNAMENNY COMBINING MARK MALO POVYSHE ON LEFT;Mn;0;NSM;;;;;N;;;;; -1CF07;ZNAMENNY COMBINING MARK POVYSHE ON LEFT;Mn;0;NSM;;;;;N;;;;; -1CF08;ZNAMENNY COMBINING MARK VYSOKO ON LEFT;Mn;0;NSM;;;;;N;;;;; -1CF09;ZNAMENNY COMBINING MARK MALO POVYSHE S KHOKHLOM ON LEFT;Mn;0;NSM;;;;;N;;;;; -1CF0A;ZNAMENNY COMBINING MARK POVYSHE S KHOKHLOM ON LEFT;Mn;0;NSM;;;;;N;;;;; -1CF0B;ZNAMENNY COMBINING MARK VYSOKO S KHOKHLOM ON LEFT;Mn;0;NSM;;;;;N;;;;; -1CF0C;ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON RIGHT;Mn;0;NSM;;;;;N;;;;; -1CF0D;ZNAMENNY COMBINING MARK NIZKO S KRYZHEM ON RIGHT;Mn;0;NSM;;;;;N;;;;; -1CF0E;ZNAMENNY COMBINING MARK TSATA ON RIGHT;Mn;0;NSM;;;;;N;;;;; -1CF0F;ZNAMENNY COMBINING MARK GORAZDO NIZKO ON RIGHT;Mn;0;NSM;;;;;N;;;;; -1CF10;ZNAMENNY COMBINING MARK NIZKO ON RIGHT;Mn;0;NSM;;;;;N;;;;; -1CF11;ZNAMENNY COMBINING MARK SREDNE ON RIGHT;Mn;0;NSM;;;;;N;;;;; -1CF12;ZNAMENNY COMBINING MARK MALO POVYSHE ON RIGHT;Mn;0;NSM;;;;;N;;;;; -1CF13;ZNAMENNY COMBINING MARK POVYSHE ON RIGHT;Mn;0;NSM;;;;;N;;;;; -1CF14;ZNAMENNY COMBINING MARK VYSOKO ON RIGHT;Mn;0;NSM;;;;;N;;;;; -1CF15;ZNAMENNY COMBINING MARK MALO POVYSHE S KHOKHLOM ON RIGHT;Mn;0;NSM;;;;;N;;;;; -1CF16;ZNAMENNY COMBINING MARK POVYSHE S KHOKHLOM ON RIGHT;Mn;0;NSM;;;;;N;;;;; -1CF17;ZNAMENNY COMBINING MARK VYSOKO S KHOKHLOM ON RIGHT;Mn;0;NSM;;;;;N;;;;; -1CF18;ZNAMENNY COMBINING MARK TSATA S KRYZHEM;Mn;0;NSM;;;;;N;;;;; -1CF19;ZNAMENNY COMBINING MARK MALO POVYSHE S KRYZHEM;Mn;0;NSM;;;;;N;;;;; -1CF1A;ZNAMENNY COMBINING MARK STRANNO MALO POVYSHE;Mn;0;NSM;;;;;N;;;;; -1CF1B;ZNAMENNY COMBINING MARK POVYSHE S KRYZHEM;Mn;0;NSM;;;;;N;;;;; -1CF1C;ZNAMENNY COMBINING MARK POVYSHE STRANNO;Mn;0;NSM;;;;;N;;;;; -1CF1D;ZNAMENNY COMBINING MARK VYSOKO S KRYZHEM;Mn;0;NSM;;;;;N;;;;; -1CF1E;ZNAMENNY COMBINING MARK MALO POVYSHE STRANNO;Mn;0;NSM;;;;;N;;;;; -1CF1F;ZNAMENNY COMBINING MARK GORAZDO VYSOKO;Mn;0;NSM;;;;;N;;;;; -1CF20;ZNAMENNY COMBINING MARK ZELO;Mn;0;NSM;;;;;N;;;;; -1CF21;ZNAMENNY COMBINING MARK ON;Mn;0;NSM;;;;;N;;;;; -1CF22;ZNAMENNY COMBINING MARK RAVNO;Mn;0;NSM;;;;;N;;;;; -1CF23;ZNAMENNY COMBINING MARK TIKHAYA;Mn;0;NSM;;;;;N;;;;; -1CF24;ZNAMENNY COMBINING MARK BORZAYA;Mn;0;NSM;;;;;N;;;;; -1CF25;ZNAMENNY COMBINING MARK UDARKA;Mn;0;NSM;;;;;N;;;;; -1CF26;ZNAMENNY COMBINING MARK PODVERTKA;Mn;0;NSM;;;;;N;;;;; -1CF27;ZNAMENNY COMBINING MARK LOMKA;Mn;0;NSM;;;;;N;;;;; -1CF28;ZNAMENNY COMBINING MARK KUPNAYA;Mn;0;NSM;;;;;N;;;;; -1CF29;ZNAMENNY COMBINING MARK KACHKA;Mn;0;NSM;;;;;N;;;;; -1CF2A;ZNAMENNY COMBINING MARK ZEVOK;Mn;0;NSM;;;;;N;;;;; -1CF2B;ZNAMENNY COMBINING MARK SKOBA;Mn;0;NSM;;;;;N;;;;; -1CF2C;ZNAMENNY COMBINING MARK RAZSEKA;Mn;0;NSM;;;;;N;;;;; -1CF2D;ZNAMENNY COMBINING MARK KRYZH ON LEFT;Mn;0;NSM;;;;;N;;;;; -1CF30;ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO;Mn;0;NSM;;;;;N;;;;; -1CF31;ZNAMENNY COMBINING TONAL RANGE MARK SVETLO;Mn;0;NSM;;;;;N;;;;; -1CF32;ZNAMENNY COMBINING TONAL RANGE MARK TRESVETLO;Mn;0;NSM;;;;;N;;;;; -1CF33;ZNAMENNY COMBINING MARK ZADERZHKA;Mn;0;NSM;;;;;N;;;;; -1CF34;ZNAMENNY COMBINING MARK DEMESTVENNY ZADERZHKA;Mn;0;NSM;;;;;N;;;;; -1CF35;ZNAMENNY COMBINING MARK OTSECHKA;Mn;0;NSM;;;;;N;;;;; -1CF36;ZNAMENNY COMBINING MARK PODCHASHIE;Mn;0;NSM;;;;;N;;;;; -1CF37;ZNAMENNY COMBINING MARK PODCHASHIE WITH VERTICAL STROKE;Mn;0;NSM;;;;;N;;;;; -1CF38;ZNAMENNY COMBINING MARK CHASHKA;Mn;0;NSM;;;;;N;;;;; -1CF39;ZNAMENNY COMBINING MARK CHASHKA POLNAYA;Mn;0;NSM;;;;;N;;;;; -1CF3A;ZNAMENNY COMBINING MARK OBLACHKO;Mn;0;NSM;;;;;N;;;;; -1CF3B;ZNAMENNY COMBINING MARK SOROCHYA NOZHKA;Mn;0;NSM;;;;;N;;;;; -1CF3C;ZNAMENNY COMBINING MARK TOCHKA;Mn;0;NSM;;;;;N;;;;; -1CF3D;ZNAMENNY COMBINING MARK DVOETOCHIE;Mn;0;NSM;;;;;N;;;;; -1CF3E;ZNAMENNY COMBINING ATTACHING VERTICAL OMET;Mn;0;NSM;;;;;N;;;;; -1CF3F;ZNAMENNY COMBINING MARK CURVED OMET;Mn;0;NSM;;;;;N;;;;; -1CF40;ZNAMENNY COMBINING MARK KRYZH;Mn;0;NSM;;;;;N;;;;; -1CF41;ZNAMENNY COMBINING LOWER TONAL RANGE INDICATOR;Mn;0;NSM;;;;;N;;;;; -1CF42;ZNAMENNY PRIZNAK MODIFIER LEVEL-2;Mn;0;NSM;;;;;N;;;;; -1CF43;ZNAMENNY PRIZNAK MODIFIER LEVEL-3;Mn;0;NSM;;;;;N;;;;; -1CF44;ZNAMENNY PRIZNAK MODIFIER DIRECTION FLIP;Mn;0;NSM;;;;;N;;;;; -1CF45;ZNAMENNY PRIZNAK MODIFIER KRYZH;Mn;0;NSM;;;;;N;;;;; -1CF46;ZNAMENNY PRIZNAK MODIFIER ROG;Mn;0;NSM;;;;;N;;;;; -1CF50;ZNAMENNY NEUME KRYUK;So;0;L;;;;;N;;;;; -1CF51;ZNAMENNY NEUME KRYUK TIKHY;So;0;L;;;;;N;;;;; -1CF52;ZNAMENNY NEUME PARAKLIT;So;0;L;;;;;N;;;;; -1CF53;ZNAMENNY NEUME DVA V CHELNU;So;0;L;;;;;N;;;;; -1CF54;ZNAMENNY NEUME KLYUCH;So;0;L;;;;;N;;;;; -1CF55;ZNAMENNY NEUME ZANOZHEK;So;0;L;;;;;N;;;;; -1CF56;ZNAMENNY NEUME STOPITSA;So;0;L;;;;;N;;;;; -1CF57;ZNAMENNY NEUME STOPITSA S OCHKOM;So;0;L;;;;;N;;;;; -1CF58;ZNAMENNY NEUME PEREVODKA;So;0;L;;;;;N;;;;; -1CF59;ZNAMENNY NEUME PEREVODKA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;; -1CF5A;ZNAMENNY NEUME STOPITSA WITH SOROCHYA NOZHKA;So;0;L;;;;;N;;;;; -1CF5B;ZNAMENNY NEUME CHELYUSTKA;So;0;L;;;;;N;;;;; -1CF5C;ZNAMENNY NEUME PALKA;So;0;L;;;;;N;;;;; -1CF5D;ZNAMENNY NEUME ZAPYATAYA;So;0;L;;;;;N;;;;; -1CF5E;ZNAMENNY NEUME GOLUBCHIK BORZY;So;0;L;;;;;N;;;;; -1CF5F;ZNAMENNY NEUME GOLUBCHIK TIKHY;So;0;L;;;;;N;;;;; -1CF60;ZNAMENNY NEUME GOLUBCHIK MRACHNY;So;0;L;;;;;N;;;;; -1CF61;ZNAMENNY NEUME GOLUBCHIK SVETLY;So;0;L;;;;;N;;;;; -1CF62;ZNAMENNY NEUME GOLUBCHIK TRESVETLY;So;0;L;;;;;N;;;;; -1CF63;ZNAMENNY NEUME VRAKHIYA PROSTAYA;So;0;L;;;;;N;;;;; -1CF64;ZNAMENNY NEUME VRAKHIYA MRACHNAYA;So;0;L;;;;;N;;;;; -1CF65;ZNAMENNY NEUME VRAKHIYA SVETLAYA;So;0;L;;;;;N;;;;; -1CF66;ZNAMENNY NEUME VRAKHIYA TRESVETLAYA;So;0;L;;;;;N;;;;; -1CF67;ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA PROSTAYA;So;0;L;;;;;N;;;;; -1CF68;ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA MRACHNAYA;So;0;L;;;;;N;;;;; -1CF69;ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA SVETLAYA;So;0;L;;;;;N;;;;; -1CF6A;ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA TRESVETLAYA;So;0;L;;;;;N;;;;; -1CF6B;ZNAMENNY NEUME DOUBLE ZAPYATAYA;So;0;L;;;;;N;;;;; -1CF6C;ZNAMENNY NEUME REVERSED CHELYUSTKA;So;0;L;;;;;N;;;;; -1CF6D;ZNAMENNY NEUME DERBITSA;So;0;L;;;;;N;;;;; -1CF6E;ZNAMENNY NEUME KHAMILO;So;0;L;;;;;N;;;;; -1CF6F;ZNAMENNY NEUME CHASHKA;So;0;L;;;;;N;;;;; -1CF70;ZNAMENNY NEUME PODCHASHIE;So;0;L;;;;;N;;;;; -1CF71;ZNAMENNY NEUME SKAMEYTSA MRACHNAYA;So;0;L;;;;;N;;;;; -1CF72;ZNAMENNY NEUME SKAMEYTSA SVETLAYA;So;0;L;;;;;N;;;;; -1CF73;ZNAMENNY NEUME SKAMEYTSA TRESVETLAYA;So;0;L;;;;;N;;;;; -1CF74;ZNAMENNY NEUME SKAMEYTSA TIKHAYA;So;0;L;;;;;N;;;;; -1CF75;ZNAMENNY NEUME DEMESTVENNY KLYUCH;So;0;L;;;;;N;;;;; -1CF76;ZNAMENNY NEUME SKAMEYTSA KLYUCHEVAYA SVETLAYA;So;0;L;;;;;N;;;;; -1CF77;ZNAMENNY NEUME SKAMEYTSA KLYUCHENEPOSTOYANNAYA;So;0;L;;;;;N;;;;; -1CF78;ZNAMENNY NEUME SKAMEYTSA KLYUCHEVAYA TIKHAYA;So;0;L;;;;;N;;;;; -1CF79;ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA PROSTAYA;So;0;L;;;;;N;;;;; -1CF7A;ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA SVETLAYA;So;0;L;;;;;N;;;;; -1CF7B;ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;; -1CF7C;ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA KLYUCHEVAYA;So;0;L;;;;;N;;;;; -1CF7D;ZNAMENNY NEUME SLOZHITIE;So;0;L;;;;;N;;;;; -1CF7E;ZNAMENNY NEUME SLOZHITIE S ZAPYATOY;So;0;L;;;;;N;;;;; -1CF7F;ZNAMENNY NEUME SLOZHITIE ZAKRYTOE;So;0;L;;;;;N;;;;; -1CF80;ZNAMENNY NEUME SLOZHITIE S KRYZHEM;So;0;L;;;;;N;;;;; -1CF81;ZNAMENNY NEUME KRYZH;So;0;L;;;;;N;;;;; -1CF82;ZNAMENNY NEUME ROG;So;0;L;;;;;N;;;;; -1CF83;ZNAMENNY NEUME FITA;So;0;L;;;;;N;;;;; -1CF84;ZNAMENNY NEUME KOBYLA;So;0;L;;;;;N;;;;; -1CF85;ZNAMENNY NEUME ZMEYTSA;So;0;L;;;;;N;;;;; -1CF86;ZNAMENNY NEUME STATYA;So;0;L;;;;;N;;;;; -1CF87;ZNAMENNY NEUME STATYA S ZAPYATOY;So;0;L;;;;;N;;;;; -1CF88;ZNAMENNY NEUME STATYA S KRYZHEM;So;0;L;;;;;N;;;;; -1CF89;ZNAMENNY NEUME STATYA S ZAPYATOY I KRYZHEM;So;0;L;;;;;N;;;;; -1CF8A;ZNAMENNY NEUME STATYA S KRYZHEM I ZAPYATOY;So;0;L;;;;;N;;;;; -1CF8B;ZNAMENNY NEUME STATYA ZAKRYTAYA;So;0;L;;;;;N;;;;; -1CF8C;ZNAMENNY NEUME STATYA ZAKRYTAYA S ZAPYATOY;So;0;L;;;;;N;;;;; -1CF8D;ZNAMENNY NEUME STATYA S ROGOM;So;0;L;;;;;N;;;;; -1CF8E;ZNAMENNY NEUME STATYA S DVUMYA ZAPYATYMI;So;0;L;;;;;N;;;;; -1CF8F;ZNAMENNY NEUME STATYA S ZAPYATOY I PODCHASHIEM;So;0;L;;;;;N;;;;; -1CF90;ZNAMENNY NEUME POLKULIZMY;So;0;L;;;;;N;;;;; -1CF91;ZNAMENNY NEUME STATYA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;; -1CF92;ZNAMENNY NEUME STRELA PROSTAYA;So;0;L;;;;;N;;;;; -1CF93;ZNAMENNY NEUME STRELA MRACHNOTIKHAYA;So;0;L;;;;;N;;;;; -1CF94;ZNAMENNY NEUME STRELA KRYZHEVAYA;So;0;L;;;;;N;;;;; -1CF95;ZNAMENNY NEUME STRELA POLUPOVODNAYA;So;0;L;;;;;N;;;;; -1CF96;ZNAMENNY NEUME STRELA POVODNAYA;So;0;L;;;;;N;;;;; -1CF97;ZNAMENNY NEUME STRELA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;; -1CF98;ZNAMENNY NEUME STRELA KLYUCHEPOVODNAYA;So;0;L;;;;;N;;;;; -1CF99;ZNAMENNY NEUME STRELA KLYUCHENEPOSTOYANNAYA;So;0;L;;;;;N;;;;; -1CF9A;ZNAMENNY NEUME STRELA TIKHAYA PUTNAYA;So;0;L;;;;;N;;;;; -1CF9B;ZNAMENNY NEUME STRELA DVOECHELNAYA;So;0;L;;;;;N;;;;; -1CF9C;ZNAMENNY NEUME STRELA DVOECHELNOKRYZHEVAYA;So;0;L;;;;;N;;;;; -1CF9D;ZNAMENNY NEUME STRELA DVOECHELNOPOVODNAYA;So;0;L;;;;;N;;;;; -1CF9E;ZNAMENNY NEUME STRELA DVOECHELNAYA KLYUCHEVAYA;So;0;L;;;;;N;;;;; -1CF9F;ZNAMENNY NEUME STRELA DVOECHELNOPOVODNAYA KLYUCHEVAYA;So;0;L;;;;;N;;;;; -1CFA0;ZNAMENNY NEUME STRELA GROMNAYA WITH SINGLE ZAPYATAYA;So;0;L;;;;;N;;;;; -1CFA1;ZNAMENNY NEUME STRELA GROMOPOVODNAYA WITH SINGLE ZAPYATAYA;So;0;L;;;;;N;;;;; -1CFA2;ZNAMENNY NEUME STRELA GROMNAYA;So;0;L;;;;;N;;;;; -1CFA3;ZNAMENNY NEUME STRELA GROMOPOVODNAYA;So;0;L;;;;;N;;;;; -1CFA4;ZNAMENNY NEUME STRELA GROMOPOVODNAYA WITH DOUBLE ZAPYATAYA;So;0;L;;;;;N;;;;; -1CFA5;ZNAMENNY NEUME STRELA GROMOKRYZHEVAYA;So;0;L;;;;;N;;;;; -1CFA6;ZNAMENNY NEUME STRELA GROMOKRYZHEVAYA POVODNAYA;So;0;L;;;;;N;;;;; -1CFA7;ZNAMENNY NEUME MECHIK;So;0;L;;;;;N;;;;; -1CFA8;ZNAMENNY NEUME MECHIK POVODNY;So;0;L;;;;;N;;;;; -1CFA9;ZNAMENNY NEUME MECHIK KLYUCHEVOY;So;0;L;;;;;N;;;;; -1CFAA;ZNAMENNY NEUME MECHIK KLYUCHEPOVODNY;So;0;L;;;;;N;;;;; -1CFAB;ZNAMENNY NEUME MECHIK KLYUCHENEPOSTOYANNY;So;0;L;;;;;N;;;;; -1CFAC;ZNAMENNY NEUME STRELA TRYASOGLASNAYA;So;0;L;;;;;N;;;;; -1CFAD;ZNAMENNY NEUME STRELA TRYASOPOVODNAYA;So;0;L;;;;;N;;;;; -1CFAE;ZNAMENNY NEUME STRELA TRYASOSTRELNAYA;So;0;L;;;;;N;;;;; -1CFAF;ZNAMENNY NEUME OSOKA;So;0;L;;;;;N;;;;; -1CFB0;ZNAMENNY NEUME OSOKA SVETLAYA;So;0;L;;;;;N;;;;; -1CFB1;ZNAMENNY NEUME OSOKA TRESVETLAYA;So;0;L;;;;;N;;;;; -1CFB2;ZNAMENNY NEUME OSOKA KRYUKOVAYA SVETLAYA;So;0;L;;;;;N;;;;; -1CFB3;ZNAMENNY NEUME OSOKA KLYUCHEVAYA SVETLAYA;So;0;L;;;;;N;;;;; -1CFB4;ZNAMENNY NEUME OSOKA KLYUCHEVAYA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;; -1CFB5;ZNAMENNY NEUME STRELA KRYUKOVAYA;So;0;L;;;;;N;;;;; -1CFB6;ZNAMENNY NEUME STRELA KRYUKOVAYA POVODNAYA;So;0;L;;;;;N;;;;; -1CFB7;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMNAYA WITH SINGLE ZAPYATAYA;So;0;L;;;;;N;;;;; -1CFB8;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOPOVODNAYA WITH SINGLE ZAPYATAYA;So;0;L;;;;;N;;;;; -1CFB9;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMNAYA;So;0;L;;;;;N;;;;; -1CFBA;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOPOVODNAYA;So;0;L;;;;;N;;;;; -1CFBB;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOPOVODNAYA WITH DOUBLE ZAPYATAYA;So;0;L;;;;;N;;;;; -1CFBC;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOKRYZHEVAYA;So;0;L;;;;;N;;;;; -1CFBD;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOKRYZHEVAYA POVODNAYA;So;0;L;;;;;N;;;;; -1CFBE;ZNAMENNY NEUME STRELA KRYUKOVAYA TRYASKA;So;0;L;;;;;N;;;;; -1CFBF;ZNAMENNY NEUME KUFISMA;So;0;L;;;;;N;;;;; -1CFC0;ZNAMENNY NEUME OBLAKO;So;0;L;;;;;N;;;;; -1CFC1;ZNAMENNY NEUME DUDA;So;0;L;;;;;N;;;;; -1CFC2;ZNAMENNY NEUME NEMKA;So;0;L;;;;;N;;;;; -1CFC3;ZNAMENNY NEUME PAUK;So;0;L;;;;;N;;;;; -1D000;BYZANTINE MUSICAL SYMBOL PSILI;So;0;L;;;;;N;;;;; -1D001;BYZANTINE MUSICAL SYMBOL DASEIA;So;0;L;;;;;N;;;;; -1D002;BYZANTINE MUSICAL SYMBOL PERISPOMENI;So;0;L;;;;;N;;;;; -1D003;BYZANTINE MUSICAL SYMBOL OXEIA EKFONITIKON;So;0;L;;;;;N;;;;; -1D004;BYZANTINE MUSICAL SYMBOL OXEIA DIPLI;So;0;L;;;;;N;;;;; -1D005;BYZANTINE MUSICAL SYMBOL VAREIA EKFONITIKON;So;0;L;;;;;N;;;;; -1D006;BYZANTINE MUSICAL SYMBOL VAREIA DIPLI;So;0;L;;;;;N;;;;; -1D007;BYZANTINE MUSICAL SYMBOL KATHISTI;So;0;L;;;;;N;;;;; -1D008;BYZANTINE MUSICAL SYMBOL SYRMATIKI;So;0;L;;;;;N;;;;; -1D009;BYZANTINE MUSICAL SYMBOL PARAKLITIKI;So;0;L;;;;;N;;;;; -1D00A;BYZANTINE MUSICAL SYMBOL YPOKRISIS;So;0;L;;;;;N;;;;; -1D00B;BYZANTINE MUSICAL SYMBOL YPOKRISIS DIPLI;So;0;L;;;;;N;;;;; -1D00C;BYZANTINE MUSICAL SYMBOL KREMASTI;So;0;L;;;;;N;;;;; -1D00D;BYZANTINE MUSICAL SYMBOL APESO EKFONITIKON;So;0;L;;;;;N;;;;; -1D00E;BYZANTINE MUSICAL SYMBOL EXO EKFONITIKON;So;0;L;;;;;N;;;;; -1D00F;BYZANTINE MUSICAL SYMBOL TELEIA;So;0;L;;;;;N;;;;; -1D010;BYZANTINE MUSICAL SYMBOL KENTIMATA;So;0;L;;;;;N;;;;; -1D011;BYZANTINE MUSICAL SYMBOL APOSTROFOS;So;0;L;;;;;N;;;;; -1D012;BYZANTINE MUSICAL SYMBOL APOSTROFOS DIPLI;So;0;L;;;;;N;;;;; -1D013;BYZANTINE MUSICAL SYMBOL SYNEVMA;So;0;L;;;;;N;;;;; -1D014;BYZANTINE MUSICAL SYMBOL THITA;So;0;L;;;;;N;;;;; -1D015;BYZANTINE MUSICAL SYMBOL OLIGON ARCHAION;So;0;L;;;;;N;;;;; -1D016;BYZANTINE MUSICAL SYMBOL GORGON ARCHAION;So;0;L;;;;;N;;;;; -1D017;BYZANTINE MUSICAL SYMBOL PSILON;So;0;L;;;;;N;;;;; -1D018;BYZANTINE MUSICAL SYMBOL CHAMILON;So;0;L;;;;;N;;;;; -1D019;BYZANTINE MUSICAL SYMBOL VATHY;So;0;L;;;;;N;;;;; -1D01A;BYZANTINE MUSICAL SYMBOL ISON ARCHAION;So;0;L;;;;;N;;;;; -1D01B;BYZANTINE MUSICAL SYMBOL KENTIMA ARCHAION;So;0;L;;;;;N;;;;; -1D01C;BYZANTINE MUSICAL SYMBOL KENTIMATA ARCHAION;So;0;L;;;;;N;;;;; -1D01D;BYZANTINE MUSICAL SYMBOL SAXIMATA;So;0;L;;;;;N;;;;; -1D01E;BYZANTINE MUSICAL SYMBOL PARICHON;So;0;L;;;;;N;;;;; -1D01F;BYZANTINE MUSICAL SYMBOL STAVROS APODEXIA;So;0;L;;;;;N;;;;; -1D020;BYZANTINE MUSICAL SYMBOL OXEIAI ARCHAION;So;0;L;;;;;N;;;;; -1D021;BYZANTINE MUSICAL SYMBOL VAREIAI ARCHAION;So;0;L;;;;;N;;;;; -1D022;BYZANTINE MUSICAL SYMBOL APODERMA ARCHAION;So;0;L;;;;;N;;;;; -1D023;BYZANTINE MUSICAL SYMBOL APOTHEMA;So;0;L;;;;;N;;;;; -1D024;BYZANTINE MUSICAL SYMBOL KLASMA;So;0;L;;;;;N;;;;; -1D025;BYZANTINE MUSICAL SYMBOL REVMA;So;0;L;;;;;N;;;;; -1D026;BYZANTINE MUSICAL SYMBOL PIASMA ARCHAION;So;0;L;;;;;N;;;;; -1D027;BYZANTINE MUSICAL SYMBOL TINAGMA;So;0;L;;;;;N;;;;; -1D028;BYZANTINE MUSICAL SYMBOL ANATRICHISMA;So;0;L;;;;;N;;;;; -1D029;BYZANTINE MUSICAL SYMBOL SEISMA;So;0;L;;;;;N;;;;; -1D02A;BYZANTINE MUSICAL SYMBOL SYNAGMA ARCHAION;So;0;L;;;;;N;;;;; -1D02B;BYZANTINE MUSICAL SYMBOL SYNAGMA META STAVROU;So;0;L;;;;;N;;;;; -1D02C;BYZANTINE MUSICAL SYMBOL OYRANISMA ARCHAION;So;0;L;;;;;N;;;;; -1D02D;BYZANTINE MUSICAL SYMBOL THEMA;So;0;L;;;;;N;;;;; -1D02E;BYZANTINE MUSICAL SYMBOL LEMOI;So;0;L;;;;;N;;;;; -1D02F;BYZANTINE MUSICAL SYMBOL DYO;So;0;L;;;;;N;;;;; -1D030;BYZANTINE MUSICAL SYMBOL TRIA;So;0;L;;;;;N;;;;; -1D031;BYZANTINE MUSICAL SYMBOL TESSERA;So;0;L;;;;;N;;;;; -1D032;BYZANTINE MUSICAL SYMBOL KRATIMATA;So;0;L;;;;;N;;;;; -1D033;BYZANTINE MUSICAL SYMBOL APESO EXO NEO;So;0;L;;;;;N;;;;; -1D034;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION;So;0;L;;;;;N;;;;; -1D035;BYZANTINE MUSICAL SYMBOL IMIFTHORA;So;0;L;;;;;N;;;;; -1D036;BYZANTINE MUSICAL SYMBOL TROMIKON ARCHAION;So;0;L;;;;;N;;;;; -1D037;BYZANTINE MUSICAL SYMBOL KATAVA TROMIKON;So;0;L;;;;;N;;;;; -1D038;BYZANTINE MUSICAL SYMBOL PELASTON;So;0;L;;;;;N;;;;; -1D039;BYZANTINE MUSICAL SYMBOL PSIFISTON;So;0;L;;;;;N;;;;; -1D03A;BYZANTINE MUSICAL SYMBOL KONTEVMA;So;0;L;;;;;N;;;;; -1D03B;BYZANTINE MUSICAL SYMBOL CHOREVMA ARCHAION;So;0;L;;;;;N;;;;; -1D03C;BYZANTINE MUSICAL SYMBOL RAPISMA;So;0;L;;;;;N;;;;; -1D03D;BYZANTINE MUSICAL SYMBOL PARAKALESMA ARCHAION;So;0;L;;;;;N;;;;; -1D03E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI ARCHAION;So;0;L;;;;;N;;;;; -1D03F;BYZANTINE MUSICAL SYMBOL ICHADIN;So;0;L;;;;;N;;;;; -1D040;BYZANTINE MUSICAL SYMBOL NANA;So;0;L;;;;;N;;;;; -1D041;BYZANTINE MUSICAL SYMBOL PETASMA;So;0;L;;;;;N;;;;; -1D042;BYZANTINE MUSICAL SYMBOL KONTEVMA ALLO;So;0;L;;;;;N;;;;; -1D043;BYZANTINE MUSICAL SYMBOL TROMIKON ALLO;So;0;L;;;;;N;;;;; -1D044;BYZANTINE MUSICAL SYMBOL STRAGGISMATA;So;0;L;;;;;N;;;;; -1D045;BYZANTINE MUSICAL SYMBOL GRONTHISMATA;So;0;L;;;;;N;;;;; -1D046;BYZANTINE MUSICAL SYMBOL ISON NEO;So;0;L;;;;;N;;;;; -1D047;BYZANTINE MUSICAL SYMBOL OLIGON NEO;So;0;L;;;;;N;;;;; -1D048;BYZANTINE MUSICAL SYMBOL OXEIA NEO;So;0;L;;;;;N;;;;; -1D049;BYZANTINE MUSICAL SYMBOL PETASTI;So;0;L;;;;;N;;;;; -1D04A;BYZANTINE MUSICAL SYMBOL KOUFISMA;So;0;L;;;;;N;;;;; -1D04B;BYZANTINE MUSICAL SYMBOL PETASTOKOUFISMA;So;0;L;;;;;N;;;;; -1D04C;BYZANTINE MUSICAL SYMBOL KRATIMOKOUFISMA;So;0;L;;;;;N;;;;; -1D04D;BYZANTINE MUSICAL SYMBOL PELASTON NEO;So;0;L;;;;;N;;;;; -1D04E;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO ANO;So;0;L;;;;;N;;;;; -1D04F;BYZANTINE MUSICAL SYMBOL KENTIMA NEO ANO;So;0;L;;;;;N;;;;; -1D050;BYZANTINE MUSICAL SYMBOL YPSILI;So;0;L;;;;;N;;;;; -1D051;BYZANTINE MUSICAL SYMBOL APOSTROFOS NEO;So;0;L;;;;;N;;;;; -1D052;BYZANTINE MUSICAL SYMBOL APOSTROFOI SYNDESMOS NEO;So;0;L;;;;;N;;;;; -1D053;BYZANTINE MUSICAL SYMBOL YPORROI;So;0;L;;;;;N;;;;; -1D054;BYZANTINE MUSICAL SYMBOL KRATIMOYPORROON;So;0;L;;;;;N;;;;; -1D055;BYZANTINE MUSICAL SYMBOL ELAFRON;So;0;L;;;;;N;;;;; -1D056;BYZANTINE MUSICAL SYMBOL CHAMILI;So;0;L;;;;;N;;;;; -1D057;BYZANTINE MUSICAL SYMBOL MIKRON ISON;So;0;L;;;;;N;;;;; -1D058;BYZANTINE MUSICAL SYMBOL VAREIA NEO;So;0;L;;;;;N;;;;; -1D059;BYZANTINE MUSICAL SYMBOL PIASMA NEO;So;0;L;;;;;N;;;;; -1D05A;BYZANTINE MUSICAL SYMBOL PSIFISTON NEO;So;0;L;;;;;N;;;;; -1D05B;BYZANTINE MUSICAL SYMBOL OMALON;So;0;L;;;;;N;;;;; -1D05C;BYZANTINE MUSICAL SYMBOL ANTIKENOMA;So;0;L;;;;;N;;;;; -1D05D;BYZANTINE MUSICAL SYMBOL LYGISMA;So;0;L;;;;;N;;;;; -1D05E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI NEO;So;0;L;;;;;N;;;;; -1D05F;BYZANTINE MUSICAL SYMBOL PARAKALESMA NEO;So;0;L;;;;;N;;;;; -1D060;BYZANTINE MUSICAL SYMBOL ETERON PARAKALESMA;So;0;L;;;;;N;;;;; -1D061;BYZANTINE MUSICAL SYMBOL KYLISMA;So;0;L;;;;;N;;;;; -1D062;BYZANTINE MUSICAL SYMBOL ANTIKENOKYLISMA;So;0;L;;;;;N;;;;; -1D063;BYZANTINE MUSICAL SYMBOL TROMIKON NEO;So;0;L;;;;;N;;;;; -1D064;BYZANTINE MUSICAL SYMBOL EKSTREPTON;So;0;L;;;;;N;;;;; -1D065;BYZANTINE MUSICAL SYMBOL SYNAGMA NEO;So;0;L;;;;;N;;;;; -1D066;BYZANTINE MUSICAL SYMBOL SYRMA;So;0;L;;;;;N;;;;; -1D067;BYZANTINE MUSICAL SYMBOL CHOREVMA NEO;So;0;L;;;;;N;;;;; -1D068;BYZANTINE MUSICAL SYMBOL EPEGERMA;So;0;L;;;;;N;;;;; -1D069;BYZANTINE MUSICAL SYMBOL SEISMA NEO;So;0;L;;;;;N;;;;; -1D06A;BYZANTINE MUSICAL SYMBOL XIRON KLASMA;So;0;L;;;;;N;;;;; -1D06B;BYZANTINE MUSICAL SYMBOL TROMIKOPSIFISTON;So;0;L;;;;;N;;;;; -1D06C;BYZANTINE MUSICAL SYMBOL PSIFISTOLYGISMA;So;0;L;;;;;N;;;;; -1D06D;BYZANTINE MUSICAL SYMBOL TROMIKOLYGISMA;So;0;L;;;;;N;;;;; -1D06E;BYZANTINE MUSICAL SYMBOL TROMIKOPARAKALESMA;So;0;L;;;;;N;;;;; -1D06F;BYZANTINE MUSICAL SYMBOL PSIFISTOPARAKALESMA;So;0;L;;;;;N;;;;; -1D070;BYZANTINE MUSICAL SYMBOL TROMIKOSYNAGMA;So;0;L;;;;;N;;;;; -1D071;BYZANTINE MUSICAL SYMBOL PSIFISTOSYNAGMA;So;0;L;;;;;N;;;;; -1D072;BYZANTINE MUSICAL SYMBOL GORGOSYNTHETON;So;0;L;;;;;N;;;;; -1D073;BYZANTINE MUSICAL SYMBOL ARGOSYNTHETON;So;0;L;;;;;N;;;;; -1D074;BYZANTINE MUSICAL SYMBOL ETERON ARGOSYNTHETON;So;0;L;;;;;N;;;;; -1D075;BYZANTINE MUSICAL SYMBOL OYRANISMA NEO;So;0;L;;;;;N;;;;; -1D076;BYZANTINE MUSICAL SYMBOL THEMATISMOS ESO;So;0;L;;;;;N;;;;; -1D077;BYZANTINE MUSICAL SYMBOL THEMATISMOS EXO;So;0;L;;;;;N;;;;; -1D078;BYZANTINE MUSICAL SYMBOL THEMA APLOUN;So;0;L;;;;;N;;;;; -1D079;BYZANTINE MUSICAL SYMBOL THES KAI APOTHES;So;0;L;;;;;N;;;;; -1D07A;BYZANTINE MUSICAL SYMBOL KATAVASMA;So;0;L;;;;;N;;;;; -1D07B;BYZANTINE MUSICAL SYMBOL ENDOFONON;So;0;L;;;;;N;;;;; -1D07C;BYZANTINE MUSICAL SYMBOL YFEN KATO;So;0;L;;;;;N;;;;; -1D07D;BYZANTINE MUSICAL SYMBOL YFEN ANO;So;0;L;;;;;N;;;;; -1D07E;BYZANTINE MUSICAL SYMBOL STAVROS;So;0;L;;;;;N;;;;; -1D07F;BYZANTINE MUSICAL SYMBOL KLASMA ANO;So;0;L;;;;;N;;;;; -1D080;BYZANTINE MUSICAL SYMBOL DIPLI ARCHAION;So;0;L;;;;;N;;;;; -1D081;BYZANTINE MUSICAL SYMBOL KRATIMA ARCHAION;So;0;L;;;;;N;;;;; -1D082;BYZANTINE MUSICAL SYMBOL KRATIMA ALLO;So;0;L;;;;;N;;;;; -1D083;BYZANTINE MUSICAL SYMBOL KRATIMA NEO;So;0;L;;;;;N;;;;; -1D084;BYZANTINE MUSICAL SYMBOL APODERMA NEO;So;0;L;;;;;N;;;;; -1D085;BYZANTINE MUSICAL SYMBOL APLI;So;0;L;;;;;N;;;;; -1D086;BYZANTINE MUSICAL SYMBOL DIPLI;So;0;L;;;;;N;;;;; -1D087;BYZANTINE MUSICAL SYMBOL TRIPLI;So;0;L;;;;;N;;;;; -1D088;BYZANTINE MUSICAL SYMBOL TETRAPLI;So;0;L;;;;;N;;;;; -1D089;BYZANTINE MUSICAL SYMBOL KORONIS;So;0;L;;;;;N;;;;; -1D08A;BYZANTINE MUSICAL SYMBOL LEIMMA ENOS CHRONOU;So;0;L;;;;;N;;;;; -1D08B;BYZANTINE MUSICAL SYMBOL LEIMMA DYO CHRONON;So;0;L;;;;;N;;;;; -1D08C;BYZANTINE MUSICAL SYMBOL LEIMMA TRION CHRONON;So;0;L;;;;;N;;;;; -1D08D;BYZANTINE MUSICAL SYMBOL LEIMMA TESSARON CHRONON;So;0;L;;;;;N;;;;; -1D08E;BYZANTINE MUSICAL SYMBOL LEIMMA IMISEOS CHRONOU;So;0;L;;;;;N;;;;; -1D08F;BYZANTINE MUSICAL SYMBOL GORGON NEO ANO;So;0;L;;;;;N;;;;; -1D090;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON ARISTERA;So;0;L;;;;;N;;;;; -1D091;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;; -1D092;BYZANTINE MUSICAL SYMBOL DIGORGON;So;0;L;;;;;N;;;;; -1D093;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA KATO;So;0;L;;;;;N;;;;; -1D094;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA ANO;So;0;L;;;;;N;;;;; -1D095;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;; -1D096;BYZANTINE MUSICAL SYMBOL TRIGORGON;So;0;L;;;;;N;;;;; -1D097;BYZANTINE MUSICAL SYMBOL ARGON;So;0;L;;;;;N;;;;; -1D098;BYZANTINE MUSICAL SYMBOL IMIDIARGON;So;0;L;;;;;N;;;;; -1D099;BYZANTINE MUSICAL SYMBOL DIARGON;So;0;L;;;;;N;;;;; -1D09A;BYZANTINE MUSICAL SYMBOL AGOGI POLI ARGI;So;0;L;;;;;N;;;;; -1D09B;BYZANTINE MUSICAL SYMBOL AGOGI ARGOTERI;So;0;L;;;;;N;;;;; -1D09C;BYZANTINE MUSICAL SYMBOL AGOGI ARGI;So;0;L;;;;;N;;;;; -1D09D;BYZANTINE MUSICAL SYMBOL AGOGI METRIA;So;0;L;;;;;N;;;;; -1D09E;BYZANTINE MUSICAL SYMBOL AGOGI MESI;So;0;L;;;;;N;;;;; -1D09F;BYZANTINE MUSICAL SYMBOL AGOGI GORGI;So;0;L;;;;;N;;;;; -1D0A0;BYZANTINE MUSICAL SYMBOL AGOGI GORGOTERI;So;0;L;;;;;N;;;;; -1D0A1;BYZANTINE MUSICAL SYMBOL AGOGI POLI GORGI;So;0;L;;;;;N;;;;; -1D0A2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOS ICHOS;So;0;L;;;;;N;;;;; -1D0A3;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI PROTOS ICHOS;So;0;L;;;;;N;;;;; -1D0A4;BYZANTINE MUSICAL SYMBOL MARTYRIA DEYTEROS ICHOS;So;0;L;;;;;N;;;;; -1D0A5;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI DEYTEROS ICHOS;So;0;L;;;;;N;;;;; -1D0A6;BYZANTINE MUSICAL SYMBOL MARTYRIA TRITOS ICHOS;So;0;L;;;;;N;;;;; -1D0A7;BYZANTINE MUSICAL SYMBOL MARTYRIA TRIFONIAS;So;0;L;;;;;N;;;;; -1D0A8;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS ICHOS;So;0;L;;;;;N;;;;; -1D0A9;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS LEGETOS ICHOS;So;0;L;;;;;N;;;;; -1D0AA;BYZANTINE MUSICAL SYMBOL MARTYRIA LEGETOS ICHOS;So;0;L;;;;;N;;;;; -1D0AB;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS ICHOS;So;0;L;;;;;N;;;;; -1D0AC;BYZANTINE MUSICAL SYMBOL ISAKIA TELOUS ICHIMATOS;So;0;L;;;;;N;;;;; -1D0AD;BYZANTINE MUSICAL SYMBOL APOSTROFOI TELOUS ICHIMATOS;So;0;L;;;;;N;;;;; -1D0AE;BYZANTINE MUSICAL SYMBOL FANEROSIS TETRAFONIAS;So;0;L;;;;;N;;;;; -1D0AF;BYZANTINE MUSICAL SYMBOL FANEROSIS MONOFONIAS;So;0;L;;;;;N;;;;; -1D0B0;BYZANTINE MUSICAL SYMBOL FANEROSIS DIFONIAS;So;0;L;;;;;N;;;;; -1D0B1;BYZANTINE MUSICAL SYMBOL MARTYRIA VARYS ICHOS;So;0;L;;;;;N;;;;; -1D0B2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOVARYS ICHOS;So;0;L;;;;;N;;;;; -1D0B3;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS TETARTOS ICHOS;So;0;L;;;;;N;;;;; -1D0B4;BYZANTINE MUSICAL SYMBOL GORTHMIKON N APLOUN;So;0;L;;;;;N;;;;; -1D0B5;BYZANTINE MUSICAL SYMBOL GORTHMIKON N DIPLOUN;So;0;L;;;;;N;;;;; -1D0B6;BYZANTINE MUSICAL SYMBOL ENARXIS KAI FTHORA VOU;So;0;L;;;;;N;;;;; -1D0B7;BYZANTINE MUSICAL SYMBOL IMIFONON;So;0;L;;;;;N;;;;; -1D0B8;BYZANTINE MUSICAL SYMBOL IMIFTHORON;So;0;L;;;;;N;;;;; -1D0B9;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION DEYTEROU ICHOU;So;0;L;;;;;N;;;;; -1D0BA;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI PA;So;0;L;;;;;N;;;;; -1D0BB;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NANA;So;0;L;;;;;N;;;;; -1D0BC;BYZANTINE MUSICAL SYMBOL FTHORA NAOS ICHOS;So;0;L;;;;;N;;;;; -1D0BD;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI DI;So;0;L;;;;;N;;;;; -1D0BE;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON DIATONON DI;So;0;L;;;;;N;;;;; -1D0BF;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI KE;So;0;L;;;;;N;;;;; -1D0C0;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI ZO;So;0;L;;;;;N;;;;; -1D0C1;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI KATO;So;0;L;;;;;N;;;;; -1D0C2;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI ANO;So;0;L;;;;;N;;;;; -1D0C3;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA DIFONIAS;So;0;L;;;;;N;;;;; -1D0C4;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA MONOFONIAS;So;0;L;;;;;N;;;;; -1D0C5;BYZANTINE MUSICAL SYMBOL FHTORA SKLIRON CHROMA VASIS;So;0;L;;;;;N;;;;; -1D0C6;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON CHROMA SYNAFI;So;0;L;;;;;N;;;;; -1D0C7;BYZANTINE MUSICAL SYMBOL FTHORA NENANO;So;0;L;;;;;N;;;;; -1D0C8;BYZANTINE MUSICAL SYMBOL CHROA ZYGOS;So;0;L;;;;;N;;;;; -1D0C9;BYZANTINE MUSICAL SYMBOL CHROA KLITON;So;0;L;;;;;N;;;;; -1D0CA;BYZANTINE MUSICAL SYMBOL CHROA SPATHI;So;0;L;;;;;N;;;;; -1D0CB;BYZANTINE MUSICAL SYMBOL FTHORA I YFESIS TETARTIMORION;So;0;L;;;;;N;;;;; -1D0CC;BYZANTINE MUSICAL SYMBOL FTHORA ENARMONIOS ANTIFONIA;So;0;L;;;;;N;;;;; -1D0CD;BYZANTINE MUSICAL SYMBOL YFESIS TRITIMORION;So;0;L;;;;;N;;;;; -1D0CE;BYZANTINE MUSICAL SYMBOL DIESIS TRITIMORION;So;0;L;;;;;N;;;;; -1D0CF;BYZANTINE MUSICAL SYMBOL DIESIS TETARTIMORION;So;0;L;;;;;N;;;;; -1D0D0;BYZANTINE MUSICAL SYMBOL DIESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;; -1D0D1;BYZANTINE MUSICAL SYMBOL DIESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;; -1D0D2;BYZANTINE MUSICAL SYMBOL DIESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;; -1D0D3;BYZANTINE MUSICAL SYMBOL DIESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;; -1D0D4;BYZANTINE MUSICAL SYMBOL YFESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;; -1D0D5;BYZANTINE MUSICAL SYMBOL YFESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;; -1D0D6;BYZANTINE MUSICAL SYMBOL YFESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;; -1D0D7;BYZANTINE MUSICAL SYMBOL YFESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;; -1D0D8;BYZANTINE MUSICAL SYMBOL GENIKI DIESIS;So;0;L;;;;;N;;;;; -1D0D9;BYZANTINE MUSICAL SYMBOL GENIKI YFESIS;So;0;L;;;;;N;;;;; -1D0DA;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MIKRI;So;0;L;;;;;N;;;;; -1D0DB;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MEGALI;So;0;L;;;;;N;;;;; -1D0DC;BYZANTINE MUSICAL SYMBOL DIASTOLI DIPLI;So;0;L;;;;;N;;;;; -1D0DD;BYZANTINE MUSICAL SYMBOL DIASTOLI THESEOS;So;0;L;;;;;N;;;;; -1D0DE;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS;So;0;L;;;;;N;;;;; -1D0DF;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS DISIMOU;So;0;L;;;;;N;;;;; -1D0E0;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TRISIMOU;So;0;L;;;;;N;;;;; -1D0E1;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TETRASIMOU;So;0;L;;;;;N;;;;; -1D0E2;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS;So;0;L;;;;;N;;;;; -1D0E3;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS DISIMOU;So;0;L;;;;;N;;;;; -1D0E4;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TRISIMOU;So;0;L;;;;;N;;;;; -1D0E5;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TETRASIMOU;So;0;L;;;;;N;;;;; -1D0E6;BYZANTINE MUSICAL SYMBOL DIGRAMMA GG;So;0;L;;;;;N;;;;; -1D0E7;BYZANTINE MUSICAL SYMBOL DIFTOGGOS OU;So;0;L;;;;;N;;;;; -1D0E8;BYZANTINE MUSICAL SYMBOL STIGMA;So;0;L;;;;;N;;;;; -1D0E9;BYZANTINE MUSICAL SYMBOL ARKTIKO PA;So;0;L;;;;;N;;;;; -1D0EA;BYZANTINE MUSICAL SYMBOL ARKTIKO VOU;So;0;L;;;;;N;;;;; -1D0EB;BYZANTINE MUSICAL SYMBOL ARKTIKO GA;So;0;L;;;;;N;;;;; -1D0EC;BYZANTINE MUSICAL SYMBOL ARKTIKO DI;So;0;L;;;;;N;;;;; -1D0ED;BYZANTINE MUSICAL SYMBOL ARKTIKO KE;So;0;L;;;;;N;;;;; -1D0EE;BYZANTINE MUSICAL SYMBOL ARKTIKO ZO;So;0;L;;;;;N;;;;; -1D0EF;BYZANTINE MUSICAL SYMBOL ARKTIKO NI;So;0;L;;;;;N;;;;; -1D0F0;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO MESO;So;0;L;;;;;N;;;;; -1D0F1;BYZANTINE MUSICAL SYMBOL KENTIMA NEO MESO;So;0;L;;;;;N;;;;; -1D0F2;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO KATO;So;0;L;;;;;N;;;;; -1D0F3;BYZANTINE MUSICAL SYMBOL KENTIMA NEO KATO;So;0;L;;;;;N;;;;; -1D0F4;BYZANTINE MUSICAL SYMBOL KLASMA KATO;So;0;L;;;;;N;;;;; -1D0F5;BYZANTINE MUSICAL SYMBOL GORGON NEO KATO;So;0;L;;;;;N;;;;; -1D100;MUSICAL SYMBOL SINGLE BARLINE;So;0;L;;;;;N;;;;; -1D101;MUSICAL SYMBOL DOUBLE BARLINE;So;0;L;;;;;N;;;;; -1D102;MUSICAL SYMBOL FINAL BARLINE;So;0;L;;;;;N;;;;; -1D103;MUSICAL SYMBOL REVERSE FINAL BARLINE;So;0;L;;;;;N;;;;; -1D104;MUSICAL SYMBOL DASHED BARLINE;So;0;L;;;;;N;;;;; -1D105;MUSICAL SYMBOL SHORT BARLINE;So;0;L;;;;;N;;;;; -1D106;MUSICAL SYMBOL LEFT REPEAT SIGN;So;0;L;;;;;N;;;;; -1D107;MUSICAL SYMBOL RIGHT REPEAT SIGN;So;0;L;;;;;N;;;;; -1D108;MUSICAL SYMBOL REPEAT DOTS;So;0;L;;;;;N;;;;; -1D109;MUSICAL SYMBOL DAL SEGNO;So;0;L;;;;;N;;;;; -1D10A;MUSICAL SYMBOL DA CAPO;So;0;L;;;;;N;;;;; -1D10B;MUSICAL SYMBOL SEGNO;So;0;L;;;;;N;;;;; -1D10C;MUSICAL SYMBOL CODA;So;0;L;;;;;N;;;;; -1D10D;MUSICAL SYMBOL REPEATED FIGURE-1;So;0;L;;;;;N;;;;; -1D10E;MUSICAL SYMBOL REPEATED FIGURE-2;So;0;L;;;;;N;;;;; -1D10F;MUSICAL SYMBOL REPEATED FIGURE-3;So;0;L;;;;;N;;;;; -1D110;MUSICAL SYMBOL FERMATA;So;0;L;;;;;N;;;;; -1D111;MUSICAL SYMBOL FERMATA BELOW;So;0;L;;;;;N;;;;; -1D112;MUSICAL SYMBOL BREATH MARK;So;0;L;;;;;N;;;;; -1D113;MUSICAL SYMBOL CAESURA;So;0;L;;;;;N;;;;; -1D114;MUSICAL SYMBOL BRACE;So;0;L;;;;;N;;;;; -1D115;MUSICAL SYMBOL BRACKET;So;0;L;;;;;N;;;;; -1D116;MUSICAL SYMBOL ONE-LINE STAFF;So;0;L;;;;;N;;;;; -1D117;MUSICAL SYMBOL TWO-LINE STAFF;So;0;L;;;;;N;;;;; -1D118;MUSICAL SYMBOL THREE-LINE STAFF;So;0;L;;;;;N;;;;; -1D119;MUSICAL SYMBOL FOUR-LINE STAFF;So;0;L;;;;;N;;;;; -1D11A;MUSICAL SYMBOL FIVE-LINE STAFF;So;0;L;;;;;N;;;;; -1D11B;MUSICAL SYMBOL SIX-LINE STAFF;So;0;L;;;;;N;;;;; -1D11C;MUSICAL SYMBOL SIX-STRING FRETBOARD;So;0;L;;;;;N;;;;; -1D11D;MUSICAL SYMBOL FOUR-STRING FRETBOARD;So;0;L;;;;;N;;;;; -1D11E;MUSICAL SYMBOL G CLEF;So;0;L;;;;;N;;;;; -1D11F;MUSICAL SYMBOL G CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;; -1D120;MUSICAL SYMBOL G CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;; -1D121;MUSICAL SYMBOL C CLEF;So;0;L;;;;;N;;;;; -1D122;MUSICAL SYMBOL F CLEF;So;0;L;;;;;N;;;;; -1D123;MUSICAL SYMBOL F CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;; -1D124;MUSICAL SYMBOL F CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;; -1D125;MUSICAL SYMBOL DRUM CLEF-1;So;0;L;;;;;N;;;;; -1D126;MUSICAL SYMBOL DRUM CLEF-2;So;0;L;;;;;N;;;;; -1D129;MUSICAL SYMBOL MULTIPLE MEASURE REST;So;0;L;;;;;N;;;;; -1D12A;MUSICAL SYMBOL DOUBLE SHARP;So;0;L;;;;;N;;;;; -1D12B;MUSICAL SYMBOL DOUBLE FLAT;So;0;L;;;;;N;;;;; -1D12C;MUSICAL SYMBOL FLAT UP;So;0;L;;;;;N;;;;; -1D12D;MUSICAL SYMBOL FLAT DOWN;So;0;L;;;;;N;;;;; -1D12E;MUSICAL SYMBOL NATURAL UP;So;0;L;;;;;N;;;;; -1D12F;MUSICAL SYMBOL NATURAL DOWN;So;0;L;;;;;N;;;;; -1D130;MUSICAL SYMBOL SHARP UP;So;0;L;;;;;N;;;;; -1D131;MUSICAL SYMBOL SHARP DOWN;So;0;L;;;;;N;;;;; -1D132;MUSICAL SYMBOL QUARTER TONE SHARP;So;0;L;;;;;N;;;;; -1D133;MUSICAL SYMBOL QUARTER TONE FLAT;So;0;L;;;;;N;;;;; -1D134;MUSICAL SYMBOL COMMON TIME;So;0;L;;;;;N;;;;; -1D135;MUSICAL SYMBOL CUT TIME;So;0;L;;;;;N;;;;; -1D136;MUSICAL SYMBOL OTTAVA ALTA;So;0;L;;;;;N;;;;; -1D137;MUSICAL SYMBOL OTTAVA BASSA;So;0;L;;;;;N;;;;; -1D138;MUSICAL SYMBOL QUINDICESIMA ALTA;So;0;L;;;;;N;;;;; -1D139;MUSICAL SYMBOL QUINDICESIMA BASSA;So;0;L;;;;;N;;;;; -1D13A;MUSICAL SYMBOL MULTI REST;So;0;L;;;;;N;;;;; -1D13B;MUSICAL SYMBOL WHOLE REST;So;0;L;;;;;N;;;;; -1D13C;MUSICAL SYMBOL HALF REST;So;0;L;;;;;N;;;;; -1D13D;MUSICAL SYMBOL QUARTER REST;So;0;L;;;;;N;;;;; -1D13E;MUSICAL SYMBOL EIGHTH REST;So;0;L;;;;;N;;;;; -1D13F;MUSICAL SYMBOL SIXTEENTH REST;So;0;L;;;;;N;;;;; -1D140;MUSICAL SYMBOL THIRTY-SECOND REST;So;0;L;;;;;N;;;;; -1D141;MUSICAL SYMBOL SIXTY-FOURTH REST;So;0;L;;;;;N;;;;; -1D142;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH REST;So;0;L;;;;;N;;;;; -1D143;MUSICAL SYMBOL X NOTEHEAD;So;0;L;;;;;N;;;;; -1D144;MUSICAL SYMBOL PLUS NOTEHEAD;So;0;L;;;;;N;;;;; -1D145;MUSICAL SYMBOL CIRCLE X NOTEHEAD;So;0;L;;;;;N;;;;; -1D146;MUSICAL SYMBOL SQUARE NOTEHEAD WHITE;So;0;L;;;;;N;;;;; -1D147;MUSICAL SYMBOL SQUARE NOTEHEAD BLACK;So;0;L;;;;;N;;;;; -1D148;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP WHITE;So;0;L;;;;;N;;;;; -1D149;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP BLACK;So;0;L;;;;;N;;;;; -1D14A;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT WHITE;So;0;L;;;;;N;;;;; -1D14B;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT BLACK;So;0;L;;;;;N;;;;; -1D14C;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT WHITE;So;0;L;;;;;N;;;;; -1D14D;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT BLACK;So;0;L;;;;;N;;;;; -1D14E;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;; -1D14F;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;; -1D150;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT WHITE;So;0;L;;;;;N;;;;; -1D151;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT BLACK;So;0;L;;;;;N;;;;; -1D152;MUSICAL SYMBOL MOON NOTEHEAD WHITE;So;0;L;;;;;N;;;;; -1D153;MUSICAL SYMBOL MOON NOTEHEAD BLACK;So;0;L;;;;;N;;;;; -1D154;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;; -1D155;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;; -1D156;MUSICAL SYMBOL PARENTHESIS NOTEHEAD;So;0;L;;;;;N;;;;; -1D157;MUSICAL SYMBOL VOID NOTEHEAD;So;0;L;;;;;N;;;;; -1D158;MUSICAL SYMBOL NOTEHEAD BLACK;So;0;L;;;;;N;;;;; -1D159;MUSICAL SYMBOL NULL NOTEHEAD;So;0;L;;;;;N;;;;; -1D15A;MUSICAL SYMBOL CLUSTER NOTEHEAD WHITE;So;0;L;;;;;N;;;;; -1D15B;MUSICAL SYMBOL CLUSTER NOTEHEAD BLACK;So;0;L;;;;;N;;;;; -1D15C;MUSICAL SYMBOL BREVE;So;0;L;;;;;N;;;;; -1D15D;MUSICAL SYMBOL WHOLE NOTE;So;0;L;;;;;N;;;;; -1D15E;MUSICAL SYMBOL HALF NOTE;So;0;L;1D157 1D165;;;;N;;;;; -1D15F;MUSICAL SYMBOL QUARTER NOTE;So;0;L;1D158 1D165;;;;N;;;;; -1D160;MUSICAL SYMBOL EIGHTH NOTE;So;0;L;1D15F 1D16E;;;;N;;;;; -1D161;MUSICAL SYMBOL SIXTEENTH NOTE;So;0;L;1D15F 1D16F;;;;N;;;;; -1D162;MUSICAL SYMBOL THIRTY-SECOND NOTE;So;0;L;1D15F 1D170;;;;N;;;;; -1D163;MUSICAL SYMBOL SIXTY-FOURTH NOTE;So;0;L;1D15F 1D171;;;;N;;;;; -1D164;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE;So;0;L;1D15F 1D172;;;;N;;;;; -1D165;MUSICAL SYMBOL COMBINING STEM;Mc;216;L;;;;;N;;;;; -1D166;MUSICAL SYMBOL COMBINING SPRECHGESANG STEM;Mc;216;L;;;;;N;;;;; -1D167;MUSICAL SYMBOL COMBINING TREMOLO-1;Mn;1;NSM;;;;;N;;;;; -1D168;MUSICAL SYMBOL COMBINING TREMOLO-2;Mn;1;NSM;;;;;N;;;;; -1D169;MUSICAL SYMBOL COMBINING TREMOLO-3;Mn;1;NSM;;;;;N;;;;; -1D16A;MUSICAL SYMBOL FINGERED TREMOLO-1;So;0;L;;;;;N;;;;; -1D16B;MUSICAL SYMBOL FINGERED TREMOLO-2;So;0;L;;;;;N;;;;; -1D16C;MUSICAL SYMBOL FINGERED TREMOLO-3;So;0;L;;;;;N;;;;; -1D16D;MUSICAL SYMBOL COMBINING AUGMENTATION DOT;Mc;226;L;;;;;N;;;;; -1D16E;MUSICAL SYMBOL COMBINING FLAG-1;Mc;216;L;;;;;N;;;;; -1D16F;MUSICAL SYMBOL COMBINING FLAG-2;Mc;216;L;;;;;N;;;;; -1D170;MUSICAL SYMBOL COMBINING FLAG-3;Mc;216;L;;;;;N;;;;; -1D171;MUSICAL SYMBOL COMBINING FLAG-4;Mc;216;L;;;;;N;;;;; -1D172;MUSICAL SYMBOL COMBINING FLAG-5;Mc;216;L;;;;;N;;;;; -1D173;MUSICAL SYMBOL BEGIN BEAM;Cf;0;BN;;;;;N;;;;; -1D174;MUSICAL SYMBOL END BEAM;Cf;0;BN;;;;;N;;;;; -1D175;MUSICAL SYMBOL BEGIN TIE;Cf;0;BN;;;;;N;;;;; -1D176;MUSICAL SYMBOL END TIE;Cf;0;BN;;;;;N;;;;; -1D177;MUSICAL SYMBOL BEGIN SLUR;Cf;0;BN;;;;;N;;;;; -1D178;MUSICAL SYMBOL END SLUR;Cf;0;BN;;;;;N;;;;; -1D179;MUSICAL SYMBOL BEGIN PHRASE;Cf;0;BN;;;;;N;;;;; -1D17A;MUSICAL SYMBOL END PHRASE;Cf;0;BN;;;;;N;;;;; -1D17B;MUSICAL SYMBOL COMBINING ACCENT;Mn;220;NSM;;;;;N;;;;; -1D17C;MUSICAL SYMBOL COMBINING STACCATO;Mn;220;NSM;;;;;N;;;;; -1D17D;MUSICAL SYMBOL COMBINING TENUTO;Mn;220;NSM;;;;;N;;;;; -1D17E;MUSICAL SYMBOL COMBINING STACCATISSIMO;Mn;220;NSM;;;;;N;;;;; -1D17F;MUSICAL SYMBOL COMBINING MARCATO;Mn;220;NSM;;;;;N;;;;; -1D180;MUSICAL SYMBOL COMBINING MARCATO-STACCATO;Mn;220;NSM;;;;;N;;;;; -1D181;MUSICAL SYMBOL COMBINING ACCENT-STACCATO;Mn;220;NSM;;;;;N;;;;; -1D182;MUSICAL SYMBOL COMBINING LOURE;Mn;220;NSM;;;;;N;;;;; -1D183;MUSICAL SYMBOL ARPEGGIATO UP;So;0;L;;;;;N;;;;; -1D184;MUSICAL SYMBOL ARPEGGIATO DOWN;So;0;L;;;;;N;;;;; -1D185;MUSICAL SYMBOL COMBINING DOIT;Mn;230;NSM;;;;;N;;;;; -1D186;MUSICAL SYMBOL COMBINING RIP;Mn;230;NSM;;;;;N;;;;; -1D187;MUSICAL SYMBOL COMBINING FLIP;Mn;230;NSM;;;;;N;;;;; -1D188;MUSICAL SYMBOL COMBINING SMEAR;Mn;230;NSM;;;;;N;;;;; -1D189;MUSICAL SYMBOL COMBINING BEND;Mn;230;NSM;;;;;N;;;;; -1D18A;MUSICAL SYMBOL COMBINING DOUBLE TONGUE;Mn;220;NSM;;;;;N;;;;; -1D18B;MUSICAL SYMBOL COMBINING TRIPLE TONGUE;Mn;220;NSM;;;;;N;;;;; -1D18C;MUSICAL SYMBOL RINFORZANDO;So;0;L;;;;;N;;;;; -1D18D;MUSICAL SYMBOL SUBITO;So;0;L;;;;;N;;;;; -1D18E;MUSICAL SYMBOL Z;So;0;L;;;;;N;;;;; -1D18F;MUSICAL SYMBOL PIANO;So;0;L;;;;;N;;;;; -1D190;MUSICAL SYMBOL MEZZO;So;0;L;;;;;N;;;;; -1D191;MUSICAL SYMBOL FORTE;So;0;L;;;;;N;;;;; -1D192;MUSICAL SYMBOL CRESCENDO;So;0;L;;;;;N;;;;; -1D193;MUSICAL SYMBOL DECRESCENDO;So;0;L;;;;;N;;;;; -1D194;MUSICAL SYMBOL GRACE NOTE SLASH;So;0;L;;;;;N;;;;; -1D195;MUSICAL SYMBOL GRACE NOTE NO SLASH;So;0;L;;;;;N;;;;; -1D196;MUSICAL SYMBOL TR;So;0;L;;;;;N;;;;; -1D197;MUSICAL SYMBOL TURN;So;0;L;;;;;N;;;;; -1D198;MUSICAL SYMBOL INVERTED TURN;So;0;L;;;;;N;;;;; -1D199;MUSICAL SYMBOL TURN SLASH;So;0;L;;;;;N;;;;; -1D19A;MUSICAL SYMBOL TURN UP;So;0;L;;;;;N;;;;; -1D19B;MUSICAL SYMBOL ORNAMENT STROKE-1;So;0;L;;;;;N;;;;; -1D19C;MUSICAL SYMBOL ORNAMENT STROKE-2;So;0;L;;;;;N;;;;; -1D19D;MUSICAL SYMBOL ORNAMENT STROKE-3;So;0;L;;;;;N;;;;; -1D19E;MUSICAL SYMBOL ORNAMENT STROKE-4;So;0;L;;;;;N;;;;; -1D19F;MUSICAL SYMBOL ORNAMENT STROKE-5;So;0;L;;;;;N;;;;; -1D1A0;MUSICAL SYMBOL ORNAMENT STROKE-6;So;0;L;;;;;N;;;;; -1D1A1;MUSICAL SYMBOL ORNAMENT STROKE-7;So;0;L;;;;;N;;;;; -1D1A2;MUSICAL SYMBOL ORNAMENT STROKE-8;So;0;L;;;;;N;;;;; -1D1A3;MUSICAL SYMBOL ORNAMENT STROKE-9;So;0;L;;;;;N;;;;; -1D1A4;MUSICAL SYMBOL ORNAMENT STROKE-10;So;0;L;;;;;N;;;;; -1D1A5;MUSICAL SYMBOL ORNAMENT STROKE-11;So;0;L;;;;;N;;;;; -1D1A6;MUSICAL SYMBOL HAUPTSTIMME;So;0;L;;;;;N;;;;; -1D1A7;MUSICAL SYMBOL NEBENSTIMME;So;0;L;;;;;N;;;;; -1D1A8;MUSICAL SYMBOL END OF STIMME;So;0;L;;;;;N;;;;; -1D1A9;MUSICAL SYMBOL DEGREE SLASH;So;0;L;;;;;N;;;;; -1D1AA;MUSICAL SYMBOL COMBINING DOWN BOW;Mn;230;NSM;;;;;N;;;;; -1D1AB;MUSICAL SYMBOL COMBINING UP BOW;Mn;230;NSM;;;;;N;;;;; -1D1AC;MUSICAL SYMBOL COMBINING HARMONIC;Mn;230;NSM;;;;;N;;;;; -1D1AD;MUSICAL SYMBOL COMBINING SNAP PIZZICATO;Mn;230;NSM;;;;;N;;;;; -1D1AE;MUSICAL SYMBOL PEDAL MARK;So;0;L;;;;;N;;;;; -1D1AF;MUSICAL SYMBOL PEDAL UP MARK;So;0;L;;;;;N;;;;; -1D1B0;MUSICAL SYMBOL HALF PEDAL MARK;So;0;L;;;;;N;;;;; -1D1B1;MUSICAL SYMBOL GLISSANDO UP;So;0;L;;;;;N;;;;; -1D1B2;MUSICAL SYMBOL GLISSANDO DOWN;So;0;L;;;;;N;;;;; -1D1B3;MUSICAL SYMBOL WITH FINGERNAILS;So;0;L;;;;;N;;;;; -1D1B4;MUSICAL SYMBOL DAMP;So;0;L;;;;;N;;;;; -1D1B5;MUSICAL SYMBOL DAMP ALL;So;0;L;;;;;N;;;;; -1D1B6;MUSICAL SYMBOL MAXIMA;So;0;L;;;;;N;;;;; -1D1B7;MUSICAL SYMBOL LONGA;So;0;L;;;;;N;;;;; -1D1B8;MUSICAL SYMBOL BREVIS;So;0;L;;;;;N;;;;; -1D1B9;MUSICAL SYMBOL SEMIBREVIS WHITE;So;0;L;;;;;N;;;;; -1D1BA;MUSICAL SYMBOL SEMIBREVIS BLACK;So;0;L;;;;;N;;;;; -1D1BB;MUSICAL SYMBOL MINIMA;So;0;L;1D1B9 1D165;;;;N;;;;; -1D1BC;MUSICAL SYMBOL MINIMA BLACK;So;0;L;1D1BA 1D165;;;;N;;;;; -1D1BD;MUSICAL SYMBOL SEMIMINIMA WHITE;So;0;L;1D1BB 1D16E;;;;N;;;;; -1D1BE;MUSICAL SYMBOL SEMIMINIMA BLACK;So;0;L;1D1BC 1D16E;;;;N;;;;; -1D1BF;MUSICAL SYMBOL FUSA WHITE;So;0;L;1D1BB 1D16F;;;;N;;;;; -1D1C0;MUSICAL SYMBOL FUSA BLACK;So;0;L;1D1BC 1D16F;;;;N;;;;; -1D1C1;MUSICAL SYMBOL LONGA PERFECTA REST;So;0;L;;;;;N;;;;; -1D1C2;MUSICAL SYMBOL LONGA IMPERFECTA REST;So;0;L;;;;;N;;;;; -1D1C3;MUSICAL SYMBOL BREVIS REST;So;0;L;;;;;N;;;;; -1D1C4;MUSICAL SYMBOL SEMIBREVIS REST;So;0;L;;;;;N;;;;; -1D1C5;MUSICAL SYMBOL MINIMA REST;So;0;L;;;;;N;;;;; -1D1C6;MUSICAL SYMBOL SEMIMINIMA REST;So;0;L;;;;;N;;;;; -1D1C7;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;; -1D1C8;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;; -1D1C9;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;; -1D1CA;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;; -1D1CB;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;; -1D1CC;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;; -1D1CD;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-2;So;0;L;;;;;N;;;;; -1D1CE;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-3;So;0;L;;;;;N;;;;; -1D1CF;MUSICAL SYMBOL CROIX;So;0;L;;;;;N;;;;; -1D1D0;MUSICAL SYMBOL GREGORIAN C CLEF;So;0;L;;;;;N;;;;; -1D1D1;MUSICAL SYMBOL GREGORIAN F CLEF;So;0;L;;;;;N;;;;; -1D1D2;MUSICAL SYMBOL SQUARE B;So;0;L;;;;;N;;;;; -1D1D3;MUSICAL SYMBOL VIRGA;So;0;L;;;;;N;;;;; -1D1D4;MUSICAL SYMBOL PODATUS;So;0;L;;;;;N;;;;; -1D1D5;MUSICAL SYMBOL CLIVIS;So;0;L;;;;;N;;;;; -1D1D6;MUSICAL SYMBOL SCANDICUS;So;0;L;;;;;N;;;;; -1D1D7;MUSICAL SYMBOL CLIMACUS;So;0;L;;;;;N;;;;; -1D1D8;MUSICAL SYMBOL TORCULUS;So;0;L;;;;;N;;;;; -1D1D9;MUSICAL SYMBOL PORRECTUS;So;0;L;;;;;N;;;;; -1D1DA;MUSICAL SYMBOL PORRECTUS FLEXUS;So;0;L;;;;;N;;;;; -1D1DB;MUSICAL SYMBOL SCANDICUS FLEXUS;So;0;L;;;;;N;;;;; -1D1DC;MUSICAL SYMBOL TORCULUS RESUPINUS;So;0;L;;;;;N;;;;; -1D1DD;MUSICAL SYMBOL PES SUBPUNCTIS;So;0;L;;;;;N;;;;; -1D1DE;MUSICAL SYMBOL KIEVAN C CLEF;So;0;L;;;;;N;;;;; -1D1DF;MUSICAL SYMBOL KIEVAN END OF PIECE;So;0;L;;;;;N;;;;; -1D1E0;MUSICAL SYMBOL KIEVAN FINAL NOTE;So;0;L;;;;;N;;;;; -1D1E1;MUSICAL SYMBOL KIEVAN RECITATIVE MARK;So;0;L;;;;;N;;;;; -1D1E2;MUSICAL SYMBOL KIEVAN WHOLE NOTE;So;0;L;;;;;N;;;;; -1D1E3;MUSICAL SYMBOL KIEVAN HALF NOTE;So;0;L;;;;;N;;;;; -1D1E4;MUSICAL SYMBOL KIEVAN QUARTER NOTE STEM DOWN;So;0;L;;;;;N;;;;; -1D1E5;MUSICAL SYMBOL KIEVAN QUARTER NOTE STEM UP;So;0;L;;;;;N;;;;; -1D1E6;MUSICAL SYMBOL KIEVAN EIGHTH NOTE STEM DOWN;So;0;L;;;;;N;;;;; -1D1E7;MUSICAL SYMBOL KIEVAN EIGHTH NOTE STEM UP;So;0;L;;;;;N;;;;; -1D1E8;MUSICAL SYMBOL KIEVAN FLAT SIGN;So;0;L;;;;;N;;;;; -1D1E9;MUSICAL SYMBOL SORI;So;0;ON;;;;;N;;;;; -1D1EA;MUSICAL SYMBOL KORON;So;0;ON;;;;;N;;;;; -1D200;GREEK VOCAL NOTATION SYMBOL-1;So;0;ON;;;;;N;;;;; -1D201;GREEK VOCAL NOTATION SYMBOL-2;So;0;ON;;;;;N;;;;; -1D202;GREEK VOCAL NOTATION SYMBOL-3;So;0;ON;;;;;N;;;;; -1D203;GREEK VOCAL NOTATION SYMBOL-4;So;0;ON;;;;;N;;;;; -1D204;GREEK VOCAL NOTATION SYMBOL-5;So;0;ON;;;;;N;;;;; -1D205;GREEK VOCAL NOTATION SYMBOL-6;So;0;ON;;;;;N;;;;; -1D206;GREEK VOCAL NOTATION SYMBOL-7;So;0;ON;;;;;N;;;;; -1D207;GREEK VOCAL NOTATION SYMBOL-8;So;0;ON;;;;;N;;;;; -1D208;GREEK VOCAL NOTATION SYMBOL-9;So;0;ON;;;;;N;;;;; -1D209;GREEK VOCAL NOTATION SYMBOL-10;So;0;ON;;;;;N;;;;; -1D20A;GREEK VOCAL NOTATION SYMBOL-11;So;0;ON;;;;;N;;;;; -1D20B;GREEK VOCAL NOTATION SYMBOL-12;So;0;ON;;;;;N;;;;; -1D20C;GREEK VOCAL NOTATION SYMBOL-13;So;0;ON;;;;;N;;;;; -1D20D;GREEK VOCAL NOTATION SYMBOL-14;So;0;ON;;;;;N;;;;; -1D20E;GREEK VOCAL NOTATION SYMBOL-15;So;0;ON;;;;;N;;;;; -1D20F;GREEK VOCAL NOTATION SYMBOL-16;So;0;ON;;;;;N;;;;; -1D210;GREEK VOCAL NOTATION SYMBOL-17;So;0;ON;;;;;N;;;;; -1D211;GREEK VOCAL NOTATION SYMBOL-18;So;0;ON;;;;;N;;;;; -1D212;GREEK VOCAL NOTATION SYMBOL-19;So;0;ON;;;;;N;;;;; -1D213;GREEK VOCAL NOTATION SYMBOL-20;So;0;ON;;;;;N;;;;; -1D214;GREEK VOCAL NOTATION SYMBOL-21;So;0;ON;;;;;N;;;;; -1D215;GREEK VOCAL NOTATION SYMBOL-22;So;0;ON;;;;;N;;;;; -1D216;GREEK VOCAL NOTATION SYMBOL-23;So;0;ON;;;;;N;;;;; -1D217;GREEK VOCAL NOTATION SYMBOL-24;So;0;ON;;;;;N;;;;; -1D218;GREEK VOCAL NOTATION SYMBOL-50;So;0;ON;;;;;N;;;;; -1D219;GREEK VOCAL NOTATION SYMBOL-51;So;0;ON;;;;;N;;;;; -1D21A;GREEK VOCAL NOTATION SYMBOL-52;So;0;ON;;;;;N;;;;; -1D21B;GREEK VOCAL NOTATION SYMBOL-53;So;0;ON;;;;;N;;;;; -1D21C;GREEK VOCAL NOTATION SYMBOL-54;So;0;ON;;;;;N;;;;; -1D21D;GREEK INSTRUMENTAL NOTATION SYMBOL-1;So;0;ON;;;;;N;;;;; -1D21E;GREEK INSTRUMENTAL NOTATION SYMBOL-2;So;0;ON;;;;;N;;;;; -1D21F;GREEK INSTRUMENTAL NOTATION SYMBOL-4;So;0;ON;;;;;N;;;;; -1D220;GREEK INSTRUMENTAL NOTATION SYMBOL-5;So;0;ON;;;;;N;;;;; -1D221;GREEK INSTRUMENTAL NOTATION SYMBOL-7;So;0;ON;;;;;N;;;;; -1D222;GREEK INSTRUMENTAL NOTATION SYMBOL-8;So;0;ON;;;;;N;;;;; -1D223;GREEK INSTRUMENTAL NOTATION SYMBOL-11;So;0;ON;;;;;N;;;;; -1D224;GREEK INSTRUMENTAL NOTATION SYMBOL-12;So;0;ON;;;;;N;;;;; -1D225;GREEK INSTRUMENTAL NOTATION SYMBOL-13;So;0;ON;;;;;N;;;;; -1D226;GREEK INSTRUMENTAL NOTATION SYMBOL-14;So;0;ON;;;;;N;;;;; -1D227;GREEK INSTRUMENTAL NOTATION SYMBOL-17;So;0;ON;;;;;N;;;;; -1D228;GREEK INSTRUMENTAL NOTATION SYMBOL-18;So;0;ON;;;;;N;;;;; -1D229;GREEK INSTRUMENTAL NOTATION SYMBOL-19;So;0;ON;;;;;N;;;;; -1D22A;GREEK INSTRUMENTAL NOTATION SYMBOL-23;So;0;ON;;;;;N;;;;; -1D22B;GREEK INSTRUMENTAL NOTATION SYMBOL-24;So;0;ON;;;;;N;;;;; -1D22C;GREEK INSTRUMENTAL NOTATION SYMBOL-25;So;0;ON;;;;;N;;;;; -1D22D;GREEK INSTRUMENTAL NOTATION SYMBOL-26;So;0;ON;;;;;N;;;;; -1D22E;GREEK INSTRUMENTAL NOTATION SYMBOL-27;So;0;ON;;;;;N;;;;; -1D22F;GREEK INSTRUMENTAL NOTATION SYMBOL-29;So;0;ON;;;;;N;;;;; -1D230;GREEK INSTRUMENTAL NOTATION SYMBOL-30;So;0;ON;;;;;N;;;;; -1D231;GREEK INSTRUMENTAL NOTATION SYMBOL-32;So;0;ON;;;;;N;;;;; -1D232;GREEK INSTRUMENTAL NOTATION SYMBOL-36;So;0;ON;;;;;N;;;;; -1D233;GREEK INSTRUMENTAL NOTATION SYMBOL-37;So;0;ON;;;;;N;;;;; -1D234;GREEK INSTRUMENTAL NOTATION SYMBOL-38;So;0;ON;;;;;N;;;;; -1D235;GREEK INSTRUMENTAL NOTATION SYMBOL-39;So;0;ON;;;;;N;;;;; -1D236;GREEK INSTRUMENTAL NOTATION SYMBOL-40;So;0;ON;;;;;N;;;;; -1D237;GREEK INSTRUMENTAL NOTATION SYMBOL-42;So;0;ON;;;;;N;;;;; -1D238;GREEK INSTRUMENTAL NOTATION SYMBOL-43;So;0;ON;;;;;N;;;;; -1D239;GREEK INSTRUMENTAL NOTATION SYMBOL-45;So;0;ON;;;;;N;;;;; -1D23A;GREEK INSTRUMENTAL NOTATION SYMBOL-47;So;0;ON;;;;;N;;;;; -1D23B;GREEK INSTRUMENTAL NOTATION SYMBOL-48;So;0;ON;;;;;N;;;;; -1D23C;GREEK INSTRUMENTAL NOTATION SYMBOL-49;So;0;ON;;;;;N;;;;; -1D23D;GREEK INSTRUMENTAL NOTATION SYMBOL-50;So;0;ON;;;;;N;;;;; -1D23E;GREEK INSTRUMENTAL NOTATION SYMBOL-51;So;0;ON;;;;;N;;;;; -1D23F;GREEK INSTRUMENTAL NOTATION SYMBOL-52;So;0;ON;;;;;N;;;;; -1D240;GREEK INSTRUMENTAL NOTATION SYMBOL-53;So;0;ON;;;;;N;;;;; -1D241;GREEK INSTRUMENTAL NOTATION SYMBOL-54;So;0;ON;;;;;N;;;;; -1D242;COMBINING GREEK MUSICAL TRISEME;Mn;230;NSM;;;;;N;;;;; -1D243;COMBINING GREEK MUSICAL TETRASEME;Mn;230;NSM;;;;;N;;;;; -1D244;COMBINING GREEK MUSICAL PENTASEME;Mn;230;NSM;;;;;N;;;;; -1D245;GREEK MUSICAL LEIMMA;So;0;ON;;;;;N;;;;; -1D2C0;KAKTOVIK NUMERAL ZERO;No;0;L;;;;0;N;;;;; -1D2C1;KAKTOVIK NUMERAL ONE;No;0;L;;;;1;N;;;;; -1D2C2;KAKTOVIK NUMERAL TWO;No;0;L;;;;2;N;;;;; -1D2C3;KAKTOVIK NUMERAL THREE;No;0;L;;;;3;N;;;;; -1D2C4;KAKTOVIK NUMERAL FOUR;No;0;L;;;;4;N;;;;; -1D2C5;KAKTOVIK NUMERAL FIVE;No;0;L;;;;5;N;;;;; -1D2C6;KAKTOVIK NUMERAL SIX;No;0;L;;;;6;N;;;;; -1D2C7;KAKTOVIK NUMERAL SEVEN;No;0;L;;;;7;N;;;;; -1D2C8;KAKTOVIK NUMERAL EIGHT;No;0;L;;;;8;N;;;;; -1D2C9;KAKTOVIK NUMERAL NINE;No;0;L;;;;9;N;;;;; -1D2CA;KAKTOVIK NUMERAL TEN;No;0;L;;;;10;N;;;;; -1D2CB;KAKTOVIK NUMERAL ELEVEN;No;0;L;;;;11;N;;;;; -1D2CC;KAKTOVIK NUMERAL TWELVE;No;0;L;;;;12;N;;;;; -1D2CD;KAKTOVIK NUMERAL THIRTEEN;No;0;L;;;;13;N;;;;; -1D2CE;KAKTOVIK NUMERAL FOURTEEN;No;0;L;;;;14;N;;;;; -1D2CF;KAKTOVIK NUMERAL FIFTEEN;No;0;L;;;;15;N;;;;; -1D2D0;KAKTOVIK NUMERAL SIXTEEN;No;0;L;;;;16;N;;;;; -1D2D1;KAKTOVIK NUMERAL SEVENTEEN;No;0;L;;;;17;N;;;;; -1D2D2;KAKTOVIK NUMERAL EIGHTEEN;No;0;L;;;;18;N;;;;; -1D2D3;KAKTOVIK NUMERAL NINETEEN;No;0;L;;;;19;N;;;;; -1D2E0;MAYAN NUMERAL ZERO;No;0;L;;;;0;N;;;;; -1D2E1;MAYAN NUMERAL ONE;No;0;L;;;;1;N;;;;; -1D2E2;MAYAN NUMERAL TWO;No;0;L;;;;2;N;;;;; -1D2E3;MAYAN NUMERAL THREE;No;0;L;;;;3;N;;;;; -1D2E4;MAYAN NUMERAL FOUR;No;0;L;;;;4;N;;;;; -1D2E5;MAYAN NUMERAL FIVE;No;0;L;;;;5;N;;;;; -1D2E6;MAYAN NUMERAL SIX;No;0;L;;;;6;N;;;;; -1D2E7;MAYAN NUMERAL SEVEN;No;0;L;;;;7;N;;;;; -1D2E8;MAYAN NUMERAL EIGHT;No;0;L;;;;8;N;;;;; -1D2E9;MAYAN NUMERAL NINE;No;0;L;;;;9;N;;;;; -1D2EA;MAYAN NUMERAL TEN;No;0;L;;;;10;N;;;;; -1D2EB;MAYAN NUMERAL ELEVEN;No;0;L;;;;11;N;;;;; -1D2EC;MAYAN NUMERAL TWELVE;No;0;L;;;;12;N;;;;; -1D2ED;MAYAN NUMERAL THIRTEEN;No;0;L;;;;13;N;;;;; -1D2EE;MAYAN NUMERAL FOURTEEN;No;0;L;;;;14;N;;;;; -1D2EF;MAYAN NUMERAL FIFTEEN;No;0;L;;;;15;N;;;;; -1D2F0;MAYAN NUMERAL SIXTEEN;No;0;L;;;;16;N;;;;; -1D2F1;MAYAN NUMERAL SEVENTEEN;No;0;L;;;;17;N;;;;; -1D2F2;MAYAN NUMERAL EIGHTEEN;No;0;L;;;;18;N;;;;; -1D2F3;MAYAN NUMERAL NINETEEN;No;0;L;;;;19;N;;;;; -1D300;MONOGRAM FOR EARTH;So;0;ON;;;;;N;;;;; -1D301;DIGRAM FOR HEAVENLY EARTH;So;0;ON;;;;;N;;;;; -1D302;DIGRAM FOR HUMAN EARTH;So;0;ON;;;;;N;;;;; -1D303;DIGRAM FOR EARTHLY HEAVEN;So;0;ON;;;;;N;;;;; -1D304;DIGRAM FOR EARTHLY HUMAN;So;0;ON;;;;;N;;;;; -1D305;DIGRAM FOR EARTH;So;0;ON;;;;;N;;;;; -1D306;TETRAGRAM FOR CENTRE;So;0;ON;;;;;N;;;;; -1D307;TETRAGRAM FOR FULL CIRCLE;So;0;ON;;;;;N;;;;; -1D308;TETRAGRAM FOR MIRED;So;0;ON;;;;;N;;;;; -1D309;TETRAGRAM FOR BARRIER;So;0;ON;;;;;N;;;;; -1D30A;TETRAGRAM FOR KEEPING SMALL;So;0;ON;;;;;N;;;;; -1D30B;TETRAGRAM FOR CONTRARIETY;So;0;ON;;;;;N;;;;; -1D30C;TETRAGRAM FOR ASCENT;So;0;ON;;;;;N;;;;; -1D30D;TETRAGRAM FOR OPPOSITION;So;0;ON;;;;;N;;;;; -1D30E;TETRAGRAM FOR BRANCHING OUT;So;0;ON;;;;;N;;;;; -1D30F;TETRAGRAM FOR DEFECTIVENESS OR DISTORTION;So;0;ON;;;;;N;;;;; -1D310;TETRAGRAM FOR DIVERGENCE;So;0;ON;;;;;N;;;;; -1D311;TETRAGRAM FOR YOUTHFULNESS;So;0;ON;;;;;N;;;;; -1D312;TETRAGRAM FOR INCREASE;So;0;ON;;;;;N;;;;; -1D313;TETRAGRAM FOR PENETRATION;So;0;ON;;;;;N;;;;; -1D314;TETRAGRAM FOR REACH;So;0;ON;;;;;N;;;;; -1D315;TETRAGRAM FOR CONTACT;So;0;ON;;;;;N;;;;; -1D316;TETRAGRAM FOR HOLDING BACK;So;0;ON;;;;;N;;;;; -1D317;TETRAGRAM FOR WAITING;So;0;ON;;;;;N;;;;; -1D318;TETRAGRAM FOR FOLLOWING;So;0;ON;;;;;N;;;;; -1D319;TETRAGRAM FOR ADVANCE;So;0;ON;;;;;N;;;;; -1D31A;TETRAGRAM FOR RELEASE;So;0;ON;;;;;N;;;;; -1D31B;TETRAGRAM FOR RESISTANCE;So;0;ON;;;;;N;;;;; -1D31C;TETRAGRAM FOR EASE;So;0;ON;;;;;N;;;;; -1D31D;TETRAGRAM FOR JOY;So;0;ON;;;;;N;;;;; -1D31E;TETRAGRAM FOR CONTENTION;So;0;ON;;;;;N;;;;; -1D31F;TETRAGRAM FOR ENDEAVOUR;So;0;ON;;;;;N;;;;; -1D320;TETRAGRAM FOR DUTIES;So;0;ON;;;;;N;;;;; -1D321;TETRAGRAM FOR CHANGE;So;0;ON;;;;;N;;;;; -1D322;TETRAGRAM FOR DECISIVENESS;So;0;ON;;;;;N;;;;; -1D323;TETRAGRAM FOR BOLD RESOLUTION;So;0;ON;;;;;N;;;;; -1D324;TETRAGRAM FOR PACKING;So;0;ON;;;;;N;;;;; -1D325;TETRAGRAM FOR LEGION;So;0;ON;;;;;N;;;;; -1D326;TETRAGRAM FOR CLOSENESS;So;0;ON;;;;;N;;;;; -1D327;TETRAGRAM FOR KINSHIP;So;0;ON;;;;;N;;;;; -1D328;TETRAGRAM FOR GATHERING;So;0;ON;;;;;N;;;;; -1D329;TETRAGRAM FOR STRENGTH;So;0;ON;;;;;N;;;;; -1D32A;TETRAGRAM FOR PURITY;So;0;ON;;;;;N;;;;; -1D32B;TETRAGRAM FOR FULLNESS;So;0;ON;;;;;N;;;;; -1D32C;TETRAGRAM FOR RESIDENCE;So;0;ON;;;;;N;;;;; -1D32D;TETRAGRAM FOR LAW OR MODEL;So;0;ON;;;;;N;;;;; -1D32E;TETRAGRAM FOR RESPONSE;So;0;ON;;;;;N;;;;; -1D32F;TETRAGRAM FOR GOING TO MEET;So;0;ON;;;;;N;;;;; -1D330;TETRAGRAM FOR ENCOUNTERS;So;0;ON;;;;;N;;;;; -1D331;TETRAGRAM FOR STOVE;So;0;ON;;;;;N;;;;; -1D332;TETRAGRAM FOR GREATNESS;So;0;ON;;;;;N;;;;; -1D333;TETRAGRAM FOR ENLARGEMENT;So;0;ON;;;;;N;;;;; -1D334;TETRAGRAM FOR PATTERN;So;0;ON;;;;;N;;;;; -1D335;TETRAGRAM FOR RITUAL;So;0;ON;;;;;N;;;;; -1D336;TETRAGRAM FOR FLIGHT;So;0;ON;;;;;N;;;;; -1D337;TETRAGRAM FOR VASTNESS OR WASTING;So;0;ON;;;;;N;;;;; -1D338;TETRAGRAM FOR CONSTANCY;So;0;ON;;;;;N;;;;; -1D339;TETRAGRAM FOR MEASURE;So;0;ON;;;;;N;;;;; -1D33A;TETRAGRAM FOR ETERNITY;So;0;ON;;;;;N;;;;; -1D33B;TETRAGRAM FOR UNITY;So;0;ON;;;;;N;;;;; -1D33C;TETRAGRAM FOR DIMINISHMENT;So;0;ON;;;;;N;;;;; -1D33D;TETRAGRAM FOR CLOSED MOUTH;So;0;ON;;;;;N;;;;; -1D33E;TETRAGRAM FOR GUARDEDNESS;So;0;ON;;;;;N;;;;; -1D33F;TETRAGRAM FOR GATHERING IN;So;0;ON;;;;;N;;;;; -1D340;TETRAGRAM FOR MASSING;So;0;ON;;;;;N;;;;; -1D341;TETRAGRAM FOR ACCUMULATION;So;0;ON;;;;;N;;;;; -1D342;TETRAGRAM FOR EMBELLISHMENT;So;0;ON;;;;;N;;;;; -1D343;TETRAGRAM FOR DOUBT;So;0;ON;;;;;N;;;;; -1D344;TETRAGRAM FOR WATCH;So;0;ON;;;;;N;;;;; -1D345;TETRAGRAM FOR SINKING;So;0;ON;;;;;N;;;;; -1D346;TETRAGRAM FOR INNER;So;0;ON;;;;;N;;;;; -1D347;TETRAGRAM FOR DEPARTURE;So;0;ON;;;;;N;;;;; -1D348;TETRAGRAM FOR DARKENING;So;0;ON;;;;;N;;;;; -1D349;TETRAGRAM FOR DIMMING;So;0;ON;;;;;N;;;;; -1D34A;TETRAGRAM FOR EXHAUSTION;So;0;ON;;;;;N;;;;; -1D34B;TETRAGRAM FOR SEVERANCE;So;0;ON;;;;;N;;;;; -1D34C;TETRAGRAM FOR STOPPAGE;So;0;ON;;;;;N;;;;; -1D34D;TETRAGRAM FOR HARDNESS;So;0;ON;;;;;N;;;;; -1D34E;TETRAGRAM FOR COMPLETION;So;0;ON;;;;;N;;;;; -1D34F;TETRAGRAM FOR CLOSURE;So;0;ON;;;;;N;;;;; -1D350;TETRAGRAM FOR FAILURE;So;0;ON;;;;;N;;;;; -1D351;TETRAGRAM FOR AGGRAVATION;So;0;ON;;;;;N;;;;; -1D352;TETRAGRAM FOR COMPLIANCE;So;0;ON;;;;;N;;;;; -1D353;TETRAGRAM FOR ON THE VERGE;So;0;ON;;;;;N;;;;; -1D354;TETRAGRAM FOR DIFFICULTIES;So;0;ON;;;;;N;;;;; -1D355;TETRAGRAM FOR LABOURING;So;0;ON;;;;;N;;;;; -1D356;TETRAGRAM FOR FOSTERING;So;0;ON;;;;;N;;;;; -1D360;COUNTING ROD UNIT DIGIT ONE;No;0;L;;;;1;N;;;;; -1D361;COUNTING ROD UNIT DIGIT TWO;No;0;L;;;;2;N;;;;; -1D362;COUNTING ROD UNIT DIGIT THREE;No;0;L;;;;3;N;;;;; -1D363;COUNTING ROD UNIT DIGIT FOUR;No;0;L;;;;4;N;;;;; -1D364;COUNTING ROD UNIT DIGIT FIVE;No;0;L;;;;5;N;;;;; -1D365;COUNTING ROD UNIT DIGIT SIX;No;0;L;;;;6;N;;;;; -1D366;COUNTING ROD UNIT DIGIT SEVEN;No;0;L;;;;7;N;;;;; -1D367;COUNTING ROD UNIT DIGIT EIGHT;No;0;L;;;;8;N;;;;; -1D368;COUNTING ROD UNIT DIGIT NINE;No;0;L;;;;9;N;;;;; -1D369;COUNTING ROD TENS DIGIT ONE;No;0;L;;;;10;N;;;;; -1D36A;COUNTING ROD TENS DIGIT TWO;No;0;L;;;;20;N;;;;; -1D36B;COUNTING ROD TENS DIGIT THREE;No;0;L;;;;30;N;;;;; -1D36C;COUNTING ROD TENS DIGIT FOUR;No;0;L;;;;40;N;;;;; -1D36D;COUNTING ROD TENS DIGIT FIVE;No;0;L;;;;50;N;;;;; -1D36E;COUNTING ROD TENS DIGIT SIX;No;0;L;;;;60;N;;;;; -1D36F;COUNTING ROD TENS DIGIT SEVEN;No;0;L;;;;70;N;;;;; -1D370;COUNTING ROD TENS DIGIT EIGHT;No;0;L;;;;80;N;;;;; -1D371;COUNTING ROD TENS DIGIT NINE;No;0;L;;;;90;N;;;;; -1D372;IDEOGRAPHIC TALLY MARK ONE;No;0;L;;;;1;N;;;;; -1D373;IDEOGRAPHIC TALLY MARK TWO;No;0;L;;;;2;N;;;;; -1D374;IDEOGRAPHIC TALLY MARK THREE;No;0;L;;;;3;N;;;;; -1D375;IDEOGRAPHIC TALLY MARK FOUR;No;0;L;;;;4;N;;;;; -1D376;IDEOGRAPHIC TALLY MARK FIVE;No;0;L;;;;5;N;;;;; -1D377;TALLY MARK ONE;No;0;L;;;;1;N;;;;; -1D378;TALLY MARK FIVE;No;0;L;;;;5;N;;;;; -1D400;MATHEMATICAL BOLD CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; -1D401;MATHEMATICAL BOLD CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; -1D402;MATHEMATICAL BOLD CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; -1D403;MATHEMATICAL BOLD CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; -1D404;MATHEMATICAL BOLD CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; -1D405;MATHEMATICAL BOLD CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; -1D406;MATHEMATICAL BOLD CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; -1D407;MATHEMATICAL BOLD CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; -1D408;MATHEMATICAL BOLD CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; -1D409;MATHEMATICAL BOLD CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; -1D40A;MATHEMATICAL BOLD CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; -1D40B;MATHEMATICAL BOLD CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; -1D40C;MATHEMATICAL BOLD CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; -1D40D;MATHEMATICAL BOLD CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; -1D40E;MATHEMATICAL BOLD CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; -1D40F;MATHEMATICAL BOLD CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; -1D410;MATHEMATICAL BOLD CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; -1D411;MATHEMATICAL BOLD CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; -1D412;MATHEMATICAL BOLD CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; -1D413;MATHEMATICAL BOLD CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; -1D414;MATHEMATICAL BOLD CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; -1D415;MATHEMATICAL BOLD CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; -1D416;MATHEMATICAL BOLD CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; -1D417;MATHEMATICAL BOLD CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; -1D418;MATHEMATICAL BOLD CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; -1D419;MATHEMATICAL BOLD CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; -1D41A;MATHEMATICAL BOLD SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; -1D41B;MATHEMATICAL BOLD SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; -1D41C;MATHEMATICAL BOLD SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; -1D41D;MATHEMATICAL BOLD SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; -1D41E;MATHEMATICAL BOLD SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; -1D41F;MATHEMATICAL BOLD SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; -1D420;MATHEMATICAL BOLD SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; -1D421;MATHEMATICAL BOLD SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; -1D422;MATHEMATICAL BOLD SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; -1D423;MATHEMATICAL BOLD SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; -1D424;MATHEMATICAL BOLD SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; -1D425;MATHEMATICAL BOLD SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; -1D426;MATHEMATICAL BOLD SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; -1D427;MATHEMATICAL BOLD SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; -1D428;MATHEMATICAL BOLD SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; -1D429;MATHEMATICAL BOLD SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; -1D42A;MATHEMATICAL BOLD SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; -1D42B;MATHEMATICAL BOLD SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; -1D42C;MATHEMATICAL BOLD SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; -1D42D;MATHEMATICAL BOLD SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; -1D42E;MATHEMATICAL BOLD SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; -1D42F;MATHEMATICAL BOLD SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; -1D430;MATHEMATICAL BOLD SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; -1D431;MATHEMATICAL BOLD SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; -1D432;MATHEMATICAL BOLD SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; -1D433;MATHEMATICAL BOLD SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; -1D434;MATHEMATICAL ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; -1D435;MATHEMATICAL ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; -1D436;MATHEMATICAL ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; -1D437;MATHEMATICAL ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; -1D438;MATHEMATICAL ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; -1D439;MATHEMATICAL ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; -1D43A;MATHEMATICAL ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; -1D43B;MATHEMATICAL ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; -1D43C;MATHEMATICAL ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; -1D43D;MATHEMATICAL ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; -1D43E;MATHEMATICAL ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; -1D43F;MATHEMATICAL ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; -1D440;MATHEMATICAL ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; -1D441;MATHEMATICAL ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; -1D442;MATHEMATICAL ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; -1D443;MATHEMATICAL ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; -1D444;MATHEMATICAL ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; -1D445;MATHEMATICAL ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; -1D446;MATHEMATICAL ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; -1D447;MATHEMATICAL ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; -1D448;MATHEMATICAL ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; -1D449;MATHEMATICAL ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; -1D44A;MATHEMATICAL ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; -1D44B;MATHEMATICAL ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; -1D44C;MATHEMATICAL ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; -1D44D;MATHEMATICAL ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; -1D44E;MATHEMATICAL ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; -1D44F;MATHEMATICAL ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; -1D450;MATHEMATICAL ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; -1D451;MATHEMATICAL ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; -1D452;MATHEMATICAL ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; -1D453;MATHEMATICAL ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; -1D454;MATHEMATICAL ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; -1D456;MATHEMATICAL ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; -1D457;MATHEMATICAL ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; -1D458;MATHEMATICAL ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; -1D459;MATHEMATICAL ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; -1D45A;MATHEMATICAL ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; -1D45B;MATHEMATICAL ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; -1D45C;MATHEMATICAL ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; -1D45D;MATHEMATICAL ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; -1D45E;MATHEMATICAL ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; -1D45F;MATHEMATICAL ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; -1D460;MATHEMATICAL ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; -1D461;MATHEMATICAL ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; -1D462;MATHEMATICAL ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; -1D463;MATHEMATICAL ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; -1D464;MATHEMATICAL ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; -1D465;MATHEMATICAL ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; -1D466;MATHEMATICAL ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; -1D467;MATHEMATICAL ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; -1D468;MATHEMATICAL BOLD ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; -1D469;MATHEMATICAL BOLD ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; -1D46A;MATHEMATICAL BOLD ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; -1D46B;MATHEMATICAL BOLD ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; -1D46C;MATHEMATICAL BOLD ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; -1D46D;MATHEMATICAL BOLD ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; -1D46E;MATHEMATICAL BOLD ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; -1D46F;MATHEMATICAL BOLD ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; -1D470;MATHEMATICAL BOLD ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; -1D471;MATHEMATICAL BOLD ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; -1D472;MATHEMATICAL BOLD ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; -1D473;MATHEMATICAL BOLD ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; -1D474;MATHEMATICAL BOLD ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; -1D475;MATHEMATICAL BOLD ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; -1D476;MATHEMATICAL BOLD ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; -1D477;MATHEMATICAL BOLD ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; -1D478;MATHEMATICAL BOLD ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; -1D479;MATHEMATICAL BOLD ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; -1D47A;MATHEMATICAL BOLD ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; -1D47B;MATHEMATICAL BOLD ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; -1D47C;MATHEMATICAL BOLD ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; -1D47D;MATHEMATICAL BOLD ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; -1D47E;MATHEMATICAL BOLD ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; -1D47F;MATHEMATICAL BOLD ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; -1D480;MATHEMATICAL BOLD ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; -1D481;MATHEMATICAL BOLD ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; -1D482;MATHEMATICAL BOLD ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; -1D483;MATHEMATICAL BOLD ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; -1D484;MATHEMATICAL BOLD ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; -1D485;MATHEMATICAL BOLD ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; -1D486;MATHEMATICAL BOLD ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; -1D487;MATHEMATICAL BOLD ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; -1D488;MATHEMATICAL BOLD ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; -1D489;MATHEMATICAL BOLD ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; -1D48A;MATHEMATICAL BOLD ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; -1D48B;MATHEMATICAL BOLD ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; -1D48C;MATHEMATICAL BOLD ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; -1D48D;MATHEMATICAL BOLD ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; -1D48E;MATHEMATICAL BOLD ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; -1D48F;MATHEMATICAL BOLD ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; -1D490;MATHEMATICAL BOLD ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; -1D491;MATHEMATICAL BOLD ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; -1D492;MATHEMATICAL BOLD ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; -1D493;MATHEMATICAL BOLD ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; -1D494;MATHEMATICAL BOLD ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; -1D495;MATHEMATICAL BOLD ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; -1D496;MATHEMATICAL BOLD ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; -1D497;MATHEMATICAL BOLD ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; -1D498;MATHEMATICAL BOLD ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; -1D499;MATHEMATICAL BOLD ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; -1D49A;MATHEMATICAL BOLD ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; -1D49B;MATHEMATICAL BOLD ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; -1D49C;MATHEMATICAL SCRIPT CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; -1D49E;MATHEMATICAL SCRIPT CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; -1D49F;MATHEMATICAL SCRIPT CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; -1D4A2;MATHEMATICAL SCRIPT CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; -1D4A5;MATHEMATICAL SCRIPT CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; -1D4A6;MATHEMATICAL SCRIPT CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; -1D4A9;MATHEMATICAL SCRIPT CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; -1D4AA;MATHEMATICAL SCRIPT CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; -1D4AB;MATHEMATICAL SCRIPT CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; -1D4AC;MATHEMATICAL SCRIPT CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; -1D4AE;MATHEMATICAL SCRIPT CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; -1D4AF;MATHEMATICAL SCRIPT CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; -1D4B0;MATHEMATICAL SCRIPT CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; -1D4B1;MATHEMATICAL SCRIPT CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; -1D4B2;MATHEMATICAL SCRIPT CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; -1D4B3;MATHEMATICAL SCRIPT CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; -1D4B4;MATHEMATICAL SCRIPT CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; -1D4B5;MATHEMATICAL SCRIPT CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; -1D4B6;MATHEMATICAL SCRIPT SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; -1D4B7;MATHEMATICAL SCRIPT SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; -1D4B8;MATHEMATICAL SCRIPT SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; -1D4B9;MATHEMATICAL SCRIPT SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; -1D4BB;MATHEMATICAL SCRIPT SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; -1D4BD;MATHEMATICAL SCRIPT SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; -1D4BE;MATHEMATICAL SCRIPT SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; -1D4BF;MATHEMATICAL SCRIPT SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; -1D4C0;MATHEMATICAL SCRIPT SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; -1D4C1;MATHEMATICAL SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; -1D4C2;MATHEMATICAL SCRIPT SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; -1D4C3;MATHEMATICAL SCRIPT SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; -1D4C5;MATHEMATICAL SCRIPT SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; -1D4C6;MATHEMATICAL SCRIPT SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; -1D4C7;MATHEMATICAL SCRIPT SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; -1D4C8;MATHEMATICAL SCRIPT SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; -1D4C9;MATHEMATICAL SCRIPT SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; -1D4CA;MATHEMATICAL SCRIPT SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; -1D4CB;MATHEMATICAL SCRIPT SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; -1D4CC;MATHEMATICAL SCRIPT SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; -1D4CD;MATHEMATICAL SCRIPT SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; -1D4CE;MATHEMATICAL SCRIPT SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; -1D4CF;MATHEMATICAL SCRIPT SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; -1D4D0;MATHEMATICAL BOLD SCRIPT CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; -1D4D1;MATHEMATICAL BOLD SCRIPT CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; -1D4D2;MATHEMATICAL BOLD SCRIPT CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; -1D4D3;MATHEMATICAL BOLD SCRIPT CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; -1D4D4;MATHEMATICAL BOLD SCRIPT CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; -1D4D5;MATHEMATICAL BOLD SCRIPT CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; -1D4D6;MATHEMATICAL BOLD SCRIPT CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; -1D4D7;MATHEMATICAL BOLD SCRIPT CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; -1D4D8;MATHEMATICAL BOLD SCRIPT CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; -1D4D9;MATHEMATICAL BOLD SCRIPT CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; -1D4DA;MATHEMATICAL BOLD SCRIPT CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; -1D4DB;MATHEMATICAL BOLD SCRIPT CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; -1D4DC;MATHEMATICAL BOLD SCRIPT CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; -1D4DD;MATHEMATICAL BOLD SCRIPT CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; -1D4DE;MATHEMATICAL BOLD SCRIPT CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; -1D4DF;MATHEMATICAL BOLD SCRIPT CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; -1D4E0;MATHEMATICAL BOLD SCRIPT CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; -1D4E1;MATHEMATICAL BOLD SCRIPT CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; -1D4E2;MATHEMATICAL BOLD SCRIPT CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; -1D4E3;MATHEMATICAL BOLD SCRIPT CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; -1D4E4;MATHEMATICAL BOLD SCRIPT CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; -1D4E5;MATHEMATICAL BOLD SCRIPT CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; -1D4E6;MATHEMATICAL BOLD SCRIPT CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; -1D4E7;MATHEMATICAL BOLD SCRIPT CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; -1D4E8;MATHEMATICAL BOLD SCRIPT CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; -1D4E9;MATHEMATICAL BOLD SCRIPT CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; -1D4EA;MATHEMATICAL BOLD SCRIPT SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; -1D4EB;MATHEMATICAL BOLD SCRIPT SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; -1D4EC;MATHEMATICAL BOLD SCRIPT SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; -1D4ED;MATHEMATICAL BOLD SCRIPT SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; -1D4EE;MATHEMATICAL BOLD SCRIPT SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; -1D4EF;MATHEMATICAL BOLD SCRIPT SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; -1D4F0;MATHEMATICAL BOLD SCRIPT SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; -1D4F1;MATHEMATICAL BOLD SCRIPT SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; -1D4F2;MATHEMATICAL BOLD SCRIPT SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; -1D4F3;MATHEMATICAL BOLD SCRIPT SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; -1D4F4;MATHEMATICAL BOLD SCRIPT SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; -1D4F5;MATHEMATICAL BOLD SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; -1D4F6;MATHEMATICAL BOLD SCRIPT SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; -1D4F7;MATHEMATICAL BOLD SCRIPT SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; -1D4F8;MATHEMATICAL BOLD SCRIPT SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; -1D4F9;MATHEMATICAL BOLD SCRIPT SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; -1D4FA;MATHEMATICAL BOLD SCRIPT SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; -1D4FB;MATHEMATICAL BOLD SCRIPT SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; -1D4FC;MATHEMATICAL BOLD SCRIPT SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; -1D4FD;MATHEMATICAL BOLD SCRIPT SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; -1D4FE;MATHEMATICAL BOLD SCRIPT SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; -1D4FF;MATHEMATICAL BOLD SCRIPT SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; -1D500;MATHEMATICAL BOLD SCRIPT SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; -1D501;MATHEMATICAL BOLD SCRIPT SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; -1D502;MATHEMATICAL BOLD SCRIPT SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; -1D503;MATHEMATICAL BOLD SCRIPT SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; -1D504;MATHEMATICAL FRAKTUR CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; -1D505;MATHEMATICAL FRAKTUR CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; -1D507;MATHEMATICAL FRAKTUR CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; -1D508;MATHEMATICAL FRAKTUR CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; -1D509;MATHEMATICAL FRAKTUR CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; -1D50A;MATHEMATICAL FRAKTUR CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; -1D50D;MATHEMATICAL FRAKTUR CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; -1D50E;MATHEMATICAL FRAKTUR CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; -1D50F;MATHEMATICAL FRAKTUR CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; -1D510;MATHEMATICAL FRAKTUR CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; -1D511;MATHEMATICAL FRAKTUR CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; -1D512;MATHEMATICAL FRAKTUR CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; -1D513;MATHEMATICAL FRAKTUR CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; -1D514;MATHEMATICAL FRAKTUR CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; -1D516;MATHEMATICAL FRAKTUR CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; -1D517;MATHEMATICAL FRAKTUR CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; -1D518;MATHEMATICAL FRAKTUR CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; -1D519;MATHEMATICAL FRAKTUR CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; -1D51A;MATHEMATICAL FRAKTUR CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; -1D51B;MATHEMATICAL FRAKTUR CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; -1D51C;MATHEMATICAL FRAKTUR CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; -1D51E;MATHEMATICAL FRAKTUR SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; -1D51F;MATHEMATICAL FRAKTUR SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; -1D520;MATHEMATICAL FRAKTUR SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; -1D521;MATHEMATICAL FRAKTUR SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; -1D522;MATHEMATICAL FRAKTUR SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; -1D523;MATHEMATICAL FRAKTUR SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; -1D524;MATHEMATICAL FRAKTUR SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; -1D525;MATHEMATICAL FRAKTUR SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; -1D526;MATHEMATICAL FRAKTUR SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; -1D527;MATHEMATICAL FRAKTUR SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; -1D528;MATHEMATICAL FRAKTUR SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; -1D529;MATHEMATICAL FRAKTUR SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; -1D52A;MATHEMATICAL FRAKTUR SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; -1D52B;MATHEMATICAL FRAKTUR SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; -1D52C;MATHEMATICAL FRAKTUR SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; -1D52D;MATHEMATICAL FRAKTUR SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; -1D52E;MATHEMATICAL FRAKTUR SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; -1D52F;MATHEMATICAL FRAKTUR SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; -1D530;MATHEMATICAL FRAKTUR SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; -1D531;MATHEMATICAL FRAKTUR SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; -1D532;MATHEMATICAL FRAKTUR SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; -1D533;MATHEMATICAL FRAKTUR SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; -1D534;MATHEMATICAL FRAKTUR SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; -1D535;MATHEMATICAL FRAKTUR SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; -1D536;MATHEMATICAL FRAKTUR SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; -1D537;MATHEMATICAL FRAKTUR SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; -1D538;MATHEMATICAL DOUBLE-STRUCK CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; -1D539;MATHEMATICAL DOUBLE-STRUCK CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; -1D53B;MATHEMATICAL DOUBLE-STRUCK CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; -1D53C;MATHEMATICAL DOUBLE-STRUCK CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; -1D53D;MATHEMATICAL DOUBLE-STRUCK CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; -1D53E;MATHEMATICAL DOUBLE-STRUCK CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; -1D540;MATHEMATICAL DOUBLE-STRUCK CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; -1D541;MATHEMATICAL DOUBLE-STRUCK CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; -1D542;MATHEMATICAL DOUBLE-STRUCK CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; -1D543;MATHEMATICAL DOUBLE-STRUCK CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; -1D544;MATHEMATICAL DOUBLE-STRUCK CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; -1D546;MATHEMATICAL DOUBLE-STRUCK CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; -1D54A;MATHEMATICAL DOUBLE-STRUCK CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; -1D54B;MATHEMATICAL DOUBLE-STRUCK CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; -1D54C;MATHEMATICAL DOUBLE-STRUCK CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; -1D54D;MATHEMATICAL DOUBLE-STRUCK CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; -1D54E;MATHEMATICAL DOUBLE-STRUCK CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; -1D54F;MATHEMATICAL DOUBLE-STRUCK CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; -1D550;MATHEMATICAL DOUBLE-STRUCK CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; -1D552;MATHEMATICAL DOUBLE-STRUCK SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; -1D553;MATHEMATICAL DOUBLE-STRUCK SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; -1D554;MATHEMATICAL DOUBLE-STRUCK SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; -1D555;MATHEMATICAL DOUBLE-STRUCK SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; -1D556;MATHEMATICAL DOUBLE-STRUCK SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; -1D557;MATHEMATICAL DOUBLE-STRUCK SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; -1D558;MATHEMATICAL DOUBLE-STRUCK SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; -1D559;MATHEMATICAL DOUBLE-STRUCK SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; -1D55A;MATHEMATICAL DOUBLE-STRUCK SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; -1D55B;MATHEMATICAL DOUBLE-STRUCK SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; -1D55C;MATHEMATICAL DOUBLE-STRUCK SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; -1D55D;MATHEMATICAL DOUBLE-STRUCK SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; -1D55E;MATHEMATICAL DOUBLE-STRUCK SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; -1D55F;MATHEMATICAL DOUBLE-STRUCK SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; -1D560;MATHEMATICAL DOUBLE-STRUCK SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; -1D561;MATHEMATICAL DOUBLE-STRUCK SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; -1D562;MATHEMATICAL DOUBLE-STRUCK SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; -1D563;MATHEMATICAL DOUBLE-STRUCK SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; -1D564;MATHEMATICAL DOUBLE-STRUCK SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; -1D565;MATHEMATICAL DOUBLE-STRUCK SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; -1D566;MATHEMATICAL DOUBLE-STRUCK SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; -1D567;MATHEMATICAL DOUBLE-STRUCK SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; -1D568;MATHEMATICAL DOUBLE-STRUCK SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; -1D569;MATHEMATICAL DOUBLE-STRUCK SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; -1D56A;MATHEMATICAL DOUBLE-STRUCK SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; -1D56B;MATHEMATICAL DOUBLE-STRUCK SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; -1D56C;MATHEMATICAL BOLD FRAKTUR CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; -1D56D;MATHEMATICAL BOLD FRAKTUR CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; -1D56E;MATHEMATICAL BOLD FRAKTUR CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; -1D56F;MATHEMATICAL BOLD FRAKTUR CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; -1D570;MATHEMATICAL BOLD FRAKTUR CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; -1D571;MATHEMATICAL BOLD FRAKTUR CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; -1D572;MATHEMATICAL BOLD FRAKTUR CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; -1D573;MATHEMATICAL BOLD FRAKTUR CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; -1D574;MATHEMATICAL BOLD FRAKTUR CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; -1D575;MATHEMATICAL BOLD FRAKTUR CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; -1D576;MATHEMATICAL BOLD FRAKTUR CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; -1D577;MATHEMATICAL BOLD FRAKTUR CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; -1D578;MATHEMATICAL BOLD FRAKTUR CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; -1D579;MATHEMATICAL BOLD FRAKTUR CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; -1D57A;MATHEMATICAL BOLD FRAKTUR CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; -1D57B;MATHEMATICAL BOLD FRAKTUR CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; -1D57C;MATHEMATICAL BOLD FRAKTUR CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; -1D57D;MATHEMATICAL BOLD FRAKTUR CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; -1D57E;MATHEMATICAL BOLD FRAKTUR CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; -1D57F;MATHEMATICAL BOLD FRAKTUR CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; -1D580;MATHEMATICAL BOLD FRAKTUR CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; -1D581;MATHEMATICAL BOLD FRAKTUR CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; -1D582;MATHEMATICAL BOLD FRAKTUR CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; -1D583;MATHEMATICAL BOLD FRAKTUR CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; -1D584;MATHEMATICAL BOLD FRAKTUR CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; -1D585;MATHEMATICAL BOLD FRAKTUR CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; -1D586;MATHEMATICAL BOLD FRAKTUR SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; -1D587;MATHEMATICAL BOLD FRAKTUR SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; -1D588;MATHEMATICAL BOLD FRAKTUR SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; -1D589;MATHEMATICAL BOLD FRAKTUR SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; -1D58A;MATHEMATICAL BOLD FRAKTUR SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; -1D58B;MATHEMATICAL BOLD FRAKTUR SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; -1D58C;MATHEMATICAL BOLD FRAKTUR SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; -1D58D;MATHEMATICAL BOLD FRAKTUR SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; -1D58E;MATHEMATICAL BOLD FRAKTUR SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; -1D58F;MATHEMATICAL BOLD FRAKTUR SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; -1D590;MATHEMATICAL BOLD FRAKTUR SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; -1D591;MATHEMATICAL BOLD FRAKTUR SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; -1D592;MATHEMATICAL BOLD FRAKTUR SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; -1D593;MATHEMATICAL BOLD FRAKTUR SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; -1D594;MATHEMATICAL BOLD FRAKTUR SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; -1D595;MATHEMATICAL BOLD FRAKTUR SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; -1D596;MATHEMATICAL BOLD FRAKTUR SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; -1D597;MATHEMATICAL BOLD FRAKTUR SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; -1D598;MATHEMATICAL BOLD FRAKTUR SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; -1D599;MATHEMATICAL BOLD FRAKTUR SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; -1D59A;MATHEMATICAL BOLD FRAKTUR SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; -1D59B;MATHEMATICAL BOLD FRAKTUR SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; -1D59C;MATHEMATICAL BOLD FRAKTUR SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; -1D59D;MATHEMATICAL BOLD FRAKTUR SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; -1D59E;MATHEMATICAL BOLD FRAKTUR SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; -1D59F;MATHEMATICAL BOLD FRAKTUR SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; -1D5A0;MATHEMATICAL SANS-SERIF CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; -1D5A1;MATHEMATICAL SANS-SERIF CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; -1D5A2;MATHEMATICAL SANS-SERIF CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; -1D5A3;MATHEMATICAL SANS-SERIF CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; -1D5A4;MATHEMATICAL SANS-SERIF CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; -1D5A5;MATHEMATICAL SANS-SERIF CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; -1D5A6;MATHEMATICAL SANS-SERIF CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; -1D5A7;MATHEMATICAL SANS-SERIF CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; -1D5A8;MATHEMATICAL SANS-SERIF CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; -1D5A9;MATHEMATICAL SANS-SERIF CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; -1D5AA;MATHEMATICAL SANS-SERIF CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; -1D5AB;MATHEMATICAL SANS-SERIF CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; -1D5AC;MATHEMATICAL SANS-SERIF CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; -1D5AD;MATHEMATICAL SANS-SERIF CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; -1D5AE;MATHEMATICAL SANS-SERIF CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; -1D5AF;MATHEMATICAL SANS-SERIF CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; -1D5B0;MATHEMATICAL SANS-SERIF CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; -1D5B1;MATHEMATICAL SANS-SERIF CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; -1D5B2;MATHEMATICAL SANS-SERIF CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; -1D5B3;MATHEMATICAL SANS-SERIF CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; -1D5B4;MATHEMATICAL SANS-SERIF CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; -1D5B5;MATHEMATICAL SANS-SERIF CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; -1D5B6;MATHEMATICAL SANS-SERIF CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; -1D5B7;MATHEMATICAL SANS-SERIF CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; -1D5B8;MATHEMATICAL SANS-SERIF CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; -1D5B9;MATHEMATICAL SANS-SERIF CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; -1D5BA;MATHEMATICAL SANS-SERIF SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; -1D5BB;MATHEMATICAL SANS-SERIF SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; -1D5BC;MATHEMATICAL SANS-SERIF SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; -1D5BD;MATHEMATICAL SANS-SERIF SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; -1D5BE;MATHEMATICAL SANS-SERIF SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; -1D5BF;MATHEMATICAL SANS-SERIF SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; -1D5C0;MATHEMATICAL SANS-SERIF SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; -1D5C1;MATHEMATICAL SANS-SERIF SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; -1D5C2;MATHEMATICAL SANS-SERIF SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; -1D5C3;MATHEMATICAL SANS-SERIF SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; -1D5C4;MATHEMATICAL SANS-SERIF SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; -1D5C5;MATHEMATICAL SANS-SERIF SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; -1D5C6;MATHEMATICAL SANS-SERIF SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; -1D5C7;MATHEMATICAL SANS-SERIF SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; -1D5C8;MATHEMATICAL SANS-SERIF SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; -1D5C9;MATHEMATICAL SANS-SERIF SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; -1D5CA;MATHEMATICAL SANS-SERIF SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; -1D5CB;MATHEMATICAL SANS-SERIF SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; -1D5CC;MATHEMATICAL SANS-SERIF SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; -1D5CD;MATHEMATICAL SANS-SERIF SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; -1D5CE;MATHEMATICAL SANS-SERIF SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; -1D5CF;MATHEMATICAL SANS-SERIF SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; -1D5D0;MATHEMATICAL SANS-SERIF SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; -1D5D1;MATHEMATICAL SANS-SERIF SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; -1D5D2;MATHEMATICAL SANS-SERIF SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; -1D5D3;MATHEMATICAL SANS-SERIF SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; -1D5D4;MATHEMATICAL SANS-SERIF BOLD CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; -1D5D5;MATHEMATICAL SANS-SERIF BOLD CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; -1D5D6;MATHEMATICAL SANS-SERIF BOLD CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; -1D5D7;MATHEMATICAL SANS-SERIF BOLD CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; -1D5D8;MATHEMATICAL SANS-SERIF BOLD CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; -1D5D9;MATHEMATICAL SANS-SERIF BOLD CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; -1D5DA;MATHEMATICAL SANS-SERIF BOLD CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; -1D5DB;MATHEMATICAL SANS-SERIF BOLD CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; -1D5DC;MATHEMATICAL SANS-SERIF BOLD CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; -1D5DD;MATHEMATICAL SANS-SERIF BOLD CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; -1D5DE;MATHEMATICAL SANS-SERIF BOLD CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; -1D5DF;MATHEMATICAL SANS-SERIF BOLD CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; -1D5E0;MATHEMATICAL SANS-SERIF BOLD CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; -1D5E1;MATHEMATICAL SANS-SERIF BOLD CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; -1D5E2;MATHEMATICAL SANS-SERIF BOLD CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; -1D5E3;MATHEMATICAL SANS-SERIF BOLD CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; -1D5E4;MATHEMATICAL SANS-SERIF BOLD CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; -1D5E5;MATHEMATICAL SANS-SERIF BOLD CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; -1D5E6;MATHEMATICAL SANS-SERIF BOLD CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; -1D5E7;MATHEMATICAL SANS-SERIF BOLD CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; -1D5E8;MATHEMATICAL SANS-SERIF BOLD CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; -1D5E9;MATHEMATICAL SANS-SERIF BOLD CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; -1D5EA;MATHEMATICAL SANS-SERIF BOLD CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; -1D5EB;MATHEMATICAL SANS-SERIF BOLD CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; -1D5EC;MATHEMATICAL SANS-SERIF BOLD CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; -1D5ED;MATHEMATICAL SANS-SERIF BOLD CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; -1D5EE;MATHEMATICAL SANS-SERIF BOLD SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; -1D5EF;MATHEMATICAL SANS-SERIF BOLD SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; -1D5F0;MATHEMATICAL SANS-SERIF BOLD SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; -1D5F1;MATHEMATICAL SANS-SERIF BOLD SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; -1D5F2;MATHEMATICAL SANS-SERIF BOLD SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; -1D5F3;MATHEMATICAL SANS-SERIF BOLD SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; -1D5F4;MATHEMATICAL SANS-SERIF BOLD SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; -1D5F5;MATHEMATICAL SANS-SERIF BOLD SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; -1D5F6;MATHEMATICAL SANS-SERIF BOLD SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; -1D5F7;MATHEMATICAL SANS-SERIF BOLD SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; -1D5F8;MATHEMATICAL SANS-SERIF BOLD SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; -1D5F9;MATHEMATICAL SANS-SERIF BOLD SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; -1D5FA;MATHEMATICAL SANS-SERIF BOLD SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; -1D5FB;MATHEMATICAL SANS-SERIF BOLD SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; -1D5FC;MATHEMATICAL SANS-SERIF BOLD SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; -1D5FD;MATHEMATICAL SANS-SERIF BOLD SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; -1D5FE;MATHEMATICAL SANS-SERIF BOLD SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; -1D5FF;MATHEMATICAL SANS-SERIF BOLD SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; -1D600;MATHEMATICAL SANS-SERIF BOLD SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; -1D601;MATHEMATICAL SANS-SERIF BOLD SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; -1D602;MATHEMATICAL SANS-SERIF BOLD SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; -1D603;MATHEMATICAL SANS-SERIF BOLD SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; -1D604;MATHEMATICAL SANS-SERIF BOLD SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; -1D605;MATHEMATICAL SANS-SERIF BOLD SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; -1D606;MATHEMATICAL SANS-SERIF BOLD SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; -1D607;MATHEMATICAL SANS-SERIF BOLD SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; -1D608;MATHEMATICAL SANS-SERIF ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; -1D609;MATHEMATICAL SANS-SERIF ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; -1D60A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; -1D60B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; -1D60C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; -1D60D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; -1D60E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; -1D60F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; -1D610;MATHEMATICAL SANS-SERIF ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; -1D611;MATHEMATICAL SANS-SERIF ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; -1D612;MATHEMATICAL SANS-SERIF ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; -1D613;MATHEMATICAL SANS-SERIF ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; -1D614;MATHEMATICAL SANS-SERIF ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; -1D615;MATHEMATICAL SANS-SERIF ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; -1D616;MATHEMATICAL SANS-SERIF ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; -1D617;MATHEMATICAL SANS-SERIF ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; -1D618;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; -1D619;MATHEMATICAL SANS-SERIF ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; -1D61A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; -1D61B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; -1D61C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; -1D61D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; -1D61E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; -1D61F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; -1D620;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; -1D621;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; -1D622;MATHEMATICAL SANS-SERIF ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; -1D623;MATHEMATICAL SANS-SERIF ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; -1D624;MATHEMATICAL SANS-SERIF ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; -1D625;MATHEMATICAL SANS-SERIF ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; -1D626;MATHEMATICAL SANS-SERIF ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; -1D627;MATHEMATICAL SANS-SERIF ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; -1D628;MATHEMATICAL SANS-SERIF ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; -1D629;MATHEMATICAL SANS-SERIF ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; -1D62A;MATHEMATICAL SANS-SERIF ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; -1D62B;MATHEMATICAL SANS-SERIF ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; -1D62C;MATHEMATICAL SANS-SERIF ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; -1D62D;MATHEMATICAL SANS-SERIF ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; -1D62E;MATHEMATICAL SANS-SERIF ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; -1D62F;MATHEMATICAL SANS-SERIF ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; -1D630;MATHEMATICAL SANS-SERIF ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; -1D631;MATHEMATICAL SANS-SERIF ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; -1D632;MATHEMATICAL SANS-SERIF ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; -1D633;MATHEMATICAL SANS-SERIF ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; -1D634;MATHEMATICAL SANS-SERIF ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; -1D635;MATHEMATICAL SANS-SERIF ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; -1D636;MATHEMATICAL SANS-SERIF ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; -1D637;MATHEMATICAL SANS-SERIF ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; -1D638;MATHEMATICAL SANS-SERIF ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; -1D639;MATHEMATICAL SANS-SERIF ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; -1D63A;MATHEMATICAL SANS-SERIF ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; -1D63B;MATHEMATICAL SANS-SERIF ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; -1D63C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; -1D63D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; -1D63E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; -1D63F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; -1D640;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; -1D641;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; -1D642;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; -1D643;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; -1D644;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; -1D645;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; -1D646;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; -1D647;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; -1D648;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; -1D649;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; -1D64A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; -1D64B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; -1D64C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; -1D64D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; -1D64E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; -1D64F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; -1D650;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; -1D651;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; -1D652;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; -1D653;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; -1D654;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; -1D655;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; -1D656;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; -1D657;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; -1D658;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; -1D659;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; -1D65A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; -1D65B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; -1D65C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; -1D65D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; -1D65E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; -1D65F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; -1D660;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; -1D661;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; -1D662;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; -1D663;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; -1D664;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; -1D665;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; -1D666;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; -1D667;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; -1D668;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; -1D669;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; -1D66A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; -1D66B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; -1D66C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; -1D66D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; -1D66E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; -1D66F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; -1D670;MATHEMATICAL MONOSPACE CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; -1D671;MATHEMATICAL MONOSPACE CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; -1D672;MATHEMATICAL MONOSPACE CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; -1D673;MATHEMATICAL MONOSPACE CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; -1D674;MATHEMATICAL MONOSPACE CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; -1D675;MATHEMATICAL MONOSPACE CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; -1D676;MATHEMATICAL MONOSPACE CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; -1D677;MATHEMATICAL MONOSPACE CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; -1D678;MATHEMATICAL MONOSPACE CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; -1D679;MATHEMATICAL MONOSPACE CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; -1D67A;MATHEMATICAL MONOSPACE CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; -1D67B;MATHEMATICAL MONOSPACE CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; -1D67C;MATHEMATICAL MONOSPACE CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; -1D67D;MATHEMATICAL MONOSPACE CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; -1D67E;MATHEMATICAL MONOSPACE CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; -1D67F;MATHEMATICAL MONOSPACE CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; -1D680;MATHEMATICAL MONOSPACE CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; -1D681;MATHEMATICAL MONOSPACE CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; -1D682;MATHEMATICAL MONOSPACE CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; -1D683;MATHEMATICAL MONOSPACE CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; -1D684;MATHEMATICAL MONOSPACE CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; -1D685;MATHEMATICAL MONOSPACE CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; -1D686;MATHEMATICAL MONOSPACE CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; -1D687;MATHEMATICAL MONOSPACE CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; -1D688;MATHEMATICAL MONOSPACE CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; -1D689;MATHEMATICAL MONOSPACE CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; -1D68A;MATHEMATICAL MONOSPACE SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; -1D68B;MATHEMATICAL MONOSPACE SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; -1D68C;MATHEMATICAL MONOSPACE SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; -1D68D;MATHEMATICAL MONOSPACE SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; -1D68E;MATHEMATICAL MONOSPACE SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; -1D68F;MATHEMATICAL MONOSPACE SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; -1D690;MATHEMATICAL MONOSPACE SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; -1D691;MATHEMATICAL MONOSPACE SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; -1D692;MATHEMATICAL MONOSPACE SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; -1D693;MATHEMATICAL MONOSPACE SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; -1D694;MATHEMATICAL MONOSPACE SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; -1D695;MATHEMATICAL MONOSPACE SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; -1D696;MATHEMATICAL MONOSPACE SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; -1D697;MATHEMATICAL MONOSPACE SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; -1D698;MATHEMATICAL MONOSPACE SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; -1D699;MATHEMATICAL MONOSPACE SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; -1D69A;MATHEMATICAL MONOSPACE SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; -1D69B;MATHEMATICAL MONOSPACE SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; -1D69C;MATHEMATICAL MONOSPACE SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; -1D69D;MATHEMATICAL MONOSPACE SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; -1D69E;MATHEMATICAL MONOSPACE SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; -1D69F;MATHEMATICAL MONOSPACE SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; -1D6A0;MATHEMATICAL MONOSPACE SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; -1D6A1;MATHEMATICAL MONOSPACE SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; -1D6A2;MATHEMATICAL MONOSPACE SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; -1D6A3;MATHEMATICAL MONOSPACE SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; -1D6A4;MATHEMATICAL ITALIC SMALL DOTLESS I;Ll;0;L;<font> 0131;;;;N;;;;; -1D6A5;MATHEMATICAL ITALIC SMALL DOTLESS J;Ll;0;L;<font> 0237;;;;N;;;;; -1D6A8;MATHEMATICAL BOLD CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;; -1D6A9;MATHEMATICAL BOLD CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;; -1D6AA;MATHEMATICAL BOLD CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;; -1D6AB;MATHEMATICAL BOLD CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;; -1D6AC;MATHEMATICAL BOLD CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;; -1D6AD;MATHEMATICAL BOLD CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;; -1D6AE;MATHEMATICAL BOLD CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;; -1D6AF;MATHEMATICAL BOLD CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;; -1D6B0;MATHEMATICAL BOLD CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;; -1D6B1;MATHEMATICAL BOLD CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;; -1D6B2;MATHEMATICAL BOLD CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;; -1D6B3;MATHEMATICAL BOLD CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;; -1D6B4;MATHEMATICAL BOLD CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;; -1D6B5;MATHEMATICAL BOLD CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;; -1D6B6;MATHEMATICAL BOLD CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;; -1D6B7;MATHEMATICAL BOLD CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;; -1D6B8;MATHEMATICAL BOLD CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;; -1D6B9;MATHEMATICAL BOLD CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;; -1D6BA;MATHEMATICAL BOLD CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;; -1D6BB;MATHEMATICAL BOLD CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;; -1D6BC;MATHEMATICAL BOLD CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;; -1D6BD;MATHEMATICAL BOLD CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;; -1D6BE;MATHEMATICAL BOLD CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;; -1D6BF;MATHEMATICAL BOLD CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;; -1D6C0;MATHEMATICAL BOLD CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;; -1D6C1;MATHEMATICAL BOLD NABLA;Sm;0;L;<font> 2207;;;;N;;;;; -1D6C2;MATHEMATICAL BOLD SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;; -1D6C3;MATHEMATICAL BOLD SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;; -1D6C4;MATHEMATICAL BOLD SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;; -1D6C5;MATHEMATICAL BOLD SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;; -1D6C6;MATHEMATICAL BOLD SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;; -1D6C7;MATHEMATICAL BOLD SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;; -1D6C8;MATHEMATICAL BOLD SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;; -1D6C9;MATHEMATICAL BOLD SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;; -1D6CA;MATHEMATICAL BOLD SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;; -1D6CB;MATHEMATICAL BOLD SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;; -1D6CC;MATHEMATICAL BOLD SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;; -1D6CD;MATHEMATICAL BOLD SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;; -1D6CE;MATHEMATICAL BOLD SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;; -1D6CF;MATHEMATICAL BOLD SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;; -1D6D0;MATHEMATICAL BOLD SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;; -1D6D1;MATHEMATICAL BOLD SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;; -1D6D2;MATHEMATICAL BOLD SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;; -1D6D3;MATHEMATICAL BOLD SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;; -1D6D4;MATHEMATICAL BOLD SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;; -1D6D5;MATHEMATICAL BOLD SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;; -1D6D6;MATHEMATICAL BOLD SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;; -1D6D7;MATHEMATICAL BOLD SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;; -1D6D8;MATHEMATICAL BOLD SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;; -1D6D9;MATHEMATICAL BOLD SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;; -1D6DA;MATHEMATICAL BOLD SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;; -1D6DB;MATHEMATICAL BOLD PARTIAL DIFFERENTIAL;Sm;0;ON;<font> 2202;;;;Y;;;;; -1D6DC;MATHEMATICAL BOLD EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;; -1D6DD;MATHEMATICAL BOLD THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;; -1D6DE;MATHEMATICAL BOLD KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;; -1D6DF;MATHEMATICAL BOLD PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;; -1D6E0;MATHEMATICAL BOLD RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;; -1D6E1;MATHEMATICAL BOLD PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;; -1D6E2;MATHEMATICAL ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;; -1D6E3;MATHEMATICAL ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;; -1D6E4;MATHEMATICAL ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;; -1D6E5;MATHEMATICAL ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;; -1D6E6;MATHEMATICAL ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;; -1D6E7;MATHEMATICAL ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;; -1D6E8;MATHEMATICAL ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;; -1D6E9;MATHEMATICAL ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;; -1D6EA;MATHEMATICAL ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;; -1D6EB;MATHEMATICAL ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;; -1D6EC;MATHEMATICAL ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;; -1D6ED;MATHEMATICAL ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;; -1D6EE;MATHEMATICAL ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;; -1D6EF;MATHEMATICAL ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;; -1D6F0;MATHEMATICAL ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;; -1D6F1;MATHEMATICAL ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;; -1D6F2;MATHEMATICAL ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;; -1D6F3;MATHEMATICAL ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;; -1D6F4;MATHEMATICAL ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;; -1D6F5;MATHEMATICAL ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;; -1D6F6;MATHEMATICAL ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;; -1D6F7;MATHEMATICAL ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;; -1D6F8;MATHEMATICAL ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;; -1D6F9;MATHEMATICAL ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;; -1D6FA;MATHEMATICAL ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;; -1D6FB;MATHEMATICAL ITALIC NABLA;Sm;0;L;<font> 2207;;;;N;;;;; -1D6FC;MATHEMATICAL ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;; -1D6FD;MATHEMATICAL ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;; -1D6FE;MATHEMATICAL ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;; -1D6FF;MATHEMATICAL ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;; -1D700;MATHEMATICAL ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;; -1D701;MATHEMATICAL ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;; -1D702;MATHEMATICAL ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;; -1D703;MATHEMATICAL ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;; -1D704;MATHEMATICAL ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;; -1D705;MATHEMATICAL ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;; -1D706;MATHEMATICAL ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;; -1D707;MATHEMATICAL ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;; -1D708;MATHEMATICAL ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;; -1D709;MATHEMATICAL ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;; -1D70A;MATHEMATICAL ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;; -1D70B;MATHEMATICAL ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;; -1D70C;MATHEMATICAL ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;; -1D70D;MATHEMATICAL ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;; -1D70E;MATHEMATICAL ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;; -1D70F;MATHEMATICAL ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;; -1D710;MATHEMATICAL ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;; -1D711;MATHEMATICAL ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;; -1D712;MATHEMATICAL ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;; -1D713;MATHEMATICAL ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;; -1D714;MATHEMATICAL ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;; -1D715;MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL;Sm;0;ON;<font> 2202;;;;Y;;;;; -1D716;MATHEMATICAL ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;; -1D717;MATHEMATICAL ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;; -1D718;MATHEMATICAL ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;; -1D719;MATHEMATICAL ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;; -1D71A;MATHEMATICAL ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;; -1D71B;MATHEMATICAL ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;; -1D71C;MATHEMATICAL BOLD ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;; -1D71D;MATHEMATICAL BOLD ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;; -1D71E;MATHEMATICAL BOLD ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;; -1D71F;MATHEMATICAL BOLD ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;; -1D720;MATHEMATICAL BOLD ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;; -1D721;MATHEMATICAL BOLD ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;; -1D722;MATHEMATICAL BOLD ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;; -1D723;MATHEMATICAL BOLD ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;; -1D724;MATHEMATICAL BOLD ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;; -1D725;MATHEMATICAL BOLD ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;; -1D726;MATHEMATICAL BOLD ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;; -1D727;MATHEMATICAL BOLD ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;; -1D728;MATHEMATICAL BOLD ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;; -1D729;MATHEMATICAL BOLD ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;; -1D72A;MATHEMATICAL BOLD ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;; -1D72B;MATHEMATICAL BOLD ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;; -1D72C;MATHEMATICAL BOLD ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;; -1D72D;MATHEMATICAL BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;; -1D72E;MATHEMATICAL BOLD ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;; -1D72F;MATHEMATICAL BOLD ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;; -1D730;MATHEMATICAL BOLD ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;; -1D731;MATHEMATICAL BOLD ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;; -1D732;MATHEMATICAL BOLD ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;; -1D733;MATHEMATICAL BOLD ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;; -1D734;MATHEMATICAL BOLD ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;; -1D735;MATHEMATICAL BOLD ITALIC NABLA;Sm;0;L;<font> 2207;;;;N;;;;; -1D736;MATHEMATICAL BOLD ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;; -1D737;MATHEMATICAL BOLD ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;; -1D738;MATHEMATICAL BOLD ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;; -1D739;MATHEMATICAL BOLD ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;; -1D73A;MATHEMATICAL BOLD ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;; -1D73B;MATHEMATICAL BOLD ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;; -1D73C;MATHEMATICAL BOLD ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;; -1D73D;MATHEMATICAL BOLD ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;; -1D73E;MATHEMATICAL BOLD ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;; -1D73F;MATHEMATICAL BOLD ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;; -1D740;MATHEMATICAL BOLD ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;; -1D741;MATHEMATICAL BOLD ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;; -1D742;MATHEMATICAL BOLD ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;; -1D743;MATHEMATICAL BOLD ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;; -1D744;MATHEMATICAL BOLD ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;; -1D745;MATHEMATICAL BOLD ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;; -1D746;MATHEMATICAL BOLD ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;; -1D747;MATHEMATICAL BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;; -1D748;MATHEMATICAL BOLD ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;; -1D749;MATHEMATICAL BOLD ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;; -1D74A;MATHEMATICAL BOLD ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;; -1D74B;MATHEMATICAL BOLD ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;; -1D74C;MATHEMATICAL BOLD ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;; -1D74D;MATHEMATICAL BOLD ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;; -1D74E;MATHEMATICAL BOLD ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;; -1D74F;MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;ON;<font> 2202;;;;Y;;;;; -1D750;MATHEMATICAL BOLD ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;; -1D751;MATHEMATICAL BOLD ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;; -1D752;MATHEMATICAL BOLD ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;; -1D753;MATHEMATICAL BOLD ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;; -1D754;MATHEMATICAL BOLD ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;; -1D755;MATHEMATICAL BOLD ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;; -1D756;MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;; -1D757;MATHEMATICAL SANS-SERIF BOLD CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;; -1D758;MATHEMATICAL SANS-SERIF BOLD CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;; -1D759;MATHEMATICAL SANS-SERIF BOLD CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;; -1D75A;MATHEMATICAL SANS-SERIF BOLD CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;; -1D75B;MATHEMATICAL SANS-SERIF BOLD CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;; -1D75C;MATHEMATICAL SANS-SERIF BOLD CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;; -1D75D;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;; -1D75E;MATHEMATICAL SANS-SERIF BOLD CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;; -1D75F;MATHEMATICAL SANS-SERIF BOLD CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;; -1D760;MATHEMATICAL SANS-SERIF BOLD CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;; -1D761;MATHEMATICAL SANS-SERIF BOLD CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;; -1D762;MATHEMATICAL SANS-SERIF BOLD CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;; -1D763;MATHEMATICAL SANS-SERIF BOLD CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;; -1D764;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;; -1D765;MATHEMATICAL SANS-SERIF BOLD CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;; -1D766;MATHEMATICAL SANS-SERIF BOLD CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;; -1D767;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;; -1D768;MATHEMATICAL SANS-SERIF BOLD CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;; -1D769;MATHEMATICAL SANS-SERIF BOLD CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;; -1D76A;MATHEMATICAL SANS-SERIF BOLD CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;; -1D76B;MATHEMATICAL SANS-SERIF BOLD CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;; -1D76C;MATHEMATICAL SANS-SERIF BOLD CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;; -1D76D;MATHEMATICAL SANS-SERIF BOLD CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;; -1D76E;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;; -1D76F;MATHEMATICAL SANS-SERIF BOLD NABLA;Sm;0;L;<font> 2207;;;;N;;;;; -1D770;MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;; -1D771;MATHEMATICAL SANS-SERIF BOLD SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;; -1D772;MATHEMATICAL SANS-SERIF BOLD SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;; -1D773;MATHEMATICAL SANS-SERIF BOLD SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;; -1D774;MATHEMATICAL SANS-SERIF BOLD SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;; -1D775;MATHEMATICAL SANS-SERIF BOLD SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;; -1D776;MATHEMATICAL SANS-SERIF BOLD SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;; -1D777;MATHEMATICAL SANS-SERIF BOLD SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;; -1D778;MATHEMATICAL SANS-SERIF BOLD SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;; -1D779;MATHEMATICAL SANS-SERIF BOLD SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;; -1D77A;MATHEMATICAL SANS-SERIF BOLD SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;; -1D77B;MATHEMATICAL SANS-SERIF BOLD SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;; -1D77C;MATHEMATICAL SANS-SERIF BOLD SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;; -1D77D;MATHEMATICAL SANS-SERIF BOLD SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;; -1D77E;MATHEMATICAL SANS-SERIF BOLD SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;; -1D77F;MATHEMATICAL SANS-SERIF BOLD SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;; -1D780;MATHEMATICAL SANS-SERIF BOLD SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;; -1D781;MATHEMATICAL SANS-SERIF BOLD SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;; -1D782;MATHEMATICAL SANS-SERIF BOLD SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;; -1D783;MATHEMATICAL SANS-SERIF BOLD SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;; -1D784;MATHEMATICAL SANS-SERIF BOLD SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;; -1D785;MATHEMATICAL SANS-SERIF BOLD SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;; -1D786;MATHEMATICAL SANS-SERIF BOLD SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;; -1D787;MATHEMATICAL SANS-SERIF BOLD SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;; -1D788;MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;; -1D789;MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL;Sm;0;ON;<font> 2202;;;;Y;;;;; -1D78A;MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;; -1D78B;MATHEMATICAL SANS-SERIF BOLD THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;; -1D78C;MATHEMATICAL SANS-SERIF BOLD KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;; -1D78D;MATHEMATICAL SANS-SERIF BOLD PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;; -1D78E;MATHEMATICAL SANS-SERIF BOLD RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;; -1D78F;MATHEMATICAL SANS-SERIF BOLD PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;; -1D790;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;; -1D791;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;; -1D792;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;; -1D793;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;; -1D794;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;; -1D795;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;; -1D796;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;; -1D797;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;; -1D798;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;; -1D799;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;; -1D79A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;; -1D79B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;; -1D79C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;; -1D79D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;; -1D79E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;; -1D79F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;; -1D7A0;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;; -1D7A1;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;; -1D7A2;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;; -1D7A3;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;; -1D7A4;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;; -1D7A5;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;; -1D7A6;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;; -1D7A7;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;; -1D7A8;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;; -1D7A9;MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA;Sm;0;L;<font> 2207;;;;N;;;;; -1D7AA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;; -1D7AB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;; -1D7AC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;; -1D7AD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;; -1D7AE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;; -1D7AF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;; -1D7B0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;; -1D7B1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;; -1D7B2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;; -1D7B3;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;; -1D7B4;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;; -1D7B5;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;; -1D7B6;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;; -1D7B7;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;; -1D7B8;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;; -1D7B9;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;; -1D7BA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;; -1D7BB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;; -1D7BC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;; -1D7BD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;; -1D7BE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;; -1D7BF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;; -1D7C0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;; -1D7C1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;; -1D7C2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;; -1D7C3;MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;ON;<font> 2202;;;;Y;;;;; -1D7C4;MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;; -1D7C5;MATHEMATICAL SANS-SERIF BOLD ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;; -1D7C6;MATHEMATICAL SANS-SERIF BOLD ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;; -1D7C7;MATHEMATICAL SANS-SERIF BOLD ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;; -1D7C8;MATHEMATICAL SANS-SERIF BOLD ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;; -1D7C9;MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;; -1D7CA;MATHEMATICAL BOLD CAPITAL DIGAMMA;Lu;0;L;<font> 03DC;;;;N;;;;; -1D7CB;MATHEMATICAL BOLD SMALL DIGAMMA;Ll;0;L;<font> 03DD;;;;N;;;;; -1D7CE;MATHEMATICAL BOLD DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;; -1D7CF;MATHEMATICAL BOLD DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;; -1D7D0;MATHEMATICAL BOLD DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;; -1D7D1;MATHEMATICAL BOLD DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;; -1D7D2;MATHEMATICAL BOLD DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;; -1D7D3;MATHEMATICAL BOLD DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;; -1D7D4;MATHEMATICAL BOLD DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;; -1D7D5;MATHEMATICAL BOLD DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;; -1D7D6;MATHEMATICAL BOLD DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;; -1D7D7;MATHEMATICAL BOLD DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;; -1D7D8;MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;; -1D7D9;MATHEMATICAL DOUBLE-STRUCK DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;; -1D7DA;MATHEMATICAL DOUBLE-STRUCK DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;; -1D7DB;MATHEMATICAL DOUBLE-STRUCK DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;; -1D7DC;MATHEMATICAL DOUBLE-STRUCK DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;; -1D7DD;MATHEMATICAL DOUBLE-STRUCK DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;; -1D7DE;MATHEMATICAL DOUBLE-STRUCK DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;; -1D7DF;MATHEMATICAL DOUBLE-STRUCK DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;; -1D7E0;MATHEMATICAL DOUBLE-STRUCK DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;; -1D7E1;MATHEMATICAL DOUBLE-STRUCK DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;; -1D7E2;MATHEMATICAL SANS-SERIF DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;; -1D7E3;MATHEMATICAL SANS-SERIF DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;; -1D7E4;MATHEMATICAL SANS-SERIF DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;; -1D7E5;MATHEMATICAL SANS-SERIF DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;; -1D7E6;MATHEMATICAL SANS-SERIF DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;; -1D7E7;MATHEMATICAL SANS-SERIF DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;; -1D7E8;MATHEMATICAL SANS-SERIF DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;; -1D7E9;MATHEMATICAL SANS-SERIF DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;; -1D7EA;MATHEMATICAL SANS-SERIF DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;; -1D7EB;MATHEMATICAL SANS-SERIF DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;; -1D7EC;MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;; -1D7ED;MATHEMATICAL SANS-SERIF BOLD DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;; -1D7EE;MATHEMATICAL SANS-SERIF BOLD DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;; -1D7EF;MATHEMATICAL SANS-SERIF BOLD DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;; -1D7F0;MATHEMATICAL SANS-SERIF BOLD DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;; -1D7F1;MATHEMATICAL SANS-SERIF BOLD DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;; -1D7F2;MATHEMATICAL SANS-SERIF BOLD DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;; -1D7F3;MATHEMATICAL SANS-SERIF BOLD DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;; -1D7F4;MATHEMATICAL SANS-SERIF BOLD DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;; -1D7F5;MATHEMATICAL SANS-SERIF BOLD DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;; -1D7F6;MATHEMATICAL MONOSPACE DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;; -1D7F7;MATHEMATICAL MONOSPACE DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;; -1D7F8;MATHEMATICAL MONOSPACE DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;; -1D7F9;MATHEMATICAL MONOSPACE DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;; -1D7FA;MATHEMATICAL MONOSPACE DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;; -1D7FB;MATHEMATICAL MONOSPACE DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;; -1D7FC;MATHEMATICAL MONOSPACE DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;; -1D7FD;MATHEMATICAL MONOSPACE DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;; -1D7FE;MATHEMATICAL MONOSPACE DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;; -1D7FF;MATHEMATICAL MONOSPACE DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;; -1D800;SIGNWRITING HAND-FIST INDEX;So;0;L;;;;;N;;;;; -1D801;SIGNWRITING HAND-CIRCLE INDEX;So;0;L;;;;;N;;;;; -1D802;SIGNWRITING HAND-CUP INDEX;So;0;L;;;;;N;;;;; -1D803;SIGNWRITING HAND-OVAL INDEX;So;0;L;;;;;N;;;;; -1D804;SIGNWRITING HAND-HINGE INDEX;So;0;L;;;;;N;;;;; -1D805;SIGNWRITING HAND-ANGLE INDEX;So;0;L;;;;;N;;;;; -1D806;SIGNWRITING HAND-FIST INDEX BENT;So;0;L;;;;;N;;;;; -1D807;SIGNWRITING HAND-CIRCLE INDEX BENT;So;0;L;;;;;N;;;;; -1D808;SIGNWRITING HAND-FIST THUMB UNDER INDEX BENT;So;0;L;;;;;N;;;;; -1D809;SIGNWRITING HAND-FIST INDEX RAISED KNUCKLE;So;0;L;;;;;N;;;;; -1D80A;SIGNWRITING HAND-FIST INDEX CUPPED;So;0;L;;;;;N;;;;; -1D80B;SIGNWRITING HAND-FIST INDEX HINGED;So;0;L;;;;;N;;;;; -1D80C;SIGNWRITING HAND-FIST INDEX HINGED LOW;So;0;L;;;;;N;;;;; -1D80D;SIGNWRITING HAND-CIRCLE INDEX HINGE;So;0;L;;;;;N;;;;; -1D80E;SIGNWRITING HAND-FIST INDEX MIDDLE;So;0;L;;;;;N;;;;; -1D80F;SIGNWRITING HAND-CIRCLE INDEX MIDDLE;So;0;L;;;;;N;;;;; -1D810;SIGNWRITING HAND-FIST INDEX MIDDLE BENT;So;0;L;;;;;N;;;;; -1D811;SIGNWRITING HAND-FIST INDEX MIDDLE RAISED KNUCKLES;So;0;L;;;;;N;;;;; -1D812;SIGNWRITING HAND-FIST INDEX MIDDLE HINGED;So;0;L;;;;;N;;;;; -1D813;SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED;So;0;L;;;;;N;;;;; -1D814;SIGNWRITING HAND-FIST INDEX HINGED MIDDLE UP;So;0;L;;;;;N;;;;; -1D815;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED;So;0;L;;;;;N;;;;; -1D816;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED INDEX BENT;So;0;L;;;;;N;;;;; -1D817;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED MIDDLE BENT;So;0;L;;;;;N;;;;; -1D818;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED CUPPED;So;0;L;;;;;N;;;;; -1D819;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED HINGED;So;0;L;;;;;N;;;;; -1D81A;SIGNWRITING HAND-FIST INDEX MIDDLE CROSSED;So;0;L;;;;;N;;;;; -1D81B;SIGNWRITING HAND-CIRCLE INDEX MIDDLE CROSSED;So;0;L;;;;;N;;;;; -1D81C;SIGNWRITING HAND-FIST MIDDLE BENT OVER INDEX;So;0;L;;;;;N;;;;; -1D81D;SIGNWRITING HAND-FIST INDEX BENT OVER MIDDLE;So;0;L;;;;;N;;;;; -1D81E;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB;So;0;L;;;;;N;;;;; -1D81F;SIGNWRITING HAND-CIRCLE INDEX MIDDLE THUMB;So;0;L;;;;;N;;;;; -1D820;SIGNWRITING HAND-FIST INDEX MIDDLE STRAIGHT THUMB BENT;So;0;L;;;;;N;;;;; -1D821;SIGNWRITING HAND-FIST INDEX MIDDLE BENT THUMB STRAIGHT;So;0;L;;;;;N;;;;; -1D822;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB BENT;So;0;L;;;;;N;;;;; -1D823;SIGNWRITING HAND-FIST INDEX MIDDLE HINGED SPREAD THUMB SIDE;So;0;L;;;;;N;;;;; -1D824;SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED THUMB SIDE;So;0;L;;;;;N;;;;; -1D825;SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED THUMB CONJOINED;So;0;L;;;;;N;;;;; -1D826;SIGNWRITING HAND-FIST INDEX HINGED MIDDLE UP THUMB SIDE;So;0;L;;;;;N;;;;; -1D827;SIGNWRITING HAND-FIST INDEX MIDDLE UP SPREAD THUMB FORWARD;So;0;L;;;;;N;;;;; -1D828;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CUPPED;So;0;L;;;;;N;;;;; -1D829;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CIRCLED;So;0;L;;;;;N;;;;; -1D82A;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB HOOKED;So;0;L;;;;;N;;;;; -1D82B;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB HINGED;So;0;L;;;;;N;;;;; -1D82C;SIGNWRITING HAND-FIST THUMB BETWEEN INDEX MIDDLE STRAIGHT;So;0;L;;;;;N;;;;; -1D82D;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE;So;0;L;;;;;N;;;;; -1D82E;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE CONJOINED;So;0;L;;;;;N;;;;; -1D82F;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE BENT;So;0;L;;;;;N;;;;; -1D830;SIGNWRITING HAND-FIST MIDDLE THUMB HOOKED INDEX UP;So;0;L;;;;;N;;;;; -1D831;SIGNWRITING HAND-FIST INDEX THUMB HOOKED MIDDLE UP;So;0;L;;;;;N;;;;; -1D832;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED HINGED THUMB SIDE;So;0;L;;;;;N;;;;; -1D833;SIGNWRITING HAND-FIST INDEX MIDDLE CROSSED THUMB SIDE;So;0;L;;;;;N;;;;; -1D834;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB FORWARD;So;0;L;;;;;N;;;;; -1D835;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED CUPPED THUMB FORWARD;So;0;L;;;;;N;;;;; -1D836;SIGNWRITING HAND-FIST MIDDLE THUMB CUPPED INDEX UP;So;0;L;;;;;N;;;;; -1D837;SIGNWRITING HAND-FIST INDEX THUMB CUPPED MIDDLE UP;So;0;L;;;;;N;;;;; -1D838;SIGNWRITING HAND-FIST MIDDLE THUMB CIRCLED INDEX UP;So;0;L;;;;;N;;;;; -1D839;SIGNWRITING HAND-FIST MIDDLE THUMB CIRCLED INDEX HINGED;So;0;L;;;;;N;;;;; -1D83A;SIGNWRITING HAND-FIST INDEX THUMB ANGLED OUT MIDDLE UP;So;0;L;;;;;N;;;;; -1D83B;SIGNWRITING HAND-FIST INDEX THUMB ANGLED IN MIDDLE UP;So;0;L;;;;;N;;;;; -1D83C;SIGNWRITING HAND-FIST INDEX THUMB CIRCLED MIDDLE UP;So;0;L;;;;;N;;;;; -1D83D;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CONJOINED HINGED;So;0;L;;;;;N;;;;; -1D83E;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB ANGLED OUT;So;0;L;;;;;N;;;;; -1D83F;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB ANGLED;So;0;L;;;;;N;;;;; -1D840;SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED OUT INDEX UP;So;0;L;;;;;N;;;;; -1D841;SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED OUT INDEX CROSSED;So;0;L;;;;;N;;;;; -1D842;SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED INDEX UP;So;0;L;;;;;N;;;;; -1D843;SIGNWRITING HAND-FIST INDEX THUMB HOOKED MIDDLE HINGED;So;0;L;;;;;N;;;;; -1D844;SIGNWRITING HAND-FLAT FOUR FINGERS;So;0;L;;;;;N;;;;; -1D845;SIGNWRITING HAND-FLAT FOUR FINGERS BENT;So;0;L;;;;;N;;;;; -1D846;SIGNWRITING HAND-FLAT FOUR FINGERS HINGED;So;0;L;;;;;N;;;;; -1D847;SIGNWRITING HAND-FLAT FOUR FINGERS CONJOINED;So;0;L;;;;;N;;;;; -1D848;SIGNWRITING HAND-FLAT FOUR FINGERS CONJOINED SPLIT;So;0;L;;;;;N;;;;; -1D849;SIGNWRITING HAND-CLAW FOUR FINGERS CONJOINED;So;0;L;;;;;N;;;;; -1D84A;SIGNWRITING HAND-FIST FOUR FINGERS CONJOINED BENT;So;0;L;;;;;N;;;;; -1D84B;SIGNWRITING HAND-HINGE FOUR FINGERS CONJOINED;So;0;L;;;;;N;;;;; -1D84C;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;; -1D84D;SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;; -1D84E;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD FOUR BENT;So;0;L;;;;;N;;;;; -1D84F;SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD FOUR BENT;So;0;L;;;;;N;;;;; -1D850;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD BENT;So;0;L;;;;;N;;;;; -1D851;SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD BENT;So;0;L;;;;;N;;;;; -1D852;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD THUMB FORWARD;So;0;L;;;;;N;;;;; -1D853;SIGNWRITING HAND-CUP FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;; -1D854;SIGNWRITING HAND-CUP FIVE FINGERS SPREAD OPEN;So;0;L;;;;;N;;;;; -1D855;SIGNWRITING HAND-HINGE FIVE FINGERS SPREAD OPEN;So;0;L;;;;;N;;;;; -1D856;SIGNWRITING HAND-OVAL FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;; -1D857;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED;So;0;L;;;;;N;;;;; -1D858;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED THUMB SIDE;So;0;L;;;;;N;;;;; -1D859;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED NO THUMB;So;0;L;;;;;N;;;;; -1D85A;SIGNWRITING HAND-FLAT;So;0;L;;;;;N;;;;; -1D85B;SIGNWRITING HAND-FLAT BETWEEN PALM FACINGS;So;0;L;;;;;N;;;;; -1D85C;SIGNWRITING HAND-FLAT HEEL;So;0;L;;;;;N;;;;; -1D85D;SIGNWRITING HAND-FLAT THUMB SIDE;So;0;L;;;;;N;;;;; -1D85E;SIGNWRITING HAND-FLAT HEEL THUMB SIDE;So;0;L;;;;;N;;;;; -1D85F;SIGNWRITING HAND-FLAT THUMB BENT;So;0;L;;;;;N;;;;; -1D860;SIGNWRITING HAND-FLAT THUMB FORWARD;So;0;L;;;;;N;;;;; -1D861;SIGNWRITING HAND-FLAT SPLIT INDEX THUMB SIDE;So;0;L;;;;;N;;;;; -1D862;SIGNWRITING HAND-FLAT SPLIT CENTRE;So;0;L;;;;;N;;;;; -1D863;SIGNWRITING HAND-FLAT SPLIT CENTRE THUMB SIDE;So;0;L;;;;;N;;;;; -1D864;SIGNWRITING HAND-FLAT SPLIT CENTRE THUMB SIDE BENT;So;0;L;;;;;N;;;;; -1D865;SIGNWRITING HAND-FLAT SPLIT LITTLE;So;0;L;;;;;N;;;;; -1D866;SIGNWRITING HAND-CLAW;So;0;L;;;;;N;;;;; -1D867;SIGNWRITING HAND-CLAW THUMB SIDE;So;0;L;;;;;N;;;;; -1D868;SIGNWRITING HAND-CLAW NO THUMB;So;0;L;;;;;N;;;;; -1D869;SIGNWRITING HAND-CLAW THUMB FORWARD;So;0;L;;;;;N;;;;; -1D86A;SIGNWRITING HAND-HOOK CURLICUE;So;0;L;;;;;N;;;;; -1D86B;SIGNWRITING HAND-HOOK;So;0;L;;;;;N;;;;; -1D86C;SIGNWRITING HAND-CUP OPEN;So;0;L;;;;;N;;;;; -1D86D;SIGNWRITING HAND-CUP;So;0;L;;;;;N;;;;; -1D86E;SIGNWRITING HAND-CUP OPEN THUMB SIDE;So;0;L;;;;;N;;;;; -1D86F;SIGNWRITING HAND-CUP THUMB SIDE;So;0;L;;;;;N;;;;; -1D870;SIGNWRITING HAND-CUP OPEN NO THUMB;So;0;L;;;;;N;;;;; -1D871;SIGNWRITING HAND-CUP NO THUMB;So;0;L;;;;;N;;;;; -1D872;SIGNWRITING HAND-CUP OPEN THUMB FORWARD;So;0;L;;;;;N;;;;; -1D873;SIGNWRITING HAND-CUP THUMB FORWARD;So;0;L;;;;;N;;;;; -1D874;SIGNWRITING HAND-CURLICUE OPEN;So;0;L;;;;;N;;;;; -1D875;SIGNWRITING HAND-CURLICUE;So;0;L;;;;;N;;;;; -1D876;SIGNWRITING HAND-CIRCLE;So;0;L;;;;;N;;;;; -1D877;SIGNWRITING HAND-OVAL;So;0;L;;;;;N;;;;; -1D878;SIGNWRITING HAND-OVAL THUMB SIDE;So;0;L;;;;;N;;;;; -1D879;SIGNWRITING HAND-OVAL NO THUMB;So;0;L;;;;;N;;;;; -1D87A;SIGNWRITING HAND-OVAL THUMB FORWARD;So;0;L;;;;;N;;;;; -1D87B;SIGNWRITING HAND-HINGE OPEN;So;0;L;;;;;N;;;;; -1D87C;SIGNWRITING HAND-HINGE OPEN THUMB FORWARD;So;0;L;;;;;N;;;;; -1D87D;SIGNWRITING HAND-HINGE;So;0;L;;;;;N;;;;; -1D87E;SIGNWRITING HAND-HINGE SMALL;So;0;L;;;;;N;;;;; -1D87F;SIGNWRITING HAND-HINGE OPEN THUMB SIDE;So;0;L;;;;;N;;;;; -1D880;SIGNWRITING HAND-HINGE THUMB SIDE;So;0;L;;;;;N;;;;; -1D881;SIGNWRITING HAND-HINGE OPEN NO THUMB;So;0;L;;;;;N;;;;; -1D882;SIGNWRITING HAND-HINGE NO THUMB;So;0;L;;;;;N;;;;; -1D883;SIGNWRITING HAND-HINGE THUMB SIDE TOUCHING INDEX;So;0;L;;;;;N;;;;; -1D884;SIGNWRITING HAND-HINGE THUMB BETWEEN MIDDLE RING;So;0;L;;;;;N;;;;; -1D885;SIGNWRITING HAND-ANGLE;So;0;L;;;;;N;;;;; -1D886;SIGNWRITING HAND-FIST INDEX MIDDLE RING;So;0;L;;;;;N;;;;; -1D887;SIGNWRITING HAND-CIRCLE INDEX MIDDLE RING;So;0;L;;;;;N;;;;; -1D888;SIGNWRITING HAND-HINGE INDEX MIDDLE RING;So;0;L;;;;;N;;;;; -1D889;SIGNWRITING HAND-ANGLE INDEX MIDDLE RING;So;0;L;;;;;N;;;;; -1D88A;SIGNWRITING HAND-HINGE LITTLE;So;0;L;;;;;N;;;;; -1D88B;SIGNWRITING HAND-FIST INDEX MIDDLE RING BENT;So;0;L;;;;;N;;;;; -1D88C;SIGNWRITING HAND-FIST INDEX MIDDLE RING CONJOINED;So;0;L;;;;;N;;;;; -1D88D;SIGNWRITING HAND-HINGE INDEX MIDDLE RING CONJOINED;So;0;L;;;;;N;;;;; -1D88E;SIGNWRITING HAND-FIST LITTLE DOWN;So;0;L;;;;;N;;;;; -1D88F;SIGNWRITING HAND-FIST LITTLE DOWN RIPPLE STRAIGHT;So;0;L;;;;;N;;;;; -1D890;SIGNWRITING HAND-FIST LITTLE DOWN RIPPLE CURVED;So;0;L;;;;;N;;;;; -1D891;SIGNWRITING HAND-FIST LITTLE DOWN OTHERS CIRCLED;So;0;L;;;;;N;;;;; -1D892;SIGNWRITING HAND-FIST LITTLE UP;So;0;L;;;;;N;;;;; -1D893;SIGNWRITING HAND-FIST THUMB UNDER LITTLE UP;So;0;L;;;;;N;;;;; -1D894;SIGNWRITING HAND-CIRCLE LITTLE UP;So;0;L;;;;;N;;;;; -1D895;SIGNWRITING HAND-OVAL LITTLE UP;So;0;L;;;;;N;;;;; -1D896;SIGNWRITING HAND-ANGLE LITTLE UP;So;0;L;;;;;N;;;;; -1D897;SIGNWRITING HAND-FIST LITTLE RAISED KNUCKLE;So;0;L;;;;;N;;;;; -1D898;SIGNWRITING HAND-FIST LITTLE BENT;So;0;L;;;;;N;;;;; -1D899;SIGNWRITING HAND-FIST LITTLE TOUCHES THUMB;So;0;L;;;;;N;;;;; -1D89A;SIGNWRITING HAND-FIST LITTLE THUMB;So;0;L;;;;;N;;;;; -1D89B;SIGNWRITING HAND-HINGE LITTLE THUMB;So;0;L;;;;;N;;;;; -1D89C;SIGNWRITING HAND-FIST LITTLE INDEX THUMB;So;0;L;;;;;N;;;;; -1D89D;SIGNWRITING HAND-HINGE LITTLE INDEX THUMB;So;0;L;;;;;N;;;;; -1D89E;SIGNWRITING HAND-ANGLE LITTLE INDEX THUMB INDEX THUMB OUT;So;0;L;;;;;N;;;;; -1D89F;SIGNWRITING HAND-ANGLE LITTLE INDEX THUMB INDEX THUMB;So;0;L;;;;;N;;;;; -1D8A0;SIGNWRITING HAND-FIST LITTLE INDEX;So;0;L;;;;;N;;;;; -1D8A1;SIGNWRITING HAND-CIRCLE LITTLE INDEX;So;0;L;;;;;N;;;;; -1D8A2;SIGNWRITING HAND-HINGE LITTLE INDEX;So;0;L;;;;;N;;;;; -1D8A3;SIGNWRITING HAND-ANGLE LITTLE INDEX;So;0;L;;;;;N;;;;; -1D8A4;SIGNWRITING HAND-FIST INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;; -1D8A5;SIGNWRITING HAND-CIRCLE INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;; -1D8A6;SIGNWRITING HAND-HINGE INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;; -1D8A7;SIGNWRITING HAND-HINGE RING;So;0;L;;;;;N;;;;; -1D8A8;SIGNWRITING HAND-ANGLE INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;; -1D8A9;SIGNWRITING HAND-FIST INDEX MIDDLE CROSS LITTLE;So;0;L;;;;;N;;;;; -1D8AA;SIGNWRITING HAND-CIRCLE INDEX MIDDLE CROSS LITTLE;So;0;L;;;;;N;;;;; -1D8AB;SIGNWRITING HAND-FIST RING DOWN;So;0;L;;;;;N;;;;; -1D8AC;SIGNWRITING HAND-HINGE RING DOWN INDEX THUMB HOOK MIDDLE;So;0;L;;;;;N;;;;; -1D8AD;SIGNWRITING HAND-ANGLE RING DOWN MIDDLE THUMB INDEX CROSS;So;0;L;;;;;N;;;;; -1D8AE;SIGNWRITING HAND-FIST RING UP;So;0;L;;;;;N;;;;; -1D8AF;SIGNWRITING HAND-FIST RING RAISED KNUCKLE;So;0;L;;;;;N;;;;; -1D8B0;SIGNWRITING HAND-FIST RING LITTLE;So;0;L;;;;;N;;;;; -1D8B1;SIGNWRITING HAND-CIRCLE RING LITTLE;So;0;L;;;;;N;;;;; -1D8B2;SIGNWRITING HAND-OVAL RING LITTLE;So;0;L;;;;;N;;;;; -1D8B3;SIGNWRITING HAND-ANGLE RING LITTLE;So;0;L;;;;;N;;;;; -1D8B4;SIGNWRITING HAND-FIST RING MIDDLE;So;0;L;;;;;N;;;;; -1D8B5;SIGNWRITING HAND-FIST RING MIDDLE CONJOINED;So;0;L;;;;;N;;;;; -1D8B6;SIGNWRITING HAND-FIST RING MIDDLE RAISED KNUCKLES;So;0;L;;;;;N;;;;; -1D8B7;SIGNWRITING HAND-FIST RING INDEX;So;0;L;;;;;N;;;;; -1D8B8;SIGNWRITING HAND-FIST RING THUMB;So;0;L;;;;;N;;;;; -1D8B9;SIGNWRITING HAND-HOOK RING THUMB;So;0;L;;;;;N;;;;; -1D8BA;SIGNWRITING HAND-FIST INDEX RING LITTLE;So;0;L;;;;;N;;;;; -1D8BB;SIGNWRITING HAND-CIRCLE INDEX RING LITTLE;So;0;L;;;;;N;;;;; -1D8BC;SIGNWRITING HAND-CURLICUE INDEX RING LITTLE ON;So;0;L;;;;;N;;;;; -1D8BD;SIGNWRITING HAND-HOOK INDEX RING LITTLE OUT;So;0;L;;;;;N;;;;; -1D8BE;SIGNWRITING HAND-HOOK INDEX RING LITTLE IN;So;0;L;;;;;N;;;;; -1D8BF;SIGNWRITING HAND-HOOK INDEX RING LITTLE UNDER;So;0;L;;;;;N;;;;; -1D8C0;SIGNWRITING HAND-CUP INDEX RING LITTLE;So;0;L;;;;;N;;;;; -1D8C1;SIGNWRITING HAND-HINGE INDEX RING LITTLE;So;0;L;;;;;N;;;;; -1D8C2;SIGNWRITING HAND-ANGLE INDEX RING LITTLE OUT;So;0;L;;;;;N;;;;; -1D8C3;SIGNWRITING HAND-ANGLE INDEX RING LITTLE;So;0;L;;;;;N;;;;; -1D8C4;SIGNWRITING HAND-FIST MIDDLE DOWN;So;0;L;;;;;N;;;;; -1D8C5;SIGNWRITING HAND-HINGE MIDDLE;So;0;L;;;;;N;;;;; -1D8C6;SIGNWRITING HAND-FIST MIDDLE UP;So;0;L;;;;;N;;;;; -1D8C7;SIGNWRITING HAND-CIRCLE MIDDLE UP;So;0;L;;;;;N;;;;; -1D8C8;SIGNWRITING HAND-FIST MIDDLE RAISED KNUCKLE;So;0;L;;;;;N;;;;; -1D8C9;SIGNWRITING HAND-FIST MIDDLE UP THUMB SIDE;So;0;L;;;;;N;;;;; -1D8CA;SIGNWRITING HAND-HOOK MIDDLE THUMB;So;0;L;;;;;N;;;;; -1D8CB;SIGNWRITING HAND-FIST MIDDLE THUMB LITTLE;So;0;L;;;;;N;;;;; -1D8CC;SIGNWRITING HAND-FIST MIDDLE LITTLE;So;0;L;;;;;N;;;;; -1D8CD;SIGNWRITING HAND-FIST MIDDLE RING LITTLE;So;0;L;;;;;N;;;;; -1D8CE;SIGNWRITING HAND-CIRCLE MIDDLE RING LITTLE;So;0;L;;;;;N;;;;; -1D8CF;SIGNWRITING HAND-CURLICUE MIDDLE RING LITTLE ON;So;0;L;;;;;N;;;;; -1D8D0;SIGNWRITING HAND-CUP MIDDLE RING LITTLE;So;0;L;;;;;N;;;;; -1D8D1;SIGNWRITING HAND-HINGE MIDDLE RING LITTLE;So;0;L;;;;;N;;;;; -1D8D2;SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE OUT;So;0;L;;;;;N;;;;; -1D8D3;SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE IN;So;0;L;;;;;N;;;;; -1D8D4;SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE;So;0;L;;;;;N;;;;; -1D8D5;SIGNWRITING HAND-CIRCLE MIDDLE RING LITTLE BENT;So;0;L;;;;;N;;;;; -1D8D6;SIGNWRITING HAND-CLAW MIDDLE RING LITTLE CONJOINED;So;0;L;;;;;N;;;;; -1D8D7;SIGNWRITING HAND-CLAW MIDDLE RING LITTLE CONJOINED SIDE;So;0;L;;;;;N;;;;; -1D8D8;SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED OUT;So;0;L;;;;;N;;;;; -1D8D9;SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED IN;So;0;L;;;;;N;;;;; -1D8DA;SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED;So;0;L;;;;;N;;;;; -1D8DB;SIGNWRITING HAND-HINGE INDEX HINGED;So;0;L;;;;;N;;;;; -1D8DC;SIGNWRITING HAND-FIST INDEX THUMB SIDE;So;0;L;;;;;N;;;;; -1D8DD;SIGNWRITING HAND-HINGE INDEX THUMB SIDE;So;0;L;;;;;N;;;;; -1D8DE;SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB DIAGONAL;So;0;L;;;;;N;;;;; -1D8DF;SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB CONJOINED;So;0;L;;;;;N;;;;; -1D8E0;SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB BENT;So;0;L;;;;;N;;;;; -1D8E1;SIGNWRITING HAND-FIST INDEX THUMB SIDE INDEX BENT;So;0;L;;;;;N;;;;; -1D8E2;SIGNWRITING HAND-FIST INDEX THUMB SIDE BOTH BENT;So;0;L;;;;;N;;;;; -1D8E3;SIGNWRITING HAND-FIST INDEX THUMB SIDE INDEX HINGE;So;0;L;;;;;N;;;;; -1D8E4;SIGNWRITING HAND-FIST INDEX THUMB FORWARD INDEX STRAIGHT;So;0;L;;;;;N;;;;; -1D8E5;SIGNWRITING HAND-FIST INDEX THUMB FORWARD INDEX BENT;So;0;L;;;;;N;;;;; -1D8E6;SIGNWRITING HAND-FIST INDEX THUMB HOOK;So;0;L;;;;;N;;;;; -1D8E7;SIGNWRITING HAND-FIST INDEX THUMB CURLICUE;So;0;L;;;;;N;;;;; -1D8E8;SIGNWRITING HAND-FIST INDEX THUMB CURVE THUMB INSIDE;So;0;L;;;;;N;;;;; -1D8E9;SIGNWRITING HAND-CLAW INDEX THUMB CURVE THUMB INSIDE;So;0;L;;;;;N;;;;; -1D8EA;SIGNWRITING HAND-FIST INDEX THUMB CURVE THUMB UNDER;So;0;L;;;;;N;;;;; -1D8EB;SIGNWRITING HAND-FIST INDEX THUMB CIRCLE;So;0;L;;;;;N;;;;; -1D8EC;SIGNWRITING HAND-CUP INDEX THUMB;So;0;L;;;;;N;;;;; -1D8ED;SIGNWRITING HAND-CUP INDEX THUMB OPEN;So;0;L;;;;;N;;;;; -1D8EE;SIGNWRITING HAND-HINGE INDEX THUMB OPEN;So;0;L;;;;;N;;;;; -1D8EF;SIGNWRITING HAND-HINGE INDEX THUMB LARGE;So;0;L;;;;;N;;;;; -1D8F0;SIGNWRITING HAND-HINGE INDEX THUMB;So;0;L;;;;;N;;;;; -1D8F1;SIGNWRITING HAND-HINGE INDEX THUMB SMALL;So;0;L;;;;;N;;;;; -1D8F2;SIGNWRITING HAND-ANGLE INDEX THUMB OUT;So;0;L;;;;;N;;;;; -1D8F3;SIGNWRITING HAND-ANGLE INDEX THUMB IN;So;0;L;;;;;N;;;;; -1D8F4;SIGNWRITING HAND-ANGLE INDEX THUMB;So;0;L;;;;;N;;;;; -1D8F5;SIGNWRITING HAND-FIST THUMB;So;0;L;;;;;N;;;;; -1D8F6;SIGNWRITING HAND-FIST THUMB HEEL;So;0;L;;;;;N;;;;; -1D8F7;SIGNWRITING HAND-FIST THUMB SIDE DIAGONAL;So;0;L;;;;;N;;;;; -1D8F8;SIGNWRITING HAND-FIST THUMB SIDE CONJOINED;So;0;L;;;;;N;;;;; -1D8F9;SIGNWRITING HAND-FIST THUMB SIDE BENT;So;0;L;;;;;N;;;;; -1D8FA;SIGNWRITING HAND-FIST THUMB FORWARD;So;0;L;;;;;N;;;;; -1D8FB;SIGNWRITING HAND-FIST THUMB BETWEEN INDEX MIDDLE;So;0;L;;;;;N;;;;; -1D8FC;SIGNWRITING HAND-FIST THUMB BETWEEN MIDDLE RING;So;0;L;;;;;N;;;;; -1D8FD;SIGNWRITING HAND-FIST THUMB BETWEEN RING LITTLE;So;0;L;;;;;N;;;;; -1D8FE;SIGNWRITING HAND-FIST THUMB UNDER TWO FINGERS;So;0;L;;;;;N;;;;; -1D8FF;SIGNWRITING HAND-FIST THUMB OVER TWO FINGERS;So;0;L;;;;;N;;;;; -1D900;SIGNWRITING HAND-FIST THUMB UNDER THREE FINGERS;So;0;L;;;;;N;;;;; -1D901;SIGNWRITING HAND-FIST THUMB UNDER FOUR FINGERS;So;0;L;;;;;N;;;;; -1D902;SIGNWRITING HAND-FIST THUMB OVER FOUR RAISED KNUCKLES;So;0;L;;;;;N;;;;; -1D903;SIGNWRITING HAND-FIST;So;0;L;;;;;N;;;;; -1D904;SIGNWRITING HAND-FIST HEEL;So;0;L;;;;;N;;;;; -1D905;SIGNWRITING TOUCH SINGLE;So;0;L;;;;;N;;;;; -1D906;SIGNWRITING TOUCH MULTIPLE;So;0;L;;;;;N;;;;; -1D907;SIGNWRITING TOUCH BETWEEN;So;0;L;;;;;N;;;;; -1D908;SIGNWRITING GRASP SINGLE;So;0;L;;;;;N;;;;; -1D909;SIGNWRITING GRASP MULTIPLE;So;0;L;;;;;N;;;;; -1D90A;SIGNWRITING GRASP BETWEEN;So;0;L;;;;;N;;;;; -1D90B;SIGNWRITING STRIKE SINGLE;So;0;L;;;;;N;;;;; -1D90C;SIGNWRITING STRIKE MULTIPLE;So;0;L;;;;;N;;;;; -1D90D;SIGNWRITING STRIKE BETWEEN;So;0;L;;;;;N;;;;; -1D90E;SIGNWRITING BRUSH SINGLE;So;0;L;;;;;N;;;;; -1D90F;SIGNWRITING BRUSH MULTIPLE;So;0;L;;;;;N;;;;; -1D910;SIGNWRITING BRUSH BETWEEN;So;0;L;;;;;N;;;;; -1D911;SIGNWRITING RUB SINGLE;So;0;L;;;;;N;;;;; -1D912;SIGNWRITING RUB MULTIPLE;So;0;L;;;;;N;;;;; -1D913;SIGNWRITING RUB BETWEEN;So;0;L;;;;;N;;;;; -1D914;SIGNWRITING SURFACE SYMBOLS;So;0;L;;;;;N;;;;; -1D915;SIGNWRITING SURFACE BETWEEN;So;0;L;;;;;N;;;;; -1D916;SIGNWRITING SQUEEZE LARGE SINGLE;So;0;L;;;;;N;;;;; -1D917;SIGNWRITING SQUEEZE SMALL SINGLE;So;0;L;;;;;N;;;;; -1D918;SIGNWRITING SQUEEZE LARGE MULTIPLE;So;0;L;;;;;N;;;;; -1D919;SIGNWRITING SQUEEZE SMALL MULTIPLE;So;0;L;;;;;N;;;;; -1D91A;SIGNWRITING SQUEEZE SEQUENTIAL;So;0;L;;;;;N;;;;; -1D91B;SIGNWRITING FLICK LARGE SINGLE;So;0;L;;;;;N;;;;; -1D91C;SIGNWRITING FLICK SMALL SINGLE;So;0;L;;;;;N;;;;; -1D91D;SIGNWRITING FLICK LARGE MULTIPLE;So;0;L;;;;;N;;;;; -1D91E;SIGNWRITING FLICK SMALL MULTIPLE;So;0;L;;;;;N;;;;; -1D91F;SIGNWRITING FLICK SEQUENTIAL;So;0;L;;;;;N;;;;; -1D920;SIGNWRITING SQUEEZE FLICK ALTERNATING;So;0;L;;;;;N;;;;; -1D921;SIGNWRITING MOVEMENT-HINGE UP DOWN LARGE;So;0;L;;;;;N;;;;; -1D922;SIGNWRITING MOVEMENT-HINGE UP DOWN SMALL;So;0;L;;;;;N;;;;; -1D923;SIGNWRITING MOVEMENT-HINGE UP SEQUENTIAL;So;0;L;;;;;N;;;;; -1D924;SIGNWRITING MOVEMENT-HINGE DOWN SEQUENTIAL;So;0;L;;;;;N;;;;; -1D925;SIGNWRITING MOVEMENT-HINGE UP DOWN ALTERNATING LARGE;So;0;L;;;;;N;;;;; -1D926;SIGNWRITING MOVEMENT-HINGE UP DOWN ALTERNATING SMALL;So;0;L;;;;;N;;;;; -1D927;SIGNWRITING MOVEMENT-HINGE SIDE TO SIDE SCISSORS;So;0;L;;;;;N;;;;; -1D928;SIGNWRITING MOVEMENT-WALLPLANE FINGER CONTACT;So;0;L;;;;;N;;;;; -1D929;SIGNWRITING MOVEMENT-FLOORPLANE FINGER CONTACT;So;0;L;;;;;N;;;;; -1D92A;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT SMALL;So;0;L;;;;;N;;;;; -1D92B;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT MEDIUM;So;0;L;;;;;N;;;;; -1D92C;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT LARGE;So;0;L;;;;;N;;;;; -1D92D;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT LARGEST;So;0;L;;;;;N;;;;; -1D92E;SIGNWRITING MOVEMENT-WALLPLANE SINGLE WRIST FLEX;So;0;L;;;;;N;;;;; -1D92F;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE STRAIGHT;So;0;L;;;;;N;;;;; -1D930;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE WRIST FLEX;So;0;L;;;;;N;;;;; -1D931;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE ALTERNATING;So;0;L;;;;;N;;;;; -1D932;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;; -1D933;SIGNWRITING MOVEMENT-WALLPLANE CROSS;So;0;L;;;;;N;;;;; -1D934;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE STRAIGHT MOVEMENT;So;0;L;;;;;N;;;;; -1D935;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE WRIST FLEX;So;0;L;;;;;N;;;;; -1D936;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE ALTERNATING;So;0;L;;;;;N;;;;; -1D937;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;; -1D938;SIGNWRITING MOVEMENT-WALLPLANE BEND SMALL;So;0;L;;;;;N;;;;; -1D939;SIGNWRITING MOVEMENT-WALLPLANE BEND MEDIUM;So;0;L;;;;;N;;;;; -1D93A;SIGNWRITING MOVEMENT-WALLPLANE BEND LARGE;So;0;L;;;;;N;;;;; -1D93B;SIGNWRITING MOVEMENT-WALLPLANE CORNER SMALL;So;0;L;;;;;N;;;;; -1D93C;SIGNWRITING MOVEMENT-WALLPLANE CORNER MEDIUM;So;0;L;;;;;N;;;;; -1D93D;SIGNWRITING MOVEMENT-WALLPLANE CORNER LARGE;So;0;L;;;;;N;;;;; -1D93E;SIGNWRITING MOVEMENT-WALLPLANE CORNER ROTATION;So;0;L;;;;;N;;;;; -1D93F;SIGNWRITING MOVEMENT-WALLPLANE CHECK SMALL;So;0;L;;;;;N;;;;; -1D940;SIGNWRITING MOVEMENT-WALLPLANE CHECK MEDIUM;So;0;L;;;;;N;;;;; -1D941;SIGNWRITING MOVEMENT-WALLPLANE CHECK LARGE;So;0;L;;;;;N;;;;; -1D942;SIGNWRITING MOVEMENT-WALLPLANE BOX SMALL;So;0;L;;;;;N;;;;; -1D943;SIGNWRITING MOVEMENT-WALLPLANE BOX MEDIUM;So;0;L;;;;;N;;;;; -1D944;SIGNWRITING MOVEMENT-WALLPLANE BOX LARGE;So;0;L;;;;;N;;;;; -1D945;SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG SMALL;So;0;L;;;;;N;;;;; -1D946;SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG MEDIUM;So;0;L;;;;;N;;;;; -1D947;SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG LARGE;So;0;L;;;;;N;;;;; -1D948;SIGNWRITING MOVEMENT-WALLPLANE PEAKS SMALL;So;0;L;;;;;N;;;;; -1D949;SIGNWRITING MOVEMENT-WALLPLANE PEAKS MEDIUM;So;0;L;;;;;N;;;;; -1D94A;SIGNWRITING MOVEMENT-WALLPLANE PEAKS LARGE;So;0;L;;;;;N;;;;; -1D94B;SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE SINGLE;So;0;L;;;;;N;;;;; -1D94C;SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE DOUBLE;So;0;L;;;;;N;;;;; -1D94D;SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE ALTERNATING;So;0;L;;;;;N;;;;; -1D94E;SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE SINGLE;So;0;L;;;;;N;;;;; -1D94F;SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE DOUBLE;So;0;L;;;;;N;;;;; -1D950;SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE ALTERNATING;So;0;L;;;;;N;;;;; -1D951;SIGNWRITING TRAVEL-WALLPLANE SHAKING;So;0;L;;;;;N;;;;; -1D952;SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL SINGLE;So;0;L;;;;;N;;;;; -1D953;SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL DOUBLE;So;0;L;;;;;N;;;;; -1D954;SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL TRIPLE;So;0;L;;;;;N;;;;; -1D955;SIGNWRITING MOVEMENT-DIAGONAL AWAY SMALL;So;0;L;;;;;N;;;;; -1D956;SIGNWRITING MOVEMENT-DIAGONAL AWAY MEDIUM;So;0;L;;;;;N;;;;; -1D957;SIGNWRITING MOVEMENT-DIAGONAL AWAY LARGE;So;0;L;;;;;N;;;;; -1D958;SIGNWRITING MOVEMENT-DIAGONAL AWAY LARGEST;So;0;L;;;;;N;;;;; -1D959;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS SMALL;So;0;L;;;;;N;;;;; -1D95A;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS MEDIUM;So;0;L;;;;;N;;;;; -1D95B;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS LARGE;So;0;L;;;;;N;;;;; -1D95C;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS LARGEST;So;0;L;;;;;N;;;;; -1D95D;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY SMALL;So;0;L;;;;;N;;;;; -1D95E;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY MEDIUM;So;0;L;;;;;N;;;;; -1D95F;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY LARGE;So;0;L;;;;;N;;;;; -1D960;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY LARGEST;So;0;L;;;;;N;;;;; -1D961;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS SMALL;So;0;L;;;;;N;;;;; -1D962;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS MEDIUM;So;0;L;;;;;N;;;;; -1D963;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS LARGE;So;0;L;;;;;N;;;;; -1D964;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS LARGEST;So;0;L;;;;;N;;;;; -1D965;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT SMALL;So;0;L;;;;;N;;;;; -1D966;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT MEDIUM;So;0;L;;;;;N;;;;; -1D967;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT LARGE;So;0;L;;;;;N;;;;; -1D968;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT LARGEST;So;0;L;;;;;N;;;;; -1D969;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE WRIST FLEX;So;0;L;;;;;N;;;;; -1D96A;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE STRAIGHT;So;0;L;;;;;N;;;;; -1D96B;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE WRIST FLEX;So;0;L;;;;;N;;;;; -1D96C;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE ALTERNATING;So;0;L;;;;;N;;;;; -1D96D;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;; -1D96E;SIGNWRITING MOVEMENT-FLOORPLANE CROSS;So;0;L;;;;;N;;;;; -1D96F;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE STRAIGHT MOVEMENT;So;0;L;;;;;N;;;;; -1D970;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE WRIST FLEX;So;0;L;;;;;N;;;;; -1D971;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE ALTERNATING MOVEMENT;So;0;L;;;;;N;;;;; -1D972;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;; -1D973;SIGNWRITING MOVEMENT-FLOORPLANE BEND;So;0;L;;;;;N;;;;; -1D974;SIGNWRITING MOVEMENT-FLOORPLANE CORNER SMALL;So;0;L;;;;;N;;;;; -1D975;SIGNWRITING MOVEMENT-FLOORPLANE CORNER MEDIUM;So;0;L;;;;;N;;;;; -1D976;SIGNWRITING MOVEMENT-FLOORPLANE CORNER LARGE;So;0;L;;;;;N;;;;; -1D977;SIGNWRITING MOVEMENT-FLOORPLANE CHECK;So;0;L;;;;;N;;;;; -1D978;SIGNWRITING MOVEMENT-FLOORPLANE BOX SMALL;So;0;L;;;;;N;;;;; -1D979;SIGNWRITING MOVEMENT-FLOORPLANE BOX MEDIUM;So;0;L;;;;;N;;;;; -1D97A;SIGNWRITING MOVEMENT-FLOORPLANE BOX LARGE;So;0;L;;;;;N;;;;; -1D97B;SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG SMALL;So;0;L;;;;;N;;;;; -1D97C;SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG MEDIUM;So;0;L;;;;;N;;;;; -1D97D;SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG LARGE;So;0;L;;;;;N;;;;; -1D97E;SIGNWRITING MOVEMENT-FLOORPLANE PEAKS SMALL;So;0;L;;;;;N;;;;; -1D97F;SIGNWRITING MOVEMENT-FLOORPLANE PEAKS MEDIUM;So;0;L;;;;;N;;;;; -1D980;SIGNWRITING MOVEMENT-FLOORPLANE PEAKS LARGE;So;0;L;;;;;N;;;;; -1D981;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE SINGLE;So;0;L;;;;;N;;;;; -1D982;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE DOUBLE;So;0;L;;;;;N;;;;; -1D983;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE ALTERNATING;So;0;L;;;;;N;;;;; -1D984;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE SINGLE;So;0;L;;;;;N;;;;; -1D985;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE DOUBLE;So;0;L;;;;;N;;;;; -1D986;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE ALTERNATING;So;0;L;;;;;N;;;;; -1D987;SIGNWRITING TRAVEL-FLOORPLANE SHAKING;So;0;L;;;;;N;;;;; -1D988;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER SMALL;So;0;L;;;;;N;;;;; -1D989;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER MEDIUM;So;0;L;;;;;N;;;;; -1D98A;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER LARGE;So;0;L;;;;;N;;;;; -1D98B;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER LARGEST;So;0;L;;;;;N;;;;; -1D98C;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE SMALL;So;0;L;;;;;N;;;;; -1D98D;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE MEDIUM;So;0;L;;;;;N;;;;; -1D98E;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE LARGE;So;0;L;;;;;N;;;;; -1D98F;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE LARGEST;So;0;L;;;;;N;;;;; -1D990;SIGNWRITING MOVEMENT-WALLPLANE CURVE THREE-QUARTER CIRCLE SMALL;So;0;L;;;;;N;;;;; -1D991;SIGNWRITING MOVEMENT-WALLPLANE CURVE THREE-QUARTER CIRCLE MEDIUM;So;0;L;;;;;N;;;;; -1D992;SIGNWRITING MOVEMENT-WALLPLANE HUMP SMALL;So;0;L;;;;;N;;;;; -1D993;SIGNWRITING MOVEMENT-WALLPLANE HUMP MEDIUM;So;0;L;;;;;N;;;;; -1D994;SIGNWRITING MOVEMENT-WALLPLANE HUMP LARGE;So;0;L;;;;;N;;;;; -1D995;SIGNWRITING MOVEMENT-WALLPLANE LOOP SMALL;So;0;L;;;;;N;;;;; -1D996;SIGNWRITING MOVEMENT-WALLPLANE LOOP MEDIUM;So;0;L;;;;;N;;;;; -1D997;SIGNWRITING MOVEMENT-WALLPLANE LOOP LARGE;So;0;L;;;;;N;;;;; -1D998;SIGNWRITING MOVEMENT-WALLPLANE LOOP SMALL DOUBLE;So;0;L;;;;;N;;;;; -1D999;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE SMALL;So;0;L;;;;;N;;;;; -1D99A;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE MEDIUM;So;0;L;;;;;N;;;;; -1D99B;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE LARGE;So;0;L;;;;;N;;;;; -1D99C;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE SMALL;So;0;L;;;;;N;;;;; -1D99D;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE MEDIUM;So;0;L;;;;;N;;;;; -1D99E;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE LARGE;So;0;L;;;;;N;;;;; -1D99F;SIGNWRITING MOVEMENT-WALLPLANE CURVE THEN STRAIGHT;So;0;L;;;;;N;;;;; -1D9A0;SIGNWRITING MOVEMENT-WALLPLANE CURVED CROSS SMALL;So;0;L;;;;;N;;;;; -1D9A1;SIGNWRITING MOVEMENT-WALLPLANE CURVED CROSS MEDIUM;So;0;L;;;;;N;;;;; -1D9A2;SIGNWRITING ROTATION-WALLPLANE SINGLE;So;0;L;;;;;N;;;;; -1D9A3;SIGNWRITING ROTATION-WALLPLANE DOUBLE;So;0;L;;;;;N;;;;; -1D9A4;SIGNWRITING ROTATION-WALLPLANE ALTERNATE;So;0;L;;;;;N;;;;; -1D9A5;SIGNWRITING MOVEMENT-WALLPLANE SHAKING;So;0;L;;;;;N;;;;; -1D9A6;SIGNWRITING MOVEMENT-WALLPLANE CURVE HITTING FRONT WALL;So;0;L;;;;;N;;;;; -1D9A7;SIGNWRITING MOVEMENT-WALLPLANE HUMP HITTING FRONT WALL;So;0;L;;;;;N;;;;; -1D9A8;SIGNWRITING MOVEMENT-WALLPLANE LOOP HITTING FRONT WALL;So;0;L;;;;;N;;;;; -1D9A9;SIGNWRITING MOVEMENT-WALLPLANE WAVE HITTING FRONT WALL;So;0;L;;;;;N;;;;; -1D9AA;SIGNWRITING ROTATION-WALLPLANE SINGLE HITTING FRONT WALL;So;0;L;;;;;N;;;;; -1D9AB;SIGNWRITING ROTATION-WALLPLANE DOUBLE HITTING FRONT WALL;So;0;L;;;;;N;;;;; -1D9AC;SIGNWRITING ROTATION-WALLPLANE ALTERNATING HITTING FRONT WALL;So;0;L;;;;;N;;;;; -1D9AD;SIGNWRITING MOVEMENT-WALLPLANE CURVE HITTING CHEST;So;0;L;;;;;N;;;;; -1D9AE;SIGNWRITING MOVEMENT-WALLPLANE HUMP HITTING CHEST;So;0;L;;;;;N;;;;; -1D9AF;SIGNWRITING MOVEMENT-WALLPLANE LOOP HITTING CHEST;So;0;L;;;;;N;;;;; -1D9B0;SIGNWRITING MOVEMENT-WALLPLANE WAVE HITTING CHEST;So;0;L;;;;;N;;;;; -1D9B1;SIGNWRITING ROTATION-WALLPLANE SINGLE HITTING CHEST;So;0;L;;;;;N;;;;; -1D9B2;SIGNWRITING ROTATION-WALLPLANE DOUBLE HITTING CHEST;So;0;L;;;;;N;;;;; -1D9B3;SIGNWRITING ROTATION-WALLPLANE ALTERNATING HITTING CHEST;So;0;L;;;;;N;;;;; -1D9B4;SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH SMALL;So;0;L;;;;;N;;;;; -1D9B5;SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH MEDIUM;So;0;L;;;;;N;;;;; -1D9B6;SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH LARGE;So;0;L;;;;;N;;;;; -1D9B7;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING CEILING SMALL;So;0;L;;;;;N;;;;; -1D9B8;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING CEILING LARGE;So;0;L;;;;;N;;;;; -1D9B9;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING SMALL DOUBLE;So;0;L;;;;;N;;;;; -1D9BA;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING LARGE DOUBLE;So;0;L;;;;;N;;;;; -1D9BB;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING SMALL TRIPLE;So;0;L;;;;;N;;;;; -1D9BC;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING LARGE TRIPLE;So;0;L;;;;;N;;;;; -1D9BD;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING SMALL SINGLE;So;0;L;;;;;N;;;;; -1D9BE;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING LARGE SINGLE;So;0;L;;;;;N;;;;; -1D9BF;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING SMALL DOUBLE;So;0;L;;;;;N;;;;; -1D9C0;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING LARGE DOUBLE;So;0;L;;;;;N;;;;; -1D9C1;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING CEILING SMALL;So;0;L;;;;;N;;;;; -1D9C2;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING CEILING LARGE;So;0;L;;;;;N;;;;; -1D9C3;SIGNWRITING ROTATION-FLOORPLANE SINGLE HITTING CEILING;So;0;L;;;;;N;;;;; -1D9C4;SIGNWRITING ROTATION-FLOORPLANE DOUBLE HITTING CEILING;So;0;L;;;;;N;;;;; -1D9C5;SIGNWRITING ROTATION-FLOORPLANE ALTERNATING HITTING CEILING;So;0;L;;;;;N;;;;; -1D9C6;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING FLOOR SMALL;So;0;L;;;;;N;;;;; -1D9C7;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING FLOOR LARGE;So;0;L;;;;;N;;;;; -1D9C8;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR SMALL DOUBLE;So;0;L;;;;;N;;;;; -1D9C9;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR LARGE DOUBLE;So;0;L;;;;;N;;;;; -1D9CA;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR TRIPLE SMALL TRIPLE;So;0;L;;;;;N;;;;; -1D9CB;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR TRIPLE LARGE TRIPLE;So;0;L;;;;;N;;;;; -1D9CC;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR SMALL SINGLE;So;0;L;;;;;N;;;;; -1D9CD;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR LARGE SINGLE;So;0;L;;;;;N;;;;; -1D9CE;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR SMALL DOUBLE;So;0;L;;;;;N;;;;; -1D9CF;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR LARGE DOUBLE;So;0;L;;;;;N;;;;; -1D9D0;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING FLOOR SMALL;So;0;L;;;;;N;;;;; -1D9D1;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING FLOOR LARGE;So;0;L;;;;;N;;;;; -1D9D2;SIGNWRITING ROTATION-FLOORPLANE SINGLE HITTING FLOOR;So;0;L;;;;;N;;;;; -1D9D3;SIGNWRITING ROTATION-FLOORPLANE DOUBLE HITTING FLOOR;So;0;L;;;;;N;;;;; -1D9D4;SIGNWRITING ROTATION-FLOORPLANE ALTERNATING HITTING FLOOR;So;0;L;;;;;N;;;;; -1D9D5;SIGNWRITING MOVEMENT-FLOORPLANE CURVE SMALL;So;0;L;;;;;N;;;;; -1D9D6;SIGNWRITING MOVEMENT-FLOORPLANE CURVE MEDIUM;So;0;L;;;;;N;;;;; -1D9D7;SIGNWRITING MOVEMENT-FLOORPLANE CURVE LARGE;So;0;L;;;;;N;;;;; -1D9D8;SIGNWRITING MOVEMENT-FLOORPLANE CURVE LARGEST;So;0;L;;;;;N;;;;; -1D9D9;SIGNWRITING MOVEMENT-FLOORPLANE CURVE COMBINED;So;0;L;;;;;N;;;;; -1D9DA;SIGNWRITING MOVEMENT-FLOORPLANE HUMP SMALL;So;0;L;;;;;N;;;;; -1D9DB;SIGNWRITING MOVEMENT-FLOORPLANE LOOP SMALL;So;0;L;;;;;N;;;;; -1D9DC;SIGNWRITING MOVEMENT-FLOORPLANE WAVE SNAKE;So;0;L;;;;;N;;;;; -1D9DD;SIGNWRITING MOVEMENT-FLOORPLANE WAVE SMALL;So;0;L;;;;;N;;;;; -1D9DE;SIGNWRITING MOVEMENT-FLOORPLANE WAVE LARGE;So;0;L;;;;;N;;;;; -1D9DF;SIGNWRITING ROTATION-FLOORPLANE SINGLE;So;0;L;;;;;N;;;;; -1D9E0;SIGNWRITING ROTATION-FLOORPLANE DOUBLE;So;0;L;;;;;N;;;;; -1D9E1;SIGNWRITING ROTATION-FLOORPLANE ALTERNATING;So;0;L;;;;;N;;;;; -1D9E2;SIGNWRITING MOVEMENT-FLOORPLANE SHAKING PARALLEL;So;0;L;;;;;N;;;;; -1D9E3;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE SMALL SINGLE;So;0;L;;;;;N;;;;; -1D9E4;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE MEDIUM SINGLE;So;0;L;;;;;N;;;;; -1D9E5;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE SMALL DOUBLE;So;0;L;;;;;N;;;;; -1D9E6;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE MEDIUM DOUBLE;So;0;L;;;;;N;;;;; -1D9E7;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL SMALL SINGLE;So;0;L;;;;;N;;;;; -1D9E8;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL MEDIUM SINGLE;So;0;L;;;;;N;;;;; -1D9E9;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL LARGE SINGLE;So;0;L;;;;;N;;;;; -1D9EA;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL SMALL DOUBLE;So;0;L;;;;;N;;;;; -1D9EB;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL MEDIUM DOUBLE;So;0;L;;;;;N;;;;; -1D9EC;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL LARGE DOUBLE;So;0;L;;;;;N;;;;; -1D9ED;SIGNWRITING MOVEMENT-WALLPLANE WRIST CIRCLE FRONT SINGLE;So;0;L;;;;;N;;;;; -1D9EE;SIGNWRITING MOVEMENT-WALLPLANE WRIST CIRCLE FRONT DOUBLE;So;0;L;;;;;N;;;;; -1D9EF;SIGNWRITING MOVEMENT-FLOORPLANE WRIST CIRCLE HITTING WALL SINGLE;So;0;L;;;;;N;;;;; -1D9F0;SIGNWRITING MOVEMENT-FLOORPLANE WRIST CIRCLE HITTING WALL DOUBLE;So;0;L;;;;;N;;;;; -1D9F1;SIGNWRITING MOVEMENT-WALLPLANE FINGER CIRCLES SINGLE;So;0;L;;;;;N;;;;; -1D9F2;SIGNWRITING MOVEMENT-WALLPLANE FINGER CIRCLES DOUBLE;So;0;L;;;;;N;;;;; -1D9F3;SIGNWRITING MOVEMENT-FLOORPLANE FINGER CIRCLES HITTING WALL SINGLE;So;0;L;;;;;N;;;;; -1D9F4;SIGNWRITING MOVEMENT-FLOORPLANE FINGER CIRCLES HITTING WALL DOUBLE;So;0;L;;;;;N;;;;; -1D9F5;SIGNWRITING DYNAMIC ARROWHEAD SMALL;So;0;L;;;;;N;;;;; -1D9F6;SIGNWRITING DYNAMIC ARROWHEAD LARGE;So;0;L;;;;;N;;;;; -1D9F7;SIGNWRITING DYNAMIC FAST;So;0;L;;;;;N;;;;; -1D9F8;SIGNWRITING DYNAMIC SLOW;So;0;L;;;;;N;;;;; -1D9F9;SIGNWRITING DYNAMIC TENSE;So;0;L;;;;;N;;;;; -1D9FA;SIGNWRITING DYNAMIC RELAXED;So;0;L;;;;;N;;;;; -1D9FB;SIGNWRITING DYNAMIC SIMULTANEOUS;So;0;L;;;;;N;;;;; -1D9FC;SIGNWRITING DYNAMIC SIMULTANEOUS ALTERNATING;So;0;L;;;;;N;;;;; -1D9FD;SIGNWRITING DYNAMIC EVERY OTHER TIME;So;0;L;;;;;N;;;;; -1D9FE;SIGNWRITING DYNAMIC GRADUAL;So;0;L;;;;;N;;;;; -1D9FF;SIGNWRITING HEAD;So;0;L;;;;;N;;;;; -1DA00;SIGNWRITING HEAD RIM;Mn;0;NSM;;;;;N;;;;; -1DA01;SIGNWRITING HEAD MOVEMENT-WALLPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;; -1DA02;SIGNWRITING HEAD MOVEMENT-WALLPLANE TILT;Mn;0;NSM;;;;;N;;;;; -1DA03;SIGNWRITING HEAD MOVEMENT-FLOORPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;; -1DA04;SIGNWRITING HEAD MOVEMENT-WALLPLANE CURVE;Mn;0;NSM;;;;;N;;;;; -1DA05;SIGNWRITING HEAD MOVEMENT-FLOORPLANE CURVE;Mn;0;NSM;;;;;N;;;;; -1DA06;SIGNWRITING HEAD MOVEMENT CIRCLE;Mn;0;NSM;;;;;N;;;;; -1DA07;SIGNWRITING FACE DIRECTION POSITION NOSE FORWARD TILTING;Mn;0;NSM;;;;;N;;;;; -1DA08;SIGNWRITING FACE DIRECTION POSITION NOSE UP OR DOWN;Mn;0;NSM;;;;;N;;;;; -1DA09;SIGNWRITING FACE DIRECTION POSITION NOSE UP OR DOWN TILTING;Mn;0;NSM;;;;;N;;;;; -1DA0A;SIGNWRITING EYEBROWS STRAIGHT UP;Mn;0;NSM;;;;;N;;;;; -1DA0B;SIGNWRITING EYEBROWS STRAIGHT NEUTRAL;Mn;0;NSM;;;;;N;;;;; -1DA0C;SIGNWRITING EYEBROWS STRAIGHT DOWN;Mn;0;NSM;;;;;N;;;;; -1DA0D;SIGNWRITING DREAMY EYEBROWS NEUTRAL DOWN;Mn;0;NSM;;;;;N;;;;; -1DA0E;SIGNWRITING DREAMY EYEBROWS DOWN NEUTRAL;Mn;0;NSM;;;;;N;;;;; -1DA0F;SIGNWRITING DREAMY EYEBROWS UP NEUTRAL;Mn;0;NSM;;;;;N;;;;; -1DA10;SIGNWRITING DREAMY EYEBROWS NEUTRAL UP;Mn;0;NSM;;;;;N;;;;; -1DA11;SIGNWRITING FOREHEAD NEUTRAL;Mn;0;NSM;;;;;N;;;;; -1DA12;SIGNWRITING FOREHEAD CONTACT;Mn;0;NSM;;;;;N;;;;; -1DA13;SIGNWRITING FOREHEAD WRINKLED;Mn;0;NSM;;;;;N;;;;; -1DA14;SIGNWRITING EYES OPEN;Mn;0;NSM;;;;;N;;;;; -1DA15;SIGNWRITING EYES SQUEEZED;Mn;0;NSM;;;;;N;;;;; -1DA16;SIGNWRITING EYES CLOSED;Mn;0;NSM;;;;;N;;;;; -1DA17;SIGNWRITING EYE BLINK SINGLE;Mn;0;NSM;;;;;N;;;;; -1DA18;SIGNWRITING EYE BLINK MULTIPLE;Mn;0;NSM;;;;;N;;;;; -1DA19;SIGNWRITING EYES HALF OPEN;Mn;0;NSM;;;;;N;;;;; -1DA1A;SIGNWRITING EYES WIDE OPEN;Mn;0;NSM;;;;;N;;;;; -1DA1B;SIGNWRITING EYES HALF CLOSED;Mn;0;NSM;;;;;N;;;;; -1DA1C;SIGNWRITING EYES WIDENING MOVEMENT;Mn;0;NSM;;;;;N;;;;; -1DA1D;SIGNWRITING EYE WINK;Mn;0;NSM;;;;;N;;;;; -1DA1E;SIGNWRITING EYELASHES UP;Mn;0;NSM;;;;;N;;;;; -1DA1F;SIGNWRITING EYELASHES DOWN;Mn;0;NSM;;;;;N;;;;; -1DA20;SIGNWRITING EYELASHES FLUTTERING;Mn;0;NSM;;;;;N;;;;; -1DA21;SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;; -1DA22;SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT DOUBLE;Mn;0;NSM;;;;;N;;;;; -1DA23;SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT ALTERNATING;Mn;0;NSM;;;;;N;;;;; -1DA24;SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;; -1DA25;SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT DOUBLE;Mn;0;NSM;;;;;N;;;;; -1DA26;SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT ALTERNATING;Mn;0;NSM;;;;;N;;;;; -1DA27;SIGNWRITING EYEGAZE-WALLPLANE CURVED;Mn;0;NSM;;;;;N;;;;; -1DA28;SIGNWRITING EYEGAZE-FLOORPLANE CURVED;Mn;0;NSM;;;;;N;;;;; -1DA29;SIGNWRITING EYEGAZE-WALLPLANE CIRCLING;Mn;0;NSM;;;;;N;;;;; -1DA2A;SIGNWRITING CHEEKS PUFFED;Mn;0;NSM;;;;;N;;;;; -1DA2B;SIGNWRITING CHEEKS NEUTRAL;Mn;0;NSM;;;;;N;;;;; -1DA2C;SIGNWRITING CHEEKS SUCKED;Mn;0;NSM;;;;;N;;;;; -1DA2D;SIGNWRITING TENSE CHEEKS HIGH;Mn;0;NSM;;;;;N;;;;; -1DA2E;SIGNWRITING TENSE CHEEKS MIDDLE;Mn;0;NSM;;;;;N;;;;; -1DA2F;SIGNWRITING TENSE CHEEKS LOW;Mn;0;NSM;;;;;N;;;;; -1DA30;SIGNWRITING EARS;Mn;0;NSM;;;;;N;;;;; -1DA31;SIGNWRITING NOSE NEUTRAL;Mn;0;NSM;;;;;N;;;;; -1DA32;SIGNWRITING NOSE CONTACT;Mn;0;NSM;;;;;N;;;;; -1DA33;SIGNWRITING NOSE WRINKLES;Mn;0;NSM;;;;;N;;;;; -1DA34;SIGNWRITING NOSE WIGGLES;Mn;0;NSM;;;;;N;;;;; -1DA35;SIGNWRITING AIR BLOWING OUT;Mn;0;NSM;;;;;N;;;;; -1DA36;SIGNWRITING AIR SUCKING IN;Mn;0;NSM;;;;;N;;;;; -1DA37;SIGNWRITING AIR BLOW SMALL ROTATIONS;So;0;L;;;;;N;;;;; -1DA38;SIGNWRITING AIR SUCK SMALL ROTATIONS;So;0;L;;;;;N;;;;; -1DA39;SIGNWRITING BREATH INHALE;So;0;L;;;;;N;;;;; -1DA3A;SIGNWRITING BREATH EXHALE;So;0;L;;;;;N;;;;; -1DA3B;SIGNWRITING MOUTH CLOSED NEUTRAL;Mn;0;NSM;;;;;N;;;;; -1DA3C;SIGNWRITING MOUTH CLOSED FORWARD;Mn;0;NSM;;;;;N;;;;; -1DA3D;SIGNWRITING MOUTH CLOSED CONTACT;Mn;0;NSM;;;;;N;;;;; -1DA3E;SIGNWRITING MOUTH SMILE;Mn;0;NSM;;;;;N;;;;; -1DA3F;SIGNWRITING MOUTH SMILE WRINKLED;Mn;0;NSM;;;;;N;;;;; -1DA40;SIGNWRITING MOUTH SMILE OPEN;Mn;0;NSM;;;;;N;;;;; -1DA41;SIGNWRITING MOUTH FROWN;Mn;0;NSM;;;;;N;;;;; -1DA42;SIGNWRITING MOUTH FROWN WRINKLED;Mn;0;NSM;;;;;N;;;;; -1DA43;SIGNWRITING MOUTH FROWN OPEN;Mn;0;NSM;;;;;N;;;;; -1DA44;SIGNWRITING MOUTH OPEN CIRCLE;Mn;0;NSM;;;;;N;;;;; -1DA45;SIGNWRITING MOUTH OPEN FORWARD;Mn;0;NSM;;;;;N;;;;; -1DA46;SIGNWRITING MOUTH OPEN WRINKLED;Mn;0;NSM;;;;;N;;;;; -1DA47;SIGNWRITING MOUTH OPEN OVAL;Mn;0;NSM;;;;;N;;;;; -1DA48;SIGNWRITING MOUTH OPEN OVAL WRINKLED;Mn;0;NSM;;;;;N;;;;; -1DA49;SIGNWRITING MOUTH OPEN OVAL YAWN;Mn;0;NSM;;;;;N;;;;; -1DA4A;SIGNWRITING MOUTH OPEN RECTANGLE;Mn;0;NSM;;;;;N;;;;; -1DA4B;SIGNWRITING MOUTH OPEN RECTANGLE WRINKLED;Mn;0;NSM;;;;;N;;;;; -1DA4C;SIGNWRITING MOUTH OPEN RECTANGLE YAWN;Mn;0;NSM;;;;;N;;;;; -1DA4D;SIGNWRITING MOUTH KISS;Mn;0;NSM;;;;;N;;;;; -1DA4E;SIGNWRITING MOUTH KISS FORWARD;Mn;0;NSM;;;;;N;;;;; -1DA4F;SIGNWRITING MOUTH KISS WRINKLED;Mn;0;NSM;;;;;N;;;;; -1DA50;SIGNWRITING MOUTH TENSE;Mn;0;NSM;;;;;N;;;;; -1DA51;SIGNWRITING MOUTH TENSE FORWARD;Mn;0;NSM;;;;;N;;;;; -1DA52;SIGNWRITING MOUTH TENSE SUCKED;Mn;0;NSM;;;;;N;;;;; -1DA53;SIGNWRITING LIPS PRESSED TOGETHER;Mn;0;NSM;;;;;N;;;;; -1DA54;SIGNWRITING LIP LOWER OVER UPPER;Mn;0;NSM;;;;;N;;;;; -1DA55;SIGNWRITING LIP UPPER OVER LOWER;Mn;0;NSM;;;;;N;;;;; -1DA56;SIGNWRITING MOUTH CORNERS;Mn;0;NSM;;;;;N;;;;; -1DA57;SIGNWRITING MOUTH WRINKLES SINGLE;Mn;0;NSM;;;;;N;;;;; -1DA58;SIGNWRITING MOUTH WRINKLES DOUBLE;Mn;0;NSM;;;;;N;;;;; -1DA59;SIGNWRITING TONGUE STICKING OUT FAR;Mn;0;NSM;;;;;N;;;;; -1DA5A;SIGNWRITING TONGUE LICKING LIPS;Mn;0;NSM;;;;;N;;;;; -1DA5B;SIGNWRITING TONGUE TIP BETWEEN LIPS;Mn;0;NSM;;;;;N;;;;; -1DA5C;SIGNWRITING TONGUE TIP TOUCHING INSIDE MOUTH;Mn;0;NSM;;;;;N;;;;; -1DA5D;SIGNWRITING TONGUE INSIDE MOUTH RELAXED;Mn;0;NSM;;;;;N;;;;; -1DA5E;SIGNWRITING TONGUE MOVES AGAINST CHEEK;Mn;0;NSM;;;;;N;;;;; -1DA5F;SIGNWRITING TONGUE CENTRE STICKING OUT;Mn;0;NSM;;;;;N;;;;; -1DA60;SIGNWRITING TONGUE CENTRE INSIDE MOUTH;Mn;0;NSM;;;;;N;;;;; -1DA61;SIGNWRITING TEETH;Mn;0;NSM;;;;;N;;;;; -1DA62;SIGNWRITING TEETH MOVEMENT;Mn;0;NSM;;;;;N;;;;; -1DA63;SIGNWRITING TEETH ON TONGUE;Mn;0;NSM;;;;;N;;;;; -1DA64;SIGNWRITING TEETH ON TONGUE MOVEMENT;Mn;0;NSM;;;;;N;;;;; -1DA65;SIGNWRITING TEETH ON LIPS;Mn;0;NSM;;;;;N;;;;; -1DA66;SIGNWRITING TEETH ON LIPS MOVEMENT;Mn;0;NSM;;;;;N;;;;; -1DA67;SIGNWRITING TEETH BITE LIPS;Mn;0;NSM;;;;;N;;;;; -1DA68;SIGNWRITING MOVEMENT-WALLPLANE JAW;Mn;0;NSM;;;;;N;;;;; -1DA69;SIGNWRITING MOVEMENT-FLOORPLANE JAW;Mn;0;NSM;;;;;N;;;;; -1DA6A;SIGNWRITING NECK;Mn;0;NSM;;;;;N;;;;; -1DA6B;SIGNWRITING HAIR;Mn;0;NSM;;;;;N;;;;; -1DA6C;SIGNWRITING EXCITEMENT;Mn;0;NSM;;;;;N;;;;; -1DA6D;SIGNWRITING SHOULDER HIP SPINE;So;0;L;;;;;N;;;;; -1DA6E;SIGNWRITING SHOULDER HIP POSITIONS;So;0;L;;;;;N;;;;; -1DA6F;SIGNWRITING WALLPLANE SHOULDER HIP MOVE;So;0;L;;;;;N;;;;; -1DA70;SIGNWRITING FLOORPLANE SHOULDER HIP MOVE;So;0;L;;;;;N;;;;; -1DA71;SIGNWRITING SHOULDER TILTING FROM WAIST;So;0;L;;;;;N;;;;; -1DA72;SIGNWRITING TORSO-WALLPLANE STRAIGHT STRETCH;So;0;L;;;;;N;;;;; -1DA73;SIGNWRITING TORSO-WALLPLANE CURVED BEND;So;0;L;;;;;N;;;;; -1DA74;SIGNWRITING TORSO-FLOORPLANE TWISTING;So;0;L;;;;;N;;;;; -1DA75;SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS;Mn;0;NSM;;;;;N;;;;; -1DA76;SIGNWRITING LIMB COMBINATION;So;0;L;;;;;N;;;;; -1DA77;SIGNWRITING LIMB LENGTH-1;So;0;L;;;;;N;;;;; -1DA78;SIGNWRITING LIMB LENGTH-2;So;0;L;;;;;N;;;;; -1DA79;SIGNWRITING LIMB LENGTH-3;So;0;L;;;;;N;;;;; -1DA7A;SIGNWRITING LIMB LENGTH-4;So;0;L;;;;;N;;;;; -1DA7B;SIGNWRITING LIMB LENGTH-5;So;0;L;;;;;N;;;;; -1DA7C;SIGNWRITING LIMB LENGTH-6;So;0;L;;;;;N;;;;; -1DA7D;SIGNWRITING LIMB LENGTH-7;So;0;L;;;;;N;;;;; -1DA7E;SIGNWRITING FINGER;So;0;L;;;;;N;;;;; -1DA7F;SIGNWRITING LOCATION-WALLPLANE SPACE;So;0;L;;;;;N;;;;; -1DA80;SIGNWRITING LOCATION-FLOORPLANE SPACE;So;0;L;;;;;N;;;;; -1DA81;SIGNWRITING LOCATION HEIGHT;So;0;L;;;;;N;;;;; -1DA82;SIGNWRITING LOCATION WIDTH;So;0;L;;;;;N;;;;; -1DA83;SIGNWRITING LOCATION DEPTH;So;0;L;;;;;N;;;;; -1DA84;SIGNWRITING LOCATION HEAD NECK;Mn;0;NSM;;;;;N;;;;; -1DA85;SIGNWRITING LOCATION TORSO;So;0;L;;;;;N;;;;; -1DA86;SIGNWRITING LOCATION LIMBS DIGITS;So;0;L;;;;;N;;;;; -1DA87;SIGNWRITING COMMA;Po;0;L;;;;;N;;;;; -1DA88;SIGNWRITING FULL STOP;Po;0;L;;;;;N;;;;; -1DA89;SIGNWRITING SEMICOLON;Po;0;L;;;;;N;;;;; -1DA8A;SIGNWRITING COLON;Po;0;L;;;;;N;;;;; -1DA8B;SIGNWRITING PARENTHESIS;Po;0;L;;;;;N;;;;; -1DA9B;SIGNWRITING FILL MODIFIER-2;Mn;0;NSM;;;;;N;;;;; -1DA9C;SIGNWRITING FILL MODIFIER-3;Mn;0;NSM;;;;;N;;;;; -1DA9D;SIGNWRITING FILL MODIFIER-4;Mn;0;NSM;;;;;N;;;;; -1DA9E;SIGNWRITING FILL MODIFIER-5;Mn;0;NSM;;;;;N;;;;; -1DA9F;SIGNWRITING FILL MODIFIER-6;Mn;0;NSM;;;;;N;;;;; -1DAA1;SIGNWRITING ROTATION MODIFIER-2;Mn;0;NSM;;;;;N;;;;; -1DAA2;SIGNWRITING ROTATION MODIFIER-3;Mn;0;NSM;;;;;N;;;;; -1DAA3;SIGNWRITING ROTATION MODIFIER-4;Mn;0;NSM;;;;;N;;;;; -1DAA4;SIGNWRITING ROTATION MODIFIER-5;Mn;0;NSM;;;;;N;;;;; -1DAA5;SIGNWRITING ROTATION MODIFIER-6;Mn;0;NSM;;;;;N;;;;; -1DAA6;SIGNWRITING ROTATION MODIFIER-7;Mn;0;NSM;;;;;N;;;;; -1DAA7;SIGNWRITING ROTATION MODIFIER-8;Mn;0;NSM;;;;;N;;;;; -1DAA8;SIGNWRITING ROTATION MODIFIER-9;Mn;0;NSM;;;;;N;;;;; -1DAA9;SIGNWRITING ROTATION MODIFIER-10;Mn;0;NSM;;;;;N;;;;; -1DAAA;SIGNWRITING ROTATION MODIFIER-11;Mn;0;NSM;;;;;N;;;;; -1DAAB;SIGNWRITING ROTATION MODIFIER-12;Mn;0;NSM;;;;;N;;;;; -1DAAC;SIGNWRITING ROTATION MODIFIER-13;Mn;0;NSM;;;;;N;;;;; -1DAAD;SIGNWRITING ROTATION MODIFIER-14;Mn;0;NSM;;;;;N;;;;; -1DAAE;SIGNWRITING ROTATION MODIFIER-15;Mn;0;NSM;;;;;N;;;;; -1DAAF;SIGNWRITING ROTATION MODIFIER-16;Mn;0;NSM;;;;;N;;;;; -1DF00;LATIN SMALL LETTER FENG DIGRAPH WITH TRILL;Ll;0;L;;;;;N;;;;; -1DF01;LATIN SMALL LETTER REVERSED SCRIPT G;Ll;0;L;;;;;N;;;;; -1DF02;LATIN LETTER SMALL CAPITAL TURNED G;Ll;0;L;;;;;N;;;;; -1DF03;LATIN SMALL LETTER REVERSED K;Ll;0;L;;;;;N;;;;; -1DF04;LATIN LETTER SMALL CAPITAL L WITH BELT;Ll;0;L;;;;;N;;;;; -1DF05;LATIN SMALL LETTER LEZH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -1DF06;LATIN SMALL LETTER TURNED Y WITH BELT;Ll;0;L;;;;;N;;;;; -1DF07;LATIN SMALL LETTER REVERSED ENG;Ll;0;L;;;;;N;;;;; -1DF08;LATIN SMALL LETTER TURNED R WITH LONG LEG AND RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -1DF09;LATIN SMALL LETTER T WITH HOOK AND RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -1DF0A;LATIN LETTER RETROFLEX CLICK WITH RETROFLEX HOOK;Lo;0;L;;;;;N;;;;; -1DF0B;LATIN SMALL LETTER ESH WITH DOUBLE BAR;Ll;0;L;;;;;N;;;;; -1DF0C;LATIN SMALL LETTER ESH WITH DOUBLE BAR AND CURL;Ll;0;L;;;;;N;;;;; -1DF0D;LATIN SMALL LETTER TURNED T WITH CURL;Ll;0;L;;;;;N;;;;; -1DF0E;LATIN LETTER INVERTED GLOTTAL STOP WITH CURL;Ll;0;L;;;;;N;;;;; -1DF0F;LATIN LETTER STRETCHED C WITH CURL;Ll;0;L;;;;;N;;;;; -1DF10;LATIN LETTER SMALL CAPITAL TURNED K;Ll;0;L;;;;;N;;;;; -1DF11;LATIN SMALL LETTER L WITH FISHHOOK;Ll;0;L;;;;;N;;;;; -1DF12;LATIN SMALL LETTER DEZH DIGRAPH WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1DF13;LATIN SMALL LETTER L WITH BELT AND PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1DF14;LATIN SMALL LETTER ENG WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1DF15;LATIN SMALL LETTER TURNED R WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1DF16;LATIN SMALL LETTER R WITH FISHHOOK AND PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1DF17;LATIN SMALL LETTER TESH DIGRAPH WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1DF18;LATIN SMALL LETTER EZH WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; -1DF19;LATIN SMALL LETTER DEZH DIGRAPH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -1DF1A;LATIN SMALL LETTER I WITH STROKE AND RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -1DF1B;LATIN SMALL LETTER O WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -1DF1C;LATIN SMALL LETTER TESH DIGRAPH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -1DF1D;LATIN SMALL LETTER C WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; -1DF1E;LATIN SMALL LETTER S WITH CURL;Ll;0;L;;;;;N;;;;; -1DF25;LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;; -1DF26;LATIN SMALL LETTER L WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;; -1DF27;LATIN SMALL LETTER N WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;; -1DF28;LATIN SMALL LETTER R WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;; -1DF29;LATIN SMALL LETTER S WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;; -1DF2A;LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;; -1E000;COMBINING GLAGOLITIC LETTER AZU;Mn;230;NSM;;;;;N;;;;; -1E001;COMBINING GLAGOLITIC LETTER BUKY;Mn;230;NSM;;;;;N;;;;; -1E002;COMBINING GLAGOLITIC LETTER VEDE;Mn;230;NSM;;;;;N;;;;; -1E003;COMBINING GLAGOLITIC LETTER GLAGOLI;Mn;230;NSM;;;;;N;;;;; -1E004;COMBINING GLAGOLITIC LETTER DOBRO;Mn;230;NSM;;;;;N;;;;; -1E005;COMBINING GLAGOLITIC LETTER YESTU;Mn;230;NSM;;;;;N;;;;; -1E006;COMBINING GLAGOLITIC LETTER ZHIVETE;Mn;230;NSM;;;;;N;;;;; -1E008;COMBINING GLAGOLITIC LETTER ZEMLJA;Mn;230;NSM;;;;;N;;;;; -1E009;COMBINING GLAGOLITIC LETTER IZHE;Mn;230;NSM;;;;;N;;;;; -1E00A;COMBINING GLAGOLITIC LETTER INITIAL IZHE;Mn;230;NSM;;;;;N;;;;; -1E00B;COMBINING GLAGOLITIC LETTER I;Mn;230;NSM;;;;;N;;;;; -1E00C;COMBINING GLAGOLITIC LETTER DJERVI;Mn;230;NSM;;;;;N;;;;; -1E00D;COMBINING GLAGOLITIC LETTER KAKO;Mn;230;NSM;;;;;N;;;;; -1E00E;COMBINING GLAGOLITIC LETTER LJUDIJE;Mn;230;NSM;;;;;N;;;;; -1E00F;COMBINING GLAGOLITIC LETTER MYSLITE;Mn;230;NSM;;;;;N;;;;; -1E010;COMBINING GLAGOLITIC LETTER NASHI;Mn;230;NSM;;;;;N;;;;; -1E011;COMBINING GLAGOLITIC LETTER ONU;Mn;230;NSM;;;;;N;;;;; -1E012;COMBINING GLAGOLITIC LETTER POKOJI;Mn;230;NSM;;;;;N;;;;; -1E013;COMBINING GLAGOLITIC LETTER RITSI;Mn;230;NSM;;;;;N;;;;; -1E014;COMBINING GLAGOLITIC LETTER SLOVO;Mn;230;NSM;;;;;N;;;;; -1E015;COMBINING GLAGOLITIC LETTER TVRIDO;Mn;230;NSM;;;;;N;;;;; -1E016;COMBINING GLAGOLITIC LETTER UKU;Mn;230;NSM;;;;;N;;;;; -1E017;COMBINING GLAGOLITIC LETTER FRITU;Mn;230;NSM;;;;;N;;;;; -1E018;COMBINING GLAGOLITIC LETTER HERU;Mn;230;NSM;;;;;N;;;;; -1E01B;COMBINING GLAGOLITIC LETTER SHTA;Mn;230;NSM;;;;;N;;;;; -1E01C;COMBINING GLAGOLITIC LETTER TSI;Mn;230;NSM;;;;;N;;;;; -1E01D;COMBINING GLAGOLITIC LETTER CHRIVI;Mn;230;NSM;;;;;N;;;;; -1E01E;COMBINING GLAGOLITIC LETTER SHA;Mn;230;NSM;;;;;N;;;;; -1E01F;COMBINING GLAGOLITIC LETTER YERU;Mn;230;NSM;;;;;N;;;;; -1E020;COMBINING GLAGOLITIC LETTER YERI;Mn;230;NSM;;;;;N;;;;; -1E021;COMBINING GLAGOLITIC LETTER YATI;Mn;230;NSM;;;;;N;;;;; -1E023;COMBINING GLAGOLITIC LETTER YU;Mn;230;NSM;;;;;N;;;;; -1E024;COMBINING GLAGOLITIC LETTER SMALL YUS;Mn;230;NSM;;;;;N;;;;; -1E026;COMBINING GLAGOLITIC LETTER YO;Mn;230;NSM;;;;;N;;;;; -1E027;COMBINING GLAGOLITIC LETTER IOTATED SMALL YUS;Mn;230;NSM;;;;;N;;;;; -1E028;COMBINING GLAGOLITIC LETTER BIG YUS;Mn;230;NSM;;;;;N;;;;; -1E029;COMBINING GLAGOLITIC LETTER IOTATED BIG YUS;Mn;230;NSM;;;;;N;;;;; -1E02A;COMBINING GLAGOLITIC LETTER FITA;Mn;230;NSM;;;;;N;;;;; -1E030;MODIFIER LETTER CYRILLIC SMALL A;Lm;0;L;<super> 0430;;;;N;;;;; -1E031;MODIFIER LETTER CYRILLIC SMALL BE;Lm;0;L;<super> 0431;;;;N;;;;; -1E032;MODIFIER LETTER CYRILLIC SMALL VE;Lm;0;L;<super> 0432;;;;N;;;;; -1E033;MODIFIER LETTER CYRILLIC SMALL GHE;Lm;0;L;<super> 0433;;;;N;;;;; -1E034;MODIFIER LETTER CYRILLIC SMALL DE;Lm;0;L;<super> 0434;;;;N;;;;; -1E035;MODIFIER LETTER CYRILLIC SMALL IE;Lm;0;L;<super> 0435;;;;N;;;;; -1E036;MODIFIER LETTER CYRILLIC SMALL ZHE;Lm;0;L;<super> 0436;;;;N;;;;; -1E037;MODIFIER LETTER CYRILLIC SMALL ZE;Lm;0;L;<super> 0437;;;;N;;;;; -1E038;MODIFIER LETTER CYRILLIC SMALL I;Lm;0;L;<super> 0438;;;;N;;;;; -1E039;MODIFIER LETTER CYRILLIC SMALL KA;Lm;0;L;<super> 043A;;;;N;;;;; -1E03A;MODIFIER LETTER CYRILLIC SMALL EL;Lm;0;L;<super> 043B;;;;N;;;;; -1E03B;MODIFIER LETTER CYRILLIC SMALL EM;Lm;0;L;<super> 043C;;;;N;;;;; -1E03C;MODIFIER LETTER CYRILLIC SMALL O;Lm;0;L;<super> 043E;;;;N;;;;; -1E03D;MODIFIER LETTER CYRILLIC SMALL PE;Lm;0;L;<super> 043F;;;;N;;;;; -1E03E;MODIFIER LETTER CYRILLIC SMALL ER;Lm;0;L;<super> 0440;;;;N;;;;; -1E03F;MODIFIER LETTER CYRILLIC SMALL ES;Lm;0;L;<super> 0441;;;;N;;;;; -1E040;MODIFIER LETTER CYRILLIC SMALL TE;Lm;0;L;<super> 0442;;;;N;;;;; -1E041;MODIFIER LETTER CYRILLIC SMALL U;Lm;0;L;<super> 0443;;;;N;;;;; -1E042;MODIFIER LETTER CYRILLIC SMALL EF;Lm;0;L;<super> 0444;;;;N;;;;; -1E043;MODIFIER LETTER CYRILLIC SMALL HA;Lm;0;L;<super> 0445;;;;N;;;;; -1E044;MODIFIER LETTER CYRILLIC SMALL TSE;Lm;0;L;<super> 0446;;;;N;;;;; -1E045;MODIFIER LETTER CYRILLIC SMALL CHE;Lm;0;L;<super> 0447;;;;N;;;;; -1E046;MODIFIER LETTER CYRILLIC SMALL SHA;Lm;0;L;<super> 0448;;;;N;;;;; -1E047;MODIFIER LETTER CYRILLIC SMALL YERU;Lm;0;L;<super> 044B;;;;N;;;;; -1E048;MODIFIER LETTER CYRILLIC SMALL E;Lm;0;L;<super> 044D;;;;N;;;;; -1E049;MODIFIER LETTER CYRILLIC SMALL YU;Lm;0;L;<super> 044E;;;;N;;;;; -1E04A;MODIFIER LETTER CYRILLIC SMALL DZZE;Lm;0;L;<super> A689;;;;N;;;;; -1E04B;MODIFIER LETTER CYRILLIC SMALL SCHWA;Lm;0;L;<super> 04D9;;;;N;;;;; -1E04C;MODIFIER LETTER CYRILLIC SMALL BYELORUSSIAN-UKRAINIAN I;Lm;0;L;<super> 0456;;;;N;;;;; -1E04D;MODIFIER LETTER CYRILLIC SMALL JE;Lm;0;L;<super> 0458;;;;N;;;;; -1E04E;MODIFIER LETTER CYRILLIC SMALL BARRED O;Lm;0;L;<super> 04E9;;;;N;;;;; -1E04F;MODIFIER LETTER CYRILLIC SMALL STRAIGHT U;Lm;0;L;<super> 04AF;;;;N;;;;; -1E050;MODIFIER LETTER CYRILLIC SMALL PALOCHKA;Lm;0;L;<super> 04CF;;;;N;;;;; -1E051;CYRILLIC SUBSCRIPT SMALL LETTER A;Lm;0;L;<sub> 0430;;;;N;;;;; -1E052;CYRILLIC SUBSCRIPT SMALL LETTER BE;Lm;0;L;<sub> 0431;;;;N;;;;; -1E053;CYRILLIC SUBSCRIPT SMALL LETTER VE;Lm;0;L;<sub> 0432;;;;N;;;;; -1E054;CYRILLIC SUBSCRIPT SMALL LETTER GHE;Lm;0;L;<sub> 0433;;;;N;;;;; -1E055;CYRILLIC SUBSCRIPT SMALL LETTER DE;Lm;0;L;<sub> 0434;;;;N;;;;; -1E056;CYRILLIC SUBSCRIPT SMALL LETTER IE;Lm;0;L;<sub> 0435;;;;N;;;;; -1E057;CYRILLIC SUBSCRIPT SMALL LETTER ZHE;Lm;0;L;<sub> 0436;;;;N;;;;; -1E058;CYRILLIC SUBSCRIPT SMALL LETTER ZE;Lm;0;L;<sub> 0437;;;;N;;;;; -1E059;CYRILLIC SUBSCRIPT SMALL LETTER I;Lm;0;L;<sub> 0438;;;;N;;;;; -1E05A;CYRILLIC SUBSCRIPT SMALL LETTER KA;Lm;0;L;<sub> 043A;;;;N;;;;; -1E05B;CYRILLIC SUBSCRIPT SMALL LETTER EL;Lm;0;L;<sub> 043B;;;;N;;;;; -1E05C;CYRILLIC SUBSCRIPT SMALL LETTER O;Lm;0;L;<sub> 043E;;;;N;;;;; -1E05D;CYRILLIC SUBSCRIPT SMALL LETTER PE;Lm;0;L;<sub> 043F;;;;N;;;;; -1E05E;CYRILLIC SUBSCRIPT SMALL LETTER ES;Lm;0;L;<sub> 0441;;;;N;;;;; -1E05F;CYRILLIC SUBSCRIPT SMALL LETTER U;Lm;0;L;<sub> 0443;;;;N;;;;; -1E060;CYRILLIC SUBSCRIPT SMALL LETTER EF;Lm;0;L;<sub> 0444;;;;N;;;;; -1E061;CYRILLIC SUBSCRIPT SMALL LETTER HA;Lm;0;L;<sub> 0445;;;;N;;;;; -1E062;CYRILLIC SUBSCRIPT SMALL LETTER TSE;Lm;0;L;<sub> 0446;;;;N;;;;; -1E063;CYRILLIC SUBSCRIPT SMALL LETTER CHE;Lm;0;L;<sub> 0447;;;;N;;;;; -1E064;CYRILLIC SUBSCRIPT SMALL LETTER SHA;Lm;0;L;<sub> 0448;;;;N;;;;; -1E065;CYRILLIC SUBSCRIPT SMALL LETTER HARD SIGN;Lm;0;L;<sub> 044A;;;;N;;;;; -1E066;CYRILLIC SUBSCRIPT SMALL LETTER YERU;Lm;0;L;<sub> 044B;;;;N;;;;; -1E067;CYRILLIC SUBSCRIPT SMALL LETTER GHE WITH UPTURN;Lm;0;L;<sub> 0491;;;;N;;;;; -1E068;CYRILLIC SUBSCRIPT SMALL LETTER BYELORUSSIAN-UKRAINIAN I;Lm;0;L;<sub> 0456;;;;N;;;;; -1E069;CYRILLIC SUBSCRIPT SMALL LETTER DZE;Lm;0;L;<sub> 0455;;;;N;;;;; -1E06A;CYRILLIC SUBSCRIPT SMALL LETTER DZHE;Lm;0;L;<sub> 045F;;;;N;;;;; -1E06B;MODIFIER LETTER CYRILLIC SMALL ES WITH DESCENDER;Lm;0;L;<super> 04AB;;;;N;;;;; -1E06C;MODIFIER LETTER CYRILLIC SMALL YERU WITH BACK YER;Lm;0;L;<super> A651;;;;N;;;;; -1E06D;MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE;Lm;0;L;<super> 04B1;;;;N;;;;; -1E08F;COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I;Mn;230;NSM;;;;;N;;;;; -1E100;NYIAKENG PUACHUE HMONG LETTER MA;Lo;0;L;;;;;N;;;;; -1E101;NYIAKENG PUACHUE HMONG LETTER TSA;Lo;0;L;;;;;N;;;;; -1E102;NYIAKENG PUACHUE HMONG LETTER NTA;Lo;0;L;;;;;N;;;;; -1E103;NYIAKENG PUACHUE HMONG LETTER TA;Lo;0;L;;;;;N;;;;; -1E104;NYIAKENG PUACHUE HMONG LETTER HA;Lo;0;L;;;;;N;;;;; -1E105;NYIAKENG PUACHUE HMONG LETTER NA;Lo;0;L;;;;;N;;;;; -1E106;NYIAKENG PUACHUE HMONG LETTER XA;Lo;0;L;;;;;N;;;;; -1E107;NYIAKENG PUACHUE HMONG LETTER NKA;Lo;0;L;;;;;N;;;;; -1E108;NYIAKENG PUACHUE HMONG LETTER CA;Lo;0;L;;;;;N;;;;; -1E109;NYIAKENG PUACHUE HMONG LETTER LA;Lo;0;L;;;;;N;;;;; -1E10A;NYIAKENG PUACHUE HMONG LETTER SA;Lo;0;L;;;;;N;;;;; -1E10B;NYIAKENG PUACHUE HMONG LETTER ZA;Lo;0;L;;;;;N;;;;; -1E10C;NYIAKENG PUACHUE HMONG LETTER NCA;Lo;0;L;;;;;N;;;;; -1E10D;NYIAKENG PUACHUE HMONG LETTER NTSA;Lo;0;L;;;;;N;;;;; -1E10E;NYIAKENG PUACHUE HMONG LETTER KA;Lo;0;L;;;;;N;;;;; -1E10F;NYIAKENG PUACHUE HMONG LETTER DA;Lo;0;L;;;;;N;;;;; -1E110;NYIAKENG PUACHUE HMONG LETTER NYA;Lo;0;L;;;;;N;;;;; -1E111;NYIAKENG PUACHUE HMONG LETTER NRA;Lo;0;L;;;;;N;;;;; -1E112;NYIAKENG PUACHUE HMONG LETTER VA;Lo;0;L;;;;;N;;;;; -1E113;NYIAKENG PUACHUE HMONG LETTER NTXA;Lo;0;L;;;;;N;;;;; -1E114;NYIAKENG PUACHUE HMONG LETTER TXA;Lo;0;L;;;;;N;;;;; -1E115;NYIAKENG PUACHUE HMONG LETTER FA;Lo;0;L;;;;;N;;;;; -1E116;NYIAKENG PUACHUE HMONG LETTER RA;Lo;0;L;;;;;N;;;;; -1E117;NYIAKENG PUACHUE HMONG LETTER QA;Lo;0;L;;;;;N;;;;; -1E118;NYIAKENG PUACHUE HMONG LETTER YA;Lo;0;L;;;;;N;;;;; -1E119;NYIAKENG PUACHUE HMONG LETTER NQA;Lo;0;L;;;;;N;;;;; -1E11A;NYIAKENG PUACHUE HMONG LETTER PA;Lo;0;L;;;;;N;;;;; -1E11B;NYIAKENG PUACHUE HMONG LETTER XYA;Lo;0;L;;;;;N;;;;; -1E11C;NYIAKENG PUACHUE HMONG LETTER NPA;Lo;0;L;;;;;N;;;;; -1E11D;NYIAKENG PUACHUE HMONG LETTER DLA;Lo;0;L;;;;;N;;;;; -1E11E;NYIAKENG PUACHUE HMONG LETTER NPLA;Lo;0;L;;;;;N;;;;; -1E11F;NYIAKENG PUACHUE HMONG LETTER HAH;Lo;0;L;;;;;N;;;;; -1E120;NYIAKENG PUACHUE HMONG LETTER MLA;Lo;0;L;;;;;N;;;;; -1E121;NYIAKENG PUACHUE HMONG LETTER PLA;Lo;0;L;;;;;N;;;;; -1E122;NYIAKENG PUACHUE HMONG LETTER GA;Lo;0;L;;;;;N;;;;; -1E123;NYIAKENG PUACHUE HMONG LETTER RRA;Lo;0;L;;;;;N;;;;; -1E124;NYIAKENG PUACHUE HMONG LETTER A;Lo;0;L;;;;;N;;;;; -1E125;NYIAKENG PUACHUE HMONG LETTER AA;Lo;0;L;;;;;N;;;;; -1E126;NYIAKENG PUACHUE HMONG LETTER I;Lo;0;L;;;;;N;;;;; -1E127;NYIAKENG PUACHUE HMONG LETTER U;Lo;0;L;;;;;N;;;;; -1E128;NYIAKENG PUACHUE HMONG LETTER O;Lo;0;L;;;;;N;;;;; -1E129;NYIAKENG PUACHUE HMONG LETTER OO;Lo;0;L;;;;;N;;;;; -1E12A;NYIAKENG PUACHUE HMONG LETTER E;Lo;0;L;;;;;N;;;;; -1E12B;NYIAKENG PUACHUE HMONG LETTER EE;Lo;0;L;;;;;N;;;;; -1E12C;NYIAKENG PUACHUE HMONG LETTER W;Lo;0;L;;;;;N;;;;; -1E130;NYIAKENG PUACHUE HMONG TONE-B;Mn;230;NSM;;;;;N;;;;; -1E131;NYIAKENG PUACHUE HMONG TONE-M;Mn;230;NSM;;;;;N;;;;; -1E132;NYIAKENG PUACHUE HMONG TONE-J;Mn;230;NSM;;;;;N;;;;; -1E133;NYIAKENG PUACHUE HMONG TONE-V;Mn;230;NSM;;;;;N;;;;; -1E134;NYIAKENG PUACHUE HMONG TONE-S;Mn;230;NSM;;;;;N;;;;; -1E135;NYIAKENG PUACHUE HMONG TONE-G;Mn;230;NSM;;;;;N;;;;; -1E136;NYIAKENG PUACHUE HMONG TONE-D;Mn;230;NSM;;;;;N;;;;; -1E137;NYIAKENG PUACHUE HMONG SIGN FOR PERSON;Lm;0;L;;;;;N;;;;; -1E138;NYIAKENG PUACHUE HMONG SIGN FOR THING;Lm;0;L;;;;;N;;;;; -1E139;NYIAKENG PUACHUE HMONG SIGN FOR LOCATION;Lm;0;L;;;;;N;;;;; -1E13A;NYIAKENG PUACHUE HMONG SIGN FOR ANIMAL;Lm;0;L;;;;;N;;;;; -1E13B;NYIAKENG PUACHUE HMONG SIGN FOR INVERTEBRATE;Lm;0;L;;;;;N;;;;; -1E13C;NYIAKENG PUACHUE HMONG SIGN XW XW;Lm;0;L;;;;;N;;;;; -1E13D;NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER;Lm;0;L;;;;;N;;;;; -1E140;NYIAKENG PUACHUE HMONG DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -1E141;NYIAKENG PUACHUE HMONG DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -1E142;NYIAKENG PUACHUE HMONG DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -1E143;NYIAKENG PUACHUE HMONG DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -1E144;NYIAKENG PUACHUE HMONG DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -1E145;NYIAKENG PUACHUE HMONG DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -1E146;NYIAKENG PUACHUE HMONG DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -1E147;NYIAKENG PUACHUE HMONG DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -1E148;NYIAKENG PUACHUE HMONG DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -1E149;NYIAKENG PUACHUE HMONG DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -1E14E;NYIAKENG PUACHUE HMONG LOGOGRAM NYAJ;Lo;0;L;;;;;N;;;;; -1E14F;NYIAKENG PUACHUE HMONG CIRCLED CA;So;0;L;;;;;N;;;;; -1E290;TOTO LETTER PA;Lo;0;L;;;;;N;;;;; -1E291;TOTO LETTER BA;Lo;0;L;;;;;N;;;;; -1E292;TOTO LETTER TA;Lo;0;L;;;;;N;;;;; -1E293;TOTO LETTER DA;Lo;0;L;;;;;N;;;;; -1E294;TOTO LETTER KA;Lo;0;L;;;;;N;;;;; -1E295;TOTO LETTER GA;Lo;0;L;;;;;N;;;;; -1E296;TOTO LETTER MA;Lo;0;L;;;;;N;;;;; -1E297;TOTO LETTER NA;Lo;0;L;;;;;N;;;;; -1E298;TOTO LETTER NGA;Lo;0;L;;;;;N;;;;; -1E299;TOTO LETTER SA;Lo;0;L;;;;;N;;;;; -1E29A;TOTO LETTER CHA;Lo;0;L;;;;;N;;;;; -1E29B;TOTO LETTER YA;Lo;0;L;;;;;N;;;;; -1E29C;TOTO LETTER WA;Lo;0;L;;;;;N;;;;; -1E29D;TOTO LETTER JA;Lo;0;L;;;;;N;;;;; -1E29E;TOTO LETTER HA;Lo;0;L;;;;;N;;;;; -1E29F;TOTO LETTER RA;Lo;0;L;;;;;N;;;;; -1E2A0;TOTO LETTER LA;Lo;0;L;;;;;N;;;;; -1E2A1;TOTO LETTER I;Lo;0;L;;;;;N;;;;; -1E2A2;TOTO LETTER BREATHY I;Lo;0;L;;;;;N;;;;; -1E2A3;TOTO LETTER IU;Lo;0;L;;;;;N;;;;; -1E2A4;TOTO LETTER BREATHY IU;Lo;0;L;;;;;N;;;;; -1E2A5;TOTO LETTER U;Lo;0;L;;;;;N;;;;; -1E2A6;TOTO LETTER E;Lo;0;L;;;;;N;;;;; -1E2A7;TOTO LETTER BREATHY E;Lo;0;L;;;;;N;;;;; -1E2A8;TOTO LETTER EO;Lo;0;L;;;;;N;;;;; -1E2A9;TOTO LETTER BREATHY EO;Lo;0;L;;;;;N;;;;; -1E2AA;TOTO LETTER O;Lo;0;L;;;;;N;;;;; -1E2AB;TOTO LETTER AE;Lo;0;L;;;;;N;;;;; -1E2AC;TOTO LETTER BREATHY AE;Lo;0;L;;;;;N;;;;; -1E2AD;TOTO LETTER A;Lo;0;L;;;;;N;;;;; -1E2AE;TOTO SIGN RISING TONE;Mn;230;NSM;;;;;N;;;;; -1E2C0;WANCHO LETTER AA;Lo;0;L;;;;;N;;;;; -1E2C1;WANCHO LETTER A;Lo;0;L;;;;;N;;;;; -1E2C2;WANCHO LETTER BA;Lo;0;L;;;;;N;;;;; -1E2C3;WANCHO LETTER CA;Lo;0;L;;;;;N;;;;; -1E2C4;WANCHO LETTER DA;Lo;0;L;;;;;N;;;;; -1E2C5;WANCHO LETTER GA;Lo;0;L;;;;;N;;;;; -1E2C6;WANCHO LETTER YA;Lo;0;L;;;;;N;;;;; -1E2C7;WANCHO LETTER PHA;Lo;0;L;;;;;N;;;;; -1E2C8;WANCHO LETTER LA;Lo;0;L;;;;;N;;;;; -1E2C9;WANCHO LETTER NA;Lo;0;L;;;;;N;;;;; -1E2CA;WANCHO LETTER PA;Lo;0;L;;;;;N;;;;; -1E2CB;WANCHO LETTER TA;Lo;0;L;;;;;N;;;;; -1E2CC;WANCHO LETTER THA;Lo;0;L;;;;;N;;;;; -1E2CD;WANCHO LETTER FA;Lo;0;L;;;;;N;;;;; -1E2CE;WANCHO LETTER SA;Lo;0;L;;;;;N;;;;; -1E2CF;WANCHO LETTER SHA;Lo;0;L;;;;;N;;;;; -1E2D0;WANCHO LETTER JA;Lo;0;L;;;;;N;;;;; -1E2D1;WANCHO LETTER ZA;Lo;0;L;;;;;N;;;;; -1E2D2;WANCHO LETTER WA;Lo;0;L;;;;;N;;;;; -1E2D3;WANCHO LETTER VA;Lo;0;L;;;;;N;;;;; -1E2D4;WANCHO LETTER KA;Lo;0;L;;;;;N;;;;; -1E2D5;WANCHO LETTER O;Lo;0;L;;;;;N;;;;; -1E2D6;WANCHO LETTER AU;Lo;0;L;;;;;N;;;;; -1E2D7;WANCHO LETTER RA;Lo;0;L;;;;;N;;;;; -1E2D8;WANCHO LETTER MA;Lo;0;L;;;;;N;;;;; -1E2D9;WANCHO LETTER KHA;Lo;0;L;;;;;N;;;;; -1E2DA;WANCHO LETTER HA;Lo;0;L;;;;;N;;;;; -1E2DB;WANCHO LETTER E;Lo;0;L;;;;;N;;;;; -1E2DC;WANCHO LETTER I;Lo;0;L;;;;;N;;;;; -1E2DD;WANCHO LETTER NGA;Lo;0;L;;;;;N;;;;; -1E2DE;WANCHO LETTER U;Lo;0;L;;;;;N;;;;; -1E2DF;WANCHO LETTER LLHA;Lo;0;L;;;;;N;;;;; -1E2E0;WANCHO LETTER TSA;Lo;0;L;;;;;N;;;;; -1E2E1;WANCHO LETTER TRA;Lo;0;L;;;;;N;;;;; -1E2E2;WANCHO LETTER ONG;Lo;0;L;;;;;N;;;;; -1E2E3;WANCHO LETTER AANG;Lo;0;L;;;;;N;;;;; -1E2E4;WANCHO LETTER ANG;Lo;0;L;;;;;N;;;;; -1E2E5;WANCHO LETTER ING;Lo;0;L;;;;;N;;;;; -1E2E6;WANCHO LETTER ON;Lo;0;L;;;;;N;;;;; -1E2E7;WANCHO LETTER EN;Lo;0;L;;;;;N;;;;; -1E2E8;WANCHO LETTER AAN;Lo;0;L;;;;;N;;;;; -1E2E9;WANCHO LETTER NYA;Lo;0;L;;;;;N;;;;; -1E2EA;WANCHO LETTER UEN;Lo;0;L;;;;;N;;;;; -1E2EB;WANCHO LETTER YIH;Lo;0;L;;;;;N;;;;; -1E2EC;WANCHO TONE TUP;Mn;230;NSM;;;;;N;;;;; -1E2ED;WANCHO TONE TUPNI;Mn;230;NSM;;;;;N;;;;; -1E2EE;WANCHO TONE KOI;Mn;230;NSM;;;;;N;;;;; -1E2EF;WANCHO TONE KOINI;Mn;230;NSM;;;;;N;;;;; -1E2F0;WANCHO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -1E2F1;WANCHO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -1E2F2;WANCHO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -1E2F3;WANCHO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -1E2F4;WANCHO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -1E2F5;WANCHO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -1E2F6;WANCHO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -1E2F7;WANCHO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -1E2F8;WANCHO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -1E2F9;WANCHO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -1E2FF;WANCHO NGUN SIGN;Sc;0;ET;;;;;N;;;;; -1E4D0;NAG MUNDARI LETTER O;Lo;0;L;;;;;N;;;;; -1E4D1;NAG MUNDARI LETTER OP;Lo;0;L;;;;;N;;;;; -1E4D2;NAG MUNDARI LETTER OL;Lo;0;L;;;;;N;;;;; -1E4D3;NAG MUNDARI LETTER OY;Lo;0;L;;;;;N;;;;; -1E4D4;NAG MUNDARI LETTER ONG;Lo;0;L;;;;;N;;;;; -1E4D5;NAG MUNDARI LETTER A;Lo;0;L;;;;;N;;;;; -1E4D6;NAG MUNDARI LETTER AJ;Lo;0;L;;;;;N;;;;; -1E4D7;NAG MUNDARI LETTER AB;Lo;0;L;;;;;N;;;;; -1E4D8;NAG MUNDARI LETTER ANY;Lo;0;L;;;;;N;;;;; -1E4D9;NAG MUNDARI LETTER AH;Lo;0;L;;;;;N;;;;; -1E4DA;NAG MUNDARI LETTER I;Lo;0;L;;;;;N;;;;; -1E4DB;NAG MUNDARI LETTER IS;Lo;0;L;;;;;N;;;;; -1E4DC;NAG MUNDARI LETTER IDD;Lo;0;L;;;;;N;;;;; -1E4DD;NAG MUNDARI LETTER IT;Lo;0;L;;;;;N;;;;; -1E4DE;NAG MUNDARI LETTER IH;Lo;0;L;;;;;N;;;;; -1E4DF;NAG MUNDARI LETTER U;Lo;0;L;;;;;N;;;;; -1E4E0;NAG MUNDARI LETTER UC;Lo;0;L;;;;;N;;;;; -1E4E1;NAG MUNDARI LETTER UD;Lo;0;L;;;;;N;;;;; -1E4E2;NAG MUNDARI LETTER UK;Lo;0;L;;;;;N;;;;; -1E4E3;NAG MUNDARI LETTER UR;Lo;0;L;;;;;N;;;;; -1E4E4;NAG MUNDARI LETTER E;Lo;0;L;;;;;N;;;;; -1E4E5;NAG MUNDARI LETTER ENN;Lo;0;L;;;;;N;;;;; -1E4E6;NAG MUNDARI LETTER EG;Lo;0;L;;;;;N;;;;; -1E4E7;NAG MUNDARI LETTER EM;Lo;0;L;;;;;N;;;;; -1E4E8;NAG MUNDARI LETTER EN;Lo;0;L;;;;;N;;;;; -1E4E9;NAG MUNDARI LETTER ETT;Lo;0;L;;;;;N;;;;; -1E4EA;NAG MUNDARI LETTER ELL;Lo;0;L;;;;;N;;;;; -1E4EB;NAG MUNDARI SIGN OJOD;Lm;0;L;;;;;N;;;;; -1E4EC;NAG MUNDARI SIGN MUHOR;Mn;232;NSM;;;;;N;;;;; -1E4ED;NAG MUNDARI SIGN TOYOR;Mn;232;NSM;;;;;N;;;;; -1E4EE;NAG MUNDARI SIGN IKIR;Mn;220;NSM;;;;;N;;;;; -1E4EF;NAG MUNDARI SIGN SUTUH;Mn;230;NSM;;;;;N;;;;; -1E4F0;NAG MUNDARI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; -1E4F1;NAG MUNDARI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -1E4F2;NAG MUNDARI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; -1E4F3;NAG MUNDARI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; -1E4F4;NAG MUNDARI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; -1E4F5;NAG MUNDARI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; -1E4F6;NAG MUNDARI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; -1E4F7;NAG MUNDARI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; -1E4F8;NAG MUNDARI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; -1E4F9;NAG MUNDARI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -1E7E0;ETHIOPIC SYLLABLE HHYA;Lo;0;L;;;;;N;;;;; -1E7E1;ETHIOPIC SYLLABLE HHYU;Lo;0;L;;;;;N;;;;; -1E7E2;ETHIOPIC SYLLABLE HHYI;Lo;0;L;;;;;N;;;;; -1E7E3;ETHIOPIC SYLLABLE HHYAA;Lo;0;L;;;;;N;;;;; -1E7E4;ETHIOPIC SYLLABLE HHYEE;Lo;0;L;;;;;N;;;;; -1E7E5;ETHIOPIC SYLLABLE HHYE;Lo;0;L;;;;;N;;;;; -1E7E6;ETHIOPIC SYLLABLE HHYO;Lo;0;L;;;;;N;;;;; -1E7E8;ETHIOPIC SYLLABLE GURAGE HHWA;Lo;0;L;;;;;N;;;;; -1E7E9;ETHIOPIC SYLLABLE HHWI;Lo;0;L;;;;;N;;;;; -1E7EA;ETHIOPIC SYLLABLE HHWEE;Lo;0;L;;;;;N;;;;; -1E7EB;ETHIOPIC SYLLABLE HHWE;Lo;0;L;;;;;N;;;;; -1E7ED;ETHIOPIC SYLLABLE GURAGE MWI;Lo;0;L;;;;;N;;;;; -1E7EE;ETHIOPIC SYLLABLE GURAGE MWEE;Lo;0;L;;;;;N;;;;; -1E7F0;ETHIOPIC SYLLABLE GURAGE QWI;Lo;0;L;;;;;N;;;;; -1E7F1;ETHIOPIC SYLLABLE GURAGE QWEE;Lo;0;L;;;;;N;;;;; -1E7F2;ETHIOPIC SYLLABLE GURAGE QWE;Lo;0;L;;;;;N;;;;; -1E7F3;ETHIOPIC SYLLABLE GURAGE BWI;Lo;0;L;;;;;N;;;;; -1E7F4;ETHIOPIC SYLLABLE GURAGE BWEE;Lo;0;L;;;;;N;;;;; -1E7F5;ETHIOPIC SYLLABLE GURAGE KWI;Lo;0;L;;;;;N;;;;; -1E7F6;ETHIOPIC SYLLABLE GURAGE KWEE;Lo;0;L;;;;;N;;;;; -1E7F7;ETHIOPIC SYLLABLE GURAGE KWE;Lo;0;L;;;;;N;;;;; -1E7F8;ETHIOPIC SYLLABLE GURAGE GWI;Lo;0;L;;;;;N;;;;; -1E7F9;ETHIOPIC SYLLABLE GURAGE GWEE;Lo;0;L;;;;;N;;;;; -1E7FA;ETHIOPIC SYLLABLE GURAGE GWE;Lo;0;L;;;;;N;;;;; -1E7FB;ETHIOPIC SYLLABLE GURAGE FWI;Lo;0;L;;;;;N;;;;; -1E7FC;ETHIOPIC SYLLABLE GURAGE FWEE;Lo;0;L;;;;;N;;;;; -1E7FD;ETHIOPIC SYLLABLE GURAGE PWI;Lo;0;L;;;;;N;;;;; -1E7FE;ETHIOPIC SYLLABLE GURAGE PWEE;Lo;0;L;;;;;N;;;;; -1E800;MENDE KIKAKUI SYLLABLE M001 KI;Lo;0;R;;;;;N;;;;; -1E801;MENDE KIKAKUI SYLLABLE M002 KA;Lo;0;R;;;;;N;;;;; -1E802;MENDE KIKAKUI SYLLABLE M003 KU;Lo;0;R;;;;;N;;;;; -1E803;MENDE KIKAKUI SYLLABLE M065 KEE;Lo;0;R;;;;;N;;;;; -1E804;MENDE KIKAKUI SYLLABLE M095 KE;Lo;0;R;;;;;N;;;;; -1E805;MENDE KIKAKUI SYLLABLE M076 KOO;Lo;0;R;;;;;N;;;;; -1E806;MENDE KIKAKUI SYLLABLE M048 KO;Lo;0;R;;;;;N;;;;; -1E807;MENDE KIKAKUI SYLLABLE M179 KUA;Lo;0;R;;;;;N;;;;; -1E808;MENDE KIKAKUI SYLLABLE M004 WI;Lo;0;R;;;;;N;;;;; -1E809;MENDE KIKAKUI SYLLABLE M005 WA;Lo;0;R;;;;;N;;;;; -1E80A;MENDE KIKAKUI SYLLABLE M006 WU;Lo;0;R;;;;;N;;;;; -1E80B;MENDE KIKAKUI SYLLABLE M126 WEE;Lo;0;R;;;;;N;;;;; -1E80C;MENDE KIKAKUI SYLLABLE M118 WE;Lo;0;R;;;;;N;;;;; -1E80D;MENDE KIKAKUI SYLLABLE M114 WOO;Lo;0;R;;;;;N;;;;; -1E80E;MENDE KIKAKUI SYLLABLE M045 WO;Lo;0;R;;;;;N;;;;; -1E80F;MENDE KIKAKUI SYLLABLE M194 WUI;Lo;0;R;;;;;N;;;;; -1E810;MENDE KIKAKUI SYLLABLE M143 WEI;Lo;0;R;;;;;N;;;;; -1E811;MENDE KIKAKUI SYLLABLE M061 WVI;Lo;0;R;;;;;N;;;;; -1E812;MENDE KIKAKUI SYLLABLE M049 WVA;Lo;0;R;;;;;N;;;;; -1E813;MENDE KIKAKUI SYLLABLE M139 WVE;Lo;0;R;;;;;N;;;;; -1E814;MENDE KIKAKUI SYLLABLE M007 MIN;Lo;0;R;;;;;N;;;;; -1E815;MENDE KIKAKUI SYLLABLE M008 MAN;Lo;0;R;;;;;N;;;;; -1E816;MENDE KIKAKUI SYLLABLE M009 MUN;Lo;0;R;;;;;N;;;;; -1E817;MENDE KIKAKUI SYLLABLE M059 MEN;Lo;0;R;;;;;N;;;;; -1E818;MENDE KIKAKUI SYLLABLE M094 MON;Lo;0;R;;;;;N;;;;; -1E819;MENDE KIKAKUI SYLLABLE M154 MUAN;Lo;0;R;;;;;N;;;;; -1E81A;MENDE KIKAKUI SYLLABLE M189 MUEN;Lo;0;R;;;;;N;;;;; -1E81B;MENDE KIKAKUI SYLLABLE M010 BI;Lo;0;R;;;;;N;;;;; -1E81C;MENDE KIKAKUI SYLLABLE M011 BA;Lo;0;R;;;;;N;;;;; -1E81D;MENDE KIKAKUI SYLLABLE M012 BU;Lo;0;R;;;;;N;;;;; -1E81E;MENDE KIKAKUI SYLLABLE M150 BEE;Lo;0;R;;;;;N;;;;; -1E81F;MENDE KIKAKUI SYLLABLE M097 BE;Lo;0;R;;;;;N;;;;; -1E820;MENDE KIKAKUI SYLLABLE M103 BOO;Lo;0;R;;;;;N;;;;; -1E821;MENDE KIKAKUI SYLLABLE M138 BO;Lo;0;R;;;;;N;;;;; -1E822;MENDE KIKAKUI SYLLABLE M013 I;Lo;0;R;;;;;N;;;;; -1E823;MENDE KIKAKUI SYLLABLE M014 A;Lo;0;R;;;;;N;;;;; -1E824;MENDE KIKAKUI SYLLABLE M015 U;Lo;0;R;;;;;N;;;;; -1E825;MENDE KIKAKUI SYLLABLE M163 EE;Lo;0;R;;;;;N;;;;; -1E826;MENDE KIKAKUI SYLLABLE M100 E;Lo;0;R;;;;;N;;;;; -1E827;MENDE KIKAKUI SYLLABLE M165 OO;Lo;0;R;;;;;N;;;;; -1E828;MENDE KIKAKUI SYLLABLE M147 O;Lo;0;R;;;;;N;;;;; -1E829;MENDE KIKAKUI SYLLABLE M137 EI;Lo;0;R;;;;;N;;;;; -1E82A;MENDE KIKAKUI SYLLABLE M131 IN;Lo;0;R;;;;;N;;;;; -1E82B;MENDE KIKAKUI SYLLABLE M135 IN;Lo;0;R;;;;;N;;;;; -1E82C;MENDE KIKAKUI SYLLABLE M195 AN;Lo;0;R;;;;;N;;;;; -1E82D;MENDE KIKAKUI SYLLABLE M178 EN;Lo;0;R;;;;;N;;;;; -1E82E;MENDE KIKAKUI SYLLABLE M019 SI;Lo;0;R;;;;;N;;;;; -1E82F;MENDE KIKAKUI SYLLABLE M020 SA;Lo;0;R;;;;;N;;;;; -1E830;MENDE KIKAKUI SYLLABLE M021 SU;Lo;0;R;;;;;N;;;;; -1E831;MENDE KIKAKUI SYLLABLE M162 SEE;Lo;0;R;;;;;N;;;;; -1E832;MENDE KIKAKUI SYLLABLE M116 SE;Lo;0;R;;;;;N;;;;; -1E833;MENDE KIKAKUI SYLLABLE M136 SOO;Lo;0;R;;;;;N;;;;; -1E834;MENDE KIKAKUI SYLLABLE M079 SO;Lo;0;R;;;;;N;;;;; -1E835;MENDE KIKAKUI SYLLABLE M196 SIA;Lo;0;R;;;;;N;;;;; -1E836;MENDE KIKAKUI SYLLABLE M025 LI;Lo;0;R;;;;;N;;;;; -1E837;MENDE KIKAKUI SYLLABLE M026 LA;Lo;0;R;;;;;N;;;;; -1E838;MENDE KIKAKUI SYLLABLE M027 LU;Lo;0;R;;;;;N;;;;; -1E839;MENDE KIKAKUI SYLLABLE M084 LEE;Lo;0;R;;;;;N;;;;; -1E83A;MENDE KIKAKUI SYLLABLE M073 LE;Lo;0;R;;;;;N;;;;; -1E83B;MENDE KIKAKUI SYLLABLE M054 LOO;Lo;0;R;;;;;N;;;;; -1E83C;MENDE KIKAKUI SYLLABLE M153 LO;Lo;0;R;;;;;N;;;;; -1E83D;MENDE KIKAKUI SYLLABLE M110 LONG LE;Lo;0;R;;;;;N;;;;; -1E83E;MENDE KIKAKUI SYLLABLE M016 DI;Lo;0;R;;;;;N;;;;; -1E83F;MENDE KIKAKUI SYLLABLE M017 DA;Lo;0;R;;;;;N;;;;; -1E840;MENDE KIKAKUI SYLLABLE M018 DU;Lo;0;R;;;;;N;;;;; -1E841;MENDE KIKAKUI SYLLABLE M089 DEE;Lo;0;R;;;;;N;;;;; -1E842;MENDE KIKAKUI SYLLABLE M180 DOO;Lo;0;R;;;;;N;;;;; -1E843;MENDE KIKAKUI SYLLABLE M181 DO;Lo;0;R;;;;;N;;;;; -1E844;MENDE KIKAKUI SYLLABLE M022 TI;Lo;0;R;;;;;N;;;;; -1E845;MENDE KIKAKUI SYLLABLE M023 TA;Lo;0;R;;;;;N;;;;; -1E846;MENDE KIKAKUI SYLLABLE M024 TU;Lo;0;R;;;;;N;;;;; -1E847;MENDE KIKAKUI SYLLABLE M091 TEE;Lo;0;R;;;;;N;;;;; -1E848;MENDE KIKAKUI SYLLABLE M055 TE;Lo;0;R;;;;;N;;;;; -1E849;MENDE KIKAKUI SYLLABLE M104 TOO;Lo;0;R;;;;;N;;;;; -1E84A;MENDE KIKAKUI SYLLABLE M069 TO;Lo;0;R;;;;;N;;;;; -1E84B;MENDE KIKAKUI SYLLABLE M028 JI;Lo;0;R;;;;;N;;;;; -1E84C;MENDE KIKAKUI SYLLABLE M029 JA;Lo;0;R;;;;;N;;;;; -1E84D;MENDE KIKAKUI SYLLABLE M030 JU;Lo;0;R;;;;;N;;;;; -1E84E;MENDE KIKAKUI SYLLABLE M157 JEE;Lo;0;R;;;;;N;;;;; -1E84F;MENDE KIKAKUI SYLLABLE M113 JE;Lo;0;R;;;;;N;;;;; -1E850;MENDE KIKAKUI SYLLABLE M160 JOO;Lo;0;R;;;;;N;;;;; -1E851;MENDE KIKAKUI SYLLABLE M063 JO;Lo;0;R;;;;;N;;;;; -1E852;MENDE KIKAKUI SYLLABLE M175 LONG JO;Lo;0;R;;;;;N;;;;; -1E853;MENDE KIKAKUI SYLLABLE M031 YI;Lo;0;R;;;;;N;;;;; -1E854;MENDE KIKAKUI SYLLABLE M032 YA;Lo;0;R;;;;;N;;;;; -1E855;MENDE KIKAKUI SYLLABLE M033 YU;Lo;0;R;;;;;N;;;;; -1E856;MENDE KIKAKUI SYLLABLE M109 YEE;Lo;0;R;;;;;N;;;;; -1E857;MENDE KIKAKUI SYLLABLE M080 YE;Lo;0;R;;;;;N;;;;; -1E858;MENDE KIKAKUI SYLLABLE M141 YOO;Lo;0;R;;;;;N;;;;; -1E859;MENDE KIKAKUI SYLLABLE M121 YO;Lo;0;R;;;;;N;;;;; -1E85A;MENDE KIKAKUI SYLLABLE M034 FI;Lo;0;R;;;;;N;;;;; -1E85B;MENDE KIKAKUI SYLLABLE M035 FA;Lo;0;R;;;;;N;;;;; -1E85C;MENDE KIKAKUI SYLLABLE M036 FU;Lo;0;R;;;;;N;;;;; -1E85D;MENDE KIKAKUI SYLLABLE M078 FEE;Lo;0;R;;;;;N;;;;; -1E85E;MENDE KIKAKUI SYLLABLE M075 FE;Lo;0;R;;;;;N;;;;; -1E85F;MENDE KIKAKUI SYLLABLE M133 FOO;Lo;0;R;;;;;N;;;;; -1E860;MENDE KIKAKUI SYLLABLE M088 FO;Lo;0;R;;;;;N;;;;; -1E861;MENDE KIKAKUI SYLLABLE M197 FUA;Lo;0;R;;;;;N;;;;; -1E862;MENDE KIKAKUI SYLLABLE M101 FAN;Lo;0;R;;;;;N;;;;; -1E863;MENDE KIKAKUI SYLLABLE M037 NIN;Lo;0;R;;;;;N;;;;; -1E864;MENDE KIKAKUI SYLLABLE M038 NAN;Lo;0;R;;;;;N;;;;; -1E865;MENDE KIKAKUI SYLLABLE M039 NUN;Lo;0;R;;;;;N;;;;; -1E866;MENDE KIKAKUI SYLLABLE M117 NEN;Lo;0;R;;;;;N;;;;; -1E867;MENDE KIKAKUI SYLLABLE M169 NON;Lo;0;R;;;;;N;;;;; -1E868;MENDE KIKAKUI SYLLABLE M176 HI;Lo;0;R;;;;;N;;;;; -1E869;MENDE KIKAKUI SYLLABLE M041 HA;Lo;0;R;;;;;N;;;;; -1E86A;MENDE KIKAKUI SYLLABLE M186 HU;Lo;0;R;;;;;N;;;;; -1E86B;MENDE KIKAKUI SYLLABLE M040 HEE;Lo;0;R;;;;;N;;;;; -1E86C;MENDE KIKAKUI SYLLABLE M096 HE;Lo;0;R;;;;;N;;;;; -1E86D;MENDE KIKAKUI SYLLABLE M042 HOO;Lo;0;R;;;;;N;;;;; -1E86E;MENDE KIKAKUI SYLLABLE M140 HO;Lo;0;R;;;;;N;;;;; -1E86F;MENDE KIKAKUI SYLLABLE M083 HEEI;Lo;0;R;;;;;N;;;;; -1E870;MENDE KIKAKUI SYLLABLE M128 HOOU;Lo;0;R;;;;;N;;;;; -1E871;MENDE KIKAKUI SYLLABLE M053 HIN;Lo;0;R;;;;;N;;;;; -1E872;MENDE KIKAKUI SYLLABLE M130 HAN;Lo;0;R;;;;;N;;;;; -1E873;MENDE KIKAKUI SYLLABLE M087 HUN;Lo;0;R;;;;;N;;;;; -1E874;MENDE KIKAKUI SYLLABLE M052 HEN;Lo;0;R;;;;;N;;;;; -1E875;MENDE KIKAKUI SYLLABLE M193 HON;Lo;0;R;;;;;N;;;;; -1E876;MENDE KIKAKUI SYLLABLE M046 HUAN;Lo;0;R;;;;;N;;;;; -1E877;MENDE KIKAKUI SYLLABLE M090 NGGI;Lo;0;R;;;;;N;;;;; -1E878;MENDE KIKAKUI SYLLABLE M043 NGGA;Lo;0;R;;;;;N;;;;; -1E879;MENDE KIKAKUI SYLLABLE M082 NGGU;Lo;0;R;;;;;N;;;;; -1E87A;MENDE KIKAKUI SYLLABLE M115 NGGEE;Lo;0;R;;;;;N;;;;; -1E87B;MENDE KIKAKUI SYLLABLE M146 NGGE;Lo;0;R;;;;;N;;;;; -1E87C;MENDE KIKAKUI SYLLABLE M156 NGGOO;Lo;0;R;;;;;N;;;;; -1E87D;MENDE KIKAKUI SYLLABLE M120 NGGO;Lo;0;R;;;;;N;;;;; -1E87E;MENDE KIKAKUI SYLLABLE M159 NGGAA;Lo;0;R;;;;;N;;;;; -1E87F;MENDE KIKAKUI SYLLABLE M127 NGGUA;Lo;0;R;;;;;N;;;;; -1E880;MENDE KIKAKUI SYLLABLE M086 LONG NGGE;Lo;0;R;;;;;N;;;;; -1E881;MENDE KIKAKUI SYLLABLE M106 LONG NGGOO;Lo;0;R;;;;;N;;;;; -1E882;MENDE KIKAKUI SYLLABLE M183 LONG NGGO;Lo;0;R;;;;;N;;;;; -1E883;MENDE KIKAKUI SYLLABLE M155 GI;Lo;0;R;;;;;N;;;;; -1E884;MENDE KIKAKUI SYLLABLE M111 GA;Lo;0;R;;;;;N;;;;; -1E885;MENDE KIKAKUI SYLLABLE M168 GU;Lo;0;R;;;;;N;;;;; -1E886;MENDE KIKAKUI SYLLABLE M190 GEE;Lo;0;R;;;;;N;;;;; -1E887;MENDE KIKAKUI SYLLABLE M166 GUEI;Lo;0;R;;;;;N;;;;; -1E888;MENDE KIKAKUI SYLLABLE M167 GUAN;Lo;0;R;;;;;N;;;;; -1E889;MENDE KIKAKUI SYLLABLE M184 NGEN;Lo;0;R;;;;;N;;;;; -1E88A;MENDE KIKAKUI SYLLABLE M057 NGON;Lo;0;R;;;;;N;;;;; -1E88B;MENDE KIKAKUI SYLLABLE M177 NGUAN;Lo;0;R;;;;;N;;;;; -1E88C;MENDE KIKAKUI SYLLABLE M068 PI;Lo;0;R;;;;;N;;;;; -1E88D;MENDE KIKAKUI SYLLABLE M099 PA;Lo;0;R;;;;;N;;;;; -1E88E;MENDE KIKAKUI SYLLABLE M050 PU;Lo;0;R;;;;;N;;;;; -1E88F;MENDE KIKAKUI SYLLABLE M081 PEE;Lo;0;R;;;;;N;;;;; -1E890;MENDE KIKAKUI SYLLABLE M051 PE;Lo;0;R;;;;;N;;;;; -1E891;MENDE KIKAKUI SYLLABLE M102 POO;Lo;0;R;;;;;N;;;;; -1E892;MENDE KIKAKUI SYLLABLE M066 PO;Lo;0;R;;;;;N;;;;; -1E893;MENDE KIKAKUI SYLLABLE M145 MBI;Lo;0;R;;;;;N;;;;; -1E894;MENDE KIKAKUI SYLLABLE M062 MBA;Lo;0;R;;;;;N;;;;; -1E895;MENDE KIKAKUI SYLLABLE M122 MBU;Lo;0;R;;;;;N;;;;; -1E896;MENDE KIKAKUI SYLLABLE M047 MBEE;Lo;0;R;;;;;N;;;;; -1E897;MENDE KIKAKUI SYLLABLE M188 MBEE;Lo;0;R;;;;;N;;;;; -1E898;MENDE KIKAKUI SYLLABLE M072 MBE;Lo;0;R;;;;;N;;;;; -1E899;MENDE KIKAKUI SYLLABLE M172 MBOO;Lo;0;R;;;;;N;;;;; -1E89A;MENDE KIKAKUI SYLLABLE M174 MBO;Lo;0;R;;;;;N;;;;; -1E89B;MENDE KIKAKUI SYLLABLE M187 MBUU;Lo;0;R;;;;;N;;;;; -1E89C;MENDE KIKAKUI SYLLABLE M161 LONG MBE;Lo;0;R;;;;;N;;;;; -1E89D;MENDE KIKAKUI SYLLABLE M105 LONG MBOO;Lo;0;R;;;;;N;;;;; -1E89E;MENDE KIKAKUI SYLLABLE M142 LONG MBO;Lo;0;R;;;;;N;;;;; -1E89F;MENDE KIKAKUI SYLLABLE M132 KPI;Lo;0;R;;;;;N;;;;; -1E8A0;MENDE KIKAKUI SYLLABLE M092 KPA;Lo;0;R;;;;;N;;;;; -1E8A1;MENDE KIKAKUI SYLLABLE M074 KPU;Lo;0;R;;;;;N;;;;; -1E8A2;MENDE KIKAKUI SYLLABLE M044 KPEE;Lo;0;R;;;;;N;;;;; -1E8A3;MENDE KIKAKUI SYLLABLE M108 KPE;Lo;0;R;;;;;N;;;;; -1E8A4;MENDE KIKAKUI SYLLABLE M112 KPOO;Lo;0;R;;;;;N;;;;; -1E8A5;MENDE KIKAKUI SYLLABLE M158 KPO;Lo;0;R;;;;;N;;;;; -1E8A6;MENDE KIKAKUI SYLLABLE M124 GBI;Lo;0;R;;;;;N;;;;; -1E8A7;MENDE KIKAKUI SYLLABLE M056 GBA;Lo;0;R;;;;;N;;;;; -1E8A8;MENDE KIKAKUI SYLLABLE M148 GBU;Lo;0;R;;;;;N;;;;; -1E8A9;MENDE KIKAKUI SYLLABLE M093 GBEE;Lo;0;R;;;;;N;;;;; -1E8AA;MENDE KIKAKUI SYLLABLE M107 GBE;Lo;0;R;;;;;N;;;;; -1E8AB;MENDE KIKAKUI SYLLABLE M071 GBOO;Lo;0;R;;;;;N;;;;; -1E8AC;MENDE KIKAKUI SYLLABLE M070 GBO;Lo;0;R;;;;;N;;;;; -1E8AD;MENDE KIKAKUI SYLLABLE M171 RA;Lo;0;R;;;;;N;;;;; -1E8AE;MENDE KIKAKUI SYLLABLE M123 NDI;Lo;0;R;;;;;N;;;;; -1E8AF;MENDE KIKAKUI SYLLABLE M129 NDA;Lo;0;R;;;;;N;;;;; -1E8B0;MENDE KIKAKUI SYLLABLE M125 NDU;Lo;0;R;;;;;N;;;;; -1E8B1;MENDE KIKAKUI SYLLABLE M191 NDEE;Lo;0;R;;;;;N;;;;; -1E8B2;MENDE KIKAKUI SYLLABLE M119 NDE;Lo;0;R;;;;;N;;;;; -1E8B3;MENDE KIKAKUI SYLLABLE M067 NDOO;Lo;0;R;;;;;N;;;;; -1E8B4;MENDE KIKAKUI SYLLABLE M064 NDO;Lo;0;R;;;;;N;;;;; -1E8B5;MENDE KIKAKUI SYLLABLE M152 NJA;Lo;0;R;;;;;N;;;;; -1E8B6;MENDE KIKAKUI SYLLABLE M192 NJU;Lo;0;R;;;;;N;;;;; -1E8B7;MENDE KIKAKUI SYLLABLE M149 NJEE;Lo;0;R;;;;;N;;;;; -1E8B8;MENDE KIKAKUI SYLLABLE M134 NJOO;Lo;0;R;;;;;N;;;;; -1E8B9;MENDE KIKAKUI SYLLABLE M182 VI;Lo;0;R;;;;;N;;;;; -1E8BA;MENDE KIKAKUI SYLLABLE M185 VA;Lo;0;R;;;;;N;;;;; -1E8BB;MENDE KIKAKUI SYLLABLE M151 VU;Lo;0;R;;;;;N;;;;; -1E8BC;MENDE KIKAKUI SYLLABLE M173 VEE;Lo;0;R;;;;;N;;;;; -1E8BD;MENDE KIKAKUI SYLLABLE M085 VE;Lo;0;R;;;;;N;;;;; -1E8BE;MENDE KIKAKUI SYLLABLE M144 VOO;Lo;0;R;;;;;N;;;;; -1E8BF;MENDE KIKAKUI SYLLABLE M077 VO;Lo;0;R;;;;;N;;;;; -1E8C0;MENDE KIKAKUI SYLLABLE M164 NYIN;Lo;0;R;;;;;N;;;;; -1E8C1;MENDE KIKAKUI SYLLABLE M058 NYAN;Lo;0;R;;;;;N;;;;; -1E8C2;MENDE KIKAKUI SYLLABLE M170 NYUN;Lo;0;R;;;;;N;;;;; -1E8C3;MENDE KIKAKUI SYLLABLE M098 NYEN;Lo;0;R;;;;;N;;;;; -1E8C4;MENDE KIKAKUI SYLLABLE M060 NYON;Lo;0;R;;;;;N;;;;; -1E8C7;MENDE KIKAKUI DIGIT ONE;No;0;R;;;;1;N;;;;; -1E8C8;MENDE KIKAKUI DIGIT TWO;No;0;R;;;;2;N;;;;; -1E8C9;MENDE KIKAKUI DIGIT THREE;No;0;R;;;;3;N;;;;; -1E8CA;MENDE KIKAKUI DIGIT FOUR;No;0;R;;;;4;N;;;;; -1E8CB;MENDE KIKAKUI DIGIT FIVE;No;0;R;;;;5;N;;;;; -1E8CC;MENDE KIKAKUI DIGIT SIX;No;0;R;;;;6;N;;;;; -1E8CD;MENDE KIKAKUI DIGIT SEVEN;No;0;R;;;;7;N;;;;; -1E8CE;MENDE KIKAKUI DIGIT EIGHT;No;0;R;;;;8;N;;;;; -1E8CF;MENDE KIKAKUI DIGIT NINE;No;0;R;;;;9;N;;;;; -1E8D0;MENDE KIKAKUI COMBINING NUMBER TEENS;Mn;220;NSM;;;;;N;;;;; -1E8D1;MENDE KIKAKUI COMBINING NUMBER TENS;Mn;220;NSM;;;;;N;;;;; -1E8D2;MENDE KIKAKUI COMBINING NUMBER HUNDREDS;Mn;220;NSM;;;;;N;;;;; -1E8D3;MENDE KIKAKUI COMBINING NUMBER THOUSANDS;Mn;220;NSM;;;;;N;;;;; -1E8D4;MENDE KIKAKUI COMBINING NUMBER TEN THOUSANDS;Mn;220;NSM;;;;;N;;;;; -1E8D5;MENDE KIKAKUI COMBINING NUMBER HUNDRED THOUSANDS;Mn;220;NSM;;;;;N;;;;; -1E8D6;MENDE KIKAKUI COMBINING NUMBER MILLIONS;Mn;220;NSM;;;;;N;;;;; -1E900;ADLAM CAPITAL LETTER ALIF;Lu;0;R;;;;;N;;;;1E922; -1E901;ADLAM CAPITAL LETTER DAALI;Lu;0;R;;;;;N;;;;1E923; -1E902;ADLAM CAPITAL LETTER LAAM;Lu;0;R;;;;;N;;;;1E924; -1E903;ADLAM CAPITAL LETTER MIIM;Lu;0;R;;;;;N;;;;1E925; -1E904;ADLAM CAPITAL LETTER BA;Lu;0;R;;;;;N;;;;1E926; -1E905;ADLAM CAPITAL LETTER SINNYIIYHE;Lu;0;R;;;;;N;;;;1E927; -1E906;ADLAM CAPITAL LETTER PE;Lu;0;R;;;;;N;;;;1E928; -1E907;ADLAM CAPITAL LETTER BHE;Lu;0;R;;;;;N;;;;1E929; -1E908;ADLAM CAPITAL LETTER RA;Lu;0;R;;;;;N;;;;1E92A; -1E909;ADLAM CAPITAL LETTER E;Lu;0;R;;;;;N;;;;1E92B; -1E90A;ADLAM CAPITAL LETTER FA;Lu;0;R;;;;;N;;;;1E92C; -1E90B;ADLAM CAPITAL LETTER I;Lu;0;R;;;;;N;;;;1E92D; -1E90C;ADLAM CAPITAL LETTER O;Lu;0;R;;;;;N;;;;1E92E; -1E90D;ADLAM CAPITAL LETTER DHA;Lu;0;R;;;;;N;;;;1E92F; -1E90E;ADLAM CAPITAL LETTER YHE;Lu;0;R;;;;;N;;;;1E930; -1E90F;ADLAM CAPITAL LETTER WAW;Lu;0;R;;;;;N;;;;1E931; -1E910;ADLAM CAPITAL LETTER NUN;Lu;0;R;;;;;N;;;;1E932; -1E911;ADLAM CAPITAL LETTER KAF;Lu;0;R;;;;;N;;;;1E933; -1E912;ADLAM CAPITAL LETTER YA;Lu;0;R;;;;;N;;;;1E934; -1E913;ADLAM CAPITAL LETTER U;Lu;0;R;;;;;N;;;;1E935; -1E914;ADLAM CAPITAL LETTER JIIM;Lu;0;R;;;;;N;;;;1E936; -1E915;ADLAM CAPITAL LETTER CHI;Lu;0;R;;;;;N;;;;1E937; -1E916;ADLAM CAPITAL LETTER HA;Lu;0;R;;;;;N;;;;1E938; -1E917;ADLAM CAPITAL LETTER QAAF;Lu;0;R;;;;;N;;;;1E939; -1E918;ADLAM CAPITAL LETTER GA;Lu;0;R;;;;;N;;;;1E93A; -1E919;ADLAM CAPITAL LETTER NYA;Lu;0;R;;;;;N;;;;1E93B; -1E91A;ADLAM CAPITAL LETTER TU;Lu;0;R;;;;;N;;;;1E93C; -1E91B;ADLAM CAPITAL LETTER NHA;Lu;0;R;;;;;N;;;;1E93D; -1E91C;ADLAM CAPITAL LETTER VA;Lu;0;R;;;;;N;;;;1E93E; -1E91D;ADLAM CAPITAL LETTER KHA;Lu;0;R;;;;;N;;;;1E93F; -1E91E;ADLAM CAPITAL LETTER GBE;Lu;0;R;;;;;N;;;;1E940; -1E91F;ADLAM CAPITAL LETTER ZAL;Lu;0;R;;;;;N;;;;1E941; -1E920;ADLAM CAPITAL LETTER KPO;Lu;0;R;;;;;N;;;;1E942; -1E921;ADLAM CAPITAL LETTER SHA;Lu;0;R;;;;;N;;;;1E943; -1E922;ADLAM SMALL LETTER ALIF;Ll;0;R;;;;;N;;;1E900;;1E900 -1E923;ADLAM SMALL LETTER DAALI;Ll;0;R;;;;;N;;;1E901;;1E901 -1E924;ADLAM SMALL LETTER LAAM;Ll;0;R;;;;;N;;;1E902;;1E902 -1E925;ADLAM SMALL LETTER MIIM;Ll;0;R;;;;;N;;;1E903;;1E903 -1E926;ADLAM SMALL LETTER BA;Ll;0;R;;;;;N;;;1E904;;1E904 -1E927;ADLAM SMALL LETTER SINNYIIYHE;Ll;0;R;;;;;N;;;1E905;;1E905 -1E928;ADLAM SMALL LETTER PE;Ll;0;R;;;;;N;;;1E906;;1E906 -1E929;ADLAM SMALL LETTER BHE;Ll;0;R;;;;;N;;;1E907;;1E907 -1E92A;ADLAM SMALL LETTER RA;Ll;0;R;;;;;N;;;1E908;;1E908 -1E92B;ADLAM SMALL LETTER E;Ll;0;R;;;;;N;;;1E909;;1E909 -1E92C;ADLAM SMALL LETTER FA;Ll;0;R;;;;;N;;;1E90A;;1E90A -1E92D;ADLAM SMALL LETTER I;Ll;0;R;;;;;N;;;1E90B;;1E90B -1E92E;ADLAM SMALL LETTER O;Ll;0;R;;;;;N;;;1E90C;;1E90C -1E92F;ADLAM SMALL LETTER DHA;Ll;0;R;;;;;N;;;1E90D;;1E90D -1E930;ADLAM SMALL LETTER YHE;Ll;0;R;;;;;N;;;1E90E;;1E90E -1E931;ADLAM SMALL LETTER WAW;Ll;0;R;;;;;N;;;1E90F;;1E90F -1E932;ADLAM SMALL LETTER NUN;Ll;0;R;;;;;N;;;1E910;;1E910 -1E933;ADLAM SMALL LETTER KAF;Ll;0;R;;;;;N;;;1E911;;1E911 -1E934;ADLAM SMALL LETTER YA;Ll;0;R;;;;;N;;;1E912;;1E912 -1E935;ADLAM SMALL LETTER U;Ll;0;R;;;;;N;;;1E913;;1E913 -1E936;ADLAM SMALL LETTER JIIM;Ll;0;R;;;;;N;;;1E914;;1E914 -1E937;ADLAM SMALL LETTER CHI;Ll;0;R;;;;;N;;;1E915;;1E915 -1E938;ADLAM SMALL LETTER HA;Ll;0;R;;;;;N;;;1E916;;1E916 -1E939;ADLAM SMALL LETTER QAAF;Ll;0;R;;;;;N;;;1E917;;1E917 -1E93A;ADLAM SMALL LETTER GA;Ll;0;R;;;;;N;;;1E918;;1E918 -1E93B;ADLAM SMALL LETTER NYA;Ll;0;R;;;;;N;;;1E919;;1E919 -1E93C;ADLAM SMALL LETTER TU;Ll;0;R;;;;;N;;;1E91A;;1E91A -1E93D;ADLAM SMALL LETTER NHA;Ll;0;R;;;;;N;;;1E91B;;1E91B -1E93E;ADLAM SMALL LETTER VA;Ll;0;R;;;;;N;;;1E91C;;1E91C -1E93F;ADLAM SMALL LETTER KHA;Ll;0;R;;;;;N;;;1E91D;;1E91D -1E940;ADLAM SMALL LETTER GBE;Ll;0;R;;;;;N;;;1E91E;;1E91E -1E941;ADLAM SMALL LETTER ZAL;Ll;0;R;;;;;N;;;1E91F;;1E91F -1E942;ADLAM SMALL LETTER KPO;Ll;0;R;;;;;N;;;1E920;;1E920 -1E943;ADLAM SMALL LETTER SHA;Ll;0;R;;;;;N;;;1E921;;1E921 -1E944;ADLAM ALIF LENGTHENER;Mn;230;NSM;;;;;N;;;;; -1E945;ADLAM VOWEL LENGTHENER;Mn;230;NSM;;;;;N;;;;; -1E946;ADLAM GEMINATION MARK;Mn;230;NSM;;;;;N;;;;; -1E947;ADLAM HAMZA;Mn;230;NSM;;;;;N;;;;; -1E948;ADLAM CONSONANT MODIFIER;Mn;230;NSM;;;;;N;;;;; -1E949;ADLAM GEMINATE CONSONANT MODIFIER;Mn;230;NSM;;;;;N;;;;; -1E94A;ADLAM NUKTA;Mn;7;NSM;;;;;N;;;;; -1E94B;ADLAM NASALIZATION MARK;Lm;0;R;;;;;N;;;;; -1E950;ADLAM DIGIT ZERO;Nd;0;R;;0;0;0;N;;;;; -1E951;ADLAM DIGIT ONE;Nd;0;R;;1;1;1;N;;;;; -1E952;ADLAM DIGIT TWO;Nd;0;R;;2;2;2;N;;;;; -1E953;ADLAM DIGIT THREE;Nd;0;R;;3;3;3;N;;;;; -1E954;ADLAM DIGIT FOUR;Nd;0;R;;4;4;4;N;;;;; -1E955;ADLAM DIGIT FIVE;Nd;0;R;;5;5;5;N;;;;; -1E956;ADLAM DIGIT SIX;Nd;0;R;;6;6;6;N;;;;; -1E957;ADLAM DIGIT SEVEN;Nd;0;R;;7;7;7;N;;;;; -1E958;ADLAM DIGIT EIGHT;Nd;0;R;;8;8;8;N;;;;; -1E959;ADLAM DIGIT NINE;Nd;0;R;;9;9;9;N;;;;; -1E95E;ADLAM INITIAL EXCLAMATION MARK;Po;0;R;;;;;N;;;;; -1E95F;ADLAM INITIAL QUESTION MARK;Po;0;R;;;;;N;;;;; -1EC71;INDIC SIYAQ NUMBER ONE;No;0;AL;;;;1;N;;;;; -1EC72;INDIC SIYAQ NUMBER TWO;No;0;AL;;;;2;N;;;;; -1EC73;INDIC SIYAQ NUMBER THREE;No;0;AL;;;;3;N;;;;; -1EC74;INDIC SIYAQ NUMBER FOUR;No;0;AL;;;;4;N;;;;; -1EC75;INDIC SIYAQ NUMBER FIVE;No;0;AL;;;;5;N;;;;; -1EC76;INDIC SIYAQ NUMBER SIX;No;0;AL;;;;6;N;;;;; -1EC77;INDIC SIYAQ NUMBER SEVEN;No;0;AL;;;;7;N;;;;; -1EC78;INDIC SIYAQ NUMBER EIGHT;No;0;AL;;;;8;N;;;;; -1EC79;INDIC SIYAQ NUMBER NINE;No;0;AL;;;;9;N;;;;; -1EC7A;INDIC SIYAQ NUMBER TEN;No;0;AL;;;;10;N;;;;; -1EC7B;INDIC SIYAQ NUMBER TWENTY;No;0;AL;;;;20;N;;;;; -1EC7C;INDIC SIYAQ NUMBER THIRTY;No;0;AL;;;;30;N;;;;; -1EC7D;INDIC SIYAQ NUMBER FORTY;No;0;AL;;;;40;N;;;;; -1EC7E;INDIC SIYAQ NUMBER FIFTY;No;0;AL;;;;50;N;;;;; -1EC7F;INDIC SIYAQ NUMBER SIXTY;No;0;AL;;;;60;N;;;;; -1EC80;INDIC SIYAQ NUMBER SEVENTY;No;0;AL;;;;70;N;;;;; -1EC81;INDIC SIYAQ NUMBER EIGHTY;No;0;AL;;;;80;N;;;;; -1EC82;INDIC SIYAQ NUMBER NINETY;No;0;AL;;;;90;N;;;;; -1EC83;INDIC SIYAQ NUMBER ONE HUNDRED;No;0;AL;;;;100;N;;;;; -1EC84;INDIC SIYAQ NUMBER TWO HUNDRED;No;0;AL;;;;200;N;;;;; -1EC85;INDIC SIYAQ NUMBER THREE HUNDRED;No;0;AL;;;;300;N;;;;; -1EC86;INDIC SIYAQ NUMBER FOUR HUNDRED;No;0;AL;;;;400;N;;;;; -1EC87;INDIC SIYAQ NUMBER FIVE HUNDRED;No;0;AL;;;;500;N;;;;; -1EC88;INDIC SIYAQ NUMBER SIX HUNDRED;No;0;AL;;;;600;N;;;;; -1EC89;INDIC SIYAQ NUMBER SEVEN HUNDRED;No;0;AL;;;;700;N;;;;; -1EC8A;INDIC SIYAQ NUMBER EIGHT HUNDRED;No;0;AL;;;;800;N;;;;; -1EC8B;INDIC SIYAQ NUMBER NINE HUNDRED;No;0;AL;;;;900;N;;;;; -1EC8C;INDIC SIYAQ NUMBER ONE THOUSAND;No;0;AL;;;;1000;N;;;;; -1EC8D;INDIC SIYAQ NUMBER TWO THOUSAND;No;0;AL;;;;2000;N;;;;; -1EC8E;INDIC SIYAQ NUMBER THREE THOUSAND;No;0;AL;;;;3000;N;;;;; -1EC8F;INDIC SIYAQ NUMBER FOUR THOUSAND;No;0;AL;;;;4000;N;;;;; -1EC90;INDIC SIYAQ NUMBER FIVE THOUSAND;No;0;AL;;;;5000;N;;;;; -1EC91;INDIC SIYAQ NUMBER SIX THOUSAND;No;0;AL;;;;6000;N;;;;; -1EC92;INDIC SIYAQ NUMBER SEVEN THOUSAND;No;0;AL;;;;7000;N;;;;; -1EC93;INDIC SIYAQ NUMBER EIGHT THOUSAND;No;0;AL;;;;8000;N;;;;; -1EC94;INDIC SIYAQ NUMBER NINE THOUSAND;No;0;AL;;;;9000;N;;;;; -1EC95;INDIC SIYAQ NUMBER TEN THOUSAND;No;0;AL;;;;10000;N;;;;; -1EC96;INDIC SIYAQ NUMBER TWENTY THOUSAND;No;0;AL;;;;20000;N;;;;; -1EC97;INDIC SIYAQ NUMBER THIRTY THOUSAND;No;0;AL;;;;30000;N;;;;; -1EC98;INDIC SIYAQ NUMBER FORTY THOUSAND;No;0;AL;;;;40000;N;;;;; -1EC99;INDIC SIYAQ NUMBER FIFTY THOUSAND;No;0;AL;;;;50000;N;;;;; -1EC9A;INDIC SIYAQ NUMBER SIXTY THOUSAND;No;0;AL;;;;60000;N;;;;; -1EC9B;INDIC SIYAQ NUMBER SEVENTY THOUSAND;No;0;AL;;;;70000;N;;;;; -1EC9C;INDIC SIYAQ NUMBER EIGHTY THOUSAND;No;0;AL;;;;80000;N;;;;; -1EC9D;INDIC SIYAQ NUMBER NINETY THOUSAND;No;0;AL;;;;90000;N;;;;; -1EC9E;INDIC SIYAQ NUMBER LAKH;No;0;AL;;;;100000;N;;;;; -1EC9F;INDIC SIYAQ NUMBER LAKHAN;No;0;AL;;;;200000;N;;;;; -1ECA0;INDIC SIYAQ LAKH MARK;No;0;AL;;;;100000;N;;;;; -1ECA1;INDIC SIYAQ NUMBER KAROR;No;0;AL;;;;10000000;N;;;;; -1ECA2;INDIC SIYAQ NUMBER KARORAN;No;0;AL;;;;20000000;N;;;;; -1ECA3;INDIC SIYAQ NUMBER PREFIXED ONE;No;0;AL;;;;1;N;;;;; -1ECA4;INDIC SIYAQ NUMBER PREFIXED TWO;No;0;AL;;;;2;N;;;;; -1ECA5;INDIC SIYAQ NUMBER PREFIXED THREE;No;0;AL;;;;3;N;;;;; -1ECA6;INDIC SIYAQ NUMBER PREFIXED FOUR;No;0;AL;;;;4;N;;;;; -1ECA7;INDIC SIYAQ NUMBER PREFIXED FIVE;No;0;AL;;;;5;N;;;;; -1ECA8;INDIC SIYAQ NUMBER PREFIXED SIX;No;0;AL;;;;6;N;;;;; -1ECA9;INDIC SIYAQ NUMBER PREFIXED SEVEN;No;0;AL;;;;7;N;;;;; -1ECAA;INDIC SIYAQ NUMBER PREFIXED EIGHT;No;0;AL;;;;8;N;;;;; -1ECAB;INDIC SIYAQ NUMBER PREFIXED NINE;No;0;AL;;;;9;N;;;;; -1ECAC;INDIC SIYAQ PLACEHOLDER;So;0;AL;;;;;N;;;;; -1ECAD;INDIC SIYAQ FRACTION ONE QUARTER;No;0;AL;;;;1/4;N;;;;; -1ECAE;INDIC SIYAQ FRACTION ONE HALF;No;0;AL;;;;1/2;N;;;;; -1ECAF;INDIC SIYAQ FRACTION THREE QUARTERS;No;0;AL;;;;3/4;N;;;;; -1ECB0;INDIC SIYAQ RUPEE MARK;Sc;0;AL;;;;;N;;;;; -1ECB1;INDIC SIYAQ NUMBER ALTERNATE ONE;No;0;AL;;;;1;N;;;;; -1ECB2;INDIC SIYAQ NUMBER ALTERNATE TWO;No;0;AL;;;;2;N;;;;; -1ECB3;INDIC SIYAQ NUMBER ALTERNATE TEN THOUSAND;No;0;AL;;;;10000;N;;;;; -1ECB4;INDIC SIYAQ ALTERNATE LAKH MARK;No;0;AL;;;;100000;N;;;;; -1ED01;OTTOMAN SIYAQ NUMBER ONE;No;0;AL;;;;1;N;;;;; -1ED02;OTTOMAN SIYAQ NUMBER TWO;No;0;AL;;;;2;N;;;;; -1ED03;OTTOMAN SIYAQ NUMBER THREE;No;0;AL;;;;3;N;;;;; -1ED04;OTTOMAN SIYAQ NUMBER FOUR;No;0;AL;;;;4;N;;;;; -1ED05;OTTOMAN SIYAQ NUMBER FIVE;No;0;AL;;;;5;N;;;;; -1ED06;OTTOMAN SIYAQ NUMBER SIX;No;0;AL;;;;6;N;;;;; -1ED07;OTTOMAN SIYAQ NUMBER SEVEN;No;0;AL;;;;7;N;;;;; -1ED08;OTTOMAN SIYAQ NUMBER EIGHT;No;0;AL;;;;8;N;;;;; -1ED09;OTTOMAN SIYAQ NUMBER NINE;No;0;AL;;;;9;N;;;;; -1ED0A;OTTOMAN SIYAQ NUMBER TEN;No;0;AL;;;;10;N;;;;; -1ED0B;OTTOMAN SIYAQ NUMBER TWENTY;No;0;AL;;;;20;N;;;;; -1ED0C;OTTOMAN SIYAQ NUMBER THIRTY;No;0;AL;;;;30;N;;;;; -1ED0D;OTTOMAN SIYAQ NUMBER FORTY;No;0;AL;;;;40;N;;;;; -1ED0E;OTTOMAN SIYAQ NUMBER FIFTY;No;0;AL;;;;50;N;;;;; -1ED0F;OTTOMAN SIYAQ NUMBER SIXTY;No;0;AL;;;;60;N;;;;; -1ED10;OTTOMAN SIYAQ NUMBER SEVENTY;No;0;AL;;;;70;N;;;;; -1ED11;OTTOMAN SIYAQ NUMBER EIGHTY;No;0;AL;;;;80;N;;;;; -1ED12;OTTOMAN SIYAQ NUMBER NINETY;No;0;AL;;;;90;N;;;;; -1ED13;OTTOMAN SIYAQ NUMBER ONE HUNDRED;No;0;AL;;;;100;N;;;;; -1ED14;OTTOMAN SIYAQ NUMBER TWO HUNDRED;No;0;AL;;;;200;N;;;;; -1ED15;OTTOMAN SIYAQ NUMBER THREE HUNDRED;No;0;AL;;;;300;N;;;;; -1ED16;OTTOMAN SIYAQ NUMBER FOUR HUNDRED;No;0;AL;;;;400;N;;;;; -1ED17;OTTOMAN SIYAQ NUMBER FIVE HUNDRED;No;0;AL;;;;500;N;;;;; -1ED18;OTTOMAN SIYAQ NUMBER SIX HUNDRED;No;0;AL;;;;600;N;;;;; -1ED19;OTTOMAN SIYAQ NUMBER SEVEN HUNDRED;No;0;AL;;;;700;N;;;;; -1ED1A;OTTOMAN SIYAQ NUMBER EIGHT HUNDRED;No;0;AL;;;;800;N;;;;; -1ED1B;OTTOMAN SIYAQ NUMBER NINE HUNDRED;No;0;AL;;;;900;N;;;;; -1ED1C;OTTOMAN SIYAQ NUMBER ONE THOUSAND;No;0;AL;;;;1000;N;;;;; -1ED1D;OTTOMAN SIYAQ NUMBER TWO THOUSAND;No;0;AL;;;;2000;N;;;;; -1ED1E;OTTOMAN SIYAQ NUMBER THREE THOUSAND;No;0;AL;;;;3000;N;;;;; -1ED1F;OTTOMAN SIYAQ NUMBER FOUR THOUSAND;No;0;AL;;;;4000;N;;;;; -1ED20;OTTOMAN SIYAQ NUMBER FIVE THOUSAND;No;0;AL;;;;5000;N;;;;; -1ED21;OTTOMAN SIYAQ NUMBER SIX THOUSAND;No;0;AL;;;;6000;N;;;;; -1ED22;OTTOMAN SIYAQ NUMBER SEVEN THOUSAND;No;0;AL;;;;7000;N;;;;; -1ED23;OTTOMAN SIYAQ NUMBER EIGHT THOUSAND;No;0;AL;;;;8000;N;;;;; -1ED24;OTTOMAN SIYAQ NUMBER NINE THOUSAND;No;0;AL;;;;9000;N;;;;; -1ED25;OTTOMAN SIYAQ NUMBER TEN THOUSAND;No;0;AL;;;;10000;N;;;;; -1ED26;OTTOMAN SIYAQ NUMBER TWENTY THOUSAND;No;0;AL;;;;20000;N;;;;; -1ED27;OTTOMAN SIYAQ NUMBER THIRTY THOUSAND;No;0;AL;;;;30000;N;;;;; -1ED28;OTTOMAN SIYAQ NUMBER FORTY THOUSAND;No;0;AL;;;;40000;N;;;;; -1ED29;OTTOMAN SIYAQ NUMBER FIFTY THOUSAND;No;0;AL;;;;50000;N;;;;; -1ED2A;OTTOMAN SIYAQ NUMBER SIXTY THOUSAND;No;0;AL;;;;60000;N;;;;; -1ED2B;OTTOMAN SIYAQ NUMBER SEVENTY THOUSAND;No;0;AL;;;;70000;N;;;;; -1ED2C;OTTOMAN SIYAQ NUMBER EIGHTY THOUSAND;No;0;AL;;;;80000;N;;;;; -1ED2D;OTTOMAN SIYAQ NUMBER NINETY THOUSAND;No;0;AL;;;;90000;N;;;;; -1ED2E;OTTOMAN SIYAQ MARRATAN;So;0;AL;;;;;N;;;;; -1ED2F;OTTOMAN SIYAQ ALTERNATE NUMBER TWO;No;0;AL;;;;2;N;;;;; -1ED30;OTTOMAN SIYAQ ALTERNATE NUMBER THREE;No;0;AL;;;;3;N;;;;; -1ED31;OTTOMAN SIYAQ ALTERNATE NUMBER FOUR;No;0;AL;;;;4;N;;;;; -1ED32;OTTOMAN SIYAQ ALTERNATE NUMBER FIVE;No;0;AL;;;;5;N;;;;; -1ED33;OTTOMAN SIYAQ ALTERNATE NUMBER SIX;No;0;AL;;;;6;N;;;;; -1ED34;OTTOMAN SIYAQ ALTERNATE NUMBER SEVEN;No;0;AL;;;;7;N;;;;; -1ED35;OTTOMAN SIYAQ ALTERNATE NUMBER EIGHT;No;0;AL;;;;8;N;;;;; -1ED36;OTTOMAN SIYAQ ALTERNATE NUMBER NINE;No;0;AL;;;;9;N;;;;; -1ED37;OTTOMAN SIYAQ ALTERNATE NUMBER TEN;No;0;AL;;;;10;N;;;;; -1ED38;OTTOMAN SIYAQ ALTERNATE NUMBER FOUR HUNDRED;No;0;AL;;;;400;N;;;;; -1ED39;OTTOMAN SIYAQ ALTERNATE NUMBER SIX HUNDRED;No;0;AL;;;;600;N;;;;; -1ED3A;OTTOMAN SIYAQ ALTERNATE NUMBER TWO THOUSAND;No;0;AL;;;;2000;N;;;;; -1ED3B;OTTOMAN SIYAQ ALTERNATE NUMBER TEN THOUSAND;No;0;AL;;;;10000;N;;;;; -1ED3C;OTTOMAN SIYAQ FRACTION ONE HALF;No;0;AL;;;;1/2;N;;;;; -1ED3D;OTTOMAN SIYAQ FRACTION ONE SIXTH;No;0;AL;;;;1/6;N;;;;; -1EE00;ARABIC MATHEMATICAL ALEF;Lo;0;AL;<font> 0627;;;;N;;;;; -1EE01;ARABIC MATHEMATICAL BEH;Lo;0;AL;<font> 0628;;;;N;;;;; -1EE02;ARABIC MATHEMATICAL JEEM;Lo;0;AL;<font> 062C;;;;N;;;;; -1EE03;ARABIC MATHEMATICAL DAL;Lo;0;AL;<font> 062F;;;;N;;;;; -1EE05;ARABIC MATHEMATICAL WAW;Lo;0;AL;<font> 0648;;;;N;;;;; -1EE06;ARABIC MATHEMATICAL ZAIN;Lo;0;AL;<font> 0632;;;;N;;;;; -1EE07;ARABIC MATHEMATICAL HAH;Lo;0;AL;<font> 062D;;;;N;;;;; -1EE08;ARABIC MATHEMATICAL TAH;Lo;0;AL;<font> 0637;;;;N;;;;; -1EE09;ARABIC MATHEMATICAL YEH;Lo;0;AL;<font> 064A;;;;N;;;;; -1EE0A;ARABIC MATHEMATICAL KAF;Lo;0;AL;<font> 0643;;;;N;;;;; -1EE0B;ARABIC MATHEMATICAL LAM;Lo;0;AL;<font> 0644;;;;N;;;;; -1EE0C;ARABIC MATHEMATICAL MEEM;Lo;0;AL;<font> 0645;;;;N;;;;; -1EE0D;ARABIC MATHEMATICAL NOON;Lo;0;AL;<font> 0646;;;;N;;;;; -1EE0E;ARABIC MATHEMATICAL SEEN;Lo;0;AL;<font> 0633;;;;N;;;;; -1EE0F;ARABIC MATHEMATICAL AIN;Lo;0;AL;<font> 0639;;;;N;;;;; -1EE10;ARABIC MATHEMATICAL FEH;Lo;0;AL;<font> 0641;;;;N;;;;; -1EE11;ARABIC MATHEMATICAL SAD;Lo;0;AL;<font> 0635;;;;N;;;;; -1EE12;ARABIC MATHEMATICAL QAF;Lo;0;AL;<font> 0642;;;;N;;;;; -1EE13;ARABIC MATHEMATICAL REH;Lo;0;AL;<font> 0631;;;;N;;;;; -1EE14;ARABIC MATHEMATICAL SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;; -1EE15;ARABIC MATHEMATICAL TEH;Lo;0;AL;<font> 062A;;;;N;;;;; -1EE16;ARABIC MATHEMATICAL THEH;Lo;0;AL;<font> 062B;;;;N;;;;; -1EE17;ARABIC MATHEMATICAL KHAH;Lo;0;AL;<font> 062E;;;;N;;;;; -1EE18;ARABIC MATHEMATICAL THAL;Lo;0;AL;<font> 0630;;;;N;;;;; -1EE19;ARABIC MATHEMATICAL DAD;Lo;0;AL;<font> 0636;;;;N;;;;; -1EE1A;ARABIC MATHEMATICAL ZAH;Lo;0;AL;<font> 0638;;;;N;;;;; -1EE1B;ARABIC MATHEMATICAL GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;; -1EE1C;ARABIC MATHEMATICAL DOTLESS BEH;Lo;0;AL;<font> 066E;;;;N;;;;; -1EE1D;ARABIC MATHEMATICAL DOTLESS NOON;Lo;0;AL;<font> 06BA;;;;N;;;;; -1EE1E;ARABIC MATHEMATICAL DOTLESS FEH;Lo;0;AL;<font> 06A1;;;;N;;;;; -1EE1F;ARABIC MATHEMATICAL DOTLESS QAF;Lo;0;AL;<font> 066F;;;;N;;;;; -1EE21;ARABIC MATHEMATICAL INITIAL BEH;Lo;0;AL;<font> 0628;;;;N;;;;; -1EE22;ARABIC MATHEMATICAL INITIAL JEEM;Lo;0;AL;<font> 062C;;;;N;;;;; -1EE24;ARABIC MATHEMATICAL INITIAL HEH;Lo;0;AL;<font> 0647;;;;N;;;;; -1EE27;ARABIC MATHEMATICAL INITIAL HAH;Lo;0;AL;<font> 062D;;;;N;;;;; -1EE29;ARABIC MATHEMATICAL INITIAL YEH;Lo;0;AL;<font> 064A;;;;N;;;;; -1EE2A;ARABIC MATHEMATICAL INITIAL KAF;Lo;0;AL;<font> 0643;;;;N;;;;; -1EE2B;ARABIC MATHEMATICAL INITIAL LAM;Lo;0;AL;<font> 0644;;;;N;;;;; -1EE2C;ARABIC MATHEMATICAL INITIAL MEEM;Lo;0;AL;<font> 0645;;;;N;;;;; -1EE2D;ARABIC MATHEMATICAL INITIAL NOON;Lo;0;AL;<font> 0646;;;;N;;;;; -1EE2E;ARABIC MATHEMATICAL INITIAL SEEN;Lo;0;AL;<font> 0633;;;;N;;;;; -1EE2F;ARABIC MATHEMATICAL INITIAL AIN;Lo;0;AL;<font> 0639;;;;N;;;;; -1EE30;ARABIC MATHEMATICAL INITIAL FEH;Lo;0;AL;<font> 0641;;;;N;;;;; -1EE31;ARABIC MATHEMATICAL INITIAL SAD;Lo;0;AL;<font> 0635;;;;N;;;;; -1EE32;ARABIC MATHEMATICAL INITIAL QAF;Lo;0;AL;<font> 0642;;;;N;;;;; -1EE34;ARABIC MATHEMATICAL INITIAL SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;; -1EE35;ARABIC MATHEMATICAL INITIAL TEH;Lo;0;AL;<font> 062A;;;;N;;;;; -1EE36;ARABIC MATHEMATICAL INITIAL THEH;Lo;0;AL;<font> 062B;;;;N;;;;; -1EE37;ARABIC MATHEMATICAL INITIAL KHAH;Lo;0;AL;<font> 062E;;;;N;;;;; -1EE39;ARABIC MATHEMATICAL INITIAL DAD;Lo;0;AL;<font> 0636;;;;N;;;;; -1EE3B;ARABIC MATHEMATICAL INITIAL GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;; -1EE42;ARABIC MATHEMATICAL TAILED JEEM;Lo;0;AL;<font> 062C;;;;N;;;;; -1EE47;ARABIC MATHEMATICAL TAILED HAH;Lo;0;AL;<font> 062D;;;;N;;;;; -1EE49;ARABIC MATHEMATICAL TAILED YEH;Lo;0;AL;<font> 064A;;;;N;;;;; -1EE4B;ARABIC MATHEMATICAL TAILED LAM;Lo;0;AL;<font> 0644;;;;N;;;;; -1EE4D;ARABIC MATHEMATICAL TAILED NOON;Lo;0;AL;<font> 0646;;;;N;;;;; -1EE4E;ARABIC MATHEMATICAL TAILED SEEN;Lo;0;AL;<font> 0633;;;;N;;;;; -1EE4F;ARABIC MATHEMATICAL TAILED AIN;Lo;0;AL;<font> 0639;;;;N;;;;; -1EE51;ARABIC MATHEMATICAL TAILED SAD;Lo;0;AL;<font> 0635;;;;N;;;;; -1EE52;ARABIC MATHEMATICAL TAILED QAF;Lo;0;AL;<font> 0642;;;;N;;;;; -1EE54;ARABIC MATHEMATICAL TAILED SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;; -1EE57;ARABIC MATHEMATICAL TAILED KHAH;Lo;0;AL;<font> 062E;;;;N;;;;; -1EE59;ARABIC MATHEMATICAL TAILED DAD;Lo;0;AL;<font> 0636;;;;N;;;;; -1EE5B;ARABIC MATHEMATICAL TAILED GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;; -1EE5D;ARABIC MATHEMATICAL TAILED DOTLESS NOON;Lo;0;AL;<font> 06BA;;;;N;;;;; -1EE5F;ARABIC MATHEMATICAL TAILED DOTLESS QAF;Lo;0;AL;<font> 066F;;;;N;;;;; -1EE61;ARABIC MATHEMATICAL STRETCHED BEH;Lo;0;AL;<font> 0628;;;;N;;;;; -1EE62;ARABIC MATHEMATICAL STRETCHED JEEM;Lo;0;AL;<font> 062C;;;;N;;;;; -1EE64;ARABIC MATHEMATICAL STRETCHED HEH;Lo;0;AL;<font> 0647;;;;N;;;;; -1EE67;ARABIC MATHEMATICAL STRETCHED HAH;Lo;0;AL;<font> 062D;;;;N;;;;; -1EE68;ARABIC MATHEMATICAL STRETCHED TAH;Lo;0;AL;<font> 0637;;;;N;;;;; -1EE69;ARABIC MATHEMATICAL STRETCHED YEH;Lo;0;AL;<font> 064A;;;;N;;;;; -1EE6A;ARABIC MATHEMATICAL STRETCHED KAF;Lo;0;AL;<font> 0643;;;;N;;;;; -1EE6C;ARABIC MATHEMATICAL STRETCHED MEEM;Lo;0;AL;<font> 0645;;;;N;;;;; -1EE6D;ARABIC MATHEMATICAL STRETCHED NOON;Lo;0;AL;<font> 0646;;;;N;;;;; -1EE6E;ARABIC MATHEMATICAL STRETCHED SEEN;Lo;0;AL;<font> 0633;;;;N;;;;; -1EE6F;ARABIC MATHEMATICAL STRETCHED AIN;Lo;0;AL;<font> 0639;;;;N;;;;; -1EE70;ARABIC MATHEMATICAL STRETCHED FEH;Lo;0;AL;<font> 0641;;;;N;;;;; -1EE71;ARABIC MATHEMATICAL STRETCHED SAD;Lo;0;AL;<font> 0635;;;;N;;;;; -1EE72;ARABIC MATHEMATICAL STRETCHED QAF;Lo;0;AL;<font> 0642;;;;N;;;;; -1EE74;ARABIC MATHEMATICAL STRETCHED SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;; -1EE75;ARABIC MATHEMATICAL STRETCHED TEH;Lo;0;AL;<font> 062A;;;;N;;;;; -1EE76;ARABIC MATHEMATICAL STRETCHED THEH;Lo;0;AL;<font> 062B;;;;N;;;;; -1EE77;ARABIC MATHEMATICAL STRETCHED KHAH;Lo;0;AL;<font> 062E;;;;N;;;;; -1EE79;ARABIC MATHEMATICAL STRETCHED DAD;Lo;0;AL;<font> 0636;;;;N;;;;; -1EE7A;ARABIC MATHEMATICAL STRETCHED ZAH;Lo;0;AL;<font> 0638;;;;N;;;;; -1EE7B;ARABIC MATHEMATICAL STRETCHED GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;; -1EE7C;ARABIC MATHEMATICAL STRETCHED DOTLESS BEH;Lo;0;AL;<font> 066E;;;;N;;;;; -1EE7E;ARABIC MATHEMATICAL STRETCHED DOTLESS FEH;Lo;0;AL;<font> 06A1;;;;N;;;;; -1EE80;ARABIC MATHEMATICAL LOOPED ALEF;Lo;0;AL;<font> 0627;;;;N;;;;; -1EE81;ARABIC MATHEMATICAL LOOPED BEH;Lo;0;AL;<font> 0628;;;;N;;;;; -1EE82;ARABIC MATHEMATICAL LOOPED JEEM;Lo;0;AL;<font> 062C;;;;N;;;;; -1EE83;ARABIC MATHEMATICAL LOOPED DAL;Lo;0;AL;<font> 062F;;;;N;;;;; -1EE84;ARABIC MATHEMATICAL LOOPED HEH;Lo;0;AL;<font> 0647;;;;N;;;;; -1EE85;ARABIC MATHEMATICAL LOOPED WAW;Lo;0;AL;<font> 0648;;;;N;;;;; -1EE86;ARABIC MATHEMATICAL LOOPED ZAIN;Lo;0;AL;<font> 0632;;;;N;;;;; -1EE87;ARABIC MATHEMATICAL LOOPED HAH;Lo;0;AL;<font> 062D;;;;N;;;;; -1EE88;ARABIC MATHEMATICAL LOOPED TAH;Lo;0;AL;<font> 0637;;;;N;;;;; -1EE89;ARABIC MATHEMATICAL LOOPED YEH;Lo;0;AL;<font> 064A;;;;N;;;;; -1EE8B;ARABIC MATHEMATICAL LOOPED LAM;Lo;0;AL;<font> 0644;;;;N;;;;; -1EE8C;ARABIC MATHEMATICAL LOOPED MEEM;Lo;0;AL;<font> 0645;;;;N;;;;; -1EE8D;ARABIC MATHEMATICAL LOOPED NOON;Lo;0;AL;<font> 0646;;;;N;;;;; -1EE8E;ARABIC MATHEMATICAL LOOPED SEEN;Lo;0;AL;<font> 0633;;;;N;;;;; -1EE8F;ARABIC MATHEMATICAL LOOPED AIN;Lo;0;AL;<font> 0639;;;;N;;;;; -1EE90;ARABIC MATHEMATICAL LOOPED FEH;Lo;0;AL;<font> 0641;;;;N;;;;; -1EE91;ARABIC MATHEMATICAL LOOPED SAD;Lo;0;AL;<font> 0635;;;;N;;;;; -1EE92;ARABIC MATHEMATICAL LOOPED QAF;Lo;0;AL;<font> 0642;;;;N;;;;; -1EE93;ARABIC MATHEMATICAL LOOPED REH;Lo;0;AL;<font> 0631;;;;N;;;;; -1EE94;ARABIC MATHEMATICAL LOOPED SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;; -1EE95;ARABIC MATHEMATICAL LOOPED TEH;Lo;0;AL;<font> 062A;;;;N;;;;; -1EE96;ARABIC MATHEMATICAL LOOPED THEH;Lo;0;AL;<font> 062B;;;;N;;;;; -1EE97;ARABIC MATHEMATICAL LOOPED KHAH;Lo;0;AL;<font> 062E;;;;N;;;;; -1EE98;ARABIC MATHEMATICAL LOOPED THAL;Lo;0;AL;<font> 0630;;;;N;;;;; -1EE99;ARABIC MATHEMATICAL LOOPED DAD;Lo;0;AL;<font> 0636;;;;N;;;;; -1EE9A;ARABIC MATHEMATICAL LOOPED ZAH;Lo;0;AL;<font> 0638;;;;N;;;;; -1EE9B;ARABIC MATHEMATICAL LOOPED GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;; -1EEA1;ARABIC MATHEMATICAL DOUBLE-STRUCK BEH;Lo;0;AL;<font> 0628;;;;N;;;;; -1EEA2;ARABIC MATHEMATICAL DOUBLE-STRUCK JEEM;Lo;0;AL;<font> 062C;;;;N;;;;; -1EEA3;ARABIC MATHEMATICAL DOUBLE-STRUCK DAL;Lo;0;AL;<font> 062F;;;;N;;;;; -1EEA5;ARABIC MATHEMATICAL DOUBLE-STRUCK WAW;Lo;0;AL;<font> 0648;;;;N;;;;; -1EEA6;ARABIC MATHEMATICAL DOUBLE-STRUCK ZAIN;Lo;0;AL;<font> 0632;;;;N;;;;; -1EEA7;ARABIC MATHEMATICAL DOUBLE-STRUCK HAH;Lo;0;AL;<font> 062D;;;;N;;;;; -1EEA8;ARABIC MATHEMATICAL DOUBLE-STRUCK TAH;Lo;0;AL;<font> 0637;;;;N;;;;; -1EEA9;ARABIC MATHEMATICAL DOUBLE-STRUCK YEH;Lo;0;AL;<font> 064A;;;;N;;;;; -1EEAB;ARABIC MATHEMATICAL DOUBLE-STRUCK LAM;Lo;0;AL;<font> 0644;;;;N;;;;; -1EEAC;ARABIC MATHEMATICAL DOUBLE-STRUCK MEEM;Lo;0;AL;<font> 0645;;;;N;;;;; -1EEAD;ARABIC MATHEMATICAL DOUBLE-STRUCK NOON;Lo;0;AL;<font> 0646;;;;N;;;;; -1EEAE;ARABIC MATHEMATICAL DOUBLE-STRUCK SEEN;Lo;0;AL;<font> 0633;;;;N;;;;; -1EEAF;ARABIC MATHEMATICAL DOUBLE-STRUCK AIN;Lo;0;AL;<font> 0639;;;;N;;;;; -1EEB0;ARABIC MATHEMATICAL DOUBLE-STRUCK FEH;Lo;0;AL;<font> 0641;;;;N;;;;; -1EEB1;ARABIC MATHEMATICAL DOUBLE-STRUCK SAD;Lo;0;AL;<font> 0635;;;;N;;;;; -1EEB2;ARABIC MATHEMATICAL DOUBLE-STRUCK QAF;Lo;0;AL;<font> 0642;;;;N;;;;; -1EEB3;ARABIC MATHEMATICAL DOUBLE-STRUCK REH;Lo;0;AL;<font> 0631;;;;N;;;;; -1EEB4;ARABIC MATHEMATICAL DOUBLE-STRUCK SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;; -1EEB5;ARABIC MATHEMATICAL DOUBLE-STRUCK TEH;Lo;0;AL;<font> 062A;;;;N;;;;; -1EEB6;ARABIC MATHEMATICAL DOUBLE-STRUCK THEH;Lo;0;AL;<font> 062B;;;;N;;;;; -1EEB7;ARABIC MATHEMATICAL DOUBLE-STRUCK KHAH;Lo;0;AL;<font> 062E;;;;N;;;;; -1EEB8;ARABIC MATHEMATICAL DOUBLE-STRUCK THAL;Lo;0;AL;<font> 0630;;;;N;;;;; -1EEB9;ARABIC MATHEMATICAL DOUBLE-STRUCK DAD;Lo;0;AL;<font> 0636;;;;N;;;;; -1EEBA;ARABIC MATHEMATICAL DOUBLE-STRUCK ZAH;Lo;0;AL;<font> 0638;;;;N;;;;; -1EEBB;ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;; -1EEF0;ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL;Sm;0;ON;;;;;N;;;;; -1EEF1;ARABIC MATHEMATICAL OPERATOR HAH WITH DAL;Sm;0;ON;;;;;N;;;;; -1F000;MAHJONG TILE EAST WIND;So;0;ON;;;;;N;;;;; -1F001;MAHJONG TILE SOUTH WIND;So;0;ON;;;;;N;;;;; -1F002;MAHJONG TILE WEST WIND;So;0;ON;;;;;N;;;;; -1F003;MAHJONG TILE NORTH WIND;So;0;ON;;;;;N;;;;; -1F004;MAHJONG TILE RED DRAGON;So;0;ON;;;;;N;;;;; -1F005;MAHJONG TILE GREEN DRAGON;So;0;ON;;;;;N;;;;; -1F006;MAHJONG TILE WHITE DRAGON;So;0;ON;;;;;N;;;;; -1F007;MAHJONG TILE ONE OF CHARACTERS;So;0;ON;;;;;N;;;;; -1F008;MAHJONG TILE TWO OF CHARACTERS;So;0;ON;;;;;N;;;;; -1F009;MAHJONG TILE THREE OF CHARACTERS;So;0;ON;;;;;N;;;;; -1F00A;MAHJONG TILE FOUR OF CHARACTERS;So;0;ON;;;;;N;;;;; -1F00B;MAHJONG TILE FIVE OF CHARACTERS;So;0;ON;;;;;N;;;;; -1F00C;MAHJONG TILE SIX OF CHARACTERS;So;0;ON;;;;;N;;;;; -1F00D;MAHJONG TILE SEVEN OF CHARACTERS;So;0;ON;;;;;N;;;;; -1F00E;MAHJONG TILE EIGHT OF CHARACTERS;So;0;ON;;;;;N;;;;; -1F00F;MAHJONG TILE NINE OF CHARACTERS;So;0;ON;;;;;N;;;;; -1F010;MAHJONG TILE ONE OF BAMBOOS;So;0;ON;;;;;N;;;;; -1F011;MAHJONG TILE TWO OF BAMBOOS;So;0;ON;;;;;N;;;;; -1F012;MAHJONG TILE THREE OF BAMBOOS;So;0;ON;;;;;N;;;;; -1F013;MAHJONG TILE FOUR OF BAMBOOS;So;0;ON;;;;;N;;;;; -1F014;MAHJONG TILE FIVE OF BAMBOOS;So;0;ON;;;;;N;;;;; -1F015;MAHJONG TILE SIX OF BAMBOOS;So;0;ON;;;;;N;;;;; -1F016;MAHJONG TILE SEVEN OF BAMBOOS;So;0;ON;;;;;N;;;;; -1F017;MAHJONG TILE EIGHT OF BAMBOOS;So;0;ON;;;;;N;;;;; -1F018;MAHJONG TILE NINE OF BAMBOOS;So;0;ON;;;;;N;;;;; -1F019;MAHJONG TILE ONE OF CIRCLES;So;0;ON;;;;;N;;;;; -1F01A;MAHJONG TILE TWO OF CIRCLES;So;0;ON;;;;;N;;;;; -1F01B;MAHJONG TILE THREE OF CIRCLES;So;0;ON;;;;;N;;;;; -1F01C;MAHJONG TILE FOUR OF CIRCLES;So;0;ON;;;;;N;;;;; -1F01D;MAHJONG TILE FIVE OF CIRCLES;So;0;ON;;;;;N;;;;; -1F01E;MAHJONG TILE SIX OF CIRCLES;So;0;ON;;;;;N;;;;; -1F01F;MAHJONG TILE SEVEN OF CIRCLES;So;0;ON;;;;;N;;;;; -1F020;MAHJONG TILE EIGHT OF CIRCLES;So;0;ON;;;;;N;;;;; -1F021;MAHJONG TILE NINE OF CIRCLES;So;0;ON;;;;;N;;;;; -1F022;MAHJONG TILE PLUM;So;0;ON;;;;;N;;;;; -1F023;MAHJONG TILE ORCHID;So;0;ON;;;;;N;;;;; -1F024;MAHJONG TILE BAMBOO;So;0;ON;;;;;N;;;;; -1F025;MAHJONG TILE CHRYSANTHEMUM;So;0;ON;;;;;N;;;;; -1F026;MAHJONG TILE SPRING;So;0;ON;;;;;N;;;;; -1F027;MAHJONG TILE SUMMER;So;0;ON;;;;;N;;;;; -1F028;MAHJONG TILE AUTUMN;So;0;ON;;;;;N;;;;; -1F029;MAHJONG TILE WINTER;So;0;ON;;;;;N;;;;; -1F02A;MAHJONG TILE JOKER;So;0;ON;;;;;N;;;;; -1F02B;MAHJONG TILE BACK;So;0;ON;;;;;N;;;;; -1F030;DOMINO TILE HORIZONTAL BACK;So;0;ON;;;;;N;;;;; -1F031;DOMINO TILE HORIZONTAL-00-00;So;0;ON;;;;;N;;;;; -1F032;DOMINO TILE HORIZONTAL-00-01;So;0;ON;;;;;N;;;;; -1F033;DOMINO TILE HORIZONTAL-00-02;So;0;ON;;;;;N;;;;; -1F034;DOMINO TILE HORIZONTAL-00-03;So;0;ON;;;;;N;;;;; -1F035;DOMINO TILE HORIZONTAL-00-04;So;0;ON;;;;;N;;;;; -1F036;DOMINO TILE HORIZONTAL-00-05;So;0;ON;;;;;N;;;;; -1F037;DOMINO TILE HORIZONTAL-00-06;So;0;ON;;;;;N;;;;; -1F038;DOMINO TILE HORIZONTAL-01-00;So;0;ON;;;;;N;;;;; -1F039;DOMINO TILE HORIZONTAL-01-01;So;0;ON;;;;;N;;;;; -1F03A;DOMINO TILE HORIZONTAL-01-02;So;0;ON;;;;;N;;;;; -1F03B;DOMINO TILE HORIZONTAL-01-03;So;0;ON;;;;;N;;;;; -1F03C;DOMINO TILE HORIZONTAL-01-04;So;0;ON;;;;;N;;;;; -1F03D;DOMINO TILE HORIZONTAL-01-05;So;0;ON;;;;;N;;;;; -1F03E;DOMINO TILE HORIZONTAL-01-06;So;0;ON;;;;;N;;;;; -1F03F;DOMINO TILE HORIZONTAL-02-00;So;0;ON;;;;;N;;;;; -1F040;DOMINO TILE HORIZONTAL-02-01;So;0;ON;;;;;N;;;;; -1F041;DOMINO TILE HORIZONTAL-02-02;So;0;ON;;;;;N;;;;; -1F042;DOMINO TILE HORIZONTAL-02-03;So;0;ON;;;;;N;;;;; -1F043;DOMINO TILE HORIZONTAL-02-04;So;0;ON;;;;;N;;;;; -1F044;DOMINO TILE HORIZONTAL-02-05;So;0;ON;;;;;N;;;;; -1F045;DOMINO TILE HORIZONTAL-02-06;So;0;ON;;;;;N;;;;; -1F046;DOMINO TILE HORIZONTAL-03-00;So;0;ON;;;;;N;;;;; -1F047;DOMINO TILE HORIZONTAL-03-01;So;0;ON;;;;;N;;;;; -1F048;DOMINO TILE HORIZONTAL-03-02;So;0;ON;;;;;N;;;;; -1F049;DOMINO TILE HORIZONTAL-03-03;So;0;ON;;;;;N;;;;; -1F04A;DOMINO TILE HORIZONTAL-03-04;So;0;ON;;;;;N;;;;; -1F04B;DOMINO TILE HORIZONTAL-03-05;So;0;ON;;;;;N;;;;; -1F04C;DOMINO TILE HORIZONTAL-03-06;So;0;ON;;;;;N;;;;; -1F04D;DOMINO TILE HORIZONTAL-04-00;So;0;ON;;;;;N;;;;; -1F04E;DOMINO TILE HORIZONTAL-04-01;So;0;ON;;;;;N;;;;; -1F04F;DOMINO TILE HORIZONTAL-04-02;So;0;ON;;;;;N;;;;; -1F050;DOMINO TILE HORIZONTAL-04-03;So;0;ON;;;;;N;;;;; -1F051;DOMINO TILE HORIZONTAL-04-04;So;0;ON;;;;;N;;;;; -1F052;DOMINO TILE HORIZONTAL-04-05;So;0;ON;;;;;N;;;;; -1F053;DOMINO TILE HORIZONTAL-04-06;So;0;ON;;;;;N;;;;; -1F054;DOMINO TILE HORIZONTAL-05-00;So;0;ON;;;;;N;;;;; -1F055;DOMINO TILE HORIZONTAL-05-01;So;0;ON;;;;;N;;;;; -1F056;DOMINO TILE HORIZONTAL-05-02;So;0;ON;;;;;N;;;;; -1F057;DOMINO TILE HORIZONTAL-05-03;So;0;ON;;;;;N;;;;; -1F058;DOMINO TILE HORIZONTAL-05-04;So;0;ON;;;;;N;;;;; -1F059;DOMINO TILE HORIZONTAL-05-05;So;0;ON;;;;;N;;;;; -1F05A;DOMINO TILE HORIZONTAL-05-06;So;0;ON;;;;;N;;;;; -1F05B;DOMINO TILE HORIZONTAL-06-00;So;0;ON;;;;;N;;;;; -1F05C;DOMINO TILE HORIZONTAL-06-01;So;0;ON;;;;;N;;;;; -1F05D;DOMINO TILE HORIZONTAL-06-02;So;0;ON;;;;;N;;;;; -1F05E;DOMINO TILE HORIZONTAL-06-03;So;0;ON;;;;;N;;;;; -1F05F;DOMINO TILE HORIZONTAL-06-04;So;0;ON;;;;;N;;;;; -1F060;DOMINO TILE HORIZONTAL-06-05;So;0;ON;;;;;N;;;;; -1F061;DOMINO TILE HORIZONTAL-06-06;So;0;ON;;;;;N;;;;; -1F062;DOMINO TILE VERTICAL BACK;So;0;ON;;;;;N;;;;; -1F063;DOMINO TILE VERTICAL-00-00;So;0;ON;;;;;N;;;;; -1F064;DOMINO TILE VERTICAL-00-01;So;0;ON;;;;;N;;;;; -1F065;DOMINO TILE VERTICAL-00-02;So;0;ON;;;;;N;;;;; -1F066;DOMINO TILE VERTICAL-00-03;So;0;ON;;;;;N;;;;; -1F067;DOMINO TILE VERTICAL-00-04;So;0;ON;;;;;N;;;;; -1F068;DOMINO TILE VERTICAL-00-05;So;0;ON;;;;;N;;;;; -1F069;DOMINO TILE VERTICAL-00-06;So;0;ON;;;;;N;;;;; -1F06A;DOMINO TILE VERTICAL-01-00;So;0;ON;;;;;N;;;;; -1F06B;DOMINO TILE VERTICAL-01-01;So;0;ON;;;;;N;;;;; -1F06C;DOMINO TILE VERTICAL-01-02;So;0;ON;;;;;N;;;;; -1F06D;DOMINO TILE VERTICAL-01-03;So;0;ON;;;;;N;;;;; -1F06E;DOMINO TILE VERTICAL-01-04;So;0;ON;;;;;N;;;;; -1F06F;DOMINO TILE VERTICAL-01-05;So;0;ON;;;;;N;;;;; -1F070;DOMINO TILE VERTICAL-01-06;So;0;ON;;;;;N;;;;; -1F071;DOMINO TILE VERTICAL-02-00;So;0;ON;;;;;N;;;;; -1F072;DOMINO TILE VERTICAL-02-01;So;0;ON;;;;;N;;;;; -1F073;DOMINO TILE VERTICAL-02-02;So;0;ON;;;;;N;;;;; -1F074;DOMINO TILE VERTICAL-02-03;So;0;ON;;;;;N;;;;; -1F075;DOMINO TILE VERTICAL-02-04;So;0;ON;;;;;N;;;;; -1F076;DOMINO TILE VERTICAL-02-05;So;0;ON;;;;;N;;;;; -1F077;DOMINO TILE VERTICAL-02-06;So;0;ON;;;;;N;;;;; -1F078;DOMINO TILE VERTICAL-03-00;So;0;ON;;;;;N;;;;; -1F079;DOMINO TILE VERTICAL-03-01;So;0;ON;;;;;N;;;;; -1F07A;DOMINO TILE VERTICAL-03-02;So;0;ON;;;;;N;;;;; -1F07B;DOMINO TILE VERTICAL-03-03;So;0;ON;;;;;N;;;;; -1F07C;DOMINO TILE VERTICAL-03-04;So;0;ON;;;;;N;;;;; -1F07D;DOMINO TILE VERTICAL-03-05;So;0;ON;;;;;N;;;;; -1F07E;DOMINO TILE VERTICAL-03-06;So;0;ON;;;;;N;;;;; -1F07F;DOMINO TILE VERTICAL-04-00;So;0;ON;;;;;N;;;;; -1F080;DOMINO TILE VERTICAL-04-01;So;0;ON;;;;;N;;;;; -1F081;DOMINO TILE VERTICAL-04-02;So;0;ON;;;;;N;;;;; -1F082;DOMINO TILE VERTICAL-04-03;So;0;ON;;;;;N;;;;; -1F083;DOMINO TILE VERTICAL-04-04;So;0;ON;;;;;N;;;;; -1F084;DOMINO TILE VERTICAL-04-05;So;0;ON;;;;;N;;;;; -1F085;DOMINO TILE VERTICAL-04-06;So;0;ON;;;;;N;;;;; -1F086;DOMINO TILE VERTICAL-05-00;So;0;ON;;;;;N;;;;; -1F087;DOMINO TILE VERTICAL-05-01;So;0;ON;;;;;N;;;;; -1F088;DOMINO TILE VERTICAL-05-02;So;0;ON;;;;;N;;;;; -1F089;DOMINO TILE VERTICAL-05-03;So;0;ON;;;;;N;;;;; -1F08A;DOMINO TILE VERTICAL-05-04;So;0;ON;;;;;N;;;;; -1F08B;DOMINO TILE VERTICAL-05-05;So;0;ON;;;;;N;;;;; -1F08C;DOMINO TILE VERTICAL-05-06;So;0;ON;;;;;N;;;;; -1F08D;DOMINO TILE VERTICAL-06-00;So;0;ON;;;;;N;;;;; -1F08E;DOMINO TILE VERTICAL-06-01;So;0;ON;;;;;N;;;;; -1F08F;DOMINO TILE VERTICAL-06-02;So;0;ON;;;;;N;;;;; -1F090;DOMINO TILE VERTICAL-06-03;So;0;ON;;;;;N;;;;; -1F091;DOMINO TILE VERTICAL-06-04;So;0;ON;;;;;N;;;;; -1F092;DOMINO TILE VERTICAL-06-05;So;0;ON;;;;;N;;;;; -1F093;DOMINO TILE VERTICAL-06-06;So;0;ON;;;;;N;;;;; -1F0A0;PLAYING CARD BACK;So;0;ON;;;;;N;;;;; -1F0A1;PLAYING CARD ACE OF SPADES;So;0;ON;;;;;N;;;;; -1F0A2;PLAYING CARD TWO OF SPADES;So;0;ON;;;;;N;;;;; -1F0A3;PLAYING CARD THREE OF SPADES;So;0;ON;;;;;N;;;;; -1F0A4;PLAYING CARD FOUR OF SPADES;So;0;ON;;;;;N;;;;; -1F0A5;PLAYING CARD FIVE OF SPADES;So;0;ON;;;;;N;;;;; -1F0A6;PLAYING CARD SIX OF SPADES;So;0;ON;;;;;N;;;;; -1F0A7;PLAYING CARD SEVEN OF SPADES;So;0;ON;;;;;N;;;;; -1F0A8;PLAYING CARD EIGHT OF SPADES;So;0;ON;;;;;N;;;;; -1F0A9;PLAYING CARD NINE OF SPADES;So;0;ON;;;;;N;;;;; -1F0AA;PLAYING CARD TEN OF SPADES;So;0;ON;;;;;N;;;;; -1F0AB;PLAYING CARD JACK OF SPADES;So;0;ON;;;;;N;;;;; -1F0AC;PLAYING CARD KNIGHT OF SPADES;So;0;ON;;;;;N;;;;; -1F0AD;PLAYING CARD QUEEN OF SPADES;So;0;ON;;;;;N;;;;; -1F0AE;PLAYING CARD KING OF SPADES;So;0;ON;;;;;N;;;;; -1F0B1;PLAYING CARD ACE OF HEARTS;So;0;ON;;;;;N;;;;; -1F0B2;PLAYING CARD TWO OF HEARTS;So;0;ON;;;;;N;;;;; -1F0B3;PLAYING CARD THREE OF HEARTS;So;0;ON;;;;;N;;;;; -1F0B4;PLAYING CARD FOUR OF HEARTS;So;0;ON;;;;;N;;;;; -1F0B5;PLAYING CARD FIVE OF HEARTS;So;0;ON;;;;;N;;;;; -1F0B6;PLAYING CARD SIX OF HEARTS;So;0;ON;;;;;N;;;;; -1F0B7;PLAYING CARD SEVEN OF HEARTS;So;0;ON;;;;;N;;;;; -1F0B8;PLAYING CARD EIGHT OF HEARTS;So;0;ON;;;;;N;;;;; -1F0B9;PLAYING CARD NINE OF HEARTS;So;0;ON;;;;;N;;;;; -1F0BA;PLAYING CARD TEN OF HEARTS;So;0;ON;;;;;N;;;;; -1F0BB;PLAYING CARD JACK OF HEARTS;So;0;ON;;;;;N;;;;; -1F0BC;PLAYING CARD KNIGHT OF HEARTS;So;0;ON;;;;;N;;;;; -1F0BD;PLAYING CARD QUEEN OF HEARTS;So;0;ON;;;;;N;;;;; -1F0BE;PLAYING CARD KING OF HEARTS;So;0;ON;;;;;N;;;;; -1F0BF;PLAYING CARD RED JOKER;So;0;ON;;;;;N;;;;; -1F0C1;PLAYING CARD ACE OF DIAMONDS;So;0;ON;;;;;N;;;;; -1F0C2;PLAYING CARD TWO OF DIAMONDS;So;0;ON;;;;;N;;;;; -1F0C3;PLAYING CARD THREE OF DIAMONDS;So;0;ON;;;;;N;;;;; -1F0C4;PLAYING CARD FOUR OF DIAMONDS;So;0;ON;;;;;N;;;;; -1F0C5;PLAYING CARD FIVE OF DIAMONDS;So;0;ON;;;;;N;;;;; -1F0C6;PLAYING CARD SIX OF DIAMONDS;So;0;ON;;;;;N;;;;; -1F0C7;PLAYING CARD SEVEN OF DIAMONDS;So;0;ON;;;;;N;;;;; -1F0C8;PLAYING CARD EIGHT OF DIAMONDS;So;0;ON;;;;;N;;;;; -1F0C9;PLAYING CARD NINE OF DIAMONDS;So;0;ON;;;;;N;;;;; -1F0CA;PLAYING CARD TEN OF DIAMONDS;So;0;ON;;;;;N;;;;; -1F0CB;PLAYING CARD JACK OF DIAMONDS;So;0;ON;;;;;N;;;;; -1F0CC;PLAYING CARD KNIGHT OF DIAMONDS;So;0;ON;;;;;N;;;;; -1F0CD;PLAYING CARD QUEEN OF DIAMONDS;So;0;ON;;;;;N;;;;; -1F0CE;PLAYING CARD KING OF DIAMONDS;So;0;ON;;;;;N;;;;; -1F0CF;PLAYING CARD BLACK JOKER;So;0;ON;;;;;N;;;;; -1F0D1;PLAYING CARD ACE OF CLUBS;So;0;ON;;;;;N;;;;; -1F0D2;PLAYING CARD TWO OF CLUBS;So;0;ON;;;;;N;;;;; -1F0D3;PLAYING CARD THREE OF CLUBS;So;0;ON;;;;;N;;;;; -1F0D4;PLAYING CARD FOUR OF CLUBS;So;0;ON;;;;;N;;;;; -1F0D5;PLAYING CARD FIVE OF CLUBS;So;0;ON;;;;;N;;;;; -1F0D6;PLAYING CARD SIX OF CLUBS;So;0;ON;;;;;N;;;;; -1F0D7;PLAYING CARD SEVEN OF CLUBS;So;0;ON;;;;;N;;;;; -1F0D8;PLAYING CARD EIGHT OF CLUBS;So;0;ON;;;;;N;;;;; -1F0D9;PLAYING CARD NINE OF CLUBS;So;0;ON;;;;;N;;;;; -1F0DA;PLAYING CARD TEN OF CLUBS;So;0;ON;;;;;N;;;;; -1F0DB;PLAYING CARD JACK OF CLUBS;So;0;ON;;;;;N;;;;; -1F0DC;PLAYING CARD KNIGHT OF CLUBS;So;0;ON;;;;;N;;;;; -1F0DD;PLAYING CARD QUEEN OF CLUBS;So;0;ON;;;;;N;;;;; -1F0DE;PLAYING CARD KING OF CLUBS;So;0;ON;;;;;N;;;;; -1F0DF;PLAYING CARD WHITE JOKER;So;0;ON;;;;;N;;;;; -1F0E0;PLAYING CARD FOOL;So;0;ON;;;;;N;;;;; -1F0E1;PLAYING CARD TRUMP-1;So;0;ON;;;;;N;;;;; -1F0E2;PLAYING CARD TRUMP-2;So;0;ON;;;;;N;;;;; -1F0E3;PLAYING CARD TRUMP-3;So;0;ON;;;;;N;;;;; -1F0E4;PLAYING CARD TRUMP-4;So;0;ON;;;;;N;;;;; -1F0E5;PLAYING CARD TRUMP-5;So;0;ON;;;;;N;;;;; -1F0E6;PLAYING CARD TRUMP-6;So;0;ON;;;;;N;;;;; -1F0E7;PLAYING CARD TRUMP-7;So;0;ON;;;;;N;;;;; -1F0E8;PLAYING CARD TRUMP-8;So;0;ON;;;;;N;;;;; -1F0E9;PLAYING CARD TRUMP-9;So;0;ON;;;;;N;;;;; -1F0EA;PLAYING CARD TRUMP-10;So;0;ON;;;;;N;;;;; -1F0EB;PLAYING CARD TRUMP-11;So;0;ON;;;;;N;;;;; -1F0EC;PLAYING CARD TRUMP-12;So;0;ON;;;;;N;;;;; -1F0ED;PLAYING CARD TRUMP-13;So;0;ON;;;;;N;;;;; -1F0EE;PLAYING CARD TRUMP-14;So;0;ON;;;;;N;;;;; -1F0EF;PLAYING CARD TRUMP-15;So;0;ON;;;;;N;;;;; -1F0F0;PLAYING CARD TRUMP-16;So;0;ON;;;;;N;;;;; -1F0F1;PLAYING CARD TRUMP-17;So;0;ON;;;;;N;;;;; -1F0F2;PLAYING CARD TRUMP-18;So;0;ON;;;;;N;;;;; -1F0F3;PLAYING CARD TRUMP-19;So;0;ON;;;;;N;;;;; -1F0F4;PLAYING CARD TRUMP-20;So;0;ON;;;;;N;;;;; -1F0F5;PLAYING CARD TRUMP-21;So;0;ON;;;;;N;;;;; -1F100;DIGIT ZERO FULL STOP;No;0;EN;<compat> 0030 002E;;0;0;N;;;;; -1F101;DIGIT ZERO COMMA;No;0;EN;<compat> 0030 002C;;0;0;N;;;;; -1F102;DIGIT ONE COMMA;No;0;EN;<compat> 0031 002C;;1;1;N;;;;; -1F103;DIGIT TWO COMMA;No;0;EN;<compat> 0032 002C;;2;2;N;;;;; -1F104;DIGIT THREE COMMA;No;0;EN;<compat> 0033 002C;;3;3;N;;;;; -1F105;DIGIT FOUR COMMA;No;0;EN;<compat> 0034 002C;;4;4;N;;;;; -1F106;DIGIT FIVE COMMA;No;0;EN;<compat> 0035 002C;;5;5;N;;;;; -1F107;DIGIT SIX COMMA;No;0;EN;<compat> 0036 002C;;6;6;N;;;;; -1F108;DIGIT SEVEN COMMA;No;0;EN;<compat> 0037 002C;;7;7;N;;;;; -1F109;DIGIT EIGHT COMMA;No;0;EN;<compat> 0038 002C;;8;8;N;;;;; -1F10A;DIGIT NINE COMMA;No;0;EN;<compat> 0039 002C;;9;9;N;;;;; -1F10B;DINGBAT CIRCLED SANS-SERIF DIGIT ZERO;No;0;ON;;;;0;N;;;;; -1F10C;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO;No;0;ON;;;;0;N;;;;; -1F10D;CIRCLED ZERO WITH SLASH;So;0;ON;;;;;N;;;;; -1F10E;CIRCLED ANTICLOCKWISE ARROW;So;0;ON;;;;;N;;;;; -1F10F;CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH;So;0;ON;;;;;N;;;;; -1F110;PARENTHESIZED LATIN CAPITAL LETTER A;So;0;L;<compat> 0028 0041 0029;;;;N;;;;; -1F111;PARENTHESIZED LATIN CAPITAL LETTER B;So;0;L;<compat> 0028 0042 0029;;;;N;;;;; -1F112;PARENTHESIZED LATIN CAPITAL LETTER C;So;0;L;<compat> 0028 0043 0029;;;;N;;;;; -1F113;PARENTHESIZED LATIN CAPITAL LETTER D;So;0;L;<compat> 0028 0044 0029;;;;N;;;;; -1F114;PARENTHESIZED LATIN CAPITAL LETTER E;So;0;L;<compat> 0028 0045 0029;;;;N;;;;; -1F115;PARENTHESIZED LATIN CAPITAL LETTER F;So;0;L;<compat> 0028 0046 0029;;;;N;;;;; -1F116;PARENTHESIZED LATIN CAPITAL LETTER G;So;0;L;<compat> 0028 0047 0029;;;;N;;;;; -1F117;PARENTHESIZED LATIN CAPITAL LETTER H;So;0;L;<compat> 0028 0048 0029;;;;N;;;;; -1F118;PARENTHESIZED LATIN CAPITAL LETTER I;So;0;L;<compat> 0028 0049 0029;;;;N;;;;; -1F119;PARENTHESIZED LATIN CAPITAL LETTER J;So;0;L;<compat> 0028 004A 0029;;;;N;;;;; -1F11A;PARENTHESIZED LATIN CAPITAL LETTER K;So;0;L;<compat> 0028 004B 0029;;;;N;;;;; -1F11B;PARENTHESIZED LATIN CAPITAL LETTER L;So;0;L;<compat> 0028 004C 0029;;;;N;;;;; -1F11C;PARENTHESIZED LATIN CAPITAL LETTER M;So;0;L;<compat> 0028 004D 0029;;;;N;;;;; -1F11D;PARENTHESIZED LATIN CAPITAL LETTER N;So;0;L;<compat> 0028 004E 0029;;;;N;;;;; -1F11E;PARENTHESIZED LATIN CAPITAL LETTER O;So;0;L;<compat> 0028 004F 0029;;;;N;;;;; -1F11F;PARENTHESIZED LATIN CAPITAL LETTER P;So;0;L;<compat> 0028 0050 0029;;;;N;;;;; -1F120;PARENTHESIZED LATIN CAPITAL LETTER Q;So;0;L;<compat> 0028 0051 0029;;;;N;;;;; -1F121;PARENTHESIZED LATIN CAPITAL LETTER R;So;0;L;<compat> 0028 0052 0029;;;;N;;;;; -1F122;PARENTHESIZED LATIN CAPITAL LETTER S;So;0;L;<compat> 0028 0053 0029;;;;N;;;;; -1F123;PARENTHESIZED LATIN CAPITAL LETTER T;So;0;L;<compat> 0028 0054 0029;;;;N;;;;; -1F124;PARENTHESIZED LATIN CAPITAL LETTER U;So;0;L;<compat> 0028 0055 0029;;;;N;;;;; -1F125;PARENTHESIZED LATIN CAPITAL LETTER V;So;0;L;<compat> 0028 0056 0029;;;;N;;;;; -1F126;PARENTHESIZED LATIN CAPITAL LETTER W;So;0;L;<compat> 0028 0057 0029;;;;N;;;;; -1F127;PARENTHESIZED LATIN CAPITAL LETTER X;So;0;L;<compat> 0028 0058 0029;;;;N;;;;; -1F128;PARENTHESIZED LATIN CAPITAL LETTER Y;So;0;L;<compat> 0028 0059 0029;;;;N;;;;; -1F129;PARENTHESIZED LATIN CAPITAL LETTER Z;So;0;L;<compat> 0028 005A 0029;;;;N;;;;; -1F12A;TORTOISE SHELL BRACKETED LATIN CAPITAL LETTER S;So;0;L;<compat> 3014 0053 3015;;;;N;;;;; -1F12B;CIRCLED ITALIC LATIN CAPITAL LETTER C;So;0;L;<circle> 0043;;;;N;;;;; -1F12C;CIRCLED ITALIC LATIN CAPITAL LETTER R;So;0;L;<circle> 0052;;;;N;;;;; -1F12D;CIRCLED CD;So;0;L;<circle> 0043 0044;;;;N;;;;; -1F12E;CIRCLED WZ;So;0;L;<circle> 0057 005A;;;;N;;;;; -1F12F;COPYLEFT SYMBOL;So;0;ON;;;;;N;;;;; -1F130;SQUARED LATIN CAPITAL LETTER A;So;0;L;<square> 0041;;;;N;;;;; -1F131;SQUARED LATIN CAPITAL LETTER B;So;0;L;<square> 0042;;;;N;;;;; -1F132;SQUARED LATIN CAPITAL LETTER C;So;0;L;<square> 0043;;;;N;;;;; -1F133;SQUARED LATIN CAPITAL LETTER D;So;0;L;<square> 0044;;;;N;;;;; -1F134;SQUARED LATIN CAPITAL LETTER E;So;0;L;<square> 0045;;;;N;;;;; -1F135;SQUARED LATIN CAPITAL LETTER F;So;0;L;<square> 0046;;;;N;;;;; -1F136;SQUARED LATIN CAPITAL LETTER G;So;0;L;<square> 0047;;;;N;;;;; -1F137;SQUARED LATIN CAPITAL LETTER H;So;0;L;<square> 0048;;;;N;;;;; -1F138;SQUARED LATIN CAPITAL LETTER I;So;0;L;<square> 0049;;;;N;;;;; -1F139;SQUARED LATIN CAPITAL LETTER J;So;0;L;<square> 004A;;;;N;;;;; -1F13A;SQUARED LATIN CAPITAL LETTER K;So;0;L;<square> 004B;;;;N;;;;; -1F13B;SQUARED LATIN CAPITAL LETTER L;So;0;L;<square> 004C;;;;N;;;;; -1F13C;SQUARED LATIN CAPITAL LETTER M;So;0;L;<square> 004D;;;;N;;;;; -1F13D;SQUARED LATIN CAPITAL LETTER N;So;0;L;<square> 004E;;;;N;;;;; -1F13E;SQUARED LATIN CAPITAL LETTER O;So;0;L;<square> 004F;;;;N;;;;; -1F13F;SQUARED LATIN CAPITAL LETTER P;So;0;L;<square> 0050;;;;N;;;;; -1F140;SQUARED LATIN CAPITAL LETTER Q;So;0;L;<square> 0051;;;;N;;;;; -1F141;SQUARED LATIN CAPITAL LETTER R;So;0;L;<square> 0052;;;;N;;;;; -1F142;SQUARED LATIN CAPITAL LETTER S;So;0;L;<square> 0053;;;;N;;;;; -1F143;SQUARED LATIN CAPITAL LETTER T;So;0;L;<square> 0054;;;;N;;;;; -1F144;SQUARED LATIN CAPITAL LETTER U;So;0;L;<square> 0055;;;;N;;;;; -1F145;SQUARED LATIN CAPITAL LETTER V;So;0;L;<square> 0056;;;;N;;;;; -1F146;SQUARED LATIN CAPITAL LETTER W;So;0;L;<square> 0057;;;;N;;;;; -1F147;SQUARED LATIN CAPITAL LETTER X;So;0;L;<square> 0058;;;;N;;;;; -1F148;SQUARED LATIN CAPITAL LETTER Y;So;0;L;<square> 0059;;;;N;;;;; -1F149;SQUARED LATIN CAPITAL LETTER Z;So;0;L;<square> 005A;;;;N;;;;; -1F14A;SQUARED HV;So;0;L;<square> 0048 0056;;;;N;;;;; -1F14B;SQUARED MV;So;0;L;<square> 004D 0056;;;;N;;;;; -1F14C;SQUARED SD;So;0;L;<square> 0053 0044;;;;N;;;;; -1F14D;SQUARED SS;So;0;L;<square> 0053 0053;;;;N;;;;; -1F14E;SQUARED PPV;So;0;L;<square> 0050 0050 0056;;;;N;;;;; -1F14F;SQUARED WC;So;0;L;<square> 0057 0043;;;;N;;;;; -1F150;NEGATIVE CIRCLED LATIN CAPITAL LETTER A;So;0;L;;;;;N;;;;; -1F151;NEGATIVE CIRCLED LATIN CAPITAL LETTER B;So;0;L;;;;;N;;;;; -1F152;NEGATIVE CIRCLED LATIN CAPITAL LETTER C;So;0;L;;;;;N;;;;; -1F153;NEGATIVE CIRCLED LATIN CAPITAL LETTER D;So;0;L;;;;;N;;;;; -1F154;NEGATIVE CIRCLED LATIN CAPITAL LETTER E;So;0;L;;;;;N;;;;; -1F155;NEGATIVE CIRCLED LATIN CAPITAL LETTER F;So;0;L;;;;;N;;;;; -1F156;NEGATIVE CIRCLED LATIN CAPITAL LETTER G;So;0;L;;;;;N;;;;; -1F157;NEGATIVE CIRCLED LATIN CAPITAL LETTER H;So;0;L;;;;;N;;;;; -1F158;NEGATIVE CIRCLED LATIN CAPITAL LETTER I;So;0;L;;;;;N;;;;; -1F159;NEGATIVE CIRCLED LATIN CAPITAL LETTER J;So;0;L;;;;;N;;;;; -1F15A;NEGATIVE CIRCLED LATIN CAPITAL LETTER K;So;0;L;;;;;N;;;;; -1F15B;NEGATIVE CIRCLED LATIN CAPITAL LETTER L;So;0;L;;;;;N;;;;; -1F15C;NEGATIVE CIRCLED LATIN CAPITAL LETTER M;So;0;L;;;;;N;;;;; -1F15D;NEGATIVE CIRCLED LATIN CAPITAL LETTER N;So;0;L;;;;;N;;;;; -1F15E;NEGATIVE CIRCLED LATIN CAPITAL LETTER O;So;0;L;;;;;N;;;;; -1F15F;NEGATIVE CIRCLED LATIN CAPITAL LETTER P;So;0;L;;;;;N;;;;; -1F160;NEGATIVE CIRCLED LATIN CAPITAL LETTER Q;So;0;L;;;;;N;;;;; -1F161;NEGATIVE CIRCLED LATIN CAPITAL LETTER R;So;0;L;;;;;N;;;;; -1F162;NEGATIVE CIRCLED LATIN CAPITAL LETTER S;So;0;L;;;;;N;;;;; -1F163;NEGATIVE CIRCLED LATIN CAPITAL LETTER T;So;0;L;;;;;N;;;;; -1F164;NEGATIVE CIRCLED LATIN CAPITAL LETTER U;So;0;L;;;;;N;;;;; -1F165;NEGATIVE CIRCLED LATIN CAPITAL LETTER V;So;0;L;;;;;N;;;;; -1F166;NEGATIVE CIRCLED LATIN CAPITAL LETTER W;So;0;L;;;;;N;;;;; -1F167;NEGATIVE CIRCLED LATIN CAPITAL LETTER X;So;0;L;;;;;N;;;;; -1F168;NEGATIVE CIRCLED LATIN CAPITAL LETTER Y;So;0;L;;;;;N;;;;; -1F169;NEGATIVE CIRCLED LATIN CAPITAL LETTER Z;So;0;L;;;;;N;;;;; -1F16A;RAISED MC SIGN;So;0;ON;<super> 004D 0043;;;;N;;;;; -1F16B;RAISED MD SIGN;So;0;ON;<super> 004D 0044;;;;N;;;;; -1F16C;RAISED MR SIGN;So;0;ON;<super> 004D 0052;;;;N;;;;; -1F16D;CIRCLED CC;So;0;ON;;;;;N;;;;; -1F16E;CIRCLED C WITH OVERLAID BACKSLASH;So;0;ON;;;;;N;;;;; -1F16F;CIRCLED HUMAN FIGURE;So;0;ON;;;;;N;;;;; -1F170;NEGATIVE SQUARED LATIN CAPITAL LETTER A;So;0;L;;;;;N;;;;; -1F171;NEGATIVE SQUARED LATIN CAPITAL LETTER B;So;0;L;;;;;N;;;;; -1F172;NEGATIVE SQUARED LATIN CAPITAL LETTER C;So;0;L;;;;;N;;;;; -1F173;NEGATIVE SQUARED LATIN CAPITAL LETTER D;So;0;L;;;;;N;;;;; -1F174;NEGATIVE SQUARED LATIN CAPITAL LETTER E;So;0;L;;;;;N;;;;; -1F175;NEGATIVE SQUARED LATIN CAPITAL LETTER F;So;0;L;;;;;N;;;;; -1F176;NEGATIVE SQUARED LATIN CAPITAL LETTER G;So;0;L;;;;;N;;;;; -1F177;NEGATIVE SQUARED LATIN CAPITAL LETTER H;So;0;L;;;;;N;;;;; -1F178;NEGATIVE SQUARED LATIN CAPITAL LETTER I;So;0;L;;;;;N;;;;; -1F179;NEGATIVE SQUARED LATIN CAPITAL LETTER J;So;0;L;;;;;N;;;;; -1F17A;NEGATIVE SQUARED LATIN CAPITAL LETTER K;So;0;L;;;;;N;;;;; -1F17B;NEGATIVE SQUARED LATIN CAPITAL LETTER L;So;0;L;;;;;N;;;;; -1F17C;NEGATIVE SQUARED LATIN CAPITAL LETTER M;So;0;L;;;;;N;;;;; -1F17D;NEGATIVE SQUARED LATIN CAPITAL LETTER N;So;0;L;;;;;N;;;;; -1F17E;NEGATIVE SQUARED LATIN CAPITAL LETTER O;So;0;L;;;;;N;;;;; -1F17F;NEGATIVE SQUARED LATIN CAPITAL LETTER P;So;0;L;;;;;N;;;;; -1F180;NEGATIVE SQUARED LATIN CAPITAL LETTER Q;So;0;L;;;;;N;;;;; -1F181;NEGATIVE SQUARED LATIN CAPITAL LETTER R;So;0;L;;;;;N;;;;; -1F182;NEGATIVE SQUARED LATIN CAPITAL LETTER S;So;0;L;;;;;N;;;;; -1F183;NEGATIVE SQUARED LATIN CAPITAL LETTER T;So;0;L;;;;;N;;;;; -1F184;NEGATIVE SQUARED LATIN CAPITAL LETTER U;So;0;L;;;;;N;;;;; -1F185;NEGATIVE SQUARED LATIN CAPITAL LETTER V;So;0;L;;;;;N;;;;; -1F186;NEGATIVE SQUARED LATIN CAPITAL LETTER W;So;0;L;;;;;N;;;;; -1F187;NEGATIVE SQUARED LATIN CAPITAL LETTER X;So;0;L;;;;;N;;;;; -1F188;NEGATIVE SQUARED LATIN CAPITAL LETTER Y;So;0;L;;;;;N;;;;; -1F189;NEGATIVE SQUARED LATIN CAPITAL LETTER Z;So;0;L;;;;;N;;;;; -1F18A;CROSSED NEGATIVE SQUARED LATIN CAPITAL LETTER P;So;0;L;;;;;N;;;;; -1F18B;NEGATIVE SQUARED IC;So;0;L;;;;;N;;;;; -1F18C;NEGATIVE SQUARED PA;So;0;L;;;;;N;;;;; -1F18D;NEGATIVE SQUARED SA;So;0;L;;;;;N;;;;; -1F18E;NEGATIVE SQUARED AB;So;0;L;;;;;N;;;;; -1F18F;NEGATIVE SQUARED WC;So;0;L;;;;;N;;;;; -1F190;SQUARE DJ;So;0;L;<square> 0044 004A;;;;N;;;;; -1F191;SQUARED CL;So;0;L;;;;;N;;;;; -1F192;SQUARED COOL;So;0;L;;;;;N;;;;; -1F193;SQUARED FREE;So;0;L;;;;;N;;;;; -1F194;SQUARED ID;So;0;L;;;;;N;;;;; -1F195;SQUARED NEW;So;0;L;;;;;N;;;;; -1F196;SQUARED NG;So;0;L;;;;;N;;;;; -1F197;SQUARED OK;So;0;L;;;;;N;;;;; -1F198;SQUARED SOS;So;0;L;;;;;N;;;;; -1F199;SQUARED UP WITH EXCLAMATION MARK;So;0;L;;;;;N;;;;; -1F19A;SQUARED VS;So;0;L;;;;;N;;;;; -1F19B;SQUARED THREE D;So;0;L;;;;;N;;;;; -1F19C;SQUARED SECOND SCREEN;So;0;L;;;;;N;;;;; -1F19D;SQUARED TWO K;So;0;L;;;;;N;;;;; -1F19E;SQUARED FOUR K;So;0;L;;;;;N;;;;; -1F19F;SQUARED EIGHT K;So;0;L;;;;;N;;;;; -1F1A0;SQUARED FIVE POINT ONE;So;0;L;;;;;N;;;;; -1F1A1;SQUARED SEVEN POINT ONE;So;0;L;;;;;N;;;;; -1F1A2;SQUARED TWENTY-TWO POINT TWO;So;0;L;;;;;N;;;;; -1F1A3;SQUARED SIXTY P;So;0;L;;;;;N;;;;; -1F1A4;SQUARED ONE HUNDRED TWENTY P;So;0;L;;;;;N;;;;; -1F1A5;SQUARED LATIN SMALL LETTER D;So;0;L;;;;;N;;;;; -1F1A6;SQUARED HC;So;0;L;;;;;N;;;;; -1F1A7;SQUARED HDR;So;0;L;;;;;N;;;;; -1F1A8;SQUARED HI-RES;So;0;L;;;;;N;;;;; -1F1A9;SQUARED LOSSLESS;So;0;L;;;;;N;;;;; -1F1AA;SQUARED SHV;So;0;L;;;;;N;;;;; -1F1AB;SQUARED UHD;So;0;L;;;;;N;;;;; -1F1AC;SQUARED VOD;So;0;L;;;;;N;;;;; -1F1AD;MASK WORK SYMBOL;So;0;ON;;;;;N;;;;; -1F1E6;REGIONAL INDICATOR SYMBOL LETTER A;So;0;L;;;;;N;;;;; -1F1E7;REGIONAL INDICATOR SYMBOL LETTER B;So;0;L;;;;;N;;;;; -1F1E8;REGIONAL INDICATOR SYMBOL LETTER C;So;0;L;;;;;N;;;;; -1F1E9;REGIONAL INDICATOR SYMBOL LETTER D;So;0;L;;;;;N;;;;; -1F1EA;REGIONAL INDICATOR SYMBOL LETTER E;So;0;L;;;;;N;;;;; -1F1EB;REGIONAL INDICATOR SYMBOL LETTER F;So;0;L;;;;;N;;;;; -1F1EC;REGIONAL INDICATOR SYMBOL LETTER G;So;0;L;;;;;N;;;;; -1F1ED;REGIONAL INDICATOR SYMBOL LETTER H;So;0;L;;;;;N;;;;; -1F1EE;REGIONAL INDICATOR SYMBOL LETTER I;So;0;L;;;;;N;;;;; -1F1EF;REGIONAL INDICATOR SYMBOL LETTER J;So;0;L;;;;;N;;;;; -1F1F0;REGIONAL INDICATOR SYMBOL LETTER K;So;0;L;;;;;N;;;;; -1F1F1;REGIONAL INDICATOR SYMBOL LETTER L;So;0;L;;;;;N;;;;; -1F1F2;REGIONAL INDICATOR SYMBOL LETTER M;So;0;L;;;;;N;;;;; -1F1F3;REGIONAL INDICATOR SYMBOL LETTER N;So;0;L;;;;;N;;;;; -1F1F4;REGIONAL INDICATOR SYMBOL LETTER O;So;0;L;;;;;N;;;;; -1F1F5;REGIONAL INDICATOR SYMBOL LETTER P;So;0;L;;;;;N;;;;; -1F1F6;REGIONAL INDICATOR SYMBOL LETTER Q;So;0;L;;;;;N;;;;; -1F1F7;REGIONAL INDICATOR SYMBOL LETTER R;So;0;L;;;;;N;;;;; -1F1F8;REGIONAL INDICATOR SYMBOL LETTER S;So;0;L;;;;;N;;;;; -1F1F9;REGIONAL INDICATOR SYMBOL LETTER T;So;0;L;;;;;N;;;;; -1F1FA;REGIONAL INDICATOR SYMBOL LETTER U;So;0;L;;;;;N;;;;; -1F1FB;REGIONAL INDICATOR SYMBOL LETTER V;So;0;L;;;;;N;;;;; -1F1FC;REGIONAL INDICATOR SYMBOL LETTER W;So;0;L;;;;;N;;;;; -1F1FD;REGIONAL INDICATOR SYMBOL LETTER X;So;0;L;;;;;N;;;;; -1F1FE;REGIONAL INDICATOR SYMBOL LETTER Y;So;0;L;;;;;N;;;;; -1F1FF;REGIONAL INDICATOR SYMBOL LETTER Z;So;0;L;;;;;N;;;;; -1F200;SQUARE HIRAGANA HOKA;So;0;L;<square> 307B 304B;;;;N;;;;; -1F201;SQUARED KATAKANA KOKO;So;0;L;<square> 30B3 30B3;;;;N;;;;; -1F202;SQUARED KATAKANA SA;So;0;L;<square> 30B5;;;;N;;;;; -1F210;SQUARED CJK UNIFIED IDEOGRAPH-624B;So;0;L;<square> 624B;;;;N;;;;; -1F211;SQUARED CJK UNIFIED IDEOGRAPH-5B57;So;0;L;<square> 5B57;;;;N;;;;; -1F212;SQUARED CJK UNIFIED IDEOGRAPH-53CC;So;0;L;<square> 53CC;;;;N;;;;; -1F213;SQUARED KATAKANA DE;So;0;L;<square> 30C7;;;;N;;;;; -1F214;SQUARED CJK UNIFIED IDEOGRAPH-4E8C;So;0;L;<square> 4E8C;;;;N;;;;; -1F215;SQUARED CJK UNIFIED IDEOGRAPH-591A;So;0;L;<square> 591A;;;;N;;;;; -1F216;SQUARED CJK UNIFIED IDEOGRAPH-89E3;So;0;L;<square> 89E3;;;;N;;;;; -1F217;SQUARED CJK UNIFIED IDEOGRAPH-5929;So;0;L;<square> 5929;;;;N;;;;; -1F218;SQUARED CJK UNIFIED IDEOGRAPH-4EA4;So;0;L;<square> 4EA4;;;;N;;;;; -1F219;SQUARED CJK UNIFIED IDEOGRAPH-6620;So;0;L;<square> 6620;;;;N;;;;; -1F21A;SQUARED CJK UNIFIED IDEOGRAPH-7121;So;0;L;<square> 7121;;;;N;;;;; -1F21B;SQUARED CJK UNIFIED IDEOGRAPH-6599;So;0;L;<square> 6599;;;;N;;;;; -1F21C;SQUARED CJK UNIFIED IDEOGRAPH-524D;So;0;L;<square> 524D;;;;N;;;;; -1F21D;SQUARED CJK UNIFIED IDEOGRAPH-5F8C;So;0;L;<square> 5F8C;;;;N;;;;; -1F21E;SQUARED CJK UNIFIED IDEOGRAPH-518D;So;0;L;<square> 518D;;;;N;;;;; -1F21F;SQUARED CJK UNIFIED IDEOGRAPH-65B0;So;0;L;<square> 65B0;;;;N;;;;; -1F220;SQUARED CJK UNIFIED IDEOGRAPH-521D;So;0;L;<square> 521D;;;;N;;;;; -1F221;SQUARED CJK UNIFIED IDEOGRAPH-7D42;So;0;L;<square> 7D42;;;;N;;;;; -1F222;SQUARED CJK UNIFIED IDEOGRAPH-751F;So;0;L;<square> 751F;;;;N;;;;; -1F223;SQUARED CJK UNIFIED IDEOGRAPH-8CA9;So;0;L;<square> 8CA9;;;;N;;;;; -1F224;SQUARED CJK UNIFIED IDEOGRAPH-58F0;So;0;L;<square> 58F0;;;;N;;;;; -1F225;SQUARED CJK UNIFIED IDEOGRAPH-5439;So;0;L;<square> 5439;;;;N;;;;; -1F226;SQUARED CJK UNIFIED IDEOGRAPH-6F14;So;0;L;<square> 6F14;;;;N;;;;; -1F227;SQUARED CJK UNIFIED IDEOGRAPH-6295;So;0;L;<square> 6295;;;;N;;;;; -1F228;SQUARED CJK UNIFIED IDEOGRAPH-6355;So;0;L;<square> 6355;;;;N;;;;; -1F229;SQUARED CJK UNIFIED IDEOGRAPH-4E00;So;0;L;<square> 4E00;;;;N;;;;; -1F22A;SQUARED CJK UNIFIED IDEOGRAPH-4E09;So;0;L;<square> 4E09;;;;N;;;;; -1F22B;SQUARED CJK UNIFIED IDEOGRAPH-904A;So;0;L;<square> 904A;;;;N;;;;; -1F22C;SQUARED CJK UNIFIED IDEOGRAPH-5DE6;So;0;L;<square> 5DE6;;;;N;;;;; -1F22D;SQUARED CJK UNIFIED IDEOGRAPH-4E2D;So;0;L;<square> 4E2D;;;;N;;;;; -1F22E;SQUARED CJK UNIFIED IDEOGRAPH-53F3;So;0;L;<square> 53F3;;;;N;;;;; -1F22F;SQUARED CJK UNIFIED IDEOGRAPH-6307;So;0;L;<square> 6307;;;;N;;;;; -1F230;SQUARED CJK UNIFIED IDEOGRAPH-8D70;So;0;L;<square> 8D70;;;;N;;;;; -1F231;SQUARED CJK UNIFIED IDEOGRAPH-6253;So;0;L;<square> 6253;;;;N;;;;; -1F232;SQUARED CJK UNIFIED IDEOGRAPH-7981;So;0;L;<square> 7981;;;;N;;;;; -1F233;SQUARED CJK UNIFIED IDEOGRAPH-7A7A;So;0;L;<square> 7A7A;;;;N;;;;; -1F234;SQUARED CJK UNIFIED IDEOGRAPH-5408;So;0;L;<square> 5408;;;;N;;;;; -1F235;SQUARED CJK UNIFIED IDEOGRAPH-6E80;So;0;L;<square> 6E80;;;;N;;;;; -1F236;SQUARED CJK UNIFIED IDEOGRAPH-6709;So;0;L;<square> 6709;;;;N;;;;; -1F237;SQUARED CJK UNIFIED IDEOGRAPH-6708;So;0;L;<square> 6708;;;;N;;;;; -1F238;SQUARED CJK UNIFIED IDEOGRAPH-7533;So;0;L;<square> 7533;;;;N;;;;; -1F239;SQUARED CJK UNIFIED IDEOGRAPH-5272;So;0;L;<square> 5272;;;;N;;;;; -1F23A;SQUARED CJK UNIFIED IDEOGRAPH-55B6;So;0;L;<square> 55B6;;;;N;;;;; -1F23B;SQUARED CJK UNIFIED IDEOGRAPH-914D;So;0;L;<square> 914D;;;;N;;;;; -1F240;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C;So;0;L;<compat> 3014 672C 3015;;;;N;;;;; -1F241;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E09;So;0;L;<compat> 3014 4E09 3015;;;;N;;;;; -1F242;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E8C;So;0;L;<compat> 3014 4E8C 3015;;;;N;;;;; -1F243;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-5B89;So;0;L;<compat> 3014 5B89 3015;;;;N;;;;; -1F244;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-70B9;So;0;L;<compat> 3014 70B9 3015;;;;N;;;;; -1F245;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6253;So;0;L;<compat> 3014 6253 3015;;;;N;;;;; -1F246;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-76D7;So;0;L;<compat> 3014 76D7 3015;;;;N;;;;; -1F247;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-52DD;So;0;L;<compat> 3014 52DD 3015;;;;N;;;;; -1F248;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557;So;0;L;<compat> 3014 6557 3015;;;;N;;;;; -1F250;CIRCLED IDEOGRAPH ADVANTAGE;So;0;L;<circle> 5F97;;;;N;;;;; -1F251;CIRCLED IDEOGRAPH ACCEPT;So;0;L;<circle> 53EF;;;;N;;;;; -1F260;ROUNDED SYMBOL FOR FU;So;0;ON;;;;;N;;;;; -1F261;ROUNDED SYMBOL FOR LU;So;0;ON;;;;;N;;;;; -1F262;ROUNDED SYMBOL FOR SHOU;So;0;ON;;;;;N;;;;; -1F263;ROUNDED SYMBOL FOR XI;So;0;ON;;;;;N;;;;; -1F264;ROUNDED SYMBOL FOR SHUANGXI;So;0;ON;;;;;N;;;;; -1F265;ROUNDED SYMBOL FOR CAI;So;0;ON;;;;;N;;;;; -1F300;CYCLONE;So;0;ON;;;;;N;;;;; -1F301;FOGGY;So;0;ON;;;;;N;;;;; -1F302;CLOSED UMBRELLA;So;0;ON;;;;;N;;;;; -1F303;NIGHT WITH STARS;So;0;ON;;;;;N;;;;; -1F304;SUNRISE OVER MOUNTAINS;So;0;ON;;;;;N;;;;; -1F305;SUNRISE;So;0;ON;;;;;N;;;;; -1F306;CITYSCAPE AT DUSK;So;0;ON;;;;;N;;;;; -1F307;SUNSET OVER BUILDINGS;So;0;ON;;;;;N;;;;; -1F308;RAINBOW;So;0;ON;;;;;N;;;;; -1F309;BRIDGE AT NIGHT;So;0;ON;;;;;N;;;;; -1F30A;WATER WAVE;So;0;ON;;;;;N;;;;; -1F30B;VOLCANO;So;0;ON;;;;;N;;;;; -1F30C;MILKY WAY;So;0;ON;;;;;N;;;;; -1F30D;EARTH GLOBE EUROPE-AFRICA;So;0;ON;;;;;N;;;;; -1F30E;EARTH GLOBE AMERICAS;So;0;ON;;;;;N;;;;; -1F30F;EARTH GLOBE ASIA-AUSTRALIA;So;0;ON;;;;;N;;;;; -1F310;GLOBE WITH MERIDIANS;So;0;ON;;;;;N;;;;; -1F311;NEW MOON SYMBOL;So;0;ON;;;;;N;;;;; -1F312;WAXING CRESCENT MOON SYMBOL;So;0;ON;;;;;N;;;;; -1F313;FIRST QUARTER MOON SYMBOL;So;0;ON;;;;;N;;;;; -1F314;WAXING GIBBOUS MOON SYMBOL;So;0;ON;;;;;N;;;;; -1F315;FULL MOON SYMBOL;So;0;ON;;;;;N;;;;; -1F316;WANING GIBBOUS MOON SYMBOL;So;0;ON;;;;;N;;;;; -1F317;LAST QUARTER MOON SYMBOL;So;0;ON;;;;;N;;;;; -1F318;WANING CRESCENT MOON SYMBOL;So;0;ON;;;;;N;;;;; -1F319;CRESCENT MOON;So;0;ON;;;;;N;;;;; -1F31A;NEW MOON WITH FACE;So;0;ON;;;;;N;;;;; -1F31B;FIRST QUARTER MOON WITH FACE;So;0;ON;;;;;N;;;;; -1F31C;LAST QUARTER MOON WITH FACE;So;0;ON;;;;;N;;;;; -1F31D;FULL MOON WITH FACE;So;0;ON;;;;;N;;;;; -1F31E;SUN WITH FACE;So;0;ON;;;;;N;;;;; -1F31F;GLOWING STAR;So;0;ON;;;;;N;;;;; -1F320;SHOOTING STAR;So;0;ON;;;;;N;;;;; -1F321;THERMOMETER;So;0;ON;;;;;N;;;;; -1F322;BLACK DROPLET;So;0;ON;;;;;N;;;;; -1F323;WHITE SUN;So;0;ON;;;;;N;;;;; -1F324;WHITE SUN WITH SMALL CLOUD;So;0;ON;;;;;N;;;;; -1F325;WHITE SUN BEHIND CLOUD;So;0;ON;;;;;N;;;;; -1F326;WHITE SUN BEHIND CLOUD WITH RAIN;So;0;ON;;;;;N;;;;; -1F327;CLOUD WITH RAIN;So;0;ON;;;;;N;;;;; -1F328;CLOUD WITH SNOW;So;0;ON;;;;;N;;;;; -1F329;CLOUD WITH LIGHTNING;So;0;ON;;;;;N;;;;; -1F32A;CLOUD WITH TORNADO;So;0;ON;;;;;N;;;;; -1F32B;FOG;So;0;ON;;;;;N;;;;; -1F32C;WIND BLOWING FACE;So;0;ON;;;;;N;;;;; -1F32D;HOT DOG;So;0;ON;;;;;N;;;;; -1F32E;TACO;So;0;ON;;;;;N;;;;; -1F32F;BURRITO;So;0;ON;;;;;N;;;;; -1F330;CHESTNUT;So;0;ON;;;;;N;;;;; -1F331;SEEDLING;So;0;ON;;;;;N;;;;; -1F332;EVERGREEN TREE;So;0;ON;;;;;N;;;;; -1F333;DECIDUOUS TREE;So;0;ON;;;;;N;;;;; -1F334;PALM TREE;So;0;ON;;;;;N;;;;; -1F335;CACTUS;So;0;ON;;;;;N;;;;; -1F336;HOT PEPPER;So;0;ON;;;;;N;;;;; -1F337;TULIP;So;0;ON;;;;;N;;;;; -1F338;CHERRY BLOSSOM;So;0;ON;;;;;N;;;;; -1F339;ROSE;So;0;ON;;;;;N;;;;; -1F33A;HIBISCUS;So;0;ON;;;;;N;;;;; -1F33B;SUNFLOWER;So;0;ON;;;;;N;;;;; -1F33C;BLOSSOM;So;0;ON;;;;;N;;;;; -1F33D;EAR OF MAIZE;So;0;ON;;;;;N;;;;; -1F33E;EAR OF RICE;So;0;ON;;;;;N;;;;; -1F33F;HERB;So;0;ON;;;;;N;;;;; -1F340;FOUR LEAF CLOVER;So;0;ON;;;;;N;;;;; -1F341;MAPLE LEAF;So;0;ON;;;;;N;;;;; -1F342;FALLEN LEAF;So;0;ON;;;;;N;;;;; -1F343;LEAF FLUTTERING IN WIND;So;0;ON;;;;;N;;;;; -1F344;MUSHROOM;So;0;ON;;;;;N;;;;; -1F345;TOMATO;So;0;ON;;;;;N;;;;; -1F346;AUBERGINE;So;0;ON;;;;;N;;;;; -1F347;GRAPES;So;0;ON;;;;;N;;;;; -1F348;MELON;So;0;ON;;;;;N;;;;; -1F349;WATERMELON;So;0;ON;;;;;N;;;;; -1F34A;TANGERINE;So;0;ON;;;;;N;;;;; -1F34B;LEMON;So;0;ON;;;;;N;;;;; -1F34C;BANANA;So;0;ON;;;;;N;;;;; -1F34D;PINEAPPLE;So;0;ON;;;;;N;;;;; -1F34E;RED APPLE;So;0;ON;;;;;N;;;;; -1F34F;GREEN APPLE;So;0;ON;;;;;N;;;;; -1F350;PEAR;So;0;ON;;;;;N;;;;; -1F351;PEACH;So;0;ON;;;;;N;;;;; -1F352;CHERRIES;So;0;ON;;;;;N;;;;; -1F353;STRAWBERRY;So;0;ON;;;;;N;;;;; -1F354;HAMBURGER;So;0;ON;;;;;N;;;;; -1F355;SLICE OF PIZZA;So;0;ON;;;;;N;;;;; -1F356;MEAT ON BONE;So;0;ON;;;;;N;;;;; -1F357;POULTRY LEG;So;0;ON;;;;;N;;;;; -1F358;RICE CRACKER;So;0;ON;;;;;N;;;;; -1F359;RICE BALL;So;0;ON;;;;;N;;;;; -1F35A;COOKED RICE;So;0;ON;;;;;N;;;;; -1F35B;CURRY AND RICE;So;0;ON;;;;;N;;;;; -1F35C;STEAMING BOWL;So;0;ON;;;;;N;;;;; -1F35D;SPAGHETTI;So;0;ON;;;;;N;;;;; -1F35E;BREAD;So;0;ON;;;;;N;;;;; -1F35F;FRENCH FRIES;So;0;ON;;;;;N;;;;; -1F360;ROASTED SWEET POTATO;So;0;ON;;;;;N;;;;; -1F361;DANGO;So;0;ON;;;;;N;;;;; -1F362;ODEN;So;0;ON;;;;;N;;;;; -1F363;SUSHI;So;0;ON;;;;;N;;;;; -1F364;FRIED SHRIMP;So;0;ON;;;;;N;;;;; -1F365;FISH CAKE WITH SWIRL DESIGN;So;0;ON;;;;;N;;;;; -1F366;SOFT ICE CREAM;So;0;ON;;;;;N;;;;; -1F367;SHAVED ICE;So;0;ON;;;;;N;;;;; -1F368;ICE CREAM;So;0;ON;;;;;N;;;;; -1F369;DOUGHNUT;So;0;ON;;;;;N;;;;; -1F36A;COOKIE;So;0;ON;;;;;N;;;;; -1F36B;CHOCOLATE BAR;So;0;ON;;;;;N;;;;; -1F36C;CANDY;So;0;ON;;;;;N;;;;; -1F36D;LOLLIPOP;So;0;ON;;;;;N;;;;; -1F36E;CUSTARD;So;0;ON;;;;;N;;;;; -1F36F;HONEY POT;So;0;ON;;;;;N;;;;; -1F370;SHORTCAKE;So;0;ON;;;;;N;;;;; -1F371;BENTO BOX;So;0;ON;;;;;N;;;;; -1F372;POT OF FOOD;So;0;ON;;;;;N;;;;; -1F373;COOKING;So;0;ON;;;;;N;;;;; -1F374;FORK AND KNIFE;So;0;ON;;;;;N;;;;; -1F375;TEACUP WITHOUT HANDLE;So;0;ON;;;;;N;;;;; -1F376;SAKE BOTTLE AND CUP;So;0;ON;;;;;N;;;;; -1F377;WINE GLASS;So;0;ON;;;;;N;;;;; -1F378;COCKTAIL GLASS;So;0;ON;;;;;N;;;;; -1F379;TROPICAL DRINK;So;0;ON;;;;;N;;;;; -1F37A;BEER MUG;So;0;ON;;;;;N;;;;; -1F37B;CLINKING BEER MUGS;So;0;ON;;;;;N;;;;; -1F37C;BABY BOTTLE;So;0;ON;;;;;N;;;;; -1F37D;FORK AND KNIFE WITH PLATE;So;0;ON;;;;;N;;;;; -1F37E;BOTTLE WITH POPPING CORK;So;0;ON;;;;;N;;;;; -1F37F;POPCORN;So;0;ON;;;;;N;;;;; -1F380;RIBBON;So;0;ON;;;;;N;;;;; -1F381;WRAPPED PRESENT;So;0;ON;;;;;N;;;;; -1F382;BIRTHDAY CAKE;So;0;ON;;;;;N;;;;; -1F383;JACK-O-LANTERN;So;0;ON;;;;;N;;;;; -1F384;CHRISTMAS TREE;So;0;ON;;;;;N;;;;; -1F385;FATHER CHRISTMAS;So;0;ON;;;;;N;;;;; -1F386;FIREWORKS;So;0;ON;;;;;N;;;;; -1F387;FIREWORK SPARKLER;So;0;ON;;;;;N;;;;; -1F388;BALLOON;So;0;ON;;;;;N;;;;; -1F389;PARTY POPPER;So;0;ON;;;;;N;;;;; -1F38A;CONFETTI BALL;So;0;ON;;;;;N;;;;; -1F38B;TANABATA TREE;So;0;ON;;;;;N;;;;; -1F38C;CROSSED FLAGS;So;0;ON;;;;;N;;;;; -1F38D;PINE DECORATION;So;0;ON;;;;;N;;;;; -1F38E;JAPANESE DOLLS;So;0;ON;;;;;N;;;;; -1F38F;CARP STREAMER;So;0;ON;;;;;N;;;;; -1F390;WIND CHIME;So;0;ON;;;;;N;;;;; -1F391;MOON VIEWING CEREMONY;So;0;ON;;;;;N;;;;; -1F392;SCHOOL SATCHEL;So;0;ON;;;;;N;;;;; -1F393;GRADUATION CAP;So;0;ON;;;;;N;;;;; -1F394;HEART WITH TIP ON THE LEFT;So;0;ON;;;;;N;;;;; -1F395;BOUQUET OF FLOWERS;So;0;ON;;;;;N;;;;; -1F396;MILITARY MEDAL;So;0;ON;;;;;N;;;;; -1F397;REMINDER RIBBON;So;0;ON;;;;;N;;;;; -1F398;MUSICAL KEYBOARD WITH JACKS;So;0;ON;;;;;N;;;;; -1F399;STUDIO MICROPHONE;So;0;ON;;;;;N;;;;; -1F39A;LEVEL SLIDER;So;0;ON;;;;;N;;;;; -1F39B;CONTROL KNOBS;So;0;ON;;;;;N;;;;; -1F39C;BEAMED ASCENDING MUSICAL NOTES;So;0;ON;;;;;N;;;;; -1F39D;BEAMED DESCENDING MUSICAL NOTES;So;0;ON;;;;;N;;;;; -1F39E;FILM FRAMES;So;0;ON;;;;;N;;;;; -1F39F;ADMISSION TICKETS;So;0;ON;;;;;N;;;;; -1F3A0;CAROUSEL HORSE;So;0;ON;;;;;N;;;;; -1F3A1;FERRIS WHEEL;So;0;ON;;;;;N;;;;; -1F3A2;ROLLER COASTER;So;0;ON;;;;;N;;;;; -1F3A3;FISHING POLE AND FISH;So;0;ON;;;;;N;;;;; -1F3A4;MICROPHONE;So;0;ON;;;;;N;;;;; -1F3A5;MOVIE CAMERA;So;0;ON;;;;;N;;;;; -1F3A6;CINEMA;So;0;ON;;;;;N;;;;; -1F3A7;HEADPHONE;So;0;ON;;;;;N;;;;; -1F3A8;ARTIST PALETTE;So;0;ON;;;;;N;;;;; -1F3A9;TOP HAT;So;0;ON;;;;;N;;;;; -1F3AA;CIRCUS TENT;So;0;ON;;;;;N;;;;; -1F3AB;TICKET;So;0;ON;;;;;N;;;;; -1F3AC;CLAPPER BOARD;So;0;ON;;;;;N;;;;; -1F3AD;PERFORMING ARTS;So;0;ON;;;;;N;;;;; -1F3AE;VIDEO GAME;So;0;ON;;;;;N;;;;; -1F3AF;DIRECT HIT;So;0;ON;;;;;N;;;;; -1F3B0;SLOT MACHINE;So;0;ON;;;;;N;;;;; -1F3B1;BILLIARDS;So;0;ON;;;;;N;;;;; -1F3B2;GAME DIE;So;0;ON;;;;;N;;;;; -1F3B3;BOWLING;So;0;ON;;;;;N;;;;; -1F3B4;FLOWER PLAYING CARDS;So;0;ON;;;;;N;;;;; -1F3B5;MUSICAL NOTE;So;0;ON;;;;;N;;;;; -1F3B6;MULTIPLE MUSICAL NOTES;So;0;ON;;;;;N;;;;; -1F3B7;SAXOPHONE;So;0;ON;;;;;N;;;;; -1F3B8;GUITAR;So;0;ON;;;;;N;;;;; -1F3B9;MUSICAL KEYBOARD;So;0;ON;;;;;N;;;;; -1F3BA;TRUMPET;So;0;ON;;;;;N;;;;; -1F3BB;VIOLIN;So;0;ON;;;;;N;;;;; -1F3BC;MUSICAL SCORE;So;0;ON;;;;;N;;;;; -1F3BD;RUNNING SHIRT WITH SASH;So;0;ON;;;;;N;;;;; -1F3BE;TENNIS RACQUET AND BALL;So;0;ON;;;;;N;;;;; -1F3BF;SKI AND SKI BOOT;So;0;ON;;;;;N;;;;; -1F3C0;BASKETBALL AND HOOP;So;0;ON;;;;;N;;;;; -1F3C1;CHEQUERED FLAG;So;0;ON;;;;;N;;;;; -1F3C2;SNOWBOARDER;So;0;ON;;;;;N;;;;; -1F3C3;RUNNER;So;0;ON;;;;;N;;;;; -1F3C4;SURFER;So;0;ON;;;;;N;;;;; -1F3C5;SPORTS MEDAL;So;0;ON;;;;;N;;;;; -1F3C6;TROPHY;So;0;ON;;;;;N;;;;; -1F3C7;HORSE RACING;So;0;ON;;;;;N;;;;; -1F3C8;AMERICAN FOOTBALL;So;0;ON;;;;;N;;;;; -1F3C9;RUGBY FOOTBALL;So;0;ON;;;;;N;;;;; -1F3CA;SWIMMER;So;0;ON;;;;;N;;;;; -1F3CB;WEIGHT LIFTER;So;0;ON;;;;;N;;;;; -1F3CC;GOLFER;So;0;ON;;;;;N;;;;; -1F3CD;RACING MOTORCYCLE;So;0;ON;;;;;N;;;;; -1F3CE;RACING CAR;So;0;ON;;;;;N;;;;; -1F3CF;CRICKET BAT AND BALL;So;0;ON;;;;;N;;;;; -1F3D0;VOLLEYBALL;So;0;ON;;;;;N;;;;; -1F3D1;FIELD HOCKEY STICK AND BALL;So;0;ON;;;;;N;;;;; -1F3D2;ICE HOCKEY STICK AND PUCK;So;0;ON;;;;;N;;;;; -1F3D3;TABLE TENNIS PADDLE AND BALL;So;0;ON;;;;;N;;;;; -1F3D4;SNOW CAPPED MOUNTAIN;So;0;ON;;;;;N;;;;; -1F3D5;CAMPING;So;0;ON;;;;;N;;;;; -1F3D6;BEACH WITH UMBRELLA;So;0;ON;;;;;N;;;;; -1F3D7;BUILDING CONSTRUCTION;So;0;ON;;;;;N;;;;; -1F3D8;HOUSE BUILDINGS;So;0;ON;;;;;N;;;;; -1F3D9;CITYSCAPE;So;0;ON;;;;;N;;;;; -1F3DA;DERELICT HOUSE BUILDING;So;0;ON;;;;;N;;;;; -1F3DB;CLASSICAL BUILDING;So;0;ON;;;;;N;;;;; -1F3DC;DESERT;So;0;ON;;;;;N;;;;; -1F3DD;DESERT ISLAND;So;0;ON;;;;;N;;;;; -1F3DE;NATIONAL PARK;So;0;ON;;;;;N;;;;; -1F3DF;STADIUM;So;0;ON;;;;;N;;;;; -1F3E0;HOUSE BUILDING;So;0;ON;;;;;N;;;;; -1F3E1;HOUSE WITH GARDEN;So;0;ON;;;;;N;;;;; -1F3E2;OFFICE BUILDING;So;0;ON;;;;;N;;;;; -1F3E3;JAPANESE POST OFFICE;So;0;ON;;;;;N;;;;; -1F3E4;EUROPEAN POST OFFICE;So;0;ON;;;;;N;;;;; -1F3E5;HOSPITAL;So;0;ON;;;;;N;;;;; -1F3E6;BANK;So;0;ON;;;;;N;;;;; -1F3E7;AUTOMATED TELLER MACHINE;So;0;ON;;;;;N;;;;; -1F3E8;HOTEL;So;0;ON;;;;;N;;;;; -1F3E9;LOVE HOTEL;So;0;ON;;;;;N;;;;; -1F3EA;CONVENIENCE STORE;So;0;ON;;;;;N;;;;; -1F3EB;SCHOOL;So;0;ON;;;;;N;;;;; -1F3EC;DEPARTMENT STORE;So;0;ON;;;;;N;;;;; -1F3ED;FACTORY;So;0;ON;;;;;N;;;;; -1F3EE;IZAKAYA LANTERN;So;0;ON;;;;;N;;;;; -1F3EF;JAPANESE CASTLE;So;0;ON;;;;;N;;;;; -1F3F0;EUROPEAN CASTLE;So;0;ON;;;;;N;;;;; -1F3F1;WHITE PENNANT;So;0;ON;;;;;N;;;;; -1F3F2;BLACK PENNANT;So;0;ON;;;;;N;;;;; -1F3F3;WAVING WHITE FLAG;So;0;ON;;;;;N;;;;; -1F3F4;WAVING BLACK FLAG;So;0;ON;;;;;N;;;;; -1F3F5;ROSETTE;So;0;ON;;;;;N;;;;; -1F3F6;BLACK ROSETTE;So;0;ON;;;;;N;;;;; -1F3F7;LABEL;So;0;ON;;;;;N;;;;; -1F3F8;BADMINTON RACQUET AND SHUTTLECOCK;So;0;ON;;;;;N;;;;; -1F3F9;BOW AND ARROW;So;0;ON;;;;;N;;;;; -1F3FA;AMPHORA;So;0;ON;;;;;N;;;;; -1F3FB;EMOJI MODIFIER FITZPATRICK TYPE-1-2;Sk;0;ON;;;;;N;;;;; -1F3FC;EMOJI MODIFIER FITZPATRICK TYPE-3;Sk;0;ON;;;;;N;;;;; -1F3FD;EMOJI MODIFIER FITZPATRICK TYPE-4;Sk;0;ON;;;;;N;;;;; -1F3FE;EMOJI MODIFIER FITZPATRICK TYPE-5;Sk;0;ON;;;;;N;;;;; -1F3FF;EMOJI MODIFIER FITZPATRICK TYPE-6;Sk;0;ON;;;;;N;;;;; -1F400;RAT;So;0;ON;;;;;N;;;;; -1F401;MOUSE;So;0;ON;;;;;N;;;;; -1F402;OX;So;0;ON;;;;;N;;;;; -1F403;WATER BUFFALO;So;0;ON;;;;;N;;;;; -1F404;COW;So;0;ON;;;;;N;;;;; -1F405;TIGER;So;0;ON;;;;;N;;;;; -1F406;LEOPARD;So;0;ON;;;;;N;;;;; -1F407;RABBIT;So;0;ON;;;;;N;;;;; -1F408;CAT;So;0;ON;;;;;N;;;;; -1F409;DRAGON;So;0;ON;;;;;N;;;;; -1F40A;CROCODILE;So;0;ON;;;;;N;;;;; -1F40B;WHALE;So;0;ON;;;;;N;;;;; -1F40C;SNAIL;So;0;ON;;;;;N;;;;; -1F40D;SNAKE;So;0;ON;;;;;N;;;;; -1F40E;HORSE;So;0;ON;;;;;N;;;;; -1F40F;RAM;So;0;ON;;;;;N;;;;; -1F410;GOAT;So;0;ON;;;;;N;;;;; -1F411;SHEEP;So;0;ON;;;;;N;;;;; -1F412;MONKEY;So;0;ON;;;;;N;;;;; -1F413;ROOSTER;So;0;ON;;;;;N;;;;; -1F414;CHICKEN;So;0;ON;;;;;N;;;;; -1F415;DOG;So;0;ON;;;;;N;;;;; -1F416;PIG;So;0;ON;;;;;N;;;;; -1F417;BOAR;So;0;ON;;;;;N;;;;; -1F418;ELEPHANT;So;0;ON;;;;;N;;;;; -1F419;OCTOPUS;So;0;ON;;;;;N;;;;; -1F41A;SPIRAL SHELL;So;0;ON;;;;;N;;;;; -1F41B;BUG;So;0;ON;;;;;N;;;;; -1F41C;ANT;So;0;ON;;;;;N;;;;; -1F41D;HONEYBEE;So;0;ON;;;;;N;;;;; -1F41E;LADY BEETLE;So;0;ON;;;;;N;;;;; -1F41F;FISH;So;0;ON;;;;;N;;;;; -1F420;TROPICAL FISH;So;0;ON;;;;;N;;;;; -1F421;BLOWFISH;So;0;ON;;;;;N;;;;; -1F422;TURTLE;So;0;ON;;;;;N;;;;; -1F423;HATCHING CHICK;So;0;ON;;;;;N;;;;; -1F424;BABY CHICK;So;0;ON;;;;;N;;;;; -1F425;FRONT-FACING BABY CHICK;So;0;ON;;;;;N;;;;; -1F426;BIRD;So;0;ON;;;;;N;;;;; -1F427;PENGUIN;So;0;ON;;;;;N;;;;; -1F428;KOALA;So;0;ON;;;;;N;;;;; -1F429;POODLE;So;0;ON;;;;;N;;;;; -1F42A;DROMEDARY CAMEL;So;0;ON;;;;;N;;;;; -1F42B;BACTRIAN CAMEL;So;0;ON;;;;;N;;;;; -1F42C;DOLPHIN;So;0;ON;;;;;N;;;;; -1F42D;MOUSE FACE;So;0;ON;;;;;N;;;;; -1F42E;COW FACE;So;0;ON;;;;;N;;;;; -1F42F;TIGER FACE;So;0;ON;;;;;N;;;;; -1F430;RABBIT FACE;So;0;ON;;;;;N;;;;; -1F431;CAT FACE;So;0;ON;;;;;N;;;;; -1F432;DRAGON FACE;So;0;ON;;;;;N;;;;; -1F433;SPOUTING WHALE;So;0;ON;;;;;N;;;;; -1F434;HORSE FACE;So;0;ON;;;;;N;;;;; -1F435;MONKEY FACE;So;0;ON;;;;;N;;;;; -1F436;DOG FACE;So;0;ON;;;;;N;;;;; -1F437;PIG FACE;So;0;ON;;;;;N;;;;; -1F438;FROG FACE;So;0;ON;;;;;N;;;;; -1F439;HAMSTER FACE;So;0;ON;;;;;N;;;;; -1F43A;WOLF FACE;So;0;ON;;;;;N;;;;; -1F43B;BEAR FACE;So;0;ON;;;;;N;;;;; -1F43C;PANDA FACE;So;0;ON;;;;;N;;;;; -1F43D;PIG NOSE;So;0;ON;;;;;N;;;;; -1F43E;PAW PRINTS;So;0;ON;;;;;N;;;;; -1F43F;CHIPMUNK;So;0;ON;;;;;N;;;;; -1F440;EYES;So;0;ON;;;;;N;;;;; -1F441;EYE;So;0;ON;;;;;N;;;;; -1F442;EAR;So;0;ON;;;;;N;;;;; -1F443;NOSE;So;0;ON;;;;;N;;;;; -1F444;MOUTH;So;0;ON;;;;;N;;;;; -1F445;TONGUE;So;0;ON;;;;;N;;;;; -1F446;WHITE UP POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; -1F447;WHITE DOWN POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; -1F448;WHITE LEFT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; -1F449;WHITE RIGHT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; -1F44A;FISTED HAND SIGN;So;0;ON;;;;;N;;;;; -1F44B;WAVING HAND SIGN;So;0;ON;;;;;N;;;;; -1F44C;OK HAND SIGN;So;0;ON;;;;;N;;;;; -1F44D;THUMBS UP SIGN;So;0;ON;;;;;N;;;;; -1F44E;THUMBS DOWN SIGN;So;0;ON;;;;;N;;;;; -1F44F;CLAPPING HANDS SIGN;So;0;ON;;;;;N;;;;; -1F450;OPEN HANDS SIGN;So;0;ON;;;;;N;;;;; -1F451;CROWN;So;0;ON;;;;;N;;;;; -1F452;WOMANS HAT;So;0;ON;;;;;N;;;;; -1F453;EYEGLASSES;So;0;ON;;;;;N;;;;; -1F454;NECKTIE;So;0;ON;;;;;N;;;;; -1F455;T-SHIRT;So;0;ON;;;;;N;;;;; -1F456;JEANS;So;0;ON;;;;;N;;;;; -1F457;DRESS;So;0;ON;;;;;N;;;;; -1F458;KIMONO;So;0;ON;;;;;N;;;;; -1F459;BIKINI;So;0;ON;;;;;N;;;;; -1F45A;WOMANS CLOTHES;So;0;ON;;;;;N;;;;; -1F45B;PURSE;So;0;ON;;;;;N;;;;; -1F45C;HANDBAG;So;0;ON;;;;;N;;;;; -1F45D;POUCH;So;0;ON;;;;;N;;;;; -1F45E;MANS SHOE;So;0;ON;;;;;N;;;;; -1F45F;ATHLETIC SHOE;So;0;ON;;;;;N;;;;; -1F460;HIGH-HEELED SHOE;So;0;ON;;;;;N;;;;; -1F461;WOMANS SANDAL;So;0;ON;;;;;N;;;;; -1F462;WOMANS BOOTS;So;0;ON;;;;;N;;;;; -1F463;FOOTPRINTS;So;0;ON;;;;;N;;;;; -1F464;BUST IN SILHOUETTE;So;0;ON;;;;;N;;;;; -1F465;BUSTS IN SILHOUETTE;So;0;ON;;;;;N;;;;; -1F466;BOY;So;0;ON;;;;;N;;;;; -1F467;GIRL;So;0;ON;;;;;N;;;;; -1F468;MAN;So;0;ON;;;;;N;;;;; -1F469;WOMAN;So;0;ON;;;;;N;;;;; -1F46A;FAMILY;So;0;ON;;;;;N;;;;; -1F46B;MAN AND WOMAN HOLDING HANDS;So;0;ON;;;;;N;;;;; -1F46C;TWO MEN HOLDING HANDS;So;0;ON;;;;;N;;;;; -1F46D;TWO WOMEN HOLDING HANDS;So;0;ON;;;;;N;;;;; -1F46E;POLICE OFFICER;So;0;ON;;;;;N;;;;; -1F46F;WOMAN WITH BUNNY EARS;So;0;ON;;;;;N;;;;; -1F470;BRIDE WITH VEIL;So;0;ON;;;;;N;;;;; -1F471;PERSON WITH BLOND HAIR;So;0;ON;;;;;N;;;;; -1F472;MAN WITH GUA PI MAO;So;0;ON;;;;;N;;;;; -1F473;MAN WITH TURBAN;So;0;ON;;;;;N;;;;; -1F474;OLDER MAN;So;0;ON;;;;;N;;;;; -1F475;OLDER WOMAN;So;0;ON;;;;;N;;;;; -1F476;BABY;So;0;ON;;;;;N;;;;; -1F477;CONSTRUCTION WORKER;So;0;ON;;;;;N;;;;; -1F478;PRINCESS;So;0;ON;;;;;N;;;;; -1F479;JAPANESE OGRE;So;0;ON;;;;;N;;;;; -1F47A;JAPANESE GOBLIN;So;0;ON;;;;;N;;;;; -1F47B;GHOST;So;0;ON;;;;;N;;;;; -1F47C;BABY ANGEL;So;0;ON;;;;;N;;;;; -1F47D;EXTRATERRESTRIAL ALIEN;So;0;ON;;;;;N;;;;; -1F47E;ALIEN MONSTER;So;0;ON;;;;;N;;;;; -1F47F;IMP;So;0;ON;;;;;N;;;;; -1F480;SKULL;So;0;ON;;;;;N;;;;; -1F481;INFORMATION DESK PERSON;So;0;ON;;;;;N;;;;; -1F482;GUARDSMAN;So;0;ON;;;;;N;;;;; -1F483;DANCER;So;0;ON;;;;;N;;;;; -1F484;LIPSTICK;So;0;ON;;;;;N;;;;; -1F485;NAIL POLISH;So;0;ON;;;;;N;;;;; -1F486;FACE MASSAGE;So;0;ON;;;;;N;;;;; -1F487;HAIRCUT;So;0;ON;;;;;N;;;;; -1F488;BARBER POLE;So;0;ON;;;;;N;;;;; -1F489;SYRINGE;So;0;ON;;;;;N;;;;; -1F48A;PILL;So;0;ON;;;;;N;;;;; -1F48B;KISS MARK;So;0;ON;;;;;N;;;;; -1F48C;LOVE LETTER;So;0;ON;;;;;N;;;;; -1F48D;RING;So;0;ON;;;;;N;;;;; -1F48E;GEM STONE;So;0;ON;;;;;N;;;;; -1F48F;KISS;So;0;ON;;;;;N;;;;; -1F490;BOUQUET;So;0;ON;;;;;N;;;;; -1F491;COUPLE WITH HEART;So;0;ON;;;;;N;;;;; -1F492;WEDDING;So;0;ON;;;;;N;;;;; -1F493;BEATING HEART;So;0;ON;;;;;N;;;;; -1F494;BROKEN HEART;So;0;ON;;;;;N;;;;; -1F495;TWO HEARTS;So;0;ON;;;;;N;;;;; -1F496;SPARKLING HEART;So;0;ON;;;;;N;;;;; -1F497;GROWING HEART;So;0;ON;;;;;N;;;;; -1F498;HEART WITH ARROW;So;0;ON;;;;;N;;;;; -1F499;BLUE HEART;So;0;ON;;;;;N;;;;; -1F49A;GREEN HEART;So;0;ON;;;;;N;;;;; -1F49B;YELLOW HEART;So;0;ON;;;;;N;;;;; -1F49C;PURPLE HEART;So;0;ON;;;;;N;;;;; -1F49D;HEART WITH RIBBON;So;0;ON;;;;;N;;;;; -1F49E;REVOLVING HEARTS;So;0;ON;;;;;N;;;;; -1F49F;HEART DECORATION;So;0;ON;;;;;N;;;;; -1F4A0;DIAMOND SHAPE WITH A DOT INSIDE;So;0;ON;;;;;N;;;;; -1F4A1;ELECTRIC LIGHT BULB;So;0;ON;;;;;N;;;;; -1F4A2;ANGER SYMBOL;So;0;ON;;;;;N;;;;; -1F4A3;BOMB;So;0;ON;;;;;N;;;;; -1F4A4;SLEEPING SYMBOL;So;0;ON;;;;;N;;;;; -1F4A5;COLLISION SYMBOL;So;0;ON;;;;;N;;;;; -1F4A6;SPLASHING SWEAT SYMBOL;So;0;ON;;;;;N;;;;; -1F4A7;DROPLET;So;0;ON;;;;;N;;;;; -1F4A8;DASH SYMBOL;So;0;ON;;;;;N;;;;; -1F4A9;PILE OF POO;So;0;ON;;;;;N;;;;; -1F4AA;FLEXED BICEPS;So;0;ON;;;;;N;;;;; -1F4AB;DIZZY SYMBOL;So;0;ON;;;;;N;;;;; -1F4AC;SPEECH BALLOON;So;0;ON;;;;;N;;;;; -1F4AD;THOUGHT BALLOON;So;0;ON;;;;;N;;;;; -1F4AE;WHITE FLOWER;So;0;ON;;;;;N;;;;; -1F4AF;HUNDRED POINTS SYMBOL;So;0;ON;;;;;N;;;;; -1F4B0;MONEY BAG;So;0;ON;;;;;N;;;;; -1F4B1;CURRENCY EXCHANGE;So;0;ON;;;;;N;;;;; -1F4B2;HEAVY DOLLAR SIGN;So;0;ON;;;;;N;;;;; -1F4B3;CREDIT CARD;So;0;ON;;;;;N;;;;; -1F4B4;BANKNOTE WITH YEN SIGN;So;0;ON;;;;;N;;;;; -1F4B5;BANKNOTE WITH DOLLAR SIGN;So;0;ON;;;;;N;;;;; -1F4B6;BANKNOTE WITH EURO SIGN;So;0;ON;;;;;N;;;;; -1F4B7;BANKNOTE WITH POUND SIGN;So;0;ON;;;;;N;;;;; -1F4B8;MONEY WITH WINGS;So;0;ON;;;;;N;;;;; -1F4B9;CHART WITH UPWARDS TREND AND YEN SIGN;So;0;ON;;;;;N;;;;; -1F4BA;SEAT;So;0;ON;;;;;N;;;;; -1F4BB;PERSONAL COMPUTER;So;0;ON;;;;;N;;;;; -1F4BC;BRIEFCASE;So;0;ON;;;;;N;;;;; -1F4BD;MINIDISC;So;0;ON;;;;;N;;;;; -1F4BE;FLOPPY DISK;So;0;ON;;;;;N;;;;; -1F4BF;OPTICAL DISC;So;0;ON;;;;;N;;;;; -1F4C0;DVD;So;0;ON;;;;;N;;;;; -1F4C1;FILE FOLDER;So;0;ON;;;;;N;;;;; -1F4C2;OPEN FILE FOLDER;So;0;ON;;;;;N;;;;; -1F4C3;PAGE WITH CURL;So;0;ON;;;;;N;;;;; -1F4C4;PAGE FACING UP;So;0;ON;;;;;N;;;;; -1F4C5;CALENDAR;So;0;ON;;;;;N;;;;; -1F4C6;TEAR-OFF CALENDAR;So;0;ON;;;;;N;;;;; -1F4C7;CARD INDEX;So;0;ON;;;;;N;;;;; -1F4C8;CHART WITH UPWARDS TREND;So;0;ON;;;;;N;;;;; -1F4C9;CHART WITH DOWNWARDS TREND;So;0;ON;;;;;N;;;;; -1F4CA;BAR CHART;So;0;ON;;;;;N;;;;; -1F4CB;CLIPBOARD;So;0;ON;;;;;N;;;;; -1F4CC;PUSHPIN;So;0;ON;;;;;N;;;;; -1F4CD;ROUND PUSHPIN;So;0;ON;;;;;N;;;;; -1F4CE;PAPERCLIP;So;0;ON;;;;;N;;;;; -1F4CF;STRAIGHT RULER;So;0;ON;;;;;N;;;;; -1F4D0;TRIANGULAR RULER;So;0;ON;;;;;N;;;;; -1F4D1;BOOKMARK TABS;So;0;ON;;;;;N;;;;; -1F4D2;LEDGER;So;0;ON;;;;;N;;;;; -1F4D3;NOTEBOOK;So;0;ON;;;;;N;;;;; -1F4D4;NOTEBOOK WITH DECORATIVE COVER;So;0;ON;;;;;N;;;;; -1F4D5;CLOSED BOOK;So;0;ON;;;;;N;;;;; -1F4D6;OPEN BOOK;So;0;ON;;;;;N;;;;; -1F4D7;GREEN BOOK;So;0;ON;;;;;N;;;;; -1F4D8;BLUE BOOK;So;0;ON;;;;;N;;;;; -1F4D9;ORANGE BOOK;So;0;ON;;;;;N;;;;; -1F4DA;BOOKS;So;0;ON;;;;;N;;;;; -1F4DB;NAME BADGE;So;0;ON;;;;;N;;;;; -1F4DC;SCROLL;So;0;ON;;;;;N;;;;; -1F4DD;MEMO;So;0;ON;;;;;N;;;;; -1F4DE;TELEPHONE RECEIVER;So;0;ON;;;;;N;;;;; -1F4DF;PAGER;So;0;ON;;;;;N;;;;; -1F4E0;FAX MACHINE;So;0;ON;;;;;N;;;;; -1F4E1;SATELLITE ANTENNA;So;0;ON;;;;;N;;;;; -1F4E2;PUBLIC ADDRESS LOUDSPEAKER;So;0;ON;;;;;N;;;;; -1F4E3;CHEERING MEGAPHONE;So;0;ON;;;;;N;;;;; -1F4E4;OUTBOX TRAY;So;0;ON;;;;;N;;;;; -1F4E5;INBOX TRAY;So;0;ON;;;;;N;;;;; -1F4E6;PACKAGE;So;0;ON;;;;;N;;;;; -1F4E7;E-MAIL SYMBOL;So;0;ON;;;;;N;;;;; -1F4E8;INCOMING ENVELOPE;So;0;ON;;;;;N;;;;; -1F4E9;ENVELOPE WITH DOWNWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;; -1F4EA;CLOSED MAILBOX WITH LOWERED FLAG;So;0;ON;;;;;N;;;;; -1F4EB;CLOSED MAILBOX WITH RAISED FLAG;So;0;ON;;;;;N;;;;; -1F4EC;OPEN MAILBOX WITH RAISED FLAG;So;0;ON;;;;;N;;;;; -1F4ED;OPEN MAILBOX WITH LOWERED FLAG;So;0;ON;;;;;N;;;;; -1F4EE;POSTBOX;So;0;ON;;;;;N;;;;; -1F4EF;POSTAL HORN;So;0;ON;;;;;N;;;;; -1F4F0;NEWSPAPER;So;0;ON;;;;;N;;;;; -1F4F1;MOBILE PHONE;So;0;ON;;;;;N;;;;; -1F4F2;MOBILE PHONE WITH RIGHTWARDS ARROW AT LEFT;So;0;ON;;;;;N;;;;; -1F4F3;VIBRATION MODE;So;0;ON;;;;;N;;;;; -1F4F4;MOBILE PHONE OFF;So;0;ON;;;;;N;;;;; -1F4F5;NO MOBILE PHONES;So;0;ON;;;;;N;;;;; -1F4F6;ANTENNA WITH BARS;So;0;ON;;;;;N;;;;; -1F4F7;CAMERA;So;0;ON;;;;;N;;;;; -1F4F8;CAMERA WITH FLASH;So;0;ON;;;;;N;;;;; -1F4F9;VIDEO CAMERA;So;0;ON;;;;;N;;;;; -1F4FA;TELEVISION;So;0;ON;;;;;N;;;;; -1F4FB;RADIO;So;0;ON;;;;;N;;;;; -1F4FC;VIDEOCASSETTE;So;0;ON;;;;;N;;;;; -1F4FD;FILM PROJECTOR;So;0;ON;;;;;N;;;;; -1F4FE;PORTABLE STEREO;So;0;ON;;;;;N;;;;; -1F4FF;PRAYER BEADS;So;0;ON;;;;;N;;;;; -1F500;TWISTED RIGHTWARDS ARROWS;So;0;ON;;;;;N;;;;; -1F501;CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS;So;0;ON;;;;;N;;;;; -1F502;CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS WITH CIRCLED ONE OVERLAY;So;0;ON;;;;;N;;;;; -1F503;CLOCKWISE DOWNWARDS AND UPWARDS OPEN CIRCLE ARROWS;So;0;ON;;;;;N;;;;; -1F504;ANTICLOCKWISE DOWNWARDS AND UPWARDS OPEN CIRCLE ARROWS;So;0;ON;;;;;N;;;;; -1F505;LOW BRIGHTNESS SYMBOL;So;0;ON;;;;;N;;;;; -1F506;HIGH BRIGHTNESS SYMBOL;So;0;ON;;;;;N;;;;; -1F507;SPEAKER WITH CANCELLATION STROKE;So;0;ON;;;;;N;;;;; -1F508;SPEAKER;So;0;ON;;;;;N;;;;; -1F509;SPEAKER WITH ONE SOUND WAVE;So;0;ON;;;;;N;;;;; -1F50A;SPEAKER WITH THREE SOUND WAVES;So;0;ON;;;;;N;;;;; -1F50B;BATTERY;So;0;ON;;;;;N;;;;; -1F50C;ELECTRIC PLUG;So;0;ON;;;;;N;;;;; -1F50D;LEFT-POINTING MAGNIFYING GLASS;So;0;ON;;;;;N;;;;; -1F50E;RIGHT-POINTING MAGNIFYING GLASS;So;0;ON;;;;;N;;;;; -1F50F;LOCK WITH INK PEN;So;0;ON;;;;;N;;;;; -1F510;CLOSED LOCK WITH KEY;So;0;ON;;;;;N;;;;; -1F511;KEY;So;0;ON;;;;;N;;;;; -1F512;LOCK;So;0;ON;;;;;N;;;;; -1F513;OPEN LOCK;So;0;ON;;;;;N;;;;; -1F514;BELL;So;0;ON;;;;;N;;;;; -1F515;BELL WITH CANCELLATION STROKE;So;0;ON;;;;;N;;;;; -1F516;BOOKMARK;So;0;ON;;;;;N;;;;; -1F517;LINK SYMBOL;So;0;ON;;;;;N;;;;; -1F518;RADIO BUTTON;So;0;ON;;;;;N;;;;; -1F519;BACK WITH LEFTWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;; -1F51A;END WITH LEFTWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;; -1F51B;ON WITH EXCLAMATION MARK WITH LEFT RIGHT ARROW ABOVE;So;0;ON;;;;;N;;;;; -1F51C;SOON WITH RIGHTWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;; -1F51D;TOP WITH UPWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;; -1F51E;NO ONE UNDER EIGHTEEN SYMBOL;So;0;ON;;;;;N;;;;; -1F51F;KEYCAP TEN;So;0;ON;;;;;N;;;;; -1F520;INPUT SYMBOL FOR LATIN CAPITAL LETTERS;So;0;ON;;;;;N;;;;; -1F521;INPUT SYMBOL FOR LATIN SMALL LETTERS;So;0;ON;;;;;N;;;;; -1F522;INPUT SYMBOL FOR NUMBERS;So;0;ON;;;;;N;;;;; -1F523;INPUT SYMBOL FOR SYMBOLS;So;0;ON;;;;;N;;;;; -1F524;INPUT SYMBOL FOR LATIN LETTERS;So;0;ON;;;;;N;;;;; -1F525;FIRE;So;0;ON;;;;;N;;;;; -1F526;ELECTRIC TORCH;So;0;ON;;;;;N;;;;; -1F527;WRENCH;So;0;ON;;;;;N;;;;; -1F528;HAMMER;So;0;ON;;;;;N;;;;; -1F529;NUT AND BOLT;So;0;ON;;;;;N;;;;; -1F52A;HOCHO;So;0;ON;;;;;N;;;;; -1F52B;PISTOL;So;0;ON;;;;;N;;;;; -1F52C;MICROSCOPE;So;0;ON;;;;;N;;;;; -1F52D;TELESCOPE;So;0;ON;;;;;N;;;;; -1F52E;CRYSTAL BALL;So;0;ON;;;;;N;;;;; -1F52F;SIX POINTED STAR WITH MIDDLE DOT;So;0;ON;;;;;N;;;;; -1F530;JAPANESE SYMBOL FOR BEGINNER;So;0;ON;;;;;N;;;;; -1F531;TRIDENT EMBLEM;So;0;ON;;;;;N;;;;; -1F532;BLACK SQUARE BUTTON;So;0;ON;;;;;N;;;;; -1F533;WHITE SQUARE BUTTON;So;0;ON;;;;;N;;;;; -1F534;LARGE RED CIRCLE;So;0;ON;;;;;N;;;;; -1F535;LARGE BLUE CIRCLE;So;0;ON;;;;;N;;;;; -1F536;LARGE ORANGE DIAMOND;So;0;ON;;;;;N;;;;; -1F537;LARGE BLUE DIAMOND;So;0;ON;;;;;N;;;;; -1F538;SMALL ORANGE DIAMOND;So;0;ON;;;;;N;;;;; -1F539;SMALL BLUE DIAMOND;So;0;ON;;;;;N;;;;; -1F53A;UP-POINTING RED TRIANGLE;So;0;ON;;;;;N;;;;; -1F53B;DOWN-POINTING RED TRIANGLE;So;0;ON;;;;;N;;;;; -1F53C;UP-POINTING SMALL RED TRIANGLE;So;0;ON;;;;;N;;;;; -1F53D;DOWN-POINTING SMALL RED TRIANGLE;So;0;ON;;;;;N;;;;; -1F53E;LOWER RIGHT SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;; -1F53F;UPPER RIGHT SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;; -1F540;CIRCLED CROSS POMMEE;So;0;ON;;;;;N;;;;; -1F541;CROSS POMMEE WITH HALF-CIRCLE BELOW;So;0;ON;;;;;N;;;;; -1F542;CROSS POMMEE;So;0;ON;;;;;N;;;;; -1F543;NOTCHED LEFT SEMICIRCLE WITH THREE DOTS;So;0;ON;;;;;N;;;;; -1F544;NOTCHED RIGHT SEMICIRCLE WITH THREE DOTS;So;0;ON;;;;;N;;;;; -1F545;SYMBOL FOR MARKS CHAPTER;So;0;ON;;;;;N;;;;; -1F546;WHITE LATIN CROSS;So;0;ON;;;;;N;;;;; -1F547;HEAVY LATIN CROSS;So;0;ON;;;;;N;;;;; -1F548;CELTIC CROSS;So;0;ON;;;;;N;;;;; -1F549;OM SYMBOL;So;0;ON;;;;;N;;;;; -1F54A;DOVE OF PEACE;So;0;ON;;;;;N;;;;; -1F54B;KAABA;So;0;ON;;;;;N;;;;; -1F54C;MOSQUE;So;0;ON;;;;;N;;;;; -1F54D;SYNAGOGUE;So;0;ON;;;;;N;;;;; -1F54E;MENORAH WITH NINE BRANCHES;So;0;ON;;;;;N;;;;; -1F54F;BOWL OF HYGIEIA;So;0;ON;;;;;N;;;;; -1F550;CLOCK FACE ONE OCLOCK;So;0;ON;;;;;N;;;;; -1F551;CLOCK FACE TWO OCLOCK;So;0;ON;;;;;N;;;;; -1F552;CLOCK FACE THREE OCLOCK;So;0;ON;;;;;N;;;;; -1F553;CLOCK FACE FOUR OCLOCK;So;0;ON;;;;;N;;;;; -1F554;CLOCK FACE FIVE OCLOCK;So;0;ON;;;;;N;;;;; -1F555;CLOCK FACE SIX OCLOCK;So;0;ON;;;;;N;;;;; -1F556;CLOCK FACE SEVEN OCLOCK;So;0;ON;;;;;N;;;;; -1F557;CLOCK FACE EIGHT OCLOCK;So;0;ON;;;;;N;;;;; -1F558;CLOCK FACE NINE OCLOCK;So;0;ON;;;;;N;;;;; -1F559;CLOCK FACE TEN OCLOCK;So;0;ON;;;;;N;;;;; -1F55A;CLOCK FACE ELEVEN OCLOCK;So;0;ON;;;;;N;;;;; -1F55B;CLOCK FACE TWELVE OCLOCK;So;0;ON;;;;;N;;;;; -1F55C;CLOCK FACE ONE-THIRTY;So;0;ON;;;;;N;;;;; -1F55D;CLOCK FACE TWO-THIRTY;So;0;ON;;;;;N;;;;; -1F55E;CLOCK FACE THREE-THIRTY;So;0;ON;;;;;N;;;;; -1F55F;CLOCK FACE FOUR-THIRTY;So;0;ON;;;;;N;;;;; -1F560;CLOCK FACE FIVE-THIRTY;So;0;ON;;;;;N;;;;; -1F561;CLOCK FACE SIX-THIRTY;So;0;ON;;;;;N;;;;; -1F562;CLOCK FACE SEVEN-THIRTY;So;0;ON;;;;;N;;;;; -1F563;CLOCK FACE EIGHT-THIRTY;So;0;ON;;;;;N;;;;; -1F564;CLOCK FACE NINE-THIRTY;So;0;ON;;;;;N;;;;; -1F565;CLOCK FACE TEN-THIRTY;So;0;ON;;;;;N;;;;; -1F566;CLOCK FACE ELEVEN-THIRTY;So;0;ON;;;;;N;;;;; -1F567;CLOCK FACE TWELVE-THIRTY;So;0;ON;;;;;N;;;;; -1F568;RIGHT SPEAKER;So;0;ON;;;;;N;;;;; -1F569;RIGHT SPEAKER WITH ONE SOUND WAVE;So;0;ON;;;;;N;;;;; -1F56A;RIGHT SPEAKER WITH THREE SOUND WAVES;So;0;ON;;;;;N;;;;; -1F56B;BULLHORN;So;0;ON;;;;;N;;;;; -1F56C;BULLHORN WITH SOUND WAVES;So;0;ON;;;;;N;;;;; -1F56D;RINGING BELL;So;0;ON;;;;;N;;;;; -1F56E;BOOK;So;0;ON;;;;;N;;;;; -1F56F;CANDLE;So;0;ON;;;;;N;;;;; -1F570;MANTELPIECE CLOCK;So;0;ON;;;;;N;;;;; -1F571;BLACK SKULL AND CROSSBONES;So;0;ON;;;;;N;;;;; -1F572;NO PIRACY;So;0;ON;;;;;N;;;;; -1F573;HOLE;So;0;ON;;;;;N;;;;; -1F574;MAN IN BUSINESS SUIT LEVITATING;So;0;ON;;;;;N;;;;; -1F575;SLEUTH OR SPY;So;0;ON;;;;;N;;;;; -1F576;DARK SUNGLASSES;So;0;ON;;;;;N;;;;; -1F577;SPIDER;So;0;ON;;;;;N;;;;; -1F578;SPIDER WEB;So;0;ON;;;;;N;;;;; -1F579;JOYSTICK;So;0;ON;;;;;N;;;;; -1F57A;MAN DANCING;So;0;ON;;;;;N;;;;; -1F57B;LEFT HAND TELEPHONE RECEIVER;So;0;ON;;;;;N;;;;; -1F57C;TELEPHONE RECEIVER WITH PAGE;So;0;ON;;;;;N;;;;; -1F57D;RIGHT HAND TELEPHONE RECEIVER;So;0;ON;;;;;N;;;;; -1F57E;WHITE TOUCHTONE TELEPHONE;So;0;ON;;;;;N;;;;; -1F57F;BLACK TOUCHTONE TELEPHONE;So;0;ON;;;;;N;;;;; -1F580;TELEPHONE ON TOP OF MODEM;So;0;ON;;;;;N;;;;; -1F581;CLAMSHELL MOBILE PHONE;So;0;ON;;;;;N;;;;; -1F582;BACK OF ENVELOPE;So;0;ON;;;;;N;;;;; -1F583;STAMPED ENVELOPE;So;0;ON;;;;;N;;;;; -1F584;ENVELOPE WITH LIGHTNING;So;0;ON;;;;;N;;;;; -1F585;FLYING ENVELOPE;So;0;ON;;;;;N;;;;; -1F586;PEN OVER STAMPED ENVELOPE;So;0;ON;;;;;N;;;;; -1F587;LINKED PAPERCLIPS;So;0;ON;;;;;N;;;;; -1F588;BLACK PUSHPIN;So;0;ON;;;;;N;;;;; -1F589;LOWER LEFT PENCIL;So;0;ON;;;;;N;;;;; -1F58A;LOWER LEFT BALLPOINT PEN;So;0;ON;;;;;N;;;;; -1F58B;LOWER LEFT FOUNTAIN PEN;So;0;ON;;;;;N;;;;; -1F58C;LOWER LEFT PAINTBRUSH;So;0;ON;;;;;N;;;;; -1F58D;LOWER LEFT CRAYON;So;0;ON;;;;;N;;;;; -1F58E;LEFT WRITING HAND;So;0;ON;;;;;N;;;;; -1F58F;TURNED OK HAND SIGN;So;0;ON;;;;;N;;;;; -1F590;RAISED HAND WITH FINGERS SPLAYED;So;0;ON;;;;;N;;;;; -1F591;REVERSED RAISED HAND WITH FINGERS SPLAYED;So;0;ON;;;;;N;;;;; -1F592;REVERSED THUMBS UP SIGN;So;0;ON;;;;;N;;;;; -1F593;REVERSED THUMBS DOWN SIGN;So;0;ON;;;;;N;;;;; -1F594;REVERSED VICTORY HAND;So;0;ON;;;;;N;;;;; -1F595;REVERSED HAND WITH MIDDLE FINGER EXTENDED;So;0;ON;;;;;N;;;;; -1F596;RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS;So;0;ON;;;;;N;;;;; -1F597;WHITE DOWN POINTING LEFT HAND INDEX;So;0;ON;;;;;N;;;;; -1F598;SIDEWAYS WHITE LEFT POINTING INDEX;So;0;ON;;;;;N;;;;; -1F599;SIDEWAYS WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; -1F59A;SIDEWAYS BLACK LEFT POINTING INDEX;So;0;ON;;;;;N;;;;; -1F59B;SIDEWAYS BLACK RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; -1F59C;BLACK LEFT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; -1F59D;BLACK RIGHT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; -1F59E;SIDEWAYS WHITE UP POINTING INDEX;So;0;ON;;;;;N;;;;; -1F59F;SIDEWAYS WHITE DOWN POINTING INDEX;So;0;ON;;;;;N;;;;; -1F5A0;SIDEWAYS BLACK UP POINTING INDEX;So;0;ON;;;;;N;;;;; -1F5A1;SIDEWAYS BLACK DOWN POINTING INDEX;So;0;ON;;;;;N;;;;; -1F5A2;BLACK UP POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; -1F5A3;BLACK DOWN POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; -1F5A4;BLACK HEART;So;0;ON;;;;;N;;;;; -1F5A5;DESKTOP COMPUTER;So;0;ON;;;;;N;;;;; -1F5A6;KEYBOARD AND MOUSE;So;0;ON;;;;;N;;;;; -1F5A7;THREE NETWORKED COMPUTERS;So;0;ON;;;;;N;;;;; -1F5A8;PRINTER;So;0;ON;;;;;N;;;;; -1F5A9;POCKET CALCULATOR;So;0;ON;;;;;N;;;;; -1F5AA;BLACK HARD SHELL FLOPPY DISK;So;0;ON;;;;;N;;;;; -1F5AB;WHITE HARD SHELL FLOPPY DISK;So;0;ON;;;;;N;;;;; -1F5AC;SOFT SHELL FLOPPY DISK;So;0;ON;;;;;N;;;;; -1F5AD;TAPE CARTRIDGE;So;0;ON;;;;;N;;;;; -1F5AE;WIRED KEYBOARD;So;0;ON;;;;;N;;;;; -1F5AF;ONE BUTTON MOUSE;So;0;ON;;;;;N;;;;; -1F5B0;TWO BUTTON MOUSE;So;0;ON;;;;;N;;;;; -1F5B1;THREE BUTTON MOUSE;So;0;ON;;;;;N;;;;; -1F5B2;TRACKBALL;So;0;ON;;;;;N;;;;; -1F5B3;OLD PERSONAL COMPUTER;So;0;ON;;;;;N;;;;; -1F5B4;HARD DISK;So;0;ON;;;;;N;;;;; -1F5B5;SCREEN;So;0;ON;;;;;N;;;;; -1F5B6;PRINTER ICON;So;0;ON;;;;;N;;;;; -1F5B7;FAX ICON;So;0;ON;;;;;N;;;;; -1F5B8;OPTICAL DISC ICON;So;0;ON;;;;;N;;;;; -1F5B9;DOCUMENT WITH TEXT;So;0;ON;;;;;N;;;;; -1F5BA;DOCUMENT WITH TEXT AND PICTURE;So;0;ON;;;;;N;;;;; -1F5BB;DOCUMENT WITH PICTURE;So;0;ON;;;;;N;;;;; -1F5BC;FRAME WITH PICTURE;So;0;ON;;;;;N;;;;; -1F5BD;FRAME WITH TILES;So;0;ON;;;;;N;;;;; -1F5BE;FRAME WITH AN X;So;0;ON;;;;;N;;;;; -1F5BF;BLACK FOLDER;So;0;ON;;;;;N;;;;; -1F5C0;FOLDER;So;0;ON;;;;;N;;;;; -1F5C1;OPEN FOLDER;So;0;ON;;;;;N;;;;; -1F5C2;CARD INDEX DIVIDERS;So;0;ON;;;;;N;;;;; -1F5C3;CARD FILE BOX;So;0;ON;;;;;N;;;;; -1F5C4;FILE CABINET;So;0;ON;;;;;N;;;;; -1F5C5;EMPTY NOTE;So;0;ON;;;;;N;;;;; -1F5C6;EMPTY NOTE PAGE;So;0;ON;;;;;N;;;;; -1F5C7;EMPTY NOTE PAD;So;0;ON;;;;;N;;;;; -1F5C8;NOTE;So;0;ON;;;;;N;;;;; -1F5C9;NOTE PAGE;So;0;ON;;;;;N;;;;; -1F5CA;NOTE PAD;So;0;ON;;;;;N;;;;; -1F5CB;EMPTY DOCUMENT;So;0;ON;;;;;N;;;;; -1F5CC;EMPTY PAGE;So;0;ON;;;;;N;;;;; -1F5CD;EMPTY PAGES;So;0;ON;;;;;N;;;;; -1F5CE;DOCUMENT;So;0;ON;;;;;N;;;;; -1F5CF;PAGE;So;0;ON;;;;;N;;;;; -1F5D0;PAGES;So;0;ON;;;;;N;;;;; -1F5D1;WASTEBASKET;So;0;ON;;;;;N;;;;; -1F5D2;SPIRAL NOTE PAD;So;0;ON;;;;;N;;;;; -1F5D3;SPIRAL CALENDAR PAD;So;0;ON;;;;;N;;;;; -1F5D4;DESKTOP WINDOW;So;0;ON;;;;;N;;;;; -1F5D5;MINIMIZE;So;0;ON;;;;;N;;;;; -1F5D6;MAXIMIZE;So;0;ON;;;;;N;;;;; -1F5D7;OVERLAP;So;0;ON;;;;;N;;;;; -1F5D8;CLOCKWISE RIGHT AND LEFT SEMICIRCLE ARROWS;So;0;ON;;;;;N;;;;; -1F5D9;CANCELLATION X;So;0;ON;;;;;N;;;;; -1F5DA;INCREASE FONT SIZE SYMBOL;So;0;ON;;;;;N;;;;; -1F5DB;DECREASE FONT SIZE SYMBOL;So;0;ON;;;;;N;;;;; -1F5DC;COMPRESSION;So;0;ON;;;;;N;;;;; -1F5DD;OLD KEY;So;0;ON;;;;;N;;;;; -1F5DE;ROLLED-UP NEWSPAPER;So;0;ON;;;;;N;;;;; -1F5DF;PAGE WITH CIRCLED TEXT;So;0;ON;;;;;N;;;;; -1F5E0;STOCK CHART;So;0;ON;;;;;N;;;;; -1F5E1;DAGGER KNIFE;So;0;ON;;;;;N;;;;; -1F5E2;LIPS;So;0;ON;;;;;N;;;;; -1F5E3;SPEAKING HEAD IN SILHOUETTE;So;0;ON;;;;;N;;;;; -1F5E4;THREE RAYS ABOVE;So;0;ON;;;;;N;;;;; -1F5E5;THREE RAYS BELOW;So;0;ON;;;;;N;;;;; -1F5E6;THREE RAYS LEFT;So;0;ON;;;;;N;;;;; -1F5E7;THREE RAYS RIGHT;So;0;ON;;;;;N;;;;; -1F5E8;LEFT SPEECH BUBBLE;So;0;ON;;;;;N;;;;; -1F5E9;RIGHT SPEECH BUBBLE;So;0;ON;;;;;N;;;;; -1F5EA;TWO SPEECH BUBBLES;So;0;ON;;;;;N;;;;; -1F5EB;THREE SPEECH BUBBLES;So;0;ON;;;;;N;;;;; -1F5EC;LEFT THOUGHT BUBBLE;So;0;ON;;;;;N;;;;; -1F5ED;RIGHT THOUGHT BUBBLE;So;0;ON;;;;;N;;;;; -1F5EE;LEFT ANGER BUBBLE;So;0;ON;;;;;N;;;;; -1F5EF;RIGHT ANGER BUBBLE;So;0;ON;;;;;N;;;;; -1F5F0;MOOD BUBBLE;So;0;ON;;;;;N;;;;; -1F5F1;LIGHTNING MOOD BUBBLE;So;0;ON;;;;;N;;;;; -1F5F2;LIGHTNING MOOD;So;0;ON;;;;;N;;;;; -1F5F3;BALLOT BOX WITH BALLOT;So;0;ON;;;;;N;;;;; -1F5F4;BALLOT SCRIPT X;So;0;ON;;;;;N;;;;; -1F5F5;BALLOT BOX WITH SCRIPT X;So;0;ON;;;;;N;;;;; -1F5F6;BALLOT BOLD SCRIPT X;So;0;ON;;;;;N;;;;; -1F5F7;BALLOT BOX WITH BOLD SCRIPT X;So;0;ON;;;;;N;;;;; -1F5F8;LIGHT CHECK MARK;So;0;ON;;;;;N;;;;; -1F5F9;BALLOT BOX WITH BOLD CHECK;So;0;ON;;;;;N;;;;; -1F5FA;WORLD MAP;So;0;ON;;;;;N;;;;; -1F5FB;MOUNT FUJI;So;0;ON;;;;;N;;;;; -1F5FC;TOKYO TOWER;So;0;ON;;;;;N;;;;; -1F5FD;STATUE OF LIBERTY;So;0;ON;;;;;N;;;;; -1F5FE;SILHOUETTE OF JAPAN;So;0;ON;;;;;N;;;;; -1F5FF;MOYAI;So;0;ON;;;;;N;;;;; -1F600;GRINNING FACE;So;0;ON;;;;;N;;;;; -1F601;GRINNING FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;; -1F602;FACE WITH TEARS OF JOY;So;0;ON;;;;;N;;;;; -1F603;SMILING FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; -1F604;SMILING FACE WITH OPEN MOUTH AND SMILING EYES;So;0;ON;;;;;N;;;;; -1F605;SMILING FACE WITH OPEN MOUTH AND COLD SWEAT;So;0;ON;;;;;N;;;;; -1F606;SMILING FACE WITH OPEN MOUTH AND TIGHTLY-CLOSED EYES;So;0;ON;;;;;N;;;;; -1F607;SMILING FACE WITH HALO;So;0;ON;;;;;N;;;;; -1F608;SMILING FACE WITH HORNS;So;0;ON;;;;;N;;;;; -1F609;WINKING FACE;So;0;ON;;;;;N;;;;; -1F60A;SMILING FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;; -1F60B;FACE SAVOURING DELICIOUS FOOD;So;0;ON;;;;;N;;;;; -1F60C;RELIEVED FACE;So;0;ON;;;;;N;;;;; -1F60D;SMILING FACE WITH HEART-SHAPED EYES;So;0;ON;;;;;N;;;;; -1F60E;SMILING FACE WITH SUNGLASSES;So;0;ON;;;;;N;;;;; -1F60F;SMIRKING FACE;So;0;ON;;;;;N;;;;; -1F610;NEUTRAL FACE;So;0;ON;;;;;N;;;;; -1F611;EXPRESSIONLESS FACE;So;0;ON;;;;;N;;;;; -1F612;UNAMUSED FACE;So;0;ON;;;;;N;;;;; -1F613;FACE WITH COLD SWEAT;So;0;ON;;;;;N;;;;; -1F614;PENSIVE FACE;So;0;ON;;;;;N;;;;; -1F615;CONFUSED FACE;So;0;ON;;;;;N;;;;; -1F616;CONFOUNDED FACE;So;0;ON;;;;;N;;;;; -1F617;KISSING FACE;So;0;ON;;;;;N;;;;; -1F618;FACE THROWING A KISS;So;0;ON;;;;;N;;;;; -1F619;KISSING FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;; -1F61A;KISSING FACE WITH CLOSED EYES;So;0;ON;;;;;N;;;;; -1F61B;FACE WITH STUCK-OUT TONGUE;So;0;ON;;;;;N;;;;; -1F61C;FACE WITH STUCK-OUT TONGUE AND WINKING EYE;So;0;ON;;;;;N;;;;; -1F61D;FACE WITH STUCK-OUT TONGUE AND TIGHTLY-CLOSED EYES;So;0;ON;;;;;N;;;;; -1F61E;DISAPPOINTED FACE;So;0;ON;;;;;N;;;;; -1F61F;WORRIED FACE;So;0;ON;;;;;N;;;;; -1F620;ANGRY FACE;So;0;ON;;;;;N;;;;; -1F621;POUTING FACE;So;0;ON;;;;;N;;;;; -1F622;CRYING FACE;So;0;ON;;;;;N;;;;; -1F623;PERSEVERING FACE;So;0;ON;;;;;N;;;;; -1F624;FACE WITH LOOK OF TRIUMPH;So;0;ON;;;;;N;;;;; -1F625;DISAPPOINTED BUT RELIEVED FACE;So;0;ON;;;;;N;;;;; -1F626;FROWNING FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; -1F627;ANGUISHED FACE;So;0;ON;;;;;N;;;;; -1F628;FEARFUL FACE;So;0;ON;;;;;N;;;;; -1F629;WEARY FACE;So;0;ON;;;;;N;;;;; -1F62A;SLEEPY FACE;So;0;ON;;;;;N;;;;; -1F62B;TIRED FACE;So;0;ON;;;;;N;;;;; -1F62C;GRIMACING FACE;So;0;ON;;;;;N;;;;; -1F62D;LOUDLY CRYING FACE;So;0;ON;;;;;N;;;;; -1F62E;FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; -1F62F;HUSHED FACE;So;0;ON;;;;;N;;;;; -1F630;FACE WITH OPEN MOUTH AND COLD SWEAT;So;0;ON;;;;;N;;;;; -1F631;FACE SCREAMING IN FEAR;So;0;ON;;;;;N;;;;; -1F632;ASTONISHED FACE;So;0;ON;;;;;N;;;;; -1F633;FLUSHED FACE;So;0;ON;;;;;N;;;;; -1F634;SLEEPING FACE;So;0;ON;;;;;N;;;;; -1F635;DIZZY FACE;So;0;ON;;;;;N;;;;; -1F636;FACE WITHOUT MOUTH;So;0;ON;;;;;N;;;;; -1F637;FACE WITH MEDICAL MASK;So;0;ON;;;;;N;;;;; -1F638;GRINNING CAT FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;; -1F639;CAT FACE WITH TEARS OF JOY;So;0;ON;;;;;N;;;;; -1F63A;SMILING CAT FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; -1F63B;SMILING CAT FACE WITH HEART-SHAPED EYES;So;0;ON;;;;;N;;;;; -1F63C;CAT FACE WITH WRY SMILE;So;0;ON;;;;;N;;;;; -1F63D;KISSING CAT FACE WITH CLOSED EYES;So;0;ON;;;;;N;;;;; -1F63E;POUTING CAT FACE;So;0;ON;;;;;N;;;;; -1F63F;CRYING CAT FACE;So;0;ON;;;;;N;;;;; -1F640;WEARY CAT FACE;So;0;ON;;;;;N;;;;; -1F641;SLIGHTLY FROWNING FACE;So;0;ON;;;;;N;;;;; -1F642;SLIGHTLY SMILING FACE;So;0;ON;;;;;N;;;;; -1F643;UPSIDE-DOWN FACE;So;0;ON;;;;;N;;;;; -1F644;FACE WITH ROLLING EYES;So;0;ON;;;;;N;;;;; -1F645;FACE WITH NO GOOD GESTURE;So;0;ON;;;;;N;;;;; -1F646;FACE WITH OK GESTURE;So;0;ON;;;;;N;;;;; -1F647;PERSON BOWING DEEPLY;So;0;ON;;;;;N;;;;; -1F648;SEE-NO-EVIL MONKEY;So;0;ON;;;;;N;;;;; -1F649;HEAR-NO-EVIL MONKEY;So;0;ON;;;;;N;;;;; -1F64A;SPEAK-NO-EVIL MONKEY;So;0;ON;;;;;N;;;;; -1F64B;HAPPY PERSON RAISING ONE HAND;So;0;ON;;;;;N;;;;; -1F64C;PERSON RAISING BOTH HANDS IN CELEBRATION;So;0;ON;;;;;N;;;;; -1F64D;PERSON FROWNING;So;0;ON;;;;;N;;;;; -1F64E;PERSON WITH POUTING FACE;So;0;ON;;;;;N;;;;; -1F64F;PERSON WITH FOLDED HANDS;So;0;ON;;;;;N;;;;; -1F650;NORTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;; -1F651;SOUTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;; -1F652;NORTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;; -1F653;SOUTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;; -1F654;TURNED NORTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;; -1F655;TURNED SOUTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;; -1F656;TURNED NORTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;; -1F657;TURNED SOUTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;; -1F658;NORTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; -1F659;SOUTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; -1F65A;NORTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; -1F65B;SOUTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; -1F65C;HEAVY NORTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; -1F65D;HEAVY SOUTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; -1F65E;HEAVY NORTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; -1F65F;HEAVY SOUTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; -1F660;NORTH WEST POINTING BUD;So;0;ON;;;;;N;;;;; -1F661;SOUTH WEST POINTING BUD;So;0;ON;;;;;N;;;;; -1F662;NORTH EAST POINTING BUD;So;0;ON;;;;;N;;;;; -1F663;SOUTH EAST POINTING BUD;So;0;ON;;;;;N;;;;; -1F664;HEAVY NORTH WEST POINTING BUD;So;0;ON;;;;;N;;;;; -1F665;HEAVY SOUTH WEST POINTING BUD;So;0;ON;;;;;N;;;;; -1F666;HEAVY NORTH EAST POINTING BUD;So;0;ON;;;;;N;;;;; -1F667;HEAVY SOUTH EAST POINTING BUD;So;0;ON;;;;;N;;;;; -1F668;HOLLOW QUILT SQUARE ORNAMENT;So;0;ON;;;;;N;;;;; -1F669;HOLLOW QUILT SQUARE ORNAMENT IN BLACK SQUARE;So;0;ON;;;;;N;;;;; -1F66A;SOLID QUILT SQUARE ORNAMENT;So;0;ON;;;;;N;;;;; -1F66B;SOLID QUILT SQUARE ORNAMENT IN BLACK SQUARE;So;0;ON;;;;;N;;;;; -1F66C;LEFTWARDS ROCKET;So;0;ON;;;;;N;;;;; -1F66D;UPWARDS ROCKET;So;0;ON;;;;;N;;;;; -1F66E;RIGHTWARDS ROCKET;So;0;ON;;;;;N;;;;; -1F66F;DOWNWARDS ROCKET;So;0;ON;;;;;N;;;;; -1F670;SCRIPT LIGATURE ET ORNAMENT;So;0;ON;;;;;N;;;;; -1F671;HEAVY SCRIPT LIGATURE ET ORNAMENT;So;0;ON;;;;;N;;;;; -1F672;LIGATURE OPEN ET ORNAMENT;So;0;ON;;;;;N;;;;; -1F673;HEAVY LIGATURE OPEN ET ORNAMENT;So;0;ON;;;;;N;;;;; -1F674;HEAVY AMPERSAND ORNAMENT;So;0;ON;;;;;N;;;;; -1F675;SWASH AMPERSAND ORNAMENT;So;0;ON;;;;;N;;;;; -1F676;SANS-SERIF HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; -1F677;SANS-SERIF HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; -1F678;SANS-SERIF HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; -1F679;HEAVY INTERROBANG ORNAMENT;So;0;ON;;;;;N;;;;; -1F67A;SANS-SERIF INTERROBANG ORNAMENT;So;0;ON;;;;;N;;;;; -1F67B;HEAVY SANS-SERIF INTERROBANG ORNAMENT;So;0;ON;;;;;N;;;;; -1F67C;VERY HEAVY SOLIDUS;So;0;ON;;;;;N;;;;; -1F67D;VERY HEAVY REVERSE SOLIDUS;So;0;ON;;;;;N;;;;; -1F67E;CHECKER BOARD;So;0;ON;;;;;N;;;;; -1F67F;REVERSE CHECKER BOARD;So;0;ON;;;;;N;;;;; -1F680;ROCKET;So;0;ON;;;;;N;;;;; -1F681;HELICOPTER;So;0;ON;;;;;N;;;;; -1F682;STEAM LOCOMOTIVE;So;0;ON;;;;;N;;;;; -1F683;RAILWAY CAR;So;0;ON;;;;;N;;;;; -1F684;HIGH-SPEED TRAIN;So;0;ON;;;;;N;;;;; -1F685;HIGH-SPEED TRAIN WITH BULLET NOSE;So;0;ON;;;;;N;;;;; -1F686;TRAIN;So;0;ON;;;;;N;;;;; -1F687;METRO;So;0;ON;;;;;N;;;;; -1F688;LIGHT RAIL;So;0;ON;;;;;N;;;;; -1F689;STATION;So;0;ON;;;;;N;;;;; -1F68A;TRAM;So;0;ON;;;;;N;;;;; -1F68B;TRAM CAR;So;0;ON;;;;;N;;;;; -1F68C;BUS;So;0;ON;;;;;N;;;;; -1F68D;ONCOMING BUS;So;0;ON;;;;;N;;;;; -1F68E;TROLLEYBUS;So;0;ON;;;;;N;;;;; -1F68F;BUS STOP;So;0;ON;;;;;N;;;;; -1F690;MINIBUS;So;0;ON;;;;;N;;;;; -1F691;AMBULANCE;So;0;ON;;;;;N;;;;; -1F692;FIRE ENGINE;So;0;ON;;;;;N;;;;; -1F693;POLICE CAR;So;0;ON;;;;;N;;;;; -1F694;ONCOMING POLICE CAR;So;0;ON;;;;;N;;;;; -1F695;TAXI;So;0;ON;;;;;N;;;;; -1F696;ONCOMING TAXI;So;0;ON;;;;;N;;;;; -1F697;AUTOMOBILE;So;0;ON;;;;;N;;;;; -1F698;ONCOMING AUTOMOBILE;So;0;ON;;;;;N;;;;; -1F699;RECREATIONAL VEHICLE;So;0;ON;;;;;N;;;;; -1F69A;DELIVERY TRUCK;So;0;ON;;;;;N;;;;; -1F69B;ARTICULATED LORRY;So;0;ON;;;;;N;;;;; -1F69C;TRACTOR;So;0;ON;;;;;N;;;;; -1F69D;MONORAIL;So;0;ON;;;;;N;;;;; -1F69E;MOUNTAIN RAILWAY;So;0;ON;;;;;N;;;;; -1F69F;SUSPENSION RAILWAY;So;0;ON;;;;;N;;;;; -1F6A0;MOUNTAIN CABLEWAY;So;0;ON;;;;;N;;;;; -1F6A1;AERIAL TRAMWAY;So;0;ON;;;;;N;;;;; -1F6A2;SHIP;So;0;ON;;;;;N;;;;; -1F6A3;ROWBOAT;So;0;ON;;;;;N;;;;; -1F6A4;SPEEDBOAT;So;0;ON;;;;;N;;;;; -1F6A5;HORIZONTAL TRAFFIC LIGHT;So;0;ON;;;;;N;;;;; -1F6A6;VERTICAL TRAFFIC LIGHT;So;0;ON;;;;;N;;;;; -1F6A7;CONSTRUCTION SIGN;So;0;ON;;;;;N;;;;; -1F6A8;POLICE CARS REVOLVING LIGHT;So;0;ON;;;;;N;;;;; -1F6A9;TRIANGULAR FLAG ON POST;So;0;ON;;;;;N;;;;; -1F6AA;DOOR;So;0;ON;;;;;N;;;;; -1F6AB;NO ENTRY SIGN;So;0;ON;;;;;N;;;;; -1F6AC;SMOKING SYMBOL;So;0;ON;;;;;N;;;;; -1F6AD;NO SMOKING SYMBOL;So;0;ON;;;;;N;;;;; -1F6AE;PUT LITTER IN ITS PLACE SYMBOL;So;0;ON;;;;;N;;;;; -1F6AF;DO NOT LITTER SYMBOL;So;0;ON;;;;;N;;;;; -1F6B0;POTABLE WATER SYMBOL;So;0;ON;;;;;N;;;;; -1F6B1;NON-POTABLE WATER SYMBOL;So;0;ON;;;;;N;;;;; -1F6B2;BICYCLE;So;0;ON;;;;;N;;;;; -1F6B3;NO BICYCLES;So;0;ON;;;;;N;;;;; -1F6B4;BICYCLIST;So;0;ON;;;;;N;;;;; -1F6B5;MOUNTAIN BICYCLIST;So;0;ON;;;;;N;;;;; -1F6B6;PEDESTRIAN;So;0;ON;;;;;N;;;;; -1F6B7;NO PEDESTRIANS;So;0;ON;;;;;N;;;;; -1F6B8;CHILDREN CROSSING;So;0;ON;;;;;N;;;;; -1F6B9;MENS SYMBOL;So;0;ON;;;;;N;;;;; -1F6BA;WOMENS SYMBOL;So;0;ON;;;;;N;;;;; -1F6BB;RESTROOM;So;0;ON;;;;;N;;;;; -1F6BC;BABY SYMBOL;So;0;ON;;;;;N;;;;; -1F6BD;TOILET;So;0;ON;;;;;N;;;;; -1F6BE;WATER CLOSET;So;0;ON;;;;;N;;;;; -1F6BF;SHOWER;So;0;ON;;;;;N;;;;; -1F6C0;BATH;So;0;ON;;;;;N;;;;; -1F6C1;BATHTUB;So;0;ON;;;;;N;;;;; -1F6C2;PASSPORT CONTROL;So;0;ON;;;;;N;;;;; -1F6C3;CUSTOMS;So;0;ON;;;;;N;;;;; -1F6C4;BAGGAGE CLAIM;So;0;ON;;;;;N;;;;; -1F6C5;LEFT LUGGAGE;So;0;ON;;;;;N;;;;; -1F6C6;TRIANGLE WITH ROUNDED CORNERS;So;0;ON;;;;;N;;;;; -1F6C7;PROHIBITED SIGN;So;0;ON;;;;;N;;;;; -1F6C8;CIRCLED INFORMATION SOURCE;So;0;ON;;;;;N;;;;; -1F6C9;BOYS SYMBOL;So;0;ON;;;;;N;;;;; -1F6CA;GIRLS SYMBOL;So;0;ON;;;;;N;;;;; -1F6CB;COUCH AND LAMP;So;0;ON;;;;;N;;;;; -1F6CC;SLEEPING ACCOMMODATION;So;0;ON;;;;;N;;;;; -1F6CD;SHOPPING BAGS;So;0;ON;;;;;N;;;;; -1F6CE;BELLHOP BELL;So;0;ON;;;;;N;;;;; -1F6CF;BED;So;0;ON;;;;;N;;;;; -1F6D0;PLACE OF WORSHIP;So;0;ON;;;;;N;;;;; -1F6D1;OCTAGONAL SIGN;So;0;ON;;;;;N;;;;; -1F6D2;SHOPPING TROLLEY;So;0;ON;;;;;N;;;;; -1F6D3;STUPA;So;0;ON;;;;;N;;;;; -1F6D4;PAGODA;So;0;ON;;;;;N;;;;; -1F6D5;HINDU TEMPLE;So;0;ON;;;;;N;;;;; -1F6D6;HUT;So;0;ON;;;;;N;;;;; -1F6D7;ELEVATOR;So;0;ON;;;;;N;;;;; -1F6DC;WIRELESS;So;0;ON;;;;;N;;;;; -1F6DD;PLAYGROUND SLIDE;So;0;ON;;;;;N;;;;; -1F6DE;WHEEL;So;0;ON;;;;;N;;;;; -1F6DF;RING BUOY;So;0;ON;;;;;N;;;;; -1F6E0;HAMMER AND WRENCH;So;0;ON;;;;;N;;;;; -1F6E1;SHIELD;So;0;ON;;;;;N;;;;; -1F6E2;OIL DRUM;So;0;ON;;;;;N;;;;; -1F6E3;MOTORWAY;So;0;ON;;;;;N;;;;; -1F6E4;RAILWAY TRACK;So;0;ON;;;;;N;;;;; -1F6E5;MOTOR BOAT;So;0;ON;;;;;N;;;;; -1F6E6;UP-POINTING MILITARY AIRPLANE;So;0;ON;;;;;N;;;;; -1F6E7;UP-POINTING AIRPLANE;So;0;ON;;;;;N;;;;; -1F6E8;UP-POINTING SMALL AIRPLANE;So;0;ON;;;;;N;;;;; -1F6E9;SMALL AIRPLANE;So;0;ON;;;;;N;;;;; -1F6EA;NORTHEAST-POINTING AIRPLANE;So;0;ON;;;;;N;;;;; -1F6EB;AIRPLANE DEPARTURE;So;0;ON;;;;;N;;;;; -1F6EC;AIRPLANE ARRIVING;So;0;ON;;;;;N;;;;; -1F6F0;SATELLITE;So;0;ON;;;;;N;;;;; -1F6F1;ONCOMING FIRE ENGINE;So;0;ON;;;;;N;;;;; -1F6F2;DIESEL LOCOMOTIVE;So;0;ON;;;;;N;;;;; -1F6F3;PASSENGER SHIP;So;0;ON;;;;;N;;;;; -1F6F4;SCOOTER;So;0;ON;;;;;N;;;;; -1F6F5;MOTOR SCOOTER;So;0;ON;;;;;N;;;;; -1F6F6;CANOE;So;0;ON;;;;;N;;;;; -1F6F7;SLED;So;0;ON;;;;;N;;;;; -1F6F8;FLYING SAUCER;So;0;ON;;;;;N;;;;; -1F6F9;SKATEBOARD;So;0;ON;;;;;N;;;;; -1F6FA;AUTO RICKSHAW;So;0;ON;;;;;N;;;;; -1F6FB;PICKUP TRUCK;So;0;ON;;;;;N;;;;; -1F6FC;ROLLER SKATE;So;0;ON;;;;;N;;;;; -1F700;ALCHEMICAL SYMBOL FOR QUINTESSENCE;So;0;ON;;;;;N;;;;; -1F701;ALCHEMICAL SYMBOL FOR AIR;So;0;ON;;;;;N;;;;; -1F702;ALCHEMICAL SYMBOL FOR FIRE;So;0;ON;;;;;N;;;;; -1F703;ALCHEMICAL SYMBOL FOR EARTH;So;0;ON;;;;;N;;;;; -1F704;ALCHEMICAL SYMBOL FOR WATER;So;0;ON;;;;;N;;;;; -1F705;ALCHEMICAL SYMBOL FOR AQUAFORTIS;So;0;ON;;;;;N;;;;; -1F706;ALCHEMICAL SYMBOL FOR AQUA REGIA;So;0;ON;;;;;N;;;;; -1F707;ALCHEMICAL SYMBOL FOR AQUA REGIA-2;So;0;ON;;;;;N;;;;; -1F708;ALCHEMICAL SYMBOL FOR AQUA VITAE;So;0;ON;;;;;N;;;;; -1F709;ALCHEMICAL SYMBOL FOR AQUA VITAE-2;So;0;ON;;;;;N;;;;; -1F70A;ALCHEMICAL SYMBOL FOR VINEGAR;So;0;ON;;;;;N;;;;; -1F70B;ALCHEMICAL SYMBOL FOR VINEGAR-2;So;0;ON;;;;;N;;;;; -1F70C;ALCHEMICAL SYMBOL FOR VINEGAR-3;So;0;ON;;;;;N;;;;; -1F70D;ALCHEMICAL SYMBOL FOR SULFUR;So;0;ON;;;;;N;;;;; -1F70E;ALCHEMICAL SYMBOL FOR PHILOSOPHERS SULFUR;So;0;ON;;;;;N;;;;; -1F70F;ALCHEMICAL SYMBOL FOR BLACK SULFUR;So;0;ON;;;;;N;;;;; -1F710;ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE;So;0;ON;;;;;N;;;;; -1F711;ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE-2;So;0;ON;;;;;N;;;;; -1F712;ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE-3;So;0;ON;;;;;N;;;;; -1F713;ALCHEMICAL SYMBOL FOR CINNABAR;So;0;ON;;;;;N;;;;; -1F714;ALCHEMICAL SYMBOL FOR SALT;So;0;ON;;;;;N;;;;; -1F715;ALCHEMICAL SYMBOL FOR NITRE;So;0;ON;;;;;N;;;;; -1F716;ALCHEMICAL SYMBOL FOR VITRIOL;So;0;ON;;;;;N;;;;; -1F717;ALCHEMICAL SYMBOL FOR VITRIOL-2;So;0;ON;;;;;N;;;;; -1F718;ALCHEMICAL SYMBOL FOR ROCK SALT;So;0;ON;;;;;N;;;;; -1F719;ALCHEMICAL SYMBOL FOR ROCK SALT-2;So;0;ON;;;;;N;;;;; -1F71A;ALCHEMICAL SYMBOL FOR GOLD;So;0;ON;;;;;N;;;;; -1F71B;ALCHEMICAL SYMBOL FOR SILVER;So;0;ON;;;;;N;;;;; -1F71C;ALCHEMICAL SYMBOL FOR IRON ORE;So;0;ON;;;;;N;;;;; -1F71D;ALCHEMICAL SYMBOL FOR IRON ORE-2;So;0;ON;;;;;N;;;;; -1F71E;ALCHEMICAL SYMBOL FOR CROCUS OF IRON;So;0;ON;;;;;N;;;;; -1F71F;ALCHEMICAL SYMBOL FOR REGULUS OF IRON;So;0;ON;;;;;N;;;;; -1F720;ALCHEMICAL SYMBOL FOR COPPER ORE;So;0;ON;;;;;N;;;;; -1F721;ALCHEMICAL SYMBOL FOR IRON-COPPER ORE;So;0;ON;;;;;N;;;;; -1F722;ALCHEMICAL SYMBOL FOR SUBLIMATE OF COPPER;So;0;ON;;;;;N;;;;; -1F723;ALCHEMICAL SYMBOL FOR CROCUS OF COPPER;So;0;ON;;;;;N;;;;; -1F724;ALCHEMICAL SYMBOL FOR CROCUS OF COPPER-2;So;0;ON;;;;;N;;;;; -1F725;ALCHEMICAL SYMBOL FOR COPPER ANTIMONIATE;So;0;ON;;;;;N;;;;; -1F726;ALCHEMICAL SYMBOL FOR SALT OF COPPER ANTIMONIATE;So;0;ON;;;;;N;;;;; -1F727;ALCHEMICAL SYMBOL FOR SUBLIMATE OF SALT OF COPPER;So;0;ON;;;;;N;;;;; -1F728;ALCHEMICAL SYMBOL FOR VERDIGRIS;So;0;ON;;;;;N;;;;; -1F729;ALCHEMICAL SYMBOL FOR TIN ORE;So;0;ON;;;;;N;;;;; -1F72A;ALCHEMICAL SYMBOL FOR LEAD ORE;So;0;ON;;;;;N;;;;; -1F72B;ALCHEMICAL SYMBOL FOR ANTIMONY ORE;So;0;ON;;;;;N;;;;; -1F72C;ALCHEMICAL SYMBOL FOR SUBLIMATE OF ANTIMONY;So;0;ON;;;;;N;;;;; -1F72D;ALCHEMICAL SYMBOL FOR SALT OF ANTIMONY;So;0;ON;;;;;N;;;;; -1F72E;ALCHEMICAL SYMBOL FOR SUBLIMATE OF SALT OF ANTIMONY;So;0;ON;;;;;N;;;;; -1F72F;ALCHEMICAL SYMBOL FOR VINEGAR OF ANTIMONY;So;0;ON;;;;;N;;;;; -1F730;ALCHEMICAL SYMBOL FOR REGULUS OF ANTIMONY;So;0;ON;;;;;N;;;;; -1F731;ALCHEMICAL SYMBOL FOR REGULUS OF ANTIMONY-2;So;0;ON;;;;;N;;;;; -1F732;ALCHEMICAL SYMBOL FOR REGULUS;So;0;ON;;;;;N;;;;; -1F733;ALCHEMICAL SYMBOL FOR REGULUS-2;So;0;ON;;;;;N;;;;; -1F734;ALCHEMICAL SYMBOL FOR REGULUS-3;So;0;ON;;;;;N;;;;; -1F735;ALCHEMICAL SYMBOL FOR REGULUS-4;So;0;ON;;;;;N;;;;; -1F736;ALCHEMICAL SYMBOL FOR ALKALI;So;0;ON;;;;;N;;;;; -1F737;ALCHEMICAL SYMBOL FOR ALKALI-2;So;0;ON;;;;;N;;;;; -1F738;ALCHEMICAL SYMBOL FOR MARCASITE;So;0;ON;;;;;N;;;;; -1F739;ALCHEMICAL SYMBOL FOR SAL-AMMONIAC;So;0;ON;;;;;N;;;;; -1F73A;ALCHEMICAL SYMBOL FOR ARSENIC;So;0;ON;;;;;N;;;;; -1F73B;ALCHEMICAL SYMBOL FOR REALGAR;So;0;ON;;;;;N;;;;; -1F73C;ALCHEMICAL SYMBOL FOR REALGAR-2;So;0;ON;;;;;N;;;;; -1F73D;ALCHEMICAL SYMBOL FOR AURIPIGMENT;So;0;ON;;;;;N;;;;; -1F73E;ALCHEMICAL SYMBOL FOR BISMUTH ORE;So;0;ON;;;;;N;;;;; -1F73F;ALCHEMICAL SYMBOL FOR TARTAR;So;0;ON;;;;;N;;;;; -1F740;ALCHEMICAL SYMBOL FOR TARTAR-2;So;0;ON;;;;;N;;;;; -1F741;ALCHEMICAL SYMBOL FOR QUICK LIME;So;0;ON;;;;;N;;;;; -1F742;ALCHEMICAL SYMBOL FOR BORAX;So;0;ON;;;;;N;;;;; -1F743;ALCHEMICAL SYMBOL FOR BORAX-2;So;0;ON;;;;;N;;;;; -1F744;ALCHEMICAL SYMBOL FOR BORAX-3;So;0;ON;;;;;N;;;;; -1F745;ALCHEMICAL SYMBOL FOR ALUM;So;0;ON;;;;;N;;;;; -1F746;ALCHEMICAL SYMBOL FOR OIL;So;0;ON;;;;;N;;;;; -1F747;ALCHEMICAL SYMBOL FOR SPIRIT;So;0;ON;;;;;N;;;;; -1F748;ALCHEMICAL SYMBOL FOR TINCTURE;So;0;ON;;;;;N;;;;; -1F749;ALCHEMICAL SYMBOL FOR GUM;So;0;ON;;;;;N;;;;; -1F74A;ALCHEMICAL SYMBOL FOR WAX;So;0;ON;;;;;N;;;;; -1F74B;ALCHEMICAL SYMBOL FOR POWDER;So;0;ON;;;;;N;;;;; -1F74C;ALCHEMICAL SYMBOL FOR CALX;So;0;ON;;;;;N;;;;; -1F74D;ALCHEMICAL SYMBOL FOR TUTTY;So;0;ON;;;;;N;;;;; -1F74E;ALCHEMICAL SYMBOL FOR CAPUT MORTUUM;So;0;ON;;;;;N;;;;; -1F74F;ALCHEMICAL SYMBOL FOR SCEPTER OF JOVE;So;0;ON;;;;;N;;;;; -1F750;ALCHEMICAL SYMBOL FOR CADUCEUS;So;0;ON;;;;;N;;;;; -1F751;ALCHEMICAL SYMBOL FOR TRIDENT;So;0;ON;;;;;N;;;;; -1F752;ALCHEMICAL SYMBOL FOR STARRED TRIDENT;So;0;ON;;;;;N;;;;; -1F753;ALCHEMICAL SYMBOL FOR LODESTONE;So;0;ON;;;;;N;;;;; -1F754;ALCHEMICAL SYMBOL FOR SOAP;So;0;ON;;;;;N;;;;; -1F755;ALCHEMICAL SYMBOL FOR URINE;So;0;ON;;;;;N;;;;; -1F756;ALCHEMICAL SYMBOL FOR HORSE DUNG;So;0;ON;;;;;N;;;;; -1F757;ALCHEMICAL SYMBOL FOR ASHES;So;0;ON;;;;;N;;;;; -1F758;ALCHEMICAL SYMBOL FOR POT ASHES;So;0;ON;;;;;N;;;;; -1F759;ALCHEMICAL SYMBOL FOR BRICK;So;0;ON;;;;;N;;;;; -1F75A;ALCHEMICAL SYMBOL FOR POWDERED BRICK;So;0;ON;;;;;N;;;;; -1F75B;ALCHEMICAL SYMBOL FOR AMALGAM;So;0;ON;;;;;N;;;;; -1F75C;ALCHEMICAL SYMBOL FOR STRATUM SUPER STRATUM;So;0;ON;;;;;N;;;;; -1F75D;ALCHEMICAL SYMBOL FOR STRATUM SUPER STRATUM-2;So;0;ON;;;;;N;;;;; -1F75E;ALCHEMICAL SYMBOL FOR SUBLIMATION;So;0;ON;;;;;N;;;;; -1F75F;ALCHEMICAL SYMBOL FOR PRECIPITATE;So;0;ON;;;;;N;;;;; -1F760;ALCHEMICAL SYMBOL FOR DISTILL;So;0;ON;;;;;N;;;;; -1F761;ALCHEMICAL SYMBOL FOR DISSOLVE;So;0;ON;;;;;N;;;;; -1F762;ALCHEMICAL SYMBOL FOR DISSOLVE-2;So;0;ON;;;;;N;;;;; -1F763;ALCHEMICAL SYMBOL FOR PURIFY;So;0;ON;;;;;N;;;;; -1F764;ALCHEMICAL SYMBOL FOR PUTREFACTION;So;0;ON;;;;;N;;;;; -1F765;ALCHEMICAL SYMBOL FOR CRUCIBLE;So;0;ON;;;;;N;;;;; -1F766;ALCHEMICAL SYMBOL FOR CRUCIBLE-2;So;0;ON;;;;;N;;;;; -1F767;ALCHEMICAL SYMBOL FOR CRUCIBLE-3;So;0;ON;;;;;N;;;;; -1F768;ALCHEMICAL SYMBOL FOR CRUCIBLE-4;So;0;ON;;;;;N;;;;; -1F769;ALCHEMICAL SYMBOL FOR CRUCIBLE-5;So;0;ON;;;;;N;;;;; -1F76A;ALCHEMICAL SYMBOL FOR ALEMBIC;So;0;ON;;;;;N;;;;; -1F76B;ALCHEMICAL SYMBOL FOR BATH OF MARY;So;0;ON;;;;;N;;;;; -1F76C;ALCHEMICAL SYMBOL FOR BATH OF VAPOURS;So;0;ON;;;;;N;;;;; -1F76D;ALCHEMICAL SYMBOL FOR RETORT;So;0;ON;;;;;N;;;;; -1F76E;ALCHEMICAL SYMBOL FOR HOUR;So;0;ON;;;;;N;;;;; -1F76F;ALCHEMICAL SYMBOL FOR NIGHT;So;0;ON;;;;;N;;;;; -1F770;ALCHEMICAL SYMBOL FOR DAY-NIGHT;So;0;ON;;;;;N;;;;; -1F771;ALCHEMICAL SYMBOL FOR MONTH;So;0;ON;;;;;N;;;;; -1F772;ALCHEMICAL SYMBOL FOR HALF DRAM;So;0;ON;;;;;N;;;;; -1F773;ALCHEMICAL SYMBOL FOR HALF OUNCE;So;0;ON;;;;;N;;;;; -1F774;LOT OF FORTUNE;So;0;ON;;;;;N;;;;; -1F775;OCCULTATION;So;0;ON;;;;;N;;;;; -1F776;LUNAR ECLIPSE;So;0;ON;;;;;N;;;;; -1F77B;HAUMEA;So;0;ON;;;;;N;;;;; -1F77C;MAKEMAKE;So;0;ON;;;;;N;;;;; -1F77D;GONGGONG;So;0;ON;;;;;N;;;;; -1F77E;QUAOAR;So;0;ON;;;;;N;;;;; -1F77F;ORCUS;So;0;ON;;;;;N;;;;; -1F780;BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; -1F781;BLACK UP-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; -1F782;BLACK RIGHT-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; -1F783;BLACK DOWN-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; -1F784;BLACK SLIGHTLY SMALL CIRCLE;So;0;ON;;;;;N;;;;; -1F785;MEDIUM BOLD WHITE CIRCLE;So;0;ON;;;;;N;;;;; -1F786;BOLD WHITE CIRCLE;So;0;ON;;;;;N;;;;; -1F787;HEAVY WHITE CIRCLE;So;0;ON;;;;;N;;;;; -1F788;VERY HEAVY WHITE CIRCLE;So;0;ON;;;;;N;;;;; -1F789;EXTREMELY HEAVY WHITE CIRCLE;So;0;ON;;;;;N;;;;; -1F78A;WHITE CIRCLE CONTAINING BLACK SMALL CIRCLE;So;0;ON;;;;;N;;;;; -1F78B;ROUND TARGET;So;0;ON;;;;;N;;;;; -1F78C;BLACK TINY SQUARE;So;0;ON;;;;;N;;;;; -1F78D;BLACK SLIGHTLY SMALL SQUARE;So;0;ON;;;;;N;;;;; -1F78E;LIGHT WHITE SQUARE;So;0;ON;;;;;N;;;;; -1F78F;MEDIUM WHITE SQUARE;So;0;ON;;;;;N;;;;; -1F790;BOLD WHITE SQUARE;So;0;ON;;;;;N;;;;; -1F791;HEAVY WHITE SQUARE;So;0;ON;;;;;N;;;;; -1F792;VERY HEAVY WHITE SQUARE;So;0;ON;;;;;N;;;;; -1F793;EXTREMELY HEAVY WHITE SQUARE;So;0;ON;;;;;N;;;;; -1F794;WHITE SQUARE CONTAINING BLACK VERY SMALL SQUARE;So;0;ON;;;;;N;;;;; -1F795;WHITE SQUARE CONTAINING BLACK MEDIUM SQUARE;So;0;ON;;;;;N;;;;; -1F796;SQUARE TARGET;So;0;ON;;;;;N;;;;; -1F797;BLACK TINY DIAMOND;So;0;ON;;;;;N;;;;; -1F798;BLACK VERY SMALL DIAMOND;So;0;ON;;;;;N;;;;; -1F799;BLACK MEDIUM SMALL DIAMOND;So;0;ON;;;;;N;;;;; -1F79A;WHITE DIAMOND CONTAINING BLACK VERY SMALL DIAMOND;So;0;ON;;;;;N;;;;; -1F79B;WHITE DIAMOND CONTAINING BLACK MEDIUM DIAMOND;So;0;ON;;;;;N;;;;; -1F79C;DIAMOND TARGET;So;0;ON;;;;;N;;;;; -1F79D;BLACK TINY LOZENGE;So;0;ON;;;;;N;;;;; -1F79E;BLACK VERY SMALL LOZENGE;So;0;ON;;;;;N;;;;; -1F79F;BLACK MEDIUM SMALL LOZENGE;So;0;ON;;;;;N;;;;; -1F7A0;WHITE LOZENGE CONTAINING BLACK SMALL LOZENGE;So;0;ON;;;;;N;;;;; -1F7A1;THIN GREEK CROSS;So;0;ON;;;;;N;;;;; -1F7A2;LIGHT GREEK CROSS;So;0;ON;;;;;N;;;;; -1F7A3;MEDIUM GREEK CROSS;So;0;ON;;;;;N;;;;; -1F7A4;BOLD GREEK CROSS;So;0;ON;;;;;N;;;;; -1F7A5;VERY BOLD GREEK CROSS;So;0;ON;;;;;N;;;;; -1F7A6;VERY HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;; -1F7A7;EXTREMELY HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;; -1F7A8;THIN SALTIRE;So;0;ON;;;;;N;;;;; -1F7A9;LIGHT SALTIRE;So;0;ON;;;;;N;;;;; -1F7AA;MEDIUM SALTIRE;So;0;ON;;;;;N;;;;; -1F7AB;BOLD SALTIRE;So;0;ON;;;;;N;;;;; -1F7AC;HEAVY SALTIRE;So;0;ON;;;;;N;;;;; -1F7AD;VERY HEAVY SALTIRE;So;0;ON;;;;;N;;;;; -1F7AE;EXTREMELY HEAVY SALTIRE;So;0;ON;;;;;N;;;;; -1F7AF;LIGHT FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -1F7B0;MEDIUM FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -1F7B1;BOLD FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -1F7B2;HEAVY FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -1F7B3;VERY HEAVY FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -1F7B4;EXTREMELY HEAVY FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -1F7B5;LIGHT SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -1F7B6;MEDIUM SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -1F7B7;BOLD SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -1F7B8;HEAVY SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -1F7B9;VERY HEAVY SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -1F7BA;EXTREMELY HEAVY SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -1F7BB;LIGHT EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -1F7BC;MEDIUM EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -1F7BD;BOLD EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -1F7BE;HEAVY EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -1F7BF;VERY HEAVY EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; -1F7C0;LIGHT THREE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; -1F7C1;MEDIUM THREE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; -1F7C2;THREE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; -1F7C3;MEDIUM THREE POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; -1F7C4;LIGHT FOUR POINTED BLACK STAR;So;0;ON;;;;;N;;;;; -1F7C5;MEDIUM FOUR POINTED BLACK STAR;So;0;ON;;;;;N;;;;; -1F7C6;FOUR POINTED BLACK STAR;So;0;ON;;;;;N;;;;; -1F7C7;MEDIUM FOUR POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; -1F7C8;REVERSE LIGHT FOUR POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; -1F7C9;LIGHT FIVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; -1F7CA;HEAVY FIVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; -1F7CB;MEDIUM SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;; -1F7CC;HEAVY SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;; -1F7CD;SIX POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; -1F7CE;MEDIUM EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;; -1F7CF;HEAVY EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;; -1F7D0;VERY HEAVY EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;; -1F7D1;HEAVY EIGHT POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; -1F7D2;LIGHT TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; -1F7D3;HEAVY TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; -1F7D4;HEAVY TWELVE POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; -1F7D5;CIRCLED TRIANGLE;So;0;ON;;;;;N;;;;; -1F7D6;NEGATIVE CIRCLED TRIANGLE;So;0;ON;;;;;N;;;;; -1F7D7;CIRCLED SQUARE;So;0;ON;;;;;N;;;;; -1F7D8;NEGATIVE CIRCLED SQUARE;So;0;ON;;;;;N;;;;; -1F7D9;NINE POINTED WHITE STAR;So;0;ON;;;;;N;;;;; -1F7E0;LARGE ORANGE CIRCLE;So;0;ON;;;;;N;;;;; -1F7E1;LARGE YELLOW CIRCLE;So;0;ON;;;;;N;;;;; -1F7E2;LARGE GREEN CIRCLE;So;0;ON;;;;;N;;;;; -1F7E3;LARGE PURPLE CIRCLE;So;0;ON;;;;;N;;;;; -1F7E4;LARGE BROWN CIRCLE;So;0;ON;;;;;N;;;;; -1F7E5;LARGE RED SQUARE;So;0;ON;;;;;N;;;;; -1F7E6;LARGE BLUE SQUARE;So;0;ON;;;;;N;;;;; -1F7E7;LARGE ORANGE SQUARE;So;0;ON;;;;;N;;;;; -1F7E8;LARGE YELLOW SQUARE;So;0;ON;;;;;N;;;;; -1F7E9;LARGE GREEN SQUARE;So;0;ON;;;;;N;;;;; -1F7EA;LARGE PURPLE SQUARE;So;0;ON;;;;;N;;;;; -1F7EB;LARGE BROWN SQUARE;So;0;ON;;;;;N;;;;; -1F7F0;HEAVY EQUALS SIGN;So;0;ON;;;;;N;;;;; -1F800;LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F801;UPWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F802;RIGHTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F803;DOWNWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F804;LEFTWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F805;UPWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F806;RIGHTWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F807;DOWNWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F808;LEFTWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F809;UPWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F80A;RIGHTWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F80B;DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F810;LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -1F811;UPWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -1F812;RIGHTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -1F813;DOWNWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -1F814;LEFTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -1F815;UPWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -1F816;RIGHTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -1F817;DOWNWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -1F818;HEAVY LEFTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -1F819;HEAVY UPWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -1F81A;HEAVY RIGHTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -1F81B;HEAVY DOWNWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -1F81C;HEAVY LEFTWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -1F81D;HEAVY UPWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -1F81E;HEAVY RIGHTWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -1F81F;HEAVY DOWNWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; -1F820;LEFTWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;; -1F821;UPWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;; -1F822;RIGHTWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;; -1F823;DOWNWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;; -1F824;LEFTWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;; -1F825;UPWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;; -1F826;RIGHTWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;; -1F827;DOWNWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;; -1F828;LEFTWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;; -1F829;UPWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;; -1F82A;RIGHTWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;; -1F82B;DOWNWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;; -1F82C;LEFTWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;; -1F82D;UPWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;; -1F82E;RIGHTWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;; -1F82F;DOWNWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;; -1F830;LEFTWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;; -1F831;UPWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;; -1F832;RIGHTWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;; -1F833;DOWNWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;; -1F834;LEFTWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;; -1F835;UPWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;; -1F836;RIGHTWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;; -1F837;DOWNWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;; -1F838;LEFTWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;; -1F839;UPWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;; -1F83A;RIGHTWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;; -1F83B;DOWNWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;; -1F83C;LEFTWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;; -1F83D;UPWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;; -1F83E;RIGHTWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;; -1F83F;DOWNWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;; -1F840;LEFTWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;; -1F841;UPWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;; -1F842;RIGHTWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;; -1F843;DOWNWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;; -1F844;LEFTWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;; -1F845;UPWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;; -1F846;RIGHTWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;; -1F847;DOWNWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;; -1F850;LEFTWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; -1F851;UPWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; -1F852;RIGHTWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; -1F853;DOWNWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; -1F854;NORTH WEST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; -1F855;NORTH EAST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; -1F856;SOUTH EAST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; -1F857;SOUTH WEST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; -1F858;LEFT RIGHT SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; -1F859;UP DOWN SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; -1F860;WIDE-HEADED LEFTWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; -1F861;WIDE-HEADED UPWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; -1F862;WIDE-HEADED RIGHTWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; -1F863;WIDE-HEADED DOWNWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; -1F864;WIDE-HEADED NORTH WEST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; -1F865;WIDE-HEADED NORTH EAST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; -1F866;WIDE-HEADED SOUTH EAST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; -1F867;WIDE-HEADED SOUTH WEST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; -1F868;WIDE-HEADED LEFTWARDS BARB ARROW;So;0;ON;;;;;N;;;;; -1F869;WIDE-HEADED UPWARDS BARB ARROW;So;0;ON;;;;;N;;;;; -1F86A;WIDE-HEADED RIGHTWARDS BARB ARROW;So;0;ON;;;;;N;;;;; -1F86B;WIDE-HEADED DOWNWARDS BARB ARROW;So;0;ON;;;;;N;;;;; -1F86C;WIDE-HEADED NORTH WEST BARB ARROW;So;0;ON;;;;;N;;;;; -1F86D;WIDE-HEADED NORTH EAST BARB ARROW;So;0;ON;;;;;N;;;;; -1F86E;WIDE-HEADED SOUTH EAST BARB ARROW;So;0;ON;;;;;N;;;;; -1F86F;WIDE-HEADED SOUTH WEST BARB ARROW;So;0;ON;;;;;N;;;;; -1F870;WIDE-HEADED LEFTWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; -1F871;WIDE-HEADED UPWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; -1F872;WIDE-HEADED RIGHTWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; -1F873;WIDE-HEADED DOWNWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; -1F874;WIDE-HEADED NORTH WEST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; -1F875;WIDE-HEADED NORTH EAST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; -1F876;WIDE-HEADED SOUTH EAST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; -1F877;WIDE-HEADED SOUTH WEST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; -1F878;WIDE-HEADED LEFTWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; -1F879;WIDE-HEADED UPWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; -1F87A;WIDE-HEADED RIGHTWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; -1F87B;WIDE-HEADED DOWNWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; -1F87C;WIDE-HEADED NORTH WEST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; -1F87D;WIDE-HEADED NORTH EAST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; -1F87E;WIDE-HEADED SOUTH EAST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; -1F87F;WIDE-HEADED SOUTH WEST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; -1F880;WIDE-HEADED LEFTWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; -1F881;WIDE-HEADED UPWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; -1F882;WIDE-HEADED RIGHTWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; -1F883;WIDE-HEADED DOWNWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; -1F884;WIDE-HEADED NORTH WEST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; -1F885;WIDE-HEADED NORTH EAST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; -1F886;WIDE-HEADED SOUTH EAST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; -1F887;WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; -1F890;LEFTWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F891;UPWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F892;RIGHTWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F893;DOWNWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F894;LEFTWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F895;UPWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F896;RIGHTWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F897;DOWNWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; -1F898;LEFTWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;; -1F899;UPWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;; -1F89A;RIGHTWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;; -1F89B;DOWNWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;; -1F89C;HEAVY ARROW SHAFT WIDTH ONE;So;0;ON;;;;;N;;;;; -1F89D;HEAVY ARROW SHAFT WIDTH TWO THIRDS;So;0;ON;;;;;N;;;;; -1F89E;HEAVY ARROW SHAFT WIDTH ONE HALF;So;0;ON;;;;;N;;;;; -1F89F;HEAVY ARROW SHAFT WIDTH ONE THIRD;So;0;ON;;;;;N;;;;; -1F8A0;LEFTWARDS BOTTOM-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; -1F8A1;RIGHTWARDS BOTTOM SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; -1F8A2;LEFTWARDS TOP SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; -1F8A3;RIGHTWARDS TOP SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; -1F8A4;LEFTWARDS LEFT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; -1F8A5;RIGHTWARDS RIGHT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; -1F8A6;LEFTWARDS RIGHT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; -1F8A7;RIGHTWARDS LEFT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; -1F8A8;LEFTWARDS BACK-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;; -1F8A9;RIGHTWARDS BACK-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;; -1F8AA;LEFTWARDS FRONT-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;; -1F8AB;RIGHTWARDS FRONT-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;; -1F8AC;WHITE ARROW SHAFT WIDTH ONE;So;0;ON;;;;;N;;;;; -1F8AD;WHITE ARROW SHAFT WIDTH TWO THIRDS;So;0;ON;;;;;N;;;;; -1F8B0;ARROW POINTING UPWARDS THEN NORTH WEST;So;0;ON;;;;;N;;;;; -1F8B1;ARROW POINTING RIGHTWARDS THEN CURVING SOUTH WEST;So;0;ON;;;;;N;;;;; -1F900;CIRCLED CROSS FORMEE WITH FOUR DOTS;So;0;ON;;;;;N;;;;; -1F901;CIRCLED CROSS FORMEE WITH TWO DOTS;So;0;ON;;;;;N;;;;; -1F902;CIRCLED CROSS FORMEE;So;0;ON;;;;;N;;;;; -1F903;LEFT HALF CIRCLE WITH FOUR DOTS;So;0;ON;;;;;N;;;;; -1F904;LEFT HALF CIRCLE WITH THREE DOTS;So;0;ON;;;;;N;;;;; -1F905;LEFT HALF CIRCLE WITH TWO DOTS;So;0;ON;;;;;N;;;;; -1F906;LEFT HALF CIRCLE WITH DOT;So;0;ON;;;;;N;;;;; -1F907;LEFT HALF CIRCLE;So;0;ON;;;;;N;;;;; -1F908;DOWNWARD FACING HOOK;So;0;ON;;;;;N;;;;; -1F909;DOWNWARD FACING NOTCHED HOOK;So;0;ON;;;;;N;;;;; -1F90A;DOWNWARD FACING HOOK WITH DOT;So;0;ON;;;;;N;;;;; -1F90B;DOWNWARD FACING NOTCHED HOOK WITH DOT;So;0;ON;;;;;N;;;;; -1F90C;PINCHED FINGERS;So;0;ON;;;;;N;;;;; -1F90D;WHITE HEART;So;0;ON;;;;;N;;;;; -1F90E;BROWN HEART;So;0;ON;;;;;N;;;;; -1F90F;PINCHING HAND;So;0;ON;;;;;N;;;;; -1F910;ZIPPER-MOUTH FACE;So;0;ON;;;;;N;;;;; -1F911;MONEY-MOUTH FACE;So;0;ON;;;;;N;;;;; -1F912;FACE WITH THERMOMETER;So;0;ON;;;;;N;;;;; -1F913;NERD FACE;So;0;ON;;;;;N;;;;; -1F914;THINKING FACE;So;0;ON;;;;;N;;;;; -1F915;FACE WITH HEAD-BANDAGE;So;0;ON;;;;;N;;;;; -1F916;ROBOT FACE;So;0;ON;;;;;N;;;;; -1F917;HUGGING FACE;So;0;ON;;;;;N;;;;; -1F918;SIGN OF THE HORNS;So;0;ON;;;;;N;;;;; -1F919;CALL ME HAND;So;0;ON;;;;;N;;;;; -1F91A;RAISED BACK OF HAND;So;0;ON;;;;;N;;;;; -1F91B;LEFT-FACING FIST;So;0;ON;;;;;N;;;;; -1F91C;RIGHT-FACING FIST;So;0;ON;;;;;N;;;;; -1F91D;HANDSHAKE;So;0;ON;;;;;N;;;;; -1F91E;HAND WITH INDEX AND MIDDLE FINGERS CROSSED;So;0;ON;;;;;N;;;;; -1F91F;I LOVE YOU HAND SIGN;So;0;ON;;;;;N;;;;; -1F920;FACE WITH COWBOY HAT;So;0;ON;;;;;N;;;;; -1F921;CLOWN FACE;So;0;ON;;;;;N;;;;; -1F922;NAUSEATED FACE;So;0;ON;;;;;N;;;;; -1F923;ROLLING ON THE FLOOR LAUGHING;So;0;ON;;;;;N;;;;; -1F924;DROOLING FACE;So;0;ON;;;;;N;;;;; -1F925;LYING FACE;So;0;ON;;;;;N;;;;; -1F926;FACE PALM;So;0;ON;;;;;N;;;;; -1F927;SNEEZING FACE;So;0;ON;;;;;N;;;;; -1F928;FACE WITH ONE EYEBROW RAISED;So;0;ON;;;;;N;;;;; -1F929;GRINNING FACE WITH STAR EYES;So;0;ON;;;;;N;;;;; -1F92A;GRINNING FACE WITH ONE LARGE AND ONE SMALL EYE;So;0;ON;;;;;N;;;;; -1F92B;FACE WITH FINGER COVERING CLOSED LIPS;So;0;ON;;;;;N;;;;; -1F92C;SERIOUS FACE WITH SYMBOLS COVERING MOUTH;So;0;ON;;;;;N;;;;; -1F92D;SMILING FACE WITH SMILING EYES AND HAND COVERING MOUTH;So;0;ON;;;;;N;;;;; -1F92E;FACE WITH OPEN MOUTH VOMITING;So;0;ON;;;;;N;;;;; -1F92F;SHOCKED FACE WITH EXPLODING HEAD;So;0;ON;;;;;N;;;;; -1F930;PREGNANT WOMAN;So;0;ON;;;;;N;;;;; -1F931;BREAST-FEEDING;So;0;ON;;;;;N;;;;; -1F932;PALMS UP TOGETHER;So;0;ON;;;;;N;;;;; -1F933;SELFIE;So;0;ON;;;;;N;;;;; -1F934;PRINCE;So;0;ON;;;;;N;;;;; -1F935;MAN IN TUXEDO;So;0;ON;;;;;N;;;;; -1F936;MOTHER CHRISTMAS;So;0;ON;;;;;N;;;;; -1F937;SHRUG;So;0;ON;;;;;N;;;;; -1F938;PERSON DOING CARTWHEEL;So;0;ON;;;;;N;;;;; -1F939;JUGGLING;So;0;ON;;;;;N;;;;; -1F93A;FENCER;So;0;ON;;;;;N;;;;; -1F93B;MODERN PENTATHLON;So;0;ON;;;;;N;;;;; -1F93C;WRESTLERS;So;0;ON;;;;;N;;;;; -1F93D;WATER POLO;So;0;ON;;;;;N;;;;; -1F93E;HANDBALL;So;0;ON;;;;;N;;;;; -1F93F;DIVING MASK;So;0;ON;;;;;N;;;;; -1F940;WILTED FLOWER;So;0;ON;;;;;N;;;;; -1F941;DRUM WITH DRUMSTICKS;So;0;ON;;;;;N;;;;; -1F942;CLINKING GLASSES;So;0;ON;;;;;N;;;;; -1F943;TUMBLER GLASS;So;0;ON;;;;;N;;;;; -1F944;SPOON;So;0;ON;;;;;N;;;;; -1F945;GOAL NET;So;0;ON;;;;;N;;;;; -1F946;RIFLE;So;0;ON;;;;;N;;;;; -1F947;FIRST PLACE MEDAL;So;0;ON;;;;;N;;;;; -1F948;SECOND PLACE MEDAL;So;0;ON;;;;;N;;;;; -1F949;THIRD PLACE MEDAL;So;0;ON;;;;;N;;;;; -1F94A;BOXING GLOVE;So;0;ON;;;;;N;;;;; -1F94B;MARTIAL ARTS UNIFORM;So;0;ON;;;;;N;;;;; -1F94C;CURLING STONE;So;0;ON;;;;;N;;;;; -1F94D;LACROSSE STICK AND BALL;So;0;ON;;;;;N;;;;; -1F94E;SOFTBALL;So;0;ON;;;;;N;;;;; -1F94F;FLYING DISC;So;0;ON;;;;;N;;;;; -1F950;CROISSANT;So;0;ON;;;;;N;;;;; -1F951;AVOCADO;So;0;ON;;;;;N;;;;; -1F952;CUCUMBER;So;0;ON;;;;;N;;;;; -1F953;BACON;So;0;ON;;;;;N;;;;; -1F954;POTATO;So;0;ON;;;;;N;;;;; -1F955;CARROT;So;0;ON;;;;;N;;;;; -1F956;BAGUETTE BREAD;So;0;ON;;;;;N;;;;; -1F957;GREEN SALAD;So;0;ON;;;;;N;;;;; -1F958;SHALLOW PAN OF FOOD;So;0;ON;;;;;N;;;;; -1F959;STUFFED FLATBREAD;So;0;ON;;;;;N;;;;; -1F95A;EGG;So;0;ON;;;;;N;;;;; -1F95B;GLASS OF MILK;So;0;ON;;;;;N;;;;; -1F95C;PEANUTS;So;0;ON;;;;;N;;;;; -1F95D;KIWIFRUIT;So;0;ON;;;;;N;;;;; -1F95E;PANCAKES;So;0;ON;;;;;N;;;;; -1F95F;DUMPLING;So;0;ON;;;;;N;;;;; -1F960;FORTUNE COOKIE;So;0;ON;;;;;N;;;;; -1F961;TAKEOUT BOX;So;0;ON;;;;;N;;;;; -1F962;CHOPSTICKS;So;0;ON;;;;;N;;;;; -1F963;BOWL WITH SPOON;So;0;ON;;;;;N;;;;; -1F964;CUP WITH STRAW;So;0;ON;;;;;N;;;;; -1F965;COCONUT;So;0;ON;;;;;N;;;;; -1F966;BROCCOLI;So;0;ON;;;;;N;;;;; -1F967;PIE;So;0;ON;;;;;N;;;;; -1F968;PRETZEL;So;0;ON;;;;;N;;;;; -1F969;CUT OF MEAT;So;0;ON;;;;;N;;;;; -1F96A;SANDWICH;So;0;ON;;;;;N;;;;; -1F96B;CANNED FOOD;So;0;ON;;;;;N;;;;; -1F96C;LEAFY GREEN;So;0;ON;;;;;N;;;;; -1F96D;MANGO;So;0;ON;;;;;N;;;;; -1F96E;MOON CAKE;So;0;ON;;;;;N;;;;; -1F96F;BAGEL;So;0;ON;;;;;N;;;;; -1F970;SMILING FACE WITH SMILING EYES AND THREE HEARTS;So;0;ON;;;;;N;;;;; -1F971;YAWNING FACE;So;0;ON;;;;;N;;;;; -1F972;SMILING FACE WITH TEAR;So;0;ON;;;;;N;;;;; -1F973;FACE WITH PARTY HORN AND PARTY HAT;So;0;ON;;;;;N;;;;; -1F974;FACE WITH UNEVEN EYES AND WAVY MOUTH;So;0;ON;;;;;N;;;;; -1F975;OVERHEATED FACE;So;0;ON;;;;;N;;;;; -1F976;FREEZING FACE;So;0;ON;;;;;N;;;;; -1F977;NINJA;So;0;ON;;;;;N;;;;; -1F978;DISGUISED FACE;So;0;ON;;;;;N;;;;; -1F979;FACE HOLDING BACK TEARS;So;0;ON;;;;;N;;;;; -1F97A;FACE WITH PLEADING EYES;So;0;ON;;;;;N;;;;; -1F97B;SARI;So;0;ON;;;;;N;;;;; -1F97C;LAB COAT;So;0;ON;;;;;N;;;;; -1F97D;GOGGLES;So;0;ON;;;;;N;;;;; -1F97E;HIKING BOOT;So;0;ON;;;;;N;;;;; -1F97F;FLAT SHOE;So;0;ON;;;;;N;;;;; -1F980;CRAB;So;0;ON;;;;;N;;;;; -1F981;LION FACE;So;0;ON;;;;;N;;;;; -1F982;SCORPION;So;0;ON;;;;;N;;;;; -1F983;TURKEY;So;0;ON;;;;;N;;;;; -1F984;UNICORN FACE;So;0;ON;;;;;N;;;;; -1F985;EAGLE;So;0;ON;;;;;N;;;;; -1F986;DUCK;So;0;ON;;;;;N;;;;; -1F987;BAT;So;0;ON;;;;;N;;;;; -1F988;SHARK;So;0;ON;;;;;N;;;;; -1F989;OWL;So;0;ON;;;;;N;;;;; -1F98A;FOX FACE;So;0;ON;;;;;N;;;;; -1F98B;BUTTERFLY;So;0;ON;;;;;N;;;;; -1F98C;DEER;So;0;ON;;;;;N;;;;; -1F98D;GORILLA;So;0;ON;;;;;N;;;;; -1F98E;LIZARD;So;0;ON;;;;;N;;;;; -1F98F;RHINOCEROS;So;0;ON;;;;;N;;;;; -1F990;SHRIMP;So;0;ON;;;;;N;;;;; -1F991;SQUID;So;0;ON;;;;;N;;;;; -1F992;GIRAFFE FACE;So;0;ON;;;;;N;;;;; -1F993;ZEBRA FACE;So;0;ON;;;;;N;;;;; -1F994;HEDGEHOG;So;0;ON;;;;;N;;;;; -1F995;SAUROPOD;So;0;ON;;;;;N;;;;; -1F996;T-REX;So;0;ON;;;;;N;;;;; -1F997;CRICKET;So;0;ON;;;;;N;;;;; -1F998;KANGAROO;So;0;ON;;;;;N;;;;; -1F999;LLAMA;So;0;ON;;;;;N;;;;; -1F99A;PEACOCK;So;0;ON;;;;;N;;;;; -1F99B;HIPPOPOTAMUS;So;0;ON;;;;;N;;;;; -1F99C;PARROT;So;0;ON;;;;;N;;;;; -1F99D;RACCOON;So;0;ON;;;;;N;;;;; -1F99E;LOBSTER;So;0;ON;;;;;N;;;;; -1F99F;MOSQUITO;So;0;ON;;;;;N;;;;; -1F9A0;MICROBE;So;0;ON;;;;;N;;;;; -1F9A1;BADGER;So;0;ON;;;;;N;;;;; -1F9A2;SWAN;So;0;ON;;;;;N;;;;; -1F9A3;MAMMOTH;So;0;ON;;;;;N;;;;; -1F9A4;DODO;So;0;ON;;;;;N;;;;; -1F9A5;SLOTH;So;0;ON;;;;;N;;;;; -1F9A6;OTTER;So;0;ON;;;;;N;;;;; -1F9A7;ORANGUTAN;So;0;ON;;;;;N;;;;; -1F9A8;SKUNK;So;0;ON;;;;;N;;;;; -1F9A9;FLAMINGO;So;0;ON;;;;;N;;;;; -1F9AA;OYSTER;So;0;ON;;;;;N;;;;; -1F9AB;BEAVER;So;0;ON;;;;;N;;;;; -1F9AC;BISON;So;0;ON;;;;;N;;;;; -1F9AD;SEAL;So;0;ON;;;;;N;;;;; -1F9AE;GUIDE DOG;So;0;ON;;;;;N;;;;; -1F9AF;PROBING CANE;So;0;ON;;;;;N;;;;; -1F9B0;EMOJI COMPONENT RED HAIR;So;0;ON;;;;;N;;;;; -1F9B1;EMOJI COMPONENT CURLY HAIR;So;0;ON;;;;;N;;;;; -1F9B2;EMOJI COMPONENT BALD;So;0;ON;;;;;N;;;;; -1F9B3;EMOJI COMPONENT WHITE HAIR;So;0;ON;;;;;N;;;;; -1F9B4;BONE;So;0;ON;;;;;N;;;;; -1F9B5;LEG;So;0;ON;;;;;N;;;;; -1F9B6;FOOT;So;0;ON;;;;;N;;;;; -1F9B7;TOOTH;So;0;ON;;;;;N;;;;; -1F9B8;SUPERHERO;So;0;ON;;;;;N;;;;; -1F9B9;SUPERVILLAIN;So;0;ON;;;;;N;;;;; -1F9BA;SAFETY VEST;So;0;ON;;;;;N;;;;; -1F9BB;EAR WITH HEARING AID;So;0;ON;;;;;N;;;;; -1F9BC;MOTORIZED WHEELCHAIR;So;0;ON;;;;;N;;;;; -1F9BD;MANUAL WHEELCHAIR;So;0;ON;;;;;N;;;;; -1F9BE;MECHANICAL ARM;So;0;ON;;;;;N;;;;; -1F9BF;MECHANICAL LEG;So;0;ON;;;;;N;;;;; -1F9C0;CHEESE WEDGE;So;0;ON;;;;;N;;;;; -1F9C1;CUPCAKE;So;0;ON;;;;;N;;;;; -1F9C2;SALT SHAKER;So;0;ON;;;;;N;;;;; -1F9C3;BEVERAGE BOX;So;0;ON;;;;;N;;;;; -1F9C4;GARLIC;So;0;ON;;;;;N;;;;; -1F9C5;ONION;So;0;ON;;;;;N;;;;; -1F9C6;FALAFEL;So;0;ON;;;;;N;;;;; -1F9C7;WAFFLE;So;0;ON;;;;;N;;;;; -1F9C8;BUTTER;So;0;ON;;;;;N;;;;; -1F9C9;MATE DRINK;So;0;ON;;;;;N;;;;; -1F9CA;ICE CUBE;So;0;ON;;;;;N;;;;; -1F9CB;BUBBLE TEA;So;0;ON;;;;;N;;;;; -1F9CC;TROLL;So;0;ON;;;;;N;;;;; -1F9CD;STANDING PERSON;So;0;ON;;;;;N;;;;; -1F9CE;KNEELING PERSON;So;0;ON;;;;;N;;;;; -1F9CF;DEAF PERSON;So;0;ON;;;;;N;;;;; -1F9D0;FACE WITH MONOCLE;So;0;ON;;;;;N;;;;; -1F9D1;ADULT;So;0;ON;;;;;N;;;;; -1F9D2;CHILD;So;0;ON;;;;;N;;;;; -1F9D3;OLDER ADULT;So;0;ON;;;;;N;;;;; -1F9D4;BEARDED PERSON;So;0;ON;;;;;N;;;;; -1F9D5;PERSON WITH HEADSCARF;So;0;ON;;;;;N;;;;; -1F9D6;PERSON IN STEAMY ROOM;So;0;ON;;;;;N;;;;; -1F9D7;PERSON CLIMBING;So;0;ON;;;;;N;;;;; -1F9D8;PERSON IN LOTUS POSITION;So;0;ON;;;;;N;;;;; -1F9D9;MAGE;So;0;ON;;;;;N;;;;; -1F9DA;FAIRY;So;0;ON;;;;;N;;;;; -1F9DB;VAMPIRE;So;0;ON;;;;;N;;;;; -1F9DC;MERPERSON;So;0;ON;;;;;N;;;;; -1F9DD;ELF;So;0;ON;;;;;N;;;;; -1F9DE;GENIE;So;0;ON;;;;;N;;;;; -1F9DF;ZOMBIE;So;0;ON;;;;;N;;;;; -1F9E0;BRAIN;So;0;ON;;;;;N;;;;; -1F9E1;ORANGE HEART;So;0;ON;;;;;N;;;;; -1F9E2;BILLED CAP;So;0;ON;;;;;N;;;;; -1F9E3;SCARF;So;0;ON;;;;;N;;;;; -1F9E4;GLOVES;So;0;ON;;;;;N;;;;; -1F9E5;COAT;So;0;ON;;;;;N;;;;; -1F9E6;SOCKS;So;0;ON;;;;;N;;;;; -1F9E7;RED GIFT ENVELOPE;So;0;ON;;;;;N;;;;; -1F9E8;FIRECRACKER;So;0;ON;;;;;N;;;;; -1F9E9;JIGSAW PUZZLE PIECE;So;0;ON;;;;;N;;;;; -1F9EA;TEST TUBE;So;0;ON;;;;;N;;;;; -1F9EB;PETRI DISH;So;0;ON;;;;;N;;;;; -1F9EC;DNA DOUBLE HELIX;So;0;ON;;;;;N;;;;; -1F9ED;COMPASS;So;0;ON;;;;;N;;;;; -1F9EE;ABACUS;So;0;ON;;;;;N;;;;; -1F9EF;FIRE EXTINGUISHER;So;0;ON;;;;;N;;;;; -1F9F0;TOOLBOX;So;0;ON;;;;;N;;;;; -1F9F1;BRICK;So;0;ON;;;;;N;;;;; -1F9F2;MAGNET;So;0;ON;;;;;N;;;;; -1F9F3;LUGGAGE;So;0;ON;;;;;N;;;;; -1F9F4;LOTION BOTTLE;So;0;ON;;;;;N;;;;; -1F9F5;SPOOL OF THREAD;So;0;ON;;;;;N;;;;; -1F9F6;BALL OF YARN;So;0;ON;;;;;N;;;;; -1F9F7;SAFETY PIN;So;0;ON;;;;;N;;;;; -1F9F8;TEDDY BEAR;So;0;ON;;;;;N;;;;; -1F9F9;BROOM;So;0;ON;;;;;N;;;;; -1F9FA;BASKET;So;0;ON;;;;;N;;;;; -1F9FB;ROLL OF PAPER;So;0;ON;;;;;N;;;;; -1F9FC;BAR OF SOAP;So;0;ON;;;;;N;;;;; -1F9FD;SPONGE;So;0;ON;;;;;N;;;;; -1F9FE;RECEIPT;So;0;ON;;;;;N;;;;; -1F9FF;NAZAR AMULET;So;0;ON;;;;;N;;;;; -1FA00;NEUTRAL CHESS KING;So;0;ON;;;;;N;;;;; -1FA01;NEUTRAL CHESS QUEEN;So;0;ON;;;;;N;;;;; -1FA02;NEUTRAL CHESS ROOK;So;0;ON;;;;;N;;;;; -1FA03;NEUTRAL CHESS BISHOP;So;0;ON;;;;;N;;;;; -1FA04;NEUTRAL CHESS KNIGHT;So;0;ON;;;;;N;;;;; -1FA05;NEUTRAL CHESS PAWN;So;0;ON;;;;;N;;;;; -1FA06;WHITE CHESS KNIGHT ROTATED FORTY-FIVE DEGREES;So;0;ON;;;;;N;;;;; -1FA07;BLACK CHESS KNIGHT ROTATED FORTY-FIVE DEGREES;So;0;ON;;;;;N;;;;; -1FA08;NEUTRAL CHESS KNIGHT ROTATED FORTY-FIVE DEGREES;So;0;ON;;;;;N;;;;; -1FA09;WHITE CHESS KING ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA0A;WHITE CHESS QUEEN ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA0B;WHITE CHESS ROOK ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA0C;WHITE CHESS BISHOP ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA0D;WHITE CHESS KNIGHT ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA0E;WHITE CHESS PAWN ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA0F;BLACK CHESS KING ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA10;BLACK CHESS QUEEN ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA11;BLACK CHESS ROOK ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA12;BLACK CHESS BISHOP ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA13;BLACK CHESS KNIGHT ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA14;BLACK CHESS PAWN ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA15;NEUTRAL CHESS KING ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA16;NEUTRAL CHESS QUEEN ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA17;NEUTRAL CHESS ROOK ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA18;NEUTRAL CHESS BISHOP ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA19;NEUTRAL CHESS KNIGHT ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA1A;NEUTRAL CHESS PAWN ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA1B;WHITE CHESS KNIGHT ROTATED ONE HUNDRED THIRTY-FIVE DEGREES;So;0;ON;;;;;N;;;;; -1FA1C;BLACK CHESS KNIGHT ROTATED ONE HUNDRED THIRTY-FIVE DEGREES;So;0;ON;;;;;N;;;;; -1FA1D;NEUTRAL CHESS KNIGHT ROTATED ONE HUNDRED THIRTY-FIVE DEGREES;So;0;ON;;;;;N;;;;; -1FA1E;WHITE CHESS TURNED KING;So;0;ON;;;;;N;;;;; -1FA1F;WHITE CHESS TURNED QUEEN;So;0;ON;;;;;N;;;;; -1FA20;WHITE CHESS TURNED ROOK;So;0;ON;;;;;N;;;;; -1FA21;WHITE CHESS TURNED BISHOP;So;0;ON;;;;;N;;;;; -1FA22;WHITE CHESS TURNED KNIGHT;So;0;ON;;;;;N;;;;; -1FA23;WHITE CHESS TURNED PAWN;So;0;ON;;;;;N;;;;; -1FA24;BLACK CHESS TURNED KING;So;0;ON;;;;;N;;;;; -1FA25;BLACK CHESS TURNED QUEEN;So;0;ON;;;;;N;;;;; -1FA26;BLACK CHESS TURNED ROOK;So;0;ON;;;;;N;;;;; -1FA27;BLACK CHESS TURNED BISHOP;So;0;ON;;;;;N;;;;; -1FA28;BLACK CHESS TURNED KNIGHT;So;0;ON;;;;;N;;;;; -1FA29;BLACK CHESS TURNED PAWN;So;0;ON;;;;;N;;;;; -1FA2A;NEUTRAL CHESS TURNED KING;So;0;ON;;;;;N;;;;; -1FA2B;NEUTRAL CHESS TURNED QUEEN;So;0;ON;;;;;N;;;;; -1FA2C;NEUTRAL CHESS TURNED ROOK;So;0;ON;;;;;N;;;;; -1FA2D;NEUTRAL CHESS TURNED BISHOP;So;0;ON;;;;;N;;;;; -1FA2E;NEUTRAL CHESS TURNED KNIGHT;So;0;ON;;;;;N;;;;; -1FA2F;NEUTRAL CHESS TURNED PAWN;So;0;ON;;;;;N;;;;; -1FA30;WHITE CHESS KNIGHT ROTATED TWO HUNDRED TWENTY-FIVE DEGREES;So;0;ON;;;;;N;;;;; -1FA31;BLACK CHESS KNIGHT ROTATED TWO HUNDRED TWENTY-FIVE DEGREES;So;0;ON;;;;;N;;;;; -1FA32;NEUTRAL CHESS KNIGHT ROTATED TWO HUNDRED TWENTY-FIVE DEGREES;So;0;ON;;;;;N;;;;; -1FA33;WHITE CHESS KING ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; -1FA34;WHITE CHESS QUEEN ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; -1FA35;WHITE CHESS ROOK ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; -1FA36;WHITE CHESS BISHOP ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; -1FA37;WHITE CHESS KNIGHT ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; -1FA38;WHITE CHESS PAWN ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; -1FA39;BLACK CHESS KING ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; -1FA3A;BLACK CHESS QUEEN ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; -1FA3B;BLACK CHESS ROOK ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; -1FA3C;BLACK CHESS BISHOP ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; -1FA3D;BLACK CHESS KNIGHT ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; -1FA3E;BLACK CHESS PAWN ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; -1FA3F;NEUTRAL CHESS KING ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; -1FA40;NEUTRAL CHESS QUEEN ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; -1FA41;NEUTRAL CHESS ROOK ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; -1FA42;NEUTRAL CHESS BISHOP ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; -1FA43;NEUTRAL CHESS KNIGHT ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; -1FA44;NEUTRAL CHESS PAWN ROTATED TWO HUNDRED SEVENTY DEGREES;So;0;ON;;;;;N;;;;; -1FA45;WHITE CHESS KNIGHT ROTATED THREE HUNDRED FIFTEEN DEGREES;So;0;ON;;;;;N;;;;; -1FA46;BLACK CHESS KNIGHT ROTATED THREE HUNDRED FIFTEEN DEGREES;So;0;ON;;;;;N;;;;; -1FA47;NEUTRAL CHESS KNIGHT ROTATED THREE HUNDRED FIFTEEN DEGREES;So;0;ON;;;;;N;;;;; -1FA48;WHITE CHESS EQUIHOPPER;So;0;ON;;;;;N;;;;; -1FA49;BLACK CHESS EQUIHOPPER;So;0;ON;;;;;N;;;;; -1FA4A;NEUTRAL CHESS EQUIHOPPER;So;0;ON;;;;;N;;;;; -1FA4B;WHITE CHESS EQUIHOPPER ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA4C;BLACK CHESS EQUIHOPPER ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA4D;NEUTRAL CHESS EQUIHOPPER ROTATED NINETY DEGREES;So;0;ON;;;;;N;;;;; -1FA4E;WHITE CHESS KNIGHT-QUEEN;So;0;ON;;;;;N;;;;; -1FA4F;WHITE CHESS KNIGHT-ROOK;So;0;ON;;;;;N;;;;; -1FA50;WHITE CHESS KNIGHT-BISHOP;So;0;ON;;;;;N;;;;; -1FA51;BLACK CHESS KNIGHT-QUEEN;So;0;ON;;;;;N;;;;; -1FA52;BLACK CHESS KNIGHT-ROOK;So;0;ON;;;;;N;;;;; -1FA53;BLACK CHESS KNIGHT-BISHOP;So;0;ON;;;;;N;;;;; -1FA60;XIANGQI RED GENERAL;So;0;ON;;;;;N;;;;; -1FA61;XIANGQI RED MANDARIN;So;0;ON;;;;;N;;;;; -1FA62;XIANGQI RED ELEPHANT;So;0;ON;;;;;N;;;;; -1FA63;XIANGQI RED HORSE;So;0;ON;;;;;N;;;;; -1FA64;XIANGQI RED CHARIOT;So;0;ON;;;;;N;;;;; -1FA65;XIANGQI RED CANNON;So;0;ON;;;;;N;;;;; -1FA66;XIANGQI RED SOLDIER;So;0;ON;;;;;N;;;;; -1FA67;XIANGQI BLACK GENERAL;So;0;ON;;;;;N;;;;; -1FA68;XIANGQI BLACK MANDARIN;So;0;ON;;;;;N;;;;; -1FA69;XIANGQI BLACK ELEPHANT;So;0;ON;;;;;N;;;;; -1FA6A;XIANGQI BLACK HORSE;So;0;ON;;;;;N;;;;; -1FA6B;XIANGQI BLACK CHARIOT;So;0;ON;;;;;N;;;;; -1FA6C;XIANGQI BLACK CANNON;So;0;ON;;;;;N;;;;; -1FA6D;XIANGQI BLACK SOLDIER;So;0;ON;;;;;N;;;;; -1FA70;BALLET SHOES;So;0;ON;;;;;N;;;;; -1FA71;ONE-PIECE SWIMSUIT;So;0;ON;;;;;N;;;;; -1FA72;BRIEFS;So;0;ON;;;;;N;;;;; -1FA73;SHORTS;So;0;ON;;;;;N;;;;; -1FA74;THONG SANDAL;So;0;ON;;;;;N;;;;; -1FA75;LIGHT BLUE HEART;So;0;ON;;;;;N;;;;; -1FA76;GREY HEART;So;0;ON;;;;;N;;;;; -1FA77;PINK HEART;So;0;ON;;;;;N;;;;; -1FA78;DROP OF BLOOD;So;0;ON;;;;;N;;;;; -1FA79;ADHESIVE BANDAGE;So;0;ON;;;;;N;;;;; -1FA7A;STETHOSCOPE;So;0;ON;;;;;N;;;;; -1FA7B;X-RAY;So;0;ON;;;;;N;;;;; -1FA7C;CRUTCH;So;0;ON;;;;;N;;;;; -1FA80;YO-YO;So;0;ON;;;;;N;;;;; -1FA81;KITE;So;0;ON;;;;;N;;;;; -1FA82;PARACHUTE;So;0;ON;;;;;N;;;;; -1FA83;BOOMERANG;So;0;ON;;;;;N;;;;; -1FA84;MAGIC WAND;So;0;ON;;;;;N;;;;; -1FA85;PINATA;So;0;ON;;;;;N;;;;; -1FA86;NESTING DOLLS;So;0;ON;;;;;N;;;;; -1FA87;MARACAS;So;0;ON;;;;;N;;;;; -1FA88;FLUTE;So;0;ON;;;;;N;;;;; -1FA90;RINGED PLANET;So;0;ON;;;;;N;;;;; -1FA91;CHAIR;So;0;ON;;;;;N;;;;; -1FA92;RAZOR;So;0;ON;;;;;N;;;;; -1FA93;AXE;So;0;ON;;;;;N;;;;; -1FA94;DIYA LAMP;So;0;ON;;;;;N;;;;; -1FA95;BANJO;So;0;ON;;;;;N;;;;; -1FA96;MILITARY HELMET;So;0;ON;;;;;N;;;;; -1FA97;ACCORDION;So;0;ON;;;;;N;;;;; -1FA98;LONG DRUM;So;0;ON;;;;;N;;;;; -1FA99;COIN;So;0;ON;;;;;N;;;;; -1FA9A;CARPENTRY SAW;So;0;ON;;;;;N;;;;; -1FA9B;SCREWDRIVER;So;0;ON;;;;;N;;;;; -1FA9C;LADDER;So;0;ON;;;;;N;;;;; -1FA9D;HOOK;So;0;ON;;;;;N;;;;; -1FA9E;MIRROR;So;0;ON;;;;;N;;;;; -1FA9F;WINDOW;So;0;ON;;;;;N;;;;; -1FAA0;PLUNGER;So;0;ON;;;;;N;;;;; -1FAA1;SEWING NEEDLE;So;0;ON;;;;;N;;;;; -1FAA2;KNOT;So;0;ON;;;;;N;;;;; -1FAA3;BUCKET;So;0;ON;;;;;N;;;;; -1FAA4;MOUSE TRAP;So;0;ON;;;;;N;;;;; -1FAA5;TOOTHBRUSH;So;0;ON;;;;;N;;;;; -1FAA6;HEADSTONE;So;0;ON;;;;;N;;;;; -1FAA7;PLACARD;So;0;ON;;;;;N;;;;; -1FAA8;ROCK;So;0;ON;;;;;N;;;;; -1FAA9;MIRROR BALL;So;0;ON;;;;;N;;;;; -1FAAA;IDENTIFICATION CARD;So;0;ON;;;;;N;;;;; -1FAAB;LOW BATTERY;So;0;ON;;;;;N;;;;; -1FAAC;HAMSA;So;0;ON;;;;;N;;;;; -1FAAD;FOLDING HAND FAN;So;0;ON;;;;;N;;;;; -1FAAE;HAIR PICK;So;0;ON;;;;;N;;;;; -1FAAF;KHANDA;So;0;ON;;;;;N;;;;; -1FAB0;FLY;So;0;ON;;;;;N;;;;; -1FAB1;WORM;So;0;ON;;;;;N;;;;; -1FAB2;BEETLE;So;0;ON;;;;;N;;;;; -1FAB3;COCKROACH;So;0;ON;;;;;N;;;;; -1FAB4;POTTED PLANT;So;0;ON;;;;;N;;;;; -1FAB5;WOOD;So;0;ON;;;;;N;;;;; -1FAB6;FEATHER;So;0;ON;;;;;N;;;;; -1FAB7;LOTUS;So;0;ON;;;;;N;;;;; -1FAB8;CORAL;So;0;ON;;;;;N;;;;; -1FAB9;EMPTY NEST;So;0;ON;;;;;N;;;;; -1FABA;NEST WITH EGGS;So;0;ON;;;;;N;;;;; -1FABB;HYACINTH;So;0;ON;;;;;N;;;;; -1FABC;JELLYFISH;So;0;ON;;;;;N;;;;; -1FABD;WING;So;0;ON;;;;;N;;;;; -1FABF;GOOSE;So;0;ON;;;;;N;;;;; -1FAC0;ANATOMICAL HEART;So;0;ON;;;;;N;;;;; -1FAC1;LUNGS;So;0;ON;;;;;N;;;;; -1FAC2;PEOPLE HUGGING;So;0;ON;;;;;N;;;;; -1FAC3;PREGNANT MAN;So;0;ON;;;;;N;;;;; -1FAC4;PREGNANT PERSON;So;0;ON;;;;;N;;;;; -1FAC5;PERSON WITH CROWN;So;0;ON;;;;;N;;;;; -1FACE;MOOSE;So;0;ON;;;;;N;;;;; -1FACF;DONKEY;So;0;ON;;;;;N;;;;; -1FAD0;BLUEBERRIES;So;0;ON;;;;;N;;;;; -1FAD1;BELL PEPPER;So;0;ON;;;;;N;;;;; -1FAD2;OLIVE;So;0;ON;;;;;N;;;;; -1FAD3;FLATBREAD;So;0;ON;;;;;N;;;;; -1FAD4;TAMALE;So;0;ON;;;;;N;;;;; -1FAD5;FONDUE;So;0;ON;;;;;N;;;;; -1FAD6;TEAPOT;So;0;ON;;;;;N;;;;; -1FAD7;POURING LIQUID;So;0;ON;;;;;N;;;;; -1FAD8;BEANS;So;0;ON;;;;;N;;;;; -1FAD9;JAR;So;0;ON;;;;;N;;;;; -1FADA;GINGER ROOT;So;0;ON;;;;;N;;;;; -1FADB;PEA POD;So;0;ON;;;;;N;;;;; -1FAE0;MELTING FACE;So;0;ON;;;;;N;;;;; -1FAE1;SALUTING FACE;So;0;ON;;;;;N;;;;; -1FAE2;FACE WITH OPEN EYES AND HAND OVER MOUTH;So;0;ON;;;;;N;;;;; -1FAE3;FACE WITH PEEKING EYE;So;0;ON;;;;;N;;;;; -1FAE4;FACE WITH DIAGONAL MOUTH;So;0;ON;;;;;N;;;;; -1FAE5;DOTTED LINE FACE;So;0;ON;;;;;N;;;;; -1FAE6;BITING LIP;So;0;ON;;;;;N;;;;; -1FAE7;BUBBLES;So;0;ON;;;;;N;;;;; -1FAE8;SHAKING FACE;So;0;ON;;;;;N;;;;; -1FAF0;HAND WITH INDEX FINGER AND THUMB CROSSED;So;0;ON;;;;;N;;;;; -1FAF1;RIGHTWARDS HAND;So;0;ON;;;;;N;;;;; -1FAF2;LEFTWARDS HAND;So;0;ON;;;;;N;;;;; -1FAF3;PALM DOWN HAND;So;0;ON;;;;;N;;;;; -1FAF4;PALM UP HAND;So;0;ON;;;;;N;;;;; -1FAF5;INDEX POINTING AT THE VIEWER;So;0;ON;;;;;N;;;;; -1FAF6;HEART HANDS;So;0;ON;;;;;N;;;;; -1FAF7;LEFTWARDS PUSHING HAND;So;0;ON;;;;;N;;;;; -1FAF8;RIGHTWARDS PUSHING HAND;So;0;ON;;;;;N;;;;; -1FB00;BLOCK SEXTANT-1;So;0;ON;;;;;N;;;;; -1FB01;BLOCK SEXTANT-2;So;0;ON;;;;;N;;;;; -1FB02;BLOCK SEXTANT-12;So;0;ON;;;;;N;;;;; -1FB03;BLOCK SEXTANT-3;So;0;ON;;;;;N;;;;; -1FB04;BLOCK SEXTANT-13;So;0;ON;;;;;N;;;;; -1FB05;BLOCK SEXTANT-23;So;0;ON;;;;;N;;;;; -1FB06;BLOCK SEXTANT-123;So;0;ON;;;;;N;;;;; -1FB07;BLOCK SEXTANT-4;So;0;ON;;;;;N;;;;; -1FB08;BLOCK SEXTANT-14;So;0;ON;;;;;N;;;;; -1FB09;BLOCK SEXTANT-24;So;0;ON;;;;;N;;;;; -1FB0A;BLOCK SEXTANT-124;So;0;ON;;;;;N;;;;; -1FB0B;BLOCK SEXTANT-34;So;0;ON;;;;;N;;;;; -1FB0C;BLOCK SEXTANT-134;So;0;ON;;;;;N;;;;; -1FB0D;BLOCK SEXTANT-234;So;0;ON;;;;;N;;;;; -1FB0E;BLOCK SEXTANT-1234;So;0;ON;;;;;N;;;;; -1FB0F;BLOCK SEXTANT-5;So;0;ON;;;;;N;;;;; -1FB10;BLOCK SEXTANT-15;So;0;ON;;;;;N;;;;; -1FB11;BLOCK SEXTANT-25;So;0;ON;;;;;N;;;;; -1FB12;BLOCK SEXTANT-125;So;0;ON;;;;;N;;;;; -1FB13;BLOCK SEXTANT-35;So;0;ON;;;;;N;;;;; -1FB14;BLOCK SEXTANT-235;So;0;ON;;;;;N;;;;; -1FB15;BLOCK SEXTANT-1235;So;0;ON;;;;;N;;;;; -1FB16;BLOCK SEXTANT-45;So;0;ON;;;;;N;;;;; -1FB17;BLOCK SEXTANT-145;So;0;ON;;;;;N;;;;; -1FB18;BLOCK SEXTANT-245;So;0;ON;;;;;N;;;;; -1FB19;BLOCK SEXTANT-1245;So;0;ON;;;;;N;;;;; -1FB1A;BLOCK SEXTANT-345;So;0;ON;;;;;N;;;;; -1FB1B;BLOCK SEXTANT-1345;So;0;ON;;;;;N;;;;; -1FB1C;BLOCK SEXTANT-2345;So;0;ON;;;;;N;;;;; -1FB1D;BLOCK SEXTANT-12345;So;0;ON;;;;;N;;;;; -1FB1E;BLOCK SEXTANT-6;So;0;ON;;;;;N;;;;; -1FB1F;BLOCK SEXTANT-16;So;0;ON;;;;;N;;;;; -1FB20;BLOCK SEXTANT-26;So;0;ON;;;;;N;;;;; -1FB21;BLOCK SEXTANT-126;So;0;ON;;;;;N;;;;; -1FB22;BLOCK SEXTANT-36;So;0;ON;;;;;N;;;;; -1FB23;BLOCK SEXTANT-136;So;0;ON;;;;;N;;;;; -1FB24;BLOCK SEXTANT-236;So;0;ON;;;;;N;;;;; -1FB25;BLOCK SEXTANT-1236;So;0;ON;;;;;N;;;;; -1FB26;BLOCK SEXTANT-46;So;0;ON;;;;;N;;;;; -1FB27;BLOCK SEXTANT-146;So;0;ON;;;;;N;;;;; -1FB28;BLOCK SEXTANT-1246;So;0;ON;;;;;N;;;;; -1FB29;BLOCK SEXTANT-346;So;0;ON;;;;;N;;;;; -1FB2A;BLOCK SEXTANT-1346;So;0;ON;;;;;N;;;;; -1FB2B;BLOCK SEXTANT-2346;So;0;ON;;;;;N;;;;; -1FB2C;BLOCK SEXTANT-12346;So;0;ON;;;;;N;;;;; -1FB2D;BLOCK SEXTANT-56;So;0;ON;;;;;N;;;;; -1FB2E;BLOCK SEXTANT-156;So;0;ON;;;;;N;;;;; -1FB2F;BLOCK SEXTANT-256;So;0;ON;;;;;N;;;;; -1FB30;BLOCK SEXTANT-1256;So;0;ON;;;;;N;;;;; -1FB31;BLOCK SEXTANT-356;So;0;ON;;;;;N;;;;; -1FB32;BLOCK SEXTANT-1356;So;0;ON;;;;;N;;;;; -1FB33;BLOCK SEXTANT-2356;So;0;ON;;;;;N;;;;; -1FB34;BLOCK SEXTANT-12356;So;0;ON;;;;;N;;;;; -1FB35;BLOCK SEXTANT-456;So;0;ON;;;;;N;;;;; -1FB36;BLOCK SEXTANT-1456;So;0;ON;;;;;N;;;;; -1FB37;BLOCK SEXTANT-2456;So;0;ON;;;;;N;;;;; -1FB38;BLOCK SEXTANT-12456;So;0;ON;;;;;N;;;;; -1FB39;BLOCK SEXTANT-3456;So;0;ON;;;;;N;;;;; -1FB3A;BLOCK SEXTANT-13456;So;0;ON;;;;;N;;;;; -1FB3B;BLOCK SEXTANT-23456;So;0;ON;;;;;N;;;;; -1FB3C;LOWER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; -1FB3D;LOWER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;; -1FB3E;LOWER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; -1FB3F;LOWER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;; -1FB40;LOWER LEFT BLOCK DIAGONAL UPPER LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; -1FB41;LOWER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;; -1FB42;LOWER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER RIGHT;So;0;ON;;;;;N;;;;; -1FB43;LOWER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;; -1FB44;LOWER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER RIGHT;So;0;ON;;;;;N;;;;; -1FB45;LOWER RIGHT BLOCK DIAGONAL LOWER LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;; -1FB46;LOWER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB47;LOWER RIGHT BLOCK DIAGONAL LOWER CENTRE TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB48;LOWER RIGHT BLOCK DIAGONAL LOWER LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB49;LOWER RIGHT BLOCK DIAGONAL LOWER CENTRE TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB4A;LOWER RIGHT BLOCK DIAGONAL LOWER LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB4B;LOWER RIGHT BLOCK DIAGONAL LOWER CENTRE TO UPPER RIGHT;So;0;ON;;;;;N;;;;; -1FB4C;LOWER LEFT BLOCK DIAGONAL UPPER CENTRE TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB4D;LOWER LEFT BLOCK DIAGONAL UPPER LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB4E;LOWER LEFT BLOCK DIAGONAL UPPER CENTRE TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB4F;LOWER LEFT BLOCK DIAGONAL UPPER LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB50;LOWER LEFT BLOCK DIAGONAL UPPER CENTRE TO LOWER RIGHT;So;0;ON;;;;;N;;;;; -1FB51;LOWER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB52;UPPER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; -1FB53;UPPER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;; -1FB54;UPPER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; -1FB55;UPPER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER RIGHT;So;0;ON;;;;;N;;;;; -1FB56;UPPER RIGHT BLOCK DIAGONAL UPPER LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; -1FB57;UPPER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;; -1FB58;UPPER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO UPPER RIGHT;So;0;ON;;;;;N;;;;; -1FB59;UPPER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;; -1FB5A;UPPER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER RIGHT;So;0;ON;;;;;N;;;;; -1FB5B;UPPER LEFT BLOCK DIAGONAL LOWER LEFT TO UPPER CENTRE;So;0;ON;;;;;N;;;;; -1FB5C;UPPER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB5D;UPPER LEFT BLOCK DIAGONAL LOWER CENTRE TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB5E;UPPER LEFT BLOCK DIAGONAL LOWER LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB5F;UPPER LEFT BLOCK DIAGONAL LOWER CENTRE TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB60;UPPER LEFT BLOCK DIAGONAL LOWER LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB61;UPPER LEFT BLOCK DIAGONAL LOWER CENTRE TO UPPER RIGHT;So;0;ON;;;;;N;;;;; -1FB62;UPPER RIGHT BLOCK DIAGONAL UPPER CENTRE TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB63;UPPER RIGHT BLOCK DIAGONAL UPPER LEFT TO UPPER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB64;UPPER RIGHT BLOCK DIAGONAL UPPER CENTRE TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB65;UPPER RIGHT BLOCK DIAGONAL UPPER LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB66;UPPER RIGHT BLOCK DIAGONAL UPPER CENTRE TO LOWER RIGHT;So;0;ON;;;;;N;;;;; -1FB67;UPPER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FB68;UPPER AND RIGHT AND LOWER TRIANGULAR THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;; -1FB69;LEFT AND LOWER AND RIGHT TRIANGULAR THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;; -1FB6A;UPPER AND LEFT AND LOWER TRIANGULAR THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;; -1FB6B;LEFT AND UPPER AND RIGHT TRIANGULAR THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;; -1FB6C;LEFT TRIANGULAR ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; -1FB6D;UPPER TRIANGULAR ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; -1FB6E;RIGHT TRIANGULAR ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; -1FB6F;LOWER TRIANGULAR ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; -1FB70;VERTICAL ONE EIGHTH BLOCK-2;So;0;ON;;;;;N;;;;; -1FB71;VERTICAL ONE EIGHTH BLOCK-3;So;0;ON;;;;;N;;;;; -1FB72;VERTICAL ONE EIGHTH BLOCK-4;So;0;ON;;;;;N;;;;; -1FB73;VERTICAL ONE EIGHTH BLOCK-5;So;0;ON;;;;;N;;;;; -1FB74;VERTICAL ONE EIGHTH BLOCK-6;So;0;ON;;;;;N;;;;; -1FB75;VERTICAL ONE EIGHTH BLOCK-7;So;0;ON;;;;;N;;;;; -1FB76;HORIZONTAL ONE EIGHTH BLOCK-2;So;0;ON;;;;;N;;;;; -1FB77;HORIZONTAL ONE EIGHTH BLOCK-3;So;0;ON;;;;;N;;;;; -1FB78;HORIZONTAL ONE EIGHTH BLOCK-4;So;0;ON;;;;;N;;;;; -1FB79;HORIZONTAL ONE EIGHTH BLOCK-5;So;0;ON;;;;;N;;;;; -1FB7A;HORIZONTAL ONE EIGHTH BLOCK-6;So;0;ON;;;;;N;;;;; -1FB7B;HORIZONTAL ONE EIGHTH BLOCK-7;So;0;ON;;;;;N;;;;; -1FB7C;LEFT AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; -1FB7D;LEFT AND UPPER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; -1FB7E;RIGHT AND UPPER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; -1FB7F;RIGHT AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; -1FB80;UPPER AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; -1FB81;HORIZONTAL ONE EIGHTH BLOCK-1358;So;0;ON;;;;;N;;;;; -1FB82;UPPER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; -1FB83;UPPER THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; -1FB84;UPPER FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; -1FB85;UPPER THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;; -1FB86;UPPER SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; -1FB87;RIGHT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; -1FB88;RIGHT THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; -1FB89;RIGHT FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; -1FB8A;RIGHT THREE QUARTERS BLOCK;So;0;ON;;;;;N;;;;; -1FB8B;RIGHT SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; -1FB8C;LEFT HALF MEDIUM SHADE;So;0;ON;;;;;N;;;;; -1FB8D;RIGHT HALF MEDIUM SHADE;So;0;ON;;;;;N;;;;; -1FB8E;UPPER HALF MEDIUM SHADE;So;0;ON;;;;;N;;;;; -1FB8F;LOWER HALF MEDIUM SHADE;So;0;ON;;;;;N;;;;; -1FB90;INVERSE MEDIUM SHADE;So;0;ON;;;;;N;;;;; -1FB91;UPPER HALF BLOCK AND LOWER HALF INVERSE MEDIUM SHADE;So;0;ON;;;;;N;;;;; -1FB92;UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK;So;0;ON;;;;;N;;;;; -1FB94;LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK;So;0;ON;;;;;N;;;;; -1FB95;CHECKER BOARD FILL;So;0;ON;;;;;N;;;;; -1FB96;INVERSE CHECKER BOARD FILL;So;0;ON;;;;;N;;;;; -1FB97;HEAVY HORIZONTAL FILL;So;0;ON;;;;;N;;;;; -1FB98;UPPER LEFT TO LOWER RIGHT FILL;So;0;ON;;;;;N;;;;; -1FB99;UPPER RIGHT TO LOWER LEFT FILL;So;0;ON;;;;;N;;;;; -1FB9A;UPPER AND LOWER TRIANGULAR HALF BLOCK;So;0;ON;;;;;N;;;;; -1FB9B;LEFT AND RIGHT TRIANGULAR HALF BLOCK;So;0;ON;;;;;N;;;;; -1FB9C;UPPER LEFT TRIANGULAR MEDIUM SHADE;So;0;ON;;;;;N;;;;; -1FB9D;UPPER RIGHT TRIANGULAR MEDIUM SHADE;So;0;ON;;;;;N;;;;; -1FB9E;LOWER RIGHT TRIANGULAR MEDIUM SHADE;So;0;ON;;;;;N;;;;; -1FB9F;LOWER LEFT TRIANGULAR MEDIUM SHADE;So;0;ON;;;;;N;;;;; -1FBA0;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT;So;0;ON;;;;;N;;;;; -1FBA1;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FBA2;BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; -1FBA3;BOX DRAWINGS LIGHT DIAGONAL MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; -1FBA4;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; -1FBA5;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; -1FBA6;BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO LOWER CENTRE TO MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FBA7;BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO UPPER CENTRE TO MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FBA8;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT AND MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; -1FBA9;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT AND MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; -1FBAA;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT TO LOWER CENTRE TO MIDDLE LEFT;So;0;ON;;;;;N;;;;; -1FBAB;BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT TO LOWER CENTRE TO MIDDLE RIGHT;So;0;ON;;;;;N;;;;; -1FBAC;BOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO UPPER CENTRE TO MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; -1FBAD;BOX DRAWINGS LIGHT DIAGONAL MIDDLE RIGHT TO UPPER CENTRE TO MIDDLE LEFT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; -1FBAE;BOX DRAWINGS LIGHT DIAGONAL DIAMOND;So;0;ON;;;;;N;;;;; -1FBAF;BOX DRAWINGS LIGHT HORIZONTAL WITH VERTICAL STROKE;So;0;ON;;;;;N;;;;; -1FBB0;ARROWHEAD-SHAPED POINTER;So;0;ON;;;;;N;;;;; -1FBB1;INVERSE CHECK MARK;So;0;ON;;;;;N;;;;; -1FBB2;LEFT HALF RUNNING MAN;So;0;ON;;;;;N;;;;; -1FBB3;RIGHT HALF RUNNING MAN;So;0;ON;;;;;N;;;;; -1FBB4;INVERSE DOWNWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;;;;; -1FBB5;LEFTWARDS ARROW AND UPPER AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; -1FBB6;RIGHTWARDS ARROW AND UPPER AND LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; -1FBB7;DOWNWARDS ARROW AND RIGHT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; -1FBB8;UPWARDS ARROW AND RIGHT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; -1FBB9;LEFT HALF FOLDER;So;0;ON;;;;;N;;;;; -1FBBA;RIGHT HALF FOLDER;So;0;ON;;;;;N;;;;; -1FBBB;VOIDED GREEK CROSS;So;0;ON;;;;;N;;;;; -1FBBC;RIGHT OPEN SQUARED DOT;So;0;ON;;;;;N;;;;; -1FBBD;NEGATIVE DIAGONAL CROSS;So;0;ON;;;;;N;;;;; -1FBBE;NEGATIVE DIAGONAL MIDDLE RIGHT TO LOWER CENTRE;So;0;ON;;;;;N;;;;; -1FBBF;NEGATIVE DIAGONAL DIAMOND;So;0;ON;;;;;N;;;;; -1FBC0;WHITE HEAVY SALTIRE WITH ROUNDED CORNERS;So;0;ON;;;;;N;;;;; -1FBC1;LEFT THIRD WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; -1FBC2;MIDDLE THIRD WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; -1FBC3;RIGHT THIRD WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; -1FBC4;NEGATIVE SQUARED QUESTION MARK;So;0;ON;;;;;N;;;;; -1FBC5;STICK FIGURE;So;0;ON;;;;;N;;;;; -1FBC6;STICK FIGURE WITH ARMS RAISED;So;0;ON;;;;;N;;;;; -1FBC7;STICK FIGURE LEANING LEFT;So;0;ON;;;;;N;;;;; -1FBC8;STICK FIGURE LEANING RIGHT;So;0;ON;;;;;N;;;;; -1FBC9;STICK FIGURE WITH DRESS;So;0;ON;;;;;N;;;;; -1FBCA;WHITE UP-POINTING CHEVRON;So;0;ON;;;;;N;;;;; -1FBF0;SEGMENTED DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;; -1FBF1;SEGMENTED DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;; -1FBF2;SEGMENTED DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;; -1FBF3;SEGMENTED DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;; -1FBF4;SEGMENTED DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;; -1FBF5;SEGMENTED DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;; -1FBF6;SEGMENTED DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;; -1FBF7;SEGMENTED DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;; -1FBF8;SEGMENTED DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;; -1FBF9;SEGMENTED DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;; -20000;<CJK Ideograph Extension B, First>;Lo;0;L;;;;;N;;;;; -2A6DF;<CJK Ideograph Extension B, Last>;Lo;0;L;;;;;N;;;;; -2A700;<CJK Ideograph Extension C, First>;Lo;0;L;;;;;N;;;;; -2B739;<CJK Ideograph Extension C, Last>;Lo;0;L;;;;;N;;;;; -2B740;<CJK Ideograph Extension D, First>;Lo;0;L;;;;;N;;;;; -2B81D;<CJK Ideograph Extension D, Last>;Lo;0;L;;;;;N;;;;; -2B820;<CJK Ideograph Extension E, First>;Lo;0;L;;;;;N;;;;; -2CEA1;<CJK Ideograph Extension E, Last>;Lo;0;L;;;;;N;;;;; -2CEB0;<CJK Ideograph Extension F, First>;Lo;0;L;;;;;N;;;;; -2EBE0;<CJK Ideograph Extension F, Last>;Lo;0;L;;;;;N;;;;; -2EBF0;<CJK Ideograph Extension I, First>;Lo;0;L;;;;;N;;;;; -2EE5D;<CJK Ideograph Extension I, Last>;Lo;0;L;;;;;N;;;;; -2F800;CJK COMPATIBILITY IDEOGRAPH-2F800;Lo;0;L;4E3D;;;;N;;;;; -2F801;CJK COMPATIBILITY IDEOGRAPH-2F801;Lo;0;L;4E38;;;;N;;;;; -2F802;CJK COMPATIBILITY IDEOGRAPH-2F802;Lo;0;L;4E41;;;;N;;;;; -2F803;CJK COMPATIBILITY IDEOGRAPH-2F803;Lo;0;L;20122;;;;N;;;;; -2F804;CJK COMPATIBILITY IDEOGRAPH-2F804;Lo;0;L;4F60;;;;N;;;;; -2F805;CJK COMPATIBILITY IDEOGRAPH-2F805;Lo;0;L;4FAE;;;;N;;;;; -2F806;CJK COMPATIBILITY IDEOGRAPH-2F806;Lo;0;L;4FBB;;;;N;;;;; -2F807;CJK COMPATIBILITY IDEOGRAPH-2F807;Lo;0;L;5002;;;;N;;;;; -2F808;CJK COMPATIBILITY IDEOGRAPH-2F808;Lo;0;L;507A;;;;N;;;;; -2F809;CJK COMPATIBILITY IDEOGRAPH-2F809;Lo;0;L;5099;;;;N;;;;; -2F80A;CJK COMPATIBILITY IDEOGRAPH-2F80A;Lo;0;L;50E7;;;;N;;;;; -2F80B;CJK COMPATIBILITY IDEOGRAPH-2F80B;Lo;0;L;50CF;;;;N;;;;; -2F80C;CJK COMPATIBILITY IDEOGRAPH-2F80C;Lo;0;L;349E;;;;N;;;;; -2F80D;CJK COMPATIBILITY IDEOGRAPH-2F80D;Lo;0;L;2063A;;;;N;;;;; -2F80E;CJK COMPATIBILITY IDEOGRAPH-2F80E;Lo;0;L;514D;;;;N;;;;; -2F80F;CJK COMPATIBILITY IDEOGRAPH-2F80F;Lo;0;L;5154;;;;N;;;;; -2F810;CJK COMPATIBILITY IDEOGRAPH-2F810;Lo;0;L;5164;;;;N;;;;; -2F811;CJK COMPATIBILITY IDEOGRAPH-2F811;Lo;0;L;5177;;;;N;;;;; -2F812;CJK COMPATIBILITY IDEOGRAPH-2F812;Lo;0;L;2051C;;;;N;;;;; -2F813;CJK COMPATIBILITY IDEOGRAPH-2F813;Lo;0;L;34B9;;;;N;;;;; -2F814;CJK COMPATIBILITY IDEOGRAPH-2F814;Lo;0;L;5167;;;;N;;;;; -2F815;CJK COMPATIBILITY IDEOGRAPH-2F815;Lo;0;L;518D;;;;N;;;;; -2F816;CJK COMPATIBILITY IDEOGRAPH-2F816;Lo;0;L;2054B;;;;N;;;;; -2F817;CJK COMPATIBILITY IDEOGRAPH-2F817;Lo;0;L;5197;;;;N;;;;; -2F818;CJK COMPATIBILITY IDEOGRAPH-2F818;Lo;0;L;51A4;;;;N;;;;; -2F819;CJK COMPATIBILITY IDEOGRAPH-2F819;Lo;0;L;4ECC;;;;N;;;;; -2F81A;CJK COMPATIBILITY IDEOGRAPH-2F81A;Lo;0;L;51AC;;;;N;;;;; -2F81B;CJK COMPATIBILITY IDEOGRAPH-2F81B;Lo;0;L;51B5;;;;N;;;;; -2F81C;CJK COMPATIBILITY IDEOGRAPH-2F81C;Lo;0;L;291DF;;;;N;;;;; -2F81D;CJK COMPATIBILITY IDEOGRAPH-2F81D;Lo;0;L;51F5;;;;N;;;;; -2F81E;CJK COMPATIBILITY IDEOGRAPH-2F81E;Lo;0;L;5203;;;;N;;;;; -2F81F;CJK COMPATIBILITY IDEOGRAPH-2F81F;Lo;0;L;34DF;;;;N;;;;; -2F820;CJK COMPATIBILITY IDEOGRAPH-2F820;Lo;0;L;523B;;;;N;;;;; -2F821;CJK COMPATIBILITY IDEOGRAPH-2F821;Lo;0;L;5246;;;;N;;;;; -2F822;CJK COMPATIBILITY IDEOGRAPH-2F822;Lo;0;L;5272;;;;N;;;;; -2F823;CJK COMPATIBILITY IDEOGRAPH-2F823;Lo;0;L;5277;;;;N;;;;; -2F824;CJK COMPATIBILITY IDEOGRAPH-2F824;Lo;0;L;3515;;;;N;;;;; -2F825;CJK COMPATIBILITY IDEOGRAPH-2F825;Lo;0;L;52C7;;;;N;;;;; -2F826;CJK COMPATIBILITY IDEOGRAPH-2F826;Lo;0;L;52C9;;;;N;;;;; -2F827;CJK COMPATIBILITY IDEOGRAPH-2F827;Lo;0;L;52E4;;;;N;;;;; -2F828;CJK COMPATIBILITY IDEOGRAPH-2F828;Lo;0;L;52FA;;;;N;;;;; -2F829;CJK COMPATIBILITY IDEOGRAPH-2F829;Lo;0;L;5305;;;;N;;;;; -2F82A;CJK COMPATIBILITY IDEOGRAPH-2F82A;Lo;0;L;5306;;;;N;;;;; -2F82B;CJK COMPATIBILITY IDEOGRAPH-2F82B;Lo;0;L;5317;;;;N;;;;; -2F82C;CJK COMPATIBILITY IDEOGRAPH-2F82C;Lo;0;L;5349;;;;N;;;;; -2F82D;CJK COMPATIBILITY IDEOGRAPH-2F82D;Lo;0;L;5351;;;;N;;;;; -2F82E;CJK COMPATIBILITY IDEOGRAPH-2F82E;Lo;0;L;535A;;;;N;;;;; -2F82F;CJK COMPATIBILITY IDEOGRAPH-2F82F;Lo;0;L;5373;;;;N;;;;; -2F830;CJK COMPATIBILITY IDEOGRAPH-2F830;Lo;0;L;537D;;;;N;;;;; -2F831;CJK COMPATIBILITY IDEOGRAPH-2F831;Lo;0;L;537F;;;;N;;;;; -2F832;CJK COMPATIBILITY IDEOGRAPH-2F832;Lo;0;L;537F;;;;N;;;;; -2F833;CJK COMPATIBILITY IDEOGRAPH-2F833;Lo;0;L;537F;;;;N;;;;; -2F834;CJK COMPATIBILITY IDEOGRAPH-2F834;Lo;0;L;20A2C;;;;N;;;;; -2F835;CJK COMPATIBILITY IDEOGRAPH-2F835;Lo;0;L;7070;;;;N;;;;; -2F836;CJK COMPATIBILITY IDEOGRAPH-2F836;Lo;0;L;53CA;;;;N;;;;; -2F837;CJK COMPATIBILITY IDEOGRAPH-2F837;Lo;0;L;53DF;;;;N;;;;; -2F838;CJK COMPATIBILITY IDEOGRAPH-2F838;Lo;0;L;20B63;;;;N;;;;; -2F839;CJK COMPATIBILITY IDEOGRAPH-2F839;Lo;0;L;53EB;;;;N;;;;; -2F83A;CJK COMPATIBILITY IDEOGRAPH-2F83A;Lo;0;L;53F1;;;;N;;;;; -2F83B;CJK COMPATIBILITY IDEOGRAPH-2F83B;Lo;0;L;5406;;;;N;;;;; -2F83C;CJK COMPATIBILITY IDEOGRAPH-2F83C;Lo;0;L;549E;;;;N;;;;; -2F83D;CJK COMPATIBILITY IDEOGRAPH-2F83D;Lo;0;L;5438;;;;N;;;;; -2F83E;CJK COMPATIBILITY IDEOGRAPH-2F83E;Lo;0;L;5448;;;;N;;;;; -2F83F;CJK COMPATIBILITY IDEOGRAPH-2F83F;Lo;0;L;5468;;;;N;;;;; -2F840;CJK COMPATIBILITY IDEOGRAPH-2F840;Lo;0;L;54A2;;;;N;;;;; -2F841;CJK COMPATIBILITY IDEOGRAPH-2F841;Lo;0;L;54F6;;;;N;;;;; -2F842;CJK COMPATIBILITY IDEOGRAPH-2F842;Lo;0;L;5510;;;;N;;;;; -2F843;CJK COMPATIBILITY IDEOGRAPH-2F843;Lo;0;L;5553;;;;N;;;;; -2F844;CJK COMPATIBILITY IDEOGRAPH-2F844;Lo;0;L;5563;;;;N;;;;; -2F845;CJK COMPATIBILITY IDEOGRAPH-2F845;Lo;0;L;5584;;;;N;;;;; -2F846;CJK COMPATIBILITY IDEOGRAPH-2F846;Lo;0;L;5584;;;;N;;;;; -2F847;CJK COMPATIBILITY IDEOGRAPH-2F847;Lo;0;L;5599;;;;N;;;;; -2F848;CJK COMPATIBILITY IDEOGRAPH-2F848;Lo;0;L;55AB;;;;N;;;;; -2F849;CJK COMPATIBILITY IDEOGRAPH-2F849;Lo;0;L;55B3;;;;N;;;;; -2F84A;CJK COMPATIBILITY IDEOGRAPH-2F84A;Lo;0;L;55C2;;;;N;;;;; -2F84B;CJK COMPATIBILITY IDEOGRAPH-2F84B;Lo;0;L;5716;;;;N;;;;; -2F84C;CJK COMPATIBILITY IDEOGRAPH-2F84C;Lo;0;L;5606;;;;N;;;;; -2F84D;CJK COMPATIBILITY IDEOGRAPH-2F84D;Lo;0;L;5717;;;;N;;;;; -2F84E;CJK COMPATIBILITY IDEOGRAPH-2F84E;Lo;0;L;5651;;;;N;;;;; -2F84F;CJK COMPATIBILITY IDEOGRAPH-2F84F;Lo;0;L;5674;;;;N;;;;; -2F850;CJK COMPATIBILITY IDEOGRAPH-2F850;Lo;0;L;5207;;;;N;;;;; -2F851;CJK COMPATIBILITY IDEOGRAPH-2F851;Lo;0;L;58EE;;;;N;;;;; -2F852;CJK COMPATIBILITY IDEOGRAPH-2F852;Lo;0;L;57CE;;;;N;;;;; -2F853;CJK COMPATIBILITY IDEOGRAPH-2F853;Lo;0;L;57F4;;;;N;;;;; -2F854;CJK COMPATIBILITY IDEOGRAPH-2F854;Lo;0;L;580D;;;;N;;;;; -2F855;CJK COMPATIBILITY IDEOGRAPH-2F855;Lo;0;L;578B;;;;N;;;;; -2F856;CJK COMPATIBILITY IDEOGRAPH-2F856;Lo;0;L;5832;;;;N;;;;; -2F857;CJK COMPATIBILITY IDEOGRAPH-2F857;Lo;0;L;5831;;;;N;;;;; -2F858;CJK COMPATIBILITY IDEOGRAPH-2F858;Lo;0;L;58AC;;;;N;;;;; -2F859;CJK COMPATIBILITY IDEOGRAPH-2F859;Lo;0;L;214E4;;;;N;;;;; -2F85A;CJK COMPATIBILITY IDEOGRAPH-2F85A;Lo;0;L;58F2;;;;N;;;;; -2F85B;CJK COMPATIBILITY IDEOGRAPH-2F85B;Lo;0;L;58F7;;;;N;;;;; -2F85C;CJK COMPATIBILITY IDEOGRAPH-2F85C;Lo;0;L;5906;;;;N;;;;; -2F85D;CJK COMPATIBILITY IDEOGRAPH-2F85D;Lo;0;L;591A;;;;N;;;;; -2F85E;CJK COMPATIBILITY IDEOGRAPH-2F85E;Lo;0;L;5922;;;;N;;;;; -2F85F;CJK COMPATIBILITY IDEOGRAPH-2F85F;Lo;0;L;5962;;;;N;;;;; -2F860;CJK COMPATIBILITY IDEOGRAPH-2F860;Lo;0;L;216A8;;;;N;;;;; -2F861;CJK COMPATIBILITY IDEOGRAPH-2F861;Lo;0;L;216EA;;;;N;;;;; -2F862;CJK COMPATIBILITY IDEOGRAPH-2F862;Lo;0;L;59EC;;;;N;;;;; -2F863;CJK COMPATIBILITY IDEOGRAPH-2F863;Lo;0;L;5A1B;;;;N;;;;; -2F864;CJK COMPATIBILITY IDEOGRAPH-2F864;Lo;0;L;5A27;;;;N;;;;; -2F865;CJK COMPATIBILITY IDEOGRAPH-2F865;Lo;0;L;59D8;;;;N;;;;; -2F866;CJK COMPATIBILITY IDEOGRAPH-2F866;Lo;0;L;5A66;;;;N;;;;; -2F867;CJK COMPATIBILITY IDEOGRAPH-2F867;Lo;0;L;36EE;;;;N;;;;; -2F868;CJK COMPATIBILITY IDEOGRAPH-2F868;Lo;0;L;36FC;;;;N;;;;; -2F869;CJK COMPATIBILITY IDEOGRAPH-2F869;Lo;0;L;5B08;;;;N;;;;; -2F86A;CJK COMPATIBILITY IDEOGRAPH-2F86A;Lo;0;L;5B3E;;;;N;;;;; -2F86B;CJK COMPATIBILITY IDEOGRAPH-2F86B;Lo;0;L;5B3E;;;;N;;;;; -2F86C;CJK COMPATIBILITY IDEOGRAPH-2F86C;Lo;0;L;219C8;;;;N;;;;; -2F86D;CJK COMPATIBILITY IDEOGRAPH-2F86D;Lo;0;L;5BC3;;;;N;;;;; -2F86E;CJK COMPATIBILITY IDEOGRAPH-2F86E;Lo;0;L;5BD8;;;;N;;;;; -2F86F;CJK COMPATIBILITY IDEOGRAPH-2F86F;Lo;0;L;5BE7;;;;N;;;;; -2F870;CJK COMPATIBILITY IDEOGRAPH-2F870;Lo;0;L;5BF3;;;;N;;;;; -2F871;CJK COMPATIBILITY IDEOGRAPH-2F871;Lo;0;L;21B18;;;;N;;;;; -2F872;CJK COMPATIBILITY IDEOGRAPH-2F872;Lo;0;L;5BFF;;;;N;;;;; -2F873;CJK COMPATIBILITY IDEOGRAPH-2F873;Lo;0;L;5C06;;;;N;;;;; -2F874;CJK COMPATIBILITY IDEOGRAPH-2F874;Lo;0;L;5F53;;;;N;;;;; -2F875;CJK COMPATIBILITY IDEOGRAPH-2F875;Lo;0;L;5C22;;;;N;;;;; -2F876;CJK COMPATIBILITY IDEOGRAPH-2F876;Lo;0;L;3781;;;;N;;;;; -2F877;CJK COMPATIBILITY IDEOGRAPH-2F877;Lo;0;L;5C60;;;;N;;;;; -2F878;CJK COMPATIBILITY IDEOGRAPH-2F878;Lo;0;L;5C6E;;;;N;;;;; -2F879;CJK COMPATIBILITY IDEOGRAPH-2F879;Lo;0;L;5CC0;;;;N;;;;; -2F87A;CJK COMPATIBILITY IDEOGRAPH-2F87A;Lo;0;L;5C8D;;;;N;;;;; -2F87B;CJK COMPATIBILITY IDEOGRAPH-2F87B;Lo;0;L;21DE4;;;;N;;;;; -2F87C;CJK COMPATIBILITY IDEOGRAPH-2F87C;Lo;0;L;5D43;;;;N;;;;; -2F87D;CJK COMPATIBILITY IDEOGRAPH-2F87D;Lo;0;L;21DE6;;;;N;;;;; -2F87E;CJK COMPATIBILITY IDEOGRAPH-2F87E;Lo;0;L;5D6E;;;;N;;;;; -2F87F;CJK COMPATIBILITY IDEOGRAPH-2F87F;Lo;0;L;5D6B;;;;N;;;;; -2F880;CJK COMPATIBILITY IDEOGRAPH-2F880;Lo;0;L;5D7C;;;;N;;;;; -2F881;CJK COMPATIBILITY IDEOGRAPH-2F881;Lo;0;L;5DE1;;;;N;;;;; -2F882;CJK COMPATIBILITY IDEOGRAPH-2F882;Lo;0;L;5DE2;;;;N;;;;; -2F883;CJK COMPATIBILITY IDEOGRAPH-2F883;Lo;0;L;382F;;;;N;;;;; -2F884;CJK COMPATIBILITY IDEOGRAPH-2F884;Lo;0;L;5DFD;;;;N;;;;; -2F885;CJK COMPATIBILITY IDEOGRAPH-2F885;Lo;0;L;5E28;;;;N;;;;; -2F886;CJK COMPATIBILITY IDEOGRAPH-2F886;Lo;0;L;5E3D;;;;N;;;;; -2F887;CJK COMPATIBILITY IDEOGRAPH-2F887;Lo;0;L;5E69;;;;N;;;;; -2F888;CJK COMPATIBILITY IDEOGRAPH-2F888;Lo;0;L;3862;;;;N;;;;; -2F889;CJK COMPATIBILITY IDEOGRAPH-2F889;Lo;0;L;22183;;;;N;;;;; -2F88A;CJK COMPATIBILITY IDEOGRAPH-2F88A;Lo;0;L;387C;;;;N;;;;; -2F88B;CJK COMPATIBILITY IDEOGRAPH-2F88B;Lo;0;L;5EB0;;;;N;;;;; -2F88C;CJK COMPATIBILITY IDEOGRAPH-2F88C;Lo;0;L;5EB3;;;;N;;;;; -2F88D;CJK COMPATIBILITY IDEOGRAPH-2F88D;Lo;0;L;5EB6;;;;N;;;;; -2F88E;CJK COMPATIBILITY IDEOGRAPH-2F88E;Lo;0;L;5ECA;;;;N;;;;; -2F88F;CJK COMPATIBILITY IDEOGRAPH-2F88F;Lo;0;L;2A392;;;;N;;;;; -2F890;CJK COMPATIBILITY IDEOGRAPH-2F890;Lo;0;L;5EFE;;;9;N;;;;; -2F891;CJK COMPATIBILITY IDEOGRAPH-2F891;Lo;0;L;22331;;;;N;;;;; -2F892;CJK COMPATIBILITY IDEOGRAPH-2F892;Lo;0;L;22331;;;;N;;;;; -2F893;CJK COMPATIBILITY IDEOGRAPH-2F893;Lo;0;L;8201;;;;N;;;;; -2F894;CJK COMPATIBILITY IDEOGRAPH-2F894;Lo;0;L;5F22;;;;N;;;;; -2F895;CJK COMPATIBILITY IDEOGRAPH-2F895;Lo;0;L;5F22;;;;N;;;;; -2F896;CJK COMPATIBILITY IDEOGRAPH-2F896;Lo;0;L;38C7;;;;N;;;;; -2F897;CJK COMPATIBILITY IDEOGRAPH-2F897;Lo;0;L;232B8;;;;N;;;;; -2F898;CJK COMPATIBILITY IDEOGRAPH-2F898;Lo;0;L;261DA;;;;N;;;;; -2F899;CJK COMPATIBILITY IDEOGRAPH-2F899;Lo;0;L;5F62;;;;N;;;;; -2F89A;CJK COMPATIBILITY IDEOGRAPH-2F89A;Lo;0;L;5F6B;;;;N;;;;; -2F89B;CJK COMPATIBILITY IDEOGRAPH-2F89B;Lo;0;L;38E3;;;;N;;;;; -2F89C;CJK COMPATIBILITY IDEOGRAPH-2F89C;Lo;0;L;5F9A;;;;N;;;;; -2F89D;CJK COMPATIBILITY IDEOGRAPH-2F89D;Lo;0;L;5FCD;;;;N;;;;; -2F89E;CJK COMPATIBILITY IDEOGRAPH-2F89E;Lo;0;L;5FD7;;;;N;;;;; -2F89F;CJK COMPATIBILITY IDEOGRAPH-2F89F;Lo;0;L;5FF9;;;;N;;;;; -2F8A0;CJK COMPATIBILITY IDEOGRAPH-2F8A0;Lo;0;L;6081;;;;N;;;;; -2F8A1;CJK COMPATIBILITY IDEOGRAPH-2F8A1;Lo;0;L;393A;;;;N;;;;; -2F8A2;CJK COMPATIBILITY IDEOGRAPH-2F8A2;Lo;0;L;391C;;;;N;;;;; -2F8A3;CJK COMPATIBILITY IDEOGRAPH-2F8A3;Lo;0;L;6094;;;;N;;;;; -2F8A4;CJK COMPATIBILITY IDEOGRAPH-2F8A4;Lo;0;L;226D4;;;;N;;;;; -2F8A5;CJK COMPATIBILITY IDEOGRAPH-2F8A5;Lo;0;L;60C7;;;;N;;;;; -2F8A6;CJK COMPATIBILITY IDEOGRAPH-2F8A6;Lo;0;L;6148;;;;N;;;;; -2F8A7;CJK COMPATIBILITY IDEOGRAPH-2F8A7;Lo;0;L;614C;;;;N;;;;; -2F8A8;CJK COMPATIBILITY IDEOGRAPH-2F8A8;Lo;0;L;614E;;;;N;;;;; -2F8A9;CJK COMPATIBILITY IDEOGRAPH-2F8A9;Lo;0;L;614C;;;;N;;;;; -2F8AA;CJK COMPATIBILITY IDEOGRAPH-2F8AA;Lo;0;L;617A;;;;N;;;;; -2F8AB;CJK COMPATIBILITY IDEOGRAPH-2F8AB;Lo;0;L;618E;;;;N;;;;; -2F8AC;CJK COMPATIBILITY IDEOGRAPH-2F8AC;Lo;0;L;61B2;;;;N;;;;; -2F8AD;CJK COMPATIBILITY IDEOGRAPH-2F8AD;Lo;0;L;61A4;;;;N;;;;; -2F8AE;CJK COMPATIBILITY IDEOGRAPH-2F8AE;Lo;0;L;61AF;;;;N;;;;; -2F8AF;CJK COMPATIBILITY IDEOGRAPH-2F8AF;Lo;0;L;61DE;;;;N;;;;; -2F8B0;CJK COMPATIBILITY IDEOGRAPH-2F8B0;Lo;0;L;61F2;;;;N;;;;; -2F8B1;CJK COMPATIBILITY IDEOGRAPH-2F8B1;Lo;0;L;61F6;;;;N;;;;; -2F8B2;CJK COMPATIBILITY IDEOGRAPH-2F8B2;Lo;0;L;6210;;;;N;;;;; -2F8B3;CJK COMPATIBILITY IDEOGRAPH-2F8B3;Lo;0;L;621B;;;;N;;;;; -2F8B4;CJK COMPATIBILITY IDEOGRAPH-2F8B4;Lo;0;L;625D;;;;N;;;;; -2F8B5;CJK COMPATIBILITY IDEOGRAPH-2F8B5;Lo;0;L;62B1;;;;N;;;;; -2F8B6;CJK COMPATIBILITY IDEOGRAPH-2F8B6;Lo;0;L;62D4;;;;N;;;;; -2F8B7;CJK COMPATIBILITY IDEOGRAPH-2F8B7;Lo;0;L;6350;;;;N;;;;; -2F8B8;CJK COMPATIBILITY IDEOGRAPH-2F8B8;Lo;0;L;22B0C;;;;N;;;;; -2F8B9;CJK COMPATIBILITY IDEOGRAPH-2F8B9;Lo;0;L;633D;;;;N;;;;; -2F8BA;CJK COMPATIBILITY IDEOGRAPH-2F8BA;Lo;0;L;62FC;;;;N;;;;; -2F8BB;CJK COMPATIBILITY IDEOGRAPH-2F8BB;Lo;0;L;6368;;;;N;;;;; -2F8BC;CJK COMPATIBILITY IDEOGRAPH-2F8BC;Lo;0;L;6383;;;;N;;;;; -2F8BD;CJK COMPATIBILITY IDEOGRAPH-2F8BD;Lo;0;L;63E4;;;;N;;;;; -2F8BE;CJK COMPATIBILITY IDEOGRAPH-2F8BE;Lo;0;L;22BF1;;;;N;;;;; -2F8BF;CJK COMPATIBILITY IDEOGRAPH-2F8BF;Lo;0;L;6422;;;;N;;;;; -2F8C0;CJK COMPATIBILITY IDEOGRAPH-2F8C0;Lo;0;L;63C5;;;;N;;;;; -2F8C1;CJK COMPATIBILITY IDEOGRAPH-2F8C1;Lo;0;L;63A9;;;;N;;;;; -2F8C2;CJK COMPATIBILITY IDEOGRAPH-2F8C2;Lo;0;L;3A2E;;;;N;;;;; -2F8C3;CJK COMPATIBILITY IDEOGRAPH-2F8C3;Lo;0;L;6469;;;;N;;;;; -2F8C4;CJK COMPATIBILITY IDEOGRAPH-2F8C4;Lo;0;L;647E;;;;N;;;;; -2F8C5;CJK COMPATIBILITY IDEOGRAPH-2F8C5;Lo;0;L;649D;;;;N;;;;; -2F8C6;CJK COMPATIBILITY IDEOGRAPH-2F8C6;Lo;0;L;6477;;;;N;;;;; -2F8C7;CJK COMPATIBILITY IDEOGRAPH-2F8C7;Lo;0;L;3A6C;;;;N;;;;; -2F8C8;CJK COMPATIBILITY IDEOGRAPH-2F8C8;Lo;0;L;654F;;;;N;;;;; -2F8C9;CJK COMPATIBILITY IDEOGRAPH-2F8C9;Lo;0;L;656C;;;;N;;;;; -2F8CA;CJK COMPATIBILITY IDEOGRAPH-2F8CA;Lo;0;L;2300A;;;;N;;;;; -2F8CB;CJK COMPATIBILITY IDEOGRAPH-2F8CB;Lo;0;L;65E3;;;;N;;;;; -2F8CC;CJK COMPATIBILITY IDEOGRAPH-2F8CC;Lo;0;L;66F8;;;;N;;;;; -2F8CD;CJK COMPATIBILITY IDEOGRAPH-2F8CD;Lo;0;L;6649;;;;N;;;;; -2F8CE;CJK COMPATIBILITY IDEOGRAPH-2F8CE;Lo;0;L;3B19;;;;N;;;;; -2F8CF;CJK COMPATIBILITY IDEOGRAPH-2F8CF;Lo;0;L;6691;;;;N;;;;; -2F8D0;CJK COMPATIBILITY IDEOGRAPH-2F8D0;Lo;0;L;3B08;;;;N;;;;; -2F8D1;CJK COMPATIBILITY IDEOGRAPH-2F8D1;Lo;0;L;3AE4;;;;N;;;;; -2F8D2;CJK COMPATIBILITY IDEOGRAPH-2F8D2;Lo;0;L;5192;;;;N;;;;; -2F8D3;CJK COMPATIBILITY IDEOGRAPH-2F8D3;Lo;0;L;5195;;;;N;;;;; -2F8D4;CJK COMPATIBILITY IDEOGRAPH-2F8D4;Lo;0;L;6700;;;;N;;;;; -2F8D5;CJK COMPATIBILITY IDEOGRAPH-2F8D5;Lo;0;L;669C;;;;N;;;;; -2F8D6;CJK COMPATIBILITY IDEOGRAPH-2F8D6;Lo;0;L;80AD;;;;N;;;;; -2F8D7;CJK COMPATIBILITY IDEOGRAPH-2F8D7;Lo;0;L;43D9;;;;N;;;;; -2F8D8;CJK COMPATIBILITY IDEOGRAPH-2F8D8;Lo;0;L;6717;;;;N;;;;; -2F8D9;CJK COMPATIBILITY IDEOGRAPH-2F8D9;Lo;0;L;671B;;;;N;;;;; -2F8DA;CJK COMPATIBILITY IDEOGRAPH-2F8DA;Lo;0;L;6721;;;;N;;;;; -2F8DB;CJK COMPATIBILITY IDEOGRAPH-2F8DB;Lo;0;L;675E;;;;N;;;;; -2F8DC;CJK COMPATIBILITY IDEOGRAPH-2F8DC;Lo;0;L;6753;;;;N;;;;; -2F8DD;CJK COMPATIBILITY IDEOGRAPH-2F8DD;Lo;0;L;233C3;;;;N;;;;; -2F8DE;CJK COMPATIBILITY IDEOGRAPH-2F8DE;Lo;0;L;3B49;;;;N;;;;; -2F8DF;CJK COMPATIBILITY IDEOGRAPH-2F8DF;Lo;0;L;67FA;;;;N;;;;; -2F8E0;CJK COMPATIBILITY IDEOGRAPH-2F8E0;Lo;0;L;6785;;;;N;;;;; -2F8E1;CJK COMPATIBILITY IDEOGRAPH-2F8E1;Lo;0;L;6852;;;;N;;;;; -2F8E2;CJK COMPATIBILITY IDEOGRAPH-2F8E2;Lo;0;L;6885;;;;N;;;;; -2F8E3;CJK COMPATIBILITY IDEOGRAPH-2F8E3;Lo;0;L;2346D;;;;N;;;;; -2F8E4;CJK COMPATIBILITY IDEOGRAPH-2F8E4;Lo;0;L;688E;;;;N;;;;; -2F8E5;CJK COMPATIBILITY IDEOGRAPH-2F8E5;Lo;0;L;681F;;;;N;;;;; -2F8E6;CJK COMPATIBILITY IDEOGRAPH-2F8E6;Lo;0;L;6914;;;;N;;;;; -2F8E7;CJK COMPATIBILITY IDEOGRAPH-2F8E7;Lo;0;L;3B9D;;;;N;;;;; -2F8E8;CJK COMPATIBILITY IDEOGRAPH-2F8E8;Lo;0;L;6942;;;;N;;;;; -2F8E9;CJK COMPATIBILITY IDEOGRAPH-2F8E9;Lo;0;L;69A3;;;;N;;;;; -2F8EA;CJK COMPATIBILITY IDEOGRAPH-2F8EA;Lo;0;L;69EA;;;;N;;;;; -2F8EB;CJK COMPATIBILITY IDEOGRAPH-2F8EB;Lo;0;L;6AA8;;;;N;;;;; -2F8EC;CJK COMPATIBILITY IDEOGRAPH-2F8EC;Lo;0;L;236A3;;;;N;;;;; -2F8ED;CJK COMPATIBILITY IDEOGRAPH-2F8ED;Lo;0;L;6ADB;;;;N;;;;; -2F8EE;CJK COMPATIBILITY IDEOGRAPH-2F8EE;Lo;0;L;3C18;;;;N;;;;; -2F8EF;CJK COMPATIBILITY IDEOGRAPH-2F8EF;Lo;0;L;6B21;;;;N;;;;; -2F8F0;CJK COMPATIBILITY IDEOGRAPH-2F8F0;Lo;0;L;238A7;;;;N;;;;; -2F8F1;CJK COMPATIBILITY IDEOGRAPH-2F8F1;Lo;0;L;6B54;;;;N;;;;; -2F8F2;CJK COMPATIBILITY IDEOGRAPH-2F8F2;Lo;0;L;3C4E;;;;N;;;;; -2F8F3;CJK COMPATIBILITY IDEOGRAPH-2F8F3;Lo;0;L;6B72;;;;N;;;;; -2F8F4;CJK COMPATIBILITY IDEOGRAPH-2F8F4;Lo;0;L;6B9F;;;;N;;;;; -2F8F5;CJK COMPATIBILITY IDEOGRAPH-2F8F5;Lo;0;L;6BBA;;;;N;;;;; -2F8F6;CJK COMPATIBILITY IDEOGRAPH-2F8F6;Lo;0;L;6BBB;;;;N;;;;; -2F8F7;CJK COMPATIBILITY IDEOGRAPH-2F8F7;Lo;0;L;23A8D;;;;N;;;;; -2F8F8;CJK COMPATIBILITY IDEOGRAPH-2F8F8;Lo;0;L;21D0B;;;;N;;;;; -2F8F9;CJK COMPATIBILITY IDEOGRAPH-2F8F9;Lo;0;L;23AFA;;;;N;;;;; -2F8FA;CJK COMPATIBILITY IDEOGRAPH-2F8FA;Lo;0;L;6C4E;;;;N;;;;; -2F8FB;CJK COMPATIBILITY IDEOGRAPH-2F8FB;Lo;0;L;23CBC;;;;N;;;;; -2F8FC;CJK COMPATIBILITY IDEOGRAPH-2F8FC;Lo;0;L;6CBF;;;;N;;;;; -2F8FD;CJK COMPATIBILITY IDEOGRAPH-2F8FD;Lo;0;L;6CCD;;;;N;;;;; -2F8FE;CJK COMPATIBILITY IDEOGRAPH-2F8FE;Lo;0;L;6C67;;;;N;;;;; -2F8FF;CJK COMPATIBILITY IDEOGRAPH-2F8FF;Lo;0;L;6D16;;;;N;;;;; -2F900;CJK COMPATIBILITY IDEOGRAPH-2F900;Lo;0;L;6D3E;;;;N;;;;; -2F901;CJK COMPATIBILITY IDEOGRAPH-2F901;Lo;0;L;6D77;;;;N;;;;; -2F902;CJK COMPATIBILITY IDEOGRAPH-2F902;Lo;0;L;6D41;;;;N;;;;; -2F903;CJK COMPATIBILITY IDEOGRAPH-2F903;Lo;0;L;6D69;;;;N;;;;; -2F904;CJK COMPATIBILITY IDEOGRAPH-2F904;Lo;0;L;6D78;;;;N;;;;; -2F905;CJK COMPATIBILITY IDEOGRAPH-2F905;Lo;0;L;6D85;;;;N;;;;; -2F906;CJK COMPATIBILITY IDEOGRAPH-2F906;Lo;0;L;23D1E;;;;N;;;;; -2F907;CJK COMPATIBILITY IDEOGRAPH-2F907;Lo;0;L;6D34;;;;N;;;;; -2F908;CJK COMPATIBILITY IDEOGRAPH-2F908;Lo;0;L;6E2F;;;;N;;;;; -2F909;CJK COMPATIBILITY IDEOGRAPH-2F909;Lo;0;L;6E6E;;;;N;;;;; -2F90A;CJK COMPATIBILITY IDEOGRAPH-2F90A;Lo;0;L;3D33;;;;N;;;;; -2F90B;CJK COMPATIBILITY IDEOGRAPH-2F90B;Lo;0;L;6ECB;;;;N;;;;; -2F90C;CJK COMPATIBILITY IDEOGRAPH-2F90C;Lo;0;L;6EC7;;;;N;;;;; -2F90D;CJK COMPATIBILITY IDEOGRAPH-2F90D;Lo;0;L;23ED1;;;;N;;;;; -2F90E;CJK COMPATIBILITY IDEOGRAPH-2F90E;Lo;0;L;6DF9;;;;N;;;;; -2F90F;CJK COMPATIBILITY IDEOGRAPH-2F90F;Lo;0;L;6F6E;;;;N;;;;; -2F910;CJK COMPATIBILITY IDEOGRAPH-2F910;Lo;0;L;23F5E;;;;N;;;;; -2F911;CJK COMPATIBILITY IDEOGRAPH-2F911;Lo;0;L;23F8E;;;;N;;;;; -2F912;CJK COMPATIBILITY IDEOGRAPH-2F912;Lo;0;L;6FC6;;;;N;;;;; -2F913;CJK COMPATIBILITY IDEOGRAPH-2F913;Lo;0;L;7039;;;;N;;;;; -2F914;CJK COMPATIBILITY IDEOGRAPH-2F914;Lo;0;L;701E;;;;N;;;;; -2F915;CJK COMPATIBILITY IDEOGRAPH-2F915;Lo;0;L;701B;;;;N;;;;; -2F916;CJK COMPATIBILITY IDEOGRAPH-2F916;Lo;0;L;3D96;;;;N;;;;; -2F917;CJK COMPATIBILITY IDEOGRAPH-2F917;Lo;0;L;704A;;;;N;;;;; -2F918;CJK COMPATIBILITY IDEOGRAPH-2F918;Lo;0;L;707D;;;;N;;;;; -2F919;CJK COMPATIBILITY IDEOGRAPH-2F919;Lo;0;L;7077;;;;N;;;;; -2F91A;CJK COMPATIBILITY IDEOGRAPH-2F91A;Lo;0;L;70AD;;;;N;;;;; -2F91B;CJK COMPATIBILITY IDEOGRAPH-2F91B;Lo;0;L;20525;;;;N;;;;; -2F91C;CJK COMPATIBILITY IDEOGRAPH-2F91C;Lo;0;L;7145;;;;N;;;;; -2F91D;CJK COMPATIBILITY IDEOGRAPH-2F91D;Lo;0;L;24263;;;;N;;;;; -2F91E;CJK COMPATIBILITY IDEOGRAPH-2F91E;Lo;0;L;719C;;;;N;;;;; -2F91F;CJK COMPATIBILITY IDEOGRAPH-2F91F;Lo;0;L;243AB;;;;N;;;;; -2F920;CJK COMPATIBILITY IDEOGRAPH-2F920;Lo;0;L;7228;;;;N;;;;; -2F921;CJK COMPATIBILITY IDEOGRAPH-2F921;Lo;0;L;7235;;;;N;;;;; -2F922;CJK COMPATIBILITY IDEOGRAPH-2F922;Lo;0;L;7250;;;;N;;;;; -2F923;CJK COMPATIBILITY IDEOGRAPH-2F923;Lo;0;L;24608;;;;N;;;;; -2F924;CJK COMPATIBILITY IDEOGRAPH-2F924;Lo;0;L;7280;;;;N;;;;; -2F925;CJK COMPATIBILITY IDEOGRAPH-2F925;Lo;0;L;7295;;;;N;;;;; -2F926;CJK COMPATIBILITY IDEOGRAPH-2F926;Lo;0;L;24735;;;;N;;;;; -2F927;CJK COMPATIBILITY IDEOGRAPH-2F927;Lo;0;L;24814;;;;N;;;;; -2F928;CJK COMPATIBILITY IDEOGRAPH-2F928;Lo;0;L;737A;;;;N;;;;; -2F929;CJK COMPATIBILITY IDEOGRAPH-2F929;Lo;0;L;738B;;;;N;;;;; -2F92A;CJK COMPATIBILITY IDEOGRAPH-2F92A;Lo;0;L;3EAC;;;;N;;;;; -2F92B;CJK COMPATIBILITY IDEOGRAPH-2F92B;Lo;0;L;73A5;;;;N;;;;; -2F92C;CJK COMPATIBILITY IDEOGRAPH-2F92C;Lo;0;L;3EB8;;;;N;;;;; -2F92D;CJK COMPATIBILITY IDEOGRAPH-2F92D;Lo;0;L;3EB8;;;;N;;;;; -2F92E;CJK COMPATIBILITY IDEOGRAPH-2F92E;Lo;0;L;7447;;;;N;;;;; -2F92F;CJK COMPATIBILITY IDEOGRAPH-2F92F;Lo;0;L;745C;;;;N;;;;; -2F930;CJK COMPATIBILITY IDEOGRAPH-2F930;Lo;0;L;7471;;;;N;;;;; -2F931;CJK COMPATIBILITY IDEOGRAPH-2F931;Lo;0;L;7485;;;;N;;;;; -2F932;CJK COMPATIBILITY IDEOGRAPH-2F932;Lo;0;L;74CA;;;;N;;;;; -2F933;CJK COMPATIBILITY IDEOGRAPH-2F933;Lo;0;L;3F1B;;;;N;;;;; -2F934;CJK COMPATIBILITY IDEOGRAPH-2F934;Lo;0;L;7524;;;;N;;;;; -2F935;CJK COMPATIBILITY IDEOGRAPH-2F935;Lo;0;L;24C36;;;;N;;;;; -2F936;CJK COMPATIBILITY IDEOGRAPH-2F936;Lo;0;L;753E;;;;N;;;;; -2F937;CJK COMPATIBILITY IDEOGRAPH-2F937;Lo;0;L;24C92;;;;N;;;;; -2F938;CJK COMPATIBILITY IDEOGRAPH-2F938;Lo;0;L;7570;;;;N;;;;; -2F939;CJK COMPATIBILITY IDEOGRAPH-2F939;Lo;0;L;2219F;;;;N;;;;; -2F93A;CJK COMPATIBILITY IDEOGRAPH-2F93A;Lo;0;L;7610;;;;N;;;;; -2F93B;CJK COMPATIBILITY IDEOGRAPH-2F93B;Lo;0;L;24FA1;;;;N;;;;; -2F93C;CJK COMPATIBILITY IDEOGRAPH-2F93C;Lo;0;L;24FB8;;;;N;;;;; -2F93D;CJK COMPATIBILITY IDEOGRAPH-2F93D;Lo;0;L;25044;;;;N;;;;; -2F93E;CJK COMPATIBILITY IDEOGRAPH-2F93E;Lo;0;L;3FFC;;;;N;;;;; -2F93F;CJK COMPATIBILITY IDEOGRAPH-2F93F;Lo;0;L;4008;;;;N;;;;; -2F940;CJK COMPATIBILITY IDEOGRAPH-2F940;Lo;0;L;76F4;;;;N;;;;; -2F941;CJK COMPATIBILITY IDEOGRAPH-2F941;Lo;0;L;250F3;;;;N;;;;; -2F942;CJK COMPATIBILITY IDEOGRAPH-2F942;Lo;0;L;250F2;;;;N;;;;; -2F943;CJK COMPATIBILITY IDEOGRAPH-2F943;Lo;0;L;25119;;;;N;;;;; -2F944;CJK COMPATIBILITY IDEOGRAPH-2F944;Lo;0;L;25133;;;;N;;;;; -2F945;CJK COMPATIBILITY IDEOGRAPH-2F945;Lo;0;L;771E;;;;N;;;;; -2F946;CJK COMPATIBILITY IDEOGRAPH-2F946;Lo;0;L;771F;;;;N;;;;; -2F947;CJK COMPATIBILITY IDEOGRAPH-2F947;Lo;0;L;771F;;;;N;;;;; -2F948;CJK COMPATIBILITY IDEOGRAPH-2F948;Lo;0;L;774A;;;;N;;;;; -2F949;CJK COMPATIBILITY IDEOGRAPH-2F949;Lo;0;L;4039;;;;N;;;;; -2F94A;CJK COMPATIBILITY IDEOGRAPH-2F94A;Lo;0;L;778B;;;;N;;;;; -2F94B;CJK COMPATIBILITY IDEOGRAPH-2F94B;Lo;0;L;4046;;;;N;;;;; -2F94C;CJK COMPATIBILITY IDEOGRAPH-2F94C;Lo;0;L;4096;;;;N;;;;; -2F94D;CJK COMPATIBILITY IDEOGRAPH-2F94D;Lo;0;L;2541D;;;;N;;;;; -2F94E;CJK COMPATIBILITY IDEOGRAPH-2F94E;Lo;0;L;784E;;;;N;;;;; -2F94F;CJK COMPATIBILITY IDEOGRAPH-2F94F;Lo;0;L;788C;;;;N;;;;; -2F950;CJK COMPATIBILITY IDEOGRAPH-2F950;Lo;0;L;78CC;;;;N;;;;; -2F951;CJK COMPATIBILITY IDEOGRAPH-2F951;Lo;0;L;40E3;;;;N;;;;; -2F952;CJK COMPATIBILITY IDEOGRAPH-2F952;Lo;0;L;25626;;;;N;;;;; -2F953;CJK COMPATIBILITY IDEOGRAPH-2F953;Lo;0;L;7956;;;;N;;;;; -2F954;CJK COMPATIBILITY IDEOGRAPH-2F954;Lo;0;L;2569A;;;;N;;;;; -2F955;CJK COMPATIBILITY IDEOGRAPH-2F955;Lo;0;L;256C5;;;;N;;;;; -2F956;CJK COMPATIBILITY IDEOGRAPH-2F956;Lo;0;L;798F;;;;N;;;;; -2F957;CJK COMPATIBILITY IDEOGRAPH-2F957;Lo;0;L;79EB;;;;N;;;;; -2F958;CJK COMPATIBILITY IDEOGRAPH-2F958;Lo;0;L;412F;;;;N;;;;; -2F959;CJK COMPATIBILITY IDEOGRAPH-2F959;Lo;0;L;7A40;;;;N;;;;; -2F95A;CJK COMPATIBILITY IDEOGRAPH-2F95A;Lo;0;L;7A4A;;;;N;;;;; -2F95B;CJK COMPATIBILITY IDEOGRAPH-2F95B;Lo;0;L;7A4F;;;;N;;;;; -2F95C;CJK COMPATIBILITY IDEOGRAPH-2F95C;Lo;0;L;2597C;;;;N;;;;; -2F95D;CJK COMPATIBILITY IDEOGRAPH-2F95D;Lo;0;L;25AA7;;;;N;;;;; -2F95E;CJK COMPATIBILITY IDEOGRAPH-2F95E;Lo;0;L;25AA7;;;;N;;;;; -2F95F;CJK COMPATIBILITY IDEOGRAPH-2F95F;Lo;0;L;7AEE;;;;N;;;;; -2F960;CJK COMPATIBILITY IDEOGRAPH-2F960;Lo;0;L;4202;;;;N;;;;; -2F961;CJK COMPATIBILITY IDEOGRAPH-2F961;Lo;0;L;25BAB;;;;N;;;;; -2F962;CJK COMPATIBILITY IDEOGRAPH-2F962;Lo;0;L;7BC6;;;;N;;;;; -2F963;CJK COMPATIBILITY IDEOGRAPH-2F963;Lo;0;L;7BC9;;;;N;;;;; -2F964;CJK COMPATIBILITY IDEOGRAPH-2F964;Lo;0;L;4227;;;;N;;;;; -2F965;CJK COMPATIBILITY IDEOGRAPH-2F965;Lo;0;L;25C80;;;;N;;;;; -2F966;CJK COMPATIBILITY IDEOGRAPH-2F966;Lo;0;L;7CD2;;;;N;;;;; -2F967;CJK COMPATIBILITY IDEOGRAPH-2F967;Lo;0;L;42A0;;;;N;;;;; -2F968;CJK COMPATIBILITY IDEOGRAPH-2F968;Lo;0;L;7CE8;;;;N;;;;; -2F969;CJK COMPATIBILITY IDEOGRAPH-2F969;Lo;0;L;7CE3;;;;N;;;;; -2F96A;CJK COMPATIBILITY IDEOGRAPH-2F96A;Lo;0;L;7D00;;;;N;;;;; -2F96B;CJK COMPATIBILITY IDEOGRAPH-2F96B;Lo;0;L;25F86;;;;N;;;;; -2F96C;CJK COMPATIBILITY IDEOGRAPH-2F96C;Lo;0;L;7D63;;;;N;;;;; -2F96D;CJK COMPATIBILITY IDEOGRAPH-2F96D;Lo;0;L;4301;;;;N;;;;; -2F96E;CJK COMPATIBILITY IDEOGRAPH-2F96E;Lo;0;L;7DC7;;;;N;;;;; -2F96F;CJK COMPATIBILITY IDEOGRAPH-2F96F;Lo;0;L;7E02;;;;N;;;;; -2F970;CJK COMPATIBILITY IDEOGRAPH-2F970;Lo;0;L;7E45;;;;N;;;;; -2F971;CJK COMPATIBILITY IDEOGRAPH-2F971;Lo;0;L;4334;;;;N;;;;; -2F972;CJK COMPATIBILITY IDEOGRAPH-2F972;Lo;0;L;26228;;;;N;;;;; -2F973;CJK COMPATIBILITY IDEOGRAPH-2F973;Lo;0;L;26247;;;;N;;;;; -2F974;CJK COMPATIBILITY IDEOGRAPH-2F974;Lo;0;L;4359;;;;N;;;;; -2F975;CJK COMPATIBILITY IDEOGRAPH-2F975;Lo;0;L;262D9;;;;N;;;;; -2F976;CJK COMPATIBILITY IDEOGRAPH-2F976;Lo;0;L;7F7A;;;;N;;;;; -2F977;CJK COMPATIBILITY IDEOGRAPH-2F977;Lo;0;L;2633E;;;;N;;;;; -2F978;CJK COMPATIBILITY IDEOGRAPH-2F978;Lo;0;L;7F95;;;;N;;;;; -2F979;CJK COMPATIBILITY IDEOGRAPH-2F979;Lo;0;L;7FFA;;;;N;;;;; -2F97A;CJK COMPATIBILITY IDEOGRAPH-2F97A;Lo;0;L;8005;;;;N;;;;; -2F97B;CJK COMPATIBILITY IDEOGRAPH-2F97B;Lo;0;L;264DA;;;;N;;;;; -2F97C;CJK COMPATIBILITY IDEOGRAPH-2F97C;Lo;0;L;26523;;;;N;;;;; -2F97D;CJK COMPATIBILITY IDEOGRAPH-2F97D;Lo;0;L;8060;;;;N;;;;; -2F97E;CJK COMPATIBILITY IDEOGRAPH-2F97E;Lo;0;L;265A8;;;;N;;;;; -2F97F;CJK COMPATIBILITY IDEOGRAPH-2F97F;Lo;0;L;8070;;;;N;;;;; -2F980;CJK COMPATIBILITY IDEOGRAPH-2F980;Lo;0;L;2335F;;;;N;;;;; -2F981;CJK COMPATIBILITY IDEOGRAPH-2F981;Lo;0;L;43D5;;;;N;;;;; -2F982;CJK COMPATIBILITY IDEOGRAPH-2F982;Lo;0;L;80B2;;;;N;;;;; -2F983;CJK COMPATIBILITY IDEOGRAPH-2F983;Lo;0;L;8103;;;;N;;;;; -2F984;CJK COMPATIBILITY IDEOGRAPH-2F984;Lo;0;L;440B;;;;N;;;;; -2F985;CJK COMPATIBILITY IDEOGRAPH-2F985;Lo;0;L;813E;;;;N;;;;; -2F986;CJK COMPATIBILITY IDEOGRAPH-2F986;Lo;0;L;5AB5;;;;N;;;;; -2F987;CJK COMPATIBILITY IDEOGRAPH-2F987;Lo;0;L;267A7;;;;N;;;;; -2F988;CJK COMPATIBILITY IDEOGRAPH-2F988;Lo;0;L;267B5;;;;N;;;;; -2F989;CJK COMPATIBILITY IDEOGRAPH-2F989;Lo;0;L;23393;;;;N;;;;; -2F98A;CJK COMPATIBILITY IDEOGRAPH-2F98A;Lo;0;L;2339C;;;;N;;;;; -2F98B;CJK COMPATIBILITY IDEOGRAPH-2F98B;Lo;0;L;8201;;;;N;;;;; -2F98C;CJK COMPATIBILITY IDEOGRAPH-2F98C;Lo;0;L;8204;;;;N;;;;; -2F98D;CJK COMPATIBILITY IDEOGRAPH-2F98D;Lo;0;L;8F9E;;;;N;;;;; -2F98E;CJK COMPATIBILITY IDEOGRAPH-2F98E;Lo;0;L;446B;;;;N;;;;; -2F98F;CJK COMPATIBILITY IDEOGRAPH-2F98F;Lo;0;L;8291;;;;N;;;;; -2F990;CJK COMPATIBILITY IDEOGRAPH-2F990;Lo;0;L;828B;;;;N;;;;; -2F991;CJK COMPATIBILITY IDEOGRAPH-2F991;Lo;0;L;829D;;;;N;;;;; -2F992;CJK COMPATIBILITY IDEOGRAPH-2F992;Lo;0;L;52B3;;;;N;;;;; -2F993;CJK COMPATIBILITY IDEOGRAPH-2F993;Lo;0;L;82B1;;;;N;;;;; -2F994;CJK COMPATIBILITY IDEOGRAPH-2F994;Lo;0;L;82B3;;;;N;;;;; -2F995;CJK COMPATIBILITY IDEOGRAPH-2F995;Lo;0;L;82BD;;;;N;;;;; -2F996;CJK COMPATIBILITY IDEOGRAPH-2F996;Lo;0;L;82E6;;;;N;;;;; -2F997;CJK COMPATIBILITY IDEOGRAPH-2F997;Lo;0;L;26B3C;;;;N;;;;; -2F998;CJK COMPATIBILITY IDEOGRAPH-2F998;Lo;0;L;82E5;;;;N;;;;; -2F999;CJK COMPATIBILITY IDEOGRAPH-2F999;Lo;0;L;831D;;;;N;;;;; -2F99A;CJK COMPATIBILITY IDEOGRAPH-2F99A;Lo;0;L;8363;;;;N;;;;; -2F99B;CJK COMPATIBILITY IDEOGRAPH-2F99B;Lo;0;L;83AD;;;;N;;;;; -2F99C;CJK COMPATIBILITY IDEOGRAPH-2F99C;Lo;0;L;8323;;;;N;;;;; -2F99D;CJK COMPATIBILITY IDEOGRAPH-2F99D;Lo;0;L;83BD;;;;N;;;;; -2F99E;CJK COMPATIBILITY IDEOGRAPH-2F99E;Lo;0;L;83E7;;;;N;;;;; -2F99F;CJK COMPATIBILITY IDEOGRAPH-2F99F;Lo;0;L;8457;;;;N;;;;; -2F9A0;CJK COMPATIBILITY IDEOGRAPH-2F9A0;Lo;0;L;8353;;;;N;;;;; -2F9A1;CJK COMPATIBILITY IDEOGRAPH-2F9A1;Lo;0;L;83CA;;;;N;;;;; -2F9A2;CJK COMPATIBILITY IDEOGRAPH-2F9A2;Lo;0;L;83CC;;;;N;;;;; -2F9A3;CJK COMPATIBILITY IDEOGRAPH-2F9A3;Lo;0;L;83DC;;;;N;;;;; -2F9A4;CJK COMPATIBILITY IDEOGRAPH-2F9A4;Lo;0;L;26C36;;;;N;;;;; -2F9A5;CJK COMPATIBILITY IDEOGRAPH-2F9A5;Lo;0;L;26D6B;;;;N;;;;; -2F9A6;CJK COMPATIBILITY IDEOGRAPH-2F9A6;Lo;0;L;26CD5;;;;N;;;;; -2F9A7;CJK COMPATIBILITY IDEOGRAPH-2F9A7;Lo;0;L;452B;;;;N;;;;; -2F9A8;CJK COMPATIBILITY IDEOGRAPH-2F9A8;Lo;0;L;84F1;;;;N;;;;; -2F9A9;CJK COMPATIBILITY IDEOGRAPH-2F9A9;Lo;0;L;84F3;;;;N;;;;; -2F9AA;CJK COMPATIBILITY IDEOGRAPH-2F9AA;Lo;0;L;8516;;;;N;;;;; -2F9AB;CJK COMPATIBILITY IDEOGRAPH-2F9AB;Lo;0;L;273CA;;;;N;;;;; -2F9AC;CJK COMPATIBILITY IDEOGRAPH-2F9AC;Lo;0;L;8564;;;;N;;;;; -2F9AD;CJK COMPATIBILITY IDEOGRAPH-2F9AD;Lo;0;L;26F2C;;;;N;;;;; -2F9AE;CJK COMPATIBILITY IDEOGRAPH-2F9AE;Lo;0;L;455D;;;;N;;;;; -2F9AF;CJK COMPATIBILITY IDEOGRAPH-2F9AF;Lo;0;L;4561;;;;N;;;;; -2F9B0;CJK COMPATIBILITY IDEOGRAPH-2F9B0;Lo;0;L;26FB1;;;;N;;;;; -2F9B1;CJK COMPATIBILITY IDEOGRAPH-2F9B1;Lo;0;L;270D2;;;;N;;;;; -2F9B2;CJK COMPATIBILITY IDEOGRAPH-2F9B2;Lo;0;L;456B;;;;N;;;;; -2F9B3;CJK COMPATIBILITY IDEOGRAPH-2F9B3;Lo;0;L;8650;;;;N;;;;; -2F9B4;CJK COMPATIBILITY IDEOGRAPH-2F9B4;Lo;0;L;865C;;;;N;;;;; -2F9B5;CJK COMPATIBILITY IDEOGRAPH-2F9B5;Lo;0;L;8667;;;;N;;;;; -2F9B6;CJK COMPATIBILITY IDEOGRAPH-2F9B6;Lo;0;L;8669;;;;N;;;;; -2F9B7;CJK COMPATIBILITY IDEOGRAPH-2F9B7;Lo;0;L;86A9;;;;N;;;;; -2F9B8;CJK COMPATIBILITY IDEOGRAPH-2F9B8;Lo;0;L;8688;;;;N;;;;; -2F9B9;CJK COMPATIBILITY IDEOGRAPH-2F9B9;Lo;0;L;870E;;;;N;;;;; -2F9BA;CJK COMPATIBILITY IDEOGRAPH-2F9BA;Lo;0;L;86E2;;;;N;;;;; -2F9BB;CJK COMPATIBILITY IDEOGRAPH-2F9BB;Lo;0;L;8779;;;;N;;;;; -2F9BC;CJK COMPATIBILITY IDEOGRAPH-2F9BC;Lo;0;L;8728;;;;N;;;;; -2F9BD;CJK COMPATIBILITY IDEOGRAPH-2F9BD;Lo;0;L;876B;;;;N;;;;; -2F9BE;CJK COMPATIBILITY IDEOGRAPH-2F9BE;Lo;0;L;8786;;;;N;;;;; -2F9BF;CJK COMPATIBILITY IDEOGRAPH-2F9BF;Lo;0;L;45D7;;;;N;;;;; -2F9C0;CJK COMPATIBILITY IDEOGRAPH-2F9C0;Lo;0;L;87E1;;;;N;;;;; -2F9C1;CJK COMPATIBILITY IDEOGRAPH-2F9C1;Lo;0;L;8801;;;;N;;;;; -2F9C2;CJK COMPATIBILITY IDEOGRAPH-2F9C2;Lo;0;L;45F9;;;;N;;;;; -2F9C3;CJK COMPATIBILITY IDEOGRAPH-2F9C3;Lo;0;L;8860;;;;N;;;;; -2F9C4;CJK COMPATIBILITY IDEOGRAPH-2F9C4;Lo;0;L;8863;;;;N;;;;; -2F9C5;CJK COMPATIBILITY IDEOGRAPH-2F9C5;Lo;0;L;27667;;;;N;;;;; -2F9C6;CJK COMPATIBILITY IDEOGRAPH-2F9C6;Lo;0;L;88D7;;;;N;;;;; -2F9C7;CJK COMPATIBILITY IDEOGRAPH-2F9C7;Lo;0;L;88DE;;;;N;;;;; -2F9C8;CJK COMPATIBILITY IDEOGRAPH-2F9C8;Lo;0;L;4635;;;;N;;;;; -2F9C9;CJK COMPATIBILITY IDEOGRAPH-2F9C9;Lo;0;L;88FA;;;;N;;;;; -2F9CA;CJK COMPATIBILITY IDEOGRAPH-2F9CA;Lo;0;L;34BB;;;;N;;;;; -2F9CB;CJK COMPATIBILITY IDEOGRAPH-2F9CB;Lo;0;L;278AE;;;;N;;;;; -2F9CC;CJK COMPATIBILITY IDEOGRAPH-2F9CC;Lo;0;L;27966;;;;N;;;;; -2F9CD;CJK COMPATIBILITY IDEOGRAPH-2F9CD;Lo;0;L;46BE;;;;N;;;;; -2F9CE;CJK COMPATIBILITY IDEOGRAPH-2F9CE;Lo;0;L;46C7;;;;N;;;;; -2F9CF;CJK COMPATIBILITY IDEOGRAPH-2F9CF;Lo;0;L;8AA0;;;;N;;;;; -2F9D0;CJK COMPATIBILITY IDEOGRAPH-2F9D0;Lo;0;L;8AED;;;;N;;;;; -2F9D1;CJK COMPATIBILITY IDEOGRAPH-2F9D1;Lo;0;L;8B8A;;;;N;;;;; -2F9D2;CJK COMPATIBILITY IDEOGRAPH-2F9D2;Lo;0;L;8C55;;;;N;;;;; -2F9D3;CJK COMPATIBILITY IDEOGRAPH-2F9D3;Lo;0;L;27CA8;;;;N;;;;; -2F9D4;CJK COMPATIBILITY IDEOGRAPH-2F9D4;Lo;0;L;8CAB;;;;N;;;;; -2F9D5;CJK COMPATIBILITY IDEOGRAPH-2F9D5;Lo;0;L;8CC1;;;;N;;;;; -2F9D6;CJK COMPATIBILITY IDEOGRAPH-2F9D6;Lo;0;L;8D1B;;;;N;;;;; -2F9D7;CJK COMPATIBILITY IDEOGRAPH-2F9D7;Lo;0;L;8D77;;;;N;;;;; -2F9D8;CJK COMPATIBILITY IDEOGRAPH-2F9D8;Lo;0;L;27F2F;;;;N;;;;; -2F9D9;CJK COMPATIBILITY IDEOGRAPH-2F9D9;Lo;0;L;20804;;;;N;;;;; -2F9DA;CJK COMPATIBILITY IDEOGRAPH-2F9DA;Lo;0;L;8DCB;;;;N;;;;; -2F9DB;CJK COMPATIBILITY IDEOGRAPH-2F9DB;Lo;0;L;8DBC;;;;N;;;;; -2F9DC;CJK COMPATIBILITY IDEOGRAPH-2F9DC;Lo;0;L;8DF0;;;;N;;;;; -2F9DD;CJK COMPATIBILITY IDEOGRAPH-2F9DD;Lo;0;L;208DE;;;;N;;;;; -2F9DE;CJK COMPATIBILITY IDEOGRAPH-2F9DE;Lo;0;L;8ED4;;;;N;;;;; -2F9DF;CJK COMPATIBILITY IDEOGRAPH-2F9DF;Lo;0;L;8F38;;;;N;;;;; -2F9E0;CJK COMPATIBILITY IDEOGRAPH-2F9E0;Lo;0;L;285D2;;;;N;;;;; -2F9E1;CJK COMPATIBILITY IDEOGRAPH-2F9E1;Lo;0;L;285ED;;;;N;;;;; -2F9E2;CJK COMPATIBILITY IDEOGRAPH-2F9E2;Lo;0;L;9094;;;;N;;;;; -2F9E3;CJK COMPATIBILITY IDEOGRAPH-2F9E3;Lo;0;L;90F1;;;;N;;;;; -2F9E4;CJK COMPATIBILITY IDEOGRAPH-2F9E4;Lo;0;L;9111;;;;N;;;;; -2F9E5;CJK COMPATIBILITY IDEOGRAPH-2F9E5;Lo;0;L;2872E;;;;N;;;;; -2F9E6;CJK COMPATIBILITY IDEOGRAPH-2F9E6;Lo;0;L;911B;;;;N;;;;; -2F9E7;CJK COMPATIBILITY IDEOGRAPH-2F9E7;Lo;0;L;9238;;;;N;;;;; -2F9E8;CJK COMPATIBILITY IDEOGRAPH-2F9E8;Lo;0;L;92D7;;;;N;;;;; -2F9E9;CJK COMPATIBILITY IDEOGRAPH-2F9E9;Lo;0;L;92D8;;;;N;;;;; -2F9EA;CJK COMPATIBILITY IDEOGRAPH-2F9EA;Lo;0;L;927C;;;;N;;;;; -2F9EB;CJK COMPATIBILITY IDEOGRAPH-2F9EB;Lo;0;L;93F9;;;;N;;;;; -2F9EC;CJK COMPATIBILITY IDEOGRAPH-2F9EC;Lo;0;L;9415;;;;N;;;;; -2F9ED;CJK COMPATIBILITY IDEOGRAPH-2F9ED;Lo;0;L;28BFA;;;;N;;;;; -2F9EE;CJK COMPATIBILITY IDEOGRAPH-2F9EE;Lo;0;L;958B;;;;N;;;;; -2F9EF;CJK COMPATIBILITY IDEOGRAPH-2F9EF;Lo;0;L;4995;;;;N;;;;; -2F9F0;CJK COMPATIBILITY IDEOGRAPH-2F9F0;Lo;0;L;95B7;;;;N;;;;; -2F9F1;CJK COMPATIBILITY IDEOGRAPH-2F9F1;Lo;0;L;28D77;;;;N;;;;; -2F9F2;CJK COMPATIBILITY IDEOGRAPH-2F9F2;Lo;0;L;49E6;;;;N;;;;; -2F9F3;CJK COMPATIBILITY IDEOGRAPH-2F9F3;Lo;0;L;96C3;;;;N;;;;; -2F9F4;CJK COMPATIBILITY IDEOGRAPH-2F9F4;Lo;0;L;5DB2;;;;N;;;;; -2F9F5;CJK COMPATIBILITY IDEOGRAPH-2F9F5;Lo;0;L;9723;;;;N;;;;; -2F9F6;CJK COMPATIBILITY IDEOGRAPH-2F9F6;Lo;0;L;29145;;;;N;;;;; -2F9F7;CJK COMPATIBILITY IDEOGRAPH-2F9F7;Lo;0;L;2921A;;;;N;;;;; -2F9F8;CJK COMPATIBILITY IDEOGRAPH-2F9F8;Lo;0;L;4A6E;;;;N;;;;; -2F9F9;CJK COMPATIBILITY IDEOGRAPH-2F9F9;Lo;0;L;4A76;;;;N;;;;; -2F9FA;CJK COMPATIBILITY IDEOGRAPH-2F9FA;Lo;0;L;97E0;;;;N;;;;; -2F9FB;CJK COMPATIBILITY IDEOGRAPH-2F9FB;Lo;0;L;2940A;;;;N;;;;; -2F9FC;CJK COMPATIBILITY IDEOGRAPH-2F9FC;Lo;0;L;4AB2;;;;N;;;;; -2F9FD;CJK COMPATIBILITY IDEOGRAPH-2F9FD;Lo;0;L;29496;;;;N;;;;; -2F9FE;CJK COMPATIBILITY IDEOGRAPH-2F9FE;Lo;0;L;980B;;;;N;;;;; -2F9FF;CJK COMPATIBILITY IDEOGRAPH-2F9FF;Lo;0;L;980B;;;;N;;;;; -2FA00;CJK COMPATIBILITY IDEOGRAPH-2FA00;Lo;0;L;9829;;;;N;;;;; -2FA01;CJK COMPATIBILITY IDEOGRAPH-2FA01;Lo;0;L;295B6;;;;N;;;;; -2FA02;CJK COMPATIBILITY IDEOGRAPH-2FA02;Lo;0;L;98E2;;;;N;;;;; -2FA03;CJK COMPATIBILITY IDEOGRAPH-2FA03;Lo;0;L;4B33;;;;N;;;;; -2FA04;CJK COMPATIBILITY IDEOGRAPH-2FA04;Lo;0;L;9929;;;;N;;;;; -2FA05;CJK COMPATIBILITY IDEOGRAPH-2FA05;Lo;0;L;99A7;;;;N;;;;; -2FA06;CJK COMPATIBILITY IDEOGRAPH-2FA06;Lo;0;L;99C2;;;;N;;;;; -2FA07;CJK COMPATIBILITY IDEOGRAPH-2FA07;Lo;0;L;99FE;;;;N;;;;; -2FA08;CJK COMPATIBILITY IDEOGRAPH-2FA08;Lo;0;L;4BCE;;;;N;;;;; -2FA09;CJK COMPATIBILITY IDEOGRAPH-2FA09;Lo;0;L;29B30;;;;N;;;;; -2FA0A;CJK COMPATIBILITY IDEOGRAPH-2FA0A;Lo;0;L;9B12;;;;N;;;;; -2FA0B;CJK COMPATIBILITY IDEOGRAPH-2FA0B;Lo;0;L;9C40;;;;N;;;;; -2FA0C;CJK COMPATIBILITY IDEOGRAPH-2FA0C;Lo;0;L;9CFD;;;;N;;;;; -2FA0D;CJK COMPATIBILITY IDEOGRAPH-2FA0D;Lo;0;L;4CCE;;;;N;;;;; -2FA0E;CJK COMPATIBILITY IDEOGRAPH-2FA0E;Lo;0;L;4CED;;;;N;;;;; -2FA0F;CJK COMPATIBILITY IDEOGRAPH-2FA0F;Lo;0;L;9D67;;;;N;;;;; -2FA10;CJK COMPATIBILITY IDEOGRAPH-2FA10;Lo;0;L;2A0CE;;;;N;;;;; -2FA11;CJK COMPATIBILITY IDEOGRAPH-2FA11;Lo;0;L;4CF8;;;;N;;;;; -2FA12;CJK COMPATIBILITY IDEOGRAPH-2FA12;Lo;0;L;2A105;;;;N;;;;; -2FA13;CJK COMPATIBILITY IDEOGRAPH-2FA13;Lo;0;L;2A20E;;;;N;;;;; -2FA14;CJK COMPATIBILITY IDEOGRAPH-2FA14;Lo;0;L;2A291;;;;N;;;;; -2FA15;CJK COMPATIBILITY IDEOGRAPH-2FA15;Lo;0;L;9EBB;;;;N;;;;; -2FA16;CJK COMPATIBILITY IDEOGRAPH-2FA16;Lo;0;L;4D56;;;;N;;;;; -2FA17;CJK COMPATIBILITY IDEOGRAPH-2FA17;Lo;0;L;9EF9;;;;N;;;;; -2FA18;CJK COMPATIBILITY IDEOGRAPH-2FA18;Lo;0;L;9EFE;;;;N;;;;; -2FA19;CJK COMPATIBILITY IDEOGRAPH-2FA19;Lo;0;L;9F05;;;;N;;;;; -2FA1A;CJK COMPATIBILITY IDEOGRAPH-2FA1A;Lo;0;L;9F0F;;;;N;;;;; -2FA1B;CJK COMPATIBILITY IDEOGRAPH-2FA1B;Lo;0;L;9F16;;;;N;;;;; -2FA1C;CJK COMPATIBILITY IDEOGRAPH-2FA1C;Lo;0;L;9F3B;;;;N;;;;; -2FA1D;CJK COMPATIBILITY IDEOGRAPH-2FA1D;Lo;0;L;2A600;;;;N;;;;; -30000;<CJK Ideograph Extension G, First>;Lo;0;L;;;;;N;;;;; -3134A;<CJK Ideograph Extension G, Last>;Lo;0;L;;;;;N;;;;; -31350;<CJK Ideograph Extension H, First>;Lo;0;L;;;;;N;;;;; -323AF;<CJK Ideograph Extension H, Last>;Lo;0;L;;;;;N;;;;; -E0001;LANGUAGE TAG;Cf;0;BN;;;;;N;;;;; -E0020;TAG SPACE;Cf;0;BN;;;;;N;;;;; -E0021;TAG EXCLAMATION MARK;Cf;0;BN;;;;;N;;;;; -E0022;TAG QUOTATION MARK;Cf;0;BN;;;;;N;;;;; -E0023;TAG NUMBER SIGN;Cf;0;BN;;;;;N;;;;; -E0024;TAG DOLLAR SIGN;Cf;0;BN;;;;;N;;;;; -E0025;TAG PERCENT SIGN;Cf;0;BN;;;;;N;;;;; -E0026;TAG AMPERSAND;Cf;0;BN;;;;;N;;;;; -E0027;TAG APOSTROPHE;Cf;0;BN;;;;;N;;;;; -E0028;TAG LEFT PARENTHESIS;Cf;0;BN;;;;;N;;;;; -E0029;TAG RIGHT PARENTHESIS;Cf;0;BN;;;;;N;;;;; -E002A;TAG ASTERISK;Cf;0;BN;;;;;N;;;;; -E002B;TAG PLUS SIGN;Cf;0;BN;;;;;N;;;;; -E002C;TAG COMMA;Cf;0;BN;;;;;N;;;;; -E002D;TAG HYPHEN-MINUS;Cf;0;BN;;;;;N;;;;; -E002E;TAG FULL STOP;Cf;0;BN;;;;;N;;;;; -E002F;TAG SOLIDUS;Cf;0;BN;;;;;N;;;;; -E0030;TAG DIGIT ZERO;Cf;0;BN;;;;;N;;;;; -E0031;TAG DIGIT ONE;Cf;0;BN;;;;;N;;;;; -E0032;TAG DIGIT TWO;Cf;0;BN;;;;;N;;;;; -E0033;TAG DIGIT THREE;Cf;0;BN;;;;;N;;;;; -E0034;TAG DIGIT FOUR;Cf;0;BN;;;;;N;;;;; -E0035;TAG DIGIT FIVE;Cf;0;BN;;;;;N;;;;; -E0036;TAG DIGIT SIX;Cf;0;BN;;;;;N;;;;; -E0037;TAG DIGIT SEVEN;Cf;0;BN;;;;;N;;;;; -E0038;TAG DIGIT EIGHT;Cf;0;BN;;;;;N;;;;; -E0039;TAG DIGIT NINE;Cf;0;BN;;;;;N;;;;; -E003A;TAG COLON;Cf;0;BN;;;;;N;;;;; -E003B;TAG SEMICOLON;Cf;0;BN;;;;;N;;;;; -E003C;TAG LESS-THAN SIGN;Cf;0;BN;;;;;N;;;;; -E003D;TAG EQUALS SIGN;Cf;0;BN;;;;;N;;;;; -E003E;TAG GREATER-THAN SIGN;Cf;0;BN;;;;;N;;;;; -E003F;TAG QUESTION MARK;Cf;0;BN;;;;;N;;;;; -E0040;TAG COMMERCIAL AT;Cf;0;BN;;;;;N;;;;; -E0041;TAG LATIN CAPITAL LETTER A;Cf;0;BN;;;;;N;;;;; -E0042;TAG LATIN CAPITAL LETTER B;Cf;0;BN;;;;;N;;;;; -E0043;TAG LATIN CAPITAL LETTER C;Cf;0;BN;;;;;N;;;;; -E0044;TAG LATIN CAPITAL LETTER D;Cf;0;BN;;;;;N;;;;; -E0045;TAG LATIN CAPITAL LETTER E;Cf;0;BN;;;;;N;;;;; -E0046;TAG LATIN CAPITAL LETTER F;Cf;0;BN;;;;;N;;;;; -E0047;TAG LATIN CAPITAL LETTER G;Cf;0;BN;;;;;N;;;;; -E0048;TAG LATIN CAPITAL LETTER H;Cf;0;BN;;;;;N;;;;; -E0049;TAG LATIN CAPITAL LETTER I;Cf;0;BN;;;;;N;;;;; -E004A;TAG LATIN CAPITAL LETTER J;Cf;0;BN;;;;;N;;;;; -E004B;TAG LATIN CAPITAL LETTER K;Cf;0;BN;;;;;N;;;;; -E004C;TAG LATIN CAPITAL LETTER L;Cf;0;BN;;;;;N;;;;; -E004D;TAG LATIN CAPITAL LETTER M;Cf;0;BN;;;;;N;;;;; -E004E;TAG LATIN CAPITAL LETTER N;Cf;0;BN;;;;;N;;;;; -E004F;TAG LATIN CAPITAL LETTER O;Cf;0;BN;;;;;N;;;;; -E0050;TAG LATIN CAPITAL LETTER P;Cf;0;BN;;;;;N;;;;; -E0051;TAG LATIN CAPITAL LETTER Q;Cf;0;BN;;;;;N;;;;; -E0052;TAG LATIN CAPITAL LETTER R;Cf;0;BN;;;;;N;;;;; -E0053;TAG LATIN CAPITAL LETTER S;Cf;0;BN;;;;;N;;;;; -E0054;TAG LATIN CAPITAL LETTER T;Cf;0;BN;;;;;N;;;;; -E0055;TAG LATIN CAPITAL LETTER U;Cf;0;BN;;;;;N;;;;; -E0056;TAG LATIN CAPITAL LETTER V;Cf;0;BN;;;;;N;;;;; -E0057;TAG LATIN CAPITAL LETTER W;Cf;0;BN;;;;;N;;;;; -E0058;TAG LATIN CAPITAL LETTER X;Cf;0;BN;;;;;N;;;;; -E0059;TAG LATIN CAPITAL LETTER Y;Cf;0;BN;;;;;N;;;;; -E005A;TAG LATIN CAPITAL LETTER Z;Cf;0;BN;;;;;N;;;;; -E005B;TAG LEFT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;; -E005C;TAG REVERSE SOLIDUS;Cf;0;BN;;;;;N;;;;; -E005D;TAG RIGHT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;; -E005E;TAG CIRCUMFLEX ACCENT;Cf;0;BN;;;;;N;;;;; -E005F;TAG LOW LINE;Cf;0;BN;;;;;N;;;;; -E0060;TAG GRAVE ACCENT;Cf;0;BN;;;;;N;;;;; -E0061;TAG LATIN SMALL LETTER A;Cf;0;BN;;;;;N;;;;; -E0062;TAG LATIN SMALL LETTER B;Cf;0;BN;;;;;N;;;;; -E0063;TAG LATIN SMALL LETTER C;Cf;0;BN;;;;;N;;;;; -E0064;TAG LATIN SMALL LETTER D;Cf;0;BN;;;;;N;;;;; -E0065;TAG LATIN SMALL LETTER E;Cf;0;BN;;;;;N;;;;; -E0066;TAG LATIN SMALL LETTER F;Cf;0;BN;;;;;N;;;;; -E0067;TAG LATIN SMALL LETTER G;Cf;0;BN;;;;;N;;;;; -E0068;TAG LATIN SMALL LETTER H;Cf;0;BN;;;;;N;;;;; -E0069;TAG LATIN SMALL LETTER I;Cf;0;BN;;;;;N;;;;; -E006A;TAG LATIN SMALL LETTER J;Cf;0;BN;;;;;N;;;;; -E006B;TAG LATIN SMALL LETTER K;Cf;0;BN;;;;;N;;;;; -E006C;TAG LATIN SMALL LETTER L;Cf;0;BN;;;;;N;;;;; -E006D;TAG LATIN SMALL LETTER M;Cf;0;BN;;;;;N;;;;; -E006E;TAG LATIN SMALL LETTER N;Cf;0;BN;;;;;N;;;;; -E006F;TAG LATIN SMALL LETTER O;Cf;0;BN;;;;;N;;;;; -E0070;TAG LATIN SMALL LETTER P;Cf;0;BN;;;;;N;;;;; -E0071;TAG LATIN SMALL LETTER Q;Cf;0;BN;;;;;N;;;;; -E0072;TAG LATIN SMALL LETTER R;Cf;0;BN;;;;;N;;;;; -E0073;TAG LATIN SMALL LETTER S;Cf;0;BN;;;;;N;;;;; -E0074;TAG LATIN SMALL LETTER T;Cf;0;BN;;;;;N;;;;; -E0075;TAG LATIN SMALL LETTER U;Cf;0;BN;;;;;N;;;;; -E0076;TAG LATIN SMALL LETTER V;Cf;0;BN;;;;;N;;;;; -E0077;TAG LATIN SMALL LETTER W;Cf;0;BN;;;;;N;;;;; -E0078;TAG LATIN SMALL LETTER X;Cf;0;BN;;;;;N;;;;; -E0079;TAG LATIN SMALL LETTER Y;Cf;0;BN;;;;;N;;;;; -E007A;TAG LATIN SMALL LETTER Z;Cf;0;BN;;;;;N;;;;; -E007B;TAG LEFT CURLY BRACKET;Cf;0;BN;;;;;N;;;;; -E007C;TAG VERTICAL LINE;Cf;0;BN;;;;;N;;;;; -E007D;TAG RIGHT CURLY BRACKET;Cf;0;BN;;;;;N;;;;; -E007E;TAG TILDE;Cf;0;BN;;;;;N;;;;; -E007F;CANCEL TAG;Cf;0;BN;;;;;N;;;;; -E0100;VARIATION SELECTOR-17;Mn;0;NSM;;;;;N;;;;; -E0101;VARIATION SELECTOR-18;Mn;0;NSM;;;;;N;;;;; -E0102;VARIATION SELECTOR-19;Mn;0;NSM;;;;;N;;;;; -E0103;VARIATION SELECTOR-20;Mn;0;NSM;;;;;N;;;;; -E0104;VARIATION SELECTOR-21;Mn;0;NSM;;;;;N;;;;; -E0105;VARIATION SELECTOR-22;Mn;0;NSM;;;;;N;;;;; -E0106;VARIATION SELECTOR-23;Mn;0;NSM;;;;;N;;;;; -E0107;VARIATION SELECTOR-24;Mn;0;NSM;;;;;N;;;;; -E0108;VARIATION SELECTOR-25;Mn;0;NSM;;;;;N;;;;; -E0109;VARIATION SELECTOR-26;Mn;0;NSM;;;;;N;;;;; -E010A;VARIATION SELECTOR-27;Mn;0;NSM;;;;;N;;;;; -E010B;VARIATION SELECTOR-28;Mn;0;NSM;;;;;N;;;;; -E010C;VARIATION SELECTOR-29;Mn;0;NSM;;;;;N;;;;; -E010D;VARIATION SELECTOR-30;Mn;0;NSM;;;;;N;;;;; -E010E;VARIATION SELECTOR-31;Mn;0;NSM;;;;;N;;;;; -E010F;VARIATION SELECTOR-32;Mn;0;NSM;;;;;N;;;;; -E0110;VARIATION SELECTOR-33;Mn;0;NSM;;;;;N;;;;; -E0111;VARIATION SELECTOR-34;Mn;0;NSM;;;;;N;;;;; -E0112;VARIATION SELECTOR-35;Mn;0;NSM;;;;;N;;;;; -E0113;VARIATION SELECTOR-36;Mn;0;NSM;;;;;N;;;;; -E0114;VARIATION SELECTOR-37;Mn;0;NSM;;;;;N;;;;; -E0115;VARIATION SELECTOR-38;Mn;0;NSM;;;;;N;;;;; -E0116;VARIATION SELECTOR-39;Mn;0;NSM;;;;;N;;;;; -E0117;VARIATION SELECTOR-40;Mn;0;NSM;;;;;N;;;;; -E0118;VARIATION SELECTOR-41;Mn;0;NSM;;;;;N;;;;; -E0119;VARIATION SELECTOR-42;Mn;0;NSM;;;;;N;;;;; -E011A;VARIATION SELECTOR-43;Mn;0;NSM;;;;;N;;;;; -E011B;VARIATION SELECTOR-44;Mn;0;NSM;;;;;N;;;;; -E011C;VARIATION SELECTOR-45;Mn;0;NSM;;;;;N;;;;; -E011D;VARIATION SELECTOR-46;Mn;0;NSM;;;;;N;;;;; -E011E;VARIATION SELECTOR-47;Mn;0;NSM;;;;;N;;;;; -E011F;VARIATION SELECTOR-48;Mn;0;NSM;;;;;N;;;;; -E0120;VARIATION SELECTOR-49;Mn;0;NSM;;;;;N;;;;; -E0121;VARIATION SELECTOR-50;Mn;0;NSM;;;;;N;;;;; -E0122;VARIATION SELECTOR-51;Mn;0;NSM;;;;;N;;;;; -E0123;VARIATION SELECTOR-52;Mn;0;NSM;;;;;N;;;;; -E0124;VARIATION SELECTOR-53;Mn;0;NSM;;;;;N;;;;; -E0125;VARIATION SELECTOR-54;Mn;0;NSM;;;;;N;;;;; -E0126;VARIATION SELECTOR-55;Mn;0;NSM;;;;;N;;;;; -E0127;VARIATION SELECTOR-56;Mn;0;NSM;;;;;N;;;;; -E0128;VARIATION SELECTOR-57;Mn;0;NSM;;;;;N;;;;; -E0129;VARIATION SELECTOR-58;Mn;0;NSM;;;;;N;;;;; -E012A;VARIATION SELECTOR-59;Mn;0;NSM;;;;;N;;;;; -E012B;VARIATION SELECTOR-60;Mn;0;NSM;;;;;N;;;;; -E012C;VARIATION SELECTOR-61;Mn;0;NSM;;;;;N;;;;; -E012D;VARIATION SELECTOR-62;Mn;0;NSM;;;;;N;;;;; -E012E;VARIATION SELECTOR-63;Mn;0;NSM;;;;;N;;;;; -E012F;VARIATION SELECTOR-64;Mn;0;NSM;;;;;N;;;;; -E0130;VARIATION SELECTOR-65;Mn;0;NSM;;;;;N;;;;; -E0131;VARIATION SELECTOR-66;Mn;0;NSM;;;;;N;;;;; -E0132;VARIATION SELECTOR-67;Mn;0;NSM;;;;;N;;;;; -E0133;VARIATION SELECTOR-68;Mn;0;NSM;;;;;N;;;;; -E0134;VARIATION SELECTOR-69;Mn;0;NSM;;;;;N;;;;; -E0135;VARIATION SELECTOR-70;Mn;0;NSM;;;;;N;;;;; -E0136;VARIATION SELECTOR-71;Mn;0;NSM;;;;;N;;;;; -E0137;VARIATION SELECTOR-72;Mn;0;NSM;;;;;N;;;;; -E0138;VARIATION SELECTOR-73;Mn;0;NSM;;;;;N;;;;; -E0139;VARIATION SELECTOR-74;Mn;0;NSM;;;;;N;;;;; -E013A;VARIATION SELECTOR-75;Mn;0;NSM;;;;;N;;;;; -E013B;VARIATION SELECTOR-76;Mn;0;NSM;;;;;N;;;;; -E013C;VARIATION SELECTOR-77;Mn;0;NSM;;;;;N;;;;; -E013D;VARIATION SELECTOR-78;Mn;0;NSM;;;;;N;;;;; -E013E;VARIATION SELECTOR-79;Mn;0;NSM;;;;;N;;;;; -E013F;VARIATION SELECTOR-80;Mn;0;NSM;;;;;N;;;;; -E0140;VARIATION SELECTOR-81;Mn;0;NSM;;;;;N;;;;; -E0141;VARIATION SELECTOR-82;Mn;0;NSM;;;;;N;;;;; -E0142;VARIATION SELECTOR-83;Mn;0;NSM;;;;;N;;;;; -E0143;VARIATION SELECTOR-84;Mn;0;NSM;;;;;N;;;;; -E0144;VARIATION SELECTOR-85;Mn;0;NSM;;;;;N;;;;; -E0145;VARIATION SELECTOR-86;Mn;0;NSM;;;;;N;;;;; -E0146;VARIATION SELECTOR-87;Mn;0;NSM;;;;;N;;;;; -E0147;VARIATION SELECTOR-88;Mn;0;NSM;;;;;N;;;;; -E0148;VARIATION SELECTOR-89;Mn;0;NSM;;;;;N;;;;; -E0149;VARIATION SELECTOR-90;Mn;0;NSM;;;;;N;;;;; -E014A;VARIATION SELECTOR-91;Mn;0;NSM;;;;;N;;;;; -E014B;VARIATION SELECTOR-92;Mn;0;NSM;;;;;N;;;;; -E014C;VARIATION SELECTOR-93;Mn;0;NSM;;;;;N;;;;; -E014D;VARIATION SELECTOR-94;Mn;0;NSM;;;;;N;;;;; -E014E;VARIATION SELECTOR-95;Mn;0;NSM;;;;;N;;;;; -E014F;VARIATION SELECTOR-96;Mn;0;NSM;;;;;N;;;;; -E0150;VARIATION SELECTOR-97;Mn;0;NSM;;;;;N;;;;; -E0151;VARIATION SELECTOR-98;Mn;0;NSM;;;;;N;;;;; -E0152;VARIATION SELECTOR-99;Mn;0;NSM;;;;;N;;;;; -E0153;VARIATION SELECTOR-100;Mn;0;NSM;;;;;N;;;;; -E0154;VARIATION SELECTOR-101;Mn;0;NSM;;;;;N;;;;; -E0155;VARIATION SELECTOR-102;Mn;0;NSM;;;;;N;;;;; -E0156;VARIATION SELECTOR-103;Mn;0;NSM;;;;;N;;;;; -E0157;VARIATION SELECTOR-104;Mn;0;NSM;;;;;N;;;;; -E0158;VARIATION SELECTOR-105;Mn;0;NSM;;;;;N;;;;; -E0159;VARIATION SELECTOR-106;Mn;0;NSM;;;;;N;;;;; -E015A;VARIATION SELECTOR-107;Mn;0;NSM;;;;;N;;;;; -E015B;VARIATION SELECTOR-108;Mn;0;NSM;;;;;N;;;;; -E015C;VARIATION SELECTOR-109;Mn;0;NSM;;;;;N;;;;; -E015D;VARIATION SELECTOR-110;Mn;0;NSM;;;;;N;;;;; -E015E;VARIATION SELECTOR-111;Mn;0;NSM;;;;;N;;;;; -E015F;VARIATION SELECTOR-112;Mn;0;NSM;;;;;N;;;;; -E0160;VARIATION SELECTOR-113;Mn;0;NSM;;;;;N;;;;; -E0161;VARIATION SELECTOR-114;Mn;0;NSM;;;;;N;;;;; -E0162;VARIATION SELECTOR-115;Mn;0;NSM;;;;;N;;;;; -E0163;VARIATION SELECTOR-116;Mn;0;NSM;;;;;N;;;;; -E0164;VARIATION SELECTOR-117;Mn;0;NSM;;;;;N;;;;; -E0165;VARIATION SELECTOR-118;Mn;0;NSM;;;;;N;;;;; -E0166;VARIATION SELECTOR-119;Mn;0;NSM;;;;;N;;;;; -E0167;VARIATION SELECTOR-120;Mn;0;NSM;;;;;N;;;;; -E0168;VARIATION SELECTOR-121;Mn;0;NSM;;;;;N;;;;; -E0169;VARIATION SELECTOR-122;Mn;0;NSM;;;;;N;;;;; -E016A;VARIATION SELECTOR-123;Mn;0;NSM;;;;;N;;;;; -E016B;VARIATION SELECTOR-124;Mn;0;NSM;;;;;N;;;;; -E016C;VARIATION SELECTOR-125;Mn;0;NSM;;;;;N;;;;; -E016D;VARIATION SELECTOR-126;Mn;0;NSM;;;;;N;;;;; -E016E;VARIATION SELECTOR-127;Mn;0;NSM;;;;;N;;;;; -E016F;VARIATION SELECTOR-128;Mn;0;NSM;;;;;N;;;;; -E0170;VARIATION SELECTOR-129;Mn;0;NSM;;;;;N;;;;; -E0171;VARIATION SELECTOR-130;Mn;0;NSM;;;;;N;;;;; -E0172;VARIATION SELECTOR-131;Mn;0;NSM;;;;;N;;;;; -E0173;VARIATION SELECTOR-132;Mn;0;NSM;;;;;N;;;;; -E0174;VARIATION SELECTOR-133;Mn;0;NSM;;;;;N;;;;; -E0175;VARIATION SELECTOR-134;Mn;0;NSM;;;;;N;;;;; -E0176;VARIATION SELECTOR-135;Mn;0;NSM;;;;;N;;;;; -E0177;VARIATION SELECTOR-136;Mn;0;NSM;;;;;N;;;;; -E0178;VARIATION SELECTOR-137;Mn;0;NSM;;;;;N;;;;; -E0179;VARIATION SELECTOR-138;Mn;0;NSM;;;;;N;;;;; -E017A;VARIATION SELECTOR-139;Mn;0;NSM;;;;;N;;;;; -E017B;VARIATION SELECTOR-140;Mn;0;NSM;;;;;N;;;;; -E017C;VARIATION SELECTOR-141;Mn;0;NSM;;;;;N;;;;; -E017D;VARIATION SELECTOR-142;Mn;0;NSM;;;;;N;;;;; -E017E;VARIATION SELECTOR-143;Mn;0;NSM;;;;;N;;;;; -E017F;VARIATION SELECTOR-144;Mn;0;NSM;;;;;N;;;;; -E0180;VARIATION SELECTOR-145;Mn;0;NSM;;;;;N;;;;; -E0181;VARIATION SELECTOR-146;Mn;0;NSM;;;;;N;;;;; -E0182;VARIATION SELECTOR-147;Mn;0;NSM;;;;;N;;;;; -E0183;VARIATION SELECTOR-148;Mn;0;NSM;;;;;N;;;;; -E0184;VARIATION SELECTOR-149;Mn;0;NSM;;;;;N;;;;; -E0185;VARIATION SELECTOR-150;Mn;0;NSM;;;;;N;;;;; -E0186;VARIATION SELECTOR-151;Mn;0;NSM;;;;;N;;;;; -E0187;VARIATION SELECTOR-152;Mn;0;NSM;;;;;N;;;;; -E0188;VARIATION SELECTOR-153;Mn;0;NSM;;;;;N;;;;; -E0189;VARIATION SELECTOR-154;Mn;0;NSM;;;;;N;;;;; -E018A;VARIATION SELECTOR-155;Mn;0;NSM;;;;;N;;;;; -E018B;VARIATION SELECTOR-156;Mn;0;NSM;;;;;N;;;;; -E018C;VARIATION SELECTOR-157;Mn;0;NSM;;;;;N;;;;; -E018D;VARIATION SELECTOR-158;Mn;0;NSM;;;;;N;;;;; -E018E;VARIATION SELECTOR-159;Mn;0;NSM;;;;;N;;;;; -E018F;VARIATION SELECTOR-160;Mn;0;NSM;;;;;N;;;;; -E0190;VARIATION SELECTOR-161;Mn;0;NSM;;;;;N;;;;; -E0191;VARIATION SELECTOR-162;Mn;0;NSM;;;;;N;;;;; -E0192;VARIATION SELECTOR-163;Mn;0;NSM;;;;;N;;;;; -E0193;VARIATION SELECTOR-164;Mn;0;NSM;;;;;N;;;;; -E0194;VARIATION SELECTOR-165;Mn;0;NSM;;;;;N;;;;; -E0195;VARIATION SELECTOR-166;Mn;0;NSM;;;;;N;;;;; -E0196;VARIATION SELECTOR-167;Mn;0;NSM;;;;;N;;;;; -E0197;VARIATION SELECTOR-168;Mn;0;NSM;;;;;N;;;;; -E0198;VARIATION SELECTOR-169;Mn;0;NSM;;;;;N;;;;; -E0199;VARIATION SELECTOR-170;Mn;0;NSM;;;;;N;;;;; -E019A;VARIATION SELECTOR-171;Mn;0;NSM;;;;;N;;;;; -E019B;VARIATION SELECTOR-172;Mn;0;NSM;;;;;N;;;;; -E019C;VARIATION SELECTOR-173;Mn;0;NSM;;;;;N;;;;; -E019D;VARIATION SELECTOR-174;Mn;0;NSM;;;;;N;;;;; -E019E;VARIATION SELECTOR-175;Mn;0;NSM;;;;;N;;;;; -E019F;VARIATION SELECTOR-176;Mn;0;NSM;;;;;N;;;;; -E01A0;VARIATION SELECTOR-177;Mn;0;NSM;;;;;N;;;;; -E01A1;VARIATION SELECTOR-178;Mn;0;NSM;;;;;N;;;;; -E01A2;VARIATION SELECTOR-179;Mn;0;NSM;;;;;N;;;;; -E01A3;VARIATION SELECTOR-180;Mn;0;NSM;;;;;N;;;;; -E01A4;VARIATION SELECTOR-181;Mn;0;NSM;;;;;N;;;;; -E01A5;VARIATION SELECTOR-182;Mn;0;NSM;;;;;N;;;;; -E01A6;VARIATION SELECTOR-183;Mn;0;NSM;;;;;N;;;;; -E01A7;VARIATION SELECTOR-184;Mn;0;NSM;;;;;N;;;;; -E01A8;VARIATION SELECTOR-185;Mn;0;NSM;;;;;N;;;;; -E01A9;VARIATION SELECTOR-186;Mn;0;NSM;;;;;N;;;;; -E01AA;VARIATION SELECTOR-187;Mn;0;NSM;;;;;N;;;;; -E01AB;VARIATION SELECTOR-188;Mn;0;NSM;;;;;N;;;;; -E01AC;VARIATION SELECTOR-189;Mn;0;NSM;;;;;N;;;;; -E01AD;VARIATION SELECTOR-190;Mn;0;NSM;;;;;N;;;;; -E01AE;VARIATION SELECTOR-191;Mn;0;NSM;;;;;N;;;;; -E01AF;VARIATION SELECTOR-192;Mn;0;NSM;;;;;N;;;;; -E01B0;VARIATION SELECTOR-193;Mn;0;NSM;;;;;N;;;;; -E01B1;VARIATION SELECTOR-194;Mn;0;NSM;;;;;N;;;;; -E01B2;VARIATION SELECTOR-195;Mn;0;NSM;;;;;N;;;;; -E01B3;VARIATION SELECTOR-196;Mn;0;NSM;;;;;N;;;;; -E01B4;VARIATION SELECTOR-197;Mn;0;NSM;;;;;N;;;;; -E01B5;VARIATION SELECTOR-198;Mn;0;NSM;;;;;N;;;;; -E01B6;VARIATION SELECTOR-199;Mn;0;NSM;;;;;N;;;;; -E01B7;VARIATION SELECTOR-200;Mn;0;NSM;;;;;N;;;;; -E01B8;VARIATION SELECTOR-201;Mn;0;NSM;;;;;N;;;;; -E01B9;VARIATION SELECTOR-202;Mn;0;NSM;;;;;N;;;;; -E01BA;VARIATION SELECTOR-203;Mn;0;NSM;;;;;N;;;;; -E01BB;VARIATION SELECTOR-204;Mn;0;NSM;;;;;N;;;;; -E01BC;VARIATION SELECTOR-205;Mn;0;NSM;;;;;N;;;;; -E01BD;VARIATION SELECTOR-206;Mn;0;NSM;;;;;N;;;;; -E01BE;VARIATION SELECTOR-207;Mn;0;NSM;;;;;N;;;;; -E01BF;VARIATION SELECTOR-208;Mn;0;NSM;;;;;N;;;;; -E01C0;VARIATION SELECTOR-209;Mn;0;NSM;;;;;N;;;;; -E01C1;VARIATION SELECTOR-210;Mn;0;NSM;;;;;N;;;;; -E01C2;VARIATION SELECTOR-211;Mn;0;NSM;;;;;N;;;;; -E01C3;VARIATION SELECTOR-212;Mn;0;NSM;;;;;N;;;;; -E01C4;VARIATION SELECTOR-213;Mn;0;NSM;;;;;N;;;;; -E01C5;VARIATION SELECTOR-214;Mn;0;NSM;;;;;N;;;;; -E01C6;VARIATION SELECTOR-215;Mn;0;NSM;;;;;N;;;;; -E01C7;VARIATION SELECTOR-216;Mn;0;NSM;;;;;N;;;;; -E01C8;VARIATION SELECTOR-217;Mn;0;NSM;;;;;N;;;;; -E01C9;VARIATION SELECTOR-218;Mn;0;NSM;;;;;N;;;;; -E01CA;VARIATION SELECTOR-219;Mn;0;NSM;;;;;N;;;;; -E01CB;VARIATION SELECTOR-220;Mn;0;NSM;;;;;N;;;;; -E01CC;VARIATION SELECTOR-221;Mn;0;NSM;;;;;N;;;;; -E01CD;VARIATION SELECTOR-222;Mn;0;NSM;;;;;N;;;;; -E01CE;VARIATION SELECTOR-223;Mn;0;NSM;;;;;N;;;;; -E01CF;VARIATION SELECTOR-224;Mn;0;NSM;;;;;N;;;;; -E01D0;VARIATION SELECTOR-225;Mn;0;NSM;;;;;N;;;;; -E01D1;VARIATION SELECTOR-226;Mn;0;NSM;;;;;N;;;;; -E01D2;VARIATION SELECTOR-227;Mn;0;NSM;;;;;N;;;;; -E01D3;VARIATION SELECTOR-228;Mn;0;NSM;;;;;N;;;;; -E01D4;VARIATION SELECTOR-229;Mn;0;NSM;;;;;N;;;;; -E01D5;VARIATION SELECTOR-230;Mn;0;NSM;;;;;N;;;;; -E01D6;VARIATION SELECTOR-231;Mn;0;NSM;;;;;N;;;;; -E01D7;VARIATION SELECTOR-232;Mn;0;NSM;;;;;N;;;;; -E01D8;VARIATION SELECTOR-233;Mn;0;NSM;;;;;N;;;;; -E01D9;VARIATION SELECTOR-234;Mn;0;NSM;;;;;N;;;;; -E01DA;VARIATION SELECTOR-235;Mn;0;NSM;;;;;N;;;;; -E01DB;VARIATION SELECTOR-236;Mn;0;NSM;;;;;N;;;;; -E01DC;VARIATION SELECTOR-237;Mn;0;NSM;;;;;N;;;;; -E01DD;VARIATION SELECTOR-238;Mn;0;NSM;;;;;N;;;;; -E01DE;VARIATION SELECTOR-239;Mn;0;NSM;;;;;N;;;;; -E01DF;VARIATION SELECTOR-240;Mn;0;NSM;;;;;N;;;;; -E01E0;VARIATION SELECTOR-241;Mn;0;NSM;;;;;N;;;;; -E01E1;VARIATION SELECTOR-242;Mn;0;NSM;;;;;N;;;;; -E01E2;VARIATION SELECTOR-243;Mn;0;NSM;;;;;N;;;;; -E01E3;VARIATION SELECTOR-244;Mn;0;NSM;;;;;N;;;;; -E01E4;VARIATION SELECTOR-245;Mn;0;NSM;;;;;N;;;;; -E01E5;VARIATION SELECTOR-246;Mn;0;NSM;;;;;N;;;;; -E01E6;VARIATION SELECTOR-247;Mn;0;NSM;;;;;N;;;;; -E01E7;VARIATION SELECTOR-248;Mn;0;NSM;;;;;N;;;;; -E01E8;VARIATION SELECTOR-249;Mn;0;NSM;;;;;N;;;;; -E01E9;VARIATION SELECTOR-250;Mn;0;NSM;;;;;N;;;;; -E01EA;VARIATION SELECTOR-251;Mn;0;NSM;;;;;N;;;;; -E01EB;VARIATION SELECTOR-252;Mn;0;NSM;;;;;N;;;;; -E01EC;VARIATION SELECTOR-253;Mn;0;NSM;;;;;N;;;;; -E01ED;VARIATION SELECTOR-254;Mn;0;NSM;;;;;N;;;;; -E01EE;VARIATION SELECTOR-255;Mn;0;NSM;;;;;N;;;;; -E01EF;VARIATION SELECTOR-256;Mn;0;NSM;;;;;N;;;;; -F0000;<Plane 15 Private Use, First>;Co;0;L;;;;;N;;;;; -FFFFD;<Plane 15 Private Use, Last>;Co;0;L;;;;;N;;;;; -100000;<Plane 16 Private Use, First>;Co;0;L;;;;;N;;;;; -10FFFD;<Plane 16 Private Use, Last>;Co;0;L;;;;;N;;;;; diff --git a/src/unicode/emoji-data.txt b/src/unicode/emoji-data.txt deleted file mode 100644 index 0ba10e9ce4..0000000000 --- a/src/unicode/emoji-data.txt +++ /dev/null @@ -1,1320 +0,0 @@ -# emoji-data.txt -# Date: 2023-02-01, 02:22:54 GMT -# © 2023 Unicode®, Inc. -# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see https://www.unicode.org/terms_of_use.html -# -# Emoji Data for UTS #51 -# Used with Emoji Version 15.1 and subsequent minor revisions (if any) -# -# For documentation and usage, see https://www.unicode.org/reports/tr51 -# -# Format: -# <codepoint(s)> ; <property> # <comments> -# Note: there is no guarantee as to the structure of whitespace or comments -# -# Characters and sequences are listed in code point order. Users should be shown a more natural order. -# See the CLDR collation order for Emoji. - - -# ================================================ - -# All omitted code points have Emoji=No - -0023 ; Emoji # E0.0 [1] (#ï¸) hash sign -002A ; Emoji # E0.0 [1] (*ï¸) asterisk -0030..0039 ; Emoji # E0.0 [10] (0ï¸..9ï¸) digit zero..digit nine -00A9 ; Emoji # E0.6 [1] (©ï¸) copyright -00AE ; Emoji # E0.6 [1] (®ï¸) registered -203C ; Emoji # E0.6 [1] (‼ï¸) double exclamation mark -2049 ; Emoji # E0.6 [1] (â‰ï¸) exclamation question mark -2122 ; Emoji # E0.6 [1] (â„¢ï¸) trade mark -2139 ; Emoji # E0.6 [1] (ℹï¸) information -2194..2199 ; Emoji # E0.6 [6] (↔ï¸..↙ï¸) left-right arrow..down-left arrow -21A9..21AA ; Emoji # E0.6 [2] (↩ï¸..↪ï¸) right arrow curving left..left arrow curving right -231A..231B ; Emoji # E0.6 [2] (⌚..⌛) watch..hourglass done -2328 ; Emoji # E1.0 [1] (⌨ï¸) keyboard -23CF ; Emoji # E1.0 [1] (âï¸) eject button -23E9..23EC ; Emoji # E0.6 [4] (â©..â¬) fast-forward button..fast down button -23ED..23EE ; Emoji # E0.7 [2] (âï¸..â®ï¸) next track button..last track button -23EF ; Emoji # E1.0 [1] (â¯ï¸) play or pause button -23F0 ; Emoji # E0.6 [1] (â°) alarm clock -23F1..23F2 ; Emoji # E1.0 [2] (â±ï¸..â²ï¸) stopwatch..timer clock -23F3 ; Emoji # E0.6 [1] (â³) hourglass not done -23F8..23FA ; Emoji # E0.7 [3] (â¸ï¸..âºï¸) pause button..record button -24C2 ; Emoji # E0.6 [1] (â“‚ï¸) circled M -25AA..25AB ; Emoji # E0.6 [2] (â–ªï¸..â–«ï¸) black small square..white small square -25B6 ; Emoji # E0.6 [1] (â–¶ï¸) play button -25C0 ; Emoji # E0.6 [1] (â—€ï¸) reverse button -25FB..25FE ; Emoji # E0.6 [4] (â—»ï¸..â—¾) white medium square..black medium-small square -2600..2601 ; Emoji # E0.6 [2] (☀ï¸..â˜ï¸) sun..cloud -2602..2603 ; Emoji # E0.7 [2] (☂ï¸..☃ï¸) umbrella..snowman -2604 ; Emoji # E1.0 [1] (☄ï¸) comet -260E ; Emoji # E0.6 [1] (☎ï¸) telephone -2611 ; Emoji # E0.6 [1] (☑ï¸) check box with check -2614..2615 ; Emoji # E0.6 [2] (☔..☕) umbrella with rain drops..hot beverage -2618 ; Emoji # E1.0 [1] (☘ï¸) shamrock -261D ; Emoji # E0.6 [1] (â˜ï¸) index pointing up -2620 ; Emoji # E1.0 [1] (☠ï¸) skull and crossbones -2622..2623 ; Emoji # E1.0 [2] (☢ï¸..☣ï¸) radioactive..biohazard -2626 ; Emoji # E1.0 [1] (☦ï¸) orthodox cross -262A ; Emoji # E0.7 [1] (☪ï¸) star and crescent -262E ; Emoji # E1.0 [1] (☮ï¸) peace symbol -262F ; Emoji # E0.7 [1] (☯ï¸) yin yang -2638..2639 ; Emoji # E0.7 [2] (☸ï¸..☹ï¸) wheel of dharma..frowning face -263A ; Emoji # E0.6 [1] (☺ï¸) smiling face -2640 ; Emoji # E4.0 [1] (♀ï¸) female sign -2642 ; Emoji # E4.0 [1] (♂ï¸) male sign -2648..2653 ; Emoji # E0.6 [12] (♈..♓) Aries..Pisces -265F ; Emoji # E11.0 [1] (♟ï¸) chess pawn -2660 ; Emoji # E0.6 [1] (â™ ï¸) spade suit -2663 ; Emoji # E0.6 [1] (♣ï¸) club suit -2665..2666 ; Emoji # E0.6 [2] (♥ï¸..♦ï¸) heart suit..diamond suit -2668 ; Emoji # E0.6 [1] (♨ï¸) hot springs -267B ; Emoji # E0.6 [1] (â™»ï¸) recycling symbol -267E ; Emoji # E11.0 [1] (♾ï¸) infinity -267F ; Emoji # E0.6 [1] (♿) wheelchair symbol -2692 ; Emoji # E1.0 [1] (âš’ï¸) hammer and pick -2693 ; Emoji # E0.6 [1] (âš“) anchor -2694 ; Emoji # E1.0 [1] (âš”ï¸) crossed swords -2695 ; Emoji # E4.0 [1] (âš•ï¸) medical symbol -2696..2697 ; Emoji # E1.0 [2] (âš–ï¸..âš—ï¸) balance scale..alembic -2699 ; Emoji # E1.0 [1] (âš™ï¸) gear -269B..269C ; Emoji # E1.0 [2] (âš›ï¸..âšœï¸) atom symbol..fleur-de-lis -26A0..26A1 ; Emoji # E0.6 [2] (âš ï¸..âš¡) warning..high voltage -26A7 ; Emoji # E13.0 [1] (âš§ï¸) transgender symbol -26AA..26AB ; Emoji # E0.6 [2] (⚪..âš«) white circle..black circle -26B0..26B1 ; Emoji # E1.0 [2] (âš°ï¸..âš±ï¸) coffin..funeral urn -26BD..26BE ; Emoji # E0.6 [2] (âš½..âš¾) soccer ball..baseball -26C4..26C5 ; Emoji # E0.6 [2] (⛄..â›…) snowman without snow..sun behind cloud -26C8 ; Emoji # E0.7 [1] (⛈ï¸) cloud with lightning and rain -26CE ; Emoji # E0.6 [1] (⛎) Ophiuchus -26CF ; Emoji # E0.7 [1] (â›ï¸) pick -26D1 ; Emoji # E0.7 [1] (⛑ï¸) rescue worker’s helmet -26D3 ; Emoji # E0.7 [1] (⛓ï¸) chains -26D4 ; Emoji # E0.6 [1] (â›”) no entry -26E9 ; Emoji # E0.7 [1] (⛩ï¸) shinto shrine -26EA ; Emoji # E0.6 [1] (⛪) church -26F0..26F1 ; Emoji # E0.7 [2] (â›°ï¸..â›±ï¸) mountain..umbrella on ground -26F2..26F3 ; Emoji # E0.6 [2] (⛲..⛳) fountain..flag in hole -26F4 ; Emoji # E0.7 [1] (â›´ï¸) ferry -26F5 ; Emoji # E0.6 [1] (⛵) sailboat -26F7..26F9 ; Emoji # E0.7 [3] (â›·ï¸..⛹ï¸) skier..person bouncing ball -26FA ; Emoji # E0.6 [1] (⛺) tent -26FD ; Emoji # E0.6 [1] (⛽) fuel pump -2702 ; Emoji # E0.6 [1] (✂ï¸) scissors -2705 ; Emoji # E0.6 [1] (✅) check mark button -2708..270C ; Emoji # E0.6 [5] (✈ï¸..✌ï¸) airplane..victory hand -270D ; Emoji # E0.7 [1] (âœï¸) writing hand -270F ; Emoji # E0.6 [1] (âœï¸) pencil -2712 ; Emoji # E0.6 [1] (✒ï¸) black nib -2714 ; Emoji # E0.6 [1] (✔ï¸) check mark -2716 ; Emoji # E0.6 [1] (✖ï¸) multiply -271D ; Emoji # E0.7 [1] (âœï¸) latin cross -2721 ; Emoji # E0.7 [1] (✡ï¸) star of David -2728 ; Emoji # E0.6 [1] (✨) sparkles -2733..2734 ; Emoji # E0.6 [2] (✳ï¸..✴ï¸) eight-spoked asterisk..eight-pointed star -2744 ; Emoji # E0.6 [1] (â„ï¸) snowflake -2747 ; Emoji # E0.6 [1] (â‡ï¸) sparkle -274C ; Emoji # E0.6 [1] (âŒ) cross mark -274E ; Emoji # E0.6 [1] (âŽ) cross mark button -2753..2755 ; Emoji # E0.6 [3] (â“..â•) red question mark..white exclamation mark -2757 ; Emoji # E0.6 [1] (â—) red exclamation mark -2763 ; Emoji # E1.0 [1] (â£ï¸) heart exclamation -2764 ; Emoji # E0.6 [1] (â¤ï¸) red heart -2795..2797 ; Emoji # E0.6 [3] (âž•..âž—) plus..divide -27A1 ; Emoji # E0.6 [1] (âž¡ï¸) right arrow -27B0 ; Emoji # E0.6 [1] (âž°) curly loop -27BF ; Emoji # E1.0 [1] (âž¿) double curly loop -2934..2935 ; Emoji # E0.6 [2] (⤴ï¸..⤵ï¸) right arrow curving up..right arrow curving down -2B05..2B07 ; Emoji # E0.6 [3] (⬅ï¸..⬇ï¸) left arrow..down arrow -2B1B..2B1C ; Emoji # E0.6 [2] (⬛..⬜) black large square..white large square -2B50 ; Emoji # E0.6 [1] (â) star -2B55 ; Emoji # E0.6 [1] (â•) hollow red circle -3030 ; Emoji # E0.6 [1] (〰ï¸) wavy dash -303D ; Emoji # E0.6 [1] (〽ï¸) part alternation mark -3297 ; Emoji # E0.6 [1] (㊗ï¸) Japanese “congratulations†button -3299 ; Emoji # E0.6 [1] (㊙ï¸) Japanese “secret†button -1F004 ; Emoji # E0.6 [1] (🀄) mahjong red dragon -1F0CF ; Emoji # E0.6 [1] (ðŸƒ) joker -1F170..1F171 ; Emoji # E0.6 [2] (🅰ï¸..🅱ï¸) A button (blood type)..B button (blood type) -1F17E..1F17F ; Emoji # E0.6 [2] (🅾ï¸..🅿ï¸) O button (blood type)..P button -1F18E ; Emoji # E0.6 [1] (🆎) AB button (blood type) -1F191..1F19A ; Emoji # E0.6 [10] (🆑..🆚) CL button..VS button -1F1E6..1F1FF ; Emoji # E0.0 [26] (🇦..🇿) regional indicator symbol letter a..regional indicator symbol letter z -1F201..1F202 ; Emoji # E0.6 [2] (ðŸˆ..🈂ï¸) Japanese “here†button..Japanese “service charge†button -1F21A ; Emoji # E0.6 [1] (🈚) Japanese “free of charge†button -1F22F ; Emoji # E0.6 [1] (🈯) Japanese “reserved†button -1F232..1F23A ; Emoji # E0.6 [9] (🈲..🈺) Japanese “prohibited†button..Japanese “open for business†button -1F250..1F251 ; Emoji # E0.6 [2] (ðŸ‰..🉑) Japanese “bargain†button..Japanese “acceptable†button -1F300..1F30C ; Emoji # E0.6 [13] (🌀..🌌) cyclone..milky way -1F30D..1F30E ; Emoji # E0.7 [2] (ðŸŒ..🌎) globe showing Europe-Africa..globe showing Americas -1F30F ; Emoji # E0.6 [1] (ðŸŒ) globe showing Asia-Australia -1F310 ; Emoji # E1.0 [1] (ðŸŒ) globe with meridians -1F311 ; Emoji # E0.6 [1] (🌑) new moon -1F312 ; Emoji # E1.0 [1] (🌒) waxing crescent moon -1F313..1F315 ; Emoji # E0.6 [3] (🌓..🌕) first quarter moon..full moon -1F316..1F318 ; Emoji # E1.0 [3] (🌖..🌘) waning gibbous moon..waning crescent moon -1F319 ; Emoji # E0.6 [1] (🌙) crescent moon -1F31A ; Emoji # E1.0 [1] (🌚) new moon face -1F31B ; Emoji # E0.6 [1] (🌛) first quarter moon face -1F31C ; Emoji # E0.7 [1] (🌜) last quarter moon face -1F31D..1F31E ; Emoji # E1.0 [2] (ðŸŒ..🌞) full moon face..sun with face -1F31F..1F320 ; Emoji # E0.6 [2] (🌟..🌠) glowing star..shooting star -1F321 ; Emoji # E0.7 [1] (🌡ï¸) thermometer -1F324..1F32C ; Emoji # E0.7 [9] (🌤ï¸..🌬ï¸) sun behind small cloud..wind face -1F32D..1F32F ; Emoji # E1.0 [3] (ðŸŒ..🌯) hot dog..burrito -1F330..1F331 ; Emoji # E0.6 [2] (🌰..🌱) chestnut..seedling -1F332..1F333 ; Emoji # E1.0 [2] (🌲..🌳) evergreen tree..deciduous tree -1F334..1F335 ; Emoji # E0.6 [2] (🌴..🌵) palm tree..cactus -1F336 ; Emoji # E0.7 [1] (🌶ï¸) hot pepper -1F337..1F34A ; Emoji # E0.6 [20] (🌷..ðŸŠ) tulip..tangerine -1F34B ; Emoji # E1.0 [1] (ðŸ‹) lemon -1F34C..1F34F ; Emoji # E0.6 [4] (ðŸŒ..ðŸ) banana..green apple -1F350 ; Emoji # E1.0 [1] (ðŸ) pear -1F351..1F37B ; Emoji # E0.6 [43] (ðŸ‘..ðŸ») peach..clinking beer mugs -1F37C ; Emoji # E1.0 [1] (ðŸ¼) baby bottle -1F37D ; Emoji # E0.7 [1] (ðŸ½ï¸) fork and knife with plate -1F37E..1F37F ; Emoji # E1.0 [2] (ðŸ¾..ðŸ¿) bottle with popping cork..popcorn -1F380..1F393 ; Emoji # E0.6 [20] (🎀..🎓) ribbon..graduation cap -1F396..1F397 ; Emoji # E0.7 [2] (🎖ï¸..🎗ï¸) military medal..reminder ribbon -1F399..1F39B ; Emoji # E0.7 [3] (🎙ï¸..🎛ï¸) studio microphone..control knobs -1F39E..1F39F ; Emoji # E0.7 [2] (🎞ï¸..🎟ï¸) film frames..admission tickets -1F3A0..1F3C4 ; Emoji # E0.6 [37] (🎠..ðŸ„) carousel horse..person surfing -1F3C5 ; Emoji # E1.0 [1] (ðŸ…) sports medal -1F3C6 ; Emoji # E0.6 [1] (ðŸ†) trophy -1F3C7 ; Emoji # E1.0 [1] (ðŸ‡) horse racing -1F3C8 ; Emoji # E0.6 [1] (ðŸˆ) american football -1F3C9 ; Emoji # E1.0 [1] (ðŸ‰) rugby football -1F3CA ; Emoji # E0.6 [1] (ðŸŠ) person swimming -1F3CB..1F3CE ; Emoji # E0.7 [4] (ðŸ‹ï¸..ðŸŽï¸) person lifting weights..racing car -1F3CF..1F3D3 ; Emoji # E1.0 [5] (ðŸ..ðŸ“) cricket game..ping pong -1F3D4..1F3DF ; Emoji # E0.7 [12] (ðŸ”ï¸..ðŸŸï¸) snow-capped mountain..stadium -1F3E0..1F3E3 ; Emoji # E0.6 [4] (ðŸ ..ðŸ£) house..Japanese post office -1F3E4 ; Emoji # E1.0 [1] (ðŸ¤) post office -1F3E5..1F3F0 ; Emoji # E0.6 [12] (ðŸ¥..ðŸ°) hospital..castle -1F3F3 ; Emoji # E0.7 [1] (ðŸ³ï¸) white flag -1F3F4 ; Emoji # E1.0 [1] (ðŸ´) black flag -1F3F5 ; Emoji # E0.7 [1] (ðŸµï¸) rosette -1F3F7 ; Emoji # E0.7 [1] (ðŸ·ï¸) label -1F3F8..1F407 ; Emoji # E1.0 [16] (ðŸ¸..ðŸ‡) badminton..rabbit -1F408 ; Emoji # E0.7 [1] (ðŸˆ) cat -1F409..1F40B ; Emoji # E1.0 [3] (ðŸ‰..ðŸ‹) dragon..whale -1F40C..1F40E ; Emoji # E0.6 [3] (ðŸŒ..ðŸŽ) snail..horse -1F40F..1F410 ; Emoji # E1.0 [2] (ðŸ..ðŸ) ram..goat -1F411..1F412 ; Emoji # E0.6 [2] (ðŸ‘..ðŸ’) ewe..monkey -1F413 ; Emoji # E1.0 [1] (ðŸ“) rooster -1F414 ; Emoji # E0.6 [1] (ðŸ”) chicken -1F415 ; Emoji # E0.7 [1] (ðŸ•) dog -1F416 ; Emoji # E1.0 [1] (ðŸ–) pig -1F417..1F429 ; Emoji # E0.6 [19] (ðŸ—..ðŸ©) boar..poodle -1F42A ; Emoji # E1.0 [1] (ðŸª) camel -1F42B..1F43E ; Emoji # E0.6 [20] (ðŸ«..ðŸ¾) two-hump camel..paw prints -1F43F ; Emoji # E0.7 [1] (ðŸ¿ï¸) chipmunk -1F440 ; Emoji # E0.6 [1] (👀) eyes -1F441 ; Emoji # E0.7 [1] (ðŸ‘ï¸) eye -1F442..1F464 ; Emoji # E0.6 [35] (👂..👤) ear..bust in silhouette -1F465 ; Emoji # E1.0 [1] (👥) busts in silhouette -1F466..1F46B ; Emoji # E0.6 [6] (👦..👫) boy..woman and man holding hands -1F46C..1F46D ; Emoji # E1.0 [2] (👬..ðŸ‘) men holding hands..women holding hands -1F46E..1F4AC ; Emoji # E0.6 [63] (👮..💬) police officer..speech balloon -1F4AD ; Emoji # E1.0 [1] (ðŸ’) thought balloon -1F4AE..1F4B5 ; Emoji # E0.6 [8] (💮..💵) white flower..dollar banknote -1F4B6..1F4B7 ; Emoji # E1.0 [2] (💶..💷) euro banknote..pound banknote -1F4B8..1F4EB ; Emoji # E0.6 [52] (💸..📫) money with wings..closed mailbox with raised flag -1F4EC..1F4ED ; Emoji # E0.7 [2] (📬..ðŸ“) open mailbox with raised flag..open mailbox with lowered flag -1F4EE ; Emoji # E0.6 [1] (📮) postbox -1F4EF ; Emoji # E1.0 [1] (📯) postal horn -1F4F0..1F4F4 ; Emoji # E0.6 [5] (📰..📴) newspaper..mobile phone off -1F4F5 ; Emoji # E1.0 [1] (📵) no mobile phones -1F4F6..1F4F7 ; Emoji # E0.6 [2] (📶..📷) antenna bars..camera -1F4F8 ; Emoji # E1.0 [1] (📸) camera with flash -1F4F9..1F4FC ; Emoji # E0.6 [4] (📹..📼) video camera..videocassette -1F4FD ; Emoji # E0.7 [1] (📽ï¸) film projector -1F4FF..1F502 ; Emoji # E1.0 [4] (📿..🔂) prayer beads..repeat single button -1F503 ; Emoji # E0.6 [1] (🔃) clockwise vertical arrows -1F504..1F507 ; Emoji # E1.0 [4] (🔄..🔇) counterclockwise arrows button..muted speaker -1F508 ; Emoji # E0.7 [1] (🔈) speaker low volume -1F509 ; Emoji # E1.0 [1] (🔉) speaker medium volume -1F50A..1F514 ; Emoji # E0.6 [11] (🔊..🔔) speaker high volume..bell -1F515 ; Emoji # E1.0 [1] (🔕) bell with slash -1F516..1F52B ; Emoji # E0.6 [22] (🔖..🔫) bookmark..water pistol -1F52C..1F52D ; Emoji # E1.0 [2] (🔬..ðŸ”) microscope..telescope -1F52E..1F53D ; Emoji # E0.6 [16] (🔮..🔽) crystal ball..downwards button -1F549..1F54A ; Emoji # E0.7 [2] (🕉ï¸..🕊ï¸) om..dove -1F54B..1F54E ; Emoji # E1.0 [4] (🕋..🕎) kaaba..menorah -1F550..1F55B ; Emoji # E0.6 [12] (ðŸ•..🕛) one o’clock..twelve o’clock -1F55C..1F567 ; Emoji # E0.7 [12] (🕜..🕧) one-thirty..twelve-thirty -1F56F..1F570 ; Emoji # E0.7 [2] (🕯ï¸..🕰ï¸) candle..mantelpiece clock -1F573..1F579 ; Emoji # E0.7 [7] (🕳ï¸..🕹ï¸) hole..joystick -1F57A ; Emoji # E3.0 [1] (🕺) man dancing -1F587 ; Emoji # E0.7 [1] (🖇ï¸) linked paperclips -1F58A..1F58D ; Emoji # E0.7 [4] (🖊ï¸..ðŸ–ï¸) pen..crayon -1F590 ; Emoji # E0.7 [1] (ðŸ–ï¸) hand with fingers splayed -1F595..1F596 ; Emoji # E1.0 [2] (🖕..🖖) middle finger..vulcan salute -1F5A4 ; Emoji # E3.0 [1] (🖤) black heart -1F5A5 ; Emoji # E0.7 [1] (🖥ï¸) desktop computer -1F5A8 ; Emoji # E0.7 [1] (🖨ï¸) printer -1F5B1..1F5B2 ; Emoji # E0.7 [2] (🖱ï¸..🖲ï¸) computer mouse..trackball -1F5BC ; Emoji # E0.7 [1] (🖼ï¸) framed picture -1F5C2..1F5C4 ; Emoji # E0.7 [3] (🗂ï¸..🗄ï¸) card index dividers..file cabinet -1F5D1..1F5D3 ; Emoji # E0.7 [3] (🗑ï¸..🗓ï¸) wastebasket..spiral calendar -1F5DC..1F5DE ; Emoji # E0.7 [3] (🗜ï¸..🗞ï¸) clamp..rolled-up newspaper -1F5E1 ; Emoji # E0.7 [1] (🗡ï¸) dagger -1F5E3 ; Emoji # E0.7 [1] (🗣ï¸) speaking head -1F5E8 ; Emoji # E2.0 [1] (🗨ï¸) left speech bubble -1F5EF ; Emoji # E0.7 [1] (🗯ï¸) right anger bubble -1F5F3 ; Emoji # E0.7 [1] (🗳ï¸) ballot box with ballot -1F5FA ; Emoji # E0.7 [1] (🗺ï¸) world map -1F5FB..1F5FF ; Emoji # E0.6 [5] (🗻..🗿) mount fuji..moai -1F600 ; Emoji # E1.0 [1] (😀) grinning face -1F601..1F606 ; Emoji # E0.6 [6] (ðŸ˜..😆) beaming face with smiling eyes..grinning squinting face -1F607..1F608 ; Emoji # E1.0 [2] (😇..😈) smiling face with halo..smiling face with horns -1F609..1F60D ; Emoji # E0.6 [5] (😉..ðŸ˜) winking face..smiling face with heart-eyes -1F60E ; Emoji # E1.0 [1] (😎) smiling face with sunglasses -1F60F ; Emoji # E0.6 [1] (ðŸ˜) smirking face -1F610 ; Emoji # E0.7 [1] (ðŸ˜) neutral face -1F611 ; Emoji # E1.0 [1] (😑) expressionless face -1F612..1F614 ; Emoji # E0.6 [3] (😒..😔) unamused face..pensive face -1F615 ; Emoji # E1.0 [1] (😕) confused face -1F616 ; Emoji # E0.6 [1] (😖) confounded face -1F617 ; Emoji # E1.0 [1] (😗) kissing face -1F618 ; Emoji # E0.6 [1] (😘) face blowing a kiss -1F619 ; Emoji # E1.0 [1] (😙) kissing face with smiling eyes -1F61A ; Emoji # E0.6 [1] (😚) kissing face with closed eyes -1F61B ; Emoji # E1.0 [1] (😛) face with tongue -1F61C..1F61E ; Emoji # E0.6 [3] (😜..😞) winking face with tongue..disappointed face -1F61F ; Emoji # E1.0 [1] (😟) worried face -1F620..1F625 ; Emoji # E0.6 [6] (😠..😥) angry face..sad but relieved face -1F626..1F627 ; Emoji # E1.0 [2] (😦..😧) frowning face with open mouth..anguished face -1F628..1F62B ; Emoji # E0.6 [4] (😨..😫) fearful face..tired face -1F62C ; Emoji # E1.0 [1] (😬) grimacing face -1F62D ; Emoji # E0.6 [1] (ðŸ˜) loudly crying face -1F62E..1F62F ; Emoji # E1.0 [2] (😮..😯) face with open mouth..hushed face -1F630..1F633 ; Emoji # E0.6 [4] (😰..😳) anxious face with sweat..flushed face -1F634 ; Emoji # E1.0 [1] (😴) sleeping face -1F635 ; Emoji # E0.6 [1] (😵) face with crossed-out eyes -1F636 ; Emoji # E1.0 [1] (😶) face without mouth -1F637..1F640 ; Emoji # E0.6 [10] (😷..🙀) face with medical mask..weary cat -1F641..1F644 ; Emoji # E1.0 [4] (ðŸ™..🙄) slightly frowning face..face with rolling eyes -1F645..1F64F ; Emoji # E0.6 [11] (🙅..ðŸ™) person gesturing NO..folded hands -1F680 ; Emoji # E0.6 [1] (🚀) rocket -1F681..1F682 ; Emoji # E1.0 [2] (ðŸš..🚂) helicopter..locomotive -1F683..1F685 ; Emoji # E0.6 [3] (🚃..🚅) railway car..bullet train -1F686 ; Emoji # E1.0 [1] (🚆) train -1F687 ; Emoji # E0.6 [1] (🚇) metro -1F688 ; Emoji # E1.0 [1] (🚈) light rail -1F689 ; Emoji # E0.6 [1] (🚉) station -1F68A..1F68B ; Emoji # E1.0 [2] (🚊..🚋) tram..tram car -1F68C ; Emoji # E0.6 [1] (🚌) bus -1F68D ; Emoji # E0.7 [1] (ðŸš) oncoming bus -1F68E ; Emoji # E1.0 [1] (🚎) trolleybus -1F68F ; Emoji # E0.6 [1] (ðŸš) bus stop -1F690 ; Emoji # E1.0 [1] (ðŸš) minibus -1F691..1F693 ; Emoji # E0.6 [3] (🚑..🚓) ambulance..police car -1F694 ; Emoji # E0.7 [1] (🚔) oncoming police car -1F695 ; Emoji # E0.6 [1] (🚕) taxi -1F696 ; Emoji # E1.0 [1] (🚖) oncoming taxi -1F697 ; Emoji # E0.6 [1] (🚗) automobile -1F698 ; Emoji # E0.7 [1] (🚘) oncoming automobile -1F699..1F69A ; Emoji # E0.6 [2] (🚙..🚚) sport utility vehicle..delivery truck -1F69B..1F6A1 ; Emoji # E1.0 [7] (🚛..🚡) articulated lorry..aerial tramway -1F6A2 ; Emoji # E0.6 [1] (🚢) ship -1F6A3 ; Emoji # E1.0 [1] (🚣) person rowing boat -1F6A4..1F6A5 ; Emoji # E0.6 [2] (🚤..🚥) speedboat..horizontal traffic light -1F6A6 ; Emoji # E1.0 [1] (🚦) vertical traffic light -1F6A7..1F6AD ; Emoji # E0.6 [7] (🚧..ðŸš) construction..no smoking -1F6AE..1F6B1 ; Emoji # E1.0 [4] (🚮..🚱) litter in bin sign..non-potable water -1F6B2 ; Emoji # E0.6 [1] (🚲) bicycle -1F6B3..1F6B5 ; Emoji # E1.0 [3] (🚳..🚵) no bicycles..person mountain biking -1F6B6 ; Emoji # E0.6 [1] (🚶) person walking -1F6B7..1F6B8 ; Emoji # E1.0 [2] (🚷..🚸) no pedestrians..children crossing -1F6B9..1F6BE ; Emoji # E0.6 [6] (🚹..🚾) men’s room..water closet -1F6BF ; Emoji # E1.0 [1] (🚿) shower -1F6C0 ; Emoji # E0.6 [1] (🛀) person taking bath -1F6C1..1F6C5 ; Emoji # E1.0 [5] (ðŸ›..🛅) bathtub..left luggage -1F6CB ; Emoji # E0.7 [1] (🛋ï¸) couch and lamp -1F6CC ; Emoji # E1.0 [1] (🛌) person in bed -1F6CD..1F6CF ; Emoji # E0.7 [3] (ðŸ›ï¸..ðŸ›ï¸) shopping bags..bed -1F6D0 ; Emoji # E1.0 [1] (ðŸ›) place of worship -1F6D1..1F6D2 ; Emoji # E3.0 [2] (🛑..🛒) stop sign..shopping cart -1F6D5 ; Emoji # E12.0 [1] (🛕) hindu temple -1F6D6..1F6D7 ; Emoji # E13.0 [2] (🛖..🛗) hut..elevator -1F6DC ; Emoji # E15.0 [1] (🛜) wireless -1F6DD..1F6DF ; Emoji # E14.0 [3] (ðŸ›..🛟) playground slide..ring buoy -1F6E0..1F6E5 ; Emoji # E0.7 [6] (🛠ï¸..🛥ï¸) hammer and wrench..motor boat -1F6E9 ; Emoji # E0.7 [1] (🛩ï¸) small airplane -1F6EB..1F6EC ; Emoji # E1.0 [2] (🛫..🛬) airplane departure..airplane arrival -1F6F0 ; Emoji # E0.7 [1] (🛰ï¸) satellite -1F6F3 ; Emoji # E0.7 [1] (🛳ï¸) passenger ship -1F6F4..1F6F6 ; Emoji # E3.0 [3] (🛴..🛶) kick scooter..canoe -1F6F7..1F6F8 ; Emoji # E5.0 [2] (🛷..🛸) sled..flying saucer -1F6F9 ; Emoji # E11.0 [1] (🛹) skateboard -1F6FA ; Emoji # E12.0 [1] (🛺) auto rickshaw -1F6FB..1F6FC ; Emoji # E13.0 [2] (🛻..🛼) pickup truck..roller skate -1F7E0..1F7EB ; Emoji # E12.0 [12] (🟠..🟫) orange circle..brown square -1F7F0 ; Emoji # E14.0 [1] (🟰) heavy equals sign -1F90C ; Emoji # E13.0 [1] (🤌) pinched fingers -1F90D..1F90F ; Emoji # E12.0 [3] (ðŸ¤..ðŸ¤) white heart..pinching hand -1F910..1F918 ; Emoji # E1.0 [9] (ðŸ¤..🤘) zipper-mouth face..sign of the horns -1F919..1F91E ; Emoji # E3.0 [6] (🤙..🤞) call me hand..crossed fingers -1F91F ; Emoji # E5.0 [1] (🤟) love-you gesture -1F920..1F927 ; Emoji # E3.0 [8] (🤠..🤧) cowboy hat face..sneezing face -1F928..1F92F ; Emoji # E5.0 [8] (🤨..🤯) face with raised eyebrow..exploding head -1F930 ; Emoji # E3.0 [1] (🤰) pregnant woman -1F931..1F932 ; Emoji # E5.0 [2] (🤱..🤲) breast-feeding..palms up together -1F933..1F93A ; Emoji # E3.0 [8] (🤳..🤺) selfie..person fencing -1F93C..1F93E ; Emoji # E3.0 [3] (🤼..🤾) people wrestling..person playing handball -1F93F ; Emoji # E12.0 [1] (🤿) diving mask -1F940..1F945 ; Emoji # E3.0 [6] (🥀..🥅) wilted flower..goal net -1F947..1F94B ; Emoji # E3.0 [5] (🥇..🥋) 1st place medal..martial arts uniform -1F94C ; Emoji # E5.0 [1] (🥌) curling stone -1F94D..1F94F ; Emoji # E11.0 [3] (ðŸ¥..ðŸ¥) lacrosse..flying disc -1F950..1F95E ; Emoji # E3.0 [15] (ðŸ¥..🥞) croissant..pancakes -1F95F..1F96B ; Emoji # E5.0 [13] (🥟..🥫) dumpling..canned food -1F96C..1F970 ; Emoji # E11.0 [5] (🥬..🥰) leafy green..smiling face with hearts -1F971 ; Emoji # E12.0 [1] (🥱) yawning face -1F972 ; Emoji # E13.0 [1] (🥲) smiling face with tear -1F973..1F976 ; Emoji # E11.0 [4] (🥳..🥶) partying face..cold face -1F977..1F978 ; Emoji # E13.0 [2] (🥷..🥸) ninja..disguised face -1F979 ; Emoji # E14.0 [1] (🥹) face holding back tears -1F97A ; Emoji # E11.0 [1] (🥺) pleading face -1F97B ; Emoji # E12.0 [1] (🥻) sari -1F97C..1F97F ; Emoji # E11.0 [4] (🥼..🥿) lab coat..flat shoe -1F980..1F984 ; Emoji # E1.0 [5] (🦀..🦄) crab..unicorn -1F985..1F991 ; Emoji # E3.0 [13] (🦅..🦑) eagle..squid -1F992..1F997 ; Emoji # E5.0 [6] (🦒..🦗) giraffe..cricket -1F998..1F9A2 ; Emoji # E11.0 [11] (🦘..🦢) kangaroo..swan -1F9A3..1F9A4 ; Emoji # E13.0 [2] (🦣..🦤) mammoth..dodo -1F9A5..1F9AA ; Emoji # E12.0 [6] (🦥..🦪) sloth..oyster -1F9AB..1F9AD ; Emoji # E13.0 [3] (🦫..ðŸ¦) beaver..seal -1F9AE..1F9AF ; Emoji # E12.0 [2] (🦮..🦯) guide dog..white cane -1F9B0..1F9B9 ; Emoji # E11.0 [10] (🦰..🦹) red hair..supervillain -1F9BA..1F9BF ; Emoji # E12.0 [6] (🦺..🦿) safety vest..mechanical leg -1F9C0 ; Emoji # E1.0 [1] (🧀) cheese wedge -1F9C1..1F9C2 ; Emoji # E11.0 [2] (ðŸ§..🧂) cupcake..salt -1F9C3..1F9CA ; Emoji # E12.0 [8] (🧃..🧊) beverage box..ice -1F9CB ; Emoji # E13.0 [1] (🧋) bubble tea -1F9CC ; Emoji # E14.0 [1] (🧌) troll -1F9CD..1F9CF ; Emoji # E12.0 [3] (ðŸ§..ðŸ§) person standing..deaf person -1F9D0..1F9E6 ; Emoji # E5.0 [23] (ðŸ§..🧦) face with monocle..socks -1F9E7..1F9FF ; Emoji # E11.0 [25] (🧧..🧿) red envelope..nazar amulet -1FA70..1FA73 ; Emoji # E12.0 [4] (🩰..🩳) ballet shoes..shorts -1FA74 ; Emoji # E13.0 [1] (🩴) thong sandal -1FA75..1FA77 ; Emoji # E15.0 [3] (🩵..🩷) light blue heart..pink heart -1FA78..1FA7A ; Emoji # E12.0 [3] (🩸..🩺) drop of blood..stethoscope -1FA7B..1FA7C ; Emoji # E14.0 [2] (🩻..🩼) x-ray..crutch -1FA80..1FA82 ; Emoji # E12.0 [3] (🪀..🪂) yo-yo..parachute -1FA83..1FA86 ; Emoji # E13.0 [4] (🪃..🪆) boomerang..nesting dolls -1FA87..1FA88 ; Emoji # E15.0 [2] (🪇..🪈) maracas..flute -1FA90..1FA95 ; Emoji # E12.0 [6] (ðŸª..🪕) ringed planet..banjo -1FA96..1FAA8 ; Emoji # E13.0 [19] (🪖..🪨) military helmet..rock -1FAA9..1FAAC ; Emoji # E14.0 [4] (🪩..🪬) mirror ball..hamsa -1FAAD..1FAAF ; Emoji # E15.0 [3] (ðŸª..🪯) folding hand fan..khanda -1FAB0..1FAB6 ; Emoji # E13.0 [7] (🪰..🪶) fly..feather -1FAB7..1FABA ; Emoji # E14.0 [4] (🪷..🪺) lotus..nest with eggs -1FABB..1FABD ; Emoji # E15.0 [3] (🪻..🪽) hyacinth..wing -1FABF ; Emoji # E15.0 [1] (🪿) goose -1FAC0..1FAC2 ; Emoji # E13.0 [3] (🫀..🫂) anatomical heart..people hugging -1FAC3..1FAC5 ; Emoji # E14.0 [3] (🫃..🫅) pregnant man..person with crown -1FACE..1FACF ; Emoji # E15.0 [2] (🫎..ðŸ«) moose..donkey -1FAD0..1FAD6 ; Emoji # E13.0 [7] (ðŸ«..🫖) blueberries..teapot -1FAD7..1FAD9 ; Emoji # E14.0 [3] (🫗..🫙) pouring liquid..jar -1FADA..1FADB ; Emoji # E15.0 [2] (🫚..🫛) ginger root..pea pod -1FAE0..1FAE7 ; Emoji # E14.0 [8] (🫠..🫧) melting face..bubbles -1FAE8 ; Emoji # E15.0 [1] (🫨) shaking face -1FAF0..1FAF6 ; Emoji # E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands -1FAF7..1FAF8 ; Emoji # E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand - -# Total elements: 1424 - -# ================================================ - -# All omitted code points have Emoji_Presentation=No - -231A..231B ; Emoji_Presentation # E0.6 [2] (⌚..⌛) watch..hourglass done -23E9..23EC ; Emoji_Presentation # E0.6 [4] (â©..â¬) fast-forward button..fast down button -23F0 ; Emoji_Presentation # E0.6 [1] (â°) alarm clock -23F3 ; Emoji_Presentation # E0.6 [1] (â³) hourglass not done -25FD..25FE ; Emoji_Presentation # E0.6 [2] (â—½..â—¾) white medium-small square..black medium-small square -2614..2615 ; Emoji_Presentation # E0.6 [2] (☔..☕) umbrella with rain drops..hot beverage -2648..2653 ; Emoji_Presentation # E0.6 [12] (♈..♓) Aries..Pisces -267F ; Emoji_Presentation # E0.6 [1] (♿) wheelchair symbol -2693 ; Emoji_Presentation # E0.6 [1] (âš“) anchor -26A1 ; Emoji_Presentation # E0.6 [1] (âš¡) high voltage -26AA..26AB ; Emoji_Presentation # E0.6 [2] (⚪..âš«) white circle..black circle -26BD..26BE ; Emoji_Presentation # E0.6 [2] (âš½..âš¾) soccer ball..baseball -26C4..26C5 ; Emoji_Presentation # E0.6 [2] (⛄..â›…) snowman without snow..sun behind cloud -26CE ; Emoji_Presentation # E0.6 [1] (⛎) Ophiuchus -26D4 ; Emoji_Presentation # E0.6 [1] (â›”) no entry -26EA ; Emoji_Presentation # E0.6 [1] (⛪) church -26F2..26F3 ; Emoji_Presentation # E0.6 [2] (⛲..⛳) fountain..flag in hole -26F5 ; Emoji_Presentation # E0.6 [1] (⛵) sailboat -26FA ; Emoji_Presentation # E0.6 [1] (⛺) tent -26FD ; Emoji_Presentation # E0.6 [1] (⛽) fuel pump -2705 ; Emoji_Presentation # E0.6 [1] (✅) check mark button -270A..270B ; Emoji_Presentation # E0.6 [2] (✊..✋) raised fist..raised hand -2728 ; Emoji_Presentation # E0.6 [1] (✨) sparkles -274C ; Emoji_Presentation # E0.6 [1] (âŒ) cross mark -274E ; Emoji_Presentation # E0.6 [1] (âŽ) cross mark button -2753..2755 ; Emoji_Presentation # E0.6 [3] (â“..â•) red question mark..white exclamation mark -2757 ; Emoji_Presentation # E0.6 [1] (â—) red exclamation mark -2795..2797 ; Emoji_Presentation # E0.6 [3] (âž•..âž—) plus..divide -27B0 ; Emoji_Presentation # E0.6 [1] (âž°) curly loop -27BF ; Emoji_Presentation # E1.0 [1] (âž¿) double curly loop -2B1B..2B1C ; Emoji_Presentation # E0.6 [2] (⬛..⬜) black large square..white large square -2B50 ; Emoji_Presentation # E0.6 [1] (â) star -2B55 ; Emoji_Presentation # E0.6 [1] (â•) hollow red circle -1F004 ; Emoji_Presentation # E0.6 [1] (🀄) mahjong red dragon -1F0CF ; Emoji_Presentation # E0.6 [1] (ðŸƒ) joker -1F18E ; Emoji_Presentation # E0.6 [1] (🆎) AB button (blood type) -1F191..1F19A ; Emoji_Presentation # E0.6 [10] (🆑..🆚) CL button..VS button -1F1E6..1F1FF ; Emoji_Presentation # E0.0 [26] (🇦..🇿) regional indicator symbol letter a..regional indicator symbol letter z -1F201 ; Emoji_Presentation # E0.6 [1] (ðŸˆ) Japanese “here†button -1F21A ; Emoji_Presentation # E0.6 [1] (🈚) Japanese “free of charge†button -1F22F ; Emoji_Presentation # E0.6 [1] (🈯) Japanese “reserved†button -1F232..1F236 ; Emoji_Presentation # E0.6 [5] (🈲..🈶) Japanese “prohibited†button..Japanese “not free of charge†button -1F238..1F23A ; Emoji_Presentation # E0.6 [3] (🈸..🈺) Japanese “application†button..Japanese “open for business†button -1F250..1F251 ; Emoji_Presentation # E0.6 [2] (ðŸ‰..🉑) Japanese “bargain†button..Japanese “acceptable†button -1F300..1F30C ; Emoji_Presentation # E0.6 [13] (🌀..🌌) cyclone..milky way -1F30D..1F30E ; Emoji_Presentation # E0.7 [2] (ðŸŒ..🌎) globe showing Europe-Africa..globe showing Americas -1F30F ; Emoji_Presentation # E0.6 [1] (ðŸŒ) globe showing Asia-Australia -1F310 ; Emoji_Presentation # E1.0 [1] (ðŸŒ) globe with meridians -1F311 ; Emoji_Presentation # E0.6 [1] (🌑) new moon -1F312 ; Emoji_Presentation # E1.0 [1] (🌒) waxing crescent moon -1F313..1F315 ; Emoji_Presentation # E0.6 [3] (🌓..🌕) first quarter moon..full moon -1F316..1F318 ; Emoji_Presentation # E1.0 [3] (🌖..🌘) waning gibbous moon..waning crescent moon -1F319 ; Emoji_Presentation # E0.6 [1] (🌙) crescent moon -1F31A ; Emoji_Presentation # E1.0 [1] (🌚) new moon face -1F31B ; Emoji_Presentation # E0.6 [1] (🌛) first quarter moon face -1F31C ; Emoji_Presentation # E0.7 [1] (🌜) last quarter moon face -1F31D..1F31E ; Emoji_Presentation # E1.0 [2] (ðŸŒ..🌞) full moon face..sun with face -1F31F..1F320 ; Emoji_Presentation # E0.6 [2] (🌟..🌠) glowing star..shooting star -1F32D..1F32F ; Emoji_Presentation # E1.0 [3] (ðŸŒ..🌯) hot dog..burrito -1F330..1F331 ; Emoji_Presentation # E0.6 [2] (🌰..🌱) chestnut..seedling -1F332..1F333 ; Emoji_Presentation # E1.0 [2] (🌲..🌳) evergreen tree..deciduous tree -1F334..1F335 ; Emoji_Presentation # E0.6 [2] (🌴..🌵) palm tree..cactus -1F337..1F34A ; Emoji_Presentation # E0.6 [20] (🌷..ðŸŠ) tulip..tangerine -1F34B ; Emoji_Presentation # E1.0 [1] (ðŸ‹) lemon -1F34C..1F34F ; Emoji_Presentation # E0.6 [4] (ðŸŒ..ðŸ) banana..green apple -1F350 ; Emoji_Presentation # E1.0 [1] (ðŸ) pear -1F351..1F37B ; Emoji_Presentation # E0.6 [43] (ðŸ‘..ðŸ») peach..clinking beer mugs -1F37C ; Emoji_Presentation # E1.0 [1] (ðŸ¼) baby bottle -1F37E..1F37F ; Emoji_Presentation # E1.0 [2] (ðŸ¾..ðŸ¿) bottle with popping cork..popcorn -1F380..1F393 ; Emoji_Presentation # E0.6 [20] (🎀..🎓) ribbon..graduation cap -1F3A0..1F3C4 ; Emoji_Presentation # E0.6 [37] (🎠..ðŸ„) carousel horse..person surfing -1F3C5 ; Emoji_Presentation # E1.0 [1] (ðŸ…) sports medal -1F3C6 ; Emoji_Presentation # E0.6 [1] (ðŸ†) trophy -1F3C7 ; Emoji_Presentation # E1.0 [1] (ðŸ‡) horse racing -1F3C8 ; Emoji_Presentation # E0.6 [1] (ðŸˆ) american football -1F3C9 ; Emoji_Presentation # E1.0 [1] (ðŸ‰) rugby football -1F3CA ; Emoji_Presentation # E0.6 [1] (ðŸŠ) person swimming -1F3CF..1F3D3 ; Emoji_Presentation # E1.0 [5] (ðŸ..ðŸ“) cricket game..ping pong -1F3E0..1F3E3 ; Emoji_Presentation # E0.6 [4] (ðŸ ..ðŸ£) house..Japanese post office -1F3E4 ; Emoji_Presentation # E1.0 [1] (ðŸ¤) post office -1F3E5..1F3F0 ; Emoji_Presentation # E0.6 [12] (ðŸ¥..ðŸ°) hospital..castle -1F3F4 ; Emoji_Presentation # E1.0 [1] (ðŸ´) black flag -1F3F8..1F407 ; Emoji_Presentation # E1.0 [16] (ðŸ¸..ðŸ‡) badminton..rabbit -1F408 ; Emoji_Presentation # E0.7 [1] (ðŸˆ) cat -1F409..1F40B ; Emoji_Presentation # E1.0 [3] (ðŸ‰..ðŸ‹) dragon..whale -1F40C..1F40E ; Emoji_Presentation # E0.6 [3] (ðŸŒ..ðŸŽ) snail..horse -1F40F..1F410 ; Emoji_Presentation # E1.0 [2] (ðŸ..ðŸ) ram..goat -1F411..1F412 ; Emoji_Presentation # E0.6 [2] (ðŸ‘..ðŸ’) ewe..monkey -1F413 ; Emoji_Presentation # E1.0 [1] (ðŸ“) rooster -1F414 ; Emoji_Presentation # E0.6 [1] (ðŸ”) chicken -1F415 ; Emoji_Presentation # E0.7 [1] (ðŸ•) dog -1F416 ; Emoji_Presentation # E1.0 [1] (ðŸ–) pig -1F417..1F429 ; Emoji_Presentation # E0.6 [19] (ðŸ—..ðŸ©) boar..poodle -1F42A ; Emoji_Presentation # E1.0 [1] (ðŸª) camel -1F42B..1F43E ; Emoji_Presentation # E0.6 [20] (ðŸ«..ðŸ¾) two-hump camel..paw prints -1F440 ; Emoji_Presentation # E0.6 [1] (👀) eyes -1F442..1F464 ; Emoji_Presentation # E0.6 [35] (👂..👤) ear..bust in silhouette -1F465 ; Emoji_Presentation # E1.0 [1] (👥) busts in silhouette -1F466..1F46B ; Emoji_Presentation # E0.6 [6] (👦..👫) boy..woman and man holding hands -1F46C..1F46D ; Emoji_Presentation # E1.0 [2] (👬..ðŸ‘) men holding hands..women holding hands -1F46E..1F4AC ; Emoji_Presentation # E0.6 [63] (👮..💬) police officer..speech balloon -1F4AD ; Emoji_Presentation # E1.0 [1] (ðŸ’) thought balloon -1F4AE..1F4B5 ; Emoji_Presentation # E0.6 [8] (💮..💵) white flower..dollar banknote -1F4B6..1F4B7 ; Emoji_Presentation # E1.0 [2] (💶..💷) euro banknote..pound banknote -1F4B8..1F4EB ; Emoji_Presentation # E0.6 [52] (💸..📫) money with wings..closed mailbox with raised flag -1F4EC..1F4ED ; Emoji_Presentation # E0.7 [2] (📬..ðŸ“) open mailbox with raised flag..open mailbox with lowered flag -1F4EE ; Emoji_Presentation # E0.6 [1] (📮) postbox -1F4EF ; Emoji_Presentation # E1.0 [1] (📯) postal horn -1F4F0..1F4F4 ; Emoji_Presentation # E0.6 [5] (📰..📴) newspaper..mobile phone off -1F4F5 ; Emoji_Presentation # E1.0 [1] (📵) no mobile phones -1F4F6..1F4F7 ; Emoji_Presentation # E0.6 [2] (📶..📷) antenna bars..camera -1F4F8 ; Emoji_Presentation # E1.0 [1] (📸) camera with flash -1F4F9..1F4FC ; Emoji_Presentation # E0.6 [4] (📹..📼) video camera..videocassette -1F4FF..1F502 ; Emoji_Presentation # E1.0 [4] (📿..🔂) prayer beads..repeat single button -1F503 ; Emoji_Presentation # E0.6 [1] (🔃) clockwise vertical arrows -1F504..1F507 ; Emoji_Presentation # E1.0 [4] (🔄..🔇) counterclockwise arrows button..muted speaker -1F508 ; Emoji_Presentation # E0.7 [1] (🔈) speaker low volume -1F509 ; Emoji_Presentation # E1.0 [1] (🔉) speaker medium volume -1F50A..1F514 ; Emoji_Presentation # E0.6 [11] (🔊..🔔) speaker high volume..bell -1F515 ; Emoji_Presentation # E1.0 [1] (🔕) bell with slash -1F516..1F52B ; Emoji_Presentation # E0.6 [22] (🔖..🔫) bookmark..water pistol -1F52C..1F52D ; Emoji_Presentation # E1.0 [2] (🔬..ðŸ”) microscope..telescope -1F52E..1F53D ; Emoji_Presentation # E0.6 [16] (🔮..🔽) crystal ball..downwards button -1F54B..1F54E ; Emoji_Presentation # E1.0 [4] (🕋..🕎) kaaba..menorah -1F550..1F55B ; Emoji_Presentation # E0.6 [12] (ðŸ•..🕛) one o’clock..twelve o’clock -1F55C..1F567 ; Emoji_Presentation # E0.7 [12] (🕜..🕧) one-thirty..twelve-thirty -1F57A ; Emoji_Presentation # E3.0 [1] (🕺) man dancing -1F595..1F596 ; Emoji_Presentation # E1.0 [2] (🖕..🖖) middle finger..vulcan salute -1F5A4 ; Emoji_Presentation # E3.0 [1] (🖤) black heart -1F5FB..1F5FF ; Emoji_Presentation # E0.6 [5] (🗻..🗿) mount fuji..moai -1F600 ; Emoji_Presentation # E1.0 [1] (😀) grinning face -1F601..1F606 ; Emoji_Presentation # E0.6 [6] (ðŸ˜..😆) beaming face with smiling eyes..grinning squinting face -1F607..1F608 ; Emoji_Presentation # E1.0 [2] (😇..😈) smiling face with halo..smiling face with horns -1F609..1F60D ; Emoji_Presentation # E0.6 [5] (😉..ðŸ˜) winking face..smiling face with heart-eyes -1F60E ; Emoji_Presentation # E1.0 [1] (😎) smiling face with sunglasses -1F60F ; Emoji_Presentation # E0.6 [1] (ðŸ˜) smirking face -1F610 ; Emoji_Presentation # E0.7 [1] (ðŸ˜) neutral face -1F611 ; Emoji_Presentation # E1.0 [1] (😑) expressionless face -1F612..1F614 ; Emoji_Presentation # E0.6 [3] (😒..😔) unamused face..pensive face -1F615 ; Emoji_Presentation # E1.0 [1] (😕) confused face -1F616 ; Emoji_Presentation # E0.6 [1] (😖) confounded face -1F617 ; Emoji_Presentation # E1.0 [1] (😗) kissing face -1F618 ; Emoji_Presentation # E0.6 [1] (😘) face blowing a kiss -1F619 ; Emoji_Presentation # E1.0 [1] (😙) kissing face with smiling eyes -1F61A ; Emoji_Presentation # E0.6 [1] (😚) kissing face with closed eyes -1F61B ; Emoji_Presentation # E1.0 [1] (😛) face with tongue -1F61C..1F61E ; Emoji_Presentation # E0.6 [3] (😜..😞) winking face with tongue..disappointed face -1F61F ; Emoji_Presentation # E1.0 [1] (😟) worried face -1F620..1F625 ; Emoji_Presentation # E0.6 [6] (😠..😥) angry face..sad but relieved face -1F626..1F627 ; Emoji_Presentation # E1.0 [2] (😦..😧) frowning face with open mouth..anguished face -1F628..1F62B ; Emoji_Presentation # E0.6 [4] (😨..😫) fearful face..tired face -1F62C ; Emoji_Presentation # E1.0 [1] (😬) grimacing face -1F62D ; Emoji_Presentation # E0.6 [1] (ðŸ˜) loudly crying face -1F62E..1F62F ; Emoji_Presentation # E1.0 [2] (😮..😯) face with open mouth..hushed face -1F630..1F633 ; Emoji_Presentation # E0.6 [4] (😰..😳) anxious face with sweat..flushed face -1F634 ; Emoji_Presentation # E1.0 [1] (😴) sleeping face -1F635 ; Emoji_Presentation # E0.6 [1] (😵) face with crossed-out eyes -1F636 ; Emoji_Presentation # E1.0 [1] (😶) face without mouth -1F637..1F640 ; Emoji_Presentation # E0.6 [10] (😷..🙀) face with medical mask..weary cat -1F641..1F644 ; Emoji_Presentation # E1.0 [4] (ðŸ™..🙄) slightly frowning face..face with rolling eyes -1F645..1F64F ; Emoji_Presentation # E0.6 [11] (🙅..ðŸ™) person gesturing NO..folded hands -1F680 ; Emoji_Presentation # E0.6 [1] (🚀) rocket -1F681..1F682 ; Emoji_Presentation # E1.0 [2] (ðŸš..🚂) helicopter..locomotive -1F683..1F685 ; Emoji_Presentation # E0.6 [3] (🚃..🚅) railway car..bullet train -1F686 ; Emoji_Presentation # E1.0 [1] (🚆) train -1F687 ; Emoji_Presentation # E0.6 [1] (🚇) metro -1F688 ; Emoji_Presentation # E1.0 [1] (🚈) light rail -1F689 ; Emoji_Presentation # E0.6 [1] (🚉) station -1F68A..1F68B ; Emoji_Presentation # E1.0 [2] (🚊..🚋) tram..tram car -1F68C ; Emoji_Presentation # E0.6 [1] (🚌) bus -1F68D ; Emoji_Presentation # E0.7 [1] (ðŸš) oncoming bus -1F68E ; Emoji_Presentation # E1.0 [1] (🚎) trolleybus -1F68F ; Emoji_Presentation # E0.6 [1] (ðŸš) bus stop -1F690 ; Emoji_Presentation # E1.0 [1] (ðŸš) minibus -1F691..1F693 ; Emoji_Presentation # E0.6 [3] (🚑..🚓) ambulance..police car -1F694 ; Emoji_Presentation # E0.7 [1] (🚔) oncoming police car -1F695 ; Emoji_Presentation # E0.6 [1] (🚕) taxi -1F696 ; Emoji_Presentation # E1.0 [1] (🚖) oncoming taxi -1F697 ; Emoji_Presentation # E0.6 [1] (🚗) automobile -1F698 ; Emoji_Presentation # E0.7 [1] (🚘) oncoming automobile -1F699..1F69A ; Emoji_Presentation # E0.6 [2] (🚙..🚚) sport utility vehicle..delivery truck -1F69B..1F6A1 ; Emoji_Presentation # E1.0 [7] (🚛..🚡) articulated lorry..aerial tramway -1F6A2 ; Emoji_Presentation # E0.6 [1] (🚢) ship -1F6A3 ; Emoji_Presentation # E1.0 [1] (🚣) person rowing boat -1F6A4..1F6A5 ; Emoji_Presentation # E0.6 [2] (🚤..🚥) speedboat..horizontal traffic light -1F6A6 ; Emoji_Presentation # E1.0 [1] (🚦) vertical traffic light -1F6A7..1F6AD ; Emoji_Presentation # E0.6 [7] (🚧..ðŸš) construction..no smoking -1F6AE..1F6B1 ; Emoji_Presentation # E1.0 [4] (🚮..🚱) litter in bin sign..non-potable water -1F6B2 ; Emoji_Presentation # E0.6 [1] (🚲) bicycle -1F6B3..1F6B5 ; Emoji_Presentation # E1.0 [3] (🚳..🚵) no bicycles..person mountain biking -1F6B6 ; Emoji_Presentation # E0.6 [1] (🚶) person walking -1F6B7..1F6B8 ; Emoji_Presentation # E1.0 [2] (🚷..🚸) no pedestrians..children crossing -1F6B9..1F6BE ; Emoji_Presentation # E0.6 [6] (🚹..🚾) men’s room..water closet -1F6BF ; Emoji_Presentation # E1.0 [1] (🚿) shower -1F6C0 ; Emoji_Presentation # E0.6 [1] (🛀) person taking bath -1F6C1..1F6C5 ; Emoji_Presentation # E1.0 [5] (ðŸ›..🛅) bathtub..left luggage -1F6CC ; Emoji_Presentation # E1.0 [1] (🛌) person in bed -1F6D0 ; Emoji_Presentation # E1.0 [1] (ðŸ›) place of worship -1F6D1..1F6D2 ; Emoji_Presentation # E3.0 [2] (🛑..🛒) stop sign..shopping cart -1F6D5 ; Emoji_Presentation # E12.0 [1] (🛕) hindu temple -1F6D6..1F6D7 ; Emoji_Presentation # E13.0 [2] (🛖..🛗) hut..elevator -1F6DC ; Emoji_Presentation # E15.0 [1] (🛜) wireless -1F6DD..1F6DF ; Emoji_Presentation # E14.0 [3] (ðŸ›..🛟) playground slide..ring buoy -1F6EB..1F6EC ; Emoji_Presentation # E1.0 [2] (🛫..🛬) airplane departure..airplane arrival -1F6F4..1F6F6 ; Emoji_Presentation # E3.0 [3] (🛴..🛶) kick scooter..canoe -1F6F7..1F6F8 ; Emoji_Presentation # E5.0 [2] (🛷..🛸) sled..flying saucer -1F6F9 ; Emoji_Presentation # E11.0 [1] (🛹) skateboard -1F6FA ; Emoji_Presentation # E12.0 [1] (🛺) auto rickshaw -1F6FB..1F6FC ; Emoji_Presentation # E13.0 [2] (🛻..🛼) pickup truck..roller skate -1F7E0..1F7EB ; Emoji_Presentation # E12.0 [12] (🟠..🟫) orange circle..brown square -1F7F0 ; Emoji_Presentation # E14.0 [1] (🟰) heavy equals sign -1F90C ; Emoji_Presentation # E13.0 [1] (🤌) pinched fingers -1F90D..1F90F ; Emoji_Presentation # E12.0 [3] (ðŸ¤..ðŸ¤) white heart..pinching hand -1F910..1F918 ; Emoji_Presentation # E1.0 [9] (ðŸ¤..🤘) zipper-mouth face..sign of the horns -1F919..1F91E ; Emoji_Presentation # E3.0 [6] (🤙..🤞) call me hand..crossed fingers -1F91F ; Emoji_Presentation # E5.0 [1] (🤟) love-you gesture -1F920..1F927 ; Emoji_Presentation # E3.0 [8] (🤠..🤧) cowboy hat face..sneezing face -1F928..1F92F ; Emoji_Presentation # E5.0 [8] (🤨..🤯) face with raised eyebrow..exploding head -1F930 ; Emoji_Presentation # E3.0 [1] (🤰) pregnant woman -1F931..1F932 ; Emoji_Presentation # E5.0 [2] (🤱..🤲) breast-feeding..palms up together -1F933..1F93A ; Emoji_Presentation # E3.0 [8] (🤳..🤺) selfie..person fencing -1F93C..1F93E ; Emoji_Presentation # E3.0 [3] (🤼..🤾) people wrestling..person playing handball -1F93F ; Emoji_Presentation # E12.0 [1] (🤿) diving mask -1F940..1F945 ; Emoji_Presentation # E3.0 [6] (🥀..🥅) wilted flower..goal net -1F947..1F94B ; Emoji_Presentation # E3.0 [5] (🥇..🥋) 1st place medal..martial arts uniform -1F94C ; Emoji_Presentation # E5.0 [1] (🥌) curling stone -1F94D..1F94F ; Emoji_Presentation # E11.0 [3] (ðŸ¥..ðŸ¥) lacrosse..flying disc -1F950..1F95E ; Emoji_Presentation # E3.0 [15] (ðŸ¥..🥞) croissant..pancakes -1F95F..1F96B ; Emoji_Presentation # E5.0 [13] (🥟..🥫) dumpling..canned food -1F96C..1F970 ; Emoji_Presentation # E11.0 [5] (🥬..🥰) leafy green..smiling face with hearts -1F971 ; Emoji_Presentation # E12.0 [1] (🥱) yawning face -1F972 ; Emoji_Presentation # E13.0 [1] (🥲) smiling face with tear -1F973..1F976 ; Emoji_Presentation # E11.0 [4] (🥳..🥶) partying face..cold face -1F977..1F978 ; Emoji_Presentation # E13.0 [2] (🥷..🥸) ninja..disguised face -1F979 ; Emoji_Presentation # E14.0 [1] (🥹) face holding back tears -1F97A ; Emoji_Presentation # E11.0 [1] (🥺) pleading face -1F97B ; Emoji_Presentation # E12.0 [1] (🥻) sari -1F97C..1F97F ; Emoji_Presentation # E11.0 [4] (🥼..🥿) lab coat..flat shoe -1F980..1F984 ; Emoji_Presentation # E1.0 [5] (🦀..🦄) crab..unicorn -1F985..1F991 ; Emoji_Presentation # E3.0 [13] (🦅..🦑) eagle..squid -1F992..1F997 ; Emoji_Presentation # E5.0 [6] (🦒..🦗) giraffe..cricket -1F998..1F9A2 ; Emoji_Presentation # E11.0 [11] (🦘..🦢) kangaroo..swan -1F9A3..1F9A4 ; Emoji_Presentation # E13.0 [2] (🦣..🦤) mammoth..dodo -1F9A5..1F9AA ; Emoji_Presentation # E12.0 [6] (🦥..🦪) sloth..oyster -1F9AB..1F9AD ; Emoji_Presentation # E13.0 [3] (🦫..ðŸ¦) beaver..seal -1F9AE..1F9AF ; Emoji_Presentation # E12.0 [2] (🦮..🦯) guide dog..white cane -1F9B0..1F9B9 ; Emoji_Presentation # E11.0 [10] (🦰..🦹) red hair..supervillain -1F9BA..1F9BF ; Emoji_Presentation # E12.0 [6] (🦺..🦿) safety vest..mechanical leg -1F9C0 ; Emoji_Presentation # E1.0 [1] (🧀) cheese wedge -1F9C1..1F9C2 ; Emoji_Presentation # E11.0 [2] (ðŸ§..🧂) cupcake..salt -1F9C3..1F9CA ; Emoji_Presentation # E12.0 [8] (🧃..🧊) beverage box..ice -1F9CB ; Emoji_Presentation # E13.0 [1] (🧋) bubble tea -1F9CC ; Emoji_Presentation # E14.0 [1] (🧌) troll -1F9CD..1F9CF ; Emoji_Presentation # E12.0 [3] (ðŸ§..ðŸ§) person standing..deaf person -1F9D0..1F9E6 ; Emoji_Presentation # E5.0 [23] (ðŸ§..🧦) face with monocle..socks -1F9E7..1F9FF ; Emoji_Presentation # E11.0 [25] (🧧..🧿) red envelope..nazar amulet -1FA70..1FA73 ; Emoji_Presentation # E12.0 [4] (🩰..🩳) ballet shoes..shorts -1FA74 ; Emoji_Presentation # E13.0 [1] (🩴) thong sandal -1FA75..1FA77 ; Emoji_Presentation # E15.0 [3] (🩵..🩷) light blue heart..pink heart -1FA78..1FA7A ; Emoji_Presentation # E12.0 [3] (🩸..🩺) drop of blood..stethoscope -1FA7B..1FA7C ; Emoji_Presentation # E14.0 [2] (🩻..🩼) x-ray..crutch -1FA80..1FA82 ; Emoji_Presentation # E12.0 [3] (🪀..🪂) yo-yo..parachute -1FA83..1FA86 ; Emoji_Presentation # E13.0 [4] (🪃..🪆) boomerang..nesting dolls -1FA87..1FA88 ; Emoji_Presentation # E15.0 [2] (🪇..🪈) maracas..flute -1FA90..1FA95 ; Emoji_Presentation # E12.0 [6] (ðŸª..🪕) ringed planet..banjo -1FA96..1FAA8 ; Emoji_Presentation # E13.0 [19] (🪖..🪨) military helmet..rock -1FAA9..1FAAC ; Emoji_Presentation # E14.0 [4] (🪩..🪬) mirror ball..hamsa -1FAAD..1FAAF ; Emoji_Presentation # E15.0 [3] (ðŸª..🪯) folding hand fan..khanda -1FAB0..1FAB6 ; Emoji_Presentation # E13.0 [7] (🪰..🪶) fly..feather -1FAB7..1FABA ; Emoji_Presentation # E14.0 [4] (🪷..🪺) lotus..nest with eggs -1FABB..1FABD ; Emoji_Presentation # E15.0 [3] (🪻..🪽) hyacinth..wing -1FABF ; Emoji_Presentation # E15.0 [1] (🪿) goose -1FAC0..1FAC2 ; Emoji_Presentation # E13.0 [3] (🫀..🫂) anatomical heart..people hugging -1FAC3..1FAC5 ; Emoji_Presentation # E14.0 [3] (🫃..🫅) pregnant man..person with crown -1FACE..1FACF ; Emoji_Presentation # E15.0 [2] (🫎..ðŸ«) moose..donkey -1FAD0..1FAD6 ; Emoji_Presentation # E13.0 [7] (ðŸ«..🫖) blueberries..teapot -1FAD7..1FAD9 ; Emoji_Presentation # E14.0 [3] (🫗..🫙) pouring liquid..jar -1FADA..1FADB ; Emoji_Presentation # E15.0 [2] (🫚..🫛) ginger root..pea pod -1FAE0..1FAE7 ; Emoji_Presentation # E14.0 [8] (🫠..🫧) melting face..bubbles -1FAE8 ; Emoji_Presentation # E15.0 [1] (🫨) shaking face -1FAF0..1FAF6 ; Emoji_Presentation # E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands -1FAF7..1FAF8 ; Emoji_Presentation # E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand - -# Total elements: 1205 - -# ================================================ - -# All omitted code points have Emoji_Modifier=No - -1F3FB..1F3FF ; Emoji_Modifier # E1.0 [5] (ðŸ»..ðŸ¿) light skin tone..dark skin tone - -# Total elements: 5 - -# ================================================ - -# All omitted code points have Emoji_Modifier_Base=No - -261D ; Emoji_Modifier_Base # E0.6 [1] (â˜ï¸) index pointing up -26F9 ; Emoji_Modifier_Base # E0.7 [1] (⛹ï¸) person bouncing ball -270A..270C ; Emoji_Modifier_Base # E0.6 [3] (✊..✌ï¸) raised fist..victory hand -270D ; Emoji_Modifier_Base # E0.7 [1] (âœï¸) writing hand -1F385 ; Emoji_Modifier_Base # E0.6 [1] (🎅) Santa Claus -1F3C2..1F3C4 ; Emoji_Modifier_Base # E0.6 [3] (ðŸ‚..ðŸ„) snowboarder..person surfing -1F3C7 ; Emoji_Modifier_Base # E1.0 [1] (ðŸ‡) horse racing -1F3CA ; Emoji_Modifier_Base # E0.6 [1] (ðŸŠ) person swimming -1F3CB..1F3CC ; Emoji_Modifier_Base # E0.7 [2] (ðŸ‹ï¸..ðŸŒï¸) person lifting weights..person golfing -1F442..1F443 ; Emoji_Modifier_Base # E0.6 [2] (👂..👃) ear..nose -1F446..1F450 ; Emoji_Modifier_Base # E0.6 [11] (👆..ðŸ‘) backhand index pointing up..open hands -1F466..1F46B ; Emoji_Modifier_Base # E0.6 [6] (👦..👫) boy..woman and man holding hands -1F46C..1F46D ; Emoji_Modifier_Base # E1.0 [2] (👬..ðŸ‘) men holding hands..women holding hands -1F46E..1F478 ; Emoji_Modifier_Base # E0.6 [11] (👮..👸) police officer..princess -1F47C ; Emoji_Modifier_Base # E0.6 [1] (👼) baby angel -1F481..1F483 ; Emoji_Modifier_Base # E0.6 [3] (ðŸ’..💃) person tipping hand..woman dancing -1F485..1F487 ; Emoji_Modifier_Base # E0.6 [3] (💅..💇) nail polish..person getting haircut -1F48F ; Emoji_Modifier_Base # E0.6 [1] (ðŸ’) kiss -1F491 ; Emoji_Modifier_Base # E0.6 [1] (💑) couple with heart -1F4AA ; Emoji_Modifier_Base # E0.6 [1] (💪) flexed biceps -1F574..1F575 ; Emoji_Modifier_Base # E0.7 [2] (🕴ï¸..🕵ï¸) person in suit levitating..detective -1F57A ; Emoji_Modifier_Base # E3.0 [1] (🕺) man dancing -1F590 ; Emoji_Modifier_Base # E0.7 [1] (ðŸ–ï¸) hand with fingers splayed -1F595..1F596 ; Emoji_Modifier_Base # E1.0 [2] (🖕..🖖) middle finger..vulcan salute -1F645..1F647 ; Emoji_Modifier_Base # E0.6 [3] (🙅..🙇) person gesturing NO..person bowing -1F64B..1F64F ; Emoji_Modifier_Base # E0.6 [5] (🙋..ðŸ™) person raising hand..folded hands -1F6A3 ; Emoji_Modifier_Base # E1.0 [1] (🚣) person rowing boat -1F6B4..1F6B5 ; Emoji_Modifier_Base # E1.0 [2] (🚴..🚵) person biking..person mountain biking -1F6B6 ; Emoji_Modifier_Base # E0.6 [1] (🚶) person walking -1F6C0 ; Emoji_Modifier_Base # E0.6 [1] (🛀) person taking bath -1F6CC ; Emoji_Modifier_Base # E1.0 [1] (🛌) person in bed -1F90C ; Emoji_Modifier_Base # E13.0 [1] (🤌) pinched fingers -1F90F ; Emoji_Modifier_Base # E12.0 [1] (ðŸ¤) pinching hand -1F918 ; Emoji_Modifier_Base # E1.0 [1] (🤘) sign of the horns -1F919..1F91E ; Emoji_Modifier_Base # E3.0 [6] (🤙..🤞) call me hand..crossed fingers -1F91F ; Emoji_Modifier_Base # E5.0 [1] (🤟) love-you gesture -1F926 ; Emoji_Modifier_Base # E3.0 [1] (🤦) person facepalming -1F930 ; Emoji_Modifier_Base # E3.0 [1] (🤰) pregnant woman -1F931..1F932 ; Emoji_Modifier_Base # E5.0 [2] (🤱..🤲) breast-feeding..palms up together -1F933..1F939 ; Emoji_Modifier_Base # E3.0 [7] (🤳..🤹) selfie..person juggling -1F93C..1F93E ; Emoji_Modifier_Base # E3.0 [3] (🤼..🤾) people wrestling..person playing handball -1F977 ; Emoji_Modifier_Base # E13.0 [1] (🥷) ninja -1F9B5..1F9B6 ; Emoji_Modifier_Base # E11.0 [2] (🦵..🦶) leg..foot -1F9B8..1F9B9 ; Emoji_Modifier_Base # E11.0 [2] (🦸..🦹) superhero..supervillain -1F9BB ; Emoji_Modifier_Base # E12.0 [1] (🦻) ear with hearing aid -1F9CD..1F9CF ; Emoji_Modifier_Base # E12.0 [3] (ðŸ§..ðŸ§) person standing..deaf person -1F9D1..1F9DD ; Emoji_Modifier_Base # E5.0 [13] (🧑..ðŸ§) person..elf -1FAC3..1FAC5 ; Emoji_Modifier_Base # E14.0 [3] (🫃..🫅) pregnant man..person with crown -1FAF0..1FAF6 ; Emoji_Modifier_Base # E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands -1FAF7..1FAF8 ; Emoji_Modifier_Base # E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand - -# Total elements: 134 - -# ================================================ - -# All omitted code points have Emoji_Component=No - -0023 ; Emoji_Component # E0.0 [1] (#ï¸) hash sign -002A ; Emoji_Component # E0.0 [1] (*ï¸) asterisk -0030..0039 ; Emoji_Component # E0.0 [10] (0ï¸..9ï¸) digit zero..digit nine -200D ; Emoji_Component # E0.0 [1] (â€) zero width joiner -20E3 ; Emoji_Component # E0.0 [1] (⃣) combining enclosing keycap -FE0F ; Emoji_Component # E0.0 [1] () VARIATION SELECTOR-16 -1F1E6..1F1FF ; Emoji_Component # E0.0 [26] (🇦..🇿) regional indicator symbol letter a..regional indicator symbol letter z -1F3FB..1F3FF ; Emoji_Component # E1.0 [5] (ðŸ»..ðŸ¿) light skin tone..dark skin tone -1F9B0..1F9B3 ; Emoji_Component # E11.0 [4] (🦰..🦳) red hair..white hair -E0020..E007F ; Emoji_Component # E0.0 [96] (ó € ..ó ¿) tag space..cancel tag - -# Total elements: 146 - -# ================================================ - -# All omitted code points have Extended_Pictographic=No - -00A9 ; Extended_Pictographic# E0.6 [1] (©ï¸) copyright -00AE ; Extended_Pictographic# E0.6 [1] (®ï¸) registered -203C ; Extended_Pictographic# E0.6 [1] (‼ï¸) double exclamation mark -2049 ; Extended_Pictographic# E0.6 [1] (â‰ï¸) exclamation question mark -2122 ; Extended_Pictographic# E0.6 [1] (â„¢ï¸) trade mark -2139 ; Extended_Pictographic# E0.6 [1] (ℹï¸) information -2194..2199 ; Extended_Pictographic# E0.6 [6] (↔ï¸..↙ï¸) left-right arrow..down-left arrow -21A9..21AA ; Extended_Pictographic# E0.6 [2] (↩ï¸..↪ï¸) right arrow curving left..left arrow curving right -231A..231B ; Extended_Pictographic# E0.6 [2] (⌚..⌛) watch..hourglass done -2328 ; Extended_Pictographic# E1.0 [1] (⌨ï¸) keyboard -2388 ; Extended_Pictographic# E0.0 [1] (⎈) HELM SYMBOL -23CF ; Extended_Pictographic# E1.0 [1] (âï¸) eject button -23E9..23EC ; Extended_Pictographic# E0.6 [4] (â©..â¬) fast-forward button..fast down button -23ED..23EE ; Extended_Pictographic# E0.7 [2] (âï¸..â®ï¸) next track button..last track button -23EF ; Extended_Pictographic# E1.0 [1] (â¯ï¸) play or pause button -23F0 ; Extended_Pictographic# E0.6 [1] (â°) alarm clock -23F1..23F2 ; Extended_Pictographic# E1.0 [2] (â±ï¸..â²ï¸) stopwatch..timer clock -23F3 ; Extended_Pictographic# E0.6 [1] (â³) hourglass not done -23F8..23FA ; Extended_Pictographic# E0.7 [3] (â¸ï¸..âºï¸) pause button..record button -24C2 ; Extended_Pictographic# E0.6 [1] (â“‚ï¸) circled M -25AA..25AB ; Extended_Pictographic# E0.6 [2] (â–ªï¸..â–«ï¸) black small square..white small square -25B6 ; Extended_Pictographic# E0.6 [1] (â–¶ï¸) play button -25C0 ; Extended_Pictographic# E0.6 [1] (â—€ï¸) reverse button -25FB..25FE ; Extended_Pictographic# E0.6 [4] (â—»ï¸..â—¾) white medium square..black medium-small square -2600..2601 ; Extended_Pictographic# E0.6 [2] (☀ï¸..â˜ï¸) sun..cloud -2602..2603 ; Extended_Pictographic# E0.7 [2] (☂ï¸..☃ï¸) umbrella..snowman -2604 ; Extended_Pictographic# E1.0 [1] (☄ï¸) comet -2605 ; Extended_Pictographic# E0.0 [1] (★) BLACK STAR -2607..260D ; Extended_Pictographic# E0.0 [7] (☇..â˜) LIGHTNING..OPPOSITION -260E ; Extended_Pictographic# E0.6 [1] (☎ï¸) telephone -260F..2610 ; Extended_Pictographic# E0.0 [2] (â˜..â˜) WHITE TELEPHONE..BALLOT BOX -2611 ; Extended_Pictographic# E0.6 [1] (☑ï¸) check box with check -2612 ; Extended_Pictographic# E0.0 [1] (☒) BALLOT BOX WITH X -2614..2615 ; Extended_Pictographic# E0.6 [2] (☔..☕) umbrella with rain drops..hot beverage -2616..2617 ; Extended_Pictographic# E0.0 [2] (☖..☗) WHITE SHOGI PIECE..BLACK SHOGI PIECE -2618 ; Extended_Pictographic# E1.0 [1] (☘ï¸) shamrock -2619..261C ; Extended_Pictographic# E0.0 [4] (☙..☜) REVERSED ROTATED FLORAL HEART BULLET..WHITE LEFT POINTING INDEX -261D ; Extended_Pictographic# E0.6 [1] (â˜ï¸) index pointing up -261E..261F ; Extended_Pictographic# E0.0 [2] (☞..☟) WHITE RIGHT POINTING INDEX..WHITE DOWN POINTING INDEX -2620 ; Extended_Pictographic# E1.0 [1] (☠ï¸) skull and crossbones -2621 ; Extended_Pictographic# E0.0 [1] (☡) CAUTION SIGN -2622..2623 ; Extended_Pictographic# E1.0 [2] (☢ï¸..☣ï¸) radioactive..biohazard -2624..2625 ; Extended_Pictographic# E0.0 [2] (☤..☥) CADUCEUS..ANKH -2626 ; Extended_Pictographic# E1.0 [1] (☦ï¸) orthodox cross -2627..2629 ; Extended_Pictographic# E0.0 [3] (☧..☩) CHI RHO..CROSS OF JERUSALEM -262A ; Extended_Pictographic# E0.7 [1] (☪ï¸) star and crescent -262B..262D ; Extended_Pictographic# E0.0 [3] (☫..â˜) FARSI SYMBOL..HAMMER AND SICKLE -262E ; Extended_Pictographic# E1.0 [1] (☮ï¸) peace symbol -262F ; Extended_Pictographic# E0.7 [1] (☯ï¸) yin yang -2630..2637 ; Extended_Pictographic# E0.0 [8] (☰..☷) TRIGRAM FOR HEAVEN..TRIGRAM FOR EARTH -2638..2639 ; Extended_Pictographic# E0.7 [2] (☸ï¸..☹ï¸) wheel of dharma..frowning face -263A ; Extended_Pictographic# E0.6 [1] (☺ï¸) smiling face -263B..263F ; Extended_Pictographic# E0.0 [5] (☻..☿) BLACK SMILING FACE..MERCURY -2640 ; Extended_Pictographic# E4.0 [1] (♀ï¸) female sign -2641 ; Extended_Pictographic# E0.0 [1] (â™) EARTH -2642 ; Extended_Pictographic# E4.0 [1] (♂ï¸) male sign -2643..2647 ; Extended_Pictographic# E0.0 [5] (♃..♇) JUPITER..PLUTO -2648..2653 ; Extended_Pictographic# E0.6 [12] (♈..♓) Aries..Pisces -2654..265E ; Extended_Pictographic# E0.0 [11] (â™”..♞) WHITE CHESS KING..BLACK CHESS KNIGHT -265F ; Extended_Pictographic# E11.0 [1] (♟ï¸) chess pawn -2660 ; Extended_Pictographic# E0.6 [1] (â™ ï¸) spade suit -2661..2662 ; Extended_Pictographic# E0.0 [2] (♡..♢) WHITE HEART SUIT..WHITE DIAMOND SUIT -2663 ; Extended_Pictographic# E0.6 [1] (♣ï¸) club suit -2664 ; Extended_Pictographic# E0.0 [1] (♤) WHITE SPADE SUIT -2665..2666 ; Extended_Pictographic# E0.6 [2] (♥ï¸..♦ï¸) heart suit..diamond suit -2667 ; Extended_Pictographic# E0.0 [1] (â™§) WHITE CLUB SUIT -2668 ; Extended_Pictographic# E0.6 [1] (♨ï¸) hot springs -2669..267A ; Extended_Pictographic# E0.0 [18] (♩..♺) QUARTER NOTE..RECYCLING SYMBOL FOR GENERIC MATERIALS -267B ; Extended_Pictographic# E0.6 [1] (â™»ï¸) recycling symbol -267C..267D ; Extended_Pictographic# E0.0 [2] (♼..♽) RECYCLED PAPER SYMBOL..PARTIALLY-RECYCLED PAPER SYMBOL -267E ; Extended_Pictographic# E11.0 [1] (♾ï¸) infinity -267F ; Extended_Pictographic# E0.6 [1] (♿) wheelchair symbol -2680..2685 ; Extended_Pictographic# E0.0 [6] (⚀..âš…) DIE FACE-1..DIE FACE-6 -2690..2691 ; Extended_Pictographic# E0.0 [2] (âš..âš‘) WHITE FLAG..BLACK FLAG -2692 ; Extended_Pictographic# E1.0 [1] (âš’ï¸) hammer and pick -2693 ; Extended_Pictographic# E0.6 [1] (âš“) anchor -2694 ; Extended_Pictographic# E1.0 [1] (âš”ï¸) crossed swords -2695 ; Extended_Pictographic# E4.0 [1] (âš•ï¸) medical symbol -2696..2697 ; Extended_Pictographic# E1.0 [2] (âš–ï¸..âš—ï¸) balance scale..alembic -2698 ; Extended_Pictographic# E0.0 [1] (⚘) FLOWER -2699 ; Extended_Pictographic# E1.0 [1] (âš™ï¸) gear -269A ; Extended_Pictographic# E0.0 [1] (âšš) STAFF OF HERMES -269B..269C ; Extended_Pictographic# E1.0 [2] (âš›ï¸..âšœï¸) atom symbol..fleur-de-lis -269D..269F ; Extended_Pictographic# E0.0 [3] (âš..⚟) OUTLINED WHITE STAR..THREE LINES CONVERGING LEFT -26A0..26A1 ; Extended_Pictographic# E0.6 [2] (âš ï¸..âš¡) warning..high voltage -26A2..26A6 ; Extended_Pictographic# E0.0 [5] (⚢..⚦) DOUBLED FEMALE SIGN..MALE WITH STROKE SIGN -26A7 ; Extended_Pictographic# E13.0 [1] (âš§ï¸) transgender symbol -26A8..26A9 ; Extended_Pictographic# E0.0 [2] (⚨..âš©) VERTICAL MALE WITH STROKE SIGN..HORIZONTAL MALE WITH STROKE SIGN -26AA..26AB ; Extended_Pictographic# E0.6 [2] (⚪..âš«) white circle..black circle -26AC..26AF ; Extended_Pictographic# E0.0 [4] (⚬..⚯) MEDIUM SMALL WHITE CIRCLE..UNMARRIED PARTNERSHIP SYMBOL -26B0..26B1 ; Extended_Pictographic# E1.0 [2] (âš°ï¸..âš±ï¸) coffin..funeral urn -26B2..26BC ; Extended_Pictographic# E0.0 [11] (âš²..âš¼) NEUTER..SESQUIQUADRATE -26BD..26BE ; Extended_Pictographic# E0.6 [2] (âš½..âš¾) soccer ball..baseball -26BF..26C3 ; Extended_Pictographic# E0.0 [5] (âš¿..⛃) SQUARED KEY..BLACK DRAUGHTS KING -26C4..26C5 ; Extended_Pictographic# E0.6 [2] (⛄..â›…) snowman without snow..sun behind cloud -26C6..26C7 ; Extended_Pictographic# E0.0 [2] (⛆..⛇) RAIN..BLACK SNOWMAN -26C8 ; Extended_Pictographic# E0.7 [1] (⛈ï¸) cloud with lightning and rain -26C9..26CD ; Extended_Pictographic# E0.0 [5] (⛉..â›) TURNED WHITE SHOGI PIECE..DISABLED CAR -26CE ; Extended_Pictographic# E0.6 [1] (⛎) Ophiuchus -26CF ; Extended_Pictographic# E0.7 [1] (â›ï¸) pick -26D0 ; Extended_Pictographic# E0.0 [1] (â›) CAR SLIDING -26D1 ; Extended_Pictographic# E0.7 [1] (⛑ï¸) rescue worker’s helmet -26D2 ; Extended_Pictographic# E0.0 [1] (â›’) CIRCLED CROSSING LANES -26D3 ; Extended_Pictographic# E0.7 [1] (⛓ï¸) chains -26D4 ; Extended_Pictographic# E0.6 [1] (â›”) no entry -26D5..26E8 ; Extended_Pictographic# E0.0 [20] (⛕..⛨) ALTERNATE ONE-WAY LEFT WAY TRAFFIC..BLACK CROSS ON SHIELD -26E9 ; Extended_Pictographic# E0.7 [1] (⛩ï¸) shinto shrine -26EA ; Extended_Pictographic# E0.6 [1] (⛪) church -26EB..26EF ; Extended_Pictographic# E0.0 [5] (⛫..⛯) CASTLE..MAP SYMBOL FOR LIGHTHOUSE -26F0..26F1 ; Extended_Pictographic# E0.7 [2] (â›°ï¸..â›±ï¸) mountain..umbrella on ground -26F2..26F3 ; Extended_Pictographic# E0.6 [2] (⛲..⛳) fountain..flag in hole -26F4 ; Extended_Pictographic# E0.7 [1] (â›´ï¸) ferry -26F5 ; Extended_Pictographic# E0.6 [1] (⛵) sailboat -26F6 ; Extended_Pictographic# E0.0 [1] (â›¶) SQUARE FOUR CORNERS -26F7..26F9 ; Extended_Pictographic# E0.7 [3] (â›·ï¸..⛹ï¸) skier..person bouncing ball -26FA ; Extended_Pictographic# E0.6 [1] (⛺) tent -26FB..26FC ; Extended_Pictographic# E0.0 [2] (â›»..⛼) JAPANESE BANK SYMBOL..HEADSTONE GRAVEYARD SYMBOL -26FD ; Extended_Pictographic# E0.6 [1] (⛽) fuel pump -26FE..2701 ; Extended_Pictographic# E0.0 [4] (⛾..âœ) CUP ON BLACK SQUARE..UPPER BLADE SCISSORS -2702 ; Extended_Pictographic# E0.6 [1] (✂ï¸) scissors -2703..2704 ; Extended_Pictographic# E0.0 [2] (✃..✄) LOWER BLADE SCISSORS..WHITE SCISSORS -2705 ; Extended_Pictographic# E0.6 [1] (✅) check mark button -2708..270C ; Extended_Pictographic# E0.6 [5] (✈ï¸..✌ï¸) airplane..victory hand -270D ; Extended_Pictographic# E0.7 [1] (âœï¸) writing hand -270E ; Extended_Pictographic# E0.0 [1] (✎) LOWER RIGHT PENCIL -270F ; Extended_Pictographic# E0.6 [1] (âœï¸) pencil -2710..2711 ; Extended_Pictographic# E0.0 [2] (âœ..✑) UPPER RIGHT PENCIL..WHITE NIB -2712 ; Extended_Pictographic# E0.6 [1] (✒ï¸) black nib -2714 ; Extended_Pictographic# E0.6 [1] (✔ï¸) check mark -2716 ; Extended_Pictographic# E0.6 [1] (✖ï¸) multiply -271D ; Extended_Pictographic# E0.7 [1] (âœï¸) latin cross -2721 ; Extended_Pictographic# E0.7 [1] (✡ï¸) star of David -2728 ; Extended_Pictographic# E0.6 [1] (✨) sparkles -2733..2734 ; Extended_Pictographic# E0.6 [2] (✳ï¸..✴ï¸) eight-spoked asterisk..eight-pointed star -2744 ; Extended_Pictographic# E0.6 [1] (â„ï¸) snowflake -2747 ; Extended_Pictographic# E0.6 [1] (â‡ï¸) sparkle -274C ; Extended_Pictographic# E0.6 [1] (âŒ) cross mark -274E ; Extended_Pictographic# E0.6 [1] (âŽ) cross mark button -2753..2755 ; Extended_Pictographic# E0.6 [3] (â“..â•) red question mark..white exclamation mark -2757 ; Extended_Pictographic# E0.6 [1] (â—) red exclamation mark -2763 ; Extended_Pictographic# E1.0 [1] (â£ï¸) heart exclamation -2764 ; Extended_Pictographic# E0.6 [1] (â¤ï¸) red heart -2765..2767 ; Extended_Pictographic# E0.0 [3] (â¥..â§) ROTATED HEAVY BLACK HEART BULLET..ROTATED FLORAL HEART BULLET -2795..2797 ; Extended_Pictographic# E0.6 [3] (âž•..âž—) plus..divide -27A1 ; Extended_Pictographic# E0.6 [1] (âž¡ï¸) right arrow -27B0 ; Extended_Pictographic# E0.6 [1] (âž°) curly loop -27BF ; Extended_Pictographic# E1.0 [1] (âž¿) double curly loop -2934..2935 ; Extended_Pictographic# E0.6 [2] (⤴ï¸..⤵ï¸) right arrow curving up..right arrow curving down -2B05..2B07 ; Extended_Pictographic# E0.6 [3] (⬅ï¸..⬇ï¸) left arrow..down arrow -2B1B..2B1C ; Extended_Pictographic# E0.6 [2] (⬛..⬜) black large square..white large square -2B50 ; Extended_Pictographic# E0.6 [1] (â) star -2B55 ; Extended_Pictographic# E0.6 [1] (â•) hollow red circle -3030 ; Extended_Pictographic# E0.6 [1] (〰ï¸) wavy dash -303D ; Extended_Pictographic# E0.6 [1] (〽ï¸) part alternation mark -3297 ; Extended_Pictographic# E0.6 [1] (㊗ï¸) Japanese “congratulations†button -3299 ; Extended_Pictographic# E0.6 [1] (㊙ï¸) Japanese “secret†button -1F000..1F003 ; Extended_Pictographic# E0.0 [4] (🀀..🀃) MAHJONG TILE EAST WIND..MAHJONG TILE NORTH WIND -1F004 ; Extended_Pictographic# E0.6 [1] (🀄) mahjong red dragon -1F005..1F0CE ; Extended_Pictographic# E0.0 [202] (🀅..🃎) MAHJONG TILE GREEN DRAGON..PLAYING CARD KING OF DIAMONDS -1F0CF ; Extended_Pictographic# E0.6 [1] (ðŸƒ) joker -1F0D0..1F0FF ; Extended_Pictographic# E0.0 [48] (ðŸƒ..🃿) <reserved-1F0D0>..<reserved-1F0FF> -1F10D..1F10F ; Extended_Pictographic# E0.0 [3] (ðŸ„..ðŸ„) CIRCLED ZERO WITH SLASH..CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH -1F12F ; Extended_Pictographic# E0.0 [1] (🄯) COPYLEFT SYMBOL -1F16C..1F16F ; Extended_Pictographic# E0.0 [4] (🅬..🅯) RAISED MR SIGN..CIRCLED HUMAN FIGURE -1F170..1F171 ; Extended_Pictographic# E0.6 [2] (🅰ï¸..🅱ï¸) A button (blood type)..B button (blood type) -1F17E..1F17F ; Extended_Pictographic# E0.6 [2] (🅾ï¸..🅿ï¸) O button (blood type)..P button -1F18E ; Extended_Pictographic# E0.6 [1] (🆎) AB button (blood type) -1F191..1F19A ; Extended_Pictographic# E0.6 [10] (🆑..🆚) CL button..VS button -1F1AD..1F1E5 ; Extended_Pictographic# E0.0 [57] (ðŸ†..🇥) MASK WORK SYMBOL..<reserved-1F1E5> -1F201..1F202 ; Extended_Pictographic# E0.6 [2] (ðŸˆ..🈂ï¸) Japanese “here†button..Japanese “service charge†button -1F203..1F20F ; Extended_Pictographic# E0.0 [13] (🈃..ðŸˆ) <reserved-1F203>..<reserved-1F20F> -1F21A ; Extended_Pictographic# E0.6 [1] (🈚) Japanese “free of charge†button -1F22F ; Extended_Pictographic# E0.6 [1] (🈯) Japanese “reserved†button -1F232..1F23A ; Extended_Pictographic# E0.6 [9] (🈲..🈺) Japanese “prohibited†button..Japanese “open for business†button -1F23C..1F23F ; Extended_Pictographic# E0.0 [4] (🈼..🈿) <reserved-1F23C>..<reserved-1F23F> -1F249..1F24F ; Extended_Pictographic# E0.0 [7] (🉉..ðŸ‰) <reserved-1F249>..<reserved-1F24F> -1F250..1F251 ; Extended_Pictographic# E0.6 [2] (ðŸ‰..🉑) Japanese “bargain†button..Japanese “acceptable†button -1F252..1F2FF ; Extended_Pictographic# E0.0 [174] (🉒..🋿) <reserved-1F252>..<reserved-1F2FF> -1F300..1F30C ; Extended_Pictographic# E0.6 [13] (🌀..🌌) cyclone..milky way -1F30D..1F30E ; Extended_Pictographic# E0.7 [2] (ðŸŒ..🌎) globe showing Europe-Africa..globe showing Americas -1F30F ; Extended_Pictographic# E0.6 [1] (ðŸŒ) globe showing Asia-Australia -1F310 ; Extended_Pictographic# E1.0 [1] (ðŸŒ) globe with meridians -1F311 ; Extended_Pictographic# E0.6 [1] (🌑) new moon -1F312 ; Extended_Pictographic# E1.0 [1] (🌒) waxing crescent moon -1F313..1F315 ; Extended_Pictographic# E0.6 [3] (🌓..🌕) first quarter moon..full moon -1F316..1F318 ; Extended_Pictographic# E1.0 [3] (🌖..🌘) waning gibbous moon..waning crescent moon -1F319 ; Extended_Pictographic# E0.6 [1] (🌙) crescent moon -1F31A ; Extended_Pictographic# E1.0 [1] (🌚) new moon face -1F31B ; Extended_Pictographic# E0.6 [1] (🌛) first quarter moon face -1F31C ; Extended_Pictographic# E0.7 [1] (🌜) last quarter moon face -1F31D..1F31E ; Extended_Pictographic# E1.0 [2] (ðŸŒ..🌞) full moon face..sun with face -1F31F..1F320 ; Extended_Pictographic# E0.6 [2] (🌟..🌠) glowing star..shooting star -1F321 ; Extended_Pictographic# E0.7 [1] (🌡ï¸) thermometer -1F322..1F323 ; Extended_Pictographic# E0.0 [2] (🌢..🌣) BLACK DROPLET..WHITE SUN -1F324..1F32C ; Extended_Pictographic# E0.7 [9] (🌤ï¸..🌬ï¸) sun behind small cloud..wind face -1F32D..1F32F ; Extended_Pictographic# E1.0 [3] (ðŸŒ..🌯) hot dog..burrito -1F330..1F331 ; Extended_Pictographic# E0.6 [2] (🌰..🌱) chestnut..seedling -1F332..1F333 ; Extended_Pictographic# E1.0 [2] (🌲..🌳) evergreen tree..deciduous tree -1F334..1F335 ; Extended_Pictographic# E0.6 [2] (🌴..🌵) palm tree..cactus -1F336 ; Extended_Pictographic# E0.7 [1] (🌶ï¸) hot pepper -1F337..1F34A ; Extended_Pictographic# E0.6 [20] (🌷..ðŸŠ) tulip..tangerine -1F34B ; Extended_Pictographic# E1.0 [1] (ðŸ‹) lemon -1F34C..1F34F ; Extended_Pictographic# E0.6 [4] (ðŸŒ..ðŸ) banana..green apple -1F350 ; Extended_Pictographic# E1.0 [1] (ðŸ) pear -1F351..1F37B ; Extended_Pictographic# E0.6 [43] (ðŸ‘..ðŸ») peach..clinking beer mugs -1F37C ; Extended_Pictographic# E1.0 [1] (ðŸ¼) baby bottle -1F37D ; Extended_Pictographic# E0.7 [1] (ðŸ½ï¸) fork and knife with plate -1F37E..1F37F ; Extended_Pictographic# E1.0 [2] (ðŸ¾..ðŸ¿) bottle with popping cork..popcorn -1F380..1F393 ; Extended_Pictographic# E0.6 [20] (🎀..🎓) ribbon..graduation cap -1F394..1F395 ; Extended_Pictographic# E0.0 [2] (🎔..🎕) HEART WITH TIP ON THE LEFT..BOUQUET OF FLOWERS -1F396..1F397 ; Extended_Pictographic# E0.7 [2] (🎖ï¸..🎗ï¸) military medal..reminder ribbon -1F398 ; Extended_Pictographic# E0.0 [1] (🎘) MUSICAL KEYBOARD WITH JACKS -1F399..1F39B ; Extended_Pictographic# E0.7 [3] (🎙ï¸..🎛ï¸) studio microphone..control knobs -1F39C..1F39D ; Extended_Pictographic# E0.0 [2] (🎜..ðŸŽ) BEAMED ASCENDING MUSICAL NOTES..BEAMED DESCENDING MUSICAL NOTES -1F39E..1F39F ; Extended_Pictographic# E0.7 [2] (🎞ï¸..🎟ï¸) film frames..admission tickets -1F3A0..1F3C4 ; Extended_Pictographic# E0.6 [37] (🎠..ðŸ„) carousel horse..person surfing -1F3C5 ; Extended_Pictographic# E1.0 [1] (ðŸ…) sports medal -1F3C6 ; Extended_Pictographic# E0.6 [1] (ðŸ†) trophy -1F3C7 ; Extended_Pictographic# E1.0 [1] (ðŸ‡) horse racing -1F3C8 ; Extended_Pictographic# E0.6 [1] (ðŸˆ) american football -1F3C9 ; Extended_Pictographic# E1.0 [1] (ðŸ‰) rugby football -1F3CA ; Extended_Pictographic# E0.6 [1] (ðŸŠ) person swimming -1F3CB..1F3CE ; Extended_Pictographic# E0.7 [4] (ðŸ‹ï¸..ðŸŽï¸) person lifting weights..racing car -1F3CF..1F3D3 ; Extended_Pictographic# E1.0 [5] (ðŸ..ðŸ“) cricket game..ping pong -1F3D4..1F3DF ; Extended_Pictographic# E0.7 [12] (ðŸ”ï¸..ðŸŸï¸) snow-capped mountain..stadium -1F3E0..1F3E3 ; Extended_Pictographic# E0.6 [4] (ðŸ ..ðŸ£) house..Japanese post office -1F3E4 ; Extended_Pictographic# E1.0 [1] (ðŸ¤) post office -1F3E5..1F3F0 ; Extended_Pictographic# E0.6 [12] (ðŸ¥..ðŸ°) hospital..castle -1F3F1..1F3F2 ; Extended_Pictographic# E0.0 [2] (ðŸ±..ðŸ²) WHITE PENNANT..BLACK PENNANT -1F3F3 ; Extended_Pictographic# E0.7 [1] (ðŸ³ï¸) white flag -1F3F4 ; Extended_Pictographic# E1.0 [1] (ðŸ´) black flag -1F3F5 ; Extended_Pictographic# E0.7 [1] (ðŸµï¸) rosette -1F3F6 ; Extended_Pictographic# E0.0 [1] (ðŸ¶) BLACK ROSETTE -1F3F7 ; Extended_Pictographic# E0.7 [1] (ðŸ·ï¸) label -1F3F8..1F3FA ; Extended_Pictographic# E1.0 [3] (ðŸ¸..ðŸº) badminton..amphora -1F400..1F407 ; Extended_Pictographic# E1.0 [8] (ðŸ€..ðŸ‡) rat..rabbit -1F408 ; Extended_Pictographic# E0.7 [1] (ðŸˆ) cat -1F409..1F40B ; Extended_Pictographic# E1.0 [3] (ðŸ‰..ðŸ‹) dragon..whale -1F40C..1F40E ; Extended_Pictographic# E0.6 [3] (ðŸŒ..ðŸŽ) snail..horse -1F40F..1F410 ; Extended_Pictographic# E1.0 [2] (ðŸ..ðŸ) ram..goat -1F411..1F412 ; Extended_Pictographic# E0.6 [2] (ðŸ‘..ðŸ’) ewe..monkey -1F413 ; Extended_Pictographic# E1.0 [1] (ðŸ“) rooster -1F414 ; Extended_Pictographic# E0.6 [1] (ðŸ”) chicken -1F415 ; Extended_Pictographic# E0.7 [1] (ðŸ•) dog -1F416 ; Extended_Pictographic# E1.0 [1] (ðŸ–) pig -1F417..1F429 ; Extended_Pictographic# E0.6 [19] (ðŸ—..ðŸ©) boar..poodle -1F42A ; Extended_Pictographic# E1.0 [1] (ðŸª) camel -1F42B..1F43E ; Extended_Pictographic# E0.6 [20] (ðŸ«..ðŸ¾) two-hump camel..paw prints -1F43F ; Extended_Pictographic# E0.7 [1] (ðŸ¿ï¸) chipmunk -1F440 ; Extended_Pictographic# E0.6 [1] (👀) eyes -1F441 ; Extended_Pictographic# E0.7 [1] (ðŸ‘ï¸) eye -1F442..1F464 ; Extended_Pictographic# E0.6 [35] (👂..👤) ear..bust in silhouette -1F465 ; Extended_Pictographic# E1.0 [1] (👥) busts in silhouette -1F466..1F46B ; Extended_Pictographic# E0.6 [6] (👦..👫) boy..woman and man holding hands -1F46C..1F46D ; Extended_Pictographic# E1.0 [2] (👬..ðŸ‘) men holding hands..women holding hands -1F46E..1F4AC ; Extended_Pictographic# E0.6 [63] (👮..💬) police officer..speech balloon -1F4AD ; Extended_Pictographic# E1.0 [1] (ðŸ’) thought balloon -1F4AE..1F4B5 ; Extended_Pictographic# E0.6 [8] (💮..💵) white flower..dollar banknote -1F4B6..1F4B7 ; Extended_Pictographic# E1.0 [2] (💶..💷) euro banknote..pound banknote -1F4B8..1F4EB ; Extended_Pictographic# E0.6 [52] (💸..📫) money with wings..closed mailbox with raised flag -1F4EC..1F4ED ; Extended_Pictographic# E0.7 [2] (📬..ðŸ“) open mailbox with raised flag..open mailbox with lowered flag -1F4EE ; Extended_Pictographic# E0.6 [1] (📮) postbox -1F4EF ; Extended_Pictographic# E1.0 [1] (📯) postal horn -1F4F0..1F4F4 ; Extended_Pictographic# E0.6 [5] (📰..📴) newspaper..mobile phone off -1F4F5 ; Extended_Pictographic# E1.0 [1] (📵) no mobile phones -1F4F6..1F4F7 ; Extended_Pictographic# E0.6 [2] (📶..📷) antenna bars..camera -1F4F8 ; Extended_Pictographic# E1.0 [1] (📸) camera with flash -1F4F9..1F4FC ; Extended_Pictographic# E0.6 [4] (📹..📼) video camera..videocassette -1F4FD ; Extended_Pictographic# E0.7 [1] (📽ï¸) film projector -1F4FE ; Extended_Pictographic# E0.0 [1] (📾) PORTABLE STEREO -1F4FF..1F502 ; Extended_Pictographic# E1.0 [4] (📿..🔂) prayer beads..repeat single button -1F503 ; Extended_Pictographic# E0.6 [1] (🔃) clockwise vertical arrows -1F504..1F507 ; Extended_Pictographic# E1.0 [4] (🔄..🔇) counterclockwise arrows button..muted speaker -1F508 ; Extended_Pictographic# E0.7 [1] (🔈) speaker low volume -1F509 ; Extended_Pictographic# E1.0 [1] (🔉) speaker medium volume -1F50A..1F514 ; Extended_Pictographic# E0.6 [11] (🔊..🔔) speaker high volume..bell -1F515 ; Extended_Pictographic# E1.0 [1] (🔕) bell with slash -1F516..1F52B ; Extended_Pictographic# E0.6 [22] (🔖..🔫) bookmark..water pistol -1F52C..1F52D ; Extended_Pictographic# E1.0 [2] (🔬..ðŸ”) microscope..telescope -1F52E..1F53D ; Extended_Pictographic# E0.6 [16] (🔮..🔽) crystal ball..downwards button -1F546..1F548 ; Extended_Pictographic# E0.0 [3] (🕆..🕈) WHITE LATIN CROSS..CELTIC CROSS -1F549..1F54A ; Extended_Pictographic# E0.7 [2] (🕉ï¸..🕊ï¸) om..dove -1F54B..1F54E ; Extended_Pictographic# E1.0 [4] (🕋..🕎) kaaba..menorah -1F54F ; Extended_Pictographic# E0.0 [1] (ðŸ•) BOWL OF HYGIEIA -1F550..1F55B ; Extended_Pictographic# E0.6 [12] (ðŸ•..🕛) one o’clock..twelve o’clock -1F55C..1F567 ; Extended_Pictographic# E0.7 [12] (🕜..🕧) one-thirty..twelve-thirty -1F568..1F56E ; Extended_Pictographic# E0.0 [7] (🕨..🕮) RIGHT SPEAKER..BOOK -1F56F..1F570 ; Extended_Pictographic# E0.7 [2] (🕯ï¸..🕰ï¸) candle..mantelpiece clock -1F571..1F572 ; Extended_Pictographic# E0.0 [2] (🕱..🕲) BLACK SKULL AND CROSSBONES..NO PIRACY -1F573..1F579 ; Extended_Pictographic# E0.7 [7] (🕳ï¸..🕹ï¸) hole..joystick -1F57A ; Extended_Pictographic# E3.0 [1] (🕺) man dancing -1F57B..1F586 ; Extended_Pictographic# E0.0 [12] (🕻..🖆) LEFT HAND TELEPHONE RECEIVER..PEN OVER STAMPED ENVELOPE -1F587 ; Extended_Pictographic# E0.7 [1] (🖇ï¸) linked paperclips -1F588..1F589 ; Extended_Pictographic# E0.0 [2] (🖈..🖉) BLACK PUSHPIN..LOWER LEFT PENCIL -1F58A..1F58D ; Extended_Pictographic# E0.7 [4] (🖊ï¸..ðŸ–ï¸) pen..crayon -1F58E..1F58F ; Extended_Pictographic# E0.0 [2] (🖎..ðŸ–) LEFT WRITING HAND..TURNED OK HAND SIGN -1F590 ; Extended_Pictographic# E0.7 [1] (ðŸ–ï¸) hand with fingers splayed -1F591..1F594 ; Extended_Pictographic# E0.0 [4] (🖑..🖔) REVERSED RAISED HAND WITH FINGERS SPLAYED..REVERSED VICTORY HAND -1F595..1F596 ; Extended_Pictographic# E1.0 [2] (🖕..🖖) middle finger..vulcan salute -1F597..1F5A3 ; Extended_Pictographic# E0.0 [13] (🖗..🖣) WHITE DOWN POINTING LEFT HAND INDEX..BLACK DOWN POINTING BACKHAND INDEX -1F5A4 ; Extended_Pictographic# E3.0 [1] (🖤) black heart -1F5A5 ; Extended_Pictographic# E0.7 [1] (🖥ï¸) desktop computer -1F5A6..1F5A7 ; Extended_Pictographic# E0.0 [2] (🖦..🖧) KEYBOARD AND MOUSE..THREE NETWORKED COMPUTERS -1F5A8 ; Extended_Pictographic# E0.7 [1] (🖨ï¸) printer -1F5A9..1F5B0 ; Extended_Pictographic# E0.0 [8] (🖩..🖰) POCKET CALCULATOR..TWO BUTTON MOUSE -1F5B1..1F5B2 ; Extended_Pictographic# E0.7 [2] (🖱ï¸..🖲ï¸) computer mouse..trackball -1F5B3..1F5BB ; Extended_Pictographic# E0.0 [9] (🖳..🖻) OLD PERSONAL COMPUTER..DOCUMENT WITH PICTURE -1F5BC ; Extended_Pictographic# E0.7 [1] (🖼ï¸) framed picture -1F5BD..1F5C1 ; Extended_Pictographic# E0.0 [5] (🖽..ðŸ—) FRAME WITH TILES..OPEN FOLDER -1F5C2..1F5C4 ; Extended_Pictographic# E0.7 [3] (🗂ï¸..🗄ï¸) card index dividers..file cabinet -1F5C5..1F5D0 ; Extended_Pictographic# E0.0 [12] (🗅..ðŸ—) EMPTY NOTE..PAGES -1F5D1..1F5D3 ; Extended_Pictographic# E0.7 [3] (🗑ï¸..🗓ï¸) wastebasket..spiral calendar -1F5D4..1F5DB ; Extended_Pictographic# E0.0 [8] (🗔..🗛) DESKTOP WINDOW..DECREASE FONT SIZE SYMBOL -1F5DC..1F5DE ; Extended_Pictographic# E0.7 [3] (🗜ï¸..🗞ï¸) clamp..rolled-up newspaper -1F5DF..1F5E0 ; Extended_Pictographic# E0.0 [2] (🗟..🗠) PAGE WITH CIRCLED TEXT..STOCK CHART -1F5E1 ; Extended_Pictographic# E0.7 [1] (🗡ï¸) dagger -1F5E2 ; Extended_Pictographic# E0.0 [1] (🗢) LIPS -1F5E3 ; Extended_Pictographic# E0.7 [1] (🗣ï¸) speaking head -1F5E4..1F5E7 ; Extended_Pictographic# E0.0 [4] (🗤..🗧) THREE RAYS ABOVE..THREE RAYS RIGHT -1F5E8 ; Extended_Pictographic# E2.0 [1] (🗨ï¸) left speech bubble -1F5E9..1F5EE ; Extended_Pictographic# E0.0 [6] (🗩..🗮) RIGHT SPEECH BUBBLE..LEFT ANGER BUBBLE -1F5EF ; Extended_Pictographic# E0.7 [1] (🗯ï¸) right anger bubble -1F5F0..1F5F2 ; Extended_Pictographic# E0.0 [3] (🗰..🗲) MOOD BUBBLE..LIGHTNING MOOD -1F5F3 ; Extended_Pictographic# E0.7 [1] (🗳ï¸) ballot box with ballot -1F5F4..1F5F9 ; Extended_Pictographic# E0.0 [6] (🗴..🗹) BALLOT SCRIPT X..BALLOT BOX WITH BOLD CHECK -1F5FA ; Extended_Pictographic# E0.7 [1] (🗺ï¸) world map -1F5FB..1F5FF ; Extended_Pictographic# E0.6 [5] (🗻..🗿) mount fuji..moai -1F600 ; Extended_Pictographic# E1.0 [1] (😀) grinning face -1F601..1F606 ; Extended_Pictographic# E0.6 [6] (ðŸ˜..😆) beaming face with smiling eyes..grinning squinting face -1F607..1F608 ; Extended_Pictographic# E1.0 [2] (😇..😈) smiling face with halo..smiling face with horns -1F609..1F60D ; Extended_Pictographic# E0.6 [5] (😉..ðŸ˜) winking face..smiling face with heart-eyes -1F60E ; Extended_Pictographic# E1.0 [1] (😎) smiling face with sunglasses -1F60F ; Extended_Pictographic# E0.6 [1] (ðŸ˜) smirking face -1F610 ; Extended_Pictographic# E0.7 [1] (ðŸ˜) neutral face -1F611 ; Extended_Pictographic# E1.0 [1] (😑) expressionless face -1F612..1F614 ; Extended_Pictographic# E0.6 [3] (😒..😔) unamused face..pensive face -1F615 ; Extended_Pictographic# E1.0 [1] (😕) confused face -1F616 ; Extended_Pictographic# E0.6 [1] (😖) confounded face -1F617 ; Extended_Pictographic# E1.0 [1] (😗) kissing face -1F618 ; Extended_Pictographic# E0.6 [1] (😘) face blowing a kiss -1F619 ; Extended_Pictographic# E1.0 [1] (😙) kissing face with smiling eyes -1F61A ; Extended_Pictographic# E0.6 [1] (😚) kissing face with closed eyes -1F61B ; Extended_Pictographic# E1.0 [1] (😛) face with tongue -1F61C..1F61E ; Extended_Pictographic# E0.6 [3] (😜..😞) winking face with tongue..disappointed face -1F61F ; Extended_Pictographic# E1.0 [1] (😟) worried face -1F620..1F625 ; Extended_Pictographic# E0.6 [6] (😠..😥) angry face..sad but relieved face -1F626..1F627 ; Extended_Pictographic# E1.0 [2] (😦..😧) frowning face with open mouth..anguished face -1F628..1F62B ; Extended_Pictographic# E0.6 [4] (😨..😫) fearful face..tired face -1F62C ; Extended_Pictographic# E1.0 [1] (😬) grimacing face -1F62D ; Extended_Pictographic# E0.6 [1] (ðŸ˜) loudly crying face -1F62E..1F62F ; Extended_Pictographic# E1.0 [2] (😮..😯) face with open mouth..hushed face -1F630..1F633 ; Extended_Pictographic# E0.6 [4] (😰..😳) anxious face with sweat..flushed face -1F634 ; Extended_Pictographic# E1.0 [1] (😴) sleeping face -1F635 ; Extended_Pictographic# E0.6 [1] (😵) face with crossed-out eyes -1F636 ; Extended_Pictographic# E1.0 [1] (😶) face without mouth -1F637..1F640 ; Extended_Pictographic# E0.6 [10] (😷..🙀) face with medical mask..weary cat -1F641..1F644 ; Extended_Pictographic# E1.0 [4] (ðŸ™..🙄) slightly frowning face..face with rolling eyes -1F645..1F64F ; Extended_Pictographic# E0.6 [11] (🙅..ðŸ™) person gesturing NO..folded hands -1F680 ; Extended_Pictographic# E0.6 [1] (🚀) rocket -1F681..1F682 ; Extended_Pictographic# E1.0 [2] (ðŸš..🚂) helicopter..locomotive -1F683..1F685 ; Extended_Pictographic# E0.6 [3] (🚃..🚅) railway car..bullet train -1F686 ; Extended_Pictographic# E1.0 [1] (🚆) train -1F687 ; Extended_Pictographic# E0.6 [1] (🚇) metro -1F688 ; Extended_Pictographic# E1.0 [1] (🚈) light rail -1F689 ; Extended_Pictographic# E0.6 [1] (🚉) station -1F68A..1F68B ; Extended_Pictographic# E1.0 [2] (🚊..🚋) tram..tram car -1F68C ; Extended_Pictographic# E0.6 [1] (🚌) bus -1F68D ; Extended_Pictographic# E0.7 [1] (ðŸš) oncoming bus -1F68E ; Extended_Pictographic# E1.0 [1] (🚎) trolleybus -1F68F ; Extended_Pictographic# E0.6 [1] (ðŸš) bus stop -1F690 ; Extended_Pictographic# E1.0 [1] (ðŸš) minibus -1F691..1F693 ; Extended_Pictographic# E0.6 [3] (🚑..🚓) ambulance..police car -1F694 ; Extended_Pictographic# E0.7 [1] (🚔) oncoming police car -1F695 ; Extended_Pictographic# E0.6 [1] (🚕) taxi -1F696 ; Extended_Pictographic# E1.0 [1] (🚖) oncoming taxi -1F697 ; Extended_Pictographic# E0.6 [1] (🚗) automobile -1F698 ; Extended_Pictographic# E0.7 [1] (🚘) oncoming automobile -1F699..1F69A ; Extended_Pictographic# E0.6 [2] (🚙..🚚) sport utility vehicle..delivery truck -1F69B..1F6A1 ; Extended_Pictographic# E1.0 [7] (🚛..🚡) articulated lorry..aerial tramway -1F6A2 ; Extended_Pictographic# E0.6 [1] (🚢) ship -1F6A3 ; Extended_Pictographic# E1.0 [1] (🚣) person rowing boat -1F6A4..1F6A5 ; Extended_Pictographic# E0.6 [2] (🚤..🚥) speedboat..horizontal traffic light -1F6A6 ; Extended_Pictographic# E1.0 [1] (🚦) vertical traffic light -1F6A7..1F6AD ; Extended_Pictographic# E0.6 [7] (🚧..ðŸš) construction..no smoking -1F6AE..1F6B1 ; Extended_Pictographic# E1.0 [4] (🚮..🚱) litter in bin sign..non-potable water -1F6B2 ; Extended_Pictographic# E0.6 [1] (🚲) bicycle -1F6B3..1F6B5 ; Extended_Pictographic# E1.0 [3] (🚳..🚵) no bicycles..person mountain biking -1F6B6 ; Extended_Pictographic# E0.6 [1] (🚶) person walking -1F6B7..1F6B8 ; Extended_Pictographic# E1.0 [2] (🚷..🚸) no pedestrians..children crossing -1F6B9..1F6BE ; Extended_Pictographic# E0.6 [6] (🚹..🚾) men’s room..water closet -1F6BF ; Extended_Pictographic# E1.0 [1] (🚿) shower -1F6C0 ; Extended_Pictographic# E0.6 [1] (🛀) person taking bath -1F6C1..1F6C5 ; Extended_Pictographic# E1.0 [5] (ðŸ›..🛅) bathtub..left luggage -1F6C6..1F6CA ; Extended_Pictographic# E0.0 [5] (🛆..🛊) TRIANGLE WITH ROUNDED CORNERS..GIRLS SYMBOL -1F6CB ; Extended_Pictographic# E0.7 [1] (🛋ï¸) couch and lamp -1F6CC ; Extended_Pictographic# E1.0 [1] (🛌) person in bed -1F6CD..1F6CF ; Extended_Pictographic# E0.7 [3] (ðŸ›ï¸..ðŸ›ï¸) shopping bags..bed -1F6D0 ; Extended_Pictographic# E1.0 [1] (ðŸ›) place of worship -1F6D1..1F6D2 ; Extended_Pictographic# E3.0 [2] (🛑..🛒) stop sign..shopping cart -1F6D3..1F6D4 ; Extended_Pictographic# E0.0 [2] (🛓..🛔) STUPA..PAGODA -1F6D5 ; Extended_Pictographic# E12.0 [1] (🛕) hindu temple -1F6D6..1F6D7 ; Extended_Pictographic# E13.0 [2] (🛖..🛗) hut..elevator -1F6D8..1F6DB ; Extended_Pictographic# E0.0 [4] (🛘..🛛) <reserved-1F6D8>..<reserved-1F6DB> -1F6DC ; Extended_Pictographic# E15.0 [1] (🛜) wireless -1F6DD..1F6DF ; Extended_Pictographic# E14.0 [3] (ðŸ›..🛟) playground slide..ring buoy -1F6E0..1F6E5 ; Extended_Pictographic# E0.7 [6] (🛠ï¸..🛥ï¸) hammer and wrench..motor boat -1F6E6..1F6E8 ; Extended_Pictographic# E0.0 [3] (🛦..🛨) UP-POINTING MILITARY AIRPLANE..UP-POINTING SMALL AIRPLANE -1F6E9 ; Extended_Pictographic# E0.7 [1] (🛩ï¸) small airplane -1F6EA ; Extended_Pictographic# E0.0 [1] (🛪) NORTHEAST-POINTING AIRPLANE -1F6EB..1F6EC ; Extended_Pictographic# E1.0 [2] (🛫..🛬) airplane departure..airplane arrival -1F6ED..1F6EF ; Extended_Pictographic# E0.0 [3] (ðŸ›..🛯) <reserved-1F6ED>..<reserved-1F6EF> -1F6F0 ; Extended_Pictographic# E0.7 [1] (🛰ï¸) satellite -1F6F1..1F6F2 ; Extended_Pictographic# E0.0 [2] (🛱..🛲) ONCOMING FIRE ENGINE..DIESEL LOCOMOTIVE -1F6F3 ; Extended_Pictographic# E0.7 [1] (🛳ï¸) passenger ship -1F6F4..1F6F6 ; Extended_Pictographic# E3.0 [3] (🛴..🛶) kick scooter..canoe -1F6F7..1F6F8 ; Extended_Pictographic# E5.0 [2] (🛷..🛸) sled..flying saucer -1F6F9 ; Extended_Pictographic# E11.0 [1] (🛹) skateboard -1F6FA ; Extended_Pictographic# E12.0 [1] (🛺) auto rickshaw -1F6FB..1F6FC ; Extended_Pictographic# E13.0 [2] (🛻..🛼) pickup truck..roller skate -1F6FD..1F6FF ; Extended_Pictographic# E0.0 [3] (🛽..🛿) <reserved-1F6FD>..<reserved-1F6FF> -1F774..1F77F ; Extended_Pictographic# E0.0 [12] (ðŸ´..ðŸ¿) LOT OF FORTUNE..ORCUS -1F7D5..1F7DF ; Extended_Pictographic# E0.0 [11] (🟕..🟟) CIRCLED TRIANGLE..<reserved-1F7DF> -1F7E0..1F7EB ; Extended_Pictographic# E12.0 [12] (🟠..🟫) orange circle..brown square -1F7EC..1F7EF ; Extended_Pictographic# E0.0 [4] (🟬..🟯) <reserved-1F7EC>..<reserved-1F7EF> -1F7F0 ; Extended_Pictographic# E14.0 [1] (🟰) heavy equals sign -1F7F1..1F7FF ; Extended_Pictographic# E0.0 [15] (🟱..🟿) <reserved-1F7F1>..<reserved-1F7FF> -1F80C..1F80F ; Extended_Pictographic# E0.0 [4] (🠌..ðŸ ) <reserved-1F80C>..<reserved-1F80F> -1F848..1F84F ; Extended_Pictographic# E0.0 [8] (🡈..ðŸ¡) <reserved-1F848>..<reserved-1F84F> -1F85A..1F85F ; Extended_Pictographic# E0.0 [6] (🡚..🡟) <reserved-1F85A>..<reserved-1F85F> -1F888..1F88F ; Extended_Pictographic# E0.0 [8] (🢈..ðŸ¢) <reserved-1F888>..<reserved-1F88F> -1F8AE..1F8FF ; Extended_Pictographic# E0.0 [82] (🢮..🣿) <reserved-1F8AE>..<reserved-1F8FF> -1F90C ; Extended_Pictographic# E13.0 [1] (🤌) pinched fingers -1F90D..1F90F ; Extended_Pictographic# E12.0 [3] (ðŸ¤..ðŸ¤) white heart..pinching hand -1F910..1F918 ; Extended_Pictographic# E1.0 [9] (ðŸ¤..🤘) zipper-mouth face..sign of the horns -1F919..1F91E ; Extended_Pictographic# E3.0 [6] (🤙..🤞) call me hand..crossed fingers -1F91F ; Extended_Pictographic# E5.0 [1] (🤟) love-you gesture -1F920..1F927 ; Extended_Pictographic# E3.0 [8] (🤠..🤧) cowboy hat face..sneezing face -1F928..1F92F ; Extended_Pictographic# E5.0 [8] (🤨..🤯) face with raised eyebrow..exploding head -1F930 ; Extended_Pictographic# E3.0 [1] (🤰) pregnant woman -1F931..1F932 ; Extended_Pictographic# E5.0 [2] (🤱..🤲) breast-feeding..palms up together -1F933..1F93A ; Extended_Pictographic# E3.0 [8] (🤳..🤺) selfie..person fencing -1F93C..1F93E ; Extended_Pictographic# E3.0 [3] (🤼..🤾) people wrestling..person playing handball -1F93F ; Extended_Pictographic# E12.0 [1] (🤿) diving mask -1F940..1F945 ; Extended_Pictographic# E3.0 [6] (🥀..🥅) wilted flower..goal net -1F947..1F94B ; Extended_Pictographic# E3.0 [5] (🥇..🥋) 1st place medal..martial arts uniform -1F94C ; Extended_Pictographic# E5.0 [1] (🥌) curling stone -1F94D..1F94F ; Extended_Pictographic# E11.0 [3] (ðŸ¥..ðŸ¥) lacrosse..flying disc -1F950..1F95E ; Extended_Pictographic# E3.0 [15] (ðŸ¥..🥞) croissant..pancakes -1F95F..1F96B ; Extended_Pictographic# E5.0 [13] (🥟..🥫) dumpling..canned food -1F96C..1F970 ; Extended_Pictographic# E11.0 [5] (🥬..🥰) leafy green..smiling face with hearts -1F971 ; Extended_Pictographic# E12.0 [1] (🥱) yawning face -1F972 ; Extended_Pictographic# E13.0 [1] (🥲) smiling face with tear -1F973..1F976 ; Extended_Pictographic# E11.0 [4] (🥳..🥶) partying face..cold face -1F977..1F978 ; Extended_Pictographic# E13.0 [2] (🥷..🥸) ninja..disguised face -1F979 ; Extended_Pictographic# E14.0 [1] (🥹) face holding back tears -1F97A ; Extended_Pictographic# E11.0 [1] (🥺) pleading face -1F97B ; Extended_Pictographic# E12.0 [1] (🥻) sari -1F97C..1F97F ; Extended_Pictographic# E11.0 [4] (🥼..🥿) lab coat..flat shoe -1F980..1F984 ; Extended_Pictographic# E1.0 [5] (🦀..🦄) crab..unicorn -1F985..1F991 ; Extended_Pictographic# E3.0 [13] (🦅..🦑) eagle..squid -1F992..1F997 ; Extended_Pictographic# E5.0 [6] (🦒..🦗) giraffe..cricket -1F998..1F9A2 ; Extended_Pictographic# E11.0 [11] (🦘..🦢) kangaroo..swan -1F9A3..1F9A4 ; Extended_Pictographic# E13.0 [2] (🦣..🦤) mammoth..dodo -1F9A5..1F9AA ; Extended_Pictographic# E12.0 [6] (🦥..🦪) sloth..oyster -1F9AB..1F9AD ; Extended_Pictographic# E13.0 [3] (🦫..ðŸ¦) beaver..seal -1F9AE..1F9AF ; Extended_Pictographic# E12.0 [2] (🦮..🦯) guide dog..white cane -1F9B0..1F9B9 ; Extended_Pictographic# E11.0 [10] (🦰..🦹) red hair..supervillain -1F9BA..1F9BF ; Extended_Pictographic# E12.0 [6] (🦺..🦿) safety vest..mechanical leg -1F9C0 ; Extended_Pictographic# E1.0 [1] (🧀) cheese wedge -1F9C1..1F9C2 ; Extended_Pictographic# E11.0 [2] (ðŸ§..🧂) cupcake..salt -1F9C3..1F9CA ; Extended_Pictographic# E12.0 [8] (🧃..🧊) beverage box..ice -1F9CB ; Extended_Pictographic# E13.0 [1] (🧋) bubble tea -1F9CC ; Extended_Pictographic# E14.0 [1] (🧌) troll -1F9CD..1F9CF ; Extended_Pictographic# E12.0 [3] (ðŸ§..ðŸ§) person standing..deaf person -1F9D0..1F9E6 ; Extended_Pictographic# E5.0 [23] (ðŸ§..🧦) face with monocle..socks -1F9E7..1F9FF ; Extended_Pictographic# E11.0 [25] (🧧..🧿) red envelope..nazar amulet -1FA00..1FA6F ; Extended_Pictographic# E0.0 [112] (🨀..🩯) NEUTRAL CHESS KING..<reserved-1FA6F> -1FA70..1FA73 ; Extended_Pictographic# E12.0 [4] (🩰..🩳) ballet shoes..shorts -1FA74 ; Extended_Pictographic# E13.0 [1] (🩴) thong sandal -1FA75..1FA77 ; Extended_Pictographic# E15.0 [3] (🩵..🩷) light blue heart..pink heart -1FA78..1FA7A ; Extended_Pictographic# E12.0 [3] (🩸..🩺) drop of blood..stethoscope -1FA7B..1FA7C ; Extended_Pictographic# E14.0 [2] (🩻..🩼) x-ray..crutch -1FA7D..1FA7F ; Extended_Pictographic# E0.0 [3] (🩽..🩿) <reserved-1FA7D>..<reserved-1FA7F> -1FA80..1FA82 ; Extended_Pictographic# E12.0 [3] (🪀..🪂) yo-yo..parachute -1FA83..1FA86 ; Extended_Pictographic# E13.0 [4] (🪃..🪆) boomerang..nesting dolls -1FA87..1FA88 ; Extended_Pictographic# E15.0 [2] (🪇..🪈) maracas..flute -1FA89..1FA8F ; Extended_Pictographic# E0.0 [7] (🪉..ðŸª) <reserved-1FA89>..<reserved-1FA8F> -1FA90..1FA95 ; Extended_Pictographic# E12.0 [6] (ðŸª..🪕) ringed planet..banjo -1FA96..1FAA8 ; Extended_Pictographic# E13.0 [19] (🪖..🪨) military helmet..rock -1FAA9..1FAAC ; Extended_Pictographic# E14.0 [4] (🪩..🪬) mirror ball..hamsa -1FAAD..1FAAF ; Extended_Pictographic# E15.0 [3] (ðŸª..🪯) folding hand fan..khanda -1FAB0..1FAB6 ; Extended_Pictographic# E13.0 [7] (🪰..🪶) fly..feather -1FAB7..1FABA ; Extended_Pictographic# E14.0 [4] (🪷..🪺) lotus..nest with eggs -1FABB..1FABD ; Extended_Pictographic# E15.0 [3] (🪻..🪽) hyacinth..wing -1FABE ; Extended_Pictographic# E0.0 [1] (🪾) <reserved-1FABE> -1FABF ; Extended_Pictographic# E15.0 [1] (🪿) goose -1FAC0..1FAC2 ; Extended_Pictographic# E13.0 [3] (🫀..🫂) anatomical heart..people hugging -1FAC3..1FAC5 ; Extended_Pictographic# E14.0 [3] (🫃..🫅) pregnant man..person with crown -1FAC6..1FACD ; Extended_Pictographic# E0.0 [8] (🫆..ðŸ«) <reserved-1FAC6>..<reserved-1FACD> -1FACE..1FACF ; Extended_Pictographic# E15.0 [2] (🫎..ðŸ«) moose..donkey -1FAD0..1FAD6 ; Extended_Pictographic# E13.0 [7] (ðŸ«..🫖) blueberries..teapot -1FAD7..1FAD9 ; Extended_Pictographic# E14.0 [3] (🫗..🫙) pouring liquid..jar -1FADA..1FADB ; Extended_Pictographic# E15.0 [2] (🫚..🫛) ginger root..pea pod -1FADC..1FADF ; Extended_Pictographic# E0.0 [4] (🫜..🫟) <reserved-1FADC>..<reserved-1FADF> -1FAE0..1FAE7 ; Extended_Pictographic# E14.0 [8] (🫠..🫧) melting face..bubbles -1FAE8 ; Extended_Pictographic# E15.0 [1] (🫨) shaking face -1FAE9..1FAEF ; Extended_Pictographic# E0.0 [7] (🫩..🫯) <reserved-1FAE9>..<reserved-1FAEF> -1FAF0..1FAF6 ; Extended_Pictographic# E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands -1FAF7..1FAF8 ; Extended_Pictographic# E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand -1FAF9..1FAFF ; Extended_Pictographic# E0.0 [7] (🫹..🫿) <reserved-1FAF9>..<reserved-1FAFF> -1FC00..1FFFD ; Extended_Pictographic# E0.0[1022] (🰀..🿽) <reserved-1FC00>..<reserved-1FFFD> - -# Total elements: 3537 - -#EOF diff --git a/src/vterm/LICENSE b/src/vterm/LICENSE new file mode 100644 index 0000000000..0d051634b2 --- /dev/null +++ b/src/vterm/LICENSE @@ -0,0 +1,23 @@ + + +The MIT License + +Copyright (c) 2008 Paul Evans <leonerd@leonerd.org.uk> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/vterm/encoding.c b/src/vterm/encoding.c new file mode 100644 index 0000000000..434ac3f99b --- /dev/null +++ b/src/vterm/encoding.c @@ -0,0 +1,230 @@ +#include "vterm_internal.h" + +#define UNICODE_INVALID 0xFFFD + +#if defined(DEBUG) && DEBUG > 1 +# define DEBUG_PRINT_UTF8 +#endif + +struct UTF8DecoderData { + // number of bytes remaining in this codepoint + int bytes_remaining; + + // number of bytes total in this codepoint once it's finished + // (for detecting overlongs) + int bytes_total; + + int this_cp; +}; + +static void init_utf8(VTermEncoding *enc, void *data_) +{ + struct UTF8DecoderData *data = data_; + + data->bytes_remaining = 0; + data->bytes_total = 0; +} + +static void decode_utf8(VTermEncoding *enc, void *data_, + uint32_t cp[], int *cpi, int cplen, + const char bytes[], size_t *pos, size_t bytelen) +{ + struct UTF8DecoderData *data = data_; + +#ifdef DEBUG_PRINT_UTF8 + printf("BEGIN UTF-8\n"); +#endif + + for(; *pos < bytelen && *cpi < cplen; (*pos)++) { + unsigned char c = bytes[*pos]; + +#ifdef DEBUG_PRINT_UTF8 + printf(" pos=%zd c=%02x rem=%d\n", *pos, c, data->bytes_remaining); +#endif + + if(c < 0x20) // C0 + return; + + else if(c >= 0x20 && c < 0x7f) { + if(data->bytes_remaining) + cp[(*cpi)++] = UNICODE_INVALID; + + cp[(*cpi)++] = c; +#ifdef DEBUG_PRINT_UTF8 + printf(" UTF-8 char: U+%04x\n", c); +#endif + data->bytes_remaining = 0; + } + + else if(c == 0x7f) // DEL + return; + + else if(c >= 0x80 && c < 0xc0) { + if(!data->bytes_remaining) { + cp[(*cpi)++] = UNICODE_INVALID; + continue; + } + + data->this_cp <<= 6; + data->this_cp |= c & 0x3f; + data->bytes_remaining--; + + if(!data->bytes_remaining) { +#ifdef DEBUG_PRINT_UTF8 + printf(" UTF-8 raw char U+%04x bytelen=%d ", data->this_cp, data->bytes_total); +#endif + // Check for overlong sequences + switch(data->bytes_total) { + case 2: + if(data->this_cp < 0x0080) data->this_cp = UNICODE_INVALID; + break; + case 3: + if(data->this_cp < 0x0800) data->this_cp = UNICODE_INVALID; + break; + case 4: + if(data->this_cp < 0x10000) data->this_cp = UNICODE_INVALID; + break; + case 5: + if(data->this_cp < 0x200000) data->this_cp = UNICODE_INVALID; + break; + case 6: + if(data->this_cp < 0x4000000) data->this_cp = UNICODE_INVALID; + break; + } + // Now look for plain invalid ones + if((data->this_cp >= 0xD800 && data->this_cp <= 0xDFFF) || + data->this_cp == 0xFFFE || + data->this_cp == 0xFFFF) + data->this_cp = UNICODE_INVALID; +#ifdef DEBUG_PRINT_UTF8 + printf(" char: U+%04x\n", data->this_cp); +#endif + cp[(*cpi)++] = data->this_cp; + } + } + + else if(c >= 0xc0 && c < 0xe0) { + if(data->bytes_remaining) + cp[(*cpi)++] = UNICODE_INVALID; + + data->this_cp = c & 0x1f; + data->bytes_total = 2; + data->bytes_remaining = 1; + } + + else if(c >= 0xe0 && c < 0xf0) { + if(data->bytes_remaining) + cp[(*cpi)++] = UNICODE_INVALID; + + data->this_cp = c & 0x0f; + data->bytes_total = 3; + data->bytes_remaining = 2; + } + + else if(c >= 0xf0 && c < 0xf8) { + if(data->bytes_remaining) + cp[(*cpi)++] = UNICODE_INVALID; + + data->this_cp = c & 0x07; + data->bytes_total = 4; + data->bytes_remaining = 3; + } + + else if(c >= 0xf8 && c < 0xfc) { + if(data->bytes_remaining) + cp[(*cpi)++] = UNICODE_INVALID; + + data->this_cp = c & 0x03; + data->bytes_total = 5; + data->bytes_remaining = 4; + } + + else if(c >= 0xfc && c < 0xfe) { + if(data->bytes_remaining) + cp[(*cpi)++] = UNICODE_INVALID; + + data->this_cp = c & 0x01; + data->bytes_total = 6; + data->bytes_remaining = 5; + } + + else { + cp[(*cpi)++] = UNICODE_INVALID; + } + } +} + +static VTermEncoding encoding_utf8 = { + .init = &init_utf8, + .decode = &decode_utf8, +}; + +static void decode_usascii(VTermEncoding *enc, void *data, + uint32_t cp[], int *cpi, int cplen, + const char bytes[], size_t *pos, size_t bytelen) +{ + int is_gr = bytes[*pos] & 0x80; + + for(; *pos < bytelen && *cpi < cplen; (*pos)++) { + unsigned char c = bytes[*pos] ^ is_gr; + + if(c < 0x20 || c == 0x7f || c >= 0x80) + return; + + cp[(*cpi)++] = c; + } +} + +static VTermEncoding encoding_usascii = { + .decode = &decode_usascii, +}; + +struct StaticTableEncoding { + const VTermEncoding enc; + const uint32_t chars[128]; +}; + +static void decode_table(VTermEncoding *enc, void *data, + uint32_t cp[], int *cpi, int cplen, + const char bytes[], size_t *pos, size_t bytelen) +{ + struct StaticTableEncoding *table = (struct StaticTableEncoding *)enc; + int is_gr = bytes[*pos] & 0x80; + + for(; *pos < bytelen && *cpi < cplen; (*pos)++) { + unsigned char c = bytes[*pos] ^ is_gr; + + if(c < 0x20 || c == 0x7f || c >= 0x80) + return; + + if(table->chars[c]) + cp[(*cpi)++] = table->chars[c]; + else + cp[(*cpi)++] = c; + } +} + +#include "encoding/DECdrawing.inc" +#include "encoding/uk.inc" + +static struct { + VTermEncodingType type; + char designation; + VTermEncoding *enc; +} +encodings[] = { + { ENC_UTF8, 'u', &encoding_utf8 }, + { ENC_SINGLE_94, '0', (VTermEncoding*)&encoding_DECdrawing }, + { ENC_SINGLE_94, 'A', (VTermEncoding*)&encoding_uk }, + { ENC_SINGLE_94, 'B', &encoding_usascii }, + { 0 }, +}; + +/* This ought to be INTERNAL but isn't because it's used by unit testing */ +VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation) +{ + for(int i = 0; encodings[i].designation; i++) + if(encodings[i].type == type && encodings[i].designation == designation) + return encodings[i].enc; + return NULL; +} diff --git a/src/vterm/encoding/DECdrawing.inc b/src/vterm/encoding/DECdrawing.inc new file mode 100644 index 0000000000..627397bcc2 --- /dev/null +++ b/src/vterm/encoding/DECdrawing.inc @@ -0,0 +1,36 @@ +static const struct StaticTableEncoding encoding_DECdrawing = { + { .decode = &decode_table }, + { + [0x60] = 0x25C6, // BLACK DIAMOND + [0x61] = 0x2592, // MEDIUM SHADE (checkerboard) + [0x62] = 0x2409, // SYMBOL FOR HORIZONTAL TAB + [0x63] = 0x240C, // SYMBOL FOR FORM FEED + [0x64] = 0x240D, // SYMBOL FOR CARRIAGE RETURN + [0x65] = 0x240A, // SYMBOL FOR LINE FEED + [0x66] = 0x00B0, // DEGREE SIGN + [0x67] = 0x00B1, // PLUS-MINUS SIGN (plus or minus) + [0x68] = 0x2424, // SYMBOL FOR NEW LINE + [0x69] = 0x240B, // SYMBOL FOR VERTICAL TAB + [0x6a] = 0x2518, // BOX DRAWINGS LIGHT UP AND LEFT (bottom-right corner) + [0x6b] = 0x2510, // BOX DRAWINGS LIGHT DOWN AND LEFT (top-right corner) + [0x6c] = 0x250C, // BOX DRAWINGS LIGHT DOWN AND RIGHT (top-left corner) + [0x6d] = 0x2514, // BOX DRAWINGS LIGHT UP AND RIGHT (bottom-left corner) + [0x6e] = 0x253C, // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL (crossing lines) + [0x6f] = 0x23BA, // HORIZONTAL SCAN LINE-1 + [0x70] = 0x23BB, // HORIZONTAL SCAN LINE-3 + [0x71] = 0x2500, // BOX DRAWINGS LIGHT HORIZONTAL + [0x72] = 0x23BC, // HORIZONTAL SCAN LINE-7 + [0x73] = 0x23BD, // HORIZONTAL SCAN LINE-9 + [0x74] = 0x251C, // BOX DRAWINGS LIGHT VERTICAL AND RIGHT + [0x75] = 0x2524, // BOX DRAWINGS LIGHT VERTICAL AND LEFT + [0x76] = 0x2534, // BOX DRAWINGS LIGHT UP AND HORIZONTAL + [0x77] = 0x252C, // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + [0x78] = 0x2502, // BOX DRAWINGS LIGHT VERTICAL + [0x79] = 0x2A7D, // LESS-THAN OR SLANTED EQUAL-TO + [0x7a] = 0x2A7E, // GREATER-THAN OR SLANTED EQUAL-TO + [0x7b] = 0x03C0, // GREEK SMALL LETTER PI + [0x7c] = 0x2260, // NOT EQUAL TO + [0x7d] = 0x00A3, // POUND SIGN + [0x7e] = 0x00B7, // MIDDLE DOT + } +}; diff --git a/src/vterm/encoding/uk.inc b/src/vterm/encoding/uk.inc new file mode 100644 index 0000000000..5c7700226b --- /dev/null +++ b/src/vterm/encoding/uk.inc @@ -0,0 +1,6 @@ +static const struct StaticTableEncoding encoding_uk = { + { .decode = &decode_table }, + { + [0x23] = 0x00a3, // £ + } +}; diff --git a/src/vterm/fullwidth.inc b/src/vterm/fullwidth.inc new file mode 100644 index 0000000000..a703529a76 --- /dev/null +++ b/src/vterm/fullwidth.inc @@ -0,0 +1,111 @@ + { 0x1100, 0x115f }, + { 0x231a, 0x231b }, + { 0x2329, 0x232a }, + { 0x23e9, 0x23ec }, + { 0x23f0, 0x23f0 }, + { 0x23f3, 0x23f3 }, + { 0x25fd, 0x25fe }, + { 0x2614, 0x2615 }, + { 0x2648, 0x2653 }, + { 0x267f, 0x267f }, + { 0x2693, 0x2693 }, + { 0x26a1, 0x26a1 }, + { 0x26aa, 0x26ab }, + { 0x26bd, 0x26be }, + { 0x26c4, 0x26c5 }, + { 0x26ce, 0x26ce }, + { 0x26d4, 0x26d4 }, + { 0x26ea, 0x26ea }, + { 0x26f2, 0x26f3 }, + { 0x26f5, 0x26f5 }, + { 0x26fa, 0x26fa }, + { 0x26fd, 0x26fd }, + { 0x2705, 0x2705 }, + { 0x270a, 0x270b }, + { 0x2728, 0x2728 }, + { 0x274c, 0x274c }, + { 0x274e, 0x274e }, + { 0x2753, 0x2755 }, + { 0x2757, 0x2757 }, + { 0x2795, 0x2797 }, + { 0x27b0, 0x27b0 }, + { 0x27bf, 0x27bf }, + { 0x2b1b, 0x2b1c }, + { 0x2b50, 0x2b50 }, + { 0x2b55, 0x2b55 }, + { 0x2e80, 0x2e99 }, + { 0x2e9b, 0x2ef3 }, + { 0x2f00, 0x2fd5 }, + { 0x2ff0, 0x2ffb }, + { 0x3000, 0x303e }, + { 0x3041, 0x3096 }, + { 0x3099, 0x30ff }, + { 0x3105, 0x312f }, + { 0x3131, 0x318e }, + { 0x3190, 0x31ba }, + { 0x31c0, 0x31e3 }, + { 0x31f0, 0x321e }, + { 0x3220, 0x3247 }, + { 0x3250, 0x4dbf }, + { 0x4e00, 0xa48c }, + { 0xa490, 0xa4c6 }, + { 0xa960, 0xa97c }, + { 0xac00, 0xd7a3 }, + { 0xf900, 0xfaff }, + { 0xfe10, 0xfe19 }, + { 0xfe30, 0xfe52 }, + { 0xfe54, 0xfe66 }, + { 0xfe68, 0xfe6b }, + { 0xff01, 0xff60 }, + { 0xffe0, 0xffe6 }, + { 0x16fe0, 0x16fe3 }, + { 0x17000, 0x187f7 }, + { 0x18800, 0x18af2 }, + { 0x1b000, 0x1b11e }, + { 0x1b150, 0x1b152 }, + { 0x1b164, 0x1b167 }, + { 0x1b170, 0x1b2fb }, + { 0x1f004, 0x1f004 }, + { 0x1f0cf, 0x1f0cf }, + { 0x1f18e, 0x1f18e }, + { 0x1f191, 0x1f19a }, + { 0x1f200, 0x1f202 }, + { 0x1f210, 0x1f23b }, + { 0x1f240, 0x1f248 }, + { 0x1f250, 0x1f251 }, + { 0x1f260, 0x1f265 }, + { 0x1f300, 0x1f320 }, + { 0x1f32d, 0x1f335 }, + { 0x1f337, 0x1f37c }, + { 0x1f37e, 0x1f393 }, + { 0x1f3a0, 0x1f3ca }, + { 0x1f3cf, 0x1f3d3 }, + { 0x1f3e0, 0x1f3f0 }, + { 0x1f3f4, 0x1f3f4 }, + { 0x1f3f8, 0x1f43e }, + { 0x1f440, 0x1f440 }, + { 0x1f442, 0x1f4fc }, + { 0x1f4ff, 0x1f53d }, + { 0x1f54b, 0x1f54e }, + { 0x1f550, 0x1f567 }, + { 0x1f57a, 0x1f57a }, + { 0x1f595, 0x1f596 }, + { 0x1f5a4, 0x1f5a4 }, + { 0x1f5fb, 0x1f64f }, + { 0x1f680, 0x1f6c5 }, + { 0x1f6cc, 0x1f6cc }, + { 0x1f6d0, 0x1f6d2 }, + { 0x1f6d5, 0x1f6d5 }, + { 0x1f6eb, 0x1f6ec }, + { 0x1f6f4, 0x1f6fa }, + { 0x1f7e0, 0x1f7eb }, + { 0x1f90d, 0x1f971 }, + { 0x1f973, 0x1f976 }, + { 0x1f97a, 0x1f9a2 }, + { 0x1f9a5, 0x1f9aa }, + { 0x1f9ae, 0x1f9ca }, + { 0x1f9cd, 0x1f9ff }, + { 0x1fa70, 0x1fa73 }, + { 0x1fa78, 0x1fa7a }, + { 0x1fa80, 0x1fa82 }, + { 0x1fa90, 0x1fa95 }, diff --git a/src/vterm/keyboard.c b/src/vterm/keyboard.c new file mode 100644 index 0000000000..7e062c8c02 --- /dev/null +++ b/src/vterm/keyboard.c @@ -0,0 +1,225 @@ +#include "vterm_internal.h" +#include <stdio.h> + +#include "nvim/tui/termkey/termkey.h" + +void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod) +{ + /* The shift modifier is never important for Unicode characters + * apart from Space + */ + if(c != ' ') + mod &= ~VTERM_MOD_SHIFT; + + if(mod == 0) { + // Normal text - ignore just shift + char str[6]; + int seqlen = fill_utf8(c, str); + vterm_push_output_bytes(vt, str, seqlen); + return; + } + + int needs_CSIu; + switch(c) { + /* Special Ctrl- letters that can't be represented elsewise */ + case 'i': case 'j': case 'm': case '[': + needs_CSIu = 1; + break; + /* Ctrl-\ ] ^ _ don't need CSUu */ + case '\\': case ']': case '^': case '_': + needs_CSIu = 0; + break; + /* Shift-space needs CSIu */ + case ' ': + needs_CSIu = !!(mod & VTERM_MOD_SHIFT); + break; + /* All other characters needs CSIu except for letters a-z */ + default: + needs_CSIu = (c < 'a' || c > 'z'); + } + + /* ALT we can just prefix with ESC; anything else requires CSI u */ + if(needs_CSIu && (mod & ~VTERM_MOD_ALT)) { + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", c, mod+1); + return; + } + + if(mod & VTERM_MOD_CTRL) + c &= 0x1f; + + vterm_push_output_sprintf(vt, "%s%c", mod & VTERM_MOD_ALT ? ESC_S : "", c); +} + +typedef struct { + enum { + KEYCODE_NONE, + KEYCODE_LITERAL, + KEYCODE_TAB, + KEYCODE_ENTER, + KEYCODE_SS3, + KEYCODE_CSI, + KEYCODE_CSI_CURSOR, + KEYCODE_CSINUM, + KEYCODE_KEYPAD, + } type; + char literal; + int csinum; +} keycodes_s; + +static keycodes_s keycodes[] = { + { KEYCODE_NONE }, // NONE + + { KEYCODE_ENTER, '\r' }, // ENTER + { KEYCODE_TAB, '\t' }, // TAB + { KEYCODE_LITERAL, '\x7f' }, // BACKSPACE == ASCII DEL + { KEYCODE_LITERAL, '\x1b' }, // ESCAPE + + { KEYCODE_CSI_CURSOR, 'A' }, // UP + { KEYCODE_CSI_CURSOR, 'B' }, // DOWN + { KEYCODE_CSI_CURSOR, 'D' }, // LEFT + { KEYCODE_CSI_CURSOR, 'C' }, // RIGHT + + { KEYCODE_CSINUM, '~', 2 }, // INS + { KEYCODE_CSINUM, '~', 3 }, // DEL + { KEYCODE_CSI_CURSOR, 'H' }, // HOME + { KEYCODE_CSI_CURSOR, 'F' }, // END + { KEYCODE_CSINUM, '~', 5 }, // PAGEUP + { KEYCODE_CSINUM, '~', 6 }, // PAGEDOWN +}; + +static keycodes_s keycodes_fn[] = { + { KEYCODE_NONE }, // F0 - shouldn't happen + { KEYCODE_SS3, 'P' }, // F1 + { KEYCODE_SS3, 'Q' }, // F2 + { KEYCODE_SS3, 'R' }, // F3 + { KEYCODE_SS3, 'S' }, // F4 + { KEYCODE_CSINUM, '~', 15 }, // F5 + { KEYCODE_CSINUM, '~', 17 }, // F6 + { KEYCODE_CSINUM, '~', 18 }, // F7 + { KEYCODE_CSINUM, '~', 19 }, // F8 + { KEYCODE_CSINUM, '~', 20 }, // F9 + { KEYCODE_CSINUM, '~', 21 }, // F10 + { KEYCODE_CSINUM, '~', 23 }, // F11 + { KEYCODE_CSINUM, '~', 24 }, // F12 +}; + +static keycodes_s keycodes_kp[] = { + { KEYCODE_KEYPAD, '0', 'p' }, // KP_0 + { KEYCODE_KEYPAD, '1', 'q' }, // KP_1 + { KEYCODE_KEYPAD, '2', 'r' }, // KP_2 + { KEYCODE_KEYPAD, '3', 's' }, // KP_3 + { KEYCODE_KEYPAD, '4', 't' }, // KP_4 + { KEYCODE_KEYPAD, '5', 'u' }, // KP_5 + { KEYCODE_KEYPAD, '6', 'v' }, // KP_6 + { KEYCODE_KEYPAD, '7', 'w' }, // KP_7 + { KEYCODE_KEYPAD, '8', 'x' }, // KP_8 + { KEYCODE_KEYPAD, '9', 'y' }, // KP_9 + { KEYCODE_KEYPAD, '*', 'j' }, // KP_MULT + { KEYCODE_KEYPAD, '+', 'k' }, // KP_PLUS + { KEYCODE_KEYPAD, ',', 'l' }, // KP_COMMA + { KEYCODE_KEYPAD, '-', 'm' }, // KP_MINUS + { KEYCODE_KEYPAD, '.', 'n' }, // KP_PERIOD + { KEYCODE_KEYPAD, '/', 'o' }, // KP_DIVIDE + { KEYCODE_KEYPAD, '\n', 'M' }, // KP_ENTER + { KEYCODE_KEYPAD, '=', 'X' }, // KP_EQUAL +}; + +void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod) +{ + if(key == VTERM_KEY_NONE) + return; + + keycodes_s k; + if(key < VTERM_KEY_FUNCTION_0) { + if(key >= sizeof(keycodes)/sizeof(keycodes[0])) + return; + k = keycodes[key]; + } + else if(key >= VTERM_KEY_FUNCTION_0 && key <= VTERM_KEY_FUNCTION_MAX) { + if((key - VTERM_KEY_FUNCTION_0) >= sizeof(keycodes_fn)/sizeof(keycodes_fn[0])) + return; + k = keycodes_fn[key - VTERM_KEY_FUNCTION_0]; + } + else if(key >= VTERM_KEY_KP_0) { + if((key - VTERM_KEY_KP_0) >= sizeof(keycodes_kp)/sizeof(keycodes_kp[0])) + return; + k = keycodes_kp[key - VTERM_KEY_KP_0]; + } + + switch(k.type) { + case KEYCODE_NONE: + break; + + case KEYCODE_TAB: + /* Shift-Tab is CSI Z but plain Tab is 0x09 */ + if(mod == VTERM_MOD_SHIFT) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "Z"); + else if(mod & VTERM_MOD_SHIFT) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%dZ", mod+1); + else + goto case_LITERAL; + break; + + case KEYCODE_ENTER: + /* Enter is CRLF in newline mode, but just LF in linefeed */ + if(vt->state->mode.newline) + vterm_push_output_sprintf(vt, "\r\n"); + else + goto case_LITERAL; + break; + + case KEYCODE_LITERAL: case_LITERAL: + if(mod & (VTERM_MOD_SHIFT|VTERM_MOD_CTRL)) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", k.literal, mod+1); + else + vterm_push_output_sprintf(vt, mod & VTERM_MOD_ALT ? ESC_S "%c" : "%c", k.literal); + break; + + case KEYCODE_SS3: case_SS3: + if(mod == 0) + vterm_push_output_sprintf_ctrl(vt, C1_SS3, "%c", k.literal); + else + goto case_CSI; + break; + + case KEYCODE_CSI: case_CSI: + if(mod == 0) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%c", k.literal); + else + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%d%c", mod + 1, k.literal); + break; + + case KEYCODE_CSINUM: + if(mod == 0) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d%c", k.csinum, k.literal); + else + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%d%c", k.csinum, mod + 1, k.literal); + break; + + case KEYCODE_CSI_CURSOR: + if(vt->state->mode.cursor) + goto case_SS3; + else + goto case_CSI; + + case KEYCODE_KEYPAD: + if(vt->state->mode.keypad) { + k.literal = k.csinum; + goto case_SS3; + } + else + goto case_LITERAL; + } +} + +void vterm_keyboard_start_paste(VTerm *vt) +{ + if(vt->state->mode.bracketpaste) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "200~"); +} + +void vterm_keyboard_end_paste(VTerm *vt) +{ + if(vt->state->mode.bracketpaste) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "201~"); +} diff --git a/src/vterm/mouse.c b/src/vterm/mouse.c new file mode 100644 index 0000000000..a9d3fe4ca9 --- /dev/null +++ b/src/vterm/mouse.c @@ -0,0 +1,99 @@ +#include "vterm_internal.h" + +#include "nvim/tui/termkey/termkey.h" + +static void output_mouse(VTermState *state, int code, int pressed, int modifiers, int col, int row) +{ + modifiers <<= 2; + + switch(state->mouse_protocol) { + case MOUSE_X10: + if(col + 0x21 > 0xff) + col = 0xff - 0x21; + if(row + 0x21 > 0xff) + row = 0xff - 0x21; + + if(!pressed) + code = 3; + + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%c%c%c", + (code | modifiers) + 0x20, col + 0x21, row + 0x21); + break; + + case MOUSE_UTF8: + { + char utf8[18]; size_t len = 0; + + if(!pressed) + code = 3; + + len += fill_utf8((code | modifiers) + 0x20, utf8 + len); + len += fill_utf8(col + 0x21, utf8 + len); + len += fill_utf8(row + 0x21, utf8 + len); + utf8[len] = 0; + + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%s", utf8); + } + break; + + case MOUSE_SGR: + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "<%d;%d;%d%c", + code | modifiers, col + 1, row + 1, pressed ? 'M' : 'm'); + break; + + case MOUSE_RXVT: + if(!pressed) + code = 3; + + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "%d;%d;%dM", + code | modifiers, col + 1, row + 1); + break; + } +} + +void vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod) +{ + VTermState *state = vt->state; + + if(col == state->mouse_col && row == state->mouse_row) + return; + + state->mouse_col = col; + state->mouse_row = row; + + if((state->mouse_flags & MOUSE_WANT_DRAG && state->mouse_buttons) || + (state->mouse_flags & MOUSE_WANT_MOVE)) { + int button = state->mouse_buttons & 0x01 ? 1 : + state->mouse_buttons & 0x02 ? 2 : + state->mouse_buttons & 0x04 ? 3 : 4; + output_mouse(state, button-1 + 0x20, 1, mod, col, row); + } +} + +void vterm_mouse_button(VTerm *vt, int button, bool pressed, VTermModifier mod) +{ + VTermState *state = vt->state; + + int old_buttons = state->mouse_buttons; + + if(button > 0 && button <= 3) { + if(pressed) + state->mouse_buttons |= (1 << (button-1)); + else + state->mouse_buttons &= ~(1 << (button-1)); + } + + /* Most of the time we don't get button releases from 4/5 */ + if(state->mouse_buttons == old_buttons && button < 4) + return; + + if(!state->mouse_flags) + return; + + if(button < 4) { + output_mouse(state, button-1, pressed, mod, state->mouse_col, state->mouse_row); + } + else if(button < 8) { + output_mouse(state, button-4 + 0x40, pressed, mod, state->mouse_col, state->mouse_row); + } +} diff --git a/src/vterm/parser.c b/src/vterm/parser.c new file mode 100644 index 0000000000..84d017a791 --- /dev/null +++ b/src/vterm/parser.c @@ -0,0 +1,408 @@ +#include "vterm_internal.h" + +#include <assert.h> +#include <stdio.h> +#include <string.h> + +#undef DEBUG_PARSER + +static bool is_intermed(unsigned char c) +{ + return c >= 0x20 && c <= 0x2f; +} + +static void do_control(VTerm *vt, unsigned char control) +{ + if(vt->parser.callbacks && vt->parser.callbacks->control) + if((*vt->parser.callbacks->control)(control, vt->parser.cbdata)) + return; + + DEBUG_LOG("libvterm: Unhandled control 0x%02x\n", control); +} + +static void do_csi(VTerm *vt, char command) +{ +#ifdef DEBUG_PARSER + printf("Parsed CSI args as:\n", arglen, args); + printf(" leader: %s\n", vt->parser.v.csi.leader); + for(int argi = 0; argi < vt->parser.v.csi.argi; argi++) { + printf(" %lu", CSI_ARG(vt->parser.v.csi.args[argi])); + if(!CSI_ARG_HAS_MORE(vt->parser.v.csi.args[argi])) + printf("\n"); + printf(" intermed: %s\n", vt->parser.intermed); + } +#endif + + if(vt->parser.callbacks && vt->parser.callbacks->csi) + if((*vt->parser.callbacks->csi)( + vt->parser.v.csi.leaderlen ? vt->parser.v.csi.leader : NULL, + vt->parser.v.csi.args, + vt->parser.v.csi.argi, + vt->parser.intermedlen ? vt->parser.intermed : NULL, + command, + vt->parser.cbdata)) + return; + + DEBUG_LOG("libvterm: Unhandled CSI %c\n", command); +} + +static void do_escape(VTerm *vt, char command) +{ + char seq[INTERMED_MAX+1]; + + size_t len = vt->parser.intermedlen; + strncpy(seq, vt->parser.intermed, len); + seq[len++] = command; + seq[len] = 0; + + if(vt->parser.callbacks && vt->parser.callbacks->escape) + if((*vt->parser.callbacks->escape)(seq, len, vt->parser.cbdata)) + return; + + DEBUG_LOG("libvterm: Unhandled escape ESC 0x%02x\n", command); +} + +static void string_fragment(VTerm *vt, const char *str, size_t len, bool final) +{ + VTermStringFragment frag = { + .str = str, + .len = len, + .initial = vt->parser.string_initial, + .final = final, + }; + + switch(vt->parser.state) { + case OSC: + if(vt->parser.callbacks && vt->parser.callbacks->osc) + (*vt->parser.callbacks->osc)(vt->parser.v.osc.command, frag, vt->parser.cbdata); + break; + + case DCS: + if(vt->parser.callbacks && vt->parser.callbacks->dcs) + (*vt->parser.callbacks->dcs)(vt->parser.v.dcs.command, vt->parser.v.dcs.commandlen, frag, vt->parser.cbdata); + break; + + case APC: + if(vt->parser.callbacks && vt->parser.callbacks->apc) + (*vt->parser.callbacks->apc)(frag, vt->parser.cbdata); + break; + + case PM: + if(vt->parser.callbacks && vt->parser.callbacks->pm) + (*vt->parser.callbacks->pm)(frag, vt->parser.cbdata); + break; + + case SOS: + if(vt->parser.callbacks && vt->parser.callbacks->sos) + (*vt->parser.callbacks->sos)(frag, vt->parser.cbdata); + break; + + case NORMAL: + case CSI_LEADER: + case CSI_ARGS: + case CSI_INTERMED: + case OSC_COMMAND: + case DCS_COMMAND: + break; + } + + vt->parser.string_initial = false; +} + +size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) +{ + size_t pos = 0; + const char *string_start; + + switch(vt->parser.state) { + case NORMAL: + case CSI_LEADER: + case CSI_ARGS: + case CSI_INTERMED: + case OSC_COMMAND: + case DCS_COMMAND: + string_start = NULL; + break; + case OSC: + case DCS: + case APC: + case PM: + case SOS: + string_start = bytes; + break; + } + +#define ENTER_STATE(st) do { vt->parser.state = st; string_start = NULL; } while(0) +#define ENTER_NORMAL_STATE() ENTER_STATE(NORMAL) + +#define IS_STRING_STATE() (vt->parser.state >= OSC_COMMAND) + + for( ; pos < len; pos++) { + unsigned char c = bytes[pos]; + bool c1_allowed = !vt->mode.utf8; + + if(c == 0x00 || c == 0x7f) { // NUL, DEL + if(IS_STRING_STATE()) { + string_fragment(vt, string_start, bytes + pos - string_start, false); + string_start = bytes + pos + 1; + } + if(vt->parser.emit_nul) + do_control(vt, c); + continue; + } + if(c == 0x18 || c == 0x1a) { // CAN, SUB + vt->parser.in_esc = false; + ENTER_NORMAL_STATE(); + if(vt->parser.emit_nul) + do_control(vt, c); + continue; + } + else if(c == 0x1b) { // ESC + vt->parser.intermedlen = 0; + if(!IS_STRING_STATE()) + vt->parser.state = NORMAL; + vt->parser.in_esc = true; + continue; + } + else if(c == 0x07 && // BEL, can stand for ST in OSC or DCS state + IS_STRING_STATE()) { + // fallthrough + } + else if(c < 0x20) { // other C0 + if(vt->parser.state == SOS) + continue; // All other C0s permitted in SOS + + if(IS_STRING_STATE()) + string_fragment(vt, string_start, bytes + pos - string_start, false); + do_control(vt, c); + if(IS_STRING_STATE()) + string_start = bytes + pos + 1; + continue; + } + // else fallthrough + + size_t string_len = bytes + pos - string_start; + + if(vt->parser.in_esc) { + // Hoist an ESC letter into a C1 if we're not in a string mode + // Always accept ESC \ == ST even in string mode + if(!vt->parser.intermedlen && + c >= 0x40 && c < 0x60 && + ((!IS_STRING_STATE() || c == 0x5c))) { + c += 0x40; + c1_allowed = true; + if(string_len) { + assert(string_len > 0); + string_len -= 1; + } + vt->parser.in_esc = false; + } + else { + string_start = NULL; + vt->parser.state = NORMAL; + } + } + + switch(vt->parser.state) { + case CSI_LEADER: + /* Extract leader bytes 0x3c to 0x3f */ + if(c >= 0x3c && c <= 0x3f) { + if(vt->parser.v.csi.leaderlen < CSI_LEADER_MAX-1) + vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen++] = c; + break; + } + + /* else fallthrough */ + vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen] = 0; + + vt->parser.v.csi.argi = 0; + vt->parser.v.csi.args[0] = CSI_ARG_MISSING; + vt->parser.state = CSI_ARGS; + + /* fallthrough */ + case CSI_ARGS: + /* Numerical value of argument */ + if(c >= '0' && c <= '9') { + if(vt->parser.v.csi.args[vt->parser.v.csi.argi] == CSI_ARG_MISSING) + vt->parser.v.csi.args[vt->parser.v.csi.argi] = 0; + vt->parser.v.csi.args[vt->parser.v.csi.argi] *= 10; + vt->parser.v.csi.args[vt->parser.v.csi.argi] += c - '0'; + break; + } + if(c == ':') { + vt->parser.v.csi.args[vt->parser.v.csi.argi] |= CSI_ARG_FLAG_MORE; + c = ';'; + } + if(c == ';') { + vt->parser.v.csi.argi++; + vt->parser.v.csi.args[vt->parser.v.csi.argi] = CSI_ARG_MISSING; + break; + } + + /* else fallthrough */ + vt->parser.v.csi.argi++; + vt->parser.intermedlen = 0; + vt->parser.state = CSI_INTERMED; + case CSI_INTERMED: + if(is_intermed(c)) { + if(vt->parser.intermedlen < INTERMED_MAX-1) + vt->parser.intermed[vt->parser.intermedlen++] = c; + break; + } + else if(c == 0x1b) { + /* ESC in CSI cancels */ + } + else if(c >= 0x40 && c <= 0x7e) { + vt->parser.intermed[vt->parser.intermedlen] = 0; + do_csi(vt, c); + } + /* else was invalid CSI */ + + ENTER_NORMAL_STATE(); + break; + + case OSC_COMMAND: + /* Numerical value of command */ + if(c >= '0' && c <= '9') { + if(vt->parser.v.osc.command == -1) + vt->parser.v.osc.command = 0; + else + vt->parser.v.osc.command *= 10; + vt->parser.v.osc.command += c - '0'; + break; + } + if(c == ';') { + vt->parser.state = OSC; + string_start = bytes + pos + 1; + break; + } + + /* else fallthrough */ + string_start = bytes + pos; + string_len = 0; + vt->parser.state = OSC; + goto string_state; + + case DCS_COMMAND: + if(vt->parser.v.dcs.commandlen < CSI_LEADER_MAX) + vt->parser.v.dcs.command[vt->parser.v.dcs.commandlen++] = c; + + if(c >= 0x40 && c<= 0x7e) { + string_start = bytes + pos + 1; + vt->parser.state = DCS; + } + break; + +string_state: + case OSC: + case DCS: + case APC: + case PM: + case SOS: + if(c == 0x07 || (c1_allowed && c == 0x9c)) { + string_fragment(vt, string_start, string_len, true); + ENTER_NORMAL_STATE(); + } + break; + + case NORMAL: + if(vt->parser.in_esc) { + if(is_intermed(c)) { + if(vt->parser.intermedlen < INTERMED_MAX-1) + vt->parser.intermed[vt->parser.intermedlen++] = c; + } + else if(c >= 0x30 && c < 0x7f) { + do_escape(vt, c); + vt->parser.in_esc = 0; + ENTER_NORMAL_STATE(); + } + else { + DEBUG_LOG("TODO: Unhandled byte %02x in Escape\n", c); + } + break; + } + if(c1_allowed && c >= 0x80 && c < 0xa0) { + switch(c) { + case 0x90: // DCS + vt->parser.string_initial = true; + vt->parser.v.dcs.commandlen = 0; + ENTER_STATE(DCS_COMMAND); + break; + case 0x98: // SOS + vt->parser.string_initial = true; + ENTER_STATE(SOS); + string_start = bytes + pos + 1; + string_len = 0; + break; + case 0x9b: // CSI + vt->parser.v.csi.leaderlen = 0; + ENTER_STATE(CSI_LEADER); + break; + case 0x9d: // OSC + vt->parser.v.osc.command = -1; + vt->parser.string_initial = true; + string_start = bytes + pos + 1; + ENTER_STATE(OSC_COMMAND); + break; + case 0x9e: // PM + vt->parser.string_initial = true; + ENTER_STATE(PM); + string_start = bytes + pos + 1; + string_len = 0; + break; + case 0x9f: // APC + vt->parser.string_initial = true; + ENTER_STATE(APC); + string_start = bytes + pos + 1; + string_len = 0; + break; + default: + do_control(vt, c); + break; + } + } + else { + size_t eaten = 0; + if(vt->parser.callbacks && vt->parser.callbacks->text) + eaten = (*vt->parser.callbacks->text)(bytes + pos, len - pos, vt->parser.cbdata); + + if(!eaten) { + DEBUG_LOG("libvterm: Text callback did not consume any input\n"); + /* force it to make progress */ + eaten = 1; + } + + pos += (eaten - 1); // we'll ++ it again in a moment + } + break; + } + } + + if(string_start) { + size_t string_len = bytes + pos - string_start; + if (string_len > 0) { + if(vt->parser.in_esc) { + string_len -= 1; + } + string_fragment(vt, string_start, string_len, false); + } + } + + return len; +} + +void vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user) +{ + vt->parser.callbacks = callbacks; + vt->parser.cbdata = user; +} + +void *vterm_parser_get_cbdata(VTerm *vt) +{ + return vt->parser.cbdata; +} + +void vterm_parser_set_emit_nul(VTerm *vt, bool emit) +{ + vt->parser.emit_nul = emit; +} diff --git a/src/vterm/pen.c b/src/vterm/pen.c new file mode 100644 index 0000000000..1876eb9881 --- /dev/null +++ b/src/vterm/pen.c @@ -0,0 +1,678 @@ +#include "vterm_internal.h" + +#include <stdio.h> + +/** + * Structure used to store RGB triples without the additional metadata stored in + * VTermColor. + */ +typedef struct { + uint8_t red, green, blue; +} VTermRGB; + +static const VTermRGB ansi_colors[] = { + /* R G B */ + { 0, 0, 0 }, // black + { 224, 0, 0 }, // red + { 0, 224, 0 }, // green + { 224, 224, 0 }, // yellow + { 0, 0, 224 }, // blue + { 224, 0, 224 }, // magenta + { 0, 224, 224 }, // cyan + { 224, 224, 224 }, // white == light grey + + // high intensity + { 128, 128, 128 }, // black + { 255, 64, 64 }, // red + { 64, 255, 64 }, // green + { 255, 255, 64 }, // yellow + { 64, 64, 255 }, // blue + { 255, 64, 255 }, // magenta + { 64, 255, 255 }, // cyan + { 255, 255, 255 }, // white for real +}; + +static int ramp6[] = { + 0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF, +}; + +static int ramp24[] = { + 0x00, 0x0B, 0x16, 0x21, 0x2C, 0x37, 0x42, 0x4D, 0x58, 0x63, 0x6E, 0x79, + 0x85, 0x90, 0x9B, 0xA6, 0xB1, 0xBC, 0xC7, 0xD2, 0xDD, 0xE8, 0xF3, 0xFF, +}; + +static void lookup_default_colour_ansi(long idx, VTermColor *col) +{ + if (idx >= 0 && idx < 16) { + vterm_color_rgb( + col, + ansi_colors[idx].red, ansi_colors[idx].green, ansi_colors[idx].blue); + } +} + +static bool lookup_colour_ansi(const VTermState *state, long index, VTermColor *col) +{ + if(index >= 0 && index < 16) { + *col = state->colors[index]; + return true; + } + + return false; +} + +static bool lookup_colour_palette(const VTermState *state, long index, VTermColor *col) +{ + if(index >= 0 && index < 16) { + // Normal 8 colours or high intensity - parse as palette 0 + return lookup_colour_ansi(state, index, col); + } + else if(index >= 16 && index < 232) { + // 216-colour cube + index -= 16; + + vterm_color_rgb(col, ramp6[index/6/6 % 6], + ramp6[index/6 % 6], + ramp6[index % 6]); + + return true; + } + else if(index >= 232 && index < 256) { + // 24 greyscales + index -= 232; + + vterm_color_rgb(col, ramp24[index], ramp24[index], ramp24[index]); + + return true; + } + + return false; +} + +static int lookup_colour(const VTermState *state, int palette, const long args[], int argcount, VTermColor *col) +{ + switch(palette) { + case 2: // RGB mode - 3 args contain colour values directly + if(argcount < 3) + return argcount; + + vterm_color_rgb(col, CSI_ARG(args[0]), CSI_ARG(args[1]), CSI_ARG(args[2])); + + return 3; + + case 5: // XTerm 256-colour mode + if (!argcount || CSI_ARG_IS_MISSING(args[0])) { + return argcount ? 1 : 0; + } + + vterm_color_indexed(col, args[0]); + + return argcount ? 1 : 0; + + default: + DEBUG_LOG("Unrecognised colour palette %d\n", palette); + return 0; + } +} + +// Some conveniences + +static void setpenattr(VTermState *state, VTermAttr attr, VTermValueType type, VTermValue *val) +{ +#ifdef DEBUG + if(type != vterm_get_attr_type(attr)) { + DEBUG_LOG("Cannot set attr %d as it has type %d, not type %d\n", + attr, vterm_get_attr_type(attr), type); + return; + } +#endif + if(state->callbacks && state->callbacks->setpenattr) + (*state->callbacks->setpenattr)(attr, val, state->cbdata); +} + +static void setpenattr_bool(VTermState *state, VTermAttr attr, int boolean) +{ + VTermValue val = { .boolean = boolean }; + setpenattr(state, attr, VTERM_VALUETYPE_BOOL, &val); +} + +static void setpenattr_int(VTermState *state, VTermAttr attr, int number) +{ + VTermValue val = { .number = number }; + setpenattr(state, attr, VTERM_VALUETYPE_INT, &val); +} + +static void setpenattr_col(VTermState *state, VTermAttr attr, VTermColor color) +{ + VTermValue val = { .color = color }; + setpenattr(state, attr, VTERM_VALUETYPE_COLOR, &val); +} + +static void set_pen_col_ansi(VTermState *state, VTermAttr attr, long col) +{ + VTermColor *colp = (attr == VTERM_ATTR_BACKGROUND) ? &state->pen.bg : &state->pen.fg; + + vterm_color_indexed(colp, col); + + setpenattr_col(state, attr, *colp); +} + +INTERNAL void vterm_state_newpen(VTermState *state) +{ + // 90% grey so that pure white is brighter + vterm_color_rgb(&state->default_fg, 240, 240, 240); + vterm_color_rgb(&state->default_bg, 0, 0, 0); + vterm_state_set_default_colors(state, &state->default_fg, &state->default_bg); + + for(int col = 0; col < 16; col++) + lookup_default_colour_ansi(col, &state->colors[col]); +} + +INTERNAL void vterm_state_resetpen(VTermState *state) +{ + state->pen.bold = 0; setpenattr_bool(state, VTERM_ATTR_BOLD, 0); + state->pen.underline = 0; setpenattr_int (state, VTERM_ATTR_UNDERLINE, 0); + state->pen.italic = 0; setpenattr_bool(state, VTERM_ATTR_ITALIC, 0); + state->pen.blink = 0; setpenattr_bool(state, VTERM_ATTR_BLINK, 0); + state->pen.reverse = 0; setpenattr_bool(state, VTERM_ATTR_REVERSE, 0); + state->pen.conceal = 0; setpenattr_bool(state, VTERM_ATTR_CONCEAL, 0); + state->pen.strike = 0; setpenattr_bool(state, VTERM_ATTR_STRIKE, 0); + state->pen.font = 0; setpenattr_int (state, VTERM_ATTR_FONT, 0); + state->pen.small = 0; setpenattr_bool(state, VTERM_ATTR_SMALL, 0); + state->pen.baseline = 0; setpenattr_int (state, VTERM_ATTR_BASELINE, 0); + + state->pen.fg = state->default_fg; setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->default_fg); + state->pen.bg = state->default_bg; setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->default_bg); + + state->pen.uri = 0; setpenattr_int(state, VTERM_ATTR_URI, 0); +} + +INTERNAL void vterm_state_savepen(VTermState *state, int save) +{ + if(save) { + state->saved.pen = state->pen; + } + else { + state->pen = state->saved.pen; + + setpenattr_bool(state, VTERM_ATTR_BOLD, state->pen.bold); + setpenattr_int (state, VTERM_ATTR_UNDERLINE, state->pen.underline); + setpenattr_bool(state, VTERM_ATTR_ITALIC, state->pen.italic); + setpenattr_bool(state, VTERM_ATTR_BLINK, state->pen.blink); + setpenattr_bool(state, VTERM_ATTR_REVERSE, state->pen.reverse); + setpenattr_bool(state, VTERM_ATTR_CONCEAL, state->pen.conceal); + setpenattr_bool(state, VTERM_ATTR_STRIKE, state->pen.strike); + setpenattr_int (state, VTERM_ATTR_FONT, state->pen.font); + setpenattr_bool(state, VTERM_ATTR_SMALL, state->pen.small); + setpenattr_int (state, VTERM_ATTR_BASELINE, state->pen.baseline); + + setpenattr_col( state, VTERM_ATTR_FOREGROUND, state->pen.fg); + setpenattr_col( state, VTERM_ATTR_BACKGROUND, state->pen.bg); + + setpenattr_int( state, VTERM_ATTR_URI, state->pen.uri); + } +} + +int vterm_color_is_equal(const VTermColor *a, const VTermColor *b) +{ + /* First make sure that the two colours are of the same type (RGB/Indexed) */ + if (a->type != b->type) { + return false; + } + + /* Depending on the type inspect the corresponding members */ + if (VTERM_COLOR_IS_INDEXED(a)) { + return a->indexed.idx == b->indexed.idx; + } + else if (VTERM_COLOR_IS_RGB(a)) { + return (a->rgb.red == b->rgb.red) + && (a->rgb.green == b->rgb.green) + && (a->rgb.blue == b->rgb.blue); + } + + return 0; +} + +void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg) +{ + *default_fg = state->default_fg; + *default_bg = state->default_bg; +} + +void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col) +{ + lookup_colour_palette(state, index, col); +} + +void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg) +{ + if(default_fg) { + state->default_fg = *default_fg; + state->default_fg.type = (state->default_fg.type & ~VTERM_COLOR_DEFAULT_MASK) + | VTERM_COLOR_DEFAULT_FG; + } + + if(default_bg) { + state->default_bg = *default_bg; + state->default_bg.type = (state->default_bg.type & ~VTERM_COLOR_DEFAULT_MASK) + | VTERM_COLOR_DEFAULT_BG; + } +} + +void vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col) +{ + if(index >= 0 && index < 16) + state->colors[index] = *col; +} + +void vterm_state_convert_color_to_rgb(const VTermState *state, VTermColor *col) +{ + if (VTERM_COLOR_IS_INDEXED(col)) { /* Convert indexed colors to RGB */ + lookup_colour_palette(state, col->indexed.idx, col); + } + col->type &= VTERM_COLOR_TYPE_MASK; /* Reset any metadata but the type */ +} + +void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright) +{ + state->bold_is_highbright = bold_is_highbright; +} + +INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argcount) +{ + // SGR - ECMA-48 8.3.117 + + int argi = 0; + int value; + + while(argi < argcount) { + // This logic is easier to do 'done' backwards; set it true, and make it + // false again in the 'default' case + int done = 1; + + long arg; + switch(arg = CSI_ARG(args[argi])) { + case CSI_ARG_MISSING: + case 0: // Reset + vterm_state_resetpen(state); + break; + + case 1: { // Bold on + const VTermColor *fg = &state->pen.fg; + state->pen.bold = 1; + setpenattr_bool(state, VTERM_ATTR_BOLD, 1); + if(!VTERM_COLOR_IS_DEFAULT_FG(fg) && VTERM_COLOR_IS_INDEXED(fg) && fg->indexed.idx < 8 && state->bold_is_highbright) + set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, fg->indexed.idx + (state->pen.bold ? 8 : 0)); + break; + } + + case 3: // Italic on + state->pen.italic = 1; + setpenattr_bool(state, VTERM_ATTR_ITALIC, 1); + break; + + case 4: // Underline + state->pen.underline = VTERM_UNDERLINE_SINGLE; + if(CSI_ARG_HAS_MORE(args[argi])) { + argi++; + switch(CSI_ARG(args[argi])) { + case 0: + state->pen.underline = 0; + break; + case 1: + state->pen.underline = VTERM_UNDERLINE_SINGLE; + break; + case 2: + state->pen.underline = VTERM_UNDERLINE_DOUBLE; + break; + case 3: + state->pen.underline = VTERM_UNDERLINE_CURLY; + break; + } + } + setpenattr_int(state, VTERM_ATTR_UNDERLINE, state->pen.underline); + break; + + case 5: // Blink + state->pen.blink = 1; + setpenattr_bool(state, VTERM_ATTR_BLINK, 1); + break; + + case 7: // Reverse on + state->pen.reverse = 1; + setpenattr_bool(state, VTERM_ATTR_REVERSE, 1); + break; + + case 8: // Conceal on + state->pen.conceal = 1; + setpenattr_bool(state, VTERM_ATTR_CONCEAL, 1); + break; + + case 9: // Strikethrough on + state->pen.strike = 1; + setpenattr_bool(state, VTERM_ATTR_STRIKE, 1); + break; + + case 10: case 11: case 12: case 13: case 14: + case 15: case 16: case 17: case 18: case 19: // Select font + state->pen.font = CSI_ARG(args[argi]) - 10; + setpenattr_int(state, VTERM_ATTR_FONT, state->pen.font); + break; + + case 21: // Underline double + state->pen.underline = VTERM_UNDERLINE_DOUBLE; + setpenattr_int(state, VTERM_ATTR_UNDERLINE, state->pen.underline); + break; + + case 22: // Bold off + state->pen.bold = 0; + setpenattr_bool(state, VTERM_ATTR_BOLD, 0); + break; + + case 23: // Italic and Gothic (currently unsupported) off + state->pen.italic = 0; + setpenattr_bool(state, VTERM_ATTR_ITALIC, 0); + break; + + case 24: // Underline off + state->pen.underline = 0; + setpenattr_int(state, VTERM_ATTR_UNDERLINE, 0); + break; + + case 25: // Blink off + state->pen.blink = 0; + setpenattr_bool(state, VTERM_ATTR_BLINK, 0); + break; + + case 27: // Reverse off + state->pen.reverse = 0; + setpenattr_bool(state, VTERM_ATTR_REVERSE, 0); + break; + + case 28: // Conceal off (Reveal) + state->pen.conceal = 0; + setpenattr_bool(state, VTERM_ATTR_CONCEAL, 0); + break; + + case 29: // Strikethrough off + state->pen.strike = 0; + setpenattr_bool(state, VTERM_ATTR_STRIKE, 0); + break; + + case 30: case 31: case 32: case 33: + case 34: case 35: case 36: case 37: // Foreground colour palette + value = CSI_ARG(args[argi]) - 30; + if(state->pen.bold && state->bold_is_highbright) + value += 8; + set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, value); + break; + + case 38: // Foreground colour alternative palette + if(argcount - argi < 1) + return; + argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.fg); + setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->pen.fg); + break; + + case 39: // Foreground colour default + state->pen.fg = state->default_fg; + setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->pen.fg); + break; + + case 40: case 41: case 42: case 43: + case 44: case 45: case 46: case 47: // Background colour palette + value = CSI_ARG(args[argi]) - 40; + set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, value); + break; + + case 48: // Background colour alternative palette + if(argcount - argi < 1) + return; + argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.bg); + setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg); + break; + + case 49: // Default background + state->pen.bg = state->default_bg; + setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg); + break; + + case 73: // Superscript + case 74: // Subscript + case 75: // Superscript/subscript off + state->pen.small = (arg != 75); + state->pen.baseline = + (arg == 73) ? VTERM_BASELINE_RAISE : + (arg == 74) ? VTERM_BASELINE_LOWER : + VTERM_BASELINE_NORMAL; + setpenattr_bool(state, VTERM_ATTR_SMALL, state->pen.small); + setpenattr_int (state, VTERM_ATTR_BASELINE, state->pen.baseline); + break; + + case 90: case 91: case 92: case 93: + case 94: case 95: case 96: case 97: // Foreground colour high-intensity palette + value = CSI_ARG(args[argi]) - 90 + 8; + set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, value); + break; + + case 100: case 101: case 102: case 103: + case 104: case 105: case 106: case 107: // Background colour high-intensity palette + value = CSI_ARG(args[argi]) - 100 + 8; + set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, value); + break; + + default: + done = 0; + break; + } + + if(!done) { + DEBUG_LOG("libvterm: Unhandled CSI SGR %ld\n", arg); + } + + while(CSI_ARG_HAS_MORE(args[argi++])); + } +} + +static int vterm_state_getpen_color(const VTermColor *col, int argi, long args[], int fg) +{ + /* Do nothing if the given color is the default color */ + if (( fg && VTERM_COLOR_IS_DEFAULT_FG(col)) || + (!fg && VTERM_COLOR_IS_DEFAULT_BG(col))) { + return argi; + } + + /* Decide whether to send an indexed color or an RGB color */ + if (VTERM_COLOR_IS_INDEXED(col)) { + const uint8_t idx = col->indexed.idx; + if (idx < 8) { + args[argi++] = (idx + (fg ? 30 : 40)); + } + else if (idx < 16) { + args[argi++] = (idx - 8 + (fg ? 90 : 100)); + } + else { + args[argi++] = CSI_ARG_FLAG_MORE | (fg ? 38 : 48); + args[argi++] = CSI_ARG_FLAG_MORE | 5; + args[argi++] = idx; + } + } + else if (VTERM_COLOR_IS_RGB(col)) { + args[argi++] = CSI_ARG_FLAG_MORE | (fg ? 38 : 48); + args[argi++] = CSI_ARG_FLAG_MORE | 2; + args[argi++] = CSI_ARG_FLAG_MORE | col->rgb.red; + args[argi++] = CSI_ARG_FLAG_MORE | col->rgb.green; + args[argi++] = col->rgb.blue; + } + return argi; +} + +INTERNAL int vterm_state_getpen(VTermState *state, long args[], int argcount) +{ + int argi = 0; + + if(state->pen.bold) + args[argi++] = 1; + + if(state->pen.italic) + args[argi++] = 3; + + if(state->pen.underline == VTERM_UNDERLINE_SINGLE) + args[argi++] = 4; + if(state->pen.underline == VTERM_UNDERLINE_CURLY) + args[argi++] = 4 | CSI_ARG_FLAG_MORE, args[argi++] = 3; + + if(state->pen.blink) + args[argi++] = 5; + + if(state->pen.reverse) + args[argi++] = 7; + + if(state->pen.conceal) + args[argi++] = 8; + + if(state->pen.strike) + args[argi++] = 9; + + if(state->pen.font) + args[argi++] = 10 + state->pen.font; + + if(state->pen.underline == VTERM_UNDERLINE_DOUBLE) + args[argi++] = 21; + + argi = vterm_state_getpen_color(&state->pen.fg, argi, args, true); + + argi = vterm_state_getpen_color(&state->pen.bg, argi, args, false); + + if(state->pen.small) { + if(state->pen.baseline == VTERM_BASELINE_RAISE) + args[argi++] = 73; + else if(state->pen.baseline == VTERM_BASELINE_LOWER) + args[argi++] = 74; + } + + return argi; +} + +int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val) +{ + switch(attr) { + case VTERM_ATTR_BOLD: + val->boolean = state->pen.bold; + return 1; + + case VTERM_ATTR_UNDERLINE: + val->number = state->pen.underline; + return 1; + + case VTERM_ATTR_ITALIC: + val->boolean = state->pen.italic; + return 1; + + case VTERM_ATTR_BLINK: + val->boolean = state->pen.blink; + return 1; + + case VTERM_ATTR_REVERSE: + val->boolean = state->pen.reverse; + return 1; + + case VTERM_ATTR_CONCEAL: + val->boolean = state->pen.conceal; + return 1; + + case VTERM_ATTR_STRIKE: + val->boolean = state->pen.strike; + return 1; + + case VTERM_ATTR_FONT: + val->number = state->pen.font; + return 1; + + case VTERM_ATTR_FOREGROUND: + val->color = state->pen.fg; + return 1; + + case VTERM_ATTR_BACKGROUND: + val->color = state->pen.bg; + return 1; + + case VTERM_ATTR_SMALL: + val->boolean = state->pen.small; + return 1; + + case VTERM_ATTR_BASELINE: + val->number = state->pen.baseline; + return 1; + + case VTERM_ATTR_URI: + val->number = state->pen.uri; + return 1; + + case VTERM_N_ATTRS: + return 0; + } + + return 0; +} + +int vterm_state_set_penattr(VTermState *state, VTermAttr attr, VTermValueType type, VTermValue *val) +{ + if (!val) { + return 0; + } + + if(type != vterm_get_attr_type(attr)) { + DEBUG_LOG("Cannot set attr %d as it has type %d, not type %d\n", + attr, vterm_get_attr_type(attr), type); + return 0; + } + + switch (attr) { + case VTERM_ATTR_BOLD: + state->pen.bold = val->boolean; + break; + case VTERM_ATTR_UNDERLINE: + state->pen.underline = val->number; + break; + case VTERM_ATTR_ITALIC: + state->pen.italic = val->boolean; + break; + case VTERM_ATTR_BLINK: + state->pen.blink = val->boolean; + break; + case VTERM_ATTR_REVERSE: + state->pen.reverse = val->boolean; + break; + case VTERM_ATTR_CONCEAL: + state->pen.conceal = val->boolean; + break; + case VTERM_ATTR_STRIKE: + state->pen.strike = val->boolean; + break; + case VTERM_ATTR_FONT: + state->pen.font = val->number; + break; + case VTERM_ATTR_FOREGROUND: + state->pen.fg = val->color; + break; + case VTERM_ATTR_BACKGROUND: + state->pen.bg = val->color; + break; + case VTERM_ATTR_SMALL: + state->pen.small = val->boolean; + break; + case VTERM_ATTR_BASELINE: + state->pen.baseline = val->number; + break; + case VTERM_ATTR_URI: + state->pen.uri = val->number; + break; + default: + return 0; + } + + if(state->callbacks && state->callbacks->setpenattr) + (*state->callbacks->setpenattr)(attr, val, state->cbdata); + + return 1; +} diff --git a/src/vterm/rect.h b/src/vterm/rect.h new file mode 100644 index 0000000000..2114f24c1b --- /dev/null +++ b/src/vterm/rect.h @@ -0,0 +1,56 @@ +/* + * Some utility functions on VTermRect structures + */ + +#define STRFrect "(%d,%d-%d,%d)" +#define ARGSrect(r) (r).start_row, (r).start_col, (r).end_row, (r).end_col + +/* Expand dst to contain src as well */ +static void rect_expand(VTermRect *dst, VTermRect *src) +{ + if(dst->start_row > src->start_row) dst->start_row = src->start_row; + if(dst->start_col > src->start_col) dst->start_col = src->start_col; + if(dst->end_row < src->end_row) dst->end_row = src->end_row; + if(dst->end_col < src->end_col) dst->end_col = src->end_col; +} + +/* Clip the dst to ensure it does not step outside of bounds */ +static void rect_clip(VTermRect *dst, VTermRect *bounds) +{ + if(dst->start_row < bounds->start_row) dst->start_row = bounds->start_row; + if(dst->start_col < bounds->start_col) dst->start_col = bounds->start_col; + if(dst->end_row > bounds->end_row) dst->end_row = bounds->end_row; + if(dst->end_col > bounds->end_col) dst->end_col = bounds->end_col; + /* Ensure it doesn't end up negatively-sized */ + if(dst->end_row < dst->start_row) dst->end_row = dst->start_row; + if(dst->end_col < dst->start_col) dst->end_col = dst->start_col; +} + +/* True if the two rectangles are equal */ +static int rect_equal(VTermRect *a, VTermRect *b) +{ + return (a->start_row == b->start_row) && + (a->start_col == b->start_col) && + (a->end_row == b->end_row) && + (a->end_col == b->end_col); +} + +/* True if small is contained entirely within big */ +static int rect_contains(VTermRect *big, VTermRect *small) +{ + if(small->start_row < big->start_row) return 0; + if(small->start_col < big->start_col) return 0; + if(small->end_row > big->end_row) return 0; + if(small->end_col > big->end_col) return 0; + return 1; +} + +/* True if the rectangles overlap at all */ +static int rect_intersects(VTermRect *a, VTermRect *b) +{ + if(a->start_row > b->end_row || b->start_row > a->end_row) + return 0; + if(a->start_col > b->end_col || b->start_col > a->end_col) + return 0; + return 1; +} diff --git a/src/vterm/screen.c b/src/vterm/screen.c new file mode 100644 index 0000000000..1f5bb36114 --- /dev/null +++ b/src/vterm/screen.c @@ -0,0 +1,1202 @@ +#include "vterm_internal.h" + +#include <stdio.h> +#include <string.h> +#include "nvim/mbyte.h" +#include "nvim/tui/termkey/termkey.h" + +#include "rect.h" + +#define UNICODE_SPACE 0x20 +#define UNICODE_LINEFEED 0x0a + +#undef DEBUG_REFLOW + +/* State of the pen at some moment in time, also used in a cell */ +typedef struct +{ + /* After the bitfield */ + VTermColor fg, bg; + + /* Opaque ID that maps to a URI in a set */ + int uri; + + unsigned int bold : 1; + unsigned int underline : 2; + unsigned int italic : 1; + unsigned int blink : 1; + unsigned int reverse : 1; + unsigned int conceal : 1; + unsigned int strike : 1; + unsigned int font : 4; /* 0 to 9 */ + unsigned int small : 1; + unsigned int baseline : 2; + + /* Extra state storage that isn't strictly pen-related */ + unsigned int protected_cell : 1; + unsigned int dwl : 1; /* on a DECDWL or DECDHL line */ + unsigned int dhl : 2; /* on a DECDHL line (1=top 2=bottom) */ +} ScreenPen; + +/* Internal representation of a screen cell */ +typedef struct +{ + uint32_t chars[VTERM_MAX_CHARS_PER_CELL]; + ScreenPen pen; +} ScreenCell; + +struct VTermScreen +{ + VTerm *vt; + VTermState *state; + + const VTermScreenCallbacks *callbacks; + void *cbdata; + + VTermDamageSize damage_merge; + /* start_row == -1 => no damage */ + VTermRect damaged; + VTermRect pending_scrollrect; + int pending_scroll_downward, pending_scroll_rightward; + + int rows; + int cols; + + unsigned int global_reverse : 1; + unsigned int reflow : 1; + + /* Primary and Altscreen. buffers[1] is lazily allocated as needed */ + ScreenCell *buffers[2]; + + /* buffer will == buffers[0] or buffers[1], depending on altscreen */ + ScreenCell *buffer; + + /* buffer for a single screen row used in scrollback storage callbacks */ + VTermScreenCell *sb_buffer; + + ScreenPen pen; +}; + +static inline void clearcell(const VTermScreen *screen, ScreenCell *cell) +{ + cell->chars[0] = 0; + cell->pen = screen->pen; +} + +static inline ScreenCell *getcell(const VTermScreen *screen, int row, int col) +{ + if(row < 0 || row >= screen->rows) + return NULL; + if(col < 0 || col >= screen->cols) + return NULL; + return screen->buffer + (screen->cols * row) + col; +} + +static ScreenCell *alloc_buffer(VTermScreen *screen, int rows, int cols) +{ + ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * rows * cols); + + for(int row = 0; row < rows; row++) { + for(int col = 0; col < cols; col++) { + clearcell(screen, &new_buffer[row * cols + col]); + } + } + + return new_buffer; +} + +static void damagerect(VTermScreen *screen, VTermRect rect) +{ + VTermRect emit; + + switch(screen->damage_merge) { + case VTERM_DAMAGE_CELL: + /* Always emit damage event */ + emit = rect; + break; + + case VTERM_DAMAGE_ROW: + /* Emit damage longer than one row. Try to merge with existing damage in + * the same row */ + if(rect.end_row > rect.start_row + 1) { + // Bigger than 1 line - flush existing, emit this + vterm_screen_flush_damage(screen); + emit = rect; + } + else if(screen->damaged.start_row == -1) { + // None stored yet + screen->damaged = rect; + return; + } + else if(rect.start_row == screen->damaged.start_row) { + // Merge with the stored line + if(screen->damaged.start_col > rect.start_col) + screen->damaged.start_col = rect.start_col; + if(screen->damaged.end_col < rect.end_col) + screen->damaged.end_col = rect.end_col; + return; + } + else { + // Emit the currently stored line, store a new one + emit = screen->damaged; + screen->damaged = rect; + } + break; + + case VTERM_DAMAGE_SCREEN: + case VTERM_DAMAGE_SCROLL: + /* Never emit damage event */ + if(screen->damaged.start_row == -1) + screen->damaged = rect; + else { + rect_expand(&screen->damaged, &rect); + } + return; + + default: + DEBUG_LOG("TODO: Maybe merge damage for level %d\n", screen->damage_merge); + return; + } + + if(screen->callbacks && screen->callbacks->damage) + (*screen->callbacks->damage)(emit, screen->cbdata); +} + +static void damagescreen(VTermScreen *screen) +{ + VTermRect rect = { + .start_row = 0, + .end_row = screen->rows, + .start_col = 0, + .end_col = screen->cols, + }; + + damagerect(screen, rect); +} + +static int putglyph(VTermGlyphInfo *info, VTermPos pos, void *user) +{ + VTermScreen *screen = user; + ScreenCell *cell = getcell(screen, pos.row, pos.col); + + if(!cell) + return 0; + + int i; + for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++) { + cell->chars[i] = info->chars[i]; + cell->pen = screen->pen; + } + if(i < VTERM_MAX_CHARS_PER_CELL) + cell->chars[i] = 0; + + for(int col = 1; col < info->width; col++) + getcell(screen, pos.row, pos.col + col)->chars[0] = (uint32_t)-1; + + VTermRect rect = { + .start_row = pos.row, + .end_row = pos.row+1, + .start_col = pos.col, + .end_col = pos.col+info->width, + }; + + cell->pen.protected_cell = info->protected_cell; + cell->pen.dwl = info->dwl; + cell->pen.dhl = info->dhl; + + damagerect(screen, rect); + + return 1; +} + +static void sb_pushline_from_row(VTermScreen *screen, int row) +{ + VTermPos pos = { .row = row }; + for(pos.col = 0; pos.col < screen->cols; pos.col++) + vterm_screen_get_cell(screen, pos, screen->sb_buffer + pos.col); + + (screen->callbacks->sb_pushline)(screen->cols, screen->sb_buffer, screen->cbdata); +} + +static int moverect_internal(VTermRect dest, VTermRect src, void *user) +{ + VTermScreen *screen = user; + + if(screen->callbacks && screen->callbacks->sb_pushline && + dest.start_row == 0 && dest.start_col == 0 && // starts top-left corner + dest.end_col == screen->cols && // full width + screen->buffer == screen->buffers[BUFIDX_PRIMARY]) { // not altscreen + for(int row = 0; row < src.start_row; row++) + sb_pushline_from_row(screen, row); + } + + int cols = src.end_col - src.start_col; + int downward = src.start_row - dest.start_row; + + int init_row, test_row, inc_row; + if(downward < 0) { + init_row = dest.end_row - 1; + test_row = dest.start_row - 1; + inc_row = -1; + } + else { + init_row = dest.start_row; + test_row = dest.end_row; + inc_row = +1; + } + + for(int row = init_row; row != test_row; row += inc_row) + memmove(getcell(screen, row, dest.start_col), + getcell(screen, row + downward, src.start_col), + cols * sizeof(ScreenCell)); + + return 1; +} + +static int moverect_user(VTermRect dest, VTermRect src, void *user) +{ + VTermScreen *screen = user; + + if(screen->callbacks && screen->callbacks->moverect) { + if(screen->damage_merge != VTERM_DAMAGE_SCROLL) + // Avoid an infinite loop + vterm_screen_flush_damage(screen); + + if((*screen->callbacks->moverect)(dest, src, screen->cbdata)) + return 1; + } + + damagerect(screen, dest); + + return 1; +} + +static int erase_internal(VTermRect rect, int selective, void *user) +{ + VTermScreen *screen = user; + + for(int row = rect.start_row; row < screen->state->rows && row < rect.end_row; row++) { + const VTermLineInfo *info = vterm_state_get_lineinfo(screen->state, row); + + for(int col = rect.start_col; col < rect.end_col; col++) { + ScreenCell *cell = getcell(screen, row, col); + + if(selective && cell->pen.protected_cell) + continue; + + cell->chars[0] = 0; + cell->pen = (ScreenPen){ + /* Only copy .fg and .bg; leave things like rv in reset state */ + .fg = screen->pen.fg, + .bg = screen->pen.bg, + }; + cell->pen.dwl = info->doublewidth; + cell->pen.dhl = info->doubleheight; + } + } + + return 1; +} + +static int erase_user(VTermRect rect, int selective, void *user) +{ + VTermScreen *screen = user; + + damagerect(screen, rect); + + return 1; +} + +static int erase(VTermRect rect, int selective, void *user) +{ + erase_internal(rect, selective, user); + return erase_user(rect, 0, user); +} + +static int scrollrect(VTermRect rect, int downward, int rightward, void *user) +{ + VTermScreen *screen = user; + + if(screen->damage_merge != VTERM_DAMAGE_SCROLL) { + vterm_scroll_rect(rect, downward, rightward, + moverect_internal, erase_internal, screen); + + vterm_screen_flush_damage(screen); + + vterm_scroll_rect(rect, downward, rightward, + moverect_user, erase_user, screen); + + return 1; + } + + if(screen->damaged.start_row != -1 && + !rect_intersects(&rect, &screen->damaged)) { + vterm_screen_flush_damage(screen); + } + + if(screen->pending_scrollrect.start_row == -1) { + screen->pending_scrollrect = rect; + screen->pending_scroll_downward = downward; + screen->pending_scroll_rightward = rightward; + } + else if(rect_equal(&screen->pending_scrollrect, &rect) && + ((screen->pending_scroll_downward == 0 && downward == 0) || + (screen->pending_scroll_rightward == 0 && rightward == 0))) { + screen->pending_scroll_downward += downward; + screen->pending_scroll_rightward += rightward; + } + else { + vterm_screen_flush_damage(screen); + + screen->pending_scrollrect = rect; + screen->pending_scroll_downward = downward; + screen->pending_scroll_rightward = rightward; + } + + vterm_scroll_rect(rect, downward, rightward, + moverect_internal, erase_internal, screen); + + if(screen->damaged.start_row == -1) + return 1; + + if(rect_contains(&rect, &screen->damaged)) { + /* Scroll region entirely contains the damage; just move it */ + vterm_rect_move(&screen->damaged, -downward, -rightward); + rect_clip(&screen->damaged, &rect); + } + /* There are a number of possible cases here, but lets restrict this to only + * the common case where we might actually gain some performance by + * optimising it. Namely, a vertical scroll that neatly cuts the damage + * region in half. + */ + else if(rect.start_col <= screen->damaged.start_col && + rect.end_col >= screen->damaged.end_col && + rightward == 0) { + if(screen->damaged.start_row >= rect.start_row && + screen->damaged.start_row < rect.end_row) { + screen->damaged.start_row -= downward; + if(screen->damaged.start_row < rect.start_row) + screen->damaged.start_row = rect.start_row; + if(screen->damaged.start_row > rect.end_row) + screen->damaged.start_row = rect.end_row; + } + if(screen->damaged.end_row >= rect.start_row && + screen->damaged.end_row < rect.end_row) { + screen->damaged.end_row -= downward; + if(screen->damaged.end_row < rect.start_row) + screen->damaged.end_row = rect.start_row; + if(screen->damaged.end_row > rect.end_row) + screen->damaged.end_row = rect.end_row; + } + } + else { + DEBUG_LOG("TODO: Just flush and redo damaged=" STRFrect " rect=" STRFrect "\n", + ARGSrect(screen->damaged), ARGSrect(rect)); + } + + return 1; +} + +static int movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user) +{ + VTermScreen *screen = user; + + if(screen->callbacks && screen->callbacks->movecursor) + return (*screen->callbacks->movecursor)(pos, oldpos, visible, screen->cbdata); + + return 0; +} + +static int setpenattr(VTermAttr attr, VTermValue *val, void *user) +{ + VTermScreen *screen = user; + + switch(attr) { + case VTERM_ATTR_BOLD: + screen->pen.bold = val->boolean; + return 1; + case VTERM_ATTR_UNDERLINE: + screen->pen.underline = val->number; + return 1; + case VTERM_ATTR_ITALIC: + screen->pen.italic = val->boolean; + return 1; + case VTERM_ATTR_BLINK: + screen->pen.blink = val->boolean; + return 1; + case VTERM_ATTR_REVERSE: + screen->pen.reverse = val->boolean; + return 1; + case VTERM_ATTR_CONCEAL: + screen->pen.conceal = val->boolean; + return 1; + case VTERM_ATTR_STRIKE: + screen->pen.strike = val->boolean; + return 1; + case VTERM_ATTR_FONT: + screen->pen.font = val->number; + return 1; + case VTERM_ATTR_FOREGROUND: + screen->pen.fg = val->color; + return 1; + case VTERM_ATTR_BACKGROUND: + screen->pen.bg = val->color; + return 1; + case VTERM_ATTR_SMALL: + screen->pen.small = val->boolean; + return 1; + case VTERM_ATTR_BASELINE: + screen->pen.baseline = val->number; + return 1; + case VTERM_ATTR_URI: + screen->pen.uri = val->number; + return 1; + + case VTERM_N_ATTRS: + return 0; + } + + return 0; +} + +static int settermprop(VTermProp prop, VTermValue *val, void *user) +{ + VTermScreen *screen = user; + + switch(prop) { + case VTERM_PROP_ALTSCREEN: + if(val->boolean && !screen->buffers[BUFIDX_ALTSCREEN]) + return 0; + + screen->buffer = val->boolean ? screen->buffers[BUFIDX_ALTSCREEN] : screen->buffers[BUFIDX_PRIMARY]; + /* only send a damage event on disable; because during enable there's an + * erase that sends a damage anyway + */ + if(!val->boolean) + damagescreen(screen); + break; + case VTERM_PROP_REVERSE: + screen->global_reverse = val->boolean; + damagescreen(screen); + break; + default: + ; /* ignore */ + } + + if(screen->callbacks && screen->callbacks->settermprop) + return (*screen->callbacks->settermprop)(prop, val, screen->cbdata); + + return 1; +} + +static int bell(void *user) +{ + VTermScreen *screen = user; + + if(screen->callbacks && screen->callbacks->bell) + return (*screen->callbacks->bell)(screen->cbdata); + + return 0; +} + +/* How many cells are non-blank + * Returns the position of the first blank cell in the trailing blank end */ +static int line_popcount(ScreenCell *buffer, int row, int rows, int cols) +{ + int col = cols - 1; + while(col >= 0 && buffer[row * cols + col].chars[0] == 0) + col--; + return col + 1; +} + +static void resize_buffer(VTermScreen *screen, int bufidx, int new_rows, int new_cols, bool active, VTermStateFields *statefields) +{ + int old_rows = screen->rows; + int old_cols = screen->cols; + + ScreenCell *old_buffer = screen->buffers[bufidx]; + VTermLineInfo *old_lineinfo = statefields->lineinfos[bufidx]; + + ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * new_rows * new_cols); + VTermLineInfo *new_lineinfo = vterm_allocator_malloc(screen->vt, sizeof(new_lineinfo[0]) * new_rows); + + int old_row = old_rows - 1; + int new_row = new_rows - 1; + + VTermPos old_cursor = statefields->pos; + VTermPos new_cursor = { -1, -1 }; + +#ifdef DEBUG_REFLOW + fprintf(stderr, "Resizing from %dx%d to %dx%d; cursor was at (%d,%d)\n", + old_cols, old_rows, new_cols, new_rows, old_cursor.col, old_cursor.row); +#endif + + /* Keep track of the final row that is knonw to be blank, so we know what + * spare space we have for scrolling into + */ + int final_blank_row = new_rows; + + while(old_row >= 0) { + int old_row_end = old_row; + /* TODO: Stop if dwl or dhl */ + while(screen->reflow && old_lineinfo && old_row > 0 && old_lineinfo[old_row].continuation) + old_row--; + int old_row_start = old_row; + + int width = 0; + for(int row = old_row_start; row <= old_row_end; row++) { + if(screen->reflow && row < (old_rows - 1) && old_lineinfo[row + 1].continuation) + width += old_cols; + else + width += line_popcount(old_buffer, row, old_rows, old_cols); + } + + if(final_blank_row == (new_row + 1) && width == 0) + final_blank_row = new_row; + + int new_height = screen->reflow + ? width ? (width + new_cols - 1) / new_cols : 1 + : 1; + + int new_row_end = new_row; + int new_row_start = new_row - new_height + 1; + + old_row = old_row_start; + int old_col = 0; + + int spare_rows = new_rows - final_blank_row; + + if(new_row_start < 0 && /* we'd fall off the top */ + spare_rows >= 0 && /* we actually have spare rows */ + (!active || new_cursor.row == -1 || (new_cursor.row - new_row_start) < new_rows)) + { + /* Attempt to scroll content down into the blank rows at the bottom to + * make it fit + */ + int downwards = -new_row_start; + if(downwards > spare_rows) + downwards = spare_rows; + int rowcount = new_rows - downwards; + +#ifdef DEBUG_REFLOW + fprintf(stderr, " scroll %d rows +%d downwards\n", rowcount, downwards); +#endif + + memmove(&new_buffer[downwards * new_cols], &new_buffer[0], (unsigned long) rowcount * new_cols * sizeof(ScreenCell)); + memmove(&new_lineinfo[downwards], &new_lineinfo[0], rowcount * sizeof(new_lineinfo[0])); + + new_row += downwards; + new_row_start += downwards; + new_row_end += downwards; + + if(new_cursor.row >= 0) + new_cursor.row += downwards; + + final_blank_row += downwards; + } + +#ifdef DEBUG_REFLOW + fprintf(stderr, " rows [%d..%d] <- [%d..%d] width=%d\n", + new_row_start, new_row_end, old_row_start, old_row_end, width); +#endif + + if(new_row_start < 0) { + if(old_row_start <= old_cursor.row && old_cursor.row <= old_row_end) { + new_cursor.row = 0; + new_cursor.col = old_cursor.col; + if(new_cursor.col >= new_cols) + new_cursor.col = new_cols-1; + } + break; + } + + for(new_row = new_row_start, old_row = old_row_start; new_row <= new_row_end; new_row++) { + int count = width >= new_cols ? new_cols : width; + width -= count; + + int new_col = 0; + + while(count) { + /* TODO: This could surely be done a lot faster by memcpy()'ing the entire range */ + new_buffer[new_row * new_cols + new_col] = old_buffer[old_row * old_cols + old_col]; + + if(old_cursor.row == old_row && old_cursor.col == old_col) + new_cursor.row = new_row, new_cursor.col = new_col; + + old_col++; + if(old_col == old_cols) { + old_row++; + + if(!screen->reflow) { + new_col++; + break; + } + old_col = 0; + } + + new_col++; + count--; + } + + if(old_cursor.row == old_row && old_cursor.col >= old_col) { + new_cursor.row = new_row, new_cursor.col = (old_cursor.col - old_col + new_col); + if(new_cursor.col >= new_cols) + new_cursor.col = new_cols-1; + } + + while(new_col < new_cols) { + clearcell(screen, &new_buffer[new_row * new_cols + new_col]); + new_col++; + } + + new_lineinfo[new_row].continuation = (new_row > new_row_start); + } + + old_row = old_row_start - 1; + new_row = new_row_start - 1; + } + + if(old_cursor.row <= old_row) { + /* cursor would have moved entirely off the top of the screen; lets just + * bring it within range */ + new_cursor.row = 0, new_cursor.col = old_cursor.col; + if(new_cursor.col >= new_cols) + new_cursor.col = new_cols-1; + } + + /* We really expect the cursor position to be set by now */ + if(active && (new_cursor.row == -1 || new_cursor.col == -1)) { + fprintf(stderr, "screen_resize failed to update cursor position\n"); + abort(); + } + + if(old_row >= 0 && bufidx == BUFIDX_PRIMARY) { + /* Push spare lines to scrollback buffer */ + if(screen->callbacks && screen->callbacks->sb_pushline) + for(int row = 0; row <= old_row; row++) + sb_pushline_from_row(screen, row); + if(active) + statefields->pos.row -= (old_row + 1); + } + if(new_row >= 0 && bufidx == BUFIDX_PRIMARY && + screen->callbacks && screen->callbacks->sb_popline) { + /* Try to backfill rows by popping scrollback buffer */ + while(new_row >= 0) { + if(!(screen->callbacks->sb_popline(old_cols, screen->sb_buffer, screen->cbdata))) + break; + + VTermPos pos = { .row = new_row }; + for(pos.col = 0; pos.col < old_cols && pos.col < new_cols; pos.col += screen->sb_buffer[pos.col].width) { + VTermScreenCell *src = &screen->sb_buffer[pos.col]; + ScreenCell *dst = &new_buffer[pos.row * new_cols + pos.col]; + + for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) { + dst->chars[i] = src->chars[i]; + if(!src->chars[i]) + break; + } + + dst->pen.bold = src->attrs.bold; + dst->pen.underline = src->attrs.underline; + dst->pen.italic = src->attrs.italic; + dst->pen.blink = src->attrs.blink; + dst->pen.reverse = src->attrs.reverse ^ screen->global_reverse; + dst->pen.conceal = src->attrs.conceal; + dst->pen.strike = src->attrs.strike; + dst->pen.font = src->attrs.font; + dst->pen.small = src->attrs.small; + dst->pen.baseline = src->attrs.baseline; + + dst->pen.fg = src->fg; + dst->pen.bg = src->bg; + + dst->pen.uri = src->uri; + + if(src->width == 2 && pos.col < (new_cols-1)) + (dst + 1)->chars[0] = (uint32_t) -1; + } + for( ; pos.col < new_cols; pos.col++) + clearcell(screen, &new_buffer[pos.row * new_cols + pos.col]); + new_row--; + + if(active) + statefields->pos.row++; + } + } + if(new_row >= 0) { + /* Scroll new rows back up to the top and fill in blanks at the bottom */ + int moverows = new_rows - new_row - 1; + memmove(&new_buffer[0], &new_buffer[(new_row + 1) * new_cols], (unsigned long) moverows * new_cols * sizeof(ScreenCell)); + memmove(&new_lineinfo[0], &new_lineinfo[new_row + 1], moverows * sizeof(new_lineinfo[0])); + + new_cursor.row -= (new_row + 1); + + for(new_row = moverows; new_row < new_rows; new_row++) { + for(int col = 0; col < new_cols; col++) + clearcell(screen, &new_buffer[new_row * new_cols + col]); + new_lineinfo[new_row] = (VTermLineInfo){ 0 }; + } + } + + vterm_allocator_free(screen->vt, old_buffer); + screen->buffers[bufidx] = new_buffer; + + vterm_allocator_free(screen->vt, old_lineinfo); + statefields->lineinfos[bufidx] = new_lineinfo; + + if(active) + statefields->pos = new_cursor; + + return; +} + +static int resize(int new_rows, int new_cols, VTermStateFields *fields, void *user) +{ + VTermScreen *screen = user; + + int altscreen_active = (screen->buffers[BUFIDX_ALTSCREEN] && screen->buffer == screen->buffers[BUFIDX_ALTSCREEN]); + + int old_rows = screen->rows; + int old_cols = screen->cols; + + if(new_cols > old_cols) { + /* Ensure that ->sb_buffer is large enough for a new or and old row */ + if(screen->sb_buffer) + vterm_allocator_free(screen->vt, screen->sb_buffer); + + screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols); + } + + resize_buffer(screen, 0, new_rows, new_cols, !altscreen_active, fields); + if(screen->buffers[BUFIDX_ALTSCREEN]) + resize_buffer(screen, 1, new_rows, new_cols, altscreen_active, fields); + else if(new_rows != old_rows) { + /* We don't need a full resize of the altscreen because it isn't enabled + * but we should at least keep the lineinfo the right size */ + vterm_allocator_free(screen->vt, fields->lineinfos[BUFIDX_ALTSCREEN]); + + VTermLineInfo *new_lineinfo = vterm_allocator_malloc(screen->vt, sizeof(new_lineinfo[0]) * new_rows); + for(int row = 0; row < new_rows; row++) + new_lineinfo[row] = (VTermLineInfo){ 0 }; + + fields->lineinfos[BUFIDX_ALTSCREEN] = new_lineinfo; + } + + screen->buffer = altscreen_active ? screen->buffers[BUFIDX_ALTSCREEN] : screen->buffers[BUFIDX_PRIMARY]; + + screen->rows = new_rows; + screen->cols = new_cols; + + if(new_cols <= old_cols) { + if(screen->sb_buffer) + vterm_allocator_free(screen->vt, screen->sb_buffer); + + screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols); + } + + /* TODO: Maaaaybe we can optimise this if there's no reflow happening */ + damagescreen(screen); + + if(screen->callbacks && screen->callbacks->resize) + return (*screen->callbacks->resize)(new_rows, new_cols, screen->cbdata); + + return 1; +} + +static int setlineinfo(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user) +{ + VTermScreen *screen = user; + + if(newinfo->doublewidth != oldinfo->doublewidth || + newinfo->doubleheight != oldinfo->doubleheight) { + for(int col = 0; col < screen->cols; col++) { + ScreenCell *cell = getcell(screen, row, col); + cell->pen.dwl = newinfo->doublewidth; + cell->pen.dhl = newinfo->doubleheight; + } + + VTermRect rect = { + .start_row = row, + .end_row = row + 1, + .start_col = 0, + .end_col = newinfo->doublewidth ? screen->cols / 2 : screen->cols, + }; + damagerect(screen, rect); + + if(newinfo->doublewidth) { + rect.start_col = screen->cols / 2; + rect.end_col = screen->cols; + + erase_internal(rect, 0, user); + } + } + + return 1; +} + +static int sb_clear(void *user) { + VTermScreen *screen = user; + + if(screen->callbacks && screen->callbacks->sb_clear) + if((*screen->callbacks->sb_clear)(screen->cbdata)) + return 1; + + return 0; +} + +static VTermStateCallbacks state_cbs = { + .putglyph = &putglyph, + .movecursor = &movecursor, + .scrollrect = &scrollrect, + .erase = &erase, + .setpenattr = &setpenattr, + .settermprop = &settermprop, + .bell = &bell, + .resize = &resize, + .setlineinfo = &setlineinfo, + .sb_clear = &sb_clear, +}; + +static VTermScreen *screen_new(VTerm *vt) +{ + VTermState *state = vterm_obtain_state(vt); + if(!state) + return NULL; + + VTermScreen *screen = vterm_allocator_malloc(vt, sizeof(VTermScreen)); + int rows, cols; + + vterm_get_size(vt, &rows, &cols); + + screen->vt = vt; + screen->state = state; + + screen->damage_merge = VTERM_DAMAGE_CELL; + screen->damaged.start_row = -1; + screen->pending_scrollrect.start_row = -1; + + screen->rows = rows; + screen->cols = cols; + + screen->global_reverse = false; + screen->reflow = false; + + screen->callbacks = NULL; + screen->cbdata = NULL; + + screen->buffers[BUFIDX_PRIMARY] = alloc_buffer(screen, rows, cols); + + screen->buffer = screen->buffers[BUFIDX_PRIMARY]; + + screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * cols); + + vterm_state_set_callbacks(screen->state, &state_cbs, screen); + + return screen; +} + +INTERNAL void vterm_screen_free(VTermScreen *screen) +{ + vterm_allocator_free(screen->vt, screen->buffers[BUFIDX_PRIMARY]); + if(screen->buffers[BUFIDX_ALTSCREEN]) + vterm_allocator_free(screen->vt, screen->buffers[BUFIDX_ALTSCREEN]); + + vterm_allocator_free(screen->vt, screen->sb_buffer); + + vterm_allocator_free(screen->vt, screen); +} + +void vterm_screen_reset(VTermScreen *screen, int hard) +{ + screen->damaged.start_row = -1; + screen->pending_scrollrect.start_row = -1; + vterm_state_reset(screen->state, hard); + vterm_screen_flush_damage(screen); +} + +static size_t _get_chars(const VTermScreen *screen, const int utf8, void *buffer, size_t len, const VTermRect rect) +{ + size_t outpos = 0; + int padding = 0; + +#define PUT(c) \ + if(utf8) { \ + size_t thislen = utf_char2len(c); \ + if(buffer && outpos + thislen <= len) \ + outpos += fill_utf8((c), (char *)buffer + outpos); \ + else \ + outpos += thislen; \ + } \ + else { \ + if(buffer && outpos + 1 <= len) \ + ((uint32_t*)buffer)[outpos++] = (c); \ + else \ + outpos++; \ + } + + for(int row = rect.start_row; row < rect.end_row; row++) { + for(int col = rect.start_col; col < rect.end_col; col++) { + ScreenCell *cell = getcell(screen, row, col); + + if(cell->chars[0] == 0) + // Erased cell, might need a space + padding++; + else if(cell->chars[0] == (uint32_t)-1) + // Gap behind a double-width char, do nothing + ; + else { + while(padding) { + PUT(UNICODE_SPACE); + padding--; + } + for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) { + PUT(cell->chars[i]); + } + } + } + + if(row < rect.end_row - 1) { + PUT(UNICODE_LINEFEED); + padding = 0; + } + } + + return outpos; +} + +size_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect) +{ + return _get_chars(screen, 0, chars, len, rect); +} + +size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect) +{ + return _get_chars(screen, 1, str, len, rect); +} + +/* Copy internal to external representation of a screen cell */ +int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell) +{ + ScreenCell *intcell = getcell(screen, pos.row, pos.col); + if(!intcell) + return 0; + + for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) { + cell->chars[i] = intcell->chars[i]; + if(!intcell->chars[i]) + break; + } + + cell->attrs.bold = intcell->pen.bold; + cell->attrs.underline = intcell->pen.underline; + cell->attrs.italic = intcell->pen.italic; + cell->attrs.blink = intcell->pen.blink; + cell->attrs.reverse = intcell->pen.reverse ^ screen->global_reverse; + cell->attrs.conceal = intcell->pen.conceal; + cell->attrs.strike = intcell->pen.strike; + cell->attrs.font = intcell->pen.font; + cell->attrs.small = intcell->pen.small; + cell->attrs.baseline = intcell->pen.baseline; + + cell->attrs.dwl = intcell->pen.dwl; + cell->attrs.dhl = intcell->pen.dhl; + + cell->fg = intcell->pen.fg; + cell->bg = intcell->pen.bg; + + cell->uri = intcell->pen.uri; + + if(pos.col < (screen->cols - 1) && + getcell(screen, pos.row, pos.col + 1)->chars[0] == (uint32_t)-1) + cell->width = 2; + else + cell->width = 1; + + return 1; +} + +int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos) +{ + /* This cell is EOL if this and every cell to the right is black */ + for(; pos.col < screen->cols; pos.col++) { + ScreenCell *cell = getcell(screen, pos.row, pos.col); + if(cell->chars[0] != 0) + return 0; + } + + return 1; +} + +VTermScreen *vterm_obtain_screen(VTerm *vt) +{ + if(vt->screen) + return vt->screen; + + VTermScreen *screen = screen_new(vt); + vt->screen = screen; + + return screen; +} + +void vterm_screen_enable_reflow(VTermScreen *screen, bool reflow) +{ + screen->reflow = reflow; +} + +#undef vterm_screen_set_reflow +void vterm_screen_set_reflow(VTermScreen *screen, bool reflow) +{ + vterm_screen_enable_reflow(screen, reflow); +} + +void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen) +{ + if(!screen->buffers[BUFIDX_ALTSCREEN] && altscreen) { + int rows, cols; + vterm_get_size(screen->vt, &rows, &cols); + + screen->buffers[BUFIDX_ALTSCREEN] = alloc_buffer(screen, rows, cols); + } +} + +void vterm_screen_set_callbacks(VTermScreen *screen, const VTermScreenCallbacks *callbacks, void *user) +{ + screen->callbacks = callbacks; + screen->cbdata = user; +} + +void *vterm_screen_get_cbdata(VTermScreen *screen) +{ + return screen->cbdata; +} + +void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermStateFallbacks *fallbacks, void *user) +{ + vterm_state_set_unrecognised_fallbacks(screen->state, fallbacks, user); +} + +void *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen) +{ + return vterm_state_get_unrecognised_fbdata(screen->state); +} + +void vterm_screen_flush_damage(VTermScreen *screen) +{ + if(screen->pending_scrollrect.start_row != -1) { + vterm_scroll_rect(screen->pending_scrollrect, screen->pending_scroll_downward, screen->pending_scroll_rightward, + moverect_user, erase_user, screen); + + screen->pending_scrollrect.start_row = -1; + } + + if(screen->damaged.start_row != -1) { + if(screen->callbacks && screen->callbacks->damage) + (*screen->callbacks->damage)(screen->damaged, screen->cbdata); + + screen->damaged.start_row = -1; + } +} + +void vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size) +{ + vterm_screen_flush_damage(screen); + screen->damage_merge = size; +} + +static int attrs_differ(VTermAttrMask attrs, ScreenCell *a, ScreenCell *b) +{ + if((attrs & VTERM_ATTR_BOLD_MASK) && (a->pen.bold != b->pen.bold)) + return 1; + if((attrs & VTERM_ATTR_UNDERLINE_MASK) && (a->pen.underline != b->pen.underline)) + return 1; + if((attrs & VTERM_ATTR_ITALIC_MASK) && (a->pen.italic != b->pen.italic)) + return 1; + if((attrs & VTERM_ATTR_BLINK_MASK) && (a->pen.blink != b->pen.blink)) + return 1; + if((attrs & VTERM_ATTR_REVERSE_MASK) && (a->pen.reverse != b->pen.reverse)) + return 1; + if((attrs & VTERM_ATTR_CONCEAL_MASK) && (a->pen.conceal != b->pen.conceal)) + return 1; + if((attrs & VTERM_ATTR_STRIKE_MASK) && (a->pen.strike != b->pen.strike)) + return 1; + if((attrs & VTERM_ATTR_FONT_MASK) && (a->pen.font != b->pen.font)) + return 1; + if((attrs & VTERM_ATTR_FOREGROUND_MASK) && !vterm_color_is_equal(&a->pen.fg, &b->pen.fg)) + return 1; + if((attrs & VTERM_ATTR_BACKGROUND_MASK) && !vterm_color_is_equal(&a->pen.bg, &b->pen.bg)) + return 1; + if((attrs & VTERM_ATTR_SMALL_MASK) && (a->pen.small != b->pen.small)) + return 1; + if((attrs & VTERM_ATTR_BASELINE_MASK) && (a->pen.baseline != b->pen.baseline)) + return 1; + if((attrs & VTERM_ATTR_URI_MASK) && (a->pen.uri != b->pen.uri)) + return 1; + + return 0; +} + +int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs) +{ + ScreenCell *target = getcell(screen, pos.row, pos.col); + + // TODO: bounds check + extent->start_row = pos.row; + extent->end_row = pos.row + 1; + + if(extent->start_col < 0) + extent->start_col = 0; + if(extent->end_col < 0) + extent->end_col = screen->cols; + + int col; + + for(col = pos.col - 1; col >= extent->start_col; col--) + if(attrs_differ(attrs, target, getcell(screen, pos.row, col))) + break; + extent->start_col = col + 1; + + for(col = pos.col + 1; col < extent->end_col; col++) + if(attrs_differ(attrs, target, getcell(screen, pos.row, col))) + break; + extent->end_col = col - 1; + + return 1; +} + +void vterm_screen_convert_color_to_rgb(const VTermScreen *screen, VTermColor *col) +{ + vterm_state_convert_color_to_rgb(screen->state, col); +} + +static void reset_default_colours(VTermScreen *screen, ScreenCell *buffer) +{ + for(int row = 0; row <= screen->rows - 1; row++) + for(int col = 0; col <= screen->cols - 1; col++) { + ScreenCell *cell = &buffer[row * screen->cols + col]; + if(VTERM_COLOR_IS_DEFAULT_FG(&cell->pen.fg)) + cell->pen.fg = screen->pen.fg; + if(VTERM_COLOR_IS_DEFAULT_BG(&cell->pen.bg)) + cell->pen.bg = screen->pen.bg; + } +} + +void vterm_screen_set_default_colors(VTermScreen *screen, const VTermColor *default_fg, const VTermColor *default_bg) +{ + vterm_state_set_default_colors(screen->state, default_fg, default_bg); + + if(default_fg && VTERM_COLOR_IS_DEFAULT_FG(&screen->pen.fg)) { + screen->pen.fg = *default_fg; + screen->pen.fg.type = (screen->pen.fg.type & ~VTERM_COLOR_DEFAULT_MASK) + | VTERM_COLOR_DEFAULT_FG; + } + + if(default_bg && VTERM_COLOR_IS_DEFAULT_BG(&screen->pen.bg)) { + screen->pen.bg = *default_bg; + screen->pen.bg.type = (screen->pen.bg.type & ~VTERM_COLOR_DEFAULT_MASK) + | VTERM_COLOR_DEFAULT_BG; + } + + reset_default_colours(screen, screen->buffers[0]); + if(screen->buffers[1]) + reset_default_colours(screen, screen->buffers[1]); +} diff --git a/src/vterm/state.c b/src/vterm/state.c new file mode 100644 index 0000000000..e09b39436a --- /dev/null +++ b/src/vterm/state.c @@ -0,0 +1,2347 @@ +#include "vterm_internal.h" + +#include <stdio.h> +#include <string.h> + +#define strneq(a,b,n) (strncmp(a,b,n)==0) + +#if defined(DEBUG) && DEBUG > 1 +# define DEBUG_GLYPH_COMBINE +#endif + +/* Some convenient wrappers to make callback functions easier */ + +static void putglyph(VTermState *state, const uint32_t chars[], int width, VTermPos pos) +{ + VTermGlyphInfo info = { + .chars = chars, + .width = width, + .protected_cell = state->protected_cell, + .dwl = state->lineinfo[pos.row].doublewidth, + .dhl = state->lineinfo[pos.row].doubleheight, + }; + + if(state->callbacks && state->callbacks->putglyph) + if((*state->callbacks->putglyph)(&info, pos, state->cbdata)) + return; + + DEBUG_LOG("libvterm: Unhandled putglyph U+%04x at (%d,%d)\n", chars[0], pos.col, pos.row); +} + +static void updatecursor(VTermState *state, VTermPos *oldpos, int cancel_phantom) +{ + if(state->pos.col == oldpos->col && state->pos.row == oldpos->row) + return; + + if(cancel_phantom) + state->at_phantom = 0; + + if(state->callbacks && state->callbacks->movecursor) + if((*state->callbacks->movecursor)(state->pos, *oldpos, state->mode.cursor_visible, state->cbdata)) + return; +} + +static void erase(VTermState *state, VTermRect rect, int selective) +{ + if(rect.end_col == state->cols) { + /* If we're erasing the final cells of any lines, cancel the continuation + * marker on the subsequent line + */ + for(int row = rect.start_row + 1; row < rect.end_row + 1 && row < state->rows; row++) + state->lineinfo[row].continuation = 0; + } + + if(state->callbacks && state->callbacks->erase) + if((*state->callbacks->erase)(rect, selective, state->cbdata)) + return; +} + +static VTermState *vterm_state_new(VTerm *vt) +{ + VTermState *state = vterm_allocator_malloc(vt, sizeof(VTermState)); + + state->vt = vt; + + state->rows = vt->rows; + state->cols = vt->cols; + + state->mouse_col = 0; + state->mouse_row = 0; + state->mouse_buttons = 0; + + state->mouse_protocol = MOUSE_X10; + + state->callbacks = NULL; + state->cbdata = NULL; + + state->selection.callbacks = NULL; + state->selection.user = NULL; + state->selection.buffer = NULL; + + vterm_state_newpen(state); + + state->bold_is_highbright = 0; + + state->combine_chars_size = 16; + state->combine_chars = vterm_allocator_malloc(state->vt, state->combine_chars_size * sizeof(state->combine_chars[0])); + + state->tabstops = vterm_allocator_malloc(state->vt, (state->cols + 7) / 8); + + state->lineinfos[BUFIDX_PRIMARY] = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo)); + /* TODO: Make an 'enable' function */ + state->lineinfos[BUFIDX_ALTSCREEN] = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo)); + state->lineinfo = state->lineinfos[BUFIDX_PRIMARY]; + + state->encoding_utf8.enc = vterm_lookup_encoding(ENC_UTF8, 'u'); + if(*state->encoding_utf8.enc->init) + (*state->encoding_utf8.enc->init)(state->encoding_utf8.enc, state->encoding_utf8.data); + + return state; +} + +INTERNAL void vterm_state_free(VTermState *state) +{ + vterm_allocator_free(state->vt, state->tabstops); + vterm_allocator_free(state->vt, state->lineinfos[BUFIDX_PRIMARY]); + if(state->lineinfos[BUFIDX_ALTSCREEN]) + vterm_allocator_free(state->vt, state->lineinfos[BUFIDX_ALTSCREEN]); + vterm_allocator_free(state->vt, state->combine_chars); + vterm_allocator_free(state->vt, state); +} + +static void scroll(VTermState *state, VTermRect rect, int downward, int rightward) +{ + if(!downward && !rightward) + return; + + int rows = rect.end_row - rect.start_row; + if(downward > rows) + downward = rows; + else if(downward < -rows) + downward = -rows; + + int cols = rect.end_col - rect.start_col; + if(rightward > cols) + rightward = cols; + else if(rightward < -cols) + rightward = -cols; + + // Update lineinfo if full line + if(rect.start_col == 0 && rect.end_col == state->cols && rightward == 0) { + int height = rect.end_row - rect.start_row - abs(downward); + + if(downward > 0) { + memmove(state->lineinfo + rect.start_row, + state->lineinfo + rect.start_row + downward, + height * sizeof(state->lineinfo[0])); + for(int row = rect.end_row - downward; row < rect.end_row; row++) + state->lineinfo[row] = (VTermLineInfo){ 0 }; + } + else { + memmove(state->lineinfo + rect.start_row - downward, + state->lineinfo + rect.start_row, + height * sizeof(state->lineinfo[0])); + for(int row = rect.start_row; row < rect.start_row - downward; row++) + state->lineinfo[row] = (VTermLineInfo){ 0 }; + } + } + + if(state->callbacks && state->callbacks->scrollrect) + if((*state->callbacks->scrollrect)(rect, downward, rightward, state->cbdata)) + return; + + if(state->callbacks) + vterm_scroll_rect(rect, downward, rightward, + state->callbacks->moverect, state->callbacks->erase, state->cbdata); +} + +static void linefeed(VTermState *state) +{ + if(state->pos.row == SCROLLREGION_BOTTOM(state) - 1) { + VTermRect rect = { + .start_row = state->scrollregion_top, + .end_row = SCROLLREGION_BOTTOM(state), + .start_col = SCROLLREGION_LEFT(state), + .end_col = SCROLLREGION_RIGHT(state), + }; + + scroll(state, rect, 1, 0); + } + else if(state->pos.row < state->rows-1) + state->pos.row++; +} + +static void grow_combine_buffer(VTermState *state) +{ + size_t new_size = state->combine_chars_size * 2; + uint32_t *new_chars = vterm_allocator_malloc(state->vt, new_size * sizeof(new_chars[0])); + + memcpy(new_chars, state->combine_chars, state->combine_chars_size * sizeof(new_chars[0])); + + vterm_allocator_free(state->vt, state->combine_chars); + + state->combine_chars = new_chars; + state->combine_chars_size = new_size; +} + +static void set_col_tabstop(VTermState *state, int col) +{ + unsigned char mask = 1 << (col & 7); + state->tabstops[col >> 3] |= mask; +} + +static void clear_col_tabstop(VTermState *state, int col) +{ + unsigned char mask = 1 << (col & 7); + state->tabstops[col >> 3] &= ~mask; +} + +static int is_col_tabstop(VTermState *state, int col) +{ + unsigned char mask = 1 << (col & 7); + return state->tabstops[col >> 3] & mask; +} + +static int is_cursor_in_scrollregion(const VTermState *state) +{ + if(state->pos.row < state->scrollregion_top || + state->pos.row >= SCROLLREGION_BOTTOM(state)) + return 0; + if(state->pos.col < SCROLLREGION_LEFT(state) || + state->pos.col >= SCROLLREGION_RIGHT(state)) + return 0; + + return 1; +} + +static void tab(VTermState *state, int count, int direction) +{ + while(count > 0) { + if(direction > 0) { + if(state->pos.col >= THISROWWIDTH(state)-1) + return; + + state->pos.col++; + } + else if(direction < 0) { + if(state->pos.col < 1) + return; + + state->pos.col--; + } + + if(is_col_tabstop(state, state->pos.col)) + count--; + } +} + +#define NO_FORCE 0 +#define FORCE 1 + +#define DWL_OFF 0 +#define DWL_ON 1 + +#define DHL_OFF 0 +#define DHL_TOP 1 +#define DHL_BOTTOM 2 + +static void set_lineinfo(VTermState *state, int row, int force, int dwl, int dhl) +{ + VTermLineInfo info = state->lineinfo[row]; + + if(dwl == DWL_OFF) + info.doublewidth = DWL_OFF; + else if(dwl == DWL_ON) + info.doublewidth = DWL_ON; + // else -1 to ignore + + if(dhl == DHL_OFF) + info.doubleheight = DHL_OFF; + else if(dhl == DHL_TOP) + info.doubleheight = DHL_TOP; + else if(dhl == DHL_BOTTOM) + info.doubleheight = DHL_BOTTOM; + + if((state->callbacks && + state->callbacks->setlineinfo && + (*state->callbacks->setlineinfo)(row, &info, state->lineinfo + row, state->cbdata)) + || force) + state->lineinfo[row] = info; +} + +static int on_text(const char bytes[], size_t len, void *user) +{ + VTermState *state = user; + + VTermPos oldpos = state->pos; + + uint32_t *codepoints = (uint32_t *)(state->vt->tmpbuffer); + size_t maxpoints = (state->vt->tmpbuffer_len) / sizeof(uint32_t); + + int npoints = 0; + size_t eaten = 0; + + VTermEncodingInstance *encoding = + state->gsingle_set ? &state->encoding[state->gsingle_set] : + !(bytes[eaten] & 0x80) ? &state->encoding[state->gl_set] : + state->vt->mode.utf8 ? &state->encoding_utf8 : + &state->encoding[state->gr_set]; + + (*encoding->enc->decode)(encoding->enc, encoding->data, + codepoints, &npoints, state->gsingle_set ? 1 : maxpoints, + bytes, &eaten, len); + + /* There's a chance an encoding (e.g. UTF-8) hasn't found enough bytes yet + * for even a single codepoint + */ + if(!npoints) + return eaten; + + if(state->gsingle_set && npoints) + state->gsingle_set = 0; + + int i = 0; + + /* This is a combining char. that needs to be merged with the previous + * glyph output */ + if(vterm_unicode_is_combining(codepoints[i])) { + /* See if the cursor has moved since */ + if(state->pos.row == state->combine_pos.row && state->pos.col == state->combine_pos.col + state->combine_width) { +#ifdef DEBUG_GLYPH_COMBINE + int printpos; + printf("DEBUG: COMBINING SPLIT GLYPH of chars {"); + for(printpos = 0; state->combine_chars[printpos]; printpos++) + printf("U+%04x ", state->combine_chars[printpos]); + printf("} + {"); +#endif + + /* Find where we need to append these combining chars */ + int saved_i = 0; + while(state->combine_chars[saved_i]) + saved_i++; + + /* Add extra ones */ + while(i < npoints && vterm_unicode_is_combining(codepoints[i])) { + if(saved_i >= state->combine_chars_size) + grow_combine_buffer(state); + state->combine_chars[saved_i++] = codepoints[i++]; + } + if(saved_i >= state->combine_chars_size) + grow_combine_buffer(state); + state->combine_chars[saved_i] = 0; + +#ifdef DEBUG_GLYPH_COMBINE + for(; state->combine_chars[printpos]; printpos++) + printf("U+%04x ", state->combine_chars[printpos]); + printf("}\n"); +#endif + + /* Now render it */ + putglyph(state, state->combine_chars, state->combine_width, state->combine_pos); + } + else { + DEBUG_LOG("libvterm: TODO: Skip over split char+combining\n"); + } + } + + for(; i < npoints; i++) { + // Try to find combining characters following this + int glyph_starts = i; + int glyph_ends; + for(glyph_ends = i + 1; + (glyph_ends < npoints) && (glyph_ends < glyph_starts + VTERM_MAX_CHARS_PER_CELL); + glyph_ends++) + if(!vterm_unicode_is_combining(codepoints[glyph_ends])) + break; + + int width = 0; + + uint32_t chars[VTERM_MAX_CHARS_PER_CELL + 1]; + + for( ; i < glyph_ends; i++) { + chars[i - glyph_starts] = codepoints[i]; + int this_width = vterm_unicode_width(codepoints[i]); +#ifdef DEBUG + if(this_width < 0) { + fprintf(stderr, "Text with negative-width codepoint U+%04x\n", codepoints[i]); + abort(); + } +#endif + width += this_width; + } + + while(i < npoints && vterm_unicode_is_combining(codepoints[i])) + i++; + + chars[glyph_ends - glyph_starts] = 0; + i--; + +#ifdef DEBUG_GLYPH_COMBINE + int printpos; + printf("DEBUG: COMBINED GLYPH of %d chars {", glyph_ends - glyph_starts); + for(printpos = 0; printpos < glyph_ends - glyph_starts; printpos++) + printf("U+%04x ", chars[printpos]); + printf("}, onscreen width %d\n", width); +#endif + + if(state->at_phantom || state->pos.col + width > THISROWWIDTH(state)) { + linefeed(state); + state->pos.col = 0; + state->at_phantom = 0; + state->lineinfo[state->pos.row].continuation = 1; + } + + if(state->mode.insert) { + /* TODO: This will be a little inefficient for large bodies of text, as + * it'll have to 'ICH' effectively before every glyph. We should scan + * ahead and ICH as many times as required + */ + VTermRect rect = { + .start_row = state->pos.row, + .end_row = state->pos.row + 1, + .start_col = state->pos.col, + .end_col = THISROWWIDTH(state), + }; + scroll(state, rect, 0, -1); + } + + putglyph(state, chars, width, state->pos); + + if(i == npoints - 1) { + /* End of the buffer. Save the chars in case we have to combine with + * more on the next call */ + int save_i; + for(save_i = 0; chars[save_i]; save_i++) { + if(save_i >= state->combine_chars_size) + grow_combine_buffer(state); + state->combine_chars[save_i] = chars[save_i]; + } + if(save_i >= state->combine_chars_size) + grow_combine_buffer(state); + state->combine_chars[save_i] = 0; + state->combine_width = width; + state->combine_pos = state->pos; + } + + if(state->pos.col + width >= THISROWWIDTH(state)) { + if(state->mode.autowrap) + state->at_phantom = 1; + } + else { + state->pos.col += width; + } + } + + updatecursor(state, &oldpos, 0); + +#ifdef DEBUG + if(state->pos.row < 0 || state->pos.row >= state->rows || + state->pos.col < 0 || state->pos.col >= state->cols) { + fprintf(stderr, "Position out of bounds after text: (%d,%d)\n", + state->pos.row, state->pos.col); + abort(); + } +#endif + + return eaten; +} + +static int on_control(unsigned char control, void *user) +{ + VTermState *state = user; + + VTermPos oldpos = state->pos; + + switch(control) { + case 0x07: // BEL - ECMA-48 8.3.3 + if(state->callbacks && state->callbacks->bell) + (*state->callbacks->bell)(state->cbdata); + break; + + case 0x08: // BS - ECMA-48 8.3.5 + if(state->pos.col > 0) + state->pos.col--; + break; + + case 0x09: // HT - ECMA-48 8.3.60 + tab(state, 1, +1); + break; + + case 0x0a: // LF - ECMA-48 8.3.74 + case 0x0b: // VT + case 0x0c: // FF + linefeed(state); + if(state->mode.newline) + state->pos.col = 0; + break; + + case 0x0d: // CR - ECMA-48 8.3.15 + state->pos.col = 0; + break; + + case 0x0e: // LS1 - ECMA-48 8.3.76 + state->gl_set = 1; + break; + + case 0x0f: // LS0 - ECMA-48 8.3.75 + state->gl_set = 0; + break; + + case 0x84: // IND - DEPRECATED but implemented for completeness + linefeed(state); + break; + + case 0x85: // NEL - ECMA-48 8.3.86 + linefeed(state); + state->pos.col = 0; + break; + + case 0x88: // HTS - ECMA-48 8.3.62 + set_col_tabstop(state, state->pos.col); + break; + + case 0x8d: // RI - ECMA-48 8.3.104 + if(state->pos.row == state->scrollregion_top) { + VTermRect rect = { + .start_row = state->scrollregion_top, + .end_row = SCROLLREGION_BOTTOM(state), + .start_col = SCROLLREGION_LEFT(state), + .end_col = SCROLLREGION_RIGHT(state), + }; + + scroll(state, rect, -1, 0); + } + else if(state->pos.row > 0) + state->pos.row--; + break; + + case 0x8e: // SS2 - ECMA-48 8.3.141 + state->gsingle_set = 2; + break; + + case 0x8f: // SS3 - ECMA-48 8.3.142 + state->gsingle_set = 3; + break; + + default: + if(state->fallbacks && state->fallbacks->control) + if((*state->fallbacks->control)(control, state->fbdata)) + return 1; + + return 0; + } + + updatecursor(state, &oldpos, 1); + +#ifdef DEBUG + if(state->pos.row < 0 || state->pos.row >= state->rows || + state->pos.col < 0 || state->pos.col >= state->cols) { + fprintf(stderr, "Position out of bounds after Ctrl %02x: (%d,%d)\n", + control, state->pos.row, state->pos.col); + abort(); + } +#endif + + return 1; +} + +static int settermprop_bool(VTermState *state, VTermProp prop, int v) +{ + VTermValue val = { .boolean = v }; + return vterm_state_set_termprop(state, prop, &val); +} + +static int settermprop_int(VTermState *state, VTermProp prop, int v) +{ + VTermValue val = { .number = v }; + return vterm_state_set_termprop(state, prop, &val); +} + +static int settermprop_string(VTermState *state, VTermProp prop, VTermStringFragment frag) +{ + VTermValue val = { .string = frag }; + return vterm_state_set_termprop(state, prop, &val); +} + +static void savecursor(VTermState *state, int save) +{ + if(save) { + state->saved.pos = state->pos; + state->saved.mode.cursor_visible = state->mode.cursor_visible; + state->saved.mode.cursor_blink = state->mode.cursor_blink; + state->saved.mode.cursor_shape = state->mode.cursor_shape; + + vterm_state_savepen(state, 1); + } + else { + VTermPos oldpos = state->pos; + + state->pos = state->saved.pos; + + settermprop_bool(state, VTERM_PROP_CURSORVISIBLE, state->saved.mode.cursor_visible); + settermprop_bool(state, VTERM_PROP_CURSORBLINK, state->saved.mode.cursor_blink); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, state->saved.mode.cursor_shape); + + vterm_state_savepen(state, 0); + + updatecursor(state, &oldpos, 1); + } +} + +static int on_escape(const char *bytes, size_t len, void *user) +{ + VTermState *state = user; + + /* Easier to decode this from the first byte, even though the final + * byte terminates it + */ + switch(bytes[0]) { + case ' ': + if(len != 2) + return 0; + + switch(bytes[1]) { + case 'F': // S7C1T + state->vt->mode.ctrl8bit = 0; + break; + + case 'G': // S8C1T + state->vt->mode.ctrl8bit = 1; + break; + + default: + return 0; + } + return 2; + + case '#': + if(len != 2) + return 0; + + switch(bytes[1]) { + case '3': // DECDHL top + if(state->mode.leftrightmargin) + break; + set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_TOP); + break; + + case '4': // DECDHL bottom + if(state->mode.leftrightmargin) + break; + set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_BOTTOM); + break; + + case '5': // DECSWL + if(state->mode.leftrightmargin) + break; + set_lineinfo(state, state->pos.row, NO_FORCE, DWL_OFF, DHL_OFF); + break; + + case '6': // DECDWL + if(state->mode.leftrightmargin) + break; + set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_OFF); + break; + + case '8': // DECALN + { + VTermPos pos; + uint32_t E[] = { 'E', 0 }; + for(pos.row = 0; pos.row < state->rows; pos.row++) + for(pos.col = 0; pos.col < ROWWIDTH(state, pos.row); pos.col++) + putglyph(state, E, 1, pos); + break; + } + + default: + return 0; + } + return 2; + + case '(': case ')': case '*': case '+': // SCS + if(len != 2) + return 0; + + { + int setnum = bytes[0] - 0x28; + VTermEncoding *newenc = vterm_lookup_encoding(ENC_SINGLE_94, bytes[1]); + + if(newenc) { + state->encoding[setnum].enc = newenc; + + if(newenc->init) + (*newenc->init)(newenc, state->encoding[setnum].data); + } + } + + return 2; + + case '7': // DECSC + savecursor(state, 1); + return 1; + + case '8': // DECRC + savecursor(state, 0); + return 1; + + case '<': // Ignored by VT100. Used in VT52 mode to switch up to VT100 + return 1; + + case '=': // DECKPAM + state->mode.keypad = 1; + return 1; + + case '>': // DECKPNM + state->mode.keypad = 0; + return 1; + + case 'c': // RIS - ECMA-48 8.3.105 + { + VTermPos oldpos = state->pos; + vterm_state_reset(state, 1); + if(state->callbacks && state->callbacks->movecursor) + (*state->callbacks->movecursor)(state->pos, oldpos, state->mode.cursor_visible, state->cbdata); + return 1; + } + + case 'n': // LS2 - ECMA-48 8.3.78 + state->gl_set = 2; + return 1; + + case 'o': // LS3 - ECMA-48 8.3.80 + state->gl_set = 3; + return 1; + + case '~': // LS1R - ECMA-48 8.3.77 + state->gr_set = 1; + return 1; + + case '}': // LS2R - ECMA-48 8.3.79 + state->gr_set = 2; + return 1; + + case '|': // LS3R - ECMA-48 8.3.81 + state->gr_set = 3; + return 1; + + default: + return 0; + } +} + +static void set_mode(VTermState *state, int num, int val) +{ + switch(num) { + case 4: // IRM - ECMA-48 7.2.10 + state->mode.insert = val; + break; + + case 20: // LNM - ANSI X3.4-1977 + state->mode.newline = val; + break; + + default: + DEBUG_LOG("libvterm: Unknown mode %d\n", num); + return; + } +} + +static void set_dec_mode(VTermState *state, int num, int val) +{ + switch(num) { + case 1: + state->mode.cursor = val; + break; + + case 5: // DECSCNM - screen mode + settermprop_bool(state, VTERM_PROP_REVERSE, val); + break; + + case 6: // DECOM - origin mode + { + VTermPos oldpos = state->pos; + state->mode.origin = val; + state->pos.row = state->mode.origin ? state->scrollregion_top : 0; + state->pos.col = state->mode.origin ? SCROLLREGION_LEFT(state) : 0; + updatecursor(state, &oldpos, 1); + } + break; + + case 7: + state->mode.autowrap = val; + break; + + case 12: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, val); + break; + + case 25: + settermprop_bool(state, VTERM_PROP_CURSORVISIBLE, val); + break; + + case 69: // DECVSSM - vertical split screen mode + // DECLRMM - left/right margin mode + state->mode.leftrightmargin = val; + if(val) { + // Setting DECVSSM must clear doublewidth/doubleheight state of every line + for(int row = 0; row < state->rows; row++) + set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF); + } + + break; + + case 1000: + case 1002: + case 1003: + settermprop_int(state, VTERM_PROP_MOUSE, + !val ? VTERM_PROP_MOUSE_NONE : + (num == 1000) ? VTERM_PROP_MOUSE_CLICK : + (num == 1002) ? VTERM_PROP_MOUSE_DRAG : + VTERM_PROP_MOUSE_MOVE); + break; + + case 1004: + settermprop_bool(state, VTERM_PROP_FOCUSREPORT, val); + state->mode.report_focus = val; + break; + + case 1005: + state->mouse_protocol = val ? MOUSE_UTF8 : MOUSE_X10; + break; + + case 1006: + state->mouse_protocol = val ? MOUSE_SGR : MOUSE_X10; + break; + + case 1015: + state->mouse_protocol = val ? MOUSE_RXVT : MOUSE_X10; + break; + + case 1047: + settermprop_bool(state, VTERM_PROP_ALTSCREEN, val); + break; + + case 1048: + savecursor(state, val); + break; + + case 1049: + settermprop_bool(state, VTERM_PROP_ALTSCREEN, val); + savecursor(state, val); + break; + + case 2004: + state->mode.bracketpaste = val; + break; + + default: + DEBUG_LOG("libvterm: Unknown DEC mode %d\n", num); + return; + } +} + +static void request_dec_mode(VTermState *state, int num) +{ + int reply; + + switch(num) { + case 1: + reply = state->mode.cursor; + break; + + case 5: + reply = state->mode.screen; + break; + + case 6: + reply = state->mode.origin; + break; + + case 7: + reply = state->mode.autowrap; + break; + + case 12: + reply = state->mode.cursor_blink; + break; + + case 25: + reply = state->mode.cursor_visible; + break; + + case 69: + reply = state->mode.leftrightmargin; + break; + + case 1000: + reply = state->mouse_flags == MOUSE_WANT_CLICK; + break; + + case 1002: + reply = state->mouse_flags == (MOUSE_WANT_CLICK|MOUSE_WANT_DRAG); + break; + + case 1003: + reply = state->mouse_flags == (MOUSE_WANT_CLICK|MOUSE_WANT_MOVE); + break; + + case 1004: + reply = state->mode.report_focus; + break; + + case 1005: + reply = state->mouse_protocol == MOUSE_UTF8; + break; + + case 1006: + reply = state->mouse_protocol == MOUSE_SGR; + break; + + case 1015: + reply = state->mouse_protocol == MOUSE_RXVT; + break; + + case 1047: + reply = state->mode.alt_screen; + break; + + case 2004: + reply = state->mode.bracketpaste; + break; + + default: + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "?%d;%d$y", num, 0); + return; + } + + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "?%d;%d$y", num, reply ? 1 : 2); +} + +static void request_version_string(VTermState *state) +{ + vterm_push_output_sprintf_str(state->vt, C1_DCS, true, ">|libvterm(%d.%d)", + VTERM_VERSION_MAJOR, VTERM_VERSION_MINOR); +} + +static int on_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user) +{ + VTermState *state = user; + int leader_byte = 0; + int intermed_byte = 0; + int cancel_phantom = 1; + + if(leader && leader[0]) { + if(leader[1]) // longer than 1 char + return 0; + + switch(leader[0]) { + case '?': + case '>': + leader_byte = leader[0]; + break; + default: + return 0; + } + } + + if(intermed && intermed[0]) { + if(intermed[1]) // longer than 1 char + return 0; + + switch(intermed[0]) { + case ' ': + case '!': + case '"': + case '$': + case '\'': + intermed_byte = intermed[0]; + break; + default: + return 0; + } + } + + VTermPos oldpos = state->pos; + + // Some temporaries for later code + int count, val; + int row, col; + VTermRect rect; + int selective; + +#define LBOUND(v,min) if((v) < (min)) (v) = (min) +#define UBOUND(v,max) if((v) > (max)) (v) = (max) + +#define LEADER(l,b) ((l << 8) | b) +#define INTERMED(i,b) ((i << 16) | b) + + switch(intermed_byte << 16 | leader_byte << 8 | command) { + case 0x40: // ICH - ECMA-48 8.3.64 + count = CSI_ARG_COUNT(args[0]); + + if(!is_cursor_in_scrollregion(state)) + break; + + rect.start_row = state->pos.row; + rect.end_row = state->pos.row + 1; + rect.start_col = state->pos.col; + if(state->mode.leftrightmargin) + rect.end_col = SCROLLREGION_RIGHT(state); + else + rect.end_col = THISROWWIDTH(state); + + scroll(state, rect, 0, -count); + + break; + + case 0x41: // CUU - ECMA-48 8.3.22 + count = CSI_ARG_COUNT(args[0]); + state->pos.row -= count; + state->at_phantom = 0; + break; + + case 0x42: // CUD - ECMA-48 8.3.19 + count = CSI_ARG_COUNT(args[0]); + state->pos.row += count; + state->at_phantom = 0; + break; + + case 0x43: // CUF - ECMA-48 8.3.20 + count = CSI_ARG_COUNT(args[0]); + state->pos.col += count; + state->at_phantom = 0; + break; + + case 0x44: // CUB - ECMA-48 8.3.18 + count = CSI_ARG_COUNT(args[0]); + state->pos.col -= count; + state->at_phantom = 0; + break; + + case 0x45: // CNL - ECMA-48 8.3.12 + count = CSI_ARG_COUNT(args[0]); + state->pos.col = 0; + state->pos.row += count; + state->at_phantom = 0; + break; + + case 0x46: // CPL - ECMA-48 8.3.13 + count = CSI_ARG_COUNT(args[0]); + state->pos.col = 0; + state->pos.row -= count; + state->at_phantom = 0; + break; + + case 0x47: // CHA - ECMA-48 8.3.9 + val = CSI_ARG_OR(args[0], 1); + state->pos.col = val-1; + state->at_phantom = 0; + break; + + case 0x48: // CUP - ECMA-48 8.3.21 + row = CSI_ARG_OR(args[0], 1); + col = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? 1 : CSI_ARG(args[1]); + // zero-based + state->pos.row = row-1; + state->pos.col = col-1; + if(state->mode.origin) { + state->pos.row += state->scrollregion_top; + state->pos.col += SCROLLREGION_LEFT(state); + } + state->at_phantom = 0; + break; + + case 0x49: // CHT - ECMA-48 8.3.10 + count = CSI_ARG_COUNT(args[0]); + tab(state, count, +1); + break; + + case 0x4a: // ED - ECMA-48 8.3.39 + case LEADER('?', 0x4a): // DECSED - Selective Erase in Display + selective = (leader_byte == '?'); + switch(CSI_ARG(args[0])) { + case CSI_ARG_MISSING: + case 0: + rect.start_row = state->pos.row; rect.end_row = state->pos.row + 1; + rect.start_col = state->pos.col; rect.end_col = state->cols; + if(rect.end_col > rect.start_col) + erase(state, rect, selective); + + rect.start_row = state->pos.row + 1; rect.end_row = state->rows; + rect.start_col = 0; + for(int row_ = rect.start_row; row_ < rect.end_row; row_++) + set_lineinfo(state, row_, FORCE, DWL_OFF, DHL_OFF); + if(rect.end_row > rect.start_row) + erase(state, rect, selective); + break; + + case 1: + rect.start_row = 0; rect.end_row = state->pos.row; + rect.start_col = 0; rect.end_col = state->cols; + for(int row_ = rect.start_row; row_ < rect.end_row; row_++) + set_lineinfo(state, row_, FORCE, DWL_OFF, DHL_OFF); + if(rect.end_col > rect.start_col) + erase(state, rect, selective); + + rect.start_row = state->pos.row; rect.end_row = state->pos.row + 1; + rect.end_col = state->pos.col + 1; + if(rect.end_row > rect.start_row) + erase(state, rect, selective); + break; + + case 2: + rect.start_row = 0; rect.end_row = state->rows; + rect.start_col = 0; rect.end_col = state->cols; + for(int row_ = rect.start_row; row_ < rect.end_row; row_++) + set_lineinfo(state, row_, FORCE, DWL_OFF, DHL_OFF); + erase(state, rect, selective); + break; + + case 3: + if(state->callbacks && state->callbacks->sb_clear) + if((*state->callbacks->sb_clear)(state->cbdata)) + return 1; + break; + } + break; + + case 0x4b: // EL - ECMA-48 8.3.41 + case LEADER('?', 0x4b): // DECSEL - Selective Erase in Line + selective = (leader_byte == '?'); + rect.start_row = state->pos.row; + rect.end_row = state->pos.row + 1; + + switch(CSI_ARG(args[0])) { + case CSI_ARG_MISSING: + case 0: + rect.start_col = state->pos.col; rect.end_col = THISROWWIDTH(state); break; + case 1: + rect.start_col = 0; rect.end_col = state->pos.col + 1; break; + case 2: + rect.start_col = 0; rect.end_col = THISROWWIDTH(state); break; + default: + return 0; + } + + if(rect.end_col > rect.start_col) + erase(state, rect, selective); + + break; + + case 0x4c: // IL - ECMA-48 8.3.67 + count = CSI_ARG_COUNT(args[0]); + + if(!is_cursor_in_scrollregion(state)) + break; + + rect.start_row = state->pos.row; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = SCROLLREGION_LEFT(state); + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, -count, 0); + + break; + + case 0x4d: // DL - ECMA-48 8.3.32 + count = CSI_ARG_COUNT(args[0]); + + if(!is_cursor_in_scrollregion(state)) + break; + + rect.start_row = state->pos.row; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = SCROLLREGION_LEFT(state); + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, count, 0); + + break; + + case 0x50: // DCH - ECMA-48 8.3.26 + count = CSI_ARG_COUNT(args[0]); + + if(!is_cursor_in_scrollregion(state)) + break; + + rect.start_row = state->pos.row; + rect.end_row = state->pos.row + 1; + rect.start_col = state->pos.col; + if(state->mode.leftrightmargin) + rect.end_col = SCROLLREGION_RIGHT(state); + else + rect.end_col = THISROWWIDTH(state); + + scroll(state, rect, 0, count); + + break; + + case 0x53: // SU - ECMA-48 8.3.147 + count = CSI_ARG_COUNT(args[0]); + + rect.start_row = state->scrollregion_top; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = SCROLLREGION_LEFT(state); + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, count, 0); + + break; + + case 0x54: // SD - ECMA-48 8.3.113 + count = CSI_ARG_COUNT(args[0]); + + rect.start_row = state->scrollregion_top; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = SCROLLREGION_LEFT(state); + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, -count, 0); + + break; + + case 0x58: // ECH - ECMA-48 8.3.38 + count = CSI_ARG_COUNT(args[0]); + + rect.start_row = state->pos.row; + rect.end_row = state->pos.row + 1; + rect.start_col = state->pos.col; + rect.end_col = state->pos.col + count; + UBOUND(rect.end_col, THISROWWIDTH(state)); + + erase(state, rect, 0); + break; + + case 0x5a: // CBT - ECMA-48 8.3.7 + count = CSI_ARG_COUNT(args[0]); + tab(state, count, -1); + break; + + case 0x60: // HPA - ECMA-48 8.3.57 + col = CSI_ARG_OR(args[0], 1); + state->pos.col = col-1; + state->at_phantom = 0; + break; + + case 0x61: // HPR - ECMA-48 8.3.59 + count = CSI_ARG_COUNT(args[0]); + state->pos.col += count; + state->at_phantom = 0; + break; + + case 0x62: { // REP - ECMA-48 8.3.103 + const int row_width = THISROWWIDTH(state); + count = CSI_ARG_COUNT(args[0]); + col = state->pos.col + count; + UBOUND(col, row_width); + while (state->pos.col < col) { + putglyph(state, state->combine_chars, state->combine_width, state->pos); + state->pos.col += state->combine_width; + } + if (state->pos.col + state->combine_width >= row_width) { + if (state->mode.autowrap) { + state->at_phantom = 1; + cancel_phantom = 0; + } + } + break; + } + + case 0x63: // DA - ECMA-48 8.3.24 + val = CSI_ARG_OR(args[0], 0); + if(val == 0) + // DEC VT100 response + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "?1;2c"); + break; + + case LEADER('>', 0x63): // DEC secondary Device Attributes + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, ">%d;%d;%dc", 0, 100, 0); + break; + + case 0x64: // VPA - ECMA-48 8.3.158 + row = CSI_ARG_OR(args[0], 1); + state->pos.row = row-1; + if(state->mode.origin) + state->pos.row += state->scrollregion_top; + state->at_phantom = 0; + break; + + case 0x65: // VPR - ECMA-48 8.3.160 + count = CSI_ARG_COUNT(args[0]); + state->pos.row += count; + state->at_phantom = 0; + break; + + case 0x66: // HVP - ECMA-48 8.3.63 + row = CSI_ARG_OR(args[0], 1); + col = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? 1 : CSI_ARG(args[1]); + // zero-based + state->pos.row = row-1; + state->pos.col = col-1; + if(state->mode.origin) { + state->pos.row += state->scrollregion_top; + state->pos.col += SCROLLREGION_LEFT(state); + } + state->at_phantom = 0; + break; + + case 0x67: // TBC - ECMA-48 8.3.154 + val = CSI_ARG_OR(args[0], 0); + + switch(val) { + case 0: + clear_col_tabstop(state, state->pos.col); + break; + case 3: + case 5: + for(col = 0; col < state->cols; col++) + clear_col_tabstop(state, col); + break; + case 1: + case 2: + case 4: + break; + /* TODO: 1, 2 and 4 aren't meaningful yet without line tab stops */ + default: + return 0; + } + break; + + case 0x68: // SM - ECMA-48 8.3.125 + if(!CSI_ARG_IS_MISSING(args[0])) + set_mode(state, CSI_ARG(args[0]), 1); + break; + + case LEADER('?', 0x68): // DEC private mode set + for(int i = 0; i < argcount; i++) { + if(!CSI_ARG_IS_MISSING(args[i])) + set_dec_mode(state, CSI_ARG(args[i]), 1); + } + break; + + case 0x6a: // HPB - ECMA-48 8.3.58 + count = CSI_ARG_COUNT(args[0]); + state->pos.col -= count; + state->at_phantom = 0; + break; + + case 0x6b: // VPB - ECMA-48 8.3.159 + count = CSI_ARG_COUNT(args[0]); + state->pos.row -= count; + state->at_phantom = 0; + break; + + case 0x6c: // RM - ECMA-48 8.3.106 + if(!CSI_ARG_IS_MISSING(args[0])) + set_mode(state, CSI_ARG(args[0]), 0); + break; + + case LEADER('?', 0x6c): // DEC private mode reset + for(int i = 0; i < argcount; i++) { + if(!CSI_ARG_IS_MISSING(args[i])) + set_dec_mode(state, CSI_ARG(args[i]), 0); + } + break; + + case 0x6d: // SGR - ECMA-48 8.3.117 + vterm_state_setpen(state, args, argcount); + break; + + case LEADER('?', 0x6d): // DECSGR + /* No actual DEC terminal recognised these, but some printers did. These + * are alternative ways to request subscript/superscript/off + */ + for(int argi = 0; argi < argcount; argi++) { + long arg; + switch(arg = CSI_ARG(args[argi])) { + case 4: // Superscript on + arg = 73; + vterm_state_setpen(state, &arg, 1); + break; + case 5: // Subscript on + arg = 74; + vterm_state_setpen(state, &arg, 1); + break; + case 24: // Super+subscript off + arg = 75; + vterm_state_setpen(state, &arg, 1); + break; + } + } + break; + + case 0x6e: // DSR - ECMA-48 8.3.35 + case LEADER('?', 0x6e): // DECDSR + val = CSI_ARG_OR(args[0], 0); + + { + char *qmark = (leader_byte == '?') ? "?" : ""; + + switch(val) { + case 0: case 1: case 2: case 3: case 4: + // ignore - these are replies + break; + case 5: + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "%s0n", qmark); + break; + case 6: // CPR - cursor position report + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "%s%d;%dR", qmark, state->pos.row + 1, state->pos.col + 1); + break; + } + } + break; + + + case INTERMED('!', 0x70): // DECSTR - DEC soft terminal reset + vterm_state_reset(state, 0); + break; + + case LEADER('?', INTERMED('$', 0x70)): + request_dec_mode(state, CSI_ARG(args[0])); + break; + + case LEADER('>', 0x71): // XTVERSION - xterm query version string + request_version_string(state); + break; + + case INTERMED(' ', 0x71): // DECSCUSR - DEC set cursor shape + val = CSI_ARG_OR(args[0], 1); + + switch(val) { + case 0: case 1: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 1); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BLOCK); + break; + case 2: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 0); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BLOCK); + break; + case 3: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 1); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_UNDERLINE); + break; + case 4: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 0); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_UNDERLINE); + break; + case 5: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 1); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BAR_LEFT); + break; + case 6: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 0); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BAR_LEFT); + break; + } + + break; + + case INTERMED('"', 0x71): // DECSCA - DEC select character protection attribute + val = CSI_ARG_OR(args[0], 0); + + switch(val) { + case 0: case 2: + state->protected_cell = 0; + break; + case 1: + state->protected_cell = 1; + break; + } + + break; + + case 0x72: // DECSTBM - DEC custom + state->scrollregion_top = CSI_ARG_OR(args[0], 1) - 1; + state->scrollregion_bottom = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? -1 : CSI_ARG(args[1]); + LBOUND(state->scrollregion_top, 0); + UBOUND(state->scrollregion_top, state->rows); + LBOUND(state->scrollregion_bottom, -1); + if(state->scrollregion_top == 0 && state->scrollregion_bottom == state->rows) + state->scrollregion_bottom = -1; + else + UBOUND(state->scrollregion_bottom, state->rows); + + if(SCROLLREGION_BOTTOM(state) <= state->scrollregion_top) { + // Invalid + state->scrollregion_top = 0; + state->scrollregion_bottom = -1; + } + + // Setting the scrolling region restores the cursor to the home position + state->pos.row = 0; + state->pos.col = 0; + if(state->mode.origin) { + state->pos.row += state->scrollregion_top; + state->pos.col += SCROLLREGION_LEFT(state); + } + + break; + + case 0x73: // DECSLRM - DEC custom + // Always allow setting these margins, just they won't take effect without DECVSSM + state->scrollregion_left = CSI_ARG_OR(args[0], 1) - 1; + state->scrollregion_right = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? -1 : CSI_ARG(args[1]); + LBOUND(state->scrollregion_left, 0); + UBOUND(state->scrollregion_left, state->cols); + LBOUND(state->scrollregion_right, -1); + if(state->scrollregion_left == 0 && state->scrollregion_right == state->cols) + state->scrollregion_right = -1; + else + UBOUND(state->scrollregion_right, state->cols); + + if(state->scrollregion_right > -1 && + state->scrollregion_right <= state->scrollregion_left) { + // Invalid + state->scrollregion_left = 0; + state->scrollregion_right = -1; + } + + // Setting the scrolling region restores the cursor to the home position + state->pos.row = 0; + state->pos.col = 0; + if(state->mode.origin) { + state->pos.row += state->scrollregion_top; + state->pos.col += SCROLLREGION_LEFT(state); + } + + break; + + case INTERMED('\'', 0x7D): // DECIC + count = CSI_ARG_COUNT(args[0]); + + if(!is_cursor_in_scrollregion(state)) + break; + + rect.start_row = state->scrollregion_top; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = state->pos.col; + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, 0, -count); + + break; + + case INTERMED('\'', 0x7E): // DECDC + count = CSI_ARG_COUNT(args[0]); + + if(!is_cursor_in_scrollregion(state)) + break; + + rect.start_row = state->scrollregion_top; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = state->pos.col; + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, 0, count); + + break; + + default: + if(state->fallbacks && state->fallbacks->csi) + if((*state->fallbacks->csi)(leader, args, argcount, intermed, command, state->fbdata)) + return 1; + + return 0; + } + + if(state->mode.origin) { + LBOUND(state->pos.row, state->scrollregion_top); + UBOUND(state->pos.row, SCROLLREGION_BOTTOM(state)-1); + LBOUND(state->pos.col, SCROLLREGION_LEFT(state)); + UBOUND(state->pos.col, SCROLLREGION_RIGHT(state)-1); + } + else { + LBOUND(state->pos.row, 0); + UBOUND(state->pos.row, state->rows-1); + LBOUND(state->pos.col, 0); + UBOUND(state->pos.col, THISROWWIDTH(state)-1); + } + + updatecursor(state, &oldpos, cancel_phantom); + +#ifdef DEBUG + if(state->pos.row < 0 || state->pos.row >= state->rows || + state->pos.col < 0 || state->pos.col >= state->cols) { + fprintf(stderr, "Position out of bounds after CSI %c: (%d,%d)\n", + command, state->pos.row, state->pos.col); + abort(); + } + + if(SCROLLREGION_BOTTOM(state) <= state->scrollregion_top) { + fprintf(stderr, "Scroll region height out of bounds after CSI %c: %d <= %d\n", + command, SCROLLREGION_BOTTOM(state), state->scrollregion_top); + abort(); + } + + if(SCROLLREGION_RIGHT(state) <= SCROLLREGION_LEFT(state)) { + fprintf(stderr, "Scroll region width out of bounds after CSI %c: %d <= %d\n", + command, SCROLLREGION_RIGHT(state), SCROLLREGION_LEFT(state)); + abort(); + } +#endif + + return 1; +} + +static char base64_one(uint8_t b) +{ + if(b < 26) + return 'A' + b; + else if(b < 52) + return 'a' + b - 26; + else if(b < 62) + return '0' + b - 52; + else if(b == 62) + return '+'; + else if(b == 63) + return '/'; + return 0; +} + +static uint8_t unbase64one(char c) +{ + if(c >= 'A' && c <= 'Z') + return c - 'A'; + else if(c >= 'a' && c <= 'z') + return c - 'a' + 26; + else if(c >= '0' && c <= '9') + return c - '0' + 52; + else if(c == '+') + return 62; + else if(c == '/') + return 63; + + return 0xFF; +} + +static void osc_selection(VTermState *state, VTermStringFragment frag) +{ + if(frag.initial) { + state->tmp.selection.mask = 0; + state->tmp.selection.state = SELECTION_INITIAL; + } + + while(!state->tmp.selection.state && frag.len) { + /* Parse selection parameter */ + switch(frag.str[0]) { + case 'c': + state->tmp.selection.mask |= VTERM_SELECTION_CLIPBOARD; + break; + case 'p': + state->tmp.selection.mask |= VTERM_SELECTION_PRIMARY; + break; + case 'q': + state->tmp.selection.mask |= VTERM_SELECTION_SECONDARY; + break; + case 's': + state->tmp.selection.mask |= VTERM_SELECTION_SELECT; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + state->tmp.selection.mask |= (VTERM_SELECTION_CUT0 << (frag.str[0] - '0')); + break; + + case ';': + state->tmp.selection.state = SELECTION_SELECTED; + if(!state->tmp.selection.mask) + state->tmp.selection.mask = VTERM_SELECTION_SELECT|VTERM_SELECTION_CUT0; + break; + } + + frag.str++; + frag.len--; + } + + if(!frag.len) { + /* Clear selection if we're already finished but didn't do anything */ + if(frag.final && state->selection.callbacks->set) { + (*state->selection.callbacks->set)(state->tmp.selection.mask, (VTermStringFragment){ + .str = NULL, + .len = 0, + .initial = state->tmp.selection.state != SELECTION_SET, + .final = true, + }, state->selection.user); + } + return; + } + + if(state->tmp.selection.state == SELECTION_SELECTED) { + if(frag.str[0] == '?') { + state->tmp.selection.state = SELECTION_QUERY; + } + else { + state->tmp.selection.state = SELECTION_SET_INITIAL; + state->tmp.selection.recvpartial = 0; + } + } + + if(state->tmp.selection.state == SELECTION_QUERY) { + if(state->selection.callbacks->query) + (*state->selection.callbacks->query)(state->tmp.selection.mask, state->selection.user); + return; + } + + if(state->tmp.selection.state == SELECTION_INVALID) + return; + + if(state->selection.callbacks->set) { + size_t bufcur = 0; + char *buffer = state->selection.buffer; + + uint32_t x = 0; /* Current decoding value */ + int n = 0; /* Number of sextets consumed */ + + if(state->tmp.selection.recvpartial) { + n = state->tmp.selection.recvpartial >> 24; + x = state->tmp.selection.recvpartial & 0x03FFFF; /* could be up to 18 bits of state in here */ + + state->tmp.selection.recvpartial = 0; + } + + while((state->selection.buflen - bufcur) >= 3 && frag.len) { + if(frag.str[0] == '=') { + if(n == 2) { + buffer[0] = (x >> 4) & 0xFF; + buffer += 1, bufcur += 1; + } + if(n == 3) { + buffer[0] = (x >> 10) & 0xFF; + buffer[1] = (x >> 2) & 0xFF; + buffer += 2, bufcur += 2; + } + + while(frag.len && frag.str[0] == '=') + frag.str++, frag.len--; + + n = 0; + } + else { + uint8_t b = unbase64one(frag.str[0]); + if(b == 0xFF) { + DEBUG_LOG("base64decode bad input %02X\n", (uint8_t)frag.str[0]); + + state->tmp.selection.state = SELECTION_INVALID; + if(state->selection.callbacks->set) { + (*state->selection.callbacks->set)(state->tmp.selection.mask, (VTermStringFragment){ + .str = NULL, + .len = 0, + .initial = true, + .final = true, + }, state->selection.user); + } + break; + } + + x = (x << 6) | b; + n++; + frag.str++, frag.len--; + + if(n == 4) { + buffer[0] = (x >> 16) & 0xFF; + buffer[1] = (x >> 8) & 0xFF; + buffer[2] = (x >> 0) & 0xFF; + + buffer += 3, bufcur += 3; + x = 0; + n = 0; + } + } + + if(!frag.len || (state->selection.buflen - bufcur) < 3) { + if(bufcur) { + (*state->selection.callbacks->set)(state->tmp.selection.mask, (VTermStringFragment){ + .str = state->selection.buffer, + .len = bufcur, + .initial = state->tmp.selection.state == SELECTION_SET_INITIAL, + .final = frag.final && !frag.len, + }, state->selection.user); + state->tmp.selection.state = SELECTION_SET; + } + + buffer = state->selection.buffer; + bufcur = 0; + } + } + + if(n) + state->tmp.selection.recvpartial = (n << 24) | x; + } +} + +static int on_osc(int command, VTermStringFragment frag, void *user) +{ + VTermState *state = user; + + switch(command) { + case 0: + settermprop_string(state, VTERM_PROP_ICONNAME, frag); + settermprop_string(state, VTERM_PROP_TITLE, frag); + return 1; + + case 1: + settermprop_string(state, VTERM_PROP_ICONNAME, frag); + return 1; + + case 2: + settermprop_string(state, VTERM_PROP_TITLE, frag); + return 1; + + case 52: + if(state->selection.callbacks) + osc_selection(state, frag); + + return 1; + + default: + if(state->fallbacks && state->fallbacks->osc) + if((*state->fallbacks->osc)(command, frag, state->fbdata)) + return 1; + } + + return 0; +} + +static void request_status_string(VTermState *state, VTermStringFragment frag) +{ + VTerm *vt = state->vt; + + char *tmp = state->tmp.decrqss; + + if(frag.initial) + tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; + + int i = 0; + while(i < sizeof(state->tmp.decrqss)-1 && tmp[i]) + i++; + while(i < sizeof(state->tmp.decrqss)-1 && frag.len--) + tmp[i++] = (frag.str++)[0]; + tmp[i] = 0; + + if(!frag.final) + return; + + switch(tmp[0] | tmp[1]<<8 | tmp[2]<<16) { + case 'm': { + // Query SGR + long args[20]; + int argc = vterm_state_getpen(state, args, sizeof(args)/sizeof(args[0])); + size_t cur = 0; + + cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + vt->mode.ctrl8bit ? "\x90" "1$r" : ESC_S "P" "1$r"); // DCS 1$r ... + if(cur >= vt->tmpbuffer_len) + return; + + for(int argi = 0; argi < argc; argi++) { + cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + argi == argc - 1 ? "%ld" : + CSI_ARG_HAS_MORE(args[argi]) ? "%ld:" : + "%ld;", + CSI_ARG(args[argi])); + if(cur >= vt->tmpbuffer_len) + return; + } + + cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + vt->mode.ctrl8bit ? "m" "\x9C" : "m" ESC_S "\\"); // ... m ST + if(cur >= vt->tmpbuffer_len) + return; + + vterm_push_output_bytes(vt, vt->tmpbuffer, cur); + return; + } + + case 'r': + // Query DECSTBM + vterm_push_output_sprintf_str(vt, C1_DCS, true, + "1$r%d;%dr", state->scrollregion_top+1, SCROLLREGION_BOTTOM(state)); + return; + + case 's': + // Query DECSLRM + vterm_push_output_sprintf_str(vt, C1_DCS, true, + "1$r%d;%ds", SCROLLREGION_LEFT(state)+1, SCROLLREGION_RIGHT(state)); + return; + + case ' '|('q'<<8): { + // Query DECSCUSR + int reply; + switch(state->mode.cursor_shape) { + case VTERM_PROP_CURSORSHAPE_BLOCK: reply = 2; break; + case VTERM_PROP_CURSORSHAPE_UNDERLINE: reply = 4; break; + case VTERM_PROP_CURSORSHAPE_BAR_LEFT: reply = 6; break; + } + if(state->mode.cursor_blink) + reply--; + vterm_push_output_sprintf_str(vt, C1_DCS, true, + "1$r%d q", reply); + return; + } + + case '\"'|('q'<<8): + // Query DECSCA + vterm_push_output_sprintf_str(vt, C1_DCS, true, + "1$r%d\"q", state->protected_cell ? 1 : 2); + return; + } + + vterm_push_output_sprintf_str(state->vt, C1_DCS, true, "0$r"); +} + +static int on_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user) +{ + VTermState *state = user; + + if(commandlen == 2 && strneq(command, "$q", 2)) { + request_status_string(state, frag); + return 1; + } + else if(state->fallbacks && state->fallbacks->dcs) + if((*state->fallbacks->dcs)(command, commandlen, frag, state->fbdata)) + return 1; + + DEBUG_LOG("libvterm: Unhandled DCS %.*s\n", (int)commandlen, command); + return 0; +} + +static int on_apc(VTermStringFragment frag, void *user) +{ + VTermState *state = user; + + if(state->fallbacks && state->fallbacks->apc) + if((*state->fallbacks->apc)(frag, state->fbdata)) + return 1; + + /* No DEBUG_LOG because all APCs are unhandled */ + return 0; +} + +static int on_pm(VTermStringFragment frag, void *user) +{ + VTermState *state = user; + + if(state->fallbacks && state->fallbacks->pm) + if((*state->fallbacks->pm)(frag, state->fbdata)) + return 1; + + /* No DEBUG_LOG because all PMs are unhandled */ + return 0; +} + +static int on_sos(VTermStringFragment frag, void *user) +{ + VTermState *state = user; + + if(state->fallbacks && state->fallbacks->sos) + if((*state->fallbacks->sos)(frag, state->fbdata)) + return 1; + + /* No DEBUG_LOG because all SOSs are unhandled */ + return 0; +} + +static int on_resize(int rows, int cols, void *user) +{ + VTermState *state = user; + VTermPos oldpos = state->pos; + + if(cols != state->cols) { + unsigned char *newtabstops = vterm_allocator_malloc(state->vt, (cols + 7) / 8); + + /* TODO: This can all be done much more efficiently bytewise */ + int col; + for(col = 0; col < state->cols && col < cols; col++) { + unsigned char mask = 1 << (col & 7); + if(state->tabstops[col >> 3] & mask) + newtabstops[col >> 3] |= mask; + else + newtabstops[col >> 3] &= ~mask; + } + + for( ; col < cols; col++) { + unsigned char mask = 1 << (col & 7); + if(col % 8 == 0) + newtabstops[col >> 3] |= mask; + else + newtabstops[col >> 3] &= ~mask; + } + + vterm_allocator_free(state->vt, state->tabstops); + state->tabstops = newtabstops; + } + + state->rows = rows; + state->cols = cols; + + if(state->scrollregion_bottom > -1) + UBOUND(state->scrollregion_bottom, state->rows); + if(state->scrollregion_right > -1) + UBOUND(state->scrollregion_right, state->cols); + + VTermStateFields fields = { + .pos = state->pos, + .lineinfos = { [0] = state->lineinfos[0], [1] = state->lineinfos[1] }, + }; + + if(state->callbacks && state->callbacks->resize) { + (*state->callbacks->resize)(rows, cols, &fields, state->cbdata); + state->pos = fields.pos; + + state->lineinfos[0] = fields.lineinfos[0]; + state->lineinfos[1] = fields.lineinfos[1]; + } + else { + if(rows != state->rows) { + for(int bufidx = BUFIDX_PRIMARY; bufidx <= BUFIDX_ALTSCREEN; bufidx++) { + VTermLineInfo *oldlineinfo = state->lineinfos[bufidx]; + if(!oldlineinfo) + continue; + + VTermLineInfo *newlineinfo = vterm_allocator_malloc(state->vt, rows * sizeof(VTermLineInfo)); + + int row; + for(row = 0; row < state->rows && row < rows; row++) { + newlineinfo[row] = oldlineinfo[row]; + } + + for( ; row < rows; row++) { + newlineinfo[row] = (VTermLineInfo){ + .doublewidth = 0, + }; + } + + vterm_allocator_free(state->vt, state->lineinfos[bufidx]); + state->lineinfos[bufidx] = newlineinfo; + } + } + } + + state->lineinfo = state->lineinfos[state->mode.alt_screen ? BUFIDX_ALTSCREEN : BUFIDX_PRIMARY]; + + if(state->at_phantom && state->pos.col < cols-1) { + state->at_phantom = 0; + state->pos.col++; + } + + if(state->pos.row < 0) + state->pos.row = 0; + if(state->pos.row >= rows) + state->pos.row = rows - 1; + if(state->pos.col < 0) + state->pos.col = 0; + if(state->pos.col >= cols) + state->pos.col = cols - 1; + + updatecursor(state, &oldpos, 1); + + return 1; +} + +static const VTermParserCallbacks parser_callbacks = { + .text = on_text, + .control = on_control, + .escape = on_escape, + .csi = on_csi, + .osc = on_osc, + .dcs = on_dcs, + .apc = on_apc, + .pm = on_pm, + .sos = on_sos, + .resize = on_resize, +}; + +VTermState *vterm_obtain_state(VTerm *vt) +{ + if(vt->state) + return vt->state; + + VTermState *state = vterm_state_new(vt); + vt->state = state; + + vterm_parser_set_callbacks(vt, &parser_callbacks, state); + + return state; +} + +void vterm_state_reset(VTermState *state, int hard) +{ + state->scrollregion_top = 0; + state->scrollregion_bottom = -1; + state->scrollregion_left = 0; + state->scrollregion_right = -1; + + state->mode.keypad = 0; + state->mode.cursor = 0; + state->mode.autowrap = 1; + state->mode.insert = 0; + state->mode.newline = 0; + state->mode.alt_screen = 0; + state->mode.origin = 0; + state->mode.leftrightmargin = 0; + state->mode.bracketpaste = 0; + state->mode.report_focus = 0; + + state->mouse_flags = 0; + + state->vt->mode.ctrl8bit = 0; + + for(int col = 0; col < state->cols; col++) + if(col % 8 == 0) + set_col_tabstop(state, col); + else + clear_col_tabstop(state, col); + + for(int row = 0; row < state->rows; row++) + set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF); + + if(state->callbacks && state->callbacks->initpen) + (*state->callbacks->initpen)(state->cbdata); + + vterm_state_resetpen(state); + + VTermEncoding *default_enc = state->vt->mode.utf8 ? + vterm_lookup_encoding(ENC_UTF8, 'u') : + vterm_lookup_encoding(ENC_SINGLE_94, 'B'); + + for(int i = 0; i < 4; i++) { + state->encoding[i].enc = default_enc; + if(default_enc->init) + (*default_enc->init)(default_enc, state->encoding[i].data); + } + + state->gl_set = 0; + state->gr_set = 1; + state->gsingle_set = 0; + + state->protected_cell = 0; + + // Initialise the props + settermprop_bool(state, VTERM_PROP_CURSORVISIBLE, 1); + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 1); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BLOCK); + + if(hard) { + state->pos.row = 0; + state->pos.col = 0; + state->at_phantom = 0; + + VTermRect rect = { 0, state->rows, 0, state->cols }; + erase(state, rect, 0); + } +} + +void vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos) +{ + *cursorpos = state->pos; +} + +void vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user) +{ + if(callbacks) { + state->callbacks = callbacks; + state->cbdata = user; + + if(state->callbacks && state->callbacks->initpen) + (*state->callbacks->initpen)(state->cbdata); + } + else { + state->callbacks = NULL; + state->cbdata = NULL; + } +} + +void *vterm_state_get_cbdata(VTermState *state) +{ + return state->cbdata; +} + +void vterm_state_set_unrecognised_fallbacks(VTermState *state, const VTermStateFallbacks *fallbacks, void *user) +{ + if(fallbacks) { + state->fallbacks = fallbacks; + state->fbdata = user; + } + else { + state->fallbacks = NULL; + state->fbdata = NULL; + } +} + +void *vterm_state_get_unrecognised_fbdata(VTermState *state) +{ + return state->fbdata; +} + +int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val) +{ + /* Only store the new value of the property if usercode said it was happy. + * This is especially important for altscreen switching */ + if(state->callbacks && state->callbacks->settermprop) + if(!(*state->callbacks->settermprop)(prop, val, state->cbdata)) + return 0; + + switch(prop) { + case VTERM_PROP_TITLE: + case VTERM_PROP_ICONNAME: + // we don't store these, just transparently pass through + return 1; + case VTERM_PROP_CURSORVISIBLE: + state->mode.cursor_visible = val->boolean; + return 1; + case VTERM_PROP_CURSORBLINK: + state->mode.cursor_blink = val->boolean; + return 1; + case VTERM_PROP_CURSORSHAPE: + state->mode.cursor_shape = val->number; + return 1; + case VTERM_PROP_REVERSE: + state->mode.screen = val->boolean; + return 1; + case VTERM_PROP_ALTSCREEN: + state->mode.alt_screen = val->boolean; + state->lineinfo = state->lineinfos[state->mode.alt_screen ? BUFIDX_ALTSCREEN : BUFIDX_PRIMARY]; + if(state->mode.alt_screen) { + VTermRect rect = { + .start_row = 0, + .start_col = 0, + .end_row = state->rows, + .end_col = state->cols, + }; + erase(state, rect, 0); + } + return 1; + case VTERM_PROP_MOUSE: + state->mouse_flags = 0; + if(val->number) + state->mouse_flags |= MOUSE_WANT_CLICK; + if(val->number == VTERM_PROP_MOUSE_DRAG) + state->mouse_flags |= MOUSE_WANT_DRAG; + if(val->number == VTERM_PROP_MOUSE_MOVE) + state->mouse_flags |= MOUSE_WANT_MOVE; + return 1; + case VTERM_PROP_FOCUSREPORT: + state->mode.report_focus = val->boolean; + return 1; + + case VTERM_N_PROPS: + return 0; + } + + return 0; +} + +void vterm_state_focus_in(VTermState *state) +{ + if(state->mode.report_focus) + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "I"); +} + +void vterm_state_focus_out(VTermState *state) +{ + if(state->mode.report_focus) + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "O"); +} + +const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row) +{ + return state->lineinfo + row; +} + +void vterm_state_set_selection_callbacks(VTermState *state, const VTermSelectionCallbacks *callbacks, void *user, + char *buffer, size_t buflen) +{ + if(buflen && !buffer) + buffer = vterm_allocator_malloc(state->vt, buflen); + + state->selection.callbacks = callbacks; + state->selection.user = user; + state->selection.buffer = buffer; + state->selection.buflen = buflen; +} + +void vterm_state_send_selection(VTermState *state, VTermSelectionMask mask, VTermStringFragment frag) +{ + VTerm *vt = state->vt; + + if(frag.initial) { + /* TODO: support sending more than one mask bit */ + static const char selection_chars[] = "cpqs"; + int idx; + for(idx = 0; idx < 4; idx++) + if(mask & (1 << idx)) + break; + + vterm_push_output_sprintf_str(vt, C1_OSC, false, "52;%c;", selection_chars[idx]); + + state->tmp.selection.sendpartial = 0; + } + + if(frag.len) { + size_t bufcur = 0; + char *buffer = state->selection.buffer; + + uint32_t x = 0; + int n = 0; + + if(state->tmp.selection.sendpartial) { + n = state->tmp.selection.sendpartial >> 24; + x = state->tmp.selection.sendpartial & 0xFFFFFF; + + state->tmp.selection.sendpartial = 0; + } + + while((state->selection.buflen - bufcur) >= 4 && frag.len) { + x = (x << 8) | frag.str[0]; + n++; + frag.str++, frag.len--; + + if(n == 3) { + buffer[0] = base64_one((x >> 18) & 0x3F); + buffer[1] = base64_one((x >> 12) & 0x3F); + buffer[2] = base64_one((x >> 6) & 0x3F); + buffer[3] = base64_one((x >> 0) & 0x3F); + + buffer += 4, bufcur += 4; + x = 0; + n = 0; + } + + if(!frag.len || (state->selection.buflen - bufcur) < 4) { + if(bufcur) + vterm_push_output_bytes(vt, state->selection.buffer, bufcur); + + buffer = state->selection.buffer; + bufcur = 0; + } + } + + if(n) + state->tmp.selection.sendpartial = (n << 24) | x; + } + + if(frag.final) { + if(state->tmp.selection.sendpartial) { + int n = state->tmp.selection.sendpartial >> 24; + uint32_t x = state->tmp.selection.sendpartial & 0xFFFFFF; + char *buffer = state->selection.buffer; + + /* n is either 1 or 2 now */ + x <<= (n == 1) ? 16 : 8; + + buffer[0] = base64_one((x >> 18) & 0x3F); + buffer[1] = base64_one((x >> 12) & 0x3F); + buffer[2] = (n == 1) ? '=' : base64_one((x >> 6) & 0x3F); + buffer[3] = '='; + + vterm_push_output_sprintf_str(vt, 0, true, "%.*s", 4, buffer); + } + else + vterm_push_output_sprintf_str(vt, 0, true, ""); + } +} diff --git a/src/vterm/unicode.c b/src/vterm/unicode.c new file mode 100644 index 0000000000..67a155c19f --- /dev/null +++ b/src/vterm/unicode.c @@ -0,0 +1,313 @@ +#include "vterm_internal.h" + +// ### The following from http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c +// With modifications: +// made functions static +// moved 'combining' table to file scope, so other functions can see it +// ################################################################### + +/* + * This is an implementation of wcwidth() and wcswidth() (defined in + * IEEE Std 1002.1-2001) for Unicode. + * + * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html + * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html + * + * In fixed-width output devices, Latin characters all occupy a single + * "cell" position of equal width, whereas ideographic CJK characters + * occupy two such cells. Interoperability between terminal-line + * applications and (teletype-style) character terminals using the + * UTF-8 encoding requires agreement on which character should advance + * the cursor by how many cell positions. No established formal + * standards exist at present on which Unicode character shall occupy + * how many cell positions on character terminals. These routines are + * a first attempt of defining such behavior based on simple rules + * applied to data provided by the Unicode Consortium. + * + * For some graphical characters, the Unicode standard explicitly + * defines a character-cell width via the definition of the East Asian + * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes. + * In all these cases, there is no ambiguity about which width a + * terminal shall use. For characters in the East Asian Ambiguous (A) + * class, the width choice depends purely on a preference of backward + * compatibility with either historic CJK or Western practice. + * Choosing single-width for these characters is easy to justify as + * the appropriate long-term solution, as the CJK practice of + * displaying these characters as double-width comes from historic + * implementation simplicity (8-bit encoded characters were displayed + * single-width and 16-bit ones double-width, even for Greek, + * Cyrillic, etc.) and not any typographic considerations. + * + * Much less clear is the choice of width for the Not East Asian + * (Neutral) class. Existing practice does not dictate a width for any + * of these characters. It would nevertheless make sense + * typographically to allocate two character cells to characters such + * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be + * represented adequately with a single-width glyph. The following + * routines at present merely assign a single-cell width to all + * neutral characters, in the interest of simplicity. This is not + * entirely satisfactory and should be reconsidered before + * establishing a formal standard in this area. At the moment, the + * decision which Not East Asian (Neutral) characters should be + * represented by double-width glyphs cannot yet be answered by + * applying a simple rule from the Unicode database content. Setting + * up a proper standard for the behavior of UTF-8 character terminals + * will require a careful analysis not only of each Unicode character, + * but also of each presentation form, something the author of these + * routines has avoided to do so far. + * + * http://www.unicode.org/unicode/reports/tr11/ + * + * Markus Kuhn -- 2007-05-26 (Unicode 5.0) + * + * Permission to use, copy, modify, and distribute this software + * for any purpose and without fee is hereby granted. The author + * disclaims all warranties with regard to this software. + * + * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c + */ + +struct interval { + int first; + int last; +}; + +/* sorted list of non-overlapping intervals of non-spacing characters */ +/* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ +static const struct interval combining[] = { + { 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 }, + { 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, + { 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 }, + { 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 }, + { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, + { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A }, + { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 }, + { 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D }, + { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, + { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, + { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C }, + { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, + { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, + { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, + { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C }, + { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D }, + { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 }, + { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 }, + { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC }, + { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, + { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, + { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, + { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, + { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, + { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, + { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, + { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, + { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, + { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, + { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F }, + { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 }, + { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD }, + { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD }, + { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 }, + { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B }, + { 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 }, + { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 }, + { 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF }, + { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 }, + { 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F }, + { 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B }, + { 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, + { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }, + { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F }, + { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 }, + { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD }, + { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F }, + { 0xE0100, 0xE01EF } +}; + + +/* auxiliary function for binary search in interval table */ +static int bisearch(uint32_t ucs, const struct interval *table, int max) { + int min = 0; + int mid; + + if (ucs < (uint32_t) table[0].first || ucs > (uint32_t) table[max].last) + return 0; + while (max >= min) { + mid = (min + max) / 2; + if (ucs > (uint32_t) table[mid].last) + min = mid + 1; + else if (ucs < (uint32_t) table[mid].first) + max = mid - 1; + else + return 1; + } + + return 0; +} + + +/* The following two functions define the column width of an ISO 10646 + * character as follows: + * + * - The null character (U+0000) has a column width of 0. + * + * - Other C0/C1 control characters and DEL will lead to a return + * value of -1. + * + * - Non-spacing and enclosing combining characters (general + * category code Mn or Me in the Unicode database) have a + * column width of 0. + * + * - SOFT HYPHEN (U+00AD) has a column width of 1. + * + * - Other format characters (general category code Cf in the Unicode + * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. + * + * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) + * have a column width of 0. + * + * - Spacing characters in the East Asian Wide (W) or East Asian + * Full-width (F) category as defined in Unicode Technical + * Report #11 have a column width of 2. + * + * - All remaining characters (including all printable + * ISO 8859-1 and WGL4 characters, Unicode control characters, + * etc.) have a column width of 1. + * + * This implementation assumes that uint32_t characters are encoded + * in ISO 10646. + */ + + +static int mk_wcwidth(uint32_t ucs) +{ + /* test for 8-bit control characters */ + if (ucs == 0) + return 0; + if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) + return -1; + + /* binary search in table of non-spacing characters */ + if (bisearch(ucs, combining, + sizeof(combining) / sizeof(struct interval) - 1)) + return 0; + + /* if we arrive here, ucs is not a combining or C0/C1 control character */ + + return 1 + + (ucs >= 0x1100 && + (ucs <= 0x115f || /* Hangul Jamo init. consonants */ + ucs == 0x2329 || ucs == 0x232a || + (ucs >= 0x2e80 && ucs <= 0xa4cf && + ucs != 0x303f) || /* CJK ... Yi */ + (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ + (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ + (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */ + (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ + (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */ + (ucs >= 0xffe0 && ucs <= 0xffe6) || + (ucs >= 0x20000 && ucs <= 0x2fffd) || + (ucs >= 0x30000 && ucs <= 0x3fffd))); +} + + +#ifdef USE_MK_WCWIDTH_CJK + +/* + * The following functions are the same as mk_wcwidth() and + * mk_wcswidth(), except that spacing characters in the East Asian + * Ambiguous (A) category as defined in Unicode Technical Report #11 + * have a column width of 2. This variant might be useful for users of + * CJK legacy encodings who want to migrate to UCS without changing + * the traditional terminal character-width behaviour. It is not + * otherwise recommended for general use. + */ +static int mk_wcwidth_cjk(uint32_t ucs) +{ + /* sorted list of non-overlapping intervals of East Asian Ambiguous + * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */ + static const struct interval ambiguous[] = { + { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 }, + { 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 }, + { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 }, + { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 }, + { 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED }, + { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA }, + { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 }, + { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B }, + { 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 }, + { 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 }, + { 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 }, + { 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE }, + { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 }, + { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA }, + { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 }, + { 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB }, + { 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB }, + { 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 }, + { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 }, + { 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 }, + { 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 }, + { 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 }, + { 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 }, + { 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 }, + { 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC }, + { 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 }, + { 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 }, + { 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 }, + { 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 }, + { 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 }, + { 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 }, + { 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B }, + { 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 }, + { 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 }, + { 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E }, + { 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 }, + { 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 }, + { 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F }, + { 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 }, + { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF }, + { 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B }, + { 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 }, + { 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 }, + { 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 }, + { 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 }, + { 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 }, + { 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 }, + { 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 }, + { 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 }, + { 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F }, + { 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF }, + { 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD } + }; + + /* binary search in table of non-spacing characters */ + if (bisearch(ucs, ambiguous, + sizeof(ambiguous) / sizeof(struct interval) - 1)) + return 2; + + return mk_wcwidth(ucs); +} + +#endif + +// ################################ +// ### The rest added by Paul Evans + +static const struct interval fullwidth[] = { +#include "fullwidth.inc" +}; + +INTERNAL int vterm_unicode_width(uint32_t codepoint) +{ + if(bisearch(codepoint, fullwidth, sizeof(fullwidth) / sizeof(fullwidth[0]) - 1)) + return 2; + + return mk_wcwidth(codepoint); +} + +INTERNAL int vterm_unicode_is_combining(uint32_t codepoint) +{ + return bisearch(codepoint, combining, sizeof(combining) / sizeof(struct interval) - 1); +} diff --git a/src/vterm/vterm.c b/src/vterm/vterm.c new file mode 100644 index 0000000000..870a61566e --- /dev/null +++ b/src/vterm/vterm.c @@ -0,0 +1,431 @@ +#include "vterm_internal.h" + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +/***************** + * API functions * + *****************/ + +static void *default_malloc(size_t size, void *allocdata) +{ + void *ptr = malloc(size); + if(ptr) + memset(ptr, 0, size); + return ptr; +} + +static void default_free(void *ptr, void *allocdata) +{ + free(ptr); +} + +static VTermAllocatorFunctions default_allocator = { + .malloc = &default_malloc, + .free = &default_free, +}; + +VTerm *vterm_new(int rows, int cols) +{ + return vterm_build(&(const struct VTermBuilder){ + .rows = rows, + .cols = cols, + }); +} + +VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata) +{ + return vterm_build(&(const struct VTermBuilder){ + .rows = rows, + .cols = cols, + .allocator = funcs, + .allocdata = allocdata, + }); +} + +/* A handy macro for defaulting values out of builder fields */ +#define DEFAULT(v, def) ((v) ? (v) : (def)) + +VTerm *vterm_build(const struct VTermBuilder *builder) +{ + const VTermAllocatorFunctions *allocator = DEFAULT(builder->allocator, &default_allocator); + + /* Need to bootstrap using the allocator function directly */ + VTerm *vt = (*allocator->malloc)(sizeof(VTerm), builder->allocdata); + + vt->allocator = allocator; + vt->allocdata = builder->allocdata; + + vt->rows = builder->rows; + vt->cols = builder->cols; + + vt->parser.state = NORMAL; + + vt->parser.callbacks = NULL; + vt->parser.cbdata = NULL; + + vt->parser.emit_nul = false; + + vt->outfunc = NULL; + vt->outdata = NULL; + + vt->outbuffer_len = DEFAULT(builder->outbuffer_len, 4096); + vt->outbuffer_cur = 0; + vt->outbuffer = vterm_allocator_malloc(vt, vt->outbuffer_len); + + vt->tmpbuffer_len = DEFAULT(builder->tmpbuffer_len, 4096); + vt->tmpbuffer = vterm_allocator_malloc(vt, vt->tmpbuffer_len); + + return vt; +} + +void vterm_free(VTerm *vt) +{ + if(vt->screen) + vterm_screen_free(vt->screen); + + if(vt->state) + vterm_state_free(vt->state); + + vterm_allocator_free(vt, vt->outbuffer); + vterm_allocator_free(vt, vt->tmpbuffer); + + vterm_allocator_free(vt, vt); +} + +INTERNAL void *vterm_allocator_malloc(VTerm *vt, size_t size) +{ + return (*vt->allocator->malloc)(size, vt->allocdata); +} + +INTERNAL void vterm_allocator_free(VTerm *vt, void *ptr) +{ + (*vt->allocator->free)(ptr, vt->allocdata); +} + +void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp) +{ + if(rowsp) + *rowsp = vt->rows; + if(colsp) + *colsp = vt->cols; +} + +void vterm_set_size(VTerm *vt, int rows, int cols) +{ + if(rows < 1 || cols < 1) + return; + + vt->rows = rows; + vt->cols = cols; + + if(vt->parser.callbacks && vt->parser.callbacks->resize) + (*vt->parser.callbacks->resize)(rows, cols, vt->parser.cbdata); +} + +int vterm_get_utf8(const VTerm *vt) +{ + return vt->mode.utf8; +} + +void vterm_set_utf8(VTerm *vt, int is_utf8) +{ + vt->mode.utf8 = is_utf8; +} + +void vterm_output_set_callback(VTerm *vt, VTermOutputCallback *func, void *user) +{ + vt->outfunc = func; + vt->outdata = user; +} + +INTERNAL void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len) +{ + if(vt->outfunc) { + (vt->outfunc)(bytes, len, vt->outdata); + return; + } + + if(len > vt->outbuffer_len - vt->outbuffer_cur) + return; + + memcpy(vt->outbuffer + vt->outbuffer_cur, bytes, len); + vt->outbuffer_cur += len; +} + +INTERNAL void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args) +{ + size_t len = vsnprintf(vt->tmpbuffer, vt->tmpbuffer_len, + format, args); + + vterm_push_output_bytes(vt, vt->tmpbuffer, len); +} + +INTERNAL void vterm_push_output_sprintf(VTerm *vt, const char *format, ...) +{ + va_list args; + va_start(args, format); + vterm_push_output_vsprintf(vt, format, args); + va_end(args); +} + +INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...) +{ + size_t cur; + + if(ctrl >= 0x80 && !vt->mode.ctrl8bit) + cur = snprintf(vt->tmpbuffer, vt->tmpbuffer_len, + ESC_S "%c", ctrl - 0x40); + else + cur = snprintf(vt->tmpbuffer, vt->tmpbuffer_len, + "%c", ctrl); + + if(cur >= vt->tmpbuffer_len) + return; + + va_list args; + va_start(args, fmt); + cur += vsnprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + fmt, args); + va_end(args); + + if(cur >= vt->tmpbuffer_len) + return; + + vterm_push_output_bytes(vt, vt->tmpbuffer, cur); +} + +INTERNAL void vterm_push_output_sprintf_str(VTerm *vt, unsigned char ctrl, bool term, const char *fmt, ...) +{ + size_t cur = 0; + + if(ctrl) { + if(ctrl >= 0x80 && !vt->mode.ctrl8bit) + cur = snprintf(vt->tmpbuffer, vt->tmpbuffer_len, + ESC_S "%c", ctrl - 0x40); + else + cur = snprintf(vt->tmpbuffer, vt->tmpbuffer_len, + "%c", ctrl); + + if(cur >= vt->tmpbuffer_len) + return; + } + + va_list args; + va_start(args, fmt); + cur += vsnprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + fmt, args); + va_end(args); + + if(cur >= vt->tmpbuffer_len) + return; + + if(term) { + cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + vt->mode.ctrl8bit ? "\x9C" : ESC_S "\\"); // ST + + if(cur >= vt->tmpbuffer_len) + return; + } + + vterm_push_output_bytes(vt, vt->tmpbuffer, cur); +} + +size_t vterm_output_get_buffer_size(const VTerm *vt) +{ + return vt->outbuffer_len; +} + +size_t vterm_output_get_buffer_current(const VTerm *vt) +{ + return vt->outbuffer_cur; +} + +size_t vterm_output_get_buffer_remaining(const VTerm *vt) +{ + return vt->outbuffer_len - vt->outbuffer_cur; +} + +size_t vterm_output_read(VTerm *vt, char *buffer, size_t len) +{ + if(len > vt->outbuffer_cur) + len = vt->outbuffer_cur; + + memcpy(buffer, vt->outbuffer, len); + + if(len < vt->outbuffer_cur) + memmove(vt->outbuffer, vt->outbuffer + len, vt->outbuffer_cur - len); + + vt->outbuffer_cur -= len; + + return len; +} + +VTermValueType vterm_get_attr_type(VTermAttr attr) +{ + switch(attr) { + case VTERM_ATTR_BOLD: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_UNDERLINE: return VTERM_VALUETYPE_INT; + case VTERM_ATTR_ITALIC: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_BLINK: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_REVERSE: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_CONCEAL: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_STRIKE: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_FONT: return VTERM_VALUETYPE_INT; + case VTERM_ATTR_FOREGROUND: return VTERM_VALUETYPE_COLOR; + case VTERM_ATTR_BACKGROUND: return VTERM_VALUETYPE_COLOR; + case VTERM_ATTR_SMALL: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_BASELINE: return VTERM_VALUETYPE_INT; + case VTERM_ATTR_URI: return VTERM_VALUETYPE_INT; + + case VTERM_N_ATTRS: return 0; + } + return 0; /* UNREACHABLE */ +} + +VTermValueType vterm_get_prop_type(VTermProp prop) +{ + switch(prop) { + case VTERM_PROP_CURSORVISIBLE: return VTERM_VALUETYPE_BOOL; + case VTERM_PROP_CURSORBLINK: return VTERM_VALUETYPE_BOOL; + case VTERM_PROP_ALTSCREEN: return VTERM_VALUETYPE_BOOL; + case VTERM_PROP_TITLE: return VTERM_VALUETYPE_STRING; + case VTERM_PROP_ICONNAME: return VTERM_VALUETYPE_STRING; + case VTERM_PROP_REVERSE: return VTERM_VALUETYPE_BOOL; + case VTERM_PROP_CURSORSHAPE: return VTERM_VALUETYPE_INT; + case VTERM_PROP_MOUSE: return VTERM_VALUETYPE_INT; + case VTERM_PROP_FOCUSREPORT: return VTERM_VALUETYPE_BOOL; + + case VTERM_N_PROPS: return 0; + } + return 0; /* UNREACHABLE */ +} + +void vterm_scroll_rect(VTermRect rect, + int downward, + int rightward, + int (*moverect)(VTermRect src, VTermRect dest, void *user), + int (*eraserect)(VTermRect rect, int selective, void *user), + void *user) +{ + VTermRect src; + VTermRect dest; + + if(abs(downward) >= rect.end_row - rect.start_row || + abs(rightward) >= rect.end_col - rect.start_col) { + /* Scroll more than area; just erase the lot */ + (*eraserect)(rect, 0, user); + return; + } + + if(rightward >= 0) { + /* rect: [XXX................] + * src: [----------------] + * dest: [----------------] + */ + dest.start_col = rect.start_col; + dest.end_col = rect.end_col - rightward; + src.start_col = rect.start_col + rightward; + src.end_col = rect.end_col; + } + else { + /* rect: [................XXX] + * src: [----------------] + * dest: [----------------] + */ + int leftward = -rightward; + dest.start_col = rect.start_col + leftward; + dest.end_col = rect.end_col; + src.start_col = rect.start_col; + src.end_col = rect.end_col - leftward; + } + + if(downward >= 0) { + dest.start_row = rect.start_row; + dest.end_row = rect.end_row - downward; + src.start_row = rect.start_row + downward; + src.end_row = rect.end_row; + } + else { + int upward = -downward; + dest.start_row = rect.start_row + upward; + dest.end_row = rect.end_row; + src.start_row = rect.start_row; + src.end_row = rect.end_row - upward; + } + + if(moverect) + (*moverect)(dest, src, user); + + if(downward > 0) + rect.start_row = rect.end_row - downward; + else if(downward < 0) + rect.end_row = rect.start_row - downward; + + if(rightward > 0) + rect.start_col = rect.end_col - rightward; + else if(rightward < 0) + rect.end_col = rect.start_col - rightward; + + (*eraserect)(rect, 0, user); +} + +void vterm_copy_cells(VTermRect dest, + VTermRect src, + void (*copycell)(VTermPos dest, VTermPos src, void *user), + void *user) +{ + int downward = src.start_row - dest.start_row; + int rightward = src.start_col - dest.start_col; + + int init_row, test_row, init_col, test_col; + int inc_row, inc_col; + + if(downward < 0) { + init_row = dest.end_row - 1; + test_row = dest.start_row - 1; + inc_row = -1; + } + else /* downward >= 0 */ { + init_row = dest.start_row; + test_row = dest.end_row; + inc_row = +1; + } + + if(rightward < 0) { + init_col = dest.end_col - 1; + test_col = dest.start_col - 1; + inc_col = -1; + } + else /* rightward >= 0 */ { + init_col = dest.start_col; + test_col = dest.end_col; + inc_col = +1; + } + + VTermPos pos; + for(pos.row = init_row; pos.row != test_row; pos.row += inc_row) + for(pos.col = init_col; pos.col != test_col; pos.col += inc_col) { + VTermPos srcpos = { pos.row + downward, pos.col + rightward }; + (*copycell)(pos, srcpos, user); + } +} + +void vterm_check_version(int major, int minor) +{ + if(major != VTERM_VERSION_MAJOR) { + fprintf(stderr, "libvterm major version mismatch; %d (wants) != %d (library)\n", + major, VTERM_VERSION_MAJOR); + exit(1); + } + + if(minor > VTERM_VERSION_MINOR) { + fprintf(stderr, "libvterm minor version mismatch; %d (wants) > %d (library)\n", + minor, VTERM_VERSION_MINOR); + exit(1); + } + + // Happy +} diff --git a/src/vterm/vterm.h b/src/vterm/vterm.h new file mode 100644 index 0000000000..929418c63a --- /dev/null +++ b/src/vterm/vterm.h @@ -0,0 +1,641 @@ +#ifndef __VTERM_H__ +#define __VTERM_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <stdlib.h> +#include <stdbool.h> + +#include "vterm_keycodes.h" + +#define VTERM_VERSION_MAJOR 0 +#define VTERM_VERSION_MINOR 3 +#define VTERM_VERSION_PATCH 3 + +#define VTERM_CHECK_VERSION \ + vterm_check_version(VTERM_VERSION_MAJOR, VTERM_VERSION_MINOR) + +/* Any cell can contain at most one basic printing character and 5 combining + * characters. This number could be changed but will be ABI-incompatible if + * you do */ +#define VTERM_MAX_CHARS_PER_CELL 6 + +typedef struct VTerm VTerm; +typedef struct VTermState VTermState; +typedef struct VTermScreen VTermScreen; + +typedef struct { + int row; + int col; +} VTermPos; + +/* some small utility functions; we can just keep these static here */ + +/* order points by on-screen flow order */ +static inline int vterm_pos_cmp(VTermPos a, VTermPos b) +{ + return (a.row == b.row) ? a.col - b.col : a.row - b.row; +} + +typedef struct { + int start_row; + int end_row; + int start_col; + int end_col; +} VTermRect; + +/* true if the rect contains the point */ +static inline int vterm_rect_contains(VTermRect r, VTermPos p) +{ + return p.row >= r.start_row && p.row < r.end_row && + p.col >= r.start_col && p.col < r.end_col; +} + +/* move a rect */ +static inline void vterm_rect_move(VTermRect *rect, int row_delta, int col_delta) +{ + rect->start_row += row_delta; rect->end_row += row_delta; + rect->start_col += col_delta; rect->end_col += col_delta; +} + +/** + * Bit-field describing the content of the tagged union `VTermColor`. + */ +typedef enum { + /** + * If the lower bit of `type` is not set, the colour is 24-bit RGB. + */ + VTERM_COLOR_RGB = 0x00, + + /** + * The colour is an index into a palette of 256 colours. + */ + VTERM_COLOR_INDEXED = 0x01, + + /** + * Mask that can be used to extract the RGB/Indexed bit. + */ + VTERM_COLOR_TYPE_MASK = 0x01, + + /** + * If set, indicates that this colour should be the default foreground + * color, i.e. there was no SGR request for another colour. When + * rendering this colour it is possible to ignore "idx" and just use a + * colour that is not in the palette. + */ + VTERM_COLOR_DEFAULT_FG = 0x02, + + /** + * If set, indicates that this colour should be the default background + * color, i.e. there was no SGR request for another colour. A common + * option when rendering this colour is to not render a background at + * all, for example by rendering the window transparently at this spot. + */ + VTERM_COLOR_DEFAULT_BG = 0x04, + + /** + * Mask that can be used to extract the default foreground/background bit. + */ + VTERM_COLOR_DEFAULT_MASK = 0x06 +} VTermColorType; + +/** + * Returns true if the VTERM_COLOR_RGB `type` flag is set, indicating that the + * given VTermColor instance is an indexed colour. + */ +#define VTERM_COLOR_IS_INDEXED(col) \ + (((col)->type & VTERM_COLOR_TYPE_MASK) == VTERM_COLOR_INDEXED) + +/** + * Returns true if the VTERM_COLOR_INDEXED `type` flag is set, indicating that + * the given VTermColor instance is an rgb colour. + */ +#define VTERM_COLOR_IS_RGB(col) \ + (((col)->type & VTERM_COLOR_TYPE_MASK) == VTERM_COLOR_RGB) + +/** + * Returns true if the VTERM_COLOR_DEFAULT_FG `type` flag is set, indicating + * that the given VTermColor instance corresponds to the default foreground + * color. + */ +#define VTERM_COLOR_IS_DEFAULT_FG(col) \ + (!!((col)->type & VTERM_COLOR_DEFAULT_FG)) + +/** + * Returns true if the VTERM_COLOR_DEFAULT_BG `type` flag is set, indicating + * that the given VTermColor instance corresponds to the default background + * color. + */ +#define VTERM_COLOR_IS_DEFAULT_BG(col) \ + (!!((col)->type & VTERM_COLOR_DEFAULT_BG)) + +/** + * Tagged union storing either an RGB color or an index into a colour palette. + * In order to convert indexed colours to RGB, you may use the + * vterm_state_convert_color_to_rgb() or vterm_screen_convert_color_to_rgb() + * functions which lookup the RGB colour from the palette maintained by a + * VTermState or VTermScreen instance. + */ +typedef union { + /** + * Tag indicating which union member is actually valid. This variable + * coincides with the `type` member of the `rgb` and the `indexed` struct + * in memory. Please use the `VTERM_COLOR_IS_*` test macros to check whether + * a particular type flag is set. + */ + uint8_t type; + + /** + * Valid if `VTERM_COLOR_IS_RGB(type)` is true. Holds the RGB colour values. + */ + struct { + /** + * Same as the top-level `type` member stored in VTermColor. + */ + uint8_t type; + + /** + * The actual 8-bit red, green, blue colour values. + */ + uint8_t red, green, blue; + } rgb; + + /** + * If `VTERM_COLOR_IS_INDEXED(type)` is true, this member holds the index into + * the colour palette. + */ + struct { + /** + * Same as the top-level `type` member stored in VTermColor. + */ + uint8_t type; + + /** + * Index into the colour map. + */ + uint8_t idx; + } indexed; +} VTermColor; + +/** + * Constructs a new VTermColor instance representing the given RGB values. + */ +static inline void vterm_color_rgb(VTermColor *col, uint8_t red, uint8_t green, + uint8_t blue) +{ + col->type = VTERM_COLOR_RGB; + col->rgb.red = red; + col->rgb.green = green; + col->rgb.blue = blue; +} + +/** + * Construct a new VTermColor instance representing an indexed color with the + * given index. + */ +static inline void vterm_color_indexed(VTermColor *col, uint8_t idx) +{ + col->type = VTERM_COLOR_INDEXED; + col->indexed.idx = idx; +} + +/** + * Compares two colours. Returns true if the colors are equal, false otherwise. + */ +int vterm_color_is_equal(const VTermColor *a, const VTermColor *b); + +typedef enum { + /* VTERM_VALUETYPE_NONE = 0 */ + VTERM_VALUETYPE_BOOL = 1, + VTERM_VALUETYPE_INT, + VTERM_VALUETYPE_STRING, + VTERM_VALUETYPE_COLOR, + + VTERM_N_VALUETYPES +} VTermValueType; + +typedef struct { + const char *str; + size_t len : 30; + bool initial : 1; + bool final : 1; +} VTermStringFragment; + +typedef union { + int boolean; + int number; + VTermStringFragment string; + VTermColor color; +} VTermValue; + +typedef enum { + /* VTERM_ATTR_NONE = 0 */ + VTERM_ATTR_BOLD = 1, // bool: 1, 22 + VTERM_ATTR_UNDERLINE, // number: 4, 21, 24 + VTERM_ATTR_ITALIC, // bool: 3, 23 + VTERM_ATTR_BLINK, // bool: 5, 25 + VTERM_ATTR_REVERSE, // bool: 7, 27 + VTERM_ATTR_CONCEAL, // bool: 8, 28 + VTERM_ATTR_STRIKE, // bool: 9, 29 + VTERM_ATTR_FONT, // number: 10-19 + VTERM_ATTR_FOREGROUND, // color: 30-39 90-97 + VTERM_ATTR_BACKGROUND, // color: 40-49 100-107 + VTERM_ATTR_SMALL, // bool: 73, 74, 75 + VTERM_ATTR_BASELINE, // number: 73, 74, 75 + VTERM_ATTR_URI, // number + + VTERM_N_ATTRS +} VTermAttr; + +typedef enum { + /* VTERM_PROP_NONE = 0 */ + VTERM_PROP_CURSORVISIBLE = 1, // bool + VTERM_PROP_CURSORBLINK, // bool + VTERM_PROP_ALTSCREEN, // bool + VTERM_PROP_TITLE, // string + VTERM_PROP_ICONNAME, // string + VTERM_PROP_REVERSE, // bool + VTERM_PROP_CURSORSHAPE, // number + VTERM_PROP_MOUSE, // number + VTERM_PROP_FOCUSREPORT, // bool + + VTERM_N_PROPS +} VTermProp; + +enum { + VTERM_PROP_CURSORSHAPE_BLOCK = 1, + VTERM_PROP_CURSORSHAPE_UNDERLINE, + VTERM_PROP_CURSORSHAPE_BAR_LEFT, + + VTERM_N_PROP_CURSORSHAPES +}; + +enum { + VTERM_PROP_MOUSE_NONE = 0, + VTERM_PROP_MOUSE_CLICK, + VTERM_PROP_MOUSE_DRAG, + VTERM_PROP_MOUSE_MOVE, + + VTERM_N_PROP_MOUSES +}; + +typedef enum { + VTERM_SELECTION_CLIPBOARD = (1<<0), + VTERM_SELECTION_PRIMARY = (1<<1), + VTERM_SELECTION_SECONDARY = (1<<2), + VTERM_SELECTION_SELECT = (1<<3), + VTERM_SELECTION_CUT0 = (1<<4), /* also CUT1 .. CUT7 by bitshifting */ +} VTermSelectionMask; + +typedef struct { + const uint32_t *chars; + int width; + unsigned int protected_cell:1; /* DECSCA-protected against DECSEL/DECSED */ + unsigned int dwl:1; /* DECDWL or DECDHL double-width line */ + unsigned int dhl:2; /* DECDHL double-height line (1=top 2=bottom) */ +} VTermGlyphInfo; + +typedef struct { + unsigned int doublewidth:1; /* DECDWL or DECDHL line */ + unsigned int doubleheight:2; /* DECDHL line (1=top 2=bottom) */ + unsigned int continuation:1; /* Line is a flow continuation of the previous */ +} VTermLineInfo; + +/* Copies of VTermState fields that the 'resize' callback might have reason to + * edit. 'resize' callback gets total control of these fields and may + * free-and-reallocate them if required. They will be copied back from the + * struct after the callback has returned. + */ +typedef struct { + VTermPos pos; /* current cursor position */ + VTermLineInfo *lineinfos[2]; /* [1] may be NULL */ +} VTermStateFields; + +typedef struct { + /* libvterm relies on this memory to be zeroed out before it is returned + * by the allocator. */ + void *(*malloc)(size_t size, void *allocdata); + void (*free)(void *ptr, void *allocdata); +} VTermAllocatorFunctions; + +void vterm_check_version(int major, int minor); + +struct VTermBuilder { + int ver; /* currently unused but reserved for some sort of ABI version flag */ + + int rows, cols; + + const VTermAllocatorFunctions *allocator; + void *allocdata; + + /* Override default sizes for various structures */ + size_t outbuffer_len; /* default: 4096 */ + size_t tmpbuffer_len; /* default: 4096 */ +}; + +VTerm *vterm_build(const struct VTermBuilder *builder); + +/* A convenient shortcut for default cases */ +VTerm *vterm_new(int rows, int cols); +/* This shortcuts are generally discouraged in favour of just using vterm_build() */ +VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata); + +void vterm_free(VTerm* vt); + +void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp); +void vterm_set_size(VTerm *vt, int rows, int cols); + +int vterm_get_utf8(const VTerm *vt); +void vterm_set_utf8(VTerm *vt, int is_utf8); + +size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len); + +/* Setting output callback will override the buffer logic */ +typedef void VTermOutputCallback(const char *s, size_t len, void *user); +void vterm_output_set_callback(VTerm *vt, VTermOutputCallback *func, void *user); + +/* These buffer functions only work if output callback is NOT set + * These are deprecated and will be removed in a later version */ +size_t vterm_output_get_buffer_size(const VTerm *vt); +size_t vterm_output_get_buffer_current(const VTerm *vt); +size_t vterm_output_get_buffer_remaining(const VTerm *vt); + +/* This too */ +size_t vterm_output_read(VTerm *vt, char *buffer, size_t len); + +void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod); +void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod); + +void vterm_keyboard_start_paste(VTerm *vt); +void vterm_keyboard_end_paste(VTerm *vt); + +void vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod); +void vterm_mouse_button(VTerm *vt, int button, bool pressed, VTermModifier mod); + +// ------------ +// Parser layer +// ------------ + +/* Flag to indicate non-final subparameters in a single CSI parameter. + * Consider + * CSI 1;2:3:4;5a + * 1 4 and 5 are final. + * 2 and 3 are non-final and will have this bit set + * + * Don't confuse this with the final byte of the CSI escape; 'a' in this case. + */ +#define CSI_ARG_FLAG_MORE (1U<<31) +#define CSI_ARG_MASK (~(1U<<31)) + +#define CSI_ARG_HAS_MORE(a) ((a) & CSI_ARG_FLAG_MORE) +#define CSI_ARG(a) ((a) & CSI_ARG_MASK) + +/* Can't use -1 to indicate a missing argument; use this instead */ +#define CSI_ARG_MISSING ((1UL<<31)-1) + +#define CSI_ARG_IS_MISSING(a) (CSI_ARG(a) == CSI_ARG_MISSING) +#define CSI_ARG_OR(a,def) (CSI_ARG(a) == CSI_ARG_MISSING ? (def) : CSI_ARG(a)) +#define CSI_ARG_COUNT(a) (CSI_ARG(a) == CSI_ARG_MISSING || CSI_ARG(a) == 0 ? 1 : CSI_ARG(a)) + +typedef struct { + int (*text)(const char *bytes, size_t len, void *user); + int (*control)(unsigned char control, void *user); + int (*escape)(const char *bytes, size_t len, void *user); + int (*csi)(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user); + int (*osc)(int command, VTermStringFragment frag, void *user); + int (*dcs)(const char *command, size_t commandlen, VTermStringFragment frag, void *user); + int (*apc)(VTermStringFragment frag, void *user); + int (*pm)(VTermStringFragment frag, void *user); + int (*sos)(VTermStringFragment frag, void *user); + int (*resize)(int rows, int cols, void *user); +} VTermParserCallbacks; + +void vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user); +void *vterm_parser_get_cbdata(VTerm *vt); + +/* Normally NUL, CAN, SUB and DEL are ignored. Setting this true causes them + * to be emitted by the 'control' callback + */ +void vterm_parser_set_emit_nul(VTerm *vt, bool emit); + +// ----------- +// State layer +// ----------- + +typedef struct { + int (*putglyph)(VTermGlyphInfo *info, VTermPos pos, void *user); + int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user); + int (*scrollrect)(VTermRect rect, int downward, int rightward, void *user); + int (*moverect)(VTermRect dest, VTermRect src, void *user); + int (*erase)(VTermRect rect, int selective, void *user); + int (*initpen)(void *user); + int (*setpenattr)(VTermAttr attr, VTermValue *val, void *user); + int (*settermprop)(VTermProp prop, VTermValue *val, void *user); + int (*bell)(void *user); + int (*resize)(int rows, int cols, VTermStateFields *fields, void *user); + int (*setlineinfo)(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user); + int (*sb_clear)(void *user); +} VTermStateCallbacks; + +typedef struct { + int (*control)(unsigned char control, void *user); + int (*csi)(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user); + int (*osc)(int command, VTermStringFragment frag, void *user); + int (*dcs)(const char *command, size_t commandlen, VTermStringFragment frag, void *user); + int (*apc)(VTermStringFragment frag, void *user); + int (*pm)(VTermStringFragment frag, void *user); + int (*sos)(VTermStringFragment frag, void *user); +} VTermStateFallbacks; + +typedef struct { + int (*set)(VTermSelectionMask mask, VTermStringFragment frag, void *user); + int (*query)(VTermSelectionMask mask, void *user); +} VTermSelectionCallbacks; + +VTermState *vterm_obtain_state(VTerm *vt); + +void vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user); +void *vterm_state_get_cbdata(VTermState *state); + +void vterm_state_set_unrecognised_fallbacks(VTermState *state, const VTermStateFallbacks *fallbacks, void *user); +void *vterm_state_get_unrecognised_fbdata(VTermState *state); + +void vterm_state_reset(VTermState *state, int hard); +void vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos); +void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg); +void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col); +void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg); +void vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col); +void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright); +int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val); +int vterm_state_set_penattr(VTermState *state, VTermAttr attr, VTermValueType type, VTermValue *val); +int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val); +void vterm_state_focus_in(VTermState *state); +void vterm_state_focus_out(VTermState *state); +const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row); + +/** + * Makes sure that the given color `col` is indeed an RGB colour. After this + * function returns, VTERM_COLOR_IS_RGB(col) will return true, while all other + * flags stored in `col->type` will have been reset. + * + * @param state is the VTermState instance from which the colour palette should + * be extracted. + * @param col is a pointer at the VTermColor instance that should be converted + * to an RGB colour. + */ +void vterm_state_convert_color_to_rgb(const VTermState *state, VTermColor *col); + +void vterm_state_set_selection_callbacks(VTermState *state, const VTermSelectionCallbacks *callbacks, void *user, + char *buffer, size_t buflen); + +void vterm_state_send_selection(VTermState *state, VTermSelectionMask mask, VTermStringFragment frag); + +// ------------ +// Screen layer +// ------------ + +typedef struct { + unsigned int bold : 1; + unsigned int underline : 2; + unsigned int italic : 1; + unsigned int blink : 1; + unsigned int reverse : 1; + unsigned int conceal : 1; + unsigned int strike : 1; + unsigned int font : 4; /* 0 to 9 */ + unsigned int dwl : 1; /* On a DECDWL or DECDHL line */ + unsigned int dhl : 2; /* On a DECDHL line (1=top 2=bottom) */ + unsigned int small : 1; + unsigned int baseline : 2; +} VTermScreenCellAttrs; + +enum { + VTERM_UNDERLINE_OFF, + VTERM_UNDERLINE_SINGLE, + VTERM_UNDERLINE_DOUBLE, + VTERM_UNDERLINE_CURLY, +}; + +enum { + VTERM_BASELINE_NORMAL, + VTERM_BASELINE_RAISE, + VTERM_BASELINE_LOWER, +}; + +typedef struct { + uint32_t chars[VTERM_MAX_CHARS_PER_CELL]; + char width; + VTermScreenCellAttrs attrs; + VTermColor fg, bg; + int uri; +} VTermScreenCell; + +typedef struct { + int (*damage)(VTermRect rect, void *user); + int (*moverect)(VTermRect dest, VTermRect src, void *user); + int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user); + int (*settermprop)(VTermProp prop, VTermValue *val, void *user); + int (*bell)(void *user); + int (*resize)(int rows, int cols, void *user); + int (*sb_pushline)(int cols, const VTermScreenCell *cells, void *user); + int (*sb_popline)(int cols, VTermScreenCell *cells, void *user); + int (*sb_clear)(void* user); +} VTermScreenCallbacks; + +VTermScreen *vterm_obtain_screen(VTerm *vt); + +void vterm_screen_set_callbacks(VTermScreen *screen, const VTermScreenCallbacks *callbacks, void *user); +void *vterm_screen_get_cbdata(VTermScreen *screen); + +void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermStateFallbacks *fallbacks, void *user); +void *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen); + +void vterm_screen_enable_reflow(VTermScreen *screen, bool reflow); + +// Back-compat alias for the brief time it was in 0.3-RC1 +#define vterm_screen_set_reflow vterm_screen_enable_reflow + +void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen); + +typedef enum { + VTERM_DAMAGE_CELL, /* every cell */ + VTERM_DAMAGE_ROW, /* entire rows */ + VTERM_DAMAGE_SCREEN, /* entire screen */ + VTERM_DAMAGE_SCROLL, /* entire screen + scrollrect */ + + VTERM_N_DAMAGES +} VTermDamageSize; + +void vterm_screen_flush_damage(VTermScreen *screen); +void vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size); + +void vterm_screen_reset(VTermScreen *screen, int hard); + +/* Neither of these functions NUL-terminate the buffer */ +size_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect); +size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect); + +typedef enum { + VTERM_ATTR_BOLD_MASK = 1 << 0, + VTERM_ATTR_UNDERLINE_MASK = 1 << 1, + VTERM_ATTR_ITALIC_MASK = 1 << 2, + VTERM_ATTR_BLINK_MASK = 1 << 3, + VTERM_ATTR_REVERSE_MASK = 1 << 4, + VTERM_ATTR_STRIKE_MASK = 1 << 5, + VTERM_ATTR_FONT_MASK = 1 << 6, + VTERM_ATTR_FOREGROUND_MASK = 1 << 7, + VTERM_ATTR_BACKGROUND_MASK = 1 << 8, + VTERM_ATTR_CONCEAL_MASK = 1 << 9, + VTERM_ATTR_SMALL_MASK = 1 << 10, + VTERM_ATTR_BASELINE_MASK = 1 << 11, + VTERM_ATTR_URI_MASK = 1 << 12, + + VTERM_ALL_ATTRS_MASK = (1 << 13) - 1 +} VTermAttrMask; + +int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs); + +int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell); + +int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos); + +/** + * Same as vterm_state_convert_color_to_rgb(), but takes a `screen` instead of a `state` + * instance. + */ +void vterm_screen_convert_color_to_rgb(const VTermScreen *screen, VTermColor *col); + +/** + * Similar to vterm_state_set_default_colors(), but also resets colours in the + * screen buffer(s) + */ +void vterm_screen_set_default_colors(VTermScreen *screen, const VTermColor *default_fg, const VTermColor *default_bg); + +// --------- +// Utilities +// --------- + +VTermValueType vterm_get_attr_type(VTermAttr attr); +VTermValueType vterm_get_prop_type(VTermProp prop); + +void vterm_scroll_rect(VTermRect rect, + int downward, + int rightward, + int (*moverect)(VTermRect src, VTermRect dest, void *user), + int (*eraserect)(VTermRect rect, int selective, void *user), + void *user); + +void vterm_copy_cells(VTermRect dest, + VTermRect src, + void (*copycell)(VTermPos dest, VTermPos src, void *user), + void *user); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/vterm/vterm_internal.h b/src/vterm/vterm_internal.h new file mode 100644 index 0000000000..53f9b5e100 --- /dev/null +++ b/src/vterm/vterm_internal.h @@ -0,0 +1,298 @@ +#ifndef __VTERM_INTERNAL_H__ +#define __VTERM_INTERNAL_H__ + +#include "vterm.h" + +#include <stdarg.h> + +#if defined(__GNUC__) +# define INTERNAL __attribute__((visibility("internal"))) +#else +# define INTERNAL +#endif + +#ifdef DEBUG +# define DEBUG_LOG(...) fprintf(stderr, __VA_ARGS__) +#else +# define DEBUG_LOG(...) +#endif + +#define ESC_S "\x1b" + +#define INTERMED_MAX 16 + +#define CSI_ARGS_MAX 16 +#define CSI_LEADER_MAX 16 + +#define BUFIDX_PRIMARY 0 +#define BUFIDX_ALTSCREEN 1 + +typedef struct VTermEncoding VTermEncoding; + +typedef struct { + VTermEncoding *enc; + + // This size should be increased if required by other stateful encodings + char data[4*sizeof(uint32_t)]; +} VTermEncodingInstance; + +struct VTermPen +{ + VTermColor fg; + VTermColor bg; + int uri; + unsigned int bold:1; + unsigned int underline:2; + unsigned int italic:1; + unsigned int blink:1; + unsigned int reverse:1; + unsigned int conceal:1; + unsigned int strike:1; + unsigned int font:4; /* To store 0-9 */ + unsigned int small:1; + unsigned int baseline:2; +}; + +struct VTermState +{ + VTerm *vt; + + const VTermStateCallbacks *callbacks; + void *cbdata; + + const VTermStateFallbacks *fallbacks; + void *fbdata; + + int rows; + int cols; + + /* Current cursor position */ + VTermPos pos; + + int at_phantom; /* True if we're on the "81st" phantom column to defer a wraparound */ + + int scrollregion_top; + int scrollregion_bottom; /* -1 means unbounded */ +#define SCROLLREGION_BOTTOM(state) ((state)->scrollregion_bottom > -1 ? (state)->scrollregion_bottom : (state)->rows) + int scrollregion_left; +#define SCROLLREGION_LEFT(state) ((state)->mode.leftrightmargin ? (state)->scrollregion_left : 0) + int scrollregion_right; /* -1 means unbounded */ +#define SCROLLREGION_RIGHT(state) ((state)->mode.leftrightmargin && (state)->scrollregion_right > -1 ? (state)->scrollregion_right : (state)->cols) + + /* Bitvector of tab stops */ + unsigned char *tabstops; + + /* Primary and Altscreen; lineinfos[1] is lazily allocated as needed */ + VTermLineInfo *lineinfos[2]; + + /* lineinfo will == lineinfos[0] or lineinfos[1], depending on altscreen */ + VTermLineInfo *lineinfo; +#define ROWWIDTH(state,row) ((state)->lineinfo[(row)].doublewidth ? ((state)->cols / 2) : (state)->cols) +#define THISROWWIDTH(state) ROWWIDTH(state, (state)->pos.row) + + /* Mouse state */ + int mouse_col, mouse_row; + int mouse_buttons; + int mouse_flags; +#define MOUSE_WANT_CLICK 0x01 +#define MOUSE_WANT_DRAG 0x02 +#define MOUSE_WANT_MOVE 0x04 + + enum { MOUSE_X10, MOUSE_UTF8, MOUSE_SGR, MOUSE_RXVT } mouse_protocol; + + /* Last glyph output, for Unicode recombining purposes */ + uint32_t *combine_chars; + size_t combine_chars_size; // Number of ELEMENTS in the above + int combine_width; // The width of the glyph above + VTermPos combine_pos; // Position before movement + + struct { + unsigned int keypad:1; + unsigned int cursor:1; + unsigned int autowrap:1; + unsigned int insert:1; + unsigned int newline:1; + unsigned int cursor_visible:1; + unsigned int cursor_blink:1; + unsigned int cursor_shape:2; + unsigned int alt_screen:1; + unsigned int origin:1; + unsigned int screen:1; + unsigned int leftrightmargin:1; + unsigned int bracketpaste:1; + unsigned int report_focus:1; + } mode; + + VTermEncodingInstance encoding[4], encoding_utf8; + int gl_set, gr_set, gsingle_set; + + struct VTermPen pen; + + VTermColor default_fg; + VTermColor default_bg; + VTermColor colors[16]; // Store the 8 ANSI and the 8 ANSI high-brights only + + int bold_is_highbright; + + unsigned int protected_cell : 1; + + /* Saved state under DEC mode 1048/1049 */ + struct { + VTermPos pos; + struct VTermPen pen; + + struct { + unsigned int cursor_visible:1; + unsigned int cursor_blink:1; + unsigned int cursor_shape:2; + } mode; + } saved; + + /* Temporary state for DECRQSS parsing */ + union { + char decrqss[4]; + struct { + uint16_t mask; + enum { + SELECTION_INITIAL, + SELECTION_SELECTED, + SELECTION_QUERY, + SELECTION_SET_INITIAL, + SELECTION_SET, + SELECTION_INVALID, + } state : 8; + uint32_t recvpartial; + uint32_t sendpartial; + } selection; + } tmp; + + struct { + const VTermSelectionCallbacks *callbacks; + void *user; + char *buffer; + size_t buflen; + } selection; +}; + +struct VTerm +{ + const VTermAllocatorFunctions *allocator; + void *allocdata; + + int rows; + int cols; + + struct { + unsigned int utf8:1; + unsigned int ctrl8bit:1; + } mode; + + struct { + enum VTermParserState { + NORMAL, + CSI_LEADER, + CSI_ARGS, + CSI_INTERMED, + DCS_COMMAND, + /* below here are the "string states" */ + OSC_COMMAND, + OSC, + DCS, + APC, + PM, + SOS, + } state; + + bool in_esc : 1; + + int intermedlen; + char intermed[INTERMED_MAX]; + + union { + struct { + int leaderlen; + char leader[CSI_LEADER_MAX]; + + int argi; + long args[CSI_ARGS_MAX]; + } csi; + struct { + int command; + } osc; + struct { + int commandlen; + char command[CSI_LEADER_MAX]; + } dcs; + } v; + + const VTermParserCallbacks *callbacks; + void *cbdata; + + bool string_initial; + + bool emit_nul; + } parser; + + /* len == malloc()ed size; cur == number of valid bytes */ + + VTermOutputCallback *outfunc; + void *outdata; + + char *outbuffer; + size_t outbuffer_len; + size_t outbuffer_cur; + + char *tmpbuffer; + size_t tmpbuffer_len; + + VTermState *state; + VTermScreen *screen; +}; + +struct VTermEncoding { + void (*init) (VTermEncoding *enc, void *data); + void (*decode)(VTermEncoding *enc, void *data, + uint32_t cp[], int *cpi, int cplen, + const char bytes[], size_t *pos, size_t len); +}; + +typedef enum { + ENC_UTF8, + ENC_SINGLE_94 +} VTermEncodingType; + +void *vterm_allocator_malloc(VTerm *vt, size_t size); +void vterm_allocator_free(VTerm *vt, void *ptr); + +void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len); +void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args); +void vterm_push_output_sprintf(VTerm *vt, const char *format, ...); +void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...); +void vterm_push_output_sprintf_str(VTerm *vt, unsigned char ctrl, bool term, const char *fmt, ...); + +void vterm_state_free(VTermState *state); + +void vterm_state_newpen(VTermState *state); +void vterm_state_resetpen(VTermState *state); +void vterm_state_setpen(VTermState *state, const long args[], int argcount); +int vterm_state_getpen(VTermState *state, long args[], int argcount); +void vterm_state_savepen(VTermState *state, int save); + +enum { + C1_SS3 = 0x8f, + C1_DCS = 0x90, + C1_CSI = 0x9b, + C1_ST = 0x9c, + C1_OSC = 0x9d, +}; + +void vterm_state_push_output_sprintf_CSI(VTermState *vts, const char *format, ...); + +void vterm_screen_free(VTermScreen *screen); + +VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation); + +int vterm_unicode_width(uint32_t codepoint); +int vterm_unicode_is_combining(uint32_t codepoint); + +#endif diff --git a/src/vterm/vterm_keycodes.h b/src/vterm/vterm_keycodes.h new file mode 100644 index 0000000000..661759febd --- /dev/null +++ b/src/vterm/vterm_keycodes.h @@ -0,0 +1,61 @@ +#ifndef __VTERM_INPUT_H__ +#define __VTERM_INPUT_H__ + +typedef enum { + VTERM_MOD_NONE = 0x00, + VTERM_MOD_SHIFT = 0x01, + VTERM_MOD_ALT = 0x02, + VTERM_MOD_CTRL = 0x04, + + VTERM_ALL_MODS_MASK = 0x07 +} VTermModifier; + +typedef enum { + VTERM_KEY_NONE, + + VTERM_KEY_ENTER, + VTERM_KEY_TAB, + VTERM_KEY_BACKSPACE, + VTERM_KEY_ESCAPE, + + VTERM_KEY_UP, + VTERM_KEY_DOWN, + VTERM_KEY_LEFT, + VTERM_KEY_RIGHT, + + VTERM_KEY_INS, + VTERM_KEY_DEL, + VTERM_KEY_HOME, + VTERM_KEY_END, + VTERM_KEY_PAGEUP, + VTERM_KEY_PAGEDOWN, + + VTERM_KEY_FUNCTION_0 = 256, + VTERM_KEY_FUNCTION_MAX = VTERM_KEY_FUNCTION_0 + 255, + + VTERM_KEY_KP_0, + VTERM_KEY_KP_1, + VTERM_KEY_KP_2, + VTERM_KEY_KP_3, + VTERM_KEY_KP_4, + VTERM_KEY_KP_5, + VTERM_KEY_KP_6, + VTERM_KEY_KP_7, + VTERM_KEY_KP_8, + VTERM_KEY_KP_9, + VTERM_KEY_KP_MULT, + VTERM_KEY_KP_PLUS, + VTERM_KEY_KP_COMMA, + VTERM_KEY_KP_MINUS, + VTERM_KEY_KP_PERIOD, + VTERM_KEY_KP_DIVIDE, + VTERM_KEY_KP_ENTER, + VTERM_KEY_KP_EQUAL, + + VTERM_KEY_MAX, // Must be last + VTERM_N_KEYS = VTERM_KEY_MAX +} VTermKey; + +#define VTERM_KEY_FUNCTION(n) (VTERM_KEY_FUNCTION_0+(n)) + +#endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3ae11bd1a7..8db05ac839 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -19,7 +19,7 @@ if(LUA_HAS_FFI) ${TEST_OPTIONS} -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake USES_TERMINAL) - add_dependencies(unittest lua-dev-deps nvim) + add_dependencies(unittest lua_dev_deps nvim) else() message(WARNING "disabling unit tests: no Luajit FFI in ${LUA_PRG}") endif() @@ -35,7 +35,7 @@ add_custom_target(functionaltest -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake DEPENDS printenv-test printargs-test shell-test pwsh-test streams-test tty-test USES_TERMINAL) -add_dependencies(functionaltest lua-dev-deps nvim) +add_dependencies(functionaltest lua_dev_deps nvim) add_custom_target(benchmark COMMAND ${CMAKE_COMMAND} @@ -44,4 +44,4 @@ add_custom_target(benchmark -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake DEPENDS tty-test USES_TERMINAL) -add_dependencies(benchmark lua-dev-deps nvim) +add_dependencies(benchmark lua_dev_deps nvim) diff --git a/test/README.md b/test/README.md index 45b3322305..d1b053fca3 100644 --- a/test/README.md +++ b/test/README.md @@ -103,7 +103,7 @@ Debugging tests DBG 2022-06-15T18:37:45.227 T57.58016.0/c UI: stop INF 2022-06-15T18:37:45.227 T57.58016.0/c os_exit:595: Nvim exit: 0 DBG 2022-06-15T18:37:45.229 T57.58016.0 read_cb:118: closing Stream (0x7fd5d700ea18): EOF (end of file) - INF 2022-06-15T18:37:45.229 T57.58016.0 on_process_exit:400: exited: pid=58017 status=0 stoptime=0 + INF 2022-06-15T18:37:45.229 T57.58016.0 on_proc_exit:400: exited: pid=58017 status=0 stoptime=0 ``` - You can set `$GDB` to [run functional tests under gdbserver](https://github.com/neovim/neovim/pull/1527): @@ -263,7 +263,7 @@ by the semantic component they are testing. Lint ==== -`make lint` (and `make lualint`) runs [luacheck](https://github.com/mpeterv/luacheck) +`make lint` (and `make lintlua`) runs [luacheck](https://github.com/mpeterv/luacheck) on the test code. If a luacheck warning must be ignored, specify the warning code. Example: diff --git a/test/_meta.lua b/test/_meta.lua new file mode 100644 index 0000000000..b736bcc6d9 --- /dev/null +++ b/test/_meta.lua @@ -0,0 +1,10 @@ +--- @meta + +do -- Mark block as optional + ---Mark a test as placeholder. + --- + ---This will not fail or pass, it will simply be marked as "pending". + ---@param name string + ---@param block? fun() + function pending(name, block) end +end diff --git a/test/client/session.lua b/test/client/session.lua index cf3d8c4f25..f1f46c5efe 100644 --- a/test/client/session.lua +++ b/test/client/session.lua @@ -7,6 +7,7 @@ local MsgpackRpcStream = require('test.client.msgpack_rpc_stream') --- @field private _prepare uv.uv_prepare_t --- @field private _timer uv.uv_timer_t --- @field private _is_running boolean +--- @field exec_lua_setup boolean local Session = {} Session.__index = Session if package.loaded['jit'] then @@ -96,8 +97,7 @@ end --- @param method string --- @param ... any ---- @return boolean ---- @return table +--- @return boolean, table function Session:request(method, ...) local args = { ... } local err, result @@ -114,6 +114,7 @@ function Session:request(method, ...) return true, result end +--- Runs the event loop. 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) diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index cf69958fd8..3775c8c7b7 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -125,11 +125,6 @@ describe('api/buf', function() it('cursor position is maintained consistently with viewport', function() local screen = Screen.new(20, 12) - screen:set_default_attr_ids { - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { reverse = true, bold = true }, - [3] = { reverse = true }, - } screen:attach() local lines = { 'line1', 'line2', 'line3', 'line4', 'line5', 'line6' } @@ -143,11 +138,11 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| line5 | line6 | {1:~ }|*2 - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -158,11 +153,11 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| boogalo 5 | line6 | {1:~ }|*2 - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -172,11 +167,11 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| boogalo 5 | ^line6 | {1:~ }|*2 - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], } @@ -216,11 +211,6 @@ describe('api/buf', function() local screen before_each(function() screen = Screen.new(20, 12) - screen:set_default_attr_ids { - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { reverse = true, bold = true }, - [3] = { reverse = true }, - } screen:attach() api.nvim_buf_set_lines( 0, @@ -243,12 +233,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| www | xxx | yyy | ^zzz | - {2:[No Name] }| + {3:[No Name] }| | ]], } @@ -258,12 +248,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| www | xxx | yyy | ^zzz | - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], } @@ -274,12 +264,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| wwweeee | xxx | yyy | ^zzz | - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], } @@ -290,12 +280,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| wwweeee | xxx | yyy | ^zzz | - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], unchanged = true, @@ -306,12 +296,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| wwweeee | xxx | ^yyy | zzz | - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], } @@ -321,12 +311,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| mmmeeeee | wwweeee | xxx | ^yyy | - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], } @@ -343,12 +333,12 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| www | xxx | yyy | zzz | - {3:[No Name] }| + {2:[No Name] }| | ]], } @@ -358,12 +348,12 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| www | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -374,12 +364,12 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| wwweeee | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -389,12 +379,12 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| wwweeee | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], unchanged = true, @@ -416,12 +406,12 @@ describe('api/buf', function() ccc | ddd | www | - {2:[No Name] }| + {3:[No Name] }| www | xxx | yyy | zzz | - {3:[No Name] }| + {2:[No Name] }| | ]], } @@ -434,12 +424,12 @@ describe('api/buf', function() ddd | www | xxx | - {2:[No Name] [+] }| + {3:[No Name] [+] }| www | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -453,12 +443,12 @@ describe('api/buf', function() ddd | wwweeee | xxx | - {2:[No Name] [+] }| + {3:[No Name] [+] }| wwweeee | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -471,12 +461,12 @@ describe('api/buf', function() ddd | mmm | wwweeee | - {2:[No Name] [+] }| + {3:[No Name] [+] }| wwweeee | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -745,10 +735,6 @@ describe('api/buf', function() it("set_lines of invisible buffer doesn't move cursor in current window", function() local screen = Screen.new(20, 5) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { bold = true }, - }) screen:attach() insert([[ @@ -771,7 +757,7 @@ describe('api/buf', function() A real window | with proper tex^t | {1:~ }| - {2:-- INSERT --} | + {5:-- INSERT --} | ]]) end) @@ -1756,11 +1742,6 @@ describe('api/buf', function() local screen before_each(function() screen = Screen.new(20, 12) - screen:set_default_attr_ids { - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { reverse = true, bold = true }, - [3] = { reverse = true }, - } screen:attach() api.nvim_buf_set_lines( 0, @@ -1783,12 +1764,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| www | xxx | yyy | ^zzz | - {2:[No Name] }| + {3:[No Name] }| | ]], } @@ -1798,12 +1779,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| www | xxx | yyy | ^zzz | - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], } @@ -1820,12 +1801,12 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| www | xxx | yyy | zzz | - {3:[No Name] }| + {2:[No Name] }| | ]], } @@ -1835,12 +1816,12 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| www | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -1861,12 +1842,12 @@ describe('api/buf', function() ccc | ddd | www | - {2:[No Name] }| + {3:[No Name] }| www | xxx | yyy | zzz | - {3:[No Name] }| + {2:[No Name] }| | ]], } @@ -1879,12 +1860,12 @@ describe('api/buf', function() ddd | www | xxx | - {2:[No Name] [+] }| + {3:[No Name] [+] }| www | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -1910,6 +1891,8 @@ describe('api/buf', function() eq({ '' }, get_text(0, 0, 18, 0, 20, {})) eq({ 'ext' }, get_text(0, -2, 1, -2, 4, {})) eq({ 'hello foo!', 'text', 'm' }, get_text(0, 0, 0, 2, 1, {})) + eq({ 'hello foo!' }, get_text(0, 0, -987654321, 0, 987654321, {})) + eq({ '' }, get_text(0, 0, -15, 0, -20, {})) end) it('errors on out-of-range', function() @@ -1923,7 +1906,7 @@ describe('api/buf', function() it('errors when start is greater than end', function() eq("'start' is higher than 'end'", pcall_err(get_text, 0, 1, 0, 0, 0, {})) - eq('start_col must be less than end_col', pcall_err(get_text, 0, 0, 1, 0, 0, {})) + eq('start_col must be less than or equal to end_col', pcall_err(get_text, 0, 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 e030b45396..527394bfd1 100644 --- a/test/functional/api/buffer_updates_spec.lua +++ b/test/functional/api/buffer_updates_spec.lua @@ -27,12 +27,10 @@ end local function sendkeys(keys) api.nvim_input(keys) - -- give nvim some time to process msgpack requests before possibly sending + -- Wait for Nvim to fully process pending input before possibly sending -- more key presses - otherwise they all pile up in the queue and get -- processed at once - local ntime = os.clock() + 0.1 - repeat - until os.clock() > ntime + n.poke_eventloop() end local function open(activate, lines) diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 7b2fe209ba..52d8fd5097 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1758,13 +1758,13 @@ describe('API/extmarks', function() command('1d 2') eq(0, #get_extmarks(-1, 0, -1, {})) -- mark is not removed when deleting bytes before the range - set_extmark( - ns, - 3, - 0, - 4, - { invalidate = true, undo_restore = false, hl_group = 'Error', end_col = 7 } - ) + set_extmark(ns, 3, 0, 4, { + invalidate = true, + undo_restore = true, + hl_group = 'Error', + end_col = 7, + right_gravity = false, + }) feed('dw') eq(3, get_extmark_by_id(ns, 3, { details = true })[3].end_col) -- mark is not removed when deleting bytes at the start of the range @@ -1778,15 +1778,18 @@ describe('API/extmarks', function() eq(1, get_extmark_by_id(ns, 3, { details = true })[3].end_col) -- mark is removed when all bytes in the range are deleted feed('hx') - eq({}, get_extmark_by_id(ns, 3, {})) + eq(true, get_extmark_by_id(ns, 3, { details = true })[3].invalid) + -- mark is restored with undo_restore == true if pos did not change + command('undo') + eq(nil, get_extmark_by_id(ns, 3, { details = true })[3].invalid) -- multiline mark is not removed when start of its range is deleted - set_extmark( - ns, - 4, - 1, - 4, - { undo_restore = false, invalidate = true, hl_group = 'Error', end_col = 7, end_row = 3 } - ) + set_extmark(ns, 4, 1, 4, { + undo_restore = false, + invalidate = true, + hl_group = 'Error', + end_col = 7, + end_row = 3, + }) feed('ddDdd') eq({ 0, 0 }, get_extmark_by_id(ns, 4, {})) -- multiline mark is removed when entirety of its range is deleted @@ -1795,10 +1798,15 @@ describe('API/extmarks', function() end) it('can set a URL', function() - set_extmark(ns, 1, 0, 0, { url = 'https://example.com', end_col = 3 }) + local url1 = 'https://example.com' + local url2 = 'http://127.0.0.1' + set_extmark(ns, 1, 0, 0, { url = url1, end_col = 3 }) + set_extmark(ns, 2, 0, 3, { url = url2, hl_group = 'Search', end_col = 5 }) local extmarks = get_extmarks(ns, 0, -1, { details = true }) - eq(1, #extmarks) - eq('https://example.com', extmarks[1][4].url) + eq(2, #extmarks) + eq(url1, extmarks[1][4].url) + eq(url2, extmarks[2][4].url) + eq('Search', extmarks[2][4].hl_group) end) it('respects priority', function() diff --git a/test/functional/api/version_spec.lua b/test/functional/api/version_spec.lua index 5dad9978b7..617786eb2d 100644 --- a/test/functional/api/version_spec.lua +++ b/test/functional/api/version_spec.lua @@ -58,10 +58,18 @@ describe('api metadata', function() return by_name end - -- Remove metadata that is not essential to backwards-compatibility. - local function filter_function_metadata(f) + -- Remove or patch metadata that is not essential to backwards-compatibility. + local function normalize_func_metadata(f) + -- Dictionary was renamed to Dict. That doesn't break back-compat because clients don't actually + -- use the `return_type` field (evidence: "ArrayOf(…)" didn't break clients). + f.return_type = f.return_type:gsub('Dictionary', 'Dict') + f.deprecated_since = nil for idx, _ in ipairs(f.parameters) do + -- Dictionary was renamed to Dict. Doesn't break back-compat because clients don't actually + -- use the `parameters` field of API metadata (evidence: "ArrayOf(…)" didn't break clients). + f.parameters[idx][1] = f.parameters[idx][1]:gsub('Dictionary', 'Dict') + f.parameters[idx][2] = '' -- Remove parameter name. end @@ -141,7 +149,7 @@ describe('api metadata', function() ) end else - eq(filter_function_metadata(f), filter_function_metadata(funcs_new[f.name])) + eq(normalize_func_metadata(f), normalize_func_metadata(funcs_new[f.name])) end end funcs_compat[level] = name_table(old_api[level].functions) diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index fd0535aa51..af4d4854f5 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -367,14 +367,11 @@ describe('API', function() it('displays messages when opts.output=false', function() local screen = Screen.new(40, 8) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - }) api.nvim_exec2("echo 'hello'", { output = false }) screen:expect { grid = [[ ^ | - {0:~ }|*6 + {1:~ }|*6 hello | ]], } @@ -383,14 +380,11 @@ describe('API', function() it("doesn't display messages when output=true", function() local screen = Screen.new(40, 6) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - }) api.nvim_exec2("echo 'hello'", { output = true }) screen:expect { grid = [[ ^ | - {0:~ }|*4 + {1:~ }|*4 | ]], } @@ -403,7 +397,7 @@ describe('API', function() screen:expect { grid = [[ ^ | - {0:~ }|*4 + {1:~ }|*4 15 | ]], } @@ -699,7 +693,7 @@ describe('API', function() pcall_err(request, 'nvim_call_dict_function', "{ 'f': '' }", 'f', { 1, 2 }) ) eq( - 'dict argument type must be String or Dictionary', + 'dict argument type must be String or Dict', pcall_err(request, 'nvim_call_dict_function', 42, 'f', { 1, 2 }) ) eq( @@ -1307,12 +1301,136 @@ describe('API', function() end) it('crlf=false does not break lines at CR, CRLF', function() api.nvim_paste('line 1\r\n\r\rline 2\nline 3\rline 4\r', false, -1) - expect('line 1\r\n\r\rline 2\nline 3\rline 4\r') + local expected = 'line 1\r\n\r\rline 2\nline 3\rline 4\r' + expect(expected) eq({ 0, 3, 14, 0 }, fn.getpos('.')) + feed('u') -- Undo. + expect('') + feed('.') -- Dot-repeat. + expect(expected) + end) + describe('repeating a paste via redo/recording', function() + -- Test with indent and control chars and multibyte chars containing 0x80 bytes + local text = dedent(([[ + foo + bar + baz + !!!%s!!!%s!!!%s!!! + 最…倒…倀… + ]]):format('\0', '\2\3\6\21\22\23\24\27', '\127')) + before_each(function() + api.nvim_set_option_value('autoindent', true, {}) + end) + local function test_paste_repeat_normal_insert(is_insert) + feed('qr' .. (is_insert and 'i' or '')) + eq('r', fn.reg_recording()) + api.nvim_paste(text, true, -1) + feed(is_insert and '<Esc>' or '') + expect(text) + feed('.') + expect(text:rep(2)) + feed('q') + eq('', fn.reg_recording()) + feed('3.') + expect(text:rep(5)) + feed('2@r') + expect(text:rep(9)) + end + it('works in Normal mode', function() + test_paste_repeat_normal_insert(false) + end) + it('works in Insert mode', function() + test_paste_repeat_normal_insert(true) + end) + local function test_paste_repeat_visual_select(is_select) + insert(('xxx\n'):rep(5)) + feed('ggqr' .. (is_select and 'gH' or 'V')) + api.nvim_paste(text, true, -1) + feed('q') + expect(text .. ('xxx\n'):rep(4)) + feed('2@r') + expect(text:rep(3) .. ('xxx\n'):rep(2)) + end + it('works in Visual mode (recording only)', function() + test_paste_repeat_visual_select(false) + end) + it('works in Select mode (recording only)', function() + test_paste_repeat_visual_select(true) + end) + end) + it('in a mapping recorded in a macro', function() + command([[nnoremap <F2> <Cmd>call nvim_paste('foo', v:false, -1)<CR>]]) + feed('qr<F2>$q') + expect('foo') + feed('@r') -- repeating a macro containing the mapping should only paste once + expect('foofoo') + end) + local function test_paste_cancel_error(is_error) + before_each(function() + exec_lua(([[ + vim.paste = (function(overridden) + return function(lines, phase) + for i, line in ipairs(lines) do + if line == 'CANCEL' then + %s + end + end + return overridden(lines, phase) + end + end)(vim.paste) + ]]):format(is_error and 'error("fake fail")' or 'return false')) + end) + local function check_paste_cancel_error(data, crlf, phase) + if is_error then + eq('fake fail', pcall_err(api.nvim_paste, data, crlf, phase)) + else + eq(false, api.nvim_paste(data, crlf, phase)) + end + end + it('in phase -1', function() + feed('A') + check_paste_cancel_error('CANCEL', true, -1) + feed('<Esc>') + expect('') + feed('.') + expect('') + end) + it('in phase 1', function() + feed('A') + check_paste_cancel_error('CANCEL', true, 1) + feed('<Esc>') + expect('') + feed('.') + expect('') + end) + it('in phase 2', function() + feed('A') + eq(true, api.nvim_paste('aaa', true, 1)) + expect('aaa') + check_paste_cancel_error('CANCEL', true, 2) + feed('<Esc>') + expect('aaa') + feed('.') + expect('aaaaaa') + end) + it('in phase 3', function() + feed('A') + eq(true, api.nvim_paste('aaa', true, 1)) + expect('aaa') + eq(true, api.nvim_paste('bbb', true, 2)) + expect('aaabbb') + check_paste_cancel_error('CANCEL', true, 3) + feed('<Esc>') + expect('aaabbb') + feed('.') + expect('aaabbbaaabbb') + end) + end + describe('vim.paste() cancel', function() + test_paste_cancel_error(false) end) - it('vim.paste() failure', function() - api.nvim_exec_lua('vim.paste = (function(lines, phase) error("fake fail") end)', {}) - eq('fake fail', pcall_err(request, 'nvim_paste', 'line 1\nline 2\nline 3', false, 1)) + describe('vim.paste() error', function() + test_paste_cancel_error(true) end) end) @@ -1441,6 +1559,28 @@ describe('API', function() it('cannot handle NULs', function() eq(0, api.nvim_strwidth('\0abc')) end) + + it('can handle emoji with variant selectors and ZWJ', function() + local selector = 'â¤ï¸' + eq(2, fn.strchars(selector)) + eq(1, fn.strcharlen(selector)) + eq(2, api.nvim_strwidth(selector)) + + local no_selector = 'â¤' + eq(1, fn.strchars(no_selector)) + eq(1, fn.strcharlen(no_selector)) + eq(1, api.nvim_strwidth(no_selector)) + + local selector_zwj_selector = 'ðŸ³ï¸â€âš§ï¸' + eq(5, fn.strchars(selector_zwj_selector)) + eq(1, fn.strcharlen(selector_zwj_selector)) + eq(2, api.nvim_strwidth(selector_zwj_selector)) + + local emoji_zwj_emoji = '🧑â€ðŸŒ¾' + eq(3, fn.strchars(emoji_zwj_emoji)) + eq(1, fn.strcharlen(emoji_zwj_emoji)) + eq(2, api.nvim_strwidth(emoji_zwj_emoji)) + end) end) describe('nvim_get_current_line, nvim_set_current_line', function() @@ -1503,9 +1643,11 @@ describe('API', function() it('nvim_get_vvar, nvim_set_vvar', function() eq('Key is read-only: count', pcall_err(request, 'nvim_set_vvar', 'count', 42)) - eq('Dictionary is locked', pcall_err(request, 'nvim_set_vvar', 'nosuchvar', 42)) + eq('Dict is locked', pcall_err(request, 'nvim_set_vvar', 'nosuchvar', 42)) api.nvim_set_vvar('errmsg', 'set by API') eq('set by API', api.nvim_get_vvar('errmsg')) + api.nvim_set_vvar('completed_item', { word = 'a', user_data = vim.empty_dict() }) + eq({}, api.nvim_get_vvar('completed_item')['user_data']) api.nvim_set_vvar('errmsg', 42) eq('42', eval('v:errmsg')) api.nvim_set_vvar('oldfiles', { 'one', 'two' }) @@ -1533,16 +1675,12 @@ describe('API', function() eq({ 1, 5 }, api.nvim_win_get_cursor(0)) local screen = Screen.new(60, 3) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { background = Screen.colors.Yellow }, - }) screen:attach() eq(1, eval('v:hlsearch')) screen:expect { grid = [[ - {1:foo} {1:^foo} {1:foo} | - {0:~ }| + {10:foo} {10:^foo} {10:foo} | + {1:~ }| | ]], } @@ -1551,7 +1689,7 @@ describe('API', function() screen:expect { grid = [[ foo ^foo foo | - {0:~ }| + {1:~ }| | ]], } @@ -1559,8 +1697,8 @@ describe('API', function() eq(1, eval('v:hlsearch')) screen:expect { grid = [[ - {1:foo} {1:^foo} {1:foo} | - {0:~ }| + {10:foo} {10:^foo} {10:foo} | + {1:~ }| | ]], } @@ -1581,9 +1719,9 @@ describe('API', function() eq(val2, request('vim_del_var', 'lua')) end) - it('truncates values with NULs in them', function() + it('preserves values with NULs in them', function() api.nvim_set_var('xxx', 'ab\0cd') - eq('ab', api.nvim_get_var('xxx')) + eq('ab\000cd', api.nvim_get_var('xxx')) end) end) @@ -2144,7 +2282,7 @@ describe('API', function() end) describe('nvim_load_context', function() - it('sets current editor state to given context dictionary', function() + it('sets current editor state to given context dict', function() local opts = { types = { 'regs', 'jumps', 'bufs', 'gvars' } } eq({}, parse_context(api.nvim_get_context(opts))) @@ -2160,7 +2298,7 @@ describe('API', function() eq({ 1, 2, 3 }, eval('[g:one, g:Two, g:THREE]')) end) - it('errors when context dictionary is invalid', function() + it('errors when context dict is invalid', function() eq( 'E474: Failed to convert list to msgpack string buffer', pcall_err(api.nvim_load_context, { regs = { {} }, jumps = { {} } }) @@ -2254,12 +2392,6 @@ describe('API', function() before_each(function() screen = Screen.new(40, 8) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { bold = true, foreground = Screen.colors.SeaGreen }, - [2] = { bold = true, reverse = true }, - [3] = { foreground = Screen.colors.Blue }, - }) end) it('prints long messages correctly #20534', function() @@ -2287,11 +2419,11 @@ describe('API', function() screen:expect { grid = [[ | - {0:~ }|*3 - {2: }| + {1:~ }|*3 + {3: }| | a | - {1:Press ENTER or type command to continue}^ | + {6:Press ENTER or type command to continue}^ | ]], } feed('<CR>') @@ -2299,12 +2431,12 @@ describe('API', function() screen:expect { grid = [[ | - {0:~ }|*2 - {2: }| + {1:~ }|*2 + {3: }| b | | c | - {1:Press ENTER or type command to continue}^ | + {6:Press ENTER or type command to continue}^ | ]], } end) @@ -2314,11 +2446,11 @@ describe('API', function() screen:expect { grid = [[ | - {0:~ }|*3 - {2: }| - aaa{3:^@}bbb{3:^@^@}ccc | - ddd{3:^@^@^@}eee | - {1:Press ENTER or type command to continue}^ | + {1:~ }|*3 + {3: }| + aaa{18:^@}bbb{18:^@^@}ccc | + ddd{18:^@^@^@}eee | + {6:Press ENTER or type command to continue}^ | ]], } end) @@ -2330,20 +2462,14 @@ describe('API', function() before_each(function() screen = Screen.new(40, 8) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { foreground = Screen.colors.White, background = Screen.colors.Red }, - [2] = { bold = true, foreground = Screen.colors.SeaGreen }, - [3] = { bold = true, reverse = true }, - }) end) it('can show one line', function() async_meths.nvim_err_write('has bork\n') screen:expect([[ ^ | - {0:~ }|*6 - {1:has bork} | + {1:~ }|*6 + {9:has bork} | ]]) end) @@ -2351,11 +2477,11 @@ describe('API', function() async_meths.nvim_err_write('something happened\nvery bad\n') screen:expect([[ | - {0:~ }|*3 + {1:~ }|*3 {3: }| - {1:something happened} | - {1:very bad} | - {2:Press ENTER or type command to continue}^ | + {9:something happened} | + {9:very bad} | + {6:Press ENTER or type command to continue}^ | ]]) end) @@ -2363,13 +2489,13 @@ describe('API', function() async_meths.nvim_err_write('FAILURE\nERROR\nEXCEPTION\nTRACEBACK\n') screen:expect([[ | - {0:~ }| + {1:~ }| {3: }| - {1:FAILURE} | - {1:ERROR} | - {1:EXCEPTION} | - {1:TRACEBACK} | - {2:Press ENTER or type command to continue}^ | + {9:FAILURE} | + {9:ERROR} | + {9:EXCEPTION} | + {9:TRACEBACK} | + {6:Press ENTER or type command to continue}^ | ]]) end) @@ -2379,8 +2505,8 @@ describe('API', function() async_meths.nvim_err_write('fail\n') screen:expect([[ ^ | - {0:~ }|*6 - {1:very fail} | + {1:~ }|*6 + {9:very fail} | ]]) n.poke_eventloop() @@ -2388,11 +2514,11 @@ describe('API', function() async_meths.nvim_err_write('more fail\ntoo fail\n') screen:expect([[ | - {0:~ }|*3 + {1:~ }|*3 {3: }| - {1:more fail} | - {1:too fail} | - {2:Press ENTER or type command to continue}^ | + {9:more fail} | + {9:too fail} | + {6:Press ENTER or type command to continue}^ | ]]) feed('<cr>') -- exit the press ENTER screen end) @@ -2402,11 +2528,11 @@ describe('API', function() screen:expect { grid = [[ | - {0:~ }|*3 + {1:~ }|*3 {3: }| - {1:aaa^@bbb^@^@ccc} | - {1:ddd^@^@^@eee} | - {2:Press ENTER or type command to continue}^ | + {9:aaa^@bbb^@^@ccc} | + {9:ddd^@^@^@eee} | + {6:Press ENTER or type command to continue}^ | ]], } end) @@ -2418,30 +2544,24 @@ describe('API', function() before_each(function() screen = Screen.new(40, 8) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { foreground = Screen.colors.White, background = Screen.colors.Red }, - [2] = { bold = true, foreground = Screen.colors.SeaGreen }, - [3] = { bold = true, reverse = true }, - }) end) it('shows only one return prompt after all lines are shown', function() async_meths.nvim_err_writeln('FAILURE\nERROR\nEXCEPTION\nTRACEBACK') screen:expect([[ | - {0:~ }| + {1:~ }| {3: }| - {1:FAILURE} | - {1:ERROR} | - {1:EXCEPTION} | - {1:TRACEBACK} | - {2:Press ENTER or type command to continue}^ | + {9:FAILURE} | + {9:ERROR} | + {9:EXCEPTION} | + {9:TRACEBACK} | + {6:Press ENTER or type command to continue}^ | ]]) feed('<CR>') screen:expect([[ ^ | - {0:~ }|*6 + {1:~ }|*6 | ]]) end) @@ -2964,6 +3084,13 @@ describe('API', function() return ('%s(%s)%s'):format(typ, args, rest) end end + + it('does not crash parsing invalid VimL expression #29648', function() + api.nvim_input(':<C-r>=') + api.nvim_input('1bork/') + assert_alive() + end) + require('test.unit.viml.expressions.parser_tests')(it, _check_parsing, hl, fmtn) end) @@ -3102,9 +3229,6 @@ describe('API', function() eq(1, api.nvim_get_current_buf()) local screen = Screen.new(20, 4) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - }) screen:attach() -- @@ -3201,7 +3325,7 @@ describe('API', function() end) describe('nvim_get_runtime_file', function() - local p = n.alter_slashes + local p = t.fix_slashes it('can find files', function() eq({}, api.nvim_get_runtime_file('bork.borkbork', false)) eq({}, api.nvim_get_runtime_file('bork.borkbork', true)) @@ -3210,36 +3334,36 @@ describe('API', function() local val = api.nvim_get_runtime_file('autoload/remote/*.vim', true) eq(2, #val) if endswith(val[1], 'define.vim') then - ok(endswith(val[1], p 'autoload/remote/define.vim')) - ok(endswith(val[2], p 'autoload/remote/host.vim')) + ok(endswith(p(val[1]), 'autoload/remote/define.vim')) + ok(endswith(p(val[2]), 'autoload/remote/host.vim')) else - ok(endswith(val[1], p 'autoload/remote/host.vim')) - ok(endswith(val[2], p 'autoload/remote/define.vim')) + ok(endswith(p(val[1]), 'autoload/remote/host.vim')) + ok(endswith(p(val[2]), 'autoload/remote/define.vim')) end val = api.nvim_get_runtime_file('autoload/remote/*.vim', false) eq(1, #val) ok( - endswith(val[1], p 'autoload/remote/define.vim') - or endswith(val[1], p 'autoload/remote/host.vim') + endswith(p(val[1]), 'autoload/remote/define.vim') + or endswith(p(val[1]), 'autoload/remote/host.vim') ) val = api.nvim_get_runtime_file('lua', true) eq(1, #val) - ok(endswith(val[1], p 'lua')) + ok(endswith(p(val[1]), 'lua')) val = api.nvim_get_runtime_file('lua/vim', true) eq(1, #val) - ok(endswith(val[1], p 'lua/vim')) + ok(endswith(p(val[1]), 'lua/vim')) end) it('can find directories', function() local val = api.nvim_get_runtime_file('lua/', true) eq(1, #val) - ok(endswith(val[1], p 'lua/')) + ok(endswith(p(val[1]), 'lua/')) val = api.nvim_get_runtime_file('lua/vim/', true) eq(1, #val) - ok(endswith(val[1], p 'lua/vim/')) + ok(endswith(p(val[1]), 'lua/vim/')) eq({}, api.nvim_get_runtime_file('foobarlang/', true)) end) @@ -3253,6 +3377,16 @@ describe('API', function() exc_exec("echo nvim_get_runtime_file('{', v:false)") ) end) + it('preserves order of runtimepath', function() + local vimruntime = fn.getenv('VIMRUNTIME') + local rtp = string.format('%s/syntax,%s/ftplugin', vimruntime, vimruntime) + api.nvim_set_option_value('runtimepath', rtp, {}) + + local val = api.nvim_get_runtime_file('vim.vim', true) + eq(2, #val) + eq(p(val[1]), vimruntime .. '/syntax/vim.vim') + eq(p(val[2]), vimruntime .. '/ftplugin/vim.vim') + end) end) describe('nvim_get_all_options_info', function() @@ -3458,13 +3592,6 @@ describe('API', function() before_each(function() screen = Screen.new(40, 8) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { bold = true, foreground = Screen.colors.SeaGreen }, - [2] = { bold = true, reverse = true }, - [3] = { foreground = Screen.colors.Brown, bold = true }, -- Statement - [4] = { foreground = Screen.colors.SlateBlue }, -- Special - }) command('highlight Statement gui=bold guifg=Brown') command('highlight Special guifg=SlateBlue') end) @@ -3474,7 +3601,7 @@ describe('API', function() screen:expect { grid = [[ ^ | - {0:~ }|*6 + {1:~ }|*6 msg | ]], } @@ -3489,8 +3616,8 @@ describe('API', function() screen:expect { grid = [[ ^ | - {0:~ }|*6 - msg_a{3:msg_b}{4:msg_c} | + {1:~ }|*6 + msg_a{15:msg_b}{16:msg_c} | ]], } end) @@ -3500,11 +3627,11 @@ describe('API', function() screen:expect { grid = [[ | - {0:~ }|*3 - {2: }| - {3:msg_a} | - {3:msg_a}{4:msg_b} | - {1:Press ENTER or type command to continue}^ | + {1:~ }|*3 + {3: }| + {15:msg_a} | + {15:msg_a}{16:msg_b} | + {6:Press ENTER or type command to continue}^ | ]], } end) @@ -3528,24 +3655,16 @@ describe('API', function() before_each(function() screen = Screen.new(100, 35) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { background = Screen.colors.Plum1 }, - [2] = { background = tonumber('0xffff40'), bg_indexed = true }, - [3] = { - background = Screen.colors.Plum1, - fg_indexed = true, - foreground = tonumber('0x00e000'), - }, - [4] = { bold = true, reverse = true, background = Screen.colors.Plum1 }, - [5] = { - foreground = Screen.colors.Blue, + screen:add_extra_attr_ids { + [100] = { background = tonumber('0xffff40'), bg_indexed = true }, + [101] = { background = Screen.colors.LightMagenta, - bold = true, + foreground = tonumber('0x00e000'), + fg_indexed = true, }, - [6] = { bold = true }, - [7] = { reverse = true, background = Screen.colors.LightMagenta }, - }) + [102] = { background = Screen.colors.LightMagenta, reverse = true }, + [103] = { background = Screen.colors.LightMagenta, bold = true, reverse = true }, + } end) it('can batch process sequences', function() @@ -3561,38 +3680,38 @@ describe('API', function() screen:expect { grid = [[ ^ | - {0:~}{1::smile }{0: }| - {0:~}{1: }{2:oooo$$$$$$$$$$$$oooo}{1: }{0: }| - {0:~}{1: }{2:oo$$$$$$$$$$$$$$$$$$$$$$$$o}{1: }{0: }| - {0:~}{1: }{2:oo$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{1: }{2:o$}{1: }{2:$$}{1: }{2:o$}{1: }{0: }| - {0:~}{1: }{2:o}{1: }{2:$}{1: }{2:oo}{1: }{2:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{1: }{2:$$}{1: }{2:$$}{1: }{2:$$o$}{1: }{0: }| - {0:~}{1: }{2:oo}{1: }{2:$}{1: }{2:$}{1: "}{2:$}{1: }{2:o$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$}{1: }{2:$$$$$$$$$o}{1: }{2:$$$o$$o$}{1: }{0: }| - {0:~}{1: "}{2:$$$$$$o$}{1: }{2:o$$$$$$$$$}{1: }{2:$$$$$$$$$$$}{1: }{2:$$$$$$$$$$o}{1: }{2:$$$$$$$$}{1: }{0: }| - {0:~}{1: }{2:$$$$$$$}{1: }{2:$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$}{1: }{0: }| - {0:~}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$$}{1: """}{2:$$$}{1: }{0: }| - {0:~}{1: "}{2:$$$}{1:""""}{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: "}{2:$$$}{1: }{0: }| - {0:~}{1: }{2:$$$}{1: }{2:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: "}{2:$$$o}{1: }{0: }| - {0:~}{1: }{2:o$$}{1:" }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:$$$o}{1: }{0: }| - {0:~}{1: }{2:$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1:" "}{2:$$$$$$ooooo$$$$o}{1: }{0: }| - {0:~}{1: }{2:o$$$oooo$$$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:o$$$$$$$$$$$$$$$$$}{1: }{0: }| - {0:~}{1: }{2:$$$$$$$$}{1:"}{2:$$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:$$$$}{1:"""""""" }{0: }| - {0:~}{1: """" }{2:$$$$}{1: "}{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1:" }{2:o$$$}{1: }{0: }| - {0:~}{1: "}{2:$$$o}{1: """}{2:$$$$$$$$$$$$$$$$$$}{1:"}{2:$$}{1:" }{2:$$$}{1: }{0: }| - {0:~}{1: }{2:$$$o}{1: "}{2:$$}{1:""}{2:$$$$$$}{1:"""" }{2:o$$$}{1: }{0: }| - {0:~}{1: }{2:$$$$o}{1: }{2:o$$$}{1:" }{0: }| - {0:~}{1: "}{2:$$$$o}{1: }{2:o$$$$$$o}{1:"}{2:$$$$o}{1: }{2:o$$$$}{1: }{0: }| - {0:~}{1: "}{2:$$$$$oo}{1: ""}{2:$$$$o$$$$$o}{1: }{2:o$$$$}{1:"" }{0: }| - {0:~}{1: ""}{2:$$$$$oooo}{1: "}{2:$$$o$$$$$$$$$}{1:""" }{0: }| - {0:~}{1: ""}{2:$$$$$$$oo}{1: }{2:$$$$$$$$$$}{1: }{0: }| - {0:~}{1: """"}{2:$$$$$$$$$$$}{1: }{0: }| - {0:~}{1: }{2:$$$$$$$$$$$$}{1: }{0: }| - {0:~}{1: }{2:$$$$$$$$$$}{1:" }{0: }| - {0:~}{1: "}{2:$$$}{1:"""" }{0: }| - {0:~}{1: }{0: }| - {0:~}{3:Press ENTER or type command to continue}{1: }{0: }| - {0:~}{4:term://~/config2/docs/pres//32693:vim --clean +smile 29,39 All}{0: }| - {0:~}{1::call nvim__screenshot("smile2.cat") }{0: }| - {0:~ }|*2 + {1:~}{4::smile }{1: }| + {1:~}{4: }{100:oooo$$$$$$$$$$$$oooo}{4: }{1: }| + {1:~}{4: }{100:oo$$$$$$$$$$$$$$$$$$$$$$$$o}{4: }{1: }| + {1:~}{4: }{100:oo$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{4: }{100:o$}{4: }{100:$$}{4: }{100:o$}{4: }{1: }| + {1:~}{4: }{100:o}{4: }{100:$}{4: }{100:oo}{4: }{100:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{4: }{100:$$}{4: }{100:$$}{4: }{100:$$o$}{4: }{1: }| + {1:~}{4: }{100:oo}{4: }{100:$}{4: }{100:$}{4: "}{100:$}{4: }{100:o$$$$$$$$$}{4: }{100:$$$$$$$$$$$$$}{4: }{100:$$$$$$$$$o}{4: }{100:$$$o$$o$}{4: }{1: }| + {1:~}{4: "}{100:$$$$$$o$}{4: }{100:o$$$$$$$$$}{4: }{100:$$$$$$$$$$$}{4: }{100:$$$$$$$$$$o}{4: }{100:$$$$$$$$}{4: }{1: }| + {1:~}{4: }{100:$$$$$$$}{4: }{100:$$$$$$$$$$$}{4: }{100:$$$$$$$$$$$}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$}{4: }{1: }| + {1:~}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$}{4: }{100:$$$$$$$$$$$$$}{4: }{100:$$$$$$$$$$$$$$}{4: """}{100:$$$}{4: }{1: }| + {1:~}{4: "}{100:$$$}{4:""""}{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: "}{100:$$$}{4: }{1: }| + {1:~}{4: }{100:$$$}{4: }{100:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: "}{100:$$$o}{4: }{1: }| + {1:~}{4: }{100:o$$}{4:" }{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: }{100:$$$o}{4: }{1: }| + {1:~}{4: }{100:$$$}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4:" "}{100:$$$$$$ooooo$$$$o}{4: }{1: }| + {1:~}{4: }{100:o$$$oooo$$$$$}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: }{100:o$$$$$$$$$$$$$$$$$}{4: }{1: }| + {1:~}{4: }{100:$$$$$$$$}{4:"}{100:$$$$}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: }{100:$$$$}{4:"""""""" }{1: }| + {1:~}{4: """" }{100:$$$$}{4: "}{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4:" }{100:o$$$}{4: }{1: }| + {1:~}{4: "}{100:$$$o}{4: """}{100:$$$$$$$$$$$$$$$$$$}{4:"}{100:$$}{4:" }{100:$$$}{4: }{1: }| + {1:~}{4: }{100:$$$o}{4: "}{100:$$}{4:""}{100:$$$$$$}{4:"""" }{100:o$$$}{4: }{1: }| + {1:~}{4: }{100:$$$$o}{4: }{100:o$$$}{4:" }{1: }| + {1:~}{4: "}{100:$$$$o}{4: }{100:o$$$$$$o}{4:"}{100:$$$$o}{4: }{100:o$$$$}{4: }{1: }| + {1:~}{4: "}{100:$$$$$oo}{4: ""}{100:$$$$o$$$$$o}{4: }{100:o$$$$}{4:"" }{1: }| + {1:~}{4: ""}{100:$$$$$oooo}{4: "}{100:$$$o$$$$$$$$$}{4:""" }{1: }| + {1:~}{4: ""}{100:$$$$$$$oo}{4: }{100:$$$$$$$$$$}{4: }{1: }| + {1:~}{4: """"}{100:$$$$$$$$$$$}{4: }{1: }| + {1:~}{4: }{100:$$$$$$$$$$$$}{4: }{1: }| + {1:~}{4: }{100:$$$$$$$$$$}{4:" }{1: }| + {1:~}{4: "}{100:$$$}{4:"""" }{1: }| + {1:~}{4: }{1: }| + {1:~}{101:Press ENTER or type command to continue}{4: }{1: }| + {1:~}{103:term://~/config2/docs/pres//32693:vim --clean +smile 29,39 All}{1: }| + {1:~}{4::call nvim__screenshot("smile2.cat") }{1: }| + {1:~ }|*2 | ]], } @@ -3624,9 +3743,9 @@ describe('API', function() screen:expect { grid = [[ | - {0:~}{1:^ }{0: }| - {0:~}{1: }{0: }|*4 - {0:~ }|*3 + {1:~}{4:^ }{1: }| + {1:~}{4: }{1: }|*4 + {1:~ }|*3 | ]], } @@ -3635,10 +3754,10 @@ describe('API', function() screen:expect { grid = [[ | - {0:~}{7: }{1: }{0: }| - {0:~}{1: }{0: }|*4 - {0:~ }|*3 - {6:-- TERMINAL --} | + {1:~}{102: }{4: }{1: }| + {1:~}{4: }{1: }|*4 + {1:~ }|*3 + {5:-- TERMINAL --} | ]], } @@ -3651,10 +3770,10 @@ describe('API', function() screen:expect { grid = [[ | - {0:~}{1:herrejösses!}{7: }{1: }{0: }| - {0:~}{1: }{0: }|*4 - {0:~ }|*3 - {6:-- TERMINAL --} | + {1:~}{4:herrejösses!}{102: }{4: }{1: }| + {1:~}{4: }{1: }|*4 + {1:~ }|*3 + {5:-- TERMINAL --} | ]], } eq('ba\024blaherrejösses!', exec_lua [[ return stream ]]) @@ -3933,11 +4052,11 @@ describe('API', function() )) eq( { - str = '3 ', - width = 2, + str = ' 3 ', + width = 9, highlights = { { group = 'LineNr', start = 0 }, - { group = 'ErrorMsg', start = 1 }, + { group = 'ErrorMsg', start = 8 }, }, }, api.nvim_eval_statusline('%l%#ErrorMsg# ', { use_statuscol_lnum = 3, highlights = true }) @@ -4472,10 +4591,6 @@ describe('API', function() end) it('does not interfere with printing line in Ex mode #19400', function() local screen = Screen.new(60, 7) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { bold = true, reverse = true }, -- MsgSeparator - }) screen:attach() insert([[ foo @@ -4484,8 +4599,8 @@ describe('API', function() screen:expect([[ foo | bar | - {0:~ }|*2 - {1: }| + {1:~ }|*2 + {3: }| Entering Ex mode. Type "visual" to go to Normal mode. | :1^ | ]]) @@ -4494,7 +4609,7 @@ describe('API', function() screen:expect([[ foo | bar | - {1: }| + {3: }| Entering Ex mode. Type "visual" to go to Normal mode. | :1 | foo | @@ -4934,14 +5049,11 @@ describe('API', function() it("doesn't display messages when output=true", function() local screen = Screen.new(40, 6) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - }) api.nvim_cmd({ cmd = 'echo', args = { [['hello']] } }, { output = true }) screen:expect { grid = [[ ^ | - {0:~ }|*4 + {1:~ }|*4 | ]], } @@ -4954,7 +5066,7 @@ describe('API', function() screen:expect { grid = [[ ^ | - {0:~ }|*4 + {1:~ }|*4 15 | ]], } @@ -5020,12 +5132,29 @@ describe('API', function() it('nvim__redraw', function() local screen = Screen.new(60, 5) screen:attach() - local win = api.nvim_get_current_win() eq('at least one action required', pcall_err(api.nvim__redraw, {})) eq('at least one action required', pcall_err(api.nvim__redraw, { buf = 0 })) eq('at least one action required', pcall_err(api.nvim__redraw, { win = 0 })) eq("cannot use both 'buf' and 'win'", pcall_err(api.nvim__redraw, { buf = 0, win = 0 })) + local win = api.nvim_get_current_win() + -- Can move cursor to recently opened window and window is flushed #28868 feed(':echo getchar()<CR>') + local newwin = api.nvim_open_win(0, false, { + relative = 'editor', + width = 1, + height = 1, + row = 1, + col = 10, + }) + api.nvim__redraw({ win = newwin, cursor = true }) + screen:expect({ + grid = [[ + | + {1:~ }{4:^ }{1: }| + {1:~ }|*2 + :echo getchar() | + ]], + }) fn.setline(1, 'foobar') command('vnew') fn.setline(1, 'foobaz') @@ -5034,11 +5163,13 @@ describe('API', function() screen:expect({ grid = [[ foobaz │foobar | - {1:~ }│{1:~ }|*2 + {1:~ }{4:^f}{1: }│{1:~ }| + {1:~ }│{1:~ }| {3:[No Name] [+] }{2:[No Name] [+] }| - ^:echo getchar() | + :echo getchar() | ]], }) + api.nvim_win_close(newwin, true) -- Can update the grid cursor position #20793 api.nvim__redraw({ cursor = true }) screen:expect({ diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 15b9b0945c..5ce93f9e04 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -85,7 +85,7 @@ describe('API/win', function() [[ local cmdwin_buf = vim.api.nvim_get_current_buf() local new_win, new_buf = ... - vim.api.nvim_buf_call(new_buf, function() + vim._with({buf = new_buf}, function() vim.api.nvim_win_set_buf(new_win, cmdwin_buf) end) ]], @@ -100,7 +100,7 @@ describe('API/win', function() [[ local cmdwin_win = vim.api.nvim_get_current_win() local new_win, new_buf = ... - vim.api.nvim_win_call(new_win, function() + vim._with({win = new_win}, function() vim.api.nvim_win_set_buf(cmdwin_win, new_buf) end) ]], @@ -164,17 +164,12 @@ describe('API/win', function() eq('typing\n some dumb text', curbuf_contents()) end) - it('does not leak memory when using invalid window ID with invalid pos', function() + it('no memory leak when using invalid window ID with invalid pos', function() eq('Invalid window id: 1', pcall_err(api.nvim_win_set_cursor, 1, { 'b\na' })) end) it('updates the screen, and also when the window is unfocused', function() local screen = Screen.new(30, 9) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue }, - [2] = { bold = true, reverse = true }, - [3] = { reverse = true }, - }) screen:attach() insert('prologue') @@ -221,10 +216,10 @@ describe('API/win', function() grid = [[ ^ | {1:~ }|*2 - {2:[No Name] }| + {3:[No Name] }| prologue | |*2 - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -235,10 +230,10 @@ describe('API/win', function() grid = [[ ^ | {1:~ }|*2 - {2:[No Name] }| + {3:[No Name] }| |*2 epilogue | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -249,10 +244,10 @@ describe('API/win', function() grid = [[ ^ | {1:~ }|*2 - {2:[No Name] }| + {3:[No Name] }| prologue | |*2 - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -286,12 +281,6 @@ describe('API/win', function() it('updates cursorline and statusline ruler in non-current window', function() local screen = Screen.new(60, 8) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [2] = { background = Screen.colors.Grey90 }, -- CursorLine - [3] = { bold = true, reverse = true }, -- StatusLine - [4] = { reverse = true }, -- StatusLineNC - }) screen:attach() command('set ruler') command('set cursorline') @@ -306,31 +295,25 @@ describe('API/win', function() aaa │aaa | bbb │bbb | ccc │ccc | - {2:dd^d }│{2:ddd }| + {21:dd^d }│{21:ddd }| {1:~ }│{1:~ }|*2 - {3:[No Name] [+] 4,3 All }{4:[No Name] [+] 4,3 All}| + {3:[No Name] [+] 4,3 All }{2:[No Name] [+] 4,3 All}| | ]]) api.nvim_win_set_cursor(oldwin, { 1, 0 }) screen:expect([[ - aaa │{2:aaa }| + aaa │{21:aaa }| bbb │bbb | ccc │ccc | - {2:dd^d }│ddd | + {21:dd^d }│ddd | {1:~ }│{1:~ }|*2 - {3:[No Name] [+] 4,3 All }{4:[No Name] [+] 1,1 All}| + {3:[No Name] [+] 4,3 All }{2:[No Name] [+] 1,1 All}| | ]]) end) it('updates cursorcolumn in non-current window', function() local screen = Screen.new(60, 8) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [2] = { background = Screen.colors.Grey90 }, -- CursorColumn - [3] = { bold = true, reverse = true }, -- StatusLine - [4] = { reverse = true }, -- StatusLineNC - }) screen:attach() command('set cursorcolumn') insert([[ @@ -341,22 +324,22 @@ describe('API/win', function() local oldwin = curwin() command('vsplit') screen:expect([[ - aa{2:a} │aa{2:a} | - bb{2:b} │bb{2:b} | - cc{2:c} │cc{2:c} | + aa{21:a} │aa{21:a} | + bb{21:b} │bb{21:b} | + cc{21:c} │cc{21:c} | dd^d │ddd | {1:~ }│{1:~ }|*2 - {3:[No Name] [+] }{4:[No Name] [+] }| + {3:[No Name] [+] }{2:[No Name] [+] }| | ]]) api.nvim_win_set_cursor(oldwin, { 2, 0 }) screen:expect([[ - aa{2:a} │{2:a}aa | - bb{2:b} │bbb | - cc{2:c} │{2:c}cc | - dd^d │{2:d}dd | + aa{21:a} │{21:a}aa | + bb{21:b} │bbb | + cc{21:c} │{21:c}cc | + dd^d │{21:d}dd | {1:~ }│{1:~ }|*2 - {3:[No Name] [+] }{4:[No Name] [+] }| + {3:[No Name] [+] }{2:[No Name] [+] }| | ]]) end) @@ -655,7 +638,7 @@ describe('API/win', function() feed('q:') exec_lua( [[ - vim.api.nvim_win_call(..., function() + vim._with({win = ...}, function() vim.api.nvim_win_close(0, true) end) ]], @@ -674,7 +657,7 @@ describe('API/win', function() exec_lua( [[ local otherwin, cmdwin = ... - vim.api.nvim_win_call(otherwin, function() + vim._with({win = otherwin}, function() vim.api.nvim_win_close(cmdwin, true) end) ]], @@ -788,7 +771,7 @@ describe('API/win', function() }) exec_lua( [[ - vim.api.nvim_win_call(..., function() + vim._with({win = ...}, function() vim.api.nvim_win_hide(0) end) ]], @@ -807,7 +790,7 @@ describe('API/win', function() exec_lua( [[ local otherwin, cmdwin = ... - vim.api.nvim_win_call(otherwin, function() + vim._with({win = otherwin}, function() vim.api.nvim_win_hide(cmdwin) end) ]], @@ -874,22 +857,6 @@ describe('API/win', function() it('with two diff windows', function() local X = api.nvim_get_vvar('maxcol') local screen = Screen.new(45, 22) - screen:set_default_attr_ids({ - [0] = { foreground = Screen.colors.Blue1, bold = true }, - [1] = { foreground = Screen.colors.Blue4, background = Screen.colors.Grey }, - [2] = { foreground = Screen.colors.Brown }, - [3] = { - foreground = Screen.colors.Blue1, - background = Screen.colors.LightCyan1, - bold = true, - }, - [4] = { background = Screen.colors.LightBlue }, - [5] = { foreground = Screen.colors.Blue4, background = Screen.colors.LightGrey }, - [6] = { background = Screen.colors.Plum1 }, - [7] = { background = Screen.colors.Red, bold = true }, - [8] = { reverse = true }, - [9] = { bold = true, reverse = true }, - }) screen:attach() exec([[ set diffopt+=context:2 number @@ -902,35 +869,35 @@ describe('API/win', function() feed('24gg') screen:expect { grid = [[ - {1: }{2: }{3:----------------}│{1: }{2: 1 }{4:00000001! }| - {1: }{2: }{3:----------------}│{1: }{2: 2 }{4:00000002!! }| - {1: }{2: 1 }00000003!!! │{1: }{2: 3 }00000003!!! | - {1: }{2: 2 }00000004!!!! │{1: }{2: 4 }00000004!!!! | - {1:+ }{2: 3 }{5:+-- 14 lines: 00}│{1:+ }{2: 5 }{5:+-- 14 lines: 00}| - {1: }{2: 17 }00000019!!!!!!!!│{1: }{2: 19 }00000019!!!!!!!!| - {1: }{2: 18 }00000020!!!!!!!!│{1: }{2: 20 }00000020!!!!!!!!| - {1: }{2: }{3:----------------}│{1: }{2: 21 }{4:00000025!!!!!!!!}| - {1: }{2: }{3:----------------}│{1: }{2: 22 }{4:00000026!!!!!!!!}| - {1: }{2: }{3:----------------}│{1: }{2: 23 }{4:00000027!!!!!!!!}| - {1: }{2: 19 }00000028!!!!!!!!│{1: }{2: 24 }^00000028!!!!!!!!| - {1: }{2: 20 }00000029!!!!!!!!│{1: }{2: 25 }00000029!!!!!!!!| - {1:+ }{2: 21 }{5:+-- 14 lines: 00}│{1:+ }{2: 26 }{5:+-- 14 lines: 00}| - {1: }{2: 35 }00000044!!!!!!!!│{1: }{2: 40 }00000044!!!!!!!!| - {1: }{2: 36 }00000045!!!!!!!!│{1: }{2: 41 }00000045!!!!!!!!| - {1: }{2: 37 }{4:00000046!!!!!!!!}│{1: }{2: }{3:----------------}| - {1: }{2: 38 }{4:00000047!!!!!!!!}│{1: }{2: }{3:----------------}| - {1: }{2: 39 }{4:00000048!!!!!!!!}│{1: }{2: }{3:----------------}| - {1: }{2: 40 }{4:00000049!!!!!!!!}│{1: }{2: }{3:----------------}| - {1: }{2: 41 }{4:00000050!!!!!!!!}│{1: }{2: }{3:----------------}| - {8:[No Name] [+] }{9:[No Name] [+] }| + {7: }{8: }{23:----------------}│{7: }{8: 1 }{22:00000001! }| + {7: }{8: }{23:----------------}│{7: }{8: 2 }{22:00000002!! }| + {7: }{8: 1 }00000003!!! │{7: }{8: 3 }00000003!!! | + {7: }{8: 2 }00000004!!!! │{7: }{8: 4 }00000004!!!! | + {7:+ }{8: 3 }{13:+-- 14 lines: 00}│{7:+ }{8: 5 }{13:+-- 14 lines: 00}| + {7: }{8: 17 }00000019!!!!!!!!│{7: }{8: 19 }00000019!!!!!!!!| + {7: }{8: 18 }00000020!!!!!!!!│{7: }{8: 20 }00000020!!!!!!!!| + {7: }{8: }{23:----------------}│{7: }{8: 21 }{22:00000025!!!!!!!!}| + {7: }{8: }{23:----------------}│{7: }{8: 22 }{22:00000026!!!!!!!!}| + {7: }{8: }{23:----------------}│{7: }{8: 23 }{22:00000027!!!!!!!!}| + {7: }{8: 19 }00000028!!!!!!!!│{7: }{8: 24 }^00000028!!!!!!!!| + {7: }{8: 20 }00000029!!!!!!!!│{7: }{8: 25 }00000029!!!!!!!!| + {7:+ }{8: 21 }{13:+-- 14 lines: 00}│{7:+ }{8: 26 }{13:+-- 14 lines: 00}| + {7: }{8: 35 }00000044!!!!!!!!│{7: }{8: 40 }00000044!!!!!!!!| + {7: }{8: 36 }00000045!!!!!!!!│{7: }{8: 41 }00000045!!!!!!!!| + {7: }{8: 37 }{22:00000046!!!!!!!!}│{7: }{8: }{23:----------------}| + {7: }{8: 38 }{22:00000047!!!!!!!!}│{7: }{8: }{23:----------------}| + {7: }{8: 39 }{22:00000048!!!!!!!!}│{7: }{8: }{23:----------------}| + {7: }{8: 40 }{22:00000049!!!!!!!!}│{7: }{8: }{23:----------------}| + {7: }{8: 41 }{22:00000050!!!!!!!!}│{7: }{8: }{23:----------------}| + {2:[No Name] [+] }{3:[No Name] [+] }| | ]], } screen:try_resize(45, 3) screen:expect { grid = [[ - {1: }{2: 19 }00000028!!!!!!!!│{1: }{2: 24 }^00000028!!!!!!!!| - {8:[No Name] [+] }{9:[No Name] [+] }| + {7: }{8: 19 }00000028!!!!!!!!│{7: }{8: 24 }^00000028!!!!!!!!| + {2:[No Name] [+] }{3:[No Name] [+] }| | ]], } @@ -1008,11 +975,6 @@ describe('API/win', function() it('with wrapped lines', function() local X = api.nvim_get_vvar('maxcol') local screen = Screen.new(45, 22) - screen:set_default_attr_ids({ - [0] = { foreground = Screen.colors.Blue1, bold = true }, - [1] = { foreground = Screen.colors.Brown }, - [2] = { background = Screen.colors.Yellow }, - }) screen:attach() exec([[ set number cpoptions+=n @@ -1035,26 +997,26 @@ describe('API/win', function() ) screen:expect { grid = [[ - {1: 1 }^foobar-foobar-foobar-foobar-foobar-foobar| + {8: 1 }^foobar-foobar-foobar-foobar-foobar-foobar| -foobar-foobar-foobar-foobar-foobar-foobar-fo| obar-foobar-foobar-foobar-foobar-foobar-fooba| r-foobar-foobar-foobar-foobar-foobar-foobar-f| oobar-foobar-foobar-foobar-foobar-foobar-foob| ar-foobar-foobar-foobar-foobar- | - {1: 2 }foobar-foobar-foobar-foobar-foobar-foobar| + {8: 2 }foobar-foobar-foobar-foobar-foobar-foobar| -foobar-foobar-foobar-foobar-foobar-foobar-fo| - obar-foobar-fo{2:???????????????}obar-foobar-foob| + obar-foobar-fo{10:???????????????}obar-foobar-foob| ar-foobar-foobar-foobar-foobar-foobar-foobar-| foobar-foobar-foobar-foobar-foobar-foobar-foo| bar-foobar-foobar-foobar-foobar-foobar-foobar| - | - {1: 3 }foobar-foobar-foobar-foobar-foobar-foobar| + {8: 3 }foobar-foobar-foobar-foobar-foobar-foobar| -foobar-foobar-foobar-foobar-foobar-foobar-fo| obar-foobar-foobar-foobar-foobar-foobar-fooba| r-foobar-foobar-foobar-foobar-foobar-foobar-f| - oobar-foobar-foobar-foob{2:!!!!!!!!!!!!!!!!!!!!!}| - {2:!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}| - {2:!!!!!!!!!}ar-foobar-foobar-foobar-foobar-fooba| + oobar-foobar-foobar-foob{10:!!!!!!!!!!!!!!!!!!!!!}| + {10:!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}| + {10:!!!!!!!!!}ar-foobar-foobar-foobar-foobar-fooba| r-foobar-foobar- | | ]], @@ -1062,7 +1024,7 @@ describe('API/win', function() screen:try_resize(45, 2) screen:expect { grid = [[ - {1: 1 }^foobar-foobar-foobar-foobar-foobar-foobar| + {8: 1 }^foobar-foobar-foobar-foobar-foobar-foobar| | ]], } @@ -1216,7 +1178,7 @@ describe('API/win', function() exec_lua, [[ local cmdwin_buf = vim.api.nvim_get_current_buf() - vim.api.nvim_buf_call(vim.api.nvim_create_buf(false, true), function() + vim._with({buf = vim.api.nvim_create_buf(false, true)}, function() vim.api.nvim_open_win(cmdwin_buf, false, { relative='editor', row=5, col=5, width=5, height=5, }) @@ -1847,6 +1809,38 @@ describe('API/win', function() eq(topdir .. '/Xacd', fn.getcwd()) end) end) + + it('no memory leak with valid title and invalid footer', function() + eq( + 'title/footer must be string or array', + pcall_err(api.nvim_open_win, 0, false, { + relative = 'editor', + row = 10, + col = 10, + height = 10, + width = 10, + border = 'single', + title = { { 'TITLE' } }, + footer = 0, + }) + ) + end) + + it('no memory leak with invalid title and valid footer', function() + eq( + 'title/footer must be string or array', + pcall_err(api.nvim_open_win, 0, false, { + relative = 'editor', + row = 10, + col = 10, + height = 10, + width = 10, + border = 'single', + title = 0, + footer = { { 'FOOTER' } }, + }) + ) + end) end) describe('set_config', function() @@ -2563,10 +2557,6 @@ describe('API/win', function() it('updates statusline when moving bottom split', function() local screen = Screen.new(10, 10) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { bold = true, reverse = true }, -- StatusLine - }) screen:attach() exec([[ set laststatus=0 @@ -2575,10 +2565,10 @@ describe('API/win', function() ]]) screen:expect([[ ^ | - {0:~ }|*3 - {1:[No Name] }| + {1:~ }|*3 + {3:[No Name] }| | - {0:~ }|*3 + {1:~ }|*3 | ]]) end) @@ -2807,61 +2797,35 @@ describe('API/win', function() border = 'single', }) eq( - 'title/footer cannot be an empty array', - pcall_err(api.nvim_win_set_config, win, { title = {} }) + 'title/footer must be string or array', + pcall_err(api.nvim_win_set_config, win, { title = 0 }) ) command('redraw!') assert_alive() - end) - - it('no crash with invalid footer', function() - local win = api.nvim_open_win(0, true, { - width = 10, - height = 10, - relative = 'editor', - row = 10, - col = 10, - footer = { { 'test' } }, - border = 'single', - }) eq( 'title/footer cannot be an empty array', - pcall_err(api.nvim_win_set_config, win, { footer = {} }) + pcall_err(api.nvim_win_set_config, win, { title = {} }) ) command('redraw!') assert_alive() end) - end) - describe('set_config', function() - it('no crash with invalid title', function() + it('no crash with invalid footer', function() local win = api.nvim_open_win(0, true, { width = 10, height = 10, relative = 'editor', row = 10, col = 10, - title = { { 'test' } }, + footer = { { 'test' } }, border = 'single', }) eq( - 'title/footer cannot be an empty array', - pcall_err(api.nvim_win_set_config, win, { title = {} }) + 'title/footer must be string or array', + pcall_err(api.nvim_win_set_config, win, { footer = 0 }) ) command('redraw!') assert_alive() - end) - - it('no crash with invalid footer', function() - local win = api.nvim_open_win(0, true, { - width = 10, - height = 10, - relative = 'editor', - row = 10, - col = 10, - footer = { { 'test' } }, - border = 'single', - }) eq( 'title/footer cannot be an empty array', pcall_err(api.nvim_win_set_config, win, { footer = {} }) @@ -2869,5 +2833,48 @@ describe('API/win', function() command('redraw!') assert_alive() end) + + describe('no crash or memory leak', function() + local win + + before_each(function() + win = api.nvim_open_win(0, false, { + relative = 'editor', + row = 10, + col = 10, + height = 10, + width = 10, + border = 'single', + title = { { 'OLD_TITLE' } }, + footer = { { 'OLD_FOOTER' } }, + }) + end) + + it('with valid title and invalid footer', function() + eq( + 'title/footer must be string or array', + pcall_err(api.nvim_win_set_config, win, { + title = { { 'NEW_TITLE' } }, + footer = 0, + }) + ) + command('redraw!') + assert_alive() + eq({ { 'OLD_TITLE' } }, api.nvim_win_get_config(win).title) + end) + + it('with invalid title and valid footer', function() + eq( + 'title/footer must be string or array', + pcall_err(api.nvim_win_set_config, win, { + title = 0, + footer = { { 'NEW_FOOTER' } }, + }) + ) + command('redraw!') + assert_alive() + eq({ { 'OLD_FOOTER' } }, api.nvim_win_get_config(win).footer) + end) + end) end) end) diff --git a/test/functional/autocmd/autocmd_oldtest_spec.lua b/test/functional/autocmd/autocmd_oldtest_spec.lua index 1a3b723ac2..5e4beb7684 100644 --- a/test/functional/autocmd/autocmd_oldtest_spec.lua +++ b/test/functional/autocmd/autocmd_oldtest_spec.lua @@ -103,9 +103,9 @@ describe('oldtests', function() it('no ml_get error with TextChanged autocommand and delete', function() local screen = Screen.new(75, 10) screen:attach() - screen:set_default_attr_ids({ - [1] = { background = Screen.colors.Cyan }, - }) + screen:add_extra_attr_ids { + [100] = { background = Screen.colors.Cyan1 }, + } exec([[ set noshowcmd noruler scrolloff=0 source test/old/testdir/samples/matchparen.vim @@ -120,9 +120,9 @@ describe('oldtests', function() } | const auto &themes = _forPeer->owner().cloudThemes(); | const auto theme = themes.themeForEmoji(themeEmoji); | - if (!theme) {1:{} | + if (!theme) {100:{} | return nonCustom; | - {1:^}} | + {100:^}} | 353 fewer lines | ]], } diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua index 5e407a9986..0429cfee89 100644 --- a/test/functional/autocmd/autocmd_spec.lua +++ b/test/functional/autocmd/autocmd_spec.lua @@ -259,15 +259,6 @@ describe('autocmd', function() local screen = Screen.new(50, 10) screen:attach() - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { background = Screen.colors.LightMagenta }, - [3] = { - background = Screen.colors.LightMagenta, - bold = true, - foreground = Screen.colors.Blue1, - }, - }) source([[ function! Doit() @@ -292,8 +283,8 @@ describe('autocmd', function() feed(':enew | doautoall User<cr>') screen:expect([[ - {2:bb }| - {3:~ }|*4 + {4:bb }| + {11:~ }|*4 {1:~ }|*4 ^:enew | doautoall User | ]]) @@ -318,8 +309,8 @@ describe('autocmd', function() command('let g:had_value = v:null') feed(':doautoall User<cr>') screen:expect([[ - {2:bb }| - {3:~ }|*4 + {4:bb }| + {11:~ }|*4 {1:~ }|*4 ^:doautoall User | ]]) @@ -343,18 +334,13 @@ describe('autocmd', function() it('`aucmd_win` cannot be changed into a normal window #13699', function() local screen = Screen.new(50, 10) screen:attach() - screen:set_default_attr_ids { - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { reverse = true }, - [3] = { bold = true, reverse = true }, - } -- Create specific layout and ensure it's left unchanged. - -- Use nvim_buf_call on a hidden buffer so aucmd_win is used. + -- Use vim._with on a hidden buffer so aucmd_win is used. exec_lua [[ vim.cmd "wincmd s | wincmd _" _G.buf = vim.api.nvim_create_buf(true, true) - vim.api.nvim_buf_call(_G.buf, function() vim.cmd "wincmd J" end) + vim._with({buf = _G.buf}, function() vim.cmd "wincmd J" end) ]] screen:expect [[ ^ | @@ -367,14 +353,14 @@ describe('autocmd', function() -- This used to crash after making aucmd_win a normal window via the above. exec_lua [[ vim.cmd "tabnew | tabclose # | wincmd s | wincmd _" - vim.api.nvim_buf_call(_G.buf, function() vim.cmd "wincmd K" end) + vim._with({buf = _G.buf}, function() vim.cmd "wincmd K" end) ]] assert_alive() screen:expect_unchanged() -- Also check with win_splitmove(). exec_lua [[ - vim.api.nvim_buf_call(_G.buf, function() + vim._with({buf = _G.buf}, function() vim.fn.win_splitmove(vim.fn.winnr(), vim.fn.win_getid(1)) end) ]] @@ -382,11 +368,11 @@ describe('autocmd', function() -- Also check with nvim_win_set_config(). matches( - ': Failed to move window %d+ into split$', + '^Failed to move window %d+ into split$', pcall_err( exec_lua, [[ - vim.api.nvim_buf_call(_G.buf, function() + vim._with({buf = _G.buf}, function() vim.api.nvim_win_set_config(0, { vertical = true, win = vim.fn.win_getid(1) @@ -398,7 +384,7 @@ describe('autocmd', function() screen:expect_unchanged() -- Ensure splitting still works from inside the aucmd_win. - exec_lua [[vim.api.nvim_buf_call(_G.buf, function() vim.cmd "split" end)]] + exec_lua [[vim._with({buf = _G.buf}, function() vim.cmd "split" end)]] screen:expect [[ ^ | {1:~ }| @@ -418,7 +404,7 @@ describe('autocmd', function() 'editor', exec_lua [[ vim.cmd "only" - vim.api.nvim_buf_call(_G.buf, function() + vim._with({buf = _G.buf}, function() _G.config = vim.api.nvim_win_get_config(0) end) return _G.config.relative @@ -463,7 +449,7 @@ describe('autocmd', function() pcall_err( exec_lua, [[ - vim.api.nvim_buf_call(_G.buf, function() + vim._with({buf = _G.buf}, function() local win = vim.api.nvim_get_current_win() vim.api.nvim_win_close(win, true) end) @@ -475,7 +461,7 @@ describe('autocmd', function() pcall_err( exec_lua, [[ - vim.api.nvim_buf_call(_G.buf, function() + vim._with({buf = _G.buf}, function() local win = vim.api.nvim_get_current_win() vim.cmd('tabnext') vim.api.nvim_win_close(win, true) @@ -488,7 +474,7 @@ describe('autocmd', function() pcall_err( exec_lua, [[ - vim.api.nvim_buf_call(_G.buf, function() + vim._with({buf = _G.buf}, function() local win = vim.api.nvim_get_current_win() vim.api.nvim_win_hide(win) end) @@ -500,7 +486,7 @@ describe('autocmd', function() pcall_err( exec_lua, [[ - vim.api.nvim_buf_call(_G.buf, function() + vim._with({buf = _G.buf}, function() local win = vim.api.nvim_get_current_win() vim.cmd('tabnext') vim.api.nvim_win_hide(win) @@ -513,9 +499,6 @@ describe('autocmd', function() it(':doautocmd does not warn "No matching autocommands" #10689', function() local screen = Screen.new(32, 3) screen:attach() - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - }) feed(':doautocmd User Foo<cr>') screen:expect { diff --git a/test/functional/autocmd/cmdline_spec.lua b/test/functional/autocmd/cmdline_spec.lua index ad3bc3576f..ca137debb8 100644 --- a/test/functional/autocmd/cmdline_spec.lua +++ b/test/functional/autocmd/cmdline_spec.lua @@ -61,12 +61,6 @@ describe('cmdline autocommands', function() clear() local screen = Screen.new(72, 8) screen:attach() - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - [3] = { bold = true, foreground = Screen.colors.SeaGreen4 }, - [4] = { bold = true, reverse = true }, - }) command("autocmd CmdlineEnter * echoerr 'FAIL'") command("autocmd CmdlineLeave * echoerr 'very error'") @@ -74,22 +68,22 @@ describe('cmdline autocommands', function() screen:expect([[ | {1:~ }|*3 - {4: }| + {3: }| : | - {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | + {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | :^ | ]]) feed("put ='lorem ipsum'<cr>") screen:expect([[ | - {4: }| + {3: }| : | - {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | + {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | :put ='lorem ipsum' | - {2:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} | + {9:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} | | - {3:Press ENTER or type command to continue}^ | + {6:Press ENTER or type command to continue}^ | ]]) -- cmdline was still executed @@ -108,11 +102,11 @@ describe('cmdline autocommands', function() screen:expect([[ | lorem ipsum | - {4: }| + {3: }| : | - {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | + {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | :put ='lorem ipsum' | - {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | + {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | :put ='lorem ipsum'^ | ]]) @@ -120,37 +114,37 @@ describe('cmdline autocommands', function() screen:expect([[ | lorem ipsum | - {4: }| + {3: }| : | - {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | + {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | :put ='lorem ipsum' | - {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | + {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | :put ='lorem ipsum^' | ]]) -- edit still works feed('.') screen:expect([[ - {4: }| + {3: }| : | - {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | + {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | :put ='lorem ipsum' | - {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | + {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | :put ='lorem ipsum.' | - {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | + {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | :put ='lorem ipsum.^' | ]]) feed('<cr>') screen:expect([[ :put ='lorem ipsum' | - {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | + {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | :put ='lorem ipsum.' | - {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | + {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | :put ='lorem ipsum.' | - {2:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} | + {9:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} | | - {3:Press ENTER or type command to continue}^ | + {6:Press ENTER or type command to continue}^ | ]]) -- cmdline was still executed diff --git a/test/functional/autocmd/dirchanged_spec.lua b/test/functional/autocmd/dirchanged_spec.lua index 24ac737b5b..1cde0e0552 100644 --- a/test/functional/autocmd/dirchanged_spec.lua +++ b/test/functional/autocmd/dirchanged_spec.lua @@ -9,7 +9,7 @@ local request = n.request local is_os = t.is_os describe('autocmd DirChanged and DirChangedPre', function() - local curdir = vim.uv.cwd():gsub('\\', '/') + local curdir = t.fix_slashes(vim.uv.cwd()) local dirs = { curdir .. '/Xtest-functional-autocmd-dirchanged.dir1', curdir .. '/Xtest-functional-autocmd-dirchanged.dir2', diff --git a/test/functional/autocmd/focus_spec.lua b/test/functional/autocmd/focus_spec.lua index 5163b576db..7f6092bf48 100644 --- a/test/functional/autocmd/focus_spec.lua +++ b/test/functional/autocmd/focus_spec.lua @@ -1,6 +1,6 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local clear = n.clear local feed_command = n.feed_command diff --git a/test/functional/autocmd/show_spec.lua b/test/functional/autocmd/show_spec.lua index 7e1818c4fd..10d242527f 100644 --- a/test/functional/autocmd/show_spec.lua +++ b/test/functional/autocmd/show_spec.lua @@ -43,11 +43,9 @@ describe(':autocmd', function() it('should not show group information if interrupted', function() local screen = Screen.new(50, 6) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, -- NonText - [2] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg - [3] = { bold = true, foreground = Screen.colors.Magenta }, -- Title - }) + screen:add_extra_attr_ids { + [100] = { foreground = Screen.colors.Magenta, bold = true }, + } screen:attach() exec([[ set more @@ -73,11 +71,11 @@ describe(':autocmd', function() feed(':autocmd<CR>') screen:expect([[ :autocmd | - {3:--- Autocommands ---} | - {3:test_1} {3:BufEnter} | + {100:--- Autocommands ---} | + {100:test_1} {100:BufEnter} | A echo 'A' | B echo 'B' | - {2:-- More --}^ | + {6:-- More --}^ | ]]) feed('q') screen:expect([[ diff --git a/test/functional/autocmd/termxx_spec.lua b/test/functional/autocmd/termxx_spec.lua index a63996ae36..64f16cf779 100644 --- a/test/functional/autocmd/termxx_spec.lua +++ b/test/functional/autocmd/termxx_spec.lua @@ -1,6 +1,6 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local uv = vim.uv local clear, command, testprg = n.clear, n.command, n.testprg @@ -199,7 +199,7 @@ end) describe('autocmd TextChangedT', function() clear() - local screen = tt.screen_setup() + local screen = tt.setup_screen() it('works', function() command('autocmd TextChangedT * ++once let g:called = 1') diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua index a98e190a60..dee13d19ae 100644 --- a/test/functional/core/channels_spec.lua +++ b/test/functional/core/channels_spec.lua @@ -288,6 +288,37 @@ describe('channels', function() eq({ 'notification', 'exit', { 3, 0 } }, next_msg()) end) + it('stdio channel works with stdout redirected to file #30509', function() + t.write_file( + 'Xstdio_write.vim', + [[ + let chan = stdioopen({}) + call chansend(chan, 'foo') + call chansend(chan, 'bar') + qall! + ]] + ) + local fd = assert(vim.uv.fs_open('Xstdio_redir', 'w', 420)) + local exit_code, exit_signal + local handle = vim.uv.spawn(nvim_prog, { + args = { '-u', 'NONE', '-i', 'NONE', '--headless', '-S', 'Xstdio_write.vim' }, + -- Simulate shell redirection: "nvim ... > Xstdio_redir". #30509 + stdio = { nil, fd, nil }, + }, function(code, signal) + vim.uv.stop() + exit_code, exit_signal = code, signal + end) + finally(function() + handle:close() + vim.uv.fs_close(fd) + os.remove('Xstdio_write.vim') + os.remove('Xstdio_redir') + end) + vim.uv.run('default') + eq({ 0, 0 }, { exit_code, exit_signal }) + eq('foobar', t.read_file('Xstdio_redir')) + end) + it('can use buffered output mode', function() skip(fn.executable('grep') == 0, 'missing "grep" command') source([[ diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua index 5b0be1e83c..d33710a63d 100644 --- a/test/functional/core/fileio_spec.lua +++ b/test/functional/core/fileio_spec.lua @@ -276,11 +276,6 @@ describe('fileio', function() write_file('Xtest-overwrite-forced', 'foobar') command('set nofixendofline') local screen = Screen.new(40, 4) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - [3] = { bold = true, foreground = Screen.colors.SeaGreen4 }, - }) screen:attach() command('set shortmess-=F') @@ -300,9 +295,9 @@ describe('fileio', function() -- use async feed_command because nvim basically hangs on the prompt feed_command('w') screen:expect([[ - {2:WARNING: The file has been changed since}| - {2: reading it!!!} | - {3:Do you really want to write to it (y/n)?}| + {9:WARNING: The file has been changed since}| + {9: reading it!!!} | + {6:Do you really want to write to it (y/n)?}| ^ | ]]) @@ -326,11 +321,11 @@ end) describe('tmpdir', function() local tmproot_pat = [=[.*[/\\]nvim%.[^/\\]+]=] local testlog = 'Xtest_tmpdir_log' - local os_tmpdir + local os_tmpdir ---@type string before_each(function() -- Fake /tmp dir so that we can mess it up. - os_tmpdir = vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname()) .. '/nvim_XXXXXXXXXX') + os_tmpdir = assert(vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname(false)) .. '/nvim_XXXXXXXXXX')) end) after_each(function() @@ -419,15 +414,4 @@ describe('tmpdir', function() rm_tmpdir() eq('E5431: tempdir disappeared (3 times)', api.nvim_get_vvar('errmsg')) end) - - it('$NVIM_APPNAME relative path', function() - clear({ - env = { - NVIM_APPNAME = 'a/b', - NVIM_LOG_FILE = testlog, - TMPDIR = os_tmpdir, - }, - }) - matches([=[.*[/\\]a%%b%.[^/\\]+]=], fn.tempname()) - end) end) diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index e1efc07452..68ac0a50f6 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local clear = n.clear local eq = t.eq @@ -910,11 +910,6 @@ describe('jobs', function() it('hides cursor and flushes messages before blocking', function() local screen = Screen.new(50, 6) - screen:set_default_attr_ids({ - [0] = { foreground = Screen.colors.Blue, bold = true }, -- NonText - [1] = { bold = true, reverse = true }, -- MsgSeparator - [2] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg - }) screen:attach() command([[let g:id = jobstart([v:progpath, '--clean', '--headless'])]]) source([[ @@ -928,8 +923,8 @@ describe('jobs', function() screen:expect { grid = [[ | - {0:~ }|*2 - {1: }| + {1:~ }|*2 + {3: }| aaa | bbb | ]], @@ -938,11 +933,11 @@ describe('jobs', function() screen:expect { grid = [[ | - {1: }| + {3: }| aaa | bbb | ccc | - {2:Press ENTER or type command to continue}^ | + {6:Press ENTER or type command to continue}^ | ]], } feed('<CR>') diff --git a/test/functional/core/log_spec.lua b/test/functional/core/log_spec.lua index cac61cda2d..a952730779 100644 --- a/test/functional/core/log_spec.lua +++ b/test/functional/core/log_spec.lua @@ -1,5 +1,6 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() +local tt = require('test.functional.testterm') local assert_log = t.assert_log local clear = n.clear @@ -29,10 +30,54 @@ describe('log', function() assert(request('nvim__stats').log_skip <= 13) end) - it('messages are formatted with name or test id', function() + it('TUI client name is "ui"', function() + local function setup(env) + clear() + -- Start Nvim with builtin UI. + local screen = tt.setup_child_nvim({ + '-u', + 'NONE', + '-i', + 'NONE', + '--cmd', + n.nvim_set, + }, { + env = env, + }) + screen:expect([[ + {1: } | + ~ |*4 + | + {3:-- TERMINAL --} | + ]]) + end + + -- Without $NVIM parent. + setup({ + NVIM = '', + NVIM_LISTEN_ADDRESS = '', + NVIM_LOG_FILE = testlog, + __NVIM_TEST_LOG = '1', + }) + -- Example: + -- ERR 2024-09-11T16:40:02.421 ui.47056 ui_client_run:165: test log message + assert_log(' ui%.%d+% +ui_client_run:%d+: test log message', testlog, 100) + + -- With $NVIM parent. + setup({ + NVIM_LOG_FILE = testlog, + __NVIM_TEST_LOG = '1', + }) + -- Example: + -- ERR 2024-09-11T16:41:17.539 ui/c/T2.47826.0 ui_client_run:165: test log message + local tid = _G._nvim_test_id + assert_log(' ui/c/' .. tid .. '%.%d+%.%d +ui_client_run:%d+: test log message', testlog, 100) + end) + + it('formats messages with session name or test id', function() -- Examples: - -- ERR 2022-05-29T12:30:03.800 T2 log_init:110: test log message - -- ERR 2022-05-29T12:30:03.814 T2/child log_init:110: test log message + -- ERR 2024-09-11T16:44:33.794 T3.49429.0 server_init:58: test log message + -- ERR 2024-09-11T16:44:33.823 c/T3.49429.0 server_init:58: test log message clear({ env = { @@ -47,10 +92,10 @@ describe('log', function() exec_lua([[ local j1 = vim.fn.jobstart({ vim.v.progpath, '-es', '-V1', '+foochild', '+qa!' }, vim.empty_dict()) - vim.fn.jobwait({ j1 }, 10000) + vim.fn.jobwait({ j1 }, 5000) ]]) - -- Child Nvim spawned by jobstart() appends "/c" to parent name. - assert_log('%.%d+%.%d/c +server_init:%d+: test log message', testlog, 100) + -- Child Nvim spawned by jobstart() prepends "c/" to parent name. + assert_log('c/' .. tid .. '%.%d+%.%d +server_init:%d+: test log message', testlog, 100) end) end) diff --git a/test/functional/core/main_spec.lua b/test/functional/core/main_spec.lua index 5e903726db..a6e917b4b2 100644 --- a/test/functional/core/main_spec.lua +++ b/test/functional/core/main_spec.lua @@ -193,4 +193,26 @@ describe('command-line option', function() matches('Run "nvim %-V1 %-v"', fn.system({ nvim_prog_abs(), '-v' })) matches('Compilation: .*Run :checkhealth', fn.system({ nvim_prog_abs(), '-V1', '-v' })) end) + + if is_os('win') then + for _, prefix in ipairs({ '~/', '~\\' }) do + it('expands ' .. prefix .. ' on Windows', function() + local fname = os.getenv('USERPROFILE') .. '\\nvim_test.txt' + finally(function() + os.remove(fname) + end) + write_file(fname, 'some text') + eq( + 'some text', + fn.system({ + nvim_prog_abs(), + '-es', + '+%print', + '+q', + prefix .. 'nvim_test.txt', + }):gsub('\n', '') + ) + end) + end + end end) diff --git a/test/functional/vimscript/server_spec.lua b/test/functional/core/server_spec.lua index 4b0dc087f6..0ec11169e9 100644 --- a/test/functional/vimscript/server_spec.lua +++ b/test/functional/core/server_spec.lua @@ -1,10 +1,8 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local assert_log = t.assert_log local eq, neq, eval = t.eq, t.neq, n.eval local clear, fn, api = n.clear, n.fn, n.api -local ok = t.ok local matches = t.matches local pcall_err = t.pcall_err local check_close = n.check_close @@ -20,12 +18,16 @@ local function clear_serverlist() end end -describe('server', function() - after_each(function() - check_close() - os.remove(testlog) - end) +after_each(function() + check_close() + os.remove(testlog) +end) +before_each(function() + os.remove(testlog) +end) + +describe('server', function() it('serverstart() stores sockets in $XDG_RUNTIME_DIR', function() local dir = 'Xtest_xdg_run' mkdir(dir) @@ -39,6 +41,21 @@ describe('server', function() end end) + it('broken $XDG_RUNTIME_DIR is not fatal #30282', function() + clear { + args_rm = { '--listen' }, + env = { NVIM_LOG_FILE = testlog, XDG_RUNTIME_DIR = '/non-existent-dir/subdir//' }, + } + + if is_os('win') then + -- Windows pipes have a special namespace and thus aren't decided by $XDG_RUNTIME_DIR. + matches('nvim', api.nvim_get_vvar('servername')) + else + eq('', api.nvim_get_vvar('servername')) + t.assert_log('Failed to start server%: no such file or directory', testlog, 100) + end + end) + it('serverstart(), serverstop() does not set $NVIM', function() clear() local s = eval('serverstart()') @@ -49,15 +66,6 @@ describe('server', function() eq('', eval('$NVIM_LISTEN_ADDRESS')) end) - it('sets new v:servername if $NVIM_LISTEN_ADDRESS is invalid', function() - clear({ env = { NVIM_LISTEN_ADDRESS = '.' } }) - -- Cleared on startup. - eq('', eval('$NVIM_LISTEN_ADDRESS')) - local servers = fn.serverlist() - eq(1, #servers) - ok(string.len(servers[1]) > 4) -- "~/.local/state/nvim…/…" or "\\.\pipe\…" - end) - it('sets v:servername at startup or if all servers were stopped', function() clear() local initial_server = api.nvim_get_vvar('servername') @@ -89,20 +97,26 @@ describe('server', function() end) it('serverstop() returns false for invalid input', function() - clear { env = { - NVIM_LOG_FILE = testlog, - NVIM_LISTEN_ADDRESS = '.', - } } + clear { + args_rm = { '--listen' }, + env = { + NVIM_LOG_FILE = testlog, + NVIM_LISTEN_ADDRESS = '', + }, + } eq(0, eval("serverstop('')")) eq(0, eval("serverstop('bogus-socket-name')")) - assert_log('Not listening on bogus%-socket%-name', testlog, 10) + t.assert_log('Not listening on bogus%-socket%-name', testlog, 10) end) it('parses endpoints', function() - clear { env = { - NVIM_LOG_FILE = testlog, - NVIM_LISTEN_ADDRESS = '.', - } } + clear { + args_rm = { '--listen' }, + env = { + NVIM_LOG_FILE = testlog, + NVIM_LISTEN_ADDRESS = '', + }, + } clear_serverlist() eq({}, fn.serverlist()) @@ -126,7 +140,7 @@ describe('server', function() if status then table.insert(expected, v4) pcall(fn.serverstart, v4) -- exists already; ignore - assert_log('Failed to start server: address already in use: 127%.0%.0%.1', testlog, 10) + t.assert_log('Failed to start server: address already in use: 127%.0%.0%.1', testlog, 10) end local v6 = '::1:12345' @@ -134,13 +148,13 @@ describe('server', function() if status then table.insert(expected, v6) pcall(fn.serverstart, v6) -- exists already; ignore - assert_log('Failed to start server: address already in use: ::1', testlog, 10) + t.assert_log('Failed to start server: address already in use: ::1', testlog, 10) end eq(expected, fn.serverlist()) clear_serverlist() -- Address without slashes is a "name" which is appended to a generated path. #8519 - matches([[.*[/\\]xtest1%.2%.3%.4[^/\\]*]], fn.serverstart('xtest1.2.3.4')) + matches([[[/\\]xtest1%.2%.3%.4[^/\\]*]], fn.serverstart('xtest1.2.3.4')) clear_serverlist() eq('Vim:Failed to start server: invalid argument', pcall_err(fn.serverstart, '127.0.0.1:65536')) -- invalid port @@ -176,24 +190,89 @@ describe('server', function() end) describe('startup --listen', function() + -- Tests Nvim output when failing to start, with and without "--headless". + -- TODO(justinmk): clear() should have a way to get stdout if Nvim fails to start. + local function _test(args, env, expected) + local function run(cmd) + return n.exec_lua(function(cmd_, env_) + return vim + .system(cmd_, { + text = true, + env = vim.tbl_extend( + 'force', + -- Avoid noise in the logs; we expect failures for these tests. + { NVIM_LOG_FILE = testlog }, + env_ or {} + ), + }) + :wait() + end, cmd, env) --[[@as vim.SystemCompleted]] + end + + local cmd = vim.list_extend({ n.nvim_prog, '+qall!', '--headless' }, args) + local r = run(cmd) + eq(1, r.code) + matches(expected, (r.stderr .. r.stdout):gsub('\\n', ' ')) + + if is_os('win') then + return -- On Windows, output without --headless is garbage. + end + table.remove(cmd, 3) -- Remove '--headless'. + assert(not vim.tbl_contains(cmd, '--headless')) + r = run(cmd) + eq(1, r.code) + matches(expected, (r.stderr .. r.stdout):gsub('\\n', ' ')) + end + it('validates', function() - clear() - local cmd = { unpack(n.nvim_argv) } - table.insert(cmd, '--listen') - matches('nvim.*: Argument missing after: "%-%-listen"', fn.system(cmd)) + clear { env = { NVIM_LOG_FILE = testlog } } + local in_use = n.eval('v:servername') ---@type string Address already used by another server. + + t.assert_nolog('Failed to start server', testlog, 100) + t.assert_nolog('Host lookup failed', testlog, 100) - cmd = { unpack(n.nvim_argv) } - table.insert(cmd, '--listen2') - matches('nvim.*: Garbage after option argument: "%-%-listen2"', fn.system(cmd)) + _test({ '--listen' }, nil, 'nvim.*: Argument missing after: "%-%-listen"') + _test({ '--listen2' }, nil, 'nvim.*: Garbage after option argument: "%-%-listen2"') + _test( + { '--listen', in_use }, + nil, + ('nvim.*: Failed to %%-%%-listen: [^:]+ already [^:]+: "%s"'):format(vim.pesc(in_use)) + ) + _test({ '--listen', '/' }, nil, 'nvim.*: Failed to %-%-listen: [^:]+: "/"') + _test( + { '--listen', 'https://example.com' }, + nil, + ('nvim.*: Failed to %%-%%-listen: %s: "https://example.com"'):format( + is_os('mac') and 'unknown node or service' or 'service not available for socket type' + ) + ) + + t.assert_log('Failed to start server', testlog, 100) + t.assert_log('Host lookup failed', testlog, 100) + + _test( + {}, + { NVIM_LISTEN_ADDRESS = in_use }, + ('nvim.*: Failed $NVIM_LISTEN_ADDRESS: [^:]+ already [^:]+: "%s"'):format(vim.pesc(in_use)) + ) + _test({}, { NVIM_LISTEN_ADDRESS = '/' }, 'nvim.*: Failed $NVIM_LISTEN_ADDRESS: [^:]+: "/"') + _test( + {}, + { NVIM_LISTEN_ADDRESS = 'https://example.com' }, + ('nvim.*: Failed $NVIM_LISTEN_ADDRESS: %s: "https://example.com"'):format( + is_os('mac') and 'unknown node or service' or 'service not available for socket type' + ) + ) end) it('sets v:servername, overrides $NVIM_LISTEN_ADDRESS', function() local addr = (is_os('win') and [[\\.\pipe\Xtest-listen-pipe]] or './Xtest-listen-pipe') clear({ env = { NVIM_LISTEN_ADDRESS = './Xtest-env-pipe' }, args = { '--listen', addr } }) + eq('', eval('$NVIM_LISTEN_ADDRESS')) -- Cleared on startup. eq(addr, api.nvim_get_vvar('servername')) -- Address without slashes is a "name" which is appended to a generated path. #8519 clear({ args = { '--listen', 'test-name' } }) - matches([[.*[/\\]test%-name[^/\\]*]], api.nvim_get_vvar('servername')) + matches([[[/\\]test%-name[^/\\]*]], api.nvim_get_vvar('servername')) end) end) diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index a53625ab1b..f48bcb9360 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -27,7 +27,6 @@ local sleep = vim.uv.sleep local startswith = vim.startswith local write_file = t.write_file local api = n.api -local alter_slashes = n.alter_slashes local is_os = t.is_os local dedent = t.dedent local tbl_map = vim.tbl_map @@ -40,22 +39,15 @@ local testlog = 'Xtest-startupspec-log' describe('startup', function() it('--clean', function() clear() - ok( - string.find( - alter_slashes(api.nvim_get_option_value('runtimepath', {})), - fn.stdpath('config'), - 1, - true - ) ~= nil + matches( + vim.pesc(t.fix_slashes(fn.stdpath('config'))), + t.fix_slashes(api.nvim_get_option_value('runtimepath', {})) ) + clear('--clean') ok( - string.find( - alter_slashes(api.nvim_get_option_value('runtimepath', {})), - fn.stdpath('config'), - 1, - true - ) == nil + not t.fix_slashes(api.nvim_get_option_value('runtimepath', {})) + :match(vim.pesc(t.fix_slashes(fn.stdpath('config')))) ) end) @@ -112,6 +104,13 @@ describe('startup', function() |*2 ]]) end) + + it(':filetype detect enables filetype detection with -u NONE', function() + clear() + eq('filetype detection:OFF plugin:OFF indent:OFF', exec_capture('filetype')) + command('filetype detect') + eq('filetype detection:ON plugin:OFF indent:OFF', exec_capture('filetype')) + end) end) describe('startup', function() @@ -400,9 +399,6 @@ describe('startup', function() read_file('Xtest_startup_ttyout') ) end) - if is_os('win') then - assert_log('stream write failed. RPC canceled; closing channel', testlog) - end end) it('input from pipe: has("ttyin")==0 has("ttyout")==1', function() @@ -435,9 +431,6 @@ describe('startup', function() read_file('Xtest_startup_ttyout') ) end) - if is_os('win') then - assert_log('stream write failed. RPC canceled; closing channel', testlog) - end end) it('input from pipe (implicit) #7679', function() @@ -1331,31 +1324,59 @@ describe('runtime:', function() end) it("loads ftdetect/*.{vim,lua} respecting 'rtp' order", function() - local ftdetect_folder = table.concat({ xconfig, 'nvim', 'ftdetect' }, pathsep) - local after_ftdetect_folder = table.concat({ xconfig, 'nvim', 'after', 'ftdetect' }, pathsep) + local rtp_folder = table.concat({ xconfig, 'nvim' }, pathsep) + local after_rtp_folder = table.concat({ rtp_folder, 'after' }, pathsep) + local ftdetect_folder = table.concat({ rtp_folder, 'ftdetect' }, pathsep) + local after_ftdetect_folder = table.concat({ after_rtp_folder, 'ftdetect' }, pathsep) mkdir_p(ftdetect_folder) mkdir_p(after_ftdetect_folder) finally(function() rmdir(ftdetect_folder) rmdir(after_ftdetect_folder) end) + write_file(table.concat({ rtp_folder, 'scripts.vim' }, pathsep), [[let g:aseq ..= 'S']]) + write_file(table.concat({ after_rtp_folder, 'scripts.vim' }, pathsep), [[let g:aseq ..= 's']]) -- A .lua file is loaded after a .vim file if they only differ in extension. -- All files in after/ftdetect/ are loaded after all files in ftdetect/. - write_file(table.concat({ ftdetect_folder, 'new-ft.vim' }, pathsep), [[let g:seq ..= 'A']]) + write_file( + table.concat({ ftdetect_folder, 'new-ft.vim' }, pathsep), + [[ + let g:seq ..= 'A' + autocmd BufRead,BufNewFile FTDETECT let g:aseq ..= 'A' + ]] + ) write_file( table.concat({ ftdetect_folder, 'new-ft.lua' }, pathsep), - [[vim.g.seq = vim.g.seq .. 'B']] + [[ + vim.g.seq = vim.g.seq .. 'B' + vim.api.nvim_create_autocmd({ 'BufRead', 'BufNewFile' }, { + pattern = 'FTDETECT', + command = "let g:aseq ..= 'B'", + }) + ]] ) write_file( table.concat({ after_ftdetect_folder, 'new-ft.vim' }, pathsep), - [[let g:seq ..= 'a']] + [[ + let g:seq ..= 'a' + autocmd BufRead,BufNewFile FTDETECT let g:aseq ..= 'a' + ]] ) write_file( table.concat({ after_ftdetect_folder, 'new-ft.lua' }, pathsep), - [[vim.g.seq = vim.g.seq .. 'b']] + [[ + vim.g.seq = vim.g.seq .. 'b' + vim.api.nvim_create_autocmd({ 'BufRead', 'BufNewFile' }, { + pattern = 'FTDETECT', + command = "let g:aseq ..= 'b'", + }) + ]] ) clear { args_rm = { '-u' }, args = { '--cmd', 'let g:seq = ""' }, env = xenv } eq('ABab', eval('g:seq')) + command('let g:aseq = ""') + command('edit FTDETECT') + eq('SsABab', eval('g:aseq')) end) end) diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua index 62bb7e19f3..d543de4acd 100644 --- a/test/functional/editor/completion_spec.lua +++ b/test/functional/editor/completion_spec.lua @@ -4,7 +4,7 @@ local Screen = require('test.functional.ui.screen') local assert_alive = n.assert_alive local clear, feed = n.clear, n.feed -local eval, eq, neq = n.eval, t.eq, t.neq +local eval, eq, neq, ok = n.eval, t.eq, t.neq, t.ok local feed_command, source, expect = n.feed_command, n.source, n.expect local fn = n.fn local command = n.command @@ -18,19 +18,10 @@ describe('completion', function() clear() screen = Screen.new(60, 8) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { background = Screen.colors.LightMagenta }, - [2] = { background = Screen.colors.Grey }, - [3] = { bold = true }, - [4] = { bold = true, foreground = Screen.colors.SeaGreen }, - [5] = { foreground = Screen.colors.Red }, - [6] = { background = Screen.colors.Black }, - [7] = { foreground = Screen.colors.White, background = Screen.colors.Red }, - [8] = { reverse = true }, - [9] = { bold = true, reverse = true }, - [10] = { foreground = Screen.colors.Grey0, background = Screen.colors.Yellow }, - }) + screen:add_extra_attr_ids { + [100] = { foreground = Screen.colors.Gray0, background = Screen.colors.Yellow }, + [101] = { background = Screen.colors.Gray0 }, + } end) describe('v:completed_item', function() @@ -42,15 +33,15 @@ describe('completion', function() screen:expect([[ foo | foo^ | - {0:~ }|*5 - {3:-- Keyword Local completion (^N^P) The only match} | + {1:~ }|*5 + {5:-- Keyword Local completion (^N^P) The only match} | ]]) feed('<C-e>') screen:expect([[ foo | ^ | - {0:~ }|*5 - {3:-- INSERT --} | + {1:~ }|*5 + {5:-- INSERT --} | ]]) feed('<ESC>') eq({}, eval('v:completed_item')) @@ -104,10 +95,10 @@ describe('completion', function() eq('foo', eval('getline(1)')) screen:expect([[ foo^ | - {2:bar foobaz baz }{0: }| - {1:abbr kind menu }{0: }| - {0:~ }|*4 - {3:-- Omni completion (^O^N^P) }{4:match 1 of 2} | + {12:bar foobaz baz }{1: }| + {4:abbr kind menu }{1: }| + {1:~ }|*4 + {5:-- Omni completion (^O^N^P) }{6:match 1 of 2} | ]]) eq({ word = 'foo', @@ -136,24 +127,24 @@ describe('completion', function() screen:expect([[ foo | ^ | - {0:~ }|*5 - {3:-- INSERT --} | + {1:~ }|*5 + {5:-- INSERT --} | ]]) feed('<C-x>') -- the ^X prompt, only test this once screen:expect([[ foo | ^ | - {0:~ }|*5 - {3:-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)} | + {1:~ }|*5 + {5:-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)} | ]]) feed('<C-n>') screen:expect([[ foo | foo^ | - {2:foo }{0: }| - {0:~ }|*4 - {3:-- Keyword Local completion (^N^P) The only match} | + {12:foo }{1: }| + {1:~ }|*4 + {5:-- Keyword Local completion (^N^P) The only match} | ]]) feed('bar<ESC>') eq('foobar', eval('getline(2)')) @@ -162,9 +153,9 @@ describe('completion', function() foo | foobar | foo^ | - {2:foo }{0: }| - {0:~ }|*3 - {3:-- INSERT --} | + {12:foo }{1: }| + {1:~ }|*3 + {5:-- INSERT --} | ]]) eq('foo', eval('getline(3)')) end) @@ -174,16 +165,16 @@ describe('completion', function() screen:expect([[ foo | ^ | - {2:foo }{0: }| - {0:~ }|*4 - {3:-- Keyword Local completion (^N^P) The only match} | + {12:foo }{1: }| + {1:~ }|*4 + {5:-- Keyword Local completion (^N^P) The only match} | ]]) feed('<C-y>') screen:expect([[ foo | foo^ | - {0:~ }|*5 - {3:-- INSERT --} | + {1:~ }|*5 + {5:-- INSERT --} | ]]) feed('<ESC>') eq('foo', eval('getline(2)')) @@ -191,9 +182,9 @@ describe('completion', function() screen:expect([[ foo |*2 ^ | - {2:foo }{0: }| - {0:~ }|*3 - {3:-- INSERT --} | + {12:foo }{1: }| + {1:~ }|*3 + {5:-- INSERT --} | ]]) feed('<C-y><ESC>') eq('foo', eval('getline(3)')) @@ -204,16 +195,16 @@ describe('completion', function() screen:expect([[ foo | ^ | - {1:foo }{0: }| - {0:~ }|*4 - {3:-- Keyword Local completion (^N^P) }{5:Back at original} | + {4:foo }{1: }| + {1:~ }|*4 + {5:-- Keyword Local completion (^N^P) }{19:Back at original} | ]]) feed('b') screen:expect([[ foo | b^ | - {0:~ }|*5 - {3:-- Keyword Local completion (^N^P) }{5:Back at original} | + {1:~ }|*5 + {5:-- Keyword Local completion (^N^P) }{19:Back at original} | ]]) feed('ar<ESC>') eq('bar', eval('getline(2)')) @@ -222,9 +213,9 @@ describe('completion', function() foo | bar | ^ | - {1:foo }{0: }| - {0:~ }|*3 - {3:-- INSERT --} | + {4:foo }{1: }| + {1:~ }|*3 + {5:-- INSERT --} | ]]) feed('bar<ESC>') eq('bar', eval('getline(3)')) @@ -235,15 +226,15 @@ describe('completion', function() screen:expect([[ foo | ^ | - {1:foo }{0: }| - {0:~ }|*4 - {3:-- Keyword Local completion (^N^P) }{5:Back at original} | + {4:foo }{1: }| + {1:~ }|*4 + {5:-- Keyword Local completion (^N^P) }{19:Back at original} | ]]) feed('<ESC>') screen:expect([[ foo | ^ | - {0:~ }|*5 + {1:~ }|*5 | ]]) eq('', eval('getline(2)')) @@ -252,16 +243,16 @@ describe('completion', function() foo | | ^ | - {1:foo }{0: }| - {0:~ }|*3 - {3:-- INSERT --} | + {4:foo }{1: }| + {1:~ }|*3 + {5:-- INSERT --} | ]]) feed('<ESC>') screen:expect([[ foo | | ^ | - {0:~ }|*4 + {1:~ }|*4 | ]]) eq('', eval('getline(3)')) @@ -336,7 +327,7 @@ describe('completion', function() end end) - describe('refresh:always', function() + describe('with refresh:always and noselect', function() before_each(function() source([[ function! TestCompletion(findstart, base) abort @@ -367,44 +358,44 @@ describe('completion', function() feed('i<C-x><C-u>') screen:expect([[ ^ | - {1:January }{6: }{0: }| - {1:February }{6: }{0: }| - {1:March }{6: }{0: }| - {1:April }{2: }{0: }| - {1:May }{2: }{0: }| - {1:June }{2: }{0: }| - {3:-- User defined completion (^U^N^P) }{5:Back at original} | + {4:January }{101: }{1: }| + {4:February }{101: }{1: }| + {4:March }{101: }{1: }| + {4:April }{12: }{1: }| + {4:May }{12: }{1: }| + {4:June }{12: }{1: }| + {5:-- User defined completion (^U^N^P) }{19:Back at original} | ]]) feed('u') screen:expect([[ u^ | - {1:January }{0: }| - {1:February }{0: }| - {1:June }{0: }| - {1:July }{0: }| - {1:August }{0: }| - {0:~ }| - {3:-- User defined completion (^U^N^P) }{5:Back at original} | + {4:January }{1: }| + {4:February }{1: }| + {4:June }{1: }| + {4:July }{1: }| + {4:August }{1: }| + {1:~ }| + {5:-- User defined completion (^U^N^P) }{19:Back at original} | ]]) feed('g') screen:expect([[ ug^ | - {1:August }{0: }| - {0:~ }|*5 - {3:-- User defined completion (^U^N^P) }{5:Back at original} | + {4:August }{1: }| + {1:~ }|*5 + {5:-- User defined completion (^U^N^P) }{19:Back at original} | ]]) feed('<Down>') screen:expect([[ ug^ | - {2:August }{0: }| - {0:~ }|*5 - {3:-- User defined completion (^U^N^P) The only match} | + {12:August }{1: }| + {1:~ }|*5 + {5:-- User defined completion (^U^N^P) The only match} | ]]) feed('<C-y>') screen:expect([[ August^ | - {0:~ }|*6 - {3:-- INSERT --} | + {1:~ }|*6 + {5:-- INSERT --} | ]]) expect('August') end) @@ -414,45 +405,45 @@ describe('completion', function() screen:expect([[ | Ja^ | - {1:January }{0: }| - {0:~ }|*4 - {3:-- User defined completion (^U^N^P) }{5:Back at original} | + {4:January }{1: }| + {1:~ }|*4 + {5:-- User defined completion (^U^N^P) }{19:Back at original} | ]]) feed('<BS>') screen:expect([[ | J^ | - {1:January }{0: }| - {1:June }{0: }| - {1:July }{0: }| - {0:~ }|*2 - {3:-- User defined completion (^U^N^P) }{5:Back at original} | + {4:January }{1: }| + {4:June }{1: }| + {4:July }{1: }| + {1:~ }|*2 + {5:-- User defined completion (^U^N^P) }{19:Back at original} | ]]) feed('<C-n>') screen:expect([[ | January^ | - {2:January }{0: }| - {1:June }{0: }| - {1:July }{0: }| - {0:~ }|*2 - {3:-- User defined completion (^U^N^P) }{4:match 1 of 3} | + {12:January }{1: }| + {4:June }{1: }| + {4:July }{1: }| + {1:~ }|*2 + {5:-- User defined completion (^U^N^P) }{6:match 1 of 3} | ]]) feed('<C-n>') screen:expect([[ | June^ | - {1:January }{0: }| - {2:June }{0: }| - {1:July }{0: }| - {0:~ }|*2 - {3:-- User defined completion (^U^N^P) }{4:match 2 of 3} | + {4:January }{1: }| + {12:June }{1: }| + {4:July }{1: }| + {1:~ }|*2 + {5:-- User defined completion (^U^N^P) }{6:match 2 of 3} | ]]) feed('<Esc>') screen:expect([[ | Jun^e | - {0:~ }|*5 + {1:~ }|*5 | ]]) feed('.') @@ -460,7 +451,7 @@ describe('completion', function() | June | Jun^e | - {0:~ }|*4 + {1:~ }|*4 | ]]) expect([[ @@ -468,6 +459,67 @@ describe('completion', function() June June]]) end) + + it('Enter does not select original text', function() + feed('iJ<C-x><C-u>') + poke_eventloop() + feed('u') + poke_eventloop() + feed('<CR>') + expect([[ + Ju + ]]) + feed('J<C-x><C-u>') + poke_eventloop() + feed('<CR>') + expect([[ + Ju + J + ]]) + end) + end) + + describe('with noselect but not refresh:always', function() + before_each(function() + source([[ + function! TestCompletion(findstart, base) abort + if a:findstart + let line = getline('.') + let start = col('.') - 1 + while start > 0 && line[start - 1] =~ '\a' + let start -= 1 + endwhile + return start + else + let ret = [] + for m in split("January February March April May June July August September October November December") + if m =~ a:base " match by regex + call add(ret, m) + endif + endfor + return {'words':ret} + endif + endfunction + + set completeopt=menuone,noselect + set completefunc=TestCompletion + ]]) + end) + + it('Enter selects original text after adding leader', function() + feed('iJ<C-x><C-u>') + poke_eventloop() + feed('u') + poke_eventloop() + feed('<CR>') + expect('Ju') + feed('<Esc>') + poke_eventloop() + -- The behavior should be the same when completion has been interrupted, + -- which can happen interactively if the completion function is slow. + feed('SJ<C-x><C-u>u<CR>') + expect('Ju') + end) end) describe('with a lot of items', function() @@ -485,46 +537,46 @@ describe('completion', function() feed('i<C-r>=TestComplete()<CR>') screen:expect([[ ^ | - {1:0 }{6: }{0: }| - {1:1 }{2: }{0: }| - {1:2 }{2: }{0: }| - {1:3 }{2: }{0: }| - {1:4 }{2: }{0: }| - {1:5 }{2: }{0: }| - {3:-- INSERT --} | + {4:0 }{101: }{1: }| + {4:1 }{12: }{1: }| + {4:2 }{12: }{1: }| + {4:3 }{12: }{1: }| + {4:4 }{12: }{1: }| + {4:5 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('7') screen:expect([[ 7^ | - {1:7 }{6: }{0: }| - {1:70 }{6: }{0: }| - {1:71 }{6: }{0: }| - {1:72 }{2: }{0: }| - {1:73 }{2: }{0: }| - {1:74 }{2: }{0: }| - {3:-- INSERT --} | + {4:7 }{101: }{1: }| + {4:70 }{101: }{1: }| + {4:71 }{101: }{1: }| + {4:72 }{12: }{1: }| + {4:73 }{12: }{1: }| + {4:74 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('<c-n>') screen:expect([[ 7^ | - {2:7 }{6: }{0: }| - {1:70 }{6: }{0: }| - {1:71 }{6: }{0: }| - {1:72 }{2: }{0: }| - {1:73 }{2: }{0: }| - {1:74 }{2: }{0: }| - {3:-- INSERT --} | + {12:7 }{101: }{1: }| + {4:70 }{101: }{1: }| + {4:71 }{101: }{1: }| + {4:72 }{12: }{1: }| + {4:73 }{12: }{1: }| + {4:74 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('<c-n>') screen:expect([[ 70^ | - {1:7 }{6: }{0: }| - {2:70 }{6: }{0: }| - {1:71 }{6: }{0: }| - {1:72 }{2: }{0: }| - {1:73 }{2: }{0: }| - {1:74 }{2: }{0: }| - {3:-- INSERT --} | + {4:7 }{101: }{1: }| + {12:70 }{101: }{1: }| + {4:71 }{101: }{1: }| + {4:72 }{12: }{1: }| + {4:73 }{12: }{1: }| + {4:74 }{12: }{1: }| + {5:-- INSERT --} | ]]) end) @@ -532,107 +584,107 @@ describe('completion', function() feed('i<C-r>=TestComplete()<CR>') screen:expect([[ ^ | - {1:0 }{6: }{0: }| - {1:1 }{2: }{0: }| - {1:2 }{2: }{0: }| - {1:3 }{2: }{0: }| - {1:4 }{2: }{0: }| - {1:5 }{2: }{0: }| - {3:-- INSERT --} | + {4:0 }{101: }{1: }| + {4:1 }{12: }{1: }| + {4:2 }{12: }{1: }| + {4:3 }{12: }{1: }| + {4:4 }{12: }{1: }| + {4:5 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('<PageDown>') screen:expect([[ ^ | - {1:0 }{6: }{0: }| - {1:1 }{2: }{0: }| - {1:2 }{2: }{0: }| - {2:3 }{0: }| - {1:4 }{2: }{0: }| - {1:5 }{2: }{0: }| - {3:-- INSERT --} | + {4:0 }{101: }{1: }| + {4:1 }{12: }{1: }| + {4:2 }{12: }{1: }| + {12:3 }{1: }| + {4:4 }{12: }{1: }| + {4:5 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('<PageDown>') screen:expect([[ ^ | - {1:5 }{6: }{0: }| - {1:6 }{2: }{0: }| - {2:7 }{0: }| - {1:8 }{2: }{0: }| - {1:9 }{2: }{0: }| - {1:10 }{2: }{0: }| - {3:-- INSERT --} | + {4:5 }{101: }{1: }| + {4:6 }{12: }{1: }| + {12:7 }{1: }| + {4:8 }{12: }{1: }| + {4:9 }{12: }{1: }| + {4:10 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('<Down>') screen:expect([[ ^ | - {1:5 }{6: }{0: }| - {1:6 }{2: }{0: }| - {1:7 }{2: }{0: }| - {2:8 }{0: }| - {1:9 }{2: }{0: }| - {1:10 }{2: }{0: }| - {3:-- INSERT --} | + {4:5 }{101: }{1: }| + {4:6 }{12: }{1: }| + {4:7 }{12: }{1: }| + {12:8 }{1: }| + {4:9 }{12: }{1: }| + {4:10 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('<PageUp>') screen:expect([[ ^ | - {1:2 }{6: }{0: }| - {1:3 }{2: }{0: }| - {2:4 }{0: }| - {1:5 }{2: }{0: }| - {1:6 }{2: }{0: }| - {1:7 }{2: }{0: }| - {3:-- INSERT --} | + {4:2 }{101: }{1: }| + {4:3 }{12: }{1: }| + {12:4 }{1: }| + {4:5 }{12: }{1: }| + {4:6 }{12: }{1: }| + {4:7 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('<PageUp>') -- stop on first item screen:expect([[ ^ | - {2:0 }{6: }{0: }| - {1:1 }{2: }{0: }| - {1:2 }{2: }{0: }| - {1:3 }{2: }{0: }| - {1:4 }{2: }{0: }| - {1:5 }{2: }{0: }| - {3:-- INSERT --} | + {12:0 }{101: }{1: }| + {4:1 }{12: }{1: }| + {4:2 }{12: }{1: }| + {4:3 }{12: }{1: }| + {4:4 }{12: }{1: }| + {4:5 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('<PageUp>') -- when on first item, unselect screen:expect([[ ^ | - {1:0 }{6: }{0: }| - {1:1 }{2: }{0: }| - {1:2 }{2: }{0: }| - {1:3 }{2: }{0: }| - {1:4 }{2: }{0: }| - {1:5 }{2: }{0: }| - {3:-- INSERT --} | + {4:0 }{101: }{1: }| + {4:1 }{12: }{1: }| + {4:2 }{12: }{1: }| + {4:3 }{12: }{1: }| + {4:4 }{12: }{1: }| + {4:5 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('<PageUp>') -- when unselected, select last item screen:expect([[ ^ | - {1:95 }{2: }{0: }| - {1:96 }{2: }{0: }| - {1:97 }{2: }{0: }| - {1:98 }{2: }{0: }| - {1:99 }{2: }{0: }| - {2:100 }{6: }{0: }| - {3:-- INSERT --} | + {4:95 }{12: }{1: }| + {4:96 }{12: }{1: }| + {4:97 }{12: }{1: }| + {4:98 }{12: }{1: }| + {4:99 }{12: }{1: }| + {12:100 }{101: }{1: }| + {5:-- INSERT --} | ]]) feed('<PageUp>') screen:expect([[ ^ | - {1:94 }{2: }{0: }| - {1:95 }{2: }{0: }| - {2:96 }{0: }| - {1:97 }{2: }{0: }| - {1:98 }{2: }{0: }| - {1:99 }{6: }{0: }| - {3:-- INSERT --} | + {4:94 }{12: }{1: }| + {4:95 }{12: }{1: }| + {12:96 }{1: }| + {4:97 }{12: }{1: }| + {4:98 }{12: }{1: }| + {4:99 }{101: }{1: }| + {5:-- INSERT --} | ]]) feed('<cr>') screen:expect([[ 96^ | - {0:~ }|*6 - {3:-- INSERT --} | + {1:~ }|*6 + {5:-- INSERT --} | ]]) end) end) @@ -668,9 +720,9 @@ describe('completion', function() screen:expect([[ inc uninc indent unindent | ind^ | - {2:indent }{0: }| - {0:~ }|*4 - {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} | + {12:indent }{1: }| + {1:~ }|*4 + {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} | ]]) -- Indents when the item is selected @@ -678,8 +730,8 @@ describe('completion', function() screen:expect([[ inc uninc indent unindent | indent^ | - {0:~ }|*5 - {3:-- INSERT --} | + {1:~ }|*5 + {5:-- INSERT --} | ]]) -- Indents when completion is exited using ESC. feed('<CR>in<C-N><BS>d<Esc>') @@ -687,7 +739,7 @@ describe('completion', function() inc uninc indent unindent | indent | in^d | - {0:~ }|*4 + {1:~ }|*4 | ]]) -- Works for unindenting too. @@ -699,9 +751,9 @@ describe('completion', function() indent | ind | unind^ | - {0:~ }{2: unindent }{0: }| - {0:~ }|*2 - {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} | + {1:~ }{12: unindent }{1: }| + {1:~ }|*2 + {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} | ]]) -- Works when going back and forth. feed('<BS>c') @@ -710,9 +762,9 @@ describe('completion', function() indent | ind | uninc^ | - {0:~ }{2: uninc }{0: }| - {0:~ }|*2 - {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} | + {1:~ }{12: uninc }{1: }| + {1:~ }|*2 + {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} | ]]) feed('<BS>d') screen:expect([[ @@ -720,9 +772,9 @@ describe('completion', function() indent | ind | unind^ | - {0:~ }{2: unindent }{0: }| - {0:~ }|*2 - {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} | + {1:~ }{12: unindent }{1: }| + {1:~ }|*2 + {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} | ]]) feed('<C-N><C-N><C-Y><Esc>') screen:expect([[ @@ -730,7 +782,7 @@ describe('completion', function() indent | ind | uninden^t | - {0:~ }|*3 + {1:~ }|*3 | ]]) end) @@ -741,15 +793,15 @@ describe('completion', function() screen:expect([[ ^foo | bar | - {0:~ }|*5 + {1:~ }|*5 | ]]) feed('A<C-x><C-l>') screen:expect([[ foo^ | bar | - {0:~ }|*5 - {3:-- Whole line completion (^L^N^P) }{7:Pattern not found} | + {1:~ }|*5 + {5:-- Whole line completion (^L^N^P) }{9:Pattern not found} | ]]) eq(-1, eval('foldclosed(1)')) end) @@ -761,10 +813,10 @@ describe('completion', function() screen:expect([[ foobar fooegg | fooegg^ | - {1:foobar }{0: }| - {2:fooegg }{0: }| - {0:~ }|*3 - {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | + {4:foobar }{1: }| + {12:fooegg }{1: }| + {1:~ }|*3 + {5:-- Keyword completion (^N^P) }{6:match 1 of 2} | ]]) assert_alive() @@ -773,10 +825,10 @@ describe('completion', function() grid = [[ foobar fooegg | fooegg^ | - {1:foobar }{0: }| - {2:fooegg }{0: }| - {0:~ }|*3 - {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | + {4:foobar }{1: }| + {12:fooegg }{1: }| + {1:~ }|*3 + {5:-- Keyword completion (^N^P) }{6:match 1 of 2} | ]], unchanged = true, } @@ -786,10 +838,10 @@ describe('completion', function() screen:expect([[ foobar fooegg | foobar^ | - {2:foobar }{0: }| - {1:fooegg }{0: }| - {0:~ }|*3 - {3:-- Keyword completion (^N^P) }{4:match 2 of 2} | + {12:foobar }{1: }| + {4:fooegg }{1: }| + {1:~ }|*3 + {5:-- Keyword completion (^N^P) }{6:match 2 of 2} | ]]) end) @@ -800,7 +852,7 @@ describe('completion', function() screen:expect { grid = [[ | - {0:~ }|*6 + {1:~ }|*6 :lua CURRENT_TESTING_VAR^ | ]], } @@ -813,19 +865,73 @@ describe('completion', function() screen:expect { grid = [[ | - {0:~ }|*5 - {10:CURRENT_TESTING_BAR}{9: CURRENT_TESTING_FOO }| + {1:~ }|*5 + {100:CURRENT_TESTING_BAR}{3: CURRENT_TESTING_FOO }| :lua CURRENT_TESTING_BAR^ | ]], unchanged = true, } end) + it('prefix is not included in completion for cmdline mode', function() + feed(':lua math.a<Tab>') + screen:expect([[ + | + {1:~ }|*5 + {100:abs}{3: acos asin atan atan2 }| + :lua math.abs^ | + ]]) + feed('<Tab>') + screen:expect([[ + | + {1:~ }|*5 + {3:abs }{100:acos}{3: asin atan atan2 }| + :lua math.acos^ | + ]]) + end) + + it('prefix is not included in completion for i_CTRL-X_CTRL-V #19623', function() + feed('ilua math.a<C-X><C-V>') + screen:expect([[ + lua math.abs^ | + {1:~ }{12: abs }{1: }| + {1:~ }{4: acos }{1: }| + {1:~ }{4: asin }{1: }| + {1:~ }{4: atan }{1: }| + {1:~ }{4: atan2 }{1: }| + {1:~ }| + {5:-- Command-line completion (^V^N^P) }{6:match 1 of 5} | + ]]) + feed('<C-V>') + screen:expect([[ + lua math.acos^ | + {1:~ }{4: abs }{1: }| + {1:~ }{12: acos }{1: }| + {1:~ }{4: asin }{1: }| + {1:~ }{4: atan }{1: }| + {1:~ }{4: atan2 }{1: }| + {1:~ }| + {5:-- Command-line completion (^V^N^P) }{6:match 2 of 5} | + ]]) + end) + + it('works when cursor is in the middle of cmdline #29586', function() + feed(':lua math.a(); 1<Left><Left><Left><Left><Left><Tab>') + screen:expect([[ + | + {1:~ }|*5 + {100:abs}{3: acos asin atan atan2 }| + :lua math.abs^(); 1 | + ]]) + end) + it('provides completion from `getcompletion()`', function() eq({ 'vim' }, fn.getcompletion('vi', 'lua')) eq({ 'api' }, fn.getcompletion('vim.ap', 'lua')) eq({ 'tbl_filter' }, fn.getcompletion('vim.tbl_fil', 'lua')) eq({ 'vim' }, fn.getcompletion('print(vi', 'lua')) + eq({ 'abs', 'acos', 'asin', 'atan', 'atan2' }, fn.getcompletion('math.a', 'lua')) + eq({ 'abs', 'acos', 'asin', 'atan', 'atan2' }, fn.getcompletion('lua math.a', 'cmdline')) -- fuzzy completion is not supported, so the result should be the same command('set wildoptions+=fuzzy') eq({ 'vim' }, fn.getcompletion('vi', 'lua')) @@ -841,36 +947,42 @@ describe('completion', function() eq('SpecialKey', fn.getcompletion('set winhighlight=NonText:', 'cmdline')[1]) end) + it('cmdline completion for -complete does not contain spaces', function() + for _, str in ipairs(fn.getcompletion('command -complete=', 'cmdline')) do + ok(not str:find(' '), 'string without spaces', str) + end + end) + describe('from the commandline window', function() it('is cleared after CTRL-C', function() feed('q:') feed('ifoo faa fee f') screen:expect([[ | - {8:[No Name] }| - {0::}foo faa fee f^ | - {0:~ }|*3 - {9:[Command Line] }| - {3:-- INSERT --} | + {2:[No Name] }| + {1::}foo faa fee f^ | + {1:~ }|*3 + {3:[Command Line] }| + {5:-- INSERT --} | ]]) feed('<c-x><c-n>') screen:expect([[ | - {8:[No Name] }| - {0::}foo faa fee foo^ | - {0:~ }{2: foo }{0: }| - {0:~ }{1: faa }{0: }| - {0:~ }{1: fee }{0: }| - {9:[Command Line] }| - {3:-- Keyword Local completion (^N^P) }{4:match 1 of 3} | + {2:[No Name] }| + {1::}foo faa fee foo^ | + {1:~ }{12: foo }{1: }| + {1:~ }{4: faa }{1: }| + {1:~ }{4: fee }{1: }| + {3:[Command Line] }| + {5:-- Keyword Local completion (^N^P) }{6:match 1 of 3} | ]]) feed('<c-c>') screen:expect([[ | - {8:[No Name] }| - {0::}foo faa fee foo | - {0:~ }|*3 - {9:[Command Line] }| + {2:[No Name] }| + {1::}foo faa fee foo | + {1:~ }|*3 + {3:[Command Line] }| :foo faa fee foo^ | ]]) end) @@ -903,9 +1015,9 @@ describe('completion', function() feed('i<C-r>=TestComplete()<CR>') screen:expect([[ ^ | - {1:1 3 2 }{0: }| - {0:~ }|*5 - {3:-- INSERT --} | + {4:1 3 2 }{1: }| + {1:~ }|*5 + {5:-- INSERT --} | ]]) end) end) @@ -918,12 +1030,12 @@ describe('completion', function() grid = [[ *backers.txt* Nvim | Xnull^ | - {2:Xnull }{6: } | - {1:Xoxomoon }{6: } | - {1:Xu }{6: } NVIM REFERENCE MANUAL | - {1:Xpayn }{2: } | - {1:Xinity }{2: } | - {3:-- Keyword Local completion (^N^P) }{4:match 1 of 7} | + {12:Xnull }{101: } | + {4:Xoxomoon }{101: } | + {4:Xu }{101: } NVIM REFERENCE MANUAL | + {4:Xpayn }{12: } | + {4:Xinity }{12: } | + {5:-- Keyword Local completion (^N^P) }{6:match 1 of 7} | ]], } end) @@ -950,8 +1062,8 @@ describe('completion', function() bar | foobar | f^ | - {0:~ }|*3 - {3:-- Keyword completion (^N^P) }{5:Back at original} | + {1:~ }|*3 + {5:-- Keyword completion (^N^P) }{19:Back at original} | ]], popupmenu = { anchor = { 1, 3, 0 }, @@ -970,8 +1082,8 @@ describe('completion', function() bar | foobar | foob^ | - {0:~ }|*3 - {3:-- Keyword completion (^N^P) }{5:Back at original} | + {1:~ }|*3 + {5:-- Keyword completion (^N^P) }{19:Back at original} | ]], popupmenu = { anchor = { 1, 3, 0 }, @@ -992,10 +1104,10 @@ describe('completion', function() bar | foobar | f^ | - {1:foo }{0: }| - {1:foobar }{0: }| - {0:~ }| - {3:-- Keyword completion (^N^P) }{5:Back at original} | + {4:foo }{1: }| + {4:foobar }{1: }| + {1:~ }| + {5:-- Keyword completion (^N^P) }{19:Back at original} | ]]) eq( { completed_item = {}, width = 15, height = 2, size = 2, col = 0, row = 4, scrollbar = false }, @@ -1007,10 +1119,10 @@ describe('completion', function() bar | foobar | foo^ | - {2:foo }{0: }| - {1:foobar }{0: }| - {0:~ }| - {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | + {12:foo }{1: }| + {4:foobar }{1: }| + {1:~ }| + {5:-- Keyword completion (^N^P) }{6:match 1 of 2} | ]]) eq('foo', eval('g:word')) feed('<C-N>') @@ -1019,10 +1131,10 @@ describe('completion', function() bar | foobar | foobar^ | - {1:foo }{0: }| - {2:foobar }{0: }| - {0:~ }| - {3:-- Keyword completion (^N^P) }{4:match 2 of 2} | + {4:foo }{1: }| + {12:foobar }{1: }| + {1:~ }| + {5:-- Keyword completion (^N^P) }{6:match 2 of 2} | ]]) eq('foobar', eval('g:word')) feed('<up>') @@ -1031,10 +1143,10 @@ describe('completion', function() bar | foobar | foobar^ | - {2:foo }{0: }| - {1:foobar }{0: }| - {0:~ }| - {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | + {12:foo }{1: }| + {4:foobar }{1: }| + {1:~ }| + {5:-- Keyword completion (^N^P) }{6:match 1 of 2} | ]]) eq('foo', eval('g:word')) feed('<down>') @@ -1043,10 +1155,10 @@ describe('completion', function() bar | foobar | foobar^ | - {1:foo }{0: }| - {2:foobar }{0: }| - {0:~ }| - {3:-- Keyword completion (^N^P) }{4:match 2 of 2} | + {4:foo }{1: }| + {12:foobar }{1: }| + {1:~ }| + {5:-- Keyword completion (^N^P) }{6:match 2 of 2} | ]]) eq('foobar', eval('g:word')) feed('<esc>') @@ -1061,11 +1173,11 @@ describe('completion', function() hullo | heeee | hello^ | - {2:hello }{0: }| - {1:hullo }{0: }| - {1:heeee }{0: }| - {0:~ }|*6 - {3:-- }{4:match 1 of 3} | + {12:hello }{1: }| + {4:hullo }{1: }| + {4:heeee }{1: }| + {1:~ }|*6 + {5:-- }{6:match 1 of 3} | ]]) command([[call timer_start(100, { -> execute('stopinsert') })]]) vim.uv.sleep(200) @@ -1075,7 +1187,7 @@ describe('completion', function() hullo | heee^e | hello | - {0:~ }|*9 + {1:~ }|*9 | ]]) end) @@ -1090,9 +1202,9 @@ describe('completion', function() screen:expect([[ ii | ii^ | - {2:ii }{0: }| - {0:~ }|*4 - {3:-- Keyword completion (^N^P) The only match} | + {12:ii }{1: }| + {1:~ }|*4 + {5:-- Keyword completion (^N^P) The only match} | ]]) assert_alive() end) @@ -1129,22 +1241,22 @@ describe('completion', function() screen:expect { grid = [[ foo^ | - {2:foo }{0: }| - {1:bar }{0: }| - {1:foa }{0: }| - {1:.hidden }{0: }| - {0:~ }|*3 - {3:-- }{4:match 1 of 4} | + {12:foo }{1: }| + {4:bar }{1: }| + {4:foa }{1: }| + {4:.hidden }{1: }| + {1:~ }|*3 + {5:-- }{6:match 1 of 4} | ]], } feed('<Esc>ccf<C-n>') screen:expect { grid = [[ foo^ | - {2:foo }{0: }| - {1:foa }{0: }| - {0:~ }|*5 - {3:-- }{4:match 1 of 2} | + {12:foo }{1: }| + {4:foa }{1: }| + {1:~ }|*5 + {5:-- }{6:match 1 of 2} | ]], } end) @@ -1168,10 +1280,10 @@ describe('completion', function() eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })")) feed('<Esc>0Yppia<Esc>ggI<C-N>') screen:expect([[ - aaaa{7:^aa}aa | - {2:aaaa } | - {1:aaaaa } | - {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | + aaaa{9:^aa}aa | + {12:aaaa } | + {4:aaaaa } | + {5:-- Keyword completion (^N^P) }{6:match 1 of 2} | ]]) feed('<C-N><C-N><Esc>') eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })")) @@ -1180,16 +1292,16 @@ describe('completion', function() feed('<C-N>') screen:expect([[ aaaaa^ | - {1:aaaa } | - {2:aaaaa } | - {3:-- Keyword completion (^N^P) }{4:match 2 of 2} | + {4:aaaa } | + {12:aaaaa } | + {5:-- Keyword completion (^N^P) }{6:match 2 of 2} | ]]) feed('<C-E>') screen:expect([[ - {7:aa}aa^ | + {9:aa}aa^ | aaaa | aaaaa | - {3:-- INSERT --} | + {5:-- INSERT --} | ]]) end) end) diff --git a/test/functional/editor/defaults_spec.lua b/test/functional/editor/defaults_spec.lua new file mode 100644 index 0000000000..47fd177f7b --- /dev/null +++ b/test/functional/editor/defaults_spec.lua @@ -0,0 +1,100 @@ +-- +-- Tests for default autocmds, mappings, commands, and menus. +-- +-- See options/defaults_spec.lua for default options and environment decisions. +-- + +local t = require('test.testutil') +local n = require('test.functional.testnvim')() +local Screen = require('test.functional.ui.screen') + +describe('default', function() + describe('autocommands', function() + it('nvim_terminal.TermClose closes terminal with default shell on success', function() + n.clear() + n.api.nvim_set_option_value('shell', n.testprg('shell-test'), {}) + n.command('set shellcmdflag=EXIT shellredir= shellpipe= shellquote= shellxquote=') + + -- Should not block other events + n.command('let g:n=0') + n.command('au BufEnter * let g:n = g:n + 1') + + n.command('terminal') + t.eq(1, n.eval('get(g:, "n", 0)')) + + t.retry(nil, 1000, function() + t.neq('terminal', n.api.nvim_get_option_value('buftype', { buf = 0 })) + t.eq(2, n.eval('get(g:, "n", 0)')) + end) + end) + end) + + describe('popupmenu', function() + it('can be disabled by user', function() + n.clear { + args = { '+autocmd! nvim_popupmenu', '+aunmenu PopUp' }, + } + local screen = Screen.new(40, 8) + screen:attach() + n.insert([[ + 1 line 1 + 2 https://example.com + 3 line 3 + 4 line 4]]) + + n.api.nvim_input_mouse('right', 'press', '', 0, 1, 4) + screen:expect({ + grid = [[ + 1 line 1 | + 2 ht^tps://example.com | + 3 line 3 | + 4 line 4 | + {1:~ }|*3 + | + ]], + }) + end) + + it('right-click on URL shows "Open in web browser"', function() + n.clear() + local screen = Screen.new(40, 8) + screen:attach() + n.insert([[ + 1 line 1 + 2 https://example.com + 3 line 3 + 4 line 4]]) + + n.api.nvim_input_mouse('right', 'press', '', 0, 3, 4) + screen:expect({ + grid = [[ + 1 line 1 | + 2 https://example.com | + 3 line 3 | + 4 li^ne 4 | + {1:~ }{4: Inspect }{1: }| + {1:~ }{4: }{1: }| + {1:~ }{4: Paste }{1: }| + {4: Select All } | + ]], + }) + + n.api.nvim_input_mouse('right', 'press', '', 0, 1, 4) + screen:expect({ + grid = [[ + 1 line 1 | + 2 ht^tps://example.com | + 3 l{4: Open in web browser } | + 4 l{4: Inspect } | + {1:~ }{4: }{1: }| + {1:~ }{4: Paste }{1: }| + {1:~ }{4: Select All }{1: }| + {4: } | + ]], + }) + end) + end) + + -- describe('key mappings', function() + -- end) +end) diff --git a/test/functional/editor/jump_spec.lua b/test/functional/editor/jump_spec.lua index 880831d9f8..ab4cefaf84 100644 --- a/test/functional/editor/jump_spec.lua +++ b/test/functional/editor/jump_spec.lua @@ -194,7 +194,7 @@ describe("jumpoptions=stack behaves like 'tagstack'", function() end) end) -describe('buffer deletion', function() +describe('buffer deletion with jumpoptions+=clean', function() local base_file = 'Xtest-functional-buffer-deletion' local file1 = base_file .. '1' local file2 = base_file .. '2' @@ -227,6 +227,12 @@ describe('buffer deletion', function() command('edit ' .. file3) end) + after_each(function() + os.remove(file1) + os.remove(file2) + os.remove(file3) + end) + it('deletes jump list entries when the current buffer is deleted', function() command('edit ' .. file1) @@ -319,6 +325,44 @@ describe('buffer deletion', function() end) end) +describe('buffer deletion with jumpoptions-=clean', function() + local base_file = 'Xtest-functional-buffer-deletion' + local file1 = base_file .. '1' + local file2 = base_file .. '2' + local base_content = 'text' + local content1 = base_content .. '1' + local content2 = base_content .. '2' + + before_each(function() + clear() + command('clearjumps') + command('set jumpoptions-=clean') + + write_file(file1, content1, false, false) + write_file(file2, content2, false, false) + + command('edit ' .. file1) + command('edit ' .. file2) + end) + + after_each(function() + os.remove(file1) + os.remove(file2) + end) + + it('Ctrl-O reopens previous buffer with :bunload or :bdelete #28968', function() + eq(file2, fn.bufname('')) + command('bunload') + eq(file1, fn.bufname('')) + feed('<C-O>') + eq(file2, fn.bufname('')) + command('bdelete') + eq(file1, fn.bufname('')) + feed('<C-O>') + eq(file2, fn.bufname('')) + end) +end) + describe('jumpoptions=view', function() local file1 = 'Xtestfile-functional-editor-jumps' local file2 = 'Xtestfile-functional-editor-jumps-2' diff --git a/test/functional/editor/macro_spec.lua b/test/functional/editor/macro_spec.lua index 27c5eddac8..680a70b78a 100644 --- a/test/functional/editor/macro_spec.lua +++ b/test/functional/editor/macro_spec.lua @@ -148,6 +148,23 @@ helloFOO]] eq({ 0, 1, 1, 0 }, fn.getpos('v')) end) + it('can be recorded and replayed in Visual mode when ignorecase', function() + command('set ignorecase') + insert('foo BAR BAR foo BAR foo BAR BAR BAR foo BAR BAR') + feed('0vqifofRq') + eq({ 0, 1, 7, 0 }, fn.getpos('.')) + eq({ 0, 1, 1, 0 }, fn.getpos('v')) + feed('Q') + eq({ 0, 1, 19, 0 }, fn.getpos('.')) + eq({ 0, 1, 1, 0 }, fn.getpos('v')) + feed('Q') + eq({ 0, 1, 27, 0 }, fn.getpos('.')) + eq({ 0, 1, 1, 0 }, fn.getpos('v')) + feed('@i') + eq({ 0, 1, 43, 0 }, fn.getpos('.')) + eq({ 0, 1, 1, 0 }, fn.getpos('v')) + end) + it('can be replayed with @ in blockwise Visual mode', function() insert [[ hello diff --git a/test/functional/editor/meta_key_spec.lua b/test/functional/editor/meta_key_spec.lua index 87fe395608..30027e2fd6 100644 --- a/test/functional/editor/meta_key_spec.lua +++ b/test/functional/editor/meta_key_spec.lua @@ -145,7 +145,8 @@ describe('meta-keys #8226 #13042', function() end) it('ALT/META with vim.on_key()', function() - feed('ifoo<CR>bar<CR>baz<Esc>gg0') + feed('ifoo<CR>bar<CR>baz<Esc>gg0viw"ay') + command('nnoremap … "') exec_lua [[ keys = {} @@ -157,15 +158,15 @@ describe('meta-keys #8226 #13042', function() end) ]] - -- <M-"> is reinterpreted as <Esc>" - feed('qrviw"ayc$FOO.<M-">apq') + -- <M-"> and <M-…> are reinterpreted as <Esc>" and <Esc>… + feed('c$FOO.<M-">apA.<M-…>ap') expect([[ - FOO.foo + FOO.foo.foo bar baz]]) - -- vim.on_key() callback should only receive <Esc>" - eq('qrviw"ayc$FOO.<Esc>"apq', exec_lua [[return table.concat(keys, '')]]) - eq('qrviw"ayc$FOO.<Esc>"apq', exec_lua [[return table.concat(typed, '')]]) + -- vim.on_key() callback should only receive <Esc>" and <Esc>… + eq('c$FOO.<Esc>"apA.<Esc>"ap', exec_lua [[return table.concat(keys, '')]]) + eq('c$FOO.<Esc>"apA.<Esc>…ap', exec_lua [[return table.concat(typed, '')]]) end) end) diff --git a/test/functional/editor/mode_cmdline_spec.lua b/test/functional/editor/mode_cmdline_spec.lua index 70bdc5d4c2..efd7a37c0b 100644 --- a/test/functional/editor/mode_cmdline_spec.lua +++ b/test/functional/editor/mode_cmdline_spec.lua @@ -48,18 +48,14 @@ describe('cmdline', function() it('redraws statusline when toggling overstrike', function() local screen = Screen.new(60, 4) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { reverse = true, bold = true }, -- StatusLine - }) screen:attach() command('set laststatus=2 statusline=%!mode(1)') feed(':') screen:expect { grid = [[ | - {0:~ }| - {1:c }| + {1:~ }| + {3:c }| :^ | ]], } @@ -67,8 +63,8 @@ describe('cmdline', function() screen:expect { grid = [[ | - {0:~ }| - {1:cr }| + {1:~ }| + {3:cr }| :^ | ]], } diff --git a/test/functional/editor/mode_insert_spec.lua b/test/functional/editor/mode_insert_spec.lua index fb3dda4bf4..87d5c46134 100644 --- a/test/functional/editor/mode_insert_spec.lua +++ b/test/functional/editor/mode_insert_spec.lua @@ -180,12 +180,6 @@ describe('insert-mode', function() it('multi-char mapping updates screen properly #25626', function() local screen = Screen.new(60, 6) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { bold = true, reverse = true }, -- StatusLine - [2] = { reverse = true }, -- StatusLineNC - [3] = { bold = true }, -- ModeMsg - }) screen:attach() command('vnew') insert('foo\nfoo\nfoo') @@ -197,10 +191,10 @@ describe('insert-mode', function() grid = [[ foo │ | foo │β^jβ | - foo │{0:~ }| - {0:~ }│{0:~ }| - {2:[No Name] [+] }{1:[No Name] [+] }| - {3:-- INSERT --} | + foo │{1:~ }| + {1:~ }│{1:~ }| + {2:[No Name] [+] }{3:[No Name] [+] }| + {5:-- INSERT --} | ]], } feed('k') @@ -208,9 +202,9 @@ describe('insert-mode', function() grid = [[ foo │ | foo │^βββ | - foo │{0:~ }| - {0:~ }│{0:~ }| - {2:[No Name] [+] }{1:[No Name] [+] }| + foo │{1:~ }| + {1:~ }│{1:~ }| + {2:[No Name] [+] }{3:[No Name] [+] }| | ]], } @@ -357,4 +351,97 @@ describe('insert-mode', function() eq(2, api.nvim_win_get_cursor(0)[1]) end) end) + + it('backspace after replacing multibyte chars', function() + local screen = Screen.new(30, 3) + screen:attach() + api.nvim_buf_set_lines(0, 0, -1, true, { 'test ȧ̟̜̚ÌÌ…m̆̉ÌÌ̇̈ Ã¥' }) + feed('^Rabcdefghi') + screen:expect([[ + abcdefghi^ | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('<bs>') + screen:expect([[ + abcdefgh^Ã¥ | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('<bs>') + screen:expect([[ + abcdefg^ Ã¥ | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('<bs>') + screen:expect([[ + abcdef^m̆̉ÌÌ̇̈ Ã¥ | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('<bs>') + screen:expect([[ + abcde^ȧ̟̜̚ÌÌ…m̆̉ÌÌ̇̈ Ã¥ | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('<bs>') + screen:expect([[ + abcd^ ȧ̟̜̚ÌÌ…m̆̉ÌÌ̇̈ Ã¥ | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('<esc>') + + api.nvim_buf_set_lines(0, 0, -1, true, { 'wow 🧑â€ðŸŒ¾ðŸ³ï¸â€âš§ï¸x' }) + feed('^Rabcd') + + screen:expect([[ + abcd^🧑â€ðŸŒ¾ðŸ³ï¸â€âš§ï¸x | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('e') + screen:expect([[ + abcde^ðŸ³ï¸â€âš§ï¸x | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('f') + screen:expect([[ + abcdef^x | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('<bs>') + screen:expect([[ + abcde^ðŸ³ï¸â€âš§ï¸x | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('<bs>') + screen:expect([[ + abcd^🧑â€ðŸŒ¾ðŸ³ï¸â€âš§ï¸x | + {1:~ }| + {5:-- REPLACE --} | + ]]) + + feed('<bs>') + screen:expect([[ + abc^ 🧑â€ðŸŒ¾ðŸ³ï¸â€âš§ï¸x | + {1:~ }| + {5:-- REPLACE --} | + ]]) + end) end) diff --git a/test/functional/editor/tabpage_spec.lua b/test/functional/editor/tabpage_spec.lua index 0b26494436..c20a6e5cb5 100644 --- a/test/functional/editor/tabpage_spec.lua +++ b/test/functional/editor/tabpage_spec.lua @@ -102,14 +102,9 @@ describe('tabpage', function() it('switching tabpage after setting laststatus=3 #19591', function() local screen = Screen.new(40, 8) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { bold = true, reverse = true }, -- StatusLine - [2] = { reverse = true }, -- TabLineFill - [3] = { bold = true }, -- TabLineSel - [4] = { background = Screen.colors.LightGrey, underline = true }, -- TabLine - [5] = { bold = true, foreground = Screen.colors.Magenta }, - }) + screen:add_extra_attr_ids { + [100] = { bold = true, foreground = Screen.colors.Fuchsia }, + } screen:attach() command('tabnew') @@ -118,18 +113,18 @@ describe('tabpage', function() command('tabnext') feed('<C-G>') screen:expect([[ - {4: [No Name] }{3: [No Name] }{2: }{4:X}| + {24: [No Name] }{5: [No Name] }{2: }{24:X}| ^ | - {0:~ }|*4 - {1:[No Name] }| + {1:~ }|*4 + {3:[No Name] }| "[No Name]" --No lines in buffer-- | ]]) command('vnew') screen:expect([[ - {4: [No Name] }{3: }{5:2}{3: [No Name] }{2: }{4:X}| + {24: [No Name] }{5: }{100:2}{5: [No Name] }{2: }{24:X}| ^ │ | - {0:~ }│{0:~ }|*4 - {1:[No Name] }| + {1:~ }│{1:~ }|*4 + {3:[No Name] }| "[No Name]" --No lines in buffer-- | ]]) end) diff --git a/test/functional/ex_cmds/append_spec.lua b/test/functional/ex_cmds/append_spec.lua index 80fdcb3134..df62aecc7f 100644 --- a/test/functional/ex_cmds/append_spec.lua +++ b/test/functional/ex_cmds/append_spec.lua @@ -23,7 +23,7 @@ local cmdtest = function(cmd, prep, ret1) end it(cmd .. 's' .. prep .. ' the current line by default', function() - command(cmd .. '\nabc\ndef\n') + command(cmd .. '\nabc\ndef') eq(ret1, buffer_contents()) end) -- Used to crash because this invokes history processing which uses diff --git a/test/functional/ex_cmds/excmd_spec.lua b/test/functional/ex_cmds/excmd_spec.lua index 20ebb2dedb..923bb99eeb 100644 --- a/test/functional/ex_cmds/excmd_spec.lua +++ b/test/functional/ex_cmds/excmd_spec.lua @@ -29,13 +29,13 @@ describe('Ex cmds', function() ':tabnext 9999999999999999999999999999999999999999', 'Vim(tabnext):E475: Invalid argument: 9999999999999999999999999999999999999999' ) - check_excmd_err( - ':N 9999999999999999999999999999999999999999', - 'Vim(Next):E939: Positive count required' + eq( + 'Vim(Next):E163: There is only one file to edit', + pcall_err(command, ':N 9999999999999999999999999999999999999999') ) check_excmd_err( ':bdelete 9999999999999999999999999999999999999999', - 'Vim(bdelete):E939: Positive count required' + 'Vim(bdelete):E516: No buffers were deleted' ) eq( 'Vim(menu):E329: No menu "9999999999999999999999999999999999999999"', diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua index 9b24854362..8f09e802eb 100644 --- a/test/functional/ex_cmds/mksession_spec.lua +++ b/test/functional/ex_cmds/mksession_spec.lua @@ -170,7 +170,7 @@ describe(':mksession', function() skip(is_os('win'), 'causes rmdir() to fail') local cwd_dir = fn.fnamemodify('.', ':p:~'):gsub([[[\/]*$]], '') - cwd_dir = cwd_dir:gsub([[\]], '/') -- :mksession always uses unix slashes. + cwd_dir = t.fix_slashes(cwd_dir) -- :mksession always uses unix slashes. local session_path = cwd_dir .. '/' .. session_file command('cd ' .. tab_dir) diff --git a/test/functional/ex_cmds/profile_spec.lua b/test/functional/ex_cmds/profile_spec.lua index 57e5c6b2dc..365583948b 100644 --- a/test/functional/ex_cmds/profile_spec.lua +++ b/test/functional/ex_cmds/profile_spec.lua @@ -6,17 +6,11 @@ require('os') local eval = n.eval local command = n.command local eq, neq = t.eq, t.neq -local tempfile = t.tmpname() +local tempfile = t.tmpname(false) local source = n.source local matches = t.matches local read_file = t.read_file --- tmpname() also creates the file on POSIX systems. Remove it again. --- We just need the name, ignoring any race conditions. -if uv.fs_stat(tempfile).uid then - os.remove(tempfile) -end - local function assert_file_exists(filepath) neq(nil, uv.fs_stat(filepath).uid) end @@ -31,6 +25,7 @@ describe(':profile', function() after_each(function() n.expect_exit(command, 'qall!') if uv.fs_stat(tempfile).uid ~= nil then + -- Delete the tempfile. We just need the name, ignoring any race conditions. os.remove(tempfile) end end) diff --git a/test/functional/ex_cmds/quickfix_commands_spec.lua b/test/functional/ex_cmds/quickfix_commands_spec.lua index 3df41b015e..9c47b1f05f 100644 --- a/test/functional/ex_cmds/quickfix_commands_spec.lua +++ b/test/functional/ex_cmds/quickfix_commands_spec.lua @@ -185,6 +185,9 @@ describe('quickfix', function() it('BufAdd does not cause E16 when reusing quickfix buffer #18135', function() local file = file_base .. '_reuse_qfbuf_BufAdd' write_file(file, ('\n'):rep(100) .. 'foo') + finally(function() + os.remove(file) + end) source([[ set grepprg=internal autocmd BufAdd * call and(0, 0) @@ -192,7 +195,24 @@ describe('quickfix', function() ]]) command('grep foo ' .. file) command('grep foo ' .. file) - os.remove(file) + end) + + it('jump message does not scroll with cmdheight=0 and shm+=O #29597', function() + local screen = Screen.new(40, 6) + screen:attach() + command('set cmdheight=0') + local file = file_base .. '_reuse_qfbuf_BufAdd' + write_file(file, 'foobar') + finally(function() + os.remove(file) + end) + command('vimgrep /foo/gj ' .. file) + feed(':cc<CR>') + screen:expect([[ + ^foobar | + {1:~ }|*4 + (1 of 1): foobar | + ]]) end) end) diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua index f806869b40..f813927f77 100644 --- a/test/functional/fixtures/fake-lsp-server.lua +++ b/test/functional/fixtures/fake-lsp-server.lua @@ -939,6 +939,48 @@ function tests.basic_formatting() } end +function tests.range_formatting() + skeleton { + on_init = function() + return { + capabilities = { + documentFormattingProvider = true, + documentRangeFormattingProvider = true, + }, + } + end, + body = function() + notify('start') + expect_request('textDocument/rangeFormatting', function() + return nil, {} + end) + notify('shutdown') + end, + } +end + +function tests.ranges_formatting() + skeleton { + on_init = function() + return { + capabilities = { + documentFormattingProvider = true, + documentRangeFormattingProvider = { + rangesSupport = true, + }, + }, + } + end, + body = function() + notify('start') + expect_request('textDocument/rangesFormatting', function() + return nil, {} + end) + notify('shutdown') + end, + } +end + function tests.set_defaults_all_capabilities() skeleton { on_init = function(_) diff --git a/test/functional/legacy/crash_spec.lua b/test/functional/legacy/crash_spec.lua index 04f77c7d4f..b63b3146f4 100644 --- a/test/functional/legacy/crash_spec.lua +++ b/test/functional/legacy/crash_spec.lua @@ -1,9 +1,14 @@ +local t = require('test.testutil') local n = require('test.functional.testnvim')() local assert_alive = n.assert_alive local clear = n.clear local command = n.command +local eq = t.eq +local eval = n.eval +local exec = n.exec local feed = n.feed +local pcall_err = t.pcall_err before_each(clear) @@ -32,3 +37,29 @@ it('no crash with very long option error message', function() pcall(command, 'source test/old/testdir/crash/poc_did_set_langmap') assert_alive() end) + +it('no crash when closing window with tag in loclist', function() + exec([[ + new + lexpr ['foo'] + lopen + let g:qf_bufnr = bufnr() + lclose + call settagstack(1, #{items: [#{tagname: 'foo', from: [g:qf_bufnr, 1, 1, 0]}]}) + ]]) + eq(1, eval('bufexists(g:qf_bufnr)')) + command('1close') + eq(0, eval('bufexists(g:qf_bufnr)')) + assert_alive() +end) + +it('no crash when writing "Untitled" file fails', function() + t.mkdir('Untitled') + finally(function() + vim.uv.fs_rmdir('Untitled') + end) + feed('ifoobar') + command('set bufhidden=unload') + eq('Vim(enew):E502: "Untitled" is a directory', pcall_err(command, 'confirm enew')) + assert_alive() +end) diff --git a/test/functional/legacy/edit_spec.lua b/test/functional/legacy/edit_spec.lua index f3d18a2541..2d98188f9b 100644 --- a/test/functional/legacy/edit_spec.lua +++ b/test/functional/legacy/edit_spec.lua @@ -44,6 +44,12 @@ describe('edit', function() {1:~ }|*4 =^ | ]]) + feed([['r'<CR><Esc>]]) + expect('r') + -- Test for inserting null and empty list + feed('a<C-R>=v:_null_list<CR><Esc>') + feed('a<C-R>=[]<CR><Esc>') + expect('r') end) -- oldtest: Test_edit_ctrl_r_failed() diff --git a/test/functional/legacy/ex_mode_spec.lua b/test/functional/legacy/ex_mode_spec.lua index 574c3e4069..e033898d7a 100644 --- a/test/functional/legacy/ex_mode_spec.lua +++ b/test/functional/legacy/ex_mode_spec.lua @@ -48,7 +48,7 @@ describe('Ex mode', function() command('set noincsearch nohlsearch inccommand=') local screen = Screen.new(60, 6) screen:attach() - command([[call setline(1, ['foo foo', 'foo foo', 'foo foo'])]]) + command([[call setline(1, repeat(['foo foo'], 4))]]) command([[set number]]) feed('gQ') screen:expect([[ @@ -110,12 +110,24 @@ describe('Ex mode', function() :^ | ]]) + -- The printed line should overwrite the colon + feed('<CR>') + screen:expect([[ + {8: 2 }foo foo | + ^^^q | + {8: 2 }foo foo | + {8: 3 }foo foo | + {8: 4 }foo foo | + :^ | + ]]) + feed(':vi<CR>') screen:expect([[ {8: 1 }foo bar | {8: 2 }foo foo | - {8: 3 }^foo foo | - {1:~ }|*2 + {8: 3 }foo foo | + {8: 4 }^foo foo | + {1:~ }| | ]]) end) diff --git a/test/functional/legacy/excmd_spec.lua b/test/functional/legacy/excmd_spec.lua index de3d498f27..753a45ee05 100644 --- a/test/functional/legacy/excmd_spec.lua +++ b/test/functional/legacy/excmd_spec.lua @@ -5,45 +5,14 @@ local Screen = require('test.functional.ui.screen') local clear = n.clear local command = n.command local exec = n.exec -local exec_lua = n.exec_lua local expect_exit = n.expect_exit local feed = n.feed local fn = n.fn -local api = n.api local read_file = t.read_file -local source = n.source local eq = t.eq local write_file = t.write_file local is_os = t.is_os -local function sizeoflong() - if not exec_lua('return pcall(require, "ffi")') then - pending('missing LuaJIT FFI') - end - return exec_lua('return require("ffi").sizeof(require("ffi").typeof("long"))') -end - -describe('Ex command', function() - before_each(clear) - after_each(function() - eq({}, api.nvim_get_vvar('errors')) - end) - - it('checks for address line overflow', function() - if sizeoflong() < 8 then - pending('Skipped: only works with 64 bit long ints') - end - - source [[ - new - call setline(1, 'text') - call assert_fails('|.44444444444444444444444', 'E1247:') - call assert_fails('|.9223372036854775806', 'E1247:') - bwipe! - ]] - end) -end) - describe(':confirm command dialog', function() local screen diff --git a/test/functional/legacy/matchparen_spec.lua b/test/functional/legacy/matchparen_spec.lua index 3841761515..df0d80f0ab 100644 --- a/test/functional/legacy/matchparen_spec.lua +++ b/test/functional/legacy/matchparen_spec.lua @@ -120,8 +120,7 @@ describe('matchparen', function() ]]) feed('i<C-X><C-N><C-N>') - screen:expect { - grid = [[ + screen:expect([[ aa | aaa | aaaa | @@ -131,7 +130,79 @@ describe('matchparen', function() {4: aaaa }{1: }| {1:~ }| {5:-- }{6:match 2 of 3} | - ]], - } + ]]) + end) + + -- oldtest: Test_matchparen_mbyte() + it("works with multibyte chars in 'matchpairs'", function() + local screen = Screen.new(30, 10) + screen:set_default_attr_ids({ + [0] = { bold = true, foreground = Screen.colors.Blue }, + [1] = { background = Screen.colors.Cyan }, + [2] = { bold = true }, + }) + screen:attach() + + exec([[ + source $VIMRUNTIME/plugin/matchparen.vim + call setline(1, ['aaaaaaaa(', 'bbbb)cc']) + set matchpairs+=(:) + ]]) + + screen:expect([[ + ^aaaaaaaa( | + bbbb)cc | + {0:~ }|*7 + | + ]]) + feed('$') + screen:expect([[ + aaaaaaaa{1:^(} | + bbbb{1:)}cc | + {0:~ }|*7 + | + ]]) + feed('j') + screen:expect([[ + aaaaaaaa( | + bbbb)c^c | + {0:~ }|*7 + | + ]]) + feed('2h') + screen:expect([[ + aaaaaaaa{1:(} | + bbbb{1:^)}cc | + {0:~ }|*7 + | + ]]) + feed('0') + screen:expect([[ + aaaaaaaa( | + ^bbbb)cc | + {0:~ }|*7 + | + ]]) + feed('kA') + screen:expect([[ + aaaaaaaa{1:(}^ | + bbbb{1:)}cc | + {0:~ }|*7 + {2:-- INSERT --} | + ]]) + feed('<Down>') + screen:expect([[ + aaaaaaaa( | + bbbb)cc^ | + {0:~ }|*7 + {2:-- INSERT --} | + ]]) + feed('<C-W>') + screen:expect([[ + aaaaaaaa{1:(} | + bbbb{1:)}^ | + {0:~ }|*7 + {2:-- INSERT --} | + ]]) end) end) diff --git a/test/functional/legacy/put_spec.lua b/test/functional/legacy/put_spec.lua index 587424da10..8b9b495679 100644 --- a/test/functional/legacy/put_spec.lua +++ b/test/functional/legacy/put_spec.lua @@ -1,52 +1,11 @@ -local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') local clear = n.clear -local exec_lua = n.exec_lua -local api = n.api local source = n.source -local eq = t.eq - -local function sizeoflong() - if not exec_lua('return pcall(require, "ffi")') then - pending('missing LuaJIT FFI') - end - return exec_lua('return require("ffi").sizeof(require("ffi").typeof("long"))') -end describe('put', function() before_each(clear) - after_each(function() - eq({}, api.nvim_get_vvar('errors')) - end) - - it('very large count 64-bit', function() - if sizeoflong() < 8 then - pending('Skipped: only works with 64 bit long ints') - end - - source [[ - new - let @" = repeat('x', 100) - call assert_fails('norm 999999999p', 'E1240:') - bwipe! - ]] - end) - - it('very large count (visual block) 64-bit', function() - if sizeoflong() < 8 then - pending('Skipped: only works with 64 bit long ints') - end - - source [[ - new - call setline(1, repeat('x', 100)) - exe "norm \<C-V>$y" - call assert_fails('norm 999999999p', 'E1240:') - bwipe! - ]] - end) -- oldtest: Test_put_other_window() it('above topline in buffer in two splits', function() diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua index 97578067d5..ec1dc59d53 100644 --- a/test/functional/legacy/scroll_opt_spec.lua +++ b/test/functional/legacy/scroll_opt_spec.lua @@ -375,6 +375,108 @@ describe('smoothscroll', function() screen:expect_unchanged() end) + -- oldtest: Test_smoothscroll_diff_change_line() + it('works in diff mode when changing line', function() + screen:try_resize(55, 20) + exec([[ + set diffopt+=followwrap smoothscroll + call setline(1, repeat(' abc', &columns)) + call setline(2, 'bar') + call setline(3, repeat(' abc', &columns)) + vnew + call setline(1, repeat(' abc', &columns)) + call setline(2, 'foo') + call setline(3, 'bar') + call setline(4, repeat(' abc', &columns)) + windo exe "normal! 2gg5\<C-E>" + windo diffthis + ]]) + + screen:expect([[ + {1:<<<}bc abc abc abc abc abc a│{1:<<<}bc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc │{7: } abc abc abc abc abc | + {7: }{22:foo }│{7: }{23:-------------------------}| + {7: }bar │{7: }^bar | + {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc | + {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc | + {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc │{7: } abc abc abc abc abc | + {1:~ }│{1:~ }|*3 + {2:[No Name] [+] }{3:[No Name] [+] }| + | + ]]) + feed('Abar') + screen:expect([[ + {1:<<<}bc abc abc abc abc abc a│{1:<<<}bc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc │{7: } abc abc abc abc abc | + {7: }{22:foo }│{7: }{23:-------------------------}| + {7: }bar │{7: }barbar^ | + {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc | + {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc | + {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc │{7: } abc abc abc abc abc | + {1:~ }│{1:~ }|*3 + {2:[No Name] [+] }{3:[No Name] [+] }| + {5:-- INSERT --} | + ]]) + feed('<Esc>') + screen:expect([[ + {1:<<<}bc abc abc abc abc abc a│{1:<<<}bc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc │{7: } abc abc abc abc abc | + {7: }{27:foo}{4: }│{7: }{27:barba^r}{4: }| + {7: }{22:bar }│{7: }{23:-------------------------}| + {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc | + {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc | + {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc │{7: } abc abc abc abc abc | + {1:~ }│{1:~ }|*3 + {2:[No Name] [+] }{3:[No Name] [+] }| + | + ]]) + feed('yyp') + screen:expect([[ + {1:<<<}bc abc abc abc abc abc a│{1:<<<}bc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc │{7: } abc abc abc abc abc | + {7: }{27:foo}{4: }│{7: }{27:barbar}{4: }| + {7: }{4:bar }│{7: }{4:^bar}{27:bar}{4: }| + {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc | + {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc | + {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a| + {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab| + {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc| + {7: } abc abc abc abc abc │{7: } abc abc abc abc abc | + {1:~ }│{1:~ }|*3 + {2:[No Name] [+] }{3:[No Name] [+] }| + | + ]]) + end) + -- oldtest: Test_smoothscroll_wrap_scrolloff_zero() it("works with zero 'scrolloff'", function() screen:try_resize(40, 8) @@ -1204,16 +1306,15 @@ describe('smoothscroll', function() set smoothscroll scrolloff=3 call setline(1, ['one', 'two long '->repeat(100), 'three', 'four', 'five', 'six']) ]]) - --FIXME: incorrect screen due to reset_skipcol()/curs_columns() shenanigans feed(':norm j721|<CR>') screen:expect([[ - two long two long two long two long two | + {1:<<<}two long two long two long two long t| + wo long two long two long two long two l| + ong two long two long two long two long | + ^two long two long two long two long two | long two long two long two long two long| two long two long two long two long two| - ^ long two long two long two long two lon| - g two long two long two long two long tw| - o long two long two long two long two lo| - ng two long two long two long two long t| + long two long two long two long two lon| :norm j721| | ]]) feed('gj') @@ -1272,15 +1373,14 @@ describe('smoothscroll', function() :norm j721| | ]]) feed('gk') - --FIXME: incorrect screen due to reset_skipcol()/curs_columns() shenanigans screen:expect([[ + {1:<<<}long two long two long two long two l| + ong two long two long two long two long | two long two long two long two long two | long two long two long two long two long| two long two long two long two long two| long two long two long two long two lon| - g two long two long two long two long tw| - o long two long two long two long two lo| - ^ng two long two long two long two long t| + ^g two long two long | :norm j721| | ]]) end) diff --git a/test/functional/legacy/signs_spec.lua b/test/functional/legacy/signs_spec.lua index 614673ee3c..27145f4c91 100644 --- a/test/functional/legacy/signs_spec.lua +++ b/test/functional/legacy/signs_spec.lua @@ -1,13 +1,14 @@ -- Tests for signs local n = require('test.functional.testnvim')() +local Screen = require('test.functional.ui.screen') -local clear, command, expect = n.clear, n.command, n.expect +local clear, command, exec, expect, feed = n.clear, n.command, n.exec, n.expect, n.feed describe('signs', function() - setup(clear) + before_each(clear) - it('is working', function() + it('are working', function() command('sign define JumpSign text=x') command([[exe 'sign place 42 line=2 name=JumpSign buffer=' . bufnr('')]]) -- Split the window to the bottom to verify :sign-jump will stay in the current @@ -21,4 +22,60 @@ describe('signs', function() 2]]) end) + + -- oldtest: Test_sign_cursor_position() + it('are drawn correctly', function() + local screen = Screen.new(75, 6) + screen:attach() + exec([[ + call setline(1, [repeat('x', 75), 'mmmm', 'yyyy']) + call cursor(2,1) + sign define s1 texthl=Search text==> + sign define s2 linehl=Pmenu + redraw + sign place 10 line=2 name=s1 + ]]) + screen:expect([[ + {7: }xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + {7: }xx | + {10:=>}^mmmm | + {7: }yyyy | + {1:~ }| + | + ]]) + + -- Change the sign text + command('sign define s1 text=-)') + screen:expect([[ + {7: }xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + {7: }xx | + {10:-)}^mmmm | + {7: }yyyy | + {1:~ }| + | + ]]) + + -- Also place a line HL sign + command('sign place 11 line=2 name=s2') + screen:expect([[ + {7: }xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + {7: }xx | + {10:-)}{4:^mmmm }| + {7: }yyyy | + {1:~ }| + | + ]]) + + -- update cursor position calculation + feed('lh') + command('sign unplace 11') + command('sign unplace 10') + screen:expect([[ + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + ^mmmm | + yyyy | + {1:~ }|*2 + | + ]]) + end) end) diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index 56969150bd..741ed0cf6e 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -145,10 +145,10 @@ describe('luaeval(vim.api.…)', function() eq(true, fn.luaeval('vim.api.nvim__id(vim.api.nvim__id)(true)')) eq( 42, - exec_lua [[ - local f = vim.api.nvim__id({42, vim.api.nvim__id}) - return f[2](f[1]) - ]] + exec_lua(function() + local f = vim.api.nvim__id({ 42, vim.api.nvim__id }) + return f[2](f[1]) + end) ) end) @@ -224,42 +224,39 @@ describe('luaeval(vim.api.…)', function() end) it('correctly converts dictionaries with type_idx to API objects', function() - eq( - 4, - eval([[type(luaeval('vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary})'))]]) - ) + eq(4, eval([[type(luaeval('vim.api.nvim__id_dict({[vim.type_idx]=vim.types.dictionary})'))]])) - eq({}, fn.luaeval('vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary})')) + eq({}, fn.luaeval('vim.api.nvim__id_dict({[vim.type_idx]=vim.types.dictionary})')) eq( { v = { 42 } }, fn.luaeval( - 'vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})' + 'vim.api.nvim__id_dict({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})' ) ) eq( { foo = 2 }, fn.luaeval( - 'vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})' + 'vim.api.nvim__id_dict({[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})' ) ) eq( { v = 10 }, fn.luaeval( - 'vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})' + 'vim.api.nvim__id_dict({v={[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})' ) ) eq( { v = {} }, fn.luaeval( - 'vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2}})' + 'vim.api.nvim__id_dict({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2}})' ) ) - -- If API requests dictionary, then empty table will be the one. This is not + -- If API requests dict, then empty table will be the one. This is not -- the case normally because empty table is an empty array. - eq({}, fn.luaeval('vim.api.nvim__id_dictionary({})')) - eq(4, eval([[type(luaeval('vim.api.nvim__id_dictionary({})'))]])) + eq({}, fn.luaeval('vim.api.nvim__id_dict({})')) + eq(4, eval([[type(luaeval('vim.api.nvim__id_dict({})'))]])) end) it('converts booleans in positional args', function() @@ -365,12 +362,12 @@ describe('luaeval(vim.api.…)', function() eq( [[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'dct': Expected Lua table]], - remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_dictionary(1)")]])) + remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_dict(1)")]])) ) eq( [[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'dct': Expected Dict-like Lua table]], remove_trace( - exc_exec([[call luaeval("vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.array})")]]) + exc_exec([[call luaeval("vim.api.nvim__id_dict({[vim.type_idx]=vim.types.array})")]]) ) ) diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index d4af7e4732..f277868b1c 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -27,30 +27,35 @@ local origlines = { before_each(function() clear() - exec_lua [[ - local evname = ... + exec_lua(function() local events = {} - function test_register(bufnr, evname, id, changedtick, utf_sizes, preview) + function _G.test_register(bufnr, evname, id, changedtick, utf_sizes, preview) local function callback(...) - table.insert(events, {id, ...}) - if test_unreg == id then + table.insert(events, { id, ... }) + if _G.test_unreg == id then return true end end - local opts = {[evname]=callback, on_detach=callback, on_reload=callback, utf_sizes=utf_sizes, preview=preview} + local opts = { + [evname] = callback, + on_detach = callback, + on_reload = callback, + utf_sizes = utf_sizes, + preview = preview, + } if changedtick then opts.on_changedtick = callback end vim.api.nvim_buf_attach(bufnr, false, opts) end - function get_events() + function _G.get_events() local ret_events = events events = {} return ret_events end - ]] + end) end) describe('lua buffer event callbacks: on_lines', function() @@ -257,13 +262,13 @@ describe('lua buffer event callbacks: on_lines', function() it('has valid cursor position while shifting', function() api.nvim_buf_set_lines(0, 0, -1, true, { 'line1' }) - exec_lua([[ + exec_lua(function() vim.api.nvim_buf_attach(0, false, { on_lines = function() vim.api.nvim_set_var('listener_cursor_line', vim.api.nvim_win_get_cursor(0)[1]) end, }) - ]]) + end) feed('>>') eq(1, api.nvim_get_var('listener_cursor_line')) end) @@ -277,19 +282,19 @@ describe('lua buffer event callbacks: on_lines', function() end) it('does not SEGFAULT when accessing window buffer info in on_detach #14998', function() - local code = [[ + local code = function() local buf = vim.api.nvim_create_buf(false, false) - vim.cmd"split" + vim.cmd 'split' vim.api.nvim_win_set_buf(0, buf) vim.api.nvim_buf_attach(buf, false, { - on_detach = function(_, buf) + on_detach = function(_, buf0) vim.fn.tabpagebuflist() - vim.fn.win_findbuf(buf) - end + vim.fn.win_findbuf(buf0) + end, }) - ]] + end exec_lua(code) command('q!') @@ -302,13 +307,13 @@ describe('lua buffer event callbacks: on_lines', function() it('#12718 lnume', function() api.nvim_buf_set_lines(0, 0, -1, true, { '1', '2', '3' }) - exec_lua([[ + exec_lua(function() vim.api.nvim_buf_attach(0, false, { on_lines = function(...) vim.api.nvim_set_var('linesev', { ... }) end, }) - ]]) + end) feed('1G0') feed('y<C-v>2j') feed('G0') @@ -326,13 +331,13 @@ describe('lua buffer event callbacks: on_lines', function() end) it('nvim_buf_call() from callback does not cause wrong Normal mode CTRL-A #16729', function() - exec_lua([[ + exec_lua(function() vim.api.nvim_buf_attach(0, false, { - on_lines = function(...) + on_lines = function() vim.api.nvim_buf_call(0, function() end) end, }) - ]]) + end) feed('itest123<Esc><C-A>') eq('test124', api.nvim_get_current_line()) end) @@ -342,19 +347,19 @@ describe('lua buffer event callbacks: on_lines', function() screen:attach() api.nvim_buf_set_lines(0, 0, -1, true, { 'aaa', 'bbb', 'ccc' }) - exec_lua([[ + exec_lua(function() local ns = vim.api.nvim_create_namespace('') vim.api.nvim_buf_attach(0, false, { on_lines = function(_, _, _, row, _, end_row) vim.api.nvim_buf_clear_namespace(0, ns, row, end_row) for i = row, end_row - 1 do - local id = vim.api.nvim_buf_set_extmark(0, ns, i, 0, { - virt_text = {{ 'NEW' .. tostring(i), 'WarningMsg' }}, + vim.api.nvim_buf_set_extmark(0, ns, i, 0, { + virt_text = { { 'NEW' .. tostring(i), 'WarningMsg' } }, }) end end, }) - ]]) + end) feed('o') screen:expect({ @@ -379,6 +384,25 @@ describe('lua buffer event callbacks: on_lines', function() ]], }) end) + + it('line lengths are correct when pressing TAB with folding #29119', function() + api.nvim_buf_set_lines(0, 0, -1, true, { 'a', 'b' }) + + exec_lua(function() + _G.res = {} + vim.o.foldmethod = 'indent' + vim.o.softtabstop = -1 + vim.api.nvim_buf_attach(0, false, { + on_lines = function(_, bufnr, _, row, _, end_row) + local lines = vim.api.nvim_buf_get_lines(bufnr, row, end_row, true) + table.insert(_G.res, lines) + end, + }) + end) + + feed('i<Tab>') + eq({ '\ta' }, exec_lua('return _G.res[#_G.res]')) + end) end) describe('lua: nvim_buf_attach on_bytes', function() diff --git a/test/functional/lua/command_line_completion_spec.lua b/test/functional/lua/command_line_completion_spec.lua index 2ba432133b..f8786a45bb 100644 --- a/test/functional/lua/command_line_completion_spec.lua +++ b/test/functional/lua/command_line_completion_spec.lua @@ -5,12 +5,14 @@ local clear = n.clear local eq = t.eq local exec_lua = n.exec_lua +--- @return { [1]: string[], [2]: integer } local get_completions = function(input, env) - return exec_lua('return {vim._expand_pat(...)}', input, env) + return exec_lua('return { vim._expand_pat(...) }', input, env) end +--- @return { [1]: string[], [2]: integer } local get_compl_parts = function(parts) - return exec_lua('return {vim._expand_pat_get_parts(...)}', parts) + return exec_lua('return { vim._expand_pat_get_parts(...) }', parts) end before_each(clear) @@ -123,6 +125,171 @@ describe('nlua_expand_pat', function() ) end) + describe('should complete vim.fn', function() + it('correctly works for simple completion', function() + local actual = get_completions('vim.fn.did') + local expected = { + { 'did_filetype' }, + #'vim.fn.', + } + eq(expected, actual) + end) + it('should not suggest items with #', function() + exec_lua [[ + -- ensure remote#host#... functions exist + vim.cmd [=[ + runtime! autoload/remote/host.vim + ]=] + -- make a dummy call to ensure vim.fn contains an entry: remote#host#... + vim.fn['remote#host#IsRunning']('python3') + ]] + local actual = get_completions('vim.fn.remo') + local expected = { + { 'remove' }, -- there should be no completion "remote#host#..." + #'vim.fn.', + } + eq(expected, actual) + end) + end) + + describe('should complete for variable accessors for', function() + it('vim.v', function() + local actual = get_completions('vim.v.t_') + local expected = { + { 't_blob', 't_bool', 't_dict', 't_float', 't_func', 't_list', 't_number', 't_string' }, + #'vim.v.', + } + eq(expected, actual) + end) + + it('vim.g', function() + exec_lua [[ + vim.cmd [=[ + let g:nlua_foo = 'completion' + let g:nlua_foo_bar = 'completion' + let g:nlua_foo#bar = 'nocompletion' " should be excluded from lua completion + ]=] + ]] + local actual = get_completions('vim.g.nlua') + local expected = { + { 'nlua_foo', 'nlua_foo_bar' }, + #'vim.g.', + } + eq(expected, actual) + end) + + it('vim.b', function() + exec_lua [[ + vim.b.nlua_foo_buf = 'bar' + vim.b.some_other_vars = 'bar' + ]] + local actual = get_completions('vim.b.nlua') + local expected = { + { 'nlua_foo_buf' }, + #'vim.b.', + } + eq(expected, actual) + end) + + it('vim.w', function() + exec_lua [[ + vim.w.nlua_win_var = 42 + ]] + local actual = get_completions('vim.w.nlua') + local expected = { + { 'nlua_win_var' }, + #'vim.w.', + } + eq(expected, actual) + end) + + it('vim.t', function() + exec_lua [[ + vim.t.nlua_tab_var = 42 + ]] + local actual = get_completions('vim.t.') + local expected = { + { 'nlua_tab_var' }, + #'vim.t.', + } + eq(expected, actual) + end) + end) + + describe('should complete for option accessors for', function() + -- for { vim.o, vim.go, vim.opt, vim.opt_local, vim.opt_global } + local test_opt = function(accessor) + do + local actual = get_completions(accessor .. '.file') + local expected = { + 'fileencoding', + 'fileencodings', + 'fileformat', + 'fileformats', + 'fileignorecase', + 'filetype', + } + eq({ expected, #accessor + 1 }, actual, accessor .. '.file') + end + do + local actual = get_completions(accessor .. '.winh') + local expected = { + 'winheight', + 'winhighlight', + } + eq({ expected, #accessor + 1 }, actual, accessor .. '.winh') + end + end + + test_opt('vim.o') + test_opt('vim.go') + test_opt('vim.opt') + test_opt('vim.opt_local') + test_opt('vim.opt_global') + + it('vim.o, suggesting all the known options', function() + local completions = get_completions('vim.o.')[1] ---@type string[] + eq( + exec_lua [[ + return vim.tbl_count(vim.api.nvim_get_all_options_info()) + ]], + #completions + ) + end) + + it('vim.bo', function() + do + local actual = get_completions('vim.bo.file') + local compls = { + -- should contain buffer options only + 'fileencoding', + 'fileformat', + 'filetype', + } + eq({ compls, #'vim.bo.' }, actual) + end + do + local actual = get_completions('vim.bo.winh') + local compls = {} + eq({ compls, #'vim.bo.' }, actual) + end + end) + + it('vim.wo', function() + do + local actual = get_completions('vim.wo.file') + local compls = {} + eq({ compls, #'vim.wo.' }, actual) + end + do + local actual = get_completions('vim.wo.winh') + -- should contain window options only + local compls = { 'winhighlight' } + eq({ compls, #'vim.wo.' }, actual) + end + end) + end) + it('should return everything if the input is of length 0', function() eq({ { 'other', 'vim' }, 0 }, get_completions('', { vim = true, other = true })) end) diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index 57b084d3d6..456ee13da2 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -178,13 +178,15 @@ describe(':lua', function() eq('hello', exec_capture(':lua = x()')) exec_lua('x = {a = 1, b = 2}') eq('{\n a = 1,\n b = 2\n}', exec_capture(':lua =x')) - exec_lua([[function x(success) - if success then - return true, "Return value" - else - return false, nil, "Error message" + exec_lua(function() + function _G.x(success) + if success then + return true, 'Return value' + else + return false, nil, 'Error message' + end end - end]]) + end) eq( dedent [[ true diff --git a/test/functional/lua/deprecated_spec.lua b/test/functional/lua/deprecated_spec.lua new file mode 100644 index 0000000000..fee34336cc --- /dev/null +++ b/test/functional/lua/deprecated_spec.lua @@ -0,0 +1,22 @@ +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local clear = n.clear +local exec_lua = n.exec_lua +local eq = t.eq + +describe('deprecated lua code', function() + before_each(clear) + + describe('vim.treesitter.get_parser()', function() + it('returns nil for versions >= 0.12', function() + local result = exec_lua(function() + if vim.version.ge(vim.version(), '0.12') then + return vim.treesitter.get_parser(0, 'borklang') + end + return nil + end) + eq(nil, result) + end) + end) +end) diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index 05082bc132..4ae1146703 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -1,7 +1,6 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local NIL = vim.NIL local command = n.command local clear = n.clear local exec_lua = n.exec_lua @@ -15,10 +14,10 @@ describe('vim.diagnostic', function() before_each(function() clear() - exec_lua [[ + exec_lua(function() require('vim.diagnostic') - function make_diagnostic(msg, lnum, col, end_lnum, end_col, severity, source, code) + local function make_diagnostic(msg, lnum, col, end_lnum, end_col, severity, source, code) return { lnum = lnum, col = col, @@ -31,54 +30,97 @@ describe('vim.diagnostic', function() } end - function make_error(msg, lnum, col, end_lnum, end_col, source, code) - return make_diagnostic(msg, lnum, col, end_lnum, end_col, vim.diagnostic.severity.ERROR, source, code) + function _G.make_error(msg, lnum, col, end_lnum, end_col, source, code) + return make_diagnostic( + msg, + lnum, + col, + end_lnum, + end_col, + vim.diagnostic.severity.ERROR, + source, + code + ) end - function make_warning(msg, lnum, col, end_lnum, end_col, source, code) - return make_diagnostic(msg, lnum, col, end_lnum, end_col, vim.diagnostic.severity.WARN, source, code) + function _G.make_warning(msg, lnum, col, end_lnum, end_col, source, code) + return make_diagnostic( + msg, + lnum, + col, + end_lnum, + end_col, + vim.diagnostic.severity.WARN, + source, + code + ) end - function make_info(msg, lnum, col, end_lnum, end_col, source, code) - return make_diagnostic(msg, lnum, col, end_lnum, end_col, vim.diagnostic.severity.INFO, source, code) + function _G.make_info(msg, lnum, col, end_lnum, end_col, source, code) + return make_diagnostic( + msg, + lnum, + col, + end_lnum, + end_col, + vim.diagnostic.severity.INFO, + source, + code + ) end - function make_hint(msg, lnum, col, end_lnum, end_col, source, code) - return make_diagnostic(msg, lnum, col, end_lnum, end_col, vim.diagnostic.severity.HINT, source, code) + function _G.make_hint(msg, lnum, col, end_lnum, end_col, source, code) + return make_diagnostic( + msg, + lnum, + col, + end_lnum, + end_col, + vim.diagnostic.severity.HINT, + source, + code + ) end - function count_diagnostics(bufnr, severity, namespace) - return #vim.diagnostic.get(bufnr, {severity = severity, namespace = namespace}) + function _G.count_diagnostics(bufnr, severity, namespace) + return #vim.diagnostic.get(bufnr, { severity = severity, namespace = namespace }) end - function count_extmarks(bufnr, namespace) + function _G.count_extmarks(bufnr, namespace) local ns = vim.diagnostic.get_namespace(namespace) local extmarks = 0 if ns.user_data.virt_text_ns then - extmarks = extmarks + #vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.virt_text_ns, 0, -1, {}) + extmarks = extmarks + + #vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.virt_text_ns, 0, -1, {}) end if ns.user_data.underline_ns then - extmarks = extmarks + #vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.underline_ns, 0, -1, {}) + extmarks = extmarks + + #vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.underline_ns, 0, -1, {}) end return extmarks end - function get_virt_text_extmarks(ns) - local ns = vim.diagnostic.get_namespace(ns) + function _G.get_virt_text_extmarks(ns) + ns = vim.diagnostic.get_namespace(ns) local virt_text_ns = ns.user_data.virt_text_ns - return vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, virt_text_ns, 0, -1, {details = true}) + return vim.api.nvim_buf_get_extmarks( + _G.diagnostic_bufnr, + virt_text_ns, + 0, + -1, + { details = true } + ) end - ]] - - exec_lua([[ - diagnostic_ns = vim.api.nvim_create_namespace("diagnostic_spec") - other_ns = vim.api.nvim_create_namespace("other_namespace") - diagnostic_bufnr = vim.api.nvim_create_buf(true, false) - local lines = {"1st line of text", "2nd line of text", "wow", "cool", "more", "lines"} - vim.fn.bufload(diagnostic_bufnr) - vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, 1, false, lines) - return diagnostic_bufnr - ]]) + end) + + exec_lua(function() + _G.diagnostic_ns = vim.api.nvim_create_namespace('diagnostic_spec') + _G.other_ns = vim.api.nvim_create_namespace('other_namespace') + _G.diagnostic_bufnr = vim.api.nvim_create_buf(true, false) + local lines = { '1st line of text', '2nd line of text', 'wow', 'cool', 'more', 'lines' } + vim.fn.bufload(_G.diagnostic_bufnr) + vim.api.nvim_buf_set_lines(_G.diagnostic_bufnr, 0, 1, false, lines) + end) end) it('creates highlight groups', function() @@ -115,27 +157,28 @@ describe('vim.diagnostic', function() end) it('retrieves diagnostics from all buffers and namespaces', function() - local result = exec_lua [[ + local result = exec_lua(function() local other_bufnr = vim.api.nvim_create_buf(true, false) - local lines = vim.api.nvim_buf_get_lines(diagnostic_bufnr, 0, -1, true) + local lines = vim.api.nvim_buf_get_lines(_G.diagnostic_bufnr, 0, -1, true) vim.api.nvim_buf_set_lines(other_bufnr, 0, 1, false, lines) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - make_error('Diagnostic #2', 2, 1, 2, 1), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + _G.make_error('Diagnostic #2', 2, 1, 2, 1), }) - vim.diagnostic.set(other_ns, other_bufnr, { - make_error('Diagnostic #3', 3, 1, 3, 1), + vim.diagnostic.set(_G.other_ns, other_bufnr, { + _G.make_error('Diagnostic #3', 3, 1, 3, 1), }) return vim.diagnostic.get() - ]] + end) eq(3, #result) eq( 2, - exec_lua( - [[return #vim.tbl_filter(function(d) return d.bufnr == diagnostic_bufnr end, ...)]], - result - ) + exec_lua(function() + return #vim.tbl_filter(function(d) + return d.bufnr == _G.diagnostic_bufnr + end, result) + end) ) eq('Diagnostic #1', result[1].message) end) @@ -143,155 +186,171 @@ describe('vim.diagnostic', function() it('removes diagnostics from the cache when a buffer is removed', function() eq( 2, - exec_lua [[ - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - local other_bufnr = vim.fn.bufadd('test | test') - local lines = vim.api.nvim_buf_get_lines(diagnostic_bufnr, 0, -1, true) - vim.api.nvim_buf_set_lines(other_bufnr, 0, 1, false, lines) - vim.cmd('bunload! ' .. other_bufnr) - - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - make_error('Diagnostic #2', 2, 1, 2, 1), - }) - vim.diagnostic.set(diagnostic_ns, other_bufnr, { - make_error('Diagnostic #3', 3, 1, 3, 1), - }) - vim.api.nvim_set_current_buf(other_bufnr) - vim.opt_local.buflisted = true - vim.cmd('bwipeout!') - return #vim.diagnostic.get() - ]] + exec_lua(function() + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + local other_bufnr = vim.fn.bufadd('test | test') + local lines = vim.api.nvim_buf_get_lines(_G.diagnostic_bufnr, 0, -1, true) + vim.api.nvim_buf_set_lines(other_bufnr, 0, 1, false, lines) + vim.cmd('bunload! ' .. other_bufnr) + + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + _G.make_error('Diagnostic #2', 2, 1, 2, 1), + }) + vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, { + _G.make_error('Diagnostic #3', 3, 1, 3, 1), + }) + vim.api.nvim_set_current_buf(other_bufnr) + vim.opt_local.buflisted = true + vim.cmd('bwipeout!') + return #vim.diagnostic.get() + end) ) eq( 2, - exec_lua [[ - vim.api.nvim_set_current_buf(diagnostic_bufnr) - vim.opt_local.buflisted = false - return #vim.diagnostic.get() - ]] + exec_lua(function() + vim.api.nvim_set_current_buf(_G.diagnostic_bufnr) + vim.opt_local.buflisted = false + return #vim.diagnostic.get() + end) ) eq( 0, - exec_lua [[ - vim.cmd('bwipeout!') - return #vim.diagnostic.get() - ]] + exec_lua(function() + vim.cmd('bwipeout!') + return #vim.diagnostic.get() + end) ) end) it('removes diagnostic from stale cache on reset', function() - local diagnostics = exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - make_error('Diagnostic #2', 2, 1, 2, 1), + local diagnostics = exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + _G.make_error('Diagnostic #2', 2, 1, 2, 1), }) - local other_bufnr = vim.fn.bufadd('test | test') - vim.cmd('noautocmd bwipeout! ' .. diagnostic_bufnr) - return vim.diagnostic.get(diagnostic_bufnr) - ]] + vim.fn.bufadd('test | test') + vim.cmd('noautocmd bwipeout! ' .. _G.diagnostic_bufnr) + return vim.diagnostic.get(_G.diagnostic_bufnr) + end) eq(2, #diagnostics) - diagnostics = exec_lua [[ + diagnostics = exec_lua(function() vim.diagnostic.reset() return vim.diagnostic.get() - ]] + end) eq(0, #diagnostics) end) it('always returns a copy of diagnostic tables', function() - local result = exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), + local result = exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), }) local diag = vim.diagnostic.get() diag[1].col = 10000 return vim.diagnostic.get()[1].col == 10000 - ]] + end) eq(false, result) end) it('resolves buffer number 0 to the current buffer', function() eq( 2, - exec_lua [[ - vim.api.nvim_set_current_buf(diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - make_error('Diagnostic #2', 2, 1, 2, 1), - }) - return #vim.diagnostic.get(0) - ]] + exec_lua(function() + vim.api.nvim_set_current_buf(_G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + _G.make_error('Diagnostic #2', 2, 1, 2, 1), + }) + return #vim.diagnostic.get(0) + end) ) end) it('saves and count a single error', function() eq( 1, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - }) - return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns) - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + }) + return _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ) + end) ) end) it('saves and count multiple errors', function() eq( 2, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - make_error('Diagnostic #2', 2, 1, 2, 1), - }) - return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns) - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + _G.make_error('Diagnostic #2', 2, 1, 2, 1), + }) + return _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ) + end) ) end) it('saves and count from multiple namespaces', function() eq( { 1, 1, 2 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic From Server 1', 1, 1, 1, 1), - }) - vim.diagnostic.set(other_ns, diagnostic_bufnr, { - make_error('Diagnostic From Server 2', 1, 1, 1, 1), - }) - return { - -- First namespace - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), - -- Second namespace - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, other_ns), - -- All namespaces - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR), - } - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic From Server 1', 1, 1, 1, 1), + }) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic From Server 2', 1, 1, 1, 1), + }) + return { + -- First namespace + _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ), + -- Second namespace + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.other_ns), + -- All namespaces + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR), + } + end) ) end) it('saves and count from multiple namespaces with respect to severity', function() eq( { 3, 0, 3 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), - make_error('Diagnostic From Server 1:2', 2, 2, 2, 2), - make_error('Diagnostic From Server 1:3', 2, 3, 3, 2), - }) - vim.diagnostic.set(other_ns, diagnostic_bufnr, { - make_warning('Warning From Server 2', 3, 3, 3, 3), - }) - return { - -- Namespace 1 - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), - -- Namespace 2 - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, other_ns), - -- All namespaces - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR), - } - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), + _G.make_error('Diagnostic From Server 1:2', 2, 2, 2, 2), + _G.make_error('Diagnostic From Server 1:3', 2, 3, 3, 2), + }) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, { + _G.make_warning('Warning From Server 2', 3, 3, 3, 3), + }) + return { + -- Namespace 1 + _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ), + -- Namespace 2 + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.other_ns), + -- All namespaces + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR), + } + end) ) end) @@ -304,160 +363,190 @@ describe('vim.diagnostic', function() local all_highlights = { 1, 1, 2, 4, 2 } eq( all_highlights, - exec_lua [[ - local ns_1_diags = { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 2, 1, 2, 3), - } - local ns_2_diags = { - make_warning("Warning 1", 2, 1, 2, 3), - } + exec_lua(function() + local ns_1_diags = { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 2, 1, 2, 3), + } + local ns_2_diags = { + _G.make_warning('Warning 1', 2, 1, 2, 3), + } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags) - vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) - return { - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN), - count_extmarks(diagnostic_bufnr, diagnostic_ns), - count_extmarks(diagnostic_bufnr, other_ns), - } - ]] + return { + _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN), + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), + } + end) ) -- Clear diagnostics from namespace 1, and make sure we have the right amount of stuff for namespace 2 eq( { 1, 1, 2, 0, 2 }, - exec_lua [[ - vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) - return { - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN), - count_extmarks(diagnostic_bufnr, diagnostic_ns), - count_extmarks(diagnostic_bufnr, other_ns), - } - ]] + exec_lua(function() + vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) + return { + _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN), + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), + } + end) ) -- Show diagnostics from namespace 1 again eq( all_highlights, - exec_lua([[ - vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) - return { - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN), - count_extmarks(diagnostic_bufnr, diagnostic_ns), - count_extmarks(diagnostic_bufnr, other_ns), - } - ]]) + exec_lua(function() + vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) + return { + _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN), + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), + } + end) ) end) it('does not display diagnostics when disabled', function() eq( { 0, 2 }, - exec_lua [[ - local ns_1_diags = { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 2, 1, 2, 3), - } - local ns_2_diags = { - make_warning("Warning 1", 2, 1, 2, 3), - } + exec_lua(function() + local ns_1_diags = { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 2, 1, 2, 3), + } + local ns_2_diags = { + _G.make_warning('Warning 1', 2, 1, 2, 3), + } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags) - vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) - vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) + vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) - return { - count_extmarks(diagnostic_bufnr, diagnostic_ns), - count_extmarks(diagnostic_bufnr, other_ns), - } - ]] + return { + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), + } + end) ) eq( { 4, 0 }, - exec_lua [[ - vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) - vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = other_ns }) + exec_lua(function() + vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) + vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.other_ns }) - return { - count_extmarks(diagnostic_bufnr, diagnostic_ns), - count_extmarks(diagnostic_bufnr, other_ns), - } - ]] + return { + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), + } + end) ) end) describe('show() and hide()', function() it('works', function() - local result = exec_lua [[ + local result = exec_lua(function() local other_bufnr = vim.api.nvim_create_buf(true, false) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) local result = {} vim.diagnostic.config({ underline = false, virtual_text = true }) local ns_1_diags = { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 2, 1, 2, 5), + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 2, 1, 2, 5), } local ns_2_diags = { - make_warning("Warning 1", 2, 1, 2, 5), + _G.make_warning('Warning 1', 2, 1, 2, 5), } local other_buffer_diags = { - make_info("This is interesting", 0, 0, 0, 0) + _G.make_info('This is interesting', 0, 0, 0, 0), } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags) - vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags) - vim.diagnostic.set(diagnostic_ns, other_bufnr, other_buffer_diags) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) + vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags) -- All buffers and namespaces - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) -- Hide one namespace - vim.diagnostic.hide(diagnostic_ns) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + vim.diagnostic.hide(_G.diagnostic_ns) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) -- Show one namespace - vim.diagnostic.show(diagnostic_ns) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + vim.diagnostic.show(_G.diagnostic_ns) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) -- Hide one buffer vim.diagnostic.hide(nil, other_bufnr) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) -- Hide everything vim.diagnostic.hide() - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) -- Show one buffer - vim.diagnostic.show(nil, diagnostic_bufnr) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + vim.diagnostic.show(nil, _G.diagnostic_bufnr) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) return result - ]] + end) eq(4, result[1]) eq(1, result[2]) @@ -468,13 +557,17 @@ describe('vim.diagnostic', function() end) it("doesn't error after bwipeout on buffer", function() - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {{ lnum = 0, end_lnum = 0, col = 0, end_col = 0 }}) - vim.cmd("bwipeout! " .. diagnostic_bufnr) + exec_lua(function() + vim.diagnostic.set( + _G.diagnostic_ns, + _G.diagnostic_bufnr, + { { lnum = 0, end_lnum = 0, col = 0, end_col = 0 } } + ) + vim.cmd('bwipeout! ' .. _G.diagnostic_bufnr) - vim.diagnostic.show(diagnostic_ns) - vim.diagnostic.hide(diagnostic_ns) - ]] + vim.diagnostic.show(_G.diagnostic_ns) + vim.diagnostic.hide(_G.diagnostic_ns) + end) end) end) @@ -505,52 +598,64 @@ describe('vim.diagnostic', function() end) it('without arguments', function() - local result = exec_lua [[ - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + local result = exec_lua(function() + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) local result = {} vim.diagnostic.config({ underline = false, virtual_text = true }) local ns_1_diags = { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 2, 1, 2, 5), + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 2, 1, 2, 5), } local ns_2_diags = { - make_warning("Warning 1", 2, 1, 2, 5), + _G.make_warning('Warning 1', 2, 1, 2, 5), } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags) - vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + ) vim.diagnostic.enable(false) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + ) -- Create a new buffer local other_bufnr = vim.api.nvim_create_buf(true, false) local other_buffer_diags = { - make_info("This is interesting", 0, 0, 0, 0) + _G.make_info('This is interesting', 0, 0, 0, 0), } - vim.diagnostic.set(diagnostic_ns, other_bufnr, other_buffer_diags) + vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) vim.diagnostic.enable() - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) return result - ]] + end) eq(3, result[1]) eq(0, result[2]) @@ -559,54 +664,66 @@ describe('vim.diagnostic', function() end) it('with buffer argument', function() - local result = exec_lua [[ + local result = exec_lua(function() local other_bufnr = vim.api.nvim_create_buf(true, false) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) local result = {} vim.diagnostic.config({ underline = false, virtual_text = true }) local ns_1_diags = { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 2, 1, 2, 5), + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 2, 1, 2, 5), } local ns_2_diags = { - make_warning("Warning 1", 2, 1, 2, 5), + _G.make_warning('Warning 1', 2, 1, 2, 5), } local other_buffer_diags = { - make_info("This is interesting", 0, 0, 0, 0) + _G.make_info('This is interesting', 0, 0, 0, 0), } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags) - vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags) - vim.diagnostic.set(diagnostic_ns, other_bufnr, other_buffer_diags) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) + vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) - vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr }) + vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr }) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) - vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr }) + vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr }) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) vim.diagnostic.enable(false, { bufnr = other_bufnr }) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) return result - ]] + end) eq(4, result[1]) eq(1, result[2]) @@ -615,44 +732,56 @@ describe('vim.diagnostic', function() end) it('with a namespace argument', function() - local result = exec_lua [[ - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + local result = exec_lua(function() + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) local result = {} vim.diagnostic.config({ underline = false, virtual_text = true }) local ns_1_diags = { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 2, 1, 2, 5), + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 2, 1, 2, 5), } local ns_2_diags = { - make_warning("Warning 1", 2, 1, 2, 5), + _G.make_warning('Warning 1', 2, 1, 2, 5), } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags) - vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + ) - vim.diagnostic.enable(false, { ns_id = diagnostic_ns }) + vim.diagnostic.enable(false, { ns_id = _G.diagnostic_ns }) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + ) - vim.diagnostic.enable(true, { ns_id = diagnostic_ns }) + vim.diagnostic.enable(true, { ns_id = _G.diagnostic_ns }) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + ) - vim.diagnostic.enable(false, { ns_id = other_ns }) + vim.diagnostic.enable(false, { ns_id = _G.other_ns }) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + ) return result - ]] + end) eq(3, result[1]) eq(1, result[2]) @@ -662,84 +791,93 @@ describe('vim.diagnostic', function() --- @return table local function test_enable(legacy) - local result = exec_lua( - [[ - local legacy = ... + return exec_lua(function() local other_bufnr = vim.api.nvim_create_buf(true, false) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) local result = {} vim.diagnostic.config({ underline = false, virtual_text = true }) local ns_1_diags = { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 2, 1, 2, 5), + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 2, 1, 2, 5), } local ns_2_diags = { - make_warning("Warning 1", 2, 1, 2, 5), + _G.make_warning('Warning 1', 2, 1, 2, 5), } local other_buffer_diags = { - make_info("This is interesting", 0, 0, 0, 0) + _G.make_info('This is interesting', 0, 0, 0, 0), } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags) - vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags) - vim.diagnostic.set(diagnostic_ns, other_bufnr, other_buffer_diags) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) + vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags) - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) if legacy then - vim.diagnostic.disable(diagnostic_bufnr, diagnostic_ns) + vim.diagnostic.disable(_G.diagnostic_bufnr, _G.diagnostic_ns) else - vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) + vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) end - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) if legacy then - vim.diagnostic.disable(diagnostic_bufnr, other_ns) + vim.diagnostic.disable(_G.diagnostic_bufnr, _G.other_ns) else - vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = other_ns }) + vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.other_ns }) end - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) if legacy then - vim.diagnostic.enable(diagnostic_bufnr, diagnostic_ns) + vim.diagnostic.enable(_G.diagnostic_bufnr, _G.diagnostic_ns) else - vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) + vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) end - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) if legacy then -- Should have no effect - vim.diagnostic.disable(other_bufnr, other_ns) + vim.diagnostic.disable(other_bufnr, _G.other_ns) else -- Should have no effect - vim.diagnostic.enable(false, { bufnr = other_bufnr, ns_id = other_ns }) + vim.diagnostic.enable(false, { bufnr = other_bufnr, ns_id = _G.other_ns }) end - table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) + - count_extmarks(diagnostic_bufnr, other_ns) + - count_extmarks(other_bufnr, diagnostic_ns)) + table.insert( + result, + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns) + + _G.count_extmarks(other_bufnr, _G.diagnostic_ns) + ) return result - ]], - legacy - ) - - return result + end) end it('with both buffer and namespace arguments', function() @@ -772,442 +910,600 @@ describe('vim.diagnostic', function() local all_highlights = { 1, 1, 2, 4, 2 } eq( all_highlights, - exec_lua [[ - local ns_1_diags = { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 2, 1, 2, 3), - } - local ns_2_diags = { - make_warning("Warning 1", 2, 1, 2, 3), - } + exec_lua(function() + local ns_1_diags = { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 2, 1, 2, 3), + } + local ns_2_diags = { + _G.make_warning('Warning 1', 2, 1, 2, 3), + } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags) - vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags) - return { - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN), - count_extmarks(diagnostic_bufnr, diagnostic_ns), - count_extmarks(diagnostic_bufnr, other_ns), - } - ]] + return { + _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN), + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), + } + end) ) -- Reset diagnostics from namespace 1 - exec_lua([[ vim.diagnostic.reset(diagnostic_ns) ]]) + exec_lua([[ vim.diagnostic.reset( _G.diagnostic_ns) ]]) -- Make sure we have the right diagnostic count eq( { 0, 1, 1, 0, 2 }, - exec_lua [[ - local diagnostic_count = {} - vim.wait(100, function () diagnostic_count = { - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN), - count_extmarks(diagnostic_bufnr, diagnostic_ns), - count_extmarks(diagnostic_bufnr, other_ns), - } end ) - return diagnostic_count - ]] + exec_lua(function() + local diagnostic_count = {} + vim.wait(100, function() + diagnostic_count = { + _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN), + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), + } + end) + return diagnostic_count + end) ) -- Reset diagnostics from namespace 2 - exec_lua([[ vim.diagnostic.reset(other_ns) ]]) + exec_lua([[ vim.diagnostic.reset(_G.other_ns) ]]) -- Make sure we have the right diagnostic count eq( { 0, 0, 0, 0, 0 }, - exec_lua [[ - local diagnostic_count = {} - vim.wait(100, function () diagnostic_count = { - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns), - count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN), - count_extmarks(diagnostic_bufnr, diagnostic_ns), - count_extmarks(diagnostic_bufnr, other_ns), - } end ) - return diagnostic_count - ]] + exec_lua(function() + local diagnostic_count = {} + vim.wait(100, function() + diagnostic_count = { + _G.count_diagnostics( + _G.diagnostic_bufnr, + vim.diagnostic.severity.ERROR, + _G.diagnostic_ns + ), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns), + _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN), + _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns), + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns), + } + end) + return diagnostic_count + end) ) end) it("doesn't error after bwipeout called on buffer", function() - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {{ lnum = 0, end_lnum = 0, col = 0, end_col = 0 }}) - vim.cmd("bwipeout! " .. diagnostic_bufnr) + exec_lua(function() + vim.diagnostic.set( + _G.diagnostic_ns, + _G.diagnostic_bufnr, + { { lnum = 0, end_lnum = 0, col = 0, end_col = 0 } } + ) + vim.cmd('bwipeout! ' .. _G.diagnostic_bufnr) - vim.diagnostic.reset(diagnostic_ns) - ]] + vim.diagnostic.reset(_G.diagnostic_ns) + end) end) end) - describe('get_next_pos()', function() + describe('get_next()', function() it('can find the next pos with only one namespace', function() eq( { 1, 1 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - return vim.diagnostic.get_next_pos() - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + }) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + local next = vim.diagnostic.get_next() + return { next.lnum, next.col } + end) ) end) it('can find next pos with two errors', function() eq( { 4, 4 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - make_error('Diagnostic #2', 4, 4, 4, 4), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_next_pos { namespace = diagnostic_ns } - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + _G.make_error('Diagnostic #2', 4, 4, 4, 4), + }) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 3, 1 }) + local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns }) + return { next.lnum, next.col } + end) ) end) it('can cycle when position is past error', function() eq( { 1, 1 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_next_pos { namespace = diagnostic_ns } - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + }) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 3, 1 }) + local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns }) + return { next.lnum, next.col } + end) ) end) it('will not cycle when wrap is off', function() eq( - false, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_next_pos { namespace = diagnostic_ns, wrap = false } - ]] + nil, + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + }) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 3, 1 }) + local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns, wrap = false }) + return next + end) ) end) it('can cycle even from the last line', function() eq( { 4, 4 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #2', 4, 4, 4, 4), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {vim.api.nvim_buf_line_count(0), 1}) - return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns } - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #2', 4, 4, 4, 4), + }) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { vim.api.nvim_buf_line_count(0), 1 }) + local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns }) + return { prev.lnum, prev.col } + end) ) end) it('works with diagnostics past the end of the line #16349', function() eq( { 4, 0 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 3, 9001, 3, 9001), - make_error('Diagnostic #2', 4, 0, 4, 0), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {1, 1}) - vim.diagnostic.goto_next { float = false } - return vim.diagnostic.get_next_pos { namespace = diagnostic_ns } - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 3, 9001, 3, 9001), + _G.make_error('Diagnostic #2', 4, 0, 4, 0), + }) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 1, 1 }) + vim.diagnostic.jump({ count = 1, float = false }) + local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns }) + return { next.lnum, next.col } + end) ) end) it('works with diagnostics before the start of the line', function() eq( { 4, 0 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 3, 9001, 3, 9001), - make_error('Diagnostic #2', 4, -1, 4, -1), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 3, 9001, 3, 9001), + _G.make_error('Diagnostic #2', 4, -1, 4, -1), }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {1, 1}) - vim.diagnostic.goto_next { float = false } - return vim.diagnostic.get_next_pos { namespace = diagnostic_ns } - ]] + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 1, 1 }) + vim.diagnostic.jump({ count = 1, float = false }) + local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns }) + return { next.lnum, next.col } + end) ) end) it('jumps to diagnostic with highest severity', function() - exec_lua([[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_info('Info', 1, 0, 1, 1), - make_error('Error', 2, 0, 2, 1), - make_warning('Warning', 3, 0, 3, 1), - make_error('Error', 4, 0, 4, 1), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_info('Info', 1, 0, 1, 1), + _G.make_error('Error', 2, 0, 2, 1), + _G.make_warning('Warning', 3, 0, 3, 1), + _G.make_error('Error', 4, 0, 4, 1), }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {1, 0}) - ]]) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + end) eq( { 3, 0 }, - exec_lua([[ - vim.diagnostic.goto_next({_highest = true}) - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.diagnostic.jump({ count = 1, _highest = true }) + return vim.api.nvim_win_get_cursor(0) + end) ) eq( { 5, 0 }, - exec_lua([[ - vim.diagnostic.goto_next({_highest = true}) - return vim.api.nvim_win_get_cursor(0) - ]]) - ) - - exec_lua([[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_info('Info', 1, 0, 1, 1), - make_hint('Hint', 2, 0, 2, 1), - make_warning('Warning', 3, 0, 3, 1), - make_hint('Hint', 4, 0, 4, 1), - make_warning('Warning', 5, 0, 5, 1), + exec_lua(function() + vim.diagnostic.jump({ count = 1, _highest = true }) + return vim.api.nvim_win_get_cursor(0) + end) + ) + + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_info('Info', 1, 0, 1, 1), + _G.make_hint('Hint', 2, 0, 2, 1), + _G.make_warning('Warning', 3, 0, 3, 1), + _G.make_hint('Hint', 4, 0, 4, 1), + _G.make_warning('Warning', 5, 0, 5, 1), }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {1, 0}) - ]]) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + end) eq( { 4, 0 }, - exec_lua([[ - vim.diagnostic.goto_next({_highest = true}) - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.diagnostic.jump({ count = 1, _highest = true }) + return vim.api.nvim_win_get_cursor(0) + end) ) eq( { 6, 0 }, - exec_lua([[ - vim.diagnostic.goto_next({_highest = true}) - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.diagnostic.jump({ count = 1, _highest = true }) + return vim.api.nvim_win_get_cursor(0) + end) ) end) it('jumps to next diagnostic if severity is non-nil', function() - exec_lua([[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_info('Info', 1, 0, 1, 1), - make_error('Error', 2, 0, 2, 1), - make_warning('Warning', 3, 0, 3, 1), - make_error('Error', 4, 0, 4, 1), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_info('Info', 1, 0, 1, 1), + _G.make_error('Error', 2, 0, 2, 1), + _G.make_warning('Warning', 3, 0, 3, 1), + _G.make_error('Error', 4, 0, 4, 1), }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {1, 0}) - ]]) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + end) eq( { 2, 0 }, - exec_lua([[ - vim.diagnostic.goto_next() - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.diagnostic.jump({ count = 1 }) + return vim.api.nvim_win_get_cursor(0) + end) ) eq( { 3, 0 }, - exec_lua([[ - vim.diagnostic.goto_next() - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.diagnostic.jump({ count = 1 }) + return vim.api.nvim_win_get_cursor(0) + end) ) eq( { 4, 0 }, - exec_lua([[ - vim.diagnostic.goto_next() - return vim.api.nvim_win_get_cursor(0) - ]]) + exec_lua(function() + vim.diagnostic.jump({ count = 1 }) + return vim.api.nvim_win_get_cursor(0) + end) ) end) end) - describe('get_prev_pos()', function() - it('can find the prev pos with only one namespace', function() + describe('get_prev()', function() + it('can find the previous diagnostic with only one namespace', function() eq( { 1, 1 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_prev_pos() - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + }) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 3, 1 }) + local prev = vim.diagnostic.get_prev() + return { prev.lnum, prev.col } + end) ) end) - it('can find prev pos with two errors', function() + it('can find the previous diagnostic with two errors', function() eq( { 1, 1 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - make_error('Diagnostic #2', 4, 4, 4, 4), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns } - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + _G.make_error('Diagnostic #2', 4, 4, 4, 4), + }) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 3, 1 }) + local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns }) + return { prev.lnum, prev.col } + end) ) end) it('can cycle when position is past error', function() eq( { 4, 4 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #2', 4, 4, 4, 4), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns } - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #2', 4, 4, 4, 4), + }) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 3, 1 }) + local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns }) + return { prev.lnum, prev.col } + end) ) end) it('respects wrap parameter', function() eq( - false, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #2', 4, 4, 4, 4), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns, wrap = false} - ]] + nil, + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #2', 4, 4, 4, 4), + }) + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, { 3, 1 }) + local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns, wrap = false }) + return prev + end) ) end) it('works on blank line #28397', function() eq( { 0, 2 }, - exec_lua [[ - local test_bufnr = vim.api.nvim_create_buf(true, false) - vim.api.nvim_buf_set_lines(test_bufnr, 0, -1, false, { - 'first line', - '', - '', - 'end line', - }) - vim.diagnostic.set(diagnostic_ns, test_bufnr, { - make_info('Diagnostic #1', 0, 2, 0, 2), - make_info('Diagnostic #2', 2, 0, 2, 0), - make_info('Diagnostic #3', 2, 0, 2, 0), + exec_lua(function() + local test_bufnr = vim.api.nvim_create_buf(true, false) + vim.api.nvim_buf_set_lines(test_bufnr, 0, -1, false, { + 'first line', + '', + '', + 'end line', + }) + vim.diagnostic.set(_G.diagnostic_ns, test_bufnr, { + _G.make_info('Diagnostic #1', 0, 2, 0, 2), + _G.make_info('Diagnostic #2', 2, 0, 2, 0), + _G.make_info('Diagnostic #3', 2, 0, 2, 0), + }) + vim.api.nvim_win_set_buf(0, test_bufnr) + vim.api.nvim_win_set_cursor(0, { 3, 0 }) + return vim.diagnostic.get_prev_pos { namespace = _G.diagnostic_ns } + end) + ) + end) + end) + + describe('jump()', function() + before_each(function() + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 0, 0, 0, 2), + _G.make_error('Diagnostic #2', 1, 1, 1, 4), + _G.make_warning('Diagnostic #3', 2, -1, 2, -1), + _G.make_info('Diagnostic #4', 3, 0, 3, 3), }) - vim.api.nvim_win_set_buf(0, test_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 0}) - return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns} - ]] + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + end) + end) + + it('can move forward', function() + eq( + { 2, 1 }, + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = 1 }) + return vim.api.nvim_win_get_cursor(0) + end) + ) + + eq( + { 4, 0 }, + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = 3 }) + return vim.api.nvim_win_get_cursor(0) + end) + ) + + eq( + { 4, 0 }, + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = math.huge, wrap = false }) + return vim.api.nvim_win_get_cursor(0) + end) + ) + end) + + it('can move backward', function() + eq( + { 3, 0 }, + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 4, 0 }) + vim.diagnostic.jump({ count = -1 }) + return vim.api.nvim_win_get_cursor(0) + end) + ) + + eq( + { 1, 0 }, + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 4, 0 }) + vim.diagnostic.jump({ count = -3 }) + return vim.api.nvim_win_get_cursor(0) + end) + ) + + eq( + { 1, 0 }, + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 4, 0 }) + vim.diagnostic.jump({ count = -math.huge, wrap = false }) + return vim.api.nvim_win_get_cursor(0) + end) + ) + end) + + it('can filter by severity', function() + eq( + { 3, 0 }, + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = 1, severity = vim.diagnostic.severity.WARN }) + return vim.api.nvim_win_get_cursor(0) + end) + ) + + eq( + { 3, 0 }, + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = 9999, severity = vim.diagnostic.severity.WARN }) + return vim.api.nvim_win_get_cursor(0) + end) + ) + end) + + it('can wrap', function() + eq( + { 1, 0 }, + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 4, 0 }) + vim.diagnostic.jump({ count = 1, wrap = true }) + return vim.api.nvim_win_get_cursor(0) + end) + ) + + eq( + { 4, 0 }, + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = -1, wrap = true }) + return vim.api.nvim_win_get_cursor(0) + end) ) end) end) describe('get()', function() it('returns an empty table when no diagnostics are present', function() - eq({}, exec_lua [[return vim.diagnostic.get(diagnostic_bufnr, {namespace=diagnostic_ns})]]) + eq( + {}, + exec_lua [[return vim.diagnostic.get( _G.diagnostic_bufnr, {namespace=diagnostic_ns})]] + ) end) it('returns all diagnostics when no severity is supplied', function() eq( 2, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 1, 1, 2, 3), - }) + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 1, 1, 2, 3), + }) - return #vim.diagnostic.get(diagnostic_bufnr) - ]] + return #vim.diagnostic.get(_G.diagnostic_bufnr) + end) ) end) it('returns only requested diagnostics when severity range is supplied', function() eq( { 2, 3, 2 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 1, 1, 2, 3), - make_info("Ignored information", 1, 1, 2, 3), - make_hint("Here's a hint", 1, 1, 2, 3), - }) + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 1, 1, 2, 3), + _G.make_info('Ignored information', 1, 1, 2, 3), + _G.make_hint("Here's a hint", 1, 1, 2, 3), + }) - return { - #vim.diagnostic.get(diagnostic_bufnr, { severity = {min=vim.diagnostic.severity.WARN} }), - #vim.diagnostic.get(diagnostic_bufnr, { severity = {max=vim.diagnostic.severity.WARN} }), - #vim.diagnostic.get(diagnostic_bufnr, { - severity = { - min=vim.diagnostic.severity.INFO, - max=vim.diagnostic.severity.WARN, - } - }), - } - ]] + return { + #vim.diagnostic.get( + _G.diagnostic_bufnr, + { severity = { min = vim.diagnostic.severity.WARN } } + ), + #vim.diagnostic.get( + _G.diagnostic_bufnr, + { severity = { max = vim.diagnostic.severity.WARN } } + ), + #vim.diagnostic.get(_G.diagnostic_bufnr, { + severity = { + min = vim.diagnostic.severity.INFO, + max = vim.diagnostic.severity.WARN, + }, + }), + } + end) ) end) it('returns only requested diagnostics when severities are supplied', function() eq( { 1, 1, 2 }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 1, 1, 2, 3), - make_info("Ignored information", 1, 1, 2, 3), - make_hint("Here's a hint", 1, 1, 2, 3), - }) + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 1, 1, 2, 3), + _G.make_info('Ignored information', 1, 1, 2, 3), + _G.make_hint("Here's a hint", 1, 1, 2, 3), + }) - return { - #vim.diagnostic.get(diagnostic_bufnr, { severity = {vim.diagnostic.severity.WARN} }), - #vim.diagnostic.get(diagnostic_bufnr, { severity = {vim.diagnostic.severity.ERROR} }), - #vim.diagnostic.get(diagnostic_bufnr, { - severity = { - vim.diagnostic.severity.INFO, - vim.diagnostic.severity.WARN, - } - }), - } - ]] + return { + #vim.diagnostic.get( + _G.diagnostic_bufnr, + { severity = { vim.diagnostic.severity.WARN } } + ), + #vim.diagnostic.get( + _G.diagnostic_bufnr, + { severity = { vim.diagnostic.severity.ERROR } } + ), + #vim.diagnostic.get(_G.diagnostic_bufnr, { + severity = { + vim.diagnostic.severity.INFO, + vim.diagnostic.severity.WARN, + }, + }), + } + end) ) end) it('allows filtering by line', function() eq( 2, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 1, 1, 2, 3), - make_info("Ignored information", 1, 1, 2, 3), - make_error("Error On Other Line", 3, 1, 3, 5), - }) + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 1, 1, 2, 3), + _G.make_info('Ignored information', 1, 1, 2, 3), + _G.make_error('Error On Other Line', 3, 1, 3, 5), + }) - return #vim.diagnostic.get(diagnostic_bufnr, {lnum = 2}) - ]] + return #vim.diagnostic.get(_G.diagnostic_bufnr, { lnum = 2 }) + end) ) end) end) @@ -1215,118 +1511,144 @@ describe('vim.diagnostic', function() describe('count', function() it('returns actually present severity counts', function() eq( - exec_lua [[return { - [vim.diagnostic.severity.ERROR] = 4, - [vim.diagnostic.severity.WARN] = 3, - [vim.diagnostic.severity.INFO] = 2, - [vim.diagnostic.severity.HINT] = 1, - }]], - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Error 1", 1, 1, 1, 2), - make_error("Error 2", 1, 3, 1, 4), - make_error("Error 3", 1, 5, 1, 6), - make_error("Error 4", 1, 7, 1, 8), - make_warning("Warning 1", 2, 1, 2, 2), - make_warning("Warning 2", 2, 3, 2, 4), - make_warning("Warning 3", 2, 5, 2, 6), - make_info("Info 1", 3, 1, 3, 2), - make_info("Info 2", 3, 3, 3, 4), - make_hint("Hint 1", 4, 1, 4, 2), + exec_lua(function() + return { + [vim.diagnostic.severity.ERROR] = 4, + [vim.diagnostic.severity.WARN] = 3, + [vim.diagnostic.severity.INFO] = 2, + [vim.diagnostic.severity.HINT] = 1, + } + end), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 1, 1, 1, 2), + _G.make_error('Error 2', 1, 3, 1, 4), + _G.make_error('Error 3', 1, 5, 1, 6), + _G.make_error('Error 4', 1, 7, 1, 8), + _G.make_warning('Warning 1', 2, 1, 2, 2), + _G.make_warning('Warning 2', 2, 3, 2, 4), + _G.make_warning('Warning 3', 2, 5, 2, 6), + _G.make_info('Info 1', 3, 1, 3, 2), + _G.make_info('Info 2', 3, 3, 3, 4), + _G.make_hint('Hint 1', 4, 1, 4, 2), }) - return vim.diagnostic.count(diagnostic_bufnr) - ]] - ) - eq( - exec_lua [[return { - [vim.diagnostic.severity.ERROR] = 2, - [vim.diagnostic.severity.INFO] = 1, - }]], - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Error 1", 1, 1, 1, 2), - make_error("Error 2", 1, 3, 1, 4), - make_info("Info 1", 3, 1, 3, 2), + return vim.diagnostic.count(_G.diagnostic_bufnr) + end) + ) + eq( + exec_lua(function() + return { + [vim.diagnostic.severity.ERROR] = 2, + [vim.diagnostic.severity.INFO] = 1, + } + end), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 1, 1, 1, 2), + _G.make_error('Error 2', 1, 3, 1, 4), + _G.make_info('Info 1', 3, 1, 3, 2), }) - return vim.diagnostic.count(diagnostic_bufnr) - ]] + return vim.diagnostic.count(_G.diagnostic_bufnr) + end) ) end) it('returns only requested diagnostics count when severity range is supplied', function() eq( - exec_lua [[return { - { [vim.diagnostic.severity.ERROR] = 1, [vim.diagnostic.severity.WARN] = 1 }, - { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1, [vim.diagnostic.severity.HINT] = 1 }, - { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 }, - }]], - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 1, 1, 2, 3), - make_info("Ignored information", 1, 1, 2, 3), - make_hint("Here's a hint", 1, 1, 2, 3), + exec_lua(function() + return { + { [vim.diagnostic.severity.ERROR] = 1, [vim.diagnostic.severity.WARN] = 1 }, + { + [vim.diagnostic.severity.WARN] = 1, + [vim.diagnostic.severity.INFO] = 1, + [vim.diagnostic.severity.HINT] = 1, + }, + { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 }, + } + end), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 1, 1, 2, 3), + _G.make_info('Ignored information', 1, 1, 2, 3), + _G.make_hint("Here's a hint", 1, 1, 2, 3), }) return { - vim.diagnostic.count(diagnostic_bufnr, { severity = {min=vim.diagnostic.severity.WARN} }), - vim.diagnostic.count(diagnostic_bufnr, { severity = {max=vim.diagnostic.severity.WARN} }), - vim.diagnostic.count(diagnostic_bufnr, { + vim.diagnostic.count( + _G.diagnostic_bufnr, + { severity = { min = vim.diagnostic.severity.WARN } } + ), + vim.diagnostic.count( + _G.diagnostic_bufnr, + { severity = { max = vim.diagnostic.severity.WARN } } + ), + vim.diagnostic.count(_G.diagnostic_bufnr, { severity = { - min=vim.diagnostic.severity.INFO, - max=vim.diagnostic.severity.WARN, - } + min = vim.diagnostic.severity.INFO, + max = vim.diagnostic.severity.WARN, + }, }), } - ]] + end) ) end) it('returns only requested diagnostics when severities are supplied', function() eq( - exec_lua [[return { - { [vim.diagnostic.severity.WARN] = 1 }, - { [vim.diagnostic.severity.ERROR] = 1 }, - { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 }, - }]], - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 1, 1, 2, 3), - make_info("Ignored information", 1, 1, 2, 3), - make_hint("Here's a hint", 1, 1, 2, 3), + exec_lua(function() + return { + { [vim.diagnostic.severity.WARN] = 1 }, + { [vim.diagnostic.severity.ERROR] = 1 }, + { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 }, + } + end), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 1, 1, 2, 3), + _G.make_info('Ignored information', 1, 1, 2, 3), + _G.make_hint("Here's a hint", 1, 1, 2, 3), }) return { - vim.diagnostic.count(diagnostic_bufnr, { severity = {vim.diagnostic.severity.WARN} }), - vim.diagnostic.count(diagnostic_bufnr, { severity = {vim.diagnostic.severity.ERROR} }), - vim.diagnostic.count(diagnostic_bufnr, { + vim.diagnostic.count( + _G.diagnostic_bufnr, + { severity = { vim.diagnostic.severity.WARN } } + ), + vim.diagnostic.count( + _G.diagnostic_bufnr, + { severity = { vim.diagnostic.severity.ERROR } } + ), + vim.diagnostic.count(_G.diagnostic_bufnr, { severity = { vim.diagnostic.severity.INFO, vim.diagnostic.severity.WARN, - } + }, }), } - ]] + end) ) end) it('allows filtering by line', function() eq( - exec_lua [[return { - [vim.diagnostic.severity.WARN] = 1, - [vim.diagnostic.severity.INFO] = 1, - }]], - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Error 1", 1, 1, 1, 5), - make_warning("Warning on Server 1", 1, 1, 2, 3), - make_info("Ignored information", 1, 1, 2, 3), - make_error("Error On Other Line", 3, 1, 3, 5), + exec_lua(function() + return { + [vim.diagnostic.severity.WARN] = 1, + [vim.diagnostic.severity.INFO] = 1, + } + end), + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 1, 1, 1, 5), + _G.make_warning('Warning on Server 1', 1, 1, 2, 3), + _G.make_info('Ignored information', 1, 1, 2, 3), + _G.make_error('Error On Other Line', 3, 1, 3, 5), }) - return vim.diagnostic.count(diagnostic_bufnr, {lnum = 2}) - ]] + return vim.diagnostic.count(_G.diagnostic_bufnr, { lnum = 2 }) + end) ) end) end) @@ -1335,137 +1657,138 @@ describe('vim.diagnostic', function() it('works with global, namespace, and ephemeral options', function() eq( 1, - exec_lua [[ - vim.diagnostic.config({ - virtual_text = false, - }) + exec_lua(function() + vim.diagnostic.config({ + virtual_text = false, + }) - vim.diagnostic.config({ - virtual_text = true, - underline = false, - }, diagnostic_ns) + vim.diagnostic.config({ + virtual_text = true, + underline = false, + }, _G.diagnostic_ns) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Some Error', 4, 4, 4, 4), - }) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Some Error', 4, 4, 4, 4), + }) - return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]] + return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + end) ) eq( 1, - exec_lua [[ - vim.diagnostic.config({ - virtual_text = false, - }) + exec_lua(function() + vim.diagnostic.config({ + virtual_text = false, + }) - vim.diagnostic.config({ - virtual_text = false, - underline = false, - }, diagnostic_ns) + vim.diagnostic.config({ + virtual_text = false, + underline = false, + }, _G.diagnostic_ns) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Some Error', 4, 4, 4, 4), - }, {virtual_text = true}) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Some Error', 4, 4, 4, 4), + }, { virtual_text = true }) - return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]] + return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + end) ) eq( 0, - exec_lua [[ - vim.diagnostic.config({ - virtual_text = false, - }) + exec_lua(function() + vim.diagnostic.config({ + virtual_text = false, + }) - vim.diagnostic.config({ - virtual_text = {severity=vim.diagnostic.severity.ERROR}, - underline = false, - }, diagnostic_ns) + vim.diagnostic.config({ + virtual_text = { severity = vim.diagnostic.severity.ERROR }, + underline = false, + }, _G.diagnostic_ns) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_warning('Some Warning', 4, 4, 4, 4), - }, {virtual_text = true}) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_warning('Some Warning', 4, 4, 4, 4), + }, { virtual_text = true }) - return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]] + return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + end) ) eq( 1, - exec_lua [[ - vim.diagnostic.config({ - virtual_text = false, - }) + exec_lua(function() + vim.diagnostic.config({ + virtual_text = false, + }) - vim.diagnostic.config({ - virtual_text = {severity=vim.diagnostic.severity.ERROR}, - underline = false, - }, diagnostic_ns) + vim.diagnostic.config({ + virtual_text = { severity = vim.diagnostic.severity.ERROR }, + underline = false, + }, _G.diagnostic_ns) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_warning('Some Warning', 4, 4, 4, 4), - }, { - virtual_text = {} -- An empty table uses default values - }) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_warning('Some Warning', 4, 4, 4, 4), + }, { + virtual_text = {}, -- An empty table uses default values + }) - return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]] + return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + end) ) end) it('can use functions for config values', function() - exec_lua [[ + exec_lua(function() vim.diagnostic.config({ - virtual_text = function() return true end, - }, diagnostic_ns) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Delayed Diagnostic', 4, 4, 4, 4), + virtual_text = function() + return true + end, + }, _G.diagnostic_ns) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), }) - ]] + end) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) + eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) -- Now, don't enable virtual text. -- We should have one less extmark displayed. - exec_lua [[ + exec_lua(function() vim.diagnostic.config({ - virtual_text = function() return false end, - }, diagnostic_ns) - ]] + virtual_text = function() + return false + end, + }, _G.diagnostic_ns) + end) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(1, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) + eq(1, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) end) it('allows filtering by severity', function() local get_extmark_count_with_severity = function(min_severity) - return exec_lua( - [[ + return exec_lua(function() vim.diagnostic.config({ underline = false, virtual_text = { - severity = {min=...}, + severity = { min = min_severity }, }, }) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_warning('Delayed Diagnostic', 4, 4, 4, 4), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_warning('Delayed Diagnostic', 4, 4, 4, 4), }) - return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]], - min_severity - ) + return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + end) end -- No messages with Error or higher @@ -1477,152 +1800,158 @@ describe('vim.diagnostic', function() end) it('allows sorting by severity', function() - exec_lua [[ + exec_lua(function() vim.diagnostic.config({ underline = false, signs = true, virtual_text = true, }) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_warning('Warning', 4, 4, 4, 4), - make_error('Error', 4, 4, 4, 4), - make_info('Info', 4, 4, 4, 4), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_warning('Warning', 4, 4, 4, 4), + _G.make_error('Error', 4, 4, 4, 4), + _G.make_info('Info', 4, 4, 4, 4), }) - function get_virt_text_and_signs(severity_sort) + function _G.get_virt_text_and_signs(severity_sort) vim.diagnostic.config({ severity_sort = severity_sort, }) - local virt_text = get_virt_text_extmarks(diagnostic_ns)[1][4].virt_text + local virt_text = _G.get_virt_text_extmarks(_G.diagnostic_ns)[1][4].virt_text local virt_texts = {} for i = 2, #virt_text - 1 do - table.insert(virt_texts, (string.gsub(virt_text[i][2], "DiagnosticVirtualText", ""))) + table.insert(virt_texts, (string.gsub(virt_text[i][2], 'DiagnosticVirtualText', ''))) end - local ns = vim.diagnostic.get_namespace(diagnostic_ns) + local ns = vim.diagnostic.get_namespace(_G.diagnostic_ns) local sign_ns = ns.user_data.sign_ns local signs = {} - local all_signs = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, sign_ns, 0, -1, {type = 'sign', details = true}) + local all_signs = vim.api.nvim_buf_get_extmarks( + _G.diagnostic_bufnr, + sign_ns, + 0, + -1, + { type = 'sign', details = true } + ) table.sort(all_signs, function(a, b) return a[1] > b[1] end) for _, v in ipairs(all_signs) do - local s = v[4].sign_hl_group:gsub('DiagnosticSign', "") + local s = v[4].sign_hl_group:gsub('DiagnosticSign', '') if not vim.tbl_contains(signs, s) then signs[#signs + 1] = s end end - return {virt_texts, signs} + return { virt_texts, signs } end - ]] + end) - local result = exec_lua [[return get_virt_text_and_signs(false)]] + local result = exec_lua [[return _G.get_virt_text_and_signs(false)]] -- Virt texts are defined lowest priority to highest, signs from -- highest to lowest eq({ 'Warn', 'Error', 'Info' }, result[1]) eq({ 'Info', 'Error', 'Warn' }, result[2]) - result = exec_lua [[return get_virt_text_and_signs(true)]] + result = exec_lua [[return _G.get_virt_text_and_signs(true)]] eq({ 'Info', 'Warn', 'Error' }, result[1]) eq({ 'Error', 'Warn', 'Info' }, result[2]) - result = exec_lua [[return get_virt_text_and_signs({ reverse = true })]] + result = exec_lua [[return _G.get_virt_text_and_signs({ reverse = true })]] eq({ 'Error', 'Warn', 'Info' }, result[1]) eq({ 'Info', 'Warn', 'Error' }, result[2]) end) it('can show diagnostic sources in virtual text', function() - local result = exec_lua [[ + local result = exec_lua(function() local diagnostics = { - make_error('Some error', 0, 0, 0, 0, 'source x'), + _G.make_error('Some error', 0, 0, 0, 0, 'source x'), } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, { + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, { underline = false, virtual_text = { prefix = '', source = 'always', - } + }, }) - local extmarks = get_virt_text_extmarks(diagnostic_ns) + local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) local virt_text = extmarks[1][4].virt_text[3][1] return virt_text - ]] + end) eq(' source x: Some error', result) - result = exec_lua [[ + result = exec_lua(function() vim.diagnostic.config({ underline = false, virtual_text = { prefix = '', source = 'if_many', - } - }, diagnostic_ns) + }, + }, _G.diagnostic_ns) - local extmarks = get_virt_text_extmarks(diagnostic_ns) + local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) local virt_text = extmarks[1][4].virt_text[3][1] return virt_text - ]] + end) eq(' Some error', result) - result = exec_lua [[ + result = exec_lua(function() local diagnostics = { - make_error('Some error', 0, 0, 0, 0, 'source x'), - make_error('Another error', 1, 1, 1, 1, 'source y'), + _G.make_error('Some error', 0, 0, 0, 0, 'source x'), + _G.make_error('Another error', 1, 1, 1, 1, 'source y'), } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, { + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, { underline = false, virtual_text = { prefix = '', source = 'if_many', - } + }, }) - local extmarks = get_virt_text_extmarks(diagnostic_ns) - local virt_text = {extmarks[1][4].virt_text[3][1], extmarks[2][4].virt_text[3][1]} + local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) + local virt_text = { extmarks[1][4].virt_text[3][1], extmarks[2][4].virt_text[3][1] } return virt_text - ]] + end) eq(' source x: Some error', result[1]) eq(' source y: Another error', result[2]) end) it('supports a format function for diagnostic messages', function() - local result = exec_lua [[ + local result = exec_lua(function() vim.diagnostic.config({ underline = false, virtual_text = { prefix = '', format = function(diagnostic) if diagnostic.severity == vim.diagnostic.severity.ERROR then - return string.format("🔥 %s", diagnostic.message) + return string.format('🔥 %s', diagnostic.message) end - return string.format("👀 %s", diagnostic.message) + return string.format('👀 %s', diagnostic.message) end, - } + }, }) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_warning('Warning', 0, 0, 0, 0), - make_error('Error', 1, 0, 1, 0), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_warning('Warning', 0, 0, 0, 0), + _G.make_error('Error', 1, 0, 1, 0), }) - local extmarks = get_virt_text_extmarks(diagnostic_ns) - return {extmarks[1][4].virt_text, extmarks[2][4].virt_text} - ]] + local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) + return { extmarks[1][4].virt_text, extmarks[2][4].virt_text } + end) eq(' 👀 Warning', result[1][3][1]) eq(' 🔥 Error', result[2][3][1]) end) it('includes source for formatted diagnostics', function() - local result = exec_lua [[ + local result = exec_lua(function() vim.diagnostic.config({ underline = false, virtual_text = { @@ -1630,21 +1959,21 @@ describe('vim.diagnostic', function() source = 'always', format = function(diagnostic) if diagnostic.severity == vim.diagnostic.severity.ERROR then - return string.format("🔥 %s", diagnostic.message) + return string.format('🔥 %s', diagnostic.message) end - return string.format("👀 %s", diagnostic.message) + return string.format('👀 %s', diagnostic.message) end, - } + }, }) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_warning('Warning', 0, 0, 0, 0, 'some_linter'), - make_error('Error', 1, 0, 1, 0, 'another_linter'), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_warning('Warning', 0, 0, 0, 0, 'some_linter'), + _G.make_error('Error', 1, 0, 1, 0, 'another_linter'), }) - local extmarks = get_virt_text_extmarks(diagnostic_ns) - return {extmarks[1][4].virt_text, extmarks[2][4].virt_text} - ]] + local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) + return { extmarks[1][4].virt_text, extmarks[2][4].virt_text } + end) eq(' some_linter: 👀 Warning', result[1][3][1]) eq(' another_linter: 🔥 Error', result[2][3][1]) end) @@ -1652,90 +1981,94 @@ describe('vim.diagnostic', function() it('can add a prefix to virtual text', function() eq( 'E Some error', - exec_lua [[ - local diagnostics = { - make_error('Some error', 0, 0, 0, 0), - } - - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, { - underline = false, - virtual_text = { - prefix = 'E', - suffix = '', + exec_lua(function() + local diagnostics = { + _G.make_error('Some error', 0, 0, 0, 0), } - }) - local extmarks = get_virt_text_extmarks(diagnostic_ns) - local prefix = extmarks[1][4].virt_text[2][1] - local message = extmarks[1][4].virt_text[3][1] - return prefix .. message - ]] + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, { + underline = false, + virtual_text = { + prefix = 'E', + suffix = '', + }, + }) + + local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) + local prefix = extmarks[1][4].virt_text[2][1] + local message = extmarks[1][4].virt_text[3][1] + return prefix .. message + end) ) eq( '[(1/1) err-code] Some error', - exec_lua [[ - local diagnostics = { - make_error('Some error', 0, 0, 0, 0, nil, 'err-code'), - } - - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, { - underline = false, - virtual_text = { - prefix = function(diag, i, total) return string.format('[(%d/%d) %s]', i, total, diag.code) end, - suffix = '', + exec_lua(function() + local diagnostics = { + _G.make_error('Some error', 0, 0, 0, 0, nil, 'err-code'), } - }) - local extmarks = get_virt_text_extmarks(diagnostic_ns) - local prefix = extmarks[1][4].virt_text[2][1] - local message = extmarks[1][4].virt_text[3][1] - return prefix .. message - ]] + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, { + underline = false, + virtual_text = { + prefix = function(diag, i, total) + return string.format('[(%d/%d) %s]', i, total, diag.code) + end, + suffix = '', + }, + }) + + local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) + local prefix = extmarks[1][4].virt_text[2][1] + local message = extmarks[1][4].virt_text[3][1] + return prefix .. message + end) ) end) it('can add a suffix to virtual text', function() eq( ' Some error ✘', - exec_lua [[ - local diagnostics = { - make_error('Some error', 0, 0, 0, 0), - } - - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, { - underline = false, - virtual_text = { - prefix = '', - suffix = ' ✘', + exec_lua(function() + local diagnostics = { + _G.make_error('Some error', 0, 0, 0, 0), } - }) - local extmarks = get_virt_text_extmarks(diagnostic_ns) - local virt_text = extmarks[1][4].virt_text[3][1] - return virt_text - ]] + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, { + underline = false, + virtual_text = { + prefix = '', + suffix = ' ✘', + }, + }) + + local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) + local virt_text = extmarks[1][4].virt_text[3][1] + return virt_text + end) ) eq( ' Some error [err-code]', - exec_lua [[ - local diagnostics = { - make_error('Some error', 0, 0, 0, 0, nil, 'err-code'), - } - - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, { - underline = false, - virtual_text = { - prefix = '', - suffix = function(diag) return string.format(' [%s]', diag.code) end, + exec_lua(function() + local diagnostics = { + _G.make_error('Some error', 0, 0, 0, 0, nil, 'err-code'), } - }) - local extmarks = get_virt_text_extmarks(diagnostic_ns) - local virt_text = extmarks[1][4].virt_text[3][1] - return virt_text - ]] + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, { + underline = false, + virtual_text = { + prefix = '', + suffix = function(diag) + return string.format(' [%s]', diag.code) + end, + }, + }) + + local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns) + local virt_text = extmarks[1][4].virt_text[3][1] + return virt_text + end) ) end) end) @@ -1749,80 +2082,80 @@ describe('vim.diagnostic', function() end) it('can perform updates after insert_leave', function() - exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]] + exec_lua [[vim.api.nvim_set_current_buf( _G.diagnostic_bufnr)]] api.nvim_input('o') eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) -- Save the diagnostics - exec_lua [[ + exec_lua(function() vim.diagnostic.config({ update_in_insert = false, }) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Delayed Diagnostic', 4, 4, 4, 4), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), }) - ]] + end) -- No diagnostics displayed yet. eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(0, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) + eq(0, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) api.nvim_input('<esc>') eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) + eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) end) it('does not perform updates when not needed', function() - exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]] + exec_lua [[vim.api.nvim_set_current_buf( _G.diagnostic_bufnr)]] api.nvim_input('o') eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) -- Save the diagnostics - exec_lua [[ + exec_lua(function() vim.diagnostic.config({ update_in_insert = false, virtual_text = true, }) - DisplayCount = 0 + _G.DisplayCount = 0 local set_virtual_text = vim.diagnostic.handlers.virtual_text.show vim.diagnostic.handlers.virtual_text.show = function(...) - DisplayCount = DisplayCount + 1 + _G.DisplayCount = _G.DisplayCount + 1 return set_virtual_text(...) end - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Delayed Diagnostic', 4, 4, 4, 4), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), }) - ]] + end) -- No diagnostics displayed yet. eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(0, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) - eq(0, exec_lua [[return DisplayCount]]) + eq(0, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) + eq(0, exec_lua [[return _G.DisplayCount]]) api.nvim_input('<esc>') eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) - eq(1, exec_lua [[return DisplayCount]]) + eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) + eq(1, exec_lua [[return _G.DisplayCount]]) -- Go in and out of insert mode one more time. api.nvim_input('o') @@ -1832,52 +2165,51 @@ describe('vim.diagnostic', function() eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) -- Should not have set the virtual text again. - eq(1, exec_lua [[return DisplayCount]]) + eq(1, exec_lua [[return _G.DisplayCount]]) end) it('never sets virtual text, in combination with insert leave', function() - exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]] + exec_lua [[vim.api.nvim_set_current_buf( _G.diagnostic_bufnr)]] api.nvim_input('o') eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) -- Save the diagnostics - exec_lua [[ + exec_lua(function() vim.diagnostic.config({ update_in_insert = false, virtual_text = false, }) - - DisplayCount = 0 + _G.DisplayCount = 0 local set_virtual_text = vim.diagnostic.handlers.virtual_text.show vim.diagnostic.handlers.virtual_text.show = function(...) - DisplayCount = DisplayCount + 1 + _G.DisplayCount = _G.DisplayCount + 1 return set_virtual_text(...) end - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Delayed Diagnostic', 4, 4, 4, 4), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), }) - ]] + end) -- No diagnostics displayed yet. eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(0, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) - eq(0, exec_lua [[return DisplayCount]]) + eq(0, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) + eq(0, exec_lua [[return _G.DisplayCount]]) api.nvim_input('<esc>') eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(1, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) - eq(0, exec_lua [[return DisplayCount]]) + eq(1, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) + eq(0, exec_lua [[return _G.DisplayCount]]) -- Go in and out of insert mode one more time. api.nvim_input('o') @@ -1887,124 +2219,136 @@ describe('vim.diagnostic', function() eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) -- Should not have set the virtual text still. - eq(0, exec_lua [[return DisplayCount]]) + eq(0, exec_lua [[return _G.DisplayCount]]) end) it('can perform updates while in insert mode, if desired', function() - exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]] + exec_lua [[vim.api.nvim_set_current_buf( _G.diagnostic_bufnr)]] api.nvim_input('o') eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) -- Save the diagnostics - exec_lua [[ + exec_lua(function() vim.diagnostic.config({ update_in_insert = true, }) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Delayed Diagnostic', 4, 4, 4, 4), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), }) - ]] + end) -- Diagnostics are displayed, because the user wanted them that way! eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) + eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) api.nvim_input('<esc>') eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) eq( 1, - exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]] ) - eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) + eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]]) end) it('can set diagnostics without displaying them', function() eq( 0, - exec_lua [[ - vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), - }) - return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]] + exec_lua(function() + vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), + }) + return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + end) ) eq( 2, - exec_lua [[ - vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }) - return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]] + exec_lua(function() + vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }) + return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + end) ) end) it('can set display options', function() eq( 0, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), - }, { virtual_text = false, underline = false }) - return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), + }, { virtual_text = false, underline = false }) + return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + end) ) eq( 1, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), - }, { virtual_text = true, underline = false }) - return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), + }, { virtual_text = true, underline = false }) + return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns) + end) ) end) it('sets and clears signs #26193 #26555', function() do - local result = exec_lua [[ + local result = exec_lua(function() vim.diagnostic.config({ signs = true, }) local diagnostics = { - make_error('Error', 1, 1, 1, 2), - make_warning('Warning', 3, 3, 3, 3), + _G.make_error('Error', 1, 1, 1, 2), + _G.make_warning('Warning', 3, 3, 3, 3), } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) - local ns = vim.diagnostic.get_namespace(diagnostic_ns) + local ns = vim.diagnostic.get_namespace(_G.diagnostic_ns) local sign_ns = ns.user_data.sign_ns - local signs = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, sign_ns, 0, -1, {type ='sign', details = true}) + local signs = vim.api.nvim_buf_get_extmarks( + _G.diagnostic_bufnr, + sign_ns, + 0, + -1, + { type = 'sign', details = true } + ) local result = {} for _, s in ipairs(signs) do result[#result + 1] = { lnum = s[2] + 1, name = s[4].sign_hl_group } end return result - ]] + end) eq({ 2, 'DiagnosticSignError' }, { result[1].lnum, result[1].name }) eq({ 4, 'DiagnosticSignWarn' }, { result[2].lnum, result[2].name }) end do - local result = exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {}) + local result = exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {}) - local ns = vim.diagnostic.get_namespace(diagnostic_ns) + local ns = vim.diagnostic.get_namespace(_G.diagnostic_ns) local sign_ns = ns.user_data.sign_ns - return vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, sign_ns, 0, -1, {type ='sign', details = true}) - ]] + return vim.api.nvim_buf_get_extmarks( + _G.diagnostic_bufnr, + sign_ns, + 0, + -1, + { type = 'sign', details = true } + ) + end) eq({}, result) end @@ -2019,22 +2363,28 @@ describe('vim.diagnostic', function() n.command('sign define DiagnosticSignInfo text= texthl= linehl=Underlined numhl=Underlined') n.command('sign define DiagnosticSignHint text= texthl= linehl=Underlined numhl=Underlined') - local result = exec_lua [[ + local result = exec_lua(function() vim.diagnostic.config({ signs = true, }) local diagnostics = { - make_error('Error', 1, 1, 1, 2), - make_warning('Warning', 3, 3, 3, 3), + _G.make_error('Error', 1, 1, 1, 2), + _G.make_warning('Warning', 3, 3, 3, 3), } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) - local ns = vim.diagnostic.get_namespace(diagnostic_ns) + local ns = vim.diagnostic.get_namespace(_G.diagnostic_ns) local sign_ns = ns.user_data.sign_ns - local signs = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, sign_ns, 0, -1, {type ='sign', details = true}) + local signs = vim.api.nvim_buf_get_extmarks( + _G.diagnostic_bufnr, + sign_ns, + 0, + -1, + { type = 'sign', details = true } + ) local result = {} for _, s in ipairs(signs) do result[#result + 1] = { @@ -2046,7 +2396,7 @@ describe('vim.diagnostic', function() } end return result - ]] + end) eq({ lnum = 2, @@ -2070,65 +2420,67 @@ describe('vim.diagnostic', function() it('can display a header', function() eq( { 'Diagnostics:', '1. Syntax error' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float() - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float() + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { "We're no strangers to love...", '1. Syntax error' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({header = "We're no strangers to love..."}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = + vim.diagnostic.open_float({ header = "We're no strangers to love..." }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { 'You know the rules', '1. Syntax error' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({header = {'You know the rules', 'Search'}}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = + vim.diagnostic.open_float({ header = { 'You know the rules', 'Search' } }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) end) it('can show diagnostics from the whole buffer', function() eq( { '1. Syntax error', '2. Some warning' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - make_warning("Some warning", 1, 1, 1, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({header = false, scope="buffer"}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + _G.make_warning('Some warning', 1, 1, 1, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'buffer' }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) end) @@ -2136,37 +2488,70 @@ describe('vim.diagnostic', function() -- Using cursor position eq( { '1. Some warning' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - make_warning("Some warning", 1, 1, 1, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - vim.api.nvim_win_set_cursor(0, {2, 1}) - local float_bufnr, winnr = vim.diagnostic.open_float({header=false}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + _G.make_warning('Some warning', 1, 1, 1, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, { 2, 1 }) + local float_bufnr, winnr = vim.diagnostic.open_float({ header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) -- With specified position eq( { '1. Some warning' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - make_warning("Some warning", 1, 1, 1, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - vim.api.nvim_win_set_cursor(0, {1, 1}) - local float_bufnr, winnr = vim.diagnostic.open_float({header=false, pos=1}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + _G.make_warning('Some warning', 1, 1, 1, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, { 1, 1 }) + local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, pos = 1 }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) + ) + + -- End position is exclusive + eq( + nil, + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 1, 1, 2, 0), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, { 1, 1 }) + local _, winnr = vim.diagnostic.open_float(0, { header = false, pos = { 2, 0 } }) + return winnr + end) + ) + + -- Works when width == 0 + eq( + { '1. Syntax error' }, + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 2, 0, 2, 0), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, { 1, 1 }) + local float_bufnr, winnr = + vim.diagnostic.open_float(0, { header = false, pos = { 2, 1 } }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) end) @@ -2174,55 +2559,94 @@ describe('vim.diagnostic', function() -- Using cursor position eq( { 'Syntax error' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 1, 1, 1, 2), - make_warning("Some warning", 1, 3, 1, 4), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - vim.api.nvim_win_set_cursor(0, {2, 2}) - local float_bufnr, winnr = vim.diagnostic.open_float({header=false, scope="cursor"}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 1, 1, 1, 3), + _G.make_warning('Some warning', 1, 3, 1, 4), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, { 2, 2 }) + local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'cursor' }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) -- With specified position eq( { 'Some warning' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 1, 1, 1, 2), - make_warning("Some warning", 1, 3, 1, 4), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - vim.api.nvim_win_set_cursor(0, {1, 1}) - local float_bufnr, winnr = vim.diagnostic.open_float({header=false, scope="cursor", pos={1,3}}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 1, 1, 1, 3), + _G.make_warning('Some warning', 1, 3, 1, 4), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, { 1, 1 }) + local float_bufnr, winnr = + vim.diagnostic.open_float({ header = false, scope = 'cursor', pos = { 1, 3 } }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) -- With column position past the end of the line. #16062 eq( { 'Syntax error' }, - exec_lua [[ - local first_line_len = #vim.api.nvim_buf_get_lines(diagnostic_bufnr, 0, 1, true)[1] - local diagnostics = { - make_error("Syntax error", 0, first_line_len + 1, 1, 0), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - vim.api.nvim_win_set_cursor(0, {1, 1}) - local float_bufnr, winnr = vim.diagnostic.open_float({header=false, scope="cursor", pos={0,first_line_len}}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local first_line_len = #vim.api.nvim_buf_get_lines(_G.diagnostic_bufnr, 0, 1, true)[1] + local diagnostics = { + _G.make_error('Syntax error', 0, first_line_len + 1, 1, 0), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, { 1, 1 }) + local float_bufnr, winnr = vim.diagnostic.open_float({ + header = false, + scope = 'cursor', + pos = { 0, first_line_len }, + }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) + ) + + -- End position is exclusive + eq( + nil, + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 1, 1, 1, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, { 1, 1 }) + local _, winnr = + vim.diagnostic.open_float(0, { header = false, scope = 'cursor', pos = { 1, 3 } }) + return winnr + end) + ) + + -- Works when width == 0 + eq( + { 'Syntax error' }, + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 2, 0, 2, 0), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + vim.api.nvim_win_set_cursor(0, { 1, 1 }) + local float_bufnr, winnr = + vim.diagnostic.open_float({ header = false, scope = 'cursor', pos = { 2, 1 } }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) end) @@ -2234,17 +2658,17 @@ describe('vim.diagnostic', function() -- 1. <msg> eq( 2, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return #lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float(_G.diagnostic_bufnr) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return #lines + end) ) end ) @@ -2252,43 +2676,44 @@ describe('vim.diagnostic', function() it('only reports diagnostics from the current buffer when bufnr is omitted #15710', function() eq( 2, - exec_lua [[ - local other_bufnr = vim.api.nvim_create_buf(true, false) - local buf_1_diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - } - local buf_2_diagnostics = { - make_warning("Some warning", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, buf_1_diagnostics) - vim.diagnostic.set(other_ns, other_bufnr, buf_2_diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float() - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return #lines - ]] + exec_lua(function() + local other_bufnr = vim.api.nvim_create_buf(true, false) + local buf_1_diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + } + local buf_2_diagnostics = { + _G.make_warning('Some warning', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, buf_1_diagnostics) + vim.diagnostic.set(_G.other_ns, other_bufnr, buf_2_diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float() + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return #lines + end) ) end) it('allows filtering by namespace', function() eq( 2, - exec_lua [[ - local ns_1_diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - } - local ns_2_diagnostics = { - make_warning("Some warning", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diagnostics) - vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, {namespace = diagnostic_ns}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return #lines - ]] + exec_lua(function() + local ns_1_diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + } + local ns_2_diagnostics = { + _G.make_warning('Some warning', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diagnostics) + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diagnostics) + local float_bufnr, winnr = + vim.diagnostic.open_float(_G.diagnostic_bufnr, { namespace = _G.diagnostic_ns }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return #lines + end) ) end) @@ -2299,17 +2724,18 @@ describe('vim.diagnostic', function() -- 1. <msg> eq( 1, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, {header = false}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return #lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = + vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return #lines + end) ) end ) @@ -2317,138 +2743,141 @@ describe('vim.diagnostic', function() it('clamps diagnostic line numbers within the valid range', function() eq( 1, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 6, 0, 6, 0), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, {header = false, pos = 5}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return #lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 6, 0, 6, 0), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = + vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false, pos = 5 }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return #lines + end) ) end) it('can show diagnostic source', function() - exec_lua [[vim.api.nvim_win_set_buf(0, diagnostic_bufnr)]] + exec_lua [[vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)]] eq( { '1. Syntax error' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3, "source x"), - } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { - header = false, - source = "if_many", - }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3, 'source x'), + } + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float(_G.diagnostic_bufnr, { + header = false, + source = 'if_many', + }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { '1. source x: Syntax error' }, - exec_lua [[ - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { - header = false, - source = "always", - }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local float_bufnr, winnr = vim.diagnostic.open_float(_G.diagnostic_bufnr, { + header = false, + source = 'always', + }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { '1. source x: Syntax error', '2. source y: Another error' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3, "source x"), - make_error("Another error", 0, 1, 0, 3, "source y"), - } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { - header = false, - source = "if_many", - }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3, 'source x'), + _G.make_error('Another error', 0, 1, 0, 3, 'source y'), + } + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float(_G.diagnostic_bufnr, { + header = false, + source = 'if_many', + }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) end) it('respects severity_sort', function() - exec_lua [[vim.api.nvim_win_set_buf(0, diagnostic_bufnr)]] + exec_lua [[vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)]] eq( { '1. Syntax error', '2. Info', '3. Error', '4. Warning' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - make_info('Info', 0, 3, 0, 4), - make_error('Error', 0, 2, 0, 2), - make_warning('Warning', 0, 0, 0, 1), - } + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + _G.make_info('Info', 0, 3, 0, 4), + _G.make_error('Error', 0, 2, 0, 2), + _G.make_warning('Warning', 0, 0, 0, 1), + } - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) - vim.diagnostic.config({severity_sort = false}) + vim.diagnostic.config({ severity_sort = false }) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { header = false }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + local float_bufnr, winnr = + vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { '1. Syntax error', '2. Error', '3. Warning', '4. Info' }, - exec_lua [[ - vim.diagnostic.config({severity_sort = true}) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { header = false }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + vim.diagnostic.config({ severity_sort = true }) + local float_bufnr, winnr = + vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { '1. Info', '2. Warning', '3. Error', '4. Syntax error' }, - exec_lua [[ - vim.diagnostic.config({severity_sort = { reverse = true } }) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { header = false }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + vim.diagnostic.config({ severity_sort = { reverse = true } }) + local float_bufnr, winnr = + vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) end) it('can filter by severity', function() local count_diagnostics_with_severity = function(min_severity, max_severity) - return exec_lua( - [[ - local min_severity, max_severity = ... + return exec_lua(function() vim.diagnostic.config({ float = { - severity = {min=min_severity, max=max_severity}, + severity = { min = min_severity, max = max_severity }, }, }) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error("Syntax error", 0, 1, 0, 3), - make_info('Info', 0, 3, 0, 4), - make_error('Error', 0, 2, 0, 2), - make_warning('Warning', 0, 0, 0, 1), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Syntax error', 0, 1, 0, 3), + _G.make_info('Info', 0, 3, 0, 4), + _G.make_error('Error', 0, 2, 0, 2), + _G.make_warning('Warning', 0, 0, 0, 1), }) - local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { header = false }) + local float_bufnr, winnr = + vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false }) if not float_bufnr then return 0 end @@ -2456,10 +2885,7 @@ describe('vim.diagnostic', function() local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return #lines - ]], - min_severity, - max_severity - ) + end) end eq(2, count_diagnostics_with_severity('ERROR')) @@ -2473,83 +2899,84 @@ describe('vim.diagnostic', function() -- Default is to add a number eq( { '1. Syntax error', '2. Some warning' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - make_warning("Some warning", 1, 1, 1, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({header = false, scope = "buffer"}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + _G.make_warning('Some warning', 1, 1, 1, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'buffer' }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { 'Syntax error', 'Some warning' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - make_warning("Some warning", 1, 1, 1, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({header = false, scope = "buffer", prefix = ""}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + _G.make_warning('Some warning', 1, 1, 1, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = + vim.diagnostic.open_float({ header = false, scope = 'buffer', prefix = '' }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { '1. Syntax error', '2. Some warning' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - make_warning("Some warning", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({ - header = false, - prefix = function(_, i, total) - -- Only show a number if there is more than one diagnostic - if total > 1 then - return string.format("%d. ", i) - end - return "" - end, - }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + _G.make_warning('Some warning', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float({ + header = false, + prefix = function(_, i, total) + -- Only show a number if there is more than one diagnostic + if total > 1 then + return string.format('%d. ', i) + end + return '' + end, + }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { 'Syntax error' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({ - header = false, - prefix = function(_, i, total) - -- Only show a number if there is more than one diagnostic - if total > 1 then - return string.format("%d. ", i) - end - return "" - end, - }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float({ + header = false, + prefix = function(_, i, total) + -- Only show a number if there is more than one diagnostic + if total > 1 then + return string.format('%d. ', i) + end + return '' + end, + }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( @@ -2562,50 +2989,51 @@ describe('vim.diagnostic', function() -- Default is to render the diagnostic error code eq( { '1. Syntax error [code-x]', '2. Some warning [code-y]' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3, nil, "code-x"), - make_warning("Some warning", 1, 1, 1, 3, nil, "code-y"), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({header = false, scope = "buffer"}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3, nil, 'code-x'), + _G.make_warning('Some warning', 1, 1, 1, 3, nil, 'code-y'), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'buffer' }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( { '1. Syntax error', '2. Some warning' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3, nil, "code-x"), - make_warning("Some warning", 1, 1, 1, 3, nil, "code-y"), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({header = false, scope = "buffer", suffix = ""}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3, nil, 'code-x'), + _G.make_warning('Some warning', 1, 1, 1, 3, nil, 'code-y'), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = + vim.diagnostic.open_float({ header = false, scope = 'buffer', suffix = '' }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) -- Suffix is rendered on the last line of a multiline diagnostic eq( { '1. Syntax error', ' More context [code-x]' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error\nMore context", 0, 1, 0, 3, nil, "code-x"), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float({header = false, scope = "buffer"}) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error\nMore context', 0, 1, 0, 3, nil, 'code-x'), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'buffer' }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) eq( @@ -2617,96 +3045,134 @@ describe('vim.diagnostic', function() it('works with the old signature', function() eq( { '1. Syntax error' }, - exec_lua [[ - local diagnostics = { - make_error("Syntax error", 0, 1, 0, 3), - } - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + local diagnostics = { + _G.make_error('Syntax error', 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) end) it('works for multi-line diagnostics #21949', function() - -- open float failed non diagnostic lnum - eq( - vim.NIL, - exec_lua [[ + -- create diagnostic + exec_lua(function() local diagnostics = { - make_error("Error in two lines lnum is 1 and end_lnum is 2", 1, 1, 2, 3), + _G.make_error('Error in two lines lnum is 1 and end_lnum is 2', 1, 1, 2, 3), } - local winids = {} - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local _, winnr = vim.diagnostic.open_float(0, { header = false }) - return winnr - ]] + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + end) + + -- open float failed non diagnostic lnum + eq( + nil, + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + local _, winnr = vim.diagnostic.open_float(0, { header = false }) + return winnr + end) + ) + eq( + nil, + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + local _, winnr = vim.diagnostic.open_float(0, { header = false, scope = 'cursor' }) + return winnr + end) ) -- can open a float window on lnum 1 eq( { '1. Error in two lines lnum is 1 and end_lnum is 2' }, - exec_lua [[ - vim.api.nvim_win_set_cursor(0, {2, 0}) - local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 2, 0 }) + local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) + ) + + -- can open a cursor-scoped float window on lnum 1 + eq( + { 'Error in two lines lnum is 1 and end_lnum is 2' }, + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 2, 1 }) + local float_bufnr, winnr = + vim.diagnostic.open_float(0, { header = false, scope = 'cursor' }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) -- can open a float window on end_lnum 2 eq( { '1. Error in two lines lnum is 1 and end_lnum is 2' }, - exec_lua [[ - vim.api.nvim_win_set_cursor(0, {3, 0}) - local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false }) - local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) - vim.api.nvim_win_close(winnr, true) - return lines - ]] + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 3, 0 }) + local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) + ) + + -- can open a cursor-scoped float window on end_lnum 2 + eq( + { 'Error in two lines lnum is 1 and end_lnum is 2' }, + exec_lua(function() + vim.api.nvim_win_set_cursor(0, { 3, 2 }) + local float_bufnr, winnr = + vim.diagnostic.open_float(0, { header = false, scope = 'cursor' }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + end) ) end) end) describe('setloclist()', function() it('sets diagnostics in lnum order', function() - local loc_list = exec_lua [[ - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + local loc_list = exec_lua(function() + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Farther Diagnostic', 4, 4, 4, 4), - make_error('Lower Diagnostic', 1, 1, 1, 1), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Farther Diagnostic', 4, 4, 4, 4), + _G.make_error('Lower Diagnostic', 1, 1, 1, 1), }) vim.diagnostic.setloclist() return vim.fn.getloclist(0) - ]] + end) assert(loc_list[1].lnum < loc_list[2].lnum) end) it('sets diagnostics in lnum order, regardless of namespace', function() - local loc_list = exec_lua [[ - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + local loc_list = exec_lua(function() + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Lower Diagnostic', 1, 1, 1, 1), + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Lower Diagnostic', 1, 1, 1, 1), }) - vim.diagnostic.set(other_ns, diagnostic_bufnr, { - make_warning('Farther Diagnostic', 4, 4, 4, 4), + vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, { + _G.make_warning('Farther Diagnostic', 4, 4, 4, 4), }) vim.diagnostic.setloclist() return vim.fn.getloclist(0) - ]] + end) assert(loc_list[1].lnum < loc_list[2].lnum) end) @@ -2725,22 +3191,23 @@ describe('vim.diagnostic', function() } eq( diagnostic, - exec_lua( - [[ - return vim.diagnostic.match(..., "^(%w+): [^:]+:(%d+):(%d+):(.+)$", {"severity", "lnum", "col", "message"}) - ]], - msg - ) + exec_lua(function() + return vim.diagnostic.match( + msg, + '^(%w+): [^:]+:(%d+):(%d+):(.+)$', + { 'severity', 'lnum', 'col', 'message' } + ) + end) ) end) it('returns nil if the pattern fails to match', function() eq( - NIL, - exec_lua [[ - local msg = "The answer to life, the universe, and everything is" - return vim.diagnostic.match(msg, "This definitely will not match", {}) - ]] + nil, + exec_lua(function() + local msg = 'The answer to life, the universe, and everything is' + return vim.diagnostic.match(msg, 'This definitely will not match', {}) + end) ) end) @@ -2756,12 +3223,15 @@ describe('vim.diagnostic', function() } eq( diagnostic, - exec_lua( - [[ - return vim.diagnostic.match(..., "^[^:]+:(%d+):(.+)$", {"lnum", "message"}, nil, {severity = vim.diagnostic.severity.INFO}) - ]], - msg - ) + exec_lua(function() + return vim.diagnostic.match( + msg, + '^[^:]+:(%d+):(.+)$', + { 'lnum', 'message' }, + nil, + { severity = vim.diagnostic.severity.INFO } + ) + end) ) end) @@ -2777,38 +3247,40 @@ describe('vim.diagnostic', function() } eq( diagnostic, - exec_lua( - [[ - return vim.diagnostic.match(..., "^(%d+):(%w+):(.+)$", {"lnum", "severity", "message"}, {FATAL = vim.diagnostic.severity.ERROR}) - ]], - msg - ) + exec_lua(function() + return vim.diagnostic.match( + msg, + '^(%d+):(%w+):(.+)$', + { 'lnum', 'severity', 'message' }, + { FATAL = vim.diagnostic.severity.ERROR } + ) + end) ) end) end) describe('toqflist() and fromqflist()', function() it('works', function() - local result = exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Error 1', 0, 1, 0, 1), - make_error('Error 2', 1, 1, 1, 1), - make_warning('Warning', 2, 2, 2, 2), - }) + local result = exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Error 1', 0, 1, 0, 1), + _G.make_error('Error 2', 1, 1, 1, 1), + _G.make_warning('Warning', 2, 2, 2, 2), + }) - local diagnostics = vim.diagnostic.get(diagnostic_bufnr) - vim.fn.setqflist(vim.diagnostic.toqflist(diagnostics)) - local list = vim.fn.getqflist() - local new_diagnostics = vim.diagnostic.fromqflist(list) + local diagnostics = vim.diagnostic.get(_G.diagnostic_bufnr) + vim.fn.setqflist(vim.diagnostic.toqflist(diagnostics)) + local list = vim.fn.getqflist() + local new_diagnostics = vim.diagnostic.fromqflist(list) - -- Remove namespace since it isn't present in the return value of - -- fromlist() - for _, v in ipairs(diagnostics) do - v.namespace = nil - end + -- Remove namespace since it isn't present in the return value of + -- fromlist() + for _, v in ipairs(diagnostics) do + v.namespace = nil + end - return {diagnostics, new_diagnostics} - ]] + return { diagnostics, new_diagnostics } + end) eq(result[1], result[2]) end) end) @@ -2828,179 +3300,181 @@ describe('vim.diagnostic', function() it('can add new handlers', function() eq( true, - exec_lua [[ - local handler_called = false - vim.diagnostic.handlers.test = { - show = function(namespace, bufnr, diagnostics, opts) - assert(namespace == diagnostic_ns) - assert(bufnr == diagnostic_bufnr) - assert(#diagnostics == 1) - assert(opts.test.some_opt == 42) - handler_called = true - end, - } + exec_lua(function() + local handler_called = false + vim.diagnostic.handlers.test = { + show = function(namespace, bufnr, diagnostics, opts) + assert(namespace == _G.diagnostic_ns) + assert(bufnr == _G.diagnostic_bufnr) + assert(#diagnostics == 1) + assert(opts.test.some_opt == 42) + handler_called = true + end, + } - vim.diagnostic.config({test = {some_opt = 42}}) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_warning("Warning", 0, 0, 0, 0), - }) - return handler_called - ]] + vim.diagnostic.config({ test = { some_opt = 42 } }) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_warning('Warning', 0, 0, 0, 0), + }) + return handler_called + end) ) end) it('can disable handlers by setting the corresponding option to false', function() eq( false, - exec_lua [[ - local handler_called = false - vim.diagnostic.handlers.test = { - show = function(namespace, bufnr, diagnostics, opts) - handler_called = true - end, - } + exec_lua(function() + local handler_called = false + vim.diagnostic.handlers.test = { + show = function(_, _, _, _) + handler_called = true + end, + } - vim.diagnostic.config({test = false}) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_warning("Warning", 0, 0, 0, 0), - }) - return handler_called - ]] + vim.diagnostic.config({ test = false }) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_warning('Warning', 0, 0, 0, 0), + }) + return handler_called + end) ) end) it("always calls a handler's hide function if defined", function() eq( { false, true }, - exec_lua [[ - local hide_called = false - local show_called = false - vim.diagnostic.handlers.test = { - show = function(namespace, bufnr, diagnostics, opts) - show_called = true - end, - hide = function(namespace, bufnr) - assert(namespace == diagnostic_ns) - assert(bufnr == diagnostic_bufnr) - hide_called = true - end, - } + exec_lua(function() + local hide_called = false + local show_called = false + vim.diagnostic.handlers.test = { + show = function(_, _, _, _) + show_called = true + end, + hide = function(namespace, bufnr) + assert(namespace == _G.diagnostic_ns) + assert(bufnr == _G.diagnostic_bufnr) + hide_called = true + end, + } - vim.diagnostic.config({test = false}) - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_warning("Warning", 0, 0, 0, 0), - }) - vim.diagnostic.hide(diagnostic_ns, diagnostic_bufnr) - return {show_called, hide_called} - ]] + vim.diagnostic.config({ test = false }) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_warning('Warning', 0, 0, 0, 0), + }) + vim.diagnostic.hide(_G.diagnostic_ns, _G.diagnostic_bufnr) + return { show_called, hide_called } + end) ) end) it('triggers the autocommand when diagnostics are set', function() eq( { true, true }, - exec_lua [[ - -- Set a different buffer as current to test that <abuf> is being set properly in - -- DiagnosticChanged callbacks - local tmp = vim.api.nvim_create_buf(false, true) - vim.api.nvim_set_current_buf(tmp) - - local triggered = {} - vim.api.nvim_create_autocmd('DiagnosticChanged', { - callback = function(args) - triggered = {args.buf, #args.data.diagnostics} - end, - }) - vim.api.nvim_buf_set_name(diagnostic_bufnr, "test | test") - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic', 0, 0, 0, 0) - }) - return { - triggered[1] == diagnostic_bufnr, - triggered[2] == 1, - } - ]] + exec_lua(function() + -- Set a different buffer as current to test that <abuf> is being set properly in + -- DiagnosticChanged callbacks + local tmp = vim.api.nvim_create_buf(false, true) + vim.api.nvim_set_current_buf(tmp) + + local triggered = {} + vim.api.nvim_create_autocmd('DiagnosticChanged', { + callback = function(args) + triggered = { args.buf, #args.data.diagnostics } + end, + }) + vim.api.nvim_buf_set_name(_G.diagnostic_bufnr, 'test | test') + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic', 0, 0, 0, 0), + }) + return { + triggered[1] == _G.diagnostic_bufnr, + triggered[2] == 1, + } + end) ) end) it('triggers the autocommand when diagnostics are cleared', function() eq( true, - exec_lua [[ - local tmp = vim.api.nvim_create_buf(false, true) - vim.api.nvim_set_current_buf(tmp) - vim.g.diagnostic_autocmd_triggered = 0 - vim.cmd('autocmd DiagnosticChanged * let g:diagnostic_autocmd_triggered = +expand("<abuf>")') - vim.api.nvim_buf_set_name(diagnostic_bufnr, "test | test") - vim.diagnostic.reset(diagnostic_ns, diagnostic_bufnr) - return vim.g.diagnostic_autocmd_triggered == diagnostic_bufnr - ]] + exec_lua(function() + local tmp = vim.api.nvim_create_buf(false, true) + vim.api.nvim_set_current_buf(tmp) + vim.g.diagnostic_autocmd_triggered = 0 + vim.cmd( + 'autocmd DiagnosticChanged * let g:diagnostic_autocmd_triggered = +expand("<abuf>")' + ) + vim.api.nvim_buf_set_name(_G.diagnostic_bufnr, 'test | test') + vim.diagnostic.reset(_G.diagnostic_ns, _G.diagnostic_bufnr) + return vim.g.diagnostic_autocmd_triggered == _G.diagnostic_bufnr + end) ) end) it('is_enabled', function() eq( { false, false, false, false, false }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - }) - vim.api.nvim_set_current_buf(diagnostic_bufnr) - vim.diagnostic.enable(false) - return { - vim.diagnostic.is_enabled(), - vim.diagnostic.is_enabled{ bufnr = 0 }, - vim.diagnostic.is_enabled{ bufnr = diagnostic_bufnr }, - vim.diagnostic.is_enabled{ bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }, - vim.diagnostic.is_enabled{ bufnr = 0, ns_id = diagnostic_ns }, - } - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + }) + vim.api.nvim_set_current_buf(_G.diagnostic_bufnr) + vim.diagnostic.enable(false) + return { + vim.diagnostic.is_enabled(), + vim.diagnostic.is_enabled { bufnr = 0 }, + vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr }, + vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }, + vim.diagnostic.is_enabled { bufnr = 0, ns_id = _G.diagnostic_ns }, + } + end) ) eq( { true, true, true, true, true }, - exec_lua [[ - vim.diagnostic.enable() - return { - vim.diagnostic.is_enabled(), - vim.diagnostic.is_enabled{ bufnr = 0 }, - vim.diagnostic.is_enabled{ bufnr = diagnostic_bufnr }, - vim.diagnostic.is_enabled{ bufnr = diagnostic_bufnr, ns_id = diagnostic_ns }, - vim.diagnostic.is_enabled{ bufnr = 0, ns_id = diagnostic_ns }, - } - ]] + exec_lua(function() + vim.diagnostic.enable() + return { + vim.diagnostic.is_enabled(), + vim.diagnostic.is_enabled { bufnr = 0 }, + vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr }, + vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns }, + vim.diagnostic.is_enabled { bufnr = 0, ns_id = _G.diagnostic_ns }, + } + end) ) end) it('is_disabled (deprecated)', function() eq( { true, true, true, true }, - exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - }) - vim.api.nvim_set_current_buf(diagnostic_bufnr) - vim.diagnostic.disable() - return { - vim.diagnostic.is_disabled(), - vim.diagnostic.is_disabled(diagnostic_bufnr), - vim.diagnostic.is_disabled(diagnostic_bufnr, diagnostic_ns), - vim.diagnostic.is_disabled(_, diagnostic_ns), - } - ]] + exec_lua(function() + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { + _G.make_error('Diagnostic #1', 1, 1, 1, 1), + }) + vim.api.nvim_set_current_buf(_G.diagnostic_bufnr) + vim.diagnostic.disable() + return { + vim.diagnostic.is_disabled(), + vim.diagnostic.is_disabled(_G.diagnostic_bufnr), + vim.diagnostic.is_disabled(_G.diagnostic_bufnr, _G.diagnostic_ns), + vim.diagnostic.is_disabled(0, _G.diagnostic_ns), + } + end) ) eq( { false, false, false, false }, - exec_lua [[ - vim.diagnostic.enable() - return { - vim.diagnostic.is_disabled(), - vim.diagnostic.is_disabled(diagnostic_bufnr), - vim.diagnostic.is_disabled(diagnostic_bufnr, diagnostic_ns), - vim.diagnostic.is_disabled(_, diagnostic_ns), - } - ]] + exec_lua(function() + vim.diagnostic.enable() + return { + vim.diagnostic.is_disabled(), + vim.diagnostic.is_disabled(_G.diagnostic_bufnr), + vim.diagnostic.is_disabled(_G.diagnostic_bufnr, _G.diagnostic_ns), + vim.diagnostic.is_disabled(0, _G.diagnostic_ns), + } + end) ) end) end) diff --git a/test/functional/lua/ffi_spec.lua b/test/functional/lua/ffi_spec.lua index 85ca264107..96f5812493 100644 --- a/test/functional/lua/ffi_spec.lua +++ b/test/functional/lua/ffi_spec.lua @@ -15,27 +15,27 @@ describe('ffi.cdef', function() eq( 12, - exec_lua [=[ - local ffi = require('ffi') + exec_lua(function() + local ffi = require('ffi') - ffi.cdef [[ + ffi.cdef [[ typedef struct window_S win_T; int win_col_off(win_T *wp); extern win_T *curwin; ]] - vim.cmd('set number numberwidth=4 signcolumn=yes:4') + vim.cmd('set number numberwidth=4 signcolumn=yes:4') - return ffi.C.win_col_off(ffi.C.curwin) - ]=] + return ffi.C.win_col_off(ffi.C.curwin) + end) ) eq( 20, - exec_lua [=[ - local ffi = require('ffi') + exec_lua(function() + local ffi = require('ffi') - ffi.cdef[[ + ffi.cdef [[ typedef struct {} stl_hlrec_t; typedef struct {} StlClickRecord; typedef struct {} statuscol_T; @@ -58,32 +58,32 @@ describe('ffi.cdef', function() ); ]] - return ffi.C.build_stl_str_hl( - ffi.C.find_window_by_handle(0, ffi.new('Error')), - ffi.new('char[1024]'), - 1024, - ffi.cast('char*', 'StatusLineOfLength20'), - -1, - 0, - 0, - 0, - nil, - nil, - nil - ) - ]=] + return ffi.C.build_stl_str_hl( + ffi.C.find_window_by_handle(0, ffi.new('Error')), + ffi.new('char[1024]'), + 1024, + ffi.cast('char*', 'StatusLineOfLength20'), + -1, + 0, + 0, + 0, + nil, + nil, + nil + ) + end) ) -- Check that extern symbols are exported and accessible eq( true, - exec_lua [[ - local ffi = require('ffi') + exec_lua(function() + local ffi = require('ffi') - ffi.cdef('uint64_t display_tick;') + ffi.cdef('uint64_t display_tick;') - return ffi.C.display_tick >= 0 - ]] + return ffi.C.display_tick >= 0 + end) ) end) end) diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua index 7db04e6f6b..574c837f92 100644 --- a/test/functional/lua/filetype_spec.lua +++ b/test/functional/lua/filetype_spec.lua @@ -18,90 +18,82 @@ describe('vim.filetype', function() before_each(function() clear() - exec_lua [[ + exec_lua(function() local bufnr = vim.api.nvim_create_buf(true, false) vim.api.nvim_set_current_buf(bufnr) - ]] + end) end) it('works with extensions', function() eq( 'radicalscript', - exec_lua [[ - vim.filetype.add({ - extension = { - rs = 'radicalscript', - }, - }) - return vim.filetype.match({ filename = 'main.rs' }) - ]] + exec_lua(function() + vim.filetype.add({ + extension = { + rs = 'radicalscript', + }, + }) + return vim.filetype.match({ filename = 'main.rs' }) + end) ) end) it('prioritizes filenames over extensions', function() eq( 'somethingelse', - exec_lua [[ - vim.filetype.add({ - extension = { - rs = 'radicalscript', - }, - filename = { - ['main.rs'] = 'somethingelse', - }, - }) - return vim.filetype.match({ filename = 'main.rs' }) - ]] + exec_lua(function() + vim.filetype.add({ + extension = { + rs = 'radicalscript', + }, + filename = { + ['main.rs'] = 'somethingelse', + }, + }) + return vim.filetype.match({ filename = 'main.rs' }) + end) ) end) it('works with filenames', function() eq( 'nim', - exec_lua [[ - vim.filetype.add({ - filename = { - ['s_O_m_e_F_i_l_e'] = 'nim', - }, - }) - return vim.filetype.match({ filename = 's_O_m_e_F_i_l_e' }) - ]] + exec_lua(function() + vim.filetype.add({ + filename = { + ['s_O_m_e_F_i_l_e'] = 'nim', + }, + }) + return vim.filetype.match({ filename = 's_O_m_e_F_i_l_e' }) + end) ) eq( 'dosini', - exec_lua( - [[ - local root = ... - vim.filetype.add({ - filename = { - ['config'] = 'toml', - [root .. '/.config/fun/config'] = 'dosini', - }, - }) - return vim.filetype.match({ filename = root .. '/.config/fun/config' }) - ]], - root - ) + exec_lua(function() + vim.filetype.add({ + filename = { + ['config'] = 'toml', + [root .. '/.config/fun/config'] = 'dosini', + }, + }) + return vim.filetype.match({ filename = root .. '/.config/fun/config' }) + end) ) end) it('works with patterns', function() eq( 'markdown', - exec_lua( - [[ - local root = ... - vim.env.HOME = '/a-funky+home%dir' - vim.filetype.add({ - pattern = { - ['~/blog/.*%.txt'] = 'markdown', - } - }) - return vim.filetype.match({ filename = '~/blog/why_neovim_is_awesome.txt' }) - ]], - root - ) + exec_lua(function() + vim.env.HOME = '/a-funky+home%dir' + vim.filetype.add({ + pattern = { + ['~/blog/.*%.txt'] = 'markdown', + }, + }) + return vim.filetype.match({ filename = '~/blog/why_neovim_is_awesome.txt' }) + end) ) end) @@ -110,43 +102,43 @@ describe('vim.filetype', function() command('file relevant_to_me') eq( 'foss', - exec_lua [[ - vim.filetype.add({ - pattern = { - ["relevant_to_(%a+)"] = function(path, bufnr, capture) - if capture == "me" then - return "foss" - end - end, - } - }) - return vim.filetype.match({ buf = 0 }) - ]] + exec_lua(function() + vim.filetype.add({ + pattern = { + ['relevant_to_(%a+)'] = function(_, _, capture) + if capture == 'me' then + return 'foss' + end + end, + }, + }) + return vim.filetype.match({ buf = 0 }) + end) ) 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' } }) - ]] + exec_lua(function() + -- 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) ) 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' } }) - ]] + exec_lua(function() + vim.filetype.add({ + extension = { + foo = 'fooscript', + }, + }) + return vim.filetype.match({ contents = { '#!/usr/bin/env foo' } }) + end) ) end) @@ -160,7 +152,12 @@ describe('vim.filetype', function() xml = { formatexpr = 'xmlformat#Format()' }, } do for option, value in pairs(opts) do - eq(value, exec_lua([[ return vim.filetype.get_option(...) ]], ft, option)) + eq( + value, + exec_lua(function() + return vim.filetype.get_option(ft, option) + end) + ) end end end) diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua index aba02ab01b..f0d49205e7 100644 --- a/test/functional/lua/fs_spec.lua +++ b/test/functional/lua/fs_spec.lua @@ -141,19 +141,14 @@ describe('vim.fs', function() it('works', function() eq( true, - exec_lua( - [[ - local dir, nvim = ... - for name, type in vim.fs.dir(dir) do - if name == nvim and type == 'file' then - return true + exec_lua(function() + for name, type in vim.fs.dir(nvim_dir) do + if name == nvim_prog_basename and type == 'file' then + return true + end end - end - return false - ]], - nvim_dir, - nvim_prog_basename - ) + return false + end) ) end) @@ -172,14 +167,12 @@ describe('vim.fs', function() io.open('testd/a/b/c/c4', 'w'):close() local function run(dir, depth, skip) - local r = exec_lua( - [[ - local dir, depth, skip = ... + return exec_lua(function() local r = {} local skip_f if skip then - skip_f = function(n) - if vim.tbl_contains(skip or {}, n) then + skip_f = function(n0) + if vim.tbl_contains(skip or {}, n0) then return false end end @@ -188,12 +181,7 @@ describe('vim.fs', function() r[name] = type_ end return r - ]], - dir, - depth, - skip - ) - return r + end) end local exp = {} @@ -263,13 +251,12 @@ describe('vim.fs', function() opts = { path = test_source_path .. '/contrib', limit = math.huge } eq( - exec_lua( - [[ - local dir = ... - return vim.tbl_map(vim.fs.basename, vim.fn.glob(dir..'/contrib/*', false, true)) - ]], - test_source_path - ), + exec_lua(function() + return vim.tbl_map( + vim.fs.basename, + vim.fn.glob(test_source_path .. '/contrib/*', false, true) + ) + end), vim.tbl_map( vim.fs.basename, vim.fs.find(function(_, d) @@ -299,11 +286,11 @@ describe('vim.fs', function() it('works with a function', function() ---@type string - local result = exec_lua([[ - return vim.fs.root(0, function(name, path) + local result = exec_lua(function() + return vim.fs.root(0, function(name, _) return name:match('%.txt$') end) - ]]) + end) eq(vim.fs.joinpath(test_source_path, 'test/functional/fixtures'), result) end) @@ -352,13 +339,10 @@ describe('vim.fs', function() local xdg_config_home = test_build_dir .. '/.config' eq( xdg_config_home .. '/nvim', - exec_lua( - [[ - vim.env.XDG_CONFIG_HOME = ... - return vim.fs.normalize('$XDG_CONFIG_HOME/nvim') - ]], - xdg_config_home - ) + exec_lua(function() + vim.env.XDG_CONFIG_HOME = xdg_config_home + return vim.fs.normalize('$XDG_CONFIG_HOME/nvim') + end) ) end) diff --git a/test/functional/lua/glob_spec.lua b/test/functional/lua/glob_spec.lua index 56cd4c9bb5..8302c7334d 100644 --- a/test/functional/lua/glob_spec.lua +++ b/test/functional/lua/glob_spec.lua @@ -2,21 +2,15 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() local eq = t.eq -local exec_lua = n.exec_lua describe('glob', function() before_each(n.clear) after_each(n.clear) - local match = function(...) - return exec_lua( - [[ - local pattern = select(1, ...) - local str = select(2, ...) - return require("vim.glob").to_lpeg(pattern):match(str) ~= nil - ]], - ... - ) + local match = function(pattern, str) + return n.exec_lua(function() + return require('vim.glob').to_lpeg(pattern):match(str) ~= nil + end) end describe('glob matching', function() @@ -161,7 +155,7 @@ describe('glob', function() eq(false, match('{ab,cd}', 'a')) eq(true, match('{ab,cd}', 'cd')) eq(true, match('{a,b,c}', 'c')) - eq(true, match('{a,{b,c}}', 'c')) + eq(false, match('{a,{b,c}}', 'c')) -- {} cannot nest end) it('should match [] groups', function() @@ -205,6 +199,19 @@ describe('glob', function() eq(true, match('[!a-zA-Z0-9]', '!')) end) + it('should handle long patterns', function() + -- lpeg has a recursion limit of 200 by default, make sure the grammar does trigger it on + -- strings longer than that + local fill_200 = + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + eq(200, fill_200:len()) + local long_lit = fill_200 .. 'a' + eq(false, match(long_lit, 'b')) + eq(true, match(long_lit, long_lit)) + local long_pat = fill_200 .. 'a/**/*.c' + eq(true, match(long_pat, fill_200 .. 'a/b/c/d.c')) + end) + it('should match complex patterns', function() eq(false, match('**/*.{c,h}', '')) eq(false, match('**/*.{c,h}', 'c')) @@ -223,6 +230,17 @@ describe('glob', function() eq(true, match('{[0-9],[a-z]}', '0')) eq(true, match('{[0-9],[a-z]}', 'a')) eq(false, match('{[0-9],[a-z]}', 'A')) + + -- glob is from willRename filter in typescript-language-server + -- https://github.com/typescript-language-server/typescript-language-server/blob/b224b878652438bcdd639137a6b1d1a6630129e4/src/lsp-server.ts#L266 + eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.js')) + eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.ts')) + eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.mts')) + eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.mjs')) + eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.cjs')) + eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.cts')) + eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.jsx')) + eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.tsx')) end) end) end) diff --git a/test/functional/lua/highlight_spec.lua b/test/functional/lua/highlight_spec.lua index c9f2d0a47f..c048949df8 100644 --- a/test/functional/lua/highlight_spec.lua +++ b/test/functional/lua/highlight_spec.lua @@ -1,14 +1,112 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() +local Screen = require('test.functional.ui.screen') local exec_lua = n.exec_lua local eq = t.eq -local neq = t.neq local eval = n.eval local command = n.command local clear = n.clear local api = n.api +describe('vim.highlight.range', function() + local screen + + before_each(function() + clear() + screen = Screen.new(60, 6) + screen:add_extra_attr_ids({ + [100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow, bold = true }, + }) + screen:attach() + api.nvim_set_option_value('list', true, {}) + api.nvim_set_option_value('listchars', 'eol:$', {}) + api.nvim_buf_set_lines(0, 0, -1, true, { + 'asdfghjkl', + '«å£=å£Â»', + 'qwertyuiop', + 'å£å£=å£å£', + 'zxcvbnm', + }) + end) + + it('works with charwise selection', function() + exec_lua(function() + local ns = vim.api.nvim_create_namespace('') + vim.highlight.range(0, ns, 'Search', { 1, 5 }, { 3, 10 }) + end) + screen:expect([[ + ^asdfghjkl{1:$} | + «å£{10:=å£Â»}{100:$} | + {10:qwertyuiop}{100:$} | + {10:å£å£=å£}å£{1:$} | + zxcvbnm{1:$} | + | + ]]) + end) + + it('works with linewise selection', function() + exec_lua(function() + local ns = vim.api.nvim_create_namespace('') + vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 0 }, { regtype = 'V' }) + end) + screen:expect([[ + {10:^asdfghjkl}{100:$} | + {10:«å£=å£Â»}{100:$} | + {10:qwertyuiop}{100:$} | + {10:å£å£=å£å£}{100:$} | + {10:zxcvbnm}{100:$} | + | + ]]) + end) + + it('works with blockwise selection', function() + exec_lua(function() + local ns = vim.api.nvim_create_namespace('') + vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 4 }, { regtype = '\022' }) + end) + screen:expect([[ + {10:^asdf}ghjkl{1:$} | + {10:«å£=}å£Â»{1:$} | + {10:qwer}tyuiop{1:$} | + {10:å£å£}=å£å£{1:$} | + {10:zxcv}bnm{1:$} | + | + ]]) + end) + + it('works with blockwise selection with width', function() + exec_lua(function() + local ns = vim.api.nvim_create_namespace('') + vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 4, 7 }, { regtype = '\0226' }) + end) + screen:expect([[ + ^asdf{10:ghjkl}{1:$} | + «å£={10:å£Â»}{1:$} | + qwer{10:tyuiop}{1:$} | + å£å£{10:=å£å£}{1:$} | + zxcv{10:bnm}{1:$} | + | + ]]) + end) + + it('can use -1 or v:maxcol to indicate end of line', function() + exec_lua(function() + local ns = vim.api.nvim_create_namespace('') + vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 1, -1 }, {}) + vim.highlight.range(0, ns, 'Search', { 2, 6 }, { 3, vim.v.maxcol }, {}) + end) + screen:expect([[ + ^asdf{10:ghjkl}{100:$} | + {10:«å£=å£Â»}{100:$} | + qwerty{10:uiop}{100:$} | + {10:å£å£=å£å£}{1:$} | + zxcvbnm{1:$} | + | + ]]) + end) +end) + describe('vim.highlight.on_yank', function() before_each(function() clear() @@ -16,53 +114,62 @@ describe('vim.highlight.on_yank', function() it('does not show errors even if buffer is wiped before timeout', function() command('new') - exec_lua([[ - vim.highlight.on_yank({timeout = 10, on_macro = true, event = {operator = "y", regtype = "v"}}) + exec_lua(function() + vim.highlight.on_yank({ + timeout = 10, + on_macro = true, + event = { operator = 'y', regtype = 'v' }, + }) vim.cmd('bwipeout!') - ]]) + end) vim.uv.sleep(10) n.feed('<cr>') -- avoid hang if error message exists eq('', eval('v:errmsg')) end) it('does not close timer twice', function() - exec_lua([[ - vim.highlight.on_yank({timeout = 10, on_macro = true, event = {operator = "y"}}) + exec_lua(function() + vim.highlight.on_yank({ timeout = 10, on_macro = true, event = { operator = 'y' } }) vim.uv.sleep(10) vim.schedule(function() - vim.highlight.on_yank({timeout = 0, on_macro = true, event = {operator = "y"}}) + vim.highlight.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } }) end) - ]]) + end) eq('', eval('v:errmsg')) end) it('does not show in another window', function() command('vsplit') - exec_lua([[ - vim.api.nvim_buf_set_mark(0,"[",1,1,{}) - vim.api.nvim_buf_set_mark(0,"]",1,1,{}) - vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}}) - ]]) - neq({}, api.nvim__win_get_ns(0)) + exec_lua(function() + vim.api.nvim_buf_set_mark(0, '[', 1, 1, {}) + vim.api.nvim_buf_set_mark(0, ']', 1, 1, {}) + vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } }) + end) + local ns = api.nvim_create_namespace('hlyank') + local win = api.nvim_get_current_win() + eq({ win }, api.nvim__ns_get(ns).wins) command('wincmd w') - eq({}, api.nvim__win_get_ns(0)) + eq({ win }, api.nvim__ns_get(ns).wins) end) it('removes old highlight if new one is created before old one times out', function() command('vnew') - exec_lua([[ - vim.api.nvim_buf_set_mark(0,"[",1,1,{}) - vim.api.nvim_buf_set_mark(0,"]",1,1,{}) - vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}}) - ]]) - neq({}, api.nvim__win_get_ns(0)) + exec_lua(function() + vim.api.nvim_buf_set_mark(0, '[', 1, 1, {}) + vim.api.nvim_buf_set_mark(0, ']', 1, 1, {}) + vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } }) + end) + local ns = api.nvim_create_namespace('hlyank') + eq(api.nvim_get_current_win(), api.nvim__ns_get(ns).wins[1]) command('wincmd w') - exec_lua([[ - vim.api.nvim_buf_set_mark(0,"[",1,1,{}) - vim.api.nvim_buf_set_mark(0,"]",1,1,{}) - vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}}) - ]]) + exec_lua(function() + vim.api.nvim_buf_set_mark(0, '[', 1, 1, {}) + vim.api.nvim_buf_set_mark(0, ']', 1, 1, {}) + vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } }) + end) + local win = api.nvim_get_current_win() + eq({ win }, api.nvim__ns_get(ns).wins) command('wincmd w') - eq({}, api.nvim__win_get_ns(0)) + eq({ win }, api.nvim__ns_get(ns).wins) end) end) diff --git a/test/functional/lua/inspector_spec.lua b/test/functional/lua/inspector_spec.lua index 8fadba6ee8..3a1263f6a3 100644 --- a/test/functional/lua/inspector_spec.lua +++ b/test/functional/lua/inspector_spec.lua @@ -12,22 +12,21 @@ describe('vim.inspect_pos', function() end) it('it returns items', function() - local ret = exec_lua([[ + local buf, items, other_buf_syntax = exec_lua(function() local buf = vim.api.nvim_create_buf(true, false) local buf1 = vim.api.nvim_create_buf(true, false) - local ns1 = vim.api.nvim_create_namespace("ns1") - local ns2 = vim.api.nvim_create_namespace("") + local ns1 = vim.api.nvim_create_namespace('ns1') + local ns2 = vim.api.nvim_create_namespace('') vim.api.nvim_set_current_buf(buf) - vim.api.nvim_buf_set_lines(0, 0, -1, false, {"local a = 123"}) - vim.api.nvim_buf_set_lines(buf1, 0, -1, false, {"--commentline"}) + vim.api.nvim_buf_set_lines(0, 0, -1, false, { 'local a = 123' }) + vim.api.nvim_buf_set_lines(buf1, 0, -1, false, { '--commentline' }) vim.bo[buf].filetype = 'lua' vim.bo[buf1].filetype = 'lua' - vim.api.nvim_buf_set_extmark(buf, ns1, 0, 10, { hl_group = "Normal" }) - vim.api.nvim_buf_set_extmark(buf, ns2, 0, 10, { hl_group = "Normal" }) - vim.cmd("syntax on") - return {buf, vim.inspect_pos(0, 0, 10), vim.inspect_pos(buf1, 0, 10).syntax } - ]]) - local buf, items, other_buf_syntax = unpack(ret) + vim.api.nvim_buf_set_extmark(buf, ns1, 0, 10, { hl_group = 'Normal' }) + vim.api.nvim_buf_set_extmark(buf, ns2, 0, 10, { hl_group = 'Normal' }) + vim.cmd('syntax on') + return buf, vim.inspect_pos(0, 0, 10), vim.inspect_pos(buf1, 0, 10).syntax + end) eq('', eval('v:errmsg')) eq({ @@ -95,14 +94,14 @@ describe('vim.show_pos', function() end) it('it does not error', function() - exec_lua([[ + exec_lua(function() local buf = vim.api.nvim_create_buf(true, false) vim.api.nvim_set_current_buf(buf) - vim.api.nvim_buf_set_lines(0, 0, -1, false, {"local a = 123"}) + vim.api.nvim_buf_set_lines(0, 0, -1, false, { 'local a = 123' }) vim.bo[buf].filetype = 'lua' - vim.cmd("syntax on") - return {buf, vim.show_pos(0, 0, 10)} - ]]) + vim.cmd('syntax on') + return { buf, vim.show_pos(0, 0, 10) } + end) eq('', eval('v:errmsg')) end) end) diff --git a/test/functional/lua/loader_spec.lua b/test/functional/lua/loader_spec.lua index f13e6664c5..8508f2aa14 100644 --- a/test/functional/lua/loader_spec.lua +++ b/test/functional/lua/loader_spec.lua @@ -12,14 +12,14 @@ describe('vim.loader', function() it('can work in compatibility with --luamod-dev #27413', function() clear({ args = { '--luamod-dev' } }) - exec_lua [[ + exec_lua(function() vim.loader.enable() - require("vim.fs") + require('vim.fs') -- try to load other vim submodules as well (Nvim Lua stdlib) for key, _ in pairs(vim._submodules) do - local modname = 'vim.' .. key -- e.g. "vim.fs" + local modname = 'vim.' .. key -- e.g. "vim.fs" local lhs = vim[key] local rhs = require(modname) @@ -28,28 +28,25 @@ describe('vim.loader', function() ('%s != require("%s"), %s != %s'):format(modname, modname, tostring(lhs), tostring(rhs)) ) end - ]] + end) end) it('handles changing files (#23027)', function() - exec_lua [[ + exec_lua(function() vim.loader.enable() - ]] + end) local tmp = t.tmpname() command('edit ' .. tmp) eq( 1, - exec_lua( - [[ - vim.api.nvim_buf_set_lines(0, 0, -1, true, {'_G.TEST=1'}) - vim.cmd.write() - loadfile(...)() - return _G.TEST - ]], - tmp - ) + exec_lua(function() + vim.api.nvim_buf_set_lines(0, 0, -1, true, { '_G.TEST=1' }) + vim.cmd.write() + loadfile(tmp)() + return _G.TEST + end) ) -- fs latency @@ -57,15 +54,12 @@ describe('vim.loader', function() eq( 2, - exec_lua( - [[ - vim.api.nvim_buf_set_lines(0, 0, -1, true, {'_G.TEST=2'}) - vim.cmd.write() - loadfile(...)() - return _G.TEST - ]], - tmp - ) + exec_lua(function() + vim.api.nvim_buf_set_lines(0, 0, -1, true, { '_G.TEST=2' }) + vim.cmd.write() + loadfile(tmp)() + return _G.TEST + end) ) end) @@ -74,8 +68,7 @@ describe('vim.loader', function() vim.loader.enable() ]] - local tmp = t.tmpname() - assert(os.remove(tmp)) + local tmp = t.tmpname(false) assert(t.mkdir(tmp)) assert(t.mkdir(tmp .. '/%')) local tmp1 = tmp .. '/%/x' @@ -88,4 +81,15 @@ describe('vim.loader', function() eq(1, exec_lua('return loadfile(...)()', tmp1)) eq(2, exec_lua('return loadfile(...)()', tmp2)) end) + + it('correct indent on error message (#29809)', function() + local errmsg = exec_lua [[ + vim.loader.enable() + local _, errmsg = pcall(require, 'non_existent_module') + return errmsg + ]] + local errors = vim.split(errmsg, '\n') + eq("\tcache_loader: module 'non_existent_module' not found", errors[3]) + eq("\tcache_loader_lib: module 'non_existent_module' not found", errors[4]) + end) end) diff --git a/test/functional/lua/loop_spec.lua b/test/functional/lua/loop_spec.lua index 566a171a84..de8200a5f1 100644 --- a/test/functional/lua/loop_spec.lua +++ b/test/functional/lua/loop_spec.lua @@ -25,30 +25,34 @@ describe('vim.uv', function() it('timer', function() exec_lua('vim.api.nvim_set_var("coroutine_cnt", 0)', {}) - local code = [[ + local code = function() local touch = 0 local function wait(ms) local this = coroutine.running() assert(this) - local timer = vim.uv.new_timer() - timer:start(ms, 0, vim.schedule_wrap(function () - timer:close() - touch = touch + 1 - coroutine.resume(this) - touch = touch + 1 - assert(touch==3) - vim.api.nvim_set_var("coroutine_cnt_1", touch) - end)) + local timer = assert(vim.uv.new_timer()) + timer:start( + ms, + 0, + vim.schedule_wrap(function() + timer:close() + touch = touch + 1 + coroutine.resume(this) + touch = touch + 1 + assert(touch == 3) + vim.api.nvim_set_var('coroutine_cnt_1', touch) + end) + ) coroutine.yield() touch = touch + 1 return touch end coroutine.wrap(function() local touched = wait(10) - assert(touched==touch) - vim.api.nvim_set_var("coroutine_cnt", touched) + assert(touched == touch) + vim.api.nvim_set_var('coroutine_cnt', touched) end)() - ]] + end eq(0, api.nvim_get_var('coroutine_cnt')) exec_lua(code) @@ -99,15 +103,19 @@ describe('vim.uv', function() -- callbacks can be scheduled to be executed in the main event loop -- where the entire API is available - exec_lua([[ - local timer = vim.uv.new_timer() - timer:start(20, 0, vim.schedule_wrap(function () - _G.is_fast = vim.in_fast_event() - timer:close() - vim.api.nvim_set_var("valid", true) - vim.api.nvim_command("echomsg 'howdy'") - end)) - ]]) + exec_lua(function() + local timer = assert(vim.uv.new_timer()) + timer:start( + 20, + 0, + vim.schedule_wrap(function() + _G.is_fast = vim.in_fast_event() + timer:close() + vim.api.nvim_set_var('valid', true) + vim.api.nvim_command("echomsg 'howdy'") + end) + ) + end) screen:expect([[ ^ | @@ -118,15 +126,15 @@ describe('vim.uv', function() eq(false, exec_lua('return _G.is_fast')) -- fast (not deferred) API functions are allowed to be called directly - exec_lua([[ - local timer = vim.uv.new_timer() - timer:start(20, 0, function () + exec_lua(function() + local timer = assert(vim.uv.new_timer()) + timer:start(20, 0, function() timer:close() -- input is queued for processing after the callback returns - vim.api.nvim_input("isneaky") + vim.api.nvim_input('isneaky') _G.mode = vim.api.nvim_get_mode() end) - ]]) + end) screen:expect([[ sneaky^ | {1:~ }|*8 @@ -134,15 +142,15 @@ describe('vim.uv', function() ]]) eq({ blocking = false, mode = 'n' }, exec_lua('return _G.mode')) - exec_lua([[ - local timer = vim.uv.new_timer() - timer:start(20, 0, function () + exec_lua(function() + local timer = assert(vim.uv.new_timer()) + timer:start(20, 0, function() _G.is_fast = vim.in_fast_event() timer:close() - _G.value = vim.fn.has("nvim-0.5") - _G.unvalue = vim.fn.has("python3") + _G.value = vim.fn.has('nvim-0.5') + _G.unvalue = vim.fn.has('python3') end) - ]]) + end) screen:expect({ any = [[{3:Vim:E5560: Vimscript function must not be called i}]] }) feed('<cr>') diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 3f62cd8325..2b23f72c7d 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -13,6 +13,7 @@ local fn = n.fn local clear = n.clear local eval = n.eval local feed = n.feed +local assert_alive = n.assert_alive local NIL = vim.NIL local eq = t.eq @@ -72,9 +73,9 @@ describe('luaeval()', function() end) it('are successfully converted to special dictionaries in table keys', function() command([[let d = luaeval('{["\0"]=1}')]]) - eq({_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n'}}, 1}}}, api.nvim_get_var('d')) + eq({_TYPE={}, _VAL={{'\000', 1}}}, api.nvim_get_var('d')) eq(1, fn.eval('d._TYPE is v:msgpack_types.map')) - eq(1, fn.eval('d._VAL[0][0]._TYPE is v:msgpack_types.string')) + eq(eval('v:t_blob'), fn.eval('type(d._VAL[0][0])')) end) it('are successfully converted to blobs from a list', function() command([[let l = luaeval('{"abc", "a\0b", "c\0d", "def"}')]]) @@ -125,11 +126,11 @@ describe('luaeval()', function() local level = 30 eq(nested_by_level[level].o, fn.luaeval(nested_by_level[level].s)) - eq({_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n', '\n'}}, '\000\n\000\000'}}}, + eq({_TYPE={}, _VAL={{'\000\n\000', '\000\n\000\000'}}}, fn.luaeval([[{['\0\n\0']='\0\n\0\0'}]])) eq(1, eval([[luaeval('{["\0\n\0"]="\0\n\0\0"}')._TYPE is v:msgpack_types.map]])) - eq(1, eval([[luaeval('{["\0\n\0"]="\0\n\0\0"}')._VAL[0][0]._TYPE is v:msgpack_types.string]])) - eq({nested={{_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n', '\n'}}, '\000\n\000\000'}}}}}, + eq(eval("v:t_blob"), eval([[type(luaeval('{["\0\n\0"]="\0\n\0\0"}')._VAL[0][0])]])) + eq({nested={{_TYPE={}, _VAL={{'\000\n\000', '\000\n\000\000'}}}}}, fn.luaeval([[{nested={{['\0\n\0']='\0\n\0\0'}}}]])) end) @@ -177,17 +178,15 @@ describe('luaeval()', function() end it('correctly passes special dictionaries', function() - eq({0, '\000\n\000'}, luaevalarg(sp('binary', '["\\n", "\\n"]'))) eq({0, '\000\n\000'}, luaevalarg(sp('string', '["\\n", "\\n"]'))) eq({0, true}, luaevalarg(sp('boolean', 1))) eq({0, false}, luaevalarg(sp('boolean', 0))) eq({0, NIL}, luaevalarg(sp('nil', 0))) - eq({0, {[""]=""}}, luaevalarg(mapsp(sp('binary', '[""]'), '""'))) eq({0, {[""]=""}}, luaevalarg(mapsp(sp('string', '[""]'), '""'))) end) it('issues an error in some cases', function() - eq("Vim(call):E5100: Cannot convert given lua table: table should contain either only integer keys or only string keys", + eq("Vim(call):E5100: Cannot convert given Lua table: table should contain either only integer keys or only string keys", exc_exec('call luaeval("{1, foo=2}")')) startswith("Vim(call):E5107: Error loading lua [string \"luaeval()\"]:", @@ -511,23 +510,16 @@ describe('v:lua', function() it('works in func options', function() local screen = Screen.new(60, 8) - screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, - [2] = {background = Screen.colors.WebGray}, - [3] = {background = Screen.colors.LightMagenta}, - [4] = {bold = true}, - [5] = {bold = true, foreground = Screen.colors.SeaGreen4}, - }) screen:attach() api.nvim_set_option_value('omnifunc', 'v:lua.mymod.omni', {}) feed('isome st<c-x><c-o>') screen:expect{grid=[[ some stuff^ | - {1:~ }{2: stuff }{1: }| - {1:~ }{3: steam }{1: }| - {1:~ }{3: strange things }{1: }| + {1:~ }{12: stuff }{1: }| + {1:~ }{4: steam }{1: }| + {1:~ }{4: strange things }{1: }| {1:~ }|*3 - {4:-- Omni completion (^O^N^P) }{5:match 1 of 3} | + {5:-- Omni completion (^O^N^P) }{6:match 1 of 3} | ]]} api.nvim_set_option_value('operatorfunc', 'v:lua.mymod.noisy', {}) feed('<Esc>g@g@') @@ -560,5 +552,41 @@ describe('v:lua', function() eq("Vim:E107: Missing parentheses: v:lua", pcall_err(eval, "'bad'->v:lua")) eq("Vim:E1085: Not a callable type: v:lua", pcall_err(eval, "'bad'->v:lua()")) eq([[Vim:E15: Invalid expression: "v:lua.()"]], pcall_err(eval, "'bad'->v:lua.()")) + + eq("Vim:E1085: Not a callable type: v:lua", pcall_err(eval, "v:lua()")) + eq([[Vim:E15: Invalid expression: "v:lua.()"]], pcall_err(eval, "v:lua.()")) + end) + + describe('invalid use in fold text', function() + before_each(function() + feed('ifoo<CR>bar<Esc>') + command('1,2fold') + end) + + it('with missing function name when used as simple function', function() + api.nvim_set_option_value('debug', 'throw', {}) + eq( + [[Vim(eval):E15: Invalid expression: "v:lua.()"]], + pcall_err(command, 'set foldtext=v:lua.() | eval foldtextresult(1)') + ) + end) + + it('with missing function name when used in expression', function() + api.nvim_set_option_value('debug', 'throw', {}) + eq( + [[Vim(eval):E15: Invalid expression: "+v:lua.()"]], + pcall_err(command, 'set foldtext=+v:lua.() | eval foldtextresult(1)') + ) + end) + + it('with non-existent function when used as simple function', function() + command('set foldtext=v:lua.NoSuchFunc() | eval foldtextresult(1)') + assert_alive() + end) + + it('with non-existent function when used in expression', function() + command('set foldtext=+v:lua.NoSuchFunc() | eval foldtextresult(1)') + assert_alive() + end) end) end) diff --git a/test/functional/lua/mpack_spec.lua b/test/functional/lua/mpack_spec.lua index efd69d4607..ebede26936 100644 --- a/test/functional/lua/mpack_spec.lua +++ b/test/functional/lua/mpack_spec.lua @@ -11,20 +11,20 @@ describe('lua vim.mpack', function() it('encodes vim.NIL', function() eq( { true, true, true, true }, - exec_lua [[ - local var = vim.mpack.decode(vim.mpack.encode({33, vim.NIL, 77})) - return {var[1]==33, var[2]==vim.NIL, var[3]==77, var[4]==nil} - ]] + exec_lua(function() + local var = vim.mpack.decode(vim.mpack.encode({ 33, vim.NIL, 77 })) + return { var[1] == 33, var[2] == vim.NIL, var[3] == 77, var[4] == nil } + end) ) end) it('encodes vim.empty_dict()', function() eq( { { {}, 'foo', {} }, true, false }, - exec_lua [[ - local var = vim.mpack.decode(vim.mpack.encode({{}, "foo", vim.empty_dict()})) - return {var, vim.islist(var[1]), vim.islist(var[3])} - ]] + exec_lua(function() + local var = vim.mpack.decode(vim.mpack.encode({ {}, 'foo', vim.empty_dict() })) + return { var, vim.islist(var[1]), vim.islist(var[3]) } + end) ) end) end) diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua index 849978f080..33a2813200 100644 --- a/test/functional/lua/overrides_spec.lua +++ b/test/functional/lua/overrides_spec.lua @@ -134,14 +134,12 @@ describe('print', function() eq('abc def', exec_capture('lua print("abc", "", "def")')) end) it('defers printing in luv event handlers', function() - exec_lua( - [[ - local cmd = ... + exec_lua(function(cmd) function test() local timer = vim.uv.new_timer() local done = false timer:start(10, 0, function() - print("very fast") + print('very fast') timer:close() done = true end) @@ -149,14 +147,12 @@ describe('print', function() -- loop until we know for sure the callback has been executed while not done do os.execute(cmd) - vim.uv.run("nowait") -- fake os_breakcheck() + vim.uv.run('nowait') -- fake os_breakcheck() end - print("very slow") - vim.api.nvim_command("sleep 1m") -- force deferred event processing + print('very slow') + vim.api.nvim_command('sleep 1m') -- force deferred event processing end - ]], - (is_os('win') and 'timeout 1') or 'sleep 0.1' - ) + end, (is_os('win') and 'timeout 1') or 'sleep 0.1') eq('very slow\nvery fast', exec_capture('lua test()')) end) diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua index 4adce42c3e..f63363d6d9 100644 --- a/test/functional/lua/runtime_spec.lua +++ b/test/functional/lua/runtime_spec.lua @@ -401,4 +401,12 @@ describe('runtime:', function() eq('ABab', eval('g:seq')) end) end) + + it('cpp ftplugin loads c ftplugin #29053', function() + eq('', eval('&commentstring')) + eq('', eval('&omnifunc')) + exec('edit file.cpp') + eq('// %s', eval('&commentstring')) + eq('ccomplete#Complete', eval('&omnifunc')) + end) end) diff --git a/test/functional/lua/snippet_spec.lua b/test/functional/lua/snippet_spec.lua index 413aa93994..eb2f17216c 100644 --- a/test/functional/lua/snippet_spec.lua +++ b/test/functional/lua/snippet_spec.lua @@ -1,3 +1,5 @@ +---@diagnostic disable: no-unknown + local t = require('test.testutil') local n = require('test.functional.testnvim')() @@ -16,11 +18,6 @@ local retry = t.retry describe('vim.snippet', function() before_each(function() clear() - - exec_lua([[ - vim.keymap.set({ 'i', 's' }, '<Tab>', function() vim.snippet.jump(1) end, { buffer = true }) - vim.keymap.set({ 'i', 's' }, '<S-Tab>', function() vim.snippet.jump(-1) end, { buffer = true }) - ]]) end) after_each(clear) @@ -61,7 +58,13 @@ describe('vim.snippet', function() end) it('adds indentation based on the start of snippet lines', function() + local curbuf = api.nvim_get_current_buf() + test_expand_success({ 'if $1 then', ' $0', 'end' }, { 'if then', ' ', 'end' }) + + -- Regression test: #29658 + api.nvim_buf_set_lines(curbuf, 0, -1, false, {}) + test_expand_success({ '${1:foo^bar}\n' }, { 'foo^bar', '' }) end) it('replaces tabs with spaces when expandtab is set', function() @@ -286,4 +289,24 @@ describe('vim.snippet', function() ]] ) end) + + it('restores snippet navigation keymaps', function() + -- Create a buffer keymap in insert mode that deletes all lines. + local curbuf = api.nvim_get_current_buf() + exec_lua('vim.api.nvim_buf_set_keymap(..., "i", "<Tab>", "<cmd>normal ggdG<cr>", {})', curbuf) + + test_expand_success({ 'var $1 = $2' }, { 'var = ' }) + + -- While the snippet is active, <Tab> should navigate between tabstops. + feed('x') + poke_eventloop() + feed('<Tab>0') + eq({ 'var x = 0' }, buf_lines(0)) + + exec_lua('vim.snippet.stop()') + + -- After exiting the snippet, the buffer keymap should be restored. + feed('<Esc>O<cr><Tab>') + eq({ '' }, buf_lines(0)) + end) end) diff --git a/test/functional/lua/system_spec.lua b/test/functional/lua/system_spec.lua index e72a009d2e..482bfcf1a9 100644 --- a/test/functional/lua/system_spec.lua +++ b/test/functional/lua/system_spec.lua @@ -6,10 +6,8 @@ local exec_lua = n.exec_lua local eq = t.eq local function system_sync(cmd, opts) - return exec_lua( - [[ - local cmd, opts = ... - local obj = vim.system(...) + return exec_lua(function() + local obj = vim.system(cmd, opts) if opts.timeout then -- Minor delay before calling wait() so the timeout uv timer can have a headstart over the @@ -24,16 +22,11 @@ local function system_sync(cmd, opts) assert(not proc, 'process still exists') return res - ]], - cmd, - opts - ) + end) end local function system_async(cmd, opts) - return exec_lua( - [[ - local cmd, opts = ... + return exec_lua(function() _G.done = false local obj = vim.system(cmd, opts, function(obj) _G.done = true @@ -51,10 +44,7 @@ local function system_async(cmd, opts) assert(not proc, 'process still exists') return _G.ret - ]], - cmd, - opts - ) + end) end describe('vim.system', function() @@ -84,7 +74,7 @@ describe('vim.system', function() end it('kill processes', function() - exec_lua([[ + exec_lua(function() local signal local cmd = vim.system({ 'cat', '-' }, { stdin = true }, function(r) signal = r.signal @@ -104,19 +94,21 @@ describe('vim.system', function() assert(not proc, 'process still exists') assert(signal == 2) - ]]) + end) end) it('SystemObj:wait() does not process non-fast events #27292', function() eq( false, - exec_lua([[ + exec_lua(function() _G.processed = false local cmd = vim.system({ 'sleep', '1' }) - vim.schedule(function() _G.processed = true end) + vim.schedule(function() + _G.processed = true + end) cmd:wait() return _G.processed - ]]) + end) ) eq(true, exec_lua([[return _G.processed]])) end) diff --git a/test/functional/lua/text_spec.lua b/test/functional/lua/text_spec.lua index 9e77953c8c..be471bfd62 100644 --- a/test/functional/lua/text_spec.lua +++ b/test/functional/lua/text_spec.lua @@ -20,5 +20,11 @@ describe('vim.text', function() eq(input, vim.text.hexdecode(output)) end end) + + it('works with very large strings', function() + local input, output = string.rep('😂', 2 ^ 16), string.rep('F09F9882', 2 ^ 16) + eq(output, vim.text.hexencode(input)) + eq(input, vim.text.hexdecode(output)) + end) end) end) diff --git a/test/functional/lua/thread_spec.lua b/test/functional/lua/thread_spec.lua index 780057b580..cbf23517dc 100644 --- a/test/functional/lua/thread_spec.lua +++ b/test/functional/lua/thread_spec.lua @@ -18,13 +18,6 @@ describe('thread', function() clear() screen = Screen.new(50, 10) screen:attach() - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { bold = true, reverse = true }, - [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - [4] = { bold = true, foreground = Screen.colors.SeaGreen4 }, - [5] = { bold = true }, - }) end) it('entry func is executed in protected mode', function() @@ -38,10 +31,10 @@ describe('thread', function() screen:expect([[ | {1:~ }|*5 - {2: }| - {3:Error in luv thread:} | - {3:[string "<nvim>"]:2: Error in thread entry func} | - {4:Press ENTER or type command to continue}^ | + {3: }| + {9:Error in luv thread:} | + {9:[string "<nvim>"]:2: Error in thread entry func} | + {6:Press ENTER or type command to continue}^ | ]]) feed('<cr>') assert_alive() @@ -65,10 +58,10 @@ describe('thread', function() screen:expect([[ | {1:~ }|*5 - {2: }| - {3:Error in luv callback, thread:} | - {3:[string "<nvim>"]:6: Error in thread callback} | - {4:Press ENTER or type command to continue}^ | + {3: }| + {9:Error in luv callback, thread:} | + {9:[string "<nvim>"]:6: Error in thread callback} | + {6:Press ENTER or type command to continue}^ | ]]) feed('<cr>') assert_alive() @@ -265,13 +258,6 @@ describe('threadpool', function() it('with invalid return value', function() local screen = Screen.new(50, 10) screen:attach() - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { bold = true, reverse = true }, - [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - [4] = { bold = true, foreground = Screen.colors.SeaGreen4 }, - [5] = { bold = true }, - }) exec_lua [[ local work = vim.uv.new_work(function() return {} end, function() end) @@ -281,10 +267,10 @@ describe('threadpool', function() screen:expect([[ | {1:~ }|*5 - {2: }| - {3:Error in luv thread:} | - {3:Error: thread arg not support type 'table' at 1} | - {4:Press ENTER or type command to continue}^ | + {3: }| + {9:Error in luv thread:} | + {9:Error: thread arg not support type 'table' at 1} | + {6:Press ENTER or type command to continue}^ | ]]) end) diff --git a/test/functional/lua/ui_event_spec.lua b/test/functional/lua/ui_event_spec.lua index 1e80c88403..0a6deaa41c 100644 --- a/test/functional/lua/ui_event_spec.lua +++ b/test/functional/lua/ui_event_spec.lua @@ -37,6 +37,9 @@ describe('vim.ui_attach', function() [2] = { bold = true }, [3] = { background = Screen.colors.Grey }, [4] = { background = Screen.colors.LightMagenta }, + [5] = { reverse = true }, + [6] = { reverse = true, bold = true }, + [7] = { background = Screen.colors.Yellow1 }, }) screen:attach() end) @@ -188,6 +191,56 @@ describe('vim.ui_attach', function() feed('version<CR><CR>v<Esc>') n.assert_alive() end) + + it("preserved 'incsearch/command' screen state after :redraw from ext_cmdline", function() + exec_lua([[ + vim.cmd.norm('ifoobar') + vim.cmd('1split cmdline') + local buf = vim.api.nvim_get_current_buf() + vim.cmd.wincmd('p') + vim.ui_attach(ns, { ext_cmdline = true }, function(event, ...) + if event == 'cmdline_show' then + local content = select(1, ...) + vim.api.nvim_buf_set_lines(buf, -2, -1, false, {content[1][2]}) + vim.cmd('redraw') + end + return true + end) + ]]) + -- Updates a cmdline window + feed(':cmdline') + screen:expect({ + grid = [[ + cmdline | + {5:cmdline [+] }| + fooba^r | + {6:[No Name] [+] }| + | + ]], + }) + -- Does not clear 'incsearch' highlighting + feed('<Esc>/foo') + screen:expect({ + grid = [[ + foo | + {5:cmdline [+] }| + {5:foo}ba^r | + {6:[No Name] [+] }| + | + ]], + }) + -- Shows new cmdline state during 'inccommand' + feed('<Esc>:%s/bar/baz') + screen:expect({ + grid = [[ + %s/bar/baz | + {5:cmdline [+] }| + foo{7:ba^z} | + {6:[No Name] [+] }| + | + ]], + }) + end) end) describe('vim.ui_attach', function() diff --git a/test/functional/lua/ui_spec.lua b/test/functional/lua/ui_spec.lua index d69e893c96..d5eede2885 100644 --- a/test/functional/lua/ui_spec.lua +++ b/test/functional/lua/ui_spec.lua @@ -157,5 +157,28 @@ describe('vim.ui', function() exec_lua [[local _, err = vim.ui.open('foo') ; return err]] ) end) + + it('opt.cmd #29490', function() + t.matches( + 'ENOENT: no such file or directory', + t.pcall_err(exec_lua, function() + vim.ui.open('foo', { cmd = { 'non-existent-tool' } }) + end) + ) + + eq( + { + code = 0, + signal = 0, + stderr = '', + stdout = 'arg1=arg1;arg2=https://example.com;', + }, + exec_lua(function(cmd_) + local cmd, err = vim.ui.open('https://example.com', { cmd = cmd_ }) + assert(cmd and not err) + return cmd:wait() + end, { n.testprg('printargs-test'), 'arg1' }) + ) + end) end) end) diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua index 553afb35d3..258b96bc43 100644 --- a/test/functional/lua/uri_spec.lua +++ b/test/functional/lua/uri_spec.lua @@ -217,7 +217,7 @@ describe('URI methods', function() ]], file ) - local expected_uri = 'file:///' .. file:gsub('\\', '/') + local expected_uri = 'file:///' .. t.fix_slashes(file) eq(expected_uri, exec_lua(test_case)) os.remove(file) end) diff --git a/test/functional/lua/version_spec.lua b/test/functional/lua/version_spec.lua index 4ce8fb8dfe..c172555091 100644 --- a/test/functional/lua/version_spec.lua +++ b/test/functional/lua/version_spec.lua @@ -112,6 +112,10 @@ describe('version', function() assert(vim.version.range('1.2.3-alpha'):has('1.2.3-alpha')) assert(not vim.version.range('1.2.3-alpha'):has('1.2.3-beta')) end) + + it('returns nil with empty version', function() + eq(vim.version.parse(''), nil) + end) end) describe('cmp()', function() diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index c8f94c6ffa..3c65ec664e 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -135,19 +135,19 @@ describe('lua stdlib', function() -- See MAINTAIN.md for the soft/hard deprecation policy describe(('vim.deprecate prerel=%s,'):format(prerel or 'nil'), function() - local curver = exec_lua('return vim.version()') --[[@as {major:number, minor:number}]] - -- "0.10" or "0.10-dev+xxx" - local curstr = ('%s.%s%s'):format(curver.major, curver.minor, prerel or '') - -- "0.10" or "0.11" - local nextver = ('%s.%s'):format(curver.major, curver.minor + (prerel and 0 or 1)) - local was_removed = prerel and 'was removed' or 'will be removed' + local curver --- @type {major:number, minor:number} + + before_each(function() + curver = exec_lua('return vim.version()') + end) it('plugin=nil, same message skipped', function() + -- "0.10" or "0.10-dev+xxx" + local curstr = ('%s.%s%s'):format(curver.major, curver.minor, prerel or '') eq( - dedent( - [[ - foo.bar() is deprecated. Run ":checkhealth vim.deprecated" for more information]] - ):format(curstr), + ([[foo.bar() is deprecated. Run ":checkhealth vim.deprecated" for more information]]):format( + curstr + ), exec_lua('return vim.deprecate(...)', 'foo.bar()', 'zub.wooo{ok=yay}', curstr) ) -- Same message as above; skipped this time. @@ -162,6 +162,10 @@ describe('lua stdlib', function() end) it('plugin=nil, show error if hard-deprecated', function() + -- "0.10" or "0.11" + local nextver = ('%s.%s'):format(curver.major, curver.minor + (prerel and 0 or 1)) + + local was_removed = prerel and 'was removed' or 'will be removed' eq( dedent( [[ @@ -173,8 +177,7 @@ describe('lua stdlib', function() it('plugin=nil, to be deleted in the next major version (1.0)', function() eq( - dedent [[ - foo.baz() is deprecated. Run ":checkhealth vim.deprecated" for more information]], + [[foo.baz() is deprecated. Run ":checkhealth vim.deprecated" for more information]], exec_lua [[ return vim.deprecate('foo.baz()', nil, '1.0') ]] ) end) @@ -535,12 +538,6 @@ describe('lua stdlib', function() matches('big failure\nvery async', remove_trace(eval('v:errmsg'))) local screen = Screen.new(60, 5) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { bold = true, reverse = true }, - [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - [4] = { bold = true, foreground = Screen.colors.SeaGreen4 }, - }) screen:attach() screen:expect { grid = [[ @@ -559,11 +556,11 @@ describe('lua stdlib', function() ]]) screen:expect { grid = [[ - {3:stack traceback:} | - {3: [C]: in function 'nvim_command'} | - {3: [string "<nvim>"]:2: in function <[string "<nvim>"]:}| - {3:1>} | - {4:Press ENTER or type command to continue}^ | + {9:stack traceback:} | + {9: [C]: in function 'nvim_command'} | + {9: [string "<nvim>"]:2: in function <[string "<nvim>"]:}| + {9:1>} | + {6:Press ENTER or type command to continue}^ | ]], } end) @@ -1062,7 +1059,7 @@ describe('lua stdlib', function() local a = { a = {[2] = 3} } local b = { a = {[3] = 3} } local c = vim.tbl_deep_extend("force", a, b) - return vim.deep_equal(c, {a = {[3] = 3}}) + return vim.deep_equal(c, {a = {[2] = 3, [3] = 3}}) ]])) eq( @@ -1074,34 +1071,28 @@ describe('lua stdlib', function() ]]) ) - matches( - 'invalid "behavior": nil', - pcall_err( - exec_lua, - [[ - return vim.tbl_deep_extend() - ]] - ) - ) + ok(exec_lua([[ + local a = { sub = { 'a', 'b' } } + local b = { sub = { 'b', 'c' } } + local c = vim.tbl_deep_extend('force', a, b) + return vim.deep_equal(c, { sub = { 'b', 'c' } }) + ]])) + + matches('invalid "behavior": nil', pcall_err(exec_lua, [[return vim.tbl_deep_extend()]])) matches( 'wrong number of arguments %(given 1, expected at least 3%)', - pcall_err( - exec_lua, - [[ - return vim.tbl_deep_extend("keep") - ]] - ) + pcall_err(exec_lua, [[return vim.tbl_deep_extend("keep")]]) ) matches( 'wrong number of arguments %(given 2, expected at least 3%)', - pcall_err( - exec_lua, - [[ - return vim.tbl_deep_extend("keep", {}) - ]] - ) + pcall_err(exec_lua, [[return vim.tbl_deep_extend("keep", {})]]) + ) + + matches( + 'after the second argument%: expected table, got number', + pcall_err(exec_lua, [[return vim.tbl_deep_extend("keep", {}, 42)]]) ) end) @@ -1200,8 +1191,7 @@ describe('lua stdlib', function() ]]) eq(true, exec_lua([[return next(vim.fn.FooFunc(3)) == nil ]])) eq(3, eval('g:test')) - -- compat: nvim_call_function uses "special" value for empty dict - eq(true, exec_lua([[return next(vim.api.nvim_call_function("FooFunc", {5})) == true ]])) + eq(true, exec_lua([[return vim.tbl_isempty(vim.api.nvim_call_function("FooFunc", {5}))]])) eq(5, eval('g:test')) eq({ 2, 'foo', true }, exec_lua([[return vim.fn.VarArg(2, "foo", true)]])) @@ -1239,7 +1229,7 @@ describe('lua stdlib', function() ) end) - it('vim.fn should error when calling API function', function() + it('vim.fn errors when calling API function', function() matches( 'Tried to call API function with vim.fn: use vim.api.nvim_get_current_line instead', pcall_err(exec_lua, 'vim.fn.nvim_get_current_line()') @@ -1314,12 +1304,6 @@ describe('lua stdlib', function() end) local screen = Screen.new(50, 7) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { bold = true, reverse = true }, - [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - [4] = { bold = true, foreground = Screen.colors.SeaGreen4 }, - }) screen:attach() exec_lua([[ timer = vim.uv.new_timer() @@ -1332,13 +1316,13 @@ describe('lua stdlib', function() ]]) screen:expect { grid = [[ - {3:[string "<nvim>"]:6: E5560: rpcrequest must not be}| - {3: called in a lua loop callback} | - {3:stack traceback:} | - {3: [C]: in function 'rpcrequest'} | - {3: [string "<nvim>"]:6: in function <[string }| - {3:"<nvim>"]:2>} | - {4:Press ENTER or type command to continue}^ | + {9:[string "<nvim>"]:6: E5560: rpcrequest must not be}| + {9: called in a lua loop callback} | + {9:stack traceback:} | + {9: [C]: in function 'rpcrequest'} | + {9: [string "<nvim>"]:6: in function <[string }| + {9:"<nvim>"]:2>} | + {6:Press ENTER or type command to continue}^ | ]], } feed('<cr>') @@ -1408,7 +1392,25 @@ describe('lua stdlib', function() exec_lua("vim.validate{arg1={{}, 't' }, arg2={ 'foo', 's' }}") exec_lua("vim.validate{arg1={2, function(a) return (a % 2) == 0 end, 'even number' }}") exec_lua("vim.validate{arg1={5, {'n', 's'} }, arg2={ 'foo', {'n', 's'} }}") - + vim.validate('arg1', 5, 'number') + vim.validate('arg1', '5', 'string') + vim.validate('arg1', { 5 }, 'table') + vim.validate('arg1', function() + return 5 + end, 'function') + vim.validate('arg1', nil, 'number', true) + vim.validate('arg1', nil, 'string', true) + vim.validate('arg1', nil, 'table', true) + vim.validate('arg1', nil, 'function', true) + + matches('arg1: expected number, got nil', pcall_err(vim.validate, 'arg1', nil, 'number')) + matches('arg1: expected string, got nil', pcall_err(vim.validate, 'arg1', nil, 'string')) + matches('arg1: expected table, got nil', pcall_err(vim.validate, 'arg1', nil, 'table')) + matches('arg1: expected function, got nil', pcall_err(vim.validate, 'arg1', nil, 'function')) + matches('arg1: expected string, got number', pcall_err(vim.validate, 'arg1', 5, 'string')) + matches('arg1: expected table, got number', pcall_err(vim.validate, 'arg1', 5, 'table')) + matches('arg1: expected function, got number', pcall_err(vim.validate, 'arg1', 5, 'function')) + matches('arg1: expected number, got string', pcall_err(vim.validate, 'arg1', '5', 'number')) matches('expected table, got number', pcall_err(exec_lua, "vim.validate{ 1, 'x' }")) matches('invalid type name: x', pcall_err(exec_lua, "vim.validate{ arg1={ 1, 'x' }}")) matches('invalid type name: 1', pcall_err(exec_lua, 'vim.validate{ arg1={ 1, 1 }}')) @@ -1472,6 +1474,60 @@ describe('lua stdlib', function() ]]) ) + eq( + { false, false }, + exec_lua([[ + local meta = { __call = {} } + assert(meta.__call) + local function new() + return setmetatable({}, meta) + end + local not_callable = new() + return { pcall(function() not_callable() end), vim.is_callable(not_callable) } + ]]) + ) + eq( + { false, false }, + exec_lua([[ + local function new() + return { __call = function()end } + end + local not_callable = new() + assert(not_callable.__call) + return { pcall(function() not_callable() end), vim.is_callable(not_callable) } + ]]) + ) + eq( + { false, false }, + exec_lua([[ + local meta = setmetatable( + { __index = { __call = function() end } }, + { __index = { __call = function() end } } + ) + assert(meta.__call) + local not_callable = setmetatable({}, meta) + assert(not_callable.__call) + return { pcall(function() not_callable() end), vim.is_callable(not_callable) } + ]]) + ) + eq( + { false, false }, + exec_lua([[ + local meta = setmetatable({ + __index = function() + return function() end + end, + }, { + __index = function() + return function() end + end, + }) + assert(meta.__call) + local not_callable = setmetatable({}, meta) + assert(not_callable.__call) + return { pcall(function() not_callable() end), vim.is_callable(not_callable) } + ]]) + ) eq(false, exec_lua('return vim.is_callable(1)')) eq(false, exec_lua("return vim.is_callable('foo')")) eq(false, exec_lua('return vim.is_callable({})')) @@ -1891,7 +1947,7 @@ describe('lua stdlib', function() eq(NIL, fn.luaeval 'vim.v.null') matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.v[0].progpath')) eq('Key is read-only: count', pcall_err(exec_lua, [[vim.v.count = 42]])) - eq('Dictionary is locked', pcall_err(exec_lua, [[vim.v.nosuchvar = 42]])) + eq('Dict is locked', pcall_err(exec_lua, [[vim.v.nosuchvar = 42]])) eq('Key is fixed: errmsg', pcall_err(exec_lua, [[vim.v.errmsg = nil]])) exec_lua([[vim.v.errmsg = 'set by Lua']]) eq('set by Lua', eval('v:errmsg')) @@ -1919,16 +1975,12 @@ describe('lua stdlib', function() eq({ 1, 5 }, api.nvim_win_get_cursor(0)) local screen = Screen.new(60, 3) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { background = Screen.colors.Yellow }, - }) screen:attach() eq(1, eval('v:hlsearch')) screen:expect { grid = [[ - {1:foo} {1:^foo} {1:foo} | - {0:~ }| + {10:foo} {10:^foo} {10:foo} | + {1:~ }| | ]], } @@ -1937,7 +1989,7 @@ describe('lua stdlib', function() screen:expect { grid = [[ foo ^foo foo | - {0:~ }| + {1:~ }| | ]], } @@ -1945,8 +1997,8 @@ describe('lua stdlib', function() eq(1, eval('v:hlsearch')) screen:expect { grid = [[ - {1:foo} {1:^foo} {1:foo} | - {0:~ }| + {10:foo} {10:^foo} {10:foo} | + {1:~ }| | ]], } @@ -2005,13 +2057,17 @@ describe('lua stdlib', function() vim.cmd "enew" ]] eq(100, fn.luaeval 'vim.wo.scrolloff') + + matches('only bufnr=0 is supported', pcall_err(exec_lua, 'vim.wo[0][10].signcolumn = "no"')) + + matches('only bufnr=0 is supported', pcall_err(exec_lua, 'local a = vim.wo[0][10].signcolumn')) end) describe('vim.opt', function() -- TODO: We still need to write some tests for optlocal, opt and then getting the options -- Probably could also do some stuff with getting things from viml side as well to confirm behavior is the same. - it('should allow setting number values', function() + it('allows setting number values', function() local scrolloff = exec_lua [[ vim.opt.scrolloff = 10 return vim.o.scrolloff @@ -2019,7 +2075,7 @@ describe('lua stdlib', function() eq(10, scrolloff) end) - pending('should handle STUPID window things', function() + pending('handles STUPID window things', function() local result = exec_lua [[ local result = {} @@ -2032,7 +2088,7 @@ describe('lua stdlib', function() eq({}, result) end) - it('should allow setting tables', function() + it('allows setting tables', function() local wildignore = exec_lua [[ vim.opt.wildignore = { 'hello', 'world' } return vim.o.wildignore @@ -2040,7 +2096,7 @@ describe('lua stdlib', function() eq('hello,world', wildignore) end) - it('should allow setting tables with shortnames', function() + it('allows setting tables with shortnames', function() local wildignore = exec_lua [[ vim.opt.wig = { 'hello', 'world' } return vim.o.wildignore @@ -2048,7 +2104,7 @@ describe('lua stdlib', function() eq('hello,world', wildignore) end) - it('should error when you attempt to set string values to numeric options', function() + it('errors when you attempt to set string values to numeric options', function() local result = exec_lua [[ return { pcall(function() vim.opt.textwidth = 'hello world' end) @@ -2058,7 +2114,7 @@ describe('lua stdlib', function() eq(false, result[1]) end) - it('should error when you attempt to setlocal a global value', function() + it('errors when you attempt to setlocal a global value', function() local result = exec_lua [[ return pcall(function() vim.opt_local.clipboard = "hello" end) ]] @@ -2066,7 +2122,7 @@ describe('lua stdlib', function() eq(false, result) end) - it('should allow you to set boolean values', function() + it('allows you to set boolean values', function() eq( { true, false, true }, exec_lua [[ @@ -2086,7 +2142,7 @@ describe('lua stdlib', function() ) end) - it('should change current buffer values and defaults for global local values', function() + it('changes current buffer values and defaults for global local values', function() local result = exec_lua [[ local result = {} @@ -2125,7 +2181,7 @@ describe('lua stdlib', function() eq('', result[8]) end) - it('should allow you to retrieve window opts even if they have not been set', function() + it('allows you to retrieve window opts even if they have not been set', function() local result = exec_lua [[ local result = {} table.insert(result, vim.opt.number:get()) @@ -2140,7 +2196,7 @@ describe('lua stdlib', function() eq({ false, false, true, true }, result) end) - it('should allow all sorts of string manipulation', function() + it('allows all sorts of string manipulation', function() eq( { 'hello', 'hello world', 'start hello world' }, exec_lua [[ @@ -2161,7 +2217,7 @@ describe('lua stdlib', function() end) describe('option:get()', function() - it('should work for boolean values', function() + it('works for boolean values', function() eq( false, exec_lua [[ @@ -2171,7 +2227,7 @@ describe('lua stdlib', function() ) end) - it('should work for number values', function() + it('works for number values', function() local tabstop = exec_lua [[ vim.opt.tabstop = 10 return vim.opt.tabstop:get() @@ -2180,7 +2236,7 @@ describe('lua stdlib', function() eq(10, tabstop) end) - it('should work for string values', function() + it('works for string values', function() eq( 'hello world', exec_lua [[ @@ -2190,7 +2246,7 @@ describe('lua stdlib', function() ) end) - it('should work for set type flaglists', function() + it('works for set type flaglists', function() local formatoptions = exec_lua [[ vim.opt.formatoptions = 'tcro' return vim.opt.formatoptions:get() @@ -2200,7 +2256,7 @@ describe('lua stdlib', function() eq(true, not formatoptions.q) end) - it('should work for set type flaglists', function() + it('works for set type flaglists', function() local formatoptions = exec_lua [[ vim.opt.formatoptions = { t = true, c = true, r = true, o = true } return vim.opt.formatoptions:get() @@ -2210,7 +2266,7 @@ describe('lua stdlib', function() eq(true, not formatoptions.q) end) - it('should work for array list type options', function() + it('works for array list type options', function() local wildignore = exec_lua [[ vim.opt.wildignore = "*.c,*.o,__pycache__" return vim.opt.wildignore:get() @@ -2220,7 +2276,7 @@ describe('lua stdlib', function() eq('*.c', wildignore[1]) end) - it('should work for options that are both commalist and flaglist', function() + it('works for options that are both commalist and flaglist', function() local result = exec_lua [[ vim.opt.whichwrap = "b,s" return vim.opt.whichwrap:get() @@ -2236,7 +2292,7 @@ describe('lua stdlib', function() eq({ b = true, h = true }, result) end) - it('should work for key-value pair options', function() + it('works for key-value pair options', function() local listchars = exec_lua [[ vim.opt.listchars = "tab:> ,space:_" return vim.opt.listchars:get() @@ -2248,7 +2304,7 @@ describe('lua stdlib', function() }, listchars) end) - it('should allow you to add numeric options', function() + it('allows you to add numeric options', function() eq( 16, exec_lua [[ @@ -2259,7 +2315,7 @@ describe('lua stdlib', function() ) end) - it('should allow you to subtract numeric options', function() + it('allows you to subtract numeric options', function() eq( 2, exec_lua [[ @@ -2272,7 +2328,7 @@ describe('lua stdlib', function() end) describe('key:value style options', function() - it('should handle dictionary style', function() + it('handles dict style', function() local listchars = exec_lua [[ vim.opt.listchars = { eol = "~", @@ -2284,7 +2340,7 @@ describe('lua stdlib', function() eq('eol:~,space:.', listchars) end) - it('should allow adding dictionary style', function() + it('allows adding dict style', function() local listchars = exec_lua [[ vim.opt.listchars = { eol = "~", @@ -2299,7 +2355,7 @@ describe('lua stdlib', function() eq('eol:~,space:-', listchars) end) - it('should allow adding dictionary style', function() + it('allows adding dict style', function() local listchars = exec_lua [[ vim.opt.listchars = { eol = "~", @@ -2313,7 +2369,7 @@ describe('lua stdlib', function() eq('eol:~,space:_', listchars) end) - it('should allow completely new keys', function() + it('allows completely new keys', function() local listchars = exec_lua [[ vim.opt.listchars = { eol = "~", @@ -2327,7 +2383,7 @@ describe('lua stdlib', function() eq('eol:~,space:.,tab:>>>', listchars) end) - it('should allow subtracting dictionary style', function() + it('allows subtracting dict style', function() local listchars = exec_lua [[ vim.opt.listchars = { eol = "~", @@ -2341,7 +2397,7 @@ describe('lua stdlib', function() eq('eol:~', listchars) end) - it('should allow subtracting dictionary style', function() + it('allows subtracting dict style', function() local listchars = exec_lua [[ vim.opt.listchars = { eol = "~", @@ -2355,7 +2411,7 @@ describe('lua stdlib', function() eq('', listchars) end) - it('should allow subtracting dictionary style multiple times', function() + it('allows subtracting dict style multiple times', function() local listchars = exec_lua [[ vim.opt.listchars = { eol = "~", @@ -2369,7 +2425,7 @@ describe('lua stdlib', function() eq('eol:~', listchars) end) - it('should allow adding a key:value string to a listchars', function() + it('allows adding a key:value string to a listchars', function() local listchars = exec_lua [[ vim.opt.listchars = { eol = "~", @@ -2383,7 +2439,7 @@ describe('lua stdlib', function() eq('eol:~,space:.,tab:>~', listchars) end) - it('should allow prepending a key:value string to a listchars', function() + it('allows prepending a key:value string to a listchars', function() local listchars = exec_lua [[ vim.opt.listchars = { eol = "~", @@ -2398,7 +2454,7 @@ describe('lua stdlib', function() end) end) - it('should automatically set when calling remove', function() + it('automatically sets when calling remove', function() eq( 'foo,baz', exec_lua [[ @@ -2410,7 +2466,7 @@ describe('lua stdlib', function() ) end) - it('should automatically set when calling remove with a table', function() + it('automatically sets when calling remove with a table', function() eq( 'foo', exec_lua [[ @@ -2422,7 +2478,7 @@ describe('lua stdlib', function() ) end) - it('should automatically set when calling append', function() + it('automatically sets when calling append', function() eq( 'foo,bar,baz,bing', exec_lua [[ @@ -2434,7 +2490,7 @@ describe('lua stdlib', function() ) end) - it('should automatically set when calling append with a table', function() + it('automatically sets when calling append with a table', function() eq( 'foo,bar,baz,bing,zap', exec_lua [[ @@ -2446,7 +2502,7 @@ describe('lua stdlib', function() ) end) - it('should allow adding tables', function() + it('allows adding tables', function() local wildignore = exec_lua [[ vim.opt.wildignore = 'foo' return vim.o.wildignore @@ -2460,7 +2516,7 @@ describe('lua stdlib', function() eq('foo,bar,baz', wildignore) end) - it('should handle adding duplicates', function() + it('handles adding duplicates', function() local wildignore = exec_lua [[ vim.opt.wildignore = 'foo' return vim.o.wildignore @@ -2480,7 +2536,7 @@ describe('lua stdlib', function() eq('foo,bar,baz', wildignore) end) - it('should allow adding multiple times', function() + it('allows adding multiple times', function() local wildignore = exec_lua [[ vim.opt.wildignore = 'foo' vim.opt.wildignore = vim.opt.wildignore + 'bar' + 'baz' @@ -2489,7 +2545,7 @@ describe('lua stdlib', function() eq('foo,bar,baz', wildignore) end) - it('should remove values when you use minus', function() + it('removes values when you use minus', function() local wildignore = exec_lua [[ vim.opt.wildignore = 'foo' return vim.o.wildignore @@ -2509,7 +2565,7 @@ describe('lua stdlib', function() eq('foo,baz', wildignore) end) - it('should prepend values when using ^', function() + it('prepends values when using ^', function() local wildignore = exec_lua [[ vim.opt.wildignore = 'foo' vim.opt.wildignore = vim.opt.wildignore ^ 'first' @@ -2524,7 +2580,7 @@ describe('lua stdlib', function() eq('super_first,first,foo', wildignore) end) - it('should not remove duplicates from wildmode: #14708', function() + it('does not remove duplicates from wildmode: #14708', function() local wildmode = exec_lua [[ vim.opt.wildmode = {"full", "list", "full"} return vim.o.wildmode @@ -2534,7 +2590,7 @@ describe('lua stdlib', function() end) describe('option types', function() - it('should allow to set option with numeric value', function() + it('allows to set option with numeric value', function() eq( 4, exec_lua [[ @@ -2583,7 +2639,7 @@ describe('lua stdlib', function() ) end) - it('should allow to set option with boolean value', function() + it('allows to set option with boolean value', function() eq( true, exec_lua [[ @@ -2632,7 +2688,7 @@ describe('lua stdlib', function() ) end) - it('should allow to set option with array or string value', function() + it('allows to set option with array or string value', function() eq( 'indent,eol,start', exec_lua [[ @@ -2679,7 +2735,7 @@ describe('lua stdlib', function() ) end) - it('should allow set option with map or string value', function() + it('allows set option with map or string value', function() eq( 'eol:~,space:.', exec_lua [[ @@ -2729,7 +2785,7 @@ describe('lua stdlib', function() ) end) - it('should allow set option with set or string value', function() + it('allows set option with set or string value', function() local ww = exec_lua [[ vim.opt.whichwrap = { b = true, @@ -3179,11 +3235,11 @@ describe('lua stdlib', function() ]] end) - it('should run from lua', function() + it('runs from lua', function() exec_lua [[vim.wait(100, function() return true end)]] end) - it('should wait the expected time if false', function() + it('waits the expected time if false', function() eq( { time = true, wait_result = { false, -1 } }, exec_lua [[ @@ -3199,7 +3255,7 @@ describe('lua stdlib', function() ) end) - it('should not block other events', function() + it('does not block other events', function() eq( { time = true, wait_result = true }, exec_lua [[ @@ -3224,7 +3280,7 @@ describe('lua stdlib', function() ) end) - it('should not process non-fast events when commanded', function() + it('does not process non-fast events when commanded', function() eq( { wait_result = false }, exec_lua [[ @@ -3247,7 +3303,7 @@ describe('lua stdlib', function() ) end) - it('should work with vim.defer_fn', function() + it('works with vim.defer_fn', function() eq( { time = true, wait_result = true }, exec_lua [[ @@ -3264,7 +3320,7 @@ describe('lua stdlib', function() ) end) - it('should not crash when callback errors', function() + it('does not crash when callback errors', function() local result = exec_lua [[ return {pcall(function() vim.wait(1000, function() error("As Expected") end) end)} ]] @@ -3280,7 +3336,7 @@ describe('lua stdlib', function() ) end) - it('should allow waiting with no callback, explicit', function() + it('allows waiting with no callback, explicit', function() eq( true, exec_lua [[ @@ -3291,7 +3347,7 @@ describe('lua stdlib', function() ) end) - it('should allow waiting with no callback, implicit', function() + it('allows waiting with no callback, implicit', function() eq( true, exec_lua [[ @@ -3302,7 +3358,7 @@ describe('lua stdlib', function() ) end) - it('should call callbacks exactly once if they return true immediately', function() + it('calls callbacks exactly once if they return true immediately', function() eq( true, exec_lua [[ @@ -3316,7 +3372,7 @@ describe('lua stdlib', function() ) end) - it('should call callbacks few times with large `interval`', function() + it('calls callbacks few times with large `interval`', function() eq( true, exec_lua [[ @@ -3327,7 +3383,7 @@ describe('lua stdlib', function() ) end) - it('should play nice with `not` when fails', function() + it('plays nice with `not` when fails', function() eq( true, exec_lua [[ @@ -3340,7 +3396,7 @@ describe('lua stdlib', function() ) end) - it('should play nice with `if` when success', function() + it('plays nice with `if` when success', function() eq( true, exec_lua [[ @@ -3353,7 +3409,7 @@ describe('lua stdlib', function() ) end) - it('should return immediately with false if timeout is 0', function() + it('returns immediately with false if timeout is 0', function() eq( { false, -1 }, exec_lua [[ @@ -3364,7 +3420,7 @@ describe('lua stdlib', function() ) end) - it('should work with tables with __call', function() + it('works with tables with __call', function() eq( true, exec_lua [[ @@ -3374,7 +3430,7 @@ describe('lua stdlib', function() ) end) - it('should work with tables with __call that change', function() + it('works with tables with __call that change', function() eq( true, exec_lua [[ @@ -3391,7 +3447,7 @@ describe('lua stdlib', function() ) end) - it('should not work with negative intervals', function() + it('fails with negative intervals', function() local pcall_result = exec_lua [[ return pcall(function() vim.wait(1000, function() return false end, -1) end) ]] @@ -3399,7 +3455,7 @@ describe('lua stdlib', function() eq(false, pcall_result) end) - it('should not work with weird intervals', function() + it('fails with weird intervals', function() local pcall_result = exec_lua [[ return pcall(function() vim.wait(1000, function() return false end, 'a string value') end) ]] @@ -3442,7 +3498,7 @@ describe('lua stdlib', function() end) end) - it('should not run in fast callbacks #26122', function() + it('fails in fast callbacks #26122', function() local screen = Screen.new(80, 10) screen:attach() exec_lua([[ @@ -3462,15 +3518,11 @@ describe('lua stdlib', function() it('vim.notify_once', function() local screen = Screen.new(60, 5) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { foreground = Screen.colors.Red }, - }) screen:attach() screen:expect { grid = [[ ^ | - {0:~ }|*3 + {1:~ }|*3 | ]], } @@ -3478,15 +3530,15 @@ describe('lua stdlib', function() screen:expect { grid = [[ ^ | - {0:~ }|*3 - {1:I'll only tell you this once...} | + {1:~ }|*3 + {19:I'll only tell you this once...} | ]], } feed('<C-l>') screen:expect { grid = [[ ^ | - {0:~ }|*3 + {1:~ }|*3 | ]], } @@ -3663,10 +3715,6 @@ describe('lua stdlib', function() it('updates ruler if cursor moved', function() -- Fixed for win_execute in vim-patch:8.1.2124, but should've applied to nvim_win_call too! local screen = Screen.new(30, 5) - screen:set_default_attr_ids { - [1] = { reverse = true }, - [2] = { bold = true, reverse = true }, - } screen:attach() exec_lua [[ _G.api = vim.api @@ -3681,9 +3729,9 @@ describe('lua stdlib', function() ]] screen:expect [[ 19 | - {1:[No Name] [+] 20,1 3%}| - ^19 | {2:[No Name] [+] 20,1 3%}| + ^19 | + {3:[No Name] [+] 20,1 3%}| | ]] exec_lua [[ @@ -3692,9 +3740,9 @@ describe('lua stdlib', function() ]] screen:expect [[ 99 | - {1:[No Name] [+] 100,1 19%}| + {2:[No Name] [+] 100,1 19%}| ^19 | - {2:[No Name] [+] 20,1 3%}| + {3:[No Name] [+] 20,1 3%}| | ]] end) @@ -3810,13 +3858,6 @@ describe('lua stdlib', function() it('vim.lua_omnifunc', function() local screen = Screen.new(60, 5) - screen:set_default_attr_ids { - [1] = { foreground = Screen.colors.Blue1, bold = true }, - [2] = { background = Screen.colors.WebGray }, - [3] = { background = Screen.colors.LightMagenta }, - [4] = { bold = true }, - [5] = { foreground = Screen.colors.SeaGreen, bold = true }, - } screen:attach() command [[ set omnifunc=v:lua.vim.lua_omnifunc ]] @@ -3826,10 +3867,10 @@ describe('lua stdlib', function() screen:expect { grid = [[ vim.inspect^ | - {1:~ }{2: inspect }{1: }| - {1:~ }{3: inspect_pos }{1: }| + {1:~ }{12: inspect }{1: }| + {1:~ }{4: inspect_pos }{1: }| {1:~ }| - {4:-- Omni completion (^O^N^P) }{5:match 1 of 2} | + {5:-- Omni completion (^O^N^P) }{6:match 1 of 2} | ]], } end) @@ -4002,7 +4043,36 @@ end) describe('vim.keymap', function() before_each(clear) - it('can make a mapping', function() + it('validates', function() + matches( + 'mode: expected string|table, got number', + pcall_err(exec_lua, [[vim.keymap.set(42, 'x', print)]]) + ) + + matches( + 'rhs: expected string|function, got nil', + pcall_err(exec_lua, [[vim.keymap.set('n', 'x')]]) + ) + + matches( + 'lhs: expected string, got table', + pcall_err(exec_lua, [[vim.keymap.set('n', {}, print)]]) + ) + + matches( + 'opts: expected table, got function', + pcall_err(exec_lua, [[vim.keymap.set({}, 'x', 42, function() end)]]) + ) + + matches( + 'rhs: expected string|function, got number', + pcall_err(exec_lua, [[vim.keymap.set('z', 'x', 42)]]) + ) + + matches('Invalid mode shortname: "z"', pcall_err(exec_lua, [[vim.keymap.set('z', 'x', 'y')]])) + end) + + it('mapping', function() eq( 0, exec_lua [[ @@ -4017,7 +4087,7 @@ describe('vim.keymap', function() eq(1, exec_lua [[return GlobalCount]]) end) - it('can make an expr mapping', function() + it('expr mapping', function() exec_lua [[ vim.keymap.set('n', 'aa', function() return '<Insert>Ï€<C-V><M-Ï€>foo<lt><Esc>' end, {expr = true}) ]] @@ -4027,7 +4097,7 @@ describe('vim.keymap', function() eq({ 'Ï€<M-Ï€>foo<' }, api.nvim_buf_get_lines(0, 0, -1, false)) end) - it('can overwrite a mapping', function() + it('overwrite a mapping', function() eq( 0, exec_lua [[ @@ -4050,7 +4120,7 @@ describe('vim.keymap', function() eq(0, exec_lua [[return GlobalCount]]) end) - it('can unmap a mapping', function() + it('unmap', function() eq( 0, exec_lua [[ @@ -4074,7 +4144,7 @@ describe('vim.keymap', function() eq('\nNo mapping found', n.exec_capture('nmap asdf')) end) - it('works with buffer-local mappings', function() + it('buffer-local mappings', function() eq( 0, exec_lua [[ @@ -4116,7 +4186,7 @@ describe('vim.keymap', function() ) end) - it('can do <Plug> mappings', function() + it('<Plug> mappings', function() eq( 0, exec_lua [[ diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua index bd8faadf5b..ad16df8a7c 100644 --- a/test/functional/lua/watch_spec.lua +++ b/test/functional/lua/watch_spec.lua @@ -12,7 +12,6 @@ local skip = t.skip -- events which can happen with some backends on some platforms local function touch(path) local tmp = t.tmpname() - io.open(tmp, 'w'):close() assert(vim.uv.fs_rename(tmp, path)) end @@ -22,16 +21,78 @@ describe('vim._watch', function() end) local function run(watchfunc) - it('detects file changes (watchfunc=' .. watchfunc .. '())', function() - if watchfunc == 'fswatch' then + -- Monkey-patches vim.notify_once so we can "spy" on it. + local function spy_notify_once() + exec_lua [[ + _G.__notify_once_msgs = {} + vim.notify_once = (function(overridden) + return function(msg, level, opts) + table.insert(_G.__notify_once_msgs, msg) + return overridden(msg, level, opts) + end + end)(vim.notify_once) + ]] + end + + local function last_notify_once_msg() + return exec_lua 'return _G.__notify_once_msgs[#_G.__notify_once_msgs]' + end + + local function do_watch(root_dir, watchfunc_) + exec_lua( + [[ + local root_dir, watchfunc = ... + + _G.events = {} + + _G.stop_watch = vim._watch[watchfunc](root_dir, { + debounce = 100, + include_pattern = vim.lpeg.P(root_dir) * vim.lpeg.P("/file") ^ -1, + exclude_pattern = vim.lpeg.P(root_dir .. '/file.unwatched'), + }, function(path, change_type) + table.insert(_G.events, { path = path, change_type = change_type }) + end) + ]], + root_dir, + watchfunc_ + ) + end + + it(watchfunc .. '() ignores nonexistent paths', function() + if watchfunc == 'inotify' then + skip(n.fn.executable('inotifywait') == 0, 'inotifywait not found') + skip(is_os('bsd'), 'inotifywait on bsd CI seems to expect path to exist?') + end + + local msg = ('watch.%s: ENOENT: no such file or directory'):format(watchfunc) + + spy_notify_once() + do_watch('/i am /very/funny.go', watchfunc) + + if watchfunc ~= 'inotify' then -- watch.inotify() doesn't (currently) call vim.notify_once. + t.retry(nil, 2000, function() + t.eq(msg, last_notify_once_msg()) + end) + end + eq(0, exec_lua [[return #_G.events]]) + + exec_lua [[_G.stop_watch()]] + end) + + it(watchfunc .. '() detects file changes', function() + if watchfunc == 'inotify' then skip(is_os('win'), 'not supported on windows') skip(is_os('mac'), 'flaky test on mac') - skip(not is_ci() and n.fn.executable('fswatch') == 0, 'fswatch not installed and not on CI') + skip(not is_ci() and n.fn.executable('inotifywait') == 0, 'inotifywait not found') end + -- Note: because this is not `elseif`, BSD is skipped for *all* cases...? if watchfunc == 'watch' then skip(is_os('mac'), 'flaky test on mac') skip(is_os('bsd'), 'Stopped working on bsd after 3ca967387c49c754561c3b11a574797504d40f38') + elseif watchfunc == 'watchdirs' and is_os('mac') then + -- Bump this (or fix the bug) if CI continues to fail in future versions of macos CI. + skip(is_ci() and vim.uv.os_uname().release == '24.0.0', 'weird failure for macOS arm 15 CI') else skip( is_os('bsd'), @@ -39,10 +100,8 @@ describe('vim._watch', function() ) end - local root_dir = vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname()) .. '/nvim_XXXXXXXXXX') - local expected_events = 0 - + --- Waits for a new event, or fails if no events are triggered. local function wait_for_event() expected_events = expected_events + 1 exec_lua( @@ -63,26 +122,11 @@ describe('vim._watch', function() ) end + local root_dir = vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname(false)) .. '/nvim_XXXXXXXXXX') local unwatched_path = root_dir .. '/file.unwatched' local watched_path = root_dir .. '/file' - exec_lua( - [[ - local root_dir, watchfunc = ... - - _G.events = {} - - _G.stop_watch = vim._watch[watchfunc](root_dir, { - debounce = 100, - include_pattern = vim.lpeg.P(root_dir) * vim.lpeg.P("/file") ^ -1, - exclude_pattern = vim.lpeg.P(root_dir .. '/file.unwatched'), - }, function(path, change_type) - table.insert(_G.events, { path = path, change_type = change_type }) - end) - ]], - root_dir, - watchfunc - ) + do_watch(root_dir, watchfunc) if watchfunc ~= 'watch' then vim.uv.sleep(200) @@ -90,16 +134,13 @@ describe('vim._watch', function() touch(watched_path) touch(unwatched_path) - wait_for_event() os.remove(watched_path) os.remove(unwatched_path) - wait_for_event() exec_lua [[_G.stop_watch()]] - -- No events should come through anymore vim.uv.sleep(100) @@ -123,5 +164,5 @@ describe('vim._watch', function() run('watch') run('watchdirs') - run('fswatch') + run('inotify') end) diff --git a/test/functional/lua/with_spec.lua b/test/functional/lua/with_spec.lua new file mode 100644 index 0000000000..99b80ef749 --- /dev/null +++ b/test/functional/lua/with_spec.lua @@ -0,0 +1,1626 @@ +local t = require('test.testutil') +local n = require('test.functional.testnvim')() +local Screen = require('test.functional.ui.screen') + +local fn = n.fn +local api = n.api +local command = n.command +local eq = t.eq +local exec_lua = n.exec_lua +local exec_capture = n.exec_capture +local matches = t.matches +local pcall_err = t.pcall_err + +describe('vim._with', function() + before_each(function() + n.clear() + exec_lua([[ + _G.fn = vim.fn + _G.api = vim.api + + _G.setup_buffers = function() + return api.nvim_create_buf(false, true), api.nvim_get_current_buf() + end + + _G.setup_windows = function() + local other_win = api.nvim_get_current_win() + vim.cmd.new() + return other_win, api.nvim_get_current_win() + end + ]]) + end) + + local assert_events_trigger = function() + local out = exec_lua [[ + -- Needs three global values defined: + -- - `test_events` - array of events which are tested. + -- - `test_context` - context to be tested. + -- - `test_trig_event` - callable triggering at least one tested event. + _G.n_events = 0 + local opts = { callback = function() _G.n_events = _G.n_events + 1 end } + api.nvim_create_autocmd(_G.test_events, opts) + + local context = { bo = { commentstring = '-- %s' } } + + -- Should not trigger events on its own + vim._with(_G.test_context, function() end) + local is_no_events = _G.n_events == 0 + + -- Should trigger events if specifically asked inside callback + local is_events = vim._with(_G.test_context, function() + _G.test_trig_event() + return _G.n_events > 0 + end) + return { is_no_events, is_events } + ]] + eq({ true, true }, out) + end + + describe('`bo` context', function() + before_each(function() + exec_lua [[ + _G.other_buf, _G.cur_buf = setup_buffers() + + -- 'commentstring' is local to buffer and string + vim.bo[other_buf].commentstring = '## %s' + vim.bo[cur_buf].commentstring = '// %s' + vim.go.commentstring = '$$ %s' + + -- 'undolevels' is global or local to buffer (global-local) and number + vim.bo[other_buf].undolevels = 100 + vim.bo[cur_buf].undolevels = 250 + vim.go.undolevels = 500 + + _G.get_state = function() + return { + bo = { + cms_cur = vim.bo[cur_buf].commentstring, + cms_other = vim.bo[other_buf].commentstring, + ul_cur = vim.bo[cur_buf].undolevels, + ul_other = vim.bo[other_buf].undolevels, + }, + go = { + cms = vim.go.commentstring, + ul = vim.go.undolevels, + }, + } + end + ]] + end) + + it('works', function() + local out = exec_lua [[ + local context = { bo = { commentstring = '-- %s', undolevels = 0 } } + + local before = get_state() + local inner = vim._with(context, function() + assert(api.nvim_get_current_buf() == cur_buf) + return get_state() + end) + + return { before = before, inner = inner, after = get_state() } + ]] + + eq({ + bo = { cms_cur = '-- %s', cms_other = '## %s', ul_cur = 0, ul_other = 100 }, + go = { cms = '$$ %s', ul = 500 }, + }, out.inner) + eq(out.before, out.after) + end) + + it('sets options in `buf` context', function() + local out = exec_lua [[ + local context = { buf = other_buf, bo = { commentstring = '-- %s', undolevels = 0 } } + + local before = get_state() + local inner = vim._with(context, function() + assert(api.nvim_get_current_buf() == other_buf) + return get_state() + end) + + return { before = before, inner = inner, after = get_state() } + ]] + + eq({ + bo = { cms_cur = '// %s', cms_other = '-- %s', ul_cur = 250, ul_other = 0 }, + go = { cms = '$$ %s', ul = 500 }, + }, out.inner) + eq(out.before, out.after) + end) + + it('restores only options from context', function() + local out = exec_lua [[ + local context = { bo = { commentstring = '-- %s' } } + + local inner = vim._with(context, function() + assert(api.nvim_get_current_buf() == cur_buf) + vim.bo[cur_buf].undolevels = 750 + vim.bo[cur_buf].commentstring = '!! %s' + return get_state() + end) + + return { inner = inner, after = get_state() } + ]] + + eq({ + bo = { cms_cur = '!! %s', cms_other = '## %s', ul_cur = 750, ul_other = 100 }, + go = { cms = '$$ %s', ul = 500 }, + }, out.inner) + eq({ + bo = { cms_cur = '// %s', cms_other = '## %s', ul_cur = 750, ul_other = 100 }, + go = { cms = '$$ %s', ul = 500 }, + }, out.after) + end) + + it('does not trigger events', function() + exec_lua [[ + _G.test_events = { 'BufEnter', 'BufLeave', 'BufWinEnter', 'BufWinLeave' } + _G.test_context = { bo = { commentstring = '-- %s' } } + _G.test_trig_event = function() vim.cmd.new() end + ]] + assert_events_trigger() + end) + + it('can be nested', function() + local out = exec_lua [[ + local before, before_inner, after_inner = get_state(), nil, nil + vim._with({ bo = { commentstring = '-- %s', undolevels = 0 } }, function() + before_inner = get_state() + inner = vim._with({ bo = { commentstring = '!! %s' } }, get_state) + after_inner = get_state() + end) + return { + before = before, before_inner = before_inner, + inner = inner, + after_inner = after_inner, after = get_state(), + } + ]] + eq('!! %s', out.inner.bo.cms_cur) + eq(0, out.inner.bo.ul_cur) + eq(out.before_inner, out.after_inner) + eq(out.before, out.after) + end) + end) + + describe('`buf` context', function() + it('works', function() + local out = exec_lua [[ + local other_buf, cur_buf = setup_buffers() + local inner = vim._with({ buf = other_buf }, function() + return api.nvim_get_current_buf() + end) + return { inner == other_buf, api.nvim_get_current_buf() == cur_buf } + ]] + eq({ true, true }, out) + end) + + it('does not trigger events', function() + exec_lua [[ + _G.test_events = { 'BufEnter', 'BufLeave', 'BufWinEnter', 'BufWinLeave' } + _G.test_context = { buf = other_buf } + _G.test_trig_event = function() vim.cmd.new() end + ]] + assert_events_trigger() + end) + + it('can access buffer options', function() + local out = exec_lua [[ + other_buf, cur_buf = setup_buffers() + vim.bo[other_buf].commentstring = '## %s' + vim.bo[cur_buf].commentstring = '// %s' + + vim._with({ buf = other_buf }, function() + vim.cmd.set('commentstring=--\\ %s') + end) + + return vim.bo[other_buf].commentstring == '-- %s' and + vim.bo[cur_buf].commentstring == '// %s' + ]] + eq(true, out) + end) + + it('works with different kinds of buffers', function() + exec_lua [[ + local assert_buf = function(buf) + vim._with({ buf = buf }, function() + assert(api.nvim_get_current_buf() == buf) + end) + end + + -- Current + assert_buf(api.nvim_get_current_buf()) + + -- Hidden listed + local listed = api.nvim_create_buf(true, true) + assert_buf(listed) + + -- Visible + local other_win, cur_win = setup_windows() + api.nvim_win_set_buf(other_win, listed) + assert_buf(listed) + + -- Shown but not visible + vim.cmd.tabnew() + assert_buf(listed) + + -- Shown in several windows + api.nvim_win_set_buf(0, listed) + assert_buf(listed) + + -- Shown in floating window + local float_buf = api.nvim_create_buf(false, true) + local config = { relative = 'editor', row = 1, col = 1, width = 5, height = 5 } + api.nvim_open_win(float_buf, false, config) + assert_buf(float_buf) + ]] + end) + + it('does not cause ml_get errors with invalid visual selection', function() + exec_lua [[ + api.nvim_buf_set_lines(0, 0, -1, true, { 'a', 'b', 'c' }) + api.nvim_feedkeys(vim.keycode('G<C-V>'), 'txn', false) + local other_buf, _ = setup_buffers() + vim._with({ buf = buf }, function() vim.cmd.redraw() end) + ]] + end) + + it('can be nested', function() + exec_lua [[ + local other_buf, cur_buf = setup_buffers() + vim._with({ buf = other_buf }, function() + assert(api.nvim_get_current_buf() == other_buf) + inner = vim._with({ buf = cur_buf }, function() + assert(api.nvim_get_current_buf() == cur_buf) + end) + assert(api.nvim_get_current_buf() == other_buf) + end) + assert(api.nvim_get_current_buf() == cur_buf) + ]] + end) + + it('can be nested crazily with hidden buffers', function() + local out = exec_lua([[ + local n = 0 + local function with_recursive_nested_bufs() + n = n + 1 + if n > 20 then return true end + + local other_buf, _ = setup_buffers() + vim.bo[other_buf].commentstring = '## %s' + local callback = function() + return api.nvim_get_current_buf() == other_buf + and vim.bo[other_buf].commentstring == '## %s' + and with_recursive_nested_bufs() + end + return vim._with({ buf = other_buf }, callback) and + api.nvim_buf_delete(other_buf, {}) == nil + end + + return with_recursive_nested_bufs() + ]]) + eq(true, out) + end) + end) + + describe('`emsg_silent` context', function() + pending('works', function() + local ok = pcall( + exec_lua, + [[ + _G.f = function() + error('This error should not interfer with execution', 0) + end + -- Should not produce error same as `vim.cmd('silent! lua _G.f()')` + vim._with({ emsg_silent = true }, f) + ]] + ) + eq(true, ok) + + -- Should properly report errors afterwards + ok = pcall(exec_lua, 'lua _G.f()') + eq(false, ok) + end) + + it('can be nested', function() + local ok = pcall( + exec_lua, + [[ + _G.f = function() + error('This error should not interfer with execution', 0) + end + -- Should produce error same as `_G.f()` + vim._with({ emsg_silent = true }, function() + vim._with( { emsg_silent = false }, f) + end) + ]] + ) + eq(false, ok) + end) + end) + + describe('`env` context', function() + before_each(function() + exec_lua [[ + vim.fn.setenv('aaa', 'hello') + _G.get_state = function() + return { aaa = vim.fn.getenv('aaa'), bbb = vim.fn.getenv('bbb') } + end + ]] + end) + + it('works', function() + local out = exec_lua [[ + local context = { env = { aaa = 'inside', bbb = 'wow' } } + local before = get_state() + local inner = vim._with(context, get_state) + return { before = before, inner = inner, after = get_state() } + ]] + + eq({ aaa = 'inside', bbb = 'wow' }, out.inner) + eq(out.before, out.after) + end) + + it('restores only variables from context', function() + local out = exec_lua [[ + local context = { env = { bbb = 'wow' } } + local before = get_state() + local inner = vim._with(context, function() + vim.env.aaa = 'inside' + return get_state() + end) + return { before = before, inner = inner, after = get_state() } + ]] + + eq({ aaa = 'inside', bbb = 'wow' }, out.inner) + eq({ aaa = 'inside', bbb = vim.NIL }, out.after) + end) + + it('can be nested', function() + local out = exec_lua [[ + local before, before_inner, after_inner = get_state(), nil, nil + vim._with({ env = { aaa = 'inside', bbb = 'wow' } }, function() + before_inner = get_state() + inner = vim._with({ env = { aaa = 'more inside' } }, get_state) + after_inner = get_state() + end) + return { + before = before, before_inner = before_inner, + inner = inner, + after_inner = after_inner, after = get_state(), + } + ]] + eq('more inside', out.inner.aaa) + eq('wow', out.inner.bbb) + eq(out.before_inner, out.after_inner) + eq(out.before, out.after) + end) + end) + + describe('`go` context', function() + before_each(function() + exec_lua [[ + vim.bo.commentstring = '## %s' + vim.go.commentstring = '$$ %s' + vim.wo.winblend = 25 + vim.go.winblend = 50 + vim.go.langmap = 'xy,yx' + + _G.get_state = function() + return { + bo = { cms = vim.bo.commentstring }, + wo = { winbl = vim.wo.winblend }, + go = { + cms = vim.go.commentstring, + winbl = vim.go.winblend, + lmap = vim.go.langmap, + }, + } + end + ]] + end) + + it('works', function() + local out = exec_lua [[ + local context = { + go = { commentstring = '-- %s', winblend = 75, langmap = 'ab,ba' }, + } + local before = get_state() + local inner = vim._with(context, get_state) + return { before = before, inner = inner, after = get_state() } + ]] + + eq({ + bo = { cms = '## %s' }, + wo = { winbl = 25 }, + go = { cms = '-- %s', winbl = 75, lmap = 'ab,ba' }, + }, out.inner) + eq(out.before, out.after) + end) + + it('works with `eventignore`', function() + -- This might be an issue if saving and restoring option context is done + -- to account for triggering `OptionSet`, but in not a good way + local out = exec_lua [[ + vim.go.eventignore = 'ModeChanged' + local inner = vim._with({ go = { eventignore = 'CursorMoved' } }, function() + return vim.go.eventignore + end) + return { inner = inner, after = vim.go.eventignore } + ]] + eq({ inner = 'CursorMoved', after = 'ModeChanged' }, out) + end) + + it('restores only options from context', function() + local out = exec_lua [[ + local context = { go = { langmap = 'ab,ba' } } + + local inner = vim._with(context, function() + vim.go.commentstring = '!! %s' + vim.go.winblend = 75 + vim.go.langmap = 'uv,vu' + return get_state() + end) + + return { inner = inner, after = get_state() } + ]] + + eq({ + bo = { cms = '## %s' }, + wo = { winbl = 25 }, + go = { cms = '!! %s', winbl = 75, lmap = 'uv,vu' }, + }, out.inner) + eq({ + bo = { cms = '## %s' }, + wo = { winbl = 25 }, + go = { cms = '!! %s', winbl = 75, lmap = 'xy,yx' }, + }, out.after) + end) + + it('does not trigger events', function() + exec_lua [[ + _G.test_events = { + 'BufEnter', 'BufLeave', 'BufWinEnter', 'BufWinLeave', 'WinEnter', 'WinLeave' + } + _G.test_context = { go = { commentstring = '-- %s', winblend = 75, langmap = 'ab,ba' } } + _G.test_trig_event = function() vim.cmd.new() end + ]] + assert_events_trigger() + end) + + it('can be nested', function() + local out = exec_lua [[ + local before, before_inner, after_inner = get_state(), nil, nil + vim._with({ go = { langmap = 'ab,ba', commentstring = '-- %s' } }, function() + before_inner = get_state() + inner = vim._with({ go = { langmap = 'uv,vu' } }, get_state) + after_inner = get_state() + end) + return { + before = before, before_inner = before_inner, + inner = inner, + after_inner = after_inner, after = get_state(), + } + ]] + eq('uv,vu', out.inner.go.lmap) + eq('-- %s', out.inner.go.cms) + eq(out.before_inner, out.after_inner) + eq(out.before, out.after) + end) + end) + + describe('`hide` context', function() + pending('works', function() + local ok = pcall( + exec_lua, + [[ + vim.o.hidden = false + vim.bo.modified = true + local init_buf = api.nvim_get_current_buf() + -- Should not produce error same as `vim.cmd('hide enew')` + vim._with({ hide = true }, function() + vim.cmd.enew() + end) + assert(api.nvim_get_current_buf() ~= init_buf) + ]] + ) + eq(true, ok) + end) + + it('can be nested', function() + local ok = pcall( + exec_lua, + [[ + vim.o.hidden = false + vim.bo.modified = true + -- Should produce error same as `vim.cmd.enew()` + vim._with({ hide = true }, function() + vim._with({ hide = false }, function() + vim.cmd.enew() + end) + end) + ]] + ) + eq(false, ok) + end) + end) + + describe('`horizontal` context', function() + local is_approx_eq = function(dim, id_1, id_2) + local f = dim == 'height' and api.nvim_win_get_height or api.nvim_win_get_width + return math.abs(f(id_1) - f(id_2)) <= 1 + end + + local win_id_1, win_id_2, win_id_3 + before_each(function() + win_id_1 = api.nvim_get_current_win() + command('wincmd v | wincmd 5>') + win_id_2 = api.nvim_get_current_win() + command('wincmd s | wincmd 5+') + win_id_3 = api.nvim_get_current_win() + + eq(is_approx_eq('width', win_id_1, win_id_2), false) + eq(is_approx_eq('height', win_id_3, win_id_2), false) + end) + + pending('works', function() + exec_lua [[ + -- Should be same as `vim.cmd('horizontal wincmd =')` + vim._with({ horizontal = true }, function() + vim.cmd.wincmd('=') + end) + ]] + eq(is_approx_eq('width', win_id_1, win_id_2), true) + eq(is_approx_eq('height', win_id_3, win_id_2), false) + end) + + pending('can be nested', function() + exec_lua [[ + -- Should be same as `vim.cmd.wincmd('=')` + vim._with({ horizontal = true }, function() + vim._with({ horizontal = false }, function() + vim.cmd.wincmd('=') + end) + end) + ]] + eq(is_approx_eq('width', win_id_1, win_id_2), true) + eq(is_approx_eq('height', win_id_3, win_id_2), true) + end) + end) + + describe('`keepalt` context', function() + pending('works', function() + local out = exec_lua [[ + vim.cmd('edit alt') + vim.cmd('edit new') + assert(fn.bufname('#') == 'alt') + + -- Should work as `vim.cmd('keepalt edit very-new')` + vim._with({ keepalt = true }, function() + vim.cmd.edit('very-new') + end) + return fn.bufname('#') == 'alt' + ]] + eq(true, out) + end) + + it('can be nested', function() + local out = exec_lua [[ + vim.cmd('edit alt') + vim.cmd('edit new') + assert(fn.bufname('#') == 'alt') + + -- Should work as `vim.cmd.edit('very-new')` + vim._with({ keepalt = true }, function() + vim._with({ keepalt = false }, function() + vim.cmd.edit('very-new') + end) + end) + return fn.bufname('#') == 'alt' + ]] + eq(false, out) + end) + end) + + describe('`keepjumps` context', function() + pending('works', function() + local out = exec_lua [[ + api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb', 'ccc' }) + local jumplist_before = fn.getjumplist() + -- Should work as `vim.cmd('keepjumps normal! Ggg')` + vim._with({ keepjumps = true }, function() + vim.cmd('normal! Ggg') + end) + return vim.deep_equal(jumplist_before, fn.getjumplist()) + ]] + eq(true, out) + end) + + it('can be nested', function() + local out = exec_lua [[ + api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb', 'ccc' }) + local jumplist_before = fn.getjumplist() + vim._with({ keepjumps = true }, function() + vim._with({ keepjumps = false }, function() + vim.cmd('normal! Ggg') + end) + end) + return vim.deep_equal(jumplist_before, fn.getjumplist()) + ]] + eq(false, out) + end) + end) + + describe('`keepmarks` context', function() + pending('works', function() + local out = exec_lua [[ + vim.cmd('set cpoptions+=R') + api.nvim_buf_set_lines(0, 0, -1, false, { 'bbb', 'ccc', 'aaa' }) + api.nvim_buf_set_mark(0, 'm', 2, 2, {}) + + -- Should be the same as `vim.cmd('keepmarks %!sort')` + vim._with({ keepmarks = true }, function() + vim.cmd('%!sort') + end) + return api.nvim_buf_get_mark(0, 'm') + ]] + eq({ 2, 2 }, out) + end) + + it('can be nested', function() + local out = exec_lua [[ + vim.cmd('set cpoptions+=R') + api.nvim_buf_set_lines(0, 0, -1, false, { 'bbb', 'ccc', 'aaa' }) + api.nvim_buf_set_mark(0, 'm', 2, 2, {}) + + vim._with({ keepmarks = true }, function() + vim._with({ keepmarks = false }, function() + vim.cmd('%!sort') + end) + end) + return api.nvim_buf_get_mark(0, 'm') + ]] + eq({ 0, 2 }, out) + end) + end) + + describe('`keepatterns` context', function() + pending('works', function() + local out = exec_lua [[ + api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb' }) + vim.cmd('/aaa') + -- Should be the same as `vim.cmd('keeppatterns /bbb')` + vim._with({ keeppatterns = true }, function() + vim.cmd('/bbb') + end) + return fn.getreg('/') + ]] + eq('aaa', out) + end) + + it('can be nested', function() + local out = exec_lua [[ + api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb' }) + vim.cmd('/aaa') + vim._with({ keeppatterns = true }, function() + vim._with({ keeppatterns = false }, function() + vim.cmd('/bbb') + end) + end) + return fn.getreg('/') + ]] + eq('bbb', out) + end) + end) + + describe('`lockmarks` context', function() + it('works', function() + local mark = exec_lua [[ + api.nvim_buf_set_lines(0, 0, 0, false, { 'aaa', 'bbb', 'ccc' }) + api.nvim_buf_set_mark(0, 'm', 2, 2, {}) + -- Should be same as `:lockmarks lua api.nvim_buf_set_lines(...)` + vim._with({ lockmarks = true }, function() + api.nvim_buf_set_lines(0, 0, 2, false, { 'uuu', 'vvv', 'www' }) + end) + return api.nvim_buf_get_mark(0, 'm') + ]] + eq({ 2, 2 }, mark) + end) + + it('can be nested', function() + local mark = exec_lua [[ + api.nvim_buf_set_lines(0, 0, 0, false, { 'aaa', 'bbb', 'ccc' }) + api.nvim_buf_set_mark(0, 'm', 2, 2, {}) + vim._with({ lockmarks = true }, function() + vim._with({ lockmarks = false }, function() + api.nvim_buf_set_lines(0, 0, 2, false, { 'uuu', 'vvv', 'www' }) + end) + end) + return api.nvim_buf_get_mark(0, 'm') + ]] + eq({ 0, 2 }, mark) + end) + end) + + describe('`noautocmd` context', function() + it('works', function() + local out = exec_lua [[ + _G.n_events = 0 + vim.cmd('au ModeChanged * lua _G.n_events = _G.n_events + 1') + -- Should be the same as `vim.cmd('noautocmd normal! vv')` + vim._with({ noautocmd = true }, function() + vim.cmd('normal! vv') + end) + return _G.n_events + ]] + eq(0, out) + end) + + it('works with User events', function() + local out = exec_lua [[ + _G.n_events = 0 + vim.cmd('au User MyEvent lua _G.n_events = _G.n_events + 1') + -- Should be the same as `vim.cmd('noautocmd doautocmd User MyEvent')` + vim._with({ noautocmd = true }, function() + api.nvim_exec_autocmds('User', { pattern = 'MyEvent' }) + end) + return _G.n_events + ]] + eq(0, out) + end) + + pending('can be nested', function() + local out = exec_lua [[ + _G.n_events = 0 + vim.cmd('au ModeChanged * lua _G.n_events = _G.n_events + 1') + vim._with({ noautocmd = true }, function() + vim._with({ noautocmd = false }, function() + vim.cmd('normal! vv') + end) + end) + return _G.n_events + ]] + eq(2, out) + end) + end) + + describe('`o` context', function() + before_each(function() + exec_lua [[ + _G.other_win, _G.cur_win = setup_windows() + _G.other_buf, _G.cur_buf = setup_buffers() + + vim.bo[other_buf].commentstring = '## %s' + vim.bo[cur_buf].commentstring = '// %s' + vim.go.commentstring = '$$ %s' + + vim.bo[other_buf].undolevels = 100 + vim.bo[cur_buf].undolevels = 250 + vim.go.undolevels = 500 + + vim.wo[other_win].virtualedit = 'block' + vim.wo[cur_win].virtualedit = 'insert' + vim.go.virtualedit = 'none' + + vim.wo[other_win].winblend = 10 + vim.wo[cur_win].winblend = 25 + vim.go.winblend = 50 + + vim.go.langmap = 'xy,yx' + + _G.get_state = function() + return { + bo = { + cms_cur = vim.bo[cur_buf].commentstring, + cms_other = vim.bo[other_buf].commentstring, + ul_cur = vim.bo[cur_buf].undolevels, + ul_other = vim.bo[other_buf].undolevels, + }, + wo = { + ve_cur = vim.wo[cur_win].virtualedit, + ve_other = vim.wo[other_win].virtualedit, + winbl_cur = vim.wo[cur_win].winblend, + winbl_other = vim.wo[other_win].winblend, + }, + go = { + cms = vim.go.commentstring, + ul = vim.go.undolevels, + ve = vim.go.virtualedit, + winbl = vim.go.winblend, + lmap = vim.go.langmap, + }, + } + end + ]] + end) + + it('works', function() + local out = exec_lua [[ + local context = { + o = { + commentstring = '-- %s', + undolevels = 0, + virtualedit = 'all', + winblend = 75, + langmap = 'ab,ba', + }, + } + + local before = get_state() + local inner = vim._with(context, function() + assert(api.nvim_get_current_buf() == cur_buf) + assert(api.nvim_get_current_win() == cur_win) + return get_state() + end) + + return { before = before, inner = inner, after = get_state() } + ]] + + -- Options in context are set with `vim.o`, so usually both local + -- and global values are affected. Yet all of them should be later + -- restored to pre-context values. + eq({ + bo = { cms_cur = '-- %s', cms_other = '## %s', ul_cur = -123456, ul_other = 100 }, + wo = { ve_cur = 'all', ve_other = 'block', winbl_cur = 75, winbl_other = 10 }, + go = { cms = '-- %s', ul = 0, ve = 'all', winbl = 75, lmap = 'ab,ba' }, + }, out.inner) + eq(out.before, out.after) + end) + + it('sets options in `buf` context', function() + local out = exec_lua [[ + local context = { buf = other_buf, o = { commentstring = '-- %s', undolevels = 0 } } + + local before = get_state() + local inner = vim._with(context, function() + assert(api.nvim_get_current_buf() == other_buf) + return get_state() + end) + + return { before = before, inner = inner, after = get_state() } + ]] + + eq({ + bo = { cms_cur = '// %s', cms_other = '-- %s', ul_cur = 250, ul_other = -123456 }, + wo = { ve_cur = 'insert', ve_other = 'block', winbl_cur = 25, winbl_other = 10 }, + -- Global `winbl` inside context ideally should be untouched and equal + -- to 50. It seems to be equal to 0 because `context.buf` uses + -- `aucmd_prepbuf` C approach which has no guarantees about window or + -- window option values inside context. + go = { cms = '-- %s', ul = 0, ve = 'none', winbl = 0, lmap = 'xy,yx' }, + }, out.inner) + eq(out.before, out.after) + end) + + it('sets options in `win` context', function() + local out = exec_lua [[ + local context = { win = other_win, o = { winblend = 75, virtualedit = 'all' } } + + local before = get_state() + local inner = vim._with(context, function() + assert(api.nvim_get_current_win() == other_win) + return get_state() + end) + + return { before = before, inner = inner, after = get_state() } + ]] + + eq({ + bo = { cms_cur = '// %s', cms_other = '## %s', ul_cur = 250, ul_other = 100 }, + wo = { winbl_cur = 25, winbl_other = 75, ve_cur = 'insert', ve_other = 'all' }, + go = { cms = '$$ %s', ul = 500, winbl = 75, ve = 'all', lmap = 'xy,yx' }, + }, out.inner) + eq(out.before, out.after) + end) + + it('restores only options from context', function() + local out = exec_lua [[ + local context = { o = { undolevels = 0, winblend = 75, langmap = 'ab,ba' } } + + local inner = vim._with(context, function() + assert(api.nvim_get_current_buf() == cur_buf) + assert(api.nvim_get_current_win() == cur_win) + + vim.o.commentstring = '!! %s' + vim.o.undolevels = 750 + vim.o.virtualedit = 'onemore' + vim.o.winblend = 99 + vim.o.langmap = 'uv,vu' + return get_state() + end) + + return { inner = inner, after = get_state() } + ]] + + eq({ + bo = { cms_cur = '!! %s', cms_other = '## %s', ul_cur = -123456, ul_other = 100 }, + wo = { ve_cur = 'onemore', ve_other = 'block', winbl_cur = 99, winbl_other = 10 }, + go = { cms = '!! %s', ul = 750, ve = 'onemore', winbl = 99, lmap = 'uv,vu' }, + }, out.inner) + eq({ + bo = { cms_cur = '!! %s', cms_other = '## %s', ul_cur = 250, ul_other = 100 }, + wo = { ve_cur = 'onemore', ve_other = 'block', winbl_cur = 25, winbl_other = 10 }, + go = { cms = '!! %s', ul = 500, ve = 'onemore', winbl = 50, lmap = 'xy,yx' }, + }, out.after) + end) + + it('does not trigger events', function() + exec_lua [[ + _G.test_events = { + 'BufEnter', 'BufLeave', 'WinEnter', 'WinLeave', 'BufWinEnter', 'BufWinLeave' + } + _G.test_context = { o = { undolevels = 0, winblend = 75, langmap = 'ab,ba' } } + _G.test_trig_event = function() vim.cmd.new() end + ]] + assert_events_trigger() + end) + + it('can be nested', function() + local out = exec_lua [[ + local before, before_inner, after_inner = get_state(), nil, nil + local cxt_o = { commentstring = '-- %s', winblend = 75, langmap = 'ab,ba', undolevels = 0 } + vim._with({ o = cxt_o }, function() + before_inner = get_state() + local inner_cxt_o = { commentstring = '!! %s', winblend = 99, langmap = 'uv,vu' } + inner = vim._with({ o = inner_cxt_o }, get_state) + after_inner = get_state() + end) + return { + before = before, before_inner = before_inner, + inner = inner, + after_inner = after_inner, after = get_state(), + } + ]] + eq('!! %s', out.inner.bo.cms_cur) + eq(99, out.inner.wo.winbl_cur) + eq('uv,vu', out.inner.go.lmap) + eq(0, out.inner.go.ul) + eq(out.before_inner, out.after_inner) + eq(out.before, out.after) + end) + end) + + describe('`sandbox` context', function() + it('works', function() + local ok, err = pcall( + exec_lua, + [[ + -- Should work as `vim.cmd('sandbox call append(0, "aaa")')` + vim._with({ sandbox = true }, function() + fn.append(0, 'aaa') + end) + ]] + ) + eq(false, ok) + matches('Not allowed in sandbox', err) + end) + + it('can NOT be nested', function() + -- This behavior is intentionally different from other flags as allowing + -- disabling `sandbox` from nested function seems to be against the point + -- of using `sandbox` context in the first place + local ok, err = pcall( + exec_lua, + [[ + vim._with({ sandbox = true }, function() + vim._with({ sandbox = false }, function() + fn.append(0, 'aaa') + end) + end) + ]] + ) + eq(false, ok) + matches('Not allowed in sandbox', err) + end) + end) + + describe('`silent` context', function() + it('works', function() + exec_lua [[ + -- Should be same as `vim.cmd('silent lua print("aaa")')` + vim._with({ silent = true }, function() print('aaa') end) + ]] + eq('', exec_capture('messages')) + + exec_lua [[ vim._with({ silent = true }, function() vim.cmd.echomsg('"bbb"') end) ]] + eq('', exec_capture('messages')) + + local screen = Screen.new(20, 5) + screen:set_default_attr_ids { + [1] = { bold = true, reverse = true }, + [2] = { bold = true, foreground = Screen.colors.Blue }, + } + screen:attach() + exec_lua [[ vim._with({ silent = true }, function() vim.cmd.echo('"ccc"') end) ]] + screen:expect [[ + ^ | + {2:~ }|*3 + | + ]] + end) + + pending('can be nested', function() + exec_lua [[ vim._with({ silent = true }, function() + vim._with({ silent = false }, function() + print('aaa') + end) + end)]] + eq('aaa', exec_capture('messages')) + end) + end) + + describe('`unsilent` context', function() + it('works', function() + exec_lua [[ + _G.f = function() + -- Should be same as `vim.cmd('unsilent lua print("aaa")')` + vim._with({ unsilent = true }, function() print('aaa') end) + end + ]] + command('silent lua f()') + eq('aaa', exec_capture('messages')) + end) + + pending('can be nested', function() + exec_lua [[ + _G.f = function() + vim._with({ unsilent = true }, function() + vim._with({ unsilent = false }, function() print('aaa') end) + end) + end + ]] + command('silent lua f()') + eq('', exec_capture('messages')) + end) + end) + + describe('`win` context', function() + it('works', function() + local out = exec_lua [[ + local other_win, cur_win = setup_windows() + local inner = vim._with({ win = other_win }, function() + return api.nvim_get_current_win() + end) + return { inner == other_win, api.nvim_get_current_win() == cur_win } + ]] + eq({ true, true }, out) + end) + + it('does not trigger events', function() + exec_lua [[ + _G.test_events = { 'WinEnter', 'WinLeave', 'BufWinEnter', 'BufWinLeave' } + _G.test_context = { win = other_win } + _G.test_trig_event = function() vim.cmd.new() end + ]] + assert_events_trigger() + end) + + it('can access window options', function() + local out = exec_lua [[ + local other_win, cur_win = setup_windows() + vim.wo[other_win].winblend = 10 + vim.wo[cur_win].winblend = 25 + + vim._with({ win = other_win }, function() + vim.cmd.setlocal('winblend=0') + end) + + return vim.wo[other_win].winblend == 0 and vim.wo[cur_win].winblend == 25 + ]] + eq(true, out) + end) + + it('works with different kinds of windows', function() + exec_lua [[ + local assert_win = function(win) + vim._with({ win = win }, function() + assert(api.nvim_get_current_win() == win) + end) + end + + -- Current + assert_win(api.nvim_get_current_win()) + + -- Not visible + local other_win, cur_win = setup_windows() + vim.cmd.tabnew() + assert_win(other_win) + + -- Floating + local float_win = api.nvim_open_win( + api.nvim_create_buf(false, true), + false, + { relative = 'editor', row = 1, col = 1, height = 5, width = 5} + ) + assert_win(float_win) + ]] + end) + + it('does not cause ml_get errors with invalid visual selection', function() + exec_lua [[ + local feedkeys = function(keys) api.nvim_feedkeys(vim.keycode(keys), 'txn', false) end + + -- Add lines to the current buffer and make another window looking into an empty buffer. + local win_empty, win_lines = setup_windows() + api.nvim_buf_set_lines(0, 0, -1, true, { 'a', 'b', 'c' }) + + -- Start Visual in current window, redraw in other window with fewer lines. + -- Should be fixed by vim-patch:8.2.4018. + feedkeys('G<C-V>') + vim._with({ win = win_empty }, function() vim.cmd.redraw() end) + + -- Start Visual in current window, extend it in other window with more lines. + -- Fixed for win_execute by vim-patch:8.2.4026, but nvim_win_call should also not be affected. + feedkeys('<Esc>gg') + api.nvim_set_current_win(win_empty) + feedkeys('gg<C-V>') + vim._with({ win = win_lines }, function() feedkeys('G<C-V>') end) + vim.cmd.redraw() + ]] + end) + + it('can be nested', function() + exec_lua [[ + local other_win, cur_win = setup_windows() + vim._with({ win = other_win }, function() + assert(api.nvim_get_current_win() == other_win) + inner = vim._with({ win = cur_win }, function() + assert(api.nvim_get_current_win() == cur_win) + end) + assert(api.nvim_get_current_win() == other_win) + end) + assert(api.nvim_get_current_win() == cur_win) + ]] + end) + + it('updates ruler if cursor moved', function() + local screen = Screen.new(30, 5) + screen:set_default_attr_ids { + [1] = { reverse = true }, + [2] = { bold = true, reverse = true }, + } + screen:attach() + exec_lua [[ + vim.opt.ruler = true + local lines = {} + for i = 0, 499 do lines[#lines + 1] = tostring(i) end + api.nvim_buf_set_lines(0, 0, -1, true, lines) + api.nvim_win_set_cursor(0, { 20, 0 }) + vim.cmd 'split' + _G.win = api.nvim_get_current_win() + vim.cmd "wincmd w | redraw" + ]] + screen:expect [[ + 19 | + {1:[No Name] [+] 20,1 3%}| + ^19 | + {2:[No Name] [+] 20,1 3%}| + | + ]] + exec_lua [[ + vim._with({ win = win }, function() api.nvim_win_set_cursor(0, { 100, 0 }) end) + vim.cmd "redraw" + ]] + screen:expect [[ + 99 | + {1:[No Name] [+] 100,1 19%}| + ^19 | + {2:[No Name] [+] 20,1 3%}| + | + ]] + end) + + it('layout in current tabpage does not affect windows in others', function() + command('tab split') + local t2_move_win = api.nvim_get_current_win() + command('vsplit') + local t2_other_win = api.nvim_get_current_win() + command('tabprevious') + matches('E36: Not enough room$', pcall_err(command, 'execute "split|"->repeat(&lines)')) + command('vsplit') + + exec_lua('vim._with({ win = ... }, function() vim.cmd.wincmd "J" end)', t2_move_win) + eq({ 'col', { { 'leaf', t2_other_win }, { 'leaf', t2_move_win } } }, fn.winlayout(2)) + end) + end) + + describe('`wo` context', function() + before_each(function() + exec_lua [[ + _G.other_win, _G.cur_win = setup_windows() + + -- 'virtualedit' is global or local to window (global-local) and string + vim.wo[other_win].virtualedit = 'block' + vim.wo[cur_win].virtualedit = 'insert' + vim.go.virtualedit = 'none' + + -- 'winblend' is local to window and number + vim.wo[other_win].winblend = 10 + vim.wo[cur_win].winblend = 25 + vim.go.winblend = 50 + + _G.get_state = function() + return { + wo = { + ve_cur = vim.wo[cur_win].virtualedit, + ve_other = vim.wo[other_win].virtualedit, + winbl_cur = vim.wo[cur_win].winblend, + winbl_other = vim.wo[other_win].winblend, + }, + go = { + ve = vim.go.virtualedit, + winbl = vim.go.winblend, + }, + } + end + ]] + end) + + it('works', function() + local out = exec_lua [[ + local context = { wo = { virtualedit = 'all', winblend = 75 } } + + local before = get_state() + local inner = vim._with(context, function() + assert(api.nvim_get_current_win() == cur_win) + return get_state() + end) + + return { before = before, inner = inner, after = get_state() } + ]] + + eq({ + wo = { ve_cur = 'all', ve_other = 'block', winbl_cur = 75, winbl_other = 10 }, + go = { ve = 'none', winbl = 75 }, + }, out.inner) + eq(out.before, out.after) + end) + + it('sets options in `win` context', function() + local out = exec_lua [[ + local context = { win = other_win, wo = { virtualedit = 'all', winblend = 75 } } + + local before = get_state() + local inner = vim._with(context, function() + assert(api.nvim_get_current_win() == other_win) + return get_state() + end) + + return { before = before, inner = inner, after = get_state() } + ]] + + eq({ + wo = { ve_cur = 'insert', ve_other = 'all', winbl_cur = 25, winbl_other = 75 }, + go = { ve = 'none', winbl = 75 }, + }, out.inner) + eq(out.before, out.after) + end) + + it('restores only options from context', function() + local out = exec_lua [[ + local context = { wo = { winblend = 75 } } + + local inner = vim._with(context, function() + assert(api.nvim_get_current_win() == cur_win) + vim.wo[cur_win].virtualedit = 'onemore' + vim.wo[cur_win].winblend = 99 + return get_state() + end) + + return { inner = inner, after = get_state() } + ]] + + eq({ + wo = { ve_cur = 'onemore', ve_other = 'block', winbl_cur = 99, winbl_other = 10 }, + go = { ve = 'none', winbl = 99 }, + }, out.inner) + eq({ + wo = { ve_cur = 'onemore', ve_other = 'block', winbl_cur = 25, winbl_other = 10 }, + go = { ve = 'none', winbl = 50 }, + }, out.after) + end) + + it('does not trigger events', function() + exec_lua [[ + _G.test_events = { 'WinEnter', 'WinLeave', 'BufWinEnter', 'BufWinLeave' } + _G.test_context = { wo = { winblend = 75 } } + _G.test_trig_event = function() vim.cmd.new() end + ]] + assert_events_trigger() + end) + + it('can be nested', function() + local out = exec_lua [[ + local before, before_inner, after_inner = get_state(), nil, nil + vim._with({ wo = { winblend = 75, virtualedit = 'all' } }, function() + before_inner = get_state() + inner = vim._with({ wo = { winblend = 99 } }, get_state) + after_inner = get_state() + end) + return { + before = before, before_inner = before_inner, + inner = inner, + after_inner = after_inner, after = get_state(), + } + ]] + eq(99, out.inner.wo.winbl_cur) + eq('all', out.inner.wo.ve_cur) + eq(out.before_inner, out.after_inner) + eq(out.before, out.after) + end) + end) + + it('returns what callback returns', function() + local out_verify = exec_lua [[ + out = { vim._with({}, function() + return 'a', 2, nil, { 4 }, function() end + end) } + return { + out[1] == 'a', out[2] == 2, out[3] == nil, + vim.deep_equal(out[4], { 4 }), + type(out[5]) == 'function', + vim.tbl_count(out), + } + ]] + eq({ true, true, true, true, true, 4 }, out_verify) + end) + + it('can return values by reference', function() + local out = exec_lua [[ + local val = { 4, 10 } + local ref = vim._with({}, function() return val end) + ref[1] = 7 + return val + ]] + eq({ 7, 10 }, out) + end) + + it('can not work with conflicting `buf` and `win`', function() + local out = exec_lua [[ + local other_buf, cur_buf = setup_buffers() + local other_win, cur_win = setup_windows() + assert(api.nvim_win_get_buf(other_win) ~= other_buf) + local _, err = pcall(vim._with, { buf = other_buf, win = other_win }, function() end) + return err + ]] + matches('Can not set both `buf` and `win`', out) + end) + + it('works with several contexts at once', function() + local out = exec_lua [[ + local other_buf, cur_buf = setup_buffers() + vim.bo[other_buf].commentstring = '## %s' + api.nvim_buf_set_lines(other_buf, 0, -1, false, { 'aaa', 'bbb', 'ccc' }) + api.nvim_buf_set_mark(other_buf, 'm', 2, 2, {}) + + vim.go.commentstring = '// %s' + vim.go.langmap = 'xy,yx' + + local context = { + buf = other_buf, + bo = { commentstring = '-- %s' }, + go = { langmap = 'ab,ba' }, + lockmarks = true, + } + + local inner = vim._with(context, function() + api.nvim_buf_set_lines(0, 0, -1, false, { 'uuu', 'vvv', 'www' }) + return { + buf = api.nvim_get_current_buf(), + bo = { cms = vim.bo.commentstring }, + go = { cms = vim.go.commentstring, lmap = vim.go.langmap }, + mark = api.nvim_buf_get_mark(0, 'm') + } + end) + + local after = { + buf = api.nvim_get_current_buf(), + bo = { cms = vim.bo[other_buf].commentstring }, + go = { cms = vim.go.commentstring, lmap = vim.go.langmap }, + mark = api.nvim_buf_get_mark(other_buf, 'm') + } + + return { + context_buf = other_buf, cur_buf = cur_buf, + inner = inner, after = after + } + ]] + + eq({ + buf = out.context_buf, + bo = { cms = '-- %s' }, + go = { cms = '// %s', lmap = 'ab,ba' }, + mark = { 2, 2 }, + }, out.inner) + eq({ + buf = out.cur_buf, + bo = { cms = '## %s' }, + go = { cms = '// %s', lmap = 'xy,yx' }, + mark = { 2, 2 }, + }, out.after) + end) + + it('works with same option set in different contexts', function() + local out = exec_lua [[ + local get_state = function() + return { + bo = { cms = vim.bo.commentstring }, + wo = { ve = vim.wo.virtualedit }, + go = { cms = vim.go.commentstring, ve = vim.go.virtualedit }, + } + end + + vim.bo.commentstring = '// %s' + vim.go.commentstring = '$$ %s' + vim.wo.virtualedit = 'insert' + vim.go.virtualedit = 'none' + + local before = get_state() + local context_no_go = { + o = { commentstring = '-- %s', virtualedit = 'all' }, + bo = { commentstring = '!! %s' }, + wo = { virtualedit = 'onemore' }, + } + local inner_no_go = vim._with(context_no_go, get_state) + local middle = get_state() + local context_with_go = { + o = { commentstring = '-- %s', virtualedit = 'all' }, + bo = { commentstring = '!! %s' }, + wo = { virtualedit = 'onemore' }, + go = { commentstring = '@@ %s', virtualedit = 'block' }, + } + local inner_with_go = vim._with(context_with_go, get_state) + return { + before = before, + inner_no_go = inner_no_go, + middle = middle, + inner_with_go = inner_with_go, + after = get_state(), + } + ]] + + -- Should prefer explicit local scopes instead of `o` + eq({ + bo = { cms = '!! %s' }, + wo = { ve = 'onemore' }, + go = { cms = '-- %s', ve = 'all' }, + }, out.inner_no_go) + eq(out.before, out.middle) + + -- Should prefer explicit global scopes instead of `o` + eq({ + bo = { cms = '!! %s' }, + wo = { ve = 'onemore' }, + go = { cms = '@@ %s', ve = 'block' }, + }, out.inner_with_go) + eq(out.middle, out.after) + end) + + pending('can forward command modifiers to user command', function() + local out = exec_lua [[ + local test_flags = { + 'emsg_silent', + 'hide', + 'keepalt', + 'keepjumps', + 'keepmarks', + 'keeppatterns', + 'lockmarks', + 'noautocmd', + 'silent', + 'unsilent', + } + + local used_smods + local command = function(data) + used_smods = data.smods + end + api.nvim_create_user_command('DummyLog', command, {}) + + local res = {} + for _, flag in ipairs(test_flags) do + used_smods = nil + vim._with({ [flag] = true }, function() vim.cmd('DummyLog') end) + res[flag] = used_smods[flag] + end + return res + ]] + for k, v in pairs(out) do + eq({ k, true }, { k, v }) + end + end) + + it('handles error in callback', function() + -- Should still restore initial context + local out_buf = exec_lua [[ + local other_buf, cur_buf = setup_buffers() + vim.bo[other_buf].commentstring = '## %s' + + local context = { buf = other_buf, bo = { commentstring = '-- %s' } } + local ok, err = pcall(vim._with, context, function() error('Oops buf', 0) end) + + return { + ok, + err, + api.nvim_get_current_buf() == cur_buf, + vim.bo[other_buf].commentstring, + } + ]] + eq({ false, 'Oops buf', true, '## %s' }, out_buf) + + local out_win = exec_lua [[ + local other_win, cur_win = setup_windows() + vim.wo[other_win].winblend = 25 + + local context = { win = other_win, wo = { winblend = 50 } } + local ok, err = pcall(vim._with, context, function() error('Oops win', 0) end) + + return { + ok, + err, + api.nvim_get_current_win() == cur_win, + vim.wo[other_win].winblend, + } + ]] + eq({ false, 'Oops win', true, 25 }, out_win) + end) + + it('handles not supported option', function() + local out = exec_lua [[ + -- Should still restore initial state + vim.bo.commentstring = '## %s' + + local context = { o = { commentstring = '-- %s' }, bo = { winblend = 10 } } + local ok, err = pcall(vim._with, context, function() end) + + return { ok = ok, err = err, cms = vim.bo.commentstring } + ]] + eq(false, out.ok) + matches('window.*option.*winblend', out.err) + eq('## %s', out.cms) + end) + + it('validates arguments', function() + exec_lua [[ + _G.get_error = function(...) + local _, err = pcall(vim._with, ...) + return err or '' + end + ]] + local get_error = function(string_args) + return exec_lua('return get_error(' .. string_args .. ')') + end + + matches('context.*table', get_error("'a', function() end")) + matches('f.*function', get_error('{}, 1')) + + local assert_context = function(bad_context, expected_type) + local bad_field = vim.tbl_keys(bad_context)[1] + matches( + 'context%.' .. bad_field .. '.*' .. expected_type, + get_error(vim.inspect(bad_context) .. ', function() end') + ) + end + + assert_context({ bo = 1 }, 'table') + assert_context({ buf = 'a' }, 'number') + assert_context({ emsg_silent = 1 }, 'boolean') + assert_context({ env = 1 }, 'table') + assert_context({ go = 1 }, 'table') + assert_context({ hide = 1 }, 'boolean') + assert_context({ keepalt = 1 }, 'boolean') + assert_context({ keepjumps = 1 }, 'boolean') + assert_context({ keepmarks = 1 }, 'boolean') + assert_context({ keeppatterns = 1 }, 'boolean') + assert_context({ lockmarks = 1 }, 'boolean') + assert_context({ noautocmd = 1 }, 'boolean') + assert_context({ o = 1 }, 'table') + assert_context({ sandbox = 1 }, 'boolean') + assert_context({ silent = 1 }, 'boolean') + assert_context({ unsilent = 1 }, 'boolean') + assert_context({ win = 'a' }, 'number') + assert_context({ wo = 1 }, 'table') + + matches('Invalid buffer', get_error('{ buf = -1 }, function() end')) + matches('Invalid window', get_error('{ win = -1 }, function() end')) + end) +end) diff --git a/test/functional/lua/xdiff_spec.lua b/test/functional/lua/xdiff_spec.lua index d5589c1f13..269dbde10a 100644 --- a/test/functional/lua/xdiff_spec.lua +++ b/test/functional/lua/xdiff_spec.lua @@ -12,15 +12,11 @@ describe('xdiff bindings', function() end) describe('can diff text', function() - before_each(function() - exec_lua [[ - a1 = 'Hello\n' - b1 = 'Helli\n' - - a2 = 'Hello\nbye\nfoo\n' - b2 = 'Helli\nbye\nbar\nbaz\n' - ]] - end) + local a1 = 'Hello\n' + local b1 = 'Helli\n' + + local a2 = 'Hello\nbye\nfoo\n' + local b2 = 'Helli\nbye\nbar\nbaz\n' it('with no callback', function() eq( @@ -30,7 +26,9 @@ describe('xdiff bindings', function() '+Helli', '', }, '\n'), - exec_lua('return vim.diff(a1, b1)') + exec_lua(function() + return vim.diff(a1, b1) + end) ) eq( @@ -44,63 +42,81 @@ describe('xdiff bindings', function() '+baz', '', }, '\n'), - exec_lua('return vim.diff(a2, b2)') + exec_lua(function() + return vim.diff(a2, b2) + end) ) end) it('with callback', function() - exec_lua([[on_hunk = function(sa, ca, sb, cb) - exp[#exp+1] = {sa, ca, sb, cb} - end]]) - eq( { { 1, 1, 1, 1 } }, - exec_lua [[ - exp = {} - assert(vim.diff(a1, b1, {on_hunk = on_hunk}) == nil) + exec_lua(function() + local exp = {} --- @type table[] + assert(vim.diff(a1, b1, { + on_hunk = function(...) + exp[#exp + 1] = { ... } + end, + }) == nil) return exp - ]] + end) ) eq( { { 1, 1, 1, 1 }, { 3, 1, 3, 2 } }, - exec_lua [[ - exp = {} - assert(vim.diff(a2, b2, {on_hunk = on_hunk}) == nil) + exec_lua(function() + local exp = {} --- @type table[] + assert(vim.diff(a2, b2, { + on_hunk = function(...) + exp[#exp + 1] = { ... } + end, + }) == nil) return exp - ]] + end) ) -- gives higher precedence to on_hunk over result_type eq( { { 1, 1, 1, 1 }, { 3, 1, 3, 2 } }, - exec_lua [[ - exp = {} - assert(vim.diff(a2, b2, {on_hunk = on_hunk, result_type='indices'}) == nil) + exec_lua(function() + local exp = {} --- @type table[] + assert(vim.diff(a2, b2, { + on_hunk = function(...) + exp[#exp + 1] = { ... } + end, + result_type = 'indices', + }) == nil) return exp - ]] + end) ) end) it('with error callback', function() - exec_lua [[ - on_hunk = function(sa, ca, sb, cb) - error('ERROR1') - end - ]] - eq( - [[error running function on_hunk: [string "<nvim>"]:0: ERROR1]], - pcall_err(exec_lua, [[vim.diff(a1, b1, {on_hunk = on_hunk})]]) + [[.../xdiff_spec.lua:0: error running function on_hunk: .../xdiff_spec.lua:0: ERROR1]], + pcall_err(exec_lua, function() + vim.diff(a1, b1, { + on_hunk = function() + error('ERROR1') + end, + }) + end) ) end) it('with hunk_lines', function() - eq({ { 1, 1, 1, 1 } }, exec_lua([[return vim.diff(a1, b1, {result_type = 'indices'})]])) + eq( + { { 1, 1, 1, 1 } }, + exec_lua(function() + return vim.diff(a1, b1, { result_type = 'indices' }) + end) + ) eq( { { 1, 1, 1, 1 }, { 3, 1, 3, 2 } }, - exec_lua([[return vim.diff(a2, b2, {result_type = 'indices'})]]) + exec_lua(function() + return vim.diff(a2, b2, { result_type = 'indices' }) + end) ) end) @@ -143,16 +159,11 @@ describe('xdiff bindings', function() '+}', '', }, '\n'), - exec_lua( - [[ - local args = {...} - return vim.diff(args[1], args[2], { - algorithm = 'patience' + exec_lua(function() + return vim.diff(a, b, { + algorithm = 'patience', }) - ]], - a, - b - ) + end) ) end) end) @@ -174,4 +185,13 @@ describe('xdiff bindings', function() pcall_err(exec_lua, [[vim.diff('a', 'b', { on_hunk = true })]]) ) end) + + it('can handle strings with embedded NUL characters (GitHub #30305)', function() + eq( + { { 0, 0, 1, 1 }, { 1, 0, 3, 2 } }, + exec_lua(function() + return vim.diff('\n', '\0\n\n\nb', { linematch = true, result_type = 'indices' }) + end) + ) + end) end) diff --git a/test/functional/options/autochdir_spec.lua b/test/functional/options/autochdir_spec.lua index c490ab67a9..a409262d84 100644 --- a/test/functional/options/autochdir_spec.lua +++ b/test/functional/options/autochdir_spec.lua @@ -22,7 +22,7 @@ describe("'autochdir'", function() end) it('is not overwritten by getwinvar() call #17609', function() - local curdir = vim.uv.cwd():gsub('\\', '/') + local curdir = t.fix_slashes(vim.uv.cwd()) local dir_a = curdir .. '/Xtest-functional-options-autochdir.dir_a' local dir_b = curdir .. '/Xtest-functional-options-autochdir.dir_b' mkdir(dir_a) diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua index f61139d92d..e3d15fa30f 100644 --- a/test/functional/options/defaults_spec.lua +++ b/test/functional/options/defaults_spec.lua @@ -1,3 +1,9 @@ +-- +-- Tests for default options and environment decisions. +-- +-- See editor/defaults_spec.lua for default autocmds, mappings, commands, and menus. +-- + local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') @@ -17,7 +23,6 @@ local insert = n.insert local neq = t.neq local mkdir = t.mkdir local rmdir = n.rmdir -local alter_slashes = n.alter_slashes local tbl_contains = vim.tbl_contains local expect_exit = n.expect_exit local check_close = n.check_close @@ -247,6 +252,7 @@ describe('startup defaults', function() } }) eq('Xtest-logpath', eval('$NVIM_LOG_FILE')) end) + it('defaults to stdpath("log")/log if empty', function() eq(true, mkdir(xdgdir) and mkdir(xdgstatedir)) clear({ @@ -255,8 +261,9 @@ describe('startup defaults', function() NVIM_LOG_FILE = '', -- Empty is invalid. }, }) - eq(xdgstatedir .. '/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) + eq(xdgstatedir .. '/log', t.fix_slashes(eval('$NVIM_LOG_FILE'))) end) + it('defaults to stdpath("log")/log if invalid', function() eq(true, mkdir(xdgdir) and mkdir(xdgstatedir)) clear({ @@ -265,7 +272,9 @@ describe('startup defaults', function() NVIM_LOG_FILE = '.', -- Any directory is invalid. }, }) - eq(xdgstatedir .. '/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) + eq(xdgstatedir .. '/log', t.fix_slashes(eval('$NVIM_LOG_FILE'))) + -- Avoid "failed to open $NVIM_LOG_FILE" noise in test output. + expect_exit(command, 'qall!') end) end) end) @@ -339,9 +348,11 @@ describe('XDG defaults', function() local state_dir = is_os('win') and 'nvim-data' or 'nvim' local root_path = is_os('win') and 'C:' or '' - describe('with too long XDG variables', function() + describe('with too long XDG vars', function() before_each(function() clear({ + -- Ensure valid --listen address despite broken XDG vars (else Nvim won't start). + args = { '--listen', is_os('win') and '' or t.tmpname(false) }, args_rm = { 'runtimepath' }, env = { NVIM_LOG_FILE = testlog, @@ -361,6 +372,9 @@ describe('XDG defaults', function() it('are correctly set', function() if not is_os('win') then + -- Broken XDG vars cause serverstart() to fail (except on Windows, where servernames are not + -- informed by $XDG_STATE_HOME). + t.matches('Failed to start server: no such file or directory', t.pcall_err(fn.serverstart)) assert_log('Failed to start server: no such file or directory: /X/X/X', testlog, 10) end @@ -368,69 +382,69 @@ describe('XDG defaults', function() eq( ( - ( + t.fix_slashes( root_path - .. ('/x'):rep(4096) - .. '/nvim' - .. ',' - .. root_path - .. ('/a'):rep(2048) - .. '/nvim' - .. ',' - .. root_path - .. ('/b'):rep(2048) - .. '/nvim' - .. (',' .. root_path .. '/c/nvim') - .. ',' - .. root_path - .. ('/X'):rep(4096) - .. '/' - .. data_dir - .. '/site' - .. ',' - .. root_path - .. ('/A'):rep(2048) - .. '/nvim/site' - .. ',' - .. root_path - .. ('/B'):rep(2048) - .. '/nvim/site' - .. (',' .. root_path .. '/C/nvim/site') - .. ',' - .. vimruntime - .. ',' - .. libdir - .. (',' .. root_path .. '/C/nvim/site/after') - .. ',' - .. root_path - .. ('/B'):rep(2048) - .. '/nvim/site/after' - .. ',' - .. root_path - .. ('/A'):rep(2048) - .. '/nvim/site/after' - .. ',' - .. root_path - .. ('/X'):rep(4096) - .. '/' - .. data_dir - .. '/site/after' - .. (',' .. root_path .. '/c/nvim/after') - .. ',' - .. root_path - .. ('/b'):rep(2048) - .. '/nvim/after' - .. ',' - .. root_path - .. ('/a'):rep(2048) - .. '/nvim/after' - .. ',' - .. root_path - .. ('/x'):rep(4096) - .. '/nvim/after' - ):gsub('\\', '/') + .. ('/x'):rep(4096) + .. '/nvim' + .. ',' + .. root_path + .. ('/a'):rep(2048) + .. '/nvim' + .. ',' + .. root_path + .. ('/b'):rep(2048) + .. '/nvim' + .. (',' .. root_path .. '/c/nvim') + .. ',' + .. root_path + .. ('/X'):rep(4096) + .. '/' + .. data_dir + .. '/site' + .. ',' + .. root_path + .. ('/A'):rep(2048) + .. '/nvim/site' + .. ',' + .. root_path + .. ('/B'):rep(2048) + .. '/nvim/site' + .. (',' .. root_path .. '/C/nvim/site') + .. ',' + .. vimruntime + .. ',' + .. libdir + .. (',' .. root_path .. '/C/nvim/site/after') + .. ',' + .. root_path + .. ('/B'):rep(2048) + .. '/nvim/site/after' + .. ',' + .. root_path + .. ('/A'):rep(2048) + .. '/nvim/site/after' + .. ',' + .. root_path + .. ('/X'):rep(4096) + .. '/' + .. data_dir + .. '/site/after' + .. (',' .. root_path .. '/c/nvim/after') + .. ',' + .. root_path + .. ('/b'):rep(2048) + .. '/nvim/after' + .. ',' + .. root_path + .. ('/a'):rep(2048) + .. '/nvim/after' + .. ',' + .. root_path + .. ('/x'):rep(4096) + .. '/nvim/after' + ) ), - (api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('runtimepath', {})) ) command('set runtimepath&') command('set backupdir&') @@ -439,92 +453,94 @@ describe('XDG defaults', function() command('set viewdir&') eq( ( - ( + t.fix_slashes( root_path - .. ('/x'):rep(4096) - .. '/nvim' - .. ',' - .. root_path - .. ('/a'):rep(2048) - .. '/nvim' - .. ',' - .. root_path - .. ('/b'):rep(2048) - .. '/nvim' - .. (',' .. root_path .. '/c/nvim') - .. ',' - .. root_path - .. ('/X'):rep(4096) - .. '/' - .. data_dir - .. '/site' - .. ',' - .. root_path - .. ('/A'):rep(2048) - .. '/nvim/site' - .. ',' - .. root_path - .. ('/B'):rep(2048) - .. '/nvim/site' - .. (',' .. root_path .. '/C/nvim/site') - .. ',' - .. vimruntime - .. ',' - .. libdir - .. (',' .. root_path .. '/C/nvim/site/after') - .. ',' - .. root_path - .. ('/B'):rep(2048) - .. '/nvim/site/after' - .. ',' - .. root_path - .. ('/A'):rep(2048) - .. '/nvim/site/after' - .. ',' - .. root_path - .. ('/X'):rep(4096) - .. '/' - .. data_dir - .. '/site/after' - .. (',' .. root_path .. '/c/nvim/after') - .. ',' - .. root_path - .. ('/b'):rep(2048) - .. '/nvim/after' - .. ',' - .. root_path - .. ('/a'):rep(2048) - .. '/nvim/after' - .. ',' - .. root_path - .. ('/x'):rep(4096) - .. '/nvim/after' - ):gsub('\\', '/') + .. ('/x'):rep(4096) + .. '/nvim' + .. ',' + .. root_path + .. ('/a'):rep(2048) + .. '/nvim' + .. ',' + .. root_path + .. ('/b'):rep(2048) + .. '/nvim' + .. (',' .. root_path .. '/c/nvim') + .. ',' + .. root_path + .. ('/X'):rep(4096) + .. '/' + .. data_dir + .. '/site' + .. ',' + .. root_path + .. ('/A'):rep(2048) + .. '/nvim/site' + .. ',' + .. root_path + .. ('/B'):rep(2048) + .. '/nvim/site' + .. (',' .. root_path .. '/C/nvim/site') + .. ',' + .. vimruntime + .. ',' + .. libdir + .. (',' .. root_path .. '/C/nvim/site/after') + .. ',' + .. root_path + .. ('/B'):rep(2048) + .. '/nvim/site/after' + .. ',' + .. root_path + .. ('/A'):rep(2048) + .. '/nvim/site/after' + .. ',' + .. root_path + .. ('/X'):rep(4096) + .. '/' + .. data_dir + .. '/site/after' + .. (',' .. root_path .. '/c/nvim/after') + .. ',' + .. root_path + .. ('/b'):rep(2048) + .. '/nvim/after' + .. ',' + .. root_path + .. ('/a'):rep(2048) + .. '/nvim/after' + .. ',' + .. root_path + .. ('/x'):rep(4096) + .. '/nvim/after' + ) ), - (api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('runtimepath', {})) ) eq( '.,' .. root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/backup//', - (api.nvim_get_option_value('backupdir', {}):gsub('\\', '/')) + t.fix_slashes(api.nvim_get_option_value('backupdir', {})) ) eq( root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/swap//', - (api.nvim_get_option_value('directory', {})):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('directory', {})) ) eq( root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/undo//', - (api.nvim_get_option_value('undodir', {})):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('undodir', {})) ) eq( root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/view//', - (api.nvim_get_option_value('viewdir', {})):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('viewdir', {})) ) end) end) - describe('with XDG variables that can be expanded', function() + describe('with expandable XDG vars', function() before_each(function() clear({ + -- Ensure valid --listen address despite broken XDG vars (else Nvim won't start). + args = { '--listen', is_os('win') and '' or t.tmpname(false) }, args_rm = { 'runtimepath' }, env = { NVIM_LOG_FILE = testlog, @@ -544,6 +560,9 @@ describe('XDG defaults', function() it('are not expanded', function() if not is_os('win') then + -- Broken XDG vars cause serverstart() to fail (except on Windows, where servernames are not + -- informed by $XDG_STATE_HOME). + t.matches('Failed to start server: no such file or directory', t.pcall_err(fn.serverstart)) assert_log( 'Failed to start server: no such file or directory: %$XDG_RUNTIME_DIR%/', testlog, @@ -554,26 +573,26 @@ describe('XDG defaults', function() local vimruntime, libdir = vimruntime_and_libdir() eq( ( - ( + t.fix_slashes( '$XDG_DATA_HOME/nvim' - .. ',$XDG_DATA_DIRS/nvim' - .. ',$XDG_CONFIG_HOME/' - .. data_dir - .. '/site' - .. ',$XDG_CONFIG_DIRS/nvim/site' - .. ',' - .. vimruntime - .. ',' - .. libdir - .. ',$XDG_CONFIG_DIRS/nvim/site/after' - .. ',$XDG_CONFIG_HOME/' - .. data_dir - .. '/site/after' - .. ',$XDG_DATA_DIRS/nvim/after' - .. ',$XDG_DATA_HOME/nvim/after' - ):gsub('\\', '/') + .. ',$XDG_DATA_DIRS/nvim' + .. ',$XDG_CONFIG_HOME/' + .. data_dir + .. '/site' + .. ',$XDG_CONFIG_DIRS/nvim/site' + .. ',' + .. vimruntime + .. ',' + .. libdir + .. ',$XDG_CONFIG_DIRS/nvim/site/after' + .. ',$XDG_CONFIG_HOME/' + .. data_dir + .. '/site/after' + .. ',$XDG_DATA_DIRS/nvim/after' + .. ',$XDG_DATA_HOME/nvim/after' + ) ), - (api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('runtimepath', {})) ) command('set runtimepath&') command('set backupdir&') @@ -582,80 +601,80 @@ describe('XDG defaults', function() command('set viewdir&') eq( ( - ( + t.fix_slashes( '$XDG_DATA_HOME/nvim' - .. ',$XDG_DATA_DIRS/nvim' - .. ',$XDG_CONFIG_HOME/' - .. data_dir - .. '/site' - .. ',$XDG_CONFIG_DIRS/nvim/site' - .. ',' - .. vimruntime - .. ',' - .. libdir - .. ',$XDG_CONFIG_DIRS/nvim/site/after' - .. ',$XDG_CONFIG_HOME/' - .. data_dir - .. '/site/after' - .. ',$XDG_DATA_DIRS/nvim/after' - .. ',$XDG_DATA_HOME/nvim/after' - ):gsub('\\', '/') + .. ',$XDG_DATA_DIRS/nvim' + .. ',$XDG_CONFIG_HOME/' + .. data_dir + .. '/site' + .. ',$XDG_CONFIG_DIRS/nvim/site' + .. ',' + .. vimruntime + .. ',' + .. libdir + .. ',$XDG_CONFIG_DIRS/nvim/site/after' + .. ',$XDG_CONFIG_HOME/' + .. data_dir + .. '/site/after' + .. ',$XDG_DATA_DIRS/nvim/after' + .. ',$XDG_DATA_HOME/nvim/after' + ) ), - (api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('runtimepath', {})) ) eq( ('.,$XDG_CONFIG_HOME/' .. state_dir .. '/backup//'), - api.nvim_get_option_value('backupdir', {}):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('backupdir', {})) ) eq( ('$XDG_CONFIG_HOME/' .. state_dir .. '/swap//'), - api.nvim_get_option_value('directory', {}):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('directory', {})) ) eq( ('$XDG_CONFIG_HOME/' .. state_dir .. '/undo//'), - api.nvim_get_option_value('undodir', {}):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('undodir', {})) ) eq( ('$XDG_CONFIG_HOME/' .. state_dir .. '/view//'), - api.nvim_get_option_value('viewdir', {}):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('viewdir', {})) ) command('set all&') eq( - ( + t.fix_slashes( '$XDG_DATA_HOME/nvim' - .. ',$XDG_DATA_DIRS/nvim' - .. ',$XDG_CONFIG_HOME/' - .. data_dir - .. '/site' - .. ',$XDG_CONFIG_DIRS/nvim/site' - .. ',' - .. vimruntime - .. ',' - .. libdir - .. ',$XDG_CONFIG_DIRS/nvim/site/after' - .. ',$XDG_CONFIG_HOME/' - .. data_dir - .. '/site/after' - .. ',$XDG_DATA_DIRS/nvim/after' - .. ',$XDG_DATA_HOME/nvim/after' - ):gsub('\\', '/'), - (api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/') + .. ',$XDG_DATA_DIRS/nvim' + .. ',$XDG_CONFIG_HOME/' + .. data_dir + .. '/site' + .. ',$XDG_CONFIG_DIRS/nvim/site' + .. ',' + .. vimruntime + .. ',' + .. libdir + .. ',$XDG_CONFIG_DIRS/nvim/site/after' + .. ',$XDG_CONFIG_HOME/' + .. data_dir + .. '/site/after' + .. ',$XDG_DATA_DIRS/nvim/after' + .. ',$XDG_DATA_HOME/nvim/after' + ), + t.fix_slashes(api.nvim_get_option_value('runtimepath', {})) ) eq( ('.,$XDG_CONFIG_HOME/' .. state_dir .. '/backup//'), - api.nvim_get_option_value('backupdir', {}):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('backupdir', {})) ) eq( ('$XDG_CONFIG_HOME/' .. state_dir .. '/swap//'), - api.nvim_get_option_value('directory', {}):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('directory', {})) ) eq( ('$XDG_CONFIG_HOME/' .. state_dir .. '/undo//'), - api.nvim_get_option_value('undodir', {}):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('undodir', {})) ) eq( ('$XDG_CONFIG_HOME/' .. state_dir .. '/view//'), - api.nvim_get_option_value('viewdir', {}):gsub('\\', '/') + t.fix_slashes(api.nvim_get_option_value('viewdir', {})) ) eq(nil, (fn.tempname()):match('XDG_RUNTIME_DIR')) end) @@ -895,7 +914,7 @@ describe('stdpath()', function() assert_alive() -- Check for crash. #8393 end) - it('reacts to $NVIM_APPNAME', function() + it('$NVIM_APPNAME', function() local appname = 'NVIM_APPNAME_TEST' .. ('_'):rep(106) clear({ env = { NVIM_APPNAME = appname, NVIM_LOG_FILE = testlog } }) eq(appname, fn.fnamemodify(fn.stdpath('config'), ':t')) @@ -916,10 +935,10 @@ describe('stdpath()', function() local function test_appname(testAppname, expected_exitcode) local lua_code = string.format( [[ - local child = vim.fn.jobstart({ vim.v.progpath, '--clean', '--headless', '+qall!' }, { env = { NVIM_APPNAME = %q } }) + local child = vim.fn.jobstart({ vim.v.progpath, '--clean', '--headless', '--listen', 'x', '+qall!' }, { env = { NVIM_APPNAME = %q } }) return vim.fn.jobwait({ child }, %d)[1] ]], - alter_slashes(testAppname), + testAppname, 3000 ) eq(expected_exitcode, exec_lua(lua_code)) @@ -935,9 +954,25 @@ describe('stdpath()', function() -- Valid appnames: test_appname('a/b', 0) test_appname('a/b\\c', 0) - if not is_os('win') then - assert_log('Failed to start server: no such file or directory:', testlog) - end + end) + + it('$NVIM_APPNAME relative path', function() + local tmpdir = t.tmpname(false) + t.mkdir(tmpdir) + + clear({ + args_rm = { '--listen' }, + env = { + NVIM_APPNAME = 'relative/appname', + NVIM_LOG_FILE = testlog, + TMPDIR = tmpdir, + }, + }) + + t.matches(vim.pesc(tmpdir), t.fix_slashes(fn.tempname())) + t.assert_nolog('tempdir', testlog, 100) + t.assert_nolog('TMPDIR', testlog, 100) + t.matches([=[[/\\]relative%-appname.[^/\\]+]=], api.nvim_get_vvar('servername')) end) describe('returns a String', function() @@ -945,19 +980,19 @@ describe('stdpath()', function() it('knows XDG_CONFIG_HOME', function() clear({ env = { - XDG_CONFIG_HOME = alter_slashes('/home/docwhat/.config'), + XDG_CONFIG_HOME = '/home/docwhat/.config', }, }) - eq(alter_slashes('/home/docwhat/.config/nvim'), fn.stdpath('config')) + eq('/home/docwhat/.config/nvim', t.fix_slashes(fn.stdpath('config'))) end) it('handles changes during runtime', function() clear({ env = { - XDG_CONFIG_HOME = alter_slashes('/home/original'), + XDG_CONFIG_HOME = '/home/original', } }) - eq(alter_slashes('/home/original/nvim'), fn.stdpath('config')) - command("let $XDG_CONFIG_HOME='" .. alter_slashes('/home/new') .. "'") - eq(alter_slashes('/home/new/nvim'), fn.stdpath('config')) + eq('/home/original/nvim', t.fix_slashes(fn.stdpath('config'))) + command("let $XDG_CONFIG_HOME='/home/new'") + eq('/home/new/nvim', t.fix_slashes(fn.stdpath('config'))) end) it("doesn't expand $VARIABLES", function() @@ -967,32 +1002,32 @@ describe('stdpath()', function() VARIABLES = 'this-should-not-happen', }, }) - eq(alter_slashes('$VARIABLES/nvim'), fn.stdpath('config')) + eq('$VARIABLES/nvim', t.fix_slashes(fn.stdpath('config'))) end) it("doesn't expand ~/", function() clear({ env = { - XDG_CONFIG_HOME = alter_slashes('~/frobnitz'), + XDG_CONFIG_HOME = '~/frobnitz', } }) - eq(alter_slashes('~/frobnitz/nvim'), fn.stdpath('config')) + eq('~/frobnitz/nvim', t.fix_slashes(fn.stdpath('config'))) end) end) describe('with "data"', function() it('knows XDG_DATA_HOME', function() clear({ env = { - XDG_DATA_HOME = alter_slashes('/home/docwhat/.local'), + XDG_DATA_HOME = '/home/docwhat/.local', } }) - eq(alter_slashes('/home/docwhat/.local/' .. datadir), fn.stdpath('data')) + eq('/home/docwhat/.local/' .. datadir, t.fix_slashes(fn.stdpath('data'))) end) it('handles changes during runtime', function() clear({ env = { - XDG_DATA_HOME = alter_slashes('/home/original'), + XDG_DATA_HOME = '/home/original', } }) - eq(alter_slashes('/home/original/' .. datadir), fn.stdpath('data')) - command("let $XDG_DATA_HOME='" .. alter_slashes('/home/new') .. "'") - eq(alter_slashes('/home/new/' .. datadir), fn.stdpath('data')) + eq('/home/original/' .. datadir, t.fix_slashes(fn.stdpath('data'))) + command("let $XDG_DATA_HOME='/home/new'") + eq('/home/new/' .. datadir, t.fix_slashes(fn.stdpath('data'))) end) it("doesn't expand $VARIABLES", function() @@ -1002,14 +1037,14 @@ describe('stdpath()', function() VARIABLES = 'this-should-not-happen', }, }) - eq(alter_slashes('$VARIABLES/' .. datadir), fn.stdpath('data')) + eq('$VARIABLES/' .. datadir, t.fix_slashes(fn.stdpath('data'))) end) it("doesn't expand ~/", function() clear({ env = { - XDG_DATA_HOME = alter_slashes('~/frobnitz'), + XDG_DATA_HOME = '~/frobnitz', } }) - eq(alter_slashes('~/frobnitz/' .. datadir), fn.stdpath('data')) + eq('~/frobnitz/' .. datadir, t.fix_slashes(fn.stdpath('data'))) end) end) @@ -1017,19 +1052,19 @@ describe('stdpath()', function() it('knows XDG_STATE_HOME', function() clear({ env = { - XDG_STATE_HOME = alter_slashes('/home/docwhat/.local'), + XDG_STATE_HOME = '/home/docwhat/.local', }, }) - eq(alter_slashes('/home/docwhat/.local/' .. statedir), fn.stdpath('state')) + eq('/home/docwhat/.local/' .. statedir, t.fix_slashes(fn.stdpath('state'))) end) it('handles changes during runtime', function() clear({ env = { - XDG_STATE_HOME = alter_slashes('/home/original'), + XDG_STATE_HOME = '/home/original', } }) - eq(alter_slashes('/home/original/' .. statedir), fn.stdpath('state')) - command("let $XDG_STATE_HOME='" .. alter_slashes('/home/new') .. "'") - eq(alter_slashes('/home/new/' .. statedir), fn.stdpath('state')) + eq('/home/original/' .. statedir, t.fix_slashes(fn.stdpath('state'))) + command("let $XDG_STATE_HOME='" .. '/home/new' .. "'") + eq('/home/new/' .. statedir, t.fix_slashes(fn.stdpath('state'))) end) it("doesn't expand $VARIABLES", function() @@ -1039,14 +1074,14 @@ describe('stdpath()', function() VARIABLES = 'this-should-not-happen', }, }) - eq(alter_slashes('$VARIABLES/' .. statedir), fn.stdpath('state')) + eq('$VARIABLES/' .. statedir, t.fix_slashes(fn.stdpath('state'))) end) it("doesn't expand ~/", function() clear({ env = { - XDG_STATE_HOME = alter_slashes('~/frobnitz'), + XDG_STATE_HOME = '~/frobnitz', } }) - eq(alter_slashes('~/frobnitz/' .. statedir), fn.stdpath('state')) + eq('~/frobnitz/' .. statedir, t.fix_slashes(fn.stdpath('state'))) end) end) @@ -1054,19 +1089,19 @@ describe('stdpath()', function() it('knows XDG_CACHE_HOME', function() clear({ env = { - XDG_CACHE_HOME = alter_slashes('/home/docwhat/.cache'), + XDG_CACHE_HOME = '/home/docwhat/.cache', }, }) - eq(alter_slashes('/home/docwhat/.cache/nvim'), fn.stdpath('cache')) + eq('/home/docwhat/.cache/nvim', t.fix_slashes(fn.stdpath('cache'))) end) it('handles changes during runtime', function() clear({ env = { - XDG_CACHE_HOME = alter_slashes('/home/original'), + XDG_CACHE_HOME = '/home/original', } }) - eq(alter_slashes('/home/original/nvim'), fn.stdpath('cache')) - command("let $XDG_CACHE_HOME='" .. alter_slashes('/home/new') .. "'") - eq(alter_slashes('/home/new/nvim'), fn.stdpath('cache')) + eq('/home/original/nvim', t.fix_slashes(fn.stdpath('cache'))) + command("let $XDG_CACHE_HOME='" .. '/home/new' .. "'") + eq('/home/new/nvim', t.fix_slashes(fn.stdpath('cache'))) end) it("doesn't expand $VARIABLES", function() @@ -1076,14 +1111,14 @@ describe('stdpath()', function() VARIABLES = 'this-should-not-happen', }, }) - eq(alter_slashes('$VARIABLES/nvim'), fn.stdpath('cache')) + eq('$VARIABLES/nvim', t.fix_slashes(fn.stdpath('cache'))) end) it("doesn't expand ~/", function() clear({ env = { - XDG_CACHE_HOME = alter_slashes('~/frobnitz'), + XDG_CACHE_HOME = '~/frobnitz', } }) - eq(alter_slashes('~/frobnitz/nvim'), fn.stdpath('cache')) + eq('~/frobnitz/nvim', t.fix_slashes(fn.stdpath('cache'))) end) end) end) @@ -1097,6 +1132,7 @@ describe('stdpath()', function() HOMEDRIVE = 'C:', HOMEPATH = '\\Users\\docwhat', LOCALAPPDATA = 'C:\\Users\\docwhat\\AppData\\Local', + NVIM_LOG_FILE = testlog, TEMP = 'C:\\Users\\docwhat\\AppData\\Local\\Temp', TMPDIR = 'C:\\Users\\docwhat\\AppData\\Local\\Temp', TMP = 'C:\\Users\\docwhat\\AppData\\Local\\Temp', @@ -1107,6 +1143,7 @@ describe('stdpath()', function() HOMEDRIVE = 'HOMEDRIVE-should-be-ignored', HOMEPATH = 'HOMEPATH-should-be-ignored', LOCALAPPDATA = 'LOCALAPPDATA-should-be-ignored', + NVIM_LOG_FILE = testlog, TEMP = 'TEMP-should-be-ignored', TMPDIR = 'TMPDIR-should-be-ignored', TMP = 'TMP-should-be-ignored', @@ -1130,12 +1167,18 @@ describe('stdpath()', function() describe(msg, function() it('set via system', function() set_paths_via_system(env_var_name, paths) - eq(expected_paths, fn.stdpath(stdpath_arg)) + eq(expected_paths, t.fix_slashes(fn.stdpath(stdpath_arg))) + if not is_os('win') then + assert_log('$TMPDIR tempdir not a directory.*TMPDIR%-should%-be%-ignored', testlog, 100) + end end) it('set at runtime', function() set_paths_at_runtime(env_var_name, paths) - eq(expected_paths, fn.stdpath(stdpath_arg)) + eq(expected_paths, t.fix_slashes(fn.stdpath(stdpath_arg))) + if not is_os('win') then + assert_log('$TMPDIR tempdir not a directory.*TMPDIR%-should%-be%-ignored', testlog, 100) + end end) end) end @@ -1146,10 +1189,10 @@ describe('stdpath()', function() 'config_dirs', 'XDG_CONFIG_DIRS', { - alter_slashes('/home/docwhat/.config'), + t.fix_slashes('/home/docwhat/.config'), }, { - alter_slashes('/home/docwhat/.config/nvim'), + t.fix_slashes('/home/docwhat/.config/nvim'), } ) @@ -1158,12 +1201,12 @@ describe('stdpath()', function() 'config_dirs', 'XDG_CONFIG_DIRS', { - alter_slashes('/home/docwhat/.config'), - alter_slashes('/etc/config'), + t.fix_slashes('/home/docwhat/.config'), + t.fix_slashes('/etc/config'), }, { - alter_slashes('/home/docwhat/.config/nvim'), - alter_slashes('/etc/config/nvim'), + t.fix_slashes('/home/docwhat/.config/nvim'), + t.fix_slashes('/etc/config/nvim'), } ) @@ -1173,25 +1216,25 @@ describe('stdpath()', function() 'XDG_CONFIG_DIRS', { '$HOME', '$TMP' }, { - alter_slashes('$HOME/nvim'), - alter_slashes('$TMP/nvim'), + t.fix_slashes('$HOME/nvim'), + t.fix_slashes('$TMP/nvim'), } ) behaves_like_dir_list_env("doesn't expand ~/", 'config_dirs', 'XDG_CONFIG_DIRS', { - alter_slashes('~/.oldconfig'), - alter_slashes('~/.olderconfig'), + t.fix_slashes('~/.oldconfig'), + t.fix_slashes('~/.olderconfig'), }, { - alter_slashes('~/.oldconfig/nvim'), - alter_slashes('~/.olderconfig/nvim'), + t.fix_slashes('~/.oldconfig/nvim'), + t.fix_slashes('~/.olderconfig/nvim'), }) end) describe('with "data_dirs"', function() behaves_like_dir_list_env('knows XDG_DATA_DIRS with one path', 'data_dirs', 'XDG_DATA_DIRS', { - alter_slashes('/home/docwhat/.data'), + t.fix_slashes('/home/docwhat/.data'), }, { - alter_slashes('/home/docwhat/.data/nvim'), + t.fix_slashes('/home/docwhat/.data/nvim'), }) behaves_like_dir_list_env( @@ -1199,12 +1242,12 @@ describe('stdpath()', function() 'data_dirs', 'XDG_DATA_DIRS', { - alter_slashes('/home/docwhat/.data'), - alter_slashes('/etc/local'), + t.fix_slashes('/home/docwhat/.data'), + t.fix_slashes('/etc/local'), }, { - alter_slashes('/home/docwhat/.data/nvim'), - alter_slashes('/etc/local/nvim'), + t.fix_slashes('/home/docwhat/.data/nvim'), + t.fix_slashes('/etc/local/nvim'), } ) @@ -1214,17 +1257,17 @@ describe('stdpath()', function() 'XDG_DATA_DIRS', { '$HOME', '$TMP' }, { - alter_slashes('$HOME/nvim'), - alter_slashes('$TMP/nvim'), + t.fix_slashes('$HOME/nvim'), + t.fix_slashes('$TMP/nvim'), } ) behaves_like_dir_list_env("doesn't expand ~/", 'data_dirs', 'XDG_DATA_DIRS', { - alter_slashes('~/.oldconfig'), - alter_slashes('~/.olderconfig'), + t.fix_slashes('~/.oldconfig'), + t.fix_slashes('~/.olderconfig'), }, { - alter_slashes('~/.oldconfig/nvim'), - alter_slashes('~/.olderconfig/nvim'), + t.fix_slashes('~/.oldconfig/nvim'), + t.fix_slashes('~/.olderconfig/nvim'), }) end) end) @@ -1244,23 +1287,3 @@ describe('stdpath()', function() end) end) end) - -describe('autocommands', function() - it('closes terminal with default shell on success', function() - clear() - api.nvim_set_option_value('shell', n.testprg('shell-test'), {}) - command('set shellcmdflag=EXIT shellredir= shellpipe= shellquote= shellxquote=') - - -- Should not block other events - command('let g:n=0') - command('au BufEnter * let g:n = g:n + 1') - - command('terminal') - eq(1, eval('get(g:, "n", 0)')) - - t.retry(nil, 1000, function() - neq('terminal', api.nvim_get_option_value('buftype', { buf = 0 })) - eq(2, eval('get(g:, "n", 0)')) - end) - end) -end) diff --git a/test/functional/plugin/editorconfig_spec.lua b/test/functional/plugin/editorconfig_spec.lua index 839a723405..5f69b8938a 100644 --- a/test/functional/plugin/editorconfig_spec.lua +++ b/test/functional/plugin/editorconfig_spec.lua @@ -7,7 +7,6 @@ local eq = t.eq local pathsep = n.get_pathsep() local fn = n.fn local api = n.api -local exec_lua = n.exec_lua local testdir = 'Xtest-editorconfig' @@ -16,8 +15,16 @@ local testdir = 'Xtest-editorconfig' local function test_case(name, expected) local filename = testdir .. pathsep .. name command('edit ' .. filename) + for opt, val in pairs(expected) do - eq(val, api.nvim_get_option_value(opt, { buf = 0 }), name) + local opt_info = api.nvim_get_option_info2(opt, {}) + if opt_info.scope == 'win' then + eq(val, api.nvim_get_option_value(opt, { win = 0 }), name) + elseif opt_info.scope == 'buf' then + eq(val, api.nvim_get_option_value(opt, { buf = 0 }), name) + else + eq(val, api.nvim_get_option_value(opt, {}), name) + end end end @@ -93,6 +100,12 @@ setup(function() [max_line_length.txt] max_line_length = 42 + + [short_spelling_language.txt] + spelling_language = de + + [long_spelling_language.txt] + spelling_language = en-NZ ]] ) end) @@ -213,13 +226,18 @@ But not this one end) it('does not operate on invalid buffers', function() - local ok, err = unpack(exec_lua([[ + local ok, err = unpack(n.exec_lua(function() vim.cmd.edit('test.txt') local bufnr = vim.api.nvim_get_current_buf() vim.cmd.bwipeout(bufnr) - return {pcall(require('editorconfig').config, bufnr)} - ]])) + return { pcall(require('editorconfig').config, bufnr) } + end)) eq(true, ok, err) end) + + it('sets spelllang', function() + test_case('short_spelling_language.txt', { spelllang = 'de' }) + test_case('long_spelling_language.txt', { spelllang = 'en_nz' }) + end) end) diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua index 9c7c953fb0..7089313303 100644 --- a/test/functional/plugin/health_spec.lua +++ b/test/functional/plugin/health_spec.lua @@ -40,11 +40,22 @@ describe(':checkhealth', function() matches('ERROR $VIM .* zub', curbuf_contents()) end) - it('completions can be listed via getcompletion()', function() - clear() + it('getcompletion()', function() + clear { args = { '-u', 'NORC', '+set runtimepath+=test/functional/fixtures' } } + eq('vim.deprecated', getcompletion('vim', 'checkhealth')[1]) eq('vim.provider', getcompletion('vim.prov', 'checkhealth')[1]) eq('vim.lsp', getcompletion('vim.ls', 'checkhealth')[1]) + + -- "test_plug/health/init.lua" should complete as "test_plug", not "test_plug.health". #30342 + eq({ + 'test_plug', + 'test_plug.full_render', + 'test_plug.submodule', + 'test_plug.submodule_empty', + 'test_plug.success1', + 'test_plug.success2', + }, getcompletion('test_plug', 'checkhealth')) end) it('completion checks for vim.health._complete() return type #28456', function() @@ -57,11 +68,9 @@ describe(':checkhealth', function() end) end) -describe('health.vim', function() +describe('vim.health', function() before_each(function() - clear { args = { '-u', 'NORC' } } - -- Provides healthcheck functions - command('set runtimepath+=test/functional/fixtures') + clear { args = { '-u', 'NORC', '+set runtimepath+=test/functional/fixtures' } } end) describe(':checkhealth', function() @@ -70,7 +79,7 @@ describe('health.vim', function() n.expect([[ ============================================================================== - test_plug.full_render: require("test_plug.full_render.health").check() + test_plug.full_render: require("test_plug.full_render.health").check() report 1 ~ - OK life is fine @@ -93,7 +102,7 @@ describe('health.vim', function() n.expect([[ ============================================================================== - test_plug: require("test_plug.health").check() + test_plug: require("test_plug.health").check() report 1 ~ - OK everything is fine @@ -102,7 +111,7 @@ describe('health.vim', function() - OK nothing to see here ============================================================================== - test_plug.success1: require("test_plug.success1.health").check() + test_plug.success1: require("test_plug.success1.health").check() report 1 ~ - OK everything is fine @@ -111,7 +120,7 @@ describe('health.vim', function() - OK nothing to see here ============================================================================== - test_plug.success2: require("test_plug.success2.health").check() + test_plug.success2: require("test_plug.success2.health").check() another 1 ~ - OK ok @@ -123,7 +132,7 @@ describe('health.vim', function() n.expect([[ ============================================================================== - test_plug.submodule: require("test_plug.submodule.health").check() + test_plug.submodule: require("test_plug.submodule.health").check() report 1 ~ - OK everything is fine @@ -148,9 +157,10 @@ describe('health.vim', function() local screen = Screen.new(50, 12) screen:attach() screen:set_default_attr_ids({ + h1 = { reverse = true }, + h2 = { foreground = tonumber('0x6a0dad') }, Ok = { foreground = Screen.colors.LightGreen }, Error = { foreground = Screen.colors.Red }, - Heading = { foreground = tonumber('0x6a0dad') }, Bar = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGrey }, }) command('checkhealth foo success1') @@ -158,15 +168,15 @@ describe('health.vim', function() screen:expect { grid = [[ ^ | - {Bar:──────────────────────────────────────────────────}| - {Heading:foo: } | + {Bar: }| + {h1:foo: }| | - {Error:ERROR} No healthcheck found for "foo" plugin. | | - {Bar:──────────────────────────────────────────────────}| - {Heading:test_plug.success1: require("test_plug.success1.he}| + {Bar: }| + {h1:test_plug.success1: require("test_pl}| | - {Heading:report 1} | + {h2:report 1} | - {Ok:OK} everything is fine | | ]], @@ -179,7 +189,7 @@ describe('health.vim', function() n.expect([[ ============================================================================== - non_existent_healthcheck: + non_existent_healthcheck: - ERROR No healthcheck found for "non_existent_healthcheck" plugin. ]]) @@ -207,18 +217,17 @@ end) describe(':checkhealth window', function() before_each(function() - clear { args = { '-u', 'NORC' } } - -- Provides healthcheck functions - command('set runtimepath+=test/functional/fixtures') + clear { args = { '-u', 'NORC', '+set runtimepath+=test/functional/fixtures' } } command('set nofoldenable nowrap laststatus=0') end) it('opens directly if no buffer created', function() local screen = Screen.new(50, 12) screen:set_default_attr_ids { + h1 = { reverse = true }, + h2 = { foreground = tonumber('0x6a0dad') }, [1] = { foreground = Screen.colors.Blue, bold = true }, [14] = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray }, - [31] = { foreground = tonumber('0x6a0dad') }, [32] = { foreground = Screen.colors.PaleGreen2 }, } screen:attach({ ext_multigrid = true }) @@ -230,15 +239,15 @@ describe(':checkhealth window', function() [3:--------------------------------------------------]| ## grid 2 ^ | - {14:──────────────────────────────────────────────────}| - {14:────────────────────────────} | - {31:test_plug.success1: require("test_plug.success1. }| - {31:health").check()} | + {14: }| + {14: } | + {h1:test_plug.success1: }| + {h1:require("test_plug.success1.health").check()} | | - {31:report 1} | + {h2:report 1} | - {32:OK} everything is fine | | - {31:report 2} | + {h2:report 2} | - {32:OK} nothing to see here | ## grid 3 | @@ -249,9 +258,10 @@ describe(':checkhealth window', function() local function test_health_vsplit(left, emptybuf, mods) local screen = Screen.new(50, 20) screen:set_default_attr_ids { + h1 = { reverse = true }, + h2 = { foreground = tonumber('0x6a0dad') }, [1] = { foreground = Screen.colors.Blue, bold = true }, [14] = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray }, - [31] = { foreground = tonumber('0x6a0dad') }, [32] = { foreground = Screen.colors.PaleGreen2 }, } screen:attach({ ext_multigrid = true }) @@ -271,19 +281,20 @@ describe(':checkhealth window', function() | ## grid 4 ^ | - {14:─────────────────────────}|*3 - {14:───} | - {31:test_plug.success1: }| - {31:require("test_plug. }| - {31:success1.health").check()}| + {14: }|*3 + {14: } | + {h1:test_plug. }| + {h1:success1: }| + {h1:require("test_plug. }| + {h1:success1.health").check()}| | - {31:report 1} | + {h2:report 1} | - {32:OK} everything is fine | | - {31:report 2} | + {h2:report 2} | - {32:OK} nothing to see here | | - {1:~ }|*4 + {1:~ }|*3 ]]):format( left and '[4:-------------------------]│[2:------------------------]|*19' or '[2:------------------------]│[4:-------------------------]|*19', @@ -330,10 +341,10 @@ describe(':checkhealth window', function() | ## grid 4 ^ | - ──────────────────────────────────────────────────| - ──────────────────────────── | - test_plug.success1: require("test_plug.success1. | - health").check() | + | + | + test_plug.success1: | + require("test_plug.success1.health").check() | | report 1 | - OK everything is fine | @@ -382,7 +393,7 @@ describe(':checkhealth window', function() command('file my_buff') command('checkhealth success1') -- define a function that collects all buffers in each tab - -- returns a dictionary like {tab1 = ["buf1", "buf2"], tab2 = ["buf3"]} + -- returns a dict like {tab1 = ["buf1", "buf2"], tab2 = ["buf3"]} source([[ function CollectBuffersPerTab() let buffs = {} diff --git a/test/functional/plugin/lsp/codelens_spec.lua b/test/functional/plugin/lsp/codelens_spec.lua index cd20e95dd1..20ef1cb49e 100644 --- a/test/functional/plugin/lsp/codelens_spec.lua +++ b/test/functional/plugin/lsp/codelens_spec.lua @@ -13,36 +13,34 @@ describe('vim.lsp.codelens', function() it('on_codelens_stores_and_displays_lenses', function() local fake_uri = 'file:///fake/uri' - local bufnr = exec_lua( - [[ - fake_uri = ... + local bufnr = exec_lua(function() local bufnr = vim.uri_to_bufnr(fake_uri) - local lines = {'So', 'many', 'lines'} + local lines = { 'So', 'many', 'lines' } vim.fn.bufload(bufnr) vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) return bufnr - ]], - fake_uri - ) + end) - exec_lua( - [[ - local bufnr = ... + exec_lua(function() local lenses = { { range = { - start = { line = 0, character = 0, }, - ['end'] = { line = 0, character = 0 } + start = { line = 0, character = 0 }, + ['end'] = { line = 0, character = 0 }, }, - command = { title = 'Lens1', command = 'Dummy' } + command = { title = 'Lens1', command = 'Dummy' }, }, } - vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr}) - ]], - bufnr - ) + vim.lsp.codelens.on_codelens( + nil, + lenses, + { method = 'textDocument/codeLens', client_id = 1, bufnr = bufnr } + ) + end) - local stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr) + local stored_lenses = exec_lua(function() + return vim.lsp.codelens.get(bufnr) + end) local expected = { { range = { @@ -57,58 +55,54 @@ describe('vim.lsp.codelens', function() } eq(expected, stored_lenses) - local virtual_text_chunks = exec_lua( - [[ - local bufnr = ... + local virtual_text_chunks = exec_lua(function() local ns = vim.lsp.codelens.__namespaces[1] local extmarks = vim.api.nvim_buf_get_extmarks(bufnr, ns, 0, -1, {}) return vim.api.nvim_buf_get_extmark_by_id(bufnr, ns, extmarks[1][1], { details = true })[3].virt_text - ]], - bufnr - ) + end) eq({ [1] = { 'Lens1', 'LspCodeLens' } }, virtual_text_chunks) end) it('can clear all lens', function() local fake_uri = 'file:///fake/uri' - local bufnr = exec_lua( - [[ - fake_uri = ... + local bufnr = exec_lua(function() local bufnr = vim.uri_to_bufnr(fake_uri) - local lines = {'So', 'many', 'lines'} + local lines = { 'So', 'many', 'lines' } vim.fn.bufload(bufnr) vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) return bufnr - ]], - fake_uri - ) + end) - exec_lua( - [[ - local bufnr = ... + exec_lua(function() local lenses = { { range = { - start = { line = 0, character = 0, }, - ['end'] = { line = 0, character = 0 } + start = { line = 0, character = 0 }, + ['end'] = { line = 0, character = 0 }, }, - command = { title = 'Lens1', command = 'Dummy' } + command = { title = 'Lens1', command = 'Dummy' }, }, } - vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr}) - ]], - bufnr - ) + vim.lsp.codelens.on_codelens( + nil, + lenses, + { method = 'textDocument/codeLens', client_id = 1, bufnr = bufnr } + ) + end) - local stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr) + local stored_lenses = exec_lua(function() + return vim.lsp.codelens.get(bufnr) + end) eq(1, #stored_lenses) - exec_lua([[ + exec_lua(function() vim.lsp.codelens.clear() - ]]) + end) - stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr) + stored_lenses = exec_lua(function() + return vim.lsp.codelens.get(bufnr) + end) eq(0, #stored_lenses) end) end) diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index 2798d57381..4df8d77d44 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -1,9 +1,16 @@ ---@diagnostic disable: no-unknown local t = require('test.testutil') +local t_lsp = require('test.functional.plugin.lsp.testutil') local n = require('test.functional.testnvim')() +local clear = n.clear local eq = t.eq +local neq = t.neq local exec_lua = n.exec_lua +local feed = n.feed +local retry = t.retry + +local create_server_definition = t_lsp.create_server_definition --- Convert completion results. --- @@ -11,38 +18,32 @@ local exec_lua = n.exec_lua ---@param candidates lsp.CompletionList|lsp.CompletionItem[] ---@param lnum? integer 0-based, defaults to 0 ---@return {items: table[], server_start_boundary: integer?} -local function complete(line, candidates, lnum) +local function complete(line, candidates, lnum, server_boundary) lnum = lnum or 0 -- nvim_win_get_cursor returns 0 based column, line:find returns 1 based local cursor_col = line:find('|') - 1 line = line:gsub('|', '') - return exec_lua( - [[ - local line, cursor_col, lnum, result = ... + return exec_lua(function(result) local line_to_cursor = line:sub(1, cursor_col) local client_start_boundary = vim.fn.match(line_to_cursor, '\\k*$') - local items, server_start_boundary = require("vim.lsp._completion")._convert_results( + local items, new_server_boundary = require('vim.lsp.completion')._convert_results( line, lnum, cursor_col, + 1, client_start_boundary, - nil, + server_boundary, result, - "utf-16" + 'utf-16' ) return { items = items, - server_start_boundary = server_start_boundary + server_start_boundary = new_server_boundary, } - ]], - line, - cursor_col, - lnum, - candidates - ) + end, candidates) end -describe('vim.lsp._completion', function() +describe('vim.lsp.completion: item conversion', function() before_each(n.clear) -- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion @@ -70,39 +71,24 @@ describe('vim.lsp._completion', function() textEdit = { newText = 'foobar', range = range0 }, }, { label = 'foocar', sortText = 'f', textEdit = { newText = 'foobar', range = range0 } }, - -- real-world snippet text + -- plain text { label = 'foocar', sortText = 'g', - insertText = 'foodar', + insertText = 'foodar(${1:var1})', + insertTextFormat = 1, + }, + { + label = '•INT16_C(c)', + insertText = 'INT16_C(${1:c})', insertTextFormat = 2, + filterText = 'INT16_C', + sortText = 'h', textEdit = { - newText = 'foobar(${1:place holder}, ${2:more ...holder{\\}})', + newText = 'INT16_C(${1:c})', range = range0, }, }, - { - label = 'foocar', - sortText = 'h', - insertText = 'foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', - insertTextFormat = 2, - }, - -- nested snippet tokens - { - label = 'foocar', - sortText = 'i', - insertText = 'foodar(${1:${2|typ1,typ2|}}) {$0\\}', - insertTextFormat = 2, - }, - -- braced tabstop - { label = 'foocar', sortText = 'j', insertText = 'foodar()${0}', insertTextFormat = 2 }, - -- plain text - { - label = 'foocar', - sortText = 'k', - insertText = 'foodar(${1:var1})', - insertTextFormat = 1, - }, } local expected = { { @@ -131,23 +117,167 @@ describe('vim.lsp._completion', function() }, { abbr = 'foocar', - word = 'foobar(place holder, more ...holder{})', + word = 'foodar(${1:var1})', -- marked as PlainText, text is used as is }, { - abbr = 'foocar', - word = 'foodar(var1 typ1, var2 *typ2) {}', + abbr = '•INT16_C(c)', + word = 'INT16_C', }, + } + local result = complete('|', completion_list) + result = vim.tbl_map(function(x) + return { + abbr = x.abbr, + word = x.word, + } + end, result.items) + eq(expected, result) + end) + + it('filters on label if filterText is missing', function() + local completion_list = { + { label = 'foo' }, + { label = 'bar' }, + } + local result = complete('fo|', completion_list) + local expected = { { - abbr = 'foocar', - word = 'foodar(typ1) {}', + abbr = 'foo', + word = 'foo', }, + } + result = vim.tbl_map(function(x) + return { + abbr = x.abbr, + word = x.word, + } + end, result.items) + eq(expected, result) + end) + + it('works on non word prefix', function() + local completion_list = { + { label = ' foo', insertText = '->foo' }, + } + local result = complete('wp.|', completion_list, 0, 2) + local expected = { { - abbr = 'foocar', - word = 'foodar()', + abbr = ' foo', + word = '->foo', }, + } + result = vim.tbl_map(function(x) + return { + abbr = x.abbr, + word = x.word, + } + end, result.items) + eq(expected, result) + end) + + it('trims trailing newline or tab from textEdit', function() + local range0 = { + start = { line = 0, character = 0 }, + ['end'] = { line = 0, character = 0 }, + } + local items = { { - abbr = 'foocar', - word = 'foodar(${1:var1})', + detail = 'ansible.builtin', + filterText = 'lineinfile ansible.builtin.lineinfile builtin ansible', + kind = 7, + label = 'ansible.builtin.lineinfile', + sortText = '2_ansible.builtin.lineinfile', + textEdit = { + newText = 'ansible.builtin.lineinfile:\n ', + range = range0, + }, + }, + } + local result = complete('|', items) + result = vim.tbl_map(function(x) + return { + abbr = x.abbr, + word = x.word, + } + end, result.items) + + local expected = { + { + abbr = 'ansible.builtin.lineinfile', + word = 'ansible.builtin.lineinfile:', + }, + } + eq(expected, result) + end) + + it('prefers wordlike components for snippets', function() + -- There are two goals here: + -- + -- 1. The `word` should match what the user started typing, so that vim.fn.complete() doesn't + -- filter it away, preventing snippet expansion + -- + -- For example, if they type `items@ins`, luals returns `table.insert(items, $0)` as + -- textEdit.newText and `insert` as label. + -- There would be no prefix match if textEdit.newText is used as `word` + -- + -- 2. If users do not expand a snippet, but continue typing, they should see a somewhat reasonable + -- `word` getting inserted. + -- + -- For example in: + -- + -- insertText: "testSuites ${1:Env}" + -- label: "testSuites" + -- + -- "testSuites" should have priority as `word`, as long as the full snippet gets expanded on accept (<c-y>) + local range0 = { + start = { line = 0, character = 0 }, + ['end'] = { line = 0, character = 0 }, + } + local completion_list = { + -- luals postfix snippet (typed text: items@ins|) + { + label = 'insert', + insertTextFormat = 2, + textEdit = { + newText = 'table.insert(items, $0)', + range = range0, + }, + }, + + -- eclipse.jdt.ls `new` snippet + { + label = 'new', + insertTextFormat = 2, + textEdit = { + newText = '${1:Object} ${2:foo} = new ${1}(${3});\n${0}', + range = range0, + }, + textEditText = '${1:Object} ${2:foo} = new ${1}(${3});\n${0}', + }, + + -- eclipse.jdt.ls `List.copyO` function call completion + { + label = 'copyOf(Collection<? extends E> coll) : List<E>', + insertTextFormat = 2, + insertText = 'copyOf', + textEdit = { + newText = 'copyOf(${1:coll})', + range = range0, + }, + }, + } + local expected = { + { + abbr = 'copyOf(Collection<? extends E> coll) : List<E>', + word = 'copyOf', + }, + { + abbr = 'insert', + word = 'insert', + }, + { + abbr = 'new', + word = 'new', }, } local result = complete('|', completion_list) @@ -159,6 +289,7 @@ describe('vim.lsp._completion', function() end, result.items) eq(expected, result) end) + it('uses correct start boundary', function() local completion_list = { isIncomplete = false, @@ -186,8 +317,10 @@ describe('vim.lsp._completion', function() dup = 1, empty = 1, icase = 1, + info = '', kind = 'Module', menu = '', + hl_group = '', word = 'this_thread', } local result = complete(' std::this|', completion_list) @@ -218,7 +351,7 @@ describe('vim.lsp._completion', function() }, }, { - filterText = 'notthis_thread', + filterText = 'no_match', insertText = 'notthis_thread', insertTextFormat = 1, kind = 9, @@ -240,8 +373,10 @@ describe('vim.lsp._completion', function() dup = 1, empty = 1, icase = 1, + info = '', kind = 'Module', menu = '', + hl_group = '', word = 'this_thread', } local result = complete(' std::this|is', completion_list) @@ -278,4 +413,316 @@ describe('vim.lsp._completion', function() eq('item-property-has-priority', item.data) eq({ line = 1, character = 1 }, item.textEdit.range.start) end) + + it( + 'uses insertText as textEdit.newText if there are editRange defaults but no textEditText', + function() + --- @type lsp.CompletionList + local completion_list = { + isIncomplete = false, + itemDefaults = { + editRange = { + start = { line = 1, character = 1 }, + ['end'] = { line = 1, character = 4 }, + }, + insertTextFormat = 2, + data = 'foobar', + }, + items = { + { + insertText = 'the-insertText', + label = 'hello', + data = 'item-property-has-priority', + }, + }, + } + local result = complete('|', completion_list) + eq(1, #result.items) + local text = result.items[1].user_data.nvim.lsp.completion_item.textEdit.newText + eq('the-insertText', text) + end + ) + + it( + 'defaults to label as textEdit.newText if insertText or textEditText are not present', + function() + local completion_list = { + isIncomplete = false, + itemDefaults = { + editRange = { + start = { line = 1, character = 1 }, + ['end'] = { line = 1, character = 4 }, + }, + insertTextFormat = 2, + data = 'foobar', + }, + items = { + { + label = 'hello', + data = 'item-property-has-priority', + }, + }, + } + local result = complete('|', completion_list) + eq(1, #result.items) + local text = result.items[1].user_data.nvim.lsp.completion_item.textEdit.newText + eq('hello', text) + end + ) +end) + +describe('vim.lsp.completion: protocol', function() + before_each(function() + clear() + exec_lua(create_server_definition) + exec_lua(function() + _G.capture = {} + --- @diagnostic disable-next-line:duplicate-set-field + vim.fn.complete = function(col, matches) + _G.capture.col = col + _G.capture.matches = matches + end + end) + end) + + after_each(clear) + + --- @param completion_result lsp.CompletionList + --- @return integer + local function create_server(completion_result) + return exec_lua(function() + local server = _G._create_server({ + capabilities = { + completionProvider = { + triggerCharacters = { '.' }, + }, + }, + handlers = { + ['textDocument/completion'] = function(_, _, callback) + callback(nil, completion_result) + end, + }, + }) + + local bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_win_set_buf(0, bufnr) + return vim.lsp.start({ + name = 'dummy', + cmd = server.cmd, + on_attach = function(client, bufnr0) + vim.lsp.completion.enable(true, client.id, bufnr0, { + convert = function(item) + return { abbr = item.label:gsub('%b()', '') } + end, + }) + end, + }) + end) + end + + local function assert_matches(fn) + retry(nil, nil, function() + fn(exec_lua('return _G.capture.matches')) + end) + end + + --- @param pos [integer, integer] + local function trigger_at_pos(pos) + exec_lua(function() + local win = vim.api.nvim_get_current_win() + vim.api.nvim_win_set_cursor(win, pos) + vim.lsp.completion.trigger() + end) + + retry(nil, nil, function() + neq(nil, exec_lua('return _G.capture.col')) + end) + end + + it('fetches completions and shows them using complete on trigger', function() + create_server({ + isIncomplete = false, + items = { + { + label = 'hello', + }, + { + label = 'hercules', + tags = { 1 }, -- 1 represents Deprecated tag + }, + { + label = 'hero', + deprecated = true, + }, + }, + }) + + feed('ih') + trigger_at_pos({ 1, 1 }) + + assert_matches(function(matches) + eq({ + { + abbr = 'hello', + dup = 1, + empty = 1, + icase = 1, + info = '', + kind = 'Unknown', + menu = '', + hl_group = '', + user_data = { + nvim = { + lsp = { + client_id = 1, + completion_item = { + label = 'hello', + }, + }, + }, + }, + word = 'hello', + }, + { + abbr = 'hercules', + dup = 1, + empty = 1, + icase = 1, + info = '', + kind = 'Unknown', + menu = '', + hl_group = 'DiagnosticDeprecated', + user_data = { + nvim = { + lsp = { + client_id = 1, + completion_item = { + label = 'hercules', + tags = { 1 }, + }, + }, + }, + }, + word = 'hercules', + }, + { + abbr = 'hero', + dup = 1, + empty = 1, + icase = 1, + info = '', + kind = 'Unknown', + menu = '', + hl_group = 'DiagnosticDeprecated', + user_data = { + nvim = { + lsp = { + client_id = 1, + completion_item = { + label = 'hero', + deprecated = true, + }, + }, + }, + }, + word = 'hero', + }, + }, matches) + end) + end) + + it('merges results from multiple clients', function() + create_server({ + isIncomplete = false, + items = { + { + label = 'hello', + }, + }, + }) + create_server({ + isIncomplete = false, + items = { + { + label = 'hallo', + }, + }, + }) + + feed('ih') + trigger_at_pos({ 1, 1 }) + + assert_matches(function(matches) + eq(2, #matches) + eq('hello', matches[1].word) + eq('hallo', matches[2].word) + end) + end) + + it('executes commands', function() + local completion_list = { + isIncomplete = false, + items = { + { + label = 'hello', + command = { + arguments = { '1', '0' }, + command = 'dummy', + title = '', + }, + }, + }, + } + local client_id = create_server(completion_list) + + exec_lua(function() + _G.called = false + local client = assert(vim.lsp.get_client_by_id(client_id)) + client.commands.dummy = function() + _G.called = true + end + end) + + feed('ih') + trigger_at_pos({ 1, 1 }) + + local item = completion_list.items[1] + exec_lua(function() + vim.v.completed_item = { + user_data = { + nvim = { + lsp = { + client_id = client_id, + completion_item = item, + }, + }, + }, + } + end) + + feed('<C-x><C-o><C-y>') + + assert_matches(function(matches) + eq(1, #matches) + eq('hello', matches[1].word) + eq(true, exec_lua('return _G.called')) + end) + end) + + it('enable(…,{convert=fn}) custom word/abbr format', function() + create_server({ + isIncomplete = false, + items = { + { + label = 'foo(bar)', + }, + }, + }) + + feed('ifo') + trigger_at_pos({ 1, 1 }) + assert_matches(function(matches) + eq('foo', matches[1].abbr) + end) + end) end) diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua index c5e14ffdc2..78c684083b 100644 --- a/test/functional/plugin/lsp/diagnostic_spec.lua +++ b/test/functional/plugin/lsp/diagnostic_spec.lua @@ -11,7 +11,9 @@ local neq = t.neq local create_server_definition = t_lsp.create_server_definition describe('vim.lsp.diagnostic', function() - local fake_uri + local fake_uri --- @type string + local client_id --- @type integer + local diagnostic_bufnr --- @type integer before_each(function() clear { env = { @@ -19,198 +21,174 @@ describe('vim.lsp.diagnostic', function() VIMRUNTIME = os.getenv 'VIMRUNTIME', } } - exec_lua [[ + exec_lua(function() require('vim.lsp') - make_range = function(x1, y1, x2, y2) + _G.make_range = function(x1, y1, x2, y2) return { start = { line = x1, character = y1 }, ['end'] = { line = x2, character = y2 } } end - make_error = function(msg, x1, y1, x2, y2) + _G.make_error = function(msg, x1, y1, x2, y2) return { - range = make_range(x1, y1, x2, y2), + range = _G.make_range(x1, y1, x2, y2), message = msg, severity = 1, } end - make_warning = function(msg, x1, y1, x2, y2) + _G.make_warning = function(msg, x1, y1, x2, y2) return { - range = make_range(x1, y1, x2, y2), + range = _G.make_range(x1, y1, x2, y2), message = msg, severity = 2, } end - make_information = function(msg, x1, y1, x2, y2) + _G.make_information = function(msg, x1, y1, x2, y2) return { - range = make_range(x1, y1, x2, y2), + range = _G.make_range(x1, y1, x2, y2), message = msg, severity = 3, } end - function get_extmarks(bufnr, client_id) - local namespace = vim.lsp.diagnostic.get_namespace(client_id) + function _G.get_extmarks(bufnr, client_id0) + local namespace = vim.lsp.diagnostic.get_namespace(client_id0) local ns = vim.diagnostic.get_namespace(namespace) local extmarks = {} if ns.user_data.virt_text_ns then - for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.virt_text_ns, 0, -1, {details=true})) do + for _, e in + pairs( + vim.api.nvim_buf_get_extmarks( + bufnr, + ns.user_data.virt_text_ns, + 0, + -1, + { details = true } + ) + ) + do table.insert(extmarks, e) end end if ns.user_data.underline_ns then - for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.underline_ns, 0, -1, {details=true})) do + for _, e in + pairs( + vim.api.nvim_buf_get_extmarks( + bufnr, + ns.user_data.underline_ns, + 0, + -1, + { details = true } + ) + ) + do table.insert(extmarks, e) end end return extmarks end - client_id = vim.lsp.start_client { + client_id = assert(vim.lsp.start_client { cmd_env = { - NVIM_LUA_NOTRACK = "1"; - }; + NVIM_LUA_NOTRACK = '1', + }, cmd = { - vim.v.progpath, '-es', '-u', 'NONE', '--headless' - }; - offset_encoding = "utf-16"; - } - ]] + vim.v.progpath, + '-es', + '-u', + 'NONE', + '--headless', + }, + offset_encoding = 'utf-16', + }) + end) fake_uri = 'file:///fake/uri' - exec_lua( - [[ - fake_uri = ... + exec_lua(function() diagnostic_bufnr = vim.uri_to_bufnr(fake_uri) - local lines = {"1st line of text", "2nd line of text", "wow", "cool", "more", "lines"} + local lines = { '1st line of text', '2nd line of text', 'wow', 'cool', 'more', 'lines' } vim.fn.bufload(diagnostic_bufnr) vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, 1, false, lines) vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - return diagnostic_bufnr - ]], - fake_uri - ) + end) end) after_each(function() clear() end) - describe('vim.lsp.diagnostic', function() - it('maintains LSP information when translating diagnostics', function() - local result = exec_lua [[ - local diagnostics = { - make_error("Error 1", 1, 1, 1, 5), - } - - diagnostics[1].code = 42 - diagnostics[1].data = "Hello world" - - vim.lsp.diagnostic.on_publish_diagnostics(nil, { - uri = fake_uri, - diagnostics = diagnostics, - }, {client_id=client_id}) - - return { - vim.diagnostic.get(diagnostic_bufnr, {lnum=1})[1], - vim.lsp.diagnostic.get_line_diagnostics(diagnostic_bufnr, 1)[1], - } - ]] - eq({ code = 42, data = 'Hello world' }, result[1].user_data.lsp) - eq(42, result[1].code) - eq(42, result[2].code) - eq('Hello world', result[2].data) - end) - end) - describe('vim.lsp.diagnostic.on_publish_diagnostics', function() it('allows configuring the virtual text via vim.lsp.with', function() local expected_spacing = 10 - local extmarks = exec_lua( - [[ - PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { + local extmarks = exec_lua(function() + _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { virtual_text = { - spacing = ..., + spacing = expected_spacing, }, }) - PublishDiagnostics(nil, { - uri = fake_uri, - diagnostics = { - make_error('Delayed Diagnostic', 4, 4, 4, 4), - } - }, {client_id=client_id} - ) + _G.PublishDiagnostics(nil, { + uri = fake_uri, + diagnostics = { + _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), + }, + }, { client_id = client_id }) - return get_extmarks(diagnostic_bufnr, client_id) - ]], - expected_spacing - ) + return _G.get_extmarks(diagnostic_bufnr, client_id) + end) - local virt_text = extmarks[1][4].virt_text - local spacing = virt_text[1][1] + local spacing = extmarks[1][4].virt_text[1][1] eq(expected_spacing, #spacing) end) it('allows configuring the virtual text via vim.lsp.with using a function', function() local expected_spacing = 10 - local extmarks = exec_lua( - [[ - spacing = ... - - PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { + local extmarks = exec_lua(function() + _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { virtual_text = function() return { - spacing = spacing, + spacing = expected_spacing, } end, }) - PublishDiagnostics(nil, { - uri = fake_uri, - diagnostics = { - make_error('Delayed Diagnostic', 4, 4, 4, 4), - } - }, {client_id=client_id} - ) + _G.PublishDiagnostics(nil, { + uri = fake_uri, + diagnostics = { + _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), + }, + }, { client_id = client_id }) - return get_extmarks(diagnostic_bufnr, client_id) - ]], - expected_spacing - ) + return _G.get_extmarks(diagnostic_bufnr, client_id) + end) - local virt_text = extmarks[1][4].virt_text - local spacing = virt_text[1][1] + local spacing = extmarks[1][4].virt_text[1][1] eq(expected_spacing, #spacing) end) it('allows filtering via severity limit', function() local get_extmark_count_with_severity = function(severity_limit) - return exec_lua( - [[ - PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { + return exec_lua(function() + _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { underline = false, virtual_text = { - severity = { min = ... } + severity = { min = severity_limit }, }, }) - PublishDiagnostics(nil, { - uri = fake_uri, - diagnostics = { - make_warning('Delayed Diagnostic', 4, 4, 4, 4), - } - }, {client_id=client_id} - ) - - return #get_extmarks(diagnostic_bufnr, client_id) - ]], - severity_limit - ) + _G.PublishDiagnostics(nil, { + uri = fake_uri, + diagnostics = { + _G.make_warning('Delayed Diagnostic', 4, 4, 4, 4), + }, + }, { client_id = client_id }) + + return #_G.get_extmarks(diagnostic_bufnr, client_id) + end, client_id, fake_uri, severity_limit) end -- No messages with Error or higher @@ -223,218 +201,284 @@ describe('vim.lsp.diagnostic', function() it('correctly handles UTF-16 offsets', function() local line = 'All 💼 and no 🎉 makes Jack a dull 👦' - local result = exec_lua( - [[ - local line = ... - vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, -1, false, {line}) + local result = exec_lua(function() + vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, -1, false, { line }) vim.lsp.diagnostic.on_publish_diagnostics(nil, { - uri = fake_uri, - diagnostics = { - make_error('UTF-16 Diagnostic', 0, 7, 0, 8), - } - }, {client_id=client_id} - ) + uri = fake_uri, + diagnostics = { + _G.make_error('UTF-16 Diagnostic', 0, 7, 0, 8), + }, + }, { client_id = client_id }) local diags = vim.diagnostic.get(diagnostic_bufnr) vim.lsp.stop_client(client_id) vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false }) return diags - ]], - line - ) + end) eq(1, #result) - eq(exec_lua([[return vim.str_byteindex(..., 7, true)]], line), result[1].col) - eq(exec_lua([[return vim.str_byteindex(..., 8, true)]], line), result[1].end_col) + eq( + exec_lua(function() + return vim.str_byteindex(line, 7, true) + end), + result[1].col + ) + eq( + exec_lua(function() + return vim.str_byteindex(line, 8, true) + end), + result[1].end_col + ) end) it('does not create buffer on empty diagnostics', function() - local bufnr - -- No buffer is created without diagnostics - bufnr = exec_lua [[ - vim.lsp.diagnostic.on_publish_diagnostics(nil, { - uri = "file:///fake/uri2", - diagnostics = {}, - }, {client_id=client_id}) - return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2")) - ]] - eq(-1, bufnr) + eq( + -1, + exec_lua(function() + vim.lsp.diagnostic.on_publish_diagnostics(nil, { + uri = 'file:///fake/uri2', + diagnostics = {}, + }, { client_id = client_id }) + return vim.fn.bufnr(vim.uri_to_fname('file:///fake/uri2')) + end) + ) -- Create buffer on diagnostics - bufnr = exec_lua [[ - vim.lsp.diagnostic.on_publish_diagnostics(nil, { - uri = "file:///fake/uri2", - diagnostics = { - make_error('Diagnostic', 0, 0, 0, 0), - }, - }, {client_id=client_id}) - return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2")) - ]] - neq(-1, bufnr) - eq(1, exec_lua([[return #vim.diagnostic.get(...)]], bufnr)) + neq( + -1, + exec_lua(function() + vim.lsp.diagnostic.on_publish_diagnostics(nil, { + uri = 'file:///fake/uri2', + diagnostics = { + _G.make_error('Diagnostic', 0, 0, 0, 0), + }, + }, { client_id = client_id }) + return vim.fn.bufnr(vim.uri_to_fname('file:///fake/uri2')) + end) + ) + eq( + 1, + exec_lua(function() + return #vim.diagnostic.get(_G.bufnr) + end) + ) -- Clear diagnostics after buffer was created - bufnr = exec_lua [[ - vim.lsp.diagnostic.on_publish_diagnostics(nil, { - uri = "file:///fake/uri2", - diagnostics = {}, - }, {client_id=client_id}) - return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2")) - ]] - neq(-1, bufnr) - eq(0, exec_lua([[return #vim.diagnostic.get(...)]], bufnr)) + neq( + -1, + exec_lua(function() + vim.lsp.diagnostic.on_publish_diagnostics(nil, { + uri = 'file:///fake/uri2', + diagnostics = {}, + }, { client_id = client_id }) + return vim.fn.bufnr(vim.uri_to_fname('file:///fake/uri2')) + end) + ) + eq( + 0, + exec_lua(function() + return #vim.diagnostic.get(_G.bufnr) + end) + ) end) end) describe('vim.lsp.diagnostic.on_diagnostic', function() before_each(function() exec_lua(create_server_definition) - exec_lua([[ - server = _create_server({ + exec_lua(function() + _G.server = _G._create_server({ capabilities = { - diagnosticProvider = { - } - } + diagnosticProvider = {}, + }, }) - function get_extmarks(bufnr, client_id) - local namespace = vim.lsp.diagnostic.get_namespace(client_id, true) + function _G.get_extmarks(bufnr, client_id0) + local namespace = vim.lsp.diagnostic.get_namespace(client_id0, true) local ns = vim.diagnostic.get_namespace(namespace) local extmarks = {} if ns.user_data.virt_text_ns then - for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.virt_text_ns, 0, -1, {details=true})) do + for _, e in + pairs( + vim.api.nvim_buf_get_extmarks( + bufnr, + ns.user_data.virt_text_ns, + 0, + -1, + { details = true } + ) + ) + do table.insert(extmarks, e) end end if ns.user_data.underline_ns then - for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.underline_ns, 0, -1, {details=true})) do + for _, e in + pairs( + vim.api.nvim_buf_get_extmarks( + bufnr, + ns.user_data.underline_ns, + 0, + -1, + { details = true } + ) + ) + do table.insert(extmarks, e) end end return extmarks end - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]]) + client_id = vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) end) it('adds diagnostics to vim.diagnostics', function() - local diags = exec_lua([[ - vim.lsp.diagnostic.on_diagnostic(nil, - { - kind = 'full', - items = { - make_error('Pull Diagnostic', 4, 4, 4, 4), - } + local diags = exec_lua(function() + vim.lsp.diagnostic.on_diagnostic(nil, { + kind = 'full', + items = { + _G.make_error('Pull Diagnostic', 4, 4, 4, 4), }, - { - params = { - textDocument = { uri = fake_uri }, - }, - uri = fake_uri, - client_id = client_id, + }, { + params = { + textDocument = { uri = fake_uri }, }, - {} - ) + uri = fake_uri, + client_id = client_id, + }, {}) return vim.diagnostic.get(diagnostic_bufnr) - ]]) + end) eq(1, #diags) eq('Pull Diagnostic', diags[1].message) end) + it('severity defaults to error if missing', function() + ---@type vim.Diagnostic[] + local diagnostics = exec_lua(function() + vim.lsp.diagnostic.on_diagnostic(nil, { + kind = 'full', + items = { + { + range = _G.make_range(4, 4, 4, 4), + message = 'bad!', + }, + }, + }, { + params = { + textDocument = { uri = fake_uri }, + }, + uri = fake_uri, + client_id = client_id, + }, {}) + return vim.diagnostic.get(diagnostic_bufnr) + end) + eq(1, #diagnostics) + eq(1, diagnostics[1].severity) + end) + it('allows configuring the virtual text via vim.lsp.with', function() local expected_spacing = 10 - local extmarks = exec_lua( - [[ - Diagnostic = vim.lsp.with(vim.lsp.diagnostic.on_diagnostic, { + local extmarks = exec_lua(function() + _G.Diagnostic = vim.lsp.with(vim.lsp.diagnostic.on_diagnostic, { virtual_text = { - spacing = ..., + spacing = expected_spacing, }, }) - Diagnostic(nil, - { - kind = 'full', - items = { - make_error('Pull Diagnostic', 4, 4, 4, 4), - } + _G.Diagnostic(nil, { + kind = 'full', + items = { + _G.make_error('Pull Diagnostic', 4, 4, 4, 4), }, - { - params = { - textDocument = { uri = fake_uri }, - }, - uri = fake_uri, - client_id = client_id, + }, { + params = { + textDocument = { uri = fake_uri }, }, - {} - ) + uri = fake_uri, + client_id = client_id, + }, {}) - return get_extmarks(diagnostic_bufnr, client_id) - ]], - expected_spacing - ) + return _G.get_extmarks(diagnostic_bufnr, client_id) + end) eq(2, #extmarks) eq(expected_spacing, #extmarks[1][4].virt_text[1][1]) end) it('clears diagnostics when client detaches', function() - exec_lua([[ - vim.lsp.diagnostic.on_diagnostic(nil, - { - kind = 'full', - items = { - make_error('Pull Diagnostic', 4, 4, 4, 4), - } + exec_lua(function() + vim.lsp.diagnostic.on_diagnostic(nil, { + kind = 'full', + items = { + _G.make_error('Pull Diagnostic', 4, 4, 4, 4), }, - { - params = { - textDocument = { uri = fake_uri }, - }, - uri = fake_uri, - client_id = client_id, + }, { + params = { + textDocument = { uri = fake_uri }, }, - {} - ) - ]]) - local diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]]) - eq(1, #diags) + uri = fake_uri, + client_id = client_id, + }, {}) + end) + + eq( + 1, + exec_lua(function() + return #vim.diagnostic.get(diagnostic_bufnr) + end) + ) - exec_lua([[ vim.lsp.stop_client(client_id) ]]) + exec_lua(function() + vim.lsp.stop_client(client_id) + end) - diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]]) - eq(0, #diags) + eq( + 0, + exec_lua(function() + return #vim.diagnostic.get(diagnostic_bufnr) + end) + ) end) it('keeps diagnostics when one client detaches and others still are attached', function() - exec_lua([[ - client_id2 = vim.lsp.start({ name = 'dummy2', cmd = server.cmd }) - - vim.lsp.diagnostic.on_diagnostic(nil, - { - kind = 'full', - items = { - make_error('Pull Diagnostic', 4, 4, 4, 4), - } + local client_id2 + exec_lua(function() + client_id2 = vim.lsp.start({ name = 'dummy2', cmd = _G.server.cmd }) + + vim.lsp.diagnostic.on_diagnostic(nil, { + kind = 'full', + items = { + _G.make_error('Pull Diagnostic', 4, 4, 4, 4), }, - { - params = { - textDocument = { uri = fake_uri }, - }, - uri = fake_uri, - client_id = client_id, + }, { + params = { + textDocument = { uri = fake_uri }, }, - {} - ) - ]]) - local diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]]) - eq(1, #diags) + uri = fake_uri, + client_id = client_id, + }, {}) + end) + + eq( + 1, + exec_lua(function() + return #vim.diagnostic.get(diagnostic_bufnr) + end) + ) - exec_lua([[ vim.lsp.stop_client(client_id2) ]]) + exec_lua(function() + vim.lsp.stop_client(client_id2) + end) - diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]]) - eq(1, #diags) + eq( + 1, + exec_lua(function() + return #vim.diagnostic.get(diagnostic_bufnr) + end) + ) end) end) end) diff --git a/test/functional/plugin/lsp/handler_spec.lua b/test/functional/plugin/lsp/handler_spec.lua index 013a5fb5e7..4b05b676a8 100644 --- a/test/functional/plugin/lsp/handler_spec.lua +++ b/test/functional/plugin/lsp/handler_spec.lua @@ -11,28 +11,31 @@ describe('lsp-handlers', function() it('should return a table with the default keys', function() eq( { hello = 'world' }, - exec_lua [[ - return vim.lsp._with_extend('test', { hello = 'world' }) - ]] + exec_lua(function() + return vim.lsp._with_extend('test', { hello = 'world' }) + end) ) end) it('should override with config keys', function() eq( { hello = 'universe', other = true }, - exec_lua [[ - return vim.lsp._with_extend('test', { other = true, hello = 'world' }, { hello = 'universe' }) - ]] + exec_lua(function() + return vim.lsp._with_extend( + 'test', + { other = true, hello = 'world' }, + { hello = 'universe' } + ) + end) ) end) it('should not allow invalid keys', function() matches( '.*Invalid option for `test`.*', - pcall_err( - exec_lua, - "return vim.lsp._with_extend('test', { hello = 'world' }, { invalid = true })" - ) + pcall_err(exec_lua, function() + return vim.lsp._with_extend('test', { hello = 'world' }, { invalid = true }) + end) ) end) end) diff --git a/test/functional/plugin/lsp/incremental_sync_spec.lua b/test/functional/plugin/lsp/incremental_sync_spec.lua index 238b90b57d..f60e159d64 100644 --- a/test/functional/plugin/lsp/incremental_sync_spec.lua +++ b/test/functional/plugin/lsp/incremental_sync_spec.lua @@ -10,11 +10,9 @@ local feed = n.feed before_each(function() clear() - exec_lua [[ - local evname = ... + exec_lua(function() local sync = require('vim.lsp.sync') local events = {} - local buffer_cache = {} -- local format_line_ending = { -- ["unix"] = '\n', @@ -24,35 +22,43 @@ before_each(function() -- local line_ending = format_line_ending[vim.api.nvim_get_option_value('fileformat', {})] - - function test_register(bufnr, id, offset_encoding, line_ending) - local curr_lines + --- @diagnostic disable-next-line:duplicate-set-field + function _G.test_register(bufnr, id, offset_encoding, line_ending) local prev_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true) - local function callback(_, bufnr, changedtick, firstline, lastline, new_lastline) - if test_unreg == id then + local function callback(_, bufnr0, _changedtick, firstline, lastline, new_lastline) + if _G.test_unreg == id then return true end - local curr_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true) + local curr_lines = vim.api.nvim_buf_get_lines(bufnr0, 0, -1, true) local incremental_change = sync.compute_diff( - prev_lines, curr_lines, firstline, lastline, new_lastline, offset_encoding, line_ending) + prev_lines, + curr_lines, + firstline, + lastline, + new_lastline, + offset_encoding, + line_ending + ) table.insert(events, incremental_change) prev_lines = curr_lines end - local opts = {on_lines=callback, on_detach=callback, on_reload=callback} + local opts = { on_lines = callback, on_detach = callback, on_reload = callback } vim.api.nvim_buf_attach(bufnr, false, opts) end - function get_events() + --- @diagnostic disable-next-line:duplicate-set-field + function _G.get_events() local ret_events = events events = {} return ret_events end - ]] + end) end) +--- @param edit_operations string[] local function test_edit( prev_buffer, edit_operations, @@ -64,13 +70,22 @@ local function test_edit( line_ending = line_ending or '\n' api.nvim_buf_set_lines(0, 0, -1, true, prev_buffer) - exec_lua('return test_register(...)', 0, 'test1', offset_encoding, line_ending) + exec_lua(function() + return _G.test_register(0, 'test1', offset_encoding, line_ending) + end) for _, edit in ipairs(edit_operations) do feed(edit) end - eq(expected_text_changes, exec_lua('return get_events(...)')) - exec_lua("test_unreg = 'test1'") + eq( + expected_text_changes, + exec_lua(function() + return _G.get_events() + end) + ) + exec_lua(function() + _G.test_unreg = 'test1' + end) end describe('incremental synchronization', function() @@ -170,7 +185,7 @@ describe('incremental synchronization', function() } test_edit({ 'a' }, { 'rb' }, expected_text_changes, 'utf-16', '\n') end) - it('deleting a line', function() + it('deleting the first line', function() local expected_text_changes = { { range = { @@ -183,11 +198,49 @@ describe('incremental synchronization', function() line = 1, }, }, - rangeLength = 12, + rangeLength = 6, + text = '', + }, + } + test_edit({ 'hello', 'world' }, { 'ggdd' }, expected_text_changes, 'utf-16', '\n') + end) + it('deleting the last line', function() + local expected_text_changes = { + { + range = { + ['start'] = { + character = 0, + line = 1, + }, + ['end'] = { + character = 0, + line = 2, + }, + }, + rangeLength = 6, + text = '', + }, + } + test_edit({ 'hello', 'world' }, { '2ggdd' }, expected_text_changes, 'utf-16', '\n') + end) + it('deleting all lines', function() + local expected_text_changes = { + { + range = { + ['start'] = { + character = 0, + line = 0, + }, + ['end'] = { + character = 5, + line = 1, + }, + }, + rangeLength = 11, text = '', }, } - test_edit({ 'hello world' }, { 'dd' }, expected_text_changes, 'utf-16', '\n') + test_edit({ 'hello', 'world' }, { 'ggdG' }, expected_text_changes, 'utf-16', '\n') end) it('deleting an empty line', function() local expected_text_changes = { diff --git a/test/functional/plugin/lsp/inlay_hint_spec.lua b/test/functional/plugin/lsp/inlay_hint_spec.lua index d3b5ae0e4e..471f2cc3e8 100644 --- a/test/functional/plugin/lsp/inlay_hint_spec.lua +++ b/test/functional/plugin/lsp/inlay_hint_spec.lua @@ -12,7 +12,8 @@ local api = n.api local clear_notrace = t_lsp.clear_notrace local create_server_definition = t_lsp.create_server_definition -local text = dedent([[ +describe('vim.lsp.inlay_hint', function() + local text = dedent([[ auto add(int a, int b) { return a + b; } int main() { @@ -22,7 +23,7 @@ int main() { } }]]) -local response = [==[ + local response = [==[ [ {"kind":1,"paddingLeft":false,"label":"-> int","position":{"character":22,"line":0},"paddingRight":false}, {"kind":2,"paddingLeft":false,"label":"a:","position":{"character":15,"line":5},"paddingRight":true}, @@ -30,7 +31,7 @@ local response = [==[ ] ]==] -local grid_without_inlay_hints = [[ + local grid_without_inlay_hints = [[ auto add(int a, int b) { return a + b; } | | int main() { | @@ -42,7 +43,7 @@ local grid_without_inlay_hints = [[ | ]] -local grid_with_inlay_hints = [[ + local grid_with_inlay_hints = [[ auto add(int a, int b){1:-> int} { return a + b; } | | int main() { | @@ -54,54 +55,58 @@ local grid_with_inlay_hints = [[ | ]] ---- @type test.functional.ui.screen -local screen -before_each(function() - clear_notrace() - screen = Screen.new(50, 9) - screen:attach() - - exec_lua(create_server_definition) - exec_lua( - [[ - local response = ... - server = _create_server({ - capabilities = { - inlayHintProvider = true, - }, - handlers = { - ['textDocument/inlayHint'] = function(_, _, callback) - callback(nil, vim.json.decode(response)) - end, - } - }) + --- @type test.functional.ui.screen + local screen - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) + --- @type integer + local client_id - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]], - response - ) + --- @type integer + local bufnr - insert(text) - exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]]) - screen:expect({ grid = grid_with_inlay_hints }) -end) + before_each(function() + clear_notrace() + screen = Screen.new(50, 9) + screen:attach() -after_each(function() - api.nvim_exec_autocmds('VimLeavePre', { modeline = false }) -end) + bufnr = n.api.nvim_get_current_buf() + exec_lua(create_server_definition) + client_id = exec_lua(function() + _G.server = _G._create_server({ + capabilities = { + inlayHintProvider = true, + }, + handlers = { + ['textDocument/inlayHint'] = function(_, _, callback) + callback(nil, vim.json.decode(response)) + end, + }, + }) + + return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) + + insert(text) + exec_lua(function() + vim.lsp.inlay_hint.enable(true, { bufnr = bufnr }) + end) + screen:expect({ grid = grid_with_inlay_hints }) + end) + + after_each(function() + api.nvim_exec_autocmds('VimLeavePre', { modeline = false }) + end) -describe('vim.lsp.inlay_hint', function() it('clears inlay hints when sole client detaches', function() - exec_lua([[vim.lsp.stop_client(client_id)]]) + exec_lua(function() + vim.lsp.stop_client(client_id) + end) screen:expect({ grid = grid_without_inlay_hints, unchanged = true }) end) it('does not clear inlay hints when one of several clients detaches', function() - exec_lua([[ - server2 = _create_server({ + local client_id2 = exec_lua(function() + _G.server2 = _G._create_server({ capabilities = { inlayHintProvider = true, }, @@ -109,13 +114,16 @@ describe('vim.lsp.inlay_hint', function() ['textDocument/inlayHint'] = function(_, _, callback) callback(nil, {}) end, - } + }, }) - client2 = vim.lsp.start({ name = 'dummy2', cmd = server2.cmd }) + local client_id2 = vim.lsp.start({ name = 'dummy2', cmd = _G.server2.cmd }) vim.lsp.inlay_hint.enable(true, { bufnr = bufnr }) - ]]) + return client_id2 + end) - exec_lua([[ vim.lsp.stop_client(client2) ]]) + exec_lua(function() + vim.lsp.stop_client(client_id2) + end) screen:expect({ grid = grid_with_inlay_hints, unchanged = true }) end) @@ -123,61 +131,85 @@ describe('vim.lsp.inlay_hint', function() it('validation', function() t.matches( 'enable: expected boolean, got table', - t.pcall_err(exec_lua, [[vim.lsp.inlay_hint.enable({}, { bufnr = bufnr })]]) + t.pcall_err(exec_lua, function() + --- @diagnostic disable-next-line:param-type-mismatch + vim.lsp.inlay_hint.enable({}, { bufnr = bufnr }) + end) ) t.matches( 'enable: expected boolean, got number', - t.pcall_err(exec_lua, [[vim.lsp.inlay_hint.enable(42)]]) + t.pcall_err(exec_lua, function() + --- @diagnostic disable-next-line:param-type-mismatch + vim.lsp.inlay_hint.enable(42) + end) ) t.matches( 'filter: expected table, got number', - t.pcall_err(exec_lua, [[vim.lsp.inlay_hint.enable(true, 42)]]) + t.pcall_err(exec_lua, function() + --- @diagnostic disable-next-line:param-type-mismatch + vim.lsp.inlay_hint.enable(true, 42) + end) ) end) describe('clears/applies inlay hints when passed false/true/nil', function() + local bufnr2 --- @type integer before_each(function() - exec_lua([[ - bufnr2 = vim.api.nvim_create_buf(true, false) - vim.lsp.buf_attach_client(bufnr2, client_id) - vim.api.nvim_win_set_buf(0, bufnr2) - ]]) + bufnr2 = exec_lua(function() + local bufnr2_0 = vim.api.nvim_create_buf(true, false) + vim.lsp.buf_attach_client(bufnr2_0, client_id) + vim.api.nvim_win_set_buf(0, bufnr2_0) + return bufnr2_0 + end) insert(text) - exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr2 })]]) - exec_lua([[vim.api.nvim_win_set_buf(0, bufnr)]]) + exec_lua(function() + vim.lsp.inlay_hint.enable(true, { bufnr = bufnr2 }) + end) + n.api.nvim_win_set_buf(0, bufnr) screen:expect({ grid = grid_with_inlay_hints }) end) it('for one single buffer', function() - exec_lua([[ + exec_lua(function() vim.lsp.inlay_hint.enable(false, { bufnr = bufnr }) vim.api.nvim_win_set_buf(0, bufnr2) - ]]) + end) screen:expect({ grid = grid_with_inlay_hints, unchanged = true }) - exec_lua([[vim.api.nvim_win_set_buf(0, bufnr)]]) + n.api.nvim_win_set_buf(0, bufnr) screen:expect({ grid = grid_without_inlay_hints, unchanged = true }) - exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]]) + exec_lua(function() + vim.lsp.inlay_hint.enable(true, { bufnr = bufnr }) + end) screen:expect({ grid = grid_with_inlay_hints, unchanged = true }) - exec_lua( - [[vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled({ bufnr = bufnr }), { bufnr = bufnr })]] - ) + exec_lua(function() + vim.lsp.inlay_hint.enable( + not vim.lsp.inlay_hint.is_enabled({ bufnr = bufnr }), + { bufnr = bufnr } + ) + end) screen:expect({ grid = grid_without_inlay_hints, unchanged = true }) - exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]]) + exec_lua(function() + vim.lsp.inlay_hint.enable(true, { bufnr = bufnr }) + end) screen:expect({ grid = grid_with_inlay_hints, unchanged = true }) end) it('for all buffers', function() - exec_lua([[vim.lsp.inlay_hint.enable(false)]]) + exec_lua(function() + vim.lsp.inlay_hint.enable(false) + end) screen:expect({ grid = grid_without_inlay_hints, unchanged = true }) - exec_lua([[vim.api.nvim_win_set_buf(0, bufnr2)]]) + n.api.nvim_win_set_buf(0, bufnr2) screen:expect({ grid = grid_without_inlay_hints, unchanged = true }) - exec_lua([[vim.lsp.inlay_hint.enable(true)]]) + exec_lua(function() + vim.lsp.inlay_hint.enable(true) + end) screen:expect({ grid = grid_with_inlay_hints, unchanged = true }) - exec_lua([[vim.api.nvim_win_set_buf(0, bufnr)]]) + n.api.nvim_win_set_buf(0, bufnr) screen:expect({ grid = grid_with_inlay_hints, unchanged = true }) end) end) @@ -198,10 +230,8 @@ describe('vim.lsp.inlay_hint', function() paddingRight = false, } - exec_lua( - [[ - local expected2 = ... - server2 = _create_server({ + exec_lua(function() + _G.server2 = _G._create_server({ capabilities = { inlayHintProvider = true, }, @@ -209,52 +239,139 @@ describe('vim.lsp.inlay_hint', function() ['textDocument/inlayHint'] = function(_, _, callback) callback(nil, { expected2 }) end, - } + }, }) - client2 = vim.lsp.start({ name = 'dummy2', cmd = server2.cmd }) + _G.client2 = vim.lsp.start({ name = 'dummy2', cmd = _G.server2.cmd }) vim.lsp.inlay_hint.enable(true, { bufnr = bufnr }) - ]], - expected2 - ) + end) --- @type vim.lsp.inlay_hint.get.ret - local res = exec_lua([[return vim.lsp.inlay_hint.get()]]) - eq({ - { bufnr = 1, client_id = 1, inlay_hint = expected[1] }, - { bufnr = 1, client_id = 1, inlay_hint = expected[2] }, - { bufnr = 1, client_id = 1, inlay_hint = expected[3] }, - { bufnr = 1, client_id = 2, inlay_hint = expected2 }, - }, res) + eq( + { + { bufnr = 1, client_id = 1, inlay_hint = expected[1] }, + { bufnr = 1, client_id = 1, inlay_hint = expected[2] }, + { bufnr = 1, client_id = 1, inlay_hint = expected[3] }, + { bufnr = 1, client_id = 2, inlay_hint = expected2 }, + }, + exec_lua(function() + return vim.lsp.inlay_hint.get() + end) + ) - --- @type vim.lsp.inlay_hint.get.ret - res = exec_lua([[return vim.lsp.inlay_hint.get({ - range = { - start = { line = 2, character = 10 }, - ["end"] = { line = 2, character = 10 }, + eq( + { + { bufnr = 1, client_id = 2, inlay_hint = expected2 }, }, - })]]) - eq({ - { bufnr = 1, client_id = 2, inlay_hint = expected2 }, - }, res) + exec_lua(function() + return vim.lsp.inlay_hint.get({ + range = { + start = { line = 2, character = 10 }, + ['end'] = { line = 2, character = 10 }, + }, + }) + end) + ) - --- @type vim.lsp.inlay_hint.get.ret - res = exec_lua([[return vim.lsp.inlay_hint.get({ - bufnr = vim.api.nvim_get_current_buf(), - range = { - start = { line = 4, character = 18 }, - ["end"] = { line = 5, character = 17 }, + eq( + { + { bufnr = 1, client_id = 1, inlay_hint = expected[2] }, + { bufnr = 1, client_id = 1, inlay_hint = expected[3] }, }, - })]]) - eq({ - { bufnr = 1, client_id = 1, inlay_hint = expected[2] }, - { bufnr = 1, client_id = 1, inlay_hint = expected[3] }, - }, res) + exec_lua(function() + return vim.lsp.inlay_hint.get({ + bufnr = vim.api.nvim_get_current_buf(), + range = { + start = { line = 4, character = 18 }, + ['end'] = { line = 5, character = 17 }, + }, + }) + end) + ) - --- @type vim.lsp.inlay_hint.get.ret - res = exec_lua([[return vim.lsp.inlay_hint.get({ - bufnr = vim.api.nvim_get_current_buf() + 1, - })]]) - eq({}, res) + eq( + {}, + exec_lua(function() + return vim.lsp.inlay_hint.get({ + bufnr = vim.api.nvim_get_current_buf() + 1, + }) + end) + ) + end) + end) +end) + +describe('Inlay hints handler', function() + local text = dedent([[ +test text + ]]) + + local response = [==[ + [ + { "position": { "line": 0, "character": 0 }, "label": "0" }, + { "position": { "line": 0, "character": 0 }, "label": "1" }, + { "position": { "line": 0, "character": 0 }, "label": "2" }, + { "position": { "line": 0, "character": 0 }, "label": "3" }, + { "position": { "line": 0, "character": 0 }, "label": "4" } + ] + ]==] + + local grid_without_inlay_hints = [[ + test text | + ^ | + | +]] + + local grid_with_inlay_hints = [[ + {1:01234}test text | + ^ | + | +]] + + --- @type test.functional.ui.screen + local screen + + --- @type integer + local client_id + + --- @type integer + local bufnr + + before_each(function() + clear_notrace() + screen = Screen.new(50, 3) + screen:attach() + + exec_lua(create_server_definition) + bufnr = n.api.nvim_get_current_buf() + client_id = exec_lua(function() + _G.server = _G._create_server({ + capabilities = { + inlayHintProvider = true, + }, + handlers = { + ['textDocument/inlayHint'] = function(_, _, callback) + callback(nil, vim.json.decode(response)) + end, + }, + }) + + vim.api.nvim_win_set_buf(0, bufnr) + + return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) + insert(text) + end) + + it('renders hints with same position in received order', function() + exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]]) + screen:expect({ grid = grid_with_inlay_hints }) + exec_lua(function() + vim.lsp.stop_client(client_id) end) + screen:expect({ grid = grid_without_inlay_hints, unchanged = true }) + end) + + after_each(function() + api.nvim_exec_autocmds('VimLeavePre', { modeline = false }) end) end) diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua index 7908c5d2e7..f72aab7e0b 100644 --- a/test/functional/plugin/lsp/semantic_tokens_spec.lua +++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua @@ -25,7 +25,7 @@ after_each(function() end) describe('semantic token highlighting', function() - local screen + local screen --- @type test.functional.ui.screen before_each(function() screen = Screen.new(40, 16) screen:attach() @@ -84,10 +84,8 @@ describe('semantic token highlighting', function() before_each(function() exec_lua(create_server_definition) - exec_lua( - [[ - local legend, response, edit_response = ... - server = _create_server({ + exec_lua(function() + _G.server = _G._create_server({ capabilities = { semanticTokensProvider = { full = { delta = true }, @@ -101,24 +99,19 @@ describe('semantic token highlighting', function() ['textDocument/semanticTokens/full/delta'] = function(_, _, callback) callback(nil, vim.fn.json_decode(edit_response)) end, - } + }, }) - ]], - legend, - response, - edit_response - ) + end, legend, response, edit_response) end) it('buffer is highlighted when attached', function() - exec_lua([[ - bufnr = vim.api.nvim_get_current_buf() + insert(text) + exec_lua(function() + local bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) vim.bo[bufnr].filetype = 'some-filetype' - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]]) - - insert(text) + vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) screen:expect { grid = [[ @@ -141,23 +134,20 @@ describe('semantic token highlighting', function() end) it('use LspTokenUpdate and highlight_token', function() - exec_lua([[ - vim.api.nvim_create_autocmd("LspTokenUpdate", { + insert(text) + exec_lua(function() + vim.api.nvim_create_autocmd('LspTokenUpdate', { callback = function(args) - local token = args.data.token - if token.type == "function" and token.modifiers.declaration then - vim.lsp.semantic_tokens.highlight_token( - token, args.buf, args.data.client_id, "Macro" - ) + local token = args.data.token --- @type STTokenRange + if token.type == 'function' and token.modifiers.declaration then + vim.lsp.semantic_tokens.highlight_token(token, args.buf, args.data.client_id, 'Macro') end end, }) - bufnr = vim.api.nvim_get_current_buf() + local bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]]) - - insert(text) + vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) screen:expect { grid = [[ @@ -180,18 +170,23 @@ describe('semantic token highlighting', function() end) it('buffer is unhighlighted when client is detached', function() - exec_lua([[ - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]]) - insert(text) - exec_lua([[ + local bufnr = n.api.nvim_get_current_buf() + local client_id = exec_lua(function() + vim.api.nvim_win_set_buf(0, bufnr) + local client_id = vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + vim.wait(1000, function() + return #_G.server.messages > 1 + end) + return client_id + end) + + exec_lua(function() + --- @diagnostic disable-next-line:duplicate-set-field vim.notify = function() end vim.lsp.buf_detach_client(bufnr, client_id) - ]]) + end) screen:expect { grid = [[ @@ -216,18 +211,19 @@ describe('semantic token highlighting', function() it( 'buffer is highlighted and unhighlighted when semantic token highlighting is started and stopped', function() - exec_lua([[ - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]]) + local bufnr = n.api.nvim_get_current_buf() + local client_id = exec_lua(function() + vim.api.nvim_win_set_buf(0, bufnr) + return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) insert(text) - exec_lua([[ - vim.notify = function() end - vim.lsp.semantic_tokens.stop(bufnr, client_id) - ]]) + exec_lua(function() + --- @diagnostic disable-next-line:duplicate-set-field + vim.notify = function() end + vim.lsp.semantic_tokens.stop(bufnr, client_id) + end) screen:expect { grid = [[ @@ -248,9 +244,9 @@ describe('semantic token highlighting', function() ]], } - exec_lua([[ - vim.lsp.semantic_tokens.start(bufnr, client_id) - ]]) + exec_lua(function() + vim.lsp.semantic_tokens.start(bufnr, client_id) + end) screen:expect { grid = [[ @@ -274,18 +270,17 @@ describe('semantic token highlighting', function() ) it('highlights start and stop when using "0" for current buffer', function() - exec_lua([[ - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]]) + local client_id = exec_lua(function() + return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) insert(text) - exec_lua([[ + exec_lua(function() + --- @diagnostic disable-next-line:duplicate-set-field vim.notify = function() end vim.lsp.semantic_tokens.stop(0, client_id) - ]]) + end) screen:expect { grid = [[ @@ -306,9 +301,9 @@ describe('semantic token highlighting', function() ]], } - exec_lua([[ + exec_lua(function() vim.lsp.semantic_tokens.start(0, client_id) - ]]) + end) screen:expect { grid = [[ @@ -331,13 +326,10 @@ describe('semantic token highlighting', function() end) it('buffer is re-highlighted when force refreshed', function() - exec_lua([[ - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]]) - insert(text) + exec_lua(function() + vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) screen:expect { grid = [[ @@ -358,9 +350,9 @@ describe('semantic token highlighting', function() ]], } - exec_lua([[ - vim.lsp.semantic_tokens.force_refresh(bufnr) - ]]) + exec_lua(function() + vim.lsp.semantic_tokens.force_refresh() + end) screen:expect { grid = [[ @@ -384,7 +376,9 @@ describe('semantic token highlighting', function() local messages = exec_lua('return server.messages') local token_request_count = 0 - for _, message in ipairs(messages) do + for _, message in + ipairs(messages --[[@as {method:string,params:table}[] ]]) + do assert(message.method ~= 'textDocument/semanticTokens/full/delta', 'delta request received') if message.method == 'textDocument/semanticTokens/full' then token_request_count = token_request_count + 1 @@ -394,31 +388,29 @@ describe('semantic token highlighting', function() end) it('destroys the highlighter if the buffer is deleted', function() - exec_lua([[ - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]]) + exec_lua(function() + vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) insert(text) - local highlighters = exec_lua([[ - vim.api.nvim_buf_delete(bufnr, { force = true }) - local semantic_tokens = vim.lsp.semantic_tokens - return semantic_tokens.__STHighlighter.active - ]]) - - eq({}, highlighters) + eq( + {}, + exec_lua(function() + local bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_delete(bufnr, { force = true }) + return vim.lsp.semantic_tokens.__STHighlighter.active + end) + ) end) it('updates highlights with delta request on buffer change', function() - exec_lua([[ - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]]) - insert(text) + + exec_lua(function() + vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) + screen:expect { grid = [[ #include <iostream> | @@ -459,45 +451,49 @@ describe('semantic token highlighting', function() end) it('prevents starting semantic token highlighting with invalid conditions', function() - exec_lua([[ - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start_client({ name = 'dummy', cmd = server.cmd }) - notifications = {} - vim.notify = function(...) table.insert(notifications, 1, {...}) end - ]]) - eq(false, exec_lua('return vim.lsp.buf_is_attached(bufnr, client_id)')) + local client_id = exec_lua(function() + _G.notifications = {} + --- @diagnostic disable-next-line:duplicate-set-field + vim.notify = function(...) + table.insert(_G.notifications, 1, { ... }) + end + return vim.lsp.start_client({ name = 'dummy', cmd = _G.server.cmd }) + end) + eq(false, exec_lua('return vim.lsp.buf_is_attached(0, ...)', client_id)) insert(text) - local notifications = exec_lua([[ - vim.lsp.semantic_tokens.start(bufnr, client_id) - return notifications - ]]) - matches('%[LSP%] Client with id %d not attached to buffer %d', notifications[1][1]) - - notifications = exec_lua([[ - vim.lsp.semantic_tokens.start(bufnr, client_id + 1) - return notifications - ]]) - matches('%[LSP%] No client with id %d', notifications[1][1]) + matches( + '%[LSP%] Client with id %d not attached to buffer %d', + exec_lua(function() + vim.lsp.semantic_tokens.start(0, client_id) + return _G.notifications[1][1] + end) + ) + + matches( + '%[LSP%] No client with id %d', + exec_lua(function() + vim.lsp.semantic_tokens.start(0, client_id + 1) + return _G.notifications[1][1] + end) + ) end) it( 'opt-out: does not activate semantic token highlighting if disabled in client attach', function() - exec_lua([[ - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ + local client_id = exec_lua(function() + return vim.lsp.start({ name = 'dummy', - cmd = server.cmd, - on_attach = vim.schedule_wrap(function(client, bufnr) + cmd = _G.server.cmd, + --- @param client vim.lsp.Client + on_attach = vim.schedule_wrap(function(client, _bufnr) client.server_capabilities.semanticTokensProvider = nil end), }) - ]]) - eq(true, exec_lua('return vim.lsp.buf_is_attached(bufnr, client_id)')) + end) + eq(true, exec_lua('return vim.lsp.buf_is_attached(0, ...)', client_id)) insert(text) @@ -520,13 +516,18 @@ describe('semantic token highlighting', function() ]], } - local notifications = exec_lua([[ - local notifications = {} - vim.notify = function(...) table.insert(notifications, 1, {...}) end - vim.lsp.semantic_tokens.start(bufnr, client_id) - return notifications - ]]) - eq('[LSP] Server does not support semantic tokens', notifications[1][1]) + eq( + '[LSP] Server does not support semantic tokens', + exec_lua(function() + local notifications = {} + --- @diagnostic disable-next-line:duplicate-set-field + vim.notify = function(...) + table.insert(notifications, 1, { ... }) + end + vim.lsp.semantic_tokens.start(0, client_id) + return notifications[1][1] + end) + ) screen:expect { grid = [[ @@ -551,28 +552,32 @@ describe('semantic token highlighting', function() ) it('ignores null responses from the server', function() - exec_lua([[ - local legend, response, edit_response = ... - server2 = _create_server({ + local client_id = exec_lua(function() + _G.server2 = _G._create_server({ capabilities = { semanticTokensProvider = { full = { delta = false }, }, }, handlers = { + --- @param callback function ['textDocument/semanticTokens/full'] = function(_, _, callback) callback(nil, nil) end, - ['textDocument/semanticTokens/full/delta'] = function() + --- @param callback function + ['textDocument/semanticTokens/full/delta'] = function(_, _, callback) callback(nil, nil) end, - } + }, }) - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server2.cmd }) - ]]) - eq(true, exec_lua('return vim.lsp.buf_is_attached(bufnr, client_id)')) + return vim.lsp.start({ name = 'dummy', cmd = _G.server2.cmd }) + end) + eq( + true, + exec_lua(function() + return vim.lsp.buf_is_attached(0, client_id) + end) + ) insert(text) @@ -597,10 +602,9 @@ describe('semantic token highlighting', function() end) it('does not send delta requests if not supported by server', function() - exec_lua( - [[ - local legend, response, edit_response = ... - server2 = _create_server({ + insert(text) + exec_lua(function() + _G.server2 = _G._create_server({ capabilities = { semanticTokensProvider = { full = { delta = false }, @@ -614,18 +618,11 @@ describe('semantic token highlighting', function() ['textDocument/semanticTokens/full/delta'] = function(_, _, callback) callback(nil, vim.fn.json_decode(edit_response)) end, - } + }, }) - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server2.cmd }) - ]], - legend, - response, - edit_response - ) + return vim.lsp.start({ name = 'dummy', cmd = _G.server2.cmd }) + end) - insert(text) screen:expect { grid = [[ #include <iostream> | @@ -669,7 +666,9 @@ describe('semantic token highlighting', function() } local messages = exec_lua('return server2.messages') local token_request_count = 0 - for _, message in ipairs(messages) do + for _, message in + ipairs(messages --[[@as {method:string,params:table}[] ]]) + do assert(message.method ~= 'textDocument/semanticTokens/full/delta', 'delta request received') if message.method == 'textDocument/semanticTokens/full' then token_request_count = token_request_count + 1 @@ -1064,10 +1063,8 @@ b = "as"]], }) do it(test.it, function() exec_lua(create_server_definition) - exec_lua( - [[ - local legend, resp = ... - server = _create_server({ + local client_id = exec_lua(function(legend, resp) + _G.server = _G._create_server({ capabilities = { semanticTokensProvider = { full = { delta = false }, @@ -1078,25 +1075,22 @@ b = "as"]], ['textDocument/semanticTokens/full'] = function(_, _, callback) callback(nil, vim.fn.json_decode(resp)) end, - } + }, }) - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]], - test.legend, - test.response - ) + return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end, test.legend, test.response) insert(test.text) test.expected_screen() - local highlights = exec_lua([[ - local semantic_tokens = vim.lsp.semantic_tokens - return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights - ]]) - eq(test.expected, highlights) + eq( + test.expected, + exec_lua(function() + local bufnr = vim.api.nvim_get_current_buf() + return vim.lsp.semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights + end) + ) end) end end) @@ -1449,11 +1443,11 @@ int main() }, }) do it(test.it, function() + local bufnr = n.api.nvim_get_current_buf() + insert(test.text1) exec_lua(create_server_definition) - exec_lua( - [[ - local legend, resp1, resp2 = ... - server = _create_server({ + local client_id = exec_lua(function(legend, resp1, resp2) + _G.server = _G._create_server({ capabilities = { semanticTokensProvider = { full = { delta = true }, @@ -1467,54 +1461,44 @@ int main() ['textDocument/semanticTokens/full/delta'] = function(_, _, callback) callback(nil, vim.fn.json_decode(resp2)) end, - } + }, }) - bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })) -- speed up vim.api.nvim_buf_set_lines calls by changing debounce to 10 for these tests - semantic_tokens = vim.lsp.semantic_tokens vim.schedule(function() - semantic_tokens.stop(bufnr, client_id) - semantic_tokens.start(bufnr, client_id, { debounce = 10 }) + vim.lsp.semantic_tokens.stop(bufnr, client_id) + vim.lsp.semantic_tokens.start(bufnr, client_id, { debounce = 10 }) end) - ]], - test.legend, - test.response1, - test.response2 - ) - - insert(test.text1) + return client_id + end, test.legend, test.response1, test.response2) test.expected_screen1() - local highlights = exec_lua([[ - return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights - ]]) - - eq(test.expected1, highlights) + eq( + test.expected1, + exec_lua(function() + return vim.lsp.semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights + end) + ) if test.edit then feed(test.edit) else - exec_lua( - [[ - local text = ... - vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, vim.fn.split(text, "\n")) + exec_lua(function(text) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, vim.fn.split(text, '\n')) vim.wait(15) -- wait for debounce - ]], - test.text2 - ) + end, test.text2) end test.expected_screen2() - highlights = exec_lua([[ - return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights - ]]) - - eq(test.expected2, highlights) + eq( + test.expected2, + exec_lua(function() + return vim.lsp.semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights + end) + ) end) end end) diff --git a/test/functional/plugin/lsp/testutil.lua b/test/functional/plugin/lsp/testutil.lua index 3430a1e1a3..a36cbac568 100644 --- a/test/functional/plugin/lsp/testutil.lua +++ b/test/functional/plugin/lsp/testutil.lua @@ -21,8 +21,35 @@ function M.clear_notrace() } end -M.create_server_definition = [[ - function _create_server(opts) +M.create_tcp_echo_server = function() + --- Create a TCP server that echos the first message it receives. + --- @param host string + ---@return uv.uv_tcp_t + ---@return integer + ---@return fun():string|nil + function _G._create_tcp_server(host) + local uv = vim.uv + local server = assert(uv.new_tcp()) + local init = nil + server:bind(host, 0) + server:listen(127, function(err) + assert(not err, err) + local socket = assert(uv.new_tcp()) + server:accept(socket) + socket:read_start(require('vim.lsp.rpc').create_read_loop(function(body) + init = body + socket:close() + end)) + end) + local port = server:getsockname().port + return server, port, function() + return init + end + end +end + +M.create_server_definition = function() + function _G._create_server(opts) opts = opts or {} local server = {} server.messages = {} @@ -42,7 +69,7 @@ M.create_server_definition = [[ handler(method, params, callback) elseif method == 'initialize' then callback(nil, { - capabilities = opts.capabilities or {} + capabilities = opts.capabilities or {}, }) elseif method == 'shutdown' then callback(nil, nil) @@ -54,7 +81,7 @@ M.create_server_definition = [[ function srv.notify(method, params) table.insert(server.messages, { method = method, - params = params + params = params, }) if method == 'exit' then dispatchers.on_exit(0, 15) @@ -74,63 +101,62 @@ M.create_server_definition = [[ return server end -]] +end -- Fake LSP server. M.fake_lsp_code = 'test/functional/fixtures/fake-lsp-server.lua' M.fake_lsp_logfile = 'Xtest-fake-lsp.log' local function fake_lsp_server_setup(test_name, timeout_ms, options, settings) - exec_lua( - [=[ - lsp = require('vim.lsp') - local test_name, fake_lsp_code, fake_lsp_logfile, timeout, options, settings = ... - TEST_RPC_CLIENT_ID = lsp.start_client { + exec_lua(function(fake_lsp_code, fake_lsp_logfile, timeout) + options = options or {} + settings = settings or {} + _G.lsp = require('vim.lsp') + _G.TEST_RPC_CLIENT_ID = _G.lsp.start_client { cmd_env = { - NVIM_LOG_FILE = fake_lsp_logfile; - NVIM_LUA_NOTRACK = "1"; - NVIM_APPNAME = "nvim_lsp_test"; - }; + NVIM_LOG_FILE = fake_lsp_logfile, + NVIM_LUA_NOTRACK = '1', + NVIM_APPNAME = 'nvim_lsp_test', + }, cmd = { - vim.v.progpath, '-l', fake_lsp_code, test_name, tostring(timeout), - }; + vim.v.progpath, + '-l', + fake_lsp_code, + test_name, + tostring(timeout), + }, handlers = setmetatable({}, { - __index = function(t, method) + __index = function(_t, _method) return function(...) return vim.rpcrequest(1, 'handler', ...) end - end; - }); - workspace_folders = {{ + end, + }), + workspace_folders = { + { uri = 'file://' .. vim.uv.cwd(), name = 'test_folder', - }}; - before_init = function(params, config) + }, + }, + before_init = function(_params, _config) vim.schedule(function() - vim.rpcrequest(1, "setup") + vim.rpcrequest(1, 'setup') end) end, on_init = function(client, result) - TEST_RPC_CLIENT = client - vim.rpcrequest(1, "init", result) - end; + _G.TEST_RPC_CLIENT = client + vim.rpcrequest(1, 'init', result) + end, flags = { - allow_incremental_sync = options.allow_incremental_sync or false; - debounce_text_changes = options.debounce_text_changes or 0; - }; - settings = settings; + allow_incremental_sync = options.allow_incremental_sync or false, + debounce_text_changes = options.debounce_text_changes or 0, + }, + settings = settings, on_exit = function(...) - vim.rpcnotify(1, "exit", ...) - end; + vim.rpcnotify(1, 'exit', ...) + end, } - ]=], - test_name, - M.fake_lsp_code, - M.fake_lsp_logfile, - timeout_ms or 1e3, - options or {}, - settings or {} - ) + end, M.fake_lsp_code, M.fake_lsp_logfile, timeout_ms or 1e3) end --- @class test.lsp.Config @@ -160,18 +186,13 @@ function M.test_rpc_server(config) -- Workaround for not being able to yield() inside __index for Lua 5.1 :( -- Otherwise I would just return the value here. return function(...) - return exec_lua( - [=[ - local name = ... - if type(TEST_RPC_CLIENT[name]) == 'function' then - return TEST_RPC_CLIENT[name](select(2, ...)) - else - return TEST_RPC_CLIENT[name] - end - ]=], - name, - ... - ) + return exec_lua(function(...) + if type(_G.TEST_RPC_CLIENT[name]) == 'function' then + return _G.TEST_RPC_CLIENT[name](...) + else + return _G.TEST_RPC_CLIENT[name] + end + end, ...) end end, }) diff --git a/test/functional/plugin/lsp/utils_spec.lua b/test/functional/plugin/lsp/utils_spec.lua index 6c6dec0667..64d58eeffd 100644 --- a/test/functional/plugin/lsp/utils_spec.lua +++ b/test/functional/plugin/lsp/utils_spec.lua @@ -11,21 +11,11 @@ describe('vim.lsp.util', function() describe('stylize_markdown', function() local stylize_markdown = function(content, opts) - return exec_lua( - [[ - local bufnr = vim.uri_to_bufnr("file:///fake/uri") + return exec_lua(function() + local bufnr = vim.uri_to_bufnr('file:///fake/uri') vim.fn.bufload(bufnr) - - local args = { ... } - local content = args[1] - local opts = args[2] - local stripped_content = vim.lsp.util.stylize_markdown(bufnr, content, opts) - - return stripped_content - ]], - content, - opts - ) + return vim.lsp.util.stylize_markdown(bufnr, content, opts) + end) end it('code fences', function() @@ -93,9 +83,64 @@ describe('vim.lsp.util', function() end) end) - describe('normalize_markdown', function() + it('convert_input_to_markdown_lines', function() + local r = exec_lua(function() + local hover_data = { + kind = 'markdown', + value = '```lua\nfunction vim.api.nvim_buf_attach(buffer: integer, send_buffer: boolean, opts: vim.api.keyset.buf_attach)\n -> boolean\n```\n\n---\n\n Activates buffer-update events. Example:\n\n\n\n ```lua\n events = {}\n vim.api.nvim_buf_attach(0, false, {\n on_lines = function(...)\n table.insert(events, {...})\n end,\n })\n ```\n\n\n @see `nvim_buf_detach()`\n @see `api-buffer-updates-lua`\n@*param* `buffer` — Buffer handle, or 0 for current buffer\n\n\n\n@*param* `send_buffer` — True if whole buffer.\n Else the first notification will be `nvim_buf_changedtick_event`.\n\n\n@*param* `opts` — Optional parameters.\n\n - on_lines: Lua callback. Args:\n - the string "lines"\n - buffer handle\n - b:changedtick\n@*return* — False if foo;\n\n otherwise True.\n\n@see foo\n@see bar\n\n', + } + return vim.lsp.util.convert_input_to_markdown_lines(hover_data) + end) + local expected = { + '```lua', + 'function vim.api.nvim_buf_attach(buffer: integer, send_buffer: boolean, opts: vim.api.keyset.buf_attach)', + ' -> boolean', + '```', + '', + '---', + '', + ' Activates buffer-update events. Example:', + '', + '', + '', + ' ```lua', + ' events = {}', + ' vim.api.nvim_buf_attach(0, false, {', + ' on_lines = function(...)', + ' table.insert(events, {...})', + ' end,', + ' })', + ' ```', + '', + '', + ' @see `nvim_buf_detach()`', + ' @see `api-buffer-updates-lua`', + '', + -- For each @param/@return: #30695 + -- - Separate each by one empty line. + -- - Remove all other blank lines. + '@*param* `buffer` — Buffer handle, or 0 for current buffer', + '', + '@*param* `send_buffer` — True if whole buffer.', + ' Else the first notification will be `nvim_buf_changedtick_event`.', + '', + '@*param* `opts` — Optional parameters.', + ' - on_lines: Lua callback. Args:', + ' - the string "lines"', + ' - buffer handle', + ' - b:changedtick', + '', + '@*return* — False if foo;', + ' otherwise True.', + '@see foo', + '@see bar', + } + eq(expected, r) + end) + + describe('_normalize_markdown', function() it('collapses consecutive blank lines', function() - local result = exec_lua [[ + local result = exec_lua(function() local lines = { 'foo', '', @@ -103,25 +148,25 @@ describe('vim.lsp.util', function() '', 'bar', '', - 'baz' + 'baz', } return vim.lsp.util._normalize_markdown(lines) - ]] + end) local expected = { 'foo', '', 'bar', '', 'baz' } eq(expected, result) end) it('removes preceding and trailing empty lines', function() - local result = exec_lua [[ + local result = exec_lua(function() local lines = { '', 'foo', 'bar', '', - '' + '', } return vim.lsp.util._normalize_markdown(lines) - ]] + end) local expected = { 'foo', 'bar' } eq(expected, result) end) @@ -129,19 +174,14 @@ describe('vim.lsp.util', function() describe('make_floating_popup_options', function() local function assert_anchor(anchor_bias, expected_anchor) - local opts = exec_lua( - [[ - local args = { ... } - local anchor_bias = args[1] - return vim.lsp.util.make_floating_popup_options(30, 10, { anchor_bias = anchor_bias }) - ]], - anchor_bias - ) + local opts = exec_lua(function() + return vim.lsp.util.make_floating_popup_options(30, 10, { anchor_bias = anchor_bias }) + end) eq(expected_anchor, string.sub(opts.anchor, 1, 1)) end - local screen + local screen --- @type test.functional.ui.screen before_each(function() n.clear() screen = Screen.new(80, 80) @@ -221,9 +261,9 @@ describe('vim.lsp.util', function() end) it('bordered window truncates dimensions correctly', function() - local opts = exec_lua([[ + local opts = exec_lua(function() return vim.lsp.util.make_floating_popup_options(100, 100, { border = 'single' }) - ]]) + end) eq(56, opts.height) end) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index c95a96baca..9956fdf628 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -33,12 +33,38 @@ local create_server_definition = t_lsp.create_server_definition local fake_lsp_code = t_lsp.fake_lsp_code local fake_lsp_logfile = t_lsp.fake_lsp_logfile local test_rpc_server = t_lsp.test_rpc_server +local create_tcp_echo_server = t_lsp.create_tcp_echo_server local function get_buf_option(name, bufnr) - bufnr = bufnr or 'BUFFER' - return exec_lua( - string.format("return vim.api.nvim_get_option_value('%s', { buf = %s })", name, bufnr) + return exec_lua(function() + bufnr = bufnr or _G.BUFFER + return vim.api.nvim_get_option_value(name, { buf = bufnr }) + end) +end + +local function make_edit(y_0, x_0, y_1, x_1, text) + return { + range = { + start = { line = y_0, character = x_0 }, + ['end'] = { line = y_1, character = x_1 }, + }, + newText = type(text) == 'table' and table.concat(text, '\n') or (text or ''), + } +end + +--- @param edits [integer, integer, integer, integer, string|string[]][] +--- @param encoding? string +local function apply_text_edits(edits, encoding) + local edits1 = vim.tbl_map( + --- @param edit [integer, integer, integer, integer, string|string[]] + function(edit) + return make_edit(unpack(edit)) + end, + edits ) + exec_lua(function() + vim.lsp.util.apply_text_edits(edits1, 1, encoding or 'utf-16') + end) end -- TODO(justinmk): hangs on Windows https://github.com/neovim/neovim/pull/11837 @@ -46,111 +72,156 @@ if skip(is_os('win')) then return end -teardown(function() - os.remove(fake_lsp_logfile) -end) - describe('LSP', function() before_each(function() clear_notrace() - - -- Run an instance of nvim on the file which contains our "scripts". - -- Pass TEST_NAME to pick the script. - local test_name = 'basic_init' - exec_lua( - [=[ - lsp = require('vim.lsp') - local test_name, fake_lsp_code, fake_lsp_logfile = ... - function test__start_client() - return lsp.start_client { - cmd_env = { - NVIM_LOG_FILE = fake_lsp_logfile; - NVIM_APPNAME = "nvim_lsp_test"; - }; - cmd = { - vim.v.progpath, '-l', fake_lsp_code, test_name; - }; - workspace_folders = {{ - uri = 'file://' .. vim.uv.cwd(), - name = 'test_folder', - }}; - } - end - TEST_CLIENT1 = test__start_client() - ]=], - test_name, - fake_lsp_code, - fake_lsp_logfile - ) end) after_each(function() + stop() + exec_lua('lsp.stop_client(lsp.get_clients(), true)') api.nvim_exec_autocmds('VimLeavePre', { modeline = false }) - -- exec_lua("lsp.stop_all_clients(true)") + end) + + teardown(function() + os.remove(fake_lsp_logfile) end) describe('server_name specified', function() + before_each(function() + -- Run an instance of nvim on the file which contains our "scripts". + -- Pass TEST_NAME to pick the script. + local test_name = 'basic_init' + exec_lua(function() + _G.lsp = require('vim.lsp') + function _G.test__start_client() + return vim.lsp.start_client { + cmd_env = { + NVIM_LOG_FILE = fake_lsp_logfile, + NVIM_APPNAME = 'nvim_lsp_test', + }, + cmd = { + vim.v.progpath, + '-l', + fake_lsp_code, + test_name, + }, + workspace_folders = { + { + uri = 'file://' .. vim.uv.cwd(), + name = 'test_folder', + }, + }, + } + end + _G.TEST_CLIENT1 = _G.test__start_client() + end) + end) + it('start_client(), stop_client()', function() retry(nil, 4000, function() - eq(1, exec_lua('return #lsp.get_clients()')) + eq( + 1, + exec_lua(function() + return #vim.lsp.get_clients() + end) + ) end) eq( 2, - exec_lua([[ - TEST_CLIENT2 = test__start_client() - return TEST_CLIENT2 - ]]) + exec_lua(function() + _G.TEST_CLIENT2 = _G.test__start_client() + return _G.TEST_CLIENT2 + end) ) eq( 3, - exec_lua([[ - TEST_CLIENT3 = test__start_client() - return TEST_CLIENT3 - ]]) + exec_lua(function() + _G.TEST_CLIENT3 = _G.test__start_client() + return _G.TEST_CLIENT3 + end) ) retry(nil, 4000, function() - eq(3, exec_lua('return #lsp.get_clients()')) + eq( + 3, + exec_lua(function() + return #vim.lsp.get_clients() + end) + ) end) - eq(false, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1) == nil')) - eq(false, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1).is_stopped()')) - exec_lua('return lsp.get_client_by_id(TEST_CLIENT1).stop()') + eq( + false, + exec_lua(function() + return vim.lsp.get_client_by_id(_G.TEST_CLIENT1) == nil + end) + ) + eq( + false, + exec_lua(function() + return vim.lsp.get_client_by_id(_G.TEST_CLIENT1).is_stopped() + end) + ) + exec_lua(function() + return vim.lsp.get_client_by_id(_G.TEST_CLIENT1).stop() + end) retry(nil, 4000, function() - eq(2, exec_lua('return #lsp.get_clients()')) + eq( + 2, + exec_lua(function() + return #vim.lsp.get_clients() + end) + ) end) - eq(true, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1) == nil')) + eq( + true, + exec_lua(function() + return vim.lsp.get_client_by_id(_G.TEST_CLIENT1) == nil + end) + ) - exec_lua('lsp.stop_client({TEST_CLIENT2, TEST_CLIENT3})') + exec_lua(function() + vim.lsp.stop_client({ _G.TEST_CLIENT2, _G.TEST_CLIENT3 }) + end) retry(nil, 4000, function() - eq(0, exec_lua('return #lsp.get_clients()')) + eq( + 0, + exec_lua(function() + return #vim.lsp.get_clients() + end) + ) end) end) it('stop_client() also works on client objects', function() - exec_lua([[ - TEST_CLIENT2 = test__start_client() - TEST_CLIENT3 = test__start_client() - ]]) + exec_lua(function() + _G.TEST_CLIENT2 = _G.test__start_client() + _G.TEST_CLIENT3 = _G.test__start_client() + end) retry(nil, 4000, function() - eq(3, exec_lua('return #lsp.get_clients()')) + eq( + 3, + exec_lua(function() + return #vim.lsp.get_clients() + end) + ) end) -- Stop all clients. - exec_lua('lsp.stop_client(lsp.get_clients())') + exec_lua(function() + vim.lsp.stop_client(vim.lsp.get_clients()) + end) retry(nil, 4000, function() - eq(0, exec_lua('return #lsp.get_clients()')) + eq( + 0, + exec_lua(function() + return #vim.lsp.get_clients() + end) + ) end) end) end) -end) -describe('LSP', function() describe('basic_init test', function() - after_each(function() - stop() - exec_lua('lsp.stop_client(lsp.get_clients(), true)') - api.nvim_exec_autocmds('VimLeavePre', { modeline = false }) - end) - it('should run correctly', function() local expected_handlers = { { NIL, {}, { method = 'test', client_id = 1 } }, @@ -221,28 +292,28 @@ describe('LSP', function() function() clear() exec_lua(create_server_definition) - local result = exec_lua([[ - local server = _create_server({ - capabilities = { - positionEncoding = "utf-8" - }, - }) + local result = exec_lua(function() + local server = _G._create_server({ + capabilities = { + positionEncoding = 'utf-8', + }, + }) - local client_id = vim.lsp.start({ - name = 'dummy', - cmd = server.cmd, - }) + local client_id = vim.lsp.start({ + name = 'dummy', + cmd = server.cmd, + }) - if not client_id then - return 'vim.lsp.start did not return client_id' - end + if not client_id then + return 'vim.lsp.start did not return client_id' + end - local client = vim.lsp.get_client_by_id(client_id) - if not client then - return 'No client found with id ' .. client_id - end - return client.offset_encoding - ]]) + local client = vim.lsp.get_client_by_id(client_id) + if not client then + return 'No client found with id ' .. client_id + end + return client.offset_encoding + end) eq('utf-8', result) end ) @@ -255,7 +326,7 @@ describe('LSP', function() return end local expected_handlers = { - { NIL, {}, { method = 'shutdown', bufnr = 1, client_id = 1 } }, + { NIL, {}, { method = 'shutdown', bufnr = 1, client_id = 1, version = 0 } }, { NIL, {}, { method = 'test', client_id = 1 } }, } test_rpc_server { @@ -285,14 +356,24 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_finish', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - ]] - eq(true, exec_lua('return lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)')) - eq(true, exec_lua('return lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID)')) - exec_lua [[ - vim.api.nvim_command(BUFFER.."bwipeout") - ]] + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + end) + eq( + true, + exec_lua(function() + return vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + end) + ) + eq( + true, + exec_lua(function() + return vim.lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + end) + ) + exec_lua(function() + vim.cmd(_G.BUFFER .. 'bwipeout') + end) end, on_init = function(_client) client = _client @@ -305,8 +386,15 @@ describe('LSP', function() on_handler = function(err, result, ctx) eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') if ctx.method == 'finish' then - exec_lua('return lsp.buf_detach_client(BUFFER, TEST_RPC_CLIENT_ID)') - eq(false, exec_lua('return lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID)')) + exec_lua(function() + return vim.lsp.buf_detach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + end) + eq( + false, + exec_lua(function() + return vim.lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + end) + ) client.stop() end end, @@ -318,31 +406,38 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_init', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) vim.api.nvim_create_autocmd('LspAttach', { callback = function(args) - local client = vim.lsp.get_client_by_id(args.data.client_id) - vim.g.lsp_attached = client.name + local client0 = assert(vim.lsp.get_client_by_id(args.data.client_id)) + vim.g.lsp_attached = client0.name end, }) vim.api.nvim_create_autocmd('LspDetach', { callback = function(args) - local client = vim.lsp.get_client_by_id(args.data.client_id) - vim.g.lsp_detached = client.name + local client0 = assert(vim.lsp.get_client_by_id(args.data.client_id)) + vim.g.lsp_detached = client0.name end, }) - ]] + end) end, on_init = function(_client) client = _client - eq(true, exec_lua('return lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)')) + eq( + true, + exec_lua(function() + return vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + end) + ) client.notify('finish') end, on_handler = function(_, _, ctx) if ctx.method == 'finish' then eq('basic_init', api.nvim_get_var('lsp_attached')) - exec_lua('return lsp.buf_detach_client(BUFFER, TEST_RPC_CLIENT_ID)') + exec_lua(function() + return vim.lsp.buf_detach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + end) eq('basic_init', api.nvim_get_var('lsp_detached')) client.stop() end @@ -356,10 +451,10 @@ describe('LSP', function() test_name = 'set_defaults_all_capabilities', on_init = function(_client) client = _client - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID) - ]] + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + end) end, on_handler = function(_, _, ctx) if ctx.method == 'test' then @@ -369,13 +464,13 @@ describe('LSP', function() eq('', get_buf_option('keywordprg')) eq( true, - exec_lua [[ - local keymap - vim.api.nvim_buf_call(BUFFER, function() - keymap = vim.fn.maparg("K", "n", false, true) + exec_lua(function() + local keymap --- @type table<string,any> + vim._with({ buf = _G.BUFFER }, function() + keymap = vim.fn.maparg('K', 'n', false, true) + end) + return keymap.callback == vim.lsp.buf.hover end) - return keymap.callback == vim.lsp.buf.hover - ]] ) client.stop() end @@ -386,13 +481,13 @@ describe('LSP', function() eq('', get_buf_option('formatexpr')) eq( '', - exec_lua [[ - local keymap - vim.api.nvim_buf_call(BUFFER, function() - keymap = vim.fn.maparg("K", "n", false, false) + exec_lua(function() + local keymap --- @type string + vim._with({ buf = _G.BUFFER }, function() + keymap = vim.fn.maparg('K', 'n', false, false) + end) + return keymap end) - return keymap - ]] ) end, } @@ -400,40 +495,42 @@ describe('LSP', function() it('should overwrite options set by ftplugins', function() local client --- @type vim.lsp.Client + local BUFFER_1 --- @type integer + local BUFFER_2 --- @type integer test_rpc_server { test_name = 'set_defaults_all_capabilities', on_init = function(_client) client = _client - exec_lua [[ + exec_lua(function() vim.api.nvim_command('filetype plugin on') BUFFER_1 = vim.api.nvim_create_buf(false, true) BUFFER_2 = vim.api.nvim_create_buf(false, true) vim.api.nvim_set_option_value('filetype', 'man', { buf = BUFFER_1 }) vim.api.nvim_set_option_value('filetype', 'xml', { buf = BUFFER_2 }) - ]] + end) -- Sanity check to ensure that some values are set after setting filetype. - eq("v:lua.require'man'.goto_tag", get_buf_option('tagfunc', 'BUFFER_1')) - eq('xmlcomplete#CompleteTags', get_buf_option('omnifunc', 'BUFFER_2')) - eq('xmlformat#Format()', get_buf_option('formatexpr', 'BUFFER_2')) + eq("v:lua.require'man'.goto_tag", get_buf_option('tagfunc', BUFFER_1)) + eq('xmlcomplete#CompleteTags', get_buf_option('omnifunc', BUFFER_2)) + eq('xmlformat#Format()', get_buf_option('formatexpr', BUFFER_2)) - exec_lua [[ - lsp.buf_attach_client(BUFFER_1, TEST_RPC_CLIENT_ID) - lsp.buf_attach_client(BUFFER_2, TEST_RPC_CLIENT_ID) - ]] + exec_lua(function() + vim.lsp.buf_attach_client(BUFFER_1, _G.TEST_RPC_CLIENT_ID) + vim.lsp.buf_attach_client(BUFFER_2, _G.TEST_RPC_CLIENT_ID) + end) end, on_handler = function(_, _, ctx) if ctx.method == 'test' then - eq('v:lua.vim.lsp.tagfunc', get_buf_option('tagfunc', 'BUFFER_1')) - eq('v:lua.vim.lsp.omnifunc', get_buf_option('omnifunc', 'BUFFER_2')) - eq('v:lua.vim.lsp.formatexpr()', get_buf_option('formatexpr', 'BUFFER_2')) + eq('v:lua.vim.lsp.tagfunc', get_buf_option('tagfunc', BUFFER_1)) + eq('v:lua.vim.lsp.omnifunc', get_buf_option('omnifunc', BUFFER_2)) + eq('v:lua.vim.lsp.formatexpr()', get_buf_option('formatexpr', BUFFER_2)) client.stop() end end, on_exit = function(_, _) - eq('', get_buf_option('tagfunc', 'BUFFER_1')) - eq('', get_buf_option('omnifunc', 'BUFFER_2')) - eq('', get_buf_option('formatexpr', 'BUFFER_2')) + eq('', get_buf_option('tagfunc', BUFFER_1)) + eq('', get_buf_option('omnifunc', BUFFER_2)) + eq('', get_buf_option('formatexpr', BUFFER_2)) end, } end) @@ -444,13 +541,13 @@ describe('LSP', function() test_name = 'set_defaults_all_capabilities', on_init = function(_client) client = _client - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_set_option_value('tagfunc', 'tfu', { buf = BUFFER }) - vim.api.nvim_set_option_value('omnifunc', 'ofu', { buf = BUFFER }) - vim.api.nvim_set_option_value('formatexpr', 'fex', { buf = BUFFER }) - lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID) - ]] + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_set_option_value('tagfunc', 'tfu', { buf = _G.BUFFER }) + vim.api.nvim_set_option_value('omnifunc', 'ofu', { buf = _G.BUFFER }) + vim.api.nvim_set_option_value('formatexpr', 'fex', { buf = _G.BUFFER }) + vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + end) end, on_handler = function(_, _, ctx) if ctx.method == 'test' then @@ -471,19 +568,19 @@ describe('LSP', function() it('should detach buffer on bufwipe', function() clear() exec_lua(create_server_definition) - local result = exec_lua([[ - local server = _create_server() + local result = exec_lua(function() + local server = _G._create_server() local bufnr = vim.api.nvim_create_buf(false, true) vim.api.nvim_set_current_buf(bufnr) local detach_called = false - vim.api.nvim_create_autocmd("LspDetach", { + vim.api.nvim_create_autocmd('LspDetach', { callback = function() detach_called = true - end + end, }) local client_id = vim.lsp.start({ name = 'detach-dummy', cmd = server.cmd }) - assert(client_id, "lsp.start must return client_id") - local client = vim.lsp.get_client_by_id(client_id) + assert(client_id, 'lsp.start must return client_id') + local client = assert(vim.lsp.get_client_by_id(client_id)) local num_attached_before = vim.tbl_count(client.attached_buffers) vim.api.nvim_buf_delete(bufnr, { force = true }) local num_attached_after = vim.tbl_count(client.attached_buffers) @@ -494,7 +591,7 @@ describe('LSP', function() num_attached_after = num_attached_after, detach_called = detach_called, } - ]]) + end) eq(true, result ~= nil, 'exec_lua must return result') eq(1, result.num_attached_before) eq(0, result.num_attached_after) @@ -504,30 +601,62 @@ describe('LSP', function() it('should not re-attach buffer if it was deleted in on_init #28575', function() clear() exec_lua(create_server_definition) - exec_lua([[ - local server = _create_server({ + exec_lua(function() + local server = _G._create_server({ handlers = { - initialize = function(method, params, callback) + initialize = function(_, _, callback) vim.schedule(function() callback(nil, { capabilities = {} }) end) - end - } + end, + }, }) local bufnr = vim.api.nvim_create_buf(false, true) local on_init_called = false - local client_id = vim.lsp.start({ + local client_id = assert(vim.lsp.start({ name = 'detach-dummy', cmd = server.cmd, on_init = function() vim.api.nvim_buf_delete(bufnr, {}) on_init_called = true - end - }) + end, + })) vim.lsp.buf_attach_client(bufnr, client_id) - local ok = vim.wait(1000, function() return on_init_called end) - assert(ok, "on_init was not called") - ]]) + local ok = vim.wait(1000, function() + return on_init_called + end) + assert(ok, 'on_init was not called') + end) + end) + + it('should allow on_lines + nvim_buf_delete during LSP initialization #28575', function() + clear() + exec_lua(create_server_definition) + exec_lua(function() + local initialized = false + local server = _G._create_server({ + handlers = { + initialize = function(_, _, callback) + vim.schedule(function() + callback(nil, { capabilities = {} }) + initialized = true + end) + end, + }, + }) + local bufnr = vim.api.nvim_create_buf(false, true) + vim.api.nvim_set_current_buf(bufnr) + vim.lsp.start({ + name = 'detach-dummy', + cmd = server.cmd, + }) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'hello' }) + vim.api.nvim_buf_delete(bufnr, {}) + local ok = vim.wait(1000, function() + return initialized + end) + assert(ok, 'lsp did not initialize') + end) end) it('client should return settings via workspace/configuration handler', function() @@ -560,19 +689,25 @@ describe('LSP', function() on_handler = function(err, result, ctx) eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') if ctx.method == 'start' then - exec_lua([=[ - local client = vim.lsp.get_client_by_id(TEST_RPC_CLIENT_ID) - client.settings = { - testSetting1 = true; - testSetting2 = false; - test = {Setting3 = 'nested' }; - }]=]) + exec_lua(function() + local client0 = vim.lsp.get_client_by_id(_G.TEST_RPC_CLIENT_ID) + client0.settings = { + testSetting1 = true, + testSetting2 = false, + test = { Setting3 = 'nested' }, + } + end) end if ctx.method == 'workspace/configuration' then local server_result = exec_lua( - [=[ + [[ local method, params = ... - return require'vim.lsp.handlers'['workspace/configuration'](err, params, {method=method, client_id=TEST_RPC_CLIENT_ID})]=], + return require 'vim.lsp.handlers'['workspace/configuration']( + err, + params, + { method = method, client_id = _G.TEST_RPC_CLIENT_ID } + ) + ]], ctx.method, result ) @@ -584,6 +719,7 @@ describe('LSP', function() end, } end) + it( 'workspace/configuration returns NIL per section if client was started without config.settings', function() @@ -594,15 +730,19 @@ describe('LSP', function() c.stop() end, on_setup = function() - result = exec_lua [[ - local result = { - items = { - {section = 'foo'}, - {section = 'bar'}, + result = exec_lua(function() + local result0 = { + items = { + { section = 'foo' }, + { section = 'bar' }, + }, } - } - return vim.lsp.handlers['workspace/configuration'](nil, result, {client_id=TEST_RPC_CLIENT_ID}) - ]] + return vim.lsp.handlers['workspace/configuration']( + nil, + result0, + { client_id = _G.TEST_RPC_CLIENT_ID } + ) + end) end, } eq({ NIL, NIL }, result) @@ -617,7 +757,9 @@ describe('LSP', function() test_name = 'basic_check_capabilities', on_init = function(client) client.stop() - local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + local full_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full + end) eq(full_kind, client.server_capabilities().textDocumentSync.change) eq({ includeText = false }, client.server_capabilities().textDocumentSync.save) eq(false, client.server_capabilities().codeLensProvider) @@ -650,11 +792,11 @@ describe('LSP', function() on_handler = function(err, result, ctx) eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') if ctx.method == 'start' then - exec_lua([=[ - BUFFER = vim.api.nvim_get_current_buf() - lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID) - vim.api.nvim_exec_autocmds('BufWritePost', { buffer = BUFFER, modeline = false }) - ]=]) + exec_lua(function() + _G.BUFFER = vim.api.nvim_get_current_buf() + vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + vim.api.nvim_exec_autocmds('BufWritePost', { buffer = _G.BUFFER, modeline = false }) + end) else client.stop() end @@ -665,21 +807,21 @@ describe('LSP', function() it('BufWritePre does not send notifications if server lacks willSave capabilities', function() clear() exec_lua(create_server_definition) - local messages = exec_lua([[ - local server = _create_server({ + local messages = exec_lua(function() + local server = _G._create_server({ capabilities = { textDocumentSync = { willSave = false, willSaveWaitUntil = false, - } + }, }, }) - local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd })) local buf = vim.api.nvim_get_current_buf() vim.api.nvim_exec_autocmds('BufWritePre', { buffer = buf, modeline = false }) vim.lsp.stop_client(client_id) return server.messages - ]]) + end) eq(4, #messages) eq('initialize', messages[1].method) eq('initialized', messages[2].method) @@ -690,13 +832,13 @@ describe('LSP', function() it('BufWritePre sends willSave / willSaveWaitUntil, applies textEdits', function() clear() exec_lua(create_server_definition) - local result = exec_lua([[ - local server = _create_server({ + local result = exec_lua(function() + local server = _G._create_server({ capabilities = { textDocumentSync = { willSave = true, willSaveWaitUntil = true, - } + }, }, handlers = { ['textDocument/willSaveWaitUntil'] = function(_, _, callback) @@ -705,21 +847,21 @@ describe('LSP', function() start = { line = 0, character = 0 }, ['end'] = { line = 0, character = 0 }, }, - newText = 'Hello' + newText = 'Hello', } - callback(nil, { text_edit, }) - end + callback(nil, { text_edit }) + end, }, }) local buf = vim.api.nvim_get_current_buf() - local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd })) vim.api.nvim_exec_autocmds('BufWritePre', { buffer = buf, modeline = false }) vim.lsp.stop_client(client_id) return { messages = server.messages, - lines = vim.api.nvim_buf_get_lines(buf, 0, -1, true) + lines = vim.api.nvim_buf_get_lines(buf, 0, -1, true), } - ]]) + end) local messages = result.messages eq('textDocument/willSave', messages[3].method) eq('textDocument/willSaveWaitUntil', messages[4].method) @@ -745,20 +887,16 @@ describe('LSP', function() eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') if ctx.method == 'start' then local tmpfile_old = tmpname() - local tmpfile_new = tmpname() - os.remove(tmpfile_new) - exec_lua( - [=[ - local oldname, newname = ... - BUFFER = vim.api.nvim_get_current_buf() - vim.api.nvim_buf_set_name(BUFFER, oldname) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, true, {"help me"}) - lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID) - vim.api.nvim_buf_call(BUFFER, function() vim.cmd('saveas ' .. newname) end) - ]=], - tmpfile_old, - tmpfile_new - ) + local tmpfile_new = tmpname(false) + exec_lua(function() + _G.BUFFER = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_set_name(_G.BUFFER, tmpfile_old) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, true, { 'help me' }) + vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + vim._with({ buf = _G.BUFFER }, function() + vim.cmd('saveas ' .. tmpfile_new) + end) + end) else client.stop() end @@ -784,12 +922,12 @@ describe('LSP', function() on_handler = function(err, result, ctx) eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') if ctx.method == 'start' then - exec_lua([=[ - BUFFER = vim.api.nvim_get_current_buf() - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, true, {"help me"}) - lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID) - vim.api.nvim_exec_autocmds('BufWritePost', { buffer = BUFFER, modeline = false }) - ]=]) + exec_lua(function() + _G.BUFFER = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, true, { 'help me' }) + vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + vim.api.nvim_exec_autocmds('BufWritePost', { buffer = _G.BUFFER, modeline = false }) + end) else client.stop() end @@ -843,16 +981,18 @@ describe('LSP', function() test_rpc_server { test_name = 'capabilities_for_client_supports_method', on_setup = function() - exec_lua([=[ - BUFFER = vim.api.nvim_get_current_buf() - lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID) - vim.lsp.handlers['textDocument/typeDefinition'] = function() end - vim.cmd(BUFFER.."bwipeout") - ]=]) + exec_lua(function() + _G.BUFFER = vim.api.nvim_get_current_buf() + vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID) + vim.lsp.handlers['textDocument/typeDefinition'] = function() end + vim.cmd(_G.BUFFER .. 'bwipeout') + end) end, on_init = function(client) client.stop() - exec_lua('vim.lsp.buf.type_definition()') + exec_lua(function() + vim.lsp.buf.type_definition() + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -873,13 +1013,15 @@ describe('LSP', function() test_rpc_server { test_name = 'capabilities_for_client_supports_method', on_setup = function() - exec_lua([=[ + exec_lua(function() vim.lsp.handlers['textDocument/typeDefinition'] = function() end - ]=]) + end) end, on_init = function(client) client.stop() - exec_lua('vim.lsp.buf.type_definition()') + exec_lua(function() + vim.lsp.buf.type_definition() + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -920,7 +1062,11 @@ describe('LSP', function() it('should forward ContentModified to callback', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { { code = -32801 }, NIL, { method = 'error_code_test', bufnr = 1, client_id = 1 } }, + { + { code = -32801 }, + NIL, + { method = 'error_code_test', bufnr = 1, client_id = 1, version = 0 }, + }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -950,7 +1096,7 @@ describe('LSP', function() it('should track pending requests to the language server', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } }, + { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 0 } }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -958,7 +1104,9 @@ describe('LSP', function() on_init = function(_client) client = _client client.request('slow_request') - local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=]) + local request = exec_lua(function() + return _G.TEST_RPC_CLIENT.requests[2] + end) eq('slow_request', request.method) eq('pending', request.type) client.notify('release') @@ -971,8 +1119,10 @@ describe('LSP', function() on_handler = function(err, _, ctx) eq(table.remove(expected_handlers), { err, {}, ctx }, 'expected handler') if ctx.method == 'slow_request' then - local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=]) - eq(NIL, request) + local request = exec_lua(function() + return _G.TEST_RPC_CLIENT.requests[2] + end) + eq(nil, request) client.notify('finish') end if ctx.method == 'finish' then @@ -993,7 +1143,9 @@ describe('LSP', function() client = _client client.request('slow_request') client.cancel_request(2) - local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=]) + local request = exec_lua(function() + return _G.TEST_RPC_CLIENT.requests[2] + end) eq('slow_request', request.method) eq('cancel', request.type) client.notify('release') @@ -1005,8 +1157,10 @@ describe('LSP', function() end, on_handler = function(err, _, ctx) eq(table.remove(expected_handlers), { err, {}, ctx }, 'expected handler') - local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=]) - eq(NIL, request) + local request = exec_lua(function() + return _G.TEST_RPC_CLIENT.requests[2] + end) + eq(nil, request) if ctx.method == 'finish' then client.stop() end @@ -1017,7 +1171,7 @@ describe('LSP', function() it('should clear pending and cancel requests on reply', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } }, + { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 0 } }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -1025,11 +1179,15 @@ describe('LSP', function() on_init = function(_client) client = _client client.request('slow_request') - local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=]) + local request = exec_lua(function() + return _G.TEST_RPC_CLIENT.requests[2] + end) eq('slow_request', request.method) eq('pending', request.type) client.cancel_request(2) - request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=]) + request = exec_lua(function() + return _G.TEST_RPC_CLIENT.requests[2] + end) eq('slow_request', request.method) eq('cancel', request.type) client.notify('release') @@ -1042,8 +1200,10 @@ describe('LSP', function() on_handler = function(err, _, ctx) eq(table.remove(expected_handlers), { err, {}, ctx }, 'expected handler') if ctx.method == 'slow_request' then - local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=]) - eq(NIL, request) + local request = exec_lua(function() + return _G.TEST_RPC_CLIENT.requests[2] + end) + eq(nil, request) client.notify('finish') end if ctx.method == 'finish' then @@ -1056,7 +1216,7 @@ describe('LSP', function() it('should trigger LspRequest autocmd when requests table changes', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } }, + { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 0 } }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -1098,21 +1258,23 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_finish', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - assert(TEST_RPC_CLIENT_ID == 1) - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - assert(lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID)) - vim.cmd(BUFFER.."bwipeout") - ]] + assert(_G.TEST_RPC_CLIENT_ID == 1) + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + assert(vim.lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + vim.cmd(_G.BUFFER .. 'bwipeout') + end) end, on_init = function(_client) client = _client - local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + local full_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full + end) eq(full_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) client.notify('finish') @@ -1140,25 +1302,30 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_check_buffer_open', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - ]] - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + end) + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_init = function(_client) client = _client - local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + local full_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full + end) eq(full_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID), "Already attached, returns true") - ]] + exec_lua(function() + assert( + vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID), + 'Already attached, returns true' + ) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1186,22 +1353,24 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_check_buffer_open', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - ]] + end) end, on_init = function(_client) client = _client - local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + local full_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full + end) eq(full_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1229,22 +1398,24 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_check_buffer_open_and_change', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - ]] + end) end, on_init = function(_client) client = _client - local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + local full_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full + end) eq(full_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1252,11 +1423,11 @@ describe('LSP', function() end, on_handler = function(err, result, ctx) if ctx.method == 'start' then - exec_lua [[ - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "boop"; + exec_lua(function() + vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, { + 'boop', }) - ]] + end) client.notify('finish') end eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') @@ -1277,23 +1448,25 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_check_buffer_open_and_change_noeol', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - vim.bo[BUFFER].eol = false - ]] + vim.bo[_G.BUFFER].eol = false + end) end, on_init = function(_client) client = _client - local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + local full_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full + end) eq(full_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1301,11 +1474,11 @@ describe('LSP', function() end, on_handler = function(err, result, ctx) if ctx.method == 'start' then - exec_lua [[ - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "boop"; + exec_lua(function() + vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, { + 'boop', }) - ]] + end) client.notify('finish') end eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') @@ -1336,6 +1509,7 @@ describe('LSP', function() }, bufnr = 2, client_id = 1, + version = 0, }, }, { NIL, {}, { method = 'start', client_id = 1 } }, @@ -1344,21 +1518,21 @@ describe('LSP', function() test_rpc_server { test_name = 'inlay_hint', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - vim.bo[BUFFER].eol = false - ]] + vim.bo[_G.BUFFER].eol = false + end) end, on_init = function(_client) client = _client eq(true, client.supports_method('textDocument/inlayHint')) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1366,9 +1540,9 @@ describe('LSP', function() end, on_handler = function(err, result, ctx) if ctx.method == 'start' then - exec_lua [[ - vim.lsp.inlay_hint.enable(true, { bufnr = BUFFER }) - ]] + exec_lua(function() + vim.lsp.inlay_hint.enable(true, { bufnr = _G.BUFFER }) + end) end if ctx.method == 'textDocument/inlayHint' then client.notify('finish') @@ -1394,23 +1568,24 @@ describe('LSP', function() allow_incremental_sync = true, }, on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - ]] + end) end, on_init = function(_client) client = _client - local sync_kind = - exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental") + local sync_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Incremental + end) eq(sync_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1418,11 +1593,11 @@ describe('LSP', function() end, on_handler = function(err, result, ctx) if ctx.method == 'start' then - exec_lua [[ - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "123boop"; + exec_lua(function() + vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, { + '123boop', }) - ]] + end) client.notify('finish') end eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') @@ -1432,6 +1607,7 @@ describe('LSP', function() end, } end) + it('should check the body and didChange incremental with debounce', function() local expected_handlers = { { NIL, {}, { method = 'shutdown', client_id = 1 } }, @@ -1446,23 +1622,24 @@ describe('LSP', function() debounce_text_changes = 5, }, on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - ]] + end) end, on_init = function(_client) client = _client - local sync_kind = - exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental") + local sync_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Incremental + end) eq(sync_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1470,11 +1647,11 @@ describe('LSP', function() end, on_handler = function(err, result, ctx) if ctx.method == 'start' then - exec_lua [[ - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "123boop"; + exec_lua(function() + vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, { + '123boop', }) - ]] + end) client.notify('finish') end eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') @@ -1496,23 +1673,24 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_check_buffer_open_and_change_incremental_editing', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - ]] + end) end, on_init = function(_client) client = _client - local sync_kind = - exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental") + local sync_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Incremental + end) eq(sync_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1541,22 +1719,24 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_check_buffer_open_and_change_multi', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - ]] + end) end, on_init = function(_client) client = _client - local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + local sync_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full + end) eq(sync_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1564,14 +1744,14 @@ describe('LSP', function() end, on_handler = function(err, result, ctx) if ctx.method == 'start' then - exec_lua [[ - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "321"; + exec_lua(function() + vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, { + '321', }) - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "boop"; + vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, { + 'boop', }) - ]] + end) client.notify('finish') end eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') @@ -1592,22 +1772,24 @@ describe('LSP', function() test_rpc_server { test_name = 'basic_check_buffer_open_and_change_multi_and_close', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - ]] + end) end, on_init = function(_client) client = _client - local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full") + local sync_kind = exec_lua(function() + return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full + end) eq(sync_kind, client.server_capabilities().textDocumentSync.change) eq(true, client.server_capabilities().textDocumentSync.openClose) - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1615,15 +1797,15 @@ describe('LSP', function() end, on_handler = function(err, result, ctx) if ctx.method == 'start' then - exec_lua [[ - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "321"; + exec_lua(function() + vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, { + '321', }) - vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, { - "boop"; + vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, { + 'boop', }) - vim.api.nvim_command(BUFFER.."bwipeout") - ]] + vim.api.nvim_command(_G.BUFFER .. 'bwipeout') + end) client.notify('finish') end eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler') @@ -1679,19 +1861,19 @@ describe('LSP', function() test_rpc_server { test_name = 'decode_nil', on_setup = function() - exec_lua [[ - BUFFER = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, { - "testing"; - "123"; + exec_lua(function() + _G.BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, { + 'testing', + '123', }) - ]] + end) end, on_init = function(_client) client = _client - exec_lua [[ - assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)) - ]] + exec_lua(function() + assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)) + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -1706,22 +1888,58 @@ describe('LSP', function() } end) end) -end) -describe('LSP', function() - before_each(function() - clear_notrace() - end) + describe('apply vscode text_edits', function() + it('single replace', function() + insert('012345678901234567890123456789') + apply_text_edits({ + { 0, 3, 0, 6, { 'Hello' } }, + }) + eq({ '012Hello678901234567890123456789' }, buf_lines(1)) + end) - local function make_edit(y_0, x_0, y_1, x_1, text) - return { - range = { - start = { line = y_0, character = x_0 }, - ['end'] = { line = y_1, character = x_1 }, - }, - newText = type(text) == 'table' and table.concat(text, '\n') or (text or ''), - } - end + it('two replaces', function() + insert('012345678901234567890123456789') + apply_text_edits({ + { 0, 3, 0, 6, { 'Hello' } }, + { 0, 6, 0, 9, { 'World' } }, + }) + eq({ '012HelloWorld901234567890123456789' }, buf_lines(1)) + end) + + it('same start pos insert are kept in order', function() + insert('012345678901234567890123456789') + apply_text_edits({ + { 0, 3, 0, 3, { 'World' } }, + { 0, 3, 0, 3, { 'Hello' } }, + }) + eq({ '012WorldHello345678901234567890123456789' }, buf_lines(1)) + end) + + it('same start pos insert and replace are kept in order', function() + insert('012345678901234567890123456789') + apply_text_edits({ + { 0, 3, 0, 3, { 'World' } }, + { 0, 3, 0, 3, { 'Hello' } }, + { 0, 3, 0, 8, { 'No' } }, + }) + eq({ '012WorldHelloNo8901234567890123456789' }, buf_lines(1)) + end) + + it('multiline', function() + exec_lua(function() + vim.api.nvim_buf_set_lines(1, 0, 0, true, { ' {', ' "foo": "bar"', ' }' }) + end) + eq({ ' {', ' "foo": "bar"', ' }', '' }, buf_lines(1)) + apply_text_edits({ + { 0, 0, 3, 0, { '' } }, + { 3, 0, 3, 0, { '{\n' } }, + { 3, 0, 3, 0, { ' "foo": "bar"\n' } }, + { 3, 0, 3, 0, { '}\n' } }, + }) + eq({ '{', ' "foo": "bar"', '}', '' }, buf_lines(1)) + end) + end) describe('apply_text_edits', function() before_each(function() @@ -1732,14 +1950,14 @@ describe('LSP', function() Fourth line of text aÌŠ Ã¥ ɧ æ±‰è¯ â†¥ 🤦 🦄]])) end) + it('applies simple edits', function() - local edits = { - make_edit(0, 0, 0, 0, { '123' }), - make_edit(1, 0, 1, 1, { '2' }), - make_edit(2, 0, 2, 2, { '3' }), - make_edit(3, 2, 3, 4, { '' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 0, 0, { '123' } }, + { 1, 0, 1, 1, { '2' } }, + { 2, 0, 2, 2, { '3' } }, + { 3, 2, 3, 4, { '' } }, + }) eq({ '123First line of text', '2econd line of text', @@ -1748,18 +1966,18 @@ describe('LSP', function() 'aÌŠ Ã¥ ɧ æ±‰è¯ â†¥ 🤦 🦄', }, buf_lines(1)) end) + it('applies complex edits', function() - local edits = { - make_edit(0, 0, 0, 0, { '', '12' }), - make_edit(0, 0, 0, 0, { '3', 'foo' }), - make_edit(0, 1, 0, 1, { 'bar', '123' }), - make_edit(0, #'First ', 0, #'First line of text', { 'guy' }), - make_edit(1, 0, 1, #'Second', { 'baz' }), - make_edit(2, #'Th', 2, #'Third', { 'e next' }), - make_edit(3, #'', 3, #'Fourth', { 'another line of text', 'before this' }), - make_edit(3, #'Fourth', 3, #'Fourth line of text', { '!' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 0, 0, { '', '12' } }, + { 0, 0, 0, 0, { '3', 'foo' } }, + { 0, 1, 0, 1, { 'bar', '123' } }, + { 0, #'First ', 0, #'First line of text', { 'guy' } }, + { 1, 0, 1, #'Second', { 'baz' } }, + { 2, #'Th', 2, #'Third', { 'e next' } }, + { 3, #'', 3, #'Fourth', { 'another line of text', 'before this' } }, + { 3, #'Fourth', 3, #'Fourth line of text', { '!' } }, + }) eq({ '', '123', @@ -1772,18 +1990,18 @@ describe('LSP', function() 'aÌŠ Ã¥ ɧ æ±‰è¯ â†¥ 🤦 🦄', }, buf_lines(1)) end) + it('applies complex edits (reversed range)', function() - local edits = { - make_edit(0, 0, 0, 0, { '', '12' }), - make_edit(0, 0, 0, 0, { '3', 'foo' }), - make_edit(0, 1, 0, 1, { 'bar', '123' }), - make_edit(0, #'First line of text', 0, #'First ', { 'guy' }), - make_edit(1, #'Second', 1, 0, { 'baz' }), - make_edit(2, #'Third', 2, #'Th', { 'e next' }), - make_edit(3, #'Fourth', 3, #'', { 'another line of text', 'before this' }), - make_edit(3, #'Fourth line of text', 3, #'Fourth', { '!' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 0, 0, { '', '12' } }, + { 0, 0, 0, 0, { '3', 'foo' } }, + { 0, 1, 0, 1, { 'bar', '123' } }, + { 0, #'First line of text', 0, #'First ', { 'guy' } }, + { 1, #'Second', 1, 0, { 'baz' } }, + { 2, #'Third', 2, #'Th', { 'e next' } }, + { 3, #'Fourth', 3, #'', { 'another line of text', 'before this' } }, + { 3, #'Fourth line of text', 3, #'Fourth', { '!' } }, + }) eq({ '', '123', @@ -1796,11 +2014,11 @@ describe('LSP', function() 'aÌŠ Ã¥ ɧ æ±‰è¯ â†¥ 🤦 🦄', }, buf_lines(1)) end) + it('applies non-ASCII characters edits', function() - local edits = { - make_edit(4, 3, 4, 4, { 'ä' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 4, 3, 4, 4, { 'ä' } }, + }) eq({ 'First line of text', 'Second line of text', @@ -1809,11 +2027,11 @@ describe('LSP', function() 'aÌŠ ä ɧ æ±‰è¯ â†¥ 🤦 🦄', }, buf_lines(1)) end) + it('applies text edits at the end of the document', function() - local edits = { - make_edit(5, 0, 5, 0, 'foobar'), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 5, 0, 5, 0, 'foobar' }, + }) eq({ 'First line of text', 'Second line of text', @@ -1823,12 +2041,12 @@ describe('LSP', function() 'foobar', }, buf_lines(1)) end) + it('applies multiple text edits at the end of the document', function() - local edits = { - make_edit(4, 0, 5, 0, ''), - make_edit(5, 0, 5, 0, 'foobar'), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 4, 0, 5, 0, '' }, + { 5, 0, 5, 0, 'foobar' }, + }) eq({ 'First line of text', 'Second line of text', @@ -1837,62 +2055,56 @@ describe('LSP', function() 'foobar', }, buf_lines(1)) end) + it('it restores marks', function() - local edits = { - make_edit(1, 0, 2, 5, 'foobar'), - make_edit(4, 0, 5, 0, 'barfoo'), - } eq(true, api.nvim_buf_set_mark(1, 'a', 2, 1, {})) - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 2, 5, 'foobar' }, + { 4, 0, 5, 0, 'barfoo' }, + }) eq({ 'First line of text', 'foobar line of text', 'Fourth line of text', 'barfoo', }, buf_lines(1)) - local mark = api.nvim_buf_get_mark(1, 'a') - eq({ 2, 1 }, mark) + eq({ 2, 1 }, api.nvim_buf_get_mark(1, 'a')) end) it('it restores marks to last valid col', function() - local edits = { - make_edit(1, 0, 2, 15, 'foobar'), - make_edit(4, 0, 5, 0, 'barfoo'), - } eq(true, api.nvim_buf_set_mark(1, 'a', 2, 10, {})) - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 2, 15, 'foobar' }, + { 4, 0, 5, 0, 'barfoo' }, + }) eq({ 'First line of text', 'foobarext', 'Fourth line of text', 'barfoo', }, buf_lines(1)) - local mark = api.nvim_buf_get_mark(1, 'a') - eq({ 2, 9 }, mark) + eq({ 2, 9 }, api.nvim_buf_get_mark(1, 'a')) end) it('it restores marks to last valid line', function() - local edits = { - make_edit(1, 0, 4, 5, 'foobar'), - make_edit(4, 0, 5, 0, 'barfoo'), - } eq(true, api.nvim_buf_set_mark(1, 'a', 4, 1, {})) - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 4, 5, 'foobar' }, + { 4, 0, 5, 0, 'barfoo' }, + }) eq({ 'First line of text', 'foobaro', }, buf_lines(1)) - local mark = api.nvim_buf_get_mark(1, 'a') - eq({ 2, 1 }, mark) + eq({ 2, 1 }, api.nvim_buf_get_mark(1, 'a')) end) describe('cursor position', function() it("don't fix the cursor if the range contains the cursor", function() api.nvim_win_set_cursor(0, { 2, 6 }) - local edits = { - make_edit(1, 0, 1, 19, 'Second line of text'), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 1, 19, 'Second line of text' }, + }) eq({ 'First line of text', 'Second line of text', @@ -1905,11 +2117,10 @@ describe('LSP', function() it('fix the cursor to the valid col if the content was removed', function() api.nvim_win_set_cursor(0, { 2, 6 }) - local edits = { - make_edit(1, 0, 1, 6, ''), - make_edit(1, 6, 1, 19, ''), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 1, 6, '' }, + { 1, 6, 1, 19, '' }, + }) eq({ 'First line of text', '', @@ -1922,11 +2133,10 @@ describe('LSP', function() it('fix the cursor to the valid row if the content was removed', function() api.nvim_win_set_cursor(0, { 2, 6 }) - local edits = { - make_edit(1, 0, 1, 6, ''), - make_edit(0, 18, 5, 0, ''), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 1, 6, '' }, + { 0, 18, 5, 0, '' }, + }) eq({ 'First line of text', }, buf_lines(1)) @@ -1935,10 +2145,9 @@ describe('LSP', function() it('fix the cursor row', function() api.nvim_win_set_cursor(0, { 3, 0 }) - local edits = { - make_edit(1, 0, 2, 0, ''), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 0, 2, 0, '' }, + }) eq({ 'First line of text', 'Third line of text', @@ -1953,10 +2162,9 @@ describe('LSP', function() api.nvim_buf_set_lines(1, -1, -1, true, { '' }) api.nvim_win_set_cursor(0, { 2, 11 }) - local edits = { - make_edit(1, 7, 1, 11, ''), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 1, 7, 1, 11, '' }, + }) eq({ 'First line of text', 'Second of text', @@ -1970,10 +2178,9 @@ describe('LSP', function() it('fix the cursor row and col', function() api.nvim_win_set_cursor(0, { 2, 12 }) - local edits = { - make_edit(0, 11, 1, 12, ''), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 11, 1, 12, '' }, + }) eq({ 'First line of text', 'Third line of text', @@ -1986,24 +2193,23 @@ describe('LSP', function() describe('with LSP end line after what Vim considers to be the end line', function() it('applies edits when the last linebreak is considered a new line', function() - local edits = { - make_edit(0, 0, 5, 0, { 'All replaced' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 5, 0, { 'All replaced' } }, + }) eq({ 'All replaced' }, buf_lines(1)) end) + it("applies edits when the end line is 2 larger than vim's", function() - local edits = { - make_edit(0, 0, 6, 0, { 'All replaced' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 6, 0, { 'All replaced' } }, + }) eq({ 'All replaced' }, buf_lines(1)) end) + it('applies edits with a column offset', function() - local edits = { - make_edit(0, 0, 5, 2, { 'All replaced' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16') + apply_text_edits({ + { 0, 0, 5, 2, { 'All replaced' } }, + }) eq({ 'All replaced' }, buf_lines(1)) end) end) @@ -2015,38 +2221,38 @@ describe('LSP', function() Test line one Test line two 21 char]])) end) + describe('with LSP end column out of bounds and start column at 0', function() it('applies edits at the end of the buffer', function() - local edits = { - make_edit(0, 0, 1, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-8') + apply_text_edits({ + { 0, 0, 1, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' } }, + }, 'utf-8') eq({ '#include "whatever.h"', '#include <algorithm>' }, buf_lines(1)) end) + it('applies edits in the middle of the buffer', function() - local edits = { - make_edit(0, 0, 0, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-8') + apply_text_edits({ + { 0, 0, 0, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' } }, + }, 'utf-8') eq( { '#include "whatever.h"', '#include <algorithm>', 'Test line two 21 char' }, buf_lines(1) ) end) end) + describe('with LSP end column out of bounds and start column NOT at 0', function() it('applies edits at the end of the buffer', function() - local edits = { - make_edit(0, 2, 1, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-8') + apply_text_edits({ + { 0, 2, 1, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' } }, + }, 'utf-8') eq({ 'Te#include "whatever.h"', '#include <algorithm>' }, buf_lines(1)) end) + it('applies edits in the middle of the buffer', function() - local edits = { - make_edit(0, 2, 0, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' }), - } - exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-8') + apply_text_edits({ + { 0, 2, 0, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' } }, + }, 'utf-8') eq( { 'Te#include "whatever.h"', '#include <algorithm>', 'Test line two 21 char' }, buf_lines(1) @@ -2057,6 +2263,7 @@ describe('LSP', function() describe('apply_text_document_edit', function() local target_bufnr --- @type integer + local text_document_edit = function(editVersion) return { edits = { @@ -2068,50 +2275,43 @@ describe('LSP', function() }, } end + before_each(function() - target_bufnr = exec_lua [[ - local bufnr = vim.uri_to_bufnr("file:///fake/uri") - local lines = {"1st line of text", "2nd line of è¯text"} + target_bufnr = exec_lua(function() + local bufnr = vim.uri_to_bufnr('file:///fake/uri') + local lines = { '1st line of text', '2nd line of è¯text' } vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) return bufnr - ]] + end) end) + it('correctly goes ahead with the edit if all is normal', function() - exec_lua("vim.lsp.util.apply_text_document_edit(..., nil, 'utf-16')", text_document_edit(5)) + exec_lua(function(text_edit) + vim.lsp.util.apply_text_document_edit(text_edit, nil, 'utf-16') + end, text_document_edit(5)) eq({ 'First ↥ 🤦 🦄 line of text', '2nd line of è¯text', }, buf_lines(target_bufnr)) end) + it('always accepts edit with version = 0', function() - exec_lua( - [[ - local args = {...} - local bufnr = select(1, ...) - local text_edit = select(2, ...) - vim.lsp.util.buf_versions[bufnr] = 10 + exec_lua(function(text_edit) + vim.lsp.util.buf_versions[target_bufnr] = 10 vim.lsp.util.apply_text_document_edit(text_edit, nil, 'utf-16') - ]], - target_bufnr, - text_document_edit(0) - ) + end, text_document_edit(0)) eq({ 'First ↥ 🤦 🦄 line of text', '2nd line of è¯text', }, buf_lines(target_bufnr)) end) + it('skips the edit if the version of the edit is behind the local buffer ', function() local apply_edit_mocking_current_version = function(edit, versionedBuf) - exec_lua( - [[ - local args = {...} - local versionedBuf = args[2] + exec_lua(function() vim.lsp.util.buf_versions[versionedBuf.bufnr] = versionedBuf.currentVersion - vim.lsp.util.apply_text_document_edit(args[1], nil, 'utf-16') - ]], - edit, - versionedBuf - ) + vim.lsp.util.apply_text_document_edit(edit, nil, 'utf-16') + end) end local baseText = { @@ -2164,13 +2364,17 @@ describe('LSP', function() } eq( expected, - exec_lua [[ - local apply_edit = { - label = nil; - edit = {}; - } - return vim.lsp.handlers['workspace/applyEdit'](nil, apply_edit, {client_id = TEST_RPC_CLIENT_ID}) - ]] + exec_lua(function() + local apply_edit = { + label = nil, + edit = {}, + } + return vim.lsp.handlers['workspace/applyEdit']( + nil, + apply_edit, + { client_id = _G.TEST_RPC_CLIENT_ID } + ) + end) ) eq(table.remove(expected_handlers), { ... }) end, @@ -2200,34 +2404,30 @@ describe('LSP', function() } end - local target_bufnr, changedtick = nil, nil + local target_bufnr --- @type integer + local changedtick --- @type integer before_each(function() - local ret = exec_lua [[ - local bufnr = vim.uri_to_bufnr("file:///fake/uri") + exec_lua(function() + target_bufnr = vim.uri_to_bufnr('file:///fake/uri') local lines = { - "Original Line #1", - "Original Line #2" + 'Original Line #1', + 'Original Line #2', } - vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) + vim.api.nvim_buf_set_lines(target_bufnr, 0, -1, false, lines) - local update_changed_tick = function() - vim.lsp.util.buf_versions[bufnr] = vim.api.nvim_buf_get_var(bufnr, 'changedtick') + local function update_changed_tick() + vim.lsp.util.buf_versions[target_bufnr] = vim.b[target_bufnr].changedtick end update_changed_tick() - vim.api.nvim_buf_attach(bufnr, false, { - on_changedtick = function() - update_changed_tick() - end + vim.api.nvim_buf_attach(target_bufnr, false, { + on_changedtick = update_changed_tick, }) - return {bufnr, vim.api.nvim_buf_get_var(bufnr, 'changedtick')} - ]] - - target_bufnr = ret[1] - changedtick = ret[2] + changedtick = vim.b[target_bufnr].changedtick + end) end) it('apply_workspace_edit applies a single edit', function() @@ -2245,19 +2445,11 @@ describe('LSP', function() 'First Line', 'Original Line #2', }, - exec_lua( - [[ - local args = {...} - local workspace_edits = args[1] - local target_bufnr = args[2] - - vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16') + exec_lua(function(workspace_edits) + vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16') - return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false) - ]], - make_workspace_edit(edits), - target_bufnr - ) + return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false) + end, make_workspace_edit(edits)) ) end) @@ -2274,24 +2466,15 @@ describe('LSP', function() eq( new_lines, - exec_lua( - [[ - local args = {...} - local workspace_edits = args[1] - local target_bufnr = args[2] - - vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16') - - return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false) - ]], - make_workspace_edit(edits), - target_bufnr - ) + exec_lua(function(workspace_edits) + vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16') + return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false) + end, make_workspace_edit(edits)) ) end) + it('Supports file creation with CreateFile payload', function() - local tmpfile = tmpname() - os.remove(tmpfile) -- Should not exist, only interested in a tmpname + local tmpfile = tmpname(false) local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile) local edit = { documentChanges = { @@ -2301,15 +2484,16 @@ describe('LSP', function() }, }, } - exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16') + exec_lua(function() + vim.lsp.util.apply_workspace_edit(edit, 'utf-16') + end) eq(true, vim.uv.fs_stat(tmpfile) ~= nil) end) + it( 'Supports file creation in folder that needs to be created with CreateFile payload', function() - local tmpfile = tmpname() - os.remove(tmpfile) -- Should not exist, only interested in a tmpname - tmpfile = tmpfile .. '/dummy/x/' + local tmpfile = tmpname(false) .. '/dummy/x/' local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile) local edit = { documentChanges = { @@ -2319,10 +2503,13 @@ describe('LSP', function() }, }, } - exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16') + exec_lua(function() + vim.lsp.util.apply_workspace_edit(edit, 'utf-16') + end) eq(true, vim.uv.fs_stat(tmpfile) ~= nil) end ) + it('createFile does not touch file if it exists and ignoreIfExists is set', function() local tmpfile = tmpname() write_file(tmpfile, 'Dummy content') @@ -2342,6 +2529,7 @@ describe('LSP', function() eq(true, vim.uv.fs_stat(tmpfile) ~= nil) eq('Dummy content', read_file(tmpfile)) end) + it('createFile overrides file if overwrite is set', function() local tmpfile = tmpname() write_file(tmpfile, 'Dummy content') @@ -2362,18 +2550,15 @@ describe('LSP', function() eq(true, vim.uv.fs_stat(tmpfile) ~= nil) eq('', read_file(tmpfile)) end) + it('DeleteFile delete file and buffer', function() local tmpfile = tmpname() write_file(tmpfile, 'Be gone') - local uri = exec_lua( - [[ - local fname = select(1, ...) - local bufnr = vim.fn.bufadd(fname) + local uri = exec_lua(function() + local bufnr = vim.fn.bufadd(tmpfile) vim.fn.bufload(bufnr) - return vim.uri_from_fname(fname) - ]], - tmpfile - ) + return vim.uri_from_fname(tmpfile) + end) local edit = { documentChanges = { { @@ -2386,9 +2571,9 @@ describe('LSP', function() eq(false, vim.uv.fs_stat(tmpfile) ~= nil) eq(false, api.nvim_buf_is_loaded(fn.bufadd(tmpfile))) end) + it('DeleteFile fails if file does not exist and ignoreIfNotExists is false', function() - local tmpfile = tmpname() - os.remove(tmpfile) + local tmpfile = tmpname(false) local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile) local edit = { documentChanges = { @@ -2412,12 +2597,8 @@ describe('LSP', function() it('Can rename an existing file', function() local old = tmpname() write_file(old, 'Test content') - local new = tmpname() - os.remove(new) -- only reserve the name, file must not exist for the test scenario - local lines = exec_lua( - [[ - local old = select(1, ...) - local new = select(2, ...) + local new = tmpname(false) + local lines = exec_lua(function() local old_bufnr = vim.fn.bufadd(old) vim.fn.bufload(old_bufnr) vim.lsp.util.rename(old, new) @@ -2425,10 +2606,7 @@ describe('LSP', function() local new_bufnr = vim.fn.bufadd(new) vim.fn.bufload(new_bufnr) return (old_bufnr == new_bufnr) and vim.api.nvim_buf_get_lines(new_bufnr, 0, -1, true) - ]], - old, - new - ) + end) eq({ 'Test content' }, lines) local exists = vim.uv.fs_stat(old) ~= nil eq(false, exists) @@ -2436,24 +2614,18 @@ describe('LSP', function() eq(true, exists) os.remove(new) end) + it('Can rename a directory', function() -- only reserve the name, file must not exist for the test scenario - local old_dir = tmpname() - local new_dir = tmpname() - os.remove(old_dir) - os.remove(new_dir) + local old_dir = tmpname(false) + local new_dir = tmpname(false) n.mkdir_p(old_dir) local file = 'file.txt' write_file(old_dir .. pathsep .. file, 'Test content') - local lines = exec_lua( - [[ - local old_dir = select(1, ...) - local new_dir = select(2, ...) - local pathsep = select(3, ...) - local file = select(4, ...) + local lines = exec_lua(function() local old_bufnr = vim.fn.bufadd(old_dir .. pathsep .. file) vim.fn.bufload(old_bufnr) vim.lsp.util.rename(old_dir, new_dir) @@ -2461,12 +2633,7 @@ describe('LSP', function() local new_bufnr = vim.fn.bufadd(new_dir .. pathsep .. file) vim.fn.bufload(new_bufnr) return (old_bufnr == new_bufnr) and vim.api.nvim_buf_get_lines(new_bufnr, 0, -1, true) - ]], - old_dir, - new_dir, - pathsep, - file - ) + end) eq({ 'Test content' }, lines) eq(false, vim.uv.fs_stat(old_dir) ~= nil) eq(true, vim.uv.fs_stat(new_dir) ~= nil) @@ -2474,47 +2641,41 @@ describe('LSP', function() os.remove(new_dir) end) + it('Does not touch buffers that do not match path prefix', function() - local old = tmpname() - local new = tmpname() - os.remove(old) - os.remove(new) + local old = tmpname(false) + local new = tmpname(false) n.mkdir_p(old) - local result = exec_lua( - [[ - local old = select(1, ...) - local new = select(2, ...) - - local old_prefixed = 'explorer://' .. old - local old_suffixed = old .. '.bak' - local new_prefixed = 'explorer://' .. new - local new_suffixed = new .. '.bak' + eq( + true, + exec_lua(function() + local old_prefixed = 'explorer://' .. old + local old_suffixed = old .. '.bak' + local new_prefixed = 'explorer://' .. new + local new_suffixed = new .. '.bak' - local old_prefixed_buf = vim.fn.bufadd(old_prefixed) - local old_suffixed_buf = vim.fn.bufadd(old_suffixed) - local new_prefixed_buf = vim.fn.bufadd(new_prefixed) - local new_suffixed_buf = vim.fn.bufadd(new_suffixed) + local old_prefixed_buf = vim.fn.bufadd(old_prefixed) + local old_suffixed_buf = vim.fn.bufadd(old_suffixed) + local new_prefixed_buf = vim.fn.bufadd(new_prefixed) + local new_suffixed_buf = vim.fn.bufadd(new_suffixed) - vim.lsp.util.rename(old, new) + vim.lsp.util.rename(old, new) - return - vim.api.nvim_buf_is_valid(old_prefixed_buf) and - vim.api.nvim_buf_is_valid(old_suffixed_buf) and - vim.api.nvim_buf_is_valid(new_prefixed_buf) and - vim.api.nvim_buf_is_valid(new_suffixed_buf) and - vim.api.nvim_buf_get_name(old_prefixed_buf) == old_prefixed and - vim.api.nvim_buf_get_name(old_suffixed_buf) == old_suffixed and - vim.api.nvim_buf_get_name(new_prefixed_buf) == new_prefixed and - vim.api.nvim_buf_get_name(new_suffixed_buf) == new_suffixed - ]], - old, - new + return vim.api.nvim_buf_is_valid(old_prefixed_buf) + and vim.api.nvim_buf_is_valid(old_suffixed_buf) + and vim.api.nvim_buf_is_valid(new_prefixed_buf) + and vim.api.nvim_buf_is_valid(new_suffixed_buf) + and vim.api.nvim_buf_get_name(old_prefixed_buf) == old_prefixed + and vim.api.nvim_buf_get_name(old_suffixed_buf) == old_suffixed + and vim.api.nvim_buf_get_name(new_prefixed_buf) == new_prefixed + and vim.api.nvim_buf_get_name(new_suffixed_buf) == new_suffixed + end) ) - eq(true, result) os.remove(new) end) + it( 'Does not rename file if target exists and ignoreIfExists is set or overwrite is false', function() @@ -2523,45 +2684,28 @@ describe('LSP', function() local new = tmpname() write_file(new, 'New file') - exec_lua( - [[ - local old = select(1, ...) - local new = select(2, ...) - - vim.lsp.util.rename(old, new, { ignoreIfExists = true }) - ]], - old, - new - ) + exec_lua(function() + vim.lsp.util.rename(old, new, { ignoreIfExists = true }) + end) eq(true, vim.uv.fs_stat(old) ~= nil) eq('New file', read_file(new)) - exec_lua( - [[ - local old = select(1, ...) - local new = select(2, ...) - - vim.lsp.util.rename(old, new, { overwrite = false }) - ]], - old, - new - ) + exec_lua(function() + vim.lsp.util.rename(old, new, { overwrite = false }) + end) eq(true, vim.uv.fs_stat(old) ~= nil) eq('New file', read_file(new)) end ) + it('Maintains undo information for loaded buffer', function() local old = tmpname() write_file(old, 'line') - local new = tmpname() - os.remove(new) + local new = tmpname(false) - local undo_kept = exec_lua( - [[ - local old = select(1, ...) - local new = select(2, ...) + local undo_kept = exec_lua(function() vim.opt.undofile = true vim.cmd.edit(old) vim.cmd.normal('dd') @@ -2574,24 +2718,18 @@ describe('LSP', function() undotree.save_last = undotree.save_last + 1 undotree.entries[1].save = undotree.entries[1].save + 1 return vim.deep_equal(undotree, vim.fn.undotree()) - ]], - old, - new - ) + end) eq(false, vim.uv.fs_stat(old) ~= nil) eq(true, vim.uv.fs_stat(new) ~= nil) eq(true, undo_kept) end) + it('Maintains undo information for unloaded buffer', function() local old = tmpname() write_file(old, 'line') - local new = tmpname() - os.remove(new) + local new = tmpname(false) - local undo_kept = exec_lua( - [[ - local old = select(1, ...) - local new = select(2, ...) + local undo_kept = exec_lua(function() vim.opt.undofile = true vim.cmd.split(old) vim.cmd.normal('dd') @@ -2601,54 +2739,39 @@ describe('LSP', function() vim.lsp.util.rename(old, new) vim.cmd.edit(new) return vim.deep_equal(undotree, vim.fn.undotree()) - ]], - old, - new - ) + end) eq(false, vim.uv.fs_stat(old) ~= nil) eq(true, vim.uv.fs_stat(new) ~= nil) eq(true, undo_kept) end) + it('Does not rename file when it conflicts with a buffer without file', function() local old = tmpname() write_file(old, 'Old File') - local new = tmpname() - os.remove(new) - - local lines = exec_lua( - [[ - local old = select(1, ...) - local new = select(2, ...) - local old_buf = vim.fn.bufadd(old) - vim.fn.bufload(old_buf) - local conflict_buf = vim.api.nvim_create_buf(true, false) - vim.api.nvim_buf_set_name(conflict_buf, new) - vim.api.nvim_buf_set_lines(conflict_buf, 0, -1, true, {'conflict'}) - vim.api.nvim_win_set_buf(0, conflict_buf) - vim.lsp.util.rename(old, new) - return vim.api.nvim_buf_get_lines(conflict_buf, 0, -1, true) - ]], - old, - new - ) + local new = tmpname(false) + + local lines = exec_lua(function() + local old_buf = vim.fn.bufadd(old) + vim.fn.bufload(old_buf) + local conflict_buf = vim.api.nvim_create_buf(true, false) + vim.api.nvim_buf_set_name(conflict_buf, new) + vim.api.nvim_buf_set_lines(conflict_buf, 0, -1, true, { 'conflict' }) + vim.api.nvim_win_set_buf(0, conflict_buf) + vim.lsp.util.rename(old, new) + return vim.api.nvim_buf_get_lines(conflict_buf, 0, -1, true) + end) eq({ 'conflict' }, lines) eq('Old File', read_file(old)) end) + it('Does override target if overwrite is true', function() local old = tmpname() write_file(old, 'Old file') local new = tmpname() write_file(new, 'New file') - exec_lua( - [[ - local old = select(1, ...) - local new = select(2, ...) - + exec_lua(function() vim.lsp.util.rename(old, new, { overwrite = true }) - ]], - old, - new - ) + end) eq(false, vim.uv.fs_stat(old) ~= nil) eq(true, vim.uv.fs_stat(new) ~= nil) @@ -2658,44 +2781,59 @@ describe('LSP', function() describe('lsp.util.locations_to_items', function() it('Convert Location[] to items', function() - local expected = { + local expected_template = { { filename = '/fake/uri', lnum = 1, + end_lnum = 2, col = 3, + end_col = 4, text = 'testing', - user_data = { + user_data = {}, + }, + } + local test_params = { + { + { uri = 'file:///fake/uri', range = { start = { line = 0, character = 2 }, - ['end'] = { line = 0, character = 3 }, + ['end'] = { line = 1, character = 3 }, }, }, }, - } - local actual = exec_lua [[ - local bufnr = vim.uri_to_bufnr("file:///fake/uri") - local lines = {"testing", "123"} - vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) - local locations = { + { { uri = 'file:///fake/uri', range = { start = { line = 0, character = 2 }, - ['end'] = { line = 0, character = 3 }, - } + -- LSP spec: if character > line length, default to the line length. + ['end'] = { line = 1, character = 10000 }, + }, }, - } - return vim.lsp.util.locations_to_items(locations, 'utf-16') - ]] - eq(expected, actual) + }, + } + for _, params in ipairs(test_params) do + local actual = exec_lua(function(params0) + local bufnr = vim.uri_to_bufnr('file:///fake/uri') + local lines = { 'testing', '123' } + vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) + return vim.lsp.util.locations_to_items(params0, 'utf-16') + end, params) + local expected = vim.deepcopy(expected_template) + expected[1].user_data = params[1] + eq(expected, actual) + end end) + it('Convert LocationLink[] to items', function() local expected = { { filename = '/fake/uri', lnum = 1, + end_lnum = 1, col = 3, + end_col = 4, text = 'testing', user_data = { targetUri = 'file:///fake/uri', @@ -2710,9 +2848,9 @@ describe('LSP', function() }, }, } - local actual = exec_lua [[ - local bufnr = vim.uri_to_bufnr("file:///fake/uri") - local lines = {"testing", "123"} + local actual = exec_lua(function() + local bufnr = vim.uri_to_bufnr('file:///fake/uri') + local lines = { 'testing', '123' } vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) local locations = { { @@ -2724,11 +2862,11 @@ describe('LSP', function() targetSelectionRange = { start = { line = 0, character = 2 }, ['end'] = { line = 0, character = 3 }, - } + }, }, } return vim.lsp.util.locations_to_items(locations, 'utf-16') - ]] + end) eq(expected, actual) end) end) @@ -2761,94 +2899,95 @@ describe('LSP', function() } eq( expected, - exec_lua [[ - local doc_syms = { - { - deprecated = false, - detail = "A", - kind = 1, - name = "TestA", - range = { - start = { - character = 0, - line = 1 + exec_lua(function() + local doc_syms = { + { + deprecated = false, + detail = 'A', + kind = 1, + name = 'TestA', + range = { + start = { + character = 0, + line = 1, + }, + ['end'] = { + character = 0, + line = 2, + }, }, - ["end"] = { - character = 0, - line = 2 - } - }, - selectionRange = { - start = { - character = 0, - line = 1 + selectionRange = { + start = { + character = 0, + line = 1, + }, + ['end'] = { + character = 4, + line = 1, + }, }, - ["end"] = { - character = 4, - line = 1 - } - }, - children = { - { - children = {}, - deprecated = false, - detail = "B", - kind = 2, - name = "TestB", - range = { - start = { - character = 0, - line = 3 + children = { + { + children = {}, + deprecated = false, + detail = 'B', + kind = 2, + name = 'TestB', + range = { + start = { + character = 0, + line = 3, + }, + ['end'] = { + character = 0, + line = 4, + }, }, - ["end"] = { - character = 0, - line = 4 - } - }, - selectionRange = { - start = { - character = 0, - line = 3 + selectionRange = { + start = { + character = 0, + line = 3, + }, + ['end'] = { + character = 4, + line = 3, + }, }, - ["end"] = { - character = 4, - line = 3 - } - } - } - } - }, - { - deprecated = false, - detail = "C", - kind = 3, - name = "TestC", - range = { - start = { - character = 0, - line = 5 + }, }, - ["end"] = { - character = 0, - line = 6 - } }, - selectionRange = { - start = { - character = 0, - line = 5 + { + deprecated = false, + detail = 'C', + kind = 3, + name = 'TestC', + range = { + start = { + character = 0, + line = 5, + }, + ['end'] = { + character = 0, + line = 6, + }, }, - ["end"] = { - character = 4, - line = 5 - } - } + selectionRange = { + start = { + character = 0, + line = 5, + }, + ['end'] = { + character = 4, + line = 5, + }, + }, + }, } - } - return vim.lsp.util.symbols_to_items(doc_syms, nil) - ]] + return vim.lsp.util.symbols_to_items(doc_syms, nil) + end) ) end) + it('DocumentSymbol has no children', function() local expected = { { @@ -2868,66 +3007,67 @@ describe('LSP', function() } eq( expected, - exec_lua [[ - local doc_syms = { - { - deprecated = false, - detail = "A", - kind = 1, - name = "TestA", - range = { - start = { - character = 0, - line = 1 + exec_lua(function() + local doc_syms = { + { + deprecated = false, + detail = 'A', + kind = 1, + name = 'TestA', + range = { + start = { + character = 0, + line = 1, + }, + ['end'] = { + character = 0, + line = 2, + }, }, - ["end"] = { - character = 0, - line = 2 - } - }, - selectionRange = { - start = { - character = 0, - line = 1 + selectionRange = { + start = { + character = 0, + line = 1, + }, + ['end'] = { + character = 4, + line = 1, + }, }, - ["end"] = { - character = 4, - line = 1 - } }, - }, - { - deprecated = false, - detail = "C", - kind = 3, - name = "TestC", - range = { - start = { - character = 0, - line = 5 + { + deprecated = false, + detail = 'C', + kind = 3, + name = 'TestC', + range = { + start = { + character = 0, + line = 5, + }, + ['end'] = { + character = 0, + line = 6, + }, }, - ["end"] = { - character = 0, - line = 6 - } - }, - selectionRange = { - start = { - character = 0, - line = 5 + selectionRange = { + start = { + character = 0, + line = 5, + }, + ['end'] = { + character = 4, + line = 5, + }, }, - ["end"] = { - character = 4, - line = 5 - } - } + }, } - } - return vim.lsp.util.symbols_to_items(doc_syms, nil) - ]] + return vim.lsp.util.symbols_to_items(doc_syms, nil) + end) ) end) end) + it('convert SymbolInformation[] to items', function() local expected = { { @@ -2947,62 +3087,88 @@ describe('LSP', function() } eq( expected, - exec_lua [[ + exec_lua(function() local sym_info = { { deprecated = false, kind = 1, - name = "TestA", + name = 'TestA', location = { range = { start = { character = 0, - line = 1 + line = 1, }, - ["end"] = { + ['end'] = { character = 0, - line = 2 - } + line = 2, + }, }, - uri = "file:///test_a" + uri = 'file:///test_a', }, - containerName = "TestAContainer" + containerName = 'TestAContainer', }, { deprecated = false, kind = 2, - name = "TestB", + name = 'TestB', location = { range = { start = { character = 0, - line = 3 + line = 3, }, - ["end"] = { + ['end'] = { character = 0, - line = 4 - } + line = 4, + }, }, - uri = "file:///test_b" + uri = 'file:///test_b', }, - containerName = "TestBContainer" - } + containerName = 'TestBContainer', + }, } return vim.lsp.util.symbols_to_items(sym_info, nil) - ]] + end) ) end) end) describe('lsp.util._get_symbol_kind_name', function() it('returns the name specified by protocol', function() - eq('File', exec_lua('return vim.lsp.util._get_symbol_kind_name(1)')) - eq('TypeParameter', exec_lua('return vim.lsp.util._get_symbol_kind_name(26)')) + eq( + 'File', + exec_lua(function() + return vim.lsp.util._get_symbol_kind_name(1) + end) + ) + eq( + 'TypeParameter', + exec_lua(function() + return vim.lsp.util._get_symbol_kind_name(26) + end) + ) end) + it('returns the name not specified by protocol', function() - eq('Unknown', exec_lua('return vim.lsp.util._get_symbol_kind_name(nil)')) - eq('Unknown', exec_lua('return vim.lsp.util._get_symbol_kind_name(vim.NIL)')) - eq('Unknown', exec_lua('return vim.lsp.util._get_symbol_kind_name(1000)')) + eq( + 'Unknown', + exec_lua(function() + return vim.lsp.util._get_symbol_kind_name(nil) + end) + ) + eq( + 'Unknown', + exec_lua(function() + return vim.lsp.util._get_symbol_kind_name(vim.NIL) + end) + ) + eq( + 'Unknown', + exec_lua(function() + return vim.lsp.util._get_symbol_kind_name(1000) + end) + ) end) end) @@ -3010,12 +3176,12 @@ describe('LSP', function() local target_bufnr --- @type integer before_each(function() - target_bufnr = exec_lua [[ - local bufnr = vim.uri_to_bufnr("file:///fake/uri") - local lines = {"1st line of text", "aÌŠ Ã¥ ɧ æ±‰è¯ â†¥ 🤦 🦄"} + target_bufnr = exec_lua(function() + local bufnr = vim.uri_to_bufnr('file:///fake/uri') + local lines = { '1st line of text', 'aÌŠ Ã¥ ɧ æ±‰è¯ â†¥ 🤦 🦄' } vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) return bufnr - ]] + end) end) local location = function(start_line, start_char, end_line, end_char) @@ -3084,19 +3250,19 @@ describe('LSP', function() local target_bufnr2 --- @type integer before_each(function() - target_bufnr = exec_lua([[ - local bufnr = vim.uri_to_bufnr("file:///fake/uri") - local lines = {"1st line of text", "aÌŠ Ã¥ ɧ æ±‰è¯ â†¥ 🤦 🦄"} + target_bufnr = exec_lua(function() + local bufnr = vim.uri_to_bufnr('file:///fake/uri') + local lines = { '1st line of text', 'aÌŠ Ã¥ ɧ æ±‰è¯ â†¥ 🤦 🦄' } vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) return bufnr - ]]) + end) - target_bufnr2 = exec_lua([[ - local bufnr = vim.uri_to_bufnr("file:///fake/uri2") - local lines = {"1st line of text", "aÌŠ Ã¥ ɧ æ±‰è¯ â†¥ 🤦 🦄"} + target_bufnr2 = exec_lua(function() + local bufnr = vim.uri_to_bufnr('file:///fake/uri2') + local lines = { '1st line of text', 'aÌŠ Ã¥ ɧ æ±‰è¯ â†¥ 🤦 🦄' } vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) return bufnr - ]]) + end) end) local location = function(start_line, start_char, end_line, end_char, second_uri) @@ -3136,14 +3302,14 @@ describe('LSP', function() it('jumps to a Location if focus is true via handler', function() exec_lua(create_server_definition) - local result = exec_lua([[ - local server = _create_server() - local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + local result = exec_lua(function() + local server = _G._create_server() + local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd })) local result = { uri = 'file:///fake/uri', selection = { start = { line = 0, character = 9 }, - ['end'] = { line = 0, character = 9 } + ['end'] = { line = 0, character = 9 }, }, takeFocus = true, } @@ -3154,9 +3320,9 @@ describe('LSP', function() vim.lsp.handlers['window/showDocument'](nil, result, ctx) vim.lsp.stop_client(client_id) return { - cursor = vim.api.nvim_win_get_cursor(0) + cursor = vim.api.nvim_win_get_cursor(0), } - ]]) + end) eq(1, result.cursor[1]) eq(9, result.cursor[2]) end) @@ -3231,7 +3397,9 @@ describe('LSP', function() api.nvim_win_set_buf(0, target_bufnr) api.nvim_win_set_cursor(0, { 2, 3 }) - exec_lua([[vim.cmd.new()]]) + exec_lua(function() + vim.cmd.new() + end) api.nvim_win_set_buf(0, target_bufnr2) api.nvim_win_set_cursor(0, { 2, 3 }) @@ -3247,7 +3415,9 @@ describe('LSP', function() api.nvim_win_set_buf(0, target_bufnr) local win = api.nvim_get_current_win() - exec_lua([[vim.cmd.new()]]) + exec_lua(function() + vim.cmd.new() + end) api.nvim_win_set_buf(0, target_bufnr2) api.nvim_win_set_cursor(0, { 2, 3 }) local split = api.nvim_get_current_win() @@ -3268,34 +3438,53 @@ describe('LSP', function() describe('lsp.util._make_floating_popup_size', function() before_each(function() - exec_lua [[ contents = - {"text tαxt txtα tex", - "text tααt tααt text", - "text tαxt tαxt"} - ]] + exec_lua(function() + _G.contents = { 'text tαxt txtα tex', 'text tααt tααt text', 'text tαxt tαxt' } + end) end) it('calculates size correctly', function() - eq({ 19, 3 }, exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents)} ]]) + eq( + { 19, 3 }, + exec_lua(function() + return { vim.lsp.util._make_floating_popup_size(_G.contents) } + end) + ) end) it('calculates size correctly with wrapping', function() eq( { 15, 5 }, - exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents,{width = 15, wrap_at = 14})} ]] + exec_lua(function() + return { + vim.lsp.util._make_floating_popup_size(_G.contents, { width = 15, wrap_at = 14 }), + } + end) ) end) it('handles NUL bytes in text', function() - exec_lua([[ contents = { - '\000\001\002\003\004\005\006\007\008\009', - '\010\011\012\013\014\015\016\017\018\019', - '\020\021\022\023\024\025\026\027\028\029', - } ]]) + exec_lua(function() + _G.contents = { + '\000\001\002\003\004\005\006\007\008\009', + '\010\011\012\013\014\015\016\017\018\019', + '\020\021\022\023\024\025\026\027\028\029', + } + end) command('set list listchars=') - eq({ 20, 3 }, exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents)} ]]) + eq( + { 20, 3 }, + exec_lua(function() + return { vim.lsp.util._make_floating_popup_size(_G.contents) } + end) + ) command('set display+=uhex') - eq({ 40, 3 }, exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents)} ]]) + eq( + { 40, 3 }, + exec_lua(function() + return { vim.lsp.util._make_floating_popup_size(_G.contents) } + end) + ) end) end) @@ -3303,27 +3492,30 @@ describe('LSP', function() it('properly trims empty lines', function() eq( { { 'foo', 'bar' } }, - exec_lua [[ return vim.lsp.util.trim_empty_lines({{ "foo", "bar" }, nil}) ]] + exec_lua(function() + --- @diagnostic disable-next-line:deprecated + return vim.lsp.util.trim_empty_lines({ { 'foo', 'bar' }, nil }) + end) ) end) end) describe('lsp.util.convert_signature_help_to_markdown_lines', function() it('can handle negative activeSignature', function() - local result = exec_lua [[ + local result = exec_lua(function() local signature_help = { activeParameter = 0, activeSignature = -1, signatures = { { - documentation = "some doc", - label = "TestEntity.TestEntity()", - parameters = {} + documentation = 'some doc', + label = 'TestEntity.TestEntity()', + parameters = {}, }, - } + }, } - return vim.lsp.util.convert_signature_help_to_markdown_lines(signature_help, 'cs', {','}) - ]] + return vim.lsp.util.convert_signature_help_to_markdown_lines(signature_help, 'cs', { ',' }) + end) local expected = { '```cs', 'TestEntity.TestEntity()', '```', 'some doc' } eq(expected, result) end) @@ -3338,12 +3530,18 @@ describe('LSP', function() ]], shiftwidth )) - eq(tabsize, exec_lua('return vim.lsp.util.get_effective_tabstop()')) + eq( + tabsize, + exec_lua(function() + return vim.lsp.util.get_effective_tabstop() + end) + ) end it('with shiftwidth = 1', function() test_tabstop(1, 1) end) + it('with shiftwidth = 0', function() test_tabstop(2, 0) end) @@ -3351,57 +3549,61 @@ describe('LSP', function() describe('vim.lsp.buf.outgoing_calls', function() it('does nothing for an empty response', function() - local qflist_count = exec_lua([=[ - require'vim.lsp.handlers'['callHierarchy/outgoingCalls'](nil, nil, {}, nil) + local qflist_count = exec_lua(function() + require 'vim.lsp.handlers'['callHierarchy/outgoingCalls'](nil, nil, {}, nil) return #vim.fn.getqflist() - ]=]) + end) eq(0, qflist_count) end) it('opens the quickfix list with the right caller', function() - local qflist = exec_lua([=[ - local rust_analyzer_response = { { - fromRanges = { { - ['end'] = { - character = 7, - line = 3 - }, - start = { - character = 4, - line = 3 - } - } }, - to = { - detail = "fn foo()", - kind = 12, - name = "foo", - range = { - ['end'] = { - character = 11, - line = 0 + local qflist = exec_lua(function() + local rust_analyzer_response = { + { + fromRanges = { + { + ['end'] = { + character = 7, + line = 3, + }, + start = { + character = 4, + line = 3, + }, }, - start = { - character = 0, - line = 0 - } }, - selectionRange = { - ['end'] = { - character = 6, - line = 0 + to = { + detail = 'fn foo()', + kind = 12, + name = 'foo', + range = { + ['end'] = { + character = 11, + line = 0, + }, + start = { + character = 0, + line = 0, + }, }, - start = { - character = 3, - line = 0 - } + selectionRange = { + ['end'] = { + character = 6, + line = 0, + }, + start = { + character = 3, + line = 0, + }, + }, + uri = 'file:///src/main.rs', }, - uri = "file:///src/main.rs" - } - } } - local handler = require'vim.lsp.handlers'['callHierarchy/outgoingCalls'] + }, + } + local handler = require 'vim.lsp.handlers'['callHierarchy/outgoingCalls'] handler(nil, rust_analyzer_response, {}) return vim.fn.getqflist() - ]=]) + end) local expected = { { @@ -3426,58 +3628,62 @@ describe('LSP', function() describe('vim.lsp.buf.incoming_calls', function() it('does nothing for an empty response', function() - local qflist_count = exec_lua([=[ - require'vim.lsp.handlers'['callHierarchy/incomingCalls'](nil, nil, {}) + local qflist_count = exec_lua(function() + require 'vim.lsp.handlers'['callHierarchy/incomingCalls'](nil, nil, {}) return #vim.fn.getqflist() - ]=]) + end) eq(0, qflist_count) end) it('opens the quickfix list with the right callee', function() - local qflist = exec_lua([=[ - local rust_analyzer_response = { { - from = { - detail = "fn main()", - kind = 12, - name = "main", - range = { - ['end'] = { - character = 1, - line = 4 + local qflist = exec_lua(function() + local rust_analyzer_response = { + { + from = { + detail = 'fn main()', + kind = 12, + name = 'main', + range = { + ['end'] = { + character = 1, + line = 4, + }, + start = { + character = 0, + line = 2, + }, }, - start = { - character = 0, - line = 2 - } + selectionRange = { + ['end'] = { + character = 7, + line = 2, + }, + start = { + character = 3, + line = 2, + }, + }, + uri = 'file:///src/main.rs', }, - selectionRange = { - ['end'] = { - character = 7, - line = 2 + fromRanges = { + { + ['end'] = { + character = 7, + line = 3, + }, + start = { + character = 4, + line = 3, + }, }, - start = { - character = 3, - line = 2 - } }, - uri = "file:///src/main.rs" }, - fromRanges = { { - ['end'] = { - character = 7, - line = 3 - }, - start = { - character = 4, - line = 3 - } - } } - } } + } - local handler = require'vim.lsp.handlers'['callHierarchy/incomingCalls'] + local handler = require 'vim.lsp.handlers'['callHierarchy/incomingCalls'] handler(nil, rust_analyzer_response, {}) return vim.fn.getqflist() - ]=]) + end) local expected = { { @@ -3502,103 +3708,126 @@ describe('LSP', function() describe('vim.lsp.buf.typehierarchy subtypes', function() it('does nothing for an empty response', function() - local qflist_count = exec_lua([=[ - require'vim.lsp.handlers'['typeHierarchy/subtypes'](nil, nil, {}) + local qflist_count = exec_lua(function() + require 'vim.lsp.handlers'['typeHierarchy/subtypes'](nil, nil, {}) return #vim.fn.getqflist() - ]=]) + end) eq(0, qflist_count) end) it('opens the quickfix list with the right subtypes', function() clear() exec_lua(create_server_definition) - local qflist = exec_lua([=[ - local clangd_response = { { - data = { - parents = { { - parents = { { - parents = { { - parents = {}, - symbolID = "62B3D268A01B9978" - } }, - symbolID = "DC9B0AD433B43BEC" - } }, - symbolID = "06B5F6A19BA9F6A8" - } }, - symbolID = "EDC336589C09ABB2" - }, - kind = 5, - name = "D2", - range = { - ["end"] = { - character = 8, - line = 9 + local qflist = exec_lua(function() + local clangd_response = { + { + data = { + parents = { + { + parents = { + { + parents = { + { + parents = {}, + symbolID = '62B3D268A01B9978', + }, + }, + symbolID = 'DC9B0AD433B43BEC', + }, + }, + symbolID = '06B5F6A19BA9F6A8', + }, + }, + symbolID = 'EDC336589C09ABB2', }, - start = { - character = 6, - line = 9 - } - }, - selectionRange = { - ["end"] = { - character = 8, - line = 9 + kind = 5, + name = 'D2', + range = { + ['end'] = { + character = 8, + line = 3, + }, + start = { + character = 6, + line = 3, + }, }, - start = { - character = 6, - line = 9 - } - }, - uri = "file:///home/jiangyinzuo/hello.cpp" - }, { - data = { - parents = { { - parents = { { - parents = { { - parents = {}, - symbolID = "62B3D268A01B9978" - } }, - symbolID = "DC9B0AD433B43BEC" - } }, - symbolID = "06B5F6A19BA9F6A8" - } }, - symbolID = "AFFCAED15557EF08" - }, - kind = 5, - name = "D1", - range = { - ["end"] = { - character = 8, - line = 8 + selectionRange = { + ['end'] = { + character = 8, + line = 3, + }, + start = { + character = 6, + line = 3, + }, }, - start = { - character = 6, - line = 8 - } + uri = 'file:///home/jiangyinzuo/hello.cpp', }, - selectionRange = { - ["end"] = { - character = 8, - line = 8 + { + data = { + parents = { + { + parents = { + { + parents = { + { + parents = {}, + symbolID = '62B3D268A01B9978', + }, + }, + symbolID = 'DC9B0AD433B43BEC', + }, + }, + symbolID = '06B5F6A19BA9F6A8', + }, + }, + symbolID = 'AFFCAED15557EF08', }, - start = { - character = 6, - line = 8 - } + kind = 5, + name = 'D1', + range = { + ['end'] = { + character = 8, + line = 2, + }, + start = { + character = 6, + line = 2, + }, + }, + selectionRange = { + ['end'] = { + character = 8, + line = 2, + }, + start = { + character = 6, + line = 2, + }, + }, + uri = 'file:///home/jiangyinzuo/hello.cpp', }, - uri = "file:///home/jiangyinzuo/hello.cpp" - } } + } - local server = _create_server({ + local server = _G._create_server({ capabilities = { - positionEncoding = "utf-8" + positionEncoding = 'utf-8', }, }) local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - local handler = require'vim.lsp.handlers'['typeHierarchy/subtypes'] - handler(nil, clangd_response, { client_id = client_id, bufnr = 1 }) + local handler = require 'vim.lsp.handlers'['typeHierarchy/subtypes'] + local bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { + 'class B : public A{};', + 'class C : public B{};', + 'class D1 : public C{};', + 'class D2 : public C{};', + 'class E : public D1, D2 {};', + }) + handler(nil, clangd_response, { client_id = client_id, bufnr = bufnr }) return vim.fn.getqflist() - ]=]) + end) local expected = { { @@ -3606,7 +3835,7 @@ describe('LSP', function() col = 7, end_col = 0, end_lnum = 0, - lnum = 10, + lnum = 4, module = '', nr = 0, pattern = '', @@ -3620,7 +3849,7 @@ describe('LSP', function() col = 7, end_col = 0, end_lnum = 0, - lnum = 9, + lnum = 3, module = '', nr = 0, pattern = '', @@ -3637,7 +3866,7 @@ describe('LSP', function() it('opens the quickfix list with the right subtypes and details', function() clear() exec_lua(create_server_definition) - local qflist = exec_lua([=[ + local qflist = exec_lua(function() local jdtls_response = { { data = { element = '=hello-java_ed323c3c/_<{Main.java[Main[A' }, @@ -3673,16 +3902,24 @@ describe('LSP', function() }, } - local server = _create_server({ + local server = _G._create_server({ capabilities = { - positionEncoding = "utf-8" + positionEncoding = 'utf-8', }, }) local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - local handler = require'vim.lsp.handlers'['typeHierarchy/subtypes'] - handler(nil, jdtls_response, { client_id = client_id, bufnr = 1 }) + local handler = require 'vim.lsp.handlers'['typeHierarchy/subtypes'] + local bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { + 'package mylist;', + '', + 'public class MyList {', + ' static class Inner extends MyList{}', + '~}', + }) + handler(nil, jdtls_response, { client_id = client_id, bufnr = bufnr }) return vim.fn.getqflist() - ]=]) + end) local expected = { { @@ -3720,103 +3957,127 @@ describe('LSP', function() describe('vim.lsp.buf.typehierarchy supertypes', function() it('does nothing for an empty response', function() - local qflist_count = exec_lua([=[ - require'vim.lsp.handlers'['typeHierarchy/supertypes'](nil, nil, {}) + local qflist_count = exec_lua(function() + require 'vim.lsp.handlers'['typeHierarchy/supertypes'](nil, nil, {}) return #vim.fn.getqflist() - ]=]) + end) eq(0, qflist_count) end) it('opens the quickfix list with the right supertypes', function() clear() exec_lua(create_server_definition) - local qflist = exec_lua([=[ - local clangd_response = { { - data = { - parents = { { - parents = { { - parents = { { - parents = {}, - symbolID = "62B3D268A01B9978" - } }, - symbolID = "DC9B0AD433B43BEC" - } }, - symbolID = "06B5F6A19BA9F6A8" - } }, - symbolID = "EDC336589C09ABB2" - }, - kind = 5, - name = "D2", - range = { - ["end"] = { - character = 8, - line = 9 + local qflist = exec_lua(function() + local clangd_response = { + { + data = { + parents = { + { + parents = { + { + parents = { + { + parents = {}, + symbolID = '62B3D268A01B9978', + }, + }, + symbolID = 'DC9B0AD433B43BEC', + }, + }, + symbolID = '06B5F6A19BA9F6A8', + }, + }, + symbolID = 'EDC336589C09ABB2', }, - start = { - character = 6, - line = 9 - } - }, - selectionRange = { - ["end"] = { - character = 8, - line = 9 + kind = 5, + name = 'D2', + range = { + ['end'] = { + character = 8, + line = 3, + }, + start = { + character = 6, + line = 3, + }, }, - start = { - character = 6, - line = 9 - } - }, - uri = "file:///home/jiangyinzuo/hello.cpp" - }, { - data = { - parents = { { - parents = { { - parents = { { - parents = {}, - symbolID = "62B3D268A01B9978" - } }, - symbolID = "DC9B0AD433B43BEC" - } }, - symbolID = "06B5F6A19BA9F6A8" - } }, - symbolID = "AFFCAED15557EF08" - }, - kind = 5, - name = "D1", - range = { - ["end"] = { - character = 8, - line = 8 + selectionRange = { + ['end'] = { + character = 8, + line = 3, + }, + start = { + character = 6, + line = 3, + }, }, - start = { - character = 6, - line = 8 - } + uri = 'file:///home/jiangyinzuo/hello.cpp', }, - selectionRange = { - ["end"] = { - character = 8, - line = 8 + { + data = { + parents = { + { + parents = { + { + parents = { + { + parents = {}, + symbolID = '62B3D268A01B9978', + }, + }, + symbolID = 'DC9B0AD433B43BEC', + }, + }, + symbolID = '06B5F6A19BA9F6A8', + }, + }, + symbolID = 'AFFCAED15557EF08', }, - start = { - character = 6, - line = 8 - } + kind = 5, + name = 'D1', + range = { + ['end'] = { + character = 8, + line = 2, + }, + start = { + character = 6, + line = 2, + }, + }, + selectionRange = { + ['end'] = { + character = 8, + line = 2, + }, + start = { + character = 6, + line = 2, + }, + }, + uri = 'file:///home/jiangyinzuo/hello.cpp', }, - uri = "file:///home/jiangyinzuo/hello.cpp" - } } + } - local server = _create_server({ + local server = _G._create_server({ capabilities = { - positionEncoding = "utf-8" + positionEncoding = 'utf-8', }, }) local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - local handler = require'vim.lsp.handlers'['typeHierarchy/supertypes'] - handler(nil, clangd_response, { client_id = client_id, bufnr = 1 }) + local handler = require 'vim.lsp.handlers'['typeHierarchy/supertypes'] + local bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { + 'class B : public A{};', + 'class C : public B{};', + 'class D1 : public C{};', + 'class D2 : public C{};', + 'class E : public D1, D2 {};', + }) + + handler(nil, clangd_response, { client_id = client_id, bufnr = bufnr }) return vim.fn.getqflist() - ]=]) + end) local expected = { { @@ -3824,7 +4085,7 @@ describe('LSP', function() col = 7, end_col = 0, end_lnum = 0, - lnum = 10, + lnum = 4, module = '', nr = 0, pattern = '', @@ -3838,7 +4099,7 @@ describe('LSP', function() col = 7, end_col = 0, end_lnum = 0, - lnum = 9, + lnum = 3, module = '', nr = 0, pattern = '', @@ -3855,7 +4116,7 @@ describe('LSP', function() it('opens the quickfix list with the right supertypes and details', function() clear() exec_lua(create_server_definition) - local qflist = exec_lua([=[ + local qflist = exec_lua(function() local jdtls_response = { { data = { element = '=hello-java_ed323c3c/_<{Main.java[Main[A' }, @@ -3891,16 +4152,24 @@ describe('LSP', function() }, } - local server = _create_server({ + local server = _G._create_server({ capabilities = { - positionEncoding = "utf-8" + positionEncoding = 'utf-8', }, }) local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - local handler = require'vim.lsp.handlers'['typeHierarchy/supertypes'] - handler(nil, jdtls_response, { client_id = client_id, bufnr = 1 }) + local handler = require 'vim.lsp.handlers'['typeHierarchy/supertypes'] + local bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { + 'package mylist;', + '', + 'public class MyList {', + ' static class Inner extends MyList{}', + '~}', + }) + handler(nil, jdtls_response, { client_id = client_id, bufnr = bufnr }) return vim.fn.getqflist() - ]=]) + end) local expected = { { @@ -3984,18 +4253,19 @@ describe('LSP', function() eq(true, client.server_capabilities().renameProvider.prepareProvider) end, on_setup = function() - exec_lua([=[ - local bufnr = vim.api.nvim_get_current_buf() - lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) - vim.lsp._stubs = {} - vim.fn.input = function(opts, on_confirm) - vim.lsp._stubs.input_prompt = opts.prompt - vim.lsp._stubs.input_text = opts.default - return 'renameto' -- expect this value in fake lsp - end - vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'', 'this is line two'}) - vim.fn.cursor(2, 13) -- the space between "line" and "two" - ]=]) + exec_lua(function() + local bufnr = vim.api.nvim_get_current_buf() + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) + vim.lsp._stubs = {} + --- @diagnostic disable-next-line:duplicate-set-field + vim.fn.input = function(opts, _) + vim.lsp._stubs.input_prompt = opts.prompt + vim.lsp._stubs.input_text = opts.default + return 'renameto' -- expect this value in fake lsp + end + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { '', 'this is line two' }) + vim.fn.cursor(2, 13) -- the space between "line" and "two" + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -4009,12 +4279,24 @@ describe('LSP', function() eq(table.remove(test.expected_handlers), { err, result, ctx }, 'expected handler') if ctx.method == 'start' then - exec_lua('vim.lsp.buf.rename()') + exec_lua(function() + vim.lsp.buf.rename() + end) end if ctx.method == 'shutdown' then if test.expected_text then - eq('New Name: ', exec_lua('return vim.lsp._stubs.input_prompt')) - eq(test.expected_text, exec_lua('return vim.lsp._stubs.input_text')) + eq( + 'New Name: ', + exec_lua(function() + return vim.lsp._stubs.input_prompt + end) + ) + eq( + test.expected_text, + exec_lua(function() + return vim.lsp._stubs.input_text + end) + ) end client.stop() end @@ -4044,25 +4326,31 @@ describe('LSP', function() on_handler = function(err, result, ctx) eq(table.remove(expected_handlers), { err, result, ctx }) if ctx.method == 'start' then - exec_lua([[ - vim.lsp.commands['dummy1'] = function(cmd) - vim.lsp.commands['dummy2'] = function() - end + exec_lua(function() + vim.lsp.commands['dummy1'] = function(_) + vim.lsp.commands['dummy2'] = function() end end local bufnr = vim.api.nvim_get_current_buf() - vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) + --- @diagnostic disable-next-line:duplicate-set-field vim.fn.inputlist = function() return 1 end vim.lsp.buf.code_action() - ]]) + end) elseif ctx.method == 'shutdown' then - eq('function', exec_lua [[return type(vim.lsp.commands['dummy2'])]]) + eq( + 'function', + exec_lua(function() + return type(vim.lsp.commands['dummy2']) + end) + ) client.stop() end end, } end) + it('Calls workspace/executeCommand if no client side command', function() local client --- @type vim.lsp.Client local expected_handlers = { @@ -4089,20 +4377,21 @@ describe('LSP', function() ctx.version = nil eq(table.remove(expected_handlers), { err, result, ctx }) if ctx.method == 'start' then - exec_lua([[ + exec_lua(function() local bufnr = vim.api.nvim_get_current_buf() - vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) vim.fn.inputlist = function() return 1 end vim.lsp.buf.code_action() - ]]) + end) elseif ctx.method == 'shutdown' then client.stop() end end, }) end) + it('Filters and automatically applies action if requested', function() local client --- @type vim.lsp.Client local expected_handlers = { @@ -4122,83 +4411,102 @@ describe('LSP', function() on_handler = function(err, result, ctx) eq(table.remove(expected_handlers), { err, result, ctx }) if ctx.method == 'start' then - exec_lua([[ - vim.lsp.commands['preferred_command'] = function(cmd) - vim.lsp.commands['executed_preferred'] = function() - end + exec_lua(function() + vim.lsp.commands['preferred_command'] = function(_) + vim.lsp.commands['executed_preferred'] = function() end end - vim.lsp.commands['type_annotate_command'] = function(cmd) - vim.lsp.commands['executed_type_annotate'] = function() - end + vim.lsp.commands['type_annotate_command'] = function(_) + vim.lsp.commands['executed_type_annotate'] = function() end end local bufnr = vim.api.nvim_get_current_buf() - vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) - vim.lsp.buf.code_action({ filter = function(a) return a.isPreferred end, apply = true, }) + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) + vim.lsp.buf.code_action({ + filter = function(a) + return a.isPreferred + end, + apply = true, + }) vim.lsp.buf.code_action({ - -- expect to be returned actions 'type-annotate' and 'type-annotate.foo' - context = { only = { 'type-annotate' }, }, - apply = true, - filter = function(a) - if a.kind == 'type-annotate.foo' then - vim.lsp.commands['filtered_type_annotate_foo'] = function() end - return false - elseif a.kind == 'type-annotate' then - return true - else - assert(nil, 'unreachable') - end - end, + -- expect to be returned actions 'type-annotate' and 'type-annotate.foo' + context = { only = { 'type-annotate' } }, + apply = true, + filter = function(a) + if a.kind == 'type-annotate.foo' then + vim.lsp.commands['filtered_type_annotate_foo'] = function() end + return false + elseif a.kind == 'type-annotate' then + return true + else + assert(nil, 'unreachable') + end + end, }) - ]]) + end) elseif ctx.method == 'shutdown' then - eq('function', exec_lua [[return type(vim.lsp.commands['executed_preferred'])]]) - eq('function', exec_lua [[return type(vim.lsp.commands['filtered_type_annotate_foo'])]]) - eq('function', exec_lua [[return type(vim.lsp.commands['executed_type_annotate'])]]) + eq( + 'function', + exec_lua(function() + return type(vim.lsp.commands['executed_preferred']) + end) + ) + eq( + 'function', + exec_lua(function() + return type(vim.lsp.commands['filtered_type_annotate_foo']) + end) + ) + eq( + 'function', + exec_lua(function() + return type(vim.lsp.commands['executed_type_annotate']) + end) + ) client.stop() end end, } end) + it('Fallback to command execution on resolve error', function() clear() exec_lua(create_server_definition) - local result = exec_lua([[ - local server = _create_server({ + local result = exec_lua(function() + local server = _G._create_server({ capabilities = { executeCommandProvider = { - commands = {"command:1"}, + commands = { 'command:1' }, }, codeActionProvider = { - resolveProvider = true - } + resolveProvider = true, + }, }, handlers = { - ["textDocument/codeAction"] = function(_, _, callback) + ['textDocument/codeAction'] = function(_, _, callback) callback(nil, { { - title = "Code Action 1", + title = 'Code Action 1', command = { - title = "Command 1", - command = "command:1", - } - } + title = 'Command 1', + command = 'command:1', + }, + }, }) end, - ["codeAction/resolve"] = function(_, _, callback) - callback("resolve failed", nil) + ['codeAction/resolve'] = function(_, _, callback) + callback('resolve failed', nil) end, - } + }, }) - local client_id = vim.lsp.start({ - name = "dummy", + local client_id = assert(vim.lsp.start({ + name = 'dummy', cmd = server.cmd, - }) + })) vim.lsp.buf.code_action({ apply = true }) vim.lsp.stop_client(client_id) return server.messages - ]]) + end) eq('codeAction/resolve', result[4].method) eq('workspace/executeCommand', result[5].method) eq('command:1', result[5].params.command) @@ -4212,6 +4520,7 @@ describe('LSP', function() pcall_err(exec_lua, 'vim.lsp.commands[1] = function() end') ) end) + it('Accepts only function values', function() matches( '.*Command added to `vim.lsp.commands` must be a function', @@ -4241,32 +4550,32 @@ describe('LSP', function() eq(table.remove(expected_handlers), { err, result, ctx }) if ctx.method == 'start' then local fake_uri = 'file:///fake/uri' - local cmd = exec_lua( - [[ - fake_uri = ... + local cmd = exec_lua(function() local bufnr = vim.uri_to_bufnr(fake_uri) vim.fn.bufload(bufnr) - vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'One line'}) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'One line' }) local lenses = { { range = { - start = { line = 0, character = 0, }, - ['end'] = { line = 0, character = 8 } + start = { line = 0, character = 0 }, + ['end'] = { line = 0, character = 8 }, }, - command = { title = 'Lens1', command = 'Dummy' } + command = { title = 'Lens1', command = 'Dummy' }, }, } - vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr}) + vim.lsp.codelens.on_codelens( + nil, + lenses, + { method = 'textDocument/codeLens', client_id = 1, bufnr = bufnr } + ) local cmd_called = nil - vim.lsp.commands['Dummy'] = function(command) - cmd_called = command + vim.lsp.commands['Dummy'] = function(command0) + cmd_called = command0 end vim.api.nvim_set_current_buf(bufnr) vim.lsp.codelens.run() return cmd_called - ]], - fake_uri - ) + end) eq({ command = 'Dummy', title = 'Lens1' }, cmd) elseif ctx.method == 'shutdown' then client.stop() @@ -4287,20 +4596,20 @@ describe('LSP', function() client = client_ end, on_setup = function() - exec_lua([=[ - local bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'One line'}) - vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) - - CALLED = false - RESPONSE = nil - local on_codelens = vim.lsp.codelens.on_codelens - vim.lsp.codelens.on_codelens = function (err, result, ...) - CALLED = true - RESPONSE = { err = err, result = result } - return on_codelens(err, result, ...) - end - ]=]) + exec_lua(function() + local bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'One line' }) + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) + + _G.CALLED = false + _G.RESPONSE = nil + local on_codelens = vim.lsp.codelens.on_codelens + vim.lsp.codelens.on_codelens = function(err, result, ...) + _G.CALLED = true + _G.RESPONSE = { err = err, result = result } + return on_codelens(err, result, ...) + end + end) end, on_exit = function(code, signal) eq(0, code, 'exit code') @@ -4310,42 +4619,52 @@ describe('LSP', function() eq(table.remove(expected_handlers), { err, result, ctx }) if ctx.method == 'start' then -- 1. first codelens request errors - local response = exec_lua([=[ - CALLED = false + local response = exec_lua(function() + _G.CALLED = false vim.lsp.codelens.refresh() - vim.wait(100, function () return CALLED end) - return RESPONSE - ]=]) + vim.wait(100, function() + return _G.CALLED + end) + return _G.RESPONSE + end) eq({ err = { code = -32002, message = 'ServerNotInitialized' } }, response) -- 2. second codelens request runs - response = exec_lua([=[ - CALLED = false - local cmd_called = nil - vim.lsp.commands["Dummy"] = function (command) - cmd_called = command + response = exec_lua(function() + _G.CALLED = false + local cmd_called --- @type string? + vim.lsp.commands['Dummy'] = function(command0) + cmd_called = command0 end vim.lsp.codelens.refresh() - vim.wait(100, function () return CALLED end) + vim.wait(100, function() + return _G.CALLED + end) vim.lsp.codelens.run() - vim.wait(100, function () return cmd_called end) + vim.wait(100, function() + return cmd_called ~= nil + end) return cmd_called - ]=]) + end) eq({ command = 'Dummy', title = 'Lens1' }, response) -- 3. third codelens request runs - response = exec_lua([=[ - CALLED = false - local cmd_called = nil - vim.lsp.commands["Dummy"] = function (command) - cmd_called = command + response = exec_lua(function() + _G.CALLED = false + local cmd_called --- @type string? + vim.lsp.commands['Dummy'] = function(command0) + cmd_called = command0 end vim.lsp.codelens.refresh() - vim.wait(100, function () return CALLED end) + vim.wait(100, function() + return _G.CALLED + end) vim.lsp.codelens.run() - vim.wait(100, function () return cmd_called end) + vim.wait(100, function() + return cmd_called ~= nil + end) return cmd_called - ]=]) + end) eq({ command = 'Dummy', title = 'Lens2' }, response) elseif ctx.method == 'shutdown' then client.stop() @@ -4363,79 +4682,73 @@ describe('LSP', function() exec_lua(create_server_definition) -- setup lsp - exec_lua( - [[ - local lens_title_per_fake_uri = ... - local server = _create_server({ - capabilities = { - codeLensProvider = { - resolveProvider = true - }, + exec_lua(function() + local server = _G._create_server({ + capabilities = { + codeLensProvider = { + resolveProvider = true, }, - handlers = { - ["textDocument/codeLens"] = function(method, params, callback) - local lenses = { - { - range = { - start = { line = 0, character = 0 }, - ['end'] = { line = 0, character = 0 }, - }, - command = { - title = lens_title_per_fake_uri[params.textDocument.uri], - command = 'Dummy', - }, + }, + handlers = { + ['textDocument/codeLens'] = function(_, params, callback) + local lenses = { + { + range = { + start = { line = 0, character = 0 }, + ['end'] = { line = 0, character = 0 }, }, - } - callback(nil, lenses) - end, - } - }) + command = { + title = lens_title_per_fake_uri[params.textDocument.uri], + command = 'Dummy', + }, + }, + } + callback(nil, lenses) + end, + }, + }) - CLIENT_ID = vim.lsp.start({ - name = "dummy", - cmd = server.cmd, - }) - ]], - lens_title_per_fake_uri - ) + _G.CLIENT_ID = vim.lsp.start({ + name = 'dummy', + cmd = server.cmd, + }) + end) -- create buffers and setup handler - exec_lua( - [[ - local lens_title_per_fake_uri = ... - local default_buf = vim.api.nvim_get_current_buf() - for fake_uri, _ in pairs(lens_title_per_fake_uri) do - local bufnr = vim.uri_to_bufnr(fake_uri) - vim.api.nvim_set_current_buf(bufnr) - vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'Some contents'}) - vim.lsp.buf_attach_client(bufnr, CLIENT_ID) - end - vim.api.nvim_buf_delete(default_buf, {force = true}) - - REQUEST_COUNT = vim.tbl_count(lens_title_per_fake_uri) - RESPONSES = {} - local on_codelens = vim.lsp.codelens.on_codelens - vim.lsp.codelens.on_codelens = function (err, result, ctx, ...) - table.insert(RESPONSES, { err = err, result = result, ctx = ctx }) - return on_codelens(err, result, ctx, ...) - end - ]], - lens_title_per_fake_uri - ) + exec_lua(function() + local default_buf = vim.api.nvim_get_current_buf() + for fake_uri in pairs(lens_title_per_fake_uri) do + local bufnr = vim.uri_to_bufnr(fake_uri) + vim.api.nvim_set_current_buf(bufnr) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'Some contents' }) + vim.lsp.buf_attach_client(bufnr, _G.CLIENT_ID) + end + vim.api.nvim_buf_delete(default_buf, { force = true }) + + _G.REQUEST_COUNT = vim.tbl_count(lens_title_per_fake_uri) + _G.RESPONSES = {} + local on_codelens = vim.lsp.codelens.on_codelens + vim.lsp.codelens.on_codelens = function(err, result, ctx, ...) + table.insert(_G.RESPONSES, { err = err, result = result, ctx = ctx }) + return on_codelens(err, result, ctx, ...) + end + end) -- call codelens refresh - local cmds = exec_lua([[ - RESPONSES = {} + local cmds = exec_lua(function() + _G.RESPONSES = {} vim.lsp.codelens.refresh() - vim.wait(100, function () return #RESPONSES >= REQUEST_COUNT end) + vim.wait(100, function() + return #_G.RESPONSES >= _G.REQUEST_COUNT + end) local cmds = {} - for _, resp in ipairs(RESPONSES) do + for _, resp in ipairs(_G.RESPONSES) do local uri = resp.ctx.params.textDocument.uri cmds[uri] = resp.result[1].command end return cmds - ]]) + end) eq({ command = 'Dummy', title = 'Lens1' }, cmds['file:///fake/uri1']) eq({ command = 'Dummy', title = 'Lens2' }, cmds['file:///fake/uri2']) end) @@ -4450,23 +4763,24 @@ describe('LSP', function() client = c end, on_handler = function() - local notify_msg = exec_lua([[ + local notify_msg = exec_lua(function() local bufnr = vim.api.nvim_get_current_buf() - vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) - local notify_msg + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) + local notify_msg --- @type string? local notify = vim.notify - vim.notify = function(msg, log_level) + vim.notify = function(msg, _) notify_msg = msg end vim.lsp.buf.format({ name = 'does-not-exist' }) vim.notify = notify return notify_msg - ]]) + end) eq('[LSP] Format request failed, no matching language servers.', notify_msg) client.stop() end, } end) + it('Sends textDocument/formatting request to format buffer', function() local expected_handlers = { { NIL, {}, { method = 'shutdown', client_id = 1 } }, @@ -4481,25 +4795,114 @@ describe('LSP', function() on_handler = function(_, _, ctx) table.remove(expected_handlers) if ctx.method == 'start' then - local notify_msg = exec_lua([[ + local notify_msg = exec_lua(function() local bufnr = vim.api.nvim_get_current_buf() - vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) - local notify_msg + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) + local notify_msg --- @type string? local notify = vim.notify - vim.notify = function(msg, log_level) + vim.notify = function(msg, _) notify_msg = msg end vim.lsp.buf.format({ bufnr = bufnr }) vim.notify = notify return notify_msg - ]]) - eq(NIL, notify_msg) + end) + eq(nil, notify_msg) + elseif ctx.method == 'shutdown' then + client.stop() + end + end, + } + end) + + it('Sends textDocument/rangeFormatting request to format a range', function() + local expected_handlers = { + { NIL, {}, { method = 'shutdown', client_id = 1 } }, + { NIL, {}, { method = 'start', client_id = 1 } }, + } + local client --- @type vim.lsp.Client + test_rpc_server { + test_name = 'range_formatting', + on_init = function(c) + client = c + end, + on_handler = function(_, _, ctx) + table.remove(expected_handlers) + if ctx.method == 'start' then + local notify_msg = exec_lua(function() + local bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar' }) + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) + local notify_msg --- @type string? + local notify = vim.notify + vim.notify = function(msg, _) + notify_msg = msg + end + vim.lsp.buf.format({ + bufnr = bufnr, + range = { + start = { 1, 1 }, + ['end'] = { 1, 1 }, + }, + }) + vim.notify = notify + return notify_msg + end) + eq(nil, notify_msg) + elseif ctx.method == 'shutdown' then + client.stop() + end + end, + } + end) + + it('Sends textDocument/rangesFormatting request to format multiple ranges', function() + local expected_handlers = { + { NIL, {}, { method = 'shutdown', client_id = 1 } }, + { NIL, {}, { method = 'start', client_id = 1 } }, + } + local client --- @type vim.lsp.Client + test_rpc_server { + test_name = 'ranges_formatting', + on_init = function(c) + client = c + end, + on_handler = function(_, _, ctx) + table.remove(expected_handlers) + if ctx.method == 'start' then + local notify_msg = exec_lua(function() + local bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar', 'baz' }) + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) + local notify_msg --- @type string? + local notify = vim.notify + vim.notify = function(msg, _) + notify_msg = msg + end + vim.lsp.buf.format({ + bufnr = bufnr, + range = { + { + start = { 1, 1 }, + ['end'] = { 1, 1 }, + }, + { + start = { 2, 2 }, + ['end'] = { 2, 2 }, + }, + }, + }) + vim.notify = notify + return notify_msg + end) + eq(nil, notify_msg) elseif ctx.method == 'shutdown' then client.stop() end end, } end) + it('Can format async', function() local expected_handlers = { { NIL, {}, { method = 'shutdown', client_id = 1 } }, @@ -4514,29 +4917,31 @@ describe('LSP', function() on_handler = function(_, _, ctx) table.remove(expected_handlers) if ctx.method == 'start' then - local result = exec_lua([[ + local result = exec_lua(function() local bufnr = vim.api.nvim_get_current_buf() - vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) + vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID) - local notify_msg + local notify_msg --- @type string? local notify = vim.notify - vim.notify = function(msg, log_level) + vim.notify = function(msg, _) notify_msg = msg end local handler = vim.lsp.handlers['textDocument/formatting'] local handler_called = false - vim.lsp.handlers['textDocument/formatting'] = function(...) + vim.lsp.handlers['textDocument/formatting'] = function() handler_called = true end vim.lsp.buf.format({ bufnr = bufnr, async = true }) - vim.wait(1000, function() return handler_called end) + vim.wait(1000, function() + return handler_called + end) vim.notify = notify vim.lsp.handlers['textDocument/formatting'] = handler - return {notify = notify_msg, handler_called = handler_called} - ]]) + return { notify = notify_msg, handler_called = handler_called } + end) eq({ handler_called = true }, result) elseif ctx.method == 'shutdown' then client.stop() @@ -4544,24 +4949,27 @@ describe('LSP', function() end, } end) + it('format formats range in visual mode', function() exec_lua(create_server_definition) - local result = exec_lua([[ - local server = _create_server({ capabilities = { - documentFormattingProvider = true, - documentRangeFormattingProvider = true, - }}) + local result = exec_lua(function() + local server = _G._create_server({ + capabilities = { + documentFormattingProvider = true, + documentRangeFormattingProvider = true, + }, + }) local bufnr = vim.api.nvim_get_current_buf() - local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd })) vim.api.nvim_win_set_buf(0, bufnr) - vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {'foo', 'bar'}) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar' }) vim.api.nvim_win_set_cursor(0, { 1, 0 }) vim.cmd.normal('v') vim.api.nvim_win_set_cursor(0, { 2, 3 }) vim.lsp.buf.format({ bufnr = bufnr, false }) vim.lsp.stop_client(client_id) return server.messages - ]]) + end) eq('textDocument/rangeFormatting', result[3].method) local expected_range = { start = { line = 0, character = 0 }, @@ -4569,17 +4977,20 @@ describe('LSP', function() } eq(expected_range, result[3].params.range) end) + it('format formats range in visual line mode', function() exec_lua(create_server_definition) - local result = exec_lua([[ - local server = _create_server({ capabilities = { - documentFormattingProvider = true, - documentRangeFormattingProvider = true, - }}) + local result = exec_lua(function() + local server = _G._create_server({ + capabilities = { + documentFormattingProvider = true, + documentRangeFormattingProvider = true, + }, + }) local bufnr = vim.api.nvim_get_current_buf() - local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd })) vim.api.nvim_win_set_buf(0, bufnr) - vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {'foo', 'bar baz'}) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar baz' }) vim.api.nvim_win_set_cursor(0, { 1, 2 }) vim.cmd.normal('V') vim.api.nvim_win_set_cursor(0, { 2, 1 }) @@ -4587,7 +4998,7 @@ describe('LSP', function() -- Format again with visual lines going from bottom to top -- Must result in same formatting - vim.cmd.normal("<ESC>") + vim.cmd.normal('<ESC>') vim.api.nvim_win_set_cursor(0, { 2, 1 }) vim.cmd.normal('V') vim.api.nvim_win_set_cursor(0, { 1, 2 }) @@ -4595,7 +5006,7 @@ describe('LSP', function() vim.lsp.stop_client(client_id) return server.messages - ]]) + end) local expected_methods = { 'initialize', 'initialized', @@ -4620,40 +5031,57 @@ describe('LSP', function() eq(expected_range, result[3].params.range) eq(expected_range, result[5].params.range) end) + it('Aborts with notify if no clients support requested method', function() exec_lua(create_server_definition) - exec_lua([[ + exec_lua(function() vim.notify = function(msg, _) - notify_msg = msg + _G.notify_msg = msg end - ]]) + end) local fail_msg = '[LSP] Format request failed, no matching language servers.' --- @param name string --- @param formatting boolean --- @param range_formatting boolean local function check_notify(name, formatting, range_formatting) local timeout_msg = '[LSP][' .. name .. '] timeout' - exec_lua( - [[ - local formatting, range_formatting, name = ... - local server = _create_server({ capabilities = { - documentFormattingProvider = formatting, - documentRangeFormattingProvider = range_formatting, - }}) + exec_lua(function() + local server = _G._create_server({ + capabilities = { + documentFormattingProvider = formatting, + documentRangeFormattingProvider = range_formatting, + }, + }) vim.lsp.start({ name = name, cmd = server.cmd }) - notify_msg = nil + _G.notify_msg = nil vim.lsp.buf.format({ name = name, timeout_ms = 1 }) - ]], - formatting, - range_formatting, - name + end) + eq( + formatting and timeout_msg or fail_msg, + exec_lua(function() + return _G.notify_msg + end) + ) + exec_lua(function() + _G.notify_msg = nil + vim.lsp.buf.format({ + name = name, + timeout_ms = 1, + range = { + start = { 1, 0 }, + ['end'] = { + 1, + 0, + }, + }, + }) + end) + eq( + range_formatting and timeout_msg or fail_msg, + exec_lua(function() + return _G.notify_msg + end) ) - eq(formatting and timeout_msg or fail_msg, exec_lua('return notify_msg')) - exec_lua([[ - notify_msg = nil - vim.lsp.buf.format({ name = name, timeout_ms = 1, range = {start={1, 0}, ['end']={1, 0}}}) - ]]) - eq(range_formatting and timeout_msg or fail_msg, exec_lua('return notify_msg')) end check_notify('none', false, false) check_notify('formatting', true, false) @@ -4683,10 +5111,9 @@ describe('LSP', function() }, } exec_lua(create_server_definition) - exec_lua( - [[ - _G.mock_locations = ... - _G.server = _create_server({ + exec_lua(function() + _G.mock_locations = mock_locations + _G.server = _G._create_server({ ---@type lsp.ServerCapabilities capabilities = { definitionProvider = true, @@ -4710,26 +5137,25 @@ describe('LSP', function() name = 'vim.foobar', kind = 12, ---@type lsp.SymbolKind location = _G.mock_locations[2], - } + }, }) end, }, }) - _G.client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) - ]], - mock_locations - ) + _G.client_id = vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) + end) end) + after_each(function() - exec_lua [[ + exec_lua(function() vim.lsp.stop_client(_G.client_id) - ]] + end) end) it('with flags=c, returns matching tags using textDocument/definition', function() - local result = exec_lua [[ + local result = exec_lua(function() return vim.lsp.tagfunc('foobar', 'c') - ]] + end) eq({ { cmd = '/\\%6l\\%1c/', -- for location (5, 23) @@ -4740,9 +5166,9 @@ describe('LSP', function() end) it('without flags=c, returns all matching tags using workspace/symbol', function() - local result = exec_lua [[ + local result = exec_lua(function() return vim.lsp.tagfunc('foobar', '') - ]] + end) eq({ { cmd = '/\\%6l\\%1c/', -- for location (5, 23) @@ -4761,80 +5187,81 @@ describe('LSP', function() end) describe('cmd', function() - it('can connect to lsp server via rpc.connect', function() - local result = exec_lua [[ - local uv = vim.uv - local server = uv.new_tcp() - local init = nil - server:bind('127.0.0.1', 0) - server:listen(127, function(err) - assert(not err, err) - local socket = uv.new_tcp() - server:accept(socket) - socket:read_start(require('vim.lsp.rpc').create_read_loop(function(body) - init = body - socket:close() - end)) - end) - local port = server:getsockname().port + it('connects to lsp server via rpc.connect using ip address', function() + exec_lua(create_tcp_echo_server) + local result = exec_lua(function() + local server, port, last_message = _G._create_tcp_server('127.0.0.1') vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) }) - vim.wait(1000, function() return init ~= nil end) - assert(init, "server must receive `initialize` request") + vim.wait(1000, function() + return last_message() ~= nil + end) + local init = last_message() + assert(init, 'server must receive `initialize` request') + server:close() + server:shutdown() + return vim.json.decode(init) + end) + eq('initialize', result.method) + end) + + it('connects to lsp server via rpc.connect using hostname', function() + skip(is_os('bsd'), 'issue with host resolution in ci') + exec_lua(create_tcp_echo_server) + local result = exec_lua(function() + local server, port, last_message = _G._create_tcp_server('::1') + vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('localhost', port) }) + vim.wait(1000, function() + return last_message() ~= nil + end) + local init = last_message() + assert(init, 'server must receive `initialize` request') server:close() server:shutdown() return vim.json.decode(init) - ]] + end) eq('initialize', result.method) end) + it('can connect to lsp server via pipe or domain_socket', function() - local tmpfile --- @type string - if is_os('win') then - tmpfile = '\\\\.\\\\pipe\\pipe.test' - else - tmpfile = tmpname() - os.remove(tmpfile) - end - local result = exec_lua( - [[ - local SOCK = ... + local tmpfile = is_os('win') and '\\\\.\\\\pipe\\pipe.test' or tmpname(false) + local result = exec_lua(function() local uv = vim.uv - local server = uv.new_pipe(false) - server:bind(SOCK) + local server = assert(uv.new_pipe(false)) + server:bind(tmpfile) local init = nil server:listen(127, function(err) - assert(not err, err) - local client = uv.new_pipe() - server:accept(client) - client:read_start(require("vim.lsp.rpc").create_read_loop(function(body) - init = body - client:close() - end)) + assert(not err, err) + local client = assert(vim.uv.new_pipe()) + server:accept(client) + client:read_start(require('vim.lsp.rpc').create_read_loop(function(body) + init = body + client:close() + end)) + end) + vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect(tmpfile) }) + vim.wait(1000, function() + return init ~= nil end) - vim.lsp.start({ name = "dummy", cmd = vim.lsp.rpc.connect(SOCK) }) - vim.wait(1000, function() return init ~= nil end) - assert(init, "server must receive `initialize` request") + assert(init, 'server must receive `initialize` request') server:close() server:shutdown() return vim.json.decode(init) - ]], - tmpfile - ) + end) eq('initialize', result.method) end) end) describe('handlers', function() it('handler can return false as response', function() - local result = exec_lua [[ - local uv = vim.uv - local server = uv.new_tcp() + local result = exec_lua(function() + local server = assert(vim.uv.new_tcp()) local messages = {} local responses = {} server:bind('127.0.0.1', 0) server:listen(127, function(err) assert(not err, err) - local socket = uv.new_tcp() + local socket = assert(vim.uv.new_tcp()) server:accept(socket) socket:read_start(require('vim.lsp.rpc').create_read_loop(function(body) local payload = vim.json.decode(body) @@ -4845,10 +5272,10 @@ describe('LSP', function() id = payload.id, jsonrpc = '2.0', result = { - capabilities = {} + capabilities = {}, }, }) - socket:write(table.concat({'Content-Length: ', tostring(#msg), '\r\n\r\n', msg})) + socket:write(table.concat({ 'Content-Length: ', tostring(#msg), '\r\n\r\n', msg })) elseif payload.method == 'initialized' then local msg = vim.json.encode({ id = 10, @@ -4856,7 +5283,7 @@ describe('LSP', function() method = 'dummy', params = {}, }) - socket:write(table.concat({'Content-Length: ', tostring(#msg), '\r\n\r\n', msg})) + socket:write(table.concat({ 'Content-Length: ', tostring(#msg), '\r\n\r\n', msg })) end else table.insert(responses, payload) @@ -4866,20 +5293,24 @@ describe('LSP', function() end) local port = server:getsockname().port local handler_called = false - vim.lsp.handlers['dummy'] = function(err, result) + vim.lsp.handlers['dummy'] = function(_, _) handler_called = true return false end - local client_id = vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) }) - local client = vim.lsp.get_client_by_id(client_id) - vim.wait(1000, function() return #messages == 2 and handler_called and #responses == 1 end) + local client_id = + assert(vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) })) + vim.lsp.get_client_by_id(client_id) + vim.wait(1000, function() + return #messages == 2 and handler_called and #responses == 1 + end) server:close() server:shutdown() return { messages = messages, handler_called = handler_called, - responses = responses } - ]] + responses = responses, + } + end) local expected = { messages = { 'initialize', 'initialized' }, handler_called = true, @@ -4897,9 +5328,7 @@ describe('LSP', function() describe('#dynamic vim.lsp._dynamic', function() it('supports dynamic registration', function() - ---@type string - local root_dir = tmpname() - os.remove(root_dir) + local root_dir = tmpname(false) mkdir(root_dir) local tmpfile = root_dir .. '/dynamic.foo' local file = io.open(tmpfile, 'w') @@ -4908,17 +5337,14 @@ describe('LSP', function() end exec_lua(create_server_definition) - local result = exec_lua( - [[ - local root_dir, tmpfile = ... - - local server = _create_server() - local client_id = vim.lsp.start({ + local result = exec_lua(function() + local server = _G._create_server() + local client_id = assert(vim.lsp.start({ name = 'dynamic-test', cmd = server.cmd, root_dir = root_dir, get_language_id = function() - return "dummy-lang" + return 'dummy-lang' end, capabilities = { textDocument = { @@ -4930,9 +5356,7 @@ describe('LSP', function() }, }, }, - }) - - local expected_messages = 2 -- initialize, initialized + })) vim.lsp.handlers['client/registerCapability'](nil, { registrations = { @@ -4940,9 +5364,11 @@ describe('LSP', function() id = 'formatting', method = 'textDocument/formatting', registerOptions = { - documentSelector = {{ - pattern = root_dir .. '/*.foo', - }}, + documentSelector = { + { + pattern = root_dir .. '/*.foo', + }, + }, }, }, }, @@ -4954,12 +5380,12 @@ describe('LSP', function() id = 'range-formatting', method = 'textDocument/rangeFormatting', registerOptions = { - documentSelector = { + documentSelector = { { - language = "dummy-lang" + language = 'dummy-lang', }, - } - } + }, + }, }, }, }, { client_id = client_id }) @@ -4976,26 +5402,22 @@ describe('LSP', function() local result = {} local function check(method, fname) local bufnr = fname and vim.fn.bufadd(fname) or nil - local client = vim.lsp.get_client_by_id(client_id) + local client = assert(vim.lsp.get_client_by_id(client_id)) result[#result + 1] = { method = method, fname = fname, - supported = client.supports_method(method, {bufnr = bufnr}) + supported = client.supports_method(method, { bufnr = bufnr }), } end - - check("textDocument/formatting") - check("textDocument/formatting", tmpfile) - check("textDocument/rangeFormatting") - check("textDocument/rangeFormatting", tmpfile) - check("textDocument/completion") + check('textDocument/formatting') + check('textDocument/formatting', tmpfile) + check('textDocument/rangeFormatting') + check('textDocument/rangeFormatting', tmpfile) + check('textDocument/completion') return result - ]], - root_dir, - tmpfile - ) + end) eq(5, #result) eq({ method = 'textDocument/formatting', supported = false }, result[1]) @@ -5007,16 +5429,26 @@ describe('LSP', function() end) describe('vim.lsp._watchfiles', function() + --- @type integer, integer, integer + local created, changed, deleted + + setup(function() + clear() + created = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]) + changed = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]) + deleted = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]) + end) + local function test_filechanges(watchfunc) it( string.format('sends notifications when files change (watchfunc=%s)', watchfunc), function() - if watchfunc == 'fswatch' then + if watchfunc == 'inotify' then skip(is_os('win'), 'not supported on windows') skip(is_os('mac'), 'flaky test on mac') skip( - not is_ci() and fn.executable('fswatch') == 0, - 'fswatch not installed and not on CI' + not is_ci() and fn.executable('inotifywait') == 0, + 'inotify-tools not installed and not on CI' ) end @@ -5033,87 +5465,80 @@ describe('LSP', function() ) end - local root_dir = tmpname() - os.remove(root_dir) + local root_dir = tmpname(false) mkdir(root_dir) exec_lua(create_server_definition) - local result = exec_lua( - [[ - local root_dir, watchfunc = ... - - local server = _create_server() - local client_id = vim.lsp.start({ - name = 'watchfiles-test', - cmd = server.cmd, - root_dir = root_dir, - capabilities = { - workspace = { - didChangeWatchedFiles = { - dynamicRegistration = true, + local result = exec_lua(function() + local server = _G._create_server() + local client_id = assert(vim.lsp.start({ + name = 'watchfiles-test', + cmd = server.cmd, + root_dir = root_dir, + capabilities = { + workspace = { + didChangeWatchedFiles = { + dynamicRegistration = true, + }, }, }, - }, - }) + })) - require('vim.lsp._watchfiles')._watchfunc = require('vim._watch')[watchfunc] + require('vim.lsp._watchfiles')._watchfunc = require('vim._watch')[watchfunc] - local expected_messages = 0 + local expected_messages = 0 - local msg_wait_timeout = watchfunc == 'watch' and 200 or 2500 + local msg_wait_timeout = watchfunc == 'watch' and 200 or 2500 - local function wait_for_message(incr) - expected_messages = expected_messages + (incr or 1) - assert( - vim.wait(msg_wait_timeout, function() - return #server.messages == expected_messages - end), - 'Timed out waiting for expected number of messages. Current messages seen so far: ' - .. vim.inspect(server.messages) - ) - end + local function wait_for_message(incr) + expected_messages = expected_messages + (incr or 1) + assert( + vim.wait(msg_wait_timeout, function() + return #server.messages == expected_messages + end), + 'Timed out waiting for expected number of messages. Current messages seen so far: ' + .. vim.inspect(server.messages) + ) + end - wait_for_message(2) -- initialize, initialized + wait_for_message(2) -- initialize, initialized - vim.lsp.handlers['client/registerCapability'](nil, { - registrations = { - { - id = 'watchfiles-test-0', - method = 'workspace/didChangeWatchedFiles', - registerOptions = { - watchers = { - { - globPattern = '**/watch', - kind = 7, + vim.lsp.handlers['client/registerCapability'](nil, { + registrations = { + { + id = 'watchfiles-test-0', + method = 'workspace/didChangeWatchedFiles', + registerOptions = { + watchers = { + { + globPattern = '**/watch', + kind = 7, + }, }, }, }, }, - }, - }, { client_id = client_id }) + }, { client_id = client_id }) - if watchfunc ~= 'watch' then - vim.wait(100) - end + if watchfunc ~= 'watch' then + vim.wait(100) + end - local path = root_dir .. '/watch' - local tmp = vim.fn.tempname() - io.open(tmp, 'w'):close() - vim.uv.fs_rename(tmp, path) + local path = root_dir .. '/watch' + local tmp = vim.fn.tempname() + io.open(tmp, 'w'):close() + vim.uv.fs_rename(tmp, path) - wait_for_message() + wait_for_message() - os.remove(path) + os.remove(path) - wait_for_message() + wait_for_message() - vim.lsp.stop_client(client_id) + vim.lsp.stop_client(client_id) - return server.messages - ]], - root_dir, - watchfunc - ) + return server.messages + end) local uri = vim.uri_from_fname(root_dir .. '/watch') @@ -5124,7 +5549,7 @@ describe('LSP', function() params = { changes = { { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + type = created, uri = uri, }, }, @@ -5136,7 +5561,7 @@ describe('LSP', function() params = { changes = { { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + type = deleted, uri = uri, }, }, @@ -5148,17 +5573,14 @@ describe('LSP', function() test_filechanges('watch') test_filechanges('watchdirs') - test_filechanges('fswatch') + test_filechanges('inotify') it('correctly registers and unregisters', function() local root_dir = '/some_dir' exec_lua(create_server_definition) - local result = exec_lua( - [[ - local root_dir = ... - - local server = _create_server() - local client_id = vim.lsp.start({ + local result = exec_lua(function() + local server = _G._create_server() + local client_id = assert(vim.lsp.start({ name = 'watchfiles-test', cmd = server.cmd, root_dir = root_dir, @@ -5169,16 +5591,22 @@ describe('LSP', function() }, }, }, - }) + })) local expected_messages = 2 -- initialize, initialized local function wait_for_messages() - assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages)) + assert( + vim.wait(200, function() + return #server.messages == expected_messages + end), + 'Timed out waiting for expected number of messages. Current messages seen so far: ' + .. vim.inspect(server.messages) + ) end wait_for_messages() - local send_event + local send_event --- @type function require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback) local stopped = false send_event = function(...) @@ -5245,9 +5673,7 @@ describe('LSP', function() wait_for_messages() return server.messages - ]], - root_dir - ) + end) local function watched_uri(fname) return vim.uri_from_fname(root_dir .. '/' .. fname) @@ -5258,7 +5684,7 @@ describe('LSP', function() eq({ changes = { { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + type = created, uri = watched_uri('file.watch0'), }, }, @@ -5267,7 +5693,7 @@ describe('LSP', function() eq({ changes = { { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + type = created, uri = watched_uri('file.watch1'), }, }, @@ -5277,12 +5703,9 @@ describe('LSP', function() it('correctly handles the registered watch kind', function() local root_dir = 'some_dir' exec_lua(create_server_definition) - local result = exec_lua( - [[ - local root_dir = ... - - local server = _create_server() - local client_id = vim.lsp.start({ + local result = exec_lua(function() + local server = _G._create_server() + local client_id = assert(vim.lsp.start({ name = 'watchfiles-test', cmd = server.cmd, root_dir = root_dir, @@ -5293,16 +5716,22 @@ describe('LSP', function() }, }, }, - }) + })) local expected_messages = 2 -- initialize, initialized local function wait_for_messages() - assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages)) + assert( + vim.wait(200, function() + return #server.messages == expected_messages + end), + 'Timed out waiting for expected number of messages. Current messages seen so far: ' + .. vim.inspect(server.messages) + ) end wait_for_messages() - local watch_callbacks = {} + local watch_callbacks = {} --- @type function[] local function send_event(...) for _, cb in ipairs(watch_callbacks) do cb(...) @@ -5318,12 +5747,14 @@ describe('LSP', function() local protocol = require('vim.lsp.protocol') local watchers = {} - local max_kind = protocol.WatchKind.Create + protocol.WatchKind.Change + protocol.WatchKind.Delete + local max_kind = protocol.WatchKind.Create + + protocol.WatchKind.Change + + protocol.WatchKind.Delete for i = 0, max_kind do table.insert(watchers, { globPattern = { baseUri = vim.uri_from_fname('/dir'), - pattern = 'watch'..tostring(i), + pattern = 'watch' .. tostring(i), }, kind = i, }) @@ -5351,9 +5782,7 @@ describe('LSP', function() wait_for_messages() return server.messages - ]], - root_dir - ) + end) local function watched_uri(fname) return vim.uri_from_fname('/dir/' .. fname) @@ -5364,51 +5793,51 @@ describe('LSP', function() eq({ changes = { { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + type = created, uri = watched_uri('watch1'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + type = changed, uri = watched_uri('watch2'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + type = created, uri = watched_uri('watch3'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + type = changed, uri = watched_uri('watch3'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + type = deleted, uri = watched_uri('watch4'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + type = created, uri = watched_uri('watch5'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + type = deleted, uri = watched_uri('watch5'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + type = changed, uri = watched_uri('watch6'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + type = deleted, uri = watched_uri('watch6'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + type = created, uri = watched_uri('watch7'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + type = changed, uri = watched_uri('watch7'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + type = deleted, uri = watched_uri('watch7'), }, }, @@ -5418,12 +5847,9 @@ describe('LSP', function() it('prunes duplicate events', function() local root_dir = 'some_dir' exec_lua(create_server_definition) - local result = exec_lua( - [[ - local root_dir = ... - - local server = _create_server() - local client_id = vim.lsp.start({ + local result = exec_lua(function() + local server = _G._create_server() + local client_id = assert(vim.lsp.start({ name = 'watchfiles-test', cmd = server.cmd, root_dir = root_dir, @@ -5434,16 +5860,22 @@ describe('LSP', function() }, }, }, - }) + })) local expected_messages = 2 -- initialize, initialized local function wait_for_messages() - assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages)) + assert( + vim.wait(200, function() + return #server.messages == expected_messages + end), + 'Timed out waiting for expected number of messages. Current messages seen so far: ' + .. vim.inspect(server.messages) + ) end wait_for_messages() - local send_event + local send_event --- @type function require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback) send_event = callback return function() @@ -5477,24 +5909,22 @@ describe('LSP', function() wait_for_messages() return server.messages - ]], - root_dir - ) + end) eq(3, #result) eq('workspace/didChangeWatchedFiles', result[3].method) eq({ changes = { { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + type = created, uri = vim.uri_from_fname('file1'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + type = changed, uri = vim.uri_from_fname('file1'), }, { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + type = created, uri = vim.uri_from_fname('file2'), }, }, @@ -5503,27 +5933,28 @@ describe('LSP', function() it("ignores registrations by servers when the client doesn't advertise support", function() exec_lua(create_server_definition) - exec_lua([[ - server = _create_server() - require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback) + exec_lua(function() + _G.server = _G._create_server() + require('vim.lsp._watchfiles')._watchfunc = function(_, _, _) -- Since the registration is ignored, this should not execute and `watching` should stay false - watching = true + _G.watching = true return function() end end - ]]) + end) local function check_registered(capabilities) - return exec_lua( - [[ - watching = false - local client_id = vim.lsp.start({ + return exec_lua(function() + _G.watching = false + local client_id = assert(vim.lsp.start({ name = 'watchfiles-test', - cmd = server.cmd, + cmd = _G.server.cmd, root_dir = 'some_dir', - capabilities = ..., + capabilities = capabilities, }, { - reuse_client = function() return false end, - }) + reuse_client = function() + return false + end, + })) vim.lsp.handlers['client/registerCapability'](nil, { registrations = { @@ -5552,10 +5983,8 @@ describe('LSP', function() }, { client_id = client_id }) vim.lsp.stop_client(client_id, true) - return watching - ]], - capabilities - ) + return _G.watching + end) end eq(is_os('mac') or is_os('win'), check_registered(nil)) -- start{_client}() defaults to make_client_capabilities(). diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua index 978178191c..6f0eeff748 100644 --- a/test/functional/plugin/man_spec.lua +++ b/test/functional/plugin/man_spec.lua @@ -8,7 +8,6 @@ local exec_lua = n.exec_lua local fn = n.fn local nvim_prog = n.nvim_prog local matches = t.matches -local write_file = t.write_file local tmpname = t.tmpname local eq = t.eq local pesc = vim.pesc @@ -17,21 +16,20 @@ local is_ci = t.is_ci -- Collects all names passed to find_path() after attempting ":Man foo". local function get_search_history(name) - local args = vim.split(name, ' ') - local code = [[ - local args = ... - local man = require('runtime.lua.man') + return exec_lua(function() + local args = vim.split(name, ' ') + local man = require('man') local res = {} - man.find_path = function(sect, name) - table.insert(res, {sect, name}) + --- @diagnostic disable-next-line:duplicate-set-field + man.find_path = function(sect, name0) + table.insert(res, { sect, name0 }) return nil end - local ok, rv = pcall(man.open_page, -1, {tab = 0}, args) + local ok, rv = pcall(man.open_page, -1, { tab = 0 }, args) assert(not ok) assert(rv and rv:match('no manual entry')) return res - ]] - return exec_lua(code, args) + end) end clear() @@ -117,6 +115,29 @@ describe(':Man', function() ]]) end) + it('clears OSC 8 hyperlink markup from text', function() + feed( + [[ + ithis <C-v><ESC>]8;;http://example.com<C-v><ESC>\Link Title<C-v><ESC>]8;;<C-v><ESC>\<ESC>]] + ) + + screen:expect { + grid = [=[ + this {c:^[}]8;;http://example.com{c:^[}\Link Title{c:^[}]8;;{c:^[}^\ | + {eob:~ }|*3 + | + ]=], + } + + exec_lua [[require'man'.init_pager()]] + + screen:expect([[ + ^this Link Title | + {eob:~ }|*3 + | + ]]) + end) + it('highlights multibyte text', function() feed( [[ @@ -203,7 +224,6 @@ describe(':Man', function() local actual_file = tmpname() -- actual_file must be an absolute path to an existent file for us to test against it matches('^/.+', actual_file) - write_file(actual_file, '') local args = { nvim_prog, '--headless', '+:Man ' .. actual_file, '+q' } matches( ('Error detected while processing command line:\r\n' .. 'man.lua: "no manual entry for %s"'):format( diff --git a/test/functional/plugin/msgpack_spec.lua b/test/functional/plugin/msgpack_spec.lua index 1d5d20ec02..61ab730da8 100644 --- a/test/functional/plugin/msgpack_spec.lua +++ b/test/functional/plugin/msgpack_spec.lua @@ -58,23 +58,11 @@ describe('autoload/msgpack.vim', function() msgpack_eq(1, '"abc\\ndef"', '"abc\\ndef"') msgpack_eq(0, '"abc\\ndef"', '"abc\\nghi"') end) - it('compares binary specials correctly', function() - msgpack_eq(1, sp('binary', '["abc\\n", "def"]'), sp('binary', '["abc\\n", "def"]')) - msgpack_eq(0, sp('binary', '["abc", "def"]'), sp('binary', '["abc\\n", "def"]')) - end) - it('compares binary specials with raw binaries correctly', function() - msgpack_eq(1, sp('binary', '["abc", "def"]'), '"abc\\ndef"') - msgpack_eq(0, sp('binary', '["abc", "def"]'), '"abcdef"') - end) it('compares string specials correctly', function() msgpack_eq(1, sp('string', '["abc\\n", "def"]'), sp('string', '["abc\\n", "def"]')) msgpack_eq(0, sp('string', '["abc", "def"]'), sp('string', '["abc\\n", "def"]')) - end) - it('compares string specials with binary correctly', function() - msgpack_eq(0, sp('string', '["abc\\n", "def"]'), sp('binary', '["abc\\n", "def"]')) - msgpack_eq(0, sp('string', '["abc", "def"]'), '"abc\\ndef"') - msgpack_eq(0, sp('binary', '["abc\\n", "def"]'), sp('string', '["abc\\n", "def"]')) - msgpack_eq(0, '"abc\\ndef"', sp('string', '["abc", "def"]')) + msgpack_eq(1, sp('string', '["abc", "def"]'), '"abc\\ndef"') + msgpack_eq(1, '"abc\\ndef"', sp('string', '["abc", "def"]')) end) it('compares ext specials correctly', function() msgpack_eq(1, sp('ext', '[1, ["", "ac"]]'), sp('ext', '[1, ["", "ac"]]')) @@ -92,20 +80,16 @@ describe('autoload/msgpack.vim', function() end) it('compares map specials correctly', function() msgpack_eq(1, mapsp(), mapsp()) - msgpack_eq(1, mapsp(sp('binary', '[""]'), '""'), mapsp(sp('binary', '[""]'), '""')) msgpack_eq( 1, mapsp(mapsp('1', '1'), mapsp('1', '1')), mapsp(mapsp('1', '1'), mapsp('1', '1')) ) msgpack_eq(0, mapsp(), mapsp('1', '1')) - msgpack_eq(0, mapsp(sp('binary', '["a"]'), '""'), mapsp(sp('binary', '[""]'), '""')) - msgpack_eq(0, mapsp(sp('binary', '[""]'), '"a"'), mapsp(sp('binary', '[""]'), '""')) - msgpack_eq(0, mapsp(sp('binary', '["a"]'), '"a"'), mapsp(sp('binary', '[""]'), '""')) msgpack_eq( 0, mapsp(mapsp('1', '1'), mapsp('1', '1')), - mapsp(sp('binary', '[""]'), mapsp('1', '1')) + mapsp(sp('string', '[""]'), mapsp('1', '1')) ) msgpack_eq( 0, @@ -138,7 +122,7 @@ describe('autoload/msgpack.vim', function() msgpack_eq(1, mapsp(sp('string', '["1"]'), '1'), '{"1": 1}') msgpack_eq(1, mapsp(sp('string', '["1"]'), sp('integer', '[1, 0, 0, 1]')), '{"1": 1}') msgpack_eq(0, mapsp(sp('integer', '[1, 0, 0, 1]'), sp('string', '["1"]')), '{1: "1"}') - msgpack_eq(0, mapsp('"1"', sp('integer', '[1, 0, 0, 1]')), '{"1": 1}') + msgpack_eq(1, mapsp('"1"', sp('integer', '[1, 0, 0, 1]')), '{"1": 1}') msgpack_eq(0, mapsp(sp('string', '["1"]'), '1', sp('string', '["2"]'), '2'), '{"1": 1}') msgpack_eq(0, mapsp(sp('string', '["1"]'), '1'), '{"1": 1, "2": 2}') end) @@ -290,7 +274,6 @@ describe('autoload/msgpack.vim', function() it('works for special dictionaries', function() type_eq('string', sp('string', '[""]')) - type_eq('binary', sp('binary', '[""]')) type_eq('ext', sp('ext', '[1, [""]]')) type_eq('array', sp('array', '[]')) type_eq('map', sp('map', '[]')) @@ -301,7 +284,7 @@ describe('autoload/msgpack.vim', function() end) it('works for regular values', function() - type_eq('binary', '""') + type_eq('string', '""') type_eq('array', '[]') type_eq('map', '{}') type_eq('integer', '1') @@ -319,7 +302,6 @@ describe('autoload/msgpack.vim', function() it('works for special dictionaries', function() sp_type_eq('string', sp('string', '[""]')) - sp_type_eq('binary', sp('binary', '[""]')) sp_type_eq('ext', sp('ext', '[1, [""]]')) sp_type_eq('array', sp('array', '[]')) sp_type_eq('map', sp('map', '[]')) @@ -347,12 +329,9 @@ describe('autoload/msgpack.vim', function() end it('works for special dictionaries', function() - string_eq('=""', sp('string', '[""]')) - string_eq('="\\n"', sp('string', '["", ""]')) - string_eq('="ab\\0c\\nde"', sp('string', '["ab\\nc", "de"]')) - string_eq('""', sp('binary', '[""]')) - string_eq('"\\n"', sp('binary', '["", ""]')) - string_eq('"ab\\0c\\nde"', sp('binary', '["ab\\nc", "de"]')) + string_eq('""', sp('string', '[""]')) + string_eq('"\\n"', sp('string', '["", ""]')) + string_eq('"ab\\0c\\nde"', sp('string', '["ab\\nc", "de"]')) string_eq('+(2)""', sp('ext', '[2, [""]]')) string_eq('+(2)"\\n"', sp('ext', '[2, ["", ""]]')) string_eq('+(2)"ab\\0c\\nde"', sp('ext', '[2, ["ab\\nc", "de"]]')) @@ -397,8 +376,8 @@ describe('autoload/msgpack.vim', function() string_eq('[]', '[]') string_eq('[[[{}]]]', '[[[{}]]]') string_eq('{}', '{}') - string_eq('{="2": 10}', '{2: 10}') - string_eq('{="2": [{}]}', '{2: [{}]}') + string_eq('{"2": 10}', '{2: 10}') + string_eq('{"2": [{}]}', '{2: [{}]}') string_eq('1', '1') string_eq('0.0', '0.0') string_eq('inf', '(1.0/0.0)') @@ -422,7 +401,6 @@ describe('autoload/msgpack.vim', function() nvim_command('let spflt = ' .. sp('float', '1.0')) nvim_command('let spext = ' .. sp('ext', '[2, ["abc", "def"]]')) nvim_command('let spstr = ' .. sp('string', '["abc", "def"]')) - nvim_command('let spbin = ' .. sp('binary', '["abc", "def"]')) nvim_command('let spbln = ' .. sp('boolean', '0')) nvim_command('let spnil = ' .. sp('nil', '0')) @@ -432,7 +410,6 @@ describe('autoload/msgpack.vim', function() nvim_command('let spflt2 = msgpack#deepcopy(spflt)') nvim_command('let spext2 = msgpack#deepcopy(spext)') nvim_command('let spstr2 = msgpack#deepcopy(spstr)') - nvim_command('let spbin2 = msgpack#deepcopy(spbin)') nvim_command('let spbln2 = msgpack#deepcopy(spbln)') nvim_command('let spnil2 = msgpack#deepcopy(spnil)') @@ -442,7 +419,6 @@ describe('autoload/msgpack.vim', function() eq('float', nvim_eval('msgpack#type(spflt2)')) eq('ext', nvim_eval('msgpack#type(spext2)')) eq('string', nvim_eval('msgpack#type(spstr2)')) - eq('binary', nvim_eval('msgpack#type(spbin2)')) eq('boolean', nvim_eval('msgpack#type(spbln2)')) eq('nil', nvim_eval('msgpack#type(spnil2)')) @@ -457,7 +433,6 @@ describe('autoload/msgpack.vim', function() nvim_command('let spext._VAL[0] = 3') nvim_command('let spext._VAL[1][0] = "gh"') nvim_command('let spstr._VAL[0] = "gh"') - nvim_command('let spbin._VAL[0] = "gh"') nvim_command('let spbln._VAL = 1') nvim_command('let spnil._VAL = 1') @@ -467,7 +442,6 @@ describe('autoload/msgpack.vim', function() eq({ _TYPE = {}, _VAL = 1.0 }, nvim_eval('spflt2')) eq({ _TYPE = {}, _VAL = { 2, { 'abc', 'def' } } }, nvim_eval('spext2')) eq({ _TYPE = {}, _VAL = { 'abc', 'def' } }, nvim_eval('spstr2')) - eq({ _TYPE = {}, _VAL = { 'abc', 'def' } }, nvim_eval('spbin2')) eq({ _TYPE = {}, _VAL = 0 }, nvim_eval('spbln2')) eq({ _TYPE = {}, _VAL = 0 }, nvim_eval('spnil2')) @@ -477,7 +451,6 @@ describe('autoload/msgpack.vim', function() nvim_command('let spflt._TYPE = []') nvim_command('let spext._TYPE = []') nvim_command('let spstr._TYPE = []') - nvim_command('let spbin._TYPE = []') nvim_command('let spbln._TYPE = []') nvim_command('let spnil._TYPE = []') @@ -487,7 +460,6 @@ describe('autoload/msgpack.vim', function() eq('float', nvim_eval('msgpack#special_type(spflt2)')) eq('ext', nvim_eval('msgpack#special_type(spext2)')) eq('string', nvim_eval('msgpack#special_type(spstr2)')) - eq('binary', nvim_eval('msgpack#special_type(spbin2)')) eq('boolean', nvim_eval('msgpack#special_type(spbln2)')) eq('nil', nvim_eval('msgpack#special_type(spnil2)')) end) @@ -509,7 +481,7 @@ describe('autoload/msgpack.vim', function() eq('map', nvim_eval('msgpack#type(map2)')) eq('integer', nvim_eval('msgpack#type(int2)')) eq('float', nvim_eval('msgpack#type(flt2)')) - eq('binary', nvim_eval('msgpack#type(bin2)')) + eq('string', nvim_eval('msgpack#type(bin2)')) nvim_command('call add(arr, 0)') nvim_command('call add(arr[0], 0)') @@ -566,21 +538,6 @@ describe('autoload/msgpack.vim', function() nvim_command('unlet g:__val') end - it('correctly loads binary strings', function() - eval_eq('binary', { 'abcdef' }, '"abcdef"') - eval_eq('binary', { 'abc', 'def' }, '"abc\\ndef"') - eval_eq('binary', { 'abc\ndef' }, '"abc\\0def"') - eval_eq('binary', { '\nabc\ndef\n' }, '"\\0abc\\0def\\0"') - eval_eq('binary', { 'abc\n\n\ndef' }, '"abc\\0\\0\\0def"') - eval_eq('binary', { 'abc\n', '\ndef' }, '"abc\\0\\n\\0def"') - eval_eq('binary', { 'abc', '', '', 'def' }, '"abc\\n\\n\\ndef"') - eval_eq('binary', { 'abc', '', '', 'def', '' }, '"abc\\n\\n\\ndef\\n"') - eval_eq('binary', { '', 'abc', '', '', 'def' }, '"\\nabc\\n\\n\\ndef"') - eval_eq('binary', { '' }, '""') - eval_eq('binary', { '"' }, '"\\""') - eval_eq('binary', { 'py3 print(sys.version_info)' }, '"py3 print(sys.version_info)"') - end) - it('correctly loads strings', function() eval_eq('string', { 'abcdef' }, '="abcdef"') eval_eq('string', { 'abc', 'def' }, '="abc\\ndef"') diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua index 1c2bcbd497..c9d49f7d01 100644 --- a/test/functional/plugin/shada_spec.lua +++ b/test/functional/plugin/shada_spec.lua @@ -68,7 +68,7 @@ describe('autoload/shada.vim', function() endfor return ret elseif type(a:val) == type('') - return {'_TYPE': v:msgpack_types.binary, '_VAL': split(a:val, "\n", 1)} + return {'_TYPE': v:msgpack_types.string, '_VAL': split(a:val, "\n", 1)} else return a:val endif @@ -253,8 +253,7 @@ describe('autoload/shada.vim', function() ' + sm magic value "TRUE"', ' # Expected integer', ' + so offset value "TRUE"', - ' # Expected binary string', - ' + sp pattern ="abc"', + ' + sp pattern "abc"', }, ([[ [{'type': 1, 'timestamp': 0, 'data': { 'sm': 'TRUE', @@ -267,7 +266,7 @@ describe('autoload/shada.vim', function() 'n': -0x40, 'l': -10, 'c': 'abc', - 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]}, + 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]}, }}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -276,15 +275,14 @@ describe('autoload/shada.vim', function() ' % Key Description Value', ' # Expected no NUL bytes', ' + f file name "abc\\0def"', - ' # Expected array of binary strings', - ' + rc contents ["abc", ="abc"]', + ' + rc contents ["abc", "abc"]', ' # Expected integer', ' + rt type "ABC"', }, ([[ [{'type': 1, 'timestamp': 0, 'data': { 'rt': 'ABC', 'rc': ["abc", {'_TYPE': v:msgpack_types.string, '_VAL': ["abc"]}], - 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]}, + 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]}, }}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -295,7 +293,7 @@ describe('autoload/shada.vim', function() ' + rc contents ["abc", "a\\nd\\0"]', }, ([[ [{'type': 1, 'timestamp': 0, 'data': { - 'rc': ["abc", {'_TYPE': v:msgpack_types.binary, '_VAL': ["a", "d\n"]}], + 'rc': ["abc", {'_TYPE': v:msgpack_types.string, '_VAL': ["a", "d\n"]}], }}] ]]):gsub('\n', '') ) end) @@ -468,7 +466,7 @@ describe('autoload/shada.vim', function() sd2strings_eq({ 'Replacement string with timestamp ' .. epoch .. ':', ' # Unexpected type: map instead of array', - ' = {="a": [10]}', + ' = {"a": [10]}', }, { { type = 3, timestamp = 0, data = { a = { 10 } } } }) sd2strings_eq( { @@ -498,7 +496,7 @@ describe('autoload/shada.vim', function() ' - :s replacement string "abc\\0def"', }, ([[ [{'type': 3, 'timestamp': 0, 'data': [ - {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]}, + {'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]}, ]}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -508,7 +506,7 @@ describe('autoload/shada.vim', function() ' - :s replacement string "abc\\ndef"', }, ([[ [{'type': 3, 'timestamp': 0, 'data': [ - {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc", "def"]}, + {'_TYPE': v:msgpack_types.string, '_VAL': ["abc", "def"]}, ]}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -519,7 +517,7 @@ describe('autoload/shada.vim', function() ' - 0', }, ([[ [{'type': 3, 'timestamp': 0, 'data': [ - {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc", "def"]}, + {'_TYPE': v:msgpack_types.string, '_VAL': ["abc", "def"]}, 0, ]}] ]]):gsub('\n', '') ) @@ -529,7 +527,7 @@ describe('autoload/shada.vim', function() sd2strings_eq({ 'History entry with timestamp ' .. epoch .. ':', ' # Unexpected type: map instead of array', - ' = {="a": [10]}', + ' = {"a": [10]}', }, { { type = 4, timestamp = 0, data = { a = { 10 } } } }) sd2strings_eq( { @@ -682,7 +680,7 @@ describe('autoload/shada.vim', function() }, ([[ [{'type': 4, 'timestamp': 0, 'data': [ 4, - {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]}, + {'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]}, ]}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -909,7 +907,7 @@ describe('autoload/shada.vim', function() sd2strings_eq({ 'Variable with timestamp ' .. epoch .. ':', ' # Unexpected type: map instead of array', - ' = {="a": [10]}', + ' = {"a": [10]}', }, { { type = 6, timestamp = 0, data = { a = { 10 } } } }) sd2strings_eq( { @@ -941,7 +939,7 @@ describe('autoload/shada.vim', function() ' # Expected more elements in list', }, ([[ [{'type': 6, 'timestamp': 0, 'data': [ - {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]}, + {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]}, ]}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -952,7 +950,7 @@ describe('autoload/shada.vim', function() ' # Expected more elements in list', }, ([[ [{'type': 6, 'timestamp': 0, 'data': [ - {'_TYPE': v:msgpack_types.binary, '_VAL': ["foo"]}, + {'_TYPE': v:msgpack_types.string, '_VAL': ["foo"]}, ]}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -963,7 +961,7 @@ describe('autoload/shada.vim', function() ' - value NIL', }, ([[ [{'type': 6, 'timestamp': 0, 'data': [ - {'_TYPE': v:msgpack_types.binary, '_VAL': ["foo"]}, + {'_TYPE': v:msgpack_types.string, '_VAL': ["foo"]}, {'_TYPE': v:msgpack_types.nil, '_VAL': ["foo"]}, ]}] ]]):gsub('\n', '') ) @@ -976,7 +974,7 @@ describe('autoload/shada.vim', function() ' - NIL', }, ([[ [{'type': 6, 'timestamp': 0, 'data': [ - {'_TYPE': v:msgpack_types.binary, '_VAL': ["foo"]}, + {'_TYPE': v:msgpack_types.string, '_VAL': ["foo"]}, {'_TYPE': v:msgpack_types.nil, '_VAL': ["foo"]}, {'_TYPE': v:msgpack_types.nil, '_VAL': ["foo"]}, ]}] ]]):gsub('\n', '') @@ -1041,7 +1039,7 @@ describe('autoload/shada.vim', function() }, ([[ [{'type': 7, 'timestamp': 0, 'data': { 'n': -10, - 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]}, + 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]}, }}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -1174,7 +1172,7 @@ describe('autoload/shada.vim', function() }, ([[ [{'type': 8, 'timestamp': 0, 'data': { 'n': -10, - 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]}, + 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]}, }}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -1237,7 +1235,7 @@ describe('autoload/shada.vim', function() sd2strings_eq({ 'Buffer list with timestamp ' .. epoch .. ':', ' # Unexpected type: map instead of array', - ' = {="a": [10]}', + ' = {"a": [10]}', }, { { type = 9, timestamp = 0, data = { a = { 10 } } } }) sd2strings_eq({ 'Buffer list with timestamp ' .. epoch .. ':', @@ -1247,7 +1245,7 @@ describe('autoload/shada.vim', function() sd2strings_eq({ 'Buffer list with timestamp ' .. epoch .. ':', ' # Expected array of maps', - ' = [{="a": 10}, []]', + ' = [{"a": 10}, []]', }, { { type = 9, timestamp = 0, data = { { a = 10 }, {} } } }) sd2strings_eq({ 'Buffer list with timestamp ' .. epoch .. ':', @@ -1322,7 +1320,7 @@ describe('autoload/shada.vim', function() }, ([[ [{'type': 9, 'timestamp': 0, 'data': [ {'f': 10}, - {'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]}}, + {'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]}}, ]}] ]]):gsub('\n', '') ) end) @@ -1385,7 +1383,7 @@ describe('autoload/shada.vim', function() }, ([[ [{'type': 10, 'timestamp': 0, 'data': { 'n': -10, - 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]}, + 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]}, }}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -1504,7 +1502,7 @@ describe('autoload/shada.vim', function() }, ([[ [{'type': 11, 'timestamp': 0, 'data': { 'n': -10, - 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]}, + 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]}, }}] ]]):gsub('\n', '') ) sd2strings_eq( @@ -1616,7 +1614,7 @@ describe('autoload/shada.vim', function() timestamp = 0, data = { c = 'abc', - f = { '!binary', { 'abc\ndef' } }, + f = { '!string', { 'abc\ndef' } }, l = -10, n = -64, rc = '10', @@ -1711,7 +1709,7 @@ describe('autoload/shada.vim', function() timestamp = 0, data = { c = 'abc', - f = { '!binary', { 'abc\ndef' } }, + f = { '!string', { 'abc\ndef' } }, l = -10, n = -64, rc = '10', @@ -1892,7 +1890,7 @@ describe('autoload/shada.vim', function() } } }, { 'Replacement string with timestamp ' .. epoch .. ':', ' # Unexpected type: map instead of array', - ' = {="a": [10]}', + ' = {"a": [10]}', }) strings2sd_eq({ { type = 3, timestamp = 0, data = {} } }, { 'Replacement string with timestamp ' .. epoch .. ':', @@ -1934,7 +1932,7 @@ describe('autoload/shada.vim', function() } } }, { 'History entry with timestamp ' .. epoch .. ':', ' # Unexpected type: map instead of array', - ' = {="a": [10]}', + ' = {"a": [10]}', }) strings2sd_eq({ { type = 4, timestamp = 0, data = {} } }, { 'History entry with timestamp ' .. epoch .. ':', @@ -2184,7 +2182,7 @@ describe('autoload/shada.vim', function() } } }, { 'Variable with timestamp ' .. epoch .. ':', ' # Unexpected type: map instead of array', - ' = {="a": [10]}', + ' = {"a": [10]}', }) strings2sd_eq({ { type = 6, timestamp = 0, data = {} } }, { 'Variable with timestamp ' .. epoch .. ':', @@ -2315,7 +2313,7 @@ describe('autoload/shada.vim', function() } } }, { 'Buffer list with timestamp ' .. epoch .. ':', ' # Unexpected type: map instead of array', - ' = {="a": [10]}', + ' = {"a": [10]}', }) strings2sd_eq( { { type = 9, timestamp = 0, data = { @@ -2325,7 +2323,7 @@ describe('autoload/shada.vim', function() { 'Buffer list with timestamp ' .. epoch .. ':', ' # Expected array of maps', - ' = [{="a": 10}, []]', + ' = [{"a": 10}, []]', } ) strings2sd_eq({ { type = 9, timestamp = 0, data = { @@ -2421,7 +2419,7 @@ describe('autoload/shada.vim', function() timestamp = 0, data = { { f = 10 }, - { f = { '!binary', { '\n' } } }, + { f = { '!string', { '\n' } } }, }, }, }, { @@ -2955,7 +2953,7 @@ describe('ftplugin/shada.vim', function() ' - :s replacement string "abc\\ndef"', ' Buffer list with timestamp ' .. epoch .. ':', ' # Expected array of maps', - '= [{="a": 10}, []]', + '= [{"a": 10}, []]', ' Buffer list with timestamp ' .. epoch .. ':', ' % Key Description Value', ' # Expected binary string', @@ -2992,7 +2990,7 @@ describe('ftplugin/shada.vim', function() ' - :s replacement string "abc\\ndef"', 'Buffer list with timestamp ' .. epoch .. ':', ' # Expected array of maps', - ' = [{="a": 10}, []]', + ' = [{"a": 10}, []]', 'Buffer list with timestamp ' .. epoch .. ':', ' % Key Description Value', ' # Expected binary string', @@ -3083,7 +3081,7 @@ describe('syntax/shada.vim', function() ' - :s replacement string DEBUG', 'Buffer list with timestamp ' .. epoch .. ':', ' # Expected array of maps', - ' = [{="a": +(10)"ac\\0df\\ngi\\"tt\\.", TRUE: FALSE}, [NIL, +(-10)""]]', + ' = [{"a": +(10)"ac\\0df\\ngi\\"tt\\.", TRUE: FALSE}, [NIL, +(-10)""]]', 'Buffer list with timestamp ' .. epoch .. ':', ' % Key Description Value', '', @@ -3119,8 +3117,8 @@ describe('syntax/shada.vim', function() {1: -} {4::s replacement string} {1:DEBUG} | {1:Buffer list} with timestamp 1970{1:-}01{1:-}01{1:T}00{1::}00{1::}00: | {4: # Expected array of maps} | - = {1:[{="}{3:a}{1:":} {1:+(}{5:10}{1:)"}{3:ac}{6:\0}{3:df}{6:\n}{3:gi}{6:\"}{3:tt\.}{1:",} {1:TRUE:} {1:FALSE},} {1:[NIL,} {1:+(}{5:-}| - {5:10}{1:)""]]} | + = {1:[{"}{3:a}{1:":} {1:+(}{5:10}{1:)"}{3:ac}{6:\0}{3:df}{6:\n}{3:gi}{6:\"}{3:tt\.}{1:",} {1:TRUE:} {1:FALSE},} {1:[NIL,} {1:+(}{5:-1}| + {5:0}{1:)""]]} | {1:Buffer list} with timestamp 1970{1:-}01{1:-}01{1:T}00{1::}00{1::}00: | {2: % Key Description Value} | | @@ -3464,7 +3462,6 @@ describe('syntax/shada.vim', function() { { 'ShaDaEntryRawMsgpack' }, ' = ' }, { { 'ShaDaMsgpackArray', 'ShaDaMsgpackArrayBraces' }, '[' }, { { 'ShaDaMsgpackArray', 'ShaDaMsgpackMap', 'ShaDaMsgpackMapBraces' }, '{' }, - { { 'ShaDaMsgpackArray', 'ShaDaMsgpackMap', 'ShaDaMsgpackString' }, '=' }, { { 'ShaDaMsgpackArray', diff --git a/test/functional/plugin/tohtml_spec.lua b/test/functional/plugin/tohtml_spec.lua index 200a5f34b2..1d05f4d6b4 100644 --- a/test/functional/plugin/tohtml_spec.lua +++ b/test/functional/plugin/tohtml_spec.lua @@ -33,6 +33,10 @@ local function html_syntax_match() attr.underline = nil attr.undercurl = true end + attr.sp = style:match('text%-decoration%-color: #(%x+)') + if attr.sp then + attr.sp = tonumber(attr.sp, 16) + end attr.bg = style:match('background%-color: #(%x+)') if attr.bg then attr.bg = tonumber(attr.bg, 16) @@ -49,7 +53,7 @@ local function html_syntax_match() local whitelist = { 'fg', 'bg', - --'sp', + 'sp', --'blend', 'bold', --'standout', @@ -132,6 +136,50 @@ local function run_tohtml_and_assert(screen, func) screen:expect({ grid = expected.grid, attr_ids = expected.attr_ids }) end +---@param guifont boolean +local function test_generates_html(guifont, expect_font) + insert([[line]]) + exec('set termguicolors') + local bg = fn.synIDattr(fn.hlID('Normal'), 'bg#', 'gui') + local fg = fn.synIDattr(fn.hlID('Normal'), 'fg#', 'gui') + local tmpfile = t.tmpname() + + exec_lua( + [[ + local guifont, outfile = ... + local html = (guifont + and require('tohtml').tohtml(0,{title="title"}) + or require('tohtml').tohtml(0,{title="title",font={ "dumyfont","anotherfont" }})) + vim.fn.writefile(html, outfile) + vim.cmd.split(outfile) + ]], + guifont, + tmpfile + ) + + local out_file = api.nvim_buf_get_name(api.nvim_get_current_buf()) + eq({ + '<!DOCTYPE html>', + '<html>', + '<head>', + '<meta charset="UTF-8">', + '<title>title</title>', + ('<meta name="colorscheme" content="%s"></meta>'):format(api.nvim_get_var('colors_name')), + '<style>', + ('* {font-family: %s,monospace}'):format(expect_font), + ('body {background-color: %s; color: %s}'):format(bg, fg), + '</style>', + '</head>', + '<body style="display: flex">', + '<pre>', + 'line', + '', + '</pre>', + '</body>', + '</html>', + }, fn.readfile(out_file)) +end + describe(':TOhtml', function() --- @type test.functional.ui.screen local screen @@ -142,33 +190,44 @@ describe(':TOhtml', function() exec('colorscheme default') end) - it('expected internal html generated', function() - insert([[line]]) + it('generates html with given font', function() + test_generates_html(false, '"dumyfont","anotherfont"') + end) + + it("generates html, respects 'guifont'", function() + exec_lua [[vim.o.guifont='Font,Escape\\,comma, Ignore space after comma']] + test_generates_html(true, '"Font","Escape,comma","Ignore space after comma"') + end) + + it('generates html from range', function() + insert([[ + line1 + line2 + line3 + ]]) + local ns = api.nvim_create_namespace '' + api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 1, end_row = 1, hl_group = 'Visual' }) exec('set termguicolors') local bg = fn.synIDattr(fn.hlID('Normal'), 'bg#', 'gui') local fg = fn.synIDattr(fn.hlID('Normal'), 'fg#', 'gui') - exec_lua [[ - local outfile = vim.fn.tempname() .. '.html' - local html = require('tohtml').tohtml(0,{title="title",font="dumyfont"}) - vim.fn.writefile(html, outfile) - vim.cmd.split(outfile) - ]] + n.command('2,2TOhtml') local out_file = api.nvim_buf_get_name(api.nvim_get_current_buf()) eq({ '<!DOCTYPE html>', '<html>', '<head>', '<meta charset="UTF-8">', - '<title>title</title>', + '<title></title>', ('<meta name="colorscheme" content="%s"></meta>'):format(api.nvim_get_var('colors_name')), '<style>', - '* {font-family: dumyfont,monospace}', + '* {font-family: monospace}', ('body {background-color: %s; color: %s}'):format(bg, fg), + '.Visual {background-color: #9b9ea4}', '</style>', '</head>', '<body style="display: flex">', - '<pre>', - 'line', + '<pre><span class="Visual">', + 'l</span>ine2', '', '</pre>', '</body>', @@ -176,9 +235,9 @@ describe(':TOhtml', function() }, fn.readfile(out_file)) end) - it('highlight attributes generated', function() + it('generates highlight attributes', function() --Make sure to uncomment the attribute in `html_syntax_match()` - exec('hi LINE gui=' .. table.concat({ + exec('hi LINE guisp=#00ff00 gui=' .. table.concat({ 'bold', 'underline', 'italic', @@ -287,7 +346,13 @@ describe(':TOhtml', function() 0, { virt_text = { { 'foo' } }, virt_text_pos = 'overlay' } ) - api.nvim_buf_set_extmark(0, ns, 2, 0, { virt_text = { { 'foo' } }, virt_text_pos = 'inline' }) + api.nvim_buf_set_extmark( + 0, + ns, + 2, + 0, + { virt_text = { { 'fo┊o', { 'Conceal', 'Comment' } } }, virt_text_pos = 'inline' } + ) --api.nvim_buf_set_extmark(0,ns,3,0,{virt_text={{'foo'}},virt_text_pos='right_align'}) run_tohtml_and_assert(screen) end) @@ -341,12 +406,12 @@ describe(':TOhtml', function() local function run() local buf = api.nvim_get_current_buf() run_tohtml_and_assert(screen, function() - exec_lua [[ - local outfile = vim.fn.tempname() .. '.html' - local html = require('tohtml').tohtml(0,{number_lines=true}) - vim.fn.writefile(html, outfile) - vim.cmd.split(outfile) - ]] + exec_lua(function() + local outfile = vim.fn.tempname() .. '.html' + local html = require('tohtml').tohtml(0, { number_lines = true }) + vim.fn.writefile(html, outfile) + vim.cmd.split(outfile) + end) end) api.nvim_set_current_buf(buf) end diff --git a/test/functional/provider/clipboard_spec.lua b/test/functional/provider/clipboard_spec.lua index 9e7df0ba6b..1094f9f4e5 100644 --- a/test/functional/provider/clipboard_spec.lua +++ b/test/functional/provider/clipboard_spec.lua @@ -94,12 +94,6 @@ describe('clipboard', function() before_each(function() clear() screen = Screen.new(72, 4) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - [2] = { bold = true, foreground = Screen.colors.SeaGreen4 }, - [3] = { bold = true, reverse = true }, - }) screen:attach() end) @@ -114,13 +108,13 @@ describe('clipboard', function() feed('"+yl') screen:expect([[ ^a | - {0:~ }|*2 + {1:~ }|*2 clipboard: No provider. Try ":checkhealth" or ":h clipboard". | ]]) feed('"+p') screen:expect([[ a^a | - {0:~ }|*2 + {1:~ }|*2 clipboard: No provider. Try ":checkhealth" or ":h clipboard". | ]]) end) @@ -132,19 +126,19 @@ describe('clipboard', function() feed('yl') screen:expect([[ ^a | - {0:~ }|*2 + {1:~ }|*2 clipboard: No provider. Try ":checkhealth" or ":h clipboard". | ]]) feed(':<CR>') screen:expect([[ ^a | - {0:~ }|*2 + {1:~ }|*2 : | ]]) feed('p') screen:expect([[ a^a | - {0:~ }|*2 + {1:~ }|*2 : | ]]) end) @@ -154,7 +148,7 @@ describe('clipboard', function() feed_command('redir @+> | :silent echo system("cat CONTRIBUTING.md") | redir END') screen:expect([[ ^ | - {0:~ }|*2 + {1:~ }|*2 clipboard: No provider. Try ":checkhealth" or ":h clipboard". | ]]) end) @@ -166,8 +160,8 @@ describe('clipboard', function() grid = [[ {3: }| clipboard: No provider. Try ":checkhealth" or ":h clipboard". | - {1:E492: Not an editor command: bogus_cmd | redir END} | - {2:Press ENTER or type command to continue}^ | + {9:E492: Not an editor command: bogus_cmd | redir END} | + {6:Press ENTER or type command to continue}^ | ]], } end) @@ -182,7 +176,7 @@ describe('clipboard', function() feed_command('let @+="foo"') screen:expect([[ ^ | - {0:~ }|*2 + {1:~ }|*2 clipboard: No provider. Try ":checkhealth" or ":h clipboard". | ]]) end) @@ -325,15 +319,11 @@ describe('clipboard (with fake clipboard.vim)', function() it('`:redir @+>|bogus_cmd|redir END` must not recurse #7184', function() local screen = Screen.new(72, 4) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - }) feed_command('redir @+> | bogus_cmd | redir END') screen:expect([[ ^ | - {0:~ }|*2 - {1:E492: Not an editor command: bogus_cmd | redir END} | + {1:~ }|*2 + {9:E492: Not an editor command: bogus_cmd | redir END} | ]]) end) @@ -719,9 +709,6 @@ describe('clipboard (with fake clipboard.vim)', function() feed_command('set mouse=a') local screen = Screen.new(30, 5) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - }) screen:attach() insert([[ the source @@ -731,7 +718,7 @@ describe('clipboard (with fake clipboard.vim)', function() screen:expect([[ the ^source | a target | - {0:~ }|*2 + {1:~ }|*2 | ]]) diff --git a/test/functional/script/luacats_grammar_spec.lua b/test/functional/script/luacats_grammar_spec.lua index 6d444e1888..8bc55879d4 100644 --- a/test/functional/script/luacats_grammar_spec.lua +++ b/test/functional/script/luacats_grammar_spec.lua @@ -159,4 +159,129 @@ describe('luacats grammar', function() name = 'type', type = '`T`', }) + + test('@param type [number,string,"good"|"bad"] this is a tuple type', { + desc = 'this is a tuple type', + kind = 'param', + name = 'type', + type = '[number,string,"good"|"bad"]', + }) + + test('@class vim.diagnostic.JumpOpts', { + kind = 'class', + name = 'vim.diagnostic.JumpOpts', + }) + + test('@class vim.diagnostic.JumpOpts : vim.diagnostic.GetOpts', { + kind = 'class', + name = 'vim.diagnostic.JumpOpts', + parent = 'vim.diagnostic.GetOpts', + }) + + test('@param opt? { cmd?: string[] } Options', { + kind = 'param', + name = 'opt?', + type = '{ cmd?: string[] }', + desc = 'Options', + }) + + ---@type [string, string?][] + local test_cases = { + { 'foo' }, + { 'foo ', 'foo' }, -- trims whitespace + { 'true' }, + { 'vim.type' }, + { 'vim-type' }, + { 'vim_type' }, + { 'foo.bar-baz_baz' }, + { '`ABC`' }, + { '42' }, + { '-42' }, + { '(foo)', 'foo' }, -- removes unnecessary parens + { 'true?' }, + { '(true)?' }, + { 'string[]' }, + { 'string|number' }, + { '(string)[]' }, + { '(string|number)[]' }, + { 'coalesce??', 'coalesce?' }, -- removes unnecessary ? + { 'number?|string' }, + { "'foo'|'bar'|'baz'" }, + { '"foo"|"bar"|"baz"' }, + { '(number)?|string' }, -- + { 'number[]|string' }, + { 'string[]?' }, + { 'foo?[]' }, + { 'vim.type?|string? ', 'vim.type?|string?' }, + { 'number[][]' }, + { 'number[][][]' }, + { 'number[][]?' }, + { 'string|integer[][]?' }, + + -- tuples + { '[string]' }, + { '[1]' }, + { '[string, number]' }, + { '[string, number]?' }, + { '[string, number][]' }, + { '[string, number]|string' }, + { '[string|number, number?]' }, + { 'string|[string, number]' }, + { '(true)?|[foo]' }, + { '[fun(a: string):boolean]' }, + + -- dict + { '{[string]:string}' }, + { '{ [ string ] : string }' }, + { '{ [ string|any ] : string }' }, + { '{[string]: string, [number]: boolean}' }, + + -- key-value table + { 'table<string,any>' }, + { 'table' }, + { 'string|table|boolean' }, + { 'string|table|(boolean)' }, + + -- table literal + { '{foo: number}' }, + { '{foo: string, bar: [number, boolean]?}' }, + { 'boolean|{reverse?:boolean}' }, + { '{ cmd?: string[] }' }, + + -- function + { 'fun(a: string, b:foo|bar): string' }, + { 'fun(a?: string): string' }, + { 'fun(a?: string): number?,string?' }, + { '(fun(a: string, b:foo|bar): string)?' }, + { 'fun(a: string, b:foo|bar): string, string' }, + { 'fun(a: string, b:foo|bar)' }, + { 'fun(_, foo, bar): string' }, + { 'fun(...): number' }, + { 'fun( ... ): number' }, + { 'fun(...:number): number' }, + { 'fun( ... : number): number' }, + + -- generics + { 'elem_or_list<string>' }, + { + 'elem_or_list<fun(client: vim.lsp.Client, initialize_result: lsp.InitializeResult)>', + nil, + }, + } + + for _, tc in ipairs(test_cases) do + local ty, exp_ty = tc[1], tc[2] + if exp_ty == nil then + exp_ty = ty + end + + local var, desc = 'x', 'some desc' + local param = string.format('@param %s %s %s', var, ty, desc) + test(param, { + kind = 'param', + name = var, + type = exp_ty, + desc = desc, + }) + end end) diff --git a/test/functional/script/text_utils_spec.lua b/test/functional/script/text_utils_spec.lua index 176c2ef816..74098b9287 100644 --- a/test/functional/script/text_utils_spec.lua +++ b/test/functional/script/text_utils_spec.lua @@ -11,8 +11,8 @@ local function md_to_vimdoc(text, start_indent, indent, text_width) start_indent = start_indent or 0 indent = indent or 0 text_width = text_width or 70 - local text_utils = require('scripts/text_utils') - return text_utils.md_to_vimdoc(table.concat(text, '\n'), start_indent, indent, text_width) + local util = require('scripts/util') + return util.md_to_vimdoc(table.concat(text, '\n'), start_indent, indent, text_width) ]], text, start_indent, diff --git a/test/functional/shada/errors_spec.lua b/test/functional/shada/errors_spec.lua index a9084da929..0016e0bdf9 100644 --- a/test/functional/shada/errors_spec.lua +++ b/test/functional/shada/errors_spec.lua @@ -28,7 +28,7 @@ describe('ShaDa error handling', function() it('fails on zero', function() wshada('\000') eq( - 'Vim(rshada):E576: Error while reading ShaDa file: expected positive integer at position 0, but got nothing', + 'Vim(rshada):E576: Error while reading ShaDa file: expected positive integer at position 1, but got nothing', exc_exec(sdrcmd()) ) end) @@ -58,7 +58,7 @@ describe('ShaDa error handling', function() it('fails on search pattern item with zero length', function() wshada('\002\000\000') eq( - 'Vim(rshada):E576: Failed to parse ShaDa file: incomplete msgpack string at position 3', + 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 is not a dict', exc_exec(sdrcmd()) ) end) @@ -89,18 +89,10 @@ describe('ShaDa error handling', function() it('fails on search pattern item with invalid byte', function() -- 195 (== 0xC1) cannot start any valid messagepack entry (the only byte - -- that cannot do this). Specifically unpack_template.h contains - -- - -- //case 0xc1: // string - -- // again_terminal_trail(NEXT_CS(p), p+1); - -- - -- (literally: commented out code) which means that in place of this code - -- `goto _failed` is used from default: case. I do not know any other way to - -- get MSGPACK_UNPACK_PARSE_ERROR and not MSGPACK_UNPACK_CONTINUE or - -- MSGPACK_UNPACK_EXTRA_BYTES. + -- that cannot do this) wshada('\002\000\001\193') eq( - 'Vim(rshada):E576: Failed to parse ShaDa file due to a msgpack parser error at position 3', + 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 is not a dict', exc_exec(sdrcmd()) ) end) @@ -108,7 +100,7 @@ describe('ShaDa error handling', function() it('fails on search pattern item with incomplete map', function() wshada('\002\000\001\129') eq( - 'Vim(rshada):E576: Failed to parse ShaDa file: incomplete msgpack string at position 3', + 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has key value which is not a string', exc_exec(sdrcmd()) ) end) @@ -124,7 +116,7 @@ describe('ShaDa error handling', function() it('fails on search pattern with extra bytes', function() wshada('\002\000\002\128\000') eq( - 'Vim(rshada):E576: Failed to parse ShaDa file: extra bytes in msgpack string at position 3', + 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has no pattern', exc_exec(sdrcmd()) ) end) @@ -132,16 +124,7 @@ describe('ShaDa error handling', function() it('fails on search pattern item with NIL value', function() wshada('\002\000\001\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 is not a dictionary', - exc_exec(sdrcmd()) - ) - end) - - -- sp entry is here because it causes an allocation. - it('fails on search pattern item with BIN key', function() - wshada('\002\000\014\131\162sp\196\001a\162sX\192\196\000\000') - eq( - 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has key which is not a string', + 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 is not a dict', exc_exec(sdrcmd()) ) end) @@ -235,35 +218,16 @@ describe('ShaDa error handling', function() ) end) - it('fails on search pattern item with STR pat key value', function() - wshada('\002\000\011\130\162sX\192\162sp\162sp') - eq( - 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has sp key value which is not a binary', - exc_exec(sdrcmd()) - ) - end) - for _, v in ipairs({ { name = 'global mark', mpack = '\007' }, { name = 'jump', mpack = '\008' }, { name = 'local mark', mpack = '\010' }, { name = 'change', mpack = '\011' }, }) do - local is_mark_test = ({ ['global mark'] = true, ['local mark'] = true })[v.name] - it('fails on ' .. v.name .. ' item with NIL value', function() wshada(v.mpack .. '\000\001\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 is not a dictionary', - exc_exec(sdrcmd()) - ) - end) - - -- f entry is here because it causes an allocation. - it('fails on ' .. v.name .. ' item with BIN key', function() - wshada(v.mpack .. '\000\013\131\161f\196\001/\162mX\192\196\000\000') - eq( - 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has key which is not a string', + 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 is not a dict', exc_exec(sdrcmd()) ) end) @@ -312,9 +276,7 @@ describe('ShaDa error handling', function() it('fails on ' .. v.name .. ' item with STR n key value', function() wshada(v.mpack .. '\000\011\130\162mX\192\161n\163spa') eq( - is_mark_test - and 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has n key value which is not an unsigned integer' - or 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has n key which is only valid for local and global mark entries', + 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has n key value which is not an integer', exc_exec(sdrcmd()) ) end) @@ -334,29 +296,12 @@ describe('ShaDa error handling', function() exc_exec(sdrcmd()) ) end) - - it('fails on ' .. v.name .. ' item with STR f key value', function() - wshada(v.mpack .. '\000\010\130\162mX\192\161f\162sp') - eq( - 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has f key value which is not a binary', - exc_exec(sdrcmd()) - ) - end) end it('fails on register item with NIL value', function() wshada('\005\000\001\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 is not a dictionary', - exc_exec(sdrcmd()) - ) - end) - - -- rc entry is here because it causes an allocation - it('fails on register item with BIN key', function() - wshada('\005\000\015\131\162rc\145\196\001a\162rX\192\196\000\000') - eq( - 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has key which is not a string', + 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 is not a dict', exc_exec(sdrcmd()) ) end) @@ -373,7 +318,7 @@ describe('ShaDa error handling', function() it('fails on register item with NIL rt key value', function() wshada('\005\000\009\130\162rX\192\162rt\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rt key value which is not an unsigned integer', + 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rt key value which is not an integer', exc_exec(sdrcmd()) ) end) @@ -381,7 +326,7 @@ describe('ShaDa error handling', function() it('fails on register item with NIL rw key value', function() wshada('\005\000\009\130\162rX\192\162rw\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rw key value which is not an unsigned integer', + 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rw key value which is not an integer', exc_exec(sdrcmd()) ) end) @@ -397,7 +342,7 @@ describe('ShaDa error handling', function() it('fails on register item with empty rc key value', function() wshada('\005\000\009\130\162rX\192\162rc\144') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rc key with empty array', + 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rc key with missing or empty array', exc_exec(sdrcmd()) ) end) @@ -413,7 +358,7 @@ describe('ShaDa error handling', function() it('fails on register item without rc array', function() wshada('\005\000\009\129\162rX\146\196\001a\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has missing rc array', + 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rc key with missing or empty array', exc_exec(sdrcmd()) ) end) @@ -421,7 +366,7 @@ describe('ShaDa error handling', function() it('fails on history item with NIL value', function() wshada('\004\000\001\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 is not an array', + 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 is not an array with enough elements', exc_exec(sdrcmd()) ) end) @@ -429,7 +374,7 @@ describe('ShaDa error handling', function() it('fails on history item with empty value', function() wshada('\004\000\001\144') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 does not have enough elements', + 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 is not an array with enough elements', exc_exec(sdrcmd()) ) end) @@ -437,7 +382,7 @@ describe('ShaDa error handling', function() it('fails on history item with single element value', function() wshada('\004\000\002\145\000') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 does not have enough elements', + 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 is not an array with enough elements', exc_exec(sdrcmd()) ) end) @@ -485,7 +430,7 @@ describe('ShaDa error handling', function() it('fails on variable item with NIL value', function() wshada('\006\000\001\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 is not an array', + 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 is not an array with enough elements', exc_exec(sdrcmd()) ) end) @@ -493,7 +438,7 @@ describe('ShaDa error handling', function() it('fails on variable item with empty value', function() wshada('\006\000\001\144') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 does not have enough elements', + 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 is not an array with enough elements', exc_exec(sdrcmd()) ) end) @@ -501,7 +446,7 @@ describe('ShaDa error handling', function() it('fails on variable item with single element value', function() wshada('\006\000\002\145\000') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 does not have enough elements', + 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 is not an array with enough elements', exc_exec(sdrcmd()) ) end) @@ -525,7 +470,7 @@ describe('ShaDa error handling', function() it('fails on replacement item with NIL value', function() wshada('\003\000\001\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 is not an array', + 'Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 is not an array with enough elements', exc_exec(sdrcmd()) ) end) @@ -533,7 +478,7 @@ describe('ShaDa error handling', function() it('fails on replacement item with empty value', function() wshada('\003\000\001\144') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 does not have enough elements', + 'Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 is not an array with enough elements', exc_exec(sdrcmd()) ) end) @@ -559,7 +504,7 @@ describe('ShaDa error handling', function() nvim_command('set shada+=%') wshada('\009\000\008\146\129\161f\196\001/\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: buffer list at position 0 contains entry that is not a dictionary', + 'Vim(rshada):E575: Error while reading ShaDa file: buffer list at position 0 contains entry that is not a dict', exc_exec(sdrcmd()) ) end) @@ -577,7 +522,7 @@ describe('ShaDa error handling', function() nvim_command('set shada+=%') wshada('\009\000\017\146\129\161f\196\001/\130\161f\196\002/a\161l\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: buffer list entry entry at position 0 has l key value which is not an integer', + 'Vim(rshada):E575: Error while reading ShaDa file: buffer list at position 0 contains entry that has l key value which is not an integer', exc_exec(sdrcmd()) ) end) @@ -613,7 +558,7 @@ describe('ShaDa error handling', function() nvim_command('set shada+=%') wshada('\009\000\017\146\129\161f\196\001/\130\161f\196\002/a\161c\192') eq( - 'Vim(rshada):E575: Error while reading ShaDa file: buffer list entry entry at position 0 has c key value which is not an integer', + 'Vim(rshada):E575: Error while reading ShaDa file: buffer list at position 0 contains entry that has c key value which is not an integer', exc_exec(sdrcmd()) ) end) diff --git a/test/functional/terminal/altscreen_spec.lua b/test/functional/terminal/altscreen_spec.lua index 12c8615799..4a61e0203d 100644 --- a/test/functional/terminal/altscreen_spec.lua +++ b/test/functional/terminal/altscreen_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local clear, eq, api = n.clear, t.eq, n.api local feed = n.feed local feed_data = tt.feed_data @@ -17,7 +17,7 @@ describe(':terminal altscreen', function() before_each(function() clear() - screen = tt.screen_setup() + screen = tt.setup_screen() feed_data({ 'line1', 'line2', diff --git a/test/functional/terminal/api_spec.lua b/test/functional/terminal/api_spec.lua index 1f10dda551..b550df80c3 100644 --- a/test/functional/terminal/api_spec.lua +++ b/test/functional/terminal/api_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local ok = t.ok if t.skip(t.is_os('win')) then diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index 96abd9f543..7a30367917 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local assert_alive = n.assert_alive local feed, clear = n.feed, n.clear @@ -29,7 +29,7 @@ describe(':terminal buffer', function() before_each(function() clear() command('set modifiable swapfile undolevels=20') - screen = tt.screen_setup() + screen = tt.setup_screen() end) it('terminal-mode forces various options', function() @@ -199,7 +199,7 @@ describe(':terminal buffer', function() {5:========== }| rows: 2, cols: 50 | {2: } | - {1:========== }| + {18:========== }| | ]]) @@ -312,6 +312,16 @@ describe(':terminal buffer', function() pcall_err(command, 'write test/functional/fixtures/tty-test.c') ) end) + + it('external interrupt (got_int) does not hang #20726', function() + eq({ mode = 't', blocking = false }, api.nvim_get_mode()) + command('call timer_start(0, {-> interrupt()})') + feed('<Ignore>') -- Add input to separate two RPC requests + eq({ mode = 't', blocking = false }, api.nvim_get_mode()) + feed([[<C-\><C-N>]]) + eq({ mode = 'nt', blocking = false }, api.nvim_get_mode()) + command('bd!') + end) end) describe(':terminal buffer', function() @@ -332,7 +342,7 @@ describe(':terminal buffer', function() command('wincmd p') -- cwd will be inserted in a file URI, which cannot contain backs - local cwd = fn.getcwd():gsub('\\', '/') + local cwd = t.fix_slashes(fn.getcwd()) local parent = cwd:match('^(.+/)') local expected = '\027]7;file://host' .. parent api.nvim_chan_send(term, string.format('%s\027\\', expected)) @@ -340,7 +350,7 @@ describe(':terminal buffer', function() eq(termbuf, eval('g:termbuf')) end) - it('TermReqeust synchronization #27572', function() + it('TermRequest synchronization #27572', function() command('autocmd! nvim_terminal TermRequest') local term = exec_lua([[ _G.input = {} @@ -564,7 +574,7 @@ if is_os('win') then feed_command('set modifiable swapfile undolevels=20') poke_eventloop() local cmd = { 'cmd.exe', '/K', 'PROMPT=$g$s' } - screen = tt.screen_setup(nil, cmd) + screen = tt.setup_screen(nil, cmd) end) it('"put" operator sends data normally', function() diff --git a/test/functional/terminal/clipboard_spec.lua b/test/functional/terminal/clipboard_spec.lua new file mode 100644 index 0000000000..4a1a0e29fd --- /dev/null +++ b/test/functional/terminal/clipboard_spec.lua @@ -0,0 +1,65 @@ +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local eq = t.eq +local retry = t.retry + +local clear = n.clear +local fn = n.fn +local testprg = n.testprg +local exec_lua = n.exec_lua +local eval = n.eval + +describe(':terminal', function() + before_each(function() + clear() + + exec_lua([[ + local function clipboard(reg, type) + if type == 'copy' then + return function(lines) + local data = table.concat(lines, '\n') + vim.g.clipboard_data = data + end + end + + if type == 'paste' then + return function() + error() + end + end + + error('invalid type: ' .. type) + end + + vim.g.clipboard = { + name = 'Test', + copy = { + ['+'] = clipboard('+', 'copy'), + ['*'] = clipboard('*', 'copy'), + }, + paste = { + ['+'] = clipboard('+', 'paste'), + ['*'] = clipboard('*', 'paste'), + }, + } + ]]) + end) + + it('can write to the system clipboard', function() + eq('Test', eval('g:clipboard.name')) + + local text = 'Hello, world! This is some\nexample text\nthat spans multiple\nlines' + local encoded = exec_lua('return vim.base64.encode(...)', text) + + local function osc52(arg) + return string.format('\027]52;;%s\027\\', arg) + end + + fn.termopen({ testprg('shell-test'), '-t', osc52(encoded) }) + + retry(nil, 1000, function() + eq(text, exec_lua([[ return vim.g.clipboard_data ]])) + end) + end) +end) diff --git a/test/functional/terminal/cursor_spec.lua b/test/functional/terminal/cursor_spec.lua index 51c6b12e62..0c5de45829 100644 --- a/test/functional/terminal/cursor_spec.lua +++ b/test/functional/terminal/cursor_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local feed, clear = n.feed, n.clear local testprg, command = n.testprg, n.command @@ -18,7 +18,7 @@ describe(':terminal cursor', function() before_each(function() clear() - screen = tt.screen_setup() + screen = tt.setup_screen() end) it('moves the screen cursor when focused', function() diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua index 4f3d010d02..05d68f6754 100644 --- a/test/functional/terminal/highlight_spec.lua +++ b/test/functional/terminal/highlight_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local feed, clear = n.feed, n.clear local api = n.api @@ -380,3 +380,23 @@ describe(':terminal highlight with custom palette', function() ]]) end) end) + +describe(':terminal', function() + before_each(clear) + + it('can display URLs', function() + local screen = Screen.new(50, 7) + screen:add_extra_attr_ids { + [100] = { url = 'https://example.com' }, + } + screen:attach() + local chan = api.nvim_open_term(0, {}) + api.nvim_chan_send(chan, '\027]8;;https://example.com\027\\Example\027]8;;\027\\') + screen:expect({ + grid = [[ + {100:^Example} | + |*6 + ]], + }) + end) +end) diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua index ad98dfc6c3..38d6b83417 100644 --- a/test/functional/terminal/mouse_spec.lua +++ b/test/functional/terminal/mouse_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local clear, eq, eval = n.clear, t.eq, n.eval local feed, api, command = n.feed, n.api, n.command local feed_data = tt.feed_data @@ -14,10 +14,12 @@ describe(':terminal mouse', function() before_each(function() clear() api.nvim_set_option_value('statusline', '==========', {}) - command('highlight StatusLine cterm=NONE') - command('highlight StatusLineNC cterm=NONE') - command('highlight VertSplit cterm=NONE') - screen = tt.screen_setup() + screen = tt.setup_screen() + command('highlight StatusLine NONE') + command('highlight StatusLineNC NONE') + command('highlight StatusLineTerm NONE') + command('highlight StatusLineTermNC NONE') + command('highlight VertSplit NONE') local lines = {} for i = 1, 30 do table.insert(lines, 'line' .. tostring(i)) diff --git a/test/functional/terminal/parser_spec.lua b/test/functional/terminal/parser_spec.lua new file mode 100644 index 0000000000..67f47c7888 --- /dev/null +++ b/test/functional/terminal/parser_spec.lua @@ -0,0 +1,15 @@ +local n = require('test.functional.testnvim')() + +local clear = n.clear +local api = n.api +local assert_alive = n.assert_alive + +describe(':terminal', function() + before_each(clear) + + it('handles invalid OSC terminators #30084', function() + local chan = api.nvim_open_term(0, {}) + api.nvim_chan_send(chan, '\027]8;;https://example.com\027\\Example\027]8;;\027\n') + assert_alive() + end) +end) diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua index 229a169996..da0bd97270 100644 --- a/test/functional/terminal/scrollback_spec.lua +++ b/test/functional/terminal/scrollback_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local clear, eq = n.clear, t.eq local feed, testprg = n.feed, n.testprg @@ -22,7 +22,7 @@ describe(':terminal scrollback', function() before_each(function() clear() - screen = tt.screen_setup(nil, nil, 30) + screen = tt.setup_screen(nil, nil, 30) end) describe('when the limit is exceeded', function() @@ -399,9 +399,9 @@ describe("'scrollback' option", function() it('set to 0 behaves as 1', function() local screen if is_os('win') then - screen = tt.screen_setup(nil, { 'cmd.exe' }, 30) + screen = tt.setup_screen(nil, { 'cmd.exe' }, 30) else - screen = tt.screen_setup(nil, { 'sh' }, 30) + screen = tt.setup_screen(nil, { 'sh' }, 30) end api.nvim_set_option_value('scrollback', 0, {}) @@ -416,10 +416,10 @@ describe("'scrollback' option", function() local screen if is_os('win') then command([[let $PROMPT='$$']]) - screen = tt.screen_setup(nil, { 'cmd.exe' }, 30) + screen = tt.setup_screen(nil, { 'cmd.exe' }, 30) else command('let $PS1 = "$"') - screen = tt.screen_setup(nil, { 'sh' }, 30) + screen = tt.setup_screen(nil, { 'sh' }, 30) end api.nvim_set_option_value('scrollback', 200, {}) @@ -480,8 +480,8 @@ describe("'scrollback' option", function() end) it('deletes extra lines immediately', function() - -- Scrollback is 10 on screen_setup - local screen = tt.screen_setup(nil, nil, 30) + -- Scrollback is 10 on setup_screen + local screen = tt.setup_screen(nil, nil, 30) local lines = {} for i = 1, 30 do table.insert(lines, 'line' .. tostring(i)) diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index d4628ea626..a7d87bb231 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -7,7 +7,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local eq = t.eq local feed_data = tt.feed_data @@ -40,8 +40,8 @@ if t.skip(is_os('win')) then end describe('TUI', function() - local screen - local child_session + local screen --[[@type test.functional.ui.screen]] + local child_session --[[@type test.Session]] local child_exec_lua before_each(function() @@ -630,6 +630,8 @@ describe('TUI', function() set mouse=a mousemodel=popup aunmenu PopUp + " Delete the default MenuPopup event handler. + autocmd! nvim_popupmenu menu PopUp.foo :let g:menustr = 'foo'<CR> menu PopUp.bar :let g:menustr = 'bar'<CR> menu PopUp.baz :let g:menustr = 'baz'<CR> @@ -973,6 +975,7 @@ describe('TUI', function() {3:-- TERMINAL --} | ]]) feed_data('\027[201~') -- End paste. + screen:expect_unchanged() feed_data('\027[27u') -- ESC: go to Normal mode. wait_for_mode('n') screen:expect([[ @@ -1056,6 +1059,11 @@ describe('TUI', function() if is_ci('github') then pending('tty-test complains about not owning the terminal -- actions/runner#241') end + screen:set_default_attr_ids({ + [1] = { reverse = true }, -- focused cursor + [3] = { bold = true }, + [19] = { bold = true, background = 121, foreground = 0 }, -- StatusLineTerm + }) child_exec_lua('vim.o.statusline="^^^^^^^"') child_exec_lua('vim.cmd.terminal(...)', testprg('tty-test')) feed_data('i') @@ -1063,7 +1071,7 @@ describe('TUI', function() tty ready | {1: } | |*2 - {5:^^^^^^^ }| + {19:^^^^^^^ }| {3:-- TERMINAL --} |*2 ]]) feed_data('\027[200~') @@ -1073,7 +1081,7 @@ describe('TUI', function() tty ready | hallo{1: } | |*2 - {5:^^^^^^^ }| + {19:^^^^^^^ }| {3:-- TERMINAL --} |*2 ]]) end) @@ -1099,7 +1107,7 @@ describe('TUI', function() screen:expect(expected_grid1) -- Dot-repeat/redo. feed_data('.') - screen:expect([[ + local expected_grid2 = [[ ESC:{6:^[} / CR: | xline 1 | ESC:{6:^[} / CR: | @@ -1107,7 +1115,8 @@ describe('TUI', function() {5:[No Name] [+] 5,1 Bot}| | {3:-- TERMINAL --} | - ]]) + ]] + screen:expect(expected_grid2) -- Undo. feed_data('u') expect_child_buf_lines(expected_crlf) @@ -1121,6 +1130,14 @@ describe('TUI', function() feed_data('\027[200~' .. table.concat(expected_lf, '\r\n') .. '\027[201~') screen:expect(expected_grid1) expect_child_buf_lines(expected_crlf) + -- Dot-repeat/redo. + feed_data('.') + screen:expect(expected_grid2) + -- Undo. + feed_data('u') + expect_child_buf_lines(expected_crlf) + feed_data('u') + expect_child_buf_lines({ '' }) end) it('paste: cmdline-mode inserts 1 line', function() @@ -1184,6 +1201,7 @@ describe('TUI', function() expect_cmdline('"stuff 1 more"') -- End the paste sequence. feed_data('\027[201~') + expect_cmdline('"stuff 1 more"') feed_data(' typed') expect_cmdline('"stuff 1 more typed"') end) @@ -1227,6 +1245,7 @@ describe('TUI', function() feed_data('line 7\nline 8\n') -- Stop paste. feed_data('\027[201~') + screen:expect_unchanged() feed_data('\n') -- <CR> to dismiss hit-enter prompt expect_child_buf_lines({ 'foo', '' }) -- Dot-repeat/redo is not modified by failed paste. @@ -1274,10 +1293,46 @@ describe('TUI', function() {} ) feed_data('\027[200~line A\nline B\n\027[201~') + expect_child_buf_lines({ '' }) feed_data('ifoo\n\027[27u') expect_child_buf_lines({ 'foo', '' }) end) + it('paste: vim.paste() cancel (retval=false) with streaming #30462', function() + child_session:request( + 'nvim_exec_lua', + [[ + vim.paste = (function(overridden) + return function(lines, phase) + for i, line in ipairs(lines) do + if line:find('!') then + return false + end + end + return overridden(lines, phase) + end + end)(vim.paste) + ]], + {} + ) + feed_data('A') + wait_for_mode('i') + feed_data('\027[200~aaa') + expect_child_buf_lines({ 'aaa' }) + feed_data('bbb') + expect_child_buf_lines({ 'aaabbb' }) + feed_data('ccc!') -- This chunk is cancelled. + expect_child_buf_lines({ 'aaabbb' }) + feed_data('ddd\027[201~') -- This chunk is ignored. + expect_child_buf_lines({ 'aaabbb' }) + feed_data('\027[27u') + wait_for_mode('n') + feed_data('.') -- Dot-repeat only includes chunks actually pasted. + expect_child_buf_lines({ 'aaabbbaaabbb' }) + feed_data('$\027[200~eee\027[201~') -- A following paste works normally. + expect_child_buf_lines({ 'aaabbbaaabbbeee' }) + end) + it("paste: 'nomodifiable' buffer", function() child_session:request('nvim_command', 'set nomodifiable') child_session:request( @@ -1396,7 +1451,6 @@ describe('TUI', function() feed_data('\n') -- Send the "stop paste" sequence. feed_data('\027[201~') - screen:expect([[ | pasted from terminal (1) | @@ -1548,10 +1602,32 @@ describe('TUI', function() screen:set_rgb_cterm(true) screen:set_default_attr_ids({ [1] = { { reverse = true }, { reverse = true } }, - [2] = { { bold = true, reverse = true }, { bold = true, reverse = true } }, + [2] = { + { bold = true, background = Screen.colors.LightGreen, foreground = Screen.colors.Black }, + { bold = true }, + }, [3] = { { bold = true }, { bold = true } }, [4] = { { fg_indexed = true, foreground = tonumber('0xe0e000') }, { foreground = 3 } }, [5] = { { foreground = tonumber('0xff8000') }, {} }, + [6] = { + { + fg_indexed = true, + bg_indexed = true, + bold = true, + background = tonumber('0x66ff99'), + foreground = Screen.colors.Black, + }, + { bold = true, background = 121, foreground = 0 }, + }, + [7] = { + { + fg_indexed = true, + bg_indexed = true, + background = tonumber('0x66ff99'), + foreground = Screen.colors.Black, + }, + { background = 121, foreground = 0 }, + }, }) child_exec_lua('vim.o.statusline="^^^^^^^"') @@ -1586,7 +1662,7 @@ describe('TUI', function() {1:t}ty ready | {4:text}colortext | |*2 - {2:^^^^^^^ }| + {6:^^^^^^^}{7: }| :set notermguicolors | {3:-- TERMINAL --} | ]], @@ -1622,12 +1698,13 @@ describe('TUI', function() ]]) end) - it('in nvim_list_uis()', function() + it('in nvim_list_uis(), sets nvim_set_client_info()', function() -- $TERM in :terminal. local exp_term = is_os('bsd') and 'builtin_xterm' or 'xterm-256color' + local ui_chan = 1 local expected = { { - chan = 1, + chan = ui_chan, ext_cmdline = false, ext_hlstate = false, ext_linegrid = true, @@ -1650,6 +1727,43 @@ describe('TUI', function() } local _, rv = child_session:request('nvim_list_uis') eq(expected, rv) + + ---@type table + local expected_version = ({ + child_session:request('nvim_exec_lua', 'return vim.version()', {}), + })[2] + -- vim.version() returns `prerelease` string. Coerce it to boolean. + expected_version.prerelease = not not expected_version.prerelease + + local expected_chan_info = { + client = { + attributes = { + license = 'Apache 2', + -- pid = 5371, + website = 'https://neovim.io', + }, + methods = {}, + name = 'nvim-tui', + type = 'ui', + version = expected_version, + }, + id = ui_chan, + mode = 'rpc', + stream = 'stdio', + } + + local status, chan_info = child_session:request('nvim_get_chan_info', ui_chan) + ok(status) + local info = chan_info.client + ok(info.attributes.pid and info.attributes.pid > 0, 'PID', info.attributes.pid or 'nil') + ok(info.version.major >= 0) + ok(info.version.minor >= 0) + ok(info.version.patch >= 0) + + -- Delete variable fields so we can deep-compare. + info.attributes.pid = nil + + eq(expected_chan_info, chan_info) end) it('allows grid to assume wider ambiwidth chars than host terminal', function() @@ -1941,9 +2055,9 @@ describe('TUI', function() if not req then return end - local url = req:match('\027]8;;(.*)$') - if url ~= nil then - table.insert(_G.urls, url) + local id, url = req:match('\027]8;id=(%d+);(.*)$') + if id ~= nil and url ~= nil then + table.insert(_G.urls, { id = tonumber(id), url = url }) end end, }) @@ -1957,7 +2071,7 @@ describe('TUI', function() }) ]]) retry(nil, 1000, function() - eq({ 'https://example.com', '' }, exec_lua([[return _G.urls]])) + eq({ { id = 0xE1EA0000, url = 'https://example.com' } }, exec_lua([[return _G.urls]])) end) end) end) @@ -1973,6 +2087,7 @@ describe('TUI', function() [3] = { bold = true }, [4] = { foreground = tonumber('0x4040ff'), fg_indexed = true }, [5] = { bold = true, reverse = true }, + [6] = { foreground = Screen.colors.White, background = Screen.colors.DarkGreen }, }) screen:attach() fn.termopen({ @@ -1998,43 +2113,44 @@ describe('TUI', function() {2:~ }│{4:~ }|*5 {2:~ }│{5:[No Name] 0,0-1 All}| {2:~ }│ | - {5:new }{1:{MATCH:<.*[/\]nvim }}| - | - ]]) - end) - - it('invalidated regions are cleared with terminal background attr', function() - local screen = Screen.new(50, 10) - screen:set_default_attr_ids({ [1] = { foreground = Screen.colors.Black } }) - screen:attach() - fn.termopen({ - nvim_prog, - '--clean', - '--cmd', - 'set termguicolors', - '--cmd', - 'sleep 10', - }, { - env = { - VIMRUNTIME = os.getenv('VIMRUNTIME'), - }, - }) - screen:expect({ - grid = [[ - {1:^ }| - {1: }|*8 - | - ]], - }) - screen:try_resize(51, 11) - screen:expect({ - grid = [[ - {1:^ }| - {1: }|*9 - | - ]], - }) - end) + {5:new }{6:{MATCH:<.*[/\]nvim }}| + | + ]]) + end) + + -- #28667, #28668 + for _, guicolors in ipairs({ 'notermguicolors', 'termguicolors' }) do + it('has no black flicker when clearing regions during startup with ' .. guicolors, function() + local screen = Screen.new(50, 10) + screen:attach() + fn.termopen({ + nvim_prog, + '--clean', + '--cmd', + 'set ' .. guicolors, + '--cmd', + 'sleep 10', + }, { + env = { + VIMRUNTIME = os.getenv('VIMRUNTIME'), + }, + }) + screen:expect({ + grid = [[ + ^ | + |*9 + ]], + intermediate = true, + }) + screen:try_resize(51, 11) + screen:expect({ + grid = [[ + ^ | + |*10 + ]], + }) + end) + end it('argv[0] can be overridden #23953', function() if not exec_lua('return pcall(require, "ffi")') then @@ -2080,7 +2196,7 @@ describe('TUI', function() finally(function() os.remove('testF') end) - local screen = tt.screen_setup( + local screen = tt.setup_screen( 0, ('"%s" -u NONE -i NONE --cmd "set noswapfile noshowcmd noruler" --cmd "normal iabc" > /dev/null 2>&1 && cat testF && rm testF'):format( nvim_prog @@ -2170,6 +2286,47 @@ describe('TUI', function() } end) + it('draws screen lines with leading spaces correctly #29711', function() + local screen = tt.setup_child_nvim({ + '-u', + 'NONE', + '-i', + 'NONE', + '--cmd', + 'set foldcolumn=6 | call setline(1, ["", repeat("aabb", 1000)]) | echo 42', + }, { extra_rows = 10, cols = 66 }) + screen:expect { + grid = [[ + | + aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabb|*12 + aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabba@@@| + [No Name] [+] 1,0-1 Top| + 42 | + -- TERMINAL -- | + ]], + attr_ids = {}, + } + feed_data('\12') -- Ctrl-L + -- The first line counts as 3 cells. + -- For the second line, 6 repeated spaces at the start counts as 2 cells, + -- so each screen line of the second line counts as 62 cells. + -- After drawing the first line and 8 screen lines of the second line, + -- 3 + 8 * 62 = 499 cells have been counted. + -- The 6 repeated spaces at the start of the next screen line exceeds the + -- 500-cell limit, so the buffer is flushed after these spaces. + screen:expect { + grid = [[ + | + aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabb|*12 + aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabba@@@| + [No Name] [+] 1,0-1 Top| + | + -- TERMINAL -- | + ]], + attr_ids = {}, + } + end) + it('no heap-buffer-overflow when changing &columns', function() -- Set a different bg colour and change $TERM to something dumber so the `print_spaces()` -- codepath in `clear_region()` is hit. @@ -2938,6 +3095,61 @@ describe('TUI', function() end) end) + it('does not query the terminal for truecolor support if $COLORTERM is set', function() + clear() + exec_lua([[ + vim.api.nvim_create_autocmd('TermRequest', { + callback = function(args) + local req = args.data + vim.g.termrequest = req + local xtgettcap = req:match('^\027P%+q([%x;]+)$') + if xtgettcap then + local t = {} + for cap in vim.gsplit(xtgettcap, ';') do + local resp = string.format('\027P1+r%s\027\\', xtgettcap) + vim.api.nvim_chan_send(vim.bo[args.buf].channel, resp) + t[vim.text.hexdecode(cap)] = true + end + vim.g.xtgettcap = t + return true + elseif req:match('^\027P$qm\027\\$') then + vim.g.decrqss = true + end + end, + }) + ]]) + + local child_server = new_pipename() + screen = tt.setup_child_nvim({ + '--listen', + child_server, + '-u', + 'NONE', + '-i', + 'NONE', + }, { + env = { + VIMRUNTIME = os.getenv('VIMRUNTIME'), + -- With COLORTERM=256, Nvim should not query the terminal and should not set 'tgc' + COLORTERM = '256', + TERM = 'xterm-256colors', + }, + }) + + screen:expect({ any = '%[No Name%]' }) + + local child_session = n.connect(child_server) + retry(nil, 1000, function() + local xtgettcap = eval("get(g:, 'xtgettcap', {})") + eq(nil, xtgettcap['Tc']) + eq(nil, xtgettcap['RGB']) + eq(nil, xtgettcap['setrgbf']) + eq(nil, xtgettcap['setrgbb']) + eq(0, eval([[get(g:, 'decrqss')]])) + eq({ true, 0 }, { child_session:request('nvim_eval', '&termguicolors') }) + end) + end) + it('queries the terminal for OSC 52 support', function() clear() exec_lua([[ diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua index f85e26a66d..fdb606e959 100644 --- a/test/functional/terminal/window_spec.lua +++ b/test/functional/terminal/window_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local feed_data = tt.feed_data local feed, clear = n.feed, n.clear local poke_eventloop = n.poke_eventloop @@ -13,11 +13,31 @@ local skip = t.skip local is_os = t.is_os describe(':terminal window', function() + before_each(clear) + + it('sets local values of window options #29325', function() + command('setglobal wrap list') + command('terminal') + eq({ 0, 0, 1 }, eval('[&l:wrap, &wrap, &g:wrap]')) + eq({ 0, 0, 1 }, eval('[&l:list, &list, &g:list]')) + command('enew') + eq({ 1, 1, 1 }, eval('[&l:wrap, &wrap, &g:wrap]')) + eq({ 1, 1, 1 }, eval('[&l:list, &list, &g:list]')) + command('buffer #') + eq({ 0, 0, 1 }, eval('[&l:wrap, &wrap, &g:wrap]')) + eq({ 0, 0, 1 }, eval('[&l:list, &list, &g:list]')) + command('new') + eq({ 1, 1, 1 }, eval('[&l:wrap, &wrap, &g:wrap]')) + eq({ 1, 1, 1 }, eval('[&l:list, &list, &g:list]')) + end) +end) + +describe(':terminal window', function() local screen before_each(function() clear() - screen = tt.screen_setup() + screen = tt.setup_screen() end) it('sets topline correctly #8556', function() @@ -37,7 +57,6 @@ describe(':terminal window', function() describe("with 'number'", function() it('wraps text', function() - skip(is_os('win')) -- todo(clason): unskip when reenabling reflow feed([[<C-\><C-N>]]) feed([[:set numberwidth=1 number<CR>i]]) screen:expect([[ @@ -67,7 +86,7 @@ describe(':terminal window', function() {7: 1 }tty ready | {7: 2 }rows: 6, cols: 48 | {7: 3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO| - {7: 4 }WXYZrows: 6, cols: 41 | + {7: 4 }PQRSTUVWXYZrows: 6, cols: 41 | {7: 5 }{1: } | {7: 6 } | {3:-- TERMINAL --} | @@ -77,7 +96,7 @@ describe(':terminal window', function() {7: 1 }tty ready | {7: 2 }rows: 6, cols: 48 | {7: 3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO| - {7: 4 }WXYZrows: 6, cols: 41 | + {7: 4 }PQRSTUVWXYZrows: 6, cols: 41 | {7: 5 } abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN| {7: 6 }OPQRSTUVWXYZ{1: } | {3:-- TERMINAL --} | @@ -87,7 +106,6 @@ describe(':terminal window', function() describe("with 'statuscolumn'", function() it('wraps text', function() - skip(is_os('win')) -- todo(clason): unskip when reenabling reflow command([[set number statuscolumn=++%l\ \ ]]) screen:expect([[ {7:++1 }tty ready | @@ -110,11 +128,11 @@ describe(':terminal window', function() ]]) feed_data('\nabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') screen:expect([[ - {7:++7 } | - {7:++8 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR| - {7:++9 }TUVWXYZ | + {7:++ 7 } | + {7:++ 8 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR| + {7:++ 9 }STUVWXYZ | {7:++10 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR| - {7:++11 }TUVWXYZrows: 6, cols: 44 | + {7:++11 }STUVWXYZrows: 6, cols: 44 | {7:++12 }{1: } | {3:-- TERMINAL --} | ]]) @@ -178,7 +196,7 @@ describe(':terminal with multigrid', function() before_each(function() clear() - screen = tt.screen_setup(0, nil, 50, nil, { ext_multigrid = true }) + screen = tt.setup_screen(0, nil, 50, nil, { ext_multigrid = true }) end) it('resizes to requested size', function() diff --git a/test/functional/terminal/window_split_tab_spec.lua b/test/functional/terminal/window_split_tab_spec.lua index 04d2e0bca7..e9218e9a3b 100644 --- a/test/functional/terminal/window_split_tab_spec.lua +++ b/test/functional/terminal/window_split_tab_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local assert_alive = n.assert_alive local clear = n.clear local feed = n.feed @@ -22,10 +22,12 @@ describe(':terminal', function() -- set the statusline to a constant value because of variables like pid -- and current directory and to improve visibility of splits api.nvim_set_option_value('statusline', '==========', {}) - command('highlight StatusLine cterm=NONE') - command('highlight StatusLineNC cterm=NONE') - command('highlight VertSplit cterm=NONE') - screen = tt.screen_setup(3) + screen = tt.setup_screen(3) + command('highlight StatusLine NONE') + command('highlight StatusLineNC NONE') + command('highlight StatusLineTerm NONE') + command('highlight StatusLineTermNC NONE') + command('highlight VertSplit NONE') end) after_each(function() diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index 6b858e4d69..8a2281e2a1 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -14,15 +14,14 @@ local is_os = t.is_os local ok = t.ok local sleep = uv.sleep ---- This module uses functions from the context of the test session, i.e. in the context of the ---- nvim being tests. +--- Functions executing in the current nvim session/process being tested. local M = {} local runtime_set = 'set runtimepath^=./build/lib/nvim/' M.nvim_prog = (os.getenv('NVIM_PRG') or t.paths.test_build_dir .. '/bin/nvim') -- Default settings for the test session. M.nvim_set = ( - 'set shortmess+=IS background=light termguicolors noswapfile noautoindent startofline' + 'set shortmess+=IS background=light noswapfile noautoindent startofline' .. ' laststatus=1 undodir=. directory=. viewdir=. backupdir=.' .. ' belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid' ) @@ -251,12 +250,14 @@ function M.set_method_error(err) method_error = err end +--- Runs the event loop of the given session. +--- --- @param lsession test.Session --- @param request_cb function? --- @param notification_cb function? --- @param setup_cb function? --- @param timeout integer ---- @return {[1]: integer, [2]: string} +--- @return [integer, string] function M.run_session(lsession, request_cb, notification_cb, setup_cb, timeout) local on_request --- @type function? local on_notification --- @type function? @@ -297,6 +298,7 @@ function M.run_session(lsession, request_cb, notification_cb, setup_cb, timeout) return lsession.eof_err end +--- Runs the event loop of the current global session. function M.run(request_cb, notification_cb, setup_cb, timeout) assert(session) return M.run_session(session, request_cb, notification_cb, setup_cb, timeout) @@ -456,7 +458,7 @@ end --- @param argv string[] --- @param merge boolean? --- @param env string[]? ---- @param keep boolean +--- @param keep boolean? --- @param io_extra uv.uv_pipe_t? used for stdin_fd, see :help ui-option --- @return test.Session function M.spawn(argv, merge, env, keep, io_extra) @@ -757,58 +759,21 @@ function M.assert_visible(bufnr, visible) end end ---- @param path string -local function do_rmdir(path) - local stat = uv.fs_stat(path) - if stat == nil then - return - end - if stat.type ~= 'directory' then - error(string.format('rmdir: not a directory: %s', path)) - end - for file in vim.fs.dir(path) do - if file ~= '.' and file ~= '..' then - local abspath = path .. '/' .. file - if t.isdir(abspath) then - do_rmdir(abspath) -- recurse - else - local ret, err = os.remove(abspath) - if not ret then - if not session then - error('os.remove: ' .. err) - else - -- Try Nvim delete(): it handles `readonly` attribute on Windows, - -- and avoids Lua cross-version/platform incompatibilities. - if -1 == M.call('delete', abspath) then - local hint = (is_os('win') and ' (hint: try :%bwipeout! before rmdir())' or '') - error('delete() failed' .. hint .. ': ' .. abspath) - end - end - end - end - end - end - local ret, err = uv.fs_rmdir(path) - if not ret then - error('luv.fs_rmdir(' .. path .. '): ' .. err) - end -end - local start_dir = uv.cwd() function M.rmdir(path) - local ret, _ = pcall(do_rmdir, path) + local ret, _ = pcall(vim.fs.rm, path, { recursive = true, force = true }) if not ret and is_os('win') then -- Maybe "Permission denied"; try again after changing the nvim -- process to the top-level directory. M.command([[exe 'cd '.fnameescape(']] .. start_dir .. "')") - ret, _ = pcall(do_rmdir, path) + ret, _ = pcall(vim.fs.rm, path, { recursive = true, force = true }) end -- During teardown, the nvim process may not exit quickly enough, then rmdir() -- will fail (on Windows). if not ret then -- Try again. sleep(1000) - do_rmdir(path) + vim.fs.rm(path, { recursive = true, force = true }) end end @@ -835,10 +800,171 @@ function M.exec_capture(code) return M.api.nvim_exec2(code, { output = true }).output end ---- @param code string +--- @param f function +--- @return table<string,any> +local function get_upvalues(f) + local i = 1 + local upvalues = {} --- @type table<string,any> + while true do + local n, v = debug.getupvalue(f, i) + if not n then + break + end + upvalues[n] = v + i = i + 1 + end + return upvalues +end + +--- @param f function +--- @param upvalues table<string,any> +local function set_upvalues(f, upvalues) + local i = 1 + while true do + local n = debug.getupvalue(f, i) + if not n then + break + end + if upvalues[n] then + debug.setupvalue(f, i, upvalues[n]) + end + i = i + 1 + end +end + +--- @type fun(f: function): table<string,any> +_G.__get_upvalues = nil + +--- @type fun(f: function, upvalues: table<string,any>) +_G.__set_upvalues = nil + +--- @param self table<string,function> +--- @param bytecode string +--- @param upvalues table<string,any> +--- @param ... any[] +--- @return any[] result +--- @return table<string,any> upvalues +local function exec_lua_handler(self, bytecode, upvalues, ...) + local f = assert(loadstring(bytecode)) + self.set_upvalues(f, upvalues) + local ret = { f(...) } --- @type any[] + --- @type table<string,any> + local new_upvalues = self.get_upvalues(f) + + do -- Check return value types for better error messages + local invalid_types = { + ['thread'] = true, + ['function'] = true, + ['userdata'] = true, + } + + for k, v in pairs(ret) do + if invalid_types[type(v)] then + error( + string.format( + "Return index %d with value '%s' of type '%s' cannot be serialized over RPC", + k, + tostring(v), + type(v) + ) + ) + end + end + end + + return ret, new_upvalues +end + +--- Execute Lua code in the wrapped Nvim session. +--- +--- When `code` is passed as a function, it is converted into Lua byte code. +--- +--- Direct upvalues are copied over, however upvalues contained +--- within nested functions are not. Upvalues are also copied back when `code` +--- finishes executing. See `:help lua-upvalue`. +--- +--- Only types which can be serialized can be transferred over, e.g: +--- `table`, `number`, `boolean`, `string`. +--- +--- `code` runs with a different environment and thus will have a different global +--- environment. See `:help lua-environments`. +--- +--- Example: +--- ```lua +--- local upvalue1 = 'upvalue1' +--- exec_lua(function(a, b, c) +--- print(upvalue1, a, b, c) +--- (function() +--- print(upvalue2) +--- end)() +--- end, 'a', 'b', 'c' +--- ``` +--- Prints: +--- ``` +--- upvalue1 a b c +--- nil +--- ``` +--- +--- Not supported: +--- ```lua +--- local a = vim.uv.new_timer() +--- exec_lua(function() +--- print(a) -- Error: a is of type 'userdata' which cannot be serialized. +--- end) +--- ``` +--- @param code string|function +--- @param ... any --- @return any function M.exec_lua(code, ...) - return M.api.nvim_exec_lua(code, { ... }) + if type(code) == 'string' then + return M.api.nvim_exec_lua(code, { ... }) + end + + assert(session) + + if not session.exec_lua_setup then + M.api.nvim_exec_lua( + [[ + _G.__test_exec_lua = { + get_upvalues = loadstring((select(1,...))), + set_upvalues = loadstring((select(2,...))), + handler = loadstring((select(3,...))) + } + setmetatable(_G.__test_exec_lua, { __index = _G.__test_exec_lua }) + ]], + { string.dump(get_upvalues), string.dump(set_upvalues), string.dump(exec_lua_handler) } + ) + session.exec_lua_setup = true + end + + --- @type any[], table<string,any> + local ret, upvalues = unpack(M.api.nvim_exec_lua( + [[ + return { + _G.__test_exec_lua:handler(...) + } + ]], + { + string.dump(code), + get_upvalues(code), + ..., + } + )) + + -- Update upvalues + if next(upvalues) then + local caller = debug.getinfo(2) + local f = caller.func + -- On PUC-Lua, if the function is a tail call, then func will be nil. + -- In this case we need to use the current function. + if not f then + assert(caller.source == '=(tail call)') + f = debug.getinfo(1).func + end + set_upvalues(f, upvalues) + end + + return unpack(ret, 1, table.maxn(ret)) end function M.get_pathsep() @@ -894,26 +1020,6 @@ function M.missing_provider(provider) assert(false, 'Unknown provider: ' .. provider) end ---- @param obj string|table ---- @return any -function M.alter_slashes(obj) - if not is_os('win') then - return obj - end - if type(obj) == 'string' then - local ret = obj:gsub('/', '\\') - return ret - elseif type(obj) == 'table' then - --- @cast obj table<any,any> - local ret = {} --- @type table<any,any> - for k, v in pairs(obj) do - ret[k] = M.alter_slashes(v) - end - return ret - end - assert(false, 'expected string or table of strings, got ' .. type(obj)) -end - local load_factor = 1 if t.is_ci() then -- Compute load factor only once (but outside of any tests). diff --git a/test/functional/terminal/testutil.lua b/test/functional/testterm.lua index f3fc5d3f93..e46ae0793c 100644 --- a/test/functional/terminal/testutil.lua +++ b/test/functional/testterm.lua @@ -1,6 +1,13 @@ --- To test tui/input.c, this module spawns `nvim` inside :terminal and sends --- bytes via jobsend(). Note: the functional/testutil.lua test-session methods --- operate on the _host_ session, _not_ the child session. +-- Functions to test :terminal and the Nvim TUI. +-- Starts a child process in a `:terminal` and sends bytes to the child via nvim_chan_send(). +-- Note: the global functional/testutil.lua test-session is _host_ session, _not_ +-- the child session. +-- +-- - Use `setup_screen()` to test `:terminal` behavior with an arbitrary command. +-- - Use `setup_child_nvim()` to test the Nvim TUI. +-- - NOTE: Only use this if your test actually needs the full lifecycle/capabilities of the +-- builtin Nvim TUI. Most tests should just use `Screen.new()` directly, or plain old API calls. + local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') @@ -9,18 +16,20 @@ local exec_lua = n.exec_lua local api = n.api local nvim_prog = n.nvim_prog -local function feed_data(data) +local M = {} + +function M.feed_data(data) if type(data) == 'table' then data = table.concat(data, '\n') end exec_lua('vim.api.nvim_chan_send(vim.b.terminal_job_id, ...)', data) end -local function feed_termcode(data) - feed_data('\027' .. data) +function M.feed_termcode(data) + M.feed_data('\027' .. data) end -local function make_lua_executor(session) +function M.make_lua_executor(session) return function(code, ...) local status, rv = session:request('nvim_exec_lua', code, { ... }) if not status then @@ -34,64 +43,74 @@ end -- some t for controlling the terminal. the codes were taken from -- infocmp xterm-256color which is less what libvterm understands -- civis/cnorm -local function hide_cursor() - feed_termcode('[?25l') +function M.hide_cursor() + M.feed_termcode('[?25l') end -local function show_cursor() - feed_termcode('[?25h') +function M.show_cursor() + M.feed_termcode('[?25h') end -- smcup/rmcup -local function enter_altscreen() - feed_termcode('[?1049h') +function M.enter_altscreen() + M.feed_termcode('[?1049h') end -local function exit_altscreen() - feed_termcode('[?1049l') +function M.exit_altscreen() + M.feed_termcode('[?1049l') end -- character attributes -local function set_fg(num) - feed_termcode('[38;5;' .. num .. 'm') +function M.set_fg(num) + M.feed_termcode('[38;5;' .. num .. 'm') end -local function set_bg(num) - feed_termcode('[48;5;' .. num .. 'm') +function M.set_bg(num) + M.feed_termcode('[48;5;' .. num .. 'm') end -local function set_bold() - feed_termcode('[1m') +function M.set_bold() + M.feed_termcode('[1m') end -local function set_italic() - feed_termcode('[3m') +function M.set_italic() + M.feed_termcode('[3m') end -local function set_underline() - feed_termcode('[4m') +function M.set_underline() + M.feed_termcode('[4m') end -local function set_underdouble() - feed_termcode('[4:2m') +function M.set_underdouble() + M.feed_termcode('[4:2m') end -local function set_undercurl() - feed_termcode('[4:3m') +function M.set_undercurl() + M.feed_termcode('[4:3m') end -local function set_strikethrough() - feed_termcode('[9m') +function M.set_strikethrough() + M.feed_termcode('[9m') end -local function clear_attrs() - feed_termcode('[0;10m') +function M.clear_attrs() + M.feed_termcode('[0;10m') end -- mouse -local function enable_mouse() - feed_termcode('[?1002h') +function M.enable_mouse() + M.feed_termcode('[?1002h') end -local function disable_mouse() - feed_termcode('[?1002l') +function M.disable_mouse() + M.feed_termcode('[?1002l') end local default_command = { testprg('tty-test') } -local function screen_setup(extra_rows, command, cols, env, screen_opts) +--- Runs `cmd` in a :terminal, and returns a `Screen` object. +--- +---@param extra_rows? integer Extra rows to add to the default screen. +---@param cmd? string|string[] Command to run in the terminal (default: `{ 'tty-test' }`) +---@param cols? integer Create screen with this many columns (default: 50) +---@param env? table Environment set on the `cmd` job. +---@param screen_opts? table Options for `Screen.new()`. +---@return test.functional.ui.screen # Screen attached to the global (not child) Nvim session. +function M.setup_screen(extra_rows, cmd, cols, env, screen_opts) extra_rows = extra_rows and extra_rows or 0 - command = command and command or default_command + cmd = cmd and cmd or default_command cols = cols and cols or 50 api.nvim_command('highlight TermCursor cterm=reverse') api.nvim_command('highlight TermCursorNC ctermbg=11') + api.nvim_command('highlight StatusLineTerm ctermbg=2 ctermfg=0') + api.nvim_command('highlight StatusLineTermNC ctermbg=2 ctermfg=8') local screen = Screen.new(cols, 7 + extra_rows) screen:set_default_attr_ids({ @@ -111,12 +130,14 @@ local function screen_setup(extra_rows, command, cols, env, screen_opts) [14] = { underline = true, reverse = true, bold = true }, [15] = { underline = true, foreground = 12 }, [16] = { background = 248, foreground = 0 }, -- Visual in :terminal session + [17] = { background = 2, foreground = 0 }, -- StatusLineTerm + [18] = { background = 2, foreground = 8 }, -- StatusLineTermNC }) screen:attach(screen_opts or { rgb = false }) api.nvim_command('enew') - api.nvim_call_function('termopen', { command, env and { env = env } or nil }) + api.nvim_call_function('termopen', { cmd, env and { env = env } or nil }) api.nvim_input('<CR>') local vim_errmsg = api.nvim_eval('v:errmsg') if vim_errmsg and '' ~= vim_errmsg then @@ -129,7 +150,7 @@ local function screen_setup(extra_rows, command, cols, env, screen_opts) -- tty-test puts the terminal into raw mode and echoes input. Tests work by -- feeding termcodes to control the display and asserting by screen:expect. - if command == default_command and screen_opts == nil then + if cmd == default_command and screen_opts == nil then -- Wait for "tty ready" to be printed before each test or the terminal may -- still be in canonical mode (will echo characters for example). local empty_line = (' '):rep(cols) @@ -156,37 +177,24 @@ local function screen_setup(extra_rows, command, cols, env, screen_opts) return screen end -local function setup_child_nvim(args, opts) +--- Spawns Nvim with `args` in a :terminal, and returns a `Screen` object. +--- +--- @note Only use this if you actually need the full lifecycle/capabilities of the builtin Nvim +--- TUI. Most tests should just use `Screen.new()` directly, or plain old API calls. +--- +---@param args? string[] Args passed to child Nvim. +---@param opts? table Options +---@return test.functional.ui.screen # Screen attached to the global (not child) Nvim session. +function M.setup_child_nvim(args, opts) opts = opts or {} - local argv = { nvim_prog, unpack(args) } + local argv = { nvim_prog, unpack(args or {}) } local env = opts.env or {} if not env.VIMRUNTIME then env.VIMRUNTIME = os.getenv('VIMRUNTIME') end - return screen_setup(0, argv, opts.cols, env) -end - -return { - feed_data = feed_data, - feed_termcode = feed_termcode, - make_lua_executor = make_lua_executor, - hide_cursor = hide_cursor, - show_cursor = show_cursor, - enter_altscreen = enter_altscreen, - exit_altscreen = exit_altscreen, - set_fg = set_fg, - set_bg = set_bg, - set_bold = set_bold, - set_italic = set_italic, - set_underline = set_underline, - set_underdouble = set_underdouble, - set_undercurl = set_undercurl, - set_strikethrough = set_strikethrough, - clear_attrs = clear_attrs, - enable_mouse = enable_mouse, - disable_mouse = disable_mouse, - screen_setup = screen_setup, - setup_child_nvim = setup_child_nvim, -} + return M.setup_screen(opts.extra_rows, argv, opts.cols, env) +end + +return M diff --git a/test/functional/treesitter/fold_spec.lua b/test/functional/treesitter/fold_spec.lua index a7f278aa01..24b085920c 100644 --- a/test/functional/treesitter/fold_spec.lua +++ b/test/functional/treesitter/fold_spec.lua @@ -48,13 +48,13 @@ void ui_refresh(void) end local function get_fold_levels() - return exec_lua([[ - local res = {} - for i = 1, vim.api.nvim_buf_line_count(0) do - res[i] = vim.treesitter.foldexpr(i) - end - return res - ]]) + return exec_lua(function() + local res = {} + for i = 1, vim.api.nvim_buf_line_count(0) do + res[i] = vim.treesitter.foldexpr(i) + end + return res + end) end it('can compute fold levels', function() @@ -246,9 +246,13 @@ function f() end -- comment]]) - exec_lua( - [[vim.treesitter.query.set('lua', 'folds', '[(function_declaration) (parameters) (arguments)] @fold')]] - ) + exec_lua(function() + vim.treesitter.query.set( + 'lua', + 'folds', + '[(function_declaration) (parameters) (arguments)] @fold' + ) + end) parse('lua') eq({ @@ -290,9 +294,13 @@ function f() ) end]]) - exec_lua( - [[vim.treesitter.query.set('lua', 'folds', '[(function_declaration) (function_definition) (parameters) (arguments)] @fold')]] - ) + exec_lua(function() + vim.treesitter.query.set( + 'lua', + 'folds', + '[(function_declaration) (function_definition) (parameters) (arguments)] @fold' + ) + end) parse('lua') -- If fold1.stop = fold2.start, then move fold1's stop up so that fold2.start gets proper level. @@ -333,9 +341,13 @@ function f(a) end end]]) - exec_lua( - [[vim.treesitter.query.set('lua', 'folds', '[(if_statement) (function_declaration) (parameters) (arguments) (table_constructor)] @fold')]] - ) + exec_lua(function() + vim.treesitter.query.set( + 'lua', + 'folds', + '[(if_statement) (function_declaration) (parameters) (arguments) (table_constructor)] @fold' + ) + end) parse('lua') eq({ @@ -408,15 +420,15 @@ t3]]) it('handles quantified patterns', function() insert([[ -import hello -import hello -import hello -import hello -import hello -import hello]]) - - exec_lua([[vim.treesitter.query.set('python', 'folds', '(import_statement)+ @fold')]]) - parse('python') +-- hello +-- hello +-- hello +-- hello +-- hello +-- hello]]) + + exec_lua([[vim.treesitter.query.set('lua', 'folds', '(comment)+ @fold')]]) + parse('lua') eq({ [1] = '>1', @@ -646,6 +658,67 @@ import hello]]) } end) + it('does not extend closed fold with `o`/`O`', function() + local screen = Screen.new(60, 24) + screen:attach() + + insert(test_text) + parse('c') + command([[set foldmethod=expr foldexpr=v:lua.vim.treesitter.foldexpr() foldcolumn=1]]) + + feed('5ggzco') + screen:expect({ + grid = [[ + {7:-}void ui_refresh(void) | + {7:│}{ | + {7:│} int width = INT_MAX, height = INT_MAX; | + {7:│} bool ext_widgets[kUIExtCount]; | + {7:+}{13:+--- 3 lines: for (UIExtension i = 0; (int)i < kUIExtCount}| + {7:│}^ | + {7:│} | + {7:│} bool inclusive = ui_override(); | + {7:-} for (size_t i = 0; i < ui_count; i++) { | + {7:2} UI *ui = uis[i]; | + {7:2} width = MIN(ui->width, width); | + {7:2} height = MIN(ui->height, height); | + {7:2} foo = BAR(ui->bazaar, bazaar); | + {7:-} for (UIExtension j = 0; (int)j < kUIExtCount; j++) { | + {7:3} ext_widgets[j] &= (ui->ui_ext[j] || inclusive); | + {7:3} } | + {7:2} } | + {7:│}} | + {1:~ }|*5 + {5:-- INSERT --} | + ]], + }) + + feed('<Esc>O') + screen:expect({ + grid = [[ + {7:-}void ui_refresh(void) | + {7:│}{ | + {7:│} int width = INT_MAX, height = INT_MAX; | + {7:│} bool ext_widgets[kUIExtCount]; | + {7:+}{13:+--- 3 lines: for (UIExtension i = 0; (int)i < kUIExtCount}| + {7:│}^ | + {7:│} |*2 + {7:│} bool inclusive = ui_override(); | + {7:-} for (size_t i = 0; i < ui_count; i++) { | + {7:2} UI *ui = uis[i]; | + {7:2} width = MIN(ui->width, width); | + {7:2} height = MIN(ui->height, height); | + {7:2} foo = BAR(ui->bazaar, bazaar); | + {7:-} for (UIExtension j = 0; (int)j < kUIExtCount; j++) { | + {7:3} ext_widgets[j] &= (ui->ui_ext[j] || inclusive); | + {7:3} } | + {7:2} } | + {7:│}} | + {1:~ }|*4 + {5:-- INSERT --} | + ]], + }) + end) + it("doesn't open folds that are not touched", function() local screen = Screen.new(40, 8) screen:set_default_attr_ids({ @@ -674,7 +747,7 @@ t2]]) grid = [[ {1:-}# h1 | {1:│}t1 | - {1:│}^ | + {1:-}^ | {1:+}{2:+-- 2 lines: # h2·····················}| {3:~ }|*3 {4:-- INSERT --} | diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua index 69984b3233..b5a6cb5c17 100644 --- a/test/functional/treesitter/highlight_spec.lua +++ b/test/functional/treesitter/highlight_spec.lua @@ -8,10 +8,9 @@ local exec_lua = n.exec_lua local feed = n.feed local command = n.command local api = n.api +local fn = n.fn local eq = t.eq -before_each(clear) - local hl_query_c = [[ (ERROR) @error @@ -65,6 +64,46 @@ static int nlua_schedule(lua_State *const lstate) return 0; }]] +local hl_grid_legacy_c = [[ + {2:^/// Schedule Lua callback on main loop's event queue} | + {3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) | + { | + {4:if} (lua_type(lstate, {5:1}) != LUA_TFUNCTION | + || lstate != lstate) { | + lua_pushliteral(lstate, {5:"vim.schedule: expected function"}); | + {4:return} lua_error(lstate); | + } | + | + LuaRef cb = nlua_ref(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, nlua_schedule_event, | + {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | + {4:return} {5:0}; | + } | + {1:~ }|*2 + | +]] + +local hl_grid_ts_c = [[ + {2:^/// Schedule Lua callback on main loop's event queue} | + {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | + { | + {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | + || {6:lstate} != {6:lstate}) { | + {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); | + {4:return} {11:lua_error}(lstate); | + } | + | + {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | + {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | + {4:return} {5:0}; | + } | + {1:~ }|*2 + | +]] + local test_text_c = [[ void ui_refresh(void) { @@ -117,9 +156,10 @@ local injection_grid_expected_c = [[ ]] describe('treesitter highlighting (C)', function() - local screen + local screen --- @type test.functional.ui.screen before_each(function() + clear() screen = Screen.new(65, 18) screen:attach() screen:set_default_attr_ids { @@ -136,16 +176,49 @@ describe('treesitter highlighting (C)', function() [11] = { foreground = Screen.colors.Cyan4 }, } - exec_lua([[ hl_query = ... ]], hl_query_c) command [[ hi link @error ErrorMsg ]] command [[ hi link @warning WarningMsg ]] end) + it('starting and stopping treesitter highlight works', function() + command('setfiletype c | syntax on') + fn.setreg('r', hl_text_c) + feed('i<C-R><C-O>r<Esc>gg') + -- legacy syntax highlighting is used by default + screen:expect(hl_grid_legacy_c) + + exec_lua(function() + vim.treesitter.query.set('c', 'highlights', hl_query_c) + vim.treesitter.start() + end) + -- treesitter highlighting is used + screen:expect(hl_grid_ts_c) + + exec_lua(function() + vim.treesitter.stop() + end) + -- legacy syntax highlighting is used + screen:expect(hl_grid_legacy_c) + + exec_lua(function() + vim.treesitter.start() + end) + -- treesitter highlighting is used + screen:expect(hl_grid_ts_c) + + exec_lua(function() + vim.treesitter.stop() + end) + -- legacy syntax highlighting is used + screen:expect(hl_grid_legacy_c) + end) + it('is updated with edits', function() insert(hl_text_c) + feed('gg') screen:expect { grid = [[ - /// Schedule Lua callback on main loop's event queue | + ^/// Schedule Lua callback on main loop's event queue | static int nlua_schedule(lua_State *const lstate) | { | if (lua_type(lstate, 1) != LUA_TFUNCTION | @@ -159,38 +232,18 @@ describe('treesitter highlighting (C)', function() multiqueue_put(main_loop.events, nlua_schedule_event, | 1, (void *)(ptrdiff_t)cb); | return 0; | - ^} | + } | {1:~ }|*2 | ]], } - exec_lua [[ - local parser = vim.treesitter.get_parser(0, "c") + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') local highlighter = vim.treesitter.highlighter - test_hl = highlighter.new(parser, {queries = {c = hl_query}}) - ]] - screen:expect { - grid = [[ - {2:/// Schedule Lua callback on main loop's event queue} | - {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | - { | - {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | - || {6:lstate} != {6:lstate}) { | - {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); | - {4:return} {11:lua_error}(lstate); | - } | - | - {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | - | - multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | - {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | - {4:return} {5:0}; | - ^} | - {1:~ }|*2 - | - ]], - } + highlighter.new(parser, { queries = { c = hl_query_c } }) + end) + screen:expect(hl_grid_ts_c) feed('5Goc<esc>dd') @@ -316,10 +369,10 @@ describe('treesitter highlighting (C)', function() it('is updated with :sort', function() insert(test_text_c) - exec_lua [[ - local parser = vim.treesitter.get_parser(0, "c") - test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query}}) - ]] + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') + vim.treesitter.highlighter.new(parser, { queries = { c = hl_query_c } }) + end) screen:expect { grid = [[ {3:int} width = {5:INT_MAX}, height = {5:INT_MAX}; | @@ -422,19 +475,19 @@ describe('treesitter highlighting (C)', function() ]], } - exec_lua [[ - parser = vim.treesitter.get_parser(0, "c") - query = vim.treesitter.query.parse("c", "(declaration) @decl") + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') + local query = vim.treesitter.query.parse('c', '(declaration) @decl') local nodes = {} for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do table.insert(nodes, node) end - parser:set_included_regions({nodes}) + parser:set_included_regions({ nodes }) - local hl = vim.treesitter.highlighter.new(parser, {queries = {c = "(identifier) @type"}}) - ]] + vim.treesitter.highlighter.new(parser, { queries = { c = '(identifier) @type' } }) + end) screen:expect { grid = [[ @@ -465,13 +518,15 @@ describe('treesitter highlighting (C)', function() screen:expect { grid = injection_grid_c } - exec_lua [[ - local parser = vim.treesitter.get_parser(0, "c", { - injections = {c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))'} + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c', { + injections = { + c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))', + }, }) local highlighter = vim.treesitter.highlighter - test_hl = highlighter.new(parser, {queries = {c = hl_query}}) - ]] + highlighter.new(parser, { queries = { c = hl_query_c } }) + end) screen:expect { grid = injection_grid_expected_c } end) @@ -481,14 +536,16 @@ describe('treesitter highlighting (C)', function() screen:expect { grid = injection_grid_c } - exec_lua [[ - vim.treesitter.language.register("c", "foo") - local parser = vim.treesitter.get_parser(0, "c", { - injections = {c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "foo")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "foo"))'} + exec_lua(function() + vim.treesitter.language.register('c', 'foo') + local parser = vim.treesitter.get_parser(0, 'c', { + injections = { + c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "foo")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "foo"))', + }, }) local highlighter = vim.treesitter.highlighter - test_hl = highlighter.new(parser, {queries = {c = hl_query}}) - ]] + highlighter.new(parser, { queries = { c = hl_query_c } }) + end) screen:expect { grid = injection_grid_expected_c } end) @@ -502,13 +559,14 @@ describe('treesitter highlighting (C)', function() } ]]) - exec_lua [[ - local injection_query = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' - vim.treesitter.query.set("c", "highlights", hl_query) - vim.treesitter.query.set("c", "injections", injection_query) + exec_lua(function() + local injection_query = + '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' + vim.treesitter.query.set('c', 'highlights', hl_query_c) + vim.treesitter.query.set('c', 'injections', injection_query) - vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, "c")) - ]] + vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c')) + end) screen:expect { grid = [[ @@ -526,40 +584,21 @@ describe('treesitter highlighting (C)', function() it('supports highlighting with custom highlight groups', function() insert(hl_text_c) + feed('gg') - exec_lua [[ - local parser = vim.treesitter.get_parser(0, "c") - test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query}}) - ]] + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') + vim.treesitter.highlighter.new(parser, { queries = { c = hl_query_c } }) + end) - screen:expect { - grid = [[ - {2:/// Schedule Lua callback on main loop's event queue} | - {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | - { | - {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | - || {6:lstate} != {6:lstate}) { | - {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); | - {4:return} {11:lua_error}(lstate); | - } | - | - {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | - | - multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | - {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | - {4:return} {5:0}; | - ^} | - {1:~ }|*2 - | - ]], - } + screen:expect(hl_grid_ts_c) -- This will change ONLY the literal strings to look like comments -- The only literal string is the "vim.schedule: expected function" in this test. exec_lua [[vim.cmd("highlight link @string.nonexistent_specializer comment")]] screen:expect { grid = [[ - {2:/// Schedule Lua callback on main loop's event queue} | + {2:^/// Schedule Lua callback on main loop's event queue} | {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | { | {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | @@ -573,7 +612,7 @@ describe('treesitter highlighting (C)', function() multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | {4:return} {5:0}; | - ^} | + } | {1:~ }|*2 | ]], @@ -590,10 +629,14 @@ describe('treesitter highlighting (C)', function() } ]]) - exec_lua [[ - local parser = vim.treesitter.get_parser(0, "c") - test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query..'\n((translation_unit) @constant (#set! "priority" 101))\n'}}) - ]] + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') + vim.treesitter.highlighter.new(parser, { + queries = { + c = hl_query_c .. '\n((translation_unit) @constant (#set! "priority" 101))\n', + }, + }) + end) -- expect everything to have Constant highlight screen:expect { grid = [[ @@ -640,11 +683,14 @@ describe('treesitter highlighting (C)', function() hi link @foo.bar Type hi link @foo String ]] - exec_lua [[ - local parser = vim.treesitter.get_parser(0, "c", {}) - local highlighter = vim.treesitter.highlighter - test_hl = highlighter.new(parser, {queries = {c = "(primitive_type) @foo.bar (string_literal) @foo"}}) - ]] + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c', {}) + local highlighter = vim.treesitter.highlighter + highlighter.new( + parser, + { queries = { c = '(primitive_type) @foo.bar (string_literal) @foo' } } + ) + end) screen:expect { grid = [[ @@ -672,10 +718,12 @@ describe('treesitter highlighting (C)', function() insert(hl_text_c) -- conceal can be empty or a single cchar. - exec_lua [=[ + exec_lua(function() vim.opt.cole = 2 - local parser = vim.treesitter.get_parser(0, "c") - test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = [[ + local parser = vim.treesitter.get_parser(0, 'c') + vim.treesitter.highlighter.new(parser, { + queries = { + c = [[ ("static" @keyword (#set! conceal "R")) @@ -688,8 +736,10 @@ describe('treesitter highlighting (C)', function() arguments: (argument_list) @arguments) (#eq? @function "multiqueue_put") (#set! @function conceal "V")) - ]]}}) - ]=] + ]], + }, + }) + end) screen:expect { grid = [[ @@ -746,11 +796,11 @@ describe('treesitter highlighting (C)', function() int z = 6; ]]) - exec_lua([[ + exec_lua(function() local query = '((declaration)+ @string)' vim.treesitter.query.set('c', 'highlights', query) vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c')) - ]]) + end) screen:expect { grid = [[ @@ -776,14 +826,10 @@ describe('treesitter highlighting (C)', function() declarator: (pointer_declarator) @variable.parameter) ]] - exec_lua( - [[ - local query = ... + exec_lua(function() vim.treesitter.query.set('c', 'highlights', query) vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c')) - ]], - query - ) + end) screen:expect { grid = [[ @@ -800,6 +846,7 @@ describe('treesitter highlighting (lua)', function() local screen before_each(function() + clear() screen = Screen.new(65, 18) screen:attach() screen:set_default_attr_ids { @@ -817,10 +864,10 @@ describe('treesitter highlighting (lua)', function() ffi.cdef("int (*fun)(int, char *);") ]] - exec_lua [[ + exec_lua(function() vim.bo.filetype = 'lua' vim.treesitter.start() - ]] + end) screen:expect { grid = [[ @@ -838,6 +885,7 @@ describe('treesitter highlighting (help)', function() local screen before_each(function() + clear() screen = Screen.new(40, 6) screen:attach() screen:set_default_attr_ids { @@ -846,9 +894,45 @@ describe('treesitter highlighting (help)', function() [3] = { bold = true, foreground = Screen.colors.Brown }, [4] = { foreground = Screen.colors.Cyan4 }, [5] = { foreground = Screen.colors.Magenta1 }, + title = { bold = true, foreground = Screen.colors.Magenta1 }, + h1_delim = { nocombine = true, underdouble = true }, + h2_delim = { nocombine = true, underline = true }, } end) + it('defaults in vimdoc/highlights.scm', function() + -- Avoid regressions when syncing upstream vimdoc queries. + + insert [[ + ============================================================================== + NVIM DOCUMENTATION + + ------------------------------------------------------------------------------ + ABOUT NVIM *tag-1* *tag-2* + + |news| News + |nvim| NVim + ]] + + feed('gg') + exec_lua(function() + vim.wo.wrap = false + vim.bo.filetype = 'help' + vim.treesitter.start() + end) + + screen:expect({ + grid = [[ + {h1_delim:^========================================}| + {title:NVIM DOCUMENTATION} | + | + {h2_delim:----------------------------------------}| + {title:ABOUT NVIM} | + | + ]], + }) + end) + it('correctly redraws added/removed injections', function() insert [[ >ruby @@ -857,10 +941,10 @@ describe('treesitter highlighting (help)', function() < ]] - exec_lua [[ + exec_lua(function() vim.bo.filetype = 'help' vim.treesitter.start() - ]] + end) screen:expect { grid = [[ @@ -912,15 +996,15 @@ describe('treesitter highlighting (help)', function() ]] ]=]) - exec_lua [[ - parser = vim.treesitter.get_parser(0, "lua", { + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'lua', { injections = { - lua = '(string content: (_) @injection.content (#set! injection.language lua))' - } + lua = '(string content: (_) @injection.content (#set! injection.language lua))', + }, }) vim.treesitter.highlighter.new(parser) - ]] + end) screen:expect { grid = [=[ @@ -936,9 +1020,10 @@ describe('treesitter highlighting (help)', function() end) describe('treesitter highlighting (nested injections)', function() - local screen + local screen --- @type test.functional.ui.screen before_each(function() + clear() screen = Screen.new(80, 7) screen:attach() screen:set_default_attr_ids { @@ -964,11 +1049,11 @@ vim.cmd([[ ]]) ]=] - exec_lua [[ + exec_lua(function() vim.opt.scrolloff = 0 vim.bo.filetype = 'lua' vim.treesitter.start() - ]] + end) -- invalidate the language tree feed('ggi--[[<ESC>04x') @@ -1006,41 +1091,93 @@ describe('treesitter highlighting (markdown)', function() local screen before_each(function() + clear() screen = Screen.new(40, 6) screen:attach() - screen:set_default_attr_ids { - [1] = { foreground = Screen.colors.Blue1 }, - [2] = { bold = true, foreground = Screen.colors.Blue1 }, - [3] = { bold = true, foreground = Screen.colors.Brown }, - [4] = { foreground = Screen.colors.Cyan4 }, - [5] = { foreground = Screen.colors.Magenta1 }, - } + exec_lua(function() + vim.bo.filetype = 'markdown' + vim.treesitter.start() + end) end) it('supports hyperlinks', function() local url = 'https://example.com' insert(string.format('[This link text](%s) is a hyperlink.', url)) - exec_lua([[ - vim.bo.filetype = 'markdown' - vim.treesitter.start() - ]]) + screen:add_extra_attr_ids({ + [100] = { foreground = Screen.colors.DarkCyan, url = 'https://example.com' }, + [101] = { + foreground = Screen.colors.SlateBlue, + url = 'https://example.com', + underline = true, + }, + }) + screen:expect({ + grid = [[ + {25:[}{100:This link text}{25:](}{101:https://example.com}{25:)} is| + a hyperlink^. | + {1:~ }|*3 + | + ]], + }) + end) - screen:expect { + it('works with spellchecked and smoothscrolled topline', function() + insert([[ +- $f(0)=\sum_{k=1}^{\infty}\frac{2}{\pi^{2}k^{2}}+\lim_{w \to 0}x$. + +```c +printf('Hello World!'); +``` + ]]) + command('set spell smoothscroll') + feed('gg<C-E>') + screen:add_extra_attr_ids({ [100] = { undercurl = true, special = Screen.colors.Red } }) + screen:expect({ grid = [[ - {4:[}{6:This link text}{4:](}{7:https://example.com}{4:)} is| - a hyperlink^. | - {2:~ }|*3 - | - ]], - attr_ids = { - [1] = { foreground = Screen.colors.Blue1 }, - [2] = { bold = true, foreground = Screen.colors.Blue1 }, - [3] = { bold = true, foreground = Screen.colors.Brown }, - [4] = { foreground = Screen.colors.Cyan4 }, - [5] = { foreground = Screen.colors.Magenta }, - [6] = { foreground = Screen.colors.Cyan4, url = url }, - [7] = { underline = true, foreground = Screen.colors.SlateBlue }, - }, - } + {1:<<<}k^{2}}+\{100:lim}_{w \to 0}x$^. | + | + {18:```}{15:c} | + {25:printf}{16:(}{26:'Hello World!'}{16:);} | + {18:```} | + | + ]], + }) end) end) + +it('starting and stopping treesitter highlight in init.lua works #29541', function() + t.write_file( + 'Xinit.lua', + [[ + vim.bo.ft = 'c' + vim.treesitter.start() + vim.treesitter.stop() + ]] + ) + finally(function() + os.remove('Xinit.lua') + end) + clear({ args = { '-u', 'Xinit.lua' } }) + eq('', api.nvim_get_vvar('errmsg')) + + local screen = Screen.new(65, 18) + screen:attach() + screen:set_default_attr_ids { + [1] = { bold = true, foreground = Screen.colors.Blue1 }, + [2] = { foreground = Screen.colors.Blue1 }, + [3] = { bold = true, foreground = Screen.colors.SeaGreen4 }, + [4] = { bold = true, foreground = Screen.colors.Brown }, + [5] = { foreground = Screen.colors.Magenta }, + [6] = { foreground = Screen.colors.Red }, + [7] = { bold = true, foreground = Screen.colors.SlateBlue }, + [8] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, + [9] = { foreground = Screen.colors.Magenta, background = Screen.colors.Red }, + [10] = { foreground = Screen.colors.Red, background = Screen.colors.Red }, + [11] = { foreground = Screen.colors.Cyan4 }, + } + + fn.setreg('r', hl_text_c) + feed('i<C-R><C-O>r<Esc>gg') + -- legacy syntax highlighting is used + screen:expect(hl_grid_legacy_c) +end) diff --git a/test/functional/treesitter/inspect_tree_spec.lua b/test/functional/treesitter/inspect_tree_spec.lua index f5acfe7c4a..1f7d15cc96 100644 --- a/test/functional/treesitter/inspect_tree_spec.lua +++ b/test/functional/treesitter/inspect_tree_spec.lua @@ -22,10 +22,10 @@ describe('vim.treesitter.inspect_tree', function() print() ]]) - exec_lua([[ + exec_lua(function() vim.treesitter.start(0, 'lua') vim.treesitter.inspect_tree() - ]]) + end) expect_tree [[ (chunk ; [0, 0] - [2, 0] @@ -37,22 +37,26 @@ describe('vim.treesitter.inspect_tree', function() it('can toggle to show anonymous nodes', function() insert([[ - print() + print('hello') ]]) - exec_lua([[ + exec_lua(function() vim.treesitter.start(0, 'lua') vim.treesitter.inspect_tree() - ]]) + end) feed('a') expect_tree [[ (chunk ; [0, 0] - [2, 0] - (function_call ; [0, 0] - [0, 7] + (function_call ; [0, 0] - [0, 14] name: (identifier) ; [0, 0] - [0, 5] - arguments: (arguments ; [0, 5] - [0, 7] + arguments: (arguments ; [0, 5] - [0, 14] "(" ; [0, 5] - [0, 6] - ")"))) ; [0, 6] - [0, 7] + (string ; [0, 6] - [0, 13] + start: "'" ; [0, 6] - [0, 7] + content: (string_content) ; [0, 7] - [0, 12] + end: "'") ; [0, 12] - [0, 13] + ")"))) ; [0, 13] - [0, 14] ]] end) @@ -63,11 +67,11 @@ describe('vim.treesitter.inspect_tree', function() ``` ]]) - exec_lua([[ + exec_lua(function() vim.treesitter.start(0, 'markdown') vim.treesitter.get_parser():parse() vim.treesitter.inspect_tree() - ]]) + end) expect_tree [[ (document ; [0, 0] - [4, 0] @@ -92,11 +96,11 @@ describe('vim.treesitter.inspect_tree', function() ``` ]]) - exec_lua([[ + exec_lua(function() vim.treesitter.start(0, 'markdown') vim.treesitter.get_parser():parse() vim.treesitter.inspect_tree() - ]]) + end) feed('I') expect_tree [[ @@ -114,4 +118,57 @@ describe('vim.treesitter.inspect_tree', function() (fenced_code_block_delimiter)))) ; [2, 0] - [2, 3] markdown ]] end) + + it('updates source and tree buffer windows and closes them correctly', function() + insert([[ + print() + ]]) + + -- setup two windows for the source buffer + exec_lua(function() + _G.source_win = vim.api.nvim_get_current_win() + vim.api.nvim_open_win(0, false, { + win = 0, + split = 'left', + }) + end) + + -- setup three windows for the tree buffer + exec_lua(function() + vim.treesitter.start(0, 'lua') + vim.treesitter.inspect_tree() + _G.tree_win = vim.api.nvim_get_current_win() + _G.tree_win_copy_1 = vim.api.nvim_open_win(0, false, { + win = 0, + split = 'left', + }) + _G.tree_win_copy_2 = vim.api.nvim_open_win(0, false, { + win = 0, + split = 'left', + }) + end) + + -- close original source window + exec_lua('vim.api.nvim_win_close(source_win, false)') + + -- navigates correctly to the remaining source buffer window + feed('<CR>') + eq('', n.api.nvim_get_vvar('errmsg')) + + -- close original tree window + exec_lua(function() + vim.api.nvim_set_current_win(_G.tree_win_copy_1) + vim.api.nvim_win_close(_G.tree_win, false) + end) + + -- navigates correctly to the remaining source buffer window + feed('<CR>') + eq('', n.api.nvim_get_vvar('errmsg')) + + -- close source buffer window and all remaining tree windows + t.pcall_err(exec_lua, 'vim.api.nvim_win_close(0, false)') + + eq(false, exec_lua('return vim.api.nvim_win_is_valid(tree_win_copy_1)')) + eq(false, exec_lua('return vim.api.nvim_win_is_valid(tree_win_copy_2)')) + end) end) diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index 40c974beee..e1e34fcecc 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -8,6 +8,7 @@ local exec_lua = n.exec_lua local pcall_err = t.pcall_err local matches = t.matches local insert = n.insert +local NIL = vim.NIL before_each(clear) @@ -15,10 +16,12 @@ describe('treesitter language API', function() -- error tests not requiring a parser library it('handles missing language', function() eq( - ".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", + '.../treesitter.lua:0: Parser could not be created for buffer 1 and language "borklang"', pcall_err(exec_lua, "parser = vim.treesitter.get_parser(0, 'borklang')") ) + eq(NIL, exec_lua("return vim.treesitter.get_parser(0, 'borklang', { error = false })")) + -- actual message depends on platform matches( "Failed to load parser for language 'borklang': uv_dlopen: .+", @@ -28,37 +31,33 @@ describe('treesitter language API', function() ) ) - eq(false, exec_lua("return pcall(vim.treesitter.language.add, 'borklang')")) + eq(NIL, exec_lua("return vim.treesitter.language.add('borklang')")) eq( false, exec_lua("return pcall(vim.treesitter.language.add, 'borklang', { path = 'borkbork.so' })") ) - eq( - ".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", - pcall_err(exec_lua, "parser = vim.treesitter.language.inspect('borklang')") - ) - matches( 'Failed to load parser: uv_dlsym: .+', pcall_err(exec_lua, 'vim.treesitter.language.add("c", { symbol_name = "borklang" })') ) end) - it('shows error for invalid language name', function() - eq( - ".../language.lua:0: '/foo/' is not a valid language name", - pcall_err(exec_lua, 'vim.treesitter.language.add("/foo/")') - ) + it('does not load parser for invalid language name', function() + eq(NIL, exec_lua('vim.treesitter.language.add("/foo/")')) end) it('inspects language', function() - local keys, fields, symbols = unpack(exec_lua([[ + local keys, fields, symbols = unpack(exec_lua(function() local lang = vim.treesitter.language.inspect('c') local keys, symbols = {}, {} - for k,_ in pairs(lang) do - keys[k] = true + for k, v in pairs(lang) do + if type(v) == 'boolean' then + keys[k] = v + else + keys[k] = true + end end -- symbols array can have "holes" and is thus not a valid msgpack array @@ -66,10 +65,10 @@ describe('treesitter language API', function() for _, v in pairs(lang.symbols) do table.insert(symbols, v) end - return {keys, lang.fields, symbols} - ]])) + return { keys, lang.fields, symbols } + end)) - eq({ fields = true, symbols = true, _abi_version = true }, keys) + eq({ fields = true, symbols = true, _abi_version = true, _wasm = false }, keys) local fset = {} for _, f in pairs(fields) do @@ -101,9 +100,10 @@ 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", + '.../treesitter.lua:0: Parser could not be created for buffer 1 and language "borklang"', pcall_err(exec_lua, "new_parser = vim.treesitter.get_parser(0, 'borklang')") ) + eq(NIL, exec_lua("return vim.treesitter.get_parser(0, 'borklang', { error = false })")) end ) @@ -113,12 +113,14 @@ describe('treesitter language API', function() int x = 3; }]]) - exec_lua([[ - langtree = vim.treesitter.get_parser(0, "c") - tree = langtree:tree_for_range({1, 3, 1, 3}) - ]]) - - eq('<node translation_unit>', exec_lua('return tostring(tree:root())')) + eq( + '<node translation_unit>', + exec_lua(function() + local langtree = vim.treesitter.get_parser(0, 'c') + local tree = langtree:tree_for_range({ 1, 3, 1, 3 }) + return tostring(tree:root()) + end) + ) end) it('retrieve the tree given a range when range is out of bounds relative to buffer', function() @@ -127,12 +129,14 @@ describe('treesitter language API', function() int x = 3; }]]) - exec_lua([[ - langtree = vim.treesitter.get_parser(0, "c") - tree = langtree:tree_for_range({10, 10, 10, 10}) - ]]) - - eq('<node translation_unit>', exec_lua('return tostring(tree:root())')) + eq( + '<node translation_unit>', + exec_lua(function() + local langtree = vim.treesitter.get_parser(0, 'c') + local tree = langtree:tree_for_range({ 10, 10, 10, 10 }) + return tostring(tree:root()) + end) + ) end) it('retrieve the node given a range', function() @@ -141,11 +145,24 @@ describe('treesitter language API', function() int x = 3; }]]) - exec_lua([[ - langtree = vim.treesitter.get_parser(0, "c") - node = langtree:named_node_for_range({1, 3, 1, 3}) - ]]) + eq( + '<node primitive_type>', + exec_lua(function() + local langtree = vim.treesitter.get_parser(0, 'c') + local node = langtree:named_node_for_range({ 1, 3, 1, 3 }) + return tostring(node) + end) + ) + end) + + it('retrieve an anonymous node given a range', function() + insert([[vim.fn.input()]]) + + exec_lua(function() + _G.langtree = vim.treesitter.get_parser(0, 'lua') + _G.node = _G.langtree:node_for_range({ 0, 3, 0, 3 }) + end) - eq('<node primitive_type>', exec_lua('return tostring(node)')) + eq('.', exec_lua('return node:type()')) end) end) diff --git a/test/functional/treesitter/node_spec.lua b/test/functional/treesitter/node_spec.lua index 96579f296b..d07ed35368 100644 --- a/test/functional/treesitter/node_spec.lua +++ b/test/functional/treesitter/node_spec.lua @@ -18,43 +18,60 @@ describe('treesitter node API', function() it('double free tree', function() insert('F') - exec_lua([[ + exec_lua(function() vim.treesitter.start(0, 'lua') vim.treesitter.get_node():tree() vim.treesitter.get_node():tree() collectgarbage() - ]]) + end) assert_alive() end) it('double free tree 2', function() - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') local x = parser:parse()[1]:root():tree() - vim.api.nvim_buf_set_text(0, 0,0, 0,0, {'y'}) + vim.api.nvim_buf_set_text(0, 0, 0, 0, 0, { 'y' }) parser:parse() - vim.api.nvim_buf_set_text(0, 0,0, 0,1, {'z'}) + vim.api.nvim_buf_set_text(0, 0, 0, 0, 1, { 'z' }) parser:parse() collectgarbage() x:root() - ]]) + end) assert_alive() end) it('get_node() with lang given', function() -- this buffer doesn't have filetype set! insert('local foo = function() end') - exec_lua([[ - node = vim.treesitter.get_node({ + exec_lua(function() + _G.node = vim.treesitter.get_node({ bufnr = 0, - pos = { 0, 6 }, -- on "foo" + pos = { 0, 6 }, -- on "foo" lang = 'lua', }) - ]]) + end) eq('foo', lua_eval('vim.treesitter.get_node_text(node, 0)')) eq('identifier', lua_eval('node:type()')) end) + it('get_node() with anonymous nodes included', function() + insert([[print('test')]]) + + exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'lua') + _G.tree = _G.parser:parse()[1] + _G.node = vim.treesitter.get_node({ + bufnr = 0, + pos = { 0, 6 }, -- on the first apostrophe + include_anonymous = true, + }) + end) + + eq("'", lua_eval('node:type()')) + eq(false, lua_eval('node:named()')) + end) + it('can move between siblings', function() insert([[ int main(int x, int y, int z) { @@ -62,16 +79,16 @@ describe('treesitter node API', function() } ]]) - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - root = tree:root() - lang = vim.treesitter.language.inspect('c') + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + _G.root = tree:root() + vim.treesitter.language.inspect('c') - function node_text(node) + function _G.node_text(node) return vim.treesitter.get_node_text(node, 0) end - ]]) + end) exec_lua 'node = root:descendant_for_range(0, 11, 0, 16)' eq('int x', lua_eval('node_text(node)')) @@ -101,13 +118,13 @@ describe('treesitter node API', function() int x = 3; }]]) - local len = exec_lua([[ - tree = vim.treesitter.get_parser(0, "c"):parse()[1] - node = tree:root():child(0) - children = node:named_children() + local len = exec_lua(function() + local tree = vim.treesitter.get_parser(0, 'c'):parse()[1] + local node = assert(tree:root():child(0)) + _G.children = node:named_children() - return #children - ]]) + return #_G.children + end) eq(3, len) eq('<node compound_statement>', lua_eval('tostring(children[3])')) @@ -119,11 +136,11 @@ describe('treesitter node API', function() int x = 3; }]]) - exec_lua([[ - tree = vim.treesitter.get_parser(0, "c"):parse()[1] - root = tree:root() - node = root:child(0):child(2) - ]]) + exec_lua(function() + local tree = vim.treesitter.get_parser(0, 'c'):parse()[1] + _G.root = tree:root() + _G.node = _G.root:child(0):child(2) + end) eq(lua_eval('tostring(root)'), lua_eval('tostring(node:root())')) end) @@ -134,11 +151,11 @@ describe('treesitter node API', function() int x = 3; }]]) - exec_lua([[ - tree = vim.treesitter.get_parser(0, "c"):parse()[1] - root = tree:root() - child = root:child(0):child(0) - ]]) + exec_lua(function() + local tree = vim.treesitter.get_parser(0, 'c'):parse()[1] + _G.root = tree:root() + _G.child = _G.root:child(0):child(0) + end) eq(28, lua_eval('root:byte_length()')) eq(3, lua_eval('child:byte_length()')) @@ -150,15 +167,15 @@ describe('treesitter node API', function() int x = 3; }]]) - exec_lua([[ - tree = vim.treesitter.get_parser(0, "c"):parse()[1] - root = tree:root() - main = root:child(0) - body = main:child(2) - statement = body:child(1) - declarator = statement:child(1) - value = declarator:child(1) - ]]) + exec_lua(function() + local tree = vim.treesitter.get_parser(0, 'c'):parse()[1] + _G.root = tree:root() + _G.main = _G.root:child(0) + _G.body = _G.main:child(2) + _G.statement = _G.body:child(1) + _G.declarator = _G.statement:child(1) + _G.value = _G.declarator:child(1) + end) eq(lua_eval('main:type()'), lua_eval('root:child_containing_descendant(value):type()')) eq(lua_eval('body:type()'), lua_eval('main:child_containing_descendant(value):type()')) diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index dbd6bb3c23..c8829f4785 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -12,9 +12,9 @@ local feed = n.feed describe('treesitter parser API', function() before_each(function() clear() - exec_lua [[ + exec_lua(function() vim.g.__ts_debug = 1 - ]] + end) end) it('parses buffer', function() @@ -23,12 +23,12 @@ describe('treesitter parser API', function() int x = 3; }]]) - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - root = tree:root() - lang = vim.treesitter.language.inspect('c') - ]]) + exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'c') + _G.tree = _G.parser:parse()[1] + _G.root = _G.tree:root() + _G.lang = vim.treesitter.language.inspect('c') + end) eq('<tree>', exec_lua('return tostring(tree)')) eq('<node translation_unit>', exec_lua('return tostring(root)')) @@ -59,11 +59,11 @@ describe('treesitter parser API', function() ) feed('2G7|ay') - exec_lua([[ - tree2 = parser:parse()[1] - root2 = tree2:root() - descendant2 = root2:descendant_for_range(1,2,1,13) - ]]) + exec_lua(function() + _G.tree2 = _G.parser:parse()[1] + _G.root2 = _G.tree2:root() + _G.descendant2 = _G.root2:descendant_for_range(1, 2, 1, 13) + end) eq(false, exec_lua('return tree2 == tree1')) eq(false, exec_lua('return root2 == root')) eq('<node declaration>', exec_lua('return tostring(descendant2)')) @@ -112,17 +112,17 @@ void ui_refresh(void) it('allows to iterate over nodes children', function() insert(test_text) - local res = exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") + local res = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') - func_node = parser:parse()[1]:root():child(0) + local func_node = parser:parse()[1]:root():child(0) - res = {} + local res = {} for node, field in func_node:iter_children() do table.insert(res, { node:type(), field }) end return res - ]]) + end) eq({ { 'primitive_type', 'type' }, @@ -135,9 +135,7 @@ void ui_refresh(void) insert(test_text) eq( - '.../treesitter.lua:0: There is no parser available for buffer 1 and one' - .. ' could not be created because lang could not be determined. Either' - .. ' pass lang or set the buffer filetype', + '.../treesitter.lua:0: Parser not found for buffer 1: language could not be determined', pcall_err(exec_lua, 'vim.treesitter.get_parser(0)') ) @@ -148,43 +146,43 @@ void ui_refresh(void) it('allows to get a child by field', function() insert(test_text) - local res = exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") + local res = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') - func_node = parser:parse()[1]:root():child(0) + _G.func_node = parser:parse()[1]:root():child(0) local res = {} - for _, node in ipairs(func_node:field("type")) do + for _, node in ipairs(_G.func_node:field('type')) do table.insert(res, { node:type(), node:range() }) end return res - ]]) + end) eq({ { 'primitive_type', 0, 0, 0, 4 } }, res) - local res_fail = exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") + local res_fail = exec_lua(function() + vim.treesitter.get_parser(0, 'c') - return #func_node:field("foo") == 0 - ]]) + return #_G.func_node:field('foo') == 0 + end) assert(res_fail) end) it('supports getting text of multiline node', function() insert(test_text) - local res = exec_lua([[ - local parser = vim.treesitter.get_parser(0, "c") + local res = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') local tree = parser:parse()[1] return vim.treesitter.get_node_text(tree:root(), 0) - ]]) + end) eq(test_text, res) - local res2 = exec_lua([[ - local parser = vim.treesitter.get_parser(0, "c") + local res2 = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') local root = parser:parse()[1]:root() return vim.treesitter.get_node_text(root:child(0):child(0), 0) - ]]) + end) eq('void', res2) end) @@ -196,7 +194,7 @@ end]] insert(text) eq( '', - exec_lua [[ + exec_lua(function() local fake_node = {} function fake_node:start() return 3, 0, 23 @@ -211,7 +209,7 @@ end]] return 3, 0, 3, 0 end return vim.treesitter.get_node_text(fake_node, 0) - ]] + end) ) end) @@ -221,7 +219,7 @@ end]] {} ```]] insert(text) - local result = exec_lua([[ + local result = exec_lua(function() local fake_node = {} function fake_node:start() return 1, 0, 7 @@ -233,38 +231,38 @@ end]] return 1, 0, 1, 0 end return vim.treesitter.get_node_text(fake_node, 0) == '' - ]]) + end) eq(true, result) end) it('allows to set simple ranges', function() insert(test_text) - local res = exec_lua [[ - parser = vim.treesitter.get_parser(0, "c") - return { parser:parse()[1]:root():range() } - ]] + local res = exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'c') + return { _G.parser:parse()[1]:root():range() } + end) eq({ 0, 0, 19, 0 }, res) -- The following sets the included ranges for the current parser -- As stated here, this only includes the function (thus the whole buffer, without the last line) - local res2 = exec_lua [[ - local root = parser:parse()[1]:root() - parser:set_included_regions({{root:child(0)}}) - parser:invalidate() - return { parser:parse(true)[1]:root():range() } - ]] + local res2 = exec_lua(function() + local root = _G.parser:parse()[1]:root() + _G.parser:set_included_regions({ { root:child(0) } }) + _G.parser:invalidate() + return { _G.parser:parse(true)[1]:root():range() } + end) eq({ 0, 0, 18, 1 }, res2) eq({ { { 0, 0, 0, 18, 1, 512 } } }, exec_lua [[ return parser:included_regions() ]]) - local range_tbl = exec_lua [[ - parser:set_included_regions { { { 0, 0, 17, 1 } } } - parser:parse() - return parser:included_regions() - ]] + local range_tbl = exec_lua(function() + _G.parser:set_included_regions { { { 0, 0, 17, 1 } } } + _G.parser:parse() + return _G.parser:included_regions() + end) eq({ { { 0, 0, 0, 17, 1, 508 } } }, range_tbl) end) @@ -272,25 +270,25 @@ end]] it('allows to set complex ranges', function() insert(test_text) - local res = exec_lua [[ - parser = vim.treesitter.get_parser(0, "c") - query = vim.treesitter.query.parse("c", "(declaration) @decl") + local res = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') + local query = vim.treesitter.query.parse('c', '(declaration) @decl') - local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do - table.insert(nodes, node) - end + local nodes = {} + for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do + table.insert(nodes, node) + end - parser:set_included_regions({nodes}) + parser:set_included_regions({ nodes }) - local root = parser:parse(true)[1]:root() + local root = parser:parse(true)[1]:root() - local res = {} - for i=0,(root:named_child_count() - 1) do - table.insert(res, { root:named_child(i):range() }) - end - return res - ]] + local res = {} + for i = 0, (root:named_child_count() - 1) do + table.insert(res, { root:named_child(i):range() }) + end + return res + end) eq({ { 2, 2, 2, 40 }, @@ -304,10 +302,10 @@ end]] end) it('allows to create string parsers', function() - local ret = exec_lua [[ - local parser = vim.treesitter.get_string_parser("int foo = 42;", "c") + local ret = exec_lua(function() + local parser = vim.treesitter.get_string_parser('int foo = 42;', 'c') return { parser:parse()[1]:root():range() } - ]] + end) eq({ 0, 0, 0, 13 }, ret) end) @@ -318,33 +316,31 @@ end]] int bar = 13; ]] - local ret = exec_lua( - [[ - local str = ... - local parser = vim.treesitter.get_string_parser(str, "c") + local ret = exec_lua(function(str) + local parser = vim.treesitter.get_string_parser(str, 'c') - local nodes = {} - local query = vim.treesitter.query.parse("c", '((identifier) @id (#eq? @id "foo"))') + local nodes = {} + local query = vim.treesitter.query.parse('c', '((identifier) @id (#eq? @id "foo"))') - for _, node in query:iter_captures(parser:parse()[1]:root(), str) do - table.insert(nodes, { node:range() }) - end + for _, node in query:iter_captures(parser:parse()[1]:root(), str) do + table.insert(nodes, { node:range() }) + end - return nodes - ]], - txt - ) + return nodes + end, txt) eq({ { 0, 10, 0, 13 } }, ret) end) describe('when creating a language tree', function() local function get_ranges() - return exec_lua [[ + return exec_lua(function() local result = {} - parser:for_each_tree(function(tree) table.insert(result, {tree:root():range()}) end) + _G.parser:for_each_tree(function(tree) + table.insert(result, { tree:root():range() }) + end) return result - ]] + end) end before_each(function() @@ -360,16 +356,17 @@ int x = INT_MAX; describe('when parsing regions independently', function() it('should inject a language', function() - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c", { + exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'c', { injections = { c = ( - '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) ' .. - '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' - ) - }}) - parser:parse(true) - ]]) + '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) ' + .. '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' + ), + }, + }) + _G.parser:parse(true) + end) eq('table', exec_lua('return type(parser:children().c)')) eq(5, exec_lua('return #parser:children().c:trees()')) @@ -397,16 +394,17 @@ int x = INT_MAX; describe('when parsing regions combined', function() it('should inject a language', function() - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c", { + exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'c', { injections = { c = ( - '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c") (#set! injection.combined)) ' .. - '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c") (#set! injection.combined))' - ) - }}) - parser:parse(true) - ]]) + '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c") (#set! injection.combined)) ' + .. '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c") (#set! injection.combined))' + ), + }, + }) + _G.parser:parse(true) + end) eq('table', exec_lua('return type(parser:children().c)')) eq(2, exec_lua('return #parser:children().c:trees()')) @@ -447,16 +445,17 @@ int x = INT_MAX; describe('when using injection.self', function() it('should inject the source language', function() - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c", { + exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'c', { injections = { c = ( - '(preproc_def (preproc_arg) @injection.content (#set! injection.self)) ' .. - '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.self))' - ) - }}) - parser:parse(true) - ]]) + '(preproc_def (preproc_arg) @injection.content (#set! injection.self)) ' + .. '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.self))' + ), + }, + }) + _G.parser:parse(true) + end) eq('table', exec_lua('return type(parser:children().c)')) eq(5, exec_lua('return #parser:children().c:trees()')) @@ -484,16 +483,17 @@ int x = INT_MAX; describe('when using the offset directive', function() it('should shift the range by the directive amount', function() - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c", { + exec_lua(function() + _G.parser = vim.treesitter.get_parser(0, 'c', { injections = { c = ( - '(preproc_def ((preproc_arg) @injection.content (#set! injection.language "c") (#offset! @injection.content 0 2 0 -1))) ' .. - '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' - ) - }}) - parser:parse(true) - ]]) + '(preproc_def ((preproc_arg) @injection.content (#set! injection.language "c") (#offset! @injection.content 0 2 0 -1))) ' + .. '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))' + ), + }, + }) + _G.parser:parse(true) + end) eq('table', exec_lua('return type(parser:children().c)')) eq({ @@ -506,7 +506,7 @@ int x = INT_MAX; }, get_ranges()) end) it('should list all directives', function() - local res_list = exec_lua [[ + local res_list = exec_lua(function() local query = vim.treesitter.query local list = query.list_directives() @@ -514,7 +514,7 @@ int x = INT_MAX; table.sort(list) return list - ]] + end) eq({ 'gsub!', 'offset!', 'set!', 'trim!' }, res_list) end) @@ -530,18 +530,18 @@ int x = INT_MAX; end) it('should return the correct language tree', function() - local result = exec_lua([[ - parser = vim.treesitter.get_parser(0, "c", { + local result = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c', { injections = { - c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c"))' - } + c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c"))', + }, }) parser:parse(true) - local sub_tree = parser:language_for_range({1, 18, 1, 19}) + local sub_tree = parser:language_for_range({ 1, 18, 1, 19 }) return sub_tree == parser:children().c - ]]) + end) eq(true, result) end) @@ -555,23 +555,23 @@ print() end) it('ignores optional captures #23100', function() - local result = exec_lua([[ - parser = vim.treesitter.get_parser(0, "lua", { + local result = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'lua', { injections = { lua = ( - '(function_call ' .. - '(arguments ' .. - '(string)? @injection.content ' .. - '(number)? @injection.content ' .. - '(#offset! @injection.content 0 1 0 -1) ' .. - '(#set! injection.language "c")))' - ) - } + '(function_call ' + .. '(arguments ' + .. '(string)? @injection.content ' + .. '(number)? @injection.content ' + .. '(#offset! @injection.content 0 1 0 -1) ' + .. '(#set! injection.language "c")))' + ), + }, }) parser:parse(true) return parser:is_valid() - ]]) + end) eq(true, result) end) @@ -584,18 +584,14 @@ print() int x = 3; ]]) - local result = exec_lua([[ - local result - - query = vim.treesitter.query.parse("c", '((number_literal) @number (#set! "key" "value"))') - parser = vim.treesitter.get_parser(0, "c") - - for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, -1, { all = true }) do - result = metadata.key - end + local result = exec_lua(function() + local query = + vim.treesitter.query.parse('c', '((number_literal) @number (#set! "key" "value"))') + local parser = vim.treesitter.get_parser(0, 'c') - return result - ]]) + local _, _, metadata = query:iter_matches(parser:parse()[1]:root(), 0, 0, -1)() + return metadata.key + end) eq('value', result) end) @@ -606,19 +602,17 @@ print() int x = 3; ]]) - local result = exec_lua([[ - local query = vim.treesitter.query - local value + local result = exec_lua(function() + local query = vim.treesitter.query.parse( + 'c', + '((number_literal) @number (#set! @number "key" "value"))' + ) + local parser = vim.treesitter.get_parser(0, 'c') - query = vim.treesitter.query.parse("c", '((number_literal) @number (#set! @number "key" "value"))') - parser = vim.treesitter.get_parser(0, "c") - - for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, -1, { all = true }) do - for _, nested_tbl in pairs(metadata) do - return nested_tbl.key - end - end - ]]) + local _, _, metadata = query:iter_matches(parser:parse()[1]:root(), 0, 0, -1)() + local _, nested_tbl = next(metadata) + return nested_tbl.key + end) eq('value', result) end) @@ -628,19 +622,17 @@ print() int x = 3; ]]) - local result = exec_lua([[ - local query = vim.treesitter.query - local result - - query = vim.treesitter.query.parse("c", '((number_literal) @number (#set! @number "key" "value") (#set! @number "key2" "value2"))') - parser = vim.treesitter.get_parser(0, "c") + local result = exec_lua(function() + local query = vim.treesitter.query.parse( + 'c', + '((number_literal) @number (#set! @number "key" "value") (#set! @number "key2" "value2"))' + ) + local parser = vim.treesitter.get_parser(0, 'c') - for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, -1, { all = true }) do - for _, nested_tbl in pairs(metadata) do - return nested_tbl - end - end - ]]) + local _, _, metadata = query:iter_matches(parser:parse()[1]:root(), 0, 0, -1)() + local _, nested_tbl = next(metadata) + return nested_tbl + end) local expected = { ['key'] = 'value', ['key2'] = 'value2', @@ -663,24 +655,21 @@ print() (function_definition) @function ]] - exec_lua([[ + exec_lua(function() vim.treesitter.start(0, 'c') - ]]) + end) local function run_query() - return exec_lua( - [[ - local query = vim.treesitter.query.parse("c", ...) - parser = vim.treesitter.get_parser() - tree = parser:parse()[1] - res = {} - for id, node in query:iter_captures(tree:root()) do - table.insert(res, {query.captures[id], node:range()}) - end - return res - ]], - query0 - ) + return exec_lua(function() + local query = vim.treesitter.query.parse('c', query0) + local parser = vim.treesitter.get_parser() + local tree = parser:parse()[1] + local res = {} + for id, node in query:iter_captures(tree:root()) do + table.insert(res, { query.captures[id], node:range() }) + end + return res + end) end eq({ @@ -718,18 +707,15 @@ print() ]] ]==] - local r = exec_lua( - [[ - local parser = vim.treesitter.get_string_parser(..., 'lua') - parser:parse(true) - local ranges = {} - parser:for_each_tree(function(tstree, tree) - ranges[tree:lang()] = { tstree:root():range(true) } - end) - return ranges - ]], - source - ) + local r = exec_lua(function() + local parser = vim.treesitter.get_string_parser(source, 'lua') + parser:parse(true) + local ranges = {} + parser:for_each_tree(function(tstree, tree) + ranges[tree:lang()] = { tstree:root():range(true) } + end) + return ranges + end) eq({ lua = { 0, 6, 6, 16, 4, 438 }, @@ -741,19 +727,14 @@ print() -- the ranges but only provide a Range4. Strip the byte entries from the ranges and make sure -- add_bytes() produces the same result. - local rb = exec_lua( - [[ - local r, source = ... - local add_bytes = require('vim.treesitter._range').add_bytes - for lang, range in pairs(r) do - r[lang] = {range[1], range[2], range[4], range[5]} - r[lang] = add_bytes(source, r[lang]) - end - return r - ]], - r, - source - ) + local rb = exec_lua(function() + local add_bytes = require('vim.treesitter._range').add_bytes + for lang, range in pairs(r) do + r[lang] = { range[1], range[2], range[4], range[5] } + r[lang] = add_bytes(source, r[lang]) + end + return r + end) eq(rb, r) end) @@ -766,25 +747,25 @@ print() ]] -- This is not a valid injection since (code) has children and include-children is not set - exec_lua [[ - parser1 = require('vim.treesitter.languagetree').new(0, "vimdoc", { + exec_lua(function() + _G.parser1 = require('vim.treesitter.languagetree').new(0, 'vimdoc', { injections = { - vimdoc = "((codeblock (language) @injection.language (code) @injection.content))" - } + vimdoc = '((codeblock (language) @injection.language (code) @injection.content))', + }, }) - parser1:parse(true) - ]] + _G.parser1:parse(true) + end) eq(0, exec_lua('return #vim.tbl_keys(parser1:children())')) - exec_lua [[ - parser2 = require('vim.treesitter.languagetree').new(0, "vimdoc", { + exec_lua(function() + _G.parser2 = require('vim.treesitter.languagetree').new(0, 'vimdoc', { injections = { - vimdoc = "((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))" - } + vimdoc = '((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))', + }, }) - parser2:parse(true) - ]] + _G.parser2:parse(true) + end) eq(1, exec_lua('return #vim.tbl_keys(parser2:children())')) eq({ { { 1, 0, 21, 2, 0, 42 } } }, exec_lua('return parser2:children().lua:included_regions()')) @@ -821,46 +802,46 @@ print() < ]]) - exec_lua [[ - parser = require('vim.treesitter.languagetree').new(0, "vimdoc", { + exec_lua(function() + _G.parser = require('vim.treesitter.languagetree').new(0, 'vimdoc', { injections = { - vimdoc = "((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))" - } + vimdoc = '((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))', + }, }) - ]] + end) --- Do not parse injections by default eq( 0, - exec_lua [[ - parser:parse() - return #vim.tbl_keys(parser:children()) - ]] + exec_lua(function() + _G.parser:parse() + return #vim.tbl_keys(_G.parser:children()) + end) ) --- Only parse injections between lines 0, 2 eq( 1, - exec_lua [[ - parser:parse({0, 2}) - return #parser:children().lua:trees() - ]] + exec_lua(function() + _G.parser:parse({ 0, 2 }) + return #_G.parser:children().lua:trees() + end) ) eq( 2, - exec_lua [[ - parser:parse({2, 6}) - return #parser:children().lua:trees() - ]] + exec_lua(function() + _G.parser:parse({ 2, 6 }) + return #_G.parser:children().lua:trees() + end) ) eq( 7, - exec_lua [[ - parser:parse(true) - return #parser:children().lua:trees() - ]] + exec_lua(function() + _G.parser:parse(true) + return #_G.parser:children().lua:trees() + end) ) end) @@ -876,13 +857,13 @@ print() feed(':set ft=help<cr>') - exec_lua [[ - vim.treesitter.get_parser(0, "vimdoc", { + exec_lua(function() + vim.treesitter.get_parser(0, 'vimdoc', { injections = { - vimdoc = "((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))" - } + vimdoc = '((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))', + }, }) - ]] + end) end) it('is valid excluding, invalid including children initially', function() diff --git a/test/functional/treesitter/query_spec.lua b/test/functional/treesitter/query_spec.lua index c3a376cd71..c97619c913 100644 --- a/test/functional/treesitter/query_spec.lua +++ b/test/functional/treesitter/query_spec.lua @@ -10,28 +10,26 @@ local pcall_err = t.pcall_err local api = n.api local fn = n.fn -local get_query_result_code = [[ - function get_query_result(query_text) - cquery = vim.treesitter.query.parse("c", query_text) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for cid, node in cquery:iter_captures(tree:root(), 0) do - -- can't transmit node over RPC. just check the name, range, and text - local text = vim.treesitter.get_node_text(node, 0) - local range = {node:range()} - table.insert(res, { cquery.captures[cid], node:type(), range, text }) - end - return res +local function get_query_result(query_text) + local cquery = vim.treesitter.query.parse('c', query_text) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for cid, node in cquery:iter_captures(tree:root(), 0) do + -- can't transmit node over RPC. just check the name, range, and text + local text = vim.treesitter.get_node_text(node, 0) + local range = { node:range() } + table.insert(res, { cquery.captures[cid], node:type(), range, text }) end -]] + return res +end describe('treesitter query API', function() before_each(function() clear() - exec_lua [[ + exec_lua(function() vim.g.__ts_debug = 1 - ]] + end) end) local test_text = [[ @@ -71,9 +69,9 @@ void ui_refresh(void) it('supports runtime queries', function() ---@type string[] - local ret = exec_lua [[ - return vim.treesitter.query.get("c", "highlights").captures - ]] + local ret = exec_lua(function() + return vim.treesitter.query.get('c', 'highlights').captures + end) -- see $VIMRUNTIME/queries/c/highlights.scm eq('variable', ret[1]) @@ -84,22 +82,17 @@ void ui_refresh(void) local long_query = test_query:rep(100) ---@return number local function q(_n) - return exec_lua( - [[ - local query, n = ... - local before = vim.api.nvim__stats().ts_query_parse_count - collectgarbage("stop") - for i=1, n, 1 do - cquery = vim.treesitter.query.parse("c", ...) - end - collectgarbage("restart") - collectgarbage("collect") - local after = vim.api.nvim__stats().ts_query_parse_count - return after - before - ]], - long_query, - _n - ) + return exec_lua(function() + local before = vim.api.nvim__stats().ts_query_parse_count + collectgarbage('stop') + for _ = 1, _n, 1 do + vim.treesitter.query.parse('c', long_query, _n) + end + collectgarbage('restart') + collectgarbage('collect') + local after = vim.api.nvim__stats().ts_query_parse_count + return after - before + end) end eq(1, q(1)) @@ -110,20 +103,17 @@ void ui_refresh(void) it('supports query and iter by capture (iter_captures)', function() insert(test_text) - local res = exec_lua( - [[ - cquery = vim.treesitter.query.parse("c", ...) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do - -- can't transmit node over RPC. just check the name and range - table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() }) - end - return res - ]], - test_query - ) + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse('c', test_query) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do + -- can't transmit node over RPC. just check the name and range + table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() }) + end + return res + end) eq({ { '@type', 'primitive_type', 8, 2, 8, 6 }, -- bool @@ -143,26 +133,23 @@ void ui_refresh(void) insert(test_text) ---@type table - local res = exec_lua( - [[ - cquery = vim.treesitter.query.parse("c", ...) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = true }) do - -- can't transmit node over RPC. just check the name and range - local mrepr = {} - for cid, nodes in pairs(match) do - for _, node in ipairs(nodes) do - table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) - end + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse('c', test_query) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do + -- can't transmit node over RPC. just check the name and range + local mrepr = {} + for cid, nodes in pairs(match) do + for _, node in ipairs(nodes) do + table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) end - table.insert(res, { pattern, mrepr }) end - return res - ]], - test_query - ) + table.insert(res, { pattern, mrepr }) + end + return res + end) eq({ { 3, { { '@type', 'primitive_type', 8, 2, 8, 6 } } }, @@ -191,20 +178,20 @@ void ui_refresh(void) it('supports query and iter by capture for quantifiers', function() insert(test_text) - local res = exec_lua( - [[ - cquery = vim.treesitter.query.parse("c", ...) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do - -- can't transmit node over RPC. just check the name and range - table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() }) - end - return res - ]], - '(expression_statement (assignment_expression (call_expression)))+ @funccall' - ) + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse( + 'c', + '(expression_statement (assignment_expression (call_expression)))+ @funccall' + ) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do + -- can't transmit node over RPC. just check the name and range + table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() }) + end + return res + end) eq({ { '@funccall', 'expression_statement', 11, 4, 11, 34 }, @@ -216,26 +203,26 @@ void ui_refresh(void) it('supports query and iter by match for quantifiers', function() insert(test_text) - local res = exec_lua( - [[ - cquery = vim.treesitter.query.parse("c", ...) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = true }) do - -- can't transmit node over RPC. just check the name and range - local mrepr = {} - for cid, nodes in pairs(match) do - for _, node in ipairs(nodes) do - table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) - end + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse( + 'c', + '(expression_statement (assignment_expression (call_expression)))+ @funccall' + ) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do + -- can't transmit node over RPC. just check the name and range + local mrepr = {} + for cid, nodes in pairs(match) do + for _, node in ipairs(nodes) do + table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) end - table.insert(res, {pattern, mrepr}) end - return res - ]], - '(expression_statement (assignment_expression (call_expression)))+ @funccall' - ) + table.insert(res, { pattern, mrepr }) + end + return res + end, '(expression_statement (assignment_expression (call_expression)))+ @funccall') eq({ { @@ -249,23 +236,78 @@ void ui_refresh(void) }, res) end) + it('returns quantified matches in order of range #29344', function() + insert([[ + int main() { + int a, b, c, d, e, f, g, h, i; + a = MIN(0, 1); + b = MIN(0, 1); + c = MIN(0, 1); + d = MIN(0, 1); + e = MIN(0, 1); + f = MIN(0, 1); + g = MIN(0, 1); + h = MIN(0, 1); + i = MIN(0, 1); + } + ]]) + + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse( + 'c', + '(expression_statement (assignment_expression (call_expression)))+ @funccall' + ) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do + -- can't transmit node over RPC. just check the name and range + local mrepr = {} + for cid, nodes in pairs(match) do + for _, node in ipairs(nodes) do + table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) + end + end + table.insert(res, { pattern, mrepr }) + end + return res + end) + + eq({ + { + 1, + { + { '@funccall', 'expression_statement', 2, 2, 2, 16 }, + { '@funccall', 'expression_statement', 3, 2, 3, 16 }, + { '@funccall', 'expression_statement', 4, 2, 4, 16 }, + { '@funccall', 'expression_statement', 5, 2, 5, 16 }, + { '@funccall', 'expression_statement', 6, 2, 6, 16 }, + { '@funccall', 'expression_statement', 7, 2, 7, 16 }, + { '@funccall', 'expression_statement', 8, 2, 8, 16 }, + { '@funccall', 'expression_statement', 9, 2, 9, 16 }, + { '@funccall', 'expression_statement', 10, 2, 10, 16 }, + }, + }, + }, res) + end) + it('can match special regex characters like \\ * + ( with `vim-match?`', function() insert('char* astring = "\\n"; (1 + 1) * 2 != 2;') ---@type table - local res = exec_lua([[ - query = ( - '([_] @plus (#vim-match? @plus "^\\\\+$"))' .. - '([_] @times (#vim-match? @times "^\\\\*$"))' .. - '([_] @paren (#vim-match? @paren "^\\\\($"))' .. - '([_] @escape (#vim-match? @escape "^\\\\\\\\n$"))' .. - '([_] @string (#vim-match? @string "^\\"\\\\\\\\n\\"$"))' + local res = exec_lua(function() + local query = ( + '([_] @plus (#vim-match? @plus "^\\\\+$"))' + .. '([_] @times (#vim-match? @times "^\\\\*$"))' + .. '([_] @paren (#vim-match? @paren "^\\\\($"))' + .. '([_] @escape (#vim-match? @escape "^\\\\\\\\n$"))' + .. '([_] @string (#vim-match? @string "^\\"\\\\\\\\n\\"$"))' ) - cquery = vim.treesitter.query.parse("c", query) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 0, -1, { all = true }) do + local cquery = vim.treesitter.query.parse('c', query) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 0, -1) do -- can't transmit node over RPC. just check the name and range local mrepr = {} for cid, nodes in pairs(match) do @@ -276,7 +318,7 @@ void ui_refresh(void) table.insert(res, { pattern, mrepr }) end return res - ]]) + end) eq({ { 2, { { '@times', '*', 0, 4, 0, 5 } } }, @@ -307,10 +349,9 @@ void ui_refresh(void) return 0; } ]]) - exec_lua(get_query_result_code) local res0 = exec_lua( - [[return get_query_result(...)]], + get_query_result, [[((primitive_type) @c-keyword (#any-of? @c-keyword "int" "float"))]] ) eq({ @@ -319,7 +360,7 @@ void ui_refresh(void) }, res0) local res1 = exec_lua( - [[return get_query_result(...)]], + get_query_result, [[ ((string_literal) @fizzbuzz-strings (#any-of? @fizzbuzz-strings "\"number= %d FizzBuzz\\n\"" @@ -340,16 +381,15 @@ void ui_refresh(void) int x = 123; enum C { y = 124 }; int main() { int z = 125; }]]) - exec_lua(get_query_result_code) local result = exec_lua( - [[return get_query_result(...)]], + get_query_result, [[((number_literal) @literal (#has-ancestor? @literal "function_definition"))]] ) eq({ { 'literal', 'number_literal', { 2, 21, 2, 24 }, '125' } }, result) result = exec_lua( - [[return get_query_result(...)]], + get_query_result, [[((number_literal) @literal (#has-ancestor? @literal "function_definition" "enum_specifier"))]] ) eq({ @@ -358,7 +398,7 @@ void ui_refresh(void) }, result) result = exec_lua( - [[return get_query_result(...)]], + get_query_result, [[((number_literal) @literal (#not-has-ancestor? @literal "enum_specifier"))]] ) eq({ @@ -370,12 +410,15 @@ void ui_refresh(void) it('allows loading query with escaped quotes and capture them `#{lua,vim}-match`?', function() insert('char* astring = "Hello World!";') - local res = exec_lua([[ - cquery = vim.treesitter.query.parse("c", '([_] @quote (#vim-match? @quote "^\\"$")) ([_] @quote (#lua-match? @quote "^\\"$"))') - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 0, -1, { all = true }) do + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse( + 'c', + '([_] @quote (#vim-match? @quote "^\\"$")) ([_] @quote (#lua-match? @quote "^\\"$"))' + ) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 0, -1) do -- can't transmit node over RPC. just check the name and range local mrepr = {} for cid, nodes in pairs(match) do @@ -386,7 +429,7 @@ void ui_refresh(void) table.insert(res, { pattern, mrepr }) end return res - ]]) + end) eq({ { 1, { { '@quote', '"', 0, 16, 0, 17 } } }, @@ -406,70 +449,60 @@ void ui_refresh(void) local custom_query = '((identifier) @main (#is-main? @main))' do - local res = exec_lua( - [[ - local query = vim.treesitter.query - - local function is_main(match, pattern, bufnr, predicate) - local nodes = match[ predicate[2] ] - for _, node in ipairs(nodes) do - if vim.treesitter.get_node_text(node, bufnr) == 'main' then - return true - end + local res = exec_lua(function() + local query = vim.treesitter.query + + local function is_main(match, _pattern, bufnr, predicate) + local nodes = match[predicate[2]] + for _, node in ipairs(nodes) do + if vim.treesitter.get_node_text(node, bufnr) == 'main' then + return true end - return false end + return false + end - local parser = vim.treesitter.get_parser(0, "c") + local parser = vim.treesitter.get_parser(0, 'c') - -- Time bomb: update this in 0.12 - if vim.fn.has('nvim-0.12') == 1 then - return 'Update this test to remove this message and { all = true } from add_predicate' - end - query.add_predicate("is-main?", is_main, { all = true }) + query.add_predicate('is-main?', is_main) - local query = query.parse("c", ...) + local query0 = query.parse('c', custom_query) - local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do - table.insert(nodes, {node:range()}) - end + local nodes = {} + for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do + table.insert(nodes, { node:range() }) + end - return nodes - ]], - custom_query - ) + return nodes + end) eq({ { 0, 4, 0, 8 } }, res) end -- Once with the old API. Remove this whole 'do' block in 0.12 do - local res = exec_lua( - [[ - local query = vim.treesitter.query + local res = exec_lua(function() + local query = vim.treesitter.query - local function is_main(match, pattern, bufnr, predicate) - local node = match[ predicate[2] ] + local function is_main(match, _pattern, bufnr, predicate) + local node = match[predicate[2]] - return vim.treesitter.get_node_text(node, bufnr) == 'main' - end + return vim.treesitter.get_node_text(node, bufnr) == 'main' + end - local parser = vim.treesitter.get_parser(0, "c") + local parser = vim.treesitter.get_parser(0, 'c') - query.add_predicate("is-main?", is_main, true) + query.add_predicate('is-main?', is_main, { all = false, force = true }) - local query = query.parse("c", ...) + local query0 = query.parse('c', custom_query) - local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do - table.insert(nodes, {node:range()}) - end + local nodes = {} + for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do + table.insert(nodes, { node:range() }) + end - return nodes - ]], - custom_query - ) + return nodes + end) -- Remove this 'do' block in 0.12 eq(0, fn.has('nvim-0.12')) @@ -477,16 +510,16 @@ void ui_refresh(void) end do - local res = exec_lua [[ + local res = exec_lua(function() local query = vim.treesitter.query - local t = {} + local r = {} for _, v in ipairs(query.list_predicates()) do - t[v] = true + r[v] = true end - return t - ]] + return r + end) eq(true, res['is-main?']) end @@ -505,18 +538,15 @@ void ui_refresh(void) local function test(input, query) api.nvim_buf_set_lines(0, 0, -1, true, vim.split(dedent(input), '\n')) - return exec_lua( - [[ - local parser = vim.treesitter.get_parser(0, "lua") - local query = vim.treesitter.query.parse("lua", ...) - local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do - nodes[#nodes+1] = { node:range() } - end - return nodes - ]], - query - ) + return exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'lua') + local query0 = vim.treesitter.query.parse('lua', query) + local nodes = {} + for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do + nodes[#nodes + 1] = { node:range() } + end + return nodes + end) end eq( @@ -583,23 +613,21 @@ void ui_refresh(void) -- Comment ]]) - local query = [[ + local result = exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'lua') + local query = vim.treesitter.query.parse( + 'lua', + [[ (((comment (comment_content))+) @bar (#lua-match? @bar "Comment")) ]] - - local result = exec_lua( - [[ - local parser = vim.treesitter.get_parser(0, "lua") - local query = vim.treesitter.query.parse("lua", ...) - local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do - nodes[#nodes+1] = { node:range() } - end - return nodes - ]], - query - ) + ) + local nodes = {} + for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do + nodes[#nodes + 1] = { node:range() } + end + return nodes + end) eq({ { 0, 2, 0, 12 }, @@ -613,23 +641,20 @@ void ui_refresh(void) eq(0, fn.has('nvim-0.12')) insert(test_text) - local res = exec_lua( - [[ - cquery = vim.treesitter.query.parse("c", ...) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do - local mrepr = {} - for cid, node in pairs(match) do - table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) - end - table.insert(res, { pattern, mrepr }) + local res = exec_lua(function() + local cquery = vim.treesitter.query.parse('c', test_query) + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = false }) do + local mrepr = {} + for cid, node in pairs(match) do + table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() }) end - return res - ]], - test_query - ) + table.insert(res, { pattern, mrepr }) + end + return res + end) eq({ { 3, { { '@type', 'primitive_type', 8, 2, 8, 6 } } }, @@ -661,23 +686,19 @@ void ui_refresh(void) int bar = 13; ]] - local ret = exec_lua( - [[ - local str = ... - local parser = vim.treesitter.get_string_parser(str, "c") + local ret = exec_lua(function() + local parser = vim.treesitter.get_string_parser(txt, 'c') - local nodes = {} - local query = vim.treesitter.query.parse("c", '((identifier) @foo)') - local first_child = parser:parse()[1]:root():child(1) + local nodes = {} + local query = vim.treesitter.query.parse('c', '((identifier) @foo)') + local first_child = assert(parser:parse()[1]:root():child(1)) - for _, node in query:iter_captures(first_child, str) do - table.insert(nodes, { node:range() }) - end + for _, node in query:iter_captures(first_child, txt) do + table.insert(nodes, { node:range() }) + end - return nodes - ]], - txt - ) + return nodes + end) eq({ { 1, 10, 1, 13 } }, ret) end) @@ -734,7 +755,10 @@ void ui_refresh(void) const char *sql = "SELECT * FROM Students WHERE name = 'Robert'); DROP TABLE Students;--"; ]]) - local query = [[ + local result = exec_lua(function() + local query = vim.treesitter.query.parse( + 'c', + [[ (declaration type: (_) declarator: (init_declarator @@ -745,20 +769,15 @@ void ui_refresh(void) (#set! injection.language "sql") (#contains? @_id "sql")) ]] - - local result = exec_lua( - [=[ - local query = vim.treesitter.query.parse("c", ...) - local parser = vim.treesitter.get_parser(0, "c") + ) + local parser = vim.treesitter.get_parser(0, 'c') local root = parser:parse()[1]:root() - local t = {} - for id, node, metadata in query:iter_captures(root, 0) do - t[query.captures[id]] = metadata + local res = {} + for id, _, metadata in query:iter_captures(root, 0) do + res[query.captures[id]] = metadata end - return t - ]=], - query - ) + return res + end) eq({ ['_id'] = { ['injection.language'] = 'sql' }, @@ -782,25 +801,22 @@ void ui_refresh(void) (#eq? @function.name "foo")) ]] - local result = exec_lua( - [[ - local query = vim.treesitter.query.parse("c", ...) - local match_preds = query.match_preds + local result = exec_lua(function() + local query0 = vim.treesitter.query.parse('c', query) + local match_preds = query0.match_preds local called = 0 - function query:match_preds(...) + function query0:match_preds(...) called = called + 1 return match_preds(self, ...) end - local parser = vim.treesitter.get_parser(0, "c") + local parser = vim.treesitter.get_parser(0, 'c') local root = parser:parse()[1]:root() local captures = {} - for id, node in query:iter_captures(root, 0) do + for id in query0:iter_captures(root, 0) do captures[#captures + 1] = id end return { called, captures } - ]], - query - ) + end) eq({ 2, { 1, 1, 2, 2 } }, result) end) diff --git a/test/functional/treesitter/utils_spec.lua b/test/functional/treesitter/utils_spec.lua index bca0aca0cb..34bea349f6 100644 --- a/test/functional/treesitter/utils_spec.lua +++ b/test/functional/treesitter/utils_spec.lua @@ -17,26 +17,30 @@ describe('treesitter utils', function() int x = 3; }]]) - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - root = tree:root() - ancestor = root:child(0) - child = ancestor:child(0) - ]]) - - eq(true, exec_lua('return vim.treesitter.is_ancestor(ancestor, child)')) - eq(false, exec_lua('return vim.treesitter.is_ancestor(child, ancestor)')) + exec_lua(function() + local parser = vim.treesitter.get_parser(0, 'c') + local tree = parser:parse()[1] + local root = tree:root() + _G.ancestor = assert(root:child(0)) + _G.child = assert(_G.ancestor:named_child(1)) + _G.child_sibling = assert(_G.ancestor:named_child(2)) + _G.grandchild = assert(_G.child:named_child(0)) + end) + + eq(true, exec_lua('return vim.treesitter.is_ancestor(_G.ancestor, _G.child)')) + eq(true, exec_lua('return vim.treesitter.is_ancestor(_G.ancestor, _G.grandchild)')) + eq(false, exec_lua('return vim.treesitter.is_ancestor(_G.child, _G.ancestor)')) + eq(false, exec_lua('return vim.treesitter.is_ancestor(_G.child, _G.child_sibling)')) end) it('can detect if a position is contained in a node', function() - exec_lua([[ - node = { + exec_lua(function() + _G.node = { range = function() return 0, 4, 0, 8 end, } - ]]) + end) eq(false, exec_lua('return vim.treesitter.is_in_node_range(node, 0, 3)')) for i = 4, 7 do diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua index 8bfceb8cce..619153724b 100644 --- a/test/functional/ui/cursor_spec.lua +++ b/test/functional/ui/cursor_spec.lua @@ -246,11 +246,11 @@ describe('ui/cursor', function() end end if m.hl_id then - m.hl_id = 64 + m.hl_id = 66 m.attr = { background = Screen.colors.DarkGray } end if m.id_lm then - m.id_lm = 69 + m.id_lm = 73 end end diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 746bfb3262..042975f898 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -2341,21 +2341,28 @@ describe('extmark decorations', function() it('supports URLs', function() insert(example_text) - local url = 'https://example.com' + local url1 = 'https://example.com' + local url2 = 'http://127.0.0.1' screen:add_extra_attr_ids { - u = { url = "https://example.com" }, + u = { url = url1 }, + uh = { url = url2, background = Screen.colors.Yellow }, } api.nvim_buf_set_extmark(0, ns, 1, 4, { end_col = 14, - url = url, + url = url1, + }) + api.nvim_buf_set_extmark(0, ns, 2, 4, { + end_col = 17, + hl_group = 'Search', + url = url2, }) - screen:expect{grid=[[ + screen:expect([[ for _,item in ipairs(items) do | {u:local text}, hl_id_cell, count = unpack(item) | - if hl_id_cell ~= nil then | + {uh:if hl_id_cell} ~= nil then | hl_id = hl_id_cell | end | for _ = 1, (count or 1) do | @@ -2368,7 +2375,7 @@ describe('extmark decorations', function() {1:~ }| {1:~ }| | - ]]} + ]]) end) it('can replace marks in place with different decorations #27211', function() @@ -4027,11 +4034,85 @@ describe('decorations: inline virtual text', function() normal! $ ]]) api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { ('b'):rep(9) } }, virt_text_pos = 'inline' }) - screen:expect{grid=[[ + screen:expect([[ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbb{1:>}| å£1234^5 | | - ]]} + ]]) + feed('g0') + screen:expect([[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbb{1:>}| + ^å£12345 | + | + ]]) + command('set showbreak=+++') + screen:expect([[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbb{1:>}| + {1:+++}^å£12345 | + | + ]]) + end) + + it('cursor position is correct if end_row or end_col is specified', function() + screen:try_resize(50, 8) + api.nvim_buf_set_lines(0, 0, -1, false, { ('a'):rep(48), ('b'):rep(48), ('c'):rep(48), ('d'):rep(48) }) + api.nvim_buf_set_extmark(0, ns, 0, 0, {end_row = 2, virt_text_pos = 'inline', virt_text = {{'I1', 'NonText'}}}) + api.nvim_buf_set_extmark(0, ns, 3, 0, {end_col = 2, virt_text_pos = 'inline', virt_text = {{'I2', 'NonText'}}}) + feed('$') + screen:expect([[ + {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa^a| + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb | + cccccccccccccccccccccccccccccccccccccccccccccccc | + {1:I2}dddddddddddddddddddddddddddddddddddddddddddddddd| + {1:~ }|*3 + | + ]]) + feed('j') + screen:expect([[ + {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb^b | + cccccccccccccccccccccccccccccccccccccccccccccccc | + {1:I2}dddddddddddddddddddddddddddddddddddddddddddddddd| + {1:~ }|*3 + | + ]]) + feed('j') + screen:expect([[ + {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb | + ccccccccccccccccccccccccccccccccccccccccccccccc^c | + {1:I2}dddddddddddddddddddddddddddddddddddddddddddddddd| + {1:~ }|*3 + | + ]]) + feed('j') + screen:expect([[ + {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb | + cccccccccccccccccccccccccccccccccccccccccccccccc | + {1:I2}ddddddddddddddddddddddddddddddddddddddddddddddd^d| + {1:~ }|*3 + | + ]]) + end) + + it('cursor position is correct with invalidated inline virt text', function() + screen:try_resize(50, 8) + api.nvim_buf_set_lines(0, 0, -1, false, { ('a'):rep(48), ('b'):rep(48) }) + api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text_pos = 'inline', virt_text = {{'INLINE', 'NonText'}}, invalidate = true }) + screen:expect([[ + {1:INLINE}^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + aaaa | + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb | + {1:~ }|*4 + | + ]]) + feed('dd$') + screen:expect([[ + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb^b | + {1:~ }|*6 + | + ]]) end) end) @@ -4936,6 +5017,28 @@ if (h->n_buckets < new_n_buckets) { // expand | ]]) end) + + it('not drawn when invalid', function() + api.nvim_buf_set_lines(0, 0, -1, false, { 'foo', 'bar' }) + api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = {{{'VIRT1'}}}, invalidate = true }) + screen:expect({ + grid = [[ + ^foo | + VIRT1 | + bar | + {1:~ }|*8 + | + ]] + }) + feed('dd') + screen:expect({ + grid = [[ + ^bar | + {1:~ }|*10 + | + ]] + }) + end) end) describe('decorations: signs', function() @@ -5497,6 +5600,60 @@ l5 api.nvim_buf_clear_namespace(0, ns, 0, -1) end) + + it([[correct numberwidth with 'signcolumn' set to "number" #28984]], function() + command('set number numberwidth=1 signcolumn=number') + api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1' }) + screen:expect({ + grid = [[ + S1 ^ | + {1:~ }|*8 + | + ]] + }) + api.nvim_buf_del_extmark(0, ns, 1) + screen:expect({ + grid = [[ + {8:1 }^ | + {1:~ }|*8 + | + ]] + }) + end) + + it('supports emoji as signs', function() + insert(example_test3) + feed 'gg' + api.nvim_buf_set_extmark(0, ns, 1, 0, {sign_text='🧑â€ðŸŒ¾'}) + -- VS16 can change width of character + api.nvim_buf_set_extmark(0, ns, 2, 0, {sign_text='â¤ï¸'}) + api.nvim_buf_set_extmark(0, ns, 3, 0, {sign_text='â¤'}) + api.nvim_buf_set_extmark(0, ns, 4, 0, {sign_text='â¤x'}) + screen:expect([[ + {7: }^l1 | + 🧑â€ðŸŒ¾l2 | + â¤ï¸l3 | + ⤠l4 | + â¤xl5 | + {7: } | + {1:~ }|*3 + | + ]]) + eq("Invalid 'sign_text'", pcall_err(api.nvim_buf_set_extmark, 0, ns, 5, 0, {sign_text='â¤ï¸x'})) + end) + + it('auto signcolumn hides with invalidated sign', function() + api.nvim_set_option_value('signcolumn', 'auto', {}) + api.nvim_buf_set_extmark(0, ns, 0, 0, {sign_text='S1', invalidate=true}) + feed('ia<cr>b<esc>dd') + screen:expect({ + grid = [[ + ^a | + {1:~ }|*8 + | + ]] + }) + end) end) describe('decorations: virt_text', function() @@ -5575,20 +5732,26 @@ describe('decorations: virt_text', function() end) describe('decorations: window scoped', function() - local screen, ns + local screen, ns, win_other local url = 'https://example.com' before_each(function() clear() screen = Screen.new(20, 10) screen:attach() screen:add_extra_attr_ids { - [100] = { special = Screen.colors.Red, undercurl = true }, - [101] = { url = "https://example.com" }, + [100] = { special = Screen.colors.Red, undercurl = true }, + [101] = { url = 'https://example.com' }, } ns = api.nvim_create_namespace 'test' insert('12345') + + win_other = api.nvim_open_win(0, false, { + col=0,row=0,width=20,height=10, + relative = 'win',style = 'minimal', + hide = true + }) end) local noextmarks = { @@ -5596,28 +5759,28 @@ describe('decorations: window scoped', function() 1234^5 | {1:~ }|*8 | - ]]} + ]], + } - local function set_scoped_extmark(line, col, opts) - return api.nvim_buf_set_extmark(0, ns, line, col, vim.tbl_extend('error', { scoped = true }, opts)) + local function set_extmark(line, col, opts) + return api.nvim_buf_set_extmark(0, ns, line, col, opts) end it('hl_group', function() - set_scoped_extmark(0, 0, { + set_extmark(0, 0, { hl_group = 'Comment', end_col = 3, }) - screen:expect(noextmarks) - - api.nvim__win_add_ns(0, ns) + api.nvim__ns_set(ns, { wins = { 0 } }) screen:expect { grid = [[ {18:123}4^5 | {1:~ }|*8 | - ]]} + ]], + } command 'split' command 'only' @@ -5626,48 +5789,55 @@ describe('decorations: window scoped', function() end) it('virt_text', function() - set_scoped_extmark(0, 0, { + set_extmark(0, 0, { virt_text = { { 'a', 'Comment' } }, virt_text_pos = 'eol', }) - set_scoped_extmark(0, 5, { + set_extmark(0, 5, { virt_text = { { 'b', 'Comment' } }, virt_text_pos = 'inline', }) - set_scoped_extmark(0, 1, { + set_extmark(0, 1, { virt_text = { { 'c', 'Comment' } }, virt_text_pos = 'overlay', }) - set_scoped_extmark(0, 1, { + set_extmark(0, 1, { virt_text = { { 'd', 'Comment' } }, virt_text_pos = 'right_align', }) - screen:expect(noextmarks) - - api.nvim__win_add_ns(0, ns) + api.nvim__ns_set(ns, { wins = { 0 } }) screen:expect { grid = [[ 1{18:c}34^5{18:b} {18:a} {18:d}| {1:~ }|*8 | - ]]} + ]], + } command 'split' command 'only' screen:expect(noextmarks) + + api.nvim__ns_set(ns, { wins = {} }) + + screen:expect { + grid = [[ + 1{18:c}34^5{18:b} {18:a} {18:d}| + {1:~ }|*8 + | + ]], + } end) it('virt_lines', function() - set_scoped_extmark(0, 0, { + set_extmark(0, 0, { virt_lines = { { { 'a', 'Comment' } } }, }) - screen:expect(noextmarks) - - api.nvim__win_add_ns(0, ns) + api.nvim__ns_set(ns, { wins = { 0 } }) screen:expect { grid = [[ @@ -5675,7 +5845,8 @@ describe('decorations: window scoped', function() {18:a} | {1:~ }|*7 | - ]]} + ]], + } command 'split' command 'only' @@ -5684,14 +5855,12 @@ describe('decorations: window scoped', function() end) it('redraws correctly with inline virt_text and wrapping', function() - set_scoped_extmark(0, 2, { - virt_text = {{ ('b'):rep(18), 'Comment' }}, - virt_text_pos = 'inline' + set_extmark(0, 2, { + virt_text = { { ('b'):rep(18), 'Comment' } }, + virt_text_pos = 'inline', }) - screen:expect(noextmarks) - - api.nvim__win_add_ns(0, ns) + api.nvim__ns_set(ns, { wins = { 0 } }) screen:expect { grid = [[ @@ -5699,9 +5868,10 @@ describe('decorations: window scoped', function() 34^5 | {1:~ }|*7 | - ]]} + ]], + } - api.nvim__win_del_ns(0, ns) + api.nvim__ns_set(ns, { wins = { win_other } }) screen:expect(noextmarks) end) @@ -5709,21 +5879,20 @@ describe('decorations: window scoped', function() pending('sign_text', function() -- TODO(altermo): The window signcolumn width is calculated wrongly (when `signcolumn=auto`) -- This happens in function `win_redraw_signcols` on line containing `buf_meta_total(buf, kMTMetaSignText) > 0` - set_scoped_extmark(0, 0, { + set_extmark(0, 0, { sign_text = 'a', sign_hl_group = 'Comment', }) - screen:expect(noextmarks) - - api.nvim__win_add_ns(0, ns) + api.nvim__ns_set(ns, { wins = { 0 } }) screen:expect { grid = [[ a 1234^5 | {2:~ }|*8 | - ]]} + ]], + } command 'split' command 'only' @@ -5732,30 +5901,34 @@ describe('decorations: window scoped', function() end) it('statuscolumn hl group', function() - set_scoped_extmark(0, 0, { - number_hl_group='comment', + set_extmark(0, 0, { + number_hl_group = 'comment', }) - set_scoped_extmark(0, 0, { - line_hl_group='comment', + set_extmark(0, 0, { + line_hl_group = 'comment', }) command 'set number' + api.nvim__ns_set(ns, { wins = { win_other } }) + screen:expect { grid = [[ {8: 1 }1234^5 | {1:~ }|*8 | - ]]} + ]], + } - api.nvim__win_add_ns(0, ns) + api.nvim__ns_set(ns, { wins = { 0 } }) screen:expect { grid = [[ {18: 1 1234^5 }| {1:~ }|*8 | - ]]} + ]], + } command 'split' command 'only' @@ -5765,36 +5938,43 @@ describe('decorations: window scoped', function() {8: 1 }1234^5 | {1:~ }|*8 | - ]]} + ]], + } end) it('spell', function() - api.nvim_buf_set_lines(0,0,-1,true,{'aa'}) + api.nvim_buf_set_lines(0, 0, -1, true, { 'aa' }) - set_scoped_extmark(0, 0, { - spell=true, - end_col=2, + set_extmark(0, 0, { + spell = true, + end_col = 2, }) command 'set spelloptions=noplainbuffer' command 'set spell' command 'syntax off' + screen:expect({ unchanged = true }) + + api.nvim__ns_set(ns, { wins = { win_other } }) + screen:expect { grid = [[ a^a | {1:~ }|*8 | - ]]} + ]], + } - api.nvim__win_add_ns(0, ns) + api.nvim__ns_set(ns, { wins = { 0 } }) screen:expect { grid = [[ {100:a^a} | {1:~ }|*8 | - ]]} + ]], + } command 'split' command 'only' @@ -5804,25 +5984,25 @@ describe('decorations: window scoped', function() a^a | {1:~ }|*8 | - ]]} + ]], + } end) it('url', function() - set_scoped_extmark(0, 0, { - end_col=3, - url=url, + set_extmark(0, 0, { + end_col = 3, + url = url, }) - screen:expect(noextmarks) - - api.nvim__win_add_ns(0, ns) + api.nvim__ns_set(ns, { wins = { 0 } }) screen:expect { grid = [[ {101:123}4^5 | {1:~ }|*8 | - ]]} + ]], + } command 'split' command 'only' @@ -5830,85 +6010,72 @@ describe('decorations: window scoped', function() screen:expect(noextmarks) end) - it('change extmarks scoped option', function() - local id = set_scoped_extmark(0, 0, { + it('change namespace scope', function() + set_extmark(0, 0, { hl_group = 'Comment', end_col = 3, }) - api.nvim__win_add_ns(0, ns) + api.nvim__ns_set(ns, { wins = { 0 } }) + eq({ wins={ api.nvim_get_current_win() } }, api.nvim__ns_get(ns)) screen:expect { grid = [[ {18:123}4^5 | {1:~ }|*8 | - ]]} + ]], + } command 'split' command 'only' screen:expect(noextmarks) - api.nvim_buf_set_extmark(0, ns, 0, 0, { - id = id, - hl_group = 'Comment', - end_col = 3, - scoped = false, - }) + api.nvim__ns_set(ns, { wins = { 0 } }) + eq({ wins={ api.nvim_get_current_win() } }, api.nvim__ns_get(ns)) screen:expect { grid = [[ {18:123}4^5 | {1:~ }|*8 | - ]]} + ]], + } - api.nvim_buf_set_extmark(0, ns, 0, 0, { - id = id, - hl_group = 'Comment', - end_col = 3, - scoped = true, + local win_new = api.nvim_open_win(0, false, { + col=0,row=0,width=20,height=10, + relative = 'win',style = 'minimal', + hide = true }) + api.nvim__ns_set(ns, { wins = { win_new } }) + eq({ wins={ win_new } }, api.nvim__ns_get(ns)) + screen:expect(noextmarks) end) - it('change namespace scope', function() - set_scoped_extmark(0, 0, { - hl_group = 'Comment', - end_col = 3, - }) + it('namespace get works', function() + eq({ wins = {} }, api.nvim__ns_get(ns)) - eq(true, api.nvim__win_add_ns(0, ns)) - eq({ ns }, api.nvim__win_get_ns(0)) + api.nvim__ns_set(ns, { wins = { 0 } }) - screen:expect { - grid = [[ - {18:123}4^5 | - {1:~ }|*8 - | - ]]} + eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns)) - command 'split' - command 'only' - eq({}, api.nvim__win_get_ns(0)) + api.nvim__ns_set(ns, { wins = {} }) - screen:expect(noextmarks) + eq({ wins = {} }, api.nvim__ns_get(ns)) + end) - eq(true, api.nvim__win_add_ns(0, ns)) - eq({ ns }, api.nvim__win_get_ns(0)) + it('remove window from namespace scope when deleted', function () + api.nvim__ns_set(ns, { wins = { 0 } }) - screen:expect { - grid = [[ - {18:123}4^5 | - {1:~ }|*8 - | - ]]} + eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns)) - eq(true, api.nvim__win_del_ns(0, ns)) - eq({}, api.nvim__win_get_ns(0)) + command 'split' + command 'only' - screen:expect(noextmarks) + eq({ wins = {} }, api.nvim__ns_get(ns)) end) end) + diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua index e79621f364..d6a04f90f6 100644 --- a/test/functional/ui/diff_spec.lua +++ b/test/functional/ui/diff_spec.lua @@ -12,6 +12,19 @@ local exec = n.exec local eq = t.eq local api = n.api +local function WriteDiffFiles(text1, text2) + write_file('Xdifile1', text1) + write_file('Xdifile2', text2) + command('checktime') +end + +local function WriteDiffFiles3(text1, text2, text3) + write_file('Xdifile1', text1) + write_file('Xdifile2', text2) + write_file('Xdifile3', text3) + command('checktime') +end + before_each(clear) describe('Diff mode screen', function() @@ -614,6 +627,34 @@ int main(int argc, char **argv) ]]) end) + it('Diff empty and non-empty file', function() + write_file(fname, '', false) + write_file(fname_2, 'foo\nbar\nbaz', false) + reread() + + feed(':set diffopt=filler<cr>') + screen:expect([[ + {7: }{23:------------------}│{7: }{22:foo }| + {7: }{23:------------------}│{7: }{22:bar }| + {7: }{23:------------------}│{7: }{22:baz }| + {7: }^ │{1:~ }| + {1:~ }│{1:~ }|*10 + {3:<onal-diff-screen-1 }{2:<l-diff-screen-1.2 }| + :set diffopt=filler | + ]]) + + feed(':set diffopt+=internal<cr>') + screen:expect([[ + {7: }{23:------------------}│{7: }{22:foo }| + {7: }{23:------------------}│{7: }{22:bar }| + {7: }{23:------------------}│{7: }{22:baz }| + {7: }^ │{1:~ }| + {1:~ }│{1:~ }|*10 + {3:<onal-diff-screen-1 }{2:<l-diff-screen-1.2 }| + :set diffopt+=internal | + ]]) + end) + it('diffopt+=icase', function() write_file(fname, 'a\nb\ncd\n', false) write_file(fname_2, 'A\nb\ncDe\n', false) @@ -1346,6 +1387,46 @@ it("diff mode doesn't restore invalid 'foldcolumn' value #21647", function() eq('0', api.nvim_get_option_value('foldcolumn', {})) end) +it("'relativenumber' doesn't draw beyond end of window in diff mode #29403", function() + local screen = Screen.new(60, 12) + screen:attach() + command('set relativenumber') + feed('10aa<CR><Esc>gg') + command('vnew') + feed('ab<CR><Esc>gg') + command('windo diffthis') + command('wincmd |') + screen:expect([[ + {8: }│{7: }{8: 0 }{27:^a}{4: }| + {8: }│{7: }{8: 1 }{22:a }| + {8: }│{7: }{8: 2 }{22:a }| + {8: }│{7: }{8: 3 }{22:a }| + {8: }│{7: }{8: 4 }{22:a }| + {8: }│{7: }{8: 5 }{22:a }| + {8: }│{7: }{8: 6 }{22:a }| + {8: }│{7: }{8: 7 }{22:a }| + {8: }│{7: }{8: 8 }{22:a }| + {8: }│{7: }{8: 9 }{22:a }| + {2:< }{3:[No Name] [+] }| + | + ]]) + feed('j') + screen:expect([[ + {8: }│{7: }{8: 1 }{27:a}{4: }| + {8: }│{7: }{8: 0 }{22:^a }| + {8: }│{7: }{8: 1 }{22:a }| + {8: }│{7: }{8: 2 }{22:a }| + {8: }│{7: }{8: 3 }{22:a }| + {8: }│{7: }{8: 4 }{22:a }| + {8: }│{7: }{8: 5 }{22:a }| + {8: }│{7: }{8: 6 }{22:a }| + {8: }│{7: }{8: 7 }{22:a }| + {8: }│{7: }{8: 8 }{22:a }| + {2:< }{3:[No Name] [+] }| + | + ]]) +end) + -- oldtest: Test_diff_binary() it('diff mode works properly if file contains NUL bytes vim-patch:8.2.3925', function() local screen = Screen.new(40, 20) @@ -1447,3 +1528,529 @@ it("diff mode draws 'breakindent' correctly after filler lines", function() | ]]) end) + +-- oldtest: Test_diff_overlapped_diff_blocks_will_be_merged() +it('diff mode overlapped diff blocks will be merged', function() + write_file('Xdifile1', '') + write_file('Xdifile2', '') + write_file('Xdifile3', '') + + finally(function() + os.remove('Xdifile1') + os.remove('Xdifile2') + os.remove('Xdifile3') + os.remove('Xdiin1') + os.remove('Xdinew1') + os.remove('Xdiout1') + os.remove('Xdiin2') + os.remove('Xdinew2') + os.remove('Xdiout2') + end) + + exec([[ + func DiffExprStub() + let txt_in = readfile(v:fname_in) + let txt_new = readfile(v:fname_new) + if txt_in == ["line1"] && txt_new == ["line2"] + call writefile(["1c1"], v:fname_out) + elseif txt_in == readfile("Xdiin1") && txt_new == readfile("Xdinew1") + call writefile(readfile("Xdiout1"), v:fname_out) + elseif txt_in == readfile("Xdiin2") && txt_new == readfile("Xdinew2") + call writefile(readfile("Xdiout2"), v:fname_out) + endif + endfunc + ]]) + + local screen = Screen.new(35, 20) + screen:attach() + command('set winwidth=10 diffopt=filler,internal') + + command('args Xdifile1 Xdifile2 | vert all | windo diffthis') + + WriteDiffFiles('a\nb', 'x\nx') + write_file('Xdiin1', 'a\nb') + write_file('Xdinew1', 'x\nx') + write_file('Xdiout1', '1c1\n2c2') + command('set diffexpr=DiffExprStub()') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:^x}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }| + {1:~ }│{1:~ }|*16 + {2:Xdifile1 }{3:Xdifile2 }| + | + ]]) + command('set diffexpr&') + + WriteDiffFiles('a\nb\nc', 'x\nc') + write_file('Xdiin1', 'a\nb\nc') + write_file('Xdinew1', 'x\nc') + write_file('Xdiout1', '1c1\n2c1') + command('set diffexpr=DiffExprStub()') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:^x}{4: }| + {7: }{22:b }│{7: }{23:---------------}| + {7: }c │{7: }c | + {1:~ }│{1:~ }|*15 + {2:Xdifile1 }{3:Xdifile2 }| + | + ]]) + command('set diffexpr&') + + WriteDiffFiles('a\nc', 'x\nx\nc') + write_file('Xdiin1', 'a\nc') + write_file('Xdinew1', 'x\nx\nc') + write_file('Xdiout1', '1c1\n1a2') + command('set diffexpr=DiffExprStub()') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:^x}{4: }| + {7: }{23:---------------}│{7: }{22:x }| + {7: }c │{7: }c | + {1:~ }│{1:~ }|*15 + {2:Xdifile1 }{3:Xdifile2 }| + | + ]]) + command('set diffexpr&') + + command('args Xdifile1 Xdifile2 Xdifile3 | vert all | windo diffthis') + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'y\nb\nc') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }| + {7: }c │{7: }c │{7: }c | + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a\ny\nc') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }c │{7: }c │{7: }c | + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a\nb\ny') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'y\ny\nc') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }c │{7: }c │{7: }c | + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a\ny\ny') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'y\ny\ny') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nx', 'y\ny\nc') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:x}{4: }│{7: }{27:c}{4: }| + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'x\nx\nc', 'a\ny\ny') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:x}{4: }│{7: }{27:^a}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'y\ny\ny\nd\ne') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:d}{4: }| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'y\ny\ny\ny\ne') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'y\ny\ny\ny\ny') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:e}{4: }│{7: }{27:e}{4: }│{7: }{27:y}{4: }| + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\ny\ny\nd\ne') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:d}{4: }| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\ny\ny\ny\ne') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\ny\ny\ny\ny') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:e}{4: }│{7: }{27:e}{4: }│{7: }{27:y}{4: }| + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nb\ny\nd\ne') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:d}{4: }| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nb\ny\ny\ne') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nb\ny\ny\ny') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:e}{4: }│{7: }{27:e}{4: }│{7: }{27:y}{4: }| + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb', 'x\nb', 'y\ny') + write_file('Xdiin1', 'a\nb') + write_file('Xdinew1', 'x\nb') + write_file('Xdiout1', '1c1') + write_file('Xdiin2', 'a\nb') + write_file('Xdinew2', 'y\ny') + write_file('Xdiout2', '1c1\n2c2') + command('set diffexpr=DiffExprStub()') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:x}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:b}{4: }│{7: }{27:y}{4: }| + {1:~ }│{1:~ }│{1:~ }|*16 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + command('set diffexpr&') + + WriteDiffFiles3('a\nb\nc\nd', 'x\nb\nx\nd', 'y\ny\nc\nd') + write_file('Xdiin1', 'a\nb\nc\nd') + write_file('Xdinew1', 'x\nb\nx\nd') + write_file('Xdiout1', '1c1\n3c3') + write_file('Xdiin2', 'a\nb\nc\nd') + write_file('Xdinew2', 'y\ny\nc\nd') + write_file('Xdiout2', '1c1\n2c2') + command('set diffexpr=DiffExprStub()') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:x}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:b}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:x}{4: }│{7: }{27:c}{4: }| + {7: }d │{7: }d │{7: }d | + {1:~ }│{1:~ }│{1:~ }|*14 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + command('set diffexpr&') + + WriteDiffFiles3('a\nb\nc\nd', 'x\nb\nx\nd', 'y\ny\ny\nd') + write_file('Xdiin1', 'a\nb\nc\nd') + write_file('Xdinew1', 'x\nb\nx\nd') + write_file('Xdiout1', '1c1\n3c3') + write_file('Xdiin2', 'a\nb\nc\nd') + write_file('Xdinew2', 'y\ny\ny\nd') + write_file('Xdiout2', '1c1\n2,3c2,3') + command('set diffexpr=DiffExprStub()') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:x}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:b}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }d │{7: }d │{7: }d | + {1:~ }│{1:~ }│{1:~ }|*14 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + command('set diffexpr&') + + WriteDiffFiles3('a\nb\nc\nd', 'x\nb\nx\nd', 'y\ny\ny\ny') + write_file('Xdiin1', 'a\nb\nc\nd') + write_file('Xdinew1', 'x\nb\nx\nd') + write_file('Xdiout1', '1c1\n3c3') + write_file('Xdiin2', 'a\nb\nc\nd') + write_file('Xdinew2', 'y\ny\ny\ny') + write_file('Xdiout2', '1c1\n2,4c2,4') + command('set diffexpr=DiffExprStub()') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:x}{4: }│{7: }{27:^y}{4: }| + {7: }{27:b}{4: }│{7: }{27:b}{4: }│{7: }{27:y}{4: }| + {7: }{27:c}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{27:d}{4: }│{7: }{27:d}{4: }│{7: }{27:y}{4: }| + {1:~ }│{1:~ }│{1:~ }|*14 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + command('set diffexpr&') + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'b\nc') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^b}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }c │{7: }c │{7: }c | + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'c') + screen:expect([[ + {7: }{4:a }│{7: }{4:a }│{7: }{23:---------}| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }c │{7: }c │{7: }^c | + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', '') + screen:expect([[ + {7: }{4:a }│{7: }{4:a }│{7: }{23:---------}| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {1:~ }│{1:~ }│{7: }^ | + {1:~ }│{1:~ }│{1:~ }|*14 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a\nc') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }c │{7: }c │{7: }c | + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'b') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^b}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {1:~ }│{1:~ }│{1:~ }|*15 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'd\ne') + screen:expect([[ + {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^d}{4: }| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'e') + screen:expect([[ + {7: }{4:a }│{7: }{4:a }│{7: }{23:---------}| + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }e │{7: }e │{7: }^e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nd\ne') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:d}{4: }| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\ne') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }{4:e }│{7: }{4:e }│{7: }{23:---------}| + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nb\nd\ne') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }| + {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:d}{4: }| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nb\ne') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }e │{7: }e │{7: }e | + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nb') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }| + {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}| + {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}| + {7: }{4:e }│{7: }{4:e }│{7: }{23:---------}| + {1:~ }│{1:~ }│{1:~ }|*13 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a\ny\nb\nc') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }| + {7: }{23:---------}│{7: }{23:---------}│{7: }{22:b }| + {7: }c │{7: }c │{7: }c | + {1:~ }│{1:~ }│{1:~ }|*14 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) + + WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a\nb\ny\nc') + screen:expect([[ + {7: }a │{7: }a │{7: }^a | + {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }| + {7: }{23:---------}│{7: }{23:---------}│{7: }{22:y }| + {7: }c │{7: }c │{7: }c | + {1:~ }│{1:~ }│{1:~ }|*14 + {2:Xdifile1 Xdifile2 }{3:Xdifile3 }| + | + ]]) +end) diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 248220e28b..9b77cb4014 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -327,6 +327,35 @@ describe('float window', function() eq(12, pos[2]) end) + it('error message when invalid field specified for split', function() + local bufnr = api.nvim_create_buf(false, true) + eq( + "non-float cannot have 'row'", + pcall_err(api.nvim_open_win, bufnr, true, { split = 'right', row = 10 }) + ) + eq( + "non-float cannot have 'col'", + pcall_err(api.nvim_open_win, bufnr, true, { split = 'right', col = 10 }) + ) + eq( + "non-float cannot have 'bufpos'", + pcall_err(api.nvim_open_win, bufnr, true, { split = 'right', bufpos = { 0, 0 } }) + ) + local winid = api.nvim_open_win(bufnr, true, { split = 'right' }) + eq( + "non-float cannot have 'row'", + pcall_err(api.nvim_win_set_config, winid, { split = 'right', row = 10 }) + ) + eq( + "non-float cannot have 'col'", + pcall_err(api.nvim_win_set_config, winid, { split = 'right', col = 10 }) + ) + eq( + "non-float cannot have 'bufpos'", + pcall_err(api.nvim_win_set_config, winid, { split = 'right', bufpos = { 0, 0 } }) + ) + end) + it('error message when reconfig missing relative field', function() local bufnr = api.nvim_create_buf(false, true) local opts = { @@ -337,15 +366,16 @@ describe('float window', function() relative = 'editor', style = 'minimal', } - local win_id = api.nvim_open_win(bufnr, true, opts) + local winid = api.nvim_open_win(bufnr, true, opts) eq( - "Missing 'relative' field when reconfiguring floating window 1001", - pcall_err(api.nvim_win_set_config, win_id, { - width = 3, - height = 3, - row = 10, - col = 10, - })) + "Missing 'relative' field when reconfiguring floating window 1001", + pcall_err(api.nvim_win_set_config, winid, { + width = 3, + height = 3, + row = 10, + col = 10, + }) + ) end) it('is not operated on by windo when non-focusable #15374', function() @@ -632,6 +662,22 @@ describe('float window', function() screen:detach() end) + it('no crash with relative="win" after %bdelete #30569', function() + exec([[ + botright vsplit + %bdelete + ]]) + api.nvim_open_win(0, false, { + relative = 'win', + win = 0, + row = 0, + col = 5, + width = 5, + height = 5, + }) + assert_alive() + end) + describe('with only one tabpage,', function() local float_opts = {relative = 'editor', row = 1, col = 1, width = 1, height = 1} local old_buf, old_win @@ -1314,6 +1360,53 @@ describe('float window', function() | ]]) end + + -- + -- floating windows inherit NormalFloat from global-ns. + -- + command('fclose') + command('hi NormalFloat guibg=LightRed') + api.nvim_open_win(0, false, { relative = 'win', row = 3, col = 3, width = 12, height = 3, style = 'minimal' }) + api.nvim_set_hl_ns(api.nvim_create_namespace('test1')) + if multigrid then + screen:expect({ + grid = [[ + ## grid 1 + [2:----------------------------------------]|*6 + [3:----------------------------------------]| + ## grid 2 + {14: 1 }^x | + {14: 2 }y | + {14: 3 } | + {0:~ }|*3 + ## grid 3 + | + ## grid 5 + {22:x }| + {22:y }| + {22: }| + ]], float_pos={ + [5] = {1002, "NW", 2, 3, 3, true, 50}; + }, win_viewport={ + [2] = {win = 1000, topline = 0, botline = 4, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0}; + [5] = {win = 1002, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0}; + }, win_viewport_margins={ + [2] = { bottom = 0, left = 0, right = 0, top = 0, win = 1000 }, + [5] = { bottom = 0, left = 0, right = 0, top = 0, win = 1002 } + }}) + else + screen:expect({ + grid = [[ + {14: 1 }^x | + {14: 2 }y | + {14: 3 } | + {0:~ }{22:x }{0: }| + {0:~ }{22:y }{0: }| + {0:~ }{22: }{0: }| + | + ]] + }) + end end) it("can use 'minimal' style", function() @@ -1532,9 +1625,9 @@ describe('float window', function() [2:----------------------------------------]|*6 [3:----------------------------------------]| ## grid 2 - {20:1}{19: }{20: }{22:^x}{21: }| - {14:2}{19: }{14: }{22:y} | - {14:3}{19: }{14: }{22: } | + {20: 1}{19: }{22:^x}{21: }| + {14: 2}{19: }{22:y} | + {14: 3}{19: }{22: } | {0:~ }|*3 ## grid 3 | @@ -1545,9 +1638,9 @@ describe('float window', function() ]], float_pos={[4] = {1001, "NW", 1, 4, 10, true}}} else screen:expect{grid=[[ - {20:1}{19: }{20: }{22:^x}{21: }| - {14:2}{19: }{14: }{22:y} | - {14:3}{19: }{14: }{22: } {15:x } | + {20: 1}{19: }{22:^x}{21: }| + {14: 2}{19: }{22:y} | + {14: 3}{19: }{22: } {15:x } | {0:~ }{15:y }{0: }| {0:~ }{15: }{0: }|*2 | @@ -2127,7 +2220,7 @@ describe('float window', function() ## grid 3 | ## grid 4 - {5:â•”â•â•â•â•â•}🦄BB{5:â•—}| + {5:â•”â•â•â•â•â•}{11:🦄BB}{5:â•—}| {5:â•‘}{1: halloj! }{5:â•‘}| {5:â•‘}{1: BORDAA }{5:â•‘}| {5:╚â•â•â•â•â•â•â•â•â•â•}| @@ -2141,7 +2234,7 @@ describe('float window', function() screen:expect{grid=[[ ^ | {0:~ }| - {0:~ }{5:â•”â•â•â•â•â•}🦄BB{5:â•—}{0: }| + {0:~ }{5:â•”â•â•â•â•â•}{11:🦄BB}{5:â•—}{0: }| {0:~ }{5:â•‘}{1: halloj! }{5:â•‘}{0: }| {0:~ }{5:â•‘}{1: BORDAA }{5:â•‘}{0: }| {0:~ }{5:╚â•â•â•â•â•â•â•â•â•â•}{0: }| @@ -2275,7 +2368,7 @@ describe('float window', function() {5:â•”â•â•â•â•â•â•â•â•â•â•—}| {5:â•‘}{1: halloj! }{5:â•‘}| {5:â•‘}{1: BORDAA }{5:â•‘}| - {5:╚â•â•â•â•â•}🦄BB{5:â•}| + {5:╚â•â•â•â•â•}{11:🦄BB}{5:â•}| ]], float_pos={ [4] = { 1001, "NW", 1, 2, 5, true } }, win_viewport={ @@ -2289,7 +2382,7 @@ describe('float window', function() {0:~ }{5:â•”â•â•â•â•â•â•â•â•â•â•—}{0: }| {0:~ }{5:â•‘}{1: halloj! }{5:â•‘}{0: }| {0:~ }{5:â•‘}{1: BORDAA }{5:â•‘}{0: }| - {0:~ }{5:╚â•â•â•â•â•}🦄BB{5:â•}{0: }| + {0:~ }{5:╚â•â•â•â•â•}{11:🦄BB}{5:â•}{0: }| | ]]} end @@ -2423,10 +2516,10 @@ describe('float window', function() ## grid 3 | ## grid 4 - {5:â•”â•â•â•â•â•}🦄{7:BB}{5:â•—}| + {5:â•”â•â•â•â•â•}{11:🦄}{7:BB}{5:â•—}| {5:â•‘}{1: halloj! }{5:â•‘}| {5:â•‘}{1: BORDAA }{5:â•‘}| - {5:╚â•â•â•â•â•}🦄{7:BB}{5:â•}| + {5:╚â•â•â•â•â•}{11:🦄}{7:BB}{5:â•}| ]], float_pos={ [4] = { 1001, "NW", 1, 2, 5, true } }, win_viewport={ @@ -2437,10 +2530,10 @@ describe('float window', function() screen:expect{grid=[[ ^ | {0:~ }| - {0:~ }{5:â•”â•â•â•â•â•}🦄{7:BB}{5:â•—}{0: }| + {0:~ }{5:â•”â•â•â•â•â•}{11:🦄}{7:BB}{5:â•—}{0: }| {0:~ }{5:â•‘}{1: halloj! }{5:â•‘}{0: }| {0:~ }{5:â•‘}{1: BORDAA }{5:â•‘}{0: }| - {0:~ }{5:╚â•â•â•â•â•}🦄{7:BB}{5:â•}{0: }| + {0:~ }{5:╚â•â•â•â•â•}{11:🦄}{7:BB}{5:â•}{0: }| | ]]} end @@ -2485,6 +2578,37 @@ describe('float window', function() end eq({{"🦄", ""}, {"BB", {"B0", "B1", ""}}}, api.nvim_win_get_config(win).title) eq({{"🦄", ""}, {"BB", {"B0", "B1", ""}}}, api.nvim_win_get_config(win).footer) + + -- making it a split should not leak memory + api.nvim_win_set_config(win, { vertical = true }) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [4:--------------------]{5:│}[2:-------------------]|*5 + {5:[No Name] [+] }{4:[No Name] }| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }|*4 + ## grid 3 + | + ## grid 4 + halloj! | + BORDAA | + {0:~ }|*3 + ]], win_viewport={ + [2] = {win = 1000, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = 1001, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + halloj! {5:│}^ | + BORDAA {5:│}{0:~ }| + {0:~ }{5:│}{0:~ }|*3 + {5:[No Name] [+] }{4:[No Name] }| + | + ]]} + end end) it('terminates border on edge of viewport when window extends past viewport', function() @@ -8991,6 +9115,7 @@ describe('float window', function() end) it('float window with hide option', function() + local cwin = api.nvim_get_current_win() local buf = api.nvim_create_buf(false,false) local win = api.nvim_open_win(buf, false, {relative='editor', width=10, height=2, row=2, col=5, hide = true}) local expected_pos = { @@ -9070,6 +9195,22 @@ describe('float window', function() | ]]) end + -- check window jump with hide + feed('<C-W><C-W>') + -- should keep on current window + eq(cwin, api.nvim_get_current_win()) + api.nvim_win_set_config(win, {hide=false}) + api.nvim_set_current_win(win) + local win3 = api.nvim_open_win(buf, true, {relative='editor', width=4, height=4, row=2, col=5, hide = false}) + api.nvim_win_set_config(win, {hide=true}) + feed('<C-W>w') + -- should goto the first window with prev + eq(cwin, api.nvim_get_current_win()) + -- windo + command('windo set winheight=6') + eq(win3, api.nvim_get_current_win()) + eq(6, api.nvim_win_get_height(win3)) + eq(2, api.nvim_win_get_height(win)) end) it(':fclose command #9663', function() diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index b7b46ddfae..87d66fa604 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -596,13 +596,13 @@ describe('highlight', function() ]]) screen:expect( [[ - {1: }^ | + {1: }{5:^ }| {1: }{2:01}{3:234 67}{2:89}{5: }| {4:~ }|*2 {7:[No Name] [+] }| - {1: } | {1: }{6:-----------------------}| - {4:~ }| + {1: }{6:-----------------------}| + {1: } | {8:[No Name] }| | ]], @@ -1078,6 +1078,44 @@ describe('CursorLine and CursorLineNr highlights', function() ]]) end) + -- oldtest: Test_cursorline_screenline_resize() + it("'cursorlineopt' screenline is updated on window resize", function() + local screen = Screen.new(75, 8) + screen:attach() + exec([[ + 50vnew + call setline(1, repeat('xyz ', 30)) + setlocal number cursorline cursorlineopt=screenline + normal! $ + ]]) + screen:expect([[ + {8: 1 }xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xy│ | + {8: }z xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz │{1:~ }| + {8: }{21:xyz xyz xyz xyz xyz xyz xyz^ }│{1:~ }| + {1:~ }│{1:~ }|*3 + {3:[No Name] [+] }{2:[No Name] }| + | + ]]) + command('vertical resize -4') + screen:expect([[ + {8: 1 }xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xy│ | + {8: }z xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz │{1:~ }| + {8: }{21:xyz xyz xyz xyz xyz xyz xyz xyz xyz^ }│{1:~ }| + {1:~ }│{1:~ }|*3 + {3:[No Name] [+] }{2:[No Name] }| + | + ]]) + command('set cpoptions+=n') + screen:expect([[ + {8: 1 }xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xy│ | + z xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz │{1:~ }| + {21:xyz xyz xyz xyz xyz xyz xyz xyz^ }│{1:~ }| + {1:~ }│{1:~ }|*3 + {3:[No Name] [+] }{2:[No Name] }| + | + ]]) + end) + -- oldtest: Test_cursorline_after_yank() it('always updated. vim-patch:8.1.0849', function() local screen = Screen.new(50, 5) diff --git a/test/functional/ui/hlstate_spec.lua b/test/functional/ui/hlstate_spec.lua index 8d14c9f73d..a255047ed7 100644 --- a/test/functional/ui/hlstate_spec.lua +++ b/test/functional/ui/hlstate_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local clear, insert = n.clear, n.insert local command = n.command diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index ca52a265fa..a3e5068e55 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -1081,6 +1081,22 @@ stack traceback: }, }) end) + + it('does not do showmode unnecessarily #29086', function() + local screen_showmode = screen._handle_msg_showmode + local showmode = 0 + screen._handle_msg_showmode = function(...) + screen_showmode(...) + showmode = showmode + 1 + end + screen:expect({ + grid = [[ + ^ | + {1:~ }|*4 + ]], + }) + eq(showmode, 1) + end) end) describe('ui/builtin messages', function() @@ -1149,7 +1165,12 @@ describe('ui/builtin messages', function() it(':syntax list langGroup output', function() command('syntax on') - command('set syntax=vim') + exec([[ + syn match vimComment excludenl +\s"[^\-:.%#=*].*$+lc=1 contains=@vimCommentGroup,vimCommentString + syn match vimComment +\<endif\s\+".*$+lc=5 contains=@vimCommentGroup,vimCommentString + syn match vimComment +\<else\s\+".*$+lc=4 contains=@vimCommentGroup,vimCommentString + hi link vimComment Comment + ]]) screen:try_resize(110, 7) feed(':syntax list vimComment<cr>') screen:expect([[ @@ -1420,6 +1441,41 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim } end) + it('supports nvim_echo messages with emoji', function() + -- stylua: ignore + async_meths.nvim_echo( + { { 'wow, ðŸ³ï¸â€âš§ï¸ðŸ§‘â€ðŸŒ¾â¤ï¸ðŸ˜‚ðŸ´â€â˜ ï¸\nvariant â¤ï¸ one\nvariant ⤠two' } }, true, {} + ) + + screen:expect([[ + | + {1:~ }| + {3: }| + wow, ðŸ³ï¸â€âš§ï¸ðŸ§‘â€ðŸŒ¾â¤ï¸ðŸ˜‚ðŸ´â€â˜ ï¸ | + variant â¤ï¸ one | + variant ⤠two | + {6:Press ENTER or type command to continue}^ | + ]]) + + feed '<cr>' + screen:expect([[ + ^ | + {1:~ }|*5 + | + ]]) + + feed ':messages<cr>' + screen:expect([[ + | + {1:~ }| + {3: }| + wow, ðŸ³ï¸â€âš§ï¸ðŸ§‘â€ðŸŒ¾â¤ï¸ðŸ˜‚ðŸ´â€â˜ ï¸ | + variant â¤ï¸ one | + variant ⤠two | + {6:Press ENTER or type command to continue}^ | + ]]) + end) + it('prints lines in Ex mode correctly with a burst of carriage returns #19341', function() command('set number') api.nvim_buf_set_lines(0, 0, 0, true, { 'aaa', 'bbb', 'ccc' }) diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index 42c877fd92..bc18680749 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -367,7 +367,7 @@ describe('ui/mouse/input', function() }) end) - it('left click in default tabline (position 4) switches to tab', function() + it('left click in default tabline (tabpage label) switches to tab', function() feed_command('%delete') insert('this is foo') feed_command('silent file foo | tabnew | file bar') @@ -385,9 +385,47 @@ describe('ui/mouse/input', function() {0:~ }|*2 | ]]) + feed('<LeftMouse><6,0>') + screen:expect_unchanged() + feed('<LeftMouse><10,0>') + screen:expect([[ + {tab: + foo }{sel: + bar }{fill: }{tab:X}| + this is ba^r{0:$} | + {0:~ }|*2 + | + ]]) + feed('<LeftMouse><12,0>') + screen:expect_unchanged() + end) + + it('left click in default tabline (blank space) switches tab', function() + feed_command('%delete') + insert('this is foo') + feed_command('silent file foo | tabnew | file bar') + insert('this is bar') + screen:expect([[ + {tab: + foo }{sel: + bar }{fill: }{tab:X}| + this is ba^r{0:$} | + {0:~ }|*2 + | + ]]) + feed('<LeftMouse><20,0>') + screen:expect([[ + {sel: + foo }{tab: + bar }{fill: }{tab:X}| + this is fo^o | + {0:~ }|*2 + | + ]]) + feed('<LeftMouse><22,0>') + screen:expect([[ + {tab: + foo }{sel: + bar }{fill: }{tab:X}| + this is ba^r{0:$} | + {0:~ }|*2 + | + ]]) end) - it('left click in default tabline (position 24) closes tab', function() + it('left click in default tabline (close label) closes tab', function() api.nvim_set_option_value('hidden', true, {}) feed_command('%delete') insert('this is foo') @@ -407,8 +445,7 @@ describe('ui/mouse/input', function() ]]) end) - it('double click in default tabline (position 4) opens new tab', function() - api.nvim_set_option_value('hidden', true, {}) + it('double click in default tabline opens new tab before', function() feed_command('%delete') insert('this is foo') feed_command('silent file foo | tabnew | file bar') @@ -426,6 +463,34 @@ describe('ui/mouse/input', function() {0:~ }|*2 | ]]) + command('tabclose') + screen:expect([[ + {sel: + foo }{tab: + bar }{fill: }{tab:X}| + this is fo^o | + {0:~ }|*2 + | + ]]) + feed('<2-LeftMouse><20,0>') + screen:expect([[ + {tab: + foo + bar }{sel: Name] }{fill: }{tab:X}| + {0:^$} | + {0:~ }|*2 + | + ]]) + command('tabclose') + screen:expect([[ + {tab: + foo }{sel: + bar }{fill: }{tab:X}| + this is ba^r{0:$} | + {0:~ }|*2 + | + ]]) + feed('<2-LeftMouse><10,0>') + screen:expect([[ + {tab: + foo }{sel: Name] }{tab: + bar }{fill: }{tab:X}| + {0:^$} | + {0:~ }|*2 + | + ]]) end) describe('%@ label', function() @@ -987,7 +1052,7 @@ describe('ui/mouse/input', function() command('set sidescroll=0') feed('<esc>:set nowrap<cr>') - feed('a <esc>20Ab<esc>') + feed('a <esc>17Ab<esc>3Ab<esc>') screen:expect([[ |*2 bbbbbbbbbbbbbbb^b | @@ -1017,7 +1082,7 @@ describe('ui/mouse/input', function() command('set sidescroll=0') feed('<esc>:set nowrap<cr>') - feed('a <esc>20Ab<esc>') + feed('a <esc>17Ab<esc>3Ab<esc>') screen:expect([[ |*2 bbbbbbbbbbbbbbb^b | @@ -2002,5 +2067,24 @@ describe('ui/mouse/input', function() feed('<Down><CR>') eq({ 4, 20 }, api.nvim_win_get_cursor(0)) eq('the moon', fn.getreg('"')) + + -- Try clicking in the cmdline + api.nvim_input_mouse('right', 'press', '', 0, 23, 0) + api.nvim_input_mouse('right', 'release', '', 0, 23, 0) + feed('<Down><Down><Down><CR>') + eq('baz', api.nvim_get_var('menustr')) + + -- Try clicking in horizontal separator with global statusline + command('set laststatus=3') + api.nvim_input_mouse('right', 'press', '', 0, 5, 0) + api.nvim_input_mouse('right', 'release', '', 0, 5, 0) + feed('<Down><CR>') + eq('foo', api.nvim_get_var('menustr')) + + -- Try clicking in the cmdline with global statusline + api.nvim_input_mouse('right', 'press', '', 0, 23, 0) + api.nvim_input_mouse('right', 'release', '', 0, 23, 0) + feed('<Down><Down><CR>') + eq('bar', api.nvim_get_var('menustr')) end) end) diff --git a/test/functional/ui/multibyte_spec.lua b/test/functional/ui/multibyte_spec.lua index dc25a09d0d..f16f750ea1 100644 --- a/test/functional/ui/multibyte_spec.lua +++ b/test/functional/ui/multibyte_spec.lua @@ -296,6 +296,86 @@ describe('multibyte rendering', function() ]], } end) + + it('supports emoji with variant selectors and ZWJ', function() + command('set ruler') + insert('ðŸ³ï¸â€âš§ï¸') + screen:expect([[ + ^ðŸ³ï¸â€âš§ï¸ | + {1:~ }|*4 + 1,1 All | + ]]) + + feed('a word<esc>') + screen:expect([[ + ðŸ³ï¸â€âš§ï¸ wor^d | + {1:~ }|*4 + 1,21-7 All | + ]]) + + feed('0') + screen:expect([[ + ^ðŸ³ï¸â€âš§ï¸ word | + {1:~ }|*4 + 1,1 All | + ]]) + + feed('l') + screen:expect([[ + ðŸ³ï¸â€âš§ï¸^ word | + {1:~ }|*4 + 1,17-3 All | + ]]) + + feed('h') + screen:expect([[ + ^ðŸ³ï¸â€âš§ï¸ word | + {1:~ }|*4 + 1,1 All | + ]]) + + feed('oâ¤ï¸ variant selected<esc>') + screen:expect([[ + ðŸ³ï¸â€âš§ï¸ word | + â¤ï¸ variant selecte^d | + {1:~ }|*3 + 2,23-19 All | + ]]) + + feed('0') + screen:expect([[ + ðŸ³ï¸â€âš§ï¸ word | + ^â¤ï¸ variant selected | + {1:~ }|*3 + 2,1 All | + ]]) + + feed('l') + screen:expect([[ + ðŸ³ï¸â€âš§ï¸ word | + â¤ï¸^ variant selected | + {1:~ }|*3 + 2,7-3 All | + ]]) + + feed('h') + screen:expect([[ + ðŸ³ï¸â€âš§ï¸ word | + ^â¤ï¸ variant selected | + {1:~ }|*3 + 2,1 All | + ]]) + + -- without selector: single width (note column 18 and not 19) + feed('o⤠variant selected<esc>') + screen:expect([[ + ðŸ³ï¸â€âš§ï¸ word | + â¤ï¸ variant selected | + ⤠variant selecte^d | + {1:~ }|*2 + 3,20-18 All | + ]]) + end) end) describe('multibyte rendering: statusline', function() @@ -348,11 +428,12 @@ describe('multibyte rendering: statusline', function() it('non-printable followed by MAX_MCO unicode combination points', function() command('set statusline=Ÿ̸⃯ᷰâƒâƒ§âƒ') -- U+9F + U+1DF0 + U+20EF + U+0338 + U+20D0 + U+20E7 + U+20DD + -- TODO: not ideal, better with plain ">" and then space+combining screen:expect([[ - ^ | - {1:~ }| - {3:<9f><1df0><20ef><0338><20d0><20e7><20dd>}| - | + ^ | + {1:~ }| + {3:<9f≯⃯ᷰâƒâƒ§âƒ }| + | ]]) end) @@ -368,9 +449,20 @@ describe('multibyte rendering: statusline', function() } end) - it('unprintable chars in filename with default stl', function() + it('emoji with ZWJ in filename with default stl', function() command('file 🧑â€ðŸ’»') - -- TODO: this is wrong but avoids a crash + screen:expect { + grid = [[ + ^ | + {1:~ }| + {3:🧑â€ðŸ’» }| + | + ]], + } + end) + + it('unprintable chars in filename with default stl', function() + command('file 🧑​💻') screen:expect { grid = [[ ^ | @@ -381,15 +473,27 @@ describe('multibyte rendering: statusline', function() } end) - it('unprintable chars in filename with custom stl', function() + it('emoji with ZWJ in filename with custom stl', function() command('set statusline=xx%#ErrorMsg#%f%##yy') command('file 🧑â€ðŸ’»') - -- TODO: this is also wrong but also avoids a crash screen:expect { grid = [[ ^ | {1:~ }| - {3:xx}{9:🧑<200d>💻}{3:yy }| + {3:xx}{9:🧑â€ðŸ’»}{3:yy }| + | + ]], + } + end) + + it('unprintable chars in filename with custom stl', function() + command('set statusline=xx%#ErrorMsg#%f%##yy') + command('file 🧑​💻') + screen:expect { + grid = [[ + ^ | + {1:~ }| + {3:xx}{9:🧑<200b>💻}{3:yy }| | ]], } diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua index dc48061a6c..e009ed0a29 100644 --- a/test/functional/ui/multigrid_spec.lua +++ b/test/functional/ui/multigrid_spec.lua @@ -1095,6 +1095,7 @@ describe('ext_multigrid', function() end) it('supports mouse', function() + command('autocmd! nvim_popupmenu') -- Delete the default MenuPopup event handler. insert('some text\nto be clicked') screen:expect{grid=[[ ## grid 1 @@ -2598,4 +2599,257 @@ describe('ext_multigrid', function() ]]) eq(1, api.nvim_get_option_value('cmdheight', {})) end) + + describe('centered cursorline', function() + before_each(function() + -- Force a centered cursorline, this caused some redrawing problems described in #30576. + -- Most importantly, win_viewport was not received in time, and sum_scroll_delta did not refresh. + command('set cursorline scrolloff=9999') + end) + it('insert line scrolls correctly', function() + for i = 1, 11 do + insert('line' .. i .. '\n') + end + screen:expect({ + grid = [[ + ## grid 1 + [2:-----------------------------------------------------]|*12 + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + line1 | + line2 | + line3 | + line4 | + line5 | + line6 | + line7 | + line8 | + line9 | + line10 | + line11 | + {23:^ }| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = 1000, topline = 0, botline = 12, curline = 11, curcol = 0, linecount = 12, sum_scroll_delta = 0}; + }, win_viewport_margins={ + [2] = { + bottom = 0, + left = 0, + right = 0, + top = 0, + win = 1000 + } + }}) + insert('line12\n') + screen:expect({ + grid = [[ + ## grid 1 + [2:-----------------------------------------------------]|*12 + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + line2 | + line3 | + line4 | + line5 | + line6 | + line7 | + line8 | + line9 | + line10 | + line11 | + line12 | + {23:^ }| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = 1000, topline = 1, botline = 13, curline = 12, curcol = 0, linecount = 13, sum_scroll_delta = 1}; + }, win_viewport_margins={ + [2] = { + bottom = 0, + left = 0, + right = 0, + top = 0, + win = 1000 + } + }}) + end) + + it('got to top scrolls correctly', function() + for i = 1, 20 do + insert('line' .. i .. '\n') + end + screen:expect({ + grid = [[ + ## grid 1 + [2:-----------------------------------------------------]|*12 + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + line10 | + line11 | + line12 | + line13 | + line14 | + line15 | + line16 | + line17 | + line18 | + line19 | + line20 | + {23:^ }| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = 1000, topline = 9, botline = 21, curline = 20, curcol = 0, linecount = 21, sum_scroll_delta = 9}; + }, win_viewport_margins={ + [2] = { + bottom = 0, + left = 0, + right = 0, + top = 0, + win = 1000 + } + }}) + feed('gg') + screen:expect({ + grid = [[ + ## grid 1 + [2:-----------------------------------------------------]|*12 + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + {23:^line1 }| + line2 | + line3 | + line4 | + line5 | + line6 | + line7 | + line8 | + line9 | + line10 | + line11 | + line12 | + ## grid 3 + | + ]], win_viewport={ + [2] = {win = 1000, topline = 0, botline = 13, curline = 0, curcol = 0, linecount = 21, sum_scroll_delta = 0}; + }, win_viewport_margins={ + [2] = { + bottom = 0, + left = 0, + right = 0, + top = 0, + win = 1000 + } + }}) + end) + + it('scrolls in the middle', function() + for i = 1, 20 do + insert('line' .. i .. '\n') + end + screen:expect({ + grid = [[ + ## grid 1 + [2:-----------------------------------------------------]|*12 + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + line10 | + line11 | + line12 | + line13 | + line14 | + line15 | + line16 | + line17 | + line18 | + line19 | + line20 | + {23:^ }| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = 1000, topline = 9, botline = 21, curline = 20, curcol = 0, linecount = 21, sum_scroll_delta = 9}; + }, win_viewport_margins={ + [2] = { + bottom = 0, + left = 0, + right = 0, + top = 0, + win = 1000 + } + }}) + feed('M') + screen:expect({ + grid = [[ + ## grid 1 + [2:-----------------------------------------------------]|*12 + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + line10 | + line11 | + line12 | + line13 | + line14 | + {23:^line15 }| + line16 | + line17 | + line18 | + line19 | + line20 | + | + ## grid 3 + | + ]], win_viewport={ + [2] = {win = 1000, topline = 9, botline = 21, curline = 14, curcol = 0, linecount = 21, sum_scroll_delta = 9}; + }, win_viewport_margins={ + [2] = { + bottom = 0, + left = 0, + right = 0, + top = 0, + win = 1000 + } + }}) + feed('k') + screen:expect({ + grid = [[ + ## grid 1 + [2:-----------------------------------------------------]|*12 + {11:[No Name] [+] }| + [3:-----------------------------------------------------]| + ## grid 2 + line9 | + line10 | + line11 | + line12 | + line13 | + {23:^line14 }| + line15 | + line16 | + line17 | + line18 | + line19 | + line20 | + ## grid 3 + | + ]], win_viewport={ + [2] = {win = 1000, topline = 8, botline = 21, curline = 13, curcol = 0, linecount = 21, sum_scroll_delta = 8}; + }, win_viewport_margins={ + [2] = { + bottom = 0, + left = 0, + right = 0, + top = 0, + win = 1000 + } + }}) + end) + end) end) diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua index 4f6454a0fb..220af06f53 100644 --- a/test/functional/ui/output_spec.lua +++ b/test/functional/ui/output_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local tt = require('test.functional.terminal.testutil') +local tt = require('test.functional.testterm') local assert_alive = n.assert_alive local mkdir, write_file, rmdir = t.mkdir, t.write_file, n.rmdir diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 8f8604eecb..f84362ede8 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -851,6 +851,8 @@ describe('ui/ext_popupmenu', function() set mouse=a mousemodel=popup aunmenu PopUp + " Delete the default MenuPopup event handler. + autocmd! nvim_popupmenu menu PopUp.foo :let g:menustr = 'foo'<CR> menu PopUp.bar :let g:menustr = 'bar'<CR> menu PopUp.baz :let g:menustr = 'baz'<CR> @@ -1129,7 +1131,7 @@ describe("builtin popupmenu 'pumblend'", function() [10] = { foreground = tonumber('0x000002') }, }) screen:attach({ rgb = false }) - command('set notermguicolors pumblend=10') + command('set pumblend=10') insert([[ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor @@ -1160,23 +1162,47 @@ describe('builtin popupmenu', function() screen = Screen.new(32, 20) screen:set_default_attr_ids({ -- popup selected item / scrollbar track - ['s'] = { background = Screen.colors.WebGray }, + s = { background = Screen.colors.Grey }, -- popup non-selected item - ['n'] = { background = Screen.colors.LightMagenta }, + n = { background = Screen.colors.Plum1 }, -- popup scrollbar knob - ['c'] = { background = Screen.colors.Grey0 }, + c = { background = Screen.colors.Black }, [1] = { bold = true, foreground = Screen.colors.Blue }, [2] = { bold = true }, [3] = { reverse = true }, [4] = { bold = true, reverse = true }, [5] = { bold = true, foreground = Screen.colors.SeaGreen }, - [6] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, + [6] = { foreground = Screen.colors.White, background = Screen.colors.Red }, [7] = { background = Screen.colors.Yellow }, -- Search [8] = { foreground = Screen.colors.Red }, - kn = { foreground = Screen.colors.Red, background = Screen.colors.Magenta }, ks = { foreground = Screen.colors.Red, background = Screen.colors.Grey }, - xn = { foreground = Screen.colors.White, background = Screen.colors.Magenta }, + kn = { foreground = Screen.colors.Red, background = Screen.colors.Plum1 }, xs = { foreground = Screen.colors.Black, background = Screen.colors.Grey }, + xn = { foreground = Screen.colors.White, background = Screen.colors.Plum1 }, + ms = { foreground = Screen.colors.Blue, background = Screen.colors.Grey }, + mn = { foreground = Screen.colors.Blue, background = Screen.colors.Plum1 }, + ds = { foreground = Screen.colors.DarkRed, background = Screen.colors.Grey }, + dn = { foreground = Screen.colors.DarkRed, background = Screen.colors.Plum1 }, + ums = { + foreground = Screen.colors.Blue, + background = Screen.colors.Grey, + underline = true, + }, + umn = { + foreground = Screen.colors.Blue, + background = Screen.colors.Plum1, + underline = true, + }, + uds = { + foreground = Screen.colors.DarkRed, + background = Screen.colors.Grey, + underline = true, + }, + udn = { + foreground = Screen.colors.DarkRed, + background = Screen.colors.Plum1, + underline = true, + }, }) screen:attach({ ext_multigrid = multigrid }) end) @@ -2528,6 +2554,7 @@ describe('builtin popupmenu', function() ]], } + -- oldtest: Test_wildmenu_pum_rightleft() feed('<tab>') screen:expect { grid = [[ @@ -2917,11 +2944,12 @@ describe('builtin popupmenu', function() feed('<C-U>sign define <Tab>') screen:expect([[ | - {1:~ }|*2 + {1:~ }| {1:~ }{s: culhl= }{1: }| {1:~ }{n: icon= }{1: }| {1:~ }{n: linehl= }{1: }| {1:~ }{n: numhl= }{1: }| + {1:~ }{n: priority= }{1: }| {1:~ }{n: text= }{1: }| {1:~ }{n: texthl= }{1: }| :sign define culhl=^ | @@ -2930,11 +2958,12 @@ describe('builtin popupmenu', function() feed('<Space><Tab>') screen:expect([[ | - {1:~ }|*2 + {1:~ }| {1:~ }{s: culhl= }{1: }| {1:~ }{n: icon= }{1: }| {1:~ }{n: linehl= }{1: }| {1:~ }{n: numhl= }{1: }| + {1:~ }{n: priority= }{1: }| {1:~ }{n: text= }{1: }| {1:~ }{n: texthl= }{1: }| :sign define culhl= culhl=^ | @@ -3547,6 +3576,66 @@ describe('builtin popupmenu', function() | ]]) end) + + -- oldtest: Test_wildmenu_pum_hl_match() + it('highlighting matched text in cmdline pum', function() + exec([[ + set wildoptions=pum,fuzzy + hi PmenuMatchSel guifg=Blue guibg=Grey + hi PmenuMatch guifg=Blue guibg=Plum1 + ]]) + + feed(':sign plc<Tab>') + screen:expect([[ + | + {1:~ }|*16 + {1:~ }{s: }{ms:pl}{s:a}{ms:c}{s:e }{1: }| + {1:~ }{n: un}{mn:pl}{n:a}{mn:c}{n:e }{1: }| + :sign place^ | + ]]) + feed('<Tab>') + screen:expect([[ + | + {1:~ }|*16 + {1:~ }{n: }{mn:pl}{n:a}{mn:c}{n:e }{1: }| + {1:~ }{s: un}{ms:pl}{s:a}{ms:c}{s:e }{1: }| + :sign unplace^ | + ]]) + feed('<Tab>') + screen:expect([[ + | + {1:~ }|*16 + {1:~ }{n: }{mn:pl}{n:a}{mn:c}{n:e }{1: }| + {1:~ }{n: un}{mn:pl}{n:a}{mn:c}{n:e }{1: }| + :sign plc^ | + ]]) + feed('<Esc>') + command('set wildoptions-=fuzzy') + feed(':sign un<Tab>') + screen:expect([[ + | + {1:~ }|*16 + {1:~ }{s: }{ms:un}{s:define }{1: }| + {1:~ }{n: }{mn:un}{n:place }{1: }| + :sign undefine^ | + ]]) + feed('<Tab>') + screen:expect([[ + | + {1:~ }|*16 + {1:~ }{n: }{mn:un}{n:define }{1: }| + {1:~ }{s: }{ms:un}{s:place }{1: }| + :sign unplace^ | + ]]) + feed('<Tab>') + screen:expect([[ + | + {1:~ }|*16 + {1:~ }{n: }{mn:un}{n:define }{1: }| + {1:~ }{n: }{mn:un}{n:place }{1: }| + :sign un^ | + ]]) + end) end it("'pumheight'", function() @@ -3718,6 +3807,8 @@ describe('builtin popupmenu', function() call setline(1, 'popup menu test') set mouse=a mousemodel=popup + " Delete the default MenuPopup event handler. + autocmd! nvim_popupmenu aunmenu PopUp menu PopUp.foo :let g:menustr = 'foo'<CR> menu PopUp.bar :let g:menustr = 'bar'<CR> @@ -4402,6 +4493,9 @@ describe('builtin popupmenu', function() -- oldtest: Test_popup_command_dump() it(':popup command', function() exec([[ + " Delete the default MenuPopup event handler. + autocmd! nvim_popupmenu + func ChangeMenu() aunmenu PopUp.&Paste nnoremenu 1.40 PopUp.&Paste :echomsg "pasted"<CR> @@ -4477,6 +4571,27 @@ describe('builtin popupmenu', function() feed('<Esc>') + command('set rightleft') + feed('/X<CR>:popup PopUp<CR>') + screen:expect([[ + evif ruof eerht owt eno| + evif ruof eerht{7:^X} owt eno dna| + {n: odnU }wt erom eno| + {1: }{n: }{1: ~}| + {1: }{n: etsaP }{1: ~}| + {1: }{n: }{1: ~}| + {1: }{n: droW tceleS }{1: ~}| + {1: }{n: ecnetneS tceleS }{1: ~}| + {1: }{n: hpargaraP tceleS }{1: ~}| + {1: }{n: eniL tceleS }{1: ~}| + {1: }{n: kcolB tceleS }{1: ~}| + {1: }{n: llA tceleS }{1: ~}| + {1: ~}|*7 + :popup PopUp | + ]]) + feed('<Esc>') + command('set norightleft') + -- Set an <expr> mapping to change a menu entry while it's displayed. -- The text should not change but the command does. -- Also verify that "changed" shows up, which means the mapping triggered. @@ -4533,6 +4648,57 @@ describe('builtin popupmenu', function() feed('<Esc>') end) + -- oldtest: Test_mouse_popup_position() + it('position of right-click menu when clicking near edge', function() + screen:try_resize(50, 20) + exec([[ + set mousemodel=popup_setpos + " Delete the default MenuPopup event handler. + autocmd! nvim_popupmenu + aunmenu * + source $VIMRUNTIME/menu.vim + call setline(1, join(range(20))) + ]]) + + api.nvim_input_mouse('right', 'press', '', 0, 0, 45 - 1) + screen:expect([[ + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ^18 19 | + {1:~ }{n: Undo }| + {1:~ }{n: }| + {1:~ }{n: Paste }| + {1:~ }{n: }| + {1:~ }{n: Select Word }| + {1:~ }{n: Select Sentence }| + {1:~ }{n: Select Paragraph}| + {1:~ }{n: Select Line }| + {1:~ }{n: Select Block }| + {1:~ }{n: Select All }| + {1:~ }|*8 + | + ]]) + feed('<Esc>') + + command('set rightleft') + api.nvim_input_mouse('right', 'press', '', 0, 0, 50 - 45) + screen:expect([[ + 91 8^1 71 61 51 41 31 21 11 01 9 8 7 6 5 4 3 2 1 0| + {n: odnU }{1: ~}| + {n: }{1: ~}| + {n: etsaP }{1: ~}| + {n: }{1: ~}| + {n: droW tceleS }{1: ~}| + {n: ecnetneS tceleS }{1: ~}| + {n:hpargaraP tceleS }{1: ~}| + {n: eniL tceleS }{1: ~}| + {n: kcolB tceleS }{1: ~}| + {n: llA tceleS }{1: ~}| + {1: ~}|*8 + | + ]]) + feed('<Esc>') + command('set norightleft') + end) + describe('"kind" and "menu"', function() before_each(function() screen:try_resize(30, 8) @@ -4569,9 +4735,9 @@ describe('builtin popupmenu', function() -- oldtest: Test_pum_highlights_custom() it('custom highlight groups', function() exec([[ - hi PmenuKind guifg=Red guibg=Magenta + hi PmenuKind guifg=Red guibg=Plum1 hi PmenuKindSel guifg=Red guibg=Grey - hi PmenuExtra guifg=White guibg=Magenta + hi PmenuExtra guifg=White guibg=Plum1 hi PmenuExtraSel guifg=Black guibg=Grey ]]) feed('iaw<C-X><C-u>') @@ -4585,6 +4751,443 @@ describe('builtin popupmenu', function() ]]) end) end) + + -- oldtest: Test_pum_highlights_match() + it('can highlight matched text', function() + exec([[ + func Omni_test(findstart, base) + if a:findstart + return col(".") + endif + return { + \ 'words': [ + \ { 'word': 'foo', 'kind': 'fookind' }, + \ { 'word': 'foofoo', 'kind': 'fookind' }, + \ { 'word': 'foobar', 'kind': 'fookind' }, + \ { 'word': 'fooBaz', 'kind': 'fookind' }, + \ { 'word': 'foobala', 'kind': 'fookind' }, + \ { 'word': 'ä½ å¥½' }, + \ { 'word': 'ä½ å¥½å—' }, + \ { 'word': 'ä½ ä¸å¥½å—' }, + \ { 'word': 'ä½ å¯å¥½å—' }, + \]} + endfunc + + func Comp() + let col = col('.') + if getline('.') == 'f' + let col -= 1 + endif + call complete(col, [ + \ #{word: "foo", icase: 1}, + \ #{word: "Foobar", icase: 1}, + \ #{word: "fooBaz", icase: 1}, + \]) + return '' + endfunc + + set omnifunc=Omni_test + set completeopt=menu,noinsert,fuzzy + hi PmenuMatchSel guifg=Blue guibg=Grey + hi PmenuMatch guifg=Blue guibg=Plum1 + ]]) + feed('i<C-X><C-O>') + local pum_start = [[ + ^ | + {s:foo fookind }{1: }| + {n:foofoo fookind }{1: }| + {n:foobar fookind }{1: }| + {n:fooBaz fookind }{1: }| + {n:foobala fookind }{1: }| + {n:ä½ å¥½ }{1: }| + {n:ä½ å¥½å— }{1: }| + {n:ä½ ä¸å¥½å— }{1: }| + {n:ä½ å¯å¥½å— }{1: }| + {1:~ }|*9 + {2:-- }{5:match 1 of 9} | + ]] + screen:expect(pum_start) + feed('fo') + screen:expect([[ + fo^ | + {ms:fo}{s:o fookind }{1: }| + {mn:fo}{n:ofoo fookind }{1: }| + {mn:fo}{n:obar fookind }{1: }| + {mn:fo}{n:oBaz fookind }{1: }| + {mn:fo}{n:obala fookind }{1: }| + {1:~ }|*13 + {2:-- }{5:match 1 of 9} | + ]]) + feed('<Esc>S<C-X><C-O>') + screen:expect(pum_start) + feed('ä½ ') + screen:expect([[ + ä½ ^ | + {ms:ä½ }{s:好 }{1: }| + {mn:ä½ }{n:å¥½å— }{1: }| + {mn:ä½ }{n:ä¸å¥½å— }{1: }| + {mn:ä½ }{n:å¯å¥½å— }{1: }| + {1:~ }|*14 + {2:-- }{5:match 1 of 9} | + ]]) + feed('å—') + screen:expect([[ + ä½ å—^ | + {ms:ä½ }{s:好}{ms:å—}{s: }{1: }| + {mn:ä½ }{n:ä¸å¥½}{mn:å—}{n: }{1: }| + {mn:ä½ }{n:å¯å¥½}{mn:å—}{n: }{1: }| + {1:~ }|*15 + {2:-- }{5:match 1 of 9} | + ]]) + feed('<C-E><Esc>') + + command('set rightleft') + feed('S<C-X><C-O>') + local pum_start_rl = [[ + ^ | + {1: }{s: dnikoof oof}| + {1: }{n: dnikoof oofoof}| + {1: }{n: dnikoof raboof}| + {1: }{n: dnikoof zaBoof}| + {1: }{n: dnikoof alaboof}| + {1: }{n: å¥½ä½ }| + {1: }{n: å—å¥½ä½ }| + {1: }{n: å—好ä¸ä½ }| + {1: }{n: å—好å¯ä½ }| + {1: ~}|*9 + {2:-- }{5:match 1 of 9} | + ]] + screen:expect(pum_start_rl) + feed('fo') + screen:expect([[ + ^ of| + {1: }{s: dnikoof o}{ms:of}| + {1: }{n: dnikoof oofo}{mn:of}| + {1: }{n: dnikoof rabo}{mn:of}| + {1: }{n: dnikoof zaBo}{mn:of}| + {1: }{n: dnikoof alabo}{mn:of}| + {1: ~}|*13 + {2:-- }{5:match 1 of 9} | + ]]) + feed('<Esc>S<C-X><C-O>') + screen:expect(pum_start_rl) + feed('ä½ ') + screen:expect([[ + ^ ä½ | + {1: }{s: 好}{ms:ä½ }| + {1: }{n: å—好}{mn:ä½ }| + {1: }{n: å—好ä¸}{mn:ä½ }| + {1: }{n: å—好å¯}{mn:ä½ }| + {1: ~}|*14 + {2:-- }{5:match 1 of 9} | + ]]) + feed('å—') + screen:expect([[ + ^ å—ä½ | + {1: }{s: }{ms:å—}{s:好}{ms:ä½ }| + {1: }{n: }{mn:å—}{n:好ä¸}{mn:ä½ }| + {1: }{n: }{mn:å—}{n:好å¯}{mn:ä½ }| + {1: ~}|*15 + {2:-- }{5:match 1 of 9} | + ]]) + feed('<C-E><Esc>') + command('set norightleft') + + command('set completeopt-=fuzzy') + feed('S<C-X><C-O>') + screen:expect(pum_start) + feed('fo') + screen:expect([[ + fo^ | + {ms:fo}{s:o fookind }{1: }| + {mn:fo}{n:ofoo fookind }{1: }| + {mn:fo}{n:obar fookind }{1: }| + {mn:fo}{n:oBaz fookind }{1: }| + {mn:fo}{n:obala fookind }{1: }| + {1:~ }|*13 + {2:-- }{5:match 1 of 9} | + ]]) + feed('<C-E><Esc>') + + command('set rightleft') + feed('S<C-X><C-O>') + screen:expect(pum_start_rl) + feed('fo') + screen:expect([[ + ^ of| + {1: }{s: dnikoof o}{ms:of}| + {1: }{n: dnikoof oofo}{mn:of}| + {1: }{n: dnikoof rabo}{mn:of}| + {1: }{n: dnikoof zaBo}{mn:of}| + {1: }{n: dnikoof alabo}{mn:of}| + {1: ~}|*13 + {2:-- }{5:match 1 of 9} | + ]]) + feed('<C-E><Esc>') + command('set norightleft') + + feed('S<C-R>=Comp()<CR>f') + screen:expect([[ + f^ | + {ms:f}{s:oo }{1: }| + {mn:F}{n:oobar }{1: }| + {mn:f}{n:ooBaz }{1: }| + {1:~ }|*15 + {2:-- INSERT --} | + ]]) + feed('o<BS><C-R>=Comp()<CR>') + screen:expect_unchanged(true) + + feed('<Esc>') + command('set completeopt+=fuzzy,menu') + feed('S hello helio hero h<C-X><C-P>') + screen:expect([[ + hello helio hero h^ | + {1:~ }{n: }{mn:h}{n:ello }{1: }| + {1:~ }{n: }{mn:h}{n:elio }{1: }| + {1:~ }{s: }{ms:h}{s:ero }{1: }| + {1:~ }|*15 + {2:-- }{5:match 1 of 3} | + ]]) + + feed('<Esc>S hello helio hero h<C-X><C-P><C-P>') + screen:expect([[ + hello helio hero h^ | + {1:~ }{n: }{mn:h}{n:ello }{1: }| + {1:~ }{s: }{ms:h}{s:elio }{1: }| + {1:~ }{n: }{mn:h}{n:ero }{1: }| + {1:~ }|*15 + {2:-- }{5:match 2 of 3} | + ]]) + + feed('<C-E><Esc>') + end) + + -- oldtest: Test_pum_user_hl_group() + it('custom hl_group override', function() + exec([[ + func CompleteFunc( findstart, base ) + if a:findstart + return 0 + endif + return { + \ 'words': [ + \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', 'hl_group': 'StrikeFake' }, + \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'W', }, + \ { 'word': 'ä½ å¥½', 'menu': 'extra text 3', 'kind': 'W', 'hl_group': 'StrikeFake' }, + \]} + endfunc + set completeopt=menu + set completefunc=CompleteFunc + + hi StrikeFake guifg=DarkRed + func HlMatch() + hi PmenuMatchSel guifg=Blue guibg=Grey gui=underline + hi PmenuMatch guifg=Blue guibg=Plum1 gui=underline + endfunc + ]]) + + feed('Saw<C-X><C-U>') + screen:expect([[ + aword1^ | + {ds:aword1 W extra text 1 }{1: }| + {n:aword2 W extra text 2 }{1: }| + {dn:ä½ å¥½ W extra text 3 }{1: }| + {1:~ }|*15 + {2:-- }{5:match 1 of 3} | + ]]) + feed('<C-E><Esc>') + + command('call HlMatch()') + + feed('Saw<C-X><C-U>') + screen:expect([[ + aword1^ | + {uds:aw}{ds:ord1 W extra text 1 }{1: }| + {umn:aw}{n:ord2 W extra text 2 }{1: }| + {dn:ä½ å¥½ W extra text 3 }{1: }| + {1:~ }|*15 + {2:-- }{5:match 1 of 3} | + ]]) + feed('<C-N>') + screen:expect([[ + aword2^ | + {udn:aw}{dn:ord1 W extra text 1 }{1: }| + {ums:aw}{s:ord2 W extra text 2 }{1: }| + {dn:ä½ å¥½ W extra text 3 }{1: }| + {1:~ }|*15 + {2:-- }{5:match 2 of 3} | + ]]) + feed('<C-E><Esc>') + end) + + -- oldtest: Test_pum_user_kind_hlgroup() + it('custom kind_hlgroup override', function() + exec([[ + func CompleteFunc( findstart, base ) + if a:findstart + return 0 + endif + return { + \ 'words': [ + \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'variable', 'kind_hlgroup': 'KindVar', 'hl_group': 'StrikeFake' }, + \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'function', 'kind_hlgroup': 'KindFunc' }, + \ { 'word': 'ä½ å¥½', 'menu': 'extra text 3', 'kind': 'class', 'kind_hlgroup': 'KindClass' }, + \]} + endfunc + set completeopt=menu + set completefunc=CompleteFunc + + hi StrikeFake guifg=DarkRed + hi KindVar guifg=DarkYellow + hi KindFunc guifg=DarkBlue + hi KindClass guifg=DarkGreen + ]]) + + local attr_ids = screen:get_default_attr_ids() + attr_ids.kvs = { foreground = Screen.colors.DarkYellow, background = Screen.colors.Grey } + attr_ids.kfn = { foreground = Screen.colors.DarkBlue, background = Screen.colors.Plum1 } + attr_ids.kcn = { foreground = Screen.colors.DarkGreen, background = Screen.colors.Plum1 } + screen:set_default_attr_ids(attr_ids) + + feed('S<C-X><C-U>') + screen:expect([[ + aword1^ | + {ds:aword1 }{kvs:variable }{ds:extra text 1 }{1: }| + {n:aword2 }{kfn:function }{n:extra text 2 }{1: }| + {n:ä½ å¥½ }{kcn:class }{n:extra text 3 }{1: }| + {1:~ }|*15 + {2:-- }{5:match 1 of 3} | + ]]) + feed('<C-E><Esc>') + end) + + -- oldtest: Test_pum_completeitemalign() + it('completeitemalign option', function() + screen:try_resize(30, 15) + exec([[ + func Omni_test(findstart, base) + if a:findstart + return col(".") + endif + return { + \ 'words': [ + \ { 'word': 'foo', 'kind': 'S', 'menu': 'menu' }, + \ { 'word': 'bar', 'kind': 'T', 'menu': 'menu' }, + \ { 'word': 'ä½ å¥½', 'kind': 'C', 'menu': '䏿–‡' }, + \]} + endfunc + + func Omni_long(findstart, base) + if a:findstart + return col(".") + endif + return { + \ 'words': [ + \ { 'word': 'loooong_foo', 'kind': 'S', 'menu': 'menu' }, + \ { 'word': 'loooong_bar', 'kind': 'T', 'menu': 'menu' }, + \]} + endfunc + set omnifunc=Omni_test + ]]) + -- T1 + command('set cia=abbr,kind,menu') + feed('S<C-X><C-O>') + screen:expect([[ + foo^ | + {s:foo S menu }{1: }| + {n:bar T menu }{1: }| + {n:ä½ å¥½ C 䏿–‡ }{1: }| + {1:~ }|*10 + {2:-- }{5:match 1 of 3} | + ]]) + feed('<C-E><ESC>') + -- T2 + command('set cia=abbr,menu,kind') + feed('S<C-X><C-O>') + screen:expect([[ + foo^ | + {s:foo menu S }{1: }| + {n:bar menu T }{1: }| + {n:ä½ å¥½ 䏿–‡ C }{1: }| + {1:~ }|*10 + {2:-- }{5:match 1 of 3} | + ]]) + feed('<C-E><ESC>') + -- T3 + command('set cia=kind,abbr,menu') + feed('S<C-X><C-O>') + screen:expect([[ + foo^ | + {s:S foo menu }{1: }| + {n:T bar menu }{1: }| + {n:C ä½ å¥½ 䏿–‡ }{1: }| + {1:~ }|*10 + {2:-- }{5:match 1 of 3} | + ]]) + feed('<C-E><ESC>') + -- T4 + command('set cia=kind,menu,abbr') + feed('S<C-X><C-O>') + screen:expect([[ + foo^ | + {s:S menu foo }{1: }| + {n:T menu bar }{1: }| + {n:C 䏿–‡ ä½ å¥½ }{1: }| + {1:~ }|*10 + {2:-- }{5:match 1 of 3} | + ]]) + feed('<C-E><ESC>') + -- T5 + command('set cia=menu,abbr,kind') + feed('S<C-X><C-O>') + screen:expect([[ + foo^ | + {s:menu foo S }{1: }| + {n:menu bar T }{1: }| + {n:䏿–‡ ä½ å¥½ C }{1: }| + {1:~ }|*10 + {2:-- }{5:match 1 of 3} | + ]]) + feed('<C-E><ESC>') + -- T6 + command('set cia=menu,kind,abbr') + feed('S<C-X><C-O>') + screen:expect([[ + foo^ | + {s:menu S foo }{1: }| + {n:menu T bar }{1: }| + {n:䏿–‡ C ä½ å¥½ }{1: }| + {1:~ }|*10 + {2:-- }{5:match 1 of 3} | + ]]) + feed('<C-E><ESC>') + -- T7 + command('set cia&') + feed('S<C-X><C-O>') + screen:expect([[ + foo^ | + {s:foo S menu }{1: }| + {n:bar T menu }{1: }| + {n:ä½ å¥½ C 䏿–‡ }{1: }| + {1:~ }|*10 + {2:-- }{5:match 1 of 3} | + ]]) + feed('<C-E><ESC>') + + -- Test_pum_completeitemalign_07 + command('set cia=menu,kind,abbr columns=12 cmdheight=2 omnifunc=Omni_long') + feed('S<C-X><C-O>') + screen:expect([[ + loooong_foo^ | + {s:menu S loooo}| + {n:menu T loooo}| + {1:~ }|*10 + | + {2:--} | + ]]) + feed('<C-E><ESC>') + end) end end diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 4625ce8553..f1891b608e 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -255,6 +255,7 @@ end function Screen:set_default_attr_ids(attr_ids) self._default_attr_ids = attr_ids + self._attrs_overridden = true end function Screen:add_extra_attr_ids(extra_attr_ids) @@ -437,7 +438,7 @@ end --- @field mouse_enabled? boolean --- --- @field win_viewport? table<integer,table<string,integer>> ---- @field float_pos? {[1]:integer,[2]:integer} +--- @field float_pos? [integer,integer] --- @field hl_groups? table<string,integer> --- --- The following keys should be used to expect the state of various ext_ @@ -699,9 +700,9 @@ screen:redraw_debug() to show all intermediate screen states.]] end, expected) end -function Screen:expect_unchanged(intermediate, waittime_ms, ignore_attrs) +function Screen:expect_unchanged(intermediate, waittime_ms) -- Collect the current screen state. - local kwargs = self:get_snapshot(nil, ignore_attrs) + local kwargs = self:get_snapshot() if intermediate then kwargs.intermediate = true @@ -787,7 +788,9 @@ function Screen:_wait(check, flags) end local eof = run_session(self._session, flags.request_cb, notification_cb, nil, minimal_timeout) if not did_flush then - err = 'no flush received' + if eof then + err = 'no flush received' + end elseif not checked then err = check() if not err and flags.unchanged then @@ -800,6 +803,9 @@ function Screen:_wait(check, flags) did_minimal_timeout = true eof = run_session(self._session, flags.request_cb, notification_cb, nil, timeout - minimal_timeout) + if not did_flush then + err = 'no flush received' + end end local did_warn = false @@ -1536,13 +1542,14 @@ end -- Use snapshot_util({}) to generate a text-only (no attributes) test. -- -- @see Screen:redraw_debug() -function Screen:snapshot_util(attrs, ignore, request_cb) +function Screen:snapshot_util(request_cb) + -- TODO: simplify this later when existing tests have been updated self:sleep(250, request_cb) - self:print_snapshot(attrs, ignore) + self:print_snapshot() end -function Screen:redraw_debug(attrs, ignore, timeout) - self:print_snapshot(attrs, ignore) +function Screen:redraw_debug(timeout) + self:print_snapshot() local function notification_cb(method, args) assert(method == 'redraw') for _, update in ipairs(args) do @@ -1552,7 +1559,7 @@ function Screen:redraw_debug(attrs, ignore, timeout) end end self:_redraw(args) - self:print_snapshot(attrs, ignore) + self:print_snapshot() return true end if timeout == nil then @@ -1596,23 +1603,12 @@ end -- Returns the current screen state in the form of a screen:expect() -- keyword-args map. -function Screen:get_snapshot(attrs, ignore) - if ignore == nil then - ignore = self._default_attr_ignore - end +function Screen:get_snapshot() local attr_state = { ids = {}, - ignore = ignore, mutable = true, -- allow _row_repr to add missing highlights } - if attrs == nil then - attrs = self._default_attr_ids - elseif isempty(attrs) then - attrs = nil - attr_state.ids = nil - else - attr_state.modified = true - end + local attrs = self._default_attr_ids if attrs ~= nil then for i, a in pairs(attrs) do @@ -1708,9 +1704,10 @@ local function fmt_ext_state(name, state) end end -function Screen:_print_snapshot(attrs, ignore) - local kwargs, ext_state, attr_state = self:get_snapshot(attrs, ignore) +function Screen:_print_snapshot() + local kwargs, ext_state, attr_state = self:get_snapshot() local attrstr = '' + local modify_attrs = not self._attrs_overridden if attr_state.modified then local attrstrs = {} for i, a in pairs(attr_state.ids) do @@ -1721,16 +1718,20 @@ function Screen:_print_snapshot(attrs, ignore) dict = '{ ' .. self:_pprint_attrs(a) .. ' }' end local keyval = (type(i) == 'number') and '[' .. tostring(i) .. ']' or i - table.insert(attrstrs, ' ' .. keyval .. ' = ' .. dict .. ',') + if not (type(i) == 'number' and modify_attrs and i <= 30) then + table.insert(attrstrs, ' ' .. keyval .. ' = ' .. dict .. ',') + end + if modify_attrs then + self._default_attr_ids = attr_state.ids + end end - attrstr = (',\n attr_ids = {\n ' .. table.concat(attrstrs, '\n ') .. '\n },') - elseif isempty(attrs) then - attrstr = ',\n attr_ids = {},' + local fn_name = modify_attrs and 'add_extra_attr_ids' or 'set_default_attr_ids' + attrstr = ('screen:' .. fn_name .. ' {\n' .. table.concat(attrstrs, '\n') .. '\n}\n\n') end - local result = ('screen:expect({\n grid = [[\n %s\n ]]%s'):format( - kwargs.grid:gsub('\n', '\n '), - attrstr + local result = ('%sscreen:expect({\n grid = [[\n %s\n ]]'):format( + attrstr, + kwargs.grid:gsub('\n', '\n ') ) for _, k in ipairs(ext_keys) do if ext_state[k] ~= nil and not (k == 'win_viewport' and not self.options.ext_multigrid) then @@ -1742,8 +1743,8 @@ function Screen:_print_snapshot(attrs, ignore) return result end -function Screen:print_snapshot(attrs, ignore) - print('\n' .. self:_print_snapshot(attrs, ignore) .. '\n') +function Screen:print_snapshot() + print('\n' .. self:_print_snapshot() .. '\n') io.stdout:flush() end diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua index 54580bf47c..85a653df36 100644 --- a/test/functional/ui/screen_basic_spec.lua +++ b/test/functional/ui/screen_basic_spec.lua @@ -4,6 +4,7 @@ local Screen = require('test.functional.ui.screen') local spawn, set_session, clear = n.spawn, n.set_session, n.clear local feed, command = n.feed, n.command +local exec = n.exec local insert = n.insert local eq = t.eq local fn, api = n.fn, n.api @@ -819,3 +820,39 @@ it("showcmd doesn't cause empty grid_line with redrawdebug=compositor #22593", f ]], } end) + +it("scrolling in narrow window doesn't draw over separator #29033", function() + clear() + local screen = Screen.new(60, 8) + screen:attach() + feed('100Oa<Esc>gg') + exec([[ + set number nowrap + vsplit + set scrollbind + wincmd l + set scrollbind + wincmd | + ]]) + screen:expect([[ + {8: }│{8: 1 }^a | + {8: }│{8: 2 }a | + {8: }│{8: 3 }a | + {8: }│{8: 4 }a | + {8: }│{8: 5 }a | + {8: }│{8: 6 }a | + {2:< }{3:[No Name] [+] }| + | + ]]) + feed('<C-F>') + screen:expect([[ + {8: }│{8: 5 }^a | + {8: }│{8: 6 }a | + {8: }│{8: 7 }a | + {8: }│{8: 8 }a | + {8: }│{8: 9 }a | + {8: }│{8: 10 }a | + {2:< }{3:[No Name] [+] }| + | + ]]) +end) diff --git a/test/functional/ui/scrollbind_spec.lua b/test/functional/ui/scrollbind_spec.lua new file mode 100644 index 0000000000..9e70b25efa --- /dev/null +++ b/test/functional/ui/scrollbind_spec.lua @@ -0,0 +1,442 @@ +local t = require('test.testutil') +local n = require('test.functional.testnvim')() +local clear = n.clear +local Screen = require('test.functional.ui.screen') + +before_each(clear) + +describe('Scrollbind', function() + local screen --- @type test.functional.ui.screen + + before_each(function() + screen = Screen.new(40, 12) + screen:attach() + end) + + it('works with one buffer with virtual lines', function() + n.exec_lua(function() + local lines = {} --- @type string[] + + for i = 1, 20 do + lines[i] = tostring(i * 2 - 1) + end + + local ns = vim.api.nvim_create_namespace('test') + + vim.api.nvim_buf_set_lines(0, 0, -1, false, lines) + vim.bo.buftype = 'nofile' + + for i in ipairs(lines) do + vim.api.nvim_buf_set_extmark(0, ns, i - 1, 0, { + virt_lines = { { { tostring(2 * i) .. ' v' } } }, + }) + end + + vim.wo.scrollbind = true + vim.cmd.vsplit() + vim.wo.scrollbind = true + end) + + n.feed('<C-d>') + + t.eq(5, n.api.nvim_get_option_value('scroll', {})) + + screen:expect({ + grid = [[ + 6 v │6 v | + 7 │7 | + 8 v │8 v | + 9 │9 | + 10 v │10 v | + ^11 │11 | + 12 v │12 v | + 13 │13 | + 14 v │14 v | + 15 │15 | + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('<C-u>') + + local line1_grid = [[ + ^1 │1 | + 2 v │2 v | + 3 │3 | + 4 v │4 v | + 5 │5 | + 6 v │6 v | + 7 │7 | + 8 v │8 v | + 9 │9 | + 10 v │10 v | + {3:[Scratch] }{2:[Scratch] }| + | + ]] + + screen:expect({ grid = line1_grid }) + + n.api.nvim_set_option_value('scroll', 6, {}) + + n.feed('<C-d>') + + screen:expect({ + grid = [[ + 7 │7 | + 8 v │8 v | + 9 │9 | + 10 v │10 v | + 11 │11 | + 12 v │12 v | + ^13 │13 | + 14 v │14 v | + 15 │15 | + 16 v │16 v | + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('<C-u>') + + screen:expect({ grid = line1_grid }) + end) + + it('works with two buffers with virtual lines on one side', function() + n.exec_lua(function() + local lines = {} --- @type string[] + + for i = 1, 20 do + lines[i] = tostring(i) + end + + local ns = vim.api.nvim_create_namespace('test') + + vim.api.nvim_buf_set_lines(0, 0, -1, false, lines) + vim.bo.buftype = 'nofile' + + vim.wo.scrollbind = true + vim.cmd.vnew() + + lines = {} --- @type string[] + + for i = 1, 20 do + lines[i] = tostring(i + (i > 3 and 4 or 0)) + end + vim.api.nvim_buf_set_lines(0, 0, -1, false, lines) + vim.bo.buftype = 'nofile' + + vim.api.nvim_buf_set_extmark(0, ns, 2, 0, { + virt_lines = { + { { '4 v' } }, + { { '5 v' } }, + { { '6 v' } }, + { { '7 v' } }, + }, + }) + + vim.wo.scrollbind = true + end) + + n.feed('<C-d>') + + t.eq(5, n.api.nvim_get_option_value('scroll', {})) + + screen:expect({ + grid = [[ + 6 v │6 | + 7 v │7 | + 8 │8 | + 9 │9 | + ^10 │10 | + 11 │11 | + 12 │12 | + 13 │13 | + 14 │14 | + 15 │15 | + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('<C-u>') + + local line1_grid = [[ + ^1 │1 | + 2 │2 | + 3 │3 | + 4 v │4 | + 5 v │5 | + 6 v │6 | + 7 v │7 | + 8 │8 | + 9 │9 | + 10 │10 | + {3:[Scratch] }{2:[Scratch] }| + | + ]] + + screen:expect({ grid = line1_grid }) + + n.api.nvim_set_option_value('scroll', 6, {}) + + n.feed('<C-d>') + + screen:expect({ + grid = [[ + 7 v │7 | + 8 │8 | + 9 │9 | + 10 │10 | + ^11 │11 | + 12 │12 | + 13 │13 | + 14 │14 | + 15 │15 | + 16 │16 | + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('<C-u>') + + screen:expect({ grid = line1_grid }) + + -- Note: not the same as n.feed('4<C-e>') + n.feed('<C-e>') + n.feed('<C-e>') + n.feed('<C-e>') + n.feed('<C-e>') + + screen:expect({ + grid = [[ + 5 v │5 | + 6 v │6 | + 7 v │7 | + ^8 │8 | + 9 │9 | + 10 │10 | + 11 │11 | + 12 │12 | + 13 │13 | + 14 │14 | + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('<C-e>') + + screen:expect({ + grid = [[ + 6 v │6 | + 7 v │7 | + ^8 │8 | + 9 │9 | + 10 │10 | + 11 │11 | + 12 │12 | + 13 │13 | + 14 │14 | + 15 │15 | + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('<C-y>') + n.feed('<C-y>') + + screen:expect({ + grid = [[ + 4 v │4 | + 5 v │5 | + 6 v │6 | + 7 v │7 | + ^8 │8 | + 9 │9 | + 10 │10 | + 11 │11 | + 12 │12 | + 13 │13 | + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + end) + + it('works with buffers of different lengths', function() + n.exec_lua(function() + vim.api.nvim_buf_set_lines(0, 0, -1, false, { '1', '2', '3' }) + vim.bo.buftype = 'nofile' + + vim.wo.scrollbind = true + vim.cmd.vnew() + + local lines = {} --- @type string[] + + for i = 1, 50 do + lines[i] = tostring(i) + end + + vim.api.nvim_buf_set_lines(0, 0, -1, false, lines) + vim.bo.buftype = 'nofile' + vim.wo.scrollbind = true + end) + + n.feed('10<C-e>') + + screen:expect({ + grid = [[ + ^11 │3 | + 12 │{1:~ }| + 13 │{1:~ }| + 14 │{1:~ }| + 15 │{1:~ }| + 16 │{1:~ }| + 17 │{1:~ }| + 18 │{1:~ }| + 19 │{1:~ }| + 20 │{1:~ }| + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('<C-y>') + + screen:expect({ + grid = [[ + 10 │3 | + ^11 │{1:~ }| + 12 │{1:~ }| + 13 │{1:~ }| + 14 │{1:~ }| + 15 │{1:~ }| + 16 │{1:~ }| + 17 │{1:~ }| + 18 │{1:~ }| + 19 │{1:~ }| + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + end) + + it('works with buffers of different lengths and virtual lines', function() + n.exec_lua(function() + vim.api.nvim_buf_set_lines(0, 0, -1, false, { '1', '5', '6' }) + + local ns = vim.api.nvim_create_namespace('test') + vim.api.nvim_buf_set_extmark(0, ns, 0, 0, { + virt_lines = { + { { '2 v' } }, + { { '3 v' } }, + { { '4 v' } }, + }, + }) + + vim.bo.buftype = 'nofile' + + vim.wo.scrollbind = true + vim.cmd.vnew() + + local lines = {} --- @type string[] + + for i = 1, 50 do + lines[i] = tostring(i) + end + + vim.api.nvim_buf_set_lines(0, 0, -1, false, lines) + vim.bo.buftype = 'nofile' + vim.wo.scrollbind = true + end) + + n.feed('<C-e>') + n.feed('<C-e>') + screen:expect({ + grid = [[ + ^3 │3 v | + 4 │4 v | + 5 │5 | + 6 │6 | + 7 │{1:~ }| + 8 │{1:~ }| + 9 │{1:~ }| + 10 │{1:~ }| + 11 │{1:~ }| + 12 │{1:~ }| + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('8<C-e>') + + screen:expect({ + grid = [[ + ^11 │6 | + 12 │{1:~ }| + 13 │{1:~ }| + 14 │{1:~ }| + 15 │{1:~ }| + 16 │{1:~ }| + 17 │{1:~ }| + 18 │{1:~ }| + 19 │{1:~ }| + 20 │{1:~ }| + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('<C-y>') + n.feed('<C-y>') + n.feed('<C-y>') + n.feed('<C-y>') + n.feed('<C-y>') + + t.eq(n.exec_lua [[return vim.fn.line('w0', 1001)]], 6) + t.eq(n.exec_lua [[return vim.fn.line('w0', 1000)]], 3) + + screen:expect({ + grid = [[ + 6 │6 | + 7 │{1:~ }| + 8 │{1:~ }| + 9 │{1:~ }| + 10 │{1:~ }| + ^11 │{1:~ }| + 12 │{1:~ }| + 13 │{1:~ }| + 14 │{1:~ }| + 15 │{1:~ }| + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + + n.feed('<C-y>') + n.feed('<C-y>') + n.feed('<C-y>') + + screen:expect({ + grid = [[ + 3 │3 v | + 4 │4 v | + 5 │5 | + 6 │6 | + 7 │{1:~ }| + 8 │{1:~ }| + 9 │{1:~ }| + 10 │{1:~ }| + ^11 │{1:~ }| + 12 │{1:~ }| + {3:[Scratch] }{2:[Scratch] }| + | + ]], + }) + end) +end) diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua index 8bdf528412..eab265cbb1 100644 --- a/test/functional/ui/searchhl_spec.lua +++ b/test/functional/ui/searchhl_spec.lua @@ -197,7 +197,8 @@ describe('search highlighting', function() } end) - it('works for multiline match', function() + -- oldtest: Test_hlsearch_cursearch() + it('works for multiline match, no duplicate highlight', function() command([[call setline(1, ['one', 'foo', 'bar', 'baz', 'foo the foo and foo', 'bar'])]]) feed('gg/foo<CR>') screen:expect([[ @@ -281,6 +282,28 @@ describe('search highlighting', function() {2:hij}kl | /efg\nhij | ]]) + + -- check clearing CurSearch when using it for another match + feed('G?^abcd<CR>Y') + screen:expect([[ + --- | + {1:abcd}efg | + hijkl | + --- | + {2:^abcd}efg | + hijkl | + ?^abcd | + ]]) + feed('kkP') + screen:expect([[ + --- | + {1:abcd}efg | + {2:^abcd}efg | + hijkl | + --- | + {1:abcd}efg | + ?^abcd | + ]]) end) end) @@ -345,12 +368,19 @@ describe('search highlighting', function() bar baz foo bar foo baz]]) feed('/foo') + screen:set_default_attr_ids({ + [1] = { bold = true, foreground = Screen.colors.Blue }, + [2] = { background = Screen.colors.Yellow }, -- Search + [3] = { reverse = true }, + [4] = { bold = true, reverse = true }, + [5] = { foreground = Screen.colors.White, background = Screen.colors.DarkGreen }, + }) screen:expect([[ {3:foo} bar baz │{MATCH:%d+}: {2:foo}{MATCH:%s+}| bar baz {2:foo} │{MATCH:%d+}: {2:foo}{MATCH:%s+}| bar {2:foo} baz │{MATCH:%d+}: {2:foo}{MATCH:%s+}| {1:~ }│{MATCH:.*}|*2 - {5:[No Name] [+] }{3:term }| + {4:[No Name] [+] }{5:term }| /foo^ | ]]) end) diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua index b353b3738a..30da79af47 100644 --- a/test/functional/ui/sign_spec.lua +++ b/test/functional/ui/sign_spec.lua @@ -4,6 +4,7 @@ local Screen = require('test.functional.ui.screen') local api, clear, eq = n.api, n.clear, t.eq local eval, exec, feed = n.eval, n.exec, n.feed +local exec_lua = n.exec_lua describe('Signs', function() local screen @@ -577,4 +578,45 @@ describe('Signs', function() ]]) eq({}, eval('sign_getdefined()')) end) + + it('no crash when unplacing signs beyond end of buffer', function() + exec([[ + sign define S1 text=S1 + sign define S2 text=S2 + sign place 1 line=8 name=S1 + sign place 2 line=9 name=S2 + ]]) + -- Now placed at end of buffer + local s1 = { + grid = [[ + S2^ | + {0:~ }|*12 + | + ]], + } + screen:expect(s1) + -- Signcolumn tracking used to not count signs placed beyond end of buffer here + exec('set signcolumn=auto:9') + screen:expect({ + grid = [[ + S2S1^ | + {0:~ }|*12 + | + ]], + }) + -- Unplacing the sign does not crash by decrementing tracked signs below zero + exec('sign unplace 1') + screen:expect(s1) + end) + + it('signcolumn width is set immediately after splitting window #30547', function() + local infos = exec_lua([[ + vim.o.number = true + vim.o.signcolumn = 'yes' + vim.cmd.wincmd('v') + return vim.fn.getwininfo() + ]]) + eq(6, infos[1].textoff) + eq(6, infos[2].textoff) + end) end) diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua index faf94bccbe..b4d4c94a5e 100644 --- a/test/functional/ui/statuscolumn_spec.lua +++ b/test/functional/ui/statuscolumn_spec.lua @@ -91,49 +91,87 @@ describe('statuscolumn', function() {8:2 }aaaaa | | ]]) + -- Doesn't crash when clicking inside padded area without click_defs + command('set numberwidth=10') + api.nvim_input_mouse('left', 'press', '', 0, 0, 5) + assert_alive() end) it("works with 'number' and 'relativenumber'", function() - command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]]) - screen:expect([[ - {8:4 │}aaaaa | - {8:5 │}aaaaa | - {8:6 │}aaaaa | - {8:7 │}aaaaa | - {8:8 │}^aaaaa | - {8:9 │}aaaaa | - {8:10│}aaaaa | - {8:11│}aaaaa | - {8:12│}aaaaa | - {8:13│}aaaaa | - {8:14│}aaaaa | - {8:15│}aaaaa | - {8:16│}aaaaa | - | - ]]) - command([[set stc=%l%=%{&rnu?'\ ':''}%r│]]) + screen:expect([[ + {8: 4 }aaaaa | + {8: 5 }aaaaa | + {8: 6 }aaaaa | + {8: 7 }aaaaa | + {8: 8 }^aaaaa | + {8: 9 }aaaaa | + {8:10 }aaaaa | + {8:11 }aaaaa | + {8:12 }aaaaa | + {8:13 }aaaaa | + {8:14 }aaaaa | + {8:15 }aaaaa | + {8:16 }aaaaa | + | + ]]) + command([[set stc=%l\ ]]) screen:expect_unchanged() - command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]]) command('set relativenumber') screen:expect([[ - {8:4 4│}aaaaa | - {8:5 3│}aaaaa | - {8:6 2│}aaaaa | - {8:7 1│}aaaaa | - {8:8 0│}^aaaaa | - {8:9 1│}aaaaa | - {8:10 2│}aaaaa | - {8:11 3│}aaaaa | - {8:12 4│}aaaaa | - {8:13 5│}aaaaa | - {8:14 6│}aaaaa | - {8:15 7│}aaaaa | - {8:16 8│}aaaaa | - | - ]]) - command([[set stc=%l%=%{&rnu?'\ ':''}%r│]]) + {8: 4 }aaaaa | + {8: 3 }aaaaa | + {8: 2 }aaaaa | + {8: 1 }aaaaa | + {8:8 }^aaaaa | + {8: 1 }aaaaa | + {8: 2 }aaaaa | + {8: 3 }aaaaa | + {8: 4 }aaaaa | + {8: 5 }aaaaa | + {8: 6 }aaaaa | + {8: 7 }aaaaa | + {8: 8 }aaaaa | + | + ]]) + command('set stc=') + screen:expect_unchanged() + command([[set nonu stc=%l\ ]]) + screen:expect([[ + {8: 4 }aaaaa | + {8: 3 }aaaaa | + {8: 2 }aaaaa | + {8: 1 }aaaaa | + {8: 0 }^aaaaa | + {8: 1 }aaaaa | + {8: 2 }aaaaa | + {8: 3 }aaaaa | + {8: 4 }aaaaa | + {8: 5 }aaaaa | + {8: 6 }aaaaa | + {8: 7 }aaaaa | + {8: 8 }aaaaa | + | + ]]) + command('set nuw=1 stc=') screen:expect_unchanged() - command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]]) + -- Correct alignment with items before and after number column + command([[set nu stc=foo\ %l\ bar]]) + screen:expect([[ + {8:foo 4 bar}aaaaa | + {8:foo 3 bar}aaaaa | + {8:foo 2 bar}aaaaa | + {8:foo 1 bar}aaaaa | + {8:foo 8 bar}^aaaaa | + {8:foo 1 bar}aaaaa | + {8:foo 2 bar}aaaaa | + {8:foo 3 bar}aaaaa | + {8:foo 4 bar}aaaaa | + {8:foo 5 bar}aaaaa | + {8:foo 6 bar}aaaaa | + {8:foo 7 bar}aaaaa | + {8:foo 8 bar}aaaaa | + | + ]]) end) it("works with highlighted 'statuscolumn'", function() @@ -160,36 +198,36 @@ describe('statuscolumn', function() ]]) command('set relativenumber') screen:expect([[ - {1:4 }{8: 4│}aaaaa | - {1:5 3}{8:│}aaaaa | - {1:6 }{8: 2│}aaaaa | - {1:7 1}{8:│}aaaaa | - {1:8 }{8: 0│}^aaaaa | - {1:9 1}{8:│}aaaaa | - {1:10}{8: 2│}aaaaa | - {1:11 3}{8:│}aaaaa | - {1:12}{8: 4│}aaaaa | - {1:13 5}{8:│}aaaaa | - {1:14}{8: 6│}aaaaa | - {1:15 7}{8:│}aaaaa | - {1:16}{8: 8│}aaaaa | + {1:4 }{8: 4│}aaaaa | + {1:5 3}{8:│}aaaaa | + {1:6 }{8: 2│}aaaaa | + {1:7 1}{8:│}aaaaa | + {1:8 }{8: 0│}^aaaaa | + {1:9 1}{8:│}aaaaa | + {1:10 }{8: 2│}aaaaa | + {1:11 3}{8:│}aaaaa | + {1:12 }{8: 4│}aaaaa | + {1:13 5}{8:│}aaaaa | + {1:14 }{8: 6│}aaaaa | + {1:15 7}{8:│}aaaaa | + {1:16 }{8: 8│}aaaaa | | ]]) command('set nonumber') screen:expect([[ - {8:4│}aaaaa | - {1:3}{8:│}aaaaa | - {8:2│}aaaaa | - {1:1}{8:│}aaaaa | - {8:0│}^aaaaa | - {1:1}{8:│}aaaaa | - {8:2│}aaaaa | - {1:3}{8:│}aaaaa | - {8:4│}aaaaa | - {1:5}{8:│}aaaaa | - {8:6│}aaaaa | - {1:7}{8:│}aaaaa | - {8:8│}aaaaa | + {1: }{8:4│}aaaaa | + {1: 3}{8:│}aaaaa | + {1: }{8:2│}aaaaa | + {1: 1}{8:│}aaaaa | + {1: }{8:0│}^aaaaa | + {1: 1}{8:│}aaaaa | + {1: }{8:2│}aaaaa | + {1: 3}{8:│}aaaaa | + {1: }{8:4│}aaaaa | + {1: 5}{8:│}aaaaa | + {1: }{8:6│}aaaaa | + {1: 7}{8:│}aaaaa | + {1: }{8:8│}aaaaa | | ]]) end) @@ -305,36 +343,36 @@ describe('statuscolumn', function() -- v:relnum is the same value on wrapped lines command([[set stc=%C%=\ %{v:relnum}│%s\ ]]) screen:expect([[ - {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 4│}{2: }{1: }aaaaaa | - {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 3│}{2: }{1: }aaaaaa | - {2: }{1: 2│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 2│}{2: }{1: }aaaaaa | - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 1│}{2: }{1: }aaaaaa | - {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 1│}{2: }{1: }aaaaaa | - {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 2│}{2: }{1: }aaaaaa | + {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: 4│}{2: }{1: }aaaaaaa | + {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: 3│}{2: }{1: }aaaaaaa | + {2: }{1: 2│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: 2│}{2: }{1: }aaaaaaa | + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: 1│}{2: }{1: }aaaaaaa | + {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: 1│}{2: }{1: }aaaaaaa | + {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: 2│}{2: }{1: }aaaaaaa | | ]]) command([[set stc=%C%=\ %{v:virtnum?'':v:relnum}│%s\ ]]) screen:expect([[ - {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | - {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | - {2: }{1: 2│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | - {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | - {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | + {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaa | + {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaa | + {2: }{1: 2│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaa | + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaa | + {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaa | + {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaa | | ]]) -- Up to 9 signs in a line @@ -347,75 +385,75 @@ describe('statuscolumn', function() command('sign place 10 line=6 name=piet2 buffer=1') command('sign place 11 line=6 name=piet1 buffer=1') screen:expect([[ - {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 2│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | - {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaa}| - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | + {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 2│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa | + {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaa}| + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa | | ]]) -- Also test fold and sign column when 'cpoptions' includes "n" command('set cpoptions+=n') feed('Hgjg0') screen:expect([[ - {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: }{5:^aaaaaaaaaaaaaaaaaaaa }| - {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 2│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaa | - {2:+}{1: 4│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaaa}| - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaa | + {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2: }{5:^aaaaaaaaaaaaaaaaaaaaa }| + {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 2│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaaa | + {2:+}{1: 4│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaa}| + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaaa | | ]]) command('set breakindent') command('sign unplace 2') feed('J2gjg0') screen:expect([[ - {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: } {5:aaaaaaaaaaaaaaaaaaaa aaaaaaaaa}| - {2: } {5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: } {5:^aaaaaaaaaaa }| - {2: }{1: 1│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: } aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: } aaaaaaaaaaaaaaaaaaaa | - {2:+}{1: 3│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaaa}| - {2: }{1: 4│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: } aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 5│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: } aaaaaaaaaaaaaaaaaaaa | + {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2: } {5:aaaaaaaaaaaaaaaaaaaaa aaaaaaa}| + {2: } {5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2: } {5:^aaaaaaaaaaaaaa }| + {2: }{1: 1│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: } aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: } aaaaaaaaaaaaaaaaaaaaa | + {2:+}{1: 3│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaa}| + {2: }{1: 4│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: } aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 5│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: } aaaaaaaaaaaaaaaaaaaaa | | ]]) command('set nobreakindent') feed('$g0') screen:expect([[ - {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: }{5:aaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaa}| + {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2: }{5:aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaa}| {2: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: }{5:^aaa }| - {2: }{1: 1│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaa | - {2:+}{1: 3│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaaa}| - {2: }{1: 4│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaa | - {2: }{1: 5│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaa | + {2: }{5:^aaaa }| + {2: }{1: 1│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaaa | + {2:+}{1: 3│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaa}| + {2: }{1: 4│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaaa | + {2: }{1: 5│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }aaaaaaaaaaaaaaaaaaaaa | | ]]) command('silent undo') @@ -427,7 +465,23 @@ describe('statuscolumn', function() virt_lines_above = true, virt_lines = {{{"virt_line above", ""}}} }) vim.api.nvim_buf_set_extmark(0, ns, 4, 0, { virt_lines = {{{"virt_line", ""}}} }) ]]) - command('set foldcolumn=0 signcolumn=no') + command('set foldcolumn=0 signcolumn=number stc=%l') + screen:expect([[ + {1:>>}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {1: 5}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {1: }virt_line | + {1: }virt_line above | + {1:>>}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {1: 7}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {4: 8}{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {1: 9}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {1:10}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {1:11}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {1:12}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {1:13}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {1:14}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + | + ]]) command( [[set stc=%{v:virtnum<0?'virtual':(!v:virtnum?'buffer':'wrapped')}%=%{'\ '.v:virtnum.'\ '.v:lnum}]] ) @@ -533,8 +587,8 @@ describe('statuscolumn', function() command([[set stc=%6s\ %l]]) exec_lua('vim.api.nvim_buf_set_extmark(0, ns, 7, 0, {sign_text = "ð’€€"})') screen:expect([[ - {8: ð’€€ 8 }^aaaaa | - {8: }{7: }{8: 9 }aaaaa | + {8: ð’€€ 8}^aaaaa | + {8: }{7: }{8: 9}aaaaa | | ]]) end) @@ -598,9 +652,6 @@ describe('statuscolumn', function() -- Check that statusline click doesn't register as statuscolumn click api.nvim_input_mouse('right', 'press', '', 0, 12, 0) eq('', eval('g:testvar')) - -- Check that cmdline click doesn't register as statuscolumn click - api.nvim_input_mouse('right', 'press', '', 0, 13, 0) - eq('', eval('g:testvar')) end) it('clicks and highlights work with control characters', function() @@ -644,26 +695,26 @@ describe('statuscolumn', function() -- clicking an item does not drag mouse api.nvim_input_mouse('left', 'press', '', 0, 0, 0) screen:expect([[ - {0:8 }^aaaaa | + {0: 8}^aaaaa | {1: Echo } | ]]) api.nvim_input_mouse('left', 'press', '', 0, 1, 5) api.nvim_input_mouse('left', 'release', '', 0, 1, 5) screen:expect([[ - {0:8 }^aaaaa | + {0: 8}^aaaaa | 0 1 l 8 | ]]) command('echo') -- clicking outside to close the menu does not drag mouse api.nvim_input_mouse('left', 'press', '', 0, 0, 0) screen:expect([[ - {0:8 }^aaaaa | + {0: 8}^aaaaa | {1: Echo } | ]]) api.nvim_input_mouse('left', 'press', '', 0, 0, 10) api.nvim_input_mouse('left', 'release', '', 0, 0, 10) screen:expect([[ - {0:8 }^aaaaa | + {0: 8}^aaaaa | | ]]) end) @@ -749,9 +800,9 @@ describe('statuscolumn', function() it('works with cmdwin', function() feed(':set stc=%l<CR>q:k$') screen:expect([[ - {8:7 }aaaaa | - {8:8 }aaaaa | - {8:9 }aaaaa | + {8: 7}aaaaa | + {8: 8}aaaaa | + {8: 9}aaaaa | {8:10}aaaaa | {2:[No Name] [+] }| {1::}{8:1}set stc=%^l | @@ -899,16 +950,16 @@ describe('statuscolumn', function() command([[set spell stc=%l\ ]]) command('call setline(8, "This is a line that contains á¶ multibyte character.")') screen:expect([[ - {8:8 }^This is a line that contains {31:á¶}| + {8: 8 }^This is a line that contains {31:á¶}| {8: } {31:multibyte} character. | - {8:9 }{31:aaaaa} | + {8: 9 }{31:aaaaa} | | ]]) end) it('line increase properly redraws buffer text with relativenumber #27709', function() screen:try_resize(33, 4) - command([[set rnu nuw=3 stc=%l\ ]]) + command([[set rnu nuw=3 stc=%{v:lnum}\ ]]) command('call setline(1, range(1, 99))') feed('Gyyp') screen:expect([[ diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua index 3087a0cde1..937e709d66 100644 --- a/test/functional/ui/statusline_spec.lua +++ b/test/functional/ui/statusline_spec.lua @@ -63,6 +63,22 @@ for _, model in ipairs(mousemodels) do eq('0 3 r', eval('g:testvar')) api.nvim_input_mouse('right', 'press', '', 0, 6, 28) eq('0 4 r', eval('g:testvar')) + api.nvim_input_mouse('x1', 'press', '', 0, 6, 17) + eq('0 1 x1', eval('g:testvar')) + api.nvim_input_mouse('x1', 'press', '', 0, 6, 17) + eq('0 2 x1', eval('g:testvar')) + api.nvim_input_mouse('x1', 'press', '', 0, 6, 17) + eq('0 3 x1', eval('g:testvar')) + api.nvim_input_mouse('x1', 'press', '', 0, 6, 17) + eq('0 4 x1', eval('g:testvar')) + api.nvim_input_mouse('x2', 'press', '', 0, 6, 28) + eq('0 1 x2', eval('g:testvar')) + api.nvim_input_mouse('x2', 'press', '', 0, 6, 28) + eq('0 2 x2', eval('g:testvar')) + api.nvim_input_mouse('x2', 'press', '', 0, 6, 28) + eq('0 3 x2', eval('g:testvar')) + api.nvim_input_mouse('x2', 'press', '', 0, 6, 28) + eq('0 4 x2', eval('g:testvar')) end) it('works with control characters and highlight', function() diff --git a/test/functional/ui/title_spec.lua b/test/functional/ui/title_spec.lua index e86fdbe5a3..3189232957 100644 --- a/test/functional/ui/title_spec.lua +++ b/test/functional/ui/title_spec.lua @@ -22,7 +22,7 @@ describe('title', function() end) it('has correct default title with unnamed file', function() - local expected = '[No Name] - NVIM' + local expected = '[No Name] - Nvim' command('set title') screen:expect(function() eq(expected, screen.title) @@ -30,7 +30,7 @@ describe('title', function() end) it('has correct default title with named file', function() - local expected = (is_os('win') and 'myfile (C:\\mydir) - NVIM' or 'myfile (/mydir) - NVIM') + local expected = (is_os('win') and 'myfile (C:\\mydir) - Nvim' or 'myfile (/mydir) - Nvim') command('set title') command(is_os('win') and 'file C:\\mydir\\myfile' or 'file /mydir/myfile') screen:expect(function() @@ -41,7 +41,7 @@ describe('title', function() describe('is not changed by', function() local file1 = is_os('win') and 'C:\\mydir\\myfile1' or '/mydir/myfile1' local file2 = is_os('win') and 'C:\\mydir\\myfile2' or '/mydir/myfile2' - local expected = (is_os('win') and 'myfile1 (C:\\mydir) - NVIM' or 'myfile1 (/mydir) - NVIM') + local expected = (is_os('win') and 'myfile1 (C:\\mydir) - Nvim' or 'myfile1 (/mydir) - Nvim') local buf2 before_each(function() @@ -82,11 +82,11 @@ describe('title', function() end) end) - it('a Lua callback calling nvim_buf_call in a hidden buffer', function() + it('a Lua callback calling vim._with in a hidden buffer', function() exec_lua(string.format( [[ vim.schedule(function() - vim.api.nvim_buf_call(%d, function() end) + vim._with({buf = %d}, function() end) end) ]], buf2 diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua index 0feec6bd03..4d01b7a779 100644 --- a/test/functional/ui/wildmode_spec.lua +++ b/test/functional/ui/wildmode_spec.lua @@ -16,30 +16,24 @@ describe("'wildmenu'", function() before_each(function() clear() screen = Screen.new(25, 5) - screen:set_default_attr_ids { - [1] = { foreground = Screen.colors.Blue, bold = true }, - [2] = { reverse = true }, - [3] = { bold = true, reverse = true }, - [5] = { bold = true }, - [31] = { foreground = Screen.colors.Grey0, background = Screen.colors.Yellow }, + screen:add_extra_attr_ids { + [100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black }, } screen:attach() end) -- oldtest: Test_wildmenu_screendump() it('works', function() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { foreground = Screen.colors.Black, background = Screen.colors.Yellow }, -- WildMenu - [2] = { bold = true, reverse = true }, -- StatusLine - }) + screen:add_extra_attr_ids { + [100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black }, + } -- Test simple wildmenu feed(':sign <Tab>') screen:expect { grid = [[ | - {0:~ }|*2 - {1:define}{2: jump list > }| + {1:~ }|*2 + {100:define}{3: jump list > }| :sign define^ | ]], } @@ -48,8 +42,8 @@ describe("'wildmenu'", function() screen:expect { grid = [[ | - {0:~ }|*2 - {2:define }{1:jump}{2: list > }| + {1:~ }|*2 + {3:define }{100:jump}{3: list > }| :sign jump^ | ]], } @@ -58,8 +52,8 @@ describe("'wildmenu'", function() screen:expect { grid = [[ | - {0:~ }|*2 - {2:define jump }{1:list}{2: > }| + {1:~ }|*2 + {3:define jump }{100:list}{3: > }| :sign list^ | ]], } @@ -69,8 +63,8 @@ describe("'wildmenu'", function() screen:expect { grid = [[ | - {0:~ }|*2 - {2:define jump list > }| + {1:~ }|*2 + {3:define jump list > }| :sign ^ | ]], } @@ -80,7 +74,7 @@ describe("'wildmenu'", function() screen:expect { grid = [[ | - {0:~ }|*3 + {1:~ }|*3 :sign ^ | ]], } @@ -92,8 +86,8 @@ describe("'wildmenu'", function() screen:expect { grid = [[ | - {0:~ }|*2 - {1:define}{2: jump list > }| + {1:~ }|*2 + {100:define}{3: jump list > }| :sign define^ | ]], } @@ -104,7 +98,7 @@ describe("'wildmenu'", function() screen:expect { grid = [[ ^ | - {0:~ }|*3 + {1:~ }|*3 | ]], } @@ -115,7 +109,7 @@ describe("'wildmenu'", function() screen:expect([[ | {1:~ }|*2 - {31:define}{3: jump list > }| + {100:define}{3: jump list > }| :sign define^ | ]]) feed('<C-E>') @@ -131,7 +125,7 @@ describe("'wildmenu'", function() screen:expect([[ | {1:~ }|*2 - {31:define}{3: jump list > }| + {100:define}{3: jump list > }| :sign define^ | ]]) feed('<tab><C-Y>') @@ -148,7 +142,7 @@ describe("'wildmenu'", function() screen:expect([[ | {1:~ }|*2 - {31:define}{3: jump list > }| + {100:define}{3: jump list > }| :sign define^ | ]]) end) @@ -162,7 +156,7 @@ describe("'wildmenu'", function() screen:expect([[ | {1:~ }|*2 - {31:define}{3: jump list > }| + {100:define}{3: jump list > }| :sign define^ | ]]) feed('<space>') @@ -188,7 +182,7 @@ describe("'wildmenu'", function() screen:expect([[ | {1:~ }|*2 - {31:!}{3: # & < = > @ > }| + {100:!}{3: # & < = > @ > }| :!^ | ]]) end) @@ -199,9 +193,17 @@ describe("'wildmenu'", function() feed((':terminal "%s" REP 5000 !terminal_output!<cr>'):format(testprg('shell-test'))) feed('G') -- Follow :terminal output. feed([[:sign <Tab>]]) -- Invoke wildmenu. + screen:add_extra_attr_ids { + [100] = { foreground = Screen.colors.Black, background = Screen.colors.Yellow }, + [101] = { + bold = true, + foreground = Screen.colors.White, + background = Screen.colors.DarkGreen, + }, + } -- NB: in earlier versions terminal output was redrawn during cmdline mode. -- For now just assert that the screen remains unchanged. - screen:expect { any = '{31:define}{3: jump list > }|\n:sign define^ |' } + screen:expect { any = '{100:define}{101: jump list > }|\n:sign define^ |' } screen:expect_unchanged() -- cmdline CTRL-D display should also be preserved. @@ -232,7 +234,7 @@ describe("'wildmenu'", function() grid = [[ | {1:~ }|*2 - {31:define}{3: jump list > }| + {100:define}{3: jump list > }| :sign define^ | ]], } @@ -259,9 +261,17 @@ describe("'wildmenu'", function() feed([[<C-\><C-N>]]) feed([[:<Tab>]]) -- Invoke wildmenu. + screen:add_extra_attr_ids { + [100] = { foreground = Screen.colors.Black, background = Screen.colors.Yellow }, + [101] = { + bold = true, + foreground = Screen.colors.White, + background = Screen.colors.DarkGreen, + }, + } -- Check only the last 2 lines, because the shell output is -- system-dependent. - screen:expect { any = '{31:!}{3: # & < = > @ > }|\n:!^' } + screen:expect { any = '{100:!}{101: # & < = > @ > }|\n:!^' } -- Because this test verifies a _lack_ of activity, we must wait the full timeout. -- So make it reasonable. screen:expect_unchanged(false, 1000) @@ -290,7 +300,7 @@ describe("'wildmenu'", function() {3: }| :set wildm | wildmenu wildmode | - {31:wildmenu}{3: wildmode }| + {100:wildmenu}{3: wildmode }| :set wildmenu^ | ]]) feed('<Esc>') @@ -416,10 +426,8 @@ describe("'wildmenu'", function() end) it('works with c_CTRL_Z standard mapping', function() - screen:set_default_attr_ids { - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { foreground = Screen.colors.Grey0, background = Screen.colors.Yellow }, - [3] = { bold = true, reverse = true }, + screen:add_extra_attr_ids { + [100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black }, } -- Wildcharm? where we are going we aint't no need no wildcharm. @@ -436,7 +444,7 @@ describe("'wildmenu'", function() grid = [[ | {1:~ }|*2 - {2:case}{3: clear cluster > }| + {100:case}{3: clear cluster > }| :syntax case^ | ]], } @@ -481,11 +489,9 @@ describe('command line completion', function() before_each(function() clear() screen = Screen.new(40, 5) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { foreground = Screen.colors.Grey0, background = Screen.colors.Yellow }, - [3] = { bold = true, reverse = true }, - }) + screen:add_extra_attr_ids { + [100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black }, + } screen:attach() end) after_each(function() @@ -513,7 +519,7 @@ describe('command line completion', function() screen:expect([[ | {1:~ }|*2 - {2:XTEST_1}{3: XTEST_2 }| + {100:XTEST_1}{3: XTEST_2 }| :!echo $XTEST_1^ | ]]) end) @@ -529,7 +535,7 @@ describe('command line completion', function() screen:expect([[ | {1:~ }|*2 - {2:XTEST_1Aaã‚B}{3: XTEST_2 }| + {100:XTEST_1Aaã‚B}{3: XTEST_2 }| :!echo $XTEST_1Aaã‚B^ | ]]) end) diff --git a/test/functional/vimscript/api_functions_spec.lua b/test/functional/vimscript/api_functions_spec.lua index b2865d2b4c..30d6c969ca 100644 --- a/test/functional/vimscript/api_functions_spec.lua +++ b/test/functional/vimscript/api_functions_spec.lua @@ -115,7 +115,7 @@ describe('eval-API', function() exec_lua, [[ local cmdwin_buf = vim.api.nvim_get_current_buf() - vim.api.nvim_buf_call(vim.api.nvim_create_buf(false, true), function() + vim._with({buf = vim.api.nvim_create_buf(false, true)}, function() vim.api.nvim_open_term(cmdwin_buf, {}) end) ]] diff --git a/test/functional/vimscript/changedtick_spec.lua b/test/functional/vimscript/changedtick_spec.lua index baea53a700..ef9d6b1a69 100644 --- a/test/functional/vimscript/changedtick_spec.lua +++ b/test/functional/vimscript/changedtick_spec.lua @@ -38,7 +38,7 @@ describe('b:changedtick', function() -- Somehow undo counts as two changes eq(5, changedtick()) end) - it('is present in b: dictionary', function() + it('is present in b: dict', function() eq(2, changedtick()) command('let d = b:') eq(2, api.nvim_get_var('d').changedtick) @@ -168,7 +168,7 @@ describe('b:changedtick', function() ) eq(2, changedtick()) end) - it('does not inherit VAR_FIXED when copying dictionary over', function() + it('does not inherit VAR_FIXED when copying dict over', function() eq(2, changedtick()) eq('', exec_capture('let d1 = copy(b:)|let d1.changedtick = 42')) eq('', exec_capture('let d2 = copy(b:)|unlet d2.changedtick')) diff --git a/test/functional/vimscript/ctx_functions_spec.lua b/test/functional/vimscript/ctx_functions_spec.lua index 5e9a803b5d..873e4f820d 100644 --- a/test/functional/vimscript/ctx_functions_spec.lua +++ b/test/functional/vimscript/ctx_functions_spec.lua @@ -295,7 +295,7 @@ describe('context functions', function() eq(outofbounds, pcall_err(call, 'ctxget', 0)) end) - it('returns context dictionary at index in context stack', function() + it('returns context dict at index in context stack', function() feed('i1<cr>2<cr>3<c-[>ddddddqahjklq') command('edit! ' .. fname1) feed('G') @@ -404,7 +404,7 @@ describe('context functions', function() eq(outofbounds, pcall_err(call, 'ctxset', { dummy = 1 }, 0)) end) - it('errors when context dictionary is invalid', function() + it('errors when context dict is invalid', function() call('ctxpush') eq( 'Vim:E474: Failed to convert list to msgpack string buffer', @@ -412,7 +412,7 @@ describe('context functions', function() ) end) - it('sets context dictionary at index in context stack', function() + it('sets context dict at index in context stack', function() api.nvim_set_var('one', 1) api.nvim_set_var('Two', 2) api.nvim_set_var('THREE', 3) diff --git a/test/functional/vimscript/fnamemodify_spec.lua b/test/functional/vimscript/fnamemodify_spec.lua index 51b1e8489a..f2cee9b83e 100644 --- a/test/functional/vimscript/fnamemodify_spec.lua +++ b/test/functional/vimscript/fnamemodify_spec.lua @@ -7,11 +7,10 @@ local fnamemodify = n.fn.fnamemodify local getcwd = n.fn.getcwd local command = n.command local write_file = t.write_file -local alter_slashes = n.alter_slashes local is_os = t.is_os local function eq_slashconvert(expected, got) - eq(alter_slashes(expected), alter_slashes(got)) + eq(t.fix_slashes(expected), t.fix_slashes(got)) end describe('fnamemodify()', function() diff --git a/test/functional/vimscript/input_spec.lua b/test/functional/vimscript/input_spec.lua index 552ae6d5cc..0b774404eb 100644 --- a/test/functional/vimscript/input_spec.lua +++ b/test/functional/vimscript/input_spec.lua @@ -108,7 +108,7 @@ describe('input()', function() {T:1}^ | ]]) end) - it('allows unequal numeric values when using {opts} dictionary', function() + it('allows unequal numeric values when using {opts} dict', function() command('echohl Test') api.nvim_set_var('opts', { prompt = 1, default = 2, cancelreturn = 3 }) feed([[:echo input(opts)<CR>]]) @@ -164,7 +164,7 @@ describe('input()', function() reset = true, } end) - it('allows omitting everything with dictionary argument', function() + it('allows omitting everything with dict argument', function() command('echohl Test') feed([[:call input({})<CR>]]) screen:expect([[ @@ -290,7 +290,7 @@ describe('inputdialog()', function() {T:1}^ | ]]) end) - it('allows unequal numeric values when using {opts} dictionary', function() + it('allows unequal numeric values when using {opts} dict', function() command('echohl Test') api.nvim_set_var('opts', { prompt = 1, default = 2, cancelreturn = 3 }) feed([[:echo input(opts)<CR>]]) @@ -346,7 +346,7 @@ describe('inputdialog()', function() reset = true, } end) - it('allows omitting everything with dictionary argument', function() + it('allows omitting everything with dict argument', function() command('echohl Test') feed(':echo inputdialog({})<CR>') screen:expect([[ diff --git a/test/functional/vimscript/json_functions_spec.lua b/test/functional/vimscript/json_functions_spec.lua index ae56e8873d..895e722e96 100644 --- a/test/functional/vimscript/json_functions_spec.lua +++ b/test/functional/vimscript/json_functions_spec.lua @@ -502,9 +502,9 @@ describe('json_decode() function', function() end it('parses strings with NUL properly', function() - sp_decode_eq({ _TYPE = 'string', _VAL = { '\n' } }, '"\\u0000"') - sp_decode_eq({ _TYPE = 'string', _VAL = { '\n', '\n' } }, '"\\u0000\\n\\u0000"') - sp_decode_eq({ _TYPE = 'string', _VAL = { '\n«\n' } }, '"\\u0000\\u00AB\\u0000"') + sp_decode_eq('\000', '"\\u0000"') + sp_decode_eq('\000\n\000', '"\\u0000\\n\\u0000"') + sp_decode_eq('\000«\000', '"\\u0000\\u00AB\\u0000"') end) it('parses dictionaries with duplicate keys to special maps', function() @@ -580,14 +580,8 @@ describe('json_decode() function', function() end) it('parses dictionaries with keys with NUL bytes to special maps', function() - sp_decode_eq( - { _TYPE = 'map', _VAL = { { { _TYPE = 'string', _VAL = { 'a\n', 'b' } }, 4 } } }, - '{"a\\u0000\\nb": 4}' - ) - sp_decode_eq( - { _TYPE = 'map', _VAL = { { { _TYPE = 'string', _VAL = { 'a\n', 'b', '' } }, 4 } } }, - '{"a\\u0000\\nb\\n": 4}' - ) + sp_decode_eq({ _TYPE = 'map', _VAL = { { 'a\000\nb', 4 } } }, '{"a\\u0000\\nb": 4}') + sp_decode_eq({ _TYPE = 'map', _VAL = { { 'a\000\nb\n', 4 } } }, '{"a\\u0000\\nb\\n": 4}') sp_decode_eq({ _TYPE = 'map', _VAL = { @@ -595,10 +589,7 @@ describe('json_decode() function', function() { 'a', 1 }, { 'c', 4 }, { 'd', 2 }, - { - { _TYPE = 'string', _VAL = { '\n' } }, - 4, - }, + { '\000', 4 }, }, }, '{"b": 3, "a": 1, "c": 4, "d": 2, "\\u0000": 4}') end) @@ -738,22 +729,11 @@ describe('json_encode() function', function() eq('{"\\u0000": 1}', eval('json_encode(todump)')) end) - it('can dump generic mapping with BIN special key and NUL', function() - command('let todump = {"_TYPE": v:msgpack_types.binary, "_VAL": ["\\n"]}') - command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}') - eq('{"\\u0000": 1}', eval('json_encode(todump)')) - end) - it('can dump STR special mapping with NUL and NL', function() command('let todump = {"_TYPE": v:msgpack_types.string, "_VAL": ["\\n", ""]}') eq('"\\u0000\\n"', eval('json_encode(todump)')) end) - it('can dump BIN special mapping with NUL and NL', function() - command('let todump = {"_TYPE": v:msgpack_types.binary, "_VAL": ["\\n", ""]}') - eq('"\\u0000\\n"', eval('json_encode(todump)')) - end) - it('cannot dump special ext mapping', function() command('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}') eq('Vim(call):E474: Unable to convert EXT string to JSON', exc_exec('call json_encode(todump)')) @@ -931,7 +911,7 @@ describe('json_encode() function', function() eq('[]', eval('json_encode(v:_null_list)')) end) - it('can dump NULL dictionary', function() + it('can dump NULL dict', function() eq('{}', eval('json_encode(v:_null_dict)')) end) diff --git a/test/functional/vimscript/map_functions_spec.lua b/test/functional/vimscript/map_functions_spec.lua index 44be5b3185..b69b7dbd57 100644 --- a/test/functional/vimscript/map_functions_spec.lua +++ b/test/functional/vimscript/map_functions_spec.lua @@ -36,7 +36,7 @@ describe('maparg()', function() lnum = 0, } - it('returns a dictionary', function() + it('returns a dict', function() command('nnoremap foo bar') eq('bar', fn.maparg('foo')) eq(foo_bar_map_table, fn.maparg('foo', 'n', false, true)) @@ -54,7 +54,7 @@ describe('maparg()', function() eq('', fn.maparg('not a mapping')) end) - it('returns an empty dictionary when no map is present and dict is requested', function() + it('returns an empty dict when no map is present and dict is requested', function() eq({}, fn.maparg('not a mapping', 'n', false, true)) end) diff --git a/test/functional/vimscript/msgpack_functions_spec.lua b/test/functional/vimscript/msgpack_functions_spec.lua index d59dceef31..d2011f9fec 100644 --- a/test/functional/vimscript/msgpack_functions_spec.lua +++ b/test/functional/vimscript/msgpack_functions_spec.lua @@ -371,13 +371,14 @@ describe('msgpack*() functions', function() eq(1, eval('dumped ==# dumped2')) end) - it('can restore and dump STR string with zero byte', function() + it('can restore and dump STR string contents with zero byte', function() command('let dumped = ["\\xA1\\n"]') command('let parsed = msgpackparse(dumped)') command('let dumped2 = msgpackdump(parsed)') - eq({ { _TYPE = {}, _VAL = { '\n' } } }, eval('parsed')) - eq(1, eval('parsed[0]._TYPE is v:msgpack_types.string')) - eq(1, eval('dumped ==# dumped2')) + eq({ '\000' }, eval('parsed')) + eq(eval('v:t_blob'), eval('type(parsed[0])')) + -- type is not preserved: prefer BIN for binary contents + eq(0, eval('dumped ==# dumped2')) end) it('can restore and dump BIN string with NL', function() @@ -428,26 +429,24 @@ describe('msgpackparse() function', function() parse_eq({ true }, { '\195' }) end) - it('restores FIXSTR as special dict', function() - parse_eq({ { _TYPE = {}, _VAL = { 'ab' } } }, { '\162ab' }) - eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.string')) + it('restores FIXSTR as string', function() + parse_eq({ 'ab' }, { '\162ab' }) end) it('restores BIN 8 as string', function() parse_eq({ 'ab' }, { '\196\002ab' }) end) - it('restores FIXEXT1 as special dictionary', function() + it('restores FIXEXT1 as special dict', function() parse_eq({ { _TYPE = {}, _VAL = { 0x10, { '', '' } } } }, { '\212\016', '' }) eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.ext')) end) - it('restores MAP with BIN key as special dictionary', function() - parse_eq({ { _TYPE = {}, _VAL = { { 'a', '' } } } }, { '\129\196\001a\196\n' }) - eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map')) + it('restores MAP with BIN key as ordinary dict', function() + parse_eq({ { a = '' } }, { '\129\196\001a\196\n' }) end) - it('restores MAP with duplicate STR keys as special dictionary', function() + it('restores MAP with duplicate STR keys as special dict', function() command('let dumped = ["\\x82\\xA1a\\xC4\\n\\xA1a\\xC4\\n"]') -- FIXME Internal error bug, can't use parse_eq() here command('silent! let parsed = msgpackparse(dumped)') @@ -455,17 +454,17 @@ describe('msgpackparse() function', function() { _TYPE = {}, _VAL = { - { { _TYPE = {}, _VAL = { 'a' } }, '' }, - { { _TYPE = {}, _VAL = { 'a' } }, '' }, + { 'a', '' }, + { 'a', '' }, }, }, }, eval('parsed')) eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map')) - eq(1, eval('g:parsed[0]._VAL[0][0]._TYPE is v:msgpack_types.string')) - eq(1, eval('g:parsed[0]._VAL[1][0]._TYPE is v:msgpack_types.string')) + eq(eval('v:t_string'), eval('type(g:parsed[0]._VAL[0][0])')) + eq(eval('v:t_string'), eval('type(g:parsed[0]._VAL[1][0])')) end) - it('restores MAP with MAP key as special dictionary', function() + it('restores MAP with MAP key as special dict', function() parse_eq({ { _TYPE = {}, _VAL = { { {}, '' } } } }, { '\129\128\196\n' }) eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map')) end) @@ -511,7 +510,7 @@ describe('msgpackparse() function', function() ) end) - it('fails to parse a dictionary', function() + it('fails to parse a dict', function() eq( 'Vim(call):E899: Argument of msgpackparse() must be a List or Blob', exc_exec('call msgpackparse({})') @@ -765,7 +764,7 @@ describe('msgpackdump() function', function() ) end) - it('fails to dump a dictionary', function() + it('fails to dump a dict', function() eq('Vim(call):E686: Argument of msgpackdump() must be a List', exc_exec('call msgpackdump({})')) end) @@ -802,7 +801,7 @@ describe('msgpackdump() function', function() it('can dump NULL string', function() dump_eq({ '\196\n' }, '[$XXX_UNEXISTENT_VAR_XXX]') - dump_eq({ '\196\n' }, '[{"_TYPE": v:msgpack_types.binary, "_VAL": [$XXX_UNEXISTENT_VAR_XXX]}]') + dump_eq({ '\196\n' }, '[v:_null_blob]') dump_eq({ '\160' }, '[{"_TYPE": v:msgpack_types.string, "_VAL": [$XXX_UNEXISTENT_VAR_XXX]}]') end) @@ -814,7 +813,7 @@ describe('msgpackdump() function', function() eq({ '\144' }, eval('msgpackdump([v:_null_list])')) end) - it('can dump NULL dictionary', function() + it('can dump NULL dict', function() eq({ '\128' }, eval('msgpackdump([v:_null_dict])')) end) end) diff --git a/test/functional/vimscript/printf_spec.lua b/test/functional/vimscript/printf_spec.lua index 3c66e07618..1fd5c3c9b6 100644 --- a/test/functional/vimscript/printf_spec.lua +++ b/test/functional/vimscript/printf_spec.lua @@ -84,10 +84,13 @@ describe('printf()', function() end api.nvim_del_var('__result') end + check_printf('v:_null_string', true) check_printf('v:_null_list', true) check_printf('v:_null_dict', true) + check_printf('v:_null_blob', true) check_printf('[]') check_printf('{}') + check_printf('0z') check_printf('function("tr", ["a"])') end) end) diff --git a/test/functional/vimscript/string_spec.lua b/test/functional/vimscript/string_spec.lua index 32aa04c0d0..4df9104e1e 100644 --- a/test/functional/vimscript/string_spec.lua +++ b/test/functional/vimscript/string_spec.lua @@ -170,9 +170,9 @@ describe('string() function', function() ) end) - it('does not show errors when dumping partials referencing the same dictionary', function() + it('does not show errors when dumping partials referencing the same dict', function() command('let d = {}') - -- Regression for “eval/typval_encode: Dump empty dictionary before + -- Regression for “eval/typval_encode: Dump empty dict before -- checking for refcycleâ€, results in error. eq( "[function('tr', {}), function('tr', {})]", @@ -256,7 +256,7 @@ describe('string() function', function() end) describe('used to represent dictionaries', function() - it('dumps empty dictionary', function() + it('dumps empty dict', function() eq('{}', eval('string({})')) end) @@ -267,7 +267,7 @@ describe('string() function', function() eq("[{}, function('tr', {})]", eval('string([d, function("tr", d)])')) end) - it('dumps non-empty dictionary', function() + it('dumps non-empty dict', function() eq("{'t''est': 1}", fn.string({ ["t'est"] = 1 })) end) diff --git a/test/old/testdir/crash/dialog_changed_uaf b/test/old/testdir/crash/dialog_changed_uaf Binary files differnew file mode 100644 index 0000000000..e37d18d6da --- /dev/null +++ b/test/old/testdir/crash/dialog_changed_uaf diff --git a/test/old/testdir/crash/double_free b/test/old/testdir/crash/double_free Binary files differnew file mode 100644 index 0000000000..895c4a04b6 --- /dev/null +++ b/test/old/testdir/crash/double_free diff --git a/test/old/testdir/crash/poc_uaf_check_argument_types b/test/old/testdir/crash/poc_uaf_check_argument_types Binary files differnew file mode 100644 index 0000000000..83a2e7b0a6 --- /dev/null +++ b/test/old/testdir/crash/poc_uaf_check_argument_types diff --git a/test/old/testdir/crash/poc_uaf_exec_instructions b/test/old/testdir/crash/poc_uaf_exec_instructions Binary files differnew file mode 100644 index 0000000000..49ae8577ff --- /dev/null +++ b/test/old/testdir/crash/poc_uaf_exec_instructions diff --git a/test/old/testdir/runtest.vim b/test/old/testdir/runtest.vim index 2d8ba60a7e..e05a78e9ca 100644 --- a/test/old/testdir/runtest.vim +++ b/test/old/testdir/runtest.vim @@ -13,6 +13,9 @@ " For csh: " setenv TEST_FILTER Test_channel " +" If the environment variable $TEST_SKIP_PAT is set then test functions +" matching this pattern will be skipped. It's the opposite of $TEST_FILTER. +" " While working on a test you can make $TEST_NO_RETRY non-empty to not retry: " export TEST_NO_RETRY=yes " @@ -45,8 +48,18 @@ " call add(v:errors, "this happened") +" Without the +eval feature we can't run these tests, bail out. +silent! while 0 + qa! +silent! endwhile + +" In the GUI we can always change the screen size. +if has('gui_running') + set columns=80 lines=25 +endif + " Check that the screen size is at least 24 x 80 characters. -if &lines < 24 || &columns < 80 +if &lines < 24 || &columns < 80 let error = 'Screen size too small! Tests require at least 24 lines with 80 characters, got ' .. &lines .. ' lines with ' .. &columns .. ' characters' echoerr error split test.log @@ -92,7 +105,12 @@ set encoding=utf-8 " REDIR_TEST_TO_NULL has a very permissive SwapExists autocommand which is for " the test_name.vim file itself. Replace it here with a more restrictive one, " so we still catch mistakes. -let s:test_script_fname = expand('%') +if has("win32") + " replace any '/' directory separators by '\\' + let s:test_script_fname = substitute(expand('%'), '/', '\\', 'g') +else + let s:test_script_fname = expand('%') +endif au! SwapExists * call HandleSwapExists() func HandleSwapExists() if exists('g:ignoreSwapExists') @@ -131,7 +149,7 @@ if has('win32') endif if has('mac') - " In MacOS, when starting a shell in a terminal, a bash deprecation warning + " In macOS, when starting a shell in a terminal, a bash deprecation warning " message is displayed. This breaks the terminal test. Disable the warning " message. let $BASH_SILENCE_DEPRECATION_WARNING = 1 @@ -431,13 +449,17 @@ func FinishTesting() if s:done == 0 if s:filtered > 0 - let message = "NO tests match $TEST_FILTER: '" .. $TEST_FILTER .. "'" + if $TEST_FILTER != '' + let message = "NO tests match $TEST_FILTER: '" .. $TEST_FILTER .. "'" + else + let message = "ALL tests match $TEST_SKIP_PAT: '" .. $TEST_SKIP_PAT .. "'" + endif else let message = 'NO tests executed' endif else if s:filtered > 0 - call add(s:messages, "Filtered " .. s:filtered .. " tests with $TEST_FILTER") + call add(s:messages, "Filtered " .. s:filtered .. " tests with $TEST_FILTER and $TEST_SKIP_PAT") endif let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test') endif @@ -530,6 +552,12 @@ endif " Execute the tests in alphabetical order. for g:testfunc in sort(s:tests) + if $TEST_SKIP_PAT != '' && g:testfunc =~ $TEST_SKIP_PAT + call add(s:messages, g:testfunc .. ' matches $TEST_SKIP_PAT') + let s:filtered += 1 + continue + endif + " Silence, please! set belloff=all let prev_error = '' diff --git a/test/old/testdir/samples/test.zip b/test/old/testdir/samples/test.zip Binary files differnew file mode 100644 index 0000000000..6d34ac6992 --- /dev/null +++ b/test/old/testdir/samples/test.zip diff --git a/test/old/testdir/samples/testa.zip b/test/old/testdir/samples/testa.zip Binary files differnew file mode 100644 index 0000000000..10b0346e76 --- /dev/null +++ b/test/old/testdir/samples/testa.zip diff --git a/test/old/testdir/setup.vim b/test/old/testdir/setup.vim index 7313a0a162..e7b4bb1a88 100644 --- a/test/old/testdir/setup.vim +++ b/test/old/testdir/setup.vim @@ -1,7 +1,7 @@ if exists('s:did_load') " Align Nvim defaults to Vim. set backspace= - set commentstring=/*%s*/ + set commentstring=/*\ %s\ */ set complete=.,w,b,u,t,i set define=^\\s*#\\s*define set directory^=. @@ -13,6 +13,7 @@ if exists('s:did_load') set laststatus=1 set listchars=eol:$ set joinspaces + set jumpoptions= set mousemodel=extend set nohidden nosmarttab noautoindent noautoread noruler noshowcmd set nohlsearch noincsearch @@ -31,8 +32,8 @@ if exists('s:did_load') endif if g:testname !~ 'test_mapping.vim$' " Make "Q" switch to Ex mode. - " This does not work for all tests. - nnoremap Q gQ + " This does not work for all tests as Nvim only supports Vim Ex mode. + nnoremap Q gQ<Cmd>call<SID>ExStart()<CR> endif endif @@ -44,12 +45,28 @@ if exists('s:did_load') endif let s:did_load = 1 +func s:ExStart() + call feedkeys($"\<Cmd>call{expand('<SID>')}ExMayEnd()\<CR>") +endfunc + +func s:ExMayEnd() + " When :normal runs out of characters in Vim, the behavior is different in + " normal Ex mode vs. Vim Ex mode. + " - In normal Ex mode, "\n" is used. + " - In Vim Ex mode, Ctrl-C is used. + " Nvim only supports Vim Ex mode, so emulate the normal Ex mode behavior. + if state('m') == '' && mode(1) == 'cv' && getcharstr(1) == "\<C-C>" + call feedkeys("\n") + endif +endfunc + " Clear Nvim default user commands, mappings and menus. comclear mapclear mapclear! aunmenu * tlunmenu * +autocmd! nvim_popupmenu " Undo the 'grepprg' and 'grepformat' setting in _defaults.lua. set grepprg& grepformat& diff --git a/test/old/testdir/summarize.vim b/test/old/testdir/summarize.vim index da5856a2e7..d0d4e00b2c 100644 --- a/test/old/testdir/summarize.vim +++ b/test/old/testdir/summarize.vim @@ -33,7 +33,7 @@ if 1 silent %s/^SKIPPED \zs.*/\=Count(submatch(0), 'skipped')/egn silent %s/^\(\d\+\)\s\+FAILED:/\=Count(submatch(1), 'failed')/egn - call extend(output, ["Skipped:"]) + call extend(output, ["Skipped:"]) call extend(output, skipped_output) call extend(output, [ diff --git a/test/old/testdir/test_arglist.vim b/test/old/testdir/test_arglist.vim index ebda332562..952b121aed 100644 --- a/test/old/testdir/test_arglist.vim +++ b/test/old/testdir/test_arglist.vim @@ -360,6 +360,7 @@ func Test_argv() call assert_equal('', argv(1, 100)) call assert_equal([], argv(-1, 100)) call assert_equal('', argv(10, -1)) + %argdelete endfunc " Test for the :argedit command @@ -744,4 +745,26 @@ func Test_all_command() %bw! endfunc +" Test for deleting buffer when creating an arglist. This was accessing freed +" memory +func Test_crash_arglist_uaf() + "%argdelete + new one + au BufAdd XUAFlocal :bw + "call assert_fails(':arglocal XUAFlocal', 'E163:') + arglocal XUAFlocal + au! BufAdd + bw! XUAFlocal + + au BufAdd XUAFlocal2 :bw + new two + new three + arglocal + argadd XUAFlocal2 Xfoobar + bw! XUAFlocal2 + bw! two + + au! BufAdd +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_assert.vim b/test/old/testdir/test_assert.vim index fe093d3582..fa63af687d 100644 --- a/test/old/testdir/test_assert.vim +++ b/test/old/testdir/test_assert.vim @@ -48,10 +48,19 @@ func Test_assert_equal() call assert_match("Expected 'bar' but got 'foo'", v:errors[0]) call remove(v:errors, 0) + let s = 'αβγ' + call assert_equal(1, assert_equal('δεζ', s)) + call assert_match("Expected 'δεζ' but got 'αβγ'", v:errors[0]) + call remove(v:errors, 0) + call assert_equal('XxxxxxxxxxxxxxxxxxxxxxX', 'XyyyyyyyyyyyyyyyyyyyyyyyyyX') call assert_match("Expected 'X\\\\\\[x occurs 21 times]X' but got 'X\\\\\\[y occurs 25 times]X'", v:errors[0]) call remove(v:errors, 0) + call assert_equal('ΩωωωωωωωωωωωωωωωωωωωωωΩ', 'ΩψψψψψψψψψψψψψψψψψψψψψψψψψΩ') + call assert_match("Expected 'Ω\\\\\\[ω occurs 21 times]Ω' but got 'Ω\\\\\\[ψ occurs 25 times]Ω'", v:errors[0]) + call remove(v:errors, 0) + " special characters are escaped call assert_equal("\b\e\f\n\t\r\\\x01\x7f", 'x') call assert_match('Expected ''\\b\\e\\f\\n\\t\\r\\\\\\x01\\x7f'' but got ''x''', v:errors[0]) @@ -189,6 +198,22 @@ func Test_wrong_error_type() call assert_equal(type([]), type(verrors)) endfunc +func Test_compare_fail() + let s:v = {} + let s:x = {"a": s:v} + let s:v["b"] = s:x + let s:w = {"c": s:x, "d": ''} + try + call assert_equal(s:w, '') + catch + call assert_equal(0, assert_exception('E724:')) + " Nvim: expected value isn't shown as NULL + " call assert_match("Expected NULL but got ''", v:errors[0]) + call assert_match("Expected .* but got ''", v:errors[0]) + call remove(v:errors, 0) + endtry +endfunc + func Test_match() call assert_equal(0, assert_match('^f.*b.*r$', 'foobar')) diff --git a/test/old/testdir/test_autocmd.vim b/test/old/testdir/test_autocmd.vim index cdcd68f3d6..9d06ebb2be 100644 --- a/test/old/testdir/test_autocmd.vim +++ b/test/old/testdir/test_autocmd.vim @@ -15,6 +15,13 @@ func s:cleanup_buffers() abort endfor endfunc +func CleanUpTestAuGroup() + augroup testing + au! + augroup END + augroup! testing +endfunc + func Test_vim_did_enter() call assert_false(v:vim_did_enter) @@ -273,8 +280,8 @@ func Test_win_tab_autocmd() augroup testing au WinNew * call add(g:record, 'WinNew') au WinClosed * call add(g:record, 'WinClosed') - au WinEnter * call add(g:record, 'WinEnter') - au WinLeave * call add(g:record, 'WinLeave') + au WinEnter * call add(g:record, 'WinEnter') + au WinLeave * call add(g:record, 'WinLeave') au TabNew * call add(g:record, 'TabNew') au TabClosed * call add(g:record, 'TabClosed') au TabEnter * call add(g:record, 'TabEnter') @@ -2010,6 +2017,38 @@ func Test_Cmdline() au! CmdlineEnter au! CmdlineLeave let &shellslash = save_shellslash + + au! CursorMovedC : let g:pos += [getcmdpos()] + let g:pos = [] + call feedkeys(":foo bar baz\<C-W>\<C-W>\<C-W>\<Esc>", 'xt') + call assert_equal([2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 9, 5, 1], g:pos) + let g:pos = [] + call feedkeys(":hello\<C-B>\<Esc>", 'xt') + call assert_equal([2, 3, 4, 5, 6, 1], g:pos) + let g:pos = [] + call feedkeys(":hello\<C-U>\<Esc>", 'xt') + call assert_equal([2, 3, 4, 5, 6, 1], g:pos) + let g:pos = [] + call feedkeys(":hello\<Left>\<C-R>=''\<CR>\<Left>\<Right>\<Esc>", 'xt') + call assert_equal([2, 3, 4, 5, 6, 5, 4, 5], g:pos) + let g:pos = [] + call feedkeys(":12345678\<C-R>=setcmdpos(3)??''\<CR>\<Esc>", 'xt') + call assert_equal([2, 3, 4, 5, 6, 7, 8, 9, 3], g:pos) + let g:pos = [] + call feedkeys(":12345678\<C-R>=setcmdpos(3)??''\<CR>\<Left>\<Esc>", 'xt') + call assert_equal([2, 3, 4, 5, 6, 7, 8, 9, 3, 2], g:pos) + au! CursorMovedC + + " setcmdpos() is no-op inside an autocommand + au! CursorMovedC : let g:pos += [getcmdpos()] | call setcmdpos(1) + let g:pos = [] + call feedkeys(":hello\<Left>\<Left>\<Esc>", 'xt') + call assert_equal([2, 3, 4, 5, 6, 5, 4], g:pos) + au! CursorMovedC + + unlet g:entered + unlet g:left + unlet g:pos endfunc " Test for BufWritePre autocommand that deletes or unloads the buffer. @@ -3738,7 +3777,7 @@ endfunc func Test_autocmd_split_dummy() " Autocommand trying to split a window containing a dummy buffer. - auto BufReadPre * exe "sbuf " .. expand("<abuf>") + auto BufReadPre * exe "sbuf " .. expand("<abuf>") " Avoid the "W11" prompt au FileChangedShell * let v:fcs_choice = 'reload' func Xautocmd_changelist() @@ -4120,4 +4159,23 @@ func Test_BufEnter_botline() set hidden&vim endfunc +" This was using freed memory +func Test_autocmd_BufWinLeave_with_vsp() + new + let fname = 'XXXBufWinLeaveUAF.txt' + let dummy = 'XXXDummy.txt' + call writefile([], fname) + call writefile([], dummy) + defer delete(fname) + defer delete(dummy) + exe "e " fname + vsp + augroup testing + exe "au BufWinLeave " .. fname .. " :e " dummy .. "| vsp " .. fname + augroup END + bw + call CleanUpTestAuGroup() + exe "bw! " .. dummy +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_autoload.vim b/test/old/testdir/test_autoload.vim index e89fe3943b..156387a2d2 100644 --- a/test/old/testdir/test_autoload.vim +++ b/test/old/testdir/test_autoload.vim @@ -21,5 +21,4 @@ func Test_source_autoload() call assert_equal(1, g:loaded_sourced_vim) endfunc - " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_blob.vim b/test/old/testdir/test_blob.vim index 25b3c00dfc..fbc080059e 100644 --- a/test/old/testdir/test_blob.vim +++ b/test/old/testdir/test_blob.vim @@ -75,6 +75,13 @@ func Test_blob_assign() VAR l = [0z12] VAR m = deepcopy(l) LET m[0] = 0z34 #" E742 or E741 should not occur. + + VAR blob1 = 0z10 + LET blob1 += v:_null_blob + call assert_equal(0z10, blob1) + LET blob1 = v:_null_blob + LET blob1 += 0z20 + call assert_equal(0z20, blob1) END call CheckLegacyAndVim9Success(lines) @@ -332,6 +339,17 @@ func Test_blob_for_loop() call assert_equal(5, i) END call CheckLegacyAndVim9Success(lines) + + " Test for skipping the loop var assignment in a for loop + let lines =<< trim END + VAR blob = 0z998877 + VAR c = 0 + for _ in blob + LET c += 1 + endfor + call assert_equal(3, c) + END + call CheckLegacyAndVim9Success(lines) endfunc func Test_blob_concatenate() @@ -850,7 +868,8 @@ func Test_indexof() call assert_equal(-1, indexof(v:_null_blob, "v:val == 0xde")) call assert_equal(-1, indexof(b, v:_null_string)) " Nvim doesn't have null functions - " call assert_equal(-1, indexof(b, test_null_function())) + " call assert_equal(-1, indexof(b, test_null_function())) + call assert_equal(-1, indexof(b, "")) let b = 0z01020102 call assert_equal(1, indexof(b, "v:val == 0x02", #{startidx: 0})) @@ -862,6 +881,7 @@ func Test_indexof() " failure cases call assert_fails('let i = indexof(b, "val == 0xde")', 'E121:') call assert_fails('let i = indexof(b, {})', 'E1256:') + call assert_fails('let i = indexof(b, " ")', 'E15:') endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_blockedit.vim b/test/old/testdir/test_blockedit.vim index e0cfe11af0..c36ff74f29 100644 --- a/test/old/testdir/test_blockedit.vim +++ b/test/old/testdir/test_blockedit.vim @@ -53,7 +53,7 @@ func Test_blockinsert_autoindent() let expected =<< trim END vim9script var d = { - a: (): asdf => 0, + a: (): asdf => 0, b: (): asdf => 0, c: (): asdf => 0, } diff --git a/test/old/testdir/test_breakindent.vim b/test/old/testdir/test_breakindent.vim index 636ec6f285..3787747104 100644 --- a/test/old/testdir/test_breakindent.vim +++ b/test/old/testdir/test_breakindent.vim @@ -837,18 +837,73 @@ func Test_breakindent20_list() \ ] let lines = s:screen_lines2(1, 9, 20) call s:compare_lines(expect, lines) + + " check with TABs + call setline(1, ["\t1.\tCongress shall make no law", + \ "\t2.) Congress shall make no law", + \ "\t3.] Congress shall make no law"]) + setl tabstop=4 list listchars=tab:<-> + norm! 1gg + redraw! + let expect = [ + \ "<-->1.<>Congress ", + \ " shall make ", + \ " no law ", + \ "<-->2.) Congress ", + \ " shall make ", + \ " no law ", + \ "<-->3.] Congress ", + \ " shall make ", + \ " no law ", + \ ] + let lines = s:screen_lines2(1, 9, 20) + call s:compare_lines(expect, lines) + + setl tabstop=2 nolist + redraw! + let expect = [ + \ " 1. Congress ", + \ " shall make no ", + \ " law ", + \ " 2.) Congress ", + \ " shall make no ", + \ " law ", + \ " 3.] Congress ", + \ " shall make no ", + \ " law ", + \ ] + let lines = s:screen_lines2(1, 9, 20) + call s:compare_lines(expect, lines) + + setl tabstop& list listchars=space:_ + redraw! + let expect = [ + \ "^I1.^ICongress_ ", + \ " shall_make_no_", + \ " law ", + \ "^I2.)_Congress_ ", + \ " shall_make_no_", + \ " law ", + \ "^I3.]_Congress_ ", + \ " shall_make_no_", + \ " law ", + \ ] + let lines = s:screen_lines2(1, 9, 20) + call s:compare_lines(expect, lines) + " check formatlistpat indent with different list levels - let &l:flp = '^\s*\*\+\s\+' + let &l:flp = '^\s*\(\*\|•\)\+\s\+' + setl list&vim listchars&vim %delete _ call setline(1, ['* Congress shall make no law', - \ '*** Congress shall make no law', + \ '••• Congress shall make no law', \ '**** Congress shall make no law']) norm! 1gg redraw! let expect = [ \ "* Congress shall ", \ " make no law ", - \ "*** Congress shall ", + \ "••• Congress shall ", \ " make no law ", \ "**** Congress shall ", \ " make no law ", @@ -864,7 +919,7 @@ func Test_breakindent20_list() let expect = [ \ "* Congress shall ", \ "> make no law ", - \ "*** Congress shall ", + \ "••• Congress shall ", \ "> make no law ", \ "**** Congress shall ", \ "> make no law ", @@ -880,7 +935,7 @@ func Test_breakindent20_list() let expect = [ \ "* Congress shall ", \ "> make no law ", - \ "*** Congress shall ", + \ "••• Congress shall ", \ "> make no law ", \ "**** Congress shall ", \ "> make no law ", @@ -1205,4 +1260,15 @@ func Test_breakindent_min_with_signcol() call s:close_windows() endfunc +func Test_breakindent_with_double_width_wrap() + 50vnew + setlocal tabstop=8 breakindent nolist + call setline(1, "\t" .. repeat('a', winwidth(0) - 9) .. 'å£å£å£') + normal! $g0 + call assert_equal(2, winline()) + call assert_equal(9, wincol()) + + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_buffer.vim b/test/old/testdir/test_buffer.vim index bc8e5eaf7b..69d22de2ce 100644 --- a/test/old/testdir/test_buffer.vim +++ b/test/old/testdir/test_buffer.vim @@ -126,6 +126,52 @@ func Test_buflist_browse() %bwipe! endfunc +" Test for :bnext and :bprev when called from help and non-help buffers. +func Test_bnext_bprev_help() + %bwipe! + + e XHelp1 | set bt=help + let b1 = bufnr() + e Xbuf1 + let b2 = bufnr() + + " There's only one buffer of each type. + b XHelp1 + bnext | call assert_equal(b1, bufnr()) + bprev | call assert_equal(b1, bufnr()) + b Xbuf1 + bnext | call assert_equal(b2, bufnr()) + bprev | call assert_equal(b2, bufnr()) + + " Add one more buffer of each type. + e XHelp2 | set bt=help + let b3 = bufnr() + e Xbuf2 + let b4 = bufnr() + + " Help buffer jumps to help buffer. + b XHelp1 + bnext | call assert_equal(b3, bufnr()) + bnext | call assert_equal(b1, bufnr()) + bprev | call assert_equal(b3, bufnr()) + bprev | call assert_equal(b1, bufnr()) + + " Regular buffer jumps to regular buffer. + b Xbuf1 + bnext | call assert_equal(b4, bufnr()) + bnext | call assert_equal(b2, bufnr()) + bprev | call assert_equal(b4, bufnr()) + bprev | call assert_equal(b2, bufnr()) + + " :brewind and :blast are not affected by the buffer type. + b Xbuf2 + brewind | call assert_equal(b1, bufnr()) + b XHelp1 + blast | call assert_equal(b4, bufnr()) + + %bwipe! +endfunc + " Test for :bdelete func Test_bdelete_cmd() %bwipe! diff --git a/test/old/testdir/test_cd.vim b/test/old/testdir/test_cd.vim index cffba99451..dd92fc6c38 100644 --- a/test/old/testdir/test_cd.vim +++ b/test/old/testdir/test_cd.vim @@ -58,22 +58,21 @@ func Test_cd_minus() call writefile(v:errors, 'Xresult') qall! [SCRIPT] - call writefile(lines, 'Xscript') + call writefile(lines, 'Xscript', 'D') if RunVim([], [], '--clean -S Xscript') call assert_equal([], readfile('Xresult')) endif - call delete('Xscript') call delete('Xresult') endfunc " Test for chdir() func Test_chdir_func() let topdir = getcwd() - call mkdir('Xdir/y/z', 'p') + call mkdir('Xchdir/y/z', 'pR') " Create a few tabpages and windows with different directories new - cd Xdir + cd Xchdir tabnew tcd y below new @@ -81,22 +80,22 @@ func Test_chdir_func() lcd z tabfirst - call assert_match('^\[global\] .*/Xdir$', trim(execute('verbose pwd'))) + call assert_match('^\[global\] .*/Xchdir$', trim(execute('verbose pwd'))) call chdir('..') call assert_equal('y', fnamemodify(getcwd(1, 2), ':t')) call assert_equal('z', fnamemodify(3->getcwd(2), ':t')) tabnext | wincmd t call assert_match('^\[tabpage\] .*/y$', trim(execute('verbose pwd'))) eval '..'->chdir() - call assert_equal('Xdir', fnamemodify(getcwd(1, 2), ':t')) - call assert_equal('Xdir', fnamemodify(getcwd(2, 2), ':t')) + call assert_equal('Xchdir', fnamemodify(getcwd(1, 2), ':t')) + call assert_equal('Xchdir', fnamemodify(getcwd(2, 2), ':t')) call assert_equal('z', fnamemodify(getcwd(3, 2), ':t')) call assert_equal('testdir', fnamemodify(getcwd(1, 1), ':t')) 3wincmd w call assert_match('^\[window\] .*/z$', trim(execute('verbose pwd'))) call chdir('..') - call assert_equal('Xdir', fnamemodify(getcwd(1, 2), ':t')) - call assert_equal('Xdir', fnamemodify(getcwd(2, 2), ':t')) + call assert_equal('Xchdir', fnamemodify(getcwd(1, 2), ':t')) + call assert_equal('Xchdir', fnamemodify(getcwd(2, 2), ':t')) call assert_equal('y', fnamemodify(getcwd(3, 2), ':t')) call assert_equal('testdir', fnamemodify(getcwd(1, 1), ':t')) @@ -110,20 +109,19 @@ func Test_chdir_func() only | tabonly call chdir(topdir) - call delete('Xdir', 'rf') endfunc " Test for changing to the previous directory '-' func Test_prev_dir() let topdir = getcwd() - call mkdir('Xdir/a/b/c', 'p') + call mkdir('Xprevdir/a/b/c', 'pR') " Create a few tabpages and windows with different directories new | only tabnew | new tabnew tabfirst - cd Xdir + cd Xprevdir tabnext | wincmd t tcd a wincmd w @@ -143,7 +141,7 @@ func Test_prev_dir() " Check the directory of all the windows tabfirst - call assert_equal('Xdir', fnamemodify(getcwd(), ':t')) + call assert_equal('Xprevdir', fnamemodify(getcwd(), ':t')) tabnext | wincmd t call assert_equal('a', fnamemodify(getcwd(), ':t')) wincmd w @@ -163,7 +161,7 @@ func Test_prev_dir() " Check the directory of all the windows tabfirst - call assert_equal('Xdir', fnamemodify(getcwd(), ':t')) + call assert_equal('Xprevdir', fnamemodify(getcwd(), ':t')) tabnext | wincmd t call assert_equal('a', fnamemodify(getcwd(), ':t')) wincmd w @@ -173,7 +171,6 @@ func Test_prev_dir() only | tabonly call chdir(topdir) - call delete('Xdir', 'rf') endfunc func Test_lcd_split() @@ -201,22 +198,26 @@ func Test_cd_from_non_existing_dir() endfunc func Test_cd_completion() - call mkdir('XComplDir1', 'p') - call mkdir('XComplDir2', 'p') - call writefile([], 'XComplFile') + call mkdir('XComplDir1', 'D') + call mkdir('XComplDir2', 'D') + call mkdir('sub/XComplDir3', 'pD') + call writefile([], 'XComplFile', 'D') for cmd in ['cd', 'chdir', 'lcd', 'lchdir', 'tcd', 'tchdir'] call feedkeys(':' .. cmd .. " XCompl\<C-A>\<C-B>\"\<CR>", 'tx') call assert_equal('"' .. cmd .. ' XComplDir1/ XComplDir2/', @:) endfor - call delete('XComplDir1', 'd') - call delete('XComplDir2', 'd') - call delete('XComplFile') + set cdpath+=sub + for cmd in ['cd', 'chdir', 'lcd', 'lchdir', 'tcd', 'tchdir'] + call feedkeys(':' .. cmd .. " XCompl\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"' .. cmd .. ' XComplDir1/ XComplDir2/ XComplDir3/', @:) + endfor + set cdpath& endfunc func Test_cd_unknown_dir() - call mkdir('Xa') + call mkdir('Xa', 'R') cd Xa call writefile(['text'], 'Xb.txt') edit Xa/Xb.txt @@ -229,7 +230,6 @@ func Test_cd_unknown_dir() bwipe! exe "bwipe! " .. first_buf - call delete('Xa', 'rf') endfunc func Test_getcwd_actual_dir() @@ -237,7 +237,7 @@ func Test_getcwd_actual_dir() CheckOption autochdir let startdir = getcwd() - call mkdir('Xactual') + call mkdir('Xactual', 'R') call test_autochdir() set autochdir edit Xactual/file.txt @@ -251,7 +251,6 @@ func Test_getcwd_actual_dir() set noautochdir bwipe! call chdir(startdir) - call delete('Xactual', 'rf') endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_cmdline.vim b/test/old/testdir/test_cmdline.vim index 443539fbfd..9f25a42c38 100644 --- a/test/old/testdir/test_cmdline.vim +++ b/test/old/testdir/test_cmdline.vim @@ -645,7 +645,8 @@ func Test_getcompletion() unlet g:cmdline_compl_params " For others test if the name is recognized. - let names = ['buffer', 'environment', 'file_in_path', 'mapping', 'tag', 'tag_listfiles', 'user'] + let names = ['buffer', 'environment', 'file_in_path', 'dir_in_path', 'mapping', 'tag', + \ 'tag_listfiles', 'user'] if has('cmdline_hist') call add(names, 'history') endif @@ -1533,7 +1534,7 @@ endfunc set cpo& -func Test_getcmdtype() +func Test_getcmdtype_getcmdprompt() call feedkeys(":MyCmd a\<C-R>=Check_cmdline(':')\<CR>\<Esc>", "xt") let cmdtype = '' @@ -1557,6 +1558,31 @@ func Test_getcmdtype() cunmap <F6> call assert_equal('', getcmdline()) + + call assert_equal('', getcmdprompt()) + augroup test_CmdlineEnter + autocmd! + autocmd CmdlineEnter * let g:cmdprompt=getcmdprompt() + augroup END + call feedkeys(":call input('Answer?')\<CR>a\<CR>\<ESC>", "xt") + call assert_equal('Answer?', g:cmdprompt) + call assert_equal('', getcmdprompt()) + call feedkeys(":\<CR>\<ESC>", "xt") + call assert_equal('', g:cmdprompt) + call assert_equal('', getcmdprompt()) + + let str = "C" .. repeat("c", 1023) .. "xyz" + call feedkeys(":call input('" .. str .. "')\<CR>\<CR>\<ESC>", "xt") + call assert_equal(str, g:cmdprompt) + + call feedkeys(':call input("Msg1\nMessage2\nAns?")' .. "\<CR>b\<CR>\<ESC>", "xt") + call assert_equal('Ans?', g:cmdprompt) + call assert_equal('', getcmdprompt()) + + augroup test_CmdlineEnter + au! + augroup END + augroup! test_CmdlineEnter endfunc func Test_getcmdwintype() @@ -2905,6 +2931,55 @@ func Test_wildmenu_pum_odd_wildchar() call StopVimInTerminal(buf) endfunc +" Test that 'rightleft' should not affect cmdline completion popup menu. +func Test_wildmenu_pum_rightleft() + CheckFeature rightleft + CheckScreendump + + let lines =<< trim END + set wildoptions=pum + set rightleft + END + call writefile(lines, 'Xwildmenu_pum_rl', 'D') + let buf = RunVimInTerminal('-S Xwildmenu_pum_rl', #{rows: 10, cols: 50}) + + call term_sendkeys(buf, ":sign \<Tab>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_rl', {}) + + call StopVimInTerminal(buf) +endfunc + +" Test highlighting matched text in cmdline completion popup menu. +func Test_wildmenu_pum_hl_match() + CheckScreendump + + let lines =<< trim END + set wildoptions=pum,fuzzy + hi PmenuMatchSel ctermfg=6 ctermbg=7 + hi PmenuMatch ctermfg=4 ctermbg=225 + END + call writefile(lines, 'Xwildmenu_pum_hl', 'D') + let buf = RunVimInTerminal('-S Xwildmenu_pum_hl', #{rows: 10, cols: 50}) + + call term_sendkeys(buf, ":sign plc\<Tab>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_hl_match_1', {}) + call term_sendkeys(buf, "\<Tab>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_hl_match_2', {}) + call term_sendkeys(buf, "\<Tab>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_hl_match_3', {}) + call term_sendkeys(buf, "\<Esc>:set wildoptions-=fuzzy\<CR>") + call TermWait(buf) + call term_sendkeys(buf, ":sign un\<Tab>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_hl_match_4', {}) + call term_sendkeys(buf, "\<Tab>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_hl_match_5', {}) + call term_sendkeys(buf, "\<Tab>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_hl_match_6', {}) + call term_sendkeys(buf, "\<Esc>") + + call StopVimInTerminal(buf) +endfunc + " Test for completion after a :substitute command followed by a pipe (|) " character func Test_cmdline_complete_substitute() @@ -3736,7 +3811,7 @@ func Test_cmdline_complete_bang_cmd_argument() endfunc func Call_cmd_funcs() - return string([getcmdpos(), getcmdscreenpos(), getcmdcompltype()]) + return [getcmdpos(), getcmdscreenpos(), getcmdcompltype()] endfunc func Test_screenpos_and_completion() @@ -3744,13 +3819,24 @@ func Test_screenpos_and_completion() call assert_equal(0, getcmdscreenpos()) call assert_equal('', getcmdcompltype()) - cnoremap <expr> <F2> string([getcmdpos(), getcmdscreenpos(), getcmdcompltype()]) + cnoremap <expr> <F2> string(Call_cmd_funcs()) call feedkeys(":let a\<F2>\<C-B>\"\<CR>", "xt") call assert_equal("\"let a[6, 7, 'var']", @:) call feedkeys(":quit \<F2>\<C-B>\"\<CR>", "xt") call assert_equal("\"quit [6, 7, '']", @:) call feedkeys(":nosuchcommand \<F2>\<C-B>\"\<CR>", "xt") call assert_equal("\"nosuchcommand [15, 16, '']", @:) + + " Check that getcmdcompltype() doesn't interfere with cmdline completion. + let g:results = [] + cnoremap <F2> <Cmd>let g:results += [[getcmdline()] + Call_cmd_funcs()]<CR> + call feedkeys(":sign un\<Tab>\<F2>\<Tab>\<F2>\<Tab>\<F2>\<C-C>", "xt") + call assert_equal([ + \ ['sign undefine', 14, 15, 'sign'], + \ ['sign unplace', 13, 14, 'sign'], + \ ['sign un', 8, 9, 'sign']], g:results) + + unlet g:results cunmap <F2> endfunc @@ -3984,4 +4070,15 @@ func Test_term_option() let &cpo = _cpo endfunc +func Test_cd_bslsh_completion_windows() + CheckMSWindows + let save_shellslash = &shellslash + set noshellslash + call system('mkdir XXXa\_b') + defer delete('XXXa', 'rf') + call feedkeys(":cd XXXa\\_b\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"cd XXXa\_b\', @:) + let &shellslash = save_shellslash +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_codestyle.vim b/test/old/testdir/test_codestyle.vim index 01dd03f693..a0cebf76d1 100644 --- a/test/old/testdir/test_codestyle.vim +++ b/test/old/testdir/test_codestyle.vim @@ -6,6 +6,45 @@ func s:ReportError(fname, lnum, msg) endif endfunc +func Test_test_files() + for fname in glob('*.vim', 0, 1) + let g:ignoreSwapExists = 'e' + exe 'edit ' .. fname + + " some files intentionally have misplaced white space + if fname =~ 'test_cindent.vim' || fname =~ 'test_join.vim' + continue + endif + + " skip files that are known to have a space before a tab + if fname !~ 'test_comments.vim' + \ && fname !~ 'test_listchars.vim' + \ && fname !~ 'test_visual.vim' + call cursor(1, 1) + let skip = 'getline(".") =~ "codestyle: ignore"' + let lnum = search(fname =~ "test_regexp_latin" ? '[^á] \t' : ' \t', 'W', 0, 0, skip) + call s:ReportError('testdir/' .. fname, lnum, 'space before Tab') + endif + + " skip files that are known to have trailing white space + if fname !~ 'test_cmdline.vim' + \ && fname !~ 'test_let.vim' + \ && fname !~ 'test_tagjump.vim' + \ && fname !~ 'test_vim9_cmd.vim' + call cursor(1, 1) + let lnum = search( + \ fname =~ 'test_vim9_assign.vim' ? '[^=]\s$' + \ : fname =~ 'test_vim9_class.vim' ? '[^)]\s$' + \ : fname =~ 'test_vim9_script.vim' ? '[^,:3]\s$' + \ : fname =~ 'test_visual.vim' ? '[^/]\s$' + \ : '[^\\]\s$') + call s:ReportError('testdir/' .. fname, lnum, 'trailing white space') + endif + endfor + + bwipe! +endfunc + func Test_help_files() set nowrapscan diff --git a/test/old/testdir/test_cpoptions.vim b/test/old/testdir/test_cpoptions.vim index 915f418712..dd959c64a8 100644 --- a/test/old/testdir/test_cpoptions.vim +++ b/test/old/testdir/test_cpoptions.vim @@ -8,7 +8,7 @@ source view_util.vim " file name. func Test_cpo_a() let save_cpo = &cpo - call writefile(['one'], 'XfileCpoA') + call writefile(['one'], 'XfileCpoA', 'D') " Wipe out all the buffers, so that the alternate file is empty edit Xfoo | %bw set cpo-=a @@ -19,8 +19,7 @@ func Test_cpo_a() set cpo+=a read XfileCpoA call assert_equal('XfileCpoA', @#) - close! - call delete('XfileCpoA') + bw! let &cpo = save_cpo endfunc @@ -40,7 +39,7 @@ func Test_cpo_A() set cpo+=A write XcpoAfile2 call assert_equal('XcpoAfile2', @#) - close! + bw! call delete('XcpoAfile2') let &cpo = save_cpo endfunc @@ -82,7 +81,7 @@ func Test_cpo_B() call assert_equal('abd ', getline(1)) call feedkeys(":imap <buffer> x\<C-A>\<C-B>\"\<CR>", 'tx') call assert_equal('"imap <buffer> x\k', @:) - close! + bw! let &cpo = save_cpo endfunc @@ -97,28 +96,27 @@ func Test_cpo_c() set cpo-=c exe "normal gg/abab\<CR>" call assert_equal(5, searchcount().total) - close! + bw! let &cpo = save_cpo endfunc " Test for the 'C' flag in 'cpo' (line continuation) func Test_cpo_C() let save_cpo = &cpo - call writefile(['let l = [', '\ 1,', '\ 2]'], 'XfileCpoC') + call writefile(['let l = [', '\ 1,', '\ 2]'], 'XfileCpoC', 'D') set cpo-=C source XfileCpoC call assert_equal([1, 2], g:l) set cpo+=C call assert_fails('source XfileCpoC', ['E697:', 'E10:']) - call delete('XfileCpoC') let &cpo = save_cpo endfunc " Test for the 'd' flag in 'cpo' (tags relative to the current file) func Test_cpo_d() let save_cpo = &cpo - call mkdir('XdirCpoD') - call writefile(["one\tXfile1\t/^one$/"], 'tags') + call mkdir('XdirCpoD', 'R') + call writefile(["one\tXfile1\t/^one$/"], 'tags', 'D') call writefile(["two\tXfile2\t/^two$/"], 'XdirCpoD/tags') set tags=./tags set cpo-=d @@ -126,9 +124,8 @@ func Test_cpo_d() call assert_equal('two', taglist('.*')[0].name) set cpo+=d call assert_equal('one', taglist('.*')[0].name) + %bw! - call delete('tags') - call delete('XdirCpoD', 'rf') set tags& let &cpo = save_cpo endfunc @@ -146,7 +143,7 @@ func Test_cpo_D() exe "norm! 1gg0f\<c-k>!!" call assert_equal(1, col('.')) set cpo-=D - close! + bw! let &cpo = save_cpo endfunc @@ -186,7 +183,7 @@ func Test_cpo_E() call assert_beeps('exe "normal v\<C-A>"') call assert_beeps('exe "normal v\<C-X>"') set cpo-=E - close! + bw! endfunc " Test for the 'f' flag in 'cpo' (read in an empty buffer sets the file name) @@ -216,7 +213,7 @@ func Test_cpo_F() set cpo+=F write XfileCpoF call assert_equal('XfileCpoF', @%) - close! + bw! call delete('XfileCpoF') let &cpo = save_cpo endfunc @@ -233,7 +230,7 @@ func Test_cpo_g() " set cpo+=g " edit " call assert_equal(1, line('.')) - close! + bw! let &cpo = save_cpo endfunc @@ -250,7 +247,7 @@ func Test_cpo_H() " call setline(1, ' ') " normal! Ia " call assert_equal(' a ', getline(1)) - close! + bw! let &cpo = save_cpo endfunc @@ -269,7 +266,7 @@ func Test_cpo_I() %d exe "normal i one\<CR>\<Up>" call assert_equal('', getline(2)) - close! + bw! let &cpo = save_cpo endfunc @@ -300,7 +297,7 @@ func Test_cpo_J() normal ( call assert_equal(colnr, col('.')) endfor - close! + bw! let &cpo = save_cpo endfunc @@ -322,7 +319,7 @@ func Test_cpo_l() set cpo+=l exe 'normal gg/[\t]' .. "\<CR>" call assert_equal([4, 10], [col('.'), virtcol('.')]) - close! + bw! let &cpo = save_cpo endfunc @@ -343,7 +340,7 @@ func Test_cpo_L() call setline(1, 'abcdefghijklmnopqr') exe "normal 0gR\<Tab>" call assert_equal("\<Tab>ijklmnopqr", getline(1)) - close! + bw! let &cpo = save_cpo endfunc @@ -381,7 +378,7 @@ func Test_cpo_M() call cursor(2, 1) call assert_beeps('normal %') - close! + bw! let &cpo = save_cpo endfunc @@ -397,7 +394,7 @@ func Test_cpo_n() set cpo+=n redraw! call assert_equal('aaaa', Screenline(2)) - close! + bw! let &cpo = save_cpo endfunc @@ -414,7 +411,7 @@ func Test_cpo_o() exe "normal /one/+2\<CR>" normal n call assert_equal(5, line('.')) - close! + bw! let &cpo = save_cpo endfunc @@ -423,14 +420,13 @@ func Test_cpo_O() let save_cpo = &cpo new XfileCpoO call setline(1, 'one') - call writefile(['two'], 'XfileCpoO') + call writefile(['two'], 'XfileCpoO', 'D') set cpo-=O call assert_fails('write', 'E13:') set cpo+=O write call assert_equal(['one'], readfile('XfileCpoO')) - close! - call delete('XfileCpoO') + bw! let &cpo = save_cpo endfunc @@ -440,7 +436,7 @@ endfunc " name) func Test_cpo_P() let save_cpo = &cpo - call writefile([], 'XfileCpoP') + call writefile([], 'XfileCpoP', 'D') new call setline(1, 'one') set cpo+=F @@ -452,7 +448,6 @@ func Test_cpo_P() call assert_equal('XfileCpoP', @%) bwipe! - call delete('XfileCpoP') let &cpo = save_cpo endfunc @@ -469,7 +464,7 @@ func Test_cpo_q() set cpo+=q normal gg4J call assert_equal(4, col('.')) - close! + bw! let &cpo = save_cpo endfunc @@ -490,7 +485,7 @@ func Test_cpo_r() let @/ = 'three' normal 2G. call assert_equal('abc three four', getline(2)) - close! + bw! let &cpo = save_cpo endfunc @@ -510,7 +505,7 @@ func Test_cpo_R() 3mark r %!sort call assert_equal(0, line("'r")) - close! + bw! let &cpo = save_cpo endfunc @@ -537,8 +532,8 @@ func Test_cpo_S() wincmd p call assert_equal(0, &autoindent) wincmd t - close! - close! + bw! + bw! let &cpo = save_cpo endfunc @@ -557,7 +552,7 @@ func Test_cpo_u() exe "normal iabc\<C-G>udef\<C-G>ughi" normal uu call assert_equal('abcdefghi', getline(1)) - close! + bw! let &cpo = save_cpo endfunc @@ -582,7 +577,7 @@ func Test_cpo_w() call assert_equal('hereZZZare some words', getline('.')) norm! 1gg2elcWYYY call assert_equal('hereZZZare someYYYwords', getline('.')) - close! + bw! let &cpo = save_cpo endfunc @@ -619,7 +614,7 @@ func Test_cpo_X() normal ggRy normal 4. call assert_equal('yyyyxxxaaaaa', getline(1)) - close! + bw! let &cpo = save_cpo endfunc @@ -638,14 +633,14 @@ func Test_cpo_y() normal ggyy normal 2G. call assert_equal("two\n", @") - close! + bw! let &cpo = save_cpo endfunc " Test for the 'Z' flag in 'cpo' (write! resets 'readonly') func Test_cpo_Z() let save_cpo = &cpo - call writefile([], 'XfileCpoZ') + call writefile([], 'XfileCpoZ', 'D') new XfileCpoZ setlocal readonly set cpo-=Z @@ -655,8 +650,7 @@ func Test_cpo_Z() setlocal readonly write! call assert_equal(1, &readonly) - close! - call delete('XfileCpoZ') + bw! let &cpo = save_cpo endfunc @@ -710,7 +704,7 @@ func Test_cpo_percent() call assert_equal(15, col('.')) normal 22|% call assert_equal(27, col('.')) - close! + bw! let &cpo = save_cpo endfunc @@ -727,7 +721,7 @@ func Test_cpo_minus() call assert_beeps('normal 10k') call assert_equal(3, line('.')) call assert_fails(10, 'E16:') - close! + bw! let &cpo = save_cpo endfunc @@ -735,7 +729,7 @@ endfunc " flag) func Test_cpo_plus() let save_cpo = &cpo - call writefile([], 'XfileCpoPlus') + call writefile([], 'XfileCpoPlus', 'D') new XfileCpoPlus call setline(1, 'foo') write X1 @@ -743,8 +737,7 @@ func Test_cpo_plus() set cpo+=+ write X2 call assert_equal(0, &modified) - close! - call delete('XfileCpoPlus') + bw! call delete('X1') call delete('X2') let &cpo = save_cpo @@ -762,7 +755,7 @@ func Test_cpo_star() " set cpo+=* " *a " call assert_equal(1, x) - close! + bw! let &cpo = save_cpo endfunc @@ -783,7 +776,7 @@ func Test_cpo_gt() normal gg"Rye normal "Rye call assert_equal("\none\none", @r) - close! + bw! let &cpo = save_cpo endfunc @@ -816,7 +809,7 @@ func Test_cpo_semicolon() call assert_equal('bbb y', getline(4)) call assert_equal('ccc', getline(5)) call assert_equal('ddd yee y', getline(6)) - close! + bw! let &cpo = save_cpo endfunc @@ -842,7 +835,7 @@ func Test_cpo_hash() " call assert_equal(['', 'one', 'two', 'three'], getline(1, '$')) " normal gg2Ozero " call assert_equal(['zero', '', 'one', 'two', 'three'], getline(1, '$')) - close! + bw! let &cpo = save_cpo endfunc @@ -850,7 +843,7 @@ endfunc " loaded and ':preserve' is used. func Test_cpo_ampersand() throw 'Skipped: Nvim does not support cpoptions flag "&"' - call writefile(['one'], 'XfileCpoAmp') + call writefile(['one'], 'XfileCpoAmp', 'D') let after =<< trim [CODE] set cpo+=& preserve @@ -860,7 +853,6 @@ func Test_cpo_ampersand() call assert_equal(1, filereadable('.XfileCpoAmp.swp')) call delete('.XfileCpoAmp.swp') endif - call delete('XfileCpoAmp') endfunc " Test for the '\' flag in 'cpo' (backslash in a [] range in a search pattern) @@ -875,7 +867,7 @@ func Test_cpo_backslash() " set cpo+=\ " exe 'normal gg/[ \-]' .. "\<CR>n" " call assert_equal(2, col('.')) - close! + bw! let &cpo = save_cpo endfunc @@ -898,7 +890,7 @@ func Test_cpo_brace() " call assert_equal(2, line('.')) " normal G{ " call assert_equal(2, line('.')) - close! + bw! let &cpo = save_cpo endfunc @@ -927,7 +919,7 @@ func Test_cpo_dot() call delete('Xfoo') set cpo& - close! + bw! let &cpo = save_cpo endfunc diff --git a/test/old/testdir/test_crash.vim b/test/old/testdir/test_crash.vim index 49e712a901..9aef245026 100644 --- a/test/old/testdir/test_crash.vim +++ b/test/old/testdir/test_crash.vim @@ -113,6 +113,7 @@ endfunc func Test_crash1_2() CheckNotBSD CheckExecutable dash + let g:test_is_flaky = 1 " The following used to crash Vim let opts = #{cmd: 'sh'} @@ -149,22 +150,9 @@ func Test_crash1_2() \ ' ; echo "crash 4: [OK]" >> '.. result .. "\<cr>") call TermWait(buf, 150) - let file = 'crash/poc_ex_substitute' - let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'" - let args = printf(cmn_args, vim, file) - " just make sure it runs, we don't care about the resulting echo - call term_sendkeys(buf, args .. "\<cr>") - " There is no output generated in Github CI for the asan clang build. - " so just skip generating the ouput. - " call term_sendkeys(buf, args .. - " \ ' && echo "crash 5: [OK]" >> '.. result .. "\<cr>") - call TermWait(buf, 150) - " clean up exe buf .. "bw!" - exe "sp " .. result - let expected = [ \ 'crash 1: [OK]', \ 'crash 2: [OK]', @@ -174,10 +162,51 @@ func Test_crash1_2() call assert_equal(expected, getline(1, '$')) bw! - call delete(result) endfunc +" This test just runs various scripts, that caused issues before. +" We are not really asserting anything here, it's just important +" that ASAN does not detect any issues. +func Test_crash1_3() + let vim = GetVimProg() + let buf = RunVimInTerminal('sh', #{cmd: 'sh'}) + + let file = 'crash/poc_ex_substitute' + let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'\<cr>" + let args = printf(cmn_args, vim, file) + call term_sendkeys(buf, args) + call TermWait(buf, 150) + + let file = 'crash/poc_uaf_exec_instructions' + let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'\<cr>" + let args = printf(cmn_args, vim, file) + call term_sendkeys(buf, args) + call TermWait(buf, 150) + + let file = 'crash/poc_uaf_check_argument_types' + let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'\<cr>" + let args = printf(cmn_args, vim, file) + call term_sendkeys(buf, args) + call TermWait(buf, 150) + + let file = 'crash/double_free' + let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'\<cr>" + let args = printf(cmn_args, vim, file) + call term_sendkeys(buf, args) + call TermWait(buf, 50) + + let file = 'crash/dialog_changed_uaf' + let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'\<cr>" + let args = printf(cmn_args, vim, file) + call term_sendkeys(buf, args) + call TermWait(buf, 150) + + " clean up + exe buf .. "bw!" + bw! +endfunc + func Test_crash2() " The following used to crash Vim let opts = #{wait_for_ruler: 0, rows: 20} diff --git a/test/old/testdir/test_cursor_func.vim b/test/old/testdir/test_cursor_func.vim index 5d99963814..99af0ab359 100644 --- a/test/old/testdir/test_cursor_func.vim +++ b/test/old/testdir/test_cursor_func.vim @@ -279,6 +279,21 @@ func Test_screenpos_number() bwipe! endfunc +func Test_screenpos_edit_newfile() + new + 20vsp + setl nowrap + call setline(1, 'abcdefghijklmnopqrstuvwxyz') + call cursor(1, 10) + norm! 5zl + call assert_equal(#{col: 5, row: 1, endcol: 5, curscol: 5}, screenpos(win_getid(), 1, 10)) + enew! + call assert_equal(1, &l:wrap) + call assert_equal(#{col: 1, row: 1, endcol: 1, curscol: 1}, screenpos(win_getid(), 1, 1)) + + bwipe! +endfunc + " Save the visual start character position func SaveVisualStartCharPos() call add(g:VisualStartPos, getcharpos('v')) diff --git a/test/old/testdir/test_cursorline.vim b/test/old/testdir/test_cursorline.vim index 99a812b1de..2c375f20c0 100644 --- a/test/old/testdir/test_cursorline.vim +++ b/test/old/testdir/test_cursorline.vim @@ -262,14 +262,34 @@ func Test_cursorline_callback() call timer_start(300, 'Func') END - call writefile(lines, 'Xcul_timer') + call writefile(lines, 'Xcul_timer', 'D') let buf = RunVimInTerminal('-S Xcul_timer', #{rows: 8}) call TermWait(buf, 310) call VerifyScreenDump(buf, 'Test_cursorline_callback_1', {}) call StopVimInTerminal(buf) - call delete('Xcul_timer') +endfunc + +func Test_cursorline_screenline_resize() + CheckScreendump + + let lines =<< trim END + 50vnew + call setline(1, repeat('xyz ', 30)) + setlocal number cursorline cursorlineopt=screenline + normal! $ + END + call writefile(lines, 'Xcul_screenline_resize', 'D') + + let buf = RunVimInTerminal('-S Xcul_screenline_resize', #{rows: 8}) + call VerifyScreenDump(buf, 'Test_cursorline_screenline_resize_1', {}) + call term_sendkeys(buf, ":vertical resize -4\<CR>") + call VerifyScreenDump(buf, 'Test_cursorline_screenline_resize_2', {}) + call term_sendkeys(buf, ":set cpoptions+=n\<CR>") + call VerifyScreenDump(buf, 'Test_cursorline_screenline_resize_3', {}) + + call StopVimInTerminal(buf) endfunc func Test_cursorline_screenline_update() @@ -280,7 +300,7 @@ func Test_cursorline_screenline_update() set cursorline cursorlineopt=screenline inoremap <F2> <Cmd>call cursor(1, 1)<CR> END - call writefile(lines, 'Xcul_screenline') + call writefile(lines, 'Xcul_screenline', 'D') let buf = RunVimInTerminal('-S Xcul_screenline', #{rows: 8}) call term_sendkeys(buf, "A") @@ -290,7 +310,17 @@ func Test_cursorline_screenline_update() call term_sendkeys(buf, "\<Esc>") call StopVimInTerminal(buf) - call delete('Xcul_screenline') +endfunc + +func Test_cursorline_screenline_zero_width() + CheckOption foldcolumn + + set cursorline culopt=screenline winminwidth=1 foldcolumn=1 + " This used to crash Vim + 1vnew | redraw + + bwipe! + set cursorline& culopt& winminwidth& foldcolumn& endfunc func Test_cursorline_cursorbind_horizontal_scroll() diff --git a/test/old/testdir/test_debugger.vim b/test/old/testdir/test_debugger.vim index ad03443cb4..3a469e8a17 100644 --- a/test/old/testdir/test_debugger.vim +++ b/test/old/testdir/test_debugger.vim @@ -524,7 +524,7 @@ func Test_Backtrace_Through_Source() call RunDbgCmd( buf, 'down', [ 'frame is zero' ] ) - " step until we have another meaninfgul trace + " step until we have another meaningful trace call RunDbgCmd(buf, 'step', ['line 5: func File2Function()']) call RunDbgCmd(buf, 'step', ['line 9: call File2Function()']) call RunDbgCmd(buf, 'backtrace', [ @@ -611,7 +611,7 @@ func Test_Backtrace_Autocmd() \ ['cmd: doautocmd User TestGlobalFunction']) call RunDbgCmd(buf, 'step', ['cmd: call GlobalFunction() | echo "Done"']) - " At this point the ontly thing in the stack is the autocommand + " At this point the only thing in the stack is the autocommand call RunDbgCmd(buf, 'backtrace', [ \ '>backtrace', \ '->0 User Autocommands for "TestGlobalFunction"', @@ -741,7 +741,7 @@ func Test_Backtrace_Autocmd() call RunDbgCmd( buf, 'down', [ 'frame is zero' ] ) - " step until we have another meaninfgul trace + " step until we have another meaningful trace call RunDbgCmd(buf, 'step', ['line 5: func File2Function()']) call RunDbgCmd(buf, 'step', ['line 9: call File2Function()']) call RunDbgCmd(buf, 'backtrace', [ @@ -867,7 +867,7 @@ func Test_Backtrace_CmdLine() call CheckDbgOutput(buf, ['command line', \ 'cmd: call GlobalFunction()'], #{msec: 5000}) - " At this point the ontly thing in the stack is the cmdline + " At this point the only thing in the stack is the cmdline call RunDbgCmd(buf, 'backtrace', [ \ '>backtrace', \ '->0 command line', @@ -1285,7 +1285,7 @@ func Test_debug_backtrace_level() \ #{ match: 'pattern' } ) " Expression evaluation in the script frame (not the function frame) - " FIXME: Unexpected in this scope (a: should not be visibnle) + " FIXME: Unexpected in this scope (a: should not be visible) call RunDbgCmd(buf, 'echo a:arg', [ 'arg1' ] ) call RunDbgCmd(buf, 'echo s:file1_var', [ 'file1' ] ) call RunDbgCmd(buf, 'echo g:global_var', [ 'global' ] ) diff --git a/test/old/testdir/test_diffmode.vim b/test/old/testdir/test_diffmode.vim index 71483b7469..a448ed9b7f 100644 --- a/test/old/testdir/test_diffmode.vim +++ b/test/old/testdir/test_diffmode.vim @@ -276,7 +276,7 @@ func Test_diffget_diffput_empty_buffer() endfunc " :diffput and :diffget completes names of buffers which -" are in diff mode and which are different then current buffer. +" are in diff mode and which are different than current buffer. " No completion when the current window is not in diff mode. func Test_diffget_diffput_completion() e Xdiff1 | diffthis @@ -679,7 +679,7 @@ func Test_diffexpr() call assert_notequal(normattr, screenattr(3, 1)) diffoff! - " Try using an non-existing function for 'diffexpr'. + " Try using a non-existing function for 'diffexpr'. set diffexpr=NewDiffFunc() call assert_fails('windo diffthis', ['E117:', 'E97:']) diffoff! @@ -830,6 +830,15 @@ func WriteDiffFiles(buf, list1, list2) endif endfunc +func WriteDiffFiles3(buf, list1, list2, list3) + call writefile(a:list1, 'Xdifile1') + call writefile(a:list2, 'Xdifile2') + call writefile(a:list3, 'Xdifile3') + if a:buf + call term_sendkeys(a:buf, ":checktime\<CR>") + endif +endfunc + " Verify a screendump with both the internal and external diff. func VerifyBoth(buf, dumpfile, extra) " trailing : for leaving the cursor on the command line @@ -997,9 +1006,17 @@ func Test_diff_screen() call WriteDiffFiles(buf, ['a ', 'x', 'cd', 'ef', 'xx xx', 'foo', 'bar'], ['a', 'x', 'c d', ' ef', 'xx xx', 'foo', '', 'bar']) call VerifyInternal(buf, 'Test_diff_19', " diffopt+=iwhiteeol") - " Test 19: test diffopt+=iwhiteall + " Test 20: test diffopt+=iwhiteall call VerifyInternal(buf, 'Test_diff_20', " diffopt+=iwhiteall") + " Test 21: Delete all lines + call WriteDiffFiles(buf, [0], []) + call VerifyBoth(buf, "Test_diff_21", "") + + " Test 22: Add line to empty file + call WriteDiffFiles(buf, [], [0]) + call VerifyBoth(buf, "Test_diff_22", "") + " clean up call StopVimInTerminal(buf) call delete('Xdifile1') @@ -1332,12 +1349,12 @@ endfunc func Test_diff_and_scroll() " this was causing an ml_get error set ls=2 - for i in range(winheight(0) * 2) - call setline(i, i < winheight(0) - 10 ? i : i + 10) + for i in range(winheight(0) * 2) + call setline(i, i < winheight(0) - 10 ? i : i + 10) endfor vnew - for i in range(winheight(0)*2 + 10) - call setline(i, i < winheight(0) - 10 ? 0 : i) + for i in range(winheight(0)*2 + 10) + call setline(i, i < winheight(0) - 10 ? 0 : i) endfor diffthis wincmd p @@ -1791,4 +1808,203 @@ func Test_diff_eob_halfpage() %bwipe! endfunc +func Test_diff_overlapped_diff_blocks_will_be_merged() + CheckScreendump + + let lines =<< trim END + func DiffExprStub() + let txt_in = readfile(v:fname_in) + let txt_new = readfile(v:fname_new) + if txt_in == ["line1"] && txt_new == ["line2"] + call writefile(["1c1"], v:fname_out) + elseif txt_in == readfile("Xdiin1") && txt_new == readfile("Xdinew1") + call writefile(readfile("Xdiout1"), v:fname_out) + elseif txt_in == readfile("Xdiin2") && txt_new == readfile("Xdinew2") + call writefile(readfile("Xdiout2"), v:fname_out) + endif + endfunc + END + call writefile(lines, 'XdiffSetup', 'D') + + call WriteDiffFiles(0, [], []) + let buf = RunVimInTerminal('-d -S XdiffSetup Xdifile1 Xdifile2', {}) + call term_sendkeys(buf, ":set autoread\<CR>\<c-w>w:set autoread\<CR>\<c-w>w") + + call WriteDiffFiles(buf, ["a", "b"], ["x", "x"]) + call writefile(["a", "b"], "Xdiin1") + call writefile(["x", "x"], "Xdinew1") + call writefile(["1c1", "2c2"], "Xdiout1") + call term_sendkeys(buf, ":set diffexpr=DiffExprStub()\<CR>:") + call VerifyBoth(buf, "Test_diff_overlapped_2.01", "") + call term_sendkeys(buf, ":set diffexpr&\<CR>:") + + call WriteDiffFiles(buf, ["a", "b", "c"], ["x", "c"]) + call writefile(["a", "b", "c"], "Xdiin1") + call writefile(["x", "c"], "Xdinew1") + call writefile(["1c1", "2d1"], "Xdiout1") + call term_sendkeys(buf, ":set diffexpr=DiffExprStub()\<CR>:") + call VerifyBoth(buf, "Test_diff_overlapped_2.02", "") + call term_sendkeys(buf, ":set diffexpr&\<CR>:") + + call WriteDiffFiles(buf, ["a", "c"], ["x", "x", "c"]) + call writefile(["a", "c"], "Xdiin1") + call writefile(["x", "x", "c"], "Xdinew1") + call writefile(["1c1", "1a2"], "Xdiout1") + call term_sendkeys(buf, ":set diffexpr=DiffExprStub()\<CR>:") + call VerifyBoth(buf, "Test_diff_overlapped_2.03", "") + call term_sendkeys(buf, ":set diffexpr&\<CR>:") + + call StopVimInTerminal(buf) + wincmd c + + call WriteDiffFiles3(0, [], [], []) + let buf = RunVimInTerminal('-d -S XdiffSetup Xdifile1 Xdifile2 Xdifile3', {}) + call term_sendkeys(buf, ":set autoread\<CR>\<c-w>w:set autoread\<CR>\<c-w>w:set autoread\<CR>\<c-w>w") + + call WriteDiffFiles3(buf, ["a", "b", "c"], ["a", "x", "c"], ["y", "b", "c"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.01", "") + + call WriteDiffFiles3(buf, ["a", "b", "c"], ["a", "x", "c"], ["a", "y", "c"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.02", "") + + call WriteDiffFiles3(buf, ["a", "b", "c"], ["a", "x", "c"], ["a", "b", "y"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.03", "") + + call WriteDiffFiles3(buf, ["a", "b", "c"], ["a", "x", "c"], ["y", "y", "c"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.04", "") + + call WriteDiffFiles3(buf, ["a", "b", "c"], ["a", "x", "c"], ["a", "y", "y"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.05", "") + + call WriteDiffFiles3(buf, ["a", "b", "c"], ["a", "x", "c"], ["y", "y", "y"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.06", "") + + call WriteDiffFiles3(buf, ["a", "b", "c"], ["a", "x", "x"], ["y", "y", "c"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.07", "") + + call WriteDiffFiles3(buf, ["a", "b", "c"], ["x", "x", "c"], ["a", "y", "y"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.08", "") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d", "e"], ["a", "x", "c", "x", "e"], ["y", "y", "y", "d", "e"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.09", "") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d", "e"], ["a", "x", "c", "x", "e"], ["y", "y", "y", "y", "e"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.10", "") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d", "e"], ["a", "x", "c", "x", "e"], ["y", "y", "y", "y", "y"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.11", "") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d", "e"], ["a", "x", "c", "x", "e"], ["a", "y", "y", "d", "e"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.12", "") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d", "e"], ["a", "x", "c", "x", "e"], ["a", "y", "y", "y", "e"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.13", "") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d", "e"], ["a", "x", "c", "x", "e"], ["a", "y", "y", "y", "y"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.14", "") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d", "e"], ["a", "x", "c", "x", "e"], ["a", "b", "y", "d", "e"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.15", "") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d", "e"], ["a", "x", "c", "x", "e"], ["a", "b", "y", "y", "e"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.16", "") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d", "e"], ["a", "x", "c", "x", "e"], ["a", "b", "y", "y", "y"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.17", "") + + call WriteDiffFiles3(buf, ["a", "b"], ["x", "b"], ["y", "y"]) + call writefile(["a", "b"], "Xdiin1") + call writefile(["x", "b"], "Xdinew1") + call writefile(["1c1"], "Xdiout1") + call writefile(["a", "b"], "Xdiin2") + call writefile(["y", "y"], "Xdinew2") + call writefile(["1c1", "2c2"], "Xdiout2") + call term_sendkeys(buf, ":set diffexpr=DiffExprStub()\<CR>:") + call VerifyInternal(buf, "Test_diff_overlapped_3.18", "") + call term_sendkeys(buf, ":set diffexpr&\<CR>:") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d"], ["x", "b", "x", "d"], ["y", "y", "c", "d"]) + call writefile(["a", "b", "c", "d"], "Xdiin1") + call writefile(["x", "b", "x", "d"], "Xdinew1") + call writefile(["1c1", "3c3"], "Xdiout1") + call writefile(["a", "b", "c", "d"], "Xdiin2") + call writefile(["y", "y", "c", "d"], "Xdinew2") + call writefile(["1c1", "2c2"], "Xdiout2") + call term_sendkeys(buf, ":set diffexpr=DiffExprStub()\<CR>:") + call VerifyInternal(buf, "Test_diff_overlapped_3.19", "") + call term_sendkeys(buf, ":set diffexpr&\<CR>:") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d"], ["x", "b", "x", "d"], ["y", "y", "y", "d"]) + call writefile(["a", "b", "c", "d"], "Xdiin1") + call writefile(["x", "b", "x", "d"], "Xdinew1") + call writefile(["1c1", "3c3"], "Xdiout1") + call writefile(["a", "b", "c", "d"], "Xdiin2") + call writefile(["y", "y", "y", "d"], "Xdinew2") + call writefile(["1c1", "2,3c2,3"], "Xdiout2") + call term_sendkeys(buf, ":set diffexpr=DiffExprStub()\<CR>:") + call VerifyInternal(buf, "Test_diff_overlapped_3.20", "") + call term_sendkeys(buf, ":set diffexpr&\<CR>:") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d"], ["x", "b", "x", "d"], ["y", "y", "y", "y"]) + call writefile(["a", "b", "c", "d"], "Xdiin1") + call writefile(["x", "b", "x", "d"], "Xdinew1") + call writefile(["1c1", "3c3"], "Xdiout1") + call writefile(["a", "b", "c", "d"], "Xdiin2") + call writefile(["y", "y", "y", "y"], "Xdinew2") + call writefile(["1c1", "2,4c2,4"], "Xdiout2") + call term_sendkeys(buf, ":set diffexpr=DiffExprStub()\<CR>:") + call VerifyInternal(buf, "Test_diff_overlapped_3.21", "") + call term_sendkeys(buf, ":set diffexpr&\<CR>:") + + call WriteDiffFiles3(buf, ["a", "b", "c"], ["a", "x", "c"], ["b", "c"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.22", "") + + call WriteDiffFiles3(buf, ["a", "b", "c"], ["a", "x", "c"], ["c"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.23", "") + + call WriteDiffFiles3(buf, ["a", "b", "c"], ["a", "x", "c"], []) + call VerifyBoth(buf, "Test_diff_overlapped_3.24", "") + + call WriteDiffFiles3(buf, ["a", "b", "c"], ["a", "x", "c"], ["a", "c"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.25", "") + + call WriteDiffFiles3(buf, ["a", "b", "c"], ["a", "x", "c"], ["a"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.26", "") + + call WriteDiffFiles3(buf, ["a", "b", "c"], ["a", "x", "c"], ["b"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.27", "") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d", "e"], ["a", "x", "c", "x", "e"], ["d", "e"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.28", "") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d", "e"], ["a", "x", "c", "x", "e"], ["e"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.29", "") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d", "e"], ["a", "x", "c", "x", "e"], ["a", "d", "e"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.30", "") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d", "e"], ["a", "x", "c", "x", "e"], ["a", "e"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.31", "") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d", "e"], ["a", "x", "c", "x", "e"], ["a"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.32", "") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d", "e"], ["a", "x", "c", "x", "e"], ["a", "b", "d", "e"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.33", "") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d", "e"], ["a", "x", "c", "x", "e"], ["a", "b", "e"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.34", "") + + call WriteDiffFiles3(buf, ["a", "b", "c", "d", "e"], ["a", "x", "c", "x", "e"], ["a", "b"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.35", "") + + call WriteDiffFiles3(buf, ["a", "b", "c"], ["a", "x", "c"], ["a", "y", "b", "c"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.36", "") + + call WriteDiffFiles3(buf, ["a", "b", "c"], ["a", "x", "c"], ["a", "b", "y", "c"]) + call VerifyBoth(buf, "Test_diff_overlapped_3.37", "") + + call StopVimInTerminal(buf) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_edit.vim b/test/old/testdir/test_edit.vim index 57ff63f26d..037282bf1a 100644 --- a/test/old/testdir/test_edit.vim +++ b/test/old/testdir/test_edit.vim @@ -1973,6 +1973,11 @@ func Test_edit_insert_reg() let @r = 'sample' call feedkeys("a\<C-R>=SaveFirstLine()\<CR>", "xt") call assert_equal('"', g:Line) + + " Test for inserting an null and an empty list + call feedkeys("a\<C-R>=test_null_list()\<CR>", "xt") + call feedkeys("a\<C-R>=[]\<CR>", "xt") + call assert_equal(['r'], getbufline('', 1, '$')) call test_override('ALL', 0) close! endfunc @@ -2112,7 +2117,7 @@ func Test_edit_overlong_file_name() file %%%%%%%%%%%%%%%%%%%%%%%%%% file %%%%%% set readonly - set ls=2 + set ls=2 redraw! set noreadonly ls& diff --git a/test/old/testdir/test_ex_mode.vim b/test/old/testdir/test_ex_mode.vim index 42f08868a0..32b01fef9e 100644 --- a/test/old/testdir/test_ex_mode.vim +++ b/test/old/testdir/test_ex_mode.vim @@ -69,7 +69,7 @@ func Test_Ex_substitute() CheckRunVimInTerminal let buf = RunVimInTerminal('', {'rows': 6}) - call term_sendkeys(buf, ":call setline(1, ['foo foo', 'foo foo', 'foo foo'])\<CR>") + call term_sendkeys(buf, ":call setline(1, repeat(['foo foo'], 4))\<CR>") call term_sendkeys(buf, ":set number\<CR>") call term_sendkeys(buf, "gQ") call WaitForAssert({-> assert_match(':', term_getline(buf, 6))}, 1000) @@ -91,8 +91,14 @@ func Test_Ex_substitute() " Pressing enter in ex mode should print the current line call term_sendkeys(buf, "\<CR>") - call WaitForAssert({-> assert_match(' 3 foo foo', - \ term_getline(buf, 5))}, 1000) + call WaitForAssert({-> assert_match(' 3 foo foo', term_getline(buf, 5))}, 1000) + call WaitForAssert({-> assert_match(':', term_getline(buf, 6))}, 1000) + + " The printed line should overwrite the colon + call term_sendkeys(buf, "\<CR>") + call WaitForAssert({-> assert_match(' 3 foo foo', term_getline(buf, 4))}, 1000) + call WaitForAssert({-> assert_match(' 4 foo foo', term_getline(buf, 5))}, 1000) + call WaitForAssert({-> assert_match(':', term_getline(buf, 6))}, 1000) call term_sendkeys(buf, ":vi\<CR>") call WaitForAssert({-> assert_match('foo bar', term_getline(buf, 1))}, 1000) @@ -282,4 +288,48 @@ func Test_ex_mode_large_indent() endfunc +" Testing implicit print command +func Test_implicit_print() + new + call setline(1, ['one', 'two', 'three']) + call feedkeys('Q:let a=execute(":1,2")', 'xt') + call feedkeys('Q:let b=execute(":3")', 'xt') + call assert_equal('one two', a->split('\n')->join(' ')) + call assert_equal('three', b->split('\n')->join(' ')) + bw! +endfunc + +" Test inserting text after the trailing bar +func Test_insert_after_trailing_bar() + new + call feedkeys("Qi|\nfoo\n.\na|bar\nbar\n.\nc|baz\n.", "xt") + call assert_equal(['', 'foo', 'bar', 'baz'], getline(1, '$')) + bwipe! +endfunc + +" Test global insert of a newline without terminating period +func Test_global_insert_newline() + new + call setline(1, ['foo']) + call feedkeys("Qg/foo/i\\\n", "xt") + call assert_equal(['', 'foo'], getline(1, '$')) + bwipe! +endfunc + +" An empty command followed by a newline shouldn't cause E749 in Ex mode. +func Test_ex_empty_command_newline() + let g:var = 0 + call feedkeys("gQexecute \"\\nlet g:var = 1\"\r", 'xt') + call assert_equal(1, g:var) + call feedkeys("gQexecute \" \\nlet g:var = 2\"\r", 'xt') + call assert_equal(2, g:var) + call feedkeys("gQexecute \"\\t \\nlet g:var = 3\"\r", 'xt') + call assert_equal(3, g:var) + call feedkeys("gQexecute \"\\\"?!\\nlet g:var = 4\"\r", 'xt') + call assert_equal(4, g:var) + call feedkeys("gQexecute \" \\\"?!\\nlet g:var = 5\"\r", 'xt') + call assert_equal(5, g:var) + unlet g:var +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_excmd.vim b/test/old/testdir/test_excmd.vim index 4a780078fd..50e5080f60 100644 --- a/test/old/testdir/test_excmd.vim +++ b/test/old/testdir/test_excmd.vim @@ -665,7 +665,7 @@ func Sandbox_tests() if has('clientserver') call assert_fails('let s=remote_expr("gvim", "2+2")', 'E48:') if !has('win32') - " remote_foreground() doesn't thrown an error message on MS-Windows + " remote_foreground() doesn't throw an error message on MS-Windows call assert_fails('call remote_foreground("gvim")', 'E48:') endif call assert_fails('let s=remote_peek("gvim")', 'E48:') @@ -718,15 +718,20 @@ func Test_not_break_expression_register() endfunc func Test_address_line_overflow() - throw 'Skipped: v:sizeoflong is N/A' " use legacy/excmd_spec.lua instead - - if v:sizeoflong < 8 + if !has('nvim') && v:sizeoflong < 8 throw 'Skipped: only works with 64 bit long ints' endif new - call setline(1, 'text') + call setline(1, range(100)) call assert_fails('|.44444444444444444444444', 'E1247:') call assert_fails('|.9223372036854775806', 'E1247:') + call assert_fails('.44444444444444444444444d', 'E1247:') + call assert_equal(range(100)->map('string(v:val)'), getline(1, '$')) + + $ + yank 77777777777777777777 + call assert_equal("99\n", @") + bwipe! endfunc diff --git a/test/old/testdir/test_expand_func.vim b/test/old/testdir/test_expand_func.vim index 454d76f0aa..12750baf67 100644 --- a/test/old/testdir/test_expand_func.vim +++ b/test/old/testdir/test_expand_func.vim @@ -7,15 +7,15 @@ let s:slnum = str2nr(expand('<slnum>')) let s:sflnum = str2nr(expand('<sflnum>')) func s:expand_sfile() - return expand('<sfile>') + return expand('<sfile>') endfunc func s:expand_slnum() - return str2nr(expand('<slnum>')) + return str2nr(expand('<slnum>')) endfunc func s:expand_sflnum() - return str2nr(expand('<sflnum>')) + return str2nr(expand('<sflnum>')) endfunc " This test depends on the location in the test file, put it first. diff --git a/test/old/testdir/test_filecopy.vim b/test/old/testdir/test_filecopy.vim new file mode 100644 index 0000000000..b526dce7b8 --- /dev/null +++ b/test/old/testdir/test_filecopy.vim @@ -0,0 +1,72 @@ +" Test filecopy() + +source check.vim +source shared.vim + +func Test_copy_file_to_file() + call writefile(['foo'], 'Xcopy1') + + call assert_true(filecopy('Xcopy1', 'Xcopy2')) + + call assert_equal(['foo'], readfile('Xcopy2')) + + " When the destination file already exists, it should not be overwritten. + call writefile(['foo'], 'Xcopy1') + call writefile(['bar'], 'Xcopy2', 'D') + call assert_false(filecopy('Xcopy1', 'Xcopy2')) + call assert_equal(['bar'], readfile('Xcopy2')) + + call delete('Xcopy2') + call delete('Xcopy1') +endfunc + +func Test_copy_symbolic_link() + CheckUnix + + call writefile(['text'], 'Xtestfile', 'D') + silent !ln -s -f Xtestfile Xtestlink + + call assert_true(filecopy('Xtestlink', 'Xtestlink2')) + call assert_equal('link', getftype('Xtestlink2')) + call assert_equal(['text'], readfile('Xtestlink2')) + + " When the destination file already exists, it should not be overwritten. + call assert_false(filecopy('Xtestlink', 'Xtestlink2')) + + call delete('Xtestlink2') + call delete('Xtestlink') + call delete('Xtestfile') +endfunc + +func Test_copy_dir_to_dir() + call mkdir('Xcopydir1') + call writefile(['foo'], 'Xcopydir1/Xfilecopy') + call mkdir('Xcopydir2') + + " Directory copy is not supported + call assert_false(filecopy('Xcopydir1', 'Xcopydir2')) + + call delete('Xcopydir2', 'rf') + call delete('Xcopydir1', 'rf') +endfunc + +func Test_copy_fails() + CheckUnix + + call writefile(['foo'], 'Xfilecopy', 'D') + + " Can't copy into a non-existing directory. + call assert_false(filecopy('Xfilecopy', 'Xdoesnotexist/Xfilecopy')) + + " Can't copy a non-existing file. + call assert_false(filecopy('Xdoesnotexist', 'Xfilecopy2')) + call assert_equal('', glob('Xfilecopy2')) + + " Can't copy to en empty file name. + call assert_false(filecopy('Xfilecopy', '')) + + call assert_fails('call filecopy("Xfilecopy", [])', 'E1174:') + call assert_fails('call filecopy(0z, "Xfilecopy")', 'E1174:') +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim index 34fe93fd55..d99656be47 100644 --- a/test/old/testdir/test_filetype.vim +++ b/test/old/testdir/test_filetype.vim @@ -96,6 +96,7 @@ func s:GetFilenameChecks() abort \ 'aml': ['file.aml'], \ 'ampl': ['file.run'], \ 'ant': ['build.xml'], + \ 'antlr4': ['parser.g4'], \ 'apache': ['.htaccess', '/etc/httpd/file.conf', '/etc/apache2/sites-2/file.com', '/etc/apache2/some.config', '/etc/apache2/conf.file/conf', '/etc/apache2/mods-some/file', '/etc/apache2/sites-some/file', '/etc/httpd/conf.d/file.config', '/etc/apache2/conf.file/file', '/etc/apache2/file.conf', '/etc/apache2/file.conf-file', '/etc/apache2/mods-file/file', '/etc/apache2/sites-file/file', '/etc/apache2/sites-file/file.com', '/etc/httpd/conf.d/file.conf', '/etc/httpd/conf.d/file.conf-file', 'access.conf', 'access.conf-file', 'any/etc/apache2/conf.file/file', 'any/etc/apache2/file.conf', 'any/etc/apache2/file.conf-file', 'any/etc/apache2/mods-file/file', 'any/etc/apache2/sites-file/file', 'any/etc/apache2/sites-file/file.com', 'any/etc/httpd/conf.d/file.conf', 'any/etc/httpd/conf.d/file.conf-file', 'any/etc/httpd/file.conf', 'apache.conf', 'apache.conf-file', 'apache2.conf', 'apache2.conf-file', 'httpd.conf', 'httpd.conf-file', 'srm.conf', 'srm.conf-file', '/etc/httpd/mods-some/file', '/etc/httpd/sites-some/file', '/etc/httpd/conf.file/conf'], \ 'apachestyle': ['/etc/proftpd/file.config,/etc/proftpd/conf.file/file', '/etc/proftpd/conf.file/file', '/etc/proftpd/file.conf', '/etc/proftpd/file.conf-file', 'any/etc/proftpd/conf.file/file', 'any/etc/proftpd/file.conf', 'any/etc/proftpd/file.conf-file', 'proftpd.conf', 'proftpd.conf-file'], \ 'applescript': ['file.scpt'], @@ -107,6 +108,7 @@ func s:GetFilenameChecks() abort \ 'asn': ['file.asn', 'file.asn1'], \ 'asterisk': ['asterisk/file.conf', 'asterisk/file.conf-file', 'some-asterisk/file.conf', 'some-asterisk/file.conf-file'], \ 'astro': ['file.astro'], + \ 'asy': ['file.asy'], \ 'atlas': ['file.atl', 'file.as'], \ 'authzed': ['schema.zed'], \ 'autohotkey': ['file.ahk'], @@ -122,7 +124,7 @@ func s:GetFilenameChecks() abort \ 'beancount': ['file.beancount'], \ 'bib': ['file.bib'], \ 'bicep': ['file.bicep', 'file.bicepparam'], - \ 'bindzone': ['named.root', '/bind/db.file', '/named/db.file', 'any/bind/db.file', 'any/named/db.file'], + \ 'bindzone': ['named.root', '/bind/db.file', '/named/db.file', 'any/bind/db.file', 'any/named/db.file', 'foobar.zone'], \ 'bitbake': ['file.bb', 'file.bbappend', 'file.bbclass', 'build/conf/local.conf', 'meta/conf/layer.conf', 'build/conf/bbappend.conf', 'meta-layer/conf/distro/foo.conf'], \ 'blade': ['file.blade.php'], \ 'blank': ['file.bl'], @@ -143,6 +145,7 @@ func s:GetFilenameChecks() abort \ 'cdl': ['file.cdl'], \ 'cdrdaoconf': ['/etc/cdrdao.conf', '/etc/defaults/cdrdao', '/etc/default/cdrdao', '.cdrdao', 'any/etc/cdrdao.conf', 'any/etc/default/cdrdao', 'any/etc/defaults/cdrdao'], \ 'cdrtoc': ['file.toc'], + \ 'cedar': ['file.cedar'], \ 'cf': ['file.cfm', 'file.cfi', 'file.cfc'], \ 'cfengine': ['cfengine.conf'], \ 'cfg': ['file.hgrc', 'filehgrc', 'hgrc', 'some-hgrc'], @@ -161,7 +164,7 @@ func s:GetFilenameChecks() abort \ 'cmakecache': ['CMakeCache.txt'], \ 'cmod': ['file.cmod'], \ 'cmusrc': ['any/.cmus/autosave', 'any/.cmus/rc', 'any/.cmus/command-history', 'any/.cmus/file.theme', 'any/cmus/rc', 'any/cmus/file.theme', '/.cmus/autosave', '/.cmus/command-history', '/.cmus/file.theme', '/.cmus/rc', '/cmus/file.theme', '/cmus/rc'], - \ 'cobol': ['file.cbl', 'file.cob', 'file.lib'], + \ 'cobol': ['file.cbl', 'file.cob'], \ 'coco': ['file.atg'], \ 'conaryrecipe': ['file.recipe'], \ 'conf': ['auto.master', 'file.conf', 'texdoc.cnf', '.x11vncrc', '.chktexrc', '.ripgreprc', 'ripgreprc', 'file.ctags', '.mbsyncrc'], @@ -221,13 +224,14 @@ func s:GetFilenameChecks() abort \ '.coveragerc', '.pypirc', '.gitlint', '.oelint.cfg', 'pylintrc', '.pylintrc', \ '/home/user/.config/bpython/config', '/home/user/.config/mypy/config', '.wakatime.cfg', '.replyrc', \ 'psprint.conf', 'sofficerc', 'any/.config/lxqt/globalkeyshortcuts.conf', 'any/.config/screengrab/screengrab.conf', - \ 'any/.local/share/flatpak/repo/config', '.notmuch-config'], + \ 'any/.local/share/flatpak/repo/config', '.notmuch-config', '.notmuch-config.myprofile', + \ '~/.config/notmuch/myprofile/config'] + s:WhenConfigHome('$XDG_CONFIG_HOME/notmuch/myprofile/config'), \ 'dot': ['file.dot', 'file.gv'], - \ 'dracula': ['file.drac', 'file.drc', 'filelvs', 'filelpe', 'drac.file', 'lpe', 'lvs', 'some-lpe', 'some-lvs'], + \ 'dracula': ['file.drac', 'file.drc', 'file.lvs', 'file.lpe', 'drac.file'], \ 'dtd': ['file.dtd'], \ 'dtrace': ['/usr/lib/dtrace/io.d'], \ 'dts': ['file.dts', 'file.dtsi', 'file.dtso', 'file.its', 'file.keymap'], - \ 'dune': ['jbuild', 'dune', 'dune-project', 'dune-workspace'], + \ 'dune': ['jbuild', 'dune', 'dune-project', 'dune-workspace', 'dune-file'], \ 'dylan': ['file.dylan'], \ 'dylanintr': ['file.intr'], \ 'dylanlid': ['file.lid'], @@ -257,6 +261,7 @@ func s:GetFilenameChecks() abort \ 'factor': ['file.factor'], \ 'falcon': ['file.fal'], \ 'fan': ['file.fan', 'file.fwt'], + \ 'faust': ['file.dsp', 'file.lib'], \ 'fennel': ['file.fnl'], \ 'fetchmail': ['.fetchmailrc'], \ 'fgl': ['file.4gl', 'file.4gh', 'file.m4gl'], @@ -286,17 +291,18 @@ func s:GetFilenameChecks() abort \ 'gitattributes': ['file.git/info/attributes', '.gitattributes', '/.config/git/attributes', '/etc/gitattributes', '/usr/local/etc/gitattributes', 'some.git/info/attributes'] + s:WhenConfigHome('$XDG_CONFIG_HOME/git/attributes'), \ 'gitcommit': ['COMMIT_EDITMSG', 'MERGE_MSG', 'TAG_EDITMSG', 'NOTES_EDITMSG', 'EDIT_DESCRIPTION'], \ 'gitconfig': ['file.git/config', 'file.git/config.worktree', 'file.git/worktrees/x/config.worktree', '.gitconfig', '.gitmodules', 'file.git/modules//config', '/.config/git/config', '/etc/gitconfig', '/usr/local/etc/gitconfig', '/etc/gitconfig.d/file', 'any/etc/gitconfig.d/file', '/.gitconfig.d/file', 'any/.config/git/config', 'any/.gitconfig.d/file', 'some.git/config', 'some.git/modules/any/config'] + s:WhenConfigHome('$XDG_CONFIG_HOME/git/config'), - \ 'gitignore': ['file.git/info/exclude', '.gitignore', '/.config/git/ignore', 'some.git/info/exclude'] + s:WhenConfigHome('$XDG_CONFIG_HOME/git/ignore'), + \ 'gitignore': ['file.git/info/exclude', '.gitignore', '/.config/git/ignore', 'some.git/info/exclude'] + s:WhenConfigHome('$XDG_CONFIG_HOME/git/ignore') + ['.prettierignore'], \ 'gitolite': ['gitolite.conf', '/gitolite-admin/conf/file', 'any/gitolite-admin/conf/file'], \ 'gitrebase': ['git-rebase-todo'], \ 'gitsendemail': ['.gitsendemail.msg.xxxxxx'], \ 'gkrellmrc': ['gkrellmrc', 'gkrellmrc_x'], \ 'gleam': ['file.gleam'], - \ 'glsl': ['file.glsl'], + \ 'glsl': ['file.glsl', 'file.vert', 'file.tesc', 'file.tese', 'file.geom', 'file.frag', 'file.comp', 'file.rgen', 'file.rmiss', 'file.rchit', 'file.rahit', 'file.rint', 'file.rcall'], \ 'gn': ['file.gn', 'file.gni'], \ 'gnash': ['gnashrc', '.gnashrc', 'gnashpluginrc', '.gnashpluginrc'], \ 'gnuplot': ['file.gpi', '.gnuplot', 'file.gnuplot', '.gnuplot_history'], \ 'go': ['file.go'], + \ 'goaccess': ['goaccess.conf'], \ 'gomod': ['go.mod'], \ 'gosum': ['go.sum', 'go.work.sum'], \ 'gowork': ['go.work'], @@ -334,6 +340,7 @@ func s:GetFilenameChecks() abort \ 'hostconf': ['/etc/host.conf', 'any/etc/host.conf'], \ 'hostsaccess': ['/etc/hosts.allow', '/etc/hosts.deny', 'any/etc/hosts.allow', 'any/etc/hosts.deny'], \ 'html': ['file.html', 'file.htm', 'file.cshtml', 'file.component.html'], + \ 'http': ['file.http'], \ 'htmlm4': ['file.html.m4'], \ 'httest': ['file.htt', 'file.htb'], \ 'hurl': ['file.hurl'], @@ -356,16 +363,17 @@ func s:GetFilenameChecks() abort \ 'janet': ['file.janet'], \ 'java': ['file.java', 'file.jav'], \ 'javacc': ['file.jj', 'file.jjt'], - \ 'javascript': ['file.js', 'file.jsm', 'file.javascript', 'file.es', 'file.mjs', 'file.cjs', '.node_repl_history'], + \ 'javascript': ['file.js', 'file.jsm', 'file.javascript', 'file.es', 'file.mjs', 'file.cjs', '.node_repl_history', '.bun_repl_history', 'deno_history.txt'], \ 'javascript.glimmer': ['file.gjs'], \ 'javascriptreact': ['file.jsx'], \ 'jess': ['file.clp'], \ 'jgraph': ['file.jgr'], + \ 'jinja': ['file.jinja'], \ 'jj': ['file.jjdescription'], \ 'jq': ['file.jq'], \ 'jovial': ['file.jov', 'file.j73', 'file.jovial'], \ 'jproperties': ['file.properties', 'file.properties_xx', 'file.properties_xx_xx', 'some.properties_xx_xx_file', 'org.eclipse.xyz.prefs'], - \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.geojson', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', 'file.jupyterlab-settings', '.prettierrc', '.firebaserc', '.stylelintrc', 'file.slnf', 'file.sublime-project', 'file.sublime-settings', 'file.sublime-workspace', 'file.bd', 'file.bda', 'file.xci', 'flake.lock'], + \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.geojson', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', 'file.jupyterlab-settings', '.prettierrc', '.firebaserc', '.stylelintrc', '.lintstagedrc', 'file.slnf', 'file.sublime-project', 'file.sublime-settings', 'file.sublime-workspace', 'file.bd', 'file.bda', 'file.xci', 'flake.lock', 'pack.mcmeta', 'deno.lock'], \ 'json5': ['file.json5'], \ 'jsonc': ['file.jsonc', '.babelrc', '.eslintrc', '.jsfmtrc', '.jshintrc', '.jscsrc', '.vsconfig', '.hintrc', '.swrc', 'jsconfig.json', 'tsconfig.json', 'tsconfig.test.json', 'tsconfig-test.json', '.luaurc'], \ 'jsonl': ['file.jsonl'], @@ -384,6 +392,7 @@ func s:GetFilenameChecks() abort \ 'lace': ['file.ace', 'file.ACE'], \ 'latte': ['file.latte', 'file.lte'], \ 'ld': ['file.ld', 'any/usr/lib/aarch64-xilinx-linux/ldscripts/aarch64elf32b.x'], + \ 'ldapconf': ['ldap.conf', '.ldaprc', 'ldaprc'], \ 'ldif': ['file.ldif'], \ 'lean': ['file.lean'], \ 'ledger': ['file.ldg', 'file.ledger', 'file.journal'], @@ -421,18 +430,19 @@ func s:GetFilenameChecks() abort \ 'mail': ['snd.123', '.letter', '.letter.123', '.followup', '.article', '.article.123', 'pico.123', 'mutt-xx-xxx', 'muttng-xx-xxx', 'ae123.txt', 'file.eml', 'reportbug-file'], \ 'mailaliases': ['/etc/mail/aliases', '/etc/aliases', 'any/etc/aliases', 'any/etc/mail/aliases'], \ 'mailcap': ['.mailcap', 'mailcap'], - \ 'make': ['file.mk', 'file.mak', 'file.dsp', 'makefile', 'Makefile', 'makefile-file', 'Makefile-file', 'some-makefile', 'some-Makefile', 'Kbuild'], + \ 'make': ['file.mk', 'file.mak', 'makefile', 'Makefile', 'makefile-file', 'Makefile-file', 'some-makefile', 'some-Makefile', 'Kbuild'], \ 'mallard': ['file.page'], "\ 'man': ['file.man'], \ 'manconf': ['/etc/man.conf', 'man.config', 'any/etc/man.conf'], \ 'map': ['file.map'], \ 'maple': ['file.mv', 'file.mpl', 'file.mws'], \ 'markdown': ['file.markdown', 'file.mdown', 'file.mkd', 'file.mkdn', 'file.mdwn', 'file.md'], - \ 'mason': ['file.mason', 'file.mhtml', 'file.comp'], + \ 'mason': ['file.mason', 'file.mhtml'], \ 'master': ['file.mas', 'file.master'], \ 'matlab': ['file.m'], \ 'maxima': ['file.demo', 'file.dmt', 'file.dm1', 'file.dm2', 'file.dm3', \ 'file.wxm', 'maxima-init.mac'], + \ 'mediawiki': ['file.mw', 'file.wiki'], \ 'mel': ['file.mel'], \ 'mermaid': ['file.mmd', 'file.mmdc', 'file.mermaid'], \ 'meson': ['meson.build', 'meson.options', 'meson_options.txt'], @@ -467,7 +477,7 @@ func s:GetFilenameChecks() abort \ 'mgp': ['file.mgp'], \ 'mib': ['file.mib', 'file.my'], \ 'mix': ['file.mix', 'file.mixal'], - \ 'mma': ['file.nb'], + \ 'mma': ['file.nb', 'file.wl'], \ 'mmp': ['file.mmp'], \ 'modconf': ['/etc/modules.conf', '/etc/modules', '/etc/conf.modules', '/etc/modprobe.file', 'any/etc/conf.modules', 'any/etc/modprobe.file', 'any/etc/modules', 'any/etc/modules.conf'], \ 'modula3': ['file.m3', 'file.mg', 'file.i3', 'file.ig', 'file.lm3'], @@ -523,7 +533,7 @@ func s:GetFilenameChecks() abort \ 'odin': ['file.odin'], \ 'omnimark': ['file.xom', 'file.xin'], \ 'ondir': ['.ondirrc'], - \ 'opam': ['opam', 'file.opam', 'file.opam.template'], + \ 'opam': ['opam', 'file.opam', 'file.opam.template', 'opam.locked', 'file.opam.locked'], \ 'openroad': ['file.or'], \ 'openscad': ['file.scad'], \ 'openvpn': ['file.ovpn', '/etc/openvpn/client/client.conf', '/usr/share/openvpn/examples/server.conf'], @@ -593,6 +603,8 @@ func s:GetFilenameChecks() abort \ 'radiance': ['file.rad', 'file.mat'], \ 'raku': ['file.pm6', 'file.p6', 'file.t6', 'file.pod6', 'file.raku', 'file.rakumod', 'file.rakudoc', 'file.rakutest'], \ 'raml': ['file.raml'], + \ 'rapid': ['file.sysx', 'file.Sysx', 'file.SysX', 'file.SYSx', 'file.SYSX', 'file.modx', 'file.Modx', 'file.ModX', 'file.MODx', 'file.MODX'], + \ 'rasi': ['file.rasi'], \ 'ratpoison': ['.ratpoisonrc', 'ratpoisonrc'], \ 'rbs': ['file.rbs'], \ 'rc': ['file.rc', 'file.rch'], @@ -624,6 +636,7 @@ func s:GetFilenameChecks() abort \ 'rtf': ['file.rtf'], \ 'ruby': ['.irbrc', 'irbrc', '.irb_history', 'irb_history', 'file.rb', 'file.rbw', 'file.gemspec', 'file.ru', 'Gemfile', 'file.builder', 'file.rxml', 'file.rjs', 'file.rant', 'file.rake', 'rakefile', 'Rakefile', 'rantfile', 'Rantfile', 'rakefile-file', 'Rakefile-file', 'Puppetfile', 'Vagrantfile'], \ 'rust': ['file.rs'], + \ 'salt': ['file.sls'], \ 'samba': ['smb.conf'], \ 'sas': ['file.sas'], \ 'sass': ['file.sass'], @@ -645,7 +658,8 @@ func s:GetFilenameChecks() abort \ 'sh': ['.bashrc', '.bash_profile', '.bash-profile', '.bash_logout', '.bash-logout', '.bash_aliases', '.bash-aliases', '.bash_history', '.bash-history', \ '/tmp/bash-fc-3Ozjlw', '/tmp/bash-fc.3Ozjlw', 'PKGBUILD', 'APKBUILD', 'file.bash', '/usr/share/doc/bash-completion/filter.sh', \ '/etc/udev/cdsymlinks.conf', 'any/etc/udev/cdsymlinks.conf', 'file.bats', '.ash_history', 'any/etc/neofetch/config.conf', '.xprofile', - \ 'user-dirs.defaults', 'user-dirs.dirs', 'makepkg.conf', '.makepkg.conf', 'file.mdd', 'file.cygport'], + \ 'user-dirs.defaults', 'user-dirs.dirs', 'makepkg.conf', '.makepkg.conf', 'file.mdd', 'file.cygport', '.env', '.envrc', 'devscripts.conf', + \ '.devscripts'], \ 'sieve': ['file.siv', 'file.sieve'], \ 'sil': ['file.sil'], \ 'simula': ['file.sim'], @@ -669,6 +683,7 @@ func s:GetFilenameChecks() abort \ 'smith': ['file.smt', 'file.smith'], \ 'smithy': ['file.smithy'], \ 'sml': ['file.sml'], + \ 'snakemake': ['file.smk', 'Snakefile'], \ 'snobol4': ['file.sno', 'file.spt'], \ 'solidity': ['file.sol'], \ 'solution': ['file.sln'], @@ -700,7 +715,7 @@ func s:GetFilenameChecks() abort \ 'svg': ['file.svg'], \ 'svn': ['svn-commitfile.tmp', 'svn-commit-file.tmp', 'svn-commit.tmp'], \ 'swayconfig': ['/home/user/.sway/config', '/home/user/.config/sway/config', '/etc/sway/config', '/etc/xdg/sway/config'], - \ 'swift': ['file.swift'], + \ 'swift': ['file.swift', 'file.swiftinterface'], \ 'swiftgyb': ['file.swift.gyb'], \ 'swig': ['file.swg', 'file.swig'], \ 'sysctl': ['/etc/sysctl.conf', '/etc/sysctl.d/file.conf', 'any/etc/sysctl.conf', 'any/etc/sysctl.d/file.conf'], @@ -758,7 +773,7 @@ func s:GetFilenameChecks() abort \ 'teraterm': ['file.ttl'], \ 'terminfo': ['file.ti'], \ 'terraform-vars': ['file.tfvars'], - \ 'tex': ['file.latex', 'file.sty', 'file.dtx', 'file.ltx', 'file.bbl', 'any/.texlive/texmf-config/tex/latex/file/file.cfg', 'file.pgf', 'file.nlo', 'file.nls', 'file.thm', 'file.eps_tex', 'file.pygtex', 'file.pygstyle', 'file.clo', 'file.aux', 'file.brf', 'file.ind', 'file.lof', 'file.loe', 'file.nav', 'file.vrb', 'file.ins', 'file.tikz', 'file.bbx', 'file.cbx', 'file.beamer'], + \ 'tex': ['file.latex', 'file.sty', 'file.dtx', 'file.ltx', 'file.bbl', 'any/.texlive/texmf-config/tex/latex/file/file.cfg', 'file.pgf', 'file.nlo', 'file.nls', 'file.thm', 'file.eps_tex', 'file.pygtex', 'file.pygstyle', 'file.clo', 'file.aux', 'file.brf', 'file.ind', 'file.lof', 'file.loe', 'file.nav', 'file.vrb', 'file.ins', 'file.tikz', 'file.bbx', 'file.cbx', 'file.beamer', 'file.pdf_tex'], \ 'texinfo': ['file.texinfo', 'file.texi', 'file.txi'], \ 'texmf': ['texmf.cnf'], \ 'text': ['file.text', 'file.txt', 'README', 'LICENSE', 'COPYING', 'AUTHORS', '/usr/share/doc/bash-completion/AUTHORS', '/etc/apt/apt.conf.d/README', '/etc/Muttrc.d/README'], @@ -853,6 +868,8 @@ func s:GetFilenameChecks() abort \ 'z8a': ['file.z8a'], \ 'zathurarc': ['zathurarc'], \ 'zig': ['file.zig', 'build.zig.zon'], + \ 'ziggy': ['file.ziggy'], + \ 'ziggy_schema': ['file.ziggy-schema'], \ 'zimbu': ['file.zu'], \ 'zimbutempl': ['file.zut'], \ 'zserio': ['file.zs'], @@ -990,6 +1007,7 @@ func s:GetScriptChecks() abort \ ['#!/path/regina']], \ 'janet': [['#!/path/janet']], \ 'dart': [['#!/path/dart']], + \ 'vim': [['#!/path/vim']], \ } endfunc @@ -1038,7 +1056,8 @@ func Test_emptybuf_ftdetect() call assert_equal('', &filetype) filetype detect call assert_equal('sh', &filetype) - close! + " close the swapfile + bw! endfunc " Test for ':filetype indent on' and ':filetype indent off' commands @@ -1136,15 +1155,14 @@ func Test_cfg_file() unlet g:filetype_cfg " RAPID cfg - let ext = 'cfg' for i in ['EIO', 'MMC', 'MOC', 'PROC', 'SIO', 'SYS'] - call writefile([i .. ':CFG'], 'cfgfile.' .. ext) - execute "split cfgfile." .. ext - call assert_equal('rapid', &filetype) - bwipe! - call delete('cfgfile.' .. ext) - " check different case of file extension - let ext = substitute(ext, '\(\l\)', '\u\1', '') + for ext in ['cfg', 'Cfg', 'CFG'] + call writefile([i .. ':CFG'], 'cfgfile.' .. ext) + execute "split cfgfile." .. ext + call assert_equal('rapid', &filetype) + bwipe! + call delete('cfgfile.' .. ext) + endfor endfor " clean up @@ -1511,6 +1529,41 @@ func Test_git_file() filetype off endfunc +func Test_haredoc_file() + filetype on + call assert_true(mkdir('foo/bar', 'pR')) + + call writefile([], 'README', 'D') + split README + call assert_notequal('haredoc', &filetype) + bwipe! + + let g:filetype_haredoc = 1 + split README + call assert_notequal('haredoc', &filetype) + bwipe! + + call writefile([], 'foo/quux.ha') + split README + call assert_equal('haredoc', &filetype) + bwipe! + call delete('foo/quux.ha') + + call writefile([], 'foo/bar/baz.ha', 'D') + split README + call assert_notequal('haredoc', &filetype) + bwipe! + + let g:haredoc_search_depth = 2 + split README + call assert_equal('haredoc', &filetype) + bwipe! + unlet g:filetype_haredoc + unlet g:haredoc_search_depth + + filetype off +endfunc + func Test_hook_file() filetype on @@ -1527,6 +1580,73 @@ func Test_hook_file() filetype off endfunc +func Test_html_file() + filetype on + + " HTML Angular + let content = ['@for (item of items; track item.name) {', ' <li> {{ item.name }}</li>', '} @empty {', ' <li> There are no items.</li>', '}'] + call writefile(content, 'Xfile.html', 'D') + split Xfile.html + call assert_equal('htmlangular', &filetype) + bwipe! + + " Django Template + let content = ['{% if foobar %}', + \ ' <ul>', + \ ' {% for question in list %}', + \ ' <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>', + \ ' {% endfor %}', + \ ' </ul>', + \ '{% else %}', + \ ' <p>No polls are available.</p>', + \ '{% endif %}'] + call writefile(content, 'Xfile.html', 'D') + split Xfile.html + call assert_equal('htmldjango', &filetype) + bwipe! + + " Super html layout + let content = ['<extend template="base.shtml">', + \ '<title id="title" var="$page.title"></title>', + \ '<head id="head"></head>', + \ '<div id="content">', + \ '</div>'] + call writefile(content, 'Xfile.shtml', 'D') + split Xfile.shtml + call assert_equal('superhtml', &filetype) + bwipe! + + " Super html template + let content = ['<!DOCTYPE html>', + \ '<html>', + \ ' <head id="head">', + \ ' <title id="title">', + \ ' <super>', + \ ' suffix', + \ ' </title>', + \ ' <super>', + \ ' </head>', + \ ' <body>', + \ ' <div id="content">', + \ ' <super>', + \ ' </div>', + \ ' </body>', + \ '</html>'] + call writefile(content, 'Xfile.shtml', 'D') + split Xfile.shtml + call assert_equal('superhtml', &filetype) + bwipe! + + " regular HTML + let content = ['<!DOCTYPE html>', '<html>', ' <head>Foobar</head>', ' <body>Content', ' </body>', '</html>'] + call writefile(content, 'Xfile.html', 'D') + split Xfile.html + call assert_equal('html', &filetype) + bwipe! + + filetype off +endfunc + func Test_m_file() filetype on @@ -2361,6 +2481,32 @@ func Test_typ_file() filetype off endfunc +func Test_dsp_file() + filetype on + + " Microsoft Developer Studio Project file + + call writefile(['# Microsoft Developer Studio Project File'], 'Xfile.dsp', 'D') + split Xfile.dsp + call assert_equal('make', &filetype) + bwipe! + + let g:filetype_dsp = 'make' + split test.dsp + call assert_equal('make', &filetype) + bwipe! + unlet g:filetype_dsp + + " Faust + + call writefile(['this is a fallback'], 'Xfile.dsp') + split Xfile.dsp + call assert_equal('faust', &filetype) + bwipe! + + filetype off +endfunc + func Test_vba_file() filetype on @@ -2469,4 +2615,86 @@ func Test_uci_file() filetype off endfunc +func Test_pro_file() + filetype on + + "Prolog + call writefile([':-module(test/1,'], 'Xfile.pro', 'D') + split Xfile.pro + call assert_equal('prolog', &filetype) + bwipe! + + call writefile(['% comment'], 'Xfile.pro', 'D') + split Xfile.pro + call assert_equal('prolog', &filetype) + bwipe! + + call writefile(['/* multiline comment'], 'Xfile.pro', 'D') + split Xfile.pro + call assert_equal('prolog', &filetype) + bwipe! + + call writefile(['rule(test, 1.7).'], 'Xfile.pro', 'D') + split Xfile.pro + call assert_equal('prolog', &filetype) + bwipe! + + " IDL + call writefile(['x = findgen(100)/10'], 'Xfile.pro', 'D') + split Xfile.pro + call assert_equal('idlang', &filetype) + + filetype off +endfunc + + +func Test_pl_file() + filetype on + + "Prolog + call writefile([':-module(test/1,'], 'Xfile.pl', 'D') + split Xfile.pl + call assert_equal('prolog', &filetype) + bwipe! + + call writefile(['% comment'], 'Xfile.pl', 'D') + split Xfile.pl + call assert_equal('prolog', &filetype) + bwipe! + + call writefile(['/* multiline comment'], 'Xfile.pl', 'D') + split Xfile.pl + call assert_equal('prolog', &filetype) + bwipe! + + call writefile(['rule(test, 1.7).'], 'Xfile.pl', 'D') + split Xfile.pl + call assert_equal('prolog', &filetype) + bwipe! + + " Perl + call writefile(['%data = (1, 2, 3);'], 'Xfile.pl', 'D') + split Xfile.pl + call assert_equal('perl', &filetype) + + filetype off +endfunc + +func Test_make_file() + filetype on + + " Microsoft Makefile + call writefile(['# Makefile for Windows', '!if "$(VIMDLL)" == "yes"'], 'XMakefile.mak', 'D') + split XMakefile.mak + call assert_equal(1, get(b:, 'make_microsoft', 0)) + bwipe! + + call writefile(['# get the list of tests', 'include testdir/Make_all.mak'], 'XMakefile.mak', 'D') + split XMakefile.mak + call assert_equal(0, get(b:, 'make_microsoft', 0)) + bwipe! + + filetype off +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_findfile.vim b/test/old/testdir/test_findfile.vim index 0f4b30aec2..06d781ed69 100644 --- a/test/old/testdir/test_findfile.vim +++ b/test/old/testdir/test_findfile.vim @@ -1,14 +1,14 @@ " Test findfile() and finddir() -let s:files = [ 'Xdir1/foo', - \ 'Xdir1/bar', - \ 'Xdir1/Xdir2/foo', - \ 'Xdir1/Xdir2/foobar', - \ 'Xdir1/Xdir2/Xdir3/bar', - \ 'Xdir1/Xdir2/Xdir3/barfoo' ] +let s:files = [ 'Xfinddir1/foo', + \ 'Xfinddir1/bar', + \ 'Xfinddir1/Xdir2/foo', + \ 'Xfinddir1/Xdir2/foobar', + \ 'Xfinddir1/Xdir2/Xdir3/bar', + \ 'Xfinddir1/Xdir2/Xdir3/barfoo' ] func CreateFiles() - call mkdir('Xdir1/Xdir2/Xdir3/Xdir2', 'p') + call mkdir('Xfinddir1/Xdir2/Xdir3/Xdir2', 'p') for f in s:files call writefile([], f) endfor @@ -16,15 +16,15 @@ endfunc func CleanFiles() " Safer to delete each file even if it's more verbose - " than doing a recursive delete('Xdir1', 'rf'). + " than doing a recursive delete('Xfinddir1', 'rf'). for f in s:files call delete(f) endfor - call delete('Xdir1/Xdir2/Xdir3/Xdir2', 'd') - call delete('Xdir1/Xdir2/Xdir3', 'd') - call delete('Xdir1/Xdir2', 'd') - call delete('Xdir1', 'd') + call delete('Xfinddir1/Xdir2/Xdir3/Xdir2', 'd') + call delete('Xfinddir1/Xdir2/Xdir3', 'd') + call delete('Xfinddir1/Xdir2', 'd') + call delete('Xfinddir1', 'd') endfunc " Test findfile({name} [, {path} [, {count}]]) @@ -34,7 +34,7 @@ func Test_findfile() let save_dir = getcwd() set shellslash call CreateFiles() - cd Xdir1 + cd Xfinddir1 e Xdir2/foo " With ,, in path, findfile() searches in current directory. @@ -83,34 +83,68 @@ func Test_findfile() " Test upwards search. cd Xdir2/Xdir3 call assert_equal('bar', findfile('bar', ';')) - call assert_match('.*/Xdir1/Xdir2/foo', findfile('foo', ';')) - call assert_match('.*/Xdir1/Xdir2/foo', findfile('foo', ';', 1)) - call assert_match('.*/Xdir1/foo', findfile('foo', ';', 2)) - call assert_match('.*/Xdir1/foo', findfile('foo', ';', 2)) - call assert_match('.*/Xdir1/Xdir2/foo', findfile('foo', 'Xdir2;', 1)) + call assert_match('.*/Xfinddir1/Xdir2/foo', findfile('foo', ';')) + call assert_match('.*/Xfinddir1/Xdir2/foo', findfile('foo', ';', 1)) + call assert_match('.*/Xfinddir1/foo', findfile('foo', ';', 2)) + call assert_match('.*/Xfinddir1/foo', findfile('foo', ';', 2)) + call assert_match('.*/Xfinddir1/Xdir2/foo', findfile('foo', 'Xdir2;', 1)) call assert_equal('', findfile('foo', 'Xdir2;', 2)) " List l should have at least 2 values (possibly more if foo file - " happens to be found upwards above Xdir1). + " happens to be found upwards above Xfinddir1). let l = findfile('foo', ';', -1) - call assert_match('.*/Xdir1/Xdir2/foo', l[0]) - call assert_match('.*/Xdir1/foo', l[1]) + call assert_match('.*/Xfinddir1/Xdir2/foo', l[0]) + call assert_match('.*/Xfinddir1/foo', l[1]) " Test upwards search with stop-directory. cd Xdir2 - let l = findfile('bar', ';' . save_dir . '/Xdir1/Xdir2/', -1) + let l = findfile('bar', ';' . save_dir . '/Xfinddir1/Xdir2/Xdir3/', -1) call assert_equal(1, len(l)) - call assert_match('.*/Xdir1/Xdir2/Xdir3/bar', l[0]) + call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0]) + let l = findfile('bar', ';' . save_dir . '/Xfinddir1/Xdir2/Xdir3', -1) + call assert_equal(1, len(l)) + call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0]) + let l = findfile('bar', ';../', -1) + call assert_equal(1, len(l)) + call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0]) + let l = findfile('bar', ';..', -1) + call assert_equal(1, len(l)) + call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0]) - let l = findfile('bar', ';' . save_dir . '/Xdir1/', -1) + let l = findfile('bar', ';' . save_dir . '/Xfinddir1/Xdir2/', -1) + call assert_equal(1, len(l)) + call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0]) + let l = findfile('bar', ';' . save_dir . '/Xfinddir1/Xdir2', -1) + call assert_equal(1, len(l)) + call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0]) + let l = findfile('bar', ';../../', -1) + call assert_equal(1, len(l)) + call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0]) + let l = findfile('bar', ';../..', -1) + call assert_equal(1, len(l)) + call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0]) + + let l = findfile('bar', ';' . save_dir . '/Xfinddir1/', -1) + call assert_equal(2, len(l)) + call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0]) + call assert_match('.*/Xfinddir1/bar', l[1]) + let l = findfile('bar', ';' . save_dir . '/Xfinddir1', -1) + call assert_equal(2, len(l)) + call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0]) + call assert_match('.*/Xfinddir1/bar', l[1]) + let l = findfile('bar', ';../../../', -1) + call assert_equal(2, len(l)) + call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0]) + call assert_match('.*/Xfinddir1/bar', l[1]) + let l = findfile('bar', ';../../..', -1) call assert_equal(2, len(l)) - call assert_match('.*/Xdir1/Xdir2/Xdir3/bar', l[0]) - call assert_match('.*/Xdir1/bar', l[1]) + call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0]) + call assert_match('.*/Xfinddir1/bar', l[1]) " Test combined downwards and upwards search from Xdir2/. cd ../.. call assert_equal('Xdir3/bar', findfile('bar', '**;', 1)) - call assert_match('.*/Xdir1/bar', findfile('bar', '**;', 2)) + call assert_match('.*/Xfinddir1/bar', findfile('bar', '**;', 2)) bwipe! call chdir(save_dir) @@ -135,7 +169,7 @@ func Test_finddir() set path=,, set shellslash call CreateFiles() - cd Xdir1 + cd Xfinddir1 call assert_equal('Xdir2', finddir('Xdir2')) call assert_equal('', 'Xdir3'->finddir()) @@ -158,17 +192,17 @@ func Test_finddir() " Test upwards dir search. cd Xdir2/Xdir3 - call assert_match('.*/Xdir1', finddir('Xdir1', ';')) + call assert_match('.*/Xfinddir1', finddir('Xfinddir1', ';')) " Test upwards search with stop-directory. - call assert_match('.*/Xdir1', finddir('Xdir1', ';' . save_dir . '/')) - call assert_equal('', finddir('Xdir1', ';' . save_dir . '/Xdir1/')) + call assert_match('.*/Xfinddir1', finddir('Xfinddir1', ';' . save_dir . '/')) + call assert_equal('', finddir('Xfinddir1', ';' . save_dir . '/Xfinddir1/')) " Test combined downwards and upwards dir search from Xdir2/. cd .. - call assert_match('.*/Xdir1', finddir('Xdir1', '**;', 1)) + call assert_match('.*/Xfinddir1', finddir('Xfinddir1', '**;', 1)) call assert_equal('Xdir3/Xdir2', finddir('Xdir2', '**;', 1)) - call assert_match('.*/Xdir1/Xdir2', finddir('Xdir2', '**;', 2)) + call assert_match('.*/Xfinddir1/Xdir2', finddir('Xdir2', '**;', 2)) call assert_equal('Xdir3', finddir('Xdir3', '**;', 1)) call chdir(save_dir) @@ -192,7 +226,7 @@ func Test_find_cmd() let save_dir = getcwd() set path=.,./**/* call CreateFiles() - cd Xdir1 + cd Xfinddir1 " Test for :find find foo diff --git a/test/old/testdir/test_flatten.vim b/test/old/testdir/test_flatten.vim index aa91060313..035ca18f73 100644 --- a/test/old/testdir/test_flatten.vim +++ b/test/old/testdir/test_flatten.vim @@ -53,7 +53,7 @@ func Test_flatten() call test_garbagecollect_now() call assert_equal([1, 2, 3], l:list) - " Tests for checking circular reference list can be flatten. + " Tests for checking circular reference list can be flattened. let l:x = [1] let l:y = [x] let l:z = flatten(l:y) diff --git a/test/old/testdir/test_fnamemodify.vim b/test/old/testdir/test_fnamemodify.vim index 258a2093bd..f0bc2503b5 100644 --- a/test/old/testdir/test_fnamemodify.vim +++ b/test/old/testdir/test_fnamemodify.vim @@ -12,6 +12,10 @@ func Test_fnamemodify() call assert_equal('r', fnamemodify('.', ':p:h')[-1:]) call assert_equal('t', fnamemodify('test.out', ':p')[-1:]) call assert_equal($HOME .. "/foo" , fnamemodify('~/foo', ':p')) + call assert_equal(fnamemodify('.', ':p:h:h:h') .. '/', fnamemodify($HOME .. '/../', ':p')) + call assert_equal(fnamemodify('.', ':p:h:h:h') .. '/', fnamemodify($HOME .. '/..', ':p')) + call assert_equal(fnamemodify('.', ':p:h:h') .. '/', fnamemodify('../', ':p')) + call assert_equal(fnamemodify('.', ':p:h:h') .. '/', fnamemodify('..', ':p')) call assert_equal('test.out', fnamemodify('test.out', ':.')) call assert_equal('a', fnamemodify('../testdir/a', ':.')) call assert_equal('~/testdir/test.out', fnamemodify('test.out', ':~')) diff --git a/test/old/testdir/test_fold.vim b/test/old/testdir/test_fold.vim index eae6952e72..6569e032f6 100644 --- a/test/old/testdir/test_fold.vim +++ b/test/old/testdir/test_fold.vim @@ -8,7 +8,73 @@ func PrepIndent(arg) return [a:arg] + repeat(["\t".a:arg], 5) endfu -func Test_address_fold() +func Test_address_fold_new_default_commentstring() + " Test with the new commentstring defaults, that includes padding after v9.1.464 + new + call setline(1, ['int FuncName() {/* {{{ */', 1, 2, 3, 4, 5, '}/* }}} */', + \ 'after fold 1', 'after fold 2', 'after fold 3']) + setl fen fdm=marker + " The next commands should all copy the same part of the buffer, + " regardless of the addressing type, since the part to be copied + " is folded away + :1y + call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */'], getreg(0,1,1)) + :.y + call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */'], getreg(0,1,1)) + :.+y + call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */'], getreg(0,1,1)) + :.,.y + call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */'], getreg(0,1,1)) + :sil .1,.y + call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */'], getreg(0,1,1)) + " use silent to make E493 go away + :sil .+,.y + call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */'], getreg(0,1,1)) + :,y + call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */'], getreg(0,1,1)) + :,+y + call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */','after fold 1'], getreg(0,1,1)) + " using .+3 as second address should c opy the whole folded line + the next 3 + " lines + :.,+3y + call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */', + \ 'after fold 1', 'after fold 2' , 'after fold 3'], getreg(0,1,1)) + :sil .,-2y + call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */'], getreg(0,1,1)) + + " now test again with folding disabled + set nofoldenable + :1y + call assert_equal(['int FuncName() {/* {{{ */'], getreg(0,1,1)) + :.y + call assert_equal(['int FuncName() {/* {{{ */'], getreg(0,1,1)) + :.+y + call assert_equal(['1'], getreg(0,1,1) ) + :.,.y + call assert_equal(['int FuncName() {/* {{{ */'], getreg(0,1,1)) + " use silent to make E493 go away + :sil .1,.y + call assert_equal(['int FuncName() {/* {{{ */', '1'], getreg(0,1,1)) + " use silent to make E493 go away + :sil .+,.y + call assert_equal(['int FuncName() {/* {{{ */', '1'], getreg(0,1,1)) + :,y + call assert_equal(['int FuncName() {/* {{{ */'], getreg(0,1,1)) + :,+y + call assert_equal(['int FuncName() {/* {{{ */', '1'], getreg(0,1,1)) + " using .+3 as second address should c opy the whole folded line + the next 3 + " lines + :.,+3y + call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3'], getreg(0,1,1)) + :7 + :sil .,-2y + call assert_equal(['4', '5', '}/* }}} */'], getreg(0,1,1)) + + quit! +endfunc + +func Test_address_fold_old_default_commentstring() + " Test with the old commentstring defaults, before v9.1.464 new call setline(1, ['int FuncName() {/*{{{*/', 1, 2, 3, 4, 5, '}/*}}}*/', \ 'after fold 1', 'after fold 2', 'after fold 3']) @@ -320,6 +386,32 @@ func Test_foldexpr_no_interrupt_addsub() set foldmethod& foldexpr& endfunc +" Fold function defined in another script +func Test_foldexpr_compiled() + throw 'Skipped: Vim9 script is N/A' + new + let lines =<< trim END + vim9script + def FoldFunc(): number + return v:lnum + enddef + + set foldmethod=expr + set foldexpr=s:FoldFunc() + END + call writefile(lines, 'XfoldExpr', 'D') + source XfoldExpr + + call setline(1, ['one', 'two', 'three']) + redraw + call assert_equal(1, foldlevel(1)) + call assert_equal(2, foldlevel(2)) + call assert_equal(3, foldlevel(3)) + + bwipe! + set foldmethod& foldexpr& +endfunc + func Check_foldlevels(expected) call assert_equal(a:expected, map(range(1, line('$')), 'foldlevel(v:val)')) endfunc @@ -433,7 +525,7 @@ func Test_move_folds_around_manual() %foldopen! 13m7 call Check_foldlevels([1, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 0]) - + bw! endfunc @@ -682,7 +774,7 @@ func Test_fold_create_marker_in_C() let content =<< trim [CODE] /* * comment - * + * * */ int f(int* p) { @@ -696,7 +788,7 @@ func Test_fold_create_marker_in_C() call append(0, content) call cursor(c + 1, 1) norm! zfG - call assert_equal(content[c] . (c < 4 ? '{{{' : '/*{{{*/'), getline(c + 1)) + call assert_equal(content[c] . (c < 4 ? '{{{' : '/* {{{ */'), getline(c + 1)) endfor set fdm& fdl& @@ -1403,6 +1495,63 @@ func Test_foldtext_scriptlocal_func() delfunc s:FoldText endfunc +" Test for setting 'foldtext' from the modeline and executing the expression +" in a sandbox +func Test_foldtext_in_modeline() + func ModelineFoldText() + call feedkeys('aFoo', 'xt') + return "folded text" + endfunc + let lines =<< trim END + func T() + let i = 1 + endfunc + " vim: foldenable foldtext=ModelineFoldText() + END + call writefile(lines, 'Xmodelinefoldtext', 'D') + + set modeline modelineexpr + split Xmodelinefoldtext + + call cursor(1, 1) + normal! zf3j + call assert_equal('folded text', foldtextresult(1)) + call assert_equal(lines, getbufline('', 1, '$')) + + bw! + set modeline& modelineexpr& + delfunc ModelineFoldText +endfunc + +" Test for setting 'foldexpr' from the modeline and executing the expression +" in a sandbox +func Test_foldexpr_in_modeline() + func ModelineFoldExpr() + call feedkeys('aFoo', 'xt') + return strlen(matchstr(getline(v:lnum),'^\s*')) + endfunc + let lines =<< trim END + aaa + bbb + ccc + ccc + bbb + aaa + " vim: foldenable foldmethod=expr foldexpr=ModelineFoldExpr() + END + call writefile(lines, 'Xmodelinefoldexpr', 'D') + + set modeline modelineexpr + split Xmodelinefoldexpr + + call assert_equal(2, foldlevel(3)) + call assert_equal(lines, getbufline('', 1, '$')) + + bw! + set modeline& modelineexpr& + delfunc ModelineFoldExpr +endfunc + " Make sure a fold containing a nested fold is split correctly when using " foldmethod=indent func Test_fold_split() @@ -1420,6 +1569,8 @@ func Test_fold_split() call assert_equal([0, 1, 1, 2, 2], range(1, 5)->map('foldlevel(v:val)')) call append(2, 'line 2.5') call assert_equal([0, 1, 0, 1, 2, 2], range(1, 6)->map('foldlevel(v:val)')) + 3d + call assert_equal([0, 1, 1, 2, 2], range(1, 5)->map('foldlevel(v:val)')) bw! endfunc @@ -1591,4 +1742,39 @@ func Test_foldexpr_end_fold() bwipe! endfunc +" Test moving cursor down to or beyond start of folded end of buffer. +func Test_cursor_down_fold_eob() + call setline(1, range(1, 4)) + norm Gzf2kj + call assert_equal(2, line('.')) + norm zojzc + call assert_equal(3, line('.')) + norm j + call assert_equal(3, line('.')) + norm k2j + call assert_equal(4, line('.')) + bwipe! +endfunc + +" issue: #15455 +func Test_cursor_fold_marker_undo() + new + call setline(1, ['{{{', '', 'This is a Line', '', 'This is a Line', '', '}}}']) + let &ul=&ul + setl foldmethod=marker + call cursor(2, 1) + norm! zo1vjdu + call assert_equal(1, foldlevel('.')) + bwipe! + new + call setline(1, ['', '{{{', '', 'This is a Line', '', 'This is a Line', '', '}}}']) + let &ul=&ul + setl foldmethod=marker + call cursor(3, 1) + norm! zo + norm! vjdu + call assert_equal(1, foldlevel('.')) + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_functions.vim b/test/old/testdir/test_functions.vim index 18d0d9aa5d..ffe7f3fb39 100644 --- a/test/old/testdir/test_functions.vim +++ b/test/old/testdir/test_functions.vim @@ -810,6 +810,10 @@ func Test_mode() call feedkeys("gQ\<Insert>\<F2>vi\<CR>", 'xt') call assert_equal("c-cvr", g:current_modes) + " Commandline mode in Visual mode should return "c-c", never "v-v". + call feedkeys("v\<Cmd>call input('')\<CR>\<F2>\<CR>\<Esc>", 'xt') + call assert_equal("c-c", g:current_modes) + " Executing commands in Vim Ex mode should return "cv", never "cvr", " as Cmdline editing has already ended. call feedkeys("gQcall Save_mode()\<CR>vi\<CR>", 'xt') @@ -2143,54 +2147,6 @@ func Test_balloon_show() endif endfunc -func Test_shellescape() - let save_shell = &shell - set shell=bash - call assert_equal("'text'", shellescape('text')) - call assert_equal("'te\"xt'", 'te"xt'->shellescape()) - call assert_equal("'te'\\''xt'", shellescape("te'xt")) - - call assert_equal("'te%xt'", shellescape("te%xt")) - call assert_equal("'te\\%xt'", shellescape("te%xt", 1)) - call assert_equal("'te#xt'", shellescape("te#xt")) - call assert_equal("'te\\#xt'", shellescape("te#xt", 1)) - call assert_equal("'te!xt'", shellescape("te!xt")) - call assert_equal("'te\\!xt'", shellescape("te!xt", 1)) - - call assert_equal("'te\nxt'", shellescape("te\nxt")) - call assert_equal("'te\\\nxt'", shellescape("te\nxt", 1)) - set shell=tcsh - call assert_equal("'te\\!xt'", shellescape("te!xt")) - call assert_equal("'te\\\\!xt'", shellescape("te!xt", 1)) - call assert_equal("'te\\\nxt'", shellescape("te\nxt")) - call assert_equal("'te\\\\\nxt'", shellescape("te\nxt", 1)) - - set shell=fish - call assert_equal("'text'", shellescape('text')) - call assert_equal("'te\"xt'", shellescape('te"xt')) - call assert_equal("'te'\\''xt'", shellescape("te'xt")) - - call assert_equal("'te%xt'", shellescape("te%xt")) - call assert_equal("'te\\%xt'", shellescape("te%xt", 1)) - call assert_equal("'te#xt'", shellescape("te#xt")) - call assert_equal("'te\\#xt'", shellescape("te#xt", 1)) - call assert_equal("'te!xt'", shellescape("te!xt")) - call assert_equal("'te\\!xt'", shellescape("te!xt", 1)) - - call assert_equal("'te\\\\xt'", shellescape("te\\xt")) - call assert_equal("'te\\\\xt'", shellescape("te\\xt", 1)) - call assert_equal("'te\\\\'\\''xt'", shellescape("te\\'xt")) - call assert_equal("'te\\\\'\\''xt'", shellescape("te\\'xt", 1)) - call assert_equal("'te\\\\!xt'", shellescape("te\\!xt")) - call assert_equal("'te\\\\\\!xt'", shellescape("te\\!xt", 1)) - call assert_equal("'te\\\\%xt'", shellescape("te\\%xt")) - call assert_equal("'te\\\\\\%xt'", shellescape("te\\%xt", 1)) - call assert_equal("'te\\\\#xt'", shellescape("te\\#xt")) - call assert_equal("'te\\\\\\#xt'", shellescape("te\\#xt", 1)) - - let &shell = save_shell -endfunc - func Test_setbufvar_options() " This tests that aucmd_prepbuf() and aucmd_restbuf() properly restore the " window layout and cursor position. @@ -3496,6 +3452,56 @@ func Test_glob() call assert_fails("call glob('*', 0, {})", 'E728:') endfunc +func Test_glob2() + call mkdir('[XglobDir]', 'R') + call mkdir('abc[glob]def', 'R') + + call writefile(['glob'], '[XglobDir]/Xglob') + call writefile(['glob'], 'abc[glob]def/Xglob') + if has("unix") + call assert_equal([], (glob('[XglobDir]/*', 0, 1))) + call assert_equal([], (glob('abc[glob]def/*', 0, 1))) + call assert_equal(['[XglobDir]/Xglob'], (glob('\[XglobDir]/*', 0, 1))) + call assert_equal(['abc[glob]def/Xglob'], (glob('abc\[glob]def/*', 0, 1))) + elseif has("win32") + let _sl=&shellslash + call assert_equal([], (glob('[XglobDir]\*', 0, 1))) + call assert_equal([], (glob('abc[glob]def\*', 0, 1))) + call assert_equal([], (glob('\[XglobDir]\*', 0, 1))) + call assert_equal([], (glob('abc\[glob]def\*', 0, 1))) + set noshellslash + call assert_equal(['[XglobDir]\Xglob'], (glob('[[]XglobDir]/*', 0, 1))) + call assert_equal(['abc[glob]def\Xglob'], (glob('abc[[]glob]def/*', 0, 1))) + set shellslash + call assert_equal(['[XglobDir]/Xglob'], (glob('[[]XglobDir]/*', 0, 1))) + call assert_equal(['abc[glob]def/Xglob'], (glob('abc[[]glob]def/*', 0, 1))) + let &shellslash=_sl + endif +endfunc + +func Test_glob_symlinks() + call writefile([], 'Xglob1') + + if has("win32") + silent !mklink XglobBad DoesNotExist + if v:shell_error + throw 'Skipped: cannot create symlinks' + endif + silent !mklink XglobOk Xglob1 + else + silent !ln -s DoesNotExist XglobBad + silent !ln -s Xglob1 XglobOk + endif + + " The broken symlink is excluded when alllinks is false. + call assert_equal(['Xglob1', 'XglobBad', 'XglobOk'], sort(glob('Xglob*', 0, 1, 1))) + call assert_equal(['Xglob1', 'XglobOk'], sort(glob('Xglob*', 0, 1, 0))) + + call delete('Xglob1') + call delete('XglobBad') + call delete('XglobOk') +endfunc + " Test for browse() func Test_browse() CheckFeature browse @@ -3557,6 +3563,42 @@ func Test_builtin_check() unlet bar endfunc +" Test for isabsolutepath() +func Test_isabsolutepath() + call assert_false(isabsolutepath('')) + call assert_false(isabsolutepath('.')) + call assert_false(isabsolutepath('../Foo')) + call assert_false(isabsolutepath('Foo/')) + if has('win32') + call assert_true(isabsolutepath('A:\')) + call assert_true(isabsolutepath('A:\Foo')) + call assert_true(isabsolutepath('A:/Foo')) + call assert_false(isabsolutepath('A:Foo')) + call assert_false(isabsolutepath('\Windows')) + call assert_true(isabsolutepath('\\Server2\Share\Test\Foo.txt')) + else + call assert_true(isabsolutepath('/')) + call assert_true(isabsolutepath('/usr/share/')) + endif +endfunc + +" Test for exepath() +func Test_exepath() + if has('win32') + call assert_notequal(exepath('cmd'), '') + + let oldNoDefaultCurrentDirectoryInExePath = $NoDefaultCurrentDirectoryInExePath + call writefile(['@echo off', 'echo Evil'], 'vim-test-evil.bat') + let $NoDefaultCurrentDirectoryInExePath = '' + call assert_notequal(exepath("vim-test-evil.bat"), '') + let $NoDefaultCurrentDirectoryInExePath = '1' + call assert_equal(exepath("vim-test-evil.bat"), '') + let $NoDefaultCurrentDirectoryInExePath = oldNoDefaultCurrentDirectoryInExePath + call delete('vim-test-evil.bat') + else + call assert_notequal(exepath('sh'), '') + endif +endfunc " Test for virtcol() func Test_virtcol() @@ -3621,7 +3663,7 @@ func Test_string_reverse() call assert_equal('', reverse(v:_null_string)) for [s1, s2] in [['', ''], ['a', 'a'], ['ab', 'ba'], ['abc', 'cba'], \ ['abcd', 'dcba'], ['«-«-»-»', '»-»-«-«'], - \ ['🇦', '🇦'], ['🇦🇧', '🇧🇦'], ['🇦🇧🇨', '🇨🇧🇦'], + \ ['🇦', '🇦'], ['🇦🇧', '🇦🇧'], ['🇦🇧🇨', '🇨🇦🇧'], \ ['🇦«🇧-🇨»🇩', '🇩»🇨-🇧«🇦']] call assert_equal(s2, reverse(s1)) endfor @@ -3729,6 +3771,8 @@ func Test_slice() call assert_equal('', 'ὰ̳βÌ̳γ̳̂δ̳̃ε̳̄ζ̳̅'->slice(1, -6)) END call CheckLegacyAndVim9Success(lines) + + call assert_equal(0, slice(v:true, 1)) endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_getvar.vim b/test/old/testdir/test_getvar.vim index 1e29f49fb4..56f737ab9c 100644 --- a/test/old/testdir/test_getvar.vim +++ b/test/old/testdir/test_getvar.vim @@ -142,21 +142,31 @@ func Test_get_func() let l:F = function('tr') call assert_equal('tr', get(l:F, 'name')) call assert_equal(l:F, get(l:F, 'func')) + call assert_equal({'required': 3, 'optional': 0, 'varargs': v:false}, + \ get(l:F, 'arity')) let Fb_func = function('s:FooBar') call assert_match('<SNR>\d\+_FooBar', get(Fb_func, 'name')) + call assert_equal({'required': 0, 'optional': 0, 'varargs': v:false}, + \ get(Fb_func, 'arity')) let Fb_ref = funcref('s:FooBar') call assert_match('<SNR>\d\+_FooBar', get(Fb_ref, 'name')) + call assert_equal({'required': 0, 'optional': 0, 'varargs': v:false}, + \ get(Fb_ref, 'arity')) call assert_equal({'func has': 'no dict'}, get(l:F, 'dict', {'func has': 'no dict'})) call assert_equal(0, get(l:F, 'dict')) call assert_equal([], get(l:F, 'args')) + " Nvim doesn't have null functions " let NF = test_null_function() " call assert_equal('', get(NF, 'name')) " call assert_equal(NF, get(NF, 'func')) " call assert_equal(0, get(NF, 'dict')) " call assert_equal([], get(NF, 'args')) + " call assert_equal({'required': 0, 'optional': 0, 'varargs': v:false}, get(NF, 'arity')) endfunc " get({partial}, {what} [, {default}]) - in test_partial.vim + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_goto.vim b/test/old/testdir/test_goto.vim index c5492ff97b..b6a6695d17 100644 --- a/test/old/testdir/test_goto.vim +++ b/test/old/testdir/test_goto.vim @@ -17,7 +17,7 @@ endfunc func Test_gD() let lines =<< trim [CODE] int x; - + int func(void) { return x; @@ -30,7 +30,7 @@ endfunc func Test_gD_too() let lines =<< trim [CODE] Filename x; - + int Filename int func() { Filename x; @@ -44,7 +44,7 @@ func Test_gD_comment() let lines =<< trim [CODE] /* int x; */ int x; - + int func(void) { return x; @@ -58,7 +58,7 @@ func Test_gD_inline_comment() let lines =<< trim [CODE] int y /* , x */; int x; - + int func(void) { return x; @@ -72,7 +72,7 @@ func Test_gD_string() let lines =<< trim [CODE] char *s[] = "x"; int x = 1; - + int func(void) { return x; @@ -85,7 +85,7 @@ endfunc func Test_gD_string_same_line() let lines =<< trim [CODE] char *s[] = "x", int x = 1; - + int func(void) { return x; @@ -99,7 +99,7 @@ func Test_gD_char() let lines =<< trim [CODE] char c = 'x'; int x = 1; - + int func(void) { return x; @@ -112,7 +112,7 @@ endfunc func Test_gd() let lines =<< trim [CODE] int x; - + int func(int x) { return x; @@ -146,7 +146,7 @@ func Test_gd_not_local() { return x; } - + int func2(int x) { return x; @@ -173,9 +173,9 @@ func Test_gd_missing_braces() def func1(a) a + 1 end - + a = 1 - + def func2() return a end @@ -252,11 +252,11 @@ func Test_gd_inline_comment_body() int func(void) { int y /* , x */; - + for (/* int x = 0 */; y < 2; y++); - + int x = 0; - + return x; } [CODE] @@ -292,7 +292,7 @@ func Test_gd_string() { char *s = "x"; int x = 1; - + return x; } [CODE] @@ -305,7 +305,7 @@ func Test_gd_string_only() int func(void) { char *s = "x"; - + return x; } [CODE] @@ -321,14 +321,16 @@ func Test_set_options_keep_col() let pos = getcurpos() normal j set invhlsearch spell spelllang=en,cjk spelloptions=camel textwidth=80 - set cursorline cursorcolumn cursorlineopt=line colorcolumn=+1 + set cursorline cursorcolumn cursorlineopt=line colorcolumn=+1 winfixbuf + set comments=:# commentstring=#%s define=function set background=dark set background=light normal k call assert_equal(pos, getcurpos()) bwipe! set hlsearch& spell& spelllang& spelloptions& textwidth& - set cursorline& cursorcolumn& cursorlineopt& colorcolumn& + set cursorline& cursorcolumn& cursorlineopt& colorcolumn& winfixbuf& + set comments& commentstring& define& set background& endfunc @@ -347,7 +349,7 @@ func Test_gd_local_block() char *b = "NULL"; return b; } - + return 0; } [CODE] diff --git a/test/old/testdir/test_increment.vim b/test/old/testdir/test_increment.vim index 433b2b4471..5c61f25103 100644 --- a/test/old/testdir/test_increment.vim +++ b/test/old/testdir/test_increment.vim @@ -705,7 +705,7 @@ endfunc " Text: " 1 23 " 4 56 -" +" " Expected: " 1) f2 Ctrl-V jl <ctrl-a>, repeat twice afterwards with . " 1 26 @@ -841,6 +841,44 @@ func Test_increment_unsigned() set nrformats-=unsigned endfunc +" Try incrementing/decrementing a number when nrformats contains blank +func Test_increment_blank() + set nrformats+=blank + + " Signed + call setline(1, '0') + exec "norm! gg0\<C-X>" + call assert_equal('-1', getline(1)) + + call setline(1, '3') + exec "norm! gg010\<C-X>" + call assert_equal('-7', getline(1)) + + call setline(1, '-0') + exec "norm! gg0\<C-X>" + call assert_equal("-1", getline(1)) + + " Unsigned + " NOTE: 18446744073709551615 == 2^64 - 1 + call setline(1, 'a-18446744073709551615') + exec "norm! gg0\<C-A>" + call assert_equal('a-18446744073709551615', getline(1)) + + call setline(1, 'a-18446744073709551615') + exec "norm! gg0\<C-A>" + call assert_equal('a-18446744073709551615', getline(1)) + + call setline(1, 'a-18446744073709551614') + exec "norm! gg08\<C-A>" + call assert_equal('a-18446744073709551615', getline(1)) + + call setline(1, 'a-1') + exec "norm! gg0\<C-A>" + call assert_equal('a-2', getline(1)) + + set nrformats-=blank +endfunc + func Test_in_decrement_large_number() " NOTE: 18446744073709551616 == 2^64 call setline(1, '18446744073709551616') diff --git a/test/old/testdir/test_indent.vim b/test/old/testdir/test_indent.vim index 3b5b643177..dcacc11663 100644 --- a/test/old/testdir/test_indent.vim +++ b/test/old/testdir/test_indent.vim @@ -176,7 +176,7 @@ func Test_modeline_indent_expr() endfunc func Test_indent_func_with_gq() - + function GetTeXIndent() " Sample indent expression for TeX files let lnum = prevnonblank(v:lnum - 1) @@ -187,7 +187,7 @@ func Test_indent_func_with_gq() let line = getline(lnum) let ind = indent(lnum) " Add a 'shiftwidth' after beginning of environments. - if line =~ '\\begin{center}' + if line =~ '\\begin{center}' let ind = ind + shiftwidth() endif return ind @@ -249,7 +249,7 @@ func Test_indent_func_with_gq() bwipe! delmark ab - delfunction GetTeXIndent + delfunction GetTeXIndent endfu func Test_formatting_keeps_first_line_indent() diff --git a/test/old/testdir/test_ins_complete.vim b/test/old/testdir/test_ins_complete.vim index 3f67a06999..48319f5017 100644 --- a/test/old/testdir/test_ins_complete.vim +++ b/test/old/testdir/test_ins_complete.vim @@ -700,14 +700,14 @@ func Test_pum_with_preview_win() CheckScreendump let lines =<< trim END - funct Omni_test(findstart, base) - if a:findstart - return col(".") - 1 - endif - return [#{word: "one", info: "1info"}, #{word: "two", info: "2info"}, #{word: "three", info: "3info"}] - endfunc - set omnifunc=Omni_test - set completeopt+=longest + funct Omni_test(findstart, base) + if a:findstart + return col(".") - 1 + endif + return [#{word: "one", info: "1info"}, #{word: "two", info: "2info"}, #{word: "three", info: "3info"}] + endfunc + set omnifunc=Omni_test + set completeopt+=longest END call writefile(lines, 'Xpreviewscript') @@ -884,6 +884,74 @@ func Test_complete_with_longest() bwipe! endfunc +" Test for buffer-local value of 'completeopt' +func Test_completeopt_buffer_local() + set completeopt=menu + new + call setline(1, ['foofoo', 'foobar', 'foobaz', '']) + call assert_equal('', &l:completeopt) + call assert_equal('menu', &completeopt) + call assert_equal('menu', &g:completeopt) + + setlocal bufhidden=hide + enew + call setline(1, ['foofoo', 'foobar', 'foobaz', '']) + call assert_equal('', &l:completeopt) + call assert_equal('menu', &completeopt) + call assert_equal('menu', &g:completeopt) + + setlocal completeopt+=fuzzy,noinsert + call assert_equal('menu,fuzzy,noinsert', &l:completeopt) + call assert_equal('menu,fuzzy,noinsert', &completeopt) + call assert_equal('menu', &g:completeopt) + call feedkeys("Gccf\<C-X>\<C-N>bz\<C-Y>", 'tnix') + call assert_equal('foobaz', getline('.')) + + setlocal completeopt= + call assert_equal('', &l:completeopt) + call assert_equal('menu', &completeopt) + call assert_equal('menu', &g:completeopt) + call feedkeys("Gccf\<C-X>\<C-N>\<C-Y>", 'tnix') + call assert_equal('foofoo', getline('.')) + + setlocal completeopt+=longest + call assert_equal('menu,longest', &l:completeopt) + call assert_equal('menu,longest', &completeopt) + call assert_equal('menu', &g:completeopt) + call feedkeys("Gccf\<C-X>\<C-N>\<C-X>\<C-Z>", 'tnix') + call assert_equal('foo', getline('.')) + + setlocal bufhidden=hide + buffer # + call assert_equal('', &l:completeopt) + call assert_equal('menu', &completeopt) + call assert_equal('menu', &g:completeopt) + call feedkeys("Gccf\<C-X>\<C-N>\<C-Y>", 'tnix') + call assert_equal('foofoo', getline('.')) + + setlocal completeopt+=fuzzy,noinsert + call assert_equal('menu,fuzzy,noinsert', &l:completeopt) + call assert_equal('menu,fuzzy,noinsert', &completeopt) + call assert_equal('menu', &g:completeopt) + call feedkeys("Gccf\<C-X>\<C-N>bz\<C-Y>", 'tnix') + call assert_equal('foobaz', getline('.')) + + buffer # + call assert_equal('menu,longest', &l:completeopt) + call assert_equal('menu,longest', &completeopt) + call assert_equal('menu', &g:completeopt) + call feedkeys("Gccf\<C-X>\<C-N>\<C-X>\<C-Z>", 'tnix') + call assert_equal('foo', getline('.')) + + setlocal bufhidden=wipe + buffer! # + bwipe! + call assert_equal('', &l:completeopt) + call assert_equal('menu', &completeopt) + call assert_equal('menu', &g:completeopt) + + set completeopt& +endfunc " Test for completing words following a completed word in a line func Test_complete_wrapscan() @@ -1623,6 +1691,23 @@ func Test_completefunc_callback() bw! delfunc s:CompleteFunc3 + " In Vim9 script s: can be omitted + let lines =<< trim END + vim9script + var CompleteFunc4Args = [] + def CompleteFunc4(findstart: bool, base: string): any + add(CompleteFunc4Args, [findstart, base]) + return findstart ? 0 : [] + enddef + set completefunc=CompleteFunc4 + new + setline(1, 'script1') + feedkeys("A\<C-X>\<C-U>\<Esc>", 'x') + assert_equal([[1, ''], [0, 'script1']], CompleteFunc4Args) + bw! + END + call CheckScriptSuccess(lines) + " invalid return value let &completefunc = {a -> 'abc'} call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x') @@ -2314,7 +2399,7 @@ endfunc func Test_ins_complete_end_of_line() " this was reading past the end of the line - new + new norm 8o€ý sil! norm o @@ -2512,4 +2597,111 @@ func Test_completefunc_first_call_complete_add() bwipe! endfunc +func Test_complete_fuzzy_match() + func OnPumChange() + let g:item = get(v:event, 'completed_item', {}) + let g:word = get(g:item, 'word', v:null) + endfunction + + augroup AAAAA_Group + au! + autocmd CompleteChanged * :call OnPumChange() + augroup END + + func Omni_test(findstart, base) + if a:findstart + return col(".") + endif + return [#{word: "foo"}, #{word: "foobar"}, #{word: "fooBaz"}, #{word: "foobala"}] + endfunc + + new + set omnifunc=Omni_test + set completeopt+=noinsert,fuzzy + call feedkeys("Gi\<C-x>\<C-o>", 'tx') + call assert_equal('foo', g:word) + call feedkeys("S\<C-x>\<C-o>fb", 'tx') + call assert_equal('fooBaz', g:word) + call feedkeys("S\<C-x>\<C-o>fa", 'tx') + call assert_equal('foobar', g:word) + " select next + call feedkeys("S\<C-x>\<C-o>fb\<C-n>", 'tx') + call assert_equal('foobar', g:word) + " can cyclically select next + call feedkeys("S\<C-x>\<C-o>fb\<C-n>\<C-n>\<C-n>", 'tx') + call assert_equal(v:null, g:word) + " select prev + call feedkeys("S\<C-x>\<C-o>fb\<C-p>", 'tx') + call assert_equal(v:null, g:word) + " can cyclically select prev + call feedkeys("S\<C-x>\<C-o>fb\<C-p>\<C-p>\<C-p>\<C-p>", 'tx') + call assert_equal('fooBaz', g:word) + + func Comp() + call complete(col('.'), ["fooBaz", "foobar", "foobala"]) + return '' + endfunc + call feedkeys("i\<C-R>=Comp()\<CR>", 'tx') + call assert_equal('fooBaz', g:word) + + " respect noselect + set completeopt+=noselect + call feedkeys("S\<C-x>\<C-o>fb", 'tx') + call assert_equal(v:null, g:word) + call feedkeys("S\<C-x>\<C-o>fb\<C-n>", 'tx') + call assert_equal('fooBaz', g:word) + + " avoid breaking default completion behavior + set completeopt=fuzzy,menu + call setline(1, ['hello help hero h']) + " Use "!" flag of feedkeys() so that ex_normal_busy is not set and + " ins_compl_check_keys() is not skipped. + " Add a "0" after the <Esc> to avoid waiting for an escape sequence. + call feedkeys("A\<C-X>\<C-N>\<Esc>0", 'tx!') + call assert_equal('hello help hero hello', getline('.')) + set completeopt+=noinsert + call setline(1, ['hello help hero h']) + call feedkeys("A\<C-X>\<C-N>\<Esc>0", 'tx!') + call assert_equal('hello help hero h', getline('.')) + + " issue #15526 + set completeopt=fuzzy,menuone,menu,noselect + call setline(1, ['Text', 'ToText', '']) + call cursor(2, 1) + call feedkeys("STe\<C-X>\<C-N>x\<CR>\<Esc>0", 'tx!') + call assert_equal('Tex', getline('.')) + + " clean up + set omnifunc= + bw! + set complete& completeopt& + autocmd! AAAAA_Group + augroup! AAAAA_Group + delfunc OnPumChange + delfunc Omni_test + delfunc Comp + unlet g:item + unlet g:word +endfunc + +" Check that tie breaking is stable for completeopt+=fuzzy (which should +" behave the same on different platforms). +func Test_complete_fuzzy_match_tie() + new + set completeopt+=fuzzy,noselect + call setline(1, ['aaabbccc', 'aaabbCCC', 'aaabbcccc', 'aaabbCCCC', '']) + + call feedkeys("Gcc\<C-X>\<C-N>ab\<C-N>\<C-Y>", 'tx') + call assert_equal('aaabbccc', getline('.')) + call feedkeys("Gcc\<C-X>\<C-N>ab\<C-N>\<C-N>\<C-Y>", 'tx') + call assert_equal('aaabbCCC', getline('.')) + call feedkeys("Gcc\<C-X>\<C-N>ab\<C-N>\<C-N>\<C-N>\<C-Y>", 'tx') + call assert_equal('aaabbcccc', getline('.')) + call feedkeys("Gcc\<C-X>\<C-N>ab\<C-N>\<C-N>\<C-N>\<C-N>\<C-Y>", 'tx') + call assert_equal('aaabbCCCC', getline('.')) + + bwipe! + set completeopt& +endfunc + " vim: shiftwidth=2 sts=2 expandtab nofoldenable diff --git a/test/old/testdir/test_jumplist.vim b/test/old/testdir/test_jumplist.vim index b4dcdad9d6..1feadead60 100644 --- a/test/old/testdir/test_jumplist.vim +++ b/test/old/testdir/test_jumplist.vim @@ -19,7 +19,7 @@ func Test_getjumplist() for i in range(1, 100) call add(lines, "Line " . i) endfor - call writefile(lines, "Xtest") + call writefile(lines, "Xtest", 'D') " Jump around and create a jump list edit Xtest @@ -61,33 +61,65 @@ func Test_getjumplist() clearjumps call test_garbagecollect_now() call assert_equal(4, l[1]) - - call delete("Xtest") endfunc -func Test_jumplist_invalid() +func Test_jumplist_wipe_buf() new clearjumps - " put some randome text - put ='a' - let prev = bufnr('%') + " Put some random text and fill the jump list. + call setline(1, ['foo', 'bar', 'baz']) + normal G + normal gg setl nomodified bufhidden=wipe e XXJumpListBuffer - let bnr = bufnr('%') - " 1) empty jumplist - let expected = [[ - \ {'lnum': 2, 'bufnr': prev, 'col': 0, 'coladd': 0}], 1] - call assert_equal(expected, getjumplist()) + " The jump list is empty as the buffer was wiped out. + call assert_equal([[], 0], getjumplist()) let jumps = execute(':jumps') call assert_equal('>', jumps[-1:]) - " now jump back - exe ":norm! \<c-o>" - let expected = [[ - \ {'lnum': 2, 'bufnr': prev, 'col': 0, 'coladd': 0}, - \ {'lnum': 1, 'bufnr': bnr, 'col': 0, 'coladd': 0}], 0] - call assert_equal(expected, getjumplist()) - let jumps = execute(':jumps') - call assert_match('> 0 2 0 -invalid-', jumps) + + " Put some random text and fill the jump list. + call setline(1, ['foo', 'bar', 'baz']) + setl bufhidden=hide + + " References to wiped buffer are deleted with multiple tabpages. + let [w1, t1] = [win_getid(), tabpagenr()] + clearjumps + normal G + normal gg + enew + + split XXJumpListBuffer + let [w2, t2] = [win_getid(), tabpagenr()] + clearjumps + normal G + normal gg + enew + + tabnew XXJumpListBuffer + let [w3, t3] = [win_getid(), tabpagenr()] + clearjumps + normal G + normal gg + enew + + split XXJumpListBuffer + let [w4, t4] = [win_getid(), tabpagenr()] + clearjumps + normal G + normal gg + enew + + for [w, t] in [[w1, t1], [w2, t2], [w3, t3], [w4, t4]] + call assert_equal(2, len(getjumplist(w, t)[0])) + endfor + + bwipe! XXJumpListBuffer + + for [w, t] in [[w1, t1], [w2, t2], [w3, t3], [w4, t4]] + call assert_equal(0, len(getjumplist(w, t)[0])) + endfor + + %bwipe! endfunc " Test for '' mark in an empty buffer diff --git a/test/old/testdir/test_lambda.vim b/test/old/testdir/test_lambda.vim index 810b41b389..0340a7260b 100644 --- a/test/old/testdir/test_lambda.vim +++ b/test/old/testdir/test_lambda.vim @@ -217,7 +217,9 @@ endfunc func Test_lambda_combination() call assert_equal(2, {x -> {x -> x}}(1)(2)) call assert_equal(10, {y -> {x -> x(y)(10)}({y -> y})}({z -> z})) - call assert_equal(5.0, {x -> {y -> x / y}}(10)(2.0)) + if has('float') + call assert_equal(5.0, {x -> {y -> x / y}}(10)(2.0)) + endif call assert_equal(6, {x -> {y -> {z -> x + y + z}}}(1)(2)(3)) call assert_equal(6, {x -> {f -> f(x)}}(3)({x -> x * 2})) diff --git a/test/old/testdir/test_let.vim b/test/old/testdir/test_let.vim index d37af45aaa..44852c1d38 100644 --- a/test/old/testdir/test_let.vim +++ b/test/old/testdir/test_let.vim @@ -521,12 +521,12 @@ END END call assert_equal(['vim', '', 'end', ' END', 'END '], var3) - let var1 =<< trim END - Line1 - Line2 - Line3 - END - END + let var1 =<< trim END + Line1 + Line2 + Line3 + END + END call assert_equal(['Line1', ' Line2', "\tLine3", ' END'], var1) let var1 =<< trim !!! @@ -563,6 +563,14 @@ END END call assert_equal(['something', 'endfunc'], var1) + " not concatenate lines + let var1 =<< END +some + \thing + \ else +END + call assert_equal(['some', ' \thing', ' \ else'], var1) + " ignore "python << xx" let var1 =<<END something diff --git a/test/old/testdir/test_listdict.vim b/test/old/testdir/test_listdict.vim index 0adc3286f9..678734dafb 100644 --- a/test/old/testdir/test_listdict.vim +++ b/test/old/testdir/test_listdict.vim @@ -57,6 +57,9 @@ func Test_list_slice() assert_equal([1, 2], l[-3 : -1]) END call CheckDefAndScriptSuccess(lines) + + call assert_fails('let l[[]] = 1', 'E730: Using a List as a String') + call assert_fails('let l[1 : []] = [1]', 'E730: Using a List as a String') endfunc " List identity @@ -175,6 +178,19 @@ func Test_list_assign() END call CheckScriptFailure(['vim9script'] + lines, 'E688:') call CheckDefExecFailure(lines, 'E1093: Expected 2 items but got 1') + + let lines =<< trim END + VAR l = [2] + LET l += v:_null_list + call assert_equal([2], l) + LET l = v:_null_list + LET l += [1] + call assert_equal([1], l) + END + call CheckLegacyAndVim9Success(lines) + + let d = {'abc': [1, 2, 3]} + call assert_fails('let d.abc[0:0z10] = [10, 20]', 'E976: Using a Blob as a String') endfunc " test for range assign @@ -195,6 +211,26 @@ func Test_list_range_assign() call CheckDefAndScriptFailure(lines, 'E1012:', 2) endfunc +func Test_list_items() + let r = [] + let l = ['a', 'b', 'c'] + for [idx, val] in items(l) + call extend(r, [[idx, val]]) + endfor + call assert_equal([[0, 'a'], [1, 'b'], [2, 'c']], r) + + call assert_fails('call items(3)', 'E1225:') +endfunc + +func Test_string_items() + let r = [] + let s = 'aÌbツ' + for [idx, val] in items(s) + call extend(r, [[idx, val]]) + endfor + call assert_equal([[0, 'aÌ'], [1, 'b'], [2, 'ツ']], r) +endfunc + " Test removing items in list func Test_list_func_remove() let lines =<< trim END @@ -420,6 +456,9 @@ func Test_dict_assign() n.key = 3 END call CheckDefFailure(lines, 'E1141:') + + let d = {'abc': {}} + call assert_fails("let d.abc[0z10] = 10", 'E976: Using a Blob as a String') endfunc " Function in script-local List or Dict @@ -1055,6 +1094,19 @@ func Test_listdict_compare() call assert_fails('echo {} =~ {}', 'E736:') endfunc +func Test_recursive_listdict_compare() + let l1 = [0, 1] + let l1[0] = l1 + let l2 = [0, 1] + let l2[0] = l2 + call assert_true(l1 == l2) + let d1 = {0: 0, 1: 1} + let d1[0] = d1 + let d2 = {0: 0, 1: 1} + let d2[0] = d2 + call assert_true(d1 == d2) +endfunc + " compare complex recursively linked list and dict func Test_listdict_compare_complex() let lines =<< trim END @@ -1416,6 +1468,8 @@ func Test_indexof() call assert_equal(-1, indexof(l, v:_null_string)) " Nvim doesn't have null functions " call assert_equal(-1, indexof(l, test_null_function())) + call assert_equal(-1, indexof(l, "")) + call assert_fails('let i = indexof(l, " ")', 'E15:') " failure cases call assert_fails('let i = indexof(l, "v:val == ''cyan''")', 'E735:') @@ -1447,4 +1501,53 @@ func Test_extendnew_leak() for i in range(100) | silent! call extendnew({}, {}, {}) | endfor endfunc +" Test for comparing deeply nested List/Dict values +func Test_deep_nested_listdict_compare() + let lines =<< trim END + func GetNestedList(sz) + let l = [] + let x = l + for i in range(a:sz) + let y = [1] + call add(x, y) + let x = y + endfor + return l + endfunc + + VAR l1 = GetNestedList(1000) + VAR l2 = GetNestedList(999) + call assert_false(l1 == l2) + + #" after 1000 nested items, the lists are considered to be equal + VAR l3 = GetNestedList(1001) + VAR l4 = GetNestedList(1002) + call assert_true(l3 == l4) + END + call CheckLegacyAndVim9Success(lines) + + let lines =<< trim END + func GetNestedDict(sz) + let d = {} + let x = d + for i in range(a:sz) + let y = {} + let x['a'] = y + let x = y + endfor + return d + endfunc + + VAR d1 = GetNestedDict(1000) + VAR d2 = GetNestedDict(999) + call assert_false(d1 == d2) + + #" after 1000 nested items, the Dicts are considered to be equal + VAR d3 = GetNestedDict(1001) + VAR d4 = GetNestedDict(1002) + call assert_true(d3 == d4) + END + call CheckLegacyAndVim9Success(lines) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_listlbr_utf8.vim b/test/old/testdir/test_listlbr_utf8.vim index 313ff30cc4..693f2015fc 100644 --- a/test/old/testdir/test_listlbr_utf8.vim +++ b/test/old/testdir/test_listlbr_utf8.vim @@ -280,6 +280,9 @@ func Test_chinese_char_on_wrap_column() call s:compare_lines(expect, lines) call assert_equal(len(expect), winline()) call assert_equal(strwidth(trim(expect[-1], ' ', 2)), wincol()) + norm! g0 + call assert_equal(len(expect), winline()) + call assert_equal(1, wincol()) call s:close_windows() endfunc @@ -315,6 +318,9 @@ func Test_chinese_char_on_wrap_column_sbr() call s:compare_lines(expect, lines) call assert_equal(len(expect), winline()) call assert_equal(strwidth(trim(expect[-1], ' ', 2)), wincol()) + norm! g0 + call assert_equal(len(expect), winline()) + call assert_equal(4, wincol()) call s:close_windows() endfunc diff --git a/test/old/testdir/test_map_functions.vim b/test/old/testdir/test_map_functions.vim index 0898242154..8f7c8bae76 100644 --- a/test/old/testdir/test_map_functions.vim +++ b/test/old/testdir/test_map_functions.vim @@ -20,7 +20,7 @@ func Test_maparg() call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo<C-V>', \ 'lhsraw': "foo\x80\xfc\x04V", 'lhsrawalt': "foo\x16", \ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'scriptversion': 1, - \ 'lnum': lnum + 1, + \ 'lnum': lnum + 1, \ 'rhs': 'is<F4>foo', 'buffer': 0, 'abbr': 0, 'mode_bits': 0x47}, \ maparg('foo<C-V>', '', 0, 1)) call assert_equal({'silent': 1, 'noremap': 1, 'script': 1, 'lhs': 'bar', diff --git a/test/old/testdir/test_mapping.vim b/test/old/testdir/test_mapping.vim index 2a4d068dea..e4e446c55c 100644 --- a/test/old/testdir/test_mapping.vim +++ b/test/old/testdir/test_mapping.vim @@ -1672,6 +1672,49 @@ func Test_unmap_simplifiable() unmap <C-I> endfunc +" Test that the first byte of rhs is not remapped if rhs starts with lhs. +func Test_map_rhs_starts_with_lhs() + new + func MapExpr() + return "\<C-R>\<C-P>" + endfunc + + for expr in [v:false, v:true] + if expr + imap <buffer><expr> <C-R> MapExpr() + else + imap <buffer> <C-R> <C-R><C-P> + endif + + for restore in [v:false, v:true] + if restore + let saved = maparg('<C-R>', 'i', v:false, v:true) + iunmap <buffer> <C-R> + call mapset(saved) + endif + + let @a = 'foo' + call assert_nobeep('call feedkeys("S\<C-R>a", "tx")') + call assert_equal('foo', getline('.')) + + let @a = 'bar' + call assert_nobeep('call feedkeys("S\<*C-R>a", "tx")') + call assert_equal('bar', getline('.')) + endfor + endfor + + " When two mappings are used for <C-I> and <Tab>, remapping should work. + imap <buffer> <C-I> <Tab>bar + imap <buffer> <Tab> foo + call feedkeys("S\<Tab>", 'xt') + call assert_equal('foo', getline('.')) + call feedkeys("S\<*C-I>", 'xt') + call assert_equal('foobar', getline('.')) + + delfunc MapExpr + bwipe! +endfunc + func Test_expr_map_escape_special() nnoremap … <Cmd>let g:got_ellipsis += 1<CR> func Func() diff --git a/test/old/testdir/test_matchparen.vim b/test/old/testdir/test_matchparen.vim index ab425b046a..7d80e43046 100644 --- a/test/old/testdir/test_matchparen.vim +++ b/test/old/testdir/test_matchparen.vim @@ -108,5 +108,35 @@ func Test_matchparen_pum_clear() call StopVimInTerminal(buf) endfunc +" Test that matchparen works with multibyte chars in 'matchpairs' +func Test_matchparen_mbyte() + CheckScreendump + + let lines =<< trim END + source $VIMRUNTIME/plugin/matchparen.vim + call setline(1, ['aaaaaaaa(', 'bbbb)cc']) + set matchpairs+=(:) + END + + call writefile(lines, 'XmatchparenMbyte', 'D') + let buf = RunVimInTerminal('-S XmatchparenMbyte', #{rows: 10}) + call VerifyScreenDump(buf, 'Test_matchparen_mbyte_1', {}) + call term_sendkeys(buf, "$") + call VerifyScreenDump(buf, 'Test_matchparen_mbyte_2', {}) + call term_sendkeys(buf, "j") + call VerifyScreenDump(buf, 'Test_matchparen_mbyte_3', {}) + call term_sendkeys(buf, "2h") + call VerifyScreenDump(buf, 'Test_matchparen_mbyte_4', {}) + call term_sendkeys(buf, "0") + call VerifyScreenDump(buf, 'Test_matchparen_mbyte_5', {}) + call term_sendkeys(buf, "kA") + call VerifyScreenDump(buf, 'Test_matchparen_mbyte_6', {}) + call term_sendkeys(buf, "\<Down>") + call VerifyScreenDump(buf, 'Test_matchparen_mbyte_7', {}) + call term_sendkeys(buf, "\<C-W>") + call VerifyScreenDump(buf, 'Test_matchparen_mbyte_8', {}) + + call StopVimInTerminal(buf) +endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_menu.vim b/test/old/testdir/test_menu.vim index d1c1180ce1..88d74c8a1a 100644 --- a/test/old/testdir/test_menu.vim +++ b/test/old/testdir/test_menu.vim @@ -482,13 +482,48 @@ func Test_popup_menu() unmenu PopUp endfunc +func Test_popup_menu_truncated() + CheckNotGui + + set mouse=a mousemodel=popup + aunmenu PopUp + for i in range(2 * &lines) + exe $'menu PopUp.{i} <Cmd>let g:res = {i}<CR>' + endfor + + func LeftClickExpr(row, col) + call Ntest_setmouse(a:row, a:col) + return "\<LeftMouse>" + endfunc + + " Clicking at the bottom should place popup menu above click position. + " <RightRelease> should not select an item immediately. + let g:res = -1 + call Ntest_setmouse(&lines, 1) + nnoremap <expr><F2> LeftClickExpr(4, 1) + call feedkeys("\<RightMouse>\<RightRelease>\<F2>", 'tx') + call assert_equal(3, g:res) + + " Clicking at the top should place popup menu below click position. + let g:res = -1 + call Ntest_setmouse(1, 1) + nnoremap <expr><F2> LeftClickExpr(5, 1) + call feedkeys("\<RightMouse>\<RightRelease>\<F2>", 'tx') + call assert_equal(3, g:res) + + nunmap <F2> + delfunc LeftClickExpr + unlet g:res + aunmenu PopUp + set mouse& mousemodel& +endfunc + " Test for MenuPopup autocommand func Test_autocmd_MenuPopup() CheckNotGui - set mouse=a - set mousemodel=popup - aunmenu * + set mouse=a mousemodel=popup + aunmenu PopUp autocmd MenuPopup * exe printf( \ 'anoremenu PopUp.Foo <Cmd>let g:res = ["%s", "%s"]<CR>', \ expand('<afile>'), expand('<amatch>')) diff --git a/test/old/testdir/test_method.vim b/test/old/testdir/test_method.vim index 88dbbd7bf4..ca1ca7d573 100644 --- a/test/old/testdir/test_method.vim +++ b/test/old/testdir/test_method.vim @@ -20,9 +20,8 @@ func Test_list_method() call assert_equal(2, l->get(1)) call assert_equal(1, l->index(2)) call assert_equal([0, 1, 2, 3], [1, 2, 3]->insert(0)) - call assert_fails('eval l->items()', 'E715:') call assert_equal('1 2 3', l->join()) - call assert_fails('eval l->keys()', 'E715:') + call assert_fails('eval l->keys()', 'E1206:') call assert_equal(3, l->len()) call assert_equal([2, 3, 4], [1, 2, 3]->map('v:val + 1')) call assert_equal(3, l->max()) @@ -34,7 +33,7 @@ func Test_list_method() call assert_equal('[1, 2, 3]', l->string()) call assert_equal(v:t_list, l->type()) call assert_equal([1, 2, 3], [1, 1, 2, 3, 3]->uniq()) - call assert_fails('eval l->values()', 'E715:') + call assert_fails('eval l->values()', 'E1206:') call assert_fails('echo []->len', 'E107:') endfunc @@ -79,6 +78,7 @@ func Test_string_method() eval "a\rb\ec"->strtrans()->assert_equal('a^Mb^[c') eval "aã‚b"->strwidth()->assert_equal(4) eval 'abc'->substitute('b', 'x', '')->assert_equal('axc') + call assert_fails('eval 123->items()', 'E1225:') eval 'abc'->printf('the %s arg')->assert_equal('the abc arg') endfunc @@ -128,12 +128,19 @@ endfunc func Test_method_syntax() eval [1, 2, 3] ->sort( ) - eval [1, 2, 3] + eval [1, 2, 3] \ ->sort( \ ) call assert_fails('eval [1, 2, 3]-> sort()', 'E15:') call assert_fails('eval [1, 2, 3]->sort ()', 'E274:') call assert_fails('eval [1, 2, 3]-> sort ()', 'E15:') + + " Test for using a method name containing a curly brace name + let s = 'len' + call assert_equal(4, "xxxx"->str{s}()) + + " Test for using a method in an interpolated string + call assert_equal('4', $'{"xxxx"->strlen()}') endfunc func Test_method_lambda() diff --git a/test/old/testdir/test_normal.vim b/test/old/testdir/test_normal.vim index a2ef07193d..46fddd6c1a 100644 --- a/test/old/testdir/test_normal.vim +++ b/test/old/testdir/test_normal.vim @@ -403,17 +403,17 @@ func Test_normal08_fold() " First fold norm! V4jzf " check that folds have been created - call assert_equal(['50/*{{{*/', '51', '52', '53', '54/*}}}*/'], getline(50,54)) + call assert_equal(['50/* {{{ */', '51', '52', '53', '54/* }}} */'], getline(50,54)) " Second fold 46 norm! V10jzf " check that folds have been created - call assert_equal('46/*{{{*/', getline(46)) - call assert_equal('60/*}}}*/', getline(60)) + call assert_equal('46/* {{{ */', getline(46)) + call assert_equal('60/* }}} */', getline(60)) norm! k call assert_equal('45', getline('.')) norm! j - call assert_equal('46/*{{{*/', getline('.')) + call assert_equal('46/* {{{ */', getline('.')) norm! j call assert_equal('61', getline('.')) norm! k @@ -422,12 +422,12 @@ func Test_normal08_fold() norm! k call assert_equal('45', getline('.')) norm! j - call assert_equal('46/*{{{*/', getline('.')) + call assert_equal('46/* {{{ */', getline('.')) norm! j call assert_equal('47', getline('.')) norm! k norm! zcVzO - call assert_equal('46/*{{{*/', getline('.')) + call assert_equal('46/* {{{ */', getline('.')) norm! j call assert_equal('47', getline('.')) norm! j @@ -435,7 +435,7 @@ func Test_normal08_fold() norm! j call assert_equal('49', getline('.')) norm! j - call assert_equal('50/*{{{*/', getline('.')) + call assert_equal('50/* {{{ */', getline('.')) norm! j call assert_equal('51', getline('.')) " delete folds @@ -1387,14 +1387,14 @@ func Test_normal18_z_fold() " First fold norm! 4zF " check that folds have been created - call assert_equal(['50/*{{{*/', '51', '52', '53/*}}}*/'], getline(50,53)) + call assert_equal(['50/* {{{ */', '51', '52', '53/* }}} */'], getline(50,53)) " Test for zd 51 norm! 2zF call assert_equal(2, foldlevel('.')) norm! kzd - call assert_equal(['50', '51/*{{{*/', '52/*}}}*/', '53'], getline(50,53)) + call assert_equal(['50', '51/* {{{ */', '52/* }}} */', '53'], getline(50,53)) norm! j call assert_equal(1, foldlevel('.')) @@ -1413,7 +1413,7 @@ func Test_normal18_z_fold() norm! 2zF 90 norm! 4zF - call assert_equal(['85/*{{{*/', '86/*{{{*/', '87/*}}}*/', '88/*}}}*/', '89', '90/*{{{*/', '91', '92', '93/*}}}*/'], getline(85,93)) + call assert_equal(['85/* {{{ */', '86/* {{{ */', '87/* }}} */', '88/* }}} */', '89', '90/* {{{ */', '91', '92', '93/* }}} */'], getline(85,93)) norm! zE call assert_equal(['85', '86', '87', '88', '89', '90', '91', '92', '93'], getline(85,93)) @@ -1425,9 +1425,9 @@ func Test_normal18_z_fold() norm! k call assert_equal('49', getline('.')) norm! j - call assert_equal('50/*{{{*/', getline('.')) + call assert_equal('50/* {{{ */', getline('.')) norm! j - call assert_equal('51/*}}}*/', getline('.')) + call assert_equal('51/* }}} */', getline('.')) norm! j call assert_equal('52', getline('.')) call assert_equal(0, &foldenable) @@ -1437,7 +1437,7 @@ func Test_normal18_z_fold() norm! zN call assert_equal('49', getline('.')) norm! j - call assert_equal('50/*{{{*/', getline('.')) + call assert_equal('50/* {{{ */', getline('.')) norm! j call assert_equal('52', getline('.')) call assert_equal(1, &foldenable) @@ -1458,9 +1458,9 @@ func Test_normal18_z_fold() norm! k call assert_equal('49', getline('.')) norm! j - call assert_equal('50/*{{{*/', getline('.')) + call assert_equal('50/* {{{ */', getline('.')) norm! j - call assert_equal('51/*}}}*/', getline('.')) + call assert_equal('51/* }}} */', getline('.')) norm! j call assert_equal('52', getline('.')) 50 @@ -1468,7 +1468,7 @@ func Test_normal18_z_fold() norm! k call assert_equal('49', getline('.')) norm! j - call assert_equal('50/*{{{*/', getline('.')) + call assert_equal('50/* {{{ */', getline('.')) norm! j call assert_equal('52', getline('.')) @@ -1477,14 +1477,14 @@ func Test_normal18_z_fold() norm! k call assert_equal('48', getline('.')) norm! j - call assert_equal('49/*{{{*/', getline('.')) + call assert_equal('49/* {{{ */', getline('.')) norm! j call assert_equal('55', getline('.')) 49 norm! za - call assert_equal('49/*{{{*/', getline('.')) + call assert_equal('49/* {{{ */', getline('.')) norm! j - call assert_equal('50/*{{{*/', getline('.')) + call assert_equal('50/* {{{ */', getline('.')) norm! j call assert_equal('52', getline('.')) set nofoldenable @@ -1498,11 +1498,11 @@ func Test_normal18_z_fold() norm! 2k call assert_equal('48', getline('.')) norm! j - call assert_equal('49/*{{{*/', getline('.')) + call assert_equal('49/* {{{ */', getline('.')) norm! j - call assert_equal('50/*{{{*/', getline('.')) + call assert_equal('50/* {{{ */', getline('.')) norm! j - call assert_equal('51/*}}}*/', getline('.')) + call assert_equal('51/* }}} */', getline('.')) norm! j call assert_equal('52', getline('.')) @@ -1514,15 +1514,15 @@ func Test_normal18_z_fold() norm! 2k call assert_equal('48', getline('.')) norm! j - call assert_equal('49/*{{{*/', getline('.')) + call assert_equal('49/* {{{ */', getline('.')) norm! j - call assert_equal('50/*{{{*/', getline('.')) + call assert_equal('50/* {{{ */', getline('.')) norm! j - call assert_equal('51/*}}}*/', getline('.')) + call assert_equal('51/* }}} */', getline('.')) norm! j call assert_equal('52', getline('.')) - " zA on a opened fold when foldenable is not set + " zA on an opened fold when foldenable is not set 50 set nofoldenable norm! zA @@ -1530,7 +1530,7 @@ func Test_normal18_z_fold() norm! k call assert_equal('48', getline('.')) norm! j - call assert_equal('49/*{{{*/', getline('.')) + call assert_equal('49/* {{{ */', getline('.')) norm! j call assert_equal('55', getline('.')) @@ -1550,7 +1550,7 @@ func Test_normal18_z_fold() norm! k call assert_equal('48', getline('.')) norm! j - call assert_equal('49/*{{{*/', getline('.')) + call assert_equal('49/* {{{ */', getline('.')) norm! j call assert_equal('55', getline('.')) set nofoldenable @@ -1559,7 +1559,7 @@ func Test_normal18_z_fold() norm! k call assert_equal('48', getline('.')) norm! j - call assert_equal('49/*{{{*/', getline('.')) + call assert_equal('49/* {{{ */', getline('.')) norm! j call assert_equal('55', getline('.')) @@ -1569,7 +1569,7 @@ func Test_normal18_z_fold() norm! zCk call assert_equal('48', getline('.')) norm! j - call assert_equal('49/*{{{*/', getline('.')) + call assert_equal('49/* {{{ */', getline('.')) norm! j call assert_equal('55', getline('.')) @@ -1580,7 +1580,7 @@ func Test_normal18_z_fold() norm! zx call assert_equal(1, &foldenable) norm! j - call assert_equal('49/*{{{*/', getline('.')) + call assert_equal('49/* {{{ */', getline('.')) norm! j call assert_equal('55', getline('.')) @@ -1592,17 +1592,17 @@ func Test_normal18_z_fold() norm! 3k call assert_equal('48', getline('.')) norm! j - call assert_equal('49/*{{{*/', getline('.')) + call assert_equal('49/* {{{ */', getline('.')) norm! j - call assert_equal('50/*{{{*/', getline('.')) + call assert_equal('50/* {{{ */', getline('.')) norm! j - call assert_equal('51/*}}}*/', getline('.')) + call assert_equal('51/* }}} */', getline('.')) norm! j call assert_equal('52', getline('.')) norm! j call assert_equal('53', getline('.')) norm! j - call assert_equal('54/*}}}*/', getline('.')) + call assert_equal('54/* }}} */', getline('.')) norm! j call assert_equal('55', getline('.')) @@ -1614,15 +1614,15 @@ func Test_normal18_z_fold() call assert_equal(1, &foldenable) call assert_equal('48', getline('.')) norm! j - call assert_equal('49/*{{{*/', getline('.')) + call assert_equal('49/* {{{ */', getline('.')) norm! j - call assert_equal('50/*{{{*/', getline('.')) + call assert_equal('50/* {{{ */', getline('.')) norm! j call assert_equal('52', getline('.')) norm! j call assert_equal('53', getline('.')) norm! j - call assert_equal('54/*}}}*/', getline('.')) + call assert_equal('54/* }}} */', getline('.')) norm! j call assert_equal('55', getline('.')) @@ -1635,7 +1635,7 @@ func Test_normal18_z_fold() norm! k call assert_equal('48', getline('.')) norm! j - call assert_equal('49/*{{{*/', getline('.')) + call assert_equal('49/* {{{ */', getline('.')) norm! j call assert_equal('55', getline('.')) @@ -1652,7 +1652,7 @@ func Test_normal18_z_fold() norm! k call assert_equal('48', getline('.')) norm! j - call assert_equal('49/*{{{*/', getline('.')) + call assert_equal('49/* {{{ */', getline('.')) norm! j call assert_equal('55', getline('.')) @@ -1671,7 +1671,7 @@ func Test_normal18_z_fold() call assert_equal(0, &foldlevel) call assert_equal('48', getline('.')) norm! j - call assert_equal('49/*{{{*/', getline('.')) + call assert_equal('49/* {{{ */', getline('.')) norm! j call assert_equal('55', getline('.')) @@ -1689,11 +1689,11 @@ func Test_normal18_z_fold() call assert_equal(2, &foldlevel) call assert_equal('48', getline('.')) norm! j - call assert_equal('49/*{{{*/', getline('.')) + call assert_equal('49/* {{{ */', getline('.')) norm! j - call assert_equal('50/*{{{*/', getline('.')) + call assert_equal('50/* {{{ */', getline('.')) norm! j - call assert_equal('51/*}}}*/', getline('.')) + call assert_equal('51/* }}} */', getline('.')) norm! j call assert_equal('52', getline('.')) @@ -1709,24 +1709,24 @@ func Test_normal18_z_fold() call assert_equal(2, &foldlevel) call assert_equal('48', getline('.')) norm! j - call assert_equal('49/*{{{*/', getline('.')) + call assert_equal('49/* {{{ */', getline('.')) norm! j - call assert_equal('50/*{{{*/', getline('.')) + call assert_equal('50/* {{{ */', getline('.')) norm! j - call assert_equal('51/*}}}*/', getline('.')) + call assert_equal('51/* }}} */', getline('.')) norm! j call assert_equal('52', getline('.')) - call append(50, ['a /*{{{*/', 'b /*}}}*/']) + call append(50, ['a /* {{{ */', 'b /* }}} */']) 48 call assert_equal('48', getline('.')) norm! j - call assert_equal('49/*{{{*/', getline('.')) + call assert_equal('49/* {{{ */', getline('.')) norm! j - call assert_equal('50/*{{{*/', getline('.')) + call assert_equal('50/* {{{ */', getline('.')) norm! j - call assert_equal('a /*{{{*/', getline('.')) + call assert_equal('a /* {{{ */', getline('.')) norm! j - call assert_equal('51/*}}}*/', getline('.')) + call assert_equal('51/* }}} */', getline('.')) norm! j call assert_equal('52', getline('.')) 48 @@ -1735,15 +1735,15 @@ func Test_normal18_z_fold() call assert_equal(3, &foldlevel) call assert_equal('48', getline('.')) norm! j - call assert_equal('49/*{{{*/', getline('.')) + call assert_equal('49/* {{{ */', getline('.')) norm! j - call assert_equal('50/*{{{*/', getline('.')) + call assert_equal('50/* {{{ */', getline('.')) norm! j - call assert_equal('a /*{{{*/', getline('.')) + call assert_equal('a /* {{{ */', getline('.')) norm! j - call assert_equal('b /*}}}*/', getline('.')) + call assert_equal('b /* }}} */', getline('.')) norm! j - call assert_equal('51/*}}}*/', getline('.')) + call assert_equal('51/* }}} */', getline('.')) norm! j call assert_equal('52', getline('.')) @@ -1878,7 +1878,7 @@ func Test_normal23_K() let not_gnu_man = has('mac') || has('bsd') if not_gnu_man - " In MacOS and BSD, the option for specifying a pager is different + " In macOS and BSD, the option for specifying a pager is different set keywordprg=man\ -P\ cat else set keywordprg=man\ --pager=cat @@ -2727,7 +2727,7 @@ func Test_normal33_g_cmd2() call assert_equal('foo first line', getline(1)) set virtualedit& - " Test for aboring a g command using CTRL-\ CTRL-G + " Test for aborting a g command using CTRL-\ CTRL-G exe "normal! g\<C-\>\<C-G>" call assert_equal('foo first line', getline('.')) @@ -3897,9 +3897,9 @@ func Test_normal_count_after_operator() bw! endfunc -func Test_normal_gj_on_extra_wide_char() +func Test_normal_gj_on_6_cell_wide_unprintable_char() new | 25vsp - let text='1 foooooooo ar e insâ€zwe1 foooooooo insâ€zwei' . + let text='1 foooooooo ar e ins​zwe1 foooooooo ins​zwei' . \ ' i drei vier fünf sechs sieben acht un zehn elf zwöfl' . \ ' dreizehn v ierzehn fünfzehn' put =text @@ -4267,12 +4267,16 @@ func Test_page_cursor_topbot() call assert_equal(18, line('.')) exe "norm! \<C-B>\<C-F>" call assert_equal(9, line('.')) + " Not when already at the start of the buffer. + exe "norm! ggj\<C-B>" + call assert_equal(2, line('.')) bwipe! endfunc " Test for Ctrl-D with long line func Test_halfpage_longline() 10new + 40vsplit call setline(1, ['long'->repeat(1000), 'short']) exe "norm! \<C-D>" call assert_equal(2, line('.')) @@ -4280,7 +4284,7 @@ func Test_halfpage_longline() endfunc " Test for Ctrl-E with long line and very narrow window, -" used to cause an inifite loop +" used to cause an infinite loop func Test_scroll_longline_no_loop() 4vnew setl smoothscroll number showbreak=> scrolloff=2 @@ -4288,4 +4292,17 @@ func Test_scroll_longline_no_loop() exe "normal! \<C-E>" bwipe! endfunc + +" Test for go command +func Test_normal_go() + new + call setline(1, ['one two three four']) + call cursor(1, 5) + norm! dvgo + call assert_equal('wo three four', getline(1)) + norm! ... + call assert_equal('three four', getline(1)) + + bwipe! +endfunc " vim: shiftwidth=2 sts=2 expandtab nofoldenable diff --git a/test/old/testdir/test_options.vim b/test/old/testdir/test_options.vim index 7786f82af2..d0ae33605b 100644 --- a/test/old/testdir/test_options.vim +++ b/test/old/testdir/test_options.vim @@ -558,6 +558,9 @@ func Test_set_completion_string_values() " call assert_equal('sync', getcompletion('set swapsync=', 'cmdline')[1]) call assert_equal('usetab', getcompletion('set switchbuf=', 'cmdline')[1]) call assert_equal('ignore', getcompletion('set tagcase=', 'cmdline')[1]) + if exists('+tabclose') + call assert_equal('left uselast', join(sort(getcompletion('set tabclose=', 'cmdline'))), ' ') + endif if exists('+termwintype') call assert_equal('conpty', getcompletion('set termwintype=', 'cmdline')[1]) endif @@ -1364,6 +1367,31 @@ func Test_local_scrolloff() set siso& endfunc +func Test_writedelay() + CheckFunction reltimefloat + + new + call setline(1, 'empty') + " Nvim: 'writedelay' is applied per screen line. + " Create 7 vertical splits first. + vs | vs | vs | vs | vs | vs + redraw + set writedelay=10 + let start = reltime() + " call setline(1, repeat('x', 70)) + " Nvim: enable 'writedelay' per screen line. + " In each of the 7 vertical splits, 10 screen lines need to be drawn. + set redrawdebug+=line + call setline(1, repeat(['x'], 10)) + redraw + let elapsed = reltimefloat(reltime(start)) + set writedelay=0 + " With 'writedelay' set should take at least 30 * 10 msec + call assert_inrange(30 * 0.01, 999.0, elapsed) + + bwipe! +endfunc + func Test_visualbell() set belloff= set visualbell @@ -1377,9 +1405,10 @@ func Test_write() new call setline(1, ['L1']) set nowrite - call assert_fails('write Xfile', 'E142:') + call assert_fails('write Xwrfile', 'E142:') set write - close! + " close swapfile + bw! endfunc " Test for 'buftype' option @@ -1400,35 +1429,6 @@ func Test_buftype() bwipe! endfunc -" Test for the 'shell' option -func Test_shell() - throw 'Skipped: Nvim does not have :shell' - CheckUnix - let save_shell = &shell - set shell= - let caught_e91 = 0 - try - shell - catch /E91:/ - let caught_e91 = 1 - endtry - call assert_equal(1, caught_e91) - let &shell = save_shell -endfunc - -" Test for the 'shellquote' option -func Test_shellquote() - CheckUnix - set shellquote=# - set verbose=20 - redir => v - silent! !echo Hello - redir END - set verbose& - set shellquote& - call assert_match(': "#echo Hello#"', v) -endfunc - " Test for the 'rightleftcmd' option func Test_rightleftcmd() CheckFeature rightleft @@ -1761,7 +1761,7 @@ func Test_cmdheight() set cmdheight& endfunc -" To specify a control character as a option value, '^' can be used +" To specify a control character as an option value, '^' can be used func Test_opt_control_char() set wildchar=^v call assert_equal("\<C-V>", nr2char(&wildchar)) diff --git a/test/old/testdir/test_packadd.vim b/test/old/testdir/test_packadd.vim index 730cb3278b..47cf520bb9 100644 --- a/test/old/testdir/test_packadd.vim +++ b/test/old/testdir/test_packadd.vim @@ -258,6 +258,19 @@ func Test_packloadall() call assert_equal(4321, g:plugin_bar_number) endfunc +func Test_start_autoload() + " plugin foo with an autoload directory + let autodir = &packpath .. '/pack/mine/start/foo/autoload' + call mkdir(autodir, 'p') + let fname = autodir .. '/foobar.vim' + call writefile(['func foobar#test()', + \ ' return 1666', + \ 'endfunc'], fname) + + call assert_equal(1666, foobar#test()) + call delete(fname) +endfunc + func Test_helptags() let docdir1 = &packpath . '/pack/mine/start/foo/doc' let docdir2 = &packpath . '/pack/mine/start/bar/doc' diff --git a/test/old/testdir/test_partial.vim b/test/old/testdir/test_partial.vim index 8b62e4a0e5..b5933cdd6d 100644 --- a/test/old/testdir/test_partial.vim +++ b/test/old/testdir/test_partial.vim @@ -284,6 +284,11 @@ func Test_auto_partial_rebind() endfunc func Test_get_partial_items() + func s:Qux(x, y, z=3, w=1, ...) + endfunc + func s:Qux1(x, y) + endfunc + let dict = {'name': 'hello'} let args = ["foo", "bar"] let Func = function('MyDictFunc') @@ -304,6 +309,23 @@ func Test_get_partial_items() let dict = {'partial has': 'no dict'} call assert_equal(dict, get(P, 'dict', dict)) call assert_equal(0, get(l:P, 'dict')) + + call assert_equal({'required': 2, 'optional': 2, 'varargs': v:true}, + \ get(funcref('s:Qux', []), 'arity')) + call assert_equal({'required': 1, 'optional': 2, 'varargs': v:true}, + \ get(funcref('s:Qux', [1]), 'arity')) + call assert_equal({'required': 0, 'optional': 2, 'varargs': v:true}, + \ get(funcref('s:Qux', [1, 2]), 'arity')) + call assert_equal({'required': 0, 'optional': 1, 'varargs': v:true}, + \ get(funcref('s:Qux', [1, 2, 3]), 'arity')) + call assert_equal({'required': 0, 'optional': 0, 'varargs': v:true}, + \ get(funcref('s:Qux', [1, 2, 3, 4]), 'arity')) + " More args than expected is not an error + call assert_equal({'required': 0, 'optional': 0, 'varargs': v:false}, + \ get(funcref('s:Qux1', [1, 2, 3, 4]), 'arity')) + + delfunc s:Qux + delfunc s:Qux1 endfunc func Test_compare_partials() @@ -381,4 +403,18 @@ func Test_compare_partials() call assert_false(F1 is N1) endfunc +func Test_partial_method() + func Foo(x, y, z) + return x + y + z + endfunc + let d = {"Fn": function('Foo', [10, 20])} + call assert_fails('echo 30->d.Fn()', 'E1265: Cannot use a partial here') + delfunc Foo +endfunc + +func Test_non_callable_type_as_method() + let d = {"Fn": 10} + call assert_fails('echo 30->d.Fn()', 'E1085: Not a callable type: d.Fn') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_popup.vim b/test/old/testdir/test_popup.vim index 56c881b958..472882fb87 100644 --- a/test/old/testdir/test_popup.vim +++ b/test/old/testdir/test_popup.vim @@ -16,7 +16,7 @@ func ListMonths() if !empty(entered) let mth = filter(mth, 'v:val=~"^".entered') endif - call complete(1, mth) + call complete(1, mth) return '' endfunc @@ -74,7 +74,7 @@ func Test_popup_complete() call feedkeys("aJu\<f5>\<c-p>l\<c-y>", 'tx') call assert_equal(["Jul"], getline(1,2)) %d - + " any-non printable, non-white character: Add this character and " reduce number of matches call feedkeys("aJu\<f5>\<c-p>l\<c-n>\<c-y>", 'tx') @@ -96,7 +96,7 @@ func Test_popup_complete() call feedkeys("aJ\<f5>".repeat("\<c-n>",3)."\<c-l>\<esc>", 'tx') call assert_equal(["J"], getline(1,2)) %d - + " <c-l> - Insert one character from the current match call feedkeys("aJ\<f5>".repeat("\<c-n>",4)."\<c-l>\<esc>", 'tx') call assert_equal(["January"], getline(1,2)) @@ -857,7 +857,7 @@ func Test_popup_position() call term_sendkeys(buf, "jI123456789_\<Esc>") call term_sendkeys(buf, "GA\<C-N>") call VerifyScreenDump(buf, 'Test_popup_position_04', {'rows': 10}) - + call term_sendkeys(buf, "\<Esc>u") call StopVimInTerminal(buf) call delete('Xtest') @@ -910,6 +910,13 @@ func Test_popup_command_dump() call term_sendkeys(buf, "\<Esc>") + if has('rightleft') + call term_sendkeys(buf, ":set rightleft\<CR>") + call term_sendkeys(buf, "/X\<CR>:popup PopUp\<CR>") + call VerifyScreenDump(buf, 'Test_popup_command_rl', {}) + call term_sendkeys(buf, "\<Esc>:set norightleft\<CR>") + endif + " Set a timer to change a menu entry while it's displayed. The text should " not change but the command does. Making the screendump also verifies that " "changed" shows up, which means the timer triggered. @@ -932,6 +939,37 @@ func Test_popup_command_dump() call StopVimInTerminal(buf) endfunc +" Test position of right-click menu when clicking near window edge. +func Test_mouse_popup_position() + CheckFeature menu + CheckScreendump + + let script =<< trim END + set mousemodel=popup_setpos + source $VIMRUNTIME/menu.vim + call setline(1, join(range(20))) + func Trigger(col) + call test_setmouse(1, a:col) + call feedkeys("\<RightMouse>", 't') + endfunc + END + call writefile(script, 'XmousePopupPosition', 'D') + let buf = RunVimInTerminal('-S XmousePopupPosition', #{rows: 20, cols: 50}) + + call term_sendkeys(buf, ":call Trigger(45)\<CR>") + call VerifyScreenDump(buf, 'Test_mouse_popup_position_01', {}) + call term_sendkeys(buf, "\<Esc>") + + if has('rightleft') + call term_sendkeys(buf, ":set rightleft\<CR>") + call term_sendkeys(buf, ":call Trigger(50 + 1 - 45)\<CR>") + call VerifyScreenDump(buf, 'Test_mouse_popup_position_02', {}) + call term_sendkeys(buf, "\<Esc>:set norightleft\<CR>") + endif + + call StopVimInTerminal(buf) +endfunc + func Test_popup_complete_backwards() new call setline(1, ['Post', 'Port', 'Po']) @@ -1178,6 +1216,8 @@ func Test_CompleteChanged() set completeopt=menu,menuone call feedkeys("i\<C-X>\<C-O>\<BS>\<BS>\<BS>f", 'tx') call assert_equal('five', g:word) + call feedkeys("i\<C-X>\<C-O>\<BS>\<BS>\<BS>f\<BS>", 'tx') + call assert_equal('one', g:word) autocmd! AAAAA_Group set complete& completeopt& @@ -1346,4 +1386,275 @@ func Test_pum_highlights_custom() call StopVimInTerminal(buf) endfunc +" Test match relate highlight group in pmenu +func Test_pum_highlights_match() + CheckScreendump + let lines =<< trim END + func Omni_test(findstart, base) + if a:findstart + return col(".") + endif + return { + \ 'words': [ + \ { 'word': 'foo', 'kind': 'fookind' }, + \ { 'word': 'foofoo', 'kind': 'fookind' }, + \ { 'word': 'foobar', 'kind': 'fookind' }, + \ { 'word': 'fooBaz', 'kind': 'fookind' }, + \ { 'word': 'foobala', 'kind': 'fookind' }, + \ { 'word': 'ä½ å¥½' }, + \ { 'word': 'ä½ å¥½å—' }, + \ { 'word': 'ä½ ä¸å¥½å—' }, + \ { 'word': 'ä½ å¯å¥½å—' }, + \]} + endfunc + + func Comp() + let col = col('.') + if getline('.') == 'f' + let col -= 1 + endif + call complete(col, [ + \ #{word: "foo", icase: 1}, + \ #{word: "Foobar", icase: 1}, + \ #{word: "fooBaz", icase: 1}, + \]) + return '' + endfunc + + set omnifunc=Omni_test + set completeopt=menu,noinsert,fuzzy + hi PmenuMatchSel ctermfg=6 ctermbg=7 + hi PmenuMatch ctermfg=4 ctermbg=225 + END + call writefile(lines, 'Xscript', 'D') + let buf = RunVimInTerminal('-S Xscript', {}) + call TermWait(buf) + call term_sendkeys(buf, "i\<C-X>\<C-O>") + call TermWait(buf, 50) + call term_sendkeys(buf, "fo") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_pum_highlights_03', {}) + call term_sendkeys(buf, "\<Esc>S\<C-X>\<C-O>") + call TermWait(buf, 50) + call term_sendkeys(buf, "ä½ ") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_pum_highlights_04', {}) + call term_sendkeys(buf, "å—") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_pum_highlights_05', {}) + call term_sendkeys(buf, "\<C-E>\<Esc>") + + if has('rightleft') + call term_sendkeys(buf, ":set rightleft\<CR>") + call TermWait(buf, 50) + call term_sendkeys(buf, "S\<C-X>\<C-O>") + call TermWait(buf, 50) + call term_sendkeys(buf, "fo") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_pum_highlights_06', {}) + call term_sendkeys(buf, "\<Esc>S\<C-X>\<C-O>") + call TermWait(buf, 50) + call term_sendkeys(buf, "ä½ ") + call VerifyScreenDump(buf, 'Test_pum_highlights_06a', {}) + call term_sendkeys(buf, "å—") + call VerifyScreenDump(buf, 'Test_pum_highlights_06b', {}) + call term_sendkeys(buf, "\<C-E>\<Esc>") + call term_sendkeys(buf, ":set norightleft\<CR>") + call TermWait(buf) + endif + + call term_sendkeys(buf, ":set completeopt-=fuzzy\<CR>") + call TermWait(buf) + call term_sendkeys(buf, "S\<C-X>\<C-O>") + call TermWait(buf, 50) + call term_sendkeys(buf, "fo") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_pum_highlights_07', {}) + call term_sendkeys(buf, "\<C-E>\<Esc>") + + if has('rightleft') + call term_sendkeys(buf, ":set rightleft\<CR>") + call TermWait(buf, 50) + call term_sendkeys(buf, "S\<C-X>\<C-O>") + call TermWait(buf, 50) + call term_sendkeys(buf, "fo") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_pum_highlights_08', {}) + call term_sendkeys(buf, "\<C-E>\<Esc>") + call term_sendkeys(buf, ":set norightleft\<CR>") + endif + + call term_sendkeys(buf, "S\<C-R>=Comp()\<CR>f") + call VerifyScreenDump(buf, 'Test_pum_highlights_09', {}) + call term_sendkeys(buf, "o\<BS>\<C-R>=Comp()\<CR>") + call VerifyScreenDump(buf, 'Test_pum_highlights_09', {}) + + " issue #15095 wrong select + call term_sendkeys(buf, "\<ESC>:set completeopt=fuzzy,menu\<CR>") + call TermWait(buf) + call term_sendkeys(buf, "S hello helio hero h\<C-X>\<C-P>") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_pum_highlights_10', {}) + + call term_sendkeys(buf, "\<ESC>S hello helio hero h\<C-X>\<C-P>\<C-P>") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_pum_highlights_11', {}) + + call term_sendkeys(buf, "\<C-E>\<Esc>") + call TermWait(buf) + + call StopVimInTerminal(buf) +endfunc + +func Test_pum_user_hl_group() + CheckScreendump + let lines =<< trim END + func CompleteFunc( findstart, base ) + if a:findstart + return 0 + endif + return { + \ 'words': [ + \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', 'hl_group': 'StrikeFake' }, + \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'W', }, + \ { 'word': 'ä½ å¥½', 'menu': 'extra text 3', 'kind': 'W', 'hl_group': 'StrikeFake' }, + \]} + endfunc + set completeopt=menu + set completefunc=CompleteFunc + + hi StrikeFake ctermfg=9 + func HlMatch() + hi PmenuMatchSel ctermfg=6 ctermbg=7 cterm=underline + hi PmenuMatch ctermfg=4 ctermbg=225 cterm=underline + endfunc + END + call writefile(lines, 'Xscript', 'D') + let buf = RunVimInTerminal('-S Xscript', {}) + + call TermWait(buf) + call term_sendkeys(buf, "Saw\<C-X>\<C-U>") + call VerifyScreenDump(buf, 'Test_pum_highlights_12', {}) + call term_sendkeys(buf, "\<C-E>\<Esc>") + + call TermWait(buf) + call term_sendkeys(buf, ":call HlMatch()\<CR>") + + call TermWait(buf) + call term_sendkeys(buf, "Saw\<C-X>\<C-U>") + call VerifyScreenDump(buf, 'Test_pum_highlights_13', {}) + call term_sendkeys(buf, "\<C-N>") + call VerifyScreenDump(buf, 'Test_pum_highlights_14', {}) + call term_sendkeys(buf, "\<C-E>\<Esc>") + + call StopVimInTerminal(buf) +endfunc + +func Test_pum_user_kind_hlgroup() + CheckScreendump + let lines =<< trim END + func CompleteFunc( findstart, base ) + if a:findstart + return 0 + endif + return { + \ 'words': [ + \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'variable', 'kind_hlgroup': 'KindVar', 'hl_group': 'StrikeFake' }, + \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'function', 'kind_hlgroup': 'KindFunc' }, + \ { 'word': 'ä½ å¥½', 'menu': 'extra text 3', 'kind': 'class', 'kind_hlgroup': 'KindClass' }, + \]} + endfunc + set completeopt=menu + set completefunc=CompleteFunc + + hi StrikeFake ctermfg=9 + hi KindVar ctermfg=yellow + hi KindFunc ctermfg=blue + hi KindClass ctermfg=green + END + call writefile(lines, 'Xscript', 'D') + let buf = RunVimInTerminal('-S Xscript', {}) + + call TermWait(buf) + call term_sendkeys(buf, "S\<C-X>\<C-U>") + call VerifyScreenDump(buf, 'Test_pum_highlights_16', {}) + call term_sendkeys(buf, "\<C-E>\<Esc>") + + call StopVimInTerminal(buf) +endfunc + +func Test_pum_completeitemalign() + CheckScreendump + let lines =<< trim END + func Omni_test(findstart, base) + if a:findstart + return col(".") + endif + return { + \ 'words': [ + \ { 'word': 'foo', 'kind': 'S', 'menu': 'menu' }, + \ { 'word': 'bar', 'kind': 'T', 'menu': 'menu' }, + \ { 'word': 'ä½ å¥½', 'kind': 'C', 'menu': '䏿–‡' }, + \]} + endfunc + + func Omni_long(findstart, base) + if a:findstart + return col(".") + endif + return { + \ 'words': [ + \ { 'word': 'loooong_foo', 'kind': 'S', 'menu': 'menu' }, + \ { 'word': 'loooong_bar', 'kind': 'T', 'menu': 'menu' }, + \]} + endfunc + set omnifunc=Omni_test + command! -nargs=0 T1 set cia=abbr,kind,menu + command! -nargs=0 T2 set cia=abbr,menu,kind + command! -nargs=0 T3 set cia=kind,abbr,menu + command! -nargs=0 T4 set cia=kind,menu,abbr + command! -nargs=0 T5 set cia=menu,abbr,kind + command! -nargs=0 T6 set cia=menu,kind,abbr + command! -nargs=0 T7 set cia& + END + call writefile(lines, 'Xscript', 'D') + let buf = RunVimInTerminal('-S Xscript', {}) + call TermWait(buf) + + " T1 is default + call term_sendkeys(buf, ":T1\<CR>S\<C-X>\<C-O>") + call VerifyScreenDump(buf, 'Test_pum_completeitemalign_01', {}) + call term_sendkeys(buf, "\<C-E>\<Esc>") + + " T2 + call term_sendkeys(buf, ":T2\<CR>S\<C-X>\<C-O>") + call VerifyScreenDump(buf, 'Test_pum_completeitemalign_02', {}) + call term_sendkeys(buf, "\<C-E>\<Esc>") + + " T3 + call term_sendkeys(buf, ":T3\<CR>S\<C-X>\<C-O>") + call VerifyScreenDump(buf, 'Test_pum_completeitemalign_03', {}) + call term_sendkeys(buf, "\<C-E>\<Esc>") + + " T4 + call term_sendkeys(buf, ":T4\<CR>S\<C-X>\<C-O>") + call VerifyScreenDump(buf, 'Test_pum_completeitemalign_04', {}) + call term_sendkeys(buf, "\<C-E>\<Esc>") + + " T5 + call term_sendkeys(buf, ":T5\<CR>S\<C-X>\<C-O>") + call VerifyScreenDump(buf, 'Test_pum_completeitemalign_05', {}) + call term_sendkeys(buf, "\<C-E>\<Esc>") + + " T6 + call term_sendkeys(buf, ":T6\<CR>S\<C-X>\<C-O>") + call VerifyScreenDump(buf, 'Test_pum_completeitemalign_06', {}) + call term_sendkeys(buf, "\<C-E>\<Esc>") + + call term_sendkeys(buf, ":set columns=12 cmdheight=2 omnifunc=Omni_long\<CR>S\<C-X>\<C-O>") + call VerifyScreenDump(buf, 'Test_pum_completeitemalign_07', {}) + call term_sendkeys(buf, "\<C-E>\<Esc>:T7\<CR>") + call StopVimInTerminal(buf) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_put.vim b/test/old/testdir/test_put.vim index 73b58dbe33..6b332faaeb 100644 --- a/test/old/testdir/test_put.vim +++ b/test/old/testdir/test_put.vim @@ -168,12 +168,6 @@ func Test_very_large_count() endfunc func Test_very_large_count_64bit() - throw 'Skipped: v:sizeoflong is N/A' " use legacy/put_spec.lua instead - - if v:sizeoflong < 8 - throw 'Skipped: only works with 64 bit long ints' - endif - new let @" = repeat('x', 100) call assert_fails('norm 999999999p', 'E1240:') @@ -190,12 +184,6 @@ func Test_very_large_count_block() endfunc func Test_very_large_count_block_64bit() - throw 'Skipped: v:sizeoflong is N/A' " use legacy/put_spec.lua instead - - if v:sizeoflong < 8 - throw 'Skipped: only works with 64 bit long ints' - endif - new call setline(1, repeat('x', 100)) exe "norm \<C-V>$y" diff --git a/test/old/testdir/test_quickfix.vim b/test/old/testdir/test_quickfix.vim index a708cabc26..753875963b 100644 --- a/test/old/testdir/test_quickfix.vim +++ b/test/old/testdir/test_quickfix.vim @@ -1020,52 +1020,50 @@ endfunc " More tests for 'errorformat' func Test_efm1() - if !has('unix') - " The 'errorformat' setting is different on non-Unix systems. - " This test works only on Unix-like systems. - return - endif + " The 'errorformat' setting is different on non-Unix systems. + " This test works only on Unix-like systems. + CheckUnix + + let l =<< trim [DATA] + "Xtestfile", line 4.12: 1506-045 (S) Undeclared identifier fd_set. + "Xtestfile", line 6 col 19; this is an error + gcc -c -DHAVE_CONFIsing-prototypes -I/usr/X11R6/include version.c + Xtestfile:9: parse error before `asd' + make: *** [src/vim/testdir/Makefile:100: test_quickfix] Error 1 + in file "Xtestfile" linenr 10: there is an error + + 2 returned + "Xtestfile", line 11 col 1; this is an error + "Xtestfile", line 12 col 2; this is another error + "Xtestfile", line 14:10; this is an error in column 10 + =Xtestfile=, line 15:10; this is another error, but in vcol 10 this time + "Xtestfile", linenr 16: yet another problem + Error in "Xtestfile" at line 17: + x should be a dot + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 17 + ^ + Error in "Xtestfile" at line 18: + x should be a dot + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 18 + .............^ + Error in "Xtestfile" at line 19: + x should be a dot + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 19 + --------------^ + Error in "Xtestfile" at line 20: + x should be a dot + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 20 + ^ - let l =<< trim [DATA] - "Xtestfile", line 4.12: 1506-045 (S) Undeclared identifier fd_set. - "Xtestfile", line 6 col 19; this is an error - gcc -c -DHAVE_CONFIsing-prototypes -I/usr/X11R6/include version.c - Xtestfile:9: parse error before `asd' - make: *** [src/vim/testdir/Makefile:100: test_quickfix] Error 1 - in file "Xtestfile" linenr 10: there is an error - - 2 returned - "Xtestfile", line 11 col 1; this is an error - "Xtestfile", line 12 col 2; this is another error - "Xtestfile", line 14:10; this is an error in column 10 - =Xtestfile=, line 15:10; this is another error, but in vcol 10 this time - "Xtestfile", linenr 16: yet another problem - Error in "Xtestfile" at line 17: - x should be a dot - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 17 - ^ - Error in "Xtestfile" at line 18: - x should be a dot - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 18 - .............^ - Error in "Xtestfile" at line 19: - x should be a dot - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 19 - --------------^ - Error in "Xtestfile" at line 20: - x should be a dot - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 20 - ^ - - Does anyone know what is the problem and how to correction it? - "Xtestfile", line 21 col 9: What is the title of the quickfix window? - "Xtestfile", line 22 col 9: What is the title of the quickfix window? - [DATA] - - call writefile(l, 'Xerrorfile1') - call writefile(l[:-2], 'Xerrorfile2') - - let m =<< [DATA] + Does anyone know what is the problem and how to correction it? + "Xtestfile", line 21 col 9: What is the title of the quickfix window? + "Xtestfile", line 22 col 9: What is the title of the quickfix window? + [DATA] + + call writefile(l, 'Xerrorfile1') + call writefile(l[:-2], 'Xerrorfile2') + + let m =<< [DATA] xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 2 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 4 @@ -1088,55 +1086,55 @@ func Test_efm1() xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 21 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 22 [DATA] - call writefile(m, 'Xtestfile') + call writefile(m, 'Xtestfile') - let save_efm = &efm - set efm+==%f=\\,\ line\ %l%*\\D%v%*[^\ ]\ %m - set efm^=%AError\ in\ \"%f\"\ at\ line\ %l:,%Z%p^,%C%m + let save_efm = &efm + set efm+==%f=\\,\ line\ %l%*\\D%v%*[^\ ]\ %m + set efm^=%AError\ in\ \"%f\"\ at\ line\ %l:,%Z%p^,%C%m - exe 'cf Xerrorfile2' - clast - copen - call assert_equal(':cf Xerrorfile2', w:quickfix_title) - wincmd p + exe 'cf Xerrorfile2' + clast + copen + call assert_equal(':cf Xerrorfile2', w:quickfix_title) + wincmd p - exe 'cf Xerrorfile1' - call assert_equal([4, 12], [line('.'), col('.')]) - cn - call assert_equal([6, 19], [line('.'), col('.')]) - cn - call assert_equal([9, 2], [line('.'), col('.')]) - cn - call assert_equal([10, 2], [line('.'), col('.')]) - cn - call assert_equal([11, 1], [line('.'), col('.')]) - cn - call assert_equal([12, 2], [line('.'), col('.')]) - cn - call assert_equal([14, 10], [line('.'), col('.')]) - cn - call assert_equal([15, 3, 10], [line('.'), col('.'), virtcol('.')]) - cn - call assert_equal([16, 2], [line('.'), col('.')]) - cn - call assert_equal([17, 6], [line('.'), col('.')]) - cn - call assert_equal([18, 7], [line('.'), col('.')]) - cn - call assert_equal([19, 8], [line('.'), col('.')]) - cn - call assert_equal([20, 9], [line('.'), col('.')]) - clast - cprev - cprev - wincmd w - call assert_equal(':cf Xerrorfile1', w:quickfix_title) - wincmd p + exe 'cf Xerrorfile1' + call assert_equal([4, 12], [line('.'), col('.')]) + cn + call assert_equal([6, 19], [line('.'), col('.')]) + cn + call assert_equal([9, 2], [line('.'), col('.')]) + cn + call assert_equal([10, 2], [line('.'), col('.')]) + cn + call assert_equal([11, 1], [line('.'), col('.')]) + cn + call assert_equal([12, 2], [line('.'), col('.')]) + cn + call assert_equal([14, 10], [line('.'), col('.')]) + cn + call assert_equal([15, 3, 10], [line('.'), col('.'), virtcol('.')]) + cn + call assert_equal([16, 2], [line('.'), col('.')]) + cn + call assert_equal([17, 6], [line('.'), col('.')]) + cn + call assert_equal([18, 7], [line('.'), col('.')]) + cn + call assert_equal([19, 8], [line('.'), col('.')]) + cn + call assert_equal([20, 9], [line('.'), col('.')]) + clast + cprev + cprev + wincmd w + call assert_equal(':cf Xerrorfile1', w:quickfix_title) + wincmd p - let &efm = save_efm - call delete('Xerrorfile1') - call delete('Xerrorfile2') - call delete('Xtestfile') + let &efm = save_efm + call delete('Xerrorfile1') + call delete('Xerrorfile2') + call delete('Xtestfile') endfunc " Test for quickfix directory stack support @@ -1410,7 +1408,7 @@ func Test_efm2() failUnlessEqual raise self.failureException, \\ W:AssertionError: 34 != 33 - + -------------------------------------------------------------- Ran 27 tests in 0.063s [DATA] @@ -2210,10 +2208,8 @@ func s:test_xgrep(cchar) endfunc func Test_grep() - if !has('unix') - " The grepprg may not be set on non-Unix systems - return - endif + " The grepprg may not be set on non-Unix systems + CheckUnix call s:test_xgrep('c') call s:test_xgrep('l') @@ -2351,254 +2347,254 @@ endfunc " Quickfix/Location list set/get properties tests func Xproperty_tests(cchar) - call s:setup_commands(a:cchar) + call s:setup_commands(a:cchar) - " Error cases - call assert_fails('call g:Xgetlist(99)', 'E715:') - call assert_fails('call g:Xsetlist(99)', 'E714:') - call assert_fails('call g:Xsetlist([], "a", [])', 'E715:') + " Error cases + call assert_fails('call g:Xgetlist(99)', 'E715:') + call assert_fails('call g:Xsetlist(99)', 'E714:') + call assert_fails('call g:Xsetlist([], "a", [])', 'E715:') - " Set and get the title - call g:Xsetlist([]) - Xopen - wincmd p - call g:Xsetlist([{'filename':'foo', 'lnum':27}]) - let s = g:Xsetlist([], 'a', {'title' : 'Sample'}) - call assert_equal(0, s) - let d = g:Xgetlist({"title":1}) - call assert_equal('Sample', d.title) - " Try setting title to a non-string value - call assert_equal(-1, g:Xsetlist([], 'a', {'title' : ['Test']})) - call assert_equal('Sample', g:Xgetlist({"title":1}).title) + " Set and get the title + call g:Xsetlist([]) + Xopen + wincmd p + call g:Xsetlist([{'filename':'foo', 'lnum':27}]) + let s = g:Xsetlist([], 'a', {'title' : 'Sample'}) + call assert_equal(0, s) + let d = g:Xgetlist({"title":1}) + call assert_equal('Sample', d.title) + " Try setting title to a non-string value + call assert_equal(-1, g:Xsetlist([], 'a', {'title' : ['Test']})) + call assert_equal('Sample', g:Xgetlist({"title":1}).title) - Xopen - call assert_equal('Sample', w:quickfix_title) - Xclose - - " Tests for action argument - silent! Xolder 999 - let qfnr = g:Xgetlist({'all':1}).nr - call g:Xsetlist([], 'r', {'title' : 'N1'}) - call assert_equal('N1', g:Xgetlist({'all':1}).title) - call g:Xsetlist([], ' ', {'title' : 'N2'}) - call assert_equal(qfnr + 1, g:Xgetlist({'all':1}).nr) - - let res = g:Xgetlist({'nr': 0}) - call assert_equal(qfnr + 1, res.nr) - call assert_equal(['nr'], keys(res)) - - call g:Xsetlist([], ' ', {'title' : 'N3'}) - call assert_equal('N2', g:Xgetlist({'nr':2, 'title':1}).title) - - " Changing the title of an earlier quickfix list - call g:Xsetlist([], 'r', {'title' : 'NewTitle', 'nr' : 2}) - call assert_equal('NewTitle', g:Xgetlist({'nr':2, 'title':1}).title) - - " Changing the title of an invalid quickfix list - call assert_equal(-1, g:Xsetlist([], ' ', - \ {'title' : 'SomeTitle', 'nr' : 99})) - call assert_equal(-1, g:Xsetlist([], ' ', - \ {'title' : 'SomeTitle', 'nr' : 'abc'})) - - if a:cchar == 'c' - copen - call assert_equal({'winid':win_getid()}, getqflist({'winid':1})) - cclose - endif + Xopen + call assert_equal('Sample', w:quickfix_title) + Xclose - " Invalid arguments - call assert_fails('call g:Xgetlist([])', 'E715') - call assert_fails('call g:Xsetlist([], "a", [])', 'E715') - let s = g:Xsetlist([], 'a', {'abc':1}) - call assert_equal(-1, s) + " Tests for action argument + silent! Xolder 999 + let qfnr = g:Xgetlist({'all':1}).nr + call g:Xsetlist([], 'r', {'title' : 'N1'}) + call assert_equal('N1', g:Xgetlist({'all':1}).title) + call g:Xsetlist([], ' ', {'title' : 'N2'}) + call assert_equal(qfnr + 1, g:Xgetlist({'all':1}).nr) - call assert_equal({}, g:Xgetlist({'abc':1})) - call assert_equal('', g:Xgetlist({'nr':99, 'title':1}).title) - call assert_equal('', g:Xgetlist({'nr':[], 'title':1}).title) + let res = g:Xgetlist({'nr': 0}) + call assert_equal(qfnr + 1, res.nr) + call assert_equal(['nr'], keys(res)) - if a:cchar == 'l' - call assert_equal({}, getloclist(99, {'title': 1})) - endif + call g:Xsetlist([], ' ', {'title' : 'N3'}) + call assert_equal('N2', g:Xgetlist({'nr':2, 'title':1}).title) - " Context related tests - let s = g:Xsetlist([], 'a', {'context':[1,2,3]}) - call assert_equal(0, s) - call test_garbagecollect_now() - let d = g:Xgetlist({'context':1}) - call assert_equal([1,2,3], d.context) - call g:Xsetlist([], 'a', {'context':{'color':'green'}}) - let d = g:Xgetlist({'context':1}) - call assert_equal({'color':'green'}, d.context) - call g:Xsetlist([], 'a', {'context':"Context info"}) - let d = g:Xgetlist({'context':1}) - call assert_equal("Context info", d.context) - call g:Xsetlist([], 'a', {'context':246}) - let d = g:Xgetlist({'context':1}) - call assert_equal(246, d.context) - " set other Vim data types as context - call g:Xsetlist([], 'a', {'context' : v:_null_blob}) - if has('channel') - call g:Xsetlist([], 'a', {'context' : test_null_channel()}) - endif - if has('job') - call g:Xsetlist([], 'a', {'context' : test_null_job()}) - endif - " Nvim doesn't have null functions - " call g:Xsetlist([], 'a', {'context' : test_null_function()}) - " Nvim doesn't have null partials - " call g:Xsetlist([], 'a', {'context' : test_null_partial()}) - call g:Xsetlist([], 'a', {'context' : ''}) - call test_garbagecollect_now() - if a:cchar == 'l' - " Test for copying context across two different location lists - new | only - let w1_id = win_getid() - let l = [1] - call setloclist(0, [], 'a', {'context':l}) - new - let w2_id = win_getid() - call add(l, 2) - call assert_equal([1, 2], getloclist(w1_id, {'context':1}).context) - call assert_equal([1, 2], getloclist(w2_id, {'context':1}).context) - unlet! l - call assert_equal([1, 2], getloclist(w2_id, {'context':1}).context) - only - call setloclist(0, [], 'f') - call assert_equal('', getloclist(0, {'context':1}).context) - endif + " Changing the title of an earlier quickfix list + call g:Xsetlist([], 'r', {'title' : 'NewTitle', 'nr' : 2}) + call assert_equal('NewTitle', g:Xgetlist({'nr':2, 'title':1}).title) - " Test for changing the context of previous quickfix lists - call g:Xsetlist([], 'f') - Xexpr "One" - Xexpr "Two" - Xexpr "Three" - call g:Xsetlist([], 'r', {'context' : [1], 'nr' : 1}) - call g:Xsetlist([], 'a', {'context' : [2], 'nr' : 2}) - " Also, check for setting the context using quickfix list number zero. - call g:Xsetlist([], 'r', {'context' : [3], 'nr' : 0}) - call test_garbagecollect_now() - let l = g:Xgetlist({'nr' : 1, 'context' : 1}) - call assert_equal([1], l.context) - let l = g:Xgetlist({'nr' : 2, 'context' : 1}) - call assert_equal([2], l.context) - let l = g:Xgetlist({'nr' : 3, 'context' : 1}) - call assert_equal([3], l.context) - - " Test for changing the context through reference and for garbage - " collection of quickfix context - let l = ["red"] - call g:Xsetlist([], ' ', {'context' : l}) - call add(l, "blue") - let x = g:Xgetlist({'context' : 1}) - call add(x.context, "green") - call assert_equal(["red", "blue", "green"], l) - call assert_equal(["red", "blue", "green"], x.context) - unlet l - call test_garbagecollect_now() - let m = g:Xgetlist({'context' : 1}) - call assert_equal(["red", "blue", "green"], m.context) - - " Test for setting/getting items - Xexpr "" - let qfprev = g:Xgetlist({'nr':0}) - let s = g:Xsetlist([], ' ', {'title':'Green', - \ 'items' : [{'filename':'F1', 'lnum':10}]}) - call assert_equal(0, s) - let qfcur = g:Xgetlist({'nr':0}) - call assert_true(qfcur.nr == qfprev.nr + 1) - let l = g:Xgetlist({'items':1}) - call assert_equal('F1', bufname(l.items[0].bufnr)) - call assert_equal(10, l.items[0].lnum) - call g:Xsetlist([], 'a', {'items' : [{'filename':'F2', 'lnum':20}, - \ {'filename':'F2', 'lnum':30}]}) - let l = g:Xgetlist({'items':1}) - call assert_equal('F2', bufname(l.items[2].bufnr)) - call assert_equal(30, l.items[2].lnum) - call g:Xsetlist([], 'r', {'items' : [{'filename':'F3', 'lnum':40}]}) - let l = g:Xgetlist({'items':1}) - call assert_equal('F3', bufname(l.items[0].bufnr)) - call assert_equal(40, l.items[0].lnum) - call g:Xsetlist([], 'r', {'items' : []}) - let l = g:Xgetlist({'items':1}) - call assert_equal(0, len(l.items)) - - call g:Xsetlist([], 'r', {'title' : 'TestTitle'}) - call g:Xsetlist([], 'r', {'items' : [{'filename' : 'F1', 'lnum' : 10, 'text' : 'L10'}]}) - call g:Xsetlist([], 'r', {'items' : [{'filename' : 'F1', 'lnum' : 10, 'text' : 'L10'}]}) - call assert_equal('TestTitle', g:Xgetlist({'title' : 1}).title) - - " Test for getting id of window associated with a location list window - if a:cchar == 'l' - only - call assert_equal(0, g:Xgetlist({'all' : 1}).filewinid) - let wid = win_getid() - Xopen - call assert_equal(wid, g:Xgetlist({'filewinid' : 1}).filewinid) - wincmd w - call assert_equal(0, g:Xgetlist({'filewinid' : 1}).filewinid) - only - endif + " Changing the title of an invalid quickfix list + call assert_equal(-1, g:Xsetlist([], ' ', + \ {'title' : 'SomeTitle', 'nr' : 99})) + call assert_equal(-1, g:Xsetlist([], ' ', + \ {'title' : 'SomeTitle', 'nr' : 'abc'})) - " The following used to crash Vim with address sanitizer - call g:Xsetlist([], 'f') - call g:Xsetlist([], 'a', {'items' : [{'filename':'F1', 'lnum':10}]}) - call assert_equal(10, g:Xgetlist({'items':1}).items[0].lnum) + if a:cchar == 'c' + copen + call assert_equal({'winid':win_getid()}, getqflist({'winid':1})) + cclose + endif - " Try setting the items using a string - call assert_equal(-1, g:Xsetlist([], ' ', {'items' : 'Test'})) + " Invalid arguments + call assert_fails('call g:Xgetlist([])', 'E715') + call assert_fails('call g:Xsetlist([], "a", [])', 'E715') + let s = g:Xsetlist([], 'a', {'abc':1}) + call assert_equal(-1, s) - " Save and restore the quickfix stack - call g:Xsetlist([], 'f') - call assert_equal(0, g:Xgetlist({'nr':'$'}).nr) - Xexpr "File1:10:Line1" - Xexpr "File2:20:Line2" - Xexpr "File3:30:Line3" - let last_qf = g:Xgetlist({'nr':'$'}).nr - call assert_equal(3, last_qf) - let qstack = [] - for i in range(1, last_qf) - let qstack = add(qstack, g:Xgetlist({'nr':i, 'all':1})) - endfor - call g:Xsetlist([], 'f') - for i in range(len(qstack)) - call g:Xsetlist([], ' ', qstack[i]) - endfor - call assert_equal(3, g:Xgetlist({'nr':'$'}).nr) - call assert_equal(10, g:Xgetlist({'nr':1, 'items':1}).items[0].lnum) - call assert_equal(20, g:Xgetlist({'nr':2, 'items':1}).items[0].lnum) - call assert_equal(30, g:Xgetlist({'nr':3, 'items':1}).items[0].lnum) - call g:Xsetlist([], 'f') + call assert_equal({}, g:Xgetlist({'abc':1})) + call assert_equal('', g:Xgetlist({'nr':99, 'title':1}).title) + call assert_equal('', g:Xgetlist({'nr':[], 'title':1}).title) - " Swap two quickfix lists - Xexpr "File1:10:Line10" - Xexpr "File2:20:Line20" - Xexpr "File3:30:Line30" - call g:Xsetlist([], 'r', {'nr':1,'title':'Colors','context':['Colors']}) - call g:Xsetlist([], 'r', {'nr':2,'title':'Fruits','context':['Fruits']}) - let l1=g:Xgetlist({'nr':1,'all':1}) - let l2=g:Xgetlist({'nr':2,'all':1}) - let save_id = l1.id - let l1.id=l2.id - let l2.id=save_id - call g:Xsetlist([], 'r', l1) - call g:Xsetlist([], 'r', l2) - let newl1=g:Xgetlist({'nr':1,'all':1}) - let newl2=g:Xgetlist({'nr':2,'all':1}) - call assert_equal('Fruits', newl1.title) - call assert_equal(['Fruits'], newl1.context) - call assert_equal('Line20', newl1.items[0].text) - call assert_equal('Colors', newl2.title) - call assert_equal(['Colors'], newl2.context) - call assert_equal('Line10', newl2.items[0].text) - call g:Xsetlist([], 'f') + if a:cchar == 'l' + call assert_equal({}, getloclist(99, {'title': 1})) + endif - " Cannot specify both a non-empty list argument and a dict argument - call assert_fails("call g:Xsetlist([{}], ' ', {})", 'E475:') + " Context related tests + let s = g:Xsetlist([], 'a', {'context':[1,2,3]}) + call assert_equal(0, s) + call test_garbagecollect_now() + let d = g:Xgetlist({'context':1}) + call assert_equal([1,2,3], d.context) + call g:Xsetlist([], 'a', {'context':{'color':'green'}}) + let d = g:Xgetlist({'context':1}) + call assert_equal({'color':'green'}, d.context) + call g:Xsetlist([], 'a', {'context':"Context info"}) + let d = g:Xgetlist({'context':1}) + call assert_equal("Context info", d.context) + call g:Xsetlist([], 'a', {'context':246}) + let d = g:Xgetlist({'context':1}) + call assert_equal(246, d.context) + " set other Vim data types as context + call g:Xsetlist([], 'a', {'context' : v:_null_blob}) + if has('channel') + call g:Xsetlist([], 'a', {'context' : test_null_channel()}) + endif + if has('job') + call g:Xsetlist([], 'a', {'context' : test_null_job()}) + endif + " Nvim doesn't have null functions + " call g:Xsetlist([], 'a', {'context' : test_null_function()}) + " Nvim doesn't have null partials + " call g:Xsetlist([], 'a', {'context' : test_null_partial()}) + call g:Xsetlist([], 'a', {'context' : ''}) + call test_garbagecollect_now() + if a:cchar == 'l' + " Test for copying context across two different location lists + new | only + let w1_id = win_getid() + let l = [1] + call setloclist(0, [], 'a', {'context':l}) + new + let w2_id = win_getid() + call add(l, 2) + call assert_equal([1, 2], getloclist(w1_id, {'context':1}).context) + call assert_equal([1, 2], getloclist(w2_id, {'context':1}).context) + unlet! l + call assert_equal([1, 2], getloclist(w2_id, {'context':1}).context) + only + call setloclist(0, [], 'f') + call assert_equal('', getloclist(0, {'context':1}).context) + endif + + " Test for changing the context of previous quickfix lists + call g:Xsetlist([], 'f') + Xexpr "One" + Xexpr "Two" + Xexpr "Three" + call g:Xsetlist([], 'r', {'context' : [1], 'nr' : 1}) + call g:Xsetlist([], 'a', {'context' : [2], 'nr' : 2}) + " Also, check for setting the context using quickfix list number zero. + call g:Xsetlist([], 'r', {'context' : [3], 'nr' : 0}) + call test_garbagecollect_now() + let l = g:Xgetlist({'nr' : 1, 'context' : 1}) + call assert_equal([1], l.context) + let l = g:Xgetlist({'nr' : 2, 'context' : 1}) + call assert_equal([2], l.context) + let l = g:Xgetlist({'nr' : 3, 'context' : 1}) + call assert_equal([3], l.context) + + " Test for changing the context through reference and for garbage + " collection of quickfix context + let l = ["red"] + call g:Xsetlist([], ' ', {'context' : l}) + call add(l, "blue") + let x = g:Xgetlist({'context' : 1}) + call add(x.context, "green") + call assert_equal(["red", "blue", "green"], l) + call assert_equal(["red", "blue", "green"], x.context) + unlet l + call test_garbagecollect_now() + let m = g:Xgetlist({'context' : 1}) + call assert_equal(["red", "blue", "green"], m.context) + + " Test for setting/getting items + Xexpr "" + let qfprev = g:Xgetlist({'nr':0}) + let s = g:Xsetlist([], ' ', {'title':'Green', + \ 'items' : [{'filename':'F1', 'lnum':10}]}) + call assert_equal(0, s) + let qfcur = g:Xgetlist({'nr':0}) + call assert_true(qfcur.nr == qfprev.nr + 1) + let l = g:Xgetlist({'items':1}) + call assert_equal('F1', bufname(l.items[0].bufnr)) + call assert_equal(10, l.items[0].lnum) + call g:Xsetlist([], 'a', {'items' : [{'filename':'F2', 'lnum':20}, + \ {'filename':'F2', 'lnum':30}]}) + let l = g:Xgetlist({'items':1}) + call assert_equal('F2', bufname(l.items[2].bufnr)) + call assert_equal(30, l.items[2].lnum) + call g:Xsetlist([], 'r', {'items' : [{'filename':'F3', 'lnum':40}]}) + let l = g:Xgetlist({'items':1}) + call assert_equal('F3', bufname(l.items[0].bufnr)) + call assert_equal(40, l.items[0].lnum) + call g:Xsetlist([], 'r', {'items' : []}) + let l = g:Xgetlist({'items':1}) + call assert_equal(0, len(l.items)) + + call g:Xsetlist([], 'r', {'title' : 'TestTitle'}) + call g:Xsetlist([], 'r', {'items' : [{'filename' : 'F1', 'lnum' : 10, 'text' : 'L10'}]}) + call g:Xsetlist([], 'r', {'items' : [{'filename' : 'F1', 'lnum' : 10, 'text' : 'L10'}]}) + call assert_equal('TestTitle', g:Xgetlist({'title' : 1}).title) + + " Test for getting id of window associated with a location list window + if a:cchar == 'l' + only + call assert_equal(0, g:Xgetlist({'all' : 1}).filewinid) + let wid = win_getid() + Xopen + call assert_equal(wid, g:Xgetlist({'filewinid' : 1}).filewinid) + wincmd w + call assert_equal(0, g:Xgetlist({'filewinid' : 1}).filewinid) + only + endif + + " The following used to crash Vim with address sanitizer + call g:Xsetlist([], 'f') + call g:Xsetlist([], 'a', {'items' : [{'filename':'F1', 'lnum':10}]}) + call assert_equal(10, g:Xgetlist({'items':1}).items[0].lnum) + + " Try setting the items using a string + call assert_equal(-1, g:Xsetlist([], ' ', {'items' : 'Test'})) + + " Save and restore the quickfix stack + call g:Xsetlist([], 'f') + call assert_equal(0, g:Xgetlist({'nr':'$'}).nr) + Xexpr "File1:10:Line1" + Xexpr "File2:20:Line2" + Xexpr "File3:30:Line3" + let last_qf = g:Xgetlist({'nr':'$'}).nr + call assert_equal(3, last_qf) + let qstack = [] + for i in range(1, last_qf) + let qstack = add(qstack, g:Xgetlist({'nr':i, 'all':1})) + endfor + call g:Xsetlist([], 'f') + for i in range(len(qstack)) + call g:Xsetlist([], ' ', qstack[i]) + endfor + call assert_equal(3, g:Xgetlist({'nr':'$'}).nr) + call assert_equal(10, g:Xgetlist({'nr':1, 'items':1}).items[0].lnum) + call assert_equal(20, g:Xgetlist({'nr':2, 'items':1}).items[0].lnum) + call assert_equal(30, g:Xgetlist({'nr':3, 'items':1}).items[0].lnum) + call g:Xsetlist([], 'f') + + " Swap two quickfix lists + Xexpr "File1:10:Line10" + Xexpr "File2:20:Line20" + Xexpr "File3:30:Line30" + call g:Xsetlist([], 'r', {'nr':1,'title':'Colors','context':['Colors']}) + call g:Xsetlist([], 'r', {'nr':2,'title':'Fruits','context':['Fruits']}) + let l1=g:Xgetlist({'nr':1,'all':1}) + let l2=g:Xgetlist({'nr':2,'all':1}) + let save_id = l1.id + let l1.id=l2.id + let l2.id=save_id + call g:Xsetlist([], 'r', l1) + call g:Xsetlist([], 'r', l2) + let newl1=g:Xgetlist({'nr':1,'all':1}) + let newl2=g:Xgetlist({'nr':2,'all':1}) + call assert_equal('Fruits', newl1.title) + call assert_equal(['Fruits'], newl1.context) + call assert_equal('Line20', newl1.items[0].text) + call assert_equal('Colors', newl2.title) + call assert_equal(['Colors'], newl2.context) + call assert_equal('Line10', newl2.items[0].text) + call g:Xsetlist([], 'f') + + " Cannot specify both a non-empty list argument and a dict argument + call assert_fails("call g:Xsetlist([{}], ' ', {})", 'E475:') endfunc func Test_qf_property() - call Xproperty_tests('c') - call Xproperty_tests('l') + call Xproperty_tests('c') + call Xproperty_tests('l') endfunc " Test for setting the current index in the location/quickfix list @@ -3132,7 +3128,7 @@ func Test_vimgrep_existing_swapfile() call assert_match('.Xapple.swo', swapname('')) call delete('Xapple') - call delete('Xapple.swp') + call delete('.Xapple.swp') augroup grep au! SwapExists augroup END @@ -3212,8 +3208,11 @@ func Test_bufoverflow() cgetexpr ['Compiler: ' . repeat('a', 1015), 'File1:10:Hello World'] set efm=%DEntering\ directory\ %f,%f:%l:%m - cgetexpr ['Entering directory ' . repeat('a', 1006), - \ 'File1:10:Hello World'] + let lines =<< trim eval END + Entering directory $"{repeat('a', 1006)}" + File1:10:Hello World + END + cgetexpr lines set efm&vim endfunc @@ -3585,15 +3584,15 @@ endfunc " Open multiple help windows using ":lhelpgrep " This test used to crash Vim func Test_Multi_LL_Help() - new | only - lhelpgrep window - lopen - e# - lhelpgrep buffer - call assert_equal(3, winnr('$')) - call assert_true(len(getloclist(1)) != 0) - call assert_true(len(getloclist(2)) != 0) - new | only + new | only + lhelpgrep window + lopen + e# + lhelpgrep buffer + call assert_equal(3, winnr('$')) + call assert_true(len(getloclist(1)) != 0) + call assert_true(len(getloclist(2)) != 0) + new | only endfunc " Tests for adding new quickfix lists using setqflist() @@ -4072,11 +4071,23 @@ func Test_ll_window_ctx() enew | only endfunc +" Similar to the problem above, but for user data. +func Test_ll_window_user_data() + call setloclist(0, [#{bufnr: bufnr(), user_data: {}}]) + lopen + wincmd t + close + call test_garbagecollect_now() + call feedkeys("\<CR>", 'tx') + call test_garbagecollect_now() + %bwipe! +endfunc + " The following test used to crash vim func Test_lfile_crash() sp Xtest au QuickFixCmdPre * bw - call assert_fails('lfile', 'E40') + call assert_fails('lfile', 'E40:') au! QuickFixCmdPre endfunc @@ -4129,6 +4140,7 @@ endfunc " The following test used to crash Vim func Test_lvimgrep_crash() + " this leaves a swapfile .test_quickfix.vim.swp around, why? sv Xtest augroup QF_Test au! @@ -4191,8 +4203,8 @@ endfunc " :vimgrep/:lvimgrep commands are running. func Test_vimgrep_autocmd() call setqflist([], 'f') - call writefile(['stars'], 'Xtest1.txt') - call writefile(['stars'], 'Xtest2.txt') + call writefile(['stars'], 'Xtest1.txt', 'D') + call writefile(['stars'], 'Xtest2.txt', 'D') " Test 1: " When searching for a pattern using :vimgrep, if the quickfix list is @@ -4222,9 +4234,9 @@ func Test_vimgrep_autocmd() autocmd BufRead Xtest2.txt call setloclist(g:save_winid, [], 'f') call assert_fails('lvimgrep stars Xtest*.txt', 'E926:') au! BufRead Xtest2.txt + " cleanup the swap files + bw! Xtest2.txt Xtest1.txt - call delete('Xtest1.txt') - call delete('Xtest2.txt') call setqflist([], 'f') endfunc @@ -4353,11 +4365,9 @@ endfunc " Test for shortening/simplifying the file name when opening the " quickfix window or when displaying the quickfix list func Test_shorten_fname() - if !has('unix') - return - endif + CheckUnix %bwipe - " Create a quickfix list with a absolute path filename + " Create a quickfix list with an absolute path filename let fname = getcwd() . '/test_quickfix.vim' call setqflist([], ' ', {'lines':[fname . ":20:Line20"], 'efm':'%f:%l:%m'}) call assert_equal(fname, bufname('test_quickfix.vim')) @@ -4366,7 +4376,7 @@ func Test_shorten_fname() call assert_equal('test_quickfix.vim', bufname('test_quickfix.vim')) cclose %bwipe - " Create a quickfix list with a absolute path filename + " Create a quickfix list with an absolute path filename call setqflist([], ' ', {'lines':[fname . ":20:Line20"], 'efm':'%f:%l:%m'}) call assert_equal(fname, bufname('test_quickfix.vim')) " Displaying the quickfix list should simplify the file path @@ -5926,6 +5936,16 @@ func Test_qfbuf_update() call Xqfbuf_update('l') endfunc +func Test_vimgrep_noswapfile() + set noswapfile + call writefile(['one', 'two', 'three'], 'Xgreppie') + vimgrep two Xgreppie + call assert_equal('two', getline('.')) + + call delete('Xgreppie') + set swapfile +endfunc + " Test for the :vimgrep 'f' flag (fuzzy match) func Xvimgrep_fuzzy_match(cchar) call s:setup_commands(a:cchar) @@ -6439,4 +6459,41 @@ func Test_cbuffer_range() call XbufferTests_range('l') endfunc +" Test for displaying fname pass from setqflist when the name +" are hard links to prevent seemly duplicate entries. +func Xtest_hardlink_fname(cchar) + call s:setup_commands(a:cchar) + %bwipe + " Create a sample source file + let lines =<< trim END + void sample() {} + int main() { sample(); return 0; } + END + call writefile(lines, 'test_qf_hardlink1.c', 'D') + defer delete('test_qf_hardlink1.c') + defer delete('test_qf_hardlink2.c') + call system('ln test_qf_hardlink1.c test_qf_hardlink2.c') + if v:shell_error + throw 'Skipped: ln throws error on this platform' + endif + call g:Xsetlist([], 'f') + " Make a qflist that contains the file and it's hard link + " like how LSP plugins set response into qflist + call g:Xsetlist([{'filename' : 'test_qf_hardlink1.c', 'lnum' : 1}, + \ {'filename' : 'test_qf_hardlink2.c', 'lnum' : 1}], ' ') + Xopen + " Ensure that two entries are displayed with different name + " so that they aren't seen as duplication. + call assert_equal(['test_qf_hardlink1.c|1| ', + \ 'test_qf_hardlink2.c|1| '], getline(1, '$')) + Xclose +endfunc + +func Test_hardlink_fname() + CheckUnix + CheckExecutable ln + call Xtest_hardlink_fname('c') + call Xtest_hardlink_fname('l') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_regexp_latin.vim b/test/old/testdir/test_regexp_latin.vim index 2cfa81e078..99a82e8386 100644 --- a/test/old/testdir/test_regexp_latin.vim +++ b/test/old/testdir/test_regexp_latin.vim @@ -28,61 +28,50 @@ func s:equivalence_test() endfunc func Test_equivalence_re1() - throw 'skipped: Nvim does not support enc=latin1' set re=1 call s:equivalence_test() + set re=0 endfunc func Test_equivalence_re2() - throw 'skipped: Nvim does not support enc=latin1' set re=2 call s:equivalence_test() + set re=0 endfunc -func Test_range_with_newline() +func Test_recursive_substitute() new - call setline(1, "a") - call assert_equal(0, search("[ -*\\n- ]")) - call assert_equal(0, search("[ -*\\t-\\n]")) + s/^/\=execute("s#^##gn") + " check we are now not in the sandbox + call setwinvar(1, 'myvar', 1) bwipe! endfunc -func Test_pattern_compile_speed() - CheckOption spellcapcheck - CheckFunction reltimefloat - - let start = reltime() - " this used to be very slow, not it should be about a second - set spc=\\v(((((Nxxxxxxx&&xxxx){179})+)+)+){179} - call assert_inrange(0.01, 10.0, reltimefloat(reltime(start))) - set spc= -endfunc - -func Test_get_equi_class() +func Test_nested_backrefs() + " Check example in change.txt. new - " Incomplete equivalence class caused invalid memory access - s/^/[[= - call assert_equal(1, search(getline(1))) - s/.*/[[. - call assert_equal(1, search(getline(1))) -endfunc + for re in range(0, 2) + exe 'set re=' . re + call setline(1, 'aa ab x') + 1s/\(\(a[a-d] \)*\)\(x\)/-\1- -\2- -\3-/ + call assert_equal('-aa ab - -ab - -x-', getline(1)) -func Test_rex_init() - set noincsearch - set re=1 - new - setlocal iskeyword=a-z - call setline(1, ['abc', 'ABC']) - call assert_equal(1, search('[[:keyword:]]')) - new - setlocal iskeyword=A-Z - call setline(1, ['abc', 'ABC']) - call assert_equal(2, search('[[:keyword:]]')) - bwipe! + call assert_equal('-aa ab - -ab - -x-', substitute('aa ab x', '\(\(a[a-d] \)*\)\(x\)', '-\1- -\2- -\3-', '')) + endfor bwipe! set re=0 endfunc +func Test_eow_with_optional() + let expected = ['abc def', 'abc', 'def', '', '', '', '', '', '', ''] + for re in range(0, 2) + exe 'set re=' . re + let actual = matchlist('abc def', '\(abc\>\)\?\s*\(def\)') + call assert_equal(expected, actual) + endfor + set re=0 +endfunc + func Test_backref() new call setline(1, ['one', 'two', 'three', 'four', 'five']) @@ -144,6 +133,50 @@ func Test_out_of_memory() call assert_fails('call search("\\v((n||<)+);")', 'E363:') endfunc +func Test_get_equi_class() + new + " Incomplete equivalence class caused invalid memory access + s/^/[[= + call assert_equal(1, search(getline(1))) + s/.*/[[. + call assert_equal(1, search(getline(1))) +endfunc + +func Test_rex_init() + set noincsearch + set re=1 + new + setlocal iskeyword=a-z + call setline(1, ['abc', 'ABC']) + call assert_equal(1, search('[[:keyword:]]')) + new + setlocal iskeyword=A-Z + call setline(1, ['abc', 'ABC']) + call assert_equal(2, search('[[:keyword:]]')) + bwipe! + bwipe! + set re=0 +endfunc + +func Test_range_with_newline() + new + call setline(1, "a") + call assert_equal(0, search("[ -*\\n- ]")) + call assert_equal(0, search("[ -*\\t-\\n]")) + bwipe! +endfunc + +func Test_pattern_compile_speed() + CheckOption spellcapcheck + CheckFunction reltimefloat + + let start = reltime() + " this used to be very slow, not it should be about a second + set spc=\\v(((((Nxxxxxxx&&xxxx){179})+)+)+){179} + call assert_inrange(0.01, 10.0, reltimefloat(reltime(start))) + set spc= +endfunc + " Tests for regexp patterns without multi-byte support. func Test_regexp_single_line_pat() " tl is a List of Lists with: @@ -937,8 +970,17 @@ func Test_regexp_error() call assert_fails("call matchlist('x x', '\\%#=1 \\ze*')", 'E888:') call assert_fails("call matchlist('x x', '\\%#=2 \\zs*')", 'E888:') call assert_fails("call matchlist('x x', '\\%#=2 \\ze*')", 'E888:') - call assert_fails('exe "normal /\\%#=1\\%[x\\%[x]]\<CR>"', 'E369:') call assert_fails("call matchstr('abcd', '\\%o841\\%o142')", 'E678:') + call assert_fails("call matchstr('abcd', '\\%#=2\\%2147483647c')", 'E951:') + call assert_fails("call matchstr('abcd', '\\%#=2\\%2147483647l')", 'E951:') + call assert_fails("call matchstr('abcd', '\\%#=2\\%2147483647v')", 'E951:') + call assert_fails('exe "normal /\\%#=1\\%[x\\%[x]]\<CR>"', 'E369:') + call assert_fails('exe "normal /\\%#=2\\%2147483647l\<CR>"', 'E951:') + call assert_fails('exe "normal /\\%#=2\\%2147483647c\<CR>"', 'E951:') + call assert_fails('exe "normal /\\%#=2\\%102261126v\<CR>"', 'E951:') + call assert_fails('exe "normal /\\%#=2\\%2147483646l\<CR>"', 'E486:') + call assert_fails('exe "normal /\\%#=2\\%2147483646c\<CR>"', 'E486:') + call assert_fails('exe "normal /\\%#=2\\%102261125v\<CR>"', 'E486:') call assert_equal('', matchstr('abcd', '\%o181\%o142')) endfunc @@ -1105,4 +1147,32 @@ func Test_recursive_substitute_expr() delfunc Repl endfunc +" def Test_compare_columns() +" # this was using a line below the last line +" enew +" setline(1, ['', '']) +" prop_type_add('name', {highlight: 'ErrorMsg'}) +" prop_add(1, 1, {length: 1, type: 'name'}) +" search('\%#=1\%>.l\n.*\%<2v', 'nW') +" search('\%#=2\%>.l\n.*\%<2v', 'nW') +" bwipe! +" prop_type_delete('name') +" enddef + +func Test_compare_column_matchstr() + " do some search in text to set the line number, it should be ignored in + " matchstr(). + enew + call setline(1, ['one', 'two', 'three']) + :3 + :/ee + bwipe! + set re=1 + call assert_equal('aaa', matchstr('aaaaaaaaaaaaaaaaaaaa', '.*\%<5v')) + set re=2 + call assert_equal('aaa', matchstr('aaaaaaaaaaaaaaaaaaaa', '.*\%<5v')) + set re=0 +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_regexp_utf8.vim b/test/old/testdir/test_regexp_utf8.vim index 728a88fa0f..505e99919c 100644 --- a/test/old/testdir/test_regexp_utf8.vim +++ b/test/old/testdir/test_regexp_utf8.vim @@ -1,5 +1,7 @@ " Tests for regexp in utf8 encoding +source shared.vim + func s:equivalence_test() let str = "AÀÃÂÃÄÅĀĂĄÇÇžÇ ÇºÈ‚È¦Èºá¸€áº áº¢áº¤áº¦áº¨áºªáº¬áº®áº°áº²áº´áº¶ BÆÉƒá¸‚ḄḆ CÇĆĈĊČƇȻḈꞒ DÄŽÄÆŠá¸Šá¸Œá¸Žá¸á¸’ EÈÉÊËĒĔĖĘĚȄȆȨɆḔḖḘḚḜẸẺẼẾỀỂỄỆ FƑḞꞘ GÄœÄžÄ Ä¢Æ“Ç¤Ç¦Ç´á¸ êž HĤĦȞḢḤḦḨḪⱧ IÃŒÃÃŽÃĨĪĬĮİƗÇȈȊḬḮỈỊ JĴɈ KÄ¶Æ˜Ç¨á¸°á¸²á¸´â±©ê€ LĹĻĽĿÅȽḶḸḺḼⱠMḾṀṂ NÑŃŅŇǸṄṆṈṊꞤ OÃ’Ã“Ã”Ã•Ã–Ã˜ÅŒÅŽÅÆŸÆ ǑǪǬǾȌȎȪȬȮȰṌṎá¹á¹’ỌỎá»á»’ỔỖỘỚỜỞỠỢ PƤṔṖⱣ QÉŠ RŔŖŘÈȒɌṘṚṜṞⱤꞦ SŚŜŞŠȘṠṢṤṦṨⱾꞨ TŢŤŦƬƮȚȾṪṬṮṰ UÙÚÛÜŨŪŬŮŰƯǕǙǛǓǗȔȖɄṲṴṶṸṺỤỦỨỪỬỮỰ VƲṼṾ WŴẀẂẄẆẈ XẊẌ YÃŶŸƳȲɎẎỲỴỶỸ ZŹŻŽƵáºáº’ẔⱫ aà áâãäåÄăąǎǟǡǻȃȧá¶á¸áºšáº¡áº£áº¥áº§áº©áº«áºáº¯áº±áº³áºµáº·â±¥ bƀɓᵬᶀḃḅḇ cÃ§Ä‡Ä‰Ä‹ÄÆˆÈ¼á¸‰êž“êž” dÄđɗáµá¶á¶‘ḋá¸á¸á¸‘ḓ eèéêëēĕėęěȅȇȩɇᶒḕḗḙḛá¸áº¹áº»áº½áº¿á»á»ƒá»…ệ fƒᵮᶂḟꞙ gÄÄŸÄ¡Ä£Ç¥Ç§ÇµÉ á¶ƒá¸¡êž¡ hĥħȟḣḥḧḩḫẖⱨꞕ iìÃîïĩīÄįÇȉȋɨᶖá¸á¸¯á»‰á»‹ jĵǰɉ kķƙǩᶄḱḳḵⱪê lĺļľŀłƚḷḹḻḽⱡ mᵯḿá¹á¹ƒ nñńņňʼnǹᵰᶇṅṇṉṋꞥ oòóôõöøÅÅőơǒǫÇÇ¿ÈÈÈ«Èȯȱɵá¹á¹á¹‘ṓá»á»á»‘ồổỗộớá»á»Ÿá»¡á»£ pƥᵱᵽᶈṕṗ qÉ‹Ê rŕŗřȑȓÉɽᵲᵳᶉṛá¹á¹Ÿêž§ sÅ›Åşšșȿᵴᶊṡṣṥṧṩꞩ tţťŧƫÆÈ›Êˆáµµá¹«á¹á¹¯á¹±áº—ⱦ uùúûüũūÅůűųǚǖưǔǘǜȕȗʉᵾᶙṳṵṷṹṻụủứừá»á»¯á»± vʋᶌṽṿ wŵáºáºƒáº…ẇẉẘ xẋẠyýÿŷƴȳÉáºáº™á»³á»µá»·á»¹ zźżžƶᵶᶎẑẓẕⱬ" let groups = split(str) @@ -188,38 +190,6 @@ func Test_classes_re2() set re=0 endfunc -func Test_recursive_substitute() - new - s/^/\=execute("s#^##gn") - " check we are now not in the sandbox - call setwinvar(1, 'myvar', 1) - bwipe! -endfunc - -func Test_nested_backrefs() - " Check example in change.txt. - new - for re in range(0, 2) - exe 'set re=' . re - call setline(1, 'aa ab x') - 1s/\(\(a[a-d] \)*\)\(x\)/-\1- -\2- -\3-/ - call assert_equal('-aa ab - -ab - -x-', getline(1)) - - call assert_equal('-aa ab - -ab - -x-', substitute('aa ab x', '\(\(a[a-d] \)*\)\(x\)', '-\1- -\2- -\3-', '')) - endfor - bwipe! - set re=0 -endfunc - -func Test_eow_with_optional() - let expected = ['abc def', 'abc', 'def', '', '', '', '', '', '', ''] - for re in range(0, 2) - exe 'set re=' . re - let actual = matchlist('abc def', '\(abc\>\)\?\s*\(def\)') - call assert_equal(expected, actual) - endfor -endfunc - func Test_reversed_range() for re in range(0, 2) exe 'set re=' . re @@ -591,6 +561,19 @@ func Test_match_invalid_byte() call delete('Xinvalid') endfunc +func Test_match_illegal_byte() + let lines =<< trim END + silent! buffer ÿ\c + next ÿ + 0scriptnames + source + END + call writefile(lines, 'Xregexp') + call system(GetVimCommand() .. ' -X -Z -e -s -S Xregexp -c qa!') + + call delete('Xregexp') +endfunc + func Test_match_too_complicated() set regexpengine=1 exe "noswapfile vsplit \xeb\xdb\x99" @@ -611,4 +594,36 @@ func Test_combining_chars_in_collection() bw! endfunc +func Test_search_multibyte_match_ascii() + new + " Match single 'Å¿' and 's' + call setline(1, 'das abc heraus abc Å¿ich abc Å¿ind') + for i in range(0, 2) + exe "set re="..i + let ic_match = matchbufline('%', '\c\%u17f', 1, '$')->mapnew({idx, val -> val.text}) + let noic_match = matchbufline('%', '\C\%u17f', 1, '$')->mapnew({idx, val -> val.text}) + call assert_equal(['s', 's', 'Å¿','Å¿'], ic_match, "Ignorecase Regex-engine: " .. &re) + call assert_equal(['Å¿','Å¿'], noic_match, "No-Ignorecase Regex-engine: " .. &re) + endfor + " Match several 'ſſ' and 'ss' + call setline(1, 'das abc herauss abc ſſich abc Å¿ind') + for i in range(0, 2) + exe "set re="..i + let ic_match = matchbufline('%', '\c\%u17f\%u17f', 1, '$')->mapnew({idx, val -> val.text}) + let noic_match = matchbufline('%', '\C\%u17f\%u17f', 1, '$')->mapnew({idx, val -> val.text}) + let ic_match2 = matchbufline('%', '\c\%u17f\+', 1, '$')->mapnew({idx, val -> val.text}) + let noic_match2 = matchbufline('%', '\C\%u17f\+', 1, '$')->mapnew({idx, val -> val.text}) + let ic_match3 = matchbufline('%', '\c[\u17f]\+', 1, '$')->mapnew({idx, val -> val.text}) + let noic_match3 = matchbufline('%', '\C[\u17f]\+', 1, '$')->mapnew({idx, val -> val.text}) + + call assert_equal(['ss', 'ſſ'], ic_match, "Ignorecase Regex-engine: " .. &re) + call assert_equal(['ſſ'], noic_match, "No-Ignorecase Regex-engine: " .. &re) + call assert_equal(['s', 'ss', 'ſſ', 'Å¿'], ic_match2, "Ignorecase Regex-engine: " .. &re) + call assert_equal(['ſſ','Å¿'], noic_match2, "No-Ignorecase Regex-engine: " .. &re) + call assert_equal(['s', 'ss', 'ſſ', 'Å¿'], ic_match3, "Ignorecase Collection Regex-engine: " .. &re) + call assert_equal(['ſſ','Å¿'], noic_match3, "No-Ignorecase Collection Regex-engine: " .. &re) + endfor + bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_ruby.vim b/test/old/testdir/test_ruby.vim index 4929496086..d4a3dc3301 100644 --- a/test/old/testdir/test_ruby.vim +++ b/test/old/testdir/test_ruby.vim @@ -282,7 +282,7 @@ func Test_ruby_Vim_buffer_get() call assert_match('Xfoo1$', rubyeval('Vim::Buffer[1].name')) call assert_match('Xfoo2$', rubyeval('Vim::Buffer[2].name')) call assert_fails('ruby print Vim::Buffer[3].name', - \ "NoMethodError: undefined method `name' for nil:NilClass") + \ "NoMethodError: undefined method `name' for nil") %bwipe endfunc @@ -337,6 +337,14 @@ func Test_ruby_Vim_evaluate() call assert_equal('FalseClass',rubyeval('Vim::evaluate("v:false").class')) endfunc +func Test_ruby_Vim_blob() + throw 'skipped: TODO: ' + call assert_equal('0z', rubyeval('Vim::blob("")')) + call assert_equal('0z31326162', rubyeval('Vim::blob("12ab")')) + call assert_equal('0z00010203', rubyeval('Vim::blob("\x00\x01\x02\x03")')) + call assert_equal('0z8081FEFF', rubyeval('Vim::blob("\x80\x81\xfe\xff")')) +endfunc + func Test_ruby_Vim_evaluate_list() call setline(line('$'), ['2 line 2']) ruby Vim.command("normal /^2\n") diff --git a/test/old/testdir/test_scriptnames.vim b/test/old/testdir/test_scriptnames.vim index 69e5e526fd..13b09a601a 100644 --- a/test/old/testdir/test_scriptnames.vim +++ b/test/old/testdir/test_scriptnames.vim @@ -1,7 +1,7 @@ " Test for the :scriptnames command func Test_scriptnames() - call writefile(['let did_load_script = 123'], 'Xscripting') + call writefile(['let did_load_script = 123'], 'Xscripting', 'D') source Xscripting call assert_equal(123, g:did_load_script) @@ -22,7 +22,6 @@ func Test_scriptnames() call assert_equal('Xscripting', expand('%:t')) bwipe - call delete('Xscripting') let msgs = execute('messages') scriptnames @@ -47,7 +46,7 @@ func Test_getscriptinfo() " def Xscript_def_func2() " enddef END - call writefile(lines, 'X22script91') + call writefile(lines, 'X22script91', 'D') source X22script91 let l = getscriptinfo() call assert_match('X22script91$', l[-1].name) @@ -103,8 +102,6 @@ func Test_getscriptinfo() let max_sid = max(map(getscriptinfo(), { k, v -> v.sid })) call assert_equal([], getscriptinfo({'sid': max_sid + 1})) - - call delete('X22script91') endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_scroll_opt.vim b/test/old/testdir/test_scroll_opt.vim index 76b4089bd1..55f9a32718 100644 --- a/test/old/testdir/test_scroll_opt.vim +++ b/test/old/testdir/test_scroll_opt.vim @@ -302,6 +302,36 @@ func Test_smoothscroll_diff_mode() call StopVimInTerminal(buf) endfunc +func Test_smoothscroll_diff_change_line() + CheckScreendump + + let lines =<< trim END + set diffopt+=followwrap smoothscroll + call setline(1, repeat(' abc', &columns)) + call setline(2, 'bar') + call setline(3, repeat(' abc', &columns)) + vnew + call setline(1, repeat(' abc', &columns)) + call setline(2, 'foo') + call setline(3, 'bar') + call setline(4, repeat(' abc', &columns)) + windo exe "normal! 2gg5\<C-E>" + windo diffthis + END + call writefile(lines, 'XSmoothDiffChangeLine', 'D') + let buf = RunVimInTerminal('-S XSmoothDiffChangeLine', #{rows: 20, columns: 55}) + + call VerifyScreenDump(buf, 'Test_smooth_diff_change_line_1', {}) + call term_sendkeys(buf, "Abar") + call VerifyScreenDump(buf, 'Test_smooth_diff_change_line_2', {}) + call term_sendkeys(buf, "\<Esc>") + call VerifyScreenDump(buf, 'Test_smooth_diff_change_line_3', {}) + call term_sendkeys(buf, "yyp") + call VerifyScreenDump(buf, 'Test_smooth_diff_change_line_4', {}) + + call StopVimInTerminal(buf) +endfunc + func Test_smoothscroll_wrap_scrolloff_zero() CheckScreendump @@ -369,18 +399,18 @@ func Test_smoothscroll_wrap_long_line() call term_sendkeys(buf, ":set scrolloff=1\<CR>") call term_sendkeys(buf, "10|\<C-E>") call VerifyScreenDump(buf, 'Test_smooth_long_6', {}) - + " 'scrolloff' set to 1, scrolling down, cursor moves screen line up call term_sendkeys(buf, "\<C-E>") call term_sendkeys(buf, "gjgj") call term_sendkeys(buf, "\<C-Y>") call VerifyScreenDump(buf, 'Test_smooth_long_7', {}) - + " 'scrolloff' set to 2, scrolling up, cursor moves screen line down call term_sendkeys(buf, ":set scrolloff=2\<CR>") call term_sendkeys(buf, "10|\<C-E>") call VerifyScreenDump(buf, 'Test_smooth_long_8', {}) - + " 'scrolloff' set to 2, scrolling down, cursor moves screen line up call term_sendkeys(buf, "\<C-E>") call term_sendkeys(buf, "gj") @@ -421,7 +451,7 @@ func Test_smoothscroll_wrap_long_line() call term_sendkeys(buf, "3Gzt") call term_sendkeys(buf, "\<C-E>j") call VerifyScreenDump(buf, 'Test_smooth_long_16', {}) - + call StopVimInTerminal(buf) endfunc @@ -436,7 +466,7 @@ func Test_smoothscroll_one_long_line() call writefile(lines, 'XSmoothOneLong', 'D') let buf = RunVimInTerminal('-S XSmoothOneLong', #{rows: 6, cols: 40}) call VerifyScreenDump(buf, 'Test_smooth_one_long_1', {}) - + call term_sendkeys(buf, "\<C-E>") call VerifyScreenDump(buf, 'Test_smooth_one_long_2', {}) @@ -458,7 +488,7 @@ func Test_smoothscroll_long_line_showbreak() call writefile(lines, 'XSmoothLongShowbreak', 'D') let buf = RunVimInTerminal('-S XSmoothLongShowbreak', #{rows: 6, cols: 40}) call VerifyScreenDump(buf, 'Test_smooth_long_showbreak_1', {}) - + call term_sendkeys(buf, "\<C-E>") call VerifyScreenDump(buf, 'Test_smooth_long_showbreak_2', {}) @@ -648,7 +678,7 @@ func Test_smoothscroll_cursor_scrolloff() call NewWindow(10, 20) setl smoothscroll wrap setl scrolloff=3 - + " 120 chars are 6 screen lines call setline(1, "abcdefghijklmnopqrstABCDEFGHIJKLMNOPQRSTabcdefghijklmnopqrstABCDEFGHIJKLMNOPQRSTabcdefghijklmnopqrstABCDEFGHIJKLMNOPQRST") call setline(2, "below") @@ -1165,7 +1195,6 @@ func Test_smooth_long_scrolloff() END call writefile(lines, 'XSmoothLongScrolloff', 'D') let buf = RunVimInTerminal('-u NONE -S XSmoothLongScrolloff', #{rows: 8, cols: 40}) - "FIXME: empty screen due to reset_skipcol()/curs_columns() shenanigans call term_sendkeys(buf, ":norm j721|\<CR>") call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_1', {}) @@ -1185,7 +1214,6 @@ func Test_smooth_long_scrolloff() call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_6', {}) call term_sendkeys(buf, "gk") - "FIXME: empty screen due to reset_skipcol()/curs_columns() shenanigans call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_7', {}) call StopVimInTerminal(buf) diff --git a/test/old/testdir/test_search.vim b/test/old/testdir/test_search.vim index 018ee7ad5a..b62c2b2e5f 100644 --- a/test/old/testdir/test_search.vim +++ b/test/old/testdir/test_search.vim @@ -674,7 +674,7 @@ func Test_search_cmdline8() endif " Prepare buffer text let lines = ['abb vim vim vi', 'vimvivim'] - call writefile(lines, 'Xsearch.txt') + call writefile(lines, 'Xsearch.txt', 'D') let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile', 'Xsearch.txt'], {'term_rows': 3}) call WaitForAssert({-> assert_equal(lines, [term_getline(buf, 1), term_getline(buf, 2)])}) @@ -693,9 +693,8 @@ func Test_search_cmdline8() call assert_notequal(a1, a2) call assert_equal(a0, a2) call assert_equal(a1, a3) - " clean up - call delete('Xsearch.txt') + " clean up bwipe! endfunc @@ -810,7 +809,7 @@ func Test_search_cmdline_incsearch_highlight_attr() " Prepare buffer text let lines = ['abb vim vim vi', 'vimvivim'] - call writefile(lines, 'Xsearch.txt') + call writefile(lines, 'Xsearch.txt', 'D') let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile', 'Xsearch.txt'], {'term_rows': 3}) call WaitForAssert({-> assert_equal(lines, [term_getline(buf, 1), term_getline(buf, 2)])}) @@ -879,9 +878,7 @@ func Test_search_cmdline_incsearch_highlight_attr() let attr_line2 = [a0,a0,a0,a0,a0,a0,a0,a0] call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr')) call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr')) - call delete('Xsearch.txt') - call delete('Xsearch.txt') bwipe! endfunc @@ -908,7 +905,7 @@ func Test_incsearch_scrolling() \ 'call setline(1, [dots, dots, dots, "", "target", dots, dots])', \ 'normal gg', \ 'redraw', - \ ], 'Xscript') + \ ], 'Xscript', 'D') let buf = RunVimInTerminal('-S Xscript', {'rows': 9, 'cols': 70}) " Need to send one key at a time to force a redraw call term_sendkeys(buf, '/') @@ -924,7 +921,6 @@ func Test_incsearch_scrolling() call term_sendkeys(buf, "\<Esc>") call StopVimInTerminal(buf) - call delete('Xscript') endfunc func Test_incsearch_search_dump() @@ -937,7 +933,7 @@ func Test_incsearch_search_dump() \ ' call setline(n, "foo " . n)', \ 'endfor', \ '3', - \ ], 'Xis_search_script') + \ ], 'Xis_search_script', 'D') let buf = RunVimInTerminal('-S Xis_search_script', {'rows': 9, 'cols': 70}) " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by " the 'ambiwidth' check. @@ -954,7 +950,6 @@ func Test_incsearch_search_dump() call term_sendkeys(buf, "\<Esc>") call StopVimInTerminal(buf) - call delete('Xis_search_script') endfunc func Test_hlsearch_dump() @@ -966,7 +961,7 @@ func Test_hlsearch_dump() \ 'call setline(1, ["xxx", "xxx", "xxx"])', \ '/.*', \ '2', - \ ], 'Xhlsearch_script') + \ ], 'Xhlsearch_script', 'D') let buf = RunVimInTerminal('-S Xhlsearch_script', {'rows': 6, 'cols': 50}) call VerifyScreenDump(buf, 'Test_hlsearch_1', {}) @@ -974,7 +969,6 @@ func Test_hlsearch_dump() call VerifyScreenDump(buf, 'Test_hlsearch_2', {}) call StopVimInTerminal(buf) - call delete('Xhlsearch_script') endfunc func Test_hlsearch_and_visual() @@ -987,14 +981,13 @@ func Test_hlsearch_and_visual() \ 'hi Search cterm=bold', \ '/yyy', \ 'call cursor(1, 6)', - \ ], 'Xhlvisual_script') + \ ], 'Xhlvisual_script', 'D') let buf = RunVimInTerminal('-S Xhlvisual_script', {'rows': 6, 'cols': 40}) call term_sendkeys(buf, "vjj") call VerifyScreenDump(buf, 'Test_hlsearch_visual_1', {}) call term_sendkeys(buf, "\<Esc>") call StopVimInTerminal(buf) - call delete('Xhlvisual_script') endfunc func Test_hlsearch_block_visual_match() @@ -1004,7 +997,7 @@ func Test_hlsearch_block_visual_match() set hlsearch call setline(1, ['aa', 'bbbb', 'cccccc']) END - call writefile(lines, 'Xhlsearch_block') + call writefile(lines, 'Xhlsearch_block', 'D') let buf = RunVimInTerminal('-S Xhlsearch_block', {'rows': 9, 'cols': 60}) call term_sendkeys(buf, "G\<C-V>$kk\<Esc>") @@ -1014,7 +1007,6 @@ func Test_hlsearch_block_visual_match() call VerifyScreenDump(buf, 'Test_hlsearch_block_visual_match', {}) call StopVimInTerminal(buf) - call delete('Xhlsearch_block') endfunc func Test_incsearch_substitute() @@ -1062,7 +1054,7 @@ func Test_hlsearch_cursearch() hi Search ctermbg=yellow hi CurSearch ctermbg=blue END - call writefile(lines, 'Xhlsearch_cursearch') + call writefile(lines, 'Xhlsearch_cursearch', 'D') let buf = RunVimInTerminal('-S Xhlsearch_cursearch', {'rows': 9, 'cols': 60}) call term_sendkeys(buf, "gg/foo\<CR>") @@ -1094,8 +1086,12 @@ func Test_hlsearch_cursearch() call term_sendkeys(buf, "h\<C-L>") call VerifyScreenDump(buf, 'Test_hlsearch_cursearch_multiple_line_5', {}) + " check clearing CurSearch when using it for another match + call term_sendkeys(buf, "G?^abcd\<CR>Y") + call term_sendkeys(buf, "kkP") + call VerifyScreenDump(buf, 'Test_hlsearch_cursearch_changed_1', {}) + call StopVimInTerminal(buf) - call delete('Xhlsearch_cursearch') endfunc " Similar to Test_incsearch_substitute() but with a screendump halfway. @@ -1110,7 +1106,7 @@ func Test_incsearch_substitute_dump() \ 'endfor', \ 'call setline(11, "bar 11")', \ '3', - \ ], 'Xis_subst_script') + \ ], 'Xis_subst_script', 'D') let buf = RunVimInTerminal('-S Xis_subst_script', {'rows': 9, 'cols': 70}) " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by " the 'ambiwidth' check. @@ -1205,7 +1201,6 @@ func Test_incsearch_substitute_dump() call term_sendkeys(buf, "<Esc>") call StopVimInTerminal(buf) - call delete('Xis_subst_script') endfunc func Test_incsearch_highlighting() @@ -1215,7 +1210,7 @@ func Test_incsearch_highlighting() call writefile([ \ 'set incsearch hlsearch', \ 'call setline(1, "hello/there")', - \ ], 'Xis_subst_hl_script') + \ ], 'Xis_subst_hl_script', 'D') let buf = RunVimInTerminal('-S Xis_subst_hl_script', {'rows': 4, 'cols': 20}) " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by " the 'ambiwidth' check. @@ -1228,7 +1223,6 @@ func Test_incsearch_highlighting() call term_sendkeys(buf, "<Esc>") call StopVimInTerminal(buf) - call delete('Xis_subst_hl_script') endfunc func Test_incsearch_with_change() @@ -1240,7 +1234,7 @@ func Test_incsearch_with_change() \ 'set incsearch hlsearch scrolloff=0', \ 'call setline(1, ["one", "two ------ X", "three"])', \ 'call timer_start(200, { _ -> setline(2, "x")})', - \ ], 'Xis_change_script') + \ ], 'Xis_change_script', 'D') let buf = RunVimInTerminal('-S Xis_change_script', {'rows': 9, 'cols': 70}) " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by " the 'ambiwidth' check. @@ -1252,7 +1246,6 @@ func Test_incsearch_with_change() call term_sendkeys(buf, "\<Esc>") call StopVimInTerminal(buf) - call delete('Xis_change_script') endfunc " Similar to Test_incsearch_substitute_dump() for :sort @@ -1263,7 +1256,7 @@ func Test_incsearch_sort_dump() call writefile([ \ 'set incsearch hlsearch scrolloff=0', \ 'call setline(1, ["another one 2", "that one 3", "the one 1"])', - \ ], 'Xis_sort_script') + \ ], 'Xis_sort_script', 'D') let buf = RunVimInTerminal('-S Xis_sort_script', {'rows': 9, 'cols': 70}) " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by " the 'ambiwidth' check. @@ -1278,7 +1271,6 @@ func Test_incsearch_sort_dump() call term_sendkeys(buf, "\<Esc>") call StopVimInTerminal(buf) - call delete('Xis_sort_script') endfunc " Similar to Test_incsearch_substitute_dump() for :vimgrep famiry @@ -1289,7 +1281,7 @@ func Test_incsearch_vimgrep_dump() call writefile([ \ 'set incsearch hlsearch scrolloff=0', \ 'call setline(1, ["another one 2", "that one 3", "the one 1"])', - \ ], 'Xis_vimgrep_script') + \ ], 'Xis_vimgrep_script', 'D') let buf = RunVimInTerminal('-S Xis_vimgrep_script', {'rows': 9, 'cols': 70}) " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by " the 'ambiwidth' check. @@ -1317,7 +1309,6 @@ func Test_incsearch_vimgrep_dump() call term_sendkeys(buf, "\<Esc>") call StopVimInTerminal(buf) - call delete('Xis_vimgrep_script') endfunc func Test_keep_last_search_pattern() @@ -1460,11 +1451,9 @@ endfunc func Test_no_last_substitute_pat() " Use viminfo to set the last search pattern to a string and make the last " substitute pattern the most recent used and make it empty (NULL). - call writefile(['~MSle0/bar', '~MSle0~&'], 'Xviminfo') + call writefile(['~MSle0/bar', '~MSle0~&'], 'Xviminfo', 'D') rviminfo! Xviminfo call assert_fails('normal n', 'E35:') - - call delete('Xviminfo') endfunc func Test_search_Ctrl_L_combining() @@ -1671,12 +1660,42 @@ func Test_search_with_no_last_pat() call writefile(v:errors, 'Xresult') qall! [SCRIPT] - call writefile(lines, 'Xscript') + call writefile(lines, 'Xscript', 'D') + + if RunVim([], [], '--clean -S Xscript') + call assert_equal([], readfile('Xresult')) + endif + call delete('Xresult') +endfunc + +" Test for using the last substitute pattern without last search pattern. +func Test_search_with_last_substitute_pat() + let lines =<< trim [SCRIPT] + new + set shortmess+=S + call setline(1, repeat(['foofoo'], 3)) + %s/foo/bar/ + call assert_equal(repeat(['barfoo'], 3), getline(1, '$')) + + call cursor(1, 1) + call assert_equal("/foo", execute('call feedkeys("/\r", "tx")', '')->trim()) + call assert_equal([0, 1, 4, 0], getpos('.')) + + if has('rightleft') + set rightleft rightleftcmd=search + call cursor(1, 1) + call assert_equal("oof/", execute('call feedkeys("/\r", "tx")', '')->trim()) + call assert_equal([0, 1, 4, 0], getpos('.')) + endif + + call writefile(v:errors, 'Xresult') + qall! + [SCRIPT] + call writefile(lines, 'Xscript', 'D') if RunVim([], [], '--clean -S Xscript') call assert_equal([], readfile('Xresult')) endif - call delete('Xscript') call delete('Xresult') endfunc @@ -1694,11 +1713,10 @@ func Test_search_tilde_pat() call writefile(v:errors, 'Xresult') qall! [SCRIPT] - call writefile(lines, 'Xscript') + call writefile(lines, 'Xscript', 'D') if RunVim([], [], '--clean -S Xscript') call assert_equal([], readfile('Xresult')) endif - call delete('Xscript') call delete('Xresult') endfunc @@ -1966,7 +1984,7 @@ func Test_incsearch_highlighting_newline() set incsearch nohls call setline(1, ['test', 'xxx']) [CODE] - call writefile(commands, 'Xincsearch_nl') + call writefile(commands, 'Xincsearch_nl', 'D') let buf = RunVimInTerminal('-S Xincsearch_nl', {'rows': 5, 'cols': 10}) call term_sendkeys(buf, '/test') call VerifyScreenDump(buf, 'Test_incsearch_newline1', {}) @@ -1982,7 +2000,6 @@ func Test_incsearch_highlighting_newline() call StopVimInTerminal(buf) " clean up - call delete('Xincsearch_nl') call test_override("char_avail", 0) bw endfunc @@ -2123,11 +2140,10 @@ func Test_search_with_invalid_range() 5/ c END - call writefile(lines, 'Xrangesearch') + call writefile(lines, 'Xrangesearch', 'D') source Xrangesearch bwipe! - call delete('Xrangesearch') endfunc diff --git a/test/old/testdir/test_search_stat.vim b/test/old/testdir/test_search_stat.vim index a2523fc6c7..b57b7ba7b0 100644 --- a/test/old/testdir/test_search_stat.vim +++ b/test/old/testdir/test_search_stat.vim @@ -308,7 +308,7 @@ func Test_searchcount_in_statusline() set hlsearch set laststatus=2 statusline+=%{TestSearchCount()} END - call writefile(lines, 'Xsearchstatusline') + call writefile(lines, 'Xsearchstatusline', 'D') let buf = RunVimInTerminal('-S Xsearchstatusline', #{rows: 10}) call TermWait(buf) call term_sendkeys(buf, "/something") @@ -316,7 +316,6 @@ func Test_searchcount_in_statusline() call term_sendkeys(buf, "\<Esc>") call StopVimInTerminal(buf) - call delete('Xsearchstatusline') endfunc func Test_search_stat_foldopen() @@ -330,7 +329,7 @@ func Test_search_stat_foldopen() call cursor(1,1) norm n END - call writefile(lines, 'Xsearchstat1') + call writefile(lines, 'Xsearchstat1', 'D') let buf = RunVimInTerminal('-S Xsearchstat1', #{rows: 10}) call VerifyScreenDump(buf, 'Test_searchstat_3', {}) @@ -342,7 +341,6 @@ func Test_search_stat_foldopen() call VerifyScreenDump(buf, 'Test_searchstat_3', {}) call StopVimInTerminal(buf) - call delete('Xsearchstat1') endfunc func! Test_search_stat_screendump() @@ -359,7 +357,7 @@ func! Test_search_stat_screendump() call cursor(1,1) norm n END - call writefile(lines, 'Xsearchstat') + call writefile(lines, 'Xsearchstat', 'D') let buf = RunVimInTerminal('-S Xsearchstat', #{rows: 10}) call VerifyScreenDump(buf, 'Test_searchstat_1', {}) @@ -368,7 +366,6 @@ func! Test_search_stat_screendump() call VerifyScreenDump(buf, 'Test_searchstat_2', {}) call StopVimInTerminal(buf) - call delete('Xsearchstat') endfunc func Test_search_stat_then_gd() @@ -379,7 +376,7 @@ func Test_search_stat_then_gd() set shortmess-=S set hlsearch END - call writefile(lines, 'Xsearchstatgd') + call writefile(lines, 'Xsearchstatgd', 'D') let buf = RunVimInTerminal('-S Xsearchstatgd', #{rows: 10}) call term_sendkeys(buf, "/dog\<CR>") @@ -389,7 +386,6 @@ func Test_search_stat_then_gd() call VerifyScreenDump(buf, 'Test_searchstatgd_2', {}) call StopVimInTerminal(buf) - call delete('Xsearchstatgd') endfunc func Test_search_stat_and_incsearch() diff --git a/test/old/testdir/test_selectmode.vim b/test/old/testdir/test_selectmode.vim index 59a1deba65..34ccdae7d8 100644 --- a/test/old/testdir/test_selectmode.vim +++ b/test/old/testdir/test_selectmode.vim @@ -323,4 +323,20 @@ func Test_ins_ctrl_o_in_insert_mode_resets_selectmode() bwipe! endfunc +" Test that an :lmap mapping for a printable keypad key is applied when typing +" it in Select mode. +func Test_selectmode_keypad_lmap() + new + lnoremap <buffer> <kPoint> ??? + lnoremap <buffer> <kEnter> !!! + setlocal iminsert=1 + call setline(1, 'abcdef') + call feedkeys("gH\<kPoint>\<Esc>", 'tx') + call assert_equal(['???'], getline(1, '$')) + call feedkeys("gH\<kEnter>\<Esc>", 'tx') + call assert_equal(['!!!'], getline(1, '$')) + + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_shell.vim b/test/old/testdir/test_shell.vim index c50161a8ed..9499462a70 100644 --- a/test/old/testdir/test_shell.vim +++ b/test/old/testdir/test_shell.vim @@ -119,6 +119,10 @@ func Test_shellescape() call assert_equal("'te\\#xt'", shellescape("te#xt", 1)) call assert_equal("'te!xt'", shellescape("te!xt")) call assert_equal("'te\\!xt'", shellescape("te!xt", 1)) + call assert_equal("'te<cword>xt'", shellescape("te<cword>xt")) + call assert_equal("'te\\<cword>xt'", shellescape("te<cword>xt", 1)) + call assert_equal("'te<cword>%xt'", shellescape("te<cword>%xt")) + call assert_equal("'te\\<cword>\\%xt'", shellescape("te<cword>%xt", 1)) call assert_equal("'te\nxt'", shellescape("te\nxt")) call assert_equal("'te\\\nxt'", shellescape("te\nxt", 1)) @@ -128,6 +132,29 @@ func Test_shellescape() call assert_equal("'te\\\nxt'", shellescape("te\nxt")) call assert_equal("'te\\\\\nxt'", shellescape("te\nxt", 1)) + set shell=fish + call assert_equal("'text'", shellescape('text')) + call assert_equal("'te\"xt'", shellescape('te"xt')) + call assert_equal("'te'\\''xt'", shellescape("te'xt")) + + call assert_equal("'te%xt'", shellescape("te%xt")) + call assert_equal("'te\\%xt'", shellescape("te%xt", 1)) + call assert_equal("'te#xt'", shellescape("te#xt")) + call assert_equal("'te\\#xt'", shellescape("te#xt", 1)) + call assert_equal("'te!xt'", shellescape("te!xt")) + call assert_equal("'te\\!xt'", shellescape("te!xt", 1)) + + call assert_equal("'te\\\\xt'", shellescape("te\\xt")) + call assert_equal("'te\\\\xt'", shellescape("te\\xt", 1)) + call assert_equal("'te\\\\'\\''xt'", shellescape("te\\'xt")) + call assert_equal("'te\\\\'\\''xt'", shellescape("te\\'xt", 1)) + call assert_equal("'te\\\\!xt'", shellescape("te\\!xt")) + call assert_equal("'te\\\\\\!xt'", shellescape("te\\!xt", 1)) + call assert_equal("'te\\\\%xt'", shellescape("te\\%xt")) + call assert_equal("'te\\\\\\%xt'", shellescape("te\\%xt", 1)) + call assert_equal("'te\\\\#xt'", shellescape("te\\#xt")) + call assert_equal("'te\\\\\\#xt'", shellescape("te\\#xt", 1)) + let &shell = save_shell endfunc @@ -161,7 +188,7 @@ func Test_shellxquote() let save_sxq = &shellxquote let save_sxe = &shellxescape - call writefile(['#!/bin/sh', 'echo "Cmd: [$*]" > Xlog'], 'Xtestshell') + call writefile(['#!/bin/sh', 'echo "Cmd: [$*]" > Xlog'], 'Xtestshell', 'D') call setfperm('Xtestshell', "r-x------") set shell=./Xtestshell @@ -185,7 +212,6 @@ func Test_shellxquote() let &shell = save_shell let &shellxquote = save_sxq let &shellxescape = save_sxe - call delete('Xtestshell') call delete('Xlog') endfunc diff --git a/test/old/testdir/test_signals.vim b/test/old/testdir/test_signals.vim index 667448a7c2..4d4c7e405f 100644 --- a/test/old/testdir/test_signals.vim +++ b/test/old/testdir/test_signals.vim @@ -86,26 +86,72 @@ func Test_signal_INT() throw 'Skipped: INT signal not supported' endif - " Skip the rest of the test when running with valgrind as signal INT is not - " received somehow by Vim when running with valgrind. - let cmd = GetVimCommand() - if cmd =~ 'valgrind' - throw 'Skipped: cannot test signal INT with valgrind' - endif - let buf = RunVimInTerminal('', {'rows': 6}) let pid_vim = term_getjob(buf)->job_info().process " Check that an endless loop in Vim is interrupted by signal INT. + call term_sendkeys(buf, ":call setline(1, 'running')\n") call term_sendkeys(buf, ":while 1 | endwhile\n") call WaitForAssert({-> assert_equal(':while 1 | endwhile', term_getline(buf, 6))}) exe 'silent !kill -s INT ' .. pid_vim + sleep 50m call term_sendkeys(buf, ":call setline(1, 'INTERRUPTED')\n") call WaitForAssert({-> assert_equal('INTERRUPTED', term_getline(buf, 1))}) call StopVimInTerminal(buf) endfunc +" Test signal TSTP. Handler sets got_tstp. +func Test_signal_TSTP() + CheckRunVimInTerminal + if !HasSignal('TSTP') + throw 'Skipped: TSTP signal not supported' + endif + + " If test fails once, it can leave temporary files and trying to rerun + " the test would then fail again if they are not deleted first. + call delete('.Xsig_TERM.swp') + call delete('XsetupAucmd') + call delete('XautoOut1') + call delete('XautoOut2') + let lines =<< trim END + au VimSuspend * call writefile(["VimSuspend triggered"], "XautoOut1", "as") + au VimResume * call writefile(["VimResume triggered"], "XautoOut2", "as") + END + call writefile(lines, 'XsetupAucmd', 'D') + + let buf = RunVimInTerminal('-S XsetupAucmd Xsig_TERM', {'rows': 6}) + let pid_vim = term_getjob(buf)->job_info().process + + call term_sendkeys(buf, ":call setline(1, 'foo')\n") + call WaitForAssert({-> assert_equal('foo', term_getline(buf, 1))}) + + call assert_false(filereadable('Xsig_TERM')) + + " After TSTP the file is not saved (same function as ^Z) + exe 'silent !kill -s TSTP ' .. pid_vim + call WaitForAssert({-> assert_true(filereadable('.Xsig_TERM.swp'))}) + sleep 100m + + " We resume after the suspend. Sleep a bit for the signal to take effect, + " also when running under valgrind. + exe 'silent !kill -s CONT ' .. pid_vim + call WaitForAssert({-> assert_true(filereadable('XautoOut2'))}) + sleep 10m + + call StopVimInTerminal(buf) + + let result = readfile('XautoOut1') + call assert_equal(["VimSuspend triggered"], result) + let result = readfile('XautoOut2') + call assert_equal(["VimResume triggered"], result) + + %bwipe! + call delete('.Xsig_TERM.swp') + call delete('XautoOut1') + call delete('XautoOut2') +endfunc + " Test a deadly signal. " " There are several deadly signals: SISEGV, SIBUS, SIGTERM... @@ -120,10 +166,6 @@ func Test_deadly_signal_TERM() throw 'Skipped: TERM signal not supported' endif CheckRunVimInTerminal - let cmd = GetVimCommand() - if cmd =~ 'valgrind' - throw 'Skipped: cannot test signal TERM with valgrind' - endif " If test fails once, it can leave temporary files and trying to rerun " the test would then fail again if they are not deleted first. @@ -134,7 +176,7 @@ func Test_deadly_signal_TERM() au VimLeave * call writefile(["VimLeave triggered"], "XautoOut", "as") au VimLeavePre * call writefile(["VimLeavePre triggered"], "XautoOut", "as") END - call writefile(lines, 'XsetupAucmd') + call writefile(lines, 'XsetupAucmd', 'D') let buf = RunVimInTerminal('-S XsetupAucmd Xsig_TERM', {'rows': 6}) let pid_vim = term_getjob(buf)->job_info().process @@ -158,7 +200,6 @@ func Test_deadly_signal_TERM() %bwipe! call delete('.Xsig_TERM.swp') - call delete('XsetupAucmd') call delete('XautoOut') endfunc diff --git a/test/old/testdir/test_signs.vim b/test/old/testdir/test_signs.vim index d7baa7e870..4ac8831239 100644 --- a/test/old/testdir/test_signs.vim +++ b/test/old/testdir/test_signs.vim @@ -89,8 +89,9 @@ func Test_sign() " Place a sign without specifying the filename or buffer sign place 77 line=9 name=Sign2 let a=execute('sign place') + " Nvim: sign line clamped to buffer length call assert_equal("\n--- Signs ---\nSigns for [NULL]:\n" . - \ " line=9 id=77 name=Sign2 priority=10\n", a) + \ " line=4 id=77 name=Sign2 priority=10\n", a) sign unplace * " Check :jump with file=... @@ -245,7 +246,7 @@ func Test_sign_completion() call assert_equal('"sign define jump list place undefine unplace', @:) call feedkeys(":sign define Sign \<C-A>\<C-B>\"\<CR>", 'tx') - call assert_equal('"sign define Sign culhl= icon= linehl= numhl= text= texthl=', @:) + call assert_equal('"sign define Sign culhl= icon= linehl= numhl= priority= text= texthl=', @:) for hl in ['culhl', 'linehl', 'numhl', 'texthl'] call feedkeys(":sign define Sign "..hl.."=Spell\<C-A>\<C-B>\"\<CR>", 'tx') @@ -253,8 +254,8 @@ func Test_sign_completion() \ 'SpellLocal SpellRare', @:) endfor - call writefile(repeat(["Sun is shining"], 30), "XsignOne") - call writefile(repeat(["Sky is blue"], 30), "XsignTwo") + call writefile(repeat(["Sun is shining"], 30), "XsignOne", 'D') + call writefile(repeat(["Sky is blue"], 30), "XsignTwo", 'D') call feedkeys(":sign define Sign icon=Xsig\<C-A>\<C-B>\"\<CR>", 'tx') call assert_equal('"sign define Sign icon=XsignOne XsignTwo', @:) @@ -331,8 +332,6 @@ func Test_sign_completion() sign undefine Sign1 sign undefine Sign2 enew - call delete('XsignOne') - call delete('XsignTwo') endfunc func Test_sign_invalid_commands() @@ -475,7 +474,7 @@ func Test_sign_funcs() call assert_fails('call sign_getdefined({})', 'E731:') " Tests for sign_place() - call writefile(repeat(["Sun is shining"], 30), "Xsign") + call writefile(repeat(["Sun is shining"], 30), "Xsign", 'D') edit Xsign call assert_equal(10, sign_place(10, '', 'sign1', 'Xsign', @@ -581,7 +580,6 @@ func Test_sign_funcs() \ 'priority' : 10}]}], \ sign_getplaced('%', {'lnum' : 22})) - call delete("Xsign") call sign_unplace('*') call sign_undefine() enew | only @@ -594,7 +592,7 @@ func Test_sign_group() call sign_unplace('*') call sign_undefine() - call writefile(repeat(["Sun is shining"], 30), "Xsign") + call writefile(repeat(["Sun is shining"], 30), "Xsign", 'D') let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error'} call assert_equal(0, sign_define("sign1", attr)) @@ -799,10 +797,11 @@ func Test_sign_group() set buftype=nofile sign place 25 line=76 name=sign1 priority=99 file=foo let a = execute('sign place') + " Nvim: sign line clamped to buffer length call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" . \ " line=10 id=5 name=sign1 priority=10\n" . \ "Signs for foo:\n" . - \ " line=76 id=25 name=sign1 priority=99\n", a) + \ " line=1 id=25 name=sign1 priority=99\n", a) close bwipe foo @@ -834,7 +833,6 @@ func Test_sign_group() " Error cases call assert_fails("sign place 3 group= name=sign1 buffer=" . bnum, 'E474:') - call delete("Xsign") call sign_unplace('*') call sign_undefine() enew | only @@ -877,8 +875,8 @@ func Test_sign_unplace() call sign_undefine() " Create two files and define signs - call writefile(repeat(["Sun is shining"], 30), "Xsign1") - call writefile(repeat(["It is beautiful"], 30), "Xsign2") + call writefile(repeat(["Sun is shining"], 30), "Xsign1", 'D') + call writefile(repeat(["It is beautiful"], 30), "Xsign2", 'D') let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error'} call sign_define("sign1", attr) @@ -1187,8 +1185,6 @@ func Test_sign_unplace() call sign_unplace('*') call sign_undefine() enew | only - call delete("Xsign1") - call delete("Xsign2") endfunc " Tests for auto-generating the sign identifier. @@ -1200,7 +1196,7 @@ func Test_aaa_sign_id_autogen() let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error'} call assert_equal(0, sign_define("sign1", attr)) - call writefile(repeat(["Sun is shining"], 30), "Xsign") + call writefile(repeat(["Sun is shining"], 30), "Xsign", 'D') edit Xsign call assert_equal(1, sign_place(0, '', 'sign1', 'Xsign', @@ -1222,7 +1218,6 @@ func Test_aaa_sign_id_autogen() call assert_equal(10, \ sign_getplaced('Xsign', {'id' : 1})[0].signs[0].lnum) - call delete("Xsign") call sign_unplace('*') call sign_undefine() enew | only @@ -1238,9 +1233,28 @@ func Test_sign_priority() call sign_define("sign1", attr) call sign_define("sign2", attr) call sign_define("sign3", attr) + let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Search', 'priority': 60} + call sign_define("sign4", attr) + + " Test for :sign list + let a = execute('sign list') + call assert_equal("\nsign sign1 text==> linehl=Search texthl=Search\n" . + \ "sign sign2 text==> linehl=Search texthl=Search\n" . + \ "sign sign3 text==> linehl=Search texthl=Search\n" . + \ "sign sign4 text==> priority=60 linehl=Search texthl=Search", a) + + " Test for sign_getdefined() + let s = sign_getdefined() + call assert_equal([ + \ {'name': 'sign1', 'texthl': 'Search', 'linehl': 'Search', 'text': '=>'}, + \ {'name': 'sign2', 'texthl': 'Search', 'linehl': 'Search', 'text': '=>'}, + \ {'name': 'sign3', 'texthl': 'Search', 'linehl': 'Search', 'text': '=>'}, + \ {'name': 'sign4', 'priority': 60, 'texthl': 'Search', 'linehl': 'Search', + \ 'text': '=>'}], + \ s) " Place three signs with different priority in the same line - call writefile(repeat(["Sun is shining"], 30), "Xsign") + call writefile(repeat(["Sun is shining"], 30), "Xsign", 'D') edit Xsign call sign_place(1, 'g1', 'sign1', 'Xsign', @@ -1576,15 +1590,33 @@ func Test_sign_priority() \ " line=10 id=5 group=g1 name=sign1 priority=20\n", a) call sign_unplace('*') + + " Test for sign with default priority. + call sign_place(1, 'g1', 'sign4', 'Xsign', {'lnum' : 3}) + sign place 2 line=5 name=sign4 group=g1 file=Xsign + + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign4', 'lnum' : 3, 'group' : 'g1', + \ 'priority' : 60}, + \ {'id' : 2, 'name' : 'sign4', 'lnum' : 5, 'group' : 'g1', + \ 'priority' : 60}], + \ s[0].signs) + + let a = execute('sign place group=g1') + call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" . + \ " line=3 id=1 group=g1 name=sign4 priority=60\n" . + \ " line=5 id=2 group=g1 name=sign4 priority=60\n", a) + + call sign_unplace('*') call sign_undefine() enew | only - call delete("Xsign") endfunc " Tests for memory allocation failures in sign functions func Test_sign_memfailures() CheckFunction test_alloc_fail - call writefile(repeat(["Sun is shining"], 30), "Xsign") + call writefile(repeat(["Sun is shining"], 30), "Xsign", 'D') edit Xsign call test_alloc_fail(GetAllocId('sign_getdefined'), 0, 0) @@ -1621,7 +1653,6 @@ func Test_sign_memfailures() call sign_unplace('*') call sign_undefine() enew | only - call delete("Xsign") endfunc " Test for auto-adjusting the line number of a placed sign. @@ -1777,11 +1808,12 @@ func Test_sign_cursor_position() let lines =<< trim END call setline(1, [repeat('x', 75), 'mmmm', 'yyyy']) call cursor(2,1) - sign define s1 texthl=Search text==> + sign define s1 texthl=Search text==> + sign define s2 linehl=Pmenu redraw - sign place 10 line=2 name=s1 + sign place 10 line=2 name=s1 END - call writefile(lines, 'XtestSigncolumn') + call writefile(lines, 'XtestSigncolumn', 'D') let buf = RunVimInTerminal('-S XtestSigncolumn', {'rows': 6}) call VerifyScreenDump(buf, 'Test_sign_cursor_1', {}) @@ -1789,15 +1821,18 @@ func Test_sign_cursor_position() call term_sendkeys(buf, ":sign define s1 text=-)\<CR>") call VerifyScreenDump(buf, 'Test_sign_cursor_2', {}) + " Also place a line HL sign + call term_sendkeys(buf, ":sign place 11 line=2 name=s2\<CR>") + call VerifyScreenDump(buf, 'Test_sign_cursor_3', {}) + " update cursor position calculation call term_sendkeys(buf, "lh") + call term_sendkeys(buf, ":sign unplace 11\<CR>") call term_sendkeys(buf, ":sign unplace 10\<CR>") - call VerifyScreenDump(buf, 'Test_sign_cursor_3', {}) - + call VerifyScreenDump(buf, 'Test_sign_cursor_4', {}) " clean up call StopVimInTerminal(buf) - call delete('XtestSigncolumn') endfunc " Return the 'len' characters in screen starting from (row,col) @@ -1916,7 +1951,7 @@ endfunc " Test for managing multiple signs using the sign functions func Test_sign_funcs_multi() - call writefile(repeat(["Sun is shining"], 30), "Xsign") + call writefile(repeat(["Sun is shining"], 30), "Xsign", 'D') edit Xsign let bnum = bufnr('') @@ -2029,5 +2064,13 @@ func Test_sign_funcs_multi() call sign_unplace('*') call sign_undefine() enew! - call delete("Xsign") endfunc + +func Test_sign_null_list() + eval v:_null_list->sign_define() + eval v:_null_list->sign_placelist() + eval v:_null_list->sign_undefine() + eval v:_null_list->sign_unplacelist() +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_sort.vim b/test/old/testdir/test_sort.vim index 94a35e3cb5..2d03dd2f2a 100644 --- a/test/old/testdir/test_sort.vim +++ b/test/old/testdir/test_sort.vim @@ -1336,6 +1336,34 @@ func Test_sort_cmd() \ ] endif endif + if has('float') + let tests += [ + \ { + \ 'name' : 'float', + \ 'cmd' : 'sort f', + \ 'input' : [ + \ '1.234', + \ '0.88', + \ ' + 123.456', + \ '1.15e-6', + \ '-1.1e3', + \ '-1.01e3', + \ '', + \ '' + \ ], + \ 'expected' : [ + \ '', + \ '', + \ '-1.1e3', + \ '-1.01e3', + \ '1.15e-6', + \ '0.88', + \ '1.234', + \ ' + 123.456' + \ ] + \ }, + \ ] + endif for t in tests enew! @@ -1497,11 +1525,10 @@ func Test_sort_with_no_last_search_pat() call writefile(v:errors, 'Xresult') qall! [SCRIPT] - call writefile(lines, 'Xscript') + call writefile(lines, 'Xscript', 'D') if RunVim([], [], '--clean -S Xscript') call assert_equal([], readfile('Xresult')) endif - call delete('Xscript') call delete('Xresult') endfunc diff --git a/test/old/testdir/test_source.vim b/test/old/testdir/test_source.vim index d4d96e36bf..01c08b183c 100644 --- a/test/old/testdir/test_source.vim +++ b/test/old/testdir/test_source.vim @@ -53,12 +53,10 @@ endfunc " When deleting a file and immediately creating a new one the inode may be " recycled. Vim should not recognize it as the same script. func Test_different_script() - call writefile(['let s:var = "asdf"'], 'XoneScript') + call writefile(['let s:var = "asdf"'], 'XoneScript', 'D') source XoneScript - call delete('XoneScript') - call writefile(['let g:var = s:var'], 'XtwoScript') + call writefile(['let g:var = s:var'], 'XtwoScript', 'D') call assert_fails('source XtwoScript', 'E121:') - call delete('XtwoScript') endfunc " When sourcing a vim script, shebang should be ignored. diff --git a/test/old/testdir/test_source_utf8.vim b/test/old/testdir/test_source_utf8.vim index 66fabe0442..f3e11a4bbc 100644 --- a/test/old/testdir/test_source_utf8.vim +++ b/test/old/testdir/test_source_utf8.vim @@ -42,7 +42,7 @@ func Test_source_ctrl_v() \ "map __3 asd\<C-V>\<C-V>", \ "map __4 asd\<C-V>\<C-V>\<C-V>", \ "map __5 asd\<C-V>\<C-V>\<C-V>", - \ ], 'Xtestfile') + \ ], 'Xtestfile', 'D') source Xtestfile enew! exe "normal __1\<Esc>\<Esc>__2\<Esc>__3\<Esc>\<Esc>__4\<Esc>__5\<Esc>" @@ -52,7 +52,6 @@ func Test_source_ctrl_v() \ getline(1, 2)) enew! - call delete('Xtestfile') unmap __1 unmap __2 unmap __3 diff --git a/test/old/testdir/test_spell.vim b/test/old/testdir/test_spell.vim index a19b64a7de..bdd8a673fd 100644 --- a/test/old/testdir/test_spell.vim +++ b/test/old/testdir/test_spell.vim @@ -5,6 +5,7 @@ source check.vim CheckFeature spell source screendump.vim +source view_util.vim func TearDown() set nospell @@ -124,6 +125,7 @@ foobar/? set spelllang= call assert_fails("call spellbadword('maxch')", 'E756:') + call assert_fails("spelldump", 'E756:') call delete('Xwords.spl') call delete('Xwords') @@ -300,6 +302,20 @@ func Test_compl_with_CTRL_X_CTRL_K_using_spell() set spell& spelllang& dictionary& ignorecase& endfunc +func Test_compl_with_CTRL_X_s() + new + set spell spelllang=en_us showmode + inoremap <buffer><F2> <Cmd>let g:msg = Screenline(&lines)<CR> + + call feedkeys("STheatre\<C-X>s\<F2>\<C-Y>\<Esc>", 'tx') + call assert_equal(['Theater'], getline(1, '$')) + call assert_match('(^S^N^P)', g:msg) + + bwipe! + set spell& spelllang& showmode& + unlet g:msg +endfunc + func Test_spellrepall() new set spell @@ -796,8 +812,8 @@ func Test_zz_sal_and_addition() throw 'skipped: Nvim does not support enc=latin1' set enc=latin1 set spellfile= - call writefile(g:test_data_dic1, "Xtest.dic") - call writefile(g:test_data_aff_sal, "Xtest.aff") + call writefile(g:test_data_dic1, "Xtest.dic", 'D') + call writefile(g:test_data_aff_sal, "Xtest.aff", 'D') mkspell! Xtest Xtest set spl=Xtest.latin1.spl spell call assert_equal('kbltykk', soundfold('goobledygoook')) @@ -805,7 +821,7 @@ func Test_zz_sal_and_addition() call assert_equal('*fls kswts tl', soundfold('oeverloos gezwets edale')) "also use an addition file - call writefile(["/regions=usgbnz", "elequint/2", "elekwint/3"], "Xtest.latin1.add") + call writefile(["/regions=usgbnz", "elequint/2", "elekwint/3"], "Xtest.latin1.add", 'D') mkspell! Xtest.latin1.add.spl Xtest.latin1.add bwipe! @@ -842,10 +858,9 @@ endfunc func Test_region_error() messages clear - call writefile(["/regions=usgbnz", "elequint/0"], "Xtest.latin1.add") + call writefile(["/regions=usgbnz", "elequint/0"], "Xtest.latin1.add", 'D') mkspell! Xtest.latin1.add.spl Xtest.latin1.add call assert_match('Invalid region nr in Xtest.latin1.add line 2: 0', execute('messages')) - call delete('Xtest.latin1.add') call delete('Xtest.latin1.add.spl') endfunc diff --git a/test/old/testdir/test_spell_utf8.vim b/test/old/testdir/test_spell_utf8.vim index 91ada1ed38..bb2c354a3d 100644 --- a/test/old/testdir/test_spell_utf8.vim +++ b/test/old/testdir/test_spell_utf8.vim @@ -726,8 +726,8 @@ endfunc " Test with SAL instead of SOFO items; test automatic reloading func Test_spell_sal_and_addition() set spellfile= - call writefile(g:test_data_dic1, "Xtest.dic") - call writefile(g:test_data_aff_sal, "Xtest.aff") + call writefile(g:test_data_dic1, "Xtest.dic", 'D') + call writefile(g:test_data_aff_sal, "Xtest.aff", 'D') mkspell! Xtest Xtest set spl=Xtest.utf-8.spl spell call assert_equal('kbltykk', soundfold('goobledygoook')) @@ -735,7 +735,7 @@ func Test_spell_sal_and_addition() call assert_equal('*fls kswts tl', soundfold('oeverloos gezwets edale')) "also use an addition file - call writefile(["/regions=usgbnz", "elequint/2", "elekwint/3"], "Xtest.utf-8.add") + call writefile(["/regions=usgbnz", "elequint/2", "elekwint/3"], "Xtest.utf-8.add", 'D') mkspell! Xtest.utf-8.add.spl Xtest.utf-8.add bwipe! diff --git a/test/old/testdir/test_spellfile.vim b/test/old/testdir/test_spellfile.vim index 4d2a6cf35f..48e46641f4 100644 --- a/test/old/testdir/test_spellfile.vim +++ b/test/old/testdir/test_spellfile.vim @@ -191,6 +191,11 @@ func Spellfile_Test(content, emsg) " Add the spell file header and version (VIMspell2) let v = 0z56494D7370656C6C32 + a:content call writefile(v, splfile, 'b') + + " 'encoding' is set before each test to clear the previously loaded suggest + " file from memory. + set encoding=utf-8 + set runtimepath=./Xtest set spelllang=Xtest if a:emsg != '' @@ -207,7 +212,7 @@ endfunc " The spell file format is described in spellfile.c func Test_spellfile_format_error() let save_rtp = &rtp - call mkdir('Xtest/spell', 'p') + call mkdir('Xtest/spell', 'pR') let splfile = './Xtest/spell/Xtest.utf-8.spl' " empty spell file @@ -311,6 +316,12 @@ func Test_spellfile_format_error() " SN_SOFO: missing sofoto call Spellfile_Test(0z0600000000050001610000, 'E759:') + " SN_SOFO: empty sofofrom and sofoto + call Spellfile_Test(0z06000000000400000000FF000000000000000000000000, '') + + " SN_SOFO: multi-byte characters in sofofrom and sofoto + call Spellfile_Test(0z0600000000080002CF810002CF82FF000000000000000000000000, '') + " SN_COMPOUND: compmax is less than 2 call Spellfile_Test(0z08000000000101, 'E759:') @@ -320,6 +331,12 @@ func Test_spellfile_format_error() " SN_COMPOUND: missing compoptions call Spellfile_Test(0z080000000005040101, 'E758:') + " SN_COMPOUND: missing comppattern + call Spellfile_Test(0z08000000000704010100000001, 'E758:') + + " SN_COMPOUND: incorrect comppatlen + call Spellfile_Test(0z080000000007040101000000020165, 'E758:') + " SN_INFO: missing info call Spellfile_Test(0z0F0000000005040101, '') @@ -329,6 +346,12 @@ func Test_spellfile_format_error() " SN_MAP: missing midword call Spellfile_Test(0z0700000000040102, '') + " SN_MAP: empty map string + call Spellfile_Test(0z070000000000FF000000000000000000000000, '') + + " SN_MAP: duplicate multibyte character + call Spellfile_Test(0z070000000004DC81DC81, 'E783:') + " SN_SYLLABLE: missing SYLLABLE item call Spellfile_Test(0z0900000000040102, '') @@ -345,20 +368,28 @@ func Test_spellfile_format_error() " LWORDTREE: missing tree node value call Spellfile_Test(0zFF0000000402, 'E758:') + " LWORDTREE: incorrect sibling node count + call Spellfile_Test(0zFF00000001040000000000000000, 'E759:') + " KWORDTREE: missing tree node call Spellfile_Test(0zFF0000000000000004, 'E758:') " PREFIXTREE: missing tree node call Spellfile_Test(0zFF000000000000000000000004, 'E758:') + " PREFIXTREE: incorrect prefcondnr + call Spellfile_Test(0zFF000000000000000000000002010200000020, 'E759:') + + " PREFIXTREE: invalid nodeidx + call Spellfile_Test(0zFF00000000000000000000000201010000, 'E759:') + let &rtp = save_rtp - call delete('Xtest', 'rf') endfunc " Test for format errors in suggest file func Test_sugfile_format_error() let save_rtp = &rtp - call mkdir('Xtest/spell', 'p') + call mkdir('Xtest/spell', 'pR') let splfile = './Xtest/spell/Xtest.utf-8.spl' let sugfile = './Xtest/spell/Xtest.utf-8.sug' @@ -441,7 +472,6 @@ func Test_sugfile_format_error() set nospell spelllang& let &rtp = save_rtp - call delete('Xtest', 'rf') endfunc " Test for using :mkspell to create a spell file from a list of words @@ -454,7 +484,7 @@ func Test_wordlist_dic() /encoding=latin1 example [END] - call writefile(lines, 'Xwordlist.dic') + call writefile(lines, 'Xwordlist.dic', 'D') let output = execute('mkspell Xwordlist.spl Xwordlist.dic') call assert_match('Duplicate /encoding= line ignored in Xwordlist.dic line 4: /encoding=latin1', output) @@ -518,15 +548,28 @@ func Test_wordlist_dic() let output = execute('mkspell! -ascii Xwordlist.spl Xwordlist.dic') call assert_match('Ignored 1 words with non-ASCII characters', output) + " keep case of a word + let lines =<< trim [END] + example/= + [END] + call writefile(lines, 'Xwordlist.dic') + let output = execute('mkspell! Xwordlist.spl Xwordlist.dic') + call assert_match('Compressed keep-case:', output) + call delete('Xwordlist.spl') - call delete('Xwordlist.dic') endfunc " Test for the :mkspell command func Test_mkspell() call assert_fails('mkspell Xtest_us.spl', 'E751:') + call assert_fails('mkspell Xtest.spl abc', 'E484:') call assert_fails('mkspell a b c d e f g h i j k', 'E754:') + " create a .aff file but not the .dic file + call writefile([], 'Xtest.aff') + call assert_fails('mkspell Xtest.spl Xtest', 'E484:') + call delete('Xtest.aff') + call writefile([], 'Xtest.spl') call writefile([], 'Xtest.dic') call assert_fails('mkspell Xtest.spl Xtest.dic', 'E13:') @@ -554,8 +597,8 @@ func Test_aff_file_format_error() CheckNotMSWindows " No word count in .dic file - call writefile([], 'Xtest.dic') - call writefile([], 'Xtest.aff') + call writefile([], 'Xtest.dic', 'D') + call writefile([], 'Xtest.aff', 'D') call assert_fails('mkspell! Xtest.spl Xtest', 'E760:') " create a .dic file for the tests below @@ -656,7 +699,7 @@ func Test_aff_file_format_error() let output = execute('mkspell! Xtest.spl Xtest') call assert_match('Different combining flag in continued affix block in Xtest.aff line 3', output) - " Try to reuse a affix used for BAD flag + " Try to reuse an affix used for BAD flag call writefile(['BAD x', 'PFX x Y 1', 'PFX x 0 re x'], 'Xtest.aff') let output = execute('mkspell! Xtest.spl Xtest') call assert_match('Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in Xtest.aff line 2: x', output) @@ -730,6 +773,44 @@ func Test_aff_file_format_error() let output = execute('mkspell! Xtest.spl Xtest') call assert_match('Illegal flag in Xtest.aff line 2: L', output) + " Nvim: non-utf8 encoding not supported + " " missing character in UPP entry. The character table is used only in a + " " non-utf8 encoding + " call writefile(['FOL abc', 'LOW abc', 'UPP A'], 'Xtest.aff') + " let save_encoding = &encoding + " set encoding=cp949 + " call assert_fails('mkspell! Xtest.spl Xtest', 'E761:') + " let &encoding = save_encoding + " + " " character range doesn't match between FOL and LOW entries + " call writefile(["FOL \u0102bc", 'LOW abc', 'UPP ABC'], 'Xtest.aff') + " let save_encoding = &encoding + " set encoding=cp949 + " call assert_fails('mkspell! Xtest.spl Xtest', 'E762:') + " let &encoding = save_encoding + " + " " character range doesn't match between FOL and UPP entries + " call writefile(["FOL \u0102bc", "LOW \u0102bc", 'UPP ABC'], 'Xtest.aff') + " let save_encoding = &encoding + " set encoding=cp949 + " call assert_fails('mkspell! Xtest.spl Xtest', 'E762:') + " let &encoding = save_encoding + " + " " additional characters in LOW and UPP entries + " call writefile(["FOL ab", "LOW abc", 'UPP ABC'], 'Xtest.aff') + " let save_encoding = &encoding + " set encoding=cp949 + " call assert_fails('mkspell! Xtest.spl Xtest', 'E761:') + " let &encoding = save_encoding + " + " " missing UPP entry + " call writefile(["FOL abc", "LOW abc"], 'Xtest.aff') + " let save_encoding = &encoding + " set encoding=cp949 + " let output = execute('mkspell! Xtest.spl Xtest') + " call assert_match('Missing FOL/LOW/UPP line in Xtest.aff', output) + " let &encoding = save_encoding + " duplicate word in the .dic file call writefile(['2', 'good', 'good', 'good'], 'Xtest.dic') call writefile(['NAME vim'], 'Xtest.aff') @@ -737,8 +818,16 @@ func Test_aff_file_format_error() call assert_match('First duplicate word in Xtest.dic line 3: good', output) call assert_match('2 duplicate word(s) in Xtest.dic', output) - call delete('Xtest.dic') - call delete('Xtest.aff') + " use multiple .aff files with different values for COMPOUNDWORDMAX and + " MIDWORD (number and string) + call writefile(['1', 'world'], 'Xtest_US.dic', 'D') + call writefile(['1', 'world'], 'Xtest_CA.dic', 'D') + call writefile(["COMPOUNDWORDMAX 3", "MIDWORD '-"], 'Xtest_US.aff', 'D') + call writefile(["COMPOUNDWORDMAX 4", "MIDWORD '="], 'Xtest_CA.aff', 'D') + let output = execute('mkspell! Xtest.spl Xtest_US Xtest_CA') + call assert_match('COMPOUNDWORDMAX value differs from what is used in another .aff file', output) + call assert_match('MIDWORD value differs from what is used in another .aff file', output) + call delete('Xtest.spl') call delete('Xtest.sug') endfunc @@ -757,9 +846,25 @@ func Test_spell_add_word() %bw! endfunc +func Test_spell_add_long_word() + set spell spellfile=./Xspellfile.add spelllang=en + + let word = repeat('a', 9000) + let v:errmsg = '' + " Spell checking doesn't really work for such a long word, + " but this should not cause an E1510 error. + exe 'spellgood ' .. word + call assert_equal('', v:errmsg) + call assert_equal([word], readfile('./Xspellfile.add')) + + set spell& spellfile= spelllang& encoding=utf-8 + call delete('./Xspellfile.add') + call delete('./Xspellfile.add.spl') +endfunc + func Test_spellfile_verbose() - call writefile(['1', 'one'], 'XtestVerbose.dic') - call writefile([], 'XtestVerbose.aff') + call writefile(['1', 'one'], 'XtestVerbose.dic', 'D') + call writefile([], 'XtestVerbose.aff', 'D') mkspell! XtestVerbose-utf8.spl XtestVerbose set spell @@ -772,15 +877,13 @@ func Test_spellfile_verbose() call assert_notmatch('Reading spell file "XtestVerbose-utf8.spl"', a) set spell& spelllang& - call delete('XtestVerbose.dic') - call delete('XtestVerbose.aff') call delete('XtestVerbose-utf8.spl') endfunc " Test NOBREAK (see :help spell-NOBREAK) func Test_NOBREAK() - call writefile(['3', 'one', 'two', 'three' ], 'XtestNOBREAK.dic') - call writefile(['NOBREAK' ], 'XtestNOBREAK.aff') + call writefile(['3', 'one', 'two', 'three' ], 'XtestNOBREAK.dic', 'D') + call writefile(['NOBREAK' ], 'XtestNOBREAK.aff', 'D') mkspell! XtestNOBREAK-utf8.spl XtestNOBREAK set spell spelllang=XtestNOBREAK-utf8.spl @@ -802,8 +905,6 @@ func Test_NOBREAK() bw! set spell& spelllang& - call delete('XtestNOBREAK.dic') - call delete('XtestNOBREAK.aff') call delete('XtestNOBREAK-utf8.spl') endfunc @@ -813,11 +914,11 @@ func Test_spellfile_CHECKCOMPOUNDPATTERN() \ 'one/c', \ 'two/c', \ 'three/c', - \ 'four'], 'XtestCHECKCOMPOUNDPATTERN.dic') + \ 'four'], 'XtestCHECKCOMPOUNDPATTERN.dic', 'D') " Forbid compound words where first word ends with 'wo' and second starts with 'on'. call writefile(['CHECKCOMPOUNDPATTERN 1', \ 'CHECKCOMPOUNDPATTERN wo on', - \ 'COMPOUNDFLAG c'], 'XtestCHECKCOMPOUNDPATTERN.aff') + \ 'COMPOUNDFLAG c'], 'XtestCHECKCOMPOUNDPATTERN.aff', 'D') mkspell! XtestCHECKCOMPOUNDPATTERN-utf8.spl XtestCHECKCOMPOUNDPATTERN set spell spelllang=XtestCHECKCOMPOUNDPATTERN-utf8.spl @@ -841,8 +942,6 @@ func Test_spellfile_CHECKCOMPOUNDPATTERN() endfor set spell& spelllang& - call delete('XtestCHECKCOMPOUNDPATTERN.dic') - call delete('XtestCHECKCOMPOUNDPATTERN.aff') call delete('XtestCHECKCOMPOUNDPATTERN-utf8.spl') endfunc @@ -851,15 +950,15 @@ func Test_spellfile_NOCOMPOUNDSUGS() call writefile(['3', \ 'one/c', \ 'two/c', - \ 'three/c'], 'XtestNOCOMPOUNDSUGS.dic') + \ 'three/c'], 'XtestNOCOMPOUNDSUGS.dic', 'D') " pass 0 tests without NOCOMPOUNDSUGS, pass 1 tests with NOCOMPOUNDSUGS for pass in [0, 1] if pass == 0 - call writefile(['COMPOUNDFLAG c'], 'XtestNOCOMPOUNDSUGS.aff') + call writefile(['COMPOUNDFLAG c'], 'XtestNOCOMPOUNDSUGS.aff', 'D') else call writefile(['NOCOMPOUNDSUGS', - \ 'COMPOUNDFLAG c'], 'XtestNOCOMPOUNDSUGS.aff') + \ 'COMPOUNDFLAG c'], 'XtestNOCOMPOUNDSUGS.aff', 'D') endif mkspell! XtestNOCOMPOUNDSUGS-utf8.spl XtestNOCOMPOUNDSUGS @@ -887,8 +986,6 @@ func Test_spellfile_NOCOMPOUNDSUGS() endfor set spell& spelllang& - call delete('XtestNOCOMPOUNDSUGS.dic') - call delete('XtestNOCOMPOUNDSUGS.aff') call delete('XtestNOCOMPOUNDSUGS-utf8.spl') endfunc @@ -901,8 +998,8 @@ func Test_spellfile_COMMON() \ 'any', \ 'tee', \ 'the', - \ 'ted'], 'XtestCOMMON.dic') - call writefile(['COMMON the and'], 'XtestCOMMON.aff') + \ 'ted'], 'XtestCOMMON.dic', 'D') + call writefile(['COMMON the and'], 'XtestCOMMON.aff', 'D') mkspell! XtestCOMMON-utf8.spl XtestCOMMON set spell spelllang=XtestCOMMON-utf8.spl @@ -914,15 +1011,13 @@ func Test_spellfile_COMMON() call assert_equal(['the', 'tee'], spellsuggest('dhe', 2)) set spell& spelllang& - call delete('XtestCOMMON.dic') - call delete('XtestCOMMON.aff') call delete('XtestCOMMON-utf8.spl') endfunc " Test NOSUGGEST (see :help spell-COMMON) func Test_spellfile_NOSUGGEST() - call writefile(['2', 'foo/X', 'fog'], 'XtestNOSUGGEST.dic') - call writefile(['NOSUGGEST X'], 'XtestNOSUGGEST.aff') + call writefile(['2', 'foo/X', 'fog'], 'XtestNOSUGGEST.dic', 'D') + call writefile(['NOSUGGEST X'], 'XtestNOSUGGEST.aff', 'D') mkspell! XtestNOSUGGEST-utf8.spl XtestNOSUGGEST set spell spelllang=XtestNOSUGGEST-utf8.spl @@ -940,8 +1035,6 @@ func Test_spellfile_NOSUGGEST() call assert_equal(['fog'], spellsuggest('fogg', 1)) set spell& spelllang& - call delete('XtestNOSUGGEST.dic') - call delete('XtestNOSUGGEST.aff') call delete('XtestNOSUGGEST-utf8.spl') endfunc @@ -950,7 +1043,7 @@ endfunc func Test_spellfile_CIRCUMFIX() " Example taken verbatim from https://github.com/hunspell/hunspell/tree/master/tests call writefile(['1', - \ 'nagy/C po:adj'], 'XtestCIRCUMFIX.dic') + \ 'nagy/C po:adj'], 'XtestCIRCUMFIX.dic', 'D') call writefile(['# circumfixes: ~ obligate prefix/suffix combinations', \ '# superlative in Hungarian: leg- (prefix) AND -bb (suffix)', \ '', @@ -965,7 +1058,7 @@ func Test_spellfile_CIRCUMFIX() \ 'SFX C Y 3', \ 'SFX C 0 obb . is:COMPARATIVE', \ 'SFX C 0 obb/AX . is:SUPERLATIVE', - \ 'SFX C 0 obb/BX . is:SUPERSUPERLATIVE'], 'XtestCIRCUMFIX.aff') + \ 'SFX C 0 obb/BX . is:SUPERSUPERLATIVE'], 'XtestCIRCUMFIX.aff', 'D') mkspell! XtestCIRCUMFIX-utf8.spl XtestCIRCUMFIX set spell spelllang=XtestCIRCUMFIX-utf8.spl @@ -984,8 +1077,6 @@ func Test_spellfile_CIRCUMFIX() endfor set spell& spelllang& - call delete('XtestCIRCUMFIX.dic') - call delete('XtestCIRCUMFIX.aff') call delete('XtestCIRCUMFIX-utf8.spl') endfunc @@ -997,12 +1088,12 @@ func Test_spellfile_SFX_strip() \ 'SFX A are hiamo [cg]are', \ 'SFX A re mo iare', \ 'SFX A re vamo are'], - \ 'XtestSFX.aff') + \ 'XtestSFX.aff', 'D') " Examples of Italian verbs: " - cantare = to sing " - cercare = to search " - odiare = to hate - call writefile(['3', 'cantare/A', 'cercare/A', 'odiare/A'], 'XtestSFX.dic') + call writefile(['3', 'cantare/A', 'cercare/A', 'odiare/A'], 'XtestSFX.dic', 'D') mkspell! XtestSFX-utf8.spl XtestSFX set spell spelllang=XtestSFX-utf8.spl @@ -1026,8 +1117,6 @@ func Test_spellfile_SFX_strip() call assert_equal(['odiamo'], spellsuggest('odiiamo', 1)) set spell& spelllang& - call delete('XtestSFX.dic') - call delete('XtestSFX.aff') call delete('XtestSFX-utf8.spl') endfunc @@ -1036,7 +1125,7 @@ endfunc func Test_init_spellfile() let save_rtp = &rtp let save_encoding = &encoding - call mkdir('Xrtp/spell', 'p') + call mkdir('Xrtp/spell', 'pR') call writefile(['vim'], 'Xrtp/spell/Xtest.dic') silent mkspell Xrtp/spell/Xtest.utf-8.spl Xrtp/spell/Xtest.dic set runtimepath=./Xrtp @@ -1046,8 +1135,8 @@ func Test_init_spellfile() call assert_equal('./Xrtp/spell/Xtest.utf-8.add', &spellfile) call assert_equal(['abc'], readfile('Xrtp/spell/Xtest.utf-8.add')) call assert_true(filereadable('Xrtp/spell/Xtest.utf-8.spl')) + set spell& spelllang& spellfile& - call delete('Xrtp', 'rf') let &encoding = save_encoding let &rtp = save_rtp %bw! @@ -1073,12 +1162,10 @@ endfunc " this was using a NULL pointer func Test_mkspell_empty_dic() - call writefile(['1'], 'XtestEmpty.dic') - call writefile(['SOFOFROM abcd', 'SOFOTO ABCD', 'SAL CIA X'], 'XtestEmpty.aff') + call writefile(['1'], 'XtestEmpty.dic', 'D') + call writefile(['SOFOFROM abcd', 'SOFOTO ABCD', 'SAL CIA X'], 'XtestEmpty.aff', 'D') mkspell! XtestEmpty.spl XtestEmpty - call delete('XtestEmpty.dic') - call delete('XtestEmpty.aff') call delete('XtestEmpty.spl') endfunc diff --git a/test/old/testdir/test_spellrare.vim b/test/old/testdir/test_spellrare.vim index bbb13c27c2..ceb35cbd17 100644 --- a/test/old/testdir/test_spellrare.vim +++ b/test/old/testdir/test_spellrare.vim @@ -11,15 +11,15 @@ func Test_spellrareword() " Create a small word list to test that spellbadword('...') " can return ['...', 'rare']. let lines =<< trim END - foo - foobar/? - foobara/? -END - call writefile(lines, 'Xwords', 'D') - - mkspell! Xwords.spl Xwords - set spelllang=Xwords.spl - call assert_equal(['foobar', 'rare'], spellbadword('foo foobar')) + foo + foobar/? + foobara/? + END + call writefile(lines, 'Xwords', 'D') + + mkspell! Xwords.spl Xwords + set spelllang=Xwords.spl + call assert_equal(['foobar', 'rare'], spellbadword('foo foobar')) new call setline(1, ['foo', '', 'foo bar foo bar foobara foo foo foo foobar', '', 'End']) diff --git a/test/old/testdir/test_startup.vim b/test/old/testdir/test_startup.vim index db9f0c4c13..ed4c4526f7 100644 --- a/test/old/testdir/test_startup.vim +++ b/test/old/testdir/test_startup.vim @@ -163,6 +163,7 @@ endfunc " horizontally or vertically. func Test_o_arg() let after =<< trim [CODE] + set cpo&vim call writefile([winnr("$"), \ winheight(1), winheight(2), &lines, \ winwidth(1), winwidth(2), &columns, @@ -1275,4 +1276,36 @@ func Test_write_in_vimrc() call delete('Xvimrc') endfunc +func Test_echo_true_in_cmd() + CheckNotGui + + let lines =<< trim END + echo v:true + call writefile(['done'], 'Xresult') + quit + END + call writefile(lines, 'Xscript') + if RunVim([], [], '--cmd "source Xscript"') + call assert_equal(['done'], readfile('Xresult')) + endif + call delete('Xscript') + call delete('Xresult') +endfunc + +func Test_rename_buffer_on_startup() + CheckUnix + + let lines =<< trim END + call writefile(['done'], 'Xresult') + qa! + END + call writefile(lines, 'Xscript') + if RunVim([], [], "--clean -e -s --cmd 'file x|new|file x' --cmd 'so Xscript'") + call assert_equal(['done'], readfile('Xresult')) + endif + call delete('Xscript') + call delete('Xresult') +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_startup_utf8.vim b/test/old/testdir/test_startup_utf8.vim index 1684d80c80..e8b99e7937 100644 --- a/test/old/testdir/test_startup_utf8.vim +++ b/test/old/testdir/test_startup_utf8.vim @@ -6,7 +6,7 @@ source screendump.vim func Test_read_stdin_utf8() let linesin = ['テスト', '€ÀÈÌÒÙ'] - call writefile(linesin, 'Xtestin') + call writefile(linesin, 'Xtestin', 'D') let before = [ \ 'set enc=utf-8', \ 'set fencs=cp932,utf-8', @@ -26,24 +26,22 @@ func Test_read_stdin_utf8() else call assert_equal('', 'RunVimPiped failed.') endif + call delete('Xtestout') - call delete('Xtestin') endfunc func Test_read_fifo_utf8() - if !has('unix') - return - endif + CheckUnix " Using bash/zsh's process substitution. if executable('bash') set shell=bash elseif executable('zsh') set shell=zsh else - return + throw 'Skipped: bash or zsh is required' endif let linesin = ['テスト', '€ÀÈÌÒÙ'] - call writefile(linesin, 'Xtestin') + call writefile(linesin, 'Xtestin', 'D') let before = [ \ 'set enc=utf-8', \ 'set fencs=cp932,utf-8', @@ -58,8 +56,8 @@ func Test_read_fifo_utf8() else call assert_equal('', 'RunVim failed.') endif + call delete('Xtestout') - call delete('Xtestin') endfunc func Test_detect_ambiwidth() @@ -71,12 +69,13 @@ func Test_detect_ambiwidth() \ 'set ambiwidth=double', \ 'call test_option_not_set("ambiwidth")', \ 'redraw', - \ ], 'Xscript') + \ ], 'Xscript', 'D') let buf = RunVimInTerminal('-S Xscript', #{keep_t_u7: 1}) call TermWait(buf) call term_sendkeys(buf, "S\<C-R>=&ambiwidth\<CR>\<Esc>") call WaitForAssert({-> assert_match('single', term_getline(buf, 1))}) call StopVimInTerminal(buf) - call delete('Xscript') endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_stat.vim b/test/old/testdir/test_stat.vim index 13ade5bee1..b9fd7f5f28 100644 --- a/test/old/testdir/test_stat.vim +++ b/test/old/testdir/test_stat.vim @@ -63,7 +63,7 @@ func Test_checktime() let fname = 'Xtest.tmp' let fl = ['Hello World!'] - call writefile(fl, fname) + call writefile(fl, fname, 'D') set autoread exec 'e' fname call SleepForTimestamp() @@ -72,8 +72,6 @@ func Test_checktime() call writefile(fl, fname) checktime call assert_equal(fl[0], getline(1)) - - call delete(fname) endfunc func Test_checktime_fast() @@ -82,7 +80,7 @@ func Test_checktime_fast() let fname = 'Xtest.tmp' let fl = ['Hello World!'] - call writefile(fl, fname) + call writefile(fl, fname, 'D') set autoread exec 'e' fname let fl = readfile(fname) @@ -91,8 +89,6 @@ func Test_checktime_fast() call writefile(fl, fname) checktime call assert_equal(fl[0], getline(1)) - - call delete(fname) endfunc func Test_autoread_fast() @@ -106,12 +102,10 @@ func Test_autoread_fast() call setline(1, 'foo') w! sleep 10m - call writefile(['bar'], 'Xautoread') + call writefile(['bar'], 'Xautoread', 'D') sleep 10m checktime call assert_equal('bar', trim(getline(1))) - - call delete('Xautoread') endfunc func Test_autoread_file_deleted() diff --git a/test/old/testdir/test_statusline.vim b/test/old/testdir/test_statusline.vim index c48bac12b4..c8162ced07 100644 --- a/test/old/testdir/test_statusline.vim +++ b/test/old/testdir/test_statusline.vim @@ -417,7 +417,7 @@ func Test_statusline() " Test statusline works with 80+ items function! StatusLabel() redrawstatus - return '[label]' + return '[label]' endfunc let statusline = '%{StatusLabel()}' for i in range(150) @@ -483,14 +483,13 @@ func Test_statusline_removed_group() set laststatus=2 let &statusline = '%#StatColorHi2#%(✓%#StatColorHi2#%) Q≡' END - call writefile(lines, 'XTest_statusline') + call writefile(lines, 'XTest_statusline', 'D') let buf = RunVimInTerminal('-S XTest_statusline', {'rows': 10, 'cols': 50}) call VerifyScreenDump(buf, 'Test_statusline_1', {}) " clean up call StopVimInTerminal(buf) - call delete('XTest_statusline') endfunc func Test_statusline_using_mode() @@ -501,7 +500,7 @@ func Test_statusline_using_mode() split setlocal statusline=+%{mode()}+ END - call writefile(lines, 'XTest_statusline') + call writefile(lines, 'XTest_statusline', 'D') let buf = RunVimInTerminal('-S XTest_statusline', {'rows': 7, 'cols': 50}) call VerifyScreenDump(buf, 'Test_statusline_mode_1', {}) @@ -512,7 +511,6 @@ func Test_statusline_using_mode() " clean up call term_sendkeys(buf, "close\<CR>") call StopVimInTerminal(buf) - call delete('XTest_statusline') endfunc func Test_statusline_after_split_vsplit() @@ -567,13 +565,12 @@ func Test_statusline_highlight_truncate() hi! link User2 ErrorMsg set statusline=%.5(%1*ABC%2*DEF%1*GHI%) END - call writefile(lines, 'XTest_statusline') + call writefile(lines, 'XTest_statusline', 'D') let buf = RunVimInTerminal('-S XTest_statusline', {'rows': 6}) call VerifyScreenDump(buf, 'Test_statusline_hl', {}) call StopVimInTerminal(buf) - call delete('XTest_statusline') endfunc func Test_statusline_showcmd() diff --git a/test/old/testdir/test_substitute.vim b/test/old/testdir/test_substitute.vim index fdb0f6fc37..90c46abe8b 100644 --- a/test/old/testdir/test_substitute.vim +++ b/test/old/testdir/test_substitute.vim @@ -743,7 +743,7 @@ func Test_sub_highlight_zero_match() endfunc func Test_nocatch_sub_failure_handling() - " normal error results in all replacements + " normal error results in all replacements func Foo() foobar endfunc @@ -806,7 +806,7 @@ func Test_replace_keeppatterns() a foobar -substitute foo asdf +substitute foo asdf foo one two . @@ -815,21 +815,26 @@ one two /^substitute s/foo/bar/ call assert_equal('foo', @/) - call assert_equal('substitute bar asdf', getline('.')) + call assert_equal('substitute bar asdf foo', getline('.')) /^substitute keeppatterns s/asdf/xyz/ call assert_equal('^substitute', @/) - call assert_equal('substitute bar xyz', getline('.')) + call assert_equal('substitute bar xyz foo', getline('.')) + + /^substitute + & + call assert_equal('^substitute', @/) + call assert_equal('substitute bar xyz bar', getline('.')) exe "normal /bar /e\<CR>" call assert_equal(15, col('.')) normal - keeppatterns /xyz call assert_equal('bar ', @/) - call assert_equal('substitute bar xyz', getline('.')) + call assert_equal('substitute bar xyz bar', getline('.')) exe "normal 0dn" - call assert_equal('xyz', getline('.')) + call assert_equal('xyz bar', getline('.')) close! endfunc @@ -892,7 +897,7 @@ func Test_sub_with_no_last_pat() call writefile(v:errors, 'Xresult') qall! [SCRIPT] - call writefile(lines, 'Xscript') + call writefile(lines, 'Xscript', 'D') if RunVim([], [], '--clean -S Xscript') call assert_equal([], readfile('Xresult')) endif @@ -909,7 +914,6 @@ func Test_sub_with_no_last_pat() " call assert_equal([], readfile('Xresult')) " endif - call delete('Xscript') call delete('Xresult') endfunc @@ -1110,13 +1114,12 @@ func Test_sub_open_cmdline_win() redir END qall! [SCRIPT] - call writefile(lines, 'Xscript') + call writefile(lines, 'Xscript', 'D') if RunVim([], [], '-u NONE -S Xscript') call assert_match('E565: Not allowed to change text or change window', \ readfile('Xresult')->join('XX')) endif - call delete('Xscript') call delete('Xresult') endfunc @@ -1509,4 +1512,18 @@ func Test_substitute_expr_recursive() exe bufnr .. "bw!" endfunc +" Test for changing 'cpo' in a substitute expression +func Test_substitute_expr_cpo() + func XSubExpr() + set cpo= + return 'x' + endfunc + + let save_cpo = &cpo + call assert_equal('xxx', substitute('abc', '.', '\=XSubExpr()', 'g')) + call assert_equal(save_cpo, &cpo) + + delfunc XSubExpr +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_swap.vim b/test/old/testdir/test_swap.vim index 65b6c57850..8a1b3ce133 100644 --- a/test/old/testdir/test_swap.vim +++ b/test/old/testdir/test_swap.vim @@ -10,14 +10,13 @@ endfunc " Tests for 'directory' option. func Test_swap_directory() - if !has("unix") - return - endif + CheckUnix + let content = ['start of testfile', \ 'line 2 Abcdefghij', \ 'line 3 Abcdefghij', \ 'end of testfile'] - call writefile(content, 'Xtest1') + call writefile(content, 'Xtest1', 'D') " '.', swap file in the same directory as file set dir=.,~ @@ -31,7 +30,7 @@ func Test_swap_directory() " './dir', swap file in a directory relative to the file set dir=./Xtest2,.,~ - call mkdir("Xtest2") + call mkdir("Xtest2", 'R') edit Xtest1 call assert_equal([], glob(swfname, 1, 1, 1)) let swfname = "Xtest2/Xtest1.swp" @@ -41,7 +40,7 @@ func Test_swap_directory() " 'dir', swap file in directory relative to the current dir set dir=Xtest.je,~ - call mkdir("Xtest.je") + call mkdir("Xtest.je", 'R') call writefile(content, 'Xtest2/Xtest3') edit Xtest2/Xtest3 call assert_equal(["Xtest2/Xtest3"], glob("Xtest2/*", 1, 1, 1)) @@ -50,15 +49,11 @@ func Test_swap_directory() call assert_equal([swfname], glob("Xtest.je/*", 1, 1, 1)) set dir& - call delete("Xtest1") - call delete("Xtest2", "rf") - call delete("Xtest.je", "rf") endfunc func Test_swap_group() - if !has("unix") - return - endif + CheckUnix + let groups = split(system('groups')) if len(groups) <= 1 throw 'Skipped: need at least two groups, got ' . string(groups) @@ -148,7 +143,7 @@ func Test_swapinfo() let info = swapinfo('doesnotexist') call assert_equal('Cannot open file', info.error) - call writefile(['burp'], 'Xnotaswapfile') + call writefile(['burp'], 'Xnotaswapfile', 'D') let info = swapinfo('Xnotaswapfile') call assert_equal('Cannot read file', info.error) call delete('Xnotaswapfile') @@ -156,7 +151,6 @@ func Test_swapinfo() call writefile([repeat('x', 10000)], 'Xnotaswapfile') let info = swapinfo('Xnotaswapfile') call assert_equal('Not a swap file', info.error) - call delete('Xnotaswapfile') endfunc func Test_swapname() @@ -204,7 +198,7 @@ func Test_swapfile_delete() " Close the file and recreate the swap file. " Now editing the file will run into the process still existing quit - call writefile(swapfile_bytes, swapfile_name) + call writefile(swapfile_bytes, swapfile_name, 'D') let s:swap_choice = 'e' let s:swapname = '' split XswapfileText @@ -232,7 +226,6 @@ func Test_swapfile_delete() call assert_equal(fnamemodify(swapfile_name, ':t'), fnamemodify(s:swapname, ':t')) call delete('XswapfileText') - call delete(swapfile_name) augroup test_swapfile_delete autocmd! augroup END @@ -246,7 +239,7 @@ func Test_swap_recover() autocmd SwapExists * let v:swapchoice = 'r' augroup END - call mkdir('Xswap') + call mkdir('Xswap', 'R') let $Xswap = 'foo' " Check for issue #4369. set dir=Xswap// " Create a valid swapfile by editing a file. @@ -259,7 +252,7 @@ func Test_swap_recover() " Close the file and recreate the swap file. quit - call writefile(swapfile_bytes, swapfile_name) + call writefile(swapfile_bytes, swapfile_name, 'D') " Edit the file again. This triggers recovery. try split Xswap/text @@ -271,9 +264,6 @@ func Test_swap_recover() call assert_equal(['one', 'two', 'three'], getline(1, 3)) quit! - call delete('Xswap/text') - call delete(swapfile_name) - call delete('Xswap', 'd') unlet $Xswap set dir& augroup test_swap_recover @@ -301,7 +291,7 @@ func Test_swap_recover_ext() " Close and delete the file and recreate the swap file. quit call delete('Xtest.scr') - call writefile(swapfile_bytes, swapfile_name) + call writefile(swapfile_bytes, swapfile_name, 'D') " Edit the file again. This triggers recovery. try split Xtest.scr @@ -314,7 +304,6 @@ func Test_swap_recover_ext() quit! call delete('Xtest.scr') - call delete(swapfile_name) augroup test_swap_recover_ext autocmd! augroup END @@ -342,7 +331,7 @@ func Test_swap_split_win() " Close and delete the file and recreate the swap file. quit call delete('Xtest.scr') - call writefile(swapfile_bytes, swapfile_name) + call writefile(swapfile_bytes, swapfile_name, 'D') " Split edit the file again. This should fail to open the window try split Xtest.scr @@ -353,7 +342,6 @@ func Test_swap_split_win() call assert_equal(1, winnr('$')) call delete('Xtest.scr') - call delete(swapfile_name) augroup test_swap_splitwin autocmd! @@ -365,7 +353,7 @@ endfunc func Test_swap_prompt_splitwin() CheckRunVimInTerminal - call writefile(['foo bar'], 'Xfile1') + call writefile(['foo bar'], 'Xfile1', 'D') edit Xfile1 preserve " should help to make sure the swap file exists @@ -400,13 +388,12 @@ func Test_swap_prompt_splitwin() call StopVimInTerminal(buf) %bwipe! - call delete('Xfile1') endfunc func Test_swap_symlink() CheckUnix - call writefile(['text'], 'Xtestfile') + call writefile(['text'], 'Xtestfile', 'D') silent !ln -s -f Xtestfile Xtestlink set dir=. @@ -417,18 +404,16 @@ func Test_swap_symlink() call assert_match('Xtestfile\.swp$', s:swapname()) bwipe! - call mkdir('Xswapdir') + call mkdir('Xswapdir', 'R') exe 'set dir=' . getcwd() . '/Xswapdir//' " Check that this also works when 'directory' ends with '//' edit Xtestlink - call assert_match('Xtestfile\.swp$', s:swapname()) + call assert_match('Xswapdir[/\\]%.*testdir%Xtestfile\.swp$', s:swapname()) bwipe! set dir& - call delete('Xtestfile') call delete('Xtestlink') - call delete('Xswapdir', 'rf') endfunc func s:get_unused_pid(base) @@ -486,7 +471,7 @@ func Test_swap_auto_delete() " Change the process ID to avoid the "still running" warning. let swapfile_bytes[24:27] = s:pid_to_blob(s:get_unused_pid( \ s:blob_to_pid(swapfile_bytes[24:27]))) - call writefile(swapfile_bytes, swapfile_name) + call writefile(swapfile_bytes, swapfile_name, 'D') edit Xtest.scr " will end up using the same swap file after deleting the existing one call assert_equal(swapfile_name, swapname('%')) @@ -510,7 +495,6 @@ func Test_swap_auto_delete() bwipe! call delete('Xtest.scr') - call delete(swapfile_name) augroup test_swap_recover_ext autocmd! augroup END @@ -539,13 +523,13 @@ endfunc " Test for the v:swapchoice variable func Test_swapchoice() - call writefile(['aaa', 'bbb'], 'Xfile5') + call writefile(['aaa', 'bbb'], 'Xfile5', 'D') edit Xfile5 preserve let swapfname = swapname('') let b = readblob(swapfname) bw! - call writefile(b, swapfname) + call writefile(b, swapfname, 'D') autocmd! SwapExists @@ -584,7 +568,6 @@ func Test_swapchoice() %bw! call assert_false(filereadable(swapfname)) - call delete('Xfile5') call delete(swapfname) augroup test_swapchoice autocmd! diff --git a/test/old/testdir/test_syntax.vim b/test/old/testdir/test_syntax.vim index 35523df17d..207efb6223 100644 --- a/test/old/testdir/test_syntax.vim +++ b/test/old/testdir/test_syntax.vim @@ -549,8 +549,7 @@ endfunc func Test_bg_detection() CheckNotGui - " auto-detection of &bg, make sure sure it isn't set anywhere before - " this test + " auto-detection of &bg, make sure it isn't set anywhere before this test hi Normal ctermbg=0 call assert_equal('dark', &bg) hi Normal ctermbg=4 @@ -645,15 +644,16 @@ func Test_syntax_c() \ ' printf("Just an example piece of C code\n");', \ ' return 0x0ff;', \ '}', + \ "\t\t ", \ ' static void', \ 'myFunction(const double count, struct nothing, long there) {', - \ ' // 123: nothing to read here', - \ ' for (int i = 0; i < count; ++i) {', - \ ' break;', - \ ' }', - \ " Note: asdf", + \ "\t// 123: nothing to endif here", + \ "\tfor (int i = 0; i < count; ++i) {", + \ "\t break;", + \ "\t}", + \ "\tNote: asdf", \ '}', - \ ], 'Xtest.c') + \ ], 'Xtest.c', 'D') " This makes the default for 'background' use "dark", check that the " response to t_RB corrects it to "light". @@ -665,7 +665,6 @@ func Test_syntax_c() call StopVimInTerminal(buf) let $COLORFGBG = '' - call delete('Xtest.c') endfun " Test \z(...) along with \z1 @@ -699,10 +698,10 @@ func Test_syn_wrong_z_one() endfunc func Test_syntax_after_bufdo() - call writefile(['/* aaa comment */'], 'Xaaa.c') - call writefile(['/* bbb comment */'], 'Xbbb.c') - call writefile(['/* ccc comment */'], 'Xccc.c') - call writefile(['/* ddd comment */'], 'Xddd.c') + call writefile(['/* aaa comment */'], 'Xaaa.c', 'D') + call writefile(['/* bbb comment */'], 'Xbbb.c', 'D') + call writefile(['/* ccc comment */'], 'Xccc.c', 'D') + call writefile(['/* ddd comment */'], 'Xddd.c', 'D') let bnr = bufnr('%') new Xaaa.c @@ -730,10 +729,6 @@ func Test_syntax_after_bufdo() bwipe! Xccc.c bwipe! Xddd.c syntax off - call delete('Xaaa.c') - call delete('Xbbb.c') - call delete('Xccc.c') - call delete('Xddd.c') endfunc func Test_syntax_foldlevel() diff --git a/test/old/testdir/test_system.vim b/test/old/testdir/test_system.vim index 6c8373b335..30fab6d55f 100644 --- a/test/old/testdir/test_system.vim +++ b/test/old/testdir/test_system.vim @@ -53,7 +53,7 @@ func Test_system_exmode() let cmd = ' -es -c "source Xscript" +q; echo "result=$?"' " Need to put this in a script, "catch" isn't found after an unknown " function. - call writefile(['try', 'call doesnotexist()', 'catch', 'endtry'], 'Xscript') + call writefile(['try', 'call doesnotexist()', 'catch', 'endtry'], 'Xscript', 'D') let a = system(GetVimCommand() . cmd) call assert_match('result=0', a) call assert_equal(0, v:shell_error) @@ -69,7 +69,6 @@ func Test_system_exmode() let cmd = ' -es -c "source Xscript" +q' let a = system(GetVimCommand() . cmd) call assert_notequal(0, v:shell_error) - call delete('Xscript') if has('unix') " echo $? only works on Unix let cmd = ' -es -c "call doesnotexist()" +q; echo $?' diff --git a/test/old/testdir/test_tabpage.vim b/test/old/testdir/test_tabpage.vim index 2bd2907a55..482da2de7f 100644 --- a/test/old/testdir/test_tabpage.vim +++ b/test/old/testdir/test_tabpage.vim @@ -967,6 +967,64 @@ func Test_tabpage_alloc_failure() call assert_equal(1, tabpagenr('$')) endfunc +func Test_tabpage_tabclose() + " Default behaviour, move to the right. + call s:reconstruct_tabpage_for_test(6) + norm! 4gt + setl tcl= + tabclose + call assert_equal("n3", bufname()) + + " Move to the left. + call s:reconstruct_tabpage_for_test(6) + norm! 4gt + setl tcl=left + tabclose + call assert_equal("n1", bufname()) + + " Move to the last used tab page. + call s:reconstruct_tabpage_for_test(6) + norm! 5gt + norm! 2gt + setl tcl=uselast + tabclose + call assert_equal("n3", bufname()) + + " Same, but the last used tab page is invalid. Move to the right. + call s:reconstruct_tabpage_for_test(6) + norm! 5gt + norm! 3gt + setl tcl=uselast + tabclose 5 + tabclose! + call assert_equal("n2", bufname()) + + " Same, but the last used tab page is invalid. Move to the left. + call s:reconstruct_tabpage_for_test(6) + norm! 5gt + norm! 3gt + setl tcl=uselast,left + tabclose 5 + tabclose! + call assert_equal("n0", bufname()) + + " Move left when moving right is not possible. + call s:reconstruct_tabpage_for_test(6) + setl tcl= + norm! 6gt + tabclose + call assert_equal("n3", bufname()) + + " Move right when moving left is not possible. + call s:reconstruct_tabpage_for_test(6) + setl tcl=left + norm! 1gt + tabclose + call assert_equal("n0", bufname()) + + setl tcl& +endfunc + " this was giving ml_get errors func Test_tabpage_last_line() enew diff --git a/test/old/testdir/test_tagfunc.vim b/test/old/testdir/test_tagfunc.vim index 44916f2fc9..812603a430 100644 --- a/test/old/testdir/test_tagfunc.vim +++ b/test/old/testdir/test_tagfunc.vim @@ -89,11 +89,11 @@ func Test_tagfunc() return v:null endfunc set tags= tfu=NullTagFunc - call assert_fails('tag nothing', 'E433') + call assert_fails('tag nothing', 'E433:') delf NullTagFunc bwipe! - set tags& tfu& cpt& + set tags& tfu& cpt& call delete('Xfile1') endfunc diff --git a/test/old/testdir/test_tagjump.vim b/test/old/testdir/test_tagjump.vim index a614c19ce2..470c5c43b4 100644 --- a/test/old/testdir/test_tagjump.vim +++ b/test/old/testdir/test_tagjump.vim @@ -777,7 +777,7 @@ func Test_tag_guess() let code =<< trim [CODE] int FUNC1 (int x) { } - int + int func2 (int y) { } int * func3 () { } @@ -1001,8 +1001,63 @@ func Test_tag_stack() call settagstack(1, {'items' : []}) call assert_fails('pop', 'E73:') + " References to wiped buffer are deleted. + for i in range(10, 20) + edit Xtest + exe "tag var" .. i + endfor + edit Xtest + + let t = gettagstack() + call assert_equal(11, t.length) + call assert_equal(12, t.curidx) + + bwipe! + + let t = gettagstack() + call assert_equal(0, t.length) + call assert_equal(1, t.curidx) + + " References to wiped buffer are deleted with multiple tabpages. + let w1 = win_getid() + call settagstack(1, {'items' : []}) + for i in range(10, 20) | edit Xtest | exe "tag var" .. i | endfor + enew + + new + let w2 = win_getid() + call settagstack(1, {'items' : []}) + for i in range(10, 20) | edit Xtest | exe "tag var" .. i | endfor + enew + + tabnew + let w3 = win_getid() + call settagstack(1, {'items' : []}) + for i in range(10, 20) | edit Xtest | exe "tag var" .. i | endfor + enew + + new + let w4 = win_getid() + call settagstack(1, {'items' : []}) + for i in range(10, 20) | edit Xtest | exe "tag var" .. i | endfor + enew + + for w in [w1, w2, w3, w4] + let t = gettagstack(w) + call assert_equal(11, t.length) + call assert_equal(12, t.curidx) + endfor + + bwipe! Xtest + + for w in [w1, w2, w3, w4] + let t = gettagstack(w) + call assert_equal(0, t.length) + call assert_equal(1, t.curidx) + endfor + + %bwipe! set tags& - %bwipe endfunc " Test for browsing multiple matching tags diff --git a/test/old/testdir/test_taglist.vim b/test/old/testdir/test_taglist.vim index 75d28c3ec4..fbb682a9b2 100644 --- a/test/old/testdir/test_taglist.vim +++ b/test/old/testdir/test_taglist.vim @@ -135,6 +135,47 @@ func Test_tagsfile_without_trailing_newline() set tags& endfunc +" Check that specifying a stop directory in 'tags' works properly. +func Test_tagfiles_stopdir() + let save_cwd = getcwd() + + call mkdir('Xtagsdir1/Xtagsdir2/Xtagsdir3', 'pR') + call writefile([], 'Xtagsdir1/Xtags', 'D') + + cd Xtagsdir1/ + let &tags = './Xtags;' .. fnamemodify('..', ':p') + call assert_equal(1, len(tagfiles())) + + cd Xtagsdir2/ + let &tags = './Xtags;' .. fnamemodify('..', ':p') + call assert_equal(1, len(tagfiles())) + + cd Xtagsdir3/ + let &tags = './Xtags;' .. fnamemodify('..', ':p') + call assert_equal(0, len(tagfiles())) + + let &tags = './Xtags;../' + call assert_equal(0, len(tagfiles())) + + cd .. + call assert_equal(1, len(tagfiles())) + + cd .. + call assert_equal(1, len(tagfiles())) + + let &tags = './Xtags;..' + call assert_equal(1, len(tagfiles())) + + cd Xtagsdir2/ + call assert_equal(1, len(tagfiles())) + + cd Xtagsdir3/ + call assert_equal(0, len(tagfiles())) + + set tags& + call chdir(save_cwd) +endfunc + " Test for ignoring comments in a tags file func Test_tagfile_ignore_comments() call writefile([ diff --git a/test/old/testdir/test_termdebug.vim b/test/old/testdir/test_termdebug.vim index fd0c850577..eb88ea6f5f 100644 --- a/test/old/testdir/test_termdebug.vim +++ b/test/old/testdir/test_termdebug.vim @@ -124,13 +124,13 @@ func Test_termdebug_basic() " 60 is approx spaceBuffer * 3 if winwidth(0) <= 78 + 60 Var - call assert_equal(winnr(), winnr('$')) - call assert_equal(winlayout(), ['col', [['leaf', 1002], ['leaf', 1001], ['leaf', 1000], ['leaf', 1003 + cn]]]) + call assert_equal(winnr('$'), winnr()) + call assert_equal(['col', [['leaf', 1002], ['leaf', 1001], ['leaf', 1000], ['leaf', 1003 + cn]]], winlayout()) let cn += 1 bw! Asm - call assert_equal(winnr(), winnr('$')) - call assert_equal(winlayout(), ['col', [['leaf', 1002], ['leaf', 1001], ['leaf', 1000], ['leaf', 1003 + cn]]]) + call assert_equal(winnr('$'), winnr()) + call assert_equal(['col', [['leaf', 1002], ['leaf', 1001], ['leaf', 1000], ['leaf', 1003 + cn]]], winlayout()) let cn += 1 bw! endif @@ -139,16 +139,16 @@ func Test_termdebug_basic() let winw = winwidth(0) Var if winwidth(0) < winw - call assert_equal(winnr(), winnr('$') - 1) - call assert_equal(winlayout(), ['col', [['leaf', 1002], ['leaf', 1001], ['row', [['leaf', 1003 + cn], ['leaf', 1000]]]]]) + call assert_equal(winnr('$') - 1, winnr()) + call assert_equal(['col', [['leaf', 1002], ['leaf', 1001], ['row', [['leaf', 1003 + cn], ['leaf', 1000]]]]], winlayout()) let cn += 1 bw! endif let winw = winwidth(0) Asm if winwidth(0) < winw - call assert_equal(winnr(), winnr('$') - 1) - call assert_equal(winlayout(), ['col', [['leaf', 1002], ['leaf', 1001], ['row', [['leaf', 1003 + cn], ['leaf', 1000]]]]]) + call assert_equal(winnr('$') - 1, winnr()) + call assert_equal(['col', [['leaf', 1002], ['leaf', 1001], ['row', [['leaf', 1003 + cn], ['leaf', 1000]]]]], winlayout()) let cn += 1 bw! endif @@ -161,6 +161,18 @@ func Test_termdebug_basic() call WaitForAssert({-> assert_equal(1, winnr('$'))}) call assert_equal([], sign_getplaced('', #{group: 'TermDebug'})[0].signs) + for use_prompt in [0, 1] + let g:termdebug_config = {} + let g:termdebug_config['use_prompt'] = use_prompt + TermdebugCommand ./XTD_basic arg args + call WaitForAssert({-> assert_equal(3, winnr('$'))}) + wincmd t + quit! + redraw! + call WaitForAssert({-> assert_equal(1, winnr('$'))}) + unlet g:termdebug_config + endfor + call s:cleanup_files(bin_name) %bw! endfunc @@ -280,9 +292,20 @@ func Test_termdebug_mapping() call assert_equal(':echom "K"<cr>', maparg('K', 'n', 0, 1).rhs) %bw! + + " -- Test that local-buffer mappings are restored in the correct buffers -- + " local mappings for foo + file foo nnoremap <buffer> K :echom "bK"<cr> nnoremap <buffer> - :echom "b-"<cr> nnoremap <buffer> + :echom "b+"<cr> + + " no mappings for 'bar' + enew + file bar + + " Start termdebug from foo + buffer foo Termdebug call WaitForAssert({-> assert_equal(3, winnr('$'))}) wincmd b @@ -290,15 +313,41 @@ func Test_termdebug_mapping() call assert_true(maparg('-', 'n', 0, 1).buffer) call assert_true(maparg('+', 'n', 0, 1).buffer) call assert_equal(maparg('K', 'n', 0, 1).rhs, ':echom "bK"<cr>') + + Source + buffer bar + call assert_false(maparg('K', 'n', 0, 1)->empty()) + call assert_false(maparg('-', 'n', 0, 1)->empty()) + call assert_false(maparg('+', 'n', 0, 1)->empty()) + call assert_true(maparg('K', 'n', 0, 1).buffer->empty()) + call assert_true(maparg('-', 'n', 0, 1).buffer->empty()) + call assert_true(maparg('+', 'n', 0, 1).buffer->empty()) wincmd t quit! redraw! call WaitForAssert({-> assert_equal(1, winnr('$'))}) + + " Termdebug session ended. Buffer 'bar' shall have no mappings + call assert_true(bufname() ==# 'bar') + call assert_false(maparg('K', 'n', 0, 1)->empty()) + call assert_false(maparg('-', 'n', 0, 1)->empty()) + call assert_false(maparg('+', 'n', 0, 1)->empty()) + call assert_true(maparg('K', 'n', 0, 1).buffer->empty()) + call assert_true(maparg('-', 'n', 0, 1).buffer->empty()) + call assert_true(maparg('+', 'n', 0, 1).buffer->empty()) + + " Buffer 'foo' shall have the same mapping as before running the termdebug + " session + buffer foo + call assert_true(bufname() ==# 'foo') call assert_true(maparg('K', 'n', 0, 1).buffer) call assert_true(maparg('-', 'n', 0, 1).buffer) call assert_true(maparg('+', 'n', 0, 1).buffer) call assert_equal(':echom "bK"<cr>', maparg('K', 'n', 0, 1).rhs) + nunmap K + nunmap + + nunmap - %bw! endfunc @@ -340,5 +389,43 @@ func Test_termdebug_bufnames() unlet g:termdebug_config endfunc +function Test_termdebug_save_restore_variables() + " saved mousemodel + let &mousemodel='' + + " saved keys + nnoremap K :echo "hello world!"<cr> + let expected_map_K = maparg('K', 'n', 0 , 1) + nnoremap + :echo "hello plus!"<cr> + let expected_map_plus = maparg('+', 'n', 0 , 1) + let expected_map_minus = {} + + " saved &columns + let expected_columns = &columns + + " We want termdebug to overwrite 'K' map but not '+' map. + let g:termdebug_config = {} + let g:termdebug_config['map_K'] = 1 + + Termdebug + call WaitForAssert({-> assert_equal(3, winnr('$'))}) + call WaitForAssert({-> assert_match(&mousemodel, 'popup_setpos')}) + wincmd t + quit! + call WaitForAssert({-> assert_equal(1, winnr('$'))}) + + call assert_true(empty(&mousemodel)) + + call assert_true(empty(expected_map_minus)) + call assert_equal(expected_map_K.rhs, maparg('K', 'n', 0, 1).rhs) + call assert_equal(expected_map_plus.rhs, maparg('+', 'n', 0, 1).rhs) + + call assert_equal(expected_columns, &columns) + + nunmap K + nunmap + + unlet g:termdebug_config +endfunction + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_textobjects.vim b/test/old/testdir/test_textobjects.vim index 3b86ae97da..0f41f0a241 100644 --- a/test/old/testdir/test_textobjects.vim +++ b/test/old/testdir/test_textobjects.vim @@ -203,6 +203,18 @@ func Test_string_html_objects() normal! 2k0vaty call assert_equal("<div><div\nattr=\"attr\"\n></div></div>", @", e) + " tag, that includes a > in some attribute + let t = "<div attr=\"attr >> foo >> bar \">Hello</div>" + $put =t + normal! fHyit + call assert_equal("Hello", @", e) + + " tag, that includes a > in some attribute + let t = "<div attr='attr >> foo >> bar '>Hello 123</div>" + $put =t + normal! fHyit + call assert_equal("Hello 123", @", e) + set quoteescape& " this was going beyond the end of the line @@ -232,7 +244,7 @@ func Test_empty_html_tag() normal 0f<vitsaaa call assert_equal('aaa', getline(1)) - " selecting a tag block in an non-empty blank line should fail + " selecting a tag block in a non-empty blank line should fail call setline(1, ' ') call assert_beeps('normal $vaty') diff --git a/test/old/testdir/test_timers.vim b/test/old/testdir/test_timers.vim index 42114618fb..f412afc03d 100644 --- a/test/old/testdir/test_timers.vim +++ b/test/old/testdir/test_timers.vim @@ -348,8 +348,15 @@ endfunc " Test that the garbage collector isn't triggered if a timer callback invokes " vgetc(). func Test_nocatch_timer_garbage_collect() - " skipped: Nvim does not support test_garbagecollect_soon(), test_override() - return + " FIXME: why does this fail only on MacOS M1? + try + CheckNotMacM1 + throw 'Skipped: Nvim does not support test_garbagecollect_soon(), test_override()' + catch /Skipped/ + let g:skipped_reason = v:exception + return + endtry + " 'uptimetime. must be bigger than the timer timeout set ut=200 call test_garbagecollect_soon() diff --git a/test/old/testdir/test_true_false.vim b/test/old/testdir/test_true_false.vim index f3c7fff4a6..976a40e153 100644 --- a/test/old/testdir/test_true_false.vim +++ b/test/old/testdir/test_true_false.vim @@ -49,11 +49,11 @@ func Test_if() endfunc function Try_arg_true_false(expr, false_val, true_val) - for v in ['v:false', '0', '"0"', '"foo"', '" "'] + for v in ['v:false', '0', '"0"', '"foo"', '" "'] let r = eval(substitute(a:expr, '%v%', v, '')) call assert_equal(a:false_val, r, 'result for ' . v . ' is not ' . string(a:false_val) . ' but ' . string(r)) endfor - for v in ['v:true', '1', '"1"', '"1foo"'] + for v in ['v:true', '1', '"1"', '"1foo"'] let r = eval(substitute(a:expr, '%v%', v, '')) call assert_equal(a:true_val, r, 'result for ' . v . ' is not ' . string(a:true_val) . ' but ' . string(r)) endfor @@ -117,12 +117,11 @@ func Test_true_false_arg() endfunc function Try_arg_non_zero(expr, false_val, true_val) - CheckFeature float - for v in ['v:false', '0', '[1]', '{2:3}', '3.4'] + for v in ['v:false', '0', '[1]', '{2:3}', '3.4'] let r = eval(substitute(a:expr, '%v%', v, '')) call assert_equal(a:false_val, r, 'result for ' . v . ' is not ' . a:false_val . ' but ' . r) endfor - for v in ['v:true', '1', '" "', '"0"'] + for v in ['v:true', '1', '" "', '"0"'] let r = eval(substitute(a:expr, '%v%', v, '')) call assert_equal(a:true_val, r, 'result for ' . v . ' is not ' . a:true_val . ' but ' . r) endfor @@ -138,14 +137,14 @@ func Test_non_zero_arg() call Try_arg_non_zero("shellescape('foo%', %v%)", "'foo%'", "'foo\\%'") " visualmode() needs to be called twice to check - for v in [v:false, 0, [1], {2:3}, 3.4] + for v in [v:false, 0, [1], {2:3}, 3.4] normal vv let r = visualmode(v) call assert_equal('v', r, 'result for ' . string(v) . ' is not "v" but ' . r) let r = visualmode(v) call assert_equal('v', r, 'result for ' . string(v) . ' is not "v" but ' . r) endfor - for v in [v:true, 1, " ", "0"] + for v in [v:true, 1, " ", "0"] normal vv let r = visualmode(v) call assert_equal('v', r, 'result for ' . v . ' is not "v" but ' . r) diff --git a/test/old/testdir/test_trycatch.vim b/test/old/testdir/test_trycatch.vim index d60b793f1b..f2142f4210 100644 --- a/test/old/testdir/test_trycatch.vim +++ b/test/old/testdir/test_trycatch.vim @@ -50,7 +50,7 @@ func T25_F() Xpath 'i' endfunc -" Also try using "fina" and "final" and "finall" as abbraviations. +" Also try using "fina" and "final" and "finall" as abbreviations. func T25_G() if 1 try diff --git a/test/old/testdir/test_utf8.vim b/test/old/testdir/test_utf8.vim index 51ac47f082..5cac4066ea 100644 --- a/test/old/testdir/test_utf8.vim +++ b/test/old/testdir/test_utf8.vim @@ -1,5 +1,5 @@ " Tests for Unicode manipulations - + source check.vim source view_util.vim source screendump.vim @@ -112,7 +112,7 @@ func Test_list2str_str2list_latin1() let save_encoding = &encoding " set encoding=latin1 - + let lres = str2list(s, 1) let sres = list2str(l, 1) call assert_equal([65, 66, 67], str2list("ABC")) @@ -228,6 +228,9 @@ func Test_setcellwidths() call setcellwidths([[0x2103, 0x2103, 2]]) redraw call assert_equal(19, wincol()) + call setcellwidths([]) + redraw + call assert_equal((aw == 'single') ? 10 : 19, wincol()) endfor set ambiwidth& isprint& @@ -252,15 +255,21 @@ func Test_setcellwidths() call assert_fails('call setcellwidths([[0x33, 0x44, 2]])', 'E1114:') - set listchars=tab:--\\u2192 + set listchars=tab:--\\u2192 fillchars=stl:\\u2501 call assert_fails('call setcellwidths([[0x2192, 0x2192, 2]])', 'E834:') - - set fillchars=stl:\\u2501 call assert_fails('call setcellwidths([[0x2501, 0x2501, 2]])', 'E835:') + call setcellwidths([[0x201c, 0x201d, 1]]) + set listchars& fillchars& ambiwidth=double + + set listchars=nbsp:\\u201c fillchars=vert:\\u201d + call assert_fails('call setcellwidths([])', 'E834:') set listchars& + call assert_fails('call setcellwidths([])', 'E835:') set fillchars& + call setcellwidths([]) + set ambiwidth& bwipe! endfunc diff --git a/test/old/testdir/test_vartabs.vim b/test/old/testdir/test_vartabs.vim index e12c71d521..82c3a513f9 100644 --- a/test/old/testdir/test_vartabs.vim +++ b/test/old/testdir/test_vartabs.vim @@ -445,4 +445,77 @@ func Test_shiftwidth_vartabstop() setlocal shiftwidth& vartabstop& tabstop& endfunc +func Test_vartabstop_latin1() + throw "Skipped: Nvim does not support 'compatible'" + let save_encoding = &encoding + new + set encoding=iso8859-1 + set compatible linebreak list revins smarttab + set vartabstop=400 + exe "norm i00\t\<C-D>" + bwipe! + let &encoding = save_encoding + set nocompatible linebreak& list& revins& smarttab& vartabstop& +endfunc + +" Verify that right-shifting and left-shifting adjust lines to the proper +" tabstops. +func Test_vartabstop_shift_right_left() + new + set expandtab + set shiftwidth=0 + set vartabstop=17,11,7 + exe "norm! aword" + let expect = "word" + call assert_equal(expect, getline(1)) + + " Shift to first tabstop. + norm! >> + let expect = " word" + call assert_equal(expect, getline(1)) + + " Shift to second tabstop. + norm! >> + let expect = " word" + call assert_equal(expect, getline(1)) + + " Shift to third tabstop. + norm! >> + let expect = " word" + call assert_equal(expect, getline(1)) + + " Shift to fourth tabstop, repeating the third shift width. + norm! >> + let expect = " word" + call assert_equal(expect, getline(1)) + + " Shift back to the third tabstop. + norm! << + let expect = " word" + call assert_equal(expect, getline(1)) + + " Shift back to the second tabstop. + norm! << + let expect = " word" + call assert_equal(expect, getline(1)) + + " Shift back to the first tabstop. + norm! << + let expect = " word" + call assert_equal(expect, getline(1)) + + " Shift back to the left margin. + norm! << + let expect = "word" + call assert_equal(expect, getline(1)) + + " Shift again back to the left margin. + norm! << + let expect = "word" + call assert_equal(expect, getline(1)) + + bwipeout! +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_vimscript.vim b/test/old/testdir/test_vimscript.vim index 6ce59e1a2e..7f29c7f651 100644 --- a/test/old/testdir/test_vimscript.vim +++ b/test/old/testdir/test_vimscript.vim @@ -6502,16 +6502,22 @@ func Test_type() call assert_equal(2, type(function("tr", [8]))) call assert_equal(3, type([])) call assert_equal(4, type({})) - call assert_equal(5, type(0.0)) + if has('float') + call assert_equal(5, type(0.0)) + endif call assert_equal(6, type(v:false)) call assert_equal(6, type(v:true)) + " call assert_equal(7, type(v:none)) call assert_equal(7, type(v:null)) call assert_equal(v:t_number, type(0)) call assert_equal(v:t_string, type("")) call assert_equal(v:t_func, type(function("tr"))) + call assert_equal(v:t_func, type(function("tr", [8]))) call assert_equal(v:t_list, type([])) call assert_equal(v:t_dict, type({})) - call assert_equal(v:t_float, type(0.0)) + if has('float') + call assert_equal(v:t_float, type(0.0)) + endif call assert_equal(v:t_bool, type(v:false)) call assert_equal(v:t_bool, type(v:true)) " call assert_equal(v:t_none, type(v:none)) @@ -6829,10 +6835,12 @@ func Test_bitwise_functions() call assert_equal(16, and(127, 16)) eval 127->and(16)->assert_equal(16) call assert_equal(0, and(127, 128)) - call assert_fails("call and(1.0, 1)", 'E805:') call assert_fails("call and([], 1)", 'E745:') call assert_fails("call and({}, 1)", 'E728:') - call assert_fails("call and(1, 1.0)", 'E805:') + if has('float') + call assert_fails("call and(1.0, 1)", 'E805:') + call assert_fails("call and(1, 1.0)", 'E805:') + endif call assert_fails("call and(1, [])", 'E745:') call assert_fails("call and(1, {})", 'E728:') " or @@ -6840,10 +6848,12 @@ func Test_bitwise_functions() call assert_equal(15, or(8, 7)) eval 8->or(7)->assert_equal(15) call assert_equal(123, or(0, 123)) - call assert_fails("call or(1.0, 1)", 'E805:') call assert_fails("call or([], 1)", 'E745:') call assert_fails("call or({}, 1)", 'E728:') - call assert_fails("call or(1, 1.0)", 'E805:') + if has('float') + call assert_fails("call or(1.0, 1)", 'E805:') + call assert_fails("call or(1, 1.0)", 'E805:') + endif call assert_fails("call or(1, [])", 'E745:') call assert_fails("call or(1, {})", 'E728:') " xor @@ -6851,10 +6861,12 @@ func Test_bitwise_functions() call assert_equal(111, xor(127, 16)) eval 127->xor(16)->assert_equal(111) call assert_equal(255, xor(127, 128)) - call assert_fails("call xor(1.0, 1)", 'E805:') + if has('float') + call assert_fails("call xor(1.0, 1)", 'E805:') + call assert_fails("call xor(1, 1.0)", 'E805:') + endif call assert_fails("call xor([], 1)", 'E745:') call assert_fails("call xor({}, 1)", 'E728:') - call assert_fails("call xor(1, 1.0)", 'E805:') call assert_fails("call xor(1, [])", 'E745:') call assert_fails("call xor(1, {})", 'E728:') " invert @@ -6862,7 +6874,9 @@ func Test_bitwise_functions() eval 127->invert()->and(65535)->assert_equal(65408) call assert_equal(65519, and(invert(16), 65535)) call assert_equal(65407, and(invert(128), 65535)) - call assert_fails("call invert(1.0)", 'E805:') + if has('float') + call assert_fails("call invert(1.0)", 'E805:') + endif call assert_fails("call invert([])", 'E745:') call assert_fails("call invert({})", 'E728:') endfunc @@ -7435,6 +7449,57 @@ func Test_for_over_string() let res ..= c .. '-' endfor call assert_equal('', res) + + " Test for using "_" as the loop variable + let i = 0 + let s = 'abc' + for _ in s + call assert_equal(s[i], _) + let i += 1 + endfor +endfunc + +" Test for deeply nested :source command {{{1 +func Test_deeply_nested_source() + throw 'Skipped: Vim9 script is N/A' + let lines =<< trim END + + so + sil 0scr + delete + so + 0 + END + call writefile(["vim9 silent! @0 \n/"] + lines, 'Xnested.vim', 'D') + + " this must not crash + let cmd = GetVimCommand() .. " -e -s -S Xnested.vim -c qa!" + call system(cmd) +endfunc + +func Test_exception_silent() + XpathINIT + let lines =<< trim END + func Throw() + Xpath 'a' + throw "Uncaught" + " This line is not executed. + Xpath 'b' + endfunc + " The exception is suppressed due to the presence of silent!. + silent! call Throw() + try + call DoesNotExist() + catch /E117:/ + Xpath 'c' + endtry + Xpath 'd' + END + let verify =<< trim END + call assert_equal('acd', g:Xpath) + END + + call RunInNewVim(lines, verify) endfunc "------------------------------------------------------------------------------- diff --git a/test/old/testdir/test_virtualedit.vim b/test/old/testdir/test_virtualedit.vim index 8d9656e058..900dcd41cc 100644 --- a/test/old/testdir/test_virtualedit.vim +++ b/test/old/testdir/test_virtualedit.vim @@ -696,14 +696,14 @@ func Test_virtualedit_mouse() set virtualedit& endfunc -" this was replacing the NUL at the end of the line +" this was replacing the NUL at the end of the line func Test_virtualedit_replace_after_tab() new s/\v/ 0 set ve=all let @" = '' sil! norm vPvr0 - + call assert_equal("\t0", getline(1)) set ve& bwipe! diff --git a/test/old/testdir/test_visual.vim b/test/old/testdir/test_visual.vim index b7b5f611c4..e25327ddd4 100644 --- a/test/old/testdir/test_visual.vim +++ b/test/old/testdir/test_visual.vim @@ -1170,8 +1170,8 @@ endfunc func Test_visual_put_in_block_using_zp() new " paste using zP - call setline(1, ['/path;text', '/path;text', '/path;text', '', - \ '/subdir', + call setline(1, ['/path;text', '/path;text', '/path;text', '', + \ '/subdir', \ '/longsubdir', \ '/longlongsubdir']) exe "normal! 5G\<c-v>2j$y" @@ -1179,8 +1179,8 @@ func Test_visual_put_in_block_using_zp() call assert_equal(['/path/subdir;text', '/path/longsubdir;text', '/path/longlongsubdir;text'], getline(1, 3)) %d " paste using zP - call setline(1, ['/path;text', '/path;text', '/path;text', '', - \ '/subdir', + call setline(1, ['/path;text', '/path;text', '/path;text', '', + \ '/subdir', \ '/longsubdir', \ '/longlongsubdir']) exe "normal! 5G\<c-v>2j$y" @@ -1193,7 +1193,7 @@ func Test_visual_put_in_block_using_zy_and_zp() new " Test 1) Paste using zp - after the cursor without trailing spaces - call setline(1, ['/path;text', '/path;text', '/path;text', '', + call setline(1, ['/path;text', '/path;text', '/path;text', '', \ 'texttext /subdir columntext', \ 'texttext /longsubdir columntext', \ 'texttext /longlongsubdir columntext']) @@ -1203,7 +1203,7 @@ func Test_visual_put_in_block_using_zy_and_zp() " Test 2) Paste using zP - in front of the cursor without trailing spaces %d - call setline(1, ['/path;text', '/path;text', '/path;text', '', + call setline(1, ['/path;text', '/path;text', '/path;text', '', \ 'texttext /subdir columntext', \ 'texttext /longsubdir columntext', \ 'texttext /longlongsubdir columntext']) @@ -1213,7 +1213,7 @@ func Test_visual_put_in_block_using_zy_and_zp() " Test 3) Paste using p - with trailing spaces %d - call setline(1, ['/path;text', '/path;text', '/path;text', '', + call setline(1, ['/path;text', '/path;text', '/path;text', '', \ 'texttext /subdir columntext', \ 'texttext /longsubdir columntext', \ 'texttext /longlongsubdir columntext']) @@ -1223,7 +1223,7 @@ func Test_visual_put_in_block_using_zy_and_zp() " Test 4) Paste using P - with trailing spaces %d - call setline(1, ['/path;text', '/path;text', '/path;text', '', + call setline(1, ['/path;text', '/path;text', '/path;text', '', \ 'texttext /subdir columntext', \ 'texttext /longsubdir columntext', \ 'texttext /longlongsubdir columntext']) @@ -1233,7 +1233,7 @@ func Test_visual_put_in_block_using_zy_and_zp() " Test 5) Yank with spaces inside the block %d - call setline(1, ['/path;text', '/path;text', '/path;text', '', + call setline(1, ['/path;text', '/path;text', '/path;text', '', \ 'texttext /sub dir/ columntext', \ 'texttext /lon gsubdir/ columntext', \ 'texttext /lon glongsubdir/ columntext']) @@ -1968,6 +1968,14 @@ func Test_visual_getregion() #" using invalid value for "type" call assert_fails("call getregion(getpos('.'), getpos('.'), {'type': '' })", 'E475:') call assert_fails("call getregionpos(getpos('.'), getpos('.'), {'type': '' })", 'E475:') + call assert_fails("call getregion(getpos('.'), getpos('.'), {'type': 'v0' })", 'E475:') + call assert_fails("call getregionpos(getpos('.'), getpos('.'), {'type': 'v0' })", 'E475:') + call assert_fails("call getregion(getpos('.'), getpos('.'), {'type': 'V0' })", 'E475:') + call assert_fails("call getregionpos(getpos('.'), getpos('.'), {'type': 'V0' })", 'E475:') + call assert_fails("call getregion(getpos('.'), getpos('.'), {'type': '\<C-v>0' })", 'E475:') + call assert_fails("call getregionpos(getpos('.'), getpos('.'), {'type': '\<C-v>0' })", 'E475:') + call assert_fails("call getregion(getpos('.'), getpos('.'), {'type': '\<C-v>1:' })", 'E475:') + call assert_fails("call getregionpos(getpos('.'), getpos('.'), {'type': '\<C-v>1:' })", 'E475:') #" using a mark from another buffer to current buffer new @@ -2069,10 +2077,12 @@ func Test_visual_getregion() \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" })) call assert_equal([ \ [[bufnr('%'), 1, 5, 0], [bufnr('%'), 1, 5, 0]], - \ [[bufnr('%'), 2, 10, 1], [bufnr('%'), 2, 10, 2]], + \ [[bufnr('%'), 2, 7, 1], [bufnr('%'), 2, 7, 2]], \ [[bufnr('%'), 3, 5, 0], [bufnr('%'), 3, 5, 0]], \ ], \ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" })) + call assert_equal(['efghijk«', '🇦«🇧«🇨«🇩', '12345'], + \ getregion(getpos('v'), getpos('.'), {'type': 'v' })) call assert_equal([ \ [[bufnr('%'), 1, 5, 0], [bufnr('%'), 1, 13, 0]], \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 22, 0]], @@ -2080,6 +2090,28 @@ func Test_visual_getregion() \ ], \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' })) + call cursor(1, 5) + call feedkeys("\<Esc>\<C-v>5l2j", 'xt') + call assert_equal(['efghij', ' «🇨« ', '567890'], + \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" })) + call assert_equal([ + \ [[bufnr('%'), 1, 5, 0], [bufnr('%'), 1, 10, 0]], + \ [[bufnr('%'), 2, 7, 1], [bufnr('%'), 2, 19, 1]], + \ [[bufnr('%'), 3, 5, 0], [bufnr('%'), 3, 10, 0]], + \ ], + \ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" })) + + call cursor(1, 4) + call feedkeys("\<Esc>\<C-v>02j", 'xt') + call assert_equal(['abcd', '🇦« ', '1234'], + \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" })) + call assert_equal([ + \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 4, 0]], + \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 7, 1]], + \ [[bufnr('%'), 3, 1, 0], [bufnr('%'), 3, 4, 0]], + \ ], + \ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" })) + #" characterwise selection with multibyte chars call cursor(1, 1) call feedkeys("\<Esc>vj", 'xt') @@ -2546,30 +2578,127 @@ func Test_getregion_invalid_buf() bwipe! endfunc -func Test_getregion_maxcol() - new +func Test_getregion_after_yank() + func! Check_Results(type) + call assert_equal(g:expected_region, + \ getregion(getpos("'["), getpos("']"), #{ type: a:type })) + call assert_equal(g:expected_regionpos, + \ getregionpos(getpos("'["), getpos("']"), #{ type: a:type })) + call assert_equal(g:expected_region, + \ getregion(getpos("']"), getpos("'["), #{ type: a:type })) + call assert_equal(g:expected_regionpos, + \ getregionpos(getpos("']"), getpos("'["), #{ type: a:type })) + let g:checked = 1 + endfunc + autocmd TextYankPost * \ : if v:event.operator ==? 'y' - \ | call assert_equal([ - \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 4, 0]], - \ ], - \ getregionpos(getpos("'["), getpos("']"), - \ #{ mode: visualmode() })) - \ | call assert_equal(['abcd'], - \ getregion(getpos("'["), getpos("']"), - \ #{ mode: visualmode() })) - \ | call assert_equal([ - \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 4, 0]], - \ ], - \ getregionpos(getpos("']"), getpos("'["), - \ #{ mode: visualmode() })) - \ | call assert_equal(['abcd'], - \ getregion(getpos("']"), getpos("'["), - \ #{ mode: visualmode() })) + \ | call Check_Results(v:event.regtype) \ | endif - call setline(1, ['abcd', 'efghij']) + + new + call setline(1, ['abcd', 'efghijk', 'lmn']) + + let g:expected_region = ['abcd'] + let g:expected_regionpos = [ + \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 4, 0]], + \ ] + let g:checked = 0 normal yy + call assert_equal(1, g:checked) + call Check_Results(getregtype('"')) + + let g:expected_region = ['cd', 'ghijk', 'n'] + let g:expected_regionpos = [ + \ [[bufnr('%'), 1, 3, 0], [bufnr('%'), 1, 4, 0]], + \ [[bufnr('%'), 2, 3, 0], [bufnr('%'), 2, 7, 0]], + \ [[bufnr('%'), 3, 3, 0], [bufnr('%'), 3, 3, 0]], + \ ] + let g:checked = 0 + call feedkeys("gg0ll\<C-V>jj$y", 'tx') + call assert_equal(1, g:checked) + call Check_Results(getregtype('"')) + call assert_equal(g:expected_region, getreg('"', v:true, v:true)) + + let g:expected_region = ['bc', 'fg', 'mn'] + let g:expected_regionpos = [ + \ [[bufnr('%'), 1, 2, 0], [bufnr('%'), 1, 3, 0]], + \ [[bufnr('%'), 2, 2, 0], [bufnr('%'), 2, 3, 0]], + \ [[bufnr('%'), 3, 2, 0], [bufnr('%'), 3, 3, 0]], + \ ] + let g:checked = 0 + call feedkeys("gg0l\<C-V>jjly", 'tx') + call assert_equal(1, g:checked) + call Check_Results(getregtype('"')) + call assert_equal(g:expected_region, getreg('"', v:true, v:true)) + + bwipe! + + new + let lines = ['asdfghjkl', '«å£=å£Â»', 'qwertyuiop', 'å£å£=å£å£', 'zxcvbnm'] + call setline(1, lines) + + let g:expected_region = lines + let g:expected_regionpos = [ + \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 9, 0]], + \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 11, 0]], + \ [[bufnr('%'), 3, 1, 0], [bufnr('%'), 3, 10, 0]], + \ [[bufnr('%'), 4, 1, 0], [bufnr('%'), 4, 13, 0]], + \ [[bufnr('%'), 5, 1, 0], [bufnr('%'), 5, 7, 0]], + \ ] + let g:checked = 0 + call feedkeys('ggyG', 'tx') + call assert_equal(1, g:checked) + call Check_Results(getregtype('"')) + call assert_equal(g:expected_region, getreg('"', v:true, v:true)) + + let g:expected_region = ['=å£Â»', 'qwertyuiop', 'å£å£=å£'] + let g:expected_regionpos = [ + \ [[bufnr('%'), 2, 6, 0], [bufnr('%'), 2, 11, 0]], + \ [[bufnr('%'), 3, 1, 0], [bufnr('%'), 3, 10, 0]], + \ [[bufnr('%'), 4, 1, 0], [bufnr('%'), 4, 10, 0]], + \ ] + let g:checked = 0 + call feedkeys('2gg02lv2j2ly', 'tx') + call assert_equal(1, g:checked) + call Check_Results(getregtype('"')) + call assert_equal(g:expected_region, getreg('"', v:true, v:true)) + + let g:expected_region = ['asdf', '«å£=', 'qwer', 'å£å£', 'zxcv'] + let g:expected_regionpos = [ + \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 4, 0]], + \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 6, 0]], + \ [[bufnr('%'), 3, 1, 0], [bufnr('%'), 3, 4, 0]], + \ [[bufnr('%'), 4, 1, 0], [bufnr('%'), 4, 6, 0]], + \ [[bufnr('%'), 5, 1, 0], [bufnr('%'), 5, 4, 0]], + \ ] + let g:checked = 0 + call feedkeys("G0\<C-V>3l4ky", 'tx') + call assert_equal(1, g:checked) + call Check_Results(getregtype('"')) + call assert_equal(g:expected_region, getreg('"', v:true, v:true)) + + let g:expected_region = ['ghjkl', 'å£Â»', 'tyuiop', '=å£å£', 'bnm'] + let g:expected_regionpos = [ + \ [[bufnr('%'), 1, 5, 0], [bufnr('%'), 1, 9, 0]], + \ [[bufnr('%'), 2, 7, 0], [bufnr('%'), 2, 11, 0]], + \ [[bufnr('%'), 3, 5, 0], [bufnr('%'), 3, 10, 0]], + \ [[bufnr('%'), 4, 7, 0], [bufnr('%'), 4, 13, 0]], + \ [[bufnr('%'), 5, 5, 0], [bufnr('%'), 5, 7, 0]], + \ ] + let g:checked = 0 + call feedkeys("G04l\<C-V>$4ky", 'tx') + call assert_equal(1, g:checked) + call Check_Results(getregtype('"')) + call assert_equal(g:expected_region, getreg('"', v:true, v:true)) + bwipe! + + unlet g:expected_region + unlet g:expected_regionpos + unlet g:checked + autocmd! TextYankPost + delfunc Check_Results endfunc func Test_visual_block_cursor_delete() @@ -2580,4 +2709,13 @@ func Test_visual_block_cursor_delete() bwipe! endfunc +func Test_visual_block_cursor_insert_enter() + new + call setline(1, ['asdf asdf', 'asdf asdf', 'asdf asdf', 'asdf asdf']) + call cursor(1, 5) + exe ":norm! \<c-v>3jcw\<cr>" + call assert_equal(['asdfw', 'asdf', 'asdfasdf', 'asdfasdf', 'asdfasdf'], getline(1, '$')) + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_winbuf_close.vim b/test/old/testdir/test_winbuf_close.vim index 26b4ba8778..d2fa6f66bb 100644 --- a/test/old/testdir/test_winbuf_close.vim +++ b/test/old/testdir/test_winbuf_close.vim @@ -223,7 +223,7 @@ func Test_window_close_splitright_noequalalways() execute "normal \<c-w>b" let h = winheight(0) let w = win_getid() - new + new q call assert_equal(h, winheight(0), "Window height does not match eight before opening and closing another window") call assert_equal(w, win_getid(), "Did not return to original window after opening and closing a window") diff --git a/test/old/testdir/test_winfixbuf.vim b/test/old/testdir/test_winfixbuf.vim index b41eaf3c9b..1777bec184 100644 --- a/test/old/testdir/test_winfixbuf.vim +++ b/test/old/testdir/test_winfixbuf.vim @@ -2934,6 +2934,7 @@ func Test_tfirst() \ "Xtags", 'D') call writefile(["one", "two", "three"], "Xfile", 'D') call writefile(["one"], "Xother", 'D') + tag one edit Xother set winfixbuf diff --git a/test/old/testdir/test_zip_plugin.vim b/test/old/testdir/test_zip_plugin.vim new file mode 100644 index 0000000000..a817d8371e --- /dev/null +++ b/test/old/testdir/test_zip_plugin.vim @@ -0,0 +1,237 @@ +so check.vim + +CheckExecutable unzip + +if 0 " Find uncovered line + profile start zip_profile + profile! file */zip*.vim +endif + +runtime plugin/zipPlugin.vim + +func Test_zip_basic() + + "## get our zip file + if !filecopy("samples/test.zip", "X.zip") + call assert_report("Can't copy samples/test.zip") + return + endif + defer delete("X.zip") + + e X.zip + + "## Check header + call assert_match('^" zip\.vim version v\d\+', getline(1)) + call assert_match('^" Browsing zipfile .*/X.zip', getline(2)) + call assert_match('^" Select a file with cursor and press ENTER', getline(3)) + call assert_match('^$', getline(4)) + + "## Check files listing + call assert_equal(["Xzip/", "Xzip/dir/", "Xzip/file.txt"], getline(5, 7)) + + "## Check ENTER on header + :1 + exe ":normal \<cr>" + call assert_equal("X.zip", @%) + + "## Check ENTER on directory + :1|:/^$//dir/ + call assert_match('Please specify a file, not a directory', + \ execute("normal \<CR>")) + + "## Check ENTER on file + :1 + call search('file.txt') + exe ":normal \<cr>" + call assert_match('zipfile://.*/X.zip::Xzip/file.txt', @%) + call assert_equal('one', getline(1)) + + "## Check editing file + if executable("zip") + s/one/two/ + call assert_equal("two", getline(1)) + w + bw|bw + e X.zip + + :1|:/^$//file/ + exe "normal \<cr>" + call assert_equal("two", getline(1)) + endif + + only + e X.zip + + "## Check extracting file + :1|:/^$//file/ + normal x + call assert_true(filereadable("Xzip/file.txt")) + + "## Check not overwriting existing file + call assert_match('<Xzip/file.txt> .* not overwriting!', execute("normal x")) + + call delete("Xzip", "rf") + + "## Check extracting directory + :1|:/^$//dir/ + call assert_match('Please specify a file, not a directory', execute("normal x")) + call assert_equal("X.zip", @%) + + "## Check "x" on header + :1 + normal x + call assert_equal("X.zip", @%) + bw + + "## Check opening zip when "unzip" program is missing + let save_zip_unzipcmd = g:zip_unzipcmd + let g:zip_unzipcmd = "/" + call assert_match('unzip not available on your system', execute("e X.zip")) + + "## Check when "unzip" don't work + if executable("false") + let g:zip_unzipcmd = "false" + call assert_match('X\.zip is not a zip file', execute("e X.zip")) + endif + bw + + let g:zip_unzipcmd = save_zip_unzipcmd + e X.zip + + "## Check opening file when "unzip" is missing + let g:zip_unzipcmd = "/" + call assert_match('sorry, your system doesn''t appear to have the / program', + \ execute("normal \<CR>")) + + bw|bw + let g:zip_unzipcmd = save_zip_unzipcmd + e X.zip + + "## Check :write when "zip" program is missing + :1|:/^$//file/ + exe "normal \<cr>Goanother\<esc>" + let save_zip_zipcmd = g:zip_zipcmd + let g:zip_zipcmd = "/" + call assert_match('sorry, your system doesn''t appear to have the / program', + \ execute("write")) + + "## Check when "zip" report failure + if executable("false") + let g:zip_zipcmd = "false" + call assert_match('sorry, unable to update .*/X.zip with Xzip/file.txt', + \ execute("write")) + endif + bw!|bw + + let g:zip_zipcmd = save_zip_zipcmd + + "## Check opening an no zipfile + call writefile(["qsdf"], "Xcorupt.zip", "D") + e! Xcorupt.zip + call assert_equal("qsdf", getline(1)) + + bw + + "## Check no existing zipfile + call assert_match('File not readable', execute("e Xnot_exists.zip")) + + bw +endfunc + +func Test_zip_glob_fname() + CheckNotMSWindows + " does not work on Windows, why? + + "## copy sample zip file + if !filecopy("samples/testa.zip", "X.zip") + call assert_report("Can't copy samples/testa.zip") + return + endif + defer delete("X.zip") + defer delete('zipglob', 'rf') + + e X.zip + + "## 1) Check extracting strange files + :1 + let fname = 'a[a].txt' + call search('\V' .. fname) + normal x + call assert_true(filereadable('zipglob/' .. fname)) + call delete('zipglob', 'rf') + + :1 + let fname = 'a*.txt' + call search('\V' .. fname) + normal x + call assert_true(filereadable('zipglob/' .. fname)) + call delete('zipglob', 'rf') + + :1 + let fname = 'a?.txt' + call search('\V' .. fname) + normal x + call assert_true(filereadable('zipglob/' .. fname)) + call delete('zipglob', 'rf') + + :1 + let fname = 'a\.txt' + call search('\V' .. escape(fname, '\\')) + normal x + call assert_true(filereadable('zipglob/' .. fname)) + call delete('zipglob', 'rf') + + :1 + let fname = 'a\\.txt' + call search('\V' .. escape(fname, '\\')) + normal x + call assert_true(filereadable('zipglob/' .. fname)) + call delete('zipglob', 'rf') + + "## 2) Check entering strange file names + :1 + let fname = 'a[a].txt' + call search('\V' .. fname) + exe ":normal \<cr>" + call assert_match('zipfile://.*/X.zip::zipglob/a\[a\].txt', @%) + call assert_equal('a test file with []', getline(1)) + bw + + e X.zip + :1 + let fname = 'a*.txt' + call search('\V' .. fname) + exe ":normal \<cr>" + call assert_match('zipfile://.*/X.zip::zipglob/a\*.txt', @%) + call assert_equal('a test file with a*', getline(1)) + bw + + e X.zip + :1 + let fname = 'a?.txt' + call search('\V' .. fname) + exe ":normal \<cr>" + call assert_match('zipfile://.*/X.zip::zipglob/a?.txt', @%) + call assert_equal('a test file with a?', getline(1)) + bw + + e X.zip + :1 + let fname = 'a\.txt' + call search('\V' .. escape(fname, '\\')) + exe ":normal \<cr>" + call assert_match('zipfile://.*/X.zip::zipglob/a\\.txt', @%) + call assert_equal('a test file with a\', getline(1)) + bw + + e X.zip + :1 + let fname = 'a\\.txt' + call search('\V' .. escape(fname, '\\')) + exe ":normal \<cr>" + call assert_match('zipfile://.*/X.zip::zipglob/a\\\\.txt', @%) + call assert_equal('a test file with a double \', getline(1)) + bw + + bw +endfunc diff --git a/test/testutil.lua b/test/testutil.lua index 439f13cf49..a920f658a1 100644 --- a/test/testutil.lua +++ b/test/testutil.lua @@ -16,7 +16,7 @@ local function shell_quote(str) return str end ---- This module uses functions from the context of the test runner. +--- Functions executing in the context of the test runner (not the current nvim test session). --- @class test.testutil local M = { paths = Paths, @@ -42,6 +42,29 @@ function M.isdir(path) return stat.type == 'directory' end +--- (Only on Windows) Replaces yucky "\\" slashes with delicious "/" slashes in a string, or all +--- string values in a table (recursively). +--- +--- @param obj string|table +--- @return any +function M.fix_slashes(obj) + if not M.is_os('win') then + return obj + end + if type(obj) == 'string' then + local ret = obj:gsub('\\', '/') + return ret + elseif type(obj) == 'table' then + --- @cast obj table<any,any> + local ret = {} --- @type table<any,any> + for k, v in pairs(obj) do + ret[k] = M.fix_slashes(v) + end + return ret + end + assert(false, 'expected string or table of strings, got ' .. type(obj)) +end + --- @param ... string|string[] --- @return string function M.argss_to_cmd(...) @@ -143,7 +166,7 @@ end --- ---@param pat (string) Lua pattern to match lines in the log file ---@param logfile? (string) Full path to log file (default=$NVIM_LOG_FILE) ----@param nrlines? (number) Search up to this many log lines +---@param nrlines? (number) Search up to this many log lines (default 10) ---@param inverse? (boolean) Assert that the pattern does NOT match. function M.assert_log(pat, logfile, nrlines, inverse) logfile = logfile or os.getenv('NVIM_LOG_FILE') or '.nvimlog' @@ -369,7 +392,7 @@ function M.check_logs() ) end -function M.sysname() +local function sysname() return uv.os_uname().sysname:lower() end @@ -380,11 +403,11 @@ function M.is_os(s) error('unknown platform: ' .. tostring(s)) end return not not ( - (s == 'win' and (M.sysname():find('windows') or M.sysname():find('mingw'))) - or (s == 'mac' and M.sysname() == 'darwin') - or (s == 'freebsd' and M.sysname() == 'freebsd') - or (s == 'openbsd' and M.sysname() == 'openbsd') - or (s == 'bsd' and M.sysname():find('bsd')) + (s == 'win' and (sysname():find('windows') or sysname():find('mingw'))) + or (s == 'mac' and sysname() == 'darwin') + or (s == 'freebsd' and sysname() == 'freebsd') + or (s == 'openbsd' and sysname() == 'openbsd') + or (s == 'bsd' and sysname():find('bsd')) ) end @@ -402,18 +425,27 @@ end local tmpname_id = 0 local tmpdir = tmpdir_get() ---- Creates a new temporary file for use by tests. -function M.tmpname() +--- Generates a unique filepath for use by tests, in a test-specific "…/Xtest_tmpdir/T42.7" +--- directory (which is cleaned up by the test runner), and writes the file unless `create=false`. +--- +---@param create? boolean (default true) Write the file. +function M.tmpname(create) if tmpdir_is_local(tmpdir) then -- Cannot control os.tmpname() dir, so hack our own tmpname() impl. tmpname_id = tmpname_id + 1 -- "…/Xtest_tmpdir/T42.7" local fname = ('%s/%s.%d'):format(tmpdir, (_G._nvim_test_id or 'nvim-test'), tmpname_id) - io.open(fname, 'w'):close() + if create ~= false then + io.open(fname, 'w'):close() + end return fname end local fname = os.tmpname() + if create == false then + os.remove(fname) + end + if M.is_os('win') and fname:sub(1, 2) == '\\s' then -- In Windows tmpname() returns a filename starting with -- special sequence \s, prepend $TEMP path diff --git a/test/unit/api/private_helpers_spec.lua b/test/unit/api/private_helpers_spec.lua index a31374bd70..bdfc83a031 100644 --- a/test/unit/api/private_helpers_spec.lua +++ b/test/unit/api/private_helpers_spec.lua @@ -43,9 +43,9 @@ describe('vim_to_object', function() simple_test('converts empty string', '') simple_test('converts non-empty string', 'foobar') simple_test('converts integer 10', { [type_key] = int_type, value = 10 }) - simple_test('converts empty dictionary', {}) - simple_test('converts dictionary with scalar values', { test = 10, test2 = true, test3 = 'test' }) - simple_test('converts dictionary with containers inside', { test = {}, test2 = { 1, 2 } }) + simple_test('converts empty dict', {}) + simple_test('converts dict with scalar values', { test = 10, test2 = true, test3 = 'test' }) + simple_test('converts dict with containers inside', { test = {}, test2 = { 1, 2 } }) simple_test('converts empty list', { [type_key] = list_type }) simple_test('converts list with scalar values', { 1, 2, 'test', 'foo' }) simple_test( diff --git a/test/unit/api/testutil.lua b/test/unit/api/testutil.lua index 0946ef194c..bb387ae0e1 100644 --- a/test/unit/api/testutil.lua +++ b/test/unit/api/testutil.lua @@ -35,10 +35,10 @@ local function init_obj2lua_tab() end return ret end, - [tonumber(api.kObjectTypeDictionary)] = function(obj) + [tonumber(api.kObjectTypeDict)] = function(obj) local ret = {} - for i = 1, tonumber(obj.data.dictionary.size) do - local kv_pair = obj.data.dictionary.items[i - 1] + for i = 1, tonumber(obj.data.dict.size) do + local kv_pair = obj.data.dict.items[i - 1] ret[ffi.string(kv_pair.key.data, kv_pair.key.size)] = obj2lua(kv_pair.value) end return ret @@ -112,8 +112,8 @@ local lua2obj_type_tab = { end end local len = #kvs - local dct = obj(api.kObjectTypeDictionary, { - dictionary = { + local dct = obj(api.kObjectTypeDict, { + dict = { size = len, capacity = len, items = ffi.cast('KeyValuePair *', api.xmalloc(len * ffi.sizeof('KeyValuePair'))), @@ -121,7 +121,7 @@ local lua2obj_type_tab = { }) for i = 1, len do local key, val = unpack(kvs[i]) - dct.data.dictionary.items[i - 1] = ffi.new( + dct.data.dict.items[i - 1] = ffi.new( 'KeyValuePair', { key = ffi.gc(lua2obj(key), nil).data.string, value = ffi.gc(lua2obj(val), nil) } ) diff --git a/test/unit/eval/encode_spec.lua b/test/unit/eval/encode_spec.lua index 5b9188163e..9f193bc2f9 100644 --- a/test/unit/eval/encode_spec.lua +++ b/test/unit/eval/encode_spec.lua @@ -21,81 +21,81 @@ describe('encode_list_write()', function() itp('writes empty string', function() local l = list() - eq(0, encode_list_write(l, '')) + encode_list_write(l, '') eq({ [type_key] = list_type }, lst2tbl(l)) end) itp('writes ASCII string literal with printable characters', function() local l = list() - eq(0, encode_list_write(l, 'abc')) + encode_list_write(l, 'abc') eq({ 'abc' }, lst2tbl(l)) end) itp('writes string starting with NL', function() local l = list() - eq(0, encode_list_write(l, '\nabc')) + encode_list_write(l, '\nabc') eq({ null_string, 'abc' }, lst2tbl(l)) end) itp('writes string starting with NL twice', function() local l = list() - eq(0, encode_list_write(l, '\nabc')) + encode_list_write(l, '\nabc') eq({ null_string, 'abc' }, lst2tbl(l)) - eq(0, encode_list_write(l, '\nabc')) + encode_list_write(l, '\nabc') eq({ null_string, 'abc', 'abc' }, lst2tbl(l)) end) itp('writes string ending with NL', function() local l = list() - eq(0, encode_list_write(l, 'abc\n')) + encode_list_write(l, 'abc\n') eq({ 'abc', null_string }, lst2tbl(l)) end) itp('writes string ending with NL twice', function() local l = list() - eq(0, encode_list_write(l, 'abc\n')) + encode_list_write(l, 'abc\n') eq({ 'abc', null_string }, lst2tbl(l)) - eq(0, encode_list_write(l, 'abc\n')) + encode_list_write(l, 'abc\n') eq({ 'abc', 'abc', null_string }, lst2tbl(l)) end) itp('writes string starting, ending and containing NL twice', function() local l = list() - eq(0, encode_list_write(l, '\na\nb\n')) + encode_list_write(l, '\na\nb\n') eq({ null_string, 'a', 'b', null_string }, lst2tbl(l)) - eq(0, encode_list_write(l, '\na\nb\n')) + encode_list_write(l, '\na\nb\n') eq({ null_string, 'a', 'b', null_string, 'a', 'b', null_string }, lst2tbl(l)) end) itp('writes string starting, ending and containing NUL with NL between twice', function() local l = list() - eq(0, encode_list_write(l, '\0\n\0\n\0')) + encode_list_write(l, '\0\n\0\n\0') eq({ '\n', '\n', '\n' }, lst2tbl(l)) - eq(0, encode_list_write(l, '\0\n\0\n\0')) + encode_list_write(l, '\0\n\0\n\0') eq({ '\n', '\n', '\n\n', '\n', '\n' }, lst2tbl(l)) end) itp('writes string starting, ending and containing NL with NUL between twice', function() local l = list() - eq(0, encode_list_write(l, '\n\0\n\0\n')) + encode_list_write(l, '\n\0\n\0\n') eq({ null_string, '\n', '\n', null_string }, lst2tbl(l)) - eq(0, encode_list_write(l, '\n\0\n\0\n')) + encode_list_write(l, '\n\0\n\0\n') eq({ null_string, '\n', '\n', null_string, '\n', '\n', null_string }, lst2tbl(l)) end) itp('writes string containing a single NL twice', function() local l = list() - eq(0, encode_list_write(l, '\n')) + encode_list_write(l, '\n') eq({ null_string, null_string }, lst2tbl(l)) - eq(0, encode_list_write(l, '\n')) + encode_list_write(l, '\n') eq({ null_string, null_string, null_string }, lst2tbl(l)) end) itp('writes string containing a few NLs twice', function() local l = list() - eq(0, encode_list_write(l, '\n\n\n')) + encode_list_write(l, '\n\n\n') eq({ null_string, null_string, null_string, null_string }, lst2tbl(l)) - eq(0, encode_list_write(l, '\n\n\n')) + encode_list_write(l, '\n\n\n') eq( { null_string, null_string, null_string, null_string, null_string, null_string, null_string }, lst2tbl(l) diff --git a/test/unit/eval/typval_spec.lua b/test/unit/eval/typval_spec.lua index c69c9b0fae..14fd7986e7 100644 --- a/test/unit/eval/typval_spec.lua +++ b/test/unit/eval/typval_spec.lua @@ -1267,26 +1267,19 @@ describe('typval.c', function() local l2 = list() -- NULL lists are equal to empty lists - eq(true, lib.tv_list_equal(l, nil, true, false)) - eq(true, lib.tv_list_equal(nil, l, false, false)) - eq(true, lib.tv_list_equal(nil, l, false, true)) - eq(true, lib.tv_list_equal(l, nil, true, true)) + eq(true, lib.tv_list_equal(l, nil, true)) + eq(true, lib.tv_list_equal(nil, l, false)) -- NULL lists are equal themselves - eq(true, lib.tv_list_equal(nil, nil, true, false)) - eq(true, lib.tv_list_equal(nil, nil, false, false)) - eq(true, lib.tv_list_equal(nil, nil, false, true)) - eq(true, lib.tv_list_equal(nil, nil, true, true)) + eq(true, lib.tv_list_equal(nil, nil, true)) + eq(true, lib.tv_list_equal(nil, nil, false)) -- As well as empty lists - eq(true, lib.tv_list_equal(l, l, true, false)) - eq(true, lib.tv_list_equal(l, l2, false, false)) - eq(true, lib.tv_list_equal(l2, l, false, true)) - eq(true, lib.tv_list_equal(l2, l2, true, true)) - end) - -- Must not use recursive=true argument in the following tests because it - -- indicates that tv_equal_recurse_limit and recursive_cnt were set which - -- is essential. This argument will be set when comparing inner lists. + eq(true, lib.tv_list_equal(l, l, true)) + eq(true, lib.tv_list_equal(l, l2, false)) + eq(true, lib.tv_list_equal(l2, l, false)) + eq(true, lib.tv_list_equal(l2, l2, true)) + end) itp('compares lists correctly when case is not ignored', function() local l1 = list('abc', { 1, 2, 'Abc' }, 'def') local l2 = list('abc', { 1, 2, 'Abc' }) @@ -1298,15 +1291,15 @@ describe('typval.c', function() local l8 = list('abc', nil, 'def') local l9 = list('abc', { 1, 2, nil }, 'def') - eq(true, lib.tv_list_equal(l1, l1, false, false)) - eq(false, lib.tv_list_equal(l1, l2, false, false)) - eq(false, lib.tv_list_equal(l1, l3, false, false)) - eq(false, lib.tv_list_equal(l1, l4, false, false)) - eq(false, lib.tv_list_equal(l1, l5, false, false)) - eq(true, lib.tv_list_equal(l1, l6, false, false)) - eq(false, lib.tv_list_equal(l1, l7, false, false)) - eq(false, lib.tv_list_equal(l1, l8, false, false)) - eq(false, lib.tv_list_equal(l1, l9, false, false)) + eq(true, lib.tv_list_equal(l1, l1, false)) + eq(false, lib.tv_list_equal(l1, l2, false)) + eq(false, lib.tv_list_equal(l1, l3, false)) + eq(false, lib.tv_list_equal(l1, l4, false)) + eq(false, lib.tv_list_equal(l1, l5, false)) + eq(true, lib.tv_list_equal(l1, l6, false)) + eq(false, lib.tv_list_equal(l1, l7, false)) + eq(false, lib.tv_list_equal(l1, l8, false)) + eq(false, lib.tv_list_equal(l1, l9, false)) end) itp('compares lists correctly when case is ignored', function() local l1 = list('abc', { 1, 2, 'Abc' }, 'def') @@ -1319,15 +1312,15 @@ describe('typval.c', function() local l8 = list('abc', nil, 'def') local l9 = list('abc', { 1, 2, nil }, 'def') - eq(true, lib.tv_list_equal(l1, l1, true, false)) - eq(false, lib.tv_list_equal(l1, l2, true, false)) - eq(true, lib.tv_list_equal(l1, l3, true, false)) - eq(false, lib.tv_list_equal(l1, l4, true, false)) - eq(true, lib.tv_list_equal(l1, l5, true, false)) - eq(true, lib.tv_list_equal(l1, l6, true, false)) - eq(true, lib.tv_list_equal(l1, l7, true, false)) - eq(false, lib.tv_list_equal(l1, l8, true, false)) - eq(false, lib.tv_list_equal(l1, l9, true, false)) + eq(true, lib.tv_list_equal(l1, l1, true)) + eq(false, lib.tv_list_equal(l1, l2, true)) + eq(true, lib.tv_list_equal(l1, l3, true)) + eq(false, lib.tv_list_equal(l1, l4, true)) + eq(true, lib.tv_list_equal(l1, l5, true)) + eq(true, lib.tv_list_equal(l1, l6, true)) + eq(true, lib.tv_list_equal(l1, l7, true)) + eq(false, lib.tv_list_equal(l1, l8, true)) + eq(false, lib.tv_list_equal(l1, l9, true)) end) end) describe('find', function() @@ -2326,7 +2319,7 @@ describe('typval.c', function() return lib.tv_dict_extend(d1, d2, action) end, emsg) end - itp('works', function() + pending('works (skip due to flakiness)', function() local d1 = dict() alloc_log:check({ a.dict(d1) }) eq({}, dct2tbl(d1)) @@ -2448,8 +2441,8 @@ describe('typval.c', function() end) end) describe('equal()', function() - local function tv_dict_equal(d1, d2, ic, recursive) - return lib.tv_dict_equal(d1, d2, ic or false, recursive or false) + local function tv_dict_equal(d1, d2, ic) + return lib.tv_dict_equal(d1, d2, ic or false) end itp('works', function() eq(true, tv_dict_equal(nil, nil)) @@ -2494,7 +2487,6 @@ describe('typval.c', function() eq(true, tv_dict_equal(d_kupper_upper, d_kupper_lower, true)) eq(false, tv_dict_equal(d_kupper_upper, d_lower, true)) eq(false, tv_dict_equal(d_kupper_upper, d_upper, true)) - eq(true, tv_dict_equal(d_upper, d_upper, true, true)) alloc_log:check({}) end) end) @@ -2923,26 +2915,19 @@ describe('typval.c', function() local nl = lua2typvalt(null_list) -- NULL lists are equal to empty lists - eq(true, lib.tv_equal(l, nl, true, false)) - eq(true, lib.tv_equal(nl, l, false, false)) - eq(true, lib.tv_equal(nl, l, false, true)) - eq(true, lib.tv_equal(l, nl, true, true)) + eq(true, lib.tv_equal(l, nl, true)) + eq(true, lib.tv_equal(nl, l, false)) -- NULL lists are equal themselves - eq(true, lib.tv_equal(nl, nl, true, false)) - eq(true, lib.tv_equal(nl, nl, false, false)) - eq(true, lib.tv_equal(nl, nl, false, true)) - eq(true, lib.tv_equal(nl, nl, true, true)) + eq(true, lib.tv_equal(nl, nl, true)) + eq(true, lib.tv_equal(nl, nl, false)) -- As well as empty lists - eq(true, lib.tv_equal(l, l, true, false)) - eq(true, lib.tv_equal(l, l2, false, false)) - eq(true, lib.tv_equal(l2, l, false, true)) - eq(true, lib.tv_equal(l2, l2, true, true)) - end) - -- Must not use recursive=true argument in the following tests because it - -- indicates that tv_equal_recurse_limit and recursive_cnt were set which - -- is essential. This argument will be set when comparing inner lists. + eq(true, lib.tv_equal(l, l, true)) + eq(true, lib.tv_equal(l, l2, false)) + eq(true, lib.tv_equal(l2, l, false)) + eq(true, lib.tv_equal(l2, l2, true)) + end) itp('compares lists correctly when case is not ignored', function() local l1 = lua2typvalt({ 'abc', { 1, 2, 'Abc' }, 'def' }) local l2 = lua2typvalt({ 'abc', { 1, 2, 'Abc' } }) @@ -2954,15 +2939,15 @@ describe('typval.c', function() local l8 = lua2typvalt({ 'abc', nil, 'def' }) local l9 = lua2typvalt({ 'abc', { 1, 2, nil }, 'def' }) - eq(true, lib.tv_equal(l1, l1, false, false)) - eq(false, lib.tv_equal(l1, l2, false, false)) - eq(false, lib.tv_equal(l1, l3, false, false)) - eq(false, lib.tv_equal(l1, l4, false, false)) - eq(false, lib.tv_equal(l1, l5, false, false)) - eq(true, lib.tv_equal(l1, l6, false, false)) - eq(false, lib.tv_equal(l1, l7, false, false)) - eq(false, lib.tv_equal(l1, l8, false, false)) - eq(false, lib.tv_equal(l1, l9, false, false)) + eq(true, lib.tv_equal(l1, l1, false)) + eq(false, lib.tv_equal(l1, l2, false)) + eq(false, lib.tv_equal(l1, l3, false)) + eq(false, lib.tv_equal(l1, l4, false)) + eq(false, lib.tv_equal(l1, l5, false)) + eq(true, lib.tv_equal(l1, l6, false)) + eq(false, lib.tv_equal(l1, l7, false)) + eq(false, lib.tv_equal(l1, l8, false)) + eq(false, lib.tv_equal(l1, l9, false)) end) itp('compares lists correctly when case is ignored', function() local l1 = lua2typvalt({ 'abc', { 1, 2, 'Abc' }, 'def' }) @@ -2975,18 +2960,18 @@ describe('typval.c', function() local l8 = lua2typvalt({ 'abc', nil, 'def' }) local l9 = lua2typvalt({ 'abc', { 1, 2, nil }, 'def' }) - eq(true, lib.tv_equal(l1, l1, true, false)) - eq(false, lib.tv_equal(l1, l2, true, false)) - eq(true, lib.tv_equal(l1, l3, true, false)) - eq(false, lib.tv_equal(l1, l4, true, false)) - eq(true, lib.tv_equal(l1, l5, true, false)) - eq(true, lib.tv_equal(l1, l6, true, false)) - eq(true, lib.tv_equal(l1, l7, true, false)) - eq(false, lib.tv_equal(l1, l8, true, false)) - eq(false, lib.tv_equal(l1, l9, true, false)) - end) - local function tv_equal(d1, d2, ic, recursive) - return lib.tv_equal(d1, d2, ic or false, recursive or false) + eq(true, lib.tv_equal(l1, l1, true)) + eq(false, lib.tv_equal(l1, l2, true)) + eq(true, lib.tv_equal(l1, l3, true)) + eq(false, lib.tv_equal(l1, l4, true)) + eq(true, lib.tv_equal(l1, l5, true)) + eq(true, lib.tv_equal(l1, l6, true)) + eq(true, lib.tv_equal(l1, l7, true)) + eq(false, lib.tv_equal(l1, l8, true)) + eq(false, lib.tv_equal(l1, l9, true)) + end) + local function tv_equal(d1, d2, ic) + return lib.tv_equal(d1, d2, ic or false) end itp('works with dictionaries', function() local nd = lua2typvalt(null_dict) @@ -3033,7 +3018,6 @@ describe('typval.c', function() eq(true, tv_equal(d_kupper_upper, d_kupper_lower, true)) eq(false, tv_equal(d_kupper_upper, d_lower, true)) eq(false, tv_equal(d_kupper_upper, d_upper, true)) - eq(true, tv_equal(d_upper, d_upper, true, true)) alloc_log:check({}) end) end) diff --git a/test/unit/fixtures/rbuffer.c b/test/unit/fixtures/rbuffer.c deleted file mode 100644 index d587d6b054..0000000000 --- a/test/unit/fixtures/rbuffer.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "nvim/rbuffer.h" -#include "rbuffer.h" - - -void ut_rbuffer_each_read_chunk(RBuffer *buf, each_ptr_cb cb) -{ - RBUFFER_UNTIL_EMPTY(buf, rptr, rcnt) { - cb(rptr, rcnt); - rbuffer_consumed(buf, rcnt); - } -} - -void ut_rbuffer_each_write_chunk(RBuffer *buf, each_ptr_cb cb) -{ - RBUFFER_UNTIL_FULL(buf, wptr, wcnt) { - cb(wptr, wcnt); - rbuffer_produced(buf, wcnt); - } -} -void ut_rbuffer_each(RBuffer *buf, each_cb cb) -{ - RBUFFER_EACH(buf, c, i) cb(c, i); -} - -void ut_rbuffer_each_reverse(RBuffer *buf, each_cb cb) -{ - RBUFFER_EACH_REVERSE(buf, c, i) cb(c, i); -} diff --git a/test/unit/fixtures/rbuffer.h b/test/unit/fixtures/rbuffer.h deleted file mode 100644 index 640092c627..0000000000 --- a/test/unit/fixtures/rbuffer.h +++ /dev/null @@ -1,9 +0,0 @@ -#include "nvim/rbuffer.h" - -typedef void(*each_ptr_cb)(char *ptr, size_t cnt); -typedef void(*each_cb)(char c, size_t i); - -void ut_rbuffer_each_read_chunk(RBuffer *buf, each_ptr_cb cb); -void ut_rbuffer_each_write_chunk(RBuffer *buf, each_ptr_cb cb); -void ut_rbuffer_each(RBuffer *buf, each_cb cb); -void ut_rbuffer_each_reverse(RBuffer *buf, each_cb cb); diff --git a/test/unit/formatc.lua b/test/unit/formatc.lua index ce9cb81f4a..04a8b4009f 100644 --- a/test/unit/formatc.lua +++ b/test/unit/formatc.lua @@ -264,6 +264,7 @@ local function formatc(str) -- and ';' indicates we're at the end of a statement, so we put end -- it with a newline. token[1] = ';\n' + end_at_brace = false end elseif typ == 'whitespace' then -- replace all whitespace by one space diff --git a/test/unit/mbyte_spec.lua b/test/unit/mbyte_spec.lua index 8fcc67d20b..bdc111de2c 100644 --- a/test/unit/mbyte_spec.lua +++ b/test/unit/mbyte_spec.lua @@ -3,8 +3,14 @@ local itp = t.gen_itp(it) local ffi = t.ffi local eq = t.eq +local to_cstr = t.to_cstr -local lib = t.cimport('./src/nvim/mbyte.h', './src/nvim/charset.h', './src/nvim/grid.h') +local lib = t.cimport( + './src/nvim/mbyte.h', + './src/nvim/charset.h', + './src/nvim/grid.h', + './src/nvim/option_vars.h' +) describe('mbyte', function() -- Convert from bytes to string @@ -45,12 +51,21 @@ describe('mbyte', function() end) end - describe('utfc_ptr2schar_len', function() + describe('utfc_ptr2schar', function() local function test_seq(seq) local firstc = ffi.new('int[1]') local buf = ffi.new('char[32]') - lib.schar_get(buf, lib.utfc_ptr2schar_len(to_string(seq), #seq, firstc)) - return { ffi.string(buf), firstc[0] } + lib.schar_get(buf, lib.utfc_ptr2schar(to_string(seq), firstc)) + local str = ffi.string(buf) + if 1 > 2 then -- for debugging + local tabel = {} + for i = 1, #str do + table.insert(tabel, string.format('0x%02x', string.byte(str, i))) + end + print('{ ' .. table.concat(tabel, ', ') .. ' }') + io.stdout:flush() + end + return { str, firstc[0] } end local function byte(val) @@ -88,7 +103,9 @@ describe('mbyte', function() eq(byte(0x7f), test_seq { 0x7f, 0xc2, 0x80 }) -- Combining character is U+0300 - eq({ '\x7f\xcc\x80', 0x7f }, test_seq { 0x7f, 0xcc, 0x80 }) + eq({ '\x29\xcc\x80', 0x29 }, test_seq { 0x29, 0xcc, 0x80 }) + -- invalid start byte for combining + eq({ '\x7f', 0x7f }, test_seq { 0x7f, 0xcc, 0x80 }) -- No UTF-8 sequence eq({ '', 0xc2 }, test_seq { 0xc2, 0x7f, 0xcc }) @@ -102,18 +119,21 @@ describe('mbyte', function() itp('4-byte sequences', function() -- No following combining character eq(byte(0x7f), test_seq { 0x7f, 0x7f, 0xcc, 0x80 }) + eq(byte(0x29), test_seq { 0x29, 0x29, 0xcc, 0x80 }) -- No second UTF-8 character eq(byte(0x7f), test_seq { 0x7f, 0xc2, 0xcc, 0x80 }) -- Combining character U+0300 - eq({ '\x7f\xcc\x80', 0x7f }, test_seq { 0x7f, 0xcc, 0x80, 0xcc }) + eq({ '\x29\xcc\x80', 0x29 }, test_seq { 0x29, 0xcc, 0x80, 0xcc }) -- No UTF-8 sequence eq({ '', 0xc2 }, test_seq { 0xc2, 0x7f, 0xcc, 0x80 }) -- No following UTF-8 character eq({ '\xc2\x80', 0x80 }, test_seq { 0xc2, 0x80, 0xcc, 0xcc }) -- Combining character U+0301 - eq({ '\xc2\x80\xcc\x81', 0x80 }, test_seq { 0xc2, 0x80, 0xcc, 0x81 }) + eq({ '\xc2\xbc\xcc\x81', 0xbc }, test_seq { 0xc2, 0xbc, 0xcc, 0x81 }) + -- U+0080 : not a valid start char + eq({ '\xc2\x80', 0x80 }, test_seq { 0xc2, 0x80, 0xcc, 0x81 }) -- One UTF-8 character eq({ '\xf4\x80\x80\x80', 0x100000 }, test_seq { 0xf4, 0x80, 0x80, 0x80 }) @@ -126,36 +146,36 @@ describe('mbyte', function() eq(byte(0x7f), test_seq { 0x7f, 0xc2, 0xcc, 0x80, 0x80 }) -- Combining character U+0300 - eq({ '\x7f\xcc\x80', 0x7f }, test_seq { 0x7f, 0xcc, 0x80, 0xcc, 0x00 }) + eq({ '\x29\xcc\x80', 0x29 }, test_seq { 0x29, 0xcc, 0x80, 0xcc, 0x00 }) -- Combining characters U+0300 and U+0301 - eq({ '\x7f\xcc\x80\xcc\x81', 0x7f }, test_seq { 0x7f, 0xcc, 0x80, 0xcc, 0x81 }) + eq({ '\x29\xcc\x80\xcc\x81', 0x29 }, test_seq { 0x29, 0xcc, 0x80, 0xcc, 0x81 }) -- Combining characters U+0300, U+0301, U+0302 eq( - { '\x7f\xcc\x80\xcc\x81\xcc\x82', 0x7f }, - test_seq { 0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82 } + { '\x29\xcc\x80\xcc\x81\xcc\x82', 0x29 }, + test_seq { 0x29, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82 } ) -- Combining characters U+0300, U+0301, U+0302, U+0303 eq( - { '\x7f\xcc\x80\xcc\x81\xcc\x82\xcc\x83', 0x7f }, - test_seq { 0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xcc, 0x83 } + { '\x29\xcc\x80\xcc\x81\xcc\x82\xcc\x83', 0x29 }, + test_seq { 0x29, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xcc, 0x83 } ) -- Combining characters U+0300, U+0301, U+0302, U+0303, U+0304 eq( - { '\x7f\xcc\x80\xcc\x81\xcc\x82\xcc\x83\xcc\x84', 0x7f }, - test_seq { 0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xcc, 0x83, 0xcc, 0x84 } + { '\x29\xcc\x80\xcc\x81\xcc\x82\xcc\x83\xcc\x84', 0x29 }, + test_seq { 0x29, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xcc, 0x83, 0xcc, 0x84 } ) -- Combining characters U+0300, U+0301, U+0302, U+0303, U+0304, U+0305 eq( - { '\x7f\xcc\x80\xcc\x81\xcc\x82\xcc\x83\xcc\x84\xcc\x85', 0x7f }, - test_seq { 0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xcc, 0x83, 0xcc, 0x84, 0xcc, 0x85 } + { '\x29\xcc\x80\xcc\x81\xcc\x82\xcc\x83\xcc\x84\xcc\x85', 0x29 }, + test_seq { 0x29, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xcc, 0x83, 0xcc, 0x84, 0xcc, 0x85 } ) -- Combining characters U+0300, U+0301, U+0302, U+0303, U+0304, U+0305, U+0306 eq( - { '\x7f\xcc\x80\xcc\x81\xcc\x82\xcc\x83\xcc\x84\xcc\x85\xcc\x86', 0x7f }, + { '\x29\xcc\x80\xcc\x81\xcc\x82\xcc\x83\xcc\x84\xcc\x85\xcc\x86', 0x29 }, test_seq { - 0x7f, + 0x29, 0xcc, 0x80, 0xcc, @@ -175,18 +195,18 @@ describe('mbyte', function() -- Only three following combining characters U+0300, U+0301, U+0302 eq( - { '\x7f\xcc\x80\xcc\x81\xcc\x82', 0x7f }, - test_seq { 0x7f, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xc2, 0x80, 0xcc, 0x84, 0xcc, 0x85 } + { '\x29\xcc\x80\xcc\x81\xcc\x82', 0x29 }, + test_seq { 0x29, 0xcc, 0x80, 0xcc, 0x81, 0xcc, 0x82, 0xc2, 0x80, 0xcc, 0x84, 0xcc, 0x85 } ) -- No UTF-8 sequence eq({ '', 0xc2 }, test_seq { 0xc2, 0x7f, 0xcc, 0x80, 0x80 }) -- No following UTF-8 character - eq({ '\xc2\x80', 0x80 }, test_seq { 0xc2, 0x80, 0xcc, 0xcc, 0x80 }) + eq({ '\xc2\xbc', 0xbc }, test_seq { 0xc2, 0xbc, 0xcc, 0xcc, 0x80 }) -- Combining character U+0301 - eq({ '\xc2\x80\xcc\x81', 0x80 }, test_seq { 0xc2, 0x80, 0xcc, 0x81, 0x7f }) + eq({ '\xc2\xbc\xcc\x81', 0xbc }, test_seq { 0xc2, 0xbc, 0xcc, 0x81, 0x7f }) -- Combining character U+0301 - eq({ '\xc2\x80\xcc\x81', 0x80 }, test_seq { 0xc2, 0x80, 0xcc, 0x81, 0xcc }) + eq({ '\xc2\xbc\xcc\x81', 0xbc }, test_seq { 0xc2, 0xbc, 0xcc, 0x81, 0xcc }) -- One UTF-8 character eq({ '\xf4\x80\x80\x80', 0x100000 }, test_seq { 0xf4, 0x80, 0x80, 0x80, 0x7f }) @@ -205,8 +225,6 @@ describe('mbyte', function() end) describe('utf_cp_bounds_len', function() - local to_cstr = t.to_cstr - local tests = { { name = 'for valid string', @@ -273,4 +291,72 @@ describe('mbyte', function() eq(expected_offsets, { b = b_offsets, e = e_offsets }) end) end) + + itp('utf_head_off', function() + local function check(str, expected_glyphs) + local len = #str + local cstr = to_cstr(str) + local breaks = { 0 } -- SOT + local pos = 0 + local mb_glyphs = {} + while pos < len do + local clen = lib.utfc_ptr2len(cstr + pos) + if clen == 0 then + eq(0, string.byte(str, pos + 1)) -- only NUL bytes can has length zery + clen = 1 -- but skip it, otherwise we get stuck + end + if clen > 1 then + table.insert(mb_glyphs, string.sub(str, pos + 1, pos + clen)) + end + pos = pos + clen + table.insert(breaks, pos) + end + eq(breaks[#breaks], len) -- include EOT as break + -- we could also send in breaks, but this is more human readable + eq(mb_glyphs, expected_glyphs) + + for i = 1, #breaks - 1 do + local start, next = breaks[i], breaks[i + 1] + + for p = start, next - 1 do + eq(p - start, lib.utf_head_off(cstr, cstr + p)) + end + end + eq(0, lib.utf_head_off(cstr, cstr + len)) -- NUL byte is safe + end + -- stylua doesn't like ZWJ chars.. + -- stylua: ignore start + check('hej och hÃ¥ 🧑â€ðŸŒ¾!', { 'Ã¥', '🧑â€ðŸŒ¾' }) + + -- emoji (various kinds of combinations, use g8 to see them) + check("ðŸ³ï¸â€âš§ï¸ðŸ§‘â€ðŸŒ¾â¤ï¸ðŸ˜‚ðŸ´â€â˜ ï¸", {"ðŸ³ï¸â€âš§ï¸", "🧑â€ðŸŒ¾", "â¤ï¸", "😂", "ðŸ´â€â˜ ï¸"}) + check('ðŸ³ï¸â€âš§ï¸xy🧑â€ðŸŒ¾\râ¤ï¸ðŸ˜‚Ã¥ðŸ´â€â˜ ï¸Â€', { 'ðŸ³ï¸â€âš§ï¸', '🧑â€ðŸŒ¾', 'â¤ï¸', '😂', 'Ã¥', 'ðŸ´â€â˜ ï¸', '€' }) + check('ðŸ³ï¸â€âš§ï¸\000🧑â€ðŸŒ¾\000â¤ï¸\000😂\000Ã¥\000ðŸ´â€â˜ ï¸\000€', { 'ðŸ³ï¸â€âš§ï¸', '🧑â€ðŸŒ¾', 'â¤ï¸', '😂', 'Ã¥', 'ðŸ´â€â˜ ï¸', '€' }) + check('\195ðŸ³ï¸â€âš§ï¸\198🧑â€ðŸŒ¾\165â¤ï¸\168\195😂\255ðŸ´â€â˜ ï¸\129€\165', { 'ðŸ³ï¸â€âš§ï¸', '🧑â€ðŸŒ¾', 'â¤ï¸', '😂', 'ðŸ´â€â˜ ï¸', '€' }) + + check('ðŸ‡¦ðŸ…±ï¸ ðŸ‡¦ðŸ‡½ 🇦🇨🇦 🇲🇽🇹🇱',{'🇦', '🅱ï¸', '🇦🇽', '🇦🇨', '🇦', '🇲🇽', '🇹🇱'}) + check('ðŸ´ó §ó ¢ó ³ó £ó ´ó ¿ðŸ´ó §ó ¢ó ·ó ¬ó ³ó ¿', {'ðŸ´ó §ó ¢ó ³ó £ó ´ó ¿', 'ðŸ´ó §ó ¢ó ·ó ¬ó ³ó ¿'}) + + check('Ã¥\165ü\195aëq\168β\000\169本\255', {'Ã¥', 'ü', 'ë', 'β', '本'}) + + lib.p_arshape = true -- default + check('سلام', { 'س', 'لا', 'Ù…' }) + lib.p_arshape = false + check('سلام', { 'س', 'Ù„', 'ا', 'Ù…' }) + + check('L̓̉̑̒̌̚ơ̗̌̒̄̀rÌ̈̈̎̕Ìè̇̅̄̄Ìm̖̟̟̅̄̚', {'L̓̉̑̒̌̚', 'ơ̗̌̒̄̀', 'rÌ̈̈̎̕Ì', 'è̇̅̄̄Ì', 'm̖̟̟̅̄̚'}) + -- stylua: ignore end + end) + + describe('utf_fold', function() + itp('does not crash with surrogates #30527', function() + eq(0xddfb, lib.utf_fold(0xddfb)) -- low surrogate, invalid as a character + eq(0xd800, lib.utf_fold(0xd800)) -- high surrogate, invalid as a character + end) + + itp("doesn't crash on invalid codepoints", function() + eq(9000000, lib.utf_fold(9000000)) + eq(0, lib.utf_fold(0)) + end) + end) end) diff --git a/test/unit/path_spec.lua b/test/unit/path_spec.lua index 6f6a80f44e..ffad552a8a 100644 --- a/test/unit/path_spec.lua +++ b/test/unit/path_spec.lua @@ -468,8 +468,11 @@ describe('path.c', function() eq(OK, result) end) - itp('concatenates directory name if it does not contain a slash', function() - local expected = uv.cwd() .. '/..' + itp('produces absolute path for .. without a slash', function() + local old_dir = uv.cwd() + uv.chdir('..') + local expected = uv.cwd() + uv.chdir(old_dir) local filename = '..' local buflen = get_buf_len(expected, filename) local do_expand = 1 @@ -478,21 +481,18 @@ describe('path.c', function() eq(OK, result) end) - itp( - 'enters given directory (instead of just concatenating the strings) if possible and if path contains a slash', - function() - local old_dir = uv.cwd() - uv.chdir('..') - local expected = uv.cwd() .. '/test.file' - uv.chdir(old_dir) - local filename = '../test.file' - local buflen = get_buf_len(expected, filename) - local do_expand = 1 - local buf, result = vim_FullName(filename, buflen, do_expand) - eq(expected, ffi.string(buf)) - eq(OK, result) - end - ) + itp('produces absolute path if possible and if path contains a slash', function() + local old_dir = uv.cwd() + uv.chdir('..') + local expected = uv.cwd() .. '/test.file' + uv.chdir(old_dir) + local filename = '../test.file' + local buflen = get_buf_len(expected, filename) + local do_expand = 1 + local buf, result = vim_FullName(filename, buflen, do_expand) + eq(expected, ffi.string(buf)) + eq(OK, result) + end) itp('just copies the path if it is already absolute and force=0', function() local absolute_path = '/absolute/path' diff --git a/test/unit/rbuffer_spec.lua b/test/unit/rbuffer_spec.lua deleted file mode 100644 index ad18ea2ddc..0000000000 --- a/test/unit/rbuffer_spec.lua +++ /dev/null @@ -1,340 +0,0 @@ -local t = require('test.unit.testutil') -local itp = t.gen_itp(it) - -local eq = t.eq -local ffi = t.ffi -local cstr = t.cstr -local to_cstr = t.to_cstr -local child_call_once = t.child_call_once - -local rbuffer = t.cimport('./test/unit/fixtures/rbuffer.h') - -describe('rbuffer functions', function() - local capacity = 16 - local rbuf - - local function inspect() - return ffi.string(rbuf.start_ptr, capacity) - end - - local function write(str) - local buf = to_cstr(str) - return rbuffer.rbuffer_write(rbuf, buf, #str) - end - - local function read(len) - local buf = cstr(len) - len = rbuffer.rbuffer_read(rbuf, buf, len) - return ffi.string(buf, len) - end - - local function get(idx) - return ffi.string(rbuffer.rbuffer_get(rbuf, idx), 1) - end - - before_each(function() - child_call_once(function() - rbuf = ffi.gc(rbuffer.rbuffer_new(capacity), rbuffer.rbuffer_free) - -- fill the internal buffer with the character '0' to simplify inspecting - ffi.C.memset(rbuf.start_ptr, string.byte('0'), capacity) - end) - end) - - describe('RBUFFER_UNTIL_FULL', function() - local chunks - - local function collect_write_chunks() - rbuffer.ut_rbuffer_each_write_chunk(rbuf, function(wptr, wcnt) - table.insert(chunks, ffi.string(wptr, wcnt)) - end) - end - - before_each(function() - chunks = {} - end) - - describe('with empty buffer in one contiguous chunk', function() - itp('is called once with the empty chunk', function() - collect_write_chunks() - eq({ '0000000000000000' }, chunks) - end) - end) - - describe('with partially empty buffer in one contiguous chunk', function() - itp('is called once with the empty chunk', function() - write('string') - collect_write_chunks() - eq({ '0000000000' }, chunks) - end) - end) - - describe('with filled buffer in one contiguous chunk', function() - itp('is not called', function() - write('abcdefghijklmnopq') - collect_write_chunks() - eq({}, chunks) - end) - end) - - describe('with buffer partially empty in two contiguous chunks', function() - itp('is called twice with each filled chunk', function() - write('1234567890') - read(8) - collect_write_chunks() - eq({ '000000', '12345678' }, chunks) - end) - end) - - describe('with buffer empty in two contiguous chunks', function() - itp('is called twice with each filled chunk', function() - write('12345678') - read(8) - collect_write_chunks() - eq({ '00000000', '12345678' }, chunks) - end) - end) - - describe('with buffer filled in two contiguous chunks', function() - itp('is not called', function() - write('12345678') - read(8) - write('abcdefghijklmnopq') - collect_write_chunks() - eq({}, chunks) - end) - end) - end) - - describe('RBUFFER_UNTIL_EMPTY', function() - local chunks - - local function collect_read_chunks() - rbuffer.ut_rbuffer_each_read_chunk(rbuf, function(rptr, rcnt) - table.insert(chunks, ffi.string(rptr, rcnt)) - end) - end - - before_each(function() - chunks = {} - end) - - describe('with empty buffer', function() - itp('is not called', function() - collect_read_chunks() - eq({}, chunks) - end) - end) - - describe('with partially filled buffer in one contiguous chunk', function() - itp('is called once with the filled chunk', function() - write('string') - collect_read_chunks() - eq({ 'string' }, chunks) - end) - end) - - describe('with filled buffer in one contiguous chunk', function() - itp('is called once with the filled chunk', function() - write('abcdefghijklmnopq') - collect_read_chunks() - eq({ 'abcdefghijklmnop' }, chunks) - end) - end) - - describe('with buffer partially filled in two contiguous chunks', function() - itp('is called twice with each filled chunk', function() - write('1234567890') - read(10) - write('long string') - collect_read_chunks() - eq({ 'long s', 'tring' }, chunks) - end) - end) - - describe('with buffer filled in two contiguous chunks', function() - itp('is called twice with each filled chunk', function() - write('12345678') - read(8) - write('abcdefghijklmnopq') - collect_read_chunks() - eq({ 'abcdefgh', 'ijklmnop' }, chunks) - end) - end) - end) - - describe('RBUFFER_EACH', function() - local chars - - local function collect_chars() - rbuffer.ut_rbuffer_each(rbuf, function(c, i) - table.insert(chars, { string.char(c), tonumber(i) }) - end) - end - before_each(function() - chars = {} - end) - - describe('with empty buffer', function() - itp('is not called', function() - collect_chars() - eq({}, chars) - end) - end) - - describe('with buffer filled in two contiguous chunks', function() - itp('collects each character and index', function() - write('1234567890') - read(10) - write('long string') - collect_chars() - eq({ - { 'l', 0 }, - { 'o', 1 }, - { 'n', 2 }, - { 'g', 3 }, - { ' ', 4 }, - { 's', 5 }, - { 't', 6 }, - { 'r', 7 }, - { 'i', 8 }, - { 'n', 9 }, - { 'g', 10 }, - }, chars) - end) - end) - end) - - describe('RBUFFER_EACH_REVERSE', function() - local chars - - local function collect_chars() - rbuffer.ut_rbuffer_each_reverse(rbuf, function(c, i) - table.insert(chars, { string.char(c), tonumber(i) }) - end) - end - before_each(function() - chars = {} - end) - - describe('with empty buffer', function() - itp('is not called', function() - collect_chars() - eq({}, chars) - end) - end) - - describe('with buffer filled in two contiguous chunks', function() - itp('collects each character and index', function() - write('1234567890') - read(10) - write('long string') - collect_chars() - eq({ - { 'g', 10 }, - { 'n', 9 }, - { 'i', 8 }, - { 'r', 7 }, - { 't', 6 }, - { 's', 5 }, - { ' ', 4 }, - { 'g', 3 }, - { 'n', 2 }, - { 'o', 1 }, - { 'l', 0 }, - }, chars) - end) - end) - end) - - describe('rbuffer_cmp', function() - local function cmp(str) - local rv = rbuffer.rbuffer_cmp(rbuf, to_cstr(str), #str) - if rv == 0 then - return 0 - else - return rv / math.abs(rv) - end - end - - describe('with buffer filled in two contiguous chunks', function() - itp('compares the common longest sequence', function() - write('1234567890') - read(10) - write('long string') - eq(0, cmp('long string')) - eq(0, cmp('long strin')) - eq(-1, cmp('long striM')) - eq(1, cmp('long strio')) - eq(0, cmp('long')) - eq(-1, cmp('lonG')) - eq(1, cmp('lonh')) - end) - end) - - describe('with empty buffer', function() - itp('returns 0 since no characters are compared', function() - eq(0, cmp('')) - end) - end) - end) - - describe('rbuffer_write', function() - itp('fills the internal buffer and returns the write count', function() - eq(12, write('short string')) - eq('short string0000', inspect()) - end) - - itp('wont write beyond capacity', function() - eq(16, write('very very long string')) - eq('very very long s', inspect()) - end) - end) - - describe('rbuffer_read', function() - itp('reads what was previously written', function() - write('to read') - eq('to read', read(20)) - end) - - itp('reads nothing if the buffer is empty', function() - eq('', read(20)) - write('empty') - eq('empty', read(20)) - eq('', read(20)) - end) - end) - - describe('rbuffer_get', function() - itp('fetch the pointer at offset, wrapping if required', function() - write('1234567890') - read(10) - write('long string') - eq('l', get(0)) - eq('o', get(1)) - eq('n', get(2)) - eq('g', get(3)) - eq(' ', get(4)) - eq('s', get(5)) - eq('t', get(6)) - eq('r', get(7)) - eq('i', get(8)) - eq('n', get(9)) - eq('g', get(10)) - end) - end) - - describe('wrapping behavior', function() - itp('writing/reading wraps across the end of the internal buffer', function() - write('1234567890') - eq('1234', read(4)) - eq('5678', read(4)) - write('987654321') - eq('3214567890987654', inspect()) - eq('90987654321', read(20)) - eq('', read(4)) - write('abcdefghijklmnopqrs') - eq('nopabcdefghijklm', inspect()) - eq('abcdefghijklmnop', read(20)) - end) - end) -end) diff --git a/test/unit/statusline_spec.lua b/test/unit/statusline_spec.lua index 973d9ec992..a97a4f41d7 100644 --- a/test/unit/statusline_spec.lua +++ b/test/unit/statusline_spec.lua @@ -56,14 +56,14 @@ describe('build_stl_str_hl', function() -- @param input_stl The format string for the statusline -- @param expected_stl The expected result string for the statusline -- - -- @param arg Options can be placed in an optional dictionary as the last parameter + -- @param arg Options can be placed in an optional dict as the last parameter -- .expected_cell_count The expected number of cells build_stl_str_hl will return -- .expected_byte_length The expected byte length of the string (defaults to byte length of expected_stl) -- .file_name The name of the file to be tested (useful in %f type tests) -- .fillchar The character that will be used to fill any 'extra' space in the stl local function statusline_test(description, statusline_cell_count, input_stl, expected_stl, arg) -- arg is the optional parameter - -- so we either fill in option with arg or an empty dictionary + -- so we either fill in option with arg or an empty dict local option = arg or {} local fillchar = option.fillchar or ' ' diff --git a/test/unit/termkey_spec.lua b/test/unit/termkey_spec.lua new file mode 100644 index 0000000000..0381cfd15a --- /dev/null +++ b/test/unit/termkey_spec.lua @@ -0,0 +1,975 @@ +local t = require('test.unit.testutil') +local itp = t.gen_itp(it) +local bit = require('bit') + +--- @alias TermKeyKey {utf8: string, type: integer, modifiers: integer, code: {codepoint: integer, sym: any, number: integer}} + +--- @class termkey +--- @field TERMKEY_CANON_SPACESYMBOL integer +--- @field TERMKEY_FLAG_SPACESYMBOL integer +--- @field TERMKEY_FLAG_UTF8 integer +--- @field TERMKEY_FORMAT_ALTISMETA integer +--- @field TERMKEY_FORMAT_CARETCTRL integer +--- @field TERMKEY_FORMAT_LONGMOD integer +--- @field TERMKEY_FORMAT_LOWERMOD integer +--- @field TERMKEY_FORMAT_LOWERSPACE integer +--- @field TERMKEY_FORMAT_MOUSE_POS integer +--- @field TERMKEY_FORMAT_SPACEMOD integer +--- @field TERMKEY_FORMAT_WRAPBRACKET integer +--- @field TERMKEY_KEYMOD_ALT integer +--- @field TERMKEY_KEYMOD_CTRL integer +--- @field TERMKEY_MOUSE_DRAG integer +--- @field TERMKEY_MOUSE_PRESS integer +--- @field TERMKEY_MOUSE_RELEASE integer +--- @field TERMKEY_RES_AGAIN integer +--- @field TERMKEY_RES_KEY integer +--- @field TERMKEY_RES_NONE integer +--- @field TERMKEY_SYM_DOWN integer +--- @field TERMKEY_SYM_PAGEUP integer +--- @field TERMKEY_SYM_SPACE integer +--- @field TERMKEY_SYM_UNKNOWN integer +--- @field TERMKEY_SYM_UP integer +--- @field TERMKEY_TYPE_DCS integer +--- @field TERMKEY_TYPE_FUNCTION integer +--- @field TERMKEY_TYPE_KEYSYM integer +--- @field TERMKEY_TYPE_MODEREPORT integer +--- @field TERMKEY_TYPE_MOUSE integer +--- @field TERMKEY_TYPE_OSC integer +--- @field TERMKEY_TYPE_POSITION integer +--- @field TERMKEY_TYPE_UNICODE integer +--- @field TERMKEY_TYPE_UNKNOWN_CSI integer +--- @field termkey_canonicalise fun(any, any):any +--- @field termkey_destroy fun(any) +--- @field termkey_get_buffer_remaining fun(any):integer +--- @field termkey_get_buffer_size fun(any):integer +--- @field termkey_get_canonflags fun(any):any +--- @field termkey_get_keyname fun(any, any):any +--- @field termkey_getkey fun(any, any):any +--- @field termkey_getkey_force fun(any, any):any +--- @field termkey_interpret_csi fun(any, any, any, any, any):any +--- @field termkey_interpret_modereport fun(any, any, any, any, any):any +--- @field termkey_interpret_mouse fun(any, any, TermKeyKey, integer, integer, integer):any +--- @field termkey_interpret_position fun(any, any, any, any):any +--- @field termkey_interpret_string fun(any, TermKeyKey, any):any +--- @field termkey_lookup_keyname fun(any, any, any):any +--- @field termkey_new_abstract fun(string, integer):any +--- @field termkey_push_bytes fun(any, string, integer):integer +--- @field termkey_set_buffer_size fun(any, integer):integer +--- @field termkey_set_canonflags fun(any, any):any +--- @field termkey_set_flags fun(any, integer) +--- @field termkey_start fun(any):integer +--- @field termkey_stop fun(any):integer +--- @field termkey_strfkey fun(any, string, integer, any, any):integer +local termkey = t.cimport( + './src/nvim/tui/termkey/termkey.h', + './src/nvim/tui/termkey/termkey-internal.h', + './src/nvim/tui/termkey/termkey_defs.h', + './src/nvim/tui/termkey/driver-csi.h' +) + +describe('termkey', function() + itp('01base', function() + local tk = termkey.termkey_new_abstract('vt100', 0) + t.neq(tk, nil) + + t.eq(termkey.termkey_get_buffer_size(tk), 256) + t.eq(tk.is_started, 1) -- tk->is_started true after construction + + termkey.termkey_stop(tk) + t.neq(tk.is_started, 1) -- tk->is_started false after termkey_stop() + + termkey.termkey_start(tk) + t.eq(tk.is_started, 1) -- tk->is_started true after termkey_start() + + termkey.termkey_destroy(tk) + end) + + itp('02getkey', function() + local tk = termkey.termkey_new_abstract('vt100', 0) + local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey + + t.eq(termkey.termkey_get_buffer_remaining(tk), 256) -- buffer free initially 256 + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_NONE) -- getkey yields RES_NONE when empty + + t.eq(termkey.termkey_push_bytes(tk, 'h', 1), 1) -- push_bytes returns 1 + + t.eq(termkey.termkey_get_buffer_remaining(tk), 255) -- buffer free 255 after push_bytes + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after h + + t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type after h + t.eq(key.code.codepoint, string.byte('h')) -- key.code.codepoint after h + t.eq(key.modifiers, 0) -- key.modifiers after h + t.eq(t.ffi.string(key.utf8), 'h') -- key.utf8 after h + + t.eq(termkey.termkey_get_buffer_remaining(tk), 256) -- buffer free 256 after getkey + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_NONE) -- getkey yields RES_NONE a second time + + termkey.termkey_push_bytes(tk, '\x01', 1) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after C-a + + t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type after C-a + t.eq(key.code.codepoint, string.byte('a')) -- key.code.codepoint after C-a + t.eq(key.modifiers, termkey.TERMKEY_KEYMOD_CTRL) -- key.modifiers after C-a + + termkey.termkey_push_bytes(tk, '\033OA', 3) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after Up + + -- is_int(key.type, TERMKEY_TYPE_KEYSYM, "key.type after Up"); + -- is_int(key.code.sym, TERMKEY_SYM_UP, "key.code.sym after Up"); + t.eq(key.modifiers, 0) -- key.modifiers after Up + + t.eq(termkey.termkey_push_bytes(tk, '\033O', 2), 2) -- push_bytes returns 2 + + -- is_int(termkey_get_buffer_remaining(tk), 254, "buffer free 254 after partial write"); + + -- is_int(termkey_getkey(tk, &key), TERMKEY_RES_AGAIN, "getkey yields RES_AGAIN after partial write"); + + termkey.termkey_push_bytes(tk, 'C', 1) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after Right completion + + -- is_int(key.type, TERMKEY_TYPE_KEYSYM, "key.type after Right"); + -- is_int(key.code.sym, TERMKEY_SYM_RIGHT, "key.code.sym after Right"); + -- is_int(key.modifiers, 0, "key.modifiers after Right"); + + -- is_int(termkey_get_buffer_remaining(tk), 256, "buffer free 256 after completion"); + + termkey.termkey_push_bytes(tk, '\033[27;5u', 7) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after Ctrl-Escape + + -- is_int(key.type, TERMKEY_TYPE_KEYSYM, "key.type after Ctrl-Escape"); + -- is_int(key.code.sym, TERMKEY_SYM_ESCAPE, "key.code.sym after Ctrl-Escape"); + -- is_int(key.modifiers, TERMKEY_KEYMOD_CTRL, "key.modifiers after Ctrl-Escape"); + + termkey.termkey_push_bytes(tk, '\0', 1) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after Ctrl-Space + + t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type after Ctrl-Space + -- t.eq(key.code.codepoint, string.byte(' ')) -- key.code.codepoint after Ctrl-Space + -- is_int(key.modifiers, TERMKEY_KEYMOD_CTRL, "key.modifiers after Ctrl-Space"); + + termkey.termkey_destroy(tk) + end) + + itp('03utf8', function() + local tk = termkey.termkey_new_abstract('vt100', termkey.TERMKEY_FLAG_UTF8) + local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey + + termkey.termkey_push_bytes(tk, 'a', 1) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY low ASCII + t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type low ASCII + t.eq(key.code.codepoint, string.byte('a')) -- key.code.codepoint low ASCII + + -- 2-byte UTF-8 range is U+0080 to U+07FF (0xDF 0xBF) + -- However, we'd best avoid the C1 range, so we'll start at U+00A0 (0xC2 0xA0) + + termkey.termkey_push_bytes(tk, '\xC2\xA0', 2) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 2 low + t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type UTF-8 2 low + t.eq(key.code.codepoint, 0x00A0) -- key.code.codepoint UTF-8 2 low + + termkey.termkey_push_bytes(tk, '\xDF\xBF', 2) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 2 high + t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type UTF-8 2 high + t.eq(key.code.codepoint, 0x07FF) -- key.code.codepoint UTF-8 2 high + + -- 3-byte UTF-8 range is U+0800 (0xE0 0xA0 0x80) to U+FFFD (0xEF 0xBF 0xBD) + + termkey.termkey_push_bytes(tk, '\xE0\xA0\x80', 3) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 low + t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type UTF-8 3 low + t.eq(key.code.codepoint, 0x0800) -- key.code.codepoint UTF-8 3 low + + termkey.termkey_push_bytes(tk, '\xEF\xBF\xBD', 3) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 high + t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type UTF-8 3 high + t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 3 high + + -- 4-byte UTF-8 range is U+10000 (0xF0 0x90 0x80 0x80) to U+10FFFF (0xF4 0x8F 0xBF 0xBF) + + termkey.termkey_push_bytes(tk, '\xF0\x90\x80\x80', 4) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 low + t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type UTF-8 4 low + t.eq(key.code.codepoint, 0x10000) -- key.code.codepoint UTF-8 4 low + + termkey.termkey_push_bytes(tk, '\xF4\x8F\xBF\xBF', 4) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 high + t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type UTF-8 4 high + t.eq(key.code.codepoint, 0x10FFFF) -- key.code.codepoint UTF-8 4 high + + -- Invalid continuations + + termkey.termkey_push_bytes(tk, '\xC2!', 2) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 2 invalid cont + t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 2 invalid cont + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 2 invalid after + t.eq(key.code.codepoint, string.byte('!')) -- key.code.codepoint UTF-8 2 invalid after + + termkey.termkey_push_bytes(tk, '\xE0!', 2) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 invalid cont + t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 3 invalid cont + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 invalid after + t.eq(key.code.codepoint, string.byte('!')) -- key.code.codepoint UTF-8 3 invalid after + + termkey.termkey_push_bytes(tk, '\xE0\xA0!', 3) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 invalid cont 2 + t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 3 invalid cont 2 + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 invalid after + t.eq(key.code.codepoint, string.byte('!')) -- key.code.codepoint UTF-8 3 invalid after + + termkey.termkey_push_bytes(tk, '\xF0!', 2) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 invalid cont + t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 4 invalid cont + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 invalid after + t.eq(key.code.codepoint, string.byte('!')) -- key.code.codepoint UTF-8 4 invalid after + + termkey.termkey_push_bytes(tk, '\xF0\x90!', 3) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 invalid cont 2 + t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 4 invalid cont 2 + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 invalid after + t.eq(key.code.codepoint, string.byte('!')) -- key.code.codepoint UTF-8 4 invalid after + + termkey.termkey_push_bytes(tk, '\xF0\x90\x80!', 4) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 invalid cont 3 + t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 4 invalid cont 3 + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 invalid after + t.eq(key.code.codepoint, string.byte('!')) -- key.code.codepoint UTF-8 4 invalid after + + -- Partials + + termkey.termkey_push_bytes(tk, '\xC2', 1) + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN UTF-8 2 partial + + termkey.termkey_push_bytes(tk, '\xA0', 1) + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 2 partial + t.eq(key.code.codepoint, 0x00A0) -- key.code.codepoint UTF-8 2 partial + + termkey.termkey_push_bytes(tk, '\xE0', 1) + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN UTF-8 3 partial + + termkey.termkey_push_bytes(tk, '\xA0', 1) + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN UTF-8 3 partial + + termkey.termkey_push_bytes(tk, '\x80', 1) + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 partial + t.eq(key.code.codepoint, 0x0800) -- key.code.codepoint UTF-8 3 partial + + termkey.termkey_push_bytes(tk, '\xF0', 1) + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN UTF-8 4 partial + + termkey.termkey_push_bytes(tk, '\x90', 1) + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN UTF-8 4 partial + + termkey.termkey_push_bytes(tk, '\x80', 1) + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN UTF-8 4 partial + + termkey.termkey_push_bytes(tk, '\x80', 1) + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 partial + t.eq(key.code.codepoint, 0x10000) -- key.code.codepoint UTF-8 4 partial + + termkey.termkey_destroy(tk) + end) + + itp('04flags', function() + local tk = termkey.termkey_new_abstract('vt100', 0) + local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey + + termkey.termkey_push_bytes(tk, ' ', 1) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after space + + t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type after space + t.eq(key.code.codepoint, string.byte(' ')) -- key.code.codepoint after space + t.eq(key.modifiers, 0) -- key.modifiers after space + + termkey.termkey_set_flags(tk, termkey.TERMKEY_FLAG_SPACESYMBOL) + + termkey.termkey_push_bytes(tk, ' ', 1) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after space + + t.eq(key.type, termkey.TERMKEY_TYPE_KEYSYM) -- key.type after space with FLAG_SPACESYMBOL + t.eq(key.code.sym, termkey.TERMKEY_SYM_SPACE) -- key.code.sym after space with FLAG_SPACESYMBOL + t.eq(key.modifiers, 0) -- key.modifiers after space with FLAG_SPACESYMBOL + + termkey.termkey_destroy(tk) + end) + + itp('06buffer', function() + local tk = termkey.termkey_new_abstract('vt100', 0) + local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey + + t.eq(termkey.termkey_get_buffer_remaining(tk), 256) -- buffer free initially 256 + t.eq(termkey.termkey_get_buffer_size(tk), 256) -- buffer size initially 256 + + t.eq(termkey.termkey_push_bytes(tk, 'h', 1), 1) -- push_bytes returns 1 + + t.eq(termkey.termkey_get_buffer_remaining(tk), 255) -- buffer free 255 after push_bytes + t.eq(termkey.termkey_get_buffer_size(tk), 256) -- buffer size 256 after push_bytes + + t.eq(not not termkey.termkey_set_buffer_size(tk, 512), true) -- buffer set size OK + + t.eq(termkey.termkey_get_buffer_remaining(tk), 511) -- buffer free 511 after push_bytes + t.eq(termkey.termkey_get_buffer_size(tk), 512) -- buffer size 512 after push_bytes + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- buffered key still usable after resize + + termkey.termkey_destroy(tk) + end) + + local function termkey_keyname2sym(tk, keyname) + local sym = t.ffi.new('TermKeySym[1]') + local endp = termkey.termkey_lookup_keyname(tk, keyname, sym) + if endp == nil then + return termkey.TERMKEY_SYM_UNKNOWN + end + return sym + end + + itp('10keyname', function() + local tk = termkey.termkey_new_abstract('vt100', 0) + + local sym = termkey_keyname2sym(tk, 'SomeUnknownKey') + t.eq(sym, termkey.TERMKEY_SYM_UNKNOWN) -- keyname2sym SomeUnknownKey + + sym = termkey_keyname2sym(tk, 'Space') + t.eq(sym[0], termkey.TERMKEY_SYM_SPACE) -- keyname2sym Space + + local _end = termkey.termkey_lookup_keyname(tk, 'Up', sym) + t.neq(_end, nil) -- termkey_get_keyname Up returns non-NULL + t.eq(t.ffi.string(_end), '') -- termkey_get_keyname Up return points at endofstring + t.eq(sym[0], termkey.TERMKEY_SYM_UP) -- termkey_get_keyname Up yields Up symbol + + _end = termkey.termkey_lookup_keyname(tk, 'DownMore', sym) + t.neq(_end, nil) -- termkey_get_keyname DownMore returns non-NULL + t.eq(t.ffi.string(_end), 'More') -- termkey_get_keyname DownMore return points at More + t.eq(sym[0], termkey.TERMKEY_SYM_DOWN) -- termkey_get_keyname DownMore yields Down symbol + + _end = termkey.termkey_lookup_keyname(tk, 'SomeUnknownKey', sym) + t.eq(_end, nil) -- termkey_get_keyname SomeUnknownKey returns NULL + + t.eq(t.ffi.string(termkey.termkey_get_keyname(tk, termkey.TERMKEY_SYM_SPACE)), 'Space') -- "get_keyname SPACE"); + + termkey.termkey_destroy(tk) + end) + + itp('11strfkey', function() + local tk = termkey.termkey_new_abstract('vt100', 0) + ---@type TermKeyKey + local key = t.ffi.new( + 'TermKeyKey', + { type = termkey.TERMKEY_TYPE_UNICODE, code = { codepoint = string.byte('A') } } + ) + local buffer = t.ffi.new('char[16]') + + local len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0) + t.eq(len, 1) -- length for unicode/A/0 + t.eq(t.ffi.string(buffer), 'A') -- buffer for unicode/A/0 + + len = termkey.termkey_strfkey( + tk, + buffer, + t.ffi.sizeof(buffer), + key, + termkey.TERMKEY_FORMAT_WRAPBRACKET + ) + t.eq(len, 1) -- length for unicode/A/0 wrapbracket + t.eq(t.ffi.string(buffer), 'A') -- buffer for unicode/A/0 wrapbracket + + ---@type TermKeyKey + key = t.ffi.new('TermKeyKey', { + type = termkey.TERMKEY_TYPE_UNICODE, + code = { codepoint = string.byte('b') }, + modifiers = termkey.TERMKEY_KEYMOD_CTRL, + }) + + len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0) + t.eq(len, 3) -- length for unicode/b/CTRL + t.eq(t.ffi.string(buffer), 'C-b') -- buffer for unicode/b/CTRL + + len = + termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, termkey.TERMKEY_FORMAT_LONGMOD) + t.eq(len, 6) -- length for unicode/b/CTRL longmod + t.eq(t.ffi.string(buffer), 'Ctrl-b') -- buffer for unicode/b/CTRL longmod + + len = termkey.termkey_strfkey( + tk, + buffer, + t.ffi.sizeof(buffer), + key, + bit.bor(termkey.TERMKEY_FORMAT_LONGMOD, termkey.TERMKEY_FORMAT_SPACEMOD) + ) + t.eq(len, 6) -- length for unicode/b/CTRL longmod|spacemod + t.eq(t.ffi.string(buffer), 'Ctrl b') -- buffer for unicode/b/CTRL longmod|spacemod + + len = termkey.termkey_strfkey( + tk, + buffer, + t.ffi.sizeof(buffer), + key, + bit.bor(termkey.TERMKEY_FORMAT_LONGMOD, termkey.TERMKEY_FORMAT_LOWERMOD) + ) + t.eq(len, 6) -- length for unicode/b/CTRL longmod|lowermod + t.eq(t.ffi.string(buffer), 'ctrl-b') -- buffer for unicode/b/CTRL longmod|lowermod + + len = termkey.termkey_strfkey( + tk, + buffer, + t.ffi.sizeof(buffer), + key, + bit.bor( + termkey.TERMKEY_FORMAT_LONGMOD, + termkey.TERMKEY_FORMAT_SPACEMOD, + termkey.TERMKEY_FORMAT_LOWERMOD + ) + ) + t.eq(len, 6) -- length for unicode/b/CTRL longmod|spacemod|lowermode + t.eq(t.ffi.string(buffer), 'ctrl b') -- buffer for unicode/b/CTRL longmod|spacemod|lowermode + + len = termkey.termkey_strfkey( + tk, + buffer, + t.ffi.sizeof(buffer), + key, + termkey.TERMKEY_FORMAT_CARETCTRL + ) + t.eq(len, 2) -- length for unicode/b/CTRL caretctrl + t.eq(t.ffi.string(buffer), '^B') -- buffer for unicode/b/CTRL caretctrl + + len = termkey.termkey_strfkey( + tk, + buffer, + t.ffi.sizeof(buffer), + key, + termkey.TERMKEY_FORMAT_WRAPBRACKET + ) + t.eq(len, 5) -- length for unicode/b/CTRL wrapbracket + t.eq(t.ffi.string(buffer), '<C-b>') -- buffer for unicode/b/CTRL wrapbracket + + ---@type TermKeyKey + key = t.ffi.new('TermKeyKey', { + type = termkey.TERMKEY_TYPE_UNICODE, + code = { codepoint = string.byte('c') }, + modifiers = termkey.TERMKEY_KEYMOD_ALT, + }) + + len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0) + t.eq(len, 3) -- length for unicode/c/ALT + t.eq(t.ffi.string(buffer), 'A-c') -- buffer for unicode/c/ALT + + len = + termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, termkey.TERMKEY_FORMAT_LONGMOD) + t.eq(len, 5) -- length for unicode/c/ALT longmod + t.eq(t.ffi.string(buffer), 'Alt-c') -- buffer for unicode/c/ALT longmod + + len = termkey.termkey_strfkey( + tk, + buffer, + t.ffi.sizeof(buffer), + key, + termkey.TERMKEY_FORMAT_ALTISMETA + ) + t.eq(len, 3) -- length for unicode/c/ALT altismeta + t.eq(t.ffi.string(buffer), 'M-c') -- buffer for unicode/c/ALT altismeta + + len = termkey.termkey_strfkey( + tk, + buffer, + t.ffi.sizeof(buffer), + key, + bit.bor(termkey.TERMKEY_FORMAT_LONGMOD, termkey.TERMKEY_FORMAT_ALTISMETA) + ) + t.eq(len, 6) -- length for unicode/c/ALT longmod|altismeta + t.eq(t.ffi.string(buffer), 'Meta-c') -- buffer for unicode/c/ALT longmod|altismeta + + ---@type TermKeyKey + key = t.ffi.new( + 'TermKeyKey', + { type = termkey.TERMKEY_TYPE_KEYSYM, code = { sym = termkey.TERMKEY_SYM_UP } } + ) + + len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0) + t.eq(len, 2) -- length for sym/Up/0 + t.eq(t.ffi.string(buffer), 'Up') -- buffer for sym/Up/0 + + len = termkey.termkey_strfkey( + tk, + buffer, + t.ffi.sizeof(buffer), + key, + termkey.TERMKEY_FORMAT_WRAPBRACKET + ) + t.eq(len, 4) -- length for sym/Up/0 wrapbracket + t.eq(t.ffi.string(buffer), '<Up>') -- buffer for sym/Up/0 wrapbracket + + ---@type TermKeyKey + key = t.ffi.new( + 'TermKeyKey', + { type = termkey.TERMKEY_TYPE_KEYSYM, code = { sym = termkey.TERMKEY_SYM_PAGEUP } } + ) + + len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0) + t.eq(len, 6) -- length for sym/PageUp/0 + t.eq(t.ffi.string(buffer), 'PageUp') -- buffer for sym/PageUp/0 + + len = termkey.termkey_strfkey( + tk, + buffer, + t.ffi.sizeof(buffer), + key, + termkey.TERMKEY_FORMAT_LOWERSPACE + ) + t.eq(len, 7) -- length for sym/PageUp/0 lowerspace + t.eq(t.ffi.string(buffer), 'page up') -- buffer for sym/PageUp/0 lowerspace + + -- If size of buffer is too small, strfkey should return something consistent + len = termkey.termkey_strfkey(tk, buffer, 4, key, 0) + t.eq(len, 6) -- length for sym/PageUp/0 + t.eq(t.ffi.string(buffer), 'Pag') -- buffer of len 4 for sym/PageUp/0 + + len = termkey.termkey_strfkey(tk, buffer, 4, key, termkey.TERMKEY_FORMAT_LOWERSPACE) + t.eq(len, 7) -- length for sym/PageUp/0 lowerspace + t.eq(t.ffi.string(buffer), 'pag') -- buffer of len 4 for sym/PageUp/0 lowerspace + + key = t.ffi.new('TermKeyKey', { type = termkey.TERMKEY_TYPE_FUNCTION, code = { number = 5 } }) ---@type TermKeyKey + + len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0) + t.eq(len, 2) -- length for func/5/0 + t.eq(t.ffi.string(buffer), 'F5') -- buffer for func/5/0 + + len = termkey.termkey_strfkey( + tk, + buffer, + t.ffi.sizeof(buffer), + key, + termkey.TERMKEY_FORMAT_WRAPBRACKET + ) + t.eq(len, 4) -- length for func/5/0 wrapbracket + t.eq(t.ffi.string(buffer), '<F5>') -- buffer for func/5/0 wrapbracket + + len = termkey.termkey_strfkey( + tk, + buffer, + t.ffi.sizeof(buffer), + key, + termkey.TERMKEY_FORMAT_LOWERSPACE + ) + t.eq(len, 2) -- length for func/5/0 lowerspace + t.eq(t.ffi.string(buffer), 'f5') -- buffer for func/5/0 lowerspace + + termkey.termkey_destroy(tk) + end) + + itp('13cmpkey', function() + local function termkey_keycmp(tk, key1, key2) + termkey.termkey_canonicalise(tk, key1) + termkey.termkey_canonicalise(tk, key2) + + if key1.type ~= key2.type then + return key1.type - key2.type + end + + if key1.type == termkey.TERMKEY_TYPE_UNICODE then + if key1.code.codepoint ~= key2.code.codepoint then + return key1.code.codepoint - key2.code.codepoint + end + end + + return key1.modifiers - key2.modifiers + end + + local tk = termkey.termkey_new_abstract('vt100', 0) + ---@type TermKeyKey + local key1 = t.ffi.new('TermKeyKey', { + type = termkey.TERMKEY_TYPE_UNICODE, + code = { codepoint = string.byte('A') }, + modifiers = 0, + }) + ---@type TermKeyKey + local key2 = t.ffi.new('TermKeyKey', { + type = termkey.TERMKEY_TYPE_UNICODE, + code = { codepoint = string.byte('A') }, + modifiers = 0, + }) + + t.eq(termkey_keycmp(tk, key1, key1), 0) -- cmpkey same structure + t.eq(termkey_keycmp(tk, key1, key2), 0) -- cmpkey identical structure + + key2.modifiers = termkey.TERMKEY_KEYMOD_CTRL + + t.eq(termkey_keycmp(tk, key1, key2) < 0, true) -- cmpkey orders CTRL after nomod + t.eq(termkey_keycmp(tk, key2, key1) > 0, true) -- cmpkey orders nomod before CTRL + + key2.code.codepoint = string.byte('B') + key2.modifiers = 0 + + t.eq(termkey_keycmp(tk, key1, key2) < 0, true) -- cmpkey orders 'B' after 'A' + t.eq(termkey_keycmp(tk, key2, key1) > 0, true) -- cmpkey orders 'A' before 'B' + + key1.modifiers = termkey.TERMKEY_KEYMOD_CTRL + + t.eq(termkey_keycmp(tk, key1, key2) < 0, true) -- cmpkey orders nomod 'B' after CTRL 'A' + t.eq(termkey_keycmp(tk, key2, key1) > 0, true) -- cmpkey orders CTRL 'A' before nomod 'B' + + key2.type = termkey.TERMKEY_TYPE_KEYSYM + key2.code.sym = termkey.TERMKEY_SYM_UP + + t.eq(termkey_keycmp(tk, key1, key2) < 0, true) -- cmpkey orders KEYSYM after UNICODE + t.eq(termkey_keycmp(tk, key2, key1) > 0, true) -- cmpkey orders UNICODE before KEYSYM + + key1.type = termkey.TERMKEY_TYPE_KEYSYM + key1.code.sym = termkey.TERMKEY_SYM_SPACE + key1.modifiers = 0 + key2.type = termkey.TERMKEY_TYPE_UNICODE + key2.code.codepoint = string.byte(' ') + key2.modifiers = 0 + + t.eq(termkey_keycmp(tk, key1, key2), 0) -- cmpkey considers KEYSYM/SPACE and UNICODE/SP identical + + termkey.termkey_set_canonflags( + tk, + bit.bor(termkey.termkey_get_canonflags(tk), termkey.TERMKEY_CANON_SPACESYMBOL) + ) + t.eq(termkey_keycmp(tk, key1, key2), 0) -- "cmpkey considers KEYSYM/SPACE and UNICODE/SP identical under SPACESYMBOL"); + + termkey.termkey_destroy(tk) + end) + + itp('30mouse', function() + local tk = termkey.termkey_new_abstract('vt100', 0) + local key = t.ffi.new('TermKeyKey', { type = -1 }) ---@type TermKeyKey + local ev = t.ffi.new('TermKeyMouseEvent[1]') + local button = t.ffi.new('int[1]') + local line = t.ffi.new('int[1]') + local col = t.ffi.new('int[1]') + local buffer = t.ffi.new('char[32]') + + termkey.termkey_push_bytes(tk, '\x1b[M !!', 6) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mouse press + + t.eq(key.type, termkey.TERMKEY_TYPE_MOUSE) -- key.type for mouse press + + t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY + + t.eq(ev[0], termkey.TERMKEY_MOUSE_PRESS) -- mouse event for press + t.eq(button[0], 1) -- mouse button for press + t.eq(line[0], 1) -- mouse line for press + t.eq(col[0], 1) -- mouse column for press + t.eq(key.modifiers, 0) -- modifiers for press + + local len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0) + t.eq(len, 13) -- string length for press + t.eq(t.ffi.string(buffer), 'MousePress(1)') -- string buffer for press + + len = termkey.termkey_strfkey( + tk, + buffer, + t.ffi.sizeof(buffer), + key, + termkey.TERMKEY_FORMAT_MOUSE_POS + ) + t.eq(len, 21) -- string length for press + t.eq(t.ffi.string(buffer), 'MousePress(1) @ (1,1)') -- string buffer for press + + termkey.termkey_push_bytes(tk, '\x1b[M@"!', 6) + + termkey.termkey_getkey(tk, key) + t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY + + t.eq(ev[0], termkey.TERMKEY_MOUSE_DRAG) -- mouse event for drag + t.eq(button[0], 1) -- mouse button for drag + t.eq(line[0], 1) -- mouse line for drag + t.eq(col[0], 2) -- mouse column for drag + t.eq(key.modifiers, 0) -- modifiers for press + + termkey.termkey_push_bytes(tk, '\x1b[M##!', 6) + + termkey.termkey_getkey(tk, key) + t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY + + t.eq(ev[0], termkey.TERMKEY_MOUSE_RELEASE) -- mouse event for release + t.eq(line[0], 1) -- mouse line for release + t.eq(col[0], 3) -- mouse column for release + t.eq(key.modifiers, 0) -- modifiers for press + + termkey.termkey_push_bytes(tk, '\x1b[M0++', 6) + + termkey.termkey_getkey(tk, key) + t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY + + t.eq(ev[0], termkey.TERMKEY_MOUSE_PRESS) -- mouse event for Ctrl-press + t.eq(button[0], 1) -- mouse button for Ctrl-press + t.eq(line[0], 11) -- mouse line for Ctrl-press + t.eq(col[0], 11) -- mouse column for Ctrl-press + t.eq(key.modifiers, termkey.TERMKEY_KEYMOD_CTRL) -- modifiers for Ctrl-press + + len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0) + t.eq(len, 15) -- string length for Ctrl-press + t.eq(t.ffi.string(buffer), 'C-MousePress(1)') -- string buffer for Ctrl-press + + termkey.termkey_push_bytes(tk, '\x1b[M`!!', 6) + + termkey.termkey_getkey(tk, key) + t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY + + t.eq(ev[0], termkey.TERMKEY_MOUSE_PRESS) -- mouse event for wheel down + t.eq(button[0], 4) -- mouse button for wheel down + + termkey.termkey_push_bytes(tk, '\x1b[Mb!!', 6) + + termkey.termkey_getkey(tk, key) + t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY + + t.eq(ev[0], termkey.TERMKEY_MOUSE_PRESS) -- mouse event for wheel left + t.eq(button[0], 6) -- mouse button for wheel left + + -- rxvt protocol + termkey.termkey_push_bytes(tk, '\x1b[0;20;20M', 10) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mouse press rxvt protocol + + t.eq(key.type, termkey.TERMKEY_TYPE_MOUSE) -- key.type for mouse press rxvt protocol + + t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY + + t.eq(ev[0], termkey.TERMKEY_MOUSE_PRESS) -- mouse event for press rxvt protocol + t.eq(button[0], 1) -- mouse button for press rxvt protocol + t.eq(line[0], 20) -- mouse line for press rxvt protocol + t.eq(col[0], 20) -- mouse column for press rxvt protocol + t.eq(key.modifiers, 0) -- modifiers for press rxvt protocol + + termkey.termkey_push_bytes(tk, '\x1b[3;20;20M', 10) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mouse release rxvt protocol + + t.eq(key.type, termkey.TERMKEY_TYPE_MOUSE) -- key.type for mouse release rxvt protocol + + t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY + + t.eq(ev[0], termkey.TERMKEY_MOUSE_RELEASE) -- mouse event for release rxvt protocol + t.eq(line[0], 20) -- mouse line for release rxvt protocol + t.eq(col[0], 20) -- mouse column for release rxvt protocol + t.eq(key.modifiers, 0) -- modifiers for release rxvt protocol + + -- SGR protocol + termkey.termkey_push_bytes(tk, '\x1b[<0;30;30M', 11) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mouse press SGR encoding + + t.eq(key.type, termkey.TERMKEY_TYPE_MOUSE) -- key.type for mouse press SGR encoding + + t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY + + t.eq(ev[0], termkey.TERMKEY_MOUSE_PRESS) -- mouse event for press SGR + t.eq(button[0], 1) -- mouse button for press SGR + t.eq(line[0], 30) -- mouse line for press SGR + t.eq(col[0], 30) -- mouse column for press SGR + t.eq(key.modifiers, 0) -- modifiers for press SGR + + termkey.termkey_push_bytes(tk, '\x1b[<0;30;30m', 11) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mouse release SGR encoding + + t.eq(key.type, termkey.TERMKEY_TYPE_MOUSE) -- key.type for mouse release SGR encoding + + t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY + + t.eq(ev[0], termkey.TERMKEY_MOUSE_RELEASE) -- mouse event for release SGR + + termkey.termkey_push_bytes(tk, '\x1b[<0;500;300M', 13) + + termkey.termkey_getkey(tk, key) + termkey.termkey_interpret_mouse(tk, key, ev, button, line, col) + + t.eq(line[0], 300) -- mouse line for press SGR wide + t.eq(col[0], 500) -- mouse column for press SGR wide + + termkey.termkey_destroy(tk) + end) + + itp('31position', function() + local tk = termkey.termkey_new_abstract('vt100', 0) + local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey + local line = t.ffi.new('int[1]') + local col = t.ffi.new('int[1]') + + termkey.termkey_push_bytes(tk, '\x1b[?15;7R', 8) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for position report + + t.eq(key.type, termkey.TERMKEY_TYPE_POSITION) -- key.type for position report + + t.eq(termkey.termkey_interpret_position(tk, key, line, col), termkey.TERMKEY_RES_KEY) -- interpret_position yields RES_KEY + + t.eq(line[0], 15) -- line for position report + t.eq(col[0], 7) -- column for position report + + -- A plain CSI R is likely to be <F3> though. + -- This is tricky :/ + + termkey.termkey_push_bytes(tk, '\x1b[R', 3) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for <F3> + + t.eq(key.type, termkey.TERMKEY_TYPE_FUNCTION) -- key.type for <F3> + t.eq(key.code.number, 3) -- key.code.number for <F3> + + termkey.termkey_destroy(tk) + end) + + itp('32modereport', function() + local tk = termkey.termkey_new_abstract('vt100', 0) + local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey + local initial = t.ffi.new('int[1]') + local mode = t.ffi.new('int[1]') + local value = t.ffi.new('int[1]') + + termkey.termkey_push_bytes(tk, '\x1b[?1;2$y', 8) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mode report + + t.eq(key.type, termkey.TERMKEY_TYPE_MODEREPORT) -- key.type for mode report + + t.eq( + termkey.termkey_interpret_modereport(tk, key, initial, mode, value), + termkey.TERMKEY_RES_KEY + ) -- interpret_modereoprt yields RES_KEY + + t.eq(initial[0], 63) -- initial indicator from mode report + t.eq(mode[0], 1) -- mode number from mode report + t.eq(value[0], 2) -- mode value from mode report + + termkey.termkey_push_bytes(tk, '\x1b[4;1$y', 7) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mode report + + t.eq(key.type, termkey.TERMKEY_TYPE_MODEREPORT) -- key.type for mode report + + t.eq( + termkey.termkey_interpret_modereport(tk, key, initial, mode, value), + termkey.TERMKEY_RES_KEY + ) -- interpret_modereoprt yields RES_KEY + + t.eq(initial[0], 0) -- initial indicator from mode report + t.eq(mode[0], 4) -- mode number from mode report + t.eq(value[0], 1) -- mode value from mode report + + termkey.termkey_destroy(tk) + end) + + itp('38csi', function() + local tk = termkey.termkey_new_abstract('vt100', 0) + local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey + local args = t.ffi.new('TermKeyCsiParam[16]') + local nargs = t.ffi.new('size_t[1]') + local command = t.ffi.new('unsigned[1]') + + termkey.termkey_push_bytes(tk, '\x1b[5;25v', 7) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for CSI v + + t.eq(key.type, termkey.TERMKEY_TYPE_UNKNOWN_CSI) -- key.type for unknown CSI + + t.eq(termkey.termkey_interpret_csi(tk, key, args, nargs, command), termkey.TERMKEY_RES_KEY) -- interpret_csi yields RES_KEY + + t.eq(nargs[0], 2) -- nargs for unknown CSI + -- t.eq(args[0], 5) -- args[0] for unknown CSI + -- t.eq(args[1], 25) -- args[1] for unknown CSI + t.eq(command[0], 118) -- command for unknown CSI + + termkey.termkey_push_bytes(tk, '\x1b[?w', 4) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for CSI ? w + t.eq(key.type, termkey.TERMKEY_TYPE_UNKNOWN_CSI) -- key.type for unknown CSI + t.eq(termkey.termkey_interpret_csi(tk, key, args, nargs, command), termkey.TERMKEY_RES_KEY) -- interpret_csi yields RES_KEY + t.eq(command[0], bit.bor(bit.lshift(63, 8), 119)) -- command for unknown CSI + + termkey.termkey_push_bytes(tk, '\x1b[?$x', 5) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for CSI ? $x + t.eq(key.type, termkey.TERMKEY_TYPE_UNKNOWN_CSI) -- key.type for unknown CSI + t.eq(termkey.termkey_interpret_csi(tk, key, args, nargs, command), termkey.TERMKEY_RES_KEY) -- interpret_csi yields RES_KEY + t.eq(command[0], bit.bor(bit.lshift(36, 16), bit.lshift(63, 8), 120)) -- command for unknown CSI + + termkey.termkey_destroy(tk) + end) + + itp('39dcs', function() + local tk = termkey.termkey_new_abstract('xterm', 0) + local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey + + -- 7bit DCS + termkey.termkey_push_bytes(tk, '\x1bP1$r1 q\x1b\\', 10) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for DCS + + t.eq(key.type, termkey.TERMKEY_TYPE_DCS) -- key.type for DCS + t.eq(key.modifiers, 0) -- key.modifiers for DCS + + local str = t.ffi.new('const char*[1]') + t.eq(termkey.termkey_interpret_string(tk, key, str), termkey.TERMKEY_RES_KEY) -- termkey_interpret_string() gives string + t.eq(t.ffi.string(str[0]), '1$r1 q') -- termkey_interpret_string() yields correct string + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_NONE) -- getkey again yields RES_NONE + + -- 8bit DCS + termkey.termkey_push_bytes(tk, '\x901$r2 q\x9c', 8) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for DCS + + t.eq(key.type, termkey.TERMKEY_TYPE_DCS) -- key.type for DCS + t.eq(key.modifiers, 0) -- key.modifiers for DCS + + t.eq(termkey.termkey_interpret_string(tk, key, str), termkey.TERMKEY_RES_KEY) -- "termkey_interpret_string() gives string"); + t.eq(t.ffi.string(str[0]), '1$r2 q') -- "termkey_interpret_string() yields correct string"); + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_NONE) -- "getkey again yields RES_NONE"); + + -- 7bit OSC + termkey.termkey_push_bytes(tk, '\x1b]15;abc\x1b\\', 10) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for OSC + + t.eq(key.type, termkey.TERMKEY_TYPE_OSC) -- key.type for OSC + t.eq(key.modifiers, 0) -- key.modifiers for OSC + + t.eq(termkey.termkey_interpret_string(tk, key, str), termkey.TERMKEY_RES_KEY) -- "termkey_interpret_string() gives string"); + t.eq(t.ffi.string(str[0]), '15;abc') -- "termkey_interpret_string() yields correct string"); + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_NONE) -- getkey again yields RES_NONE + + -- False alarm + termkey.termkey_push_bytes(tk, '\x1bP', 2) + + t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN for false alarm + + t.eq(termkey.termkey_getkey_force(tk, key), termkey.TERMKEY_RES_KEY) -- getkey_force yields RES_KEY for false alarm + + t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type for false alarm + t.eq(key.code.codepoint, string.byte('P')) -- key.code.codepoint for false alarm + t.eq(key.modifiers, termkey.TERMKEY_KEYMOD_ALT) -- key.modifiers for false alarm + + termkey.termkey_destroy(tk) + end) +end) |