ox-farm.el - A Shmups Forum effortposting tool

A place for people with an interest in developing new shmups.
Post Reply
User avatar
Lander
Posts: 1204
Joined: Tue Oct 18, 2022 11:15 pm
Location: Area 1 Mostly

ox-farm.el - A Shmups Forum effortposting tool

Post by Lander »

A learned philosopher once said: Cache your important posts in Notepad++

Prithee, friends; join me on a journey to the outer limits of this idea.

♫ NOW PLAYING (LOOP) ♫ Adam Freeland - Fear is the Mind Killer ♫
 
◉ ox-farm.el - A Shmups Forum effortposting tool
 
In part of building my long-promised, recently-released Taromaru ST, I put together a tool called ox-farm.el - Org eXporter for shmupsFARM in Emacs Lisp - in an effort to recover a presentable document from the ST's ill-structured initial draft.

Said draft was composed on a custom posting platform built in SQL and Bash which, frankly, wasn't particularly good to begin with. After losing the control scripts to human error, I ended up dumping the database by hand and building this to replace it:

ox-farm.el - Plaintext In / Shmups Forum Out
Image


ox-farm is, in effect, what that first attempt should have been: A handy utility to ease the composition of ambitious posting projects like STs, score trackers, special occasion posts, and other rich content.

It plugs a high-powered rich text interface - with power and usability well in excess of common formats like Markdown, but cognitive load far below that of LaTeX - into the Shmups Forum variant of BBCode, allowing posts to be composed with a degree of efficiency and efficacy beyond that of the faithful old phpBB editor.
Last edited by Lander on Thu Aug 29, 2024 2:05 am, edited 4 times in total.
User avatar
Lander
Posts: 1204
Joined: Tue Oct 18, 2022 11:15 pm
Location: Area 1 Mostly

Index

Post by Lander »

Last edited by Lander on Tue Aug 27, 2024 5:43 am, edited 2 times in total.
User avatar
Lander
Posts: 1204
Joined: Tue Oct 18, 2022 11:15 pm
Location: Area 1 Mostly

Details

Post by Lander »

◉ Org

Org is a 'major mode' - i.e. specialized file format and suite of associated tooling - for the Emacs text editor. The left panel in the image above illustrates my local setup editing a copy of the Taromaru ST.

It behaves somewhat like Rich Text or Markdown, offering terse inline syntax for text styling, complex structure like nested headlines, tables, inline images, tagged sections (a.k.a. quotes, spoilers, code,) broader functionality like templating, snippet expansion, agenda management, work clocking, and much more.

But - unlike other formats - it accomplishes all of this entirely in user-facing plain text. No HTML/XML style nested tags, opaque backend data, proprietary graphical widgets, or other common text package or format bugbears. Just simple, clever characters, lots of hotkeys, and some very pretty themes. Owing to this, it can be read and written outside of Emacs like any other plain text - albeit without the various built-in utilities. See Example for details.

ox-farm implements a Shmups export backend for Org, so you can export to it in much the same way as other supported format, like HTML, PDF, or LaTeX.

For those looking to pick up Org, System Crafters has a good series of tutorial videos, and accompanying quick-start Emacs configuration.

◉ Emacs

GNU Emacs is the world's longest-standing extensible text editor. It takes the extremely broad problem of managing characters on a screen, and - effectively - solves it.

Which is to say, it's better referred to as an advanced framework for text-based applications. Or, for the pedantic, an extremely well-integrated Lisp interpreter.

One could further state that it's more of a 'do everything' program at this point in its life, ranging from a humble text editor, through email client, feed reader, web browser, operating system, all the way to full blown organise my entire life plz Zettelkasten system.

For a more practical example: In this case we're just using it to compose, but Emacs is powerful enough that it could scale all the way to hosting a full-featured Shmups Forum desktop client.

◉ Lisp

Lisp (or List Processor) is a prolific family of programming languages established during the 1980s, which rose to prominence in the field of Artificial Intelligence research.

Its most interesting property is homoiconicity - which is to say, its internal and external representations are essentially the same. To wit, it's just about the simplest language you can invent without sacrificing expressibility or falling down the esolang hole.

It's simple. Elegant, if a little bracket-heavy. And Emacs - and by extension, ox-farm - is entirely written and configured in a specialized version of it called Emacs Lisp, meaning it'll run consistently anywhere.

Fret not - you don't need to know programming to use Emacs unless you want to write a plugin; using Lisp to write the equivalent of an INI or .conf file is quite trivial.
But know that Lisp is a prime factor in Emacs' evolution into a freestanding ultra-hackable software ecosystem, and is - more generally - quite cool 8)

◉ Further reading

GNU Emacs
Org mode for GNU Emacs
Lisp (programming language) - Wikipedia
Last edited by Lander on Tue Aug 27, 2024 5:10 am, edited 4 times in total.
User avatar
Lander
Posts: 1204
Joined: Tue Oct 18, 2022 11:15 pm
Location: Area 1 Mostly

Installation

Post by Lander »

ox-farm can be installed by copying the source code below into a file named ox-farm.el within one of Emacs' local load paths, and adding the following to your init file:

Code: Select all

(with-eval-after-load "org"
  (require 'ox-farm)
  (add-to-list 'org-export-backends 'farm))
For a less manual experience, configuring it as a local package in a manager such as use-package or elpaca is recommended.

It depends on ox-bb , which can be installed automatically if configured via package manager, or manually from within emacs with the following command:

Code: Select all

C-x package-install RET
ox-bb RET
(Note: This may require manual configuration of extra package sources, such as MELPA.)

◉ Inline image support

This configuration snippet (and its org-yt dependency) provide Org the means to display HTTP image links inline, and Shmups Forum image tags are - presently - implemented in ox-farm by way of its imghttp and imghttps URL types.

◉ Animated GIF support

The org-inline-anim package is also recommended, as a means to preview animated GIFs.
Last edited by Lander on Tue Aug 27, 2024 5:12 am, edited 6 times in total.
User avatar
Lander
Posts: 1204
Joined: Tue Oct 18, 2022 11:15 pm
Location: Area 1 Mostly

Source Code

Post by Lander »

Code: Select all

;;; ox-farm.el --- Org eXporter for shmupsFARM in Emacs Lisp -*- lexical-binding: t; -*-

;; Copyright (C) 2024 Lander
;; Licensed under GNU GPL v3 or later.

;; This file is part of ox-farm.

;; ox-farm is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; ox-farm is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with ox-farm.  If not, see <http://www.gnu.org/licenses/>.

;; Author: Lander
;; URL: https://shmups.system11.org/memberlist.php?mode=viewprofile&u=25062
;; Keywords: shmups forum, bbcode, org, export, outlines
;; Version: 0.0.1
;; Package-Requires: ((emacs "24.4")
;;                    (org   "8.0")
;;                    (ox-bb "0.0.1"))

;;; Commentary:

;; This library implements a Shmups Forum BBCode back-end for Org exporter.
;; It builds upon ox-bb, by Christian Garbs.
;;
;; ox-farm provides four different commands for export:
;;
;; - `ox-farm-export-as-bbcode' exports to a buffer named
;;   "*Org Shmups Forum Export*" and automatically applies `bbcode-mode'
;;   if it is available.
;;
;; - `ox-farm-export-to-kill-ring' does the same and additionally copies
;;   the exported buffer to the kill ring so that the generated BBCode
;;   is available in the Clipboard.
;;
;; - `ox-farm-export-to-bbcode' exports to a file with an extension
;;   configured via `org-bbcode-extension', or ".bbcode" if it is nil.
;;
;; - `org-farm-publish-to-bbcode' exports a file to Shmups Forum BBCode
;;   via the Org backend, and can be used to publish as a
;;   project via the Org Export Dispatcher (C-c C-e P).

;;; Code:

(require 'ox)
(require 'ox-bb)

;;; Globals

(defvar ox-farm-base-url "https://shmups.system11.org"
  "Base URL for auto-generated Shmups Forum links.")

(defvar ox-farm-post-ids '()
  "Alist mapping file URI string to numeric Shmups Forum post ID.
If set, local file links will be remapped to the corresponding post.")

(defvar ox-farm-headline-bullets
  '("◉" "    ○" "        ●" "            ○" "                 ●")
  "List of characters used to identify headline levels.")

(defvar ox-farm-headline-sizes
  '(150 140 130 120 110)
  "List of Shmups Forum font sizes used for headline levels.")

(defvar ox-farm-headline-colors
  '("#ff79c6" "#d4b8fb" "#ffa7d9" "#d4b8fb" "#ffa7d9")
  "List of hexadecimal color codes used for headline levels.")

(defvar ox-farm-link-color
  "#ffb86c"
  "Hexadecimal color code used for links.")

;;;###autoload
(defvar org-bb-extension "bbcode"
  "File extension to use for published BBCode files.")

;;; Backend definition

; internal reminder: for Org format information see
; https://orgmode.org/worg/dev/org-element-api.html

(org-export-define-backend 'farm
  '((bold . ox-bb-bold)
    (center-block . ox-bb-undefined)
    (clock . ox-bb-undefined)
    (code . ox-farm-code)
    (drawer . ox-bb-undefined)
    (dynamic-block . ox-bb-undefined)
    (entity . ox-bb-entity)
    (example-block . ox-bb-undefined)
    (export-block . ox-bb-undefined)
    (export-snippet . ox-bb-undefined)
    (fixed-width . ox-bb-fixed-width)
    (footnote-definition . ox-bb-footnote-definition)
    (footnote-reference . ox-bb-footnote-reference)
    (headline . ox-farm-headline)
    (horizontal-rule . ox-bb-undefined)
    (inline-src-block . ox-bb-undefined)
    (inlinetask . ox-bb-undefined)
    (inner-template . ox-bb-inner-template)
    (italic . ox-bb-italic)
    (item . ox-bb-item)
    ;; (keyword . ox-bb-undefined) ;; don't fail, just skip keywords
    (latex-environment . ox-bb-undefined)
    (latex-fragment . ox-bb-undefined)
    (line-break . ox-farm-line-break)
    (link . ox-farm-link)
    (node-property . ox-bb-undefined)
    (paragraph . ox-bb-paragraph)
    (plain-list . ox-farm-plain-list)
    (plain-text . ox-bb-plain-text)
    (planning . ox-bb-undefined)
    (property-drawer . ox-bb-undefined)
    (quote-block . ox-bb-quote-block)
    (radio-target . ox-bb-undefined)
    (section . ox-bb-section)
    (special-block . ox-farm-special-block)
    (src-block . ox-farm-src-block)
    (statistics-cookie . ox-bb-undefined)
    (strike-through . ox-bb-undefined)
    (subscript . ox-bb-undefined)
    (superscript . ox-bb-undefined)
    (table . ox-farm-table)
    (table-cell . ox-farm-table-cell)
    (table-row . ox-farm-table-row)
    (target . ox-bb-undefined)
    (template . ox-bb-template)
    (timestamp . ox-bb-undefined)
    (underline . ox-bb-underline)
    (verbatim . ox-farm-verbatim)
    (verse-block . ox-bb-undefined))
  :menu-entry
  '(?f "Export to Shmups Forum"
       ((?B "As BBCode buffer" ox-farm-export-as-bbcode)
        (?f "As BBCode file" ox-farm-export-to-bbcode)
        (?b "As BBCode buffer and to clipboard" ox-farm-export-to-kill-ring))))

;; prevent bogus byte-compiler warning
(declare-function bbcode-mode "bbcode-mode" ())

(defun ox-farm-headline (headline contents info)
  "Transcode HEADLINE element from Org to BBCode.
CONTENTS is the headline contents.  INFO is a plist used as
a communication channel."
  (let ((title (org-export-data (org-element-property :title headline) info))
        (level (org-export-get-relative-level headline info)))
    (if (org-element-property :footnote-section-p headline)
        ""
      (concat
       (ox-farm--format-headline title level)
       contents))))

(defun ox-farm--format-headline (text level)
  "Format TEXT as a headline of the given LEVEL."
  (let* ((index (- level 1))
         (indent (nth index ox-farm-headline-bullets))
         (size (nth index ox-farm-headline-sizes))
         (color (nth index ox-farm-headline-colors)))
    (concat (ox-bb--put-in-value-tag
             "color"
             (ox-bb--put-in-value-tag
              "size"
              (format "%s %s" indent text)
              size)
             color)
            "\n")))

(defun ox-farm-line-break (_line-break _contents _info)
  "Transcode a LINE-BREAK object from Org to Shmups Forum BBCode.
CONTENTS is nil.  INFO is a plist holding contextual
information."
  ;; Org and Shmups Forum both strip whitespace,
  ;; so we use an empty modifier to force the matter.
  "[b][/b]\n")

(defun ox-farm-link (link contents _info)
  "Transcode a LINK element from Org to Shmups Forum BBCode.
CONTENTS is the contents of the link, as a string.  INFO is
  a plist used as a communication channel."
  (let ((type (org-element-property :type link))
        (path (org-element-property :path link))
        (raw  (org-element-property :raw-link link)))
    (cond
     ((string= type "fuzzy")
      (cond
       ((string-prefix-p "about:" raw)
        (ox-farm--put-url contents raw))
       (t (user-error "Unknown fuzzy LINK type encountered: `%s'" raw))))
     ;; Regular HTTP
     ((member type '("http" "https"))
      (ox-farm--put-url contents (concat type ":" path)))
     ;; Inline image HTTP
     ((member type '("imghttp" "imghttps"))
      (ox-bb--put-in-tag "img" (concat (substring type 3) ":" path)))
     ;; Local file
     ((equal type "file")
      (message "Path: %s" path)
      (if-let ((post-id (alist-get path ox-farm-post-ids
                                   nil nil #'equal)))
          ;; Substitute any local file links with known post IDs
          (ox-farm--put-url contents (format "%s/viewtopic.php?p=%s#p%s"
                                             ox-farm-base-url
                                             post-id
                                             post-id))
        ;; Otherwise, warn the user that their link is invalid
        (user-error "File link %s has no ox-farm-post-ids entry" path)))
     (t (user-error "LINK type `%s' not yet supported" type)))))

(defun ox-farm--put-url (contents href)
  "Puts the CONTENTS inside a [url] tag pointing to HREF.
Automagically escapes the target URL."
  (let* ((target (ox-bb--fix-url (url-encode-url (org-link-unescape href))))
         (text   (or contents target)))
    (ox-farm--format-link target text)))

(defun ox-farm--format-link (target text)
  "Puts TEXT into a styled url tag pointing at TARGET."
  (ox-bb--put-in-tag
   "b"
   (ox-bb--put-in-value-tag
    "url"
    (ox-bb--put-in-value-tag
     "color"
     text
     ox-farm-link-color)
    target)))

(defun ox-farm--put-in-value-tag (tag value contents &optional attributes)
  "Puts the BBcode tag TAG around the CONTENTS string.
Optional ATTRIBUTES for the tag can be given as an alist of
key/value pairs (both strings)."
  (let ((attribute-string
         (if attributes
             (mapconcat
              (function (lambda (attribute)
                          (let ((key (car attribute))
                                (value (cdr attribute)))
                            (format " %s=%s" key value))))
              attributes
              "")
           "")))
    (format "[%s=%s%s]%s[/%s]" tag value attribute-string contents tag)))

(defun ox-farm-special-block (special-block contents _info)
  "Transcode a SPECIAL-BLOCK element from Org to BBCode.
CONTENTS holds the contents of the block.  INFO is a plist used
as a communication channel."
  (let ((type (org-element-property :type special-block)))
    (pcase type
      ("spoiler" (let* ((params
                         (org-babel-parse-header-arguments
                          (org-element-property
                           :parameters
                           special-block)))
                        (name (alist-get :name params))
                        (contents (ox-bb--force-leading-newline contents)))
                   (ox-bb--put-in-value-tag
                    type
                    (ox-bb--force-leading-newline contents)
                    (format "\"%s\"" name))))
      ("shmups_quote" (let* ((params
                              (org-babel-parse-header-arguments
                               (org-element-property
                                :parameters
                                special-block)))
                             (user (alist-get :user params))
                             (post-id (alist-get :post-id params))
                             (time (alist-get :time params))
                             (user-id (alist-get :user-id params))
                             (contents (ox-bb--force-leading-newline contents))
                             attributes)
                        (dolist (param `(("post_id" . ,post-id)
                                         ("time" . ,time)
                                         ("user_id" . ,user-id)))
                          (when (cdr param)
                            (push param attributes)))
                        (message "Attributes: %s" attributes)
                        (ox-farm--put-in-value-tag
                         "quote"
                         user
                         (ox-bb--force-leading-newline contents)
                         attributes)))
      (t (error "SPECIAL-BLOCK type %s is not implemented" type)))))

(defun ox-farm-code (code _contents _info)
  "Transcode a CODE element from Org to Shmups Forum BBCode.
CONTENTS is nil.  INFO is a plist used as a communication channel."
  (ox-bb--put-in-value-tag
   "color" (org-element-property :value code) "#FFFF00"))

(defun ox-farm-verbatim (code _contents _info)
  "Transcode a CODE element from Org to Shmups Forum BBCode.
CONTENTS is nil.  INFO is a plist used as a communication channel."
  (ox-bb--put-in-value-tag
   "color" (org-element-property :value code) "#00FF00"))

(defun ox-farm-plain-list (plain-list contents _info)
  "Transcode a PLAIN-LIST element from Org to Shmups Forum BBCode.
CONTENTS is the contents of the plain-list, as a string.  INFO is
  a plist used as a communication channel."
  (let* ((type (org-element-property :type plain-list))
         (structure (org-element-property :structure plain-list))
         (first-bullet (substring (caddr (car structure)) 0 1))
         (content-block (ox-bb--as-block (org-trim contents))))
    (message (pp first-bullet))
    (concat
     (pcase type
       (`descriptive (ox-bb--put-in-tag "list" content-block))
       (`unordered (ox-bb--put-in-tag "list" content-block))
       (`ordered (ox-bb--put-in-value-tag "list" content-block first-bullet))
       (other (user-error "PLAIN-LIST type `%s' not yet supported" other)))
     "\n")))

(defun ox-farm-table (table contents _info)
  "Transcode a TABLE element from Org to Shmups Forum BBCode.
CONTENTS contains the already rendered body of the table.  INFO
is a plist used as a communication channel."
  (ox-bb--put-in-value-tag "table"
                           contents
                           (if-let ((name (org-element-property :name table)))
                               (format "\"%s\"" name)
                             "")))

(defun ox-farm-table-row (_table-row contents _info)
  "Transcode a TABLE-ROW element from Org to Shmups Forum BBCode.
CONTENTS contains the already rendered row content.  INFO is a
plist used as a communication channel."
  (ox-bb--put-in-tag "tr"
                     (if contents
                         contents
                       "")))

(defun ox-farm-table-cell (_table-cell contents _info)
  "Transcode a TABLE-CELL element from Org to Shmups Forum BBCode.
CONTENTS contains the already rendered cell content.  INFO is a
plist used as a communication channel."
  (ox-bb--put-in-tag "td"
                     (if contents
                         contents
                       "")))

(defun ox-farm-src-block (src-block _contents info)
  "Transcode a SRC-BLOCK element from Org to Shmups Farm BBCode.
CONTENTS holds the contents of the block.  INFO is a plist used
as a communication channel."
  (let ((code (org-export-format-code-default src-block info)))
    (if (equal code "") ""
      (ox-bb--put-in-tag "code" (ox-bb--force-leading-newline code)))))

;;; Export methods

;;;###autoload
(defun ox-farm-export-as-bbcode
    (&optional async subtreep visible-only body-only ext-plist)
  "Export current buffer to a Shmups Forum BBCode buffer.

If narrowing is active in the current buffer, only export its
narrowed part.

If a region is active, export that region.

A non-nil optional argument ASYNC means the process should happen
asynchronously.  The resulting buffer should be accessible
through the `org-export-stack' interface.

When optional argument SUBTREEP is non-nil, export the sub-tree
at point, extracting information from the headline properties
first.

When optional argument VISIBLE-ONLY is non-nil, don't export
contents of hidden elements.

TODO: document BODY-ONLY

EXT-PLIST, when provided, is a property list with external
parameters overriding Org default settings, but still inferior to
file-local settings.

Export is done in a buffer named \"*Org Shmups Forum Export*\".  If
available, `bbcode-mode' is enabled in the buffer."
  (interactive)
  (org-export-to-buffer 'farm "*Org Shmups Forum Export*"
    async subtreep visible-only body-only ext-plist
    (lambda () (when (featurep 'bbcode-mode) (bbcode-mode)))))

;;;###autoload
(defun ox-farm-export-to-bbcode
    (&optional async subtreep visible-only body-only ext-plist)
  "Export current buffer to a Shmups Forum BBCode file.

If narrowing is active in the current buffer, only export its
narrowed part.

If a region is active, export that region.

A non-nil optional argument ASYNC means the process should happen
asynchronously.  The resulting buffer should be accessible
through the `org-export-stack' interface.

When optional argument SUBTREEP is non-nil, export the sub-tree
at point, extracting information from the headline properties
first.

When optional argument VISIBLE-ONLY is non-nil, don't export
contents of hidden elements.

TODO: document BODY-ONLY

EXT-PLIST, when provided, is a property list with external
parameters overriding Org default settings, but still inferior to
file-local settings.

Return output file's name."
  (interactive)
  (let* ((file (org-export-output-file-name org-bb-extension subtreep))
         (org-export-coding-system org-html-coding-system))
    (org-export-to-file 'farm file
      async subtreep visible-only body-only ext-plist)))

;;;###autoload
(defun ox-farm-export-to-kill-ring
    (&optional async subtreep visible-only body-only ext-plist)
  "Export current buffer to a Shmups Forum BBCode buffer and kill ring.

If narrowing is active in the current buffer, only export its
narrowed part.

If a region is active, export that region.

A non-nil optional argument ASYNC means the process should happen
asynchronously.  The resulting buffer should be accessible
through the `org-export-stack' interface.

When optional argument SUBTREEP is non-nil, export the sub-tree
at point, extracting information from the headline properties
first.

When optional argument VISIBLE-ONLY is non-nil, don't export
contents of hidden elements.

TODO: document BODY-ONLY

EXT-PLIST, when provided, is a property list with external
parameters overriding Org default settings, but still inferior to
file-local settings.

Export is done in a buffer named \"*Org Shmups Forum Export*\" which is
automatically copied to the kill ring (Clipboard)."
  (interactive)
  (let ((oldval org-export-copy-to-kill-ring))
    (progn
      (setq org-export-copy-to-kill-ring t)
      (ox-farm-export-as-bbcode async subtreep visible-only body-only ext-plist)
      (setq org-export-copy-to-kill-ring oldval))))

(defun org-farm-publish-to-bbcode (plist filename pub-dir)
  "Publish an org file to Shmups Forum BBCode.

FILENAME is the filename of the Org file to be published.
PLIST is the property list for the given project.
PUB-DIR is the publishing directory.

Return output file name."
  (org-publish-org-to 'farm filename
                      (concat (when (> (length org-bb-extension) 0) ".")
                              (or (plist-get plist :bb-extension)
                                  org-bb-extension
                                  "bbcode"))
                      plist pub-dir))

;;; Package provision

(provide 'ox-farm)

;;; ox-farm.el ends here
Last edited by Lander on Tue Aug 27, 2024 3:34 am, edited 1 time in total.
User avatar
Lander
Posts: 1204
Joined: Tue Oct 18, 2022 11:15 pm
Location: Area 1 Mostly

Usage

Post by Lander »

ox-farm is most easily invoked via the Org Export Dispatcher - hotkeyed to C-c C-e f when editing an Org buffer.

The Org Export Dispatcher
Image


◉ Basic

For single-post usage, the Export to BBCode buffer and clipboard command is the most direct option - invoked with C-c C-e f b, it will perform conversion, display the result in a buffer for inspection, and copy its contents to the system clipboard for easy pasting into the Shmups Forum posting interface.

    ○ Alphabetical ordered lists

ox-farm is capable of exporting both numeric and alphabetized ordered lists (see the Example section for details,) but the org-list-allow-alphabetical variable must to be set to t to activate the associated Org syntax:

Code: Select all

M-x customize-group RET
org-plain-lists RET
[Customize 'Org List Allow Alphabetical' entry via user interface.]
Or, more directly:

Code: Select all

M-: (setq org-list-allow-alphabetical t) RET
    ○ Advanced

Larger content spanning multiple posts can be organized into an Org Project; a collection of files that can be exported together in batch.

This requires creating an export configuration - most conveniently as an inline Emacs Lisp source block that can be run from an Org buffer with C-c C-c, or as a freestanding .el file that can be run with C-c C-e.

This configuration will persist for the remainder of the editing session, allowing the C-c C-e P family of commands to act as quick batch exports.

Code: Select all

;; Define the publishing project
(setq org-publish-project-alist
      (list
       (list "my-st"
             :base-directory "/path/to/my-st/content"
             :publishing-directory "/path/to/my-st/posts"
             :publishing-function 'org-farm-publish-to-bbcode
             :preserve-breaks t)))

;; Publish to disk
(org-publish-all t)
In practical use, the Basic workflow is still likely to be the most ergonomic for multi-file projects, but batch processing is useful for making sure none of your files have errors without manually converting them one-by-one.

It's also worth noting that - since Emacs is fundamentally a Lisp interpreter - this process can be invoked from the command line (or a shell script / batch file) using the --eval switch to publish content without ever touching the GUI.

        ● Autogenerated links

Org links between local files - the kind you might create with C-c C-l file:my-file.org RET My File RET and navigate with C-c C-o while editing your project - can be automatically converted into the respective Shmups Forum HTTP links during export.

To do this, set the ox-farm-post-ids variable in your export configuration before invoking org-publish-all; it should be formatted as an associative list with local file path strings as keys, and numeric post IDs as values, which can be extracted from the end of a Shmups Forum URL by copy-pasting it into an editor.

Code: Select all

;; Specify mapping from files to Shmups Forum post IDs
(setq ox-farm-post-ids
  '(("01-opening.org"   . 1234)
    ("02-anecdotes.org" . 1235)
    ("03-content.org"   . 1236)
    ("04-closing.org"   . 1237)))

◉ Customization

ox-farm exposes a set of variables for styling the generated output. These can be found under the Globals header in the source code, and inspected or modified in your export script. They can also be inspected and modified from within Emacs by typing C-h v <variable-name> RET.
Last edited by Lander on Tue Aug 27, 2024 5:31 am, edited 6 times in total.
User avatar
Lander
Posts: 1204
Joined: Tue Oct 18, 2022 11:15 pm
Location: Area 1 Mostly

Example

Post by Lander »

The following Org document:

Code: Select all

* Heading 1
** Heading 2
*** Heading 3
**** Heading 4
***** Heading 5
\\
* Plain text
\\
Totototo.
Chichipa.
Papapap.
\\
* Styling
\\
*Bold*
/Italic/
_Underline_
=Verbatim=
~Code~
\\
* Link
\\
[[https://shmups.system11.org][Link]]
\\
* Inline Image
\\
[[imghttps://i.imgur.com/VZQmO5Z.png]]
\\
* Unordered lists
\\
** Dash syntax

- Dash
- List
- Syntax
  - Neat

** Plus syntax

+ Plus
+ List
+ Syntax
  + Cool

** Star syntax

 * Star
 * List
 * Syntax
   * (Not recommended)

** Description syntax

- My position on Ketsui :: Helicopters are rad.
+ Quoth of Donpachi :: Bees be mad.
 * Star syntax :: Indents kinda bad.

* Ordered lists
\\
** Braced
\\
*** Numbered
\\
1) Numbered
2) Braced
3) List
*** Alphabet
\\
a) Alphabet
b) Braced
c) List
*** ALPHABET
\\
A) ALPHABET
B) Braced
C) List
** Dotted
\\
*** Numbered
\\
1. Numbered
2. Dotted
3. List
*** Alphabet
\\
a. Alphabet
b. Dotted
c. List
*** ALPHABET
\\
A. Alphabet
B. Dotted
C. List
* Table
\\
#+NAME: I am a Table
| *Otherwise* |    Little |
| *Known*     |     Bobby |
| *As*        |    Tables |
| /QED/       | :mrgreen: |
\\
* Code Block

#+begin_src elisp :results silent
  (message "Hello, world!")
#+end_src

* Quote Block

#+begin_shmups_quote :user Lander :post-id 1561673 :time 1724215561 :user-id 25062
  Some lengthy blather no doubt.
#+end_shmups_quote

* Spoiler Block

#+begin_spoiler :name Naughty Secrets
  That mountain in the background has an eagle on it.
#+end_spoiler
Looks like this in appropriately-themed Emacs
Image


And renders like this on Shmups Forum:

◉ Heading 1
    ○ Heading 2
        ● Heading 3
            ○ Heading 4
                 ● Heading 5

◉ Plain text

Totototo.
Chichipa.
Papapap.

◉ Styling

Bold
Italic
Underline
Verbatim
Code

◉ Link

Link

◉ Inline Image

Image

◉ Unordered lists

    ○ Dash syntax
  • Dash
  • List
  • Syntax
    • Neat
    ○ Plus syntax
  • Plus
  • List
  • Syntax
    • Cool
    ○ Star syntax
  • Star
  • List
  • Syntax
    • (Not recommended)
    ○ Description syntax
  • My position on Ketsui: Helicopters are rad.
  • Quoth of Donpachi: Bees be mad.
    • Star syntax: Indents kinda bad.
◉ Ordered lists
    ○ Braced
        ● Numbered
  1. Numbered
  2. Braced
  3. List
        ● Alphabet
  1. Alphabet
  2. Braced
  3. List
        ● ALPHABET
  1. ALPHABET
  2. Braced
  3. List
    ○ Dotted
        ● Numbered
  1. Numbered
  2. Dotted
  3. List
        ● Alphabet
  1. Alphabet
  2. Dotted
  3. List
        ● ALPHABET
  1. Alphabet
  2. Dotted
  3. List
◉ Table

I am a Table
OtherwiseLittle
KnownBobby
AsTables
QED:mrgreen:


◉ Code Block

Code: Select all

(message "Hello, world!")
◉ Quote Block
Lander wrote: Wed Aug 21, 2024 4:46 am Some lengthy blather no doubt.
◉ Spoiler Block
Naughty Secrets
That mountain in the background has an eagle on it.
Last edited by Lander on Tue Aug 27, 2024 5:08 am, edited 14 times in total.
User avatar
Lander
Posts: 1204
Joined: Tue Oct 18, 2022 11:15 pm
Location: Area 1 Mostly

Closing

Post by Lander »

◉ Changelog
    ○ v0.0.1

Initial release.

◉ Future Research

If there's interest, I might be able to package a subset of my own Emacs configuration into an easy-start distribution specialized around editing Shmups posts, to make it a bit easier for interested users to get on-board - let me know.

Longer term, I'd like to extend Emacs to be able to read the 'farm as well as write it; essentially acting as a smart frontend to a web session that's able to filter pages down to clean minimal text, and present it as an Org buffer.

And then there's more fanciful stuff, like gluing the reading and writing together with various bits of UI, mimicking the various around-the-edges bits of the site and bringing it up to feature-parity. It's daydream-y blue sky territory right now, but would be nice to do.

◉ Compatibility

I'd be grateful if other users could confirm whether the header indenting looks correct, since the non-breaking-space character used for it may end up in different proportion depending on your local font setup - ideally, each subsequent level's dot should left-align with the first letter of the headline above it.

If that doesn't work properly across systems, I'll revert the defaults back to no indent for the next release.
User avatar
BIL
Posts: 19685
Joined: Thu May 10, 2007 12:39 pm
Location: COLONY

Re: ox-farm.el - A Shmups Forum effortposting tool

Post by BIL »

Superb! Image Indentation looks good to me, with the mild caveat I'm currently on my ancient-ass 4:3 monitor. :oops: Will check via 16:9 monitor today, too.

Got a few STs on the back burner, currently, so will give the documentation a look, and see if I can whip up a few drafts. :smile:
User avatar
Lander
Posts: 1204
Joined: Tue Oct 18, 2022 11:15 pm
Location: Area 1 Mostly

Re: ox-farm.el - A Shmups Forum effortposting tool

Post by Lander »

Nice, thanks for the confirmation - it should be fine across aspect ratios; the big ticket is whether the 'farm font is standardized between different browsers, OSes, and so on.
Web being web, there's almost certainly some way to break it, but with any luck that'll only be for folks who customize their browser and understand the risks :mrgreen:

And cool! Feel free to ask if you need any setup advice, starting vanilla Emacs for the first time and seeing this unfriendly ox staring back in eye-searing #FFFFFF has a tendency to scare people away :oops:
Post Reply