├── .gitattributes ├── ftplugin └── vimhdl.vim ├── MANIFEST.in ├── .gitignore ├── .gitmodules ├── unittest.cfg ├── .ci ├── requirements.txt ├── setup_ghdl.sh ├── vroom │ ├── test_006_get_vim_info.vroom │ ├── test_007_server_should_start_only_when_opening_hdl_file.vroom │ ├── test_002_no_project_configured.vroom │ ├── test_010_create_project_file_with_conf_file_set.vroom │ ├── test_005_issue_15_quickfix_jump.vroom │ ├── test_004_issue_10.vroom │ ├── test_003_with_project_without_builder.vroom │ ├── test_008_get_dependencies_and_build_sequence.vroom │ ├── test_011_create_project_file_with_args.vroom │ ├── test_001_editing_multiple_files.vroom │ └── test_009_create_project_file_with_clear_setup.vroom ├── Dockerfile ├── docker_build.sh ├── setup_vim.sh ├── vimhdl_tests │ ├── __init__.py │ ├── vim_mock.py │ ├── test_vim_helpers.py │ └── test_runner.py ├── setup_nvim.sh └── vimrc ├── setup.cfg ├── .coveragerc ├── .codeclimate.yml ├── plugin └── vimhdl.vim ├── python └── vimhdl │ ├── __init__.py │ ├── base_requests.py │ ├── vim_helpers.py │ ├── config_gen_wrapper.py │ ├── vim_client.py │ └── _version.py ├── syntax └── vimhdl.vim ├── syntax_checkers ├── vhdl │ └── vimhdl.vim ├── verilog │ └── vimhdl.vim └── systemverilog │ └── vimhdl.vim ├── .travis.yml ├── run_tests.sh ├── README.md ├── autoload └── vimhdl.vim ├── doc └── vimhdl.txt └── LICENSE /.gitattributes: -------------------------------------------------------------------------------- 1 | python/vimhdl/_version.py export-subst 2 | -------------------------------------------------------------------------------- /ftplugin/vimhdl.vim: -------------------------------------------------------------------------------- 1 | setlocal bufhidden=delete 2 | setlocal noswapfile 3 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include versioneer.py 2 | include python/vimhdl/_version.py 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.pyo 3 | *.swp 4 | tags 5 | .coverage 6 | .coverage.* 7 | .foo 8 | htmlcov/ 9 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "dependencies/hdlcc"] 2 | path = dependencies/hdlcc 3 | url = https://github.com/suoto/hdlcc 4 | -------------------------------------------------------------------------------- /unittest.cfg: -------------------------------------------------------------------------------- 1 | [unittest] 2 | plugins = nose2.plugins.layers 3 | # [coverage] 4 | # always-on = True 5 | # coverage = vimhdl 6 | # coverage-report = html 7 | [layer-reporter] 8 | always-on = True 9 | colors = True 10 | highlight-words = A 11 | having 12 | should 13 | indent = 14 | -------------------------------------------------------------------------------- /.ci/requirements.txt: -------------------------------------------------------------------------------- 1 | argcomplete 2 | codecov 3 | colorama 4 | coverage 5 | coveralls 6 | futures 7 | git+https://github.com/suoto/rainbow_logging_handler 8 | greenlet 9 | logutils 10 | mock 11 | msgpack-python 12 | neovim 13 | nose2 14 | nose2-cov 15 | prettytable 16 | requests==v2.20.0 17 | six 18 | testfixtures 19 | trollius 20 | urllib3==1.24.2 21 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [versioneer] 2 | VCS = git 3 | style = pep440 4 | versionfile_source = python/vimhdl/_version.py 5 | tag_prefix = v 6 | 7 | [mypy] 8 | python_version = 3.7 9 | follow_imports = silent 10 | warn_unused_configs = true 11 | warn_unused_ignores = true 12 | 13 | [isort] 14 | forced_separate=nose2,hdl_checker 15 | multi_line_output=3 16 | include_trailing_comma=True 17 | force_grid_wrap=0 18 | use_parentheses=True 19 | line_length=88 20 | 21 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | source = vimhdl 3 | branch = True 4 | parallel = True 5 | omit = ./python/vimhdl/_version.py 6 | 7 | [report] 8 | show_missing = True 9 | 10 | # Regexes for lines to exclude from consideration 11 | exclude_lines = 12 | # Have to re-enable the standard pragma 13 | pragma: no cover 14 | 15 | # Don't complain about missing debug-only code: 16 | def __repr__ 17 | # def __str__ 18 | 19 | except ImportError: 20 | if __name__ == '__main__': 21 | @abc.abstractproperty 22 | @abc.abstractmethod 23 | 24 | # vim:ft=cfg: 25 | -------------------------------------------------------------------------------- /.ci/setup_ghdl.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -x 4 | set +e 5 | 6 | CACHE_DIR="${HOME}/cache/" 7 | GHDL_TAR_GZ="${CACHE_DIR}/ghdl.tar.gz" 8 | INSTALLATION_DIR="${HOME}/builders/ghdl/" 9 | 10 | mkdir -p "${CACHE_DIR}" 11 | mkdir -p "${INSTALLATION_DIR}" 12 | # CWD=$(pwd) 13 | 14 | if [ ! -f "${GHDL_TAR_GZ}" ]; then 15 | wget "${GHDL_URL}" -O "${GHDL_TAR_GZ}" 16 | fi 17 | 18 | if [ ! -d "${INSTALLATION_DIR}/bin" ]; then 19 | mkdir -p "${INSTALLATION_DIR}" 20 | tar zxvf "${GHDL_TAR_GZ}" --directory "${INSTALLATION_DIR}" 21 | fi 22 | 23 | "${INSTALLATION_DIR}"/bin/ghdl --version 24 | -------------------------------------------------------------------------------- /.ci/vroom/test_006_get_vim_info.vroom: -------------------------------------------------------------------------------- 1 | Open a buffer and set filetype to VHDL. This should allow us to get VimhdlInfo 2 | This file will be modified before it runs to replace __vimhdl__version__ and 3 | __hdl_checker__version__ with their real values 4 | :edit dummy.vhd 5 | :write (0.5) 6 | :set filetype=vhdl (0.5) 7 | :write (0.5) 8 | :VimhdlInfo 9 | ~ vimhdl debug info 10 | ~ - vimhdl version: __vimhdl__version__ 11 | ~ - hdl_checker version: __hdl_checker__version__ 12 | ~ - Server PID: .* (regex) 13 | ~ - Server logs: .* (regex) 14 | ~ - Server stdout: .* (regex) 15 | ~ - Server stderr: .* (regex) 16 | -------------------------------------------------------------------------------- /.ci/vroom/test_007_server_should_start_only_when_opening_hdl_file.vroom: -------------------------------------------------------------------------------- 1 | Right after opening Vim, the hdl_checker server should not be running. We'll call 2 | VimhdlInfo twice to ensure it doesn't starts 3 | :VimhdlInfo 4 | ~ vimhdl debug info 5 | ~ - vimhdl version: .* (regex) 6 | ~ - hdl_checker server is not running 7 | Setting the filetype to __filetype__ should trigger the server start 8 | :set filetype=__filetype__ 9 | Now the server should be running 10 | :VimhdlInfo 11 | ~ vimhdl debug info 12 | ~ - vimhdl version: __vimhdl__version__ 13 | ~ - hdl_checker version: __hdl_checker__version__ 14 | ~ - Server PID: .* (regex) 15 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | duplication: 4 | enabled: true 5 | config: 6 | languages: 7 | - python 8 | shellcheck: 9 | enabled: true 10 | fixme: 11 | enabled: true 12 | radon: 13 | enabled: true 14 | config: 15 | python_version: 2 16 | threshold: "C" 17 | fixme: 18 | enabled: true 19 | checks: 20 | FIXME: 21 | enabled: false 22 | TODO: 23 | enabled: false 24 | XXX: 25 | enabled: false 26 | ratings: 27 | paths: 28 | - "**.py" 29 | exclude_paths: 30 | - .ci/vimhdl_tests/* 31 | - python/vimhdl/_version.py 32 | - versioneer.py 33 | 34 | -------------------------------------------------------------------------------- /.ci/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM tweekmonster/vim-testbed:latest 2 | 3 | RUN install_vim -tag v8.0.0027 -build \ 4 | -tag v8.1.0519 -build \ 5 | -tag neovim:v0.2.0 -build \ 6 | -tag neovim:v0.3.5 -build 7 | 8 | ENV PACKAGES=" \ 9 | bash \ 10 | git \ 11 | python3 \ 12 | py3-pip \ 13 | wget \ 14 | " 15 | 16 | RUN apk --update add $PACKAGES && \ 17 | rm -rf /var/cache/apk/* /tmp/* /var/tmp/* 18 | 19 | RUN git clone https://github.com/google/vroom && \ 20 | cd vroom && \ 21 | git checkout 95c0b9140c610524155adb41a1d1dd686582d130 && \ 22 | pip3 install -e . 23 | 24 | RUN pip3 install vim-vint==0.3.15 25 | 26 | 27 | 28 | # RUN pip3 install hdl-checker==0.6 29 | -------------------------------------------------------------------------------- /plugin/vimhdl.vim: -------------------------------------------------------------------------------- 1 | " This file is part of vim-hdl. 2 | " 3 | " Copyright (c) 2015-2016 Andre Souto 4 | " 5 | " vim-hdl is free software: you can redistribute it and/or modify 6 | " it under the terms of the GNU General Public License as published by 7 | " the Free Software Foundation, either version 3 of the License, or 8 | " (at your option) any later version. 9 | " 10 | " vim-hdl is distributed in the hope that it will be useful, 11 | " but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | " GNU General Public License for more details. 14 | " 15 | " You should have received a copy of the GNU General Public License 16 | " along with vim-hdl. If not, see . 17 | " 18 | augroup vimhdl 19 | autocmd! VimEnter * :call vimhdl#setup() 20 | autocmd! Filetype vhdl :call vimhdl#setup() 21 | autocmd! Filetype verilog :call vimhdl#setup() 22 | autocmd! Filetype systemverilog :call vimhdl#setup() 23 | augroup END 24 | 25 | " vim: set foldmarker={,} foldlevel=0 foldmethod=marker : 26 | -------------------------------------------------------------------------------- /.ci/docker_build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # This file is part of vim-hdl. 3 | # 4 | # Copyright (c) 2015 - 2019 suoto (Andre Souto) 5 | # 6 | # vim-hdl is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # vim-hdl is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with vim-hdl. If not, see . 18 | 19 | set -xe 20 | 21 | DOCKER_TAG="${DOCKER_TAG:-latest}" 22 | PATH_TO_THIS_SCRIPT=$(readlink -f "$(dirname "$0")") 23 | DOCKERFILE=$PATH_TO_THIS_SCRIPT/Dockerfile 24 | CONTEXT=$(git -C "$(PATH_TO_THIS_SCRIPT)" rev-parse --show-toplevel) 25 | 26 | docker build -t suoto/hdl_checker_test:"$DOCKER_TAG" -f "$DOCKERFILE" "$CONTEXT" 27 | -------------------------------------------------------------------------------- /python/vimhdl/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of vim-hdl. 2 | # 3 | # Copyright (c) 2015-2016 Andre Souto 4 | # 5 | # vim-hdl is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # vim-hdl is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with vim-hdl. If not, see . 17 | """ 18 | vim-hdl is a VHDL syntax check provider that relies on third-party 19 | tools. See https://github.com/suoto/vim-hdl for more information 20 | """ 21 | 22 | from __future__ import print_function 23 | 24 | from ._version import get_versions 25 | from .vim_client import VimhdlClient 26 | 27 | __version__ = get_versions()["version"] 28 | del get_versions 29 | -------------------------------------------------------------------------------- /syntax/vimhdl.vim: -------------------------------------------------------------------------------- 1 | " Quit when a (custom) syntax file was already loaded 2 | if exists('b:current_syntax') 3 | finish 4 | endif 5 | " 6 | syn clear 7 | syn case ignore 8 | 9 | syn match vimhdlProjectFileComment "#.*" 10 | syn match vimhdlProjectFileComment "^\s*\zs#.*$" 11 | syn match vimhdlProjectFileComment "\s\zs#.*$" 12 | 13 | syn match vimhdlProjectFileLang display '\(^\|\[\)\<\(vhdl\|verilog\|systemverilog\)\>\(\s\|\]\)' 14 | syn match vimhdlProjectFileBuilders display '\<\(msim\|xvhdl\|ghdl\|fallback\)\>' 15 | syn match vimhdlProjectFileSrc display ' [a-z./][^ ]\+\.\(svh\|vh\|sv\|v\|vhd\|vhdl\)\>\s*' 16 | 17 | syn keyword vimhdlProjectFileKeywords builder global_build_flags batch_build_flags 18 | syn keyword vimhdlProjectFileKeywords single_build_flags 19 | 20 | hi def link vimhdlProjectFileComment Comment 21 | hi def link vimhdlProjectFileKeywords Keyword 22 | hi def link vimhdlProjectFileLang Identifier 23 | hi def link vimhdlProjectFileBuilders Constant 24 | hi def link vimhdlProjectFileSrc String 25 | 26 | let b:current_syntax = 'vimhdlProjectFile' 27 | 28 | " vim: ts=8 sw=2 29 | -------------------------------------------------------------------------------- /.ci/setup_vim.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -x 4 | 5 | if [ "${VERSION}" == "latest" ]; then 6 | sudo bash -c 'apt-get update && apt-get upgrade vim-gnome' 7 | elif [ "${VERSION}" == "master" ]; then 8 | # Clone repo if the cached folder doesn't exists 9 | if [ ! -d "${CACHE}/vim-${VERSION}" ]; then 10 | git clone --quiet https://github.com/vim/vim "${CACHE}/vim-${VERSION}" 11 | fi 12 | 13 | pushd "${CACHE}/vim-${VERSION}" || exit 14 | git clean -fdx 15 | git checkout "${VERSION}" 16 | 17 | if [[ ${TRAVIS_PYTHON_VERSION} == 3* ]]; then 18 | ./configure --with-features=huge \ 19 | --prefix="$HOME/.local" \ 20 | --enable-python3interp=yes \ 21 | --enable-gui=auto \ 22 | --with-x 23 | else 24 | ./configure --with-features=huge \ 25 | --prefix="$HOME/.local" \ 26 | --enable-pythoninterp=yes \ 27 | --enable-gui=auto \ 28 | --with-x 29 | fi 30 | 31 | make -j 32 | make install 33 | popd || exit 34 | 35 | fi 36 | 37 | set +x 38 | 39 | vim --version 40 | -------------------------------------------------------------------------------- /.ci/vroom/test_002_no_project_configured.vroom: -------------------------------------------------------------------------------- 1 | Edit a VHD file without any project file. It is expected to run only the static checker 2 | :SyntasticInfo 3 | I don't want to type the file within vroom, so I'll copy another file :) 4 | :tabe ../hdlcc_ci/hdl_lib/common_lib/edge_detector.vhd 5 | > ggVGy 6 | :echo delete('source.vhd') 7 | :tabe source.vhd 8 | > P 9 | :write 10 | :SyntasticInfo 11 | ~ Syntastic version:.* (regex) 12 | ~ Info for filetype: vhdl 13 | ~ Global mode: active 14 | ~ Filetype vhdl is active 15 | ~ The current file will be checked automatically 16 | ~ Available checker.* (regex) 17 | ~ Currently enabled checker.* (regex) 18 | 19 | This file has no errors, so the quickfix list must be empty 20 | :SyntasticCheck 21 | :silent! lopen 22 | & 23 | :lclose 24 | 25 | Find where the architecture declaration begins and insert a signal declaration, 26 | which should result in the static checker saying it is not used 27 | > /^\s*architecture\s\+\w\+\s\+of\s\+\w\+ 28 | > o signal unused : integer; 29 | :w 30 | :silent! lopen 31 | \s*source.vhd|43 col 13 warning| signal "unused" is never used (regex) 32 | :echo delete('source.vhd') 33 | 34 | -------------------------------------------------------------------------------- /.ci/vroom/test_010_create_project_file_with_conf_file_set.vroom: -------------------------------------------------------------------------------- 1 | Run the config file creation helper without any source and check if it finds 2 | VHDL, Verilog, SystemVerilog files and headers correctly 3 | :cd ~/dummy_test_path/ 4 | :VimhdlCreateProjectFile 5 | # This is the resulting project file, please review and save when done. The 6 | # g:vimhdl_conf_file variable has been temporarily changed to point to this 7 | # file should you wish to open HDL files and test the results. When finished, 8 | # close this buffer; you''ll be prompted to either use this file or revert to 9 | # the original one. 10 | # 11 | # ---- Everything up to this line will be automatically removed ---- 12 | # Files found: 5 13 | # Available builders: msim, ghdl 14 | builder = msim 15 | global_build_flags[systemverilog] = +incdir+./sv_includes 16 | global_build_flags[verilog] = +incdir+./path_a +incdir+./v_includes 17 | \s* (regex) 18 | vhdl lib ./path_a/some_source.vhd\s* (regex) 19 | vhdl lib ./path_a/source_tb.vhd -2008\s* (regex) 20 | systemverilog lib ./path_b/a_systemverilog_source.sv\s* (regex) 21 | verilog lib ./path_b/a_verilog_source.v\s* (regex) 22 | vhdl lib ./path_b/some_source.vhd\s* (regex) 23 | \s* (regex) 24 | # vim: filetype=vimhdl\s* (regex) 25 | 26 | -------------------------------------------------------------------------------- /.ci/vimhdl_tests/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of vim-hdl. 2 | # 3 | # vim-hdl is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation, either version 3 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # vim-hdl is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with vim-hdl. If not, see . 15 | 16 | 17 | import logging 18 | import sys 19 | 20 | def _setupLogging(): # pragma: no cover 21 | """ 22 | Overwrite the default formatter 23 | """ 24 | for handler in logging.root.handlers: 25 | handler.formatter = logging.Formatter( 26 | '%(levelname)-7s | %(asctime)s | ' + 27 | '%(name)s @ %(funcName)s():%(lineno)d %(threadName)s ' + 28 | '|\t%(message)s', datefmt='%H:%M:%S') 29 | 30 | logging.getLogger('urllib3').setLevel(logging.WARNING) 31 | logging.getLogger('pynvim').setLevel(logging.WARNING) 32 | 33 | _setupLogging() 34 | -------------------------------------------------------------------------------- /.ci/vroom/test_005_issue_15_quickfix_jump.vroom: -------------------------------------------------------------------------------- 1 | Macro that writes and waits for the save msg (seems needed in some cases) 2 | @macro (write) 3 | :write 4 | ~ ".*".*\swritten (regex) 5 | @endmacro 6 | 7 | 8 | 9 | 10 | Edit a VHD file without any project file. It is expected to run only the static checker 11 | :SyntasticInfo 12 | I don't want to type the file within vroom, so I'll copy another file :) 13 | :tabe ../hdlcc_ci/hdl_lib/common_lib/edge_detector.vhd 14 | > ggVGy 15 | ~ 111 lines yanked 16 | :echo delete('source.vhd') 17 | :tabe source.vhd 18 | > P 19 | ~ 111 more lines 20 | @do (write) 21 | 22 | This file has no errors, so the quickfix list must be empty 23 | :SyntasticCheck 24 | :lopen 25 | & 26 | :lclose 27 | 28 | Find where the architecture declaration begins and insert a signal declaration, 29 | which should result in the static checker saying it is not used 30 | > /^\s*architecture\s\+\w\+\s\+of\s\+\w\+ 31 | > o signal unused : integer; 32 | @do (write) 33 | :lopen 34 | source.vhd|37 col \d+ warning| signal "unused" is never used (regex) 35 | 36 | Jump from the quickfix list and check if we move to the line that has the error 37 | > (1.0) 38 | :echom line('.') 39 | ~ 37 40 | :echom getline('.') 41 | ~ ^.*\bsignal unused : integer;\s* (regex) 42 | 43 | -------------------------------------------------------------------------------- /.ci/vroom/test_004_issue_10.vroom: -------------------------------------------------------------------------------- 1 | Macro that checks if the quickfix is empty 2 | @macro (assert_qf_empty) 3 | :echom &ft 4 | ~ vhdl 5 | :SyntasticCheck 6 | :lopen 7 | :echom getline('.') 8 | & 9 | :quit 10 | @endmacro 11 | 12 | Macro that checks if vimhdl is enabled 13 | @macro (vimhdl_check) 14 | :SyntasticInfo 15 | ~ Syntastic version:.* (regex) 16 | ~ Info for filetype: vhdl 17 | ~ Global mode: active 18 | ~ Filetype vhdl is active 19 | ~ The current file will be checked automatically 20 | ~ Available checker(s:|:)\s*.*\bvimhdl\b.* (regex) 21 | ~ Currently enabled checker(s:|:)\s*.*\bvimhdl\b.* (regex) 22 | @endmacro 23 | 24 | 25 | 26 | 27 | Edit some files on Vim after using hdlcc_sa.py to build outside Vim 28 | :let g:vimhdl_conf_file = getcwd() . '/../hdlcc_ci/hdl_lib/ghdl.prj' 29 | :cd ../hdlcc_ci/hdl_lib 30 | :edit common_lib/edge_detector.vhd (2.0) 31 | @do (vimhdl_check) 32 | 33 | This file has no errors 34 | @do (assert_qf_empty) 35 | 36 | Remove an important line so the builder must tell there's an error 37 | > /^end\s\+edge_detector 38 | > dd 39 | :echom getline('.') 40 | ~ end edge_detector; 41 | :write 42 | ~ ".*".*\swritten (regex) 43 | :SyntasticCheck 44 | :lopen 45 | common_lib/edge_detector.vhd|36 col 1 error| 'end' is expected instead of 'architecture' 46 | :lclose 47 | > u 48 | :write 49 | @do (assert_qf_empty) 50 | 51 | -------------------------------------------------------------------------------- /.ci/vroom/test_003_with_project_without_builder.vroom: -------------------------------------------------------------------------------- 1 | Macro that checks if the quickfix is empty 2 | @macro (assert_qf_empty) 3 | :echom &ft 4 | ~ vhdl 5 | :silent! SyntasticCheck 6 | :silent! lopen 7 | :echom getline('.') 8 | & 9 | :quit 10 | @endmacro 11 | 12 | Macro that writes and waits for the save msg (seems needed in some cases) 13 | @macro (write) 14 | :write 15 | ~ ".*".*\swritten (regex) 16 | @endmacro 17 | 18 | 19 | 20 | 21 | We'll test what happens when we configure a project but the builder it specifies 22 | is not found, which should trigger using the fallback builder 23 | :let hdl_lib_path = getcwd() . '/../hdlcc_ci/hdl_lib' 24 | :let g:vimhdl_conf_file = hdl_lib_path . '/msim.prj' 25 | :cd ../hdlcc_ci/hdl_lib 26 | :edit common_lib/edge_detector.vhd 27 | ~ "common_lib/edge_detector.vhd".* (regex) 28 | > i 29 | ~ Failed to create builder 'msim' 30 | 31 | @do (assert_qf_empty) 32 | 33 | Change the project filename to a builder we have configured 34 | :let g:vimhdl_conf_file = hdl_lib_path . '/ghdl.prj' 35 | @do (write) 36 | @do (assert_qf_empty) 37 | 38 | Remove an important line so the builder must tell there's an error 39 | > /^end\s\+edge_detector 40 | > dd 41 | :echom getline('.') 42 | ~ end edge_detector; 43 | @do (write) 44 | :silent! SyntasticCheck 45 | :silent! lopen 46 | common_lib/edge_detector.vhd|35 col 1 error| 'end' is expected instead of 'architecture' 47 | :lclose 48 | > u 49 | @do (write) 50 | @do (assert_qf_empty) 51 | 52 | -------------------------------------------------------------------------------- /.ci/setup_nvim.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -x 4 | 5 | # Neovim working path defaults to home 6 | if [ -z "${NEOVIM_BUILD_DIR}" ]; then NEOVIM_BUILD_DIR=${HOME}/neovim-build; fi 7 | 8 | if [ ! -d "${NEOVIM_BUILD_DIR}" ]; then mkdir -p "${NEOVIM_BUILD_DIR}"; fi 9 | 10 | if [ "${VERSION}" == "master" ]; then 11 | # Get the master version from git 12 | git clone --quiet https://github.com/neovim/neovim --depth 1 "${NEOVIM_BUILD_DIR}/neovim-master" 13 | elif [ ! -f "${NEOVIM_BUILD_DIR}/neovim-${VERSION}" ]; then 14 | # Other release tags we get from Neovim's releases archive 15 | wget --quiet "https://github.com/neovim/neovim/archive/v${VERSION}.tar.gz" \ 16 | -O "${NEOVIM_BUILD_DIR}/neovim.tar.gz" 17 | pushd "${NEOVIM_BUILD_DIR}" || exit 18 | tar zxvf "neovim.tar.gz" 19 | popd || exit 20 | fi 21 | 22 | if [ ! -f "${NEOVIM_BUILD_DIR}/neovim-${VERSION}/build/bin/nvim" ]; then 23 | pushd "${NEOVIM_BUILD_DIR}/neovim-${VERSION}" || exit 24 | make clean 25 | make CMAKE_BUILD_TYPE=Release -j 26 | popd || exit 27 | fi 28 | 29 | export PATH="${NEOVIM_BUILD_DIR}/neovim-${VERSION}/build/bin:${PATH}" 30 | export VIM="${NEOVIM_BUILD_DIR}/neovim-${VERSION}/runtime" 31 | 32 | # Ensure the binary being selected is the one we want 33 | if [ ! "$(which nvim)" -ef "${NEOVIM_BUILD_DIR}/neovim-${VERSION}/build/bin/nvim" ]; then 34 | echo "Neovim binary points to \"$(which nvim)\" but it should point to \ 35 | \"${NEOVIM_BUILD_DIR}/neovim-${VERSION}/build/bin/nvim\"" 36 | exit -1 37 | fi 38 | 39 | set +x 40 | 41 | nvim --version 42 | 43 | -------------------------------------------------------------------------------- /.ci/vroom/test_008_get_dependencies_and_build_sequence.vroom: -------------------------------------------------------------------------------- 1 | Macro that checks if the quickfix is empty 2 | @macro (assert_qf_empty) 3 | :echom &ft 4 | ~ vhdl 5 | :silent! SyntasticCheck 6 | :silent! lopen 7 | :echom getline('.') 8 | & 9 | :quit 10 | @endmacro 11 | 12 | Macro that checks if vimhdl is enabled 13 | @macro (vimhdl_check) 14 | :SyntasticInfo 15 | ~ Syntastic version:.* (regex) 16 | ~ Info for filetype: vhdl 17 | ~ Global mode: active 18 | ~ Filetype vhdl is active 19 | ~ The current file will be checked automatically 20 | ~ Available checker(s:|:)\s*.*\bvimhdl\b.* (regex) 21 | ~ Currently enabled checker(s:|:)\s*.*\bvimhdl\b.* (regex) 22 | @endmacro 23 | 24 | Edit different files under the same project 25 | :let g:vimhdl_conf_file = getcwd() . '/../hdlcc_ci/hdl_lib/ghdl.prj' 26 | :cd ../hdlcc_ci/hdl_lib 27 | :edit common_lib/edge_detector.vhd 28 | @do (vimhdl_check) 29 | 30 | :VimhdlViewDependencies 31 | ~ Dependencies for .*/edge_detector.vhd (regex) 32 | ~ - common_lib.common_pkg 33 | ~ - common_lib.sr_delay 34 | ~ - common_lib.synchronizer 35 | ~ - ieee.std_logic_1164 36 | 37 | Order doesn't really matter 38 | :VimhdlViewBuildSequence 39 | ~ Build sequence for .*/edge_detector.vhd (regex) 40 | ~ 1: .*/hdl_lib/common_lib/(common_pkg|synchronizer|sr_delay).vhd \(library: common_lib\) (regex) 41 | ~ 2: .*/hdl_lib/common_lib/(common_pkg|synchronizer|sr_delay).vhd \(library: common_lib\) (regex) 42 | ~ 3: .*/hdl_lib/common_lib/(common_pkg|synchronizer|sr_delay).vhd \(library: common_lib\) (regex) 43 | -------------------------------------------------------------------------------- /.ci/vimhdl_tests/vim_mock.py: -------------------------------------------------------------------------------- 1 | # This file is part of vim-hdl. 2 | # 3 | # vim-hdl is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation, either version 3 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # vim-hdl is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with vim-hdl. If not, see . 15 | 16 | import sys 17 | 18 | try: # Python 3.x 19 | import unittest.mock as mock # pylint: disable=import-error, no-name-in-module 20 | except ImportError: # Python 2.x 21 | import mock 22 | 23 | 24 | 25 | vim = mock.MagicMock() # pylint: disable=invalid-name 26 | 27 | def mockVim(): 28 | sys.modules['vim'] = vim 29 | 30 | vim.current = mock.MagicMock() 31 | vim.current.buffer = mock.MagicMock( 32 | vars={'current_buffer_var_0' : 'current_buffer_value_0', 33 | 'current_buffer_var_1' : 'current_buffer_value_1'}) 34 | 35 | vim.buffers = { 36 | 0 : mock.MagicMock(vars={'buffer_0_var_0' : 'buffer_0_var_value_0', 37 | 'buffer_0_var_1' : 'buffer_0_var_value_1'}), 38 | 1 : mock.MagicMock(vars={'buffer_1_var_0' : 'buffer_1_var_value_0', 39 | 'buffer_1_var_1' : 'buffer_1_var_value_1'}), 40 | } 41 | 42 | 43 | -------------------------------------------------------------------------------- /.ci/vroom/test_011_create_project_file_with_args.vroom: -------------------------------------------------------------------------------- 1 | Run the config file creation helper but specify directories 2 | :pwd 3 | ~ .*\/hdl_lib.* (regex) 4 | :VimhdlCreateProjectFile memory/ 5 | # This is the resulting project file, please review and save when done. The 6 | # g:vimhdl_conf_file variable has been temporarily changed to point to this 7 | # file should you wish to open HDL files and test the results. When finished, 8 | # close this buffer; you''ll be prompted to either use this file or revert to 9 | # the original one. 10 | # 11 | # ---- Everything up to this line will be automatically removed ---- 12 | # Files found: 6\s* (regex) 13 | # Available builders: ghdl 14 | builder = ghdl 15 | \s* (regex) 16 | vhdl lib memory/async_fifo.vhd\s* (regex) 17 | vhdl lib memory/ram_inference.vhd\s* (regex) 18 | vhdl lib memory/ram_inference_dport.vhd\s* (regex) 19 | vhdl lib memory/testbench/async_fifo_tb.vhd\s* (regex) 20 | vhdl lib memory/testbench/fifo_bfm_pkg.vhd\s* (regex) 21 | vhdl lib memory/testbench/ram_model_pkg.vhd\s* (regex) 22 | \s* (regex) 23 | # vim: filetype=vimhdl 24 | :VimhdlCreateProjectFile common_lib/ 25 | # This is the resulting project file, please review and save when done. The 26 | # g:vimhdl_conf_file variable has been temporarily changed to point to this 27 | # file should you wish to open HDL files and test the results. When finished, 28 | # close this buffer; you''ll be prompted to either use this file or revert to 29 | # the original one. 30 | # 31 | # ---- Everything up to this line will be automatically removed ---- 32 | # Files found: 5\s* (regex) 33 | # Available builders: ghdl 34 | builder = ghdl 35 | \s* (regex) 36 | vhdl lib common_lib/common_pkg.vhd\s* (regex) 37 | vhdl lib common_lib/edge_detector.vhd\s* (regex) 38 | vhdl lib common_lib/pulse_sync.vhd\s* (regex) 39 | vhdl lib common_lib/sr_delay.vhd\s* (regex) 40 | vhdl lib common_lib/synchronizer.vhd\s* (regex) 41 | \s* (regex) 42 | # vim: filetype=vimhdl 43 | 44 | -------------------------------------------------------------------------------- /syntax_checkers/vhdl/vimhdl.vim: -------------------------------------------------------------------------------- 1 | " This file is part of vim-hdl. 2 | " 3 | " Copyright (c) 2015-2016 Andre Souto 4 | " 5 | " vim-hdl is free software: you can redistribute it and/or modify 6 | " it under the terms of the GNU General Public License as published by 7 | " the Free Software Foundation, either version 3 of the License, or 8 | " (at your option) any later version. 9 | " 10 | " vim-hdl is distributed in the hope that it will be useful, 11 | " but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | " GNU General Public License for more details. 14 | " 15 | " You should have received a copy of the GNU General Public License 16 | " along with vim-hdl. If not, see . 17 | " 18 | "============================================================================ 19 | " For Syntastic license, check http://sam.zoy.org/wtfpl/COPYING 20 | "============================================================================ 21 | 22 | " {{ Pre setup 23 | if exists('g:loaded_syntastic_vhdl_vimhdl_checker') 24 | finish 25 | endif 26 | let g:loaded_syntastic_vhdl_vimhdl_checker = 1 27 | 28 | if !exists('g:syntastic_vhdl_vimhdl_sort') 29 | let g:syntastic_vhdl_vimhdl_sort = 0 " vim-hdl returns sorted messages 30 | endif 31 | 32 | let s:save_cpo = &cpoptions 33 | set cpoptions&vim 34 | " }} 35 | " {{ vimhdl availability checker 36 | function! SyntaxCheckers_vhdl_vimhdl_IsAvailable() dict 37 | if has('python') || has('python3') 38 | return 1 39 | endif 40 | return 0 41 | endfunction 42 | " }} 43 | " {{ vimhdl location list assembler 44 | function! SyntaxCheckers_vhdl_vimhdl_GetLocList() dict 45 | return vimhdl#getMessagesForCurrentBuffer() 46 | endfunction 47 | " }} 48 | " {{ Register vimhdl within Syntastic 49 | call g:SyntasticRegistry.CreateAndRegisterChecker({ 50 | \ 'filetype' : 'vhdl', 51 | \ 'name' : 'vimhdl'}) 52 | " }} 53 | 54 | let &cpoptions = s:save_cpo 55 | unlet s:save_cpo 56 | 57 | " vim: set foldmarker={{,}} foldlevel=0 foldmethod=marker : 58 | -------------------------------------------------------------------------------- /syntax_checkers/verilog/vimhdl.vim: -------------------------------------------------------------------------------- 1 | " This file is part of vim-hdl. 2 | " 3 | " Copyright (c) 2015-2016 Andre Souto 4 | " 5 | " vim-hdl is free software: you can redistribute it and/or modify 6 | " it under the terms of the GNU General Public License as published by 7 | " the Free Software Foundation, either version 3 of the License, or 8 | " (at your option) any later version. 9 | " 10 | " vim-hdl is distributed in the hope that it will be useful, 11 | " but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | " GNU General Public License for more details. 14 | " 15 | " You should have received a copy of the GNU General Public License 16 | " along with vim-hdl. If not, see . 17 | " 18 | "============================================================================ 19 | " For Syntastic license, check http://sam.zoy.org/wtfpl/COPYING 20 | "============================================================================ 21 | 22 | " {{ Pre setup 23 | if exists('g:loaded_syntastic_verilog_vimhdl_checker') 24 | finish 25 | endif 26 | let g:loaded_syntastic_verilog_vimhdl_checker = 1 27 | 28 | if !exists('g:syntastic_verilog_vimhdl_sort') 29 | let g:syntastic_verilog_vimhdl_sort = 0 " vim-hdl returns sorted messages 30 | endif 31 | 32 | let s:save_cpo = &cpoptions 33 | set cpoptions&vim 34 | " }} 35 | " {{ vimhdl availability checker 36 | function! SyntaxCheckers_verilog_vimhdl_IsAvailable() dict 37 | if has('python') || has('python3') 38 | return 1 39 | endif 40 | return 0 41 | endfunction 42 | " }} 43 | " {{ vimhdl location list assembler 44 | function! SyntaxCheckers_verilog_vimhdl_GetLocList() dict 45 | return vimhdl#getMessagesForCurrentBuffer() 46 | endfunction 47 | " }} 48 | " {{ Register vimhdl within Syntastic 49 | call g:SyntasticRegistry.CreateAndRegisterChecker({ 50 | \ 'filetype' : 'verilog', 51 | \ 'name' : 'vimhdl'}) 52 | " }} 53 | 54 | let &cpoptions = s:save_cpo 55 | unlet s:save_cpo 56 | 57 | " vim: set foldmarker={{,}} foldlevel=0 foldmethod=marker : 58 | -------------------------------------------------------------------------------- /syntax_checkers/systemverilog/vimhdl.vim: -------------------------------------------------------------------------------- 1 | " This file is part of vim-hdl. 2 | " 3 | " Copyright (c) 2015-2016 Andre Souto 4 | " 5 | " vim-hdl is free software: you can redistribute it and/or modify 6 | " it under the terms of the GNU General Public License as published by 7 | " the Free Software Foundation, either version 3 of the License, or 8 | " (at your option) any later version. 9 | " 10 | " vim-hdl is distributed in the hope that it will be useful, 11 | " but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | " GNU General Public License for more details. 14 | " 15 | " You should have received a copy of the GNU General Public License 16 | " along with vim-hdl. If not, see . 17 | " 18 | "============================================================================ 19 | " For Syntastic license, check http://sam.zoy.org/wtfpl/COPYING 20 | "============================================================================ 21 | 22 | " {{ Pre setup 23 | if exists('g:loaded_syntastic_systemverilog_vimhdl_checker') 24 | finish 25 | endif 26 | let g:loaded_syntastic_systemverilog_vimhdl_checker = 1 27 | 28 | if !exists('g:syntastic_systemverilog_vimhdl_sort') 29 | let g:syntastic_systemverilog_vimhdl_sort = 0 " vim-hdl returns sorted messages 30 | endif 31 | 32 | let s:save_cpo = &cpoptions 33 | set cpoptions&vim 34 | " }} 35 | " {{ vimhdl availability checker 36 | function! SyntaxCheckers_systemverilog_vimhdl_IsAvailable() dict 37 | if has('python') || has('python3') 38 | return 1 39 | endif 40 | return 0 41 | endfunction 42 | " }} 43 | " {{ vimhdl location list assembler 44 | function! SyntaxCheckers_systemverilog_vimhdl_GetLocList() dict 45 | return vimhdl#getMessagesForCurrentBuffer() 46 | endfunction 47 | " }} 48 | " {{ Register vimhdl within Syntastic 49 | call g:SyntasticRegistry.CreateAndRegisterChecker({ 50 | \ 'exec' : '', 51 | \ 'filetype' : 'systemverilog', 52 | \ 'name' : 'vimhdl'}) 53 | " }} 54 | 55 | let &cpoptions = s:save_cpo 56 | unlet s:save_cpo 57 | 58 | " vim: set foldmarker={{,}} foldlevel=0 foldmethod=marker : 59 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: python 3 | dist: trusty 4 | 5 | env: 6 | global: 7 | - CACHE=${HOME}/cache 8 | - GHDL_HOST="http://downloads.sourceforge.net/project/ghdl-updates/Builds" 9 | - GHDL_URL="${GHDL_HOST}/ghdl-0.33/ghdl-0.33-x86_64-linux.tgz" 10 | - COLUMNS=80 11 | - LINES=50 12 | matrix: 13 | include: 14 | # Test Vim bundled with Ubuntu 14.04 LTS (Vim is using Python 2) 15 | - dist: trusty 16 | env: CI_TARGET=vim DISTRO=trusty 17 | python: 3.6 18 | 19 | # Test Vim bundled with Ubuntu 16.04 LTS (Vim is using Python 2) 20 | - dist: xenial 21 | env: CI_TARGET=vim DISTRO=xenial 22 | python: 3.6 23 | 24 | # Test Vim version from Ubuntu 18.04 (updating from apt-get to use Python 25 | # 3) 26 | - dist: xenial 27 | env: CI_TARGET=vim DISTRO=xenial VERSION=latest 28 | python: 3.5 29 | - dist: xenial 30 | env: CI_TARGET=vim DISTRO=xenial VERSION=latest 31 | python: 3.6 32 | 33 | - dist: xenial 34 | env: CI_TARGET=neovim DISTRO=xenial VERSION=master 35 | python: 3.5 36 | - dist: xenial 37 | env: CI_TARGET=neovim DISTRO=xenial VERSION=master 38 | python: 3.6 39 | 40 | addons: 41 | apt: 42 | packages: 43 | - autoconf 44 | - automake 45 | - cmake 46 | - g++ 47 | - gettext 48 | - libgtk2.0-dev 49 | - libgnome2-dev 50 | - libtool 51 | - ninja-build 52 | - pkg-config 53 | - unzip 54 | - vim-gnome 55 | - xvfb 56 | 57 | before_script: 58 | - if [ "${CI_TARGET}" == "neovim" ]; then 59 | sudo apt-get install libtool-bin; 60 | fi 61 | - pip install -U pip 62 | - git submodule update --init --recursive 63 | - mkdir -p ${CACHE} 64 | 65 | - cd ${TRAVIS_BUILD_DIR} 66 | - git clone --quiet --recursive --depth 1 --branch=hdlcc_ci 67 | https://github.com/suoto/hdlcc_ci ../hdlcc_ci 68 | 69 | - ./.ci/setup_ghdl.sh 70 | - if [ "${CI_TARGET}" == "vim" ]; then source ./.ci/setup_vim.sh; fi 71 | - if [ "${CI_TARGET}" == "neovim" ]; then source ./.ci/setup_nvim.sh; fi 72 | 73 | script: 74 | - set +xe 75 | - xvfb-run --server-args='-screen 0, 1024x768x24' -e /dev/stdout 76 | ./run_tests.sh --log-capture -F 77 | 78 | after_success: 79 | - export COVERALLS_PARALLEL=true 80 | - coveralls 81 | - bash <(curl -s https://codecov.io/bash) 82 | after_failure: 83 | - echo '##########################################################' 84 | - echo '##########################################################' 85 | - cat /tmp/vim-hdl.log 86 | - echo '##########################################################' 87 | - echo '##########################################################' 88 | - cat /tmp/hdlcc-stdout.log 89 | - echo '##########################################################' 90 | - echo '##########################################################' 91 | - cat /tmp/hdlcc-stderr.log 92 | - echo '##########################################################' 93 | - echo '##########################################################' 94 | - cat /tmp/hdlcc.log 95 | - echo '##########################################################' 96 | - echo '##########################################################' 97 | - if [ "${CI_TARGET}" == "neovim" ]; then 98 | nvim +checkhealth +"w health.log" +qa; 99 | cat health.log 100 | fi 101 | - echo '##########################################################' 102 | - echo '##########################################################' 103 | -------------------------------------------------------------------------------- /.ci/vimrc: -------------------------------------------------------------------------------- 1 | if has('python3') 2 | let s:using_python2 = 0 3 | elseif has('python') 4 | let s:using_python2 = 1 5 | else 6 | throw "Unable to identify Python version" 7 | endif 8 | 9 | syntax off 10 | filetype plugin indent on 11 | set nocompatible 12 | 13 | set shortmess=filnxtToO 14 | 15 | if $CI == "true" 16 | set rtp+=~/.vim/syntastic 17 | set rtp+=~/.vim/vim-hdl 18 | else 19 | set rtp+=~/dot_vim/syntastic 20 | set rtp+=~/dot_vim/vim-hdl 21 | endif 22 | 23 | function! s:Pyeval( eval_string ) "{ Inspired on YCM 24 | if s:using_python2 25 | return pyeval( a:eval_string ) 26 | endif 27 | return py3eval( a:eval_string ) 28 | endfunction 29 | "} 30 | " 31 | let s:python_until_eof = s:using_python2 ? "python << EOF" : "python3 << EOF" 32 | let s:python_command = s:using_python2 ? "py " : "py3 " 33 | 34 | let g:syntastic_always_populate_loc_list = 1 35 | let g:syntastic_auto_loc_list = 0 36 | let g:syntastic_check_on_open = 0 37 | let g:syntastic_check_on_wq = 1 38 | 39 | let g:syntastic_vhdl_vimhdl_sort = 0 40 | let g:vimhdl_auto_save_created_config_file = 1 41 | 42 | let g:vimhdl_log_level = 'DEBUG' 43 | let g:vimhdl_log_file = getcwd() . '/hdl_checker.log' 44 | 45 | " To avoid Press "ENTER..." message 46 | set cmdheight=15 47 | 48 | function! s:SetupPythonEnv() abort 49 | 50 | if exists('g:ci_setup_done') && g:ci_setup_done 51 | return 52 | endif 53 | 54 | exec s:python_until_eof 55 | import logging 56 | import sys 57 | import os 58 | import os.path as p 59 | from threading import Lock 60 | 61 | import six 62 | 63 | def setupLogging(stream, level, color=True): # pragma: no cover 64 | "Setup logging according to the command line parameters" 65 | if isinstance(stream, six.string_types): 66 | class Stream(object): 67 | """ 68 | File subclass that allows RainbowLoggingHandler to write 69 | with colors 70 | """ 71 | _lock = Lock() 72 | _color = color 73 | 74 | def __init__(self, *args, **kwargs): 75 | self._fd = open(*args, **kwargs) 76 | 77 | def isatty(self): 78 | """ 79 | Tells if this stream accepts control chars 80 | """ 81 | return self._color 82 | 83 | def write(self, text): 84 | """ 85 | Writes to the stream 86 | """ 87 | with self._lock: 88 | self._fd.write(text.encode('utf-8', errors='replace')) 89 | 90 | _stream = Stream(stream, 'ab', buffering=1) 91 | else: 92 | _stream = stream 93 | 94 | handler = logging.StreamHandler(_stream) 95 | handler.formatter = logging.Formatter( 96 | '%(levelname)-7s | %(asctime)s | ' + 97 | '%(name)s @ %(funcName)s():%(lineno)d %(threadName)s ' + 98 | '|\t%(message)s', datefmt='%H:%M:%S') 99 | 100 | 101 | logging.getLogger('urllib3').setLevel(logging.WARNING) 102 | logging.getLogger('pynvim').setLevel(logging.WARNING) 103 | 104 | logging.root.addHandler(handler) 105 | logging.root.setLevel(level) 106 | 107 | 108 | def setupVimLogging(): 109 | log_path = '/tmp' 110 | log_file = p.join(log_path, 'vim-hdl.log') 111 | index = 0 112 | while True: 113 | try: 114 | open(log_file, 'a').close() 115 | break 116 | except IOError: 117 | log_file = p.join(log_path, 'vim_log_%d_%d.log' % (os.getpid(), index)) 118 | index += 1 119 | logging.getLogger('requests').setLevel(logging.WARNING) 120 | logging.getLogger('nose2').setLevel(logging.INFO) 121 | logging.getLogger('pynvim').setLevel(logging.INFO) 122 | logging.getLogger('urllib3').setLevel(logging.INFO) 123 | setupLogging(log_file, logging.DEBUG, True) 124 | 125 | setupVimLogging() 126 | 127 | _logger = logging.getLogger(__name__) 128 | 129 | _logger.info("Set up vim python logger") 130 | _logger.info("Python path is: %s", sys.path) 131 | 132 | import vim 133 | 134 | try: 135 | import coverage 136 | _logger.info("Coverage module succesfully imported") 137 | cov = coverage.Coverage(config_file='.coveragerc') 138 | cov.start() 139 | 140 | def onVimLeave(): 141 | try: 142 | global cov 143 | cov.stop() 144 | cov.save() 145 | _logger.info("Coverage data saved") 146 | except: 147 | _logger.exception("Unable to save coverage data") 148 | 149 | except: 150 | _logger.fatal("Unable to import 'coverage'") 151 | def onVimLeave(): 152 | _logger.warning("No coverage started, can't stop it") 153 | 154 | EOF 155 | autocmd! VimLeavePre * :silent! call s:Pyeval('onVimLeave()') 156 | 157 | let g:ci_setup_done = 1 158 | 159 | endfunction 160 | 161 | call s:SetupPythonEnv() 162 | 163 | -------------------------------------------------------------------------------- /run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # This file is part of vim-hdl. 3 | # 4 | # Copyright (c) 2015-2016 Andre Souto 5 | # 6 | # vim-hdl is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # vim-hdl is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with vim-hdl. If not, see . 18 | 19 | ############################################################################## 20 | # Parse CLI arguments ######################################################## 21 | ############################################################################## 22 | RUNNER_ARGS=() 23 | 24 | while [ -n "$1" ]; do 25 | case "$1" in 26 | -C) CLEAN_AND_QUIT="1";; 27 | -c) CLEAN="1";; 28 | *) RUNNER_ARGS+=($1) 29 | esac 30 | shift 31 | done 32 | 33 | ############################################################################## 34 | # If we're not running inside CI, adjust some variables to mimic it ########## 35 | ############################################################################## 36 | if [ -z "${CI}" ]; then 37 | if [ -z "${CI_TARGET}" ]; then 38 | CI_TARGET=vim 39 | fi 40 | 41 | VIRTUAL_ENV_DEST=~/dev/vimhdl_venv 42 | 43 | if [ -z "${VERSION}" ]; then 44 | VERSION=master 45 | fi 46 | 47 | fi 48 | 49 | ############################################################################## 50 | # Functions ################################################################## 51 | ############################################################################## 52 | function _setup_ci_env { 53 | cmd="virtualenv --clear ${VIRTUAL_ENV_DEST}" 54 | 55 | if [ -n "${PYTHON}" ]; then 56 | cmd="$cmd --python=${PYTHON}" 57 | else 58 | cmd="$cmd --python=python3" 59 | fi 60 | 61 | $cmd 62 | # shellcheck disable=SC1090 63 | source ${VIRTUAL_ENV_DEST}/bin/activate 64 | 65 | } 66 | 67 | function _install_packages { 68 | pip install git+https://github.com/google/vroom 69 | pip install neovim 70 | 71 | pip install -r ./.ci/requirements.txt 72 | 73 | # Default Vim on Travis is always Python 2, install stuff for that as well 74 | if [ "${CI_TARGET}" == "vim" ] \ 75 | && [ -n "${CI}" ] \ 76 | && [[ ${TRAVIS_PYTHON_VERSION} == 3* ]]; then 77 | echo "sudo pip2 installing .ci/requirements.txt with" 78 | sudo -H pip2 install -r ./.ci/requirements.txt 79 | pip2 install -r ./.ci/requirements.txt --user 80 | fi 81 | 82 | } 83 | 84 | function _cleanup_if_needed { 85 | if [ -n "${CLEAN_AND_QUIT}${CLEAN}" ]; then 86 | git clean -fdx || exit -1 87 | git submodule foreach --recursive git clean -fdx || exit -1 88 | pushd ../hdlcc_ci/hdl_lib 89 | git reset HEAD --hard 90 | popd 91 | pushd ../hdlcc_ci/vim-hdl-examples 92 | git reset HEAD --hard 93 | popd 94 | 95 | if [ -n "${CLEAN_AND_QUIT}" ]; then exit; fi 96 | fi 97 | } 98 | 99 | function _setup_dotfiles { 100 | if [ "${CI}" == "true" ]; then 101 | DOT_VIM="$HOME/.vim" 102 | DOT_VIMRC="$HOME/.vimrc" 103 | else 104 | DOT_VIM="$HOME/dot_vim" 105 | DOT_VIMRC="$DOT_VIM/vimrc" 106 | fi 107 | 108 | mkdir -p "$DOT_VIM" 109 | if [ ! -d "$DOT_VIM/syntastic" ]; then 110 | git clone https://github.com/scrooloose/syntastic "$DOT_VIM/syntastic" 111 | fi 112 | if [ ! -d "$DOT_VIM/vim-hdl" ]; then 113 | ln -s "$PWD" "$DOT_VIM/vim-hdl" 114 | fi 115 | 116 | cp ./.ci/vimrc "$DOT_VIMRC" 117 | } 118 | 119 | ############################################################################## 120 | # Now to the script itself ################################################### 121 | ############################################################################## 122 | 123 | set -e 124 | 125 | # If we're not running on a CI server, create a virtual env to mimic its 126 | # behaviour 127 | if [ -z "${CI}" ]; then 128 | if [ -n "${CLEAN}" ] && [ -d "${VIRTUAL_ENV_DEST}" ]; then 129 | echo "Removing previous virtualenv" 130 | rm -rf ${VIRTUAL_ENV_DEST} 131 | fi 132 | _setup_ci_env 133 | fi 134 | 135 | _cleanup_if_needed 136 | _install_packages 137 | 138 | export PATH=${HOME}/builders/ghdl/bin/:${PATH} 139 | 140 | ghdl --version 141 | 142 | _setup_dotfiles 143 | 144 | if [ "${CI_TARGET}" == "vim" ]; then vim --version; fi 145 | if [ "${CI_TARGET}" == "neovim" ]; then nvim --version; fi 146 | 147 | echo "Terminal size is $COLUMNS x $LINES" 148 | 149 | set +e 150 | 151 | python -m coverage run -m nose2 -s .ci/ "${RUNNER_ARGS[@]}" 152 | 153 | RESULT=$? 154 | 155 | python -m coverage combine 156 | python -m coverage report 157 | python -m coverage html 158 | 159 | [ -z "${CI}" ] && [ -n "${VIRTUAL_ENV}" ] && deactivate 160 | 161 | exit ${RESULT} 162 | -------------------------------------------------------------------------------- /.ci/vroom/test_001_editing_multiple_files.vroom: -------------------------------------------------------------------------------- 1 | Macro that checks if the quickfix is empty 2 | @macro (assert_qf_empty) 3 | :echom &ft 4 | ~ vhdl 5 | :silent! SyntasticCheck 6 | :silent! lopen 7 | :echom getline('.') 8 | & 9 | :quit 10 | @endmacro 11 | 12 | Macro that checks if vimhdl is enabled 13 | @macro (vimhdl_check) 14 | :SyntasticInfo 15 | ~ Syntastic version:.* (regex) 16 | ~ Info for filetype: vhdl 17 | ~ Global mode: active 18 | ~ Filetype vhdl is active 19 | ~ The current file will be checked automatically 20 | ~ Available checker(s:|:)\s*.*\bvimhdl\b.* (regex) 21 | ~ Currently enabled checker(s:|:)\s*.*\bvimhdl\b.* (regex) 22 | @endmacro 23 | 24 | Macro that writes and waits for the save msg (seems needed in some cases) 25 | @macro (write) 26 | :write 27 | ~ ".*".*\swritten (regex) 28 | @endmacro 29 | 30 | 31 | 32 | 33 | Edit different files under the same project 34 | @system (RELAXED) 35 | :read !ghdl --version 36 | ! ghdl --version 37 | ~ \d+ more lines (regex) 38 | & 39 | GHDL 0.33 .* (regex) 40 | \s*Compiled with .* (regex) 41 | \s*GCC back-end code generator (regex) 42 | Written by Tristan Gingold. 43 | & 44 | Copyright (C) 2003 - 2015 Tristan Gingold. (verbatim) 45 | GHDL is free software, covered by the GNU General Public License. There is NO (verbatim) 46 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. (verbatim) 47 | @system 48 | 49 | 50 | 51 | :let g:vimhdl_conf_file = getcwd() . '/../hdlcc_ci/hdl_lib/ghdl.prj' 52 | :cd ../hdlcc_ci/hdl_lib 53 | :edit common_lib/edge_detector.vhd 54 | @do (vimhdl_check) 55 | 56 | Again, this file has no errors 57 | @do (assert_qf_empty) 58 | 59 | Remove an important line so the builder must tell there's an error 60 | > /^end\s\+edge_detector 61 | > dd 62 | :echom getline('.') 63 | ~ end edge_detector; 64 | @do (write) 65 | :silent! SyntasticCheck 66 | :silent! lopen 67 | common_lib/edge_detector.vhd|35 col 1 error| 'end' is expected instead of 'architecture' 68 | :lclose 69 | > u 70 | @do (write) 71 | @do (assert_qf_empty) 72 | 73 | 74 | 75 | Ok, so the previous file worked fine. Let's open another file that our edge_detector 76 | depends on, like the sr_delay 77 | :edit common_lib/sr_delay.vhd 78 | Again, this file has no errors 79 | @do (write) 80 | :lclose 81 | @do (assert_qf_empty) 82 | 83 | Let's rename the 'clken' port to 'clk_en' 84 | :%s/\/clk_en/g 85 | This won't cause errors for this file 86 | @do (write) 87 | :lclose 88 | @do (assert_qf_empty) 89 | 90 | 91 | 92 | But our edge detector should warn that a port named 'clken' doens't exist 93 | anymore 94 | :edit common_lib/edge_detector.vhd 95 | @do (write) 96 | :silent! lopen 97 | common_lib/edge_detector.vhd|74 col 24 error| no interface for 'clken' in association 98 | :lclose 99 | 100 | Let's undo our changes 101 | :edit common_lib/sr_delay.vhd 102 | :%s/\/clken/g 103 | @do (write) 104 | :lclose 105 | @do (assert_qf_empty) 106 | 107 | Again, this should propagate 108 | :edit common_lib/edge_detector.vhd 109 | @do (write) 110 | :lclose 111 | @do (assert_qf_empty) 112 | 113 | 114 | 115 | We'll edit a packge that both sr_delay and the edge_detector depend. Let's see 116 | what happens! 117 | :edit common_lib/common_pkg.vhd 118 | :lclose 119 | @do (assert_qf_empty) 120 | :10 121 | > o constant SOME_CONSTANT : integer := 14 122 | @do (write) 123 | :silent! SyntasticCheck 124 | :silent! lopen 125 | common_lib/common_pkg.vhd|12 col 5 error| ';' is expected instead of 'function' 126 | :q 127 | 128 | > a; 129 | @do (write) 130 | :lclose 131 | @do (assert_qf_empty) 132 | 133 | 134 | The package has changed but neither the edge_detector or sr_delay have been 135 | rebuilt 136 | :edit common_lib/edge_detector.vhd 137 | @do (write) 138 | :lclose 139 | @do (assert_qf_empty) 140 | 141 | Let's rebuild 142 | :edit common_lib/synchronizer.vhd 143 | @do (write) 144 | :lclose 145 | @do (assert_qf_empty) 146 | 147 | Let's rebuild 148 | :edit common_lib/sr_delay.vhd 149 | @do (write) 150 | :lclose 151 | @do (assert_qf_empty) 152 | 153 | 154 | The package has changed but neither the edge_detector or sr_delay have been 155 | rebuilt 156 | :edit common_lib/edge_detector.vhd 157 | @do (write) 158 | :lclose 159 | @do (assert_qf_empty) 160 | 161 | 162 | 163 | Corrupt hdl_checker database, check it actually fails and then ask it to 164 | rebuild to confirm it works again 165 | :edit common_lib/edge_detector.vhd 166 | @do (write) 167 | :lclose 168 | @do (assert_qf_empty) 169 | Delete some internals 170 | @system (RELAXED) 171 | :!rm -rf .hdl_checker/*cf 172 | ! rm -rf .hdl_checker/.* (regex) 173 | @system 174 | Checking right now should fail 175 | :silent! SyntasticCheck 176 | :silent! lopen 177 | common_lib/edge_detector\.vhd|13 col 20 error| (primary)? unit "common_pkg" not found in library "common_lib" (regex) 178 | :lclose 179 | Rebuild and check that there's no errors 180 | :VimhdlRebuildProject 181 | :silent! SyntasticCheck 182 | @do (assert_qf_empty) 183 | -------------------------------------------------------------------------------- /python/vimhdl/base_requests.py: -------------------------------------------------------------------------------- 1 | # This file is part of vim-hdl. 2 | # 3 | # Copyright (c) 2015-2016 Andre Souto 4 | # 5 | # vim-hdl is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # vim-hdl is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with vim-hdl. If not, see . 17 | """ 18 | Wrapper for vim-hdl usage within Vim's Python interpreter 19 | """ 20 | 21 | import json 22 | import logging 23 | from threading import Thread 24 | 25 | import requests 26 | 27 | _logger = logging.getLogger(__name__) 28 | 29 | 30 | class BaseRequest(object): # pylint: disable=useless-object-inheritance 31 | """ 32 | Base request object 33 | """ 34 | 35 | _meth = "" 36 | timeout = 10 37 | url = None 38 | 39 | def __init__(self, **kwargs): 40 | self.payload = kwargs 41 | _logger.debug( 42 | "Creating request for '%s' with payload '%s'", self._meth, self.payload 43 | ) 44 | 45 | def sendRequestAsync(self, func=None): 46 | """ 47 | Processes the request in a separate thread and puts the 48 | received request on queue Q 49 | """ 50 | 51 | def asyncRequest(): 52 | """ 53 | Simple asynchronous request wrapper 54 | """ 55 | try: 56 | result = self.sendRequest() 57 | if func is not None: 58 | func(result) 59 | except: # pragma: no cover 60 | _logger.exception("Error sending request") 61 | raise 62 | 63 | Thread(target=asyncRequest).start() 64 | 65 | def sendRequest(self): 66 | """ 67 | Blocking send request. Returns a response object should the 68 | server respond. It only catches a ConnectionError exception 69 | (this means the server could not be reached). In this case, 70 | return is None 71 | """ 72 | try: 73 | response = requests.post( 74 | self.url + "/" + self._meth, data=self.payload, timeout=self.timeout 75 | ) 76 | if not response.ok: # pragma: no cover 77 | _logger.warning("Server response error: '%s'", response.text) 78 | response = None 79 | 80 | # Both requests and urllib3 have different exceptions depending 81 | # on their versions, so we'll catch any exceptions for now until 82 | # we work out which ones actually happen 83 | except BaseException as exc: 84 | _logger.warning( 85 | "Sending request '%s' raised exception: '%s'", str(self), str(exc) 86 | ) 87 | return None 88 | 89 | return response 90 | 91 | 92 | class RequestMessagesByPath(BaseRequest): 93 | """ 94 | Request messages for the quickfix list 95 | """ 96 | 97 | _meth = "get_messages_by_path" 98 | 99 | def __init__(self, project_file, path): 100 | super(RequestMessagesByPath, self).__init__( 101 | project_file=project_file, path=path 102 | ) 103 | 104 | 105 | class RequestQueuedMessages(BaseRequest): 106 | """ 107 | Request UI messages 108 | """ 109 | 110 | _meth = "get_ui_messages" 111 | 112 | def __init__(self, project_file): 113 | super(RequestQueuedMessages, self).__init__(project_file=project_file) 114 | 115 | 116 | class RequestHdlCheckerInfo(BaseRequest): 117 | """ 118 | Request UI messages 119 | """ 120 | 121 | _meth = "get_diagnose_info" 122 | 123 | def __init__(self, project_file=None): 124 | super(RequestHdlCheckerInfo, self).__init__(project_file=project_file) 125 | 126 | 127 | class ListWorkingBuilders(BaseRequest): 128 | """ 129 | Request a list of checkers that can be used 130 | """ 131 | 132 | _meth = "get_working_builders" 133 | 134 | 135 | class RequestProjectRebuild(BaseRequest): 136 | """ 137 | Request UI messages 138 | """ 139 | 140 | _meth = "rebuild_project" 141 | 142 | def __init__(self, project_file=None): 143 | super(RequestProjectRebuild, self).__init__(project_file=project_file) 144 | 145 | 146 | class GetDependencies(BaseRequest): 147 | """ 148 | Notifies the server that a buffer has been left 149 | """ 150 | 151 | _meth = "get_dependencies" 152 | 153 | def __init__(self, project_file, path): 154 | super(GetDependencies, self).__init__(project_file=project_file, path=path) 155 | 156 | 157 | class GetBuildSequence(BaseRequest): 158 | """ 159 | Notifies the server that a buffer has been left 160 | """ 161 | 162 | _meth = "get_build_sequence" 163 | 164 | def __init__(self, project_file, path): 165 | super(GetBuildSequence, self).__init__(project_file=project_file, path=path) 166 | 167 | 168 | class RunConfigGenerator(BaseRequest): 169 | """ 170 | Notifies the server that a buffer has been left 171 | """ 172 | 173 | _meth = "run_config_generator" 174 | 175 | def __init__(self, generator, *args, **kwargs): 176 | super(RunConfigGenerator, self).__init__( 177 | generator=generator, args=json.dumps(args), kwargs=json.dumps(kwargs) 178 | ) 179 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vim-hdl 2 | 3 | ## May I have your attention please? 4 | 5 | **[HDL Checker][hdl_checker] implements the core functionality of `vim-hdl` and 6 | because it now supports [Language Server Protocol][LSP], `vim-hdl` is being 7 | deprecated** 8 | 9 | ### How to continue using HDL Checker 10 | 11 | Any [LSP client][LSP_clients] should work, be it on Vim or other editors. 12 | 13 | Have a look at [HDL Checker supported editors][hdl_checker_editor_support] to 14 | check some examples of how to set it up. 15 | 16 | ### But I want to keep using Syntastic! 17 | 18 | You'll need to install HDL Checker pip package: 19 | 20 | ``` 21 | pip install hdl-checker --upgrade 22 | ``` 23 | 24 | or 25 | 26 | ``` 27 | pip install hdl-checker --upgrade --user 28 | ``` 29 | 30 | Just make sure you can run `hdl_checker --version` and it should work just fine. 31 | 32 | ### Rationale 33 | 34 | Back when vim-hdl started, Vim did not have the widespread support for LSP it has 35 | today and with it I can actually focus in the core functionality and support more 36 | platforms at the same time. This last update is likely the last one! 37 | 38 | --- 39 | 40 | [![Build Status](https://travis-ci.org/suoto/vim-hdl.svg?branch=master)](https://travis-ci.org/suoto/vim-hdl) 41 | [![codecov](https://codecov.io/gh/suoto/vim-hdl/branch/master/graph/badge.svg)](https://codecov.io/gh/suoto/vim-hdl) 42 | [![Join the chat at https://gitter.im/suoto/vim-hdl](https://badges.gitter.im/suoto/vim-hdl.svg)](https://gitter.im/suoto/vim-hdl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 43 | [![Analytics](https://ga-beacon.appspot.com/UA-68153177-3/vim-hdl/README.md?pixel)](https://github.com/suoto/vim-hdl) 44 | 45 | vim-hdl is a Vim plugin that uses [HDL Checker][hdl_checker] to provide some 46 | helpers to VHDL development: 47 | 48 | * Syntax checking (using 49 | [third-party-compilers](#supported-third-party-compilers) + 50 | [Syntastic][Syntastic]) 51 | * [Style checking](#style-checking) 52 | 53 | --- 54 | 55 | ![vim-hdl screenshot](http://i.imgur.com/2hZox5r.gif) 56 | 57 | --- 58 | 59 | ## Installation 60 | 61 | ### [Pathogen][pathogen] 62 | 63 | ```bash 64 | cd ~/.vim/bundle/ 65 | git clone https://github.com/suoto/vim-hdl.git 66 | ``` 67 | 68 | ### [Vundle][vundle] 69 | 70 | In your .vimrc: 71 | 72 | ```viml 73 | Plugin 'suoto/vim-hdl' 74 | ``` 75 | 76 | ### Notes 77 | 78 | * Requires Vim compiled with Python support, plus features needed by 79 | [Syntastic][Syntastic] itself 80 | * Only tested on Linux with recent Vim versions (7.4+) 81 | 82 | --- 83 | 84 | ## Usage 85 | 86 | vim-hdl requires a configuration file listing libraries, source files, build 87 | flags, etc. Select the configuration file via 88 | 89 | ```viml 90 | " Configure the project file 91 | let g:vimhdl_conf_file = '' 92 | ``` 93 | 94 | You use the `VimhdlCreateProjectFile` command to search and help you setting up 95 | the configuration file 96 | 97 | ```viml 98 | :VimhdlCreateProjectFile 99 | ``` 100 | 101 | See the [wiki](https://github.com/suoto/hdl_checker/wiki) for details on how to write 102 | it. 103 | 104 | Any other [Syntastic][Syntastic] option should work as well. 105 | 106 | You can clone [vim-hdl-examples][vim-hdl-examples] repository and try a ready to 107 | use setup. 108 | 109 | --- 110 | 111 | ## Supported third-party compilers 112 | 113 | * [Mentor Graphics® ModelSim®][Mentor_msim] 114 | * [ModelSim-Altera® Edition][Altera_msim] 115 | * [GHDL][GHDL] 116 | 117 | --- 118 | 119 | ## Style checking 120 | 121 | Style checks are independent of a third-party compiler. Checking includes: 122 | 123 | * Signal names in lower case 124 | * Constants and generics in upper case 125 | * Unused signals, constants, generics, shared variables, libraries, types and 126 | attributes 127 | * Comment tags (`FIXME`, `TODO`, `XXX`) 128 | 129 | Notice that currently the unused reports has caveats, namely declarations with 130 | the same name inherited from a component, function, procedure, etc. In the 131 | following example, the signal `rdy` won't be reported as unused in spite of the 132 | fact it is not used. 133 | 134 | ```vhdl 135 | signal rdy, refclk, rst : std_logic; 136 | ... 137 | 138 | idelay_ctrl_u : idelay_ctrl 139 | port map (rdy => open, 140 | refclk => refclk, 141 | rst => rst); 142 | ``` 143 | 144 | --- 145 | 146 | ## Issues 147 | 148 | * [vim-hdl issue tracker][vimhdl_issue_tracker] should be used for bugs, feature 149 | requests, etc related to the Vim client itself (something that only happens 150 | with Vim) 151 | * [HDL Checker issue tracker][hdl_checker_issue_tracker] should be used for bugs, 152 | feature requests, etc related to the code checker backend. 153 | 154 | If unsure, use [vim-hdl issue tracker][vimhdl_issue_tracker], it will be moved to 155 | [HDL Checker issue tracker][hdl_checker_issue_tracker] if applicable. 156 | 157 | ## License 158 | 159 | This software is licensed under the [GPL v3 license][gpl]. 160 | 161 | ## Notice 162 | 163 | Mentor Graphics®, ModelSim® and their respective logos are trademarks or 164 | registered trademarks of Mentor Graphics, Inc. 165 | 166 | Altera® and its logo is a trademark or registered trademark of Altera 167 | Corporation. 168 | 169 | Xilinx® and its logo is a trademark or registered trademark of Xilinx, Inc. 170 | 171 | vim-hdl's author has no connection or affiliation to any of the trademarks 172 | mentioned or used by this software. 173 | 174 | [Altera_msim]: https://www.altera.com/downloads/download-center.html 175 | [ConfigParser]: https://docs.python.org/2/library/configparser.html 176 | [GHDL]: https://github.com/tgingold/ghdl 177 | [gpl]: http://www.gnu.org/copyleft/gpl.html 178 | [hdl_checker]: https://github.com/suoto/hdl_checker 179 | [hdl_checker_editor_support]: https://github.com/suoto/hdl_checker#editor-support 180 | [hdl_checker_issue_tracker]: https://github.com/suoto/hdl_checker/issues 181 | [LSP]: https://en.wikipedia.org/wiki/Language_Server_Protocol 182 | [Mentor_msim]: http://www.mentor.com/products/fv/modelsim/ 183 | [pathogen]: https://github.com/tpope/vim-pathogen 184 | [Syntastic]: https://github.com/scrooloose/syntastic 185 | [vim-hdl-examples]: https://github.com/suoto/vim-hdl-examples 186 | [vimhdl_issue_tracker]: https://github.com/suoto/vim-hdl/issues 187 | [vundle]: https://github.com/VundleVim/Vundle.vim 188 | [Xilinx_Vivado]: http://www.xilinx.com/products/design-tools/vivado/vivado-webpack.html 189 | [LSP_clients]: https://microsoft.github.io/language-server-protocol/implementors/tools/ 190 | -------------------------------------------------------------------------------- /python/vimhdl/vim_helpers.py: -------------------------------------------------------------------------------- 1 | # This file is part of vim-hdl. 2 | # 3 | # Copyright (c) 2015-2016 Andre Souto 4 | # 5 | # vim-hdl is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # vim-hdl is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with vim-hdl. If not, see . 17 | "Misc helpers for common vim-hdl operations" 18 | 19 | import json 20 | import logging 21 | import os.path as p 22 | import socket 23 | 24 | import vim # type: ignore # pylint: disable=import-error 25 | 26 | _logger = logging.getLogger(__name__) 27 | 28 | 29 | def _toUnicode(value): # pragma: no cover 30 | """ 31 | Returns a unicode type; either the new python-future str type or 32 | the real unicode type. The difference shouldn't matter. 33 | 34 | These were "Borrowed" from YCM. 35 | See https://github.com/Valloric/YouCompleteMe 36 | """ 37 | if not value: 38 | return str() 39 | if isinstance(value, str): 40 | return value 41 | if isinstance(value, bytes): 42 | # All incoming text should be utf8 43 | return str(value, "utf8") 44 | return str(value) 45 | 46 | 47 | def _escapeForVim(text): 48 | """ 49 | Escape text for Vim. 50 | """ 51 | return _toUnicode(text.replace("'", "' . \"'\" . '")) 52 | 53 | 54 | def toVimDict(obj, vim_variable): 55 | """ 56 | Converts the 'obj' dict to a Vim dictionary by iterating over the 57 | key/value pairs. The reason for this is because Vim has some issues 58 | interpreting strings with both escaped single and double quotes (or 59 | I haven't found a way to code it properly...). The thing is, in some 60 | cases, doing vim.command('let foo = ') often fails when 61 | key or value has both single and double quotes, but it works if 62 | the fields are assigned individually, because we can force which 63 | one of the quotes will require escape 64 | """ 65 | vim.command("let %s = { }" % vim_variable) 66 | for key, value in obj.items(): 67 | if isinstance(value, (str, bytes)): 68 | value = _escapeForVim(value) 69 | if isinstance(key, (str, bytes)): 70 | key = _escapeForVim(key) 71 | vim.command("let {0}['{1}'] = '{2}'".format(vim_variable, key, value)) 72 | 73 | 74 | def postVimInfo(message): 75 | """ 76 | These were "Borrowed" from YCM. 77 | See https://github.com/Valloric/YouCompleteMe 78 | """ 79 | _logger.info(message) 80 | vim.command( 81 | "redraw | echom '{0}' | echohl None".format(_escapeForVim(str(message))) 82 | ) 83 | 84 | 85 | def postVimWarning(message): 86 | """ 87 | These were "Borrowed" from YCM. 88 | See https://github.com/Valloric/YouCompleteMe 89 | """ 90 | _logger.warning(message) 91 | vim.command( 92 | "redraw | echohl WarningMsg | echom '{0}' | echohl None".format( 93 | _escapeForVim(str(message)) 94 | ) 95 | ) 96 | 97 | 98 | def postVimError(message): 99 | """ 100 | These were "Borrowed" from YCM. 101 | See https://github.com/Valloric/YouCompleteMe 102 | """ 103 | _logger.error(message) 104 | vim.command( 105 | "echohl ErrorMsg | echom '{0}' | echohl None".format( 106 | _escapeForVim(str(message)) 107 | ) 108 | ) 109 | 110 | 111 | def getUnusedLocalhostPort(): 112 | """ 113 | These were "Borrowed" from YCM. 114 | See https://github.com/Valloric/YouCompleteMe 115 | """ 116 | sock = socket.socket() 117 | # This tells the OS to give us any free port in the range [1024 - 65535] 118 | sock.bind(("", 0)) 119 | port = sock.getsockname()[1] 120 | sock.close() 121 | return port 122 | 123 | 124 | # Methods of accessing g: and b: work only with Vim 7.4+ 125 | 126 | 127 | def _getVimGlobals(var=None): 128 | """ 129 | Returns a global variable, i.e., from g: 130 | """ 131 | if var is None: 132 | return vim.vars 133 | return vim.vars[var] 134 | 135 | 136 | def _getBufferVars(vbuffer=None, var=None): 137 | """ 138 | Returns a buffer variable, i.e., from b: 139 | """ 140 | if vbuffer is None: 141 | vbuffer = vim.current.buffer 142 | if var is None: 143 | return vbuffer.vars 144 | return vbuffer.vars[var] 145 | 146 | 147 | def getProjectFile(): 148 | """ 149 | Searches for a valid HDL Checker configuration file in buffer vars (i.e., 150 | inside b:) then in global vars (i.e., inside g:) 151 | """ 152 | if "vimhdl_conf_file" in _getBufferVars(): 153 | conf_file = p.abspath(p.expanduser(_getBufferVars(var="vimhdl_conf_file"))) 154 | if p.exists(p.dirname(conf_file)) and p.exists(conf_file): 155 | return conf_file 156 | 157 | _logger.debug("Buffer config file '%s' is set but not " "readable", conf_file) 158 | 159 | if "vimhdl_conf_file" in _getVimGlobals(): 160 | conf_file = p.abspath(p.expanduser(_getVimGlobals("vimhdl_conf_file"))) 161 | if p.exists(p.dirname(conf_file)) and p.exists(conf_file): 162 | return conf_file 163 | 164 | _logger.debug("Global config file '%s' is set but not " "readable", conf_file) 165 | 166 | _logger.info("Couldn't find a valid config file") 167 | return None 168 | 169 | 170 | # See YouCompleteMe/python/ycm/vimsupport.py 171 | def getIntValue(variable): 172 | return int(vim.eval(variable)) 173 | 174 | 175 | # See YouCompleteMe/python/ycm/vimsupport.py 176 | def presentDialog(message, choices, default_choice_index=0): 177 | """Presents the user with a dialog where a choice can be made. 178 | This will be a dialog for gvim users or a question in the message buffer 179 | for vim users or if `set guioptions+=c` was used. 180 | 181 | choices is list of alternatives. 182 | default_choice_index is the 0-based index of the default element 183 | that will get choosen if the user hits . Use -1 for no default. 184 | 185 | PresentDialog will return a 0-based index into the list 186 | or -1 if the dialog was dismissed by using , Ctrl-C, etc. 187 | 188 | If you are presenting a list of options for the user to choose from, such as 189 | a list of imports, or lines to insert (etc.), SelectFromList is a better 190 | option. 191 | 192 | See also: 193 | :help confirm() in vim (Note that vim uses 1-based indexes) 194 | 195 | Example call: 196 | PresentDialog("Is this a nice example?", ["Yes", "No", "May&be"]) 197 | Is this a nice example? 198 | [Y]es, (N)o, May(b)e:""" 199 | 200 | to_eval = "confirm('{0}', '{1}', {2})".format( 201 | _escapeForVim(_toUnicode(message)), 202 | _escapeForVim(_toUnicode("\n".join(choices))), 203 | default_choice_index + 1, 204 | ) 205 | try: 206 | return getIntValue(to_eval) - 1 207 | except KeyboardInterrupt: 208 | return -1 209 | return -1 210 | -------------------------------------------------------------------------------- /python/vimhdl/config_gen_wrapper.py: -------------------------------------------------------------------------------- 1 | # This file is part of vim-hdl. 2 | # 3 | # Copyright (c) 2015-2016 Andre Souto 4 | # 5 | # vim-hdl is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # vim-hdl is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with vim-hdl. If not, see . 17 | """ 18 | Wraps a piece of text and handles inserting _preface before it and then 19 | removing it when the user closes the file. Also handles back up and restoring 20 | in case something goes wrong 21 | """ 22 | 23 | import logging 24 | import os 25 | import os.path as p 26 | 27 | import six 28 | 29 | import vim # pylint: disable=import-error 30 | from vimhdl.vim_helpers import getProjectFile, presentDialog 31 | 32 | 33 | # Copied from ycmd 34 | def toBytes(value): # pragma: no cover 35 | """ 36 | Consistently returns the new bytes() type from python-future. 37 | Assumes incoming strings are either UTF-8 or unicode (which is 38 | converted to UTF-8). 39 | """ 40 | 41 | if not value: 42 | return bytes() 43 | 44 | # This is tricky. On py2, the bytes type from builtins (from python-future) is 45 | # a subclass of str. So all of the following are true: 46 | # isinstance(str(), bytes) 47 | # isinstance(bytes(), str) 48 | # But they don't behave the same in one important aspect: iterating over a 49 | # bytes instance yields ints, while iterating over a (raw, py2) str yields 50 | # chars. We want consistent behavior so we force the use of bytes(). 51 | 52 | if isinstance(value, bytes): 53 | return value 54 | 55 | # This is meant to catch Python 2's native str type. 56 | 57 | if isinstance(value, bytes): 58 | return bytes(value, encoding="utf8") 59 | 60 | if isinstance(value, str): 61 | # On py2, with `from builtins import *` imported, the following is true: 62 | # 63 | # bytes(str(u'abc'), 'utf8') == b"b'abc'" 64 | # 65 | # Obviously this is a bug in python-future. So we work around it. Also filed 66 | # upstream at: https://github.com/PythonCharmers/python-future/issues/193 67 | # We can't just return value.encode('utf8') on both py2 & py3 because on 68 | # py2 that *sometimes* returns the built-in str type instead of the newbytes 69 | # type from python-future. 70 | 71 | if six.PY2: 72 | return bytes(value.encode("utf8"), encoding="utf8") 73 | 74 | return bytes(value, encoding="utf8") 75 | 76 | # This is meant to catch `int` and similar non-string/bytes types. 77 | 78 | return toBytes(str(value)) 79 | 80 | 81 | class ConfigGenWrapper(object): 82 | """ 83 | Wraps a piece of text and handles inserting _preface before it and then 84 | removing it when the user closes the file. Also handles back up and 85 | restoring in case something goes wrong 86 | """ 87 | 88 | _preface = """\ 89 | # This is the resulting project file, please review and save when done. The 90 | # g:vimhdl_conf_file variable has been temporarily changed to point to this 91 | # file should you wish to open HDL files and test the results. When finished, 92 | # close this buffer; you''ll be prompted to either use this file or revert to 93 | # the original one. 94 | # 95 | # ---- Everything up to this line will be automatically removed ----""" 96 | 97 | # If the user hasn't already set vimhdl_conf_file in g: or b:, we'll use 98 | # this instead 99 | _default_conf_filename = "vimhdl.prj" 100 | 101 | _logger = logging.getLogger(__name__) 102 | 103 | def __init__(self): 104 | self._project_file = toBytes( 105 | getProjectFile() or self._default_conf_filename 106 | ).decode() 107 | 108 | self._backup_file = p.join( 109 | p.dirname(self._project_file), 110 | "." + p.basename(self._project_file) + ".backup", 111 | ) 112 | 113 | def run(self, text): 114 | """ 115 | Runs the wrapper using 'text' as content 116 | """ 117 | # Cleanup autogroups before doing anything 118 | vim.command("autocmd! vimhdl BufUnload") 119 | 120 | # In case no project file was set and we used the default one 121 | if "vimhdl_conf_file" not in vim.vars: 122 | vim.vars["vimhdl_conf_file"] = self._project_file 123 | 124 | # Backup 125 | if p.exists(self._project_file): 126 | self._logger.info( 127 | "Backing up %s to %s", self._project_file, self._backup_file 128 | ) 129 | os.rename(self._project_file, self._backup_file) 130 | 131 | contents = "\n".join([str(self._preface), text, "", "# vim: filetype=vimhdl"]) 132 | 133 | self._logger.info("Writing contents to %s", self._project_file) 134 | open(self._project_file, "w").write(contents) 135 | 136 | # Need to open the resulting file and then setup auto commands to avoid 137 | # triggering them when loading / unloading the new buffer 138 | self._openResultingFileForEdit() 139 | self._setupOnQuitAutocmds() 140 | 141 | def _setupOnQuitAutocmds(self): 142 | """ 143 | Creates an autocmd for the specified file only 144 | """ 145 | self._logger.debug("Setting up auto cmds for %s", self._project_file) 146 | # Create hook to remove preface text when closing the file 147 | vim.command("augroup vimhdl") 148 | vim.command( 149 | "autocmd BufUnload %s :call s:onVimhdlTempQuit()" 150 | % p.abspath(self._project_file) 151 | ) 152 | vim.command("augroup END") 153 | 154 | def _openResultingFileForEdit(self): 155 | """ 156 | Opens the resulting conf file for editing so the user can tweak and 157 | test 158 | """ 159 | self._logger.debug("Opening resulting file for edition") 160 | # If the current buffer is already pointing to the project file, reuse 161 | # it 162 | if not p.exists(vim.current.buffer.name) or p.samefile( 163 | vim.current.buffer.name, self._project_file 164 | ): 165 | vim.command("edit! %s" % self._project_file) 166 | else: 167 | vim.command("vsplit %s" % self._project_file) 168 | 169 | vim.current.buffer.vars["is_vimhdl_generated"] = True 170 | vim.command("set filetype=vimhdl") 171 | 172 | def onVimhdlTempQuit(self): 173 | """ 174 | Callback for closing the generated project file to remove the preface 175 | from the buffer contents 176 | """ 177 | # Don't touch files created by the user of files where the preface has 178 | # already been (presumably) taken out 179 | if not vim.current.buffer.vars.get("is_vimhdl_generated", False): 180 | return 181 | 182 | # No pop on Vim's RemoteMap dictionary 183 | del vim.current.buffer.vars["is_vimhdl_generated"] 184 | # No need to call this again 185 | vim.command("autocmd! vimhdl BufUnload") 186 | 187 | try: 188 | should_save = vim.vars["vimhdl_auto_save_created_config_file"] == 1 189 | except KeyError: 190 | # Ask if the user wants to use the resulting file or if the backup 191 | # should be restored 192 | should_save = ( 193 | presentDialog( 194 | "Project file contents were modified, should save changes or " 195 | "restore backup?", 196 | ["Save changes", "Restore backup"], 197 | ) 198 | == 0 199 | ) 200 | 201 | if should_save: 202 | self._removePrefaceAndSave() 203 | else: 204 | self._restoreBackup() 205 | 206 | def _restoreBackup(self): 207 | """ 208 | Restores the backup file (if exists) as the main project file 209 | """ 210 | if p.exists(self._backup_file): 211 | os.rename(self._backup_file, self._project_file) 212 | else: 213 | self._logger.info("No backup file exists, can't recover") 214 | 215 | def _removePrefaceAndSave(self): 216 | """ 217 | Remove contents until the line we said we would and save the file 218 | """ 219 | # Search for the last line we said we'd remove 220 | lnum = 0 221 | for lnum, line in enumerate(vim.current.buffer): 222 | if "Everything up to this line will be automatically removed" in line: 223 | self._logger.debug("Breaing at line %d", lnum) 224 | break 225 | 226 | # Remove line not found 227 | if not lnum: 228 | return 229 | 230 | # Update and save 231 | vim.current.buffer[:] = list(vim.current.buffer)[lnum + 1 :] 232 | vim.command("write!") 233 | -------------------------------------------------------------------------------- /autoload/vimhdl.vim: -------------------------------------------------------------------------------- 1 | " This file is part of vim-hdl. 2 | " 3 | " Copyright (c) 2015-2016 Andre Souto 4 | " 5 | " vim-hdl is free software: you can redistribute it and/or modify 6 | " it under the terms of the GNU General Public License as published by 7 | " the Free Software Foundation, either version 3 of the License, or 8 | " (at your option) any later version. 9 | " 10 | " vim-hdl is distributed in the hope that it will be useful, 11 | " but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | " GNU General Public License for more details. 14 | " 15 | " You should have received a copy of the GNU General Public License 16 | " along with vim-hdl. If not, see . 17 | " 18 | let s:vimhdl_path = escape(expand(':p:h'), '\') . '/../' 19 | 20 | function! s:usingPython2() abort abort "{ Inspired on YCM 21 | if has('python3') 22 | return 0 23 | elseif has('python') 24 | return 1 25 | endif 26 | throw 'Unable to identify Python version' 27 | endfunction 28 | "} 29 | 30 | " Inspired on YCM 31 | let s:using_python2 = s:usingPython2() 32 | let s:python_until_eof = s:using_python2 ? 'python << EOF' : 'python3 << EOF' 33 | let s:python_command = s:using_python2 ? 'py ' : 'py3 ' 34 | 35 | function! s:pyEval( eval_string ) abort "{ Inspired on YCM 36 | if s:using_python2 37 | return pyeval( a:eval_string ) 38 | endif 39 | return py3eval( a:eval_string ) 40 | endfunction 41 | "} 42 | function! s:postWarning(msg) abort "{ function! 43 | redraw | echohl WarningMsg | echom a:msg | echohl None" 44 | endfunction "} 45 | function! s:postInfo(msg) abort "{ function! 46 | redraw | echom a:msg | echohl None 47 | endfunction "} 48 | " { s:setupPython() Setup Vim's Python environment to call vim-hdl within Vim 49 | " ============================================================================ 50 | function! s:setupPython() abort 51 | let l:log_level = get(g:, 'vimhdl_log_level', 'INFO') 52 | let l:log_file = get(g:, 'vimhdl_log_file', '') 53 | 54 | exec s:python_until_eof 55 | import sys 56 | if 'vimhdl' not in sys.modules: 57 | import sys, vim 58 | import os.path as p 59 | import logging 60 | _logger = logging.getLogger(__name__) 61 | 62 | # Add a null handler for issue #19 63 | logging.root.addHandler(logging.NullHandler()) 64 | 65 | _logger = logging.getLogger(__name__) 66 | for path in (p.join(vim.eval('s:vimhdl_path'), 'python'),): 67 | if path not in sys.path: 68 | path = p.abspath(path) 69 | if p.exists(path): 70 | sys.path.insert(0, path) 71 | _logger.info("Adding %s", path) 72 | else: 73 | _logger.warning("Path '%s' doesn't exists!", path) 74 | import vimhdl 75 | 76 | # Create the client if it doesn't exists yet 77 | try: 78 | vimhdl_client 79 | _logger.warning("vimhdl client already exists, skiping") 80 | except NameError: 81 | vimhdl_client = vimhdl.VimhdlClient( 82 | log_level=vim.eval('l:log_level'), 83 | log_target=vim.eval('l:log_file'), 84 | ) 85 | EOF 86 | 87 | endfunction 88 | " } 89 | " { s:setupCommands() Setup Vim commands to interact with vim-hdl 90 | " ============================================================================ 91 | function! s:setupCommands() abort 92 | command! VimhdlInfo call s:printInfo() 93 | command! VimhdlViewDependencies call s:viewDependencies() 94 | command! VimhdlRebuildProject call s:pyEval('bool(vimhdl_client.rebuildProject())') 95 | command! VimhdlRestartServer call s:restartServer() 96 | command! VimhdlViewBuildSequence call s:viewBuildSequence() 97 | command! -nargs=* -complete=dir 98 | \ VimhdlCreateProjectFile call s:createProjectFile() 99 | endfunction 100 | " } 101 | " { s:setupHooks() Setup filetype hooks 102 | " ============================================================================ 103 | function! s:setupHooks(...) abort 104 | augroup vimhdl 105 | for l:ext in a:000 106 | for l:event in ['BufWritePost', 'FocusGained', 'CursorMoved', 107 | \'CursorMovedI', 'CursorHold', 'CursorHoldI', 108 | \'InsertEnter'] 109 | execute('autocmd! ' . l:event . ' ' . l:ext . ' ' . 110 | \':' . s:python_command . ' vimhdl_client.requestUiMessages(''' . l:event . ''')') 111 | endfor 112 | endfor 113 | augroup END 114 | endfunction 115 | " } 116 | " { s:setupSyntastic() Setup Syntastic to use vimhdl in the given filetypes 117 | " ============================================================================ 118 | function! s:setupSyntastic(...) abort 119 | for l:filetype in a:000 120 | if !exists('g:syntastic_' . l:filetype . '_checkers') 121 | execute('let g:syntastic_' . l:filetype . '_checkers = ["vimhdl"]') 122 | else 123 | execute('let g:syntastic_' . l:filetype . '_checkers += ["vimhdl"]') 124 | end 125 | endfor 126 | 127 | endfunction 128 | " } 129 | " { s:printInfo() Handle for VimHdlInfo command 130 | " ============================================================================ 131 | function! s:printInfo() abort 132 | echom 'vimhdl debug info' 133 | let l:debug_info = s:pyEval('vimhdl_client.getVimhdlInfo()') 134 | for l:line in split( l:debug_info, '\n' ) 135 | echom l:line 136 | endfor 137 | endfunction 138 | " } 139 | " { s:restartServer() Handle for VimHdlRestartServer command 140 | " ============================================================================ 141 | function! s:restartServer() abort 142 | if !(count(['vhdl', 'verilog', 'systemverilog'], &filetype)) 143 | call s:postWarning("Not a HDL file, can't restart server") 144 | return 145 | endif 146 | echom 'Restarting HDL Checker server' 147 | 148 | let l:log_level = get(g:, 'vimhdl_log_level', 'INFO') 149 | let l:log_file = get(g:, 'vimhdl_log_file', v:null) 150 | 151 | exec s:python_until_eof 152 | _logger.info("Restarting HDL Checker server") 153 | vimhdl_client.shutdown() 154 | del vimhdl_client 155 | vimhdl_client = vimhdl.VimhdlClient( 156 | log_level=vim.eval('l:log_level'), 157 | log_target=vim.eval('l:log_file'), 158 | ) 159 | EOF 160 | unlet! g:vimhdl_server_started 161 | call s:startServer() 162 | 163 | endfunction 164 | " } 165 | " { vimhdl#getMessagesForCurrentBuffer() 166 | " ============================================================================ 167 | function! vimhdl#getMessagesForCurrentBuffer() abort 168 | let l:loclist = [] 169 | exec s:python_until_eof 170 | try: 171 | vimhdl_client.getMessages(vim.current.buffer, 'l:loclist') 172 | except: 173 | _logger.exception("Error getting messages") 174 | EOF 175 | return l:loclist 176 | endfunction 177 | "} 178 | " { s:listDependencies() 179 | " ============================================================================ 180 | function! s:viewDependencies() abort 181 | if !(count(['vhdl', 'verilog', 'systemverilog'], &filetype)) 182 | call s:postWarning("Not a HDL file, can't restart server") 183 | return 184 | endif 185 | let l:dependencies = s:pyEval('vimhdl_client.getDependencies()') 186 | for l:line in split(l:dependencies, "\n") 187 | echom l:line 188 | endfor 189 | endfunction 190 | "} 191 | " { s:listBuildSequence() 192 | " ============================================================================ 193 | function! s:viewBuildSequence() abort 194 | if !(count(['vhdl', 'verilog', 'systemverilog'], &filetype)) 195 | call s:postWarning("Not a HDL file, can't restart server") 196 | return 197 | endif 198 | let l:sequence = s:pyEval('vimhdl_client.getBuildSequence()') 199 | for l:line in split(l:sequence, "\n") 200 | echom l:line 201 | endfor 202 | endfunction 203 | "} 204 | " { s:createProjectFile 205 | " ============================================================================ 206 | function! s:createProjectFile(...) abort 207 | call s:startServer() 208 | 209 | let b:local_arg = a:000 210 | exec s:python_until_eof 211 | vimhdl_client.updateHelperWrapper() 212 | EOF 213 | endfunction 214 | "} 215 | " { s:onVimhdlTempQuit() Handles leaving the temporary config file edit 216 | " ============================================================================ 217 | function! s:onVimhdlTempQuit() 218 | exec s:python_until_eof 219 | vimhdl_client.helper_wrapper.onVimhdlTempQuit() 220 | EOF 221 | endfunction 222 | "} 223 | " { vimhdl#setup() Main vim-hdl setup 224 | " ============================================================================ 225 | function! vimhdl#setup() abort 226 | if !(exists('g:vimhdl_loaded') && g:vimhdl_loaded) 227 | let g:vimhdl_loaded = 1 228 | call s:setupPython() 229 | call s:setupCommands() 230 | call s:setupHooks('*.vhd', '*.vhdl', '*.v', '*.sv') 231 | call s:setupSyntastic('vhdl', 'verilog', 'systemverilog') 232 | endif 233 | 234 | if count(['vhdl', 'verilog', 'systemverilog'], &filetype) 235 | call s:startServer() 236 | endif 237 | endfunction 238 | " } 239 | " { s:startServer() Starts HDL Checker server 240 | " ============================================================================ 241 | function! s:startServer() abort 242 | if (exists('g:vimhdl_server_started') && g:vimhdl_server_started) 243 | return 244 | endif 245 | 246 | let g:vimhdl_server_started = 1 247 | call s:pyEval('bool(vimhdl_client.startServer())') 248 | 249 | endfunction 250 | "} 251 | " vim: set foldmarker={,} foldlevel=0 foldmethod=marker : 252 | -------------------------------------------------------------------------------- /.ci/vroom/test_009_create_project_file_with_clear_setup.vroom: -------------------------------------------------------------------------------- 1 | Macro that checks if vimhdl is enabled 2 | @macro (vimhdl_check) 3 | :SyntasticInfo 4 | ~ Syntastic version:.* (regex) 5 | ~ Info for filetype: vhdl 6 | ~ Global mode: active 7 | ~ Filetype vhdl is active 8 | ~ The current file will be checked automatically 9 | ~ Available checker(s:|:)\s*.*\bvimhdl\b.* (regex) 10 | ~ Currently enabled checker(s:|:)\s*.*\bvimhdl\b.* (regex) 11 | @endmacro 12 | 13 | Macro that writes and waits for the save msg (seems needed in some cases) 14 | @macro (write) 15 | :write 16 | ~ ".*".*\swritten (regex) 17 | @endmacro 18 | 19 | 20 | 21 | 22 | Run the config file creation helper when editing a HDL source 23 | :edit edge_detector.vhd 24 | :VimhdlCreateProjectFile 25 | # This is the resulting project file, please review and save when done. The 26 | # g:vimhdl_conf_file variable has been temporarily changed to point to this 27 | # file should you wish to open HDL files and test the results. When finished, 28 | # close this buffer; you''ll be prompted to either use this file or revert to 29 | # the original one. 30 | # 31 | # ---- Everything up to this line will be automatically removed ---- 32 | # Files found: 5\s* (regex) 33 | # Available builders: ghdl 34 | builder = ghdl 35 | \s* (regex) 36 | vhdl lib ./common_pkg.vhd\s* (regex) 37 | vhdl lib ./edge_detector.vhd\s* (regex) 38 | vhdl lib ./pulse_sync.vhd\s* (regex) 39 | vhdl lib ./sr_delay.vhd\s* (regex) 40 | vhdl lib ./synchronizer.vhd\s* (regex) 41 | \s* (regex) 42 | # vim: filetype=vimhdl 43 | Close the file and open it to check lines were actually removed 44 | :quit 45 | :tabe vimhdl.prj 46 | # Files found: 5 47 | # Available builders: ghdl 48 | builder = ghdl 49 | \s* (regex) 50 | vhdl lib ./common_pkg.vhd\s* (regex) 51 | vhdl lib ./edge_detector.vhd\s* (regex) 52 | vhdl lib ./pulse_sync.vhd\s* (regex) 53 | vhdl lib ./sr_delay.vhd\s* (regex) 54 | vhdl lib ./synchronizer.vhd\s* (regex) 55 | \s* (regex) 56 | # vim: filetype=vimhdl 57 | 58 | 59 | 60 | Run the config file creation helper when editing a HDL source, make changes and 61 | try to quit. Resulting file should not be changed 62 | :edit edge_detector.vhd 63 | :VimhdlCreateProjectFile 64 | # This is the resulting project file, please review and save when done. The 65 | # g:vimhdl_conf_file variable has been temporarily changed to point to this 66 | # file should you wish to open HDL files and test the results. When finished, 67 | # close this buffer; you''ll be prompted to either use this file or revert to 68 | # the original one. 69 | # 70 | # ---- Everything up to this line will be automatically removed ---- 71 | # Files found: 5 72 | # Available builders: ghdl 73 | builder = ghdl 74 | \s* (regex) 75 | vhdl lib ./common_pkg.vhd\s* (regex) 76 | vhdl lib ./edge_detector.vhd\s* (regex) 77 | vhdl lib ./pulse_sync.vhd\s* (regex) 78 | vhdl lib ./sr_delay.vhd\s* (regex) 79 | vhdl lib ./synchronizer.vhd\s* (regex) 80 | \s* (regex) 81 | # vim: filetype=vimhdl 82 | > 3dd 83 | @messages (RELAXED) 84 | :quit 85 | ~ E37: No write since last change (add ! to override) 86 | @messages 87 | # close this buffer; you''ll be prompted to either use this file or revert to 88 | # the original one. 89 | # 90 | # ---- Everything up to this line will be automatically removed ---- 91 | # Files found: 5 92 | # Available builders: ghdl 93 | builder = ghdl 94 | \s* (regex) 95 | vhdl lib ./common_pkg.vhd\s* (regex) 96 | vhdl lib ./edge_detector.vhd\s* (regex) 97 | vhdl lib ./pulse_sync.vhd\s* (regex) 98 | vhdl lib ./sr_delay.vhd\s* (regex) 99 | vhdl lib ./synchronizer.vhd\s* (regex) 100 | \s* (regex) 101 | # vim: filetype=vimhdl 102 | @do (write) 103 | # close this buffer; you''ll be prompted to either use this file or revert to 104 | # the original one. 105 | # 106 | # ---- Everything up to this line will be automatically removed ---- 107 | # Files found: 5 108 | # Available builders: ghdl 109 | builder = ghdl 110 | \s* (regex) 111 | vhdl lib ./common_pkg.vhd\s* (regex) 112 | vhdl lib ./edge_detector.vhd\s* (regex) 113 | vhdl lib ./pulse_sync.vhd\s* (regex) 114 | vhdl lib ./sr_delay.vhd\s* (regex) 115 | vhdl lib ./synchronizer.vhd\s* (regex) 116 | \s* (regex) 117 | # vim: filetype=vimhdl 118 | :quit 119 | :tabe vimhdl.prj 120 | # Files found: 5 121 | # Available builders: ghdl 122 | builder = ghdl 123 | \s* (regex) 124 | vhdl lib ./common_pkg.vhd\s* (regex) 125 | vhdl lib ./edge_detector.vhd\s* (regex) 126 | vhdl lib ./pulse_sync.vhd\s* (regex) 127 | vhdl lib ./sr_delay.vhd\s* (regex) 128 | vhdl lib ./synchronizer.vhd\s* (regex) 129 | \s* (regex) 130 | # vim: filetype=vimhdl 131 | 132 | 133 | 134 | Run the config file creation helper when editing a HDL source so that the 135 | generated project file opens up for editing, then create a new file on a 136 | different tab and run the creation helper again. The old contents should be 137 | replaced with the newly generated config file, but the old contents should be 138 | accessible via undo 139 | :edit edge_detector.vhd 140 | :VimhdlCreateProjectFile 141 | # This is the resulting project file, please review and save when done. The 142 | # g:vimhdl_conf_file variable has been temporarily changed to point to this 143 | # file should you wish to open HDL files and test the results. When finished, 144 | # close this buffer; you''ll be prompted to either use this file or revert to 145 | # the original one. 146 | # 147 | # ---- Everything up to this line will be automatically removed ---- 148 | # Files found: 5 149 | # Available builders: ghdl 150 | builder = ghdl 151 | \s* (regex) 152 | vhdl lib ./common_pkg.vhd\s* (regex) 153 | vhdl lib ./edge_detector.vhd\s* (regex) 154 | vhdl lib ./pulse_sync.vhd\s* (regex) 155 | vhdl lib ./sr_delay.vhd\s* (regex) 156 | vhdl lib ./synchronizer.vhd\s* (regex) 157 | \s* (regex) 158 | # vim: filetype=vimhdl 159 | :tabedit oh_i_need_this_as_well.vhd 160 | > i-- Never mind, will do this later 161 | @do (write) 162 | :quit 163 | :VimhdlCreateProjectFile 164 | # This is the resulting project file, please review and save when done. The 165 | # g:vimhdl_conf_file variable has been temporarily changed to point to this 166 | # file should you wish to open HDL files and test the results. When finished, 167 | # close this buffer; you''ll be prompted to either use this file or revert to 168 | # the original one. 169 | # 170 | # ---- Everything up to this line will be automatically removed ---- 171 | # Files found: 6 172 | # Available builders: ghdl 173 | builder = ghdl 174 | \s* (regex) 175 | vhdl lib ./common_pkg.vhd\s* (regex) 176 | vhdl lib ./edge_detector.vhd\s* (regex) 177 | vhdl lib ./oh_i_need_this_as_well.vhd\s* (regex) 178 | vhdl lib ./pulse_sync.vhd\s* (regex) 179 | vhdl lib ./sr_delay.vhd\s* (regex) 180 | vhdl lib ./synchronizer.vhd\s* (regex) 181 | \s* (regex) 182 | # vim: filetype=vimhdl 183 | :quit 184 | 185 | 186 | 187 | Run the config file creation helper from within a run, when for example 188 | updating it 189 | :edit some_new_file.vhd 190 | @do (write) 191 | :VimhdlCreateProjectFile 192 | # This is the resulting project file, please review and save when done. The 193 | # g:vimhdl_conf_file variable has been temporarily changed to point to this 194 | # file should you wish to open HDL files and test the results. When finished, 195 | # close this buffer; you''ll be prompted to either use this file or revert to 196 | # the original one. 197 | # 198 | # ---- Everything up to this line will be automatically removed ---- 199 | # Files found: 7 200 | # Available builders: ghdl 201 | builder = ghdl 202 | \s* (regex) 203 | vhdl lib ./common_pkg.vhd\s* (regex) 204 | vhdl lib ./edge_detector.vhd\s* (regex) 205 | vhdl lib ./oh_i_need_this_as_well.vhd\s* (regex) 206 | vhdl lib ./pulse_sync.vhd\s* (regex) 207 | vhdl lib ./some_new_file.vhd\s* (regex) 208 | vhdl lib ./sr_delay.vhd\s* (regex) 209 | vhdl lib ./synchronizer.vhd\s* (regex) 210 | \s* (regex) 211 | # vim: filetype=vimhdl 212 | Make sure that running twice won't mess up and will give the same results 213 | :VimhdlCreateProjectFile 214 | # This is the resulting project file, please review and save when done. The 215 | # g:vimhdl_conf_file variable has been temporarily changed to point to this 216 | # file should you wish to open HDL files and test the results. When finished, 217 | # close this buffer; you''ll be prompted to either use this file or revert to 218 | # the original one. 219 | # 220 | # ---- Everything up to this line will be automatically removed ---- 221 | # Files found: 7 222 | # Available builders: ghdl 223 | builder = ghdl 224 | \s* (regex) 225 | vhdl lib ./common_pkg.vhd\s* (regex) 226 | vhdl lib ./edge_detector.vhd\s* (regex) 227 | vhdl lib ./oh_i_need_this_as_well.vhd\s* (regex) 228 | vhdl lib ./pulse_sync.vhd\s* (regex) 229 | vhdl lib ./some_new_file.vhd\s* (regex) 230 | vhdl lib ./sr_delay.vhd\s* (regex) 231 | vhdl lib ./synchronizer.vhd\s* (regex) 232 | \s* (regex) 233 | # vim: filetype=vimhdl 234 | Again, close the file and open it to check lines were actually removed 235 | :quit 236 | :tabe vimhdl.prj 237 | # Files found: 7 238 | # Available builders: ghdl 239 | builder = ghdl 240 | \s* (regex) 241 | vhdl lib ./common_pkg.vhd\s* (regex) 242 | vhdl lib ./edge_detector.vhd\s* (regex) 243 | vhdl lib ./oh_i_need_this_as_well.vhd\s* (regex) 244 | vhdl lib ./pulse_sync.vhd\s* (regex) 245 | vhdl lib ./some_new_file.vhd\s* (regex) 246 | vhdl lib ./sr_delay.vhd\s* (regex) 247 | vhdl lib ./synchronizer.vhd\s* (regex) 248 | \s* (regex) 249 | # vim: filetype=vimhdl 250 | -------------------------------------------------------------------------------- /.ci/vimhdl_tests/test_vim_helpers.py: -------------------------------------------------------------------------------- 1 | # This file is part of vim-hdl. 2 | # 3 | # vim-hdl is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation, either version 3 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # vim-hdl is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with vim-hdl. If not, see . 15 | 16 | # pylint: disable=function-redefined, missing-docstring, protected-access 17 | 18 | from __future__ import print_function 19 | 20 | import sys 21 | import os 22 | import os.path as p 23 | import logging 24 | from nose2.tools import such 25 | 26 | try: # Python 3.x 27 | import unittest.mock as mock # pylint: disable=import-error, no-name-in-module 28 | except ImportError: # Python 2.x 29 | import mock 30 | 31 | _CI = os.environ.get("CI", None) is not None 32 | 33 | _logger = logging.getLogger(__name__) 34 | 35 | def _setupPaths(): 36 | base_path = p.abspath(p.join(p.dirname(__file__), '..', '..')) 37 | # Add vim-hdl own Python code and hdlcc also (needed by vimhdl) 38 | for path in (p.join(base_path, 'python'),): 39 | assert p.exists(path), "Path '%s' doesn't exists!" % path 40 | sys.path.insert(0, path) 41 | 42 | _setupPaths() 43 | 44 | # pylint: disable=import-error,wrong-import-position 45 | from vimhdl_tests.vim_mock import mockVim 46 | mockVim() 47 | import vim 48 | import vimhdl # pylint: disable=unused-import 49 | import vimhdl.vim_helpers as vim_helpers 50 | # pylint: enable=import-error,wrong-import-position 51 | 52 | with such.A('vim_helpers module') as it: 53 | @it.should("return all buffer variables from the current buffer if " 54 | "neither buffer or variable are defined") 55 | def test(): 56 | it.assertEquals( 57 | vim_helpers._getBufferVars(), 58 | {'current_buffer_var_0' : 'current_buffer_value_0', 59 | 'current_buffer_var_1' : 'current_buffer_value_1'}) 60 | 61 | @it.should("return the given buffer variable of the current buffer if " 62 | "only the first one is given") 63 | def test(): 64 | it.assertEquals(vim_helpers._getBufferVars(var='current_buffer_var_0'), 65 | 'current_buffer_value_0') 66 | it.assertEquals(vim_helpers._getBufferVars(var='current_buffer_var_1'), 67 | 'current_buffer_value_1') 68 | 69 | @it.should("return all variables of other buffers") 70 | def test(): 71 | it.assertEquals( 72 | vim_helpers._getBufferVars(vim.buffers[0]), 73 | {'buffer_0_var_0' : 'buffer_0_var_value_0', 74 | 'buffer_0_var_1' : 'buffer_0_var_value_1',} 75 | ) 76 | it.assertEquals( 77 | vim_helpers._getBufferVars(vim.buffers[1]), 78 | {'buffer_1_var_0' : 'buffer_1_var_value_0', 79 | 'buffer_1_var_1' : 'buffer_1_var_value_1',} 80 | ) 81 | 82 | @it.should("return a specific variable of a specific buffer") 83 | def test(): 84 | it.assertEquals( 85 | vim_helpers._getBufferVars(vim.buffers[0], 'buffer_0_var_0'), 86 | 'buffer_0_var_value_0',) 87 | 88 | @it.should("post vim info correctly formatted") 89 | def test(): 90 | vim_helpers.postVimInfo("Some info") 91 | vim.command.assert_called_with( 92 | "redraw | echom 'Some info' | echohl None") 93 | 94 | @it.should("post vim warning correctly formatted") 95 | def test(): 96 | vim_helpers.postVimWarning("Some warning") 97 | vim.command.assert_called_with( 98 | "redraw | echohl WarningMsg | echom 'Some warning' | echohl None") 99 | 100 | @it.should("post vim error correctly formatted") 101 | def test(): 102 | vim_helpers.postVimError("Some error") 103 | vim.command.assert_called_with( 104 | "echohl ErrorMsg | echom 'Some error' | echohl None") 105 | 106 | with it.having("both global and local project files configured"): 107 | def deleteProjectFiles(): 108 | for prj_filename in (it._global_prj_filename, 109 | it._local_prj_filename): 110 | if p.exists(prj_filename): 111 | os.remove(prj_filename) 112 | 113 | @it.has_setup 114 | def setup(): 115 | it._global_prj_filename = p.abspath(p.join( 116 | os.curdir, 'global_project.prj')) 117 | 118 | it._local_prj_filename = p.abspath(p.join( 119 | os.curdir, 'local_project.prj')) 120 | 121 | it._global_patch = mock.patch( 122 | 'vim.vars', {'vimhdl_conf_file' : it._global_prj_filename}) 123 | it._local_patch = mock.patch( 124 | 'vim.current.buffer.vars', {'vimhdl_conf_file' : it._local_prj_filename}) 125 | 126 | it._global_patch.start() 127 | it._local_patch.start() 128 | 129 | @it.has_teardown 130 | def teardown(): 131 | deleteProjectFiles() 132 | it._global_patch.stop() 133 | it._local_patch.stop() 134 | 135 | @it.should("give precedence to local project file when both are " 136 | "readable") 137 | def test(): 138 | for prj_filename in (it._global_prj_filename, 139 | it._local_prj_filename): 140 | assert not p.exists(prj_filename) 141 | open(prj_filename, 'w').close() 142 | 143 | it.assertEqual(it._local_prj_filename, 144 | vim_helpers.getProjectFile()) 145 | 146 | deleteProjectFiles() 147 | 148 | @it.should("use the local project file even if the global is not " 149 | "readable") 150 | def test(): 151 | for prj_filename in (it._local_prj_filename, ): 152 | assert not p.exists(prj_filename) 153 | open(prj_filename, 'w').close() 154 | 155 | it.assertEqual(it._local_prj_filename, 156 | vim_helpers.getProjectFile()) 157 | 158 | deleteProjectFiles() 159 | 160 | @it.should("fallback to the global project file when the local " 161 | "project file is not readable") 162 | def test(): 163 | for prj_filename in (it._global_prj_filename, ): 164 | assert not p.exists(prj_filename) 165 | open(prj_filename, 'w').close() 166 | 167 | it.assertEqual(it._global_prj_filename, 168 | vim_helpers.getProjectFile()) 169 | 170 | deleteProjectFiles() 171 | 172 | with it.having("only a global project file configured"): 173 | def deleteProjectFiles(): 174 | for prj_filename in (it._global_prj_filename, 175 | it._local_prj_filename): 176 | if p.exists(prj_filename): 177 | os.remove(prj_filename) 178 | 179 | @it.has_setup 180 | def setup(): 181 | it._global_prj_filename = p.abspath(p.join( 182 | os.curdir, 'global_project.prj')) 183 | 184 | it._local_prj_filename = p.abspath(p.join( 185 | os.curdir, 'local_project.prj')) 186 | 187 | it._global_patch = mock.patch( 188 | 'vim.vars', {'vimhdl_conf_file' : it._global_prj_filename}) 189 | 190 | it._global_patch.start() 191 | 192 | @it.has_teardown 193 | def teardown(): 194 | deleteProjectFiles() 195 | it._global_patch.stop() 196 | 197 | @it.should("return the global project file when it's readable") 198 | def test(): 199 | for prj_filename in (it._global_prj_filename, ): 200 | assert not p.exists(prj_filename) 201 | open(prj_filename, 'w').close() 202 | 203 | it.assertEqual(it._global_prj_filename, 204 | vim_helpers.getProjectFile()) 205 | 206 | deleteProjectFiles() 207 | 208 | @it.should("return None if the global project file is not readable") 209 | def test(): 210 | it.assertIsNone(vim_helpers.getProjectFile()) 211 | deleteProjectFiles() 212 | 213 | with it.having("only a local project file configured"): 214 | def deleteProjectFiles(): 215 | for prj_filename in (it._global_prj_filename, 216 | it._local_prj_filename): 217 | if p.exists(prj_filename): 218 | os.remove(prj_filename) 219 | 220 | @it.has_setup 221 | def setup(): 222 | it._global_prj_filename = p.abspath(p.join( 223 | os.curdir, 'global_project.prj')) 224 | 225 | it._local_prj_filename = p.abspath(p.join( 226 | os.curdir, 'local_project.prj')) 227 | 228 | it._local_patch = mock.patch( 229 | 'vim.current.buffer.vars', {'vimhdl_conf_file' : it._local_prj_filename}) 230 | 231 | it._local_patch.start() 232 | 233 | @it.has_teardown 234 | def teardown(): 235 | deleteProjectFiles() 236 | it._local_patch.stop() 237 | 238 | @it.should("give precedence to local project file when both are " 239 | "readable") 240 | def test(): 241 | for prj_filename in (it._global_prj_filename, 242 | it._local_prj_filename): 243 | assert not p.exists(prj_filename) 244 | open(prj_filename, 'w').close() 245 | 246 | it.assertEqual(it._local_prj_filename, 247 | vim_helpers.getProjectFile()) 248 | 249 | deleteProjectFiles() 250 | 251 | @it.should("use the local project file even if the global is not " 252 | "readable") 253 | def test(): 254 | for prj_filename in (it._local_prj_filename, ): 255 | assert not p.exists(prj_filename) 256 | open(prj_filename, 'w').close() 257 | 258 | it.assertEqual(it._local_prj_filename, 259 | vim_helpers.getProjectFile()) 260 | 261 | deleteProjectFiles() 262 | 263 | @it.should("return None if the local project file is not readable") 264 | def test(): 265 | deleteProjectFiles() 266 | it.assertIsNone(vim_helpers.getProjectFile()) 267 | deleteProjectFiles() 268 | 269 | it.createTests(globals()) 270 | -------------------------------------------------------------------------------- /.ci/vimhdl_tests/test_runner.py: -------------------------------------------------------------------------------- 1 | # This file is part of vim-hdl. 2 | # 3 | # vim-hdl is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation, either version 3 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # vim-hdl is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with vim-hdl. If not, see . 15 | 16 | # pylint: disable=function-redefined, missing-docstring, protected-access 17 | 18 | import glob 19 | import logging 20 | import os 21 | import os.path as p 22 | import re 23 | import shutil 24 | import subprocess as subp 25 | import tempfile 26 | from contextlib import contextmanager 27 | 28 | import mock 29 | from nose2.tools import such 30 | from nose2.tools.params import params 31 | 32 | _logger = logging.getLogger(__name__) 33 | 34 | PATH_TO_TESTS = p.abspath(p.join(".ci", "vroom")) 35 | HDLCC_CI = p.abspath(p.join("..", "hdlcc_ci")) 36 | ON_CI = os.environ.get("CI", None) is not None 37 | NEOVIM_TARGET = os.environ.get("CI_TARGET", "vim") == "neovim" 38 | VROOM_EXTRA_ARGS = os.environ.get("VROOM_EXTRA_ARGS", None) 39 | 40 | 41 | @contextmanager 42 | def pushd(path): 43 | prev = os.getcwd() 44 | _logger.debug("%s => %s", repr(prev), repr(path)) 45 | os.chdir(path) 46 | try: 47 | yield 48 | finally: 49 | _logger.debug("%s => %s", repr(os.getcwd()), repr(prev)) 50 | os.chdir(prev) 51 | 52 | 53 | def runShell(cmd, shell=False, cwd=None): 54 | _logger.info("$ %s", " ".join([str(x) for x in cmd])) 55 | for line in subp.check_output(cmd, shell=shell, cwd=cwd).splitlines(): 56 | _logger.info("> %s", line.decode()) 57 | 58 | 59 | with such.A("vim-hdl test") as it: 60 | 61 | @contextmanager 62 | def mockMsim(): 63 | """ 64 | Creates a temporary path and vcom/vlog empty executables just so that hdlcc 65 | reports them as existing 66 | """ 67 | with tempfile.TemporaryDirectory(prefix="vimhdl_test_") as temp_path: 68 | for bin_name in "vcom", "vlog": 69 | bin_path = p.join(temp_path, bin_name) 70 | open(bin_path, "w").write("#/usr/bin/env sh") 71 | os.chmod(bin_path, int("755", 8)) 72 | 73 | # Add the builder path to the environment so we can call it 74 | new_path = os.pathsep.join([temp_path + "/", os.environ["PATH"]]) 75 | with mock.patch.dict("os.environ", {"PATH": new_path}) as vsim_mock: 76 | yield vsim_mock 77 | 78 | def runVroom(test_name): 79 | cmd = ["vroom", "-u", p.expanduser("~/.vimrc" if ON_CI else "~/dot_vim/vimrc")] 80 | 81 | output = p.join("/tmp", "vroom_%s.log" % p.basename(test_name)) 82 | 83 | cmd += ["--out", output] 84 | 85 | if ON_CI: 86 | cmd += ["--nocolor"] 87 | 88 | # This has been weird at a times, adding a bit of extra delay between 89 | # commands seems to help 90 | cmd += ["-d", "0.5" if ON_CI else "0.2"] 91 | 92 | if NEOVIM_TARGET: 93 | cmd += ["--neovim"] 94 | if VROOM_EXTRA_ARGS is not None: 95 | cmd += re.split(r"\s+", VROOM_EXTRA_ARGS) 96 | 97 | cmd += [test_name] 98 | 99 | _logger.info("$ %s", " ".join(cmd)) 100 | if os.system(" ".join(cmd)) != 0: 101 | _logger.error("Test failed: %s", test_name) 102 | for line in open(output).readlines(): 103 | line = line[:-1] 104 | if line: 105 | _logger.error(">> %s", line) 106 | it.fail("Test failed: %s" % test_name) 107 | 108 | def dbgFindCoverage(): 109 | cnt = 0 110 | for report in glob.glob(".coverage.*"): 111 | cnt += 1 112 | _logger.warning("Coverage report: %s", p.abspath(report)) 113 | 114 | it.assertEqual(cnt, 0, "Found stuff!!!") 115 | 116 | def gitClean(path): 117 | _logger.debug("Cleaning up non-git files") 118 | runShell(["git", "clean", "-fd"], cwd=path or ".") 119 | 120 | def cleanHdlLib(): 121 | _logger.debug("Resetting hdl_lib") 122 | 123 | runShell(["git", "reset", "HEAD", "--hard"], cwd=p.join(HDLCC_CI, "hdl_lib")) 124 | 125 | gitClean(p.join(HDLCC_CI, "hdl_lib")) 126 | 127 | runShell(["git", "status", "--porcelain"], cwd=p.join(HDLCC_CI, "hdl_lib")) 128 | 129 | def pipInstallHdlcc(): 130 | cmd = ["pip", "install", "hdl_checker", "-U"] 131 | _logger.debug("Installing HDLCC via pip with command:") 132 | runShell(cmd) 133 | 134 | _logger.debug("We should be able to call it now") 135 | runShell(["hdl_checker", "-V"]) 136 | 137 | def pipUninstallHdlcc(): 138 | runShell(["pip", "uninstall", "hdl_checker", "-y"]) 139 | 140 | @it.has_setup 141 | def setup(): 142 | pipInstallHdlcc() 143 | 144 | @it.has_teardown 145 | def teardown(): 146 | pipUninstallHdlcc() 147 | 148 | for vroom_test in glob.glob(p.join(PATH_TO_TESTS, "*.vroom")): 149 | vroom_post = p.join(p.dirname(vroom_test), "alt_" + p.basename(vroom_test)) 150 | if p.exists(vroom_post): 151 | os.remove(vroom_post) 152 | 153 | if p.exists("source.vhd"): 154 | os.remove("source.vhd") 155 | 156 | @it.has_test_setup 157 | def testSetup(): 158 | cleanHdlLib() 159 | 160 | @it.has_test_teardown 161 | def testTeardown(): 162 | cleanHdlLib() 163 | 164 | @it.should("handle session with multiple files to edit") 165 | def test(): 166 | vroom_test = p.join(PATH_TO_TESTS, 167 | "test_001_editing_multiple_files.vroom") 168 | runVroom(vroom_test) 169 | 170 | @it.should("run only static checks if no project was configured") 171 | def test(): 172 | vroom_test = p.join(PATH_TO_TESTS, 173 | 'test_002_no_project_configured.vroom') 174 | runVroom(vroom_test) 175 | 176 | @it.should("warn when unable to create the configured builder") 177 | def test(): 178 | gitClean(p.join(HDLCC_CI, "hdl_lib")) 179 | vroom_test = p.join(PATH_TO_TESTS, 180 | 'test_003_with_project_without_builder.vroom') 181 | runVroom(vroom_test) 182 | 183 | @it.should("not result on E926 when jumping from quickfix") 184 | def test(): 185 | if p.exists("source.vhd"): 186 | os.remove("source.vhd") 187 | 188 | vroom_test = p.join(PATH_TO_TESTS, "test_005_issue_15_quickfix_jump.vroom") 189 | runVroom(vroom_test) 190 | 191 | @it.should("print vimhdl diagnose info") 192 | def test(): 193 | import sys 194 | 195 | sys.path.insert(0, "python") 196 | sys.path.insert(0, p.join("dependencies", "hdlcc")) 197 | import vimhdl # pylint: disable=import-error 198 | import hdl_checker # pylint: disable=import-error 199 | 200 | vroom_test = p.join(PATH_TO_TESTS, "test_006_get_vim_info.vroom") 201 | lines = open(vroom_test, "r").read() 202 | 203 | lines = lines.replace("__vimhdl__version__", vimhdl.__version__) 204 | lines = lines.replace("__hdl_checker__version__", hdl_checker.__version__) 205 | sys.path.remove("python") 206 | sys.path.remove(p.join("dependencies", "hdlcc")) 207 | 208 | del sys.modules["vimhdl"] 209 | del sys.modules["hdl_checker"] 210 | 211 | vroom_post = vroom_test.replace("test_006", "alt_test_006") 212 | open(vroom_post, "w").write(lines) 213 | 214 | runVroom(vroom_post) 215 | 216 | @it.should("only start hdlcc server when opening a hdl file") 217 | @params("vhdl", "verilog", "systemverilog") 218 | def test(case, filetype): # pylint: disable=unused-argument 219 | vroom_test = p.join( 220 | PATH_TO_TESTS, 221 | "test_007_server_should_start_only_when_opening_hdl_file.vroom", 222 | ) 223 | 224 | import sys 225 | 226 | sys.path.insert(0, "python") 227 | sys.path.insert(0, p.join("dependencies", "hdlcc")) 228 | import vimhdl # pylint: disable=import-error 229 | import hdl_checker # pylint: disable=import-error 230 | 231 | lines = open(vroom_test, "r").read() 232 | 233 | lines = lines.replace("__vimhdl__version__", vimhdl.__version__) 234 | lines = lines.replace("__hdl_checker__version__", hdl_checker.__version__) 235 | 236 | lines = lines.replace("__filetype__", filetype) 237 | 238 | sys.path.remove("python") 239 | sys.path.remove(p.join("dependencies", "hdlcc")) 240 | 241 | del sys.modules["vimhdl"] 242 | del sys.modules["hdl_checker"] 243 | 244 | vroom_post = vroom_test.replace("test_007", "alt_test_007") 245 | open(vroom_post, "w").write(lines) 246 | 247 | runVroom(vroom_post) 248 | 249 | @it.should("get dependencies and build sequence") 250 | def test(): 251 | vroom_test = p.join( 252 | PATH_TO_TESTS, "test_008_get_dependencies_and_build_sequence.vroom" 253 | ) 254 | runVroom(vroom_test) 255 | 256 | # @it.should("run config helper without g:vimhdl_conf_file set") 257 | # def test(): 258 | # vroom_test = p.join( 259 | # PATH_TO_TESTS, "test_009_create_project_file_with_clear_setup.vroom" 260 | # ) 261 | 262 | # # Remove all project files before running 263 | # for path in glob.glob(p.join(HDLCC_CI, "*.prj")): 264 | # _logger.info("Removing '%s'", path) 265 | # os.remove(path) 266 | 267 | # target_path = p.join(HDLCC_CI, "hdl_lib", "common_lib") 268 | 269 | # with pushd(target_path): 270 | # runVroom(vroom_test) 271 | # dbgFindCoverage() 272 | 273 | # @it.should("find include paths when running the config helper") 274 | # def test(): 275 | # vroom_test = p.abspath( 276 | # p.join( 277 | # PATH_TO_TESTS, "test_010_create_project_file_with_conf_file_set.vroom" 278 | # ) 279 | # ) 280 | 281 | # # Remove all project files before running 282 | # for path in glob.glob(p.join(HDLCC_CI, "*.prj")): 283 | # _logger.info("Removing '%s'", path) 284 | # os.remove(path) 285 | 286 | # # Needs to agree with vroom test file 287 | # dummy_test_path = p.expanduser("~/dummy_test_path") 288 | 289 | # # Create a dummy arrangement of sources 290 | # if p.exists(dummy_test_path): 291 | # shutil.rmtree(dummy_test_path) 292 | 293 | # os.mkdir(dummy_test_path) 294 | 295 | # with pushd(dummy_test_path): 296 | # os.mkdir("path_a") 297 | # os.mkdir("path_b") 298 | # os.mkdir("v_includes") 299 | # os.mkdir("sv_includes") 300 | # # Create empty sources 301 | # for path in ( 302 | # p.join("path_a", "some_source.vhd"), 303 | # p.join("path_a", "header_out_of_place.vh"), 304 | # p.join("path_a", "source_tb.vhd"), 305 | # p.join("path_b", "some_source.vhd"), 306 | # p.join("path_b", "a_verilog_source.v"), 307 | # p.join("path_b", "a_systemverilog_source.sv"), 308 | # # Create headers for both extensions 309 | # p.join("v_includes", "verilog_header.vh"), 310 | # p.join("sv_includes", "systemverilog_header.svh"), 311 | # # Make the tree 'dirty' with other source types 312 | # p.join("path_a", "not_hdl_source.log"), 313 | # p.join("path_a", "not_hdl_source.py"), 314 | # ): 315 | # _logger.info("Writing to %s", path) 316 | # open(path, "w").write("") 317 | 318 | # # This shouldn't run under pushd context otherwise we won't get the 319 | # # coverage reports 320 | # with mockMsim(): 321 | # runVroom(vroom_test) 322 | 323 | # @it.should("find files in specified paths") 324 | # def test(): 325 | # vroom_test = p.abspath( 326 | # p.join(PATH_TO_TESTS, "test_011_create_project_file_with_args.vroom") 327 | # ) 328 | 329 | # with pushd(p.join(HDLCC_CI, "hdl_lib")): 330 | # runVroom(vroom_test) 331 | # dbgFindCoverage() 332 | 333 | 334 | it.createTests(globals()) 335 | -------------------------------------------------------------------------------- /doc/vimhdl.txt: -------------------------------------------------------------------------------- 1 | *vimhdl* Vim plugin to aid VHDL development 2 | 3 | .-. .-..-. .-. .-..----. .-. ~ 4 | | | / / '-'.-. .-.| | | || .. \| | ~ 5 | | |/ / .-.| V || '-' || | | || | ~ 6 | | / | || |V| || .-. || '' /| '--. ~ 7 | '--' '-''-' '-''-' '-''----' '----' ~ 8 | Vim plugin to aid VHDL development ~ 9 | 10 | ============================================================================== 11 | Contents ~ 12 | 13 | 1. Intro.............................................|vimhdl-intro| 14 | 1.1. vimhdl version v0.3 and newer................|vimhdl-version-0.3| 15 | 1.2. HDL Checker..................................|vimhdl-hdl-checker| 16 | 2. User guide........................................|vimhdl-user-guide| 17 | 2.1. Quickstart...................................|vimhdl-quickstart| 18 | 2.2. JSON-style config file.......................|vimhdl-json-config-file| 19 | 2.3. PRJ-style config file........................|vimhdl-prj-config-file| 20 | 2.4. Style check..................................|vimhdl-style-check| 21 | 3. Vim commands......................................|vimhdl-commands| 22 | 4. Options...........................................|vimhdl-options| 23 | 4.1. Configuration file...........................|vimhdl-config-file| 24 | 4.2. Logging level................................|vimhdl-log-level| 25 | 4.3. Log file.....................................|vimhdl-log-file| 26 | 27 | ============================================================================== 28 | 1. Intro *vimhdl-intro* 29 | 30 | vimhdl is a plugin that implements an HTTP client that talks to |hdl-checker| so its 31 | output is shown either on Vim's quickfix list via |Syntastic| or Vim's messages. 32 | 33 | ------------------------------------------------------------------------------ 34 | 1 1 vimhdl version v0 3 and newer *vimhdl-version-0.3* 35 | 36 | Starting from vimhdl 0.3, dependencies are not bundled anymore, which includes 37 | |hdl-checker|. To make sure you have the dependencies needed, run from a 38 | terminal: > 39 | 40 | pip install -r /requirements.txt 41 | 42 | If vimhdl was installed using `vim-plug` defaults, that would be > 43 | 44 | pip install -r $HOME/.vim/plugged/vim-hdl/requirements.txt 45 | 46 | ------------------------------------------------------------------------------ 47 | 1.2. HDL Checker *hdlcc* *vimhdl-hdlcc* *hdl-checker* *vimhdl-hdl-checker* 48 | 49 | HDL Checker is a language server that wraps VHDL/Verilg/SystemVerilog tools 50 | that aims to reduce the boilerplate code needed to set things up. It supports 51 | Language Server Protocol or a custom HTTP interface. HDL Checker automates 52 | tasks when possible. Currently, this means 53 | 54 | - Inferring library VHDL files likely belong to 55 | - Taking dependencies into account when building so you don't need to provide 56 | a source list ordered by hand. 57 | - Finding and rebuilding sources and design units that the compiler says are 58 | out of date (typically rebuilding sources that depend on package that has 59 | been changed) 60 | - Easily switch between different compilers 61 | 62 | 63 | ============================================================================== 64 | 2. User guide *vimhdl-user-guide* 65 | 66 | ------------------------------------------------------------------------------ 67 | 2.1. Quickstart *vimhdl-quickstart* 68 | *vimhdl-compilers-options* 69 | 70 | Vimhdl can be used with or without a config file. The full project file 71 | documentation can be found at https://github.com/suoto/hdl_checker/wiki, which 72 | is reproduced below. 73 | 74 | HDL Checker can work with or without a configuration file. Both LSP and HTTP 75 | mode function very similarly, except LSP mode will look for sources under a 76 | workspace's root URI if no configuration file is found (therefore, as of now, 77 | using LSP is preferred). More info on LSP can be found on the LSP Spec: 78 | https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/ 79 | 80 | Because automatic library discovery might be incorrect, one can use a JSON 81 | configuration file to list files or to hint those which libraries were guessed 82 | incorrectly. 83 | 84 | Please note that if a configuration file is specified, no search is done, so 85 | even though the file can specify paths with or without a library, it should 86 | specify *all* paths. 87 | 88 | Also, please note that the legacy project file format does not support listing 89 | files without libraries. 90 | 91 | If a configuration file is specified, HDL Checker will try to decode it as 92 | JSON first and, if that fails, will parse as `prj`. 93 | 94 | When using the legacy format, one can use `set filetype=vimhdl` to enable 95 | syntax highlighting. 96 | 97 | ------------------------------------------------------------------------------ 98 | 2.2. JSON-style config file *vimhdl-json-config-file* 99 | 100 | JSON format is as show below: 101 | 102 | **Note:** Notation below uses JSON5 for the comments for readability only, 103 | configuration files follow "regular" JSON > 104 | 105 | { 106 | /* 107 | * List of source files (optional, defaults to []). If specificed, must be 108 | * a list of either strings or source spec tuples, where source spec tuple 109 | * is a tuple in the form [string, dict[string, string]] (see below for 110 | * details). 111 | */ 112 | "sources": [ 113 | 114 | /* 115 | * Sources can be defined solely by their paths. Absolute paths are 116 | * unchanged, relative paths are made absolute by using the path to the 117 | * configuration file. Sources imported from an included file will follow 118 | * the same principle but using the path to the included path. 119 | */ 120 | "/path/to/file_0", 121 | 122 | /* 123 | * Tuples can be used to add more info on the path. First element of the 124 | * tuple must the a string with the path, second element is optional 125 | * (defaults to an empty dictionary). Dictionary can specify the path's 126 | * library ({"library": "name_of_the_library"}, special compile 127 | * flags({"flags": ["flag_1", "flag_2"]}) or both. 128 | */ 129 | [ "/path/with/library/and/flags", { "library": "foo", "flags": ["-2008"] } ], 130 | [ "/path/with/library", { "library": "foo" } ], 131 | [ "/path/with/flags", { "flags": ["-2008"] } ] 132 | ], 133 | 134 | /* 135 | * Extra config files to be added to the project (optional, defaults to []) 136 | * If specificed, must be a list of stings. 137 | */ 138 | "include": [ "/path/to/another/json/file" ], 139 | 140 | /* 141 | * Language / scope specific info (optional, defaults to {}). Setting 142 | * these, event if empty, will override values defined per compiler. Flags 143 | * should be specified as a list of strings. 144 | * 145 | * The scope keys are: 146 | * - "single": flags used to build the file being checked 147 | * - "dependencies": flags used to build the dependencies of the file 148 | * being checked 149 | * - "global": flags used on both target and its dependencies 150 | * 151 | * For example, suppose the compilation sequence for a given source S is A, 152 | * B, C and then S. The tool will compile A, B and C using global and 153 | * dependencies flags, while S will be compiled using global and single 154 | * flags. 155 | */ 156 | "vhdl": { 157 | "flags": { 158 | "single": ["flag_1", "flag_2"], 159 | "dependencies": [], 160 | "global": [] 161 | } 162 | }, 163 | "verilog": { 164 | "flags": { 165 | "single": [], 166 | "dependencies": [], 167 | "global": [] 168 | } 169 | }, 170 | "systemverilog": { 171 | "flags": { 172 | "single": [], 173 | "dependencies": [], 174 | "global": [] 175 | } 176 | } 177 | } 178 | < 179 | ------------------------------------------------------------------------------ 180 | 2.3. PRJ-style config file *vimhdl-prj-config-file* 181 | 182 | Old style project file syntax is as follows: > 183 | 184 | # This is a comment 185 | 186 | # This is being deprecated, listed here for documentation only! 187 | [ builder = (msim|ghdl|xvhdl) ] 188 | 189 | [ global_build_flags[ (vhdl|verilog|systemverilog) ] = ] 190 | 191 | # Specifying sources 192 | (vhdl|verilog|systemverilog) [file specific flags] 193 | < 194 | 195 | An example project file could be: > 196 | 197 | global_build_flags = -32 # Common flags for all languages 198 | global_build_flags[vhdl] = -rangecheck 199 | global_build_flags[verilog] = -lint 200 | global_build_flags[systemverilog] = -lint 201 | 202 | # Relative paths (relative to the project file if using HTTP mode or the 203 | # project root if using LSP mode) 204 | vhdl my_library foo.vhd -check_synthesis 205 | vhdl my_library foo_tb.vhd -2008 206 | verilog my_library verilog/a_verilog_file.v -pedanticerrors 207 | 208 | # Absolute paths are handled as such 209 | systemverilog my_library /home/user/some_systemverilog_file.sv -pedanticerrors 210 | 211 | # Wildcards are supported 212 | vhdl my_library library/*.vhd 213 | vhdl my_library library/*/*.vhd 214 | 215 | Setting specific flags can be done per language or per file > 216 | 217 | global_build_flags[vhdl] = 218 | global_build_flags[verilog] = 219 | global_build_flags[systemverilog] = 220 | 221 | ------------------------------------------------------------------------------ 222 | 2.4. Style check *vimhdl-style-check* 223 | 224 | TODO... 225 | 226 | ============================================================================== 227 | 3. Vim commands *vimhdl-commands* 228 | 229 | ------------------------------------------------------------------------------ 230 | *vimhdl-commands-info* *VimhdlInfo* 231 | :VimhdlInfo 232 | 233 | Use this command to get the versions of both |vimhdl| and |hdl-checker|, the builder 234 | currently in use and some |hdl-checker| server info. 235 | 236 | ------------------------------------------------------------------------------ 237 | *vimhdl-commands-rebuildproject* *VimhdlRebuildProject* 238 | :VimhdlRebuildProject 239 | 240 | Use this command if you feel either |vimhdl| or |hdl-checker| seem to be misbehaving. 241 | This will cause |hdl-checker| to clean up both the project cache and the target 242 | folder and restar building the project from scratch. Please note that on 243 | project with large numbers of files this can be lengthy. 244 | 245 | ------------------------------------------------------------------------------ 246 | *vimhdl-commands-restartserver* *VimhdlRestartServer* 247 | :VimhdlRestartServer 248 | 249 | Restarts the |hdl-checker| server manually. 250 | 251 | 252 | ------------------------------------------------------------------------------ 253 | *vimhdl-commands-createprojectfile* *VimhdlCreateProjectFile* 254 | :VimhdlCreateProjectFile [paths] 255 | 256 | Runs a simple file finder on [paths] and tries to populate the contents of the 257 | configuration file based on that. This can be used as a basis for writing your 258 | own configuration files. 259 | 260 | ------------------------------------------------------------------------------ 261 | *vimhdl-commands-viewdependencies* *VimhdlViewDependencies* 262 | :VimhdlViewDependencies 263 | 264 | Prints the dependencies of the current file in the . 265 | format. 266 | 267 | ------------------------------------------------------------------------------ 268 | *vimhdl-commands-viewbuildsequence* *VimhdlViewBuildSequence* 269 | :VimhdlViewBuildSequence 270 | 271 | Prints out the build sequence of the current file for debuggin purposes. 272 | 273 | 274 | ============================================================================== 275 | 4. Options *vimhdl-options* 276 | 277 | ------------------------------------------------------------------------------ 278 | 4.1. Configuration file *vimhdl-config-file* 279 | 280 | *'b:vimhdl_conf_file'* *'g:vimhdl_conf_file'* 281 | 282 | Type: string 283 | Default: 284 | 285 | See |vimhdl-quickstart| for a quick intro or a more complete version on GitHub 286 | at https://github.com/suoto/hdl_checker/wiki. 287 | 288 | Usage: > 289 | let g:vimhdl_conf_file = '' 290 | or > 291 | let b:vimhdl_conf_file = '' 292 | 293 | Note that b:vimhdl_conf_file have preference over g:vimhdl_conf_file. 294 | 295 | ------------------------------------------------------------------------------ 296 | 4.2. Logging level *vimhdl-log-level* 297 | 298 | *'g:vimhdl_log_level'* 299 | 300 | Type: string 301 | Default: 'INFO' 302 | 303 | Selects the log level to pass to the |hdl-checker| server upon starting it. 304 | Valid values are CRITICAL, ERROR, WARNING, INFO and DEBUG. See also 305 | |vimhdl-log-file|. 306 | 307 | Usage: > 308 | let g:vimhdl_log_level = 'INFO' 309 | 310 | ------------------------------------------------------------------------------ 311 | 4.3. Log file *vimhdl-log-file* 312 | 313 | *'g:vimhdl_log_file'* 314 | 315 | Type: string 316 | Default: 317 | 318 | Selects the log file to pass to the |hdl-checker| server upon starting it. 319 | Relative paths will use |getcwd()|. If this variable is not set or set to an 320 | empty string, |hdl-checker| will decide what to do. To get more info, see 321 | |hdl-checker| help by running on a terminal > 322 | 323 | hdl_checker --help 324 | 325 | Usage: > 326 | let g:vimhdl_log_level = 'INFO' 327 | 328 | See also |vimhdl-log-level|. 329 | 330 | ============================================================================== 331 | 332 | vim: ft=help 333 | -------------------------------------------------------------------------------- /python/vimhdl/vim_client.py: -------------------------------------------------------------------------------- 1 | # This file is part of vim-hdl. 2 | # 3 | # Copyright (c) 2015-2016 Andre Souto 4 | # 5 | # vim-hdl is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # vim-hdl is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with vim-hdl. If not, see . 17 | "Wrapper for vim-hdl usage within Vim's Python interpreter" 18 | 19 | import atexit 20 | import logging 21 | import os 22 | import os.path as p 23 | import subprocess as subp 24 | import sys 25 | import time 26 | from multiprocessing import Queue 27 | from pprint import pformat 28 | from tempfile import NamedTemporaryFile 29 | 30 | import vim # type: ignore # pylint: disable=import-error 31 | import vimhdl 32 | import vimhdl.vim_helpers as vim_helpers 33 | from vimhdl.base_requests import (BaseRequest, GetBuildSequence, 34 | GetDependencies, RequestHdlCheckerInfo, 35 | RequestMessagesByPath, RequestProjectRebuild, 36 | RequestQueuedMessages, RunConfigGenerator) 37 | from vimhdl.config_gen_wrapper import ConfigGenWrapper 38 | 39 | _ON_WINDOWS = sys.platform == "win32" 40 | 41 | _logger = logging.getLogger(__name__) 42 | 43 | 44 | def _sortKey(record): 45 | """ 46 | Key for sorting records 47 | """ 48 | return ( 49 | 1 if "Error" in record["type"] else 2, 50 | record["lnum"] if isinstance(record["lnum"], int) else 0, 51 | record["col"] if isinstance(record["col"], int) else 0, 52 | record["nr"] if isinstance(record["nr"], int) else 0, 53 | ) 54 | 55 | 56 | def _sortBuildMessages(records): 57 | """ 58 | Sorts the build messages using Vim's terminology 59 | """ 60 | for record in records: 61 | for key in ("lnum", "nr", "col"): 62 | try: 63 | record[key] = int(record[key]) 64 | except ValueError: 65 | pass 66 | records.sort(key=_sortKey) 67 | return records 68 | 69 | 70 | # pylint:disable=inconsistent-return-statements 71 | 72 | 73 | class VimhdlClient: # pylint: disable=too-many-instance-attributes 74 | """ 75 | Point of entry of Vim commands 76 | """ 77 | 78 | # If the user hasn't already set vimhdl_conf_file in g: or b:, we'll use 79 | # this instead 80 | _default_conf_filename = "vimhdl.prj" 81 | 82 | def __init__(self, **options): 83 | self._logger = logging.getLogger(__name__ + "." + self.__class__.__name__) 84 | self._logger.info("Creating vimhdl client object: %s", options) 85 | 86 | self._server = None 87 | # Store constructor args 88 | self._host = options.get("host", "localhost") 89 | self._port = options.get("port", vim_helpers.getUnusedLocalhostPort()) 90 | self._log_level = str(options.get("log_level", "DEBUG")) 91 | self._log_file = ( 92 | options.get("log_target", None) 93 | or NamedTemporaryFile( 94 | prefix="vimhdl_log_pid{}_".format(os.getpid()), suffix=".log" 95 | ).name 96 | ) 97 | 98 | self._stdout = ( 99 | options.get("stdout", None) 100 | or NamedTemporaryFile( 101 | prefix="vimhdl_stdout_pid{}_".format(os.getpid()), suffix=".log" 102 | ).name 103 | ) 104 | 105 | self._stderr = ( 106 | options.get("stderr", None) 107 | or NamedTemporaryFile( 108 | prefix="vimhdl_stderr_pid{}_".format(os.getpid()), suffix=".log" 109 | ).name 110 | ) 111 | 112 | self._posted_notifications = [] 113 | 114 | self._ui_queue = Queue() 115 | self.helper_wrapper = ConfigGenWrapper() 116 | 117 | # Set url on the BaseRequest class as well 118 | BaseRequest.url = "http://{}:{}".format(self._host, self._port) 119 | 120 | def startServer(self): 121 | """ 122 | Starts the hdl_checker server, waits until it responds and register 123 | server shutdown when exiting Vim's Python interpreter 124 | """ 125 | self._startServerProcess() 126 | self._waitForServerSetup() 127 | 128 | atexit.register(self.shutdown) 129 | 130 | def _postError(self, msg): 131 | """ 132 | Post errors to the user once 133 | """ 134 | if ("error", msg) not in self._posted_notifications: 135 | self._posted_notifications += [("error", msg)] 136 | vim_helpers.postVimError(msg) 137 | 138 | def _postWarning(self, msg): 139 | """ 140 | Post warnings to the user once 141 | """ 142 | if ("warn", msg) not in self._posted_notifications: 143 | self._posted_notifications += [("warn", msg)] 144 | vim_helpers.postVimWarning(msg) 145 | 146 | def _isServerAlive(self): 147 | """ 148 | Checks if the the server is alive 149 | """ 150 | if self._server is None: 151 | return False 152 | is_alive = self._server.poll() is None 153 | if not is_alive: 154 | self._postWarning("hdl_checker server is not running") 155 | return is_alive 156 | 157 | def _startServerProcess(self): 158 | """ 159 | Starts the hdl_checker server 160 | """ 161 | self._logger.info("Running vim_hdl client setup") 162 | 163 | hdl_checker_executable = "hdl_checker" 164 | 165 | # Try to get the version before to catch potential issues 166 | try: 167 | _cmd = [hdl_checker_executable, "--version"] 168 | self._logger.debug("Will run %s", " ".join(map(str, _cmd))) 169 | self._logger.info( 170 | "version: %s", subp.check_output(_cmd, stderr=subp.STDOUT) 171 | ) 172 | except (subp.CalledProcessError, FileNotFoundError) as exc: 173 | # self._postError() 174 | vim_helpers.postVimError("Error while starting server: {}".format(exc)) 175 | return 176 | 177 | cmd = [ 178 | hdl_checker_executable, 179 | "--host", 180 | self._host, 181 | "--port", 182 | str(self._port), 183 | "--stdout", 184 | self._stdout, 185 | "--stderr", 186 | self._stderr, 187 | "--attach-to-pid", 188 | str(os.getpid()), 189 | "--log-level", 190 | self._log_level, 191 | "--log-stream", 192 | self._log_file, 193 | ] 194 | 195 | self._logger.info( 196 | "Starting hdl_checker server with '%s'", " ".join(map(str, cmd)) 197 | ) 198 | 199 | try: 200 | if _ON_WINDOWS: 201 | self._server = subp.Popen( 202 | cmd, 203 | stdout=subp.PIPE, 204 | stderr=subp.PIPE, 205 | creationflags=subp.CREATE_NEW_PROCESS_GROUP, 206 | ) 207 | else: 208 | self._server = subp.Popen( 209 | cmd, 210 | stdout=subp.PIPE, 211 | stderr=subp.PIPE, 212 | preexec_fn=os.setpgrp, 213 | ) 214 | 215 | if not self._isServerAlive(): 216 | self._postError("Failed to launch hdl_checker server") 217 | except subp.CalledProcessError: 218 | self._logger.exception("Error calling '%s'", " ".join(cmd)) 219 | 220 | def _waitForServerSetup(self): 221 | """ 222 | Wait for ~10s until the server is actually responding 223 | """ 224 | for _ in range(10): 225 | time.sleep(0.2) 226 | request = RequestHdlCheckerInfo() 227 | response = request.sendRequest() 228 | self._logger.debug(response) 229 | if response: 230 | self._logger.info("Ok, server is really up") 231 | return 232 | self._logger.info("Server is not responding yet") 233 | 234 | self._postError("Unable to talk to server") 235 | 236 | def shutdown(self): 237 | """ 238 | Kills the hdl_checker server 239 | """ 240 | if not self._isServerAlive(): 241 | self._logger.warning("Server is not running") 242 | return 243 | self._logger.debug("Sending shutdown signal") 244 | os.kill(self._server.pid, 9) 245 | self._server.terminate() 246 | self._logger.debug("Done") 247 | 248 | def _handleAsyncRequest(self, response): 249 | """ 250 | Callback passed to asynchronous requests 251 | """ 252 | if response is not None: 253 | self._ui_queue.put(response) 254 | 255 | def _postQueuedMessages(self): 256 | """ 257 | Empty our queue in a single message 258 | """ 259 | while not self._ui_queue.empty(): 260 | messages = self._ui_queue.get() 261 | for severity, message in messages.json().get("ui_messages", []): 262 | if severity == "info": 263 | vim_helpers.postVimInfo(message) 264 | elif severity == "warning": 265 | self._postWarning(message) 266 | elif severity == "error": 267 | self._postError(message) 268 | else: 269 | vim_helpers.postVimError( 270 | "Unknown severity '%s' for message '%s'" % (severity, message) 271 | ) 272 | 273 | def getMessages(self, vim_buffer=None, vim_var=None): 274 | """ 275 | Returns a list of messages to populate the quickfix list. For 276 | more info, check :help getqflist() 277 | """ 278 | if not self._isServerAlive(): 279 | self._logger.warning("Server is not alive, can't get messages") 280 | return 281 | 282 | if vim_buffer is None: 283 | vim_buffer = vim.current.buffer 284 | 285 | if vim_var is not None: 286 | vim.command("let {0} = []".format(vim_var)) 287 | 288 | project_file = vim_helpers.getProjectFile() 289 | path = p.abspath(vim_buffer.name) 290 | 291 | request = RequestMessagesByPath(project_file=project_file, path=path) 292 | 293 | response = request.sendRequest() 294 | if response is None: 295 | return 296 | 297 | messages = [] 298 | for msg in response.json().get("messages", []): 299 | _logger.info("msg:\n%s", pformat(msg)) 300 | text = str(msg["text"]) if msg["text"] else "" 301 | vim_fmt_dict = { 302 | "lnum": int(msg.get("line_number", 0)) + 1, 303 | "bufnr": str(vim_buffer.number), 304 | "filename": msg.get("filename", None) or vim_buffer.name, 305 | "valid": "1", 306 | "text": text, 307 | "nr": msg.get("error_code", None) or "0", 308 | "type": msg.get("severity", None) or "E", 309 | "col": int(msg.get("column_number", 0)) + 1, 310 | } 311 | try: 312 | vim_fmt_dict["subtype"] = str(msg["error_subtype"]) 313 | except KeyError: 314 | pass 315 | 316 | _logger.info(vim_fmt_dict) 317 | messages.append(vim_fmt_dict) 318 | 319 | self.requestUiMessages("getMessages") 320 | 321 | if vim_var is None: 322 | return _sortBuildMessages(messages) 323 | 324 | for msg in _sortBuildMessages(messages): 325 | vim_helpers.toVimDict(msg, "_dict") 326 | vim.command("let {0} += [{1}]".format(vim_var, "_dict")) 327 | vim.command("unlet! _dict") 328 | 329 | def requestUiMessages(self, event): 330 | """Retrieves UI messages from the server and post them with the 331 | appropriate severity level""" 332 | self._logger.info( 333 | "Handling event '%s'. Filetype is %s", event, vim.eval("&filetype") 334 | ) 335 | self._postQueuedMessages() 336 | 337 | if not self._isServerAlive(): 338 | return 339 | 340 | project_file = vim_helpers.getProjectFile() 341 | 342 | request = RequestQueuedMessages(project_file=project_file) 343 | 344 | request.sendRequestAsync(self._handleAsyncRequest) 345 | 346 | def getVimhdlInfo(self): 347 | """ 348 | Gets info about the current project and hdl_checker server 349 | """ 350 | project_file = vim_helpers.getProjectFile() 351 | request = RequestHdlCheckerInfo(project_file=project_file) 352 | 353 | response = request.sendRequest() 354 | 355 | info = ["vimhdl version: %s" % vimhdl.__version__] 356 | 357 | if response is not None: 358 | # The server has responded something, so just print it 359 | self._logger.info("Response: %s", str(response.json()["info"])) 360 | 361 | info += response.json()["info"] 362 | else: 363 | info += ["hdl_checker server is not running"] 364 | 365 | info += [ 366 | "Server logs: " + self._log_file, 367 | "Server stdout: " + self._stdout, 368 | "Server stderr: " + self._stderr, 369 | ] 370 | 371 | _logger.info("info: %s", info) 372 | return "\n".join(["- " + str(x) for x in info]) 373 | 374 | def rebuildProject(self): 375 | """ 376 | Rebuilds the current project 377 | """ 378 | if vim.eval("&filetype") not in ("vhdl", "verilog", "systemverilog"): 379 | vim_helpers.postVimWarning("Not a VHDL file, can't rebuild") 380 | return 381 | 382 | vim_helpers.postVimInfo("Rebuilding project...") 383 | project_file = vim_helpers.getProjectFile() 384 | request = RequestProjectRebuild(project_file=project_file) 385 | 386 | response = request.sendRequest() 387 | 388 | if response is None: 389 | return "hdl_checker server is not running" 390 | 391 | self._logger.info("Response: %s", repr(response)) 392 | 393 | def getDependencies(self): 394 | """ 395 | Gets the dependencies for a given path 396 | """ 397 | self._postQueuedMessages() 398 | 399 | if not self._isServerAlive(): 400 | return 401 | 402 | project_file = vim_helpers.getProjectFile() 403 | 404 | request = GetDependencies( 405 | project_file=project_file, path=vim.current.buffer.name 406 | ) 407 | 408 | response = request.sendRequest() 409 | if response is not None: 410 | self._logger.debug("Response: %s", str(response.json()["dependencies"])) 411 | 412 | return "\n".join( 413 | ["Dependencies for %s" % vim.current.buffer.name] 414 | + ["- %s" % x for x in sorted(response.json()["dependencies"])] 415 | ) 416 | 417 | return "Source has no dependencies" 418 | 419 | def getBuildSequence(self): 420 | """ 421 | Gets the build sequence for the current path 422 | """ 423 | self._postQueuedMessages() 424 | 425 | if not self._isServerAlive(): 426 | return 427 | 428 | project_file = vim_helpers.getProjectFile() 429 | 430 | request = GetBuildSequence( 431 | project_file=project_file, path=vim.current.buffer.name 432 | ) 433 | 434 | response = request.sendRequest() 435 | if response is not None: 436 | self._logger.debug("Response: %s", str(response.json()["sequence"])) 437 | 438 | sequence = response.json()["sequence"] 439 | if sequence: 440 | i = 1 441 | msg = ["Build sequence for %s\n" % vim.current.buffer.name] 442 | for i, item in enumerate(sequence, 1): 443 | msg += ["%d: %s" % (i, item)] 444 | return "\n".join(msg) 445 | 446 | return "Build sequence is empty" 447 | 448 | return "" 449 | 450 | def updateHelperWrapper(self): 451 | """ 452 | Requests the config file content from the server and return the wrapper 453 | class 454 | """ 455 | paths = vim.eval("b:local_arg") or ["."] 456 | 457 | request = RunConfigGenerator(generator="SimpleFinder", paths=paths) 458 | response = request.sendRequest() 459 | if response is None: 460 | return 461 | 462 | self.helper_wrapper.run(response.json()["content"]) 463 | -------------------------------------------------------------------------------- /python/vimhdl/_version.py: -------------------------------------------------------------------------------- 1 | 2 | # This file helps to compute a version number in source trees obtained from 3 | # git-archive tarball (such as those provided by githubs download-from-tag 4 | # feature). Distribution tarballs (built by setup.py sdist) and build 5 | # directories (produced by setup.py build) will contain a much shorter file 6 | # that just contains the computed version number. 7 | 8 | # This file is released into the public domain. Generated by 9 | # versioneer-0.16 (https://github.com/warner/python-versioneer) 10 | 11 | """Git implementation of _version.py.""" 12 | 13 | import errno 14 | import os 15 | import re 16 | import subprocess 17 | import sys 18 | 19 | 20 | def get_keywords(): 21 | """Get the keywords needed to look up the version information.""" 22 | # these strings will be replaced by git during git-archive. 23 | # setup.py/versioneer.py will grep for the variable names, so they must 24 | # each be defined on a line of their own. _version.py will just call 25 | # get_keywords(). 26 | git_refnames = " (HEAD -> master)" 27 | git_full = "1eee342afa0fa627b74e7cb4c076c761663c2473" 28 | keywords = {"refnames": git_refnames, "full": git_full} 29 | return keywords 30 | 31 | 32 | class VersioneerConfig: 33 | """Container for Versioneer configuration parameters.""" 34 | 35 | 36 | def get_config(): 37 | """Create, populate and return the VersioneerConfig() object.""" 38 | # these strings are filled in when 'setup.py versioneer' creates 39 | # _version.py 40 | cfg = VersioneerConfig() 41 | cfg.VCS = "git" 42 | cfg.style = "pep440" 43 | cfg.tag_prefix = "v" 44 | cfg.parentdir_prefix = "None" 45 | cfg.versionfile_source = "python/vimhdl/_version.py" 46 | cfg.verbose = False 47 | return cfg 48 | 49 | 50 | class NotThisMethod(Exception): 51 | """Exception raised if a method is not valid for the current scenario.""" 52 | 53 | 54 | LONG_VERSION_PY = {} 55 | HANDLERS = {} 56 | 57 | 58 | def register_vcs_handler(vcs, method): # decorator 59 | """Decorator to mark a method as the handler for a particular VCS.""" 60 | def decorate(f): 61 | """Store f in HANDLERS[vcs][method].""" 62 | if vcs not in HANDLERS: 63 | HANDLERS[vcs] = {} 64 | HANDLERS[vcs][method] = f 65 | return f 66 | return decorate 67 | 68 | 69 | def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False): 70 | """Call the given command(s).""" 71 | assert isinstance(commands, list) 72 | p = None 73 | for c in commands: 74 | try: 75 | dispcmd = str([c] + args) 76 | # remember shell=False, so use git.cmd on windows, not just git 77 | p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE, 78 | stderr=(subprocess.PIPE if hide_stderr 79 | else None)) 80 | break 81 | except EnvironmentError: 82 | e = sys.exc_info()[1] 83 | if e.errno == errno.ENOENT: 84 | continue 85 | if verbose: 86 | print("unable to run %s" % dispcmd) 87 | print(e) 88 | return None 89 | else: 90 | if verbose: 91 | print("unable to find command, tried %s" % (commands,)) 92 | return None 93 | stdout = p.communicate()[0].strip() 94 | if sys.version_info[0] >= 3: 95 | stdout = stdout.decode() 96 | if p.returncode != 0: 97 | if verbose: 98 | print("unable to run %s (error)" % dispcmd) 99 | return None 100 | return stdout 101 | 102 | 103 | def versions_from_parentdir(parentdir_prefix, root, verbose): 104 | """Try to determine the version from the parent directory name. 105 | 106 | Source tarballs conventionally unpack into a directory that includes 107 | both the project name and a version string. 108 | """ 109 | dirname = os.path.basename(root) 110 | if not dirname.startswith(parentdir_prefix): 111 | if verbose: 112 | print("guessing rootdir is '%s', but '%s' doesn't start with " 113 | "prefix '%s'" % (root, dirname, parentdir_prefix)) 114 | raise NotThisMethod("rootdir doesn't start with parentdir_prefix") 115 | return {"version": dirname[len(parentdir_prefix):], 116 | "full-revisionid": None, 117 | "dirty": False, "error": None} 118 | 119 | 120 | @register_vcs_handler("git", "get_keywords") 121 | def git_get_keywords(versionfile_abs): 122 | """Extract version information from the given file.""" 123 | # the code embedded in _version.py can just fetch the value of these 124 | # keywords. When used from setup.py, we don't want to import _version.py, 125 | # so we do it with a regexp instead. This function is not used from 126 | # _version.py. 127 | keywords = {} 128 | try: 129 | f = open(versionfile_abs, "r") 130 | for line in f.readlines(): 131 | if line.strip().startswith("git_refnames ="): 132 | mo = re.search(r'=\s*"(.*)"', line) 133 | if mo: 134 | keywords["refnames"] = mo.group(1) 135 | if line.strip().startswith("git_full ="): 136 | mo = re.search(r'=\s*"(.*)"', line) 137 | if mo: 138 | keywords["full"] = mo.group(1) 139 | f.close() 140 | except EnvironmentError: 141 | pass 142 | return keywords 143 | 144 | 145 | @register_vcs_handler("git", "keywords") 146 | def git_versions_from_keywords(keywords, tag_prefix, verbose): 147 | """Get version information from git keywords.""" 148 | if not keywords: 149 | raise NotThisMethod("no keywords at all, weird") 150 | refnames = keywords["refnames"].strip() 151 | if refnames.startswith("$Format"): 152 | if verbose: 153 | print("keywords are unexpanded, not using") 154 | raise NotThisMethod("unexpanded keywords, not a git-archive tarball") 155 | refs = set([r.strip() for r in refnames.strip("()").split(",")]) 156 | # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of 157 | # just "foo-1.0". If we see a "tag: " prefix, prefer those. 158 | TAG = "tag: " 159 | tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) 160 | if not tags: 161 | # Either we're using git < 1.8.3, or there really are no tags. We use 162 | # a heuristic: assume all version tags have a digit. The old git %d 163 | # expansion behaves like git log --decorate=short and strips out the 164 | # refs/heads/ and refs/tags/ prefixes that would let us distinguish 165 | # between branches and tags. By ignoring refnames without digits, we 166 | # filter out many common branch names like "release" and 167 | # "stabilization", as well as "HEAD" and "master". 168 | tags = set([r for r in refs if re.search(r'\d', r)]) 169 | if verbose: 170 | print("discarding '%s', no digits" % ",".join(refs-tags)) 171 | if verbose: 172 | print("likely tags: %s" % ",".join(sorted(tags))) 173 | for ref in sorted(tags): 174 | # sorting will prefer e.g. "2.0" over "2.0rc1" 175 | if ref.startswith(tag_prefix): 176 | r = ref[len(tag_prefix):] 177 | if verbose: 178 | print("picking %s" % r) 179 | return {"version": r, 180 | "full-revisionid": keywords["full"].strip(), 181 | "dirty": False, "error": None 182 | } 183 | # no suitable tags, so version is "0+unknown", but full hex is still there 184 | if verbose: 185 | print("no suitable tags, using unknown + full revision id") 186 | return {"version": "0+unknown", 187 | "full-revisionid": keywords["full"].strip(), 188 | "dirty": False, "error": "no suitable tags"} 189 | 190 | 191 | @register_vcs_handler("git", "pieces_from_vcs") 192 | def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): 193 | """Get version from 'git describe' in the root of the source tree. 194 | 195 | This only gets called if the git-archive 'subst' keywords were *not* 196 | expanded, and _version.py hasn't already been rewritten with a short 197 | version string, meaning we're inside a checked out source tree. 198 | """ 199 | if not os.path.exists(os.path.join(root, ".git")): 200 | if verbose: 201 | print("no .git in %s" % root) 202 | raise NotThisMethod("no .git directory") 203 | 204 | GITS = ["git"] 205 | if sys.platform == "win32": 206 | GITS = ["git.cmd", "git.exe"] 207 | # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] 208 | # if there isn't one, this yields HEX[-dirty] (no NUM) 209 | describe_out = run_command(GITS, ["describe", "--tags", "--dirty", 210 | "--always", "--long", 211 | "--match", "%s*" % tag_prefix], 212 | cwd=root) 213 | # --long was added in git-1.5.5 214 | if describe_out is None: 215 | raise NotThisMethod("'git describe' failed") 216 | describe_out = describe_out.strip() 217 | full_out = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) 218 | if full_out is None: 219 | raise NotThisMethod("'git rev-parse' failed") 220 | full_out = full_out.strip() 221 | 222 | pieces = {} 223 | pieces["long"] = full_out 224 | pieces["short"] = full_out[:7] # maybe improved later 225 | pieces["error"] = None 226 | 227 | # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] 228 | # TAG might have hyphens. 229 | git_describe = describe_out 230 | 231 | # look for -dirty suffix 232 | dirty = git_describe.endswith("-dirty") 233 | pieces["dirty"] = dirty 234 | if dirty: 235 | git_describe = git_describe[:git_describe.rindex("-dirty")] 236 | 237 | # now we have TAG-NUM-gHEX or HEX 238 | 239 | if "-" in git_describe: 240 | # TAG-NUM-gHEX 241 | mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) 242 | if not mo: 243 | # unparseable. Maybe git-describe is misbehaving? 244 | pieces["error"] = ("unable to parse git-describe output: '%s'" 245 | % describe_out) 246 | return pieces 247 | 248 | # tag 249 | full_tag = mo.group(1) 250 | if not full_tag.startswith(tag_prefix): 251 | if verbose: 252 | fmt = "tag '%s' doesn't start with prefix '%s'" 253 | print(fmt % (full_tag, tag_prefix)) 254 | pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" 255 | % (full_tag, tag_prefix)) 256 | return pieces 257 | pieces["closest-tag"] = full_tag[len(tag_prefix):] 258 | 259 | # distance: number of commits since tag 260 | pieces["distance"] = int(mo.group(2)) 261 | 262 | # commit: short hex revision ID 263 | pieces["short"] = mo.group(3) 264 | 265 | else: 266 | # HEX: no tags 267 | pieces["closest-tag"] = None 268 | count_out = run_command(GITS, ["rev-list", "HEAD", "--count"], 269 | cwd=root) 270 | pieces["distance"] = int(count_out) # total number of commits 271 | 272 | return pieces 273 | 274 | 275 | def plus_or_dot(pieces): 276 | """Return a + if we don't already have one, else return a .""" 277 | if "+" in pieces.get("closest-tag", ""): 278 | return "." 279 | return "+" 280 | 281 | 282 | def render_pep440(pieces): 283 | """Build up version string, with post-release "local version identifier". 284 | 285 | Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you 286 | get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty 287 | 288 | Exceptions: 289 | 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] 290 | """ 291 | if pieces["closest-tag"]: 292 | rendered = pieces["closest-tag"] 293 | if pieces["distance"] or pieces["dirty"]: 294 | rendered += plus_or_dot(pieces) 295 | rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) 296 | if pieces["dirty"]: 297 | rendered += ".dirty" 298 | else: 299 | # exception #1 300 | rendered = "0+untagged.%d.g%s" % (pieces["distance"], 301 | pieces["short"]) 302 | if pieces["dirty"]: 303 | rendered += ".dirty" 304 | return rendered 305 | 306 | 307 | def render_pep440_pre(pieces): 308 | """TAG[.post.devDISTANCE] -- No -dirty. 309 | 310 | Exceptions: 311 | 1: no tags. 0.post.devDISTANCE 312 | """ 313 | if pieces["closest-tag"]: 314 | rendered = pieces["closest-tag"] 315 | if pieces["distance"]: 316 | rendered += ".post.dev%d" % pieces["distance"] 317 | else: 318 | # exception #1 319 | rendered = "0.post.dev%d" % pieces["distance"] 320 | return rendered 321 | 322 | 323 | def render_pep440_post(pieces): 324 | """TAG[.postDISTANCE[.dev0]+gHEX] . 325 | 326 | The ".dev0" means dirty. Note that .dev0 sorts backwards 327 | (a dirty tree will appear "older" than the corresponding clean one), 328 | but you shouldn't be releasing software with -dirty anyways. 329 | 330 | Exceptions: 331 | 1: no tags. 0.postDISTANCE[.dev0] 332 | """ 333 | if pieces["closest-tag"]: 334 | rendered = pieces["closest-tag"] 335 | if pieces["distance"] or pieces["dirty"]: 336 | rendered += ".post%d" % pieces["distance"] 337 | if pieces["dirty"]: 338 | rendered += ".dev0" 339 | rendered += plus_or_dot(pieces) 340 | rendered += "g%s" % pieces["short"] 341 | else: 342 | # exception #1 343 | rendered = "0.post%d" % pieces["distance"] 344 | if pieces["dirty"]: 345 | rendered += ".dev0" 346 | rendered += "+g%s" % pieces["short"] 347 | return rendered 348 | 349 | 350 | def render_pep440_old(pieces): 351 | """TAG[.postDISTANCE[.dev0]] . 352 | 353 | The ".dev0" means dirty. 354 | 355 | Eexceptions: 356 | 1: no tags. 0.postDISTANCE[.dev0] 357 | """ 358 | if pieces["closest-tag"]: 359 | rendered = pieces["closest-tag"] 360 | if pieces["distance"] or pieces["dirty"]: 361 | rendered += ".post%d" % pieces["distance"] 362 | if pieces["dirty"]: 363 | rendered += ".dev0" 364 | else: 365 | # exception #1 366 | rendered = "0.post%d" % pieces["distance"] 367 | if pieces["dirty"]: 368 | rendered += ".dev0" 369 | return rendered 370 | 371 | 372 | def render_git_describe(pieces): 373 | """TAG[-DISTANCE-gHEX][-dirty]. 374 | 375 | Like 'git describe --tags --dirty --always'. 376 | 377 | Exceptions: 378 | 1: no tags. HEX[-dirty] (note: no 'g' prefix) 379 | """ 380 | if pieces["closest-tag"]: 381 | rendered = pieces["closest-tag"] 382 | if pieces["distance"]: 383 | rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) 384 | else: 385 | # exception #1 386 | rendered = pieces["short"] 387 | if pieces["dirty"]: 388 | rendered += "-dirty" 389 | return rendered 390 | 391 | 392 | def render_git_describe_long(pieces): 393 | """TAG-DISTANCE-gHEX[-dirty]. 394 | 395 | Like 'git describe --tags --dirty --always -long'. 396 | The distance/hash is unconditional. 397 | 398 | Exceptions: 399 | 1: no tags. HEX[-dirty] (note: no 'g' prefix) 400 | """ 401 | if pieces["closest-tag"]: 402 | rendered = pieces["closest-tag"] 403 | rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) 404 | else: 405 | # exception #1 406 | rendered = pieces["short"] 407 | if pieces["dirty"]: 408 | rendered += "-dirty" 409 | return rendered 410 | 411 | 412 | def render(pieces, style): 413 | """Render the given version pieces into the requested style.""" 414 | if pieces["error"]: 415 | return {"version": "unknown", 416 | "full-revisionid": pieces.get("long"), 417 | "dirty": None, 418 | "error": pieces["error"]} 419 | 420 | if not style or style == "default": 421 | style = "pep440" # the default 422 | 423 | if style == "pep440": 424 | rendered = render_pep440(pieces) 425 | elif style == "pep440-pre": 426 | rendered = render_pep440_pre(pieces) 427 | elif style == "pep440-post": 428 | rendered = render_pep440_post(pieces) 429 | elif style == "pep440-old": 430 | rendered = render_pep440_old(pieces) 431 | elif style == "git-describe": 432 | rendered = render_git_describe(pieces) 433 | elif style == "git-describe-long": 434 | rendered = render_git_describe_long(pieces) 435 | else: 436 | raise ValueError("unknown style '%s'" % style) 437 | 438 | return {"version": rendered, "full-revisionid": pieces["long"], 439 | "dirty": pieces["dirty"], "error": None} 440 | 441 | 442 | def get_versions(): 443 | """Get version information or return default if unable to do so.""" 444 | # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have 445 | # __file__, we can work backwards from there to the root. Some 446 | # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which 447 | # case we can only use expanded keywords. 448 | 449 | cfg = get_config() 450 | verbose = cfg.verbose 451 | 452 | try: 453 | return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, 454 | verbose) 455 | except NotThisMethod: 456 | pass 457 | 458 | try: 459 | root = os.path.realpath(__file__) 460 | # versionfile_source is the relative path from the top of the source 461 | # tree (where the .git directory might live) to this file. Invert 462 | # this to find the root from __file__. 463 | for i in cfg.versionfile_source.split('/'): 464 | root = os.path.dirname(root) 465 | except NameError: 466 | return {"version": "0+unknown", "full-revisionid": None, 467 | "dirty": None, 468 | "error": "unable to find root of source tree"} 469 | 470 | try: 471 | pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) 472 | return render(pieces, cfg.style) 473 | except NotThisMethod: 474 | pass 475 | 476 | try: 477 | if cfg.parentdir_prefix: 478 | return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) 479 | except NotThisMethod: 480 | pass 481 | 482 | return {"version": "0+unknown", "full-revisionid": None, 483 | "dirty": None, 484 | "error": "unable to compute version"} 485 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | 676 | --------------------------------------------------------------------------------