Emacs i formatowanie kodów źródłowych

Ten blog jest częściowo techniczny; blog anglojęzyczny jest techniczny praktycznie całkowicie. Często (częstawo?) potrzebuję wklejać w tekst (edytowany jedynie słusznym edytorem w jedynie słusznym języku znaczników) fragmenty kodu źródłowego. Jest parę rozwiązań, które mogę zastosować na blogaskach; oczywiście wszystkie kiepskie.

Można przeładować HTML-owy tag <pre>, za pomocą JavaScriptu albo pług-inów systemu blogowego. Drugie rozwiązanie może ma jakiś sens na Wordpressie, ale na Joggasku jest niemożliwe; JavaScript—fajnie, w większości przypadków działa, ale oskryptowywać się dla takiej pierdółki? HTML i CSS są całkowicie zdolne do pokazania ładnie sformatowanego i pokolorowanego kodu, bez uciekania się do pomocy skryptów. No i żaden skrypt w pehapie czy żawaskrypcie nie pokoloruje mi składni tak ładnie jak mój Emacs ;)

Emacs, z dodatkiem htmlize.el, potrafi zakodować bufor lub jego fragment do postaci pliku HTML, z zachowaniem kolorowania. Jeśli ustawimy zmienną htmlize-output-type na 'inline-css, to generowany jest HTML zdatny do przeklejenia prosto do pisanego kodu, ze stylami w formie <span style="…">. Dwa problemy: generowany jest cały HTML (z nagłówkiem itd), a kolor tła jest ustawiany w tagu body, a nie pre, co powoduje, że trzeba go przekleić. Zwykle robiłem to ręcznie, ale potrzebując przegenerować wszystkie przykłady potrzebne w drugiej części tutoriala Yaclml, wymiękłem.

Po pewnym czasie…

(require 'htmlize)

(defun jph/strip-htmlized-buffer ()
  "Strip htmlized buffer to <pre> tag, copying style attribute from <body> to <pre>."
  (interactive)
  (goto-char (point-min))
  (re-search-forward "<body\\( style=[^>]*\\)>")
  (let ((style (match-string 1)))
    (search-forward "<pre")
    (insert style)
    (delete-region (point-min) (line-beginning-position))

    (search-forward "</pre>")
    (delete-region (point) (point-max))
    (insert "\n")))

(defun jph/htmlize-fragment (prefix)
  "Replace fragment of current buffer with htmlized file.

Text between comments <!-- htmlize filename --> and
<!-- end htmlize --> gets replaced with htmlized file
`filename' (only the <pre> tag).

If a negative prefix is given, text between comments is removed.

Only one pair of comments is processed (nearest one forward from
current point position).
"
  (interactive "p")
  (when (search-forward "<!-- htmlize " nil t)
    (let ((source-file (thing-at-point 'filename)))
      (beginning-of-line 2)
      (let ((start (point)))
        (search-forward "<!-- end htmlize ")
        (beginning-of-line)
        (delete-region start (point)))
      (when (>= prefix 0) ; '-' prefix prevents inserting the htmlized text
        (insert (with-current-buffer (find-file-noselect source-file)
                  (with-current-buffer (htmlize-buffer)
                    (jph/strip-htmlized-buffer)
                    (prog1 (buffer-string)
                      (kill-buffer)))))))
    t))

(defun jph/htmlize-all-fragments (prefix)
  "Replace all indicated fragments of current buffer with htmlized files.

All pair of <!-- htmlize filename --> and <!-- end htmlize --> comments
are processed with `jph/htmlize-fragment'.  If negative prefix is given,
inside of all such comment pairs is deleted."
  (interactive "p")
  (goto-char (point-min))
  (while (jph/htmlize-fragment prefix)))

Powyższą wklejkę wpisałem w swój kod tak:

<!-- htmlize htmlize-fragments.el -->
<!-- end htmlize -->

Następnie wywołałem magiczne zaklęcie M-x jph/htmlize-all-fragments—i gotowe. Z ujemnym prefiksem (M-- M-x jph/htmlize-all-fragments) kod spomiędzy magicznych komentarzy jest kasowany (jeśli np. edytujemy tekst, a wielkie <pre> przetykane <span>-ami nas rozpraszają). Kod jest do przeklejenia stąd, albo do ściągnięcia pod adresem http://gist.github.com/285335. Smacznego!

  1. Dodek powiedział(a):

    Cześć,
    ja tutaj chciałem tylko zostawić zaproszenie na #lisp-pl na Freenode :)

  2. mina86 powiedział(a):

    O tak, przerośnięte wpisy ze stylami w atrybucie... bo przecież uwielbiamy czekać, aż strona się wczyta.

    Htmlize używałem swego czasu do drukowania, ale zaprzestałem, gdy odkryłem, że są do tego narzędzia generujące ładny PostScript.

  3. Daniel powiedział(a):

    E tam jedynie słusznym. Ja się przestawiłem na Markdown do pisania wpisów (z HTML, tak tak). I życie stało się prostsze.

  4. Maciek powiedział(a):

    @Dodek, dzięki, jak mnie najdzie na freenode, zajrzę :)

    @mina86, tak, bo HTML jest najcięższym elementem strony. Lepiej takie rzeczy zostawić JS, będzie szybciej, sprawniej i użyteczniej. Bo chyba nie mówisz o wywaleniu tych styli do głównego CSS - nie ma aż tak dużej różnicy objętości między <span style="color: #abcdef"> a <span class="foo-bar-baz"> + definicją klasy, żeby równoważyło to wygodę przeklejenia skrawka kodu.

    @Daniel, ja się przestawiłem na HTML po bezskutecznych próbach znalezienia wygodnego języka znaczników ze spójną i jednoznaczną składnią. I nie pisz mi o tym, że Markdown ma fallback do HTML, bo nie mogę do markdowna przekleić poprawnego kodu HTML (znaczy, mogę, ale SPECIAL-VARIABLE w skrawku kodu nie wyświetli mi się tak, jak bym chciał—więc do kitu z taką "zgodnością", jeśli korzystając z niej muszę pamiętać o pasożytniczej składni md). Nxhtml-mode+yasnippet ułatwia pisanie na tle, że w czystym HTML jest mi szybciej i sprawniej. Czasem jeszcze korzystam z org-mode, ale to nie ze względu na markup, ale raczej wygodę edycji. Jedno, co mnie wciąż w gołym HTML boli, to konieczność pisania <p>…</p> zamiast TeX-awego rozdzielania akapitów pustą linią—ale do tego pewnie też w końcu jakiś elisp napiszę.

  5. Maciek powiedział(a):

    @Daniel, no właśnie—tutaj też "gwiazdka-SPECIAL-VARIABLE-gwiazdka" nie wyświetliło mi się tak, jak bym chciał. ;)

  6. Maciek powiedział(a):

    @mina86, btw—tak z ciekawości— po co na Twoim blogu jest stopka? ;)

  7. Daniel powiedział(a):

    To chyba jakiegoś innego markdowna znasz, niż ja; aktualna wersja nie psuje gwiazdek-coś-gwiazdek wewnątrz <pre>...</pre>, spokojnie można wklejać.

    Natomiast kolorowanie najchętniej widziałbym jako jakąś wtyczkę/nakładkę na Markdowna, dzięki której można byłoby powiedzieć "pokoloruj ten kawałek kodu jako CL". Chcę, żeby moje wpisy blogowe były plikami tekstowymi. I żeby się łatwo czytały i edytowały.

    A póki co nie koloruję snippetów u siebie. Dłuższe rzeczy i tak wrzucam na GitHub, a w zrozumieniu krótszych kolory nie są aż tak nieodzowne.

Dodaj komentarz:

Kategorie

Archiwum