org-mode中的sexp捕获

8
我将尝试创建一个捕获模板,将URL转换为带有<title>作为链接名称的org-mode链接。
我的转换函数如下:
(defun get-page-title (url)
  "Get title of web page, whose url can be found in the current line"
  ;; Get title of web page, with the help of functions in url.el
  (with-current-buffer (url-retrieve-synchronously url)
    ;; find title by grep the html code
    (goto-char 0)
    (re-search-forward "<title>\\([^<]*\\)</title>" nil t 1)
    (setq web_title_str (match-string 1))
    ;; find charset by grep the html code
    (goto-char 0)

    ;; find the charset, assume utf-8 otherwise
    (if (re-search-forward "charset=\\([-0-9a-zA-Z]*\\)" nil t 1)
        (setq coding_charset (downcase (match-string 1)))
      (setq coding_charset "utf-8")
    ;; decode the string of title.
    (setq web_title_str (decode-coding-string web_title_str (intern
                                                             coding_charset)))
    )
  (concat "[[" url "][" web_title_str "]]")
  ))

当从普通的emacs lisp代码中调用它时,它会返回正确的结果。但是当在org-capture-template中使用时,它只返回bad url

setq org-capture-templates
    (quote
     (("l" "Link" entry (file+headline "" "Links")
       "* \"%c\" %(get-page-title \"%c\")"))))

扩展的顺序不同吗?我需要以不同方式转义字符串吗?魔术?第一个%c仅用于调试字符串,确实被打印为"url"。

请不要浪费时间指出使用正则表达式解析XML是错误的方法。克苏鲁已经在缠绕着我,这不会让情况变得更糟。

3个回答

7
问题在于模板参数的扩展顺序。简单的%模板在sexp评估完成后进行扩展。原始错误消息仍然包含一个模板,因此被扩展为剪贴板的内容,因此错误消息不包含最初传递给get-page-title的字符串。
解决方案是从sexp内部访问kill ring。
%(get-page-title (current-kill 0))

编辑:此行为现在已在org-mode中记录。


@LeVieuxGildas 接受自己的答案总是有点痛苦。我已经更新并接受了它。 - pmr
2
我阅读 手册页面 的方式是,它应该按相反的方式工作 -“评估Elisp sexp并用结果替换。 为方便起见,在此之前将展开表达式中的%:关键字(请参阅下文)占位符。”但我同意您所描述的情况似乎正在发生。 - studgeek
@studgeek 这是高度版本特定的。在我修复文档以提及排序之后,方便之处已被添加。检查您的 org-mode 版本并检查结果。 - pmr

6
不使用org-protocol.el解决方案吗?具体内容请参考http://orgmode.org/worg/org-contrib/org-protocol.html。我刚用以下模板测试了一下(在标题中添加子标题作为您想要的标题)。
模板:
("t"
"Testing Template"
entry
(file+headline "~/org/capture.org" "Testing")
"* %^{Title}\n** %:description\n\n  Source: %u, %c\n\n%i"
:empty-lines 1)

然后使用基于浏览器的键绑定(在我的情况下是Opera,但也提供了Firefox、Uzbl、Acrobat和Conkeror的示例),我能够捕获以下内容:

** Testing for StackExchange
*** org-protocol.el - Intercept calls from emacsclient to trigger custom actions

  Source: [2011-08-05 Fri], [[http://orgmode.org/worg/org-contrib/org-protocol.html]
  [org-protocol.el - Intercept calls from emacsclient to trigger custom actions]]

    org-protocol intercepts calls from emacsclient to trigger custom actions
    without external dependencies.

(我为了让滚动条保持最小化,故意打断了 org-link 的链接,它原本不是两行)


不错的解决方案。我之前不知道如何使用org-protocol,但这肯定比我的方法更易用。 - pmr
我撤回我所说的话。在不得不涉及gconf和所有那些不向后兼容的东西之后,我爬回了我的“一切都是emacs”的世界。这里非常舒适,我不必再忍受这些烦心的事情了。 - pmr
@pmr 或许值得在邮件列表上询问是否有任何方法来解决这个问题。否则,我能想到的最接近的解决方法可能是 org.el 的 8487-8498 行,它们涉及如何从 w3 和 w3m 进行捕获(应该能够添加到 org-store-link-props 中以包括标题)。 - Jonathan Leech-Pepin
好的,Emacs方面的一切都正常工作,并且手动调用带有org-protocol的emacsclient也可以。说服任何奇怪的gconf-tools去执行它们被告知的任务是另一回事。 ;) - pmr
@pmr 我还没有在Linux上测试过它,我是在XP机器上做的工作,并且运行良好。当我在周末尝试在我的Arch系统上时,我遇到了你所遇到的相同问题,因为该系统上没有gnome,所以也没有gconf工具来进行修复。然而,Opera仍然能够让它正常工作(可以在其中配置自定义协议,而不仅仅是映射到默认值)。我将在邮件列表中询问,在没有gconf工具可用的情况下,我应该从哪里查找配置协议的方法。 - Jonathan Leech-Pepin

4

@aboabo在https://stackoverflow.com/a/21080770/255961分享了一个未文档化的变量,它提供了一个更通用的解决方案来处理如何在模板中使用关键字值(除了kill ring)的问题。变量org-store-link-plist存储了所有传递到捕获中的信息。因此,您可以通过以下函数直接访问其值,使其更加易于理解:

(defun url()
  (plist-get org-store-link-plist :url))
("w" "capture" entry (file "~/refile.org")
     "* [[%:link][%:description]] :NOTE:\n%(url)%U\n"
     :immediate-finish t) 

根据手册页面(下面引述),我认为你在问题中的方法也应该行得通。但是,我同意你描述的情况实际上正在发生-相对于手册来说,这似乎是一个错误。

%(sexp) 评估Elisp表达式并用结果替换。为了方便起见,在此之前将扩展表达式中的%:关键字(请参阅下文)占位符。


就像我在回复你的评论中已经说过的那样:确保你的org版本与在线手册的版本匹配。尽管我因为明显的原因不喜欢摆弄未记录的变量,但你的方法似乎很有效。 - pmr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接