Accueil > Informatique > Emacs > org-protocol : partie 3

org-protocol : partie 3

mercredi 10 février 2021, par Vincent

Cet article est le dernier d’une série de trois autour d’org-protocol et org-roam

 partie 1 : marque-page et capture
 partie 2 : marque-page et notes roam
 partie 3 : gestion de documents pdf avec org-roam

Pré-requis et contexte

 Debian buster sid
 emacs 26+ (testé avec emacs 27 et emacs 28) en mode client/server
 straight pour la gestion de paquets d’emacs
 un bureau compatible avec freedesktop (gnome/xfce/ etc.)

Objectifs

L’objectif est de créer facilement des notes roam pour des fichiers pdf en essayant de pré-remplir certains champs du modèle de note à l’aide des meta-données. Une fois la note créée, elle pourra contenir des annotations synchronisées avec le fichier pdf.

Plus précisément, le déroulé sera le suivant :
 une fenêtre emacs client est ouverte (comment ça emacs n’est pas toujours ouvert sur votre bureau :) )
 clic droit sur un fichier pdf
 ouvrir le fichier avec emacs
 remplir la note roam pré-remplie
 C-c C-c pour enregistrer la note
 ouvrir la note, pour lire le pdf et l’annoter avec la possibilité de créer des liens avec d’autres notes roam

On obtient des notes bibliographiques qui s’intègrent parfaitement avec le système de gestion de connaissances mis en place dans les articles précédents.

installation de pdf-tools

Commençons par créer le répertoire qui accueillera une copie des fichiers pdf.

mkdir -p ~/Documents/Memo/pdfs

Pour ce qui concerne pdf-tools, il suffit de suivre les instructions d’installation de pdf-tools sur la page github du projet. Au chargement de pdf-tools la ligne (pdf-tools-install) déclenche la compilation du programme epdfinfo. La compilation nécessite les paquetages debian suivant :

apt-get install libpng-dev zlib1g-dev libpoppler-glib-dev  libpoppler-private-dev imagemagick automake

La fonction parsepdf se charge de :
 copier un pdf dans le répertoire Memo/pdfs ;
 récupérer les métadonnées du pdf ;
 de sortir une note roam préremplie.

Par ailleurs, un modèle est enregistré dans org-roam-capture-ref-templates et sera appelé via org-protocol.

(use-package pdf-tools
  :straight t
  :hook (org-load . org-pdftools-setup-link)
  (pdf-view-mode . pdf-misc-menu-bar-minor-mode)
  :config
  (setq-default pdf-view-display-size 'fit-page)
  (setq parsepdf-directory "~/Documents/Memo/pdfs")
 (setq pdf-annot-activate-created-annotations t)
 (define-key pdf-view-mode-map (kbd "C-s") 'isearch-forward)
 ;(add-hook 'pdf-view-mode-hook (lambda () (cua-mode 0)))
 (setq pdf-view-resize-factor 1.1)
 (define-key pdf-view-mode-map (kbd "h") 'pdf-annot-add-highlight-markup-annotation)
 (define-key pdf-view-mode-map (kbd "t") 'pdf-annot-add-text-annotation)
 (define-key pdf-view-mode-map (kbd "D") 'pdf-annot-delete)


  (defun parsepdf(fichier)
  """Ouvre un fichier pdf avec pdfview, récupère les informations et pré-rempli une note roam"
  (let* (
        (inputfile (replace-regexp-in-string "file:'\\(.*\\)'" "\\1" fichier ))
        (filename (concat (format-time-string "%Hh%M--%d-%m-%y--") (file-name-nondirectory inputfile) ))
        (valeurs '(()))
        (file (concat parsepdf-directory "/" filename))
        )

;    (message (concat "je travaille sur " file))

    ;;copie du fichier
    (copy-file inputfile file)
    ;;récupération des metadonnées
    ;(split-window-right)
    (find-file file)
     (let
         (
          (oldbufpdf (current-buffer))
          )
       (pdf-misc-display-metadata)
       (with-current-buffer "*PDF-Metadata*"
         (text-mode)
         (goto-char (point-min))
         (dolist (ligne (mapcar 'substring-no-properties (split-string (buffer-string) "\n")))
           (if  (string-match "\\s-*\\(.*?\\):\\(.*\\)" ligne )
	       (progn
		 (push (cons (match-string 1 ligne) (match-string 2 ligne ))  valeurs)
		 )
             )
           )
         )
                                        ;(pop valeurs)

       (kill-buffer  "*PDF-Metadata*")
       (kill-buffer oldbufpdf)

       )
                                        ; Écriture de la roam-note

      (let*  (
             (auteur (cdr (assoc "author" valeurs )))
             (motclefs (concat "\"" (replace-regexp-in-string "," "\" \"" (cdr (assoc "keywords" valeurs ))) "\""))
             (titre (cdr (assoc "title" valeurs )))
             (annee (max (nth 5 (parse-time-string (cdr (assoc "modified" valeurs ))))
                    (nth 5 (parse-time-string (cdr (assoc "created" valeurs ))))))
             )

	(if (equal "\"\"" motclefs)
	    (setq motclefs nil))

        (if (equal "" titre)
            (setq  titre   (replace-regexp-in-string ".pdf" ""  (file-name-nondirectory inputfile) ))
          )

	(if (equal "" auteur)
	    (setq auteur "%^{auteur}")
	  )

        (if (> annee 1970 )
            (setq annee  (format "%d" annee))
          (setq  annee "")
          )

	(setq titre (concat "%^{titre|" titre "}"))

        (concat
         "#+title:"
         titre
         "\n"
         "#+ROAM_KEY: file:"
         file
         "\n#+ROAM_TAGS: pdf " motclefs "\n"
         "[[file:" file "][%\\1]]\n"
	 "\n* Meta information\n"
         ":PROPERTIES: \n"
         ":AUTEUR: "
         auteur
         "\n"
                                        ;  ":JOURNAL: ${journaltitle}\n"
                                        ;  ":DATE: ${date}\n"
         ":TIMESTAMP: %T\n"
         ":ANNÉE: "
         annee
                                        ;  ":DOI: ${doi}\n"
                                        ;  ":URL: ${url}\n"
	 "\n:URL: \n:JOURNAL: "
         "\n:END:\n\n\n* Notes\n"
         ":PROPERTIES:\n"
         ":INTERLEAVE_PDF: "
          (replace-regexp-in-string "file:" "" file )
         "\n:END:"
         )

        )
      )
)
 :hook (pdf-view-mode . pdf-misc-menu-bar-minor-mode)
 :custom
(org-roam-capture-ref-templates
   '(("p" "ref" plain #'org-roam--capture-get-point "%(parsepdf \"${ref}\")%?" :file-name "pdfcapture:%<%Y%m%d%H%M%S>" :unnarrowed t)))
  
:init
(pdf-tools-install)

(add-to-list 'auto-mode-alist      '("\\.pdf\\'" . pdf-view-mode))

)

Installation de org-noter

Ce paquetage permet d’annoter les pdf dans un fichier org synchronisé.

(use-package org-noter
  :straight t
  :bind
   ("C-c r n" . org-noter)
  :config
  (setq org-noter-always-create-frame t
        org-noter-separate-notes-from-heading t
        org-noter-default-heading-title "Page $p$"
        org-noter-auto-save-last-location t
        org-noter-separate-notes-from-heading t
        org-noter-doc-property-in-notes t
        )
  (setq org-noter-property-doc-file "INTERLEAVE_PDF"
        org-noter-property-note-location "INTERLEAVE_PAGE_NOTE")
)

Intégration avec le bureau

Créons un fichier emacscapture.desktop dans le répertoire ~/.local/share/applications/.

[Desktop Entry]
Version=1.0
Name=Emacs (pdf capture)
GenericName=Emacs
GenericName[fr]=Emacs(Capture pdf)
Exec=emacsclient "org-protocol://roam-ref?template=p&ref=file:%U" 
Icon=emacs
Type=Application
Terminal=false
Categories=Utility;Development;TextEditor;
StartupWMClass=Emacs
Keywords=Text;Editor;Org;
MimeType=application/pdf;application/x-pdf;

et créons ou mettons à jour le fichier mimeapps.list (toujours dans le répertoire ~/.local/share/applications/ ) en ajoutant sous la clef [Added Applications] la ligne application/pdf=emacscapture.desktop.

on obtient par exemple ce fichier

[Added Applications]
application/pdf=emacscapture.desktop

Enfin mettons à jour le bureau
update-desktop-database ~/.local/share/applications/

Utilisation

Une fenêtre emacsclient étant ouverte, après un clic droit sur un fichier pdf, on ouvre avec EmacsCapture le fichier.

Une note-roam pré-remplie s’affiche, après l’avoir complétée : C-c C-c pour l’enregistrer.

Import d’un fichier pdf

On souhaite lire et commenter le pdf. (C-c r d pour sélectionner la note, C-c r n pour lire le pdf avec pdf-tools et org-noter)

Par exemple, si le fichier pdf contient une table des matières, on peut l’importer dans la note org-noter-create-skeleton ou . La navigation dans la note et dans le fichier pdf sera synchronisée.

Mise à jour d’un note en important la table des matières

On peut réaliser des annotations, soit dans la note,

Annotation synchronisée dans la note roam

soit dans le pdf.

Annotation enregistrée dans le pdf

Les possibilités sont nombreuses, je vous renvoie aux documentations des paquets pdf-tools et org-noter pour explorer toutes les possiblités.

Pour aller plus loin

 Capturer des captures d’écran dans des notes org-download
 Gérer une bibliographie orb, qui fait le lien entre org-roam, l’excellent org-ref et bibtex.

Et comme d’habitude le fichier init.el de synthèse.

Le fichier init.el qui résume les trois articles.