使用 org 的文件名作为 EGO 生成的 URL

为啥这里的markdown渲染的格式会出错"(ºДº*)

我的博客原文

概述

EOG 默认是使用文章的标题来生成 URL 的,这么做的坏处有二:

  1. 如果文章的标题里面有汉字,生成的 URL 因为编码的原因会变的特别长,不美观。
  2. 只要更改了文章的标题,URL 就会随之而改变,以后就不好找了。而且 disqus 和多说也会把 修改标题之后的文章当成新的文章。

我修改了 EGO 生成 URL 的策略,现在我的博客就是使用 hack 之后的 EGO 来生成的。

改进方法

    (defun liu233w//ego--generate-uri (default-uri-template creation-date title)
      "类似于`ego--generate-uri',只不过读取 org 的文件名作为 title"
      (let ((uri-template (or (ego--read-org-option "URI")
                              default-uri-template))
            (date-list (split-string (if creation-date
                                         (ego--fix-timestamp-string creation-date)
                                       (format-time-string "%Y-%m-%d"))
                                     "-"))
            (encoded-title (ego--encode-string-to-url
                            ;; 获取 buffer 的文件名
                            (replace-regexp-in-string "^.*/\\|\\.org$" "" (buffer-file-name)))))
        (format-spec uri-template `((?y . ,(car date-list))
                                    (?m . ,(cadr date-list))
                                    (?d . ,(cl-caddr date-list))
                                    (?t . ,encoded-title)))))

如果你不介意直接覆盖函数的话,可以把函数名换成 ego--generate-uri ,这样 EGO 的默认函数就 被覆盖了。如果你不想这么做,可以修改 ego--category-config-alist 中的 :uri-generator , 如我的代码所示:

    (setf ego--category-config-alist
                '(("blog"
                   :show-meta t
                   :show-comment t
                   ;; 将 org 的文件名当做 uri,参考函数
                   :uri-generator liu233w//ego--generate-uri
                   :uri-template "/blog/%y/%m/%d/%t/"
                   :sort-by :date     ;; how to sort the posts
                   :category-index t) ;; generate category index or not
                  ("acm"
                   :show-meta t
                   :show-comment t
                   ;; 将 org 的文件名当做 uri,参考函数
                   :uri-generator liu233w//ego--generate-uri
                   :uri-template "/acm/%y/%m/%d/%t/"
                   :sort-by :date     ;; how to sort the posts
                   :category-index t)
                  ("index"
                   :show-meta nil
                   :show-comment nil
                   :uri-generator ego--generate-uri
                   :uri-template "/"
                   :sort-by :date
                   :category-index nil)
                  ("about"
                   :show-meta nil
                   :show-comment nil
                   :uri-generator ego--generate-uri
                   :uri-template "/about/"
                   :sort-by :date
                   :category-index nil)
                  ))

原理

相比于原来的函数,我只是把 let 中的参数 title 换成了 (replace-regexp-in-string "^.*/\\|\\.org$" "" (buffer-file-name)) 而已。因为这个函数会在每一个打开的 buffer 中运行,所以可以通过 buffer-file-name 来获取当前 org 文件的路径,然后用正则表达式把多余的内容删掉,只保留文件名即可。

表达式的效果:

    (replace-regexp-in-string "^.*/\\|\\.org$" ""
                              "d:/TOTALCMD/tools/emacs/home/documents/blog/blog/change-url-generator.org")

change-url-generator

比较神奇的是 emacs 的正则表达式居然是把转义之后的 | 符号当做分支符号,而没有转义的 是符号本身,这跟其他的正则表达式实现不一样啊。

    (replace-regexp-in-string "ab|c" "dd" "ab|c")

dd

    (replace-regexp-in-string "ab\\|c" "dd" "ab|c")

dd|dd

貌似括号也是这样的。

| 是个普通字符,特殊字符只有下面数个

The special characters are `.', `*', `+', `?', `[', `^', `$', and `\';

Grep 默认使用的正则表达式(basic regular expression)也如此。

org 自带的 publish 默认就是用文件名作为 URL 的。一种更流行的 URL 模式是:

.../2016/06/Emacs-Lisp-as-script-language.html
=>
.../2016/06/Emacs-Lisp-as-script-language/index.html

在浏览器地址栏里只需显示 .../2016/06/Emacs-Lisp-as-script-language/,这样会更短、更美观一些。

Edit: 看了下你的博客已经在用那种比较简洁的 URL 了。

其实我之前没有用过正则表达式:sweat_smile:

但是不管是网上的教程还是正则表达式的在线测试都是把|当成特殊字符的,所以我以为主流的都是这样 _(:зゝ∠)_


另外,EGO已经把这个函数更新了,可以在URL模板里面放上 %f来表示文件名。

我的博客也更新了新的内容:

16/8/24 更新

找到了新的办法:用 nadvice.el 修改 ego--insert-options-template 即可。请确保以下的 代码在 EGO 加载之后运行。

    (require 'nadvice)
    ;; 改变默认的元数据模板,使插入的 URL 为 "category/%y/%m/%d/%f/"
    (defun org-config//advice-of-ego--insert-options-template (args)
      (setf (second args)
            (replace-regexp-in-string "%t/ Or .*$" "%f/"
                                      (second args)))
      args)
    
    (advice-add 'ego--insert-options-template :filter-args
                'org-config//advice-of-ego--insert-options-template
                )

nadvice.el 是一个 emacs 内置的新 package,与 defadvice 类似,它可以改变 某个函数的默认行为。 ego-new-post 会调用 ego--insert-options-template 来插入 org 文件的元数据。 advice-added 函数通过参数 :filter-args 将我的自定义函数 套在了原来函数的外面,传递给原函数的参数要经过我的函数的处理才能真正传递给它。

如果你在新建文章的时候使用了默认生成的模板(调用 ego-new-post 函数的最后回答 yes), 传递给 ego--insert-options-template 的第二个参数(URL 模板)默认会是 /your-category/%y/%m/%d/%t/ Or /your-category/%t/ ,我的函数将通过正则表达式把它 替换成 /your-category/%y/%m/%d/%f/ ,默认使用文件名当做 URL,这样就不需要再手动修改了。 如果你回答 no 来自己指定标题和 uri 的话,我的函数是不会影响的。

现在就可以去掉原来自定义的 ego--generate-uri 函数,把原来 org 文件里面的 %t 替换成 %f 了。上面的代码可比原来的修改少多了。

至于批量替换,可以用 emacs 的 dired 来做。用 dired 标记所有需要替换的文件,然后按 Q , 就可以像在一个文件中替换文本那样替换所有文件中的文本了。