#+title: Trot: TRAMP Org Noter integration
* Usage
Remember to configure the hook in order to actually enable this functionality:
#+BEGIN_SRC emacs-lisp :eval no
;; `add-hook' might be preferable.
;; I like to know that nothing else is going on.
(setopt org-noter-open-document-functions '(trot-open))
#+END_SRC
* materials
:PROPERTIES:
:header-args: :results verbatim :cache yes
:END:
Org Noter prioritizes the hook ~org-noter-open-document-functions~.
There's nothing in it by default, so anything I put there will be called.
Its functions take one argument, the value of the org property specifying the file Noter should use.
** We'll need to determine whether or not the notes file itself is being accessed through TRAMP:
#+BEGIN_SRC emacs-lisp
(cons (tramp-tramp-file-p "/home/ty/")
(tramp-tramp-file-p "/ssh:tykozic.net:/home/ty/"))
#+END_SRC
#+RESULTS[093b86cb0c40f4208689e04a188d69d273b9e171]:
: (nil . t)
** If it is, parse it to obtain the TRAMP location
#+BEGIN_SRC emacs-lisp
(tramp-dissect-file-name "/ssh:tykozic.net:/home/ty/")
;; causes error: not a tramp file name
;;(tramp-dissect-file-name "/home/ty/test.txt")
#+END_SRC
#+RESULTS[05e2e72c58c14b39e15c47b2632ab8f8059e92d2]:
: (tramp-file-name "ssh" nil nil "tykozic.net" nil "/home/ty/" nil)
** Assume no hops, and rebuild the file of the document
#+BEGIN_SRC emacs-lisp :eval no :noweb-ref code
(defun trot-ensure-suffix (suffix str)
(if (string-suffix-p suffix str)
str
(concat str suffix)))
(defun trot-tramp-substitute-file (tramp-file-string new-local-name)
(let ((old (tramp-dissect-file-name tramp-file-string)))
(tramp-make-tramp-file-name
old
(if (file-name-absolute-p new-local-name)
new-local-name
(concat (trot-ensure-suffix "/" (tramp-file-name-localname old))
new-local-name)))))
#+END_SRC
#+BEGIN_SRC emacs-lisp :noweb yes
<<code>>
(format "%s\n%s"
(trot-tramp-substitute-file
"/ssh:ty@tykozic.net:/home/ty/sync"
"ref/document.pdf")
(trot-tramp-substitute-file
"/ssh:ty@tykozic.net:/home/ty/sync/"
"/somewhere/else.epub"))
#+END_SRC
#+RESULTS[5e8cfbfce9b70405b730713bdb0936dd68d0c75b]:
: "/ssh:ty@tykozic.net:/home/ty/sync/ref/document.pdf
: /ssh:ty@tykozic.net:/somewhere/else.epub"
** But we won't use that file directly; we'll download a temporary copy and return its buffer
#+BEGIN_SRC emacs-lisp :eval no :noweb-ref code
(defun trot-locally-accessible-copy (file)
"Returns the path to a locally accessible copy of FILE.
Therefore, if FILE is already accessible, returns FILE. Otherwise
invokes TRAMP."
(or (file-local-copy file)
file))
#+END_SRC
* Putting it all together
#+BEGIN_SRC emacs-lisp :eval no :noweb-ref code
(defun trot-open (doc-path)
"Function for `org-noter-open-document-functions'.
If the notes file is opened via TRAMP, open a local copy of the document
file instead of attempting to open it using TRAMP. Otherwise, defer to
org noter's fallback methods of opening it."
(when (tramp-tramp-file-p default-directory)
(find-file-noselect
(trot-locally-accessible-copy
(trot-tramp-substitute-file default-directory doc-path)))))
#+END_SRC
* Final tangle
#+BEGIN_SRC emacs-lisp :tangle trot.el :noweb yes
;;; trot.el --- TRAMP with Org Noter using local copies -*- lexical-binding: t; -*-
;; Copyright (C) 2025 Ty Kozic
;; Author: Ty Kozic <tykozic@posteo.net>
;; Created: 16 Nov 2025
;; URL: https://tykozic.net/fossil/emacs-trot
;; This file is not part of GNU Emacs.
;; Copyright 2025 Ty Kozic
;; This file is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published
;; by the Free Software Foundation, either version 3 of the License,
;; or (at your option) any later version. This file 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 file. If not, see
;; <https://www.gnu.org/licenses/>.
;; Tangled from =trot.org=.
<<code>>
(provide 'trot)
;;; trot.el ends here
#+END_SRC