Emacs/SLY/SLIME: Split configs into separate files.
parent
cee33bff61
commit
6b765a9867
|
@ -17,282 +17,10 @@
|
|||
(when (require 'clhs nil 'noerror)
|
||||
(clhs-setup)))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;; Sly
|
||||
|
||||
;; TODO: Report upstream.
|
||||
;; https://github.com/joaotavora/sly/issues/363
|
||||
;; REVIEW: This probably works for SLIME too.
|
||||
(defvar ambrevar/sly-sbcl-core-extra-packages '(:ambrevar))
|
||||
(defun ambrevar/sly-dump-sbcl-core (&rest extra-package-keywords)
|
||||
"Dump an SBCL core optimized for SLY.
|
||||
EXTRA-PACKAGE-KEYWORDS can be included in the core.
|
||||
The core is stored in `user-emacs-directory'/sly.
|
||||
Return path to the generated core, or nil if it failed to generate.
|
||||
If the core already exists, it's only regenerated if the SBCL version has
|
||||
changed, of when called interactively."
|
||||
(interactive ambrevar/sly-sbcl-core-extra-packages)
|
||||
(cl-flet ((read-bytes (path)
|
||||
(with-temp-buffer
|
||||
(insert-file-contents-literally path)
|
||||
(buffer-substring-no-properties (point-min) (point-max))))
|
||||
(call-process-to-string (command &rest args)
|
||||
(with-temp-buffer
|
||||
(apply #'call-process command nil t nil args)
|
||||
(buffer-string))))
|
||||
(let* ((sbcl-core-dir (expand-file-name "sly/" user-emacs-directory))
|
||||
(sbcl-core (expand-file-name "sbcl.core-for-sly" sbcl-core-dir))
|
||||
(sbcl-core-version (expand-file-name "sbcl.version" sbcl-core-dir))
|
||||
(current-sbcl-version (cadr (split-string
|
||||
(call-process-to-string "sbcl" "--version"))))
|
||||
(lisp-output-buffer (get-buffer-create " *Lisp dump log*")))
|
||||
(when (or (called-interactively-p 'any)
|
||||
(not (file-exists-p sbcl-core-version))
|
||||
(not (version= (car (split-string (read-bytes sbcl-core-version)))
|
||||
current-sbcl-version)))
|
||||
(make-directory sbcl-core-dir :parents)
|
||||
(with-current-buffer lisp-output-buffer
|
||||
(erase-buffer))
|
||||
(apply #'call-process
|
||||
"sbcl" nil (list lisp-output-buffer t) nil
|
||||
"--eval" "(mapc 'require '(sb-bsd-sockets sb-posix sb-introspect sb-cltl2 asdf))"
|
||||
(append
|
||||
(mapcan (lambda (package-keyword)
|
||||
(list "--eval" (format "(require %S)" package-keyword)))
|
||||
extra-package-keywords)
|
||||
(list
|
||||
"--eval" (format "(save-lisp-and-die %S)" sbcl-core)))))
|
||||
(if (not (file-exists-p sbcl-core))
|
||||
(switch-to-buffer-other-window lisp-output-buffer)
|
||||
(with-temp-file sbcl-core-version
|
||||
(insert current-sbcl-version))
|
||||
sbcl-core))))
|
||||
|
||||
(defvar ambrevar/sly-status--last-command-time nil)
|
||||
(make-variable-buffer-local 'ambrevar/sly-status--last-command-time)
|
||||
(defun ambrevar/sly-status--record ()
|
||||
(setq ambrevar/sly-status--last-command-time (current-time)))
|
||||
|
||||
(defun ambrevar/sly-status-formatter (timestamp duration)
|
||||
"Return the status display for `ambrevar/sly-status'.
|
||||
TIMESTAMP is the value returned by `current-time' and DURATION is the floating
|
||||
time the command took to complete in seconds."
|
||||
(format "#[STATUS] End time %s, duration %.3fs\n"
|
||||
(format-time-string "%F %T" timestamp)
|
||||
duration))
|
||||
|
||||
(defcustom ambrevar/sly-status-min-duration 1
|
||||
"If a command takes more time than this, display its status with `ambrevar/sly-status'."
|
||||
:group 'sly
|
||||
:type 'number)
|
||||
|
||||
(defun ambrevar/sly-status (&optional formatter min-duration)
|
||||
"Termination timestamp and duration of command.
|
||||
Status is only returned if command duration was longer than
|
||||
MIN-DURATION \(defaults to `ambrevar/sly-status-min-duration'). FORMATTER
|
||||
is a function of two arguments, TIMESTAMP and DURATION, that
|
||||
returns a string."
|
||||
(if ambrevar/sly-status--last-command-time
|
||||
(let ((duration (time-to-seconds
|
||||
(time-subtract (current-time) ambrevar/sly-status--last-command-time))))
|
||||
(setq ambrevar/sly-status--last-command-time nil)
|
||||
(if (> duration (or min-duration
|
||||
ambrevar/sly-status-min-duration))
|
||||
(funcall (or formatter
|
||||
#'ambrevar/sly-status-formatter)
|
||||
(current-time)
|
||||
duration)
|
||||
""))
|
||||
(progn
|
||||
(advice-add 'sly-mrepl--send-input-sexp :after #'ambrevar/sly-status--record)
|
||||
"")))
|
||||
|
||||
(defun ambrevar/sly-prepare-prompt (old-func &rest args)
|
||||
(let ((package (nth 0 args))
|
||||
(new-prompt (format "%s%s\n%s"
|
||||
(ambrevar/sly-status)
|
||||
(abbreviate-file-name default-directory)
|
||||
(nth 1 args)))
|
||||
(error-level (nth 2 args))
|
||||
(condition (nth 3 args)))
|
||||
(funcall old-func package new-prompt error-level condition)))
|
||||
|
||||
(defun ambrevar/sly-mrepl-previous-prompt ()
|
||||
"Go to the beginning of the previous REPL prompt."
|
||||
(interactive)
|
||||
;; This has two wrinkles around the first prompt: (1) when going to
|
||||
;; the first prompt it leaves point at column 0 (1) when called from
|
||||
;; frist prompt goes to beginning of buffer. The correct fix is to
|
||||
;; patch comint.el's comint-next-prompt and comint-previous-prompt
|
||||
;; anyway...
|
||||
(let* ((inhibit-field-text-motion t)
|
||||
(pos (previous-single-char-property-change
|
||||
(previous-single-char-property-change (point)
|
||||
'sly-mrepl--prompt)
|
||||
'sly-mrepl--prompt)))
|
||||
(goto-char pos)
|
||||
(goto-char (line-beginning-position)))
|
||||
(end-of-line))
|
||||
|
||||
(defun ambrevar/sly-mrepl-next-prompt ()
|
||||
"Go to the beginning of the next REPL prompt."
|
||||
(interactive)
|
||||
(let ((pos (next-single-char-property-change (line-beginning-position 2)
|
||||
'sly-mrepl--prompt)))
|
||||
(goto-char pos)
|
||||
(if (get-text-property (point) 'sly-mrepl--prompt)
|
||||
(goto-char (next-single-char-property-change (point)
|
||||
'sly-mrepl--prompt))
|
||||
(point))))
|
||||
|
||||
(with-eval-after-load 'sly
|
||||
(require 'patch-sly)
|
||||
(advice-add 'sly-mrepl--insert-prompt :around #'ambrevar/sly-prepare-prompt)
|
||||
|
||||
(advice-add 'sly-mrepl-next-prompt :override #'ambrevar/sly-mrepl-next-prompt)
|
||||
(advice-add 'sly-mrepl-previous-prompt :override #'ambrevar/sly-mrepl-previous-prompt)
|
||||
|
||||
(when (executable-find "lisp-repl-core-dumper")
|
||||
;; Warning: ,restart-lisp does not take changes into account, the buffer must be re-created.
|
||||
(setq sly-lisp-implementations
|
||||
`((sbcl-ambrevar ("lisp-repl-core-dumper" "sbcl" "ambrevar"))
|
||||
(sbcl ("lisp-repl-core-dumper" "sbcl"))
|
||||
;; Simple REPL environment (no container):
|
||||
(sbcl-nyxt ("guix" "environment" "--pure"
|
||||
"--preserve=^PERSONAL$" ; To find personal config, like engines and bookmarks.
|
||||
"-l" ,(expand-file-name "~/common-lisp/nyxt/build-scripts/guix.scm")
|
||||
;; glib is needed to export GIO_EXTRA_MODULES.
|
||||
"--ad-hoc" "glib" "glib-networking" "gsettings-desktop-schemas"
|
||||
"gnupg" "--" "sbcl"))
|
||||
;; Faster, but not pure. TODO: Can we purify it? Run it in a container?
|
||||
(sbcl-nyxt-fast
|
||||
(lambda ()
|
||||
;; TODO: Replace root when source has changed?
|
||||
(let ((root (expand-file-name "~/.guix-temp-profiles/nyxt"))
|
||||
(cache (expand-file-name "~/.cache/lisp-repl-core-nyxt")))
|
||||
(unless (file-exists-p root)
|
||||
(make-directory (file-name-directory root) :parents)
|
||||
(call-process "guix" nil nil nil
|
||||
"environment" "--pure"
|
||||
"--preserve=^PERSONAL$" ; To find personal config, like engines and bookmarks.
|
||||
"-r" root
|
||||
"-l" (expand-file-name "~/common-lisp/nyxt/build-scripts/guix.scm")
|
||||
"--ad-hoc" "glib" "glib-networking" "gsettings-desktop-schemas"
|
||||
;; "nss-certs" ; Only needed in containers.
|
||||
;; "libfixposix" ; TODO: We should not need this.
|
||||
"gnupg"
|
||||
"coreutils"
|
||||
"lisp-repl-core-dumper"
|
||||
"--" "env" (concat "LISP_REPL_CORE_PATH=" cache)
|
||||
"lisp-repl-core-dumper" "sbcl"))
|
||||
;; TODO: Include Nyxt Lisp deps in core dump?
|
||||
`(("bash" "-c" ,(concat
|
||||
(format "source '%s/etc/profile'" root)
|
||||
" && LISP_REPL_CORE_PATH=" cache
|
||||
" lisp-repl-core-dumper sbcl"))))))
|
||||
(sbcl-nyxt-site ("guix" "environment" "--pure"
|
||||
"-m" ,(expand-file-name "~/common-lisp/nyxt-site/guix-manifest.scm")
|
||||
"--" "sbcl"))
|
||||
(ccl ("lisp-repl-core-dumper" "ccl"))
|
||||
(clisp ("lisp-repl-core-dumper" "clisp"))
|
||||
(ecl ("ecl")))))
|
||||
|
||||
(setq sly-connection-update-interval 0.1)
|
||||
|
||||
(with-eval-after-load 'sly-mrepl
|
||||
(set-face-attribute 'sly-mrepl-output-face nil :inherit 'default :foreground)
|
||||
(setq sly-mrepl-history-file-name (expand-file-name "sly-mrepl-history" user-emacs-directory))
|
||||
;; While `,i RET` is short enough, it's one more key away in Evil insert state:
|
||||
(define-key sly-mrepl-mode-map (kbd "C-c M-p") 'sly-mrepl-set-package)
|
||||
(define-key sly-mrepl-mode-map (kbd "C-c M-o") 'sly-mrepl-clear-repl))
|
||||
|
||||
(defun ambrevar/sly-load-reload-system ()
|
||||
(interactive)
|
||||
(funcall
|
||||
(if (sly-eval `(slynk-asdf:asdf-system-loaded-p ,(intern (sly-current-package))))
|
||||
#'sly-asdf-reload-system
|
||||
#'sly-asdf-load-system)
|
||||
(intern (sly-current-package))))
|
||||
(define-key lisp-mode-map (kbd "<f6>") 'ambrevar/sly-load-reload-system)
|
||||
|
||||
(defun ambrevar/sly-colorize-buffer (str)
|
||||
"Useful for colorized output like the tests of Prove."
|
||||
(ansi-color-apply str))
|
||||
(add-hook 'sly-mrepl-output-filter-functions 'ambrevar/sly-colorize-buffer)
|
||||
|
||||
(defun ambrevar/indent-and-helm-company (arg)
|
||||
"Indent then call `helm-company'.
|
||||
Good substitute for `sly-mrepl-indent-and-complete-symbol'."
|
||||
(interactive "P")
|
||||
(indent-for-tab-command arg)
|
||||
(helm-company))
|
||||
|
||||
(setq sly-command-switch-to-existing-lisp 'always)
|
||||
(add-hook 'sly-mrepl-hook #'ambrevar/init-lispy)
|
||||
(add-hook 'sly-mrepl-hook #'rainbow-delimiters-mode)
|
||||
;; REVIEW: With Emacs 27 we can:
|
||||
;; (customize-set-variable 'helm-completion-style 'emacs)
|
||||
;; (add-to-list 'completion-styles 'backend)
|
||||
(when (require 'helm-sly nil 'noerror)
|
||||
;; (add-hook 'sly-mrepl-hook #'helm-sly-disable-internal-completion)
|
||||
;; REVIEW: Company completion has the benefit of having annotations.
|
||||
(when (require 'helm-company nil :noerror)
|
||||
(add-hook 'lisp-mode-hook #'company-mode)
|
||||
(define-key lisp-mode-map (kbd "<tab>") 'ambrevar/indent-and-helm-company)
|
||||
(define-key lisp-mode-map (kbd "M-<tab>") 'ambrevar/indent-and-helm-company)
|
||||
(defun ambrevar/sly-set-keys ()
|
||||
(define-key sly-mrepl-mode-map (kbd "<tab>") 'ambrevar/indent-and-helm-company)
|
||||
(define-key sly-mrepl-mode-map (kbd "M-<tab>") 'ambrevar/indent-and-helm-company))
|
||||
(add-hook 'sly-mrepl-hook #'ambrevar/sly-set-keys)
|
||||
(add-hook 'sly-mrepl-hook #'company-mode))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;; SLIME
|
||||
(defun ambrevar/slime-rainbow-init ()
|
||||
(font-lock-mode -1)
|
||||
(rainbow-delimiters-mode)
|
||||
(font-lock-mode))
|
||||
(require 'init-sly))
|
||||
|
||||
(with-eval-after-load 'slime
|
||||
;; REVIEW: Fix issue https://github.com/slime/slime/issues/523:
|
||||
;; Remove with SLIME 2.25.
|
||||
(setq slime-defpackage-regexp
|
||||
"^(\\(cl:\\|common-lisp:\\|uiop:\\)?\\(defpackage\\|define-package\\)\\>[ \t']*")
|
||||
|
||||
(setq slime-lisp-implementations
|
||||
'((sbcl ("sbcl" "--noinform"))
|
||||
(ccl ("ccl"))
|
||||
(ecl ("ecl"))))
|
||||
(let ((slime-extra '(slime-fancy
|
||||
;; slime-banner
|
||||
slime-mrepl
|
||||
slime-xref-browser
|
||||
;; slime-highlight-edits ; A bit slow...
|
||||
slime-sprof
|
||||
slime-quicklisp
|
||||
slime-asdf
|
||||
slime-indentation)))
|
||||
;; TODO: Fix slime-repl-ansi-color.
|
||||
;; (when (require 'slime-repl-ansi-color nil t)
|
||||
;; (add-to-list 'slime-extra 'slime-repl-ansi-color)
|
||||
;; (setq slime-repl-ansi-color t))
|
||||
|
||||
;; slime-company should not be `require'd, see
|
||||
;; https://github.com/anwyn/slime-company/issues/11.
|
||||
(when (ignore-errors (find-library-name "slime-company"))
|
||||
(add-to-list 'slime-extra 'slime-company))
|
||||
(define-key slime-editing-map (kbd "C-c C-d C-h") 'slime-documentation-lookup)
|
||||
(slime-setup slime-extra)
|
||||
(add-hook 'slime-repl-mode-hook 'ambrevar/init-lispy)
|
||||
(add-hook 'slime-repl-mode-hook #'ambrevar/slime-rainbow-init)))
|
||||
|
||||
(with-eval-after-load 'sly
|
||||
(when (require 'helm-sly nil 'noerror)
|
||||
(global-helm-sly-mode)
|
||||
(add-to-list 'helm-source-names-using-follow "Lisp xrefs"))
|
||||
|
||||
(when (require 'helm-slime nil 'noerror)
|
||||
(global-helm-slime-mode)
|
||||
(add-to-list 'helm-source-names-using-follow "SLIME xrefs")))
|
||||
(require 'init-slime))
|
||||
|
||||
(provide 'init-lisp)
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
(defun ambrevar/slime-rainbow-init ()
|
||||
(font-lock-mode -1)
|
||||
(rainbow-delimiters-mode)
|
||||
(font-lock-mode))
|
||||
|
||||
;; REVIEW: Fix issue https://github.com/slime/slime/issues/523:
|
||||
;; Remove with SLIME 2.25.
|
||||
(setq slime-defpackage-regexp
|
||||
"^(\\(cl:\\|common-lisp:\\|uiop:\\)?\\(defpackage\\|define-package\\)\\>[ \t']*")
|
||||
|
||||
(setq slime-lisp-implementations
|
||||
'((sbcl ("sbcl" "--noinform"))
|
||||
(ccl ("ccl"))
|
||||
(ecl ("ecl"))))
|
||||
(let ((slime-extra '(slime-fancy
|
||||
;; slime-banner
|
||||
slime-mrepl
|
||||
slime-xref-browser
|
||||
;; slime-highlight-edits ; A bit slow...
|
||||
slime-sprof
|
||||
slime-quicklisp
|
||||
slime-asdf
|
||||
slime-indentation)))
|
||||
;; TODO: Fix slime-repl-ansi-color.
|
||||
;; (when (require 'slime-repl-ansi-color nil t)
|
||||
;; (add-to-list 'slime-extra 'slime-repl-ansi-color)
|
||||
;; (setq slime-repl-ansi-color t))
|
||||
|
||||
;; slime-company should not be `require'd, see
|
||||
;; https://github.com/anwyn/slime-company/issues/11.
|
||||
(when (ignore-errors (find-library-name "slime-company"))
|
||||
(add-to-list 'slime-extra 'slime-company))
|
||||
(define-key slime-editing-map (kbd "C-c C-d C-h") 'slime-documentation-lookup)
|
||||
(slime-setup slime-extra)
|
||||
(add-hook 'slime-repl-mode-hook 'ambrevar/init-lispy)
|
||||
(add-hook 'slime-repl-mode-hook #'ambrevar/slime-rainbow-init))
|
||||
|
||||
(when (require 'helm-slime nil :noerror)
|
||||
(global-helm-slime-mode)
|
||||
(add-to-list 'helm-source-names-using-follow "SLIME xrefs"))
|
||||
|
||||
(provide 'init-slime)
|
|
@ -0,0 +1,188 @@
|
|||
(require 'patch-sly)
|
||||
|
||||
(when (executable-find "lisp-repl-core-dumper")
|
||||
;; Warning: ,restart-lisp does not take changes into account, the buffer must be re-created.
|
||||
(setq sly-lisp-implementations
|
||||
`((sbcl-ambrevar ("lisp-repl-core-dumper" "sbcl" "ambrevar"))
|
||||
(sbcl ("lisp-repl-core-dumper" "sbcl"))
|
||||
;; Simple REPL environment (no container):
|
||||
(sbcl-nyxt ("guix" "environment" "--pure"
|
||||
"--preserve=^PERSONAL$" ; To find personal config, like engines and bookmarks.
|
||||
"-l" ,(expand-file-name "~/common-lisp/nyxt/build-scripts/guix.scm")
|
||||
;; glib is needed to export GIO_EXTRA_MODULES.
|
||||
"--ad-hoc" "glib" "glib-networking" "gsettings-desktop-schemas"
|
||||
"gnupg" "--" "sbcl"))
|
||||
;; Faster, but not pure. TODO: Can we purify it? Run it in a container?
|
||||
(sbcl-nyxt-fast
|
||||
(lambda ()
|
||||
;; TODO: Replace root when source has changed?
|
||||
(let ((root (expand-file-name "~/.guix-temp-profiles/nyxt"))
|
||||
(cache (expand-file-name "~/.cache/lisp-repl-core-nyxt")))
|
||||
(unless (file-exists-p root)
|
||||
(make-directory (file-name-directory root) :parents)
|
||||
(call-process "guix" nil nil nil
|
||||
"environment" "--pure"
|
||||
"--preserve=^PERSONAL$" ; To find personal config, like engines and bookmarks.
|
||||
"-r" root
|
||||
"-l" (expand-file-name "~/common-lisp/nyxt/build-scripts/guix.scm")
|
||||
"--ad-hoc" "glib" "glib-networking" "gsettings-desktop-schemas"
|
||||
;; "nss-certs" ; Only needed in containers.
|
||||
;; "libfixposix" ; TODO: We should not need this.
|
||||
"gnupg"
|
||||
"coreutils"
|
||||
"lisp-repl-core-dumper"
|
||||
"--" "env" (concat "LISP_REPL_CORE_PATH=" cache)
|
||||
"lisp-repl-core-dumper" "sbcl"))
|
||||
;; TODO: Include Nyxt Lisp deps in core dump?
|
||||
`(("bash" "-c" ,(concat
|
||||
(format "source '%s/etc/profile'" root)
|
||||
" && LISP_REPL_CORE_PATH=" cache
|
||||
" lisp-repl-core-dumper sbcl"))))))
|
||||
(sbcl-nyxt-site ("guix" "environment" "--pure"
|
||||
"-m" ,(expand-file-name "~/common-lisp/nyxt-site/guix-manifest.scm")
|
||||
"--" "sbcl"))
|
||||
(ccl ("lisp-repl-core-dumper" "ccl"))
|
||||
(clisp ("lisp-repl-core-dumper" "clisp"))
|
||||
(ecl ("ecl")))))
|
||||
|
||||
(setq sly-connection-update-interval 0.1)
|
||||
|
||||
(with-eval-after-load 'sly
|
||||
(when (require 'helm-sly nil :noerror)
|
||||
(global-helm-sly-mode)
|
||||
(add-to-list 'helm-source-names-using-follow "Lisp xrefs")))
|
||||
|
||||
(with-eval-after-load 'sly-mrepl
|
||||
(set-face-attribute 'sly-mrepl-output-face nil :inherit 'default :foreground)
|
||||
(setq sly-mrepl-history-file-name (expand-file-name "sly-mrepl-history" user-emacs-directory))
|
||||
;; While `,i RET` is short enough, it's one more key away in Evil insert state:
|
||||
(define-key sly-mrepl-mode-map (kbd "C-c M-p") 'sly-mrepl-set-package)
|
||||
(define-key sly-mrepl-mode-map (kbd "C-c M-o") 'sly-mrepl-clear-repl))
|
||||
|
||||
(defun ambrevar/sly-load-reload-system ()
|
||||
(interactive)
|
||||
(funcall
|
||||
(if (sly-eval `(slynk-asdf:asdf-system-loaded-p ,(intern (sly-current-package))))
|
||||
#'sly-asdf-reload-system
|
||||
#'sly-asdf-load-system)
|
||||
(intern (sly-current-package))))
|
||||
(define-key lisp-mode-map (kbd "<f6>") 'ambrevar/sly-load-reload-system)
|
||||
|
||||
(defun ambrevar/sly-colorize-buffer (str)
|
||||
"Useful for colorized output like the tests of Prove."
|
||||
(ansi-color-apply str))
|
||||
(add-hook 'sly-mrepl-output-filter-functions 'ambrevar/sly-colorize-buffer)
|
||||
|
||||
(defun ambrevar/indent-and-helm-company (arg)
|
||||
"Indent then call `helm-company'.
|
||||
Good substitute for `sly-mrepl-indent-and-complete-symbol'."
|
||||
(interactive "P")
|
||||
(indent-for-tab-command arg)
|
||||
(helm-company))
|
||||
|
||||
(setq sly-command-switch-to-existing-lisp 'always)
|
||||
(add-hook 'sly-mrepl-hook #'ambrevar/init-lispy)
|
||||
(add-hook 'sly-mrepl-hook #'rainbow-delimiters-mode)
|
||||
;; REVIEW: With Emacs 27 we can:
|
||||
;; (customize-set-variable 'helm-completion-style 'emacs)
|
||||
;; (add-to-list 'completion-styles 'backend)
|
||||
(when (require 'helm-sly nil 'noerror)
|
||||
;; (add-hook 'sly-mrepl-hook #'helm-sly-disable-internal-completion)
|
||||
;; REVIEW: Company completion has the benefit of having annotations.
|
||||
(when (require 'helm-company nil :noerror)
|
||||
(add-hook 'lisp-mode-hook #'company-mode)
|
||||
(define-key lisp-mode-map (kbd "<tab>") 'ambrevar/indent-and-helm-company)
|
||||
(define-key lisp-mode-map (kbd "M-<tab>") 'ambrevar/indent-and-helm-company)
|
||||
(defun ambrevar/sly-set-keys ()
|
||||
(define-key sly-mrepl-mode-map (kbd "<tab>") 'ambrevar/indent-and-helm-company)
|
||||
(define-key sly-mrepl-mode-map (kbd "M-<tab>") 'ambrevar/indent-and-helm-company))
|
||||
(add-hook 'sly-mrepl-hook #'ambrevar/sly-set-keys)
|
||||
(add-hook 'sly-mrepl-hook #'company-mode)))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Prompt customization
|
||||
;; TODO: Upstream!
|
||||
|
||||
(defvar ambrevar/sly-status--last-command-time nil)
|
||||
(make-variable-buffer-local 'ambrevar/sly-status--last-command-time)
|
||||
(defun ambrevar/sly-status--record ()
|
||||
(setq ambrevar/sly-status--last-command-time (current-time)))
|
||||
|
||||
(defun ambrevar/sly-status-formatter (timestamp duration)
|
||||
"Return the status display for `ambrevar/sly-status'.
|
||||
TIMESTAMP is the value returned by `current-time' and DURATION is the floating
|
||||
time the command took to complete in seconds."
|
||||
(format "#[STATUS] End time %s, duration %.3fs\n"
|
||||
(format-time-string "%F %T" timestamp)
|
||||
duration))
|
||||
|
||||
(defcustom ambrevar/sly-status-min-duration 1
|
||||
"If a command takes more time than this, display its status with `ambrevar/sly-status'."
|
||||
:group 'sly
|
||||
:type 'number)
|
||||
|
||||
(defun ambrevar/sly-status (&optional formatter min-duration)
|
||||
"Termination timestamp and duration of command.
|
||||
Status is only returned if command duration was longer than
|
||||
MIN-DURATION \(defaults to `ambrevar/sly-status-min-duration'). FORMATTER
|
||||
is a function of two arguments, TIMESTAMP and DURATION, that
|
||||
returns a string."
|
||||
(if ambrevar/sly-status--last-command-time
|
||||
(let ((duration (time-to-seconds
|
||||
(time-subtract (current-time) ambrevar/sly-status--last-command-time))))
|
||||
(setq ambrevar/sly-status--last-command-time nil)
|
||||
(if (> duration (or min-duration
|
||||
ambrevar/sly-status-min-duration))
|
||||
(funcall (or formatter
|
||||
#'ambrevar/sly-status-formatter)
|
||||
(current-time)
|
||||
duration)
|
||||
""))
|
||||
(progn
|
||||
(advice-add 'sly-mrepl--send-input-sexp :after #'ambrevar/sly-status--record)
|
||||
"")))
|
||||
|
||||
(defun ambrevar/sly-prepare-prompt (old-func &rest args)
|
||||
(let ((package (nth 0 args))
|
||||
(new-prompt (format "%s%s\n%s"
|
||||
(ambrevar/sly-status)
|
||||
(abbreviate-file-name default-directory)
|
||||
(nth 1 args)))
|
||||
(error-level (nth 2 args))
|
||||
(condition (nth 3 args)))
|
||||
(funcall old-func package new-prompt error-level condition)))
|
||||
|
||||
(defun ambrevar/sly-mrepl-previous-prompt ()
|
||||
"Go to the beginning of the previous REPL prompt."
|
||||
(interactive)
|
||||
;; This has two wrinkles around the first prompt: (1) when going to
|
||||
;; the first prompt it leaves point at column 0 (1) when called from
|
||||
;; frist prompt goes to beginning of buffer. The correct fix is to
|
||||
;; patch comint.el's comint-next-prompt and comint-previous-prompt
|
||||
;; anyway...
|
||||
(let* ((inhibit-field-text-motion t)
|
||||
(pos (previous-single-char-property-change
|
||||
(previous-single-char-property-change (point)
|
||||
'sly-mrepl--prompt)
|
||||
'sly-mrepl--prompt)))
|
||||
(goto-char pos)
|
||||
(goto-char (line-beginning-position)))
|
||||
(end-of-line))
|
||||
|
||||
(defun ambrevar/sly-mrepl-next-prompt ()
|
||||
"Go to the beginning of the next REPL prompt."
|
||||
(interactive)
|
||||
(let ((pos (next-single-char-property-change (line-beginning-position 2)
|
||||
'sly-mrepl--prompt)))
|
||||
(goto-char pos)
|
||||
(if (get-text-property (point) 'sly-mrepl--prompt)
|
||||
(goto-char (next-single-char-property-change (point)
|
||||
'sly-mrepl--prompt))
|
||||
(point))))
|
||||
|
||||
(advice-add 'sly-mrepl--insert-prompt :around #'ambrevar/sly-prepare-prompt)
|
||||
|
||||
(advice-add 'sly-mrepl-next-prompt :override #'ambrevar/sly-mrepl-next-prompt)
|
||||
(advice-add 'sly-mrepl-previous-prompt :override #'ambrevar/sly-mrepl-previous-prompt)
|
||||
|
||||
(provide 'init-sly)
|
Loading…
Reference in New Issue