emacs-orgmode
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[O] A proposal to integrate org-mode with bookmark+ (bookmark plus / bmk


From: 曾俊賢
Subject: [O] A proposal to integrate org-mode with bookmark+ (bookmark plus / bmkp) , org-bookmark and evince for bookmarking source code and pdf documents with exact coordinate
Date: Sun, 17 Feb 2013 08:25:13 +0800 (CST)

Hi there. 


I'm very interested in the potential applications of org-mode, and spent some 
time to write some code to facilitate the integration between bookmark+ and 
evince.

I'd like to share the code with you and discuss with you about it.


There are primarily two use cases.

- To bookmark source code files (*.c *.h) with bookmark+

   - essentially there's already org-bookmark.el in the contrib. accompanying 
org-mode.

   - when browsing codes, I bookmark with C-x r m , then enter the name, then a 
bookmark is created for me

   - then copy this bookmark with C-c l,then in the org file C-c C-l to insert 
this bookmark link

   - I made two changes here;

     - when opening a bookmark link, I need to ensure that bookmark+'s 
*Bookmark List* buffer is open in case it opens the vallina bookmark list

     - really need the opened file shown in the other buffer

   - the changes I made:
================================================================
diff --git a/home/sig/src/org-mode/contrib/lisp/org-bookmark.el 
b/home/sig/Dropbox/emacs/lisp/org-bookmark.el
index 5c669b0..170bd57 100644
--- a/home/sig/src/org-mode/contrib/lisp/org-bookmark.el
+++ b/home/sig/Dropbox/emacs/lisp/org-bookmark.el
@@ -52,7 +52,9 @@ Otherwise prompt the user for the right bookmark to use."
 
 (defun org-bookmark-open (bookmark)
   "Visit the bookmark BOOKMARK."
-  (bookmark-jump bookmark))
+  (unless (get-buffer "*Bookmark List*")
+    (bookmark-bmenu-list))
+  (bookmark-jump-other-window bookmark))
 
 (defun org-bookmark-store-link ()
   "Store a link to the current line's bookmark in bookmark list."
===============================================================
- To bookmark pdf files, which gets a little bit awkward...

  - need to modify evince and create a global minor mode (in bmkp-evince.el 
attached at the end of this mail) to handle the dbus communication

  - pulled evince following https://live.gnome.org/Evince/GettingEvince

  - I reused the syncview / syncsource calls, testing if auctex is present; if 
not, then fall back into vallina mode in which

  - when C-<mouse click> in evince, send a syncsource dbus message with 
filename, page number and y coordinate

    - the global minor mode picks up the syncsource message and add a 
customized bookmark with customized handler

    - then copy this bookmark with C-c l,then in the org file C-c C-l to insert 
this bookmark

  - when following the bookmark link in an org file, call the customized 
handler,

    - which in turn calls syncview, which opens the pdf file and scroll the 
document to the place bookmarked

  - know issues

    - when the file is not already open, the call to syncview will open the 
file; however the scrolling is broken somehow; any following call to syncview 
works just fine; don't know why...

    - I tried to make autoloads work in  bmkp-evince.el but failed; don't know 
why...

===============================================================
diff --git a/libview/ev-view.c b/libview/ev-view.c
index dd6b728..91bc096 100644
--- a/libview/ev-view.c
+++ b/libview/ev-view.c
@@ -3055,13 +3055,15 @@ ev_view_synctex_backward_search (EvView *view,
     gint x_new = 0, y_new = 0;
     EvSourceLink *link;
 
-    if (!ev_document_has_synctex (view->document))
-        return FALSE;
 
     if (!get_doc_point_from_location (view, x, y, &page, &x_new, &y_new))
         return FALSE;
 
-    link = ev_document_synctex_backward_search (view->document, page, x_new, 
y_new);
+    if (ev_document_has_synctex (view->document))
+        link = ev_document_synctex_backward_search (view->document, page, 
x_new, y_new);
+    else
+        link = 
ev_source_link_new(g_path_get_basename(ev_document_get_uri(view->document)), 
page+1, y_new);
+
     if (link) {
         g_signal_emit (view, signals[SIGNAL_SYNC_SOURCE], 0, link);
         ev_source_link_free (link);
@@ -6023,7 +6025,16 @@ ev_view_highlight_forward_search (EvView       *view,
     GdkRectangle view_rect;
 
     if (!ev_document_has_synctex (view->document))
-        return;
+    {
+        page=link->line-1;
+        ev_document_model_set_page (view->model, page);
+        EvRectangle rect;
+        GdkRectangle view_rect;
+        view_rect.x=0;    view_rect.y=0;    view_rect.width=0;  
view_rect.height=0;
+        rect.x1=0;  rect.y1=link->col;  rect.x2=0;  rect.y2=link->col;
+        _ev_view_transform_doc_rect_to_view_rect (view, page, &rect, 
&view_rect);
+        ensure_rectangle_is_visible (view, &view_rect);
+    }else{
 
     mapping = ev_document_synctex_forward_search (view->document, link);
     if (!mapping)
@@ -6038,6 +6049,7 @@ ev_view_highlight_forward_search (EvView       *view,
 
     _ev_view_transform_doc_rect_to_view_rect (view, page, &mapping->area, 
&view_rect);
     ensure_rectangle_is_visible (view, &view_rect);
+    }
     gtk_widget_queue_draw (GTK_WIDGET (view));
 }
 
diff --git a/shell/ev-window.c b/shell/ev-window.c
index 97f4a90..b6414a1 100644
--- a/shell/ev-window.c
+++ b/shell/ev-window.c
@@ -7006,6 +7006,16 @@ handle_sync_view_cb (EvEvinceWindow        *object,
         gtk_window_present_with_time (GTK_WINDOW (window), timestamp);
     }
 
+    else if (window->priv->document) {
+        EvSourceLink link;
+        link.filename = (char *) source_file;
+        g_variant_get (source_point, "(ii)", &link.line, &link.col);
+        ev_view_highlight_forward_search (EV_VIEW (window->priv->view), &link);
+        gtk_window_present_with_time (GTK_WINDOW (window), timestamp);
+    }else {
+        g_message("FILE NOT OPENED!! source_file: %s", source_file);
+        return FALSE;
+    }
     ev_evince_window_complete_sync_view (object, invocation);
 
     return TRUE;
===============================================================
- and here comes bmkp-evince.el
===============================================================
;;;###autoload (autoload 'obmkp-evince-dbus-p "bmkp-evince")
(defun obmkp-evince-dbus-p (&rest options)
  "Return non-nil, if evince is installed and accessible via DBUS.
Additional OPTIONS may be given to extend the check.  If none are
given, only the minimal requirements needed by backward search
are checked.  If OPTIONS include `:forward', which is currently
the only option, then additional requirements needed by forward
search are checked, too."
  (and (not (featurep 'xemacs)) ; XEmacs 21.4 has no `require' with
                    ; arity 3, and no dbus support anyway.
       (require 'dbus nil :no-error)
       (functionp 'dbus-register-signal)
       (getenv "DBUS_SESSION_BUS_ADDRESS")
       (executable-find "evince")
       (or (not (memq :forward options))
       (let ((spec (dbus-introspect-get-method
            :session "org.gnome.evince.Daemon"
            "/org/gnome/evince/Daemon"
            "org.gnome.evince.Daemon"
            "FindDocument")))
         ;; FindDocument must exist, and its signature must be (String,
         ;; Boolean, String).  Evince versions between 2.30 and 2.91.x
         ;; didn't have the Boolean spawn argument we need to start evince
         ;; initially.
         (and spec
          (equal '("s" "b" "s")
             (delq nil (mapcar (lambda (elem)
                         (when (and (listp elem)
                            (eq (car elem) 'arg))
                           (cdr (caar (cdr elem)))))
                       spec))))))))

;;;###autoload (autoload 'bmkp-jump-evince "bmkp-evince")
(defun bmkp-jump-evince (bookmark)
  "BOOKMARK is a bookmark name or a bookmark record."
  (message "  ;; Implements the `handler' ")
  (let* 
      ((file       (bookmark-prop-get bookmark 'filename))
     (apage  (bookmark-prop-get bookmark 'page))
     (acoory  (bookmark-prop-get bookmark 'coory)))
    (let* ((uri (concat "file://" file))
      (message uri)
       (owner (dbus-call-method
           :session "org.gnome.evince.Daemon"
           "/org/gnome/evince/Daemon"
           "org.gnome.evince.Daemon"
           "FindDocument"
           uri
           t)))
      (if owner
;      (message "owner")
      (dbus-call-method
       :session owner
       "/org/gnome/evince/Window/0"
       "org.gnome.evince.Window"
       "SyncView"
       file;(buffer-file-name)
       (list :struct :int32 apage :int32 acoory)
       :uint32 (let ((time (float-time)))
             ;; FIXME: Evince wants a timestamp as UInt32, but POSIX time
             ;; is too large for emacs integers on 32 bit systems.  Emacs
             ;; 24.2 will allow providing DBUS ints as floats, and this
             ;; dbus version will be identifiable by its new variables
             ;; `dbus-compiled-version' and `dbus-runtime-version'.  But
             ;; it seems providing just 1 as timestamp has no negative
             ;; consequences, anyway.
             (if (> most-positive-fixnum time)
             (round time)
               1)))
       (error "Couldn't find the Evince instance for %s" uri)))
    ))

;;;###autoload (autoload 'obmkp-source-correlate-sync-source "bmkp-evince")
(defun obmkp-source-correlate-sync-source (file linecol &rest ignored)
  "Show TeX FILE with point at LINECOL.
This function is called when emacs receives a SyncSource signal
emitted from the Evince document viewer.  IGNORED absorbs an
unused id field accompanying the DBUS signal sent by Evince-3.0.0
or newer."
  ;; FILE may be given as relative path to the TeX-master root document or as
  ;; absolute file:// URL.  In the former case, the tex file has to be already
  ;; opened.
(message "obmkp-source-correlate-sync-source")
 (let* 
     (
      (ctime    (current-time))
      (f (condition-case nil
         (progn
           (require 'url-parse)
           (aref (url-generic-parse-url file) 6)
           )
       ;; For Emacs 21 compatibility, which doesn't have the
       ;; url package.
       (file-error (replace-regexp-in-string "^file://" "" file))
       ))
      (apage (car linecol))
      (acoory (cadr linecol))
      (bookmark-name (format "%i:address@hidden" apage acoory 
(file-name-nondirectory f) ))
      )
  (bookmark-store bookmark-name
          `((filename . ,f)
            (handler  . bmkp-jump-evince)
            (version  . "20130210")
            (page     . ,apage)
            (coory   . ,acoory)
            (notes    . "")
            (visits       . 0)
            (time         . ,ctime)
            (created      . ,ctime)
            )
                  nil nil nil)
  (let ((new  (bmkp-bookmark-record-from-name bookmark-name 'NOERROR)))
    (unless (memq new bmkp-latest-bookmark-alist)
      (setq bmkp-latest-bookmark-alist  (cons new bmkp-latest-bookmark-alist)))
    (bookmark-bmenu-surreptitiously-rebuild-list nil)
    new)
   )
  )

;;;###autoload (autoload 'obmkp-source-correlate-mode "bmkp-evince")
(define-minor-mode obmkp-source-correlate-mode
  "Minor mode for forward and inverse search.

If enabled, the viewer can be advised to show the output page
corresponding to the point in the source and vice versa.

The method to be used can be controlled with the variable
`TeX-source-correlate-method'.  Currently source specials or
SyncTeX are recognized."
  ;:group 'TeX-view
  ;; Since this is a global minor mode and we don't want to require
  ;; tex.el when the mode variable is set, the mode function is called
  ;; explicitely (if necessary) in `VirTeX-common-initialization'.  We
  ;; do it there because otherwise `kill-all-local-variables' would
  ;; reset `TeX-source-correlate-output-page-function' which is
  ;; buffer-local.
  :global t

;  (obmkp-set-mode-name 'obmkp-source-correlate-mode t t)
;  (setq obmkp-source-correlate-start-server-flag obmkp-source-correlate-mode)
  ;; Register Emacs for the SyncSource DBUS signal emitted by Evince.
  (when (obmkp-evince-dbus-p)
    (dbus-register-signal
     :session nil "/org/gnome/evince/Window/0"
     "org.gnome.evince.Window" "SyncSource"
     'obmkp-source-correlate-sync-source))
;  (unless obmkp-source-correlate-method-active
;    (setq obmkp-source-correlate-method-active
;       (if (eq obmkp-source-correlate-method 'auto)
;           (obmkp-source-correlate-determine-method)
;         obmkp-source-correlate-method)))
;  (when (eq obmkp-source-correlate-method-active 'synctex)
;    (setq obmkp-source-correlate-output-page-function
;       (when obmkp-source-correlate-mode
;         'obmkp-synctex-output-page)))
)
(provide 'bmkp-evince)
===============================================================




reply via email to

[Prev in Thread] Current Thread [Next in Thread]