remove old unused submodules.
This commit is contained in:
parent
d0d842e62c
commit
fc890df22d
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -1,6 +0,0 @@
|
|||||||
[submodule "lisp/multi-line-it"]
|
|
||||||
path = lisp/multi-line-it
|
|
||||||
url = https://github.com/IvanMalison/multi-line-it.git
|
|
||||||
[submodule "lisp/emacs-testify"]
|
|
||||||
path = lisp/emacs-testify
|
|
||||||
url = https://github.com/IvanMalison/emacs-testify.git
|
|
4
init.el
4
init.el
@ -19,6 +19,8 @@
|
|||||||
(setq custom-file "~/.emacs.d/custom.el")
|
(setq custom-file "~/.emacs.d/custom.el")
|
||||||
(when (file-exists-p custom-file) (load custom-file))
|
(when (file-exists-p custom-file) (load custom-file))
|
||||||
|
|
||||||
|
(add-to-list 'load-path "~/.emacs.d/lisp")
|
||||||
|
|
||||||
;; =============================================================================
|
;; =============================================================================
|
||||||
;; ELPA/package.el/MELPA
|
;; ELPA/package.el/MELPA
|
||||||
;; =============================================================================
|
;; =============================================================================
|
||||||
@ -50,7 +52,7 @@
|
|||||||
|
|
||||||
(defvar packages-python '(jedi pymacs pytest sphinx-doc))
|
(defvar packages-python '(jedi pymacs pytest sphinx-doc))
|
||||||
(defvar packages-scala '(scala-mode2 ensime))
|
(defvar packages-scala '(scala-mode2 ensime))
|
||||||
(defvar packages-js '(js2-mode js3-mode web-beautify tern tern-auto-complete))
|
(defvar packages-js '(js2-mode js3-mode web-beautify tern tern-auto-complete slime-js))
|
||||||
|
|
||||||
(defun ensure-packages-installed (packages)
|
(defun ensure-packages-installed (packages)
|
||||||
(dolist (p packages)
|
(dolist (p packages)
|
||||||
|
@ -1 +0,0 @@
|
|||||||
Subproject commit c64b99e729eae0df9d9c65f8deecc602c972519f
|
|
@ -1 +0,0 @@
|
|||||||
Subproject commit c62ca553af2e23b7e06113b1b90f5c3165fe68a2
|
|
@ -1,842 +0,0 @@
|
|||||||
;;; pymacs.el --- Interface between Emacs Lisp and Python
|
|
||||||
|
|
||||||
;; Copyright © 2001-2003, 2012, 2013 Progiciels Bourbeau-Pinard inc.
|
|
||||||
|
|
||||||
;; Author: François Pinard <pinard@iro.umontreal.ca>
|
|
||||||
;; Maintainer: François Pinard <pinard@iro.umontreal.ca>
|
|
||||||
;; URL: https://github.com/pinard/Pymacs
|
|
||||||
;; Version: 0.25
|
|
||||||
;; Keywords: Python interface protocol
|
|
||||||
|
|
||||||
;; 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.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;; Pymacs is a powerful tool which, once started from Emacs, allows
|
|
||||||
;; both-way communication between Emacs Lisp and Python. Pymacs aims
|
|
||||||
;; Python as an extension language for Emacs rather than the other way
|
|
||||||
;; around. Visit http://pymacs.progiciels-bpi.ca to read its manual,
|
|
||||||
;; which also contains installation instructions.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
;; The code is organized into pages, grouping declarations by topic.
|
|
||||||
;; Such pages are introduced by a form feed and a topic description.
|
|
||||||
|
|
||||||
;;; 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-called-interactively-p
|
|
||||||
(defalias 'pymacs-called-interactively-p
|
|
||||||
(cond ((fboundp 'called-interactively-p) 'called-interactively-p)
|
|
||||||
;; Emacs before 22.
|
|
||||||
(t 'interactive-p)))
|
|
||||||
|
|
||||||
;; 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.")
|
|
||||||
|
|
||||||
(defvar pymacs-load-history nil "Pymacs loading history.")
|
|
||||||
|
|
||||||
(defvar pymacs-after-load-functions nil
|
|
||||||
"Special hook run after loading a Python module.
|
|
||||||
Each function there is called with a single argument, the Python
|
|
||||||
module name passed to as the first argument of `pymacs-load'.")
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(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 noerror)))
|
|
||||||
(cond (lisp-code (let ((result (eval lisp-code)))
|
|
||||||
(add-to-list 'pymacs-load-history
|
|
||||||
(list module prefix noerror)
|
|
||||||
;; append so that order is kept
|
|
||||||
'append)
|
|
||||||
(message "Pymacs loading %s...done" module)
|
|
||||||
(run-hook-with-args 'pymacs-after-load-functions module)
|
|
||||||
result))
|
|
||||||
(noerror (message "Pymacs loading %s...failed" module) nil))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun pymacs-autoload (function module &optional prefix docstring interactive)
|
|
||||||
"Pymacs's equivalent of the standard emacs facility `autoload'.
|
|
||||||
Define FUNCTION to autoload from Python MODULE using PREFIX.
|
|
||||||
If PREFIX is not given, it defaults to MODULE followed by a dash.
|
|
||||||
Optional DOCSTRING documents FUNCTION until it gets loaded.
|
|
||||||
INTERACTIVE is normally the argument to the function `interactive',
|
|
||||||
t means `interactive' without arguments, nil means not interactive,
|
|
||||||
which is the default."
|
|
||||||
(unless (symbolp function)
|
|
||||||
(error "`%s' should be a symbol" function))
|
|
||||||
(unless (stringp module)
|
|
||||||
(error "`%s' should be a string" module))
|
|
||||||
(unless (pymacs-python-reference function)
|
|
||||||
|
|
||||||
(defalias function
|
|
||||||
`(lambda (&rest args)
|
|
||||||
,(or docstring
|
|
||||||
(format "Function `%s' to be loaded from Python module `%s'"
|
|
||||||
function module))
|
|
||||||
,(cond ((eq interactive t) '(interactive))
|
|
||||||
(interactive `(interactive ,interactive)))
|
|
||||||
(pymacs-load ,module ,prefix)
|
|
||||||
(unless (pymacs-python-reference ',function)
|
|
||||||
(error "Pymacs autoload failed to define function %s" ',function))
|
|
||||||
(apply ',function args)))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(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 (pymacs-called-interactively-p)
|
|
||||||
(message "%S" value))
|
|
||||||
value))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(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 (pymacs-called-interactively-p)
|
|
||||||
(message "%S" value))
|
|
||||||
value))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(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)))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(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
|
|
||||||
(let ((pymacs-forget-mutability t))
|
|
||||||
(pymacs-call "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)
|
|
||||||
(when multibyte
|
|
||||||
(princ "b"))
|
|
||||||
(princ (mapconcat 'identity
|
|
||||||
(split-string (prin1-to-string text) "\n")
|
|
||||||
"\\n"))
|
|
||||||
(when multibyte
|
|
||||||
(princ ".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 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.25")
|
|
||||||
(pymacs-report-error
|
|
||||||
"Pymacs Lisp version is 0.25, 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-call "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)
|
|
||||||
(let ((modules pymacs-load-history))
|
|
||||||
(setq pymacs-load-history nil)
|
|
||||||
(when (and modules (yes-or-no-p "Reload modules in previous session? "))
|
|
||||||
(mapc (lambda (args)
|
|
||||||
;; Be defensive in case sys.path differs
|
|
||||||
(condition-case err
|
|
||||||
(apply 'pymacs-load args)
|
|
||||||
(error
|
|
||||||
(message "%s: %s" (car err) (error-message-string err)))))
|
|
||||||
modules)))))
|
|
||||||
|
|
||||||
(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 (buffer-live-p 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)
|
|
||||||
;;; pymacs.el ends here
|
|
124
lisp/setup-slime-js.el
Normal file
124
lisp/setup-slime-js.el
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
;; Taken from https://github.com/magnars/.emacs.d/blob/master/setup-slime-js.el
|
||||||
|
;; js2-refactor is commented out
|
||||||
|
|
||||||
|
;; Set up slime-js
|
||||||
|
;;
|
||||||
|
;; To install, see https://github.com/swank-js/swank-js/wiki/Installation
|
||||||
|
;;
|
||||||
|
;; This is what I did:
|
||||||
|
;;
|
||||||
|
;; npm install swank-js -g
|
||||||
|
;; M-x package-install slime-js
|
||||||
|
;;
|
||||||
|
;; The slime-js version in marmalade requires swank 2010.04.04, or at least
|
||||||
|
;; one prior to the breaking change in 2011.
|
||||||
|
;;
|
||||||
|
;; It also requires js2-mode, which is a good choice in either case. I highly
|
||||||
|
;; recommend this fork:
|
||||||
|
;;
|
||||||
|
;; https://github.com/mooz/js2-mode
|
||||||
|
;;
|
||||||
|
;; My settings found in this file also requires js2-refactor:
|
||||||
|
;;
|
||||||
|
;; https://github.com/magnars/js2-refactor.el
|
||||||
|
;;
|
||||||
|
;; I have included this file in init.el like so:
|
||||||
|
;;
|
||||||
|
;; (add-hook 'after-init-hook
|
||||||
|
;; #'(lambda ()
|
||||||
|
;; (when (locate-library "slime-js")
|
||||||
|
;; (require 'setup-slime-js))))
|
||||||
|
;;
|
||||||
|
|
||||||
|
(require 'slime)
|
||||||
|
(require 'slime-js)
|
||||||
|
;(require 'js2-refactor)
|
||||||
|
|
||||||
|
(set-default 'slime-js-target-url "http://localhost:3000")
|
||||||
|
(set-default 'slime-js-connect-url "http://localhost:8009")
|
||||||
|
(set-default 'slime-js-starting-url "/")
|
||||||
|
(set-default 'slime-js-swank-command "swank-js")
|
||||||
|
(set-default 'slime-js-swank-args '())
|
||||||
|
(set-default 'slime-js-browser-command "open -v \"Google Chrome\"")
|
||||||
|
(set-default 'slime-js-browser-jacked-in-p nil)
|
||||||
|
|
||||||
|
(add-hook 'js2-mode-hook (lambda () (slime-js-minor-mode 1)))
|
||||||
|
|
||||||
|
(defun slime-js-run-swank ()
|
||||||
|
"Runs the swank side of the equation."
|
||||||
|
(interactive)
|
||||||
|
(apply #'make-comint "swank-js" slime-js-swank-command nil slime-js-swank-args))
|
||||||
|
|
||||||
|
(defun slime-js-jack-in-node ()
|
||||||
|
"Start a swank-js server and connect to it, opening a repl."
|
||||||
|
(interactive)
|
||||||
|
(slime-js-run-swank)
|
||||||
|
(sleep-for 1)
|
||||||
|
(setq slime-protocol-version 'ignore)
|
||||||
|
(slime-connect "localhost" 4005))
|
||||||
|
|
||||||
|
(defun slime-js-jack-in-browser ()
|
||||||
|
"Start a swank-js server, connect to it, open a repl, open a browser, connect to that."
|
||||||
|
(interactive)
|
||||||
|
(slime-js-jack-in-node)
|
||||||
|
(sleep-for 2)
|
||||||
|
(slime-js-set-target-url slime-js-target-url)
|
||||||
|
(shell-command (concat slime-js-browser-command " " slime-js-connect-url slime-js-starting-url))
|
||||||
|
(sleep-for 3)
|
||||||
|
(setq slime-remote-history nil)
|
||||||
|
(slime-js-sticky-select-remote (caadr (slime-eval '(js:list-remotes))))
|
||||||
|
(setq slime-js-browser-jacked-in-p t)
|
||||||
|
(global-set-key [f5] 'slime-js-reload))
|
||||||
|
|
||||||
|
(defadvice save-buffer (after save-css-buffer activate)
|
||||||
|
(when (and slime-js-browser-jacked-in-p (eq major-mode 'css-mode))
|
||||||
|
(slime-js-refresh-css)))
|
||||||
|
|
||||||
|
(defun js2-eval-friendly-node-p (n)
|
||||||
|
(or (and (js2-stmt-node-p n) (not (js2-block-node-p n)))
|
||||||
|
(and (js2-function-node-p n) (js2-function-node-name n))))
|
||||||
|
|
||||||
|
(defun slime-js--echo-result (result &rest _)
|
||||||
|
(message result))
|
||||||
|
|
||||||
|
(defun slime-js--replace-with-result (replacement beg end)
|
||||||
|
(save-excursion
|
||||||
|
(goto-char beg)
|
||||||
|
(delete-char (- end beg))
|
||||||
|
(insert replacement)))
|
||||||
|
|
||||||
|
(defun slime-js-eval-region (beg end &optional func)
|
||||||
|
(lexical-let ((func (or func 'slime-js--echo-result))
|
||||||
|
(beg beg)
|
||||||
|
(end end))
|
||||||
|
(slime-flash-region beg end)
|
||||||
|
(slime-js-eval
|
||||||
|
(buffer-substring-no-properties beg end)
|
||||||
|
#'(lambda (s) (funcall func (cadr s) beg end)))))
|
||||||
|
|
||||||
|
(defun slime-js-eval-statement (&optional func)
|
||||||
|
(let ((node (js2r--closest 'js2-eval-friendly-node-p)))
|
||||||
|
(slime-js-eval-region (js2-node-abs-pos node)
|
||||||
|
(js2-node-abs-end node)
|
||||||
|
func)))
|
||||||
|
|
||||||
|
(defun slime-js-eval-current ()
|
||||||
|
(interactive)
|
||||||
|
(if (use-region-p)
|
||||||
|
(slime-js-eval-region (point) (mark))
|
||||||
|
(slime-js-eval-statement)))
|
||||||
|
|
||||||
|
(defun slime-js-eval-and-replace-current ()
|
||||||
|
(interactive)
|
||||||
|
(if (use-region-p)
|
||||||
|
(slime-js-eval-region (point) (mark) 'slime-js--replace-with-result)
|
||||||
|
(slime-js-eval-statement 'slime-js--replace-with-result)))
|
||||||
|
|
||||||
|
(define-key slime-js-minor-mode-map (kbd "C-x C-e") 'slime-js-eval-current)
|
||||||
|
(define-key slime-js-minor-mode-map (kbd "C-c C-e") 'slime-js-eval-and-replace-current)
|
||||||
|
|
||||||
|
;; Remove slime-minor-mode from mode line if diminish.el is installed
|
||||||
|
(when (boundp 'diminish)
|
||||||
|
(diminish 'slime-js-minor-mode))
|
||||||
|
|
||||||
|
(provide 'setup-slime-js)
|
Loading…
Reference in New Issue
Block a user