;;; ewb.el --- Emacs Web Browser ; M ;E B ; W ;; Copyright (C) 2002 Patware Unc. ;; Author: Patrick Anderson ;; Keywords: browser, web, net ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; Commentary: ;; type C-h m for keystroke help ;; sites that kind of work: emacswiki.org, google.com, slashdot.org ;; sites that don't work: patware.freeshell.org, sf.net ;; latest at http://patware.freeshell.org/emacs/ewb.el ;; Version: -.2a --- removed referer string. ;; Version: -.2 --- sending referer. changed version numbering. ewb-href now accepts . need to move to state-machine parser. ;; Version: -.3 --- prefix arg or file extensions suppress formatting. write bookmarks to file, customizeable ;; Version: -.4 --- added ewb-revert [(g)], minibuffer state messages, display ewb-current-url above header, mouse-face, help-echo ;; Version: -.5 --- first alpha. ;; Installation: ;; (autoload 'ewb "ewb" "emacs web browser" t) ;put in your .emacs ;; type M-x eval-buffer RET then M-x ewb RET to try it now ;; M-x customize-variable RET browse-url-browser-function to make ewb your default browser. ;; goals: ;; handle form data (rfc 2616) ;; asynchronous operation ;; look at ;; display bold, italics ;; turn into a link (defgroup ewb nil "emacs web browser" :group 'hypermedia) (defcustom ewb-suppressed-extensions "\.el$\\|\.txt$" "documents with these extensions won't be parsed.") (defcustom ewb-bookmark-file "~/notebook/emacs/.ewb.bookmarks" "bookmark file" :group 'ewb) (defcustom ewb-history-file "~/notebook/emacs/.ewb.history" "history file" :group 'ewb) ;................................................................................ (defvar ewb-href "<[aA][^>]*\\(?:[hH][rR][eE][fF]\\|[nN][aA][mM][eE]\\)=\"?\\([^\">]+\\)[^>]*>") (defvar ewb-history nil) (defvar ewb-current-host nil) (defvar ewb-current-dir nil) (defvar ewb-current-url nil) (defvar ewb-mode-map (make-sparse-keymap)) (define-key ewb-mode-map [(b)] 'ewb-bookmarks) (defun ewb-bookmarks () (interactive) (find-file ewb-bookmark-file)) (define-key ewb-mode-map [(a)] '(lambda () (interactive) (write-region (concat ewb-current-url "\n") nil ewb-bookmark-file t))) (define-key ewb-mode-map [(o)] 'ewb) (define-key ewb-mode-map [(g)] 'ewb-revert) (defun ewb-revert (&optional raw) (interactive "P") (ewb ewb-current-url raw) (setq ewb-history (cdr ewb-history))) (define-key ewb-mode-map [(9)] 'ewb-next) (defun ewb-next () "jump to next link" (interactive) (re-search-forward ewb-href) (message (match-string 1))) (define-key ewb-mode-map [(shift 9)] 'ewb-prev) (defun ewb-prev () "jump to prev link" (interactive) (re-search-backward ewb-href) (message (match-string 1))) (define-key ewb-mode-map [(13)] 'ewb-follow) (defun ewb-follow (&optional raw) "follow this link" (interactive "P") (re-search-backward ewb-href) (ewb-parse-url (match-string 1) 1 raw)) (define-key ewb-mode-map [(mouse-2)] 'ewb-follow-mouse) (defun ewb-follow-mouse (event &optional raw) (interactive "e\nP") (goto-char (posn-point (event-end event))) (ewb-follow raw)) (define-key ewb-mode-map [(s)] 'ewb-search) (defun ewb-search (str) "use google" (interactive "sFor: ") (ewb (concat "www.google.com/search?q=" (dired-replace-in-string " " "+" str)))) (define-key ewb-mode-map [(q)] 'bury-buffer) (define-key ewb-mode-map " " 'scroll-up) (define-key ewb-mode-map [(u)] 'scroll-down) (define-key ewb-mode-map [(h)] '(lambda () (interactive) (mapcar 'print ewb-history))) (define-key ewb-mode-map [(U)] 'ewb-back) (defun ewb-back (&optional raw) "go back in history" (interactive "P") (if ewb-history (progn (setq ewb-history (cdr ewb-history)) (let ((cur (car ewb-history))) (setq ewb-history (cdr ewb-history)) ;remove self, since ewb-get adds (ewb cur raw))))) (defun ewb-mode () "emacs web browser mode. \\{ewb-mode-map}" (interactive) (kill-all-local-variables) (use-local-map ewb-mode-map) (setq mode-name "ewb") (setq major-mode 'ewb-mode) (add-to-invisibility-spec 'ewb) ; (make-local-variable 'font-lock-defaults) ; (setq font-lock-defaults '(ewb-mode-font-lock-keywords t nil nil nil)) (run-hooks 'ewb-mode-hook)) (defun ewb-filter (proc string) "string is typically 1k" (with-current-buffer (process-buffer proc) (save-excursion (goto-char (point-max)) (insert string)))) (defun ewb-sentinel (process event) (message "formatting...") (save-excursion (goto-char (point-min)) (let ((href-end)) (while (setq href-end (re-search-forward ewb-href nil t)) (let* ((href-overlay (make-overlay (match-beginning 0) href-end)) (url (match-string 1)) (link-end (re-search-forward "" nil t)) (link-overlay (make-overlay href-end (- link-end 4)))) (overlay-put href-overlay 'invisible 'ewb) (overlay-put href-overlay 'intangible 'ewb) (overlay-put link-overlay 'face 'font-lock-keyword-face) (overlay-put link-overlay 'mouse-face 'highlight) (overlay-put link-overlay 'help-echo url)) (replace-match "" t t))) ;; (goto-char (point-min)) ;; (while (setq end (re-search-forward (concat ;; "\\(<[bB][rR]>\\|<[pP]>\\|<[hH][rR]>\\|\\)" ;; "\\|\\(&[nN][bB][sS][pP];\\|[ ]+\\)" ;; "\\|\\(]*>\\|&[a-zA-Z0-9#]+;\\|\r\\)") ;; nil t)) ;; (replace-match "\n" t t nil 1) ;; (replace-match " " t t nil 2) ;; (replace-match "" t t nil 3)) (goto-char (point-min)) (while (setq end (re-search-forward "<[bB][rR]>\\|<[pP]>\\|<[hH][rR]>\\|" nil t)) (replace-match "\n" t t)) (goto-char (point-min)) (while (setq end (re-search-forward "&[nN][bB][sS][pP];\\|[ ]+" nil t)) (replace-match " " t t)) (goto-char (point-min)) (while (setq end (re-search-forward "]*>\\|&[a-zA-Z0-9#]+;\\|\r" nil t)) (replace-match "" t t)) ) (message "done.")) (defun ewb (url &optional raw) "emacs web browser. \\{ewb-mode-map}" (interactive "sURL: \nP") (ewb-parse-url url nil raw)) (defun ewb-parse-url (url followed &optional raw) " a 'followed' link has a looser file spec, tighter host spec: a host must begin with (http:)?// a link such as \"a.b\" specifies file or directory. an 'interactive' url has a tighter 'file' spec, looser host spec: a host might not begin with (http:)?// a link such as \"a.b\" specifies a host." (if followed (string-match "\\(http:\\)?\\(//[^/\n]+\\)?\\(/\\)?\\(\\(?:[^/\n]+/\\)*\\)\\(.*\\)" url) ; 1=protocol?, 2=//host? 3=/?, 4=dir/* 5=file? (string-match "\\(http://\\)?\\([^/\n]+\\)\\(/\\)?\\(\\(?:[^/\n]+/\\)*\\)\\(.*\\)" url)) ; 1=protocol//?, 2=host 3=/?, 4=dir/* 5=file? (let* ((host (match-string 2 url)) (dir (match-string 4 url)) (file (match-string 5 url))) (if host (progn (string-match "\\(//\\)?\\(.*\\)" host) (setq host (match-string 2 host)))) ;just match the 2nd chunk (ewb-get host dir file raw))) (defun ewb-get (host dir file &optional raw) ;port (let* ((port 80) (buf (get-buffer-create "*Emacs Web Browser*")) (ewb-connection) (referer ewb-current-url)) (if host (progn (setq ewb-current-host host) (setq ewb-current-dir dir))) ;force this (generally to clear) (if dir (if (not (= 0 (length dir))) (setq ewb-current-dir dir))) (setq ewb-current-url (concat "http://" ewb-current-host "/" ewb-current-dir file)) (setq ewb-history (cons ewb-current-url ewb-history)) (message (concat "downloading " ewb-current-url "...")) (setq ewb-connection (open-network-stream "ewb-connection" buf ewb-current-host port)) (switch-to-buffer buf) (erase-buffer) (ewb-mode) (insert (concat ewb-current-url "\n")) (overlay-put (make-overlay 1 (+ (length ewb-current-url) 1)) 'face 'font-lock-constant-face) (set-process-filter ewb-connection 'ewb-filter) (if (and (null raw) (not (string-match ewb-suppressed-extensions file))) (set-process-sentinel ewb-connection 'ewb-sentinel)) ; (process-send-string ewb-connection (concat "GET /" ewb-current-dir file " HTTP/1.0 " referer "\n\n")))) (process-send-string ewb-connection (concat "GET /" ewb-current-dir file " HTTP/1.0\n\n")))) ; (process-send-string ewb-connection (concat "GET /" ewb-current-dir file " HTTP/1.1\r\n\r\n")) (provide 'ewb) ;;; ewb.el ends here