[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master b0e75df: Make wcheck-mode an externals/wcheck-mode package
From: |
Teemu Likonen |
Subject: |
[elpa] master b0e75df: Make wcheck-mode an externals/wcheck-mode package |
Date: |
Sun, 4 Oct 2020 08:10:38 -0400 (EDT) |
branch: master
commit b0e75df7a50c07a311f80e58ca15f452da5865b8
Author: Teemu Likonen <tlikonen@iki.fi>
Commit: Teemu Likonen <tlikonen@iki.fi>
Make wcheck-mode an externals/wcheck-mode package
---
externals-list | 2 +-
packages/wcheck-mode/README.md | 404 -------
packages/wcheck-mode/wcheck-mode.el | 2232 -----------------------------------
3 files changed, 1 insertion(+), 2637 deletions(-)
diff --git a/externals-list b/externals-list
index 79e088a..209021b 100644
--- a/externals-list
+++ b/externals-list
@@ -170,7 +170,7 @@
("transient" :external "https://github.com/magit/transient")
;;FIXME:("vlf" :subtree ??)
("verilog-mode" :core "lisp/progmodes/verilog-mode.el")
- ("wcheck-mode" :subtree
"https://github.com/tlikonen/wcheck-mode.git")
+ ("wcheck-mode" :external
"https://github.com/tlikonen/wcheck-mode")
("web-server" :subtree
"https://github.com/eschulte/emacs-web-server.git")
("webfeeder" :external
"https://gitlab.com/ambrevar/emacs-webfeeder.git")
("websocket" :subtree
"https://github.com/ahyatt/emacs-websocket.git")
diff --git a/packages/wcheck-mode/README.md b/packages/wcheck-mode/README.md
deleted file mode 100644
index 6fc47f4..0000000
--- a/packages/wcheck-mode/README.md
+++ /dev/null
@@ -1,404 +0,0 @@
-Wcheck Mode
-===========
-
-**General-purpose text-checker interface for Emacs text editor**
-
-
-Introduction
-------------
-
-Wcheck mode is a general-purpose text-checker interface for [Emacs][]
-text editor. Wcheck mode is a minor mode which provides an on-the-fly
-text checker. It checks the visible text area, as you type, and possibly
-highlights some parts of it. What is checked and how are all
-configurable.
-
-Wcheck mode can use external programs or Emacs Lisp functions for
-checking text. For example, Wcheck mode can be used with spell-checker
-programs such as Ispell, Enchant and Hunspell, but actually any tool
-that can receive text from standard input stream and send text to
-standard output can be used. Wcheck mode sends parts of buffer's content
-to an external program or an Emacs Lisp function and, relying on their
-output, decides if some parts of text should be marked in the buffer.
-
-[Emacs]: http://www.gnu.org/software/emacs/
-
-
-Features
---------
-
-In Wcheck mode's configuration different configuration units are called
-_languages_. In terms of a spelling checker it is natural to think of
-them as different human languages. Wcheck mode is not limited to that,
-though. Language is just a configuration unit for a specific text
-checking purpose.
-
-Each language can use its own checker engine (external program or a
-function), command-line arguments and other settings, such as the
-regular expressions and syntax table that are used to match words (or
-other text elements) in Emacs buffer. User can choose which _face_ is
-used to mark text elements in buffer.
-
-User can create language-specific and major mode specific settings
-defining which _faces_ to read or skip in buffers. A typical use for
-this feature is to spell-check only those areas in buffer which are
-written in the target language. For example, in email messages usually
-the message body and Subject header are important enough to spell-check.
-In programming modes user could spell-check only documentation strings
-and comments (or the opposite if you want to use Wcheck mode to check
-keywords and syntax of the programming language itself).
-
-Wcheck mode can also be configured to offer any kind of actions for
-marked text. Actions are presented to user through a menu which is
-activated either by (1) clicking the right mouse button on a marked text
-or (2) executing interactive command `wcheck-actions` while the cursor
-(the point) is on a marked text.
-
-If you use Wcheck mode as a spelling checker then it's natural to
-configure an action menu that offers spelling suggestions for misspelled
-words. The action menu could also have an option to add marked word to
-spell-checker's dictionary, so that the word is recognized in the
-future. That's only one application for Wcheck mode, though. Wcheck mode
-can be configured to find almost any kind of text elements from buffer,
-mark them, and offer any kind of actions for marked text.
-
-
-How does it compare to other spell-checkers?
---------------------------------------------
-
-The open design makes Wcheck mode (internally) quite different from
-spell-checkers like [Flyspell][] mode and [Speck][] mode. They are
-specific tools for spell-checking through Ispell or compatible program
-and are therefore very much tied to Ispell's features and command-line
-interface. This can be useful if you want to use Ispell or fully
-compatible program for spell-checking natural languages. However, not
-all human languages can be supported through Ispell and there can also
-be other kind of text-checking needs.
-
-The motivation behind Wcheck mode is to offer more general-purpose and
-configurable interface for text checking. It can be configured to work
-with almost anything: user's custom shell, Awk or Perl scripts, Lisp
-functions or other checkers and text filters. Even if you only need a
-spelling checker for human languages Wcheck mode can be a good choice.
-It has more configuration possibilities than other spell-checkers and
-the on-the-fly checker performs very well. It's a true real-time
-checker.
-
-[Flyspell]: http://www.emacswiki.org/emacs/FlySpell
-[Speck]: http://www.emacswiki.org/SpeckMode
-
-
-Install
--------
-
-You can install Wcheck mode through [GNU Elpa][Elpa] or [Melpa][]
-package archives. Alternatively you can put `wcheck-mode.el` file to
-some directory in your Emacs's `load-path` and add the following lines
-to Emacs's initialization file (`~/.emacs` or `~/.emacs.d/init.el`):
-
- (autoload 'wcheck-mode "wcheck-mode"
- "Toggle wcheck-mode." t)
- (autoload 'wcheck-change-language "wcheck-mode"
- "Switch wcheck-mode languages." t)
- (autoload 'wcheck-actions "wcheck-mode"
- "Open actions menu." t)
- (autoload 'wcheck-jump-forward "wcheck-mode"
- "Move point forward to next marked text area." t)
- (autoload 'wcheck-jump-backward "wcheck-mode"
- "Move point backward to previous marked text area." t)
-
-[Elpa]: https://elpa.gnu.org/
-[Melpa]: https://melpa.org/
-
-
-Configuration and basic usage
------------------------------
-
-The internal documentation of variable `wcheck-language-data` has a
-complete description on how to configure Wcheck mode language data. For
-easy configuration you can use the options in the customize group named
-_wcheck_ (`M-x customize-group RET wcheck RET`).
-
-It might be convenient to bind Wcheck mode commands to some easily
-accessible keys, for example:
-
- (global-set-key (kbd "C-c s") 'wcheck-mode)
- (global-set-key (kbd "C-c l") 'wcheck-change-language)
- (global-set-key (kbd "C-c c") 'wcheck-actions)
- (global-set-key (kbd "C-c n") 'wcheck-jump-forward)
- (global-set-key (kbd "C-c p") 'wcheck-jump-backward)
-
-Interactive command `wcheck-mode` toggles the text-checker minor mode
-for the current buffer. Command `wcheck-change-language` is used to
-switch languages and command `wcheck-actions` (or the right mouse
-button) opens an actions menu for marked text. Commands
-`wcheck-jump-forward` and `wcheck-jump-backward` jump to next or
-previous marked text area.
-
-A note for Emacs Lisp programmers: Emacs Lisp function
-`wcheck-marked-text-at` returns information about marked text at a
-buffer position. Programmers can use it to perform any kind of actions
-for marked text. Function `wcheck-query-language-data` can be used for
-querying effective configuration data for any language.
-
-
-Examples
---------
-
-
-### Basic spell-checking
-
-Here are some examples on how you can fill the `wcheck-language-data`
-variable. The value is a list of language configurations:
-
- (setq wcheck-language-data
- '(("language"
- ...)
- ("another language"
- ...)))
-
-Perhaps the most common use for Wcheck mode is to spell-check human
-languages with Ispell (or compatible) spelling checker. Let's start with
-examples on how to configure that.
-
-The following settings configure two languages which are named "British
-English" and "Finnish". The former language uses Ispell program as the
-spell-checker engine. The latter uses Enchant which has an
-Ispell-compatible command-line interface. Both languages use Wcheck
-mode's actions feature to offer spelling suggestions for misspelled
-words. Since both spelling checkers print spelling suggestions in the
-Ispell format we use built-in function
-`wcheck-parser-ispell-suggestions` to parse the output and populate the
-actions (spelling suggestions) menu for user.
-
- ("British English"
- (program . "/usr/bin/ispell")
- (args "-l" "-d" "british")
- (action-program . "/usr/bin/ispell")
- (action-args "-a" "-d" "british")
- (action-parser . wcheck-parser-ispell-suggestions))
-
- ("Finnish"
- (program . "/usr/bin/enchant")
- (args "-l" "-d" "fi")
- (syntax . my-finnish-syntax-table)
- (action-program . "/usr/bin/enchant")
- (action-args "-a" "-d" "fi")
- (action-parser . wcheck-parser-ispell-suggestions))
-
-The "Finnish" language above used a special syntax table called
-`my-finnish-syntax-table`. It could be defined like this:
-
- (defvar my-finnish-syntax-table
- (copy-syntax-table text-mode-syntax-table))
-
- (modify-syntax-entry ?- "w" my-finnish-syntax-table)
-
-It copies `text-mode-syntax-table` (which Wcheck mode uses by default)
-and sets the syntactic meaning of the ASCII hyphen character (-) to a
-word character ("w"). Wcheck mode and its regular expression search will
-use that syntax table when scanning buffers' content in that language.
-
-
-### Choose what to check
-
-On some Emacs major modes there is no need to spell-check everything in
-the buffer. For example, in programming languages modes it is probably
-useful to spell-check only programmer's comments and functions'
-documentation strings. This can be configured with language option
-`read-or-skip-faces`. The following incomplete language configuration
-makes special treatment for emacs-lisp-mode: it checks only text areas
-which have been marked with faces `font-lock-comment-face` and
-`font-lock-doc-face`.
-
- ("Some language"
- ;; (program ...)
- ;; (args ...)
- (read-or-skip-faces
- (emacs-lisp-mode read font-lock-comment-face font-lock-string-face)))
-
-Because `read-or-skip-faces` settings is often not a language specific
-option but a general major mode specific setting it can be more useful
-to put `read-or-skip-faces` settings in variable
-`wcheck-language-data-defaults` like this:
-
- (setq wcheck-language-data-defaults
- '((read-or-skip-faces
- ((emacs-lisp-mode lisp-mode)
- read font-lock-comment-face font-lock-doc-face)
- (sh-mode
- read font-lock-comment-face)
- (message-mode
- read nil message-header-subject message-cited-text)
- (latex-mode
- read nil font-latex-sectioning-1-face
- font-latex-sectioning-2-face
- font-latex-sectioning-3-face
- font-latex-sectioning-4-face font-latex-bold-face
- font-latex-italic-face font-lock-constant-face)
- (org-mode
- read nil org-level-1 org-level-2 org-level-3 org-level-4
- org-level-5 org-level-6 org-level-7 org-level-8)
- (git-commit-mode
- read nil git-commit-summary-face))))
-
-
-### Add words to dictionary
-
-Below is an example on how to add an "Add to dictionary" feature to the
-actions menu, among spelling suggestions. First, there's the language
-configuration. The example below is similar to the "British English"
-configuration above except that Enchant spell-checker is used and
-`action-parser` is a custom function (which will be defined later).
-
- ("British English"
- (program . "/usr/bin/enchant")
- (args "-l" "-d" "en_GB")
- (action-program . "/usr/bin/enchant")
- (action-args "-a" "-d" "en_GB")
- (action-parser . enchant-suggestions-menu))
-
-The action parser is custom function `enchant-suggestions-menu`. It will
-call `wcheck-parser-ispell-suggestions` and then add "Add to dictionary"
-option in the front of the spelling suggestions list. Choosing that
-option from the actions menu will call function
-`enchant-add-to-dictionary` (will be defined later).
-
- (defun enchant-suggestions-menu (marked-text)
- (cons (cons "[Add to dictionary]" 'enchant-add-to-dictionary)
- (wcheck-parser-ispell-suggestions)))
-
-Now we need to define the function `enchant-add-to-dictionary`. Below is
-an example that works in GNU/Linux systems with Enchant spell-checker.
-With small modifications it should work with other spelling checkers and
-operating systems.
-
-For British English language the user dictionary file is
-`~/.config/enchant/en_GB.dic`. The language code is extracted
-automatically from `wcheck-language-data` variable, so the function
-works with any Enchant language. Note that adding a word to a dictionary
-file doesn't have effect on the current spell-checking session. The
-Enchant program must be restarted.
-
- (defvar enchant-dictionaries-dir "~/.config/enchant")
-
- (defun enchant-add-to-dictionary (marked-text)
- (let* ((word (aref marked-text 0))
- (language (aref marked-text 4))
- (file (let ((code (nth 1 (member "-d" (wcheck-query-language-data
- language 'action-args)))))
- (when (stringp code)
- (concat (file-name-as-directory
enchant-dictionaries-dir)
- code ".dic")))))
-
- (when (and file (file-writable-p file))
- (with-temp-buffer
- (insert word) (newline)
- (append-to-file (point-min) (point-max) file)
- (message "Added word \"%s\" to the %s dictionary"
- word language)))))
-
-
-### Other than human languages
-
-Spell-checking human languages is not the only application for Wcheck
-mode. The following configuration adds language called "Trailing
-whitespace" which finds and marks all trailing whitespace characters
-(spaces and tabs) on buffer's lines. It uses regular expressions to
-match the whitespace. The checker program is the Emacs Lisp function
-`identity` which just returns its argument unchanged. The
-`action-program` option and feature is used to build an action menu with
-just one option: remove the whitespace. It replaces the original
-whitespace string with empty string.
-
- ("Trailing whitespace"
- (program . identity)
- (action-program . (lambda (marked-text)
- (list (cons "Remove whitespace" ""))))
- (face . highlight)
- (regexp-start . "")
- (regexp-body . "[ \t]+")
- (regexp-end . "$")
- (regexp-discard . "")
- (read-or-skip-faces
- (nil)))
-
-Sometimes it's useful to highlight only a small number of keywords in
-buffer. The following example adds a language called "Highlight FIXMEs"
-which marks only "FIXME" words. FIXME is some programmers' convention to
-put reminders in source code that some parts are not complete yet and
-will be fixed or completed later. In source code files such keywords are
-written in program's comments only, not in the actual code, so we use
-`read-or-skip-faces` feature to scan only the comments. This example
-configures it for `emacs-lisp-mode` and `c-mode`. In all other major
-modes FIXMEs are marked everywhere.
-
- ("Highlight FIXMEs"
- (program . (lambda (strings)
- (when (member "FIXME" strings)
- (list "FIXME"))))
- (face . highlight)
- (read-or-skip-faces
- ((emacs-lisp-mode c-mode) read font-lock-comment-face)
- (nil)))
-
-The following example adds a language "email" for highlighting email
-addresses in buffer and creating an action menu which has option to
-start composing mail to that address. Here's the language configuration:
-
- ("email"
- (program . email-address-detect)
- (face . highlight)
- (case-fold . t)
- (regexp-start . "\\<")
- (regexp-body . "\\S-+@\\S-+")
- (regexp-end . "\\>")
- (regexp-discard . "")
- (action-program . email-action-menu)
- (read-or-skip-faces
- (nil)))
-
-Then the needed functions:
-
- (defun email-address-detect (strings)
- (let (addresses)
- (dolist (string strings addresses)
- (when (string-match "\\<[a-z.-]+\\>@\\<[a-z.-]+\\>" string)
- (push (match-string-no-properties 0 string) addresses)))))
-
- (defun email-action-menu (marked-text)
- (list (cons (concat "Mail to <" (aref marked-text 0) ">")
- (lambda (marked-text)
- (compose-mail (aref marked-text 0))))))
-
-Note that detecting all valid email addresses is difficult and a much
-more advanced parser is needed for that. Feel free to replace the
-detection function with a better one.
-
-
-The source code repository
---------------------------
-
-GitHub repository URL: <https://github.com/tlikonen/wcheck-mode>
-
-The branch named _master_ is the release branch and it should always be
-safe to use. New features and experimental code are developed in other
-branches and possibly merged to _master_ when they are ready.
-
-
-Copyright and license
----------------------
-
-Copyright (C) 2009-2019 Free Software Foundation, Inc.
-
-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.
-
-The license text: <http://www.gnu.org/licenses/gpl-3.0.html>
diff --git a/packages/wcheck-mode/wcheck-mode.el
b/packages/wcheck-mode/wcheck-mode.el
deleted file mode 100644
index 74f8dce..0000000
--- a/packages/wcheck-mode/wcheck-mode.el
+++ /dev/null
@@ -1,2232 +0,0 @@
-;;; wcheck-mode.el --- General interface for text checkers -*-
lexical-binding: t -*-
-
-;; Copyright (C) 2009-2019 Free Software Foundation, Inc.
-
-;; Author: Teemu Likonen <tlikonen@iki.fi>
-;; Maintainer: Teemu Likonen <tlikonen@iki.fi>
-;; Created: 2009-07-04
-;; URL: https://github.com/tlikonen/wcheck-mode
-;; Keywords: text spell check languages ispell
-;; Version: 2019.6.17
-
-;; 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.
-;;
-;; The license text: <http://www.gnu.org/licenses/gpl-3.0.html>
-
-
-;; INSTALLATION
-;;
-;; Put this file to some directory in your Emacs's "load-path" and add
-;; the following lines to Emacs's initialization file (~/.emacs):
-;;
-;; (autoload 'wcheck-mode "wcheck-mode"
-;; "Toggle wcheck-mode." t)
-;; (autoload 'wcheck-change-language "wcheck-mode"
-;; "Switch wcheck-mode languages." t)
-;; (autoload 'wcheck-actions "wcheck-mode"
-;; "Open actions menu." t)
-;; (autoload 'wcheck-jump-forward "wcheck-mode"
-;; "Move point forward to next marked text area." t)
-;; (autoload 'wcheck-jump-backward "wcheck-mode"
-;; "Move point backward to previous marked text area." t)
-;;
-;; See customize group "wcheck" for information on how to configure
-;; Wcheck mode. (M-x customize-group RET wcheck RET)
-
-
-;;; Commentary:
-;;
-;; A general interface for text checkers
-;;
-;; Wcheck mode is a general-purpose text-checker interface for Emacs
-;; text editor. Wcheck mode a minor mode which provides an on-the-fly
-;; text checker. It checks the visible text area, as you type, and
-;; possibly highlights some parts of it. What is checked and how are all
-;; configurable.
-;;
-;; Wcheck mode can use external programs or Emacs Lisp functions for
-;; checking text. For example, Wcheck mode can be used with
-;; spell-checker programs such as Ispell, Enchant and Hunspell, but
-;; actually any tool that can receive text from standard input stream
-;; and send text to standard output can be used. Wcheck mode sends parts
-;; of buffer's content to an external program or an Emacs Lisp function
-;; and, relying on their output, decides if some parts of text should be
-;; marked in the buffer.
-
-;;; Code:
-
-
-(eval-when-compile
- ;; Silence compiler
- (declare-function outline-show-entry "outline"))
-
-
-;;; Settings
-
-
-;;;###autoload
-(defgroup wcheck nil
- "General interface for text checkers."
- :group 'applications)
-
-
-(defconst wcheck--language-data-customize-interface
- '(choice
- :format "%[Option%] %v"
-
- (cons :tag "Program" :format "%v"
- (const :tag "Program" :format "%t: " program)
- (choice :format "%[Type%] %v"
- (file :tag "Filename" :format "\n\t\t%t: %v")
- (function :tag "Function" :format "\n\t\t%t: %v")))
-
- (cons :tag "Arguments" :format "%v"
- (const :format "" args)
- (repeat :tag "Arguments"
- (string :format "%v")))
-
- (cons :tag "Output parser function" :format "%v"
- (const :tag "Output parser" :format "%t: " parser)
- (choice :format "%[Parser%] %v" :value nil
- (const :tag "Lines" wcheck-parser-lines)
- (const :tag "Whitespace" wcheck-parser-whitespace)
- (function :tag "Custom function"
- :format "%t:\n\t\t%v")))
-
- (cons :tag "Connection type" :format "%v"
- (const :tag "Connection: " :format "%t" connection)
- (choice :format "%[Type%] %v" :value nil
- (const :tag "pipe (nil)" nil)
- (const :tag "pty" :match (lambda (widget value)
- (or (eq value t)
- (eq value 'pty)))
- pty)))
-
- (cons :tag "Face" :format "%v"
- (const :tag "Face" :format "%t: " face)
- (symbol :format "%v"))
-
- (cons :tag "Syntax table" :format "%v"
- (const :tag "Syntax table" :format "%t: " syntax)
- (variable :format "%v"))
-
- (cons :tag "Regexp start" :format "%v"
- (const :tag "Regexp start" :format "%t: " regexp-start)
- (regexp :format "%v"))
-
- (cons :tag "Regexp body" :format "%v"
- (const :tag "Regexp body" :format "%t: " regexp-body)
- (regexp :format "%v"))
-
- (cons :tag "Regexp end" :format "%v"
- (const :tag "Regexp end" :format "%t: " regexp-end)
- (regexp :format "%v"))
-
- (cons :tag "Regexp discard" :format "%v"
- (const :tag "Regexp discard" :format "%t: " regexp-discard)
- (regexp :format "%v"))
-
- (cons :tag "Regexp case" :format "%v"
- (const :tag "Regexp" :format "%t: " case-fold)
- (choice :format "%[Case%] %v" :value nil
- :match (lambda (widget value) t)
- :value-to-internal (lambda (widget value)
- (if value t nil))
- (const :tag "sensitive" nil)
- (const :tag "insensitive" t)))
-
- (cons
- :tag "Read or skip faces" :format "%v"
- (const :tag "Read or skip faces" :format "%t" read-or-skip-faces)
- (repeat
- :tag ""
- (cons :format "%v"
-
- (choice :format "%[Major mode%] %v"
- (const :tag "All major modes"
- :match (lambda (widget value) (null value))
- nil)
- (repeat
- :tag "Select major modes"
- :match (lambda (widget value)
- (or (symbolp value) (consp value)))
- :value-to-internal (lambda (widget value)
- (if (symbolp value)
- (list value)
- value))
- :value-to-external (lambda (widget value)
- (if (and (consp value)
- (symbolp (car value))
- (null (cdr value)))
- (car value)
- value))
- (symbol :format "%v")))
-
- (choice :format "%[Operation mode%] %v"
- (const :tag "Read everything" nil)
- (cons :tag "Read selected faces" :format "%v"
- (const :tag "Read selected faces"
- :format "%t" read)
- (repeat :tag "" (sexp :format "%v")))
- (cons :tag "Skip selected faces" :format "%v"
- (const :tag "Skip selected faces"
- :format "%t" skip)
- (repeat :tag "" (sexp :format "%v")))))))
-
- (cons :tag "Action program" :format "%v"
- (const :tag "Action program" :format "%t: " action-program)
- (choice :format "%[Type%] %v"
- (file :tag "Filename" :format "\n\t\t%t: %v")
- (function :tag "Function" :format "\n\t\t%t: %v")))
-
- (cons :tag "Action program's arguments" :format "%v"
- (const :format "" action-args)
- (repeat :tag "Action program's arguments"
- (string :format "%v")))
-
- (cons :tag "Action parser function" :format "%v"
- (const :tag "Action parser" :format "%t: "
- action-parser)
- (choice :format "%[Parser%] %v" :value nil
- (const :tag "Ispell" wcheck-parser-ispell-suggestions)
- (const :tag "Lines" wcheck-parser-lines)
- (const :tag "Whitespace" wcheck-parser-whitespace)
- (function :tag "Custom function"
- :format "%t:\n\t\t%v")))
-
- (cons :tag "Action autoselect mode" :format "%v"
- (const :tag "Action autoselect" :format "%t: " action-autoselect)
- (choice :format "%[Mode%] %v" :value nil
- :match (lambda (widget value) t)
- :value-to-internal (lambda (widget value)
- (if value t nil))
- (const :tag "off" nil)
- (const :tag "on" t)))))
-
-
-;;;###autoload
-(defcustom wcheck-language-data
- ;; FIXME: Auto-fill by looking at installed spell-checkers and dictionaries!
- nil
- "Language configuration for `wcheck-mode'.
-
-The variable is an association list (alist) and its elements are
-of the form:
-
- (LANGUAGE (KEY . VALUE) [(KEY . VALUE) ...])
-
-LANGUAGE is a name string for this particular configuration unit
-and KEY and VALUE pairs denote settings for the language.
-
-Below is the documentation of possible KEYs and corresponding
-VALUEs. The documentation is divided in two parts: checker
-options and action options. The first part describes all options
-related to checking the content of an Emacs buffer (and possibly
-marking some of it). The second part describes options which
-configure actions which user can choose for a marked text on
-buffer.
-
-NOTE: There is also variable `wcheck-language-data-defaults'
-which is used to define default values. The defaults are used
-when a language-specific option in `wcheck-language-data' does
-not exist or is not valid.
-
-
-Checker options
----------------
-
-The checker options configure LANGUAGE's text-checking and
-text-marking features. With these you can configure how buffer's
-content is examined, what checker engine is used and how text is
-marked in the buffer.
-
-program
-args
- `program' is either the name (a string) of an external
- executable program or an Emacs Lisp function (a symbol or a
- lambda expression). They are used as the checker engine for
- the LANGUAGE. When `program' names an external executable
- program then `args' are the command-line arguments (a list of
- strings) for the program.
-
- `wcheck-mode' collects text strings from the buffer and sends
- them to `program' to analyze. When `program' is an external
- executable program the collected strings are sent (each on a
- separate line) through the standard input stream to the
- program. The program must write to standard output stream all
- the strings which it thinks should be marked in the Emacs
- buffer. The output of the program is then parsed with
- `parser' function (see below).
-
- When `program' is an Emacs Lisp function (a symbol or a
- lambda expression) the function is called with one argument:
- a list of strings collected from the buffer. The function is
- supposed to check them and return a list of strings (or nil).
- The returned strings will be marked in the buffer.
-
- See options `regexp-start', `regexp-body' and `regexp-end'
- below for details on how text is collected from the buffer.
-
-parser
- VALUE of this option is an Emacs Lisp function which is
- responsible for parsing the output of `program'. This parser
- function is only used when `program' is an external
- executable program (not a function).
-
- The parser function is run without arguments and within the
- context of a buffer that contains all the output from the
- external program. The point is located at the beginning of
- the buffer. From that buffer the `parser' function should
- collect all the strings that are meant to be marked in the
- buffer that is being checked. The function must return them
- as a list of strings or nil if there are none to be marked.
-
- For the most common cases there are two parser functions
- already implemented:
-
- `wcheck-parser-lines' turns each line in program's output
- to a separate string. You should use this function as the
- output parser if you spell-check with Ispell-like program
- with its \"-l\" command-line option. They output each
- misspelled word on a separate line. This is the default
- output parser.
-
- `wcheck-parser-whitespace' turns each whitespace-
- separated token in the output to a separate string.
-
-connection
- The VALUE is used to set variable `process-connection-type'
- when starting the process for LANGUAGE. If the VALUE is nil
- use a pipe for communication; if it's `pty' (or t) use a PTY.
- The default is to use a pipe (nil). (This option is ignored
- when the program is a function.)
-
-face
- A symbol referring to the face which is used to mark text with
- this LANGUAGE. The default is `wcheck-default-face'.
-
-syntax
- VALUE is a variable (a symbol) referring to an Emacs syntax
- table. This option temporarily sets the effective syntax
- table when buffer's content is scanned with `regexp-start',
- `regexp-body', `regexp-end' and `regexp-discard' (see below)
- as well as when `program', `parser', `action-program' and
- `action-parser' functions are called. The default value is
- `text-mode-syntax-table'. This option does not affect syntax
- table settings anywhere else. See the Info node
- `(elisp)Syntax Tables' for more information on the topic.
-
-regexp-start
-regexp-body
-regexp-end
- Regular expression strings which match the start of a string
- body, characters within the body and the end of the body,
- respectively.
-
- This is how they are used in practice: `wcheck-mode' scans
- buffer's content and looks for strings that match the
- following regular expression
-
- REGEXP-START\\(REGEXP-BODY\\)REGEXP-END
-
- The regular expression back reference \\1 is used to extract
- `regexp-body' part from the matched string. That string is
- then matched against `regexp-discard' (see below) and if it
- doesn't match the string is sent to the text checker program
- or function to analyze.
-
- Strings returned from the program or function are quoted for
- regular expression special characters (with `regexp-quote'
- function) and marked in Emacs buffer using the following
- construction: `regexp-start + STRING + regexp-end'. The
- STRING part is marked with `face' (see above).
-
- You can't use grouping constructs `\\( ... \\)' in
- `regexp-start' because the back reference `\\1' is used for
- separating the `regexp-body' match string from the
- `regexp-start' and `regexp-end' match strings. You can use
- \"shy\" groups `\\(?: ... \\)' which do not record the
- matched substring. Grouping constructs `\\( ... \\)' are
- allowed in `regexp-body' and `regexp-end'. Just note that the
- first group and back reference \\1 is already taken.
-
- The default values for the regular expressions are
-
- \\=\\<\\='* (regexp-start)
- \\w+? (regexp-body)
- \\='*\\=\\> (regexp-end)
-
- Effectively they match a series of word characters defined in
- the effective syntax table. Single quotes (\\=') at the start
- and end of a word are excluded. This is probably a good thing
- when using `wcheck-mode' as a spelling checker.
-
-regexp-discard
- The string that matched `regexp-body' is then matched against
- the value of this option. If this regular expression matches,
- then the string is discarded and won't be sent to the
- text-checker program or function to analyze. You can use this
- to define exceptions to the `regexp-body' match. The default
- value is
-
- \\\\=`\\='+\\\\='
-
- which discards the body string if it consists only of single
- quotes. This was chosen as the default because the default
- syntax table `text-mode-syntax-table' defines single quote as
- a word character. It's probably not useful to mark individual
- single quotes in a buffer when `wcheck-mode' is used as a
- spelling checker.
-
- If you don't want to have any discarding rules set this
- option to empty string (\"\").
-
-case-fold
- This boolean value is used to temporarily bind the value of
- variable `case-fold-search'. The nil value means
- case-sensitive and a non-nil means case-insensitive search.
- The default is case-sensitive (nil). This option is effective
- with `regexp-start', `regexp-body', `regexp-end' and
- `regexp-discard' as well as when `program', `parser',
- `action-program' and `action-parser' functions are called.
-
-read-or-skip-faces
- This option controls which faces `wcheck-mode' should read or
- skip when scanning buffer's content. The value must be a list
- and its items are also lists:
-
- (MAJOR-MODE [OPERATION-MODE [FACE ...]])
-
- MAJOR-MODE is a symbol or a list of symbols. Symbols refer to
- the major mode(s) which the settings are for. Use nil as the
- MAJOR-MODE to define default settings. Settings that come
- after the pseudo major-mode nil are ignored.
-
- OPERATION-MODE is symbol `read' or `skip' defining whether
- the FACEs should be read or skipped. If it's `read' then only
- the listed faces are read. If it's `skip' then the listed
- faces are skipped and all other faces are read. If there is
- no OPERATION-MODE at all (i.e., the list has just one
- element, MAJOR-MODE) then everything is read.
-
- The rest of the items are FACEs. They are typically symbols
- but some Emacs modes may use strings, property lists or cons
- cells for defining faces. For more information see Info
- node `(elisp) Special Properties'. Use nil as the face to
- refer to the normal text which does not have a face text
- property.
-
- Example:
-
- (read-or-skip-faces
- ((emacs-lisp-mode c-mode) read
- font-lock-comment-face font-lock-doc-face)
- (org-mode skip font-lock-comment-face org-link)
- (text-mode)
- (nil read nil))
-
- It says that in `emacs-lisp-mode' and `c-mode' only the text
- which have been highlighted with `font-lock-comment-face' or
- `font-lock-doc-face' is read (i.e., checked). In `org-mode'
- faces `font-lock-comment-face' and `org-link' are
- skipped (i.e., not checked) and all other faces are read. In
- `text-mode' everything is read. Finally, in all other major
- modes only the normal text (nil) is read.
-
- Most likely not all `read-or-skip-faces' settings are
- specific to a certain language so it could be more useful to
- put them in variable `wcheck-language-data-defaults' instead.
- That way they are used with all languages. Normally the
- global default is equivalent to
-
- (read-or-skip-faces
- (nil))
-
- which means that in all major modes read everything. It is
- sometimes useful to have this setting in language-specific
- options because the parsing stops right there. Therefore it
- overrides all global settings which user may have changed
- with variable `wcheck-language-data-defaults'.
-
- Note: You can use command `\\[what-cursor-position]' with a
- prefix argument to see what faces are active at the cursor
- position. Then you can use the information to configure this
- option.
-
-
-Action options
---------------
-
-\"Actions\" are any kind of operations that can be executed for
-marked text in an Emacs buffer. Actions are presented to user
-through a menu which is activated either by (1) clicking the
-right mouse button on a marked text or (2) executing interactive
-command `wcheck-actions' while the cursor (the point) is on a
-marked text.
-
-If you use `wcheck-mode' as a spelling checker then it's natural
-to configure an action menu that offers spelling suggestions for
-the misspelled word. The action menu could also have an option to
-add the word to spell-checker's dictionary, so that the word is
-recognized next time.
-
-action-program
-action-args
- `action-program' is either the name (a string) of an external
- executable program or an Emacs Lisp function (a symbol or a
- lambda expression). When it's the name of an executable
- program then `action-args' are the command-line arguments (a
- list of strings) for the program.
-
- When `action-program' is an external executable program the
- marked text is sent to the program through the standard input
- stream. The program should send its feedback data (usually
- suggested substitute strings) to the standard output stream.
- The output is parsed with `action-parser' function (see
- below) and function's return value is used to construct an
- action menu for user. The format and effect of
- `action-parser' function's return value is described below.
-
- When `action-program' is an Emacs Lisp function the function
- is called with one argument: a vector returned by
- `wcheck-marked-text-at' function. The `action-program'
- function is supposed to gather some substitute suggestion
- strings or give other actions for the marked text in the
- buffer. Function's return value is used to construct an
- action menu for user. The format and effect of
- `action-program' function's return value is described below.
-
-action-parser
- VALUE of this option is an Emacs Lisp function which is
- responsible for parsing the output of `action-program'. This
- parser function is only used when `action-program' is an
- external executable program (not a function).
-
- The parser function is run with one argument: a vector
- returned by `wcheck-marked-text-at' for the marked text in
- question. The parser function is called within the context of
- a buffer that contains all the output from `action-program'.
- The point is located at the beginning of the buffer.
-
- The `action-parser' function should examine the buffer for
- interesting information (such as spelling suggestions) and
- return them in the format that is described below.
-
- For the most common cases there are three parser functions
- already implemented:
-
- `wcheck-parser-ispell-suggestions' parses substitute
- suggestions from the output of Ispell or compatible
- program, such as Enchant. Use this function as the
- `action-parser' if you get spelling suggestions from an
- Ispell-like program with its \"-a\" command-line option.
-
- `wcheck-parser-lines' function turns each line in the
- output to individual substitute suggestions.
-
- `wcheck-parser-whitespace'. Each whitespace-separated
- token in the program's output is a separate suggestion.
-
-action-autoselect
- If this option is non-nil and the action menu has only one
- menu item then the item is chosen automatically without
- actually showing the menu. If this option is nil (which is
- the default) then the menu is always shown.
-
-
-The return value of `action-program' function and `action-parser'
-function must be a list. The empty list (nil) means that there
-are no actions available for the marked text. Otherwise each
-elements in the list must be either a string or a cons cell. If
-an element is a string it is an individual substitute suggestion
-string for the original marked text. The same string is shown in
-the actions menu. When user chooses such option from the action
-menu the original text is substituted in the Emacs buffer.
-
-If an element is a cons cell it must be one of
-
- (\"Menu item\" . \"substitute string\")
- (\"Menu item\" . some-function)
-
-The \"car\" value of the cons cell must be a string. The string
-is shown in the action menu as one of the options. The \"cdr\"
-value of the cons cell defines the action that is taken for the
-menu option. If the \"cdr\" value is a string then that string is
-the substitute string. If the \"cdr\" value is a function (a
-symbol or a lambda expression) then that function is called when
-user chooses the menu option. The function is called with one
-argument: a vector returned by `wcheck-marked-text-at' function
-for the marked text in question.
-
-Effectively `action-program' function or `action-program'
-executable program with `action-parser' function provide a
-feature that can offer spelling suggestions for user: just return
-suggestions as a list of strings. Alternatively they can offer
-any kind of useful actions by calling custom functions. There are
-a lot of possibilities.
-
-
-For configuration examples, see the README file in URL
-`https://github.com/tlikonen/wcheck-mode'."
-
- :group 'wcheck
- :type
- `(repeat
- (list :format "%v"
- (string :tag "Language")
- (repeat :inline t
- :tag "Options"
- ,wcheck--language-data-customize-interface))))
-
-
-;;;###autoload
-(defconst wcheck--language-data-defaults-hard-coded
- '((parser . wcheck-parser-lines)
- (connection . nil)
- (face . wcheck-default-face)
- (syntax . text-mode-syntax-table)
- (regexp-start . "\\<'*")
- (regexp-body . "\\w+?")
- (regexp-end . "'*\\>")
- (regexp-discard . "\\`'+\\'")
- (case-fold . nil)
- (read-or-skip-faces (nil))
- (action-autoselect . nil))
- "Hard-coded default language configuration for `wcheck-mode'.
-This constant is for Wcheck mode's internal use only. This
-provides useful defaults if both `wcheck-language-data' and
-`wcheck-language-data-defaults' fail.")
-
-
-;;;###autoload
-(defcustom wcheck-language-data-defaults
- wcheck--language-data-defaults-hard-coded
- "Default language configuration for `wcheck-mode'.
-These default values are used when language-specific settings
-don't provide a valid value. `wcheck-mode' will choose some
-useful defaults even if this variable is not (properly) set. See
-variable `wcheck-language-data' for information about possible
-settings.
-
-Here's an example value for the variable:
-
- ((parser . wcheck-parser-lines)
- (action-parser . wcheck-parser-ispell-suggestions)
- (connection . nil)
- (face . wcheck-default-face)
- (syntax . text-mode-syntax-table)
- (regexp-start . \"\\\\=\\<\\='*\")
- (regexp-body . \"\\\\w+?\")
- (regexp-end . \"\\='*\\\\=\\>\")
- (regexp-discard . \"\\\\\\=`\\='+\\\\\\='\")
- (case-fold . nil)
- (read-or-skip-faces
- ((emacs-lisp-mode c-mode) read
- font-lock-comment-face font-lock-doc-face)
- (message-mode read nil
- message-header-subject message-cited-text)))"
-
- :group 'wcheck
- :type `(repeat ,wcheck--language-data-customize-interface))
-
-
-;;;###autoload
-(defcustom wcheck-language ""
- "Default language for `wcheck-mode'.
-
-Normally the global value defines the language for new buffers.
-If a buffer-local value exists it is used instead. This variable
-becomes automatically buffer-local when `wcheck-mode' is turned
-on in a buffer, so changing the global value does not affect
-buffers which already have `wcheck-mode' turned on.
-
-User is free to set this variable directly (e.g., in programs)
-but in interactive use it is usually better to use the command
-`\\[wcheck-change-language]' instead. The command can change
-language immediately while `wcheck-mode' is turned on, whereas
-changing just the value of this variable takes effect only when
-`wcheck-mode' is turned on next time."
- :type '(string :tag "Default language")
- :group 'wcheck)
-(make-variable-buffer-local 'wcheck-language)
-
-
-;;;###autoload
-(defface wcheck-default-face
- '((t (:underline "red")))
- "Default face for marking strings in a buffer.
-This is used when language does not define a face."
- :group 'wcheck)
-
-
-;;; Variables
-
-
-(defvar wcheck-mode nil)
-(defvar wcheck-mode-map (make-sparse-keymap)
- "Keymap for `wcheck-mode'.")
-
-(defvar wcheck--timer nil)
-(defvar wcheck--timer-idle .3
- "`wcheck-mode' idle timer delay (in seconds).")
-(defvar wcheck--timer-paint-event-count 0)
-
-(defvar wcheck--timer-paint-event-count-std 3
- "Run buffer paint event this many times in a row.
-With too low values all data from external processes may not have
-arrived and window gets only partially painted. A higher value
-increases the probability that windows get fully painted but it
-also makes `wcheck-jump-forward' and `wcheck-jump-backward'
-slower. A suitable compromise may be 3 or 4.")
-
-(defvar wcheck--change-language-history nil
- "Language history for command `wcheck-change-language'.")
-
-(defvar wcheck--buffer-data nil)
-
-(defvar wcheck--jump-step 5000)
-
-
-;;; Macros
-
-
-(defmacro wcheck--define-condition (name superclass &optional message)
- (declare (indent defun))
- `(progn
- (put ',name 'error-conditions
- (append (get ',superclass 'error-conditions) (list ',name)))
- (put ',name 'error-message ,message)
- ',name))
-
-
-(defmacro wcheck--loop-over-reqs-engine (key var &rest body)
- `(dolist (,var (delq nil (mapcar (lambda (buffer)
- (when (wcheck--buffer-data-get
- :buffer buffer ,key)
- buffer))
- (wcheck--buffer-data-get-all :buffer))))
- (when (buffer-live-p ,var)
- (with-current-buffer ,var
- ,@body))))
-
-
-(defmacro wcheck--loop-over-read-reqs (var &rest body)
- (declare (indent 1))
- `(wcheck--loop-over-reqs-engine :read-req ,var ,@body))
-(defmacro wcheck--loop-over-paint-reqs (var &rest body)
- (declare (indent 1))
- `(wcheck--loop-over-reqs-engine :paint-req ,var ,@body))
-(defmacro wcheck--loop-over-jump-reqs (var &rest body)
- (declare (indent 1))
- `(wcheck--loop-over-reqs-engine :jump-req ,var ,@body))
-
-
-(defmacro wcheck--with-language-data (var-lang bindings &rest body)
- (declare (indent 2))
- (let ((language (make-symbol "--wck-language--")))
- `(let* ((,language ,(cadr var-lang))
- ,@(when (car var-lang)
- `((,(car var-lang) ,language)))
- ,@(mapcar
- (lambda (var)
- (cond ((symbolp var)
- (list var `(wcheck-query-language-data
- ,language ',var)))
- ((and var (listp var))
- (list (car var) `(wcheck-query-language-data
- ,language ',(cadr var))))))
- bindings))
- ,@body)))
-
-
-;;; Conditions
-
-
-(wcheck--define-condition wcheck--error error)
-(wcheck--define-condition wcheck--language-does-not-exist-error wcheck--error)
-(wcheck--define-condition wcheck--program-not-configured-error wcheck--error)
-(wcheck--define-condition wcheck--not-a-list-of-strings-error wcheck--error)
-(wcheck--define-condition wcheck--funcall-error wcheck--error)
-(wcheck--define-condition wcheck--action-error wcheck--error)
-(wcheck--define-condition wcheck--action-program-error wcheck--action-error)
-(wcheck--define-condition wcheck--parser-function-not-configured-error
- wcheck--action-error)
-(wcheck--define-condition wcheck--overlay-not-found-error wcheck--error)
-
-
-;;; Interactive commands
-
-
-;;;###autoload
-(defun wcheck-change-language (language &optional global)
- "Change language for current buffer (or globally).
-Change `wcheck-mode' language to LANGUAGE. The change is
-buffer-local but if GLOBAL is non-nil (prefix argument if called
-interactively) then change the global default language."
- (interactive
- (let* ((comp (mapcar #'car wcheck-language-data))
- (default (cond ((and current-prefix-arg
- (member (default-value 'wcheck-language) comp))
- (default-value 'wcheck-language))
- ((member wcheck-language comp)
- wcheck-language)
- ((car comp))
- (t ""))))
- (list (completing-read
- (format (if current-prefix-arg
- "Global default language (%s): "
- "Language for the current buffer (%s): ")
- default)
- comp nil t nil 'wcheck--change-language-history default)
- current-prefix-arg)))
-
- (condition-case error-data
- (when (stringp language)
- ;; Change the language, locally or globally, and update buffer
- ;; database, if needed.
- (if global
- ;; Just change the global value and leave.
- (setq-default wcheck-language language)
-
- ;; Change the buffer-local value.
- (setq wcheck-language language)
- ;; If the mode is currently turned on check if language's
- ;; checker program or function is configured and if all is OK
- ;; request update for the buffer.
- (when wcheck-mode
- (if (wcheck--program-configured-p wcheck-language)
- ;; It's OK; update the buffer.
- (progn
- (wcheck--buffer-lang-proc-data-update
- (current-buffer) wcheck-language)
- (wcheck--buffer-data-set (current-buffer) :read-req t)
- (wcheck--remove-overlays))
-
- (signal 'wcheck--program-not-configured-error wcheck-language))))
-
- ;; Return the language.
- language)
-
- (wcheck--program-not-configured-error
- (wcheck-mode -1)
- (message "Language \"%s\": checker program is not configured"
- (cdr error-data)))))
-
-
-(defun wcheck--mode-turn-on ()
- ;; Turn the mode on, but first some checks.
- (let ((buffer (current-buffer))
- (language wcheck-language))
- (condition-case error-data
- (cond
- ((minibufferp buffer)
- (signal 'wcheck--error "Can't use `wcheck-mode' in a minibuffer"))
-
- ((not (wcheck--language-exists-p language))
- (signal 'wcheck--language-does-not-exist-error language))
-
- ((not (wcheck--program-configured-p language))
- (signal 'wcheck--program-not-configured-error language))
-
- (t
- (make-local-variable 'wcheck-language)
- (wcheck--add-local-hooks buffer)
- (wcheck--add-global-hooks)
- (wcheck--buffer-lang-proc-data-update buffer language)
- (wcheck--timer-start)
- (wcheck--buffer-data-set buffer :read-req t)))
-
- (wcheck--program-not-configured-error
- (wcheck-mode -1)
- (message "Language \"%s\": checker program not configured"
- (cdr error-data)))
-
- (wcheck--language-does-not-exist-error
- (wcheck-mode -1)
- (message "Language \"%s\" does not exist" (cdr error-data))))))
-
-
-(defun wcheck--mode-turn-off ()
- (let ((buffer (current-buffer)))
- ;; We clear overlays form the buffer, remove the buffer from buffer
- ;; database.
- (wcheck--remove-overlays)
- (wcheck--buffer-lang-proc-data-update buffer nil)
-
- ;; If there are no buffers using wcheck-mode anymore, stop the idle
- ;; timer and remove global hooks.
- (when (null (wcheck--buffer-data-get-all :buffer))
- (wcheck--timer-stop)
- (wcheck--remove-global-hooks))
- (wcheck--remove-local-hooks buffer)))
-
-
-(defun wcheck--mode-line-lang ()
- (condition-case nil
- (let (lang-code)
- (catch 'enough
- (mapc (lambda (c)
- (when (char-equal ?w (char-syntax c))
- (push c lang-code)
- (when (>= (length lang-code) 2)
- (throw 'enough t))))
- (wcheck--buffer-data-get :buffer (current-buffer) :language)))
- (apply #'string (nreverse lang-code)))
- (error "")))
-
-
-;;;###autoload
-(define-minor-mode wcheck-mode
- "General interface for text checkers.
-
-With optional (prefix) ARG turn on the mode if ARG is positive,
-otherwise turn it off. If ARG is not given toggle the mode.
-
-Wcheck is a minor mode for automatically checking and marking
-strings in Emacs buffer. Wcheck sends (parts of) buffer's content
-to a text-checker back-end and, relying on its output, decides if
-some parts of text should be marked.
-
-Wcheck can be used with external spell-checker programs such as
-Ispell and Enchant, but actually any tool that can receive text
-stream from standard input and send text to standard output can
-be used. The checker back-end can also be an Emacs Lisp function.
-
-Different configuration units are called \"languages\". See the
-documentation of variables `wcheck-language-data',
-`wcheck-language-data-defaults' and `wcheck-language' for
-information on how to configure Wcheck mode. You can access and
-configure the variables through customize group `wcheck'.
-
-Interactive command `wcheck-change-language' is used to switch
-languages. Command `wcheck-actions' gives an action menu for the
-marked text at point (also accessible through the right-click
-mouse menu). Commands `wcheck-jump-forward' and
-`wcheck-jump-backward' move point to next/previous marked text
-area.
-
-A note for Emacs Lisp programmers: Emacs Lisp function
-`wcheck-marked-text-at' returns information about marked text at
-a buffer position. Function `wcheck-query-language-data' can be
-used for querying effective configuration data for any language."
-
- :init-value nil
- :lighter (" W:" (:eval (wcheck--mode-line-lang)))
- :keymap wcheck-mode-map
-
- (condition-case error-data
- (if wcheck-mode
- (wcheck--mode-turn-on)
- (wcheck--mode-turn-off))
-
- (wcheck--error
- (wcheck-mode -1)
- (message "%s" (cdr error-data)))))
-
-
-;;; Timers
-
-
-(defun wcheck--timer-start ()
- "Start `wcheck-mode' idle timer if it's not running already."
- (unless wcheck--timer
- (setq wcheck--timer
- (run-with-idle-timer wcheck--timer-idle t
- #'wcheck--timer-read-event))))
-
-
-(defun wcheck--timer-stop ()
- "Stop `wcheck-mode' idle timer."
- (when wcheck--timer
- (cancel-timer wcheck--timer)
- (setq wcheck--timer nil)))
-
-
-(defun wcheck--funcall-after-idle (function &rest args)
- (apply #'run-with-idle-timer
- (+ wcheck--timer-idle (wcheck--current-idle-time-seconds))
- nil function args))
-
-
-(defun wcheck--timer-paint-event-run (&optional count)
- (if (integerp count)
- (let ((at-least (max count wcheck--timer-paint-event-count)))
- (if (> wcheck--timer-paint-event-count 0)
- (setq wcheck--timer-paint-event-count at-least)
- (setq wcheck--timer-paint-event-count at-least)
- (wcheck--funcall-after-idle #'wcheck--timer-paint-event)))
- (if (> (setq wcheck--timer-paint-event-count
- (1- wcheck--timer-paint-event-count))
- 0)
- (wcheck--funcall-after-idle #'wcheck--timer-paint-event)
- (wcheck--timer-jump-event))))
-
-
-(defun wcheck--force-read (buffer)
- (redisplay t)
- (wcheck--buffer-data-set buffer :read-req t)
- (wcheck--timer-read-event))
-
-
-(defun wcheck--timer-read-event ()
- "Send windows' content to checker program or function.
-
-This function is usually called by the `wcheck-mode' idle timer.
-The function walks through all windows which belong to buffers
-that have requested update. It reads windows' content and sends
-it checker program or function associated with the buffer's
-language. Finally, this function starts another idle timer for
-marking strings in buffers."
-
- (wcheck--loop-over-read-reqs buffer
- (unless (wcheck--buffer-data-get :buffer buffer :jump-req)
- ;; We are about to fulfill buffer's window-reading request so
- ;; remove the request. Reset also the list of received strings and
- ;; visible window areas.
- (wcheck--buffer-data-set buffer :read-req nil)
- (wcheck--buffer-data-set buffer :strings nil)
- (wcheck--buffer-data-set buffer :areas nil)
-
- ;; Walk through all windows which belong to this buffer.
- (let (area-alist strings)
- (walk-windows (lambda (window)
- (when (eq buffer (window-buffer window))
- ;; Store the visible buffer area.
- (push (cons (window-start window)
- (window-end window t))
- area-alist)))
- 'nomb t)
-
- ;; Combine overlapping buffer areas and read strings from all
- ;; areas.
- (let ((combined (wcheck--combine-overlapping-areas area-alist)))
- (wcheck--buffer-data-set buffer :areas combined)
- (dolist (area combined)
- (setq strings (append (wcheck--read-strings
- buffer (car area) (cdr area))
- strings))))
- ;; Send strings to checker engine.
- (wcheck--send-strings buffer strings))))
-
- ;; Start a timer which will mark text in buffers/windows.
- (wcheck--timer-paint-event-run wcheck--timer-paint-event-count-std))
-
-
-(defun wcheck--send-strings (buffer strings)
- "Send STRINGS for the process that handles BUFFER.
-STRINGS is a list of strings to be sent as input for the external
-process which handles BUFFER. Each string in STRINGS is sent as
-separate line."
- (wcheck--with-language-data
- (nil (wcheck--buffer-data-get :buffer buffer :language))
- (program syntax (case-fold-search case-fold))
-
- (condition-case nil
- (cond ((or (wcheck--buffer-data-get :buffer buffer :process)
- (stringp program))
- (process-send-string
- (wcheck--start-get-process buffer)
- (concat (mapconcat #'identity strings "\n") "\n"))
- (condition-case nil
- (with-current-buffer
- (process-buffer (wcheck--buffer-data-get
- :buffer buffer :process))
- (erase-buffer))
- (error nil)))
-
- ((functionp program)
- (when (buffer-live-p buffer)
- (with-current-buffer buffer
- (let ((received
- (save-match-data
- (condition-case nil
- (with-syntax-table (eval syntax)
- (funcall program strings))
- (error (signal 'wcheck--funcall-error nil))))))
- (if (wcheck--list-of-strings-p received)
- (when received
- (wcheck--buffer-data-set buffer :strings received)
- (wcheck--buffer-data-set buffer :paint-req t))
- (signal 'wcheck--not-a-list-of-strings-error nil)))))))
-
- (wcheck--not-a-list-of-strings-error
- (with-current-buffer buffer
- (wcheck-mode -1)
- (message (concat "Checker function did not return a list of "
- "strings (or nil)"))))
-
- (wcheck--funcall-error
- (message "Checker function signaled an error")))))
-
-
-(defun wcheck--receive-strings (process string)
- "`wcheck-mode' process output handler function."
- (let ((buffer (wcheck--buffer-data-get :process process :buffer)))
- (wcheck--with-language-data
- (nil (wcheck--buffer-data-get :process process :language))
- (parser syntax (case-fold-search case-fold))
- (when (buffer-live-p buffer)
- (with-current-buffer buffer
-
- ;; If process is running proceed to collect and paint the
- ;; strings.
- (condition-case error-data
- (if (wcheck--process-running-p process)
- (with-current-buffer (process-buffer process)
- (save-excursion
- (goto-char (point-max))
- (insert string)
- (let ((parsed-strings
- (save-match-data
- (save-excursion
- (goto-char (point-min))
- (condition-case nil
- (with-syntax-table (eval syntax)
- (funcall parser))
- (error (signal 'wcheck--funcall-error
- nil)))))))
- (when (and parsed-strings
- (wcheck--list-of-strings-p parsed-strings))
- (wcheck--buffer-data-set
- buffer :strings parsed-strings)
- (wcheck--buffer-data-set buffer :paint-req t)))))
-
- ;; It's not running. Turn off the mode.
- (wcheck-mode -1)
- (signal 'wcheck--error
- (format "Process is not running for buffer \"%s\""
- (buffer-name buffer))))
-
- (wcheck--funcall-error
- (message "Checker output parser function signaled an error"))
-
- (wcheck--error
- (message "%s" (cdr error-data)))))))))
-
-
-(defun wcheck--timer-paint-event ()
- "Mark strings in windows.
-
-This is normally called by the `wcheck-mode' idle timer. This
-function marks (with overlays) strings in the buffers that have
-requested it."
-
- (wcheck--loop-over-paint-reqs buffer
- (unless (wcheck--buffer-data-get :buffer buffer :jump-req)
- (wcheck--remove-overlays))
- ;; We are about to mark text in this buffer so remove this buffer's
- ;; request.
- (wcheck--buffer-data-set buffer :paint-req nil)
- ;; Walk through the visible text areas and mark text based on the
- ;; string list returned by an external process.
- (when wcheck-mode
- (dolist (area (wcheck--buffer-data-get :buffer buffer :areas))
- (wcheck--paint-strings buffer (car area) (cdr area)
- (wcheck--buffer-data-get :buffer buffer
- :strings)
- ;; If jump-req is active then paint
- ;; invisible text too.
- (wcheck--buffer-data-get :buffer buffer
- :jump-req)))))
-
- (wcheck--timer-paint-event-run))
-
-
-(defun wcheck--timer-jump-event ()
- (require 'outline)
- (wcheck--loop-over-jump-reqs buffer
- (let* ((jump-req (wcheck--buffer-data-get :buffer buffer :jump-req))
- (start (wcheck--jump-req-start jump-req))
- (bound (wcheck--jump-req-bound jump-req))
- (window (wcheck--jump-req-window jump-req)))
-
- (wcheck--buffer-data-set buffer :jump-req nil)
-
- (condition-case nil
- (cond ((> bound start)
- (let ((ol (wcheck--overlay-next start bound)))
- (cond (ol
- (if (and (window-live-p window)
- (eq buffer (window-buffer window)))
- (set-window-point window (overlay-end ol))
- (goto-char (overlay-end ol)))
- (when (invisible-p (point))
- (outline-show-entry))
- (message "Found from line %s"
- (line-number-at-pos (point)))
- (wcheck--force-read buffer))
- ((< bound (point-max))
- (wcheck--jump-req buffer window (1+ bound)
- (+ (1+ bound) wcheck--jump-step)))
- (t
- (signal 'wcheck--overlay-not-found-error nil)))))
- ((< bound start)
- (let ((ol (wcheck--overlay-previous start bound)))
- (cond (ol
- (if (and (window-live-p window)
- (eq buffer (window-buffer window)))
- (set-window-point window (overlay-start ol))
- (goto-char (overlay-start ol)))
- (when (invisible-p (point))
- (outline-show-entry))
- (message "Found from line %s"
- (line-number-at-pos (point)))
- (wcheck--force-read buffer))
- ((> bound (point-min))
- (wcheck--jump-req buffer window (1- bound)
- (- (1- bound) wcheck--jump-step)))
- (t
- (signal 'wcheck--overlay-not-found-error nil)))))
- (t
- (signal 'wcheck--overlay-not-found-error nil)))
-
- (wcheck--overlay-not-found-error
- (message "Found nothing")
- (wcheck--force-read buffer))))))
-
-
-;;; Hooks
-
-
-(defun wcheck--add-local-hooks (buffer)
- (with-current-buffer buffer
- (dolist (hook '((kill-buffer-hook . wcheck--hook-kill-buffer)
- (window-scroll-functions . wcheck--hook-window-scroll)
- (after-change-functions . wcheck--hook-after-change)
- (change-major-mode-hook . wcheck--hook-change-major-mode)
- (outline-view-change-hook
- . wcheck--hook-outline-view-change)))
- (add-hook (car hook) (cdr hook) nil t))))
-
-
-(defun wcheck--remove-local-hooks (buffer)
- (with-current-buffer buffer
- (dolist (hook '((kill-buffer-hook . wcheck--hook-kill-buffer)
- (window-scroll-functions . wcheck--hook-window-scroll)
- (after-change-functions . wcheck--hook-after-change)
- (change-major-mode-hook . wcheck--hook-change-major-mode)
- (outline-view-change-hook
- . wcheck--hook-outline-view-change)))
- (remove-hook (car hook) (cdr hook) t))))
-
-
-(defun wcheck--add-global-hooks ()
- (dolist (hook '((window-size-change-functions
- . wcheck--hook-window-size-change)
- (window-configuration-change-hook
- . wcheck--hook-window-configuration-change)))
- (add-hook (car hook) (cdr hook))))
-
-
-(defun wcheck--remove-global-hooks ()
- (dolist (hook '((window-size-change-functions
- . wcheck--hook-window-size-change)
- (window-configuration-change-hook
- . wcheck--hook-window-configuration-change)))
- (remove-hook (car hook) (cdr hook))))
-
-
-(defun wcheck--hook-window-scroll (window _window-start)
- "`wcheck-mode' hook for window scroll.
-Request update for the buffer when its window have been scrolled."
- (with-current-buffer (window-buffer window)
- (when wcheck-mode
- (wcheck--buffer-data-set (current-buffer) :read-req t))))
-
-
-(defun wcheck--hook-window-size-change (frame)
- "`wcheck-mode' hook for window size change.
-Request update for the buffer when its window's size has
-changed."
- (walk-windows (lambda (window)
- (with-current-buffer (window-buffer window)
- (when wcheck-mode
- (wcheck--buffer-data-set (current-buffer)
- :read-req t))))
- 'nomb
- frame))
-
-
-(defun wcheck--hook-window-configuration-change ()
- "`wcheck-mode' hook for window configuration change.
-Request update for the buffer when its window's configuration has
-changed."
- (walk-windows (lambda (window)
- (with-current-buffer (window-buffer window)
- (when wcheck-mode
- (wcheck--buffer-data-set (current-buffer)
- :read-req t))))
- 'nomb
- 'currentframe))
-
-
-(defun wcheck--hook-after-change (_beg _end _len)
- "`wcheck-mode' hook for buffer content change.
-Request update for the buffer when its content has been edited."
- ;; The buffer that has changed is the current buffer when this hook
- ;; function is called.
- (when wcheck-mode
- (wcheck--buffer-data-set (current-buffer) :read-req t)))
-
-
-(defun wcheck--hook-outline-view-change ()
- "`wcheck-mode' hook for outline view change.
-Request update for the buffer when its outline view has changed."
- (when wcheck-mode
- (wcheck--buffer-data-set (current-buffer) :read-req t)))
-
-
-(defun wcheck--hook-kill-buffer ()
- "`wcheck-mode' hook for kill-buffer operation.
-Turn off `wcheck-mode' when buffer is being killed."
- (wcheck-mode -1))
-
-
-(defun wcheck--hook-change-major-mode ()
- "`wcheck-mode' hook for major mode change.
-Turn off `wcheck-mode' before changing major mode."
- (wcheck-mode -1))
-
-
-;;; Processes
-
-
-(defun wcheck--start-get-process (buffer)
- "Start or get external process for BUFFER.
-Start a new process or get already existing process for BUFFER.
-Return the object of that particular process or nil if the
-operation was unsuccessful."
- ;; If process for this BUFFER exists return it.
- (or (wcheck--buffer-data-get :buffer buffer :process)
- ;; It doesn't exist so start a new one.
- (wcheck--with-language-data
- (nil (wcheck--buffer-data-get :buffer buffer :language))
- (program args (process-connection-type connection))
-
- (when (wcheck--program-executable-p program)
- ;; Start the process.
- (let ((proc (apply #'start-process "wcheck" nil program args)))
- ;; Add the process Lisp object to database.
- (wcheck--buffer-data-set buffer :process proc)
- ;; Set the output handler function and the associated buffer.
- (set-process-filter proc #'wcheck--receive-strings)
- (set-process-buffer proc (generate-new-buffer
- (concat " *wcheck-process <"
- (buffer-name buffer) ">*")))
- ;; Prevent Emacs from querying user about running processes
- ;; when killing Emacs.
- (set-process-query-on-exit-flag proc nil)
- ;; Return the process object.
- proc)))))
-
-
-(defun wcheck--buffer-lang-proc-data-update (buffer language)
- "Update process and language data for BUFFER.
-Calling this function is the primary way to maintain the language
-and process data associated to BUFFER. If LANGUAGE is nil remove
-BUFFER from the list."
- (when (and (bufferp buffer)
- (or (stringp language)
- (not language)))
-
- ;; Construct a list of currently used processes.
- (let ((old-processes (remq nil (wcheck--buffer-data-get-all :process))))
-
- ;; Remove dead buffers and possible minibuffers from the list.
- (dolist (item (wcheck--buffer-data-get-all :buffer))
- (when (or (not (buffer-live-p item))
- (minibufferp item))
- (wcheck--buffer-data-delete item)))
-
- (if language
- (progn
- ;; LANGUAGE was given. If data for this buffer does not
- ;; exist create it.
- (unless (wcheck--buffer-data-get :buffer buffer)
- (wcheck--buffer-data-create buffer))
- ;; Add this BUFFER's language info and reset the process
- ;; info.
- (wcheck--buffer-data-set buffer :language language)
- (wcheck--buffer-data-set buffer :process nil))
-
- ;; LANGUAGE was not given so this normally means that
- ;; wcheck-mode is being turned off for this buffer. Remove
- ;; BUFFER's data.
- (wcheck--buffer-data-delete buffer))
-
- ;; Construct a list of processes that are still used.
- (let ((new-processes (remq nil (wcheck--buffer-data-get-all :process))))
- ;; Stop those processes which are no longer needed.
- (dolist (proc old-processes)
- (unless (memq proc new-processes)
- (kill-buffer (process-buffer proc))
- (delete-process proc))))))
-
- (wcheck--buffer-data-get :buffer buffer))
-
-
-;;; Read and paint strings
-
-
-(defun wcheck--read-strings (buffer beg end &optional invisible)
- "Return a list of text elements in BUFFER.
-Scan BUFFER between positions BEG and END and search for text
-elements according to buffer's language settings (see
-`wcheck-language-data'). If INVISIBLE is non-nil read all buffer
-areas, including invisible ones. Otherwise skip invisible text."
-
- (when (buffer-live-p buffer)
- (with-current-buffer buffer
- (save-excursion
-
- (when font-lock-mode
- (save-excursion
- (funcall (if (fboundp 'font-lock-ensure)
- #'font-lock-ensure
- #'font-lock-fontify-region)
- (min beg end) (max beg end))))
-
- (wcheck--with-language-data
- (language (wcheck--buffer-data-get :buffer buffer :language))
- (regexp-start regexp-body regexp-end regexp-discard
- syntax (case-fold-search case-fold))
-
- (let ((regexp
- (concat regexp-start "\\(" regexp-body "\\)" regexp-end))
- (face-p (wcheck--generate-face-predicate language major-mode))
- (search-spaces-regexp nil)
- (old-point 0)
- strings)
-
- (with-syntax-table (eval syntax)
- (goto-char beg)
- (save-match-data
- (while (and (re-search-forward regexp end t)
- (> (point) old-point))
- (cond ((and (not invisible)
- (invisible-p (match-beginning 1)))
- ;; This point is invisible. Let's jump forward
- ;; to next change of "invisible" property.
- (goto-char (next-single-char-property-change
- (match-beginning 1) 'invisible buffer
- end)))
-
- ((and (funcall face-p)
- (or (equal regexp-discard "")
- (not (string-match
- regexp-discard
- (match-string-no-properties 1)))))
- ;; Add the match to the string list.
- (push (match-string-no-properties 1) strings)))
- (setq old-point (point)))))
- (delete-dups strings)))))))
-
-
-(defun wcheck--paint-strings (buffer beg end strings &optional invisible)
- "Mark strings in buffer.
-
-Mark all strings in STRINGS which are visible in BUFFER within
-position range from BEG to END. If INVISIBLE is non-nil paint all
-buffer areas, including invisible ones. Otherwise skip invisible
-text."
-
- (when (buffer-live-p buffer)
- (with-current-buffer buffer
- (save-excursion
-
- (wcheck--with-language-data
- (language (wcheck--buffer-data-get :buffer buffer :language))
- (regexp-start regexp-end syntax (case-fold-search case-fold)
- (ol-face face) action-program)
-
- (let ((face-p (wcheck--generate-face-predicate language major-mode))
- (search-spaces-regexp nil)
- (ol-keymap (make-sparse-keymap))
- (ol-mouse-face nil)
- (ol-help-echo nil)
- regexp old-point)
-
- (when action-program
- (define-key ol-keymap [down-mouse-3]
'wcheck--mouse-click-overlay)
- (define-key ol-keymap [mouse-3] 'undefined)
- (setq ol-mouse-face 'highlight
- ol-help-echo "mouse-3: show actions"))
-
- (with-syntax-table (eval syntax)
- (save-match-data
- (dolist (string strings)
- (setq regexp (concat regexp-start "\\("
- (regexp-quote string) "\\)"
- regexp-end)
- old-point 0)
- (goto-char beg)
-
- (while (and (re-search-forward regexp end t)
- (> (point) old-point))
- (cond ((and (not invisible)
- (invisible-p (match-beginning 1)))
- ;; The point is invisible so jump forward to
- ;; the next change of "invisible" text
- ;; property.
- (goto-char (next-single-char-property-change
- (match-beginning 1) 'invisible buffer
- end)))
- ((funcall face-p)
- ;; Make an overlay.
- (wcheck--make-overlay
- buffer ol-face ol-mouse-face ol-help-echo ol-keymap
- (match-beginning 1) (match-end 1))))
- (setq old-point (point))))))))))))
-
-
-;;; Jump forward or backward
-
-
-(defun wcheck--overlay-next (start bound)
- (unless (>= start (point-max))
- (catch 'overlay
- (dolist (ol (overlays-at start))
- (when (overlay-get ol 'wcheck-mode)
- (throw 'overlay ol)))
- (let ((pos start))
- (while (and (setq pos (next-overlay-change pos))
- (< pos (min bound (point-max))))
- (dolist (ol (overlays-at pos))
- (when (overlay-get ol 'wcheck-mode)
- (throw 'overlay ol))))))))
-
-
-(defun wcheck--overlay-previous (start bound)
- (unless (<= start (point-min))
- (catch 'overlay
- (let ((pos start))
- (while t
- (setq pos (previous-overlay-change pos))
- (dolist (ol (overlays-at pos))
- (when (overlay-get ol 'wcheck-mode)
- (throw 'overlay ol)))
- (when (<= pos (max bound (point-min)))
- (throw 'overlay nil)))))))
-
-
-(defun wcheck--line-start-at (pos)
- (save-excursion
- (goto-char pos)
- (line-beginning-position)))
-
-
-(defun wcheck--line-end-at (pos)
- (save-excursion
- (goto-char pos)
- (line-end-position)))
-
-
-(defun wcheck--jump-req (buffer window start bound)
- (unless (= start bound)
- (with-current-buffer buffer
- (setq bound (funcall (if (> bound start)
- 'wcheck--line-end-at
- 'wcheck--line-start-at)
- bound))
- (message "Searching in lines %d-%d..."
- (line-number-at-pos start)
- (line-number-at-pos bound))
- (wcheck--buffer-data-set buffer :jump-req (wcheck--jump-req-create
- window start bound))
- (wcheck--buffer-data-set buffer :areas (list (cons (min start bound)
- (max start bound))))
- (wcheck--send-strings buffer (wcheck--read-strings
- buffer (min start bound)
- (max start bound) t))
- (wcheck--timer-paint-event-run wcheck--timer-paint-event-count-std))))
-
-
-(defun wcheck--invisible-text-in-area-p (buffer beg end)
- (catch 'invisible
- (let ((pos (min beg end))
- (end (max beg end)))
- (when (invisible-p pos)
- (throw 'invisible t))
- (while (and (setq pos (next-single-char-property-change
- pos 'invisible buffer))
- (< pos end))
- (when (invisible-p pos)
- (throw 'invisible t))))))
-
-
-;;;###autoload
-(defun wcheck-jump-forward ()
- "Move point forward to next marked text area."
- (interactive)
- (let ((buffer (current-buffer))
- (window (selected-window)))
- (unless wcheck-mode
- (wcheck-mode 1))
- (when wcheck-mode
- (wcheck--buffer-data-set buffer :jump-req nil)
- (let ((ol (wcheck--overlay-next
- (point) (window-end (selected-window) t))))
- (if (and ol (not (wcheck--invisible-text-in-area-p
- buffer (point) (overlay-end ol))))
- (goto-char (overlay-end ol))
- (if (eobp)
- (message "End of buffer")
- (wcheck--jump-req buffer window (point)
- (+ (point) wcheck--jump-step))))))))
-
-
-;;;###autoload
-(defun wcheck-jump-backward ()
- "Move point backward to previous marked text area."
- (interactive)
- (let ((buffer (current-buffer))
- (window (selected-window)))
- (unless wcheck-mode
- (wcheck-mode 1))
- (when wcheck-mode
- (wcheck--buffer-data-set buffer :jump-req nil)
- (let ((ol (wcheck--overlay-previous
- (point) (window-start (selected-window)))))
- (if (and ol (not (wcheck--invisible-text-in-area-p
- buffer (point) (overlay-start ol))))
- (goto-char (overlay-start ol))
- (if (bobp)
- (message "Beginning of buffer")
- (wcheck--jump-req buffer window (point)
- (- (point) wcheck--jump-step))))))))
-
-
-;;; Actions
-
-
-(defun wcheck-marked-text-at (pos)
- "Return information about marked text at POS.
-
-POS is a buffer position. The return value is a vector of five
-elements: (1) the marked text string, (2) buffer position at the
-beginning of the text, (3) position at the end of the text, (4)
-the overlay object which marks the text and (5) the current
-language as a string. The return value is nil if there are no
-marked text at POS.
-
-If you need more information about the current language settings
-use `wcheck-query-language-data' for querying effective language
-settings."
-
- (let ((overlay (catch 'my-overlay
- (dolist (ol (overlays-at pos))
- (when (overlay-get ol 'wcheck-mode)
- (throw 'my-overlay ol))))))
- (when overlay
- (let ((start (overlay-start overlay))
- (end (overlay-end overlay)))
- (vector (buffer-substring-no-properties start end)
- start end overlay
- (wcheck--buffer-data-get
- :buffer (current-buffer) :language))))))
-
-
-;;;###autoload
-(defun wcheck-actions (pos &optional event)
- "Offer actions for marked text.
-
-This function is usually called through a right mouse button
-event or interactively by a user. In both cases function's
-arguments are filled automatically.
-
-If buffer position POS is on marked text (and action program is
-properly configured) show a menu of actions. When this function
-is called interactively POS is automatically the current point
-position. Optional EVENT argument is a mouse event which is
-present if this function is called through a right mouse button
-click on marked text. If EVENT is non-nil use a graphic toolkit's
-menu (when available) for selecting actions. Otherwise use a text
-menu.
-
-When user chooses one of the options from the menu the related
-action is executed. It could mean that the original marked text
-is replaced with the chosen substitute. Menu options can trigger
-any kind of actions, though."
-
- (interactive "d")
- (condition-case error-data
- (let ((marked-text (or (wcheck-marked-text-at pos)
- (wcheck-marked-text-at (1- pos))))
- (return-value nil))
-
- (if (not marked-text)
- (signal 'wcheck--action-error "There is no marked text here")
- (let* ((start (copy-marker (aref marked-text 1)))
- (end (copy-marker (aref marked-text 2)))
- (actions (wcheck--get-actions marked-text))
- (choice (cond ((and (null (cdr actions))
- (wcheck-query-language-data
- (aref marked-text 4) 'action-autoselect))
- (cdar actions))
- ((and event (display-popup-menus-p))
- (wcheck--choose-action-popup actions event))
- (t (wcheck--choose-action-minibuffer
actions)))))
-
- (cond ((and (stringp choice)
- (markerp start)
- (markerp end))
- (with-current-buffer (marker-buffer start)
- (if buffer-read-only
- (signal 'wcheck--action-error "Buffer is read-only")
- (delete-region start end)
- (goto-char start)
- (insert choice)
- (setq return-value choice))))
- ((functionp choice)
- (funcall choice marked-text)
- (setq return-value choice)))
-
- (if (markerp start) (set-marker start nil))
- (if (markerp end) (set-marker end nil))))
- return-value)
-
- (wcheck--action-program-error
- (message "Language \"%s\": action program is not configured"
- (cdr error-data)))
-
- (wcheck--parser-function-not-configured-error
- (message "Language \"%s\": parser function is not configured"
- (cdr error-data)))
-
- (wcheck--error
- (message "%s" (cdr error-data)))))
-
-
-(defun wcheck--get-actions (marked-text)
- "Get actions from external program or a function.
-
-MARKED-TEXT must be a vector such as the one returned by
-`wcheck-marked-text-at' function."
-
- (wcheck--with-language-data
- (language (aref marked-text 4))
- ((program action-program)
- (args action-args)
- (parser action-parser)
- (case-fold-search case-fold)
- syntax)
-
- (with-syntax-table (eval syntax)
- (cond ((not (wcheck--action-program-configured-p language))
- (signal 'wcheck--action-program-error language))
-
- ((and (stringp program)
- (not parser))
- (signal 'wcheck--parser-function-not-configured-error language))
-
- ((stringp program)
- (with-temp-buffer
- (insert (aref marked-text 0))
- (apply #'call-process-region (point-min) (point-max)
- program t t nil args)
- (goto-char (point-min))
- (wcheck--clean-actions
- (save-match-data
- (condition-case nil (funcall parser marked-text)
- (error (signal 'wcheck--funcall-error
- (concat "Action parser function "
- "signaled an error"))))))))
-
- ((functionp program)
- (wcheck--clean-actions
- (save-match-data
- (condition-case nil (funcall program marked-text)
- (error (signal 'wcheck--funcall-error
- (concat "Action function signaled "
- "an error")))))))))))
-
-
-(defun wcheck--clean-actions (actions)
- (when (listp actions)
- (delete nil (mapcar (lambda (item)
- (cond ((stringp item)
- (cons (wcheck--clean-string item)
- item))
- ((and (consp item)
- (stringp (car item))
- (or (functionp (cdr item))
- (stringp (cdr item))))
- (cons (wcheck--clean-string (car item))
- (cdr item)))))
- actions))))
-
-
-(defun wcheck--clean-string (string)
- (if (equal string "")
- "[Empty string]"
- (setq string (replace-regexp-in-string "[^[:print:]]+" "" string))
- (if (not (string-match "[^[:space:]]" string))
- "[Space or control chars]"
- (replace-regexp-in-string "\\(?:\\` +\\| +\\'\\)" "" string))))
-
-
-(defun wcheck--choose-action-popup (actions event)
- "Create a pop-up menu to choose an action.
-ACTIONS is a list of strings. EVENT is the mouse event that
-originated this sequence of function calls. Return user's
-choice (a string) or nil."
- (let ((menu (list "Choose"
- (cons "" (if actions
- (mapcar (lambda (item)
- (cons (wcheck--clean-string
- (car item))
- (cdr item)))
- actions)
- (list "[No actions]"))))))
- (x-popup-menu event menu)))
-
-
-(defun wcheck--read-key (prompt)
- (if (fboundp 'read-key)
- (read-key prompt)
- (read-char prompt)))
-
-
-(defun wcheck--choose-action-minibuffer (actions)
- "Create a text menu to choose a substitute action.
-ACTIONS is a list of strings. Return user's choice (a string)
-or nil."
- (if actions
- (let ((chars (append (number-sequence ?1 ?9) (list ?0)
- (number-sequence ?a ?z)))
- alist)
-
- (with-temp-buffer
- (setq mode-line-format (list "--- Choose %-")
- cursor-type nil
- truncate-lines t)
-
- (let (sug string)
- (while (and actions chars)
- (setq sug (car actions)
- actions (cdr actions)
- string (concat (propertize (format "%c)" (car chars))
- 'face 'bold)
- " " (wcheck--clean-string (car sug)) " ")
- alist (cons (cons (car chars) (cdr sug)) alist)
- chars (cdr chars))
- (insert string)
- (when (and actions chars
- (> (+ (- (point) (line-beginning-position))
- (length (concat "x) " (caar actions))))
- (window-width)))
- (delete-char -2)
- (newline 1))))
-
- (delete-char -2)
- (goto-char (point-min))
- (setq buffer-read-only t)
-
- (let* ((window-min-height 2)
- (split-window-keep-point t)
- (window (split-window-vertically
- (- 0 (min (count-lines (point-min) (point-max))
- (- (window-body-height) 2))
- 1)))
- (prompt
- (apply #'propertize
- (let ((last (caar alist)))
- (format "Number %s(%s):"
- (if (memq last (number-sequence ?a ?z))
- "or letter "
- "")
- (cond ((= last ?1) "1")
- ((memq last (number-sequence ?2 ?9))
- (format "1-%c" last))
- ((= last ?0) "1-9,0")
- ((= last ?a) "1-9,0,a")
- ((memq last (number-sequence ?b ?z))
- (format "1-9,0,a-%c" last))
- (t ""))))
- minibuffer-prompt-properties)))
- (set-window-buffer window (current-buffer))
- (set-window-dedicated-p window t)
- ;; Return the choice or nil.
- (cond ((cdr (assq (wcheck--read-key prompt) alist)))
- (t (message "Abort") nil)))))
- (message "No actions")
- nil))
-
-
-(defun wcheck-parser-lines (&rest _ignored)
- "Parser for newline-separated output.
-Return current buffer's lines as a list of strings."
- (delete-dups (split-string (buffer-substring-no-properties
- (point-min) (point-max))
- "\n+" t)))
-
-
-(defun wcheck-parser-whitespace (&rest _ignored)
- "Parser for whitespace-separated output.
-Split current buffer's content to whitespace-separated tokens and
-return them as a list of strings."
- (delete-dups (split-string (buffer-substring-no-properties
- (point-min) (point-max))
- "[ \f\t\n\r\v]+" t)))
-
-
-(defun wcheck-parser-ispell-suggestions (&rest _ignored)
- "Parser for Ispell-compatible programs' spelling suggestions."
- (let ((search-spaces-regexp nil))
- (when (re-search-forward "^& [^ ]+ \\([0-9]+\\) [0-9]+: \\(.+\\)$" nil t)
- (let ((count (string-to-number (match-string-no-properties 1)))
- (words (split-string (match-string-no-properties 2) ", " t)))
- (delete-dups (nbutlast words (- (length words) count)))))))
-
-
-;;; Face information functions
-
-
-(defun wcheck--collect-faces (beg end)
- "Return a list of faces between positions BEG and END."
- (let ((pos beg)
- face faces)
- (while (< pos end)
- (setq face (get-text-property pos 'face)
- pos (1+ pos))
- (if (and face (listp face))
- (setq faces (append face faces))
- (push face faces)))
- (delete-dups faces)))
-
-
-(defun wcheck--major-mode-face-settings (language mode)
- "Return read/skip face settings for MODE."
- (let ((data (wcheck-query-language-data language 'read-or-skip-faces))
- conf)
- (catch 'answer
- (while data
- (setq conf (pop data))
- (when (or (eq nil (car conf))
- (eq mode (car conf))
- (and (listp (car conf))
- (memq mode (car conf))))
- (throw 'answer conf))))))
-
-
-(defun wcheck--face-found-p (user-faces buffer-faces)
- "Return t if a symbol in USER-FACES is found from BUFFER-FACES.
-Both arguments are lists."
- (catch 'found
- (dolist (face user-faces)
- (when (member face buffer-faces)
- (throw 'found t)))))
-
-
-(defun wcheck--generate-face-predicate (language mode)
- "Generate a face predicate function for scanning buffer.
-Return a predicate function that is used to decide whether
-`wcheck-mode' should read or paint text at the current point
-position with LANGUAGE and MODE. The called predicate function
-will return a boolean."
- (let* ((face-settings (wcheck--major-mode-face-settings
- language mode))
- (mode (nth 1 face-settings))
- (faces (nthcdr 2 face-settings)))
- (cond ((not font-lock-mode)
- (lambda () t))
- ((eq mode 'read)
- (lambda ()
- (wcheck--face-found-p
- faces (wcheck--collect-faces
- (match-beginning 1) (match-end 1)))))
- ((eq mode 'skip)
- (lambda ()
- (not (wcheck--face-found-p
- faces (wcheck--collect-faces
- (match-beginning 1) (match-end 1))))))
- (t (lambda () t)))))
-
-
-;;; Miscellaneous low-level functions
-
-
-(defun wcheck--language-data-valid-p (key value)
- (cond ((and (eq key 'syntax)
- (syntax-table-p (and (boundp value) (eval value)))))
- ((and (eq key 'face)
- (facep value)))
- ((and (memq key '(regexp-start regexp-body regexp-end regexp-discard))
- (stringp value)))
- ((and (memq key '(program action-program))
- (or (stringp value)
- (functionp value)
- (and value (symbolp value)
- (error "Invalid %s value: %S" key value)))))
- ((and (eq key 'args)
- (wcheck--list-of-strings-p value)))
- ((and (eq key 'action-args)
- (wcheck--list-of-strings-p value)))
- ((and (memq key '(parser action-parser))
- (or (functionp value)
- (and value
- (error "%s not a function: %S" key value)))))
- ((memq key '(connection case-fold action-autoselect)))
- ((and (eq key 'read-or-skip-faces)
- (wcheck--list-of-lists-p value)))))
-
-
-(defun wcheck-query-language-data (language key)
- "Query `wcheck-mode' language data.
-
-Return LANGUAGE's value for KEY. Valid keys (symbols) are
-described in the documentation of user variable
-`wcheck-language-data'. If that variable does not define
-a (valid) value for the KEY then query the value from
-`wcheck-language-data-defaults' or use internal defaults."
-
- (when (wcheck--language-exists-p language)
- (let* ((data
- (and (wcheck--list-of-lists-p wcheck-language-data)
- (assq key (cdr (assoc language wcheck-language-data)))))
- (default
- (and (wcheck--list-of-lists-p wcheck-language-data-defaults)
- (assq key wcheck-language-data-defaults)))
- (hard-coded
- (and (wcheck--list-of-lists-p
- wcheck--language-data-defaults-hard-coded)
- (assq key wcheck--language-data-defaults-hard-coded)))
- (conf
- (list (when (wcheck--language-data-valid-p key (cdr data))
- data)
- (when (wcheck--language-data-valid-p key (cdr default))
- default)
- (when (wcheck--language-data-valid-p key (cdr hard-coded))
- hard-coded))))
-
- (if (eq key 'read-or-skip-faces)
- (apply #'append (mapcar #'cdr conf))
- (cdr (assq key conf))))))
-
-
-(defun wcheck--language-exists-p (language)
- "Return t if LANGUAGE exists in `wcheck-language-data'."
- (and (wcheck--list-of-lists-p wcheck-language-data)
- (member language (mapcar #'car wcheck-language-data))
- (stringp language)
- (> (length language) 0)
- t))
-
-
-(defun wcheck--program-executable-p (program)
- "Return non-nil if PROGRAM is executable regular file."
- (when (stringp program)
- (let ((f (executable-find program)))
- (and f
- (file-regular-p f)
- (file-executable-p f)))))
-
-
-(defun wcheck--program-configured-p (language)
- (let ((program (wcheck-query-language-data language 'program)))
- (or (wcheck--program-executable-p program)
- (functionp program))))
-
-
-(defun wcheck--action-program-configured-p (language)
- (let ((program (wcheck-query-language-data language 'action-program)))
- (or (wcheck--program-executable-p program)
- (functionp program))))
-
-
-(defun wcheck--list-of-strings-p (object)
- (and (listp object)
- (not (memq nil (mapcar #'stringp object)))))
-
-
-(defun wcheck--list-of-lists-p (object)
- (and (listp object)
- (not (memq nil (mapcar #'listp object)))))
-
-
-(defun wcheck--process-running-p (process)
- (eq 'run (process-status process)))
-
-
-(defun wcheck--current-idle-time-seconds ()
- "Return current idle time in seconds.
-The returned value is a floating point number."
- (let* ((idle (or (current-idle-time)
- '(0 0 0)))
- (high (nth 0 idle))
- (low (nth 1 idle))
- (micros (nth 2 idle)))
- (+ (* high 65536)
- low
- (/ micros 1000000.0))))
-
-
-(defun wcheck--combine-overlapping-areas (alist)
- "Combine overlapping items in ALIST.
-ALIST is a list of (A . B) items in which A and B are integers.
-Each item denote a buffer position range from A to B. This
-function returns a new list which has items in increasing order
-according to A's and all overlapping A B ranges are combined."
- (let ((alist (sort (copy-sequence alist)
- (lambda (a b)
- (< (car a) (car b)))))
- final previous)
- (while alist
- (while (not (equal previous alist))
- (setq previous alist
- alist (append (wcheck--combine-two (car previous) (cadr
previous))
- (nthcdr 2 previous))))
- (setq final (cons (car alist) final)
- alist (cdr alist)
- previous nil))
- (nreverse final)))
-
-
-(defun wcheck--combine-two (a b)
- (let ((a1 (car a))
- (a2 (cdr a))
- (b1 (car b))
- (b2 (cdr b)))
- (cond ((and a b)
- (if (>= (1+ a2) b1)
- (list (cons a1 (if (> b2 a2) b2 a2)))
- (list a b)))
- ((not a) (list b))
- (t (append (list a) b)))))
-
-
-;;; Overlays
-
-
-(defun wcheck--make-overlay (buffer face mouse-face help-echo keymap beg end)
- "Create an overlay to mark text.
-Create an overlay in BUFFER from range BEG to END. FACE,
-MOUSE-FACE, HELP-ECHO and KEYMAP are overlay's properties."
- (let ((overlay (make-overlay beg end buffer)))
- (dolist (prop `((wcheck-mode . t)
- (face . ,face)
- (mouse-face . ,mouse-face)
- (modification-hooks wcheck--remove-changed-overlay)
- (insert-in-front-hooks wcheck--remove-changed-overlay)
- (insert-behind-hooks wcheck--remove-changed-overlay)
- (evaporate . t)
- (keymap . ,keymap)
- (help-echo . ,help-echo)))
- (overlay-put overlay (car prop) (cdr prop)))))
-
-
-(defun wcheck--remove-overlays (&optional beg end)
- "Remove `wcheck-mode' overlays from current buffer.
-If optional arguments BEG and END exist remove overlays from
-range BEG to END. Otherwise remove all overlays."
- (remove-overlays beg end 'wcheck-mode t))
-
-
-(defun wcheck--remove-changed-overlay (overlay after _beg _end &optional _len)
- "Hook for removing overlay which is being edited."
- (unless after
- (delete-overlay overlay)))
-
-
-(defun wcheck--mouse-click-overlay (event)
- "Overlay mouse-click event.
-Send the mouse pointer position and mouse event to the
-`wcheck-actions' function."
- (interactive "e")
- (wcheck-actions (posn-point (event-end event)) event))
-
-
-;;; Buffer data access functions
-
-
-(defconst wcheck--buffer-data-keys
- '(:buffer :process :language :read-req :paint-req :jump-req :areas :strings))
-
-
-(defun wcheck--buffer-data-key-index (key)
- "Return the index of KEY in buffer data object."
- (let ((index 0))
- (catch 'answer
- (dolist (data-key wcheck--buffer-data-keys nil)
- (if (eq key data-key)
- (throw 'answer index)
- (setq index (1+ index)))))))
-
-
-(defun wcheck--buffer-data-create (buffer)
- "Create data instance for BUFFER.
-But only if it doesn't exist already."
- (unless (wcheck--buffer-data-get :buffer buffer)
- (let ((data (make-vector (length wcheck--buffer-data-keys) nil)))
- (aset data (wcheck--buffer-data-key-index :buffer) buffer)
- (push data wcheck--buffer-data))))
-
-
-(defun wcheck--buffer-data-delete (buffer)
- "Delete all data associated to BUFFER."
- (let ((index (wcheck--buffer-data-key-index :buffer)))
- (setq wcheck--buffer-data
- (delq nil (mapcar (lambda (item)
- (unless (eq buffer (aref item index))
- item))
- wcheck--buffer-data)))))
-
-
-(defun wcheck--buffer-data-get (key value &optional target-key)
- "Query the first matching KEY VALUE pair and return TARGET-KEY.
-If optional TARGET-KEY is not given return all data associated
-with the matching KEY VALUE."
- (catch 'answer
- (let ((index (wcheck--buffer-data-key-index key)))
- (dolist (item wcheck--buffer-data)
- (when (equal value (aref item index))
- (throw 'answer (if target-key
- (aref item (wcheck--buffer-data-key-index
- target-key))
- item)))))))
-
-
-(defun wcheck--buffer-data-get-all (&optional key)
- "Return every buffer's value for KEY.
-If KEY is nil return all buffer's all data."
- (if key
- (let ((index (wcheck--buffer-data-key-index key)))
- (mapcar (lambda (item)
- (aref item index))
- wcheck--buffer-data))
- wcheck--buffer-data))
-
-
-(defun wcheck--buffer-data-set (buffer key value)
- "Set KEY's VALUE for BUFFER."
- (let ((item (wcheck--buffer-data-get :buffer buffer)))
- (when item
- (aset item (wcheck--buffer-data-key-index key) value))))
-
-
-(defun wcheck--jump-req-create (window start bound)
- (when (and (number-or-marker-p start)
- (number-or-marker-p bound)
- (windowp window))
- (vector window start bound)))
-
-
-(defun wcheck--jump-req-window (jump-req)
- (aref jump-req 0))
-(defun wcheck--jump-req-start (jump-req)
- (aref jump-req 1))
-(defun wcheck--jump-req-bound (jump-req)
- (aref jump-req 2))
-
-
-(provide 'wcheck-mode)
-
-;;; wcheck-mode.el ends here
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [elpa] master b0e75df: Make wcheck-mode an externals/wcheck-mode package,
Teemu Likonen <=