在Emacs中编辑Markdown管道表格

30

我喜欢用Markdown写作,并经常需要表格。有没有在Emacs中编辑Markdown的管道表格的好方法?我指的是这种语法:

| Header | Header | Right |
|--------|--------|------:|
|  Cell  |  Cell  |  $10  |
|  Cell  |  Cell  |  $20  |

我最初尝试了Emacs的table mode,它很不错,但是它设计用于“网格表格”,而Markdown不支持这种类型(比如在Github的Markdown中)。

还有org-mode的表格模式,可以用作较小的模式。这相当接近;但现在交叉点被+字符替换,并且没有对齐冒号的支持。因此,org-tblmode首先给我这样的东西:

| Header | Header | Right |
|--------+--------+-------|
| Cell   | Cell   | $10   |
| Cell   | Cell   | $20   |

然后我需要手动编辑成以下内容(编辑交集字符并添加对齐冒号):

| Header | Header | Right |
|--------|--------|------:|
| Cell   | Cell   | $10   |
| Cell   | Cell   | $20   |

有没有办法让org-tblmode也能处理这个表格?你还用/建议使用什么编辑Markdown的管道表格在Emacs中?

7个回答

11

OrgMode具有很好的功能orgtbl-to-generic,可将orgmode表格转换为外部格式。我发现一个简单的例子,它基于orgtbl-to-generic定义自定义转换器:https://gist.github.com/yryozo/5807243。此外,还可以在此处查看ORGTBL接收/发送功能的说明:http://dynamic-thinking.blogspot.ru/2009/11/orgtbl-mode.html。您需要在Emacs中定义自定义orgtbl-to-gfm函数,并将其放置到autoload中,然后您可以使用小模式orgtbl-mode来编辑表格。

小限制:仅支持右和左列对齐,因为Emacs OrgMode自身不支持中央对齐。

请参见上面的示例org-mode源代码:

<!---
#+ORGTBL: SEND sample orgtbl-to-gfm
| Column 1      | Column 2 |
|---------------+----------|
|               | <l>      |
| Sample line 1 | 100      |
| Sample line 2 | 200      |
-->

而从org-mode源代码转换成的markdown结果如下:

<!--- BEGIN RECEIVE ORGTBL sample -->
| Column 1 | Column 2 |
|---|---|
| Sample line 1 | 100 |
| Sample line 2 | 200 |
<!--- END RECEIVE ORGTBL sample -->

他们两个都放在同一个文件中。


添加示例非常感谢。 - Charles Merriam
1
@CharlesMerriam,我在答案中添加了示例。 - Alexander I.Grafov

10

这是我在markdown模式下处理表格的方法。可能有点取巧,但对我来说足够好用了。它会向markdown缓冲区添加一个本地钩子,在保存时将整个缓冲区中的“-+-”替换为“-|-”。

(require 'org-table)

(defun cleanup-org-tables ()
  (save-excursion
    (goto-char (point-min))
    (while (search-forward "-+-" nil t) (replace-match "-|-"))
    ))

(add-hook 'markdown-mode-hook 'orgtbl-mode)
(add-hook 'markdown-mode-hook
          (lambda()
            (add-hook 'after-save-hook 'cleanup-org-tables  nil 'make-it-local)))

10

1
在我的情况下,TAB键也可以使用。 - Glenn

4
将该功能绑定到一个键上,以实现区域的右对齐转换:
(defun markdown-regexp-right (beg end)
  (interactive "r")
  (replace-regexp "-\|[^-]" "-:|\n" nil beg end)    
  (replace-regexp "-\\+-" "-|-" nil beg end)
)

这将在右对齐的情况下用-|-替换-+-,并用:|替换-|

请注意包括\n,因为这可以确保其他-|-不会被改变为-:|,而只有在后面跟着一个new-line时才会更改-|


我很感谢您的建议,但不幸的是,当我尝试这段代码时,它会使我的Emacs崩溃 :/ 如果注释掉第二行,它似乎可以工作,所以可能是无限循环并导致堆栈溢出的原因。 - John J. Camilleri
否则它能完成工作吗? - PascalVKooten
是的,我在一个区域内调用它,并且没有(replace-regexp "-\|[^-]" "-:|\n" nil beg end)这一行,它可以正常工作(它只是替换交叉点)。 - John J. Camilleri
是否还有其他需要添加的内容? - PascalVKooten
问题在于它不够耐用。因此,我可以从一个org-mode表格开始,然后运行这个函数将其转换为管道表格。但是,如果任何单元格的内容长度发生变化,我按下C-c C-c重新对齐所有内容(orgtbl-mode快捷键),它会完全搞砸一切。我希望有更多实际的编辑模式适用于管道表格,但也许没有这样的模式存在。 - John J. Camilleri
显示剩余3条评论

3

Org-mode非常接近,我认为这是使用其orgtbl小模式和任意语法转换的情况。包含:-、-:或:-:的行将删除其冒号,并添加第二行<l><c><r>以通知org-mode对齐方式。然后翻译回来不应该太难了。不幸的是,我现在还不够擅长Emacs,无法编写它。顺便说一句,pandoc的markdown解析器确实接受由org-mode生成的+。

看了一下,我认为org-mode中的现有钩子需要在文本周围添加太多垃圾,并且需要一些编辑函数。由于这是我第一次尝试emacs lisp,我的emacs lisp用于在orgtbl和markdown之间进行转换简直太糟糕了,但我已经成功转换了一个测试表格。


1
我也遇到了这个问题(我最近才转用emacs),我编写了一个小的AWK脚本,可以将您提到的“网格表”(即不使用org-mode表)转换为GFM表格。
您可以有几种方法使用此脚本。您只需标记表,然后键入C-u M-| awk脚本名称RET(我从this Stackoverflow thread学到了这个技巧)。这将使用区域作为AWK脚本的stdin,并替换该区域的输出。我在编写ELisp方面非常新手,但我还编写了一些辅助函数。 table-gfm-export函数目前不会像交互式使用C-u M-|那样替换文本,因为它仍然保留原始表格在缓冲区中。
(defun table-gfm-capture (start end)
  "convert Markdown table to Emacs table
there should be no pipes beginning or ending the line,
although this is valid syntax. Loses justification."
  (interactive "r")
  ;; should prompt user for justification
  (table-capture start end "|"
         "[\n][:|-]*" 'center))

(defun table-gfm-export (start end)
  "uses AWK script to convert Emacs table to
GFM Markdown table"
  (interactive "r")
  ;; replace gfm_table_format if necessary
  (shell-command-on-region start end "gfm_table_format" t t)
  (table-unrecognize))

这个脚本的一个好处是它可以使用一些简单的正则表达式来识别列的对齐方式。另一个函数table-gfm-capture无法保持对齐,因此您不能自由地来回切换。该系统基本上是为在表格模式下进行所有编辑,然后在最后导出到GFM而设计的。你可能会认为Emacs已经具备了使用table-generate-source生成Markdown表格的功能,但不幸的是并没有。
#!/usr/bin/env awk -f
# -*- mode: awk -*-

BEGIN {
    FS="|";
    first=1;
}

function detect_justification(f) {
    if (match(f, /^ .* $/)) {
        return 0;               # center-justified
    } else if (match(f, / $/)) {
        return -1;              # left-justified
    } else { return 1; }        # right-justified
}

function gen_field(len, just) {
    str = sprintf("%*s", len, "");
    gsub(/ /, "-", str);
    if (just <= 0) {
        # left or center, start with :
        sub(/-/, ":", str);
    }
    if (just >= 0) {
        # right or center, end with :
        sub(/-$/, ":", str);
    }
    return str;
}

function gen_rule() {
    str = "";
    # ignore first and last empty fields
    for (i=1; i < NF; i++) {
        len = length($i);
        just = detect_justification($i);
        str = sprintf("%s%s|", str, gen_field(len, just));
    }
    return str;
}

function sanitize_line(line) {
    # strip outer pipes and trailing whitespace
    if (index(line, "|") == 1) {
        line = substr(line, 2);
    }
    sub(/[ |]*$/, "", line);
    return line;
}

! /^\+/ {
    print(sanitize_line($0));
    if (first) {
        print(sanitize_line(gen_rule()));
        first = 0;
    }
}

0

Markdown-mode 包为 GitHub 风格的 markdown 提供了表格支持。

Markdown-mode 是 Spacemacs(以及其他社区配置)的一部分。请注意,如果在 Spacemacs 中同时使用 markdown 和 org 层,则 orgtbl 将劫持一些关键绑定,即 TAB 并使用 org 语法格式化表格。禁用 orgtbl-mode 可以解除 orgtbl 的占用。


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