Files
emacs/lisp/emacs-application-framework/app/browser/eaf-browser.el
2022-01-04 15:21:47 +01:00

769 lines
29 KiB
EmacsLisp

;;; eaf-browser.el --- Browser plugins
;; Filename: eaf-browser.el
;; Description: Browser plugins
;; Author: Andy Stewart <lazycat.manatee@gmail.com>
;; Maintainer: Andy Stewart <lazycat.manatee@gmail.com>
;; Copyright (C) 2021, Andy Stewart, all rights reserved.
;; Created: 2021-07-20 22:30:28
;; Version: 0.1
;; Last-Updated: Sat Dec 11 14:47:23 2021 (-0500)
;; By: Mingde (Matthew) Zeng
;; URL: http://www.emacswiki.org/emacs/download/eaf-browser.el
;; Keywords:
;; Compatibility: GNU Emacs 28.0.50
;;
;; Features that might be required by this library:
;;
;;
;;
;;; This file is NOT part of GNU Emacs
;;; License
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
;; Floor, Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; Browser plugins
;;
;;; Installation:
;;
;; Put eaf-browser.el to your load-path.
;; The load-path is usually ~/elisp/.
;; It's set in your ~/.emacs like this:
;; (add-to-list 'load-path (expand-file-name "~/elisp"))
;;
;; And the following to your ~/.emacs startup file.
;;
;; (require 'eaf-browser)
;;
;; No need more.
;;; Customize:
;;
;;
;;
;; All of the above can customize by:
;; M-x customize-group RET eaf-browser RET
;;
;;; Change log:
;;
;; 2021/07/20
;; * First released.
;;
;;; Acknowledgements:
;;
;;
;;
;;; TODO
;;
;;
;;
;;; Require
;;; Code:
(defgroup eaf-browser nil
"The Browser application of Emacs application framework."
:group 'eaf)
(defcustom eaf-browser-search-engines `(("google" . "http://www.google.com/search?ie=utf-8&oe=utf-8&q=%s")
("duckduckgo" . "https://duckduckgo.com/?q=%s")
("bing" . "https://bing.com/search?q=%s"))
"The default search engines offered by EAF.
Each element has the form (NAME . URL).
NAME is a search engine name, as a string.
URL pecifies the url format for the search engine.
It should have a %s as placeholder for search string."
:type '(alist :key-type (string :tag "Search engine name")
:value-type (string :tag "Search engine url")))
(defcustom eaf-browser-default-search-engine "google"
"The default search engine used by `eaf-open-browser' and `eaf-search-it'.
It must defined at `eaf-browser-search-engines'."
:type 'string)
(defcustom eaf-browser-extension-list
'("html" "htm")
"The extension list of browser application."
:type 'cons)
(defcustom eaf-browser-continue-where-left-off nil
"Similar to Chromium's Setting -> On start-up -> Continue where you left off.
If non-nil, all active EAF Browser buffers will be saved before Emacs is killed,
and will re-open them when calling `eaf-browser-restore-buffers' in the future session."
:type 'boolean)
(defcustom eaf-browser-fullscreen-move-cursor-corner nil
"If non-nil, move the mouse cursor to the corner when fullscreen in the browser."
:type 'boolean)
(defcustom eaf-browser-enable-plugin t
"If non-nil, enable QtWebEngine plugins for EAF Browser."
:type 'boolean)
(defcustom eaf-browser-enable-adblocker nil
"If non-nil, enable adblocker for EAF Browser."
:type 'boolean)
(defcustom eaf-browser-enable-autofill nil
"If non-nil, enable autofill password for EAF Browser."
:type 'boolean)
(defcustom eaf-browser-enable-javascript t
"If non-nil, enable javascript for EAF Browser."
:type 'boolean)
(defcustom eaf-browser-enable-scrollbar nil
"If non-nil, enable scroll bar for EAF Browser."
:type 'boolean)
(defcustom eaf-browser-remember-history t
"If non-nil, remember browsing history for EAF Browser.
The history file is stored in .emacs.d/eaf/browser/history/log.txt"
:type 'boolean)
(defcustom eaf-browser-ignore-history-list
'("google.com/search")
"A list of case insensitive regexp URL to ignore when saving EAF Browser history."
:type 'cons)
(defcustom eaf-browser-default-zoom 1.0
"Set the default zoom factor for EAF Browser."
:type 'float)
(defcustom eaf-browser-font-family ""
"Set font family for EAF Browser."
:type 'string)
(defcustom eaf-browser-progress-bar-height "2"
"Set progress bar height for EAF Browser."
:type 'int)
(defcustom eaf-browser-progress-bar-color (eaf-get-theme-foreground-color)
"Color of progress bar in hex code `#hhhhhh'.
Default is the foreground color of EAF buffer."
:type 'string)
(defcustom eaf-browser-text-selection-color "auto"
"Possible values are `auto' or a hex code `#hhhhhh' of a color.
If it is set to `auto', then the selection color will be automatically
configured by darkreader.js."
:type 'string)
(defcustom eaf-browser-blank-page-url "https://www.google.com"
"Set the blank page url for EAF Browser."
:type 'string)
(defcustom eaf-browser-download-path "~/Downloads"
"Set the download path for EAF Browser."
:type 'string)
(defcustom eaf-browser-aria2-proxy-host ""
"Set proxy host for aria2 downloader for EAF Browser."
:type 'string)
(defcustom eaf-browser-aria2-proxy-port ""
"Set proxy port for aria2 downloader for EAF Browser."
:type 'string)
(defcustom eaf-browser-aria2-auto-file-renaming nil
"If non-nil, aria2 downloader will auto rename files for EAF Browser."
:type 'boolean)
(defcustom eaf-browser-dark-mode "follow"
"Configure the dark mode setting for EAF Browser.
Options:
- \"follow\" to follow Emacs theme
- \"force\" to force dark mode
- nil to disable dark mode"
:type 'string)
(defcustom eaf-browser-pc-user-agent "Mozilla/5.0 (X11; Linux x86_64; rv:85.0) Gecko/20100101 Firefox/85.0"
"Simulate a PC User-Agent for EAF Browser."
:type 'string)
(defcustom eaf-browser-phone-user-agent "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A5370a Safari/604.1"
"Simulate a Phone User-Agent for EAF Browser."
:type 'string)
(defcustom eaf-browser-chrome-history-file "~/.config/google-chrome/Default/History"
"Set the chrome history file when exporting chrome history."
:type 'string)
(defcustom eaf-browser-translate-language ""
"EAF browser will use current system locale if this option is empty"
:type 'string)
(defcustom eaf-browser-unknown-url-scheme-policy "AllowUnknownUrlSchemesFromUserInteraction"
"Allowed options: DisallowUnknownUrlSchemes, AllowUnknownUrlSchemesFromUserInteraction, or AllowAllUnknownUrlSchemes."
:type 'string)
(defcustom eaf-browser-reader-mode-style
"<style> #readability-page-1 { width: 60%; margin: auto; line-height:1.5; font-size: 18px } </style>"
"The string of css style used by reader-mode."
:type 'string)
(defcustom eaf-chrome-bookmark-file "~/.config/google-chrome/Default/Bookmarks"
"The default chrome bookmark file to import."
:type 'string)
(defcustom eaf-browser-caret-mode-keybinding
'(("j" . "caret_next_line")
("k" . "caret_previous_line")
("l" . "caret_next_character")
("h" . "caret_previous_character")
("w" . "caret_next_word")
("b" . "caret_previous_word")
(")" . "caret_next_sentence")
("(" . "caret_previous_sentence")
("g" . "caret_to_bottom")
("G" . "caret_to_top")
("/" . "caret_search_forward")
("?" . "caret_search_backward")
("." . "caret_clear_search")
("v" . "caret_toggle_mark")
("o" . "caret_rotate_selection")
("y" . "caret_translate_text")
("q" . "caret_exit")
("C-n" . "caret_next_line")
("C-p" . "caret_previous_line")
("C-f" . "caret_next_character")
("C-b" . "caret_previous_character")
("M-f" . "caret_next_word")
("M-b" . "caret_previous_word")
("M-e" . "caret_next_sentence")
("M-a" . "caret_previous_sentence")
("C-<" . "caret_to_bottom")
("C->" . "caret_to_top")
("C-s" . "caret_search_forward")
("C-r" . "caret_search_backward")
("C-." . "caret_clear_search")
("C-SPC" . "caret_toggle_mark")
("C-o" . "caret_rotate_selection")
("C-y" . "caret_translate_text")
("C-q" . "caret_exit")
("c" . "insert_or_caret_at_line")
("M-c" . "caret_toggle_browsing")
("<escape>" . "caret_exit"))
"The keybinding of EAF Browser Caret Mode."
:type 'cons)
(defcustom eaf-browser-keybinding
'(("C--" . "zoom_out")
("C-=" . "zoom_in")
("C-0" . "zoom_reset")
("C-s" . "search_text_forward")
("C-r" . "search_text_backward")
("C-n" . "scroll_up")
("C-p" . "scroll_down")
("C-f" . "scroll_right")
("C-b" . "scroll_left")
("C-v" . "scroll_up_page")
("C-y" . "yank_text")
("C-w" . "kill_text")
("M-e" . "atomic_edit")
("M-c" . "caret_toggle_browsing")
("M-D" . "select_text")
("M-s" . "open_link")
("M-S" . "open_link_new_buffer")
("M-B" . "open_link_background_buffer")
("C-/" . "undo_action")
("M-_" . "redo_action")
("M-w" . "copy_text")
("M-f" . "history_forward")
("M-b" . "history_backward")
("M-q" . "clear_cookies")
("C-t" . "toggle_password_autofill")
("C-d" . "save_page_password")
("M-a" . "toggle_adblocker")
("C-M-q" . "clear_history")
("C-M-i" . "import_chrome_history")
("M-v" . "scroll_down_page")
("M-<" . "scroll_to_begin")
("M->" . "scroll_to_bottom")
("M-p" . "duplicate_page")
("M-t" . "new_blank_page")
("M-d" . "toggle_dark_mode")
("SPC" . "insert_or_scroll_up_page")
("J" . "insert_or_select_left_tab")
("K" . "insert_or_select_right_tab")
("j" . "insert_or_scroll_up")
("k" . "insert_or_scroll_down")
("h" . "insert_or_scroll_left")
("l" . "insert_or_scroll_right")
("f" . "insert_or_open_link")
("F" . "insert_or_open_link_new_buffer")
("O" . "insert_or_open_link_new_buffer_other_window")
("B" . "insert_or_open_link_background_buffer")
("c" . "insert_or_caret_at_line")
("u" . "insert_or_scroll_down_page")
("d" . "insert_or_scroll_up_page")
("H" . "insert_or_history_backward")
("L" . "insert_or_history_forward")
("t" . "insert_or_new_blank_page")
("T" . "insert_or_recover_prev_close_page")
("i" . "insert_or_focus_input")
("I" . "insert_or_open_downloads_setting")
("r" . "insert_or_refresh_page")
("g" . "insert_or_scroll_to_begin")
("x" . "insert_or_close_buffer")
("G" . "insert_or_scroll_to_bottom")
("-" . "insert_or_zoom_out")
("=" . "insert_or_zoom_in")
("0" . "insert_or_zoom_reset")
("m" . "insert_or_save_as_bookmark")
("o" . "insert_or_open_browser")
("y" . "insert_or_download_youtube_video")
("Y" . "insert_or_download_youtube_audio")
("p" . "insert_or_toggle_device")
("P" . "insert_or_duplicate_page")
("1" . "insert_or_save_as_pdf")
("2" . "insert_or_save_as_single_file")
("3" . "insert_or_save_as_screenshot")
("v" . "insert_or_view_source")
("e" . "insert_or_edit_url")
("n" . "insert_or_export_text")
("," . "insert_or_switch_to_reader_mode")
("." . "insert_or_translate_text")
(";" . "insert_or_translate_page")
("C-M-c" . "copy_code")
("C-M-l" . "copy_link")
("C-a" . "select_all_or_input_text")
("M-u" . "clear_focus")
("C-j" . "open_downloads_setting")
("M-o" . "eval_js")
("M-O" . "eval_js_file")
("<escape>" . "eaf-browser-send-esc-or-exit-fullscreen")
("M-," . "eaf-send-down-key")
("M-." . "eaf-send-up-key")
("M-m" . "eaf-send-return-key")
("<f5>" . "refresh_page")
("<f12>" . "open_devtools")
("<C-return>" . "eaf-send-ctrl-return-sequence")
("C-<left>" . "eaf-send-ctrl-left-sequence")
("C-<right>" . "eaf-send-ctrl-right-sequence")
("C-<delete>" . "eaf-send-ctrl-delete-sequence")
("C-<backspace>" . "eaf-send-ctrl-backspace-sequence")
)
"The keybinding of EAF Browser."
:type 'cons)
(defcustom eaf-browser-key-alias
'(("C-a" . "<home>")
("C-e" . "<end>"))
"The key alias of EAF Browser."
:type 'cons)
(defun eaf--browser-update-position (position-percentage)
"Format mode line position indicator to show the current position in percentage."
(setq-local mode-line-position `(,position-percentage))
(force-mode-line-update))
(defun eaf-browser-restore-buffers ()
"EAF restore all opened EAF Browser buffers in the previous Emacs session.
This should be used after setting `eaf-browser-continue-where-left-off' to t."
(interactive)
(if eaf-browser-continue-where-left-off
(let* ((browser-restore-file-path
(concat eaf-config-location
(file-name-as-directory "browser")
(file-name-as-directory "history")
"restore.txt"))
(browser-url-list
(with-temp-buffer (insert-file-contents browser-restore-file-path)
(split-string (buffer-string) "\n" t))))
(if (eaf-epc-live-p eaf-epc-process)
(dolist (url browser-url-list)
(eaf-open-browser url))
(dolist (url browser-url-list)
(push `(,url "browser" "") eaf--active-buffers))
(when eaf--active-buffers (eaf-open-browser (nth 0 (car eaf--active-buffers))))))
(user-error "Please set `eaf-browser-continue-where-left-off' to t first!")))
(defun eaf--browser-bookmark ()
"Restore EAF buffer according to browser bookmark from the current file path or web URL."
`((handler . eaf--bookmark-restore)
(eaf-app . "browser")
(defaults . ,(list eaf--bookmark-title))
(filename . ,(eaf-get-path-or-url))))
(defun eaf--browser-chrome-bookmark (name url)
"Restore EAF buffer according to chrome bookmark of given title and web URL."
`((handler . eaf--bookmark-restore)
(eaf-app . "browser")
(defaults . ,(list name))
(filename . ,url)))
(defun eaf--browser-bookmark-restore (bookmark)
(eaf-open-browser (cdr (assq 'filename bookmark))))
(defalias 'eaf--browser-firefox-bookmark 'eaf--browser-chrome-bookmark)
(defvar eaf--firefox-bookmarks nil
"Bookmarks that should be imported from firefox.")
(defun eaf--useful-firefox-bookmark? (uri)
"Check whether uri is a website url."
(or (string-prefix-p "http://" uri)
(string-prefix-p "https://" uri)))
(defun eaf--firefox-bookmark-to-import? (title uri)
"Check whether uri should be imported."
(when (eaf--useful-firefox-bookmark? uri)
(let ((old (gethash uri eaf--existing-bookmarks)))
(when (or
(not old)
(and (string-equal old "") (not (string-equal title ""))))
t))))
(defun eaf--firefox-bookmark-to-import (title uri)
(puthash uri title eaf--existing-bookmarks)
(add-to-list 'eaf--firefox-bookmarks (cons uri title)))
(defun eaf-import-firefox-bookmarks ()
"Command to import firefox bookmarks."
(interactive)
(when (eaf-read-input "In order to import, you should first backup firefox's bookmarks to a json file. Continue?" "yes-or-no" "")
(let ((fx-bookmark-file (read-file-name "Choose firefox bookmark file:")))
(if (not (file-exists-p fx-bookmark-file))
(message "Firefox bookmark file: '%s' is not exist." fx-bookmark-file)
(setq eaf--firefox-bookmarks nil)
(setq eaf--existing-bookmarks (eaf--load-existing-bookmarks))
(let ((orig-bookmark-record-fn bookmark-make-record-function)
(data (json-read-file fx-bookmark-file)))
(cl-labels ((fn (item)
(pcase (alist-get 'typeCode item)
(1
(let ((title (alist-get 'title item ""))
(uri (alist-get 'uri item)))
(when (eaf--firefox-bookmark-to-import? title uri)
(eaf--firefox-bookmark-to-import title uri))))
(2
(mapc #'fn (alist-get 'children item))))))
(fn data)
(dolist (bm eaf--firefox-bookmarks)
(let ((uri (car bm))
(title (cdr bm)))
(setq-local bookmark-make-record-function
#'(lambda () (eaf--browser-firefox-bookmark title uri)))
(bookmark-set title)))
(setq-local bookmark-make-record-function orig-bookmark-record-fn)
(bookmark-save)
(message "Import success.")))))))
(defun eaf--create-new-browser-buffer (new-window-buffer-id)
"Function for creating a new browser buffer with the specified NEW-WINDOW-BUFFER-ID."
(let ((eaf-buffer
;; Create a buffer which name look like first buffer (but
;; different). this can prevent mode-line flicker. the
;; buffer's name will be changed to title when title is
;; ready.
(generate-new-buffer
(concat (buffer-name (car (buffer-list))) " "))))
(with-current-buffer eaf-buffer
(eaf--gen-keybinding-map (eaf--get-app-bindings "browser"))
(eaf-mode)
(set (make-local-variable 'eaf--buffer-id) new-window-buffer-id)
(set (make-local-variable 'eaf--buffer-url) "")
(set (make-local-variable 'eaf--buffer-app-name) "browser"))
(switch-to-buffer eaf-buffer)
;; When user open new window by click link, we should clean
;; minibuffer's message, for it may be show useless info.
(message nil)))
(defun eaf-browser--duplicate-page-in-new-tab (url)
"Duplicate a new tab for the dedicated URL."
(eaf-open (eaf-wrap-url url) "browser" nil t))
(defun eaf-is-valid-web-url (url)
"Return the same URL if it is valid."
(when (and url
;; URL should not include blank char.
(< (length (split-string url)) 2)
;; Use regexp matching URL.
(or (and
(string-prefix-p "file://" url)
(string-suffix-p ".html" url))
;; Normal url address.
(string-match "^\\(https?://\\)?[a-z0-9]+\\([-.][a-z0-9]+\\)*.+\\..+[a-z0-9.]\\{1,6\\}\\(:[0-9]{1,5}\\)?\\(/.*\\)?$" url)
;; Localhost url.
(string-match "^\\(https?://\\)?\\(localhost\\|127.0.0.1\\):[0-9]+/?" url)))
url))
(defun eaf-wrap-url (url)
"Wraps URL with prefix http:// if URL does not include it."
(if (or (string-prefix-p "http://" url)
(string-prefix-p "https://" url)
(string-prefix-p "file://" url)
(string-prefix-p "chrome://" url))
url
(concat "http://" url)))
;;;###autoload
(defun eaf-open-browser-in-background (url &optional args)
"Open browser with the specified URL and optional ARGS in background."
(setq eaf--monitor-configuration-p nil)
(let ((save-buffer (current-buffer)))
(eaf-open-browser url args)
(switch-to-buffer save-buffer))
(setq eaf--monitor-configuration-p t))
;;;###autoload
(defun eaf-open-browser-with-history ()
"A wrapper around `eaf-open-browser' that provides browser history candidates.
If URL is an invalid URL, it will use `eaf-browser-default-search-engine' to search URL as string literal.
This function works best if paired with a fuzzy search package."
(interactive)
(let* ((browser-history-file-path
(concat eaf-config-location
(file-name-as-directory "browser")
(file-name-as-directory "history")
"log.txt"))
(history-pattern "^\\(.+\\)ᛝ\\(.+\\)ᛡ\\(.+\\)$")
(history-file-exists (file-exists-p browser-history-file-path))
(history (completing-read
"[EAF/browser] Search || URL || History: "
(if history-file-exists
(mapcar
(lambda (h) (when (string-match history-pattern h)
(format "[%s] ⇰ %s" (match-string 1 h) (match-string 2 h))))
(with-temp-buffer (insert-file-contents browser-history-file-path)
(split-string (buffer-string) "\n" t)))
nil)))
(history-url (eaf-is-valid-web-url (when (string-match "\s\\(.+\\)$" history)
(match-string 1 history)))))
(cond (history-url (eaf-open-browser history-url))
((eaf-is-valid-web-url history) (eaf-open-browser history))
(t (eaf-search-it history)))))
(defun eaf--create-search-url (search-string &optional search-engine use-user-engine)
"Create a search-url for SEARCH-STRING using SEARCH-ENGINE.
SEARCH-ENGINE is defaulted to `eaf-browser-default-search-engine'.
When USE-USER-ENGINE is non-nil, user can choose a search engine defined in `eaf-browser-search-engines'"
(let* ((real-search-engine (if use-user-engine
(let ((all-search-engine (mapcar #'car eaf-browser-search-engines)))
(completing-read
(format "[EAF/browser] Select search engine (default %s): " eaf-browser-default-search-engine)
all-search-engine nil t nil nil eaf-browser-default-search-engine))
(or search-engine eaf-browser-default-search-engine)))
(link (or (cdr (assoc real-search-engine
eaf-browser-search-engines))
(error (format "[EAF/browser] Search engine %s is unknown to EAF!" real-search-engine))))
(search-url (format link search-string)))
search-url))
;;;###autoload
(defun eaf-search-it (&optional search-string search-engine)
"Use SEARCH-ENGINE search SEARCH-STRING.
If called interactively, SEARCH-STRING is defaulted to symbol or region string.
The user can enter a customized SEARCH-STRING. SEARCH-ENGINE is defaulted
to `eaf-browser-default-search-engine' with a prefix arg, the user is able to
choose a search engine defined in `eaf-browser-search-engines'"
(interactive)
(let* ((current-symbol (if mark-active
(if (eq major-mode 'pdf-view-mode)
(progn
(declare-function pdf-view-active-region-text "pdf-view.el")
(car (pdf-view-active-region-text)))
(buffer-substring (region-beginning) (region-end)))
(symbol-at-point)))
(search-string (if search-string search-string
(let ((search-string (read-string (format "[EAF/browser] Search (%s): " current-symbol))))
(if (string-blank-p search-string) current-symbol
search-string))))
(use-user-engine current-prefix-arg)
(search-url (eaf--create-search-url search-string search-engine use-user-engine)))
(eaf-open search-url "browser")))
(defun eaf--exit_fullscreen_request ()
"Exit EAF browser fullscreen."
(setq-local eaf-fullscreen-p nil)
(eaf-monitor-configuration-change))
(defun eaf-browser-send-esc-or-exit-fullscreen ()
"Escape fullscreen status if browser current is fullscreen.
Otherwise send key 'esc' to browser."
(interactive)
(if eaf-fullscreen-p
(eaf-call-async "eval_function" eaf--buffer-id "exit_fullscreen" "<escape>")
(eaf-call-async "send_key" eaf--buffer-id "<escape>")))
(defun eaf-browser-is-loading ()
"Return non-nil if current page is loading."
(interactive)
(when (and (string= eaf--buffer-app-name "browser")
(string= (eaf-call-sync "execute_function" eaf--buffer-id "page_is_loading") "True"))))
(defun eaf--browser-export-text (buffer-name html-text)
(let ((eaf-export-text-buffer (get-buffer-create buffer-name)))
(with-current-buffer eaf-export-text-buffer
(read-only-mode -1)
(erase-buffer)
(insert html-text)
(goto-char (point-min))
(read-only-mode 1))
(switch-to-buffer eaf-export-text-buffer)
))
(defun eaf--atomic-edit (buffer-id focus-text)
"EAF Browser: edit FOCUS-TEXT with Emacs's BUFFER-ID."
(split-window-below -10)
(other-window 1)
(let ((edit-text-buffer (generate-new-buffer (format "eaf-%s-atomic-edit" eaf--buffer-app-name)))
(buffer-app-name eaf--buffer-app-name))
(with-current-buffer edit-text-buffer
(eaf-edit-mode)
(set (make-local-variable 'eaf--buffer-app-name) buffer-app-name)
(set (make-local-variable 'eaf--buffer-id) buffer-id))
(switch-to-buffer edit-text-buffer)
(setq-local eaf-edit-confirm-action "")
(eaf--edit-set-header-line)
(insert focus-text)
;; When text line number above
(when (> (line-number-at-pos) 30)
(goto-char (point-min)))))
(defun eaf-edit-buffer-cancel ()
"Cancel EAF Browser focus text input and closes the buffer."
(interactive)
(kill-buffer)
(delete-window)
(message "[EAF/%s] Edit cancelled!" eaf--buffer-app-name))
(defun eaf-edit-buffer-switch-to-org-mode ()
"Switch to `org-mode' to edit table handily."
(interactive)
(let ((buffer-app-name eaf--buffer-app-name)
(buffer-id eaf--buffer-id))
(org-mode)
(set (make-local-variable 'eaf--buffer-app-name) buffer-app-name)
(set (make-local-variable 'eaf--buffer-id) buffer-id)
(outline-show-all)
(goto-char (point-min))
(local-set-key (kbd "C-c C-c") 'eaf-edit-buffer-confirm)
(local-set-key (kbd "C-c C-k") 'eaf-edit-buffer-cancel)
(eaf--edit-set-header-line)))
(defun eaf--edit-set-header-line ()
"Set header line."
(setq header-line-format
(substitute-command-keys
(concat
"\\<eaf-edit-mode-map>"
" EAF/" eaf--buffer-app-name " EDIT: "
"Confirm with `\\[eaf-edit-buffer-confirm]', "
"Cancel with `\\[eaf-edit-buffer-cancel]'. "
"Switch to org-mode with `\\[eaf-edit-buffer-switch-to-org-mode]'. "
))))
(defun eaf-open-devtool-page ()
"Use EAF Browser to open the devtools page."
(delete-other-windows)
(split-window (selected-window) (/ (* (nth 3 (eaf-get-window-allocation (selected-window))) 2) 3) nil t)
(other-window 1)
(eaf-open "about:blank" "browser" "devtools"))
(defun eaf--toggle-caret-browsing (caret-status)
"Toggle caret browsing given CARET-STATUS."
(if caret-status
(eaf--gen-keybinding-map eaf-browser-caret-mode-keybinding t)
(eaf--gen-keybinding-map eaf-browser-keybinding))
(setq eaf--buffer-map-alist (list (cons t eaf-mode-map))))
(defun eaf-import-chrome-bookmarks ()
"Command to import chrome bookmarks."
(interactive)
(when (eaf-read-input "Are you sure to import chrome bookmarks to EAF" "yes-or-no" "")
(if (not (file-exists-p eaf-chrome-bookmark-file))
(message "Chrome bookmark file: '%s' is not exist, check `eaf-chrome-bookmark-file` setting." eaf-chrome-bookmark-file)
(let ((orig-bookmark-record-fn bookmark-make-record-function)
(data (json-read-file eaf-chrome-bookmark-file)))
(cl-labels ((fn (item)
(pcase (alist-get 'type item)
("url"
(let ((name (alist-get 'name item))
(url (alist-get 'url item)))
(if (not (equal "chrome://bookmarks/" url))
(progn
(setq-local bookmark-make-record-function
#'(lambda () (eaf--browser-chrome-bookmark name url)))
(bookmark-set name)))))
("folder"
(mapc #'fn (alist-get 'children item))))))
(fn (alist-get 'bookmark_bar (alist-get 'roots data)))
(setq-local bookmark-make-record-function orig-bookmark-record-fn)
(bookmark-save)
(message "Import success."))))))
;;;###autoload
(defun eaf-open-browser (url &optional args)
"Open EAF browser application given a URL and ARGS."
(interactive "M[EAF/browser] URL: ")
(eaf-open (eaf-wrap-url url) "browser" args))
;;;###autoload
(defun eaf-open-browser-other-window (url &optional args)
"Open EAF browser application given a URL and ARGS in other window."
(interactive "M[EAF/browser] URL: ")
(when (< (length (window-list)) 2)
(split-window-right))
(other-window 1)
(eaf-open (eaf-wrap-url url) "browser" args))
(defun eaf-open-url-at-point ()
"Open URL at current point by EAF browser."
(interactive)
(eaf-open-browser (browse-url-url-at-point)))
(defun eaf-toggle-proxy()
"Toggle proxy to none or default proxy."
(interactive)
(eaf-call-sync "toggle_proxy"))
(add-to-list 'eaf-app-binding-alist '("browser" . eaf-browser-keybinding))
(setq eaf-browser-module-path (concat (file-name-directory load-file-name) "buffer.py"))
(add-to-list 'eaf-app-module-path-alist '("browser" . eaf-browser-module-path))
(add-to-list 'eaf-app-bookmark-handlers-alist '("browser" . eaf--browser-bookmark))
(add-to-list 'eaf-app-bookmark-restore-alist '("browser" . eaf--browser-bookmark-restore))
(add-to-list 'eaf-app-extensions-alist '("browser" . eaf-browser-extension-list))
(provide 'eaf-browser)
;;; eaf-browser.el ends here