;;; sly-messages.el --- Messages, errors, echo-area and visual feedback utils for SLY -*- lexical-binding: t; -*- ;; Copyright (C) 2014 João Távora ;; Author: João Távora ;; Keywords: ;; 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 3 of the License, 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, see . ;;; Commentary: ;; ;;; Code: (require 'cl-lib) (defvar sly--last-message nil) (defun sly-message (format-string &rest args) "Like `message', but use a prefix." (let ((body (apply #'format format-string args))) (setq sly--last-message (format "[sly] %s" body)) (message "%s" sly--last-message))) (add-hook 'echo-area-clear-hook 'sly--message-clear-last-message) (defun sly--message-clear-last-message () (setq sly--last-message nil)) (defun sly-temp-message (wait sit-for format &rest args) "Wait WAIT seconds then display a message for SIT-FOR seconds. A nil value for WAIT means \"now\". SIT-FOR is has the semantincs of `minibuffer-message-timeout', which see." (run-with-timer wait nil #'(lambda () (let ((existing sly--last-message) (text (apply #'format format args))) (if (minibuffer-window-active-p (minibuffer-window)) (let ((minibuffer-message-timeout sit-for)) (minibuffer-message "[sly] %s" text)) (message "[sly] %s" text) ; don't sly-message here (run-with-timer sit-for nil #'(lambda () ;; restore the message (when existing (message "%s" existing))))))))) (defun sly-warning (format-string &rest args) (display-warning '(sly warning) (apply #'format format-string args))) (defun sly-error (format-string &rest args) (apply #'error (format "[sly] %s" format-string) args)) (defun sly-user-error (format-string &rest args) (apply #'user-error (format "[sly] %s" format-string) args)) (defun sly-display-oneliner (format-string &rest format-args) (let* ((msg (apply #'format format-string format-args))) (unless (minibuffer-window-active-p (minibuffer-window)) (sly-message (sly-oneliner msg))))) (defun sly-oneliner (string) "Return STRING truncated to fit in a single echo-area line." (substring string 0 (min (length string) (or (cl-position ?\n string) most-positive-fixnum) (1- (window-width (minibuffer-window)))))) (defun sly-completing-read (prompt choices &optional predicate require-match initial-input hist def inherit-input-method) "Like `completing-read', but tweak `completing-read-function'. Specifically, if the `completion-read-function' has not been tweaked, and `icomplete-mode' is not being used, use `ido-completing-read' to provide a better UX." (let ((completing-read-function (if (and (eq completing-read-function 'completing-read-default) (not icomplete-mode)) #'ido-completing-read completing-read-function))) (completing-read prompt choices predicate require-match initial-input hist def inherit-input-method))) (defun sly-y-or-n-p (format-string &rest args) (let ((prompt (apply #'format (concat "[sly] " format-string) args))) (y-or-n-p prompt))) ;;; Flashing the region ;;; (defvar sly-flash-inhibit nil "If non-nil `sly-flash-region' does nothing") (defvar sly--flash-overlay (make-overlay 0 0)) (overlay-put sly--flash-overlay 'priority 1000) (cl-defun sly-flash-region (start end &key timeout face times (pattern '(0.2))) "Temporarily highlight region from START to END." (if pattern (cl-assert (and (null times) (null timeout)) nil "If PATTERN is supplied, don't supply TIMES or TIMEOUT") (setq pattern (make-list (* 2 times) timeout))) (unless sly-flash-inhibit (let ((buffer (current-buffer))) (move-overlay sly--flash-overlay start end buffer) (cl-labels ((on () (overlay-put sly--flash-overlay 'face (or face 'highlight))) (off () (overlay-put sly--flash-overlay 'face nil)) (relevant-p () (equal (list start end buffer) (list (overlay-start sly--flash-overlay) (overlay-end sly--flash-overlay) (overlay-buffer sly--flash-overlay)))) (onoff () (when (and pattern (relevant-p)) (on) (run-with-timer (pop pattern) nil (lambda () (when (relevant-p) (off) (when pattern (run-with-timer (pop pattern) nil (lambda () (onoff)))))))))) (onoff))))) (provide 'sly-messages) ;;; sly-messages.el ends here