├── .github └── workflows │ └── main.yml ├── .travis.yml ├── Cask ├── README.md ├── flycheck-posframe.el └── screenshots └── flycheck-posframe.png /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | 7 | jobs: 8 | check: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | emacs_version: 14 | - 26.1 15 | - 26.2 16 | - 26.3 17 | - 27.1 18 | - 27.2 19 | - 28.1 20 | - snapshot 21 | # ignore_warnings: 22 | # - true 23 | include: 24 | - emacs_version: snapshot 25 | ignore_warnings: false 26 | steps: 27 | - uses: actions/checkout@v2 28 | - uses: purcell/setup-emacs@master 29 | with: 30 | version: ${{ matrix.emacs_version }} 31 | - uses: leotaku/elisp-check@master 32 | with: 33 | check: melpa 34 | file: flycheck-posframe.el 35 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: emacs-lisp 2 | sudo: false 3 | addons: 4 | apt: 5 | packages: 6 | - autogen 7 | - ca-certificates 8 | - curl 9 | - gcc 10 | - libgmp-dev 11 | - m4 12 | - make 13 | - pkg-config 14 | - xz-utils 15 | cache: 16 | directories: 17 | - $HOME/local 18 | before_install: 19 | - sudo sh travis-ci/travis-gnutls.sh 20 | - gnutls-cli -v 21 | - curl -fsSkL https://gist.github.com/rejeep/ebcd57c3af83b049833b/raw > x.sh && source ./x.sh 22 | - evm install $EVM_EMACS --use --skip 23 | - cask 24 | env: 25 | global: 26 | - PATH=$HOME/local/bin:$PATH 27 | - EVM_EMACS=emacs-git-snapshot-travis 28 | script: 29 | - emacs --version 30 | - cask build 31 | notifications: 32 | email: false 33 | -------------------------------------------------------------------------------- /Cask: -------------------------------------------------------------------------------- 1 | (source gnu) 2 | (source melpa) 3 | 4 | (package-file "flycheck-posframe.el") 5 | 6 | (development 7 | (depends-on "flycheck") 8 | (depends-on "posframe")) 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flycheck-posframe 2 | 3 | [![License GPL 3](https://img.shields.io/badge/license-GPL_3-green.svg)](http://www.gnu.org/licenses/gpl-3.0.txt) 4 | [![MELPA](http://melpa.org/packages/flycheck-posframe-badge.svg)](http://melpa.org/#/flycheck-posframe) 5 | [![Build Status](https://travis-ci.org/alexmurray/flycheck-posframe.svg?branch=master)](https://travis-ci.org/alexmurray/flycheck-posframe) 6 | 7 | Display flycheck error messages via 8 | [posframe](https://github.com/tumashu/posframe). 9 | 10 | ![flycheck-posframe screenshot](screenshots/flycheck-posframe.png) 11 | 12 | ## Installation 13 | 14 | ### MELPA 15 | 16 | The preferred way to install `flycheck-posframe` is via 17 | [MELPA](http://melpa.org) - then you can just M-x package-install RET 18 | flycheck-posframe RET 19 | 20 | To enable then simply add the following to your init file: 21 | 22 | ```emacs-lisp 23 | (with-eval-after-load 'flycheck 24 | (require 'flycheck-posframe) 25 | (add-hook 'flycheck-mode-hook #'flycheck-posframe-mode)) 26 | ``` 27 | 28 | We recommend to use [use-package](https://github.com/jwiegley/use-package) to 29 | make this automatic: 30 | 31 | ```emacs-lisp 32 | (use-package flycheck-posframe 33 | :ensure t 34 | :after flycheck 35 | :config (add-hook 'flycheck-mode-hook #'flycheck-posframe-mode)) 36 | ``` 37 | 38 | ### Manual 39 | 40 | If you would like to install the package manually, download or clone it and 41 | place within Emacs' `load-path`, then you can require it in your init file like 42 | this: 43 | 44 | ```emacs-lisp 45 | (require 'flycheck-posframe) 46 | (add-hook 'flycheck-mode-hook #'flycheck-posframe-mode) 47 | ``` 48 | 49 | NOTE: This will also require the manual installation of `flycheck` if you have 50 | not done so already. 51 | 52 | ## Configuration 53 | 54 | ### Default Pretty Configuration 55 | 56 | Calling `(flycheck-posframe-configure-pretty-defaults)` will configure 57 | `flycheck-posframe` to show warnings and errors with nicer faces (inheriting 58 | from `warning` and `error` respectively), and set the prefix for each to nicer 59 | unicode characters. 60 | 61 | ### Manual Configuration 62 | 63 | There are a few settings which can be configured to customise the display 64 | of error messages. These include the faces which are used to show the error 65 | messages `flycheck-posframe-info-face`, `flycheck-posframe-warning-face` 66 | and `flycheck-posframe-error-face` and a string which is used as the prefix 67 | for each message 68 | `flycheck-posframe-info-prefix``flycheck-posframe-warning-prefix` and 69 | `flycheck-posframe-error-prefix`. The background colour can be specified as 70 | the `background` attribute of the `flycheck-posframe-background-face` 71 | face. `The position, as well as the border width and colour can also be 72 | customised via the `flycheck-posframe-position`, 73 | `flycheck-posframe-border-width` and `flycheck-posframe-border-color` 74 | variables respectively. 75 | 76 | #### `flycheck-posframe-LEVEL-face` 77 | 78 | By default each of `flycheck-posframe-LEVEL-face` inherits from the `default` 79 | face so should appear like the rest of the text in the buffer. If however you 80 | want to ensure error messages stand-out you could configure them to inherit 81 | from the `error` face: 82 | 83 | ``` 84 | (set-face-attribute 'flycheck-posframe-error-face nil :inherit 'error) 85 | ``` 86 | 87 | #### `flycheck-posframe-LEVEL-prefix` 88 | 89 | By default `flycheck-posframe-LEVEL-prefix` is set to "➤ ". If however you 90 | wanted to show each warning message prefixed with the unicode WARNING SIGN symbol 91 | (U+26A0) "⚠ " you could configure it as follows: 92 | 93 | ``` 94 | (setq flycheck-posframe-warning-prefix "\u26a0 ") 95 | ``` 96 | 97 | #### `flycheck-posframe-background-face` 98 | 99 | By default `flycheck-posframe-background-face` inherits from the default 100 | face, so the background colour should be the same as the standard window 101 | frame background colour. This can be customised like any other face (ie. by 102 | using `customize-face` or manually setting the `:background` face 103 | attribute) 104 | 105 | #### `flycheck-posframe-border-face` 106 | 107 | By default `flycheck-posframe-border-face` inherits from the default face, 108 | so the background colour should be the same as the standard foreground 109 | colour. This can be customised like any other face (ie. by using 110 | `customize-face` or manually setting the `:foreground` face attribute) 111 | 112 | #### `flycheck-posframe-border-use-error-face` 113 | 114 | By default `flycheck-posframe-border-use-error-face` is nil. When non-nil, it 115 | will override `flycheck-posframe-border-face` with the foreground of the face 116 | for the highest error level that is shown by `posframe`. 117 | 118 | #### `flycheck-posframe-border-width` 119 | 120 | By default `flycheck-posframe-border-width` is zero but this can be set to 121 | an integer number of pixels to specify the width of the border. 122 | 123 | #### `flycheck-posframe-position` 124 | 125 | By default `flycheck-posframe-position` is set to 126 | `point-bottom-left-corner` so that errors are shown just below point. This 127 | can be customised to any of the existing positions supported by 128 | `posframe`. For example, to display errors at the bottom-left of the 129 | window: 130 | 131 | ``` 132 | (setq flycheck-posframe-position 'window-bottom-left-corner) 133 | ``` 134 | 135 | ## License 136 | 137 | Copyright © 2019 Alex Murray 138 | 139 | Distributed under GNU GPL, version 3. 140 | -------------------------------------------------------------------------------- /flycheck-posframe.el: -------------------------------------------------------------------------------- 1 | ;;; flycheck-posframe.el --- Show flycheck error messages using posframe.el 2 | 3 | ;; Copyright (C) 2021 Alex Murray 4 | 5 | ;; Author: Alex Murray 6 | ;; Maintainer: Alex Murray 7 | ;; URL: https://github.com/alexmurray/flycheck-posframe 8 | ;; Version: 0.9 9 | ;; Package-Requires: ((flycheck "0.24") (emacs "26") (posframe "0.7.0")) 10 | 11 | ;; This file is not part of GNU Emacs. 12 | 13 | ;; This program is free software: you can redistribute it and/or modify 14 | ;; it under the terms of the GNU General Public License as published by 15 | ;; the Free Software Foundation, either version 3 of the License, or 16 | ;; (at your option) any later version. 17 | 18 | ;; This program is distributed in the hope that it will be useful, 19 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | ;; GNU General Public License for more details. 22 | 23 | ;; You should have received a copy of the GNU General Public License 24 | ;; along with this program. If not, see . 25 | 26 | ;;; Commentary: 27 | 28 | ;; Show flycheck error messages using posframe.el 29 | 30 | ;;;; Setup 31 | 32 | ;; (with-eval-after-load 'flycheck 33 | ;; (require 'flycheck-posframe) 34 | ;; (add-hook 'flycheck-mode-hook #'flycheck-posframe-mode)) 35 | 36 | ;;; Code: 37 | (require 'flycheck) 38 | (require 'posframe) 39 | 40 | (defgroup flycheck-posframe nil 41 | "Display Flycheck errors in tooltips using posframe.el." 42 | :prefix "flycheck-posframe-" 43 | :group 'flycheck 44 | :link '(url-link :tag "Github" "https://github.com/alexmurray/flycheck-posframe")) 45 | 46 | (defcustom flycheck-posframe-position 'point-bottom-left-corner 47 | "Where to position the flycheck-posframe frame." 48 | :group 'flycheck-posframe 49 | :type '(choice 50 | (const :tag "Center of the frame" frame-center) 51 | (const :tag "Centered at the top of the frame" frame-top-center) 52 | (const :tag "Left corner at the top of the frame" frame-top-left-corner) 53 | (const :tag "Right corner at the top of the frame" frame-top-right-corner) 54 | (const :tag "Left corner at the bottom of the frame" frame-bottom-left-corner) 55 | (const :tag "Right corner at the bottom of the frame" frame-bottom-right-corner) 56 | (const :tag "Center of the window" window-center) 57 | (const :tag "Left corner at the top of the window" window-top-left-corner) 58 | (const :tag "Right corner at the top of the window" window-top-right-corner) 59 | (const :tag "Left corner at the bottom of the window" window-bottom-left-corner) 60 | (const :tag "Right corner at the bottom of the window" window-bottom-right-corner) 61 | (const :tag "Top left corner of point" point-top-left-corner) 62 | (const :tag "Bottom left corner of point" point-bottom-left-corner)) 63 | :package-version '(flycheck-posframe . "0.6")) 64 | 65 | (defcustom flycheck-posframe-border-width 0 66 | "Width of the border for a flycheck-posframe frame." 67 | :group 'flycheck-posframe 68 | :type 'integer 69 | :package-version '(flycheck-posframe . "0.6")) 70 | 71 | (defcustom flycheck-posframe-border-use-error-face nil 72 | "If non-nil, `flycheck-posframe-border-face' will be overriden by the foreground of the highest error level face." 73 | :group 'flycheck-posframe 74 | :type 'boolean 75 | :package-version '(flycheck-posframe . "0.7")) 76 | 77 | (defcustom flycheck-posframe-prefix "\u27a4 " 78 | "String to be displayed before every default message in posframe." 79 | :group 'flycheck-posframe 80 | :type 'string 81 | :package-version '(flycheck-posframe . "0.3")) 82 | 83 | (defcustom flycheck-posframe-info-prefix flycheck-posframe-prefix 84 | "String to be displayed before every info message in posframe." 85 | :group 'flycheck-posframe 86 | :type 'string 87 | :package-version '(flycheck-posframe . "0.3")) 88 | 89 | (defcustom flycheck-posframe-warning-prefix flycheck-posframe-prefix 90 | "String to be displayed before every warning message in posframe." 91 | :group 'flycheck-posframe 92 | :type 'string 93 | :package-version '(flycheck-posframe . "0.3")) 94 | 95 | (defcustom flycheck-posframe-error-prefix flycheck-posframe-prefix 96 | "String to be displayed before every error message in posframe." 97 | :group 'flycheck-posframe 98 | :type 'string 99 | :package-version '(flycheck-posframe . "0.1")) 100 | 101 | (defface flycheck-posframe-face 102 | '((t :inherit default)) 103 | "The default face to use for displaying messages in posframe." 104 | :group 'flycheck-posframe 105 | :package-version '(flycheck-posframe . "0.2")) 106 | 107 | (defface flycheck-posframe-info-face 108 | '((t :inherit flycheck-posframe-face)) 109 | "The face to use for displaying info messages in posframe." 110 | :group 'flycheck-posframe 111 | :package-version '(flycheck-posframe . "0.3")) 112 | 113 | (defface flycheck-posframe-warning-face 114 | '((t :inherit flycheck-posframe-face)) 115 | "The face to use for displaying warning messages in posframe." 116 | :group 'flycheck-posframe 117 | :package-version '(flycheck-posframe . "0.3")) 118 | 119 | (defface flycheck-posframe-error-face 120 | '((t :inherit flycheck-posframe-face)) 121 | "The face to use for displaying warning messages in posframe." 122 | :group 'flycheck-posframe 123 | :package-version '(flycheck-posframe . "0.3")) 124 | 125 | (defface flycheck-posframe-background-face 126 | '((t)) 127 | "The background color of the flycheck-posframe frame. 128 | Only the `background' is used in this face." 129 | :group 'flycheck-posframe 130 | :package-version '(flycheck-posframe . "0.4")) 131 | 132 | (defface flycheck-posframe-border-face 133 | '((t)) 134 | "The border color of the flycheck-posframe frame. 135 | Only the `foreground' is used in this face." 136 | :group 'flycheck-posframe 137 | :package-version '(flycheck-posframe . "0.6")) 138 | 139 | (defvar flycheck-posframe-buffer "*flycheck-posframe-buffer*" 140 | "The posframe buffer name use by flycheck-posframe.") 141 | 142 | (defvar flycheck-posframe-old-display-function nil 143 | "The former value of `flycheck-display-errors-function'.") 144 | 145 | (defvar flycheck-posframe-last-position nil 146 | "Last position for which a flycheck posframe was displayed.") 147 | 148 | (defun flycheck-posframe-check-position () 149 | "Update `flycheck-posframe-last-position', returning t if there was no change." 150 | (equal flycheck-posframe-last-position 151 | (setq flycheck-posframe-last-position 152 | (list (current-buffer) (buffer-modified-tick) (point))))) 153 | 154 | (defcustom flycheck-posframe-inhibit-functions nil 155 | "Functions to inhibit display of flycheck posframe." 156 | :type 'hook 157 | :group 'flycheck-posframe) 158 | 159 | (defun flycheck-posframe-get-prefix-for-error (err) 160 | "Return the prefix which should be used to display ERR." 161 | (pcase (flycheck-error-level err) 162 | ('info flycheck-posframe-info-prefix) 163 | ('warning flycheck-posframe-warning-prefix) 164 | ('error flycheck-posframe-error-prefix) 165 | (_ flycheck-posframe-prefix))) 166 | 167 | (defun flycheck-posframe-get-face-for-error (err) 168 | "Return the face which should be used to display ERR." 169 | (pcase (flycheck-error-level err) 170 | ('info 'flycheck-posframe-info-face) 171 | ('warning 'flycheck-posframe-warning-face) 172 | ('error 'flycheck-posframe-error-face) 173 | (_ 'flycheck-posframe-face))) 174 | 175 | (defun flycheck-posframe-highest-error-level-face (errs) 176 | "Return the face corresponding to the highest error level from ERRS." 177 | (flycheck-posframe-get-face-for-error (cl-reduce 178 | (lambda (err1 err2) (if (flycheck-error-level-< err1 err2) err2 err1)) 179 | errs))) 180 | 181 | (defun flycheck-posframe-format-error (err) 182 | "Formats ERR for display." 183 | (propertize (concat 184 | (flycheck-posframe-get-prefix-for-error err) 185 | (flycheck-error-format-message-and-id err)) 186 | 'face 187 | `(:inherit ,(flycheck-posframe-get-face-for-error err))) ) 188 | 189 | (defun flycheck-posframe-format-errors (errors) 190 | "Formats ERRORS messages for display." 191 | (let ((messages (sort 192 | (mapcar #'flycheck-posframe-format-error 193 | (delete-dups errors)) 194 | 'string-lessp))) 195 | (mapconcat 'identity messages "\n"))) 196 | 197 | (defun flycheck-posframe-hidehandler (_info) 198 | "Hide posframe if position has changed since last display." 199 | (not (flycheck-posframe-check-position))) 200 | 201 | (defun flycheck-posframe-show-posframe (errors) 202 | "Display ERRORS, using posframe.el library." 203 | (posframe-hide flycheck-posframe-buffer) 204 | (when (and errors 205 | (not (run-hook-with-args-until-success 'flycheck-posframe-inhibit-functions))) 206 | (let ((poshandler (intern (format "posframe-poshandler-%s" flycheck-posframe-position)))) 207 | (unless (functionp poshandler) 208 | (setq poshandler nil)) 209 | (flycheck-posframe-check-position) 210 | (posframe-show 211 | flycheck-posframe-buffer 212 | :string (flycheck-posframe-format-errors errors) 213 | :background-color (face-background 'flycheck-posframe-background-face nil t) 214 | :position (point) 215 | :internal-border-width flycheck-posframe-border-width 216 | :internal-border-color (face-foreground (if flycheck-posframe-border-use-error-face 217 | (flycheck-posframe-highest-error-level-face errors) 218 | 'flycheck-posframe-border-face) nil t) 219 | :poshandler poshandler 220 | :hidehandler #'flycheck-posframe-hidehandler)))) 221 | 222 | ;;;###autoload 223 | (defun flycheck-posframe-configure-pretty-defaults () 224 | "Configure some nicer settings for prettier display." 225 | (setq flycheck-posframe-warning-prefix "\u26a0 ") 226 | (setq flycheck-posframe-error-prefix "\u274c ") 227 | (set-face-attribute 'flycheck-posframe-warning-face nil :inherit 'warning) 228 | (set-face-attribute 'flycheck-posframe-error-face nil :inherit 'error)) 229 | 230 | ;;;###autoload 231 | (define-minor-mode flycheck-posframe-mode 232 | "A minor mode to show Flycheck error messages in a posframe." 233 | :lighter nil 234 | :group 'flycheck-posframe 235 | (cond 236 | ;; Use our display function and remember the old one but only if we haven't 237 | ;; yet configured it, to avoid activating twice. 238 | ((and flycheck-posframe-mode 239 | (not (eq flycheck-display-errors-function 240 | #'flycheck-posframe-show-posframe))) 241 | (setq-local flycheck-posframe-old-display-function 242 | flycheck-display-errors-function) 243 | (setq-local flycheck-display-errors-function 244 | #'flycheck-posframe-show-posframe)) 245 | ;; Reset the display function and remove ourselves from all hooks but only 246 | ;; if the mode is still active. 247 | ((and (not flycheck-posframe-mode) 248 | (eq flycheck-display-errors-function 249 | #'flycheck-posframe-show-posframe)) 250 | (setq-local flycheck-display-errors-function 251 | flycheck-posframe-old-display-function) 252 | (setq-local flycheck-posframe-old-display-function nil)))) 253 | 254 | (provide 'flycheck-posframe) 255 | ;;; flycheck-posframe.el ends here 256 | -------------------------------------------------------------------------------- /screenshots/flycheck-posframe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexmurray/flycheck-posframe/19896b922c76a0f460bf3fe8d8ebc2f9ac9028d8/screenshots/flycheck-posframe.png --------------------------------------------------------------------------------