原文地址:https://raw.githubusercontent.com/lujun9972/lujun9972.github.com/source/Emacs之怒/MobileOrg的一个BUG.org
MobileOrg中其实有一个BUG,就是不能在手机端连续修改同一个entry两次,因为MobileOrg手机端会记录下每次修改手机端上的旧内容和新内容,并且在 org-mobile-pull 的时候对比记录的旧内容是否与电脑上当前的内容相同。
然而...MobileOrg手机端在未与电脑端(org-mobile-push后再同步)同步前是不会更改真正的内容的!
也就是说,假设对一个entry的内容更改过程是 A->B->C,那么本来我们想象应该是记录成这样的:
* entry ** old A ** new B * entry ** old B ** new C
但实际上记录的是
* entry ** old A ** new B * entry ** old A ** new C
因此只能应用 A->B 的变更,而无法应用 B->C 的变更。
一个解决方案是修改 org-mobile-force-mobile-change 来强制应用新值,这对非 body 类的操作还是比较适合的
(setq org-mobile-force-mobile-change '(todo todostate tags priority heading addheading))
但是对于 body 类的修改来说是不太适合的,因为mobileorg的 clock-in, clock-out 操作会修改 body 的内容,而这部分内容修改起来很麻烦
一个更完善的解决方案可能是自定义新的 org-mobile-edit 函数,然后设置到 org-mobile-action-alist 变量中. 在这个函数中,对于 body 类修改使用 (patch (diff old new)) 的方法可能更适合。
(defun org-mobile-edit (what old new) "Edit item WHAT in the current entry by replacing OLD with NEW. WHAT can be \"heading\", \"todo\", \"tags\", \"priority\", or \"body\". The edit only takes place if the current value is equal (except for white space) the OLD. If this is so, OLD will be replace by NEW and the command will return t. If something goes wrong, a string will be returned that indicates what went wrong." (let (current old1 new1 level) (if (stringp what) (setq what (intern what))) (cond ((memq what '(todo todostate)) (setq current (org-get-todo-state)) (cond ((equal new "DONEARCHIVE") (org-todo 'done) (org-archive-subtree-default)) ((equal new current) t) ; nothing needs to be done ((or (equal current old) (eq org-mobile-force-mobile-change t) (memq 'todo org-mobile-force-mobile-change)) (org-todo (or new 'none)) t) (t (error "State before change was expected as \"%s\", but is \"%s\"" old current)))) ((eq what 'tags) (setq current (org-get-tags) new1 (and new (org-split-string new ":+")) old1 (and old (org-split-string old ":+"))) (cond ((org-mobile-tags-same-p current new1) t) ; no change needed ((or (org-mobile-tags-same-p current old1) (eq org-mobile-force-mobile-change t) (memq 'tags org-mobile-force-mobile-change)) (org-set-tags-to new1) t) (t (error "Tags before change were expected as \"%s\", but are \"%s\"" (or old "") (or current ""))))) ((eq what 'priority) (let ((case-fold-search nil)) (when (looking-at org-complex-heading-regexp) (let ((current (and (match-end 3) (substring (match-string 3) 2 3)))) (cond ((equal current new) t) ;no action required ((or (equal current old) (eq org-mobile-force-mobile-change t) (memq 'tags org-mobile-force-mobile-change)) (org-priority (and new (string-to-char new)))) (t (error "Priority was expected to be %s, but is %s" old current))))))) ((eq what 'heading) (let ((case-fold-search nil)) (when (looking-at org-complex-heading-regexp) (let ((current (match-string 4))) (cond ((equal current new) t) ;no action required ((or (equal current old) (eq org-mobile-force-mobile-change t) (memq 'heading org-mobile-force-mobile-change)) (goto-char (match-beginning 4)) (insert new) (delete-region (point) (+ (point) (length current))) (org-set-tags nil 'align)) (t (error "Heading changed in MobileOrg and on the computer"))))))) ((eq what 'addheading) (if (org-at-heading-p) ; if false we are in top-level of file (progn ;; Workaround a `org-insert-heading-respect-content' bug ;; which prevents correct insertion when point is invisible (org-show-subtree) (end-of-line 1) (org-insert-heading-respect-content t) (org-demote)) (beginning-of-line) (insert "* ")) (insert new)) ((eq what 'refile) (org-copy-subtree) (org-with-point-at (org-mobile-locate-entry new) (if (org-at-heading-p) ; if false we are in top-level of file (progn (setq level (org-get-valid-level (funcall outline-level) 1)) (org-end-of-subtree t t) (org-paste-subtree level)) (org-paste-subtree 1))) (org-cut-subtree)) ((eq what 'delete) (org-cut-subtree)) ((eq what 'archive) (org-archive-subtree)) ((eq what 'archive-sibling) (org-archive-to-archive-sibling)) ((eq what 'body) (setq current (buffer-substring (min (1+ (point-at-eol)) (point-max)) (save-excursion (outline-next-heading) (point)))) (if (not (string-match "\\S-" current)) (setq current nil)) (cond ((org-mobile-bodies-same-p current new) t) ; no action necessary ((or (org-mobile-bodies-same-p current old) (eq org-mobile-force-mobile-change t) (memq 'body org-mobile-force-mobile-change)) (save-excursion (end-of-line 1) (insert "\n" new) (or (bolp) (insert "\n")) (delete-region (point) (progn (org-back-to-heading t) (outline-next-heading) (point)))) t) ((or (memq 'bodymerge org-mobile-force-mobile-change)) (save-excursion (let* ((fileA (make-temp-file "org-mobile" nil "A" old)) (fileB (make-temp-file "org-mobile" nil "B" new)) (fileC (make-temp-file "org-mobile" nil "C" current)) (fileDiff (make-temp-file "org-mobile" nil "Diff" (shell-command-to-string (format "diff %s %s" fileA fileB)))) (patch-result (shell-command (format "patch -f %s %s" fileC fileDiff)))) (when (string-match-p "FAILED" patch-result) ;patch失败 (error patch-result)) (setq current (with-temp-buffer (insert-file-contents fileC) (buffer-string))) (delete-file fileA) (delete-file fileB) (delete-file fileC) (delete-file (concat fileC ".orig")) (delete-file fileDiff) (message "current:%s" current)) ;; (diff-buffer-with-file ) (end-of-line 1) (insert "\n" current) (or (bolp) (insert "\n")) (delete-region (point) (progn (org-back-to-heading t) (outline-next-heading) (point)))) t) (t (error "Body was changed in MobileOrg and on the computer")))))))
MobileOrg同步BUG解析
本文深入探讨了MobileOrg中存在的一个同步BUG,即连续修改同一entry两次时,第二次修改无法正确同步的问题。文章提供了详细的背景信息,包括MobileOrg的同步机制,并提出了解决方案,如修改org-mobile-force-mobile-change配置及自定义org-mobile-edit函数。

被折叠的 条评论
为什么被折叠?



