diff --git a/bundle/pycomplexity/autoload/.hg/00changelog.i b/bundle/pycomplexity/autoload/.hg/00changelog.i new file mode 100644 index 0000000..d3a8311 Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/00changelog.i differ diff --git a/bundle/pycomplexity/autoload/.hg/branch b/bundle/pycomplexity/autoload/.hg/branch new file mode 100644 index 0000000..4ad96d5 --- /dev/null +++ b/bundle/pycomplexity/autoload/.hg/branch @@ -0,0 +1 @@ +default diff --git a/bundle/pycomplexity/autoload/.hg/branchheads.cache b/bundle/pycomplexity/autoload/.hg/branchheads.cache new file mode 100644 index 0000000..62f47cd --- /dev/null +++ b/bundle/pycomplexity/autoload/.hg/branchheads.cache @@ -0,0 +1,2 @@ +ebdcc0d237c74189d8c479110eb38c2c5b408a99 70 +ebdcc0d237c74189d8c479110eb38c2c5b408a99 default diff --git a/bundle/pycomplexity/autoload/.hg/dirstate b/bundle/pycomplexity/autoload/.hg/dirstate new file mode 100644 index 0000000..b804ba6 Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/dirstate differ diff --git a/bundle/pycomplexity/autoload/.hg/hgrc b/bundle/pycomplexity/autoload/.hg/hgrc new file mode 100644 index 0000000..b4ab8d8 --- /dev/null +++ b/bundle/pycomplexity/autoload/.hg/hgrc @@ -0,0 +1,2 @@ +[paths] +default = http://bitbucket.org/garybernhardt/pycomplexity diff --git a/bundle/pycomplexity/autoload/.hg/requires b/bundle/pycomplexity/autoload/.hg/requires new file mode 100644 index 0000000..ca69271 --- /dev/null +++ b/bundle/pycomplexity/autoload/.hg/requires @@ -0,0 +1,4 @@ +revlogv1 +store +fncache +dotencode diff --git a/bundle/pycomplexity/autoload/.hg/store/00changelog.i b/bundle/pycomplexity/autoload/.hg/store/00changelog.i new file mode 100644 index 0000000..088dd93 Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/00changelog.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/00manifest.i b/bundle/pycomplexity/autoload/.hg/store/00manifest.i new file mode 100644 index 0000000..0bdf1ee Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/00manifest.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/_c_o_n_t_r_i_b_u_t_o_r_s.i b/bundle/pycomplexity/autoload/.hg/store/data/_c_o_n_t_r_i_b_u_t_o_r_s.i new file mode 100644 index 0000000..0969a4d Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/_c_o_n_t_r_i_b_u_t_o_r_s.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/_t_o_d_o.txt.i b/bundle/pycomplexity/autoload/.hg/store/data/_t_o_d_o.txt.i new file mode 100644 index 0000000..7924b4d Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/_t_o_d_o.txt.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/base.vim.i b/bundle/pycomplexity/autoload/.hg/store/data/base.vim.i new file mode 100644 index 0000000..099789f Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/base.vim.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/build.py.i b/bundle/pycomplexity/autoload/.hg/store/data/build.py.i new file mode 100644 index 0000000..1a542bf Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/build.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/complexity.py.i b/bundle/pycomplexity/autoload/.hg/store/data/complexity.py.i new file mode 100644 index 0000000..a3b4818 Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/complexity.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/complexity.vim.i b/bundle/pycomplexity/autoload/.hg/store/data/complexity.vim.i new file mode 100644 index 0000000..284b834 Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/complexity.vim.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/grammar/count__nodes.py.i b/bundle/pycomplexity/autoload/.hg/store/data/grammar/count__nodes.py.i new file mode 100644 index 0000000..15cef1e Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/grammar/count__nodes.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/grammar/everything.py.i b/bundle/pycomplexity/autoload/.hg/store/data/grammar/everything.py.i new file mode 100644 index 0000000..cf4a2ff Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/grammar/everything.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/grammar/python__ast__node__types.txt.i b/bundle/pycomplexity/autoload/.hg/store/data/grammar/python__ast__node__types.txt.i new file mode 100644 index 0000000..86f0ead Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/grammar/python__ast__node__types.txt.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/linum.el.i b/bundle/pycomplexity/autoload/.hg/store/data/linum.el.i new file mode 100644 index 0000000..abd789c Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/linum.el.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/pycomplexity.el.i b/bundle/pycomplexity/autoload/.hg/store/data/pycomplexity.el.i new file mode 100644 index 0000000..71cbcc5 Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/pycomplexity.el.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/runtests.py.i b/bundle/pycomplexity/autoload/.hg/store/data/runtests.py.i new file mode 100644 index 0000000..2bc4c1a Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/runtests.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/test.py.i b/bundle/pycomplexity/autoload/.hg/store/data/test.py.i new file mode 100644 index 0000000..69bf60b Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/test.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/tests/____init____.py.i b/bundle/pycomplexity/autoload/.hg/store/data/tests/____init____.py.i new file mode 100644 index 0000000..7df5ddf Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/tests/____init____.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/tests/manual/test__function__on__first__line.py.i b/bundle/pycomplexity/autoload/.hg/store/data/tests/manual/test__function__on__first__line.py.i new file mode 100644 index 0000000..736460c Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/tests/manual/test__function__on__first__line.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/tests/manual/test__functions.py.i b/bundle/pycomplexity/autoload/.hg/store/data/tests/manual/test__functions.py.i new file mode 100644 index 0000000..8e8e2d6 Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/tests/manual/test__functions.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/tests/manual/test__high__complexity__module.py.i b/bundle/pycomplexity/autoload/.hg/store/data/tests/manual/test__high__complexity__module.py.i new file mode 100644 index 0000000..be20718 Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/tests/manual/test__high__complexity__module.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/tests/manual/test__update__function.py.i b/bundle/pycomplexity/autoload/.hg/store/data/tests/manual/test__update__function.py.i new file mode 100644 index 0000000..0880765 Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/tests/manual/test__update__function.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/tests/test__comprehensions.py.i b/bundle/pycomplexity/autoload/.hg/store/data/tests/test__comprehensions.py.i new file mode 100644 index 0000000..bf65556 Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/tests/test__comprehensions.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/tests/test__conditionals.py.i b/bundle/pycomplexity/autoload/.hg/store/data/tests/test__conditionals.py.i new file mode 100644 index 0000000..3f921f0 Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/tests/test__conditionals.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/tests/test__exceptions.py.i b/bundle/pycomplexity/autoload/.hg/store/data/tests/test__exceptions.py.i new file mode 100644 index 0000000..cb89cf3 Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/tests/test__exceptions.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/tests/test__functions__and__classes.py.i b/bundle/pycomplexity/autoload/.hg/store/data/tests/test__functions__and__classes.py.i new file mode 100644 index 0000000..601f3a8 Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/tests/test__functions__and__classes.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/tests/test__integration.py.i b/bundle/pycomplexity/autoload/.hg/store/data/tests/test__integration.py.i new file mode 100644 index 0000000..4935423 Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/tests/test__integration.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/tests/test__loops.py.i b/bundle/pycomplexity/autoload/.hg/store/data/tests/test__loops.py.i new file mode 100644 index 0000000..e4daf05 Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/tests/test__loops.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/tests/test__scoped__objects.py.i b/bundle/pycomplexity/autoload/.hg/store/data/tests/test__scoped__objects.py.i new file mode 100644 index 0000000..08dc436 Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/tests/test__scoped__objects.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/tests/test__simple__statements.py.i b/bundle/pycomplexity/autoload/.hg/store/data/tests/test__simple__statements.py.i new file mode 100644 index 0000000..2a74bbe Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/tests/test__simple__statements.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/tests/utils.py.i b/bundle/pycomplexity/autoload/.hg/store/data/tests/utils.py.i new file mode 100644 index 0000000..ed5f582 Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/tests/utils.py.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/data/~2ehgignore.i b/bundle/pycomplexity/autoload/.hg/store/data/~2ehgignore.i new file mode 100644 index 0000000..3c0d556 Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/data/~2ehgignore.i differ diff --git a/bundle/pycomplexity/autoload/.hg/store/fncache b/bundle/pycomplexity/autoload/.hg/store/fncache new file mode 100644 index 0000000..e4c1220 --- /dev/null +++ b/bundle/pycomplexity/autoload/.hg/store/fncache @@ -0,0 +1,28 @@ +data/.hgignore.i +data/CONTRIBUTORS.i +data/TODO.txt.i +data/base.vim.i +data/build.py.i +data/complexity.py.i +data/complexity.vim.i +data/grammar/count_nodes.py.i +data/grammar/everything.py.i +data/grammar/python_ast_node_types.txt.i +data/linum.el.i +data/pycomplexity.el.i +data/runtests.py.i +data/test.py.i +data/tests/__init__.py.i +data/tests/manual/test_function_on_first_line.py.i +data/tests/manual/test_functions.py.i +data/tests/manual/test_high_complexity_module.py.i +data/tests/manual/test_update_function.py.i +data/tests/test_comprehensions.py.i +data/tests/test_conditionals.py.i +data/tests/test_exceptions.py.i +data/tests/test_functions_and_classes.py.i +data/tests/test_integration.py.i +data/tests/test_loops.py.i +data/tests/test_scoped_objects.py.i +data/tests/test_simple_statements.py.i +data/tests/utils.py.i diff --git a/bundle/pycomplexity/autoload/.hg/store/undo b/bundle/pycomplexity/autoload/.hg/store/undo new file mode 100644 index 0000000..d772ae6 Binary files /dev/null and b/bundle/pycomplexity/autoload/.hg/store/undo differ diff --git a/bundle/pycomplexity/autoload/.hg/tags.cache b/bundle/pycomplexity/autoload/.hg/tags.cache new file mode 100644 index 0000000..66a976b --- /dev/null +++ b/bundle/pycomplexity/autoload/.hg/tags.cache @@ -0,0 +1,2 @@ +70 ebdcc0d237c74189d8c479110eb38c2c5b408a99 + diff --git a/bundle/pycomplexity/autoload/.hg/undo.branch b/bundle/pycomplexity/autoload/.hg/undo.branch new file mode 100644 index 0000000..331d858 --- /dev/null +++ b/bundle/pycomplexity/autoload/.hg/undo.branch @@ -0,0 +1 @@ +default \ No newline at end of file diff --git a/bundle/pycomplexity/autoload/.hg/undo.desc b/bundle/pycomplexity/autoload/.hg/undo.desc new file mode 100644 index 0000000..f3f540e --- /dev/null +++ b/bundle/pycomplexity/autoload/.hg/undo.desc @@ -0,0 +1,3 @@ +0 +pull +http://bitbucket.org/garybernhardt/pycomplexity diff --git a/bundle/pycomplexity/autoload/.hg/undo.dirstate b/bundle/pycomplexity/autoload/.hg/undo.dirstate new file mode 100644 index 0000000..e69de29 diff --git a/bundle/pycomplexity/ftplugin/python/.hgignore b/bundle/pycomplexity/autoload/.hgignore similarity index 100% rename from bundle/pycomplexity/ftplugin/python/.hgignore rename to bundle/pycomplexity/autoload/.hgignore diff --git a/bundle/pycomplexity/autoload/CONTRIBUTORS b/bundle/pycomplexity/autoload/CONTRIBUTORS new file mode 100644 index 0000000..e5a9486 --- /dev/null +++ b/bundle/pycomplexity/autoload/CONTRIBUTORS @@ -0,0 +1,9 @@ +Original vim script by Gary Bernhardt +Emacs support added by Ignas Mikalajūnas + +Patches contributed by: + - Godefroid Chapelle + - Steve Bedford + - Chris Clark + - Peter Prohaska + diff --git a/bundle/pycomplexity/autoload/TODO.txt b/bundle/pycomplexity/autoload/TODO.txt new file mode 100644 index 0000000..849e0c6 --- /dev/null +++ b/bundle/pycomplexity/autoload/TODO.txt @@ -0,0 +1,3 @@ +Should catching multiple exception types in an "except" increase complexity? + +Handle nested functions. diff --git a/bundle/pycomplexity/autoload/base.vim b/bundle/pycomplexity/autoload/base.vim new file mode 100644 index 0000000..1b85d36 --- /dev/null +++ b/bundle/pycomplexity/autoload/base.vim @@ -0,0 +1,38 @@ +" complexity.vim +" Gary Bernhardt (http://blog.extracheese.org) +" +" This will add cyclomatic complexity annotations to your source code. It is +" no longer wrong (as previous versions were!) + +if !has('signs') + finish +endif +if !has('python') + finish +endif +python << endpython +import vim +%(python_source)s +endpython + +function! ShowComplexity() + python << END +show_complexity() +END +" no idea why it is needed to update colors each time +" to actually see the colors +hi low_complexity guifg=#004400 guibg=#004400 +hi medium_complexity guifg=#bbbb00 guibg=#bbbb00 +hi high_complexity guifg=#ff2222 guibg=#ff2222 +endfunction + +hi SignColumn guifg=fg guibg=bg +hi low_complexity guifg=#004400 guibg=#004400 +hi medium_complexity guifg=#bbbb00 guibg=#bbbb00 +hi high_complexity guifg=#ff2222 guibg=#ff2222 +sign define low_complexity text=XX texthl=low_complexity +sign define medium_complexity text=XX texthl=medium_complexity +sign define high_complexity text=XX texthl=high_complexity + +autocmd! BufReadPost,BufWritePost,FileReadPost,FileWritePost *.py call ShowComplexity() + diff --git a/bundle/pycomplexity/ftplugin/python/build.py b/bundle/pycomplexity/autoload/build.py similarity index 100% rename from bundle/pycomplexity/ftplugin/python/build.py rename to bundle/pycomplexity/autoload/build.py diff --git a/bundle/pycomplexity/ftplugin/python/complexity.py b/bundle/pycomplexity/autoload/complexity.py similarity index 100% rename from bundle/pycomplexity/ftplugin/python/complexity.py rename to bundle/pycomplexity/autoload/complexity.py diff --git a/bundle/pycomplexity/ftplugin/python/complexity.vim b/bundle/pycomplexity/autoload/complexity.vim similarity index 100% rename from bundle/pycomplexity/ftplugin/python/complexity.vim rename to bundle/pycomplexity/autoload/complexity.vim diff --git a/bundle/pycomplexity/ftplugin/python/grammar/count_nodes.py b/bundle/pycomplexity/autoload/grammar/count_nodes.py similarity index 100% rename from bundle/pycomplexity/ftplugin/python/grammar/count_nodes.py rename to bundle/pycomplexity/autoload/grammar/count_nodes.py diff --git a/bundle/pycomplexity/ftplugin/python/grammar/everything.py b/bundle/pycomplexity/autoload/grammar/everything.py similarity index 100% rename from bundle/pycomplexity/ftplugin/python/grammar/everything.py rename to bundle/pycomplexity/autoload/grammar/everything.py diff --git a/bundle/pycomplexity/ftplugin/python/grammar/python_ast_node_types.txt b/bundle/pycomplexity/autoload/grammar/python_ast_node_types.txt similarity index 100% rename from bundle/pycomplexity/ftplugin/python/grammar/python_ast_node_types.txt rename to bundle/pycomplexity/autoload/grammar/python_ast_node_types.txt diff --git a/bundle/pycomplexity/autoload/linum.el b/bundle/pycomplexity/autoload/linum.el new file mode 100644 index 0000000..e09ba02 --- /dev/null +++ b/bundle/pycomplexity/autoload/linum.el @@ -0,0 +1,192 @@ +;;; linum.el --- Display line numbers to the left of buffers + +;; Copyright (C) 2007, 2008 Markus Triska + +;; Author: Markus Triska +;; Keywords: convenience + +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file GPL.txt . If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;; Display line numbers for the current buffer. Copy linum.el to your +;; load-path and add to your .emacs: + +;; (require 'linum) + +;; Then toggle display of line numbers with M-x linum-mode. To enable +;; line numbering in all buffers, use M-x global-linum-mode. + +;;; Code: + +(defconst linum-version "0.9wza") + +(defvar linum-overlays nil "Overlays used in this buffer.") +(defvar linum-available nil "Overlays available for reuse.") +(defvar linum-before-numbering-hook nil + "Functions run in each buffer before line numbering starts.") + +(mapc #'make-variable-buffer-local '(linum-overlays linum-available)) + +(defgroup linum nil + "Show line numbers to the left of buffers" + :group 'convenience) + +;;;###autoload +(defcustom linum-format 'dynamic + "Format used to display line numbers. Either a format string +like \"%7d\", 'dynamic to adapt the width as needed, or a +function that is called with a line number as its argument and +should evaluate to a string to be shown on that line. See also +`linum-before-numbering-hook'." + :group 'linum + :type 'sexp) + +(defface linum + '((t :inherit (shadow default))) + "Face for displaying line numbers in the display margin." + :group 'linum) + +(defcustom linum-eager t + "Whether line numbers should be updated after each command. +The conservative setting `nil' might miss some buffer changes, +and you have to scroll or press C-l to update the numbers." + :group 'linum + :type 'boolean) + +(defcustom linum-delay nil + "Delay updates to give Emacs a chance for other changes." + :group 'linum + :type 'boolean) + +;;;###autoload +(define-minor-mode linum-mode + "Toggle display of line numbers in the left marginal area." + :lighter "" ; for desktop.el + (if linum-mode + (progn + (if linum-eager + (add-hook 'post-command-hook (if linum-delay + 'linum-schedule + 'linum-update-current) nil t) + (add-hook 'after-change-functions 'linum-after-change nil t)) + (add-hook 'window-scroll-functions 'linum-after-scroll nil t) + ;; mistake in Emacs: window-size-change-functions cannot be local + (add-hook 'window-size-change-functions 'linum-after-size) + (add-hook 'change-major-mode-hook 'linum-delete-overlays nil t) + (add-hook 'window-configuration-change-hook + 'linum-after-config nil t) + (linum-update-current)) + (remove-hook 'post-command-hook 'linum-update-current t) + (remove-hook 'post-command-hook 'linum-schedule t) + (remove-hook 'window-size-change-functions 'linum-after-size) + (remove-hook 'window-scroll-functions 'linum-after-scroll t) + (remove-hook 'after-change-functions 'linum-after-change t) + (remove-hook 'window-configuration-change-hook 'linum-after-config t) + (remove-hook 'change-major-mode-hook 'linum-delete-overlays t) + (linum-delete-overlays))) + +;;;###autoload +(define-globalized-minor-mode global-linum-mode linum-mode linum-on) + +(defun linum-on () + (unless (minibufferp) + (linum-mode 1))) + +(defun linum-delete-overlays () + "Delete all overlays displaying line numbers for this buffer." + (mapc #'delete-overlay linum-overlays) + (setq linum-overlays nil) + (dolist (w (get-buffer-window-list (current-buffer) nil t)) + (set-window-margins w 0))) + +(defun linum-update-current () + "Update line numbers for the current buffer." + (linum-update (current-buffer))) + +(defun linum-update (buffer) + "Update line numbers for all windows displaying BUFFER." + (with-current-buffer buffer + (when linum-mode + (setq linum-available linum-overlays) + (setq linum-overlays nil) + (save-excursion + (mapc #'linum-update-window + (get-buffer-window-list buffer nil 'visible))) + (mapc #'delete-overlay linum-available) + (setq linum-available nil)))) + +(defun linum-update-window (win) + "Update line numbers for the portion visible in window WIN." + (goto-char (window-start win)) + (let ((line (line-number-at-pos)) + (limit (window-end win t)) + (fmt (cond ((stringp linum-format) linum-format) + ((eq linum-format 'dynamic) + (let ((w (length (number-to-string + (count-lines (point-min) (point-max)))))) + (concat "%" (number-to-string w) "d"))))) + (width 0)) + (run-hooks 'linum-before-numbering-hook) + ;; Create an overlay (or reuse an existing one) for each + ;; line visible in this window, if necessary. + (while (and (not (eobp)) (<= (point) limit)) + (let* ((str (if fmt + (propertize (format fmt line) 'face 'linum) + (funcall linum-format line))) + (visited (catch 'visited + (dolist (o (overlays-in (point) (point))) + (when (string= (overlay-get o 'linum-str) str) + (unless (memq o linum-overlays) + (push o linum-overlays)) + (setq linum-available (delete o linum-available)) + (throw 'visited t)))))) + (setq width (max width (length str))) + (unless visited + (let ((ov (if (null linum-available) + (make-overlay (point) (point)) + (move-overlay (pop linum-available) (point) (point))))) + (push ov linum-overlays) + (overlay-put ov 'before-string + (propertize " " 'display `((margin left-margin) ,str))) + (overlay-put ov 'linum-str str)))) + (forward-line) + (setq line (1+ line))) + (set-window-margins win width))) + +(defun linum-after-change (beg end len) + ;; update overlays on deletions, and after newlines are inserted + (when (or (= beg end) + (= end (point-max)) + ;; TODO: use string-match-p with CVS or new release + (string-match "\n" (buffer-substring-no-properties beg end))) + (linum-update-current))) + +(defun linum-after-scroll (win start) + (linum-update (window-buffer win))) + +(defun linum-after-size (frame) + (linum-after-config)) + +(defun linum-schedule () + ;; schedule an update; the delay gives Emacs a chance for display changes + (run-with-idle-timer 0 nil #'linum-update-current)) + +(defun linum-after-config () + (walk-windows (lambda (w) (linum-update (window-buffer w))) nil 'visible)) + +(provide 'linum) +;;; linum.el ends here diff --git a/bundle/pycomplexity/autoload/pycomplexity.el b/bundle/pycomplexity/autoload/pycomplexity.el new file mode 100644 index 0000000..47fdbe8 --- /dev/null +++ b/bundle/pycomplexity/autoload/pycomplexity.el @@ -0,0 +1,155 @@ +;;; pycomplexity.el --- Display python code complexity to the left of buffers + +;; Copyright (C) 2009 Ignas Mikalajunas + +;; Author: Ignas Mikalajunas +;; Keywords: convenience + +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file GPL.txt . If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;; Display complexity information for the current buffer. + +;; Add to your .emacs: + +;; (add-to-list 'load-path "~/.site-lisp/pycomplexity/") + +;; (require 'linum) +;; (require 'pycomplexity) +;; (add-hook 'python-mode-hook +;; (function (lambda () +;; (pycomplexity-mode) +;; (linum-mode)))) + +;;; Code: + +(defconst pycomplexity-version "0.1") + + +(defvar complexity-last-change 0 "Time last change to some python buffer happened.") +(defvar complexity-data nil "Calcuated code complexity information for this buffer.") +(make-variable-buffer-local 'complexity-data) + +(defgroup pycomplexity nil + "Show complexity information to the left of buffers" + :group 'convenience) + +(defface pycomplexity-complexity-low + '((t (:background "green" + :foreground "green"))) + "Face that marks simple code " + :group 'pycomplexity) + +(defface pycomplexity-complexity-normal + '((t (:background "yellow" + :foreground "yellow"))) + "Face that marks normal code " + :group 'pycomplexity) + +(defface pycomplexity-complexity-high + '((t (:background "red" + :foreground "red"))) + "Face that marks complex code " + :group 'pycomplexity) + +(defcustom pycomplexity-delay 5 + "Update coverage information once in this many seconds." + :group 'pycomplexity + :type 'int) + +(defcustom pycomplexity-python "python" + "Python interpreter used to run the complexity calculation script." + :group 'pycomplexity + :type 'string) + +(defcustom pycomplexity-script + (expand-file-name "complexity.py" + (file-name-directory (or load-file-name buffer-file-name))) + "Pycomplexity python script." + :group 'pycomplexity + :type 'string) + +;;;###autoload +(define-minor-mode pycomplexity-mode + "Toggle display complexity of the python code you are editing." + :lighter "" ; for desktop.el + (if pycomplexity-mode + (progn + (add-hook 'after-change-functions 'pycomplexity-on-change nil t) + (add-hook 'after-save-hook 'pycomplexity-on-change-force nil t) + (setf linum-format 'pycomplexity-line-format) + (pycomplexity-on-change-force)) + (setf linum-format 'dynamic) + (remove-hook 'after-change-functions 'pycomplexity-on-change t))) + +(defun pycomplexity-get-complexity (line data) + (multiple-value-bind (face str complexity) + (loop for info in data + for from = (first info) + for to = (second info) + for complexity = (third info) + when (and (>= line from) + (<= line to)) + return (cond ((> complexity 14) (values 'pycomplexity-complexity-high "h" complexity)) + ((> complexity 7) (values 'pycomplexity-complexity-normal "n" complexity)) + (t (values 'pycomplexity-complexity-low "l" complexity))) + when (< line from) + return (values 'default " " 0)) + (if face (values face str complexity) + (values 'default " " 0)))) + +(defun pycomplexity-line-format (line) + (multiple-value-bind (face str complexity) + (pycomplexity-get-complexity line complexity-data) + (propertize str 'face face + 'help-echo (format "Complexity of this function is %d" complexity)))) + + +(defun pycomplexity-make-buffer-copy () + (let* ((source-file-name buffer-file-name) + (file-name (flymake-create-temp-inplace source-file-name "complexity"))) + (make-directory (file-name-directory file-name) 1) + (write-region nil nil file-name nil 566) + file-name)) + +(defun pycomplexity-get-raw-complexity-data (file-name) + (shell-command-to-string (format "%s %s %s" + pycomplexity-python + pycomplexity-script + file-name))) + +(defun pycomplexity-on-change-force (&optional beg end len) + (pycomplexity-on-change beg end len t)) + +(defun pycomplexity-on-change (&optional beg end len force) + (let ((since-last-change (- (float-time) complexity-last-change))) + (when (or (> since-last-change pycomplexity-delay) force) + (setf complexity-last-change (float-time)) + (let* ((temp-source-file-name (pycomplexity-make-buffer-copy)) + (result (pycomplexity-get-raw-complexity-data temp-source-file-name)) + (data (loop + for line in (save-match-data (split-string result "[\n\r]+")) + for parsed-line = (loop for item in (split-string line) + when item collect (read item)) + when (and parsed-line + (equal (car (last parsed-line)) 'function)) + collect (subseq parsed-line 0 3)))) + (when data (setf complexity-data data)) + (delete-file temp-source-file-name))))) + +(provide 'pycomplexity) +;;; pycomplexity.el ends here diff --git a/bundle/pycomplexity/ftplugin/python/runtests.py b/bundle/pycomplexity/autoload/runtests.py similarity index 100% rename from bundle/pycomplexity/ftplugin/python/runtests.py rename to bundle/pycomplexity/autoload/runtests.py diff --git a/bundle/pycomplexity/autoload/tests/__init__.py b/bundle/pycomplexity/autoload/tests/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/bundle/pycomplexity/autoload/tests/__init__.py @@ -0,0 +1 @@ + diff --git a/bundle/pycomplexity/autoload/tests/manual/test_function_on_first_line.py b/bundle/pycomplexity/autoload/tests/manual/test_function_on_first_line.py new file mode 100644 index 0000000..979c8e5 --- /dev/null +++ b/bundle/pycomplexity/autoload/tests/manual/test_function_on_first_line.py @@ -0,0 +1,29 @@ +def RED(): + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + a if a else a + diff --git a/bundle/pycomplexity/autoload/tests/manual/test_functions.py b/bundle/pycomplexity/autoload/tests/manual/test_functions.py new file mode 100644 index 0000000..92e9a35 --- /dev/null +++ b/bundle/pycomplexity/autoload/tests/manual/test_functions.py @@ -0,0 +1,45 @@ +def one(): + pass + +def two(): + a if a else a + +def three(): + a if a else a if a else a + +def four(): + a if a else a if a else a if a else a + +def five(): + a if a else a if a else a if a else a if a else a + +def six(): + a if a else a if a else a if a else a if a else a if a else a + +def seven(): + a if a else a if a else a if a else a if a else a if a else a if a else a + +def eight(): + a if a else a if a else a if a else a if a else a if a else a if a else a if a else a + +def nine(): + a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a + +def ten(): + a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a + +def eleven(): + a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a + +def twelve(): + a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a + +def thirteen(): + a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a + +def fourteen(): + a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a + +def fifteen(): + a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a + diff --git a/bundle/pycomplexity/autoload/tests/manual/test_high_complexity_module.py b/bundle/pycomplexity/autoload/tests/manual/test_high_complexity_module.py new file mode 100644 index 0000000..3acb1af --- /dev/null +++ b/bundle/pycomplexity/autoload/tests/manual/test_high_complexity_module.py @@ -0,0 +1,2 @@ +a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a if a else a + diff --git a/bundle/pycomplexity/autoload/tests/manual/test_update_function.py b/bundle/pycomplexity/autoload/tests/manual/test_update_function.py new file mode 100644 index 0000000..2ff76d6 --- /dev/null +++ b/bundle/pycomplexity/autoload/tests/manual/test_update_function.py @@ -0,0 +1,9 @@ +def foo(): + x if x else x if x else x if x else x if x else x if x else x if x else x + # Delete this line, then save. The function should go from yellow to + # green. Then undo and save. The *whole thing* should go back to yellow. + x if x else x + pass + pass + pass + diff --git a/bundle/pycomplexity/autoload/tests/test_comprehensions.py b/bundle/pycomplexity/autoload/tests/test_comprehensions.py new file mode 100644 index 0000000..dbf4589 --- /dev/null +++ b/bundle/pycomplexity/autoload/tests/test_comprehensions.py @@ -0,0 +1,58 @@ +from tests.utils import complexity + + +class describe_list_comprehensions: + def test_list_comprehension(self): + assert complexity("[x for x in y]").score == 2 + + def test_list_comprehension_with_inline_conditional(self): + assert complexity("[x if y else z for x in x]").score == 3 + + def test_nested_list_comprehensions(self): + assert complexity("[x for x in [y for y in z]]").score == 3 + + def test_list_comprehensions_with_multiple_fors(self): + assert complexity("[x for x in y for y in z]").score == 3 + + def test_list_comprehension_with_conditional(self): + assert complexity("[x for x in y if x]").score == 3 + + def test_list_comprehension_with_multiple_conditionals(self): + assert complexity("[x for x in y if x and y]").score == 4 + + def test_list_comprehension_with_multiple_conditionals_and_fors(self): + assert complexity( + """ + [x for x in x + for y in y + if x and y] + """).score == 5 + + +class describe_generator_expression: + def test_generator_expression(self): + assert complexity("(x for x in y)").score == 2 + + def test_with_inline_conditional(self): + assert complexity("(x if y else z for x in x)").score == 3 + + def test_nested(self): + assert complexity("(x for x in (y for y in z))").score == 3 + + def test_with_multiple_fors(self): + assert complexity("(x for x in y for y in z)").score == 3 + + def test_with_conditional(self): + assert complexity("(x for x in y if x)").score == 3 + + def test_with_multiple_conditionals(self): + assert complexity("(x for x in y if x and y)").score == 4 + + def test_with_multiple_conditionals_and_fors(self): + assert complexity( + """ + (x for x in x + for y in y + if x and y) + """).score == 5 + diff --git a/bundle/pycomplexity/autoload/tests/test_conditionals.py b/bundle/pycomplexity/autoload/tests/test_conditionals.py new file mode 100644 index 0000000..feddf3c --- /dev/null +++ b/bundle/pycomplexity/autoload/tests/test_conditionals.py @@ -0,0 +1,95 @@ +from tests.utils import complexity + + +class describe_conditionals: + def test_simple_branch(self): + assert complexity( + """ + if x: 1 + # implicit else + """).score == 2 + + def test_branch_with_else(self): + assert complexity( + """ + if x: 1 + else: 2 + """).score == 2 + + def test_branch_with_else_if(self): + assert complexity( + """ + if x: 1 + elif y: 2 + # implicit else + """).score == 3 + + def test_branch_with_else_if_and_else(self): + assert complexity( + """ + if x: 1 + elif y: 2 + else: 3 + """).score == 3 + + def test_child_nodes_of_ifs(self): + assert complexity( + """ + if x: + if y: 1 + else: 2 + else: 3 + """).score == 3 + + def test_child_nodes_of_elses(self): + assert complexity( + """ + if x: 1 + else: + if y: 1 + # implicit else + """).score == 3 + + def test_compound_conditionals(self): + assert complexity( + """ + if x or y: 1 + """).score == 3 + + def test_chained_compound_conditionals(self): + assert complexity( + """ + if a or b or c and d and e: 1 + """).score == 6 + + def test_nested_compound_conditionals(self): + assert complexity( + """ + if x or (y or z): 1 + """).score == 4 + + def test_logical_operator_inside_conditional_but_outside_test(self): + assert complexity( + """ + if x: + x and y + """).score == 2 + + +class describe_inline_conditionals: + def test_inline_conditionals(self): + assert complexity("b if c else d").score == 2 + + def test_nested_inline_conditionals(self): + assert complexity( + """ + (b + if c + else (d + if e + else f)) + """).score == 3 + + def test_logical_operator_in_inline_conditional(self): + assert complexity("a if b and c else d").score == 3 + diff --git a/bundle/pycomplexity/autoload/tests/test_exceptions.py b/bundle/pycomplexity/autoload/tests/test_exceptions.py new file mode 100644 index 0000000..56414c6 --- /dev/null +++ b/bundle/pycomplexity/autoload/tests/test_exceptions.py @@ -0,0 +1,74 @@ +from tests.utils import complexity + + +class describe_exception_handling: + def test_try(self): + assert complexity( + """ + try: 1 + except: 2 + """).score == 2 + + def test_try_with_multiple_excepts(self): + assert complexity( + """ + try: 1 + except A: 2 + except B: 3 + except C: 4 + """).score == 4 + + def test_try_with_multiple_exception_types_in_one_except(self): + assert complexity( + """ + try: 1 + except (A, B): 2 + """).score == 2 + + def test_try_with_child_nodes(self): + assert complexity( + """ + try: + if x: 1 + else: 2 + except: 2 + """).score == 3 + + def test_try_with_finally(self): + assert complexity( + """ + try: 1 + except: 2 + finally: 3 + """).score == 2 + + def test_try_with_else(self): + assert complexity( + """ + try: 1 + except: 2 + else: 3 + """).score == 2 + + def test_try_with_finally_and_child_nodes(self): + # Try/finally/else/except are all deceiving. The try and finally don't + # add any paths because they both always happen. An except adds one + # (it can either happen or not), but an else doesn't (it's equivalent + # to adding the code after the line in the try: that threw the + # exception, so it doesn't add a path). + assert complexity( + """ + try: + if a: 1 + else: 2 + except: + if a: 1 + else: 2 + else: + if a: 1 + else: 2 + finally: + if a: 1 + else: 2 + """).score == 6 + diff --git a/bundle/pycomplexity/autoload/tests/test_integration.py b/bundle/pycomplexity/autoload/tests/test_integration.py new file mode 100644 index 0000000..fe04613 --- /dev/null +++ b/bundle/pycomplexity/autoload/tests/test_integration.py @@ -0,0 +1,56 @@ +from tests.utils import complexity + + +class describe_integration: + def test_multiple_ifs_in_a_for_loop(self): + assert complexity( + """ + for x in y: + if x: pass + # implicit else + if y: pass + # implicit else + """).score == 4 + + def test_lambdas_in_a_function(self): + assert complexity( + """ + def foo(): + x = lambda: x if x else x + y if y else y + """).results.named('foo').score == 3 + + def test_a_big_hairy_mess(self): + assert complexity( + """ + while True: #1 + if x and y or (z and w): #4 + try: + x or y + raise x + except: #1 + 5 + finally: + break + else: + [x for x in [x and y for x in y if z or w]] #5 + try: + return + except A: #1 + return + except B: #1 + (y for y in z) #1 + finally: + raise (x for x in z) #1 + """).score == 15 + + def test_module_stat_comes_before_function_stat(self): + stats = complexity("def foo(): pass\npass").results + stat_names = [stat.name for stat in stats.ordered_by_line()] + assert stat_names == ['', 'foo'] + + def test_class_stat_comes_before_module_stat(self): + stats = complexity("class Foo: pass\npass").results + stat_names = [stat.name for stat in stats.ordered_by_line()] + assert stat_names == ['', 'Foo'] + diff --git a/bundle/pycomplexity/autoload/tests/test_loops.py b/bundle/pycomplexity/autoload/tests/test_loops.py new file mode 100644 index 0000000..7ef2107 --- /dev/null +++ b/bundle/pycomplexity/autoload/tests/test_loops.py @@ -0,0 +1,135 @@ +from tests.utils import complexity + + +class describe_for_loops: + def test_for_loops(self): + assert complexity( + """ + for x in y: 1 + # implicit else + """).score == 2 + + def test_else_clauses_on_for_loops(self): + assert complexity( + """ + for x in y: 1 + else: 2 + """).score == 2 + + def test_child_nodes_of_for_loops(self): + assert complexity( + """ + for x in y: + if x: 1 + else: 2 + # implicit else + """).score == 3 + + def test_child_nodes_in_for_loop_else_clauses(self): + assert complexity( + """ + for x in y: 1 + else: + if x: 2 + else: 3 + """).score == 3 + + def test_break_statements_in_for_loops(self): + # This seems like it should be more complex than an if with "pass"es, + # but it's not. The break just reroutes the "if" path: instead of + # going to the end of the loop and back up top, it goes straight back + # up. + assert complexity( + """ + for x in y: + if x: + break + """).score == 3 + + def test_break_statements_in_for_loops_with_else_clauses(self): + # A "break" in a for loop skips the "else". My intuitive + # interpretation is that this should increase CC by one. However, it's + # basically a GOTO, and GOTOs don't increase the CC. Drawing the graph + # out seems to confirm that a "break" with an "else" does not add a + # path. + assert complexity( + """ + for x in y: + if x: + break + else: + pass + """).score == 3 + + def test_continue_statement_in_for_loop(self): + assert complexity( + """ + for x in y: + if x: + continue + """).score == 3 + + +# These are basically identical to the "for" loop tests, but abstracting them +# to remove the duplication would be just as long and more confusing. +class describe_while_loops: + def test_while_loops(self): + assert complexity( + """ + while x: 1 + # implicit else + """).score == 2 + + def test_else_clauses_on_while_loops(self): + assert complexity( + """ + while x: 1 + else: 2 + """).score == 2 + + def test_child_nodes_of_while_loops(self): + assert complexity( + """ + while x: + if x: 1 + else: 2 + # implicit else + """).score == 3 + + def test_child_nodes_in_while_loop_else_clauses(self): + assert complexity( + """ + while x: 1 + else: + if x: 2 + else: 3 + """).score == 3 + + def test_break_statements_in_while_loops(self): + # See discussion for "for" loops above. + assert complexity( + """ + while x: + if x: + break + """).score == 3 + + def test_break_statements_in_while_loops_with_else_clauses(self): + # See discussion for for loops above. + assert complexity( + """ + while x: + if x: + break + else: + pass + """).score == 3 + + def test_continue_statement_in_while_loop(self): + assert complexity( + """ + while x: + if x: + continue + """).score == 3 + diff --git a/bundle/pycomplexity/autoload/tests/test_scoped_objects.py b/bundle/pycomplexity/autoload/tests/test_scoped_objects.py new file mode 100644 index 0000000..3eba3be --- /dev/null +++ b/bundle/pycomplexity/autoload/tests/test_scoped_objects.py @@ -0,0 +1,163 @@ +from tests.utils import complexity + + +class describe_modules: + def test_that_they_are_scored(self): + assert complexity( + """ + a if a else a + """).results.named('').score == 2 + assert complexity( + """ + 0 if x else 1 if y else 2 + """).results.named('').score == 3 + + def test_that_they_know_their_names(self): + assert complexity("").results.named('').name == '' + + def test_that_they_know_their_line_range(self): + stats = complexity("").results.named('') + assert stats.start_line == 1 + assert stats.end_line == 1 + + stats = complexity( + """ + a + """).results.named('') + print '-%s-' % ( + """ + a + """) + assert stats.start_line == 1 + assert stats.end_line == 3 + + def test_module_with_function_in_it(self): + assert complexity( + """ + a if a else a + def foo(): + a if a else a + a if a else a + """).results.named('').score == 3 + + +class describe_functions: + def test_that_they_are_scored(self): + assert complexity( + """ + def foo(): + 0 if x else 1 + """).results.named('foo').score == 2 + assert complexity( + """ + def foo(): + 0 if x else 1 if y else 2 + """).results.named('foo').score == 3 + + def test_that_they_know_their_names(self): + assert complexity( + """ + def foo(): pass + """).results.named('foo').name == 'foo' + + def test_that_they_know_their_line_range(self): + stats = complexity("def foo(): pass").results.named('foo') + assert stats.start_line == 1 + assert stats.end_line == 1 + + stats = complexity( + """ + def foo(): pass + """).results.named('foo') + assert stats.start_line == 2 + assert stats.end_line == 2 + + +class describe_classes: + def test_that_they_are_scored(self): + assert complexity( + """ + class Foo: + 0 if x else 1 + """).results.named('Foo').score == 2 + assert complexity( + """ + class Foo: + 0 if x else 1 if y else 2 + """).results.named('Foo').score == 3 + + def test_that_they_know_their_names(self): + assert complexity( + """ + class Foo: pass + """).results.named('Foo').name == 'Foo' + + def test_that_they_know_their_line_range(self): + stats = complexity("class Foo: pass").results.named('Foo') + assert stats.start_line == 1 + assert stats.end_line == 1 + + stats = complexity( + """ + class Foo: + pass + """).results.named('Foo') + assert stats.start_line == 2 + assert stats.end_line == 3 + + def test_that_they_include_code_interspersed_with_methods(self): + stats = complexity( + """ + class Foo: + 0 if x else 1 + def foo(self): pass + 0 if x else 1 + """).results.named('Foo') + assert stats.score == 3 + assert stats.end_line == 5 + + + +class describe_methods: + def test_that_they_are_scored(self): + assert complexity( + """ + class Foo: + def foo(): + 0 if x else 1 + """).results.named('Foo.foo').score == 2 + assert complexity( + """ + class Foo: + def foo(): + 0 if x else 1 if y else 2 + """).results.named('Foo.foo').score == 3 + + def test_that_they_know_their_names(self): + assert complexity( + """ + class Foo: + def foo(): pass + """).results.named('Foo.foo').name == 'Foo.foo' + + def test_that_they_know_their_line_range(self): + stats = complexity( + """ + class Foo(): + def foo(): + pass + """).results.named('Foo.foo') + assert stats.start_line == 3 + assert stats.end_line == 4 + + stats = complexity( + """ + pass + class Foo: + def foo(): + pass + pass + """).results.named('Foo.foo') + assert stats.start_line == 4 + assert stats.end_line == 6 + diff --git a/bundle/pycomplexity/autoload/tests/test_simple_statements.py b/bundle/pycomplexity/autoload/tests/test_simple_statements.py new file mode 100644 index 0000000..4511692 --- /dev/null +++ b/bundle/pycomplexity/autoload/tests/test_simple_statements.py @@ -0,0 +1,34 @@ +from tests.utils import complexity + + +class describe_simple_statements: + def test_pass(self): + assert complexity('pass').score == 1 + + def test_statement_sequence(self): + assert complexity( + """ + pass + pass + """).score == 1 + + def test_constant(self): + assert complexity("1").score == 1 + + def test_assignment(self): + assert complexity("x = 1").score == 1 + + def test_name(self): + assert complexity("a").score == 1 + + def test_sequence_of_names(self): + assert complexity( + """ + a + b + c + """).score == 1 + + def test_logical_operators(self): + assert complexity('a and b or (c or d and not e)').score == 1 + diff --git a/bundle/pycomplexity/autoload/tests/utils.py b/bundle/pycomplexity/autoload/tests/utils.py new file mode 100644 index 0000000..7118ded --- /dev/null +++ b/bundle/pycomplexity/autoload/tests/utils.py @@ -0,0 +1,8 @@ +from textwrap import dedent + +from complexity import compute_code_complexity + + +def complexity(code): + return compute_code_complexity(dedent(code)) + diff --git a/bundle/vim-pyflakes/README.mdown b/bundle/vim-pyflakes/README.mdown new file mode 100644 index 0000000..bbf4648 --- /dev/null +++ b/bundle/vim-pyflakes/README.mdown @@ -0,0 +1,38 @@ +Installation +------------ +1. Install [pyflakes](http://pypi.python.org/pypi/pyflakes/) +2. Copy the file `ftplugin/python_pyflakes.vim` to your `~/.vim/ftplugin` directory + + +Usage +----- +1. Open a Python file +2. Press `` to run `pyflakes` on it + +It shows the errors inside a quickfix window, which will allow your to quickly +jump to the error locations by simply pressing [Enter]. + + +Customization +------------- +If you don't want to use the `` key for pyflakes-checking, simply remap it to +another key. It autodetects whether it has been remapped and won't register +the `` key if so. For example, to remap it to `` instead, use: + + autocmd FileType python map :call Pyflakes() + + +Tips +---- +A tip might be to run the Pyflakes check every time you write a Python file, to +enable this, add the following line to your `.vimrc` file (thanks +[Godefroid](http://github.com/gotcha)!): + + autocmd BufWritePost *.py call Pyflakes() + + +This plugin goes well together with the following plugins: + +- [PEP8](http://github.com/nvie/vim-pep8) (Python coding style checker under ``) +- [PyUnit](http://github.com/nvie/vim-pyunit) (unit test helper under `` + and ``) diff --git a/bundle/vim-pyflakes/ftplugin/python_pyflakes.vim b/bundle/vim-pyflakes/ftplugin/python_pyflakes.vim new file mode 100644 index 0000000..b363a7a --- /dev/null +++ b/bundle/vim-pyflakes/ftplugin/python_pyflakes.vim @@ -0,0 +1,74 @@ +" +" Python filetype plugin for running pyflakes +" Language: Python (ft=python) +" Maintainer: Vincent Driessen +" Version: Vim 7 (may work with lower Vim versions, but not tested) +" URL: http://github.com/nvie/vim-pyflakes +" +" Only do this when not done yet for this buffer +if exists("b:loaded_pyflakes_ftplugin") + finish +endif +let b:loaded_pyflakes_ftplugin=1 + +let s:pyflakes_cmd="/usr/local/Cellar/python/2.7/Frameworks/Python.framework/Versions/2.7/bin//pyflakes" + +if !exists("*Pyflakes()") + function Pyflakes() + if !executable(s:pyflakes_cmd) + echoerr "File " . s:pyflakes_cmd . " not found. Please install it first." + return + endif + + set lazyredraw " delay redrawing + cclose " close any existing cwindows + + " store old grep settings (to restore later) + let l:old_gfm=&grepformat + let l:old_gp=&grepprg + + " write any changes before continuing + if &readonly == 0 + update + endif + + " perform the grep itself + let &grepformat="%f:%l: %m" + let &grepprg=s:pyflakes_cmd + silent! grep! % + + " restore grep settings + let &grepformat=l:old_gfm + let &grepprg=l:old_gp + + " open cwindow + let has_results=getqflist() != [] + if has_results + execute 'belowright copen' + setlocal wrap + nnoremap c :cclose + nnoremap q :cclose + endif + + set nolazyredraw + redraw! + + if has_results == 0 + " Show OK status + hi Green ctermfg=green + echohl Green + echon "Static analysis OK" + echohl + endif + endfunction +endif + +" Add mappings, unless the user didn't want this. +" The default mapping is registered under to by default, unless the user +" remapped it already (or a mapping exists already for ) +if !exists("no_plugin_maps") && !exists("no_pyflakes_maps") + if !hasmapto('Pyflakes(') + noremap :call Pyflakes() + noremap! :call Pyflakes() + endif +endif diff --git a/plugin/minibufexpl.vim b/plugin/minibufexpl.vim new file mode 100644 index 0000000..4e78063 --- /dev/null +++ b/plugin/minibufexpl.vim @@ -0,0 +1,1838 @@ +" Mini Buffer Explorer +" +" HINT: Type zR if you don't know how to use folds +" +" Script Info and Documentation {{{ +"============================================================================= +" Copyright: Copyright (C) 2002 & 2003 Bindu Wavell +" Permission is hereby granted to use and distribute this code, +" with or without modifications, provided that this copyright +" notice is copied with it. Like anything else that's free, +" minibufexplorer.vim is provided *as is* and comes with no +" warranty of any kind, either expressed or implied. In no +" event will the copyright holder be liable for any damamges +" resulting from the use of this software. +" +" Name Of File: minibufexpl.vim +" Description: Mini Buffer Explorer Vim Plugin +" Maintainer: Bindu Wavell +" URL: http://vim.sourceforge.net/scripts/script.php?script_id=159 +" Last Change: Sunday, June 21, 2004 +" Version: 6.3.2 +" Derived from Jeff Lanzarotta's bufexplorer.vim version 6.0.7 +" Jeff can be reached at (jefflanzarotta@yahoo.com) and the +" original plugin can be found at: +" http://lanzarotta.tripod.com/vim/plugin/6/bufexplorer.vim.zip +" +" Usage: Normally, this file should reside in the plugins +" directory and be automatically sourced. If not, you must +" manually source this file using ':source minibufexplorer.vim'. +" +" You may use the default keymappings of +" +" mbe - Opens MiniBufExplorer +" +" or you may want to add something like the following +" key mapping to your _vimrc/.vimrc file. +" +" map b :MiniBufExplorer +" +" However, in most cases you won't need any key-bindings at all. +" +" is usually backslash so type "\mbe" (quickly) to open +" the -MiniBufExplorer- window. +" +" Other keymappings include: mbc to close the Explorer +" window, mbu to force the Explorer to Update and +" mbt to toggle the Explorer window; it will open if +" closed or close if open. Each of these key bindings can be +" overridden (see the notes on mbe above.) +" +" You can map these additional commands as follows: +" +" map c :CMiniBufExplorer +" map u :UMiniBufExplorer +" map t :TMiniBufExplorer +" +" NOTE: you can change the key binding used in these mappings +" so that they fit with your configuration of vim. +" +" You can also call each of these features by typing the +" following in command mode: +" +" :MiniBufExplorer " Open and/or goto Explorer +" :CMiniBufExplorer " Close the Explorer if it's open +" :UMiniBufExplorer " Update Explorer without navigating +" :TMiniBufExplorer " Toggle the Explorer window open and +" closed. +" +" To control where the new split window goes relative to the +" current window, use the setting: +" +" let g:miniBufExplSplitBelow=0 " Put new window above +" " current or on the +" " left for vertical split +" let g:miniBufExplSplitBelow=1 " Put new window below +" " current or on the +" " right for vertical split +" +" The default for this is read from the &splitbelow VIM option. +" +" By default we are now (as of 6.0.2) forcing the -MiniBufExplorer- +" window to open up at the edge of the screen. You can turn this +" off by setting the following variable in your .vimrc: +" +" let g:miniBufExplSplitToEdge = 0 +" +" If you would like a vertical explorer you can assign the column +" width (in characters) you want for your explorer window with the +" following .vimrc variable (this was introduced in 6.3.0): +" +" let g:miniBufExplVSplit = 20 " column width in chars +" +" IN HORIZONTAL MODE: +" It is now (as of 6.1.1) possible to set a maximum height for +" the -MiniBufExplorer- window. You can set the max height by +" letting the following variable in your .vimrc: +" +" let g:miniBufExplMaxSize = +" +" setting this to 0 will mean the window gets as big as +" needed to fit all your buffers. +" +" NOTE: This was g:miniBufExplMaxHeight before 6.3.0; the old +" setting is backwards compatible if you don't use MaxSize. +" +" As of 6.2.2 it is possible to set a minimum height for the +" -MiniBufExplorer- window. You can set the min height by +" letting the following variable in your .vimrc: +" +" let g:miniBufExplMinSize = +" +" NOTE: This was g:miniBufExplMinHeight before 6.3.0; the old +" setting is backwards compatible if you don't use MinSize. +" +" IN VERTICAL MODE: (as of 6.3.0) +" By default the vertical explorer has a fixed width. If you put: +" +" let g:miniBufExplMaxSize = +" +" into your .vimrc then MBE will attempt to set the width of the +" MBE window to be as wide as your widest tab. The width will not +" exceed MaxSize even if you have wider tabs. +" +" Accepting the default value of 0 for this will give you a fixed +" width MBE window. +" +" You can specify a MinSize for the vertical explorer window by +" putting the following in your .vimrc: +" +" let g:miniBufExplMinSize = +" +" This will have no effect unless you also specivy MaxSize. +" +" By default we are now (as of 6.0.1) turning on the MoreThanOne +" option. This stops the -MiniBufExplorer- from opening +" automatically until more than one eligible buffer is available. +" You can turn this feature off by setting the following variable +" in your .vimrc: +" +" let g:miniBufExplorerMoreThanOne=1 +" +" (The following enhancement is as of 6.2.2) +" Setting this to 0 will cause the MBE window to be loaded even +" if no buffers are available. Setting it to 1 causes the MBE +" window to be loaded as soon as an eligible buffer is read. You +" can also set it to larger numbers. So if you set it to 4 for +" example the MBE window wouldn't auto-open until 4 eligibles +" buffers had been loaded. This is nice for folks that don't +" want an MBE window unless they are editing more than two or +" three buffers. +" +" To enable the optional mapping of Control + Vim Direction Keys +" [hjkl] to window movement commands, you can put the following into +" your .vimrc: +" +" let g:miniBufExplMapWindowNavVim = 1 +" +" To enable the optional mapping of Control + Arrow Keys to window +" movement commands, you can put the following into your .vimrc: +" +" let g:miniBufExplMapWindowNavArrows = 1 +" +" To enable the optional mapping of and to a +" function that will bring up the next or previous buffer in the +" current window, you can put the following into your .vimrc: +" +" let g:miniBufExplMapCTabSwitchBufs = 1 +" +" To enable the optional mapping of and to mappings +" that will move to the next and previous (respectively) window, you +" can put the following into your .vimrc: +" +" let g:miniBufExplMapCTabSwitchWindows = 1 +" +" +" NOTE: If you set the ...TabSwitchBufs AND ...TabSwitchWindows, +" ...TabSwitchBufs will be enabled and ...TabSwitchWindows +" will not. +" +" As of MBE 6.3.0, you can put the following into your .vimrc: +" +" let g:miniBufExplUseSingleClick = 1 +" +" If you would like to single click on tabs rather than double +" clicking on them to goto the selected buffer. +" +" NOTE: If you use the single click option in taglist.vim you may +" need to get an updated version that includes a patch I +" provided to allow both explorers to provide single click +" buffer selection. +" +" It is possible to customize the the highlighting for the tabs in +" the MBE by configuring the following highlighting groups: +" +" MBENormal - for buffers that have NOT CHANGED and +" are NOT VISIBLE. +" MBEChanged - for buffers that HAVE CHANGED and are +" NOT VISIBLE +" MBEVisibleNormal - buffers that have NOT CHANGED and are +" VISIBLE +" MBEVisibleChanged - buffers that have CHANGED and are VISIBLE +" +" You can either link to an existing highlighting group by +" adding a command like: +" +" hi link MBEVisibleChanged Error +" +" to your .vimrc or you can specify exact foreground and background +" colors using the following syntax: +" +" hi MBEChanged guibg=darkblue ctermbg=darkblue termbg=white +" +" NOTE: If you set a colorscheme in your .vimrc you should do it +" BEFORE updating the MBE highlighting groups. +" +" If you use other explorers like TagList you can (As of 6.2.8) put: +" +" let g:miniBufExplModSelTarget = 1 +" +" into your .vimrc in order to force MBE to try to place selected +" buffers into a window that does not have a nonmodifiable buffer. +" The upshot of this should be that if you go into MBE and select +" a buffer, the buffer should not show up in a window that is +" hosting an explorer. +" +" There is a VIM bug that can cause buffers to show up without +" their highlighting. The following setting will cause MBE to +" try and turn highlighting back on (introduced in 6.3.1): +" +" let g:miniBufExplForceSyntaxEnable = 1 +" +" MBE has had a basic debugging capability for quite some time. +" However, it has not been very friendly in the past. As of 6.0.8, +" you can put one of each of the following into your .vimrc: +" +" let g:miniBufExplorerDebugLevel = 0 " MBE serious errors output +" let g:miniBufExplorerDebugLevel = 4 " MBE all errors output +" let g:miniBufExplorerDebugLevel = 10 " MBE reports everything +" +" You can also set a DebugMode to cause output to be target as +" follows (default is mode 3): +" +" let g:miniBufExplorerDebugMode = 0 " Errors will show up in +" " a vim window +" let g:miniBufExplorerDebugMode = 1 " Uses VIM's echo function +" " to display on the screen +" let g:miniBufExplorerDebugMode = 2 " Writes to a file +" " MiniBufExplorer.DBG +" let g:miniBufExplorerDebugMode = 3 " Store output in global: +" " g:miniBufExplorerDebugOutput +" +" Or if you are able to start VIM, you might just perform these +" at a command prompt right before you do the operation that is +" failing. +" +" History: Moved to end of file +" +" Known Issues: When debugging is turned on and set to output to a window, there +" are some cases where the window is opened more than once, there +" are other cases where an old debug window can be lost. +" +" Several MBE commands can break the window history so [pnw] +" might not take you to the expected window. +" +" Todo: Add the ability to specify a regexp for eligible buffers +" allowing the ability to filter out certain buffers that +" you don't want to control from MBE +" +"============================================================================= +" }}} + +" Startup Check +" +" Has this plugin already been loaded? {{{ +" +if exists('loaded_minibufexplorer') + finish +endif +let loaded_minibufexplorer = 1 +" }}} + +" Mappings and Commands +" +" MBE Keyboard Mappings {{{ +" If we don't already have keyboard mappings for MBE then create them +" +if !hasmapto('MiniBufExplorer') + map mbe MiniBufExplorer +endif +if !hasmapto('CMiniBufExplorer') + map mbc CMiniBufExplorer +endif +if !hasmapto('UMiniBufExplorer') + map mbu UMiniBufExplorer +endif +if !hasmapto('TMiniBufExplorer') + map mbt TMiniBufExplorer +endif + +" }}} +" MBE