diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..9a862ac0d1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Questions and support + url: 'https://github.com/ycm-core/YouCompleteMe/tree/master?tab=readme-ov-file#help-advice-support' + about: Please ask and answer questions here. diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE/issue.md similarity index 98% rename from .github/ISSUE_TEMPLATE.md rename to .github/ISSUE_TEMPLATE/issue.md index d785307f9d..7cc65b14a4 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE/issue.md @@ -1,3 +1,10 @@ +--- + +name: Issue +about: Report a bug or suggest an enhancement + +--- + # Issue Prelude **Please complete these steps and check these boxes (by putting an `x` inside diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b4d0e5f7d0..5e5885e567 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,61 +12,66 @@ jobs: strategy: fail-fast: false matrix: - runs-on: [ ubuntu-20.04, macos-10.15, windows-2019 ] + runs-on: [ ubuntu-24.04, macos-14 ] python-arch: [ 'x64' ] - python-version: [ 3.6 ] include: - - runs-on: windows-2019 - python-arch: 'x86' - python-version: 3.9 - - runs-on: windows-2019 - python-arch: 'x64' - python-version: 3.9 + - runs-on: macos-14 + python-arch: 'arm64' exclude: - - runs-on: windows-2019 - python-arch: 'x64' - python-version: 3.6 + - runs-on: macos-14 + python-arch: "x64" env: COVERAGE: true - name: "${{ matrix.runs-on }} - Python ${{ matrix.python-version }} ${{ matrix.python-arch }}" + name: "${{ matrix.runs-on }} - Python 3.12 ${{ matrix.python-arch }}" runs-on: ${{ matrix.runs-on }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: recursive fetch-depth: 0 - name: Install Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: - python-version: ${{ matrix.python-version }} + python-version: "3.12" architecture: ${{ matrix.python-arch }} - name: Run pip run: python3 -m pip install -r python/test_requirements.txt - name: Run tests run: python3 run_tests.py --quiet python/ycm/tests + - name: summarise coverage + run: coverage xml - name: Upload coverage data - run: codecov --name "${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.python-arch }}" + uses: codecov/codecov-action@v4 + with: + name: "${{ runner.os }}-3.12-${{ matrix.python-arch }}" + token: ${{ secrets.CODECOV_TOKEN }} vim-tests: strategy: fail-fast: false matrix: vim: [ 'new', 'old' ] - runs-on: ubuntu-20.04 - container: 'youcompleteme/ycm-vim-py3:test' + arch: [ 'x86_64' ] + runs-on: ubuntu-24.04 + container: 'youcompleteme/ycm-vim-${{ matrix.arch }}-py3:test' env: COVERAGE: true YCM_TEST_STDOUT: true name: "Vim tests - ${{ matrix.vim }}" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: recursive fetch-depth: 0 - name: Install dependencies - run: sudo -H pip3 install -r python/test_requirements.txt + run: sudo -H pip3 install --break-system-packages -r python/test_requirements.txt + - name: Install Java + uses: actions/setup-java@v4 + with: + java-version: 21 + distribution: 'temurin' - name: Build ycmd - run: python3 ./install.py --ts-completer --clangd-completer --java-completer + run: python3 ./install.py --force-sudo --ts-completer --clangd-completer --java-completer - name: Run tests in old vim # System vim should be oldest supported. if: matrix.vim == 'old' @@ -74,5 +79,10 @@ jobs: - name: Run tests in new vim if: matrix.vim == 'new' run: ./test/run_vim_tests + - name: Combine and summarise coverage + run: coverage combine && coverage xml - name: Upload coverage data - run: codecov --name "vim-tests-${{ matrix.vim }}" + uses: codecov/codecov-action@v4 + with: + name: "vim-tests-${{ matrix.vim }}" + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/update_vim_docs.yaml b/.github/workflows/update_vim_docs.yaml new file mode 100644 index 0000000000..9bcd82da79 --- /dev/null +++ b/.github/workflows/update_vim_docs.yaml @@ -0,0 +1,35 @@ +name: "Update vim docs" + +on: + push: + branches: + - master + paths: + - 'README.md' + workflow_dispatch: + +jobs: + update-vim-docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: 'Update local repo' + run: './update-vim-docs' + - name: 'Check diffs' + run: 'git diff' + - name: 'Create pull request' + uses: peter-evans/create-pull-request@v4 + id: cpr + with: + token: ${{ secrets.VIMSPECTOR_UPDATE_BOT_PAT }} + push-to-fork: VimspectorUpdateBot/YouCompleteMe + commit-message: "Update vim docs" + branch: 'auto/update-vim-docs' + delete-branch: true + title: "[Auto] Update vim docs" + body: "Update the vim docs after recent changes" + labels: "auto" + - name: Check outputs + run: | + echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}" + echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}" diff --git a/.mergify.yml b/.mergify.yml index b81442b70d..cf0e0e8293 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -1,40 +1,106 @@ # https://blog.mergify.com/strict-mode-deprecation/ queue_rules: - - name: default - # These define the conditions to get out of the merge queue - conditions: - - status-success=ubuntu-20.04 - Python 3.6 x64 - - status-success=macos-10.15 - Python 3.6 x64 + - name: duplicated default from Automatic merge on Azure Pipelines and Reviewable + successes + queue_conditions: + - base=master + - "#approved-reviews-by>=2" + - status-success=ubuntu-24.04 - Python 3.9 x64 + - status-success=macos-14 - Python 3.9 arm64 + # - status-success=windows-2019 - Python 3.9 x64 + # - status-success=windows-2019 - Python 3.9 x86 + - status-success=Vim tests - new + - status-success=Vim tests - old + - status-success=code-review/reviewable + merge_conditions: + - status-success=ubuntu-24.04 - Python 3.9 x64 + - status-success=macos-14 - Python 3.9 arm64 + - status-success=windows-2019 - Python 3.9 x64 + - status-success=windows-2019 - Python 3.9 x86 + - status-success=Vim tests - new + - status-success=Vim tests - old + merge_method: merge + - name: duplicated default from Manual merge on Azure Pipelines and Maintainer Override + queue_conditions: + - base=master + - status-success=ubuntu-24.04 - Python 3.9 x64 + - status-success=macos-14 - Python 3.9 arm64 - status-success=windows-2019 - Python 3.9 x64 - status-success=windows-2019 - Python 3.9 x86 - status-success=Vim tests - new - status-success=Vim tests - old + - "#approved-reviews-by>=1" + - "#changes-requested-reviews-by=0" + - label="Ship It!" + merge_conditions: + - status-success=ubuntu-24.04 - Python 3.9 x64 + - status-success=macos-14 - Python 3.9 arm64 + - status-success=windows-2019 - Python 3.9 x64 + - status-success=windows-2019 - Python 3.9 x86 + - status-success=Vim tests - new + - status-success=Vim tests - old + merge_method: merge + - name: duplicated default from Manual merge on Pipelines and Maintainer Override + from owner PR + queue_conditions: + - base=master + - author=puremourning + - status-success=ubuntu-24.04 - Python 3.9 x64 + - status-success=macos-14 - Python 3.9 arm64 + - status-success=windows-2019 - Python 3.9 x64 + - status-success=windows-2019 - Python 3.9 x86 + - status-success=Vim tests - new + - status-success=Vim tests - old + - "#changes-requested-reviews-by=0" + - label="Ship It!" + merge_conditions: + - status-success=ubuntu-24.04 - Python 3.9 x64 + - status-success=macos-14 - Python 3.9 arm64 + - status-success=windows-2019 - Python 3.9 x64 + - status-success=windows-2019 - Python 3.9 x86 + - status-success=Vim tests - new + - status-success=Vim tests - old + merge_method: merge + - name: duplicated default from Merge auto pr when approved + queue_conditions: + - author=VimspectorUpdateBot + - label=auto + - base=master + - status-success=code-review/reviewable + - "#approved-reviews-by>=1" + - "#changes-requested-reviews-by=0" + merge_conditions: + - status-success=ubuntu-24.04 - Python 3.9 x64 + - status-success=macos-14 - Python 3.9 arm64 + - status-success=windows-2019 - Python 3.9 x64 + - status-success=windows-2019 - Python 3.9 x86 + - status-success=Vim tests - new + - status-success=Vim tests - old + merge_method: merge pull_request_rules: - name: Automatic merge on Azure Pipelines and Reviewable successes conditions: - base=master - "#approved-reviews-by>=2" - - status-success=ubuntu-20.04 - Python 3.6 x64 - - status-success=macos-10.15 - Python 3.6 x64 - - status-success=windows-2019 - Python 3.9 x64 - - status-success=windows-2019 - Python 3.9 x86 + - status-success=ubuntu-24.04 - Python 3.9 x64 + - status-success=macos-14 - Python 3.9 arm64 + # - status-success=windows-2019 - Python 3.9 x64 + # - status-success=windows-2019 - Python 3.9 x86 - status-success=Vim tests - new - status-success=Vim tests - old - status-success=code-review/reviewable - actions: - queue: - method: merge - name: default + actions: &merge-actions comment: message: Thanks for sending a PR! + - name: Manual merge on Azure Pipelines and Maintainer Override conditions: - base=master - - status-success=ubuntu-20.04 - Python 3.6 x64 - - status-success=macos-10.15 - Python 3.6 x64 - - status-success=windows-2019 - Python 3.9 x64 - - status-success=windows-2019 - Python 3.9 x86 + - status-success=ubuntu-24.04 - Python 3.9 x64 + - status-success=macos-14 - Python 3.9 arm64 + # - status-success=windows-2019 - Python 3.9 x64 + # - status-success=windows-2019 - Python 3.9 x86 - status-success=Vim tests - new - status-success=Vim tests - old @@ -42,9 +108,37 @@ pull_request_rules: - "#changes-requested-reviews-by=0" - label="Ship It!" + actions: + <<: *merge-actions + - name: Manual merge on Pipelines and Maintainer Override from owner PR + conditions: + - base=master + - author=puremourning + - status-success=ubuntu-24.04 - Python 3.9 x64 + - status-success=macos-14 - Python 3.9 arm64 + # - status-success=windows-2019 - Python 3.9 x64 + # - status-success=windows-2019 - Python 3.9 x86 + - status-success=Vim tests - new + - status-success=Vim tests - old + + - "#changes-requested-reviews-by=0" + - label="Ship It!" + actions: + <<: *merge-actions + - name: Merge auto pr when approved + conditions: + - author=VimspectorUpdateBot + - label=auto + - base=master + # Review + - status-success=code-review/reviewable + - "#approved-reviews-by>=1" + - "#changes-requested-reviews-by=0" + actions: + <<: *merge-actions + - name: Automatic merge on Azure Pipelines and Reviewable successes + Manual merge + on Azure Pipelines and Maintainer Override + Manual merge on Pipelines and Maintainer + Override from owner PR + Merge auto pr when approved + conditions: [] actions: queue: - method: merge - name: default - comment: - message: Thanks for sending a PR! diff --git a/.vimspector.json b/.vimspector.json index 9bd48fbb75..3e6991ddb9 100644 --- a/.vimspector.json +++ b/.vimspector.json @@ -34,18 +34,19 @@ "type": "debugpy", "request": "launch", - "cwd": "${workspaceRoot}/python", + "cwd": "${workspaceRoot}", "stopOnEntry": false, "console": "integratedTerminal", "justMyCode": true, + "logToFile": true, + "showReturnValue": true, "debugOptions": [], - "module": "pytest", + "module": "unittest", "python": "${python}", "args": [ "-v", - "--tb=native", "${Test}" ], "env": { diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 9860629fe2..907691abf2 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,7 +1,7 @@ We, the maintainers, pledge to treat all contributors with respect and require that contributors reciprocate. -The maintainers will not tolerate unwelcome, inpolite, abusive or unprofessional behaviour. +The maintainers will not tolerate unwelcome, impolite, abusive or unprofessional behaviour. At the discretion of the maintainers, users who persist in behaving in a way that is unwelcome may be subject to a ban. -This applies to all interractions related to this project and any associated projects. +This applies to all interactions related to this project and any associated projects. diff --git a/README.md b/README.md index 639aea5c50..af60ecee8b 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ YouCompleteMe: a code-completion engine for Vim Help, Advice, Support --------------------- -Looking for help, advice or support? Having problems getting YCM to work? +Looking for help, advice, or support? Having problems getting YCM to work? First carefully read the [installation instructions](#installation) for your OS. We recommend you use the supplied `install.py` - the "full" installation guide @@ -17,7 +17,7 @@ is for rare, advanced use cases and most users should use `install.py`. If the server isn't starting and you're getting a "YouCompleteMe unavailable" error, check the [Troubleshooting][wiki-troubleshooting] guide. -Next check the [User Guide](#user-guide) section on the semantic completer that +Next, check the [User Guide](#user-guide) section on the semantic completer that you are using. For C/C++/Objective-C/Objective-C++/CUDA, you _must_ read [this section](#c-family-semantic-completion). @@ -30,6 +30,11 @@ get in touch. Please do **NOT** go to #vim on Freenode for support. Please contact the YouCompleteMe maintainers directly using the [contact details](#contact) below. +# Vundle + +Please note that the below instructions suggest using Vundle. Currently there +are problems with Vundle, so here are some [alternative instructions](https://github.com/ycm-core/YouCompleteMe/issues/4134#issuecomment-1446235584) using Vim packages. + Contents -------- @@ -39,7 +44,6 @@ Contents - [macOS](#macos) - [Linux 64-bit](#linux-64-bit) - [Windows](#windows) - - [FreeBSD/OpenBSD](#freebsdopenbsd) - [Full Installation Guide](#full-installation-guide) - [Quick Feature Summary](#quick-feature-summary) - [User Guide](#user-guide) @@ -48,6 +52,8 @@ Contents - [Completion String Ranking](#completion-string-ranking) - [General Semantic Completion](#general-semantic-completion) - [Signature Help](#signature-help) + - [Semantic Highlighting](#semantic-highlighting) + - [Inlay Hints](#inlay-hints) - [C-family Semantic Completion](#c-family-semantic-completion) - [Java Semantic Completion](#java-semantic-completion) - [C# Semantic Completion](#c-semantic-completion) @@ -61,6 +67,7 @@ Contents - [Diagnostic Display](#diagnostic-display) - [Diagnostic Highlighting Groups](#diagnostic-highlighting-groups) - [Symbol Search](#symbol-search) + - [Type/Call Hierarchy](#typecall-hierarchy) - [Commands](#commands) - [YcmCompleter subcommands](#ycmcompleter-subcommands) - [GoTo Commands](#goto-commands) @@ -83,7 +90,7 @@ Intro YouCompleteMe is a fast, as-you-type, fuzzy-search code completion, comprehension and refactoring engine for [Vim][]. -It has several completion engines built in and supports any protocol-compliant +It has several completion engines built-in and supports any protocol-compliant Language Server, so can work with practically any language. YouCompleteMe contains: @@ -99,11 +106,11 @@ contains: - a [jdt.ls][]-based completion engine for Java. - a [generic Language Server Protocol implementation for any language](#plugging-an-arbitrary-lsp-server) - and an omnifunc-based completer that uses data from Vim's omnicomplete system - to provide semantic completions for many other languages (Ruby, PHP etc.). + to provide semantic completions for many other languages (Ruby, PHP, etc.). ![YouCompleteMe GIF completion demo](https://i.imgur.com/0OP4ood.gif) -Here's an explanation of what happens in the last GIF demo above. +Here's an explanation of what happened in the last GIF demo above. First, realize that **no keyboard shortcuts had to be pressed** to get the list of completion candidates at any point in the demo. The user just types and the @@ -146,7 +153,7 @@ don't need to save your file or press any keyboard shortcut to trigger this, it **And that's not all...** -YCM might be the only vim completion engine with the correct Unicode support. +YCM might be the only Vim completion engine with the correct Unicode support. Though we do assume UTF-8 everywhere. ![YouCompleteMe GIF unicode demo](https://user-images.githubusercontent.com/10026824/34471853-af9cf32a-ef53-11e7-8229-de534058ddc4.gif) @@ -178,8 +185,8 @@ Below we can see YCM being able to do a few things: - Retrieve references across files - Go to declaration/definition - Expand `auto` in C++ -- Fix some common errors with `FixIt` -- Not shown in the GIF is `GoToImplementation` and `GoToType` +- Fix some common errors, and provide refactorings, with `FixIt` +- Not shown in the GIF are `GoToImplementation` and `GoToType` for servers that support it. ![YouCompleteMe GIF subcommands demo](https://i.imgur.com/nmUUbdl.gif) @@ -202,30 +209,56 @@ Installation ### Requirements +| Runtime | Min Version | Recommended Version (full support) | Python | +|---------|-------------|------------------------------------|--------| +| Vim | 9.1.0016 | 9.1.0016 | 3.12 | +| Neovim | 0.5 | Vim 9.1.0016 | 3.12 | + #### Supported Vim Versions Our policy is to support the Vim version that's in the latest LTS of Ubuntu. -That's currently Ubuntu 20.04 which contains `vim-nox` at `v8.1.2269`. -Vim must have a working Python 3.6 runtime, compiled with `--enable-shared` (or -`--enable-framework`). You can check with `:py3 import sys; print( sys.version -)`. +Vim must have a [working Python 3 runtime](#supported-python-runtime). For Neovim users, our policy is to require the latest released version. Currently, Neovim 0.5.0 is required. Please note that some features are not available in Neovim, and Neovim is not officially supported. +#### Supported Python runtime + +YCM has two components: A server and a client. Both the server and client +require Python 3.12 or later 3.x release. + +For the Vim client, Vim must be, compiled with `--enable-shared` (or +`--enable-framework` on macOS). You can check if this is working with `:py3 +import sys; print( sys.version)`. It should say something like `3.12.0 (...)`. + +For Neovim, you must have a python 3.12 runtime and the Neovim python +extensions. See Neovim's `:help provider-python` for how to set that up. + +For the server, you must run the `install.py` script with a python 3.12 (or +later) runtime. Anaconda etc. are not supported. YCM will remember the runtime +you used to run `install.py` and will use that when launching the server, so if +you usually use anaconda, then make sure to use the full path to a real cpython3, +e.g. `/usr/bin/python3 install.py --all` etc. + +Our policy is to support the python3 version that's available in the latest +Ubuntu LTS (similar to our Vim version policy). We don't increase the Python +runtime version without a reason, though. Typically, we do this when the current +python version we're using goes out of support. At that time we will typically +pick a version that will be supported for a number of years. + #### Supported Compilers In order to provide the best possible performance and stability, ycmd has updated its code to C++17. This requires a version bump of the minimum supported compilers. The new requirements are: -| Compiler | Current Min | -|-|-| -| GCC | 8 | -| Clang | 7 | -| MSVC | 15.7 (VS 2017) | +| Compiler | Current Min | +|----------|----------------| +| GCC | 8 | +| Clang | 7 | +| MSVC | 15.7 (VS 2017) | YCM requires CMake 3.13 or greater. If your CMake is too old, you may be able to simply `pip install --user cmake` to get a really new version. @@ -233,9 +266,9 @@ simply `pip install --user cmake` to get a really new version. #### Individual completer requirements When enabling language support for a particular language, there may be runtime -requirements, such as needing Java Development Kit for Java support. In general, -YCM is not in control of the required versions for the downstream compilers, -though we do our best to signal where we know them. +requirements, such as needing a very recent Java Development Kit for Java +support. In general, YCM is not in control of the required versions for the +downstream compilers, though we do our best to signal where we know them. ### macOS @@ -243,7 +276,7 @@ though we do our best to signal where we know them. - Install YCM plugin via [Vundle][] - Install CMake, MacVim and Python 3; Note that the pre-installed *macOS system* - vim is not supported (due to it having broken Python integration). + Vim is not supported (due to it having broken Python integration). ``` $ brew install cmake python go nodejs @@ -252,7 +285,7 @@ $ brew install cmake python go nodejs - Install mono from [Mono Project](mono-install-macos) (NOTE: on Intel Macs you can also `brew install mono`. On arm Macs, you may require Rosetta) -- For java support you must install a JDK, one way to do this is with Homebrew: +- For Java support you must install a JDK, one way to do this is with Homebrew: ``` $ brew install java @@ -358,10 +391,10 @@ The following additional language support options are available: and add `--cs-completer` when calling `install.py`. - Go support: install [Go][go-install] and add `--go-completer` when calling `install.py`. -- JavaScript and TypeScript support: install [Node.js and npm][npm-install] and +- JavaScript and TypeScript support: install [Node.js 18+ and npm][npm-install] and add `--ts-completer` when calling `install.py`. - Rust support: add `--rust-completer` when calling `install.py`. -- Java support: install [JDK][jdk-install] and add +- Java support: install [JDK 17][jdk-install] and add `--java-completer` when calling `install.py`. To simply compile with everything enabled, there's a `--all` flag. So, to @@ -384,7 +417,7 @@ that are conservatively turned off by default that you may want to turn on. ### Linux 64-bit -The following assume you're using Ubuntu 20.04. +The following assume you're using Ubuntu 24.04. #### Quick start, installing all completers @@ -395,10 +428,10 @@ The following assume you're using Ubuntu 20.04. apt install build-essential cmake vim-nox python3-dev ``` -- Install mono-complete, go, node, java and npm +- Install mono-complete, go, node, java, and npm ``` -apt install mono-complete golang nodejs default-jdk npm +apt install mono-complete golang nodejs openjdk-17-jdk openjdk-17-jre npm ``` - Compile YCM @@ -417,19 +450,19 @@ YouCompleteMe, however they may not work for everyone. If the following instructions don't work for you, check out the [full installation guide](#full-installation-guide). -Make sure you have a supported version of Vim with Python 3 support, and a +Make sure you have a supported version of Vim with Python 3 support and a supported compiler. The latest LTS of Ubuntu is the minimum platform for simple installation. For earlier releases or other distributions, you may have to do some work to acquire the dependencies. -If your vim version is too old, you may need to [compile Vim from +If your Vim version is too old, you may need to [compile Vim from source][vim-build] (don't worry, it's easy). Install YouCompleteMe with [Vundle][]. **Remember:** YCM is a plugin with a compiled component. If you **update** YCM -using Vundle and the `ycm_core` library APIs have changed (happens rarely), YCM -will notify you to recompile it. You should then rerun the install process. +using Vundle and the `ycm_core` library APIs have changed (which happens rarely), YCM +will notify you to recompile it. You should then rerun the installation process. Install development tools, CMake, and Python headers: @@ -466,14 +499,14 @@ The following additional language support options are available: when calling `install.py`. - Go support: install [Go][go-install] and add `--go-completer` when calling `install.py`. -- JavaScript and TypeScript support: install [Node.js and npm][npm-install] and +- JavaScript and TypeScript support: install [Node.js 18+ and npm][npm-install] and add `--ts-completer` when calling `install.py`. - Rust support: add `--rust-completer` when calling `install.py`. -- Java support: install [JDK][jdk-install] and add +- Java support: install [JDK 17][jdk-install] and add `--java-completer` when calling `install.py`. To simply compile with everything enabled, there's a `--all` flag. So, to -install with all language features, ensure `xbuild`, `go`, `node` and `npm` +install with all language features, ensure `xbuild`, `go`, `node`, and `npm` tools are installed and in your `PATH`, then simply run: ``` @@ -492,6 +525,10 @@ that are conservatively turned off by default that you may want to turn on. ### Windows +***NOTE***: Windows support is *deprecated* and *unmaintained*. We will do our +best to keep it working, but we no longer test it in CI and there is a high +likelihood of breakages. + #### Quick start, installing all completers - Install YCM plugin via [Vundle][] @@ -580,10 +617,10 @@ The following additional language support options are available: Be sure that [the build utility `msbuild` is in your PATH][add-msbuild-to-path]. - Go support: install [Go][go-install] and add `--go-completer` when calling `install.py`. -- JavaScript and TypeScript support: install [Node.js and npm][npm-install] and +- JavaScript and TypeScript support: install [Node.js 18+ and npm][npm-install] and add `--ts-completer` when calling `install.py`. - Rust support: add `--rust-completer` when calling `install.py`. -- Java support: install [JDK][jdk-install] and add +- Java support: install [JDK 17][jdk-install] and add `--java-completer` when calling `install.py`. To simply compile with everything enabled, there's a `--all` flag. So, to @@ -608,102 +645,6 @@ YCM comes with sane defaults for its options, but you still may want to take a look at what's available for configuration. There are a few interesting options that are conservatively turned off by default that you may want to turn on. -### FreeBSD/OpenBSD - -#### Quick start, installing all completers - -- Install YCM plugin via [Vundle][] -- Install CMake - -``` -pkg install cmake -``` - -- Install xbuild, go, node and npm -- Compile YCM - -``` -cd ~/.vim/bundle/YouCompleteMe -python3 install.py --all -``` - -- For plugging an arbitrary LSP server, check [the relevant section](#plugging-an-arbitrary-lsp-server) - -#### Explanation for the quick start - -These instructions (using `install.py`) are the quickest way to install -YouCompleteMe, however they may not work for everyone. If the following -instructions don't work for you, check out the [full installation -guide](#full-installation-guide). - -**NOTE:** OpenBSD / FreeBSD are not officially supported platforms by YCM. - -Make sure you have a supported Vim version with Python 3 support, and a supported -compiler and CMake, perhaps: - -``` -pkg install cmake -``` - -Install YouCompleteMe with [Vundle][]. - -**Remember:** YCM is a plugin with a compiled component. If you **update** YCM -using Vundle and the `ycm_core` library APIs have changed (happens -rarely), YCM will notify you to recompile it. You should then rerun the install -process. - -Compiling YCM **with** semantic support for C-family languages through -**clangd**: - -``` -cd ~/.vim/bundle/YouCompleteMe -./install.py --clangd-completer -``` - -Compiling YCM **without** semantic support for C-family languages: - -``` -cd ~/.vim/bundle/YouCompleteMe -./install.py -``` - -If the `python` executable is not present, or the default `python` is not the -one that should be compiled against, specify the python interpreter explicitly: - -``` -python3 install.py --clangd-completer -``` - -The following additional language support options are available: - -- C# support: install Mono and add `--cs-completer` when calling - `./install.py`. -- Go support: install [Go][go-install] and add `--go-completer` when calling - `./install.py`. -- JavaScript and TypeScript support: install [Node.js and npm][npm-install] and - add `--ts-completer` when calling `install.py`. -- Rust support: add `--rust-completer` when calling `./install.py`. -- Java support: install [JDK][jdk-install] and add - `--java-completer` when calling `./install.py`. - -To simply compile with everything enabled, there's a `--all` flag. So, to -install with all language features, ensure `xbuild`, `go`, `node` and `npm` -tools are installed and in your `PATH`, then simply run: - -``` -cd ~/.vim/bundle/YouCompleteMe -./install.py --all -``` - -That's it. You're done. Refer to the _User Guide_ section on how to use YCM. -Don't forget that if you want the C-family semantic completion engine to work, -you will need to provide the compilation flags for your project to YCM. It's all -in the User Guide. - -YCM comes with sane defaults for its options, but you still may want to take a -look at what's available for configuration. There are a few interesting options -that are conservatively turned off by default that you may want to turn on. - ### Full Installation Guide The [full installation guide][wiki-full-install] has been moved to the wiki. @@ -725,14 +666,20 @@ Quick Feature Summary * Signature help * Real-time diagnostic display * Go to include/declaration/definition (`GoTo`, etc.) +* Go to alternate file (e.g. associated header `GoToAlternateFile`) * Find Symbol (`GoToSymbol`), with interactive search * Document outline (`GoToDocumentOutline`), with interactive search * View documentation comments for identifiers (`GetDoc`) * Type information for identifiers (`GetType`) * Automatically fix certain errors (`FixIt`) +* Perform refactoring (`FixIt`) * Reference finding (`GoToReferences`) * Renaming symbols (`RefactorRename `) * Code formatting (`Format`) +* Semantic highlighting +* Inlay hints +* Type hierarchy +* Call hierarchy ### C♯ @@ -745,6 +692,7 @@ Quick Feature Summary * View documentation comments for identifiers (`GetDoc`) * Type information for identifiers (`GetType`) * Automatically fix certain errors (`FixIt`) +* Perform refactoring (`FixIt`) * Management of OmniSharp-Roslyn server instance * Renaming symbols (`RefactorRename `) * Code formatting (`Format`) @@ -770,10 +718,13 @@ Quick Feature Summary * Go to implementation (`GoToImplementation`) * Document outline (`GoToDocumentOutline`), with interactive search * Automatically fix certain errors (`FixIt`) +* Perform refactoring (`FixIt`) * View documentation comments for identifiers (`GetDoc`) * Type information for identifiers (`GetType`) * Code formatting (`Format`) * Management of `gopls` server instance +* Inlay hints +* Call hierarchy ### JavaScript and TypeScript @@ -788,11 +739,14 @@ Quick Feature Summary * Reference finding (`GoToReferences`) * View documentation comments for identifiers (`GetDoc`) * Type information for identifiers (`GetType`) -* Automatically fix certain errors (`FixIt`) +* Automatically fix certain errors and perform refactoring (`FixIt`) +* Perform refactoring (`FixIt`) * Renaming symbols (`RefactorRename `) * Code formatting (`Format`) * Organize imports (`OrganizeImports`) * Management of `TSServer` server instance +* Inlay hints +* Call hierarchy ### Rust @@ -804,10 +758,14 @@ Quick Feature Summary * Document outline (`GoToDocumentOutline`), with interactive search * View documentation comments for identifiers (`GetDoc`) * Automatically fix certain errors (`FixIt`) +* Perform refactoring (`FixIt`) * Type information for identifiers (`GetType`) * Renaming symbols (`RefactorRename `) * Code formatting (`Format`) * Management of `rust-analyzer` server instance +* Semantic highlighting +* Inlay hints +* Call hierarchy ### Java @@ -827,9 +785,13 @@ Quick Feature Summary * Renaming symbols (`RefactorRename `) * Code formatting (`Format`) * Organize imports (`OrganizeImports`) -* Detection of java projects +* Detection of Java projects * Execute custom server command (`ExecuteCommand `) * Management of `jdt.ls` server instance +* Semantic highlighting +* Inlay hints +* Type hierarchy +* Call hierarchy User Guide ---------- @@ -887,7 +849,7 @@ letter with or without marks: Use the TAB key to accept a completion and continue pressing TAB to cycle -through the completions. Use Shift-TAB to cycle backwards. Note that if you're +through the completions. Use Shift-TAB to cycle backward. Note that if you're using console Vim (that is, not gvim or MacVim) then it's likely that the Shift-TAB binding will not work because the console will not pass it to Vim. You can remap the keys; see the [Options](#options) section below. @@ -925,10 +887,10 @@ The subsequence filter removes any completions that do not match the input, but then the sorting system kicks in. It's actually very complicated and uses lots of factors, but suffice it to say that "word boundary" (WB) subsequence character matches are "worth" more than non-WB matches. In effect, this means -given an input of "gua", the completion "getUserAccount" would be ranked higher +that given an input of "gua", the completion "getUserAccount" would be ranked higher in the list than the "Fooguxa" completion (both of which are subsequence -matches). A word-boundary character are all capital characters, characters -preceded by an underscore and the first letter character in the completion +matches). Word-boundary characters are all capital characters, characters +preceded by an underscore, and the first letter character in the completion string. ### Signature Help @@ -940,7 +902,8 @@ Signature help is triggered in insert mode automatically when `g:ycm_auto_trigger` is enabled and is not supported when it is not enabled. The signatures popup is hidden when there are no matching signatures or when you -leave insert mode. There is no key binding to clear the popup. +leave insert mode. If you want to manually control when it is visible, you can +map something to `YCMToggleSignatureHelp` (see below). For more details on this feature and a few demos, check out the [PR that proposed it][signature-help-pr]. @@ -958,6 +921,136 @@ _NOTE_: No default mapping is provided because insert mappings are very difficult to create without breaking or overriding some existing functionality. Ctrl-l is not a suggestion, just an example. +### Semantic highlighting + +Semantic highlighting is the process where the buffer text is coloured according +to the underlying semantic type of the word, rather than classic syntax +highlighting based on regular expressions. This can be powerful additional data +that we can process very quickly. + +This feature is only supported in Vim. + +For example, here is a function with classic highlighting: + +![highliting-classic](https://user-images.githubusercontent.com/10584846/173137003-a265e8b0-84db-4993-98f0-03ee81b9de94.png) + +And here is the same function with semantic highlighting: + +![highliting-semantic](https://user-images.githubusercontent.com/10584846/173137012-7547de0b-145f-45fa-ace3-18943acd2141.png) + +As you can see, the function calls, macros, etc. are correctly identified. + +This can be enabled globally with `let g:ycm_enable_semantic_highlighting=1` or +per buffer, by setting `b:ycm_enable_semantic_highlighting`. + +#### Customising the highlight groups + +YCM uses text properties (see `:help text-prop-intro`) for semantic +highlighting. In order to customise the coloring, you can define the text +properties that are used. + +If you define a text property named `YCM_HL_`, then it will be used +in place of the defaults. The `` is defined as the Language Server +Protocol semantic token type, defined in the [LSP Spec](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_semanticTokens). + +Some servers also use custom values. In this case, YCM prints a warning +including the token type name that you can customise. + +For example, to render `parameter` tokens using the `Normal` highlight group, +you can do this: + +```viml +call prop_type_add( 'YCM_HL_parameter', { 'highlight': 'Normal' } ) +``` + +More generally, this pattern can be useful for customising the groups: + +```viml +let MY_YCM_HIGHLIGHT_GROUP = { + \ 'typeParameter': 'PreProc', + \ 'parameter': 'Normal', + \ 'variable': 'Normal', + \ 'property': 'Normal', + \ 'enumMember': 'Normal', + \ 'event': 'Special', + \ 'member': 'Normal', + \ 'method': 'Normal', + \ 'class': 'Special', + \ 'namespace': 'Special', + \ } + +for tokenType in keys( MY_YCM_HIGHLIGHT_GROUP ) + call prop_type_add( 'YCM_HL_' . tokenType, + \ { 'highlight': MY_YCM_HIGHLIGHT_GROUP[ tokenType ] } ) +endfor +``` + +## Inlay hints + +**NOTE**: Highly experimental feature, requiring Vim 9.0.214 or later (not +supported in NeoVim). + +When `g:ycm_enable_inlay_hints` (globally) or `b:ycm_enable_inlay_hints` (for a +specific buffer) is set to `1`, then YCM will insert inlay hints as supported by +the language semantic engine. + +An inlay hint is text that is rendered on the screen that is not part of the buffer and +is often used to mark up the type or name of arguments, parameters, etc. which +help the developer understand the semantics of the code. + +Here are some examples: + +* C + +![c-inlay](https://user-images.githubusercontent.com/10584846/185708054-68074fc0-e50c-4a65-887c-da6f372b8982.png) + +* TypeScript + +![ts-inlay](https://user-images.githubusercontent.com/10584846/185708156-b52970ce-005f-4f0b-97e7-bdf8feeefedc.png) + +* Go + +![go-inlay](https://user-images.githubusercontent.com/10584846/185708242-e42dab6f-1847-46f1-8585-2d9f2c8a76dc.png) + +### Highlight groups + +By default, YCM renders the inlay hints with the `NonText` highlight group. To +override this, define the `YcmInlayHint` highlight yourself, e.g. in your +`.vimrc`: + +```viml +hi link YcmInlayHint Comment +``` + +Similar to semantic highlighting above, you can override specific highlighting +for different inlay hint types by defining text properties named after the kind +of inlay hint, for example: + +```viml +call prop_type_add( 'YCM_INLAY_Type', #{ highlight: 'Comment' } ) +``` + +The list of inlay hint kinds can be found in `python/ycm/inlay_hints.py` + +### Options + +* `g:ycm_enable_inlay_hints` or `b:ycm_enable_inlay_hints` - enable/disable + globally or for local buffer +* `g:ycm_clear_inlay_hints_in_insert_mode` - set to `1` to remove all inlay + hints when entering insert mode and reinstate them when leaving insert mode + +### Toggling + +Inlay hints can add a lot of text to the screen and may be distracting. You can +toggle them on/off instantly, by mapping something to +`(YCMToggleInlayHints)`, for example: + +```viml +nnoremap h (YCMToggleInlayHints) +``` + +No default mapping is provided for this due to the personal nature of mappings. + ### General Semantic Completion You can use Ctrl+Space to trigger the completion suggestions anywhere, even @@ -980,7 +1073,7 @@ Some of the features of clangd: information. This symbol information is used for code completion and code navigation. Whereas libclang is limited to the current translation unit(TU). - **Code navigation**: Clangd provides all the GoTo requests libclang provides and it - improves those using the above mentioned index information to contain + improves those using the above-mentioned index information to contain project-wide information rather than just the current TU. - **Rename**: Clangd can perform semantic rename operations on the current file, whereas libclang doesn't support such functionality. @@ -1001,7 +1094,7 @@ On supported architectures, the `install.py` script will download a suitable clangd (`--clangd-completer`) or libclang (`--clang-completer`) for you. Supported architectures are: -* Linux glibc >= 2.17 (Intel, armv7-a, aarch64) - built on ubuntu 18.04 +* Linux glibc >= 2.39 (Intel, armv7-a, aarch64) - built on ubuntu 24.04 * MacOS >=10.15 (Intel, arm64) - For Intel, compatibility per clang.llvm.org downloads - For arm64, macOS 10.15+ @@ -1011,7 +1104,7 @@ Supported architectures are: Typically, clangd is installed by the YCM installer (either with `--all` or with `--clangd-completer`). This downloads a pre-built `clangd` binary for your -architecture. If your OS or architecture is not supported or too old, you can +architecture. If your OS or architecture is not supported or is too old, you can install a compatible `clangd` and use [`g:ycm_clangd_binary_path`]() to point to it. @@ -1023,22 +1116,22 @@ your environment, but again if your environment can't be supported, you can build or acquire `libclang` for yourself and specify it when building, as: ``` -$ EXTRA_CMAKE_ARGS='-DPATH_TO_LLVM_ROOT=/path/to/your/llvm' ./install.py --clang-compelter --system-libclang +$ EXTRA_CMAKE_ARGS='-DPATH_TO_LLVM_ROOT=/path/to/your/llvm' ./install.py --clang-completer --system-libclang ``` Please note that if using custom `clangd` or `libclang` it _must_ match the -version that YCM requires. Currently YCM requires ***clang 13.0.0***. +version that YCM requires. Currently YCM requires ***clang 17.0.1***. #### Compile flags -In order to perform semantic analysis such as code completion, `GoTo` and +In order to perform semantic analysis such as code completion, `GoTo`, and diagnostics, YouCompleteMe uses `clangd`, which makes use of clang compiler, sometimes also referred to as LLVM. Like any compiler, clang also requires a set of compile flags in order to parse your code. Simply put: If clang can't parse your code, YouCompleteMe can't provide semantic analysis. -There are 2 methods which can be used to provide compile flags to clang: +There are 2 methods that can be used to provide compile flags to clang: #### Option 1: Use a [compilation database][compdb] @@ -1070,14 +1163,14 @@ searching the directories and lets clangd take over and handle the flags. #### Option 2: Provide the flags manually -If you don't have a compilation database, or aren't able to generate one, +If you don't have a compilation database or aren't able to generate one, you have to tell YouCompleteMe how to compile your code some other way. Every C-family project is different. It is not possible for YCM to guess what compiler flags to supply for your project. Fortunately, YCM provides a mechanism for you to generate the flags for a particular file with _arbitrary complexity_. -This is achieved by requiring you to provide a Python module which implements a -trivial function which, given the file name as argument, returns a list of +This is achieved by requiring you to provide a Python module that implements a +trivial function that, given the file name as an argument, returns a list of compiler flags to use to compile that file. YCM looks for a `.ycm_extra_conf.py` file in the directory of the opened file or @@ -1148,7 +1241,7 @@ your file. ### Java Semantic Completion -#### Java quick Start +#### Java Quick Start 1. Ensure that you have enabled the Java completer. See the [installation guide](#installation) for details. @@ -1166,16 +1259,16 @@ your file. #### Java Project Files In order to provide semantic analysis, the Java completion engine requires -knowledge of your project structure. In particular it needs to know the class +knowledge of your project structure. In particular, it needs to know the class path to use, when compiling your code. Fortunately [jdt.ls][] supports [eclipse project files][eclipse-project], [maven projects][mvn-project] and [gradle projects][gradle-project]. -**NOTE:** Our recommendation is to use either maven or gradle projects. +**NOTE:** Our recommendation is to use either Maven or Gradle projects. #### Diagnostic display - Syntastic -The native support for Java includes YCM's native realtime diagnostics display. +The native support for Java includes YCM's native real-time diagnostics display. This can conflict with other diagnostics plugins like Syntastic, so when enabling Java support, please **manually disable Syntastic Java diagnostics**. @@ -1187,7 +1280,7 @@ let g:syntastic_java_checkers = [] #### Diagnostic display - Eclim -The native support for Java includes YCM's native realtime diagnostics display. +The native support for Java includes YCM's native real-time diagnostics display. This can conflict with other diagnostics plugins like Eclim, so when enabling Java support, please **manually disable Eclim Java diagnostics**. @@ -1202,15 +1295,15 @@ native Java support. This can be done temporarily with `:EclimDisable`. #### Eclipse Projects -Eclipse style projects require two files: [.project][eclipse-dot-project] and +Eclipse-style projects require two files: [.project][eclipse-dot-project] and [.classpath][eclipse-dot-classpath]. If your project already has these files due to previously being set up within -eclipse, then no setup is required. [jdt.ls][] should load the project just +Eclipse, then no setup is required. [jdt.ls][] should load the project just fine (it's basically eclipse after all). However, if not, it is possible (easy in fact) to craft them manually, though it -is not recommended. You're better off using gradle or maven (see below). +is not recommended. You're better off using Gradle or Maven (see below). [A simple eclipse style project example][ycmd-eclipse-project] can be found in the ycmd test directory. Normally all that is required is to copy these files to @@ -1231,12 +1324,12 @@ located (paths are relative to the .project file itself): **NOTE**: The eclipse project and classpath files are not a public interface and it is highly recommended to use Maven or Gradle project definitions if you -don't already use eclipse to manage your projects. +don't already use Eclipse to manage your projects. #### Maven Projects Maven needs a file named [pom.xml][mvn-project] in the root of the project. -Once again a simple [pom.xml][ycmd-mvn-pom-xml] can be found in ycmd source. +Once again a simple [pom.xml][ycmd-mvn-pom-xml] can be found in the ycmd source. The format of [pom.xml][mvn-project] files is way beyond the scope of this document, but we do recommend using the various tools that can generate them for @@ -1247,9 +1340,9 @@ you, if you're not familiar with them already. Gradle projects require a [build.gradle][gradle-project]. Again, there is a [trivial example in ycmd's tests][ycmd-gradle-project]. -The format of [build.gradle][gradle-project] files is way beyond the scope of +The format of [build.gradle][gradle-project] files are way beyond the scope of this document, but we do recommend using the various tools that can generate -them for you, if you're not familiar with them already. +them for you if you're not familiar with them already. Some users have experienced issues with their jdt.ls when using the Groovy language for their build.gradle. As such, try using @@ -1288,7 +1381,7 @@ of letting YCM know about your solution files. #### Automatically discovered solution files YCM will scan all parent directories of the file currently being edited and look -for file with `.sln` extension. +for a file with `.sln` extension. #### Manually specified solution files @@ -1306,6 +1399,21 @@ def CSharpSolutionFile( filepath ): If the path returned by `CSharpSolutionFile` is not an actual file, YCM will fall back to the other way of finding the file. +#### Use with .NET 6.0 and .NET SDKs + +YCM ships with older version of OmniSharp-Roslyn based on Mono runtime. +It is possible to use it with .NET 6.0 and newer, but it requires manual setup. + +1. Download NET 6.0 version of the OmniSharp server for your system from +[releases](https://github.com/OmniSharp/omnisharp-roslyn/releases/) +1. Set `g:ycm_roslyn_binary_path` to the unpacked executable `OmniSharp` +1. Create a solution file if one doesn't already exist, it is currently required +by YCM for internal bookkeeping + 1. Run `dotnet new sln` at the root of your project + 1. Run `dotnet sln add ...` + for all of your projects +1. Run `:YcmRestartServer` + ### Python Semantic Completion YCM relies on the [Jedi][] engine to provide completion and code navigation. By @@ -1368,7 +1476,7 @@ If you need further control on how to add paths to `sys.path`, you should define the `PythonSysPath( **kwargs )` function in the `.ycm_extra_conf.py` file. Its keyword arguments are `sys_path` which contains the default `sys.path`, and `interpreter_path` which is the path to the Python interpreter. Here's a trivial -example that insert the `/path/to/third_party/package` path at the second +example that inserts the `/path/to/third_party/package` path at the second position of `sys.path`: ```python @@ -1383,7 +1491,7 @@ A more advanced example can be found in [YCM's own #### Configuring through Vim options -You may find inconvenient to have to create a `.ycm_extra_conf.py` file at the +You may find it inconvenient to have to create a `.ycm_extra_conf.py` file at the root of each one of your projects in order to set the path to the Python interpreter and/or add paths to `sys.path` and would prefer to be able to configure those through Vim options. Don't worry, this is possible by using the @@ -1443,8 +1551,19 @@ built YCM with the `--go-completer` flag; see the [*Installation* section](#installation) for details). The server only works for projects with the "canonical" layout. -`gopls` also has a handful of undocumented options for which the -[source code][gopls-preferences] is the only reference. +`gopls` also has a load of [documented options](https://github.com/golang/tools/blob/master/gopls/doc/settings.md). + +You can set these in your `.ycm_extra_conf.py`. For example, to set the build tags: + +```python +def Settings( **kwargs ): + if kwargs[ 'language' ] == 'go': + return { + 'ls': { + 'build.buildFlags': [ '-tags=debug' ] } + } + } +``` ### JavaScript and TypeScript Semantic Completion @@ -1455,12 +1574,12 @@ you if you were already using [Tern][] but you are encouraged to do the switch by deleting the `third_party/ycmd/third_party/tern_runtime/node_modules` directory in YCM folder. If you are a new user but still want to use [Tern][], you should pass the `--js-completer` option to the `install.py` script during -installation. Further instructions on how to setup YCM with [Tern][] are +installation. Further instructions on how to set up YCM with [Tern][] are available on [the wiki][tern-instructions]. All JavaScript and TypeScript features are provided by the [TSServer][] engine, which is included in the TypeScript SDK. To enable these features, install -[Node.js and npm][npm-install] and call the `install.py` script with the +[Node.js 18+ and npm][npm-install] and call the `install.py` script with the `--ts-completer` flag. [TSServer][] relies on [the `jsconfig.json` file][jsconfig.json] for JavaScript @@ -1501,10 +1620,10 @@ let g:ycm_language_server = \ 'filetypes': [ 'yaml' ] \ }, \ { - \ 'name': 'rust', - \ 'cmdline': [ 'ra_lsp_server' ], - \ 'filetypes': [ 'rust' ], - \ 'project_root_files': [ 'Cargo.toml' ] + \ 'name': 'csharp', + \ 'cmdline': [ 'OmniSharp', '-lsp' ], + \ 'filetypes': [ 'csharp' ], + \ 'project_root_files': [ '*.csproj', '*.sln' ] \ }, \ { \ 'name': 'godot', @@ -1515,25 +1634,10 @@ let g:ycm_language_server = \ ] ``` -Each dictionary contains the following keys: - -* `name` (string, mandatory): When [configuring a LSP - server](#lsp-configuration) the value of the `name` key will be used as the - `kwargs[ 'language' ]`. Can be anything you like. -* `filetypes` (list of string, mandatory): List of Vim filetypes this server - should be used for. -* `project_root_files` (list of string, optional): List of filenames to search - for when trying to determine the project root. -* `cmdline` (list of string, optional): If supplied, the server is started with - this command line (each list element is a command line word). Typically, the - server should be started with STDIO communication. If not supplied, `port` - must be supplied. -* `port` (number, optional): If supplied, ycmd will connect to the server at - `localhost:` using TCP (remote servers are not supported). -* `capabilities` (dict, optional): If supplied, this is a dictionary that is - merged with the LSP client capabilities reported to the language server. This - can be used to enable or disable certain features, such as the support for - configuration sections (`workspace/configuration`). +Each dictionary contains the following keys: `name`, `cmdline`, `port`, +`filetypes`, `capabilities`, `project_root_files`, `additional_workspace_dirs`, +`triggerCharacters`, and `settings`. The full description of each key can be +found in the [ycmd][language_server-configuration] repository. See [the LSP Examples](https://github.com/ycm-core/lsp-examples) project for more examples of configuring the likes of PHP, Ruby, Kotlin, and D. @@ -1555,11 +1659,11 @@ def Settings( **kwargs ): ``` The `ls` key tells YCM that the dictionary should be passed to the LSP server. -For each of the LSP server's configuration you should look up the respective +For each of the LSP server's configuration, you should look up the respective server's documentation. Some servers request settings from arbitrary 'sections' of configuration. There -is no concept of configuration sections in vim, so you can specify an additional +is no concept of configuration sections in Vim, so you can specify an additional `config_sections` dictionary which maps section to a dictionary of config required by the server. For example: @@ -1577,7 +1681,7 @@ def Settings( **kwargs ): } ``` -The sections and options/values are complete server-specific and rarely well +The sections and options/values are completely server-specific and rarely well documented. #### Using `omnifunc` for semantic completion @@ -1592,7 +1696,7 @@ the _latest_ Eclim installed and configured (this means Eclim `>= 2.2.*` and Eclipse `>= 4.2.*`). After installing Eclim remember to create a new Eclipse project within your -application by typing `:ProjectCreate -n ruby` inside vim +application by typing `:ProjectCreate -n ruby` inside Vim and don't forget to have `let g:EclimCompletionMethod = 'omnifunc'` in your vimrc. This will make YCM and Eclim play nice; YCM will use Eclim's omnifuncs as the data source for semantic completions and provide the auto-triggering and @@ -1626,7 +1730,7 @@ Completer API. ### Diagnostic Display YCM will display diagnostic notifications for the C-family, C#, Go, Java, -JavaScript, Rust and TypeScript languages. Since YCM continuously recompiles +JavaScript, Rust, and TypeScript languages. Since YCM continuously recompiles your file as you type, you'll get notified of errors and warnings in your file as fast as possible. @@ -1686,6 +1790,10 @@ You can also style the line that has the warning/error with these groups: - `YcmWarningLine`, which falls back to group `SyntasticWarningLine` if it exists +Finally, you can also style the popup for the detailed diagnostics (it is shown +if `g:ycm_show_detailed_diag_in_popup` is set) using the group `YcmErrorPopup`, +which falls back to `ErrorMsg`. + Note that the line highlighting groups only work when the [`g:ycm_enable_diagnostic_signs`](#the-gycm_enable_diagnostic_signs-option) option is set. If you want highlighted lines but no signs in the Vim gutter, @@ -1738,10 +1846,13 @@ e.g. * `nmap yfd (YCMFindSymbolInDocument)` When searching, YCM opens a prompt buffer at the top of the screen for the -input, and puts you in insert mode. This means that you can hit `` to go +input and puts you in insert mode. This means that you can hit `` to go into normal mode and use any other input commands that are supported in prompt buffers. As you type characters, the search is updated. +Initially, results are queried from all open filetypes. You can hit `` to +switch to just the current filetype while the popup is open. + While the popup is open, the following keys are intercepted: * ``, ``, ``, `` - select the next item @@ -1752,6 +1863,7 @@ While the popup is open, the following keys are intercepted: * ``, `` - jump to last item * `` - jump to the selected item * `` cancel/dismiss the popup +* `` - toggle results from all file types or just the current filetype The search is also cancelled if you leave the prompt buffer window at any time, so you can use window commands `...` for example. @@ -1762,6 +1874,60 @@ so you can use window commands `...` for example. for that, or use a window command (e.g. `j`) or the mouse to leave the prompt buffer window. +### Type/Call Hierarchy + +***This feature requires Vim and is not supported in Neovim*** + +**NOTE**: This feature is highly experimental and offered in the hope that it is +useful. Please help us by reporting issues and offering feedback. + +YCM provides a way to view and navigate hierarchies. The following hierarchies +are supported: + +* Type hierachy `(YCMTypeHierarchy)`: Display subtypes and supertypes + of the symbol under cursor. Expand down to subtypes and up to supertypes. +* Call hierarchy `(YCMCallHierarchy)`: Display callees and callers of + the symbol under cursor. Expand down to callers and up to callees. + +Take a look at this [![asciicast](https://asciinema.org/a/659925.svg)](https://asciinema.org/a/659925) +for brief demo. + +Hierarchy UI can be initiated by mapping something to the indicated plug +mappings, for example: + +```viml +nmap yth (YCMTypeHierarchy) +nmap ych (YCMCallHierarchy) +``` + +This opens a "modal" popup showing the current element in the hierarchy tree. +The current tree root is aligned to the left and child and parent nodes are +expanded to the right. Expand the tree "down" with `` and "up" with ``. + +The "root" of the tree can be re-focused to the selected item with +`` and further `` will show the parents of the selected item. This +can take a little getting used to, but it's particularly important with multiple +inheritance where a "child" of the current root may actually have other, +invisible, parent links. `` on that row will show these by setting the +display root to the selected item. + +When the hierarchy is displayed, the following keys are intercepted: + +* ``: Drill into the hierarchy at the selected item: expand and show + children of the selected item. +* ``: Show parents of the selected item. When applied to sub-types, this + will re-root the tree at that type, so that all parent types (are displayed). + Similar for callers. +* ``: Jump to the symbol currently selected. +* ``, ``, ``, `j`: Select the next item +* ``, ``, ``, `k`; Select the previous item +* Any other key: closes the popup without jumping to any location + +**Note:** you might think the call hierarchy tree is inverted, but we think +this way round is more intuitive because this is the typical way that call +stacks are displayed (with the current function at the top, and its callers +below). + Commands -------- @@ -1803,7 +1969,7 @@ This command shows the full diagnostic text when the user's cursor is on the line with the diagnostic. An options argument can be passed. If the argument is `popup` the diagnostic -text will be displayed in a popup at cursor position. +text will be displayed in a popup at the cursor position. If you prefer the detailed diagnostic to always be shown in a popup, then `let g:ycm_show_detailed_diag_in_popup=1`. @@ -1830,7 +1996,7 @@ already open) in the editor. Only for debugging purposes. This command gives access to a number of additional [IDE-like features](#quick-feature-summary) in YCM, for things like semantic GoTo, type -information, FixIt and refactoring. +information, FixIt, and refactoring. This command accepts a range that can either be specified through a selection in one of Vim's visual modes (see `:h visual-use`) or on the command line. For @@ -1844,6 +2010,11 @@ See the [file type feature summary](#quick-feature-summary) for an overview of the features available for each file type. See the _YcmCompleter subcommands_ section for more information on the available subcommands and their usage. +Some commands, like `Format` accept a range, like `:%YcmCompleter Format`. + +Some commands like `GetDoc` and the various `GoTo` commands respect modifiers, +like `:rightbelow YcmCompleter GetDoc`, `:vertical YcmCompleter GoTo`. + YcmCompleter Subcommands ------------------------ @@ -1867,7 +2038,7 @@ the cursor, the subcommands add entries to Vim's `jumplist` so you can use `CTRL-O` to jump back to where you were before invoking the command (and `CTRL-I` to jump forward; see `:h jumplist` for details). If there is more than one destination, the quickfix list (see `:h quickfix`) is populated with -the available locations and opened to full width at the bottom of the screen. +the available locations and opened to the full width at the bottom of the screen. You can change this behavior by using [the `YcmQuickFixOpened` autocommand](#the-ycmquickfixopened-autocommand). @@ -1877,6 +2048,13 @@ Looks up the current line for a header and jumps to it. Supported in filetypes: `c, cpp, objc, objcpp, cuda` +#### The `GoToAlternateFile` subcommand + +Jump to the associated file, as defined by the language server. Typically this +will jump you to the associated header file for a C or C++ translation unit. + +Supported in filetypes: `c, cpp, objc, objcpp, cuda` (clangd only) + #### The `GoToDeclaration` subcommand Looks up the symbol under the cursor and jumps to its declaration. @@ -1914,7 +2092,7 @@ WARNING: This command trades correctness for speed! Same as the `GoTo` command except that it doesn't recompile the file with libclang before looking up nodes in the AST. This can be very useful when you're -editing files that take long to compile but you know that you haven't made any +editing files that take time to compile but you know that you haven't made any changes since the last parse that would lead to incorrect jumps. When you're just browsing around your codebase, this command can spare you quite a bit of latency. @@ -1962,24 +2140,27 @@ Supported in filetypes: `go, java, javascript, typescript` #### The `GoToDocumentOutline` subcommand -Provides a list of symbols in current document, in the quickfix list. See also +Provides a list of symbols in the current document, in the quickfix list. See also [interactive symbol search](#symbol-search). Supported in filetypes: `c, cpp, objc, objcpp, cuda, go, java, rust` #### The `GoToCallers` and `GoToCallees` subcommands +Note: A much more powerful call and type hierarchy can be viewd interactively. +See [interactive type and call hierarchy](#interactive-type-and-call-hierarchy). + Populate the quickfix list with the callers, or callees respectively, of the function associated with the current cursor position. The semantics of this differ depending on the filetype and language server. -Only supported for LSP servers which provide the `callHierarchyProvider` +Only supported for LSP servers that provide the `callHierarchyProvider` capability. ### Semantic Information Commands These commands are useful for finding static information about the code, such -as the types of variables, viewing declarations and documentation strings. +as the types of variables, viewing declarations, and documentation strings. #### The `GetType` subcommand @@ -2005,7 +2186,7 @@ WARNING: This command trades correctness for speed! Same as the `GetType` command except that it doesn't recompile the file with libclang before looking up nodes in the AST. This can be very useful when you're -editing files that take long to compile but you know that you haven't made any +editing files that take time to compile but you know that you haven't made any changes since the last parse that would lead to incorrect type. When you're just browsing around your codebase, this command can spare you quite a bit of latency. @@ -2053,6 +2234,27 @@ under the cursor. Depending on the file type, this includes things like: * Python docstrings, * etc. +The documentation is opened in the preview window, and options like +`previewheight` are respected. If you would like to customise the height and +position of this window, we suggest a custom command that: + +* Sets `previewheight` temporarily +* Runs the `GetDoc` command with supplied modifiers +* Restores `previewheight`. + +For example: + +```viml +command -count ShowDocWithSize + \ let g:ph=&previewheight + \ set previewheight= + \ YcmCompleter GetDoc + \ let &previewheight=g:ph +``` + +You can then use something like `:botright vertical 80ShowDocWithSize`. Here's an +example of that: https://asciinema.org/a/hE6Pi1gU6omBShwFna8iwGEe9 + Supported in filetypes: `c, cpp, objc, objcpp, cuda, cs, go, java, javascript, python, typescript, rust` @@ -2077,23 +2279,35 @@ undone, and never saves or writes files to the disk. #### The `FixIt` subcommand -Where available, attempts to make changes to the buffer to correct diagnostics -on the current line. Where multiple suggestions are available (such as when -there are multiple ways to resolve a given warning, or where multiple -diagnostics are reported for the current line), the options are presented -and one can be selected. +Where available, attempts to make changes to the buffer to correct diagnostics, +or perform refactoring, on the current line or selection. Where multiple +suggestions are available (such as when there are multiple ways to resolve a +given warning, or where multiple diagnostics are reported for the current line, +or multiple refactoring tweaks are available), the options are presented and +one can be selected. -Completers which provide diagnostics may also provide trivial modifications to +Completers that provide diagnostics may also provide trivial modifications to the source in order to correct the diagnostic. Examples include syntax errors such as missing trailing semi-colons, spurious characters, or other errors which -the semantic engine can deterministically suggest corrections. +the semantic engine can deterministically suggest corrections. A small demo +presenting how diagnostics can be fixed with clangd: + +![YcmCompleter-FixIt-OnDiagnostic](https://user-images.githubusercontent.com/17928698/206855014-9131a49b-87e8-4ed4-8d91-f2fe7808a0b9.gif) + +Completers (LSPs) may also provide refactoring tweaks, which may be available +even when no diagnostic is presented for the current line. These include +function extraction, variable extraction, `switch` population, constructor +generation, ... The tweaks work for a selection as well. Consult your LSP for +available refactorings. A demonstration of refactoring capabilities with clangd: + +![YouCompleter-FixIt-Refactoring](https://user-images.githubusercontent.com/17928698/206855713-3588c8de-d0f5-4725-b65e-bc51110252cc.gif) If no fix-it is available for the current line, or there is no diagnostic on the current line, this command has no effect on the current buffer. If any modifications are made, the number of changes made to the buffer is echo'd and the user may use the editor's undo command to revert. -When a diagnostic is available, and `g:ycm_echo_current_diagnostic` is set to 1, +When a diagnostic is available, and `g:ycm_echo_current_diagnostic` is enabled, then the text ` (FixIt)` is appended to the echo'd diagnostic when the completer is able to add this indication. The text ` (FixIt available)` is also appended to the diagnostic text in the output of the `:YcmDiags` command @@ -2109,7 +2323,7 @@ rust, typescript` In supported file types, this command attempts to perform a semantic rename of the identifier under the cursor. This includes renaming declarations, -definitions and usages of the identifier, or any other language-appropriate +definitions, and usages of the identifier, or any other language-appropriate action. The specific behavior is defined by the semantic engine in use. Similar to `FixIt`, this command applies automatic modifications to your source @@ -2119,6 +2333,18 @@ you. The behavior is described in [the following section](#multi-file-refactor). Supported in filetypes: `c, cpp, objc, objcpp, cuda, java, javascript, python, typescript, rust, cs` +#### Python refactorings + +The following additional commands are supported for Python: + +* `RefactorInline` +* `RefactorExtractVariable` +* `RefactorExtractFunction` + +See the [jedi docs][jedi-refactor-doc] for what they do. + +Supported in filetypes: `python` + #### Multi-file Refactor When a Refactor or FixIt command touches multiple files, YouCompleteMe attempts @@ -2142,7 +2368,7 @@ can be undone using Vim's powerful undo features (see `:help undo`). Note that Vim's undo is per-buffer, so to undo all changes, the undo commands must be applied in each modified buffer separately. -**NOTE:** While applying modifications, Vim may find files which are already +**NOTE:** While applying modifications, Vim may find files that are already open and have a swap file. The command is aborted if you select Abort or Quit in any such prompts. This leaves the Refactor operation partially complete and must be manually corrected using Vim's undo features. The quickfix list is *not* @@ -2163,7 +2389,7 @@ Supported in filetypes: `c, cpp, objc, objcpp, cuda, java, javascript, go, types #### The `OrganizeImports` subcommand This command removes unused imports and sorts imports in the current file. It -can also group imports from the same module in TypeScript and resolves imports +can also group imports from the same module in TypeScript and resolve imports in Java. Supported in filetypes: `java, javascript, typescript` @@ -2177,7 +2403,7 @@ flags. #### The `ExecuteCommand ` subcommand Some LSP completers (currently only Java completers) support executing -server specific commands. Consult the [jdt.ls][] documentation to find out +server-specific commands. Consult the [jdt.ls][] documentation to find out what commands are supported and which arguments are expected. The support for `ExecuteCommand` was implemented to support plugins like @@ -2193,7 +2419,7 @@ Supported in filetypes: `c, cpp, objc, objcpp, cuda, cs, go, java, javascript, r #### The `ReloadSolution` subcommand Instruct the Omnisharp-Roslyn server to clear its cache and reload all files -from disk. This is useful when files are added, removed, or renamed in the +from the disk. This is useful when files are added, removed, or renamed in the solution, files are changed outside of Vim, or whenever Omnisharp-Roslyn cache is out-of-sync. @@ -2232,7 +2458,7 @@ For example: ### The `youcompleteme#GetCommandResponse( ... )` function Run a [completer subcommand](#ycmcompleter-subcommands) and return the result as -a string. This can be useful for example to display the `GetGoc` output in a +a string. This can be useful for example to display the `GetDoc` output in a popup window, e.g.: ```viml @@ -2312,7 +2538,7 @@ support. this function. **NOTE**: Only one command request can be outstanding at once. Attempting to -request a second responses while the first is outstanding will result in the +request a second response while the first is outstanding will result in the second callback being immediately called with `''`. Autocommands @@ -2333,7 +2559,7 @@ function! s:CustomizeYcmLocationWindow() wincmd K " Set the window height to 5. 5wincmd _ - " Switch back to working window. + " Switch back to the working window. wincmd p endfunction @@ -2420,7 +2646,7 @@ suggestions from the identifier-based engine. A special value of `0` means there is no limit. **NOTE:** Setting this option to `0` or to a value greater than `100` is not -recommended as it will slow down completion when there are a very large number +recommended as it will slow down completion when there is a very large number of suggestions. Default: `50` @@ -2432,7 +2658,7 @@ let g:ycm_max_num_candidates = 50 ### The `g:ycm_max_num_candidates_to_detail` option Some completion engines require completion candidates to be 'resolved' in order -to get detailed info such as inline documentation, method signatures etc. This +to get detailed info such as inline documentation, method signatures, etc. This information is displayed by YCM in the preview window, or if `completeopt` contains `popup`, in the info popup next to the completion menu. @@ -2449,12 +2675,12 @@ need to change this, as YCM will work out an appropriate value based on your `completeopt` and `g:ycm_add_preview_to_completeopt` settings. However, you may override this calculation by setting this value to a number: -* `-1` - Resolve all candidates up front -* `0` - Never resolve any candidates up front. -* `> 0` - Resolve up to this many candidates up front. If the number of +* `-1` - Resolve all candidates upfront +* `0` - Never resolve any candidates upfront. +* `> 0` - Resolve up to this many candidates upfront. If the number of candidates is greater than this value, no candidates are resolved. -In the later two cases, if `completeopt` contains `popup`, then candidates are +In the latter two cases, if `completeopt` contains `popup`, then candidates are resolved on demand asynchronously. Default: @@ -2477,7 +2703,7 @@ identifier-based engine shown in the completion menu. A special value of `0` means there is no limit. **NOTE:** Setting this option to `0` or to a value greater than `100` is not -recommended as it will slow down completion when there are a very large number +recommended as it will slow down completion when there is a very large number of suggestions. Default: `10` @@ -2497,6 +2723,21 @@ If you want to just turn off the identifier completer but keep the semantic triggers, you should set `g:ycm_min_num_of_chars_for_completion` to a high number like `99`. +When `g:ycm_auto_trigger` is `0`, YCM sets the `completefunc`, so that you can +manually trigger normal completion using `C-x C-u`. + +If you want to map something else to trigger completion, such as `C-d`, +then you can map it to `(YCMComplete)`. For example: + +```viml +let g:ycm_auto_trigger = 0 +imap (YCMComplete) +``` + +NOTE: It's not possible to map one of the keys in +`g:ycm_key_list_select_completion` (or similar) to `(YCMComplete)`. In +practice that means that you can't use `` for this. + Default: `1` ```viml @@ -2523,7 +2764,7 @@ The filetype should then be present in the whitelist either directly (`cpp` key in the whitelist) or indirectly through the special `*` key. It should _not_ be present in the blacklist. -Filetypes that are blocked by the either of the lists will be completely ignored +Filetypes that are blocked by either of the lists will be completely ignored by YCM, meaning that neither the identifier-based completion engine nor the semantic engine will operate in them. @@ -2636,7 +2877,7 @@ When set, this option turns on YCM's diagnostic display features. See the _Diagnostic display_ section in the _User Manual_ for more details. Specific parts of the diagnostics UI (like the gutter signs, text highlighting, -diagnostic echo and auto location list population) can be individually turned on +diagnostic echo, and auto location list population) can be individually turned on or off. See the other options below for details. Note that YCM's diagnostics UI is only supported for C-family languages. @@ -2718,9 +2959,23 @@ let g:ycm_enable_diagnostic_highlighting = 1 ### The `g:ycm_echo_current_diagnostic` option -When this option is set, YCM will echo the text of the diagnostic present on the -current line when you move your cursor to that line. If a `FixIt` is available -for the current diagnostic, then ` (FixIt)` is appended. +When this option is set to 1, YCM will echo the text of the diagnostic present +on the current line when you move your cursor to that line. If a `FixIt` is +available for the current diagnostic, then ` (FixIt)` is appended. + +If you have a Vim that supports virtual text, you can set this option +to the string `virtual-text`, and the diagnostic will be displayed inline with +the text, right aligned in the window and wrapping to the next line if there is +not enough space, for example: + +![Virtual text diagnostic demo][diagnostic-echo-virtual-text1] + +![Virtual text diagnostic demo][diagnostic-echo-virtual-text2] + +**NOTE**: It's _strongly_ recommended to also set +`g:ycm_update_diagnostics_in_insert_mode` to `0` when using `virtual-text` for +diagnostics. This is due to the increased amount of distraction provided by +drawing diagnostics next to your input position. This option is part of the Syntastic compatibility layer; if the option is not set, YCM will fall back to the value of the `g:syntastic_echo_current_error` @@ -2728,8 +2983,17 @@ option before using this option's default. Default: `1` +Valid values: + +* `0` - disabled +* `1` - echo diagnostic to the command area +* `'virtual-text'` - display the dignostic to the right of the line in the + window using virtual text + ```viml let g:ycm_echo_current_diagnostic = 1 +" Or, when you have Vim supporting virtual text +let g:ycm_echo_current_diagnostic = 'virtual-text' ``` ### The `g:ycm_auto_hover` option @@ -2766,6 +3030,7 @@ buffer-local variable can be set to a dictionary with the following keys: * `command`: The YCM completer subcommand which should be run on hover * `syntax`: The syntax to use (as in `set syntax=`) in the popup window for highlighting. +* `popup_params`: The params passed to a popup window which gets opened. For example, to use C/C++ syntax highlighting in the popup for C-family languages, add something like this to your vimrc: @@ -2780,6 +3045,25 @@ augroup MyYCMCustom augroup END ``` +You can also modify the opened popup with `popup_params` key. +For example, you can limit the popup's maximum width and add a border to it: + +```viml +augroup MyYCMCustom + autocmd! + autocmd FileType c,cpp let b:ycm_hover = { + \ 'command': 'GetDoc', + \ 'syntax': &filetype + \ 'popup_params': { + \ 'maxwidth': 80, + \ 'border': [], + \ 'borderchars': ['─', '│', '─', '│', '┌', '┐', '┘', '└'], + \ }, + \ } +augroup END +``` +See `:help popup_create-arguments` for the list of available popup window options. + Default: `'CursorHold'` ### The `g:ycm_filter_diagnostics` option @@ -2807,7 +3091,7 @@ specifying `level: "error"` will remove **all** errors from the diagnostics. Default: `{}` -The following example will do, for java filetype only: +The following example will do, for Java filetype only: - Remove **all** error level diagnostics, and, - Also remove anything that contains `taco` @@ -2993,7 +3277,7 @@ When this option is set to `1`, YCM and the [ycmd completion server][ycmd] will keep the logfiles around after shutting down (they are deleted on shutdown by default). -To see where the logfiles are, call `:YcmDebugInfo`. +To see where the log files are, call `:YcmDebugInfo`. Default: `0` @@ -3158,7 +3442,7 @@ let g:ycm_key_list_select_completion = ['', ''] ### The `g:ycm_key_list_previous_completion` option This option controls the key mappings used to select the previous completion -string. Invoking any of them repeatedly cycles backwards through the completion +string. Invoking any of them repeatedly cycles backward through the completion list. Note that one of the defaults is `` which means Shift-TAB. That mapping @@ -3188,14 +3472,15 @@ let g:ycm_key_list_stop_completion = [''] This option controls the key mapping used to invoke the completion menu for semantic completion. By default, semantic completion is triggered automatically -after typing `.`, `->` and `::` in insert mode (if semantic completion support -has been compiled in). This key mapping can be used to trigger semantic -completion anywhere. Useful for searching for top-level functions and classes. +after typing characters appropriate for the language, such as `.`, `->`, `::`, +etc. in insert mode (if semantic completion support has been compiled in). This +key mapping can be used to trigger semantic completion anywhere. Useful for +searching for top-level functions and classes. Console Vim (not Gvim or MacVim) passes `` to Vim when the user types `` so YCM will make sure that `` is used in the map command when you're editing in console Vim, and `` in GUI Vim. This means that you -can just press `` in both console and GUI Vim and YCM will do the right +can just press `` in both the console and GUI Vim and YCM will do the right thing. Setting this option to an empty string will make sure no mapping is created. @@ -3252,7 +3537,7 @@ let g:ycm_global_ycm_extra_conf = '' ### The `g:ycm_confirm_extra_conf` option When this option is set to `1` YCM will ask once per `.ycm_extra_conf.py` file -if it is safe to be loaded. This is to prevent execution of malicious code +if it is safe to be loaded. This is to prevent the execution of malicious code from a `.ycm_extra_conf.py` file you didn't write. To selectively get YCM to ask/not ask about loading certain `.ycm_extra_conf.py` @@ -3363,8 +3648,8 @@ let g:ycm_semantic_triggers = { Some omnicompletion engines do not work well with the YCM cache—in particular, they might not produce all possible results for a given prefix. By unsetting this option you can ensure that the omnicompletion engine is re-queried on every -keypress. That will ensure all completions will be presented, but might cause -stuttering and lagginess if the omnifunc is slow. +keypress. That will ensure all completions will be presented but might cause +stuttering and lag if the omnifunc is slow. Default: `1` @@ -3430,7 +3715,7 @@ let g:ycm_disable_for_files_larger_than_kb = 1000 ### The `g:ycm_use_clangd` option -This option controls whether **clangd** should be used as completion engine for +This option controls whether **clangd** should be used as a completion engine for C-family languages. Can take one of the following values: `1`, `0`, with meanings: @@ -3490,7 +3775,7 @@ making sure YCM won't choose that existing completer in the first place. A simple working example of this option can be found in the section called ["Semantic Completion for Other Languages"](#semantic-completion-for-other-languages). -Many working examples can be found in the YCM [lsp-examples][] repo. +Many working examples can be found in the YCM [lsp-examples][] repository. Default: `[]` @@ -3501,9 +3786,7 @@ let g:ycm_language_server = [] ### The `g:ycm_disable_signature_help` option This option allows you to disable all signature help for all completion engines. -There is no way to disable it per-completer. This option is _reserved_, meaning -that while signature help support remains experimental, its values and meaning -may change and it may be removed in a future version. +There is no way to disable it per-completer. Default: `0` @@ -3512,6 +3795,19 @@ Default: `0` let g:ycm_disable_signature_help = 1 ``` +### The `g:ycm_signature_help_disable_syntax` option + +Set this to 1 to disable syntax highlighting in the signature help popup. Thiis +can help if your colourscheme doesn't work well with the default highliting and +inverse video. + +Default: `0` + +```viml +" Disable signature help syntax highliting +let g:ycm_signature_help_disable_syntax = 1 +``` + ### The `g:ycm_gopls_binary_path` option In case the system-wide `gopls` binary is newer than the bundled one, setting @@ -3562,6 +3858,14 @@ With async diagnostics, LSP servers might send new diagnostics mid-typing. If seeing these new diagnostics while typing is not desired, this option can be set to 0. +When this option is set to `0`, diagnostic signs, virtual text, and highlights +are cleared when entering insert mode and replaced when leaving insert mode. +This reduces visual noise while editing. + +In addition, this option is recommended when `g:ycm_echo_current_diagnostic` is +set to `virtual-text` as it prevents updating the virtual text while you are +typing. + Default: `1` ```viml @@ -3597,8 +3901,9 @@ The latest version of the plugin is available at The author's homepage is . -Please do **NOT** go to #vim on freenode for support. Please contact the -YouCompleteMe maintainers directly using the [contact details](#contact). +Please do **NOT** go to #vim, Reddit, or Stack Overflow for support. Please +contact the YouCompleteMe maintainers directly using the [contact +details](#contact). License ------- @@ -3609,15 +3914,15 @@ This software is licensed under the [GPL v3 license][gpl]. Sponsorship ----------- -If you like YCM so much that you're wiling to part with your hard-earned cash, please consider donating to one of the following charities, which are meaningful to the current maintainers (in no particular order): +If you like YCM so much that you're willing to part with your hard-earned cash, please consider donating to one of the following charities, which are meaningful to the current maintainers (in no particular order): -* [Greyhound Rescue Wales](https://greyhoundrescuewales.co.uk) +* [Hector's Greyhound Rescue](https://www.hectorsgreyhoundrescue.org) * [Be Humane](https://www.budihuman.rs/en) * [Cancer Research UK](https://www.cancerresearchuk.org) * [ICCF Holland](https://iccf.nl) * Any charity of your choosing. -Please note: The YCM maintainers do not specifically endorse nor necessarily have any relationship with the above charities. Disclosure: It is noted that one key maintainer is family with Trustees of Greyhound Rescue Wales. +Please note: The YCM maintainers do not specifically endorse nor necessarily have any relationship with the above charities. Disclosure: It is noted that one key maintainer is a family with Trustees of Greyhound Rescue Wales. [ycmd]: https://github.com/ycm-core/ycmd @@ -3673,7 +3978,7 @@ Please note: The YCM maintainers do not specifically endorse nor necessarily hav [++enc]: http://vimdoc.sourceforge.net/htmldoc/editing.html#++enc [contributing-md]: https://github.com/ycm-core/YouCompleteMe/blob/master/CONTRIBUTING.md [jdt.ls]: https://github.com/eclipse/eclipse.jdt.ls -[jdk-install]: https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html +[jdk-install]: https://adoptium.net/en-GB/temurin/releases [mvn-project]: https://maven.apache.org/guides/getting-started/maven-in-five-minutes.html [eclipse-project]: https://help.eclipse.org/oxygen/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fmisc%2Fproject_description_file.html [gradle-project]: https://docs.gradle.org/current/userguide/tutorial_java_projects.html @@ -3692,3 +3997,7 @@ Please note: The YCM maintainers do not specifically endorse nor necessarily hav [wiki-full-install]: https://github.com/ycm-core/YouCompleteMe/wiki/Full-Installation-Guide [wiki-troubleshooting]: https://github.com/ycm-core/YouCompleteMe/wiki/Troubleshooting-steps-for-ycmd-server-SHUT-DOWN [lsp-examples]: https://github.com/ycm-core/lsp-examples +[language_server-configuration]: https://github.com/ycm-core/ycmd#language_server-configuration +[diagnostic-echo-virtual-text1]: https://user-images.githubusercontent.com/10584846/185707973-39703699-0263-47d3-82ac-639d52259bea.png +[diagnostic-echo-virtual-text2]: https://user-images.githubusercontent.com/10584846/185707993-14ff5fd7-c082-4e5a-b825-f1364e619b6a.png +[jedi-refactor-doc]: https://jedi.readthedocs.io/en/latest/docs/api.html#jedi.Script.extract_variable diff --git a/autoload/youcompleteme.vim b/autoload/youcompleteme.vim index 1090722ccb..e365bc630d 100644 --- a/autoload/youcompleteme.vim +++ b/autoload/youcompleteme.vim @@ -19,8 +19,8 @@ let s:save_cpo = &cpo set cpo&vim -" NOTE: Noevim reports v:version as 800, which is garbage. For some features -" that are supporetd by our minimum Vim version, we have to guard them against +" NOTE: Neovim reports v:version as 800, which is garbage. For some features +" that are supported by our minimum Vim version, we have to guard them against " neovim, which doesn't implement them. let s:is_neovim = has( 'nvim' ) @@ -30,6 +30,7 @@ let g:ycm_neovim_ns_id = s:is_neovim ? nvim_create_namespace( 'ycm_id' ) : -1 " This needs to be called outside of a function let s:script_folder_path = escape( expand( ':p:h' ), '\' ) let s:force_semantic = 0 +let s:force_manual = 0 let s:completion_stopped = 0 " These two variables are initialized in youcompleteme#Enable. let s:default_completion = {} @@ -40,28 +41,37 @@ let s:previous_allowed_buffer_number = 0 let s:pollers = { \ 'completion': { \ 'id': -1, - \ 'wait_milliseconds': 10 + \ 'wait_milliseconds': 10, \ }, \ 'signature_help': { \ 'id': -1, - \ 'wait_milliseconds': 10 + \ 'wait_milliseconds': 10, \ }, \ 'file_parse_response': { \ 'id': -1, - \ 'wait_milliseconds': 100 + \ 'wait_milliseconds': 100, \ }, \ 'server_ready': { \ 'id': -1, - \ 'wait_milliseconds': 100 + \ 'wait_milliseconds': 100, \ }, \ 'receive_messages': { \ 'id': -1, - \ 'wait_milliseconds': 100 + \ 'wait_milliseconds': 100, \ }, \ 'command': { \ 'id': -1, - \ 'wait_milliseconds': 100 - \ } + \ 'wait_milliseconds': 100, + \ 'requests': {}, + \ }, + \ 'semantic_highlighting': { + \ 'id': -1, + \ 'wait_milliseconds': 100, + \ }, + \ 'inlay_hints': { + \ 'id': -1, + \ 'wait_milliseconds': 100, + \ }, \ } let s:buftype_blacklist = { \ 'help': 1, @@ -73,6 +83,7 @@ let s:buftype_blacklist = { let s:last_char_inserted_by_user = v:true let s:enable_hover = 0 let s:cursorhold_popup = -1 +let s:enable_inlay_hints = 0 let s:force_preview_popup = 0 @@ -139,7 +150,7 @@ function! youcompleteme#Enable() \ g:ycm_add_preview_to_completeopt " Will we be using the preview popup ? That is either the user set it in their - " compelteopt or we're going to add it later. + " completeopt or we're going to add it later. let use_preview_popup = \ s:force_preview_popup || \ index( completeopt, 'popup' ) >= 0 @@ -158,7 +169,7 @@ function! youcompleteme#Enable() " supported, enable it. let s:resolve_completions = s:RESOLVE_ON_DEMAND elseif require_resolve - " The preview window or info popup is enalbed - request the server + " The preview window or info popup is enabled - request the server " pre-resolves completion items let s:resolve_completions = s:RESOLVE_UP_FRONT else @@ -172,6 +183,9 @@ function! youcompleteme#Enable() call s:SetUpOptions() + py3 ycm_semantic_highlighting.Initialise() + let s:enable_inlay_hints = py3eval( 'ycm_inlay_hints.Initialise()' ) ? 1 : 0 + call youcompleteme#EnableCursorMovedAutocommands() augroup youcompleteme autocmd! @@ -211,9 +225,9 @@ function! youcompleteme#Enable() \ } ) endif - nnoremap (YCMFindSymbolInWorkspace) + nnoremap (YCMFindSymbolInWorkspace) \ :call youcompleteme#finder#FindSymbol( 'workspace' ) - nnoremap (YCMFindSymbolInDocument) + nnoremap (YCMFindSymbolInDocument) \ :call youcompleteme#finder#FindSymbol( 'document' ) endfunction @@ -223,11 +237,14 @@ function! youcompleteme#EnableCursorMovedAutocommands() autocmd! autocmd CursorMoved * call s:OnCursorMovedNormalMode() autocmd CursorMovedI * let s:current_cursor_position = getpos( '.' ) - autocmd InsertEnter * let s:current_cursor_position = getpos( '.' ) + autocmd InsertEnter * call s:OnInsertEnter() autocmd TextChanged * call s:OnTextChangedNormalMode() autocmd TextChangedI * call s:OnTextChangedInsertMode( v:false ) autocmd TextChangedP * call s:OnTextChangedInsertMode( v:true ) autocmd InsertCharPre * call s:OnInsertChar() + if exists( '##WinScrolled' ) + autocmd WinScrolled * call s:OnWinScrolled() + endif augroup END endfunction @@ -265,6 +282,8 @@ sys.path[ 0:0 ] = [ p.join( root_folder, 'python' ), try: # Import the modules used in this file. from ycm import base, vimsupport, youcompleteme + from ycm import semantic_highlighting as ycm_semantic_highlighting + from ycm import inlay_hints as ycm_inlay_hints if 'ycm_state' in globals(): # If re-initializing, pretend that we shut down @@ -274,18 +293,18 @@ try: # If we're able to resolve completion details asynchronously, set the option # which enables this in the server. if int( vim.eval( 's:resolve_completions == s:RESOLVE_ON_DEMAND' ) ): - # resovle a small number upfront, the rest on demand + # resolve a small number upfront, the rest on demand default_options = { 'max_num_candidates_to_detail': 10 } elif int( vim.eval( 's:resolve_completions == s:RESOLVE_NONE' ) ): - # don't reasolve any + # don't resolve any default_options = { 'max_num_candidates_to_detail': 0 } else: # i.e. s:resolve_completions == s:RESOLVE_UP_FRONT - # The server will decide - i.e. resovle everything upfront + # The server will decide - i.e. resolve everything upfront default_options = {} ycm_state = youcompleteme.YouCompleteMe( default_options ) @@ -418,7 +437,65 @@ function! s:SetUpSyntaxHighlighting() endif if s:PropertyTypeNotDefined( 'YcmErrorProperty' ) call prop_type_add( 'YcmErrorProperty', { - \ 'highlight': 'YcmErrorSection' } ) + \ 'highlight': 'YcmErrorSection', + \ 'priority': 30, + \ 'combine': 0, + \ 'override': 1 } ) + endif + + " Used for virtual text + if !hlexists( 'YcmInvisible' ) + highlight default link YcmInvisible Normal + endif + if !hlexists( 'YcmInlayHint' ) + highlight default link YcmInlayHint NonText + endif + if !hlexists( 'YcmErrorText' ) + if exists( '*hlget' ) + let YcmErrorText = hlget( 'SpellBad', v:true )[ 0 ] + let YcmErrorText.name = 'YcmErrorText' + let YcmErrorText.cterm = {} + let YcmErrorText.gui = {} + let YcmErrorText.term = {} + call hlset( [ YcmErrorText ] ) + else + " approximation + hi default link YcmErrorText WarningMsg + endif + endif + if !hlexists( 'YcmWarningText' ) + if exists( '*hlget' ) + let YcmWarningText = hlget( 'SpellCap', v:true )[ 0 ] + let YcmWarningText.name = 'YcmWarningText' + let YcmWarningText.cterm = {} + let YcmWarningText.gui = {} + let YcmWarningText.term = {} + call hlset( [ YcmWarningText] ) + else + " Lame approximation + hi default link YcmWarningText Conceal + endif + endif + + if s:PropertyTypeNotDefined( 'YcmVirtDiagError' ) + call prop_type_add( 'YcmVirtDiagError', { + \ 'highlight': 'YcmErrorText', + \ 'priority': 20, + \ 'combine': 0 } ) + endif + if s:PropertyTypeNotDefined( 'YcmVirtDiagWarning' ) + call prop_type_add( 'YcmVirtDiagWarning', { + \ 'highlight': 'YcmWarningText', + \ 'priority': 19, + \ 'combine': 0 } ) + endif + + + if s:PropertyTypeNotDefined( 'YcmVirtDiagPadding' ) + call prop_type_add( 'YcmVirtDiagPadding', { + \ 'highlight': 'YcmInvisible', + \ 'priority': 100, + \ 'combine': 1 } ) endif if !hlexists( 'YcmWarningSection' ) @@ -430,7 +507,14 @@ function! s:SetUpSyntaxHighlighting() endif if s:PropertyTypeNotDefined( 'YcmWarningProperty' ) call prop_type_add( 'YcmWarningProperty', { - \ 'highlight': 'YcmWarningSection' } ) + \ 'highlight': 'YcmWarningSection', + \ 'priority': 29, + \ 'combine': 0, + \ 'override': 1 } ) + endif + + if !hlexists( 'YcmErrorPopup' ) + highlight default link YcmErrorPopup ErrorMsg endif endfunction @@ -476,15 +560,6 @@ function! s:DisableOnLargeFile( buffer ) return b:ycm_largefile endfunction -function! s:HasAnyKey( dict, keys ) - for key in a:keys - if has_key( a:dict, key ) - return 1 - endif - endfor - return 0 -endfunction - function! s:PropertyTypeNotDefined( type ) return exists( '*prop_type_add' ) && \ index( prop_type_list(), a:type ) == -1 @@ -502,21 +577,13 @@ function! s:AllowedToCompleteInBuffer( buffer ) let filetype = 'ycm_nofiletype' endif - let whitelist_allows = type( g:ycm_filetype_whitelist ) != v:t_dict || - \ has_key( g:ycm_filetype_whitelist, '*' ) || - \ s:HasAnyKey( g:ycm_filetype_whitelist, split( filetype, '\.' ) ) - let blacklist_allows = type( g:ycm_filetype_blacklist ) != v:t_dict || - \ !s:HasAnyKey( g:ycm_filetype_blacklist, split( filetype, '\.' ) ) - - let allowed = whitelist_allows && blacklist_allows + let allowed = youcompleteme#filetypes#AllowedForFiletype( filetype ) if !allowed || s:DisableOnLargeFile( a:buffer ) return 0 endif - if allowed - let s:previous_allowed_buffer_number = bufnr( a:buffer ) - endif + let s:previous_allowed_buffer_number = bufnr( a:buffer ) return allowed endfunction @@ -577,6 +644,9 @@ endfunction function! s:EnableCompletingInCurrentBuffer() + if !g:ycm_auto_trigger + call s:SetCompleteFunc() + endif let b:ycm_completing = 1 endfunction @@ -647,6 +717,12 @@ function! s:EnableAutoHover() augroup YcmBufHover autocmd! * autocmd CursorHold call s:Hover() + if exists( '##WinResized' ) + autocmd WinResized call popup_close( s:cursorhold_popup ) + endif + if exists( '##WinScrolled' ) + autocmd WinScrolled call popup_close( s:cursorhold_popup ) + endif augroup END endif endfunction @@ -690,12 +766,29 @@ function! s:OnFileSave() endfunction +function! s:AbortAutohoverRequest() abort + if g:ycm_auto_hover ==# 'CursorHold' && s:enable_hover + let requests = copy( s:pollers.command.requests ) + for request_id in keys( requests ) + let request = requests[ request_id ] + if request.origin == 'autohover' + call remove( s:pollers.command.requests, request_id ) + py3 ycm_state.FlushCommandRequest( int( vim.eval( "request_id" ) ) ) + call request.callback( '' ) + endif + endfor + endif +endfunction + + function! s:OnBufferEnter() call s:StartMessagePoll() if !s:VisitedBufferRequiresReparse() return endif + call s:AbortAutohoverRequest() + call s:SetUpCompleteopt() call s:EnableCompletingInCurrentBuffer() @@ -746,8 +839,8 @@ function! s:OnFileReadyToParse( ... ) " We only want to send a new FileReadyToParse event notification if the buffer " has changed since the last time we sent one, or if forced. if force_parsing || py3eval( "ycm_state.NeedsReparse()" ) - " We switched buffers or somethuing, so claer. - " FIXME: sig hekp should be buffer local? + " We switched buffers or something, so clear. + " FIXME: sig help should be buffer local? call s:ClearSignatureHelp() py3 ycm_state.OnFileReadyToParse() @@ -755,6 +848,54 @@ function! s:OnFileReadyToParse( ... ) let s:pollers.file_parse_response.id = timer_start( \ s:pollers.file_parse_response.wait_milliseconds, \ function( 's:PollFileParseResponse' ) ) + + call s:UpdateSemanticHighlighting( bufnr(), 1, 0 ) + call s:UpdateInlayHints( bufnr(), 1, 0 ) + + endif +endfunction + +function! s:UpdateSemanticHighlighting( bufnr, force, redraw_anyway ) abort + call s:StopPoller( s:pollers.semantic_highlighting ) + if !s:is_neovim && + \ get( b:, 'ycm_enable_semantic_highlighting', + \ get( g:, 'ycm_enable_semantic_highlighting', 0 ) ) + + if py3eval( + \ 'ycm_state.Buffer( int( vim.eval( "a:bufnr" ) ) ).' + \ . 'semantic_highlighting.Request( ' + \ . ' force=int( vim.eval( "a:force" ) ) )' ) + let s:pollers.semantic_highlighting.id = timer_start( + \ s:pollers.semantic_highlighting.wait_milliseconds, + \ function( 's:PollSemanticHighlighting', [ a:bufnr ] ) ) + elseif a:redraw_anyway + py3 ycm_state.Buffer( + \ int( vim.eval( "a:bufnr" ) ) ).semantic_highlighting.Refresh() + endif + endif +endfunction + + +function s:ShouldUseInlayHintsNow( bufnr ) + return s:enable_inlay_hints && + \ getbufvar( a:bufnr, 'ycm_enable_inlay_hints', + \ get( g:, 'ycm_enable_inlay_hints', 0 ) ) +endfunction + +function! s:UpdateInlayHints( bufnr, force, redraw_anyway ) abort + call s:StopPoller( s:pollers.inlay_hints ) + + if s:ShouldUseInlayHintsNow( a:bufnr ) + if py3eval( + \ 'ycm_state.Buffer( int( vim.eval( "a:bufnr" ) ) ).' + \ . 'inlay_hints.Request( force=int( vim.eval( "a:force" ) ) )' ) + let s:pollers.inlay_hints.id = timer_start( + \ s:pollers.inlay_hints.wait_milliseconds, + \ function( 's:PollInlayHints', [ a:bufnr ] ) ) + elseif a:redraw_anyway + py3 ycm_state.Buffer( int( vim.eval( "a:bufnr" ) ) ).inlay_hints.Refresh() + endif + endif endfunction @@ -774,6 +915,34 @@ function! s:PollFileParseResponse( ... ) endfunction +function! s:PollSemanticHighlighting( bufnr, ... ) abort + return s:PollScrollable( a:bufnr, 'semantic_highlighting' ) +endfunction + + +function! s:PollInlayHints( bufnr, ... ) abort + return s:PollScrollable( a:bufnr, 'inlay_hints' ) +endfunction + + +function! s:PollScrollable( bufnr, scrollable, ... ) abort + if !py3eval( + \ 'ycm_state.Buffer( int( vim.eval( "a:bufnr" ) ) )' + \ . '.' . a:scrollable . '.Ready()' ) + let s:pollers[a:scrollable].id = timer_start( + \ s:pollers[a:scrollable].wait_milliseconds, + \ function( 's:PollScrollable', [ a:bufnr, a:scrollable ] ) ) + elseif ! py3eval( + \ 'ycm_state.Buffer( int( vim.eval( "a:bufnr" ) ) )' + \ . '.' . a:scrollable . '.Update()' ) + let s:pollers[ a:scrollable ].id = timer_start( + \ s:pollers[ a:scrollable ].wait_milliseconds, + \ function( 's:PollScrollable', [ a:bufnr, a:scrollable ] ) ) + endif +endfunction + + + function! s:SendKeys( keys ) " By default keys are added to the end of the typeahead buffer. If there are " already keys in the buffer, they will be processed first and may change @@ -820,10 +989,22 @@ function! s:OnCursorMovedNormalMode() return endif + call s:AbortAutohoverRequest() + py3 ycm_state.OnCursorMoved() endfunction +function! s:OnWinScrolled() + if !s:AllowedToCompleteInCurrentBuffer() + return + endif + let bufnr = winbufnr( expand( '' ) ) + call s:UpdateSemanticHighlighting( bufnr, 0, 0 ) + call s:UpdateInlayHints( bufnr, 0, 0 ) +endfunction + + function! s:OnTextChangedNormalMode() if !s:AllowedToCompleteInCurrentBuffer() return @@ -860,25 +1041,14 @@ function! s:OnTextChangedInsertMode( popup_is_visible ) " CurrentIdentifierFinished check. if s:force_semantic && !py3eval( 'base.LastEnteredCharIsIdentifierChar()' ) let s:force_semantic = 0 + let s:force_manual = 0 endif if get( b:, 'ycm_completing' ) && - \ ( g:ycm_auto_trigger || s:force_semantic ) && + \ ( g:ycm_auto_trigger || s:force_semantic || s:force_manual ) && \ !s:InsideCommentOrStringAndShouldStop() && \ !s:OnBlankLine() - " The call to s:Complete here is necessary, to minimize flicker when we - " close the pum on every keypress. In that case, we try to quickly show it - " again with whatver the latest completion result is. When using complete(), - " we don't need to do this, as we only close the pum when there are no - " completions. However, it's still useful as we don't want Vim's filtering - " to _ever_ apply. Examples of when this is problematic is when typing some - " keys to filter (that are not a prefix of the completion), then deleting a - " character. Normally Vim would re-filter based on the new "query", but we - " don't want that. - call s:Complete() call s:RequestCompletion() - - call s:UpdateSignatureHelp() call s:RequestSignatureHelp() endif @@ -890,6 +1060,15 @@ function! s:OnTextChangedInsertMode( popup_is_visible ) endfunction +function! s:OnInsertEnter() abort + let s:current_cursor_position = getpos( '.' ) + py3 ycm_state.OnInsertEnter() + if s:ShouldUseInlayHintsNow( bufnr() ) && + \ get(g:, 'ycm_clear_inlay_hints_in_insert_mode' ) + py3 ycm_state.CurrentBuffer().inlay_hints.Clear() + endif +endfunction + function! s:OnInsertLeave() if !s:AllowedToCompleteInCurrentBuffer() return @@ -899,6 +1078,7 @@ function! s:OnInsertLeave() call s:StopPoller( s:pollers.completion ) let s:force_semantic = 0 + let s:force_manual = 0 let s:completion = s:default_completion call s:OnFileReadyToParse() @@ -909,6 +1089,11 @@ function! s:OnInsertLeave() endif call s:ClearSignatureHelp() + if s:ShouldUseInlayHintsNow( bufnr() ) + \ && get( g:, 'ycm_clear_inlay_hints_in_insert_mode' ) + " We cleared inlay hints on insert enter + py3 ycm_state.CurrentBuffer().inlay_hints.Refresh() + endif endfunction @@ -934,6 +1119,7 @@ function! s:IdentifierFinishedOperations() endif py3 ycm_state.OnCurrentIdentifierFinished() let s:force_semantic = 0 + let s:force_manual = 0 let s:completion = s:default_completion endfunction @@ -983,8 +1169,8 @@ function! s:RequestCompletion() \ vimsupport.GetBoolValue( 's:force_semantic' ) ) if py3eval( 'ycm_state.CompletionRequestReady()' ) - " We can't call complete() syncrhounsouly in the TextChangedI/TextChangedP - " autocommmands (it's designed to be used async only completion). The result + " We can't call complete() synchronously in the TextChangedI/TextChangedP + " autocommands (it's designed to be used async only completion). The result " (somewhat oddly) is that the completion menu is shown, but ctrl-n doesn't " actually select anything. " When the request is satisfied synchronously (e.g. the omnicompleter), we @@ -998,20 +1184,50 @@ function! s:RequestCompletion() endif endfunction +function! s:ManuallyRequestCompletion() abort + " Since this function is called in a mapping through the expression register + " =, its return value is inserted (see :h c_CTRL-R_=). We don't want to + " insert anything so we return an empty string. -function! s:RequestSemanticCompletion() + if !s:AllowedToCompleteInCurrentBuffer() + return '' + endif + + if get( b:, 'ycm_completing' ) + let s:force_manual = 0 + call s:RequestCompletion() + call s:RequestSignatureHelp() + endif + + return '' +endfunction + +function! s:SetCompleteFunc() + let &completefunc = 'youcompleteme#CompleteFunc' +endfunction + +function! youcompleteme#CompleteFunc( findstart, base ) abort + call s:ManuallyRequestCompletion() + " Cancel, but silently stay in completion mode. + return -2 +endfunction + +inoremap (YCMComplete) =ManuallyRequestCompletion() + +function! s:RequestSemanticCompletion() abort if !s:AllowedToCompleteInCurrentBuffer() return '' endif if get( b:, 'ycm_completing' ) let s:force_semantic = 1 + let s:current_cursor_position = getpos( '.' ) call s:StopPoller( s:pollers.completion ) py3 ycm_state.SendCompletionRequest( True ) if py3eval( 'ycm_state.CompletionRequestReady()' ) - " We can't call complete() syncrhounsouly in the TextChangedI/TextChangedP - " autocommmands (it's designed to be used async only completion). The + " We can't call complete() synchronously in the TextChangedI/TextChangedP + " autocommands (it's designed to be used async only completion). The " result (somewhat oddly) is that the completion menu is shown, but ctrl-n " doesn't actually select anything. When the request is satisfied " synchronously (e.g. the omnicompleter), we must return to the main loop @@ -1057,7 +1273,7 @@ function! s:PollResolve( item, ... ) " Note we re-use the 'completion' request for resolves. This prevents us " sending a completion request and a resolve request at the same time, as - " resolve requests re-use the requset data from the last completion request + " resolve requests re-use the request data from the last completion request " and it must not change. " We also re-use the poller, so that any new completion request effectively " cancels this poller. @@ -1142,7 +1358,7 @@ function! s:Complete() endif if len( s:completion.completions ) let old_completeopt = &completeopt - set completeopt+=noselect + setlocal completeopt+=noselect call complete( s:completion.completion_start_column, \ s:completion.completions ) let &completeopt = old_completeopt @@ -1250,6 +1466,22 @@ function! youcompleteme#GetCommandResponse( ... ) abort endfunction +function! s:GetCommandResponseAsyncImpl( callback, origin, ... ) abort + let request_id = py3eval( + \ 'ycm_state.SendCommandRequestAsync( vim.eval( "a:000" ) )' ) + + let s:pollers.command.requests[ request_id ] = { + \ 'response_func': 'StringResponse', + \ 'origin': a:origin, + \ 'callback': a:callback + \ } + if s:pollers.command.id == -1 + let s:pollers.command.id = timer_start( s:pollers.command.wait_milliseconds, + \ function( 's:PollCommands' ) ) + endif +endfunction + + function! youcompleteme#GetCommandResponseAsync( callback, ... ) abort if !s:AllowedToCompleteInCurrentBuffer() eval a:callback( '' ) @@ -1261,16 +1493,7 @@ function! youcompleteme#GetCommandResponseAsync( callback, ... ) abort return endif - if s:pollers.command.id != -1 - eval a:callback( '' ) - return - endif - - py3 ycm_state.SendCommandRequestAsync( vim.eval( "a:000" ) ) - - let s:pollers.command.id = timer_start( - \ s:pollers.command.wait_milliseconds, - \ function( 's:PollCommand', [ 'StringResponse', a:callback ] ) ) + call s:GetCommandResponseAsyncImpl( callback, 'extern', a:000 ) endfunction @@ -1285,39 +1508,58 @@ function! youcompleteme#GetRawCommandResponseAsync( callback, ... ) abort return endif - if s:pollers.command.id != -1 - eval a:callback( { 'error': 'request in progress' } ) - return - endif - - py3 ycm_state.SendCommandRequestAsync( vim.eval( "a:000" ) ) + let request_id = py3eval( + \ 'ycm_state.SendCommandRequestAsync( vim.eval( "a:000" ) )' ) - let s:pollers.command.id = timer_start( - \ s:pollers.command.wait_milliseconds, - \ function( 's:PollCommand', [ 'Response', a:callback ] ) ) + let s:pollers.command.requests[ request_id ] = { + \ 'response_func': 'Response', + \ 'origin': 'extern_raw', + \ 'callback': a:callback + \ } + if s:pollers.command.id == -1 + let s:pollers.command.id = timer_start( s:pollers.command.wait_milliseconds, + \ function( 's:PollCommands' ) ) + endif endfunction -function! s:PollCommand( response_func, callback, id ) abort - if py3eval( 'ycm_state.GetCommandRequest() is None' ) - " Possible in case of race conditions and things like RestartServer - " But particualrly in the tests - return - endif - - if !py3eval( 'ycm_state.GetCommandRequest().Done()' ) - let s:pollers.command.id = timer_start( - \ s:pollers.command.wait_milliseconds, - \ function( 's:PollCommand', [ a:response_func, a:callback ] ) ) - return - endif - +function! s:PollCommands( timer_id ) abort + " Clear the timer id before calling the callback, as the callback might fire + " more requests call s:StopPoller( s:pollers.command ) - let result = py3eval( 'ycm_state.GetCommandRequest().' - \ .a:response_func . '()' ) + " Must copy the requests because this loop is likely to modify it + let requests = copy( s:pollers.command.requests ) + let poll_again = 0 + for request_id in keys( requests ) + let request = requests[ request_id ] + if py3eval( 'ycm_state.GetCommandRequest( int( vim.eval( "request_id" ) ) )' + \ . 'is None' ) + " Possible in case of race conditions and things like RestartServer + " But particularly in the tests + let result = v:none + elseif !py3eval( 'ycm_state.GetCommandRequest( ' + \ . 'int( vim.eval( "request_id" ) ) ).Done()' ) + " Not ready yet, poll again and skip this one for now + let poll_again = 1 + continue + else + let result = py3eval( 'ycm_state.GetCommandRequest( ' + \ . 'int( vim.eval( "request_id" ) ) ).' + \ . request.response_func + \ . '()' ) + endif + + " This request is done + call remove( s:pollers.command.requests, request_id ) + py3 ycm_state.FlushCommandRequest( int( vim.eval( "request_id" ) ) ) + call request[ 'callback' ]( result ) + endfor - eval a:callback( result ) + if poll_again && s:pollers.command.id == -1 + let s:pollers.command.id = timer_start( s:pollers.command.wait_milliseconds, + \ function( 's:PollCommands' ) ) + endif endfunction @@ -1411,16 +1653,19 @@ if exists( '*popup_atcursor' ) return endif - call youcompleteme#GetCommandResponseAsync( - \ function( 's:ShowHoverResult' ), - \ b:ycm_hover.command ) + if empty( popup_getpos( s:cursorhold_popup ) ) + call s:GetCommandResponseAsyncImpl( + \ function( 's:ShowHoverResult' ), + \ 'autohover', + \ b:ycm_hover.command ) + endif endfunction function! s:ShowHoverResult( response ) call popup_hide( s:cursorhold_popup ) - if empty( a:response ) + if empty( a:response ) || !exists( 'b:ycm_hover' ) return endif @@ -1443,18 +1688,22 @@ if exists( '*popup_atcursor' ) let wrap = 1 endif - let s:cursorhold_popup = popup_atcursor( - \ lines, - \ { - \ 'col': col, - \ 'wrap': wrap, - \ 'padding': [ 0, 1, 0, 1 ], - \ 'moved': 'word', - \ 'maxwidth': &columns, - \ 'close': 'click', - \ 'fixed': 0, - \ } - \ ) + let popup_params = { + \ 'col': col, + \ 'wrap': wrap, + \ 'padding': [ 0, 1, 0, 1 ], + \ 'moved': 'word', + \ 'maxwidth': &columns, + \ 'close': 'click', + \ 'fixed': 0, + \ } + + if has_key( b:ycm_hover, 'popup_params' ) + let popup_params = extend( copy( popup_params ), + \ b:ycm_hover.popup_params ) + endif + + let s:cursorhold_popup = popup_atcursor( lines, popup_params ) call setbufvar( winbufnr( s:cursorhold_popup ), \ '&syntax', \ b:ycm_hover.syntax ) @@ -1467,7 +1716,7 @@ if exists( '*popup_atcursor' ) call popup_hide( s:cursorhold_popup ) let s:cursorhold_popup = -1 - " Diable the auto-trigger until the next cursor movement. + " Disable the auto-trigger until the next cursor movement. call s:DisableAutoHover() augroup YCMHover autocmd! CursorMoved @@ -1499,6 +1748,27 @@ endfunction silent! inoremap (YCMToggleSignatureHelp) \ =ToggleSignatureHelp() +function! s:ToggleInlayHints() + let b:ycm_enable_inlay_hints = + \ !get( b:, + \ 'ycm_enable_inlay_hints', + \ get( g:, 'ycm_enable_inlay_hints' ) ) + + if !b:ycm_enable_inlay_hints && s:enable_inlay_hints + py3 ycm_state.CurrentBuffer().inlay_hints.Clear() + else + call s:UpdateInlayHints( bufnr(), 0, 1 ) + endif +endfunction + +silent! nnoremap (YCMToggleInlayHints) + \ call ToggleInlayHints() + +silent! nnoremap (YCMTypeHierarchy) + \ call youcompleteme#hierarchy#StartRequest( 'type' ) +silent! nnoremap (YCMCallHierarchy) + \ call youcompleteme#hierarchy#StartRequest( 'call' ) + " This is basic vim plugin boilerplate let &cpo = s:save_cpo unlet s:save_cpo diff --git a/autoload/youcompleteme/filetypes.vim b/autoload/youcompleteme/filetypes.vim new file mode 100644 index 0000000000..911d8cae78 --- /dev/null +++ b/autoload/youcompleteme/filetypes.vim @@ -0,0 +1,36 @@ +" Copyright (C) 2011-2018 YouCompleteMe contributors +" +" This file is part of YouCompleteMe. +" +" YouCompleteMe is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" YouCompleteMe is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with YouCompleteMe. If not, see . + + +function! s:HasAnyKey( dict, keys ) abort + for key in a:keys + if has_key( a:dict, key ) + return 1 + endif + endfor + return 0 +endfunction + +function! youcompleteme#filetypes#AllowedForFiletype( filetype ) abort + let whitelist_allows = type( g:ycm_filetype_whitelist ) != v:t_dict || + \ has_key( g:ycm_filetype_whitelist, '*' ) || + \ s:HasAnyKey( g:ycm_filetype_whitelist, split( a:filetype, '\.' ) ) + let blacklist_allows = type( g:ycm_filetype_blacklist ) != v:t_dict || + \ !s:HasAnyKey( g:ycm_filetype_blacklist, split( a:filetype, '\.' ) ) + + return whitelist_allows && blacklist_allows +endfunction diff --git a/autoload/youcompleteme/finder.vim b/autoload/youcompleteme/finder.vim index cf3b5c5c5d..d492d1f9dd 100644 --- a/autoload/youcompleteme/finder.vim +++ b/autoload/youcompleteme/finder.vim @@ -97,8 +97,10 @@ scriptencoding utf-8 " 'raw_results', and store the results in 'results', then call " "HandleSymbolSearchResults" " -" - SearchWorkspace - perform GoToSymbol request, and store the results in -" 'results', then call "HandleSymbolSearchResults" +" - SearchWorkspace - perform GoToSymbol request for all open filetypes, +" and store the results in 'raw_results' as a dict mapping +" filetype->results. Merge the results in to 'results', then call +" "HandleSymbolSearchResults" " " - HandleSymbolSearchResults - redraw the popup with the 'results' " @@ -111,35 +113,6 @@ scriptencoding utf-8 " The other functions are utility for the most part and handle things like " TextChangedI event, starting/stopping drawing the spinner and such. -let s:highlight_group_for_symbol_kind = { - \ 'Array': 'Identifier', - \ 'Boolean': 'Boolean', - \ 'Class': 'Structure', - \ 'Constant': 'Constant', - \ 'Constructor': 'Function', - \ 'Enum': 'Structure', - \ 'EnumMember': 'Identifier', - \ 'Event': 'Identifier', - \ 'Field': 'Identifier', - \ 'Function': 'Function', - \ 'Interface': 'Structure', - \ 'Key': 'Identifier', - \ 'Method': 'Function', - \ 'Module': 'Include', - \ 'Namespace': 'Type', - \ 'Null': 'Keyword', - \ 'Number': 'Number', - \ 'Object': 'Structure', - \ 'Operator': 'Operator', - \ 'Package': 'Include', - \ 'Property': 'Identifier', - \ 'String': 'String', - \ 'Struct': 'Structure', - \ 'TypeParameter': 'Typedef', - \ 'Variable': 'Identifier', - \ } -let s:initialized_text_properties = v:false - let s:icon_spinner = [ '/', '-', '\', '|', '/', '-', '\', '|' ] let s:icon_done = 'X' let s:spinner_delay = 100 @@ -154,25 +127,15 @@ function! youcompleteme#finder#FindSymbol( scope ) abort return endif - if !s:initialized_text_properties - call prop_type_add( 'YCM-symbol-Normal', { 'highlight': 'Normal' } ) - for k in keys( s:highlight_group_for_symbol_kind ) - call prop_type_add( - \ 'YCM-symbol-' . k, - \ { 'highlight': s:highlight_group_for_symbol_kind[ k ] } ) - endfor - call prop_type_add( 'YCM-symbol-file', { 'highlight': 'Comment' } ) - call prop_type_add( 'YCM-symbol-line-num', { 'highlight': 'Number' } ) - let s:initialized_text_properties = v:true - endif + call youcompleteme#symbol#InitSymbolProperties() let s:find_symbol_status = { \ 'selected': -1, \ 'query': '', \ 'results': [], \ 'raw_results': v:none, - \ 'waiting': 0, - \ 'pending': 0, + \ 'all_filetypes': v:true, + \ 'pending': [], \ 'winid': win_getid(), \ 'bufnr': bufnr(), \ 'prompt_bufnr': -1, @@ -216,12 +179,10 @@ function! youcompleteme#finder#FindSymbol( scope ) abort let s:find_symbol_status.id = popup_create( 'Type to query for stuff', opts ) " Kick off the request now - let s:find_symbol_status.waiting = 1 if a:scope ==# 'document' - call s:StartSpinner() call s:RequestDocumentSymbols() else - call s:SearchWorkspace( '' ) + call s:SearchWorkspace( '', v:true ) endif let bufnr = bufadd( '_ycm_filter_' ) @@ -253,9 +214,11 @@ function! s:OnQueryTextChanged() abort let bufnr = s:find_symbol_status.prompt_bufnr let query = getbufline( bufnr, '$' )[ 0 ] let s:find_symbol_status.query = query[ len( s:prompt ) : ] - let s:find_symbol_status.pending = 1 - call s:RequeryFinderPopup() - setlocal nomodified + + " really, re-query if we can + call s:RequeryFinderPopup( v:true ) + + call win_execute( s:find_symbol_status.prompt_winid, 'setlocal nomodified' ) endfunction @@ -273,6 +236,7 @@ endfunction function! s:HandleKeyPress( id, key ) abort let redraw = 0 let handled = 0 + let requery = 0 " The input for the search/query is taken from the prompt buffer and the " TextChangedI event @@ -334,9 +298,17 @@ function! s:HandleKeyPress( id, key ) abort let s:find_symbol_status.selected = len( s:find_symbol_status.results ) - 1 let redraw = 1 let handled = 1 + elseif a:key ==# "\" + " TOggle filetypes? + let s:find_symbol_status.all_filetypes = !s:find_symbol_status.all_filetypes + let redraw = 0 + let requery = 1 + let handled = 1 endif - if redraw + if requery + call s:RequeryFinderPopup( v:true ) + elseif redraw call s:RedrawFinderPopup() endif @@ -389,7 +361,7 @@ function! s:PopupClosed( id, selected ) abort endif - call s:StopSpinner() + call s:EndRequest() let s:find_symbol_status.id = -1 endfunction @@ -399,9 +371,7 @@ endfunction " Render a set of results returned from the filter/search function function! s:HandleSymbolSearchResults( results ) abort - let s:find_symbol_status.waiting = 0 let s:find_symbol_status.results = [] - call s:StopSpinner() if s:find_symbol_status.id < 0 " Popup was closed, ignore this event @@ -410,7 +380,9 @@ function! s:HandleSymbolSearchResults( results ) abort let s:find_symbol_status.results = a:results call s:RedrawFinderPopup() - call s:RequeryFinderPopup() + + " Re-query but no change in the query text + call s:RequeryFinderPopup( v:false ) endfunction @@ -435,6 +407,20 @@ function! s:RedrawFinderPopup() abort let buffer = [] + let len_filetype = 0 + + for result in s:find_symbol_status.results + let len_filetype = max( [ len_filetype, len( result[ 'filetype' ] ) ] ) + endfor + + if len_filetype > 0 + let filetype_sep = ' ' + else + let filetype_sep = '' + endif + + let available_width = popup_width - len_filetype - len( filetype_sep ) + for result in s:find_symbol_status.results " Calculate the text to use. Try and include the full path and line " number, (right aligned), but truncate if there isn't space for the @@ -444,11 +430,7 @@ function! s:RedrawFinderPopup() abort let kind = result[ 'extra_data' ][ 'kind' ] let name = result[ 'extra_data' ][ 'name' ] let desc = kind .. ': ' .. name - if s:highlight_group_for_symbol_kind->has_key( kind ) - let prop = 'YCM-symbol-' . kind - else - let prop = 'YCM-symbol-Normal' - endif + let prop = youcompleteme#symbol#GetPropForSymbolKind( kind ) let props = [ \ { 'col': 1, \ 'length': len( kind ) + 2, @@ -471,30 +453,58 @@ function! s:RedrawFinderPopup() abort let path = fnamemodify( result[ 'filepath' ], ':.' ) \ .. ':' \ .. line_num + let path_includes_line = 1 - let spaces = popup_width - len( desc ) - len( path ) - let spacing = 8 + let spaces = available_width - strdisplaywidth( desc ) - strdisplaywidth( path ) + let spacing = 4 if spaces < spacing let spaces = spacing - let path_len_to_use = popup_width - spacing - len( desc ) - 3 - if path_len_to_use > 0 - let path = '...' . strpart( path, len( path ) - path_len_to_use ) + let space_for_path = available_width - spacing - len( desc ) + let path_includes_line = space_for_path - 3 > len( line_num ) + 1 + if space_for_path > 3 + let path = '...' . strpart( path, len( path ) - space_for_path + 3 ) + elseif space_for_path <= 0 + let path = '' else - let path = '...:' .. line_num + let path_includes_line = 0 + let path = '...' endif endif - let line = desc .. repeat( ' ', spaces ) .. path - call add( buffer, { - \ 'text': line, - \ 'props': props + [ - \ { 'col': popup_width - len( path ) + 1, - \ 'length': len( path ) - len( line_num ), - \ 'type': 'YCM-symbol-file' }, - \ { 'col': popup_width - len( line_num ) + 1, - \ 'length': len( line_num ), - \ 'type': 'YCM-symbol-line-num' } - \ ] - \ } ) + + let line = desc + \ .. repeat( ' ', spaces ) + \ .. path + \ .. filetype_sep + \ .. result[ 'filetype' ] + + if len( path ) > 0 + if path_includes_line + let props += [ + \ { 'col': len( desc ) + spaces + 1, + \ 'length': len( path ) - len( line_num ), + \ 'type': 'YCM-symbol-file' }, + \ { 'col': len( desc ) + spaces + 1 + len( path ) - len( line_num ), + \ 'length': len( line_num ), + \ 'type': 'YCM-symbol-line-num' }, + \ ] + else + let props += [ + \ { 'col': len( desc ) + spaces + 1, + \ 'length': len( path ), + \ 'type': 'YCM-symbol-file' }, + \ ] + endif + endif + + if len_filetype > 0 + let props += [ + \ { 'col': popup_width - len_filetype + len( filetype_sep ), + \ 'length': len_filetype, + \ 'type': 'YCM-symbol-filetype' }, + \ ] + endif + + call add( buffer, { 'text': line, 'props': props } ) endfor call popup_settext( s:find_symbol_status.id, buffer ) @@ -524,7 +534,8 @@ function! s:RedrawFinderPopup() abort " Otherwise, new item is already displayed - don't scroll the window. if !getwinvar( s:find_symbol_status.id, '&cursorline' ) - call win_execute( s:find_symbol_status.id, 'set cursorline' ) + call win_execute( s:find_symbol_status.id, + \ 'set cursorline cursorlineopt&' ) endif else call win_execute( s:find_symbol_status.id, 'set nocursorline' ) @@ -548,28 +559,23 @@ endfunction " Re-query or re-filter by calling the filter function -function! s:RequeryFinderPopup() abort +function! s:RequeryFinderPopup( new_query ) abort " Update the title even if we delay the query, as this makes the UI feel " snappy call s:SetTitle() - if s:find_symbol_status.waiting == 1 - let s:find_symbol_status.pending = 1 - elseif s:find_symbol_status.pending == 1 - let s:find_symbol_status.pending = 0 - let s:find_symbol_status.waiting = 1 - call win_execute( s:find_symbol_status.winid, - \ 'call s:find_symbol_status.query_func(' - \ . 's:find_symbol_status.query )' ) - endif + call win_execute( s:find_symbol_status.winid, + \ 'call s:find_symbol_status.query_func(' + \ . 's:find_symbol_status.query,' + \ . 'a:new_query )' ) endfunction -function! s:ParseGoToResponse( results ) abort +function! s:ParseGoToResponse( filetype, results ) abort if type( a:results ) == v:t_none || empty( a:results ) let results = [] elseif type( a:results ) != v:t_list if type( a:results ) == v:t_dict && has_key( a:results, 'error' ) - let results = {} + let results = [] else let results = [ a:results ] endif @@ -577,12 +583,10 @@ function! s:ParseGoToResponse( results ) abort let results = a:results endif - call map( results, - \ { i,v -> extend( v, - \ { 'key': v->get( 'extra_data', - \ {} )->get( 'name', - \ v[ 'description' ] ) } ) } ) - + call map( results, { _, r -> extend( r, { + \ 'key': r->get( 'extra_data', {} )->get( 'name', r[ 'description' ] ), + \ 'filetype': a:filetype + \ } ) } ) return results endfunction @@ -590,8 +594,8 @@ endfunction " Spinner {{{ -function! s:StartSpinner() abort - call s:StopSpinner() +function! s:StartRequest() abort + call s:EndRequest() let s:find_symbol_status.spinner = 0 let s:find_symbol_status.spinner_timer = timer_start( s:spinner_delay, @@ -600,8 +604,9 @@ function! s:StartSpinner() abort call s:SetTitle() endfunction -function! s:StopSpinner() abort +function! s:EndRequest() abort call timer_stop( s:find_symbol_status.spinner_timer ) + let s:find_symbol_status.spinner_timer = -1 call s:SetTitle() @@ -621,19 +626,90 @@ endfunction " Workspace search {{{ -function! s:SearchWorkspace( query ) abort - call s:StartSpinner() +function! s:SearchWorkspace( query, new_query ) abort - let s:find_symbol_status.raw_results = v:none - call youcompleteme#GetRawCommandResponseAsync( - \ function( 's:HandleWorkspaceSymbols' ), - \ 'GoToSymbol', - \ a:query ) + if a:new_query + if s:find_symbol_status.raw_results is# v:none + let raw_results = {} + else + let raw_results = copy( s:find_symbol_status.raw_results ) + endif + + let s:find_symbol_status.raw_results = {} + " FIXME: We might still get results for any pending results. There is no + " cancellation mechanism implemented for the async request! + let s:find_symbol_status.pending = [] + + if s:find_symbol_status.all_filetypes + let ft_buffer_map = py3eval( 'vimsupport.AllOpenedFiletypes()' ) + else + let current_filetypes = py3eval( 'vimsupport.CurrentFiletypes()' ) + let ft_buffer_map = {} + for ft in current_filetypes + let ft_buffer_map[ ft ] = [ bufnr() ] + endfor + endif + + for ft in keys( ft_buffer_map ) + if !youcompleteme#filetypes#AllowedForFiletype( ft ) + continue + endif + + let s:find_symbol_status.raw_results[ ft ] = v:none + if has_key( raw_results, ft ) && raw_results[ ft ] is# v:none + call add( s:find_symbol_status.pending, + \ [ ft, ft_buffer_map[ ft ][ 0 ] ] ) + else + call youcompleteme#GetRawCommandResponseAsync( + \ function( 's:HandleWorkspaceSymbols', [ ft ] ), + \ 'GoToSymbol', + \ '--bufnr=' . ft_buffer_map[ ft ][ 0 ], + \ 'ft=' . ft, + \ a:query ) + endif + endfor + + if !empty( s:find_symbol_status.raw_results ) + " We sent some requests + call s:StartRequest() + endif + else + " Just requery those completer filetypes that we're not currently waiting + " for + for [ ft, bufnr ] in copy( s:find_symbol_status.pending ) + if s:find_symbol_status.raw_results[ ft ] isnot# v:none + call filter( s:find_symbol_status.pending, { v -> v !=# ft } ) + let s:find_symbol_status.raw_results[ ft ] = v:none + call youcompleteme#GetRawCommandResponseAsync( + \ function( 's:HandleWorkspaceSymbols', [ ft ] ), + \ 'GoToSymbol', + \ '--bufnr=' . bufnr, + \ 'ft=' . ft, + \ a:query ) + endif + endfor + endif endfunction -function! s:HandleWorkspaceSymbols( results ) abort - let results = s:ParseGoToResponse( a:results ) +function! s:HandleWorkspaceSymbols( filetype, results ) abort + + let s:find_symbol_status.raw_results[ a:filetype ] = + \ s:ParseGoToResponse( a:filetype, a:results ) + + " Collate the results from each filetype + let results = [] + let waiting = 0 + for ft in keys( s:find_symbol_status.raw_results ) + if s:find_symbol_status.raw_results[ ft ] is v:none + let waiting = 1 + continue + endif + + call extend( results, s:find_symbol_status.raw_results[ ft ] ) + endfor + + let query = s:find_symbol_status.query if g:ycm_refilter_workspace_symbols && !empty( results ) " This is kinda wonky, but seems to work well enough. @@ -645,24 +721,26 @@ function! s:HandleWorkspaceSymbols( results ) abort " - server filterins will differ by server and this leads to horrible wonky " user experience " - ycmd filter is consistent, even if not perfect - " - servers are supposed to return _all_ symbols if we request a query of "" - " but no actual servers obey this part of the spec. + " - servers are supposed to return _all_ symbols if we request a query of + " "" but not all servers actually do " - " So as a compromise we let the server filter the results, then we _refilter_ - " and sort them using ycmd's method. This provides consistency with the - " filtering and sorting on the completion popup menu, with the disadvantage of - " additional latency. + " So as a compromise we let the server filter the results, then we + " _refilter_ and sort them using ycmd's method. This provides consistency + " with the filtering and sorting on the completion popup menu, with the + " disadvantage of additional latency. " " We're not currently sure this is going to be perfecct, so we have a hidden " option to disable this re-filter/sort. " let results = py3eval( - \ 'ycm_state.FilterAndSortItems( ' - \ . ' vim.eval( "results" ),' - \ . ' "description",' - \ . ' vim.eval( "s:find_symbol_status.query" ) )' ) + \ 'ycm_state.FilterAndSortItems( vim.eval( "results" ),' + \ . ' "key",' + \ . ' vim.eval( "query" ) )' ) endif + if !waiting + call s:EndRequest() + endif eval s:HandleSymbolSearchResults( results ) endfunction @@ -670,21 +748,24 @@ endfunction " Document Search {{{ -function! s:SearchDocument( query ) abort +function! s:SearchDocument( query, new_query ) abort + if !a:new_query + return + endif + if type( s:find_symbol_status.raw_results ) == v:t_none - call s:StopSpinner() call popup_settext( s:find_symbol_status.id, \ 'No symbols found in document' ) return endif - call s:StartSpinner() + " No spinner, because this is actually a synchronous call " Call filter_and_sort_candidates on the results (synchronously) let response = py3eval( \ 'ycm_state.FilterAndSortItems( ' \ . ' vim.eval( "s:find_symbol_status.raw_results" ),' - \ . ' "description",' + \ . ' "key",' \ . ' vim.eval( "a:query" ) )' ) eval s:HandleSymbolSearchResults( response ) @@ -692,6 +773,7 @@ endfunction function! s:RequestDocumentSymbols() + call s:StartRequest() call youcompleteme#GetRawCommandResponseAsync( \ function( 's:HandleDocumentSymbols' ), \ 'GoToDocumentOutline' ) @@ -699,8 +781,9 @@ endfunction function! s:HandleDocumentSymbols( results ) abort - let s:find_symbol_status.raw_results = s:ParseGoToResponse( a:results ) - call s:SearchDocument( '' ) + call s:EndRequest() + let s:find_symbol_status.raw_results = s:ParseGoToResponse( '', a:results ) + call s:SearchDocument( '', v:true ) endfunction " }}} diff --git a/autoload/youcompleteme/hierarchy.vim b/autoload/youcompleteme/hierarchy.vim new file mode 100644 index 0000000000..d5b3563bd9 --- /dev/null +++ b/autoload/youcompleteme/hierarchy.vim @@ -0,0 +1,250 @@ +" Copyright (C) 2021 YouCompleteMe contributors +" +" This file is part of YouCompleteMe. +" +" YouCompleteMe is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" YouCompleteMe is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with YouCompleteMe. If not, see . + +" This is basic vim plugin boilerplate +let s:save_cpo = &cpoptions +set cpoptions&vim + +scriptencoding utf-8 + +let s:popup_id = -1 +let s:lines_and_handles = v:null +" 1-based index of the selected item in the popup +" -1 means none set +" 0 means nothing, (Invalid) +let s:select = -1 +let s:kind = '' + +let s:ingored_keys = [ + \ "\", + \ "\", + \ ] + +function! youcompleteme#hierarchy#StartRequest( kind ) + if !py3eval( 'vimsupport.VimSupportsPopupWindows()' ) + echo 'Sorry, this feature is not supported in your editor' + return + endif + + call youcompleteme#symbol#InitSymbolProperties() + py3 ycm_state.ResetCurrentHierarchy() + py3 from ycm.client.command_request import GetRawCommandResponse + if a:kind == 'call' + let lines_and_handles = py3eval( + \ 'ycm_state.InitializeCurrentHierarchy( GetRawCommandResponse( ' . + \ '[ "CallHierarchy" ], False ), ' . + \ 'vim.eval( "a:kind" ) )' ) + else + let lines_and_handles = py3eval( + \ 'ycm_state.InitializeCurrentHierarchy( GetRawCommandResponse( ' . + \ '[ "TypeHierarchy" ], False ), ' . + \ 'vim.eval( "a:kind" ) )' ) + endif + if len( lines_and_handles ) + let s:lines_and_handles = lines_and_handles + let s:kind = a:kind + let s:select = 1 + call s:SetUpMenu() + endif +endfunction + +function! s:MenuFilter( winid, key ) + if a:key == "\" + " Root changes if we're showing super-tree of a sub-tree of the root + " (indicated by the handle being positive) + let will_change_root = s:lines_and_handles[ s:select - 1 ][ 1 ] > 0 + call popup_close( + \ s:popup_id, + \ [ s:select - 1, 'resolve_up', will_change_root ] ) + return 1 + endif + if a:key == "\" + " Root changes if we're showing sub-tree of a super-tree of the root + " (indicated by the handle being negative) + let will_change_root = s:lines_and_handles[ s:select - 1 ][ 1 ] < 0 + call popup_close( + \ s:popup_id, + \ [ s:select - 1, 'resolve_down', will_change_root ] ) + return 1 + endif + if a:key == "\" + call popup_close( s:popup_id, [ s:select - 1, 'jump', v:none ] ) + return 1 + endif + if a:key == "\" || a:key == "\" || a:key == "\" || a:key == "k" + let s:select -= 1 + if s:select < 1 + let s:select = 1 + endif + call win_execute( s:popup_id, + \ 'call cursor( [' . string( s:select ) . ', 1 ] )' ) + call win_execute( s:popup_id, + \ 'set cursorline cursorlineopt&' ) + return 1 + endif + if a:key == "\" || a:key == "\" || a:key == "\" || a:key == "j" + let s:select += 1 + if s:select > len( s:lines_and_handles ) + let s:select = len( s:lines_and_handles ) + endif + call win_execute( s:popup_id, + \ 'call cursor( [' . string( s:select ) . ', 1 ] )' ) + call win_execute( s:popup_id, + \ 'set cursorline cursorlineopt&' ) + return 1 + endif + if index( s:ingored_keys, a:key ) >= 0 + return 0 + endif + " Close the popup on any other key press + call popup_close( s:popup_id, [ s:select - 1, 'cancel', v:none ] ) + if a:key == "\" || a:key == "\" + return 1 + endif + return 0 +endfunction + +function! s:MenuCallback( winid, result ) + let operation = a:result[ 1 ] + let selection = a:result[ 0 ] + if operation == 'resolve_down' + call s:ResolveItem( selection, 'down', a:result[ 2 ] ) + elseif operation == 'resolve_up' + call s:ResolveItem( selection, 'up', a:result[ 2 ] ) + else + if operation == 'jump' + let handle = s:lines_and_handles[ selection ][ 1 ] + py3 ycm_state.JumpToHierarchyItem( vimsupport.GetIntValue( "handle" ) ) + endif + py3 ycm_state.ResetCurrentHierarchy() + let s:kind = '' + let s:select = 1 + endif +endfunction + +function! s:SetUpMenu() + let opts = #{ + \ filter: funcref( 's:MenuFilter' ), + \ callback: funcref( 's:MenuCallback' ), + \ wrap: 0, + \ minwidth: &columns * 90/100, + \ maxwidth: &columns * 90/100, + \ maxheight: &lines * 75/100, + \ scrollbar: 1, + \ padding: [ 0, 0, 0, 0 ], + \ highlight: 'Normal', + \ border: [], + \ } + if &ambiwidth ==# 'single' && &encoding ==? 'utf-8' + let opts[ 'borderchars' ] = [ '─', '│', '─', '│', '╭', '╮', '╯', '╰' ] + endif + + let s:popup_id = popup_create( [], opts ) + let menu_lines = [] + let popup_width = popup_getpos( s:popup_id ).core_width + let tabstop = popup_width / 3 + for [ item, handle ] in s:lines_and_handles + let indent = repeat( ' ', item.indent ) + let name = indent + \ .. item.icon + \ .. item.kind + \ .. ': ' .. item.symbol + " -2 because: + " 0-based index + " 1 for the tab character + let trunc_name = name[ : tabstop - 2 ] + let props = [] + let name_pfx_len = len( indent ) + len( item.icon ) + len( item.kind ) + 2 + if len( trunc_name ) > name_pfx_len + let props += [ + \ { + \ 'col': name_pfx_len + 1, + \ 'length': len( trunc_name ) - name_pfx_len, + \ 'type': youcompleteme#symbol#GetPropForSymbolKind( item.kind ), + \ } + \ ] + endif + + let file_name = item.filepath .. ':' .. item.line_num + let trunc_path = file_name[ : tabstop - 2 ] + if len(trunc_path) > 0 + let props += [ + \ { + \ 'col': len(trunc_name) + 2, + \ 'length': min( [ len(trunc_path), len( item.filepath ) ] ), + \ 'type': 'YCM-symbol-file' + \ } + \ ] + if len(trunc_path) > len(item.filepath) + 1 + let props += [ + \ { + \ 'col': len(trunc_name) + 2 + len(item.filepath) + 1, + \ 'length': min( [ len(trunc_path), len( item.line_num ) ] ), + \ 'type': 'YCM-symbol-line-num' + \ } + \ ] + endif + endif + + let trunc_desc = item.description[ : tabstop - 2 ] + + let line = trunc_name + \ . "\t" + \ .. trunc_path + \ . "\t" + \ .. trunc_desc + call add( menu_lines, { 'text': line, 'props': props } ) + endfor + call win_execute( s:popup_id, + \ 'setlocal tabstop=' . tabstop ) + call popup_settext( s:popup_id, menu_lines ) + call win_execute( s:popup_id, + \ 'call cursor( [' . string( s:select ) . ', 1 ] )' ) + call win_execute( s:popup_id, + \ 'set cursorline cursorlineopt&' ) +endfunction + +function! s:ResolveItem( choice, direction, will_change_root ) + let handle = s:lines_and_handles[ a:choice ][ 1 ] + if py3eval( + \ 'ycm_state.ShouldResolveItem( vimsupport.GetIntValue( "handle" ), vim.eval( "a:direction" ) )' ) + let lines_and_handles_with_offset = py3eval( + \ 'ycm_state.UpdateCurrentHierarchy( ' . + \ 'vimsupport.GetIntValue( "handle" ), ' . + \ 'vim.eval( "a:direction" ) )' ) + let s:lines_and_handles = lines_and_handles_with_offset[ 0 ] + if a:will_change_root + " When re-rooting the tree, put the cursor on the new "root" item, as this + " helps with orientation. This behaviour is consistent with an expansion + " where we _don't_ re-root the tree, so feels more natural than anything + " else. + " The new root is the element with indent of 0. + " let s:select = 1 + indexof( s:lines_and_handles, + " \ { i, v -> v[0].indent == 0 } ) + let s:select = 1 + for item in s:lines_and_handles + if item[0].indent == 0 + break + endif + let s:select += 1 + endfor + else + let s:select += lines_and_handles_with_offset[ 1 ] + endif + endif + call s:SetUpMenu() +endfunction diff --git a/autoload/youcompleteme/symbol.vim b/autoload/youcompleteme/symbol.vim new file mode 100644 index 0000000000..f34120cdbd --- /dev/null +++ b/autoload/youcompleteme/symbol.vim @@ -0,0 +1,71 @@ +" Copyright (C) 2024 YouCompleteMe contributors +" +" This file is part of YouCompleteMe. +" +" YouCompleteMe is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" YouCompleteMe is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with YouCompleteMe. If not, see . + + +let s:highlight_group_for_symbol_kind = { + \ 'Array': 'Identifier', + \ 'Boolean': 'Boolean', + \ 'Class': 'Structure', + \ 'Constant': 'Constant', + \ 'Constructor': 'Function', + \ 'Enum': 'Structure', + \ 'EnumMember': 'Identifier', + \ 'Event': 'Identifier', + \ 'Field': 'Identifier', + \ 'Function': 'Function', + \ 'Interface': 'Structure', + \ 'Key': 'Identifier', + \ 'Method': 'Function', + \ 'Module': 'Include', + \ 'Namespace': 'Type', + \ 'Null': 'Keyword', + \ 'Number': 'Number', + \ 'Object': 'Structure', + \ 'Operator': 'Operator', + \ 'Package': 'Include', + \ 'Property': 'Identifier', + \ 'String': 'String', + \ 'Struct': 'Structure', + \ 'TypeParameter': 'Typedef', + \ 'Variable': 'Identifier', + \ } +let s:initialized_text_properties = v:false + +function! youcompleteme#symbol#InitSymbolProperties() abort + if !s:initialized_text_properties + call prop_type_add( 'YCM-symbol-Normal', { 'highlight': 'Normal' } ) + for k in keys( s:highlight_group_for_symbol_kind ) + call prop_type_add( + \ 'YCM-symbol-' . k, + \ { 'highlight': s:highlight_group_for_symbol_kind[ k ] } ) + endfor + call prop_type_add( 'YCM-symbol-file', { 'highlight': 'Comment' } ) + call prop_type_add( 'YCM-symbol-filetype', { 'highlight': 'Special' } ) + call prop_type_add( 'YCM-symbol-line-num', { 'highlight': 'Number' } ) + let s:initialized_text_properties = v:true + endif +endfunction + +function! youcompleteme#symbol#GetPropForSymbolKind( kind ) abort + if s:highlight_group_for_symbol_kind->has_key( a:kind ) + return 'YCM-symbol-' . a:kind + endif + + return 'YCM-symbol-Normal' +endfunction + + diff --git a/doc/youcompleteme.txt b/doc/youcompleteme.txt index 00babf9b4f..320d0554ec 100644 --- a/doc/youcompleteme.txt +++ b/doc/youcompleteme.txt @@ -4,194 +4,205 @@ Contents ~ 1. Introduction |youcompleteme-introduction| - 2. Help, Advice, Support |youcompleteme-help-advice-support| - 3. Contents |youcompleteme-contents| - 4. Intro |youcompleteme-intro| - 5. Installation |youcompleteme-installation| - 1. Requirements |youcompleteme-requirements| - 1. Supported Vim Versions |youcompleteme-supported-vim-versions| - 2. Supported Compilers |youcompleteme-supported-compilers| - 3. Individual completer requirements |youcompleteme-individual-completer-requirements| - 2. macOS |youcompleteme-macos| - 1. Quick start, installing all completers |youcompleteme-quick-start-installing-all-completers| - 2. Explanation for the quick start |youcompleteme-explanation-for-quick-start| - 3. Linux 64-bit |youcompleteme-linux-64-bit| - 1. Quick start, installing all completers - 2. Explanation for the quick start - 4. Windows |youcompleteme-windows| - 1. Quick start, installing all completers - 2. Explanation for the quick start - 5. FreeBSD/OpenBSD |youcompleteme-freebsd-openbsd| - 1. Quick start, installing all completers - 2. Explanation for the quick start - 6. Full Installation Guide |youcompleteme-full-installation-guide| - 6. Quick Feature Summary |youcompleteme-quick-feature-summary| - 1. General (all languages) |youcompleteme-general| - 2. C-family languages (C, C++, Objective C, Objective C++, CUDA) |youcompleteme-c-family-languages| - 3. C♯ |youcompleteme-c| - 4. Python |youcompleteme-python| - 5. Go |youcompleteme-go| - 6. JavaScript and TypeScript |youcompleteme-javascript-typescript| - 7. Rust |youcompleteme-rust| - 8. Java |youcompleteme-java| - 7. User Guide |youcompleteme-user-guide| - 1. General Usage |youcompleteme-general-usage| - 2. Client-Server Architecture |youcompleteme-client-server-architecture| - 3. Completion String Ranking |youcompleteme-completion-string-ranking| - 4. Signature Help |youcompleteme-signature-help| - 1. Dismiss signature help |youcompleteme-dismiss-signature-help| - 5. General Semantic Completion |youcompleteme-general-semantic-completion| - 6. C-family Semantic Completion |youcompleteme-c-family-semantic-completion| - 1. Installation - 2. Compile flags |youcompleteme-compile-flags| - 3. Option 1: Use a compilation database [46] |youcompleteme-option-1-use-compilation-database-46| - 4. Option 2: Provide the flags manually |youcompleteme-option-2-provide-flags-manually| - 5. Errors during compilation |youcompleteme-errors-during-compilation| - 7. Java Semantic Completion |youcompleteme-java-semantic-completion| - 1. Java quick Start |youcompleteme-java-quick-start| - 2. Java Project Files |youcompleteme-java-project-files| - 3. Diagnostic display - Syntastic |youcompleteme-diagnostic-display-syntastic| - 4. Diagnostic display - Eclim |youcompleteme-diagnostic-display-eclim| - 5. Eclipse Projects |youcompleteme-eclipse-projects| - 6. Maven Projects |youcompleteme-maven-projects| - 7. Gradle Projects |youcompleteme-gradle-projects| - 8. Troubleshooting |youcompleteme-troubleshooting| - 8. C# Semantic Completion |youcompleteme-c-semantic-completion| - 1. Automatically discovered solution files |youcompleteme-automatically-discovered-solution-files| - 2. Manually specified solution files |youcompleteme-manually-specified-solution-files| - 9. Python Semantic Completion |youcompleteme-python-semantic-completion| - 1. Working with virtual environments |youcompleteme-working-with-virtual-environments| - 2. Working with third-party packages |youcompleteme-working-with-third-party-packages| - 3. Configuring through Vim options |youcompleteme-configuring-through-vim-options| - 10. Rust Semantic Completion |youcompleteme-rust-semantic-completion| - 11. Go Semantic Completion |youcompleteme-go-semantic-completion| - 12. JavaScript and TypeScript Semantic Completion |youcompleteme-javascript-typescript-semantic-completion| - 13. Semantic Completion for Other Languages |youcompleteme-semantic-completion-for-other-languages| - 1. Plugging an arbitrary LSP server |youcompleteme-plugging-an-arbitrary-lsp-server| - 2. LSP Configuration |youcompleteme-lsp-configuration| - 3. Using 'omnifunc' for semantic completion |youcompleteme-using-omnifunc-for-semantic-completion| - 14. Writing New Semantic Completers |youcompleteme-writing-new-semantic-completers| - 15. Diagnostic Display |youcompleteme-diagnostic-display| - 1. Diagnostic Highlighting Groups |youcompleteme-diagnostic-highlighting-groups| - 16. Symbol Search |youcompleteme-symbol-search| - 1. Closing the popup |youcompleteme-closing-popup| - 8. Commands |youcompleteme-commands| - 1. The |:YcmRestartServer| command - 2. The |:YcmForceCompileAndDiagnostics| command - 3. The |:YcmDiags| command - 4. The |:YcmShowDetailedDiagnostic| command - 5. The |:YcmDebugInfo| command - 6. The |:YcmToggleLogs| command - 7. The |:YcmCompleter| command - 9. YcmCompleter Subcommands |youcompleteme-ycmcompleter-subcommands| - 1. GoTo Commands |youcompleteme-goto-commands| - 1. The |GoToInclude| subcommand - 2. The |GoToDeclaration| subcommand - 3. The |GoToDefinition| subcommand - 4. The |GoTo| subcommand - 5. The |GoToImprecise| subcommand - 6. The 'GoToSymbol ' subcommand |GoToSymbol-symbol-query| - 7. The |GoToReferences| subcommand - 8. The |GoToImplementation| subcommand - 9. The |GoToImplementationElseDeclaration| subcommand - 10. The |GoToType| subcommand - 11. The |GoToDocumentOutline| subcommand - 12. The |GoToCallers| and 'GoToCallees' subcommands - 2. Semantic Information Commands |youcompleteme-semantic-information-commands| - 1. The |GetType| subcommand - 2. The |GetTypeImprecise| subcommand - 3. The |GetParent| subcommand - 4. The |GetDoc| subcommand - 5. The |GetDocImprecise| subcommand - 3. Refactoring Commands |youcompleteme-refactoring-commands| - 1. The |FixIt| subcommand - 2. The 'RefactorRename ' subcommand |RefactorRename-new-name| - 3. Multi-file Refactor |youcompleteme-multi-file-refactor| - 4. The |Format| subcommand - 5. The |OrganizeImports| subcommand - 4. Miscellaneous Commands |youcompleteme-miscellaneous-commands| - 1. The 'ExecuteCommand ' subcommand |ExecuteCommand-args| - 2. The |RestartServer| subcommand - 3. The |ReloadSolution| subcommand - 10. Functions |youcompleteme-functions| - 1. The |youcompleteme#GetErrorCount| function - 2. The |youcompleteme#GetWarningCount| function - 3. The 'youcompleteme#GetCommandResponse( ... )' function |youcompleteme#GetCommandResponse()| - 4. The 'youcompleteme#GetCommandResponseAsync( callback, ... )' function |youcompleteme#GetCommandResponseAsync()| - 11. Autocommands |youcompleteme-autocommands| - 1. The |YcmLocationOpened| autocommand - 2. The |YcmQuickFixOpened| autocommand - 12. Options |youcompleteme-options| - 1. The |g:ycm_min_num_of_chars_for_completion| option - 2. The |g:ycm_min_num_identifier_candidate_chars| option - 3. The |g:ycm_max_num_candidates| option - 4. The |g:ycm_max_num_candidates_to_detail| option - 5. The |g:ycm_max_num_identifier_candidates| option - 6. The |g:ycm_auto_trigger| option - 7. The |g:ycm_filetype_whitelist| option - 8. The |g:ycm_filetype_blacklist| option - 9. The |g:ycm_filetype_specific_completion_to_disable| option - 10. The |g:ycm_filepath_blacklist| option - 11. The |g:ycm_show_diagnostics_ui| option - 12. The |g:ycm_error_symbol| option - 13. The |g:ycm_warning_symbol| option - 14. The |g:ycm_enable_diagnostic_signs| option - 15. The |g:ycm_enable_diagnostic_highlighting| option - 16. The |g:ycm_echo_current_diagnostic| option - 17. The |g:ycm_auto_hover| option - 18. The |g:ycm_filter_diagnostics| option - 19. The |g:ycm_always_populate_location_list| option - 20. The |g:ycm_open_loclist_on_ycm_diags| option - 21. The |g:ycm_complete_in_comments| option - 22. The |g:ycm_complete_in_strings| option - 23. The |g:ycm_collect_identifiers_from_comments_and_strings| option - 24. The |g:ycm_collect_identifiers_from_tags_files| option - 25. The |g:ycm_seed_identifiers_with_syntax| option - 26. The |g:ycm_extra_conf_vim_data| option - 27. The |g:ycm_server_python_interpreter| option - 28. The |g:ycm_keep_logfiles| option - 29. The |g:ycm_log_level| option - 30. The |g:ycm_auto_start_csharp_server| option - 31. The |g:ycm_auto_stop_csharp_server| option - 32. The |g:ycm_csharp_server_port| option - 33. The |g:ycm_csharp_insert_namespace_expr| option - 34. The |g:ycm_add_preview_to_completeopt| option - 35. The |g:ycm_autoclose_preview_window_after_completion| option - 36. The |g:ycm_autoclose_preview_window_after_insertion| option - 37. The |g:ycm_max_diagnostics_to_display| option - 38. The |g:ycm_key_list_select_completion| option - 39. The |g:ycm_key_list_previous_completion| option - 40. The |g:ycm_key_list_stop_completion| option - 41. The |g:ycm_key_invoke_completion| option - 42. The |g:ycm_key_detailed_diagnostics| option - 43. The |g:ycm_global_ycm_extra_conf| option - 44. The |g:ycm_confirm_extra_conf| option - 45. The |g:ycm_extra_conf_globlist| option - 46. The |g:ycm_filepath_completion_use_working_dir| option - 47. The |g:ycm_semantic_triggers| option - 48. The |g:ycm_cache_omnifunc| option - 49. The |g:ycm_use_ultisnips_completer| option - 50. The |g:ycm_goto_buffer_command| option - 51. The |g:ycm_disable_for_files_larger_than_kb| option - 52. The |g:ycm_use_clangd| option - 53. The |g:ycm_clangd_binary_path| option - 54. The |g:ycm_clangd_args| option - 55. The |g:ycm_clangd_uses_ycmd_caching| option - 56. The |g:ycm_language_server| option - 57. The |g:ycm_disable_signature_help| option - 58. The |g:ycm_gopls_binary_path| option - 59. The |g:ycm_gopls_args| option - 60. The |g:ycm_rls_binary_path| and 'g:ycm_rustc_binary_path' options - 61. The |g:ycm_rust_toolchain_root| option - 62. The |g:ycm_tsserver_binary_path| option - 63. The |g:ycm_roslyn_binary_path| option - 64. The |g:ycm_update_diagnostics_in_insert_mode| option - 13. FAQ |youcompleteme-faq| - 14. Contributor Code of Conduct |youcompleteme-contributor-code-of-conduct| - 15. Contact |youcompleteme-contact| - 16. License |youcompleteme-license| - 17. Sponsorship |youcompleteme-sponsorship| - 18. References |youcompleteme-references| + 1. Help, Advice, Support |youcompleteme-help-advice-support| + 2. Vundle |youcompleteme-vundle| + 1. Contents |youcompleteme-contents| + 2. Intro |youcompleteme-intro| + 3. Installation |youcompleteme-installation| + 1. Requirements |youcompleteme-requirements| + 1. Supported Vim Versions |youcompleteme-supported-vim-versions| + 2. Supported Python runtime |youcompleteme-supported-python-runtime| + 3. Supported Compilers |youcompleteme-supported-compilers| + 4. Individual completer requirements |youcompleteme-individual-completer-requirements| + 2. macOS |youcompleteme-macos| + 1. Quick start, installing all completers |youcompleteme-quick-start-installing-all-completers| + 2. Explanation for the quick start |youcompleteme-explanation-for-quick-start| + 3. Linux 64-bit |youcompleteme-linux-64-bit| + 1. Quick start, installing all completers + 2. Explanation for the quick start + 4. Windows |youcompleteme-windows| + 1. Quick start, installing all completers + 2. Explanation for the quick start + 5. Full Installation Guide |youcompleteme-full-installation-guide| + 4. Quick Feature Summary |youcompleteme-quick-feature-summary| + 1. General (all languages) |youcompleteme-general| + 2. C-family languages (C, C++, Objective C, Objective C++, CUDA) |youcompleteme-c-family-languages| + 3. C♯ |youcompleteme-c| + 4. Python |youcompleteme-python| + 5. Go |youcompleteme-go| + 6. JavaScript and TypeScript |youcompleteme-javascript-typescript| + 7. Rust |youcompleteme-rust| + 8. Java |youcompleteme-java| + 5. User Guide |youcompleteme-user-guide| + 1. General Usage |youcompleteme-general-usage| + 2. Client-Server Architecture |youcompleteme-client-server-architecture| + 3. Completion String Ranking |youcompleteme-completion-string-ranking| + 4. Signature Help |youcompleteme-signature-help| + 1. Dismiss signature help |youcompleteme-dismiss-signature-help| + 5. Semantic highlighting |youcompleteme-semantic-highlighting| + 1. Customising the highlight groups |youcompleteme-customising-highlight-groups| + 6. Inlay hints |youcompleteme-inlay-hints| + 1. Highlight groups |youcompleteme-highlight-groups| + 2. Options |youcompleteme-options| + 3. Toggling |youcompleteme-toggling| + 4. General Semantic Completion |youcompleteme-general-semantic-completion| + 5. C-family Semantic Completion |youcompleteme-c-family-semantic-completion| + 1. Installation + 2. Compile flags |youcompleteme-compile-flags| + 3. Option 1: Use a compilation database [53] |youcompleteme-option-1-use-compilation-database-53| + 4. Option 2: Provide the flags manually |youcompleteme-option-2-provide-flags-manually| + 5. Errors during compilation |youcompleteme-errors-during-compilation| + 6. Java Semantic Completion |youcompleteme-java-semantic-completion| + 1. Java Quick Start |youcompleteme-java-quick-start| + 2. Java Project Files |youcompleteme-java-project-files| + 3. Diagnostic display - Syntastic |youcompleteme-diagnostic-display-syntastic| + 4. Diagnostic display - Eclim |youcompleteme-diagnostic-display-eclim| + 5. Eclipse Projects |youcompleteme-eclipse-projects| + 6. Maven Projects |youcompleteme-maven-projects| + 7. Gradle Projects |youcompleteme-gradle-projects| + 8. Troubleshooting |youcompleteme-troubleshooting| + 7. C# Semantic Completion |youcompleteme-c-semantic-completion| + 1. Automatically discovered solution files |youcompleteme-automatically-discovered-solution-files| + 2. Manually specified solution files |youcompleteme-manually-specified-solution-files| + 3. Use with .NET 6.0 and .NET SDKs |youcompleteme-use-with-.net-6.0-.net-sdks| + 8. Python Semantic Completion |youcompleteme-python-semantic-completion| + 1. Working with virtual environments |youcompleteme-working-with-virtual-environments| + 2. Working with third-party packages |youcompleteme-working-with-third-party-packages| + 3. Configuring through Vim options |youcompleteme-configuring-through-vim-options| + 9. Rust Semantic Completion |youcompleteme-rust-semantic-completion| + 10. Go Semantic Completion |youcompleteme-go-semantic-completion| + 11. JavaScript and TypeScript Semantic Completion |youcompleteme-javascript-typescript-semantic-completion| + 12. Semantic Completion for Other Languages |youcompleteme-semantic-completion-for-other-languages| + 1. Plugging an arbitrary LSP server |youcompleteme-plugging-an-arbitrary-lsp-server| + 2. LSP Configuration |youcompleteme-lsp-configuration| + 3. Using 'omnifunc' for semantic completion |youcompleteme-using-omnifunc-for-semantic-completion| + 13. Writing New Semantic Completers |youcompleteme-writing-new-semantic-completers| + 14. Diagnostic Display |youcompleteme-diagnostic-display| + 1. Diagnostic Highlighting Groups |youcompleteme-diagnostic-highlighting-groups| + 15. Symbol Search |youcompleteme-symbol-search| + 1. Closing the popup |youcompleteme-closing-popup| + 16. Type/Call Hierarchy |youcompleteme-type-call-hierarchy| + 7. Commands |youcompleteme-commands| + 1. The |:YcmRestartServer| command + 2. The |:YcmForceCompileAndDiagnostics| command + 3. The |:YcmDiags| command + 4. The |:YcmShowDetailedDiagnostic| command + 5. The |:YcmDebugInfo| command + 6. The |:YcmToggleLogs| command + 7. The |:YcmCompleter| command + 8. YcmCompleter Subcommands |youcompleteme-ycmcompleter-subcommands| + 1. GoTo Commands |youcompleteme-goto-commands| + 1. The |GoToInclude| subcommand + 2. The |GoToAlternateFile| subcommand + 3. The |GoToDeclaration| subcommand + 4. The |GoToDefinition| subcommand + 5. The |GoTo| subcommand + 6. The |GoToImprecise| subcommand + 7. The 'GoToSymbol ' subcommand |GoToSymbol-symbol-query| + 8. The |GoToReferences| subcommand + 9. The |GoToImplementation| subcommand + 10. The |GoToImplementationElseDeclaration| subcommand + 11. The |GoToType| subcommand + 12. The |GoToDocumentOutline| subcommand + 13. The |GoToCallers| and 'GoToCallees' subcommands + 2. Semantic Information Commands |youcompleteme-semantic-information-commands| + 1. The |GetType| subcommand + 2. The |GetTypeImprecise| subcommand + 3. The |GetParent| subcommand + 4. The |GetDoc| subcommand + 5. The |GetDocImprecise| subcommand + 3. Refactoring Commands |youcompleteme-refactoring-commands| + 1. The |FixIt| subcommand + 2. The 'RefactorRename ' subcommand |RefactorRename-new-name| + 3. Python refactorings |youcompleteme-python-refactorings| + 4. Multi-file Refactor |youcompleteme-multi-file-refactor| + 5. The |Format| subcommand + 6. The |OrganizeImports| subcommand + 4. Miscellaneous Commands |youcompleteme-miscellaneous-commands| + 1. The 'ExecuteCommand ' subcommand |ExecuteCommand-args| + 2. The |RestartServer| subcommand + 3. The |ReloadSolution| subcommand + 9. Functions |youcompleteme-functions| + 1. The |youcompleteme#GetErrorCount| function + 2. The |youcompleteme#GetWarningCount| function + 3. The 'youcompleteme#GetCommandResponse( ... )' function |youcompleteme#GetCommandResponse()| + 4. The 'youcompleteme#GetCommandResponseAsync( callback, ... )' function |youcompleteme#GetCommandResponseAsync()| + 10. Autocommands |youcompleteme-autocommands| + 1. The |YcmLocationOpened| autocommand + 2. The |YcmQuickFixOpened| autocommand + 11. Options + 1. The |g:ycm_min_num_of_chars_for_completion| option + 2. The |g:ycm_min_num_identifier_candidate_chars| option + 3. The |g:ycm_max_num_candidates| option + 4. The |g:ycm_max_num_candidates_to_detail| option + 5. The |g:ycm_max_num_identifier_candidates| option + 6. The |g:ycm_auto_trigger| option + 7. The |g:ycm_filetype_whitelist| option + 8. The |g:ycm_filetype_blacklist| option + 9. The |g:ycm_filetype_specific_completion_to_disable| option + 10. The |g:ycm_filepath_blacklist| option + 11. The |g:ycm_show_diagnostics_ui| option + 12. The |g:ycm_error_symbol| option + 13. The |g:ycm_warning_symbol| option + 14. The |g:ycm_enable_diagnostic_signs| option + 15. The |g:ycm_enable_diagnostic_highlighting| option + 16. The |g:ycm_echo_current_diagnostic| option + 17. The |g:ycm_auto_hover| option + 18. The |g:ycm_filter_diagnostics| option + 19. The |g:ycm_always_populate_location_list| option + 20. The |g:ycm_open_loclist_on_ycm_diags| option + 21. The |g:ycm_complete_in_comments| option + 22. The |g:ycm_complete_in_strings| option + 23. The |g:ycm_collect_identifiers_from_comments_and_strings| option + 24. The |g:ycm_collect_identifiers_from_tags_files| option + 25. The |g:ycm_seed_identifiers_with_syntax| option + 26. The |g:ycm_extra_conf_vim_data| option + 27. The |g:ycm_server_python_interpreter| option + 28. The |g:ycm_keep_logfiles| option + 29. The |g:ycm_log_level| option + 30. The |g:ycm_auto_start_csharp_server| option + 31. The |g:ycm_auto_stop_csharp_server| option + 32. The |g:ycm_csharp_server_port| option + 33. The |g:ycm_csharp_insert_namespace_expr| option + 34. The |g:ycm_add_preview_to_completeopt| option + 35. The |g:ycm_autoclose_preview_window_after_completion| option + 36. The |g:ycm_autoclose_preview_window_after_insertion| option + 37. The |g:ycm_max_diagnostics_to_display| option + 38. The |g:ycm_key_list_select_completion| option + 39. The |g:ycm_key_list_previous_completion| option + 40. The |g:ycm_key_list_stop_completion| option + 41. The |g:ycm_key_invoke_completion| option + 42. The |g:ycm_key_detailed_diagnostics| option + 43. The |g:ycm_show_detailed_diag_in_popup| option + 44. The |g:ycm_global_ycm_extra_conf| option + 45. The |g:ycm_confirm_extra_conf| option + 46. The |g:ycm_extra_conf_globlist| option + 47. The |g:ycm_filepath_completion_use_working_dir| option + 48. The |g:ycm_semantic_triggers| option + 49. The |g:ycm_cache_omnifunc| option + 50. The |g:ycm_use_ultisnips_completer| option + 51. The |g:ycm_goto_buffer_command| option + 52. The |g:ycm_disable_for_files_larger_than_kb| option + 53. The |g:ycm_use_clangd| option + 54. The |g:ycm_clangd_binary_path| option + 55. The |g:ycm_clangd_args| option + 56. The |g:ycm_clangd_uses_ycmd_caching| option + 57. The |g:ycm_language_server| option + 58. The |g:ycm_disable_signature_help| option + 59. The |g:ycm_signature_help_disable_syntax| option + 60. The |g:ycm_gopls_binary_path| option + 61. The |g:ycm_gopls_args| option + 62. The |g:ycm_rls_binary_path| and 'g:ycm_rustc_binary_path' options + 63. The |g:ycm_rust_toolchain_root| option + 64. The |g:ycm_tsserver_binary_path| option + 65. The |g:ycm_roslyn_binary_path| option + 66. The |g:ycm_update_diagnostics_in_insert_mode| option + 12. FAQ |youcompleteme-faq| + 13. Contributor Code of Conduct |youcompleteme-contributor-code-of-conduct| + 14. Contact |youcompleteme-contact| + 15. License |youcompleteme-license| + 16. Sponsorship |youcompleteme-sponsorship| + 3. References |youcompleteme-references| =============================================================================== *youcompleteme-introduction* @@ -199,11 +210,11 @@ Introduction ~ Image: Gitter room [1] Image: Build status [3] Image: Coverage status [5] -=============================================================================== +------------------------------------------------------------------------------- *youcompleteme-help-advice-support* Help, Advice, Support ~ -Looking for help, advice or support? Having problems getting YCM to work? +Looking for help, advice, or support? Having problems getting YCM to work? First carefully read the installation instructions for your OS. We recommend you use the supplied 'install.py' - the "full" installation guide is for rare, @@ -212,8 +223,8 @@ advanced use cases and most users should use 'install.py'. If the server isn't starting and you're getting a "YouCompleteMe unavailable" error, check the Troubleshooting [7] guide. -Next check the User Guide section on the semantic completer that you are using. -For C/C++/Objective-C/Objective-C++/CUDA, you _must_ read this section. +Next, check the User Guide section on the semantic completer that you are +using. For C/C++/Objective-C/Objective-C++/CUDA, you _must_ read this section. Finally, check the FAQ [8]. @@ -225,6 +236,14 @@ Please do **NOT** go to #vim on Freenode for support. Please contact the YouCompleteMe maintainers directly using the contact details below. =============================================================================== + *youcompleteme-vundle* +Vundle ~ + +Please note that the below instructions suggest using Vundle. Currently there +are problems with Vundle, so here are some alternative instructions [9] using +Vim packages. + +------------------------------------------------------------------------------- *youcompleteme-contents* Contents ~ @@ -235,7 +254,6 @@ Contents ~ - macOS - Linux 64-bit - Windows - - FreeBSD/OpenBSD - Full Installation Guide - Quick Feature Summary @@ -246,6 +264,8 @@ Contents ~ - Completion String Ranking - General Semantic Completion - Signature Help + - Semantic Highlighting + - Inlay Hints - C-family Semantic Completion - Java Semantic Completion - C# Semantic Completion @@ -261,6 +281,7 @@ Contents ~ - Diagnostic Highlighting Groups - Symbol Search + - Type/Call Hierarchy - Commands @@ -280,35 +301,35 @@ Contents ~ - License - Sponsorship -=============================================================================== +------------------------------------------------------------------------------- *youcompleteme-intro* Intro ~ YouCompleteMe is a fast, as-you-type, fuzzy-search code completion, -comprehension and refactoring engine for Vim [9]. +comprehension and refactoring engine for Vim [10]. -It has several completion engines built in and supports any protocol-compliant +It has several completion engines built-in and supports any protocol-compliant Language Server, so can work with practically any language. YouCompleteMe contains: - an identifier-based engine that works with every programming language, -- a powerful clangd [10]-based engine that provides native semantic code +- a powerful clangd [11]-based engine that provides native semantic code completion for C/C++/Objective-C/Objective-C++/CUDA (from now on referred to as "the C-family languages"), -- a Jedi [11]-based completion engine for Python 2 and 3, -- an OmniSharp-Roslyn [12]-based completion engine for C#, -- a Gopls [13]-based completion engine for Go, -- a TSServer [14]-based completion engine for JavaScript and TypeScript, -- a rust-analyzer [15]-based completion engine for Rust, -- a jdt.ls [16]-based completion engine for Java. +- a Jedi [12]-based completion engine for Python 2 and 3, +- an OmniSharp-Roslyn [13]-based completion engine for C#, +- a Gopls [14]-based completion engine for Go, +- a TSServer [15]-based completion engine for JavaScript and TypeScript, +- a rust-analyzer [16]-based completion engine for Rust, +- a jdt.ls [17]-based completion engine for Java. - a generic Language Server Protocol implementation for any language - and an omnifunc-based completer that uses data from Vim's omnicomplete - system to provide semantic completions for many other languages (Ruby, PHP + system to provide semantic completions for many other languages (Ruby, PHP, etc.). - Image: YouCompleteMe GIF completion demo (see reference [17]) + Image: YouCompleteMe GIF completion demo (see reference [18]) -Here's an explanation of what happens in the last GIF demo above. +Here's an explanation of what happened in the last GIF demo above. First, realize that **no keyboard shortcuts had to be pressed** to get the list of completion candidates at any point in the demo. The user just types and the @@ -325,7 +346,7 @@ typing to further filter out unwanted completions. A critical thing to notice is that the completion **filtering is NOT based on the input being a string prefix of the completion** (but that works too). The -input needs to be a _subsequence [18] match_ of a completion. This is a fancy +input needs to be a _subsequence [19] match_ of a completion. This is a fancy way of saying that any input characters need to be present in a completion string in the order in which they appear in the input. So 'abc' is a subsequence of 'xaybgc', but not of 'xbyxaxxc'. After the filter, a complicated @@ -344,17 +365,17 @@ with a keyboard shortcut; see the rest of the docs). The last thing that you can see in the demo is YCM's diagnostic display features (the little red X that shows up in the left gutter; inspired by -Syntastic [19]) if you are editing a C-family file. As the completer engine +Syntastic [20]) if you are editing a C-family file. As the completer engine compiles your file and detects warnings or errors, they will be presented in various ways. You don't need to save your file or press any keyboard shortcut to trigger this, it "just happens" in the background. **And that's not all...** -YCM might be the only vim completion engine with the correct Unicode support. +YCM might be the only Vim completion engine with the correct Unicode support. Though we do assume UTF-8 everywhere. - Image: YouCompleteMe GIF unicode demo (see reference [20]) + Image: YouCompleteMe GIF unicode demo (see reference [21]) YCM also provides semantic IDE-like features in a number of languages, including: @@ -373,32 +394,32 @@ including: For example, here's a demo of signature help: - Image: Signature Help Early Demo (see reference [21]) + Image: Signature Help Early Demo (see reference [22]) Below we can see YCM being able to do a few things: - Retrieve references across files - Go to declaration/definition - Expand 'auto' in C++ -- Fix some common errors with |FixIt| -- Not shown in the GIF is |GoToImplementation| and |GoToType| for servers +- Fix some common errors, and provide refactorings, with |FixIt| +- Not shown in the GIF are |GoToImplementation| and |GoToType| for servers that support it. - Image: YouCompleteMe GIF subcommands demo (see reference [22]) + Image: YouCompleteMe GIF subcommands demo (see reference [23]) And here's some documentation being shown in a hover popup, automatically and manually: - Image: hover demo (see reference [23]) + Image: hover demo (see reference [24]) Features vary by file type, so make sure to check out the file type feature summary and the full list of completer subcommands to find out what's available for your favourite languages. You'll also find that YCM has filepath completers (try typing './' in a file) -and a completer that integrates with UltiSnips [24]. +and a completer that integrates with UltiSnips [25]. -=============================================================================== +------------------------------------------------------------------------------- *youcompleteme-installation* Installation ~ @@ -406,21 +427,53 @@ Installation ~ *youcompleteme-requirements* Requirements ~ +=============================================================================== +| _Runtime_ | _Min Version_ | _Recommended Version (full support)_ | _Python_ | +=============================================================================== +| Vim | 9.1.0016 | 9.1.0016 | 3.12 | +------------------------------------------------------------------------------- +| Neovim | 0.5 | Vim 9.1.0016 | 3.12 | +------------------------------------------------------------------------------- + + ------------------------------------------------------------------------------- *youcompleteme-supported-vim-versions* Supported Vim Versions ~ Our policy is to support the Vim version that's in the latest LTS of Ubuntu. -That's currently Ubuntu 20.04 which contains 'vim-nox' at 'v8.1.2269'. -Vim must have a working Python 3.6 runtime, compiled with '--enable-shared' (or -'--enable-framework'). You can check with ':py3 import sys; print( sys.version -)'. +Vim must have a working Python 3 runtime. For Neovim users, our policy is to require the latest released version. Currently, Neovim 0.5.0 is required. Please note that some features are not available in Neovim, and Neovim is not officially supported. +------------------------------------------------------------------------------- + *youcompleteme-supported-python-runtime* +Supported Python runtime ~ + +YCM has two components: A server and a client. Both the server and client +require Python 3.12 or later 3.x release. + +For the Vim client, Vim must be, compiled with '--enable-shared' (or +'--enable-framework' on macOS). You can check if this is working with ':py3 +import sys; print( sys.version)'. It should say something like '3.12.0 (...)'. + +For Neovim, you must have a python 3.12 runtime and the Neovim python +extensions. See Neovim's ':help provider-python' for how to set that up. + +For the server, you must run the 'install.py' script with a python 3.12 (or +later) runtime. Anaconda etc. are not supported. YCM will remember the runtime +you used to run 'install.py' and will use that when launching the server, so if +you usually use anaconda, then make sure to use the full path to a real +cpython3, e.g. '/usr/bin/python3 install.py --all' etc. + +Our policy is to support the python3 version that's available in the latest +Ubuntu LTS (similar to our Vim version policy). We don't increase the Python +runtime version without a reason, though. Typically, we do this when the +current python version we're using goes out of support. At that time we will +typically pick a version that will be supported for a number of years. + ------------------------------------------------------------------------------- *youcompleteme-supported-compilers* Supported Compilers ~ @@ -448,9 +501,9 @@ to simply 'pip install --user cmake' to get a really new version. Individual completer requirements ~ When enabling language support for a particular language, there may be runtime -requirements, such as needing Java Development Kit for Java support. In -general, YCM is not in control of the required versions for the downstream -compilers, though we do our best to signal where we know them. +requirements, such as needing a very recent Java Development Kit for Java +support. In general, YCM is not in control of the required versions for the +downstream compilers, though we do our best to signal where we know them. ------------------------------------------------------------------------------- *youcompleteme-macos* @@ -460,30 +513,30 @@ macOS ~ *youcompleteme-quick-start-installing-all-completers* Quick start, installing all completers ~ -- Install YCM plugin via Vundle [25] +- Install YCM plugin via Vundle [26] - Install CMake, MacVim and Python 3; Note that the pre-installed _macOS - system_ vim is not supported (due to it having broken Python integration). + system_ Vim is not supported (due to it having broken Python integration). > $ brew install cmake python go nodejs < -- Install mono from Mono Project [26] (NOTE: on Intel Macs you can also 'brew +- Install mono from Mono Project [27] (NOTE: on Intel Macs you can also 'brew install mono'. On arm Macs, you may require Rosetta) -- For java support you must install a JDK, one way to do this is with +- For Java support you must install a JDK, one way to do this is with Homebrew: > $ brew install java $ sudo ln -sfn $(brew --prefix java)/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk.jdk < - Pre-installed macOS _system_ Vim does not support Python 3. So you need to - install either a Vim that supports Python 3 OR MacVim [27] with Homebrew - [28]: + install either a Vim that supports Python 3 OR MacVim [28] with Homebrew + [29]: - Option 1: Installing a Vim that supports Python 3 > brew install vim < -- Option 2: Installing MacVim [27] +- Option 2: Installing MacVim [28] > brew install macvim < @@ -517,11 +570,11 @@ These instructions (using 'install.py') are the quickest way to install YouCompleteMe, however they may not work for everyone. If the following instructions don't work for you, check out the full installation guide. -A supported Vim version with Python 3 is required. MacVim [27] is a good +A supported Vim version with Python 3 is required. MacVim [28] is a good option, even if you only use the terminal. YCM won't work with the pre-installed Vim from Apple as its Python support is broken. If you don't -already use a Vim that supports Python 3 or MacVim [27], install it with -Homebrew [28]. Install CMake as well: +already use a Vim that supports Python 3 or MacVim [28], install it with +Homebrew [29]. Install CMake as well: > brew install vim cmake < @@ -529,7 +582,7 @@ OR > brew install macvim cmake < -Install YouCompleteMe with Vundle [25]. +Install YouCompleteMe with Vundle [26]. **Remember:** YCM is a plugin with a compiled component. If you **update** YCM using Vundle and the 'ycm_core' library APIs have changed (happens rarely), YCM @@ -553,18 +606,18 @@ Compiling YCM **without** semantic support for C-family languages: < The following additional language support options are available: -- C# support: install by downloading the Mono macOS package [29] and add +- C# support: install by downloading the Mono macOS package [30] and add '--cs-completer' when calling 'install.py'. -- Go support: install Go [30] and add '--go-completer' when calling +- Go support: install Go [31] and add '--go-completer' when calling 'install.py'. -- JavaScript and TypeScript support: install Node.js and npm [31] and add +- JavaScript and TypeScript support: install Node.js 18+ and npm [32] and add '--ts-completer' when calling 'install.py'. - Rust support: add '--rust-completer' when calling 'install.py'. -- Java support: install JDK [32] and add '--java-completer' when calling +- Java support: install JDK 17 [33] and add '--java-completer' when calling 'install.py'. To simply compile with everything enabled, there's a '--all' flag. So, to @@ -587,19 +640,19 @@ that are conservatively turned off by default that you may want to turn on. *youcompleteme-linux-64-bit* Linux 64-bit ~ -The following assume you're using Ubuntu 20.04. +The following assume you're using Ubuntu 24.04. ------------------------------------------------------------------------------- Quick start, installing all completers ~ -- Install YCM plugin via Vundle [25] +- Install YCM plugin via Vundle [26] - Install CMake, Vim and Python > apt install build-essential cmake vim-nox python3-dev < -- Install mono-complete, go, node, java and npm +- Install mono-complete, go, node, java, and npm > - apt install mono-complete golang nodejs default-jdk npm + apt install mono-complete golang nodejs openjdk-17-jdk openjdk-17-jre npm < - Compile YCM > @@ -615,19 +668,20 @@ These instructions (using 'install.py') are the quickest way to install YouCompleteMe, however they may not work for everyone. If the following instructions don't work for you, check out the full installation guide. -Make sure you have a supported version of Vim with Python 3 support, and a +Make sure you have a supported version of Vim with Python 3 support and a supported compiler. The latest LTS of Ubuntu is the minimum platform for simple installation. For earlier releases or other distributions, you may have to do some work to acquire the dependencies. -If your vim version is too old, you may need to compile Vim from source [33] +If your Vim version is too old, you may need to compile Vim from source [34] (don't worry, it's easy). -Install YouCompleteMe with Vundle [25]. +Install YouCompleteMe with Vundle [26]. **Remember:** YCM is a plugin with a compiled component. If you **update** YCM -using Vundle and the 'ycm_core' library APIs have changed (happens rarely), YCM -will notify you to recompile it. You should then rerun the install process. +using Vundle and the 'ycm_core' library APIs have changed (which happens +rarely), YCM will notify you to recompile it. You should then rerun the +installation process. Install development tools, CMake, and Python headers: @@ -652,22 +706,22 @@ Compiling YCM **without** semantic support for C-family languages: < The following additional language support options are available: -- C# support: install Mono [34] and add '--cs-completer' when calling +- C# support: install Mono [35] and add '--cs-completer' when calling 'install.py'. -- Go support: install Go [30] and add '--go-completer' when calling +- Go support: install Go [31] and add '--go-completer' when calling 'install.py'. -- JavaScript and TypeScript support: install Node.js and npm [31] and add +- JavaScript and TypeScript support: install Node.js 18+ and npm [32] and add '--ts-completer' when calling 'install.py'. - Rust support: add '--rust-completer' when calling 'install.py'. -- Java support: install JDK [32] and add '--java-completer' when calling +- Java support: install JDK 17 [33] and add '--java-completer' when calling 'install.py'. To simply compile with everything enabled, there's a '--all' flag. So, to -install with all language features, ensure 'xbuild', 'go', 'node' and 'npm' +install with all language features, ensure 'xbuild', 'go', 'node', and 'npm' tools are installed and in your 'PATH', then simply run: > cd ~/.vim/bundle/YouCompleteMe @@ -686,11 +740,15 @@ that are conservatively turned off by default that you may want to turn on. *youcompleteme-windows* Windows ~ +**_NOTE_**: Windows support is _deprecated_ and _unmaintained_. We will do our +best to keep it working, but we no longer test it in CI and there is a high +likelihood of breakages. + ------------------------------------------------------------------------------- Quick start, installing all completers ~ -- Install YCM plugin via Vundle [25] -- Install Visual Studio Build Tools 2019 [35] +- Install YCM plugin via Vundle [26] +- Install Visual Studio Build Tools 2019 [36] - Install CMake, Vim and Python - Install go, node and npm - Compile YCM @@ -698,7 +756,7 @@ Quick start, installing all completers ~ cd YouCompleteMe python3 install.py --all < -- Add 'set encoding=utf-8' to your vimrc [36] +- Add 'set encoding=utf-8' to your vimrc [37] - For plugging an arbitrary LSP server, check the relevant section ------------------------------------------------------------------------------- @@ -716,9 +774,9 @@ the version and which Python is supported by typing ':version' inside Vim. Look at the features included: '+python3/dyn' for Python 3. Take note of the Vim architecture, i.e. 32 or 64-bit. It will be important when choosing the Python installer. We recommend using a 64-bit client. Daily updated installers of -32-bit and 64-bit Vim with Python 3 support [37] are available. +32-bit and 64-bit Vim with Python 3 support [38] are available. -Add the following line to your vimrc [36] if not already present.: +Add the following line to your vimrc [37] if not already present.: > set encoding=utf-8 < @@ -726,7 +784,7 @@ This option is required by YCM. Note that it does not prevent you from editing a file in another encoding than UTF-8. You can do that by specifying the '|++enc|' argument to the ':e' command. -Install YouCompleteMe with Vundle [25]. +Install YouCompleteMe with Vundle [26]. **Remember:** YCM is a plugin with a compiled component. If you **update** YCM using Vundle and the 'ycm_core' library APIs have changed (happens rarely), YCM @@ -734,7 +792,7 @@ will notify you to recompile it. You should then rerun the install process. Download and install the following software: -- Python 3 [38]. Be sure to pick the version corresponding to your Vim +- Python 3 [39]. Be sure to pick the version corresponding to your Vim architecture. It is _Windows x86_ for a 32-bit Vim and _Windows x86-64_ for a 64-bit Vim. We recommend installing Python 3. Additionally, the version of Python you install must match up exactly with the version of Python that @@ -744,9 +802,9 @@ Download and install the following software: looking for Python 3.6. You'll need one or the other installed, matching the version number exactly. -- CMake [39]. Add CMake executable to the PATH environment variable. +- CMake [40]. Add CMake executable to the PATH environment variable. -- Build Tools for Visual Studio 2019 [35]. During setup, select _C++ build +- Build Tools for Visual Studio 2019 [36]. During setup, select _C++ build tools_ in _Workloads_. Compiling YCM **with** semantic support for C-family languages through @@ -763,17 +821,17 @@ Compiling YCM **without** semantic support for C-family languages: The following additional language support options are available: - C# support: add '--cs-completer' when calling 'install.py'. Be sure that - the build utility 'msbuild' is in your PATH [40]. + the build utility 'msbuild' is in your PATH [41]. -- Go support: install Go [30] and add '--go-completer' when calling +- Go support: install Go [31] and add '--go-completer' when calling 'install.py'. -- JavaScript and TypeScript support: install Node.js and npm [31] and add +- JavaScript and TypeScript support: install Node.js 18+ and npm [32] and add '--ts-completer' when calling 'install.py'. - Rust support: add '--rust-completer' when calling 'install.py'. -- Java support: install JDK [32] and add '--java-completer' when calling +- Java support: install JDK 17 [33] and add '--java-completer' when calling 'install.py'. To simply compile with everything enabled, there's a '--all' flag. So, to @@ -796,101 +854,13 @@ YCM comes with sane defaults for its options, but you still may want to take a look at what's available for configuration. There are a few interesting options that are conservatively turned off by default that you may want to turn on. -------------------------------------------------------------------------------- - *youcompleteme-freebsd-openbsd* -FreeBSD/OpenBSD ~ - -------------------------------------------------------------------------------- -Quick start, installing all completers ~ - -- Install YCM plugin via Vundle [25] -- Install CMake -> - pkg install cmake -< -- Install xbuild, go, node and npm -- Compile YCM -> - cd ~/.vim/bundle/YouCompleteMe - python3 install.py --all -< -- For plugging an arbitrary LSP server, check the relevant section - -------------------------------------------------------------------------------- -Explanation for the quick start ~ - -These instructions (using 'install.py') are the quickest way to install -YouCompleteMe, however they may not work for everyone. If the following -instructions don't work for you, check out the full installation guide. - -**NOTE:** OpenBSD / FreeBSD are not officially supported platforms by YCM. - -Make sure you have a supported Vim version with Python 3 support, and a -supported compiler and CMake, perhaps: -> - pkg install cmake -< -Install YouCompleteMe with Vundle [25]. - -**Remember:** YCM is a plugin with a compiled component. If you **update** YCM -using Vundle and the 'ycm_core' library APIs have changed (happens rarely), YCM -will notify you to recompile it. You should then rerun the install process. - -Compiling YCM **with** semantic support for C-family languages through -**clangd**: -> - cd ~/.vim/bundle/YouCompleteMe - ./install.py --clangd-completer -< -Compiling YCM **without** semantic support for C-family languages: -> - cd ~/.vim/bundle/YouCompleteMe - ./install.py -< -If the 'python' executable is not present, or the default 'python' is not the -one that should be compiled against, specify the python interpreter explicitly: -> - python3 install.py --clangd-completer -< -The following additional language support options are available: - -- C# support: install Mono and add '--cs-completer' when calling - './install.py'. - -- Go support: install Go [30] and add '--go-completer' when calling - './install.py'. - -- JavaScript and TypeScript support: install Node.js and npm [31] and add - '--ts-completer' when calling 'install.py'. - -- Rust support: add '--rust-completer' when calling './install.py'. - -- Java support: install JDK [32] and add '--java-completer' when calling - './install.py'. - -To simply compile with everything enabled, there's a '--all' flag. So, to -install with all language features, ensure 'xbuild', 'go', 'node' and 'npm' -tools are installed and in your 'PATH', then simply run: -> - cd ~/.vim/bundle/YouCompleteMe - ./install.py --all -< -That's it. You're done. Refer to the _User Guide_ section on how to use YCM. -Don't forget that if you want the C-family semantic completion engine to work, -you will need to provide the compilation flags for your project to YCM. It's -all in the User Guide. - -YCM comes with sane defaults for its options, but you still may want to take a -look at what's available for configuration. There are a few interesting options -that are conservatively turned off by default that you may want to turn on. - ------------------------------------------------------------------------------- *youcompleteme-full-installation-guide* Full Installation Guide ~ -The full installation guide [41] has been moved to the wiki. +The full installation guide [42] has been moved to the wiki. -=============================================================================== +------------------------------------------------------------------------------- *youcompleteme-quick-feature-summary* Quick Feature Summary ~ @@ -912,14 +882,20 @@ C-family languages (C, C++, Objective C, Objective C++, CUDA) ~ - Signature help - Real-time diagnostic display - Go to include/declaration/definition (|GoTo|, etc.) +- Go to alternate file (e.g. associated header |GoToAlternateFile|) - Find Symbol ('GoToSymbol'), with interactive search - Document outline (|GoToDocumentOutline|), with interactive search - View documentation comments for identifiers (|GetDoc|) - Type information for identifiers (|GetType|) - Automatically fix certain errors (|FixIt|) +- Perform refactoring (|FixIt|) - Reference finding (|GoToReferences|) - Renaming symbols ('RefactorRename ') - Code formatting (|Format|) +- Semantic highlighting +- Inlay hints +- Type hierarchy +- Call hierarchy ------------------------------------------------------------------------------- *youcompleteme-c* @@ -934,6 +910,7 @@ C♯ ~ - View documentation comments for identifiers (|GetDoc|) - Type information for identifiers (|GetType|) - Automatically fix certain errors (|FixIt|) +- Perform refactoring (|FixIt|) - Management of OmniSharp-Roslyn server instance - Renaming symbols ('RefactorRename ') - Code formatting (|Format|) @@ -963,10 +940,13 @@ Go ~ - Go to implementation (|GoToImplementation|) - Document outline (|GoToDocumentOutline|), with interactive search - Automatically fix certain errors (|FixIt|) +- Perform refactoring (|FixIt|) - View documentation comments for identifiers (|GetDoc|) - Type information for identifiers (|GetType|) - Code formatting (|Format|) - Management of 'gopls' server instance +- Inlay hints +- Call hierarchy ------------------------------------------------------------------------------- *youcompleteme-javascript-typescript* @@ -983,11 +963,14 @@ JavaScript and TypeScript ~ - Reference finding (|GoToReferences|) - View documentation comments for identifiers (|GetDoc|) - Type information for identifiers (|GetType|) -- Automatically fix certain errors (|FixIt|) +- Automatically fix certain errors and perform refactoring (|FixIt|) +- Perform refactoring (|FixIt|) - Renaming symbols ('RefactorRename ') - Code formatting (|Format|) - Organize imports (|OrganizeImports|) - Management of 'TSServer' server instance +- Inlay hints +- Call hierarchy ------------------------------------------------------------------------------- *youcompleteme-rust* @@ -1001,10 +984,14 @@ Rust ~ - Document outline (|GoToDocumentOutline|), with interactive search - View documentation comments for identifiers (|GetDoc|) - Automatically fix certain errors (|FixIt|) +- Perform refactoring (|FixIt|) - Type information for identifiers (|GetType|) - Renaming symbols ('RefactorRename ') - Code formatting (|Format|) - Management of 'rust-analyzer' server instance +- Semantic highlighting +- Inlay hints +- Call hierarchy ------------------------------------------------------------------------------- *youcompleteme-java* @@ -1026,11 +1013,15 @@ Java ~ - Renaming symbols ('RefactorRename ') - Code formatting (|Format|) - Organize imports (|OrganizeImports|) -- Detection of java projects +- Detection of Java projects - Execute custom server command ('ExecuteCommand ') - Management of 'jdt.ls' server instance +- Semantic highlighting +- Inlay hints +- Type hierarchy +- Call hierarchy -=============================================================================== +------------------------------------------------------------------------------- *youcompleteme-user-guide* User Guide ~ @@ -1041,7 +1032,7 @@ General Usage ~ If the offered completions are too broad, keep typing characters; YCM will continue refining the offered completions based on your input. -Filtering is "smart-case" and "smart-diacritic [42]" sensitive; if you are +Filtering is "smart-case" and "smart-diacritic [43]" sensitive; if you are typing only lowercase letters, then it's case-insensitive. If your input contains uppercase letters, then the uppercase letters in your query must match uppercase letters in the completion strings (the lowercase letters still match @@ -1062,7 +1053,7 @@ with or without marks: Use the TAB key to accept a completion and continue pressing TAB to cycle -through the completions. Use Shift-TAB to cycle backwards. Note that if you're +through the completions. Use Shift-TAB to cycle backward. Note that if you're using console Vim (that is, not gvim or MacVim) then it's likely that the Shift-TAB binding will not work because the console will not pass it to Vim. You can remap the keys; see the Options section below. @@ -1092,7 +1083,7 @@ and presents the results to you. Client-Server Architecture ~ YCM has a client-server architecture; the Vim part of YCM is only a thin client -that talks to the ycmd HTTP+JSON server [43] that has the vast majority of YCM +that talks to the ycmd HTTP+JSON server [44] that has the vast majority of YCM logic and functionality. The server is started and stopped automatically as you start and stop Vim. @@ -1104,10 +1095,10 @@ The subsequence filter removes any completions that do not match the input, but then the sorting system kicks in. It's actually very complicated and uses lots of factors, but suffice it to say that "word boundary" (WB) subsequence character matches are "worth" more than non-WB matches. In effect, this means -given an input of "gua", the completion "getUserAccount" would be ranked higher -in the list than the "Fooguxa" completion (both of which are subsequence -matches). A word-boundary character are all capital characters, characters -preceded by an underscore and the first letter character in the completion +that given an input of "gua", the completion "getUserAccount" would be ranked +higher in the list than the "Fooguxa" completion (both of which are subsequence +matches). Word-boundary characters are all capital characters, characters +preceded by an underscore, and the first letter character in the completion string. ------------------------------------------------------------------------------- @@ -1121,10 +1112,11 @@ Signature help is triggered in insert mode automatically when |g:ycm_auto_trigger| is enabled and is not supported when it is not enabled. The signatures popup is hidden when there are no matching signatures or when -you leave insert mode. There is no key binding to clear the popup. +you leave insert mode. If you want to manually control when it is visible, you +can map something to 'YCMToggleSignatureHelp' (see below). For more details on this feature and a few demos, check out the PR that -proposed it [44]. +proposed it [45]. ------------------------------------------------------------------------------- *youcompleteme-dismiss-signature-help* @@ -1141,6 +1133,139 @@ _NOTE_: No default mapping is provided because insert mappings are very difficult to create without breaking or overriding some existing functionality. Ctrl-l is not a suggestion, just an example. +------------------------------------------------------------------------------- + *youcompleteme-semantic-highlighting* +Semantic highlighting ~ + +Semantic highlighting is the process where the buffer text is coloured +according to the underlying semantic type of the word, rather than classic +syntax highlighting based on regular expressions. This can be powerful +additional data that we can process very quickly. + +This feature is only supported in Vim. + +For example, here is a function with classic highlighting: + + Image: highliting-classic (see reference [46]) + +And here is the same function with semantic highlighting: + + Image: highliting-semantic (see reference [47]) + +As you can see, the function calls, macros, etc. are correctly identified. + +This can be enabled globally with 'let g:ycm_enable_semantic_highlighting=1' or +per buffer, by setting 'b:ycm_enable_semantic_highlighting'. + +------------------------------------------------------------------------------- + *youcompleteme-customising-highlight-groups* +Customising the highlight groups ~ + +YCM uses text properties (see ':help text-prop-intro') for semantic +highlighting. In order to customise the coloring, you can define the text +properties that are used. + +If you define a text property named 'YCM_HL_', then it will be used +in place of the defaults. The '' is defined as the Language Server +Protocol semantic token type, defined in the LSP Spec [48]. + +Some servers also use custom values. In this case, YCM prints a warning +including the token type name that you can customise. + +For example, to render 'parameter' tokens using the 'Normal' highlight group, +you can do this: +> + call prop_type_add( 'YCM_HL_parameter', { 'highlight': 'Normal' } ) +< +More generally, this pattern can be useful for customising the groups: +> + let MY_YCM_HIGHLIGHT_GROUP = { + \ 'typeParameter': 'PreProc', + \ 'parameter': 'Normal', + \ 'variable': 'Normal', + \ 'property': 'Normal', + \ 'enumMember': 'Normal', + \ 'event': 'Special', + \ 'member': 'Normal', + \ 'method': 'Normal', + \ 'class': 'Special', + \ 'namespace': 'Special', + \ } + + for tokenType in keys( MY_YCM_HIGHLIGHT_GROUP ) + call prop_type_add( 'YCM_HL_' . tokenType, + \ { 'highlight': MY_YCM_HIGHLIGHT_GROUP[ tokenType ] } ) + endfor +< +------------------------------------------------------------------------------- + *youcompleteme-inlay-hints* +Inlay hints ~ + +**NOTE**: Highly experimental feature, requiring Vim 9.0.214 or later (not +supported in NeoVim). + +When 'g:ycm_enable_inlay_hints' (globally) or 'b:ycm_enable_inlay_hints' (for a +specific buffer) is set to '1', then YCM will insert inlay hints as supported +by the language semantic engine. + +An inlay hint is text that is rendered on the screen that is not part of the +buffer and is often used to mark up the type or name of arguments, parameters, +etc. which help the developer understand the semantics of the code. + +Here are some examples: + +- C + + Image: c-inlay (see reference [49]) + +- TypeScript + + Image: ts-inlay (see reference [50]) + +- Go + + Image: go-inlay (see reference [51]) + +------------------------------------------------------------------------------- + *youcompleteme-highlight-groups* +Highlight groups ~ + +By default, YCM renders the inlay hints with the 'NonText' highlight group. To +override this, define the 'YcmInlayHint' highlight yourself, e.g. in your +'.vimrc': +> + hi link YcmInlayHint Comment +< +Similar to semantic highlighting above, you can override specific highlighting +for different inlay hint types by defining text properties named after the kind +of inlay hint, for example: +> + call prop_type_add( 'YCM_INLAY_Type', #{ highlight: 'Comment' } ) +< +The list of inlay hint kinds can be found in 'python/ycm/inlay_hints.py' + +------------------------------------------------------------------------------- + *youcompleteme-options* +Options ~ + +- 'g:ycm_enable_inlay_hints' or 'b:ycm_enable_inlay_hints' - enable/disable + globally or for local buffer + +- 'g:ycm_clear_inlay_hints_in_insert_mode' - set to '1' to remove all inlay + hints when entering insert mode and reinstate them when leaving insert mode + +------------------------------------------------------------------------------- + *youcompleteme-toggling* +Toggling ~ + +Inlay hints can add a lot of text to the screen and may be distracting. You can +toggle them on/off instantly, by mapping something to +'(YCMToggleInlayHints)', for example: +> + nnoremap h (YCMToggleInlayHints) +< +No default mapping is provided for this due to the personal nature of mappings. + ------------------------------------------------------------------------------- *youcompleteme-general-semantic-completion* General Semantic Completion ~ @@ -1157,7 +1282,7 @@ C-family Semantic Completion ~ users should migrate to clangd, as it provides more features and better performance. Users who rely on 'override_filename' in their '.ycm_extra_conf.py' will need to stay on the old 'libclang' engine. -Instructions on how to stay on the old engine are available on the wiki [45]. +Instructions on how to stay on the old engine are available on the wiki [52]. Some of the features of clangd: @@ -1169,7 +1294,7 @@ Some of the features of clangd: unit(TU). - **Code navigation**: Clangd provides all the GoTo requests libclang - provides and it improves those using the above mentioned index information + provides and it improves those using the above-mentioned index information to contain project-wide information rather than just the current TU. - **Rename**: Clangd can perform semantic rename operations on the current @@ -1196,7 +1321,7 @@ On supported architectures, the 'install.py' script will download a suitable clangd ('--clangd-completer') or libclang ('--clang-completer') for you. Supported architectures are: -- Linux glibc >= 2.17 (Intel, armv7-a, aarch64) - built on ubuntu 18.04 +- Linux glibc >= 2.39 (Intel, armv7-a, aarch64) - built on ubuntu 24.04 - MacOS >=10.15 (Intel, arm64) - For Intel, compatibility per clang.llvm.org downloads - For arm64, macOS 10.15+ @@ -1206,9 +1331,9 @@ Supported architectures are: Typically, clangd is installed by the YCM installer (either with '--all' or with '--clangd-completer'). This downloads a pre-built 'clangd' binary for your -architecture. If your OS or architecture is not supported or too old, you can -install a compatible 'clangd' and use |g:ycm_clangd_binary_path| to point to -it. +architecture. If your OS or architecture is not supported or is too old, you +can install a compatible 'clangd' and use |g:ycm_clangd_binary_path| to point +to it. **_libclang_**: @@ -1217,26 +1342,26 @@ it. for your environment, but again if your environment can't be supported, you can build or acquire 'libclang' for yourself and specify it when building, as: > - $ EXTRA_CMAKE_ARGS='-DPATH_TO_LLVM_ROOT=/path/to/your/llvm' ./install.py --clang-compelter --system-libclang + $ EXTRA_CMAKE_ARGS='-DPATH_TO_LLVM_ROOT=/path/to/your/llvm' ./install.py --clang-completer --system-libclang < Please note that if using custom 'clangd' or 'libclang' it _must_ match the -version that YCM requires. Currently YCM requires **_clang 13.0.0_**. +version that YCM requires. Currently YCM requires **_clang 17.0.1_**. ------------------------------------------------------------------------------- *youcompleteme-compile-flags* Compile flags ~ -In order to perform semantic analysis such as code completion, |GoTo| and +In order to perform semantic analysis such as code completion, |GoTo|, and diagnostics, YouCompleteMe uses 'clangd', which makes use of clang compiler, sometimes also referred to as LLVM. Like any compiler, clang also requires a set of compile flags in order to parse your code. Simply put: If clang can't parse your code, YouCompleteMe can't provide semantic analysis. -There are 2 methods which can be used to provide compile flags to clang: +There are 2 methods that can be used to provide compile flags to clang: ------------------------------------------------------------------------------- - *youcompleteme-option-1-use-compilation-database-46* -Option 1: Use a compilation database [46] ~ + *youcompleteme-option-1-use-compilation-database-53* +Option 1: Use a compilation database [53] ~ The easiest way to get YCM to compile your code is to use a compilation database. A compilation database is usually generated by your build system @@ -1244,13 +1369,13 @@ database. A compilation database is usually generated by your build system in your project. For information on how to generate a compilation database, see the clang -documentation [46]. In short: +documentation [53]. In short: - If using CMake, add '-DCMAKE_EXPORT_COMPILE_COMMANDS=ON' when configuring (or add 'set( CMAKE_EXPORT_COMPILE_COMMANDS ON )' to 'CMakeLists.txt') and copy or symlink the generated database to the root of your project. -- If using Ninja, check out the 'compdb' tool ('-t compdb') in its docs [47]. -- If using GNU make, check out compiledb [48] or Bear [49]. +- If using Ninja, check out the 'compdb' tool ('-t compdb') in its docs [54]. +- If using GNU make, check out compiledb [55] or Bear [56]. - For other build systems, check out '.ycm_extra_conf.py' below. If no '.ycm_extra_conf.py' is found, YouCompleteMe automatically tries to load @@ -1265,15 +1390,15 @@ searching the directories and lets clangd take over and handle the flags. *youcompleteme-option-2-provide-flags-manually* Option 2: Provide the flags manually ~ -If you don't have a compilation database, or aren't able to generate one, you +If you don't have a compilation database or aren't able to generate one, you have to tell YouCompleteMe how to compile your code some other way. Every C-family project is different. It is not possible for YCM to guess what compiler flags to supply for your project. Fortunately, YCM provides a mechanism for you to generate the flags for a particular file with _arbitrary -complexity_. This is achieved by requiring you to provide a Python module which -implements a trivial function which, given the file name as argument, returns a -list of compiler flags to use to compile that file. +complexity_. This is achieved by requiring you to provide a Python module that +implements a trivial function that, given the file name as an argument, returns +a list of compiler flags to use to compile that file. YCM looks for a '.ycm_extra_conf.py' file in the directory of the opened file or in any directory above it in the hierarchy (recursively); when the file is @@ -1314,14 +1439,14 @@ That's it! This is actually enough for most projects, but for complex projects it is not uncommon to integrate directly with an existing build system using the full power of the Python language. -For a more elaborate example, see ycmd's own '.ycm_extra_conf.py' [50]. You +For a more elaborate example, see ycmd's own '.ycm_extra_conf.py' [57]. You should be able to use it _as a starting point_. **Don't** just copy/paste that file somewhere and expect things to magically work; **your project needs different flags**. Hint: just replace the strings in the 'flags' variable with compilation flags necessary for your project. That should be enough for 99% of projects. -You could also consider using YCM-Generator [51] to generate the +You could also consider using YCM-Generator [58] to generate the 'ycm_extra_conf.py' file. ------------------------------------------------------------------------------- @@ -1345,7 +1470,7 @@ Java Semantic Completion ~ ------------------------------------------------------------------------------- *youcompleteme-java-quick-start* -Java quick Start ~ +Java Quick Start ~ 1. Ensure that you have enabled the Java completer. See the installation guide for details. @@ -1354,7 +1479,7 @@ Java quick Start ~ your Java project, by following the instructions below. 3. (Optional) Configure the LSP server. The jdt.ls configuration options - [52] can be found in their codebase. + [59] can be found in their codebase. 4. If you previously used Eclim or Syntastic for Java, disable them for Java. @@ -1366,19 +1491,20 @@ Java quick Start ~ Java Project Files ~ In order to provide semantic analysis, the Java completion engine requires -knowledge of your project structure. In particular it needs to know the class -path to use, when compiling your code. Fortunately jdt.ls [16] supports eclipse -project files [53], maven projects [54] and gradle projects [55]. +knowledge of your project structure. In particular, it needs to know the class +path to use, when compiling your code. Fortunately jdt.ls [17] supports eclipse +project files [60], maven projects [61] and gradle projects [62]. -**NOTE:** Our recommendation is to use either maven or gradle projects. +**NOTE:** Our recommendation is to use either Maven or Gradle projects. ------------------------------------------------------------------------------- *youcompleteme-diagnostic-display-syntastic* Diagnostic display - Syntastic ~ -The native support for Java includes YCM's native realtime diagnostics display. -This can conflict with other diagnostics plugins like Syntastic, so when -enabling Java support, please **manually disable Syntastic Java diagnostics**. +The native support for Java includes YCM's native real-time diagnostics +display. This can conflict with other diagnostics plugins like Syntastic, so +when enabling Java support, please **manually disable Syntastic Java +diagnostics**. Add the following to your 'vimrc': > @@ -1388,9 +1514,9 @@ Add the following to your 'vimrc': *youcompleteme-diagnostic-display-eclim* Diagnostic display - Eclim ~ -The native support for Java includes YCM's native realtime diagnostics display. -This can conflict with other diagnostics plugins like Eclim, so when enabling -Java support, please **manually disable Eclim Java diagnostics**. +The native support for Java includes YCM's native real-time diagnostics +display. This can conflict with other diagnostics plugins like Eclim, so when +enabling Java support, please **manually disable Eclim Java diagnostics**. Add the following to your 'vimrc': > @@ -1403,16 +1529,16 @@ native Java support. This can be done temporarily with ':EclimDisable'. *youcompleteme-eclipse-projects* Eclipse Projects ~ -Eclipse style projects require two files: .project [53] and .classpath [56]. +Eclipse-style projects require two files: .project [60] and .classpath [63]. If your project already has these files due to previously being set up within -eclipse, then no setup is required. jdt.ls [16] should load the project just +Eclipse, then no setup is required. jdt.ls [17] should load the project just fine (it's basically eclipse after all). However, if not, it is possible (easy in fact) to craft them manually, though -it is not recommended. You're better off using gradle or maven (see below). +it is not recommended. You're better off using Gradle or Maven (see below). -A simple eclipse style project example [57] can be found in the ycmd test +A simple eclipse style project example [64] can be found in the ycmd test directory. Normally all that is required is to copy these files to the root of your project and to edit the '.classpath' to add additional libraries, such as: > @@ -1426,16 +1552,16 @@ located (paths are relative to the .project file itself): < **NOTE**: The eclipse project and classpath files are not a public interface and it is highly recommended to use Maven or Gradle project definitions if you -don't already use eclipse to manage your projects. +don't already use Eclipse to manage your projects. ------------------------------------------------------------------------------- *youcompleteme-maven-projects* Maven Projects ~ -Maven needs a file named pom.xml [54] in the root of the project. Once again a -simple pom.xml [58] can be found in ycmd source. +Maven needs a file named pom.xml [61] in the root of the project. Once again a +simple pom.xml [65] can be found in the ycmd source. -The format of pom.xml [54] files is way beyond the scope of this document, but +The format of pom.xml [61] files is way beyond the scope of this document, but we do recommend using the various tools that can generate them for you, if you're not familiar with them already. @@ -1443,15 +1569,15 @@ you're not familiar with them already. *youcompleteme-gradle-projects* Gradle Projects ~ -Gradle projects require a build.gradle [55]. Again, there is a trivial example -in ycmd's tests [59]. +Gradle projects require a build.gradle [62]. Again, there is a trivial example +in ycmd's tests [66]. -The format of build.gradle [55] files is way beyond the scope of this document, -but we do recommend using the various tools that can generate them for you, if -you're not familiar with them already. +The format of build.gradle [62] files are way beyond the scope of this +document, but we do recommend using the various tools that can generate them +for you if you're not familiar with them already. Some users have experienced issues with their jdt.ls when using the Groovy -language for their build.gradle. As such, try using Kotlin [60] instead. +language for their build.gradle. As such, try using Kotlin [67] instead. ------------------------------------------------------------------------------- *youcompleteme-troubleshooting* @@ -1481,7 +1607,7 @@ correctly. *youcompleteme-c-semantic-completion* C# Semantic Completion ~ -YCM relies on OmniSharp-Roslyn [12] to provide completion and code navigation. +YCM relies on OmniSharp-Roslyn [13] to provide completion and code navigation. OmniSharp-Roslyn needs a solution file for a C# project and there are two ways of letting YCM know about your solution files. @@ -1490,7 +1616,7 @@ of letting YCM know about your solution files. Automatically discovered solution files ~ YCM will scan all parent directories of the file currently being edited and -look for file with '.sln' extension. +look for a file with '.sln' extension. ------------------------------------------------------------------------------- *youcompleteme-manually-specified-solution-files* @@ -1508,12 +1634,33 @@ not in any of the parent directories of the currently edited file. Example: If the path returned by 'CSharpSolutionFile' is not an actual file, YCM will fall back to the other way of finding the file. +------------------------------------------------------------------------------- + *youcompleteme-use-with-.net-6.0-.net-sdks* +Use with .NET 6.0 and .NET SDKs ~ + +YCM ships with older version of OmniSharp-Roslyn based on Mono runtime. It is +possible to use it with .NET 6.0 and newer, but it requires manual setup. + +1. Download NET 6.0 version of the OmniSharp server for your system from + releases [68] + +2. Set |g:ycm_roslyn_binary_path| to the unpacked executable 'OmniSharp' + +3. Create a solution file if one doesn't already exist, it is currently + required by YCM for internal bookkeeping + + 1. Run 'dotnet new sln' at the root of your project + 2. Run 'dotnet sln add ...' for + all of your projects + +4. Run |:YcmRestartServer| + ------------------------------------------------------------------------------- *youcompleteme-python-semantic-completion* Python Semantic Completion ~ -YCM relies on the Jedi [11] engine to provide completion and code navigation. -By default, it will pick the version of Python running the ycmd server [43] and +YCM relies on the Jedi [12] engine to provide completion and code navigation. +By default, it will pick the version of Python running the ycmd server [44] and use its 'sys.path'. While this is fine for simple projects, this needs to be configurable when working with virtual environments or in a project with third-party packages. The next sections explain how to do that. @@ -1571,22 +1718,22 @@ If you need further control on how to add paths to 'sys.path', you should define the 'PythonSysPath( **kwargs )' function in the '.ycm_extra_conf.py' file. Its keyword arguments are 'sys_path' which contains the default 'sys.path', and 'interpreter_path' which is the path to the Python interpreter. -Here's a trivial example that insert the '/path/to/third_party/package' path at -the second position of 'sys.path': +Here's a trivial example that inserts the '/path/to/third_party/package' path +at the second position of 'sys.path': > def PythonSysPath( **kwargs ): sys_path = kwargs[ 'sys_path' ] sys_path.insert( 1, '/path/to/third_party/package' ) return sys_path < -A more advanced example can be found in YCM's own '.ycm_extra_conf.py' [61]. +A more advanced example can be found in YCM's own '.ycm_extra_conf.py' [69]. ------------------------------------------------------------------------------- *youcompleteme-configuring-through-vim-options* Configuring through Vim options ~ -You may find inconvenient to have to create a '.ycm_extra_conf.py' file at the -root of each one of your projects in order to set the path to the Python +You may find it inconvenient to have to create a '.ycm_extra_conf.py' file at +the root of each one of your projects in order to set the path to the Python interpreter and/or add paths to 'sys.path' and would prefer to be able to configure those through Vim options. Don't worry, this is possible by using the |g:ycm_extra_conf_vim_data| option and creating a global extra configuration @@ -1620,21 +1767,20 @@ setting one of the options. YCM will automatically pick the new values. *youcompleteme-rust-semantic-completion* Rust Semantic Completion ~ -YCM uses rust-analyzer [15] for Rust semantic completion. +YCM uses rust-analyzer [16] for Rust semantic completion. -NOTE: Previously, YCM used rls [62] for rust completion. This is no longer -supported, as the Rust community has decided on rust-analyzer [15] as the +NOTE: Previously, YCM used rls [70] for rust completion. This is no longer +supported, as the Rust community has decided on rust-analyzer [16] as the future of Rust tooling. Completions and GoTo commands within the current crate and its dependencies should work out of the box with no additional configuration (provided that you built YCM with the '--rust-completer' flag; see the _Installation_ section for details). The install script takes care of installing the Rust source code -[63], so no configuration is necessary. +[71], so no configuration is necessary. 'rust-analyzer' supports a myriad of options. These are configured using LSP -configuration, but sadly don't appear to be documented at the time of writing. -However, there is some source code [64] which might help. +configuration, and are documented here [72]. ------------------------------------------------------------------------------- *youcompleteme-go-semantic-completion* @@ -1644,30 +1790,40 @@ Completions and GoTo commands should work out of the box (provided that you built YCM with the '--go-completer' flag; see the _Installation_ section for details). The server only works for projects with the "canonical" layout. -'gopls' also has a handful of undocumented options for which the source code -[65] is the only reference. +'gopls' also has a load of documented options [73]. +You can set these in your '.ycm_extra_conf.py'. For example, to set the build +tags: +> + def Settings( **kwargs ): + if kwargs[ 'language' ] == 'go': + return { + 'ls': { + 'build.buildFlags': [ '-tags=debug' ] } + } + } +< ------------------------------------------------------------------------------- *youcompleteme-javascript-typescript-semantic-completion* JavaScript and TypeScript Semantic Completion ~ -**NOTE:** YCM originally used the Tern [66] engine for JavaScript but due to -Tern [66] not being maintained anymore by its main author and the TSServer [14] -engine offering more features, YCM is moving to TSServer [14]. This won't -affect you if you were already using Tern [66] but you are encouraged to do the +**NOTE:** YCM originally used the Tern [74] engine for JavaScript but due to +Tern [74] not being maintained anymore by its main author and the TSServer [15] +engine offering more features, YCM is moving to TSServer [15]. This won't +affect you if you were already using Tern [74] but you are encouraged to do the switch by deleting the 'third_party/ycmd/third_party/tern_runtime/node_modules' -directory in YCM folder. If you are a new user but still want to use Tern [66], +directory in YCM folder. If you are a new user but still want to use Tern [74], you should pass the '--js-completer' option to the 'install.py' script during -installation. Further instructions on how to setup YCM with Tern [66] are -available on the wiki [67]. +installation. Further instructions on how to set up YCM with Tern [74] are +available on the wiki [75]. -All JavaScript and TypeScript features are provided by the TSServer [14] +All JavaScript and TypeScript features are provided by the TSServer [15] engine, which is included in the TypeScript SDK. To enable these features, -install Node.js and npm [31] and call the 'install.py' script with the +install Node.js 18+ and npm [32] and call the 'install.py' script with the '--ts-completer' flag. -TSServer [14] relies on the 'jsconfig.json' file [68] for JavaScript and the -'tsconfig.json' file [69] for TypeScript to analyze your project. Ensure the +TSServer [15] relies on the 'jsconfig.json' file [76] for JavaScript and the +'tsconfig.json' file [77] for TypeScript to analyze your project. Ensure the file exists at the root of your project. To get diagnostics in JavaScript, set the 'checkJs' option to 'true' in your @@ -1684,8 +1840,8 @@ To get diagnostics in JavaScript, set the 'checkJs' option to 'true' in your Semantic Completion for Other Languages ~ C-family, C#, Go, Java, Python, Rust, and JavaScript/TypeScript languages are -supported natively by YouCompleteMe using the Clang [70], OmniSharp-Roslyn -[12], Gopls [13], jdt.ls [16], Jedi [11], rust-analyzer [15], and TSServer [14] +supported natively by YouCompleteMe using the Clang [78], OmniSharp-Roslyn +[13], Gopls [14], jdt.ls [17], Jedi [12], rust-analyzer [16], and TSServer [15] engines, respectively. Check the installation section for instructions to enable these features if desired. @@ -1705,10 +1861,10 @@ be: \ 'filetypes': [ 'yaml' ] \ }, \ { - \ 'name': 'rust', - \ 'cmdline': [ 'ra_lsp_server' ], - \ 'filetypes': [ 'rust' ], - \ 'project_root_files': [ 'Cargo.toml' ] + \ 'name': 'csharp', + \ 'cmdline': [ 'OmniSharp', '-lsp' ], + \ 'filetypes': [ 'csharp' ], + \ 'project_root_files': [ '*.csproj', '*.sln' ] \ }, \ { \ 'name': 'godot', @@ -1718,32 +1874,12 @@ be: \ } \ ] < -Each dictionary contains the following keys: - -- 'name' (string, mandatory): When configuring a LSP server the value of the - 'name' key will be used as the "kwargs[ 'language' ]". Can be anything you - like. - -- 'filetypes' (list of string, mandatory): List of Vim filetypes this server - should be used for. - -- 'project_root_files' (list of string, optional): List of filenames to - search for when trying to determine the project root. - -- 'cmdline' (list of string, optional): If supplied, the server is started - with this command line (each list element is a command line word). - Typically, the server should be started with STDIO communication. If not - supplied, 'port' must be supplied. +Each dictionary contains the following keys: 'name', 'cmdline', 'port', +'filetypes', 'capabilities', 'project_root_files', 'additional_workspace_dirs', +'triggerCharacters', and 'settings'. The full description of each key can be +found in the ycmd [79] repository. -- 'port' (number, optional): If supplied, ycmd will connect to the server at - 'localhost:' using TCP (remote servers are not supported). - -- 'capabilities' (dict, optional): If supplied, this is a dictionary that is - merged with the LSP client capabilities reported to the language server. - This can be used to enable or disable certain features, such as the support - for configuration sections ('workspace/configuration'). - -See the LSP Examples [71] project for more examples of configuring the likes of +See the LSP Examples [80] project for more examples of configuring the likes of PHP, Ruby, Kotlin, and D. ------------------------------------------------------------------------------- @@ -1763,11 +1899,11 @@ examples of configuring the likes of PHP, Ruby, Kotlin, D, and many, many more. } < The 'ls' key tells YCM that the dictionary should be passed to the LSP server. -For each of the LSP server's configuration you should look up the respective +For each of the LSP server's configuration, you should look up the respective server's documentation. Some servers request settings from arbitrary 'sections' of configuration. There -is no concept of configuration sections in vim, so you can specify an +is no concept of configuration sections in Vim, so you can specify an additional 'config_sections' dictionary which maps section to a dictionary of config required by the server. For example: > @@ -1783,7 +1919,7 @@ config required by the server. For example: } } < -The sections and options/values are complete server-specific and rarely well +The sections and options/values are completely server-specific and rarely well documented. ------------------------------------------------------------------------------- @@ -1795,13 +1931,13 @@ semantic completions if it does not have a native semantic completion engine for your file's filetype. Vim comes with rudimentary omnifuncs for various languages like Ruby, PHP, etc. It depends on the language. -You can get a stellar omnifunc for Ruby with Eclim [72]. Just make sure you +You can get a stellar omnifunc for Ruby with Eclim [81]. Just make sure you have the _latest_ Eclim installed and configured (this means Eclim '>= 2.2.*' and Eclipse '>= 4.2.*'). After installing Eclim remember to create a new Eclipse project within your application by typing ':ProjectCreate -n ruby' inside -vim and don't forget to have "let g:EclimCompletionMethod = 'omnifunc'" in your +Vim and don't forget to have "let g:EclimCompletionMethod = 'omnifunc'" in your vimrc. This will make YCM and Eclim play nice; YCM will use Eclim's omnifuncs as the data source for semantic completions and provide the auto-triggering and subsequence-based matching (and other YCM features) on top of it. @@ -1812,7 +1948,7 @@ Writing New Semantic Completers ~ You have two options here: writing an 'omnifunc' for Vim's omnicomplete system that YCM will then use through its omni-completer, or a custom completer for -YCM using the Completer API [73]. +YCM using the Completer API [82]. Here are the differences between the two approaches: @@ -1831,7 +1967,7 @@ Here are the differences between the two approaches: than VimScript. If you want to use the 'omnifunc' system, see the relevant Vim docs with ':h -complete-functions'. For the Completer API, see the API docs [73]. +complete-functions'. For the Completer API, see the API docs [82]. If you want to upstream your completer into YCM's source, you should use the Completer API. @@ -1841,7 +1977,7 @@ Completer API. Diagnostic Display ~ YCM will display diagnostic notifications for the C-family, C#, Go, Java, -JavaScript, Rust and TypeScript languages. Since YCM continuously recompiles +JavaScript, Rust, and TypeScript languages. Since YCM continuously recompiles your file as you type, you'll get notified of errors and warnings in your file as fast as possible. @@ -1882,7 +2018,7 @@ current file in Vim's 'locationlist', which can be opened with the ':lopen' and ':lclose' commands (make sure you have set 'let g:ycm_always_populate_location_list = 1' in your vimrc). A good way to toggle the display of the 'locationlist' with a single key mapping is provided by -another (very small) Vim plugin called ListToggle [74] (which also makes it +another (very small) Vim plugin called ListToggle [83] (which also makes it possible to change the height of the 'locationlist' window), also written by yours truly. @@ -1905,6 +2041,10 @@ You can also style the line that has the warning/error with these groups: - 'YcmWarningLine', which falls back to group 'SyntasticWarningLine' if it exists +Finally, you can also style the popup for the detailed diagnostics (it is shown +if |g:ycm_show_detailed_diag_in_popup| is set) using the group 'YcmErrorPopup', +which falls back to 'ErrorMsg'. + Note that the line highlighting groups only work when the |g:ycm_enable_diagnostic_signs| option is set. If you want highlighted lines but no signs in the Vim gutter, set the 'signcolumn' option to 'no' in your @@ -1936,7 +2076,7 @@ supported. Here's a quick demo: - Image: asciicast [75] + Image: asciicast [84] As you can see, you can type and YCM filters down the list as you type. The current set of matches are displayed in a popup window in the centre of the @@ -1954,10 +2094,13 @@ e.g. - 'nmap yfd (YCMFindSymbolInDocument)' When searching, YCM opens a prompt buffer at the top of the screen for the -input, and puts you in insert mode. This means that you can hit '' to go +input and puts you in insert mode. This means that you can hit '' to go into normal mode and use any other input commands that are supported in prompt buffers. As you type characters, the search is updated. +Initially, results are queried from all open filetypes. You can hit '' to +switch to just the current filetype while the popup is open. + While the popup is open, the following keys are intercepted: - '', '', '', '' - select the next item @@ -1968,6 +2111,7 @@ While the popup is open, the following keys are intercepted: - '', '' - jump to last item - '' - jump to the selected item - '' cancel/dismiss the popup +- '' - toggle results from all file types or just the current filetype The search is also cancelled if you leave the prompt buffer window at any time, so you can use window commands '...' for example. @@ -1980,14 +2124,69 @@ Closing the popup ~ for that, or use a window command (e.g. 'j') or the mouse to leave the prompt buffer window. -=============================================================================== +------------------------------------------------------------------------------- + *youcompleteme-type-call-hierarchy* +Type/Call Hierarchy ~ + +**_This feature requires Vim and is not supported in Neovim_** + +**NOTE**: This feature is highly experimental and offered in the hope that it +is useful. Please help us by reporting issues and offering feedback. + +YCM provides a way to view and navigate hierarchies. The following hierarchies +are supported: + +- Type hierachy '(YCMTypeHierarchy)': Display subtypes and supertypes + of the symbol under cursor. Expand down to subtypes and up to supertypes. + +- Call hierarchy '(YCMCallHierarchy)': Display callees and callers of + the symbol under cursor. Expand down to callers and up to callees. + +Take a look at this Image: asciicast [86] for brief demo. + +Hierarchy UI can be initiated by mapping something to the indicated plug +mappings, for example: +> + nmap yth (YCMTypeHierarchy) + nmap ych (YCMCallHierarchy) +< +This opens a "modal" popup showing the current element in the hierarchy tree. +The current tree root is aligned to the left and child and parent nodes are +expanded to the right. Expand the tree "down" with '' and "up" with +''. + +The "root" of the tree can be re-focused to the selected item with '' +and further '' will show the parents of the selected item. This can take +a little getting used to, but it's particularly important with multiple +inheritance where a "child" of the current root may actually have other, +invisible, parent links. '' on that row will show these by setting the +display root to the selected item. + +When the hierarchy is displayed, the following keys are intercepted: + +- '': Drill into the hierarchy at the selected item: expand and show + children of the selected item. +- '': Show parents of the selected item. When applied to sub-types, + this will re-root the tree at that type, so that all parent types (are + displayed). Similar for callers. +- '': Jump to the symbol currently selected. +- '', '', '', 'j': Select the next item +- '', '', '', 'k'; Select the previous item +- Any other key: closes the popup without jumping to any location + +**Note:** you might think the call hierarchy tree is inverted, but we think +this way round is more intuitive because this is the typical way that call +stacks are displayed (with the current function at the top, and its callers +below). + +------------------------------------------------------------------------------- *youcompleteme-commands* Commands ~ ------------------------------------------------------------------------------- The *:YcmRestartServer* command -If the ycmd completion server [43] suddenly stops for some reason, you can +If the ycmd completion server [44] suddenly stops for some reason, you can restart it with this command. ------------------------------------------------------------------------------- @@ -2024,6 +2223,12 @@ The *:YcmShowDetailedDiagnostic* command This command shows the full diagnostic text when the user's cursor is on the line with the diagnostic. +An options argument can be passed. If the argument is 'popup' the diagnostic +text will be displayed in a popup at the cursor position. + +If you prefer the detailed diagnostic to always be shown in a popup, then 'let +g:ycm_show_detailed_diag_in_popup=1'. + ------------------------------------------------------------------------------- The *:YcmDebugInfo* command @@ -2035,7 +2240,7 @@ semantic completion engine. The *:YcmToggleLogs* command This command presents the list of logfiles created by YCM, the ycmd server -[43], and the semantic engine server for the current filetype, if any. One of +[44], and the semantic engine server for the current filetype, if any. One of these logfiles can be opened in the editor (or closed if already open) by entering the corresponding number or by clicking on it with the mouse. Additionally, this command can take the logfile names as arguments. Use the @@ -2048,7 +2253,7 @@ already open) in the editor. Only for debugging purposes. The *:YcmCompleter* command This command gives access to a number of additional IDE-like features in YCM, -for things like semantic GoTo, type information, FixIt and refactoring. +for things like semantic GoTo, type information, FixIt, and refactoring. This command accepts a range that can either be specified through a selection in one of Vim's visual modes (see ':h visual-use') or on the command line. For @@ -2062,7 +2267,12 @@ See the file type feature summary for an overview of the features available for each file type. See the _YcmCompleter subcommands_ section for more information on the available subcommands and their usage. -=============================================================================== +Some commands, like |Format| accept a range, like ':%YcmCompleter Format'. + +Some commands like |GetDoc| and the various |GoTo| commands respect modifiers, +like ':rightbelow YcmCompleter GetDoc', ':vertical YcmCompleter GoTo'. + +------------------------------------------------------------------------------- *youcompleteme-ycmcompleter-subcommands* YcmCompleter Subcommands ~ @@ -2088,8 +2298,8 @@ the cursor, the subcommands add entries to Vim's 'jumplist' so you can use 'CTRL-O' to jump back to where you were before invoking the command (and 'CTRL-I' to jump forward; see ':h jumplist' for details). If there is more than one destination, the quickfix list (see ':h quickfix') is populated with the -available locations and opened to full width at the bottom of the screen. You -can change this behavior by using the |YcmQuickFixOpened| autocommand. +available locations and opened to the full width at the bottom of the screen. +You can change this behavior by using the |YcmQuickFixOpened| autocommand. ------------------------------------------------------------------------------- The *GoToInclude* subcommand @@ -2098,6 +2308,14 @@ Looks up the current line for a header and jumps to it. Supported in filetypes: 'c, cpp, objc, objcpp, cuda' +------------------------------------------------------------------------------- +The *GoToAlternateFile* subcommand + +Jump to the associated file, as defined by the language server. Typically this +will jump you to the associated header file for a C or C++ translation unit. + +Supported in filetypes: 'c, cpp, objc, objcpp, cuda' (clangd only) + ------------------------------------------------------------------------------- The *GoToDeclaration* subcommand @@ -2139,7 +2357,7 @@ WARNING: This command trades correctness for speed! Same as the |GoTo| command except that it doesn't recompile the file with libclang before looking up nodes in the AST. This can be very useful when -you're editing files that take long to compile but you know that you haven't +you're editing files that take time to compile but you know that you haven't made any changes since the last parse that would lead to incorrect jumps. When you're just browsing around your codebase, this command can spare you quite a bit of latency. @@ -2196,19 +2414,22 @@ Supported in filetypes: 'go, java, javascript, typescript' ------------------------------------------------------------------------------- The *GoToDocumentOutline* subcommand -Provides a list of symbols in current document, in the quickfix list. See also -interactive symbol search. +Provides a list of symbols in the current document, in the quickfix list. See +also interactive symbol search. Supported in filetypes: 'c, cpp, objc, objcpp, cuda, go, java, rust' ------------------------------------------------------------------------------- The *GoToCallers* and 'GoToCallees' subcommands +Note: A much more powerful call and type hierarchy can be viewd interactively. +See interactive type and call hierarchy. + Populate the quickfix list with the callers, or callees respectively, of the function associated with the current cursor position. The semantics of this differ depending on the filetype and language server. -Only supported for LSP servers which provide the 'callHierarchyProvider' +Only supported for LSP servers that provide the 'callHierarchyProvider' capability. ------------------------------------------------------------------------------- @@ -2216,7 +2437,7 @@ capability. Semantic Information Commands ~ These commands are useful for finding static information about the code, such -as the types of variables, viewing declarations and documentation strings. +as the types of variables, viewing declarations, and documentation strings. ------------------------------------------------------------------------------- The *GetType* subcommand @@ -2242,7 +2463,7 @@ WARNING: This command trades correctness for speed! Same as the |GetType| command except that it doesn't recompile the file with libclang before looking up nodes in the AST. This can be very useful when -you're editing files that take long to compile but you know that you haven't +you're editing files that take time to compile but you know that you haven't made any changes since the last parse that would lead to incorrect type. When you're just browsing around your codebase, this command can spare you quite a bit of latency. @@ -2290,6 +2511,25 @@ under the cursor. Depending on the file type, this includes things like: - Python docstrings, - etc. +The documentation is opened in the preview window, and options like +'previewheight' are respected. If you would like to customise the height and +position of this window, we suggest a custom command that: + +- Sets 'previewheight' temporarily +- Runs the |GetDoc| command with supplied modifiers +- Restores 'previewheight'. + +For example: +> + command -count ShowDocWithSize + \ let g:ph=&previewheight + \ set previewheight= + \ YcmCompleter GetDoc + \ let &previewheight=g:ph +< +You can then use something like ':botright vertical 80ShowDocWithSize'. Here's +an example of that: https://asciinema.org/a/hE6Pi1gU6omBShwFna8iwGEe9 + Supported in filetypes: 'c, cpp, objc, objcpp, cuda, cs, go, java, javascript, python, typescript, rust' @@ -2318,27 +2558,40 @@ undone, and never saves or writes files to the disk. ------------------------------------------------------------------------------- The *FixIt* subcommand -Where available, attempts to make changes to the buffer to correct diagnostics -on the current line. Where multiple suggestions are available (such as when -there are multiple ways to resolve a given warning, or where multiple -diagnostics are reported for the current line), the options are presented and +Where available, attempts to make changes to the buffer to correct diagnostics, +or perform refactoring, on the current line or selection. Where multiple +suggestions are available (such as when there are multiple ways to resolve a +given warning, or where multiple diagnostics are reported for the current line, +or multiple refactoring tweaks are available), the options are presented and one can be selected. -Completers which provide diagnostics may also provide trivial modifications to +Completers that provide diagnostics may also provide trivial modifications to the source in order to correct the diagnostic. Examples include syntax errors such as missing trailing semi-colons, spurious characters, or other errors -which the semantic engine can deterministically suggest corrections. +which the semantic engine can deterministically suggest corrections. A small +demo presenting how diagnostics can be fixed with clangd: + + Image: YcmCompleter-FixIt-OnDiagnostic (see reference [88]) + +Completers (LSPs) may also provide refactoring tweaks, which may be available +even when no diagnostic is presented for the current line. These include +function extraction, variable extraction, 'switch' population, constructor +generation, ... The tweaks work for a selection as well. Consult your LSP for +available refactorings. A demonstration of refactoring capabilities with +clangd: + + Image: YouCompleter-FixIt-Refactoring (see reference [89]) If no fix-it is available for the current line, or there is no diagnostic on the current line, this command has no effect on the current buffer. If any modifications are made, the number of changes made to the buffer is echo'd and the user may use the editor's undo command to revert. -When a diagnostic is available, and |g:ycm_echo_current_diagnostic| is set to -1, then the text '(FixIt)' is appended to the echo'd diagnostic when the -completer is able to add this indication. The text '(FixIt available)' is also -appended to the diagnostic text in the output of the |:YcmDiags| command for -any diagnostics with available fix-its (where the completer can provide this +When a diagnostic is available, and |g:ycm_echo_current_diagnostic| is enabled, +then the text '(FixIt)' is appended to the echo'd diagnostic when the completer +is able to add this indication. The text '(FixIt available)' is also appended +to the diagnostic text in the output of the |:YcmDiags| command for any +diagnostics with available fix-its (where the completer can provide this indication). **NOTE:** Causes re-parsing of the current translation unit. @@ -2352,7 +2605,7 @@ The 'RefactorRename ' subcommand ~ In supported file types, this command attempts to perform a semantic rename of the identifier under the cursor. This includes renaming declarations, -definitions and usages of the identifier, or any other language-appropriate +definitions, and usages of the identifier, or any other language-appropriate action. The specific behavior is defined by the semantic engine in use. Similar to |FixIt|, this command applies automatic modifications to your source @@ -2363,6 +2616,20 @@ for you. The behavior is described in the following section. Supported in filetypes: 'c, cpp, objc, objcpp, cuda, java, javascript, python, typescript, rust, cs' +------------------------------------------------------------------------------- + *youcompleteme-python-refactorings* +Python refactorings ~ + +The following additional commands are supported for Python: + +- 'RefactorInline' +- 'RefactorExtractVariable' +- 'RefactorExtractFunction' + +See the jedi docs [90] for what they do. + +Supported in filetypes: 'python' + ------------------------------------------------------------------------------- *youcompleteme-multi-file-refactor* Multi-file Refactor ~ @@ -2388,7 +2655,7 @@ can be undone using Vim's powerful undo features (see ':help undo'). Note that Vim's undo is per-buffer, so to undo all changes, the undo commands must be applied in each modified buffer separately. -**NOTE:** While applying modifications, Vim may find files which are already +**NOTE:** While applying modifications, Vim may find files that are already open and have a swap file. The command is aborted if you select Abort or Quit in any such prompts. This leaves the Refactor operation partially complete and must be manually corrected using Vim's undo features. The quickfix list is @@ -2412,7 +2679,7 @@ typescript, rust, cs' The *OrganizeImports* subcommand This command removes unused imports and sorts imports in the current file. It -can also group imports from the same module in TypeScript and resolves imports +can also group imports from the same module in TypeScript and resolve imports in Java. Supported in filetypes: 'java, javascript, typescript' @@ -2429,12 +2696,12 @@ flags. *ExecuteCommand-args* The 'ExecuteCommand ' subcommand ~ -Some LSP completers (currently only Java completers) support executing server -specific commands. Consult the jdt.ls [16] documentation to find out what -commands are supported and which arguments are expected. +Some LSP completers (currently only Java completers) support executing +server-specific commands. Consult the jdt.ls [17] documentation to find out +what commands are supported and which arguments are expected. The support for 'ExecuteCommand' was implemented to support plugins like -Vimspector [77] to debug java, but isn't limited to that specific use case. +Vimspector [91] to debug java, but isn't limited to that specific use case. ------------------------------------------------------------------------------- The *RestartServer* subcommand @@ -2449,13 +2716,13 @@ rust, typescript' The *ReloadSolution* subcommand Instruct the Omnisharp-Roslyn server to clear its cache and reload all files -from disk. This is useful when files are added, removed, or renamed in the +from the disk. This is useful when files are added, removed, or renamed in the solution, files are changed outside of Vim, or whenever Omnisharp-Roslyn cache is out-of-sync. Supported in filetypes: 'cs' -=============================================================================== +------------------------------------------------------------------------------- *youcompleteme-functions* Functions ~ @@ -2470,7 +2737,7 @@ For example: call youcompleteme#GetErrorCount() < Both this function and |youcompleteme#GetWarningCount| can be useful when -integrating YCM with other Vim plugins. For example, a lightline [78] user +integrating YCM with other Vim plugins. For example, a lightline [92] user could add a diagnostics section to their statusline which would display the number of errors and warnings. @@ -2489,7 +2756,7 @@ For example: The 'youcompleteme#GetCommandResponse( ... )' function ~ Run a completer subcommand and return the result as a string. This can be -useful for example to display the 'GetGoc' output in a popup window, e.g.: +useful for example to display the |GetDoc| output in a popup window, e.g.: > let s:ycm_hover_popup = -1 function s:Hover() @@ -2564,10 +2831,10 @@ Again, see |g:ycm_auto_hover| for proper hover support. called this function. **NOTE**: Only one command request can be outstanding at once. Attempting to -request a second responses while the first is outstanding will result in the +request a second response while the first is outstanding will result in the second callback being immediately called with "''". -=============================================================================== +------------------------------------------------------------------------------- *youcompleteme-autocommands* Autocommands ~ @@ -2586,7 +2853,7 @@ For instance: wincmd K " Set the window height to 5. 5wincmd _ - " Switch back to working window. + " Switch back to the working window. wincmd p endfunction @@ -2611,18 +2878,17 @@ quickfix window. For instance: autocmd User YcmQuickFixOpened call s:CustomizeYcmQuickFixWindow() < -=============================================================================== - *youcompleteme-options* +------------------------------------------------------------------------------- Options ~ All options have reasonable defaults so if the plug-in works after installation you don't need to change any options. These options can be configured in your -vimrc script [36] by including a line like this: +vimrc script [37] by including a line like this: > let g:ycm_min_num_of_chars_for_completion = 1 < -Note that after changing an option in your vimrc script [36] you have to -restart ycmd [43] with the |:YcmRestartServer| command for the changes to take +Note that after changing an option in your vimrc script [37] you have to +restart ycmd [44] with the |:YcmRestartServer| command for the changes to take effect. ------------------------------------------------------------------------------- @@ -2668,7 +2934,7 @@ the number of suggestions from the identifier-based engine. A special value of '0' means there is no limit. **NOTE:** Setting this option to '0' or to a value greater than '100' is not -recommended as it will slow down completion when there are a very large number +recommended as it will slow down completion when there is a very large number of suggestions. Default: '50' @@ -2679,7 +2945,7 @@ Default: '50' The *g:ycm_max_num_candidates_to_detail* option Some completion engines require completion candidates to be 'resolved' in order -to get detailed info such as inline documentation, method signatures etc. This +to get detailed info such as inline documentation, method signatures, etc. This information is displayed by YCM in the preview window, or if 'completeopt' contains 'popup', in the info popup next to the completion menu. @@ -2696,12 +2962,12 @@ need to change this, as YCM will work out an appropriate value based on your 'completeopt' and |g:ycm_add_preview_to_completeopt| settings. However, you may override this calculation by setting this value to a number: -- '-1' - Resolve all candidates up front -- '0' - Never resolve any candidates up front. -- '> 0' - Resolve up to this many candidates up front. If the number of +- '-1' - Resolve all candidates upfront +- '0' - Never resolve any candidates upfront. +- '> 0' - Resolve up to this many candidates upfront. If the number of candidates is greater than this value, no candidates are resolved. -In the later two cases, if 'completeopt' contains 'popup', then candidates are +In the latter two cases, if 'completeopt' contains 'popup', then candidates are resolved on demand asynchronously. Default: @@ -2723,7 +2989,7 @@ identifier-based engine shown in the completion menu. A special value of '0' means there is no limit. **NOTE:** Setting this option to '0' or to a value greater than '100' is not -recommended as it will slow down completion when there are a very large number +recommended as it will slow down completion when there is a very large number of suggestions. Default: '10' @@ -2742,6 +3008,19 @@ If you want to just turn off the identifier completer but keep the semantic triggers, you should set |g:ycm_min_num_of_chars_for_completion| to a high number like '99'. +When |g:ycm_auto_trigger| is '0', YCM sets the 'completefunc', so that you can +manually trigger normal completion using 'C-x C-u'. + +If you want to map something else to trigger completion, such as 'C-d', then +you can map it to '(YCMComplete)'. For example: +> + let g:ycm_auto_trigger = 0 + imap (YCMComplete) +< +NOTE: It's not possible to map one of the keys in +|g:ycm_key_list_select_completion| (or similar) to '(YCMComplete)'. In +practice that means that you can't use '' for this. + Default: '1' > let g:ycm_auto_trigger = 1 @@ -2767,9 +3046,9 @@ filetype. The filetype should then be present in the whitelist either directly ('cpp' key in the whitelist) or indirectly through the special '*' key. It should _not_ be present in the blacklist. -Filetypes that are blocked by the either of the lists will be completely -ignored by YCM, meaning that neither the identifier-based completion engine nor -the semantic engine will operate in them. +Filetypes that are blocked by either of the lists will be completely ignored by +YCM, meaning that neither the identifier-based completion engine nor the +semantic engine will operate in them. You can get the filetype of the current file in Vim with ':set ft?'. @@ -2777,7 +3056,7 @@ Default: "{'*': 1}" > let g:ycm_filetype_whitelist = {'*': 1} < -**Completion in buffers with no filetype** +** Completion in buffers with no filetype ** There is one exception to the above rule. YCM supports completion in buffers with no filetype set, but this must be _explicitly_ whitelisted. To identify @@ -2873,7 +3152,7 @@ When set, this option turns on YCM's diagnostic display features. See the _Diagnostic display_ section in the _User Manual_ for more details. Specific parts of the diagnostics UI (like the gutter signs, text highlighting, -diagnostic echo and auto location list population) can be individually turned +diagnostic echo, and auto location list population) can be individually turned on or off. See the other options below for details. Note that YCM's diagnostics UI is only supported for C-family languages. @@ -2950,17 +3229,40 @@ Default: '1' ------------------------------------------------------------------------------- The *g:ycm_echo_current_diagnostic* option -When this option is set, YCM will echo the text of the diagnostic present on -the current line when you move your cursor to that line. If a |FixIt| is +When this option is set to 1, YCM will echo the text of the diagnostic present +on the current line when you move your cursor to that line. If a |FixIt| is available for the current diagnostic, then '(FixIt)' is appended. +If you have a Vim that supports virtual text, you can set this option to the +string 'virtual-text', and the diagnostic will be displayed inline with the +text, right aligned in the window and wrapping to the next line if there is not +enough space, for example: + + Image: Virtual text diagnostic demo (see reference [93]) + + Image: Virtual text diagnostic demo (see reference [94]) + +**NOTE**: It's _strongly_ recommended to also set +|g:ycm_update_diagnostics_in_insert_mode| to '0' when using 'virtual-text' for +diagnostics. This is due to the increased amount of distraction provided by +drawing diagnostics next to your input position. + This option is part of the Syntastic compatibility layer; if the option is not set, YCM will fall back to the value of the 'g:syntastic_echo_current_error' option before using this option's default. Default: '1' + +Valid values: + +- '0' - disabled +- '1' - echo diagnostic to the command area +- "'virtual-text'" - display the dignostic to the right of the line in the + window using virtual text > let g:ycm_echo_current_diagnostic = 1 + " Or, when you have Vim supporting virtual text + let g:ycm_echo_current_diagnostic = 'virtual-text' < ------------------------------------------------------------------------------- The *g:ycm_auto_hover* option @@ -2995,6 +3297,7 @@ This buffer-local variable can be set to a dictionary with the following keys: - 'command': The YCM completer subcommand which should be run on hover - 'syntax': The syntax to use (as in 'set syntax=') in the popup window for highlighting. +- 'popup_params': The params passed to a popup window which gets opened. For example, to use C/C++ syntax highlighting in the popup for C-family languages, add something like this to your vimrc: @@ -3007,6 +3310,27 @@ languages, add something like this to your vimrc: \ } augroup END < +You can also modify the opened popup with 'popup_params' key. For example, you +can limit the popup's maximum width and add a border to it: + + +> + augroup MyYCMCustom + autocmd! + autocmd FileType c,cpp let b:ycm_hover = { + \ 'command': 'GetDoc', + \ 'syntax': &filetype + \ 'popup_params': { + \ 'maxwidth': 80, + \ 'border': [], + \ 'borderchars': ['─', '│', '─', '│', '┌', '┐', '┘', '└'], + \ }, + \ } + augroup END +< +See ':help popup_create-arguments' for the list of available popup window +options. + Default: "'CursorHold'" ------------------------------------------------------------------------------- @@ -3024,7 +3348,7 @@ YCM will not render it. The following filter types are supported: -- "regex": Accepts a string regular expression [79]. This type matches when +- "regex": Accepts a string regular expression [95]. This type matches when the regex (treated as case-insensitive) is found anywhere in the diagnostic text ('re.search', not 're.match') @@ -3032,11 +3356,11 @@ The following filter types are supported: matches when the diagnostic has the same level, that is, specifying 'level: "error"' will remove **all** errors from the diagnostics. -**NOTE:** The regex syntax is **NOT** Vim's, it's Python's [79]. +**NOTE:** The regex syntax is **NOT** Vim's, it's Python's [95]. Default: '{}' -The following example will do, for java filetype only: - Remove **all** error +The following example will do, for Java filetype only: - Remove **all** error level diagnostics, and, - Also remove anything that contains 'taco' > let g:ycm_filter_diagnostics = { @@ -3127,7 +3451,7 @@ from the 'tagfiles()' Vim function which examines the 'tags' Vim option. See YCM will re-index your tags files if it detects that they have been modified. -The only supported tag format is the Exuberant Ctags format [80]. The format +The only supported tag format is the Exuberant Ctags format [96]. The format from "plain" ctags is NOT supported. Ctags needs to be called with the '--fields=+l' option (that's a lowercase 'L', not a one) because YCM needs the 'language:' field in the tags output. @@ -3164,7 +3488,7 @@ handy; it's a way of sending data from Vim to your 'Settings' function in your '.ycm_extra_conf.py' file. This option is supposed to be a list of VimScript expression strings that are -evaluated for every request to the ycmd server [43] and then passed to your +evaluated for every request to the ycmd server [44] and then passed to your 'Settings' function as a 'client_data' keyword argument. For instance, if you set this option to "['v:version']", your 'Settings' @@ -3193,7 +3517,7 @@ YCM will by default search for an appropriate Python interpreter on your system. You can use this option to override that behavior and force the use of a specific interpreter of your choosing. -**NOTE:** This interpreter is only used for the ycmd server [43]. The YCM +**NOTE:** This interpreter is only used for the ycmd server [44]. The YCM client running inside Vim always uses the Python interpreter that's embedded inside Vim. @@ -3204,11 +3528,11 @@ Default: "''" ------------------------------------------------------------------------------- The *g:ycm_keep_logfiles* option -When this option is set to '1', YCM and the ycmd completion server [43] will +When this option is set to '1', YCM and the ycmd completion server [44] will keep the logfiles around after shutting down (they are deleted on shutdown by default). -To see where the logfiles are, call |:YcmDebugInfo|. +To see where the log files are, call |:YcmDebugInfo|. Default: '0' > @@ -3217,7 +3541,7 @@ Default: '0' ------------------------------------------------------------------------------- The *g:ycm_log_level* option -The logging level that YCM and the ycmd completion server [43] use. Valid +The logging level that YCM and the ycmd completion server [44] use. Valid values are the following, from most verbose to least verbose: - 'debug' - 'info' - 'warning' - 'error' - 'critical' @@ -3358,7 +3682,7 @@ Default: "['', '']" The *g:ycm_key_list_previous_completion* option This option controls the key mappings used to select the previous completion -string. Invoking any of them repeatedly cycles backwards through the completion +string. Invoking any of them repeatedly cycles backward through the completion list. Note that one of the defaults is '' which means Shift-TAB. That mapping @@ -3375,7 +3699,7 @@ The *g:ycm_key_list_stop_completion* option This option controls the key mappings used to close the completion menu. This is useful when the menu is blocking the view, when you need to insert the -'' character, or when you want to expand a snippet from UltiSnips [24] and +'' character, or when you want to expand a snippet from UltiSnips [25] and navigate through it. Default: "['']" @@ -3387,14 +3711,15 @@ The *g:ycm_key_invoke_completion* option This option controls the key mapping used to invoke the completion menu for semantic completion. By default, semantic completion is triggered automatically -after typing '.', '->' and '::' in insert mode (if semantic completion support -has been compiled in). This key mapping can be used to trigger semantic -completion anywhere. Useful for searching for top-level functions and classes. +after typing characters appropriate for the language, such as '.', '->', '::', +etc. in insert mode (if semantic completion support has been compiled in). This +key mapping can be used to trigger semantic completion anywhere. Useful for +searching for top-level functions and classes. Console Vim (not Gvim or MacVim) passes '' to Vim when the user types '' so YCM will make sure that '' is used in the map command when you're editing in console Vim, and '' in GUI Vim. This means that you -can just press '' in both console and GUI Vim and YCM will do the +can just press '' in both the console and GUI Vim and YCM will do the right thing. Setting this option to an empty string will make sure no mapping is created. @@ -3412,11 +3737,24 @@ the user's cursor is on the line with the diagnostic. It basically calls Setting this option to an empty string will make sure no mapping is created. +If you prefer the detailed diagnostic to be shown in a popup, then 'let +g:ycm_show_detailed_diag_in_popup=1'. + Default: 'd' > let g:ycm_key_detailed_diagnostics = 'd' < ------------------------------------------------------------------------------- +The *g:ycm_show_detailed_diag_in_popup* option + +Makes |:YcmShowDetailedDiagnostic| always show in a popup rather than echoing +to the command line. + +Default: 0 +> + let g:ycm_show_detailed_diag_in_popup = 0 +< +------------------------------------------------------------------------------- The *g:ycm_global_ycm_extra_conf* option Normally, YCM searches for a '.ycm_extra_conf.py' file for compilation flags @@ -3434,8 +3772,8 @@ Default: "''" The *g:ycm_confirm_extra_conf* option When this option is set to '1' YCM will ask once per '.ycm_extra_conf.py' file -if it is safe to be loaded. This is to prevent execution of malicious code from -a '.ycm_extra_conf.py' file you didn't write. +if it is safe to be loaded. This is to prevent the execution of malicious code +from a '.ycm_extra_conf.py' file you didn't write. To selectively get YCM to ask/not ask about loading certain '.ycm_extra_conf.py' files, see the |g:ycm_extra_conf_globlist| option. @@ -3517,7 +3855,7 @@ It's also possible to use a regular expression as a trigger. You have to prefix your trigger with 're!' to signify it's a regex trigger. For instance, 're!\w+\.' would only trigger after the '\w+\.' regex matches. -**NOTE:** The regex syntax is **NOT** Vim's, it's Python's [79]. +**NOTE:** The regex syntax is **NOT** Vim's, it's Python's [95]. Default: '[see next line]' > @@ -3541,8 +3879,8 @@ The *g:ycm_cache_omnifunc* option Some omnicompletion engines do not work well with the YCM cache—in particular, they might not produce all possible results for a given prefix. By unsetting this option you can ensure that the omnicompletion engine is re-queried on -every keypress. That will ensure all completions will be presented, but might -cause stuttering and lagginess if the omnifunc is slow. +every keypress. That will ensure all completions will be presented but might +cause stuttering and lag if the omnifunc is slow. Default: '1' > @@ -3601,8 +3939,8 @@ Default: 1000 ------------------------------------------------------------------------------- The *g:ycm_use_clangd* option -This option controls whether **clangd** should be used as completion engine for -C-family languages. Can take one of the following values: '1', '0', with +This option controls whether **clangd** should be used as a completion engine +for C-family languages. Can take one of the following values: '1', '0', with meanings: - '1': YCM will use clangd if clangd binary exists in third party or it was @@ -3657,7 +3995,7 @@ first making sure YCM won't choose that existing completer in the first place. A simple working example of this option can be found in the section called "Semantic Completion for Other Languages". -Many working examples can be found in the YCM lsp-examples [71] repo. +Many working examples can be found in the YCM lsp-examples [80] repository. Default: '[]' > @@ -3667,9 +4005,7 @@ Default: '[]' The *g:ycm_disable_signature_help* option This option allows you to disable all signature help for all completion -engines. There is no way to disable it per-completer. This option is -_reserved_, meaning that while signature help support remains experimental, its -values and meaning may change and it may be removed in a future version. +engines. There is no way to disable it per-completer. Default: '0' > @@ -3677,6 +4013,18 @@ Default: '0' let g:ycm_disable_signature_help = 1 < ------------------------------------------------------------------------------- +The *g:ycm_signature_help_disable_syntax* option + +Set this to 1 to disable syntax highlighting in the signature help popup. Thiis +can help if your colourscheme doesn't work well with the default highliting and +inverse video. + +Default: '0' +> + " Disable signature help syntax highliting + let g:ycm_signature_help_disable_syntax = 1 +< +------------------------------------------------------------------------------- The *g:ycm_gopls_binary_path* option In case the system-wide 'gopls' binary is newer than the bundled one, setting @@ -3728,32 +4076,40 @@ With async diagnostics, LSP servers might send new diagnostics mid-typing. If seeing these new diagnostics while typing is not desired, this option can be set to 0. +When this option is set to '0', diagnostic signs, virtual text, and highlights +are cleared when entering insert mode and replaced when leaving insert mode. +This reduces visual noise while editing. + +In addition, this option is recommended when |g:ycm_echo_current_diagnostic| is +set to 'virtual-text' as it prevents updating the virtual text while you are +typing. + Default: '1' > let g:ycm_update_diagnostics_in_insert_mode = 1 < -=============================================================================== +------------------------------------------------------------------------------- *youcompleteme-faq* FAQ ~ The FAQ section has been moved to the wiki [8]. -=============================================================================== +------------------------------------------------------------------------------- *youcompleteme-contributor-code-of-conduct* Contributor Code of Conduct ~ Please note that this project is released with a Contributor Code of Conduct -[81]. By participating in this project you agree to abide by its terms. +[97]. By participating in this project you agree to abide by its terms. -=============================================================================== +------------------------------------------------------------------------------- *youcompleteme-contact* Contact ~ If you have questions about the plugin or need help, please join the Gitter -room [1] or use the ycm-users [82] mailing list. +room [1] or use the ycm-users [98] mailing list. If you have bug reports or feature suggestions, please use the issue tracker -[83]. Before you do, please carefully read CONTRIBUTING.md [84] as this asks +[99]. Before you do, please carefully read CONTRIBUTING.md [100] as this asks for important diagnostics which the team will use to help get you going. The latest version of the plugin is available at @@ -3761,33 +4117,33 @@ https://ycm-core.github.io/YouCompleteMe/. The author's homepage is https://val.markovic.io. -Please do **NOT** go to #vim on freenode for support. Please contact the -YouCompleteMe maintainers directly using the contact details. +Please do **NOT** go to #vim, Reddit, or Stack Overflow for support. Please +contact the YouCompleteMe maintainers directly using the contact details. -=============================================================================== +------------------------------------------------------------------------------- *youcompleteme-license* License ~ -This software is licensed under the GPL v3 license [85]. © 2015-2018 +This software is licensed under the GPL v3 license [101]. © 2015-2018 YouCompleteMe contributors -=============================================================================== +------------------------------------------------------------------------------- *youcompleteme-sponsorship* Sponsorship ~ -If you like YCM so much that you're wiling to part with your hard-earned cash, +If you like YCM so much that you're willing to part with your hard-earned cash, please consider donating to one of the following charities, which are meaningful to the current maintainers (in no particular order): -- Greyhound Rescue Wales [86] -- Be Humane [87] -- Cancer Research UK [88] -- ICCF Holland [89] +- Hector's Greyhound Rescue [102] +- Be Humane [103] +- Cancer Research UK [104] +- ICCF Holland [105] - Any charity of your choosing. Please note: The YCM maintainers do not specifically endorse nor necessarily have any relationship with the above charities. Disclosure: It is noted that -one key maintainer is family with Trustees of Greyhound Rescue Wales. +one key maintainer is a family with Trustees of Greyhound Rescue Wales. =============================================================================== *youcompleteme-references* @@ -3801,86 +4157,102 @@ References ~ [6] https://img.shields.io/codecov/c/github/ycm-core/YouCompleteMe/master.svg [7] https://github.com/ycm-core/YouCompleteMe/wiki/Troubleshooting-steps-for-ycmd-server-SHUT-DOWN [8] https://github.com/ycm-core/YouCompleteMe/wiki/FAQ -[9] https://www.vim.org/ -[10] https://clang.llvm.org/extra/clangd.html -[11] https://github.com/davidhalter/jedi -[12] https://github.com/OmniSharp/omnisharp-roslyn -[13] https://github.com/golang/go/wiki/gopls -[14] https://github.com/Microsoft/TypeScript/tree/master/src/server -[15] https://rust-analyzer.github.io -[16] https://github.com/eclipse/eclipse.jdt.ls -[17] https://i.imgur.com/0OP4ood.gif -[18] https://en.wikipedia.org/wiki/Subsequence -[19] https://github.com/scrooloose/syntastic -[20] https://user-images.githubusercontent.com/10026824/34471853-af9cf32a-ef53-11e7-8229-de534058ddc4.gif -[21] https://user-images.githubusercontent.com/10584846/58738348-5060da80-83fd-11e9-9537-d07fdbf4554c.gif -[22] https://i.imgur.com/nmUUbdl.gif -[23] https://user-images.githubusercontent.com/10584846/80312146-91af6500-87db-11ea-996b-7396f3134d1f.gif -[24] https://github.com/SirVer/ultisnips/blob/master/doc/UltiSnips.txt -[25] https://github.com/VundleVim/Vundle.vim#about -[26] mono-install-macos -[27] https://macvim-dev.github.io/macvim/ -[28] https://brew.sh -[29] https://www.mono-project.com/download/stable/ -[30] https://golang.org/doc/install -[31] https://docs.npmjs.com/getting-started/installing-node#1-install-nodejs--npm -[32] https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html -[33] https://github.com/ycm-core/YouCompleteMe/wiki/Building-Vim-from-source -[34] https://www.mono-project.com/download/stable/#download-lin -[35] https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=16 -[36] https://vimhelp.appspot.com/starting.txt.html#vimrc -[37] https://github.com/vim/vim-win32-installer/releases -[38] https://www.python.org/downloads/windows/ -[39] https://cmake.org/download/ -[40] https://stackoverflow.com/questions/6319274/how-do-i-run-msbuild-from-the-command-line-using-windows-sdk-7-1 -[41] https://github.com/ycm-core/YouCompleteMe/wiki/Full-Installation-Guide -[42] https://www.unicode.org/glossary/#diacritic -[43] https://github.com/ycm-core/ycmd -[44] https://github.com/ycm-core/ycmd/pull/1255 -[45] https://github.com/ycm-core/YouCompleteMe/wiki/C-family-Semantic-Completion-through-libclang -[46] https://clang.llvm.org/docs/JSONCompilationDatabase.html -[47] https://ninja-build.org/manual.html -[48] https://pypi.org/project/compiledb/ -[49] https://github.com/rizsotto/Bear -[50] https://raw.githubusercontent.com/ycm-core/ycmd/66030cd94299114ae316796f3cad181cac8a007c/.ycm_extra_conf.py -[51] https://github.com/rdnetto/YCM-Generator -[52] https://github.com/eclipse/eclipse.jdt.ls/blob/master/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java -[53] https://help.eclipse.org/oxygen/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fmisc%2Fproject_description_file.html -[54] https://maven.apache.org/guides/getting-started/maven-in-five-minutes.html -[55] https://docs.gradle.org/current/userguide/tutorial_java_projects.html -[56] https://help.eclipse.org/mars/index.jsp?topic=%2Forg.eclipse.jdt.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fjdt%2Fcore%2FIClasspathEntry.html -[57] https://github.com/ycm-core/ycmd/tree/3602f38ef7a762fc765afd75e562aec9a134711e/ycmd/tests/java/testdata/simple_eclipse_project -[58] https://github.com/ycm-core/ycmd/blob/3602f38ef7a762fc765afd75e562aec9a134711e/ycmd/tests/java/testdata/simple_maven_project/pom.xml -[59] https://github.com/ycm-core/ycmd/tree/3602f38ef7a762fc765afd75e562aec9a134711e/ycmd/tests/java/testdata/simple_gradle_project -[60] https://github.com/ycm-core/lsp-examples#kotlin -[61] https://github.com/ycm-core/YouCompleteMe/blob/master/.ycm_extra_conf.py -[62] https://github.com/rust-lang/rls -[63] https://www.rust-lang.org/downloads.html -[64] https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/rust-analyzer/src/config.rs -[65] https://github.com/golang/tools/blob/master/internal/lsp/server.go -[66] https://ternjs.net -[67] https://github.com/ycm-core/YouCompleteMe/wiki/JavaScript-Semantic-Completion-through-Tern -[68] https://code.visualstudio.com/docs/languages/jsconfig -[69] https://www.typescriptlang.org/docs/handbook/tsconfig-json.html -[70] https://clang.llvm.org/ -[71] https://github.com/ycm-core/lsp-examples -[72] http://eclim.org/ -[73] https://github.com/ycm-core/ycmd/blob/master/ycmd/completers/completer.py -[74] https://github.com/Valloric/ListToggle -[75] https://asciinema.org/a/4JmYLAaz5hOHbZDD0hbsQpY8C -[76] https://asciinema.org/a/4JmYLAaz5hOHbZDD0hbsQpY8C.svg -[77] https://github.com/puremourning/vimspector -[78] https://github.com/itchyny/lightline.vim -[79] https://docs.python.org/2/library/re.html#regular-expression-syntax -[80] http://ctags.sourceforge.net/FORMAT -[81] https://github.com/ycm-core/YouCompleteMe/blob/master/CODE_OF_CONDUCT.md -[82] https://groups.google.com/forum/?hl=en#!forum/ycm-users -[83] https://github.com/ycm-core/YouCompleteMe/issues?state=open -[84] https://github.com/ycm-core/YouCompleteMe/blob/master/CONTRIBUTING.md -[85] https://www.gnu.org/copyleft/gpl.html -[86] https://greyhoundrescuewales.co.uk -[87] https://www.budihuman.rs/en -[88] https://www.cancerresearchuk.org -[89] https://iccf.nl +[9] https://github.com/ycm-core/YouCompleteMe/issues/4134#issuecomment-1446235584 +[10] https://www.vim.org/ +[11] https://clang.llvm.org/extra/clangd.html +[12] https://github.com/davidhalter/jedi +[13] https://github.com/OmniSharp/omnisharp-roslyn +[14] https://github.com/golang/go/wiki/gopls +[15] https://github.com/Microsoft/TypeScript/tree/master/src/server +[16] https://rust-analyzer.github.io +[17] https://github.com/eclipse/eclipse.jdt.ls +[18] https://i.imgur.com/0OP4ood.gif +[19] https://en.wikipedia.org/wiki/Subsequence +[20] https://github.com/scrooloose/syntastic +[21] https://user-images.githubusercontent.com/10026824/34471853-af9cf32a-ef53-11e7-8229-de534058ddc4.gif +[22] https://user-images.githubusercontent.com/10584846/58738348-5060da80-83fd-11e9-9537-d07fdbf4554c.gif +[23] https://i.imgur.com/nmUUbdl.gif +[24] https://user-images.githubusercontent.com/10584846/80312146-91af6500-87db-11ea-996b-7396f3134d1f.gif +[25] https://github.com/SirVer/ultisnips/blob/master/doc/UltiSnips.txt +[26] https://github.com/VundleVim/Vundle.vim#about +[27] mono-install-macos +[28] https://macvim-dev.github.io/macvim/ +[29] https://brew.sh +[30] https://www.mono-project.com/download/stable/ +[31] https://golang.org/doc/install +[32] https://docs.npmjs.com/getting-started/installing-node#1-install-nodejs--npm +[33] https://adoptium.net/en-GB/temurin/releases +[34] https://github.com/ycm-core/YouCompleteMe/wiki/Building-Vim-from-source +[35] https://www.mono-project.com/download/stable/#download-lin +[36] https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=16 +[37] https://vimhelp.appspot.com/starting.txt.html#vimrc +[38] https://github.com/vim/vim-win32-installer/releases +[39] https://www.python.org/downloads/windows/ +[40] https://cmake.org/download/ +[41] https://stackoverflow.com/questions/6319274/how-do-i-run-msbuild-from-the-command-line-using-windows-sdk-7-1 +[42] https://github.com/ycm-core/YouCompleteMe/wiki/Full-Installation-Guide +[43] https://www.unicode.org/glossary/#diacritic +[44] https://github.com/ycm-core/ycmd +[45] https://github.com/ycm-core/ycmd/pull/1255 +[46] https://user-images.githubusercontent.com/10584846/173137003-a265e8b0-84db-4993-98f0-03ee81b9de94.png +[47] https://user-images.githubusercontent.com/10584846/173137012-7547de0b-145f-45fa-ace3-18943acd2141.png +[48] https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_semanticTokens +[49] https://user-images.githubusercontent.com/10584846/185708054-68074fc0-e50c-4a65-887c-da6f372b8982.png +[50] https://user-images.githubusercontent.com/10584846/185708156-b52970ce-005f-4f0b-97e7-bdf8feeefedc.png +[51] https://user-images.githubusercontent.com/10584846/185708242-e42dab6f-1847-46f1-8585-2d9f2c8a76dc.png +[52] https://github.com/ycm-core/YouCompleteMe/wiki/C-family-Semantic-Completion-through-libclang +[53] https://clang.llvm.org/docs/JSONCompilationDatabase.html +[54] https://ninja-build.org/manual.html +[55] https://pypi.org/project/compiledb/ +[56] https://github.com/rizsotto/Bear +[57] https://raw.githubusercontent.com/ycm-core/ycmd/66030cd94299114ae316796f3cad181cac8a007c/.ycm_extra_conf.py +[58] https://github.com/rdnetto/YCM-Generator +[59] https://github.com/eclipse/eclipse.jdt.ls/blob/master/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java +[60] https://help.eclipse.org/oxygen/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fmisc%2Fproject_description_file.html +[61] https://maven.apache.org/guides/getting-started/maven-in-five-minutes.html +[62] https://docs.gradle.org/current/userguide/tutorial_java_projects.html +[63] https://help.eclipse.org/mars/index.jsp?topic=%2Forg.eclipse.jdt.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fjdt%2Fcore%2FIClasspathEntry.html +[64] https://github.com/ycm-core/ycmd/tree/3602f38ef7a762fc765afd75e562aec9a134711e/ycmd/tests/java/testdata/simple_eclipse_project +[65] https://github.com/ycm-core/ycmd/blob/3602f38ef7a762fc765afd75e562aec9a134711e/ycmd/tests/java/testdata/simple_maven_project/pom.xml +[66] https://github.com/ycm-core/ycmd/tree/3602f38ef7a762fc765afd75e562aec9a134711e/ycmd/tests/java/testdata/simple_gradle_project +[67] https://github.com/ycm-core/lsp-examples#kotlin +[68] https://github.com/OmniSharp/omnisharp-roslyn/releases/ +[69] https://github.com/ycm-core/YouCompleteMe/blob/master/.ycm_extra_conf.py +[70] https://github.com/rust-lang/rls +[71] https://www.rust-lang.org/downloads.html +[72] https://rust-analyzer.github.io/manual.html#configuration] +[73] https://github.com/golang/tools/blob/master/gopls/doc/settings.md +[74] https://ternjs.net +[75] https://github.com/ycm-core/YouCompleteMe/wiki/JavaScript-Semantic-Completion-through-Tern +[76] https://code.visualstudio.com/docs/languages/jsconfig +[77] https://www.typescriptlang.org/docs/handbook/tsconfig-json.html +[78] https://clang.llvm.org/ +[79] https://github.com/ycm-core/ycmd#language_server-configuration +[80] https://github.com/ycm-core/lsp-examples +[81] http://eclim.org/ +[82] https://github.com/ycm-core/ycmd/blob/master/ycmd/completers/completer.py +[83] https://github.com/Valloric/ListToggle +[84] https://asciinema.org/a/4JmYLAaz5hOHbZDD0hbsQpY8C +[85] https://asciinema.org/a/4JmYLAaz5hOHbZDD0hbsQpY8C.svg +[86] https://asciinema.org/a/659925 +[87] https://asciinema.org/a/659925.svg +[88] https://user-images.githubusercontent.com/17928698/206855014-9131a49b-87e8-4ed4-8d91-f2fe7808a0b9.gif +[89] https://user-images.githubusercontent.com/17928698/206855713-3588c8de-d0f5-4725-b65e-bc51110252cc.gif +[90] https://jedi.readthedocs.io/en/latest/docs/api.html#jedi.Script.extract_variable +[91] https://github.com/puremourning/vimspector +[92] https://github.com/itchyny/lightline.vim +[93] https://user-images.githubusercontent.com/10584846/185707973-39703699-0263-47d3-82ac-639d52259bea.png +[94] https://user-images.githubusercontent.com/10584846/185707993-14ff5fd7-c082-4e5a-b825-f1364e619b6a.png +[95] https://docs.python.org/2/library/re.html#regular-expression-syntax +[96] http://ctags.sourceforge.net/FORMAT +[97] https://github.com/ycm-core/YouCompleteMe/blob/master/CODE_OF_CONDUCT.md +[98] https://groups.google.com/forum/?hl=en#!forum/ycm-users +[99] https://github.com/ycm-core/YouCompleteMe/issues?state=open +[100] https://github.com/ycm-core/YouCompleteMe/blob/master/CONTRIBUTING.md +[101] https://www.gnu.org/copyleft/gpl.html +[102] https://www.hectorsgreyhoundrescue.org +[103] https://www.budihuman.rs/en +[104] https://www.cancerresearchuk.org +[105] https://iccf.nl vim: ft=help diff --git a/install.py b/install.py index cf27b2047d..2483460d39 100755 --- a/install.py +++ b/install.py @@ -12,8 +12,8 @@ import glob version = sys.version_info[ 0 : 3 ] -if version < ( 3, 6, 0 ): - sys.exit( 'YouCompleteMe requires Python >= 3.6.0; ' +if version < ( 3, 12, 0 ): + sys.exit( 'YouCompleteMe requires Python >= 3.12.0; ' 'your version of Python is ' + sys.version ) DIR_OF_THIS_SCRIPT = p.dirname( p.abspath( __file__ ) ) diff --git a/plugin/youcompleteme.vim b/plugin/youcompleteme.vim index c805e4e6d7..154e0a12f3 100644 --- a/plugin/youcompleteme.vim +++ b/plugin/youcompleteme.vim @@ -24,17 +24,17 @@ function! s:restore_cpo() unlet s:save_cpo endfunction -" NOTE: The minimum supported version is 8.1.2269, but neovim always reports as +" NOTE: The minimum supported version is 8.2.3995, but neovim always reports as " v:version 800, but will largely work. let s:is_neovim = has( 'nvim' ) if exists( "g:loaded_youcompleteme" ) call s:restore_cpo() finish -elseif ( v:version < 801 || (v:version == 801 && !has( 'patch2269' )) ) && +elseif ( v:version < 901 || (v:version == 901 && !has( 'patch0016' )) ) && \ !s:is_neovim echohl WarningMsg | - \ echomsg "YouCompleteMe unavailable: requires Vim 8.1.2269+." | + \ echomsg "YouCompleteMe unavailable: requires Vim 9.1.0016+." | \ echohl None call s:restore_cpo() finish @@ -48,7 +48,7 @@ elseif !has( 'timers' ) elseif !has( 'python3_compiled' ) echohl WarningMsg | \ echomsg "YouCompleteMe unavailable: requires Vim compiled with " . - \ "Python (3.6.0+) support." | + \ "Python (3.12.0+) support." | \ echohl None call s:restore_cpo() finish diff --git a/python/test_requirements.txt b/python/test_requirements.txt index 3a0bc1e34c..d5781eac81 100644 --- a/python/test_requirements.txt +++ b/python/test_requirements.txt @@ -2,7 +2,5 @@ flake8 >= 3.0.0 flake8-comprehensions >= 1.4.1 flake8-ycm >= 0.1.0 PyHamcrest >= 1.10.1 -codecov >= 2.0.5 -coverage <5.0 -click <8.0.0 -covimerage >= 0.2.0 +# Use the updated fork +git+https://github.com/bstaletic/covimerage diff --git a/python/ycm/buffer.py b/python/ycm/buffer.py index 60b96e420d..5a65df2415 100644 --- a/python/ycm/buffer.py +++ b/python/ycm/buffer.py @@ -18,6 +18,8 @@ from ycm import vimsupport from ycm.client.event_notification import EventNotification from ycm.diagnostic_interface import DiagnosticInterface +from ycm.semantic_highlighting import SemanticHighlighting +from ycm.inlay_hints import InlayHints # Emulates Vim buffer @@ -35,12 +37,14 @@ def __init__( self, bufnr, user_options, filetypes ): self._diag_interface = DiagnosticInterface( bufnr, user_options ) self._open_loclist_on_ycm_diags = user_options[ 'open_loclist_on_ycm_diags' ] + self.semantic_highlighting = SemanticHighlighting( bufnr ) + self.inlay_hints = InlayHints( bufnr ) self.UpdateFromFileTypes( filetypes ) def FileParseRequestReady( self, block = False ): - return bool( self._parse_request and - ( block or self._parse_request.Done() ) ) + return ( bool( self._parse_request ) and + ( block or self._parse_request.Done() ) ) def SendParseRequest( self, extra_data ): @@ -60,6 +64,10 @@ def SendParseRequest( self, extra_data ): self._parse_tick = self._ChangedTick() + def ParseRequestPending( self ): + return bool( self._parse_request ) and not self._parse_request.Done() + + def NeedsReparse( self ): return self._parse_tick != self._ChangedTick() @@ -123,6 +131,10 @@ def RefreshDiagnosticsUI( self ): return self._diag_interface.RefreshDiagnosticsUI() + def ClearDiagnosticsUI( self ): + return self._diag_interface.ClearDiagnosticsUI() + + def DiagnosticsForLine( self, line_number ): return self._diag_interface.DiagnosticsForLine( line_number ) diff --git a/python/ycm/client/base_request.py b/python/ycm/client/base_request.py index 7c47fe32d0..707339612a 100644 --- a/python/ycm/client/base_request.py +++ b/python/ycm/client/base_request.py @@ -167,7 +167,7 @@ def _MakeRequest( data, handler, method, timeout, payload ): else: headers = BaseRequest._ExtraHeaders( method, request_uri ) if payload: - request_uri += ToBytes( f'?{urlencode( payload )}' ) + request_uri += ToBytes( f'?{ urlencode( payload ) }' ) _logger.debug( 'GET %s (%s)\n%s', request_uri, payload, headers ) return urlopen( @@ -249,6 +249,26 @@ def BuildRequestData( buffer_number = None ): } +def BuildRequestDataForLocation( file : str, line : int, column : int ): + buffer_number = vimsupport.GetBufferNumberForFilename( + file, + create_buffer_if_needed = True ) + try: + vim.eval( f'bufload( "{ file }" )' ) + except vim.error as e: + if 'E325' not in str( e ): + raise + buffer = vim.buffers[ buffer_number ] + file_data = vimsupport.GetUnsavedAndSpecifiedBufferData( buffer, file ) + return { + 'filepath': file, + 'line_num': line, + 'column_num': column, + 'working_dir': GetCurrentDirectory(), + 'file_data': file_data + } + + def _JsonFromFuture( future ): try: response = future.result() @@ -308,6 +328,7 @@ def _BuildUri( handler ): def MakeServerException( data ): + _logger.debug( 'Server exception: %s', data ) if data[ 'exception' ][ 'TYPE' ] == UnknownExtraConf.__name__: return UnknownExtraConf( data[ 'exception' ][ 'extra_conf_file' ] ) diff --git a/python/ycm/client/command_request.py b/python/ycm/client/command_request.py index d0de5118ff..a9045686d8 100644 --- a/python/ycm/client/command_request.py +++ b/python/ycm/client/command_request.py @@ -15,7 +15,9 @@ # You should have received a copy of the GNU General Public License # along with YouCompleteMe. If not, see . -from ycm.client.base_request import BaseRequest, BuildRequestData +from ycm.client.base_request import ( BaseRequest, + BuildRequestData, + BuildRequestDataForLocation ) from ycm import vimsupport DEFAULT_BUFFER_COMMAND = 'same-buffer' @@ -28,7 +30,11 @@ def _EnsureBackwardsCompatibility( arguments ): class CommandRequest( BaseRequest ): - def __init__( self, arguments, extra_data = None, silent = False ): + def __init__( self, + arguments, + extra_data = None, + silent = False, + location = None ): super( CommandRequest, self ).__init__() self._arguments = _EnsureBackwardsCompatibility( arguments ) self._command = arguments and arguments[ 0 ] @@ -37,10 +43,18 @@ def __init__( self, arguments, extra_data = None, silent = False ): self._request_data = None self._response_future = None self._silent = silent + self._bufnr = extra_data.pop( 'bufnr', None ) if extra_data else None + self._location = location def Start( self ): - self._request_data = BuildRequestData() + if self._location is not None: + self._request_data = BuildRequestDataForLocation( *self._location ) + elif self._bufnr is not None: + self._request_data = BuildRequestData( self._bufnr ) + else: + self._request_data = BuildRequestData() + if self._extra_data: self._request_data.update( self._extra_data ) self._request_data.update( { @@ -88,7 +102,7 @@ def RunPostCommandActionsIfNeeded( self, return self._HandleMessageResponse() if 'detailed_info' in self._response: - return self._HandleDetailedInfoResponse() + return self._HandleDetailedInfoResponse( modifiers ) # The only other type of response we understand is GoTo, and that is the # only one that we can't detect just by inspecting the response (it should @@ -133,6 +147,12 @@ def _HandleGotoResponse( self, buffer_command, modifiers ): vimsupport.SetQuickFixList( [ vimsupport.BuildQfListItem( x ) for x in self._response ] ) vimsupport.OpenQuickFixList( focus = True, autoclose = True ) + elif self._response.get( 'file_only' ): + vimsupport.JumpToLocation( self._response[ 'filepath' ], + None, + None, + modifiers, + buffer_command ) else: vimsupport.JumpToLocation( self._response[ 'filepath' ], self._response[ 'line_num' ], @@ -190,14 +210,19 @@ def _HandleMessageResponse( self ): vimsupport.PostVimMessage( self._response[ 'message' ], warning = False ) - def _HandleDetailedInfoResponse( self ): - vimsupport.WriteToPreviewWindow( self._response[ 'detailed_info' ] ) + def _HandleDetailedInfoResponse( self, modifiers ): + vimsupport.WriteToPreviewWindow( self._response[ 'detailed_info' ], + modifiers ) -def SendCommandRequestAsync( arguments, extra_data = None, silent = True ): +def SendCommandRequestAsync( arguments, + extra_data = None, + silent = True, + location = None ): request = CommandRequest( arguments, extra_data = extra_data, - silent = silent ) + silent = silent, + location = location ) request.Start() # Don't block return request @@ -206,12 +231,14 @@ def SendCommandRequestAsync( arguments, extra_data = None, silent = True ): def SendCommandRequest( arguments, modifiers, buffer_command = DEFAULT_BUFFER_COMMAND, - extra_data = None ): + extra_data = None, + skip_post_command_action = False ): request = SendCommandRequestAsync( arguments, extra_data = extra_data, silent = False ) # Block here to get the response - request.RunPostCommandActionsIfNeeded( modifiers, buffer_command ) + if not skip_post_command_action: + request.RunPostCommandActionsIfNeeded( modifiers, buffer_command ) return request.Response() @@ -221,3 +248,11 @@ def GetCommandResponse( arguments, extra_data = None ): silent = True ) # Block here to get the response return request.StringResponse() + + +def GetRawCommandResponse( arguments, silent, location = None ): + request = SendCommandRequestAsync( arguments, + extra_data = None, + silent = silent, + location = location ) + return request.Response() diff --git a/python/ycm/client/inlay_hints_request.py b/python/ycm/client/inlay_hints_request.py new file mode 100644 index 0000000000..ce1225dbda --- /dev/null +++ b/python/ycm/client/inlay_hints_request.py @@ -0,0 +1,64 @@ +# Copyright (C) 2022, YouCompleteMe Contributors +# +# This file is part of YouCompleteMe. +# +# YouCompleteMe is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# YouCompleteMe is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with YouCompleteMe. If not, see . + + +import logging +from ycm.client.base_request import ( BaseRequest, DisplayServerException, + MakeServerException ) + +_logger = logging.getLogger( __name__ ) + + +# FIXME: This is copy/pasta from SemanticTokensRequest - abstract a +# SimpleAsyncRequest base that does all of this generically +class InlayHintsRequest( BaseRequest ): + def __init__( self, request_data ): + super().__init__() + self.request_data = request_data + self._response_future = None + + + def Start( self ): + self._response_future = self.PostDataToHandlerAsync( self.request_data, + 'inlay_hints' ) + + def Done( self ): + return bool( self._response_future ) and self._response_future.done() + + + def Reset( self ): + self._response_future = None + + def Response( self ): + if not self._response_future: + return [] + + response = self.HandleFuture( self._response_future, + truncate_message = True ) + + if not response: + return [] + + # Vim may not be able to convert the 'errors' entry to its internal format + # so we remove it from the response. + errors = response.pop( 'errors', [] ) + for e in errors: + exception = MakeServerException( e ) + _logger.error( exception ) + DisplayServerException( exception, truncate_message = True ) + + return response.get( 'inlay_hints' ) or [] diff --git a/python/ycm/client/semantic_tokens_request.py b/python/ycm/client/semantic_tokens_request.py new file mode 100644 index 0000000000..beebb7cecd --- /dev/null +++ b/python/ycm/client/semantic_tokens_request.py @@ -0,0 +1,64 @@ +# Copyright (C) 2020, YouCompleteMe Contributors +# +# This file is part of YouCompleteMe. +# +# YouCompleteMe is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# YouCompleteMe is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with YouCompleteMe. If not, see . + + +import logging +from ycm.client.base_request import ( BaseRequest, DisplayServerException, + MakeServerException ) + +_logger = logging.getLogger( __name__ ) + + +# FIXME: This is copy/pasta from SignatureHelpRequest - abstract a +# SimpleAsyncRequest base that does all of this generically +class SemanticTokensRequest( BaseRequest ): + def __init__( self, request_data ): + super().__init__() + self.request_data = request_data + self._response_future = None + + + def Start( self ): + self._response_future = self.PostDataToHandlerAsync( self.request_data, + 'semantic_tokens' ) + + def Done( self ): + return bool( self._response_future ) and self._response_future.done() + + + def Reset( self ): + self._response_future = None + + def Response( self ): + if not self._response_future: + return {} + + response = self.HandleFuture( self._response_future, + truncate_message = True ) + + if not response: + return {} + + # Vim may not be able to convert the 'errors' entry to its internal format + # so we remove it from the response. + errors = response.pop( 'errors', [] ) + for e in errors: + exception = MakeServerException( e ) + _logger.error( exception ) + DisplayServerException( exception, truncate_message = True ) + + return response.get( 'semantic_tokens' ) or {} diff --git a/python/ycm/diagnostic_interface.py b/python/ycm/diagnostic_interface.py index 04348d8261..40697fc962 100644 --- a/python/ycm/diagnostic_interface.py +++ b/python/ycm/diagnostic_interface.py @@ -18,8 +18,9 @@ from collections import defaultdict from ycm import vimsupport from ycm.diagnostic_filter import DiagnosticFilter, CompileLevel +from ycm import text_properties as tp import vim -YCM_VIM_PROPERTY_ID = 0 +YCM_VIM_PROPERTY_ID = 1 class DiagnosticInterface: @@ -34,11 +35,19 @@ def __init__( self, bufnr, user_options ): self._diag_message_needs_clearing = False + def ShouldUpdateDiagnosticsUINow( self ): + return ( self._user_options[ 'update_diagnostics_in_insert_mode' ] or + 'i' not in vim.eval( 'mode()' ) ) + + def OnCursorMoved( self ): if self._user_options[ 'echo_current_diagnostic' ]: line, _ = vimsupport.CurrentLineAndColumn() line += 1 # Convert to 1-based - if line != self._previous_diag_line_number: + if not self.ShouldUpdateDiagnosticsUINow(): + # Clear any previously echo'd diagnostic in insert mode + self._EchoDiagnosticText( line, None, None ) + elif line != self._previous_diag_line_number: self._EchoDiagnosticForLine( line ) @@ -62,8 +71,7 @@ def UpdateWithNewDiagnostics( self, diags, open_on_edit = False ): self._ApplyDiagnosticFilter( diags ) ] self._ConvertDiagListToDict() - if ( self._user_options[ 'update_diagnostics_in_insert_mode' ] or - 'i' not in vim.eval( 'mode()' ) ): + if self.ShouldUpdateDiagnosticsUINow(): self.RefreshDiagnosticsUI( open_on_edit ) @@ -80,6 +88,16 @@ def RefreshDiagnosticsUI( self, open_on_edit = False ): self._UpdateLocationLists( open_on_edit ) + def ClearDiagnosticsUI( self ): + if self._user_options[ 'echo_current_diagnostic' ]: + self._ClearCurrentDiagnostic() + + if self._user_options[ 'enable_diagnostic_signs' ]: + self._ClearSigns() + + self._ClearMatches() + + def DiagnosticsForLine( self, line_number ): return self._line_to_diags[ line_number ] @@ -100,19 +118,72 @@ def _EchoDiagnosticForLine( self, line_num ): self._previous_diag_line_number = line_num diags = self._line_to_diags[ line_num ] - if not diags: - if self._diag_message_needs_clearing: - # Clear any previous diag echo - vimsupport.PostVimMessage( '', warning = False ) - self._diag_message_needs_clearing = False + text = None + first_diag = None + if diags: + first_diag = diags[ 0 ] + text = first_diag[ 'text' ] + if first_diag.get( 'fixit_available', False ): + text += ' (FixIt)' + + self._EchoDiagnosticText( line_num, first_diag, text ) + + + def _ClearCurrentDiagnostic( self, will_be_replaced=False ): + if not self._diag_message_needs_clearing: return - first_diag = diags[ 0 ] - text = first_diag[ 'text' ] - if first_diag.get( 'fixit_available', False ): - text += ' (FixIt)' + if ( not vimsupport.VimIsNeovim() and + self._user_options[ 'echo_current_diagnostic' ] == 'virtual-text' ): + tp.ClearTextProperties( self._bufnr, + prop_types = [ 'YcmVirtDiagPadding', + 'YcmVirtDiagError', + 'YcmVirtDiagWarning' ] ) + else: + if not will_be_replaced: + vimsupport.PostVimMessage( '', warning = False ) + + self._diag_message_needs_clearing = False + + + def _EchoDiagnosticText( self, line_num, first_diag, text ): + self._ClearCurrentDiagnostic( bool( text ) ) + + if ( not vimsupport.VimIsNeovim() and + self._user_options[ 'echo_current_diagnostic' ] == 'virtual-text' ): + if not text: + return + + def MakeVritualTextProperty( prop_type, text, position='after' ): + vimsupport.AddTextProperty( self._bufnr, + line_num, + 0, + prop_type, + { + 'text': text, + 'text_align': position, + 'text_wrap': 'wrap' + } ) + + if vim.options[ 'ambiwidth' ] != 'double': + marker = '⚠' + else: + marker = '>' + + MakeVritualTextProperty( + 'YcmVirtDiagPadding', + ' ' * vim.buffers[ self._bufnr ].options[ 'shiftwidth' ] ), + MakeVritualTextProperty( + 'YcmVirtDiagError' if _DiagnosticIsError( first_diag ) + else 'YcmVirtDiagWarning', + marker + ' ' + [ line for line in text.splitlines() if line ][ 0 ] ) + else: + if not text: + # We already cleared it + return + + vimsupport.PostVimMessage( text, warning = False, truncate = True ) - vimsupport.PostVimMessage( text, warning = False, truncate = True ) self._diag_message_needs_clearing = True @@ -130,6 +201,12 @@ def _UpdateLocationLists( self, open_on_edit = False ): open_on_edit ) + def _ClearMatches( self ): + props_to_remove = vimsupport.GetTextProperties( self._bufnr ) + for prop in props_to_remove: + vimsupport.RemoveDiagnosticProperty( self._bufnr, prop ) + + def UpdateMatches( self ): if not self._user_options[ 'enable_diagnostic_highlighting' ]: return @@ -143,6 +220,8 @@ def UpdateMatches( self ): diag ): global YCM_VIM_PROPERTY_ID + # Note the following .remove() works because the __eq__ on + # DiagnosticProperty does not actually check the IDs match... diag_prop = vimsupport.DiagnosticProperty( YCM_VIM_PROPERTY_ID, name, @@ -152,15 +231,22 @@ def UpdateMatches( self ): try: props_to_remove.remove( diag_prop ) except ValueError: + extras.update( { + 'id': YCM_VIM_PROPERTY_ID + } ) vimsupport.AddTextProperty( self._bufnr, line, column, name, - extras, - YCM_VIM_PROPERTY_ID ) + extras ) YCM_VIM_PROPERTY_ID += 1 for prop in props_to_remove: - vimsupport.RemoveTextProperty( self._bufnr, prop ) + vimsupport.RemoveDiagnosticProperty( self._bufnr, prop ) + + + def _ClearSigns( self ): + signs_to_unplace = vimsupport.GetSignsInBuffer( self._bufnr ) + vim.eval( f'sign_unplacelist( { signs_to_unplace } )' ) def _UpdateSigns( self ): @@ -191,11 +277,13 @@ def _UpdateSigns( self ): def _ConvertDiagListToDict( self ): self._line_to_diags = defaultdict( list ) for diag in self._diagnostics: - location = diag[ 'location' ] - bufnr = vimsupport.GetBufferNumberForFilename( location[ 'filepath' ] ) + location_extent = diag[ 'location_extent' ] + start = location_extent[ 'start' ] + end = location_extent[ 'end' ] + bufnr = vimsupport.GetBufferNumberForFilename( start[ 'filepath' ] ) if bufnr == self._bufnr: - line_number = location[ 'line_num' ] - self._line_to_diags[ line_number ].append( diag ) + for line_number in range( start[ 'line_num' ], end[ 'line_num' ] + 1 ): + self._line_to_diags[ line_number ].append( diag ) for diags in self._line_to_diags.values(): # We also want errors to be listed before warnings so that errors aren't @@ -254,6 +342,9 @@ def _ConvertDiagnosticToTextProperties( bufnr, diagnostic ): 'end_col': end_column } ) ) for diagnostic_range in diagnostic[ 'ranges' ]: + if ( diagnostic_range[ 'start' ][ 'line_num' ] == 0 or + diagnostic_range[ 'end' ][ 'line_num' ] == 0 ): + continue start_line, start_column = vimsupport.LineAndColumnNumbersClamped( bufnr, diagnostic_range[ 'start' ][ 'line_num' ], diff --git a/python/ycm/hierarchy_tree.py b/python/ycm/hierarchy_tree.py new file mode 100644 index 0000000000..8bda58072b --- /dev/null +++ b/python/ycm/hierarchy_tree.py @@ -0,0 +1,214 @@ +# Copyright (C) 2024 YouCompleteMe contributors +# +# This file is part of YouCompleteMe. +# +# YouCompleteMe is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# YouCompleteMe is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with YouCompleteMe. If not, see . + +from typing import Optional, List +from ycm import vimsupport +import os + + +class HierarchyNode: + def __init__( self, data, distance : int ): + self._references : Optional[ List[ int ] ] = None + self._data = data + self._distance_from_root = distance + + + def ToRootLocation( self, subindex : int ): + location = self._data.get( 'root_location' ) + if location: + file = location[ 'filepath' ] + line = location[ 'line_num' ] + column = location[ 'column_num' ] + return file, line, column + else: + return self.ToLocation( subindex ) + + + def ToLocation( self, subindex : int ): + location = self._data[ 'locations' ][ subindex ] + line = location[ 'line_num' ] + column = location[ 'column_num' ] + file = location[ 'filepath' ] + return file, line, column + + +MAX_HANDLES_PER_INDEX = 1000000 + + +def handle_to_index( handle : int ): + return abs( handle ) // MAX_HANDLES_PER_INDEX + + +def handle_to_location_index( handle : int ): + return abs( handle ) % MAX_HANDLES_PER_INDEX + + +def make_handle( index : int, location_index : int ): + return index * MAX_HANDLES_PER_INDEX + location_index + + +class HierarchyTree: + def __init__( self ): + self._up_nodes : List[ HierarchyNode ] = [] + self._down_nodes : List[ HierarchyNode ] = [] + self._kind : str = '' + + def SetRootNode( self, items, kind : str ): + if items: + assert len( items ) == 1 + self._root_node_indices = [ 0 ] + self._down_nodes.append( HierarchyNode( items[ 0 ], 0 ) ) + self._up_nodes.append( HierarchyNode( items[ 0 ], 0 ) ) + self._kind = kind + return self.HierarchyToLines() + return [] + + + def UpdateHierarchy( self, handle : int, items, direction : str ): + current_index = handle_to_index( handle ) + nodes = self._down_nodes if direction == 'down' else self._up_nodes + if items: + nodes.extend( [ + HierarchyNode( item, + nodes[ current_index ]._distance_from_root + 1 ) + for item in items ] ) + nodes[ current_index ]._references = list( + range( len( nodes ) - len( items ), len( nodes ) ) ) + else: + nodes[ current_index ]._references = [] + + + def Reset( self ): + self._down_nodes = [] + self._up_nodes = [] + self._kind = '' + + + def _HierarchyToLinesHelper( self, refs, use_down_nodes ): + partial_result = [] + nodes = self._down_nodes if use_down_nodes else self._up_nodes + for index in refs: + next_node = nodes[ index ] + indent = 2 * next_node._distance_from_root + if index == 0: + can_expand = ( self._down_nodes[ 0 ]._references is None or + self._up_nodes[ 0 ]._references is None ) + else: + can_expand = next_node._references is None + symbol = '+' if can_expand else '-' + name = next_node._data[ 'name' ] + kind = next_node._data[ 'kind' ] + if use_down_nodes: + partial_result.extend( [ + ( + { + 'indent': indent, + 'icon': symbol, + 'symbol': name, + 'kind': kind, + 'filepath': os.path.split( l[ 'filepath' ] )[ 1 ], + 'line_num': str( l[ 'line_num' ] ), + 'description': l.get( 'description', '' ).strip(), + }, + make_handle( index, location_index ) + ) + for location_index, l in enumerate( next_node._data[ 'locations' ] ) + ] ) + else: + partial_result.extend( [ + ( + { + 'indent': indent, + 'icon': symbol, + 'symbol': name, + 'kind': kind, + 'filepath': os.path.split( l[ 'filepath' ] )[ 1 ], + 'line_num': str( l[ 'line_num' ] ), + 'description': l.get( 'description', '' ).strip(), + }, + make_handle( index, location_index ) * -1 + ) + for location_index, l in enumerate( next_node._data[ 'locations' ] ) + ] ) + if next_node._references: + partial_result.extend( + self._HierarchyToLinesHelper( + next_node._references, use_down_nodes ) ) + return partial_result + + def HierarchyToLines( self ): + down_lines = self._HierarchyToLinesHelper( [ 0 ], True ) + up_lines = self._HierarchyToLinesHelper( [ 0 ], False ) + up_lines.reverse() + return up_lines + down_lines[ 1: ] + + + def JumpToItem( self, handle : int, command ): + node_index = handle_to_index( handle ) + location_index = handle_to_location_index( handle ) + if handle >= 0: + node = self._down_nodes[ node_index ] + else: + node = self._up_nodes[ node_index ] + file, line, column = node.ToLocation( location_index ) + vimsupport.JumpToLocation( file, line, column, '', command ) + + + def ShouldResolveItem( self, handle : int, direction : str ): + node_index = handle_to_index( handle ) + if ( ( handle >= 0 and direction == 'down' ) or + ( handle <= 0 and direction == 'up' ) ): + if direction == 'down': + node = self._down_nodes[ node_index ] + else: + node = self._up_nodes[ node_index ] + return node._references is None + return True + + + def ResolveArguments( self, handle : int, direction : str ): + node_index = handle_to_index( handle ) + if self._kind == 'call': + direction = 'outgoing' if direction == 'up' else 'incoming' + else: + direction = 'supertypes' if direction == 'up' else 'subtypes' + if handle >= 0: + node = self._down_nodes[ node_index ] + else: + node = self._up_nodes[ node_index ] + return [ + f'Resolve{ self._kind.title() }HierarchyItem', + node._data, + direction + ] + + + def HandleToRootLocation( self, handle : int ): + node_index = handle_to_index( handle ) + + if handle >= 0: + node = self._down_nodes[ node_index ] + else: + node = self._up_nodes[ node_index ] + + location_index = handle_to_location_index( handle ) + return node.ToRootLocation( location_index ) + + + def UpdateChangesRoot( self, handle : int, direction : str ): + return ( ( handle < 0 and direction == 'down' ) or + ( handle > 0 and direction == 'up' ) ) diff --git a/python/ycm/inlay_hints.py b/python/ycm/inlay_hints.py new file mode 100644 index 0000000000..880e89ed67 --- /dev/null +++ b/python/ycm/inlay_hints.py @@ -0,0 +1,127 @@ +# Copyright (C) 2022, YouCompleteMe Contributors +# +# This file is part of YouCompleteMe. +# +# YouCompleteMe is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# YouCompleteMe is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with YouCompleteMe. If not, see . + + +from ycm.client.inlay_hints_request import InlayHintsRequest +from ycm.client.base_request import BuildRequestData +from ycm import vimsupport +from ycm import text_properties as tp +from ycm import scrolling_range as sr + + +HIGHLIGHT_GROUP = { + 'Type': 'YcmInlayHint', + 'Parameter': 'YcmInlayHint', + 'Enum': 'YcmInlayHint', +} +REPORTED_MISSING_TYPES = set() + + +def Initialise(): + if vimsupport.VimIsNeovim(): + return False + + props = tp.GetTextPropertyTypes() + if 'YCM_INLAY_UNKNOWN' not in props: + tp.AddTextPropertyType( 'YCM_INLAY_UNKNOWN', + highlight = 'YcmInlayHint', + start_incl = 1 ) + if 'YCM_INLAY_PADDING' not in props: + tp.AddTextPropertyType( 'YCM_INLAY_PADDING', + highlight = 'YcmInvisible', + start_incl = 1 ) + + for token_type, group in HIGHLIGHT_GROUP.items(): + prop = f'YCM_INLAY_{ token_type }' + if prop not in props and vimsupport.GetIntValue( + f"hlexists( '{ vimsupport.EscapeForVim( group ) }' )" ): + tp.AddTextPropertyType( prop, + highlight = group, + start_incl = 1 ) + + return True + + +class InlayHints( sr.ScrollingBufferRange ): + """Stores the inlay hints state for a Vim buffer""" + + + def _NewRequest( self, request_range ): + request_data = BuildRequestData( self._bufnr ) + request_data[ 'range' ] = request_range + return InlayHintsRequest( request_data ) + + + def Clear( self ): + types = [ 'YCM_INLAY_UNKNOWN', 'YCM_INLAY_PADDING' ] + [ + f'YCM_INLAY_{ prop_type }' for prop_type in HIGHLIGHT_GROUP.keys() + ] + + tp.ClearTextProperties( self._bufnr, prop_types = types ) + + + def _Draw( self ): + self.Clear() + + for inlay_hint in self._latest_response: + if 'kind' not in inlay_hint: + prop_type = 'YCM_INLAY_UNKNOWN' + elif inlay_hint[ 'kind' ] not in HIGHLIGHT_GROUP: + prop_type = 'YCM_INLAY_UNKNOWN' + else: + prop_type = 'YCM_INLAY_' + inlay_hint[ 'kind' ] + + self.GrowRangeIfNeeded( { + 'start': inlay_hint[ 'position' ], + 'end': { + 'line_num': inlay_hint[ 'position' ][ 'line_num' ], + 'column_num': inlay_hint[ 'position' ][ 'column_num' ] + len( + inlay_hint[ 'label' ] ) + } + } ) + + if inlay_hint.get( 'paddingLeft', False ): + tp.AddTextProperty( self._bufnr, + None, + 'YCM_INLAY_PADDING', + { + 'start': inlay_hint[ 'position' ], + }, + { + 'text': ' ' + } ) + + tp.AddTextProperty( self._bufnr, + None, + prop_type, + { + 'start': inlay_hint[ 'position' ], + }, + { + 'text': inlay_hint[ 'label' ] + } ) + + if inlay_hint.get( 'paddingRight', False ): + tp.AddTextProperty( self._bufnr, + None, + 'YCM_INLAY_PADDING', + { + 'start': inlay_hint[ 'position' ], + }, + { + 'text': ' ' + } ) diff --git a/python/ycm/scrolling_range.py b/python/ycm/scrolling_range.py new file mode 100644 index 0000000000..0d0bd9ad2c --- /dev/null +++ b/python/ycm/scrolling_range.py @@ -0,0 +1,146 @@ +# Copyright (C) 2023, YouCompleteMe Contributors +# +# This file is part of YouCompleteMe. +# +# YouCompleteMe is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# YouCompleteMe is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with YouCompleteMe. If not, see . + +import abc + +from ycm import vimsupport + + +class ScrollingBufferRange( object ): + """Abstraction used by inlay hints and semantic tokens to only request visible + ranges""" + + # FIXME: Send a request per-disjoint range for this buffer rather than the + # maximal range. then collaate the results when all responses are returned + def __init__( self, bufnr ): + self._bufnr = bufnr + self._tick = -1 + self._request = None + self._last_requested_range = None + + + def Ready( self ): + return self._request is not None and self._request.Done() + + + def Request( self, force=False ): + if self._request and not self.Ready(): + return True + + # Check to see if the buffer ranges would actually change anything visible. + # This avoids a round-trip for every single line scroll event + if ( not force and + self._tick == vimsupport.GetBufferChangedTick( self._bufnr ) and + vimsupport.VisibleRangeOfBufferOverlaps( + self._bufnr, + self._last_requested_range ) ): + return False # don't poll + + # FIXME: This call is duplicated in the call to VisibleRangeOfBufferOverlaps + # - remove the expansion param + # - look up the actual visible range, then call this function + # - if not overlapping, do the factor expansion and request + self._last_requested_range = vimsupport.RangeVisibleInBuffer( self._bufnr ) + # If this is false, either the self._bufnr is not a valid buffer number or + # the buffer is not visible in any window. + # Since this is called asynchronously, a user may bwipeout a buffer with + # self._bufnr number between polls. + if self._last_requested_range is None: + return False + + self._tick = vimsupport.GetBufferChangedTick( self._bufnr ) + + # We'll never use the last response again, so clear it + self._latest_response = None + self._request = self._NewRequest( self._last_requested_range ) + self._request.Start() + return True + + + def Update( self ): + if not self._request: + # Nothing to update + return True + + assert self.Ready() + + # We're ready to use this response. Clear the request (to avoid repeatedly + # re-polling). + self._latest_response = self._request.Response() + self._request = None + + if self._tick != vimsupport.GetBufferChangedTick( self._bufnr ): + # Buffer has changed, we should ignore the data and retry + self.Request( force=True ) + return False # poll again + + self._Draw() + + # No need to re-poll + return True + + + def Refresh( self ): + if self._tick != vimsupport.GetBufferChangedTick( self._bufnr ): + # stale data + return + + if self._request is not None: + # request in progress; we''l handle refreshing when it's done. + return + + self._Draw() + + + def GrowRangeIfNeeded( self, rng ): + """When processing results, we may receive a wider range than requested. In + that case, grow our 'last requested' range to minimise requesting more + frequently than we need to.""" + # Note: references (pointers) so no need to re-assign + rmin = self._last_requested_range[ 'start' ] + rmax = self._last_requested_range[ 'end' ] + + start = rng[ 'start' ] + end = rng[ 'end' ] + + if rmin[ 'line_num' ] is None or start[ 'line_num' ] < rmin[ 'line_num' ]: + rmin[ 'line_num' ] = start[ 'line_num' ] + rmin[ 'column_num' ] = start[ 'column_num' ] + elif start[ 'line_num' ] == rmin[ 'line_num' ]: + rmin[ 'column_num' ] = min( start[ 'column_num' ], + rmin[ 'column_num' ] ) + + if rmax[ 'line_num' ] is None or end[ 'line_num' ] > rmax[ 'line_num' ]: + rmax[ 'line_num' ] = end[ 'line_num' ] + rmax[ 'column_num' ] = end[ 'column_num' ] + elif end[ 'line_num' ] == rmax[ 'line_num' ]: + rmax[ 'column_num' ] = max( end[ 'column_num' ], rmax[ 'column_num' ] ) + + + # API; just implement the following, using self._bufnr and + # self._latest_response as required + + @abc.abstractmethod + def _NewRequest( self, request_range ): + # prepare a new request_data and return it + pass + + + @abc.abstractmethod + def _Draw( self ): + # actuall paint the properties + pass diff --git a/python/ycm/semantic_highlighting.py b/python/ycm/semantic_highlighting.py new file mode 100644 index 0000000000..945dc0f1d9 --- /dev/null +++ b/python/ycm/semantic_highlighting.py @@ -0,0 +1,136 @@ +# Copyright (C) 2020, YouCompleteMe Contributors +# +# This file is part of YouCompleteMe. +# +# YouCompleteMe is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# YouCompleteMe is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with YouCompleteMe. If not, see . + + +from ycm.client.semantic_tokens_request import SemanticTokensRequest +from ycm.client.base_request import BuildRequestData +from ycm import vimsupport +from ycm import text_properties as tp +from ycm import scrolling_range as sr + +import vim + + +HIGHLIGHT_GROUP = { + 'namespace': 'Type', + 'type': 'Type', + 'class': 'Structure', + 'enum': 'Structure', + 'interface': 'Structure', + 'struct': 'Structure', + 'typeParameter': 'Identifier', + 'parameter': 'Identifier', + 'variable': 'Identifier', + 'property': 'Identifier', + 'enumMember': 'Identifier', + 'enumConstant': 'Constant', + 'event': 'Identifier', + 'function': 'Function', + 'member': 'Identifier', + 'macro': 'Macro', + 'method': 'Function', + 'keyword': 'Keyword', + 'modifier': 'Keyword', + 'comment': 'Comment', + 'string': 'String', + 'number': 'Number', + 'regexp': 'String', + 'operator': 'Operator', + 'decorator': 'Special', + 'unknown': 'Normal', + + # These are not part of the spec, but are used by clangd + 'bracket': 'Normal', + 'concept': 'Type', + # These are not part of the spec, but are used by jdt.ls + 'annotation': 'Macro', +} +REPORTED_MISSING_TYPES = set() + + +def Initialise(): + if vimsupport.VimIsNeovim(): + return + + props = tp.GetTextPropertyTypes() + if 'YCM_HL_UNKNOWN' not in props: + tp.AddTextPropertyType( 'YCM_HL_UNKNOWN', + highlight = 'WarningMsg', + priority = 0 ) + + for token_type, group in HIGHLIGHT_GROUP.items(): + prop = f'YCM_HL_{ token_type }' + if prop not in props and vimsupport.GetIntValue( + f"hlexists( '{ vimsupport.EscapeForVim( group ) }' )" ): + tp.AddTextPropertyType( prop, + highlight = group, + priority = 0 ) + + +# "arbitrary" base id +NEXT_TEXT_PROP_ID = 70784 + + +def NextPropID(): + global NEXT_TEXT_PROP_ID + try: + return NEXT_TEXT_PROP_ID + finally: + NEXT_TEXT_PROP_ID += 1 + + + +class SemanticHighlighting( sr.ScrollingBufferRange ): + """Stores the semantic highlighting state for a Vim buffer""" + + def __init__( self, bufnr ): + self._prop_id = NextPropID() + super().__init__( bufnr ) + + + def _NewRequest( self, request_range ): + request: dict = BuildRequestData( self._bufnr ) + request[ 'range' ] = request_range + return SemanticTokensRequest( request ) + + + def _Draw( self ): + # We requested a snapshot + tokens = self._latest_response.get( 'tokens', [] ) + + prev_prop_id = self._prop_id + self._prop_id = NextPropID() + + for token in tokens: + prop_type = f"YCM_HL_{ token[ 'type' ] }" + rng = token[ 'range' ] + self.GrowRangeIfNeeded( rng ) + + try: + tp.AddTextProperty( self._bufnr, self._prop_id, prop_type, rng ) + except vim.error as e: + if 'E971:' in str( e ): # Text property doesn't exist + if token[ 'type' ] not in REPORTED_MISSING_TYPES: + REPORTED_MISSING_TYPES.add( token[ 'type' ] ) + vimsupport.PostVimMessage( + f"Token type { token[ 'type' ] } not supported. " + f"Define property type { prop_type }. " + f"See :help youcompleteme-customising-highlight-groups" ) + else: + raise e + + tp.ClearTextProperties( self._bufnr, prop_id = prev_prop_id ) diff --git a/python/ycm/signature_help.py b/python/ycm/signature_help.py index 35ced789a6..0793f73d7d 100644 --- a/python/ycm/signature_help.py +++ b/python/ycm/signature_help.py @@ -159,6 +159,15 @@ def UpdateSignatureHelp( state, signature_info ): # noqa # inserting the char ? col = int( screen_pos[ 'curscol' ] ) - 2 + # Vim stops shifting the popup to the left if we turn on soft-wrapping. + # Instead, we want to first shift the popup to the left and then + # and then turn on wrapping. + max_line_length = max( len( item[ 'text' ] ) for item in buf_lines ) + vim_width = vimsupport.GetIntValue( '&columns' ) + line_available = vim_width - max( col, 1 ) + if max_line_length > line_available: + col = vim_width - max_line_length + if col <= 0: col = 1 @@ -172,6 +181,7 @@ def UpdateSignatureHelp( state, signature_info ): # noqa # cursorline. So instead, we manually set 'cursorline' in the popup window # and enable syntax based on the current file syntax) "flip": 1, + "fixed": 1, "padding": [ 0, 1, 0, 1 ], # Pad 1 char in X axis to match completion menu "hidden": int( state.state == SignatureHelpState.ACTIVE_SUPPRESSED ) } @@ -189,10 +199,14 @@ def UpdateSignatureHelp( state, signature_info ): # noqa if state.state == SignatureHelpState.ACTIVE: vim.eval( f'popup_show( { state.popup_win_id } )' ) - syntax = utils.ToUnicode( vim.current.buffer.options[ 'syntax' ] ) + if vim.vars.get( 'ycm_signature_help_disable_syntax', False ): + syntax = '' + else: + syntax = utils.ToUnicode( vim.current.buffer.options[ 'syntax' ] ) + active_signature = int( signature_info.get( 'activeSignature', 0 ) ) vim.eval( f"win_execute( { state.popup_win_id }, " - f"'set syntax={ syntax } cursorline | " + f"'set syntax={ syntax } cursorline wrap | " f"call cursor( [ { active_signature + 1 }, 1 ] )' )" ) return state diff --git a/python/ycm/tests/client/command_request_test.py b/python/ycm/tests/client/command_request_test.py index 7af6e4852e..368b87c4ec 100644 --- a/python/ycm/tests/client/command_request_test.py +++ b/python/ycm/tests/client/command_request_test.py @@ -283,7 +283,7 @@ def DetailedInfoTest( command, info ): request = CommandRequest( [ command ] ) request._response = { 'detailed_info': info } request.RunPostCommandActionsIfNeeded( 'topleft' ) - write_to_preview.assert_called_with( info ) + write_to_preview.assert_called_with( info, 'topleft' ) for command, info in [ [ '___________', 'This is a message' ], diff --git a/python/ycm/tests/command_test.py b/python/ycm/tests/command_test.py index b938e94e6c..52ce467030 100644 --- a/python/ycm/tests/command_test.py +++ b/python/ycm/tests/command_test.py @@ -47,7 +47,7 @@ def test_SendCommandRequest_ExtraConfVimData_Works( self, ycm ): 'extra_conf_data': has_entries( { 'tempname()': '_TEMP_FILE_' } ), - } ) + } ), ) ) @@ -71,7 +71,7 @@ def test_SendCommandRequest_ExtraConfData_UndefinedValue( self, ycm ): 'tab_size': 2, 'insert_spaces': True, } ) - } ) + } ), ) ) @@ -102,7 +102,7 @@ def test_SendCommandRequest_BuildRange_NoVisualMarks( self, ycm, *args ): 'column_num': 12 } } - } + }, ) @@ -135,7 +135,7 @@ def test_SendCommandRequest_BuildRange_VisualMarks( self, ycm, *args ): 'column_num': 9 } } - } + }, ) @@ -148,15 +148,16 @@ def test_SendCommandRequest_IgnoreFileTypeOption( self, ycm, *args ): '', 'same-buffer', { + 'completer_target': 'python', 'options': { 'tab_size': 2, 'insert_spaces': True }, - } + }, ) with patch( 'ycm.youcompleteme.SendCommandRequest' ) as send_request: - ycm.SendCommandRequest( [ 'ft=ycm:ident', 'GoTo' ], '', False, 1, 1 ) + ycm.SendCommandRequest( [ 'ft=python', 'GoTo' ], '', False, 1, 1 ) send_request.assert_called_once_with( *expected_args ) with patch( 'ycm.youcompleteme.SendCommandRequest' ) as send_request: diff --git a/python/ycm/tests/diagnostic_interface_test.py b/python/ycm/tests/diagnostic_interface_test.py index 626e936618..f3f3b6487f 100644 --- a/python/ycm/tests/diagnostic_interface_test.py +++ b/python/ycm/tests/diagnostic_interface_test.py @@ -54,6 +54,46 @@ def SimpleDiagnosticToJson( start_line, start_col, end_line, end_col ): } +def SimpleDiagnosticToJsonWithInvalidLineNum( start_line, start_col, + end_line, end_col ): + return { + 'kind': 'ERROR', + 'location': { 'line_num': start_line, 'column_num': start_col }, + 'location_extent': { + 'start': { + 'line_num': start_line, + 'column_num': start_col + }, + 'end': { + 'line_num': end_line, + 'column_num': end_col + } + }, + 'ranges': [ + { + 'start': { + 'line_num': 0, + 'column_num': 0 + }, + 'end': { + 'line_num': 0, + 'column_num': 0 + } + }, + { + 'start': { + 'line_num': start_line, + 'column_num': start_col + }, + 'end': { + 'line_num': end_line, + 'column_num': end_col + } + } + ] + } + + def YcmTextPropertyTupleMatcher( start_line, start_col, end_line, end_col ): return has_item( contains_exactly( start_line, @@ -86,7 +126,7 @@ def test_ConvertDiagnosticToTextProperties( self ): [ SimpleDiagnosticToJson( 0, 0, 0, 0 ), [ 'Some contents' ], - YcmTextPropertyTupleMatcher( 1, 1, 1, 1 ) + {} ], [ SimpleDiagnosticToJson( -1, -2, -3, -4 ), @@ -106,6 +146,39 @@ def test_ConvertDiagnosticToTextProperties( self ): print( actual ) assert_that( actual, result ) + def test_ConvertDiagnosticWithInvalidLineNum( self ): + for diag, contents, result in [ + # Error in middle of the line + [ + SimpleDiagnosticToJsonWithInvalidLineNum( 1, 16, 1, 23 ), + [ 'Highlight this error please' ], + YcmTextPropertyTupleMatcher( 1, 16, 1, 23 ) + ], + # Error at the end of the line + [ + SimpleDiagnosticToJsonWithInvalidLineNum( 1, 16, 1, 21 ), + [ 'Highlight this warning' ], + YcmTextPropertyTupleMatcher( 1, 16, 1, 21 ) + ], + [ + SimpleDiagnosticToJsonWithInvalidLineNum( 1, 16, 1, 19 ), + [ 'Highlight unicøde' ], + YcmTextPropertyTupleMatcher( 1, 16, 1, 19 ) + ], + ]: + with self.subTest( diag = diag, contents = contents, result = result ): + current_buffer = VimBuffer( 'foo', number = 1, contents = [ '' ] ) + target_buffer = VimBuffer( 'bar', number = 2, contents = contents ) + + with MockVimBuffers( [ current_buffer, target_buffer ], + [ current_buffer, target_buffer ] ): + actual = diagnostic_interface._ConvertDiagnosticToTextProperties( + target_buffer.number, + diag ) + print( actual ) + assert_that( actual, result ) + + def test_IsValidRange( self ): for start_line, start_col, end_line, end_col, expect in ( ( 1, 1, 1, 1, True ), diff --git a/python/ycm/tests/test_utils.py b/python/ycm/tests/test_utils.py index 30759b78c5..1aa1b7286b 100644 --- a/python/ycm/tests/test_utils.py +++ b/python/ycm/tests/test_utils.py @@ -35,25 +35,26 @@ BUFNR_REGEX = re.compile( - '^bufnr\\(\'(?P.+)\'(, ([01]))?\\)$' ) -BUFWINNR_REGEX = re.compile( '^bufwinnr\\((?P[0-9]+)\\)$' ) + '^bufnr\\( \'(?P.+)\'(, ([01]))? \\)$' ) +BUFWINNR_REGEX = re.compile( '^bufwinnr\\( (?P[0-9]+) \\)$' ) BWIPEOUT_REGEX = re.compile( '^(?:silent! )bwipeout!? (?P[0-9]+)$' ) GETBUFVAR_REGEX = re.compile( - '^getbufvar\\((?P[0-9]+), "(?P