1
0
Fork 0
mirror of synced 2024-12-25 00:03:20 -05:00

I don't know how to ignore autoformatting *.h.in files, so change into autoformat files manually.

This commit is contained in:
Kurtis Moxley 2022-06-05 22:09:27 +08:00
parent e371e16382
commit 27c01e54fa
23 changed files with 2776 additions and 1 deletions

View file

@ -0,0 +1,21 @@
version: 2.1
jobs:
lint:
docker:
- image: circleci/python:latest
auth:
username: $DOCKERHUB_USERNAME
password: $DOCKERHUB_PASSWORD
steps:
- checkout
- run:
name: Lint
command: |
pip install vim-vint
vint .
workflows:
lint:
jobs:
- lint

View file

@ -0,0 +1,33 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
### Bug description
A clear and concise description of what the bug is.
### To Reproduce
Steps to reproduce the behavior:
1. ...
2. ...
### Expected behavior
A clear and concise description of what you expected to happen.
### Behavior with minimal `.vimrc`
A clear and concise description of what happens whe trying to reproduce the bug with a minimal `.vimrc`. Ideally, a minimal `.vimrc` only contains configuration for this plugin, and nothing else. If the minimal `.vimrc` used is more complicated, please post the content here.
### Screenshots
If applicable, add screenshots to help explain your problem.
### Other info
- OS:
- Vim/Neovim version:
- Vim-CMake version (5th line in `:help cmake`):
- CMake version (`cmake --version`):
### Additional context
Add any other context about the problem here.

View file

@ -0,0 +1,19 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: feature request
assignees: ''
---
### Request description
A clear and concise description of what the feature request is.
### Desired behavior
A clear and concise description of what you want to happen.
### Alternatives solutions
A clear and concise description of any alternative solutions or features you've considered.
### Additional context
Add any other context or screenshots about the feature request here.

View file

@ -0,0 +1,7 @@
---
name: Other
about: General feedback or question
title: ''
labels: ''
assignees: ''
---

View file

@ -0,0 +1 @@
.data/

View file

@ -0,0 +1,11 @@
cmdargs:
verbose: true
severity: style_problem
stat: true
color: true
env:
neovim: true
policies:
ProhibitImplicitScopeVariable:
enabled: true

View file

@ -0,0 +1,175 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog][format], and this project adheres to
[Semantic Versioning][semver].
## Unreleased
### Added
* An explicit error message is issues when running Neovim versions < 0.5
<!--=========================================================================-->
## 0.7.1 &ndash; 2022-04-10
### Changed
* The command list passed to `jobstart()` (or `job_start()` in Vim) is now
properly formatted
* A link to the `compile_commands.json` file is only created on a successful
`:CMakeGenerate` and on a successful `:CMakeSwitch`
* Symbolic links are created using the CMake command-line tool `cmake -E
create_symlink`
<!--=========================================================================-->
## 0.7.0 &ndash; 2022-03-16
### Added
* MS-Windows is now supported, but only using Neovim for now
* The new command `:CMakeStop` allows the user to stop the process currently
running in the Vim-CMake console
* The new configuration option `g:cmake_console_echo_cmd` controls whether the
Vim-CMake console should echo the running command before running the command
itself
* The new configuration option `g:cmake_log_file` controls whether, and where,
to store logs generated by the plugin
### Changed
* Code has a new internal structure, and cyclic dependencies are removed
* The Vim-CMake console terminal does not make use of an external Bash script
any longer, now the plugin is fully written in Vimscript
* Fixed searching of root path and build directory location
* Detecting CMake version now works also for packages which are not called just
`cmake` (for instance, the `cmake3` package in the `epel` repo)
<!--=========================================================================-->
## 0.6.2 &ndash; 2021-08-02
### Changed
* `-DCMAKE_BUILD_TYPE` flag is now always added when running `:CMakeGenerate`
* The hashbang for `bash` in `scripts/console.sh` has been made more portable by
using `/usr/bin/env`.
<!--=========================================================================-->
## 0.6.1 &ndash; 2021-06-19
### Added
* Set `bufhidden=hide` on the Vim-CMake buffer to avoid error E37 in some Vim
instances.
### Changed
* Running a command does not result in jumping into the Vim-CMake window and
back in the background, thus reducing the number of unnecessarily triggered
events.
<!--=========================================================================-->
## 0.6.0 &ndash; 2021-04-14
### Added
* `g:cmake_build_dir_location`, location of the build directory, relative to the
project root.
### Changed
* Usage of `:CMakeGenerate`, now build configuration directory and
`CMAKE_BUILD_TYPE` can be controlled independently.
<!--=========================================================================-->
## 0.5.0 &ndash; 2021-02-22
### Added
* Implemented user autocommands `CMakeBuildFailed` and `CMakeBuildSuceeded` to
customize behaviour after `:CMakeBuild`
### Changed
* Fixed bug that wouldn't make the console script run when Vim-CMake is
installed in a directory that contains spaces.
* Make the `WinEnter` autocmd in console.vim buffer-local.
* Set correct source and build directories even when invoking Vim-CMake commands
from subdirectory of root (source) directory.
* Internal implementation of `:CMakeGenerate` made more structured.
* Automatically set the configuration option `CMAKE_EXPORT_COMPILE_COMMANDS` to
`ON` when `g:cmake_link_compile_commands` is set to `1`.
* Pass job callbacks directly to `jobstart`/`termopen`.
<!--=========================================================================-->
## 0.4.0 &ndash; 2020-10-13
### Added
* `g:cmake_generate_options`, list of options to pass to CMake by default when
running `:CMakeGenerate`.
### Changed
* Fixed parsing command output in Vim to populate the quickfix list.
* Updated source code documentation format.
<!--=========================================================================-->
## 0.3.0 &ndash; 2020-09-01
### Added
* Quickfix list population after each build.
<!--=========================================================================-->
## 0.2.2 &ndash; 2020-07-18
### Changed
* Support for Airline is now provided in the vim-airline plugin, and disabling
Airline's terminal extension is not needed anymore.
<!--=========================================================================-->
## 0.2.1 &ndash; 2020-07-15
### Changed
* Pass absolute path to `findfile()` when searching for existing build
configurations.
<!--=========================================================================-->
## 0.2.0 &ndash; 2020-07-12
### Added
* `:CMakeSwitch` command, and `<Plug>(CMakeSwitch)` mapping, to switch between
build configurations.
* `g:cmake_default_config`, the default build configuration on start-up.
* Print Vim-CMake updates when new version is pulled.
### Changed
* `:CMakeGenerate` can be called with build configuration as a direct option,
e.g., `:CMakeGenerate Release`.
### Removed
* `g:cmake_default_build_dir`.
<!--=========================================================================-->
## 0.1.1 &ndash; 2020-06-11
### Changed
* `:CMakeBuild!` and `:CMakeInstall` now use the native `--clean-first` and
`--install` CMake options.
* Fix error when vim-airline not loaded and polish statusline/Airline output.
### Removed
* `:CMakeBuildClean`, as `:CMakeBuild!` should cover most of the use cases, and
`:CMakeBuild clean` can still be used.
<!--=========================================================================-->
## 0.1.0 &ndash; 2020-05-09
First version.
<!--=========================================================================-->
[format]: https://keepachangelog.com/en/1.0.0/
[semver]: https://semver.org/spec/v2.0.0.html

View file

@ -0,0 +1,43 @@
# Contributing Guidelines
The easiest method to contribute to this project is by providing feedback,
requesting a feature or reporting a bug. Prior to opening an issue, check the
existing ones, as there might be one that already covers your points. When
you need to open a new one, provide as much information as you can, especially
for bug reports.
<!--=========================================================================-->
## Pull Requests
Do you feel like contributing code? Awesome! Find an open issue you want to
tackle (can be one of your own), then open a pull request following [these
guidelines][pr-guidelines]. Make sure to **test your changes thoroughly** and,
if needed,
* update the documentation in `doc/cmake.txt`
* generate help tags with `vim -u NONE -c "helptags doc | q"`
* update the README
* update the "Unreleased" section in the CHANGELOG
<!--=========================================================================-->
## Coding Style
In case you are planning to submit a pull request, please keep your changes
minimal and maintain a clear coding style. Name your functions and variables
sensibly, comment non-obvious lines of code and match the formatting style of
the rest of the code (indentation, line width, spacing, etc.).
This project adheres to the [Google Vimscript Style Guide][style-guide], with a
few exceptions:
* use four spaces for indents (not two)
* indent continued lines by eight spaces (not four)
You can use [Vint][vint] and run `vint .` in the repository root to check the
code against the above style guide.
<!--=========================================================================-->
[pr-guidelines]: https://opensource.guide/how-to-contribute/#opening-a-pull-request
[style-guide]: https://google.github.io/styleguide/vimscriptguide.xml
[vint]: https://github.com/Vimjas/vint

View file

@ -0,0 +1,19 @@
Copyright (c) 2020-2021 Carlo Delle Donne
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,172 @@
# Vim-CMake
Vim-CMake is a plugin for building CMake projects inside of Vim/Neovim, with a
nice visual feedback.
![lint](https://img.shields.io/circleci/build/github/cdelledonne/vim-cmake?label=lint&logo=circleci)
![language](https://img.shields.io/github/languages/top/cdelledonne/vim-cmake)
![version](https://img.shields.io/github/v/tag/cdelledonne/vim-cmake?label=version&sort=semver)
![license](https://img.shields.io/github/license/cdelledonne/vim-cmake)
![screencast][screencast]
**Features**
* Visual experience, shows CMake output in a console-like window
* Slick management of build configurations
* Autocompletion for build targets and build configurations
* Quickfix list population after each build
* Airline/statusline status information, including current build configuration
* Plug-and-play, but configurable
* Written in Vimscript
**Requirements**
* Vim with `+terminal`, or Neovim >= 0.5
* Under Windows, only Neovim is supported at the moment
<!--=========================================================================-->
## Installation
Use a package manager like [vim-plug][vim-plug]:
```vim
Plug 'cdelledonne/vim-cmake'
```
or Vim's native package manager:
```sh
mkdir -p ~/.vim/pack/plug/start
cd ~/.vim/pack/plug/start
git clone https://github.com/cdelledonne/vim-cmake.git
```
<!--=========================================================================-->
## Usage
Run `:CMakeGenerate` from the top-level CMake source directory to generate a
build system for the project. Then, run `:CMakeBuild` to build the project.
The built files will end up in the binary directory ([out-of-source
build][oos]). To switch between build configurations, run `:CMakeSwitch
<config>`.
With Vim-CMake, you can easily manage build configurations (Debug, Release,
etc.), build specific targets and control build options, and fix errors using
Vim's quickfix feature. For a detailed explanation of commands, mappings and
functionalities run `:help cmake`. A quick overview follows.
### Commands and `<Plug>` mappings
| Command | `<Plug>` mapping | Description |
|:--------------------------|:------------------|:--------------------------------------|
| `:CMakeGenerate[!]` | `(CMakeGenerate)` | Generate build system |
| `:CMakeClean` | `(CMakeClean)` | Remove build system and build files |
| `:CMakeBuild[!] [target]` | `(CMakeBuild)` | Build a project |
| `:CMakeInstall` | `(CMakeInstall)` | Install build output |
| `:CMakeSwitch <config>` | `(CMakeSwitch)` | Switch to another build configuration |
| `:CMakeOpen` | `(CMakeOpen)` | Open CMake console window |
| `:CMakeClose` | `(CMakeClose)` | Close CMake console window |
| `:CMakeStop` | `(CMakeStop)` | Stop running command |
### Additional `<Plug>` mappings
| `<Plug>` mapping | Behaves as |
|:---------------------|:------------------------------------------------------|
| `(CMakeBuildTarget)` | `(CMakeBuild)`, but leaves cursor in the command line |
### Key mappings in the CMake console window
| Key mapping | Description |
|:------------|:---------------------------|
| `cg` | Run `:CMakeGenerate` |
| `cb` | Run `:CMakeBuild` |
| `ci` | Run `:CMakeInstall` |
| `cq` | Close CMake console window |
| `<C-C>` | Stop running command |
### Events
Vim-CMake provides a set of custom events to trigger further actions.
Run `:help cmake` for an extensive documentation of all configuration options and examples
| Event | Description |
|:--------------------------------|:------------------------------------------|
| `User CMakeBuildSucceeded` | Triggered after a successful `:CMakeBuild`|
| `User CMakeBuildFailed` | Triggered after a failed `:CMakeBuild` |
### Quickfix list
After each build (e.g. run with `:CMakeBuild`), Vim-CMake populates a quickfix
list to speedup the edit-compile-run cycle, similarly to when running `:make` in
Vim/Neovim. Upon an unsuccessful build, just use the standard quickfix commands
to open the list of errors (e.g. `:copen`) and jump between errors (e.g.
`:cfirst`, `:cnext`).
<!--=========================================================================-->
## Configuration
Vim-CMake has sensible defaults. Again, run `:help cmake` for an extensive
documentation of all the configuration options. A list of default values
follows.
| Options | Default |
|:--------------------------------|:-------------------|
| `g:cmake_command` | `'cmake'` |
| `g:cmake_default_config` | `'Debug'` |
| `g:cmake_build_dir_location` | `'.'` |
| `g:cmake_generate_options` | `[]` |
| `g:cmake_build_options` | `[]` |
| `g:cmake_native_build_options` | `[]` |
| `g:cmake_console_size` | `15` |
| `g:cmake_console_position` | `'botright'` |
| `g:cmake_console_echo_cmd` | `1` |
| `g:cmake_jump` | `0` |
| `g:cmake_jump_on_completion` | `0` |
| `g:cmake_jump_on_error` | `1` |
| `g:cmake_link_compile_commands` | `0` |
| `g:cmake_root_markers` | `['.git', '.svn']` |
| `g:cmake_log_file` | `''` |
<!--=========================================================================-->
## Contributing
Feedback and feature requests are appreciated. Bug reports and pull requests
are very welcome. Check the [Contributing Guidelines][contributing] for how to
write a feature request, post an issue or submit a pull request.
<!--=========================================================================-->
## Related projects
* [vhdirk/vim-cmake][vim-cmake]
* [ilyachur/cmake4vim][cmake4vim]
* [jalcine/cmake.vim][cmake.vim]
* [sigidagi/vim-cmake-project][vim-cmake-project]
* [LucHermitte/vim-build-tools-wrapper][LucHermitte/vim-build-tools-wrapper]
* [kassio/neoterm][neoterm]
<!--=========================================================================-->
## License
Vim-CMake is licensed under the [MIT license][license]. Copyright (c)
2020&ndash;2022 Carlo Delle Donne.
<!--=========================================================================-->
[screencast]: https://user-images.githubusercontent.com/24732205/88468329-18aad100-cee2-11ea-94f4-f2ac59a2e6b9.gif
[vim-cmake]: https://github.com/vhdirk/vim-cmake
[cmake4vim]: https://github.com/ilyachur/cmake4vim
[cmake.vim]: https://github.com/jalcine/cmake.vim
[vim-cmake-project]: https://github.com/sigidagi/vim-cmake-project
[LucHermitte/vim-build-tools-wrapper]: https://github.com/LucHermitte/vim-build-tools-wrapper
[neoterm]: https://github.com/kassio/neoterm
[vim-plug]: https://github.com/junegunn/vim-plug
[oos]: https://cprieto.com/posts/2016/10/cmake-out-of-source-build.html
[contributing]: ./CONTRIBUTING.md
[license]: ./LICENSE

View file

@ -0,0 +1,135 @@
" ==============================================================================
" Location: autoload/cmake.vim
" Description: API functions and global data for Vim-CMake
" ==============================================================================
let s:buildsys = cmake#buildsys#Get()
let s:build = cmake#build#Get()
let s:const = cmake#const#Get()
let s:logger = cmake#logger#Get()
let s:terminal = cmake#terminal#Get()
" Print news of new Vim-CMake versions.
call cmake#util#PrintNews(s:const.plugin_version, s:const.plugin_news)
" Log config options.
call s:logger.LogInfo('Configuration options:')
for s:cvar in sort(keys(s:const.config_vars))
call s:logger.LogInfo('> g:%s: %s', s:cvar, string(g:[s:cvar]))
endfor
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" API functions
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" API function for :CMakeGenerate and <Plug>(CMakeGenerate).
"
" Params:
" clean : Number
" whether to clean before generating
" a:1 : String
" (optional) build configuration and additional CMake options
"
function! cmake#Generate(clean, ...) abort
call s:logger.LogDebug('API invoked: cmake#Generate(%s, %s)', a:clean, a:000)
call s:buildsys.Generate(a:clean, join(a:000))
endfunction
" API function for :CMakeClean and <Plug>(CMakeClean).
"
function! cmake#Clean() abort
call s:logger.LogDebug('API invoked: cmake#Clean()')
call s:buildsys.Clean()
endfunction
" API function for :CMakeSwitch.
"
" Params:
" a:1 : String
" build configuration
"
function! cmake#Switch(...) abort
call s:logger.LogDebug('API invoked: cmake#Switch(%s)', string(a:1))
call s:buildsys.Switch(a:1)
endfunction
" API function for completion for :CMakeSwitch.
"
" Params:
" arg_lead : String
" the leading portion of the argument currently being completed
" cmd_line : String
" the entire command line
" cursor_pos : Number
" the cursor position in the command line (byte index)
"
" Returns:
" String
" stringified list of existing configuration directories
"
function! cmake#GetConfigs(arg_lead, cmd_line, cursor_pos) abort
call s:logger.LogDebug('API invoked: cmake#GetConfigs()')
return join(s:buildsys.GetConfigs(), "\n")
endfunction
" API function for :CMakeBuild and <Plug>(CMakeBuild).
"
" Params:
" clean : Number
" whether to clean before building
" a:1 : String
" (optional) target and other build options
"
function! cmake#Build(clean, ...) abort
call s:logger.LogDebug('API invoked: cmake#Build(%s, %s)', a:clean, a:000)
call s:build.Build(a:clean, join(a:000))
endfunction
" API function for :CMakeInstall and <Plug>(CMakeInstall).
"
function! cmake#Install() abort
call s:logger.LogDebug('API invoked: cmake#Install()')
call s:build.Install()
endfunction
" API function for completion for :CMakeBuild.
"
" API function for completion for :CMakeBuild.
"
" Params:
" arg_lead : String
" the leading portion of the argument currently being completed
" cmd_line : String
" the entire command line
" cursor_pos : Number
" the cursor position in the command line (byte index)
"
" Returns:
" String
" available targets, one per line
"
function! cmake#GetBuildTargets(arg_lead, cmd_line, cursor_pos) abort
call s:logger.LogDebug('API invoked: cmake#GetBuildTargets()')
return join(s:buildsys.GetTargets(), "\n")
endfunction
" API function for :CMakeStop.
"
function! cmake#Stop() abort
call s:logger.LogDebug('API invoked: cmake#Stop()')
call s:terminal.Stop()
endfunction
" API function for :CMakeOpen.
"
function! cmake#Open() abort
call s:logger.LogDebug('API invoked: cmake#Open()')
call s:terminal.Open(v:false)
endfunction
" API function for :CMakeClose.
"
function! cmake#Close() abort
call s:logger.LogDebug('API invoked: cmake#Close()')
call s:terminal.Close()
endfunction

View file

@ -0,0 +1,128 @@
" ==============================================================================
" Location: autoload/cmake/build.vim
" Description: Functions for building a project
" ==============================================================================
let s:build = {}
let s:buildsys = cmake#buildsys#Get()
let s:const = cmake#const#Get()
let s:logger = cmake#logger#Get()
let s:quickfix = cmake#quickfix#Get()
let s:system = cmake#system#Get()
let s:terminal = cmake#terminal#Get()
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Private functions and callbacks
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Get dictionary of build arguments from command-line string.
"
" Params:
" argstring : String
" command-line arguments, like target and additional build options
"
" Returns:
" Dictionary
" CMake build options, target and native options
"
" Example:
" argstring = --jobs 4 all -- VERBOSE=1
" return = {
" \ 'cmake_build_options': ['--jobs', '4'],
" \ 'target': ['--target', 'all'],
" \ 'native_build_options': ['VERBOSE=1']
" \ }
"
function! s:GetBuildArgs(argstring) abort
let l:argdict = {}
let l:arglist = split(a:argstring)
" Search arguments for one that matches the name of a target.
for l:t in s:buildsys.GetTargets()
let l:match_res = match(l:arglist, '\m\C^' . l:t)
if l:match_res != -1
" If found, get target and remove from list of arguments.
let l:target = l:arglist[l:match_res]
let l:argdict['target'] = ['--target', l:target]
call remove(l:arglist, l:match_res)
break
endif
endfor
" Search for command-line native build tool arguments.
let l:match_res = match(l:arglist, '\m\C^--$')
if l:match_res != -1
" Get command-line native build tool arguments and remove from list.
let l:argdict['native_build_options'] = l:arglist[l:match_res+1:]
" Remove from list of other arguments.
call remove(l:arglist, l:match_res, -1)
endif
" Get command-line CMake arguments.
let l:argdict['cmake_build_options'] = l:arglist
return l:argdict
endfunction
" Generate quickfix list after running build command.
"
function! s:GenerateQuickfix() abort
call s:quickfix.Generate(s:terminal.GetOutput())
endfunction
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Public functions
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Build a project using the generated buildsystem.
"
" Params:
" clean : Boolean
" whether to clean before building
" argstring : String
" build target and other options
"
function! s:build.Build(clean, argstring) abort
call s:logger.LogDebug('Invoked: build.Build(%s, %s)',
\ a:clean, string(a:argstring))
let l:path_to_current_config = s:buildsys.GetPathToCurrentConfig()
let l:build_dir = s:system.Path([l:path_to_current_config], v:true)
let l:command = [g:cmake_command, '--build', l:build_dir]
let l:options = {}
" Parse additional options.
let l:options = s:GetBuildArgs(a:argstring)
" Add CMake build options to the command.
let l:command += g:cmake_build_options
let l:command += get(l:options, 'cmake_build_options', [])
if a:clean
let l:command += ['--clean-first']
endif
" Add target to the command, if any was provided.
let l:command += get(l:options, 'target', [])
" Add native build tool options to the command.
if len(g:cmake_native_build_options) > 0 ||
\ len(get(l:options, 'native_build_options', [])) > 0
let l:command += ['--']
let l:command += g:cmake_native_build_options
let l:command += get(l:options, 'native_build_options', [])
endif
" Run build command.
call s:terminal.Run(l:command, 'build',
\ [function('s:GenerateQuickfix')],
\ [function('s:GenerateQuickfix')],
\ ['CMakeBuildSucceeded'], ['CMakeBuildFailed']
\ )
endfunction
" Install a project.
"
function! s:build.Install() abort
call s:logger.LogDebug('Invoked: build.Install()')
let l:path_to_current_config = s:buildsys.GetPathToCurrentConfig()
let l:build_dir = s:system.Path([l:path_to_current_config], v:true)
let l:command = [g:cmake_command, '--install', l:build_dir]
call s:terminal.Run(l:command, 'install', [], [], [], [])
endfunction
" Get build 'object'.
"
function! cmake#build#Get() abort
return s:build
endfunction

View file

@ -0,0 +1,443 @@
" ==============================================================================
" Location: autoload/cmake/buildsys.vim
" Description: Functions for generating the buildsystem
" ==============================================================================
let s:buildsys = {}
let s:buildsys.cmake_version = 0
let s:buildsys.project_root = ''
let s:buildsys.current_config = ''
let s:buildsys.path_to_current_config = ''
let s:buildsys.configs = []
let s:buildsys.targets = []
let s:logger = cmake#logger#Get()
let s:statusline = cmake#statusline#Get()
let s:system = cmake#system#Get()
let s:terminal = cmake#terminal#Get()
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Private functions
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Find project root by looking for g:cmake_root_markers upwards.
"
" Returns:
" String
" escaped path to the root of the project
"
function! s:FindProjectRoot() abort
let l:root = getcwd()
let l:escaped_cwd = fnameescape(getcwd())
for l:marker in g:cmake_root_markers
" Search CWD upward for l:marker, assuming it is a file.
let l:marker_path = findfile(l:marker, l:escaped_cwd . ';' . $HOME)
if len(l:marker_path) > 0
" If found, strip l:marker from it.
let l:root = fnamemodify(l:marker_path, ':h')
break
endif
" Search CWD upward for l:marker, assuming it is a directory.
let l:marker_path = finddir(l:marker, l:escaped_cwd . ';' . $HOME)
if len(l:marker_path) > 0
" If found, strip l:marker from it.
let l:root = fnamemodify(l:marker_path, ':h')
break
endif
endfor
return l:root
endfunction
" Get absolute path to location where the build directory is located.
"
" Returns:
" String
" path to build directory location
"
function! s:GetBuildDirLocation() abort
return s:system.Path(
\ [s:buildsys.project_root, g:cmake_build_dir_location], v:false)
endfunction
" Find CMake variable in list of options.
"
" Params:
" opts : List
" list of options
" variable : String
" variable to find
"
" Returns:
" String
" value of the CMake variable, or an empty string if the variable was
" not found
"
" Example:
" to find the variable 'CMAKE_BUILD_TYPE', which would be passed by the user
" as '-D CMAKE_BUILD_TYPE=<value>', call
" s:FindVarInOpts(opts, 'CMAKE_BUILD_TYPE')
"
function! s:FindVarInOpts(opts, variable) abort
if len(a:opts) > 0
" Search the list of command-line options for an entry matching
" '-D <variable>=<value>' or '-D <variable>:<type>=<value>' or
" '-D<variable>=<value>' or '-D<variable>:<type>=<value>'.
let l:opt = matchstr(a:opts, '\m\C-D\s*' . a:variable)
" If found, return the value, otherwise return an empty string.
if len(l:opt) > 0
return split(l:opt, '=')[1]
else
return ''
endif
endif
endfunction
" Process build configuration.
"
" Params:
" opts : List
" list of options
"
function! s:ProcessBuildConfig(opts) abort
let l:config = s:buildsys.current_config
" Check if the first entry of the list of command-line options starts with a
" letter (and not with a dash), in which case the user will have passed the
" name of the build configuration as the first option.
if (len(a:opts) > 0) && (match(a:opts[0], '\m\C^\w') >= 0)
" Update build config name and remove from list of options.
let l:config = a:opts[0]
call s:SetCurrentConfig(l:config)
call remove(a:opts, 0)
endif
" If the list of command-line options does not contain an explicit value for
" the 'CMAKE_BUILD_TYPE' variable, add it.
if s:FindVarInOpts(a:opts, 'CMAKE_BUILD_TYPE') ==# ''
call add(a:opts, '-D CMAKE_BUILD_TYPE=' . l:config)
endif
endfunction
" Get list of command-line options from string of arguments.
"
" Params:
" argstring : String
" string containing command-line arguments
"
" Returns:
" List
" list of unprocessed command-line options
"
" Example:
" an argument string like the following
" 'Debug -D VAR_A=1 -DVAR_B=0 -Wdev -U VAR_C'
" results in a list of options like the following
" ['Debug', '-D VAR_A=1', '-DVAR_B=0', '-Wdev', '-U VAR_C']
"
function! s:ArgStringToOptList(argstring) abort
let l:opts = []
for l:arg in split(a:argstring)
" If list of options is empty, append first argument.
if len(l:opts) == 0
call add(l:opts, l:arg)
" If argument starts with a dash, append it to the list of options.
elseif match(l:arg, '\m\C^-') >= 0
call add(l:opts, l:arg)
" If argument does not start with a dash, it must belong to the last
" option that was added to the list, thus extend that option.
else
let l:opts[-1] = join([l:opts[-1], l:arg])
endif
endfor
return l:opts
endfunction
" Process string of arguments and return parsed options.
"
" Params:
" argstring : String
" string containing command-line arguments
"
" Returns:
" Dictionary
" opts : List
" list of options
" source_dir : String
" path to source directory
" build_dir : String
" path to build directory
"
function! s:ProcessArgString(argstring) abort
let l:opts = s:ArgStringToOptList(a:argstring)
call s:ProcessBuildConfig(l:opts)
" If compile commands are to be exported, and the
" 'CMAKE_EXPORT_COMPILE_COMMANDS' variable is not set, set it.
if g:cmake_link_compile_commands
if s:FindVarInOpts(l:opts, 'CMAKE_EXPORT_COMPILE_COMMANDS') ==# ''
call add(l:opts, '-D CMAKE_EXPORT_COMPILE_COMMANDS=ON')
endif
endif
" Set source and build directories. Must be done after processing the build
" configuration so that the current build configuration is up to date before
" setting the build directory.
let l:source_dir = s:system.Path([s:buildsys.project_root], v:true)
let l:build_dir = s:system.Path([s:buildsys.path_to_current_config], v:true)
" Return dictionary of options.
let l:optdict = {}
let l:optdict.opts = l:opts
let l:optdict.source_dir = l:source_dir
let l:optdict.build_dir = l:build_dir
return l:optdict
endfunction
" Refresh list of build configuration directories.
"
function! s:RefreshConfigs() abort
" List of directories inside of which a CMakeCache file is found.
let l:cache_dirs = findfile(
\ 'CMakeCache.txt',
\ s:GetBuildDirLocation() . '/**1',
\ -1)
" Transform paths to just names of directories. These will be the names of
" existing configuration directories.
call map(l:cache_dirs, {_, val -> fnamemodify(val, ':h:t')})
let s:buildsys.configs = l:cache_dirs
call s:logger.LogDebug('Build configs: %s', s:buildsys.configs)
endfunction
" Callback for RefreshTargets().
"
function! s:RefreshTargetsCb(...) abort
let l:data = s:system.ExtractStdoutCallbackData(a:000)
for l:line in l:data
if match(l:line, '\m\C\.\.\.\s') == 0
let l:target = split(l:line)[1]
let s:buildsys.targets += [l:target]
endif
endfor
endfunction
" Refresh list of available CMake targets.
"
function! s:RefreshTargets() abort
let s:buildsys.targets = []
let l:build_dir = s:buildsys.path_to_current_config
let l:command = [g:cmake_command,
\ '--build', l:build_dir,
\ '--target', 'help'
\ ]
call s:system.JobRun(
\ l:command, v:true, function('s:RefreshTargetsCb'), v:null, v:false)
endfunction
" Check if build configuration directory exists.
"
" Params:
" config : String
" configuration to check
"
" Returns:
" Boolean
" v:true if the build configuration exists, v:false otherwise
"
function! s:ConfigExists(config) abort
return index(s:buildsys.configs, a:config) >= 0
endfunction
" Set current build configuration.
"
" Params:
" config : String
" build configuration name
"
function! s:SetCurrentConfig(config) abort
let s:buildsys.current_config = a:config
let l:path = s:system.Path([s:GetBuildDirLocation(), a:config], v:false)
let s:buildsys.path_to_current_config = l:path
call s:logger.LogInfo('Current config: %s (%s)',
\ s:buildsys.current_config,
\ s:buildsys.path_to_current_config
\ )
call s:statusline.SetBuildInfo(s:buildsys.current_config)
endfunction
" Link compile commands from source directory to build directory.
"
function! s:LinkCompileCommands() abort
if !g:cmake_link_compile_commands
return
endif
let l:target = s:system.Path(
\ [s:buildsys.path_to_current_config, 'compile_commands.json'],
\ v:true
\ )
let l:link = s:system.Path(
\ [s:buildsys.project_root, 'compile_commands.json'],
\ v:true,
\ )
let l:command = [g:cmake_command, '-E', 'create_symlink', l:target, l:link]
call s:system.JobRun(l:command, v:true, v:null, v:null, v:false)
endfunction
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Public functions
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Generate a buildsystem for the project using CMake.
"
" Params:
" clean : Boolean
" whether to clean before generating
" argstring : String
" build configuration and additional CMake options
"
function! s:buildsys.Generate(clean, argstring) abort
call s:logger.LogDebug('Invoked: buildsys.Generate(%s, %s)',
\ a:clean, string(a:argstring))
let l:command = [g:cmake_command]
let l:optdict = s:ProcessArgString(a:argstring)
" Construct command.
call extend(l:command, g:cmake_generate_options)
call extend(l:command, l:optdict.opts)
if l:self.cmake_version < 313
call add(l:command, '-H' . l:optdict.source_dir)
call add(l:command, '-B' . l:optdict.build_dir)
else
call add(l:command, '-S ' . l:optdict.source_dir)
call add(l:command, '-B ' . l:optdict.build_dir)
endif
" Clean project buildsystem, if requested.
if a:clean
call l:self.Clean()
endif
" Run generate command.
call s:terminal.Run(
\ l:command, 'generate',
\ [
\ function('s:RefreshConfigs'),
\ function('s:RefreshTargets'),
\ function('s:LinkCompileCommands')
\ ],
\ [function('s:RefreshConfigs')],
\ [], []
\ )
endfunction
" Clean buildsystem.
"
function! s:buildsys.Clean() abort
call s:logger.LogDebug('Invoked: buildsys.Clean()')
if isdirectory(l:self.path_to_current_config)
call delete(l:self.path_to_current_config, 'rf')
endif
call s:RefreshConfigs()
endfunction
" Set current build configuration after checking that the configuration exists.
"
" Params:
" config : String
" build configuration name
"
function! s:buildsys.Switch(config) abort
call s:logger.LogDebug('Invoked: buildsys.Switch(%s)', a:config)
" Check that config exists.
if !s:ConfigExists(a:config)
call s:logger.EchoError(
\ "Build configuration '%s' not found, run ':CMakeGenerate %s'",
\ a:config, a:config)
call s:logger.LogError(
\ "Build configuration '%s' not found, run ':CMakeGenerate %s'",
\ a:config, a:config)
return
endif
call s:SetCurrentConfig(a:config)
call s:LinkCompileCommands()
endfunction
" Get list of configuration directories (containing a buildsystem).
"
" Returns:
" List
" list of existing configuration directories
"
function! s:buildsys.GetConfigs() abort
return l:self.configs
endfunction
" Get list of available build targets.
"
" Returns:
" List
" list of available build targets
"
function! s:buildsys.GetTargets() abort
if len(l:self.targets) == 0
call s:RefreshTargets()
endif
return l:self.targets
endfunction
" Get current build configuration.
"
" Returns:
" String
" build configuration
"
function! s:buildsys.GetCurrentConfig() abort
return l:self.current_config
endfunction
" Get path to CMake source directory of current project.
"
" Returns:
" String
" path to CMake source directory
"
function! s:buildsys.GetSourceDir() abort
return l:self.project_root
endfunction
" Get path to current build configuration.
"
" Returns:
" String
" path to build configuration
"
function! s:buildsys.GetPathToCurrentConfig() abort
return l:self.path_to_current_config
endfunction
" Get buildsys 'object'.
"
function! cmake#buildsys#Get() abort
return s:buildsys
endfunction
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Initialization
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function! s:GetCMakeVersionCb(...) abort
let l:data = s:system.ExtractStdoutCallbackData(a:000)
for l:line in l:data
if match(l:line, '\m\C^cmake\S* version') == 0
let l:version_str = split(split(l:line)[2], '\.')
let l:major = str2nr(l:version_str[0])
let l:minor = str2nr(l:version_str[1])
let s:buildsys.cmake_version = l:major * 100 + l:minor
break
endif
endfor
endfunction
" Get CMake version. The version is stored as MAJOR * 100 + MINOR (e.g., version
" 3.13.3 would result in 313).
let s:command = [g:cmake_command, '--version']
call s:system.JobRun(
\ s:command, v:true, function('s:GetCMakeVersionCb'), v:null, v:false)
" Must be done before any other initial configuration.
let s:buildsys.project_root = s:system.Path([s:FindProjectRoot()], v:false)
call s:logger.LogInfo('Project root: %s', s:buildsys.project_root)
call s:SetCurrentConfig(g:cmake_default_config)
call s:RefreshConfigs()

View file

@ -0,0 +1,47 @@
" ==============================================================================
" Location: autoload/cmake/const.vim
" Description: Constants and definitions
" ==============================================================================
let s:const = {}
let s:const.plugin_version = '0.7.1'
let s:const.plugin_news = {
\ '0.2.0': ['Vim-CMake has a new feature, run `:help cmake-switch`'],
\ '0.3.0': ['Vim-CMake has a new feature, run `:help cmake-quickfix`'],
\ '0.4.0': ['Vim-CMake has a new config option `g:cmake_generate_options`'],
\ '0.5.0': ['Vim-CMake has a new feature, run `:help cmake-events`'],
\ '0.6.0': [
\ 'Vim-CMake has a new config option `g:cmake_build_dir_location`',
\ 'Vim-CMake has improved :CMakeGenerate, run `:help cmake-generate`'
\ ],
\ '0.7.0': [
\ 'Vim-CMake has new command `:CMakeStop`, run `:help cmake-stop`',
\ 'Vim-CMake has a new config option `g:cmake_console_echo_cmd`'
\ ],
\ }
let s:const.config_vars = {
\ 'cmake_command' : 'cmake',
\ 'cmake_default_config' : 'Debug',
\ 'cmake_build_dir_location' : '.',
\ 'cmake_generate_options' : [],
\ 'cmake_build_options' : [],
\ 'cmake_native_build_options' : [],
\ 'cmake_console_size' : 15,
\ 'cmake_console_position' : 'botright',
\ 'cmake_console_echo_cmd' : 1,
\ 'cmake_jump' : 0,
\ 'cmake_jump_on_completion' : 0,
\ 'cmake_jump_on_error' : 1,
\ 'cmake_link_compile_commands' : 0,
\ 'cmake_root_markers' : ['.git', '.svn'],
\ 'cmake_log_file' : '',
\ }
" Get const 'object'.
"
function! cmake#const#Get() abort
return s:const
endfunction

View file

@ -0,0 +1,132 @@
" ==============================================================================
" Location: autoload/cmake/logger.vim
" Description: Logger
" ==============================================================================
let s:logger = {}
function! s:Echo(fmt, arglist) abort
" Trick to convert list (a:arglist) into arguments for printf().
let l:PrintfPartial = function('printf', [a:fmt] + a:arglist)
echomsg '[Vim-CMake] ' . l:PrintfPartial()
endfunction
function! s:Log(fmt, level, arglist) abort
" Trick to convert list (a:arglist) into arguments for printf().
let l:PrintfPartial = function('printf', [a:fmt] + a:arglist)
let l:logstring = printf(
\ '[%s] [%5s] %s',
\ strftime('%Y-%m-%d %T'),
\ a:level,
\ l:PrintfPartial()
\ )
call writefile([l:logstring], g:cmake_log_file, 'a')
endfunction
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Public functions
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Log a debug message.
"
" Params:
" fmt : String
" printf-like format string (see :help printf())
" ... :
" list of arguments to replace placeholders in format string
"
function! s:logger.LogDebug(fmt, ...) abort
if g:cmake_log_file !=# ''
call s:Log(a:fmt, 'DEBUG', a:000)
end
endfunction
" Log an information message.
"
" Params:
" fmt : String
" printf-like format string (see :help printf())
" ... :
" list of arguments to replace placeholders in format string
"
function! s:logger.LogInfo(fmt, ...) abort
if g:cmake_log_file !=# ''
call s:Log(a:fmt, 'INFO', a:000)
end
endfunction
" Log a warning message.
"
" Params:
" fmt : String
" printf-like format string (see :help printf())
" ... :
" list of arguments to replace placeholders in format string
"
function! s:logger.LogWarn(fmt, ...) abort
if g:cmake_log_file !=# ''
call s:Log(a:fmt, 'WARN', a:000)
end
endfunction
" Log an error message.
"
" Params:
" fmt : String
" printf-like format string (see :help printf())
" ... :
" list of arguments to replace placeholders in format string
"
function! s:logger.LogError(fmt, ...) abort
if g:cmake_log_file !=# ''
call s:Log(a:fmt, 'ERROR', a:000)
end
endfunction
" Echo an information message.
"
" Params:
" fmt : String
" printf-like format string (see :help printf())
" ... :
" list of arguments to replace placeholders in format string
"
function! s:logger.EchoInfo(fmt, ...) abort
echohl MoreMsg
call s:Echo(a:fmt, a:000)
echohl None
endfunction
" Echo a warning message.
"
" Params:
" fmt : String
" printf-like format string (see :help printf())
" ... :
" list of arguments to replace placeholders in format string
"
function! s:logger.EchoWarn(fmt, ...) abort
echohl WarningMsg
call s:Echo(a:fmt, a:000)
echohl None
endfunction
" Echo an error message.
"
" Params:
" fmt : String
" printf-like format string (see :help printf())
" ... :
" list of arguments to replace placeholders in format string
"
function! s:logger.EchoError(fmt, ...) abort
echohl Error
call s:Echo(a:fmt, a:000)
echohl None
endfunction
" Get logger 'object'
"
function! cmake#logger#Get() abort
return s:logger
endfunction

View file

@ -0,0 +1,56 @@
" ==============================================================================
" Location: autoload/cmake/quickfix.vim
" Description: Functions for populating the quickfix window
" ==============================================================================
let s:quickfix = {}
let s:quickfix.list = {}
let s:quickfix.list.items = []
let s:quickfix.list.title = 'CMakeBuild'
let s:quickfix.id = -1
let s:filters = [
\ 'v:val.valid == 1',
\ 'filereadable(bufname(v:val.bufnr))',
\ ]
let s:logger = cmake#logger#Get()
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Public functions
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Generate Quickfix list from lines
"
" Params:
" lines_to_parse : List
" list of lines to parse to generate Quickfix list
"
function! s:quickfix.Generate(lines_to_parse) abort
call s:logger.LogDebug('Invoked: s:quickfix.Generate()')
" Create a list of quickfix items from the output of the last command.
let l:list = getqflist({'lines': a:lines_to_parse})
let l:self.list.items = filter(l:list.items, join(s:filters, ' && '))
" If a quickfix list for Vim-CMake exists, make that list active and replace
" its items with the new ones.
if getqflist({'id': l:self.id}).id == l:self.id
let l:current = getqflist({'nr': 0}).nr
let l:target = getqflist({'id': l:self.id, 'nr': 0}).nr
if l:current > l:target
execute 'silent colder ' . (l:current - l:target)
elseif l:current < l:target
execute 'silent cnewer ' . (l:target - l:current)
endif
call setqflist([], 'r', {'items': l:self.list.items})
call s:logger.LogDebug('Replaced existing Quickfix list')
" Otherwise, create a new quickfix list.
else
call setqflist([], ' ', l:self.list)
call s:logger.LogDebug('Created new Quickfix list')
endif
let l:self.id = getqflist({'nr': 0, 'id': 0}).id
endfunction
function! cmake#quickfix#Get() abort
return s:quickfix
endfunction

View file

@ -0,0 +1,84 @@
" ==============================================================================
" Location: autoload/cmake/statusline.vim
" Description: Functions for handling statusline information
" ==============================================================================
let s:statusline = {}
let s:statusline.build_info = ''
let s:statusline.cmd_info = ''
let s:logger = cmake#logger#Get()
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Public functions
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Set build info string for statusline/airline.
"
" Params:
" build_info : String
" statusline build info
"
function! s:statusline.SetBuildInfo(build_info) abort
call s:logger.LogDebug('Invoked: statusline.SetBuildInfo(%s)', a:build_info)
let l:self.build_info = a:build_info
endfunction
" Set command info string for statusline/airline.
"
" Params:
" cmd_info : String
" statusline command info
"
function! s:statusline.SetCmdInfo(cmd_info) abort
call s:logger.LogDebug('Invoked: statusline.SetCmdInfo(%s)', a:cmd_info)
let l:self.cmd_info = a:cmd_info
endfunction
" Force a refresh of the statusline/airline.
"
function! s:statusline.Refresh() abort
if exists('g:loaded_airline') && g:loaded_airline
execute 'AirlineRefresh!'
else
execute 'redrawstatus!'
endif
endfunction
" Get build info string for statusline/airline.
"
" Params:
" active : Number
" whether called for the statusline of an active window
"
" Returns:
" String
" statusline build info
"
function! cmake#statusline#GetBuildInfo(active) abort
if a:active
return s:statusline.build_info
else
return '[' . s:statusline.build_info . ']'
endif
endfunction
" Get command info string for statusline/airline.
"
" Returns:
" String
" statusline command info (command currently running)
"
function! cmake#statusline#GetCmdInfo() abort
if len(s:statusline.cmd_info) > 0
return s:statusline.cmd_info
else
return ' '
endif
endfunction
" Get statusline 'object'.
"
function! cmake#statusline#Get() abort
return s:statusline
endfunction

View file

@ -0,0 +1,256 @@
" ==============================================================================
" Location: autoload/cmake/system.vim
" Description: System abstraction layer
" ==============================================================================
let s:system = {}
let s:stdout_partial_line = {}
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Private functions
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function! s:ManipulateCommand(command) abort
let l:ret_command = []
for l:arg in a:command
" Remove double quotes around argument that are quoted. For instance,
" '-G "Unix Makefiles"' results in '-G Unix Makefiles'.
let l:quotes_regex = '\m\C\(^\|[^"\\]\)"\([^"]\|$\)'
let l:arg = substitute(l:arg, l:quotes_regex, '\1\2', 'g')
" Split arguments that are composed of an option (short '-O' or long
" '--option') and a follow-up string, where the option and the string
" are separated by a space.
let l:split_regex = '\m\C^\(-\w\|--\w\+\)\s\(.\+\)'
let l:match_list = matchlist(l:arg, l:split_regex)
if len(l:match_list) > 0
call add(l:ret_command, l:match_list[1])
call add(l:ret_command, l:match_list[2])
else
call add(l:ret_command, l:arg)
endif
endfor
return l:ret_command
endfunction
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Public functions
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Generate escaped path string from list of components.
"
" Params:
" components : List
" list of path components (strings)
" relative : Boolean
" whether to have the path relative to the current directory or absolute
"
" Returns:
" String
" escaped path string with appropriate path separators
"
function! s:system.Path(components, relative) abort
let l:components = a:components
let l:separator = has('win32') ? '\' : '/'
" Join path components and get absolute path.
let l:path = join(l:components, l:separator)
let l:path = simplify(l:path)
let l:path = fnamemodify(l:path, ':p')
" If path ends with separator, remove separator from path.
if match(l:path, '\m\C\' . l:separator . '$') != -1
let l:path = fnamemodify(l:path, ':h')
endif
" Reduce to relative path if requested.
if a:relative
" For some reason, reducing the path to relative returns an empty string
" if the path happens to be the same as CWD. Thus, only reduce the path
" to relative when it is not CWD, otherwise just return '.'.
if l:path ==# getcwd()
let l:path = '.'
else
let l:path = fnamemodify(l:path, ':.')
endif
endif
" Simplify and escape path.
let l:path = simplify(l:path)
let l:path = fnameescape(l:path)
return l:path
endfunction
" Run arbitrary job in the background.
"
" Params:
" command : List
" the command to be run, as a list of command and arguments
" wait : Boolean
" whether to wait for completion
" stdout_cb : Funcref
" stdout callback (can be v:null), which should take a variable number
" of arguments, and from which s:system.ExtractStdoutCallbackData(a:000)
" can be called to retrieve the stdout string
" exit_cb : Funcref
" exit callback (can be v:null), which should take a variable number of
" arguments, and from which s:system.ExtractExitCallbackData(a:000) can
" be called to retrieve the exit code
" pty : Boolean
" whether to allocate a pseudo terminal for the job
"
" Return:
" Number
" job id
"
function! s:system.JobRun(command, wait, stdout_cb, exit_cb, pty) abort
let l:options = {}
let l:options['pty'] = a:pty
let l:command = s:ManipulateCommand(a:command)
if has('nvim')
if a:stdout_cb isnot# v:null
let l:options['on_stdout'] = a:stdout_cb
endif
if a:exit_cb isnot# v:null
let l:options['on_exit'] = a:exit_cb
endif
" In some cases, the PTY in MS-Windows (ConPTY) uses ANSI escape
" sequences to move the cursor position (ESC[<n>;<m>H) rather than
" inseting newline characters. Setting the width of the PTY to be very
" large and the height to be as small as possible (but larger than 1)
" seems to circumvent this problem. Hacky, but it seems to work.
if has('win32')
let l:options['width'] = 10000
let l:options['height'] = 2
endif
let l:job_id = jobstart(l:command, l:options)
else
if a:stdout_cb isnot# v:null
let l:options['out_cb'] = a:stdout_cb
endif
if a:exit_cb isnot# v:null
let l:options['exit_cb'] = a:exit_cb
endif
let l:job_id = job_start(l:command, l:options)
endif
" Wait for job to complete, if requested.
if a:wait
call l:self.JobWait(l:job_id)
endif
return l:job_id
endfunction
" Wait for job to complete.
"
" Params:
" job_id : Number
" job id
"
function! s:system.JobWait(job_id) abort
if has('nvim')
call jobwait([a:job_id])
else
while job_status(a:job_id) ==# 'run'
execute 'sleep 5m'
endwhile
endif
endfunction
" Wait for job's channel to be closed.
"
" Params:
" job_id : Number
" job id
"
function! s:system.ChannelWait(job_id) abort
" Only makes sense in Vim currently.
if !has('nvim')
let l:chan_id = job_getchannel(a:job_id)
while ch_status(l:chan_id, {'part': 'out'}) !=# 'closed'
execute 'sleep 5m'
endwhile
endif
endfunction
" Stop job.
"
" Params:
" job_id : Number
" job id
"
function! s:system.JobStop(job_id) abort
try
if has('nvim')
call jobstop(a:job_id)
else
call job_stop(a:job_id)
endif
catch /.*/
endtry
endfunction
" Extract data from a job's stdout callback.
"
" Params:
" cb_arglist : List
" variable-size list of arguments as passed to the callback, which will
" differ between Neovim and Vim
"
" Returns:
" List
" stdout data, as a list of strings
"
function! s:system.ExtractStdoutCallbackData(cb_arglist) abort
let l:channel = a:cb_arglist[0]
let l:data = a:cb_arglist[1]
if has('nvim')
let l:eof = (l:data == [''])
" In Neovim, remove all the CR characters, which are returned when a
" pseudo terminal is allocated for the job.
call map(l:data, {_, val -> substitute(val, '\m\C\r', '', 'g')})
" The first and the last lines may be partial lines, thus they need to
" be joined on consecutive iterations. See :help channel-lines.
" When this function is called for the first time for a particular
" channel, allocate an empty partial line for that channel.
if !has_key(s:stdout_partial_line, l:channel)
let s:stdout_partial_line[l:channel] = ''
endif
" Append first entry of output list to partial line.
let s:stdout_partial_line[l:channel] .= remove(l:data, 0)
" If output list contains more entries, they are all complete lines
" except for the last entry. Return the saved partial line (which is now
" complete) and all the complete lines from the list, and save a new
" partial line (the last entry of the list).
if len(l:data) > 0
call insert(l:data, s:stdout_partial_line[l:channel])
let s:stdout_partial_line[l:channel] = remove(l:data, -1)
endif
" At the end of the stream of a channel, remove the dictionary entry for
" that channel.
if l:eof
call remove(s:stdout_partial_line, l:channel)
endif
else
" In Vim, l:data is a string, so we transform it to a list (consisting
" of a single element).
let l:data = [l:data]
endif
return l:data
endfunction
" Extract data from a system's exit callback.
"
" Params:
" cb_arglist : List
" variable-size list of arguments as passed to the callback, which will
" differ between Neovim and Vim
"
" Returns:
" Number
" exit code
"
function! s:system.ExtractExitCallbackData(cb_arglist) abort
return a:cb_arglist[1]
endfunction
" Get system 'object'.
"
function! cmake#system#Get() abort
return s:system
endfunction

View file

@ -0,0 +1,472 @@
" ==============================================================================
" Location: autoload/cmake/terminal.vim
" Description: Terminal abstraction layer
" ==============================================================================
let s:terminal = {}
let s:terminal.console_buffer = -1
let s:terminal.console_cmd_info = {
\ 'generate': 'Generating buildsystem...',
\ 'build': 'Building...',
\ 'install': 'Installing...',
\ 'NONE': '',
\ }
let s:terminal.console_cmd = {
\ 'id': -1,
\ 'running': v:false,
\ 'callbacks': [],
\ 'callbacks_err': [],
\ 'autocmds': [],
\ 'autocmds_err': [],
\ }
let s:terminal.console_cmd_output = []
let s:term_tty = ''
let s:term_id = -1
let s:term_chan_id = -1
let s:exit_term_mode = 0
let s:logger = cmake#logger#Get()
let s:statusline = cmake#statusline#Get()
let s:system = cmake#system#Get()
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" ANSI sequence filters
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" https://en.wikipedia.org/wiki/ANSI_escape_code
" https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
let s:ansi_esc = '\e'
let s:ansi_csi = s:ansi_esc . '\['
let s:ansi_st = '\(\%x07\|\\\)'
let s:pre_echo_filter = ''
let s:post_echo_filter = ''
let s:post_echo_rep_pat = ''
let s:post_echo_rep_sub = ''
" In ConPTY (MS-Windows), remove ANSI sequences that mess up the terminal before
" echoing data to the terminal:
" - 'erase screen' sequences
" - 'move cursor' sequences
if has('win32')
let s:pre_echo_filter = s:pre_echo_filter
\ . '\(' . s:ansi_csi . '\d*J' . '\)'
\ . '\|\(' . s:ansi_csi . '\(\d\+;\)*\d*H' . '\)'
endif
" Remove ANSI sequences for coloring and style after echoing to the terminal.
let s:post_echo_filter .= '\(' . s:ansi_csi . '\(\d\+;\)*\d*m' . '\)'
" Remove additional ANSI sequences returened by ConPTY (MS-Windows) after
" echoing to the terminal:
" - 'erase from cursor' sequences
" - 'erase from cursor to EOL' sequences
" - 'hide/show cursor' sequences
" - 'console title' sequences
if has('win32')
let s:post_echo_filter = s:post_echo_filter
\ . '\|\(' . s:ansi_csi . '\d*X' . '\)'
\ . '\|\(' . s:ansi_csi . 'K' . '\)'
\ . '\|\(' . s:ansi_csi . '?25[hl]' . '\)'
\ . '\|\(' . s:ansi_esc . '\]' . '0;.*' . s:ansi_st . '\)'
endif
" Replace 'move forward' sequences with spaces in ConPTY (MS-Windows) after
" echoing to the terminal
if has('win32')
let s:post_echo_rep_pat .= s:ansi_csi . '\(\d*\)C'
let s:post_echo_rep_sub .= '\=repeat('' '', submatch(1))'
endif
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Private functions
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Callback for the stdout of the command running in the Vim-CMake console.
"
function! s:ConsoleCmdStdoutCb(...) abort
let l:data = s:system.ExtractStdoutCallbackData(a:000)
call s:FilterStdoutPreEcho(l:data)
call s:TermEcho(l:data)
call s:FilterStdoutPostEcho(l:data)
" Save console output to list.
let s:terminal.console_cmd_output += l:data
endfunction
" Callback for the end of the command running in the Vim-CMake console.
"
function! s:ConsoleCmdExitCb(...) abort
call s:logger.LogDebug('Invoked console exit callback')
" Waiting for the job's channel to be closed ensures that all output has
" been processed. This is useful in Vim, where buffered stdout may still
" come in after entering this function.
call s:system.ChannelWait(s:terminal.console_cmd.id)
let l:error = s:system.ExtractExitCallbackData(a:000)
call s:OnCompleteCommand(l:error, v:false)
endfunction
" Enter terminal mode.
"
function! s:EnterTermMode() abort
if mode() !=# 't'
execute 'normal! i'
endif
endfunction
" Exit terminal mode.
"
function! s:ExitTermMode() abort
if mode() ==# 't'
call feedkeys("\<C-\>\<C-N>", 'n')
endif
endfunction
" Define actions to perform when completing/stopping a command.
"
function! s:OnCompleteCommand(error, stopped) abort
if a:error == 0
let l:callbacks = s:terminal.console_cmd.callbacks
let l:autocmds = s:terminal.console_cmd.autocmds
else
let l:callbacks = s:terminal.console_cmd.callbacks_err
let l:autocmds = s:terminal.console_cmd.autocmds_err
endif
" Reset state
let s:terminal.console_cmd.id = -1
let s:terminal.console_cmd.running = v:false
let s:terminal.console_cmd.callbacks = []
let s:terminal.console_cmd.callbacks_err = []
let s:terminal.console_cmd.autocmds = []
let s:terminal.console_cmd.autocmds_err = []
" Append empty line to terminal.
call s:TermEcho([''])
" Exit terminal mode if inside the Vim-CMake console window (useful for
" Vim). Otherwise the terminal mode is exited after WinEnter event.
if win_getid() == bufwinid(s:terminal.console_buffer)
call s:ExitTermMode()
else
let s:exit_term_mode = 1
endif
" Update statusline.
call s:statusline.SetCmdInfo(s:terminal.console_cmd_info['NONE'])
call s:statusline.Refresh()
" The rest of the tasks are not to be carried out if the running command was
" stopped by the user.
if a:stopped
return
endif
" Focus Vim-CMake console window, if requested.
if g:cmake_jump_on_completion
call s:terminal.Focus()
else
if a:error != 0 && g:cmake_jump_on_error
call s:terminal.Focus()
endif
endif
" Handle callbacks and autocmds.
" Note: Funcref variable names must start with a capital.
for l:Callback in l:callbacks
call s:logger.LogDebug('Callback invoked: %s()', l:Callback)
call l:Callback()
endfor
for l:autocmd in l:autocmds
call s:logger.LogDebug('Executing autocmd %s', l:autocmd)
execute 'doautocmd <nomodeline> User ' . l:autocmd
endfor
endfunction
" Define actions to perform when entering the Vim-CMake console window.
"
function! s:OnEnterConsoleWindow() abort
if winnr() == bufwinnr(s:terminal.console_buffer) && s:exit_term_mode
let s:exit_term_mode = 0
call s:ExitTermMode()
endif
endfunction
" Start arbitrary command with output to be displayed in Vim-CMake console.
"
" Params:
" command : List
" the command to be run, as a list of command and arguments
"
" Return:
" Number
" job id
"
function! s:ConsoleCmdStart(command) abort
let l:console_win_id = bufwinid(s:terminal.console_buffer)
" For Vim, must go back into Terminal-Job mode for the command's output to
" be appended to the buffer.
if !has('nvim')
call win_execute(l:console_win_id, 'call s:EnterTermMode()', '')
endif
" Run command.
let l:job_id = s:system.JobRun(
\ a:command, v:false, function('s:ConsoleCmdStdoutCb'),
\ function('s:ConsoleCmdExitCb'), v:true)
" For Neovim, scroll manually to the end of the terminal buffer while the
" command's output is being appended.
if has('nvim')
let l:buffer_length = nvim_buf_line_count(s:terminal.console_buffer)
call nvim_win_set_cursor(l:console_win_id, [l:buffer_length, 0])
endif
return l:job_id
endfunction
" Create Vim-CMake window.
"
" Returns:
" Number
" number of the created window
"
function! s:CreateConsoleWindow() abort
execute join([g:cmake_console_position, g:cmake_console_size . 'split'])
setlocal winfixheight
setlocal winfixwidth
call s:logger.LogDebug('Created console window')
endfunction
" Create Vim-CMake buffer and apply local settings.
"
" Returns:
" Number
" number of the created buffer
"
function! s:CreateConsoleBuffer() abort
execute 'enew'
call s:TermSetup()
nnoremap <buffer> <silent> cg :CMakeGenerate<CR>
nnoremap <buffer> <silent> cb :CMakeBuild<CR>
nnoremap <buffer> <silent> ci :CMakeInstall<CR>
nnoremap <buffer> <silent> cq :CMakeClose<CR>
nnoremap <buffer> <silent> <C-C> :CMakeStop<CR>
setlocal nonumber
setlocal norelativenumber
setlocal signcolumn=auto
setlocal nobuflisted
setlocal filetype=vimcmake
setlocal statusline=[CMake]
setlocal statusline+=\ %{cmake#statusline#GetBuildInfo(0)}
setlocal statusline+=\ %{cmake#statusline#GetCmdInfo()}
" Avoid error E37 on :CMakeClose in some Vim instances.
setlocal bufhidden=hide
augroup cmake
autocmd WinEnter <buffer> call s:OnEnterConsoleWindow()
augroup END
return bufnr()
call s:logger.LogDebug('Created console buffer')
endfunction
" Setup Vim-CMake console terminal.
"
function! s:TermSetup() abort
" Open job-less terminal to echo command outputs to.
let l:options = {}
if has('nvim')
let s:term_chan_id = nvim_open_term(bufnr(''), l:options)
else
let l:options['curwin'] = 1
let l:term = term_start('NONE', l:options)
let s:term_id = term_getjob(l:term)
let s:term_tty = job_info(s:term_id)['tty_in']
call term_setkill(l:term, 'term')
endif
endfunction
" Echo strings to terminal.
"
" Params:
" data : List
" list of strings to echo
"
function! s:TermEcho(data) abort
if len(a:data) == 0
return
endif
if has('nvim')
call chansend(s:term_chan_id, join(a:data, "\r\n") . "\r\n")
else
call writefile(a:data, s:term_tty)
endif
endfunction
" Filter stdout data to remove ANSI sequences that should not be sent to the
" console terminal.
"
" Params:
" data : List
" list of stdout strings to filter (filtering is done in-place)
"
function! s:FilterStdoutPreEcho(data) abort
if s:pre_echo_filter !=# ''
call map(a:data, {_, val -> substitute(
\ val, s:pre_echo_filter, '', 'g')})
endif
endfunction
" Filter stdout data to remove remaining ANSI sequences after sending the data
" to the console terminal.
"
" Params:
" data : List
" list of stdout strings to filter (filtering is done in-place)
"
function! s:FilterStdoutPostEcho(data) abort
if s:post_echo_filter !=# ''
call map(a:data, {_, val -> substitute(
\ val, s:post_echo_filter, '', 'g')})
endif
if s:post_echo_rep_pat !=# ''
call map(a:data, {_, val -> substitute(
\ val, s:post_echo_rep_pat, s:post_echo_rep_sub, 'g')})
endif
endfunction
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Public functions
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Open Vim-CMake console window.
"
" Params:
" clear : Boolean
" if set, a new buffer is created and the old one is deleted
"
function! s:terminal.Open(clear) abort
call s:logger.LogDebug('Invoked: terminal.Open(%s)', a:clear)
let l:original_win_id = win_getid()
let l:cmake_win_id = bufwinid(l:self.console_buffer)
if l:cmake_win_id == -1
" If a Vim-CMake window does not exist, create it.
call s:CreateConsoleWindow()
if bufexists(l:self.console_buffer)
" If a Vim-CMake buffer exists, open it in the Vim-CMake window, or
" delete it if a:clear is set.
if !a:clear
execute 'b ' . l:self.console_buffer
call win_gotoid(l:original_win_id)
return
else
execute 'bd! ' . l:self.console_buffer
endif
endif
" Create Vim-CMake buffer if none exist, or if the old one was deleted.
let l:self.console_buffer = s:CreateConsoleBuffer()
else
" If a Vim-CMake window exists, and a:clear is set, create a new
" Vim-CMake buffer and delete the old one.
if a:clear
let l:old_buffer = l:self.console_buffer
call l:self.Focus()
let l:self.console_buffer = s:CreateConsoleBuffer()
if bufexists(l:old_buffer) && l:old_buffer != l:self.console_buffer
execute 'bd! ' . l:old_buffer
endif
endif
endif
if l:original_win_id != win_getid()
call win_gotoid(l:original_win_id)
endif
endfunction
" Focus Vim-CMake console window.
"
function! s:terminal.Focus() abort
call s:logger.LogDebug('Invoked: terminal.Focus()')
call win_gotoid(bufwinid(l:self.console_buffer))
endfunction
" Close Vim-CMake console window.
"
function! s:terminal.Close() abort
call s:logger.LogDebug('Invoked: terminal.Close()')
if bufexists(l:self.console_buffer)
let l:cmake_win_id = bufwinid(l:self.console_buffer)
if l:cmake_win_id != -1
execute win_id2win(l:cmake_win_id) . 'wincmd q'
endif
endif
endfunction
" Run arbitrary command in the Vim-CMake console.
"
" Params:
" command : List
" the command to be run, as a list of command and arguments
" tag : String
" command tag, must be an item of keys(l:self.console_cmd_info)
" cbs : List
" list of callbacks (Funcref) to be invoked upon successful completion
" of the command
" cbs_err : List
" list of callbacks (Funcref) to be invoked upon unsuccessful completion
" of the command
" aus : List
" list of autocmds (String) to be invoked upon successful completion of
" the command
" aus_err : List
" list of autocmds (String) to be invoked upon unsuccessful completion
" of the command
"
function! s:terminal.Run(command, tag, cbs, cbs_err, aus, aus_err) abort
call s:logger.LogDebug('Invoked: terminal.Run(%s, %s, %s, %s, %s, %s)',
\ a:command, string(a:tag), a:cbs, a:cbs_err, a:aus, a:aus_err)
call assert_notequal(index(keys(l:self.console_cmd_info), a:tag), -1)
" Prevent executing this function when a command is already running
if l:self.console_cmd.running
call s:logger.EchoError('Another CMake command is already running')
call s:logger.LogError('Another CMake command is already running')
return
endif
let l:self.console_cmd.running = v:true
let l:self.console_cmd.callbacks = a:cbs
let l:self.console_cmd.callbacks_err = a:cbs_err
let l:self.console_cmd.autocmds = a:aus
let l:self.console_cmd.autocmds_err = a:aus_err
let l:self.console_cmd_output = []
" Open Vim-CMake console window.
call l:self.Open(v:false)
" Echo start message to terminal.
if g:cmake_console_echo_cmd
call s:TermEcho([printf(
\ '%sRunning command: %s%s',
\ "\e[1;35m",
\ join(a:command),
\ "\e[0m")
\ ])
endif
" Run command.
call s:statusline.SetCmdInfo(l:self.console_cmd_info[a:tag])
let l:self.console_cmd.id = s:ConsoleCmdStart(a:command)
" Jump to Vim-CMake console window if requested.
if g:cmake_jump
call l:self.Focus()
endif
endfunction
" Stop command currently running in the Vim-CMake console.
"
function! s:terminal.Stop() abort
call s:logger.LogDebug('Invoked: terminal.Stop()')
call s:system.JobStop(l:self.console_cmd.id)
call s:OnCompleteCommand(0, v:true)
endfunction
" Get output from the last command run.
"
" Returns
" List:
" output from the last command, as a list of strings
"
function! s:terminal.GetOutput() abort
return l:self.console_cmd_output
endfunction
" Get terminal 'object'.
"
function! cmake#terminal#Get() abort
return s:terminal
endfunction

View file

@ -0,0 +1,81 @@
" ==============================================================================
" Location: autoload/cmake/util.vim
" Description: Utility functions
" ==============================================================================
let s:logger = cmake#logger#Get()
let s:system = cmake#system#Get()
let s:repo_dir = expand('<sfile>:p:h:h:h')
let s:data_dir = s:system.Path([s:repo_dir, '.data'], v:false)
let s:data_file = s:system.Path([s:data_dir, 'previous-version.bin'], v:false)
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Private functions
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function! s:VersionToNumber(_, version) abort
let l:version = split(a:version, '\.')
let l:major = str2nr(l:version[0])
let l:minor = str2nr(l:version[1])
let l:patch = str2nr(l:version[2])
let l:number = l:major * 10000 + l:minor * 100 + l:patch
return l:number
endfunction
function! s:NumberToVersion(number) abort
let l:major = a:number / 10000
let l:minor = (a:number - l:major * 10000) / 100
let l:patch = a:number - l:major * 10000 - l:minor * 100
let l:version = l:major . '.' . l:minor . '.' . l:patch
return l:version
endfunction
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Public functions
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Print news of newer Vim-CMake versions.
"
" Params:
" current_version : String
" current version of the plugin (in the format <major>.<minor>.<patch>)
" news : Dictionary
" dictionary of news, where a key identifies a version (in the format
" <major>.<minor>.<patch>), and a value is a string containing the news
" to print for a version
"
function! cmake#util#PrintNews(current_version, news) abort
" Make a list of all version numbers, transform to integers, and sort.
let l:all_version_numbers = keys(a:news)
call map(l:all_version_numbers, function('s:VersionToNumber'))
call sort(l:all_version_numbers)
try
" Try to read previous version number from file.
let l:line = readfile(s:data_file, 'b')
catch /.*/
" Store current version number.
try
call mkdir(s:data_dir, 'p')
call writefile([a:current_version], s:data_file, 'b')
catch /.*/
endtry
return
endtry
" Get previous version number from file, then write current version number.
let l:previous_version_number = s:VersionToNumber('', l:line[0])
if l:previous_version_number < s:VersionToNumber('', a:current_version)
try
call writefile([a:current_version], s:data_file, 'b')
catch /.*/
endtry
endif
" Print updates for newer versions.
for l:number in l:all_version_numbers
if l:number > l:previous_version_number
for l:news_item in a:news[s:NumberToVersion(l:number)]
call s:logger.EchoInfo(l:news_item)
endfor
endif
endfor
endfunction

View file

@ -0,0 +1,351 @@
*cmake.txt* Vim/Neovim plugin for working with CMake projects
*cmake* *vim-cmake*
Maintainer: Carlo Delle Donne <https://github.com/cdelledonne>
Version: 0.7.1
==============================================================================
CONTENTS *cmake-contents*
1. Intro .............................................. |cmake-intro|
2. Usage .............................................. |cmake-usage|
3. Commands ........................................... |cmake-commands|
3.1 Generating a project build system .............. |cmake-generate|
3.2 Building and installing a project .............. |cmake-build|
3.3 Switch between build configurations............. |cmake-switch|
3.4 Opening and closing the CMake console .......... |cmake-console|
3.5 Stopping the running command ................... |cmake-stop|
4. Mappings ........................................... |cmake-mappings|
4.1 Global <Plug> mappings ......................... |cmake-plug-mappings|
4.2 CMake console window key mappings .............. |cmake-key-mappings|
5. Events ............................................. |cmake-events|
6. Quickfix list ...................................... |cmake-quickfix|
7. Configuration ...................................... |cmake-configuration|
8. Contributing ....................................... |cmake-contributing|
9. License ............................................ |cmake-license|
==============================================================================
INTRO *cmake-intro*
Vim-CMake is a plugin for building CMake projects inside of Vim/Neovim, with a
nice visual feedback.
Features~
- Visual experience, shows CMake output in a console-like window
- Slick management of build configurations
- Autocompletion for build targets and build configurations
- Quickfix list population after each build
- Airline/statusline status information, including current build configuration
- Plug-and-play, but configurable
- Written in Vimscript
Requirements~
- Vim with `+terminal`, or Neovim >= 0.5
- Under Windows, only Neovim is supported at the moment
==============================================================================
USAGE *cmake-usage*
Run |:CMakeGenerate| from the top-level CMake source directory to generate a
build system for the project. Then, run |:CMakeBuild| to build the project.
The built files will end up in the binary directory (out-of-source build). To
switch between build configurations, run |:CMakeSwitch| {config}.
With Vim-CMake, you can easily manage build configurations (Debug, Release,
etc.), build specific targets and control build options, and fix errors using
Vim's |quickfix| feature. Read on for a detailed explanation of commands,
mappings and configuration options.
==============================================================================
COMMANDS *cmake-commands*
Vim-CMake defines a small set of CMake-related commands.
------------------------------------------------------------------------------
*cmake-generate*
Generating a project build system~
*:CMakeGenerate*
:CMakeGenerate[!] [config] [opts]
Generate project build system for a CMake project. If
[!] is supplied, the existing build system is removed
before generating a new one. [config] specifies the
build configuration to generate. [opts] are passed
directly to CMake.
By default, the build system is generated for the build configuration
specified by `g:cmake_default_config` (see |cmake-configuration|). For
instance, if the default build configuration is "Debug", `cmake` will be
passed `-D CMAKE_BUILD_TYPE=Debug`, and the build system will be generated in
`Debug/`, relative to `g:cmake_build_dir_location` (see
|cmake-configuration|). That will result in the following `cmake` command:
>
cmake -D CMAKE_BUILD_TYPE=Debug [...] \
-S <project_root> -B <build_dir_location>/Debug
<
To generate a build system for another configuration, e.g., "Release", run
>
:CMakeGenerate Release [...]
<
which will result in the following `cmake` command:
>
cmake -D CMAKE_BUILD_TYPE=Release [...] \
-S <project_root> -B <build_dir_location>/Release
<
To generate a build system for a configuration, while passing a different
`CMAKE_BUILD_TYPE` to `cmake`, run
>
:CMakeGenerate SomeConfigName -D CMAKE_BUILD_TYPE=Release [...]
<
which will result in the following `cmake` command:
>
cmake -D CMAKE_BUILD_TYPE=Release [...] \
-S <project_root> -B <build_dir_location>/SomeConfigName
<
Use |:CMakeSwitch| to switch between build configurations.
*:CMakeClean*
:CMakeClean Remove project build system relative to the current
build configuration.
------------------------------------------------------------------------------
*cmake-build*
Building and installing a project~
*:CMakeBuild*
:CMakeBuild[!] [opts] [target] [-- [nativeopts]]
Build a project using the generated build system
from the current build configuration, and populate a
quickfix list (see |cmake-quickfix|). If [!] is
supplied, the existing build files are cleaned (using
CMake's `--clean-first` option) before building the
project. [opts] are passed directly to CMake.
[target] is the target to build instead of the default
target. [nativeopts] are passed directly to the
native tool.
For instance, to build the target `mytarget` using a maximum of 4 processes
and passing the `VERBOSE=1` option to the native tool, run
>
:CMakeBuild --parallel 4 mytarget -- VERBOSE=1
<
Vim-CMake provides autocompletion for build targets. Just press <TAB> at any
point after `:CMakeBuild` in the command line to trigger autocompletion, e.g.
>
:CMakeBuild --parallel 4 <TAB>
<
*:CMakeInstall*
:CMakeInstall Install a project from the current build
configuration.
------------------------------------------------------------------------------
*cmake-switch*
Switching between build configurations~
*:CMakeSwitch*
:CMakeSwitch {config} Switch to build configuration {config}. The build
configuration must exist, that is, there has to be a
project build system (for instance generated with
|:CMakeGenerate|) in the directory {config}.
For instance, to switch to an existing configuration called "Release", run
>
:CMakeSwitch Release
<
The default build configuration on start-up is specified by
`g:cmake_default_config` (see |cmake-configuration|). Use |:CMakeGenerate| to
generate a build configuration.
Vim-CMake provides autocompletion for existing build configurations. Press
<TAB> after `:CMakeSwitch` in the command line to trigger autocompletion.
------------------------------------------------------------------------------
*cmake-console*
Opening and closing the CMake console~
*:CMakeOpen*
:CMakeOpen Open the CMake console window.
*:CMakeClose*
:CMakeClose Close the CMake console window.
------------------------------------------------------------------------------
*cmake-stop*
Stopping the running command~
*:CMakeStop*
:CMakeStop Stop the command that is currently running in the
Vim-CMake console. Stopping a command does not
trigger the associated events (see |cmake-events|).
==============================================================================
MAPPINGS *cmake-mappings*
In addition to commands, Vim-CMake defines some global <Plug> mappings and
some key mappings specific to the CMake console window.
------------------------------------------------------------------------------
*cmake-plug-mappings*
Global <Plug> mappings~
<Plug>(CMakeGenerate) Equivalent to `:CMakeGenerate`.
<Plug>(CMakeClean) Equivalent to `:CMakeClean`.
<Plug>(CMakeBuild) Equivalent to `:CMakeBuild`.
<Plug>(CMakeBuildTarget)
Inserts `:CMakeBuild` in the command line, and leaves
the cursor there.
<Plug>(CMakeInstall) Equivalent to `:CMakeInstall`.
<Plug>(CMakeSwitch) Inserts `:CMakeSwitch` in the command line, and leaves
the cursor there.
<Plug>(CMakeOpen) Equivalent to `:CMakeOpen`.
<Plug>(CMakeClose) Equivalent to `:CMakeClose`.
<Plug>(CMakeStop) Equivalent to `:CMakeStop`.
Example usage of the <Plug> mappings:
>
nmap <leader>cg <Plug>(CMakeGenerate)
nmap <leader>cb <Plug>(CMakeBuild)
nmap <leader>ci <Plug>(CMakeInstall)
nmap <leader>cs <Plug>(CMakeSwitch)
nmap <leader>cq <Plug>(CMakeClose)
<
------------------------------------------------------------------------------
*cmake-key-mappings*
CMake console window key mappings~
cg Run `:CMakeGenerate`.
cb Run `:CMakeBuild`.
ci Run `:CMakeInstall`.
cq Close the CMake console window.
<C-C> Stop the running command.
==============================================================================
EVENTS *cmake-events*
To customize the behaviour after a `:CMakeBuild` command has finished, Vim-CMake
defines some user events.
`CMakeBuildFailed` Triggered after a build has failed
`CMakeBuildSucceeded` Triggered after a build has succeeded
Example usage of `CMakeBuildFailed` to jump to the first error
>
let g:cmake_jump_on_error = 0 " We do not want to focus the console
augroup vim-cmake-group
autocmd User CMakeBuildFailed :cfirst
augroup END
<
Example usage of `CMakeBuildSucceeded` to close the Vim-CMake console
>
augroup vim-cmake-group
autocmd! User CMakeBuildSucceeded CMakeClose
augroup END
<
==============================================================================
QUICKFIX LIST *cmake-quickfix*
After each build (e.g. run with |:CMakeBuild|), Vim-CMake populates a quickfix
list to speedup the edit-compile-run cycle, similarly to when running |:make|
in Vim/Neovim. Upon an unsuccessful build, just use the standard quickfix
commands to open the list of errors (e.g. |:copen|) and jump between errors
(e.g. |:cfirst|, |:cnext|).
Build errors are parsed using 'errorformat'.
==============================================================================
CONFIGURATION *cmake-configuration*
Vim-CMake has sensible defaults, but aims to be configurable. A list of
configuration options, with default values, follows.
g:cmake_command (default: `'cmake'`)
Name (or full path) of the CMake executable.
g:cmake_default_config (default: `'Debug'`)
Default build configuration on start-up.
g:cmake_build_dir_location (default: `'.'`)
Location of the build directory, relative to the
project root. Each build configuration creates a
build directory at this location.
g:cmake_generate_options (default: `[]`)
List of options to pass to CMake by default when
running |:CMakeGenerate|.
g:cmake_build_options (default: `[]`)
List of options to pass to CMake by default when
running |:CMakeBuild|.
g:cmake_native_build_options (default: `[]`)
List of options to pass to the native tool by default
when running |:CMakeBuild|.
g:cmake_console_size (default: `15`)
Size of the CMake console window.
g:cmake_console_position (default: `'botright'`)
Command modifier to use when opening the CMake console
window (see |:botright|).
g:cmake_console_echo_cmd (default: `1`)
Echo running command in the Vim-CMake console, before
showing the output for the command itself.
g:cmake_jump (default: `0`)
Whether to jump to the CMake console window when
running a `:CMake` command.
g:cmake_jump_on_completion (default: `0`)
Whether to jump to the CMake console window when a
`:CMake` command completes.
g:cmake_jump_on_error (default: `1`)
Whether to jump to the CMake console window when a
`:CMake` command returns an error.
g:cmake_link_compile_commands (default: `0`)
Whether to create a symlink in the CMake source
directory to the `compile_commands.json` file. If
this is enabled, the CMake configuration options
`CMAKE_EXPORT_COMPILE_COMMANDS` will be set to `ON`
(unless explicitly set to something else in the
command-line arguments to `:CMakeGenerate`). NOTE:
under MS-Windows, creating symlinks only work if the
"Developer mode" is enabled, or if running the console
as an administrator.
g:cmake_root_markers (default: `['.git', '.svn']`)
List of file/directory names used to locate the
project root. When Vim-CMake is loaded, it looks for
the project root starting from the CWD.
g:cmake_log_file (default: `''`)
Path to a file where to store the log of Vim-CMake.
An empty value disables logging.
==============================================================================
CONTRIBUTING *cmake-contributing*
Feedback and feature requests are appreciated. Bug reports and pull requests
are very welcome. Check the Contributing Guidelines for how to write a
feature request, post an issue or submit a pull request:
https://github.com/cdelledonne/vim-cmake/blob/master/CONTRIBUTING.md
==============================================================================
LICENSE *cmake-license*
MIT license. Copyright (c) 2020-2022 Carlo Delle Donne.
------------------------------------------------------------------------------
vim:tw=78:ts=8:noet:ft=help:norl:

View file

@ -0,0 +1,89 @@
" ==============================================================================
" File: cmake.vim
" Description: Vim-CMake, a Vim/Neovim plugin for working with CMake projects
" Maintainer: Carlo Delle Donne <https://github.com/cdelledonne>
" Version: 0.7.1
" License: MIT
" ==============================================================================
if exists('g:loaded_cmake') && g:loaded_cmake
finish
endif
let g:loaded_cmake = 1
" Assign user/default values to coniguration variables.
" NOTE: must be done before loading other scripts.
let s:const = cmake#const#Get()
for s:cvar in items(s:const.config_vars)
if !has_key(g:, s:cvar[0])
let g:[s:cvar[0]] = s:cvar[1]
endif
endfor
let s:logger = cmake#logger#Get()
" Check required features.
if has('nvim')
if !has('nvim-0.5.0')
call s:logger.EchoError('Only Neovim versions >= 0.5 are supported')
call s:logger.LogError('Only Neovim versions >= 0.5 are supported')
finish
endif
else
if has('win32')
call s:logger.EchoError('Under Windows, only Neovim is supported at the moment')
call s:logger.LogError('Under Windows, only Neovim is supported at the moment')
finish
endif
if !has('terminal')
call s:logger.EchoError('Must run Neovim, or Vim with +terminal')
call s:logger.LogError('Must run Neovim, or Vim with +terminal')
finish
endif
endif
call s:logger.LogInfo('Loading Vim-CMake')
" Check if CMake executable exists.
if !executable(g:cmake_command)
call s:logger.EchoError('Binary ''%s'' not found in PATH', g:cmake_command)
call s:logger.LogError('Binary ''%s'' not found in PATH', g:cmake_command)
finish
endif
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Commands
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
command -nargs=? -bang CMakeGenerate call cmake#Generate(<bang>0, <f-args>)
command -nargs=? CMakeClean call cmake#Clean()
command -nargs=1 -complete=custom,cmake#GetConfigs CMakeSwitch call cmake#Switch(<f-args>)
command -nargs=? -bang -complete=custom,cmake#GetBuildTargets CMakeBuild call cmake#Build(<bang>0, <f-args>)
command CMakeInstall call cmake#Install()
command CMakeOpen call cmake#Open()
command CMakeClose call cmake#Close()
command CMakeStop call cmake#Stop()
call s:logger.LogInfo('Commands defined')
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Mappings
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
nnoremap <silent> <Plug>(CMakeGenerate) :call cmake#Generate(0)<CR>
nnoremap <silent> <Plug>(CMakeClean) :call cmake#Clean()<CR>
nnoremap <Plug>(CMakeSwitch) :CMakeSwitch<Space>
nnoremap <silent> <Plug>(CMakeBuild) :call cmake#Build(0)<CR>
nnoremap <silent> <Plug>(CMakeInstall) :call cmake#Install()<CR>
nnoremap <Plug>(CMakeBuildTarget) :CMakeBuild<Space>
nnoremap <silent> <Plug>(CMakeOpen) :call cmake#Open()<CR>
nnoremap <silent> <Plug>(CMakeClose) :call cmake#Close()<CR>
nnoremap <silent> <Plug>(CMakeStop) :call cmake#Stop()<CR>
call s:logger.LogInfo('Mappings defined')
call s:logger.LogInfo('Vim-CMake loaded')

View file

@ -208,7 +208,7 @@ inoremap <silent><expr> <cr> pumvisible() ? coc#_select_confirm()
" => Vim-autoformat " => Vim-autoformat
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
let g:python3_host_prog="/usr/bin/python3" let g:python3_host_prog="/usr/bin/python3"
autocmd BufWrite * :Autoformat "autocmd BufWrite * :Autoformat
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Rainbow Parentheses " => Rainbow Parentheses