1. Brodie Rao
  2. dotfiles

Commits

Brodie Rao  committed 63ab7d8

emacs: update .emacs and add ropemacs stuff

  • Participants
  • Parent commits d6d3a4d
  • Branches default

Comments (0)

Files changed (85)

File .emacs

View file
  • Ignore whitespace
 ; Set up GUI-related stuff as soon as possible
 (menu-bar-mode -1)
 (when window-system
+  (tool-bar-mode -1)
+  (scroll-bar-mode -1)
   (add-to-list 'default-frame-alist '(background-color . "black"))
-  (add-to-list 'default-frame-alist '(alpha 92 92))
-  (add-to-list 'default-frame-alist '(width . 80))
-  (add-to-list 'default-frame-alist '(height . 42)))
+  (add-to-list 'default-frame-alist '(width . 162))
+  (add-to-list 'default-frame-alist '(height . 60))
+
+  ; Set PATH/exec-path based on the shell's configuration
+  (defun set-path-from-shell ()
+    (if (get-buffer "*set-path-from-shell*")
+        (kill-buffer "*set-path-from-shell*"))
+    (call-process-shell-command "zsh -c 'echo $PATH'" nil
+                                "*set-path-from-shell*")
+    (with-current-buffer "*set-path-from-shell*"
+      (let ((output (buffer-substring (point-min) (- (point-max) 1)))
+            (emacs-path (nth 0 (last exec-path))))
+        (setenv "PATH" (concat output emacs-path))
+        (setq exec-path `(,@(split-string output ":") ,emacs-path))
+        (kill-buffer "*set-path-from-shell*"))))
+  (set-path-from-shell))
 
 ; Color theme
 (add-to-list 'custom-theme-load-path "~/.emacs.d/themes")
 (setq js2-mirror-mode nil)
 (setq js2-language-version 150)
 (setq js2-rebind-eol-bol-keys nil)
+(setq dabbrev-case-distinction nil)
+
+; ropemacs stuff
+(setq ropemacs-guess-project t)
+(setenv "PYTHONPATH" (concat (expand-file-name "~/.emacs.d/python") ":"
+                             (getenv "PYTHONPATH")))
 
 ; Disable the fringe for all frames
 (add-to-list 'default-frame-alist '(left-fringe . 0))
 
 (add-hook 'python-mode-hook
           '(lambda ()
+             (require 'pymacs)
+             (pymacs-load "ropemacs" "rope-")
+             (ropemacs-mode 1)
              (hs-minor-mode 1)
              (define-key python-mode-map (kbd "RET") 'newline-maybe-indent)
              (define-key python-mode-map (kbd "M-RET") 'hs-toggle-hiding)))
 (global-set-key (kbd "C-x M-s") 'sudo-unset-ro-or-save)
 (global-set-key (kbd "C-x M-f") 'sudo-find-file)
 (global-set-key (kbd "C--") 'undo)
+(global-set-key (kbd "C-<tab>") 'dabbrev-expand)
 (when (fboundp 'ns-toggle-fullscreen)
   (global-set-key (kbd "s-<return>") 'ns-toggle-fullscreen))
 (when window-system

File .emacs.d/plugins/pymacs.el

View file
  • Ignore whitespace
+;;; Interface between Emacs Lisp and Python - Lisp part.    -*- emacs-lisp -*-
+;;; Copyright © 2001, 2002, 2003 Progiciels Bourbeau-Pinard inc.
+;;; François Pinard <pinard@iro.umontreal.ca>, 2001.
+
+;;; This program 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 2, or (at your option)
+;;; any later version.
+;;;
+;;; This program 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 this program; if not, write to the Free Software Foundation,
+;;; Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.  */
+
+;;; Portability stunts.
+
+(defvar pymacs-use-hash-tables
+  (and (fboundp 'make-hash-table) (fboundp 'gethash) (fboundp 'puthash))
+  "Set to t if hash tables are available.")
+
+(eval-and-compile
+
+  ;; pymacs-cancel-timer
+  (defalias 'pymacs-cancel-timer
+    (cond ((fboundp 'cancel-timer) 'cancel-timer)
+          ;; XEmacs case - yet having post-gc-hook, this is unused.
+          ((fboundp 'delete-itimer) 'delete-itimer)
+          (t 'ignore)))
+
+  ;; pymacs-kill-without-query
+  (if (fboundp 'set-process-query-on-exit-flag)
+      (defun pymacs-kill-without-query (process)
+        "Tell recent Emacs how to quickly destroy PROCESS while exiting."
+        (set-process-query-on-exit-flag process nil))
+    (defalias 'pymacs-kill-without-query
+      (if (fboundp 'process-kill-without-query-process)
+          'process-kill-without-query-process
+        'ignore)))
+
+  ;; pymacs-multibyte-string-p
+  (cond ((fboundp 'multibyte-string-p)
+         (defalias 'pymacs-multibyte-string-p 'multibyte-string-p))
+        ((fboundp 'find-charset-string)
+         (defun pymacs-multibyte-string-p (string)
+           "Tell XEmacs if STRING should be handled as multibyte."
+           (not (member (find-charset-string string) '(nil (ascii))))))
+        (t
+         ; Tell XEmacs that STRING is unibyte, when Mule is not around!
+         (defalias 'pymacs-multibyte-string-p 'ignore)))
+
+  ;; pymacs-report-error
+  (defalias 'pymacs-report-error (symbol-function 'error))
+
+  ;; pymacs-set-buffer-multibyte
+  (if (fboundp 'set-buffer-multibyte)
+      (defalias 'pymacs-set-buffer-multibyte 'set-buffer-multibyte)
+    (defun pymacs-set-buffer-multibyte (flag)
+      "For use in Emacs 20.2 or earlier.  Under XEmacs: no operation."
+      (setq enable-multibyte-characters flag)))
+
+  ;; pymacs-timerp
+  (defalias 'pymacs-timerp
+    (cond ((fboundp 'timerp) 'timerp)
+         ; XEmacs case - yet having post-gc-hook, this is unused.
+          ((fboundp 'itimerp) 'itimerp)
+          (t 'ignore)))
+
+  )
+
+;;; Published variables and functions.
+
+(defvar pymacs-python-command "python"
+  "Shell command used to start Python interpreter.")
+
+(defvar pymacs-load-path nil
+  "List of additional directories to search for Python modules.
+The directories listed will be searched first, in the order given.")
+
+(defvar pymacs-trace-transit '(5000 . 30000)
+  "Keep the communication buffer growing, for debugging.
+When this variable is nil, the `*Pymacs*' communication buffer gets erased
+before each communication round-trip.  Setting it to `t' guarantees that
+the full communication is saved, which is useful for debugging.
+It could also be given as (KEEP . LIMIT): whenever the buffer exceeds LIMIT
+bytes, it is reduced to approximately KEEP bytes.")
+
+(defvar pymacs-forget-mutability nil
+  "Transmit copies to Python instead of Lisp handles, as much as possible.
+When this variable is nil, most mutable objects are transmitted as handles.
+This variable is meant to be temporarily rebound to force copies.")
+
+(defvar pymacs-mutable-strings nil
+  "Prefer transmitting Lisp strings to Python as handles.
+When this variable is nil, strings are transmitted as copies, and the
+Python side thus has no way for modifying the original Lisp strings.
+This variable is ignored whenever `forget-mutability' is set.")
+
+(defvar pymacs-timeout-at-start 30
+  "Maximum reasonable time, in seconds, for starting the Pymacs helper.
+A machine should be pretty loaded before one needs to increment this.")
+
+(defvar pymacs-timeout-at-reply 5
+  "Expected maximum time, in seconds, to get the first line of a reply.
+The status of the Pymacs helper is checked at every such timeout.")
+
+(defvar pymacs-timeout-at-line 2
+  "Expected maximum time, in seconds, to get another line of a reply.
+The status of the Pymacs helper is checked at every such timeout.")
+
+(defvar pymacs-auto-restart 'ask
+  "Should the Pymacs helper be restarted whenever it dies?
+Possible values are nil, t or ask.")
+
+(defvar pymacs-dreadful-zombies nil
+  "If zombies should trigger hard errors, whenever they get called.
+If `nil', calling a zombie will merely produce a diagnostic message.")
+
+(defun pymacs-load (module &optional prefix noerror)
+  "Import the Python module named MODULE into Emacs.
+Each function in the Python module is made available as an Emacs function.
+The Lisp name of each function is the concatenation of PREFIX with
+the Python name, in which underlines are replaced by dashes.  If PREFIX is
+not given, it defaults to MODULE followed by a dash.
+If NOERROR is not nil, do not raise error when the module is not found."
+  (interactive
+   (let* ((module (read-string "Python module? "))
+          (default (concat (car (last (split-string module "\\."))) "-"))
+          (prefix (read-string (format "Prefix? [%s] " default)
+                               nil nil default)))
+     (list module prefix)))
+  (message "Pymacs loading %s..." module)
+  (let ((lisp-code (pymacs-call "pymacs_load_helper" module prefix)))
+    (cond (lisp-code (let ((result (eval lisp-code)))
+                       (message "Pymacs loading %s...done" module)
+                       result))
+          (noerror (message "Pymacs loading %s...failed" module) nil)
+          (t (pymacs-report-error "Pymacs loading %s...failed" module)))))
+
+(defun pymacs-eval (text)
+  "Compile TEXT as a Python expression, and return its value."
+  (interactive "sPython expression? ")
+  (let ((value (pymacs-serve-until-reply "eval" `(princ ,text))))
+    (when (interactive-p)
+      (message "%S" value))
+    value))
+
+(defun pymacs-exec (text)
+  "Compile and execute TEXT as a sequence of Python statements.
+This functionality is experimental, and does not appear to be useful."
+  (interactive "sPython statements? ")
+  (let ((value (pymacs-serve-until-reply "exec" `(princ ,text))))
+    (when (interactive-p)
+      (message "%S" value))
+    value))
+
+(defun pymacs-call (function &rest arguments)
+  "Return the result of calling a Python function FUNCTION over ARGUMENTS.
+FUNCTION is a string denoting the Python function, ARGUMENTS are separate
+Lisp expressions, one per argument.  Immutable Lisp constants are converted
+to Python equivalents, other structures are converted into Lisp handles."
+  (pymacs-serve-until-reply
+   "eval" `(pymacs-print-for-apply ',function ',arguments)))
+
+(defun pymacs-apply (function arguments)
+  "Return the result of calling a Python function FUNCTION over ARGUMENTS.
+FUNCTION is a string denoting the Python function, ARGUMENTS is a list of
+Lisp expressions.  Immutable Lisp constants are converted to Python
+equivalents, other structures are converted into Lisp handles."
+  (pymacs-serve-until-reply
+   "eval" `(pymacs-print-for-apply ',function ',arguments)))
+
+;;; Integration details.
+
+;; This page tries to increase the integration seamlessness of Pymacs
+;; with the reminder of Emacs.
+
+;; Module "desktop" savagely kills `*Pymacs*' in some circumstances.
+;; Let's avoid such damage.
+
+(eval-after-load 'desktop
+  '(push "\\*Pymacs\\*" desktop-clear-preserve-buffers))
+
+;; Python functions and modules should ideally look like Lisp
+;; functions and modules.
+
+(when t
+
+  (defadvice documentation (around pymacs-ad-documentation activate)
+    ;; Integration of doc-strings.
+    (let* ((reference (pymacs-python-reference function))
+           (python-doc (when reference
+                         (pymacs-eval (format "doc_string(%s)" reference)))))
+      (if (or reference python-doc)
+          (setq ad-return-value
+                (concat
+                 "It interfaces to a Python function.\n\n"
+                 (when python-doc
+                   (if raw python-doc (substitute-command-keys python-doc)))))
+        ad-do-it)))
+
+  (defun pymacs-python-reference (object)
+    ;; Return the text reference of a Python object if possible, else nil.
+    (when (functionp object)
+      (let* ((definition (indirect-function object))
+             (body (and (pymacs-proper-list-p definition)
+                        (> (length definition) 2)
+                        (eq (car definition) 'lambda)
+                        (cddr definition))))
+        (when (and body (listp (car body)) (eq (caar body) 'interactive))
+          ;; Skip the interactive specification of a function.
+          (setq body (cdr body)))
+        (when (and body
+                   ;; Advised functions start with a string.
+                   (not (stringp (car body)))
+                   ;; Python trampolines hold exactly one expression.
+                   (= (length body) 1))
+          (let ((expression (car body)))
+            ;; EXPRESSION might now hold something like:
+            ;;    (pymacs-apply (quote (pymacs-python . N)) ARGUMENT-LIST)
+            (when (and (pymacs-proper-list-p expression)
+                       (= (length expression) 3)
+                       (eq (car expression) 'pymacs-apply)
+                       (eq (car (cadr expression)) 'quote))
+              (setq object (cadr (cadr expression))))))))
+    (when (eq (car-safe object) 'pymacs-python)
+      (format "python[%d]" (cdr object)))))
+
+;; The following functions are experimental -- they are not satisfactory yet.
+
+(defun pymacs-file-handler (operation &rest arguments)
+  ;; Integration of load-file, autoload, etc.
+  ;; Emacs might want the contents of some `MODULE.el' which does not exist,
+  ;; while there is a `MODULE.py' or `MODULE.pyc' file in the same directory.
+  ;; The goal is to generate a virtual contents for this `MODULE.el' file, as
+  ;; a set of Lisp trampoline functions to the Python module functions.
+  ;; Python modules can then be loaded or autoloaded as if they were Lisp.
+  (cond ((and (eq operation 'file-readable-p)
+              (let ((module (substring (car arguments) 0 -3)))
+                (or (pymacs-file-force operation arguments)
+                    (file-readable-p (concat module ".py"))
+                    (file-readable-p (concat module ".pyc"))))))
+        ((and (eq operation 'load)
+              (not (pymacs-file-force
+                    'file-readable-p (list (car arguments))))
+              (file-readable-p (car arguments)))
+         (let ((lisp-code (pymacs-call "pymacs_load_helper"
+                                       (substring (car arguments) 0 -3)
+                                       nil)))
+           (unless lisp-code
+             (pymacs-report-error "Python import error"))
+           (eval lisp-code)))
+        ((and (eq operation 'insert-file-contents)
+              (not (pymacs-file-force
+                    'file-readable-p (list (car arguments))))
+              (file-readable-p (car arguments)))
+         (let ((lisp-code (pymacs-call "pymacs_load_helper"
+                                       (substring (car arguments) 0 -3)
+                                       nil)))
+           (unless lisp-code
+             (pymacs-report-error "Python import error"))
+           (insert (prin1-to-string lisp-code))))
+        (t (pymacs-file-force operation arguments))))
+
+(defun pymacs-file-force (operation arguments)
+  ;; Bypass the file handler.
+  (let ((inhibit-file-name-handlers
+         (cons 'pymacs-file-handler
+               (and (eq inhibit-file-name-operation operation)
+                    inhibit-file-name-handlers)))
+        (inhibit-file-name-operation operation))
+    (apply operation arguments)))
+
+;(add-to-list 'file-name-handler-alist '("\\.el\\'" . pymacs-file-handler))
+
+;;; Gargabe collection of Python IDs.
+
+;; Python objects which have no Lisp representation are allocated on the
+;; Python side as `python[INDEX]', and INDEX is transmitted to Emacs, with
+;; the value to use on the Lisp side for it.  Whenever Lisp does not need a
+;; Python object anymore, it should be freed on the Python side.  The
+;; following variables and functions are meant to fill this duty.
+
+(defvar pymacs-used-ids nil
+  "List of received IDs, currently allocated on the Python side.")
+
+;; This is set whenever the Pymacs helper successfully starts, and is
+;; also used to later detect the death of a previous helper.  If
+;; pymacs-use-hash-tables is unset, this variable receives `t' when
+;; the helper starts, so the detection works nevertheless.
+(defvar pymacs-weak-hash nil
+  "Weak hash table, meant to find out which IDs are still needed.")
+
+(defvar pymacs-gc-wanted nil
+  "Flag that it is desirable to clean up unused IDs on the Python side.")
+
+(defvar pymacs-gc-inhibit nil
+  "Flag that a new Pymacs garbage collection should just not run now.")
+
+(defvar pymacs-gc-timer nil
+  "Timer to trigger Pymacs garbage collection at regular time intervals.
+The timer is used only if `post-gc-hook' is not available.")
+
+(defun pymacs-schedule-gc (&optional xemacs-list)
+  (unless pymacs-gc-inhibit
+    (setq pymacs-gc-wanted t)))
+
+(defun pymacs-garbage-collect ()
+  ;; Clean up unused IDs on the Python side.
+  (when (and pymacs-use-hash-tables (not pymacs-gc-inhibit))
+    (let ((pymacs-gc-inhibit t)
+          (pymacs-forget-mutability t)
+          (ids pymacs-used-ids)
+          used-ids unused-ids)
+      (while ids
+        (let ((id (car ids)))
+          (setq ids (cdr ids))
+          (if (gethash id pymacs-weak-hash)
+              (setq used-ids (cons id used-ids))
+            (setq unused-ids (cons id unused-ids)))))
+      (setq pymacs-used-ids used-ids
+            pymacs-gc-wanted nil)
+      (when unused-ids
+        (pymacs-apply "free_python" unused-ids)))))
+
+(defun pymacs-defuns (arguments)
+  ;; Take one argument, a list holding a number of items divisible by 3.  The
+  ;; first argument is an INDEX, the second is a NAME, the third is the
+  ;; INTERACTION specification, and so forth.  Register Python INDEX with a
+  ;; function with that NAME and INTERACTION on the Lisp side.  The strange
+  ;; calling convention is to minimise quoting at call time.
+  (while (>= (length arguments) 3)
+    (let ((index (nth 0 arguments))
+          (name (nth 1 arguments))
+          (interaction (nth 2 arguments)))
+      (fset name (pymacs-defun index interaction))
+      (setq arguments (nthcdr 3 arguments)))))
+
+(defun pymacs-defun (index interaction)
+  ;; Register INDEX on the Lisp side with a Python object that is a function,
+  ;; and return a lambda form calling that function.  If the INTERACTION
+  ;; specification is nil, the function is not interactive.  Otherwise, the
+  ;; function is interactive, INTERACTION is then either a string, or the
+  ;; index of an argument-less Python function returning the argument list.
+  (let ((object (pymacs-python index)))
+    (cond ((null interaction)
+           `(lambda (&rest arguments)
+              (pymacs-apply ',object arguments)))
+          ((stringp interaction)
+           `(lambda (&rest arguments)
+              (interactive ,interaction)
+              (pymacs-apply ',object arguments)))
+          (t `(lambda (&rest arguments)
+                (interactive (pymacs-call ',(pymacs-python interaction)))
+                (pymacs-apply ',object arguments))))))
+
+(defun pymacs-python (index)
+  ;; Register on the Lisp side a Python object having INDEX, and return it.
+  ;; The result is meant to be recognised specially by `print-for-eval', and
+  ;; in the function position by `print-for-apply'.
+  (let ((object (cons 'pymacs-python index)))
+    (when pymacs-use-hash-tables
+      (puthash index object pymacs-weak-hash)
+      (setq pymacs-used-ids (cons index pymacs-used-ids)))
+    object))
+
+;;; Generating Python code.
+
+;; Many Lisp expressions cannot fully be represented in Python, at least
+;; because the object is mutable on the Lisp side.  Such objects are allocated
+;; somewhere into a vector of handles, and the handle index is used for
+;; communication instead of the expression itself.
+
+(defvar pymacs-lisp nil
+  "Vector of handles to hold transmitted expressions.")
+
+(defvar pymacs-freed-list nil
+  "List of unallocated indices in Lisp.")
+
+;; When the Python GC is done with a Lisp object, a communication occurs so to
+;; free the object on the Lisp side as well.
+
+(defun pymacs-allocate-lisp (expression)
+  ;; This function allocates some handle for an EXPRESSION, and return its
+  ;; index.
+  (unless pymacs-freed-list
+    (let* ((previous pymacs-lisp)
+           (old-size (length previous))
+           (new-size (if (zerop old-size) 100 (+ old-size (/ old-size 2))))
+           (counter new-size))
+      (setq pymacs-lisp (make-vector new-size nil))
+      (while (> counter 0)
+        (setq counter (1- counter))
+        (if (< counter old-size)
+            (aset pymacs-lisp counter (aref previous counter))
+          (setq pymacs-freed-list (cons counter pymacs-freed-list))))))
+  (let ((index (car pymacs-freed-list)))
+    (setq pymacs-freed-list (cdr pymacs-freed-list))
+    (aset pymacs-lisp index expression)
+    index))
+
+(defun pymacs-free-lisp (indices)
+  ;; This function is triggered from Python side for Lisp handles which lost
+  ;; their last reference.  These references should be cut on the Lisp side as
+  ;; well, or else, the objects will never be garbage-collected.
+  (while indices
+    (let ((index (car indices)))
+      (aset pymacs-lisp index nil)
+      (setq pymacs-freed-list (cons index pymacs-freed-list)
+            indices (cdr indices)))))
+
+(defun pymacs-print-for-apply (function arguments)
+  ;; This function prints a Python expression calling FUNCTION, which is a
+  ;; string naming a Python function, or a Python reference, over all its
+  ;; ARGUMENTS, which are Lisp expressions.
+  (let ((separator "")
+        argument)
+    (if (eq (car-safe function) 'pymacs-python)
+        (princ (format "python[%d]" (cdr function)))
+      (princ function))
+    (princ "(")
+    (while arguments
+      (setq argument (car arguments)
+            arguments (cdr arguments))
+      (princ separator)
+      (setq separator ", ")
+      (pymacs-print-for-eval argument))
+    (princ ")")))
+
+(defun pymacs-print-for-eval (expression)
+  ;; This function prints a Python expression out of a Lisp EXPRESSION.
+  (let (done)
+    (cond ((not expression)
+           (princ "None")
+           (setq done t))
+          ((eq expression t)
+           (princ "True")
+           (setq done t))
+          ((numberp expression)
+           (princ expression)
+           (setq done t))
+          ((stringp expression)
+           (when (or pymacs-forget-mutability
+                     (not pymacs-mutable-strings))
+             (let* ((multibyte (pymacs-multibyte-string-p expression))
+                    (text (if multibyte
+                              (encode-coding-string expression 'utf-8)
+                            (copy-sequence expression))))
+               (set-text-properties 0 (length text) nil text)
+               (princ (mapconcat 'identity
+                                 (split-string (prin1-to-string text) "\n")
+                                 "\\n"))
+               (when multibyte
+                 (princ ".encode('ISO-8859-1').decode('UTF-8')")))
+             (setq done t)))
+          ((symbolp expression)
+           (let ((name (symbol-name expression)))
+             ;; The symbol can only be transmitted when in the main oblist.
+             (when (eq expression (intern-soft name))
+               (princ "lisp[")
+               (prin1 name)
+               (princ "]")
+               (setq done t))))
+          ((vectorp expression)
+           (when pymacs-forget-mutability
+             (let ((limit (length expression))
+                   (counter 0))
+               (princ "(")
+               (while (< counter limit)
+                 (unless (zerop counter)
+                   (princ ", "))
+                 (pymacs-print-for-eval (aref expression counter))
+                 (setq counter (1+ counter)))
+               (when (= limit 1)
+                 (princ ","))
+               (princ ")")
+               (setq done t))))
+          ((eq (car-safe expression) 'pymacs-python)
+           (princ "python[")
+           (princ (cdr expression))
+           (princ "]")
+           (setq done t))
+          ((pymacs-proper-list-p expression)
+           (when pymacs-forget-mutability
+             (princ "[")
+             (pymacs-print-for-eval (car expression))
+             (while (setq expression (cdr expression))
+               (princ ", ")
+               (pymacs-print-for-eval (car expression)))
+             (princ "]")
+             (setq done t))))
+    (unless done
+      (let ((class (cond ((vectorp expression) "Vector")
+                         ((and pymacs-use-hash-tables
+                               (hash-table-p expression))
+                          "Table")
+                         ((bufferp expression) "Buffer")
+                         ((pymacs-proper-list-p expression) "List")
+                         (t "Lisp"))))
+        (princ class)
+        (princ "(")
+        (princ (pymacs-allocate-lisp expression))
+        (princ ")")))))
+
+;;; Communication protocol.
+
+(defvar pymacs-transit-buffer nil
+  "Communication buffer between Emacs and Python.")
+
+;; The principle behind the communication protocol is that it is easier to
+;; generate than parse, and that each language already has its own parser.
+;; So, the Emacs side generates Python text for the Python side to interpret,
+;; while the Python side generates Lisp text for the Lisp side to interpret.
+;; About nothing but expressions are transmitted, which are evaluated on
+;; arrival.  The pseudo `reply' function is meant to signal the final result
+;; of a series of exchanges following a request, while the pseudo `error'
+;; function is meant to explain why an exchange could not have been completed.
+
+;; The protocol itself is rather simple, and contains human readable text
+;; only.  A message starts at the beginning of a line in the communication
+;; buffer, either with `>' for the Lisp to Python direction, or `<' for the
+;; Python to Lisp direction.  This is followed by a decimal number giving the
+;; length of the message text, a TAB character, and the message text itself.
+;; Message direction alternates systematically between messages, it never
+;; occurs that two successive messages are sent in the same direction.  The
+;; first message is received from the Python side, it is `(version VERSION)'.
+
+(defun pymacs-start-services ()
+  ;; This function gets called automatically, as needed.
+  (let ((buffer (get-buffer-create "*Pymacs*")))
+    (with-current-buffer buffer
+      ;; Erase the buffer in case some previous incarnation of the
+      ;; Pymacs helper died.  Otherwise, the "(goto-char (point-min))"
+      ;; below might not find the proper synchronising reply and later
+      ;; trigger a spurious "Protocol error" diagnostic.
+      (erase-buffer)
+      (buffer-disable-undo)
+      (pymacs-set-buffer-multibyte nil)
+      (set-buffer-file-coding-system 'raw-text)
+      (save-match-data
+        ;; Launch the Pymacs helper.
+        (let ((process
+               (apply 'start-process "pymacs" buffer
+                      (let ((python (getenv "PYMACS_PYTHON")))
+                        (if (or (null python) (equal python ""))
+                            pymacs-python-command
+                          python))
+                      "-c" (concat "import sys;"
+                                   " from Pymacs.pymacs import main;"
+                                   " main(*sys.argv[1:])")
+                      (append
+                       (and (>= emacs-major-version 24) '("-f"))
+                       (mapcar 'expand-file-name pymacs-load-path)))))
+          (pymacs-kill-without-query process)
+          ;; Receive the synchronising reply.
+          (while (progn
+                   (goto-char (point-min))
+                   (not (re-search-forward "<\\([0-9]+\\)\t" nil t)))
+            (unless (accept-process-output process pymacs-timeout-at-start)
+              (pymacs-report-error
+               "Pymacs helper did not start within %d seconds"
+                     pymacs-timeout-at-start)))
+          (let ((marker (process-mark process))
+                (limit-position (+ (match-end 0)
+                                   (string-to-number (match-string 1)))))
+            (while (< (marker-position marker) limit-position)
+              (unless (accept-process-output process pymacs-timeout-at-start)
+                (pymacs-report-error
+                 "Pymacs helper probably was interrupted at start")))))
+        ;; Check that synchronisation occurred.
+        (goto-char (match-end 0))
+        (let ((reply (read (current-buffer))))
+          (if (and (pymacs-proper-list-p reply)
+                   (= (length reply) 2)
+                   (eq (car reply) 'version))
+              (unless (string-equal (cadr reply) "0.24-beta2")
+                (pymacs-report-error
+                 "Pymacs Lisp version is 0.24-beta2, Python is %s"
+                 (cadr reply)))
+            (pymacs-report-error "Pymacs got an invalid initial reply")))))
+    (if (not pymacs-use-hash-tables)
+        (setq pymacs-weak-hash t)
+      (when pymacs-used-ids
+        ;; A previous Pymacs session occurred in this Emacs session,
+        ;; some IDs hang around which do not correspond to anything on
+        ;; the Python side.  Python should not recycle such IDs for
+        ;; new objects.
+        (let ((pymacs-transit-buffer buffer)
+              (pymacs-forget-mutability t)
+              (pymacs-gc-inhibit t))
+          (pymacs-apply "zombie_python" pymacs-used-ids))
+        (setq pymacs-used-ids nil))
+      (setq pymacs-weak-hash (make-hash-table :weakness 'value))
+      (if (boundp 'post-gc-hook)
+          (add-hook 'post-gc-hook 'pymacs-schedule-gc)
+        (setq pymacs-gc-timer (run-at-time 20 20 'pymacs-schedule-gc))))
+    ;; If nothing failed, only then declare that Pymacs has started!
+    (setq pymacs-transit-buffer buffer)))
+
+(defun pymacs-terminate-services ()
+  ;; This function is mainly provided for documentation purposes.
+  (interactive)
+  (garbage-collect)
+  (pymacs-garbage-collect)
+  (when (or (not pymacs-used-ids)
+            (yes-or-no-p "\
+Killing the Pymacs helper might create zombie objects.  Kill? "))
+    (cond ((boundp 'post-gc-hook)
+           (remove-hook 'post-gc-hook 'pymacs-schedule-gc))
+          ((pymacs-timerp pymacs-gc-timer)
+           (pymacs-cancel-timer pymacs-gc-timer)))
+    (when pymacs-transit-buffer
+      (kill-buffer pymacs-transit-buffer))
+    (setq pymacs-gc-inhibit nil
+          pymacs-gc-timer nil
+          pymacs-transit-buffer nil
+          pymacs-lisp nil
+          pymacs-freed-list nil)))
+
+(defun pymacs-serve-until-reply (action inserter)
+  ;; This function builds a Python request by printing ACTION and
+  ;; evaluating INSERTER, which itself prints an argument.  It then
+  ;; sends the request to the Pymacs helper, and serves all
+  ;; sub-requests coming from the Python side, until either a reply or
+  ;; an error is finally received.
+  (unless (and pymacs-transit-buffer
+               (buffer-name pymacs-transit-buffer)
+               (get-buffer-process pymacs-transit-buffer))
+    (when pymacs-weak-hash 
+      (unless (or (eq pymacs-auto-restart t)
+                  (and (eq pymacs-auto-restart 'ask)
+                       (yes-or-no-p "The Pymacs helper died.  Restart it? ")))
+        (pymacs-report-error "There is no Pymacs helper!")))
+    (pymacs-start-services))
+  (when pymacs-gc-wanted
+    (pymacs-garbage-collect))
+  (let ((inhibit-quit t)
+        done value)
+    (while (not done)
+      (let ((form (pymacs-round-trip action inserter)))
+        (setq action (car form))
+        (when (eq action 'free)
+          (pymacs-free-lisp (cadr form))
+          (setq form (cddr form)
+                action (car form)))
+        (let* ((pair (pymacs-interruptible-eval (cadr form)))
+               (success (cdr pair)))
+          (setq value (car pair))
+          (cond ((eq action 'eval)
+                 (if success
+                     (setq action "return"
+                           inserter `(pymacs-print-for-eval ',value))
+                   (setq action "raise"
+                         inserter `(let ((pymacs-forget-mutability t))
+                                     (pymacs-print-for-eval ,value)))))
+                ((eq action 'expand)
+                 (if success
+                     (setq action "return"
+                           inserter `(let ((pymacs-forget-mutability t))
+                                       (pymacs-print-for-eval ,value)))
+                   (setq action "raise"
+                         inserter `(let ((pymacs-forget-mutability t))
+                                     (pymacs-print-for-eval ,value)))))
+                ((eq action 'return)
+                 (if success
+                     (setq done t)
+                   (pymacs-report-error "%s" value)))
+                ((eq action 'raise)
+                 (if success
+                     (pymacs-report-error "Python: %s" value)
+                   (pymacs-report-error "%s" value)))
+                (t (pymacs-report-error "Protocol error: %s" form))))))
+    value))
+
+(defun pymacs-round-trip (action inserter)
+  ;; This function produces a Python request by printing and
+  ;; evaluating INSERTER, which itself prints an argument.  It sends
+  ;; the request to the Pymacs helper, awaits for any kind of reply,
+  ;; and returns it.
+  (with-current-buffer pymacs-transit-buffer
+    ;; Possibly trim the beginning of the transit buffer.
+    (cond ((not pymacs-trace-transit)
+           (erase-buffer))
+          ((consp pymacs-trace-transit)
+           (when (> (buffer-size) (cdr pymacs-trace-transit))
+             (let ((cut (- (buffer-size) (car pymacs-trace-transit))))
+               (when (> cut 0)
+                 (save-excursion
+                   (goto-char cut)
+                   (unless (memq (preceding-char) '(0 ?\n))
+                     (forward-line 1))
+                   (delete-region (point-min) (point))))))))
+    ;; Send the request, wait for a reply, and process it.
+    (let* ((process (get-buffer-process pymacs-transit-buffer))
+           (status (process-status process))
+           (marker (process-mark process))
+           (moving (= (point) marker))
+           send-position reply-position reply)
+      (save-excursion
+        (save-match-data
+          ;; Encode request.
+          (setq send-position (marker-position marker))
+          (let ((standard-output marker))
+            (princ action)
+            (princ " ")
+            (eval inserter))
+          (goto-char marker)
+          (unless (= (preceding-char) ?\n)
+            (princ "\n" marker))
+          ;; Send request text.
+          (goto-char send-position)
+          (insert (format ">%d\t" (- marker send-position)))
+          (setq reply-position (marker-position marker))
+          (process-send-region process send-position marker)
+          ;; Receive reply text.
+          (while (and (eq status 'run)
+                      (progn
+                        (goto-char reply-position)
+                        (not (re-search-forward "<\\([0-9]+\\)\t" nil t))))
+            (unless (accept-process-output process pymacs-timeout-at-reply)
+              (setq status (process-status process))))
+          (when (eq status 'run)
+            (let ((limit-position (+ (match-end 0)
+                                     (string-to-number (match-string 1)))))
+              (while (and (eq status 'run)
+                          (< (marker-position marker) limit-position))
+                (unless (accept-process-output process pymacs-timeout-at-line)
+                  (setq status (process-status process))))))
+          ;; Decode reply.
+          (if (not (eq status 'run))
+              (pymacs-report-error "Pymacs helper status is `%S'" status)
+            (goto-char (match-end 0))
+            (setq reply (read (current-buffer))))))
+      (when (and moving (not pymacs-trace-transit))
+        (goto-char marker))
+      reply)))
+
+(defun pymacs-interruptible-eval (expression)
+  ;; This function produces a pair (VALUE . SUCCESS) for EXPRESSION.
+  ;; A cautious evaluation of EXPRESSION is attempted, and any
+  ;; error while evaluating is caught, including Emacs quit (C-g).
+  ;; Any Emacs quit also gets forward as a SIGINT to the Pymacs handler.
+  ;; With SUCCESS being true, VALUE is the expression value.
+  ;; With SUCCESS being false, VALUE is an interruption diagnostic.
+  (condition-case info
+      (cons (let ((inhibit-quit nil)) (eval expression)) t)
+    (quit (setq quit-flag t)
+          (interrupt-process pymacs-transit-buffer)
+          (cons "*Interrupted!*" nil))
+    (error (cons (prin1-to-string info) nil))))
+
+(defun pymacs-proper-list-p (expression)
+  ;; Tell if a list is proper, id est, that it is `nil' or ends with `nil'.
+  (cond ((not expression))
+        ((consp expression) (not (cdr (last expression))))))
+
+(provide 'pymacs)

File .emacs.d/python/Pymacs/__init__.py

View file
  • Ignore whitespace
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright © 2002, 2003 Progiciels Bourbeau-Pinard inc.
+# François Pinard <pinard@iro.umontreal.ca>, 2002.
+
+# This program 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 2, or (at your option)
+# any later version.
+#
+# This program 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 this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.  */
+
+"""\
+Interface between Emacs Lisp and Python - Module initialisation.
+
+A few symbols are moved in here so they appear to be defined at this level.
+"""
+
+
+
+
+from pymacs import Let, lisp
+
+# Identification of version.
+
+__package__ = 'Pymacs'
+__version__ = '0.24-beta2'

File .emacs.d/python/Pymacs/pymacs.py

View file
  • Ignore whitespace
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright © 2001, 2002, 2003 Progiciels Bourbeau-Pinard inc.
+# François Pinard <pinard@iro.umontreal.ca>, 2001.
+
+# This program 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 2, or (at your option)
+# any later version.
+#
+# This program 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 this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.  */
+
+"""\
+Interface between Emacs Lisp and Python - Python part.
+
+Emacs may launch this module as a stand-alone program, in which case it
+acts as a server of Python facilities for that Emacs session, reading
+requests from standard input and writing replies on standard output.
+When used in this way, the program is called "the Pymacs helper".
+
+This module may also be usefully imported by other Python modules.
+See the Pymacs documentation (check `README') for more information.
+"""
+
+
+
+
+
+
+
+
+
+
+__metaclass__ = type
+import os, sys
+
+def fixup_icanon():
+    # otherwise sys.stdin.read hangs for large inputs in emacs 24
+    # see comment in emacs source code sysdep.c
+    import termios
+    a = termios.tcgetattr(1)
+    a[3] &= ~termios.ICANON
+    termios.tcsetattr(1, termios.TCSANOW, a)
+
+try:
+    import signal
+except ImportError:
+    # Jython does not have signal.
+    signal = None
+
+## Python services for Emacs applications.
+
+class Main:
+    debug_file = None
+    signal_file = None
+
+    def main(self, *arguments):
+        """\
+Execute Python services for Emacs, and Emacs services for Python.
+This program is meant to be called from Emacs, using `pymacs.el'.
+
+Debugging options:
+    -d FILE  Debug the protocol to FILE.
+    -s FILE  Trace received signals to FILE.
+
+Arguments are added to the search path for Python modules.
+"""
+
+        # Decode options.
+        arguments = (os.environ.get('PYMACS_OPTIONS', '').split()
+                     + list(arguments))
+        import getopt
+        options, arguments = getopt.getopt(arguments, 'fd:s:')
+        for option, value in options:
+            if option == '-d':
+                self.debug_file = value
+            elif option == '-s':
+                self.signal_file = value
+            elif option == '-f':
+                try:
+                    fixup_icanon()
+                except:
+                    pass
+
+        arguments.reverse()
+        for argument in arguments:
+            if os.path.isdir(argument):
+                sys.path.insert(0, argument)
+
+        # Inhibit signals.  The Interrupt signal is temporary enabled, however,
+        # while executing any Python code received from the Lisp side.
+        if signal is not None:
+
+            # See the comment for IO_ERRORS_WITH_SIGNALS in ppppconfig.py.
+            self.original_handler = signal.signal(
+                    signal.SIGINT, self.interrupt_handler)
+
+
+
+
+
+
+
+
+
+
+        self.inhibit_quit = True
+
+
+        # Re-open standard input and output in binary mode.
+        sys.stdin = os.fdopen(sys.stdin.fileno(), 'rb')
+        sys.stdout = os.fdopen(sys.stdout.fileno(), 'wb')
+
+        # Start protocol and services.
+        lisp._protocol.send('version', '"0.24-beta2"')
+        lisp._protocol.loop()
+
+    def generic_handler(self, number, frame):
+        if self.signal_file:
+            handle = open(self.signal_file, 'a')
+            handle.write('%d\n' % number)
+            handle.close()
+
+    def interrupt_handler(self, number, frame):
+        if self.signal_file:
+            star = (' *', '')[self.inhibit_quit]
+            handle = open(self.signal_file, 'a')
+            handle.write('%d%s\n' % (number, star))
+            handle.close()
+        if not self.inhibit_quit:
+            self.original_handler(number, frame)
+
+run = Main()
+main = run.main
+
+
+
+
+
+class error(Exception): pass
+class ProtocolError(error): pass
+class ZombieError(error): pass
+
+class Protocol:
+
+    # All exec's and eval's triggered from the Emacs side are all executed
+    # within the "loop" method below, so all user context is kept as
+    # local variables within this single routine.  Different instances
+    # of this Protocol class would yield independant evaluation contexts.
+    # But in the usual case, there is only one such instance kept within a
+    # Lisp_Interface instance, and the "lisp" global variable within this
+    # module holds such a Lisp_Interface instance.
+
+    def __init__(self):
+        self.freed = []
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    def loop(self):
+        # The server loop repeatedly receives a request from Emacs and
+        # returns a response, which is either the value of the received
+        # Python expression, or the Python traceback if an error occurs
+        # while evaluating the expression.
+
+        # The server loop may also be executed, as a recursive invocation,
+        # in the context of Emacs serving a Python request.  In which
+        # case, we might also receive a notification from Emacs telling
+        # that the reply has been transmitted, or that an error occurred.
+        # A reply notification from Emacs interrupts the loop: the result
+        # of this function is then the value returned from Emacs.
+        done = False
+        while not done:
+            try:
+                action, text = self.receive()
+                if action == 'eval':
+                    action = 'return'
+                    try:
+                        run.inhibit_quit = False
+                        value = eval(text)
+                    finally:
+                        run.inhibit_quit = True
+                elif action == 'exec':
+                    action = 'return'
+                    value = None
+                    try:
+                        run.inhibit_quit = False
+                        exec text
+                    finally:
+                        run.inhibit_quit = True
+                elif action == 'return':
+                    done = True
+                    try:
+                        run.inhibit_quit = False
+                        value = eval(text)
+                    finally:
+                        run.inhibit_quit = True
+                elif action == 'raise':
+                    action = 'raise'
+                    value = 'Emacs: ' + text
+                else:
+
+
+
+                    raise ProtocolError("Unknown action %r" % action)
+            except KeyboardInterrupt:
+                if done:
+                    raise
+                action = 'raise'
+                value = '*Interrupted*'
+            except ProtocolError, exception:
+                sys.exit("Protocol error: %s\n" % exception)
+            except:
+                import StringIO, traceback
+                buffer = StringIO.StringIO()
+                traceback.print_exc(file=buffer)
+                action = 'raise'
+                value = buffer.getvalue()
+            if not done:
+                fragments = []
+                print_lisp(value, fragments.append, True)
+                self.send(action, ''.join(fragments))
+        return value
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    def receive(self):
+        # Receive a Python expression from Emacs, return (ACTION, TEXT).
+        prefix = sys.stdin.read(3)
+        if not prefix or prefix[0] != '>':
+
+
+
+            raise ProtocolError("`>' expected.")
+        while prefix[-1] != '\t':
+            character = sys.stdin.read(1)
+            if not character:
+
+
+
+                raise ProtocolError("Empty stdin read.")
+            prefix += character
+        text = sys.stdin.read(int(prefix[1:-1]))
+        if run.debug_file is not None:
+            handle = open(run.debug_file, 'a')
+            handle.write(prefix + text)
+            handle.close()
+        return text.split(None, 1)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    def send(self, action, text):
+        # Send ACTION and its TEXT argument to Emacs.
+        if self.freed:
+            # All delayed Lisp cleanup is piggied back on the transmission.
+            text = ('(free (%s) %s %s)\n'
+                    % (' '.join(map(str, self.freed)), action, text))
+            self.freed = []
+        else:
+            text = '(%s %s)\n' % (action, text)
+        prefix = '<%d\t' % len(text)
+        if run.debug_file is not None:
+            handle = open(run.debug_file, 'a')
+            handle.write(prefix + text)
+            handle.close()
+        sys.stdout.write(prefix + text)
+        sys.stdout.flush()
+
+def pymacs_load_helper(file_without_extension, prefix):
+    # This function imports a Python module, then returns a Lisp expression
+    # which, when later evaluated, will install trampoline definitions
+    # in Emacs for accessing the Python module facilities.  Module, given
+    # through FILE_WITHOUT_EXTENSION, may be a full path, yet without the
+    # `.py' or `.pyc' suffix, in which case the directory is temporarily
+    # added to the Python search path for the sole duration of that import.
+    # All defined symbols on the Lisp side have have PREFIX prepended,
+    # and have Python underlines in Python turned into dashes.  If PREFIX
+    # is None, it then defaults to the base name of MODULE with underlines
+    # turned to dashes, followed by a dash.
+    directory, module_name = os.path.split(file_without_extension)
+    module_components = module_name.split('.')
+    if prefix is None:
+        prefix = module_components[-1].replace('_', '-') + '-'
+    try:
+        module = sys.modules.get(module_name)
+        if module:
+            reload(module)
+        else:
+            try:
+                if directory:
+                    sys.path.insert(0, directory)
+                module = __import__(module_name)
+            finally:
+                if directory:
+                    del sys.path[0]
+            # Whenever MODULE_NAME is of the form [PACKAGE.]...MODULE,
+            # __import__ returns the outer PACKAGE, not the module.
+            for component in module_components[1:]:
+                module = getattr(module, component)
+    except ImportError:
+        return None
+    load_hook = module.__dict__.get('pymacs_load_hook')
+    if load_hook:
+        load_hook()
+    interactions = module.__dict__.get('interactions', {})
+    if not isinstance(interactions, dict):
+        interactions = {}
+    arguments = []
+    for name, value in module.__dict__.items():
+        if callable(value) and value is not lisp:
+            arguments.append(allocate_python(value))
+            arguments.append(lisp[prefix + name.replace('_', '-')])
+            try:
+                interaction = value.interaction
+            except AttributeError:
+                interaction = interactions.get(value)
+            if callable(interaction):
+                arguments.append(allocate_python(interaction))
+            else:
+                arguments.append(interaction)
+    if arguments:
+        return [lisp.progn,
+                [lisp.pymacs_defuns, [lisp.quote, arguments]],
+                module]
+    return [lisp.quote, module]
+
+def doc_string(function):
+    if hasattr(function, '__doc__'):
+        return function.__doc__
+
+## Garbage collection matters.
+
+# Many Python types do not have direct Lisp equivalents, and may not be
+# directly returned to Lisp for this reason.  They are rather allocated in
+# a list of handles, below, and a handle index is used for communication
+# instead of the Python value.  Whenever such a handle is freed from the
+# Lisp side, its index is added of a freed list for later reuse.
+
+python = []
+freed_list = []
+
+def allocate_python(value):
+    assert not isinstance(value, str), (type(value), repr(value))
+    # Allocate some handle to hold VALUE, return its index.
+    if freed_list:
+        index = freed_list[-1]
+        del freed_list[-1]
+        python[index] = value
+    else:
+        index = len(python)
+        python.append(value)
+    return index
+
+def free_python(*indices):
+    # Return many handles to the pool.
+    for index in indices:
+        python[index] = None
+        freed_list.append(index)
+
+def zombie_python(*indices):
+    # Ensure that some handles are _not_ in the pool.
+    for index in indices:
+        while index >= len(python):
+            freed_list.append(len(python))
+            python.append(None)
+        python[index] = zombie
+        freed_list.remove(index)
+    # Merely to make `*Pymacs*' a bit more readable.
+    freed_list.sort()
+
+def zombie(*arguments):
+    # This catch-all function is set as the value for any function which
+    # disappeared with a previous Pymacs helper process, so calling
+    # such a function from Emacs will trigger a decipherable diagnostic.
+    diagnostic = "Object vanished when the Pymacs helper was killed"
+    if lisp.pymacs_dreadful_zombies.value():
+
+
+
+        raise ZombieError(diagnostic)
+    lisp.message(diagnostic)
+
+## Emacs services for Python applications.
+
+class Let:
+
+    def __init__(self, **keywords):
+        # The stack holds (METHOD, DATA) pairs, where METHOD is the expected
+        # unbound pop_* method, and DATA holds information to be restored.
+        # METHOD may not be bound to the instance, as this would induce
+        # reference cycles, and then, __del__ would not be called timely.
+        self.stack = []
+        if keywords:
+            self.push(**keywords)
+
+    def __del__(self):
+        self.pops()
+
+
+
+
+
+
+    def __nonzero__(self):
+        # So stylistic `if let:' executes faster.
+        return True
+
+    def pops(self):
+        while self.stack:
+            self.stack[-1][0](self)
+
+    def push(self, **keywords):
+        data = []
+        for name, value in keywords.items():
+            data.append((name, getattr(lisp, name).value()))
+            setattr(lisp, name, value)
+        self.stack.append((Let.pop, data))
+        return self
+
+    def pop(self):
+        method, data = self.stack.pop()
+        assert method == Let.pop, (method, data)
+        for name, value in data:
+            setattr(lisp, name, value)
+
+    def push_excursion(self):
+        self.stack.append((Let.pop_excursion, (lisp.current_buffer(),
+                                               lisp.point_marker(),
+                                               lisp.mark_marker())))
+        return self
+
+    def pop_excursion(self):
+        method, data = self.stack.pop()
+        assert method == Let.pop_excursion, (method, data)
+        buffer, point_marker, mark_marker = data
+        lisp.set_buffer(buffer)
+        lisp.goto_char(point_marker)
+        lisp.set_mark(mark_marker)
+        lisp.set_marker(point_marker, None)
+        lisp.set_marker(mark_marker, None)
+
+    def push_match_data(self):
+        self.stack.append((Let.pop_match_data, lisp.match_data()))
+        return self
+
+    def pop_match_data(self):
+        method, data = self.stack.pop()
+        assert method == Let.pop_match_data, (method, data)
+        lisp.set_match_data(data)
+
+    def push_restriction(self):
+        self.stack.append((Let.pop_restriction, (lisp.point_min_marker(),
+                                                 lisp.point_max_marker())))
+        return self
+
+    def pop_restriction(self):
+        method, data = self.stack.pop()
+        assert method == Let.pop_restriction, (method, data)
+        point_min_marker, point_max_marker = data
+        lisp.narrow_to_region(point_min_marker, point_max_marker)
+        lisp.set_marker(point_min_marker, None)
+        lisp.set_marker(point_max_marker, None)
+
+    def push_selected_window(self):
+        self.stack.append((Let.pop_selected_window, lisp.selected_window()))
+        return self
+
+    def pop_selected_window(self):
+        method, data = self.stack.pop()
+        assert method == Let.pop_selected_window, (method, data)
+        lisp.select_window(data)
+
+    def push_window_excursion(self):
+        self.stack.append((Let.pop_window_excursion,
+                           lisp.current_window_configuration()))
+        return self
+
+    def pop_window_excursion(self):
+        method, data = self.stack.pop()
+        assert method == Let.pop_window_excursion, (method, data)
+        lisp.set_window_configuration(data)
+
+class Symbol:
+
+    def __init__(self, text):
+        self.text = text
+
+    def __repr__(self):
+        return 'lisp[%s]' % repr(self.text)
+
+    def __str__(self):
+        return '\'' + self.text
+
+    def value(self):
+        return lisp._eval(self.text)
+
+    def copy(self):
+        return lisp._expand(self.text)
+
+    def set(self, value):
+        if value is None:
+            lisp._eval('(setq %s nil)' % self.text)
+        else:
+            fragments = []
+            write = fragments.append
+            write('(progn (setq %s ' % self.text)
+            print_lisp(value, write, True)
+            write(') nil)')
+            lisp._eval(''.join(fragments))
+
+    def __call__(self, *arguments):
+        fragments = []
+        write = fragments.append
+        write('(%s' % self.text)
+        for argument in arguments:
+            write(' ')
+            print_lisp(argument, write, True)
+        write(')')
+        return lisp._eval(''.join(fragments))
+
+class Lisp:
+
+    def __init__(self, index):
+        self.index = index
+
+    def __del__(self):
+        lisp._protocol.freed.append(self.index)
+
+    def __repr__(self):
+        return ('lisp(%s)' % repr(lisp('(prin1-to-string %s)' % self)))
+
+    def __str__(self):
+        return '(aref pymacs-lisp %d)' % self.index
+
+    def value(self):
+        return self
+
+    def copy(self):
+        return lisp._expand(str(self))
+
+class Buffer(Lisp):
+    pass
+
+    #def write(text):
+    #    # So you could do things like
+    #    # print >>lisp.current_buffer(), "Hello World"
+    #    lisp.insert(text, self)
+
+    #def point(self):
+    #    return lisp.point(self)
+
+class List(Lisp):
+
+    def __call__(self, *arguments):
+        fragments = []
+        write = fragments.append
+        write('(%s' % self)
+        for argument in arguments:
+            write(' ')
+            print_lisp(argument, write, True)
+        write(')')
+        return lisp._eval(''.join(fragments))
+
+    def __len__(self):
+        return lisp._eval('(length %s)' % self)
+
+    def __getitem__(self, key):
+        value = lisp._eval('(nth %d %s)' % (key, self))
+        if value is None and key >= len(self):
+
+
+
+            raise IndexError(key)
+        return value
+
+    def __setitem__(self, key, value):
+        fragments = []
+        write = fragments.append
+        write('(setcar (nthcdr %d %s) ' % (key, self))
+        print_lisp(value, write, True)
+        write(')')
+        lisp._eval(''.join(fragments))
+
+class Table(Lisp):
+
+    def __getitem__(self, key):
+        fragments = []
+        write = fragments.append
+        write('(gethash ')
+        print_lisp(key, write, True)
+        write(' %s)' % self)
+        return lisp._eval(''.join(fragments))
+
+    def __setitem__(self, key, value):
+        fragments = []
+        write = fragments.append
+        write('(puthash ')
+        print_lisp(key, write, True)
+        write(' ')
+        print_lisp(value, write, True)
+        write(' %s)' % self)
+        lisp._eval(''.join(fragments))
+
+class Vector(Lisp):
+
+    def __len__(self):
+        return lisp._eval('(length %s)' % self)
+
+    def __getitem__(self, key):
+        return lisp._eval('(aref %s %d)' % (self, key))
+
+    def __setitem__(self, key, value):
+        fragments = []
+        write = fragments.append
+        write('(aset %s %d ' % (self, key))
+        print_lisp(value, write, True)
+        write(')')
+        lisp._eval(''.join(fragments))
+
+class Lisp_Interface:
+
+    def __init__(self):
+        self.__dict__['_cache'] = {'nil': None}
+        self.__dict__['_protocol'] = Protocol()
+
+    def __call__(self, text):
+        return self._eval('(progn %s)' % text)
+
+    def _eval(self, text):
+        self._protocol.send('eval', text)
+        return self._protocol.loop()
+
+    def _expand(self, text):
+        self._protocol.send('expand', text)
+        return self._protocol.loop()
+
+    def __getattr__(self, name):
+        if name[0] == '_':
+
+
+
+            raise AttributeError(name)
+        return self[name.replace('_', '-')]
+
+    def __setattr__(self, name, value):
+        if name[0] == '_':
+
+
+
+            raise AttributeError(name)
+        self[name.replace('_', '-')] = value
+
+    def __getitem__(self, name):
+        try:
+            return self._cache[name]
+        except KeyError:
+            symbol = self._cache[name] = Symbol(name)
+            return symbol
+
+    def __setitem__(self, name, value):
+        try:
+            symbol = self._cache[name]
+        except KeyError:
+            symbol = self._cache[name] = Symbol(name)
+        symbol.set(value)
+
+lisp = Lisp_Interface()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+print_lisp_quoted_specials = {
+        '"': '\\"', '\\': '\\\\', '\b': '\\b', '\f': '\\f',
+        '\n': '\\n', '\r': '\\r', '\t': '\\t'}
+
+def print_lisp(value, write, quoted):
+    if value is None:
+        write('nil')
+    elif isinstance(bool, type) and isinstance(value, bool):
+        write(('nil', 't')[value])
+    elif isinstance(value, int):
+        write(repr(value))
+    elif isinstance(value, float):
+        write(repr(value))
+    elif isinstance(value, basestring):
+        multibyte = False
+        if isinstance(value, unicode):
+            try:
+                value = value.encode('ASCII')
+            except UnicodeError:
+                value = value.encode('UTF-8')
+                multibyte = True
+        if multibyte:
+            write('(decode-coding-string ')
+        write('"')
+        for character in value:
+            special = print_lisp_quoted_specials.get(character)
+            if special is not None:
+                write(special)
+            elif 32 <= ord(character) < 127:
+                write(character)
+            else:
+                write('\\%.3o' % ord(character))
+        write('"')
+        if multibyte:
+            write(' \'utf-8)')
+    elif isinstance(value, list):
+        if quoted:
+            write("'")
+        if len(value) == 0:
+            write('nil')
+        elif len(value) == 2 and value[0] == lisp.quote:
+            write("'")
+            print_lisp(value[1], write, False)
+        else:
+            write('(')
+            print_lisp(value[0], write, False)
+            for sub_value in value[1:]:
+                write(' ')
+                print_lisp(sub_value, write, False)
+            write(')')
+    elif isinstance(value, tuple):
+        write('[')
+        if len(value) > 0:
+            print_lisp(value[0], write, False)
+            for sub_value in value[1:]:
+                write(' ')
+                print_lisp(sub_value, write, False)
+        write(']')
+    elif isinstance(value, Lisp):
+        write(str(value))
+    elif isinstance(value, Symbol):
+        if quoted:
+            write("'")
+        write(value.text)
+    elif callable(value):
+        write('(pymacs-defun %d nil)' % allocate_python(value))
+    else:
+        write('(pymacs-python %d)' % allocate_python(value))
+
+if __name__ == '__main__':
+    main(*sys.argv[1:])

File .emacs.d/python/rope/__init__.py

View file
  • Ignore whitespace
+"""rope, a python refactoring library"""
+
+INFO = __doc__
+VERSION = '0.9.3'
+COPYRIGHT = """\
+Copyright (C) 2006-2010 Ali Gholami Rudi
+Copyright (C) 2009-2010 Anton Gritsay
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of GNU General Public License as published by the
+Free Software Foundation; either version 2 of the license, or (at your
+opinion) any later version.
+
+This program 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."""

File .emacs.d/python/rope/base/__init__.py

View file
  • Ignore whitespace
+"""Base rope package
+
+This package contains rope core modules that are used by other modules
+and packages.
+
+"""
+
+__all__ = ['project', 'libutils', 'exceptions']

File .emacs.d/python/rope/base/arguments.py

View file
  • Ignore whitespace
+import rope.base.evaluate
+from rope.base import ast
+
+
+class Arguments(object):
+    """A class for evaluating parameters passed to a function
+
+    You can use the `create_arguments` factory.  It handles implicit
+    first arguments.
+
+    """
+
+    def __init__(self, args, scope):
+        self.args = args
+        self.scope = scope
+        self.instance = None
+
+    def get_arguments(self, parameters):
+        result = []
+        for pyname in self.get_pynames(parameters):
+            if pyname is None:
+                result.append(None)
+            else:
+                result.append(pyname.get_object())
+        return result
+
+    def get_pynames(self, parameters):
+        result = [None] * max(len(parameters), len(self.args))
+        for index, arg in enumerate(self.args):
+            if isinstance(arg, ast.keyword) and arg.arg in parameters:
+                result[parameters.index(arg.arg)] = self._evaluate(arg.value)
+            else:
+                result[index] = self._evaluate(arg)
+        return result
+
+    def get_instance_pyname(self):
+        if self.args:
+            return self._evaluate(self.args[0])
+
+    def _evaluate(self, ast_node):
+        return rope.base.evaluate.eval_node(self.scope, ast_node)
+
+
+def create_arguments(primary, pyfunction, call_node, scope):
+    """A factory for creating `Arguments`"""
+    args = list(call_node.args)
+    args.extend(call_node.keywords)
+    called = call_node.func
+    # XXX: Handle constructors
+    if _is_method_call(primary, pyfunction) and \
+       isinstance(called, ast.Attribute):
+        args.insert(0, called.value)
+    return Arguments(args, scope)
+
+
+class ObjectArguments(object):
+
+    def __init__(self, pynames):
+        self.pynames = pynames
+
+    def get_arguments(self, parameters):
+        result = []
+        for pyname in self.pynames:
+            if pyname is None:
+                result.append(None)
+            else:
+                result.append(pyname.get_object())
+        return result
+
+    def get_pynames(self, parameters):
+        return self.pynames
+
+    def get_instance_pyname(self):
+        return self.pynames[0]
+class MixedArguments(object):
+
+    def __init__(self, pyname, arguments, scope):
+        """`argumens` is an instance of `Arguments`"""
+        self.pyname = pyname
+        self.args = arguments
+
+    def get_pynames(self, parameters):
+        return [self.pyname] + self.args.get_pynames(parameters[1:])
+
+    def get_arguments(self, parameters):
+        result = []
+        for pyname in self.get_pynames(parameters):
+            if pyname is None:
+                result.append(None)
+            else:
+                result.append(pyname.get_object())
+        return result
+
+    def get_instance_pyname(self):
+        return self.pyname
+
+
+def _is_method_call(primary, pyfunction):
+    if primary is None:
+        return False
+    pyobject = primary.get_object()
+    if isinstance(pyobject.get_type(), rope.base.pyobjects.PyClass) and \
+       isinstance(pyfunction, rope.base.pyobjects.PyFunction) and \
+       isinstance(pyfunction.parent, rope.base.pyobjects.PyClass):
+        return True
+    if isinstance(pyobject.get_type(), rope.base.pyobjects.AbstractClass) and \
+       isinstance(pyfunction, rope.base.builtins.BuiltinFunction):
+        return True
+    return False

File .emacs.d/python/rope/base/ast.py

View file
  • Ignore whitespace
+import _ast
+from _ast import *
+
+from rope.base import fscommands
+
+
+def parse(source, filename='<string>'):
+    # NOTE: the raw string should be given to `compile` function
+    if isinstance(source, unicode):
+        source = fscommands.unicode_to_file_data(source)
+    if '\r' in source:
+        source = source.replace('\r\n', '\n').replace('\r', '\n')