首页 > 解决方案 > 如何在 Emacs 的 Org 模式下在 Source Block 的“#+RESULTS”预览输出周围添加“#+ATTR_HTML”?

问题描述

我在 org 中使用 Plantuml,效果很好。但是,我试图通过在#+RESULTS输出标记之前自动添加一些HTML 标记来进行一些更改,这样可以获得漂亮的HTML 输出效果。

我的示例代码如下:

#+BEGIN_SRC plantuml :file test.png
@startuml

  package "Some Group" {
          HTTP - [First Component]
          [Another Component]
  }

  node "Other Groups" {
          FTP - [Second Component]
          [First Component] --> FTP
  } 

  cloud {
          [Example 1]
  }


  database "MySql" {
          folder "This is my folder" {
                  [Folder 3]
          }
          frame "Foo" {
                  [Frame 4]
          }
  }


  [Another Component] --> [Example 1]
  [Example 1] --> [Folder 3]
  [Folder 3] --> [Frame 4]

  @enduml
#+END_SRC

在 Plantuml 的“Cc Cc”之后,您将在 plantuml 代码块下方得到以下输出:

#+RESULTS:
[[file:test.png]]

但是,我希望它自动附加上面的#+RESULT标记,如下所示,这将显示在 Emacs 中的 plantuml 源代码块下方:

#+ATTR_HTML: :width 80% 
#+ATTR_ORG: :width 80% 
#+ATTR_HTML: :style background-color: white; border-radius: 8px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
#+RESULTS:
[[file:test.png]]

然后,我可以通过“Cc Ce h o”将 org 文件输出为 HTML,得到一个漂亮的 HTML。

我怎样才能做到?

谢谢 !

标签: htmloutputorg-modeattrplantuml

解决方案


标准技术是为源块命名:

#+NAME: foo
#+BEGIN_SRC plantuml :file test.png
@startuml
...
#+END_SRC

当你评估代码块时,它会产生一个#+RESULTS:像这样的标题:

#+RESULTS: foo
[[file:test.png]]

现在您可以#+ATTR_*在结果之前添加声明:

#+ATTR_HTML: :width 80% 
#+ATTR_ORG: :width 
#+ATTR_HTML: :style background-color: white; border-radius: 8px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
#+RESULTS: foo
[[file:test.png]]

重新运行代码块会将文件链接放在同一个位置,并且不会留下任何#+ATTR-*东西。然后,您可以导出并获得“漂亮的 HTML”!

编辑:以上内容的主要目的是避免在未命名块时所需的手动工作在每次重新评估源代码后,您必须不断将属性声明移动到新生成的 #+RESULTS: 部分块(并清理旧结果)。从我的 POV 来看,这是令人讨厌的部分,并且块的命名很好地处理了它。

然后添加属性声明成为我不特别希望自动化的一次性任务,主要是因为不同块的属性必然不同,所以我为一个块所做的任何事情都必须完全改变另一个:我宁愿手动完成一次性任务。

也就是说,您可以部分自动化属性插入,例如通过创建一个函数来执行插入并将其绑定到一个键:

(defun insert-attr-decls ()
  (interactive)
  (insert "#+ATTR_HTML: :width 80%\n")
  (insert "#+ATTR_ORG: :width 80%\n") 
  (insert "#+ATTR_HTML: :style background-color: white; border-radius: 8px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);\n"))

(define-key org-mode-map [f10] 'insert-attr-decls)

然后在第一次评估后,将点放在#+RESULTS: foo生成的线之前,然后按F10。从我的 POV 来看,这就是我要停下来的地方(如果我走了这么远)。

下一步将是搜索插入应该去的地方,然后调用上面的函数——虽然我确信它可以改进:

(defun insert-attr-decls ()
  (insert "#+ATTR_HTML: :width 80%\n")
  (insert "#+ATTR_ORG: :width 80%\n") 
  (insert "#+ATTR_HTML: :style background-color: white; border-radius: 8px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);\n"))

(defun insert-attr-decls-at (s)
  (let ((case-fold-search t))
   (if (search-forward s nil t)
    (progn 
       (search-backward s nil t)
       (insert-attr-decls)))))

(defun insert-attr-decls-at-results ()
  (interactive)
  (save-excursion
   (insert-attr-decls-at "#+RESULTS:")))

(define-key org-mode-map [f10] 'insert-attr-decls-at-results)

这已经是复杂性的巨大飞跃,它可能包含错误:例如,如果#+RESULTS:缓冲区中没有字符串会发生什么?我没有测试过。所以如果其他人愿意花时间制作一个“完美”的功能,那么是的,也许我会接受并使用它。但除非这将成为我的主要工作,否则我宁愿把时间花在其他地方:如果确实证明它确实是一个时间槽,你总是可以在以后自动化它。

下一步(我不会这样做)将C-c C-c评估块添加属性声明。您可以通过添加insert-attr-decls-at-resultsorg-babel-after-execute-hook变量来做到这一点:

(add-hook 'org-babel-after-execute-hook 'insert-attr-decls-at-results)

这里的问题是,在每次求值时,你都会多添加一个属性声明块:你真的必须重写插入函数来检查是否已经有一个属性声明块,如果有,什么也不做。这留作练习。

AFAIAC 故事的寓意是:您可以使所有事情自动化,但并非所有事情都值得自动化。


推荐阅读