Add django-mode package

This commit is contained in:
Gergely Polonkai 2016-06-29 09:23:50 +02:00
parent 82dcd249e1
commit 1158f795c5
4 changed files with 727 additions and 0 deletions

View File

@ -0,0 +1,489 @@
;;; django-html-mode.el --- Major mode for editing Django HTML templates
;; Author: Eduardo de Oliviera Padoan <edcrypt@gmail.com>
;; Michael J. Korman <mike@mkorman.org>
;; Török Gábor <gabor@20y.hu>
;; Greg V <floatboth@me.com>
;; Unknown Original Author
;; Keywords: languages
;;; Commentary:
;;
;; This django-html-mode is mainly derived from nxml-mode.
;;; History:
;;
;; TODO: Make comment-region work with Django comments instead of HTML comments
(require 'nxml-mode)
;;; Code:
(defgroup django-html nil
"Customizations for `django-html-mode'."
:prefix "django-html-"
:group 'django)
(defvar django-html-mode-hook nil
"List of functions to be executed on entry to `django-html-mode'.")
(defvar django-html-mode-map
(let ((django-html-mode-map (make-keymap)))
(define-key django-html-mode-map "\C-c\C-dj" 'newline-and-indent)
(define-key django-html-mode-map "\C-c\C-d]" 'django-html-close-tag)
(define-key django-html-mode-map "\C-c\C-di" 'django-html-insert-tag)
django-html-mode-map)
"Keymap for Django major mode.")
;; if : if, if not, if A or B, if not A or B, if not A and B
;; for : for a in alist reversed
;; forloop.counter The current iteration of the loop (1-indexed)
;; forloop.counter0 The current iteration of the loop (0-indexed)
;; forloop.revcounter The number of iterations from the end of the loop
;; (1-indexed)
;; forloop.revcounter0 The number of iterations from the end of the loop
;; (0-indexed)
;; forloop.first True if this is the first time through the loop
;; forloop.last True if this is the last time through the loop
;; forloop.parentloop For nested loops, this is the loop "above" the
;; current one
;; ifequal : ifequal A B
;; comment : {% This is comment %}
;; filter : {{ name | lower }}
;; keyword-end : if, for, ifequal, block, ifnotequal, spaceless
;; keyword-3 : regroup
;; keyword-2 : for, ifequal
;; keyword-1 : if, block, extends, include, ifchanged, load, now, ssi, withratio
;; keyword-0 : else, spaceless
(defconst django-html-open-block "{%"
"Start keyword for template blocks.")
(defconst django-html-close-block "%}"
"End keyword for template blocks.")
(defconst django-html-open-comment "{#"
"Start keyword for template comments.")
(defconst django-html-close-comment "#}"
"End keyword for template comments.")
(defconst django-html-open-variable "{{"
"Start keyword for template variables.")
(defconst django-html-close-variable "}}"
"End keyword for template variables.")
(defconst django-html-font-lock-keywords
(append
nxml-font-lock-keywords
`(;; comment
(,(rx (eval django-html-open-comment)
(1+ space)
(0+ (not (any "#")))
(1+ space)
(eval django-html-close-comment))
. font-lock-comment-face)
;; variable font lock
(,(rx (eval django-html-open-variable)
(1+ space)
(group (0+ (not (any "}"))))
(1+ space)
(eval django-html-close-variable))
(1 font-lock-variable-name-face))
;; start, end keyword font lock
(,(rx (group (or (eval django-html-open-block)
(eval django-html-close-block)
(eval django-html-open-comment)
(eval django-html-close-comment)
(eval django-html-open-variable)
(eval django-html-close-variable))))
(1 font-lock-builtin-face))
;; end prefix keyword font lock
(,(rx (eval django-html-open-block)
(1+ space)
(group (and "end"
;; end prefix keywords
(or "autoescape" "block" "blocktrans" "cache" "comment"
"filter" "for" "if" "ifchanged" "ifequal"
"ifnotequal" "spaceless" "trans" "with")))
(1+ space)
(eval django-html-close-block))
(1 font-lock-keyword-face))
;; more words after keyword
(,(rx (eval django-html-open-block)
(1+ space)
(group (or "autoescape" "block" "blocktrans" "cache" "comment"
"cycle" "debug" "else" "empty" "extends" "filter" "firstof" "for"
"if" "ifchanged" "ifequal" "ifnotequal" "include"
"load" "now" "regroup" "spaceless" "ssi" "templatetag"
"trans" "url" "widthratio" "with"))
;; TODO: is there a more beautiful way?
(0+ (not (any "}")))
(1+ space)
(eval django-html-close-block))
(1 font-lock-keyword-face))
;; TODO: if specific cases for supporting "or", "not", and "and"
;; for sepcific cases for supporting in
(,(rx (eval django-html-open-block)
(1+ space)
"for"
(1+ space)
(group (1+ (or word ?_ ?.)))
(1+ space)
(group "in")
(1+ space)
(group (1+ (or word ?_ ?.)))
(group (? (1+ space) "reverse"))
(1+ space)
(eval django-html-close-block))
(1 font-lock-variable-name-face) (2 font-lock-keyword-face)
(3 font-lock-variable-name-face) (4 font-lock-keyword-face)))))
(defvar django-html-mode-syntax-table
(let ((django-html-mode-syntax-table (make-syntax-table)))
django-html-mode-syntax-table)
"Syntax table for django-html-mode.")
;;; Auto-close tags
(defvar django-html-closable-tags
'("autoescape" "blocktrans" "block" "cache"
"comment" "filter" "for" "ifchanged"
"ifequal" "ifnotequal" "if" "spaceless"
"with"))
;;; Non-auto close tags
(defvar django-html-nonclosable-tags
'("cycle" "debug" "empty" "extends" "firstof" "include"
"load" "now" "regroup" "ssi" "templatetag"
"url" "widthratio"))
(defvar django-html-all-tags
(append django-html-closable-tags django-html-nonclosable-tags))
(defvar django-html-tag-re
(concat
django-html-open-block
"\\s *\\(end\\)?\\("
(mapconcat 'identity django-html-closable-tags "\\|")
"\\)[^%]*"
django-html-close-block))
;;;###autoload
(define-derived-mode django-html-mode nxml-mode "django-html"
"Major mode for editing Django html templates (.djhtml).
\\{django-html-mode-map}"
:group 'django-html
;; it mainly from nxml-mode font lock setting
(set (make-local-variable 'font-lock-defaults)
'((django-html-font-lock-keywords)
nil t nil nil
(font-lock-syntactic-keywords
. nxml-font-lock-keywords))))
(add-hook 'django-html-mode-hook (lambda () (setq indent-tabs-mode nil)))
(defun django-html-find-open-tag ()
"Return open tag for closed template tag.
If tags are unbalanced, raise error."
(if (search-backward-regexp django-html-tag-re nil t)
(if (match-string 1) ; If it's an end tag
(if (not (string= (match-string 2) (django-html-find-open-tag)))
(error "Unmatched Django tag")
(django-html-find-open-tag))
(match-string 2)) ; Otherwise, return the match
nil))
(defun django-html-close-tag ()
"Close the previously opened template tag."
(interactive)
(let ((open-tag (save-excursion (django-html-find-open-tag))))
(if open-tag
(insert
(format "%s end%s %s"
django-html-open-block open-tag django-html-close-block))
(error "Nothing to close"))))
(define-skeleton django-html-closing-template
"Insert a generic template with a closing tag." nil
django-html-open-block " " str " " django-html-close-block
_
django-html-open-block " " "end" str " " django-html-close-block)
(define-skeleton django-html-nonclosing-template
"Insert a generic template without a closing tag." nil
django-html-open-block " " str " " django-html-close-block)
(defun django-html-make-opening-tag (tag)
(format "%s %s %s"
django-html-open-block
tag
django-html-close-block))
(defun django-html-make-closing-tag (tag)
(django-html-make-opening-tag
(concat "end" tag)))
;;;; Skeletons for inserting tags.
;; TODO: regroup tag. This has a more complicated syntax.
;; TODO: url tag. Maybe this should read URLs from the URLconf?
;; TODO: auto-complete filters.
(define-skeleton django-html-autoescape-template
"Insert \"autoescape\" template." nil
(let ((on-or-off (if (y-or-n-p "autoescape on? ")
"on" "off")))
(format "%s autoescape %s %s"
django-html-open-block
on-or-off
django-html-close-block)))
(define-skeleton django-html-for-template
"Insert \"for\" template." nil
(format "%s for %s in %s %s"
django-html-open-block
(read-string "item: ")
(read-string "array: ")
django-html-close-block) ?\n
_ ?\n
(when (y-or-n-p "\"empty\" clause? ")
(django-html-make-opening-tag "empty")) ?\n
(django-html-make-closing-tag "for"))
(define-skeleton django-html-if-template
"Insert \"if\" template." nil
(format "%s if %s "
django-html-open-block
(setq v1 (skeleton-read "condition: ")))
(if (string= "" v1) -1)
django-html-close-block ?\n
_ ?\n
(when (y-or-n-p "\"else\" clause? ")
(django-html-make-opening-tag "else")) ?\n
(django-html-make-closing-tag "if"))
(define-skeleton django-html-ifequal-template
"Insert \"ifequal\" template." nil
(format "%s ifequal %s %s %s "
django-html-open-block
(read-string "variable 1: ")
(read-string "variable 2: ")
django-html-close-block) ?\n
_ ?\n
(when (y-or-n-p "\"else\" clause? ")
(django-html-make-opening-tag "else")) ?\n
(django-html-make-closing-tag "ifequal"))
(define-skeleton django-html-ifnotequal-template
"Insert \"ifnotequal\" template." nil
(format "%s ifnotequal %s %s %s "
django-html-open-block
(read-string "variable 1: ")
(read-string "variable 2: ")
django-html-close-block) ?\n
_ ?\n
(when (y-or-n-p "\"else\" clause? ")
(django-html-make-opening-tag "else")) ?\n
(django-html-make-closing-tag "ifnotequal"))
(define-skeleton django-html-include-template
"Insert \"include\" template." nil
(format "%s include " django-html-open-block)
(read-string "template: ")
" " django-html-close-block)
(define-skeleton django-html-load-template
"Insert \"load\" template." nil
(format "%s load " django-html-open-block)
(read-string "module: ")
" " django-html-close-block)
(define-skeleton django-html-now-template
"Insert \"now\" template." nil
(format "%s now " django-html-open-block)
"\"" (read-string "format string: ") "\""
" " django-html-close-block)
(define-skeleton django-html-ssi-template
"Insert \"ssi\" template." nil
(format "%s ssi " django-html-open-block)
(read-string "file: ")
" "
(if (y-or-n-p "parsed? ")
"parsed ")
django-html-close-block)
(define-skeleton django-html-templatetag-template
"Insert \"templatetag\" template." nil
(format "%s templatetag " django-html-open-block)
(completing-read "template tag (TAB for completion): "
'("openblock" "closeblock" "openvariable"
"closevariable" "openbrace" "closebrace"
"opencomment" "closecomment") nil t)
" "
django-html-close-block)
(define-skeleton django-html-widthratio-template
"Insert \"widthratio\" template." nil
(format "%s widthratio %s %s %s %s" django-html-open-block
(read-string "given value: ")
(read-string "max value: ")
(read-string "constant: ")
django-html-close-block))
(define-skeleton django-html-with-template
"Insert \"with\" template." nil
(format "%s with %s as %s %s"
django-html-open-block
(read-string "variable: ")
(read-string "alias: ")
django-html-close-block)
_
(django-html-make-closing-tag "with"))
(define-skeleton django-html-block-template
"Insert \"block\" template." nil
(let ((block-name (read-string "block: ")))
(format "%s block %s %s"
django-html-open-block
block-name
django-html-close-block)) ?\n
_ ?\n
(django-html-make-closing-tag "block"))
(define-skeleton django-html-cycle-template
"Insert \"cycle\" template." nil
(format "%s cycle " django-html-open-block)
("item: " str " ") -1
" as "
(setq v1 (skeleton-read "name: "))
(if (string= "" v1) -4) " " django-html-close-block)
(define-skeleton django-html-extends-template
"Insert \"extends\" template." nil
(format "%s extends " django-html-open-block)
(read-string "parent: ")
" " django-html-close-block)
(define-skeleton django-html-filter-template
"Insert \"filter\" template." nil
(format "%s filter " django-html-open-block)
("filter: " str "|") -1
" " django-html-close-block)
(define-skeleton django-html-firstof-template
"Insert \"firstof\" template." nil
(format "%s firstof " django-html-open-block)
("item: " str " ") -1
" \"" (setq v1 (skeleton-read "fallback value: ")) "\""
(if (string= "" v1) -3)
" " django-html-close-block)
(defun django-html-insert-tag ()
"Prompts the user for a tag, and inserts opening and closing tags."
(interactive)
(let ((tag (completing-read "Tag (TAB for completion): " django-html-all-tags)))
(cond ((string= tag "autoescape")
(django-html-autoescape-template))
((string= tag "cycle")
(django-html-cycle-template))
((string= tag "extends")
(django-html-extends-template))
((string= tag "filter")
(django-html-filter-template))
((string= tag "firstof")
(django-html-firstof-template))
((string= tag "for")
(django-html-for-template))
((string= tag "if")
(django-html-if-template))
((string= tag "ifequal")
(django-html-ifequal-template))
((string= tag "ifnotequal")
(django-html-ifnotequal-template))
((string= tag "include")
(django-html-include-template))
((string= tag "load")
(django-html-load-template))
((string= tag "now")
(django-html-now-template))
((string= tag "ssi")
(django-html-ssi-template))
((string= tag "templatetag")
(django-html-templatetag-template))
((string= tag "widthratio")
(django-html-widthratio-template))
((string= tag "with")
(django-html-with-template))
((string= tag "block")
(django-html-block-template))
((member tag django-html-closable-tags)
(django-html-closing-template tag))
(t
(django-html-nonclosing-template tag)))))
(easy-menu-define django-html-menu django-html-mode-map "Django-HTML menu"
'("Django-HTML"
["Insert Tag" django-html-insert-tag t]
["Auto-close Tag" django-html-close-tag t]
("Tag Templates"
["autoescape" django-html-autoescape-template t]
["block" django-html-block-template t]
["cycle" django-html-cycle-template t]
["extends" django-html-extends-template t]
["filter" django-html-filter-template t]
["firstof" django-html-firstof-template t]
["for" django-html-for-template t]
["if" django-html-if-template t]
["ifequal" django-html-ifequal-template t]
["ifnotequal" django-html-ifnotequal-template t]
["include" django-html-include-template t]
["load" django-html-load-template t]
["now" django-html-now-template t]
["ssi" django-html-ssi-template t]
["templatetag" django-html-templatetag-template t]
["widthratio" django-html-widthratio-template t]
["with" django-html-with-template t])))
(easy-menu-add django-html-menu django-html-mode-map)
;; A part from http://garage.pimentech.net/libcommonDjango_django_emacs/
;; Modified a little
(defun django-insert-trans (from to &optional buffer)
(interactive "*r")
(save-excursion
(save-restriction
(narrow-to-region from to)
(goto-char from)
(iso-iso2sgml from to)
(insert "{% trans \"")
(goto-char (point-max))
(insert "\" %}")
(point-max))))
(define-key django-html-mode-map (kbd "C-t") 'django-insert-trans)
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.djhtml$" . django-html-mode))
;; This part ends here
(provide 'django-html-mode)
;;; django-html-mode.el ends here

View File

@ -0,0 +1,44 @@
;;; django-mode-autoloads.el --- automatically extracted autoloads
;;
;;; Code:
(add-to-list 'load-path (or (file-name-directory #$) (car load-path)))
;;;### (autoloads nil "django-html-mode" "django-html-mode.el" (22387
;;;;;; 29372 428700 65000))
;;; Generated autoloads from django-html-mode.el
(autoload 'django-html-mode "django-html-mode" "\
Major mode for editing Django html templates (.djhtml).
\\{django-html-mode-map}
\(fn)" t nil)
(add-to-list 'auto-mode-alist '("\\.djhtml$" . django-html-mode))
;;;***
;;;### (autoloads nil "django-mode" "django-mode.el" (22387 29372
;;;;;; 420706 182000))
;;; Generated autoloads from django-mode.el
(autoload 'django-mode "django-mode" "\
Major mode for Django web framework.
\(fn)" t nil)
(add-to-list 'auto-mode-alist '("\\<\\(models\\|views\\|handlers\\|feeds\\|sitemaps\\|admin\\|context_processors\\|urls\\|settings\\|tests\\|assets\\|forms\\)\\.py\\'" . django-mode))
;;;***
;;;### (autoloads nil nil ("django-mode-pkg.el") (22387 29372 445484
;;;;;; 219000))
;;;***
;; Local Variables:
;; version-control: never
;; no-byte-compile: t
;; no-update-autoloads: t
;; End:
;;; django-mode-autoloads.el ends here

View File

@ -0,0 +1,5 @@
(define-package "django-mode" "20150207.517" "Major mode for Django web framework." 'nil :keywords
'("languages"))
;; Local Variables:
;; no-byte-compile: t
;; End:

View File

@ -0,0 +1,189 @@
;;; django-mode.el --- Major mode for Django web framework.
;; Copyright (C) 2010-2012 Greg V
;; Author: Greg V <floatboth@me.com>
;; Keywords: languages
;; This file is NOT part of GNU Emacs.
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;;; Code:
(condition-case nil
(require 'python)
(error
(require 'python-mode)))
(defvar django-template-regexp ".*\\(@render_to\\|render_to_response\\|TemplateResponse\\)(['\"]\\([^'\"]*\\)['\"].*
?")
(defvar django-view-regexp ".*(.+, ?['\"]\\([^'\",]+\\)['\"].*).*
?")
(defvar django-model-regexp "^[^.]* \\([^.,]+\\)\\(.objects\\|(\\).*
?")
(defun django-root (&optional dir home)
;; Copied from Rinari and modified accordingly.
(or dir (setq dir default-directory))
(if (and (file-exists-p (expand-file-name "settings.py" dir))
(file-exists-p (expand-file-name "manage.py" dir)))
dir
(let ((new-dir (expand-file-name (file-name-as-directory "..") dir)))
;; regexp to match windows roots, tramp roots, or regular posix roots
(unless (string-match "\\(^[[:alpha:]]:/$\\|^/[^\/]+:\\|^/$\\)" dir)
(django-root new-dir)))))
(defun django-jump-to-template ()
(interactive)
(let ((fname (replace-regexp-in-string django-template-regexp "\\2" (thing-at-point 'line))))
(let ((projfname (concat (django-root) "templates/" fname))
(appfname (concat default-directory "templates/" fname)))
(if (file-exists-p appfname)
(find-file appfname)
(find-file projfname)))))
(defun django-jump-to-view ()
(interactive)
(let ((vname (replace-regexp-in-string django-view-regexp "\\1" (thing-at-point 'line))))
(find-file (concat default-directory "views.py"))
(set-text-properties 0 (length vname) nil vname)
(re-search-forward (concat vname "(.*):
"))))
(defun django-jump-to-model ()
(interactive)
(let ((mname (replace-regexp-in-string django-model-regexp "\\1" (thing-at-point 'line))))
(find-file (concat default-directory "models.py"))
(re-search-forward (concat mname "(.*):
"))))
(defun django-jump ()
(interactive)
(if (string-match django-template-regexp (thing-at-point 'line))
(django-jump-to-template))
(if (string-match django-view-regexp (thing-at-point 'line))
(django-jump-to-view))
(if (string-match django-model-regexp (thing-at-point 'line))
(django-jump-to-model)))
(defun django-python-command ()
(if (boundp 'python-shell-interpreter)
(concat python-shell-interpreter " " python-shell-interpreter-args)
(mapconcat 'identity (cons python-python-command python-python-command-args) " ")))
(defun django-manage (command)
(interactive "sCommand:")
(compile (concat (django-python-command) " " (django-root) "manage.py " command)))
(defun django-syncdb ()
(interactive)
(django-manage "syncdb --noinput"))
(defun django-flush ()
(interactive)
(django-manage "flush --noinput"))
(defun django-reset (name)
(interactive "sReset app:")
(django-manage (concat "reset " name " --noinput")))
(defun django-migrate ()
(interactive)
(django-manage "migrate"))
(defun django-assets-rebuild ()
(interactive)
(django-manage "assets rebuild"))
(defun django-startapp (name)
(interactive "sName:")
(django-manage (concat "startapp " name)))
(defun django-makemessages ()
(interactive)
(django-manage "makemessages --all --symlinks"))
(defun django-compilemessages ()
(interactive)
(django-manage "compilemessages"))
(defun django-test (name)
(interactive "sTest app:")
(django-manage (concat "test " name)))
(defun django-shell ()
(interactive)
(term (concat (django-python-command) " " (django-root) "manage.py shell")))
(defun django-dbshell ()
(interactive)
(term (concat (django-python-command) " " (django-root) "manage.py dbshell")))
(defun django-insert-transpy (from to &optional buffer)
;; From http://garage.pimentech.net/libcommonDjango_django_emacs/
;; Modified a little
(interactive "*r")
(save-excursion
(save-restriction
(narrow-to-region from to)
(goto-char from)
(iso-iso2sgml from to)
(insert "_(")
(goto-char (point-max))
(insert ")")
(point-max))))
;;;###autoload
(define-derived-mode django-mode python-mode "Django" "Major mode for Django web framework.")
(define-key django-mode-map (kbd "C-t") 'django-insert-transpy)
(define-key django-mode-map (kbd "C-x j") 'django-jump)
(define-key django-mode-map (kbd "C-c m") 'django-manage)
(define-key django-mode-map (kbd "C-c t") 'django-test)
(define-key django-mode-map (kbd "C-c s") 'django-syncdb)
(define-key django-mode-map (kbd "C-c a") 'django-startapp)
(add-hook 'django-mode-hook
(lambda ()
(font-lock-add-keywords nil
'(("\\<\\(django\\|models\\|forms\\|request\\)\\>" 1 font-lock-type-face)
("\\<\\(get_list_or_404\\|get_object_or_404\\|redirect\\|render_to_response\\)\\>" . font-lock-builtin-face))
)))
(easy-menu-define django-menu django-mode-map "Django menu"
'("Django"
["Start an app" django-startapp t]
["Run tests" django-test t]
["Sync database" django-syncdb t]
["Flush database" django-flush t]
["Reset database" django-reset t]
["Run database migrations" django-migrate t]
["Rebuild assets" django-assets-rebuild t]
["Make translations" django-makemessages t]
["Compile translations" django-compilemessages t]
["Open Python shell" django-shell t]
["Open database shell" django-dbshell t]
["Run other command" django-manage t]
"-"
["Jump" django-jump t]
["Insert translation mark" django-insert-transpy t]))
(easy-menu-add django-menu django-mode-map)
;;;###autoload
(add-to-list 'auto-mode-alist '("\\<\\(models\\|views\\|handlers\\|feeds\\|sitemaps\\|admin\\|context_processors\\|urls\\|settings\\|tests\\|assets\\|forms\\)\\.py\\'" . django-mode))
(provide 'django-mode)
;; django-mode.el ends here