I'm using tab-bar to tabify my work in Emacs, and so far I found tabbar-ruler that basically adds an indicator to show when a file is modified.
It doesn't work by itself, apparently.
I added some pieces of code that let tabbar know the file is modified,
but it doesn't work when I revert my work.
I need some hook, if possible, to let emacs know that upon reaching a "don't have to save" state, it will udpate the tabbar.
This is the code so far:
(defadvice tabbar-buffer-tab-label (after fixup_tab_label_space_and_flag activate)
(setq ad-return-value
(if (and (buffer-modified-p (tabbar-tab-value tab))
(buffer-file-name (tabbar-tab-value tab)))
(concat " " (concat ad-return-value " "))
(concat " " (concat ad-return-value " ")))))
;; Called each time the modification state of the buffer changed.
(defun er/modification-state-change ()
(tabbar-set-template tabbar-current-tabset nil)
(tabbar-display-update))
(add-hook 'after-save-hook 'er/modification-state-change)
;; First-change-hook is called BEFORE the change is made.
(defun er/on-buffer-modification ()
(set-buffer-modified-p t)
(er/modification-state-change))
(add-hook 'first-change-hook 'er/on-buffer-modification)
;; Retrieve original state after revert is made.
(defun er/on-buffer-revert ()
(set-buffer-modified-p nil)
(er/modification-state-change))
(add-hook 'after-revert-hook 'er/on-buffer-revert)
The er/on-buffer-revert function is my attempt to at least reach a reverted buffer state.
Doesn't work either.
The first piece of code, btw, is just to add an additional space tabbar doesn't originaly have.
Any thoughts?
I know you asked this several years ago, but here's a working example that properly supports reverts. Note that it supports tabbar state correctly for the following situations:
buffer reverts
undo back to last saved state
changing the text to match what it was before the last save
(defun my-ignore-buffer-p ()
(not (buffer-file-name)))
(setq my-buffer-hashes (make-hash-table :test 'equal))
(defun my-set-buffer-hash ()
(puthash (current-buffer) (buffer-hash) my-buffer-hashes))
(defun my-get-buffer-hash ()
(gethash (current-buffer) my-buffer-hashes))
(defun my-buffer-hash-changed-p ()
(not (string= (buffer-hash) (my-get-buffer-hash))))
;; Hook save and change events to show modified buffers in tabbar
(defun on-saving-buffer ()
(tabbar-set-template tabbar-current-tabset nil)
(tabbar-display-update))
(defun on-modifying-buffer ()
(unless (my-ignore-buffer-p)
(my-set-buffer-hash)
(set-buffer-modified-p (buffer-modified-p))
(tabbar-set-template tabbar-current-tabset nil)
(tabbar-display-update)))
(defun after-modifying-buffer (begin end length)
(unless (my-ignore-buffer-p)
(set-buffer-modified-p (my-buffer-hash-changed-p))
(tabbar-set-template tabbar-current-tabset nil)
(tabbar-display-update)))
(add-hook 'after-save-hook 'on-saving-buffer)
(add-hook 'first-change-hook 'on-modifying-buffer)
(add-hook 'after-change-functions 'after-modifying-buffer)
Related
I have defined a .dir-locals.el file with the following content:
((python-mode . ((cr/virtualenv-name . "saas"))))
In my .emacs I have the following function to retrieve this value and provide a virtualenv path:
(defun cr/virtualenv ()
(cond (cr/virtualenv-name (format "%s/%s" virtualenv-base cr/virtualenv-name))
((getenv "EMACS_VIRTUAL_ENV") (getenv "EMACS_VIRTUAL_ENV"))
(t "~/.emacs.d/python")))
Finally, in my python-mode-hook list, I have this hook function:
(add-hook 'python-mode-hook 'cr/python-mode-shell-setup)
(defun cr/python-mode-shell-setup ()
(message "virtualenv-name is %s" cr/virtualenv-name)
(let ((python-base (cr/virtualenv)))
(cond ((and (fboundp 'ipython-shell-hook) (file-executable-p (concat python-base "/bin/ipython")))
(setq python-python-command (concat python-base "/bin/ipython"))
(setq py-python-command (concat python-base "/bin/ipython"))
(setq py-python-command-args '( "-colors" "NoColor")))
(t
(setq python-python-command (concat python-base "/bin/python"))
(setq py-python-command (concat python-base "/bin/python"))
(setq py-python-command-args nil)))))
When I open a new python file, the message logged by cr/python-mode-shell-setup indicates that cr/virtualenv-name is nil. However, when I C-h v the name, I get "saas" instead.
Obviously there's a load order issue here; is there a way to have my mode hook statements respond to directory-local variables?
This happens because normal-mode calls (set-auto-mode) and (hack-local-variables) in that order.
However hack-local-variables-hook is run after the local variables have been processed, which enables some solutions:
The first is to make Emacs run a new "local variables hook" for each major mode:
(add-hook 'hack-local-variables-hook 'run-local-vars-mode-hook)
(defun run-local-vars-mode-hook ()
"Run a hook for the major-mode after the local variables have been processed."
(run-hooks (intern (concat (symbol-name major-mode) "-local-vars-hook"))))
(add-hook 'python-mode-local-vars-hook 'cr/python-mode-shell-setup)
(Your original function can be used unmodified, with that approach.)
A second option is to utilise the optional LOCAL argument to add-hook that makes the specified function buffer-local. With this approach you could write your hook as follows:
(add-hook 'python-mode-hook 'cr/python-mode-shell-setup)
(defun cr/python-mode-shell-setup ()
(add-hook 'hack-local-variables-hook
(lambda () (message "virtualenv-name is %s" cr/virtualenv-name)
(let ((python-base (cr/virtualenv)))
(cond ((and (fboundp 'ipython-shell-hook) (file-executable-p (concat python-base "/bin/ipython")))
(setq python-python-command (concat python-base "/bin/ipython"))
(setq py-python-command (concat python-base "/bin/ipython"))
(setq py-python-command-args '( "-colors" "NoColor")))
(t
(setq python-python-command (concat python-base "/bin/python"))
(setq py-python-command (concat python-base "/bin/python"))
(setq py-python-command-args nil)))))
nil t)) ; buffer-local hack-local-variables-hook
i.e. python-mode-hook runs first and registers the anonymous function with hack-local-variables-hook for the current buffer only; and that function is then called after the local variables have been processed.
Lindydancer's comment prompts a third approach. It's not nearly as clean as the other two, but proved interesting regardless. I didn't like the idea of causing (hack-local-variables) to be called twice, but I see that if you set the local-enable-local-variables buffer-locally, it prevents (hack-local-variables) from doing anything, so you could do this:
(defun cr/python-mode-shell-setup ()
(report-errors "File local-variables error: %s"
(hack-local-variables)))
(set (make-local-variable 'local-enable-local-variables) nil)
(let ((python-base (cr/virtualenv)))
...))
Obviously that modifies the normal sequence of execution a little, so side effects may be possible. I was worried that if the same major mode is set by a local variable comment in the file, this might cause infinite recursion, but that doesn't actually appear to be a problem.
Local variable header comments (e.g. -*- mode: foo -*-) are handled by (set-auto-mode), so those are fine; but a mode: foo Local Variables: comment seems like it would be an issue as it is handled by (hack-local-variables), and so if the mode is set that way I thought it would cause recursion.
In practice I was able to trigger the problem by using a simple function as a 'mode' which did nothing more than try to run its hooks; however testing with a 'proper' mode did not exhibit the problem, so it's probably safe in reality. I didn't look into this further (as the other two solutions are much cleaner than this), but I would guess the delayed mode hooks mechanism probably explains it?
I'm trying to use Document View in Emacs to read PDFs, but I can't figure out how to make it behave similarly to the 'fit to width' command many PDF readers have. Is there an internal way to do this?
The following snippet defines a new minor-mode doc-view-autofit-mode, which I have activated below using doc-view-mode-hook. It works for me on Emacs 24.3 on Ubuntu 14.04, even to the point of resizing the zoom when I resize the window!
(There is usually a short resize delay thanks to doc-view-autofit-timer-start, but I'm happy to live with this.)
I take no credit for the solution; I found this code on the emacs-devel mailing list.
(require 'cl)
;;;; Automatic fitting minor mode
(defcustom doc-view-autofit-timer-start 1.0
"Initial value (seconds) for the timer that delays the fitting when
`doc-view-autofit-fit' is called (Which is when a window
configuration change occurs and a document needs to be fitted)."
:type 'number
:group 'doc-view)
(defcustom doc-view-autofit-timer-inc 0.02
"Value to increase (seconds) the timer (see `doc-view-autofit-timer-start')
by, if there is another window configuration change occuring, before
it runs out."
:type 'number
:group 'doc-view)
(defcustom doc-view-autofit-default-fit 'width
"The fitting type initially used when mode is enabled.
Valid values are: width, height, page."
:type 'symbol
:group 'doc-view)
(defvar doc-view-autofit-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-c W") 'doc-view-autofit-width)
(define-key map (kbd "C-c H") 'doc-view-autofit-height)
(define-key map (kbd "C-c P") 'doc-view-autofit-page)
map)
"Keymap used by `doc-view-autofit-mode'.")
(defun doc-view-autofit-set (type)
"Set autofitting to TYPE for current buffer."
(when doc-view-autofit-mode
(setq doc-view-autofit-type type)
(doc-view-autofit-fit)))
(defun doc-view-autofit-width ()
"Set autofitting to width for current buffer."
(interactive) (doc-view-autofit-set 'width))
(defun doc-view-autofit-height ()
"Set autofitting to height for current buffer."
(interactive) (doc-view-autofit-set 'height))
(defun doc-view-autofit-page ()
"Set autofitting to page for current buffer."
(interactive) (doc-view-autofit-set 'page))
(defun doc-view-autofit-fit ()
"Fits the document in the selected window's buffer
delayed with a timer, so multiple calls in succession
don't cause as much overhead."
(lexical-let
((window (selected-window)))
(if (equal doc-view-autofit-timer nil)
(setq doc-view-autofit-timer
(run-with-timer
doc-view-autofit-timer-start nil
(lambda ()
(if (window-live-p window)
(save-selected-window
(select-window window)
(cancel-timer doc-view-autofit-timer)
(setq doc-view-autofit-timer nil)
(cond
((equal 'width doc-view-autofit-type)
(doc-view-fit-width-to-window))
((equal 'height doc-view-autofit-type)
(doc-view-fit-height-to-window))
((equal 'page doc-view-autofit-type)
(doc-view-fit-page-to-window))))))))
(timer-inc-time doc-view-autofit-timer doc-view-autofit-timer-inc))))
(define-minor-mode doc-view-autofit-mode
"Minor mode for automatic (timer based) fitting in DocView."
:lighter " AFit" :keymap doc-view-autofit-mode-map :group 'doc-view
(when doc-view-autofit-mode
(set (make-local-variable 'doc-view-autofit-type)
doc-view-autofit-default-fit)
(set (make-local-variable 'doc-view-autofit-timer) nil)
(add-hook 'window-configuration-change-hook
'doc-view-autofit-fit nil t)
(doc-view-autofit-fit))
(when (not doc-view-autofit-mode)
(remove-hook 'window-configuration-change-hook
'doc-view-autofit-fit t)
(when doc-view-autofit-timer
(cancel-timer doc-view-autofit-timer)
(setq doc-view-autofit-timer nil))
(setq doc-view-autofit-type nil)))
(add-hook 'doc-view-mode-hook 'doc-view-autofit-mode)
It works for me:
(add-hook 'doc-view-mode-hook 'doc-view-fit-width-to-window)
Update: It doesn't work correctly if a conversion (to png or something else) is still ongoing (First opening the document). There is alternative, more reliable way, which handles this special case (it doesn't use hook at all but uses advice):
(defadvice doc-view-display (after fit-width activate)
(doc-view-fit-width-to-window))
The following is a slight modification of the answer by Chris -- it provides compatibility with functions like find-file-other-window -- e.g., when the selected-window is different than the one displaying the *.pdf file.
(defvar last-displayed-doc-view-buffer nil)
(defun get-last-displayed-doc-view-buffer ()
(setq last-displayed-doc-view-buffer (current-buffer)))
(add-hook 'doc-view-mode-hook 'get-last-displayed-doc-view-buffer)
(defun doc-view-autofit-fit ()
"Fits the document in the selected window's buffer
delayed with a timer, so multiple calls in succession
don't cause as much overhead."
(if (null doc-view-autofit-timer)
(setq doc-view-autofit-timer
(run-with-timer doc-view-autofit-timer-start nil (lambda ()
(let* (
(selected-window
(cond
((eq major-mode 'doc-view-mode)
(selected-window))
(t
(get-buffer-window last-displayed-doc-view-buffer))))
(current-buffer
(cond
((eq major-mode 'doc-view-mode)
(current-buffer))
(t
(get-buffer last-displayed-doc-view-buffer))))
(selected-fit
(when (buffer-live-p (get-buffer current-buffer))
(with-current-buffer (get-buffer current-buffer)
doc-view-autofit-type))) )
(when (window-live-p selected-window)
(with-selected-window selected-window
(when doc-view-autofit-timer (cancel-timer doc-view-autofit-timer))
(setq doc-view-autofit-timer nil)
(cond
((eq 'width selected-fit)
(doc-view-fit-width-to-window))
((eq 'height selected-fit)
(doc-view-fit-height-to-window))
((eq 'page selected-fit)
(doc-view-fit-page-to-window)))))))))
(timer-inc-time doc-view-autofit-timer doc-view-autofit-timer-inc)))
And, as noted in my earlier comment to Chris' answer, the following variables need definitions:
(defvar doc-view-autofit-timer nil)
(defvar doc-view-autofit-type nil)
Because the modification above adds a new function to the doc-view-mode-hook to obtain the current-buffer, which is needed for the function doc-view-autofit-fit, it is necessary to ensure that the latter function is appended to the end of the doc-view-mode-hook. So the change looks like this -- i.e., we add a t for the append argument:
(add-hook 'doc-view-mode-hook 'doc-view-autofit-mode t)
Everything else from Chris's answer that has not been superseded by the above modifications remain in effect.
TO DO:
Create a test to examine each page while scrolling to make certain that the view coincides with the autofit-type. Presently, errors occur in page size when dealing with a long *.pdf file.
Just a note: (require 'cl) is out of date. Since emacs-24.3 it should be
(require ‘cl-lib)
See http://www.emacswiki.org/emacs/CommonLispForEmacs
I have various things set up in my 'before-save-hook. For example, I run 'delete-trailing-whitespace. This is what I want in almost all occasions.
But sometimes, I'm working on files that are shared with other people, and the file already has a bunch of trailing whitespace. If I save the file, I'll get a big diff that's pretty confusing, as my change is buried in dozens or hundreds of meaningless changes. Yes, everyone could just tell their diff tool to not show whitespace changes, but that's something that everyone has to do every time they look at the diff. I'd rather not even have the whitespace change.
Is there anything I can do to save the file without the whitespace changes, short of starting a new instance of Emacs with no init.el file, or with a modified init.el that doesn't have the hook?
Here is how I save without triggering delete-trailing-whitespace:
C-x C-q C-x C-s C-x C-q: read-only, save, revert read-only
A simpler solution I came up with is that my fundamental-mode has no hooks installed, because I want it to be as plain as possible. Thus if I want to save a file without running hooks, I temporarily switch to fundamental-mode.
Based on a comment discussion with #Stefan, here are two possible (untested) solutions:
Use let:
(defun save-buffer-without-dtw ()
(interactive)
(let ((b (current-buffer))) ; memorize the buffer
(with-temp-buffer ; new temp buffer to bind the global value of before-save-hook
(let ((before-save-hook (remove 'delete-trailing-whitespace before-save-hook)))
(with-current-buffer b ; go back to the current buffer, before-save-hook is now buffer-local
(let ((before-save-hook (remove 'delete-trailing-whitespace before-save-hook)))
(save-buffer)))))))
Use unwind-protect:
(defun save-buffer-without-dtw ()
(interactive)
(let ((restore-global
(memq 'delete-trailing-whitespace (default-value before-save-hook)))
(restore-local
(and (local-variable-p 'before-save-hook)
(memq 'delete-trailing-whitespace before-save-hook))))
(unwind-protect
(progn
(when restore-global
(remove-hook 'before-save-hook 'delete-trailing-whitespace))
(when restore-local
(remove-hook 'before-save-hook 'delete-trailing-whitespace t))
(save-buffer))
(when restore-global
(add-hook 'before-save-hook 'delete-trailing-whitespace))
(when restore-local
(add-hook 'before-save-hook 'delete-trailing-whitespace nil t)))))
The problem with the second solution is that the order of functions in the before-save-hook may change.
Here's another solution:
(defvar my-inhibit-dtw nil)
(defun my-delete-trailing-whitespace ()
(unless my-inhibit-dtw (delete-trailing-whitespace)))
(add-hook 'before-save-hook 'my-delete-trailing-whitespace)
and then
(defun my-inhibit-dtw ()
(interactive)
(set (make-local-variable 'my-inhibit-dtw) t))
so you can M-x my-inhibit-dtw RET in the buffers where you don't want to trim whitespace.
I wrote a command inspired by Nicholas Douma's solution.
(defun olav-save-buffer-as-is ()
"Save file \"as is\", that is in read-only-mode."
(interactive)
(if buffer-read-only
(save-buffer)
(read-only-mode 1)
(save-buffer)
(read-only-mode 0)))
What we need to do is remove 'delete-trailing-whitespace from before-save-hook, save the buffer, then add it back.
This code will do that, but only remove and add it if it's there to begin with.
;; save the buffer, removing and readding the 'delete-trailing-whitespace function
;; to 'before-save-hook if it's there
(defun save-buffer-no-delete-trailing-whitespace ()
(interactive)
(let ((normally-should-delete-trailing-whitespace (memq 'delete-trailing-whitespace before-save-hook)))
(when normally-should-delete-trailing-whitespace
(remove-hook 'before-save-hook 'delete-trailing-whitespace))
(save-buffer)
(when normally-should-delete-trailing-whitespace
(add-hook 'before-save-hook 'delete-trailing-whitespace))))
(global-set-key (kbd "C-c C-s") 'save-buffer-no-delete-trailing-whitespace)
It also binds the command to (kbd C-c C-s), for convenience.
I am trying to uniquely identify a window,
so that I can select and delete the window if I press a key over again, though I am having trouble doing this.
(setq split-window-right-toggle-var nil)
(defun split-window-right-toggle ()
(interactive)
(if split-window-right-toggle-var
(progn
(right-split-undo)
(setq split-window-right-toggle-var nil))
(progn
(right-split-do)
(setq split-window-right-toggle-var t))))
(defun right-split-do ()
(interactive)
(split-window-right)
(other-window 1))
(defun right-split-undo ()
(interactive)
(other-window -1)
(delete-window))
The issue with this code is that it heavily depends on which window is active, there for can
change the state of my windows and delete the wrong window, can I uniquely give my window a name then target that window name for deletion ? I am really new at Emacs lisp and would appreciate any help thanks.
You can try out something like this:
(setq window-names (make-hash-table :test 'equal ))
(defun name-window ()
(interactive)
(let ((name (read-input "Name: ")))
(setf (gethash name window-names) (selected-window))))
(defun del-window ()
(interactive)
(let ((name (read-input "Name: ")))
(delete-window (gethash name window-names))))
(selected-window) returns a reference to the current window.
(next-window) returns the next window. Use Emacs' self documenting features
to find out more or refer to the manual.
Here is how I would write your command
(defvar ej-spit-window-saved nil)
(defun ej-split-window-right-toggle ()
"toggle split right"
(interactive)
(setq ej-split-window-saved
(if (and ej-split-window-saved
(frame-visible-p (window-frame ej-split-window-saved)))
(delete-window ej-split-window-saved)
(split-window-right))))
Notes
prefix functions/variables for easier debugging.
it's never too early to document code.
Since I am using org-mode to track my todo list in emacs, I like the iPhone app: MobileOrg, with it, I can access my todo list all day.
But here's the problem:
I have to manually org-mobile-push my changes from local file to mobile phone through dropbox, and org-mobile-pull the changes made by phone back.
How to make that automatically? Like adding some recipes in dotemacs file.
Add these two lines to dot emacs file:
(add-hook 'after-init-hook 'org-mobile-pull)
(add-hook 'kill-emacs-hook 'org-mobile-push)
With them, it automatically pulls the changes on emacs startup, and pushes the changes before emacs exits.
-- Update
If you never exit your Emacs, this solution might not work for you. So, another solution using idle timer
;; moble sync
(defvar org-mobile-sync-timer nil)
(defvar org-mobile-sync-idle-secs (* 60 10))
(defun org-mobile-sync ()
(interactive)
(org-mobile-pull)
(org-mobile-push))
(defun org-mobile-sync-enable ()
"enable mobile org idle sync"
(interactive)
(setq org-mobile-sync-timer
(run-with-idle-timer org-mobile-sync-idle-secs t
'org-mobile-sync)));
(defun org-mobile-sync-disable ()
"disable mobile org idle sync"
(interactive)
(cancel-timer org-mobile-sync-timer))
(org-mobile-sync-enable)
I just found out it is same as below answer, so, if you prefer the idle timer solution, please upvote tkf's answer.
I have something like this in my Emacs setting to do push and pull when I am away from computer.
(defvar my-org-mobile-sync-timer nil)
(defvar my-org-mobile-sync-secs (* 60 20))
(defun my-org-mobile-sync-pull-and-push ()
(org-mobile-pull)
(org-mobile-push)
(when (fboundp 'sauron-add-event)
(sauron-add-event 'my 3 "Called org-mobile-pull and org-mobile-push")))
(defun my-org-mobile-sync-start ()
"Start automated `org-mobile-push'"
(interactive)
(setq my-org-mobile-sync-timer
(run-with-idle-timer my-org-mobile-sync-secs t
'my-org-mobile-sync-pull-and-push)))
(defun my-org-mobile-sync-stop ()
"Stop automated `org-mobile-push'"
(interactive)
(cancel-timer my-org-mobile-sync-timer))
(my-org-mobile-sync-start)
Alternative is to put the following in cron job
(I found this here https://github.com/matburt/mobileorg-android/wiki/Scripting/):
emacs --batch --load ~/.emacs --eval "(org-mobile-pull)" --eval "(org-mobile-push)"
This code is taken from http://kenmankoff.com/2012/08/17/emacs-org-mode-and-mobileorg-auto-sync/, with a couple of details changed. You need to configure the variables in the beginning. This code will
Check every 30s whether MobileOrg has synced, and if so
Pull from MobileOrg.
Push to MobileOrg.
This is necessary to update the agenda views in MobileOrg.
With this behavior, you can be away from your computer, update some things in MobileOrg, sync, wait 30 seconds, sync again, and your mobile agenda view will be updated.
Whenever an org file is saved
Check whether the saved org file is supposed to be synced with MobileOrg, and if so
Wait for the user to become idle
Push to MobileOrg
Code for your .emacs file:
(require 'org-mobile)
;; Configure these two variables
(setq org-mobile-inbox-for-pull "~/Dropbox/org/mobile.org"
org-mobile-directory "~/Dropbox/MobileOrg")
(require 'gnus-async)
;; Define a timer variable
(defvar org-mobile-push-timer nil
"Timer that `org-mobile-push-timer' used to reschedule itself, or nil.")
;; Push to mobile when the idle timer runs out
(defun org-mobile-push-with-delay (secs)
(when org-mobile-push-timer
(cancel-timer org-mobile-push-timer))
(setq org-mobile-push-timer
(run-with-idle-timer
(* 1 secs) nil 'org-mobile-push)))
;; After saving files, start an idle timer after which we are going to push
(add-hook 'after-save-hook
(lambda ()
(if (or (eq major-mode 'org-mode) (eq major-mode 'org-agenda-mode))
(dolist (file (org-mobile-files-alist))
(if (string= (expand-file-name (car file)) (buffer-file-name))
(org-mobile-push-with-delay 10))))))
;; watch mobileorg.org for changes, and then call org-mobile-pull
(defun org-mobile-install-monitor (file secs)
(run-with-timer
0 secs
(lambda (f p)
(unless (< p (second (time-since (elt (file-attributes f) 5))))
(org-mobile-pull)
(org-mobile-push)))
file secs))
(defvar monitor-timer (org-mobile-install-monitor (concat org-mobile-directory "/mobileorg.org") 30)
"Check if file changed every 30 s.")
you can also push right after saving a note, like this:
(add-hook
'after-save-hook
(lambda ()
(if (string= buffer-file-name "<path to my notes.org>")
(org-mobile-push)
)
))
I use this elisp code from gist on my init.el and it works pretty well, except it doesn't have org-mobile-pull built in.
As a side solution, similar to Sandeep C's
;; for Emacs 24.3.1 insert next line
(require 'cl)
;; automatically org-mobile-push on save of a file
(add-hook
'after-save-hook
(lambda ()
(let (
(org-filenames (mapcar 'file-name-nondirectory (directory-files org-directory))) ; list of org file names (not paths)
(filename (file-name-nondirectory buffer-file-name)) ; list of the buffers filename (not path)
)
(if (find filename org-filenames :test #'string=)
(org-mobile-push)
)
)
)
)
I opted to simply push when saving, so I added this to my emacs init file:
(defun org-mobile-push-on-save ()
"Used in `after-save-hook'."
(when (memq this-command '(save-buffer save-some-buffers))
(org-mobile-push)))
(add-hook 'org-mode-hook
(lambda ()
(add-hook 'after-save-hook 'org-mobile-push-on-save nil 'make-local)))
In a nutshell, it adds an after-save-hook to org-mode buffers.
More info on the code:
https://emacs.stackexchange.com/a/14476/12694
https://stackoverflow.com/a/6141681/45881
For auto-pull, a timer as in other answers is probably a good way.