diff options
| author | João Távora | 2017-10-10 02:14:46 +0100 |
|---|---|---|
| committer | João Távora | 2017-10-10 13:08:41 +0100 |
| commit | 1c2e1884407f6210b0787e76e0707049e2babc8f (patch) | |
| tree | 44f48b1f20c9199bdb7cba4fa9e07d565d67c94b | |
| parent | 0f7f677f82677a29a7f5abacbb1045cd26c003c5 (diff) | |
| download | emacs-1c2e1884407f6210b0787e76e0707049e2babc8f.tar.gz emacs-1c2e1884407f6210b0787e76e0707049e2babc8f.zip | |
Add full documentation on new Flymake API
Also, as a minor addition to this API, set flymake-text
on the diagnostic overlay. This enables a good example in
the section "Customization Flymake annotations".
* doc/misc/flymake.texi (Overview of Flymake)
(Syntax check statuses): Rework.
(Backend exceptions): Rename from "Troubleshooting"
(Customizable variables): Add flymake-start-on-flymake-mode. Rework.
(Extending Flymake): Write chapter.
(Customizing Flymake annotations, Flymake backends)
(Flymake utility functions, An annotated example backend):
New sections and subsections
* lisp/progmodes/flymake.el (flymake-diagnostic-functions)
(flymake-diagnostic-types-alist): Rework docstring.
(flymake--highlight-line): Set and use flymake-text property in overlay.
(flymake-goto-next-error, flymake-goto-prev-error): Fix funny quotes.
| -rw-r--r-- | doc/misc/flymake.texi | 464 | ||||
| -rw-r--r-- | lisp/progmodes/flymake.el | 41 |
2 files changed, 444 insertions, 61 deletions
diff --git a/doc/misc/flymake.texi b/doc/misc/flymake.texi index a85fe4a30e1..9207ed496f7 100644 --- a/doc/misc/flymake.texi +++ b/doc/misc/flymake.texi | |||
| @@ -66,23 +66,11 @@ modify this GNU manual.'' | |||
| 66 | Flymake is a universal on-the-fly buffer checker implemented as an | 66 | Flymake is a universal on-the-fly buffer checker implemented as an |
| 67 | Emacs minor mode. When enabled, Flymake visually annotates the buffer | 67 | Emacs minor mode. When enabled, Flymake visually annotates the buffer |
| 68 | with diagnostic information coming from one or more different sources, | 68 | with diagnostic information coming from one or more different sources, |
| 69 | or @emph{backends}. | 69 | or @dfn{backends}. |
| 70 | |||
| 71 | Historically, Flymake used to accept diagnostics from a single, albeit | ||
| 72 | reasonably flexible, backend. | ||
| 73 | |||
| 74 | This backend isn't (yet) obsolete and so is still available as a | ||
| 75 | fallback and active by default(@pxref{The legacy Proc backend}). It works by | ||
| 76 | selecting a syntax check tool from a preconfigured list (compiler for | ||
| 77 | C++ files, @code{perl} for perl files, etc.), and executing it in the | ||
| 78 | background, passing it a temporary file which is a copy of the current | ||
| 79 | buffer, and parsing the output for known error/warning message | ||
| 80 | patterns. | ||
| 81 | 70 | ||
| 82 | Flymake annotates the buffer by highlighting problematic buffer | 71 | Flymake annotates the buffer by highlighting problematic buffer |
| 83 | regions with a special space. It also displays an overall buffer | 72 | regions with a special space. It displays an overall buffer status in |
| 84 | status in the mode line. Status information displayed by Flymake | 73 | the mode line containing totals for different types of diagnostics. |
| 85 | contains totals for different types of diagnostics. | ||
| 86 | 74 | ||
| 87 | @code{flymake-goto-next-error} and @code{flymake-goto-prev-error} are | 75 | @code{flymake-goto-next-error} and @code{flymake-goto-prev-error} are |
| 88 | commands that allow easy navigation to the next/previous erroneous | 76 | commands that allow easy navigation to the next/previous erroneous |
| @@ -97,14 +85,30 @@ and @kbd{M-p} in @code{flymake-mode}, by adding to your init file: | |||
| 97 | Syntax check is done ``on-the-fly''. It is started whenever | 85 | Syntax check is done ``on-the-fly''. It is started whenever |
| 98 | 86 | ||
| 99 | @itemize @bullet | 87 | @itemize @bullet |
| 100 | @item @code{flymake-mode} is started; | 88 | @item @code{flymake-mode} is started, unless |
| 101 | @item a newline character is added to the buffer; | 89 | @code{flymake-start-on-flymake-mode} is nil. |
| 102 | @item some changes were made to the buffer more than @code{0.5} seconds ago (the | 90 | |
| 103 | delay is configurable). | 91 | @item a newline character is added to the buffer, unless |
| 92 | @code{flymake-start-syntax-check-on-newline} is nil. | ||
| 93 | |||
| 94 | @item some changes were made to the buffer more than @code{0.5} | ||
| 95 | seconds ago (the delay is configurable in | ||
| 96 | @code{flymake-no-changes-timeout}). | ||
| 104 | @end itemize | 97 | @end itemize |
| 105 | 98 | ||
| 106 | Flymake is a universal syntax checker in the sense that it's easily | 99 | Flymake is a universal syntax checker in the sense that it's easily |
| 107 | extended to support new backends. @xref{Customizable variables}. | 100 | extended to support new backends @pxref{Extending Flymake}. |
| 101 | |||
| 102 | Historically, Flymake used to accept diagnostics from a single, albeit | ||
| 103 | reasonably flexible, backend. | ||
| 104 | |||
| 105 | This backend isn't (yet) obsolete and so is still available as a | ||
| 106 | fallback and active by default(@pxref{The legacy Proc backend}). It works by | ||
| 107 | selecting a syntax check tool from a preconfigured list (compiler for | ||
| 108 | C++ files, @code{perl} for perl files, etc.), and executing it in the | ||
| 109 | background, passing it a temporary file which is a copy of the current | ||
| 110 | buffer, and parsing the output for known error/warning message | ||
| 111 | patterns. | ||
| 108 | 112 | ||
| 109 | @node Installing Flymake | 113 | @node Installing Flymake |
| 110 | @chapter Installing | 114 | @chapter Installing |
| @@ -123,7 +127,7 @@ nothing to do by way of installation. | |||
| 123 | * Running the syntax check:: | 127 | * Running the syntax check:: |
| 124 | * Navigating to error lines:: @c * Viewing error messages:: | 128 | * Navigating to error lines:: @c * Viewing error messages:: |
| 125 | * Syntax check statuses:: | 129 | * Syntax check statuses:: |
| 126 | * Troubleshooting:: | 130 | * Backend exceptions:: |
| 127 | * Customizable variables:: | 131 | * Customizable variables:: |
| 128 | @end menu | 132 | @end menu |
| 129 | 133 | ||
| @@ -151,7 +155,7 @@ line in @code{.emacs}: | |||
| 151 | When @code{flymake-mode} is active, syntax check is started | 155 | When @code{flymake-mode} is active, syntax check is started |
| 152 | automatically on any of the three conditions mentioned above. Syntax | 156 | automatically on any of the three conditions mentioned above. Syntax |
| 153 | check can also be started manually by using the @code{flymake-start} | 157 | check can also be started manually by using the @code{flymake-start} |
| 154 | function. | 158 | command. |
| 155 | 159 | ||
| 156 | @node Navigating to error lines | 160 | @node Navigating to error lines |
| 157 | @section Navigating to error lines | 161 | @section Navigating to error lines |
| @@ -160,17 +164,17 @@ function. | |||
| 160 | After syntax check is completed, lines for which at least one error or | 164 | After syntax check is completed, lines for which at least one error or |
| 161 | warning has been reported are highlighted, and total number of errors | 165 | warning has been reported are highlighted, and total number of errors |
| 162 | and warning is shown in the mode line. Use the following functions to | 166 | and warning is shown in the mode line. Use the following functions to |
| 163 | navigate the highlighted lines. | 167 | navigate the highlighted lines: |
| 164 | 168 | ||
| 165 | @multitable @columnfractions 0.25 0.75 | 169 | @table @code |
| 166 | 170 | ||
| 167 | @item @code{flymake-goto-next-error} | 171 | @item flymake-goto-next-error |
| 168 | @tab Moves point to the next erroneous line, if any. | 172 | Moves point to the next erroneous line, if any. |
| 169 | 173 | ||
| 170 | @item @code{flymake-goto-prev-error} | 174 | @item flymake-goto-prev-error |
| 171 | @tab Moves point to the previous erroneous line. | 175 | Moves point to the previous erroneous line. |
| 172 | 176 | ||
| 173 | @end multitable | 177 | @end table |
| 174 | 178 | ||
| 175 | If the user option @code{flymake-wrap-around} is active | 179 | If the user option @code{flymake-wrap-around} is active |
| 176 | (@pxref{Customizable variables}), these functions treat diagnostics | 180 | (@pxref{Customizable variables}), these functions treat diagnostics |
| @@ -181,7 +185,7 @@ to the first diagnostic when invoked in the end of the buffer. | |||
| 181 | @section Syntax check statuses | 185 | @section Syntax check statuses |
| 182 | @cindex Syntax check statuses | 186 | @cindex Syntax check statuses |
| 183 | 187 | ||
| 184 | After syntax check is finished, its status is displayed in the mode line. | 188 | While enabled, Flymake displays its status in the mode line. |
| 185 | The following statuses are defined: | 189 | The following statuses are defined: |
| 186 | 190 | ||
| 187 | @multitable @columnfractions 0.25 0.75 | 191 | @multitable @columnfractions 0.25 0.75 |
| @@ -191,8 +195,9 @@ where questioned. | |||
| 191 | 195 | ||
| 192 | @item @code{!} | 196 | @item @code{!} |
| 193 | @tab All the configured Flymake backends have disabled themselves. | 197 | @tab All the configured Flymake backends have disabled themselves. |
| 194 | Left-clicking the ``Flymake'' mode line indicator beings the user | 198 | Left-clicking Flymake's mode line indicator pops up a menu listing the |
| 195 | @code{*Flymake log*} buffer where these situations may be investigated | 199 | option to visit Flymake's log buffer. In this buffer these situations |
| 200 | can be investigated. | ||
| 196 | 201 | ||
| 197 | @item @code{?} | 202 | @item @code{?} |
| 198 | @tab There are no configured Flymake backends in | 203 | @tab There are no configured Flymake backends in |
| @@ -203,12 +208,25 @@ Left-clicking the ``Flymake'' mode line indicator beings the user | |||
| 203 | check process. | 208 | check process. |
| 204 | @end multitable | 209 | @end multitable |
| 205 | 210 | ||
| 206 | @node Troubleshooting | 211 | @node Backend exceptions |
| 207 | @section Troubleshooting | 212 | @section Backend exceptions |
| 208 | @cindex Logging | 213 | @cindex Logging |
| 209 | @cindex Troubleshooting | 214 | @cindex Backend exceptions |
| 215 | |||
| 216 | Some backends may take longer than others to respond or complete, and | ||
| 217 | some may decide to @dfn{disable} themselves if they are not suitable | ||
| 218 | for the current buffer. A disabled backend is not tried again for | ||
| 219 | future checks of the current buffer. | ||
| 220 | |||
| 221 | The commands @code{flymake-reporting-backends}, | ||
| 222 | @code{flymake-running-backends} and @code{flymake-disabled-backends} | ||
| 223 | inform on the specific situation. | ||
| 210 | 224 | ||
| 211 | Flymake uses a simple logging facility for indicating important points | 225 | Toggling @code{flymake-mode} off and on again or invoking |
| 226 | @code{flymake-start} with a prefix argument is one way to reset the | ||
| 227 | disabled backend list so they will be tried again in the next check. | ||
| 228 | |||
| 229 | Flymake also uses a simple logging facility for indicating important points | ||
| 212 | in the control flow. The logging facility sends logging messages to | 230 | in the control flow. The logging facility sends logging messages to |
| 213 | the @file{*Flymake log*} buffer. The information logged can be used for | 231 | the @file{*Flymake log*} buffer. The information logged can be used for |
| 214 | resolving various problems related to Flymake. | 232 | resolving various problems related to Flymake. |
| @@ -220,17 +238,22 @@ and @code{warning-minimum-level} variables. | |||
| 220 | @section Customizable variables | 238 | @section Customizable variables |
| 221 | @cindex Customizable variables | 239 | @cindex Customizable variables |
| 222 | 240 | ||
| 223 | This section summarizes variables used for the configuration of the | 241 | This section summarizes customization variables used for the |
| 224 | Flymake user interface. | 242 | configuration of the Flymake user interface. |
| 225 | 243 | ||
| 226 | @table @code | 244 | @table @code |
| 227 | @item flymake-no-changes-timeout | 245 | @item flymake-no-changes-timeout |
| 228 | If any changes are made to the buffer, syntax check is automatically | 246 | If any changes are made to the buffer, syntax check is automatically |
| 229 | started after @code{flymake-no-changes-timeout} seconds. | 247 | started after this many seconds, unless the user makes another change, |
| 248 | which resets the timer. | ||
| 230 | 249 | ||
| 231 | @item flymake-start-syntax-check-on-newline | 250 | @item flymake-start-syntax-check-on-newline |
| 232 | A boolean flag indicating whether to start syntax check after a | 251 | A boolean flag indicating whether to start syntax check immediately |
| 233 | newline character is added to the buffer. | 252 | after a newline character is added to the buffer. |
| 253 | |||
| 254 | @item flymake-start-on-flymake-mode | ||
| 255 | A boolean flag indicating whether to start syntax check immediately | ||
| 256 | after enabling @code{flymake-mode}. | ||
| 234 | 257 | ||
| 235 | @item flymake-error | 258 | @item flymake-error |
| 236 | A custom face for highlighting regions for which an error has been | 259 | A custom face for highlighting regions for which an error has been |
| @@ -265,6 +288,365 @@ If non-nil, moving to errors with @code{flymake-goto-next-error} and | |||
| 265 | @chapter Extending Flymake | 288 | @chapter Extending Flymake |
| 266 | @cindex Extending Flymake | 289 | @cindex Extending Flymake |
| 267 | 290 | ||
| 291 | Flymake can primarily be extended in one of two ways: | ||
| 292 | |||
| 293 | @enumerate | ||
| 294 | @item | ||
| 295 | By changing the look and feel of the annotations produced by the | ||
| 296 | different backends. | ||
| 297 | |||
| 298 | @item | ||
| 299 | By adding a new buffer-checking backend. | ||
| 300 | @end enumerate | ||
| 301 | |||
| 302 | The following sections discuss each approach in detail: | ||
| 303 | |||
| 304 | @menu | ||
| 305 | * Flymake error types:: | ||
| 306 | * Backend functions:: | ||
| 307 | @end menu | ||
| 308 | |||
| 309 | @node Flymake error types | ||
| 310 | @section Customizing Flymake error types | ||
| 311 | |||
| 312 | The variable @code{flymake-diagnostic-types-alist} is looked up by | ||
| 313 | Flymake every time an annotation for a diagnostic is created in the | ||
| 314 | buffer. Specifically, this variable holds a table of correspondence | ||
| 315 | between symbols designating diagnostic types and an additional | ||
| 316 | sub-table of properties pertaining to each diagnostic type. | ||
| 317 | |||
| 318 | Both tables are laid out in association list (@pxref{Association | ||
| 319 | Lists,,, elisp, The Emacs Lisp Reference Manual}) format, and thus can | ||
| 320 | be conveniently accessed with the functions of the @code{assoc} | ||
| 321 | family. | ||
| 322 | |||
| 323 | You can use any symbol-value association in the properties sub-table, | ||
| 324 | but some symbols have special meaning as to where and how Flymake | ||
| 325 | presents the diagnostic: | ||
| 326 | |||
| 327 | @itemize | ||
| 328 | |||
| 329 | @item @code{bitmap}, an image displayed in the fringe according to | ||
| 330 | @code{flymake-fringe-indicator-position}. The value actually follows | ||
| 331 | the syntax of @code{flymake-error-bitmap}(@pxref{Customizable | ||
| 332 | variables}). It is overridden by any @code{before-string} overlay | ||
| 333 | property. | ||
| 334 | |||
| 335 | @item @code{severity} is a non-negative integer specifying the diagnostic's | ||
| 336 | severity. The higher, the more serious. If the overlay property | ||
| 337 | @code{priority} is not specified, @code{severity} is used to set it | ||
| 338 | and help sort overlapping overlays. | ||
| 339 | |||
| 340 | @item Every property pertaining to overlays (@pxref{Overlay | ||
| 341 | Properties,,, elisp, The Emacs Lisp Reference Manual}), except | ||
| 342 | @code{category} and @code{evaporate}. These properties are used to | ||
| 343 | affect the appearance of Flymake annotations. | ||
| 344 | |||
| 345 | As an example, here's how to make errors (diagnostics of the type | ||
| 346 | @code{:error}) stand out even more prominently in the buffer, by | ||
| 347 | raising the characters with a @code{display} overlay property. | ||
| 348 | |||
| 349 | @example | ||
| 350 | (push '(display . (raise 1.2)) | ||
| 351 | (cdr (assoc :error flymake-diagnostic-types-alist))) | ||
| 352 | @end example | ||
| 353 | |||
| 354 | @item @code{flymake-category} is a symbol whose property list is considered | ||
| 355 | a default for missing values of any other properties. | ||
| 356 | @end itemize | ||
| 357 | |||
| 358 | Three default diagnostic types, @code{:error}, @code{:warning} and | ||
| 359 | @code{:note} are predefined in | ||
| 360 | @code{flymake-diagnostic-types-alist}. By default each lists a single | ||
| 361 | @code{flymake-category} property whose value is, respectively, the | ||
| 362 | symbols @code{flymake-error}, @code{flymake-warning} and | ||
| 363 | @code{flymake-note}. | ||
| 364 | |||
| 365 | These category symbols' plists is where the values of customizable | ||
| 366 | variables and faces such as @code{flymake-error-bitmap} are found. | ||
| 367 | Thus, if you change their plists, Flymake may stop honouring these | ||
| 368 | user customizations. | ||
| 369 | |||
| 370 | The @code{flymake-category} special property is also especially useful | ||
| 371 | to backend authors that create diagnostics objects with non-default | ||
| 372 | types that differ from an existing type by only a few properties | ||
| 373 | (@pxref{Flymake utility functions}). | ||
| 374 | |||
| 375 | As an example, consider configuring a new diagnostic type | ||
| 376 | @code{:low-priority-note} that behaves much like the @code{:note} | ||
| 377 | priority but without an overlay face. | ||
| 378 | |||
| 379 | @example | ||
| 380 | (add-to-list | ||
| 381 | 'flymake-diagnostic-types-alist | ||
| 382 | `(:low-priority-note . ((face . nil) | ||
| 383 | (flymake-category . flymake-note)))) | ||
| 384 | @end example | ||
| 385 | |||
| 386 | As you might have guessed, Flymake's annotations are implemented as | ||
| 387 | overlays(@pxref{Overlays,,, elisp, The Emacs Lisp Reference Manual}). | ||
| 388 | Along with the properties that you specify for the specific type of | ||
| 389 | diagnostic, Flymake adds the property @code{flymake-text} to these | ||
| 390 | overlays, and sets it to the message string that the backend used to | ||
| 391 | describe the diagnostic. | ||
| 392 | |||
| 393 | Since overlays also support arbitrary keymaps, you can use this | ||
| 394 | property @code{flymake-text} to create interactive annotations, such | ||
| 395 | as in the following example binding a @kbd{mouse-3} event (middle | ||
| 396 | mouse button click) to an internet search for the text of a | ||
| 397 | @code{:warning} or @code{:error}. | ||
| 398 | |||
| 399 | @example | ||
| 400 | (defun my-search-for-message (event) | ||
| 401 | (interactive "e") | ||
| 402 | (let ((ovs (overlays-at (posn-point (event-start event)))) | ||
| 403 | ov) | ||
| 404 | ;; loop until flymake overlay we clicked on is recovered | ||
| 405 | (while (not (overlay-get (setq ov (pop ovs)) 'flymake-text))) | ||
| 406 | (when ov | ||
| 407 | (eww-browse-url | ||
| 408 | (concat "https://duckduckgo.com/?q=" | ||
| 409 | (replace-regexp-in-string " " | ||
| 410 | "+" | ||
| 411 | (overlay-get ov 'flymake-text))) | ||
| 412 | t)))) | ||
| 413 | |||
| 414 | (dolist (type '(:warning :error)) | ||
| 415 | (let ((a (assoc type flymake-diagnostic-types-alist))) | ||
| 416 | (setf (cdr a) | ||
| 417 | (append `((mouse-face . highlight) | ||
| 418 | (keymap . ,(let ((map (make-sparse-keymap))) | ||
| 419 | (define-key map [mouse-2] | ||
| 420 | 'my-search-for-message) | ||
| 421 | map))) | ||
| 422 | (cdr a))))) | ||
| 423 | @end example | ||
| 424 | |||
| 425 | @node Backend functions | ||
| 426 | @section Backend functions | ||
| 427 | |||
| 428 | Flymake backends are Lisp functions placed in the special hook | ||
| 429 | @code{flymake-diagnostic-functions}. | ||
| 430 | |||
| 431 | A backend's responsibility is to diagnose the contents of a buffer for | ||
| 432 | problems, registering these problem's positions, type and summarized | ||
| 433 | description. This information is collected in the form of diagnostic | ||
| 434 | objects created with the function @code{flymake-make-diagnostic} and | ||
| 435 | then handed over to Flymake, which then proceeds to annotate the | ||
| 436 | buffer. | ||
| 437 | |||
| 438 | A request for a buffer check and the subsequent delivery of | ||
| 439 | diagnostics are the two key events of the interaction between Flymake | ||
| 440 | and backend. Each such event corresponds to a well-defined function | ||
| 441 | calling convention: one for calls made by Flymake into the backend via | ||
| 442 | the backend function, and second one in the reverse direction via a | ||
| 443 | callback. To be usable, backends must adhere to both. | ||
| 444 | |||
| 445 | Backend functions must accept an arbitrary number of arguments: | ||
| 446 | |||
| 447 | @itemize | ||
| 448 | @item the first argument is always @var{report-fn}, a callback function | ||
| 449 | detailed below; | ||
| 450 | |||
| 451 | @item the remaining arguments are keyword-value pairs in the | ||
| 452 | form (@var{:key} @var{value} @var{:key2} @var{value2}...). Currently, | ||
| 453 | Flymake provides no such arguments, but backend functions must be | ||
| 454 | prepared to accept (and possibly ignore) any number of them. | ||
| 455 | @end itemize | ||
| 456 | |||
| 457 | Whenever Flymake or the user decides to re-check the buffer, backend | ||
| 458 | functions are called as detailed above and are expected to initiate | ||
| 459 | this check, but aren't in any way required to complete it before | ||
| 460 | exiting: if the computation involved is computationally expensive, as | ||
| 461 | is often the case in large buffers, that slower task should be | ||
| 462 | scheduled for the future using asynchronous processes or other | ||
| 463 | asynchronous mechanisms. | ||
| 464 | |||
| 465 | In any case, backend functions are expected to return quickly or | ||
| 466 | signal an error, in which case the backend is disabled | ||
| 467 | (@pxref{Backend exceptions}). | ||
| 468 | |||
| 469 | If the function returns, Flymake considers the backend to be | ||
| 470 | @dfn{running}. If it has not done so already, the backend is expected | ||
| 471 | to call the function @var{report-fn} passed to it, at which point | ||
| 472 | Flymake considers the backend to be @dfn{reporting}. Backends call | ||
| 473 | @var{report-fn} by passing it a single argument @var{report-action} | ||
| 474 | followed by an optional list of keyword-value pairs in the form | ||
| 475 | (@var{:report-key} @var{value} @var{:report-key2} @var{value2}...). | ||
| 476 | |||
| 477 | Currently accepted values for @var{report-action} are: | ||
| 478 | |||
| 479 | @itemize | ||
| 480 | @item A (possibly empty) list of diagnostic objects created with | ||
| 481 | @code{flymake-make-diagnostic}, causing Flymake to annotate the | ||
| 482 | buffer with this information. | ||
| 483 | |||
| 484 | A backend may call @var{report-fn} repeatedly in this manner, but only | ||
| 485 | until Flymake considers that the most recently requested buffer check | ||
| 486 | is now obsolete because, say, buffer contents have changed in the | ||
| 487 | meantime. The backend is only given notice of this via a renewed call | ||
| 488 | to the backend function. Thus, to prevent making obsolete reports and | ||
| 489 | wasting resources, backend functions should first cancel any ongoing | ||
| 490 | processing from previous calls. | ||
| 491 | |||
| 492 | @item The symbol @code{:panic}, signaling that the backend has encountered | ||
| 493 | an exceptional situation and should be disabled. | ||
| 494 | @end itemize | ||
| 495 | |||
| 496 | Currently accepted @var{report-key} arguments are: | ||
| 497 | |||
| 498 | @itemize | ||
| 499 | @item @code{:explanation}: value should give user-readable | ||
| 500 | details of the situation encountered, if any. | ||
| 501 | |||
| 502 | @item @code{:force}: value should be a boolean suggesting | ||
| 503 | that Flymake consider the report even if it was somehow | ||
| 504 | unexpected. | ||
| 505 | @end itemize | ||
| 506 | |||
| 507 | @menu | ||
| 508 | * Flymake utility functions:: | ||
| 509 | * An annotated example backend:: | ||
| 510 | @end menu | ||
| 511 | |||
| 512 | @node Flymake utility functions | ||
| 513 | @subsection Flymake utility functions | ||
| 514 | |||
| 515 | Before delivering them to Flymake, backends create diagnostic objects | ||
| 516 | by calling the function @code{flymake-make-diagnostic}. | ||
| 517 | |||
| 518 | @deffn Function flymake-make-diagnostic buffer beg end type text | ||
| 519 | Make a Flymake diagnostic for @var{buffer}'s region from @var{beg} to | ||
| 520 | @var{end}. @var{type} is a key to | ||
| 521 | @code{flymake-diagnostic-types-alist} and @var{text} is a description | ||
| 522 | of the problem detected in this region. | ||
| 523 | @end deffn | ||
| 524 | |||
| 525 | It is often the case with external syntax tools that a diagnostic's | ||
| 526 | position is reported in terms of a line number, and sometimes a column | ||
| 527 | number. To convert this information into a buffer position, backends | ||
| 528 | can use the following function: | ||
| 529 | |||
| 530 | @deffn Function flymake-diag-region buffer line &optional col | ||
| 531 | Compute @var{buffer}'s region (@var{beg} . @var{end}) corresponding to | ||
| 532 | @var{line} and @var{col}. If @var{col} is nil, return a region just | ||
| 533 | for @var{line}. Return nil if the region is invalid. | ||
| 534 | @end deffn | ||
| 535 | |||
| 536 | For troubleshooting purposes, backends may record arbitrary | ||
| 537 | exceptional or erroneous situations into the Flymake log | ||
| 538 | buffer (@pxref{Backend exceptions}): | ||
| 539 | |||
| 540 | @deffn Macro flymake-log level msg &optional args | ||
| 541 | Log, at level @var{level}, the message @var{msg} formatted with | ||
| 542 | @var{args}. @var{level} is passed to @code{display-warning}, which is | ||
| 543 | used to display the warning in Flymake's log buffer. | ||
| 544 | @end deffn | ||
| 545 | |||
| 546 | @node An annotated example backend | ||
| 547 | @subsection An annotated example backend | ||
| 548 | |||
| 549 | This section presents an annotated example of a complete working | ||
| 550 | Flymake backend. The example illustrates the process of writing a | ||
| 551 | backend as outlined above. | ||
| 552 | |||
| 553 | The backend in question is used for checking Ruby source files. It | ||
| 554 | uses asynchronous processes (@pxref{Asynchronous Processes,,, elisp, | ||
| 555 | The Emacs Lisp Reference Manual}), a common technique for performing | ||
| 556 | parallel processing in Emacs. | ||
| 557 | |||
| 558 | The following code needs lexical binding (@pxref{Using Lexical | ||
| 559 | Binding,,, elisp, The Emacs Lisp Reference Manual}) to be active. | ||
| 560 | |||
| 561 | @example | ||
| 562 | ;;; ruby-flymake.el --- A ruby Flymake backend -*- lexical-binding: t; -*- | ||
| 563 | (defvar-local ruby--flymake-proc nil) | ||
| 564 | |||
| 565 | (defun ruby-flymake (report-fn &rest _args) | ||
| 566 | ;; Not having a ruby interpreter is a serious problem which should cause | ||
| 567 | ;; the backend to disable itself, so an @code{error} is signalled. | ||
| 568 | ;; | ||
| 569 | (unless (executable-find | ||
| 570 | "ruby") (error "Cannot find a suitable ruby")) | ||
| 571 | ;; If a live process launched in an earlier check was found, that | ||
| 572 | ;; process is killed. When that process's sentinel eventually runs, | ||
| 573 | ;; it will notice its obsoletion, since if have since reset | ||
| 574 | ;; `ruby-flymake-proc' to a different value | ||
| 575 | ;; | ||
| 576 | (when (process-live-p ruby--flymake-proc) | ||
| 577 | (kill-process ruby--flymake-proc)) | ||
| 578 | |||
| 579 | ;; save the current buffer, the narrowing restrinction, remove any | ||
| 580 | ;; narrowing restriction | ||
| 581 | ;; | ||
| 582 | (let ((source (current-buffer))) | ||
| 583 | (save-restriction | ||
| 584 | (widen) | ||
| 585 | ;; reset the `ruby--flymake-proc' process to a new process | ||
| 586 | ;; calling the ruby tool | ||
| 587 | ;; | ||
| 588 | (setq | ||
| 589 | ruby--flymake-proc | ||
| 590 | (make-process | ||
| 591 | :name "ruby-flymake" :noquery t :connection-type 'pipe | ||
| 592 | ;; make output goes to a temporary buffer | ||
| 593 | ;; | ||
| 594 | :buffer (generate-new-buffer " *ruby-flymake*") | ||
| 595 | :command '("ruby" "-w" "-c") | ||
| 596 | :sentinel | ||
| 597 | (lambda (proc _event) | ||
| 598 | ;; Check that the process as indeed exited, as it might | ||
| 599 | ;; be simply suspended | ||
| 600 | ;; | ||
| 601 | (when (eq 'exit (process-status proc)) | ||
| 602 | (unwind-protect | ||
| 603 | ;; Only proceed if `proc' is the same as | ||
| 604 | ;; `ruby--flymake-proc' which indicates that | ||
| 605 | ;; `proc' is not an obsolete process. | ||
| 606 | ;; | ||
| 607 | (if (eq proc ruby--flymake-proc) | ||
| 608 | (with-current-buffer (process-buffer proc) | ||
| 609 | (goto-char (point-min)) | ||
| 610 | ;; Parse the output buffer for diagnostic's | ||
| 611 | ;; messages and locations, collect them in a list | ||
| 612 | ;; of objects, and call `report-fn'. | ||
| 613 | ;; | ||
| 614 | (cl-loop | ||
| 615 | while (search-forward-regexp | ||
| 616 | "^\\(?:.*.rb\\|-\\):\\([0-9]+\\): \\(.*\\)$" | ||
| 617 | nil t) | ||
| 618 | for msg = (match-string 2) | ||
| 619 | for (beg . end) = (flymake-diag-region | ||
| 620 | source | ||
| 621 | (string-to-number (match-string 1))) | ||
| 622 | for type = (if (string-match "^warning" msg) | ||
| 623 | :warning | ||
| 624 | :error) | ||
| 625 | collect (flymake-make-diagnostic source | ||
| 626 | beg | ||
| 627 | end | ||
| 628 | type | ||
| 629 | msg) | ||
| 630 | into diags | ||
| 631 | finally (funcall report-fn diags))) | ||
| 632 | (flymake-log :warning "Cancelling obsolete check %s" | ||
| 633 | proc)) | ||
| 634 | ;; Cleanup the temporary buffer used to hold the | ||
| 635 | ;; check's output. | ||
| 636 | ;; | ||
| 637 | (kill-buffer (process-buffer proc))))))) | ||
| 638 | ;; send the buffer contents to the process's stdin, followed by | ||
| 639 | ;; an EOF | ||
| 640 | ;; | ||
| 641 | (process-send-region ruby--flymake-proc (point-min) (point-max)) | ||
| 642 | (process-send-eof ruby--flymake-proc)))) | ||
| 643 | |||
| 644 | (defun ruby-setup-flymake-backend () | ||
| 645 | (add-hook 'flymake-diagnostic-functions 'ruby-flymake nil t)) | ||
| 646 | |||
| 647 | (add-hook 'ruby-mode-hook 'ruby-setup-flymake-backend) | ||
| 648 | @end example | ||
| 649 | |||
| 268 | @node The legacy Proc backend | 650 | @node The legacy Proc backend |
| 269 | @chapter The legacy ``Proc'' backend | 651 | @chapter The legacy ``Proc'' backend |
| 270 | @cindex The legacy Proc backend | 652 | @cindex The legacy Proc backend |
diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el index fa0c756ae30..c52dad722ce 100644 --- a/lisp/progmodes/flymake.el +++ b/lisp/progmodes/flymake.el | |||
| @@ -322,12 +322,12 @@ region is invalid." | |||
| 322 | (defvar flymake-diagnostic-functions nil | 322 | (defvar flymake-diagnostic-functions nil |
| 323 | "Special hook of Flymake backends that check a buffer. | 323 | "Special hook of Flymake backends that check a buffer. |
| 324 | 324 | ||
| 325 | The functions in this hook diagnose problems in a buffer’s | 325 | The functions in this hook diagnose problems in a buffer's |
| 326 | contents and provide information to the Flymake user interface | 326 | contents and provide information to the Flymake user interface |
| 327 | about where and how to annotate problems diagnosed in a buffer. | 327 | about where and how to annotate problems diagnosed in a buffer. |
| 328 | 328 | ||
| 329 | Whenever Flymake or the user decides to re-check the buffer, each | 329 | Each backend function must be prepared to accept an arbitrary |
| 330 | function is called with an arbitrary number of arguments: | 330 | number of arguments: |
| 331 | 331 | ||
| 332 | * the first argument is always REPORT-FN, a callback function | 332 | * the first argument is always REPORT-FN, a callback function |
| 333 | detailed below; | 333 | detailed below; |
| @@ -337,11 +337,12 @@ function is called with an arbitrary number of arguments: | |||
| 337 | no such arguments, but backend functions must be prepared to | 337 | no such arguments, but backend functions must be prepared to |
| 338 | accept and possibly ignore any number of them. | 338 | accept and possibly ignore any number of them. |
| 339 | 339 | ||
| 340 | Backend functions are expected to initiate the buffer check, but | 340 | Whenever Flymake or the user decides to re-check the buffer, |
| 341 | aren't required to complete it check before exiting: if the | 341 | backend functions are called as detailed above and are expected |
| 342 | computation involved is expensive, especially for large buffers, | 342 | to initiate this check, but aren't required to complete it before |
| 343 | that task can be scheduled for the future using asynchronous | 343 | exiting: if the computation involved is expensive, especially for |
| 344 | processes or other asynchronous mechanisms. | 344 | large buffers, that task can be scheduled for the future using |
| 345 | asynchronous processes or other asynchronous mechanisms. | ||
| 345 | 346 | ||
| 346 | In any case, backend functions are expected to return quickly or | 347 | In any case, backend functions are expected to return quickly or |
| 347 | signal an error, in which case the backend is disabled. Flymake | 348 | signal an error, in which case the backend is disabled. Flymake |
| @@ -375,10 +376,10 @@ Currently accepted values for REPORT-ACTION are: | |||
| 375 | 376 | ||
| 376 | Currently accepted REPORT-KEY arguments are: | 377 | Currently accepted REPORT-KEY arguments are: |
| 377 | 378 | ||
| 378 | * ‘:explanation’: value should give user-readable details of | 379 | * `:explanation' value should give user-readable details of |
| 379 | the situation encountered, if any. | 380 | the situation encountered, if any. |
| 380 | 381 | ||
| 381 | * ‘:force’: value should be a boolean suggesting that Flymake | 382 | * `:force': value should be a boolean suggesting that Flymake |
| 382 | consider the report even if it was somehow unexpected.") | 383 | consider the report even if it was somehow unexpected.") |
| 383 | 384 | ||
| 384 | (defvar flymake-diagnostic-types-alist | 385 | (defvar flymake-diagnostic-types-alist |
| @@ -407,12 +408,12 @@ properties are: | |||
| 407 | 408 | ||
| 408 | * `severity', a non-negative integer specifying the diagnostic's | 409 | * `severity', a non-negative integer specifying the diagnostic's |
| 409 | severity. The higher, the more serious. If the overlay | 410 | severity. The higher, the more serious. If the overlay |
| 410 | priority `priority' is not specified, `severity' is used to set | 411 | property `priority' is not specified, `severity' is used to set |
| 411 | it and help sort overlapping overlays. | 412 | it and help sort overlapping overlays. |
| 412 | 413 | ||
| 413 | * `flymake-category', a symbol whose property list is considered | 414 | * `flymake-category', a symbol whose property list is considered |
| 414 | as a default for missing values of any other properties. This | 415 | a default for missing values of any other properties. This is |
| 415 | is useful to backend authors when creating new diagnostic types | 416 | useful to backend authors when creating new diagnostic types |
| 416 | that differ from an existing type by only a few properties.") | 417 | that differ from an existing type by only a few properties.") |
| 417 | 418 | ||
| 418 | (put 'flymake-error 'face 'flymake-error) | 419 | (put 'flymake-error 'face 'flymake-error) |
| @@ -497,8 +498,7 @@ associated `flymake-category' return DEFAULT." | |||
| 497 | (lambda (_window _ov pos) | 498 | (lambda (_window _ov pos) |
| 498 | (mapconcat | 499 | (mapconcat |
| 499 | (lambda (ov) | 500 | (lambda (ov) |
| 500 | (let ((diag (overlay-get ov 'flymake--diagnostic))) | 501 | (overlay-get ov 'flymake-text)) |
| 501 | (flymake--diag-text diag))) | ||
| 502 | (flymake--overlays :beg pos) | 502 | (flymake--overlays :beg pos) |
| 503 | "\n"))) | 503 | "\n"))) |
| 504 | (default-maybe 'severity (warning-numeric-level :error)) | 504 | (default-maybe 'severity (warning-numeric-level :error)) |
| @@ -507,6 +507,7 @@ associated `flymake-category' return DEFAULT." | |||
| 507 | ;; | 507 | ;; |
| 508 | (overlay-put ov 'evaporate t) | 508 | (overlay-put ov 'evaporate t) |
| 509 | (overlay-put ov 'flymake t) | 509 | (overlay-put ov 'flymake t) |
| 510 | (overlay-put ov 'flymake-text (flymake--diag-text diagnostic)) | ||
| 510 | (overlay-put ov 'flymake--diagnostic diagnostic))) | 511 | (overlay-put ov 'flymake--diagnostic diagnostic))) |
| 511 | 512 | ||
| 512 | ;; Nothing in Flymake uses this at all any more, so this is just for | 513 | ;; Nothing in Flymake uses this at all any more, so this is just for |
| @@ -715,7 +716,7 @@ Interactively, with a prefix arg, FORCE is t." | |||
| 715 | (remove-hook 'post-command-hook #'start-post-command | 716 | (remove-hook 'post-command-hook #'start-post-command |
| 716 | nil) | 717 | nil) |
| 717 | (with-current-buffer buffer | 718 | (with-current-buffer buffer |
| 718 | (flymake-start (remove 'post-command deferred) force))) | 719 | (flymake-start (remove 'post-command deferred) force))) |
| 719 | (start-on-display | 720 | (start-on-display |
| 720 | () | 721 | () |
| 721 | (remove-hook 'window-configuration-change-hook #'start-on-display | 722 | (remove-hook 'window-configuration-change-hook #'start-on-display |
| @@ -873,9 +874,9 @@ Do it only if `flymake-no-changes-timeout' is non-nil." | |||
| 873 | (defun flymake-goto-next-error (&optional n filter interactive) | 874 | (defun flymake-goto-next-error (&optional n filter interactive) |
| 874 | "Go to Nth next Flymake error in buffer matching FILTER. | 875 | "Go to Nth next Flymake error in buffer matching FILTER. |
| 875 | Interactively, always move to the next error. With a prefix arg, | 876 | Interactively, always move to the next error. With a prefix arg, |
| 876 | skip any diagnostics with a severity less than ‘:warning’. | 877 | skip any diagnostics with a severity less than `:warning'. |
| 877 | 878 | ||
| 878 | If ‘flymake-wrap-around’ is non-nil and no more next errors, | 879 | If `flymake-wrap-around' is non-nil and no more next errors, |
| 879 | resumes search from top. | 880 | resumes search from top. |
| 880 | 881 | ||
| 881 | FILTER is a list of diagnostic types found in | 882 | FILTER is a list of diagnostic types found in |
| @@ -928,9 +929,9 @@ applied." | |||
| 928 | (defun flymake-goto-prev-error (&optional n filter interactive) | 929 | (defun flymake-goto-prev-error (&optional n filter interactive) |
| 929 | "Go to Nth previous Flymake error in buffer matching FILTER. | 930 | "Go to Nth previous Flymake error in buffer matching FILTER. |
| 930 | Interactively, always move to the previous error. With a prefix | 931 | Interactively, always move to the previous error. With a prefix |
| 931 | arg, skip any diagnostics with a severity less than ‘:warning’. | 932 | arg, skip any diagnostics with a severity less than `:warning'. |
| 932 | 933 | ||
| 933 | If ‘flymake-wrap-around’ is non-nil and no more previous errors, | 934 | If `flymake-wrap-around' is non-nil and no more previous errors, |
| 934 | resumes search from bottom. | 935 | resumes search from bottom. |
| 935 | 936 | ||
| 936 | FILTER is a list of diagnostic types found in | 937 | FILTER is a list of diagnostic types found in |