diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..563dea8 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,58 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. +# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake +# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby + +name: CI + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +permissions: + contents: read + +jobs: + test: + name: "test on ${{ matrix.os }} ; ${{ matrix.neovim && 'neovim' || 'vim' }}" + + strategy: + matrix: + # Testing doesn't seem to work on Windows: output log file + # cannot be read... + # os: [ubuntu-latest, macos-latest, windows-latest] + os: [ubuntu-latest, macos-latest] + neovim: [false, true] + # TODO: Test different flavours of Vim... + + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v4 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.0 + bundler-cache: true # runs 'bundle install' and caches installed gems automatically + - name: Setup Vim + uses: rhysd/action-setup-vim@v1 + # uses: thinca/action-setup-vim@v2 + id: vim + with: + neovim: ${{matrix.neovim }} + configure-args: | + --with-features=huge + + - name: Run tests on Linux + if: runner.os == 'Linux' # headless execution is required on Linux + run: | + bundle list + xvfb-run bundle exec rake ci + - name: Run tests on ${{ matrix.os }} + if: runner.os != 'Linux' + run: | + bundle exec rake ci diff --git a/Flavorfile b/Flavorfile new file mode 100644 index 0000000..790f4ba --- /dev/null +++ b/Flavorfile @@ -0,0 +1,2 @@ +flavor 'LucHermitte/lh-vim-lib', '>= 5.3.3' +flavor 'LucHermitte/lh-tags', '>= 3.0.7' diff --git a/Gemfile b/Gemfile index e6bce45..2a84387 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -gem 'rspec', '~> 3.9.0' -gem 'vimrunner', '~> 0.3.4' +gem 'rspec', '~> 3.13.0' +# gem 'vimrunner', '~> 0.3.5' gem 'rake', '~> 13.0.1' -gem 'vim-flavor', '~> 2.2.2' +gem 'vim-flavor', '~> 4.0.3' diff --git a/README.md b/README.md index b5efb7d..cf75648 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,11 @@ -# lh-dev [![Build Status](https://secure.travis-ci.org/LucHermitte/lh-dev.png?branch=master)](http://travis-ci.org/LucHermitte/lh-dev) [![Project Stats](https://www.openhub.net/p/21020/widgets/project_thin_badge.gif)](https://www.openhub.net/p/21020) +# lh-dev [![Last release][Releases-badge]][Releases-url] [![Build Status][gh-action-badge]][gh-action-result] [![Project Stats][openhub-badge]][openhub-url] + +[Releases-badge]: https://img.shields.io/github/tag/LucHermitte/lh-dev.svg +[Releases-url]: https://github.com/LucHermitte/lh-dev/tags +[gh-action-badge]: ./../../actions/workflows/tests.yml/badge.svg?branch=master "Test" +[gh-action-result]: ./../../actions/workflows/tests.yml?query=branch%3Amaster +[openhub-badge]: https://www.openhub.net/p/21020/widgets/project_thin_badge.gif +[openhub-url]: https://www.openhub.net/p/21020 ## Introduction diff --git a/Rakefile b/Rakefile index c73cab2..747d969 100644 --- a/Rakefile +++ b/Rakefile @@ -15,11 +15,11 @@ end task :test => :spec task :spec do - sh "rspec ~/.vim-flavor/repos/LucHermitte_vim-UT/spec" + sh "bundle exec rspec ~/.vim-flavor/repos/LucHermitte_vim-UT/spec/UT_spec_v2.rb" end task :install do - sh 'cat VimFlavor >> tests/VimFlavor' + sh 'cat Flavorfile >> tests/Flavorfile' sh 'cd tests && bundle exec vim-flavor install' end diff --git a/VimFlavor b/VimFlavor deleted file mode 100644 index 3b46377..0000000 --- a/VimFlavor +++ /dev/null @@ -1,2 +0,0 @@ -flavor 'LucHermitte/lh-vim-lib', '>= 4.6.0' -flavor 'LucHermitte/lh-tags', '>= 3.0.0' diff --git a/autoload/lh/dev/c/function.vim b/autoload/lh/dev/c/function.vim index 768e5ab..5e6fe75 100644 --- a/autoload/lh/dev/c/function.vim +++ b/autoload/lh/dev/c/function.vim @@ -5,7 +5,7 @@ " Version: 2.0.0 let s:k_version = 2000 " Created: 31st May 2010 -" Last Update: 09th Apr 2021 +" Last Update: 23rd Aug 2024 "------------------------------------------------------------------------ " Description: " Overridden functions from lh#dev#function, for C and derived languages @@ -17,6 +17,7 @@ let s:k_version = 2000 " (*) Fix lh#dev#c#function#_build_param_call/decl " (*) Support template types in lh#dev#c#function#_analyse_parameter " when the expected parameter name is known +" (*) Make _analyse_parameter resilient to &isk " 1.6.2 " (*) Fix :GOTOIMPL to support operators like += " 1.5.1 @@ -197,90 +198,99 @@ endfunction " [/] UT " [X] variadic parameter "..." function! lh#dev#c#function#_analyse_parameter(param, ...) abort - if a:0 > 0 && type(a:1) != type({}) - " Old API... - let must_clean_space = a:1 - let expected_param_name = '[^=]{-}' - else - let opts = get(a:, 1, {}) - let must_clean_space = get(opts, 'must_clean_space', 0) - let expected_param_name = get(opts, 'expected_param_name', '[^=]{-}') - endif - let param = a:param - let res = {} + let cleanup = lh#on#exit() + \.restore('&isk') + try + setlocal isk-=< + setlocal isk-=> + setlocal isk-=: + if a:0 > 0 && type(a:1) != type({}) + " Old API... + let must_clean_space = a:1 + let expected_param_name = '[^=]{-}' + else + let opts = get(a:, 1, {}) + let must_clean_space = get(opts, 'must_clean_space', 0) + let expected_param_name = get(opts, 'expected_param_name', '[^=]{-}') + endif + let param = a:param + let res = {} - " Merge spaces - if must_clean_space - let param = substitute(param, '\v\_s+', ' ', 'g') - endif - " variadic ? - if param == '...' - let res.type = 'va_list' - let res.default = '' - let res.name = '...' - return res - endif - " Default Value: after = sign - let match_res = matchlist(param, '\v^\s*(.{-}<'.expected_param_name.'>)\s*\=\s*(.{-})\s*$') - if !empty(match_res) - " Cannot use stridx for types likes `sometype` - " let [all, param, res.default ; rest] = matchlist(param, '\v^\s*([^=]{-})\s*\=\s*(.{-})\s*$') - let [all, param, res.default ; rest] = match_res - else - " trim spaces - let param = matchstr(param, '\v^\s*\zs.{-}\ze\s*$') - let res.default = '' - endif - " Special Case: array - let purge_inner_dimension = 1 - let array = match(param, '\v(\s*\[.*\])+$') - if array != -1 - let array_spec = matchstr(param[array : -1], '\v\s*\zs.*') - let param = param[ : array-1] - else - let array_spec = '' - endif - " Special Case: function pointer - if param =~ '\v(.{-})\s*\(\s*\*(\S{-})\s*\)\s*(\(.*\))' - let [all, ret_type, res.name, func_type; rest] = matchlist(param, '\v(.{-})\s*\(\s*\*(\S{-})\s*\)\s*(\(.*\))') - let res.type = ret_type.' (*)'.func_type - elseif param =~ '\v(.{-})\s*\(\s*\*(\S{-})\s*\)' - " Special Case: array, (*name)[] syntax - let [all, ret_type, res.name; rest] = matchlist(param, '\v(.{-})\s*\(\s*\*(\S{-})\s*\)') - let res.type = ret_type.'(*)' - let purge_inner_dimension = 0 - else - " Name: last part in usual case, or separated with * or & - let res.name = matchstr(param, '\v\S([*& ])+\zs\S+$') - " unless the last part is - " - "int", "float", "char", "short", ... - " - or "something>(::othething)=" - " - or everything - if res.name =~ '\v<(int|char|short|long|float|double)>|\>' - " \ || res.type =~ '\v(::)$' " doesn't exist yet - let res.name = '' + " Merge spaces + if must_clean_space + let param = substitute(param, '\v\_s+', ' ', 'g') endif - " Type: - let res.type = matchstr(param[:strlen(param)-strlen(res.name)-1], '\v.*\S') - if res.type =~ '\v(::)$' " merge back - let res.name = '' - let res.type = param + " variadic ? + if param == '...' + let res.type = 'va_list' + let res.default = '' + let res.name = '...' + return res endif - " Remove spaces around *, & - " TODO: remove space around < and > (in C++11 only?) - if must_clean_space - let res.type = substitute(res.type, '\v\s*([*&]+)\s*', '\1', 'g') + " Default Value: after = sign + let match_res = matchlist(param, '\v^\s*(.*<'.expected_param_name.'>)\s*\=\s*(.{-})\s*$') + if !empty(match_res) + " Cannot use stridx for types likes `sometype` + " let [all, param, res.default ; rest] = matchlist(param, '\v^\s*([^=]{-})\s*\=\s*(.{-})\s*$') + let [all, param, res.default ; rest] = match_res + else + " trim spaces + let param = matchstr(param, '\v^\s*\zs.{-}\ze\s*$') + let res.default = '' + endif + " Special Case: array + let purge_inner_dimension = 1 + let array = match(param, '\v(\s*\[.*\])+$') + if array != -1 + let array_spec = matchstr(param[array : -1], '\v\s*\zs.*') + let param = param[ : array-1] + else + let array_spec = '' + endif + " Special Case: function pointer + if param =~ '\v(.{-})\s*\(\s*\*(\S{-})\s*\)\s*(\(.*\))' + let [all, ret_type, res.name, func_type; rest] = matchlist(param, '\v(.{-})\s*\(\s*\*(\S{-})\s*\)\s*(\(.*\))') + let res.type = ret_type.' (*)'.func_type + elseif param =~ '\v(.{-})\s*\(\s*\*(\S{-})\s*\)' + " Special Case: array, (*name)[] syntax + let [all, ret_type, res.name; rest] = matchlist(param, '\v(.{-})\s*\(\s*\*(\S{-})\s*\)') + let res.type = ret_type.'(*)' + let purge_inner_dimension = 0 + else + " Name: last part in usual case, or separated with * or & + let res.name = matchstr(param, '\v\S([*& ])+\zs\S+$') + " unless the last part is + " - "int", "float", "char", "short", ... + " - or "something>(::othething)=" + " - or everything + if res.name =~ '\v<(int|char|short|long|float|double)>|\>' + " \ || res.type =~ '\v(::)$' " doesn't exist yet + let res.name = '' + endif + " Type: + let res.type = matchstr(param[:strlen(param)-strlen(res.name)-1], '\v.*\S') + if res.type =~ '\v(::)$' " merge back + let res.name = '' + let res.type = param + endif + " Remove spaces around *, & + " TODO: remove space around < and > (in C++11 only?) + if must_clean_space + let res.type = substitute(res.type, '\v\s*([*&]+)\s*', '\1', 'g') + endif endif - endif - if purge_inner_dimension - let array_spec = substitute(array_spec, '\v^\[\zs\d+\ze\]', '', '') - endif - let res.type .= array_spec - " New line before the parameter - let res.nl = match(a:param, "\\v^\\s*[\n\r]") >= 0 - " Result - return res + if purge_inner_dimension + let array_spec = substitute(array_spec, '\v^\[\zs\d+\ze\]', '', '') + endif + let res.type .= array_spec + " New line before the parameter + let res.nl = match(a:param, "\\v^\\s*[\n\r]") >= 0 + " Result + return res + finally + call cleanup.finalize() + endtry endfunction function! lh#dev#c#function#_type(variable_tag) abort "{{{3 diff --git a/autoload/lh/dev/cpp/types.vim b/autoload/lh/dev/cpp/types.vim index a39331c..3fed30f 100644 --- a/autoload/lh/dev/cpp/types.vim +++ b/autoload/lh/dev/cpp/types.vim @@ -7,7 +7,7 @@ " Version: 2.0.0 let s:k_version = '2.0.0' " Created: 10th Feb 2009 -" Last Update: 09th Mar 2021 +" Last Update: 23rd Aug 2024 "------------------------------------------------------------------------ " Description: " Analysis functions for C++ types. @@ -26,6 +26,7 @@ let s:k_version = '2.0.0' " opt: lh#dev#cpp#use_cpp11() " + Fix const related functions to support multi-levels types " (T**) +" + Add resilience to &isk value " v1.5.0: - #_of_var " v1.3.9: - better magic/nomagic neutrality " - snake_case enforced @@ -147,25 +148,34 @@ let s:k_types.= '|' let s:k_types.= '|' function! lh#dev#cpp#types#is_base_type(type, pointerAsWell) abort - call s:Verbose('Check lh#dev#cpp#types#is_base_type(%1)', a:type) - - let expr = s:ExtractPattern( a:type, s:k_scope ) - let expr = s:ExtractPattern( expr, s:k_sign ) - let expr = s:ExtractPattern( expr, s:k_size ) - let expr = s:ExtractPattern( expr, s:k_types ) - let user_base_types = lh#ft#option#get('base_type_pattern', 'cpp') - call s:Verbose('(cpp_)base_type_pattern: %1', user_base_types) - if lh#option#is_set(user_base_types) - let expr = s:ExtractPattern( expr, user_base_types) - endif - if a:pointerAsWell==1 - if match( substitute(expr,'\s*','','g'), '\v(\*|\&)+$' ) != -1 - return 1 + let cleanup = lh#on#exit() + \.restore('&isk') + try + setlocal isk-=< + setlocal isk-=> + setlocal isk-=: + call s:Verbose('Check lh#dev#cpp#types#is_base_type(%1)', a:type) + + let expr = s:ExtractPattern( a:type, s:k_scope ) + let expr = s:ExtractPattern( expr, s:k_sign ) + let expr = s:ExtractPattern( expr, s:k_size ) + let expr = s:ExtractPattern( expr, s:k_types ) + let user_base_types = lh#ft#option#get('base_type_pattern', 'cpp') + call s:Verbose('(cpp_)base_type_pattern: %1', user_base_types) + if lh#option#is_set(user_base_types) + let expr = s:ExtractPattern( expr, user_base_types) endif - endif - call s:Verbose('Expr: %1 => %2base_type', expr, (expr=='' ? '' : 'not a ')) - " return strlen(expr) == 0 - return expr == '' + if a:pointerAsWell==1 + if match( substitute(expr,'\s*','','g'), '\v(\*|\&)+$' ) != -1 + return 1 + endif + endif + call s:Verbose('Expr: %1 => %2base_type', expr, (expr=='' ? '' : 'not a ')) + " return strlen(expr) == 0 + return expr == '' + finally + call cleanup.finalize() + endtry endfunction function! lh#dev#cpp#types#IsBaseType(type, pointerAsWell) abort " Deprecated function @@ -204,9 +214,18 @@ endfunction " Function: lh#dev#cpp#types#is_const(type) : bool {{{3 function! lh#dev#cpp#types#is_const(type) abort - call lh#assert#value(a:type).not().empty() - let parts = s:DecomposeType(a:type) - return parts[-1] =~ '\v' + let cleanup = lh#on#exit() + \.restore('&isk') + try + setlocal isk-=< + setlocal isk-=> + setlocal isk-=: + call lh#assert#value(a:type).not().empty() + let parts = s:DecomposeType(a:type) + return parts[-1] =~ '\v' + finally + call cleanup.finalize() + endtry endfunction " Function: lh#dev#cpp#types#remove_cv(type) : string {{{3 @@ -238,11 +257,20 @@ endfunction " # Pointer related functions {{{2 " Function: lh#dev#cpp#types#is_pointer(type) : bool {{{3 function! lh#dev#cpp#types#is_pointer(type) abort - " Special case: owner - if a:type =~ '\v^\<.*\*\s*\>\s*$' - return 1 - endif - return a:type =~ '\v([*]|(pointer|_ptr|Ptr|||)(\<.*\>)=)\s*$' + let cleanup = lh#on#exit() + \.restore('&isk') + try + setlocal isk-=< + setlocal isk-=> + setlocal isk-=: + " Special case: owner + if a:type =~ '\v^\<.*\*\s*\>\s*$' + return 1 + endif + return a:type =~ '\v([*]|(pointer|_ptr|Ptr|||)(\<.*\>)=)\s*$' + finally + call cleanup.finalize() + endtry endfunction function! lh#dev#cpp#types#IsPointer(type) abort @@ -252,33 +280,60 @@ endfunction " Function: lh#dev#cpp#types#is_view(type) : bool {{{3 " string_view, span, ... function! lh#dev#cpp#types#is_view(type) abort + let cleanup = lh#on#exit() + \.restore('&isk') + try + setlocal isk-=< + setlocal isk-=> + setlocal isk-=: return a:type =~ '\v_view>|' + finally + call cleanup.finalize() + endtry endfunction " Function: lh#dev#cpp#types#is_smart_ptr(type) : bool {{{3 function! lh#dev#cpp#types#is_smart_ptr(type) abort - let regex = lh#ft#option#get('smart_ptr_pattern', 'cpp') - if lh#option#is_set(regex) && a:type =~ regex - return 1 - elseif a:type =~ '\v^\<.*\*\s*\>\s*$' - " Special case: owner - return 1 - endif - return a:type =~ '\v(_ptr||)(\<.*\>)=\s*$' + let cleanup = lh#on#exit() + \.restore('&isk') + try + setlocal isk-=< + setlocal isk-=> + setlocal isk-=: + let regex = lh#ft#option#get('smart_ptr_pattern', 'cpp') + if lh#option#is_set(regex) && a:type =~ regex + return 1 + elseif a:type =~ '\v^\<.*\*\s*\>\s*$' + " Special case: owner + return 1 + endif + return a:type =~ '\v(_ptr||)(\<.*\>)=\s*$' + finally + call cleanup.finalize() + endtry endfunction " Function: lh#dev#cpp#types#is_not_owning_ptr(type) : bool {{{3 function! lh#dev#cpp#types#is_not_owning_ptr(type) abort - if a:type =~ '\v\*\s*$' - return lh#ft#option#get('is_following_CppCoreGuideline', 'cpp', 0) + let cleanup = lh#on#exit() + \.restore('&isk') + try + setlocal isk-=< + setlocal isk-=> + setlocal isk-=: + if a:type =~ '\v\*\s*$' + return lh#ft#option#get('is_following_CppCoreGuideline', 'cpp', 0) " Meaning, own is defined, and no own<> <=> no need to copy - elseif a:type =~ '\v(auto|unique|scoped|shared)_ptr' - return 0 - elseif a:type =~ '\v' - return 0 - else - return 1 - endif + elseif a:type =~ '\v(auto|unique|scoped|shared)_ptr' + return 0 + elseif a:type =~ '\v' + return 0 + else + return 1 + endif + finally + call cleanup.finalize() + endtry endfunction " Function: lh#dev#cpp#types#remove_ptr(type) : string {{{3 diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 00a4152..e69de29 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,85 +0,0 @@ -require 'tmpdir' -require 'vimrunner' -require 'vimrunner/rspec' -require 'support/vim' -require 'rspec/expectations' -require 'support/vim_matchers' -# require 'simplecov' - -# SimpleCov.start - -module Vimrunner - class Client - def runtime(script) - script_path = Path.new(script) - command("runtime #{script_path}") - end - end -end - - -Vimrunner::RSpec.configure do |config| - config.reuse_server = true - - vim_plugin_path = File.expand_path('.') - vim_flavor_path = ENV['HOME']+'/.vim/flavors' - - config.start_vim do - vim = Vimrunner.start_gvim - # vim = Vimrunner.start - - vim.add_plugin(vim_flavor_path, 'bootstrap.vim') - vim.prepend_runtimepath(vim_plugin_path+'/after') - vim.prepend_runtimepath(vim_plugin_path) - - # lh-UT - vim_UT_path = File.expand_path('../../../vim-UT', __FILE__) - vim.prepend_runtimepath(vim_UT_path) - vim.runtime('plugin/UT.vim') - - # pp vim_flavor_path - # lh-vim-lib - vim_lib_path = File.expand_path('../../../lh-vim-lib', __FILE__) - vim.prepend_runtimepath(vim_lib_path) - vim.runtime('plugin/let.vim') # LetIfUndef - # vim.runtime('plugin/ui-functions.vim') # lh#ui#confirm - # vim.command(':messages') - - # lh-dev - vim_dev_path = File.expand_path('../../../lh-dev', __FILE__) - vim.prepend_runtimepath(vim_dev_path) - vim.runtime('plugin/dev.vim') # AddStyle - - # lh-brackets - vim_brackets_path = File.expand_path('../../../lh-brackets', __FILE__) - vim.prepend_runtimepath(vim_brackets_path) - vim.runtime('plugin/misc_map.vim') # Inoreab - vim.runtime('plugin/common_brackets.vim') # Brackets - vim.runtime('plugin/bracketing.base.vim') # !mark! - vim.command('set enc=utf-8') - vim.command('SetMarker <+ +>') - - # pp vim.echo('&rtp') - vim.command('set shm=') - - has_redo = vim.echo('has("patch-7.4.849")') - if has_redo != "1" - puts "WARNING: this flavor of vim won't permit to support redo" - end - vim - end -end - -RSpec.configure do |config| - config.include Support::Vim - - def write_file(filename, contents) - dirname = File.dirname(filename) - FileUtils.mkdir_p dirname if not File.directory?(dirname) - - File.open(filename, 'w') { |f| f.write(contents) } - end -end - -# vim:set sw=2: - diff --git a/tests/Flavorfile b/tests/Flavorfile new file mode 100644 index 0000000..328228c --- /dev/null +++ b/tests/Flavorfile @@ -0,0 +1,2 @@ +flavor 'LucHermitte/vim-UT', '>= 2.0.8' +flavor 'editorconfig/editorconfig-vim' diff --git a/tests/VimFlavor b/tests/VimFlavor deleted file mode 100644 index 4e4e77e..0000000 --- a/tests/VimFlavor +++ /dev/null @@ -1,3 +0,0 @@ -flavor 'LucHermitte/vim-UT', '>= 0.4.0' -flavor 'LucHermitte/lh-brackets', '>= 3.1.2' -flavor 'editorconfig/editorconfig-vim' diff --git a/tests/lh/dev-cpptypes.vim b/tests/lh/dev-cpptypes.vim index 1e28bdf..298f655 100644 --- a/tests/lh/dev-cpptypes.vim +++ b/tests/lh/dev-cpptypes.vim @@ -5,7 +5,7 @@ " Version: 2.0.0. let s:k_version = '200' " Created: 03rd Dec 2015 -" Last Update: 19th Dec 2019 +" Last Update: 23rd Aug 2024 "------------------------------------------------------------------------ " Description: " Tests to autoload/lh/dev/cpp/types.vim functions @@ -28,7 +28,7 @@ call lh#askvim#scriptnames() let s:cpo_save=&cpo set cpo&vim -let s:isk_save=&cpo +let s:isk_save=&isk set isk&vim "------------------------------------------------------------------------ @@ -365,6 +365,6 @@ endfunction " }}}1 "------------------------------------------------------------------------ let &cpo=s:cpo_save -let &isk=s:cpo_save +let &isk=s:isk_save "============================================================================= " vim600: set fdm=marker: