@me Ok, here's a working(?) proof-of-concept for
#emacs namespaces: https://git.sr.ht/~thuna/namespace-el
In order to use it, go to your scratch buffer (or just any elisp
buffer), do M-x enable-namespace. Then, define a namespace via
(define-namespace :foo
(:use nil)
(:export my-symbols...))
where (:use nil) serves the same purpose as (:use :cl) in Common Lisp.
Afterwards, you can either do
(in-namespace :foo)
...
or
(with-namespace :foo
...)
You should also be able to file-locally set `buffer-namespace', but I
haven't tried it.
Here's a working snippet:
(define-namespace :foo
(:use nil)
(:export bar setq nil))
(define-namespace :baz
(:use :foo)
(:export bar))
(with-namespace :foo
(setq foo 2))
foo:bar ;; => 2
(with-namespace :baz
(setq bar 5)
(setq quux 10))
foo:bar ;; => 5
baz:bar ;; => 5
baz:quux ;; => 10
although you'll need to patch elisp--preceding-sexp for C-x C-e to see
the individual values. Here's the code you need to evaluate (at least
on my version, I suggest trying this in a fresh emacs in case
something goes wrong): https://0x0.st/84sj.txt
@me I have fleshed it out more (or rather, ported
over CL's packages): https://git.sr.ht/~thuna/cl-package (this is
still the same repo, but I've changed the name).
The demo is:
- require cl-package / load cl-package.el
- require cl-package-reader / load cl-package-reader.el
- go to a new buffer (or the scratch buffer)
- M-x cl-package-activate-reader RET
- Insert the snippet
- Do eval-buffer, or after applying the same patch as before (replace `(read...)' with `(funcall load-read-function...)' in `elisp--preceding-sexp') go through each form (you can skip cl-in-package) one by one with C-x C-e
- Have fun
The snippet is:
(cl-defpackage test
(:use :global)
(:shadow baz)
(:export baz))
(cl-in-package :test)
(setq test:baz 10)
(message "%S" test:baz) ;; => 10
(intern-soft "test:baz") ;; => nil
Where the second nil means that no symbol with the literal name
"test:baz" exists in emacs, and that the symbol we're referring to
with test:baz is something else entirely, which you can also see with:
(eq (intern "test:baz") 'test:baz) => nil
There are probably a lot of problems, some of which are:
- defpackage does not play nice with redefinitions (or rather, you can't do it at all), just pop cl-package-registry (but not completely, always leave the last item, if you want to fully reset it set it to (list obarray)) and redefine it again
- I have the elisp runtime in the pseudo-package :global, but trying to use :global in your own package will force it to check all (tens of thousands of!) symbols for conflicts, so it'll take a couple seconds during the defpackage in the snippet. I will later define packages containing the various elisp packages for proper modularity, so it should get better
- Once you evaluate cl-in-package, eval-buffer starts with cl-in-package, which it probably shouldn't be doing, but I don't know
and who knows how many more!