unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#28907: 26.0.90; [eww] some problems in input/textarea
@ 2017-10-20  8:39 Katsumi Yamaoka
  2017-10-27 13:31 ` Eli Zaretskii
  0 siblings, 1 reply; 14+ messages in thread
From: Katsumi Yamaoka @ 2017-10-20  8:39 UTC (permalink / raw)
  To: 28907

[-- Attachment #1: Type: text/plain, Size: 1648 bytes --]

Hi,

There are some problems with an input form and a textarea as
follows:

・Can't enter text at the beginnig of input/textarea if there is
  a link just above the form.
・Can't enter space at (1- eol).
・Can't kill a line.
・Can't undo.
・Can't retrieve the response for the submit in a certain site.
・Padding width gets incorrect if there is a wide character.
・A major mode command like `g' doesn't work at the right outside
  of textarea.

I tested and tried to improve them in mainly:
<https://www.excite.co.jp/world/english/>    [1]
A patch is below.  Some of them would have to be improved further,
though.

Thanks.

[1] This is an English-Japanese translation service; you can
find the textarea slot for entering an original English text at
the line 191 in an eww buffer.  Please note that the translation
is not so accurate. ;-)

P.S. I will be absent from the net till Thursday, sorry.

In GNU Emacs 26.0.90 (build 1, i686-pc-cygwin, GTK+ Version 3.18.9)
 of 2017-10-20 built on localhost
Windowing system distributor 'The Cygwin/X Project', version 11.0.11900000

* lisp/net/eww.el (eww, eww-reload): Disable undo.
(eww-render): Enable undo when a user enters things in input/textarea.
(eww-tag-a): Make keymap prop non-sticky.
(eww-kill-line): New command.
(eww-textarea-map): Use it.
(eww-process-text-input): Enable a user to enter space at (1- eol);
don't break the form when killing a line at the beginning of the form.
(eww-tag-textarea): Treat textarea's text as its value if it is null;
work the padding correctly when there is a wide character;
make keymap prop non-sticky.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: text/x-patch, Size: 4439 bytes --]

--- eww.el~	2017-09-14 22:06:50.000000000 +0000
+++ eww.el	2017-10-20 08:36:56.427163000 +0000
@@ -256,6 +256,7 @@
    (if (eq major-mode 'eww-mode)
        (current-buffer)
      (get-buffer-create "*eww*")))
+  (buffer-disable-undo)
   (eww-setup-buffer)
   ;; Check whether the domain only uses "Highly Restricted" Unicode
   ;; IDNA characters.  If not, transform to punycode to indicate that
@@ -397,7 +398,10 @@
 	    (setq eww-history-position 0)
 	    (and last-coding-system-used
 		 (set-buffer-file-coding-system last-coding-system-used))
-	    (run-hooks 'eww-after-render-hook)))
+	    (run-hooks 'eww-after-render-hook)
+	    (add-hook 'before-change-functions
+		      (lambda (&rest _args) (buffer-enable-undo))
+		      nil t)))
       (kill-buffer data-buffer))))
 
 (defun eww-parse-headers ()
@@ -546,7 +550,8 @@
   (eww-handle-link dom)
   (let ((start (point)))
     (shr-tag-a dom)
-    (put-text-property start (point) 'keymap eww-link-keymap)))
+    (add-text-properties start (point) (list 'keymap eww-link-keymap
+					     'rear-nonsticky t))))
 
 (defun eww-update-header-line-format ()
   (setq header-line-format
@@ -916,6 +921,7 @@
 a prefix argument), don't reload the page from the network, but
 just re-display the HTML already fetched."
   (interactive "P")
+  (buffer-disable-undo)
   (let ((url (plist-get eww-data :url)))
     (if local
 	(if (null (plist-get eww-data :dom))
@@ -966,6 +972,7 @@
     (define-key map [(control c) (control c)] 'eww-submit)
     (define-key map [?\t] 'shr-next-link)
     (define-key map [?\M-\t] 'shr-previous-link)
+    (define-key map "\C-k" 'eww-kill-line)
     map))
 
 (defvar eww-select-map
@@ -990,6 +997,13 @@
     (when (> (point) start)
       (forward-char 1))))
 
+;; FIXME: make it usable for `eww-text-map'.
+(defun eww-kill-line (&optional _arg)
+  "Kill the rest of the current line."
+  (interactive "P")
+  (let ((inhibit-read-only t))
+    (kill-region (point) (line-end-position))))
+
 (defun eww-beginning-of-field ()
   (cond
    ((bobp)
@@ -1134,6 +1148,8 @@
 		 (1- (line-end-position))
 	       (eww-end-of-field)))
 	    (while (and (> length 0)
+			;; Don't delete space a user enters at (1- eol).
+			(< end (point))
 			(eql (char-after (1- (point))) ? ))
 	      (delete-region (1- (point)) (point))
 	      (cl-decf length))))
@@ -1141,10 +1157,11 @@
 	  ;; Add padding.
 	  (save-excursion
 	    (goto-char end)
-	    (goto-char
-	     (if (equal type "textarea")
-		 (1- (line-end-position))
-	       (1+ (eww-end-of-field))))
+	    (if (equal type "textarea")
+		;; Don't move point if the line is empty.
+		(unless (and (bolp) (eolp))
+		  (goto-char (1- (line-end-position))))
+	      (goto-char (1+ (eww-end-of-field))))
 	    (let ((start (point)))
               (insert (make-string (abs length) ? ))
 	      (set-text-properties start (point) properties))
@@ -1166,13 +1183,14 @@
                'display (make-string (length value) ?*)))))))))
 
 (defun eww-tag-textarea (dom)
-  (let ((start (point))
-	(value (or (dom-attr dom 'value) ""))
+  (let ((value (or (dom-attr dom 'value) (dom-text dom)))
 	(lines (string-to-number (or (dom-attr dom 'rows) "10")))
 	(width (string-to-number (or (dom-attr dom 'cols) "10")))
-	end)
+	start end)
     (shr-ensure-newline)
-    (insert value)
+    (setq start (point))
+    (let ((fill-column width))
+      (fill-region start (progn (insert value) (point))))
     (shr-ensure-newline)
     (when (< (count-lines start (point)) lines)
       (dotimes (_ (- lines (count-lines start (point))))
@@ -1181,14 +1199,16 @@
     (goto-char start)
     (while (< (point) end)
       (end-of-line)
-      (let ((pad (- width (- (point) (line-beginning-position)))))
+      (let ((pad (- width (current-column)))) ;; There may be a wide character.
 	(when (> pad 0)
 	  (insert (make-string pad ? ))))
       (add-face-text-property (line-beginning-position)
 			      (point) 'eww-form-textarea)
-      (put-text-property (line-beginning-position) (point) 'inhibit-read-only t)
-      (put-text-property (line-beginning-position) (point)
-			 'local-map eww-textarea-map)
+      (add-text-properties (line-beginning-position) (point)
+			   `(inhibit-read-only t
+			     local-map ,eww-textarea-map
+			     ;; Enable the major mode keymap on newlines.
+			     rear-nonsticky t))
       (forward-line 1))
     (put-text-property start (point) 'eww-form
 		       (list :eww-form eww-form

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

* bug#28907: 26.0.90; [eww] some problems in input/textarea
  2017-10-20  8:39 bug#28907: 26.0.90; [eww] some problems in input/textarea Katsumi Yamaoka
@ 2017-10-27 13:31 ` Eli Zaretskii
  2017-10-29 23:30   ` Katsumi Yamaoka
  0 siblings, 1 reply; 14+ messages in thread
From: Eli Zaretskii @ 2017-10-27 13:31 UTC (permalink / raw)
  To: Katsumi Yamaoka, Lars Ingebrigtsen; +Cc: 28907

> Date: Fri, 20 Oct 2017 17:39:29 +0900
> From: Katsumi Yamaoka <yamaoka@jpl.org>
> 
> There are some problems with an input form and a textarea as
> follows:
> 
> ・Can't enter text at the beginnig of input/textarea if there is
>   a link just above the form.
> ・Can't enter space at (1- eol).
> ・Can't kill a line.
> ・Can't undo.
> ・Can't retrieve the response for the submit in a certain site.
> ・Padding width gets incorrect if there is a wide character.
> ・A major mode command like `g' doesn't work at the right outside
>   of textarea.
> 
> I tested and tried to improve them in mainly:
> <https://www.excite.co.jp/world/english/>    [1]
> A patch is below.  Some of them would have to be improved further,
> though.

Thanks.

Lars, any comments?  Should we install this, and if so, on what
branch?





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

* bug#28907: 26.0.90; [eww] some problems in input/textarea
  2017-10-27 13:31 ` Eli Zaretskii
@ 2017-10-29 23:30   ` Katsumi Yamaoka
  2017-11-02  7:39     ` Katsumi Yamaoka
  0 siblings, 1 reply; 14+ messages in thread
From: Katsumi Yamaoka @ 2017-10-29 23:30 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Lars Ingebrigtsen, 28907

On Fri, 27 Oct 2017 16:31:49 +0300, Eli Zaretskii wrote:
>> Date: Fri, 20 Oct 2017 17:39:29 +0900
>> From: Katsumi Yamaoka <yamaoka@jpl.org>

>> There are some problems with an input form and a textarea as
>> follows:

>> ・Can't enter text at the beginnig of input/textarea if there is
>>   a link just above the form.
>> ・Can't enter space at (1- eol).
>> ・Can't kill a line.
>> ・Can't undo.
>> ・Can't retrieve the response for the submit in a certain site.
>> ・Padding width gets incorrect if there is a wide character.
>> ・A major mode command like `g' doesn't work at the right outside
>>   of textarea.

>> I tested and tried to improve them in mainly:
>> <https://www.excite.co.jp/world/english/>    [1]
>> A patch is below.  Some of them would have to be improved further,
>> though.

> Thanks.

> Lars, any comments?  Should we install this, and if so, on what
> branch?

Please don't install my patch as is, as I realized it is not
necessarily a better solution.  In particular, to make kill and
yank work properly, we would have to improve the handling of
inlined editable input/textarea further.  Though I'm not sure
whether I can reach to the best result, I'd like to work on it.

Thanks.





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

* bug#28907: 26.0.90; [eww] some problems in input/textarea
  2017-10-29 23:30   ` Katsumi Yamaoka
@ 2017-11-02  7:39     ` Katsumi Yamaoka
  2017-11-10  7:57       ` Katsumi Yamaoka
  0 siblings, 1 reply; 14+ messages in thread
From: Katsumi Yamaoka @ 2017-11-02  7:39 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Lars Ingebrigtsen, 28907

On Mon, 30 Oct 2017 08:30:39 +0900, Katsumi Yamaoka wrote:
> On Fri, 27 Oct 2017 16:31:49 +0300, Eli Zaretskii wrote:
>>> Date: Fri, 20 Oct 2017 17:39:29 +0900
>>> From: Katsumi Yamaoka <yamaoka@jpl.org>

>>> There are some problems with an input form and a textarea as
>>> follows:

>>> ・Can't enter text at the beginnig of input/textarea if there is
>>>   a link just above the form.
>>> ・Can't enter space at (1- eol).
>>> ・Can't kill a line.
>>> ・Can't undo.
>>> ・Can't retrieve the response for the submit in a certain site.
>>> ・Padding width gets incorrect if there is a wide character.
>>> ・A major mode command like `g' doesn't work at the right outside
>>>   of textarea.

[...]

> Please don't install my patch as is, as I realized it is not
> necessarily a better solution.  In particular, to make kill and
> yank work properly, we would have to improve the handling of
> inlined editable input/textarea further.  Though I'm not sure
> whether I can reach to the best result, I'd like to work on it.

Progress report:
・Implementing `kill' and `yank' features have been almost done.
・`yank-pop' is in progress.
・No idea for making `undo' work properly so far.

http://www.jpl.org/tmp/eww-20171102.el

Regards,
(I will be absent till Monday.)





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

* bug#28907: 26.0.90; [eww] some problems in input/textarea
  2017-11-02  7:39     ` Katsumi Yamaoka
@ 2017-11-10  7:57       ` Katsumi Yamaoka
  2017-11-10  8:28         ` Eli Zaretskii
  2017-11-14  8:26         ` Katsumi Yamaoka
  0 siblings, 2 replies; 14+ messages in thread
From: Katsumi Yamaoka @ 2017-11-10  7:57 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Lars Ingebrigtsen, 28907

[-- Attachment #1: Type: text/plain, Size: 2373 bytes --]

On Thu, 02 Nov 2017 16:39:53 +0900, Katsumi Yamaoka wrote:
> On Mon, 30 Oct 2017 08:30:39 +0900, Katsumi Yamaoka wrote:
>> On Fri, 27 Oct 2017 16:31:49 +0300, Eli Zaretskii wrote:
>>>> Date: Fri, 20 Oct 2017 17:39:29 +0900
>>>> From: Katsumi Yamaoka <yamaoka@jpl.org>

>>>> There are some problems with an input form and a textarea as
>>>> follows:

>>>> ・Can't enter text at the beginnig of input/textarea if there is
>>>>   a link just above the form.
>>>> ・Can't enter space at (1- eol).
>>>> ・Can't kill a line.
>>>> ・Can't undo.
>>>> ・Can't retrieve the response for the submit in a certain site.
>>>> ・Padding width gets incorrect if there is a wide character.
>>>> ・A major mode command like `g' doesn't work at the right outside
>>>>   of textarea.

[...]

Some generic editing commands, except for `undo', now almost work
in input/textarea.  To try writing something in those fields, you
can use the following two pages:

<https://html.com/tags/input/#Code_Example>
<https://html.com/tags/textarea/#Code_Example>

A patch is below.

* lisp/net/eww.el (eww-preprocess-text-input): New function that
calculates changed length based on string width, not characters.
(eww-render): Add it to before-change-functions.
(eww-tag-a): Make keymap text property non-sticky.
(eww-text-map, eww-textarea-map): Remap some generic editing keys.
(eww-beginning-of-text, eww-end-of-text): Work on textarea as well.
(eww-field-extract-text, eww-field-uniline-text, eww-field-insert-text)
(eww-field-funcall): New functions.
(eww-field-backward-delete-char-untabify)
(eww-field-delete-backward-char, eww-field-delete-char)
(eww-field-kill-line, eww-field-kill-region, eww-field-newline)
(eww-field-open-line, eww-field-yank, eww-field-yank-pop): New commands.
(eww-form-text): Pass field width to eww-form property.
(eww-field-replace-length): New internal variable.
(eww-process-text-input): Use string width based changed length;
enable a user to enter space at (1- eol);
don't break the form when killing a line at the beginning of the form.
(eww-tag-textarea): Treat textarea's text as its value if it is null;
work the padding correctly when there is a wide character;
make keymap prop non-sticky;
pass field width and height to eww-form property.
(eww-size-text-inputs): Make the field end position a marker.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: text/x-patch, Size: 19527 bytes --]

--- eww.el~	2017-09-14 22:06:50.000000000 +0000
+++ eww.el	2017-11-10 07:54:06.465612900 +0000
@@ -397,7 +397,9 @@
 	    (setq eww-history-position 0)
 	    (and last-coding-system-used
 		 (set-buffer-file-coding-system last-coding-system-used))
-	    (run-hooks 'eww-after-render-hook)))
+	    (run-hooks 'eww-after-render-hook)
+	    (add-hook 'before-change-functions
+		      'eww-preprocess-text-input nil t)))
       (kill-buffer data-buffer))))
 
 (defun eww-parse-headers ()
@@ -546,7 +548,8 @@
   (eww-handle-link dom)
   (let ((start (point)))
     (shr-tag-a dom)
-    (put-text-property start (point) 'keymap eww-link-keymap)))
+    (put-text-property start (point) 'keymap eww-link-keymap)
+    (put-text-property start (point) 'rear-nonsticky '(keymap))))
 
 (defun eww-update-header-line-format ()
   (setq header-line-format
@@ -955,17 +958,29 @@
     (define-key map [(control a)] 'eww-beginning-of-text)
     (define-key map [(control c) (control c)] 'eww-submit)
     (define-key map [(control e)] 'eww-end-of-text)
+    (define-key map [(control j)] 'eww-submit)
     (define-key map [?\t] 'shr-next-link)
     (define-key map [?\M-\t] 'shr-previous-link)
+    (dolist (cmd '(backward-delete-char-untabify
+		   delete-backward-char delete-char
+		   kill-line kill-region yank yank-pop))
+      (define-key map `[remap ,cmd] (intern (format "eww-field-%s" cmd))))
+    (define-key map [remap open-line] 'ignore)
     map))
 
 (defvar eww-textarea-map
   (let ((map (make-keymap)))
     (set-keymap-parent map text-mode-map)
-    (define-key map "\r" 'forward-line)
+    (define-key map "\r" 'eww-field-newline)
+    (define-key map [(control a)] 'eww-beginning-of-text)
     (define-key map [(control c) (control c)] 'eww-submit)
+    (define-key map [(control e)] 'eww-end-of-text)
     (define-key map [?\t] 'shr-next-link)
     (define-key map [?\M-\t] 'shr-previous-link)
+    (dolist (cmd '(backward-delete-char-untabify
+		   delete-backward-char delete-char
+		   kill-line kill-region open-line yank yank-pop))
+      (define-key map `[remap ,cmd] (intern (format "eww-field-%s" cmd))))
     map))
 
 (defvar eww-select-map
@@ -975,20 +990,343 @@
     map))
 
 (defun eww-beginning-of-text ()
-  "Move to the start of the input field."
+  "Move to the beginning of the current line in the input field."
   (interactive)
-  (goto-char (eww-beginning-of-field)))
+  (beginning-of-line)
+  (goto-char (text-property-not-all (point) (line-end-position)
+				    'inhibit-read-only nil)))
 
 (defun eww-end-of-text ()
-  "Move to the end of the text in the input field."
+  "Move to the end of the text of the current line in the input field.
+When the point is already in the end of the text, move to the end of
+the current line."
   (interactive)
-  (goto-char (eww-end-of-field))
-  (let ((start (eww-beginning-of-field)))
-    (while (and (equal (following-char) ? )
-		(> (point) start))
-      (forward-char -1))
-    (when (> (point) start)
-      (forward-char 1))))
+  (let ((end (or (text-property-any (point) (line-end-position)
+				    'inhibit-read-only nil)
+		 (line-end-position))))
+    (unless (prog1
+		(and (looking-at " *") (>= (match-end 0) end))
+	      (goto-char (if (get-text-property end 'inhibit-read-only)
+			     end (1- end))))
+      (skip-chars-backward " "))))
+
+(defun eww-field-extract-text ()
+  "Return the contents of the input/textarea field where the point is.
+The contents will be divided into a list of two (or three) parts by
+the mark (if exists as either active or inactive in the field) and
+the current position, and returned as the form:
+
+(FLAG (\"TEXT\" ...) (\"TEXT\" ...) ...)
+
+Where FLAG will be non-nil if the mark is behind the current position.
+Each part is a list of text lines; text lines may be nil that means
+a null text; a text line does not end with a newline; assume that
+there is a newline between adjacent text lines."
+  (let* ((form (get-text-property (point) 'eww-form))
+	 (start (or (cdr (assq :start form)) (point-min)))
+	 (end (or (cdr (assq :end form)) (point-max)))
+	 (mk (mark t))
+	 (pos (point))
+	 (from start)
+	 swap opos boundary bound to lines parts)
+    (if (and mk (>= mk start) (<= mk end))
+	(when (setq swap (> mk pos))
+	  (setq mk (prog1 (setq opos pos) (setq pos mk))))
+      (setq mk nil))
+    (setq boundary (or mk pos))
+    (while (< from end)
+      (if (= from boundary)
+	  (progn
+	    (push '(nil) parts)
+	    (if mk
+		(setq mk nil
+		      boundary pos)
+	      (setq boundary end)))
+	(goto-char from)
+	(setq bound (min boundary (line-end-position))
+	      to (or (and form
+			  (text-property-any from bound 'inhibit-read-only nil))
+		     bound))
+	(push (buffer-substring-no-properties from to) lines)
+	(when (or (= to boundary)
+		  (not (setq from (if form
+				      (text-property-not-all
+				       (1+ to) boundary 'inhibit-read-only nil)
+				    (forward-line 1)
+				    (and (bolp) (< (point) boundary)
+					 (point))))))
+	  (goto-char boundary)
+	  (when (or (bolp)
+		    (and form
+			 (not (get-text-property (1- boundary)
+						 'inhibit-read-only))))
+	    (push "" lines))
+	  (push (nreverse lines) parts)
+	  (setq lines nil
+		from boundary)
+	  (if mk
+	      (setq mk nil
+		    boundary pos)
+	    (setq boundary end)))))
+    (goto-char (or opos pos))
+    (if parts
+	(cons swap (if (= pos end)
+		       (nconc (nreverse parts) '((nil)))
+		     (nreverse parts)))
+      `(,swap (nil) (nil) (nil)))))
+
+(defun eww-field-uniline-text ()
+  "Extract text from the current temporary buffer excluding newlines."
+  (let ((pos (point))
+	parts)
+    (while (re-search-forward "\\([\t ]+\\)\n+\\|\n+\\([\t ]+\\)" nil t)
+      (replace-match "\\1\\2"))
+    (goto-char pos)
+    (while (re-search-forward "\n+" nil 'move)
+      (replace-match " "))
+    (skip-chars-backward "\t ")
+    (setq parts (list (list (buffer-substring pos (point)))))
+    (delete-region pos (point-max))
+    (when (setq pos (mark t))
+      (goto-char pos)
+      (while (re-search-forward "\\([\t ]+\\)\n+\\|\n+\\([\t ]+\\)" nil t)
+	(replace-match "\\1\\2"))
+      (goto-char pos)
+      (while (re-search-forward "\n+" nil t)
+	(replace-match " "))
+      (push (list (buffer-substring pos (point-max))) parts)
+      (delete-region pos (point-max)))
+    (goto-char (point-min))
+    (while (re-search-forward "\\([\t ]+\\)\n+\\|\n+\\([\t ]+\\)" nil t)
+      (replace-match "\\1\\2"))
+    (goto-char (point-min))
+    (while (re-search-forward "\n+" nil t)
+      (replace-match " "))
+    (cons (list (buffer-string)) parts)))
+
+(defun eww-field-insert-text (parts &optional swap-point-and-mark)
+  "Insert PARTS, a list of lists of text lines, in the current buffer.
+Put an inactive mark at the beginning of the second part if there are
+tree parts.  Position point at the beginning of the last part.  If
+SWAP-POINT-AND-MARK is non-nil, the point and the mark will be swapped."
+  (let* ((form (get-text-property (point) 'eww-form))
+	 (textareap (equal (plist-get form :type) "textarea"))
+	 (start (cdr (assq :start form)))
+	 (end (cdr (assq :end form)))
+	 mk pos)
+    (if form ;; We are in an eww buffer.
+	(let ((properties (text-properties-at start))
+	      (width (plist-get form :width))
+	      (inhibit-read-only t)
+	      (inhibit-modification-hooks t)
+	      indent lines line from to len)
+	  (unless textareap
+	    (with-temp-buffer
+	      (eww-field-insert-text parts)
+	      (setq parts (eww-field-uniline-text))))
+	  (goto-char start)
+	  (setq indent (current-column))
+	  (while (< (point) end)
+	    (if parts
+		(while (setq lines (pop parts))
+		  (while lines
+		    ;; We are in the beginning of the text line.
+		    (when (setq line (pop lines))
+		      (setq from (point))
+		      (goto-char (or (text-property-any from (line-end-position)
+							'inhibit-read-only nil)
+				     (line-end-position)))
+		      (setq to (cons (current-column) (point-marker)))
+		      (goto-char from)
+		      (unless (equal line "")
+			(insert-before-markers line)
+			(set-text-properties from (point) properties)
+			(setq from (point)))
+		      (unless (or textareap (eq (char-before) ? ))
+			(insert-before-markers " ")
+			(set-text-properties from (point) properties))
+		      (when (> (setq len (- width (current-column) indent)) 0)
+			(set-text-properties
+			 (point) (progn
+				   (insert-before-markers (make-string len ? ))
+				   (point))
+			 properties))
+		      (delete-region (point) (cdr to))
+		      (when (and textareap (eolp))
+			(set-text-properties (point) (1+ (point)) properties))
+		      (if lines
+			  (if (or (= (point) end)
+				  (progn
+				    (forward-line 1)
+				    (>= (point) end)))
+			      (progn
+				(setq from (point))
+				(insert-before-markers
+				 (make-string (car to) ? )
+				 (if (memq (char-after (cdr to)) '(nil ?\n))
+				     "\n" ""))
+				(set-text-properties from (point) properties)
+				(forward-char -1)
+				(move-to-column indent))
+			    (move-to-column indent))
+			(goto-char from)
+			(unless (or (not textareap)
+				    (bolp)
+				    (not (get-text-property
+					  (1- from) 'inhibit-read-only)))
+			  (forward-line 1)
+			  (when (>= (point) end)
+			    (goto-char end)
+			    (insert (make-string (car to) ? ) "\n")
+			    (set-text-properties end (point) properties)
+			    (set-marker end (point)))
+			  (goto-char from)))
+		      (set-marker (cdr to) nil)))
+		  (cond ((cdr parts) (setq mk (point)))
+			(parts (setq pos (point)))))
+	      (setq from (point)) ;; The end of the last text line.
+	      (goto-char (or (text-property-any from (line-end-position)
+						'inhibit-read-only nil)
+			     (line-end-position)))
+	      (setq to (cons (current-column) (point-marker)))
+	      (if textareap
+		  (progn
+		    (goto-char from)
+		    (insert-before-markers
+		     (make-string (max 0 (- (car to) (current-column))) ? ))
+		    (set-text-properties from (point) properties)
+		    (delete-region (point) (cdr to))
+		    (when (eolp)
+		      (set-text-properties (point) (1+ (point)) properties))
+		    (forward-line 1)
+		    (when (< (point) end)
+		      (move-to-column indent)))
+		(skip-chars-backward " " start)
+		(when (>= (setq len (- width
+				       (string-width
+					(buffer-substring start (point)))))
+			  0)
+		  (forward-char len)
+		  (delete-region (point) (cdr to)))
+		(goto-char (cdr to))
+		(unless (eq (char-before) ? )
+		  (insert-before-markers " ")
+		  (set-text-properties (1- (point)) (point) properties)))
+	      (set-marker (cdr to) nil)))
+	  ;; We are in `end' that is the end of the textarea.
+	  (when (and textareap
+		     (setq lines (plist-get form :lines))
+		     (progn
+		       (goto-char pos)
+		       (forward-line 1)
+		       (prog1
+			   (< (point) end)
+			 (goto-char end)))
+		     (< (setq lines (- lines (count-lines start end))) 0))
+	    (forward-line lines)
+	    (when (re-search-forward "\\(?:[^\n ]+[\n ]+\\)*[^\n ]+" end t)
+	      (forward-line 1))
+	    (delete-region (point) end)))
+      ;; We are in a temporary buffer.
+      (while parts
+	(insert (mapconcat #'identity (pop parts) "\n"))
+	(cond ((cdr parts) (setq mk (point)))
+	      (parts (setq pos (point))))))
+    (when mk
+      (when swap-point-and-mark
+	(setq mk (prog1 pos (setq pos mk))))
+      (goto-char mk)
+      (push-mark))
+    (goto-char (if end (min pos (1- end)) pos))))
+
+(defun eww-field-funcall (function &rest args)
+  "Run FUNCTION on the copied field and replace the field with the result.
+ARGS is a list of arguments that will be passed to FUNCTION."
+  (let* ((parts (eww-field-extract-text))
+	 (swap (pop parts))
+	 pos)
+    (unwind-protect
+	(with-temp-buffer
+	  (eww-field-insert-text parts swap)
+	  (setq pos (point-marker))
+	  (goto-char (point-min))
+	  (while (re-search-forward " +$" pos t)
+	    (replace-match ""))
+	  (goto-char pos)
+	  (while (re-search-forward " +$" nil t)
+	    (replace-match ""))
+	  (goto-char pos)
+	  (set-marker pos nil)
+	  (unwind-protect
+	      (apply function args)
+	    (setq pos (point))
+	    (goto-char (point-max))
+	    (skip-chars-backward "\n " pos)
+	    (delete-region (point) (point-max))
+	    (goto-char pos)
+	    (setq parts (cdr (eww-field-extract-text)))))
+      (eww-field-insert-text parts swap)
+      (deactivate-mark))))
+
+(defun eww-field-backward-delete-char-untabify (arg &optional killp)
+  "Delete characters backward, changing tabs into spaces.
+See `backward-delete-char-untabify' for more information."
+  (interactive "*p\nP")
+  (eww-field-funcall #'backward-delete-char-untabify arg killp))
+
+(defun eww-field-delete-backward-char (n &optional killflag)
+  "Delete the previous N characters (following if N is negative).
+See `delete-backward-char' for more information."
+  (interactive "p\nP")
+  (eww-field-funcall #'delete-backward-char n killflag))
+
+(defun eww-field-delete-char (n &optional killflag)
+  "Delete the following N characters (previous if N is negative).
+See `delete-char' for more information."
+  (interactive "p\nP")
+  (eww-field-funcall #'delete-char n killflag))
+
+(defun eww-field-kill-line (&optional arg)
+  "Kill the rest of the current line.  See `kill-line' for more info."
+  (interactive "*P")
+  (eww-field-funcall #'kill-line arg))
+
+(defun eww-field-kill-region (beg end &optional region)
+  "Kill text between point and mark.  See `kill-region' for more info."
+  (interactive (list (mark) (point) 'region))
+  (unless (and beg end)
+    (user-error "The mark is not set now, so there is no region"))
+  (eww-field-funcall #'kill-region beg end region))
+
+(defun eww-field-newline (&optional arg interactive)
+  "Insert a newline, and move to left margin of the new line if it's blank.
+See `newline' for more information."
+  (interactive "*P\np")
+  (eww-field-funcall #'newline arg interactive))
+
+(defun eww-field-open-line (n)
+  "Insert a newline and leave point before it.
+See `open-line' for more information."
+  (interactive "*p")
+  (eww-field-funcall #'open-line n))
+
+(defun eww-field-yank (&optional arg)
+  "Reinsert the last stretch of killed text.  See `yank' for more info."
+  (interactive "*P")
+  (push-mark)
+  (eww-field-funcall #'yank arg))
+
+(defun eww-field-yank-pop (&optional arg)
+  "Replace just-yanked stretch of killed text with a different stretch.
+See `yank-pop' for more infomation."
+  (interactive "*p")
+  (let ((start (eww-beginning-of-field))
+	(mk (mark t)))
+    (unless (and mk (>= mk start) (<= mk (eww-end-of-field)))
+      (goto-char (prog1 (point)
+		   (goto-char start)
+		   (push-mark))))
+    (eww-field-funcall #'yank-pop arg)))
 
 (defun eww-beginning-of-field ()
   (cond
@@ -1099,7 +1437,10 @@
                        (list :eww-form eww-form
                              :value value
                              :type type
-                             :name (dom-attr dom 'name)))
+                             :name (dom-attr dom 'name)
+			     :width width))
+    ;; Enable the major mode keymap on the subsequent gap.
+    (put-text-property start (point) 'rear-nonsticky '(local-map))
     (insert " ")))
 
 (defconst eww-text-input-types '("text" "password" "textarea"
@@ -1109,19 +1450,26 @@
   "List of input types which represent a text input.
 See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.")
 
-(defun eww-process-text-input (beg end replace-length)
+(defvar eww-field-replace-length nil)
+
+(defun eww-preprocess-text-input (beg end)
+  (setq eww-field-replace-length (string-width (buffer-substring beg end))))
+
+(defun eww-process-text-input (beg end _replace-length)
   (when-let* ((pos (and (< (1+ end) (point-max))
 		        (> (1- end) (point-min))
 		        (cond
+			 ((get-text-property end 'eww-form)
+			  end)
 		         ((get-text-property (1+ end) 'eww-form)
 			  (1+ end))
 		         ((get-text-property (1- end) 'eww-form)
 			  (1- end))))))
     (let* ((form (get-text-property pos 'eww-form))
 	   (properties (text-properties-at pos))
-           (buffer-undo-list t)
 	   (inhibit-read-only t)
-	   (length (- end beg replace-length))
+	   (length (- (string-width (buffer-substring beg end))
+		      eww-field-replace-length))
 	   (type (plist-get form :type)))
       (when (and form
 		 (member type eww-text-input-types))
@@ -1134,6 +1482,8 @@
 		 (1- (line-end-position))
 	       (eww-end-of-field)))
 	    (while (and (> length 0)
+			;; Don't delete space a user enters at (1- eol).
+			(< end (point))
 			(eql (char-after (1- (point))) ? ))
 	      (delete-region (1- (point)) (point))
 	      (cl-decf length))))
@@ -1141,13 +1491,10 @@
 	  ;; Add padding.
 	  (save-excursion
 	    (goto-char end)
-	    (goto-char
-	     (if (equal type "textarea")
-		 (1- (line-end-position))
-	       (1+ (eww-end-of-field))))
-	    (let ((start (point)))
-              (insert (make-string (abs length) ? ))
-	      (set-text-properties start (point) properties))
+	    (if (equal type "textarea")
+		(end-of-line)
+	      (goto-char (1+ (eww-end-of-field))))
+	    (insert-before-markers (make-string (abs length) ? ))
 	    (goto-char (1- end)))))
 	(set-text-properties (cdr (assq :start form))
                              (cdr (assq :end form))
@@ -1166,13 +1513,14 @@
                'display (make-string (length value) ?*)))))))))
 
 (defun eww-tag-textarea (dom)
-  (let ((start (point))
-	(value (or (dom-attr dom 'value) ""))
+  (let ((value (or (dom-attr dom 'value) (dom-text dom)))
 	(lines (string-to-number (or (dom-attr dom 'rows) "10")))
 	(width (string-to-number (or (dom-attr dom 'cols) "10")))
-	end)
+	start end)
     (shr-ensure-newline)
-    (insert value)
+    (setq start (point))
+    (let ((fill-column width))
+      (fill-region start (progn (insert value) (point))))
     (shr-ensure-newline)
     (when (< (count-lines start (point)) lines)
       (dotimes (_ (- lines (count-lines start (point))))
@@ -1181,20 +1529,24 @@
     (goto-char start)
     (while (< (point) end)
       (end-of-line)
-      (let ((pad (- width (- (point) (line-beginning-position)))))
+      (let ((pad (- width (current-column)))) ;; There may be a wide character.
 	(when (> pad 0)
 	  (insert (make-string pad ? ))))
       (add-face-text-property (line-beginning-position)
 			      (point) 'eww-form-textarea)
-      (put-text-property (line-beginning-position) (point) 'inhibit-read-only t)
-      (put-text-property (line-beginning-position) (point)
-			 'local-map eww-textarea-map)
+      (add-text-properties (line-beginning-position) (point)
+			   `(inhibit-read-only t
+			     local-map ,eww-textarea-map
+			     ;; Enable the major mode keymap on newlines.
+			     rear-nonsticky (local-map)))
       (forward-line 1))
     (put-text-property start (point) 'eww-form
 		       (list :eww-form eww-form
 			     :value value
 			     :type "textarea"
-			     :name (dom-attr dom 'name)))))
+			     :name (dom-attr dom 'name)
+			     :lines lines
+			     :width width))))
 
 (defun eww-tag-input (dom)
   (let ((type (downcase (or (dom-attr dom 'type) "text")))
@@ -1366,7 +1718,7 @@
           (nconc props (list (cons :start start)))
           (setq start (next-single-property-change
                        start 'eww-form nil (point-max)))
-          (nconc props (list (cons :end start))))))))
+          (nconc props (list (cons :end (set-marker (make-marker) start)))))))))
 
 (defun eww-input-value (input)
   (let ((type (plist-get input :type))

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

* bug#28907: 26.0.90; [eww] some problems in input/textarea
  2017-11-10  7:57       ` Katsumi Yamaoka
@ 2017-11-10  8:28         ` Eli Zaretskii
  2017-11-10  9:10           ` Katsumi Yamaoka
  2017-11-14  8:26         ` Katsumi Yamaoka
  1 sibling, 1 reply; 14+ messages in thread
From: Eli Zaretskii @ 2017-11-10  8:28 UTC (permalink / raw)
  To: Katsumi Yamaoka; +Cc: larsi, 28907

> Date: Fri, 10 Nov 2017 16:57:23 +0900
> From: Katsumi Yamaoka <yamaoka@jpl.org>
> Cc: Lars Ingebrigtsen <larsi@gnus.org>, 28907@debbugs.gnu.org
> 
> Some generic editing commands, except for `undo', now almost work
> in input/textarea.  To try writing something in those fields, you
> can use the following two pages:
> 
> <https://html.com/tags/input/#Code_Example>
> <https://html.com/tags/textarea/#Code_Example>
> 
> A patch is below.

You say "almost work" because you are still working on this?  Or is
this patch complete enough to push it?

Anyway, looks like quite a large changeset, almost a new feature.
Should we put it on master or do you think it should be on the release
branch for some reason?

Lars, any comments?

Thanks.





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

* bug#28907: 26.0.90; [eww] some problems in input/textarea
  2017-11-10  8:28         ` Eli Zaretskii
@ 2017-11-10  9:10           ` Katsumi Yamaoka
  0 siblings, 0 replies; 14+ messages in thread
From: Katsumi Yamaoka @ 2017-11-10  9:10 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: larsi, 28907

On Fri, 10 Nov 2017 10:28:52 +0200, Eli Zaretskii wrote:
> You say "almost work" because you are still working on this?  Or is
> this patch complete enough to push it?

It's complete at this time.  Even though there might be some
minor bugs (and they will be likely, maybe), it should be better
than the existing one.

> Anyway, looks like quite a large changeset, almost a new feature.
> Should we put it on master or do you think it should be on the release
> branch for some reason?

I don't want to install it to the release branch so much, as it
is big as you say, and it might break the simpleness of eww.el.
So,

> Lars, any comments?

Regards,





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

* bug#28907: 26.0.90; [eww] some problems in input/textarea
  2017-11-10  7:57       ` Katsumi Yamaoka
  2017-11-10  8:28         ` Eli Zaretskii
@ 2017-11-14  8:26         ` Katsumi Yamaoka
  2017-11-17  8:42           ` Katsumi Yamaoka
  1 sibling, 1 reply; 14+ messages in thread
From: Katsumi Yamaoka @ 2017-11-14  8:26 UTC (permalink / raw)
  To: 28907; +Cc: Lars Ingebrigtsen

On Fri, 10 Nov 2017 16:57:23 +0900, Katsumi Yamaoka wrote:
> Some generic editing commands, except for `undo', now almost work
> in input/textarea.  To try writing something in those fields, you
> can use the following two pages:

> <https://html.com/tags/input/#Code_Example>
> <https://html.com/tags/textarea/#Code_Example>

Here is a revised patch:

<http://www.jpl.org/tmp/eww.el-20171114.patch>





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

* bug#28907: 26.0.90; [eww] some problems in input/textarea
  2017-11-14  8:26         ` Katsumi Yamaoka
@ 2017-11-17  8:42           ` Katsumi Yamaoka
  2017-12-13  8:19             ` Katsumi Yamaoka
  2017-12-27 21:12             ` Lars Ingebrigtsen
  0 siblings, 2 replies; 14+ messages in thread
From: Katsumi Yamaoka @ 2017-11-17  8:42 UTC (permalink / raw)
  To: 28907; +Cc: Lars Ingebrigtsen

On Tue, 14 Nov 2017 17:26:02 +0900, Katsumi Yamaoka wrote:
> On Fri, 10 Nov 2017 16:57:23 +0900, Katsumi Yamaoka wrote:
>> Some generic editing commands, except for `undo', now almost work
>> in input/textarea.  To try writing something in those fields, you
>> can use the following two pages:

>> <https://html.com/tags/input/#Code_Example>
>> <https://html.com/tags/textarea/#Code_Example>

I've implemented `undo' at last.  It is still somewhat buggy, so
I will improve it further.  It's a good brain exercise anyway. ;-)

<http://www.jpl.org/tmp/eww.el-20171117.patch>





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

* bug#28907: 26.0.90; [eww] some problems in input/textarea
  2017-11-17  8:42           ` Katsumi Yamaoka
@ 2017-12-13  8:19             ` Katsumi Yamaoka
  2017-12-15  9:03               ` Eli Zaretskii
  2017-12-27 21:12             ` Lars Ingebrigtsen
  1 sibling, 1 reply; 14+ messages in thread
From: Katsumi Yamaoka @ 2017-12-13  8:19 UTC (permalink / raw)
  To: 28907; +Cc: Lars Ingebrigtsen

On Fri, 17 Nov 2017 17:42:35 +0900, Katsumi Yamaoka wrote:
> Some generic editing commands, except for `undo', now almost work
> in input/textarea.  To try writing something in those fields, you
> can use the following two pages:

> <https://html.com/tags/input/#Code_Example>
> <https://html.com/tags/textarea/#Code_Example>

I've completed the `undo' feature used in eww's editable fields.
It supports undo/redo-switching and works just like Emacs's undo.
The last (hopefully) patch containing changelog entries is here:

<http://www.jpl.org/tmp/eww.el-20171213.patch>

I would like to apply it to the emacs trunk if it is acceptable.

Thanks.





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

* bug#28907: 26.0.90; [eww] some problems in input/textarea
  2017-12-13  8:19             ` Katsumi Yamaoka
@ 2017-12-15  9:03               ` Eli Zaretskii
  2017-12-15  9:58                 ` Katsumi Yamaoka
  0 siblings, 1 reply; 14+ messages in thread
From: Eli Zaretskii @ 2017-12-15  9:03 UTC (permalink / raw)
  To: Katsumi Yamaoka; +Cc: larsi, 28907

> Date: Wed, 13 Dec 2017 17:19:53 +0900
> From: Katsumi Yamaoka <yamaoka@jpl.org>
> Cc: Lars Ingebrigtsen <larsi@gnus.org>
> 
> On Fri, 17 Nov 2017 17:42:35 +0900, Katsumi Yamaoka wrote:
> > Some generic editing commands, except for `undo', now almost work
> > in input/textarea.  To try writing something in those fields, you
> > can use the following two pages:
> 
> > <https://html.com/tags/input/#Code_Example>
> > <https://html.com/tags/textarea/#Code_Example>
> 
> I've completed the `undo' feature used in eww's editable fields.
> It supports undo/redo-switching and works just like Emacs's undo.
> The last (hopefully) patch containing changelog entries is here:
> 
> <http://www.jpl.org/tmp/eww.el-20171213.patch>
> 
> I would like to apply it to the emacs trunk if it is acceptable.

Looks good to me, thanks.

Does this implement new user-level features, or just fix bugs?  In the
former case, a NEWS entry describing user-visible changes would be
appropriate.





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

* bug#28907: 26.0.90; [eww] some problems in input/textarea
  2017-12-15  9:03               ` Eli Zaretskii
@ 2017-12-15  9:58                 ` Katsumi Yamaoka
  0 siblings, 0 replies; 14+ messages in thread
From: Katsumi Yamaoka @ 2017-12-15  9:58 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: larsi, 28907

On Fri, 15 Dec 2017 11:03:59 +0200, Eli Zaretskii wrote:
> Does this implement new user-level features, or just fix bugs?  In the
> former case, a NEWS entry describing user-visible changes would be
> appropriate.

Well, I think we can say it's a bug fix because it enables users
to use some common editing commands as usual.  An inlined editable
field in eww is very special, never seen before (that is why I
was motivated to improve it :).  So, what should have been
mentioned would be it in NEWS.25, I think.





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

* bug#28907: 26.0.90; [eww] some problems in input/textarea
  2017-11-17  8:42           ` Katsumi Yamaoka
  2017-12-13  8:19             ` Katsumi Yamaoka
@ 2017-12-27 21:12             ` Lars Ingebrigtsen
  2018-04-12 22:30               ` Lars Ingebrigtsen
  1 sibling, 1 reply; 14+ messages in thread
From: Lars Ingebrigtsen @ 2017-12-27 21:12 UTC (permalink / raw)
  To: Katsumi Yamaoka; +Cc: 28907

Katsumi Yamaoka <yamaoka@jpl.org> writes:

> I've implemented `undo' at last.  It is still somewhat buggy, so
> I will improve it further.  It's a good brain exercise anyway. ;-)

Thanks for fixing this.  :-)

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





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

* bug#28907: 26.0.90; [eww] some problems in input/textarea
  2017-12-27 21:12             ` Lars Ingebrigtsen
@ 2018-04-12 22:30               ` Lars Ingebrigtsen
  0 siblings, 0 replies; 14+ messages in thread
From: Lars Ingebrigtsen @ 2018-04-12 22:30 UTC (permalink / raw)
  To: Katsumi Yamaoka; +Cc: 28907

Lars Ingebrigtsen <larsi@gnus.org> writes:

> Katsumi Yamaoka <yamaoka@jpl.org> writes:
>
>> I've implemented `undo' at last.  It is still somewhat buggy, so
>> I will improve it further.  It's a good brain exercise anyway. ;-)
>
> Thanks for fixing this.  :-)

And I'm closing this bug report.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





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

end of thread, other threads:[~2018-04-12 22:30 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-20  8:39 bug#28907: 26.0.90; [eww] some problems in input/textarea Katsumi Yamaoka
2017-10-27 13:31 ` Eli Zaretskii
2017-10-29 23:30   ` Katsumi Yamaoka
2017-11-02  7:39     ` Katsumi Yamaoka
2017-11-10  7:57       ` Katsumi Yamaoka
2017-11-10  8:28         ` Eli Zaretskii
2017-11-10  9:10           ` Katsumi Yamaoka
2017-11-14  8:26         ` Katsumi Yamaoka
2017-11-17  8:42           ` Katsumi Yamaoka
2017-12-13  8:19             ` Katsumi Yamaoka
2017-12-15  9:03               ` Eli Zaretskii
2017-12-15  9:58                 ` Katsumi Yamaoka
2017-12-27 21:12             ` Lars Ingebrigtsen
2018-04-12 22:30               ` Lars Ingebrigtsen

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).