unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#19338: [PATCH 0/3] Implement an ElDoc function which describes char at point
@ 2014-12-10 17:24 Michal Nazarewicz
  2014-12-10 17:49 ` bug#19338: [PATCH 1/3] eldoc: use default eldoc function if local one gives no results Michal Nazarewicz
  0 siblings, 1 reply; 16+ messages in thread
From: Michal Nazarewicz @ 2014-12-10 17:24 UTC (permalink / raw)
  To: 19338

From: Michal Nazarewicz <mina86@mina86.com>

`describe-char-eldoc' displays information about character at point,
and can be used as a default value of `eldoc-documentation-function'.
It is useful when, for example, one needs to distinguish various
spaces (e.g. ] [, ] [, ] [, etc.) while using mono-spaced font.

Michal Nazarewicz (3):
  eldoc: use default eldoc function if local one gives no results
  descr-text: add `describe-char-eldoc' describing character at point
  eldoc: convert `eldoc-documentation-function' into a defcustom

 etc/NEWS                          | 10 +++-
 lisp/descr-text.el                | 96 +++++++++++++++++++++++++++++++++++++++
 lisp/emacs-lisp/eldoc.el          | 20 ++++++--
 test/automated/descr-text-test.el | 94 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 214 insertions(+), 6 deletions(-)
 create mode 100644 test/automated/descr-text-test.el

-- 
2.2.0.rc0.207.ga3a616c






^ permalink raw reply	[flat|nested] 16+ messages in thread

* bug#19338: [PATCH 1/3] eldoc: use default eldoc function if local one gives no results
  2014-12-10 17:24 bug#19338: [PATCH 0/3] Implement an ElDoc function which describes char at point Michal Nazarewicz
@ 2014-12-10 17:49 ` Michal Nazarewicz
  2014-12-10 17:49   ` bug#19338: [PATCH 2/3] descr-text: add `describe-char-eldoc' describing character at point Michal Nazarewicz
                     ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Michal Nazarewicz @ 2014-12-10 17:49 UTC (permalink / raw)
  To: 19338

From: Michal Nazarewicz <mina86@mina86.com>

* lisp/emacs-lisp/eldoc.el (eldoc-print-current-symbol-info): If
local `eldoc-documentation-function' returns no docstring and the
variable has a non-nil default value, try it as well.  This allows
setting up a global documentation function which will still be
used if given major mode has its own.
---
 etc/NEWS                 | 6 ++++--
 lisp/emacs-lisp/eldoc.el | 8 +++++++-
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 407df82..50338cf 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -199,8 +199,10 @@ typing RET.
 result of the calculation into the current buffer.
 
 ** ElDoc
-*** New minor mode global-eldoc-mode
-*** eldoc-documentation-function now defaults to nil
+*** New minor mode `global-eldoc-mode'
+*** `eldoc-documentation-function' now defaults to nil
+*** Default value of `eldoc-documentation-function now' is consulted if
+local function does not return any documentation.
 
 ** eww
 
diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el
index 6dddf5b..06ee164 100644
--- a/lisp/emacs-lisp/eldoc.el
+++ b/lisp/emacs-lisp/eldoc.el
@@ -345,7 +345,13 @@ This variable is expected to be set buffer-locally by modes that support ElDoc."
              (when eldoc-last-message
                (eldoc-message nil)
                nil))
-	 (eldoc-message (funcall eldoc-documentation-function)))))
+         (eldoc-message
+          (or (funcall eldoc-documentation-function)
+              ;; If local documentation function did not return anything, try
+              ;; global one.
+              (when (local-variable-p 'eldoc-documentation-function)
+                (let ((func (default-value 'eldoc-documentation-function)))
+                  (when func (funcall func)))))))))
 
 \f
 ;; When point is in a sexp, the function args are not reprinted in the echo
-- 
2.2.0.rc0.207.ga3a616c






^ permalink raw reply related	[flat|nested] 16+ messages in thread

* bug#19338: [PATCH 2/3] descr-text: add `describe-char-eldoc' describing character at point
  2014-12-10 17:49 ` bug#19338: [PATCH 1/3] eldoc: use default eldoc function if local one gives no results Michal Nazarewicz
@ 2014-12-10 17:49   ` Michal Nazarewicz
  2014-12-10 17:49   ` bug#19338: [PATCH 3/3] eldoc: convert `eldoc-documentation-function' into a defcustom Michal Nazarewicz
  2014-12-10 20:05   ` bug#19338: [PATCH 1/3] eldoc: use default eldoc function if local one gives no results Stefan Monnier
  2 siblings, 0 replies; 16+ messages in thread
From: Michal Nazarewicz @ 2014-12-10 17:49 UTC (permalink / raw)
  To: 19338

From: Michal Nazarewicz <mina86@mina86.com>

* lisp/descr-text.el (describe-char-eldoc): New function returning
basic Unicode codepoint information (e.g. name) about character
at point.  It is meant to be used as a default value of the
`eldoc-documentation-function' variable.
(describe-char-eldoc--format, describe-char-eldoc--truncate):
New helper functions for `describe-char-eldoc' function.

* tests/automated/descr-text-test.el: New file with tests for
`describe-char-eldoc--truncate', `describe-char-eldoc--format',
and `describe-char-eldoc'.
---
 etc/NEWS                          |  4 ++
 lisp/descr-text.el                | 96 +++++++++++++++++++++++++++++++++++++++
 test/automated/descr-text-test.el | 94 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 194 insertions(+)
 create mode 100644 test/automated/descr-text-test.el

diff --git a/etc/NEWS b/etc/NEWS
index 50338cf..77a2f9b 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -203,6 +203,10 @@ result of the calculation into the current buffer.
 *** `eldoc-documentation-function' now defaults to nil
 *** Default value of `eldoc-documentation-function now' is consulted if
 local function does not return any documentation.
+*** `describe-char-eldoc' displays information about character at point,
+and can be used as a default value of `eldoc-documentation-function'.  It is
+useful when, for example, one needs to distinguish various spaces (e.g. ] [,
+] [, ] [, etc.) while using mono-spaced font.
 
 ** eww
 
diff --git a/lisp/descr-text.el b/lisp/descr-text.el
index 1dc43e9..d435fe6 100644
--- a/lisp/descr-text.el
+++ b/lisp/descr-text.el
@@ -825,6 +825,102 @@ relevant to POS."
 
 (define-obsolete-function-alias 'describe-char-after 'describe-char "22.1")
 
+;;; Describe-Char-ElDoc
+
+(defun describe-char-eldoc--truncate (name width)
+  "Truncate NAME at white spaces such that it is no longer than WIDTH.
+
+If NAME consists of white space only, return an empty string.
+
+Otherwise, if NAME consists of a single word (where word is defined as sequence
+of non-white space characters), return that word even if it's longer than WIDTH.
+
+Otherwise, if first word in NAME is longer or equal WIDTH, return that word with
+ellipsis character (\"…\") appended; this results in a string longer than WIDTH.
+
+Otherwise, take as many words from NAME as possible, separating them with
+a single space character, while not exceeding WIDTH characters length limit.  If
+not all words fit, append ellipsis character (\"…\") at the end; the ellipsis is
+counted towards WIDTH."
+  (let ((words (split-string name)))
+    (if words
+        (let ((last words))
+          (setq width (- width (length (car words))))
+          (while (and (cdr last)
+                      (<= (+ (length (cadr last)) (if (cddr last) 2 1)) width))
+            (setq last (cdr last))
+            (setq width (- width (length (car last)) 1)))
+          (let ((ellipsis (and (cdr last) "…")))
+            (setcdr last nil)
+            (concat (mapconcat 'identity words " ") ellipsis)))
+      "")))
+
+(defun describe-char-eldoc--format (ch &optional width)
+  "Format a description for character CH which is no more than WIDTH characters.
+
+Full description message has a \"U+<hex>: <name> (<gc>: <general category>)\"
+format where:
+- <hex> is a hexadecimal codepoint of the character (zero-padded to at least
+  four digits),
+- <name> is name of the character.
+- <gc> is a two-letter abbreviation of the general-category of the character,
+  and
+- <general category> is full name of the general-category of the character.
+
+If WIDTH is non-nil some elements of the description may be omitted to
+accommodate the length restriction.  Under certain condition, the function may
+return string longer than WIDTH, see `describe-char-eldoc--truncate'."
+  (let ((name (get-char-code-property ch 'name)))
+    (when name
+      (let* ((code (propertize (format "U+%04X" ch)
+                               'face 'font-lock-constant-face))
+             (gc (get-char-code-property ch 'general-category))
+             (gc-desc (char-code-property-description 'general-category gc)))
+
+        (unless (or (not width) (<= (length name) width))
+          (setq name (describe-char-eldoc--truncate name width)))
+        (setq name (concat (substring name 0 1) (downcase (substring name 1))))
+        (setq name (propertize name 'face 'font-lock-variable-name-face))
+
+        (setq gc (propertize (symbol-name gc) 'face 'font-lock-comment-face))
+        (when gc-desc
+          (setq gc-desc (propertize gc-desc 'face 'font-lock-comment-face)))
+
+        (let ((lcode    (length code))
+              (lname    (length name))
+              (lgc      (length gc))
+              (lgc-desc (and gc-desc (length gc-desc))))
+          (cond
+           ((and gc-desc
+                 (or (not width) (<= (+ lcode lname lgc lgc-desc 7) width)))
+            (concat code ": " name " (" gc ": " gc-desc ")"))
+           ((and gc-desc (<= (+ lcode lname lgc-desc 5) width))
+            (concat code ": " name " (" gc-desc ")"))
+           ((or (not width) (<= (+ lcode lname lgc 5) width))
+            (concat code ": " name " (" gc ")"))
+           ((<= (+ lname lgc 3) width)
+            (concat name " (" gc ")"))
+           (t name)))))))
+
+;;;###autoload
+(defun describe-char-eldoc ()
+  "Returns a description of character at point for use by ElDoc mode.
+
+If character at point is a printable ASCII character (i.e. codepoint between 32
+and 127 inclusively), nil is returned.  Otherwise a description formatted by
+`describe-char-eldoc--format' function is returned taking into account value
+of `eldoc-echo-area-use-multiline-p' variable and width of minibuffer window for
+width limit.
+
+This function is meant to be used as a value of `eldoc-documentation-function'
+variable."
+  (let ((ch (following-char)))
+    (when (and (not (zerop ch)) (or (< ch 32) (> ch 127)))
+      (describe-char-eldoc--format
+       ch
+       (unless (eq eldoc-echo-area-use-multiline-p t)
+         (1- (window-width (minibuffer-window))))))))
+
 (provide 'descr-text)
 
 ;;; descr-text.el ends here
diff --git a/test/automated/descr-text-test.el b/test/automated/descr-text-test.el
new file mode 100644
index 0000000..81a4375
--- /dev/null
+++ b/test/automated/descr-text-test.el
@@ -0,0 +1,94 @@
+;;; descr-text-test.el --- ERT tests for descr-text.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2014 Free Software Foundation, Inc.
+
+;; Author:     Michal Nazarewicz <mina86@mina86.com>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package defines regression tests for the descr-text package.
+
+;;; Code:
+
+(require 'ert)
+(require 'descr-text)
+
+
+(ert-deftest descr-text-test-truncate ()
+  "Tests describe-char-eldoc--truncate function."
+  (should (equal ""
+                 (describe-char-eldoc--truncate " \t \n" 100)))
+  (should (equal "foo"
+                 (describe-char-eldoc--truncate "foo" 1)))
+  (should (equal "foo…"
+                 (describe-char-eldoc--truncate "foo wilma fred" 0)))
+  (should (equal "foo…"
+                 (describe-char-eldoc--truncate
+                  "foo wilma fred" (length "foo wilma"))))
+  (should (equal "foo wilma…"
+                 (describe-char-eldoc--truncate
+                  "foo wilma fred" (1+ (length "foo wilma")))))
+  (should (equal "foo wilma…"
+                 (describe-char-eldoc--truncate
+                  "foo wilma fred" (1- (length "foo wilma fred")))))
+  (should (equal "foo wilma fred"
+                 (describe-char-eldoc--truncate
+                  "foo wilma fred" (length "foo wilma fred"))))
+  (should (equal "foo wilma fred"
+                 (describe-char-eldoc--truncate
+                  "  foo\t wilma \nfred\t " (length "foo wilma fred")))))
+
+(ert-deftest descr-text-test-format-desc ()
+  "Tests describe-char-eldoc--format function."
+  (should (equal "U+2026: Horizontal ellipsis (Po: Punctuation, Other)"
+                 (describe-char-eldoc--format ?…)))
+  (should (equal "U+2026: Horizontal ellipsis (Punctuation, Other)"
+                 (describe-char-eldoc--format ?… 51)))
+  (should (equal "U+2026: Horizontal ellipsis (Po)"
+                 (describe-char-eldoc--format ?… 40)))
+  (should (equal "Horizontal ellipsis (Po)"
+                 (describe-char-eldoc--format ?… 30)))
+  (should (equal "Horizontal ellipsis"
+                 (describe-char-eldoc--format ?… 20)))
+  (should (equal "Horizontal…"
+                 (describe-char-eldoc--format ?… 10))))
+
+(ert-deftest descr-text-test-desc ()
+  "Tests describe-char-eldoc function."
+  (with-temp-buffer
+    (insert "a…")
+    (goto-char (point-min))
+    (should (eq ?a (following-char))) ; make sure we are where we think we are
+    ;; Function should return nil for an ASCII character.
+    (should (not (describe-char-eldoc)))
+
+    (goto-char (1+ (point)))
+    (should (eq ?… (following-char)))
+    (let ((eldoc-echo-area-use-multiline-p t))
+      ;; Function should return description of an Unicode character.
+      (should (equal "U+2026: Horizontal ellipsis (Po: Punctuation, Other)"
+                     (describe-char-eldoc))))
+
+    (goto-char (point-max))
+    ;; At the end of the buffer, function should return nil and not blow up.
+    (should (not (describe-char-eldoc)))))
+
+
+(provide 'descr-text-test)
+
+;;; descr-text-test.el ends here
-- 
2.2.0.rc0.207.ga3a616c






^ permalink raw reply related	[flat|nested] 16+ messages in thread

* bug#19338: [PATCH 3/3] eldoc: convert `eldoc-documentation-function' into a defcustom
  2014-12-10 17:49 ` bug#19338: [PATCH 1/3] eldoc: use default eldoc function if local one gives no results Michal Nazarewicz
  2014-12-10 17:49   ` bug#19338: [PATCH 2/3] descr-text: add `describe-char-eldoc' describing character at point Michal Nazarewicz
@ 2014-12-10 17:49   ` Michal Nazarewicz
  2014-12-10 20:08     ` Stefan Monnier
  2014-12-10 20:05   ` bug#19338: [PATCH 1/3] eldoc: use default eldoc function if local one gives no results Stefan Monnier
  2 siblings, 1 reply; 16+ messages in thread
From: Michal Nazarewicz @ 2014-12-10 17:49 UTC (permalink / raw)
  To: 19338

From: Michal Nazarewicz <mina86@mina86.com>

* lisp/emacs-lisp/eldoc.el (eldoc-documentation-function): Change
from defvar to defcustom with `describe-char-eldoc' function
as one of the suggested values.
---
 lisp/emacs-lisp/eldoc.el | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el
index 06ee164..aeddf90 100644
--- a/lisp/emacs-lisp/eldoc.el
+++ b/lisp/emacs-lisp/eldoc.el
@@ -321,8 +321,8 @@ Otherwise work like `message'."
 
 \f
 ;;;###autoload
-(defvar eldoc-documentation-function nil
-  "Function to call to return doc string.
+(defcustom eldoc-documentation-function nil
+  "Function to call to return doc string for ElDoc mode.
 The function of no args should return a one-line string for displaying
 doc about a function etc. appropriate to the context around point.
 It should return nil if there's no doc appropriate for the context.
@@ -334,7 +334,13 @@ the variables `eldoc-argument-case' and `eldoc-echo-area-use-multiline-p',
 and the face `eldoc-highlight-function-argument', if they are to have any
 effect.
 
-This variable is expected to be set buffer-locally by modes that support ElDoc.")
+Major modes can set this variable buffer-locally to overwrite the global
+default, but if local documentation function returns no doc string, the global
+one will be tried as well."
+  :type '(radio (function-item describe-char-eldoc)
+                function
+                (const :tag "No documentation function" nil))
+  :group 'eldoc)
 
 (defun eldoc-print-current-symbol-info ()
   ;; This is run from post-command-hook or some idle timer thing,
-- 
2.2.0.rc0.207.ga3a616c






^ permalink raw reply related	[flat|nested] 16+ messages in thread

* bug#19338: [PATCH 1/3] eldoc: use default eldoc function if local one gives no results
  2014-12-10 17:49 ` bug#19338: [PATCH 1/3] eldoc: use default eldoc function if local one gives no results Michal Nazarewicz
  2014-12-10 17:49   ` bug#19338: [PATCH 2/3] descr-text: add `describe-char-eldoc' describing character at point Michal Nazarewicz
  2014-12-10 17:49   ` bug#19338: [PATCH 3/3] eldoc: convert `eldoc-documentation-function' into a defcustom Michal Nazarewicz
@ 2014-12-10 20:05   ` Stefan Monnier
  2014-12-10 21:46     ` Michal Nazarewicz
  2 siblings, 1 reply; 16+ messages in thread
From: Stefan Monnier @ 2014-12-10 20:05 UTC (permalink / raw)
  To: Michal Nazarewicz; +Cc: 19338

> -	 (eldoc-message (funcall eldoc-documentation-function)))))
> +         (eldoc-message
> +          (or (funcall eldoc-documentation-function)
> +              ;; If local documentation function did not return anything, try
> +              ;; global one.
> +              (when (local-variable-p 'eldoc-documentation-function)
> +                (let ((func (default-value 'eldoc-documentation-function)))
> +                  (when func (funcall func)))))))))

We don't need that: if the major-mode wants that to happen, it can do
that with an appropriate call to add-function, which will take care of
delegating to the global value if/when applicable.

This works very much like the add-hook's `local' argument.


        Stefan





^ permalink raw reply	[flat|nested] 16+ messages in thread

* bug#19338: [PATCH 3/3] eldoc: convert `eldoc-documentation-function' into a defcustom
  2014-12-10 17:49   ` bug#19338: [PATCH 3/3] eldoc: convert `eldoc-documentation-function' into a defcustom Michal Nazarewicz
@ 2014-12-10 20:08     ` Stefan Monnier
  0 siblings, 0 replies; 16+ messages in thread
From: Stefan Monnier @ 2014-12-10 20:08 UTC (permalink / raw)
  To: Michal Nazarewicz; +Cc: 19338

> -(defvar eldoc-documentation-function nil
> -  "Function to call to return doc string.
> +(defcustom eldoc-documentation-function nil
> +  "Function to call to return doc string for ElDoc mode.

This variable will be modified programmatically by various Elisp
packages, which interacts poorly with Custom.

If you want your describe-char-eldoc thingy to be Custom-izable, you'd
probably be better served with a describe-char-eldoc-mode minor-mode,
which you can then enable via Custom.


        Stefan





^ permalink raw reply	[flat|nested] 16+ messages in thread

* bug#19338: [PATCH 1/3] eldoc: use default eldoc function if local one gives no results
  2014-12-10 20:05   ` bug#19338: [PATCH 1/3] eldoc: use default eldoc function if local one gives no results Stefan Monnier
@ 2014-12-10 21:46     ` Michal Nazarewicz
  2014-12-11  2:38       ` Stefan Monnier
  0 siblings, 1 reply; 16+ messages in thread
From: Michal Nazarewicz @ 2014-12-10 21:46 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 19338

On Wed, Dec 10 2014, Stefan Monnier <monnier@IRO.UMontreal.CA> wrote:
>> -	 (eldoc-message (funcall eldoc-documentation-function)))))
>> +         (eldoc-message
>> +          (or (funcall eldoc-documentation-function)
>> +              ;; If local documentation function did not return anything, try
>> +              ;; global one.
>> +              (when (local-variable-p 'eldoc-documentation-function)
>> +                (let ((func (default-value 'eldoc-documentation-function)))
>> +                  (when func (funcall func)))))))))
>
> We don't need that: if the major-mode wants that to happen, it can do
> that with an appropriate call to add-function, which will take care of
> delegating to the global value if/when applicable.
>
> This works very much like the add-hook's `local' argument.

So the point here is that I don't want major-mode to be aware of what
I might have set the default value of `eldoc-documentation-function' to
(and work even if I change it at any point).

This is also why I made `eldoc-documentation-function' into a defcustom
so user can customise the default value regardless of what major-mode is
doing.

I first tried doing it with `eldoc-mode' but the result didn't seem
clean or working correctly when major mode had its own eldoc function
set.

-- 
Best regards,                                         _     _
.o. | Liege of Serenely Enlightened Majesty of      o' \,=./ `o
..o | Computer Science,  Michał “mina86” Nazarewicz    (o o)
ooo +--<mpn@google.com>--<xmpp:mina86@jabber.org>--ooO--(_)--Ooo--





^ permalink raw reply	[flat|nested] 16+ messages in thread

* bug#19338: [PATCH 1/3] eldoc: use default eldoc function if local one gives no results
  2014-12-10 21:46     ` Michal Nazarewicz
@ 2014-12-11  2:38       ` Stefan Monnier
  2014-12-11 16:02         ` bug#19338: [PATCHv2 1/2] descr-text: add `describe-char-eldoc' describing character at point Michal Nazarewicz
  2014-12-11 16:59         ` bug#19338: [PATCH 1/3] eldoc: use default eldoc function if local one gives no results Stefan Monnier
  0 siblings, 2 replies; 16+ messages in thread
From: Stefan Monnier @ 2014-12-11  2:38 UTC (permalink / raw)
  To: Michal Nazarewicz; +Cc: 19338

> So the point here is that I don't want major-mode to be aware of what
> I might have set the default value of `eldoc-documentation-function' to

The major mode doesn't have to be aware of it.  It should simply always
delegate to the default function (i.e. ideally use :before-until, of
course that requires fixing the default value of
eldoc-documentation-function).

> (and work even if I change it at any point).

Just like the `local' arg of add-hook, add-function correctly handles
later changes to the global value of the variable.


        Stefan





^ permalink raw reply	[flat|nested] 16+ messages in thread

* bug#19338: [PATCHv2 1/2] descr-text: add `describe-char-eldoc' describing character at point
  2014-12-11  2:38       ` Stefan Monnier
@ 2014-12-11 16:02         ` Michal Nazarewicz
  2014-12-11 16:02           ` bug#19338: [PATCHv2 2/2] eldoc: convert `eldoc-documentation-function' into a defcustom Michal Nazarewicz
                             ` (2 more replies)
  2014-12-11 16:59         ` bug#19338: [PATCH 1/3] eldoc: use default eldoc function if local one gives no results Stefan Monnier
  1 sibling, 3 replies; 16+ messages in thread
From: Michal Nazarewicz @ 2014-12-11 16:02 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 19338

From: Michal Nazarewicz <mina86@mina86.com>

* lisp/descr-text.el (describe-char-eldoc): New function returning
basic Unicode codepoint information (e.g. name) about character
at point.  It is meant to be used as a default value of the
`eldoc-documentation-function' variable.
(describe-char-eldoc--format, describe-char-eldoc--truncate):
New helper functions for `describe-char-eldoc' function.

* tests/automated/descr-text-test.el: New file with tests for
`describe-char-eldoc--truncate', `describe-char-eldoc--format',
and `describe-char-eldoc'.
---
 etc/NEWS                          |  8 +++-
 lisp/descr-text.el                | 96 +++++++++++++++++++++++++++++++++++++++
 test/automated/descr-text-test.el | 94 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 196 insertions(+), 2 deletions(-)
 create mode 100644 test/automated/descr-text-test.el

diff --git a/etc/NEWS b/etc/NEWS
index 407df82..61f6dcc 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -199,8 +199,12 @@ typing RET.
 result of the calculation into the current buffer.
 
 ** ElDoc
-*** New minor mode global-eldoc-mode
-*** eldoc-documentation-function now defaults to nil
+*** New minor mode `global-eldoc-mode'
+*** `eldoc-documentation-function' now defaults to `ignore'
+*** `describe-char-eldoc' displays information about character at point,
+and can be used as a default value of `eldoc-documentation-function'.  It is
+useful when, for example, one needs to distinguish various spaces (e.g. ] [,
+] [, ] [, etc.) while using mono-spaced font.
 
 ** eww
 
diff --git a/lisp/descr-text.el b/lisp/descr-text.el
index 1dc43e9..d435fe6 100644
--- a/lisp/descr-text.el
+++ b/lisp/descr-text.el
@@ -825,6 +825,102 @@ relevant to POS."
 
 (define-obsolete-function-alias 'describe-char-after 'describe-char "22.1")
 
+;;; Describe-Char-ElDoc
+
+(defun describe-char-eldoc--truncate (name width)
+  "Truncate NAME at white spaces such that it is no longer than WIDTH.
+
+If NAME consists of white space only, return an empty string.
+
+Otherwise, if NAME consists of a single word (where word is defined as sequence
+of non-white space characters), return that word even if it's longer than WIDTH.
+
+Otherwise, if first word in NAME is longer or equal WIDTH, return that word with
+ellipsis character (\"…\") appended; this results in a string longer than WIDTH.
+
+Otherwise, take as many words from NAME as possible, separating them with
+a single space character, while not exceeding WIDTH characters length limit.  If
+not all words fit, append ellipsis character (\"…\") at the end; the ellipsis is
+counted towards WIDTH."
+  (let ((words (split-string name)))
+    (if words
+        (let ((last words))
+          (setq width (- width (length (car words))))
+          (while (and (cdr last)
+                      (<= (+ (length (cadr last)) (if (cddr last) 2 1)) width))
+            (setq last (cdr last))
+            (setq width (- width (length (car last)) 1)))
+          (let ((ellipsis (and (cdr last) "…")))
+            (setcdr last nil)
+            (concat (mapconcat 'identity words " ") ellipsis)))
+      "")))
+
+(defun describe-char-eldoc--format (ch &optional width)
+  "Format a description for character CH which is no more than WIDTH characters.
+
+Full description message has a \"U+<hex>: <name> (<gc>: <general category>)\"
+format where:
+- <hex> is a hexadecimal codepoint of the character (zero-padded to at least
+  four digits),
+- <name> is name of the character.
+- <gc> is a two-letter abbreviation of the general-category of the character,
+  and
+- <general category> is full name of the general-category of the character.
+
+If WIDTH is non-nil some elements of the description may be omitted to
+accommodate the length restriction.  Under certain condition, the function may
+return string longer than WIDTH, see `describe-char-eldoc--truncate'."
+  (let ((name (get-char-code-property ch 'name)))
+    (when name
+      (let* ((code (propertize (format "U+%04X" ch)
+                               'face 'font-lock-constant-face))
+             (gc (get-char-code-property ch 'general-category))
+             (gc-desc (char-code-property-description 'general-category gc)))
+
+        (unless (or (not width) (<= (length name) width))
+          (setq name (describe-char-eldoc--truncate name width)))
+        (setq name (concat (substring name 0 1) (downcase (substring name 1))))
+        (setq name (propertize name 'face 'font-lock-variable-name-face))
+
+        (setq gc (propertize (symbol-name gc) 'face 'font-lock-comment-face))
+        (when gc-desc
+          (setq gc-desc (propertize gc-desc 'face 'font-lock-comment-face)))
+
+        (let ((lcode    (length code))
+              (lname    (length name))
+              (lgc      (length gc))
+              (lgc-desc (and gc-desc (length gc-desc))))
+          (cond
+           ((and gc-desc
+                 (or (not width) (<= (+ lcode lname lgc lgc-desc 7) width)))
+            (concat code ": " name " (" gc ": " gc-desc ")"))
+           ((and gc-desc (<= (+ lcode lname lgc-desc 5) width))
+            (concat code ": " name " (" gc-desc ")"))
+           ((or (not width) (<= (+ lcode lname lgc 5) width))
+            (concat code ": " name " (" gc ")"))
+           ((<= (+ lname lgc 3) width)
+            (concat name " (" gc ")"))
+           (t name)))))))
+
+;;;###autoload
+(defun describe-char-eldoc ()
+  "Returns a description of character at point for use by ElDoc mode.
+
+If character at point is a printable ASCII character (i.e. codepoint between 32
+and 127 inclusively), nil is returned.  Otherwise a description formatted by
+`describe-char-eldoc--format' function is returned taking into account value
+of `eldoc-echo-area-use-multiline-p' variable and width of minibuffer window for
+width limit.
+
+This function is meant to be used as a value of `eldoc-documentation-function'
+variable."
+  (let ((ch (following-char)))
+    (when (and (not (zerop ch)) (or (< ch 32) (> ch 127)))
+      (describe-char-eldoc--format
+       ch
+       (unless (eq eldoc-echo-area-use-multiline-p t)
+         (1- (window-width (minibuffer-window))))))))
+
 (provide 'descr-text)
 
 ;;; descr-text.el ends here
diff --git a/test/automated/descr-text-test.el b/test/automated/descr-text-test.el
new file mode 100644
index 0000000..81a4375
--- /dev/null
+++ b/test/automated/descr-text-test.el
@@ -0,0 +1,94 @@
+;;; descr-text-test.el --- ERT tests for descr-text.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2014 Free Software Foundation, Inc.
+
+;; Author:     Michal Nazarewicz <mina86@mina86.com>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package defines regression tests for the descr-text package.
+
+;;; Code:
+
+(require 'ert)
+(require 'descr-text)
+
+
+(ert-deftest descr-text-test-truncate ()
+  "Tests describe-char-eldoc--truncate function."
+  (should (equal ""
+                 (describe-char-eldoc--truncate " \t \n" 100)))
+  (should (equal "foo"
+                 (describe-char-eldoc--truncate "foo" 1)))
+  (should (equal "foo…"
+                 (describe-char-eldoc--truncate "foo wilma fred" 0)))
+  (should (equal "foo…"
+                 (describe-char-eldoc--truncate
+                  "foo wilma fred" (length "foo wilma"))))
+  (should (equal "foo wilma…"
+                 (describe-char-eldoc--truncate
+                  "foo wilma fred" (1+ (length "foo wilma")))))
+  (should (equal "foo wilma…"
+                 (describe-char-eldoc--truncate
+                  "foo wilma fred" (1- (length "foo wilma fred")))))
+  (should (equal "foo wilma fred"
+                 (describe-char-eldoc--truncate
+                  "foo wilma fred" (length "foo wilma fred"))))
+  (should (equal "foo wilma fred"
+                 (describe-char-eldoc--truncate
+                  "  foo\t wilma \nfred\t " (length "foo wilma fred")))))
+
+(ert-deftest descr-text-test-format-desc ()
+  "Tests describe-char-eldoc--format function."
+  (should (equal "U+2026: Horizontal ellipsis (Po: Punctuation, Other)"
+                 (describe-char-eldoc--format ?…)))
+  (should (equal "U+2026: Horizontal ellipsis (Punctuation, Other)"
+                 (describe-char-eldoc--format ?… 51)))
+  (should (equal "U+2026: Horizontal ellipsis (Po)"
+                 (describe-char-eldoc--format ?… 40)))
+  (should (equal "Horizontal ellipsis (Po)"
+                 (describe-char-eldoc--format ?… 30)))
+  (should (equal "Horizontal ellipsis"
+                 (describe-char-eldoc--format ?… 20)))
+  (should (equal "Horizontal…"
+                 (describe-char-eldoc--format ?… 10))))
+
+(ert-deftest descr-text-test-desc ()
+  "Tests describe-char-eldoc function."
+  (with-temp-buffer
+    (insert "a…")
+    (goto-char (point-min))
+    (should (eq ?a (following-char))) ; make sure we are where we think we are
+    ;; Function should return nil for an ASCII character.
+    (should (not (describe-char-eldoc)))
+
+    (goto-char (1+ (point)))
+    (should (eq ?… (following-char)))
+    (let ((eldoc-echo-area-use-multiline-p t))
+      ;; Function should return description of an Unicode character.
+      (should (equal "U+2026: Horizontal ellipsis (Po: Punctuation, Other)"
+                     (describe-char-eldoc))))
+
+    (goto-char (point-max))
+    ;; At the end of the buffer, function should return nil and not blow up.
+    (should (not (describe-char-eldoc)))))
+
+
+(provide 'descr-text-test)
+
+;;; descr-text-test.el ends here
-- 
2.2.0.rc0.207.ga3a616c






^ permalink raw reply related	[flat|nested] 16+ messages in thread

* bug#19338: [PATCHv2 2/2] eldoc: convert `eldoc-documentation-function' into a defcustom
  2014-12-11 16:02         ` bug#19338: [PATCHv2 1/2] descr-text: add `describe-char-eldoc' describing character at point Michal Nazarewicz
@ 2014-12-11 16:02           ` Michal Nazarewicz
  2015-01-20 14:08             ` Michal Nazarewicz
  2014-12-11 16:56           ` bug#19338: [PATCHv2 1/2] descr-text: add `describe-char-eldoc' describing character at point Leo Liu
  2014-12-14 19:46           ` Eli Zaretskii
  2 siblings, 1 reply; 16+ messages in thread
From: Michal Nazarewicz @ 2014-12-11 16:02 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 19338

From: Michal Nazarewicz <mina86@mina86.com>

* lisp/emacs-lisp/eldoc.el (eldoc-documentation-function): Change from
defvar to defcustom with `describe-char-eldoc' function as one of the
suggested values.  Describe how major modes should use `add-function' to
alter value of the defcustom.

* lisp/hexl.el (hexl-mode): Set `eldoc-documentation-function' using
`add-function' so the default value is always used.
* lisp/ielm.el (inferior-emacs-lisp-mode): Set
`eldoc-documentation-function' using `add-function' so the default
value is always used.
* lisp/progmodes/cfengine.el (cfengine3-mode): Set
`eldoc-documentation-function' using `add-function' so the default
value is always used.
* lisp/progmodes/elisp-mode (emacs-lisp-mode): Set
`eldoc-documentation-function' using `add-function' so the default
value is always used.
* lisp/progmodes/octave.el (octave-mode): Set
`eldoc-documentation-function' using `add-function' so the default
value is always used.
* lisp/progmodes/python.el (python-mode): Set
`eldoc-documentation-function' using `add-function' so the default
value is always used.
* lisp/simple.el (read--expression): Set `eldoc-documentation-function'
using `add-function' so the default value is always used.
---
 lisp/emacs-lisp/eldoc.el     | 15 ++++++++++++---
 lisp/hexl.el                 |  4 ++--
 lisp/ielm.el                 |  6 +++---
 lisp/progmodes/cfengine.el   |  3 ++-
 lisp/progmodes/elisp-mode.el |  4 ++--
 lisp/progmodes/octave.el     |  3 ++-
 lisp/progmodes/python.el     |  4 ++--
 lisp/simple.el               |  4 ++--
 8 files changed, 27 insertions(+), 16 deletions(-)

diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el
index 2ee3d23..2360954 100644
--- a/lisp/emacs-lisp/eldoc.el
+++ b/lisp/emacs-lisp/eldoc.el
@@ -323,8 +323,8 @@ Otherwise work like `message'."
 
 \f
 ;;;###autoload
-(defvar eldoc-documentation-function #'ignore
-  "Function to call to return doc string.
+(defcustom eldoc-documentation-function #'ignore
+  "Function to call to return doc string for ElDoc mode.
 The function of no args should return a one-line string for displaying
 doc about a function etc. appropriate to the context around point.
 It should return nil if there's no doc appropriate for the context.
@@ -336,7 +336,16 @@ the variables `eldoc-argument-case' and `eldoc-echo-area-use-multiline-p',
 and the face `eldoc-highlight-function-argument', if they are to have any
 effect.
 
-This variable is expected to be set buffer-locally by modes that support ElDoc.")
+Major modes should modify this variable using `add-function', for example:
+  (add-function :before-until (local 'eldoc-documentation-function)
+                #'foo-mode-eldoc-function)
+so that the global documentation function (i.e. the default value of the
+variable) is taken into account if the major mode specific function does not
+return any documentation."
+  :type '(radio (function-item describe-char-eldoc)
+                function
+                (const :tag "No documentation function" #'ignore))
+  :group 'eldoc)
 
 (defun eldoc-print-current-symbol-info ()
   ;; This is run from post-command-hook or some idle timer thing,
diff --git a/lisp/hexl.el b/lisp/hexl.el
index 5c23f49..e1b1f98 100644
--- a/lisp/hexl.el
+++ b/lisp/hexl.el
@@ -394,8 +394,8 @@ You can use \\[hexl-find-file] to visit a file in Hexl mode.
     (add-hook 'change-major-mode-hook 'hexl-maybe-dehexlify-buffer nil t)
 
     ;; Set a callback function for eldoc.
-    (hexl-mode--setq-local 'eldoc-documentation-function
-                           #'hexl-print-current-point-info)
+    (add-function :before-until (local 'eldoc-documentation-function)
+                  #'hexl-print-current-point-info)
     (eldoc-add-command-completions "hexl-")
     (eldoc-remove-command "hexl-save-buffer"
 			  "hexl-current-address")
diff --git a/lisp/ielm.el b/lisp/ielm.el
index 37e66cc..f776f13 100644
--- a/lisp/ielm.el
+++ b/lisp/ielm.el
@@ -380,7 +380,7 @@ nonempty, then flushes the buffer."
                      (*3 ***)
                      (active-process (ielm-process))
                      (old-standard-output standard-output)
-                     new-standard-output 
+                     new-standard-output
                      ielm-temp-buffer)
                 (set-match-data ielm-match-data)
                 (save-excursion
@@ -542,8 +542,8 @@ Customized bindings may be defined in `ielm-map', which currently contains:
   (set (make-local-variable 'completion-at-point-functions)
        '(comint-replace-by-expanded-history
          ielm-complete-filename elisp-completion-at-point))
-  (setq-local eldoc-documentation-function
-              #'elisp-eldoc-documentation-function)
+  (add-function :before-until (local 'eldoc-documentation-function)
+                #'elisp-eldoc-documentation-function)
   (set (make-local-variable 'ielm-prompt-internal) ielm-prompt)
   (set (make-local-variable 'comint-prompt-read-only) ielm-prompt-read-only)
   (setq comint-get-old-input 'ielm-get-old-input)
diff --git a/lisp/progmodes/cfengine.el b/lisp/progmodes/cfengine.el
index 53d5be9..42de44e 100644
--- a/lisp/progmodes/cfengine.el
+++ b/lisp/progmodes/cfengine.el
@@ -1350,7 +1350,8 @@ to the action header."
                  (when buffer-file-name
                    (shell-quote-argument buffer-file-name)))))
 
-  (setq-local eldoc-documentation-function #'cfengine3-documentation-function)
+  (add-function :before-until (local 'eldoc-documentation-function)
+                #'cfengine3-documentation-function)
 
   (add-hook 'completion-at-point-functions
             #'cfengine3-completion-function nil t)
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index ba70f90..3094dec 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -229,8 +229,8 @@ Blank lines separate paragraphs.  Semicolons start comments.
   :group 'lisp
   (lisp-mode-variables nil nil 'elisp)
   (setq imenu-case-fold-search nil)
-  (setq-local eldoc-documentation-function
-              #'elisp-eldoc-documentation-function)
+  (add-function :before-until (local 'eldoc-documentation-function)
+                #'elisp-eldoc-documentation-function)
   (add-hook 'completion-at-point-functions
             #'elisp-completion-at-point nil 'local))
 
diff --git a/lisp/progmodes/octave.el b/lisp/progmodes/octave.el
index 7d96363..90b1e44 100644
--- a/lisp/progmodes/octave.el
+++ b/lisp/progmodes/octave.el
@@ -601,7 +601,8 @@ Key bindings:
   (add-hook 'before-save-hook 'octave-sync-function-file-names nil t)
   (setq-local beginning-of-defun-function 'octave-beginning-of-defun)
   (and octave-font-lock-texinfo-comment (octave-font-lock-texinfo-comment))
-  (setq-local eldoc-documentation-function 'octave-eldoc-function)
+  (add-function :before-until (local 'eldoc-documentation-function)
+                'octave-eldoc-function)
 
   (easy-menu-add octave-mode-menu))
 
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 63597d5..586109a 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -4378,8 +4378,8 @@ Arguments START and END narrow the buffer region to work on."
                                                  (current-column))))
          (^ '(- (1+ (current-indentation))))))
 
-  (set (make-local-variable 'eldoc-documentation-function)
-       #'python-eldoc-function)
+  (add-function :before-until (local 'eldoc-documentation-function)
+                #'python-eldoc-function)
 
   (add-to-list 'hs-special-modes-alist
                `(python-mode "^\\s-*\\(?:def\\|class\\)\\>" nil "#"
diff --git a/lisp/simple.el b/lisp/simple.el
index 9f44798..806581b 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -1407,8 +1407,8 @@ display the result of expression evaluation."
     (minibuffer-with-setup-hook
         (lambda ()
           ;; FIXME: call emacs-lisp-mode?
-          (setq-local eldoc-documentation-function
-                      #'elisp-eldoc-documentation-function)
+          (add-function :before-until (local 'eldoc-documentation-function)
+                        #'elisp-eldoc-documentation-function)
           (add-hook 'completion-at-point-functions
                     #'elisp-completion-at-point nil t)
           (run-hooks 'eval-expression-minibuffer-setup-hook))
-- 
2.2.0.rc0.207.ga3a616c






^ permalink raw reply related	[flat|nested] 16+ messages in thread

* bug#19338: [PATCHv2 1/2] descr-text: add `describe-char-eldoc' describing character at point
  2014-12-11 16:02         ` bug#19338: [PATCHv2 1/2] descr-text: add `describe-char-eldoc' describing character at point Michal Nazarewicz
  2014-12-11 16:02           ` bug#19338: [PATCHv2 2/2] eldoc: convert `eldoc-documentation-function' into a defcustom Michal Nazarewicz
@ 2014-12-11 16:56           ` Leo Liu
  2014-12-11 17:21             ` Michal Nazarewicz
  2014-12-14 19:46           ` Eli Zaretskii
  2 siblings, 1 reply; 16+ messages in thread
From: Leo Liu @ 2014-12-11 16:56 UTC (permalink / raw)
  To: Michal Nazarewicz; +Cc: 19338

On 2014-12-11 17:02 +0100, Michal Nazarewicz wrote:
> `describe-char-eldoc' displays information about character at point,
> +and can be used as a default value of `eldoc-documentation-function'.

Boy! don't we have enough ways to annoy users?

> It is +useful when, for example, one needs to distinguish various
> spaces (e.g. ] [, +] [, ] [, etc.) while using mono-spaced font.

C-x =

Leo





^ permalink raw reply	[flat|nested] 16+ messages in thread

* bug#19338: [PATCH 1/3] eldoc: use default eldoc function if local one gives no results
  2014-12-11  2:38       ` Stefan Monnier
  2014-12-11 16:02         ` bug#19338: [PATCHv2 1/2] descr-text: add `describe-char-eldoc' describing character at point Michal Nazarewicz
@ 2014-12-11 16:59         ` Stefan Monnier
  1 sibling, 0 replies; 16+ messages in thread
From: Stefan Monnier @ 2014-12-11 16:59 UTC (permalink / raw)
  To: Michal Nazarewicz; +Cc: 19338

> course that requires fixing the default value of
> eldoc-documentation-function).

Which I fixed yesterday, by the way,


        Stefan





^ permalink raw reply	[flat|nested] 16+ messages in thread

* bug#19338: [PATCHv2 1/2] descr-text: add `describe-char-eldoc' describing character at point
  2014-12-11 16:56           ` bug#19338: [PATCHv2 1/2] descr-text: add `describe-char-eldoc' describing character at point Leo Liu
@ 2014-12-11 17:21             ` Michal Nazarewicz
  0 siblings, 0 replies; 16+ messages in thread
From: Michal Nazarewicz @ 2014-12-11 17:21 UTC (permalink / raw)
  To: Leo Liu; +Cc: 19338

> On 2014-12-11 17:02 +0100, Michal Nazarewicz wrote:
>> `describe-char-eldoc' displays information about character at point,
>> +and can be used as a default value of `eldoc-documentation-function'.

On Fri, Dec 12 2014, Leo Liu <sdl.web@gmail.com> wrote:
> Boy! don't we have enough ways to annoy users?

It's not enabled by default and you don't have to use it.

>> It is +useful when, for example, one needs to distinguish various
>> spaces (e.g. ] [, +] [, ] [, etc.) while using mono-spaced font.

> C-x =

C-x = (i) is two keystrokes, and (ii) does not even give character's
name.

C-u C-x = (i) is three keystrokes, (ii) pops up a new window, which
later needs to be closed somehow, (iii) contents of which is actually
terribly hard to read (e.g. name of the character is somewhere in the
middle).

-- 
Best regards,                                         _     _
.o. | Liege of Serenely Enlightened Majesty of      o' \,=./ `o
..o | Computer Science,  Michał “mina86” Nazarewicz    (o o)
ooo +--<mpn@google.com>--<xmpp:mina86@jabber.org>--ooO--(_)--Ooo--





^ permalink raw reply	[flat|nested] 16+ messages in thread

* bug#19338: [PATCHv2 1/2] descr-text: add `describe-char-eldoc' describing character at point
  2014-12-11 16:02         ` bug#19338: [PATCHv2 1/2] descr-text: add `describe-char-eldoc' describing character at point Michal Nazarewicz
  2014-12-11 16:02           ` bug#19338: [PATCHv2 2/2] eldoc: convert `eldoc-documentation-function' into a defcustom Michal Nazarewicz
  2014-12-11 16:56           ` bug#19338: [PATCHv2 1/2] descr-text: add `describe-char-eldoc' describing character at point Leo Liu
@ 2014-12-14 19:46           ` Eli Zaretskii
  2014-12-14 20:40             ` bug#19338: [PATCHv3 " Michal Nazarewicz
  2 siblings, 1 reply; 16+ messages in thread
From: Eli Zaretskii @ 2014-12-14 19:46 UTC (permalink / raw)
  To: Michal Nazarewicz; +Cc: 19338

> From: Michal Nazarewicz <mpn@google.com>
> Date: Thu, 11 Dec 2014 17:02:31 +0100
> Cc: 19338@debbugs.gnu.org
> 
> From: Michal Nazarewicz <mina86@mina86.com>
> 
> * lisp/descr-text.el (describe-char-eldoc): New function returning
> basic Unicode codepoint information (e.g. name) about character
> at point.  It is meant to be used as a default value of the
> `eldoc-documentation-function' variable.
> (describe-char-eldoc--format, describe-char-eldoc--truncate):
> New helper functions for `describe-char-eldoc' function.
> 
> * tests/automated/descr-text-test.el: New file with tests for
> `describe-char-eldoc--truncate', `describe-char-eldoc--format',
> and `describe-char-eldoc'.

Thanks.  Allow me a few comments about the documentation parts.

> +(defun describe-char-eldoc--truncate (name width)
> +  "Truncate NAME at white spaces such that it is no longer than WIDTH.
> +
> +If NAME consists of white space only, return an empty string.
> +
> +Otherwise, if NAME consists of a single word (where word is defined as sequence
> +of non-white space characters), return that word even if it's longer than WIDTH.
> +
> +Otherwise, if first word in NAME is longer or equal WIDTH, return that word with
> +ellipsis character (\"…\") appended; this results in a string longer than WIDTH.
> +
> +Otherwise, take as many words from NAME as possible, separating them with
> +a single space character, while not exceeding WIDTH characters length limit.  If
> +not all words fit, append ellipsis character (\"…\") at the end; the ellipsis is
> +counted towards WIDTH."

The lines in this doc string are too long, some of them are longer
than 79 characters, which will overflow the typical line width on a
TTY.

More importantly, this kind of "pseudo-code" description of what
the function does is not the best way of documenting a function.  It
is best to describe it in natural-language terms, and start with the
most general, then go to the corner cases.  Pseudo-code usually forces
you to describe the corner cases first, which is confusing and might
lead the reader to wrong conclusions.  Likewise with minor details,
like the fact that words are separated with a single space: this
should be mentioned only after you describe the main job.

> +          (let ((ellipsis (and (cdr last) "…")))

Btw, will this display OK on a TTY?  Not all TTYs support UTF-8.

> +Full description message has a \"U+<hex>: <name> (<gc>: <general category>)\"
> +format where:
> +- <hex> is a hexadecimal codepoint of the character (zero-padded to at least
> +  four digits),
> +- <name> is name of the character.

We don't use <this style> to describe parameters, we use THIS STYLE.

> +(defun describe-char-eldoc ()
> +  "Returns a description of character at point for use by ElDoc mode.

"Return", not "Returns".

> +If character at point is a printable ASCII character (i.e. codepoint between 32
> +and 127 inclusively), nil is returned.  Otherwise a description formatted by
> +`describe-char-eldoc--format' function is returned taking into account value

Here you suddenly switch to passive tense, which is both longer and
make the sentence more complicated.  Try sticking to active as much as
is practical.

Thanks again for working on this.





^ permalink raw reply	[flat|nested] 16+ messages in thread

* bug#19338: [PATCHv3 1/2] descr-text: add `describe-char-eldoc' describing character at point
  2014-12-14 19:46           ` Eli Zaretskii
@ 2014-12-14 20:40             ` Michal Nazarewicz
  0 siblings, 0 replies; 16+ messages in thread
From: Michal Nazarewicz @ 2014-12-14 20:40 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 19338

* lisp/descr-text.el (describe-char-eldoc): New function returning
basic Unicode codepoint information (e.g. name) about character
at point.  It is meant to be used as a default value of the
`eldoc-documentation-function' variable.
(describe-char-eldoc--format, describe-char-eldoc--truncate):
New helper functions for `describe-char-eldoc' function.

* tests/automated/descr-text-test.el: New file with tests for
`describe-char-eldoc--truncate', `describe-char-eldoc--format',
and `describe-char-eldoc'.
---
 etc/NEWS                          |  8 +++-
 lisp/descr-text.el                | 97 +++++++++++++++++++++++++++++++++++++++
 test/automated/descr-text-test.el | 94 +++++++++++++++++++++++++++++++++++++
 3 files changed, 197 insertions(+), 2 deletions(-)
 create mode 100644 test/automated/descr-text-test.el

>> +          (let ((ellipsis (and (cdr last) "…")))

On Sun, Dec 14 2014, Eli Zaretskii <eliz@gnu.org> wrote:
> Btw, will this display OK on a TTY?  Not all TTYs support UTF-8.

It will if TTY supports UTF-8. ;)  Perhaps it's not a problem on TTYs
that do not because people are unlikely to open documents using Unicode
on such TTYs?

I used “…” because it's a single character so it does not carve cut that
much from the WIDTH (alternative “...” would be three characters).

In any event, changed it to “...”.

diff --git a/etc/NEWS b/etc/NEWS
index e5656fa..53dc795 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -218,8 +218,12 @@ typing RET.
 result of the calculation into the current buffer.
 
 ** ElDoc
-*** New minor mode global-eldoc-mode
-*** eldoc-documentation-function now defaults to nil
+*** New minor mode `global-eldoc-mode'
+*** `eldoc-documentation-function' now defaults to `ignore'
+*** `describe-char-eldoc' displays information about character at point,
+and can be used as a default value of `eldoc-documentation-function'.  It is
+useful when, for example, one needs to distinguish various spaces (e.g. ] [,
+] [, ] [, etc.) while using mono-spaced font.
 
 ** eww
 
diff --git a/etc/NEWS b/etc/NEWS
index e5656fa..53dc795 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -218,8 +218,12 @@ typing RET.
 result of the calculation into the current buffer.
 
 ** ElDoc
-*** New minor mode global-eldoc-mode
-*** eldoc-documentation-function now defaults to nil
+*** New minor mode `global-eldoc-mode'
+*** `eldoc-documentation-function' now defaults to `ignore'
+*** `describe-char-eldoc' displays information about character at point,
+and can be used as a default value of `eldoc-documentation-function'.  It is
+useful when, for example, one needs to distinguish various spaces (e.g. ] [,
+] [, ] [, etc.) while using mono-spaced font.
 
 ** eww
 
diff --git a/lisp/descr-text.el b/lisp/descr-text.el
index 1dc43e9..56f5866 100644
--- a/lisp/descr-text.el
+++ b/lisp/descr-text.el
@@ -825,6 +825,102 @@ relevant to POS."
 
 (define-obsolete-function-alias 'describe-char-after 'describe-char "22.1")
 
+;;; Describe-Char-ElDoc
+
+(defun describe-char-eldoc--truncate (name width)
+  "Truncate NAME at white spaces such that it is no longer than WIDTH.
+
+Split NAME on white space character and return string with as
+many leading words of NAME as possible without exceeding WIDTH
+characters.  If NAME consists of white space characters only,
+return an empty string.  Three dots (\"...\") are appended to
+returned string if some of the words from NAME have been omitted.
+
+NB: Function may return string longer than WIDTH if name consists
+of a single word, or it's first word is longer than WIDTH
+characters."
+  (let ((words (split-string name)))
+    (if words
+        (let ((last words))
+          (setq width (- width (length (car words))))
+          (while (and (cdr last)
+                      (<= (+ (length (cadr last)) (if (cddr last) 4 1)) width))
+            (setq last (cdr last))
+            (setq width (- width (length (car last)) 1)))
+          (let ((ellipsis (and (cdr last) "...")))
+            (setcdr last nil)
+            (concat (mapconcat 'identity words " ") ellipsis)))
+      "")))
+
+(defun describe-char-eldoc--format (ch &optional width)
+  "Format a description for character CH which is no more than WIDTH characters.
+
+Full description message has a \"U+HEX: NAME (GC: GENERAL-CATEGORY)\"
+format where:
+- HEX is a hexadecimal codepoint of the character (zero-padded to at
+  least four digits),
+- NAME is name of the character.
+- GC is a two-letter abbreviation of the general-category of the
+  character, and
+- GENERAL-CATEGORY is full name of the general-category of the
+  character.
+
+If WIDTH is non-nil some elements of the description may be
+omitted to accommodate the length restriction.  Under certain
+condition, the function may return string longer than WIDTH, see
+`describe-char-eldoc--truncate'."
+  (let ((name (get-char-code-property ch 'name)))
+    (when name
+      (let* ((code (propertize (format "U+%04X" ch)
+                               'face 'font-lock-constant-face))
+             (gc (get-char-code-property ch 'general-category))
+             (gc-desc (char-code-property-description 'general-category gc)))
+
+        (unless (or (not width) (<= (length name) width))
+          (setq name (describe-char-eldoc--truncate name width)))
+        (setq name (concat (substring name 0 1) (downcase (substring name 1))))
+        (setq name (propertize name 'face 'font-lock-variable-name-face))
+
+        (setq gc (propertize (symbol-name gc) 'face 'font-lock-comment-face))
+        (when gc-desc
+          (setq gc-desc (propertize gc-desc 'face 'font-lock-comment-face)))
+
+        (let ((lcode    (length code))
+              (lname    (length name))
+              (lgc      (length gc))
+              (lgc-desc (and gc-desc (length gc-desc))))
+          (cond
+           ((and gc-desc
+                 (or (not width) (<= (+ lcode lname lgc lgc-desc 7) width)))
+            (concat code ": " name " (" gc ": " gc-desc ")"))
+           ((and gc-desc (<= (+ lcode lname lgc-desc 5) width))
+            (concat code ": " name " (" gc-desc ")"))
+           ((or (not width) (<= (+ lcode lname lgc 5) width))
+            (concat code ": " name " (" gc ")"))
+           ((<= (+ lname lgc 3) width)
+            (concat name " (" gc ")"))
+           (t name)))))))
+
+;;;###autoload
+(defun describe-char-eldoc ()
+  "Return a description of character at point for use by ElDoc mode.
+
+Return nil if character at point is a printable ASCII
+character (i.e. codepoint between 32 and 127 inclusively).
+Otherwise return a description formatted by
+`describe-char-eldoc--format' function taking into account value
+of `eldoc-echo-area-use-multiline-p' variable and width of
+minibuffer window for width limit.
+
+This function is meant to be used as a value of
+`eldoc-documentation-function' variable."
+  (let ((ch (following-char)))
+    (when (and (not (zerop ch)) (or (< ch 32) (> ch 127)))
+      (describe-char-eldoc--format
+       ch
+       (unless (eq eldoc-echo-area-use-multiline-p t)
+         (1- (window-width (minibuffer-window))))))))
+
 (provide 'descr-text)
 
 ;;; descr-text.el ends here
diff --git a/test/automated/descr-text-test.el b/test/automated/descr-text-test.el
new file mode 100644
index 0000000..81ae727
--- /dev/null
+++ b/test/automated/descr-text-test.el
@@ -0,0 +1,94 @@
+;;; descr-text-test.el --- ERT tests for descr-text.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2014 Free Software Foundation, Inc.
+
+;; Author:     Michal Nazarewicz <mina86@mina86.com>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package defines regression tests for the descr-text package.
+
+;;; Code:
+
+(require 'ert)
+(require 'descr-text)
+
+
+(ert-deftest descr-text-test-truncate ()
+  "Tests describe-char-eldoc--truncate function."
+  (should (equal ""
+                 (describe-char-eldoc--truncate " \t \n" 100)))
+  (should (equal "foo"
+                 (describe-char-eldoc--truncate "foo" 1)))
+  (should (equal "foo..."
+                 (describe-char-eldoc--truncate "foo wilma fred" 0)))
+  (should (equal "foo..."
+                 (describe-char-eldoc--truncate
+                  "foo wilma fred" (length "foo wilma"))))
+  (should (equal "foo wilma..."
+                 (describe-char-eldoc--truncate
+                  "foo wilma fred" (+ 3 (length "foo wilma")))))
+  (should (equal "foo wilma..."
+                 (describe-char-eldoc--truncate
+                  "foo wilma fred" (1- (length "foo wilma fred")))))
+  (should (equal "foo wilma fred"
+                 (describe-char-eldoc--truncate
+                  "foo wilma fred" (length "foo wilma fred"))))
+  (should (equal "foo wilma fred"
+                 (describe-char-eldoc--truncate
+                  "  foo\t wilma \nfred\t " (length "foo wilma fred")))))
+
+(ert-deftest descr-text-test-format-desc ()
+  "Tests describe-char-eldoc--format function."
+  (should (equal "U+2026: Horizontal ellipsis (Po: Punctuation, Other)"
+                 (describe-char-eldoc--format ?…)))
+  (should (equal "U+2026: Horizontal ellipsis (Punctuation, Other)"
+                 (describe-char-eldoc--format ?… 51)))
+  (should (equal "U+2026: Horizontal ellipsis (Po)"
+                 (describe-char-eldoc--format ?… 40)))
+  (should (equal "Horizontal ellipsis (Po)"
+                 (describe-char-eldoc--format ?… 30)))
+  (should (equal "Horizontal ellipsis"
+                 (describe-char-eldoc--format ?… 20)))
+  (should (equal "Horizontal..."
+                 (describe-char-eldoc--format ?… 10))))
+
+(ert-deftest descr-text-test-desc ()
+  "Tests describe-char-eldoc function."
+  (with-temp-buffer
+    (insert "a…")
+    (goto-char (point-min))
+    (should (eq ?a (following-char))) ; make sure we are where we think we are
+    ;; Function should return nil for an ASCII character.
+    (should (not (describe-char-eldoc)))
+
+    (goto-char (1+ (point)))
+    (should (eq ?… (following-char)))
+    (let ((eldoc-echo-area-use-multiline-p t))
+      ;; Function should return description of an Unicode character.
+      (should (equal "U+2026: Horizontal ellipsis (Po: Punctuation, Other)"
+                     (describe-char-eldoc))))
+
+    (goto-char (point-max))
+    ;; At the end of the buffer, function should return nil and not blow up.
+    (should (not (describe-char-eldoc)))))
+
+
+(provide 'descr-text-test)
+
+;;; descr-text-test.el ends here
-- 
2.2.0.rc0.207.ga3a616c






^ permalink raw reply related	[flat|nested] 16+ messages in thread

* bug#19338: [PATCHv2 2/2] eldoc: convert `eldoc-documentation-function' into a defcustom
  2014-12-11 16:02           ` bug#19338: [PATCHv2 2/2] eldoc: convert `eldoc-documentation-function' into a defcustom Michal Nazarewicz
@ 2015-01-20 14:08             ` Michal Nazarewicz
  0 siblings, 0 replies; 16+ messages in thread
From: Michal Nazarewicz @ 2015-01-20 14:08 UTC (permalink / raw)
  To: 19338-done

On Thu, Dec 11 2014, Michal Nazarewicz <mpn@google.com> wrote:
> * lisp/emacs-lisp/eldoc.el (eldoc-documentation-function): Change from
> defvar to defcustom with `describe-char-eldoc' function as one of the
> suggested values.  Describe how major modes should use `add-function' to
> alter value of the defcustom.

FYI, v3 1/2 and this patch pushed to master except without changing the
variable to defcustom.

-- 
Best regards,                                         _     _
.o. | Liege of Serenely Enlightened Majesty of      o' \,=./ `o
..o | Computer Science,  Michał “mina86” Nazarewicz    (o o)
ooo +--<mpn@google.com>--<xmpp:mina86@jabber.org>--ooO--(_)--Ooo--





^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2015-01-20 14:08 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-12-10 17:24 bug#19338: [PATCH 0/3] Implement an ElDoc function which describes char at point Michal Nazarewicz
2014-12-10 17:49 ` bug#19338: [PATCH 1/3] eldoc: use default eldoc function if local one gives no results Michal Nazarewicz
2014-12-10 17:49   ` bug#19338: [PATCH 2/3] descr-text: add `describe-char-eldoc' describing character at point Michal Nazarewicz
2014-12-10 17:49   ` bug#19338: [PATCH 3/3] eldoc: convert `eldoc-documentation-function' into a defcustom Michal Nazarewicz
2014-12-10 20:08     ` Stefan Monnier
2014-12-10 20:05   ` bug#19338: [PATCH 1/3] eldoc: use default eldoc function if local one gives no results Stefan Monnier
2014-12-10 21:46     ` Michal Nazarewicz
2014-12-11  2:38       ` Stefan Monnier
2014-12-11 16:02         ` bug#19338: [PATCHv2 1/2] descr-text: add `describe-char-eldoc' describing character at point Michal Nazarewicz
2014-12-11 16:02           ` bug#19338: [PATCHv2 2/2] eldoc: convert `eldoc-documentation-function' into a defcustom Michal Nazarewicz
2015-01-20 14:08             ` Michal Nazarewicz
2014-12-11 16:56           ` bug#19338: [PATCHv2 1/2] descr-text: add `describe-char-eldoc' describing character at point Leo Liu
2014-12-11 17:21             ` Michal Nazarewicz
2014-12-14 19:46           ` Eli Zaretskii
2014-12-14 20:40             ` bug#19338: [PATCHv3 " Michal Nazarewicz
2014-12-11 16:59         ` bug#19338: [PATCH 1/3] eldoc: use default eldoc function if local one gives no results Stefan Monnier

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).