检查链表有环

检查链表是否有环,貌似目前的标准答案是使用两根指针。下面是Emacs中的实现,亮点在指针变量命名。

/* Signal `error' with message S, and additional arg ARG.
   If ARG is not a genuine list, make it a one-element list.  */

void
signal_error (const char *s, Lisp_Object arg)
{
  Lisp_Object tortoise, hare;

  hare = tortoise = arg;
  while (CONSP (hare))
    {
      hare = XCDR (hare);
      if (!CONSP (hare))
	break;

      hare = XCDR (hare);
      tortoise = XCDR (tortoise);

      if (EQ (hare, tortoise))
	break;
    }

  if (!NILP (hare))
    arg = Fcons (arg, Qnil);	/* Make it a list.  */

  xsignal (Qerror, Fcons (build_string (s), arg));
}

在Emacs源码中搜索tortoise,可以发现多处类似实现。

玩转org-mode refile

refile是org-mode一个非常强大的工具,它实现了移动headline的自动化。

所谓自动化,就是无需下述手工操作:

  1. 剪切某条headline及其相关内容;
  2. 移动到目标位置;
  3. 粘贴并调整headline的层级(level)。

而是在该headline上执行C-c C-w,在minibuffer上选择移动目标,即可。

缺省情况,当前文件的所有level 1的headline作为移动目标供选择,如果需要更加灵活的选择移动目标,可以配置org-refile-targets变量。org-refile-targets的值是a list of cons cells,每个cons cell指定一种移动目标,所有cons cells指定的移动目标的合集,就是全部可供选择的移动目标。org-refile-targets的默认值为nil,效果与下面的配置相同。

(setq org-refile-targets '((nil . (:level . 1))))

在我的org-mode配置中,一般的TODO通常作为level 2的headline存在,但是对于相关度很高的一组TODO,会归并到一个level 2的PROJECT下,作为level 3的headline存在。通过配置org-capture-templates可以方便快速地创建TODO或者PROJECT,但是如果想把TODO直接加入某个PROJECT,而不是作为通常的level 2的headline,则需要如下配置:

(setq org-refile-targets
      '((nil . (:level . 1))
        (nil . (:todo . "PROJECT"))))

nil表示只考虑当前文件的level 1的headline或者PROJECT

如果想refile到其它文件,可以用一个变量(它的值是一个文件名列表)替代nil。如:

(setq org-refile-targets
      '((wl-org-code-comment-files . (:level . 1))
        (nil . (:level . 1))
        (nil . (:todo . "PROJECT"))))

更详细的配制方法参见org-refile-targets的帮助注释。