summaryrefslogtreecommitdiffhomepage
path: root/lib/doc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/doc')
-rw-r--r--lib/doc/jao-doc-session.el29
-rw-r--r--lib/doc/jao-mac.el228
-rw-r--r--lib/doc/jao-org-focus.el117
-rw-r--r--lib/doc/jao-org-links.el26
-rw-r--r--lib/doc/jao-org-notes.el33
-rw-r--r--lib/doc/jao-pdf.el84
6 files changed, 481 insertions, 36 deletions
diff --git a/lib/doc/jao-doc-session.el b/lib/doc/jao-doc-session.el
index 877a8cb..df7e994 100644
--- a/lib/doc/jao-doc-session.el
+++ b/lib/doc/jao-doc-session.el
@@ -1,6 +1,6 @@
;;; jao-doc-session.el --- persistent document sessions -*- lexical-binding: t; -*-
-;; Copyright (C) 2022, 2024 jao
+;; Copyright (C) 2022, 2024, 2025 jao
;; Author: jao <mail@jao.io>
;; Keywords: docs
@@ -20,15 +20,18 @@
;;; Code:
-(persist-defvar jao-doc-session nil "Documents session")
+(define-multisession-variable jao-doc--session nil)
-(defvar-local jao-doc-session--is-doc nil)
+(defun jao-doc-session () (multisession-value jao-doc--session))
+
+(defvar-local jao-doc-session-is-doc nil
+ "Locally marks a buffer as belonging to a session.
+
+See also `jao-doc-session-mark'.")
(defun jao-doc-session-is-doc (&optional buffer)
"Check whether the given or current buffer belong to the doc session."
- (buffer-local-value 'jao-doc-session--is-doc (or buffer (current-buffer))))
-
-(defun jao-doc-session (&optional file) jao-doc-session)
+ (buffer-local-value 'jao-doc-session-is-doc (or buffer (current-buffer))))
(defun jao-doc-session-save (&optional skip-current force)
"Traverse all current buffers and update the value of `jao-doc-session'."
@@ -36,24 +39,24 @@
(let ((docs '())
(cb (and skip-current (current-buffer))))
(dolist (b (buffer-list))
- (when-let (fs (and (not (eq cb b)) (jao-doc-session-is-doc b)))
+ (when-let* ((fs (and (not (eq cb b)) (jao-doc-session-is-doc b)))
+ (fs (if (listp fs) fs (list (buffer-file-name b)))))
(dolist (f fs) (add-to-list 'docs f))))
(when (or force (> (length docs) 0))
- (setq jao-doc-session docs))))
+ (setf (multisession-value jao-doc--session) docs))))
(defun jao-doc-session-mark (&optional path)
"Mark the current buffer's file, or PATH, as persistent across sessions."
- (unless (listp jao-doc-session--is-doc)
- (setq jao-doc-session--is-doc (ensure-list jao-doc-session--is-doc)))
- (cl-pushnew (or path (buffer-file-name)) jao-doc-session--is-doc)
+ (unless (listp jao-doc-session-is-doc)
+ (setq jao-doc-session-is-doc (ensure-list jao-doc-session-is-doc)))
+ (cl-pushnew (or path (buffer-file-name)) jao-doc-session-is-doc)
(jao-doc-session-save))
(defun jao-doc-session--maybe-save ()
(when (jao-doc-session-is-doc) (jao-doc-session-save t)))
-(defvar jao-doc-session-inhibit-save nil)
-
(add-hook 'kill-buffer-hook #'jao-doc-session--maybe-save)
+(add-hook 'kill-emacs-hook #'jao-doc-session-save)
(provide 'jao-doc-session)
;;; jao-doc-session.el ends here
diff --git a/lib/doc/jao-mac.el b/lib/doc/jao-mac.el
new file mode 100644
index 0000000..ad11ea2
--- /dev/null
+++ b/lib/doc/jao-mac.el
@@ -0,0 +1,228 @@
+;;; jao-mac.el --- Running applescript. -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2025 Jose Antonio Ortega Ruiz
+
+;; Author: Jose Antonio Ortega Ruiz <mail@jao.io>
+;; Keywords: lisp
+
+;; 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 of the License, 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. If not, see <https://www.gnu.org/licenses/>.
+
+(require 'jao-shell)
+
+;;; applescript
+(defun jao-mac-applescript-prepare (&rest lines)
+ (let ((script (mapconcat 'identity lines "\r"))
+ (start))
+ (while (string-match "\n" script)
+ (setq script (replace-match "\r" t t script)))
+ (while (string-match "'" script start)
+ (setq start (+ 2 (match-beginning 0))
+ script (replace-match "\\'" t t script)))
+ script))
+
+(defun jao-mac-run-applescript (script)
+ (string-trim (shell-command-to-string (format "osascript -e '%s'" script))))
+
+(defun jao-mac-run-applescript* (&rest lines)
+ (jao-mac-run-applescript (apply #'jao-mac-applescript-prepare lines)))
+
+(defun jao-mac-tell-app (app &rest script-lines)
+ (let* ((app-id (string-split app))
+ (id (if (> (length app-id) 1) (car app-id) ""))
+ (app (if (> (length app-id) 1) (cadr app-id) (car app-id)))
+ (pre (list (format "tell application %s %S" id app)))
+ (post '("end tell\n")))
+ (apply #'jao-mac-run-applescript* (append pre script-lines post))))
+
+;;; open
+
+(defun jao-mac-open (thing &rest args)
+ "Invoke open after formatting thing with args, using `format'"
+ (jao-shell-exec (format "open %s" (apply #'format thing args))))
+
+(defun jao-mac-open-in-skim (&optional file page height)
+ (interactive)
+ (let* ((file (if file (expand-file-name file) (buffer-file-name)))
+ (page (or page (and (derived-mode-p 'doc-view-mode)
+ (doc-view-current-page)))))
+ (jao-mac-open "skim://%s%s" file (if page (format "#page=%s" page) ""))))
+
+;; https://alvinalexander.com/macos/applescript-how-to-open-pdf-file-in-preview-go-to-page/
+;; This will work as long as Preview is the default app for the file at hand.
+(defun jao-mac-open-in-preview (&optional file page height)
+ (interactive)
+ (let ((file (if file (expand-file-name file) (buffer-file-name)))
+ (page (or page (and (derived-mode-p 'doc-view-doc)
+ (doc-view-current-page)))))
+ (jao-mac-run-applescript*
+ (format "tell application id \"com.apple.Preview\" to open (POSIX file %S)\r\r"
+ (file-truename file))
+ "delay 1"
+ "tell application \"System Events\""
+ "keystroke \"g\" using {option down, command down}"
+ (format "keystroke %s" (or page 1))
+ "delay 0.1\rkeystroke return\rend tell")))
+
+;;; notifications
+
+(defun jao-mac-notify (title subtitle msg)
+ (jao-mac-run-applescript*
+ (format "display notification %S with title %S subtitle %S"
+ msg title subtitle)))
+
+;;; Skim
+(defvar jao-skim--current-file-script
+ (jao-mac-applescript-prepare
+ "tell application \"Skim\""
+ " try"
+ " set theD to front document"
+ " set theP to (path of theD)"
+ " set thePg to (get index of current page of theD)"
+ " return (theP & \"::\" & thePg)"
+ " on error"
+ " return \"\""
+ " end try"
+ "end tell"))
+
+(defun jao-skim-current-doc ()
+ "Returns a list of path and page number for the current Skim doc."
+ (when-let* ((p (jao-mac-run-applescript jao-skim--current-file-script))
+ (p (and (not (string-blank-p p)) p)))
+ (let ((ps (split-string p "::")))
+ (list (car ps) (string-to-number (cadr ps))))))
+
+(defun jao-skim-open-current-doc ()
+ (interactive)
+ (when-let* ((ps (jao-skim-current-doc)))
+ (apply 'jao-open-doc ps)))
+
+(defvar jao-skim--current-page-text
+ (jao-mac-applescript-prepare
+ "tell application \"Skim\""
+ "return the text of the current page of the front document"
+ "end tell"))
+
+(defun jao-skim-page-text ()
+ (jao-mac-run-applescript jao-skim--current-page-text))
+
+(defun jao-skim-view-page-text ()
+ (interactive)
+ (when-let* ((ps (jao-skim-current-doc))
+ (p (car ps))
+ (n (cadr ps))
+ (txt (jao-skim-page-text))
+ (bn (format "*%s - %s - txt*" p n)))
+ (with-current-buffer (get-buffer-create bn)
+ (delete-region (point-min) (point-max))
+ (insert txt)
+ (pop-to-buffer (current-buffer)))))
+
+;;; NetNewsWire
+
+(defvar jao-nnw--current-article-script
+ (jao-mac-applescript-prepare
+ "tell application \"NetNewsWire\""
+ "try"
+ "return (the url of the current article)"
+ "on error"
+ "return \"\""
+ "end try"
+ "end tell"))
+
+(defun jao-nnw-current-article ()
+ "The URL of the current article in NetNewsWire"
+ (jao-mac-run-applescript jao-nnw--current-article-script))
+
+(defun jao-nnw-browse-current-article ()
+ "Browse the URL of the current NNW article."
+ (interactive)
+ (if-let* ((url (jao-nnw-current-article)))
+ (unless (string-empty-p url)
+ (browse-url url))
+ (message "No article selected in NetNewsWire")))
+
+(defvar jao-nnw--label-cmd
+ "lsappinfo info -app NetNewsWire -only StatusLabel")
+
+(defun jao-nnw-unread-count ()
+ "A very hacky, yet efficient, way of getting NNW's badge."
+ (let ((s (shell-command-to-string jao-nnw--label-cmd)))
+ (when (string-match ".*=\"\\([0-9]+\\)\" ." s)
+ (string-to-number (match-string 1 s)))))
+
+(defun jao-mac-open-nnw ()
+ (interactive)
+ (jao-mac-open "-a NetNewsWire"))
+
+;;; Safari
+(defun jao-safari-current-url ()
+ (jao-mac-tell-app "Safari" "return URL of current tab of window 1"))
+
+(defun jao-safari-browse-current ()
+ "Browse the URL of the current Safari topmost document."
+ (interactive)
+ (browse-url (jao-safari-current-url)))
+
+;;; Firefox
+(defvar jao-ffox--current-url-script
+ (jao-mac-applescript-prepare
+ "tell application \"Firefox\""
+ " activate"
+ " delay 0.15"
+ " tell application \"System Events\""
+ " keystroke \"l\" using command down"
+ " delay 0.20"
+ " keystroke \"c\" using command down"
+ " end tell"
+ " delay 0.5"
+ "end tell"
+ "return the clipboard"))
+
+(defun jao-firefox-current-url ()
+ (let ((res (jao-mac-run-applescript jao-ffox--current-url-script)))
+ (jao-mac-run-applescript "tell application \"Emacs\" to activate")
+ res))
+
+(defun jao-firefox-open ()
+ (interactive)
+ (jao-mac-open "-a Firefox"))
+
+;;; DevonThink
+
+(defun jao-devon-tell (&rest script-lines)
+ (apply #'jao-mac-tell-app "id DNtp" script-lines ))
+
+(defun jao-devon-find-url (file)
+ (jao-devon-tell
+ "repeat with db in databases"
+ (format "set res to lookup records with path %S in db"
+ (file-truename file))
+ "if res /= {} then return the reference URL of (item 1 of res)"
+ "end repeat"
+ "return \"\""))
+
+(defun jao-devon-show-search (s)
+ (jao-devon-tell (format "show search %S" s) "activate"))
+
+(defun jao-devon-open (file &optional page height)
+ (let ((url (jao-devon-find-url file)))
+ (if (string-empty-p (or url ""))
+ (let ((jao-pdf-open-in-emacs t))
+ (jao-find-or-open file page height))
+ (let* ((p (if page (format "?page=%s" (- page 1)) ""))
+ (u (format "%s%s" url p)))
+ (jao-mac-open "%s%s" url p)))))
+
+(provide 'jao-mac)
+;;; jao-mac.el ends here
diff --git a/lib/doc/jao-org-focus.el b/lib/doc/jao-org-focus.el
new file mode 100644
index 0000000..e9d6ed2
--- /dev/null
+++ b/lib/doc/jao-org-focus.el
@@ -0,0 +1,117 @@
+;;; jao-org-focus.el --- focusing on org subtrees -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2025 Jose Antonio Ortega Ruiz
+
+;; Author: Jose Antonio Ortega Ruiz <mail@jao.io>
+;; Keywords: docs
+
+;; 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 of the License, 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. If not, see <https://www.gnu.org/licenses/>.
+
+(require 'org)
+
+(defvar-local jao-org-focus--parent nil)
+(defvar-local jao-org-focus--section nil)
+
+;;; focus on subtree
+(defun jao-org-focus ()
+ "Pop creatingly to an indirect buffer focused on the encloing subtree.
+
+When invoked on an indirect buffer, pops back to its base."
+ (interactive)
+ (if-let* ((b (get-buffer (or jao-org-focus--parent ""))))
+ (pop-to-buffer b)
+ (when-let* ((elem (org-element-at-point))
+ (header (if (eq 'headline (org-element-type elem))
+ elem
+ (org-previous-visible-heading 1)
+ (org-element-at-point)))
+ (title (org-element-property :title header))
+ (parent (buffer-name))
+ (bname (format "%s [%s]" title parent)))
+ (if-let* ((b (get-buffer bname)))
+ (pop-to-buffer b)
+ (clone-indirect-buffer bname t)
+ (org-focus-mode -1)
+ (org-focus-child-mode)
+ (setq jao-org-focus--parent parent
+ jao-org-focus--section title)
+ (org-narrow-to-subtree)
+ (show-subtree)))))
+
+(defun jao-org-focus-redisplay ()
+ "Redisplay a focused buffer.
+
+Useful when its parent has been reorganised and the narrowing is out of
+sync."
+ (interactive)
+ (when-let* ((title jao-org-focus--section))
+ (widen)
+ (goto-char (point-min))
+ (when (re-search-forward (format "\\*+ %s" title) nil t)
+ (org-narrow-to-subtree)
+ (goto-char (point-min)))))
+
+(defun jao-org-focus-redisplay-children ()
+ "Find focused children and redisplay them."
+ (interactive)
+ (dolist (b (jao-org-focus-list))
+ (with-current-buffer b (jao-org-focus-redisplay))))
+
+(defun jao-org-focus-list (&optional any-parent)
+ "List of buffers that are focusing on a subtree of this one or its parent."
+ (let ((n (or jao-org-focus--parent (buffer-name))))
+ (seq-filter (lambda (b)
+ (let ((p (buffer-local-value 'jao-org-focus--parent b)))
+ (and p (or any-parent (string= n p)))))
+ (buffer-list))))
+
+(defvar jao-org-focus--focused-history nil)
+
+(defun jao-org-focus-switch (arg)
+ "Read with completion a focused child and pop to it.
+
+With arg, offer to switch to all children, regardless of their parent."
+ (interactive "P")
+ (let ((fl (mapcar 'buffer-name (jao-org-focus-list arg))))
+ (unless fl (error "No focused children"))
+ (pop-to-buffer
+ (completing-read "Focused child: " fl
+ nil t nil 'jao-org-focus--focused-history))))
+
+(defvar jao-org-focus-consult-buffer-source
+ `(:name "Focus buffers"
+ :category jao-org-focus-buffers
+ :action switch-to-buffer
+ :hidden t
+ :narrow ,(cons ?o "focus")
+ :history jao-org-focus--focused-history
+ :items ,(lambda () (mapcar 'buffer-name (jao-org-focus-list t)))))
+
+(define-minor-mode org-focus-mode
+ "A mode where keeping track of focused children is on by default."
+ :lighter " ◎"
+ :keymap '(("\C-cl" . jao-org-focus-switch)
+ ("\C-cR" . jao-org-focus-redisplay)
+ ("\C-co" . jao-org-focus))
+ (if org-focus-mode
+ (add-hook 'after-save-hook #'jao-org-focus-redisplay-children nil t)
+ (remove-hook 'after-save-hook #'jao-org-focus-redisplay-children t)))
+
+(define-minor-mode org-focus-child-mode
+ "A mode for the children of a focused org buffer."
+ :lighter " ◉"
+ :keymap org-focus-mode-map)
+
+(provide 'jao-org-focus)
+;;; jao-org-focus.el ends here
diff --git a/lib/doc/jao-org-links.el b/lib/doc/jao-org-links.el
index 88c0561..95f2d67 100644
--- a/lib/doc/jao-org-links.el
+++ b/lib/doc/jao-org-links.el
@@ -17,8 +17,9 @@
(funcall (or jao-org-open-pdf-fun #'jao-org--default-open) path page height))
(defun jao-org-links--open-pdf (link)
- "Open LINK in pdf-view-mode."
- (cond ((string-match "\\(.*\\)::\\([0-9]*\\)\\+\\+\\([[0-9]\\.*[0-9]*\\)" link)
+ "Open LINK using `jaor-org-open-pdf-fn'."
+ (cond ((string-match "\\(.*\\)::\\([0-9]*\\)\\+\\+\\([[0-9]\\.*[0-9]*\\)"
+ link)
(let* ((path (match-string 1 link))
(page (string-to-number (match-string 2 link)))
(height (string-to-number (match-string 3 link))))
@@ -101,21 +102,28 @@
(insert "\n#+startup: latexpreview\n\n"))
;;;###autoload
-(defun jao-org-pdf-goto-org (arg)
+(defun jao-org-pdf-goto-org (arg &optional file-name)
(interactive "P")
- (when (jao-pdf-is-pdf-file buffer-file-name)
- (let* ((file (jao-org-notes-find-for-pdf))
- (new (not (file-exists-p file)))
- (title (jao-pdf-title)))
- (when (or arg new) (org-store-link nil t))
+ (when (jao-pdf-is-pdf-file (or file-name buffer-file-name))
+ (let* ((file (jao-org-notes-find-for-pdf file-name))
+ (new (not (file-exists-p file))))
+ (if (and (not file-name) (or arg new))
+ (org-store-link nil t)
+ (when-let* ((fboundp 'jao-skim-current-doc)
+ (lnk (jao-pdf-skim-org-link nil)))
+ (kill-new lnk)))
(find-file-other-window file)
(when new
- (jao-org-insert-doc-skeleton title)
+ (jao-org-insert-doc-skeleton (jao-pdf-title file-name))
(org-insert-link)))))
;;;###autoload
(defun jao-org-pdf-goto-org* () (interactive) (jao-org-pdf-goto-org t))
+(defun jao-org-org-to-pdf-file ()
+ (expand-file-name (concat "doc/" (file-name-base buffer-file-name) ".pdf")
+ (file-name-directory jao-org-notes-dir)))
+
;;;###autoload
(defun jao-org-goto-pdf ()
(interactive)
diff --git a/lib/doc/jao-org-notes.el b/lib/doc/jao-org-notes.el
index bd82543..bd45723 100644
--- a/lib/doc/jao-org-notes.el
+++ b/lib/doc/jao-org-notes.el
@@ -1,6 +1,6 @@
;;; jao-org-notes.el --- A simple system for org note taking -*- lexical-binding: t; -*-
-;; Copyright (C) 2020, 2021, 2022, 2024 jao
+;; Copyright (C) 2020, 2021, 2022, 2024, 2025 jao
;; Author: jao <mail@jao.io>
;; Keywords: tools
@@ -57,7 +57,11 @@
(string-to-number (cadr m))))
(defun jao-org-notes--matches (lines)
- (mapcar (lambda (l) (jao-org-notes--clean-match (split-string l "\0" t))) lines))
+ (seq-keep (lambda (l)
+ (let ((m (split-string (or l "") "\0" t)))
+ (when (and (car m) (cadr m))
+ (jao-org-notes--clean-match m))))
+ lines))
(defun jao-org-notes--grep-rx (rx &rest rg-args)
(let ((default-directory jao-org-notes-dir))
@@ -71,14 +75,15 @@
(and (string-match-p "^[^:]+ + :" m) "tags")
"titles"))
-(defun jao-org-notes--consult-rg (prompt &optional cat no-req cmd)
+(defun jao-org-notes--consult-rg (prompt &optional cat no-req cmd initial)
(let ((default-directory (expand-file-name (or cat "") jao-org-notes-dir)))
(consult--read
- (consult--async-command #'jao-org-notes--rg-title-or-tags
- (consult--async-transform jao-org-notes--matches))
+ (consult--async-pipeline
+ (consult--process-collection #'jao-org-notes--rg-title-or-tags)
+ (consult--async-transform #'jao-org-notes--matches))
:prompt prompt
- :initial (consult--async-split-initial "")
- :add-history (concat (consult--async-split-initial (thing-at-point 'symbol)))
+ :initial (or initial "")
+ :add-history (thing-at-point 'symbol)
:require-match (not no-req)
:category 'jao-org-notes-lookup
:group 'jao-org-notes--consult-group
@@ -94,9 +99,10 @@
(cond ((file-exists-p (expand-file-name cat jao-org-notes-dir)) cat)
((yes-or-no-p "New category, create?") cat))))
-(defun jao-org-notes--insert-title ()
+(defun jao-org-notes--insert-title (&optional title)
(let* ((cat (jao-org-notes--cat))
- (title (file-name-base (jao-org-notes--consult-rg "Title: " cat t)))
+ (note (jao-org-notes--consult-rg "Title: " cat t nil title))
+ (title (file-name-base note))
(title (replace-regexp-in-string "^#" "" title)))
(when (not (string-empty-p title))
(let* ((base (replace-regexp-in-string " +" "-" (downcase title)))
@@ -160,16 +166,16 @@
(interactive)
(consult-ripgrep (expand-file-name (or cat "") jao-org-notes-dir) initial))
-(defun jao-org-notes-create ()
+(defun jao-org-notes-create (&optional title)
"Create a new note file, matching tags and titles with completion."
(interactive)
- (when (jao-org-notes--insert-title)
+ (when (jao-org-notes--insert-title title)
(org-insert-time-stamp (current-time) t t "#+date: " "\n")
(insert "#+tags: :"
(mapconcat #'identity (jao-org-notes--read-tags) ":")
":\n"))
(save-buffer)
- (buffer-file-name))
+ (current-buffer))
(defun jao-org-notes-backlinks ()
"Show a list of note files linking to the current one."
@@ -210,7 +216,8 @@
(defun jao-org-notes-setup (mnemonic)
"Set up the notes system, providing a mnemonic character for its org template."
(setq org-capture-templates
- (add-to-list 'org-capture-templates (jao-org-notes--template mnemonic))
+ (add-to-list 'org-capture-templates
+ (jao-org-notes--template mnemonic))
jao-org-notes--tags (jao-org-notes-all-tags))
(when (fboundp 'org-capture-upgrade-templates)
(org-capture-upgrade-templates org-capture-templates)))
diff --git a/lib/doc/jao-pdf.el b/lib/doc/jao-pdf.el
index 1ee74bc..162cd9a 100644
--- a/lib/doc/jao-pdf.el
+++ b/lib/doc/jao-pdf.el
@@ -1,6 +1,6 @@
;;; jao-pdf.el --- utilities for pdf files -*- lexical-binding: t; -*-
-;; Copyright (C) 2022 jao
+;; Copyright (C) 2022, 2025 jao
;; Author: jao <mail@jao.io>
;; Keywords: docs
@@ -96,5 +96,87 @@
(defun jao-pdf-zathura-org-link (title)
(jao-pdf--zathura-link (jao-pdf-zathura-file-info title)))
+(defun jao-zathura-open (file page)
+ (let ((id (jao-x11-search-window (jao-pdf-zathura-title-rx file))))
+ (if (string-blank-p id)
+ (progn
+ (when jao-xmonad-enabled (jao-x11-goto-ws 2))
+ (jao-shell-exec (jao-pdf-zathura-open-cmd file page)))
+ (let* ((page (if page (format " && xdotool type %dg" page) ""))
+ (cmd (format "xdotool windowactivate %s%s" id page)))
+ (jao-shell-exec cmd t)))))
+
+;;; Mac
+
+(when (eq system-type 'darwin)
+ (require 'jao-mac)
+ (defun jao-pdf-skim-org-link (title)
+ (when-let* ((fp (jao-skim-current-doc))
+ (file (file-name-nondirectory (car fp)))
+ (page (cadr fp))
+ (lnk (format "doc:%s::%s" file page)))
+ (org-make-link-string lnk title)))
+
+ (defun jao-pdf-insert-skim-org-link ()
+ (interactive)
+ (if-let* ((title (read-string "Title: "))
+ (lnk (jao-pdf-skim-org-link title)))
+ (insert lnk)
+ (user-error "Skim is not viewing any docs!"))))
+
+;;; Open doc functions
+(defvar jao-pdf-open-in-emacs t)
+
+(defun jao-find-or-open (file &optional page height)
+ (cond ((and jao-pdf-open-in-emacs window-system)
+ (let* ((buffs (buffer-list))
+ (b (catch 'done
+ (while buffs
+ (when (string-equal (buffer-file-name (car buffs)) file)
+ (throw 'done (car buffs)))
+ (setq buffs (cdr buffs))))))
+ (jao-afio-goto-docs)
+ (if b (pop-to-buffer b) (find-file file))
+ (when page (jao-doc-view-goto-page page height))))
+ (jao-river-enabled (jao-river-open-with-zathura file page))
+ (jao-sway-enabled (jao-sway-open-with-zathura file page))
+ ((eq system-type 'darwin) (jao-mac-open-in-skim file page))
+ (t (jao-zathura-open file page))))
+
+(defun jao-open-doc (&optional file page height)
+ (interactive)
+ (when-let (file (or file
+ (read-file-name "Document: "
+ (concat jao-org-dir "/doc/"))))
+ (funcall jao-open-doc-fun file page height)))
+
+(defun jao-select-pdf ()
+ (interactive)
+ (jao-buffer-same-mode '(pdf-view-mode doc-view-mode org-mode)
+ #'jao-afio-goto-docs))
+
+(defun jao-open-with-zathura ()
+ (interactive)
+ (when-let (f buffer-file-name)
+ (let ((p (jao-doc-view-current-page)))
+ (cond (jao-river-enabled (jao-river-open-with-zathura f p))
+ (jao-sway-enabled (jao-sway-open-with-zathura f p))
+ (t (jao-zathura-open f p))))))
+
+;;; doc:// links for browse-url
+
+(defun jao-open-doc-url (url &rest _)
+ (when (string-match "doc://\\([^?]+\\)\\(\\?.*\\)?" url)
+ (let ((file (match-string 1 url))
+ (page (when-let* ((qs (match-string 2 url))
+ (long (> (length qs) 1))
+ (ps (url-parse-query-string (substring qs 1)))
+ (pn (cadr (assoc "page" ps))))
+ (string-to-number pn))))
+ (jao-open-doc (expand-file-name (concat "doc/" file) jao-org-dir) page))))
+
+(add-to-list 'browse-url-handlers (cons "^doc://.+" 'jao-open-doc-url))
+
+
(provide 'jao-pdf)
;;; jao-pdf.el ends here