├── .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}) --------------------------------------------------------------------------------