65a3b9a9bf
The former depends on yasnippet that I don’t use (but maybe I will later).
320 lines
12 KiB
EmacsLisp
320 lines
12 KiB
EmacsLisp
;;; django-manage.el --- Django minor mode for commanding manage.py
|
|
|
|
;; Copyright (C) 2015 Daniel Gopar
|
|
|
|
;; Author: Daniel Gopar <gopardaniel@yahoo.com>
|
|
;; Package-Requires: ((hydra "0.13.2"))
|
|
;; Package-Version: 20160818.1912
|
|
;; Version: 0.1
|
|
;; Keywords: languages
|
|
|
|
;; This file is NOT part of GNU Emacs.
|
|
|
|
;; GNU Emacs is free software: you can redistribute it and/or modify
|
|
;; it under the terms of the GNU General Public License as published by
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
;; (at your option) any later version.
|
|
|
|
;; GNU Emacs is distributed in the hope that it will be useful,
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
;; GNU General Public License for more details.
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
;;; Commentary:
|
|
;;
|
|
;; Simple package to be to be able to control `manage.py', the standard
|
|
;; file that every Django project comes with. You are able to call any
|
|
;; command with `django-manage-command' plus it comes with code
|
|
;; completion so third party plugins will also be completed.
|
|
|
|
;;; Code:
|
|
|
|
(condition-case nil
|
|
(require 'python)
|
|
(error
|
|
(require 'python-mode)))
|
|
(require 'hydra)
|
|
|
|
(defcustom django-manage-shell-preference 'pyshell
|
|
"What shell to use."
|
|
:type 'symbol
|
|
:options '(eshell term pyshell)
|
|
:group 'shell)
|
|
|
|
(defcustom django-manage-server-ipaddr "127.0.0.1"
|
|
"What address Django will use when running the dev server."
|
|
:type 'string
|
|
:group 'server)
|
|
|
|
(defcustom django-manage-server-port "8000"
|
|
"What port Django will use when running the dev server."
|
|
:type 'string
|
|
:group 'server)
|
|
|
|
(defcustom django-manage-prompt-for-command nil
|
|
"When non-nil will ask for confirmation on command.
|
|
Will affect every function other than `django-manage-command'."
|
|
:type 'boolean
|
|
:group 'django-manage)
|
|
|
|
(defcustom django-manage-root ""
|
|
"The directory where 'manage.py' lives."
|
|
:type 'string
|
|
:group 'django-manage)
|
|
(make-local-variable 'django-manage-root)
|
|
|
|
(defun django-manage-root ()
|
|
"Return the root directory of Django project."
|
|
;; Check if projectile is in use, and if it is. Return root directory
|
|
(if (not (string= django-manage-root ""))
|
|
django-manage-root
|
|
(if (fboundp 'projectile-project-root)
|
|
(projectile-project-root)
|
|
;; Try looking for the directory holding 'manage.py'
|
|
(locate-dominating-file default-directory "manage.py"))))
|
|
|
|
(defun django-manage-python-command ()
|
|
"Return Python version to use with args."
|
|
(if (boundp 'python-shell-interpreter)
|
|
(concat python-shell-interpreter " " python-shell-interpreter-args)
|
|
;; For old python.el
|
|
(mapconcat 'identity (cons python-python-command python-python-command-args) " ")))
|
|
|
|
(defun django-manage-get-commands ()
|
|
"Return list of django commands."
|
|
(let ((help-output
|
|
(shell-command-to-string (concat python-shell-interpreter " "
|
|
(shell-quote-argument (django-manage-root)) "manage.py -h"))))
|
|
(setq dj-commands-str
|
|
(with-temp-buffer
|
|
(progn
|
|
(insert help-output)
|
|
(beginning-of-buffer)
|
|
(delete-region (point) (search-forward "Available subcommands:" nil nil nil))
|
|
;; cleanup [auth] and stuff
|
|
(beginning-of-buffer)
|
|
(save-excursion
|
|
(replace-regexp "\\[.*\\]" ""))
|
|
(buffer-string))))
|
|
;; get a list of commands from the output of manage.py -h
|
|
;; What would be the pattern to optimize this ?
|
|
(setq dj-commands-str (s-split "\n" dj-commands-str))
|
|
(setq dj-commands-str (-remove (lambda (x) (string= x "")) dj-commands-str))
|
|
(setq dj-commands-str (mapcar (lambda (x) (s-trim x)) dj-commands-str))
|
|
(sort dj-commands-str 'string-lessp)))
|
|
|
|
(defun django-manage-command (command &optional no-prompt)
|
|
"Allow to run any `manage.py' command.
|
|
Argument COMMAND command for django to run.
|
|
Optional Argument NO-PROMPT if non-nil will *not* ask if you wish to pass extra arguments."
|
|
;; nil nil: enable user to exit with any command. Still, he can not edit a completed choice.
|
|
(interactive (list (completing-read "Command: " (django-manage-get-commands) nil nil)))
|
|
(if (not no-prompt)
|
|
;; Now ask to edit the command. How to do the two actions at once ?
|
|
(setq command (read-shell-command "Run command like this: " command)))
|
|
(compile (concat (django-manage-python-command) " "
|
|
(shell-quote-argument (django-manage-root)) "manage.py " command)))
|
|
|
|
(defun django-manage-makemigrations (&optional app-name)
|
|
"Run \"makemigrations app-name\", will prompt for \"app-name\".
|
|
You can leave blank to simply run \"makemigrations\".
|
|
To choose arguments call `django-manage-command'.
|
|
Optional argument APP-NAME name of django app create migrations."
|
|
(interactive "sName: ")
|
|
(django-manage-command (concat "makemigrations " app-name)
|
|
(not django-manage-prompt-for-command)))
|
|
|
|
(defun django-manage-flush ()
|
|
"Run \"flush --noinput\". To choose arguments call `django-manage-command'."
|
|
(interactive)
|
|
(django-manage-command "flush --noinput"
|
|
(not django-manage-prompt-for-command)))
|
|
|
|
(defun django-manage-runserver ()
|
|
"Start the development server. To change what address and port to use,
|
|
customize `django-manage-server-ipaddr' and `django-manage-server-port'
|
|
If you want to pass arguments, then call `django-manage-command'"
|
|
(interactive)
|
|
(let ((parent-dir (file-name-base (substring (django-manage-root) 0 -1))))
|
|
(compile (concat (django-manage-python-command) " "
|
|
(shell-quote-argument (django-manage-root)) "manage.py runserver "
|
|
django-manage-server-ipaddr ":" django-manage-server-port))
|
|
(with-current-buffer "*compilation*"
|
|
(rename-buffer (format "*runserver[%s]*" parent-dir)))))
|
|
|
|
(defun django-manage-migrate ()
|
|
"Run \"migrate\". To choose arguments call `django-manage-command'."
|
|
(interactive)
|
|
(django-manage-command "migrate"
|
|
(not django-manage-prompt-for-command)))
|
|
|
|
(defun django-manage-assets-rebuild ()
|
|
"Run \"assets rebuild\". To choose arguments call `django-manage-command'."
|
|
(interactive)
|
|
(django-manage-command "assets rebuild"
|
|
(not django-manage-prompt-for-command)))
|
|
|
|
(defun django-manage-startapp (name)
|
|
"Run \"startapp name\". Will prompt for name of app.
|
|
To choose arguments call `django-manage-command'.
|
|
Argument NAME name of app to create."
|
|
(interactive "sName:")
|
|
(django-manage-command (concat "startapp " name)
|
|
(not django-manage-prompt-for-command)))
|
|
|
|
(defun django-manage-makemessages ()
|
|
"Run \"makemessages --all --symlinks\".
|
|
To pass arguments call `django-manage-command'."
|
|
(interactive)
|
|
(django-manage-command "makemessages --all --symlinks"
|
|
(not django-manage-prompt-for-command)))
|
|
|
|
(defun django-manage-compilemessages ()
|
|
"Run \"compilemessages\". To pass arguments call `django-manage-command'."
|
|
(interactive)
|
|
(django-manage-command "compilemessages"
|
|
(not django-manage-prompt-for-command)))
|
|
|
|
(defun django-manage-test (name)
|
|
"Run \"test name\". Will prompt for Django app name to test.
|
|
To pass arguments call `django-manage-command'.
|
|
Argument NAME name of django app to test."
|
|
(interactive "sTest app:")
|
|
(django-manage-command (concat "test " name)
|
|
(not django-manage-prompt-for-command)))
|
|
|
|
(defun django-manage--prep-shell (pref-shell)
|
|
"Prepare the shell with users preference.
|
|
Argument PREF-SHELL users shell of choice"
|
|
;; If a preexisting shell buffer exists return that one. If not create it
|
|
(let* ((parent-dir (file-name-base (substring (django-manage-root) 0 -1)))
|
|
(default-directory (django-manage-root))
|
|
(buffer-shell-name
|
|
(format (if (string= pref-shell "shell") "*Django Shell[%s]*" "*Django DBshell[%s]*") parent-dir)))
|
|
;; If it exists return it
|
|
(if (get-buffer buffer-shell-name)
|
|
(switch-to-buffer buffer-shell-name)
|
|
;; Shell didn't exist, so let's create it
|
|
(if (eq 'term django-manage-shell-preference)
|
|
(term (concat (django-manage-python-command) " "
|
|
(shell-quote-argument (django-manage-root)) "manage.py " pref-shell)))
|
|
(if (eq 'eshell django-manage-shell-preference)
|
|
(progn
|
|
(unless (get-buffer eshell-buffer-name)
|
|
(eshell))
|
|
(insert (concat (django-manage-python-command) " "
|
|
(shell-quote-argument (django-manage-root)) "manage.py " pref-shell))
|
|
(eshell-send-input)))
|
|
(if (eq 'pyshell django-manage-shell-preference)
|
|
(let ((setup-code "os.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"%s.settings\")")
|
|
(cmd ";from django.core.management import execute_from_command_line")
|
|
(exe (if (string= pref-shell "shell")
|
|
";import django;django.setup()"
|
|
(format ";execute_from_command_line(['manage.py', '%s'])" pref-shell))))
|
|
(run-python (python-shell-parse-command))
|
|
(python-shell-send-string (concat (format setup-code parent-dir) cmd exe))
|
|
(switch-to-buffer (python-shell-get-buffer))))
|
|
(rename-buffer buffer-shell-name))))
|
|
|
|
(defun django-manage-shell ()
|
|
"Start Python shell with Django already configured."
|
|
(interactive)
|
|
(django-manage--prep-shell "shell"))
|
|
|
|
(defun django-manage-dbshell ()
|
|
"Start Database shell."
|
|
(interactive)
|
|
(django-manage--prep-shell "dbshell"))
|
|
|
|
(defun django-manage-insert-transpy (from to &optional buffer)
|
|
"Wraps highlighted region in _(...) for i18n.
|
|
Argument FROM start point TO wrap.
|
|
Optional argument BUFFER end point to wrap."
|
|
;; 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))))
|
|
|
|
(defhydra django-manage-hydra (:color blue
|
|
:hint nil)
|
|
"
|
|
Manage.py
|
|
--------------------------------------------------
|
|
|
|
_mm_: Enter manage.py commnand _r_: runserver _f_: Flush _t_: Run rest
|
|
_ma_: Makemigrations _sa_: Start new app _i_: Insert transpy
|
|
_mg_: Migrate _ss_: Run shell _a_: Rebuild Assets
|
|
_me_: Make messages _sd_: Run DB Shell _c_: Compile messages
|
|
|
|
_q_: Cancel
|
|
|
|
"
|
|
("mm" django-manage-command)
|
|
("ma" django-manage-makemigrations)
|
|
("mg" django-manage-migrate)
|
|
("me" django-manage-makemessages)
|
|
|
|
("r" django-manage-runserver "Start server")
|
|
("sa" django-manage-startapp)
|
|
("ss" django-manage-shell)
|
|
("sd" django-manage-dbshell)
|
|
|
|
("f" django-manage-flush)
|
|
("a" django-manage-assets-rebuild)
|
|
("c" django-manage-compilemessages)
|
|
("t" django-manage-test)
|
|
|
|
("i" django-manage-insert-transpy)
|
|
("q" nil "cancel"))
|
|
|
|
(defvar django-manage-map
|
|
(let ((map (make-keymap)))
|
|
(define-key map (kbd "C-c C-x") 'django-manage-hydra/body)
|
|
map))
|
|
|
|
(defun django-manage-setup ()
|
|
"Determine whether to start minor mode or not."
|
|
(when (and (stringp buffer-file-name)
|
|
(locate-dominating-file default-directory "manage.py"))
|
|
(django-manage)))
|
|
|
|
;;;###autoload
|
|
(define-minor-mode django-manage
|
|
"Minor mode for handling Django's manage.py"
|
|
:lighter " Manage"
|
|
:keymap django-manage-map)
|
|
|
|
(easy-menu-define django-manage-menu django-manage-map "Django menu"
|
|
'("Django"
|
|
["Start an app" django-manage-startapp t]
|
|
["Run tests" django-manage-test t]
|
|
["Make migrations" django-manage-makemigrations t]
|
|
["Flush database" django-manage-flush t]
|
|
["Runserver" django-manage-runserver t]
|
|
["Run database migrations" django-manage-migrate t]
|
|
["Rebuild assets" django-manage-assets-rebuild t]
|
|
["Make translations" django-manage-makemessages t]
|
|
["Compile translations" django-manage-compilemessages t]
|
|
["Open Python shell" django-manage-shell t]
|
|
["Open database shell" django-manage-dbshell t]
|
|
["Run other command" django-manage-command t]
|
|
"-"
|
|
["Insert translation mark" django-manage-insert-transpy t]))
|
|
|
|
(easy-menu-add django-manage-menu django-manage-map)
|
|
|
|
(provide 'django-manage)
|
|
|
|
;;; django-manage.el ends here
|