fix python keybindings, auto cleanup python imports on save
[emacs-init.git] / python / init_python.el
1 (autoload 'python-mode "python-mode" "Python Mode." t)
2 (add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode))
3 (add-to-list 'interpreter-mode-alist '("python" . python-mode))
4 (require 'python-mode)
5 (add-hook 'python-mode-hook
6       (lambda ()
7         (set-variable 'py-indent-offset 4)
8         ;(set-variable 'py-smart-indentation nil)
9         (set-variable 'indent-tabs-mode nil)
10         (define-key py-mode-map (kbd "RET") 'newline-and-indent)
11         ;(define-key py-mode-map [tab] 'yas/expand)
12         ;(setq yas/after-exit-snippet-hook 'indent-according-to-mode)
13         ;(smart-operator-mode-on)
14         ))
15 ;; pymacs
16 (autoload 'pymacs-apply "pymacs")
17 (autoload 'pymacs-call "pymacs")
18 (autoload 'pymacs-eval "pymacs" nil t)
19 (autoload 'pymacs-exec "pymacs" nil t)
20 (autoload 'pymacs-load "pymacs" nil t)
21 ;;(eval-after-load "pymacs"
22 ;;  '(add-to-list 'pymacs-load-path YOUR-PYMACS-DIRECTORY"))
23 (pymacs-load "ropemacs" "rope-")
24 (setq ropemacs-enable-autoimport t)
25
26 ;; M-/               rope-code-assist
27 ;; C-c g             rope-goto-definition
28 ;; C-c d             rope-show-doc
29 ;; C-c f             rope-find-occurrences
30 ;; M-?               rope-lucky-assist
31
32 (define-key ropemacs-local-keymap "\M-/" 'hippie-expand)
33
34 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
35 ;;; Auto-completion
36 ;;;  Integrates:
37 ;;;   1) Rope
38 ;;;   2) Yasnippet
39 ;;;   all with AutoComplete.el
40 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
41 (defun prefix-list-elements (list prefix)
42   (let (value)
43     (nreverse
44      (dolist (element list value)
45       (setq value (cons (format "%s%s" prefix element) value))))))
46 (defvar ac-source-rope
47   '((candidates
48      . (lambda ()
49          (prefix-list-elements (rope-completions) ac-target))))
50   "Source for Rope")
51 (defun ac-python-find ()
52   "Python `ac-find-function'."
53   (require 'thingatpt)
54   (let ((symbol (car-safe (bounds-of-thing-at-point 'symbol))))
55     (if (null symbol)
56         (if (string= "." (buffer-substring (- (point) 1) (point)))
57             (point)
58           nil)
59       symbol)))
60 (defun ac-python-candidate ()
61   "Python `ac-candidates-function'"
62   (let (candidates)
63     (dolist (source ac-sources)
64       (if (symbolp source)
65           (setq source (symbol-value source)))
66       (let* ((ac-limit (or (cdr-safe (assq 'limit source)) ac-limit))
67              (requires (cdr-safe (assq 'requires source)))
68              cand)
69         (if (or (null requires)
70                 (>= (length ac-target) requires))
71             (setq cand
72                   (delq nil
73                         (mapcar (lambda (candidate)
74                                   (propertize candidate 'source source))
75                                 (funcall (cdr (assq 'candidates source)))))))
76         (if (and (> ac-limit 1)
77                  (> (length cand) ac-limit))
78             (setcdr (nthcdr (1- ac-limit) cand) nil))
79         (setq candidates (append candidates cand))))
80     (delete-dups candidates)))
81 (add-hook 'python-mode-hook
82           (lambda ()
83                  (auto-complete-mode 1)
84                  (set (make-local-variable 'ac-sources)
85                       (append ac-sources '(ac-source-rope) '(ac-source-yasnippet)))
86                  (set (make-local-variable 'ac-find-function) 'ac-python-find)
87                  (set (make-local-variable 'ac-candidate-function) 'ac-python-candidate)
88                  (set (make-local-variable 'ac-auto-start) nil)))
89 ;;Ryan's python specific tab completion
90 (defun ryan-python-tab ()
91   ; Try the following:
92   ; 1) Do a yasnippet expansion
93   ; 2) Do a Rope code completion
94   ; 3) Do an indent
95   (interactive)
96   (if (eql (ac-start) 0)
97       (indent-for-tab-command)))
98 (defadvice ac-start (before advice-turn-on-auto-start activate)
99   (set (make-local-variable 'ac-auto-start) t))
100 (defadvice ac-cleanup (after advice-turn-off-auto-start activate)
101   (set (make-local-variable 'ac-auto-start) nil))
102 ;(define-key py-mode-map "\t" 'ryan-python-tab)
103 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
104 ;;; End Auto Completion
105 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
106 ;; Auto Syntax Error Hightlight
107 (when (load "flymake" t)
108   (defun flymake-pyflakes-init ()
109     (let* ((temp-file (flymake-init-create-temp-buffer-copy
110                        'flymake-create-temp-inplace))
111            (local-file (file-relative-name
112                         temp-file
113                         (file-name-directory buffer-file-name))))
114       (list "pyflakes" (list local-file))))
115   (add-to-list 'flymake-allowed-file-name-masks
116                '("\\.py\\'" flymake-pyflakes-init)))
117 (add-hook 'find-file-hook 'flymake-find-file-hook)
118
119 (defun py-cleanup-imports (&optional nowait)
120   (interactive)
121   (let (beg end)
122     (if (region-active-p)
123         (setq beg (region-beginning)
124               end (region-end))
125       (save-excursion
126         (goto-char (point-min))
127         (while (and (re-search-forward "^\\(import\\s-+\\|from\\s-+\\)" nil t)
128                     (looking-at "__future__")))
129         (beginning-of-line)
130         (if (not (looking-at "\\(import\\s-+\\|from\\s-+\\)"))
131             (error "No imports found"))
132         (setq beg (point))
133         (while (looking-at "\\(import\\s-+\\|from\\s-+\\)")
134           (forward-line 1))
135         (setq end (point))))
136     (sort-lines t beg end)
137     (goto-char beg)
138     (let ((end-marker (make-marker))
139           (doing-imports t)
140           (b beg))
141       (set-marker end-marker end)
142       (while (< (point) end-marker)
143         (let ((is-import (looking-at "import\\s-+"))
144               (eol-marker (save-excursion (end-of-line) (point-marker)))
145               prefix)
146           (if (and doing-imports (not is-import))
147               (progn
148                 (if (> (point) b)
149                     (progn
150                       (sort-lines nil beg (point))
151                       (setq b (point))))
152                 (setq doing-imports nil)))
153           (setq prefix (if is-import "import "
154                          (buffer-substring-no-properties
155                           (point) (re-search-forward "\\s-+import\\s-+" eol-marker t))))
156           (while (search-forward "," eol-marker t)
157             (delete-char -1)
158             (delete-horizontal-space)
159             (insert "\n" prefix))
160           (forward-line 1)))
161       (sort-lines nil b (point))
162       (if (and (not nowait) (boundp flymake-is-running))
163           (progn
164             (while flymake-is-running (sit-for .1))
165             (flymake-start-syntax-check)
166             (while flymake-is-running (sit-for .1))
167             (goto-char beg)
168             (while (< (point) end-marker)
169               (if (and (loop for ov in (overlays-at (point))
170                              thereis (flymake-overlay-p ov))
171                        (not (save-excursion (search-forward "unused"
172                                                             (save-excursion (end-of-line) (point))
173                                                             t ))))
174                   (delete-region (point)
175                                  (progn (forward-line 1) (point)))
176                 (forward-line 1))))))))
177
178 (defun flyspell-py-progmode-verify ()
179   "Replacement for standard flyspell-generic-progmode-verify which
180 checks for C/C++ preproc directives. Additionally, anything after ^L
181 is ignored (Those are the file local variables and local words)."
182   (let ((f (get-text-property (point) 'face)))
183     (and (memq f flyspell-prog-text-faces)
184          (not (save-excursion
185                 (beginning-of-line)
186                 (looking-at "#!")))
187          (not (let ((l (max (point-min) (- (point-max) 4096))))
188                 (and (< l (point))
189                      (save-excursion (search-backward "\f" l t)))))
190          (not (let* ((pos (python-in-string/comment))
191                      (c (and pos (char-after pos))))
192                 (and pos (not (save-excursion
193                                 (goto-char pos)
194                                 (beginning-of-line)
195                                 (looking-at (concat "^\\s-*[uUrR]?" (regexp-quote (make-string 3 c))))))))))))
196
197 (defun flyspell-py-mode ()
198   "Turn on `flyspell-mode` for comments and multi-line strings"
199   (interactive)
200   (setq flyspell-generic-check-word-p 'flyspell-py-progmode-verify)
201   (flyspell-mode t))
202
203 (provide 'init_python)