├── .gitignore
├── README.md
├── django-html-mode.el
├── django-mode.el
├── django-snippets.el
└── snippets
└── text-mode
├── nxml-mode
└── django-html-mode
│ ├── cssas
│ └── jsas
└── python-mode
└── django-mode
├── asset
├── feed
├── handler
├── here
├── manager
├── model
├── modelform
├── namedurl
├── sitemap
├── url
└── view
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | *.DS_Store
3 | *.elc
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Django mode for Emacs
2 |
3 | ## How to install
4 |
5 | 1. Install [yasnippet](http://code.google.com/p/yasnippet/)
6 | 2. Add something like this to your Emacs config:
7 |
8 | ```lisp
9 | (require 'django-html-mode)
10 | (require 'django-mode)
11 | (yas/load-directory "path-to/django-mode/snippets")
12 | (add-to-list 'auto-mode-alist '("\\.djhtml$" . django-html-mode))
13 | ```
14 |
15 | ## Jumping
16 | Move your cursor to a line that contains the thing you want to go and press `C-x j`.
17 | Django-mode supports jumping to:
18 |
19 | - templates, eg. `render_to_response('some.html')` will open some.html. (it supports `@render_to` from [annoying](http://bitbucket.org/offline/django-annoying), classic `render_to_response` and the new 1.3 `TemplateResponse`)
20 | - views (from urls.py), urls.py and views.py must be in the same directory (no global urls.py for all apps, it's a bad practice after all!)
21 | - models, from `Model.objects.*` or `Model(*)`, no support for `get_object_or_404(Model*` yet
22 |
23 | ## Inserting translation marks
24 | Select a string you want to translate and press `C-t`. This works in both Python and templates.
25 |
26 | ## Running management commands
27 | Check out the Django menu :)
28 | BTW, default keybindings:
29 |
30 | - `C-c m` asks for a command to run (with completion of all available commands and ido completion)
31 | - `C-c t` runs tests
32 | - `C-c s` runs syncdb
33 | - `C-c a` creates an app (asking for a name first)
34 |
35 | ## Running a make target
36 | With `M-x django-make` (`C-c M` in django-mode), you get a helm menu to choose a Makefile target. It will run from the project root (we use [helm-make](https://github.com/abo-abo/helm-make)).
37 |
--------------------------------------------------------------------------------
/django-html-mode.el:
--------------------------------------------------------------------------------
1 | ;;; django-html-mode.el --- Major mode for editing Django HTML templates
2 |
3 | ;; Author: Eduardo de Oliviera Padoan
4 | ;; Michael J. Korman
5 | ;; Török Gábor
6 | ;; Greg V
7 | ;; Unknown Original Author
8 | ;; Keywords: languages
9 |
10 | ;;; Commentary:
11 | ;;
12 | ;; This django-html-mode is mainly derived from nxml-mode.
13 |
14 | ;;; History:
15 | ;;
16 |
17 | ;; TODO: Make comment-region work with Django comments instead of HTML comments
18 |
19 | (require 'nxml-mode)
20 |
21 | ;;; Code:
22 | (defgroup django-html nil
23 | "Customizations for `django-html-mode'."
24 | :prefix "django-html-"
25 | :group 'django)
26 |
27 | (defvar django-html-mode-hook nil
28 | "List of functions to be executed on entry to `django-html-mode'.")
29 |
30 | (defvar django-html-mode-map
31 | (let ((django-html-mode-map (make-keymap)))
32 | (define-key django-html-mode-map "\C-c\C-dj" 'newline-and-indent)
33 | (define-key django-html-mode-map "\C-c\C-d]" 'django-html-close-tag)
34 | (define-key django-html-mode-map "\C-c\C-di" 'django-html-insert-tag)
35 | django-html-mode-map)
36 | "Keymap for Django major mode.")
37 |
38 | ;; if : if, if not, if A or B, if not A or B, if not A and B
39 | ;; for : for a in alist reversed
40 | ;; forloop.counter The current iteration of the loop (1-indexed)
41 | ;; forloop.counter0 The current iteration of the loop (0-indexed)
42 | ;; forloop.revcounter The number of iterations from the end of the loop
43 | ;; (1-indexed)
44 | ;; forloop.revcounter0 The number of iterations from the end of the loop
45 | ;; (0-indexed)
46 | ;; forloop.first True if this is the first time through the loop
47 | ;; forloop.last True if this is the last time through the loop
48 | ;; forloop.parentloop For nested loops, this is the loop "above" the
49 | ;; current one
50 | ;; ifequal : ifequal A B
51 | ;; comment : {% This is comment %}
52 | ;; filter : {{ name | lower }}
53 |
54 | ;; keyword-end : if, for, ifequal, block, ifnotequal, spaceless
55 | ;; keyword-3 : regroup
56 | ;; keyword-2 : for, ifequal
57 | ;; keyword-1 : if, block, extends, include, ifchanged, load, now, ssi, withratio
58 | ;; keyword-0 : else, spaceless
59 |
60 | (defconst django-html-open-block "{%"
61 | "Start keyword for template blocks.")
62 |
63 | (defconst django-html-close-block "%}"
64 | "End keyword for template blocks.")
65 |
66 | (defconst django-html-open-comment "{#"
67 | "Start keyword for template comments.")
68 |
69 | (defconst django-html-close-comment "#}"
70 | "End keyword for template comments.")
71 |
72 | (defconst django-html-open-variable "{{"
73 | "Start keyword for template variables.")
74 |
75 | (defconst django-html-close-variable "}}"
76 | "End keyword for template variables.")
77 |
78 | (defconst django-html-font-lock-keywords
79 | (append
80 | nxml-font-lock-keywords
81 |
82 | `(;; comment
83 | (,(rx (eval django-html-open-comment)
84 | (1+ space)
85 | (0+ (not (any "#")))
86 | (1+ space)
87 | (eval django-html-close-comment))
88 | . font-lock-comment-face)
89 |
90 | ;; variable font lock
91 | (,(rx (eval django-html-open-variable)
92 | (1+ space)
93 | (group (0+ (not (any "}"))))
94 | (1+ space)
95 | (eval django-html-close-variable))
96 | (1 font-lock-variable-name-face))
97 |
98 | ;; start, end keyword font lock
99 | (,(rx (group (or (eval django-html-open-block)
100 | (eval django-html-close-block)
101 | (eval django-html-open-comment)
102 | (eval django-html-close-comment)
103 | (eval django-html-open-variable)
104 | (eval django-html-close-variable))))
105 | (1 font-lock-builtin-face))
106 |
107 | ;; end prefix keyword font lock
108 | (,(rx (eval django-html-open-block)
109 | (1+ space)
110 | (group (and "end"
111 | ;; end prefix keywords
112 | (or "autoescape" "block" "blocktrans" "cache" "comment"
113 | "filter" "for" "if" "ifchanged" "ifequal"
114 | "ifnotequal" "spaceless" "trans" "with")))
115 | (1+ space)
116 | (eval django-html-close-block))
117 | (1 font-lock-keyword-face))
118 |
119 | ;; more words after keyword
120 | (,(rx (eval django-html-open-block)
121 | (1+ space)
122 | (group (or "autoescape" "block" "blocktrans" "cache" "comment"
123 | "cycle" "debug" "else" "empty" "extends" "filter" "firstof" "for"
124 | "if" "ifchanged" "ifequal" "ifnotequal" "include"
125 | "load" "now" "regroup" "spaceless" "ssi" "templatetag"
126 | "trans" "url" "widthratio" "with"))
127 |
128 | ;; TODO: is there a more beautiful way?
129 | (0+ (not (any "}")))
130 |
131 | (1+ space)
132 | (eval django-html-close-block))
133 | (1 font-lock-keyword-face))
134 |
135 | ;; TODO: if specific cases for supporting "or", "not", and "and"
136 |
137 | ;; for sepcific cases for supporting in
138 | (,(rx (eval django-html-open-block)
139 | (1+ space)
140 | "for"
141 | (1+ space)
142 |
143 | (group (1+ (or word ?_ ?.)))
144 |
145 | (1+ space)
146 | (group "in")
147 | (1+ space)
148 |
149 | (group (1+ (or word ?_ ?.)))
150 |
151 | (group (? (1+ space) "reverse"))
152 |
153 | (1+ space)
154 | (eval django-html-close-block))
155 | (1 font-lock-variable-name-face) (2 font-lock-keyword-face)
156 | (3 font-lock-variable-name-face) (4 font-lock-keyword-face)))))
157 |
158 | (defvar django-html-mode-syntax-table
159 | (let ((django-html-mode-syntax-table (make-syntax-table)))
160 | django-html-mode-syntax-table)
161 | "Syntax table for django-html-mode.")
162 |
163 | ;;; Auto-close tags
164 | (defvar django-html-closable-tags
165 | '("autoescape" "blocktrans" "block" "cache"
166 | "comment" "filter" "for" "ifchanged"
167 | "ifequal" "ifnotequal" "if" "spaceless"
168 | "with"))
169 | ;;; Non-auto close tags
170 | (defvar django-html-nonclosable-tags
171 | '("cycle" "debug" "empty" "extends" "firstof" "include"
172 | "load" "now" "regroup" "ssi" "templatetag"
173 | "url" "widthratio"))
174 |
175 | (defvar django-html-all-tags
176 | (append django-html-closable-tags django-html-nonclosable-tags))
177 |
178 | (defvar django-html-tag-re
179 | (concat
180 | django-html-open-block
181 | "\\s *\\(end\\)?\\("
182 | (mapconcat 'identity django-html-closable-tags "\\|")
183 | "\\)[^%]*"
184 | django-html-close-block))
185 |
186 | ;;;###autoload
187 | (define-derived-mode django-html-mode nxml-mode "django-html"
188 | "Major mode for editing Django html templates (.djhtml).
189 |
190 | \\{django-html-mode-map}"
191 | :group 'django-html
192 |
193 | ;; it mainly from nxml-mode font lock setting
194 | (set (make-local-variable 'font-lock-defaults)
195 | '((django-html-font-lock-keywords)
196 | nil t nil nil
197 | (font-lock-syntactic-keywords
198 | . nxml-font-lock-keywords))))
199 |
200 | (add-hook 'django-html-mode-hook (lambda () (setq indent-tabs-mode nil)))
201 |
202 | (defun django-html-find-open-tag ()
203 | "Return open tag for closed template tag.
204 |
205 | If tags are unbalanced, raise error."
206 | (if (search-backward-regexp django-html-tag-re nil t)
207 | (if (match-string 1) ; If it's an end tag
208 | (if (not (string= (match-string 2) (django-html-find-open-tag)))
209 | (error "Unmatched Django tag")
210 | (django-html-find-open-tag))
211 | (match-string 2)) ; Otherwise, return the match
212 | nil))
213 |
214 | (defun django-html-close-tag ()
215 | "Close the previously opened template tag."
216 | (interactive)
217 | (let ((open-tag (save-excursion (django-html-find-open-tag))))
218 | (if open-tag
219 | (insert
220 | (format "%s end%s %s"
221 | django-html-open-block open-tag django-html-close-block))
222 | (error "Nothing to close"))))
223 |
224 | (define-skeleton django-html-closing-template
225 | "Insert a generic template with a closing tag." nil
226 | django-html-open-block " " str " " django-html-close-block
227 | _
228 | django-html-open-block " " "end" str " " django-html-close-block)
229 |
230 | (define-skeleton django-html-nonclosing-template
231 | "Insert a generic template without a closing tag." nil
232 | django-html-open-block " " str " " django-html-close-block)
233 |
234 | (defun django-html-make-opening-tag (tag)
235 | (format "%s %s %s"
236 | django-html-open-block
237 | tag
238 | django-html-close-block))
239 |
240 | (defun django-html-make-closing-tag (tag)
241 | (django-html-make-opening-tag
242 | (concat "end" tag)))
243 |
244 | ;;;; Skeletons for inserting tags.
245 | ;; TODO: regroup tag. This has a more complicated syntax.
246 | ;; TODO: url tag. Maybe this should read URLs from the URLconf?
247 | ;; TODO: auto-complete filters.
248 |
249 | (define-skeleton django-html-autoescape-template
250 | "Insert \"autoescape\" template." nil
251 | (let ((on-or-off (if (y-or-n-p "autoescape on? ")
252 | "on" "off")))
253 | (format "%s autoescape %s %s"
254 | django-html-open-block
255 | on-or-off
256 | django-html-close-block)))
257 |
258 | (define-skeleton django-html-for-template
259 | "Insert \"for\" template." nil
260 | (format "%s for %s in %s %s"
261 | django-html-open-block
262 | (read-string "item: ")
263 | (read-string "array: ")
264 | django-html-close-block) ?\n
265 | _ ?\n
266 | (when (y-or-n-p "\"empty\" clause? ")
267 | (django-html-make-opening-tag "empty")) ?\n
268 | (django-html-make-closing-tag "for"))
269 |
270 | (define-skeleton django-html-if-template
271 | "Insert \"if\" template." nil
272 | (format "%s if %s "
273 | django-html-open-block
274 | (setq v1 (skeleton-read "condition: ")))
275 | (if (string= "" v1) -1)
276 | django-html-close-block ?\n
277 | _ ?\n
278 | (when (y-or-n-p "\"else\" clause? ")
279 | (django-html-make-opening-tag "else")) ?\n
280 | (django-html-make-closing-tag "if"))
281 |
282 | (define-skeleton django-html-ifequal-template
283 | "Insert \"ifequal\" template." nil
284 | (format "%s ifequal %s %s %s "
285 | django-html-open-block
286 | (read-string "variable 1: ")
287 | (read-string "variable 2: ")
288 | django-html-close-block) ?\n
289 | _ ?\n
290 | (when (y-or-n-p "\"else\" clause? ")
291 | (django-html-make-opening-tag "else")) ?\n
292 | (django-html-make-closing-tag "ifequal"))
293 |
294 | (define-skeleton django-html-ifnotequal-template
295 | "Insert \"ifnotequal\" template." nil
296 | (format "%s ifnotequal %s %s %s "
297 | django-html-open-block
298 | (read-string "variable 1: ")
299 | (read-string "variable 2: ")
300 | django-html-close-block) ?\n
301 | _ ?\n
302 | (when (y-or-n-p "\"else\" clause? ")
303 | (django-html-make-opening-tag "else")) ?\n
304 | (django-html-make-closing-tag "ifnotequal"))
305 |
306 | (define-skeleton django-html-include-template
307 | "Insert \"include\" template." nil
308 | (format "%s include " django-html-open-block)
309 | (read-string "template: ")
310 | " " django-html-close-block)
311 |
312 | (define-skeleton django-html-load-template
313 | "Insert \"load\" template." nil
314 | (format "%s load " django-html-open-block)
315 | (read-string "module: ")
316 | " " django-html-close-block)
317 |
318 | (define-skeleton django-html-now-template
319 | "Insert \"now\" template." nil
320 | (format "%s now " django-html-open-block)
321 | "\"" (read-string "format string: ") "\""
322 | " " django-html-close-block)
323 |
324 | (define-skeleton django-html-ssi-template
325 | "Insert \"ssi\" template." nil
326 | (format "%s ssi " django-html-open-block)
327 | (read-string "file: ")
328 | " "
329 | (if (y-or-n-p "parsed? ")
330 | "parsed ")
331 | django-html-close-block)
332 |
333 | (define-skeleton django-html-templatetag-template
334 | "Insert \"templatetag\" template." nil
335 | (format "%s templatetag " django-html-open-block)
336 | (completing-read "template tag (TAB for completion): "
337 | '("openblock" "closeblock" "openvariable"
338 | "closevariable" "openbrace" "closebrace"
339 | "opencomment" "closecomment") nil t)
340 | " "
341 | django-html-close-block)
342 |
343 | (define-skeleton django-html-widthratio-template
344 | "Insert \"widthratio\" template." nil
345 | (format "%s widthratio %s %s %s %s" django-html-open-block
346 | (read-string "given value: ")
347 | (read-string "max value: ")
348 | (read-string "constant: ")
349 | django-html-close-block))
350 |
351 | (define-skeleton django-html-with-template
352 | "Insert \"with\" template." nil
353 | (format "%s with %s as %s %s"
354 | django-html-open-block
355 | (read-string "variable: ")
356 | (read-string "alias: ")
357 | django-html-close-block)
358 | _
359 | (django-html-make-closing-tag "with"))
360 |
361 | (define-skeleton django-html-block-template
362 | "Insert \"block\" template." nil
363 | (let ((block-name (read-string "block: ")))
364 | (format "%s block %s %s"
365 | django-html-open-block
366 | block-name
367 | django-html-close-block)) ?\n
368 | _ ?\n
369 | (django-html-make-closing-tag "block"))
370 |
371 | (define-skeleton django-html-cycle-template
372 | "Insert \"cycle\" template." nil
373 | (format "%s cycle " django-html-open-block)
374 | ("item: " str " ") -1
375 | " as "
376 | (setq v1 (skeleton-read "name: "))
377 | (if (string= "" v1) -4) " " django-html-close-block)
378 |
379 | (define-skeleton django-html-extends-template
380 | "Insert \"extends\" template." nil
381 | (format "%s extends " django-html-open-block)
382 | (read-string "parent: ")
383 | " " django-html-close-block)
384 |
385 | (define-skeleton django-html-filter-template
386 | "Insert \"filter\" template." nil
387 | (format "%s filter " django-html-open-block)
388 | ("filter: " str "|") -1
389 | " " django-html-close-block)
390 |
391 | (define-skeleton django-html-firstof-template
392 | "Insert \"firstof\" template." nil
393 | (format "%s firstof " django-html-open-block)
394 | ("item: " str " ") -1
395 | " \"" (setq v1 (skeleton-read "fallback value: ")) "\""
396 | (if (string= "" v1) -3)
397 | " " django-html-close-block)
398 |
399 | (defun django-html-insert-tag ()
400 | "Prompts the user for a tag, and inserts opening and closing tags."
401 | (interactive)
402 | (let ((tag (completing-read "Tag (TAB for completion): " django-html-all-tags)))
403 | (cond ((string= tag "autoescape")
404 | (django-html-autoescape-template))
405 | ((string= tag "cycle")
406 | (django-html-cycle-template))
407 | ((string= tag "extends")
408 | (django-html-extends-template))
409 | ((string= tag "filter")
410 | (django-html-filter-template))
411 | ((string= tag "firstof")
412 | (django-html-firstof-template))
413 | ((string= tag "for")
414 | (django-html-for-template))
415 | ((string= tag "if")
416 | (django-html-if-template))
417 | ((string= tag "ifequal")
418 | (django-html-ifequal-template))
419 | ((string= tag "ifnotequal")
420 | (django-html-ifnotequal-template))
421 | ((string= tag "include")
422 | (django-html-include-template))
423 | ((string= tag "load")
424 | (django-html-load-template))
425 | ((string= tag "now")
426 | (django-html-now-template))
427 | ((string= tag "ssi")
428 | (django-html-ssi-template))
429 | ((string= tag "templatetag")
430 | (django-html-templatetag-template))
431 | ((string= tag "widthratio")
432 | (django-html-widthratio-template))
433 | ((string= tag "with")
434 | (django-html-with-template))
435 | ((string= tag "block")
436 | (django-html-block-template))
437 | ((member tag django-html-closable-tags)
438 | (django-html-closing-template tag))
439 | (t
440 | (django-html-nonclosing-template tag)))))
441 |
442 | (easy-menu-define django-html-menu django-html-mode-map "Django-HTML menu"
443 | '("Django-HTML"
444 | ["Insert Tag" django-html-insert-tag t]
445 | ["Auto-close Tag" django-html-close-tag t]
446 | ("Tag Templates"
447 | ["autoescape" django-html-autoescape-template t]
448 | ["block" django-html-block-template t]
449 | ["cycle" django-html-cycle-template t]
450 | ["extends" django-html-extends-template t]
451 | ["filter" django-html-filter-template t]
452 | ["firstof" django-html-firstof-template t]
453 | ["for" django-html-for-template t]
454 | ["if" django-html-if-template t]
455 | ["ifequal" django-html-ifequal-template t]
456 | ["ifnotequal" django-html-ifnotequal-template t]
457 | ["include" django-html-include-template t]
458 | ["load" django-html-load-template t]
459 | ["now" django-html-now-template t]
460 | ["ssi" django-html-ssi-template t]
461 | ["templatetag" django-html-templatetag-template t]
462 | ["widthratio" django-html-widthratio-template t]
463 | ["with" django-html-with-template t])))
464 |
465 | (easy-menu-add django-html-menu django-html-mode-map)
466 |
467 | ;; A part from http://garage.pimentech.net/libcommonDjango_django_emacs/
468 | ;; Modified a little
469 | (defun django-insert-trans (from to &optional buffer)
470 | (interactive "*r")
471 | (save-excursion
472 | (save-restriction
473 | (narrow-to-region from to)
474 | (goto-char from)
475 | (iso-iso2sgml from to)
476 | (insert "{% trans \"")
477 | (goto-char (point-max))
478 | (insert "\" %}")
479 | (point-max))))
480 | (define-key django-html-mode-map (kbd "C-t") 'django-insert-trans)
481 |
482 | ;;;###autoload
483 | (add-to-list 'auto-mode-alist '("\\.djhtml$" . django-html-mode))
484 |
485 | ;; This part ends here
486 |
487 | (provide 'django-html-mode)
488 |
489 | ;;; django-html-mode.el ends here
490 |
--------------------------------------------------------------------------------
/django-mode.el:
--------------------------------------------------------------------------------
1 | ;;; django-mode.el --- Major mode for Django web framework.
2 |
3 | ;; Copyright (C) 2010-2012 Greg V
4 |
5 | ;; Author: Greg V
6 | ;; Keywords: languages
7 | ;; Package-Requires: ((projectile "0") (s "0") (helm-make "0"))
8 |
9 | ;; This file is NOT part of GNU Emacs.
10 |
11 | ;; Licensed under the Apache License, Version 2.0 (the "License");
12 | ;; you may not use this file except in compliance with the License.
13 | ;; You may obtain a copy of the License at
14 | ;;
15 | ;; http://www.apache.org/licenses/LICENSE-2.0
16 | ;;
17 | ;; Unless required by applicable law or agreed to in writing, software
18 | ;; distributed under the License is distributed on an "AS IS" BASIS,
19 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | ;; See the License for the specific language governing permissions and
21 | ;; limitations under the License.
22 |
23 | ;;; Code:
24 |
25 | (condition-case nil
26 | (require 'python)
27 | (error
28 | (require 'python-mode)))
29 |
30 | (require 'helm-make)
31 | (require 'projectile)
32 | (require 's)
33 |
34 | (defvar django-template-regexp ".*\\(@render_to\\|render_to_response\\|TemplateResponse\\)(['\"]\\([^'\"]*\\)['\"].*
35 | ?")
36 |
37 | (defvar django-view-regexp ".*(.+, ?['\"]\\([^'\",]+\\)['\"].*).*
38 | ?")
39 |
40 | (defvar django-model-regexp "^[^.]* \\([^.,]+\\)\\(.objects\\|(\\).*
41 | ?")
42 |
43 | (defun django-root (&optional dir home)
44 | ;; Copied from Rinari and modified accordingly.
45 | ;TODO: replace straight with projectile-project-root ?
46 | (or dir (setq dir default-directory))
47 | (if (and (file-exists-p (expand-file-name "settings.py" dir))
48 | (file-exists-p (expand-file-name "manage.py" dir)))
49 | dir
50 | (let ((new-dir (expand-file-name (file-name-as-directory "..") dir)))
51 | ;; regexp to match windows roots, tramp roots, or regular posix roots
52 | (unless (string-match "\\(^[[:alpha:]]:/$\\|^/[^\/]+:\\|^/$\\)" dir)
53 | (django-root new-dir)))))
54 |
55 | (defun django-jump-to-template ()
56 | (interactive)
57 | (let ((fname (replace-regexp-in-string django-template-regexp "\\2" (thing-at-point 'line))))
58 | (let ((projfname (concat (django-root) "templates/" fname))
59 | (appfname (concat default-directory "templates/" fname)))
60 | (if (file-exists-p appfname)
61 | (find-file appfname)
62 | (find-file projfname)))))
63 |
64 | (defun django-jump-to-view ()
65 | (interactive)
66 | (let ((vname (replace-regexp-in-string django-view-regexp "\\1" (thing-at-point 'line))))
67 | (find-file (concat default-directory "views.py"))
68 | (set-text-properties 0 (length vname) nil vname)
69 | (re-search-forward (concat vname "(.*):
70 | "))))
71 |
72 | (defun django-jump-to-model ()
73 | (interactive)
74 | (let ((mname (replace-regexp-in-string django-model-regexp "\\1" (thing-at-point 'line))))
75 | (find-file (concat default-directory "models.py"))
76 | (re-search-forward (concat mname "(.*):
77 | "))))
78 |
79 | (defun django-jump ()
80 | (interactive)
81 | (if (string-match django-template-regexp (thing-at-point 'line))
82 | (django-jump-to-template))
83 | (if (string-match django-view-regexp (thing-at-point 'line))
84 | (django-jump-to-view))
85 | (if (string-match django-model-regexp (thing-at-point 'line))
86 | (django-jump-to-model)))
87 |
88 |
89 | (defun django-python-command ()
90 | (if (boundp 'python-shell-interpreter)
91 | (concat python-shell-interpreter " " python-shell-interpreter-args)
92 | (mapconcat 'identity (cons python-python-command python-python-command-args) " ")))
93 |
94 | (defun django-get-commands ()
95 | "Get a list of all available commands, including the ones coming from
96 | extensions, by reading the output of manage.py -h"
97 | (let* ((help-output (shell-command-to-string (concat "python " (projectile-project-root) "manage.py -h")))
98 | (commands-block
99 | (with-temp-buffer
100 | (progn
101 | (insert help-output)
102 | (beginning-of-buffer)
103 | ;; Delete help header
104 | (delete-region (point) (search-forward "Available subcommands:" nil nil nil))
105 | ;; Delete section names, in brackets like [auth]
106 | (beginning-of-buffer)
107 | (save-excursion
108 | (replace-regexp "\\[.*\\]" ""))
109 | (buffer-string))))
110 | (commands-list (s-split "\n" commands-block))
111 | (commands-list (-remove (lambda (x) (string= x "")) commands-list))
112 | (commands-list (mapcar (lambda (x) (s-trim x)) commands-list)))
113 | (sort commands-list 'string-lessp)))
114 |
115 | (defun django-manage (command)
116 | "Ask for a command, with ido completion. We can edit it after the
117 | choice. Run with python-shell-interpreter."
118 | (interactive (list (ido-completing-read "Command... " (django-get-commands) nil nil)))
119 | ;; Edit the command.
120 | (let ((command (read-shell-command "Run command like this: " command)))
121 | (compile (concat (django-python-command) " " (django-root) "manage.py " command))))
122 |
123 | (defun django-make ()
124 | "Ask for a make target with helm, run it from project's root."
125 | (interactive)
126 | (call-interactively 'helm-make-projectile))
127 |
128 | (defun django-syncdb ()
129 | (interactive)
130 | (django-manage "syncdb --noinput"))
131 |
132 | (defun django-flush ()
133 | (interactive)
134 | (django-manage "flush --noinput"))
135 |
136 | (defun django-reset (name)
137 | (interactive "sReset app:")
138 | (django-manage (concat "reset " name " --noinput")))
139 |
140 | (defun django-migrate ()
141 | (interactive)
142 | (django-manage "migrate"))
143 |
144 | (defun django-assets-rebuild ()
145 | (interactive)
146 | (django-manage "assets rebuild"))
147 |
148 | (defun django-startapp (name)
149 | (interactive "sName:")
150 | (django-manage (concat "startapp " name)))
151 |
152 | (defun django-makemessages ()
153 | (interactive)
154 | (django-manage "makemessages --all --symlinks"))
155 |
156 | (defun django-compilemessages ()
157 | (interactive)
158 | (django-manage "compilemessages"))
159 |
160 | (defun django-test (name)
161 | (interactive "sTest app:")
162 | (django-manage (concat "test " name)))
163 |
164 | (defun django-shell ()
165 | (interactive)
166 | (term (concat (django-python-command) " " (django-root) "manage.py shell")))
167 |
168 | (defun django-dbshell ()
169 | (interactive)
170 | (term (concat (django-python-command) " " (django-root) "manage.py dbshell")))
171 |
172 | (defun django-insert-transpy (from to &optional buffer)
173 | ;; From http://garage.pimentech.net/libcommonDjango_django_emacs/
174 | ;; Modified a little
175 | (interactive "*r")
176 | (save-excursion
177 | (save-restriction
178 | (narrow-to-region from to)
179 | (goto-char from)
180 | (iso-iso2sgml from to)
181 | (insert "_(")
182 | (goto-char (point-max))
183 | (insert ")")
184 | (point-max))))
185 |
186 | ;;;###autoload
187 | (define-derived-mode django-mode python-mode "Django" "Major mode for Django web framework.")
188 | (define-key django-mode-map (kbd "C-t") 'django-insert-transpy)
189 | (define-key django-mode-map (kbd "C-x j") 'django-jump)
190 | (define-key django-mode-map (kbd "C-c m") 'django-manage)
191 | (define-key django-mode-map (kbd "C-c t") 'django-test)
192 | (define-key django-mode-map (kbd "C-c s") 'django-syncdb)
193 | (define-key django-mode-map (kbd "C-c a") 'django-startapp)
194 | (define-key django-mode-map (kbd "C-c M") 'django-make)
195 | (add-hook 'django-mode-hook
196 | (lambda ()
197 | (font-lock-add-keywords nil
198 | '(("\\<\\(django\\|models\\|forms\\|request\\)\\>" 1 font-lock-type-face)
199 | ("\\<\\(get_list_or_404\\|get_object_or_404\\|redirect\\|render_to_response\\)\\>" . font-lock-builtin-face))
200 | )))
201 |
202 | (easy-menu-define django-menu django-mode-map "Django menu"
203 | '("Django"
204 | ["Start an app" django-startapp t]
205 | ["Run tests" django-test t]
206 | ["Sync database" django-syncdb t]
207 | ["Flush database" django-flush t]
208 | ["Reset database" django-reset t]
209 | ["Run database migrations" django-migrate t]
210 | ["Rebuild assets" django-assets-rebuild t]
211 | ["Make translations" django-makemessages t]
212 | ["Compile translations" django-compilemessages t]
213 | ["Open Python shell" django-shell t]
214 | ["Open database shell" django-dbshell t]
215 | ["Run other command" django-manage t]
216 | "-"
217 | ["Jump" django-jump t]
218 | ["Insert translation mark" django-insert-transpy t]))
219 |
220 | (easy-menu-add django-menu django-mode-map)
221 |
222 | ;;;###autoload
223 | (add-to-list 'auto-mode-alist '("\\<\\(models\\|views\\|handlers\\|feeds\\|sitemaps\\|admin\\|context_processors\\|urls\\|settings\\|tests\\|assets\\|forms\\)\\.py\\'" . django-mode))
224 |
225 | (provide 'django-mode)
226 | ;; django-mode.el ends here
227 |
--------------------------------------------------------------------------------
/django-snippets.el:
--------------------------------------------------------------------------------
1 | ;;; django-snippets.el --- Yasnippets for django
2 |
3 | ;; Copyright (C) 2013 Yasuyuki Oka
4 |
5 | ;; Author: Yasuyuki Oka
6 | ;; URL: https://github.com/myfreeweb/django-mode
7 | ;; Package-Requires: ((yasnippet "0.8.0"))
8 |
9 | ;; This program is free software; you can redistribute it and/or modify
10 | ;; it under the terms of the GNU General Public License as published by
11 | ;; the Free Software Foundation, either version 3 of the License, or
12 | ;; (at your option) any later version.
13 |
14 | ;; This program is distributed in the hope that it will be useful,
15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | ;; GNU General Public License for more details.
18 |
19 | ;; You should have received a copy of the GNU General Public License
20 | ;; along with this program. If not, see .
21 |
22 | ;;; Commentary:
23 |
24 | ;;; Code:
25 |
26 | (defvar django-snippets-dir
27 | (file-name-directory (or (buffer-file-name) load-file-name)))
28 |
29 | ;;;###autoload
30 | (defun django-snippets-initialize ()
31 | (let ((snip-dir (expand-file-name "snippets" django-snippets-dir)))
32 | (add-to-list 'yas-snippet-dirs snip-dir t)
33 | (yas-load-directory snip-dir)))
34 |
35 | ;;;###autoload
36 | (eval-after-load 'yasnippet
37 | '(django-snippets-initialize))
38 |
39 | (require 'yasnippet)
40 |
41 | (provide 'django-snippets)
42 |
43 | ;;; django-snippets.el ends here
44 |
--------------------------------------------------------------------------------
/snippets/text-mode/nxml-mode/django-html-mode/cssas:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # key: cssas
3 | # name: cssas
4 | # contributor: MyFreeWeb
5 | # --
6 | {% assets "${1:css_main}" %}{% endassets %}
--------------------------------------------------------------------------------
/snippets/text-mode/nxml-mode/django-html-mode/jsas:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # key: jsas
3 | # name: jsas
4 | # contributor: MyFreeWeb
5 | # --
6 | {% assets "${1:js_main}" %}{% endassets %}
--------------------------------------------------------------------------------
/snippets/text-mode/python-mode/django-mode/asset:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # key: asset
3 | # name: asset
4 | # contributor: MyFreeWeb
5 | # --
6 | register('${1:js_main}', Bundle(${2:'jquery-1.4.1.min.js',}), filters='${3:jsmin}', output='${4:bundle.js}')
--------------------------------------------------------------------------------
/snippets/text-mode/python-mode/django-mode/feed:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # key: feed
3 | # name : feed
4 | # contributor : MyFreeWeb
5 | # --
6 | class ${1:MyFeed}(Feed):
7 | title = u"${2: My Feed}"
8 | link = "${3:/feeds/rss}"
9 | description = u"${4:This is a feed}"
10 | author_name = "${5:Vasily Pupkin}"
11 | author_email = "${6:me@example.com}"
12 |
13 | def items(self):
14 | return ${7:MyModel}.objects.order_by('-id')
--------------------------------------------------------------------------------
/snippets/text-mode/python-mode/django-mode/handler:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # key: handler
3 | # name: view
4 | # contributor: MyFreeWeb
5 | # --
6 | class ${1:MyHandler}(BaseHandler):
7 | allowed_methods = ('GET', 'POST', 'PUT', 'DELETE')
8 | model = ${2:MyModel}
9 |
10 | @throttle(${3:60, 60})
11 | def read(${4:self, request}):
12 | return rc.ALL_OK
13 |
14 | @throttle($3)
15 | def create($4):
16 | return rc.CREATED
17 |
18 | @throttle($3)
19 | def update($4):
20 | return rc.ALL_OK
21 |
22 | @throttle($3)
23 | def delete($4):
24 | return rc.DELETED
--------------------------------------------------------------------------------
/snippets/text-mode/python-mode/django-mode/here:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # key: here
3 | # name: here
4 | # contributor: MyFreeWeb
5 | # --
6 | import os
7 | here = lambda *x: os.path.join(os.path.abspath(os.path.dirname(__file__)), *x)
8 |
--------------------------------------------------------------------------------
/snippets/text-mode/python-mode/django-mode/manager:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # key: manager
3 | # name: manager
4 | # contributor: Brandon Height
5 | # --
6 | class ${1:MyModelManager}(models.Manager):
7 | def get_query_set(self):
8 | return super(${1:MyModelManager}, self).get_query_set().filter()
9 |
--------------------------------------------------------------------------------
/snippets/text-mode/python-mode/django-mode/model:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # key: model
3 | # name: model
4 | # contributor: MyFreeWeb
5 | # --
6 | class ${1:MyModel}(models.Model):
7 | name = models.CharField(max_length=256)
8 |
9 | def __unicode__(self):
10 | return self.name
11 |
12 | @models.permalink
13 | def get_absolute_url(self):
14 | pass
--------------------------------------------------------------------------------
/snippets/text-mode/python-mode/django-mode/modelform:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # key: modelform
3 | # name: modelform
4 | # contributor: Brandon Height
5 | # --
6 | class ${1:MyModelForm}(ModelForm):
7 | class Meta:
8 | model = ${2:MyModel}
9 |
--------------------------------------------------------------------------------
/snippets/text-mode/python-mode/django-mode/namedurl:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # key: namedurl
3 | # name: namedurl
4 | # contributor: Brandon Height
5 | # --
6 | url(r'${1:^page/$}', '${2:myview}', name='${3:url_name}'),
--------------------------------------------------------------------------------
/snippets/text-mode/python-mode/django-mode/sitemap:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # key: sitemap
3 | # name: sitemap
4 | # contributor: MyFreeWeb
5 | # --
6 | class ${1:MyMap}(Sitemap):
7 | changefreq = "${2:never}"
8 | priority = ${3:0.5}
9 |
10 | def items(self):
11 | return ${4:MyModel}.objects.filter()
--------------------------------------------------------------------------------
/snippets/text-mode/python-mode/django-mode/url:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # key: url
3 | # name: url
4 | # contributor: MyFreeWeb
5 | # --
6 | (r'${1:^page/$}', '${2:myview}'),
--------------------------------------------------------------------------------
/snippets/text-mode/python-mode/django-mode/view:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # key: view
3 | # name: view
4 | # contributor: MyFreeWeb
5 | # --
6 | def ${1:myview}(request):
7 | ${2:obj} = ${3:MyModel}.objects.filter()
8 | return render_to_response('${4:template.html}', {'${5:object}': $2})
--------------------------------------------------------------------------------