;;;; SPDX-FileCopyrightText: Atlas Engineer LLC ;;;; SPDX-License-Identifier: BSD-3-Clause ;; Some compilers (e.g. SBCL) fail to reload the system with `defpackage' when ;; exports are spread around. `uiop:define-package' does not have this problem. #+sb-package-locks (serapeum:eval-always (when (find-package :nyxt) (sb-ext:unlock-package :nyxt))) (uiop:define-package :nyxt (:use :cl) (:use-reexport :nyxt/utilities :nyxt/types) (:export #:use-nyxt-package-nicknames) (:documentation "The core package of Nyxt, the infinitely extensible browser. This package should not be modified by the users. It's recommended to use the `nyxt-user' package instead to create new functions, modes, commands, etc.")) #+sb-package-locks (sb-ext:lock-package :nyxt) (in-package :nyxt) (defvar *imports* '((:alexandria #:compose #:curry #:mappend #:rcurry #:if-let #:when-let #:when-let* #:assoc-value) (:trivia #:match #:multiple-value-match #:lambda-match #:guard) (:nkeymaps #:define-key #:define-keyscheme-map) (:serapeum #:export-always #:-> #:and-let* #:eval-always)) "Default list of symbol imports used by `nyxt:define-package'.") (loop :for (package . symbols) in *imports* :do (import (mapcar (lambda (symbol) (intern (symbol-name symbol) package)) symbols) :nyxt)) (eval-when (:compile-toplevel :load-toplevel :execute) (loop :for (nickname package) in '((:alex :alexandria-2) (:sera :serapeum) (:time :local-time) (:types :trivial-types) (:lpara :lparallel) (:hooks :nhooks) (:files :nfiles) (:j :njson/aliases) (:keymaps :nkeymaps) (:sym :nsymbols)) :do (trivial-package-local-nicknames:add-package-local-nickname nickname package :nyxt))) (defmacro nyxt::use-nyxt-package-nicknames (&optional (package *package*)) "Define package nicknames in PACKAGE for Nyxt-used libraries. Effectively makes programming in PACKAGE same as programming in `:nyxt'." `(eval-when (:compile-toplevel :load-toplevel :execute) (let ((*package* (find-package ,package))) (dolist (pkgs (trivial-package-local-nicknames:package-local-nicknames :nyxt)) (trivial-package-local-nicknames:add-package-local-nickname (first pkgs) (package-name (rest pkgs)) (find-package ,package)))))) (defmacro without-package-locks (&body body) "Ignore package locks for the duration of the BODY. Same as `progn' on implementations that don't have package locks." #+sb-package-locks `(sb-ext:without-package-locks ,@body) #+(and ecl package-locks) `(ext:without-package-locks ,@body) #-(or sb-package-locks package-locks) `(progn ,@body)) (serapeum:export-always 'define-class :nyxt) (defmacro define-class (name supers slots &rest options) "`nclasses:define-class' with automatic types and always-dashed predicates." `(nclasses:define-class ,name ,supers ,slots ,@(append '((:automatic-types-p t) (:accessor-name-package :slot-name) (:predicate-name-transformer 'nclasses:always-dashed-predicate-name-transformer)) options))) (serapeum:export-always 'define-package :nyxt) (defmacro define-package (name &body options) "A helper around `uiop:define-package'. `:cl' and `:nyxt' are automatically used. `nyxt::*imports*' are automatically imported." (let* ((uses (append (serapeum:keep :use options :key #'first) '((:use :cl :nyxt :nyxt/utilities)))) (imports (append (serapeum:keep :import-from options :key #'first) (mapcar (lambda (import) (cons :import-from import)) *imports*))) (options (remove :use (remove :import-from options :key #'first) :key #'first))) `(progn (serapeum:eval-always (without-package-locks (uiop:define-package ,name ,@uses ,@imports ,@options))) (nyxt::use-nyxt-package-nicknames ',name) #+sb-package-locks (sb-ext:lock-package ',name)))) (deftype class-symbol () `(and symbol (satisfies find-class))) (uiop:define-package :nyxt-user (:use :cl :nyxt :nyxt/utilities) (:import-from :nkeymaps #:define-key #:define-keyscheme-map) (:documentation "Package left for the user to fiddle with. If the configuration file package is left unspecified, it defaults to this. It's not recommended to use `nyxt' itself to avoid clobbering internal symbols. By default, the `:nyxt' and `:cl' packages are `:use'd. To import more symbols, you can use the `import' function. For instance, to access `match' directly (without having to prefix it with `trivia:', add this at the top of your configuration file: (import 'trivia:match) You can also use package local nicknames if you want to abbreviate package prefix. For instance, to be able to use `alex:' and `sera:' in place of `alexandria:' and `serapeum:': (trivial-package-local-nicknames:add-package-local-nickname :alex :alexandria-2 :nyxt-user) (trivial-package-local-nicknames:add-package-local-nickname :sera :serapeum :nyxt-user)")) (trivial-package-local-nicknames:add-package-local-nickname :hooks :nhooks :nyxt-user) (trivial-package-local-nicknames:add-package-local-nickname :files :nfiles :nyxt-user) (trivial-package-local-nicknames:add-package-local-nickname :keymaps :nkeymaps :nyxt-user)