MobileOrg的一个BUG

MobileOrg同步BUG解析
本文深入探讨了MobileOrg中存在的一个同步BUG,即连续修改同一entry两次时,第二次修改无法正确同步的问题。文章提供了详细的背景信息,包括MobileOrg的同步机制,并提出了解决方案,如修改org-mobile-force-mobile-change配置及自定义org-mobile-edit函数。

原文地址: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")))))))
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值