This is only relevant if you write your own macros. If you do,
remember to add a debug declaration in them.
+
+ *** The theading macros (~->~ and ~-->~)
+
+ The threading macros would require special treatment to namespace
+ correctly. However, you can use the ~:functionlike-macros~ keyword to
+ tell *Names* to treat them as regular functions.
+
+ For example, in the following snippet:
+ #+BEGIN_SRC emacs-lisp
+ (require 'dash)
+ (define-namespace foo-
+ :functionlike-macros (-> ->>)
+
+ (defvar var nil)
+ (defun fun (x &optional y)
+ (concat x y))
+
+ (-> "some string"
+ (fun var)
+ fun)
+ )
+ #+END_SRC
+ the ~(fun var)~ part would be namespaced prefectly fine (~fun~ and
+ ~var~ will be identified as a function and variable respectively),
+ because it looks like a regular function call. However, the second use
+ of ~fun~ will not be correctly namespaced, because that ~fun~ looks
+ like a variable.
+
+ In other words, you should use these macros like this instead:
+ #+BEGIN_SRC emacs-lisp
+ (-> "some string"
+ (fun var)
+ (fun))
+ #+END_SRC
+
** Accessing Global Symbols
If one of your definitions shadows a global definition, you can still
access it by prefixing it with =::=.
(defmacro names-print (name &rest forms)
"Return the expanded results of (namespace NAME :global :verbose FORMS).
Ideal for determining why a specific form isn't being parsed
- correctly."
+ correctly. You may need to set `eval-expression-print-level' and
+ `eval-expression-print-length' to nil in order to see your full
+ expansion."
(declare (indent (lambda (&rest x) 0)) (debug 0))
- `(let ((eval-expression-print-level (max eval-expression-print-level 300))
- (eval-expression-print-length (max eval-expression-print-length 300)))
- (macroexpand '(define-namespace ,name :global :verbose ,@forms))))
+ `(define-namespace ,name :global :verbose ,@forms))
(defvar names-font-lock
'(("^:autoload\\_>" 0 'font-lock-warning-face prepend)
(kill-buffer b))))))
(defun names--top-of-namespace ()
- ""
- (progn
- (beginning-of-defun)
- (ignore-errors
- (backward-up-list)
- (names--looking-at-namespace))))
+ "Move to the top of current namespace, and return non-nil.
+ If not inside a namespace, return nil and don't move point."
+ (let ((top (save-excursion
+ (beginning-of-defun)
+ (ignore-errors
+ (backward-up-list))
+ (when (names--looking-at-namespace)
+ (point)))))
+ (when top
+ (goto-char top)
+ t)))
(defun names-eval-defun (edebug-it)
"Identical to `eval-defun', except it works for forms inside namespaces.
\f
;;; eval-last-sexp
(defalias 'names--preceding-sexp-original
- (symbol-function 'elisp--preceding-sexp))
+ (if (fboundp 'elisp--preceding-sexp)
+ (symbol-function 'elisp--preceding-sexp)
+ (symbol-function 'preceding-sexp)))
(defun names--preceding-sexp ()
"Like `elisp--preceding-sexp', but expand namespaces."
"Identical to `eval-last-sexp', except it works for forms inside namespaces.
Argument EVAL-LAST-SEXP-ARG-INTERNAL is the same as `eval-last-sexp'."
(interactive "P")
- (cl-letf (((symbol-function 'elisp--preceding-sexp)
- #'names--preceding-sexp))
+ (cl-letf (((symbol-function 'elisp--preceding-sexp) #'names--preceding-sexp)
+ ((symbol-function 'preceding-sexp) #'names--preceding-sexp))
(eval-last-sexp eval-last-sexp-arg-internal)))
(defun names-eval-print-last-sexp (eval-last-sexp-arg-internal)
"Identical to `eval-print-last-sexp', except it works for forms inside namespaces.
Argument EVAL-LAST-SEXP-ARG-INTERNAL is the same as `eval-print-last-sexp'."
(interactive "P")
- (cl-letf (((symbol-function 'elisp--preceding-sexp)
- #'names--preceding-sexp))
+ (cl-letf (((symbol-function 'elisp--preceding-sexp) #'names--preceding-sexp)
+ ((symbol-function 'preceding-sexp) #'names--preceding-sexp))
(eval-print-last-sexp eval-last-sexp-arg-internal)))
- ;; (pp (symbol-function 'names-eval-defun) (current-buffer))
+ ;; (pp (symbol-function 'names--preceding-sexp-original) (current-buffer))
+
+ (defun names-pprint ()
+ "Pretty-print an expansion of the namespace around point."
+ (interactive)
+ (save-excursion
+ (when (names--top-of-namespace)
+ (let ((ns (cdr (read (current-buffer)))))
+ (pp-macroexpand-expression
+ (macroexpand (cons 'names-print ns)))))))
\f
;;; Find stuff
;; Author: Artur Malabarba <bruce.connor.am@gmail.com>
;; Maintainer: Artur Malabarba <bruce.connor.am@gmail.com>
;; URL: http://github.com/Bruce-Connor/names
- ;; Version: 20150115.1
+ ;; Version: 20150618.0
;; Package-Requires: ((emacs "24.1") (cl-lib "0.5"))
;; Keywords: extensions lisp
;; Prefix: names
"Load autoloaded definition DEF from function named NAME."
(unless (load (cadr def) 'noerror)
(error "Macro `%s' is autoloaded, but its file (%s) couldn't be loaded"
- name (cadr def)))
+ name (cadr def)))
(symbol-function name))
(lambda (f prop &rest _)
(if (fboundp 'macrop) #'macrop
(lambda (object)
"Non-nil if and only if OBJECT is a macro."
- (let ((def (indirect-function object t)))
+ (let ((def (or (ignore-errors (indirect-function object t))
+ (ignore-errors (indirect-function object)))))
(when (consp def)
(or (eq 'macro (car def))
(and (names--autoloadp def) (memq (nth 4 def) '(macro t)))))))))
\f
;;; ---------------------------------------------------------------
;;; Variables
- (defconst names-version "20150115.1" "Version of the names.el package.")
+ (defconst names-version "20150618.0" "Version of the names.el package.")
(defvar names--name nil
"Name of the current namespace inside the `define-namespace' macro.")
"The version number given by :version.
Used to define a constant and a command.")
+ (defvar names--functionlike-macros nil
+ "Function-like macros, even if their debug-spec says otherwise.
+ When expanding the namespace, these macros will be treated
+ exactly like functions. This means that their contents will be
+ namespaced like regular function arguments.
+
+ To add macros to this list, pass the :functionlike-macros keyword
+ to your namespace along with a list of macro names (as unquoted
+ symbols).
+ Example:
+
+ (define-namespace foo-
+ :functionlike-macros (-> ->> thread-first thread-last)
+ ;; Rest of code
+ )")
+
(defconst names--keyword-list
`((:group
1 ,(lambda (x)
(format "\\`%s" (regexp-quote val)))))
"Change the value of the `names--protection' variable.")
+ (:functionlike-macros
+ 1
+ ,(lambda (x) (setq names--functionlike-macros
+ (append x names--functionlike-macros)))
+ "A list of values to be appended to `names--functionlike-macros'.")
+
(:no-let-vars
0 nil
"Indicates variables assigned in let-bind are NOT candidates for namespacing.")
(remove
nil
(mapcar (lambda (x) (when (funcall (or ,pred #'identity) (or (car-safe x) x))
- (or (car-safe x) x)))
- ,var))))
+ (or (car-safe x) x)))
+ ,var))))
(defmacro names--next-keyword (body)
"If car of BODY is a known keyword, `pop' it (and its arguments) from body.
(names--remove-namespace-from-list
(names--filter-if-bound byte-compile-macro-environment (lambda (x) (not (names--compat-macrop x))))
(names--filter-if-bound byte-compile-function-environment (lambda (x) (not (names--compat-macrop x))))))
+ (names--functionlike-macros names--functionlike-macros)
names--keywords names--local-vars key-and-args
names--version names--package names--group-parent)
;; Read keywords
byte-compile-macro-environment))))))))
;;;###autoload
- (defadvice find-function-search-for-symbol
- (around names-around-find-function-search-for-symbol-advice
- (symbol type library) activate)
- "Make sure `find-function-search-for-symbol' understands namespaces."
- ad-do-it
- (ignore-errors
- (unless (cdr ad-return-value)
- (with-current-buffer (car ad-return-value)
- (search-forward-regexp "^(define-namespace\\_>")
- (skip-chars-forward "\r\n[:blank:]")
- (let* ((names--regexp
- (concat "\\`" (regexp-quote
- (symbol-name (read (current-buffer))))))
- (short-symbol
- ;; We manually implement `names--remove-namespace'
- ;; because it might not be loaded.
- (let ((name (symbol-name symbol)))
- (when (string-match names--regexp name)
- (intern (replace-match "" nil nil name))))))
- (when short-symbol
- (ad-set-arg 0 short-symbol)
- ad-do-it))))))
+ (eval-after-load 'find-func
+ '(defadvice find-function-search-for-symbol
+ (around names-around-find-function-search-for-symbol-advice
+ (symbol type library) activate)
+ "Make sure `find-function-search-for-symbol' understands namespaces."
+ ad-do-it
+ (ignore-errors
+ (unless (cdr ad-return-value)
+ (with-current-buffer (car ad-return-value)
+ (search-forward-regexp "^(define-namespace\\_>")
+ (skip-chars-forward "\r\n[:blank:]")
+ (let* ((names--regexp
+ (concat "\\`" (regexp-quote
+ (symbol-name (read (current-buffer))))))
+ (short-symbol
+ ;; We manually implement `names--remove-namespace'
+ ;; because it might not be loaded.
+ (let ((name (symbol-name symbol)))
+ (when (string-match names--regexp name)
+ (intern (replace-match "" nil nil name))))))
+ (when short-symbol
+ (ad-set-arg 0 short-symbol)
+ ad-do-it)))))))
(defun names--extract-autoloads (body)
"Return a list of the forms in BODY preceded by :autoload."
"If non-nil, verbose message are printed regardless of the :verbose keyword.
Use this to easily turn on verbosity during tests.")
- ;; This is calling edebug even on `when' and `unless'
(defun names--args-of-function-or-macro (function args macro)
"Namespace FUNCTION's arguments ARGS, with special treatment if MACRO is non-nil."
(if macro
(names--verbose (eq function 'push)))
(names--message "Edebug-spec of `%s' is %s" function it)
;; Macros where we evaluate all arguments are like functions.
- (if (equal it t)
+ (if (or (equal it t)
+ (memq function names--functionlike-macros))
(names--args-of-function-or-macro function args nil)
;; Macros where nothing is evaluated we can just return.
(if (equal it 0)
;; Defun, defmacro, and defsubst macros are pretty predictable.
(defun names--convert-defmacro (form)
"Special treatment for `defmacro' FORM."
- (let* (;; (names--name-already-prefixed t) ;FIXME: Unused?!
- (name (cadr form))
+ (let* ((name (cadr form))
(spaced-name (names--prepend name))
decl)
(add-to-list 'names--macro name)