]> code.delx.au - gnu-emacs/blobdiff - lisp/net/shr.el
; Remove obsolete comment in tramp.el
[gnu-emacs] / lisp / net / shr.el
index 06a75a46bf20d9e27667b91abbe34bb2d45eeecb..58deaea6f53cf75e283fe260711b362630f1108a 100644 (file)
@@ -57,7 +57,7 @@ fit these criteria."
   :group 'shr
   :type '(choice (const nil) regexp))
 
-(defcustom shr-use-fonts nil
+(defcustom shr-use-fonts t
   "If non-nil, use proportional fonts for text."
   :version "25.1"
   :group 'shr
@@ -152,11 +152,11 @@ cid: URL as the argument.")
 (defvar shr-ignore-cache nil)
 (defvar shr-external-rendering-functions nil)
 (defvar shr-target-id nil)
-(defvar shr-inhibit-decoration nil)
 (defvar shr-table-separator-length 1)
 (defvar shr-table-separator-pixel-width 0)
 (defvar shr-table-id nil)
 (defvar shr-current-font nil)
+(defvar shr-internal-bullet nil)
 
 (defvar shr-map
   (let ((map (make-sparse-keymap)))
@@ -177,7 +177,7 @@ cid: URL as the argument.")
 
 ;; Public functions and commands.
 (declare-function libxml-parse-html-region "xml.c"
-                 (start end &optional base-url))
+                 (start end &optional base-url discard-comments))
 
 (defun shr-render-buffer (buffer)
   "Display the HTML rendering of the current buffer."
@@ -216,14 +216,35 @@ DOM should be a parse tree as generated by
        (shr-table-id 0)
        (shr-warning nil)
        (shr-table-separator-pixel-width (shr-string-pixel-width "-"))
+       (shr-internal-bullet (cons shr-bullet
+                                  (shr-string-pixel-width shr-bullet)))
        (shr-internal-width (or (and shr-width
                                     (if (not shr-use-fonts)
                                         shr-width
                                       (* shr-width (frame-char-width))))
+                                ;; We need to adjust the available
+                                ;; width for when the user disables
+                                ;; the fringes, which will cause the
+                                ;; display engine usurp one column for
+                                ;; the continuation glyph.
                                (if (not shr-use-fonts)
-                                   (- (window-width) 2)
-                                 (- (window-pixel-width)
-                                    (* (frame-fringe-width) 2))))))
+                                   (- (window-body-width) 1
+                                       (if (and (null shr-width)
+                                                (or (zerop
+                                                     (fringe-columns 'right))
+                                                    (zerop
+                                                     (fringe-columns 'left))))
+                                           0
+                                         1))
+                                 (- (window-body-width nil t)
+                                     (* 2 (frame-char-width))
+                                     (if (and (null shr-width)
+                                              (or (zerop
+                                                   (fringe-columns 'right))
+                                                  (zerop
+                                                   (fringe-columns 'left))))
+                                         (* (frame-char-width) 2)
+                                       0))))))
     (shr-descend dom)
     (shr-fill-lines start (point))
     (shr-remove-trailing-whitespace start (point))
@@ -437,8 +458,18 @@ size, and full-buffer size."
     (with-temp-buffer
       (let ((shr-indentation 0)
            (shr-start nil)
-           (shr-internal-width (- (window-pixel-width)
-                                  (* (frame-fringe-width) 2))))
+           (shr-internal-width (- (window-body-width nil t)
+                                   (* 2 (frame-char-width))
+                                   ;; Adjust the window width for when
+                                   ;; the user disables the fringes,
+                                   ;; which causes the display engine
+                                   ;; to usurp one column for the
+                                   ;; continuation glyph.
+                                   (if (and (null shr-width)
+                                            (or (zerop (fringe-columns 'right))
+                                                (zerop (fringe-columns 'left))))
+                                       (* (frame-char-width) 2)
+                                     0))))
        (shr-insert text)
        (buffer-string)))))
 
@@ -492,33 +523,46 @@ size, and full-buffer size."
     (insert "\n"))
   (cond
    ((eq shr-folding-mode 'none)
-    (insert text))
-   (t
-    (when (and (string-match "\\`[ \t\n\r ]" text)
-              (not (bolp))
-              (not (eq (char-after (1- (point))) ? )))
-      (insert " "))
-    (let ((start (point))
-         (bolp (bolp)))
+    (let ((start (point)))
       (insert text)
       (save-restriction
        (narrow-to-region start (point))
-       (goto-char start)
-       (when (looking-at "[ \t\n\r ]+")
+       ;; Remove soft hyphens.
+       (goto-char (point-min))
+       (while (search-forward "­" nil t)
          (replace-match "" t t))
-       (while (re-search-forward "[ \t\n\r ]+" nil t)
-         (replace-match " " t t))
-       (goto-char (point-max)))
-      ;; We may have removed everything we inserted if if was just
-      ;; spaces.
-      (unless (= start (point))
-       ;; Mark all lines that should possibly be folded afterwards.
-       (when bolp
-         (shr-mark-fill start))
-       (when shr-use-fonts
-         (add-face-text-property start (point)
-                                 (or shr-current-font 'variable-pitch)
-                                 t)))))))
+       (goto-char (point-max)))))
+   (t
+    (let ((font-start (point)))
+      (when (and (string-match "\\`[ \t\n\r ]" text)
+                (not (bolp))
+                (not (eq (char-after (1- (point))) ? )))
+       (insert " "))
+      (let ((start (point))
+           (bolp (bolp)))
+       (insert text)
+       (save-restriction
+         (narrow-to-region start (point))
+         (goto-char start)
+         (when (looking-at "[ \t\n\r ]+")
+           (replace-match "" t t))
+         (while (re-search-forward "[ \t\n\r ]+" nil t)
+           (replace-match " " t t))
+         ;; Remove soft hyphens.
+         (goto-char (point-min))
+         (while (search-forward "­" nil t)
+           (replace-match "" t t))
+         (goto-char (point-max)))
+       ;; We may have removed everything we inserted if if was just
+       ;; spaces.
+       (unless (= font-start (point))
+         ;; Mark all lines that should possibly be folded afterwards.
+         (when bolp
+           (shr-mark-fill start))
+         (when shr-use-fonts
+           (put-text-property font-start (point)
+                              'face
+                              (or shr-current-font 'variable-pitch)))))))))
 
 (defun shr-fill-lines (start end)
   (if (<= shr-internal-width 0)
@@ -549,7 +593,12 @@ size, and full-buffer size."
                       (point) 'shr-continuation-indentation))
        start)
     (put-text-property (point) (1+ (point)) 'shr-indentation nil)
-    (shr-indent)
+    (let ((face (get-text-property (point) 'face))
+         (background-start (point)))
+      (shr-indent)
+      (when face
+       (put-text-property background-start (point) 'face
+                          `,(shr-face-background face))))
     (setq start (point))
     (setq shr-indentation (or continuation shr-indentation))
     (shr-vertical-motion shr-internal-width)
@@ -569,8 +618,13 @@ size, and full-buffer size."
       ;; Success; continue.
       (when (= (preceding-char) ?\s)
        (delete-char -1))
-      (insert "\n")
-      (shr-indent)
+      (let ((face (get-text-property (point) 'face))
+           (background-start (point)))
+       (insert "\n")
+       (shr-indent)
+       (when face
+         (put-text-property background-start (point) 'face
+                            `,(shr-face-background face))))
       (setq start (point))
       (shr-vertical-motion shr-internal-width)
       (when (looking-at " $")
@@ -595,7 +649,9 @@ size, and full-buffer size."
        ;; There's no breakable point, so we give it up.
        (let (found)
          (goto-char bp)
-         (unless shr-kinsoku-shorten
+          ;; Don't overflow the window edge, even if
+          ;; shr-kinsoku-shorten is nil.
+         (unless (or shr-kinsoku-shorten (null shr-width))
            (while (setq found (re-search-forward
                                "\\(\\c>\\)\\| \\|\\c<\\|\\c|"
                                (line-end-position) 'move)))
@@ -607,9 +663,12 @@ size, and full-buffer size."
        ;; Don't put kinsoku-bol characters at the beginning of a line,
        ;; or kinsoku-eol characters at the end of a line.
        (cond
-       (shr-kinsoku-shorten
+        ;; Don't overflow the window edge, even if shr-kinsoku-shorten
+        ;; is nil.
+       ((or shr-kinsoku-shorten (null shr-width))
         (while (and (not (memq (preceding-char) (list ?\C-@ ?\n ? )))
-                    (shr-char-kinsoku-eol-p (preceding-char)))
+                    (or (shr-char-kinsoku-eol-p (preceding-char))
+                         (shr-char-kinsoku-bol-p (following-char))))
           (backward-char 1))
         (when (setq failed (<= (point) start))
           ;; There's no breakable point that doesn't violate kinsoku,
@@ -683,6 +742,9 @@ size, and full-buffer size."
          shr-base))
   (when (zerop (length url))
     (setq url nil))
+  ;; Strip leading whitespace
+  (and url (string-match "\\`\\s-+" url)
+       (setq url (substring url (match-end 0))))
   (cond ((or (not url)
             (not base)
             (string-match "\\`[a-z]*:" url))
@@ -708,23 +770,32 @@ size, and full-buffer size."
 
 (defun shr-ensure-paragraph ()
   (unless (bobp)
-    (if (<= (current-column) shr-indentation)
-       (unless (save-excursion
-                 (forward-line -1)
-                 (looking-at " *$"))
-         (insert "\n"))
-      (if (save-excursion
-           (beginning-of-line)
-           ;; If the current line is totally blank, and doesn't even
-           ;; have any face properties set, then delete the blank
-           ;; space.
-           (and (looking-at " *$")
-                (not (get-text-property (point) 'face))
-                (not (= (next-single-property-change (point) 'face nil
-                                                     (line-end-position))
-                        (line-end-position)))))
-         (delete-region (match-beginning 0) (match-end 0))
-       (insert "\n\n")))))
+    (let ((prefix (get-text-property (line-beginning-position)
+                                    'shr-prefix-length)))
+      (cond
+       ((and (bolp)
+            (save-excursion
+              (forward-line -1)
+              (looking-at " *$")))
+       ;; We're already at a new paragraph; do nothing.
+       )
+       ((and prefix
+            (= prefix (- (point) (line-beginning-position))))
+       ;; Do nothing; we're at the start of a <li>.
+       )
+       ((save-excursion
+         (beginning-of-line)
+         ;; If the current line is totally blank, and doesn't even
+         ;; have any face properties set, then delete the blank
+         ;; space.
+         (and (looking-at " *$")
+              (not (get-text-property (point) 'face))
+              (not (= (next-single-property-change (point) 'face nil
+                                                   (line-end-position))
+                      (line-end-position)))))
+       (delete-region (match-beginning 0) (match-end 0)))
+       (t
+       (insert "\n\n"))))))
 
 (defun shr-indent ()
   (when (> shr-indentation 0)
@@ -745,16 +816,15 @@ size, and full-buffer size."
 ;; blank text at the start of the line, and the newline at the end, to
 ;; avoid ugliness.
 (defun shr-add-font (start end type)
-  (unless shr-inhibit-decoration
-    (save-excursion
-      (goto-char start)
-      (while (< (point) end)
-       (when (bolp)
-         (skip-chars-forward " "))
-       (add-face-text-property (point) (min (line-end-position) end) type t)
-       (if (< (line-end-position) end)
-           (forward-line 1)
-         (goto-char end))))))
+  (save-excursion
+    (goto-char start)
+    (while (< (point) end)
+      (when (bolp)
+        (skip-chars-forward " "))
+      (add-face-text-property (point) (min (line-end-position) end) type t)
+      (if (< (line-end-position) end)
+          (forward-line 1)
+        (goto-char end)))))
 
 (defun shr-mouse-browse-url (ev)
   "Browse the URL under the mouse cursor."
@@ -913,6 +983,9 @@ Return a string with image data."
                (search-forward "\r\n\r\n" nil t))
        (shr-parse-image-data)))))
 
+(declare-function libxml-parse-xml-region "xml.c"
+                 (start end &optional base-url discard-comments))
+
 (defun shr-parse-image-data ()
   (let ((data (buffer-substring (point) (point-max)))
        (content-type
@@ -1003,8 +1076,7 @@ ones, in case fg and bg are nil."
                (shr-color-visible bg fg)))))))
 
 (defun shr-colorize-region (start end fg &optional bg)
-  (when (and (not shr-inhibit-decoration)
-            (or fg bg))
+  (when (and (or fg bg) (>= (display-color-cells) 88))
     (let ((new-colors (shr-color-check fg bg)))
       (when new-colors
        (when fg
@@ -1017,44 +1089,6 @@ ones, in case fg and bg are nil."
                                  t)))
       new-colors)))
 
-(defun shr-expand-newlines (start end color)
-  (save-restriction
-    ;; Skip past all white space at the start and ends.
-    (goto-char start)
-    (skip-chars-forward " \t\n")
-    (beginning-of-line)
-    (setq start (point))
-    (goto-char end)
-    (skip-chars-backward " \t\n")
-    (forward-line 1)
-    (setq end (point))
-    (narrow-to-region start end)
-    (let ((width (shr-buffer-width))
-         column)
-      (goto-char (point-min))
-      (while (not (eobp))
-       (end-of-line)
-       (when (and (< (setq column (current-column)) width)
-                  (< (setq column (shr-previous-newline-padding-width column))
-                     width))
-         (let ((overlay (make-overlay (point) (1+ (point)))))
-           (overlay-put overlay 'before-string
-                        (concat
-                         (mapconcat
-                          (lambda (overlay)
-                            (let ((string (plist-get
-                                           (overlay-properties overlay)
-                                           'before-string)))
-                              (if (not string)
-                                  ""
-                                (overlay-put overlay 'before-string "")
-                                string)))
-                          (overlays-at (point))
-                          "")
-                         (propertize (make-string (- width column) ? )
-                                     'face (list :background color))))))
-       (forward-line 1)))))
-
 (defun shr-previous-newline-padding-width (width)
   (let ((overlays (overlays-at (point)))
        (previous-width 0))
@@ -1168,6 +1202,10 @@ ones, in case fg and bg are nil."
 (defun shr-tag-u (dom)
   (shr-fontize-dom dom 'underline))
 
+(defun shr-tag-tt (dom)
+  (let ((shr-current-font 'default))
+    (shr-generic dom)))
+
 (defun shr-parse-style (style)
   (when style
     (save-match-data
@@ -1208,8 +1246,7 @@ ones, in case fg and bg are nil."
        (shr-ensure-newline)
        (insert " "))
       (put-text-property start (1+ start) 'shr-target-id shr-target-id))
-    (when (and url
-              (not shr-inhibit-decoration))
+    (when url
       (shr-urlify (or shr-start start) (shr-expand-url url) title))))
 
 (defun shr-tag-object (dom)
@@ -1422,13 +1459,16 @@ The preference is a float determined from `shr-prefer-media-type'."
                (prog1
                    (format "%d " shr-list-mode)
                  (setq shr-list-mode (1+ shr-list-mode)))
-             shr-bullet)))
+             (car shr-internal-bullet)))
+          (width (if (numberp shr-list-mode)
+                     (shr-string-pixel-width bullet)
+                   (cdr shr-internal-bullet))))
       (insert bullet)
       (shr-mark-fill start)
-      (let ((shr-indentation (+ shr-indentation
-                               (shr-string-pixel-width bullet))))
+      (let ((shr-indentation (+ shr-indentation width)))
        (put-text-property start (1+ start)
                           'shr-continuation-indentation shr-indentation)
+       (put-text-property start (1+ start) 'shr-prefix-length (length bullet))
        (shr-generic dom)))))
 
 (defun shr-mark-fill (start)
@@ -1451,7 +1491,9 @@ The preference is a float determined from `shr-prefer-media-type'."
   (shr-generic dom))
 
 (defun shr-tag-h1 (dom)
-  (shr-heading dom '(variable-pitch (:height 1.3 :weight bold))))
+  (shr-heading dom (if shr-use-fonts
+                      '(variable-pitch (:height 1.3 :weight bold))
+                    'bold)))
 
 (defun shr-tag-h2 (dom)
   (shr-heading dom 'bold))
@@ -1470,8 +1512,12 @@ The preference is a float determined from `shr-prefer-media-type'."
 
 (defun shr-tag-hr (_dom)
   (shr-ensure-newline)
-  ;; FIXME: Should try to make a line of the required pixel size.
-  (insert (make-string (window-width) shr-hr-line) "\n"))
+  (insert (make-string (if (not shr-use-fonts)
+                          shr-internal-width
+                        (1+ (/ shr-internal-width
+                               shr-table-separator-pixel-width)))
+                      shr-hr-line)
+         "\n"))
 
 (defun shr-tag-title (dom)
   (shr-heading dom 'bold 'underline))
@@ -1667,11 +1713,16 @@ The preference is a float determined from `shr-prefer-media-type'."
              (dolist (line lines)
                (end-of-line)
                (let ((start (point)))
-                 (insert line
-                         (propertize " "
-                                     'display `(space :align-to (,pixel-align))
-                                     'shr-table-indent shr-table-id)
-                         shr-table-vertical-line)
+                 (insert
+                  line
+                  (propertize " "
+                              'display `(space :align-to (,pixel-align))
+                              'face (and (> (length line) 0)
+                                         (shr-face-background
+                                          (get-text-property
+                                           (1- (length line)) 'face line)))
+                              'shr-table-indent shr-table-id)
+                  shr-table-vertical-line)
                  (shr-colorize-region
                   start (1- (point)) (nth 5 column) (nth 6 column)))
                (forward-line 1))
@@ -1692,6 +1743,16 @@ The preference is a float determined from `shr-prefer-media-type'."
     (unless (= start (point))
       (put-text-property start (1+ start) 'shr-table-id shr-table-id))))
 
+(defun shr-face-background (face)
+  (and (consp face)
+       (let ((background nil))
+        (dolist (elem face)
+          (when (and (consp elem)
+                     (eq (car elem) :background))
+            (setq background (cadr elem))))
+        (and background
+             (list :background background)))))
+
 (defun shr-expand-alignments (start end)
   (while (< (setq start (next-single-property-change
                         start 'shr-table-id nil end))
@@ -1748,7 +1809,7 @@ The preference is a float determined from `shr-prefer-media-type'."
          (setq i (1+ i)))))
     (let ((extra (- (apply '+ (append suggested-widths nil))
                    (apply '+ (append widths nil))
-                   (* shr-table-separator-pixel-width (length widths))))
+                   (* shr-table-separator-pixel-width (1+ (length widths)))))
          (expanded-columns 0))
       ;; We have extra, unused space, so divide this space amongst the
       ;; columns.
@@ -1777,7 +1838,6 @@ The preference is a float determined from `shr-prefer-media-type'."
 
 (defun shr-make-table-1 (dom widths &optional fill)
   (let ((trs nil)
-       (shr-inhibit-decoration (not fill))
        (rowspans (make-vector (length widths) 0))
        (colspan-remaining 0)
        colspan-width colspan-count
@@ -2024,8 +2084,4 @@ The preference is a float determined from `shr-prefer-media-type'."
 
 (provide 'shr)
 
-;; Local Variables:
-;; coding: utf-8
-;; End:
-
 ;;; shr.el ends here