├── .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 | [](https://travis-ci.org/suoto/vim-hdl)
41 | [](https://codecov.io/gh/suoto/vim-hdl)
42 | [](https://gitter.im/suoto/vim-hdl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
43 | [](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 | 
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 |
--------------------------------------------------------------------------------