[Date Prev][Date Next][Thread Prev][][Date Index][Thread Index]

[REFACTOR] w3m-process-queue memory and redability [PATCH]



I'm submitting the attached patch due to extreme frustration in trying
to debug an issue in page loading and display that are rooted in
functions performed asynchronously by emacs-w3m. It also has the effect
of greatly reducing the memory used / thrashed when performing page
loads.

BACKGROUND: The code base tracks all current asynchronous processes
using the data structure `w3m-process-queue', which is a list whose
elements have a basic structure:

    (cons ,command ,arguments)
    (vector 'w3m-process-object
            ,buffer
            ,process
            ,handlers)))

The final component of each element, "handlers" is itself a vector,
in the form:

    (vector ,buffer ,parent-buffer ,functions nil)

In that vector, "functions" is a list of functions for that particular
asynchronous process to perform. The elements of this final sub-list are
the literal code snippets of the BODY of `w3m-process-do' macro
calls. To save you from looking it up, the spec of that macro is:

    (w3m-process-do (VAR FORM) &rest BODY)

In my testing, a typical single page load will generate a list of at
least eight handlers, copying and re-styling a few hundred lines of elisp
text. Generally, each page load recreates another copy of the same few
hundred lines and adds it to the list. Additionally, the re-styling make
it difficult to read and correspond to the actual elisp as written in
the .el source files.

EXAMPLE:

1] From an emacs-w3m session that has no current asynchronous processes
   active, evaluate the variable `w3m-process-queue'. It should be nil.

2] Load a page that will hang forever, so that you can leisurely observe
   the state of  `w3m-process-queue' when an asynchronous process is
   active. I've been using 'G https://verifiedfacts.org', which hangs
   because the site does not handle https.

3] Evaluate again `w3m-process-queue', and as you scroll through the
   result, don't just note its length, note also how the code has been
   restyled. Each code snippet corresponds to a single BODY predicate of
   a `w3m-process-do' macro call.

4] Now, if you're willing to apply the patch and re-evaluate file
   w3m.el, you can observe the difference in `w3m-process-queue' size
   and content. Perform 'G https://verifiedfacts.org' once again and
   when you re-evaluate the variable, you'll see that the output is
   short, with clear references to handler-functions that can be
   referenced for debugging.

DESCRIPTION: What the patch does is replace the BODY predicate of
`w3m-process-do' macro calls with a single line call to new functions
w3m--foo--handler-function. I also created a function for a huge COND
clause in `w3m-goto-url', just for readability. This is just a
refactoring patch; it does not / should not alter behavior.

FINALLY: In a few hours, I go off-line for three days - Jewish holiday.

-- 
hkp://keys.gnupg.net
CA45 09B5 5351 7C11 A9D1  7286 0036 9E45 1595 8BC0
Index: w3m.el
===================================================================
RCS file: /storage/cvsroot/emacs-w3m/w3m.el,v
retrieving revision 1.1711
diff -b -u -p -r1.1711 w3m.el
--- w3m.el	17 May 2018 04:21:01 -0000	1.1711
+++ w3m.el	18 May 2018 19:27:24 -0000
@@ -5536,26 +5540,7 @@ If the optional argument NO-CACHE is non
 		       (list (prin1-to-string x))))))))
 		arguments)))

-(defun w3m-w3m-dump-extra (url handler)
-  "Retrive headers and contents pointed to by URL"
-  (lexical-let ((url url)
-		(silent w3m-message-silent))
-    (setq w3m-current-url url
-	  url (w3m-url-strip-authinfo url))
-    (w3m-message "Reading %s...%s"
-		 (w3m-url-readable-string url)
-		 (if (and w3m-async-exec (not w3m-process-waited))
-		     (substitute-command-keys "\
- (Type `\\<w3m-mode-map>\\[w3m-process-stop]' to stop asynchronous process)")
-		   ""))
-    (w3m-process-do
-	(success
-	 (w3m-process-start handler
-			    w3m-command
-			    (append w3m-command-arguments
-				    (w3m-w3m-expand-arguments
-				     w3m-dump-head-source-command-arguments)
-				    (list url))))
+(defun w3m--dump-extra--handler-function (url silent)
       (let ((w3m-message-silent silent))
 	(w3m-message "Reading %s...done" (w3m-url-readable-string url))
 	(when success
@@ -5571,7 +5556,26 @@ If the optional argument NO-CACHE is non
 		(delete-region (point-min) (point))
 		(w3m-cache-header url header)
 		(w3m-cache-contents url (current-buffer))
-		(w3m-w3m-parse-header url header)))))))))
+            (w3m-w3m-parse-header url header)))))))
+
+
+(defun w3m-w3m-dump-extra (url handler)
+  "Retrive headers and contents pointed to by URL"
+  (lexical-let ((url url)
+                (silent w3m-message-silent))
+    (setq w3m-current-url url
+          url (w3m-url-strip-authinfo url))
+    (w3m-message "Reading %s...%s"
+      (w3m-url-readable-string url)
+      (if (and w3m-async-exec (not w3m-process-waited))
+        (substitute-command-keys "\n (Type `\\<w3m-mode-map>\\[w3m-process-stop]' to stop asynchronous process)") ""))
+    (w3m-process-do
+      (success (w3m-process-start handler w3m-command
+                 (append w3m-command-arguments
+                    (w3m-w3m-expand-arguments w3m-dump-head-source-command-arguments)
+                    (list url))))
+      (w3m--dump-extra--handler-function url silent))))
+

 (defun w3m-additional-command-arguments (url)
   "Return a list of additional arguments passed to the w3m command.
@@ -5708,19 +5712,8 @@ Third optional CONTENT-TYPE is the Conte
       (setq args (nconc args (list "-header" (concat "Referer: " referer)))))
     args))

-(defun w3m-w3m-retrieve (url no-uncompress no-cache post-data referer handler)
-  "Retrieve web contents pointed to by URL using the external w3m command.
-It will put the retrieved contents into the current buffer.  See
-`w3m-retrieve' for how does it work asynchronously with the arguments."
-  (lexical-let ((url (w3m-w3m-canonicalize-url url))
-		(no-uncompress no-uncompress)
-		(current-buffer (current-buffer))
-		(silent w3m-message-silent))
-    (w3m-process-do-with-temp-buffer
-	(attr (progn
-		(set-buffer-multibyte nil)
-		(w3m-w3m-retrieve-1 url post-data referer no-cache
-				    (or w3m-follow-redirection 0) handler)))
+
+(defun w3m--retrieve--handler-function (url silent no-uncompress current-buffer)
       (setq w3m-http-status (car-safe attr))
       (let ((w3m-message-silent silent))
 	(when attr
@@ -5739,7 +5732,56 @@ It will put the retrieved contents into
 	      (ding)
 	      (w3m-message "Can't decode encoded contents: %s" url)
 	      nil))
-	   (t nil)))))))
+       (t nil)))))
+
+(defun w3m-w3m-retrieve (url no-uncompress no-cache post-data referer handler)
+  "Retrieve web contents pointed to by URL using the external w3m command.
+It will put the retrieved contents into the current buffer.  See
+`w3m-retrieve' for how does it work asynchronously with the arguments."
+  (lexical-let ((url (w3m-w3m-canonicalize-url url))
+                (no-uncompress no-uncompress)
+                (current-buffer (current-buffer))
+                (silent w3m-message-silent))
+    (w3m-process-do-with-temp-buffer
+        (attr (progn
+                (set-buffer-multibyte nil)
+                (w3m-w3m-retrieve-1 url post-data referer no-cache
+                                    (or w3m-follow-redirection 0) handler)))
+        (w3m--retrieve--handler-function url silent no-uncompress current-buffer))))
+
+(defun w3m--retrieve-1--handler-function (url post-data referer no-cache
+                                          counter handler temp-file)
+  (and temp-file
+       (file-exists-p temp-file)
+       (delete-file temp-file))
+  (if (memq (car attr) '(301 302 303 304 305 306 307))
+      (if (zerop counter)
+          ;; Redirect counter exceeds `w3m-follow-redirection'.
+          'redirection-exceeded
+        ;; Follow redirection.
+        (erase-buffer)
+        (unless (and post-data
+                     (cond
+                      ((memq (car attr) '(301 302))
+                       (if w3m-redirect-with-get
+                           (setq post-data nil)
+                         (not (y-or-n-p
+                               (format "Send POST data to `%s'?" url)))))
+                      ((eq (car attr) 303) ; => See Other
+                       (setq post-data nil))
+                      ((eq (car attr) 307) ; => Temporary redirection
+                       (not (y-or-n-p
+                             (format "Send POST data to `%s'?" url))))))
+          (w3m-w3m-retrieve-1
+            (nth 6 attr) post-data referer no-cache (1- counter) handler)))
+    (if (and (eq (car attr) 406)
+             (not (equal url (nth 6 attr))))
+        ;; Attempt to retrieve an alternative url.
+        (progn
+          (erase-buffer)
+          (w3m-w3m-retrieve-1 (nth 6 attr) post-data referer no-cache
+                              counter handler))
+      (or (w3m-w3m-onload-redirection attr counter) attr))))

 (defun w3m-w3m-retrieve-1 (url post-data referer no-cache counter handler)
   "A subroutine for `w3m-w3m-retrieve'."
@@ -5785,38 +5827,8 @@ It will put the retrieved contents into
 			   (w3m-w3m-parse-header
 			    url (w3m-cache-request-header url))))
 		    (w3m-w3m-dump-extra url handler)))
-	(and temp-file
-	     (file-exists-p temp-file)
-	     (delete-file temp-file))
-	(if (memq (car attr) '(301 302 303 304 305 306 307))
-	    (if (zerop counter)
-		;; Redirect counter exceeds `w3m-follow-redirection'.
-		'redirection-exceeded
-	      ;; Follow redirection.
-	      (erase-buffer)
-	      (unless (and post-data
-			   (cond
-			    ((memq (car attr) '(301 302))
-			     (if w3m-redirect-with-get
-				 (setq post-data nil)
-			       (not (y-or-n-p
-				     (format "Send POST data to `%s'?" url)))))
-			    ((eq (car attr) 303) ; => See Other
-			     (setq post-data nil))
-			    ((eq (car attr) 307) ; => Temporary redirection
-			     (not (y-or-n-p
-				   (format "Send POST data to `%s'?" url))))))
-		(w3m-w3m-retrieve-1 (nth 6 attr)
-				    post-data referer no-cache
-				    (1- counter) handler)))
-	  (if (and (eq (car attr) 406)
-		   (not (equal url (nth 6 attr))))
-	      ;; Attempt to retrieve an alternative url.
-	      (progn
-		(erase-buffer)
-		(w3m-w3m-retrieve-1 (nth 6 attr) post-data referer no-cache
-				    counter handler))
-	    (or (w3m-w3m-onload-redirection attr counter) attr)))))))
+        (w3m--retrieve-1--handler-function
+           url post-data referer no-cache counter handler temp-file)))))

 (defvar w3m-onload-url nil "Url redirected to by onload.")

@@ -6426,50 +6438,7 @@ to fold them).  Things in textarea won't
   (w3m-message "Rendering...done")
   (w3m-rendering-extract-title))

-(defun w3m-retrieve-and-render (url &optional no-cache charset
-				    post-data referer handler)
-  "Retrieve contents of URL and render them in the current buffer.
-It returns a `w3m-process' object and comes to an end immediately.
-The HANDLER function will be called when rendering is complete.  When
-a new content is retrieved in the buffer, the HANDLER function will be
-called with t as an argument.  Otherwise, it will be called with nil."
-  (when (and w3m-clear-display-while-reading
-	     (get-buffer-window (current-buffer) 'visible)
-	     (not (string-match "\\`about:" url)))
-    ;; Clear the current display while reading a new page.
-    (set-window-hscroll nil 0)
-    (let ((inhibit-read-only t))
-      (erase-buffer)
-      (insert-char ?\n (/ (window-height) 2))
-      (insert-char ?  (max 0 (/ (- (window-width) (length url) 11) 2)))
-      (insert "Reading " url "...")
-      (sit-for 0)))
-  (unless (and w3m-current-ssl
-	       w3m-confirm-leaving-secure-page
-	       ;; Permit leaving safe pages without confirmation for
-	       ;; several safe commands.  For more detail of
-	       ;; definition of safe commands, see the thread
-	       ;; beginning at [emacs-w3m:09767].
-	       (not
-		(or (memq this-command
-			  '(w3m
-			    w3m-goto-url w3m-redisplay-this-page
-			    w3m-reload-this-page w3m-history
-			    w3m-view-next-page w3m-view-previous-page
-			    w3m-view-header w3m-view-source))
-		    (string-match "\\`\\(?:ht\\|f\\)tps://" url)
-		    (prog1
-			(y-or-n-p "You are leaving secure page.  Continue? ")
-		      (message nil)))))
-    (lexical-let ((url (w3m-url-strip-fragment url))
-		  (charset charset)
-		  (page-buffer (current-buffer))
-		  (arrival-time (current-time))
-		  (silent w3m-message-silent))
-      (w3m-process-do-with-temp-buffer
-	  (type (progn
-		  (w3m-clear-local-variables)
-		  (w3m-retrieve url nil no-cache post-data referer handler)))
+(defun w3m--retrieve-and-render--handler-function (url silent page-buffer arrival-time charset)
 	(when w3m-onload-url
 	      (setq url w3m-onload-url
 		    w3m-onload-url nil))
@@ -6478,8 +6447,7 @@ called with t as an argument.  Otherwise
 	    (setq url (w3m-url-strip-authinfo url))
 	    (if type
 		(if (string= type "X-w3m-error/redirection")
-		    (when (w3m-show-redirection-error-information
-			   url page-buffer)
+              (when (w3m-show-redirection-error-information url page-buffer)
 		      (w3m-arrived-add url nil (current-time) (current-time))
 		      (w3m-message "Cannot retrieve URL: %s" url))
 		  (let ((modified-time (w3m-last-modified url)))
@@ -6494,10 +6462,8 @@ called with t as an argument.  Otherwise
 			(setf (w3m-arrived-last-modified real)
 			      (w3m-arrived-last-modified url))
 			(setq url real)))
-		    (prog1 (w3m-create-page
-			    url
-			    (or (w3m-arrived-content-type url)
-				type)
+              (prog1 (w3m-create-page url
+                       (or (w3m-arrived-content-type url) type)
 			    (or charset
 				(w3m-arrived-content-charset url)
 				(w3m-content-charset url))
@@ -6515,14 +6481,9 @@ called with t as an argument.  Otherwise
 		      (zone-call 'zone-pgm-dissolve 1))
 		    (erase-buffer)
 		    (insert-char ?\n (/ (window-height) 2))
-		    (insert-char ?  (max 0 (/ (- (window-width)
-						 (length url) 15)
-					      2)))
+              (insert-char ?  (max 0 (/ (- (window-width) (length url) 15) 2)))
 		    (insert "Reading " url " ")
-		    (put-text-property (point) (progn
-						 (insert "failed!")
-						 (point))
-				       'face 'w3m-error)
+              (put-text-property (point) (progn (insert "failed!") (point)) 'face 'w3m-error)
 		    (setq w3m-current-url url
 			  w3m-current-title "Fail"))))
 	      (w3m-arrived-add url nil (current-time) (current-time))
@@ -6542,7 +6503,51 @@ called with t as an argument.  Otherwise
 				  w3m-process-exit-status))
 			 (w3m-http-status
 			  (format " (http status: %s)" w3m-http-status))
-			 (t ""))))))))))))
+                   (t "")))))))))
+
+(defun w3m-retrieve-and-render (url &optional no-cache charset
+                                    post-data referer handler)
+  "Retrieve contents of URL and render them in the current buffer.
+It returns a `w3m-process' object and comes to an end immediately.
+The HANDLER function will be called when rendering is complete.  When
+a new content is retrieved in the buffer, the HANDLER function will be
+called with t as an argument.  Otherwise, it will be called with nil."
+  (when (and w3m-clear-display-while-reading
+             (get-buffer-window (current-buffer) 'visible)
+             (not (string-match "\\`about:" url)))
+    ;; Clear the current display while reading a new page.
+    (set-window-hscroll nil 0)
+    (let ((inhibit-read-only t))
+      (erase-buffer)
+      (w3m-display-progress-message url)))
+  (unless (and w3m-current-ssl
+               w3m-confirm-leaving-secure-page
+               ;; Permit leaving safe pages without confirmation for
+               ;; several safe commands.  For more detail of
+               ;; definition of safe commands, see the thread
+               ;; beginning at [emacs-w3m:09767].
+               (not
+                (or (memq this-command
+                          '(w3m
+                            w3m-goto-url w3m-redisplay-this-page
+                            w3m-reload-this-page w3m-history
+                            w3m-view-next-page w3m-view-previous-page
+                            w3m-view-header w3m-view-source))
+                    (string-match "\\`\\(?:ht\\|f\\)tps://" url)
+                    (prog1
+                        (y-or-n-p "You are leaving secure page.  Continue? ")
+                      (message nil)))))
+    (lexical-let ((url (w3m-url-strip-fragment url))
+                  (charset charset)
+                  (page-buffer (current-buffer))
+                  (arrival-time (current-time))
+                  (silent w3m-message-silent))
+      (w3m-process-do-with-temp-buffer
+          (type (progn
+                  (w3m-clear-local-variables)
+                  (w3m-retrieve url nil no-cache post-data referer handler)))
+          (w3m--retrieve-and-render--handler-function url
+            silent page-buffer arrival-time charset)))))

 (defun w3m-show-error-information (url charset page-buffer)
   "Create and prepare the error information."
@@ -9704,109 +9712,98 @@ helpful message is presented and the ope
  `\\<w3m-mode-map>\\[w3m-search-new-session]' to perform a search in a new buffer.
  `\\<w3m-mode-map>\\[w3m-goto-url-new-session]' to visit a URL in a new buffer."))))

-;;;###autoload
-(defun w3m-goto-url (url &optional reload charset post-data referer handler
-			 element no-popup save-pos)
-  "Visit World Wide Web pages in the current buffer.
-
-This is the primitive function of `w3m'.
-
-If the second argument RELOAD is non-nil, reload a content of URL.
-Except that if it is 'redisplay, re-display the page without reloading.
-The third argument CHARSET specifies a charset to be used for decoding
-a content.
-The fourth argument POST-DATA should be a string or a cons cell.
-If it is a string, it makes this function request a body as if
-the content-type is \"x-www-form-urlencoded\".  If it is a cons cell,
-the car of a cell is used as the content-type and the cdr of a cell is
-used as the body.
-If the fifth argument REFERER is specified, it is used for a Referer:
-field for this request.
-The remaining HANDLER, ELEMENT[1], NO-POPUP, and SAVE-POS[2] are for
-the internal operations of emacs-w3m.
-You can also use \"quicksearch\" url schemes such as \"gg:emacs\" which
-would search for the term \"emacs\" with the Google search engine.
-See the `w3m-search' function and the variable `w3m-uri-replace-alist'.
-
-Notes for the developers:
-\[1] ELEMENT is a history element which has already been registered in
-the `w3m-history-flat' variable.  It is corresponding to URL to be
-retrieved at this time, not for the url of the current page.

-\[2] SAVE-POS leads this function to save the current emacs-w3m window
-configuration; i.e. to run `w3m-history-store-position'.
-`w3m-history-store-position' should be called in a w3m-mode buffer, so
-this will be convenient if a command that calls this function may be
-invoked in other than a w3m-mode buffer."
-  (interactive
-   (list (unless (w3m--buffer-busy-error)
-	   (w3m-input-url "Open URL in current buffer" nil nil nil
-			  'feeling-searchy 'no-initial))
-	 current-prefix-arg
-	 (w3m-static-if (fboundp 'universal-coding-system-argument)
-	     coding-system-for-read)))
-  (when (and (stringp url)
-	     (not (w3m-interactive-p)))
-    (setq url (w3m-canonicalize-url url)))
-  (set-text-properties 0 (length url) nil url)
-  (unless (or (w3m-url-local-p url)
-	      (string-match "\\`about:" url)
-	      (let ((case-fold-search t))
-		(string-match "\\`mailto:"; url)))
-    (w3m-string-match-url-components url)
-    (setq url (concat (save-match-data
-			(w3m-url-transfer-encode-string
-			 (substring url 0 (match-beginning 8))))
-		      (if (match-beginning 8)
-			  (concat "#" (match-string 9 url))
-			""))))
-  (cond
-   ;; process mailto: protocol
-   ((string-match "\\`mailto:"; url)
-    (w3m-goto-mailto-url url post-data))
-   ;; process ftp: protocol
-   ((and w3m-use-ange-ftp
-	 (string-match "\\`ftps?://" url)
-	 (not (string= "text/html" (w3m-local-content-type url))))
-    (w3m-goto-ftp-url url))
-   ;; find-file directly
-   ((condition-case nil
-	(and (w3m-url-local-p url)
-	     w3m-local-find-file-function
-	     (let ((base-url (w3m-url-strip-fragment url))
-		   (match (car w3m-local-find-file-regexps))
-		   nomatch file)
-	       (and (or (not match)
-			(string-match match base-url))
-		    (not (and (setq nomatch (cdr w3m-local-find-file-regexps))
-			      (string-match nomatch base-url)))
-		    (setq file (w3m-url-to-file-name base-url))
-		    (file-exists-p file)
-		    (not (file-directory-p file))
-		    (prog1
-			t
-		      (funcall (if (functionp w3m-local-find-file-function)
-				   w3m-local-find-file-function
-				 (eval w3m-local-find-file-function))
-			       file)))))
-      (error nil)))
-   ;; process buffer-local url
-   ((w3m-buffer-local-url-p url)
-    (let (file-part fragment-part)
-      (w3m-string-match-url-components url)
-      (setq file-part (concat (match-string 4 url)
-			      (match-string 5 url))
-	    fragment-part (match-string 9 url))
-      (cond
-       ((and (string= file-part "")
-	     fragment-part)
-	(w3m-search-name-anchor fragment-part))
-       ((not (string= file-part ""))
-	(w3m-goto-url (w3m-expand-url (substring url (match-beginning 4))
-				      (concat "file://" default-directory))
-		      reload charset post-data referer handler element))
-       (t (w3m-message "No URL at point")))))
-   ((w3m-url-valid url)
+(defun w3m--goto-url--handler-function (url reload charset post-data referer
+                                        redisplay name reuse-history)
+  (with-current-buffer w3m-current-buffer
+    (setq w3m-current-process nil)
+    (if (not action)
+        (w3m-history-push
+         w3m-current-url
+         (list :title (or w3m-current-title
+                          "<no-title>")))
+      (w3m-string-match-url-components w3m-current-url)
+      (and (match-beginning 8)
+           (setq name (match-string 9 w3m-current-url)))
+      (when (and name
+                 (progn
+                   ;; Redisplay to search an anchor sure.
+                   (sit-for 0)
+                   (w3m-search-name-anchor
+                    name nil
+                    (not (eq action 'cursor-moved)))))
+        (setf (w3m-arrived-time
+               (w3m-url-strip-authinfo orig))
+              (w3m-arrived-time url)))
+      (unless (eq action 'cursor-moved)
+        (if (equal referer "about://history/")
+            ;; Don't sprout a new branch for
+            ;; the existing history element.
+            (let ((w3m-history-reuse-history-elements t))
+              (w3m-history-push
+               w3m-current-url
+               (list :title w3m-current-title))
+              ;; Fix the history position pointers.
+              (when history-position
+                (setcar w3m-history
+                        (w3m-history-regenerate-pointers
+                         history-position))))
+          (let ((w3m-history-reuse-history-elements
+                 reuse-history)
+                (position (when (eq 'reload reuse-history)
+                            (cadar w3m-history))))
+            (w3m-history-push
+             w3m-current-url
+             (list :title w3m-current-title))
+            (when position
+              (w3m-history-set-current position))))
+        (w3m-history-add-properties
+         (list :referer referer
+               :post-data post-data))
+        (unless w3m-toggle-inline-images-permanently
+          (setq w3m-display-inline-images
+                w3m-default-display-inline-images))
+        (when (and w3m-use-form reload)
+          (w3m-form-textarea-files-remove))
+        (cond ((w3m-display-inline-images-p)
+               (and w3m-force-redisplay (sit-for 0))
+               (w3m-toggle-inline-images 'force reload))
+              ((and (w3m-display-graphic-p)
+                    (eq action 'image-page))
+               (and w3m-force-redisplay (sit-for 0))
+               (w3m-toggle-inline-image 'force reload)))))
+    (setq buffer-read-only t)
+    (set-buffer-modified-p nil)
+    (setq list-buffers-directory w3m-current-title)
+    ;; must be `w3m-current-url'
+    (setq default-directory
+          (w3m-current-directory w3m-current-url))
+    (w3m-buffer-name-add-title)
+    (w3m-update-toolbar)
+    (let ((real-url (if (w3m-arrived-p url)
+                        (or (w3m-real-url url) url)
+                      url)))
+      (run-hook-with-args 'w3m-display-functions real-url)
+      (run-hook-with-args 'w3m-display-hook real-url))
+    (w3m-select-buffer-update)
+    (w3m-session-crash-recovery-save)
+    (and w3m-current-url
+         (stringp w3m-current-url)
+         (or (string-match
+              "\\`about://\\(?:header\\|source\\)/"
+              w3m-current-url)
+             (equal (w3m-content-type w3m-current-url)
+                    "text/plain"))
+         (setq truncate-lines nil))
+    ;; restore position must call after hooks for localcgi.
+    (when (or reload redisplay)
+      (w3m-history-restore-position))
+    (w3m-set-buffer-unseen)
+    (w3m-refresh-at-time)))
+
+(defun w3m--goto-url--valid-url (url reload charset post-data referer handler
+                                 element no-popup save-pos)
+  "Main function called by `w3m-goto-url' for handling generic URLS."
     (w3m-buffer-setup)			; Setup buffer.
     (w3m-arrived-setup)			; Setup arrived database.
     (unless no-popup
@@ -9884,7 +9881,7 @@ invoked in other than a w3m-mode buffer.
 				(eq w3m-local-directory-view-method 'w3m-dtree)
 				(string-match "\\`file:///" url))
 		       (setq url (replace-match "about://dtree/" nil nil url)
-			     orig url))
+                orig furl))
 		     ;; Split body and fragments.
 		     (w3m-string-match-url-components url)
 		     (and (match-beginning 8)
@@ -9895,114 +9892,130 @@ invoked in other than a w3m-mode buffer.
 			 (setq url (w3m-url-decode-string url))))
 		     (w3m-process-do
 			 (action
-			  (if (and (not reload)
-				   (not redisplay)
+           (if (and (not reload) (not redisplay)
 				   (stringp w3m-current-url)
 				   (string= url w3m-current-url))
-			      (progn
-				(w3m-refontify-anchor)
-				'cursor-moved)
+             (progn (w3m-refontify-anchor) 'cursor-moved)
 			    (when w3m-name-anchor-from-hist
 			      (w3m-history-plist-put
 			       :name-anchor-hist
-			       (append
-				(list 1 nil)
+                  (append (list 1 nil)
 				(and
 				 (integerp (car w3m-name-anchor-from-hist))
 				 (nthcdr (1+ (car w3m-name-anchor-from-hist))
 					 w3m-name-anchor-from-hist)))))
 			    (setq w3m-name-anchor-from-hist
-				  (plist-get (nthcdr 3 element)
-					     :name-anchor-hist))
+              (plist-get (nthcdr 3 element) :name-anchor-hist))
 			    (setq w3m-current-process
-				  (w3m-retrieve-and-render
-				   orig reload charset
-				   post-data referer handler))))
-		       (with-current-buffer w3m-current-buffer
-			 (setq w3m-current-process nil)
-			 (if (not action)
-			     (w3m-history-push
-			      w3m-current-url
-			      (list :title (or w3m-current-title
-					       "<no-title>")))
-			   (w3m-string-match-url-components w3m-current-url)
-			   (and (match-beginning 8)
-				(setq name (match-string 9 w3m-current-url)))
-			   (when (and name
-				      (progn
-					;; Redisplay to search an anchor sure.
-					(sit-for 0)
-					(w3m-search-name-anchor
-					 name nil
-					 (not (eq action 'cursor-moved)))))
-			     (setf (w3m-arrived-time
-				    (w3m-url-strip-authinfo orig))
-				   (w3m-arrived-time url)))
-			   (unless (eq action 'cursor-moved)
-			     (if (equal referer "about://history/")
-				 ;; Don't sprout a new branch for
-				 ;; the existing history element.
-				 (let ((w3m-history-reuse-history-elements t))
-				   (w3m-history-push
-				    w3m-current-url
-				    (list :title w3m-current-title))
-				   ;; Fix the history position pointers.
-				   (when history-position
-				     (setcar w3m-history
-					     (w3m-history-regenerate-pointers
-					      history-position))))
-			       (let ((w3m-history-reuse-history-elements
-				      reuse-history)
-				     (position (when (eq 'reload reuse-history)
-						 (cadar w3m-history))))
-				 (w3m-history-push
-				  w3m-current-url
-				  (list :title w3m-current-title))
-				 (when position
-				   (w3m-history-set-current position))))
-			     (w3m-history-add-properties
-			      (list :referer referer
-				    :post-data post-data))
-			     (unless w3m-toggle-inline-images-permanently
-			       (setq w3m-display-inline-images
-				     w3m-default-display-inline-images))
-			     (when (and w3m-use-form reload)
-			       (w3m-form-textarea-files-remove))
-			     (cond ((w3m-display-inline-images-p)
-				    (and w3m-force-redisplay (sit-for 0))
-				    (w3m-toggle-inline-images 'force reload))
-				   ((and (w3m-display-graphic-p)
-					 (eq action 'image-page))
-				    (and w3m-force-redisplay (sit-for 0))
-				    (w3m-toggle-inline-image 'force reload)))))
-			 (setq buffer-read-only t)
-			 (set-buffer-modified-p nil)
-			 (setq list-buffers-directory w3m-current-title)
-			 ;; must be `w3m-current-url'
-			 (setq default-directory
-			       (w3m-current-directory w3m-current-url))
-			 (w3m-buffer-name-add-title)
-			 (w3m-update-toolbar)
-			 (let ((real-url (if (w3m-arrived-p url)
-					     (or (w3m-real-url url) url)
-					   url)))
-			   (run-hook-with-args 'w3m-display-functions real-url)
-			   (run-hook-with-args 'w3m-display-hook real-url))
-			 (w3m-select-buffer-update)
-			 (w3m-session-crash-recovery-save)
-			 (and w3m-current-url
-			      (stringp w3m-current-url)
-			      (or (string-match
-				   "\\`about://\\(?:header\\|source\\)/"
-				   w3m-current-url)
-				  (equal (w3m-content-type w3m-current-url)
-					 "text/plain"))
-			      (setq truncate-lines nil))
-			 ;; restore position must call after hooks for localcgi.
-			 (when (or reload redisplay)
-			   (w3m-history-restore-position))
-			 (w3m-set-buffer-unseen)
-			 (w3m-refresh-at-time)))))))
+              (w3m-retrieve-and-render orig reload charset post-data referer handler))))
+          (w3m--goto-url--handler-function url
+            reload charset post-data referer redisplay name reuse-history))))))
+
+;;;###autoload
+(defun w3m-goto-url (url &optional reload charset post-data referer handler
+                         element no-popup save-pos)
+  "Visit World Wide Web pages in the current buffer.
+
+This is the primitive function of `w3m'.
+
+If the second argument RELOAD is non-nil, reload a content of URL.
+Except that if it is 'redisplay, re-display the page without reloading.
+The third argument CHARSET specifies a charset to be used for decoding
+a content.
+The fourth argument POST-DATA should be a string or a cons cell.
+If it is a string, it makes this function request a body as if
+the content-type is \"x-www-form-urlencoded\".  If it is a cons cell,
+the car of a cell is used as the content-type and the cdr of a cell is
+used as the body.
+If the fifth argument REFERER is specified, it is used for a Referer:
+field for this request.
+The remaining HANDLER, ELEMENT[1], NO-POPUP, and SAVE-POS[2] are for
+the internal operations of emacs-w3m.
+You can also use \"quicksearch\" url schemes such as \"gg:emacs\" which
+would search for the term \"emacs\" with the Google search engine.
+See the `w3m-search' function and the variable `w3m-uri-replace-alist'.
+
+Notes for the developers:
+\[1] ELEMENT is a history element which has already been registered in
+the `w3m-history-flat' variable.  It is corresponding to URL to be
+retrieved at this time, not for the url of the current page.
+
+\[2] SAVE-POS leads this function to save the current emacs-w3m window
+configuration; i.e. to run `w3m-history-store-position'.
+`w3m-history-store-position' should be called in a w3m-mode buffer, so
+this will be convenient if a command that calls this function may be
+invoked in other than a w3m-mode buffer."
+  (interactive
+   (list (unless (w3m--buffer-busy-error)
+           (w3m-input-url "Open URL in current buffer" nil nil nil
+                          'feeling-searchy 'no-initial))
+         current-prefix-arg
+         (w3m-static-if (fboundp 'universal-coding-system-argument)
+             coding-system-for-read)))
+  (when (and (stringp url)
+             (not (w3m-interactive-p)))
+    (setq url (w3m-canonicalize-url url)))
+  (set-text-properties 0 (length url) nil url)
+  (unless (or (w3m-url-local-p url)
+              (string-match "\\`about:" url)
+              (let ((case-fold-search t))
+                (string-match "\\`mailto:"; url)))
+    (w3m-string-match-url-components url)
+    (setq url (concat (save-match-data
+                        (w3m-url-transfer-encode-string
+                         (substring url 0 (match-beginning 8))))
+                      (if (match-beginning 8)
+                          (concat "#" (match-string 9 url))
+                        ""))))
+  (cond
+   ;; process mailto: protocol
+   ((string-match "\\`mailto:"; url)
+    (w3m-goto-mailto-url url post-data))
+   ;; process ftp: protocol
+   ((and w3m-use-ange-ftp
+         (string-match "\\`ftps?://" url)
+         (not (string= "text/html" (w3m-local-content-type url))))
+    (w3m-goto-ftp-url url))
+   ;; find-file directly
+   ((condition-case nil
+        (and (w3m-url-local-p url)
+             w3m-local-find-file-function
+             (let ((base-url (w3m-url-strip-fragment url))
+                   (match (car w3m-local-find-file-regexps))
+                   nomatch file)
+               (and (or (not match)
+                        (string-match match base-url))
+                    (not (and (setq nomatch (cdr w3m-local-find-file-regexps))
+                              (string-match nomatch base-url)))
+                    (setq file (w3m-url-to-file-name base-url))
+                    (file-exists-p file)
+                    (not (file-directory-p file))
+                    (prog1
+                        t
+                      (funcall (if (functionp w3m-local-find-file-function)
+                                   w3m-local-find-file-function
+                                 (eval w3m-local-find-file-function))
+                               file)))))
+      (error nil)))
+   ;; process buffer-local url
+   ((w3m-buffer-local-url-p url)
+    (let (file-part fragment-part)
+      (w3m-string-match-url-components url)
+      (setq file-part (concat (match-string 4 url)
+                              (match-string 5 url))
+            fragment-part (match-string 9 url))
+      (cond
+       ((and (string= file-part "")
+             fragment-part)
+        (w3m-search-name-anchor fragment-part))
+       ((not (string= file-part ""))
+        (w3m-goto-url (w3m-expand-url (substring url (match-beginning 4))
+                                      (concat "file://" default-directory))
+                      reload charset post-data referer handler element))
+       (t (w3m-message "No URL at point")))))
+   ((w3m-url-valid url)
+    (w3m--goto-url--valid-url url reload charset post-data referer handler
+                              element no-popup save-pos))
    (t (w3m-message "Invalid URL: %s" url))))

 (defun w3m-current-directory (url)
Index: ChangeLog
===================================================================
RCS file: /storage/cvsroot/emacs-w3m/ChangeLog,v
retrieving revision 1.3668
diff -b -u -p -r1.3668 ChangeLog
--- ChangeLog	17 May 2018 04:21:01 -0000	1.3668
+++ ChangeLog	18 May 2018 19:38:01 -0000
@@ -1,3 +1,14 @@
+2018-05-18  Boruch Baum  <boruch_baum@xxxxxxx>
+
+	* w3m.el (w3m--dump-extra--handler-function)
+	(w3m--retrieve--handler-function, w3m--retrieve-1--handler-function)
+	(defun w3m--retrieve-and-render--handler-function)
+	(w3m--goto-url--handler-function, w3m--goto-url--valid-url): New functions to reduce
+	memory footprint of `w3m-process-queue', aid readability debugging.
+
+	* w3m.el (w3m-w3m-dump-extra, w3m-w3m-retrieve, w3m-w3m-retrieve-1)
+	(w3m-retrieve-and-render, w3m-goto-url): Use the new functions listed above.
+
 2018-05-17  Katsumi Yamaoka  <yamaoka@xxxxxxx>
 
 	Work for mailto urls.