summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThanos Apollo <[email protected]>2023-09-27 02:10:25 +0300
committerThanos Apollo <[email protected]>2023-09-27 02:10:25 +0300
commit47b73144d1b30514df003560851de3bd06e88b81 (patch)
tree27b0b2e914c6867d90f6ce456b123606803a8a09
parent696a16039e28e5844a164d69f60006b9c11a0067 (diff)
[New] Add nyxt, slightly modified config from aartaka
m---------.config/nyxt/aarta-config0
-rw-r--r--.config/nyxt/ace.lisp154
-rw-r--r--.config/nyxt/bookmarks.lisp3
-rw-r--r--.config/nyxt/commands.lisp136
-rw-r--r--.config/nyxt/config-back.lisp33
-rw-r--r--.config/nyxt/config.lisp227
-rw-r--r--.config/nyxt/dark-reader.lisp12
-rw-r--r--.config/nyxt/freestance.lisp6
-rw-r--r--.config/nyxt/github.lisp139
-rw-r--r--.config/nyxt/hsplit.lisp25
-rw-r--r--.config/nyxt/kaomoji.lisp10
-rw-r--r--.config/nyxt/keybinds.lisp34
-rw-r--r--.config/nyxt/objdump.lisp52
-rw-r--r--.config/nyxt/passwd.lisp14
-rw-r--r--.config/nyxt/search-engines.lisp99
-rw-r--r--.config/nyxt/status.lisp33
-rw-r--r--.config/nyxt/style.lisp43
-rw-r--r--.config/nyxt/unpdf.lisp86
18 files changed, 1106 insertions, 0 deletions
diff --git a/.config/nyxt/aarta-config b/.config/nyxt/aarta-config
new file mode 160000
+Subproject 562dc7ba5f67c60cedcfa920a8001111e0f6a87
diff --git a/.config/nyxt/ace.lisp b/.config/nyxt/ace.lisp
new file mode 100644
index 0000000..2fe3a62
--- /dev/null
+++ b/.config/nyxt/ace.lisp
@@ -0,0 +1,154 @@
+(in-package #:nyxt-user)
+
+;;;; This is a configuration for the Ace editor Nyxt integration
+;;;; (https://github.com/atlas-engineer/nx-ace).
+
+(define-configuration nx-ace:ace-mode
+ ((nx-ace:extensions
+ (mapcar
+ (lambda (name)
+ (quri:merge-uris (quri:uri name)
+ (quri:uri "https://cdnjs.cloudflare.com/ajax/libs/ace/1.9.6/")))
+ '("keybinding-emacs.min.js"
+ ;; Themes
+ "theme-twilight.min.js"
+ "theme-github.min.js"
+ ;; Language modes
+ "mode-c_cpp.min.js"
+ "mode-asciidoc.min.js"
+ "mode-clojure.min.js"
+ "mode-csharp.min.js"
+ "mode-css.min.js"
+ "mode-diff.min.js"
+ "mode-dot.min.js"
+ "mode-forth.min.js"
+ "mode-fsharp.min.js"
+ "mode-gitignore.min.js"
+ "mode-glsl.min.js"
+ "mode-golang.min.js"
+ "mode-haskell.min.js"
+ "mode-html.min.js"
+ "mode-ini.min.js"
+ "mode-java.min.js"
+ "mode-javascript.min.js"
+ "mode-json.min.js"
+ "mode-jsx.min.js"
+ "mode-julia.min.js"
+ "mode-kotlin.min.js"
+ "mode-latex.min.js"
+ "mode-lisp.min.js"
+ "mode-lua.min.js"
+ "mode-makefile.min.js"
+ "mode-markdown.min.js"
+ "mode-mediawiki.min.js"
+ "mode-nix.min.js"
+ "mode-objectivec.min.js"
+ "mode-perl.min.js"
+ "mode-plain_text.min.js"
+ "mode-python.min.js"
+ "mode-r.min.js"
+ "mode-robot.min.js"
+ "mode-ruby.min.js"
+ "mode-rust.min.js"
+ "mode-scala.min.js"
+ "mode-scheme.min.js"
+ "mode-sh.min.js"
+ "mode-snippets.min.js"
+ "mode-sql.min.js"
+ "mode-svg.min.js"
+ "mode-tex.min.js"
+ "mode-text.min.js"
+ "mode-tsx.min.js"
+ "mode-typescript.min.js"
+ "mode-xml.min.js"
+ "mode-yaml.min.js"
+ ;; Snippets
+ "snippets/c_cpp.min.js"
+ "snippets/css.min.js"
+ "snippets/html.min.js"
+ "snippets/javascript.min.js"
+ "snippets/json.min.js"
+ "snippets/latex.min.js"
+ "snippets/lisp.min.js"
+ "snippets/makefile.min.js"
+ "snippets/markdown.min.js"
+ "snippets/plain_text.min.js"
+ "snippets/python.min.js"
+ "snippets/scheme.min.js"
+ "snippets/snippets.min.js"
+ "snippets/tex.min.js"
+ "snippets/text.min.js"
+ "snippets/yaml.min.js"
+ ;; Language Workers
+ "worker-base.min.js"
+ "worker-css.min.js"
+ "worker-html.min.js"
+ "worker-javascript.min.js"
+ "worker-json.min.js"
+ "worker-xml.min.js"
+ "worker-yaml.min.js"
+ ;; Extensions
+ "ext-language_tools.min.js"
+ "ext-emmet.min.js"
+ "ext-keybinding_menu.min.js"
+ "ext-modelist.min.js"
+ "ext-searchbox.min.js"
+ "ext-settings_menu.min.js"
+ "ext-themelist.min.js"
+ "ext-beautify.min.js"
+ "ext-prompt.min.js"
+ "ext-split.min.js"
+ "ext-whitespace.min.js"
+ "ext-statusbar.min.js")))))
+
+(define-configuration nx-ace:ace-mode
+ ((nx-ace::theme "ace/theme/twilight")
+ (nx-ace::keybindings "ace/keyboard/emacs")))
+
+(define-configuration nx-ace:ace-mode
+ ((nx-ace:epilogue
+ (str:concat
+ (ps:ps
+ (flet ((req (ext)
+ (ps:chain ace (require ext)))
+ (bind (key command)
+ (ps:chain editor commands (bind-key key command))))
+ (req "ace/ext/searchbox")
+ (req "ace/ext/split")
+ (req "ace/ext/themelist")
+ (req "ace/ext/emmet")
+ (req "ace/ext/language_tools")
+ (req "ace/worker/javascript")
+ (ps:chain editor (set-option "fontSize" 18))
+ (ps:chain editor (set-option "enableBasicAutocompletion" t))
+ (ps:chain editor (set-option "enableSnippets" t))
+ (ps:chain editor session
+ (set-mode (ps:chain (req "ace/ext/modelist")
+ (get-mode-for-path (ps:@ window location href)) mode)))
+ (bind "Shift-space" "setMark")
+ (bind "Ctrl-\\" "toggleFoldWidget")
+ (bind "Ctrl-c ;" "toggleComment")
+ (bind "Ctrl-Alt-b" "jumptomatching")
+ (bind "Ctrl-Alt-f" "jumptomatching")
+ (bind "Alt-space" "expandToMatching")
+ (bind "Alt-%" "replace")
+ (req "ace/ext/split")
+ (ps:chain (req "ace/ext/settings_menu") (init editor))
+ (ps:chain (req "ace/ext/keybinding_menu") (init editor))
+ (bind "Ctrl-h m" (lambda (editor)
+ (ps:chain editor (show-keyboard-shortcuts))))
+ (bind "C-i" "indent")
+ (ps:chain editor commands
+ (add-command (ps:chain ace (require "ace/ext/beautify") commands 0)))))))))
+
+(define-configuration nx-ace:ace-mode
+ ((style (str:concat
+ %slot-value%
+ (theme:themed-css (theme *browser*)
+ `("#kbshortcutmenu"
+ :background-color ,theme:background
+ :color ,theme:on-background))))
+ (nx-ace::keybindings "ace/keyboard/emacs")))
+
+(define-configuration :editor-buffer
+ ((default-modes `(nx-ace:ace-mode ,@%slot-value%))))
diff --git a/.config/nyxt/bookmarks.lisp b/.config/nyxt/bookmarks.lisp
new file mode 100644
index 0000000..da2a19e
--- /dev/null
+++ b/.config/nyxt/bookmarks.lisp
@@ -0,0 +1,3 @@
+(
+(:url "https://boards.4channel.org/g/thread/96062082/ptg-private-trackers-general" :title "/g/ - /ptg - Private Trackers General - Technology - 4chan" :date "2023-09-18T01:01:24.699824Z" :tags ("4chan"))
+)
diff --git a/.config/nyxt/commands.lisp b/.config/nyxt/commands.lisp
new file mode 100644
index 0000000..c048935
--- /dev/null
+++ b/.config/nyxt/commands.lisp
@@ -0,0 +1,136 @@
+(in-package #:nyxt-user)
+
+(define-command-global eval-expression ()
+ "Prompt for the expression and evaluate it, echoing result to the `message-area'.
+Part of this is functionality is built into execute-command on 3.*.
+BUT: this one lacks error handling, so I often use it for Nyxt-internal debugger."
+ (let ((expression-string
+ ;; Read an arbitrary expression. No error checking, though.
+ (first (prompt :prompt "Expression to evaluate"
+ :sources (list (make-instance 'prompter:raw-source))))))
+ ;; Message the evaluation result to the message-area down below.
+ (echo "~S" (eval (read-from-string expression-string)))))
+
+(defvar unicode '()
+ "All the Unicode characters (or, well, all the characters the implementation supports.)")
+
+(define-class unicode-source (prompter:source)
+ ((prompter:name "Unicode character")
+ (prompter:filter-preprocessor #'prompter:filter-exact-matches)
+ (prompter:constructor (lambda ()
+ (or unicode
+ (setf unicode
+ (loop for i from 0
+ while (ignore-errors (code-char i))
+ collect (code-char i))))))))
+
+(defmethod prompter:object-attributes ((char character) (source unicode-source))
+ `(("Character" ,(if (graphic-char-p char)
+ (princ-to-string char)
+ (format nil "~s" char)))
+ ("Name" ,(char-name char))
+ ("Code" ,(format nil "~D/~:*~X" (char-code char)))))
+
+(define-command-global insert-unicode (&key (character (prompt :prompt "Character to insert"
+ :sources 'unicode-source)))
+ "Insert the chosen Unicode character."
+ (ffi-buffer-paste (string character)))
+
+(nyxt/mode/bookmarklets:define-bookmarklet-command-global
+ post-to-hn
+ "Post the link you're currently on to Hacker News"
+ "window.location=\"https://news.ycombinator.com/submitlink?u=\" + encodeURIComponent(document.location) + \"&t=\" + encodeURIComponent(document.title)")
+
+(define-command-global open-in-nosave-buffer ()
+ "Make a new nosave buffer with URL at point."
+ (let ((url (url-at-point (current-buffer))))
+ (make-nosave-buffer :url url)))
+
+(ffi-add-context-menu-command
+ (lambda ()
+ (when (url-at-point (current-buffer))
+ (make-nosave-buffer :url (url-at-point (current-buffer)))))
+ "Open Link in New Nosave Buffer")
+
+#+nyxt-gtk
+(define-command-global make-new-buffer-with-url-and-context ()
+ "Make a new buffer with a user-chosen context and a URL under pointer."
+ (nyxt/renderer/gtk:make-buffer-with-context :url (url-at-point (current-buffer))))
+
+(ffi-add-context-menu-command
+ 'make-new-buffer-with-url-and-context
+ "Open Link in New Buffer with Context")
+
+(define-panel-command-global search-translate-selection (&key (selection (ffi-buffer-copy (current-buffer))))
+ (panel "*Translate panel*" :right)
+ "Open the translation of the selected word in a panel buffer."
+ (setf (ffi-width panel) 550)
+ (run-thread "search translation URL loader"
+ (sleep 0.3)
+ (buffer-load (quri:uri (format nil (nyxt::search-url (nyxt::default-search-engine))
+ (str:concat "translate " (ffi-buffer-copy (current-buffer)))))
+ :buffer panel))
+ "")
+
+(ffi-add-context-menu-command
+ 'search-translate-selection
+ "Translate Selection")
+
+(define-command-global add-autofill ()
+ "Add an autofill with the selected text to the list of `autofill-mode' autofills."
+ (push (make-instance 'nyxt/mode/autofill:autofill
+ :name (prompt1 :prompt "Autofill key" :sources 'prompter:raw-source)
+ :fill (ffi-buffer-copy (current-buffer)))
+ (nyxt/mode/autofill::autofills (current-mode :autofill))))
+
+(ffi-add-context-menu-command
+ 'add-autofill
+ "Add Temporary Autofill")
+
+(ffi-add-context-menu-command
+ (lambda ()
+ (let ((url (url-at-point (current-buffer))))
+ (nyxt/mode/bookmark:bookmark-add url :title (fetch-url-title url))))
+ "Bookmark this URL")
+
+(defmethod nyxt:value->html :around ((value string) &optional compact-p)
+ (declare (ignorable compact-p))
+ (if (html-string-p value)
+ (spinneret:with-html-string
+ (:label
+ (:raw (call-next-method))
+ (:br)
+ (:raw value)))
+ (call-next-method)))
+
+(defun make-clcs-link (symbol)
+ (str:concat "https://cl-community-spec.github.io/pages/"
+ (str:replace-all "-" "_002d" symbol)))
+
+(defmemo ping-clcs (symbol)
+ (handler-case
+ (prog1
+ t
+ (dex:get (make-clcs-link symbol)))
+ (error () nil)))
+
+(define-command-global clcs-lookup ()
+ (prompt
+ :sources (list (make-instance
+ 'prompter:source
+ :name "CL symbols"
+ :constructor (mapcar #'prini-to-string
+ (nsymbols:package-symbols :cl :visibility :external))
+ :enable-marks-p t
+ :filter-postprocessor #'(lambda (suggestions source input)
+ (declare (ignorable source input))
+ (remove-if (complement #'ping-clcs) suggestions
+ :key #'prompter:value))
+ :actions-on-return (list
+ (lambda-command clcs-current-buffer* (symbols)
+ (mapcar (alexandria:curry #'make-buffer-focus :url)
+ (mapcar #'make-clcs-link (rest symbols)))
+ (buffer-load (make-clcs-link (first symbols))))
+ (lambda-command clcs-new-buffer* (symbols)
+ (mapcar (alexandria:curry #'make-buffer-focus :url)
+ (mapcar #'make-clcs-link symbols))))))))
diff --git a/.config/nyxt/config-back.lisp b/.config/nyxt/config-back.lisp
new file mode 100644
index 0000000..3bcc50b
--- /dev/null
+++ b/.config/nyxt/config-back.lisp
@@ -0,0 +1,33 @@
+(define-configuration browser
+ ((theme theme:+dark-theme+)))
+(define-configuration (web-buffer prompt-buffer panel-buffer
+ nyxt/mode/editor:editor-buffer)
+ ((default-modes (pushnew 'nyxt/mode/emacs:emacs-mode %slot-value%))))
+
+
+
+(defvar *my-search-engines*
+ (list
+ '("google" "https://google.com/search?q=~a" "https://google.com")
+ '("doi" "https://dx.doi.org/~a" "https://dx.doi.org/")
+ '("duck" "https://duckduckgo.com/?q=~a" "https://duckudckgo.com"))
+ "List of search engines.")
+
+(define-configuration context-buffer
+ "Go through the search engines above and make-search-engine out of them."
+ ((search-engines
+ (append %slot-default%
+ (mapcar
+ (lambda (engine) (apply 'make-search-engine engine))
+ *my-search-engines*)))))
+
+(define-configuration nyxt/mode/style:dark-mode
+ ((style
+ (theme:themed-css (theme *browser*)
+ `(* :background-color ,theme:background "!important"
+ :background-image none "!important" :color "blue"
+ "!important")
+ `(a :background-color ,theme:background "!important"
+ :background-image none "!important" :color "#AAAAAA"
+ "!important")))))
+
diff --git a/.config/nyxt/config.lisp b/.config/nyxt/config.lisp
new file mode 100644
index 0000000..fa4416e
--- /dev/null
+++ b/.config/nyxt/config.lisp
@@ -0,0 +1,227 @@
+(in-package #:nyxt-user)
+
+;;; Reset ASDF registries to allow loading Lisp systems from
+;;; everywhere.
+#+nyxt-3 (reset-asdf-registries)
+
+;;; Load quicklisp. Not sure it works.
+#-quicklisp
+(let ((quicklisp-init
+ (merge-pathnames "quicklisp/setup.lisp" (user-homedir-pathname))))
+ (when (probe-file quicklisp-init)
+ (load quicklisp-init)))
+
+(defvar *web-buffer-modes*
+ '(:emacs-mode
+; :blocker-mode :force-https-mode
+ :reduce-tracking-mode
+ :user-script-mode :bookmarklets-mode)
+ "The modes to enable in any web-buffer by default.
+Extension files (like dark-reader.lisp) are to append to this list.
+
+Why the variable? Because it's too much hassle copying it everywhere.")
+
+;;; Loading files from the same directory.
+(define-nyxt-user-system-and-load nyxt-user/basic-config
+ :components ("keybinds" "status" "commands" "hsplit" "style" "unpdf" "objdump" "github"))
+
+;;; Loading extensions and third-party-dependent configs. See the
+;;; matching files for where to find those extensions.
+(defmacro defextsystem (system &optional file)
+ "Helper macro to load configuration for extensions.
+Loads a newly-generated ASDF system depending on SYSTEM.
+FILE, if provided, is loaded after the generated system successfully
+loads."
+ `(define-nyxt-user-system-and-load ,(gensym "NYXT-USER/")
+ :depends-on (,system) ,@(when file
+ `(:components (,file)))))
+
+;(defextsystem :nx-search-engines "search-engines")
+(defextsystem :nx-kaomoji "kaomoji")
+(defextsystem :nx-ace "ace.lisp")
+(defextsystem :nx-fruit)
+(defextsystem :nx-freestance-handler "freestance")
+(defextsystem :nx-dark-reader "dark-reader")
+
+(defvar *my-search-engines*
+ (list
+ '("google" "https://google.com/search?q=~a" "https://google.com")
+ '("doi" "https://dx.doi.org/~a" "https://dx.doi.org/")
+ '("duck" "https://duckduckgo.com/?q=~a" "https://duckudckgo.com")
+ '("thanos" "https://search.thanosapollo.com/searxng/search?q=~a"))
+ "List of search engines.")
+
+(define-configuration context-buffer
+ "Go through the search engines above and make-search-engine out of them."
+ ((search-engines
+ (append %slot-default%
+ (mapcar
+ (lambda (engine) (apply 'make-search-engine engine))
+ *my-search-engines*)))))
+
+(define-configuration browser
+ ;; Enable --remote --eval code evaluation.
+ ((remote-execution-p t)
+ (external-editor-program
+ (list "emacsclient" "-cn" "-a" "" "-F"
+ "((font . \"JetBrains Mono\") (vertical-scroll-bars) (tool-bar-lines) (menu-bar-lines))"))))
+
+(define-configuration :autofill-mode
+ "Setting up autofills."
+ ((autofills (flet ((autofill (name fill)
+ (nyxt/mode/autofill:make-autofill :name name :fill fill))
+ (done (text)
+ (lambda ()
+ (uiop:strcat text " in " (trivial-clipboard:text)))))
+ (list (autofill "ellipsis" "…")
+ (autofill "naive" "naïve")
+ (autofill "andre" "André")
+ (autofill "ala" "a-lá")
+ (autofill "let" "laisser-faire")
+ (autofill "voila" "Et voilà!")
+ (autofill "done" (done "Done"))
+ (autofill "fixed" (done "Fixed"))
+ (autofill "reverted" (done "Reverted")))))))
+
+;;; Those are settings that every type of buffer should share.
+(define-configuration (:modable-buffer :prompt-buffer :editor-buffer)
+ "Set up Emacs keybindings everywhere possible.
+
+If you're the VI person, then use this:
+(define-configuration :web-buffer
+ ((default-modes (append (list :vi-normal-mode) %slot-value%))))
+
+You probably want to stay with CUA in :prompt-buffer, because it's too
+weird using it with VI bindings. But if you're feeling risky, then:
+(define-configuration :prompt-buffer
+ ((default-modes (append (list :vi-insert-mode) %slot-value%))))"
+ ((default-modes `(:emacs-mode ,@%slot-value%))))
+
+(define-configuration :prompt-buffer
+ "Make the attribute widths adjust to the content in them.
+
+It's not exactly necessary on master, because there are more or less
+intuitive default widths, but these are sometimes inefficient (and
+note that I made this feature so I want to have it :P)."
+ ((dynamic-attribute-width-p t)))
+
+(define-configuration :web-buffer
+ ((download-engine
+ :renderer
+ :doc "This overrides download engine to use WebKit instead of Nyxt-native
+Dexador-based download engine. I don't remember why I switched,
+though.")
+ (search-always-auto-complete-p
+ nil
+ :doc "I don't like search completion when I don't need it.")
+ (global-history-p
+ nil
+ :doc "It was disabled after 2.2.4, while being a useful feature.
+I'm forcing it here, because I'm getting lost in buffer-local
+histories otherwise...")))
+
+(define-configuration :prompt-buffer
+ ((hide-single-source-header-p
+ t
+ :doc "This is to hide the header is there's only one source.
+There also used to be other settings to make prompt-buffer a bit
+more minimalist, but those are internal APIs :(")))
+
+(define-configuration :web-buffer
+ "Basic modes setup for web-buffer."
+ ((default-modes `(,@*web-buffer-modes* ,@%slot-value%))))
+
+(define-configuration :browser
+ "Set new buffer URL (a.k.a. start page, new tab page)."
+ ((default-new-buffer-url (quri:uri "nyxt:nyxt/mode/repl:repl"))))
+
+(define-configuration :nosave-buffer
+ "Enable proxy in nosave (private, incognito) buffers."
+ ((default-modes `(:proxy-mode ,@*web-buffer-modes* ,@%slot-value%))))
+
+(define-configuration :hint-mode
+ "Set up QWERTY home row as the hint keys."
+ ((hints-alphabet "DSJKHLFAGNMXCWEIO")))
+
+(define-configuration :history-mode
+ ((backtrack-to-hubs-p
+ t
+ :doc "I often browse with \"hub\" places, like GitHub notifications page.
+Having all the links it leads to to be forward children of it is useful.
+The feature is slightly experimental, though.")))
+
+(define-configuration :modable-buffer
+ "This makes auto-rules to prompt me about remembering this or that mode when I toggle it."
+ ((prompt-on-mode-toggle-p t)))
+
+(defmethod ffi-buffer-make :after ((buffer nyxt/renderer/gtk::gtk-buffer))
+ "Setting WebKit-specific settings.
+WARNING: Not exactly the best way to configure Nyxt, because it relies
+on internal APIs and CFFI...
+
+See
+https://webkitgtk.org/reference/webkit2gtk/stable/WebKitSettings.html
+for the full list of settings you can tweak this way."
+ (when (slot-boundp buffer 'nyxt/renderer/gtk::gtk-object)
+ (let* ((settings (webkit:webkit-web-view-get-settings
+ (nyxt/renderer/gtk::gtk-object buffer))))
+ (setf
+ ;; Resizeable textareas. It's not perfect, but still a cool feature to have.
+ (webkit:webkit-settings-enable-resizable-text-areas settings) t
+ ;; Write console errors/warnings to the shell, to ease debugging.
+ (webkit:webkit-settings-enable-write-console-messages-to-stdout settings) t
+ ;; "Inspect element" context menu option available at any moment.
+ (webkit:webkit-settings-enable-developer-extras settings) t
+ ;; Enable WebRTC.
+ (webkit:webkit-settings-enable-media-stream settings) t
+ ;; Use Cantarell-18 as the default font.
+ (webkit:webkit-settings-default-font-family settings) "JetBrains Mono"
+ (webkit:webkit-settings-default-font-size settings) 18
+ ;; Use Hack-17 as the monospace font.
+ (webkit:webkit-settings-monospace-font-family settings) "Hack"
+ (webkit:webkit-settings-default-monospace-font-size settings) 17
+ ;; Use Unifont for pictograms.
+ (webkit:webkit-settings-pictograph-font-family settings) "Material Icons")))
+ ;; Set the view background to black.
+ (cffi:foreign-funcall
+ "webkit_web_view_set_background_color"
+ :pointer (g:pointer (nyxt/renderer/gtk:gtk-object buffer))
+ ;; GdkRgba is simply an array of four doubles.
+ :pointer (cffi:foreign-alloc
+ :double
+ :count 4
+ ;; red green blue alpha
+ :initial-contents '(0d0 0d0 0d0 1d0))))
+
+(defmethod files:resolve ((profile nyxt:nyxt-profile) (file nyxt/mode/bookmark:bookmarks-file))
+ "Reroute the bookmarks to the config directory."
+ #p"~/.config/nyxt/bookmarks.lisp")
+
+(define-configuration :reduce-tracking-mode
+ ((query-tracking-parameters
+ (append '("utm_source" "utm_medium" "utm_campaign" "utm_term" "utm_content")
+ %slot-value%)
+ :doc "This is to strip UTM-parameters off all the links.
+Upstream Nyxt doesn't have it because it may break some websites.")
+ (preferred-user-agent
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"
+ :doc "Mimic Chrome on MacOS.")))
+
+(unless nyxt::*run-from-repl-p*
+ (define-configuration :browser
+ "Enable Nyxt-internal debugging, but only in binary mode and after startup if done.
+There are conditions raised at startup, and I don't want to catch
+those, hanging my Nyxt)."
+ ((after-startup-hook (hooks:add-hook %slot-value% #'toggle-debug-on-error)))))
+
+;; (defun request-log (request-data)
+;; (log:debug "~:@(~a~) ~a (~@[~*toplevel~]~@[~*resource~]) ~{~&~a~}"
+;; (http-method request-data) (url request-data)
+;; (toplevel-p request-data) (resource-p request-data)
+;; (request-headers request-data))
+;; request-data)
+
+;; (define-configuration :web-buffer
+;; "Request debugging, clutters the shell real fast."
+;; ((request-resource-hook
+;; (hooks:add-hook %slot-value% #'request-log))))
diff --git a/.config/nyxt/dark-reader.lisp b/.config/nyxt/dark-reader.lisp
new file mode 100644
index 0000000..e770d82
--- /dev/null
+++ b/.config/nyxt/dark-reader.lisp
@@ -0,0 +1,12 @@
+(in-package #:nyxt-user)
+
+(define-configuration nx-dark-reader:dark-reader-mode
+ ((nxdr:selection-color "#CD5C5C")
+ (nxdr:background-color "black")
+ (nxdr:text-color "white")
+ (nxdr:grayscale 50)
+ (nxdr:contrast 100)
+ (nxdr:brightness 100)))
+
+(define-configuration :web-buffer
+ ((default-modes `(nx-dark-reader:dark-reader-mode ,@%slot-value%))))
diff --git a/.config/nyxt/freestance.lisp b/.config/nyxt/freestance.lisp
new file mode 100644
index 0000000..c40c853
--- /dev/null
+++ b/.config/nyxt/freestance.lisp
@@ -0,0 +1,6 @@
+(in-package #:nyxt-user)
+
+(define-configuration :web-buffer
+ "Adding YouTube -> Invidious handler."
+ ((request-resource-hook
+ (hooks:add-hook %slot-value% 'nx-freestance-handler:invidious-handler))))
diff --git a/.config/nyxt/github.lisp b/.config/nyxt/github.lisp
new file mode 100644
index 0000000..78724a9
--- /dev/null
+++ b/.config/nyxt/github.lisp
@@ -0,0 +1,139 @@
+;; Could be an extension someday.
+(nyxt:define-package :nx-github-mode
+ (:documentation "Mode with GitHub-related commands."))
+(in-package :nx-github-mode)
+
+(nyxt:define-mode github-mode ()
+ "Manage Nyxt GitHub repository with convenient keybindings."
+ ((glyph "γ")
+ (keyscheme-map
+ (define-keyscheme-map "github-mode" ()
+ keyscheme:emacs
+ (list
+ "C-c C-c" 'approve-pull-request
+ "C-c C-m" 'new-feature-request
+ "C-c C-k" 'report-bug
+ "C-c C-r" 'review
+ "C-c C-0" 'notifications)))))
+
+(define-command notifications ()
+ (let* ((notification-links (clss:select "a[href^=\"https://github.com/notifications\"]"
+ (document-model (current-buffer))))
+ (back-to-notifications
+ (unless (uiop:emptyp notification-links)
+ (find-if (lambda (l) (search "Back to notifications" (nyxt/dom:body l)))
+ notification-links))))
+ (if back-to-notifications
+ (nyxt/dom:click-element back-to-notifications)
+ (buffer-load "https://github.com/notifications?query=reason:assign%20reason:mention%20reason:review-requested%20reason:team-mention%20reason:ci-activity"))))
+
+(define-command nyxt ()
+ (buffer-load "https://github.com/atlas-engineer/nyxt"))
+
+(defun debug-autofill ()
+ (ps-eval
+ (setf (ps:@ document active-element value) ""))
+ (format
+ nil "**Describe the bug**
+
+**Precise recipe to reproduce the issue**
+
+For website-specific issues:
+Can you reproduce this issue with Epiphany / GNOME Web (https://wiki.gnome.org/Apps/Web)?
+
+**Information**
+- OS name+version: GuixSD
+```sh
+$ guix describe
+~a
+```
+- Graphics card and driver: Intel UHD 620, `i915`
+``` sh
+$ lspci -v
+...
+00:02.0 VGA compatible controller: Intel Corporation UHD Graphics (rev 01) (prog-if 00 [VGA controller])
+ Subsystem: Lenovo Device 5089
+ Flags: bus master, fast devsel, latency 0, IRQ 165
+ Memory at 601c000000 (64-bit, non-prefetchable) [size=16M]
+ Memory at 4000000000 (64-bit, prefetchable) [size=256M]
+ I/O ports at 3000 [size=64]
+ Expansion ROM at 000c0000 [virtual] [disabled] [size=128K]
+ Capabilities: <access denied>
+ Kernel driver in use: i915
+ Kernel modules: i915
+...
+```
+- Desktop environment / Window manager name+version: StumpWM 20.11
+- How you installed Nyxt (Guix pack, package manager, build from source): `guix package -f nyxt.scm`
+- Information from `show-system-information`:
+```
+~a
+```
+
+**Output when started from a shell** "
+ (uiop:run-program "guix describe"
+ :output '(:string :stripped t))
+ (nyxt::system-information)))
+
+(define-command report-bug ()
+ "Report the bug on Nyxt GitHub, filling all the necessary information in the process."
+ (let* ((title (prompt1
+ :prompt "Title of the issue"
+ :sources (list (make-instance 'prompter:raw-source))))
+ (buffer (make-buffer-focus
+ :url (quri:uri (format nil "https://github.com/atlas-engineer/nyxt/issues/new?&template=bug_report.md&title=~a"
+ title)))))
+ (hooks:once-on (buffer-loaded-hook buffer)
+ (buffer)
+ (ps-eval
+ (ps:chain (nyxt/ps:qs document "#issue_body") (focus)))
+ (ffi-buffer-paste buffer (debug-autofill)))))
+
+(define-command new-feature-request ()
+ "Open a new feature request in Nyxt repo."
+ (let* ((title (prompt1
+ :prompt "Title of the issue"
+ :sources (list (make-instance 'prompter:raw-source))))
+ (buffer (make-buffer-focus
+ :url (quri:uri (format nil "https://github.com/atlas-engineer/nyxt/issues/new?assignees=&labels=feature&template=feature_request.md&title=~a"
+ title)))))
+ (hooks:once-on (buffer-loaded-hook buffer)
+ (buffer)
+ (ps-eval
+ (ps:chain (nyxt/ps:qs document "#issue_body") (focus))))))
+
+(define-command review ()
+ "Open the file diffing tab of the pull request."
+ (let* ((url (url (current-buffer)))
+ (files-url (quri:copy-uri
+ url
+ :path (str:concat (string-right-trim "/" (quri:uri-path url))
+ "/files"))))
+ (unless (or (search "/files" (render-url url))
+ (string/= "github.com" (quri:uri-domain url)))
+ (buffer-load files-url))))
+
+(define-command approve-pull-request ()
+ "Approve the pull request currently open."
+ (review)
+ (hooks:wait-on (buffer-loaded-hook (current-buffer))
+ buffer
+ ;; Make sure Nyxt DOM is fresh.
+ (update-document-model :buffer buffer)
+ (flet ((sel (selector)
+ (let ((result (clss:select selector (document-model buffer))))
+ (unless (uiop:emptyp result)
+ (elt result 0)))))
+ ;; Nyxt/DOM already has lots of things, so why not use them?
+ (nyxt/dom:toggle-details-element (sel "#review-changes-modal"))
+ (nyxt/dom:click-element (sel "input[type=radio][value=approve]"))
+ (nyxt/dom:click-element (sel "button[type=submit]")))))
+
+(define-command done ()
+ (let* ((button (elt (clss:select "button[type=\"submit\"][title=\"Done\"],
+button[type=\"submit\"][aria-label=\"Done\"]"
+ (document-model (current-buffer))) 0)))
+ (nyxt/dom:click-element button)))
+
+(define-auto-rule '(match-domain "github.com")
+ :included '(github-mode))
diff --git a/.config/nyxt/hsplit.lisp b/.config/nyxt/hsplit.lisp
new file mode 100644
index 0000000..2f49510
--- /dev/null
+++ b/.config/nyxt/hsplit.lisp
@@ -0,0 +1,25 @@
+(in-package #:nyxt-user)
+
+(define-panel-command hsplit-internal (&key (url (quri:render-uri (url (current-buffer)))))
+ (panel "*Duplicate panel*" :right)
+ "Duplicate the current buffer URL in the panel buffer on the right.
+
+A poor man's hsplit :)"
+ (setf (ffi-width panel) 550)
+ (run-thread "URL loader"
+ (sleep 0.3)
+ (buffer-load (quri:uri url) :buffer panel))
+ "")
+
+(define-command-global close-all-panels ()
+ "Close all the panel buffers there are."
+ (alexandria:when-let ((panels (nyxt/renderer/gtk::panel-buffers-right (current-window))))
+ (delete-panel-buffer :window (current-window) :panels panels))
+ (alexandria:when-let ((panels (nyxt/renderer/gtk::panel-buffers-left (current-window))))
+ (delete-panel-buffer :window (current-window) :panels panels)))
+
+(define-command-global hsplit ()
+ "Based on `hsplit-internal' above."
+ (if (nyxt/renderer/gtk::panel-buffers-right (current-window))
+ (delete-all-panel-buffers (current-window))
+ (hsplit-internal)))
diff --git a/.config/nyxt/kaomoji.lisp b/.config/nyxt/kaomoji.lisp
new file mode 100644
index 0000000..f288b03
--- /dev/null
+++ b/.config/nyxt/kaomoji.lisp
@@ -0,0 +1,10 @@
+(in-package #:nyxt-user)
+
+;;;; This is a file with settings for my nx-kaomoji extension.
+;;;; You can find it at https://github.com/aartaka/nx-kaomoji
+
+(define-configuration :document-mode
+ "Add a single keybinding for the extension-provided `kaomoji-fill' command."
+ ((keymap-scheme
+ (alter-keyscheme %slot-value% nyxt/keyscheme:emacs
+ "C-c K" 'nx-kaomoji:kaomoji-fill))))
diff --git a/.config/nyxt/keybinds.lisp b/.config/nyxt/keybinds.lisp
new file mode 100644
index 0000000..2eb5116
--- /dev/null
+++ b/.config/nyxt/keybinds.lisp
@@ -0,0 +1,34 @@
+(in-package #:nyxt-user)
+
+(define-configuration :document-mode
+ "Add basic keybindings."
+ ((keyscheme-map
+ (keymaps:define-keyscheme-map
+ "custom" (list :import %slot-value%)
+ ;; If you want to have VI bindings overriden, just use
+ ;; `scheme:vi-normal' or `scheme:vi-insert' instead of
+ ;; `scheme:emacs'.
+ nyxt/keyscheme:emacs
+ (list "C-c p" 'copy-password
+ "C-c y" 'autofill
+ "C-f" :history-forwards-maybe-query
+ "C-i" :input-edit-mode
+ "M-:" 'eval-expression
+ "C-s" :search-buffer
+ "C-x 3" 'hsplit
+ "C-x 1" 'close-all-panels
+ "C-'" (lambda-command insert-left-angle-quote ()
+ (ffi-buffer-paste (current-buffer) "«"))
+ "C-M-'" (lambda-command insert-left-angle-quote ()
+ (ffi-buffer-paste (current-buffer) "»"))
+ "C-M-hyphen" (lambda-command insert-left-angle-quote ()
+ (ffi-buffer-paste (current-buffer) "—"))
+ "C-M-_" (lambda-command insert-left-angle-quote ()
+ (ffi-buffer-paste (current-buffer) "–"))
+ "C-E" (lambda-command small-e-with-acute ()
+ (ffi-buffer-paste (current-buffer) "é"))
+ "C-A" (lambda-command small-a-with-acute ()
+ (ffi-buffer-paste (current-buffer) "á"))
+ "C-I" (lambda-command small-i-diaeresis ()
+ (ffi-buffer-paste (current-buffer) "ï"))
+ "C-h hyphen" 'clcs-lookup)))))
diff --git a/.config/nyxt/objdump.lisp b/.config/nyxt/objdump.lisp
new file mode 100644
index 0000000..341e2ce
--- /dev/null
+++ b/.config/nyxt/objdump.lisp
@@ -0,0 +1,52 @@
+(in-package #:nyxt-user)
+
+(define-internal-page-command-global objdump (&key (file (uiop:native-namestring
+ (prompt1 :prompt "File to disassemble"
+ :input (uiop:native-namestring (uiop:getcwd))
+ :sources 'nyxt/mode/file-manager:file-source))))
+ (buffer (format nil "Objdump of ~a" file))
+ "Show disassembly of code sections and contents of data sections in FILE."
+ (spinneret:with-html-string
+ (let* ((disassembly
+ (uiop:run-program (list "objdump" "--demangle" "--debugging" "--disassemble"
+ "--line-numbers" "--source" "--visualize-jumps" "--wide" file)
+ :output '(:string :stripped t)))
+ (lines (member-if (lambda (elem) (uiop:string-prefix-p "Disassembly" elem))
+ (mapcar #'str:trim (str:split "
+
+" disassembly :omit-nulls t))))
+ (sections (mapcar
+ (lambda (string)
+ (multiple-value-bind (start end starts ends)
+ (ppcre:scan "(\\d+)\\s*([^\\s]*).*" string)
+ (subseq string (elt starts 1) (elt ends 1))))
+ (remove-if-not
+ (lambda (str) (digit-char-p (elt str 0)))
+ (remove-if #'uiop:emptyp
+ (mapcar #'str:trim
+ (serapeum:lines
+ (uiop:run-program (list "objdump" "-h" file)
+ :output '(:string :stripped t))))))))
+ (code-sections (loop for (section code) on lines by #'cddr
+ collect (if (uiop:string-prefix-p "Disassembly of section " section)
+ (serapeum:slice section 23 -1)
+ section)))
+ (data-sections (set-difference sections code-sections :test #'string-equal)))
+ (loop for (section code) on lines by #'cddr
+ collect (:nsection
+ :id (prini-to-string (new-id))
+ :title (if (uiop:string-prefix-p "Disassembly of section " section)
+ (subseq section 23)
+ section)
+ (:pre code)))
+ (loop for data in data-sections
+ collect (:nsection
+ :id (prini-to-string (new-id))
+ :title data
+ (:pre (cadr (mapcar
+ #'str:trim
+ (str:split "
+
+" (uiop:run-program (list "objdump" "--section" data "--full-contents" file)
+ :output '(:string :stripped t))
+:omit-nulls t)))))))))
diff --git a/.config/nyxt/passwd.lisp b/.config/nyxt/passwd.lisp
new file mode 100644
index 0000000..8fc56fe
--- /dev/null
+++ b/.config/nyxt/passwd.lisp
@@ -0,0 +1,14 @@
+(in-package #:nyxt-user)
+
+(defmethod initialize-instance :after ((interface password:keepassxc-interface) &key &allow-other-keys)
+ "I use KeePassXC, and this simply sets the location of the password files."
+ (setf (password:password-file interface) "/home/aartaka/Documents/p.kdbx"))
+
+(define-configuration :password-mode
+ "This is to emphasize that I use KeePassXC.
+Nyxt is (was?) not always smart enough to guess that."
+ ((password-interface (make-instance 'password:keepassxc-interface))))
+
+(define-configuration :buffer
+ ((default-modes (append `(:password-mode) %slot-value%))))
+
diff --git a/.config/nyxt/search-engines.lisp b/.config/nyxt/search-engines.lisp
new file mode 100644
index 0000000..9ff81b2
--- /dev/null
+++ b/.config/nyxt/search-engines.lisp
@@ -0,0 +1,99 @@
+(in-package #:nyxt-user)
+
+;;;; This is a file with settings for my nx-search-engines extension.
+;;;; You can find it at https://github.com/aartaka/nx-search-engines
+
+(defvar *duckduckgo-keywords*
+ '(:theme :dark
+ :help-improve-duckduckgo nil
+ :homepage-privacy-tips nil
+ :privacy-newsletter nil
+ :newsletter-reminders nil
+ :install-reminders nil
+ :install-duckduckgo nil
+ :units-of-measure :metric
+ :keyboard-shortcuts t
+ :advertisements nil
+ :open-in-new-tab nil
+ :infinite-scroll t
+ :safe-search :off
+ :font-size :medium
+ :header-behavior :on-fixed
+ :font :jetbrains-mono
+ :background-color "000000"
+ :center-alignment t)
+ "My DDG settings, shared between the usual, image-search and other
+types of DuckDuckGo.")
+
+(define-configuration :context-buffer
+ ((search-engines (list
+ ;; engines: is a prefix for `nx-search-engines',
+ ;; it only works if you load nx-search-engines.
+ (engines:google :shortcut "gmaps"
+ :object :maps)
+ (make-instance 'search-engine
+ :shortcut "osm"
+ :search-url "https://www.openstreetmap.org/search?query=~a"
+ :fallback-url (quri:uri "https://www.openstreetmap.org/"))
+ (make-instance 'search-engine
+ :shortcut "golang"
+ :search-url "https://golang.org/pkg/~a/"
+ :fallback-url (quri:uri "https://golang.org/pkg/")
+ ;; A good example of a custom
+ ;; completion function. You can do
+ ;; crazy stuff in completion
+ ;; function (like reading shell
+ ;; commands or files).
+ :completion-function
+ (let ((installed-packages
+ (str:split nyxt::+newline+
+ (ignore-errors
+ (uiop:run-program
+ "go list all"
+ :output '(:string :stripped t))))))
+ (lambda (input)
+ (sort
+ (serapeum:filter (alexandria:curry #'str:containsp input)
+ installed-packages)
+ #'> :key (alexandria:curry
+ #'prompter::score-suggestion-string input)))))
+ (engines:wikipedia :shortcut "w")
+ (make-instance 'search-engine
+ :shortcut "yi"
+ :search-url "https://yandex.ru/images/search?text=~a"
+ :fallback-url (quri:uri "https://yandex.ru/images/"))
+ (make-instance 'search-engine
+ :shortcut "y"
+ :search-url "https://yandex.com/search/?text=~a"
+ :fallback-url (quri:uri "https://yandex.com/search/"))
+ (engines:google :shortcut "g"
+ :safe-search nil)
+ (engines:google-scholar :shortcut "gs")
+ (engines:google-scholar :shortcut "scholar-new"
+ :starting-time 2015)
+ (engines:startpage
+ :shortcut "sp"
+ :family-filter nil
+ :settings-string "806f879950cd466952c5379f2307693b30b87ef2da8e631a6b9c190cf0251f48de50be0202b48b0fa76beefe9b7427b693baeb77c4d24660dc6799469afc24785a974987168e79ce297ca202ad28")
+ (apply #'engines:duckduckgo-images
+ :shortcut "i" *duckduckgo-keywords*)
+ (engines:duckduckgo-html-only :shortcut "dho")
+ (engines:github :shortcut "git")
+ (engines:brave :shortcut "b")
+ (engines:teddit :shortcut "red")
+ (engines:libgen :shortcut "l")
+ (engines:invidious :shortcut "yt")
+ (engines:hacker-news :shortcut "hn")
+ (engines:wordnet :shortcut "wn" :show-word-frequencies t)
+ (apply #'engines:duckduckgo
+ :shortcut "d" *duckduckgo-keywords*)
+ (engines:searx
+ :shortcut "a"
+ :base-search-url "https://search.atlas.engineer/searxng/search?q=~a"
+ :fallback-url (quri:uri "https://search.atlas.engineer")
+ :completion-function (engines:make-duckduckgo-completion)
+ :auto-complete :yandex
+ :style :dark
+ :safe-search :none
+ :request-method :post)
+ (gloabl-history-p nil)))))
diff --git a/.config/nyxt/status.lisp b/.config/nyxt/status.lisp
new file mode 100644
index 0000000..9b47a24
--- /dev/null
+++ b/.config/nyxt/status.lisp
@@ -0,0 +1,33 @@
+(in-package #:nyxt-user)
+
+(define-configuration :status-buffer
+ "Display modes as short glyphs."
+ ((glyph-mode-presentation-p t)))
+
+;(define-configuration :force-https-mode ((glyph "ϕ")))
+(define-configuration :user-script-mode ((glyph "u")))
+(define-configuration :blocker-mode ((glyph "β")))
+(define-configuration :proxy-mode ((glyph "π")))
+(define-configuration :reduce-tracking-mode ((glyph "τ")))
+(define-configuration :certificate-exception-mode ((glyph "χ")))
+(define-configuration :style-mode ((glyph "ϕ")))
+(define-configuration :cruise-control-mode ((glyph "σ")))
+
+(define-configuration status-buffer
+ "Hide most of the status elements but URL and modes."
+ ((style (str:concat
+ %slot-value%
+ (theme:themed-css (theme *browser*)
+ `("#controls,#tabs"
+ :display none !important))))))
+
+(defmethod format-status-load-status ((status status-buffer))
+ "A fancier load status."
+ (spinneret:with-html-string
+ (:span (if (and (current-buffer)
+ (web-buffer-p (current-buffer)))
+ (case (slot-value (current-buffer) 'nyxt::status)
+ (:unloaded "∅")
+ (:loading "∞")
+ (:finished ""))
+ ""))))
diff --git a/.config/nyxt/style.lisp b/.config/nyxt/style.lisp
new file mode 100644
index 0000000..a9dbe37
--- /dev/null
+++ b/.config/nyxt/style.lisp
@@ -0,0 +1,43 @@
+(in-package #:nyxt-user)
+
+;; This automatically darkens WebKit-native interfaces and sends the
+;; "prefers-color-scheme: dark" to all the supporting websites.
+(setf (uiop:getenv "GTK_THEME") "Adwaita:dark")
+
+(define-configuration browser
+ "Configuring my reddish theme."
+ ((theme (make-instance
+ 'theme:theme
+ :background-color "black"
+ :accent-color "#CD5C5C"
+ :accent-alt-color "#6C2429"
+ :warning-color "#CEFF00"
+ :primary-color "rgb(170, 170, 170)"
+ :secondary-color "rgb(100, 100, 100)"))))
+
+(define-configuration :dark-mode
+ "Dark-mode is a simple mode for simple HTML pages to color those in a darker palette.
+
+I don't like the default gray-ish colors, though. Thus, I'm overriding
+those to be a bit more laconia-like.
+
+I'm not using this mode, though: I have nx-dark-reader."
+ ((style
+ (theme:themed-css (theme *browser*)
+ `(*
+ :background-color ,(if (theme:dark-p theme:theme)
+ theme:background
+ theme:on-background)
+ "!important"
+ :background-image none "!important"
+ :color ,(if (theme:dark-p theme:theme)
+ theme:on-background
+ theme:background)
+ "!important")
+ `(a
+ :background-color ,(if (theme:dark-p theme:theme)
+ theme:background
+ theme:on-background)
+ "!important"
+ :background-image none "!important"
+ :color ,theme:primary "!important")))))
diff --git a/.config/nyxt/unpdf.lisp b/.config/nyxt/unpdf.lisp
new file mode 100644
index 0000000..8b46457
--- /dev/null
+++ b/.config/nyxt/unpdf.lisp
@@ -0,0 +1,86 @@
+(in-package #:nyxt-user)
+
+;; I'm definining a new scheme to redirect PDF requests to. What it does is:
+;; - Get the original file (if the URL is a filesystem path, simply use it).
+;; - Save it to disk (if remote).
+;; - Run pdftotext over the file.
+;; - Display pdftotext output in a nice HTML page with interlinkable
+;; page numbers and page contents as <pre> tags.
+(define-internal-scheme "unpdf"
+ (lambda (url buffer)
+ (let* ((url (quri:uri url))
+ (original-url (quri:uri (quri:url-decode (quri:uri-path url))))
+ (local-p (or (null (quri:uri-scheme original-url))
+ (string= "file" (quri:uri-scheme original-url))))
+ (original-content (unless local-p
+ (dex:get (quri:render-uri original-url) :force-binary t))))
+ (flet ((display-pdf-contents (file)
+ (if (uiop:file-exists-p file)
+ (let ((pages (ignore-errors
+ (uiop:split-string
+ (uiop:run-program `("pdftotext" "-nodiag" ,(uiop:native-namestring file) "-")
+ :output '(:string :stripped t))
+ :separator '(#\Page)))))
+ (spinneret:with-html-string
+ (:head
+ (:style (style buffer))
+ ;; A class to override the <pre> colors.
+ (:style (theme:themed-css (theme *browser*)
+ #+(or nyxt-2 nyxt-3-pre-release-1)
+ (.override
+ :background-color theme:background
+ :color theme:on-background
+ :font-size "150%"
+ :line-height "150%")
+ #+(and nyxt-3 (not (or nyxt-2 nyxt-3-pre-release-1)))
+ `(.override
+ :background-color ,theme:background
+ :color ,theme:on-background
+ :font-size "150%"
+ :line-height "150%"))))
+ (loop for page in pages
+ for number from 1
+ unless (uiop:emptyp page)
+ do (:section
+ :id (princ-to-string number)
+ (:h2.override (:a :href (format nil "#~d" number)
+ (princ-to-string number)))
+ (:pre.override (or page ""))))))
+ "")))
+ (if local-p
+ (display-pdf-contents (pathname (quri:uri-path original-url)))
+ (uiop:with-temporary-file (:pathname path :type "pdf" :keep t)
+ (log:debug "Temp file for ~a is ~a" url path)
+ (alexandria:write-byte-vector-into-file
+ (coerce original-content '(vector (unsigned-byte 8))) path :if-exists :supersede)
+ (display-pdf-contents path))))))
+ :local-p t)
+
+(define-command-global unpdf-download-this ()
+ "A helper for unpdf: pages to download the original PDF to the regular destination.
+
+Unpdf redirects all requests, even those that you need to read
+elsewhere, thus I need this command."
+ (let* ((buffer (current-buffer))
+ (url (url buffer)))
+ (if (string= "unpdf" (quri:uri-scheme url))
+ (ffi-buffer-download buffer (quri:uri-path url))
+ ;; I need to turn it into a mode someday...
+ (echo-warning "This command is for unpdf: pages only, it's useless elsewhere!"))))
+
+(defun redirect-pdf (request-data)
+ (if (and (toplevel-p request-data)
+ (uiop:string-prefix-p "application/pdf" (mime-type request-data)))
+ ;; I should somehow prompt about downloading instead...
+ (progn
+ (echo "Redirecting to the unpdf URL...")
+ (make-buffer-focus :url (quri:uri (str:concat "unpdf:" (render-url (url request-data)))))
+ ;; Return nil to prevent Nyxt from downloading this PDF.
+ nil)
+ request-data))
+
+(define-configuration :web-buffer
+ ((request-resource-hook (hooks:add-hook %slot-value% 'redirect-pdf))))
+
+(define-configuration nyxt/mode/file-manager:file-source
+ ((supported-media-types `("pdf" ,@%slot-value%))))