123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- (in-package :nyxt-user) ; While implicit, this allows SLY to know which package we are in.
- (defun eval-in-emacs (&rest s-exps)
- "Evaluate S-exps with `emacsclient'."
- (let ((s-exps-string (cl-ppcre:regex-replace-all
- ;; Discard the package prefix.
- "next-user::?"
- (write-to-string
- `(progn ,@s-exps) :case :downcase)
- "")))
- (log:debug "Sending to Emacs: ~s" s-exps-string)
- (ignore-errors (uiop:run-program
- (list "emacsclient" "--eval" s-exps-string)))))
- (defvar *my-keymap* (make-keymap "my-map")
- "Keymap for `my-mode'.")
- (define-command org-capture (&optional (buffer (current-buffer)))
- "Org-capture current page."
- (eval-in-emacs
- `(org-link-set-parameters
- "next"
- :store (lambda ()
- (org-store-link-props
- :type "next"
- :link ,(url buffer)
- :description ,(title buffer))))
- `(org-capture)))
- (define-key *my-keymap* "C-M-o" 'org-capture)
- (define-command youtube-dl-current-page (&optional (buffer (current-buffer)))
- "Download a video in the currently open buffer."
- (eval-in-emacs
- (if (search "youtu" (url buffer))
- `(progn (youtube-dl ,(url buffer)) (youtube-dl-list))
- `(ambrevar/youtube-dl-url ,(url buffer)))))
- (define-key *my-keymap* "C-M-c d" 'youtube-dl-current-page)
- (define-command play-video-in-current-page (&optional (buffer (current-buffer)))
- "Play video in the currently open buffer."
- (uiop:run-program (list "mpv" (url buffer))))
- (define-key *my-keymap* "C-M-c v" 'play-video-in-current-page)
- (define-mode my-mode ()
- "Dummy mode for the custom key bindings in `*my-keymap*'."
- ((keymap-scheme (keymap:make-scheme
- scheme:emacs *my-keymap*
- scheme:vi-normal *my-keymap*))))
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (defvar +youtube-dl-command+ "youtube-dl"
- "Path to the 'youtube-dl' program.")
- ;; (defun auto-yt-dl-handler (url)
- ;; "Download a Youtube URL asynchronously to /tmp/videos/.
- ;; Videos are downloaded with `+youtube-dl-command+'."
- ;; (let ((uri (quri:uri url)))
- ;; (when (and uri
- ;; (member-string (quri:uri-domain uri) '("youtube.com" "youtu.be"))
- ;; (string= (quri:uri-path uri) "/watch"))
- ;; (log:info "Youtube: downloading ~a" url)
- ;; (uiop:launch-program (list +youtube-dl-command+ url "-o" "/tmp/videos/%(title)s.%(ext)s"))))
- ;; url)
- (defparameter old-reddit-handler
- (url-dispatching-handler
- 'old-reddit-dispatcher
- (match-host "www.reddit.com")
- (lambda (url)
- (quri:copy-uri url :host "old.reddit.com"))))
- (defparameter magnet-handler
- (url-dispatching-handler
- 'transmission-magnet-links
- (match-scheme "magnet")
- (lambda (url)
- (uiop:launch-program
- (list "transmission-remote" "--add"
- (object-string url)))
- (echo "Magnet link opened in Transmission.")
- nil)))
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (defvar *my-blocked-hosts*
- (nyxt/blocker-mode:make-hostlist
- :hosts '("platform.twitter.com"
- "syndication.twitter.com"
- "m.media-amazon.com")))
- (define-configuration nyxt/blocker-mode:blocker-mode
- ((nyxt/blocker-mode:hostlists (append (list *my-blocked-hosts*) %slot-default))))
- (defun format-c->lisp (s)
- "Incomplete substitution of C format string to Lisp format string.
- Recognized formats:
- - %%
- - %s"
- (str:join "%" (mapcar (lambda (s) (str:replace-all "%s" "~a" s))
- (str:split "%%" s))))
- (defun read-emacs-engines (stream)
- "Return a list of (NAME URL SHORTCUT)."
- (loop for object = (read stream nil :eof)
- until (eq object :eof)
- when (eq (car object) 'defengine)
- collect (make-instance 'search-engine
- :shortcut (getf (nthcdr 3 object) :keybinding)
- :search-url (format-c->lisp (nth 2 object)))))
- (defun personal-file (path)
- (str:concat (uiop:getenv "PERSONAL") "/" path))
- (defvar my-search-engines
- (loop for file in `("~/.emacs.d/lisp/init-engine.el"
- ,(personal-file "/bookmarks/engines.el"))
- append (nyxt::with-maybe-gpg-file (s file)
- (read-emacs-engines s))))
- (define-configuration (buffer web-buffer)
- ((default-modes (append '(my-mode vi-normal-mode) %slot-default))))
- (define-configuration buffer ; Multiple configurations work!
- ((search-engines (append my-search-engines %slot-default))
- (bookmarks-path (make-instance 'bookmarks-data-path
- :basename (personal-file "bookmarks/bookmarks.lisp.gpg")))
- (auto-mode-rules-path
- (make-instance 'auto-mode-rules-data-path :basename (personal-file "bookmarks/auto-mode-rules.lisp.gpg")))))
- (define-configuration web-buffer
- ((default-modes (append
- '(auto-mode
- blocker-mode
- force-https-mode
- noimage-mode
- noscript-mode
- proxy-mode
- reduce-tracking-mode)
- %slot-default))))
- (defvar *my-request-resource-handlers*
- (list
- magnet-handler
- old-reddit-handler))
- ;; (load-after-system :invidious-handler
- ;; (nyxt-init-file "invidious.lisp"))
- (defmethod deserialize-eww-bookmarks (stream)
- "This version of deserialize-bookmarks is compatible with Ambrevar's EWW
- format."
- (handler-case
- (let ((*standard-input* stream))
- (let ((entries (read stream)))
- (mapcar (lambda (entry)
- (when (getf entry :date)
- (setf (getf entry :date)
- (local-time:parse-timestring (getf entry :date))))
- (when (getf entry :time)
- (let ((timestamp (asctime->timestamp (getf entry :time))))
- (when timestamp
- (setf (getf entry :date) timestamp)))
- (remf entry :time))
- (when (getf entry :search)
- (setf (getf entry :search-url) (getf entry :search))
- (remf entry :search))
- (when (getf entry :mark)
- (setf (getf entry :shortcut) (getf entry :mark))
- (remf entry :mark))
- (apply #'make-instance 'nyxt:bookmark-entry
- entry))
- entries)))
- (error (c)
- (log:error "During bookmark deserialization: ~a" c)
- nil)))
- (defun restore-eww-bookmarks ()
- "Restore the bookmarks from EWW."
- (handler-case
- (let ((data (with-data-file (file (make-instance 'data-path
- :basename (personal-file "bookmarks/eww-bookmarks.gpg"))
- :direction :input
- :if-does-not-exist nil)
- (when file
- (deserialize-eww-bookmarks file)))))
- (when data
- (echo "Loading ~a bookmarks from ~s."
- (length data)
- (expand-path (bookmarks-path *browser*)))
- (setf (slot-value *browser* 'nyxt::bookmarks-data) data)))
- (error (c)
- (echo-warning "Failed to load bookmarks from ~s: ~a" (expand-path (bookmarks-path *browser*)) c))))
- (define-configuration browser
- ((session-restore-prompt :always-restore)))
- (setf nyxt/vcs:*vcs-projects-roots* '("~/projects"
- "~/common-lisp"
- "~/.local/share/emacs/site-lisp"))
- (defun my-status-style (&key (mode-background-color "rgb(120,120,120)"))
- (cl-css:css
- `((body
- :background "rgb(160, 160, 160)"
- :font-size "14px"
- :color "rgb(32, 32, 32)"
- :padding 0
- :margin 0
- :line-height "20px")
- (".arrow"
- :width "10px"
- :height "20px")
- (".arrow-right"
- :clip-path "polygon(0 100%, 100% 50%, 0 0)")
- (".arrow-left"
- :clip-path "polygon(0 50%, 100% 100%, 100% 0)")
- ("#container"
- :display "grid"
- ;; Columns: controls, arrow, url, arrow, modes
- :grid-template-columns "115px 10px auto 10px auto"
- :overflow-y "hidden")
- ("#controls"
- :background-color "rgb(80,80,80)"
- :padding-left "5px"
- :overflow "hidden"
- :white-space "nowrap")
- ("#url"
- :background-color "rgb(160,160,160)"
- :min-width "100px"
- :text-overflow "ellipsis"
- :overflow-x "hidden"
- :white-space "nowrap"
- :padding-left "15px"
- :padding-right "10px"
- :margin-left "-10px")
- ("#modes"
- :background-color ,mode-background-color
- :color "rgb(230, 230, 230)"
- :text-align "right"
- :padding-right "5px"
- ;; Uncomment the following to trim the mode list.
- ;; :text-overflow "ellipsis"
- ;; :overflow-x "hidden"
- :white-space "nowrap")
- (.button
- :color "rgb(230, 230, 230)"
- :text-decoration "none"
- :padding-left "2px"
- :padding-right "2px"
- :margin-left "2px"
- :margin-right "2px")
- (|.button:hover|
- :color "black"))))
- (defun my-format-status (window)
- (let ((buffer (current-buffer window)))
- (if (or (internal-buffer-p buffer)
- (find-submode buffer 'proxy-mode))
- (setf (style (status-buffer window))
- (my-status-style))
- (setf (style (status-buffer window))
- (my-status-style :mode-background-color "rgb(255,0,0)")))
- (markup:markup
- (:div :id "container"
- (:div :id "controls"
- (markup:raw (format-status-buttons)))
- (:div :class "arrow arrow-right"
- :style "background-color:rgb(80,80,80)" "")
- (:div :id "url"
- (markup:raw
- (format-status-load-status buffer)
- (format-status-url buffer)))
- (:div :class "arrow arrow-left"
- :style "background-color:rgb(220,120,120);background-color:rgb(120,120,120)" "")
- (:div :id "modes"
- (format-status-modes buffer))))))
- (define-configuration window
- ((status-formatter #'my-format-status)))
- (load-after-system :slynk (nyxt-init-file "slynk.lisp"))
- (defvar +dev-data-profile+ (make-instance 'data-profile :name "dev")
- "Development profile.")
- (defmethod nyxt:expand-data-path ((profile (eql +dev-data-profile+)) (path data-path))
- "Persist data to /tmp/nyxt/."
- (expand-default-path (make-instance (class-name (class-of path))
- :basename (basename path)
- :dirname "/tmp/nyxt/")))
- ;; After init:
- (load (nyxt-init-file "config.lisp"))
|