├── .gitignore ├── VimFlavor ├── compiler └── BTW │ ├── gcc.vim │ ├── make.vim │ ├── cygwin.vim │ ├── gmake.vim │ ├── STLFilt.vim │ ├── syntax │ └── cc.vim │ ├── TreeProject.vim │ ├── run_in_background.pl │ ├── SunSWProLinkIsError.vim │ ├── run_and_recontact_vim.pl │ ├── ant.pl │ ├── SunSWProLinkIsError.pl │ ├── ant.vim │ ├── cygwin.pl │ ├── shorten_filenames.vim │ ├── aap.vim │ ├── cmake.vim │ ├── gcc.pl │ └── substitute_filenames.vim ├── doc ├── screencast-BTW.gif ├── filter.md ├── make_run.md └── BuildToolsWrapper.txt ├── addon-info.json ├── tests └── lh │ └── UT_project_create.vim ├── mkVba └── mk-BTW.vim ├── README.md ├── License.md ├── autoload ├── airline │ └── extensions │ │ └── btw.vim └── lh │ ├── btw │ ├── filters.vim │ ├── project.vim │ ├── job_build.vim │ ├── project_options.vim │ ├── option.vim │ ├── chain.vim │ ├── build.vim │ └── cmake.vim │ └── btw.vim └── plugin └── BuildToolsWrapper.vim /.gitignore: -------------------------------------------------------------------------------- 1 | tags 2 | *.sw* 3 | *~ 4 | *.pyc 5 | -------------------------------------------------------------------------------- /VimFlavor: -------------------------------------------------------------------------------- 1 | flavor 'LucHermitte/lh-vim-lib', '>= 4.0.0' 2 | -------------------------------------------------------------------------------- /compiler/BTW/gcc.vim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucHermitte/vim-build-tools-wrapper/HEAD/compiler/BTW/gcc.vim -------------------------------------------------------------------------------- /compiler/BTW/make.vim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucHermitte/vim-build-tools-wrapper/HEAD/compiler/BTW/make.vim -------------------------------------------------------------------------------- /compiler/BTW/cygwin.vim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucHermitte/vim-build-tools-wrapper/HEAD/compiler/BTW/cygwin.vim -------------------------------------------------------------------------------- /compiler/BTW/gmake.vim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucHermitte/vim-build-tools-wrapper/HEAD/compiler/BTW/gmake.vim -------------------------------------------------------------------------------- /doc/screencast-BTW.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucHermitte/vim-build-tools-wrapper/HEAD/doc/screencast-BTW.gif -------------------------------------------------------------------------------- /compiler/BTW/STLFilt.vim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucHermitte/vim-build-tools-wrapper/HEAD/compiler/BTW/STLFilt.vim -------------------------------------------------------------------------------- /compiler/BTW/syntax/cc.vim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucHermitte/vim-build-tools-wrapper/HEAD/compiler/BTW/syntax/cc.vim -------------------------------------------------------------------------------- /compiler/BTW/TreeProject.vim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucHermitte/vim-build-tools-wrapper/HEAD/compiler/BTW/TreeProject.vim -------------------------------------------------------------------------------- /compiler/BTW/run_in_background.pl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucHermitte/vim-build-tools-wrapper/HEAD/compiler/BTW/run_in_background.pl -------------------------------------------------------------------------------- /compiler/BTW/SunSWProLinkIsError.vim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucHermitte/vim-build-tools-wrapper/HEAD/compiler/BTW/SunSWProLinkIsError.vim -------------------------------------------------------------------------------- /compiler/BTW/run_and_recontact_vim.pl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucHermitte/vim-build-tools-wrapper/HEAD/compiler/BTW/run_and_recontact_vim.pl -------------------------------------------------------------------------------- /compiler/BTW/ant.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # $Id$ 3 | # Author: Luc Hermitte 4 | # 5 | # Purpose: Get rid of ant format 6 | # Created: Mon 22 May 2006 08:12:59 PM CEST 7 | # Last Update: $date$ 8 | # ====================================================================== 9 | 10 | # Main loop: get rid of /^\s*[.*]\s*/ 11 | while (<>) 12 | { 13 | chop; 14 | $_ =~ s/^\s*\[.*?\]\s*// ; 15 | print "$_\n"; 16 | } 17 | -------------------------------------------------------------------------------- /addon-info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "build-tools-wrapper", 3 | "version" : "dev", 4 | "author" : "Luc Hermitte ", 5 | "maintainer" : "Luc Hermitte ", 6 | "repository" : {"type": "git", "url": "git@github.com:LucHermitte/vim-build-tools-wrapper.git"}, 7 | "dependencies" : { 8 | "lh-vim-lib" : {"type" : "git", "url" : "git@github.com:LucHermitte/lh-vim-lib.git"} 9 | }, 10 | "description" : "Projects building plugin" 11 | } 12 | -------------------------------------------------------------------------------- /compiler/BTW/SunSWProLinkIsError.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Author: Luc Hermitte 3 | # 4 | # Purpose: Fiter outputs from SunSWPro CC to tell that link errors are 5 | # actually errors. 6 | # Defined as a filter to use on make's result. 7 | # Meant to be used by Vim. 8 | # Created: 28th Nov 2004 9 | # Last Update: 08th Dec 2004 10 | # ====================================================================== 11 | 12 | ### Code {{{1 13 | 14 | use strict ; 15 | 16 | ## Main loop: The convertion. {{{2 17 | 18 | while (<>) 19 | { 20 | chop; 21 | $_ =~ s/(Undefined first referenced)/--link-error--:0:$1/ ; 22 | print "$_\n"; 23 | } 24 | # ====================================================================== 25 | # vim600: set foldmethod=marker: 26 | # vim:et:ts=8:tw=79: 27 | -------------------------------------------------------------------------------- /tests/lh/UT_project_create.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " $Id$ 3 | " File: tests/lh/UT_project_create.vim {{{1 4 | " Author: Luc Hermitte 5 | " 6 | " Version: 0..3..4. 7 | let s:k_version = '0.3.4' 8 | " Created: 15th Jan 2015 9 | " Last Update: $Date$ 10 | "------------------------------------------------------------------------ 11 | " Description: 12 | " Unit tests for lh#btw#project functions. 13 | " }}}1 14 | "============================================================================= 15 | 16 | UTSuite [BTW] Testing lh#btw#project 17 | 18 | runtime autoload/lh/btw/project.vim 19 | 20 | let s:cpo_save=&cpo 21 | set cpo&vim 22 | 23 | "------------------------------------------------------------------------ 24 | function! s:Test_analyse_params() 25 | let ref = {'project_kind': {'c':1,'cmake':1}, '_prj_name': 'toto', '_prj_config': 'titi', '_prj_src_dir': 'dir'} 26 | Assert ref == lh#btw#project#_analyse_params('c' , 'cmake', 'name', 'toto', 'config:', 'titi', 'src_dir=dir') 27 | endfunction 28 | 29 | "------------------------------------------------------------------------ 30 | let &cpo=s:cpo_save 31 | "============================================================================= 32 | " vim600: set fdm=marker: 33 | -------------------------------------------------------------------------------- /compiler/BTW/ant.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " $Id$ 3 | " File: ant.vim {{{1 4 | " Author: Luc Hermitte 5 | " 6 | " Version: «version» 7 | " Created: 22nd May 2006 8 | " Last Update: $Date$ 9 | "------------------------------------------------------------------------ 10 | " Description: «description» 11 | " 12 | "------------------------------------------------------------------------ 13 | " Installation: «install details» 14 | " History: «history» 15 | " TODO: «missing features» 16 | " }}}1 17 | "============================================================================= 18 | 19 | 20 | "============================================================================= 21 | " Avoid global reinclusion {{{1 22 | let s:cpo_save=&cpo 23 | set cpo&vim 24 | if exists("g:loaded_BTW_ant") 25 | \ && !exists('g:force_reload_BTW_ant') 26 | let &cpo=s:cpo_save 27 | finish 28 | endif 29 | let g:loaded_BTW_ant = 1 30 | " Avoid global reinclusion }}}1 31 | "------------------------------------------------------------------------ 32 | " Functions {{{1 33 | 34 | " a- emplacement of the perl filter 35 | let s:file = substitute(expand(':p:h'), ' ', '\\ ', 'g') 36 | 37 | " b- filter to apply over `ant' outputs: '/' --> {root} 38 | let g:BTW_filter_program_ant = s:file."/ant.pl" 39 | 40 | " Functions }}}1 41 | "------------------------------------------------------------------------ 42 | let &cpo=s:cpo_save 43 | "============================================================================= 44 | " vim600: set fdm=marker: 45 | -------------------------------------------------------------------------------- /compiler/BTW/cygwin.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # $Id$ 3 | # Author: Luc Hermitte 4 | # 5 | # Purpose: Convert Cygwin pathames to plain Windows pathnames. 6 | # Defined as a filter to use on make's result. 7 | # Meant to be used by Vim. 8 | # Created: 05/29/04 01:12:19 9 | # Last Update: $date$ 10 | # ====================================================================== 11 | 12 | # cygroot 13 | my $cygroot = `cygpath -m /`; 14 | chomp($cygroot); 15 | 16 | # Hash table for the paths already translated with ``realname'' 17 | my %paths = () ; 18 | 19 | # Proxy function: returns the realname of the path 20 | # This function looks for converted paths into the hastable, if nothing is 21 | # found in the table, the result is built and added into the table 22 | # TODO: follow mounted things 23 | sub WindowsPath 24 | { 25 | my ($path) = @_ ; 26 | if ( exists( $h{$path} ) ) { 27 | return $h{$path} ; 28 | } else { 29 | # Get the real localtion of the file 30 | $wpath = `realpath "$path"`; 31 | chomp ($wpath); 32 | # /cygdrive/c/path -> C:/path 33 | $wpath =~ s#/cygdrive/(.)#\u\1:# ; 34 | # /c/path -> C:/path ; I suppose /cygdrive/c/ is mounted into /c/ 35 | $wpath =~ s#^/([^/])/#\u\1:/# ; 36 | # /path -> C:/cygwin/path ; may be F:/cygwin/, .... 37 | $wpath =~ s#^/#$cygroot/# ; 38 | # Add the path into the hash-table 39 | $h{$path} = $wpath ; 40 | return $wpath ; 41 | } 42 | } 43 | 44 | # Main loop: convert Cygwin paths into MsWindows paths 45 | while (<>) 46 | { 47 | chop; 48 | if ( m#^( */.*?)(\:\d*\:?.*$)# ) { 49 | printf WindowsPath($1)."$2\n"; 50 | } else { 51 | print "$_\n"; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /mkVba/mk-BTW.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: mk-BTW.vim 3 | " Maintainer: Luc Hermitte 4 | " 5 | " Licence: GPLv3 6 | " Version: 0.7.0 7 | let s:version = '0.7.0' 8 | " Created: 06th Nov 2007 9 | " Last Update: 17th Jun 2016 10 | "------------------------------------------------------------------------ 11 | let s:project = 'lh-BTW' 12 | cd :p:h 13 | try 14 | let save_rtp = &rtp 15 | let &rtp = expand(':p:h:h').','.&rtp 16 | exe '23,$MkVimball! '.s:project.'-'.s:version 17 | set modifiable 18 | set buftype= 19 | finally 20 | let &rtp = save_rtp 21 | endtry 22 | finish 23 | License.md 24 | README.md 25 | VimFlavor 26 | addon-info.json 27 | autoload/airline/extensions/btw.vim 28 | autoload/lh/btw.vim 29 | autoload/lh/btw/build.vim 30 | autoload/lh/btw/chain.vim 31 | autoload/lh/btw/cmake.vim 32 | autoload/lh/btw/filters.vim 33 | autoload/lh/btw/job_build.vim 34 | autoload/lh/btw/option.vim 35 | autoload/lh/btw/project.vim 36 | autoload/lh/btw/project_options.vim 37 | compiler/BTW/STLFilt.vim 38 | compiler/BTW/SunSWProLinkIsError.pl 39 | compiler/BTW/SunSWProLinkIsError.vim 40 | compiler/BTW/TreeProject.vim 41 | compiler/BTW/aap.vim 42 | compiler/BTW/ant.pl 43 | compiler/BTW/ant.vim 44 | compiler/BTW/cmake.vim 45 | compiler/BTW/cygwin.pl 46 | compiler/BTW/cygwin.vim 47 | compiler/BTW/gcc.pl 48 | compiler/BTW/gcc.vim 49 | compiler/BTW/gmake.vim 50 | compiler/BTW/make.vim 51 | compiler/BTW/run_and_recontact_vim.pl 52 | compiler/BTW/run_in_background.pl 53 | compiler/BTW/substitute_filenames.vim 54 | compiler/BTW/syntax/cc.vim 55 | doc/BuildToolsWrapper.txt 56 | doc/cmake.md 57 | lh-build-tools-wrapper-addon-info.txt 58 | plugin/BuildToolsWrapper.vim 59 | tests/lh/UT_project_create.vim 60 | -------------------------------------------------------------------------------- /compiler/BTW/shorten_filenames.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: compiler/BTW/shorten_filenames.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " Version: 0.7.0. 6 | let s:k_version = 070 7 | " Created: 22nd Mar 2015 8 | " Last Update: 16th Oct 2016 9 | "------------------------------------------------------------------------ 10 | " Description: 11 | " BTW filter to shorter filenames (with conceal feature) 12 | " 13 | " Parameters: 14 | " - (bg):{ft_}BTW_shorten_names: [ pattern, [pattern,cchar], ...] 15 | " 16 | " }}}1 17 | "============================================================================= 18 | 19 | let s:cpo_save=&cpo 20 | set cpo&vim 21 | "------------------------------------------------------------------------ 22 | " Main {{{1 23 | function! BTW_Shorten_Filenames() abort 24 | " We cannot apply s:Tranform (from substitute_filenames) to shorten filename. 25 | " Indeed the qf.text won't contain the filename. Filenames have already 26 | " been decoded and replaced by a bufnr. 27 | " At best, we can conceal 28 | syn match qfFileName /^[^|]*/ nextgroup=qfSeparator contains=qfShortenFile 29 | let list = lh#ft#option#get('BTW.shorten_names', &ft, []) 30 | for pat in list 31 | if type(pat)==type([]) 32 | let expr = pat[0] 33 | let cchar = pat[1] 34 | else 35 | let expr = pat 36 | let cchar = '&' 37 | endif 38 | if lh#encoding#strlen(cchar) > 1 39 | call lh#common#warning_msg('Invalid conceal-character `'.cchar."' for `".expr."' given to shorten_filenames BTW filter: its length is > 1") 40 | else 41 | exe 'syn match qfShortenFile #'.expr.'# conceal contained cchar='.cchar 42 | endif 43 | endfor 44 | setlocal conceallevel=1 45 | setlocal concealcursor=nc 46 | endfunction 47 | 48 | call lh#btw#filters#register_hook(8, 'BTW_Shorten_Filenames', 'syntax') 49 | 50 | " }}}1 51 | "------------------------------------------------------------------------ 52 | let &cpo=s:cpo_save 53 | "============================================================================= 54 | " vim600: set fdm=marker: 55 | -------------------------------------------------------------------------------- /compiler/BTW/aap.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: compiler/BTW/aap.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " URL: http://hermitte.free.fr/vim/ressources/vimfiles/compiler/BTW/aap.vim 6 | " Version: 0.1 7 | " Created: 28th Nov 2004 8 | " Last Update: 29th Nov 2004 9 | "------------------------------------------------------------------------ 10 | " Description: A-A-P Filter for Build-Tools-Wrapper -- a Vim plugin. 11 | " 12 | "------------------------------------------------------------------------ 13 | " Installation: 14 | " -1- Install A-A-P 15 | " 0- Install Build-Tools-Wrapper. 16 | " 1- Drop this file into {rtp}/compiler/BTW/ 17 | " 2- Execute the command ":BTW set aap" or ":BTW setlocal aap" to load 18 | " this filter. 19 | " 20 | " History: 21 | " v0.1: First version of the filter 22 | " Uses the work done on my (LH speaking) previous compiler-plugin for 23 | " aap. 24 | " TODO: 25 | " * Add the various error messages specific to aap. 26 | " }}}1 27 | "============================================================================= 28 | 29 | 30 | "============================================================================= 31 | " Avoid global reinclusion {{{1 32 | if exists("g:loaded_aap_vim") 33 | \ && !exists('g:force_reload_aap_vim') 34 | finish 35 | endif 36 | let g:loaded_aap_vim = 1 37 | let s:cpo_save=&cpo 38 | set cpo&vim 39 | " Avoid global reinclusion }}}1 40 | "------------------------------------------------------------------------ 41 | " The definitions {{{1 42 | 43 | " a- Program to run 44 | " TODO: check if we are using aap or aap.bat 45 | if has('windows') 46 | let g:BTW_filter_program_aap = 'aap.bat' 47 | else 48 | let g:BTW_filter_program_aap = 'aap' 49 | endif 50 | 51 | " b- default value for 'efm' 52 | " 53 | " %+A is used to accept "Do not know" in the error message 54 | " set efm+=%+EAap:\ Do\ not\ know\ %m 55 | let g:BTW_adjust_efm_aap = '%+EAap: Do not know %m' 56 | \ . ',' . 'Aap: Error in recipe "%f" line %l: %m' 57 | 58 | " }}}1 59 | "------------------------------------------------------------------------ 60 | let &cpo=s:cpo_save 61 | "============================================================================= 62 | " vim600: set fdm=marker: 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | BTW has two main purposes: 4 | * [To simplify the on-the-fly tuning of `'compiler'` settings.](doc/filter.md) 5 | * [To offer a simplified interface to build, execute, test our programs.](doc/make_run.md) 6 | 7 | It is also able to interface with [projects under CMake](doc/cmake.md). 8 | 9 | And, it provides an [airline](https://github.com/bling/vim-airline) extension 10 | that displays the current project name and compilation mode. This information 11 | will also be displayed for the quickfix window. 12 | 13 | # Installation 14 | * Requirements: Vim 7.+, [lh-vim-lib](http://github.com/LucHermitte/lh-vim-lib) (v4.0.0) 15 | * With [vim-addon-manager](https://github.com/MarcWeber/vim-addon-manager), install build-tools-wrapper (this is the preferred method because of the dependencies) 16 | ```vim 17 | ActivateAddons build-tools-wrapper 18 | ``` 19 | * or with [vim-flavor](http://github.com/kana/vim-flavor) which also supports 20 | dependencies: 21 | ``` 22 | flavor 'LucHermitte/vim-build-tools-wrapper' 23 | ``` 24 | * or you can clone the git repositories (expecting I haven't forgotten anything): 25 | ```vim 26 | git clone git@github.com:LucHermitte/lh-vim-lib.git 27 | git clone git@github.com:LucHermitte/vim-build-tools-wrapper.git 28 | ``` 29 | * or with Vundle/NeoBundle (expecting I haven't forgotten anything): 30 | ```vim 31 | Bundle 'LucHermitte/lh-vim-lib' 32 | Bundle 'LucHermitte/vim-build-tools-wrapper' 33 | ``` 34 | 35 | # See also 36 | 37 | ## Dependencies 38 | 39 | You will most certainly require a project management plugin. I can offer you [local\_vimrc](http://github.com/LucHermitte/local_vimrc), there are plenty alternatives (with similar names), or even the good old project.vim plugin. 40 | 41 | ## Examples of configuration of BTW 42 | 43 | * See the two `_local_vimrc*.vim` files from my [Rasende Roboter solver](http://github.com/LucHermitte/Rasende). 44 | * See the two same files from my configuration for working with openjpeg _(link to be added)_. 45 | 46 | ## Alternatives 47 | There are a few alternative plugins that I'm aware of: 48 | * [Tim Pope's vim-dispatch](http://github.com/tpope/vim-dispatch) regarding the encapsulation of `:make` 49 | * Marc Weber's _name-forgotten_ plugin to run things in background 50 | * [Jacky Alciné's CMake.vim plugin](http://jalcine.github.io/cmake.vim/) 51 | 52 | [![Project Stats](https://www.openhub.net/p/21020/widgets/project_thin_badge.gif)](https://www.openhub.net/p/21020) 53 | -------------------------------------------------------------------------------- /License.md: -------------------------------------------------------------------------------- 1 | Copyright 2001-2015, Luc Hermitte 2 | 3 | # Scripts License 4 | 5 | All scripts (VimL, templates, bash, perl, etc.) from lh-vim are 6 | distributed under FSF's GPLv3 license. 7 | 8 | See http://www.gnu.org/licenses/gpl.txt for more information. 9 | 10 | 11 | # License exception for generated code 12 | 13 | Many lh-vim scripts generate code. Unless specified otherwise, the code generated is under the following license exception. 14 | 15 | 16 | Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 17 | 18 | This Exception is an additional permission under section 7 of the GNU General Public License, version 3 ("GPLv3"). It applies to a given file that bears a notice placed by the copyright holder of the file stating that the file is governed by GPLv3 along with this Exception. 19 | 20 | The purpose of this Exception is to allow distribution of lh-vim's typical output under terms of the recipient's choice (including proprietary). 21 | 22 | ## 0. Definitions. 23 | "Covered Code" is the source or object code of a version of lh-vim that is a covered work under this License. 24 | 25 | "Normally Copied Code" for a version of lh-vim means all parts of its Covered Code which that version can copy from its code (i.e., not from its input file) into its minimally verbose, non-debugging and non-tracing output. 26 | 27 | "Ineligible Code" is Covered Code that is not Normally Copied Code. 28 | 29 | ## 1. Grant of Additional Permission. 30 | You have permission to propagate output of lh-vim, even if such propagation would otherwise violate the terms of GPLv3. However, if by modifying lh-vim you cause any Ineligible Code of the version you received to become Normally Copied Code of your modified version, then you void this Exception for the resulting covered work. If you convey that resulting covered work, you must remove this Exception in accordance with the second paragraph of Section 7 of GPLv3. 31 | 32 | ## 2. No Weakening of lh-vim Copyleft. 33 | 34 | The availability of this Exception does not imply any general presumption that third-party software is unaffected by the copyleft requirements of the license of lh-vim. 35 | 36 | Disclaimer: This lh-vim license exception is directly derived from [AUTOCONF CONFIGURE SCRIPT EXCEPTION](http://www.gnu.org/licenses/autoconf-exception.html) to GPLv3 license. 37 | 38 | # License for documentation 39 | 40 | The documentation of lh-vim scripts distributed along the scripts, and of the wiki pages here are under the Creative Commons license ([CC by SA 3.0](http://creativecommons.org/licenses/by-sa/3.0/)) 41 | -------------------------------------------------------------------------------- /compiler/BTW/cmake.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: compiler/BTW/cmake.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " Version: 0.4.2 6 | " Created: 21st Feb 2012 7 | " Last Update: 10th Apr 2015 8 | "------------------------------------------------------------------------ 9 | " Description: 10 | " BTW cmake compilation toolchain 11 | " $ cmake --build --config [--target ] 12 | " $ ctest 13 | " 14 | " Options: 15 | " [bg]:BTW_project_build_dir 16 | " [bg]:BTW_project_config._.compilation.mode/[bg]:BTW_project_build_mode 17 | " 18 | " TODO: 19 | " * Use the internal lh#btw#_register_fix_ctest() 20 | " * Have a option function instead of [bg]:BTW_project_build_dir in order 21 | " to be able to peek into the unique (to be) [bg]:BTW_project_config. 22 | " }}}1 23 | "============================================================================= 24 | 25 | let s:cpo_save=&cpo 26 | set cpo&vim 27 | "------------------------------------------------------------------------ 28 | " How to invoke cmake to compile with it 29 | function! s:compile_cmake(...) 30 | let target = a:0 ? (' --target '.a:1) : '' 31 | let build_dir = lh#btw#option#_compilation_dir() 32 | let config = lh#btw#build_mode('Release') 33 | let res = 'cmake --build '.lh#path#fix(build_dir).' --config '.config.target 34 | return res 35 | endfunction 36 | 37 | let b:BTW_filter_program_cmake = function(s:getSNR('compile_cmake')) 38 | "------------------------------------------------------------------------ 39 | " cmake messes up with the error format as it prepends the error lines with 40 | " "%d>" 41 | " => tell BTW to fix efm by prepending what other tools add 42 | function! s:fix_efm_cmake(efm) 43 | let efm = split(a:efm, ',') 44 | call map(efm, '"%\\d%\\+>".v:val') 45 | return join(efm, ',') 46 | endfunction 47 | 48 | let b:BTW_adjust_efm_cmake = { 49 | \ 'post': function(s:getSNR('fix_efm_cmake')), 50 | \ 'value': 'default efm' 51 | \} 52 | 53 | "------------------------------------------------------------------------ 54 | " 55 | " s:getSNR([func_name]) {{{3 56 | function! s:getSNR(...) 57 | if !exists("s:SNR") 58 | let s:SNR=matchstr(expand(''), '\d\+_\zegetSNR$') 59 | endif 60 | return s:SNR . (a:0>0 ? (a:1) : '') 61 | endfunction 62 | 63 | "------------------------------------------------------------------------ 64 | let &cpo=s:cpo_save 65 | "============================================================================= 66 | " vim600: set fdm=marker: 67 | -------------------------------------------------------------------------------- /compiler/BTW/gcc.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Author: Luc Hermitte 3 | # 4 | # Purpose: Filter outputs from GCC like the error messages from the 5 | # link phase. 6 | # Defined as a filter to use on make's result. 7 | # Meant to be used by Vim. 8 | # Created: 28th Nov 2004 9 | # Last Update: 08th Dec 2004 10 | # ====================================================================== 11 | 12 | ### Code {{{1 13 | 14 | use strict ; 15 | use Getopt::Long ; # Getoptions() 16 | 17 | ## Options {{{2 18 | my $grp_lnk = 1; 19 | my $click_lnk = 0; 20 | my $obj_dir = ""; 21 | my $src_dir = ""; 22 | 23 | # check_options() {{{3 24 | sub check_options { 25 | GetOptions ( 26 | "grp-lnk:i" => \$grp_lnk 27 | # ,"no-grp-lnk" => sub { $grp_lnk = 0; } 28 | ,"clk-lnk:i" => \$click_lnk 29 | # ,"no-clk-lnk" => sub { $click_lnk = 0; } 30 | ,"obj=s" => \$obj_dir 31 | ,"tu=s" => \$src_dir 32 | ) or die("gcc.pl [-grp-lnk] [-clk-lnk [-obj=dir] [-tu=dir] ]\n"); 33 | 34 | # Eat a terminal / at the end of the object-files path 35 | $obj_dir =~ s#[^\\/]$#$&/# ; 36 | # Search for / or \ i the object-files path 37 | $obj_dir =~ s#[\\/]#[\\\\/]#g ; 38 | # Only use / in the error message -> Vim does not care. 39 | $src_dir =~ s#\\#/#g ; 40 | # If non nul, be sure there is a / at the end. 41 | $src_dir =~ s#[^\\/]$#$&/# ; 42 | 43 | } 44 | 45 | check_options() ; 46 | 47 | ## obj2src {{{2 48 | sub obj2src { 49 | my ($path, $file) = @_ ; 50 | $path =~ s#^$obj_dir#$src_dir# ; 51 | return "$path$file"; 52 | } 53 | 54 | ## check_obj {{{2 55 | # In the :match, the $i are: 56 | # $1: path 57 | # $2: object file 58 | # $3: entry in the object file (?) 59 | # $4: name of the translation unit 60 | # $5: error message 61 | 62 | my $last_obj_file ; 63 | sub check_obj { 64 | my $disp_file ; 65 | if ( m#^(?:(.*[/\\])([^/\\]*\.o(?:bj)?))(\(.*?\)):([^:]*):(.*)# ) { 66 | # path/filename to display 67 | if ($click_lnk) { 68 | $disp_file = obj2src($1, $4) . "\:1:" ; 69 | } else { 70 | $disp_file = "$1$2\:$4\:" ; 71 | } 72 | 73 | # if I want to merge these errors 74 | if ( !$grp_lnk || ("$last_obj_file" ne "$1$4") ) { 75 | $last_obj_file = "$1$4" ; 76 | printf "$disp_file" ; 77 | if ($grp_lnk) { 78 | printf " Link error(s)\n" ; 79 | } 80 | } 81 | # Print the current error 82 | printf "$3$5\n"; 83 | return 1 ; 84 | } else { return 0 ; } 85 | } 86 | 87 | ## check_lib {{{2 88 | # In the :match, the $i are: 89 | # $1: path/library(object_file) 90 | # $2: entry in the object file (?) 91 | # $3: name of the translation unit 92 | # $4: error message 93 | 94 | sub check_lib { 95 | return 0 if !$grp_lnk; 96 | if ( m#^(.*\.a\(.*?\))(\(.*?\)):([^:]*):(.*)# ) { 97 | if ( "$last_obj_file" ne "$1" ) { 98 | $last_obj_file = "$1" ; 99 | printf "$1\:: Link error(s)\n"; 100 | } 101 | printf "$2 $3\: $4\n"; 102 | return 1 ; 103 | } else { return 0 ; } 104 | } 105 | 106 | ## Main loop: The convertion. {{{2 107 | 108 | my $do_sthg_on_obj = $grp_lnk || $click_lnk ; 109 | 110 | while (<>) 111 | { 112 | chop; 113 | if ( $do_sthg_on_obj && (check_obj($_) || check_lib($_))) { 114 | } else { 115 | print "$_\n"; 116 | } 117 | } 118 | 119 | 120 | # ====================================================================== 121 | # vim600: set foldmethod=marker: 122 | # vim:et:ts=8:tw=79: 123 | -------------------------------------------------------------------------------- /compiler/BTW/substitute_filenames.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: compiler/BTW/substitute_filenames.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " Licence: GPLv3 6 | " Version: 0.7.0 7 | " Created: 14th Mar 2014 8 | " Last Update: 16th Oct 2016 9 | "------------------------------------------------------------------------ 10 | " Description: 11 | " BTW filter to replace expressions on the fly 12 | " This kind of filter is useful when the build chain uses configuration 13 | " files that are instaciated in the build directory. 14 | " The actual file that needs to be opened in the original file in thoses 15 | " cases. 16 | " 17 | " Parameters: 18 | " - (bg):{ft_}BTW_substitute_names: [ [old1, new1], [old2, new2], ...] 19 | "------------------------------------------------------------------------ 20 | " TODO: 21 | " Support multiple uses: 22 | " - this plugin shall replace cygwin filter for instance 23 | " and we must be able to continue to use it to display the original 24 | " filenames 25 | " }}}1 26 | "============================================================================= 27 | 28 | let s:cpo_save=&cpo 29 | set cpo&vim 30 | "------------------------------------------------------------------------ 31 | " Main {{{1 32 | function! BTW_Substitute_Filenames() abort 33 | let list = lh#ft#option#get('BTW.substitute_names', &ft, []) 34 | if !empty(list) 35 | call s:Transform(list, 1) 36 | endif 37 | endfunction 38 | 39 | function! s:Transform(list, doSubstitute) abort 40 | let subst_list = a:list 41 | call map(subst_list, '[lh#btw#_evaluate(v:val[0]), lh#btw#_evaluate(v:val[1])]') 42 | let g:qfs = [] 43 | try 44 | let qf_changed = 0 45 | let qflist = getqflist() 46 | 47 | for qf in qflist 48 | " 1- Fixing text 49 | let qft = qf.text 50 | for [before, after] in subst_list 51 | let qft = substitute(qft, before, after, 'g') 52 | endfor 53 | if qft != qf.text 54 | if qf.bufnr == 0 55 | let till_colon = matchstr(qft, '^[^:]*\ze:') " won't work under windows... 56 | if filereadable(till_colon) " trick files recognized on the fly 57 | let qf.bufnr = - lh#buffer#get_nr(till_colon) 58 | endif 59 | let qf.text = qft[(len(till_colon)+1) : ] 60 | let qf.text = substitute(qf.text, '^\s*', '', '') 61 | let qf.filename = till_colon 62 | else 63 | let qf.text = qft 64 | endif 65 | let qf_changed = 1 66 | let g:qfs += [qf] 67 | endif 68 | 69 | " 2- Fixing buffer loaded 70 | if a:doSubstitute && qf.bufnr > 0 71 | let old_bufname = bufname(qf.bufnr) 72 | let new_bufname = old_bufname 73 | for [before, after] in subst_list 74 | let new_bufname = substitute(new_bufname, before, after, 'g') 75 | endfor 76 | 77 | if new_bufname != old_bufname 78 | let msg = qf.bufnr . ' -> ' 79 | let qf.bufnr = lh#buffer#get_nr(new_bufname) 80 | let msg.= qf.bufnr . ' ('.new_bufname.')' 81 | " echomsg msg 82 | let qf_changed = 1 83 | endif 84 | elseif qf.bufnr < 0 85 | let qf.bufnr = - qf.bufnr " trick files recognized on the fly 86 | endif 87 | endfor 88 | 89 | if qf_changed 90 | call setqflist(qflist, 'r') 91 | endif 92 | catch /.*/ 93 | call lh#common#error_msg("Error: ".v:exception. " throw at: ".v:throwpoint) 94 | endtry 95 | endfunction 96 | 97 | call lh#btw#filters#register_hook(2, 'BTW_Substitute_Filenames', 'post') 98 | 99 | " }}}1 100 | let &cpo=s:cpo_save 101 | "============================================================================= 102 | " vim600: set fdm=marker: 103 | -------------------------------------------------------------------------------- /autoload/airline/extensions/btw.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: autoload/airline/extensions/btw.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " Version: 0.7.0 6 | let s:k_version = '070' 7 | " Created: 09th Apr 2015 8 | " Last Update: 16th Oct 2016 9 | "------------------------------------------------------------------------ 10 | " Description: 11 | " Airline extension for BuildToolsWrapper 12 | " TODO: 13 | " - Display number of errors and warnings 14 | " }}}1 15 | "============================================================================= 16 | 17 | let s:cpo_save=&cpo 18 | set cpo&vim 19 | "------------------------------------------------------------------------ 20 | " ## Misc Functions {{{1 21 | " # Version {{{2 22 | function! airline#extensions#btw#version() 23 | return s:k_version 24 | endfunction 25 | 26 | " # Debug {{{2 27 | if !exists('s:verbose') 28 | let s:verbose = 0 29 | endif 30 | function! airline#extensions#btw#verbose(...) 31 | if a:0 > 0 | let s:verbose = a:1 | endif 32 | return s:verbose 33 | endfunction 34 | 35 | function! s:Verbose(expr) 36 | if s:verbose 37 | echomsg a:expr 38 | endif 39 | endfunction 40 | 41 | function! airline#extensions#btw#debug(expr) 42 | return eval(a:expr) 43 | endfunction 44 | 45 | 46 | "------------------------------------------------------------------------ 47 | " ## Options {{{1 48 | LetIfUndef g:airline#extensions#btw#section 'b' 49 | LetIfUndef g:airline#extensions#btw#section_qf 'a' 50 | 51 | " ## Exported functions {{{1 52 | " # Registration {{{2 53 | 54 | " Due to some potential rendering issues, the use of the `space` variable is 55 | " recommended. 56 | let s:spc = g:airline_symbols.space 57 | 58 | " Function: airline#extensions#btw#init(ext) {{{3 59 | function! airline#extensions#btw#init(ext) abort 60 | " Here we define a new part for the plugin. This allows users to place this 61 | " extension in arbitrary locations. 62 | call airline#parts#define_raw('cats', '%{airline#extensions#btw#build_mode()}') 63 | 64 | " Next up we add a funcref so that we can run some code prior to the 65 | " statusline getting modifed. 66 | call a:ext.add_statusline_func('airline#extensions#btw#apply') 67 | 68 | " You can also add a funcref for inactive statuslines. 69 | " call a:ext.add_inactive_statusline_func('airline#extensions#btw#unapply') 70 | endfunction 71 | 72 | " Function: airline#extensions#btw#apply(...) {{{3 73 | " This function will be invoked just prior to the statusline getting modified. 74 | function! airline#extensions#btw#apply(...) abort 75 | " First, in case this is a qf window, add metrics. 76 | if &ft == 'qf' 77 | let metrics = lh#btw#build#_get_metrics() 78 | let w:airline_section_error = metrics.errors 79 | let w:airline_section_warning = metrics.warnings 80 | endif 81 | 82 | " Then, we check this is a compiled file with a compilation mode & al 83 | if !lh#btw#option#_has_project_config() 84 | return 85 | endif 86 | 87 | " Get the section to use according to the current filetype 88 | let section = lh#ft#option#get_postfixed('airline#extensions#btw#section', &ft, 'b', 'g') 89 | 90 | " Let's say we want to append to section_{section}, first we check if there's 91 | " already a window-local override, and if not, create it off of the global 92 | " section_{section}. 93 | let w:airline_section_{section} = get(w:, 'airline_section_'.section, g:airline_section_{section}) 94 | 95 | " Then we just append this extenion to it, optionally using separators. 96 | let fmt = lh#option#get('airline#extensions#btw#format_section', s:spc.g:airline_left_alt_sep.s:spc.'%s') 97 | let w:airline_section_{section} .= printf(fmt, '%{airline#extensions#btw#build_mode()}') 98 | endfunction 99 | 100 | " Function: airline#extensions#btw#build_mode() {{{3 101 | function! airline#extensions#btw#build_mode() abort 102 | let mode = lh#btw#build_mode() 103 | let name = lh#btw#project_name() 104 | let fmt = lh#option#get('airline#extensions#btw#format_mode', '%s'.s:spc.'%s') 105 | return printf(fmt, name, mode) 106 | endfunction 107 | "------------------------------------------------------------------------ 108 | " ## Internal functions {{{1 109 | 110 | " }}}1 111 | "------------------------------------------------------------------------ 112 | let &cpo=s:cpo_save 113 | "============================================================================= 114 | " vim600: set fdm=marker: 115 | -------------------------------------------------------------------------------- /autoload/lh/btw/filters.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: autoload/lh/btw/filters.vim {{{1 3 | " Maintainer: Luc Hermitte 4 | " 5 | " Licence: GPLv3 6 | " Version: 0.4.0 7 | let s:k_version = 040 8 | " Created: 13th Mar 2014 9 | " Last Update: 23rd Mar 2015 10 | "------------------------------------------------------------------------ 11 | " Description: 12 | " Generic way to add on-the-fly filters and hooks on quickfix results 13 | " (from within vim) 14 | " }}}1 15 | "============================================================================= 16 | 17 | let s:cpo_save=&cpo 18 | set cpo&vim 19 | "------------------------------------------------------------------------ 20 | " ## Misc Functions {{{1 21 | " # Version {{{2 22 | function! lh#btw#filters#version() 23 | return s:k_version 24 | endfunction 25 | 26 | " # Debug {{{2 27 | let s:verbose = get(s:, 'verbose', 0) 28 | function! lh#btw#filters#verbose(...) 29 | if a:0 > 0 | let s:verbose = a:1 | endif 30 | return s:verbose 31 | endfunction 32 | 33 | function! s:Log(expr, ...) 34 | call call('lh#log#this',[a:expr]+a:000) 35 | endfunction 36 | 37 | function! s:Verbose(expr, ...) 38 | if s:verbose 39 | call call('s:Log',[a:expr]+a:000) 40 | endif 41 | endfunction 42 | 43 | function! lh#btw#filters#debug(expr) abort 44 | return eval(a:expr) 45 | endfunction 46 | 47 | "------------------------------------------------------------------------ 48 | " ## Exported functions {{{1 49 | 50 | " # QuickFix Hooks {{{2 51 | " Function: lh#btw#filters#register_hook(prio, Hook, kind) {{{3 52 | function! lh#btw#filters#register_hook(prio, Hook, kind) 53 | if !exists('s:qf_hooks') 54 | call lh#btw#filters#_clear_hooks() 55 | augroup BTW_QF_PreHook 56 | au! 57 | " clean folding data before compiling 58 | au QuickFixCmdPre make call lh#btw#filters#_apply_quick_fix_hooks('pre') 59 | au QuickFixCmdPost make call lh#btw#filters#_apply_quick_fix_hooks('post') 60 | au FileType qf call lh#btw#filters#_apply_quick_fix_hooks('open') 61 | augroup END 62 | endif 63 | 64 | if !has_key(s:qf_hooks[a:kind], a:prio) 65 | let s:qf_hooks[a:kind][a:prio] = {} 66 | endif 67 | let s:qf_hooks[a:kind][a:prio][a:Hook] = function(a:Hook) 68 | endfunction 69 | 70 | " Function: lh#btw#filters#register_hooks(Hooks) {{{3 71 | function! lh#btw#filters#register_hooks(Hooks) 72 | if !exists('s:qf_hooks') 73 | call lh#btw#filters#_clear_hooks() 74 | augroup BTW_QF_PreHook 75 | au! 76 | " clean folding data before compiling 77 | au QuickFixCmdPre make call s:ApplyQuickFixHooks('pre') 78 | au QuickFixCmdPost make call s:ApplyQuickFixHooks('post') 79 | au FileType qf call s:ApplyQuickFixHooks('open') 80 | augroup END 81 | endif 82 | 83 | for [kind, prio_hook] in items(a:Hooks) 84 | for [prio, Hook] in items(prio_hook) 85 | if !has_key(s:qf_hooks[kind], prio) 86 | let s:qf_hooks[kind][prio] = {} 87 | endif 88 | let s:qf_hooks[kind][prio][Hook] = function(Hook) 89 | endfor 90 | endfor 91 | endfunction 92 | 93 | " Function: lh#btw#filters#_apply_quick_fix_hooks(hook_kind) {{{3 94 | function! lh#btw#filters#_apply_quick_fix_hooks(hook_kind) abort 95 | if !exists('s:qf_hooks') | return | endif 96 | let hooks_by_prio_dict = s:qf_hooks[a:hook_kind] 97 | let hooks_by_prio = items(hooks_by_prio_dict) 98 | call sort(hooks_by_prio, 's:SortByFirstNum') 99 | let hooks = map(copy(hooks_by_prio), 'v:val[1]') 100 | 101 | for hooks_of_prio in hooks 102 | for Hook in values(hooks_of_prio) 103 | call s:Verbose(a:hook_kind . ' -> ' . string(Hook)) 104 | if s:verbose >= 2 105 | debug call Hook() 106 | else 107 | call Hook() 108 | endif 109 | endfor 110 | endfor 111 | endfunction 112 | 113 | " Function: lh#btw#filters#_clear_hooks() {{{3 114 | function! lh#btw#filters#_clear_hooks() 115 | let s:qf_hooks = {'pre':{}, 'post':{}, 'open':{}, 'syntax':{}} 116 | endfunction 117 | 118 | "------------------------------------------------------------------------ 119 | " ## Internal functions {{{1 120 | " # Misc functions {{{2 121 | " Function: s:SortByFirstNum(lhs, rhs) {{{3 122 | function! s:SortByFirstNum(lhs, rhs) 123 | let diff = eval(a:lhs[0]) - eval(a:rhs[0]) 124 | return diff < 0 ? -1 125 | \ : diff == 0 ? 0 126 | \ : 1 127 | endfunction 128 | 129 | " }}}1 130 | "------------------------------------------------------------------------ 131 | let &cpo=s:cpo_save 132 | "============================================================================= 133 | " vim600: set fdm=marker: 134 | -------------------------------------------------------------------------------- /autoload/lh/btw/project.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: autoload/lh/btw/project.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " Version: 0.7.0. 6 | let s:k_version = 070 7 | " Created: 15th Jan 2015 8 | " Last Update: 14th Oct 2016 9 | "------------------------------------------------------------------------ 10 | " Description: 11 | " Internal functions to generate new project config files from templates. 12 | " Todo: 13 | " * Apply mt_jump_to_first_markers on the 2 other files generated 14 | " }}}1 15 | "============================================================================= 16 | 17 | let s:cpo_save=&cpo 18 | set cpo&vim 19 | "------------------------------------------------------------------------ 20 | " ## Misc Functions {{{1 21 | " # Version {{{2 22 | function! lh#btw#project#version() 23 | return s:k_version 24 | endfunction 25 | 26 | " # Debug {{{2 27 | let s:verbose = get(s:, 'verbose', 0) 28 | function! lh#btw#project#verbose(...) 29 | if a:0 > 0 | let s:verbose = a:1 | endif 30 | return s:verbose 31 | endfunction 32 | 33 | function! s:Log(expr, ...) 34 | call call('lh#log#this',[a:expr]+a:000) 35 | endfunction 36 | 37 | function! s:Verbose(expr, ...) 38 | if s:verbose 39 | call call('s:Log',[a:expr]+a:000) 40 | endif 41 | endfunction 42 | 43 | function! lh#btw#project#debug(expr) abort 44 | return eval(a:expr) 45 | endfunction 46 | 47 | "------------------------------------------------------------------------ 48 | " ## Exported functions {{{1 49 | " # New project {{{2 50 | " Function: lh#btw#project#new(...) {{{3 51 | function! lh#btw#project#new(...) abort 52 | if a:0 == 0 53 | call lh#common#warning_msg('BTW new_project ... name= config= -src_dir= (def=expand("%:p:h"))') 54 | return 55 | endif 56 | let extension_for_configurable_files = '' 57 | 58 | let args = call('lh#btw#project#_analyse_params', a:000) 59 | if has_key(args, '_prj_config') 60 | if args._prj_config !~ '^g:' 61 | let args._prj_config = 'g:'.args._prj_config 62 | endif 63 | endif 64 | let args.description = "Definition of vim's local options for the project ". (args._prj_name) 65 | let cleanup = lh#on#exit() 66 | \.restore('g:mt_IDontWantTemplatesAutomaticallyInserted') 67 | \.restore('g:mt_jump_to_first_markers') 68 | " mu-template expansion will be done manually in order to inject the precise 69 | " parameters 70 | try 71 | let g:mt_IDontWantTemplatesAutomaticallyInserted = 1 72 | let g:mt_jump_to_first_markers = 0 73 | call lh#window#split('_vimrc_local.vim') 74 | call lh#mut#expand_and_jump(0, 'vim', args) 75 | 76 | if has_key(args.project_kind, 'c') || has_key(args.project_kind, 'cpp') 77 | call lh#window#split('_vimrc_cpp_style.vim') 78 | call lh#mut#expand_and_jump(0, 'vim/internals/vim-header', args) 79 | normal! G 80 | call lh#mut#expand_and_jump(0, 'vim/internals/vim-rc-local-cpp-style', args) 81 | normal! G 82 | call lh#mut#expand_and_jump(0, 'vim/internals/vim-footer', args) 83 | endif 84 | let using_cmake = has_key(args.project_kind, 'cmake') 85 | if using_cmake 86 | let extension_for_configurable_files = 'in' 87 | call lh#window#split('_vimrc_local_global_defs.vim') 88 | call lh#mut#expand_and_jump(0, 'vim/internals/vim-header', args) 89 | normal! G 90 | call lh#mut#expand_and_jump(0, 'vim/internals/vim-rc-local-global-cmake-def', args) 91 | normal! G 92 | call lh#mut#expand_and_jump(0, 'vim/internals/vim-footer', args) 93 | endif 94 | finally 95 | call cleanup.finalize() 96 | endtry 97 | if has_key(args.project_kind, 'doxygen') 98 | call lh#window#split('Doxyfile'.extension_for_configurable_files) 99 | endif 100 | if using_cmake 101 | call lh#window#split('CMakeLists.txt') 102 | endif 103 | endfunction 104 | 105 | "------------------------------------------------------------------------ 106 | " ## Internal functions {{{1 107 | " # Preparations {{{2 108 | let s:ctxs = 'name\|src_dir\|config' 109 | function! lh#btw#project#_analyse_params(...) abort 110 | try 111 | let isk_save = &isk 112 | set isk-=: 113 | 114 | let kind = [] 115 | let args = {} 116 | let ctx = '' 117 | for opt in a:000 118 | if ctx == 'kind' 119 | let kind += split(opt, ',') 120 | let ctx = '' 121 | elseif !empty(ctx) 122 | let args['_prj_'.ctx] = opt 123 | let ctx = '' 124 | else 125 | let match = matchstr(opt, '^\('.s:ctxs.'\)\>\ze[=:]\=') 126 | let lm = len(match) 127 | let lo = len(opt) 128 | if lm == 0 129 | let kind += [opt] 130 | elseif lo==lm || (lo - lm == 1 && opt[lm] =~ '[:=]') 131 | let ctx = match 132 | elseif lo > lm + 1 133 | if opt[lm] != '=' 134 | throw "'=' expected in ".string(opt) 135 | endif 136 | let args['_prj_'.match] = opt[lm+1:] 137 | endif 138 | endif 139 | endfor 140 | 141 | let args.project_kind = eval('extend('.join(map(kind, '{(v:val): 1}'), ',').')') 142 | 143 | return args 144 | finally 145 | let &isk = isk_save 146 | endtry 147 | endfunction 148 | 149 | " }}}1 150 | "------------------------------------------------------------------------ 151 | let &cpo=s:cpo_save 152 | "============================================================================= 153 | " vim600: set fdm=marker: 154 | -------------------------------------------------------------------------------- /autoload/lh/btw/job_build.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: autoload/lh/btw/job_build.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " Version: 0.7.0. 6 | let s:k_version = '070' 7 | " Created: 10th May 2016 8 | " Last Update: 12th Oct 2016 9 | "------------------------------------------------------------------------ 10 | " Description: 11 | " Background compilation with latest job_start() API 12 | " 13 | " This feature requires patch 7.4.1980 (if I'm not mistaken) 14 | " 15 | "------------------------------------------------------------------------ 16 | " TODO: 17 | " }}}1 18 | "============================================================================= 19 | let s:cpo_save=&cpo 20 | set cpo&vim 21 | "------------------------------------------------------------------------ 22 | " ## Misc Functions {{{1 23 | " # Version {{{2 24 | function! lh#btw#job_build#version() 25 | return s:k_version 26 | endfunction 27 | 28 | " # Debug {{{2 29 | let s:verbose = get(s:, 'verbose', 0) 30 | function! lh#btw#job_build#verbose(...) 31 | if a:0 > 0 | let s:verbose = a:1 | endif 32 | return s:verbose 33 | endfunction 34 | 35 | function! s:Log(expr, ...) 36 | call call('lh#log#this',[a:expr]+a:000) 37 | endfunction 38 | 39 | function! s:Verbose(expr, ...) 40 | if s:verbose 41 | call call('s:Log',[a:expr]+a:000) 42 | endif 43 | endfunction 44 | 45 | function! lh#btw#job_build#debug(expr) abort 46 | return eval(a:expr) 47 | endfunction 48 | 49 | 50 | "------------------------------------------------------------------------ 51 | " ## Globals private variables {{{1 52 | " - s:job 53 | " - s:cmd 54 | " - g:lh#btw#auto_cbottom 55 | 56 | let s:has_qf_properties = has("patch-7.4.2200") 57 | 58 | "------------------------------------------------------------------------ 59 | " ## API functions {{{1 60 | " Function: lh#btw#job_build#execute(cmd) {{{2 61 | function! lh#btw#job_build#execute(cmd) abort 62 | " if lh#btw#job_build#is_running() 63 | " let choice = CONFIRM("A background compilation is under way. Do you want to\n-> ", ["&Wait for the current compilation to finish", "&Stop the current compilation and start a new one"]) 64 | " if choice == 2 65 | " let s:must_replace_comp = a:cmd 66 | " call lh#btw#job_build#_stop() 67 | " endif 68 | " return 69 | " endif 70 | call s:init(a:cmd) 71 | return 72 | endfunction 73 | 74 | "------------------------------------------------------------------------ 75 | " ## Internal functions {{{1 76 | 77 | " # Compilation {{{2 78 | function! s:job_description(job) abort " {{{3 79 | let what = a:job.project_name . (!empty(a:job.build_mode) ? ' ('.a:job.build_mode.')' : '') 80 | return what 81 | endfunction 82 | 83 | function! s:closeCB(channel, job_info) abort " {{{3 84 | echomsg string(a:000) 85 | " call s:Verbose("Background compilation with `%1' %2", s:cmd, job_status(a:channel)) 86 | try 87 | let stamp = reltime() 88 | call s:Verbose("Background compilation with `%1' finished", s:cmd) 89 | while ch_status(a:channel) == 'buffered' 90 | call s:callbackCB(a:channel, ch_read(a:channel)) 91 | endwhile 92 | let time = reltimefloat(reltime(s:job.start_time, stamp)) 93 | call setqflist([{'text': "Background compilation with `".(s:cmd)."` finished in ".string(time)."s with exitval ".a:job_info.exitval}], 'a') 94 | finally 95 | call s:Verbose('Job finished %1 -- %2', s:job, a:job_info) 96 | let what = s:job_description(s:job) 97 | unlet s:job 98 | endtry 99 | if ! exists('s:must_replace_comp') 100 | call lh#btw#build#_copen_bg_complete(what, a:job_info) 101 | redraw 102 | else 103 | call lh#btw#job_build#execute(s:must_replace_comp) 104 | unlet s:must_replace_comp 105 | endif 106 | endfunction 107 | 108 | function! s:callbackCB(channel, msg) abort " {{{3 109 | caddexpr a:msg 110 | if exists(':cbottom') && g:lh#btw#auto_cbottom 111 | let qf = getqflist() 112 | call assert_true(!empty(qf)) 113 | cbottom 114 | if qf[-1].valid 115 | let g:lh#btw#auto_cbottom = 0 116 | endif 117 | endif 118 | endfunction 119 | 120 | function! s:start_fail_cb() dict abort " {{{3 121 | call setqflist([{'text': "Background compilation with `".(self.cmd)."` finished with exitval ".job_info(self.job).exitval}], 'a') 122 | endfunction 123 | 124 | function! s:before_start_cb() dict abort " {{{3 125 | if exists(':cbottom') 126 | let g:lh#btw#auto_cbottom = lh#btw#option#_auto_scroll_in_bg() 127 | endif 128 | call s:Verbose("Background compilation with `%1' started", self.cmd) 129 | " Filling qflist is required because of lh#btw#build#_show_error() in caller 130 | " function 131 | let what = s:job_description(self) 132 | echomsg "Compilation of ".what." started." 133 | call setqflist([{'text': "Background compilation with `".(self.cmd)."` started"}]) 134 | call setqflist([], 'r', 135 | \ {'title': self.build_mode. ' compilation of ' . self.project_name}) 136 | let self.start_time = reltime() 137 | let s:job = self 138 | endfunction 139 | 140 | if exists(':cbottom') " {{{3 141 | let g:lh#btw#auto_cbottom = 0 142 | augroup BTW_stop_cbottom 143 | au! 144 | au BufEnter * if &ft=='qf' | let g:lh#btw#auto_cbottom = 0 | endif 145 | augroup END 146 | endif 147 | 148 | " Function: s:init(cmd) {{{3 149 | function! s:init(cmd) abort 150 | let s:cmd = a:cmd 151 | let mode = lh#btw#build_mode() 152 | let job = 153 | \ { 'txt' : 'Build '.lh#btw#project_name() . (empty(mode) ? '' : ' ('.mode.')') 154 | \ , 'cmd' : a:cmd 155 | \ , 'close_cb' : function('s:closeCB') 156 | \ , 'callback' : function('s:callbackCB') 157 | \ , 'start_fail_cb' : function('s:start_fail_cb') 158 | \ , 'before_start_cb': function('s:before_start_cb') 159 | \ , 'build_mode' : mode 160 | \ , 'project_name' : lh#btw#project_name() 161 | \ } 162 | call lh#async#queue(job) 163 | " Cannot return anything yet 164 | endfunction 165 | 166 | "------------------------------------------------------------------------ 167 | " }}}1 168 | "------------------------------------------------------------------------ 169 | let &cpo=s:cpo_save 170 | "============================================================================= 171 | " vim600: set fdm=marker: 172 | -------------------------------------------------------------------------------- /autoload/lh/btw/project_options.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: autoload/lh/btw/project_options.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " Licence: GPLv3 6 | " Version: 0.7.0 7 | let s:k_version = 0700 8 | " Created: 06th Sep 2012 9 | " Last Update: 14th Oct 2016 10 | "------------------------------------------------------------------------ 11 | " Description: 12 | " API to help define project options 13 | " 14 | "------------------------------------------------------------------------ 15 | " Installation: 16 | " Drop this file into {rtp}/autoload/lh/btw 17 | " Requires Vim7+, lh-vim 3.1.6 18 | " History: 19 | " v0.7.0 20 | " * Use new logging framework 21 | " v0.5.3 22 | " * Updated to new lh-vim-lib functions that create new splits, ignoring E36 23 | " v0.2.14: 24 | " * bug: When the project is organized with symbolic links, settings 25 | " weren't applied. e.g. 26 | " $$/ 27 | " +-> repo/branches/B42 28 | " +-> sources/ -> symlink to $$/repo/branches/B42 29 | " +-> build/ 30 | " v0.2.11: 31 | " * bug: don't prevent syntax highlighting & ft detection to be triggered 32 | " when launching vim with several files 33 | " v0.2.0: first factorization 34 | " TODO: «missing features» 35 | " Example: Defining CTest verbosity from local_vimrc: {{{2 36 | " let s:root = expand(":p:h") 37 | " let b:BTW_project_executable = { 'type': 'ctest', 'rule': '-VV'} 38 | " let g:sea_ctest_mode_menu = { 39 | " \ 'variable': 'sea_ctest_mode', 40 | " \ 'idx_crt_value': 0, 41 | " \ 'values': ['', '-V', '-VV'], 42 | " \ 'menu': {'priority': s:menu_priority.'30', 'name': s:menu_name.'CTest'}, 43 | " \ '_root': s:root 44 | " \ } 45 | " function! g:sea_ctest_mode_menu.do_update() dict 46 | " let b:BTW_project_executable.rule = g:sea_ctest_mode 47 | " endfunction 48 | " call lh#btw#project_options#add_toggle_option(g:sea_ctest_mode_menu) 49 | " 50 | " Example: Defining compilation mode in a cmake environment from local_vimrc {{{2 51 | " (two build dirs: build-d and build-r) 52 | " function! s:UpdateCompilDir() 53 | " let p = expand('%:p:h') 54 | " let s:build_dir = 'build-'.tolower(g:sea_compil_mode[0]) 55 | " let b:BTW_compilation_dir = s:project_root.'/'.s:build_dir 56 | " endfunction 57 | " let g:sea_compil_mode_menu = { 58 | " \ 'variable': 'sea_compil_mode', 59 | " \ 'idx_crt_value': 0, 60 | " \ 'values': ['Debug', 'Release'], 61 | " \ 'menu': {'priority': s:menu_priority.'20', 'name': s:menu_name.'M&ode'}, 62 | " \ '_root': s:root 63 | " \ } 64 | " 65 | " function! g:sea_compil_mode_menu.do_update() dict 66 | " let b:BTW_project_build_mode = g:sea_compil_mode 67 | " call s:UpdateCompilDir() 68 | " BTW rebuild 69 | " " we could also change the path to the project executable here as well 70 | " endfunction 71 | " call lh#btw#project_options#add_toggle_option(g:sea_compil_mode_menu) 72 | " 73 | " }}}1 74 | "============================================================================= 75 | 76 | let s:cpo_save=&cpo 77 | set cpo&vim 78 | "------------------------------------------------------------------------ 79 | " ## Misc Functions {{{1 80 | " # Version {{{2 81 | function! lh#btw#project_options#version() 82 | return s:k_version 83 | endfunction 84 | 85 | " # Debug {{{2 86 | let s:verbose = get(s:, 'verbose', 0) 87 | function! lh#btw#project_options#verbose(...) 88 | if a:0 > 0 | let s:verbose = a:1 | endif 89 | return s:verbose 90 | endfunction 91 | 92 | function! s:Log(expr, ...) 93 | call call('lh#log#this',[a:expr]+a:000) 94 | endfunction 95 | 96 | function! s:Verbose(expr, ...) 97 | if s:verbose 98 | call call('s:Log',[a:expr]+a:000) 99 | endif 100 | endfunction 101 | 102 | function! lh#btw#project_options#debug(expr) abort 103 | return eval(a:expr) 104 | endfunction 105 | 106 | "------------------------------------------------------------------------ 107 | " ## Globals {{{1 108 | if !exists('s:indices') 109 | let s:indices = {} 110 | endif 111 | 112 | if !exists('s:menus') 113 | let s:menus = {} 114 | endif 115 | 116 | 117 | "------------------------------------------------------------------------ 118 | " ## Internal functions {{{1 119 | " # s:Hook() dict {{{2 120 | function! s:Hook() dict abort 121 | " First check whether the data has already been updated for the buffer 122 | " considered 123 | let bid = bufnr('%') 124 | if !has_key(self, "_previous") 125 | let self._previous = {} 126 | endif 127 | if !has_key(self._previous, bid) 128 | let self._previous[bid] = -1 129 | endif 130 | let previous = self._previous[bid] 131 | let crt_value = self.val_id() 132 | if crt_value == previous 133 | call s:Verbose("abort for buffer ".expand('%:p')) 134 | return 135 | endif 136 | try 137 | call lh#window#split() 138 | " Bug: iterating on listed buffers (e.g. from vim *.cpp) is enough to 139 | " disable syntax highlighting 140 | " => 141 | " We delay the settings of b:variables for not loaded buffers. 142 | for b in lh#buffer#list('bufloaded') 143 | exe 'b '.b 144 | call s:Update(self) 145 | endfor 146 | finally 147 | q 148 | " Assert exists(self.variable) 149 | let self._previous[bid] = crt_value 150 | endtry 151 | endfunction 152 | 153 | " # s:Update(dict) {{{2 154 | function! s:Update(dict) abort 155 | try 156 | let p = expand('%:p') 157 | if !empty(p) && lh#path#is_in(p, a:dict._root) 158 | if s:verbose 159 | debug call a:dict.do_update() 160 | else 161 | call a:dict.do_update() 162 | endif 163 | let bid = bufnr('%') 164 | let a:dict._previous[bid] = a:dict.val_id() 165 | endif 166 | catch /.*/ 167 | let g:exception_data = a:dict 168 | echoerr "Buffer ".bufnr('%').": Cannot update project option ".string(a:dict).': '.v:exception.' at '.v:throwpoint 169 | endtry 170 | endfunction 171 | 172 | " # s:getSNR() {{{2 173 | function! s:getSNR(...) 174 | if !exists("s:SNR") 175 | let s:SNR=matchstr(expand(''), '\d\+_\zegetSNR$') 176 | endif 177 | return s:SNR . (a:0>0 ? (a:1) : '') 178 | endfunction 179 | 180 | "------------------------------------------------------------------------ 181 | " ## Exported functions {{{1 182 | " Function: lh#btw#project_options#add_toggle_option(menu) {{{2 183 | function! lh#btw#project_options#add_toggle_option(menu) abort 184 | if has_key(s:menus, a:menu.variable) 185 | " need to merge new info (i.e. everything but idx_crt_value) 186 | let menu = s:menus[a:menu.variable] 187 | let menu.values = a:menu.values 188 | let menu.menu = a:menu.menu 189 | else 190 | let s:menus[a:menu.variable] = a:menu 191 | let menu = s:menus[a:menu.variable] 192 | let menu.hook = function(s:getSNR('Hook')) 193 | endif 194 | call lh#menu#def_toggle_item(menu) 195 | " call menu.hook() " already called in menu#s:Set() 196 | return menu 197 | endfunction 198 | 199 | " Function: lh#btw#project_options#add_string_option(menu) {{{2 200 | function! lh#btw#project_options#add_string_option(menu) abort 201 | if has_key(s:menus, a:menu.variable) 202 | " need to merge new info (i.e. everything but idx_crt_value) 203 | let menu = s:menus[a:menu.variable] 204 | let menu.values = a:menu.values 205 | let menu.menu = a:menu.menu 206 | else 207 | let s:menus[a:menu.variable] = a:menu 208 | let menu = s:menus[a:menu.variable] 209 | let menu.hook = function(s:getSNR('Hook')) 210 | endif 211 | call lh#menu#def_string_item(menu) 212 | " call menu.hook() " already called in menu#s:Set() 213 | return menu 214 | endfunction 215 | 216 | " }}}1 217 | "------------------------------------------------------------------------ 218 | let &cpo=s:cpo_save 219 | "============================================================================= 220 | " vim600: set fdm=marker: 221 | -------------------------------------------------------------------------------- /autoload/lh/btw/option.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: autoload/lh/btw/option.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " Version: 0.7.0. 6 | let s:k_version = '070' 7 | " Created: 23rd Mar 2015 8 | " Last Update: 10th Aug 2016 9 | "------------------------------------------------------------------------ 10 | " Description: 11 | " Centralize BTW option retrieval 12 | " 13 | " List of deprecated variables in v0.7.0: 14 | " - (bpg):BTW_project -> (bpg):BTW.project 15 | " - (bpg):BTW_project_target -> (bpg):BTW.target 16 | " - (bpg):BTW_project_executable -> (bpg):BTW.executable 17 | " - (bpg):BTW_project_config -> (bpg):BTW.project_config 18 | " (bpg):BTW_project_build_mode -> (bpg):BTW.project_config 19 | " - g:BTW_autoscroll_background_compilation -> g:BTW.autoscroll_background_compilation 20 | " - g:BTW_GotoError -> g:BTW.goto_error 21 | " - g:BTW_make_in_background -> g:BTW.make_in_background 22 | " - g:BTW_make_multijobs -> g:BTW.make_multijobs 23 | " - (bpg):BTW_make_in_background_in -> (bpg):BTW.make_in_background_in 24 | " - (bpg):BTW_use_prio -> (bpg):BTW.use_prio 25 | " - g:BTW_qf_position -> g:BTW.qf_position 26 | " - g:BTW_QF_size -> g:BTW.qf_size 27 | " - (gpb):BTW_qf_syntax -> (gpb):BTW.qf_syntax 28 | " - (bpg):BTW_run_parameters -> (bpg):BTW.run_parameters 29 | " - (bpg):BTW_project_name -> (bpg):BTW.project_name 30 | " }}}1 31 | "============================================================================= 32 | 33 | let s:cpo_save=&cpo 34 | set cpo&vim 35 | "------------------------------------------------------------------------ 36 | " ## Misc Functions {{{1 37 | " # Version {{{2 38 | function! lh#btw#option#version() 39 | return s:k_version 40 | endfunction 41 | 42 | " # Debug {{{2 43 | if !exists('s:verbose') 44 | let s:verbose = 0 45 | endif 46 | function! lh#btw#option#verbose(...) 47 | if a:0 > 0 | let s:verbose = a:1 | endif 48 | return s:verbose 49 | endfunction 50 | 51 | function! s:Verbose(expr) 52 | if s:verbose 53 | echomsg a:expr 54 | endif 55 | endfunction 56 | 57 | function! lh#btw#option#debug(expr) 58 | return eval(a:expr) 59 | endfunction 60 | 61 | 62 | "------------------------------------------------------------------------ 63 | " ## Options {{{1 64 | " # Deprecated compatibility {{{2 65 | function! s:get(name, default, ...) abort " {{{3 66 | let res = call('lh#option#get', ['BTW.'.a:name, lh#option#unset()] + a:000) 67 | if lh#option#is_set(res) | return res | endif 68 | return call('lh#option#get', ['BTW_'.a:name, a:default] + a:000) 69 | endfunction 70 | 71 | function! s:old(name, default, ...) abort " {{{3 72 | return call('lh#option#get', ['BTW_'.a:name, a:default] + a:000) 73 | endfunction 74 | 75 | function! s:get_explicit_names(new_name, old_name, default, ...) abort " {{{3 76 | let res = call('lh#option#get', ['BTW.'.a:new_name, lh#option#unset()] + a:000) 77 | if lh#option#is_set(res) | return res | endif 78 | return call('lh#option#get', ['BTW_'.a:old_name, a:default] + a:000) 79 | endfunction 80 | 81 | function! s:get_from_buf(bufid, name, default, ...) abort " {{{3 82 | let res = call('lh#option#get_from_buf', [a:bufid, 'BTW.'.a:name, lh#option#unset()] + a:000) 83 | if lh#option#is_set(res) | return res | endif 84 | return call('lh#option#get_from_buf', [a:bufid, 'BTW_'.a:name, a:default] + a:000) 85 | endfunction 86 | 87 | " Function: lh#btw#option#_check_deprecated_options() {{{3 88 | let s:has_been_notified = 0 89 | function! lh#btw#option#_check_deprecated_options() abort 90 | let g = filter(copy(g:), 'v:key =~ "^BTW_"') 91 | let b = filter(copy(b:), 'v:key =~ "^BTW_"') 92 | if !s:has_been_notified && (empty(g) || empty(b)) 93 | let s:has_been_notified = 1 94 | call lh#common#error_msg("It seems you're using old BuildToolsWrappers options. They have been renamed. See :h BTW-deprecated-options") 95 | endif 96 | endfunction 97 | " # Compilation options {{{2 98 | " Function: lh#btw#option#_auto_scroll_in_bg() {{{3 99 | function! lh#btw#option#_auto_scroll_in_bg() abort 100 | return lh#option#get('BTW.autoscroll_background_compilation', 1, 'g') 101 | endfunction 102 | call lh#let#if_undef( 103 | \ 'g:BTW.autoscroll_background_compilation', 104 | \ s:old('autoscroll_background_compilation', 1, 'g')) 105 | 106 | " Function: lh#btw#option#_goto_error() {{{3 107 | function! lh#btw#option#_goto_error() abort 108 | return s:get_explicit_names('goto_error', 'GotoError', 1, 'g') 109 | endfunction 110 | 111 | " Function: lh#btw#option#_make_in_bg() {{{3 112 | " TODO: Shall we have the option project relative ? 113 | function! lh#btw#option#_make_in_bg() abort 114 | return lh#option#get('BTW.make_in_background', 0, 'g') 115 | endfunction 116 | call lh#let#if_undef( 117 | \ 'g:BTW.make_in_background', 118 | \ s:old('make_in_background', 0, 'g')) 119 | 120 | " Function: lh#btw#option#_make_in_bg_in() {{{3 121 | function! lh#btw#option#_make_in_bg_in() abort 122 | return s:get('make_in_background_in', '') 123 | endfunction 124 | 125 | " Function: lh#btw#option#_make_mj() {{{3 126 | function! lh#btw#option#_make_mj() abort 127 | let value = lh#option#get('BTW.make_multijobs', 0, 'g') 128 | if type(value) != type(0) 129 | call lh#common#error_msg("option BTW.make_multijobs is not a number") 130 | return 0 131 | endif 132 | return value 133 | endfunction 134 | call lh#let#if_undef( 135 | \ 'g:BTW.make_multijobs', 136 | \ s:old('make_multijobs', 0, 'g')) 137 | 138 | " Function: lh#btw#option#_project_config([bufid]) {{{3 139 | function! lh#btw#option#_project_config(...) abort 140 | if a:0 > 0 141 | " from buf version => no default to detect undefined option 142 | let bufid = a:1 143 | return s:get_from_buf(bufid, 'project_config', lh#option#unset()) 144 | else 145 | return s:get('project_config', {'type': 'modeline'} ) 146 | endif 147 | endfunction 148 | 149 | " Function: lh#btw#option#_has_project_config() {{{3 150 | function! lh#btw#option#_has_project_config() abort 151 | return exists('b:BTW_project_config') 152 | \ || exists('b:BTW.project_config') 153 | \ || lh#project#exists('p:BTW.project_config') 154 | endfunction 155 | 156 | 157 | " Function: lh#btw#option#_use_prio() {{{3 158 | function! lh#btw#option#_use_prio() abort 159 | return s:get('use_prio', 'update') 160 | endfunction 161 | 162 | 163 | " # Quickfix options {{{2 164 | " Function: lh#btw#option#_qf_position() {{{3 165 | function! lh#btw#option#_qf_position() abort 166 | return s:get('qf_position', '', 'g') 167 | endfunction 168 | 169 | " Function: lh#btw#option#_qf_size() {{{3 170 | function! lh#btw#option#_qf_size() abort 171 | " Default: 1/4 of total screen size 172 | let mx = min([15, &lines / 4]) 173 | let nl = mx > &winfixheight ? mx : &winfixheight 174 | let nl = s:get_explicit_names('qf_size', 'QF_size', nl, 'g') 175 | return nl 176 | endfunction 177 | 178 | " Function: lh#btw#option#_qf_syntax() {{{3 179 | function! lh#btw#option#_qf_syntax() abort 180 | " TODO: check why the order has been reversed 181 | return lh#option#get('BTW_qf_syntax', '', 'gpb') 182 | endfunction 183 | 184 | " # Miscellaneous options {{{2 185 | " Function: lh#btw#option#_run_parameters() {{{3 186 | function! lh#btw#option#_run_parameters() abort 187 | return s:get('run_parameters','') 188 | endfunction 189 | 190 | " Function: lh#btw#option#_project_name([bufid]) {{{3 191 | function! lh#btw#option#_project_name(...) abort 192 | return a:0 > 0 193 | \ ? s:get_from_buf(a:1, 'project_name', lh#option#unset()) 194 | \ : s:get('project_name') 195 | endfunction 196 | 197 | " Function: lh#btw#option#_compilation_dir([bufid]) {{{3 198 | function! lh#btw#option#_compilation_dir(...) abort 199 | return a:0 > 0 200 | \ ? s:get_from_buf(a:1, 'compilation_dir', '.') 201 | \ : s:get('compilation_dir', '.') 202 | endfunction 203 | 204 | " }}}1 205 | "------------------------------------------------------------------------ 206 | let &cpo=s:cpo_save 207 | "============================================================================= 208 | " vim600: set fdm=marker: 209 | -------------------------------------------------------------------------------- /doc/filter.md: -------------------------------------------------------------------------------- 1 | # Filter compilation output 2 | 3 | ## 1- Rationale 4 | 5 | When we want to use another compiler from vim, we have to load it with the 6 | `:compiler` command. This way we can change the `'errorformat'` and the 7 | `'makeprg'` options. This is nice. But this is not enough. 8 | * This approach does not permit to parse every error format. For instance: 9 | * It's impossible to have `'errorformat'` decode error messages produced 10 | by CMake (when used to compile, with whatever compiler) or CTest. Indeed 11 | these tools prepend each line produced with a number followed by a 12 | closing angle bracket: `%d>`. 13 | 14 | * Default compiler plugins don't translate pathnames on the fly, nor simplify 15 | error messages. This means that we'll have to pipe the result of the 16 | compilation chain (`make`, `ant`, `bjam`, ...) with: 17 | * the [indispensable STLfilt](http://www.bdsoft.com/tools/stlfilt.html) or 18 | [gccfilter](http://www.mixtion.org/gccfilter/) in order to simplify C++ 19 | error messages ; 20 | * `cygpath` in order to transform cygwin pathnames into windows pathnames 21 | (because we are using compilers, coming from cygwin, from native-gvim). 22 | * `c++filt` if we want to parse compilation output to transform all C++ 23 | mangled names into something comprehensible. 24 | 25 | In any case, we certainly don't want to define one compiler plugin for each 26 | possible situation (make + gccfilter, make + gccfilter + cygwin, ant + STLFilt + 27 | cygwin, ...) 28 | 29 | * Compiler plugins are made to support a single tool. Using several tools 30 | together is not expected. It means that: 31 | * We cannot compile with ant, convert cygwin filenames and expect gcc error 32 | messages (_corrupted_ by ant) 33 | * We cannot decode error messages from several distinct compilers or tools 34 | used by a common compilation chain: a Makefile can execute `$(CXX)`, 35 | `$(FC)`, Doxygen, and LaTeX. 36 | 37 | * Compiler-plugins aren't meant either to handle folding, or to conceal text 38 | in the quickfix window. 39 | 40 | In short, compiler-plugins don't scale. Sometimes, we need to add one filter, 41 | sometimes another or several. This is where BTW saves the day. 42 | 43 | ## 2- Filters 44 | 45 | Filters are of several kinds: 46 | * The ones that set what is to used as the main compilation chain (make, nmake, ant, rake, javac, ...) 47 | * The ones that filter the result of the compilation chain (cygwin make&gcc called from win32-gvim, application of STLfilt, cleaning up of CMake noise, ...) 48 | * The ones that fix `'errorformat'` 49 | * The ones that add useless but neat things (highlighting of result, folding related things, concealling of non pertinent text, ...) 50 | 51 | ### 2.1- Using filters 52 | 53 | #### Listing active filters: `:BTW echo ToolsChain()` 54 | The list of active filters in the current buffer can be obtained with: 55 | ```vim 56 | BTW echo ToolsChain() 57 | ``` 58 | 59 | #### Adding filters: `:BTW set(local)` 60 | In order to specify the compilation chain use: 61 | ```vim 62 | :BTW set _name of the filter_ 63 | :BTW setlocal _name of the filter_ 64 | ``` 65 | 66 | By default, vim default `'errorformat`' and `'makeprg'` are used. This is `make` filter. 67 | 68 | Other filters are simply added with either: 69 | ```vim 70 | :BTW add _name of the filter_ 71 | :BTW addlocal _name of the filter_ 72 | ``` 73 | 74 | If you're using a plugin that permits to emulate projects like 75 | [local_vimrc](http://github.com/LucHermitte/local_vimrc) prefer `setlocal` and 76 | `addlocal` subcommands. The filters used will be local to the buffers (/files) 77 | belonging to the project. 78 | 79 | Note: if `setlocal` or `addlocal` have been used in a buffer, the filters added 80 | with `set` or `add` will be ignored. 81 | 82 | #### Removing filters: `:BTW remove(local)` 83 | A filter added can be removed with: 84 | ```vim 85 | :BTW remove _name of the filter_ 86 | :BTW removelocal _name of the filter_ 87 | ``` 88 | 89 | Notes: 90 | * This two commands are meant for interactive tests of filters. If you have 91 | added your filters with `:BTW addlocal` from a 92 | [_vimrc_local file](http://github.com/LucHermitte/local_vimrc), you'll 93 | quite certainly observe odd behaviours. 94 | * `remove` will only remove global filters 95 | * `removelocal` will try to remove the local filter in all known buffers. 96 | 97 | ### 2.2- Default filters 98 | 99 | #### Compiler-plugins 100 | Any compiler-plugin installed can be used as a filter. 101 | 102 | #### Executables 103 | Any program available in the `$PATH` can be a filter (dmSTLfilt.pl, c++filt, ...) 104 | 105 | #### `cygwin` 106 | This filter fixes cygwin pathnames into windows pathnames. 107 | 108 | In the _vimrc\_local file, I write: 109 | ```vim 110 | if lh#system#OnDOSWindows() && lh#system#SystemDetected() == 'unix' 111 | BTW addlocal cygwin 112 | endif 113 | ``` 114 | 115 | #### Compilation chains 116 | `make`, `ant` (fix program output), `aap` 117 | 118 | #### `cmake` 119 | Removes this damn `%d>` that prepends outputs from `cmake` and `ctest` 120 | executables. 121 | 122 | ```vim 123 | " #### in _vimrc_local.vim 124 | :BTW setlocal cmake 125 | ``` 126 | 127 | It relies on the following options: 128 | * `(bg):BTW_project_build_dir` (This should changed an be masked in future 129 | versions) 130 | * `(bg):BTW_project_build_mode` (default: `Release`) 131 | 132 | This is mainly meant when the compilation is done with `cmake --build`. Tests executed 133 | thanks to CTest are addressed with the _project execution type_, when the tests 134 | are run with ``: 135 | ```vim 136 | " #### in _vimrc_local.vim 137 | LetIfUndef b:BTW_project_executable.type 'ctest' 138 | ``` 139 | 140 | #### `STLfilt` 141 | Filters C++ compiler output to in order to have readable error messages (the 142 | .vim file may need to be tuned to use the right STL filter). 143 | 144 | ```vim 145 | BTW addlocal STLfilt 146 | ``` 147 | 148 | #### `SunSWProLinkIsError` 149 | To have SunCC link error appear as errors. 150 | 151 | #### `shorten_filenames` 152 | This filter conceals part of filenames. 153 | 154 | It is parametrized with the [lh-dev option](http://github.com/LucHermitte/lh-dev#options-1) 155 | `(bg):{ft_}BTW_shorten_names`. The option takes a list of regex to conceal with 156 | `&` and/or lists of regex+conceal-characters, e.g. 157 | 158 | ```vim 159 | " #### in a _vimrc_local.vim file 160 | " Define the concealled file parts 161 | let b:BTW_shorten_names = [ 162 | \ [ '/usr/include', 'I' ], 163 | \ [ '/usr/local/include', 'L' ], 164 | \ 'foobar' 165 | \ ] 166 | " Tell to automatically import the buffer local variable to the quickfix 167 | " window 168 | QFImport b:BTW_shorten_names 169 | " Add the filter to the list of filter applied 170 | BTW addlocal shorten_filenames 171 | ``` 172 | 173 | Note: It's executed with _syntax_ _hooks_ of priority 8. The way quickfix 174 | works, we cannot alter filenames without altering the associated buffer number. 175 | Hence, the only way to simplify displayed filenames consists in concealing 176 | some of their parts. 177 | 178 | ```vim 179 | call lh#btw#filters#register_hook(8, 'BTW_Shorten_Filenames', 'syntax') 180 | ``` 181 | 182 | #### `substitute_filenames` 183 | This filters corrects filenames within vim. 184 | 185 | Some programs may produce error messages that cannot be decoded with vim 186 | `'errorformat'` option -- see CTest that prepends each line produced by the 187 | number of the test followed by a `>`. 188 | 189 | This filter permits to correct, from within Vim, filenames produced. It has the 190 | advantage of being portable (the filter relies exclusively on VimL), however 191 | it presents some quirks. Sometimes, syntax highlighting disappear in buffers 192 | already loaded that are recognized by the filter. 193 | 194 | In other words, prefer to correct produced filenames while `'makeprg'` command 195 | is executed. If you don't want to write a perl/sed/python script, you can alway 196 | use this filter. 197 | 198 | 199 | The filter is parametrized with the 200 | [lh-dev option](http://github.com/LucHermitte/lh-dev#options-1) 201 | `(bg):{ft_}BTW_substitute_names`. The option takes a list of lists. Each 202 | sublist contains a regex to match filenames to corrects, and the replacement 203 | text. 204 | 205 | ```vim 206 | " #### in a _vimrc_local.vim file 207 | " Define how filenames are converted 208 | " - ^%d> is stripped 209 | " - */build/{build-type}/copy_xsd (automatically filled and generated during 210 | " the compilation by copying files from 211 | " {project-root}/data/xsd/GENERATION_SCHEMAS/) is converted to the original file. 212 | let b:BTW_substitute_names = [ 213 | \ [ '\d\+>\s*', ''], 214 | \ [ 215 | \ lh#function#bind(string('^'.b:BTW_compilation_dir.'/copy_xsds')), 216 | \ g:PRJ_config.paths.trunk.'/../data/xsd/GENERATION_SCHEMAS' 217 | \ ] 218 | \ ] 219 | " Tell to automatically import the buffer local variable to the quickfix 220 | " window 221 | QFImport b:BTW_substitute_names 222 | " Add the filter to the list of filter applied 223 | BTW addlocal substitute_filenames 224 | ``` 225 | 226 | Note: It's executed with a _post_ _hook_ of priority 2. 227 | 228 | ```vim 229 | call lh#btw#filters#register_hook(2, 'BTW_Substitute_Filenames', 'post') 230 | ``` 231 | ### Create a new filter 232 | 233 | To be documented... 234 | 235 | ## 3- Some examples 236 | 237 | ### C++ project, compiled with g++ through ant and cpp\_task 238 | ```vim 239 | BTW addlocal ant 240 | BTW addlocal STLfilt 241 | ``` 242 | 243 | ### ... 244 | -------------------------------------------------------------------------------- /doc/make_run.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Introduction 4 | 5 | BTW offers a simplified way to build and execute programs from vim. In essence, this plugin encapsulates `:make` and `:!./%<`. 6 | 7 | # Options 8 | Several options can permit to tune the behaviour of BTW. 9 | 10 | ## Keybindings 11 | | Command | Default keybinding | Variable to set in `.vimrc` | 12 | |:---------------------------------|:-----------------------|:------------------------------| 13 | | `:Make` | `` | `g:BTW.key.make` | 14 | | `:StopBGCompilation`1 | N/A (yet) | N/A (yet) | 15 | | `:Execute` | `` | `g:BTW.key.execute` | 16 | | `:Config` | `` | `g:BTW.key.config` | 17 | | `:ReConfig` | `` | `g:BTW.key.re_config` | 18 | 19 | #### Notes: 20 | * 1 Requires Vim 7.4-1980 compiled with +job feature. 21 | 22 | ## Behaviour 23 | ### Compilation 24 | 25 | | Role | Option name | Values (default) | Best set in/changed with | 26 | |:------------------------------------------------------------------------------------------------|:------------------------------------------|:------------------------|:-----------------------------| 27 | | Shall the compilation happen in background? 1 | `g:BTW.make_in_background` | 1/(0) | `.vimrc`/`:ToggleMakeBG` | 28 | | Shall the background compilation autoscroll the qf-window to display last message?2 | `g:BTW.autoscroll_background_compilation` | 1/(0) | `.vimrc`/`:ToggleAutoScrollBG` | 29 | | Shall the compilation use all available cores? | `g:BTW.make_multijobs` | _n_/(0) | `.vimrc`/`:ToggleMakeMJ` | 30 | | Directory where the compilation shall be done | `(bpg):BTW.compilation_dir` | path ('') | `local_vimrc` / [BTW CMake submodule](doc/cmake.md) | 31 | | Shall we update BTW tools chain every time we compile? | `(bpg):BTW.use_prio` | `''`/(`'update'`) | `local_vimrc` | 32 | | Command to use to compile in background (useful to follow the compilation in an external xterm) | `(bpg):BTW.make_in_background_in` | (`''`)/`'xterm -e'`/... | `local_vimrc` | 33 | | Name of the project | `(bpg):BTW.project` | (`'%<'`) | `local_vimrc` | 34 | | Build Target | `(bpg):BTW.target` | (project name, or `'all'` if empty) | `local_vimrc` | 35 | 36 | #### Notes: 37 | * 1 Requires perl or Vim 7.4-1980 compiled with +job feature. The 38 | old perl way works on *nix systems. The new +job way has been tested 39 | successfully on: 40 | 41 | | | Linux | Cygwin + gvim643 | Cygwin + cyg-vim | Mingw + gvim645 | VC10 + gvim 645 | 42 | |:------------------|:-------------------|:----------------------------|:-----------------|:---------------------------|:--------------------------------| 43 | |Mono-file project | :heavy_check_mark: | :heavy_check_mark: | :question: | :question: | :heavy_check_mark: 4 | 44 | |Out-of-source build| :heavy_check_mark: | :question: | :question: | :question: | :question: | 45 | * 2 Requires Vim 7.4-1980 compiled with +job feature. 46 | * 3 My `&shell` options are configured through my very old [system-tool plugin](https://github.com/LucHermitte/vim-system-tools). More investigations are required for other configurations. 47 | * 4 Tested with [gvim64](https://bintray.com/veegee/generic/vim_x64) launched from _VS2015 CLI for native x64_ console, and `:BTW set cl`, and `:Make %`. 48 | * 5 Without any Cygwin binaries in the $PATH. 49 | 50 | 51 | ### Configuration 52 | 53 | The option `(bpg):BTW.project_config` says what to do on `:Config`. 54 | When `(bpg):BTW.project_config.type` equals 55 | * `modeline`, add a _let-modeline_ 56 | * `makefile`, open the make file named `(bpg):BTW.project_config.file` in `(bpg):BTW.project_config.wd`. 57 | * `ccmake`, starts ccmake in `(bpg):BTW.project_config.wd`, with `(bpg):BTW.project_config.args` as parameters. 58 | 59 | 60 | ### Report errors 61 | | Role | Option name | Values (default) | Best set in | 62 | |:------------------------------------------------|:---------------------|:-----------------------------------------|:----------------| 63 | | Tunes where the quickfix window shall be opened | `g:BTW.qf_position` | (`''`)/`'botright'`/... | `.vimrc` | 64 | | Tunes the size of the quickfix window | `g:BTW.qf_size` | number of lines (max(15, &winfixheight)) | `.vimrc` | 65 | | Tells whether we shall jump to the first error | `g:BTW.goto_error` | (1)/0 | `.vimrc` | 66 | 67 | ### Execution 68 | 69 | | Role | Option name | Values (default) | Best set in | 70 | |:-----------------------------------------------------------|:---------------------------|:-----------------------------------------|:----------------| 71 | | Parameters to pass to the program executed with `:Execute` | `(bpg):BTW.run_parameters` | string (empty) | `local_vimrc` | 72 | | Program to execute | `(bpg):BTW.executable` | (project name, or does nothing if empty) | `local_vimrc` | 73 | 74 | 75 | # Build 76 | 77 | Projects are compiled on `` or `:Make`, in the directory specified by `(bpg):BTW.compilation_dir`. The compilation may be done in background (on nix boxes only), it may use all cores available. 78 | 79 | The compilation tries to detect automatically the target though `(bpg):BTW.project...` options, though it may be forced as a parameter to `:Make`. 80 | 81 | When an error is found, the quickfix window will get automatically opened. However, when the quickfix window is not opened (link errors are not detected by default as compilation errors), the command `:Copen` is provided. `:Copen` differs from `:copen` in the sense it adjust its size the number of lines to display. 82 | 83 | ## Mono-file projects 84 | 85 | ### From the shell 86 | First, a quick reminder. When, our system has gnu make installed (and not the badly configured gnumake from Mingw), we can compile the standalone file `foo.c` with `make foo` from our shell. We don't need to (and must not) write any Makefile! The executable `foo` will be generated in the current directory. 87 | 88 | Any need to inject an option ? `$CFLAGS`, `$CXXFLAGS`, `$CPPFLAGS`, `$LDFLAGS` (to name the main ones) are already there waiting to be set. For instance, we can compile the C++14 standalone file bar.cpp with `CXXFLAGS='-std=c++1y' make bar`. And execute the result with `./bar`. 89 | 90 | ### From vim 91 | How is it related to vim, you'll ask? Well, this means we can compile foo.c from vim with `:make foo`, or even `:make %<` when the current buffer is foo.c. To compile bar.cpp, we'll first have to set `$CXXFLAGS` with `:let $CXXFLAGS='-std=c++1y'`, and then we can simply compile with `:make %<`. _Et voilà!_ 92 | 93 | ### From vim with BTW 94 | The way BTW handles its default settings, we just need to hit `` to compile the current buffer. And if we need to set options, just set `$CXXFLAGS` once, and hit `` or `:Make` (note the capital 'M') 95 | 96 | NB: my plugin let-modeline may help here. 97 | 98 | #### Limitations 99 | Of course, this will only work as long as there is no Makefile in the same directory of the file we wish to compile. If there is a Makefile, I strongly suggest you to better organize the directory where your pet projects/tests are. I usually have projects made of single files in a same directory, but when a project (even a small one) is made of several files, I store its files apart. 100 | 101 | Note, that this will work only if there are implicit rules known by gnumake to handle the file you wish to compile. For other organizations, filetypes without implicit rules know by gnumake, or scripts to be interpreted, you can play with [filters](doc/filter.md), or use other plugins like [SingleCompile](https://github.com/xuhdev/SingleCompile). 102 | 103 | ## Multi-files projects 104 | 105 | This time BTW won't be able to use the name of the current buffer to determine the target to use with `make`. Define a Makefile, and set the option `(bpg):BTW.target` to whatever you wish ('all', 'myprog', or 'whatever'). 106 | 107 | The best way to define this option is from a project oriented plugin like [local\_vimrc](http://github.com/LucHermitte/local_vimrc) 108 | 109 | ## CMake based projects 110 | 111 | [I have a lot of things to say on this topic](cmake.md). 112 | 113 | 114 | # Execute 115 | 116 | Just hit `` to execute the current program. You may have to change the key bound if you are using vim in console instead of gvim or macvim. 117 | 118 | In the case of the multi-files project, or a project having tests managed through CTest, you'll have to set `(bpg):BTW.executable`. 119 | 120 | If `(bpg):BTW.executable` contains `{ 'type': 'make' }`, the execution is redirected to the quickfix window. Same thing with `{ 'type': 'ctest' }`, but this time the result is filtered on-the-fly to correct the noise introduced by CTest (regarding `&errorformat`) 121 | 122 | # Demo 123 | You'll see in this little demo, an example of use of BTW on two CMake based 124 | projects simultaneously opened in Vim 8 (7.4-2342 actually). 125 | 126 | The compilation of both projects is launched in background. The job queue (from 127 | [lh-vim-lib](http://github.com/LucHermitte/lh-vim-lib)) is then opened to 128 | follow what is done in background and what will be done shortly after. 129 | 130 | The explicit update (in background) of tags for all files in 131 | [ITK project](http://www.itk.org) is also requested (thanks to 132 | [lh-tags](http://github.com/LucHermitte/lh-tags) v2.0.3). 133 | 134 | And we see ITK compilation fails because `cmake` has never been run for the 135 | _reldeb_ compilation mode (_ReleaseWithDebugInfo_). A problem is detected and the 136 | next jobs are not executed automatically. The job queue is paused (I also could 137 | have ignored the error, etc.). 138 | 139 | Then I change the current compilation mode to _sanitize_ (some kind of 140 | _ReleaseWithDebugInfo_ mode but compiled with clang++ with two sanitizations 141 | activated). This time `cmake` has been executed in the associated directory. I 142 | register the compilation on ITK in this mode. 143 | 144 | The queue is still paused. I _unpause_ the job queue through the `:Jobs` console. 145 | Eventually I see ITK is still not compiling, but this is another issue. 146 | 147 | ![background compilation demo](screencast-BTW.gif "Demo of background compilation of 2 dictinct projects with different compilation modes") 148 | -------------------------------------------------------------------------------- /autoload/lh/btw.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: autoload/lh/btw.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " Version: 0.7.0 6 | let s:k_version = 070 7 | " Created: 14th Mar 2014 8 | " Last Update: 26th Aug 2016 9 | "------------------------------------------------------------------------ 10 | " Description: 11 | " API & Internals for BuildToolsWrapper 12 | " 13 | " TODO: 14 | " * :cclose + :Copen + :cnewer clears the variables imported in the previous 15 | " run 16 | " }}}1 17 | "============================================================================= 18 | 19 | let s:cpo_save=&cpo 20 | set cpo&vim 21 | let s:has_qf_properties = has("patch-7.4.2200") 22 | "------------------------------------------------------------------------ 23 | " ## Misc Functions {{{1 24 | " # Version {{{2 25 | function! lh#btw#version() 26 | return s:k_version 27 | endfunction 28 | 29 | " # Debug {{{2 30 | let s:verbose = get(s:, 'verbose', 0) 31 | function! lh#btw#verbose(...) 32 | if a:0 > 0 | let s:verbose = a:1 | endif 33 | return s:verbose 34 | endfunction 35 | 36 | function! s:Log(expr, ...) 37 | call call('lh#log#this',[a:expr]+a:000) 38 | endfunction 39 | 40 | function! s:Verbose(expr, ...) 41 | if s:verbose 42 | call call('s:Log',[a:expr]+a:000) 43 | endif 44 | endfunction 45 | 46 | function! lh#btw#debug(expr) abort 47 | return eval(a:expr) 48 | endfunction 49 | 50 | "------------------------------------------------------------------------ 51 | " ## Exported functions {{{1 52 | 53 | " Function: lh#btw#compilation_dir([bufid]) {{{3 54 | function! lh#btw#compilation_dir(...) 55 | return call('lh#btw#option#_compilation_dir', a:000) 56 | endfunction 57 | 58 | " Function: lh#btw#build_mode([default]) {{{3 59 | function! lh#btw#build_mode(...) abort 60 | let default = a:0 == 0 ? '' : a:1 61 | if lh#btw#option#_has_project_config() 62 | let project_config = lh#btw#option#_project_config() 63 | let config = get(project_config, '_', {}) 64 | let mode = get(get(config, 'compilation', {}), 'mode', default) 65 | return mode 66 | else 67 | " BTW_project_build_mode is deprecated! 68 | return lh#option#get('BTW_project_build_mode', default) 69 | endif 70 | endfunction 71 | 72 | " Function: lh#btw#project_name([bufid]) {{{3 73 | function! lh#btw#project_name(...) abort 74 | let bufid = a:0 > 0 ? a:1 : bufnr('%') 75 | let project_config = lh#btw#option#_project_config(bufid) " use from_buf version to detect undefined 76 | " 1- Information set in b:project_config._.name ? 77 | if lh#option#is_set(project_config) 78 | let config = get(project_config, '_', {}) 79 | let name = get(config, 'name', '') 80 | return name 81 | else 82 | " 2- Information set in b:BTW_project_name ? 83 | let name = lh#btw#option#_project_name(bufid) 84 | if lh#option#is_set(name) | return name | endif 85 | " 3- Is this a qf window ? 86 | if getbufvar(bufid, '&ft') == 'qf' | return lh#btw#project_name(g:lh#btw#_last_buffer) | endif 87 | " 4- Information available in repo name ? 88 | " TODO: we should decode subdirectories 89 | let url = lh#vcs#get_url(fnamemodify(bufname(bufid), ':p:h')) 90 | if lh#option#is_set(url) && !empty(url) 91 | return matchstr(url, '.*/\zs.*') 92 | endif 93 | " N- Return default! 94 | return fnamemodify(bufname(bufid), ':r') 95 | endif 96 | endfunction 97 | 98 | "------------------------------------------------------------------------ 99 | " ## Internal functions {{{1 100 | " # Misc Functions: {{{2 101 | " s:getSNR([func_name]) {{{3 102 | function! s:getSNR(...) 103 | if !exists("s:SNR") 104 | let s:SNR=matchstr(expand(''), '\d\+_\zegetSNR$') 105 | endif 106 | return s:SNR . (a:0>0 ? (a:1) : '') 107 | endfunction 108 | 109 | " Function: lh#btw#_evaluate(expr) {{{3 110 | function! lh#btw#_evaluate(expr) 111 | if type(a:expr) == type({}) 112 | if lh#ref#is_bound(a:expr) 113 | return a:expr.resolve() 114 | else 115 | let res = lh#function#execute(a:expr) 116 | endif 117 | elseif type(a:expr) == type('') 118 | let res = a:expr 119 | else 120 | throw "Unexpected variable type" 121 | endif 122 | return res 123 | endfunction 124 | 125 | " # Folding functions {{{2 126 | " Function: lh#btw#qf_fold_text() {{{3 127 | " Defines foldtext for each fold built from s:qf_folds 128 | " @param[in] s:qf_folds 129 | function! lh#btw#_qf_fold_text() abort 130 | let test_nr = s:qf_folds[-1][v:foldstart] 131 | if !has_key(s:qf_folds[test_nr], 'complement') | return | endif 132 | let t = foldtext().': ' 133 | let l = (4 - len(test_nr)) 134 | let t.= repeat(' ', l). (s:qf_folds[test_nr].name) .' ' 135 | let t.= s:qf_folds[test_nr].complement 136 | return t 137 | endfunction 138 | 139 | 140 | " # CTest hooks {{{2 141 | " Function: lh#btw#_register_fix_ctest() {{{3 142 | " When working with CTest, we need to: 143 | " - translate the name of the files in error from "{test-number}: file:line: 144 | " message" 145 | " and we can fold the messages from each test. 146 | function! lh#btw#_register_fix_ctest() abort 147 | let hooks = { 148 | \ 'pre' : {1: s:getSNR('QuickFixCleanFolds')}, 149 | \ 'post': {2: s:getSNR('FixCTestOutput')}, 150 | \ 'open': {9: s:getSNR('QuickFixDefFolds')} 151 | \ } 152 | call lh#btw#filters#register_hooks(hooks) 153 | endfunction 154 | 155 | " Function: s:QuickFixCleanFolds() {{{3 156 | function! s:QuickFixCleanFolds() 157 | " echomsg "Clean QF folds" 158 | let s:qf_folds = {} 159 | endfunction 160 | 161 | " Function: s:FixCTestOutput() {{{3 162 | " Parse CTest output to fix filenames, and extract forlding information 163 | function! s:FixCTestOutput() abort 164 | try 165 | " echomsg "parse CTest output" 166 | let qf_changed = 0 167 | let qflist = getqflist() 168 | let s:qf_folds = {-1: {}} 169 | let line_nr = 1 170 | let test_nr = -1 171 | let test_name = '' 172 | let test_name_lengths = [] 173 | for qf in qflist 174 | let qft = qf.text 175 | " echo '===<'.qft.'>===' 176 | if qft =~ '^test \d\+\s*$' 177 | " Test start line 178 | let test_nr = matchstr(qft, '^test \zs\d\+\ze\s*$') 179 | " assert(!has_key(qf_folds, test_nr)) 180 | let s:qf_folds[test_nr] = {'begin': line_nr} 181 | let s:qf_folds[-1][line_nr] = test_nr 182 | elseif qft =~ '^\s*\d\+/\d\+ Test\s\+#\d\+:' 183 | " Test end line 184 | let test_nr = matchstr(qft, '^\s*\d\+/\d\+ Test\s\+#\zs\d\+\ze:') 185 | let test_success = matchstr(qft, '^\s*\d\+/\d\+ Test\s\+#\d\+:\s\+'.test_name.' \.\+\s*\zs\S\+') 186 | let g:qft = qft 187 | let s:qf_folds[test_nr].end = line_nr 188 | let s:qf_folds[test_nr].complement = test_success 189 | let test_nr = -1 190 | let test_name = '' 191 | elseif qft =~ '^\s*Start\s\+\d\+: ' 192 | let test_nr = matchstr(qft, '^\s*Start\s\+\zs\d\+\ze:') 193 | if !has_key(s:qf_folds, test_nr) 194 | let s:qf_folds[test_nr] = {'begin': line_nr} 195 | let s:qf_folds[-1][line_nr] = test_nr 196 | endif 197 | let test_name = matchstr(qft, '^\s*Start\s\+'.test_nr.': \zs\S\+\ze\s*$') 198 | let s:qf_folds[test_nr].name = test_name 199 | let test_name_lengths += [ len(test_name) ] 200 | elseif qf.bufnr != 0 201 | let b_name = bufname(qf.bufnr) 202 | let update_bufnr = 0 203 | if b_name =~ '^'.test_nr.': ' " CTest messing with errors 204 | let b_name = b_name[len(test_nr.': '):] 205 | let update_bufnr = 1 206 | " echomsg test_nr .' -> '. b_name 207 | " else 208 | " echomsg test_nr .' != '. b_name 209 | endif 210 | if b_name =~ '^\S\+\s\+\S\+$' && qf.text =~ '\c.*Assertion.*' 211 | let b_name = matchstr(b_name, '^\S\+\s\+\zs.*') 212 | let update_bufnr = 1 213 | endif 214 | if update_bufnr 215 | let msg = qf.bufnr . ' -> ' 216 | let qf.bufnr = lh#buffer#get_nr(b_name) 217 | let msg.= qf.bufnr . ' ('.b_name.')' 218 | " echomsg msg 219 | let qf_changed = 1 220 | endif 221 | endif 222 | let line_nr += 1 223 | endfor 224 | 225 | " Find the max length of all test names and align them. 226 | let l = max(test_name_lengths) 227 | for [t, pos] in items(s:qf_folds) 228 | if t != -1 229 | let pos.name .= ' '.repeat('.', 3 + l-len(pos.name)) 230 | endif 231 | endfor 232 | 233 | if qf_changed 234 | call setqflist(qflist, 'r') 235 | endif 236 | catch /.*/ 237 | call lh#common#error_msg("Error: ".v:exception. " throw at: ".v:throwpoint) 238 | endtry 239 | endfunction 240 | 241 | " Function: s:QuickFixDefFolds() {{{3 242 | " Defines folds for each test 243 | " @param[in] s:qf_folds 244 | function! s:QuickFixDefFolds() abort 245 | if !exists('s:qf_folds') | return | endif 246 | for [t, pos] in items(s:qf_folds) 247 | if t != -1 248 | " echomsg t.' -> '.string(pos) 249 | if has_key(pos, 'begin') && has_key(pos, 'end') 250 | exe (pos.begin).','.(pos.end).'fold' 251 | else 252 | echomsg "Missing " .(has_key(pos, 'begin') ? "" : "-start-").(has_key(pos, 'end') ? "" : "-end-")." fold for test #".t 253 | endif 254 | endif 255 | endfor 256 | setlocal foldtext=lh#btw#_qf_fold_text() 257 | endfunction 258 | 259 | " # Quickfix auto import: {{{2 260 | " Some variables need to be imported automatically into quickfix buffer 261 | " Variables: {{{3 262 | if !exists('s:qf_options_to_import') 263 | let s:qf_options_to_import = {} 264 | let s:qf_saved_options = [] 265 | endif 266 | augroup QFExportVar 267 | au! 268 | au BufWipeout * call s:QuickFixRemoveExports(expand('')) 269 | augroup END 270 | 271 | " Function: s:QuickFixImport() {{{3 272 | function! s:QuickFixImport() abort 273 | let bhere = bufnr('%') 274 | 275 | let qf = getqflist() 276 | if empty(qf) | return | endif 277 | let qf0 = qf[0] 278 | if qf0.text =~ '^BTW: ' 279 | " The qf list has already been proccessed, we need to import what it 280 | " contains 281 | let idx = - qf0.nr 282 | let data = s:qf_saved_options[idx] 283 | let bid = data.bid 284 | let b:last_buffer = bid 285 | for [var, value] in items(data) 286 | if var != 'bid' && lh#option#is_set(value) 287 | call setbufvar(bhere, var, value) 288 | endif 289 | silent! unlet value 290 | endfor 291 | else 292 | " If everyting works fine, this branch of coe should not be executed! 293 | " It could, when not using BTW function to compile. 294 | 295 | " First call to :copen, things haven't been serialized yet 296 | if !exists('g:lh#btw#_last_buffer') | return | endif 297 | let bid = g:lh#btw#_last_buffer 298 | 299 | if !has_key(s:qf_options_to_import, bid) 300 | echomsg "Import: No variable required for buffer ".bid." (".bufname(bid).")" 301 | return 302 | endif 303 | let variables = keys(s:qf_options_to_import[bid]) 304 | call s:Verbose("Importing: ".string(variables)) 305 | for var in variables 306 | let value = deepcopy(lh#option#getbufvar(bid, var)) " don't want to be updated if the compilation mode changes 307 | if lh#option#is_set(value) 308 | call setbufvar(bhere, var, value) 309 | endif 310 | silent! unlet value 311 | endfor 312 | endif 313 | 314 | let b:last_buffer = g:lh#btw#_last_buffer 315 | 316 | " This has no effect :( Is it because of the aucommand on QF open ? 317 | let w:quickfix_title = lh#btw#build_mode(). ' compilation of ' . lh#btw#project_name() 318 | endfunction 319 | 320 | " Function: s:QuickFixRemoveExports(fname) {{{3 321 | function! s:QuickFixRemoveExports(fname) 322 | if empty(a:fname) | return | endif 323 | let bid = bufnr(a:fname) 324 | call s:Verbose("Removing exported variables for buffer ".bid) 325 | silent! unlet s:qf_options_to_import[bid] 326 | endfunction 327 | 328 | " Augroup: QFImport {{{3 329 | call lh#btw#filters#register_hook(1, s:getSNR('QuickFixImport'), 'open') 330 | 331 | " Function: lh#btw#qf_add_var_to_import(varname) {{{3 332 | function! lh#btw#qf_add_var_to_import(varname) abort 333 | let bid = bufnr('%') 334 | if !has_key(s:qf_options_to_import, bid) 335 | let s:qf_options_to_import[bid] = {} 336 | endif 337 | 338 | " Strip b: / &l: 339 | let varname = substitute(a:varname, '^b:\|^&\zsl:', '', '') 340 | let s:qf_options_to_import[bid][varname] = 1 341 | endfunction 342 | 343 | " Function: lh#btw#qf_remove_var_to_import(varname) {{{3 344 | function! lh#btw#qf_remove_var_to_import(varname) 345 | let bid = bufnr('%') 346 | silent! unlet s:qf_options_to_import[bid][a:varname] 347 | if empty(s:qf_options_to_import[bid]) 348 | call s:QuickFixRemoveExports(bid) 349 | endif 350 | endfunction 351 | 352 | " Function: lh#btw#qf_clear_import() {{{3 353 | function! lh#btw#qf_clear_import() 354 | let s:qf_options_to_import = {} 355 | endfunction 356 | 357 | " Function: lh#btw#_save_last_buffer_data() {{{3 358 | function! lh#btw#_save_last_buffer_data() abort 359 | let bid = bufnr('%') 360 | let g:lh#btw#_last_buffer = bid 361 | 362 | if !has_key(s:qf_options_to_import, bid) 363 | echomsg "Import: No variable required for buffer ".bid." (".bufname(bid).")" 364 | return 365 | endif 366 | let variables = keys(s:qf_options_to_import[bid]) 367 | call s:Verbose("Saving: ".string(variables)) 368 | let data = { 'bid': bid } 369 | for var in variables 370 | let value = deepcopy(lh#option#getbufvar(bid, var)) " don't want to be updated if the compilation mode changes 371 | if lh#option#is_set(value) 372 | let data[var] = value 373 | endif 374 | silent! unlet value 375 | endfor 376 | 377 | " check whether the same data already exist => reuse the index 378 | let idx = index(s:qf_saved_options, data) 379 | if idx == -1 380 | " Otherwise, add the data 381 | let idx = len(s:qf_saved_options) 382 | let s:qf_saved_options += [ data ] 383 | endif 384 | 385 | " Put local data in the quickfix for later uses 386 | let qf = getqflist() 387 | let qf0 = { 'bufnr': 0, 'lnum': 0, 'col': 0, 'vcol': 0, 'pattern': '', 'type': '' } 388 | let qf0.nr = - idx 389 | let qf0.text = 'BTW: '. lh#btw#build_mode(). ' compilation of ' . lh#btw#project_name() 390 | call insert(qf, qf0) 391 | if s:has_qf_properties 392 | let title = getqflist({'title':1}) 393 | endif 394 | " This line messes with the current qfwindow title 395 | " -> force it back with patch 7.4-2200 396 | call setqflist(qf, 'r') 397 | if s:has_qf_properties 398 | call setqflist([], 'r', title) 399 | endif 400 | endfunction 401 | 402 | "}}}1 403 | "------------------------------------------------------------------------ 404 | let &cpo=s:cpo_save 405 | "============================================================================= 406 | " vim600: set fdm=marker: 407 | -------------------------------------------------------------------------------- /autoload/lh/btw/chain.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: autoload/lh/btw/chain.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " Version: 0.7.0. 6 | let s:k_version = '070' 7 | " Created: 23rd Mar 2015 8 | " Last Update: 14th Oct 2016 9 | "------------------------------------------------------------------------ 10 | " Description: 11 | " Internal functions dedicated to filter chain management. 12 | " }}}1 13 | "============================================================================= 14 | 15 | let s:cpo_save=&cpo 16 | set cpo&vim 17 | "------------------------------------------------------------------------ 18 | " ## Misc Functions {{{1 19 | " # Version {{{2 20 | function! lh#btw#chain#version() 21 | return s:k_version 22 | endfunction 23 | 24 | " # Debug {{{2 25 | let s:verbose = get(s:, 'verbose', 0) 26 | function! lh#btw#chain#verbose(...) 27 | if a:0 > 0 | let s:verbose = a:1 | endif 28 | return s:verbose 29 | endfunction 30 | 31 | function! s:Log(expr, ...) 32 | call call('lh#log#this',[a:expr]+a:000) 33 | endfunction 34 | 35 | function! s:Verbose(expr, ...) 36 | if s:verbose 37 | call call('s:Log',[a:expr]+a:000) 38 | endif 39 | endfunction 40 | 41 | function! lh#btw#chain#debug(expr) abort 42 | return eval(a:expr) 43 | endfunction 44 | 45 | 46 | "------------------------------------------------------------------------ 47 | " ## Exported functions {{{1 48 | 49 | "------------------------------------------------------------------------ 50 | " ## Internal functions {{{1 51 | 52 | " # Filter list management {{{2 53 | " lh#btw#chain#_filters_list(): Helper {{{3 54 | function! lh#btw#chain#_filters_list() abort 55 | return lh#option#get('BTW_filters_list', []) 56 | 57 | " problem: lh#option#get this will ignore empty variables => custom function 58 | " (I suspect I wrote the previous comment before I wrote 59 | " lh#option#get_non_empty()) 60 | if exists('b:BTW_filters_list') | return b:BTW_filters_list 61 | elseif exists('g:BTW_filters_list') | return g:BTW_filters_list 62 | else | return [] 63 | endif 64 | endfunction 65 | 66 | " AddFilter(scope,filter): Exposed/public feature {{{3 67 | function! s:AddFilter(scope, filter) abort 68 | let var = a:scope . ':BTW_filters_list' 69 | if !exists(var) || empty({var}) 70 | let {var} = [a:filter] 71 | elseif ! s:HasFilter(a:filter, var) 72 | let {var} += [a:filter] 73 | endif 74 | endfunction 75 | 76 | " RemoveFilter(scope,filter): Exposed/public feature {{{3 77 | function! s:RemoveFilter(scope, filter) abort 78 | if 'g' == a:scope 79 | " Don't try to be smarter than that: we won't remove it from local filter list. 80 | if ! s:DoRemoveFilter(a:scope, a:filter) 81 | call lh#common#error_msg('BTW: Error no global filter-plugin named "' 82 | \ . a:filter . '" to remove') 83 | endif 84 | elseif ('b' == a:scope) 85 | let bnum = bufnr('%') 86 | let buffers = lh#buffer#list() 87 | for buffer in buffers 88 | let var = getbufvar(buffer, 'BTW_filters_list', []) 89 | let idx = match(var, a:filter) 90 | if buffer == bnum 91 | \ || (idx!=-1 && 1==CONFIRM("Do you want to remove ".string(a:filter)." from ".bufname(buffer)." filter list?", "&Yes\n&No", 1)) 92 | if -1 == idx 93 | call lh#common#error_msg('BTW: Error no global filter-plugin named "' 94 | \ . a:filter . '" to remove') 95 | else 96 | call remove(var, idx) 97 | " No need to call setbufvar as getbufvar returns a reference 98 | endif 99 | endif 100 | endfor 101 | endif 102 | return 103 | 104 | " Old code that was trying to be too smart 105 | let var = a:scope . ':BTW_filters_list' 106 | 107 | if 'g' == a:scope 108 | " If global scope: remove it for every buffer 109 | let bnum = bufnr('%') 110 | exe 'bufdo call s:DoRemoveFilter("b", "'.a:filter.'")' 111 | " exe 'bufdo BTW removelocal '.a:filter 112 | exe ':buffer '.bnum 113 | elseif ('b' == a:scope) && !exists(var) 114 | \ && s:HasFilter(a:filter, var) 115 | " \ && (match(lh#btw#chain#_filters_list(),a:filter) >= 0) 116 | " Defines a local set of filter-plugins from previous the global list 117 | let b:BTW_filters_list = g:BTW_filters_list 118 | " finally: call DoRemove 119 | else 120 | call lh#common#error_msg('BTW: Error no such filter-plugin to remove "' 121 | \ . a:filter . '"') 122 | " s:DoRemove(): kind of "big" no-op 123 | endif 124 | 125 | " Do remove it for this scope 126 | call s:DoRemoveFilter(a:scope, a:filter) 127 | endfunction 128 | 129 | function! s:DoRemoveFilter(scope,filter) abort 130 | let var = a:scope . ':BTW_filters_list' 131 | if exists(var) 132 | let idx = match({var}, a:filter) 133 | if -1 != idx 134 | call remove({var}, idx) 135 | return 1 136 | endif 137 | endif 138 | return 0 139 | endfunction 140 | 141 | " HasFilterGuessScope(filter): {{{3 142 | function! s:HasFilterGuessScope(filter) abort 143 | if exists('b:BTW_filters_list') 144 | return s:HasFilter(a:filter, 'b:BTW_filters_list') 145 | elseif exists('g:BTW_filters_list') 146 | return s:HasFilter(a:filter, 'g:BTW_filters_list') 147 | else 148 | return 0 149 | endif 150 | endfunction 151 | 152 | " HasFilter(filter, var): {{{3 153 | " @pre exists({a:var}) 154 | function! s:HasFilter(filter, var) abort 155 | return -1 != match({a:var}, a:filter) 156 | endfunction 157 | 158 | " lh#btw#chain#_find_filter(filter): Helper {{{3 159 | function! lh#btw#chain#_find_filter(filter) abort 160 | let filter = a:filter . '.vim' 161 | let result =globpath(&rtp, "compiler/BTW-".filter) . "\n" . 162 | \ globpath(&rtp, "compiler/BTW_".filter). "\n" . 163 | \ globpath(&rtp, "compiler/BTW/".filter) 164 | let result = substitute(result, '\n\n', '\n', 'g') 165 | let result = substitute(result, '^\n', '', 'g') 166 | return result 167 | endfunction 168 | 169 | 170 | " # Build Chain: {{{2 171 | let s:sfile = expand(':p') 172 | 173 | " lh#btw#chain#_BTW(command [,filter]): Main function {{{3 174 | if !exists('g:BTW_BTW_in_use') 175 | function! lh#btw#chain#_BTW(command, ...) abort 176 | " todo: check a:0 > 1 177 | if 'set' == a:command | let g:BTW_build_tool = a:1 178 | if exists('b:BTW_build_tool') 179 | let b:BTW_build_tool = a:1 180 | endif 181 | elseif 'setlocal' == a:command | let b:BTW_build_tool = a:1 182 | elseif 'setoption' == a:command | call s:SetOption('g', a:000) 183 | elseif 'setoptionlocal' == a:command | call s:SetOption('b', a:000) 184 | elseif 'add' == a:command | call s:AddFilter('g', a:1) 185 | elseif 'addlocal' == a:command | call s:AddFilter('b', a:1) 186 | " if exists('b:BTW_filters_list') " ????? 187 | " call s:AddFilter('b', a:1) 188 | " endif 189 | elseif 'remove' == a:command | call s:RemoveFilter('g', a:1) 190 | elseif 'removelocal' == a:command | call s:RemoveFilter('b', a:1) 191 | elseif 'rebuild' == a:command " wait for lh#btw#chain#_reconstruct() 192 | elseif 'echo' == a:command | exe "echo s:".a:1 193 | elseif 'debug' == a:command | exe "debug echo s:".a:1 194 | " echo s:{a:f1} ## don't support «echo s:f('foo')» 195 | elseif 'reloadPlugin' == a:command 196 | let cleanup = lh#on#exit() 197 | \.restore('g:force_reload_BuildToolsWrapper') 198 | \.restore('g:BTW_BTW_in_use') 199 | try 200 | let g:BTW_BTW_in_use = 1 201 | runtime! autoload/lh/btw/*.vim autoload/lh/btw.vim 202 | 203 | let g:force_reload_BuildToolsWrapper = 1 204 | runtime plugin/BuildToolsWrapper.vim 205 | finally 206 | call cleanup.finalize() 207 | endtry 208 | return 209 | elseif a:command =~ '\%(help\|?\)' 210 | call s:Usage() 211 | return 212 | elseif a:command =~ '\' 213 | call call(function('lh#btw#project#new'), a:000) 214 | endif 215 | call lh#btw#chain#_reconstruct() 216 | endfunction 217 | endif 218 | 219 | " lh#btw#chain#_reconstruct(): {{{3 220 | function! lh#btw#chain#_reconstruct() abort 221 | let efm = {'value': '', 'post':[] } 222 | let prog = lh#option#get('BTW_build_tool', 'make') 223 | call s:LoadFilter(prog) 224 | let Makeprg = lh#option#get('BTW_filter_program_'.prog, prog, 'bg') 225 | if type(Makeprg) == type(function('has')) 226 | let makeprg = Makeprg('$*') 227 | else 228 | let makeprg = Makeprg . ' $*' 229 | endif 230 | call s:AdjustEFM(prog, efm) 231 | 232 | let dir = lh#btw#option#_compilation_dir() 233 | let need_pipefail = 0 234 | if !empty(dir) 235 | let makeprg = '(cd '.shellescape(dir).' && ' . makeprg . ')' 236 | endif 237 | 238 | let filters_list = lh#btw#chain#_filters_list() 239 | for filter in filters_list 240 | call s:LoadFilter(filter) 241 | " let efm = efm . ',' . lh#option#get('BTW_adjust_efm_'.filter, '', 'g') 242 | call s:AdjustEFM(filter, efm) 243 | let prg = lh#option#get(s:ToVarName('BTW_filter_program_'.filter), '', 'bg') 244 | 245 | if !empty(prg) 246 | " Faire dans BTW-{filter}.vim 247 | " let prg = substitute(expand(':p:h'), ' ', '\\ ', 'g') 248 | let makeprg .= ' 2>&1 \| '.prg 249 | let need_pipefail = 1 250 | endif 251 | endfor 252 | if &shell =~ 'bash' && need_pipefail 253 | " TODO support other UNIX flavors 254 | " see http://stackoverflow.com/questions/1221833/bash-pipe-output-and-capture-exit-status 255 | let makeprg = 'set -o pipefail ; ' . makeprg 256 | endif 257 | 258 | let islocal = exists('b:BTW_build_tool') || exists('b:BTW_filters_list') 259 | let local = islocal ? 'l:' : '' 260 | let set = islocal ? 'setlocal ' : 'set ' 261 | 262 | " Set makeprog 263 | exe 'let &'.local.'makeprg = makeprg' 264 | " set does not seems to work 265 | " exe set . 'makeprg="'. makeprg . '"' 266 | " exe set . 'makeprg='. escape(makeprg, '\ ') 267 | 268 | " Set errorformat ; strip redundant commas 269 | let v_efm = substitute(efm.value, ',\+', ',', "g") 270 | let v_efm = matchstr(v_efm, '^,*\zs.*') 271 | for P in efm.post 272 | let v_efm = P(v_efm) 273 | endfor 274 | " default used ... by default 275 | if strlen(v_efm) 276 | " Add the new formats 277 | " exe set . 'efm+="'. efm . '"' 278 | " exe set . 'efm+='. escape(efm, '\ ') 279 | " exe 'let &'.local.'efm = &'.local."efm . ',' . efm" 280 | exe 'let &'.local.'efm = v_efm' 281 | endif 282 | " set efm&vim " Reset to default value 283 | " let &efm = &efm . ',' . efm " Add the new formats 284 | endfunction 285 | 286 | " DefaultEFM(): {{{3 287 | " @return default value of &efm 288 | function! s:DefaultEFM(wanted_efm) abort 289 | " call Dfunc('s:DefaultEFM('.a:wanted_efm.')') 290 | let save_efm = &l:efm 291 | if a:wanted_efm == 'default efm' 292 | setlocal efm&vim 293 | else 294 | " if exists("current_compiler") 295 | silent! unlet b:current_compiler 296 | silent! unlet g:current_compiler 297 | " endif 298 | " exe 'compiler '.a:wanted_efm 299 | exe 'runtime compiler/'.a:wanted_efm.'.vim' 300 | if strlen(&makeprg) && !exists('g:BTW_filter_program_'.a:wanted_efm) && !exists('b:BTW_filter_program_'.a:wanted_efm) 301 | " @todo use the correct scope -> b:/g: 302 | let g:BTW_filter_program_{a:wanted_efm} = &makeprg 303 | endif 304 | endif 305 | let efm = &l:efm 306 | let &l:efm = save_efm 307 | " call Dret('s:DefaultEFM '.efm) 308 | return efm 309 | endfunction 310 | 311 | " AdjustEFM(filter, efm): {{{3 312 | function! s:AdjustEFM(filter, efm) abort 313 | let filter_efm = lh#option#get('BTW_adjust_efm_'.a:filter, '', 'bg') 314 | if type(filter_efm) == type({}) 315 | let added = filter_efm.value 316 | if has_key(filter_efm, 'post') 317 | let a:efm.post += [filter_efm.post] 318 | endif 319 | else 320 | let added = filter_efm 321 | endif 322 | " if added =~ "default efm" 323 | " TODO: use split and join 324 | let added = substitute(added, 'default efm', 325 | \ escape(s:DefaultEFM('default efm'), '\'), '') 326 | " endif 327 | if added =~ 'import:' 328 | let compiler_plugin_imported = matchstr(added, 'import: \zs[^,]*') 329 | let added = substitute(added, 'import: \%([^,]\{-}\ze\%(,\|$\)\)', 330 | \ escape(s:DefaultEFM(compiler_plugin_imported), '\'), '') 331 | endif 332 | let a:efm.value = 333 | \ lh#option#get('BTW_ignore_efm_'.a:filter, '', 'bg') 334 | \ . a:efm.value 335 | \ . (strlen(added) ? ','.added : '') 336 | endfunction 337 | 338 | " ToVarName(filterName): {{{3 339 | function! s:ToVarName(filterName) abort 340 | let filterName = substitute(a:filterName, '[^A-Za-z0-9_]', '_', 'g') 341 | return filterName 342 | endfunction 343 | 344 | " LoadFilter(filter): {{{3 345 | function! s:LoadFilter(filter) abort 346 | if 0 != strlen(lh#btw#chain#_find_filter(a:filter)) 347 | " First nominal case: there is a BTW-a:filter that will be loaded 348 | exe 'runtime! compiler/BTW-'.a:filter.'.vim compiler/BTW_'.a:filter.'.vim compiler/BTW/'.a:filter.'.vim' 349 | " echo 'runtime! compiler/BTW-'.a:filter.'.vim compiler/BTW_'.a:filter.'.vim compiler/BTW/'.a:filter.'.vim' 350 | elseif 0 != strlen(globpath(&rtp, 'compiler/'.a:filter.'.vim')) 351 | " Second case: there is a compiler plugin named {a:filter}.vim 352 | let b:BTW_adjust_efm_{a:filter} = 'import: '.a:filter 353 | elseif 0 != strlen(globpath(&rtp, 'compiler/BTW/'.a:filter.'.pl')) 354 | " Third case: there is a perl script compiler/BTW/{a:filter}.pl 355 | let g:BTW_filter_program_{a:filter} = globpath(&rtp, 'compiler/BTW/'.a:filter.'.vim') 356 | elseif executable(a:filter) 357 | let filter = s:ToVarName(a:filter) 358 | let g:BTW_filter_program_{filter} = a:filter 359 | else 360 | " There is no such a:filter 361 | endif 362 | endfunction 363 | 364 | " ToolsChain(): Helper {{{3 365 | function! s:ToolsChain() abort 366 | return join([lh#option#get('BTW_build_tool', 'make')] + lh#btw#chain#_filters_list(), ' | ') 367 | endfunction 368 | 369 | " Usage(): {{{3 370 | function! s:Usage() 371 | echo "Build Tools Wrapper: USAGE" 372 | endfunction 373 | 374 | " # Command completion {{{2 375 | " Constants {{{3 376 | let s:commands="set\nsetlocal\nsetoption\nsetoptionlocal\nadd\naddlocal\nremove\nremovelocal\nrebuild\necho\ndebug\nreloadPlugin\nnew_project\n?\nhelp" 377 | let s:functions="ToolsChain()\nHasFilterGuessScope(\nHasFilter(\nFindFilter(" 378 | let s:functions=s:functions. "\nProjectName()\nTargetRule()\nExecutable()" 379 | let s:variables="commands\nfunctions\nvariables" 380 | let s:k_new_prj = ['c', 'cpp', 'cmake', 'name=', 'config=', 'src_dir='] 381 | let s:k_options = ['compilation_dir', 'project_config', 'project_name', 382 | \ 'run_parameters', 'project_executable', 'project_target', 'project'] 383 | 384 | " lh#btw#chain#_BTW_complete(ArgLead, CmdLine, CursorPos): Auto-complete {{{3 385 | function! lh#btw#chain#_BTW_complete(ArgLead, CmdLine, CursorPos) 386 | let tmp = substitute(a:CmdLine, '\s*\S*', 'Z', 'g') 387 | let pos = strlen(tmp) 388 | call s:Verbose('complete(lead="%1", cmdline="%2", cursorpos=%3) -- tmp=%4, pos=%5', a:ArgLead, a:CmdLine, a:CursorPos, tmp, pos) 389 | 390 | if 2 == pos 391 | " First argument: a command 392 | return s:commands 393 | elseif 3 == pos 394 | " Second argument: first arg of the command 395 | if -1 != match(a:CmdLine, '^BTW\s\+\%(echo\|debug\)') 396 | return s:functions . "\n" . s:variables 397 | elseif -1 != match(a:CmdLine, '^BTW\s\+\%(help\|?\)') 398 | elseif -1 != match(a:CmdLine, '^BTW\s\+\%(set\|add\)\%(local\)\=\>') 399 | " Adds a filter 400 | " let files = globpath(&rtp, 'compiler/BT-*') 401 | " let files = files . globpath(&rtp, 'compiler/BT_*') 402 | " let files = files . globpath(&rtp, 'compiler/BT/*') 403 | let files = lh#btw#chain#_find_filter('*') 404 | let files = substitute(files, 405 | \ '\(^\|\n\).\{-}compiler[\\/]BTW[-_\\/]\(.\{-}\)\.vim\>\ze\%(\n\|$\)', 406 | \ '\1\2', 'g') 407 | return files 408 | elseif -1 != match(a:CmdLine, '^BTW\s\+\%(setoption\)\%(local\)\=\>') 409 | return join(s:k_options, "\n") 410 | elseif -1 != match(a:CmdLine, '^BTW\s\+remove\%(local\)\=') 411 | " Removes a filter 412 | return join(lh#btw#chain#_filters_list(), "\n") 413 | elseif -1 != match(a:CmdLine, '^BTW\s\+\') 414 | return "c\ncpp\ncmake\ndoxygen\nname=\nconfig=\nsrc_dir=" 415 | endif 416 | elseif 4 <= pos 417 | let p = matchend(a:CmdLine, '^BTW\s\+\') 418 | if -1 != p 419 | let already_there = split(a:CmdLine[p : ]) 420 | " let g:already_there = already_there 421 | return join(filter(copy(s:k_new_prj), 'match(already_there, "\\<".v:val."\\>")==-1'), "\n") 422 | endif 423 | endif 424 | " finally: unknown 425 | echoerr 'BTW: unespected parameter ``'. a:ArgLead ."''" 426 | return '' 427 | endfunction 428 | 429 | " # Miscelleanous: {{{2 430 | 431 | " Function: s:SetOption(scope, opts) {{{3 432 | function! s:SetOption(scope, opts) abort 433 | let a_name = 'BTW_'.a:opts[0] 434 | if len(a:opts) > 1 435 | let value = a:opts[1] 436 | if a:scope == 'g' 437 | let name = 'b:'.a_name 438 | if exists(name) 439 | call lh#common#warning_msg("Warning: ".name." is already set to ".{name}) 440 | endif 441 | endif 442 | let name = a:scope.':'.a_name 443 | let {name} = value 444 | else " only display the value 445 | let value = lh#option#get(a_name) 446 | if lh#option#is_set(value) 447 | echo "Option " . a_name . " is set to ".string(value) 448 | else 449 | call lh#common#warning_msg("Warning: ".a_name." is not set.") 450 | endif 451 | endif 452 | endfunction 453 | " }}}1 454 | "------------------------------------------------------------------------ 455 | let &cpo=s:cpo_save 456 | "============================================================================= 457 | " vim600: set fdm=marker: 458 | -------------------------------------------------------------------------------- /autoload/lh/btw/build.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: autoload/lh/btw/build.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " Version: 0.7.0. 6 | let s:k_version = '070' 7 | " Created: 23rd Mar 2015 8 | " Last Update: 19th Oct 2016 9 | "------------------------------------------------------------------------ 10 | " Description: 11 | " Internal functions used to build projects 12 | " }}}1 13 | "============================================================================= 14 | 15 | let s:cpo_save=&cpo 16 | set cpo&vim 17 | "------------------------------------------------------------------------ 18 | " ## Misc Functions {{{1 19 | " # Version {{{2 20 | function! lh#btw#build#version() 21 | return s:k_version 22 | endfunction 23 | 24 | " # Debug {{{2 25 | let s:verbose = get(s:, 'verbose', 0) 26 | function! lh#btw#build#verbose(...) 27 | if a:0 > 0 | let s:verbose = a:1 | endif 28 | return s:verbose 29 | endfunction 30 | 31 | function! s:Log(expr, ...) 32 | call call('lh#log#this',[a:expr]+a:000) 33 | endfunction 34 | 35 | function! s:Verbose(expr, ...) 36 | if s:verbose 37 | call call('s:Log',[a:expr]+a:000) 38 | endif 39 | endfunction 40 | 41 | function! lh#btw#build#debug(expr) 42 | return eval(a:expr) 43 | endfunction 44 | 45 | 46 | "------------------------------------------------------------------------ 47 | " ## Internal functions {{{1 48 | 49 | " # Options {{{2 50 | " TODO: distinguish rule-name for the compilation (e.g. ``all'') and the final 51 | " executable 52 | 53 | " Function: s:ProjectName() {{{3 54 | " This option can be defined: 55 | " - with a _vimrc_local file 56 | " - with a let-modeline 57 | " @todo deprecate this in favour of lh#btw#project_name() 58 | " @deprecated (bg):BTW_project, use (bpg):BTW.project 59 | function! s:ProjectName() abort 60 | let res = lh#option#get('BTW.project') 61 | if lh#option#is_set(res) | return res 62 | elseif exists('b:BTW_project') | return b:BTW_project 63 | elseif exists('g:BTW_project') | return g:BTW_project 64 | elseif &ft == 'qf' | cclose | return s:ProjectName() 65 | elseif lh#ft#is_script() | return '%' 66 | else | return '%<' 67 | endif 68 | endfunction 69 | 70 | " Function: s:TargetRule() {{{3 71 | " @deprecated (bg):BTW_project_target, use (bpg):BTW.target 72 | function! s:TargetRule() abort 73 | " TODO: find a better name 74 | " TODO: try to detect available rules in Makefile/main.aap/..., 75 | " and cache them 76 | " TODO: cclose is not the best way to quit the qf window -> memorize the 77 | " buffer from which it was compiled last 78 | if &ft == 'qf' | cclose | return s:TargetRule() | endif 79 | let res = lh#option#get('BTW.target') 80 | if lh#option#is_set(res) | return res 81 | elseif exists('b:BTW_project_target') | return b:BTW_project_target 82 | elseif exists('g:BTW_project_target') | return g:BTW_project_target 83 | else 84 | let res = s:ProjectName() 85 | if empty(res) 86 | res = 'all' " just a guess 87 | endif 88 | return res 89 | endif 90 | endfunction 91 | 92 | " Function: s:Executable() {{{3 93 | " @deprecated (bg):BTW_project_executable, use (bpg):BTW.executable 94 | let s:ext = lh#os#OnDOSWindows() ? '.exe' : '' 95 | function! s:Executable() abort 96 | " TODO: find a better name 97 | " TODO: try to detect available rules in Makefile/main.aap/..., 98 | " and cache them 99 | " TODO: cclose is not the best way to quit the qf window -> memorize the 100 | " buffer from which it was compiled last 101 | if &ft == 'qf' | cclose | return s:Executable() | endif 102 | let res = lh#option#get('BTW.executable') 103 | if lh#option#is_set(res) | return res 104 | elseif exists('b:BTW_project_executable') | return b:BTW_project_executable 105 | elseif exists('g:BTW_project_executable') | return g:BTW_project_executable 106 | else 107 | let res = s:ProjectName() 108 | if empty(res) 109 | throw "BTW: Sorry, I'm not able to deduce project name in order to know which executable to run. Please see `:h BTW-project-executable`" 110 | " TODO: glob()+executable() -> possible executable in the build 111 | " directory 112 | endif 113 | let res .= s:ext 114 | return res 115 | endif 116 | endfunction 117 | 118 | " # Run (anything) {{{2 119 | " Function: s:RunInBackGround() {{{3 120 | if exists('s:run_in_background') 121 | unlet s:run_in_background 122 | endif 123 | 124 | function! s:FetchRunInBackground() abort 125 | " This is a the old background compilation function for vim version < 8 126 | let rib_progname = lh#os#OnDOSWindows() 127 | \ ? 'run_and_recontact_vim' 128 | \ : 'run_in_background' 129 | 130 | if exists('*globpath') 131 | let s:run_in_background = globpath(&rtp, 'compiler/BTW/'.rib_progname.'.pl') 132 | else 133 | call lh#common#error_msg( "Build Tools Wrapper:\n This plugin requires either a version of Vim that defines |globpath()|\n" 134 | \." Please upgrade your version of vim\n") 135 | finish 136 | endif 137 | 138 | let s:run_in_background = 'perl '.lh#path#fix(s:run_in_background, !lh#os#OnDOSWindows()) 139 | endfunction 140 | 141 | function! s:RunInBackground() 142 | if !exists('s:run_in_background') 143 | call s:FetchRunInBackground() 144 | endif 145 | return s:run_in_background 146 | endfunction 147 | 148 | 149 | " Function: s:DoRunAndCaptureOutput(program [, args]) {{{3 150 | let s:k_multijobs_options = { 151 | \ 'make': '-j' 152 | \} 153 | let s:has_jobs = exists('*job_start') && has("patch-7.4.1980") 154 | function! s:DoRunAndCaptureOutput(program, ...) abort 155 | let bg = (has('clientserver') || s:has_jobs) && lh#btw#option#_make_in_bg() 156 | let cleanup = lh#on#exit() 157 | \.restore('&makeprg') 158 | if bg 159 | if !s:has_jobs " case handled latter 160 | let run_in = lh#btw#option#_make_in_bg_in() 161 | if strlen(run_in) 162 | " Typically xterm -e 163 | let run_in = ' --program="'.run_in.'"' 164 | endif 165 | let &makeprg = s:RunInBackground() 166 | \ . ' --vim=' . v:progname 167 | \ . ' --servername=' . v:servername 168 | \ . run_in 169 | \ . ' "' . (a:program) . '"' 170 | endif 171 | else " synchronous building 172 | let &makeprg = a:program 173 | endif 174 | let args = join(a:000, ' ') 175 | let nb_jobs = lh#btw#option#_make_mj() 176 | " if has_key(s:k_multijobs_options, a:program) && type(nb_jobs) == type(0) && nb_jobs > 0 177 | if type(nb_jobs) == type(0) && nb_jobs > 0 178 | " let args .= ' '. s:k_multijobs_options[a:program] .nb_jobs 179 | let args .= ' -j' .nb_jobs 180 | endif 181 | 182 | try 183 | if bg && s:has_jobs 184 | let args = expand(args) 185 | call s:Verbose('rpl $* w/ %1', args) 186 | let cmd = substitute(&makeprg, '\$\*', args, 'g') 187 | " makeprg escapes pipes, we need to unescape them for job_start 188 | let cmd = substitute(cmd, '\\|', '|', 'g') 189 | call lh#btw#job_build#execute(cmd) 190 | elseif lh#os#OnDOSWindows() && bg 191 | let cmd = ':!start '.substitute(&makeprg, '\$\*', args, 'g') 192 | exe cmd 193 | else 194 | " lh#os#make will inject p:$ENV on-the-fly, if needed. 195 | call lh#os#make(args, '!') 196 | endif 197 | catch /.*/ 198 | if lh#btw#filters#verbose() > 0 199 | debug call lh#common#error_msg("Error: ".v:exception. " thrown at: ".v:throwpoint) 200 | else 201 | call lh#common#error_msg("Error: ".v:exception. " thrown at: ".v:throwpoint) 202 | endif 203 | finally 204 | " Records which was the last buffer 205 | if &ft != 'qf' 206 | call lh#btw#_save_last_buffer_data() 207 | endif 208 | 209 | call cleanup.finalize() 210 | endtry 211 | 212 | if bg && s:has_jobs 213 | call lh#btw#build#_copen_bg() 214 | else 215 | call lh#btw#build#_show_error() 216 | endif 217 | return bg 218 | endfunction 219 | 220 | " # Compile {{{2 221 | " Function: lh#btw#build#_compile([target]) {{{3 222 | function! lh#btw#build#_compile(...) abort 223 | update 224 | call lh#btw#option#_check_deprecated_options() 225 | if a:0 > 0 && strlen(a:1) 226 | let rule = a:1 227 | else 228 | let rule = s:TargetRule() 229 | endif 230 | " else ... pouvoir avoir s:TargetRule() . a:1 ; si ?! 231 | 232 | if lh#btw#option#_use_prio() == 'update' 233 | call lh#btw#chain#_reconstruct() 234 | endif 235 | let bg = s:DoRunAndCaptureOutput(&makeprg, rule) 236 | if !bg 237 | echomsg "Compilation finished".(len(rule)?" (".rule.")" : "") 238 | if exists(':CompilHintsUpdate') 239 | :CompilHintsUpdate 240 | endif 241 | endif 242 | endfunction 243 | 244 | " Function: lh#btw#build#_show_error([cop|cwin]) {{{3 245 | function! lh#btw#build#_show_error(...) abort 246 | let qf_position = lh#btw#option#_qf_position() 247 | 248 | if a:0 == 1 && a:1 =~ '^\%(cw\%[window]\|copen\)$' 249 | let open_qf = a:1 250 | else 251 | let open_qf = 'cwindow' 252 | endif 253 | let winid = lh#window#getid() 254 | 255 | " --- The following code is borrowed from LaTeXSuite 256 | " close the quickfix window before trying to open it again, otherwise 257 | " whether or not we end up in the quickfix window after the :cwindow 258 | " command is not fixed. 259 | let winnum = winnr() 260 | cclose 261 | " cd . is used to avoid absolutepaths in the quickfix window 262 | cd . 263 | exe qf_position . ' ' . open_qf 264 | 265 | setlocal nowrap 266 | 267 | " if we moved to a different window, then it means we had some errors. 268 | if winnum != winnr() 269 | " resize the window to just fit in with the number of lines. 270 | let nl = lh#btw#option#_qf_size() 271 | let nl = line('$') < nl ? line('$') : nl 272 | exe nl.' wincmd _' 273 | 274 | " Apply syntax hooks 275 | let syn = lh#btw#option#_qf_syntax() 276 | if !empty(syn) 277 | silent exe 'runtime compiler/BTW/syntax/'.syn.'.vim' 278 | endif 279 | call lh#btw#filters#_apply_quick_fix_hooks('syntax') 280 | endif 281 | if lh#btw#option#_goto_error() 282 | call lh#window#gotoid(winid) 283 | endif 284 | " When calling :Copen, restore automatic scroll of qf window 285 | if exists('g:lh#btw#auto_cbottom') 286 | let g:lh#btw#auto_cbottom = lh#btw#option#_auto_scroll_in_bg() 287 | cbottom 288 | endif 289 | endfunction 290 | 291 | " Function: lh#btw#build#_copen_bg_complete(what, job_info, [cop|cwin]) {{{3 292 | function! lh#btw#build#_copen_bg_complete(what, job_info, ...) abort 293 | let opt = (a:0>0) ? a:1 : '' 294 | if get(g:, 'lh#btw#auto_cbottom', 1) 295 | call call('lh#btw#build#_show_error', a:000) 296 | endif 297 | let msg 298 | \ = a:what 299 | \ . (a:job_info.exitval == 0 ? " successfully built" : " build failed (w/ exitval:".(a:job_info.exitval).")") 300 | call lh#common#warning_msg("Build complete: ".msg."!") 301 | if exists(':CompilHintsUpdate') 302 | :CompilHintsUpdate 303 | endif 304 | endfunction 305 | 306 | " Function: lh#btw#build#_copen_bg([cop|cwin]) {{{3 307 | " lh#btw#build#_show_error overload that does an unconditional opening of the 308 | " qf window 309 | function! lh#btw#build#_copen_bg(...) abort 310 | let qf_position = lh#btw#option#_qf_position() 311 | 312 | if a:0 == 1 && a:1 =~ '^\%(cw\%[window]\|copen\)$' 313 | let open_qf = a:1 314 | else 315 | let open_qf = 'copen' 316 | endif 317 | let winid = lh#window#getid() 318 | 319 | cclose 320 | " cd . is used to avoid absolutepaths in the quickfix window 321 | cd . 322 | exe qf_position . ' ' . open_qf 323 | 324 | setlocal nowrap 325 | 326 | call assert_notequal(winid, lh#window#getid()) " a call to setqflist() should move us to the qfwindow 327 | call assert_equal(&ft, 'qf') 328 | " resize the window to have the right number of lines 329 | let nl = lh#btw#option#_qf_size() 330 | exe nl.' wincmd _' 331 | let w:quickfix_title = lh#btw#build_mode(). ' compilation of ' . lh#btw#project_name() 332 | 333 | " Apply syntax hooks 334 | let syn = lh#btw#option#_qf_syntax() 335 | if !empty(syn) 336 | silent exe 'runtime compiler/BTW/syntax/'.syn.'.vim' 337 | endif 338 | call lh#btw#filters#_apply_quick_fix_hooks('syntax') 339 | call lh#window#gotoid(winid) 340 | endfunction 341 | 342 | " Function: lh#btw#build#_get_metrics() {{{3 343 | function! lh#btw#build#_get_metrics() abort 344 | let qf = getqflist() 345 | let recognized = filter(qf, 'get(v:val, "valid", 1)') 346 | " TODO: support other locales 347 | let errors = filter(copy(recognized), 'v:val.type == "E" || v:val.text =~ "\\v^ *(error|erreur)"') 348 | let warnings = filter(copy(recognized), 'v:val.type == "W" || v:val.text =~ "\\v^ *(warning|attention)"') 349 | let res = { 'all': len(qf), 'errors': len(errors), 'warnings': len(warnings) } 350 | return res 351 | endfunction 352 | 353 | " # Execute {{{2 354 | " Function: lh#btw#build#_execute() {{{3 355 | function! lh#btw#build#_execute() 356 | let path = s:Executable() 357 | if type(path) == type({}) 358 | " Assert(path.type == 'make') 359 | " Extract environment variables. 360 | let ctx='' 361 | for [k,v] in items(path) 362 | if k[0] == '$' 363 | let ctx .= k[1:].'='.v.' ' 364 | endif 365 | endfor 366 | " Execute the command 367 | if path.type =~ 'make\|ctest' 368 | let makeprg = &makeprg 369 | if path.type == 'ctest' 370 | let makeprg = substitute(&makeprg, '\', 'ctest', '') 371 | call lh#btw#_register_fix_ctest() 372 | endif 373 | if !empty(ctx) 374 | let p = matchend(makeprg, '.*;') 375 | if -1 == p 376 | let makeprg = ctx.makeprg 377 | else 378 | " several commands => inject the variables on the last command 379 | let makeprg = makeprg[ : (p-1)].ctx.makeprg[p : ] 380 | endif 381 | endif 382 | call s:DoRunAndCaptureOutput(makeprg, path.rule) 383 | else 384 | call lh#common#error_msg( "BTW: unexpected type (".(path.type).") for the command to run") 385 | endif 386 | else " normal case: string = command to execute 387 | if (lh#os#system_detected() == 'unix') && (path[0]!='/') && (path!~'[a-zA-Z]:[/\\]') && (path!~'cd') 388 | " todo, check executable(split(path)[0]) 389 | let path = './' . path 390 | endif 391 | let cmd = lh#path#fix(path) . ' ' .lh#btw#option#_run_parameters() 392 | call s:Verbose(':!%1', cmd) 393 | exe ':!'.cmd 394 | endif 395 | endfunction 396 | 397 | " # Config {{{2 398 | " Function: lh#btw#build#_config() {{{3 399 | function! lh#btw#build#_config() abort 400 | let how = lh#btw#option#_project_config() 401 | if how.type == 'modeline' 402 | call lh#btw#build#_add_let_modeline() 403 | elseif how.type == 'makefile' 404 | let wd = lh#btw#_evaluate(how.wd) 405 | let file = lh#btw#_evaluate(how.file) 406 | call lh#buffer#jump(wd.'/'.file) 407 | elseif how.type == 'ccmake' 408 | let wd = lh#btw#_evaluate(how.wd) 409 | if lh#os#OnDOSWindows() 410 | " - the first ":!start" runs a windows command 411 | " - "cmd /c" is used to define the second "start" command (see "start /?") 412 | " - the second "start" is used to set the current directory and run the 413 | " execution. 414 | let prg = 'start /b cmd /c start /D '.lh#path#fix(wd, 0, '"') 415 | \.' /B cmake-gui '.lh#path#fix(how.arg, 0, '"') 416 | else 417 | " let's suppose no spaces are used 418 | " let prg = 'xterm -e "cd '.wd.' && ccmake '.(how.arg).'"' 419 | let prg = 'cd '.wd.' && cmake-gui '.(how.arg).'&' 420 | endif 421 | " let g:prg = prg 422 | call s:Verbose(":!".prg) 423 | exe ':silent !'.prg 424 | endif 425 | endfunction 426 | 427 | " Function: lh#btw#build#_re_config() {{{3 428 | function! lh#btw#build#_re_config() abort 429 | let how = lh#btw#option#_project_config() 430 | if how.type == 'modeline' 431 | if exists(':FirstModeLine') 432 | :FirstModeLine 433 | return 434 | endif 435 | elseif how.type == 'makefile' 436 | " let wd = lh#btw#_evaluate(how.wd) 437 | " let file = lh#btw#_evaluate(how.file) 438 | " call lh#buffer#jump(wd.'/'.file) 439 | return 440 | elseif how.type == 'ccmake' 441 | debug let wd = lh#btw#_evaluate(how.wd) 442 | if lh#os#OnDOSWindows() 443 | " - the first ":!start" runs a windows command 444 | " - "cmd /c" is used to define the second "start" command (see "start /?") 445 | " - the second "start" is used to set the current directory and run the 446 | " execution. 447 | let prg = 'start /b cmd /c start /D '.lh#path#fix(wd, 0, '"') 448 | \.' /B cmake .' 449 | else 450 | " let's suppose no spaces are used 451 | " let prg = 'xterm -e "cd '.wd.' && cmake ."' 452 | call s:Verbose('Reconfigure with: cd %1 && cmake .', wd) 453 | let prg = 'cd '.wd.' && cmake .' 454 | endif 455 | call s:Verbose(":!".prg) 456 | " TODO: Asynch execution through &makeprg! 457 | exe ':!'.prg 458 | endif 459 | endfunction 460 | 461 | " Function: lh#btw#build#_add_let_modeline() {{{3 462 | " Meant to be used with let-modeline.vim 463 | function! lh#btw#build#_add_let_modeline() abort 464 | " TODO: become smart: auto detect makefile, A-A-P, scons, ... 465 | 466 | " Check if there is already a Makefile 467 | let make_files = glob('Makefile*') 468 | if strlen(make_files) 469 | let make_files = substitute("\n".make_files, '\n', '\0Edit \&', 'g') 470 | " elseif !strlen(aap_files) 471 | " let make_files = "\nEdit &Makefile" 472 | endif 473 | 474 | let opts = '' 475 | if &ft == 'cpp' 476 | let opts .= "\nC&XXFLAGS\nC&PPFLAGS" 477 | elseif &ft == 'c' 478 | let opts .= "\n&CFLAGS\nC&PPFLAGS" 479 | endif 480 | let which = WHICH('COMBO', 'Which option must be set ?', 481 | \ "Abort" 482 | \ . make_files 483 | \ . opts 484 | \ . "\n$L&DFLAGS\n$LD&LIBS" 485 | \ . "\n".lh#marker#txt('bpg').":&BTW_project" 486 | \ ) 487 | if which =~ 'Abort\|^$' 488 | " Nothing to do 489 | elseif which =~ '^Edit.*$' 490 | call lh#window#split(matchstr(which, 'Edit\s*\zs.*')) 491 | else 492 | below split 493 | let s = search('Vim:\s*let\s\+.*'.which.'\s*=\zs') 494 | if s <= 0 495 | let l = '// Vim: let '.which."='".lh#marker#txt('option')."'" 496 | call append('$', l) 497 | endif 498 | endif 499 | endfunction 500 | 501 | " }}}1 502 | "------------------------------------------------------------------------ 503 | let &cpo=s:cpo_save 504 | "============================================================================= 505 | " vim600: set fdm=marker: 506 | -------------------------------------------------------------------------------- /doc/BuildToolsWrapper.txt: -------------------------------------------------------------------------------- 1 | *BuildToolsWrapper.txt* Projects building plugin 2 | For Vim version 7.x. Last change: 14th Oct 2016 3 | 4 | 5 | BuildToolsWrapper Plugin MANUAL By Luc Hermitte 6 | version 0.7.0 7 | 8 | 9 | ------------------------------------------------------------------------------ 10 | Contents~ 11 | |BTW-presentation| Presentation 12 | |BTW-filters| Filter plugins 13 | |BTW-filter-purpose| Purpose 14 | |:BTW| :BTW, the filters management command 15 | |BTW-default-filters| Default filters 16 | |BTW-write-filter| Write a filter 17 | 18 | |BTW-Build-Execute| Build and Execute 19 | 20 | |?link?| ?title? 21 | |add-local-help| Instructions on installing this file 22 | 23 | 24 | ------------------------------------------------------------------------------ 25 | *BTW-presentation* 26 | Presentation~ 27 | 28 | This plugin serves two distinct, but related, purposes: 29 | - define a flexible alternative to Vim |compiler-plugin|s, 30 | -> |BTW-filters|, 31 | - and ease the compilation of projects 32 | -> |BTW-Build-Execute|. 33 | 34 | 35 | ------------------------------------------------------------------------------ 36 | *BTW-filters* 37 | Filter-plugins~ 38 | 39 | Purpose~ 40 | BuildToolsWrapper.vim offers an alternative and modular way to define and use 41 | |compiler-plugin|s. The classical approach consists in defining as many 42 | compiler-plugins as we have unique environments in which we compile our 43 | programs. With BuildToolsWrapper.vim we can define independant filters, and 44 | choose which ones to use regarding to our environment and project. 45 | 46 | For instance in a project, we can load the filters for A-A-P, GCC, and Cygwin, 47 | if we are using Cygwin-tools from win32-Vim. In another, we will use gmake 48 | filter instead of A-A-P filter, and still use GCC filter and may be even a 49 | filter wrapping STLFit (). 50 | 51 | 52 | Generalities~ 53 | BuildToolsWrapper.vim distinguishes two kind of plugins: 54 | - the ones associated to the main build tool ((g)Make, A-A-P, bjam, scons, ant, 55 | ...) 56 | - and the ones associated to the various tools involded in the build chain. That 57 | is to say the various compilers, linkers and other programs (Test Unit 58 | Frameworks, Documentation tools, ...) used. 59 | 60 | 61 | BTW filter-plugins can define two different, but related, things: 62 | - the 'errorformat' associated to a tool. |g:BTW_adjust_efm_{tool}| 63 | - the external filter that must be applied over the results of the compilation 64 | process. |[bg]:BTW_filter_program_{tool}| 65 | 66 | Last thing, a distinction is made between global and local definitions. As with 67 | compiler-plugins, we should prefer local definitions over global ones. Every 68 | time the definitions of a filter are loaded by |:BTW|, we can choose to use them 69 | globally or locally to the current buffer. Every local setting overrides the 70 | global settings. 71 | 72 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 73 | *BTW-filter-purpose* 74 | 75 | ?Insert here? 76 | 77 | 78 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 79 | *:BTW* 80 | :BTW, The filters management command~ 81 | 82 | The filters used in a specific project are managed with the command :BTW. 83 | 84 | This command accepts the following sub-commands: 85 | 86 | - :BTW set {main-filter} *:BTW-set* 87 | - :BTW setlocal {main-filter} *:BTW-setlocal* 88 | These two commands set the main filter-plugin, i.e. the one associated to the 89 | build tool -- i.e. make, A-A-P, scons, bjam, ... 90 | With "setlocal", we override the main filter-plugin. 91 | 92 | - :BTW add {filter} *:BTW-add* 93 | - :BTW addlocal {filter} *:BTW-addlocal* 94 | These two commands add a filter-plugin at the end of the chain 95 | of filter-plugins applied over the result of the compilation process. 96 | The order of the filters applied respects the order of the calls to 97 | ":BTW add(local)". 98 | With "addlocal", we override (ignore), in the scope of the current buffer, the 99 | filter-plugins globally loaded. 100 | ? must add-global apply to local lists when they already exist ? 101 | 102 | - :BTW remove {filter} *:BTW-remove* 103 | - :BTW removelocal {filter} *:BTW-removelocal* 104 | Remove a filter-plugin from the chain of filter-plugins applied. 105 | global: the filter-plugin will also be removed from every buffer-local list 106 | local: if there is no local list, and the filter is found in the global list, 107 | then a local list is build from the global one, but without the 108 | filter. 109 | todo: retest 110 | 111 | - :BTW clear {filter} *:BTW-clear* 112 | - :BTW clearlocal {filter} *:BTW-clearlocal* 113 | Full reset of the filter-plugins used. This command can be seen as an 114 | alternative to calling |:BTW-remove| on every filter-plugin. 115 | Yet to be implemented 116 | 117 | - :BTW rebuild *:BTW-rebuild* 118 | Little helper command. Only useful when the vim script (that defines a 119 | filter-plugin) has been changed, and we want to refresh 'makeprg' and 120 | 'errorformat' in consequence. 121 | 122 | - :BTW echo {expr} *:BTW-echo* 123 | Debug oriented helper function. It serves to evaluate and display an internal 124 | (script scope -> s:) data/function from BuildToolsWrapper.vim. 125 | 126 | In order to ease the use of |:BTW|, this command supports a smart 127 | auto-completion. 128 | 129 | 130 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 131 | *BTW-default-filters* 132 | Default filters~ 133 | 134 | A few filter-plugins are shipped with BuildToolsWrapper. 135 | 136 | Main filter-plugins~ 137 | - A-A-P () 138 | The filter-plugin defines: 139 | - the program to use according to the OS -> aap or aap.bat 140 | - a few adjustments to the 'errorformat', in order to take into account some 141 | error messages from A-A-P. 142 | 143 | - (g)make. 144 | filter-plugin yet to be written... It will contain folding stuff. 145 | 146 | Other filter-plugins~ 147 | - GCC, the filter-plugin defines: 148 | - the typical settings for 'errorformat' (may be enhanced/corrected in the 149 | future) 150 | - a way to have clickable link-error messages, and to regroup them. This 151 | feature is acheived thanks to an external perl filter ; and a few syntax 152 | highlighting additions have added for the "qf" filetype. 153 | Regarding the options available to the end user: 154 | - *g:BTW_gcc_group_lnk* (boolean [1] ?) indicates whether we wish to regroup 155 | the link-errors 156 | - *g:BTW_gcc_click_lnk* (boolean [1] ?) indicates whether we wish to have 157 | clickable link-errors. 158 | - *g:BTW_gcc_obj_dir* (string: ['']) directory where the object files will 159 | be stored. 160 | - *g:BTW_gcc_src_dir* (string ['']) directory where the translation units 161 | are. 162 | 163 | - TreeProject 164 | See this filter-plugin as an example of what can be done. 165 | The filter-plugin will find and set, on a buffer-basis, which makefile must be 166 | used, according to the directory (matching an independant subcomponent of a 167 | big project) in which the files of the buffer is stored. 168 | 169 | - Cygwin () 170 | This filter-plugin is useful when we use cygwin tools to compile anything from 171 | the win32 native version of Vim. Indeed, win32-vim does not understand Cygwin 172 | symbolic links, nor Cygwin absolute paths. 173 | That's why there is a {rtp}/compiler/BTW/cygwin.vim. This plugin relies on an 174 | external perl script. 175 | 176 | 177 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 178 | *BTW-write-filter* 179 | Write a filter-plugin~ 180 | 181 | The filter-plugin {name} is supposed to be associated to the file 182 | {rtp}/compiler/BTW/{name}.vim, where {rtp} refers to any directory from the 183 | 'runtimepath'. 184 | 185 | 186 | Many things can be done in these filter-plugin, however, BuildToolsWrapper waits 187 | for two (optional) settings: 188 | - *[bg]:BTW_filter_program_{tool}* 189 | It could be any external program: a perl script with its arguments, a 190 | call to make after having changed the current directory, ..., or even a 191 | |FuncRef| (see compiler/BTW/cmake.vim) 192 | - *g:BTW_adjust_efm_{tool}* 193 | This is used to define the 'errorformat' for the quick-fix window. 194 | In order to support post-treatments on &efm value, this variable can be a 195 | |Dictionary| of the form: > 196 | {"value": string, "post": FuncRef} 197 | 198 | 199 | Note: there are a few variables you will see from Vim. However, do not 200 | manipulate them directly. They are actually internal variables you must ignore. 201 | -> `[bg]:BTW_filters_list`, `[bg]:BTW_build_tool` 202 | 203 | 204 | ------------------------------------------------------------------------------ 205 | *BTW-Build-Execute* 206 | Build and Execute~ 207 | 208 | BTW also serves to ease the compilation of projects and execute programs built. 209 | 210 | The different possible operations are: 211 | 212 | *:Make* 213 | Building a program...~ 214 | The command |:Make| accepts an optional target. The default target is determined 215 | according to the heuristic described in |BTW-project-target|. 216 | 217 | By default, |:Make| (with no argument) is binded to . This can be overrided 218 | with the option |g:BTW.key.make|. 219 | 220 | *:Make-background* 221 | ...in background...~ 222 | The compilation will be done in background if *g:BTW.make_in_background* is 223 | set to 1. This option is best set in |.vimrc|, and best changed with 224 | *:ToggleMakeBG* , or the related |menu| under `Project`. 225 | 226 | ...with jobs~ 227 | If a sufficient version of Vim is detected (at least v7.4-1980), the 228 | compilation will be done thanks to the new +|job| feature. By default, the 229 | quickfix window will scroll automatically to show last errors -- given a 230 | recent enough version of Vim (v7.4.1997) that implements |:cbottom|. To stop 231 | the scrolling, jump to the |quickfix-window|, and execute |:Copen| to 232 | reactivate it. 233 | You can also set the option *g:BTW.autoscroll_background_compilation* 234 | to 0 to completly disable this autoscrolling feature. 235 | 236 | The background compilation (based on |+job|) can be stopped at any time thanks 237 | to |:StopBGExecution| 238 | 239 | ...or with perl~ 240 | With older versions of Vim, perl will be required to run `make` into the 241 | background. 242 | 243 | *:Make-multijobs* 244 | ...with multiple jobs~ 245 | The compilation can be done with multiple jobs thanks to 246 | *g:BTW.make_multijobs* option. Set it to the number of jobs you wish to use. 247 | This feature makes sense only with `make` executables that provide the `-j` 248 | option. 249 | The option value can be toggled with *:ToggleMakeMJ* or the related |menu|. 250 | 251 | *:Execute* 252 | Executing a program~ 253 | The command |:Execute| accepts no arguments. The default program to execute is 254 | determined according to the heuristic described in |BTW-project-executable|. 255 | 256 | Arguments to the program can be specified with the option 257 | |(bpg):BTW.run_parameters|. 258 | 259 | By default, |:Execute| (with no argument) is binded to This can be 260 | overrided with the option |[bpg]:BTW.key_execute|. 261 | 262 | *BTW-Build-Configure* 263 | Configuration of the build process~ 264 | A little helper is provided for when we can rely on gmake to automatically 265 | compile programs made of only one translation unit (.c, .cpp, ...). Typically 266 | small test programs, and not real projects. 267 | 268 | Depending on |(bpg):BTW.project_config| `.how` field, *:Config* will: 269 | - `"modeline"` -> Help to add a |let-modeline| for various environment 270 | variables like `$CFLAGS`, `$CXXFLAGS`, `$LDFLAGS`, `$LDLIBS`, 271 | |(bpg):BTW.project|, ... The let-modeline will be added at the 272 | bottom of the edited file. 273 | Pointless if you haven't installed my |let-modeline.vim| 274 | plugin. 275 | - `"makefile"` -> Jump to the `Makefile` associated to the `.wd` key. 276 | - `"ccmake"` -> execute `ccmake {.how.arg}` (or `cmake-gui {.how.arg}`) 277 | from `(bpg):BTW.project_config.wd` directory. 278 | 279 | Depending on |(bpg):BTW.project_config| `.how` field, *:ReConfig* will: 280 | - `"modeline"` -> reload the |let-modeline| with |:FirstModeline|; 281 | - `"makefile"` -> do nothing (for now?); 282 | - `"ccmake"` -> execute `cmake .` from the right directory; 283 | 284 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 285 | *BTW-keybindings* 286 | 287 | *g:BTW.key.make* (def. ) keybinding associated to |:Make|. 288 | *g:BTW.key.execute* (def. ) keybinding associated to |:Execute|. 289 | *g:BTW.key.config* (def. ) keybinding associated to |:Config|. 290 | *g:BTW.key.re_config* (def. ) keybinding associated to |:ReConfig|. 291 | 292 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 293 | Heuristics~ 294 | 295 | *BTW-project-target* 296 | Target heuristics~ 297 | The target used by |:Make| is chosen according to the following rule. 298 | - First |:Make| tries to use the option *(bpg):BTW.target* 299 | - If not set, it tries to use the target from the heuristics |BTW-project-name|. 300 | - If nothing is returned, "all" is assumed. 301 | 302 | *BTW-project-executable* 303 | Executable heuristics~ 304 | The executable used by |:Execute| is chosen according to the following rule. 305 | - |:Execute| tries to use the option *(bpg):BTW.executable* 306 | - If not set, it tries to use the name from the heuristics |BTW-project-name|, 307 | to which it may add ".exe" if vim is runned under Windows. (MsDos is not taken 308 | into account) 309 | - If nothing is returned, nothing is returned. 310 | I will eventually try to detect acceptable executables in the build directory. 311 | 312 | *BTW-project-name* 313 | Project name heuristics~ 314 | The name of the project is defined by *(bpg):BTW.project* , if set. If not, it 315 | uses the name of the file in the current buffer (|%<|), or the name of the file 316 | from alternate buffer (|#<|) if we are in the |quickfix-window|. 317 | 318 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 319 | *BTW-quickfix* 320 | Options for the Quickfix window~ 321 | 322 | Several options permit to tune how the |quickfix-window| is handled by |:Make|, 323 | |:Cwin| and |:Copen|. 324 | 325 | *g:BTW.qf_position* defines where the |quickfix-window| will be opened. 326 | Typical values match the commands: |:vert|, |:lefta|, |:abo|, ... 327 | 328 | *g:BTW.qf_size* defines the maximum heigth of the |quickfix-window|. The default 329 | value is 1/4 of vim screen/window ('lines'). 330 | Note: the corresponding code has been stolen from |LaTeX-Suite|. 331 | 332 | *g:BTW.goto_error* defines whether |:Make| will automatically jump to the 333 | first error. The default value is true (1). 334 | 335 | 336 | ------------------------------------------------------------------------------ 337 | *BTW-requirements* 338 | External requirements~ 339 | 340 | BTW depends on the following plugins: 341 | - |lh-vim-lib| v4.0.0 342 | 343 | A few other scripts of mine will be useful with BTW. 344 | - |local_vimrc| is a plugin that permits to define options (and any other things 345 | like mappings, functions, ...) that will be local to the files in the 346 | sub-directories of the one where there are _vimrc_local.vim files. 347 | (local_vimrc is a plugin that enables local .vimrc's named _vimrc_local.vim) 348 | - |lh-compil-hint| 349 | 350 | 351 | ------------------------------------------------------------------------------ 352 | *BTW-deprecated-options* 353 | 354 | In Version 0.7.0, option naming policy has changed. Old variable names are 355 | still supported for the moment. 356 | 357 | The idea is to store options in the |dictionaries| *g:BTW.* , *p:BTW.* (a 358 | |p:|roject variable) and *b:BTW.* instead of the multiple `g:BTW_xxx` and 359 | `b:BTW_xxx` variables. 360 | 361 | Here is the translation table: 362 | Old Name -> New name 363 | ----------------------------------------------------------------------------------- 364 | *(bpg):BTW_project* -> |(bpg):BTW.project| 365 | *(bpg):BTW_project_target* -> |(bpg):BTW.target| 366 | *(bpg):BTW_project_executable* -> |(bpg):BTW.executable| 367 | *(bpg):BTW_project_config* -> |(bpg):BTW.project_config| 368 | *(bpg):BTW_project_build_mode* -> |(bpg):BTW.project_config| 369 | *(bpg):BTW_compilation_dir* -> |(bpg):BTW.compilation_dir| 370 | *g:BTW_autoscroll_background_compilation* -> |g:BTW.autoscroll_background_compilation| 371 | *g:BTW_GotoError* -> |g:BTW.goto_error| 372 | *g:BTW_make_in_background* -> |g:BTW.make_in_background| 373 | *g:BTW_make_multijobs* -> |g:BTW.make_multijobs| 374 | *(bpg):BTW_make_in_background_in* -> |(bpg):BTW.make_in_background_in| 375 | *(bpg):BTW_use_prio* -> |(bpg):BTW.use_prio| 376 | *g:BTW_qf_position* -> |g:BTW.qf_position| 377 | *g:BTW_QF_size* -> |g:BTW.qf_size| 378 | *(gpb):BTW_qf_syntax* -> |(gpb):BTW.qf_syntax| 379 | *(bpg):BTW_run_parameters* -> |(bpg):BTW.run_parameters| 380 | *(bpg):BTW_project_name* -> |(bpg):BTW.project_name| 381 | *(bg):BTW_key_make* -> |g:BTW.key.make| 382 | *(bg):BTW_key_execute* -> |g:BTW.key.execute| 383 | *(bg):BTW_key_config* -> |g:BTW.key.config| 384 | *(bg):BTW_key_re_config* -> |g:BTW.key.re_config| 385 | 386 | 387 | ------------------------------------------------------------------------------ 388 | *BTW-future* 389 | TODO list~ 390 | - Auto-completion (Read/Write) for BTW variables 391 | - Priority (for add and addlocal) ; 392 | - Better doc 393 | - Find better names / terminology ; 394 | - Support for folding 395 | - Full detailled example tuned with local_vimrc 396 | - Filter-plugins for: STLFit, Doxygen 397 | - Improve and document *QFImport* , |BTW.compilation_dir| , "import:" 398 | 399 | ------------------------------------------------------------------------------ 400 | © Luc Hermitte, 2004-2016, , CC by SA 3.0 {{{1 401 | VIM: let b:VS_language = 'american' 402 | vim:ts=8:sw=4:tw=80:fo=tcq2:isk=!-~,^*,^\|,^\":ft=help: 403 | -------------------------------------------------------------------------------- /plugin/BuildToolsWrapper.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: plugin/BuildToolsWrapper.vim {{{1 3 | " Maintainer: Luc Hermitte 4 | " 5 | " Licence: GPLv3 6 | " Version: 0.7.0 7 | let s:k_version = 0700 8 | " Created: 28th Nov 2004 9 | " Last Update: 12th Oct 2016 10 | "------------------------------------------------------------------------ 11 | " Description: Flexible alternative to Vim compiler-plugins. 12 | " 13 | "------------------------------------------------------------------------ 14 | " Installation: 15 | " Drop this plugin into {rtp}/plugin/ 16 | " Requires: lh-vim-lib (v3.1.0+), System_utils, also available on my web site 17 | " Other Recommended Scripts: menu-maps.vim, local_vimrc.vim 18 | " 19 | " History: {{{2 20 | " v0.0.1: 28th Nov 2004 : First Version 21 | " * Focalize on :BTW 22 | " 23 | " v0.0.2: Merge two related projects. 24 | " * Integrate the work I've done on the previous C-ftplugin -> 25 | " c_compile.vim 26 | " 27 | " v0.0.3: 28 | " * ?:Make? support an optional list of targets 29 | " * BTW_filter_prog can be local to a buffer 30 | " => regarding to the current directory (thanks to local_vimrc.vim) we 31 | " can use different makefiles, but the same build program. 32 | " The other solution I haven't considered (yet?) was to use callback 33 | " functions. 34 | " * Little bug fix in the ``edit settings'' confirm-box ; some \n were 35 | " badly handled. 36 | " * New commands: :Copen and :Cwindow which work like :copen and :cwindow 37 | " except they show up to BTW_QF_size error lines (default 15), and they 38 | " jump (or not) to the first error according to BTW_GotoError. 39 | " 40 | " v0.0.4: 13th Jan 2005 41 | " * g:BTW_qf_position -> :vert, :lefta, :abo, ... 42 | " * ?:BTW reloadPlugin? -> To ease plugin test & maintenance 43 | " 44 | " v0.0.5: 11th Mar 2005 45 | " * ?:BTW delete? 46 | " * ?:BTW echo? auto completes the values of various internal functions 47 | " ProjectName() TargetRule() Executable() 48 | " 49 | " v0.0.6: 26th May 2005 50 | " * Do not prepend './' to executable path if, under unix, it starts with 51 | " '/' 52 | " 53 | " v0.0.7: 27th May 2005 54 | " * Use :cclose instead of :bw in s:CompileQF() 55 | " * Use :cclose as well in s:Executable(), s:ProjectName() and 56 | " s:TargetRule() 57 | " * No need to quote the arguments to :Make anymore 58 | " * Can run :Make in background, if the option 59 | " [bg]:BTW_make_in_background is set to 1 60 | " Warning: As those damn pop-ups on the Internet, the quickfix window 61 | " can be opened at any time. Which may break our current manipulations. 62 | " * Toggled menu for g:BTW_make_in_background (g(lobal) scope only, not [bg]) 63 | " 64 | " v0.0.8: 30th May 2005 65 | " * new option for errorformat configuration: g:BTW_ignore_efm_{filter} 66 | " * We can ask for using the default value of efm by setting 67 | " g:BTW_adjust_efm_{filter} to "default efm". 68 | " Default efm: -> ?set efm&vim? 69 | " %f(%l) : %t%*\D%n: %m 70 | " %*[^"]"%f"%*\D%l: %m 71 | " %f(%l) : %m 72 | " %*[^ ] %f %l: %m 73 | " %f:%l:%m 74 | " 75 | " v0.0.9: 22nd Jul 2005 76 | " * Run in background works with several filters (output piped), and even 77 | " with filter that expands into "cd path ; make -f file.mk" 78 | " Tested under Solaris. 79 | " * The temporary file can be in any directory. 80 | " 81 | " v0.0.10: 17th Nov 2005 - 06th Nov 2007 82 | " * First support for syntax additions -> [bg]BTW_qf_syntax_{...} 83 | " Will be rewritten ... 84 | " * Better management of efm 85 | " * Simplification: Use of :cgetfile for build in backgound 86 | " * Auto detection of where run_in_background.pl is, without the explicit 87 | " need to searchInRuntime.vim -- as long as Vim supports the function 88 | " |globpath()| 89 | " * auto-import of |compiler-plugin| with just "|BTW-add| ant" for 90 | " instance. 91 | " * A filter can import definitions from a |compiler-plugin|. e.g.: 92 | " let g:BTW_adjust_efm_{filter} = 'import: ant,default efm' 93 | " If the filter does not provide a [bg]:BTW_filter_program_{filter}, 94 | " the one from the compiler plugin will be used. 95 | " * Executable() programs (in $PATH) can be added as filter 96 | " * Adapted to the refactorization of MenuMake 97 | " * run_in_background patched to work under Cygwin -- except perl's fork 98 | " isn't forking 99 | " * b:want_buffermenu_or_global_disable is not used as the menus are not 100 | " limited to the current buffer 101 | " * Dependency changed from LHOption to lh-vim-lib 102 | " v0.0.11: 22nd Oct 2010 103 | " * Can run anything and capture its output 104 | " * Config support let-modeline, ccmake, makefile 105 | " v0.0.12: 21st Mar 2011 106 | " * New option BTW_make_multijobs to run make with multiple jobs (-j2, 107 | " etc) 108 | " v0.0.13: 19th Aug 2011 109 | " * New option BTW_compilation_dir 110 | " * New feature: :QFImport to import variables into quickfix 111 | " v0.0.14: 21st Feb 2012 112 | " * New way to easily change settings in the filters used: 113 | " BTW_filter_program_{filter} can be a |FuncRef|. 114 | " see compiler/BTW/cmake.vim 115 | " * BTW_adjust_efm_{filer} may be a dictionary 116 | " {"value": string, "post": FuncRef} to support post-treatments on &efm 117 | " value. see compiler/BTW/cmake.vim 118 | " v0.1.0: 13th Mar 2012 119 | " * "configure" while the type is "cmake" correctly runs cmake-gui on 120 | " windows boxes 121 | " * :Execute works under windows 122 | " * Try to use lh-compl-hints if installed 123 | " v0.1.1: 08th Jun 2012 124 | " * running "configure" didn't detect non-Windows correctly 125 | " v0.2.0: 06th Sep 2012 126 | " * API to help define project options 127 | " v0.2.1: 12th Sep 2012 128 | " * API to help define CMake/CTest-based project options 129 | " v0.2.2: 18th Sep 2012 130 | " * CTest outputs are fixed so filenames are correctly recognized 131 | " * CTest outputs are folded 132 | " v0.2.3: 21st Sep 2012 133 | " * bug fix: unable to fold CTest tests when test number > 9 134 | " * using "normal V" to create fold has memory side effect 135 | " * clean folds before entering QF windows through make 136 | " v0.2.4: 21st Sep 2012 137 | " * List all (c)tests 138 | " * first draft to execute selected test (buggged at this point) 139 | " v0.2.5: 25th Sep 2012 140 | " * Possible to execute selected (C)test 141 | " * Optional project configuration for btw/project_options 142 | " v0.2.6: 19th Oct 2012 143 | " * Bugfix in #lh#btw#cmake#update_list() 144 | " v0.2.7: 23rd Oct 2012 145 | " * bugfix: Toggle *CtestList* now updates the target test 146 | " v0.2.8: 29th Oct 2012 147 | " * bugfix: updating CTest test lists was made in the wrong menu position 148 | " v0.2.9: 07th Nov 2012 149 | " * bugix: updating CTest test lists was not updating new test id 150 | " v0.2.10: 21st Nov 2012 151 | " * enh: g:BTW_make_multijobs default value is lh#os#cpu_number() 152 | " v0.2.11: 08th Jan 2013 153 | " * enh: Generates .clang_complete file ... but in b:BTW_compilation_dir 154 | " * enh: Generates clang_indexer DB, in b:BTW_compilation_dir 155 | " * bug: Don't prevent syntax highlighting & ft detection to be triggered 156 | " when launching vim with several files 157 | " v0.2.12: 23rd Jan 2013 158 | " * bug: lh#btw#cmake#update_list() won't fail when executed from a 159 | " buffer not under the paths.trunk directory. 160 | " * bug: Generated ctest menu accept test names with non-word "\W" 161 | " characters. 162 | " v0.2.13: 23rd Jan 2013 163 | " * enh: Calling ":cd" before opening the quickfix window in order to 164 | " avoid absolutepaths in the qf window 165 | " v0.2.14: 25th Jul 2013 166 | " * bug: When the project is organized with symbolic links, settings 167 | " weren't applied. e.g. 168 | " $$/ 169 | " +-> repo/branches/B42 170 | " +-> sources/ -> symlink to $$/repo/branches/B42 171 | " +-> build/ 172 | " * enh: The compilation mode doesn't need anymore to be "Debug" or 173 | " "Release", it can be anything now like for instance: "ARM", "80x86", 174 | " ... 175 | " v0.2.15: 19th Dec 2013 176 | " * enh: ctest folding now displays the name of the test as well 177 | " v0.3.0: 14th Mar 2014 178 | " * s:Evaluate() moved to lh/btw.vim autoload plugin 179 | " v0.3.1: 29th Jul 2014 180 | " * ctest filters now use BTW hooks facility 181 | " * BTW hooks can be debuged when lh#btw#filter#verbose >= 2 182 | " v0.3.2: 02nd Sep 2014 183 | " * New option [bg]:BTW_use_prio ("update"|"makeprg") can tells to always 184 | " update makeprg, or never. 185 | " v0.3.3: 12th Dec 2014 186 | " * New API function: lh#btw#compilation_dir() 187 | " v0.3.4: 16th Jan 2015 188 | " * New subcommand to generate local_vimrc files for C&C++ projects and 189 | " projects managed with CMake -> :BTW new_project 190 | " * Minor refactoring in lh#btw#filters functions 191 | " v0.4.0: 20th Mar 2015 192 | " * several functions moved to autoload plugins 193 | " * filter BTW/sustitute_file supports several substitution lists with 194 | " (bg):{ft_}BTW_substitute_names: [ [old1, new1], [old2, new2], ...] 195 | " * filter BTW/shorten_filenames permits to shorten (/conceal part of) 196 | " filenames with 197 | " (bg):{ft_}BTW_shorten_names: [ pattern, [pattern,cchar], ...] 198 | " * New hook group: "syntax" 199 | " * qf_export_variable rewritten => many tests are required 200 | " * "BTW remove" & "BTW removelocal" behaviours slightly changed. 201 | " v0.4.1: 09th Apr 2015 202 | " * QFImport feature reworked: now it has to be executed for each buffer 203 | " (i.e. in a local vimrc) 204 | " * Airline extension defined -> "btw". 205 | " It relies on: 206 | " - b:BTW_project_config['_'].name and 207 | " - b:BTW_project_config['_'].compilation.mode. 208 | " v0.4.2: 10th Apr 2015 209 | " * b:BTW_project_build_mode deprecated in favour of 210 | " b:BTW_project_config['_'].compilation.mode. 211 | " * Current project name can be obtained with: lh#btw#project_name() 212 | " * Current project build mode can be obtained with: lh#btw#build_mode() 213 | " v0.4.3: 13th Apr 2015 214 | " * QFImported variables are correctly associated to the state of the 215 | " buffer where the compilation is launched at the moment it is launched. 216 | " * calls to setqflist() now replace the current qflist (instead of 217 | " appending a new one) 218 | " v0.4.4: 16th Apr 2015 219 | " * Fix default value for lh#btw#project_name() to return an empty string 220 | " * No longer depends on system-tools. 221 | " v0.4.5: 05th May 2015 222 | " * New feature: :ReConfig that'll reload let-modeline, or execute 223 | " "cmake ." in the right path. 224 | " v0.5.0: 09th Jul 2015 225 | " * New feature: :BTW setoption that'll help set BTW options (targets, 226 | " ...) 227 | " v0.5.1: 24th Sep 2015 228 | " * ":Execute" on scripts will correctly work. Requires lh-vim-lib 3.3.3. 229 | " v0.5.2: 22nd Oct 2015 230 | " * Usage message for ":BTW new_project" 231 | " v0.5.3: 30th Oct 2015 232 | " * Updated to new lh-vim-lib functions that create new splits, ignoring E36 233 | " * Bug fix in ':BTW new_project' usage feature 234 | " v0.5.5: 26th Apr 2016 235 | " * On Windows, when `[bg]:BTW_project_executable` is set, ".exe" won't 236 | " be appended automatically 237 | " v0.5.5: 03rd May 2016 238 | " * Fix "No maping found" on plain vim (!= gvim) 239 | " v0.6.0: 20th Jun 2016 240 | " * Fix incorrect mapping definition 241 | " v0.7.0: 11th Aug 2016 - 11th Oct 2016 242 | " * Add toggle menu/command from autoscroll bg compilation 243 | " * Use new logging framework in some places 244 | " * Background compilation based on lh#async 245 | " * Take p:$ENV into account to compile programs 246 | " 247 | " TODO: {{{2 248 | " * &magic 249 | " * Support priority -> ?:BTW add cygwin 9? 250 | " * Write doc 251 | " * ? addlocal when there is already something ? 252 | " - or, xor, 253 | " - use local only ? 254 | " * Folding -> tools names (ld, gcc, g++) + other tools 255 | " 1st lvl: directories 256 | " 2nd lvl: tools <--- use special colors for tools 257 | " 3rd lvl: files 258 | " * Test if the definition abort (reconstruct). If so, revert to the 259 | " preceding values of the variables. (-> try-finally ?) 260 | " * Some way to use the efm values from another filter (we may consider 261 | " that loading the filter is enough), or directly set: 262 | " let g:BTW_adjust_efm_foo = g:BTW_adjust_efm_bar 263 | " * if '$*' is already present in the filter_program, then don't append 264 | " it. 265 | " * Is there a real need for ?:LMake?, ?:LOpen? ? I'm not sure that 266 | " commands like :lmake (et al.) are that useful as long as there is no 267 | " way to say that a particular |location-list| is shared between 268 | " several windows from a same project. 269 | " * executable() filters should be able to accept arguments 270 | " * Chain successful compilation with program execution 271 | " }}}1 272 | "============================================================================= 273 | 274 | 275 | "============================================================================= 276 | " Avoid global reinclusion {{{1 277 | let s:cpo_save=&cpo 278 | set cpo&vim 279 | 280 | if exists("g:loaded_BuildToolsWrapper") 281 | if !exists('g:force_reload_BuildToolsWrapper') 282 | let &cpo=s:cpo_save 283 | finish 284 | else 285 | echomsg "Reloading ".expand('') 286 | endif 287 | endif 288 | let g:loaded_BuildToolsWrapper = s:k_version 289 | 290 | " Dependencies {{{1 291 | runtime plugin/compil-hints.vim 292 | 293 | " Global options {{{1 294 | let s:key_make = lh#option#get('BTW.key.make' , '', 'g') 295 | let s:key_execute = lh#option#get('BTW.key.execute' , '', 'g') 296 | let s:key_config = lh#option#get('BTW.key.config' , '', 'g') 297 | let s:key_re_config = lh#option#get('BTW.key.re_config', '', 'g') 298 | 299 | " Options }}}1 300 | "------------------------------------------------------------------------ 301 | " ## Commands and mappings {{{1 302 | 303 | " # Multi-purposes command {{{2 304 | command! -nargs=+ -complete=custom,lh#btw#chain#_BTW_complete BTW :call lh#btw#chain#_BTW() 305 | 306 | " # Quickfix import variables commands {{{2 307 | command! -nargs=1 -complete=var QFImport :call lh#btw#qf_add_var_to_import() 308 | command! -nargs=0 QFClearImport :call lh#btw#qf_clear_import() 309 | 310 | " # Build/Make invokation {{{2 311 | command! -nargs=* Make :call lh#btw#build#_compile("") 312 | command! -nargs=0 Execute :call lh#btw#build#_execute() 313 | command! -nargs=0 AddLetModeline :call lh#btw#build#_add_let_modeline() 314 | command! -nargs=0 Config :call lh#btw#build#_config() 315 | command! -nargs=0 ReConfig :call lh#btw#build#_re_config() 316 | command! -nargs=0 Copen :call lh#btw#build#_show_error('copen') 317 | command! -nargs=0 Cwindow :call lh#btw#build#_show_error('cwindow') 318 | command! -nargs=+ CopenBG :call lh#btw#build#_copen_bg() 319 | command! -nargs=0 ToggleMakeMJ :call s:ToggleMakeMJ() 320 | command! -nargs=0 ToggleMakeBG :call s:ToggleMakeInBG() 321 | 322 | let s:has_jobs = exists('*job_start') && has("patch-7.4.1980") 323 | if s:has_jobs 324 | if exists(':cbottom') 325 | command! -nargs=0 ToggleAutoScrollBG :call s:ToggleAutoScrollInBG() 326 | endif 327 | endif 328 | 329 | " # Menus {{{2 330 | 331 | function! s:MenuMakeBG() 332 | if has('gui_running') && has ('menu') 333 | let value = lh#btw#option#_make_in_bg() 334 | amenu 50.99 &Project.------ Nop 335 | let C = value ? 'X' : "\\ " 336 | let UC = value ? "\\ " : 'X' 337 | silent! exe "anoremenu 50.100 &Project.&[" . C . escape("] Make in &background", '\ ') . " :ToggleMakeBG" 338 | silent! exe "aunmenu Project.[" . UC . escape ("] Make in background", ' ') 339 | endif 340 | endfunction 341 | 342 | function! s:MenuAutoScrollBG() 343 | if has('gui_running') && has ('menu') 344 | let value = lh#btw#option#_auto_scroll_in_bg() 345 | amenu 50.99 &Project.------ Nop 346 | let C = value ? 'X' : "\\ " 347 | let UC = value ? "\\ " : 'X' 348 | silent! exe "anoremenu 50.100 &Project.&[" . C . escape("] AutoScroll in &background", '\ ') . " :ToggleAutoScrollBG" 349 | silent! exe "aunmenu Project.[" . UC . escape ("] AutoScroll in background", ' ') 350 | endif 351 | endfunction 352 | 353 | function! s:MenuMakeMJ() 354 | if has('gui_running') && has ('menu') 355 | let value = lh#btw#option#_make_mj() 356 | " if type(value) != type(0) 357 | " endif 358 | if exists('s:old_mj') 359 | silent! exe "aunmenu Project.[" . s:old_mj . escape ("] Make using multiple jobs", ' ') 360 | endif 361 | amenu 50.99 &Project.------ Nop 362 | silent! exe "anoremenu 50.101 &Project.[" . value . escape("] Make using multiple &jobs", '\ ') . " :ToggleMakeMJ" 363 | let s:old_mj = value 364 | endif 365 | endfunction 366 | 367 | if has('gui_running') && has ('menu') 368 | \ && 0!=strlen(globpath(&rtp, 'autoload/lh/menu.vim')) 369 | " let b:want_buffermenu_or_global_disable = 0 370 | " 0->no ; 1->yes ; 2->global disable 371 | call lh#menu#make('n', '50.10', '&Project.&ReConfig', s:key_re_config, 372 | \ '', ':ReConfig') 373 | call lh#menu#make('n', '50.15', '&Project.&Config', s:key_config, 374 | \ '', ':Config') 375 | amenu 50.29 &Project.---- Nop 376 | call lh#menu#make('ni', '50.30', '&Project.&Make project', s:key_make, 377 | \ '', ':Make') 378 | call lh#menu#make('ni', '50.50', '&Project.&Execute', s:key_execute, 379 | \ '', ':Execute') 380 | 381 | call s:MenuMakeBG() 382 | call s:MenuMakeMJ() 383 | else 384 | exe ' nnoremap '.s:key_make .' :call lh#btw#build#_compile()' 385 | exe ' inoremap '.s:key_make .' :call lh#btw#build#_compile()' 386 | 387 | exe ' nnoremap '.s:key_execute .' :call lh#btw#build#_execute()' 388 | exe ' inoremap '.s:key_execute .' :call lh#btw#build#_execute()' 389 | 390 | exe ' nnoremap '.s:key_re_config .' :ReConfig' 391 | exe ' nnoremap '.s:key_config .' :Config' 392 | endif 393 | " ## Commands and mappings }}}1 394 | "------------------------------------------------------------------------ 395 | " ## Internals {{{1 396 | 397 | " # Menus (options) {{{2 398 | " Function: s:ToggleMakeInBG() {{{3 399 | function! s:ToggleMakeInBG() abort 400 | let value = lh#btw#option#_make_in_bg() 401 | let g:BTW.make_in_background = 1 - value 402 | call lh#common#warning_msg ("Compilation configured to run in " 403 | \ . (value ? "foreground" : "background")) 404 | 405 | call s:MenuMakeBG() 406 | endfunction 407 | 408 | " Function: s:ToggleAutoScrollInBG() {{{3 409 | function! s:ToggleAutoScrollInBG() abort 410 | let value = lh#btw#option#_auto_scroll_in_bg() 411 | let g:BTW.autoscroll_background_compilation = 1 - value 412 | call lh#common#warning_msg ("Autoscrolling in qf window when compiling in background has been " 413 | \ . (value ? "deactivated" : "activated")) 414 | 415 | call s:MenuAutoScrollBG() 416 | endfunction 417 | 418 | " Function: s:ToggleMakeMJ() {{{3 419 | let s:k_cpu_number = lh#os#cpu_number() 420 | function! s:ToggleMakeMJ() abort 421 | let value = lh#btw#option#_make_mj() 422 | let g:BTW.make_multijobs = (value==0) ? s:k_cpu_number : 0 423 | call lh#common#warning_msg("Compling on " . 424 | \ ((g:BTW.make_multijobs>1) ? (g:BTW.make_multijobs . " cpus") : "1 cpu")) 425 | 426 | call s:MenuMakeMJ() 427 | endfunction 428 | 429 | " ## Internals }}}1 430 | "------------------------------------------------------------------------ 431 | let &cpo=s:cpo_save 432 | "============================================================================= 433 | " vim600: set fdm=marker: 434 | -------------------------------------------------------------------------------- /autoload/lh/btw/cmake.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: autoload/lh/btw/cmake.vim {{{1 3 | " Author: Luc Hermitte 4 | " 5 | " Version: 0.7.0 6 | let s:k_version = 0700 7 | " Created: 12th Sep 2012 8 | " Last Update: 14th Oct 2016 9 | "------------------------------------------------------------------------ 10 | " Description: 11 | " Simplifies the defintion of CMake based projects 12 | " Example: 13 | " let s:menu_priority = '50.120.' 14 | " let s:menu_name = '&Project.&FooBar.' 15 | " 16 | " let g:foorbar_config_menu = { 17 | " \ '_project': 'project_config', 18 | " \ 'menu': {'priority': s:menu_priority, 'name': s:menu_name} 19 | " \ } 20 | " call lh#btw#cmake#def_options(g:sea_config_menu, [ 21 | " \ 'def_toggable_compil_mode', 22 | " \ 'def_toggable_ctest_verbosity', 23 | " \ 'def_ctest_targets']) 24 | " And then, through the menu (gvim), or: 25 | " - :Toggle ProjectFooBarMode 26 | " - :Toggle ProjectCTestVerbosity 27 | " - :Set ProjectCTestTargetTests {regex} 28 | " we can change the compilation mode (used by :Make/), of the arguments to 29 | " ctest () 30 | " 31 | "------------------------------------------------------------------------ 32 | " Installation: 33 | " Requires Vim7+, lh-vim-lib 4.0.0 34 | " TODO: 35 | " * Simplify the definition of the "_project" sub-dictionary as it 36 | " requires many options. 37 | " * For multiple tests, we need to use -I and not -R 38 | " * Get rid of b:BTW_compilation_dir and rely only on 39 | " b:BTW_project_config._ 40 | " }}}1 41 | "============================================================================= 42 | 43 | let s:cpo_save=&cpo 44 | set cpo&vim 45 | "------------------------------------------------------------------------ 46 | " ## Misc Functions {{{1 47 | " # Version {{{2 48 | function! lh#btw#cmake#version() 49 | return s:k_version 50 | endfunction 51 | 52 | " # Debug {{{2 53 | let s:verbose = get(s:, 'verbose', 0) 54 | function! lh#btw#cmake#verbose(...) 55 | if a:0 > 0 | let s:verbose = a:1 | endif 56 | return s:verbose 57 | endfunction 58 | 59 | function! s:Log(expr, ...) 60 | call call('lh#log#this',[a:expr]+a:000) 61 | endfunction 62 | 63 | function! s:Verbose(expr, ...) 64 | if s:verbose 65 | call call('s:Log',[a:expr]+a:000) 66 | endif 67 | endfunction 68 | 69 | function! lh#btw#cmake#debug(expr) abort 70 | return eval(a:expr) 71 | endfunction 72 | 73 | 74 | "------------------------------------------------------------------------ 75 | " ## Exported functions {{{1 76 | " Function: lh#btw#cmake#def_options(config, options) {{{2 77 | " {config} shall contain: 78 | " - menu.priority and menu.name 79 | " - _project settings 80 | " - paths 81 | " - trunk // It's important to tune this variable to distinguish between subprojects 82 | " - project // Root path of the project 83 | " - doxyfile 84 | " - sources // This matches all the trunk => complete even with test files 85 | " - build_root_dir // Points to the root (/list of root) directory(/ies) 86 | " // where build directories are stored. Meant to be used with `auto_detect_compil_modes`. 87 | " - _build // Internal, points to the compilation dir used 88 | " // to set b:BTW_compilation_dir 89 | " - _clic // Subpath where clang indexer DB is stored from _build 90 | " // defaults to ".clic/index.bd" 91 | " - clic() // Returns _build + _clic (by default) 92 | " - build 93 | " - Debug 94 | " - Release 95 | " - compilation (optional) 96 | " - mode 'Debug' from ['Debug', 'Release'] " matches the subdirs from build/ 97 | " - tests (all optional) 98 | " - verbosity '' from ['', '-V', '-VV'] 99 | " - checking_memory 'no' from ['no', 'yes'] 100 | " - test_regex '' 101 | " - active_list [] 102 | " {options} is the list of lh#btw#cmake functions to call 103 | if !exists('s:config') 104 | let s:config = {} 105 | endif 106 | function! lh#btw#cmake#def_options(config, options) abort 107 | let s:config[a:config._project] = a:config " in case it is required to access other config stuff 108 | " Set default values 109 | call lh#let#if_undef('g:'.a:config._project.'.compilation.mode', 'Release') 110 | call lh#let#if_undef('g:'.a:config._project.'.paths._clic', '.clic/index.db') 111 | call lh#let#if_undef('g:'.a:config._project.'.paths.clic', function(s:getSNR('GetClic'))) 112 | call lh#let#if_undef('g:'.a:config._project.'.tests.verbosity', '') 113 | call lh#let#if_undef('g:'.a:config._project.'.tests.checking_memory', 'no') 114 | call lh#let#if_undef('g:'.a:config._project.'.tests.test_regex', '') 115 | call lh#let#if_undef('g:'.a:config._project.'.tests.active_list', []) 116 | 117 | " Add all selected options to menu 118 | for option in a:options 119 | " deepcopy of menu, shallow copy of _project 120 | let menu_def = { 121 | \ 'menu': copy(a:config.menu), 122 | \ '_project': a:config._project 123 | \ } 124 | " save the menu in order to make hooks and other stuff accessible 125 | if has_key(a:config, option) 126 | let a:config[option].menu = menu_def.menu 127 | let a:config[option]._project = menu_def._project 128 | let menu_def = a:config[option] 129 | else 130 | let a:config[option] = menu_def 131 | endif 132 | 133 | " execute the action to initialize everything 134 | call lh#btw#cmake#{option}(menu_def) 135 | endfor 136 | endfunction 137 | 138 | " Function: lh#btw#cmake#auto_detect_compil_modes(menu_def) {{{2 139 | " This function will automaticall fill _config.build dict, AND execute 140 | " def_toggable_compil_mode 141 | function! lh#btw#cmake#auto_detect_compil_modes(menu_def) abort 142 | let a:menu_def.project = function(s:getSNR('project')) 143 | " It may be a list of directories actually... 144 | " but relative to `project` 145 | let build_root = get(a:menu_def.project().paths, 'build_root_dir', lh#option#unset()) 146 | if lh#option#is_unset(build_root) 147 | throw "Please set `g:".a:menu_def._project.".path.build_root_dir` in order to autodetect compilation modes" 148 | endif 149 | let project_root = a:menu_def.project().paths.project 150 | 151 | let subs = lh#path#glob_as_list(project_root.'/'.build_root, '*') 152 | call filter(subs, 'isdirectory(v:val)') 153 | if empty(subs) 154 | throw "No subdirectories found in `".build_root."`: cannot deduce compilations modes" 155 | endif 156 | 157 | " Check directories without Makefiles 158 | let without_makefile = filter(copy(subs), '! filereadable(v:val."/Makefile")') 159 | " Check directories without CMakeLists 160 | let without_cmakecache = filter(copy(subs), '! filereadable(v:val."/CMakeCache.txt")') 161 | 162 | let msg = '' 163 | if !empty(without_makefile) 164 | let msg .= "\nThe following build directories have no Makefile: ".join(without_makefile, ', ') 165 | endif 166 | if !empty(without_cmakecache) 167 | let msg .= "\nThe following build directories have no CMakeCache.txt file ".join(without_cmakecache, ', ') 168 | endif 169 | if !empty(msg) 170 | let msg = "Warning:" . msg 171 | call lh#common#echomsg_multilines(msg) 172 | endif 173 | 174 | for sub in subs 175 | call lh#let#if_undef('g:'.a:menu_def._project.'.build.'.fnamemodify(sub, ':t'), lh#path#strip_start(sub, project_root)) 176 | endfor 177 | 178 | " And finally, prepare everything 179 | call lh#btw#cmake#def_toggable_compil_mode(a:menu_def) 180 | endfunction 181 | 182 | " Function: lh#btw#cmake#def_toggable_compil_mode(menu_def) {{{2 183 | " {menu_def} shall contain: 184 | " - menu.priority and menu.name 185 | " - _project settings 186 | function! lh#btw#cmake#def_toggable_compil_mode(menu_def) abort 187 | function! a:menu_def.project() dict abort " dereference _project 188 | return eval('g:'.self._project) 189 | endfunction 190 | " Automatically set variables for lh#btw#project_options#add_toggle_option, 191 | " and lh#menu#def_toggle_item 192 | let a:menu_def.values = keys(a:menu_def.project().build) 193 | " "variable" is a variable name, hence _project being a string 194 | let a:menu_def.variable = a:menu_def._project.'.compilation.mode' 195 | let a:menu_def._root = a:menu_def.project().paths.trunk 196 | let a:menu_def.menu.priority .= '20' 197 | let a:menu_def.menu.name .= 'M&ode' 198 | " Default (polymorphic) functions for determining the current project 199 | " executable, and the current compilation directory 200 | if !has_key(a:menu_def, 'set_project_executable') 201 | let a:menu_def.set_project_executable = function(s:getSNR('SetProjectExecutable')) 202 | endif 203 | if !has_key(a:menu_def, 'update_compil_dir') 204 | let a:menu_def.update_compil_dir = function(s:getSNR('UpdateCompilDir')) 205 | endif 206 | function! a:menu_def.do_update() dict abort 207 | " let b:BTW_project_build_mode = self.eval() 208 | call self.update_compil_dir() 209 | BTW rebuild 210 | call self.set_project_executable() 211 | endfunction 212 | call lh#btw#project_options#add_toggle_option(a:menu_def) 213 | endfunction 214 | 215 | " Function: lh#btw#cmake#def_toggable_ctest_verbosity(menu_def) {{{2 216 | " {menu_def} shall contain: 217 | " - menu.priority and menu.name 218 | " - _project settings 219 | function! lh#btw#cmake#def_toggable_ctest_verbosity(menu_def) abort 220 | function! a:menu_def.project() dict abort " dereference _project 221 | return eval('g:'.self._project) 222 | endfunction 223 | " Automatically set variables for lh#btw#project_options#add_toggle_option, 224 | " and lh#menu#def_toggle_item 225 | let a:menu_def.values = ['', '-V', '-VV'] 226 | " "variable" is a variable name, hence _project being a string 227 | let a:menu_def.variable = a:menu_def._project.'.tests.verbosity' 228 | let actual_variable_name = (a:menu_def.variable[0]=='$' ? '' : 'g:') . a:menu_def.variable 229 | if !exists(actual_variable_name) 230 | let a:menu_def.idx_crt_value = 0 231 | endif 232 | let a:menu_def._root = a:menu_def.project().paths.trunk 233 | let a:menu_def.menu.priority .= '30.10' 234 | let a:menu_def.menu.name .= 'C&Test.&Verbosity' 235 | " Default (polymorphic) functions for determining the current project 236 | " executable, and the current compilation directory 237 | if !has_key(a:menu_def, 'set_ctest_argument') 238 | let a:menu_def.set_ctest_argument = function(s:getSNR('SetCTestArgument')) 239 | endif 240 | function! a:menu_def.do_update() dict abort 241 | call self.set_ctest_argument() 242 | endfunction 243 | call lh#btw#project_options#add_toggle_option(a:menu_def) 244 | endfunction 245 | 246 | " Function: lh#btw#cmake#def_ctest_targets(menu_def) {{{2 247 | " {menu_def} shall contain: 248 | " - menu.priority and menu.name 249 | " - _project settings 250 | function! lh#btw#cmake#def_ctest_targets(menu_def) abort 251 | function! a:menu_def.project() dict abort " dereference _project 252 | return eval('g:'.self._project) 253 | endfunction 254 | " Automatically set variables for lh#btw#project_options#add_toggle_option, 255 | " and lh#menu#def_toggle_item 256 | let a:menu_def.values = '' 257 | " "variable" is a variable name, hence _project being a string 258 | let a:menu_def.variable = a:menu_def._project.'.tests.test_regex' 259 | let a:menu_def._root = a:menu_def.project().paths.trunk 260 | let a:menu_def.menu.priority .= '30.20' 261 | let a:menu_def.menu.name .= 'C&Test.&Target Test(s)' 262 | " Default (polymorphic) functions for determining the current project 263 | " executable, and the current compilation directory 264 | if !has_key(a:menu_def, 'set_ctest_argument') 265 | let a:menu_def.set_ctest_argument = function(s:getSNR('SetCTestArgument')) 266 | endif 267 | function! a:menu_def.do_update() dict abort 268 | call self.set_ctest_argument() 269 | endfunction 270 | call lh#btw#project_options#add_string_option(a:menu_def) 271 | endfunction 272 | 273 | " Function: lh#btw#cmake#def_toggable_ctest_checkmem(menu_def) {{{2 274 | " {menu_def} shall contain: 275 | " - menu.priority and menu.name 276 | " - _project settings 277 | function! lh#btw#cmake#def_toggable_ctest_checkmem(menu_def) abort 278 | function! a:menu_def.project() dict abort " dereference _project 279 | return eval('g:'.self._project) 280 | endfunction 281 | " Automatically set variables for lh#btw#project_options#add_toggle_option, 282 | " and lh#menu#def_toggle_item 283 | let a:menu_def.idx_crt_value = 0 284 | let a:menu_def.values = ['no', 'yes'] 285 | " "variable" is a variable name, hence _project being a string 286 | let a:menu_def.variable = a:menu_def._project.'.tests.checking_memory' 287 | let a:menu_def._root = a:menu_def.project().paths.trunk 288 | let a:menu_def.menu.priority .= '30.30' 289 | let a:menu_def.menu.name .= 'C&Test.Check &Memory' 290 | " Default (polymorphic) functions for determining the current project 291 | " executable, and the current compilation directory 292 | if !has_key(a:menu_def, 'set_ctest_argument') 293 | let a:menu_def.set_ctest_argument = function(s:getSNR('SetCTestArgument')) 294 | endif 295 | function! a:menu_def.do_update() dict abort 296 | call self.set_ctest_argument() 297 | endfunction 298 | call lh#btw#project_options#add_toggle_option(a:menu_def) 299 | endfunction 300 | 301 | " Function: lh#btw#cmake#update_list(menu_def) {{{2 302 | function! lh#btw#cmake#update_list(menu_def) abort 303 | if type(a:menu_def) == type({}) 304 | let proj_id = a:menu_def._project 305 | function! a:menu_def.project() dict " dereference _project 306 | return eval('g:'.self._project) 307 | endfunction 308 | else 309 | let proj_id = a:menu_def 310 | endif 311 | let p = expand('%:p') 312 | " a:menu_def.project().paths.trunk 313 | if empty(p) || lh#path#is_in(p, a:menu_def.project().paths.trunk) != 0 314 | return 315 | endif 316 | 317 | let menu_def = s:config[proj_id].update_list 318 | let tests = lh#os#system('cd '.lh#btw#option#_compilation_dir(). ' && ctest -N') 319 | if type(a:menu_def) == type({}) 320 | " let's say that the first call is an initialization with a dictionary, and 321 | " that the following calls are made with a string naming the 322 | " menu_definition to use. 323 | let menu_def.menu.priority .= '30.900' 324 | let menu_def.menu.name .= 'C&Test.&List' 325 | endif 326 | silent! exe 'aunmenu! '. menu_def.menu.name 327 | exe "amenu ".(menu_def.menu.priority).'.89 '.(menu_def.menu.name).'.-- Nop ' 328 | exe "amenu ".(menu_def.menu.priority).'.90 '.(menu_def.menu.name).'.&Update' 329 | \ .' :call lh#btw#cmake#update_list('.string(menu_def._project).')' 330 | 331 | let l_tests = split(tests, "\n") 332 | call filter(l_tests, "v:val =~ 'Test\\s\\+#'") 333 | call map(l_tests, 'substitute(v:val, "^\\s*Test\\s\\+#\\d\\+:\\s\\+", "", "")') 334 | let i = 1 335 | for test in l_tests 336 | let menu = { 337 | \ '_project': (menu_def._project), 338 | \ 'project' : (menu_def.project), 339 | \ 'menu' : { 340 | \ 'priority': (menu_def.menu.priority).'.'.i, 341 | \ 'name' : (menu_def.menu.name).'.'.test} 342 | \ } 343 | " function! menu.project() dict " dereference _project 344 | " return eval('g:'.self._project) 345 | " endfunction 346 | let menu.idx_crt_value = 0 347 | let menu.values = [0, 1] 348 | let menu.texts = [' ', 'X'] 349 | " Initialize to: not active, by default 350 | let testvar = substitute(test, '\W', '_', 'g') 351 | call lh#let#if_undef('g:'.menu_def._project.'.tests.list.'.testvar, 0) 352 | let menu.variable = menu_def._project.'.tests.list.'.testvar 353 | let menu._root = menu_def.project().paths.trunk 354 | let menu._testname = test 355 | let menu._testnr = i 356 | let menu.set_ctest_argument = function(s:getSNR('SetCTestArgument')) 357 | function! menu.do_update() dict 358 | " This part affects a global setting 359 | let l_tests = self.project().tests.active_list 360 | let updated = 0 361 | if self.val_id() 362 | " add test name 363 | if match(l_tests, self._testnr) < 0 364 | let updated = 1 365 | let l_tests += [self._testnr] 366 | endif 367 | else 368 | " remove test name 369 | let idx = match(l_tests, self._testnr) 370 | if idx >= 0 371 | let updated = 1 372 | call remove(l_tests, idx) 373 | endif 374 | endif 375 | if updated 376 | let project = self.project() 377 | let g:self = self 378 | let project.tests.active_list = l_tests 379 | endif 380 | " This part affects a buffer-local setting => always update 381 | if s:verbose 382 | debug call self.set_ctest_argument() 383 | else 384 | call self.set_ctest_argument() 385 | endif 386 | endfunction 387 | let menu = lh#btw#project_options#add_toggle_option(menu) 388 | " not all keys are updated => force the new _testnr value 389 | let menu._root = menu_def.project().paths.trunk 390 | let menu._testname = test 391 | let menu._testnr = i 392 | 393 | let i+=1 394 | endfor 395 | call lh#common#warning_msg('List of (C)Tests updated: '.len(l_tests).' tests have been found.') 396 | endfunction 397 | 398 | " Function: lh#btw#cmake#add_gen_clic_DB(menu_def) {{{2 399 | " {menu_def} shall contain: 400 | " - menu.priority and menu.name 401 | " - _project settings 402 | function! lh#btw#cmake#add_gen_clic_DB(menu_def) 403 | " let a:menu_def.menu.priority .= '90' 404 | " let a:menu_def.menu.name .= '&Update\ Clang\ Complete\ compilation\ settings' 405 | " silent! exe 'aunmenu! '. a:menu_def.menu.name 406 | " exe "amenu ".(a:menu_def.menu.priority).'.89 '.(a:menu_def.menu.name).'.-- Nop ' 407 | call lh#menu#make('nic', 408 | \ a:menu_def.menu.priority.'90', a:menu_def.menu.name.'Update Clang &Complete compilation settings', 409 | \ 'tc', '', ':call lh#btw#cmake#_gen_clang_complete()' ) 410 | call lh#menu#make('nic', 411 | \ a:menu_def.menu.priority.'91', a:menu_def.menu.name.'Update Code &Index Base', 412 | \ 'ti', '', ':call clang#update_clic('.string(a:menu_def._project).')' ) 413 | endfunction 414 | 415 | " ## Internal functions {{{1 416 | " # s:getSNR() {{{2 417 | function! s:getSNR(...) 418 | if !exists("s:SNR") 419 | let s:SNR=matchstr(expand(''), '\d\+_\zegetSNR$') 420 | endif 421 | return s:SNR . (a:0>0 ? (a:1) : '') 422 | endfunction 423 | 424 | " # s:project() {{{2 425 | function! s:project() dict abort " dereference _project 426 | return eval('g:'.self._project) 427 | endfunction 428 | 429 | " # s:UpdateCompilDir() dict {{{2 430 | function! s:UpdateCompilDir() dict 431 | " "let self.project().paths = value" is refused by viml interpreter => hence 432 | " the auxiliary reference 433 | let paths = self.project().paths 434 | let paths._build = paths.project.'/'.self.project().build[self.project().compilation.mode] 435 | call lh#let#to('P:BTW.compilation_dir', paths._build) 436 | " echoerr "Compiling ".expand('%')." in ".lh#btw#option#_compilation_dir() 437 | if has_key(self, '_update_compil_dir_hook') 438 | " Can be used to update things like LD_LIBRARY_PATH, ... 439 | call self._update_compil_dir_hook() 440 | endif 441 | endfunction 442 | 443 | " # s:GetClic() dict {{{2 444 | function! s:GetClic() dict 445 | return self._build . '/' . self._clic 446 | endfunction 447 | 448 | " # s:SetProjectExecutable() dict {{{2 449 | function! s:SetProjectExecutable() dict 450 | endfunction 451 | 452 | " # s:IndicesListToCTestIArgument() dict {{{2 453 | function! s:IndicesListToCTestIArgument(list) 454 | " Converts the list of tests to run to a list that CTest will 455 | " understand 456 | " -> first test repeated, coma, then list of remaining tests 457 | let list = sort(a:list) 458 | let res = ' -I '.list[0].','.list[0] 459 | let remaining_tests = list[1:] 460 | if !empty(remaining_tests) 461 | let res .= ',,'.join(remaining_tests, ',') 462 | endif 463 | return res 464 | endfunction 465 | 466 | function! s:SetCTestArgument() dict 467 | " -R have precedence over arguments to -I ; like with ctest 468 | LetIfUndef P:BTW.executable.type 'ctest' 469 | let test_regex = self.project().tests.test_regex 470 | let which = self.project().tests.active_list 471 | let checkmem = self.project().tests.checking_memory 472 | " call confirm('regex type: '.type(test_regex) . "\nwhich type: ".type(which), '&Ok', 1) 473 | let rule = self.project().tests.verbosity 474 | \ . (checkmem=='yes' ? (' -D ExperimentalMemCheck') : ('')) 475 | let rule 476 | \ .= (! empty(test_regex)) ? (' -R '.test_regex) 477 | \ : (! empty(which)) ? s:IndicesListToCTestIArgument(which) 478 | \ : '' 479 | call lh#let#to('P:BTW.executable.rule', rule) 480 | call s:Verbose('%1: P:BTW.project_executable.rule <- %2', expand('%'), rule) 481 | endfunction 482 | 483 | " Function: lh#btw#cmake#_gen_clang_complete() {{{2 484 | function! lh#btw#cmake#_gen_clang_complete() 485 | let cmd = 'cd '.lh#btw#option#_compilation_dir(). ' && cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .' 486 | let res = lh#os#system(cmd) 487 | if v:shell_error != 0 488 | call lh#common#error_msg("Cannot execute ``".cmd."'': ".res) 489 | return 490 | endif 491 | let filename = lh#btw#option#_compilation_dir().'/compile_commands.json' 492 | if !file_readable(filename) 493 | call lh#common#error_msg(filename ." hasn't been generated by ``".cmd."''") 494 | return 495 | endif 496 | let json = join(readfile(filename), "") 497 | let data = json_encoding#Decode(json) " from vim-addon-json-encoding 498 | let merged_options = {} 499 | for file in data 500 | let options = '' 501 | let file_options = split(file.command) 502 | let use_next = 0 503 | for option in file_options 504 | if use_next 505 | let options .= option.' ' 506 | let use_next = 0 507 | elseif option =~ '^-[DI]\|^-std\|-no' " first draft 508 | let options .= option.' ' 509 | elseif option =~ '^-i' 510 | let options .= option.' ' 511 | let use_next = 1 512 | endif 513 | endfor 514 | for option in split(options, '\s\+\zs\ze-') 515 | if !empty(option) 516 | let merged_options[option] = '1' 517 | endif 518 | endfor 519 | endfor 520 | let clang_complete_path = lh#btw#option#_compilation_dir().'/.clang_complete' 521 | if filewritable( clang_complete_path) 522 | call writefile(keys(merged_options), clang_complete_path) 523 | call lh#common#warning_msg(lh#btw#option#_compilation_dir().'/.clang_complete updated.') 524 | else 525 | call lh#common#error_msg("[BTW] Cannot write to ". clang_complete_path) 526 | endif 527 | endfunction 528 | 529 | "------------------------------------------------------------------------ 530 | " }}}1 531 | "------------------------------------------------------------------------ 532 | let &cpo=s:cpo_save 533 | "============================================================================= 534 | " vim600: set fdm=marker: 535 | --------------------------------------------------------------------------------