Jekyll 下使用 Org-mode

Yicheng 于 2020-05-11 发布

org到html的转换在emacs里面很容易搞定。

但是为了在code server内编辑+发布,我找到了jekyll-org 在安装了gem依赖以后,.org文件可以成功地被解析。分割线下方是一些测试:

[已解决] 目前发现代码块和引用块(#+开头的)没法正确转换。如下图:

code-block-not-show.png

看了下代码,最终发现问题所在,原来是org-ruby转换的代码块是用<pre>tag包起来的。 但是主题的css文件里pre定义了字体大小为0:

.page-post pre {
  font-size: 0;
  ...
  tab-size: 4;
}

将字体改为正常大小就好了,顺便改了下tab缩进字符数为2,其他保持不变:

.page-post pre {
  font-size: 13px;
  ...
  tab-size: 2;
}

[已解决] 但是马上又引出了另外一个问题:代码块没颜色高亮显示,不好看:

code-block-no-color.png

翻看了org-ruby的说明,发现是没有安装依赖的缘故:需要加上Pygments.rb 或者 Coderay。

试了下Pygments.rb,报了个错:

`Error: could not read file /blog/_posts/2020-05-11-org-mode.org: Failed to get header.`

然后换成Coderay,结果就可以了。不过支持的语言比Pygments.rb要少很多,像elisp就不行。

[已解决] categories 没办法正确加载,可能是与配置文件有关

这个其实也是头文件没写好,加上这么一行就好了:

#+CATEGORIES: jekyll org-mode

---------------------------------END----------------------------- #

-----------------分割线 分割线,以下内容均为测试-------------------- #

----------------------------------------------------------------- #

org-table 测试

abc
123

代码高亮

#include<iostream>
using namespace std;
int main() {
        cout<<"Hello World"; 
        return 0; 
}

很长的代码块

/**
 * 稍加改造,md5函数挂在了blog对象上
 */
(function ($) {
        var rotateLeft = function (lValue, iShiftBits) {
                return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
        }
        var addUnsigned = function (lX, lY) {
                var lX4, lY4, lX8, lY8, lResult;
                lX8 = (lX & 0x80000000);
                lY8 = (lY & 0x80000000);
                lX4 = (lX & 0x40000000);
                lY4 = (lY & 0x40000000);
                lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
                if (lX4 & lY4) return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
                if (lX4 | lY4) {
                        if (lResult & 0x40000000) return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
                        else return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
                } else {
                        return (lResult ^ lX8 ^ lY8);
                }
        }
        var F = function (x, y, z) {
                return (x & y) | ((~x) & z);
        }
        var G = function (x, y, z) {
                return (x & z) | (y & (~z));
        }
        var H = function (x, y, z) {
                return (x ^ y ^ z);
        }
        var I = function (x, y, z) {
                return (y ^ (x | (~z)));
        }
        var FF = function (a, b, c, d, x, s, ac) {
                a = addUnsigned(a, addUnsigned(addUnsigned(F(b, c, d), x), ac));
                return addUnsigned(rotateLeft(a, s), b);
        };
        var GG = function (a, b, c, d, x, s, ac) {
                a = addUnsigned(a, addUnsigned(addUnsigned(G(b, c, d), x), ac));
                return addUnsigned(rotateLeft(a, s), b);
        };
        var HH = function (a, b, c, d, x, s, ac) {
                a = addUnsigned(a, addUnsigned(addUnsigned(H(b, c, d), x), ac));
                return addUnsigned(rotateLeft(a, s), b);
        };
        var II = function (a, b, c, d, x, s, ac) {
                a = addUnsigned(a, addUnsigned(addUnsigned(I(b, c, d), x), ac));
                return addUnsigned(rotateLeft(a, s), b);
        };
        var convertToWordArray = function (string) {
                var lWordCount;
                var lMessageLength = string.length;
                var lNumberOfWordsTempOne = lMessageLength + 8;
                var lNumberOfWordsTempTwo = (lNumberOfWordsTempOne - (lNumberOfWordsTempOne % 64)) / 64;
                var lNumberOfWords = (lNumberOfWordsTempTwo + 1) * 16;
                var lWordArray = Array(lNumberOfWords - 1);
                var lBytePosition = 0;
                var lByteCount = 0;
                while (lByteCount < lMessageLength) {
                        lWordCount = (lByteCount - (lByteCount % 4)) / 4;
                        lBytePosition = (lByteCount % 4) * 8;
                        lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
                        lByteCount++;
                }
                lWordCount = (lByteCount - (lByteCount % 4)) / 4;
                lBytePosition = (lByteCount % 4) * 8;
                lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
                lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
                lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
                return lWordArray;
        };
        var wordToHex = function (lValue) {
                var WordToHexValue = "", WordToHexValueTemp = "", lByte, lCount;
                for (lCount = 0; lCount <= 3; lCount++) {
                        lByte = (lValue >>> (lCount * 8)) & 255;
                        WordToHexValueTemp = "0" + lByte.toString(16);
                        WordToHexValue = WordToHexValue + WordToHexValueTemp.substr(WordToHexValueTemp.length - 2, 2);
                }
                return WordToHexValue;
        };
        var uTF8Encode = function (string) {
                string = string.replace(/\x0d\x0a/g, "\x0a");
                var output = "";
                for (var n = 0; n < string.length; n++) {
                        var c = string.charCodeAt(n);
                        if (c < 128) {
                                output += String.fromCharCode(c);
                        } else if ((c > 127) && (c < 2048)) {
                                output += String.fromCharCode((c >> 6) | 192);
                                output += String.fromCharCode((c & 63) | 128);
                        } else {
                                output += String.fromCharCode((c >> 12) | 224);
                                output += String.fromCharCode(((c >> 6) & 63) | 128);
                                output += String.fromCharCode((c & 63) | 128);
                        }
                }
                return output;
        };

        $.md5 = function (string) {
                var x = Array();
                var k, AA, BB, CC, DD, a, b, c, d;
                var S11 = 7, S12 = 12, S13 = 17, S14 = 22;
                var S21 = 5, S22 = 9, S23 = 14, S24 = 20;
                var S31 = 4, S32 = 11, S33 = 16, S34 = 23;
                var S41 = 6, S42 = 10, S43 = 15, S44 = 21;
                string = uTF8Encode(string);
                x = convertToWordArray(string);
                a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
                for (k = 0; k < x.length; k += 16) {
                        AA = a; BB = b; CC = c; DD = d;
                        a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
                        d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
                        c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
                        b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
                        a = FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
                        d = FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
                        c = FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
                        b = FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
                        a = FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
                        d = FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
                        c = FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
                        b = FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
                        a = FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
                        d = FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
                        c = FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
                        b = FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
                        a = GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
                        d = GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
                        c = GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
                        b = GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
                        a = GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
                        d = GG(d, a, b, c, x[k + 10], S22, 0x2441453);
                        c = GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
                        b = GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
                        a = GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
                        d = GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
                        c = GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
                        b = GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
                        a = GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
                        d = GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
                        c = GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
                        b = GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
                        a = HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
                        d = HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
                        c = HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
                        b = HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
                        a = HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
                        d = HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
                        c = HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
                        b = HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
                        a = HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
                        d = HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
                        c = HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
                        b = HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
                        a = HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
                        d = HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
                        c = HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
                        b = HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
                        a = II(a, b, c, d, x[k + 0], S41, 0xF4292244);
                        d = II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
                        c = II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
                        b = II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
                        a = II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
                        d = II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
                        c = II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
                        b = II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
                        a = II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
                        d = II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
                        c = II(c, d, a, b, x[k + 6], S43, 0xA3014314);
                        b = II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
                        a = II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
                        d = II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
                        c = II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
                        b = II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
                        a = addUnsigned(a, AA);
                        b = addUnsigned(b, BB);
                        c = addUnsigned(c, CC);
                        d = addUnsigned(d, DD);
                }
                var tempValue = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);
                return tempValue.toLowerCase();
        }

})(blog);

例子块

春江潮水连海平,海上明月共潮生。
滟滟随波千万里,何处春江无月明!

目录1

目录2

目录3

目录4

目录5
目录6

图片显示

绝对路径链接

https://yicheng.ren/posts/2020/05/11/nyan-cat.jpg

相对路径链接

nyan-cat.jpg

文件下载

highlight.zip // 可用,文件已经删除。

TODO的处理

测试

另一个测试

TODO DONE 之类的关键词会被隐藏掉。

----------------------- org-ruby 测试文件:

Turns out there's more way to do code than just BEGIN_EXAMPLE.

Inline examples

This should work:

  fixed width? how does this work?   
                        ...........
                       ............
                                  .
                       .  .   .   .
                       .          ..
                       ....... .....
                           .  .
                           ....

Two ASCII blobs.

BEGIN_SRC

And this:

# Finds all emphasis matches in a string.
# Supply a block that will get the marker and body as parameters.
def match_all(str)
  str.scan(@org_emphasis_regexp) do |match|
    yield $2, $3
  end
end

Now let's test case-insensitive code blocks.

# Finds all emphasis matches in a string.
# Supply a block that will get the marker and body as parameters.
def match_all(str)
  str.scan(@org_emphasis_regexp) do |match|
    yield $2, $3
  end
end
(def fib-seq
  (concat
   [0 1]
   ((fn rfib [a b]
        (lazy-cons (+ a b) (rfib b (+ a b)))) 0 1)))
 
user> (take 20 fib-seq)
(0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181)

Even if no language is set, it is still wrapped in code tags but class is empty.

echo 'Defaults env_keeps="http_proxy https_proxy ftp_proxy"' | sudo tee -a /etc/sudoers

It should be possible to write a colon at the beginning of an example

I really love to write about :symbols. They sure are the best things in the world!

{
:one => 1,
:two => 2
}
(defproject helloworld "0.1"
:dependencies [[org.clojure/clojure
                 "1.1.0-master-SNAPSHOT"]
              [org.clojure/clojure-contrib
                 "1.0-SNAPSHOT"]]
:main helloworld)

Code syntax highlight with Coderay

No language selected

Nothing to see here

CSS example

* {
 /* apply a natural box layout model to all elements */
 box-sizing: border-box; 
 -moz-box-sizing: border-box; 
 -webkit-box-sizing: border-box; 
}

HTML example

<html>
  <head>
    <title>Hello</title>
  </head>
  <body>
    <h1>Hello</h1>
  </body>
</html>

Ruby example

class Post << ActiveRecord::Base
  def print_title
    puts "#{self.title}"
  end
end

Python example

import mapnik

m = mapnik.Map(600, 800)
m.background = Map.Color('steelblue')

Javascript example

exports = this;

(function($){

var Posts = {};

Posts.index = function(){
// TODO
};

})(jQuery);

JSON example

{ name: "Waldemar"
, surname: "Quevedo"
}

PHP example

echo "Hello";
phpinfo();
var_dump(some_var);

Elisp example

(defun hello()
  (interactive)
  (message "hello"))

Not supported language example

!+!+++!++!++!++!+

According to the Org mode docs, it is possible to customize whether the code block will be exported or not.

About the #+RESULTS: block

Using Org Babel features, it is possible to set :results output to a code block and render the results within a #+RESULTS: code block:

#+begin_src ruby :results output :exports both
puts "Hello world"
#+end_src

#+RESULTS:
: Hello world

One thing about the #+RESULTS: code blocks, is that they exist in several forms:

  1. As an accumulated group of inline examples:
    #+begin_src python :results output :exports both
    print "like"
    print "this"
    print "etc..."
    #+end_src
    
    #+RESULTS:
    : like
    : this
    : etc...
        
  2. As an example code block.
    #+begin_src ruby :results output :exports both
    10.times {|n| puts n }
    #+end_src
    
    #+RESULTS:
    #+begin_example
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #+end_example
        
  3. Also, in case :results output code is used, the results would be a src block of the same language as the original one.
    #+begin_src ruby :results output code
    counter = 0
    10.times { puts "puts '#{counter += 1}'" } # Displayed in first code block
    puts counter # Displayed in second code block
    #+end_src
    
    #+RESULTS:
    #+begin_src ruby
    puts '1'
    puts '2'
    puts '3'
    puts '4'
    puts '5'
    puts '6'
    puts '7'
    puts '8'
    puts '9'
    puts '10'
    10
    #+end_src
    
    #+RESULTS:
    : 10
        

Default options

The default is to export only the code blocks.

The following is an code block written in Emacs Lisp and its result should not be exported.

(message "hello world")

The following is a code block written in Python and its result should not be exported.

for i in range(0,12):
  print "import this"

:exports code

Only the code would be in the output, the same as when no option is set.

var message = "Hello world!";

console.log(message);

And as block example too:

var message = "Hello world!";
for (var i = 0; i< 10; i++) {
  console.log(message);
}

:exports none

This omits both the resulting block, and the code block itself.

This should work as well when using an example block.

:exports both

Math::PI + 1
4.14159265358979

Should behave the same when within a block example.

hello = <<HELLO
The following is a text
that will contain at least 10 lines or more
so that when C-c C-c is pressed
and Emacs lisp
evals what is inside of the block,
enough lines would be created
such that an example block 
would appear underneath the
block that was executed.
This happens after 10 lines by default.
HELLO
The following is a text
that will contain at least 10 lines or more
so that when C-c C-c is pressed
and Emacs lisp
evals what is inside of the block,
enough lines would be created
such that an example block 
would appear underneath the
block that was executed.
This happens after 10 lines by default.

:exports results

This option can't be completely supported by OrgRuby since we would have to eval the code block using :lang, so Org Babel features would have to be implemented as well.

But in case the resulting block is within the Org mode file, the code block will be omitted and only the results block would appear.

3.141592653589793

The same should happen when a block example is used instead:

any string
any string
any string
any string
any string
any string
any string
any string
any string
any string

Removing the prepended comma from Org mode src blocks

As mentioned in http://orgmode.org/manual/Literal-examples.html, when at the beginning of the line there is either “,*” or “,#+” this prepended comma should be removed before parsing.

(Fixes https://github.com/bdewey/org-ruby/issues/50)

Here the prepended comma will be removed.

* Hello
** Goodbye
 *** Not a headline, but prepended comma still removed.
* I am a headline

Here the prepended comma is should not be removed.

{
  "one":   1
, "two":   2
, "three": 3
, "four":  4
}

Here the prepended comma is also removed

Emacs Org mode implementation also removes it.

text = <<TEXT
#+TITLE: Prepended comma world
* Hello world
More text here
TEXT

Here the prepended comma will be remove for the Hello world headline

,  ,* Hi
,  
,  ,* This will be appended a comma
* Hello world  
,  

Here the prepended comma will be removed

#+TITLE: "Hello world"

This will be rendered as normal

,,,,,,,,,,,,,,,,,*Hello world