summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom Willemse2014-04-15 23:53:52 +0200
committerGravatar Tom Willemse2014-04-15 23:53:52 +0200
commit35a7bb5d57b5564119ea414a0e334cb700f42516 (patch)
tree3763fda1f381ab29701819917197f049933421a7
parent5ad0cebed5a861e0384812c9b200f8d8df6d4c8d (diff)
downloademacs-35a7bb5d57b5564119ea414a0e334cb700f42516.tar.gz
emacs-35a7bb5d57b5564119ea414a0e334cb700f42516.zip
Add some python editing functions, with tests
-rw-r--r--.emacs.d/init.el160
1 files changed, 160 insertions, 0 deletions
diff --git a/.emacs.d/init.el b/.emacs.d/init.el
index ac73282..0f69cbd 100644
--- a/.emacs.d/init.el
+++ b/.emacs.d/init.el
@@ -126,6 +126,16 @@ MODE1 is enabled and vice-versa."
;;;; Functions
+(defun oni:add-import-from (package import)
+ (interactive
+ (list (completing-read "From package: " (oni:collect-from-imports))
+ (read-string "Import: ")))
+ (save-excursion
+ (goto-char (point-min))
+ (search-forward (concat "from " package " import ("))
+ (insert "\n " import ",")
+ (oni:sort-imports)))
+
(defun oni:after-save-func ()
"Function for `after-save-hook'."
(executable-make-buffer-file-executable-if-script-p)
@@ -196,6 +206,15 @@ MODE1 is enabled and vice-versa."
(oni:shorten-dir
(abbreviate-file-name (eshell/pwd))))))))
+(defun oni:collect-from-imports ()
+ (let (results)
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward "from \\(.+\\) import" nil :noerror)
+ (push (buffer-substring-no-properties (match-beginning 1)
+ (match-end 1)) results)))
+ results))
+
(defun oni:current-jabber-status ()
"Return a string representing the current jabber status."
(or (and (not *jabber-connected*) "Offline")
@@ -335,6 +354,25 @@ If COUNT has been specified indent by that much, otherwise look at
(local-unset-key (kbd "]"))
(local-unset-key (kbd "}")))
+(defun oni:make-import-multiline (from-point to-point)
+ (interactive (list (line-beginning-position)
+ (line-end-position)))
+ (goto-char from-point)
+ (search-forward "import" to-point)
+ (insert " (\n")
+ (delete-horizontal-space)
+ (let ((imports-start (point)) imports-end)
+ (while (search-forward "," to-point :noeror)
+ (insert "\n")
+ (delete-horizontal-space))
+ (end-of-line)
+ (insert ",\n")
+ (setf imports-end (point))
+ (insert ")")
+ (python-indent-shift-right imports-start imports-end)
+ (forward-line -1)
+ (oni:sort-imports)))
+
(defun oni:make-readable ()
"Make non-programming buffers a little more readable."
(setq line-spacing .2))
@@ -804,6 +842,128 @@ If no direction is given, don't split."
(setq-default electric-pair-mode nil) ; But keep it globally disabled.
)))
+;;;; Tests
+
+(stante-after ert
+ (ert-deftest oni:add-import-from ()
+ (with-temp-buffer
+ (python-mode)
+ (insert "from myaethon2.core.administration.models import (
+ Client,
+ Contact,
+ Individual,
+ Location,
+)")
+ (oni:add-import-from "myaethon2.core.administration.models" "Debtor")
+ (should (equal (buffer-substring-no-properties (point-min) (point-max))
+ "from myaethon2.core.administration.models import (
+ Client,
+ Contact,
+ Debtor,
+ Individual,
+ Location,
+)"))))
+
+ (ert-deftest oni:collect-from-imports ()
+ (with-temp-buffer
+ (python-mode)
+ (insert "import calendar as cal
+import datetime
+
+from django.conf import settings
+from django.contrib import messages
+from django.contrib.auth.decorators import login_required, permission_required
+from django.core.context_processors import csrf
+from django.core.exceptions import PermissionDenied
+from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
+from django.core.urlresolvers import reverse
+from django.db import transaction
+from django.db.models import Q
+from django.shortcuts import get_object_or_404, render
+from django.utils import formats
+from django.utils.translation import ugettext as _
+
+from myaethon2.core.business_units import BU
+from myaethon2.core.forms import MultiFormWrapper
+from myaethon2.core.models import AUser, Service
+from myaethon2.core.planning.models import Booking, JOB_TYPES
+from myaethon2.core.util import simplify_timedelta
+from myaethon2.core.views import SearchAndSortListView
+from myaethon2.jobs import forms, status
+from myaethon2.jobs.models import Assignment, Job, JobGroup
+from myaethon2.jobs.util import JobFactory
+from myaethon2.workers.models import Worker
+from myaethon2.export import Exporter, XLSGenerator
+
+from django.http import (
+ HttpResponseForbidden,
+ HttpResponseNotAllowed,
+ HttpResponseRedirect,
+)
+
+from django.views.generic import (
+ CreateView,
+ DeleteView,
+ DetailView,
+ ListView,
+ UpdateView,
+)
+
+from myaethon2.core.administration.models import (
+ Client,
+ Contact,
+ Debtor,
+ Individual,
+ Location,
+)
+
+from myaethon2.core.decorators import (
+ json_response,
+ protect_with,
+ with_help_text,
+)")
+ (should (equal (sort (oni:collect-from-imports) #'string-lessp)
+ '("django.conf"
+ "django.contrib"
+ "django.contrib.auth.decorators"
+ "django.core.context_processors"
+ "django.core.exceptions"
+ "django.core.paginator"
+ "django.core.urlresolvers"
+ "django.db"
+ "django.db.models"
+ "django.http"
+ "django.shortcuts"
+ "django.utils"
+ "django.utils.translation"
+ "django.views.generic"
+ "myaethon2.core.administration.models"
+ "myaethon2.core.business_units"
+ "myaethon2.core.decorators"
+ "myaethon2.core.forms"
+ "myaethon2.core.models"
+ "myaethon2.core.planning.models"
+ "myaethon2.core.util"
+ "myaethon2.core.views"
+ "myaethon2.export"
+ "myaethon2.jobs"
+ "myaethon2.jobs.models"
+ "myaethon2.jobs.util"
+ "myaethon2.workers.models")))))
+
+ (ert-deftest oni:make-import-multiline ()
+ (with-temp-buffer
+ (python-mode)
+ (insert "from myaethon2.core.administration.models import Contact, Individual, Client, Location")
+ (oni:make-import-multiline (line-beginning-position) (line-end-position))
+ (should (equal (buffer-substring-no-properties (point-min) (point-max))
+ "from myaethon2.core.administration.models import (
+ Client,
+ Contact,
+ Individual,
+ Location,
+)")))))
+
;;;; Aliases
(defalias 'yes-or-no-p 'y-or-n-p)