Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open PDF on a given page #208

Open
goderich opened this issue Jul 29, 2021 · 7 comments
Open

Open PDF on a given page #208

goderich opened this issue Jul 29, 2021 · 7 comments
Labels
Enhancement Would be nice to have

Comments

@goderich
Copy link

goderich commented Jul 29, 2021

Org-mode supports opening links on a specified page, e.g. [[file:document.pdf::5]] can be configured to open on page 5 of the file.

I tried looking through the manual (and the source code a bit), and I don't think Ebib supports this. I believe it would be a useful addition.

@joostkremers
Copy link
Owner

Could you be a bit more specific as to what exactly you're looking for? How would you specify the page to open? What would happen if you want to open the file on a different page?

@goderich
Copy link
Author

goderich commented Aug 7, 2021

Sure! I was thinking of the following cases: sometimes you have a proceedings or some other kind of collection of papers. It doesn't always makes sense to split the file or have separate copies of it. It might instead be simpler to link to different pages of the same file. Some time ago I tried a rudimentary manual version of paper/notes management in org-mode, and I utilized page links in this way.

How would you specify the page to open?

As per the initial post, by appending ::N to the filename, where N is the page number. Ebib wouldn't have to do much beyond parsing the link properly and passing the filename and page number to a user-defined function, like org-mode does. Afaik org doesn't open such links unless your settings clearly state the command with which to open them, so there's no need for a default case. Although just opening the file (without the page number) could be used as a fallback option, I think.

What would happen if you want to open the file on a different page?

I don't know if it's a big deal. It seems relatively simple to scroll to a different page if need be. It's just nice to be able to open the same file on the exact page a given paper starts -- for a dozen different papers!

If you mean being able to create different links that point to different pages in a PDF, then yes, that's exactly the point!

@joostkremers
Copy link
Owner

Sorry for the late reply. Thanks for the clarification, that does sound like a very good idea. Since I don't have much time to work on Ebib at the moment, I can't promise anything, but I'll put it on the to-do list.

@joostkremers joostkremers added the Enhancement Would be nice to have label Aug 16, 2021
@goderich
Copy link
Author

That's totally fine! I don't have much time at the moment myself, but if I have time before you do, I could try implementing it myself.

@Hugo-Heagren
Copy link
Contributor

Hugo-Heagren commented Nov 3, 2021

I remembered thinking this issue was interesting so I had a look today. I don't think the implementation is too difficult. Here's what I knocked up as a first go:

diff --git a/ebib.el b/ebib.el
index 06bb730..e988f65 100644
--- a/ebib.el
+++ b/ebib.el
@@ -2887,8 +2887,19 @@ file to choose."
       (beep))))
 
 (defun ebib--call-file-viewer (file)
-  "Open FILE with an external viewer."
-  (let ((file-full-path (ebib--expand-file-name file)))
+  "Open FILE with an external viewer.
+
+When FILE includes a delimiter `::', treat everything before the
+delimiter as a filepath, and everything after it as a location.
+After opening the file, go to the location. If the file is a pdf,
+the location is interpretted as a page number, otherwise as a
+line number."
+  (let* ((file-pos (and (string-match "\\`\\(.*\\)::\\(.*\\)\\'" file)
+			(match-string 2 file)))
+	 (file-full-path (ebib--expand-file-name
+			  (if file-pos
+			      (match-string 1 file)
+			    file))))
     (if (file-exists-p file-full-path)
         (let ((ext (file-name-extension file-full-path)))
           (ebib--ifstring (viewer (cdr (assoc ext ebib-file-associations)))
@@ -2900,7 +2911,13 @@ file to choose."
                 (call-process viewer nil 0 nil file-full-path))
             (message "Opening `%s'" file-full-path)
             (ebib-lower)
-            (find-file file-full-path)))
+            (find-file file-full-path))
+	  (when file-pos
+	    (widen)
+	    (let ((goto-func (cl-case ext
+			       ("pdf" 'pdf-view-goto-page)
+			       (t 'goto-line))))
+	    (funcall goto-func (string-to-number file-pos)))))
       (error "[Ebib] File not found: `%s'" (funcall ebib-file-name-mod-function file nil)))))
 
 (defun ebib-set-dialect (dialect)

This interprets the number after :: as a page number for pdfs, and a line number for text files. This was mostly a proof of concept that it would be possible to specify different 'handlers' for different document types because that might be relevant, though of course in practice the pdf one is the most important. Some questions about what the best implementation would be...

Ebib wouldn't have to do much beyond parsing the link properly and passing the filename and page number to a user-defined function, like org-mode does.

AFAICT, org mode handles :: internally. It has user-specifiable functions for opening files though (org-file-apps), but if there is a line or search string specified (after the ::) it ignore these and open in emacs anyway. It then has internal functionality for getting to the relevant line. How would you like to see this managed in ebib (mostly asking @goderich here)? There is already ebib-file-associations, but this is really for specifying non-emacs apps (what should ebib do with the page number in these cases? Mostly it will be impractical to jump to a page number in a external application, but some hardcore users might want to be able to specify their own ways of doing so?). It is worth noting that types of file will also need different functions for moving around---goto-line and pdf-view-goto-page are different (though this could all be wrapped inside an ebib function with an alist if need be).

Secondly, you are clearly inspired by org-mode's functionality, and it is significantly richer than just jumping to line/page numbers. Strings and special markers can be used to jump to headings in org files, or the first occurence of a search string. Would you also want/use this sort of functionality? I often work with pdfs with sections and bookmarks, and I know it would sometimes be useful for me to be able to jump to those.

Some housekeeping: would we want to display the full contents of the file field in things like the prompt for choosing files, or parse out the file path itself (and maybe make the page reference available as metadata to something like marginalia)?

Any other thoughts? I'd be happy to tidy up the code above and submit a PR.


A slightly different thought. I would use this feature in a way which would produce a new problem. I'm working on an essay which refers to lots of different papers, all published in the same book. I have one pdf of the book. I could carefully mark up all my entries, open one and read it for a while, then open another one and... be dumped in the same buffer as the first, losing where I was with the first paper (having been moved to the beginning of the second), because emacs recognises the file is already open.

To avoid this, you could set some kind of attribute or local variable for each buffer ebib opens, with the id of the associated entry. Then it would be possible to create and distinguish buffers of the same file but different entries from each other (I think these are called indirect buffers?). For the user's sake it might also be good to change the name of each buffer to a string representative of the entry (like "$author | $title"--this is actually a small QOL I've been thinking about doing personally anyway).

@goderich
Copy link
Author

goderich commented Nov 4, 2021

Thanks @Hugo-Heagren! I actually use an external application for PDFs (zathura), and I defined a setting to open PDFs from org-mode on a given page in zathura. If this gets implemented for ebib, I would do the same thing: open the files in an external application. Which is why I said "used-defined function" (or perhaps a variable): only being able to use this inside Emacs is not how I envisioned this.

@joostkremers
Copy link
Owner

Ebib wouldn't have to do much beyond parsing the link properly and passing the filename and page number to a user-defined function, like org-mode does.

AFAICT, org mode handles :: internally. It has user-specifiable functions for opening files though (org-file-apps), but if there is a line or search string specified (after the ::) it ignore these and open in emacs anyway. It then has internal functionality for getting to the relevant line. How would you like to see this managed in ebib (mostly asking @goderich here)? There is already ebib-file-associations, but this is really for specifying non-emacs apps (what should ebib do with the page number in these cases? Mostly it will be impractical to jump to a page number in a external application, but some hardcore users might want to be able to specify their own ways of doing so?).

As @goderich already mentioned, this should work for external apps as well. PDF viewers, at least the proper ones, allow some way to specify a page number on the command line, and I'd like Ebib to support that. ebib-file-associations should remain the central place to register what to do with files, depending on the file extension.

That means ebib-file-associations should be extended in two ways. It should support arguments, including optional ones, because it also work for file fields that don't specify a page number, and it should support specifying an Elisp function instead of an external command.

This way, the information following :: can be anything you want, you just have to make sure the function or external command being called supports whatever is passed to it.

Some housekeeping: would we want to display the full contents of the file field in things like the prompt for choosing files, or parse out the file path itself (and maybe make the page reference available as metadata to something like marginalia)?

Initially, I'd display the full contents in the prompt. Of course, it would be nice to have it available for marginalia, but not everyone uses it, so it would be more appropriate to have that as an user-configurable option, but that can be added later on.

To avoid this, you could set some kind of attribute or local variable for each buffer ebib opens, with the id of the associated entry. Then it would be possible to create and distinguish buffers of the same file but different entries from each other (I think these are called indirect buffers?).

Yes, this sounds like a job for indirect buffers.

For the user's sake it might also be good to change the name of each buffer to a string representative of the entry (like "$author | $title"--this is actually a small QOL I've been thinking about doing personally anyway).

Sounds pretty neat.

I'd definitely include something like this if you were to create a PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement Would be nice to have
Projects
None yet
Development

No branches or pull requests

3 participants