├── .clang_complete ├── .coveragerc ├── .github ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md ├── no-response.yml ├── stale.yml └── workflows │ └── main.yml ├── .gitignore ├── .no-sublime-package ├── Default.sublime-commands ├── Default.sublime-keymap ├── EasyClangComplete.py ├── EasyClangComplete.sublime-settings ├── LICENSE ├── Main.sublime-menu ├── Preferences.sublime-settings ├── README.md ├── dependencies.json ├── docs ├── about.md ├── commands.md ├── configs.md ├── credits.md ├── img │ ├── AutoComplete.gif │ ├── ecc.png │ ├── error.png │ ├── error_dot.png │ ├── error_mono.png │ ├── favicon.ico │ ├── includes.gif │ ├── my_photo.jpg │ ├── warning.png │ ├── warning_dot.png │ └── warning_mono.png ├── includes_completion.md ├── index.md ├── pc_readme.md ├── settings.md └── support.md ├── easy_clang_complete.sublime-project ├── external └── bazel-compilation-database │ ├── .ycm_extra_conf.py │ ├── BUILD │ ├── LICENSE │ ├── README.md │ ├── WORKSPACE │ ├── aspects.bzl │ ├── generate.sh │ └── plugin │ └── bazel-compilation-database.vim ├── messages.json ├── messages ├── 2.0.0.rst ├── 3.0.0.rst ├── 4.0.0.rst ├── 5.0.0.rst ├── 6.0.0.rst ├── 6.0.1.rst ├── 6.0.2.rst ├── 6.0.3.rst ├── 6.1.0.rst ├── 6.1.1.rst ├── 6.1.2.rst ├── 6.1.3.rst ├── 6.2.0.rst ├── 6.2.1.rst ├── 6.2.2.rst ├── 6.2.3.rst ├── 6.2.4.rst ├── 6.2.5.rst ├── 6.2.6.rst ├── 6.2.7.rst ├── 6.2.8.rst ├── 6.3.0.rst ├── 6.4.0.rst ├── 6.4.1.rst ├── 6.4.2.rst ├── 6.4.3.rst ├── 6.4.4.rst ├── 6.4.5.rst ├── 6.5.0.rst ├── 6.5.1.rst ├── 6.5.2.rst └── install.rst ├── mkdocs.yml ├── pics ├── ecc.png └── icons │ ├── dot.svg │ ├── error.png │ ├── error.svg │ ├── error_dot.png │ ├── error_mono.png │ ├── warning.png │ ├── warning.svg │ ├── warning_dot.png │ └── warning_mono.png ├── plugin ├── __init__.py ├── clang │ ├── __init__.py │ ├── cindex.py │ ├── cindex32.py │ ├── cindex33.py │ ├── cindex34.py │ ├── cindex35.py │ ├── cindex36.py │ ├── cindex37.py │ ├── cindex38.py │ ├── cindex39.py │ ├── cindex40.py │ ├── cindex50.py │ └── enumerations.py ├── completion │ ├── __init__.py │ ├── base_complete.py │ ├── bin_complete.py │ ├── compiler_variant.py │ └── lib_complete.py ├── error_vis │ ├── __init__.py │ ├── popup.css │ ├── popup_error_vis.py │ └── popups.py ├── flags_sources │ ├── CppProperties.py │ ├── __init__.py │ ├── bazel.py │ ├── c_cpp_properties.py │ ├── cmake_file.py │ ├── compilation_db.py │ ├── compiler_builtins.py │ ├── flags_file.py │ ├── flags_source.py │ └── makefile.py ├── settings │ ├── __init__.py │ ├── settings_manager.py │ └── settings_storage.py ├── utils │ ├── __init__.py │ ├── action_request.py │ ├── catkinizer.py │ ├── clang_utils.py │ ├── file.py │ ├── flag.py │ ├── include_parser.py │ ├── index_location.py │ ├── macro_parser.py │ ├── module_reloader.py │ ├── output_panel_handler.py │ ├── progress_status.py │ ├── quick_panel_handler.py │ ├── search_scope.py │ ├── singleton.py │ ├── subl │ │ ├── row_col.py │ │ └── subl_bridge.py │ ├── thread_job.py │ ├── thread_pool.py │ ├── tools.py │ └── unique_list.py └── view_config │ ├── __init__.py │ ├── view_config.py │ └── view_config_manager.py ├── tests ├── CppProperties_files │ ├── empty │ │ └── CppProperties.json │ ├── environment │ │ └── CppProperties.json │ └── simple │ │ └── CppProperties.json ├── __init__.py ├── bazel │ ├── bad_project │ │ ├── WORKSPACE │ │ └── app │ │ │ ├── BUILD │ │ │ └── main.cpp │ └── good_project │ │ ├── WORKSPACE │ │ └── app │ │ ├── BUILD │ │ └── main.cpp ├── c_cpp_properties_files │ ├── c_cpp_properties.json │ ├── empty │ │ └── c_cpp_properties.json │ ├── environment │ │ └── c_cpp_properties.json │ └── simple │ │ └── c_cpp_properties.json ├── catkin_tests │ └── catkin_ws │ │ └── src │ │ └── project │ │ ├── CMakeLists.txt │ │ └── main.cpp ├── cmake_tests │ ├── CMakeLists.txt │ ├── lib │ │ ├── CMakeLists.txt │ │ ├── a.cpp │ │ └── a.h │ └── test_a.cpp ├── compilation_db_files │ ├── arguments │ │ └── compile_commands.json │ ├── command │ │ └── compile_commands.json │ ├── command_c │ │ └── compile_commands.json │ ├── command_c_ccache │ │ └── compile_commands.json │ ├── command_c_ccache_irrelevant │ │ └── compile_commands.json │ └── directory │ │ └── compile_commands.json ├── gui_test_wrapper.py ├── makefile_files │ ├── .gitignore │ ├── Makefile │ ├── inc │ │ └── bar.h │ ├── lib │ │ ├── Makefile │ │ ├── bar.c │ │ └── foo │ │ │ ├── foo.c │ │ │ └── foo.h │ └── main.c ├── test_CppProperties.py ├── test_action_request.py ├── test_bazel.py ├── test_c_cpp_properties.py ├── test_catkinizer.py ├── test_clang_complete_file.py ├── test_clang_utils.py ├── test_cmake_file.py ├── test_compilation_db.py ├── test_compiler_builtins.py ├── test_complete.py ├── test_docs.py ├── test_error_vis.py ├── test_file.py ├── test_files │ ├── Makefile.cmake │ ├── test.cpp │ ├── testTemplatesManual.cpp │ ├── test_changes.cpp │ ├── test_errors.cpp │ ├── test_info.cpp │ ├── test_info_arguments_link.cpp │ ├── test_location.cpp │ ├── test_method_one_parameter.m │ ├── test_method_two_parameters.m │ ├── test_objective_c.m │ ├── test_objective_c_covariant.m │ ├── test_objective_cpp.mm │ ├── test_property.m │ ├── test_templates.cpp │ ├── test_unicode.cpp │ ├── test_vector.cpp │ ├── test_void_method.m │ └── test_wrong_triggers.cpp ├── test_flag.py ├── test_flags_source.py ├── test_include_parser.py ├── test_index_location.py ├── test_macro_parser.py ├── test_makefile.py ├── test_output_panel_handler.py ├── test_panel_handler.py ├── test_row_col.py ├── test_search_scope.py ├── test_settings.py ├── test_singleton.py ├── test_style.py ├── test_subl_bridge.py ├── test_thread_pool.py ├── test_tools.py ├── test_unique_list.py └── test_view_config.py └── unittesting.json /.clang_complete: -------------------------------------------------------------------------------- 1 | -I/home/igor/.config/sublime-text-3/Packages/EasyClangComplete/src blah 2 | -I/home/igor/.config/sublime-text-3/Packages/EasyClangComplete 3 | -Ilocal_folder 4 | -Wabi 5 | -std=c++14 6 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | omit = 3 | /*/tests/* 4 | /*/clang/* 5 | /*/EasyClangComplete.py 6 | 7 | [report] 8 | ignore_errors = True 9 | 10 | [xml] 11 | output = .cobertura 12 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing ## 2 | Contributions are welcome! Look at the issue list. If there is something you 3 | think you can tackle, write about it in that issue and submit a Pull Request. 4 | 5 | ### Follow issue template! ### 6 | Please follow the issue template *exactly* when creating a new issue. 7 | I will be closing issues that do not follow that template. Please understand 8 | that maintaining this codebase takes time and I expect at least well-formatted 9 | issue statement to be able to tackle it. It is very demotivating to format 10 | the issues instead of actually solving them, so I would really like to outsource this task to the original submitter. 11 | 12 | Please don't jump into creating a Pull Request straight away and open an issue 13 | first. This way, we can synchronize our views on the problem, so that everyone 14 | avoids losing time. 15 | 16 | ### Branches ### 17 | There are two branches: 18 | - `master`: used for ongoing development. Merges into `release` branchright 19 | before a new release. 20 | - `release`: should be stable and following the last release. Used for urgent 21 | bug fixing exclusively on top of the previous release. 22 | 23 | ### Code style ### 24 | - Line width is `80` characters 25 | - Every public function should be documented. 26 | - The code *must* pass linters: 27 | + `pep8` 28 | + `pep257`: ignoring `["D209", "D203", "D204", "D213", "D406", "D407"]` 29 | 30 | Please ensure, that your code conforms to this. 31 | 32 | ## Tests ## 33 | Most crucial functionality is covered with unit tests using 34 | [UnitTesting](https://github.com/randy3k/UnitTesting) Sublime Text plugin. 35 | 36 | Whenever you contribute new functionality, please make sure it is covered 37 | by unit tests. It helps to maintain the quality of this software and to 38 | deal with all complex parts. I will not merge the PRs without unit tests 39 | covering the new functionality. 40 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: niosus 4 | open_collective: niosus 5 | issuehunt: niosus 6 | custom: ['https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=2QLY7J4Q944HS'] 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Read instructions carefully! # 2 | - I know its annoying, but bear with me 3 | - Take 2 minutes to make sure your issue is readable 4 | - I will close malformed issues 5 | 6 | # Please do this before submitting: # 7 | - Check for already solved issues 8 | - Try restarting Sublime Text 9 | - Remove this header and fill info below the line 10 | 11 | # Create minimal example if you can # 12 | If you can create a minimal example and link it here. 13 | - Ideally it should compile on Linux 14 | - It must work if I build it from the terminal 15 | 16 | # Copy the log # 17 | To capture the log: 18 | - Set `"verbose": true` in plugin settings 19 | - Restart Sublime Text 20 | - Open the file or do the action that causes trouble 21 | - Open console with Ctrl+` 22 | - Copy *full* output to a text file and link it to this issue 23 | - Or copy it below under `` 24 | 25 | # Fill the gaps below this line and remove all text above it # 26 | -------------------------------------------------------------- 27 | 28 | # System info: # 29 | - Sublime Text version: `` 30 | - Which system are you on: `` 31 | - Clang version: `` 32 | 33 | # What happens: # 34 | Describe your issue here. 35 | 36 |
37 | Log that illustrates the issue: 38 | 39 | ``` 40 | 41 | ``` 42 | 43 |
44 | 45 | 46 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Before submitting make sure # 2 | - Make sure your branch is based on `master` 3 | - Reference an issue that this PR closes if there is one 4 | - Add your PR descriptions below the line 5 | - Remove this prefix (everything above the line right below) 6 | 7 | ------------------------------------------------------------------------------- 8 | 9 | YOUR PR DESCRIPTION GOES HERE 10 | 11 | -------------------------------------------------------------------------------- /.github/no-response.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-no-response - https://github.com/probot/no-response 2 | 3 | # Number of days of inactivity before an Issue is closed for lack of response 4 | daysUntilClose: 30 5 | # Label requiring a response 6 | responseRequiredLabel: awaiting-feedback 7 | # Comment to post when closing an Issue for lack of response. Set to `false` to disable 8 | closeComment: > 9 | This issue has been automatically closed because there has been no response 10 | to our request for more information from the original author. With only the 11 | information that is currently in the issue, we don't have enough information 12 | to take action. Please feel free to reopen with more information. 13 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 365 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 30 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: wontfix 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Just comment 15 | here to prevent this from happening. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: > 18 | The issue has been automatically closed due to lack of activity. Feel free to 19 | reopen the issue if it is still relevant. 20 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | run-tests: 7 | strategy: 8 | fail-fast: false 9 | matrix: 10 | st-version: [4] 11 | os: ["ubuntu-latest", "macOS-latest", "windows-latest"] 12 | runs-on: ${{ matrix.os }} 13 | steps: 14 | - uses: actions/checkout@v2 15 | - uses: SublimeText/UnitTesting/actions/setup@v1 16 | with: 17 | sublime-text-version: ${{ matrix.st-version }} 18 | - name: Install dependencies 19 | if: runner.os == 'Linux' 20 | run: | 21 | python -m pip install --upgrade pip pycodestyle pep257 mkdocs mkdocs-material 22 | curl -L -o bazelisk "https://github.com/bazelbuild/bazelisk/releases/download/v1.3.0/bazelisk-linux-amd64" 23 | chmod +x bazelisk && sudo mv bazelisk /usr/local/bin/bazel 24 | shell: bash 25 | - uses: SublimeText/UnitTesting/actions/run-tests@v1 26 | with: 27 | coverage: true 28 | codecov-upload: true 29 | - name: Build mkdocs 30 | if: runner.os == 'Linux' 31 | run: mkdocs build --verbose --clean --strict; 32 | - name: Deploy to GitHub Pages 33 | if: runner.os == 'Linux' && github.ref == 'refs/heads/master' 34 | uses: JamesIves/github-pages-deploy-action@4.1.7 35 | with: 36 | branch: gh-pages 37 | folder: site 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # added by GitSavvy 3 | /easy_clang_complete.sublime-workspace 4 | 5 | # added by GitSavvy 6 | /test.c 7 | 8 | # added by GitSavvy 9 | /test.cpp 10 | 11 | # added by GitSavvy 12 | /easy_auto_complete.sublime-workspace 13 | 14 | # added by GitSavvy 15 | /tests/cmake_tests/.clang_complete 16 | 17 | /plugin/utils/__pycache__/ 18 | 19 | *__pycache__/ 20 | EasyClangComplete.sublime-workspace 21 | 22 | *.pyc 23 | 24 | /docs/.sass-cache/ 25 | 26 | /site/ 27 | /tests/bazel_project/bazel-bazel_project 28 | /tests/bazel_project/bazel-bin 29 | /tests/bazel_project/bazel-out 30 | /tests/bazel_project/bazel-testlogs 31 | /tests/bazel_project/compile_commands.json 32 | tests/bazel/good_project/bazel-* 33 | *compile_commands.json 34 | tests/bazel/bad_project/bazel-* 35 | -------------------------------------------------------------------------------- /.no-sublime-package: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/.no-sublime-package -------------------------------------------------------------------------------- /Default.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "ECC: Settings", 4 | "command": "edit_settings", 5 | "args": { 6 | "base_file": "${packages}/EasyClangComplete/EasyClangComplete.sublime-settings" 7 | } 8 | }, 9 | { 10 | "caption": "ECC: Open completion triggers location", 11 | "command": "edit_settings", 12 | "args": { 13 | "base_file": "${packages}/EasyClangComplete/Preferences.sublime-settings" 14 | } 15 | }, 16 | { 17 | "caption": "ECC: Show all errors", 18 | "command": "ecc_show_all_errors" 19 | }, 20 | { 21 | "caption": "ECC: Clean current CMake cache", 22 | "command": "clean_cmake" 23 | }, 24 | { 25 | "caption": "ECC: Show popup info", 26 | "command": "ecc_show_popup_info" 27 | }, 28 | { 29 | "caption": "ECC: (Bazel) Generate compile_commands.json", 30 | "command": "generate_bazel_comp_db" 31 | }, 32 | ] 33 | -------------------------------------------------------------------------------- /Default.sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { "keys": ["shift+f12"], "command": "ecc_goto_declaration"}, 3 | { 4 | "keys": ["<"], 5 | "command": "ecc_complete_includes", 6 | "args": {"opening_char": "<"}, 7 | "context": 8 | [ 9 | {"key": "selector", "operand": "meta.preprocessor.include"}, 10 | {"key": "auto_complete_visible", "operand": false } 11 | ] 12 | }, 13 | { 14 | "keys": ["\""], 15 | "command": "ecc_complete_includes", 16 | "args": {"opening_char": "\""}, 17 | "context": 18 | [ 19 | {"key": "selector", "operand": "meta.preprocessor.include"}, 20 | {"key": "auto_complete_visible", "operand": false } 21 | ] 22 | } 23 | ] 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2018 Igor Bogoslavskyi 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Preferences", 4 | "mnemonic": "n", 5 | "id": "preferences", 6 | "children": 7 | [ 8 | { 9 | "caption": "Package Settings", 10 | "mnemonic": "P", 11 | "id": "package-settings", 12 | "children": 13 | [ 14 | { 15 | "caption": "EasyClangComplete", 16 | "children": 17 | [ 18 | { 19 | "command": "edit_settings", 20 | "args": 21 | { 22 | "base_file": "${packages}/EasyClangComplete/EasyClangComplete.sublime-settings" 23 | }, 24 | "caption": "Settings" 25 | }, 26 | 27 | { 28 | "command": "edit_settings", 29 | "args": { 30 | "base_file": "${packages}/EasyClangComplete/Default ($platform).sublime-keymap" 31 | }, 32 | "caption": "Key Bindings" 33 | }, 34 | ] 35 | } 36 | ] 37 | } 38 | ] 39 | } 40 | ] 41 | -------------------------------------------------------------------------------- /Preferences.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | // DO NOT MODIFY! 3 | // Your changes will be overwritten upon plugin update. 4 | // To change the triggers, copy these lines to your user preferences. 5 | "auto_complete_triggers": 6 | [ 7 | { 8 | "selector": "source.c++ - string - comment - constant.numeric", 9 | "characters": ".>:", 10 | }, 11 | { 12 | "selector": "source.c - string - comment - constant.numeric", 13 | "characters": ".>:", 14 | }, 15 | { 16 | "selector": "source.objc++ - string - comment - constant.numeric", 17 | "characters": ".>: ", 18 | }, 19 | { 20 | "selector": "source.objc - string - comment - constant.numeric", 21 | "characters": ".>: ", 22 | }, 23 | { 24 | "selector": "source.cuda-c++ - string - comment - constant.numeric", 25 | "characters": ".>: ", 26 | }, 27 | ], 28 | } 29 | -------------------------------------------------------------------------------- /dependencies.json: -------------------------------------------------------------------------------- 1 | { 2 | "*": { 3 | ">=3124": [ 4 | "pygments", 5 | "python-markdown", 6 | "mdpopups", 7 | "python-jinja2", 8 | "markupsafe", 9 | "pymdownx", 10 | "pyyaml" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /docs/about.md: -------------------------------------------------------------------------------- 1 | # About me 2 | 3 | ![My pic](img/my_photo.jpg) 4 | 5 | I started this plugin as a PhD student at the University of Bonn, doing 6 | Robotics, Computer Vision and Photogrammetry. I wrote this plugin because 7 | of my obsession with Sublime Text and the need (and will) to code in C++ every 8 | day. At the start of this journey there was no plugin that would suit my needs *exactly* and as a result you see this plugin here today. 9 | 10 | ## [Support the development of this plugin](support.md) 11 | -------------------------------------------------------------------------------- /docs/commands.md: -------------------------------------------------------------------------------- 1 | # Available commands 2 | There is a number of commands that you can run from Sublime Text with 3 | Ctrl+Shift+P (or 4 | Cmd+Shift+P on MacOS) that are related to 5 | EasyClangComplete. 6 | 7 | !!! tip "Pro tip" 8 | You can assign a key binding to any of the commands represented below to make running them quick and effortless. 9 | 10 | ## Clear CMake cache 11 | Ctrl+Shift+P -> `Clean current CMake cache` 12 | 13 | This command makes sure we clean the temporary build folder where CMake 14 | generates files. 15 | 16 | ## Show all errors 17 | Ctrl+Shift+P -> `Show all errors` 18 | 19 | This command shows a panel with a list of all errors that are visible from the current translation unit. When you select one, the plugin will navigate you to the place where the error occurs. 20 | 21 | ## Show popup info 22 | Ctrl+Shift+P -> `Show popup info` 23 | 24 | Show an information popup with the type of the symbol under the cursor. 25 | 26 | ## Open settings 27 | Ctrl+Shift+P -> `Settings` 28 | 29 | Open a new window with **Default** and **User** settings opened side by side for quick adjustment of the settings used by the plugin. 30 | 31 | ## Generate a compilation database with Bazel 32 | Ctrl+Shift+P -> `Generate compile_commands.json` 33 | 34 | Uses Bazel through the script provided by [@grailbio](https://github.com/grailbio/bazel-compilation-database) to generate a `compile_commands.json` file in the folder of your `WORKSPACE` file. By default, the plugin will then be able to read this file to get the correct flags. 35 | 36 | -------------------------------------------------------------------------------- /docs/credits.md: -------------------------------------------------------------------------------- 1 | # Credits 2 | The whole work seen here was originally a fork of another repository: 3 | [ClangAutoComplete](https://github.com/pl-ca/ClangAutoComplete) 4 | 5 | However, with time this plugin has grown quite different from its origin and 6 | this is why you see it as a separate package now. Anyway, feel free to check 7 | out what `ClangAutoComplete` has to offer and come back if you still like this 8 | plugin more. 9 | 10 | The trick with multiple `clang.cindex` files is inspired by this repo: 11 | [clangHelper](https://github.com/griebd/clangHelper). Thanks for inspiration! 12 | 13 | The progress indicator idea is from 14 | [ColorSublime](https://github.com/Colorsublime/Colorsublime-Plugin) plugin. 15 | 16 | Some functionality is there only because of the awesome contributors to this 17 | project. To see their names plese check out the contributors page. 18 | -------------------------------------------------------------------------------- /docs/img/AutoComplete.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/docs/img/AutoComplete.gif -------------------------------------------------------------------------------- /docs/img/ecc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/docs/img/ecc.png -------------------------------------------------------------------------------- /docs/img/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/docs/img/error.png -------------------------------------------------------------------------------- /docs/img/error_dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/docs/img/error_dot.png -------------------------------------------------------------------------------- /docs/img/error_mono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/docs/img/error_mono.png -------------------------------------------------------------------------------- /docs/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/docs/img/favicon.ico -------------------------------------------------------------------------------- /docs/img/includes.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/docs/img/includes.gif -------------------------------------------------------------------------------- /docs/img/my_photo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/docs/img/my_photo.jpg -------------------------------------------------------------------------------- /docs/img/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/docs/img/warning.png -------------------------------------------------------------------------------- /docs/img/warning_dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/docs/img/warning_dot.png -------------------------------------------------------------------------------- /docs/img/warning_mono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/docs/img/warning_mono.png -------------------------------------------------------------------------------- /docs/includes_completion.md: -------------------------------------------------------------------------------- 1 | # Completing the includes (exprerimental) 2 | 3 | The plugin has an experimental capability to complete includes. Currently, the automatic completion after typing `#include <` will not work due to a way brackets get auto-matched by Sublime Text (read more about it [here](https://forum.sublimetext.com/t/completion-triggers/13139/5)). 4 | 5 | However, when using Alt+/ on Linux and Ctrl+Space on Windows and macOS after `<` symbol while typing `#include <` the plugin will walk the tree starting at the current include folders (read more about where these come from [here](../configs)) to generate a list of potential includes that it will show momentarily. 6 | 7 | This is still experimental and can be a bit slow. Also, the number of includes is limited by approx. 4 million entries. 8 | -------------------------------------------------------------------------------- /docs/pc_readme.md: -------------------------------------------------------------------------------- 1 | # EasyClangComplete auto-completion for human beings 2 | 3 | ![Example](img/AutoComplete.gif) 4 | 5 | ## **Simple start in just 3 steps!** 6 | 7 | ### **1. Install this plugin** 8 | 9 | - In Sublime Text press CTRL+Shift+P and 10 | install `EasyClangComplete` 11 | 12 | ### **2. Install clang** 13 | - **Ubuntu** : `sudo apt-get install clang` 14 | - **OSX** : ships `clang` by default. You are all set! 15 | - **Windows** : install the latest release from clang website. 16 | - **Other Systems** : use your package manager or install from clang website. 17 | - clang website: http://llvm.org/releases/download.html 18 | 19 | ### **3. Configure your compiler flags and include folders** 20 | 21 | #### Do you use CMake? 22 | You're in luck! The plugin will run cmake on a proper `CMakeLists.txt` in your 23 | project folder and will use information from it to complete your code out of 24 | the box! For more details, read the plugin docs about 25 | [CMake](https://niosus.github.io/EasyClangComplete/configs/#using-cmake-recommended). 26 | 27 | #### Don't like CMake? 28 | Don't worry! There are plenty of ways to configure the plugin! Read the related 29 | documentation [page](https://niosus.github.io/EasyClangComplete/configs/) for 30 | more info! 31 | 32 | ## [Extensive documentation](https://niosus.github.io/EasyClangComplete/) 33 | There are so many things I want to tell you! There is so much the plugin is 34 | capable of! Read the [docs](https://niosus.github.io/EasyClangComplete/) to get 35 | started! 36 | 37 | ## [Support this project!](https://niosus.github.io/EasyClangComplete/support/) 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /docs/support.md: -------------------------------------------------------------------------------- 1 | # Support the project 2 | [![Donate][img-paypal]][donate-paypal] 3 | [![Bountysource][img-bountysource]][bountysource-link] 4 | [![Beerpay][img-beerpay]][beerpay] 5 | [![OpenCollective Backers][img-open-backers]][opencollective] 6 | [![OpenCollective Sponsors][img-open-sponsors]][opencollective] 7 | 8 | This project cost me a ton of sleepless nights. Liters of tea and coke have 9 | been consumed while writing this code. If you feel like this unhealthy behavior 10 | is something you might want to support - smash one of the buttons above (or 11 | below)! You're awesome! :+1: 12 | 13 | 14 | 15 | ## Become a contributor! 16 | Want to support the development and make me sleep even less? Submit a PR or throw some money at me. Your avatar will magically appear below! 17 | 18 | 19 | 20 | ## Become a sponsor! 21 | Are you using this plugin at work at a company? Fight your manager/boss to 22 | support the development of this plugin as it will totally make you so much more 23 | productive :wink:! Plus your company avatar will appear on the main page so 24 | that they can boast that they support Open Source! Imagine how good you and 25 | your company will feel afterwards! :smile: 26 | 27 | 28 | 29 | 30 | [release]: https://github.com/niosus/EasyClangComplete/releases 31 | [downloads]: https://packagecontrol.io/packages/EasyClangComplete 32 | [travis]: https://travis-ci.org/niosus/EasyClangComplete 33 | [appveyor]: https://ci.appveyor.com/project/niosus/easyclangcomplete/branch/master 34 | [codacy]: https://www.codacy.com/app/zabugr/EasyClangComplete/dashboard 35 | [coverage]: https://www.codacy.com/app/zabugr/EasyClangComplete/dashboard 36 | [gitter]: https://gitter.im/niosus/EasyClangComplete?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge 37 | [donate-paypal]: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=2QLY7J4Q944HS 38 | [donate-flattr]: https://flattr.com/submit/auto?user_id=niosus&url=https://github.com/niosus/EasyClangComplete&title=EasyClangComplete&language=Python&tags=github&category=software 39 | [libclang-issue]: https://github.com/niosus/EasyClangComplete/issues/88 40 | [cmake-issue]: https://github.com/niosus/EasyClangComplete/issues/19 41 | [bountysource-link]: https://www.bountysource.com/teams/easyclangcomplete 42 | [beerpay]: https://beerpay.io/niosus/EasyClangComplete 43 | [gratipay]: https://gratipay.com/EasyClangComplete/ 44 | [maintainerd]: https://github.com/divmain/maintainerd 45 | [opencollective]: https://opencollective.com/easyclangcomplete/#contributors 46 | 47 | [img-gratipay]: https://img.shields.io/gratipay/user/niosus.svg?style=flat-square 48 | [img-beerpay]: https://beerpay.io/niosus/EasyClangComplete/badge.svg?style=flat-square 49 | [img-bountysource]: https://img.shields.io/bountysource/team/easyclangcomplete/activity.svg?style=flat-square 50 | [img-appveyor]: https://img.shields.io/appveyor/ci/niosus/easyclangcomplete/master.svg?style=flat-square&label=windows 51 | [img-travis]: https://img.shields.io/travis/niosus/EasyClangComplete/master.svg?style=flat-square&label=linux%20|%20osx 52 | [img-codacy]: https://img.shields.io/codacy/grade/254f8db44b004dffa76b8cebfece4c06.svg?style=flat-square 53 | [img-coverage]: https://img.shields.io/codacy/coverage/254f8db44b004dffa76b8cebfece4c06.svg?style=flat-square 54 | [img-release]: https://img.shields.io/github/release/niosus/EasyClangComplete.svg?style=flat-square 55 | [img-downloads]: https://img.shields.io/packagecontrol/dm/EasyClangComplete.svg?maxAge=3600&style=flat-square 56 | [img-downloads-month]: https://img.shields.io/packagecontrol/dm/EasyClangComplete.svg?maxAge=2592000&style=flat-square 57 | [img-subl]: https://img.shields.io/badge/Sublime%20Text-3-green.svg?style=flat-square 58 | [img-mit]: https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square 59 | [img-paypal]: https://img.shields.io/badge/Donate-PayPal-blue.svg?style=flat-square 60 | [img-flattr]: https://img.shields.io/badge/Donate-Flattr-blue.svg?style=flat-square 61 | [img-gitter]: https://badges.gitter.im/niosus/EasyClangComplete.svg?style=flat-square 62 | [img-open-backers]: https://opencollective.com/easyclangcomplete/backers/badge.svg?style=flat-square 63 | [img-open-sponsors]: https://opencollective.com/easyclangcomplete/sponsors/badge.svg?style=flat-square 64 | -------------------------------------------------------------------------------- /easy_clang_complete.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | "build_systems": 3 | [ 4 | { 5 | "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)", 6 | "name": "Anaconda Python Builder", 7 | "selector": "source.python", 8 | "shell_cmd": "\"python3\" -u \"$file\"" 9 | } 10 | ], 11 | "folders": 12 | [ 13 | { 14 | "path": "." 15 | } 16 | ], 17 | "settings": 18 | { 19 | "ecc_flags_sources": 20 | [ 21 | { 22 | "file": "CMakeLists.txt", 23 | "flags": 24 | [ 25 | "-DCMAKE_BUILD_TYPE=Release", 26 | "-D XXXX=ON" 27 | ], 28 | "prefix_paths": 29 | [ 30 | "/opt/ros/indigo", 31 | "~/Code/catkin_ws/devel", 32 | "$project_base_path/catkin_ws/devel" 33 | ] 34 | }, 35 | { 36 | "file": "Makefile" 37 | }, 38 | { 39 | "file": ".clang_complete" 40 | } 41 | ], 42 | "ecc_use_libclang": true, 43 | "sublack": 44 | { 45 | "black_on_save": false 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /external/bazel-compilation-database/BUILD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/external/bazel-compilation-database/BUILD -------------------------------------------------------------------------------- /external/bazel-compilation-database/WORKSPACE: -------------------------------------------------------------------------------- 1 | # Copyright 2017 GRAIL, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | workspace(name = "bazel_compdb") 16 | 17 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 18 | 19 | http_archive( 20 | name = "rules_cc", 21 | urls = ["https://github.com/bazelbuild/rules_cc/archive/262ebec3c2296296526740db4aefce68c80de7fa.tar.gz"], 22 | sha256 = "3057c13fa4d431eb0e7a9c28eea13f25987d29f869406b5ee3f2bd9c4134cb0c", 23 | ) 24 | -------------------------------------------------------------------------------- /external/bazel-compilation-database/generate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2017 GRAIL, Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Generates a compile_commands.json file at $(bazel info workspace) for 18 | # libclang based tools. 19 | 20 | # This is inspired from 21 | # https://github.com/google/kythe/blob/master/tools/cpp/generate_compilation_database.sh 22 | 23 | set -e 24 | 25 | source_dir=0 26 | 27 | usage() { 28 | printf "usage: %s flags\nwhere flags can be:\n" "${BASH_SOURCE[0]}" 29 | printf "\t-s\tuse the original source directory instead of bazel execroot\n" 30 | printf "\n" 31 | } 32 | 33 | while getopts "sh" opt; do 34 | case "${opt}" in 35 | "s") source_dir=1 ;; 36 | "h") usage; exit 0;; 37 | *) >&2 echo "invalid option ${opt}"; exit 1;; 38 | esac 39 | done 40 | 41 | # This function is copied from https://source.bazel.build/bazel/+/master:scripts/packages/bazel.sh. 42 | # `readlink -f` that works on OSX too. 43 | function get_realpath() { 44 | if [ "$(uname -s)" == "Darwin" ]; then 45 | local queue="$1" 46 | if [[ "${queue}" != /* ]] ; then 47 | # Make sure we start with an absolute path. 48 | queue="${PWD}/${queue}" 49 | fi 50 | local current="" 51 | while [ -n "${queue}" ]; do 52 | # Removing a trailing /. 53 | queue="${queue#/}" 54 | # Pull the first path segment off of queue. 55 | local segment="${queue%%/*}" 56 | # If this is the last segment. 57 | if [[ "${queue}" != */* ]] ; then 58 | segment="${queue}" 59 | queue="" 60 | else 61 | # Remove that first segment. 62 | queue="${queue#*/}" 63 | fi 64 | local link="${current}/${segment}" 65 | if [ -h "${link}" ] ; then 66 | link="$(readlink "${link}")" 67 | queue="${link}/${queue}" 68 | if [[ "${link}" == /* ]] ; then 69 | current="" 70 | fi 71 | else 72 | current="${link}" 73 | fi 74 | done 75 | 76 | echo "${current}" 77 | else 78 | readlink -f "$1" 79 | fi 80 | } 81 | 82 | readonly ASPECTS_DIR="$(dirname "$(get_realpath "${BASH_SOURCE[0]}")")" 83 | readonly OUTPUT_GROUPS="compdb_files" 84 | 85 | readonly WORKSPACE="$(bazel info workspace)" 86 | readonly EXEC_ROOT="$(bazel info execution_root)" 87 | readonly COMPDB_FILE="${WORKSPACE}/compile_commands.json" 88 | 89 | readonly QUERY_CMD=( 90 | bazel query 91 | --noshow_progress 92 | --noshow_loading_progress 93 | 'kind("cc_(library|binary|test|inc_library|proto_library)", //...) union kind("objc_(library|binary|test)", //...)' 94 | ) 95 | 96 | # Clean any previously generated files. 97 | if [[ -e "${EXEC_ROOT}" ]]; then 98 | find "${EXEC_ROOT}" -name '*.compile_commands.json' -delete 99 | fi 100 | 101 | # shellcheck disable=SC2046 102 | bazel build \ 103 | "--override_repository=bazel_compdb=${ASPECTS_DIR}" \ 104 | "--aspects=@bazel_compdb//:aspects.bzl%compilation_database_aspect" \ 105 | "--noshow_progress" \ 106 | "--noshow_loading_progress" \ 107 | "--output_groups=${OUTPUT_GROUPS}" \ 108 | "$@" \ 109 | $("${QUERY_CMD[@]}") > /dev/null 110 | 111 | echo "[" > "${COMPDB_FILE}" 112 | find "${EXEC_ROOT}" -name '*.compile_commands.json' -exec bash -c 'cat "$1" && echo ,' _ {} \; \ 113 | >> "${COMPDB_FILE}" 114 | echo "]" >> "${COMPDB_FILE}" 115 | 116 | sed -i.bak -e '/^,$/d' -e '$s/,$//' "${COMPDB_FILE}" # Hygiene to make valid json 117 | if (( source_dir )); then 118 | sed -i.bak -e "s|__EXEC_ROOT__|${WORKSPACE}|" "${COMPDB_FILE}" # Replace exec_root marker 119 | # This is for libclang to help find source files from external repositories. 120 | ln -f -s "${EXEC_ROOT}/external" "${WORKSPACE}/external" 121 | else 122 | sed -i.bak -e "s|__EXEC_ROOT__|${EXEC_ROOT}|" "${COMPDB_FILE}" # Replace exec_root marker 123 | # This is for YCM to help find the DB when following generated files. 124 | # The file may be deleted by bazel on the next build. 125 | ln -f -s "${WORKSPACE}/${COMPDB_FILE}" "${EXEC_ROOT}/" 126 | fi 127 | sed -i.bak -e "s|-isysroot __BAZEL_XCODE_SDKROOT__||" "${COMPDB_FILE}" # Replace -isysroot __BAZEL_XCODE_SDKROOT__ marker 128 | 129 | # Clean up backup file left behind by sed. 130 | rm "${COMPDB_FILE}.bak" 131 | -------------------------------------------------------------------------------- /external/bazel-compilation-database/plugin/bazel-compilation-database.vim: -------------------------------------------------------------------------------- 1 | let g:ycm_global_ycm_extra_conf = expand(":p:h:h") . "/.ycm_extra_conf.py" 2 | -------------------------------------------------------------------------------- /messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "install": "messages/install.rst", 3 | "2.0.0": "messages/2.0.0.rst", 4 | "3.0.0": "messages/3.0.0.rst", 5 | "4.0.0": "messages/4.0.0.rst", 6 | "5.0.0": "messages/5.0.0.rst", 7 | "6.0.0": "messages/6.0.0.rst", 8 | "6.0.1": "messages/6.0.1.rst", 9 | "6.0.2": "messages/6.0.2.rst", 10 | "6.0.3": "messages/6.0.3.rst", 11 | "6.1.0": "messages/6.1.0.rst", 12 | "6.1.1": "messages/6.1.1.rst", 13 | "6.1.2": "messages/6.1.2.rst", 14 | "6.1.3": "messages/6.1.3.rst", 15 | "6.2.0": "messages/6.2.0.rst", 16 | "6.2.1": "messages/6.2.1.rst", 17 | "6.2.2": "messages/6.2.2.rst", 18 | "6.2.3": "messages/6.2.3.rst", 19 | "6.2.4": "messages/6.2.4.rst", 20 | "6.2.5": "messages/6.2.5.rst", 21 | "6.2.6": "messages/6.2.6.rst", 22 | "6.2.7": "messages/6.2.7.rst", 23 | "6.2.8": "messages/6.2.8.rst", 24 | "6.3.0": "messages/6.3.0.rst", 25 | "6.4.0": "messages/6.4.0.rst", 26 | "6.4.1": "messages/6.4.1.rst", 27 | "6.4.2": "messages/6.4.2.rst", 28 | "6.4.3": "messages/6.4.3.rst", 29 | "6.4.4": "messages/6.4.4.rst", 30 | "6.4.5": "messages/6.4.5.rst", 31 | "6.5.0": "messages/6.5.0.rst", 32 | "6.5.1": "messages/6.5.1.rst", 33 | "6.5.2": "messages/6.5.2.rst" 34 | } 35 | -------------------------------------------------------------------------------- /messages/2.0.0.rst: -------------------------------------------------------------------------------- 1 | Version 2.0.0 2 | ============= 3 | 4 | New features: 5 | ------------- 6 | 7 | - **BIG CHANGE**: if your build system is `CMake` the plugin will generate a 8 | compilation database and then a file `.clang_complete` near an appropriate 9 | `CMakeLists.txt` with the flags needed for your project. It will regenerate 10 | this file if you change anything in `CMakeLists.txt`. The process should be 11 | completely automatic, but this behavior is still in beta. You can always 12 | disable it either from settings or when prompted via a dialog. 13 | - Lots of small improvements and bug fixes. 14 | - fix regression in loading relative paths from `.clang_complete` file. 15 | - support libclang with clang-3.8 on Ubuntu 16.04 with error linting and 16 | completions 17 | - initial support for libclang with clang-3.9 18 | - fix completions of arrays shown wrongly with binary comletion mode 19 | - thanks to @rchl: 20 | + fix hiding default completions when plugin completions were not generated 21 | + fix completions not working on active view after starting Sublime Text 22 | - fix for usage with OS X El Captain 23 | - since Sublime Text version 3123 libclang method should work on Windows with 24 | clang-3.9. Check it out! 25 | - when using libclang translation units are cleared based on timer to avoid 26 | taking all your memory in case you have many tabs open. 27 | - thanks to @rchl you don't need to restart Sublime Text in case you changed 28 | any settings. 29 | - thanks to @Mischa-Alff std flags are not separated anymore and the popup 30 | words don't break after every word on some systems 31 | - detection of cmake projects is now case insensitive as should be 32 | - NO MORE `include_dirs`, `std_flag_c`, `std_flag_cpp` SETTINGS! 33 | + use `common_flags`, `c_flags` and `cpp_flags` instead 34 | + to specify include paths, use `-I` in `common_flags` 35 | + specify `-std=*` flags in `c_flags` and/or `cpp_flags` 36 | + see updated default settings for an example 37 | - `libclang` way should be working on Windows with `clang` version >= 3.9 38 | - override any plugin setting from project-specific settings 39 | - completions can be triggered from any place (e.g. in the middle of words) 40 | with default sublime auto completion keyboard shortcut 41 | - completions will not be shown if you continue on typing for those rare slow 42 | completion requests. 43 | - new wildcard for `common_flags`: `$clang_version`. Allows for generic include 44 | folder for any version of clang 45 | - fixed a bunch of crashes and deadlocks, improved overall concurrency support 46 | - overall code base improvements and many-many bug fixes 47 | -------------------------------------------------------------------------------- /messages/3.0.0.rst: -------------------------------------------------------------------------------- 1 | Version 3.0.0 2 | ============= 3 | 4 | New features: 5 | ------------- 6 | 7 | - add support for `-isysroot` flag for OSX, fix `-isystem` flag. 8 | - allow wider error popup windows 9 | - open plugin settings side-by-side just like sublime does with its settings 10 | - flags order is now preserved, so the flags are passed to clang in the same 11 | order as they appear in settings and/or .clang_complete file 12 | - fix the completions being shown in a wrong location after a long completion 13 | request has finished while the cursor was moved 14 | - Following settings not used anymore or updated: 15 | + `cmake_flags_priority` 16 | + `generate_flags_with_cmake` 17 | + `search_clang_complete_file` 18 | + `max_tu_age` changed to `max_cache_age` 19 | - `.clang_complete` file will not get generated by the plugin anymore. Instead, 20 | the flags are loaded directly from their source file, e.g. `CMakeLists.txt`, 21 | `compile_commands.json` or user-defined `.clang_complete`. 22 | - New setting introduced: 23 | + `flags_sources` to allow specifying where the plugin will try to get flags 24 | for compilation from. 25 | - When using `libclang` the plugin now filters private members, destructors, 26 | constructors and enums when needed. Thanks @simia for contribution. 27 | -------------------------------------------------------------------------------- /messages/6.0.1.rst: -------------------------------------------------------------------------------- 1 | Version 6.0.1 2 | ============= 3 | 4 | Bug fixes: 5 | ----------------------- 6 | - Fix crash when trying to read "search_in" flag sources setting. 7 | 8 | 9 | Support the development! 10 | ------------------------ 11 | 💜 this plugin? Please consider buying me a 🍵 12 | https://github.com/niosus/EasyClangComplete#support-it 13 | 14 | Thanks to all the awesome contributors! 15 | If you add bounties to Bountysource you can support them too! 16 | https://www.bountysource.com/teams/easyclangcomplete 17 | 18 | Become a backer on Open Collective! 19 | https://opencollective.com/EasyClangComplete#backers 20 | 21 | I you use this plugin in a company, push to become a sponsor! 22 | https://opencollective.com/EasyClangComplete#sponsor 23 | 24 | This plugin took a significant amount of effort. It is available and will always 25 | be available for free, both as freedom and as beer. 26 | 27 | If you appreciate it - support it. How much would you say it is worth to you? 28 | -------------------------------------------------------------------------------- /messages/6.0.2.rst: -------------------------------------------------------------------------------- 1 | Version 6.0.2 2 | ============= 3 | 4 | Bug fixes: 5 | ---------- 6 | - Fix -cxx-isystem flag not parsed correctly. 7 | - Fix error with new list search scope. 8 | - Thanks to @mjendruk the wildcard "$project_base_path" will **not** be 9 | deprecated. Please ignore the message in version 6.0.0 release. 10 | "$project_base_path" has a different meaning than "$project_path". Both will 11 | be available for use. 12 | 13 | 14 | Support the development! 15 | ------------------------ 16 | 💜 this plugin? Please consider buying me a 🍵 17 | https://github.com/niosus/EasyClangComplete#support-it 18 | 19 | Thanks to all the awesome contributors! 20 | If you add bounties to Bountysource you can support them too! 21 | https://www.bountysource.com/teams/easyclangcomplete 22 | 23 | Become a backer on Open Collective! 24 | https://opencollective.com/EasyClangComplete#backers 25 | 26 | I you use this plugin in a company, push to become a sponsor! 27 | https://opencollective.com/EasyClangComplete#sponsor 28 | 29 | This plugin took a significant amount of effort. It is available and will always 30 | be available for free, both as freedom and as beer. 31 | 32 | If you appreciate it - support it. How much would you say it is worth to you? 33 | -------------------------------------------------------------------------------- /messages/6.0.3.rst: -------------------------------------------------------------------------------- 1 | Version 6.0.3 2 | ============= 3 | 4 | Bug fixes and new features: 5 | --------------------------- 6 | - Fix cleaning cache when clearning CMake build. 7 | - Add support for different separators in flags. Fix parsing flags with spaces. 8 | - Travis ci config for Linux is updated to xenial. Build is green again. 9 | 10 | Support the development! 11 | ------------------------ 12 | 💜 this plugin? Please consider buying me a 🍵 13 | https://github.com/niosus/EasyClangComplete#support-it 14 | 15 | Thanks to all the awesome contributors! 16 | If you add bounties to Bountysource you can support them too! 17 | https://www.bountysource.com/teams/easyclangcomplete 18 | 19 | Become a backer on Open Collective! 20 | https://opencollective.com/EasyClangComplete#backers 21 | 22 | I you use this plugin in a company, push to become a sponsor! 23 | https://opencollective.com/EasyClangComplete#sponsor 24 | 25 | This plugin took a significant amount of effort. It is available and will always 26 | be available for free, both as freedom and as beer. 27 | 28 | If you appreciate it - support it. How much would you say it is worth to you? 29 | -------------------------------------------------------------------------------- /messages/6.1.0.rst: -------------------------------------------------------------------------------- 1 | Version 6.1.0 2 | ============= 3 | 4 | Breaking changes: 5 | ----------------- 6 | The compilation database is now parsed differently by default: 7 | + All entries are parsed in a lazy fashion by default. 8 | + This allows to load huge databases relatively quickly. 9 | + There is no more "all" entry added to the database. 10 | + If the file is not in the database and no mapping to an existing file found 11 | through "header_to_source_mapping" setting there will be no flags emmitted 12 | for this file. 13 | + To return old behavior, set "lazy_flag_parsing" setting to "false". 14 | 15 | Other changes: 16 | -------------- 17 | - Resolve symlinks for file locations in info popup. 18 | - Resolve symlinks for files from compilation flags sources. 19 | - Show column and row when showing index. 20 | 21 | Support the development! 22 | ------------------------ 23 | 💜 this plugin? Please consider buying me a 🍵 24 | https://github.com/niosus/EasyClangComplete#support-it 25 | 26 | Thanks to all the awesome contributors! 27 | If you add bounties to Bountysource you can support them too! 28 | https://www.bountysource.com/teams/easyclangcomplete 29 | 30 | Become a backer on Open Collective! 31 | https://opencollective.com/EasyClangComplete#backers 32 | 33 | I you use this plugin in a company, push to become a sponsor! 34 | https://opencollective.com/EasyClangComplete#sponsor 35 | 36 | This plugin took a significant amount of effort. It is available and will always 37 | be available for free, both as freedom and as beer. 38 | 39 | If you appreciate it - support it. How much would you say it is worth to you? 40 | -------------------------------------------------------------------------------- /messages/6.1.1.rst: -------------------------------------------------------------------------------- 1 | Version 6.1.1 2 | ============= 3 | 4 | Quick fix: 5 | ---------- 6 | Add support for Apple Clang 11.0 7 | 8 | Support the development! 9 | ------------------------ 10 | 💜 this plugin? Please consider buying me a 🍵 11 | https://github.com/niosus/EasyClangComplete#support-it 12 | 13 | Thanks to all the awesome contributors! 14 | If you add bounties to Bountysource you can support them too! 15 | https://www.bountysource.com/teams/easyclangcomplete 16 | 17 | Become a backer on Open Collective! 18 | https://opencollective.com/EasyClangComplete#backers 19 | 20 | I you use this plugin in a company, push to become a sponsor! 21 | https://opencollective.com/EasyClangComplete#sponsor 22 | 23 | This plugin took a significant amount of effort. It is available and will always 24 | be available for free, both as freedom and as beer. 25 | 26 | If you appreciate it - support it. How much would you say it is worth to you? 27 | -------------------------------------------------------------------------------- /messages/6.1.2.rst: -------------------------------------------------------------------------------- 1 | Version 6.1.1 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | - Add .so.8 prefix, thanks @jeeb 7 | - Move user-defined flags to the end of all flags to allow overriding generated ones 8 | - When showing an error dialog, tell the user it comes from ECC 9 | 10 | Support the development! 11 | ------------------------ 12 | 💜 this plugin? Please consider buying me a 🍵 13 | https://github.com/niosus/EasyClangComplete#support-it 14 | 15 | Thanks to all the awesome contributors! 16 | If you add bounties to Bountysource you can support them too! 17 | https://www.bountysource.com/teams/easyclangcomplete 18 | 19 | Become a backer on Open Collective! 20 | https://opencollective.com/EasyClangComplete#backers 21 | 22 | I you use this plugin in a company, push to become a sponsor! 23 | https://opencollective.com/EasyClangComplete#sponsor 24 | 25 | This plugin took a significant amount of effort. It is available and will always 26 | be available for free, both as freedom and as beer. 27 | 28 | If you appreciate it - support it. How much would you say it is worth to you? 29 | -------------------------------------------------------------------------------- /messages/6.1.3.rst: -------------------------------------------------------------------------------- 1 | Version 6.1.3 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | - Support Clang 9 7 | - Avoid crashing when expanding an invalid path 8 | - Allow working with ccache, thanks @maximmenshikov 9 | - Grammar fixes in docs, thanks @ryanpcmcquen 10 | 11 | Support the development! 12 | ------------------------ 13 | 💜 this plugin? Please consider buying me a 🍵 14 | https://github.com/niosus/EasyClangComplete#support-it 15 | 16 | Thanks to all the awesome contributors! 17 | If you add bounties to Bountysource you can support them too! 18 | https://www.bountysource.com/teams/easyclangcomplete 19 | 20 | Become a backer on Open Collective! 21 | https://opencollective.com/EasyClangComplete#backers 22 | 23 | I you use this plugin in a company, push to become a sponsor! 24 | https://opencollective.com/EasyClangComplete#sponsor 25 | 26 | This plugin took a significant amount of effort. It is available and will always 27 | be available for free, both as freedom and as beer. 28 | 29 | If you appreciate it - support it. How much would you say it is worth to you? 30 | -------------------------------------------------------------------------------- /messages/6.2.0.rst: -------------------------------------------------------------------------------- 1 | Version 6.2.0 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | - Add linter visualization settings, thanks @oakmountainapps 7 | - New setting: "linter_mark_style": "outline", see docs 8 | - Refactor getting default flags from compilers 9 | - Refactor tools module to aid future extensibility and testability 10 | 11 | Support the development! 12 | ------------------------ 13 | 💜 this plugin? Please consider buying me a 🍵 14 | https://github.com/niosus/EasyClangComplete#support-it 15 | 16 | Thanks to all the awesome contributors! 17 | If you add bounties to Bountysource you can support them too! 18 | https://www.bountysource.com/teams/easyclangcomplete 19 | 20 | Become a backer on Open Collective! 21 | https://opencollective.com/EasyClangComplete#backers 22 | 23 | I you use this plugin in a company, push to become a sponsor! 24 | https://opencollective.com/EasyClangComplete#sponsor 25 | 26 | This plugin took a significant amount of effort. It is available and will always 27 | be available for free, both as freedom and as beer. 28 | 29 | If you appreciate it - support it. How much would you say it is worth to you? 30 | -------------------------------------------------------------------------------- /messages/6.2.1.rst: -------------------------------------------------------------------------------- 1 | Version 6.2.1 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | - Expand the entries in the header_to_source_mapping setting 7 | - Make ignore list more powerful by not filtering out stars in it 8 | 9 | Support the development! 10 | ------------------------ 11 | 💜 this plugin? Please consider buying me a 🍵 12 | https://github.com/niosus/EasyClangComplete#support-it 13 | 14 | Thanks to all the awesome contributors! 15 | If you add bounties to Bountysource you can support them too! 16 | https://www.bountysource.com/teams/easyclangcomplete 17 | 18 | Become a backer on Open Collective! 19 | https://opencollective.com/EasyClangComplete#backers 20 | 21 | I you use this plugin in a company, push to become a sponsor! 22 | https://opencollective.com/EasyClangComplete#sponsor 23 | 24 | This plugin took a significant amount of effort. It is available and will always 25 | be available for free, both as freedom and as beer. 26 | 27 | If you appreciate it - support it. How much would you say it is worth to you? 28 | -------------------------------------------------------------------------------- /messages/6.2.2.rst: -------------------------------------------------------------------------------- 1 | Version 6.2.2 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | - Strip "(framework directory)" for macOS builds, thanks @saagarjha 7 | - Disambiguate warnings from errors by the gutter icon 8 | - Disable loading default definitions from a compiler by default as it seems 9 | to cause quite a bit of problems. To restore the behavior just enable: 10 | "use_default_definitions": true 11 | 12 | 💜 this plugin? Consider supporting its development! 💰💸💶 13 | ------------------------------------------------------------ 14 | ‼️NEW‼️ Head to GitHub Sponsors and support my work if you enjoy the plugin! 15 | https://github.com/sponsors/niosus 16 | 17 | Alternatively, become a backer on Open Collective! 18 | https://opencollective.com/EasyClangComplete#backers 19 | 20 | I you use this plugin in a company, push to become a sponsor! 21 | https://opencollective.com/EasyClangComplete#sponsor 22 | 23 | This plugin took a significant amount of effort. It is available and will always 24 | be available for free, both as freedom and as beer. 25 | 26 | If you appreciate it - support it. How much would you say it is worth to you? 27 | 28 | For more info head here: 29 | https://github.com/niosus/EasyClangComplete#support-it 30 | -------------------------------------------------------------------------------- /messages/6.2.3.rst: -------------------------------------------------------------------------------- 1 | Version 6.2.3 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | - New setting "ignore_flags": 7 | You can now set up a list of patterns to ignore flags you don't want to be 8 | passed to clang. This is useful, when there is, say, gcc-specific header in 9 | the include flags and you want to get rid of it as it causes compilation 10 | issues for clang. 11 | 12 | 💜 this plugin? Consider supporting its development! 💰💸💶 13 | ------------------------------------------------------------ 14 | ‼️NEW‼️ Head to GitHub Sponsors and support my work if you enjoy the plugin! 15 | https://github.com/sponsors/niosus 16 | 17 | Alternatively, become a backer on Open Collective! 18 | https://opencollective.com/EasyClangComplete#backers 19 | 20 | I you use this plugin in a company, push to become a sponsor! 21 | https://opencollective.com/EasyClangComplete#sponsor 22 | 23 | This plugin took a significant amount of effort. It is available and will always 24 | be available for free, both as freedom and as beer. 25 | 26 | If you appreciate it - support it. How much would you say it is worth to you? 27 | 28 | For more info head here: 29 | https://github.com/niosus/EasyClangComplete#support-it 30 | -------------------------------------------------------------------------------- /messages/6.2.4.rst: -------------------------------------------------------------------------------- 1 | Version 6.2.4 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | - Fix the issue of `clang_binary` not expanding wildcards and variables 7 | 8 | 💜 this plugin? Consider supporting its development! 💰💸💶 9 | ------------------------------------------------------------ 10 | ‼️NEW‼️ Head to GitHub Sponsors and support my work if you enjoy the plugin! 11 | https://github.com/sponsors/niosus 12 | 13 | Alternatively, become a backer on Open Collective! 14 | https://opencollective.com/EasyClangComplete#backers 15 | 16 | I you use this plugin in a company, push to become a sponsor! 17 | https://opencollective.com/EasyClangComplete#sponsor 18 | 19 | This plugin took a significant amount of effort. It is available and will always 20 | be available for free, both as freedom and as beer. 21 | 22 | If you appreciate it - support it. How much would you say it is worth to you? 23 | 24 | For more info head here: 25 | https://github.com/niosus/EasyClangComplete#support-it 26 | -------------------------------------------------------------------------------- /messages/6.2.5.rst: -------------------------------------------------------------------------------- 1 | Version 6.2.5 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | This is mostly a dev release that increases test coverage. 7 | No functionality should be changed on the user side. 8 | 9 | 💜 this plugin? Consider supporting its development! 💰💸💶 10 | ------------------------------------------------------------ 11 | ‼️NEW‼️ Head to GitHub Sponsors and support my work if you enjoy the plugin! 12 | https://github.com/sponsors/niosus 13 | 14 | Alternatively, become a backer on Open Collective! 15 | https://opencollective.com/EasyClangComplete#backers 16 | 17 | I you use this plugin in a company, push to become a sponsor! 18 | https://opencollective.com/EasyClangComplete#sponsor 19 | 20 | This plugin took a significant amount of effort. It is available and will always 21 | be available for free, both as freedom and as beer. 22 | 23 | If you appreciate it - support it. How much would you say it is worth to you? 24 | 25 | For more info head here: 26 | https://github.com/niosus/EasyClangComplete#support-it 27 | -------------------------------------------------------------------------------- /messages/6.2.6.rst: -------------------------------------------------------------------------------- 1 | Version 6.2.6 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | - Fix a bug using the wrong row for showing error popup 7 | 8 | 💜 this plugin? Consider supporting its development! 💰💸💶 9 | ------------------------------------------------------------ 10 | ‼️NEW‼️ Head to GitHub Sponsors and support my work if you enjoy the plugin! 11 | https://github.com/sponsors/niosus 12 | 13 | Alternatively, become a backer on Open Collective! 14 | https://opencollective.com/EasyClangComplete#backers 15 | 16 | I you use this plugin in a company, push to become a sponsor! 17 | https://opencollective.com/EasyClangComplete#sponsor 18 | 19 | This plugin took a significant amount of effort. It is available and will always 20 | be available for free, both as freedom and as beer. 21 | 22 | If you appreciate it - support it. How much would you say it is worth to you? 23 | 24 | For more info head here: 25 | https://github.com/niosus/EasyClangComplete#support-it 26 | -------------------------------------------------------------------------------- /messages/6.2.7.rst: -------------------------------------------------------------------------------- 1 | Version 6.2.7 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | - Fix the off-by-one error when showing compilation errors 7 | - Fix not being able to use ECC on multi-user system 8 | - Slight refactoring of the code 9 | 10 | Warning: 11 | -------- 12 | You might need to restart Sublime Text after this update. 13 | 14 | 15 | 💜 this plugin? Consider supporting its development! 💰💸💶 16 | ------------------------------------------------------------ 17 | ‼️NEW‼️ Head to GitHub Sponsors and support my work if you enjoy the plugin! 18 | https://github.com/sponsors/niosus 19 | 20 | Alternatively, become a backer on Open Collective! 21 | https://opencollective.com/EasyClangComplete#backers 22 | 23 | I you use this plugin in a company, push to become a sponsor! 24 | https://opencollective.com/EasyClangComplete#sponsor 25 | 26 | This plugin took a significant amount of effort. It is available and will always 27 | be available for free, both as freedom and as beer. 28 | 29 | If you appreciate it - support it. How much would you say it is worth to you? 30 | 31 | For more info head here: 32 | https://github.com/niosus/EasyClangComplete#support-it 33 | -------------------------------------------------------------------------------- /messages/6.2.8.rst: -------------------------------------------------------------------------------- 1 | Version 6.2.8 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | - Fix flag parsing for paths starting with `/U`. 7 | 8 | 9 | 💜 this plugin? Consider supporting its development! 💰💸💶 10 | ------------------------------------------------------------ 11 | ‼️NEW‼️ Head to GitHub Sponsors and support my work if you enjoy the plugin! 12 | https://github.com/sponsors/niosus 13 | 14 | Alternatively, become a backer on Open Collective! 15 | https://opencollective.com/EasyClangComplete#backers 16 | 17 | I you use this plugin in a company, push to become a sponsor! 18 | https://opencollective.com/EasyClangComplete#sponsor 19 | 20 | This plugin took a significant amount of effort. It is available and will always 21 | be available for free, both as freedom and as beer. 22 | 23 | If you appreciate it - support it. How much would you say it is worth to you? 24 | 25 | For more info head here: 26 | https://github.com/niosus/EasyClangComplete#support-it 27 | -------------------------------------------------------------------------------- /messages/6.3.0.rst: -------------------------------------------------------------------------------- 1 | Version 6.3.0 2 | ============= 3 | 4 | Generate compilation database with Bazel! 5 | ----------------------------------------- 6 | There is a new option available for everyone using Bazel on Linux and OSX. 7 | It is still experimental, but seems to be working. 8 | 9 | If you have a Bazel project, open any file in it and call the command: 10 | "ECC: (Bazel) Generate compile_commands.json" 11 | 12 | This will use https://github.com/grailbio/bazel-compilation-database 13 | It generates a compilation database and if it fails it shows the error 14 | in an output panel. The approximate sequence of actions is as follows: 15 | 16 | - Search for a folder with a WORKSPACE file up the tree. 17 | - Run a script "generate.sh" from the repo in that folder. 18 | - If the command fails, show the output. 19 | 20 | 👏🧼 Stay safe! 21 | --------------- 22 | Hope everyone is staying safe in these weird times! This is a good time to 23 | stay at home and delve into that side-project you've been postponing for ages! 24 | -------------------------------------------------------------------------------- /messages/6.4.0.rst: -------------------------------------------------------------------------------- 1 | Version 6.4.0 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | - Show which command is running along with the progress status. 7 | 8 | 👏🧼 Stay safe! 9 | --------------- 10 | Hope everyone is staying safe in these weird times! This is a good time to 11 | stay at home and delve into that side-project you've been postponing for ages! 12 | 13 | 14 | 💜 this plugin? Consider supporting its development! 💰💸💶 15 | ------------------------------------------------------------ 16 | ‼️NEW‼️ Head to GitHub Sponsors and support my work if you enjoy the plugin! 17 | https://github.com/sponsors/niosus 18 | 19 | Alternatively, become a backer on Open Collective! 20 | https://opencollective.com/EasyClangComplete#backers 21 | 22 | I you use this plugin in a company, push to become a sponsor! 23 | https://opencollective.com/EasyClangComplete#sponsor 24 | 25 | This plugin took a significant amount of effort. It is available and will always 26 | be available for free, both as freedom and as beer. 27 | 28 | If you appreciate it - support it. How much would you say it is worth to you? 29 | 30 | For more info head here: 31 | https://github.com/niosus/EasyClangComplete#support-it 32 | -------------------------------------------------------------------------------- /messages/6.4.1.rst: -------------------------------------------------------------------------------- 1 | Version 6.4.1 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | - Fix progress showing a wrong job name. 7 | - Show console output if CMake generation fails. 8 | - Fix cmake flags source overwriting CMAKE_PREFIX_PATHS environment variable. 9 | - Add more suffixes to find libclang, thanks @jeeb. 10 | - Fix docs generation after updating the theme. 11 | 12 | Development announcement: 13 | ------------------------- 14 | I decided to move away from using the "dev" branch. Now all the development 15 | will be happening in the "master" branch. The releases will be sourced from 16 | the "release" branch. See contribution guidelines for details. 17 | 18 | 19 | 💜 this plugin? Consider supporting its development! 💰💸💶 20 | ------------------------------------------------------------ 21 | ‼️NEW‼️ Head to GitHub Sponsors and support my work if you enjoy the plugin! 22 | https://github.com/sponsors/niosus 23 | 24 | Alternatively, become a backer on Open Collective! 25 | https://opencollective.com/EasyClangComplete#backers 26 | 27 | I you use this plugin in a company, push to become a sponsor! 28 | https://opencollective.com/EasyClangComplete#sponsor 29 | 30 | This plugin took a significant amount of effort. It is available and will always 31 | be available for free, both as freedom and as beer. 32 | 33 | If you appreciate it - support it. How much would you say it is worth to you? 34 | 35 | For more info head here: 36 | https://github.com/niosus/EasyClangComplete#support-it 37 | -------------------------------------------------------------------------------- /messages/6.4.2.rst: -------------------------------------------------------------------------------- 1 | Version 6.4.2 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | - Add proper failure detection of CMake run. 7 | 8 | 9 | 💜 this plugin? Consider supporting its development! 💰💸💶 10 | ------------------------------------------------------------ 11 | ‼️NEW‼️ Head to GitHub Sponsors and support my work if you enjoy the plugin! 12 | https://github.com/sponsors/niosus 13 | 14 | Alternatively, become a backer on Open Collective! 15 | https://opencollective.com/EasyClangComplete#backers 16 | 17 | If you use this plugin in a company, push to become a sponsor! 18 | https://opencollective.com/EasyClangComplete#sponsor 19 | 20 | This plugin took a significant amount of effort. It is available and will always 21 | be available for free, both as freedom and as beer. 22 | 23 | If you appreciate it - support it. How much would you say it is worth to you? 24 | 25 | For more info head here: 26 | https://github.com/niosus/EasyClangComplete#support-it 27 | -------------------------------------------------------------------------------- /messages/6.4.3.rst: -------------------------------------------------------------------------------- 1 | Version 6.4.3 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | - More powerful cmake-related flags parsing. If you ever wanted to use flags 7 | like `-DCMAKE_PREFIX_PATH=~/some_path/*`, now you can! 8 | See [1] for details. 9 | - **WARNING**: the sub-setting of the `CMakeLists.txt` entry `prefix_paths` 10 | is now deprecated as all the functionality is covered by the more useful 11 | `flags` sub-setting. You can still use it for now, but I will remove it 12 | in the future. 13 | - Fixed a jump to a wrong location when going to declaration, thanks @berteauxjb 14 | - Fixed typo in the message below, thanks @berkus 15 | 16 | [1]: https://niosus.github.io/EasyClangComplete/settings/#cmake-specific-options 17 | 18 | Love this plugin? Support its development! 💰💸💶 19 | ------------------------------------------------- 20 | ‼️NEW‼️ Head to GitHub Sponsors and support my work if you enjoy the plugin! 21 | https://github.com/sponsors/niosus 22 | 23 | Alternatively, become a backer on Open Collective! 24 | https://opencollective.com/EasyClangComplete#backers 25 | 26 | If you use this plugin in a company, push to become a sponsor! 27 | https://opencollective.com/EasyClangComplete#sponsor 28 | 29 | This plugin took a significant amount of effort. It is available and will always 30 | be available for free, both as freedom and as beer. 31 | 32 | If you appreciate it - support it. How much would you say it is worth to you? 33 | 34 | For more info head here: 35 | https://github.com/niosus/EasyClangComplete#support-it 36 | -------------------------------------------------------------------------------- /messages/6.4.4.rst: -------------------------------------------------------------------------------- 1 | Version 6.4.4 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | - Fixed a bug when calling "ECC: clean current cmake cache". 7 | It now works as expected. 8 | 9 | Love this plugin? Support its development! 💰💸💶 10 | ------------------------------------------------- 11 | If you appreciate it - support it. How much would you say it is worth to you? 12 | This plugin took a significant amount of effort. It is available and will always 13 | be available for free, both as freedom and as beer. 14 | 15 | GitHub Sponsors is the preferred way to support the development 16 | https://github.com/sponsors/niosus 17 | 18 | Alternatively, become a backer on Open Collective! 19 | https://opencollective.com/EasyClangComplete#backers 20 | 21 | If you use this plugin in a company, push to become a sponsor! 22 | https://opencollective.com/EasyClangComplete#sponsor 23 | 24 | For more info head here: 25 | https://github.com/niosus/EasyClangComplete#support-it 26 | -------------------------------------------------------------------------------- /messages/6.4.5.rst: -------------------------------------------------------------------------------- 1 | Version 6.4.5 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | - Add `-target` as a separable flag, thanks @papadokolos 7 | - Fix a bug in parsing flags with =, thanks @papadokolos 8 | - Parse non-posix compilation dbs on non-posix systems, thanks @papadokolos 9 | - Update docs about `$project_base_path`, thanks @dot4qu 10 | - Fix missing enum completions 11 | 12 | Hey! It's been a while! 13 | ----------------------- 14 | There has not been updates for a while and I think it is good. The plugin still 15 | gets installed often but there is really not that many issues being opened. I 16 | understand, however, that not everyone will open an issue if something does not 17 | work. 18 | 19 | At this point, I would like to ask you to take action: 20 | - If something does not work - please open an issue! It will force me to go 21 | back to work on this. 22 | - If everything has been working without much updates: consider supporting this 23 | development. Sending some money my way is always welcome, but if you don't have 24 | any to spare - shoot me an email (or open an issue) and tell about how you use 25 | the plugin. 26 | 27 | At this point, with >35K downloads I feel a bit discouraged by the lack of 28 | feedback and it is hard to put in work on issues that I don't personally 29 | experience after a full day of work. If you appreciate this effort, do show 30 | your support. 31 | 32 | GitHub Sponsors is the preferred way to support the development 33 | https://github.com/sponsors/niosus 34 | 35 | Alternatively, become a backer on Open Collective! 36 | https://opencollective.com/EasyClangComplete#backers 37 | 38 | If you use this plugin in a company, push to become a sponsor! 39 | https://opencollective.com/EasyClangComplete#sponsor 40 | 41 | For more info head here: 42 | https://github.com/niosus/EasyClangComplete#support-it 43 | -------------------------------------------------------------------------------- /messages/6.5.0.rst: -------------------------------------------------------------------------------- 1 | Version 6.5.0 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | - New include autocompletion! 7 | - New setting "autocomplete_includes" defaulted to true, so make 8 | sure to reload sublime text! 9 | - Press `<` or `"` after `#include` to open quick panel with guided 10 | completion for your includes. The initial list is populated from 11 | the current translation unit (make sure the initial parsing is 12 | complete!) while the next layers stem from chosen folders. In the 13 | end, the picked file is committed to file. 14 | - Details here: 15 | https://niosus.github.io/EasyClangComplete/settings/#autocomplete_includes 16 | - Info popup now also shows references from open files. 17 | - Get rid of a singleton in the thread pool. Use a single instance per 18 | plugin. 19 | 20 | Huuuge thanks to my GitHub Sponsors! You're amazing! 🙏 21 | ------------------------------------------------------- 22 | - @vaporstack 23 | - @Andreasdahlberg 24 | 25 | Join them on GitHub Sponsors and support the development! 26 | https://github.com/sponsors/niosus 27 | 28 | Reach out! 😉 29 | ------------- 30 | 31 | Tell me how YOU use the plugin! Tweet at me at @igor_niosus 🐦 32 | 33 | Other means of support here: 34 | https://github.com/niosus/EasyClangComplete#support-it 35 | -------------------------------------------------------------------------------- /messages/6.5.1.rst: -------------------------------------------------------------------------------- 1 | Version 6.5.1 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | - ECC now plays well with other panels being open and won't force 7 | close them in case CMake has failed. 8 | 9 | Huuuge thanks to my GitHub Sponsors! You're amazing! 🙏 10 | ------------------------------------------------------- 11 | - @vaporstack 12 | - @Andreasdahlberg 13 | 14 | Join them on GitHub Sponsors and support the development! 15 | https://github.com/sponsors/niosus 16 | 17 | Reach out! 😉 18 | ------------- 19 | 20 | Tell me how YOU use the plugin! 21 | - PM me on reddit: @soinus 22 | - Tweet at me on twitter: @igor_niosus 🐦 23 | 24 | Other means of support here: 25 | https://github.com/niosus/EasyClangComplete#support-it 26 | -------------------------------------------------------------------------------- /messages/6.5.2.rst: -------------------------------------------------------------------------------- 1 | Version 6.5.2 2 | ============= 3 | 4 | Improvements and bug fixes: 5 | --------------------------- 6 | - A fix for a missing flag for M1 Apple arm architecture 7 | - [dev] Rewrite the CI setup to ease further development 8 | 9 | Huuuge thanks to my GitHub Sponsors! You're amazing! 🙏 10 | ------------------------------------------------------- 11 | - @vaporstack 12 | - @Andreasdahlberg 13 | 14 | Join them on GitHub Sponsors and support the development! 15 | https://github.com/sponsors/niosus 16 | 17 | Reach out! 😉 18 | ------------- 19 | 20 | Tell me how YOU are using the plugin! 21 | - PM me on reddit: @soinus 22 | - Tweet at me on twitter: @igor_niosus 🐦 23 | 24 | Other means of support here: 25 | ---------------------------- 26 | https://github.com/niosus/EasyClangComplete#support-it 27 | -------------------------------------------------------------------------------- /messages/install.rst: -------------------------------------------------------------------------------- 1 | A plugin for easy to use clang-based completions:: 2 | 3 | ╔═╗┌─┐┌─┐┬ ┬ ╔═╗┬ ┌─┐┌┐┌┌─┐ ╔═╗┌─┐┌┬┐┌─┐┬ ┌─┐┌┬┐┌─┐ 4 | ║╣ ├─┤└─┐└┬┘ ║ │ ├─┤││││ ┬ ║ │ ││││├─┘│ ├┤ │ ├┤ 5 | ╚═╝┴ ┴└─┘ ┴ ╚═╝┴─┘┴ ┴┘└┘└─┘ ╚═╝└─┘┴ ┴┴ ┴─┘└─┘ ┴ └─┘ 6 | 7 | Let't get started! 8 | ================== 9 | 10 | You're just two steps away! 11 | 12 | 1. Install clang 13 | ---------------- 14 | 15 | - **Ubuntu** : ``sudo apt-get install clang`` 16 | - **OSX** : ships `clang` by default. You are all set! 17 | - **Windows** : install the latest release from clang website. 18 | - **Other Systems** : use your package manager or install from clang website. 19 | - clang website: http://llvm.org/releases/download.html 20 | 21 | 2. Configure your includes 22 | -------------------------- 23 | 24 | Using CMake? 25 | ~~~~~~~~~~~~ 26 | 27 | Plugin will run cmake on a proper ``CMakeLists.txt`` in your project folder and 28 | will use information from it to complete your code out of the box. 29 | 30 | Don't like CMake? 31 | ~~~~~~~~~~~~~~~~~~ 32 | 33 | There are many ways of configuring the plugin! 34 | Read the docs here: https://niosus.github.io/EasyClangComplete/configs/ 35 | 36 | That's it! You're ready to use the plugin! 37 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 38 | 39 | Intro and Documentation 40 | ~~~~~~~~~~~~~~~~~~~~~~~ 41 | 42 | https://niosus.github.io/EasyClangComplete/ 43 | 44 | Thanks! 45 | ======= 46 | 47 | 💜 this plugin? Consider buying me a 🍵 48 | https://niosus.github.io/EasyClangComplete/support/ 49 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: EasyClangComplete 2 | nav: 3 | - Getting started: index.md 4 | - Configure compiler flags: configs.md 5 | - Complete includes: includes_completion.md 6 | - Full settings guide: settings.md 7 | - Available commands: commands.md 8 | - About me: about.md 9 | - Credits: credits.md 10 | - Support this project: support.md 11 | theme: 12 | name: 'material' 13 | palette: 14 | primary: 'teal' 15 | accent: 'cyan' 16 | logo: 'img/ecc.png' 17 | favicon: 'img/favicon.ico' 18 | extra: 19 | social: 20 | - icon: fontawesome/brands/github 21 | link: https://github.com/niosus 22 | - icon: fontawesome/brands/linkedin 23 | link: https://www.linkedin.com/in/igor-bogoslavskyi-72650b43/ 24 | 25 | copyright: 'Copyright © 2015 - 2020 Igor Bogoslavskyi' 26 | 27 | markdown_extensions: 28 | - admonition 29 | - codehilite 30 | - pymdownx.arithmatex 31 | - pymdownx.betterem: 32 | smart_enable: all 33 | - pymdownx.caret 34 | - pymdownx.critic 35 | - pymdownx.details 36 | - pymdownx.emoji: 37 | emoji_generator: !!python/name:pymdownx.emoji.to_svg 38 | - pymdownx.inlinehilite 39 | - pymdownx.magiclink 40 | - pymdownx.mark 41 | - pymdownx.smartsymbols 42 | - pymdownx.superfences 43 | - pymdownx.tasklist: 44 | custom_checkbox: true 45 | - pymdownx.tilde 46 | - toc: 47 | permalink: true 48 | -------------------------------------------------------------------------------- /pics/ecc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/pics/ecc.png -------------------------------------------------------------------------------- /pics/icons/dot.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 44 | 46 | 47 | 49 | image/svg+xml 50 | 52 | 53 | 54 | 55 | 56 | 61 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /pics/icons/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/pics/icons/error.png -------------------------------------------------------------------------------- /pics/icons/error.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 44 | 46 | 47 | 49 | image/svg+xml 50 | 52 | 53 | 54 | 55 | 56 | 61 | 65 | 71 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /pics/icons/error_dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/pics/icons/error_dot.png -------------------------------------------------------------------------------- /pics/icons/error_mono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/pics/icons/error_mono.png -------------------------------------------------------------------------------- /pics/icons/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/pics/icons/warning.png -------------------------------------------------------------------------------- /pics/icons/warning.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 46 | 51 | 56 | 57 | 59 | 60 | 62 | image/svg+xml 63 | 65 | 66 | 67 | 68 | 69 | 74 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /pics/icons/warning_dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/pics/icons/warning_dot.png -------------------------------------------------------------------------------- /pics/icons/warning_mono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/pics/icons/warning_mono.png -------------------------------------------------------------------------------- /plugin/__init__.py: -------------------------------------------------------------------------------- 1 | """Module that holds all the functionality of ECC.""" 2 | -------------------------------------------------------------------------------- /plugin/clang/__init__.py: -------------------------------------------------------------------------------- 1 | """Module that handles libclang python bindings.""" 2 | -------------------------------------------------------------------------------- /plugin/clang/enumerations.py: -------------------------------------------------------------------------------- 1 | #===- enumerations.py - Python Enumerations ------------------*- python -*--===# 2 | # 3 | # The LLVM Compiler Infrastructure 4 | # 5 | # This file is distributed under the University of Illinois Open Source 6 | # License. See LICENSE.TXT for details. 7 | # 8 | #===------------------------------------------------------------------------===# 9 | 10 | """ 11 | Clang Enumerations 12 | ================== 13 | This module provides static definitions of enumerations that exist in libclang. 14 | Enumerations are typically defined as a list of tuples. The exported values are 15 | typically munged into other types or classes at module load time. 16 | All enumerations are centrally defined in this file so they are all grouped 17 | together and easier to audit. And, maybe even one day this file will be 18 | automatically generated by scanning the libclang headers! 19 | """ 20 | 21 | # Maps to CXTokenKind. Note that libclang maintains a separate set of token 22 | # enumerations from the C++ API. 23 | TokenKinds = [ 24 | ('PUNCTUATION', 0), 25 | ('KEYWORD', 1), 26 | ('IDENTIFIER', 2), 27 | ('LITERAL', 3), 28 | ('COMMENT', 4), 29 | ] 30 | 31 | __all__ = ['TokenKinds'] 32 | -------------------------------------------------------------------------------- /plugin/completion/__init__.py: -------------------------------------------------------------------------------- 1 | """Module that handles completion.""" 2 | -------------------------------------------------------------------------------- /plugin/completion/base_complete.py: -------------------------------------------------------------------------------- 1 | """Contains base class for completers. 2 | 3 | Attributes: 4 | log (logging.Logger): logger for this module 5 | 6 | """ 7 | import logging 8 | 9 | from ..utils.subl.subl_bridge import SublBridge 10 | 11 | log = logging.getLogger("ECC") 12 | 13 | 14 | class BaseCompleter: 15 | """A base class for clang based completions. 16 | 17 | Attributes: 18 | compiler_variant (CompilerVariant): compiler specific options 19 | valid (bool): is completer valid 20 | version_str (str): version string of format "3.4.0" 21 | error_vis (obj): an object of error visualizer 22 | """ 23 | name = "base" 24 | 25 | valid = False 26 | 27 | def __init__(self, settings, error_vis): 28 | """Initialize the BaseCompleter. 29 | 30 | Args: 31 | settings (SettingsStorage): an object that stores current settings 32 | error_vis (ErrorVis): an object of error visualizer 33 | 34 | Raises: 35 | RuntimeError: if clang not defined we throw an error 36 | 37 | """ 38 | # check if clang binary is defined 39 | if not settings.clang_binary: 40 | raise RuntimeError("clang binary not defined") 41 | 42 | self.compiler_variant = None 43 | self.version_str = settings.clang_version 44 | self.clang_binary = settings.clang_binary 45 | # initialize error visualization 46 | self.error_vis = error_vis 47 | # Store the latest errors here 48 | self.latest_errors = None 49 | 50 | def complete(self, completion_request): 51 | """Generate completions. See children for implementation. 52 | 53 | Args: 54 | completion_request (ActionRequest): request object 55 | 56 | Raises: 57 | NotImplementedError: Guarantees we do not call this abstract method 58 | """ 59 | raise NotImplementedError("calling abstract method") 60 | 61 | def info(self, tooltip_request, settings): 62 | """Provide information about object in given location. 63 | 64 | Using the current translation unit it queries libclang for available 65 | information about cursor. 66 | 67 | Args: 68 | tooltip_request (tools.ActionRequest): A request for action 69 | from the plugin. 70 | settings: All plugin settings. 71 | 72 | Raises: 73 | NotImplementedError: Guarantees we do not call this abstract method 74 | """ 75 | raise NotImplementedError("calling abstract method") 76 | 77 | def update(self, view, settings): 78 | """Update the completer for this view. 79 | 80 | This can increase consequent completion speeds or is needed to just 81 | show errors. 82 | 83 | Args: 84 | view (sublime.View): this view 85 | settings: all plugin settings 86 | 87 | Raises: 88 | NotImplementedError: Guarantees we do not call this abstract method 89 | """ 90 | raise NotImplementedError("calling abstract method") 91 | 92 | def get_declaration_location(self, view, row_col): 93 | """Get location of declaration from given location in file. 94 | 95 | Args: 96 | view (sublime.View): current view. 97 | row_col (ZeroBasedRowCol): location of the cursor. 98 | 99 | Returns: 100 | Location: location of declaration 101 | """ 102 | raise NotImplementedError("calling abstract method") 103 | 104 | def save_errors(self, output): 105 | """Generate and store the errors. 106 | 107 | Args: 108 | output (object): opaque output to be parsed by compiler variant 109 | """ 110 | self.latest_errors = self.compiler_variant.errors_from_output(output) 111 | 112 | def show_errors(self, view): 113 | """Show current complie errors. 114 | 115 | Args: 116 | view (sublime.View): Current view 117 | """ 118 | if not SublBridge.is_valid_view(view): 119 | log.error("cannot show errors. View became invalid!") 120 | return 121 | self.error_vis.generate(view, self.latest_errors) 122 | self.error_vis.show_errors(view) 123 | -------------------------------------------------------------------------------- /plugin/error_vis/__init__.py: -------------------------------------------------------------------------------- 1 | """Module that handles error visualization.""" 2 | -------------------------------------------------------------------------------- /plugin/error_vis/popup.css: -------------------------------------------------------------------------------- 1 | .ECC .admonition 2 | { 3 | border-radius: 0rem; 4 | top: -3rem; 5 | margin-bottom: 0; 6 | } 7 | .ECC .admonition-title 8 | { 9 | border-radius: 0rem; 10 | } 11 | -------------------------------------------------------------------------------- /plugin/flags_sources/__init__.py: -------------------------------------------------------------------------------- 1 | """Handle different flags sources.""" 2 | -------------------------------------------------------------------------------- /plugin/flags_sources/bazel.py: -------------------------------------------------------------------------------- 1 | """Stores a class that manages genberation of compilation db with Bazel.""" 2 | from ..utils.output_panel_handler import OutputPanelHandler 3 | from ..utils.search_scope import TreeSearchScope 4 | from ..utils.tools import PKG_FOLDER 5 | from ..utils.tools import Tools 6 | from ..utils.file import File 7 | 8 | from os import path 9 | 10 | import logging 11 | log = logging.getLogger("ECC") 12 | 13 | 14 | class Bazel(): 15 | """Collection of methods to generate a compilation database.""" 16 | 17 | @staticmethod 18 | def generate_compdb(view): 19 | """Generate the compilation database.""" 20 | OutputPanelHandler.hide_panel() 21 | output = '' 22 | workspace_file = File.search( 23 | 'WORKSPACE', TreeSearchScope(path.dirname(view.file_name()))) 24 | if not workspace_file: 25 | return None 26 | cmd = [path.join(PKG_FOLDER, 'external', 27 | 'bazel-compilation-database', 'generate.sh')] 28 | output = Tools.run_command(cmd, cwd=workspace_file.folder) 29 | return output 30 | 31 | @staticmethod 32 | def compdb_generated(future): 33 | """Generate a compilation database.""" 34 | if future.done() and not future.cancelled(): 35 | output_text = future.result() 36 | log.debug("Database generated. Output: \n%s", output_text) 37 | if "ERROR: " in output_text: 38 | log.error("Could not generate compilation database. Output: %s", 39 | output_text) 40 | OutputPanelHandler.show( 41 | "Could not generate compilation database.\n" + output_text) 42 | else: 43 | OutputPanelHandler.show("Could not generate compilation database.") 44 | -------------------------------------------------------------------------------- /plugin/flags_sources/flags_file.py: -------------------------------------------------------------------------------- 1 | """Stores a class that manages flags loading from .clang_complete files. 2 | 3 | Attributes: 4 | log (logging.Logger): current logger. 5 | """ 6 | from .flags_source import FlagsSource 7 | from ..utils.file import File 8 | from ..utils.singleton import FlagsFileCache 9 | from ..utils.flag import Flag 10 | 11 | from os import path 12 | 13 | import logging 14 | 15 | log = logging.getLogger("ECC") 16 | 17 | 18 | class FlagsFile(FlagsSource): 19 | """Manages flags parsing from .clang_complete file. 20 | 21 | Attributes: 22 | cache (dict): Cache of all parsed files to date. Stored by full file 23 | path. Needed to avoid reparsing the file multiple times. 24 | path_for_file (dict): A path to a database for every source file path. 25 | """ 26 | _FILE_NAME = ".clang_complete" 27 | 28 | def __init__(self, include_prefixes): 29 | """Initialize a flag file storage. 30 | 31 | Args: 32 | include_prefixes (str[]): A List of valid include prefixes. 33 | """ 34 | super().__init__(include_prefixes) 35 | self._cache = FlagsFileCache() 36 | 37 | def get_flags(self, file_path=None, search_scope=None): 38 | """Get flags for file. 39 | 40 | Args: 41 | file_path (None, optional): A path to the query file. 42 | search_scope (SearchScope, optional): Where to search for a 43 | .clang_complete file. 44 | 45 | Returns: 46 | str[]: Return a list of flags in this .clang_complete file 47 | """ 48 | # prepare search scope 49 | search_scope = self._update_search_scope_if_needed( 50 | search_scope, file_path) 51 | # check if we have a hashed version 52 | log.debug("[clang_complete_file]:[get]: for file %s", file_path) 53 | cached_flags_path = self._get_cached_from(file_path) 54 | log.debug("[clang_complete_file]:[cached]: '%s'", cached_flags_path) 55 | flags_file = File.search(self._FILE_NAME, search_scope) 56 | if not flags_file: 57 | return None 58 | flags_file_path = flags_file.full_path 59 | log.debug("[clang_complete_file]:[current]: '%s'", flags_file_path) 60 | if not flags_file_path: 61 | return None 62 | 63 | flags = None 64 | parsed_before = flags_file_path in self._cache 65 | if parsed_before: 66 | log.debug("[clang_complete_file]: found cached .clang_complete") 67 | cached_flags_path = flags_file_path 68 | flags_file_path_same = (flags_file_path == cached_flags_path) 69 | flags_file_same = File.is_unchanged(cached_flags_path) 70 | if flags_file_path_same and flags_file_same: 71 | log.debug("[clang_complete_file]:[unchanged]: load cached") 72 | return self._cache[cached_flags_path] 73 | log.debug("[clang_complete_file]:[changed]: load new") 74 | if cached_flags_path and cached_flags_path in self._cache: 75 | del self._cache[cached_flags_path] 76 | flags = self.__flags_from_clang_file(File(flags_file_path)) 77 | if flags: 78 | self._cache[cached_flags_path] = flags 79 | if file_path: 80 | self._cache[file_path] = flags_file_path 81 | # now we return whatever we have 82 | return flags 83 | 84 | def __flags_from_clang_file(self, file): 85 | """Get flags from .clang_complete file. 86 | 87 | Args: 88 | file (File): A file objects that represents the file to parse. 89 | 90 | Returns: 91 | str[]: List of flags from file. 92 | """ 93 | if not path.exists(file.full_path): 94 | log.debug(".clang_complete does not exist yet. No flags present.") 95 | return [] 96 | if not file.loaded(): 97 | log.error("cannot get flags from clang_complete_file. No file.") 98 | return [] 99 | 100 | return Flag.tokenize_list(file.lines, file.folder) 101 | -------------------------------------------------------------------------------- /plugin/flags_sources/flags_source.py: -------------------------------------------------------------------------------- 1 | """Holds an abstract class defining a flags source.""" 2 | from os import path 3 | 4 | from ..utils.search_scope import TreeSearchScope 5 | 6 | 7 | class FlagsSource(object): 8 | """An abstract class defining a Flags Source.""" 9 | 10 | def __init__(self, include_prefixes): 11 | """Initialize default flags storage.""" 12 | self._include_prefixes = include_prefixes 13 | 14 | def get_flags(self, file_path=None, search_scope=None): 15 | """Get flags for a view path [ABSTRACT]. 16 | 17 | Raises: 18 | NotImplementedError: Should not be called directly. 19 | """ 20 | raise NotImplementedError("calling abstract method") 21 | 22 | @staticmethod 23 | def _update_search_scope_if_needed(search_scope, file_path): 24 | if not search_scope: 25 | # Search from current file up the tree. 26 | return TreeSearchScope(from_folder=path.dirname(file_path)) 27 | # We already know what we are doing. Leave search scope unchanged. 28 | return search_scope 29 | 30 | def _get_cached_from(self, file_path): 31 | """Get cached path for file path. 32 | 33 | Args: 34 | file_path (str): Input file path. 35 | 36 | Returns: 37 | str: Path to the cached flag source path. 38 | """ 39 | if file_path and file_path in self._cache: 40 | return self._cache[file_path] 41 | return None 42 | -------------------------------------------------------------------------------- /plugin/flags_sources/makefile.py: -------------------------------------------------------------------------------- 1 | """Stores a class that manages flags loading from Makefiles. 2 | 3 | Attributes: 4 | log (logging.Logger): current logger. 5 | """ 6 | from os import path 7 | import subprocess 8 | import shlex 9 | import logging 10 | 11 | from .flags_source import FlagsSource 12 | from ..utils.file import File 13 | from ..utils.singleton import MakefileCache 14 | from ..utils.flag import Flag 15 | 16 | log = logging.getLogger("ECC") 17 | 18 | 19 | class Makefile(FlagsSource): 20 | """Manages flags parsing from Makefiles. 21 | 22 | Attributes: 23 | cache (dict): Cache of all parsed files to date. Stored by full file 24 | path. Needed to avoid reparsing the file multiple times. 25 | """ 26 | _FILE_NAME = "Makefile" 27 | 28 | def __init__(self, include_prefixes): 29 | """Initialize a flag file storage. 30 | 31 | Args: 32 | include_prefixes (str[]): A List of valid include prefixes. 33 | """ 34 | super().__init__(include_prefixes) 35 | self._cache = MakefileCache() 36 | 37 | def get_flags(self, file_path=None, search_scope=None): 38 | """Get flags for file. 39 | 40 | Args: 41 | file_path (None, optional): A path to the query file. 42 | search_scope (SearchScope, optional): Where to search for a 43 | Makefile 44 | 45 | Returns: 46 | str[]: Return a list of flags in this Makefile 47 | """ 48 | search_scope = self._update_search_scope_if_needed( 49 | search_scope, file_path) 50 | log.debug("[Makefile]:[get]: for file %s", file_path) 51 | makefile = File.search(self._FILE_NAME, search_scope) 52 | if not makefile: 53 | return None 54 | makefile_path = makefile.full_path 55 | log.debug("[Makefile]:[current]: '%s'", makefile_path) 56 | if not makefile_path: 57 | return None 58 | cached_makefile_path = self._get_cached_from(file_path) 59 | log.debug("[Makefile]:[cached]: '%s'", cached_makefile_path) 60 | 61 | if makefile_path in self._cache: 62 | log.debug("[Makefile]: found cached Makefile") 63 | cached_makefile_path = makefile_path 64 | if makefile_path == cached_makefile_path: 65 | if File.is_unchanged(cached_makefile_path): 66 | log.debug("[Makefile]:[unchanged]: load cached") 67 | return self._cache[cached_makefile_path] 68 | log.debug("[Makefile]:[changed]: load new") 69 | if cached_makefile_path and cached_makefile_path in self._cache: 70 | del self._cache[cached_makefile_path] 71 | flags = self.__flags_from_makefile(File(makefile_path)) 72 | if flags: 73 | self._cache[makefile_path] = flags 74 | if file_path: 75 | self._cache[file_path] = makefile_path 76 | return flags 77 | 78 | def __flags_from_makefile(self, file): 79 | """Get flags from Makefile. 80 | 81 | Args: 82 | file (File): A file objects that represents the file to parse. 83 | 84 | Returns: 85 | str[]: List of flags from Makefile. 86 | """ 87 | if not path.exists(file.full_path) or not file.loaded(): 88 | log.error("cannot get flags from Makefile. No file.") 89 | return [] 90 | 91 | cmd = [ 92 | "make", "-s", "-C", file.folder, 93 | "-f", self._FILE_NAME, "-f", "-", 94 | ] 95 | makevars = [ 96 | "DEFAULT_INCLUDES", 97 | "INCLUDES", 98 | "AM_CPPFLAGS", 99 | "CPPFLAGS", 100 | "AM_CFLAGS", 101 | "CFLAGS", 102 | ] 103 | for makevar in makevars: 104 | cmd.append("print-" + makevar) 105 | pipe = subprocess.PIPE 106 | make = subprocess.Popen(cmd, stdout=pipe, stdin=pipe, stderr=pipe) 107 | printer = "print-%:\n\t@echo '$($*)'\n".encode("utf-8") 108 | output = make.communicate(input=printer)[0].decode("utf-8") 109 | tokens = [] 110 | for line in output.split("\n"): 111 | if line: 112 | tokens += shlex.split(line) 113 | return Flag.tokenize_list(tokens, file.folder) 114 | -------------------------------------------------------------------------------- /plugin/settings/__init__.py: -------------------------------------------------------------------------------- 1 | """Handle settings of the plugin.""" 2 | -------------------------------------------------------------------------------- /plugin/utils/__init__.py: -------------------------------------------------------------------------------- 1 | """Various utilities.""" 2 | -------------------------------------------------------------------------------- /plugin/utils/action_request.py: -------------------------------------------------------------------------------- 1 | """Encapsulates action request.""" 2 | import logging 3 | log = logging.getLogger("ECC") 4 | 5 | 6 | class ActionRequest(object): 7 | """A wrapper for action request. 8 | 9 | Provides a way to identify an action request and provide some information 10 | used when creating the request. 11 | """ 12 | 13 | def __init__(self, view, trigger_position): 14 | """Initialize the object. 15 | 16 | Args: 17 | view (sublime.View): The view for which request is created. 18 | trigger_position(int): The position for which request was created. 19 | """ 20 | self._view = view 21 | self._trigger_position = trigger_position 22 | 23 | def get_view(self): 24 | """Return the view for which action was requested.""" 25 | return self._view 26 | 27 | def get_trigger_position(self): 28 | """Get position of the trigger for which action was requested.""" 29 | return self._trigger_position 30 | 31 | def get_identifier(self): 32 | """Generate unique tuple for file and trigger position.""" 33 | return (self._view.buffer_id(), self._trigger_position) 34 | 35 | def is_suitable_for_view(self, view): 36 | """Check if view is suitable for this action request. 37 | 38 | Return True if specified view and its current position is deemed 39 | suitable for completions generated by this action request. """ 40 | if view != self._view: 41 | log.debug("Active view doesn't match action view") 42 | return False 43 | # We accept both current position and position to the left of the 44 | # current word as valid as we don't know how much user already typed 45 | # after the trigger. 46 | current_position = view.sel()[0].a 47 | valid_positions = [current_position, view.word(current_position).a] 48 | if self._trigger_position not in valid_positions: 49 | log.debug("View's trigger positions %s doesn't match action " 50 | "trigger position %s", 51 | valid_positions, 52 | self._trigger_position) 53 | return False 54 | return True 55 | -------------------------------------------------------------------------------- /plugin/utils/index_location.py: -------------------------------------------------------------------------------- 1 | """Class that mimics cursor.location for dealing with index locations.""" 2 | 3 | from os import path 4 | 5 | 6 | class IndexLocation: 7 | """Location of a file that mimics Cursor.location.""" 8 | 9 | class File: 10 | """Help class to mimic Cursor.file.""" 11 | 12 | def __init__(self, name): 13 | """Initialize file name.""" 14 | # 'name' is a bad name for a variable, but we need it to be this way 15 | # to conform with cursor.location. 16 | self.name = name 17 | self.extension = path.splitext(name)[1] 18 | self.short_name = path.basename(name) 19 | 20 | def __init__(self, filename, line, column): 21 | """Initialize new location.""" 22 | self.file = IndexLocation.File(filename) 23 | self.line = line 24 | self.column = column 25 | -------------------------------------------------------------------------------- /plugin/utils/macro_parser.py: -------------------------------------------------------------------------------- 1 | """Parse a macro from cindex.""" 2 | 3 | 4 | class MacroParser(object): 5 | """Parse info from macros. 6 | 7 | Clang doesn't provide much information for MACRO_DEFINITION cursors, 8 | so we have to parse this info ourselves. 9 | """ 10 | 11 | def __init__(self, name, location): 12 | """Parse the macro with the given name from its location. 13 | 14 | Args: 15 | name (str): Macro's name. 16 | location (cindex.SourceLocation): Macro definition's location. 17 | Can be None for unittests that parse with text content 18 | directly instead of loading from file. 19 | 20 | Future improvement: if there are line continuation characters 21 | in a macro with parenthesis, continue parsing into the next line 22 | to find it and create a proper args string. 23 | """ 24 | self._args_string = '' 25 | self._name = name 26 | self._body = '' 27 | if location and location.file and location.file.name: 28 | with open(location.file.name, 'r', encoding='utf-8', 29 | errors='ignore') as f: 30 | macro_file_lines = f.readlines() 31 | self._parse_macro_file_lines(macro_file_lines, location.line) 32 | 33 | def _parse_macro_file_lines(self, macro_file_lines, macro_line_number): 34 | """Parse a macro from lines of text containing the macro. 35 | 36 | Args: 37 | macro_file_lines (list[str]): lines of text containing the macro 38 | macro_line_number (int): line number (1-based) of the macro 39 | in macro_file_lines. 40 | """ 41 | macro_line = macro_file_lines[macro_line_number - 1].strip() 42 | # strip leading '#define' 43 | macro_line = macro_line.lstrip('#').lstrip().lstrip('define') 44 | macro_line = macro_line.lstrip().lstrip(self._name) 45 | # macro that looks like a function, possibly with args 46 | if macro_line.startswith('('): 47 | end_args_index = macro_line.find(')') 48 | # There should always be a closing parenthesis, but check 49 | # just in case a) the code is malformed or b) the macro 50 | # definition is continued on the next line so we can't 51 | # find it on this line. 52 | if end_args_index != -1: 53 | # If extra spaces, e.g. "#define MACRO( x , y , z )", 54 | # then flatten down to just "(x, y, z)" 55 | args_str = macro_line[1:end_args_index] 56 | args_str = ''.join(args_str.split()) 57 | args_str = args_str.replace(',', ', ') 58 | self._args_string = '(' + args_str + ')' 59 | macro_line = macro_line[end_args_index + 1:] 60 | 61 | self._body = macro_line.strip() 62 | while self._body.endswith("\\"): 63 | macro_line_number += 1 64 | line = macro_file_lines[macro_line_number - 1].rstrip() 65 | self._body += "\n" + line 66 | 67 | @property 68 | def args_string(self): 69 | """Get arguments string. 70 | 71 | Examples: 72 | '#define MACRO()' would return '()' 73 | '#define MACRO(x, y)' would return '(x, y)' 74 | '#define MACRO' would return '' 75 | """ 76 | return self._args_string 77 | 78 | @property 79 | def body_string(self): 80 | """Get macro body string.""" 81 | return self._body 82 | -------------------------------------------------------------------------------- /plugin/utils/module_reloader.py: -------------------------------------------------------------------------------- 1 | """A class needed to reload modules.""" 2 | import sys 3 | import imp 4 | import logging 5 | 6 | from .tools import PKG_NAME 7 | 8 | log = logging.getLogger("ECC") 9 | 10 | 11 | class ModuleReloader: 12 | """Reloader for all dependencies.""" 13 | 14 | MAX_RELOAD_TRIES = 10 15 | 16 | @staticmethod 17 | def reload_all(ignore_string='singleton'): 18 | """Reload all loaded modules.""" 19 | prefix = PKG_NAME + '.plugin.' 20 | # reload all twice to make sure all dependencies are satisfied 21 | log.debug( 22 | "Reloading modules that start with '%s' and don't contain '%s'", 23 | prefix, ignore_string) 24 | log.debug("Reload all modules first time") 25 | ModuleReloader.reload_once(prefix, ignore_string) 26 | log.debug("Reload all modules second time") 27 | ModuleReloader.reload_once(prefix, ignore_string) 28 | log.debug("All modules reloaded") 29 | 30 | @staticmethod 31 | def reload_once(prefix, ignore_string): 32 | """Reload all modules once.""" 33 | try_counter = 0 34 | try: 35 | for name, module in sys.modules.items(): 36 | if name.startswith(prefix) and ignore_string not in name: 37 | log.debug("Reloading module: '%s'", name) 38 | imp.reload(module) 39 | except OSError as e: 40 | if try_counter >= ModuleReloader.MAX_RELOAD_TRIES: 41 | log.fatal("Too many tries to reload and no success. Fail.") 42 | return 43 | try_counter += 1 44 | log.error("Received an error: %s on try %s. Try again.", 45 | e, try_counter) 46 | ModuleReloader.reload_once(prefix, ignore_string) 47 | -------------------------------------------------------------------------------- /plugin/utils/output_panel_handler.py: -------------------------------------------------------------------------------- 1 | """Handle everything related to the output panel.""" 2 | import time 3 | import sublime 4 | 5 | 6 | class OutputPanelHandler(): 7 | """Handle the output panel.""" 8 | PANEL_TAG = "ECC" 9 | PANEL_NAME = "output." + PANEL_TAG 10 | 11 | @staticmethod 12 | def hide_panel(): 13 | """Hide the output panel.""" 14 | window = sublime.active_window() 15 | if window.active_panel() == OutputPanelHandler.PANEL_NAME: 16 | window.run_command( 17 | "hide_panel", {"panel": OutputPanelHandler.PANEL_NAME}) 18 | 19 | @staticmethod 20 | def show(text): 21 | """Show the panel with text.""" 22 | window = sublime.active_window() 23 | window.destroy_output_panel(OutputPanelHandler.PANEL_TAG) 24 | panel_view = window.create_output_panel( 25 | OutputPanelHandler.PANEL_TAG) 26 | while panel_view.is_loading(): 27 | time.sleep(0.1) 28 | panel_view.run_command("select_all") 29 | panel_view.run_command("right_delete") 30 | 31 | settings = panel_view.settings() 32 | settings.set("tab_size", 0) 33 | settings.set("line_numbers", True) 34 | panel_view.run_command("insert", {"characters": text}) 35 | panel_view.sel().clear() 36 | panel_view.show(panel_view.size()) 37 | 38 | window.run_command( 39 | "show_panel", {"panel": OutputPanelHandler.PANEL_NAME}) 40 | panel_view.set_read_only(True) 41 | -------------------------------------------------------------------------------- /plugin/utils/progress_status.py: -------------------------------------------------------------------------------- 1 | """Module for progress status indicator. 2 | 3 | Attributes: 4 | MSG_CHARS_COLOR_SUBLIME: chars for using in colorsublime-like progress 5 | MSG_READY_COLOR_SUBLIME: ready message in colorsublime-like progress 6 | MSG_CHARS_MOON (str): chars for using in moon-like progress 7 | MSG_READY_MOON (str): ready message in moon-like progress 8 | """ 9 | 10 | import sublime 11 | 12 | MSG_CHARS_MOON = u'🌑🌒🌓🌔🌕🌖🌗🌘' 13 | MSG_READY_MOON = u'✔' 14 | MSG_CHARS_COLOR_SUBLIME = u'⣾⣽⣻⢿⡿⣟⣯⣷' 15 | MSG_READY_COLOR_SUBLIME = ' READY ' 16 | 17 | 18 | class BaseProgressStatus(object): 19 | """A base class for progress status.""" 20 | 21 | MSG_TAG = '000_ECC' 22 | MSG_MASK = ' | {msg} |' 23 | PROGRESS_MASK = 'ECC: [{progress}]' 24 | FULL_MASK = PROGRESS_MASK + MSG_MASK 25 | 26 | def __init__(self): 27 | """Initialize progress status.""" 28 | self.showing = False 29 | self.msg_chars = None 30 | self.msg_ready = None 31 | 32 | @staticmethod 33 | def set_status(message): 34 | """Set status message for the current view.""" 35 | view = sublime.active_window().active_view() 36 | view.set_status(BaseProgressStatus.MSG_TAG, message) 37 | 38 | def erase_status(self): 39 | """Erase status message for the current view.""" 40 | self.showing = False 41 | view = sublime.active_window().active_view() 42 | view.erase_status(BaseProgressStatus.MSG_TAG) 43 | 44 | def show_as_ready(self): 45 | """Show ready state.""" 46 | if not self.showing: 47 | return 48 | BaseProgressStatus.set_status( 49 | BaseProgressStatus.PROGRESS_MASK.format(progress=self.msg_ready)) 50 | 51 | def update_progress(self, message=''): 52 | """Abstract method. Generate next message.""" 53 | raise NotImplementedError("abstract method is called") 54 | 55 | 56 | class MoonProgressStatus(BaseProgressStatus): 57 | """Progress status that shows phases of the moon.""" 58 | 59 | def __init__(self): 60 | """Init moon progress status.""" 61 | super().__init__() 62 | self.idx = 0 63 | self.msg_chars = MSG_CHARS_MOON 64 | self.msg_ready = MSG_READY_MOON 65 | 66 | def update_progress(self, message): 67 | """Show next moon phase and a custom message.""" 68 | if not self.showing: 69 | return 70 | chars = self.msg_chars 71 | mod = len(chars) 72 | self.idx = (self.idx + 1) % mod 73 | BaseProgressStatus.set_status( 74 | BaseProgressStatus.FULL_MASK.format( 75 | progress=chars[self.idx], msg=message)) 76 | 77 | 78 | class ColorSublimeProgressStatus(BaseProgressStatus): 79 | """Progress status that shows phases of the moon.""" 80 | 81 | def __init__(self): 82 | """Init color sublime like progress status.""" 83 | super().__init__() 84 | self.msg_chars = MSG_CHARS_COLOR_SUBLIME 85 | self.msg_ready = MSG_READY_COLOR_SUBLIME 86 | 87 | def update_progress(self, message): 88 | """Show next random progress indicator and a custom message.""" 89 | if not self.showing: 90 | return 91 | from random import sample 92 | mod = len(self.msg_chars) 93 | rands = [self.msg_chars[x % mod] for x in sample(range(100), 10)] 94 | BaseProgressStatus.set_status( 95 | BaseProgressStatus.FULL_MASK.format( 96 | progress=''.join(rands), msg=message)) 97 | 98 | 99 | class NoneSublimeProgressStatus(BaseProgressStatus): 100 | """Progress status that does nothing.""" 101 | 102 | def __init__(self): 103 | """Init color sublime like progress status.""" 104 | super().__init__() 105 | self.showing = False 106 | 107 | def show_as_ready(self): 108 | """Empty implementation.""" 109 | pass 110 | 111 | def update_progress(self, message): 112 | """Empty implementation.""" 113 | pass 114 | -------------------------------------------------------------------------------- /plugin/utils/quick_panel_handler.py: -------------------------------------------------------------------------------- 1 | """Host a class that controls the way we interact with quick pannel.""" 2 | 3 | import logging 4 | import sublime 5 | 6 | from ..error_vis.popup_error_vis import MIN_ERROR_SEVERITY 7 | 8 | log = logging.getLogger("ECC") 9 | 10 | 11 | class ErrorQuickPanelHandler(): 12 | """Handle the quick panel.""" 13 | 14 | ENTRY_TEMPLATE = "{type}: {error}" 15 | 16 | def __init__(self, view, errors): 17 | """Initialize the object. 18 | 19 | Args: 20 | view (sublime.View): Current view. 21 | errors (list(dict)): A list of error dicts. 22 | """ 23 | self.view = view 24 | self.errors = errors 25 | 26 | def items_to_show(self): 27 | """Present errors as list of lists.""" 28 | contents = [] 29 | for error_dict in self.errors: 30 | error_type = 'ERROR' 31 | if error_dict['severity'] < MIN_ERROR_SEVERITY: 32 | error_type = 'WARNING' 33 | contents.append( 34 | [ 35 | ErrorQuickPanelHandler.ENTRY_TEMPLATE.format( 36 | type=error_type, 37 | error=error_dict['error']), 38 | error_dict['file'] 39 | ]) 40 | return contents 41 | 42 | def on_done(self, idx): 43 | """Pick this error to navigate to a file.""" 44 | log.debug("Picked idx: %s", idx) 45 | if idx < 0 or idx >= len(self.errors): 46 | return None 47 | return self.view.window().open_file(self.__get_formatted_location(idx), 48 | sublime.ENCODED_POSITION) 49 | 50 | def __get_formatted_location(self, idx): 51 | picked_entry = self.errors[idx] 52 | return "{file}:{row}:{col}".format(file=picked_entry['file'], 53 | row=picked_entry['row'], 54 | col=picked_entry['col']) 55 | 56 | def show(self, window): 57 | """Show the quick panel.""" 58 | start_idx = 0 59 | window.show_quick_panel( 60 | self.items_to_show(), 61 | self.on_done, 62 | sublime.MONOSPACE_FONT, 63 | start_idx) 64 | -------------------------------------------------------------------------------- /plugin/utils/search_scope.py: -------------------------------------------------------------------------------- 1 | """Defines all search scopes used in this project.""" 2 | from os import path 3 | 4 | ROOT_PATH = path.abspath('/') 5 | 6 | 7 | class TreeSearchScope: 8 | """Encapsulation of a search scope to search up the tree.""" 9 | 10 | def __init__(self, 11 | from_folder=ROOT_PATH, 12 | to_folder=ROOT_PATH): 13 | """Initialize the search scope.""" 14 | self.from_folder = from_folder 15 | self.to_folder = to_folder 16 | 17 | @property 18 | def from_folder(self): 19 | """Get the starting folder.""" 20 | return self._from_folder 21 | 22 | @from_folder.setter 23 | def from_folder(self, folder): 24 | """Set the last folder in search.""" 25 | self._from_folder = folder 26 | self._current_folder = self._from_folder 27 | 28 | @property 29 | def to_folder(self): 30 | """Get the end of search folder.""" 31 | return self._to_folder 32 | 33 | @to_folder.setter 34 | def to_folder(self, folder): 35 | """Set the last folder in search.""" 36 | self._to_folder = folder 37 | self._one_past_last = path.dirname(self._to_folder) 38 | 39 | def __bool__(self): 40 | """Check if the search scope is empty.""" 41 | return self.from_folder != ROOT_PATH 42 | 43 | def __iter__(self): 44 | """Make this an iterator.""" 45 | self._current_folder = self._from_folder 46 | return self 47 | 48 | def __next__(self): 49 | """Get next folder to search in.""" 50 | current_folder = self._current_folder 51 | self._current_folder = path.dirname(self._current_folder) 52 | scope_end_reached = current_folder == self._one_past_last 53 | root_reached = current_folder == self._current_folder 54 | if root_reached or scope_end_reached: 55 | raise StopIteration 56 | else: 57 | return current_folder 58 | 59 | def __repr__(self): 60 | """Return search scope as a printable string.""" 61 | return 'SearchScope: from_folder: {}, to_folder: {}'.format( 62 | self._from_folder, self._to_folder) 63 | 64 | 65 | class ListSearchScope: 66 | """Encapsulation of a search scope to search in a list.""" 67 | 68 | def __init__(self, paths=[]): 69 | """Initialize the search scope.""" 70 | self.folders = paths 71 | 72 | @property 73 | def folders(self): 74 | """Get the starting folder.""" 75 | return self._folders 76 | 77 | @folders.setter 78 | def folders(self, paths): 79 | """Set the folders.""" 80 | self._folders = [f for f in paths if path.isdir(f)] 81 | self._iter = iter(self._folders) 82 | 83 | def __bool__(self): 84 | """Check if the search scope is not empty.""" 85 | return len(self._folders) > 0 86 | 87 | def __iter__(self): 88 | """Make this an iterator.""" 89 | self._iter = iter(self._folders) 90 | return self._iter 91 | 92 | def __next__(self): 93 | """Get next folder to search in.""" 94 | return next(self._iter) 95 | 96 | def __repr__(self): 97 | """Return search scope as a printable string.""" 98 | return 'SearchScope: folders: {}'.format(self._folders) 99 | -------------------------------------------------------------------------------- /plugin/utils/singleton.py: -------------------------------------------------------------------------------- 1 | """Singleton related stuff. Should only be imported ONCE.""" 2 | 3 | 4 | def singleton(class_): 5 | """Singleton class wrapper. 6 | 7 | Args: 8 | class_ (Class): Class to wrap. 9 | 10 | Returns: 11 | class_: unique instance of object. 12 | """ 13 | instances = {} 14 | 15 | def getinstance(*args, **kwargs): 16 | """Get instance of a class.""" 17 | if class_ not in instances: 18 | instances[class_] = class_(*args, **kwargs) 19 | return instances[class_] 20 | return getinstance 21 | 22 | # ALL the singletons used throughout the codebase go below this line: 23 | ############################################################################## 24 | ############################################################################## 25 | ############################################################################## 26 | 27 | 28 | @singleton 29 | class ViewConfigCache(dict): 30 | """Singleton for view configurations cache.""" 31 | pass 32 | 33 | 34 | @singleton 35 | class CppPropertiesCache(dict): 36 | """Singleton for CppProperties.json file cache.""" 37 | pass 38 | 39 | 40 | @singleton 41 | class CCppPropertiesCache(dict): 42 | """Singleton for c_cpp_properties.json file cache.""" 43 | pass 44 | 45 | 46 | @singleton 47 | class CMakeFileCache(dict): 48 | """Singleton for CMakeLists.txt file cache.""" 49 | pass 50 | 51 | 52 | @singleton 53 | class MakefileCache(dict): 54 | """Singleton for Makefile file cache.""" 55 | pass 56 | 57 | 58 | @singleton 59 | class ComplationDbCache(dict): 60 | """Singleton for compilation database cache.""" 61 | pass 62 | 63 | 64 | @singleton 65 | class ThreadCache(dict): 66 | """Singleton for a cache of running threads.""" 67 | pass 68 | 69 | 70 | @singleton 71 | class FlagsFileCache(dict): 72 | """Singleton for .clang_fomplete file cache.""" 73 | pass 74 | 75 | 76 | class GenericCache: 77 | """A class to be able to import the function below.""" 78 | @staticmethod 79 | def clear_all_caches(): 80 | """Clear all existing caches.""" 81 | CCppPropertiesCache().clear() 82 | CMakeFileCache().clear() 83 | MakefileCache().clear() 84 | ComplationDbCache().clear() 85 | CppPropertiesCache().clear() 86 | FlagsFileCache().clear() 87 | ViewConfigCache().clear() 88 | ThreadCache().clear() 89 | -------------------------------------------------------------------------------- /plugin/utils/subl/row_col.py: -------------------------------------------------------------------------------- 1 | """Represent different ways to work with row and column in views.""" 2 | 3 | 4 | class ZeroIndexedRowCol(): 5 | """A cursor position as 0-indexed row and column.""" 6 | 7 | def __init__(self, row, col): 8 | """Initialize from row and column as seen in file (start with 1).""" 9 | self._row = row 10 | self._col = col 11 | 12 | @property 13 | def row(self): 14 | """Return row.""" 15 | return self._row 16 | 17 | @property 18 | def col(self): 19 | """Return col.""" 20 | return self._col 21 | 22 | def as_1d_location(self, view): 23 | """Return the cursor position as 1d location in a view.""" 24 | return view.text_point(self._row, self._col) 25 | 26 | @staticmethod 27 | def from_one_indexed(one_indexed_row_col): 28 | """Convert 1-indexed row column into the 0-indexed representation.""" 29 | return ZeroIndexedRowCol(one_indexed_row_col._row - 1, 30 | one_indexed_row_col._col - 1) 31 | 32 | @staticmethod 33 | def from_1d_location(view, pos): 34 | """Get row and column from a 1d location in a view.""" 35 | if pos is None: 36 | return ZeroIndexedRowCol.from_current_cursor_pos(view) 37 | row, col = view.rowcol(pos) 38 | return ZeroIndexedRowCol(row, col) 39 | 40 | @classmethod 41 | def from_current_cursor_pos(cls, view): 42 | """Generate row and columg from current cursor position in view.""" 43 | pos = view.sel() 44 | if pos is None or len(pos) < 1: 45 | # something is wrong 46 | return None 47 | # We care about the first position only. 48 | pos = pos[0].a 49 | return cls.from_1d_location(view, pos) 50 | 51 | def as_tuple(self): 52 | """Return as tuple.""" 53 | return (self._row, self._col) 54 | 55 | 56 | class OneIndexedRowCol(): 57 | """Stores a cursor position.""" 58 | 59 | def __init__(self, row, col): 60 | """Initialize from a zero-indexed row and column.""" 61 | self._row = row 62 | self._col = col 63 | 64 | @staticmethod 65 | def from_zero_indexed(zero_indexed_row_col): 66 | """Convert 0-indexed row column into the 1-indexed representation.""" 67 | return ZeroIndexedRowCol(zero_indexed_row_col._row + 1, 68 | zero_indexed_row_col._col + 1) 69 | 70 | @property 71 | def row(self): 72 | """Return row.""" 73 | return self._row 74 | 75 | @property 76 | def col(self): 77 | """Return col.""" 78 | return self._col 79 | 80 | def as_tuple(self): 81 | """Return as tuple.""" 82 | return (self._row, self._col) 83 | -------------------------------------------------------------------------------- /plugin/utils/thread_job.py: -------------------------------------------------------------------------------- 1 | """Class that defined a job to be run in a thread pool. 2 | 3 | Attributes: 4 | log (logging.Logger): Logger for current module. 5 | """ 6 | import logging 7 | 8 | 9 | log = logging.getLogger("ECC") 10 | 11 | 12 | class ThreadJob: 13 | """A class for a job that can be submitted to ThreadPool. 14 | 15 | Attributes: 16 | name (str): Name of this job. 17 | callback (func): Function to use as callback. 18 | function (func): Function to run asynchronously. 19 | args (object[]): Sequence of additional arguments for `function`. 20 | """ 21 | 22 | UPDATE_TAG = "Updating translation unit" 23 | CLEAR_TAG = "Clearing" 24 | COMPLETE_TAG = "Completing" 25 | COMPLETE_INCLUDES_TAG = "Competing includes" 26 | GENERATE_DB_TAG = "Generating compilation database" 27 | INFO_TAG = "Showing info" 28 | 29 | def __init__(self, name, callback, function, args): 30 | """Initialize a job. 31 | 32 | Args: 33 | name (str): Name of this job. 34 | callback (func): Function to use as callback. 35 | function (func): Function to run asynchronously. 36 | args (object[]): Sequence of additional arguments for `function`. 37 | future (future): A future that tracks the execution of this job. 38 | """ 39 | self.name = name 40 | self.callback = callback 41 | self.function = function 42 | self.args = args 43 | self.future = None 44 | 45 | def is_high_priority(self): 46 | """Check if job is high priority.""" 47 | return self.name in [ThreadJob.UPDATE_TAG, 48 | ThreadJob.CLEAR_TAG, 49 | ThreadJob.GENERATE_DB_TAG] 50 | 51 | def __repr__(self): 52 | """Representation.""" 53 | return "job: '{name}'".format(name=self.name) 54 | 55 | def overrides(self, other): 56 | """Define if one job overrides another.""" 57 | if self.is_same_type_as(other): 58 | return True 59 | if self.is_high_priority() and not other.is_high_priority(): 60 | return True 61 | return False 62 | 63 | def is_same_type_as(self, other): 64 | """Define if these are the same type of jobs.""" 65 | return self.name == other.name 66 | -------------------------------------------------------------------------------- /plugin/utils/tools.py: -------------------------------------------------------------------------------- 1 | """Collection of various tools.""" 2 | from os import path 3 | from os import environ 4 | 5 | import sublime 6 | import logging 7 | import subprocess 8 | 9 | 10 | PKG_NAME = path.basename(path.dirname(path.dirname(path.dirname(__file__)))) 11 | PKG_FOLDER = path.dirname(path.dirname(path.dirname(__file__))) 12 | 13 | _log = logging.getLogger("ECC") 14 | 15 | 16 | class Tools: 17 | """Just a bunch of helpful tools.""" 18 | 19 | @staticmethod 20 | def seconds_from_string(time_str): 21 | """Get int seconds from string. 22 | 23 | Args: 24 | time_str (str): string in format 'HH:MM:SS' 25 | 26 | Returns: 27 | int: seconds 28 | """ 29 | h, m, s = time_str.split(":") 30 | return int(h) * 3600 + int(m) * 60 + int(s) 31 | 32 | @staticmethod 33 | def run_command(command, shell=False, cwd=path.curdir, env=environ, 34 | stdin=None, default=None): 35 | """Run a generic command in a subprocess. 36 | 37 | Args: 38 | command (str): command to run 39 | stdin: The standard input channel for the started process. 40 | default (andy): The default return value in case run fails. 41 | 42 | Returns: 43 | str: raw command output or default value 44 | """ 45 | output_text = default 46 | try: 47 | startupinfo = None 48 | if sublime.platform() == "windows": 49 | # Don't let console window pop-up briefly. 50 | startupinfo = subprocess.STARTUPINFO() 51 | startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW 52 | startupinfo.wShowWindow = subprocess.SW_HIDE 53 | if stdin is None: 54 | stdin = subprocess.PIPE 55 | output = subprocess.check_output(command, 56 | stdin=stdin, 57 | stderr=subprocess.STDOUT, 58 | shell=shell, 59 | cwd=cwd, 60 | env=env, 61 | startupinfo=startupinfo) 62 | output_text = ''.join(map(chr, output)) 63 | except subprocess.CalledProcessError as e: 64 | output_text = e.output.decode("utf-8") 65 | _log.debug("Command finished with code: %s", e.returncode) 66 | _log.debug("Command output: \n%s", output_text) 67 | except OSError: 68 | _log.debug( 69 | "Executable file not found executing: {}".format(command)) 70 | return output_text 71 | 72 | @staticmethod 73 | def get_unique_str(init_string): 74 | """Generate md5 unique sting hash given init_string.""" 75 | import hashlib 76 | augmented_string = init_string + path.expanduser('~') 77 | return hashlib.md5(augmented_string.encode('utf-8')).hexdigest() 78 | -------------------------------------------------------------------------------- /plugin/utils/unique_list.py: -------------------------------------------------------------------------------- 1 | """Encapsulates set augmented list with unique stored values.""" 2 | 3 | 4 | class UniqueList: 5 | """A list that guarantees unique insertion.""" 6 | 7 | def __init__(self, other=None): 8 | """Init with another iterable if it is present.""" 9 | self.__values = list() 10 | self.__values_set = set() 11 | if not other: 12 | return 13 | for value in other: 14 | self.append(value) 15 | 16 | def append(self, value): 17 | """Append a single value. 18 | 19 | Args: 20 | value: input value 21 | """ 22 | if value not in self.__values_set: 23 | self.__values.append(value) 24 | self.__values_set.add(value) 25 | 26 | def as_list(self): 27 | """Return an ordinary python list.""" 28 | return self.__values 29 | 30 | def clear(self): 31 | """Clear the list.""" 32 | self.__values = list() 33 | self.__values_set = set() 34 | 35 | def __add__(self, other): 36 | """Append another iterable. 37 | 38 | Args: 39 | other (iterable): some other iterable container 40 | Returns: 41 | UniqueList: new list with appended elements 42 | """ 43 | for value in other: 44 | self.append(value) 45 | return self 46 | 47 | def __iter__(self): 48 | """Make iterable.""" 49 | return iter(self.__values) 50 | 51 | def __str__(self): 52 | """Make convertable to str.""" 53 | return str(self.__values) 54 | -------------------------------------------------------------------------------- /plugin/view_config/__init__.py: -------------------------------------------------------------------------------- 1 | """View config and things related to it.""" 2 | -------------------------------------------------------------------------------- /tests/CppProperties_files/empty/CppProperties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "includePath": [ 5 | ], 6 | "intelliSenseMode": "msvc-x64", 7 | "name": "waf_build_tree" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /tests/CppProperties_files/environment/CppProperties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "includePath": [ 5 | "${env.TEST_VARIABLE_TO_EXPAND}" 6 | ], 7 | "intelliSenseMode": "msvc-x64", 8 | "name": "waf_build_tree" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /tests/CppProperties_files/simple/CppProperties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "includePath": [ 5 | "/folder/include/path", 6 | "/another/file/path" 7 | ], 8 | "intelliSenseMode": "msvc-x64", 9 | "name": "waf_build_tree" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | """Tests of ECC.""" 2 | -------------------------------------------------------------------------------- /tests/bazel/bad_project/WORKSPACE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/tests/bazel/bad_project/WORKSPACE -------------------------------------------------------------------------------- /tests/bazel/bad_project/app/BUILD: -------------------------------------------------------------------------------- 1 | cc_binary( 2 | name = "main" 3 | srcs = ["main.cpp"], 4 | ) 5 | -------------------------------------------------------------------------------- /tests/bazel/bad_project/app/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char const *argv[]) { 4 | std::vector vec; 5 | vec.push_back(10); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /tests/bazel/good_project/WORKSPACE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niosus/EasyClangComplete/49cfb0325297752a900b072a64282f94f2a021f8/tests/bazel/good_project/WORKSPACE -------------------------------------------------------------------------------- /tests/bazel/good_project/app/BUILD: -------------------------------------------------------------------------------- 1 | cc_binary( 2 | name = "main", 3 | srcs = ["main.cpp"], 4 | ) 5 | -------------------------------------------------------------------------------- /tests/bazel/good_project/app/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char const *argv[]) { 4 | std::vector vec; 5 | vec.push_back(10); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /tests/c_cpp_properties_files/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Win32", 5 | "intelliSenseMode": "msvc-x64", 6 | "includePath": [ "${workspaceRoot}" ], 7 | "defines": [ "FOO", "BAR=100" ], 8 | "compileCommands": "/path/to/compile_commands.json", 9 | "browse": { 10 | "path": [ "${workspaceRoot}" ], 11 | "limitSymbolsToIncludedHeaders": true, 12 | "databaseFilename": "" 13 | } 14 | } 15 | ], 16 | "version": 2 17 | } -------------------------------------------------------------------------------- /tests/c_cpp_properties_files/empty/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Win32", 5 | "intelliSenseMode": "msvc-x64", 6 | "includePath": [], 7 | "defines": [], 8 | "compileCommands": "/path/to/compile_commands.json", 9 | "browse": { 10 | "path": [ "${workspaceRoot}" ], 11 | "limitSymbolsToIncludedHeaders": true, 12 | "databaseFilename": "" 13 | } 14 | } 15 | ], 16 | "version": 2 17 | } -------------------------------------------------------------------------------- /tests/c_cpp_properties_files/environment/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Win32", 5 | "intelliSenseMode": "msvc-x64", 6 | "includePath": [ "${TEST_VARIABLE_TO_EXPAND}" ], 7 | "defines": [ "lib_EXPORTS" ], 8 | "compileCommands": "/path/to/compile_commands.json", 9 | "browse": { 10 | "path": [ "${workspaceRoot}" ], 11 | "limitSymbolsToIncludedHeaders": true, 12 | "databaseFilename": "" 13 | } 14 | } 15 | ], 16 | "version": 2 17 | } -------------------------------------------------------------------------------- /tests/c_cpp_properties_files/simple/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Win32", 5 | "intelliSenseMode": "msvc-x64", 6 | "includePath": [ "/lib_include_dir" ], 7 | "defines": [ "lib_EXPORTS" ], 8 | "compileCommands": "/path/to/compile_commands.json", 9 | "browse": { 10 | "path": [ "${workspaceRoot}" ], 11 | "limitSymbolsToIncludedHeaders": true, 12 | "databaseFilename": "" 13 | } 14 | } 15 | ], 16 | "version": 2 17 | } -------------------------------------------------------------------------------- /tests/catkin_tests/catkin_ws/src/project/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(catkin_test) 2 | cmake_minimum_required(VERSION 3.0) 3 | 4 | find_package(catkin) 5 | 6 | add_executable(main main.cpp) 7 | -------------------------------------------------------------------------------- /tests/catkin_tests/catkin_ws/src/project/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Igor Bogoslavskyi, year 2018. 2 | // In case of any problems with the code please contact me. 3 | 4 | int main(int argc, char const *argv[]) { return 0; } 5 | -------------------------------------------------------------------------------- /tests/cmake_tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | project (test_cmake_project) 4 | 5 | add_subdirectory(lib) 6 | include_directories(lib) 7 | 8 | add_executable(test_a test_a.cpp) 9 | target_link_libraries(test_a liba) 10 | -------------------------------------------------------------------------------- /tests/cmake_tests/lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(liba SHARED a.cpp) 2 | -------------------------------------------------------------------------------- /tests/cmake_tests/lib/a.cpp: -------------------------------------------------------------------------------- 1 | #include "a.h" 2 | 3 | #include 4 | 5 | void A::foo(int bar) { fprintf(stderr, "hello: %d\n", bar); } 6 | -------------------------------------------------------------------------------- /tests/cmake_tests/lib/a.h: -------------------------------------------------------------------------------- 1 | struct A { 2 | int bar; 3 | void foo(int bar); 4 | }; 5 | -------------------------------------------------------------------------------- /tests/cmake_tests/test_a.cpp: -------------------------------------------------------------------------------- 1 | #include "a.h" 2 | 3 | int main(int argc, char const *argv[]) { 4 | A a; 5 | a.foo(10); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /tests/compilation_db_files/arguments/compile_commands.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "arguments": [ 4 | "c++", 5 | "-I/lib_include_dir", 6 | "-o", 7 | "CMakeFiles/main_obj.o", 8 | "-c", 9 | "/home/user/dummy_main.cpp" 10 | ], 11 | "directory": "/main_dir", 12 | "file": "/home/user/dummy_main.cpp" 13 | }, 14 | { 15 | "arguments": [ 16 | "c++", 17 | "-Dlib_EXPORTS", 18 | "-fPIC", 19 | "-o", 20 | "CMakeFiles/lib_obj.o", 21 | "-c", 22 | "/home/user/dummy_lib.cpp" 23 | ], 24 | "directory": "/lib_dir", 25 | "file": "/home/user/dummy_lib.cpp" 26 | } 27 | ] 28 | -------------------------------------------------------------------------------- /tests/compilation_db_files/command/compile_commands.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "directory": "/main_dir", 4 | "command": "c++ -I/lib_include_dir -o CMakeFiles/main_obj.o -c /home/user/dummy_main.cpp", 5 | "file": "/home/user/dummy_main.cpp" 6 | }, 7 | { 8 | "directory": "/lib_dir", 9 | "command": "c++ -Dlib_EXPORTS -fPIC -o CMakeFiles/lib_obj.o -c /home/user/dummy_lib.cpp", 10 | "file": "/home/user/dummy_lib.cpp" 11 | } 12 | ] 13 | -------------------------------------------------------------------------------- /tests/compilation_db_files/command_c/compile_commands.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "command": "cc -c -I/home/blah/clients -I/home/blah -I/home/blah/core/h -I/home/blah/network/h -I/home/blah/update/h -I/home/blah/h -I/home/blah/h -I/usr/include -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libsoup-2.4 -I/usr/include/libxml2 -I/usr/include -I/platform/include/fd655 -I/platform/include/ct1628 -I/home/blah/h -I/home/blah/fs/h -I/home/blah/network/h -I/home/blah/update/h -I/home/blah/update/h -Wall -Wno-unused-function -D_REENTRANT -DWITH_THREADS=1 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fgnu89-inline -fPIC -D_ALI_BUILD_ -D_GNU_SOURCE -shared-libgcc -std=gnu99 -march=armv7-a -mtune=cortex-a9 -DARMV7SP -ggdb -O2 -Werror -DDEVELOP -o -mfpu=vfp3 -mfloat-abi=softfp -mtune=cortex-a9 -march=armv7-a -Wno-poison-system-directories /home/blah/c/blah.c", 4 | "directory": "/home/blah", 5 | "file": "/home/blah.c" 6 | } 7 | ] 8 | -------------------------------------------------------------------------------- /tests/compilation_db_files/command_c_ccache/compile_commands.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "command": "ccache cc -c -I/home/blah/clients -I/home/blah -I/home/blah/core/h -I/home/blah/network/h -I/home/blah/update/h -I/home/blah/h -I/home/blah/h -I/usr/include -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libsoup-2.4 -I/usr/include/libxml2 -I/usr/include -I/platform/include/fd655 -I/platform/include/ct1628 -I/home/blah/h -I/home/blah/fs/h -I/home/blah/network/h -I/home/blah/update/h -I/home/blah/update/h -Wall -Wno-unused-function -D_REENTRANT -DWITH_THREADS=1 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fgnu89-inline -fPIC -D_ALI_BUILD_ -D_GNU_SOURCE -shared-libgcc -std=gnu99 -march=armv7-a -mtune=cortex-a9 -DARMV7SP -ggdb -O2 -Werror -DDEVELOP -o -mfpu=vfp3 -mfloat-abi=softfp -mtune=cortex-a9 -march=armv7-a -Wno-poison-system-directories /home/blah/c/blah.c", 4 | "directory": "/home/blah", 5 | "file": "/home/blah.c" 6 | } 7 | ] 8 | -------------------------------------------------------------------------------- /tests/compilation_db_files/command_c_ccache_irrelevant/compile_commands.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "command": "cc -c -I/home/blah/clients -I/home/blah -I/home/blah/core/h -I/home/blah/network/h -I/home/blah/update/h -I/home/blah/h -I/home/blah/h -I/usr/include -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libsoup-2.4 -I/usr/include/libxml2 -I/usr/include -I/platform/include/fd655 -I/platform/include/ct1628 -I/home/blah/h -I/home/blah/fs/h -I/home/blah/network/h -I/home/blah/update/h -I/home/blah/update/h -Wall -Wno-unused-function -D_REENTRANT -DWITH_THREADS=1 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fgnu89-inline -fPIC -D_ALI_BUILD_ -D_GNU_SOURCE -shared-libgcc -std=gnu99 -march=armv7-a -mtune=cortex-a9 -DARMV7SP -ggdb -O2 -Werror -DDEVELOP -o -mfpu=vfp3 -mfloat-abi=softfp -mtune=cortex-a9 -march=armv7-a -Wno-poison-system-directories ccache", 4 | "directory": "/home/blah", 5 | "file": "/home/blah.c" 6 | } 7 | ] 8 | -------------------------------------------------------------------------------- /tests/compilation_db_files/directory/compile_commands.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "arguments": [ 4 | "c++", 5 | "-I./include", 6 | "-I../../include", 7 | "-isystem", 8 | "../matilda", 9 | "test.cpp" 10 | ], 11 | "directory": "/foo/bar/test", 12 | "file": "test.cpp" 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /tests/gui_test_wrapper.py: -------------------------------------------------------------------------------- 1 | """Tests for cmake database generation.""" 2 | import sublime 3 | import time 4 | from unittest import TestCase 5 | 6 | from EasyClangComplete.plugin.utils.tools import PKG_NAME 7 | 8 | 9 | class GuiTestWrapper(TestCase): 10 | """A class that makes gui tests easier. 11 | 12 | Attributes: 13 | view (sublime.View): Current view. 14 | """ 15 | 16 | def setUp(self): 17 | """Prepare the view every run.""" 18 | # Ensure we have a window to work with. 19 | s = sublime.load_settings("Preferences.sublime-settings") 20 | s.set("close_windows_when_empty", False) 21 | s = sublime.load_settings(PKG_NAME + ".sublime-settings") 22 | s.set("verbose", True) 23 | s.set("cmake_flags_priority", "overwrite") 24 | self.view = None 25 | 26 | def tearDown(self): 27 | """Cleanup method run after every test.""" 28 | # If we have a view, close it. 29 | if self.view: 30 | self.view.set_scratch(True) 31 | self.view.window().focus_view(self.view) 32 | self.view.window().run_command("close_file") 33 | self.view = None 34 | 35 | def set_up_view(self, file_path=None, cursor_position=None): 36 | """Open the view and wait until its open. 37 | 38 | Args: 39 | file_path (str): The path to a file to open in a new view. 40 | cursor_position (ZeroIndexedRowCol): row and column of the cursor. 41 | """ 42 | # Open the view. 43 | if file_path: 44 | self.view = sublime.active_window().open_file(file_path) 45 | else: 46 | self.view = sublime.active_window().new_file() 47 | self.view.settings().set("disable_easy_clang_complete", True) 48 | 49 | # Ensure it's loaded. 50 | while self.view.is_loading(): 51 | time.sleep(0.1) 52 | 53 | if cursor_position: 54 | self.view.sel().clear() 55 | self.view.sel().add( 56 | sublime.Region(cursor_position.as_1d_location(self.view))) 57 | 58 | def get_row(self, row): 59 | """Get text of a particular row. 60 | 61 | Args: 62 | row (int): number of row 63 | 64 | Returns: 65 | str: row contents 66 | """ 67 | return self.view.substr(self.view.line(self.view.text_point(row, 0))) 68 | 69 | def check_view(self, file_path): 70 | """Test that setup view correctly sets up the view.""" 71 | self.set_up_view(file_path) 72 | 73 | self.assertEqual(self.view.file_name(), file_path) 74 | file = open(file_path, 'r') 75 | row = 0 76 | line = file.readline() 77 | while line: 78 | self.assertEqual(line[:-1], self.get_row(row)) 79 | row += 1 80 | line = file.readline() 81 | file.close() 82 | -------------------------------------------------------------------------------- /tests/makefile_files/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | /app 4 | -------------------------------------------------------------------------------- /tests/makefile_files/Makefile: -------------------------------------------------------------------------------- 1 | INCLUDES = -Iinc 2 | CPPFLAGS = -DREQUIRED_DEFINE 3 | CC = clang 4 | 5 | app : main.c inc/bar.h 6 | $(MAKE) -C lib 7 | $(CC) $(INCLUDES) $(CPPFLAGS) -o $@ main.c lib/libbar.a 8 | 9 | clean : 10 | $(MAKE) -C lib clean 11 | rm app 12 | -------------------------------------------------------------------------------- /tests/makefile_files/inc/bar.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef REQUIRED_DEFINE 3 | # error missing required define 4 | #endif 5 | 6 | int bar(const char *str); 7 | -------------------------------------------------------------------------------- /tests/makefile_files/lib/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS = -Ifoo 2 | CPPFLAGS = -DREQUIRED_DEFINE 3 | CC = clang 4 | AR = ar 5 | 6 | libbar.a : bar.o foo.o 7 | $(AR) rcs $@ $? 8 | 9 | foo.o : foo/foo.h foo/foo.c 10 | $(CC) $(CFLAGS) -c -o $@ foo/foo.c 11 | 12 | bar.o : bar.c 13 | $(CC) $(CFLAGS) -c -o $@ bar.c 14 | 15 | clean : 16 | rm *.o *.a 17 | -------------------------------------------------------------------------------- /tests/makefile_files/lib/bar.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int bar(const char *str) 5 | { 6 | return foo(strlen(str), 3); 7 | } 8 | -------------------------------------------------------------------------------- /tests/makefile_files/lib/foo/foo.c: -------------------------------------------------------------------------------- 1 | #include "foo.h" 2 | 3 | int foo(int len, int magic) 4 | { 5 | return len % magic; 6 | } 7 | -------------------------------------------------------------------------------- /tests/makefile_files/lib/foo/foo.h: -------------------------------------------------------------------------------- 1 | int foo(int len, int magic); 2 | -------------------------------------------------------------------------------- /tests/makefile_files/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | int main(int argc, const char *argv[]) 6 | { 7 | printf("%s: %d\n", argv[0], bar(argv[0])); 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /tests/test_CppProperties.py: -------------------------------------------------------------------------------- 1 | """Test CppProperties flags generation.""" 2 | import imp 3 | import platform 4 | from os import path, environ 5 | from unittest import TestCase 6 | 7 | from EasyClangComplete.plugin.flags_sources import CppProperties 8 | from EasyClangComplete.plugin.utils import tools 9 | from EasyClangComplete.plugin.utils import flag 10 | from EasyClangComplete.plugin.utils import file 11 | from EasyClangComplete.plugin.utils import search_scope 12 | 13 | imp.reload(CppProperties) 14 | imp.reload(tools) 15 | imp.reload(flag) 16 | imp.reload(file) 17 | imp.reload(search_scope) 18 | 19 | CppProperties = CppProperties.CppProperties 20 | SearchScope = search_scope.TreeSearchScope 21 | Flag = flag.Flag 22 | File = file.File 23 | 24 | 25 | def _get_test_folder(name): 26 | return path.join(path.dirname(__file__), 'CppProperties_files', name) 27 | 28 | 29 | class TestCppProperties(TestCase): 30 | """Test generating flags with a 'CppProperties.json' file.""" 31 | 32 | def test_get_all_flags(self): 33 | """Test if CppProperties.json is found.""" 34 | include_prefixes = ['-I'] 35 | db = CppProperties(include_prefixes) 36 | 37 | expected = [ 38 | Flag('-I', path.normpath('/folder/include/path')), 39 | Flag('-I', path.normpath('/another/file/path')), 40 | ] 41 | 42 | scope = SearchScope(from_folder=_get_test_folder('simple')) 43 | self.assertEqual(expected, db.get_flags(search_scope=scope)) 44 | 45 | def test_expand_environment_variables(self): 46 | """Test environment variables are expanded.""" 47 | include_prefixes = ['-I'] 48 | db = CppProperties(include_prefixes) 49 | environ['TEST_VARIABLE_TO_EXPAND'] = '/lib_include_dir' 50 | 51 | expected = [ 52 | Flag('-I', path.normpath('/lib_include_dir')), 53 | ] 54 | 55 | scope = SearchScope(from_folder=_get_test_folder('environment')) 56 | self.assertEqual(expected, db.get_flags(search_scope=scope)) 57 | 58 | def test_no_db_in_folder(self): 59 | """Test if no json is found.""" 60 | if platform.system() == "Darwin": 61 | # This test is disabled as the current path is trying to reach a 62 | # network resource on MacOS. I guess we have to deal with this at 63 | # some point later. 64 | return 65 | include_prefixes = ['-I'] 66 | db = CppProperties(include_prefixes) 67 | 68 | expected = None 69 | 70 | self.assertEqual(expected, db.get_flags( 71 | File.canonical_path('/home/user/dummy_main.cpp'))) 72 | 73 | def test_empty_include_and_defines(self): 74 | """Test that empty fields are handled correctly.""" 75 | include_prefixes = ['-I'] 76 | db = CppProperties(include_prefixes) 77 | 78 | expected = [] 79 | 80 | scope = SearchScope(from_folder=_get_test_folder('empty')) 81 | self.assertEqual(expected, db.get_flags(search_scope=scope)) 82 | -------------------------------------------------------------------------------- /tests/test_c_cpp_properties.py: -------------------------------------------------------------------------------- 1 | """Test c_cpp_properties flags generation.""" 2 | import imp 3 | import platform 4 | from os import path, environ 5 | from unittest import TestCase 6 | 7 | from EasyClangComplete.plugin.flags_sources import c_cpp_properties 8 | from EasyClangComplete.plugin.utils import tools 9 | from EasyClangComplete.plugin.utils import flag 10 | from EasyClangComplete.plugin.utils import file 11 | from EasyClangComplete.plugin.utils import search_scope 12 | 13 | 14 | imp.reload(c_cpp_properties) 15 | imp.reload(tools) 16 | imp.reload(flag) 17 | imp.reload(file) 18 | imp.reload(search_scope) 19 | 20 | CCppProperties = c_cpp_properties.CCppProperties 21 | SearchScope = search_scope.TreeSearchScope 22 | Flag = flag.Flag 23 | File = file.File 24 | 25 | 26 | class TestCCppProperties(TestCase): 27 | """Test generating flags with a 'c_cpp_properties.json' file.""" 28 | 29 | def test_get_all_flags(self): 30 | """Test if c_cpp_properties.json is found.""" 31 | include_prefixes = ['-I'] 32 | db = CCppProperties(include_prefixes) 33 | 34 | expected = [Flag('-I', path.normpath('/lib_include_dir')), 35 | Flag('', '-Dlib_EXPORTS')] 36 | path_to_db = path.join(path.dirname(__file__), 37 | 'c_cpp_properties_files', 38 | 'simple') 39 | scope = SearchScope(from_folder=path_to_db) 40 | self.assertEqual(expected, db.get_flags(search_scope=scope)) 41 | 42 | def test_expand_environment_variables(self): 43 | """Test environment variables are expanded.""" 44 | include_prefixes = ['-I'] 45 | db = CCppProperties(include_prefixes) 46 | environ['TEST_VARIABLE_TO_EXPAND'] = '/lib_include_dir' 47 | 48 | expected = [Flag('-I', path.normpath('/lib_include_dir')), 49 | Flag('', '-Dlib_EXPORTS')] 50 | path_to_db = path.join(path.dirname(__file__), 51 | 'c_cpp_properties_files', 52 | 'environment') 53 | scope = SearchScope(from_folder=path_to_db) 54 | print(scope) 55 | self.assertEqual(expected, db.get_flags(search_scope=scope)) 56 | 57 | def test_no_db_in_folder(self): 58 | """Test if no json is found.""" 59 | if platform.system() == "Darwin": 60 | # This test is disabled as the current path is trying to reach a 61 | # network resource on MacOS. I guess we have to deal with this at 62 | # some point later. 63 | return 64 | include_prefixes = ['-I'] 65 | db = CCppProperties(include_prefixes) 66 | 67 | flags = db.get_flags(File.canonical_path('/home/user/dummy_main.cpp')) 68 | self.assertTrue(flags is None) 69 | 70 | def test_empty_include_and_defines(self): 71 | """Test that empty fields are handled correctly.""" 72 | include_prefixes = ['-I'] 73 | db = CCppProperties(include_prefixes) 74 | 75 | expected = [] 76 | path_to_db = path.join(path.dirname(__file__), 77 | 'c_cpp_properties_files', 78 | 'empty') 79 | scope = SearchScope(from_folder=path_to_db) 80 | self.assertEqual(expected, db.get_flags(search_scope=scope)) 81 | -------------------------------------------------------------------------------- /tests/test_catkinizer.py: -------------------------------------------------------------------------------- 1 | """Test compilation database flags generation.""" 2 | import imp 3 | import sublime 4 | import platform 5 | 6 | from os import path 7 | 8 | from EasyClangComplete.tests.gui_test_wrapper import GuiTestWrapper 9 | from EasyClangComplete.plugin.utils import catkinizer 10 | from EasyClangComplete.plugin.utils import file 11 | imp.reload(file) 12 | imp.reload(catkinizer) 13 | 14 | Catkinizer = catkinizer.Catkinizer 15 | File = file.File 16 | 17 | 18 | class BaseTestCatkinizer(object): 19 | """Test unique list.""" 20 | 21 | def setUp(self): 22 | """Prepare the view and store the settings.""" 23 | super(BaseTestCatkinizer, self).setUp() 24 | self.__project_data_backup = sublime.active_window().project_data() 25 | if not sublime.active_window().project_data(): 26 | # Load a file and put it into current data. 27 | project_file = path.join(path.dirname(__file__), 28 | '..', 29 | 'easy_clang_complete.sublime-project') 30 | import json 31 | with open(project_file) as f: 32 | project_json = json.load(f) 33 | sublime.active_window().set_project_data(project_json) 34 | 35 | def tearDown(self): 36 | """Restore project settings and close the view.""" 37 | sublime.active_window().set_project_data(self.__project_data_backup) 38 | super(BaseTestCatkinizer, self).tearDown() 39 | 40 | def test_init(self): 41 | """Test initialization.""" 42 | test_file = File( 43 | path.join(path.dirname(__file__), 'cmake_tests', 'CMakeLists.txt')) 44 | catkinizer = Catkinizer(test_file) 45 | self.assertEqual(catkinizer._Catkinizer__cmake_file.full_path, 46 | test_file.full_path) 47 | 48 | def test_setting_getting_project_data(self): 49 | """Test setting and getting project data.""" 50 | self.assertEqual(sublime.active_window().project_data(), 51 | Catkinizer._Catkinizer__get_sublime_project_data()) 52 | Catkinizer._Catkinizer__save_sublime_project_data({}) 53 | self.assertEqual(sublime.active_window().project_data(), {}) 54 | 55 | def test_get_ros_distro_path(self): 56 | """Check that we can get the paths to ros. 57 | 58 | Here we just check that we get the first path from a given folder.""" 59 | cmake_tests_folder = path.join(path.dirname(__file__), 'cmake_tests') 60 | print(cmake_tests_folder) 61 | picked = Catkinizer._Catkinizer__get_ros_distro_path( 62 | cmake_tests_folder + '/*') 63 | self.assertEqual(path.dirname(picked), cmake_tests_folder) 64 | 65 | def test_get_cmake_entry(self): 66 | """Get cmake entry.""" 67 | project_data = Catkinizer._Catkinizer__get_sublime_project_data() 68 | settings_entry = project_data[Catkinizer._SETTINGS_TAG] 69 | flags_sources = settings_entry[Catkinizer._FLAGS_SOURCES_TAG] 70 | cmake_entry = Catkinizer._Catkinizer__get_cmake_entry(flags_sources) 71 | expected_entry = { 72 | "file": "CMakeLists.txt", 73 | "flags": 74 | [ 75 | "-DCMAKE_BUILD_TYPE=Release", 76 | "-D XXXX=ON" 77 | ], 78 | "prefix_paths": 79 | [ 80 | "/opt/ros/indigo", 81 | "~/Code/catkin_ws/devel", 82 | "$project_base_path/catkin_ws/devel", 83 | ] 84 | } 85 | self.assertEqual(cmake_entry, expected_entry) 86 | 87 | def test_get_catkin_ws(self): 88 | """Test getting a catkin workspace.""" 89 | catkin_proj_cmake_file = File( 90 | path.join(path.dirname(__file__), 91 | 'catkin_tests', 92 | 'catkin_ws', 93 | 'src', 94 | 'project', 95 | 'CMakeLists.txt')) 96 | catkinizer = Catkinizer(catkin_proj_cmake_file) 97 | ws_path = catkinizer._Catkinizer__get_catkin_workspace_path() 98 | catkin_ws = path.join(path.dirname(__file__), 99 | 'catkin_tests', 'catkin_ws', 'devel') 100 | catkin_ws = catkin_ws.replace(path.expanduser('~'), '~', 1) 101 | self.assertEqual(ws_path, catkin_ws) 102 | 103 | 104 | print(platform.system()) 105 | if platform.system() is not 'Windows': 106 | class TestCatkinizer(BaseTestCatkinizer, GuiTestWrapper): 107 | """Test class for the binary based completer.""" 108 | pass 109 | -------------------------------------------------------------------------------- /tests/test_clang_complete_file.py: -------------------------------------------------------------------------------- 1 | """Tests for cmake database generation. 2 | 3 | Attributes: 4 | FlagsFile (TYPE): Description 5 | """ 6 | import imp 7 | from os import path 8 | from unittest import TestCase 9 | 10 | from EasyClangComplete.plugin.flags_sources import flags_file 11 | from EasyClangComplete.plugin.utils import flag 12 | from EasyClangComplete.plugin.utils import search_scope 13 | 14 | imp.reload(flags_file) 15 | imp.reload(flag) 16 | imp.reload(search_scope) 17 | 18 | SearchScope = search_scope.TreeSearchScope 19 | 20 | FlagsFile = flags_file.FlagsFile 21 | 22 | Flag = flag.Flag 23 | 24 | 25 | class TestFlagsFile(TestCase): 26 | """Test finding and generatgin flags from .clang_complete file. 27 | 28 | Attributes: 29 | view (TYPE): Description 30 | """ 31 | 32 | def test_init(self): 33 | """Initialization test.""" 34 | self.assertEqual(FlagsFile._FILE_NAME, '.clang_complete') 35 | 36 | def test_load_file(self): 37 | """Test finding and loading existing file.""" 38 | test_file_path = path.join( 39 | path.dirname(__file__), 'test_files', 'test.cpp') 40 | 41 | flags_file = FlagsFile(['-I', '-isystem']) 42 | flags = flags_file.get_flags(test_file_path) 43 | # This flag only exists in .clang_complete to help us test that 44 | # we can read the flag. 45 | self.assertIn(Flag('', '-Wabi'), flags) 46 | 47 | def test_fail_to_find(self): 48 | """Test failing to find a .clang_complete file.""" 49 | test_file_path = path.join( 50 | path.dirname(__file__), 'test_files', 'test.cpp') 51 | 52 | folder = path.dirname(test_file_path) 53 | flags_file = FlagsFile(['-I', '-isystem']) 54 | wrong_scope = SearchScope(from_folder=folder, to_folder=folder) 55 | flags = flags_file.get_flags(test_file_path, wrong_scope) 56 | self.assertIs(flags, None) 57 | -------------------------------------------------------------------------------- /tests/test_clang_utils.py: -------------------------------------------------------------------------------- 1 | """Test clang utilities.""" 2 | import imp 3 | from unittest import TestCase 4 | 5 | from EasyClangComplete.plugin.utils import clang_utils 6 | 7 | imp.reload(clang_utils) 8 | 9 | ClangUtils = clang_utils.ClangUtils 10 | 11 | 12 | class test_clang_utils(TestCase): 13 | """Test other things.""" 14 | 15 | def test_get_cindex(self): 16 | """Test that we get a correct clang module.""" 17 | module = ClangUtils.get_cindex_module_for_version("3.8") 18 | self.assertTrue(module.endswith('cindex38')) 19 | module = ClangUtils.get_cindex_module_for_version("9.0") 20 | self.assertTrue(module.endswith('cindex50')) 21 | # Check that we return the latest cindex for unsupported ones. 22 | module = ClangUtils.get_cindex_module_for_version("999.0") 23 | self.assertTrue(module.endswith('cindex50')) 24 | 25 | def test_get_apple_version(self): 26 | """Test that we get a correct clang module.""" 27 | apple_version_output = 'Apple LLVM version 10.0.1' 28 | version = ClangUtils._get_apple_clang_version_str(apple_version_output) 29 | self.assertEquals(version, '6.0') 30 | # Check that we are pretty future proof. 31 | apple_version_output = 'Apple LLVM version 99.0.1' 32 | version = ClangUtils._get_apple_clang_version_str(apple_version_output) 33 | self.assertEquals(version, '7.0') 34 | 35 | def test_get_all_possible_filenames(self): 36 | """Test that we get a correct clang module.""" 37 | all_paths = ClangUtils.get_all_possible_filenames('3.8') 38 | self.assertGreater(len(all_paths), 0) 39 | for path in all_paths: 40 | self.assertNotIn('$version', path) 41 | 42 | def test_find_libclang(self): 43 | """Test that we get a correct clang module.""" 44 | version_str = ClangUtils.get_clang_version_str('clang++') 45 | libclang_dir, full_libclang_path = ClangUtils.find_libclang( 46 | 'clang++', 'blah', version_str) 47 | self.assertIsNotNone(libclang_dir) 48 | self.assertIsNotNone(full_libclang_path) 49 | from os import path 50 | self.assertEquals(path.dirname(full_libclang_path), libclang_dir) 51 | -------------------------------------------------------------------------------- /tests/test_docs.py: -------------------------------------------------------------------------------- 1 | """Test that all docs are there.""" 2 | from os import path 3 | from unittest import TestCase 4 | 5 | 6 | def parse_code_headers(md_file_path): 7 | """Parse all settings names from the markdown.""" 8 | import re 9 | all_settings_headers_regex = re.compile(r"###\s\*\*`(\w+)`\*\*.*") 10 | with open(md_file_path) as f: 11 | contents = f.read() 12 | matches = all_settings_headers_regex.findall(contents) 13 | return matches 14 | 15 | 16 | def parse_settings(json_file_path): 17 | """Parse all settings names from the json file.""" 18 | import re 19 | all_settings_regex = re.compile(r'^ "(\w+)"\s*:.+$', flags=re.MULTILINE) 20 | with open(json_file_path) as f: 21 | contents = f.read() 22 | matches = all_settings_regex.findall(contents) 23 | return matches 24 | 25 | 26 | class TestSomething(TestCase): 27 | """Test that the settings have descriptions in the docs.""" 28 | 29 | def test_all_settings(self): 30 | """Test that all settings have docs.""" 31 | project_folder = path.dirname(path.dirname(__file__)) 32 | md_file = path.join(project_folder, 'docs', 'settings.md') 33 | settings_file = path.join( 34 | project_folder, 'EasyClangComplete.sublime-settings') 35 | self.assertEqual(set(parse_code_headers(md_file)), 36 | set(parse_settings(settings_file))) 37 | -------------------------------------------------------------------------------- /tests/test_files/Makefile.cmake: -------------------------------------------------------------------------------- 1 | # CMAKE generated file: DO NOT EDIT! 2 | # Generated by "Unix Makefiles" Generator, CMake Version 3.5 3 | 4 | # The generator used is: 5 | set(CMAKE_DEPENDS_GENERATOR "Unix Makefiles") 6 | 7 | # The top level Makefile was generated from the following files: 8 | set(CMAKE_MAKEFILE_DEPENDS 9 | "CMakeCache.txt" 10 | "/usr/share/cmake-3.5/Modules/CMakeCCompiler.cmake.in" 11 | "/usr/share/cmake-3.5/Modules/Platform/UnixPaths.cmake" 12 | ) 13 | 14 | # The corresponding makefile is: 15 | set(CMAKE_MAKEFILE_OUTPUTS 16 | "Makefile" 17 | "CMakeFiles/cmake.check_cache" 18 | ) 19 | 20 | # Byproducts of CMake generate step: 21 | set(CMAKE_MAKEFILE_PRODUCTS 22 | "CMakeFiles/3.5.1/CMakeSystem.cmake" 23 | "lib/CMakeFiles/CMakeDirectoryInformation.cmake" 24 | ) 25 | 26 | # Dependency information for all targets: 27 | set(CMAKE_DEPEND_INFO_FILES 28 | "CMakeFiles/test_a.dir/DependInfo.cmake" 29 | "lib/CMakeFiles/liba.dir/DependInfo.cmake" 30 | ) 31 | -------------------------------------------------------------------------------- /tests/test_files/test.cpp: -------------------------------------------------------------------------------- 1 | class A { 2 | int a; 3 | void foo(int a); 4 | public: 5 | void foo(double a); 6 | }; 7 | int main(int argc, char const *argv[]) { 8 | A a; 9 | a. 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /tests/test_files/testTemplatesManual.cpp: -------------------------------------------------------------------------------- 1 | /// File using several C++ libraries with templated types, 2 | /// useful for manual testing of popup info by hovering over code. 3 | /// Not added to auto-testing because popups include 4 | /// libC++ implementation details that can change without warning, 5 | /// making it difficult to test for correct info in the popups. 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | class A { 13 | int a; 14 | void foo(int a); 15 | public: 16 | void foo(double a); 17 | 18 | template 19 | int bar() { return BarTemplateParameter;} 20 | 21 | template 22 | void barTemp3(); 23 | 24 | template 25 | int barM(std::shared_ptr a, const std::shared_ptr& aConst) { return M;} 26 | 27 | std::shared_ptr& barNoTempl( 28 | std::shared_ptr sharedPtr, 29 | const std::shared_ptr& constRefToSharedPtr, 30 | std::shared_ptr&& rValueRefToSharedPtr); 31 | }; 32 | 33 | 34 | template 35 | class Templated { 36 | }; 37 | 38 | template 39 | class TemplatedTwo { 40 | }; 41 | 42 | int main(int argc, char const *argv[]) { 43 | std::shared_ptr pointerToA; 44 | pointerToA.reset(); 45 | pointerToA->bar<5>(); 46 | pointerToA->barTemp3(); 47 | pointerToA->barM<5>(pointerToA, pointerToA); 48 | pointerToA.reset(pointerToA.get()); 49 | std::pair, std::string> myPair; 50 | myPair.first = nullptr; 51 | 52 | A justA; 53 | A& refA = justA; 54 | A* ptrA; 55 | A*& ptrRefA = ptrA; 56 | A&& rvalueRefA = std::move(justA); 57 | Templated templatedInt; 58 | Templated templatedA; 59 | Templated templatedOnARvalueRef; 60 | Templated*>* templatedSharedPtrARvalueRef; 61 | Templated&& templatedARValueRef = std::move(templatedA); 62 | Templated templatedAPtr; 63 | Templated& templatedAPtrRef = templatedAPtr; 64 | Templated> templatedSharedPtrAPtr; 65 | Templated> templatedConstSharedPtrAPtr; 66 | Templated*>* templatedConstSharedPtrAPtrPtr; 67 | Templated> templatedSharedPtrA; 68 | Templated> templatedSharedPtrConstA; 69 | Templated> templatedConstSharedPtrConstA; 70 | 71 | TemplatedTwo templatedTwoAA; 72 | TemplatedTwo, const std::shared_ptr*> templatedTwoSharedConstA_ConstSharedPtrPointer; 73 | A a; 74 | a.foo(2.0); 75 | 76 | std::array arraySize5; 77 | 78 | auto lambda = [](std::shared_ptr a) { 79 | return a; 80 | }; 81 | lambda(pointerToA); 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /tests/test_files/test_changes.cpp: -------------------------------------------------------------------------------- 1 | int main(int argc, char const *argv[]) { 2 | /* code */ 3 | return 0; 4 | } 5 | -------------------------------------------------------------------------------- /tests/test_files/test_errors.cpp: -------------------------------------------------------------------------------- 1 | int main(int argc, char const *argv[]) { 2 | foo. 3 | return 0; 4 | } 5 | -------------------------------------------------------------------------------- /tests/test_files/test_info.cpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | /// @brief Class for my cool class. 3 | /// 4 | class MyCoolClass { 5 | public: 6 | /** 7 | * @brief This is short. 8 | * 9 | * And this is a full comment. 10 | * 11 | * @param[in] a param a 12 | * @param[in] b param b 13 | */ 14 | void foo(int a, int b); 15 | }; 16 | 17 | int main(int argc, char const *argv[]) { 18 | MyCoolClass cool_class; 19 | cool_class.foo(2, 2); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /tests/test_files/test_info_arguments_link.cpp: -------------------------------------------------------------------------------- 1 | class Foo {}; 2 | 3 | class MyCoolClass { 4 | public: 5 | void foo(Foo a, Foo* b); 6 | }; 7 | 8 | int main(int argc, char const *argv[]) { 9 | MyCoolClass cool_class; 10 | cool_class.foo(Foo(), nullptr); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /tests/test_files/test_location.cpp: -------------------------------------------------------------------------------- 1 | class MyCoolClass { 2 | public: 3 | void foo() { 4 | // Do nothing. 5 | } 6 | }; 7 | 8 | int main(int argc, char const *argv[]) { 9 | MyCoolClass cool_class; 10 | cool_class.foo(); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /tests/test_files/test_method_one_parameter.m: -------------------------------------------------------------------------------- 1 | #include 2 | @interface Foo : NSObject 3 | -(void) oneParameterMethod:(BOOL)boolParam; 4 | @end 5 | int main(int argc, char const *argv[]) { 6 | Foo* foo = [[Foo alloc] init]; 7 | [foo 8 | } 9 | 10 | -------------------------------------------------------------------------------- /tests/test_files/test_method_two_parameters.m: -------------------------------------------------------------------------------- 1 | #include 2 | @interface Foo : NSObject 3 | -(NSInteger*) bar:(BOOL)b1 strParam:(NSString*)str1; 4 | @end 5 | int main(int argc, char const *argv[]) { 6 | Foo* foo = [[Foo alloc] init]; 7 | [foo 8 | } 9 | -------------------------------------------------------------------------------- /tests/test_files/test_objective_c.m: -------------------------------------------------------------------------------- 1 | // A bunch of different types of protocols/methods 2 | 3 | #import 4 | #import 5 | 6 | @class Foo; 7 | 8 | @protocol Protocol 9 | -(void)protocolMethodVoidNoParameters; ///< Has a brief comment 10 | -(BOOL)protocolMethodBoolNoParameters; 11 | -(void)protocolMethodVoidOneStringParameter:(NSString*)s1; 12 | -(void)protocolMethodVoidTwoStringParameters:(NSString*)s1 13 | stringParam2:(NSString*)s2; 14 | +(void)protocolClassMethod; 15 | @property (assign) BOOL protocolPropertyBool; 16 | @end 17 | 18 | @interface Interface : NSObject 19 | -(void)interfaceMethodVoidNoParameters; ///< Brief comment. 20 | -(BOOL)interfaceMethodBoolNoParameters; 21 | -(void)interfaceMethodVoidOneStringParameter:(NSString*)s1; 22 | -(void)interfaceMethodVoidTwoStringParameters:(NSString*)s1 23 | stringParam2:(NSString*)s2; 24 | -(void)interfaceMethodVoidTwoParametersSecondUnnamed:(int)int1 25 | :(int)int2; 26 | +(Foo*)interfaceClassMethodFooTwoFooParameters:(Foo*)f1 27 | fooParam2:(Foo*)f2; 28 | @property (assign) NSString* interfacePropertyString; 29 | @end 30 | 31 | @implementation Interface 32 | @synthesize protocolPropertyBool; 33 | 34 | -(void)interfaceMethodVoidNoParameters {} 35 | -(BOOL)interfaceMethodBoolNoParameters { return YES; } 36 | -(void)interfaceMethodVoidOneStringParameter:(NSString*)s1 {} 37 | -(void)interfaceMethodVoidTwoStringParameters:(NSString*)s1 38 | stringParam2:(NSString*)s2 {} 39 | -(void)interfaceMethodVoidTwoParametersSecondUnnamed:(int)int1 40 | :(int)int2 {} 41 | +(Foo*)interfaceClassMethodFooTwoFooParameters:(Foo*)f1 42 | fooParam2:(Foo*)f2 { return nil; } 43 | 44 | -(void)protocolMethodVoidNoParameters {} 45 | -(BOOL)protocolMethodBoolNoParameters { return YES; } 46 | -(void)protocolMethodVoidOneStringParameter:(NSString*)s1 {} 47 | -(void)protocolMethodVoidTwoStringParameters:(NSString*)s1 48 | stringParam2:(NSString*)s2 {} 49 | +(void)protocolClassMethod {} 50 | 51 | @end 52 | 53 | @interface Interface (Category) 54 | -(void)categoryMethodVoidNoParameters; 55 | @end 56 | 57 | @implementation Interface (Category) 58 | -(void)categoryMethodVoidNoParameters{} 59 | @end 60 | 61 | /// Just a bunch of calls used to help manually test tooltip popups 62 | int main(int argc, const char * argv[]) 63 | { 64 | Interface* interface = [[Interface alloc] init]; 65 | 66 | [interface interfaceMethodVoidNoParameters]; 67 | [interface interfaceMethodBoolNoParameters]; 68 | [interface interfaceMethodVoidOneStringParameter:nil]; 69 | [interface interfaceMethodVoidTwoStringParameters:nil stringParam2:nil]; 70 | [interface interfaceMethodVoidTwoParametersSecondUnnamed:0 :0]; 71 | [Interface interfaceClassMethodFooTwoFooParameters:nil fooParam2:nil]; 72 | interface.interfacePropertyString = nil; 73 | 74 | [interface protocolMethodVoidNoParameters]; 75 | [interface protocolMethodBoolNoParameters]; 76 | [interface protocolMethodVoidOneStringParameter:nil]; 77 | [interface protocolMethodVoidTwoStringParameters:nil stringParam2:nil]; 78 | [Interface protocolClassMethod]; 79 | interface.protocolPropertyBool = YES; 80 | 81 | [interface categoryMethodVoidNoParameters]; 82 | 83 | [interface performSelector:@selector(interfaceMethodVoidNoParameters)]; 84 | 85 | id protocol = nil; 86 | [protocol protocolMethodVoidNoParameters]; 87 | [protocol protocolMethodBoolNoParameters]; 88 | [protocol protocolMethodVoidOneStringParameter:nil]; 89 | [protocol protocolMethodVoidTwoStringParameters:nil stringParam2:nil]; 90 | 91 | interface. 92 | NSLog(@"Hello world"); 93 | 94 | return 0; 95 | } 96 | 97 | -------------------------------------------------------------------------------- /tests/test_files/test_objective_c_covariant.m: -------------------------------------------------------------------------------- 1 | #import 2 | @class Foo; 3 | @interface MyCovariant<__covariant ObjectType> : NSObject 4 | -(MyCovariant*)covariantMethod; 5 | @end 6 | -------------------------------------------------------------------------------- /tests/test_files/test_objective_cpp.mm: -------------------------------------------------------------------------------- 1 | #include 2 | int main(int argc, char const *argv[]) { 3 | std::string str; 4 | str. 5 | } 6 | -------------------------------------------------------------------------------- /tests/test_files/test_property.m: -------------------------------------------------------------------------------- 1 | #include 2 | @interface Foo : NSObject 3 | @property BOOL boolProperty; 4 | @end 5 | int main(int argc, char const *argv[]) { 6 | Foo* foo = [[Foo alloc] init]; 7 | foo. 8 | } 9 | -------------------------------------------------------------------------------- /tests/test_files/test_templates.cpp: -------------------------------------------------------------------------------- 1 | class Foo; 2 | template 3 | class TemplateClass 4 | { 5 | public: 6 | void foo(TemplateClass); 7 | }; 8 | int main(int argc, char const *argv[]) { 9 | TemplateClass instanceClassTypeInt; 10 | TemplateClass instanceClassAndDefaults; 11 | TemplateClass> instanceNested; 12 | TemplateClass instancePointer; 13 | TemplateClass instanceRef; 14 | TemplateClass instanceRValueRef; 15 | instanceRValueRef.foo(instanceRValueRef); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /tests/test_files/test_unicode.cpp: -------------------------------------------------------------------------------- 1 | // This file has some unicode characters in the comments 2 | // that should not disrupt ECC 3 | // ` © 4 | class Foo {}; 5 | int main(int argc, char const *argv[]) { 6 | Foo foo; 7 | } 8 | -------------------------------------------------------------------------------- /tests/test_files/test_vector.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | int main(int argc, char const *argv[]) { 3 | std::vector vec; 4 | vec. 5 | } 6 | -------------------------------------------------------------------------------- /tests/test_files/test_void_method.m: -------------------------------------------------------------------------------- 1 | #include 2 | @interface Foo : NSObject 3 | -(void) voidMethod; 4 | @end 5 | int main(int argc, char const *argv[]) { 6 | Foo* foo = [[Foo alloc] init]; 7 | [foo 8 | } 9 | 10 | -------------------------------------------------------------------------------- /tests/test_files/test_wrong_triggers.cpp: -------------------------------------------------------------------------------- 1 | int main(int argc, char const *argv[]) { 2 | int a = 2; 3 | a > 2. 4 | } -------------------------------------------------------------------------------- /tests/test_flag.py: -------------------------------------------------------------------------------- 1 | """Tests for flag class.""" 2 | import imp 3 | from unittest import TestCase 4 | 5 | from EasyClangComplete.plugin.utils import flag 6 | 7 | imp.reload(flag) 8 | 9 | Flag = flag.Flag 10 | 11 | 12 | class TestFlag(TestCase): 13 | """Test getting flags from CMakeLists.txt.""" 14 | 15 | def test_init(self): 16 | """Initialization test.""" 17 | flag = Flag.Builder().from_unparsed_string("-Ihello").build() 18 | self.assertEqual(flag.as_list(), ["-I", "hello"]) 19 | self.assertEqual(flag.prefix, "-I") 20 | self.assertEqual(flag.body, "hello") 21 | self.assertEqual(str(flag), "-Ihello") 22 | flag = Flag("hello", "world", " ") 23 | self.assertEqual(flag.as_list(), ["hello", "world"]) 24 | self.assertEqual(flag.prefix, "hello") 25 | self.assertEqual(flag.body, "world") 26 | self.assertEqual(flag.separator, " ") 27 | self.assertEqual(str(flag), "hello world") 28 | 29 | def test_hash(self): 30 | """Test that hash is always the same when needed.""" 31 | flag1 = Flag("hello", "world") 32 | flag2 = Flag("hello", "world") 33 | flag3 = Flag("world", "hello") 34 | self.assertEqual(hash(flag1), hash(flag2)) 35 | self.assertNotEqual(hash(flag1), hash(flag3)) 36 | 37 | def test_put_into_container(self): 38 | """Test adding to hashed container.""" 39 | flags_set = set() 40 | flag1 = Flag("", "hello") 41 | flag2 = Flag("", "world") 42 | flag3 = Flag("hello", "world") 43 | flag4 = Flag("world", "hello") 44 | flags_set.add(flag1) 45 | flags_set.add(flag2) 46 | flags_set.add(flag3) 47 | self.assertIn(flag1, flags_set) 48 | self.assertIn(flag2, flags_set) 49 | self.assertIn(flag3, flags_set) 50 | self.assertNotIn(flag4, flags_set) 51 | 52 | def test_tokenize(self): 53 | """Test tokenizing a list of all split flags.""" 54 | split_str = ["-I", "hello", "-Iblah", "-isystem", "world"] 55 | list_of_flags = Flag.tokenize_list(split_str) 56 | self.assertTrue(len(list_of_flags), 3) 57 | self.assertIn(Flag("-I", "hello", " "), list_of_flags) 58 | self.assertIn(Flag("-I", "blah"), list_of_flags) 59 | self.assertIn(Flag("-isystem", "world", " "), list_of_flags) 60 | 61 | def test_builder(self): 62 | """Test tokenizing a list of all split flags.""" 63 | flag1 = Flag.Builder().with_prefix('hello').with_body('world').build() 64 | self.assertEqual(Flag("hello", "world"), flag1) 65 | flag3 = Flag.Builder().from_unparsed_string('-Iworld').build() 66 | self.assertEqual(Flag("-I", "world"), flag3) 67 | flag4 = Flag.Builder().from_unparsed_string('-include world').build() 68 | self.assertEqual(Flag("-include", "world", " "), flag4) 69 | # Check that we don't trigger on /U flag. 70 | import platform 71 | if platform.system() != "Windows": 72 | flag5 = Flag.Builder().from_unparsed_string('/User/blah').build() 73 | self.assertEqual(Flag("", "", ""), flag5) 74 | 75 | def test_builder_invalid(self): 76 | """Test tokenizing invalid flags.""" 77 | flag2 = Flag.Builder().from_unparsed_string('hello world').build() 78 | self.assertEqual(Flag("", ""), flag2) 79 | -------------------------------------------------------------------------------- /tests/test_flags_source.py: -------------------------------------------------------------------------------- 1 | """Tests for cmake database generation.""" 2 | import imp 3 | from os import path 4 | from unittest import TestCase 5 | 6 | from EasyClangComplete.plugin.flags_sources import flags_source 7 | from EasyClangComplete.plugin.utils import flag 8 | 9 | imp.reload(flags_source) 10 | imp.reload(flag) 11 | 12 | FlagsSource = flags_source.FlagsSource 13 | Flag = flag.Flag 14 | 15 | 16 | class TestFlagsSource(TestCase): 17 | """Test getting flags from a list of chunks.""" 18 | 19 | def test_init(self): 20 | """Initialization test.""" 21 | include_prefixes = ["-I", "-isystem"] 22 | flags_source = FlagsSource(include_prefixes) 23 | self.assertEqual(flags_source._include_prefixes, include_prefixes) 24 | 25 | def test_parse_flags(self): 26 | """Test that the flags are parsed correctly.""" 27 | from os import listdir 28 | current_folder = path.dirname(__file__) 29 | folder_to_expand = path.join(current_folder, '*') 30 | initial_str_flags = ["-I", current_folder, "-I" + current_folder, 31 | "-isystem", current_folder, "-std=c++11", 32 | "#simulate a comment", 33 | "-Iblah\n", "-I", "blah", "-I" + folder_to_expand] 34 | flags = Flag.tokenize_list(initial_str_flags, current_folder) 35 | expected_blah_path = path.join(current_folder, "blah") 36 | self.assertIn(Flag("-I", current_folder, " "), flags) 37 | self.assertIn(Flag("-I", current_folder), flags) 38 | self.assertIn(Flag("-isystem", current_folder, " "), flags) 39 | self.assertIn(Flag("-I", expected_blah_path, " "), flags) 40 | self.assertIn(Flag("-I", expected_blah_path), flags) 41 | self.assertIn(Flag("", "-std=c++11"), flags) 42 | 43 | # Check star expansion for a flags source 44 | for child in listdir(current_folder): 45 | child = path.join(current_folder, child) 46 | if path.isdir(child): 47 | self.assertIn(Flag("-I", child), flags) 48 | 49 | self.assertNotIn(Flag("", "-Iblah"), flags) 50 | self.assertNotIn(Flag("-I", "blah", " "), flags) 51 | self.assertNotIn(Flag("", "-isystem" + current_folder), flags) 52 | -------------------------------------------------------------------------------- /tests/test_index_location.py: -------------------------------------------------------------------------------- 1 | """Test index location.""" 2 | import imp 3 | from unittest import TestCase 4 | 5 | from EasyClangComplete.plugin.utils import index_location 6 | 7 | imp.reload(index_location) 8 | 9 | IndexLocation = index_location.IndexLocation 10 | 11 | 12 | class test_index_location(TestCase): 13 | """Test generating an index location.""" 14 | 15 | def test_simple_init(self): 16 | """Test short initialization.""" 17 | location = IndexLocation(filename='test.cpp', line=10, column=10) 18 | self.assertEqual(location.file.name, 'test.cpp') 19 | self.assertEqual(location.file.extension, '.cpp') 20 | self.assertEqual(location.file.short_name, 'test.cpp') 21 | self.assertEqual(location.line, 10) 22 | self.assertEqual(location.column, 10) 23 | 24 | def test_full_init(self): 25 | """Test full initialization.""" 26 | from os import path 27 | long_path = path.join('some', 'folder', 'test.cpp') 28 | location = IndexLocation(filename=long_path, line=10, column=10) 29 | self.assertEqual(location.file.name, long_path) 30 | self.assertEqual(location.file.extension, '.cpp') 31 | self.assertEqual(location.file.short_name, 'test.cpp') 32 | 33 | def test_no_extension(self): 34 | """Test if we can initialize without the extension.""" 35 | from os import path 36 | long_path = path.join('some', 'folder', 'test') 37 | location = IndexLocation(filename=long_path, line=10, column=10) 38 | self.assertEqual(location.file.name, long_path) 39 | self.assertEqual(location.file.extension, '') 40 | self.assertEqual(location.file.short_name, 'test') 41 | -------------------------------------------------------------------------------- /tests/test_macro_parser.py: -------------------------------------------------------------------------------- 1 | """Test macro parsing.""" 2 | from unittest import TestCase 3 | 4 | from EasyClangComplete.plugin.utils.macro_parser import MacroParser 5 | 6 | 7 | class TestMacroParser(TestCase): 8 | """Tests MacroParser.""" 9 | 10 | def test_args_string_non_function_like_macro(self): 11 | """Test parsing a macro with no '()'.""" 12 | parser = MacroParser('TEST_MACRO', None) 13 | parser._parse_macro_file_lines( 14 | macro_file_lines=['#define TEST_MACRO 1'], 15 | macro_line_number=1) 16 | self.assertEqual(parser.args_string, '') 17 | 18 | def test_args_string_function_macro_no_args(self): 19 | """Test parsing a function-like macro that takes no arguments.""" 20 | parser = MacroParser('TEST_MACRO', None) 21 | parser._parse_macro_file_lines( 22 | macro_file_lines=['#define TEST_MACRO() 1'], 23 | macro_line_number=1) 24 | self.assertEqual(parser.args_string, '()') 25 | 26 | def test_args_string_function_macro_one_arg(self): 27 | """Test parsing a function-like macro that takes one argument.""" 28 | parser = MacroParser('TEST_MACRO', None) 29 | parser._parse_macro_file_lines( 30 | macro_file_lines=['#define TEST_MACRO(x) (x)'], 31 | macro_line_number=1) 32 | self.assertEqual(parser.args_string, '(x)') 33 | 34 | def test_args_string_function_macro_multiple_args(self): 35 | """Test parsing a function-like macro that takes multiple arguments.""" 36 | parser = MacroParser('TEST_MACRO', None) 37 | parser._parse_macro_file_lines( 38 | macro_file_lines=['#define TEST_MACRO(x, y, z) (x + y + z)'], 39 | macro_line_number=1) 40 | self.assertEqual(parser.args_string, '(x, y, z)') 41 | 42 | def test_args_string_macro_extra_whitespace(self): 43 | """Test parsing a function-like macro with extra whitespace.""" 44 | parser = MacroParser('TEST_MACRO', None) 45 | parser._parse_macro_file_lines( 46 | macro_file_lines=[' # define TEST_MACRO( x , y, z ) (x)'], 47 | macro_line_number=1) 48 | self.assertEqual(parser.args_string, '(x, y, z)') 49 | 50 | def test_body_string_macro_empty(self): 51 | """Test parsing a macro without parameters.""" 52 | parser = MacroParser('TEST_MACRO', None) 53 | parser._parse_macro_file_lines( 54 | macro_file_lines=[' # define TEST_MACRO'], 55 | macro_line_number=1) 56 | self.assertEqual(parser.body_string, '') 57 | 58 | def test_body_string_macro_inline(self): 59 | """Test parsing a single-line macro.""" 60 | parser = MacroParser('TEST_MACRO', None) 61 | parser._parse_macro_file_lines( 62 | macro_file_lines=[' # define TEST_MACRO 42'], 63 | macro_line_number=1) 64 | self.assertEqual(parser.body_string, '42') 65 | 66 | def test_body_string_macro_next_line(self): 67 | """Test parsing a macro with val on next line.""" 68 | parser = MacroParser('TEST_MACRO', None) 69 | parser._parse_macro_file_lines( 70 | macro_file_lines=[' # define TEST_MACRO \\\n 42'], 71 | macro_line_number=1) 72 | self.assertEqual(parser.body_string, '\\\n 42') 73 | 74 | def test_body_string_macro_curr_next_line(self): 75 | """Test parsing a macro with val on current and next lines.""" 76 | parser = MacroParser('TEST_MACRO', None) 77 | parser._parse_macro_file_lines( 78 | macro_file_lines=[' # define TEST_MACRO 24\\\n 42'], 79 | macro_line_number=1) 80 | self.assertEqual(parser.body_string, '24\\\n 42') 81 | 82 | def test_body_string_macro_curr_next_lines(self): 83 | """Test parsing a function macro on multiple lines.""" 84 | parser = MacroParser('TEST_MACRO', None) 85 | parser._parse_macro_file_lines( 86 | macro_file_lines=[' #define TEST_MACRO(x) 24\\\n 42\\\n11\\\n123'], 87 | macro_line_number=1) 88 | self.assertEqual(parser.body_string, '24\\\n 42\\\n11\\\n123') 89 | -------------------------------------------------------------------------------- /tests/test_makefile.py: -------------------------------------------------------------------------------- 1 | """Tests for Makefile flags extraction.""" 2 | import imp 3 | import platform 4 | from os import path 5 | from unittest import TestCase 6 | 7 | from EasyClangComplete.plugin.utils import flag 8 | from EasyClangComplete.plugin.utils import search_scope 9 | from EasyClangComplete.plugin.flags_sources import makefile 10 | 11 | imp.reload(makefile) 12 | imp.reload(flag) 13 | imp.reload(search_scope) 14 | 15 | SearchScope = search_scope.TreeSearchScope 16 | 17 | Makefile = makefile.Makefile 18 | 19 | Flag = flag.Flag 20 | 21 | 22 | class TestMakefile(object): 23 | """Test finding and generating flags from Makeifles.""" 24 | 25 | def test_init(self): 26 | """Initialization test.""" 27 | self.assertEqual(Makefile._FILE_NAME, 'Makefile') 28 | 29 | def _get_project_root(self): 30 | return path.join(path.dirname(__file__), 'makefile_files') 31 | 32 | def _check_include(self, flags, include): 33 | expected = path.join(self._get_project_root(), include) 34 | self.assertIn(Flag('-I', expected), flags) 35 | 36 | def _check_define(self, flags, define): 37 | self.assertIn(Flag('', '-D' + define), flags) 38 | 39 | def _check_makefile(self, cache, flags, test_path, makefile_path): 40 | expected = path.join(self._get_project_root(), makefile_path) 41 | self.assertEqual(expected, cache[test_path]) 42 | self.assertEqual(flags, cache[expected]) 43 | 44 | def _check_cache(self, cache, flags, makefile_path): 45 | key = path.join(self._get_project_root(), makefile_path) 46 | self.assertEqual(flags, cache[key]) 47 | 48 | def test_makefile_root(self): 49 | """Test finding and parsing root Makefile.""" 50 | test_path = path.join(self._get_project_root(), 'main.c') 51 | 52 | mfile = Makefile(['-I', '-isystem']) 53 | flags = mfile.get_flags(test_path) 54 | self._check_include(flags, "inc") 55 | self._check_define(flags, "REQUIRED_DEFINE") 56 | self._check_makefile(mfile._cache, flags, test_path, "Makefile") 57 | 58 | def test_makefile_lib(self): 59 | """Test finding and parsing library Makefile.""" 60 | test_path = path.join(self._get_project_root(), 'lib', 'bar.c') 61 | 62 | mfile = Makefile(['-I', '-isystem']) 63 | flags = mfile.get_flags(test_path) 64 | self._check_include(flags, path.join("lib", "foo")) 65 | self._check_makefile(mfile._cache, flags, test_path, 66 | path.join("lib", "Makefile")) 67 | 68 | def test_makefile_sub(self): 69 | """Test finding and parsing Makefile for library subdir.""" 70 | test_path = path.join(self._get_project_root(), 'lib', 'foo', 'foo.c') 71 | 72 | mfile = Makefile(['-I', '-isystem']) 73 | flags = mfile.get_flags(test_path) 74 | self._check_include(flags, path.join("lib", "foo")) 75 | self._check_makefile(mfile._cache, flags, test_path, 76 | path.join("lib", "Makefile")) 77 | 78 | def test_makefile_fail(self): 79 | """Test behavior when no Makefile found.""" 80 | test_path = path.join(path.dirname(__file__), 'test_files', 'test.cpp') 81 | 82 | mfile = Makefile(['-I', '-isystem']) 83 | flags = mfile.get_flags(test_path) 84 | self.assertTrue(flags is None) 85 | 86 | 87 | if platform.system() != "Windows": 88 | class MakefileTestRunner(TestMakefile, TestCase): 89 | """Run make only if we are not on windows.""" 90 | pass 91 | -------------------------------------------------------------------------------- /tests/test_output_panel_handler.py: -------------------------------------------------------------------------------- 1 | """Test OutputPanelHandler.""" 2 | 3 | from EasyClangComplete.plugin.utils import output_panel_handler 4 | from unittest import TestCase 5 | 6 | import time 7 | import imp 8 | import sublime 9 | 10 | imp.reload(output_panel_handler) 11 | 12 | OutputPanelHandler = output_panel_handler.OutputPanelHandler 13 | 14 | 15 | class TestOutputPanelHandler(TestCase): 16 | """Test that we can create an output panel.""" 17 | 18 | def tearDown(self): 19 | """Cleanup method run after every test.""" 20 | window = sublime.active_window() 21 | window.run_command("show_panel", {"panel": "output.UnitTesting"}) 22 | 23 | def test_panel_creation(self): 24 | """Test that we can open a panel.""" 25 | OutputPanelHandler.show("hello world") 26 | window = sublime.active_window() 27 | self.assertIsNotNone(window.active_panel()) 28 | self.assertEqual(window.active_panel(), OutputPanelHandler.PANEL_NAME) 29 | panel_view = window.find_output_panel(OutputPanelHandler.PANEL_TAG) 30 | contents = panel_view.substr(sublime.Region(0, panel_view.size())) 31 | self.assertEqual(contents, "hello world") 32 | 33 | def test_panel_closing(self): 34 | """Test that we can close a panel.""" 35 | OutputPanelHandler.show("hello world") 36 | window = sublime.active_window() 37 | self.assertEqual(window.active_panel(), OutputPanelHandler.PANEL_NAME) 38 | OutputPanelHandler.hide_panel() 39 | self.assertIsNone(window.active_panel()) 40 | 41 | def test_not_closing_panel(self): 42 | """Test that we don't close a panel with a wrong name.""" 43 | window = sublime.active_window() 44 | test_panel_name = "test_panel" 45 | panel_view = window.create_output_panel(test_panel_name) 46 | while panel_view.is_loading(): 47 | time.sleep(0.1) 48 | if not window.active_panel(): 49 | # We cannot initialize a panel probably because of a CI quirk. 50 | return 51 | self.assertIsNotNone(window.active_panel()) 52 | self.assertNotEqual(window.active_panel(), 53 | OutputPanelHandler.PANEL_NAME) 54 | OutputPanelHandler.hide_panel() 55 | self.assertIsNotNone(window.active_panel()) 56 | self.assertNotEqual(window.active_panel(), 57 | OutputPanelHandler.PANEL_NAME) 58 | window.destroy_output_panel(test_panel_name) 59 | -------------------------------------------------------------------------------- /tests/test_panel_handler.py: -------------------------------------------------------------------------------- 1 | """Test compilation database flags generation.""" 2 | import imp 3 | 4 | from EasyClangComplete.tests.gui_test_wrapper import GuiTestWrapper 5 | from EasyClangComplete.plugin.utils import quick_panel_handler 6 | imp.reload(quick_panel_handler) 7 | 8 | ErrorQuickPanelHandler = quick_panel_handler.ErrorQuickPanelHandler 9 | 10 | 11 | class test_panel_handler(GuiTestWrapper): 12 | """Test unique list.""" 13 | 14 | def test_init(self): 15 | """Test initialization.""" 16 | self.set_up_view() 17 | errors = [{"hello": "world"}] 18 | panel_handler = ErrorQuickPanelHandler(self.view, errors) 19 | self.assertEqual(self.view, panel_handler.view) 20 | self.assertEqual(errors, panel_handler.errors) 21 | 22 | def test_items_to_show(self): 23 | """Test that the items are well formatted.""" 24 | self.set_up_view() 25 | errors = [ 26 | { 27 | "severity": 3, 28 | "error": "ERROR_MSG", 29 | "file": "error_file" 30 | }, 31 | { 32 | "severity": 2, 33 | "error": "WARNING_MSG", 34 | "file": "warning_file" 35 | } 36 | ] 37 | panel_handler = ErrorQuickPanelHandler(self.view, errors) 38 | items_to_show = panel_handler.items_to_show() 39 | expected = [["ERROR: ERROR_MSG", "error_file"], 40 | ["WARNING: WARNING_MSG", "warning_file"]] 41 | self.assertEqual(items_to_show, expected) 42 | 43 | def test_on_done(self): 44 | """Test that the items are well formatted.""" 45 | self.set_up_view() 46 | errors = [ 47 | { 48 | "severity": 3, 49 | "error": "ERROR_MSG", 50 | "file": "error_file", 51 | "row": 0, 52 | "col": 0 53 | }, 54 | ] 55 | panel_handler = ErrorQuickPanelHandler(self.view, errors) 56 | self.assertIsNone(panel_handler.on_done(-1)) 57 | self.assertIsNone(panel_handler.on_done(1)) 58 | view = panel_handler.on_done(0) 59 | self.assertIsNotNone(view) 60 | view.set_scratch(True) 61 | view.window().focus_view(view) 62 | view.window().run_command("close_file") 63 | -------------------------------------------------------------------------------- /tests/test_row_col.py: -------------------------------------------------------------------------------- 1 | """Tests for classes incapsulating row and column positions.""" 2 | import imp 3 | from os import path 4 | 5 | from EasyClangComplete.plugin.utils.subl import row_col 6 | from EasyClangComplete.tests.gui_test_wrapper import GuiTestWrapper 7 | 8 | imp.reload(row_col) 9 | 10 | ZeroIndexedRowCol = row_col.ZeroIndexedRowCol 11 | OneIndexedRowCol = row_col.OneIndexedRowCol 12 | 13 | 14 | class TestRowCol(GuiTestWrapper): 15 | """Test getting flags from CMakeLists.txt.""" 16 | 17 | def test_setup_view(self): 18 | """Test that setup view correctly sets up the view.""" 19 | file_name = path.join(path.dirname(__file__), 20 | 'test_files', 21 | 'test.cpp') 22 | self.check_view(file_name) 23 | 24 | def test_init(self): 25 | """Initialization test.""" 26 | pos = ZeroIndexedRowCol(4, 2) 27 | self.assertEquals(pos.row, 4) 28 | self.assertEquals(pos.col, 2) 29 | self.assertEquals((4, 2), pos.as_tuple()) 30 | 31 | def test_init_from_one_indexed(self): 32 | """Initialization test from 1-indexed row and column.""" 33 | pos = ZeroIndexedRowCol.from_one_indexed(OneIndexedRowCol(4, 2)) 34 | self.assertEquals(pos.row, 3) 35 | self.assertEquals(pos.col, 1) 36 | self.assertEquals((3, 1), pos.as_tuple()) 37 | 38 | def test_init_from_zero_indexed(self): 39 | """Initialization test from 0-indexed row and column.""" 40 | pos = OneIndexedRowCol.from_zero_indexed(ZeroIndexedRowCol(4, 2)) 41 | self.assertEquals(pos.row, 5) 42 | self.assertEquals(pos.col, 3) 43 | self.assertEquals((5, 3), pos.as_tuple()) 44 | 45 | def test_location(self): 46 | """Location is valid.""" 47 | file_name = path.join(path.dirname(__file__), 48 | 'test_files', 49 | 'test.cpp') 50 | self.set_up_view(file_name) 51 | pos = ZeroIndexedRowCol(4, 2) 52 | self.assertEquals(pos.row, 4) 53 | self.assertEquals(pos.col, 2) 54 | location = pos.as_1d_location(self.view) 55 | pos_from_location = ZeroIndexedRowCol.from_1d_location( 56 | self.view, location) 57 | self.assertEquals(pos.row, pos_from_location.row) 58 | self.assertEquals(pos.col, pos_from_location.col) 59 | 60 | default_location = ZeroIndexedRowCol.from_1d_location(self.view, None) 61 | self.assertEquals(0, default_location.row) 62 | self.assertEquals(0, default_location.col) 63 | -------------------------------------------------------------------------------- /tests/test_singleton.py: -------------------------------------------------------------------------------- 1 | """Test tools. 2 | 3 | Attributes: 4 | easy_clang_complete (module): this plugin module 5 | SublBridge (SublBridge): class for subl bridge 6 | """ 7 | import imp 8 | from unittest import TestCase 9 | 10 | from EasyClangComplete.plugin.utils import singleton 11 | 12 | 13 | imp.reload(singleton) 14 | 15 | singleton = singleton.singleton 16 | 17 | 18 | class test_singleton(TestCase): 19 | """Test other things.""" 20 | 21 | def test_singleton(self): 22 | """Test if singleton returns a unique reference.""" 23 | @singleton 24 | class A(object): 25 | """Class A.""" 26 | pass 27 | 28 | @singleton 29 | class B(object): 30 | """Class B different from class A.""" 31 | pass 32 | 33 | a = A() 34 | aa = A() 35 | b = B() 36 | bb = B() 37 | self.assertEqual(id(a), id(aa)) 38 | self.assertEqual(id(b), id(bb)) 39 | self.assertNotEqual(id(a), id(b)) 40 | -------------------------------------------------------------------------------- /tests/test_style.py: -------------------------------------------------------------------------------- 1 | """Test conformance to pep8 and pep257.""" 2 | from unittest import TestCase 3 | from os import path 4 | 5 | from EasyClangComplete.plugin.utils.tools import Tools 6 | 7 | PEP_257_IGNORE = [ 8 | "D209", 9 | "D203", 10 | "D204", 11 | "D213", 12 | "D406", 13 | "D407" 14 | ] 15 | 16 | PEP257_CMD = "pep257 '{}' --match-dir='^(?!clang|external).*' --ignore={}" 17 | PEP8_CMD = 'pycodestyle --exclude=clang,external,.git '\ 18 | '--show-source --show-pep8 --count --max-line-length=80 "{}"' 19 | 20 | PLUGIN_SOURCE_FOLDER = path.dirname(path.dirname(__file__)) 21 | 22 | LINUX_MISSING_MSG = "command not found" 23 | WINDOWS_MISSING_MSG = "is not recognized as an internal or external command" 24 | 25 | 26 | class TestStyle(TestCase): 27 | """Test that the code conforms to pep8 and pep257.""" 28 | 29 | def test_pep8(self): 30 | """Test conformance to pep8.""" 31 | self.maxDiff = None 32 | cmd = PEP8_CMD.format(PLUGIN_SOURCE_FOLDER) 33 | output = Tools.run_command(cmd, shell=True) 34 | if LINUX_MISSING_MSG in output or WINDOWS_MISSING_MSG in output: 35 | print('no pep8 found in path!') 36 | return 37 | self.assertEquals(output, "") 38 | 39 | def test_pep257(self): 40 | """Test conformance to pep257.""" 41 | self.maxDiff = None 42 | cmd = PEP257_CMD.format(PLUGIN_SOURCE_FOLDER, ','.join(PEP_257_IGNORE)) 43 | output = Tools.run_command(cmd, shell=True) 44 | if LINUX_MISSING_MSG in output or WINDOWS_MISSING_MSG in output: 45 | print('no pep257 found in path!') 46 | return 47 | self.assertEquals(output, "") 48 | -------------------------------------------------------------------------------- /tests/test_subl_bridge.py: -------------------------------------------------------------------------------- 1 | """Test tools. 2 | 3 | Attributes: 4 | easy_clang_complete (module): this plugin module 5 | SublBridge (SublBridge): class for subl bridge 6 | """ 7 | import imp 8 | from os import path 9 | 10 | from EasyClangComplete.plugin.settings import settings_manager 11 | from EasyClangComplete.plugin.utils.subl import subl_bridge 12 | 13 | from EasyClangComplete.tests.gui_test_wrapper import GuiTestWrapper 14 | 15 | 16 | imp.reload(settings_manager) 17 | imp.reload(subl_bridge) 18 | 19 | SettingsManager = settings_manager.SettingsManager 20 | 21 | SublBridge = subl_bridge.SublBridge 22 | PosStatus = subl_bridge.PosStatus 23 | 24 | 25 | class test_tools_command(GuiTestWrapper): 26 | """Test sublime commands.""" 27 | 28 | def set_text(self, string): 29 | """Set text to a view. 30 | 31 | Args: 32 | string (str): some string to set 33 | """ 34 | self.view.run_command("insert", {"characters": string}) 35 | 36 | def move(self, dist, forward=True): 37 | """Move the cursor by distance. 38 | 39 | Args: 40 | dist (int): pixels to move 41 | forward (bool, optional): forward or backward in the file 42 | 43 | """ 44 | for _ in range(dist): 45 | self.view.run_command("move", 46 | {"by": "characters", "forward": forward}) 47 | 48 | def test_next_line(self): 49 | """Test returning next line.""" 50 | self.set_up_view() 51 | self.set_text("hello\nworld!") 52 | self.move(10, forward=False) 53 | next_line = SublBridge.next_line(self.view) 54 | self.assertEqual(next_line, "world!") 55 | 56 | def test_wrong_triggers(self): 57 | """Test that we don't complete on numbers and wrong triggers.""" 58 | self.set_up_view(path.join(path.dirname(__file__), 59 | 'test_files', 60 | 'test_wrong_triggers.cpp')) 61 | # Load the completions. 62 | manager = SettingsManager() 63 | settings = manager.user_settings() 64 | 65 | # Check the current cursor position is completable. 66 | self.assertEqual(self.get_row(2), " a > 2.") 67 | 68 | # check that '>' does not trigger completions 69 | pos = self.view.text_point(2, 5) 70 | current_word = self.view.substr(self.view.word(pos)) 71 | self.assertEqual(current_word, "> ") 72 | status = SublBridge.get_pos_status(pos, self.view, settings) 73 | 74 | # Verify that we got the expected completions back. 75 | self.assertEqual(status, PosStatus.WRONG_TRIGGER) 76 | 77 | # check that 'a' does not trigger completions 78 | pos = self.view.text_point(2, 3) 79 | current_word = self.view.substr(self.view.word(pos)) 80 | self.assertEqual(current_word, "a") 81 | 82 | status = SublBridge.get_pos_status(pos, self.view, settings) 83 | 84 | # Verify that we got the expected completions back. 85 | self.assertEqual(status, PosStatus.COMPLETION_NOT_NEEDED) 86 | 87 | # check that '2.' does not trigger completions 88 | pos = self.view.text_point(2, 8) 89 | current_word = self.view.substr(self.view.word(pos)) 90 | self.assertEqual(current_word, ".\n") 91 | 92 | status = SublBridge.get_pos_status(pos, self.view, settings) 93 | 94 | # Verify that we got the expected completions back. 95 | self.assertEqual(status, PosStatus.WRONG_TRIGGER) 96 | -------------------------------------------------------------------------------- /tests/test_thread_pool.py: -------------------------------------------------------------------------------- 1 | """Test delayed thread pool.""" 2 | import time 3 | from unittest import TestCase 4 | 5 | import EasyClangComplete.plugin.utils.thread_pool 6 | import EasyClangComplete.plugin.utils.thread_job 7 | 8 | ThreadPool = EasyClangComplete.plugin.utils.thread_pool.ThreadPool 9 | ThreadJob = EasyClangComplete.plugin.utils.thread_job.ThreadJob 10 | 11 | 12 | def run_me(result): 13 | """Run this asyncronously.""" 14 | time.sleep(0.2) 15 | return result 16 | 17 | 18 | TIMEOUT = 5.0 19 | 20 | 21 | class TestContainer(): 22 | """A test container to store results of the operation.""" 23 | 24 | def __init__(self): 25 | """Initialize this object.""" 26 | self.futures = [] 27 | 28 | def on_job_done(self, future): 29 | """Call this when the job is done.""" 30 | self.futures.append(future) 31 | 32 | def wait_until_got_number_of_callbacks(self, number): 33 | """Wait until callback is called.""" 34 | slept = 0.0 35 | time_step = 0.1 36 | while not len(self.futures) == number and slept < TIMEOUT: 37 | time.sleep(time_step) 38 | slept += time_step 39 | 40 | 41 | class TestThreadPool(TestCase): 42 | """Test thread pool.""" 43 | 44 | def test_single_job(self): 45 | """Test single job.""" 46 | test_container = TestContainer() 47 | job = ThreadJob(name="test_job", 48 | callback=test_container.on_job_done, 49 | function=run_me, 50 | args=[True]) 51 | pool = ThreadPool() 52 | pool.new_job(job) 53 | test_container.wait_until_got_number_of_callbacks(1) 54 | self.assertGreater(len(test_container.futures), 0) 55 | self.assertFalse(test_container.futures[0].cancelled()) 56 | self.assertTrue(test_container.futures[0].result()) 57 | 58 | def test_override_job(self): 59 | """Test overriding job. 60 | 61 | The first job should be overridden by the next one. 62 | """ 63 | test_container = TestContainer() 64 | job_1 = ThreadJob(name="test_job", 65 | function=run_me, 66 | callback=test_container.on_job_done, 67 | args=["job_1"]) 68 | job_2 = ThreadJob(name="test_job", 69 | function=run_me, 70 | callback=test_container.on_job_done, 71 | args=["job_2"]) 72 | job_3 = ThreadJob(name="test_job", 73 | function=run_me, 74 | callback=test_container.on_job_done, 75 | args=["job_3"]) 76 | pool = ThreadPool() 77 | pool.new_job(job_1) 78 | pool.new_job(job_2) 79 | pool.new_job(job_3) 80 | test_container.wait_until_got_number_of_callbacks(3) 81 | self.assertEqual(len(test_container.futures), 3) 82 | # Here is what happens. job_1 runs so cannot be cancelled by job_2, so 83 | # job_1 keeps running while job_2 is added to the queue. Then we add 84 | # job_3, which cancels job_2, which immediately calls it's callback, 85 | # thus the first future in the result is from job_2. Then job_1 86 | # eventually finishes. Then job_3 starts and finishes. 87 | self.assertTrue(test_container.futures[0].cancelled()) 88 | self.assertFalse(test_container.futures[1].cancelled()) 89 | self.assertEqual(test_container.futures[1].result(), "job_1") 90 | self.assertFalse(test_container.futures[2].cancelled()) 91 | self.assertEqual(test_container.futures[2].result(), "job_3") 92 | -------------------------------------------------------------------------------- /tests/test_tools.py: -------------------------------------------------------------------------------- 1 | """Test tools. 2 | 3 | Attributes: 4 | easy_clang_complete (module): this plugin module 5 | SublBridge (SublBridge): class for subl bridge 6 | """ 7 | import imp 8 | from unittest import TestCase 9 | from os import path 10 | 11 | from EasyClangComplete.plugin.utils import tools 12 | from EasyClangComplete.plugin.utils import file 13 | 14 | imp.reload(tools) 15 | imp.reload(file) 16 | 17 | File = file.File 18 | Tools = tools.Tools 19 | 20 | PKG_NAME = tools.PKG_NAME 21 | 22 | 23 | class test_tools(TestCase): 24 | """Test other things.""" 25 | 26 | def test_pkg_name(self): 27 | """Test if the package name is correct.""" 28 | self.assertEqual(PKG_NAME, "EasyClangComplete") 29 | 30 | def test_seconds_from_string(self): 31 | """Test that we can convert time to seconds.""" 32 | self.assertEqual(60, Tools.seconds_from_string('00:00:60')) 33 | self.assertEqual(60, Tools.seconds_from_string('00:01:00')) 34 | self.assertEqual(120, Tools.seconds_from_string('00:02:00')) 35 | self.assertEqual(60 * 60, Tools.seconds_from_string('01:00:00')) 36 | self.assertEqual(60 * 60 + 1, Tools.seconds_from_string('01:00:01')) 37 | 38 | def test_run_command(self): 39 | """Test if the commands are run correctly.""" 40 | import platform 41 | if platform.system() == 'Windows': 42 | return 43 | temp_dir = File.get_temp_dir() 44 | temp_file_name = 'test_run_command.log' 45 | temp_file_path = path.join(temp_dir, temp_file_name) 46 | if path.exists(temp_file_path): 47 | import os 48 | os.remove(temp_file_path) 49 | self.assertFalse(path.exists(temp_file_path)) 50 | cmd_list = ['touch', temp_file_name] 51 | Tools.run_command(cmd_list, cwd=temp_dir) 52 | self.assertTrue(path.exists(temp_file_path)) 53 | cmd = 'rm {}'.format(temp_file_path) 54 | Tools.run_command(cmd, shell=True) 55 | self.assertFalse(path.exists(temp_file_path)) 56 | -------------------------------------------------------------------------------- /tests/test_unique_list.py: -------------------------------------------------------------------------------- 1 | """Test compilation database flags generation.""" 2 | from unittest import TestCase 3 | 4 | from EasyClangComplete.plugin.utils.unique_list import UniqueList 5 | 6 | 7 | class test_unique_list(TestCase): 8 | """Test unique list.""" 9 | def test_init(self): 10 | """Test initialization.""" 11 | unique_list = UniqueList() 12 | self.assertEqual([], unique_list.as_list()) 13 | self.assertEqual("[]", str(unique_list)) 14 | unique_list = UniqueList([1, 2, 3]) 15 | self.assertEqual([1, 2, 3], unique_list.as_list()) 16 | self.assertEqual("[1, 2, 3]", str(unique_list)) 17 | 18 | def test_append(self): 19 | """Test appending single values to unique list.""" 20 | unique_list = UniqueList() 21 | unique_list.append(1) 22 | self.assertEqual([1], unique_list.as_list()) 23 | unique_list.append(3) 24 | self.assertEqual([1, 3], unique_list.as_list()) 25 | unique_list.append(1) 26 | self.assertEqual([1, 3], unique_list.as_list()) 27 | unique_list.append(2) 28 | self.assertEqual([1, 3, 2], unique_list.as_list()) 29 | 30 | def test_clear(self): 31 | """Test clearing the list.""" 32 | unique_list = UniqueList([1, 2, 3]) 33 | self.assertEqual([1, 2, 3], unique_list.as_list()) 34 | unique_list.clear() 35 | self.assertEqual([], unique_list.as_list()) 36 | 37 | def test_iterable(self): 38 | """Test iterating over values.""" 39 | unique_list = UniqueList([0, 1, 2]) 40 | counter = 0 41 | for i in unique_list: 42 | self.assertEqual(i, counter) 43 | counter += 1 44 | 45 | def test_add(self): 46 | """Test merging with other iterable.""" 47 | unique_list = UniqueList([1, 2, 3]) 48 | other_list = [1, 4, 2, 5] 49 | unique_list += other_list 50 | self.assertEqual([1, 2, 3, 4, 5], unique_list.as_list()) 51 | -------------------------------------------------------------------------------- /unittesting.json: -------------------------------------------------------------------------------- 1 | { 2 | "tests_dir" : "tests", 3 | "pattern" : "test*.py", 4 | "async": true, 5 | "deferred": false, 6 | "verbosity": 10, 7 | "reload_package_on_testing": true, 8 | "show_reload_progress": true, 9 | "output": "", 10 | "capture_console": true 11 | } 12 | --------------------------------------------------------------------------------