commit 8cf7f1a5cd7d339c66a5b4bc0e1e48ecf4cef758 Author: Lucien Cartier-Tilet Date: Tue Jun 1 01:17:03 2021 +0200 initial commit I’m basically porting my old `conlanging' Spacemacs layer to a vanilla Emacs package. The original layer can be found here: https://labs.phundrak.com/phundrak/conlang-layer diff --git a/conlanging.el b/conlanging.el new file mode 100644 index 0000000..78a3111 --- /dev/null +++ b/conlanging.el @@ -0,0 +1,370 @@ +;;; conlanging.el --- Helper functions for conlanging -*- lexical-binding: t -*- + +;; Author: Lucien Cartier-Tilet +;; Maintainer: Lucien Cartier-Tilet +;; Version: 0.1.0 +;; Package-Requires: ((emacs "24") (org "9") (eioio "1")) +;; Homepage: https://labs.phundrak.com/phundrak/conlanging.el + +;; This file is not part of GNU Emacs + +;; This program 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. + +;; This program 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 this program. If not, see . + + +;;; Commentary: +;; This package is not made in order to be used by a lot of people. +;; Actually, it is made only for me. As such, there is no chance to +;; find it on any ELPA or MELPA. +;; +;; Functions and variables in this package are just helpers for myself +;; in order to write more easily the documentation on my conlangs. +;; This includes stuff such as automatic generation of text in +;; non-latin scripts or LaTeX-specific text from transliterated text, +;; graphviz trees for some stuff like syntax and feature trees, and +;; finally functions for creating automatic phonetics of a language a +;; tad complex when it comes to its pronunciation. + +;;; Code: + +(require 'org) +(require 'ox) +(require 'seq) +(require 'eieio) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ; Tree generation ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun conlanging--declare-node (t-node-text t-node-generation) + "Declares a node in the graphviz source code. + +The node’s identifier will be `T-NODE-GENERATION', and it will +bear the label `T-NODE-TEXT'." + (format "%d[label=\"%s\"];" + t-node-generation + t-node-text)) + +;;;###autoload +(defun conlanging-tree-to-dot (t-tree &optional t-current-generation t-previous-generation) + "Translate an Elisp tree into a graphviz tree. + +Translate `T-TREE' with any number of children per node +to a corresponding graphviz file that can be executed from dot. + +`T-CURRENT-GENERATION' represents the generation number, +incremented when changing from a node to another node from the +same generation, multiplied by 10 when going from a node to one +of its children. For internal use only. + +`T-PREVIOUS-GENERATION' is the generation number from previous +named node. For internal use only." + (cond + ((null t-previous-generation) ;; first call + (concat "graph{graph[dpi=300];node[shape=plaintext];graph[bgcolor=\"transparent\"];" + (conlanging--declare-node (car t-tree) 0) + (conlanging-tree-to-dot (cdr t-tree) 1 0) + "}")) + ((null t-tree) "") ;; last call in this branch + ((atom (car t-tree)) ;; '("text" () () ()) manage the label + (concat (conlanging--declare-node (car t-tree) + t-current-generation) + ;; make link + (concat (number-to-string t-previous-generation) " -- " + (number-to-string t-current-generation) ";") + (conlanging-tree-to-dot (cdr t-tree) + (+ 1 + (* 10 t-current-generation)) + t-current-generation))) + ((listp (car t-tree)) ;; '(() () ()) manage the branches + (concat (conlanging-tree-to-dot (car t-tree) ;; child of current node + t-current-generation + t-previous-generation) + (conlanging-tree-to-dot (cdr t-tree) + (+ 1 t-current-generation) + t-previous-generation))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ; Text transformation ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + ; Mattér ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ; dead conlang ;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar conlanging--matter-latin-to-runes '((", *" . "᛬") + ("\\. *" . "᛭") + (" +" . "᛫") + ("ċ" . "ᛇ") + ("ch" . "ᛇ") + ("ae" . "ᚫ") + ("æ" . "ᚫ") + ("dh" . "ᛋ") + ("z" . "ᛋ") + ("ð" . "ᛋ") + ("th" . "ᚦ") + ("s" . "ᚦ") + ("þ" . "ᚦ") + ("w" . "ᚹ") + ("ƿ" . "ᚹ") + ("g" . "ᚷ") + ("ᵹ" . "ᚷ") + ("ea" . "ᛠ") + ("f" . "ᚠ") + ("u" . "ᚢ") + ("o" . "ᚩ") + ("r" . "ᚱ") + ("c" . "ᚳ") + ("h" . "ᚻ") + ("n" . "ᚾ") + ("i" . "ᛁ") + ("j" . "ᛄ") + ("p" . "ᛈ") + ("v" . "ᛝ") + ("t" . "ᛏ") + ("b" . "ᛒ") + ("e" . "ᛖ") + ("m" . "ᛗ") + ("l" . "ᛚ") + ("d" . "ᛞ") + ("é" . "ᛟ") + ("a" . "ᚪ") + ("y" . "ᚣ")) + "Equivalence between the Mattér Latin and Runic scripts. + +The first element of a pair is the Latin script orthography, the +second is the Runic equivalent.") + +(defvar conlanging--matter-latin-to-native '((" +" . " ") + ("ch" . "ċ") + ("ae" . "æ") + ("th" . "þ") + ("s" . "þ") + ("dh" . "ð") + ("z" . "ð") + ("w" . "ƿ") + ("j" . "i")) + "Equivalence between Mattér orthography and transliterated Mattér. + +The first element of a pair is the transliterated Latin script +orthography, the second is the native Latin script equivalent.") + +(defvar conlanging--matter-latin-to-latex '((", *" . ":") + ("\\. *" . "*") + (" +" . ".") + ("ch" . "I") + ("ċ" . "I") + ("ae" . "æ") + ("ea" . "\\\\ea") + ("ƿ" . "w") + ("dh" . "s") + ("z" . "s") + ("ð" . "s") + ("th" . "þ") + ("s" . "þ") + ("v" . "\\\\ng") + ("é " . "\\\\oe")) + "Mattér orthography to LaTeX code. + +Equivalence between the Mattér orthography in the Latin script +and the LaTeX code for the Runic script. The first element of a +pair is the Latin script orthography, the second is the Runic +LaTeX code equivalent.") + + ; Eittlandic ;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar conlanging--eittlandic-latin-to-latex '((", *\\|\\. *" . "\\\\tripledot") + (" +" . ":") + ("hv" . "x") + ("í" . "i") + ("é" . "\\\\e") + ("ę\\|æ" . "æ") + ("ý" . "y") + ("œ" . "ø") + ("ú" . "u") + ("ó" . "o") + ("á\\|ǫ" . "a") + ("j" . "i")) + "Eittlandic Latin script to LaTeX code. +The first element of a pair is the Latin script orthography, the +second is the Runic LaTeX code equivalent.") + +(defvar conlanging--eittlandic-latin-to-runes '((", *\\|\\. *" . "⁝") + (" +\\|:" . "᛬") + ("hv" . "ᛪ") + ("i\\|í\\|j" . "ᛁ") + ("é" . "ᛂ") + ("e\\|ę\\|æ" . "ᛅ") + ("y\\|ý" . "ᛦ") + ("ø\\|œ" . "ᚯ") + ("u\\|ú\\|v\\|w" . "ᚢ") + ("o\\|ó" . "ᚮ") + ("a\\|á\\|ǫ" . "ᛆ") + ("p" . "ᛔ") + ("b" . "ᛒ") + ("f" . "ᚠ") + ("t" . "ᛐ") + ("d" . "ᛑ") + ("þ" . "ᚦ") + ("ð" . "ᚧ") + ("s" . "ᛋ") + ("k" . "ᚴ") + ("g" . "ᚵ") + ("h" . "ᚼ") + ("m" . "ᛘ") + ("n" . "ᚿ") + ("r" . "ᚱ") + ("l" . "ᛚ")) + "Eittlandic latin orthography to runes. +The first element of a pair is the Latin script orthography, the +second is the Runic equivalent.") + +(defvar conlanging-language-list `((matter-runes . ,conlanging--matter-latin-to-runes) + (matter-latin . ,conlanging--matter-latin-to-native) + (matter-latex . ,conlanging--matter-latin-to-latex) + (eittlandic-runes . ,conlanging--eittlandic-latin-to-runes) + (eittlandic-latex . ,conlanging--eittlandic-latin-to-latex))) + +(defun conlanging--translate (text table) + "Translate TEXT through its correspondance TABLE." + (dolist (elem table) + (setq text (replace-regexp-in-string (car elem) (cdr elem) text))) + text) + +(defun conlanging--replace-region-by-translation (table) + "Replace region with its translation through TABLE. +See `conlanging--translate'." + (interactive) + (let* ((beg (region-beginning)) + (end (region-end)) + (region-str (buffer-substring-no-properties beg end))) + (delete-region beg end) + (goto-char beg) + (insert (conlanging--translate region-str table)))) + +;;;###autoload +(defun conlanging-language-to-script (text language) + "Transform TEXT or current word or region in LANGUAGE to its native script. +LANGUAGE can be one of the values found in `conlanging-language-list'." + (interactive) + (let* ((table (alist-get language conlanging-language-list))) + (conlanging--translate text table))) + +;;;###autoload +(defun conlanging-to-org-runes (text language) + "Translate TEXT from LANGUAGE to LaTeX runes equivalent for org exports. + +LANGUAGE must be one of the following values: +- `matter' +- `eittlandic'" + (interactive) + (if (org-export-derived-backend-p org-export-current-backend 'latex) + (format "\\textarm{%s}" (conlanging--translate text + (pcase language + ('eittlandic 'eittlandic-latex) + ('matter 'matter-latex) + (otherwise (error "Option \"%s\" not supported" otherwise))))) + (conlanging--translate text + (pcase language + ('eittlandic 'eittlandic-runes) + ('matter 'matter-runes) + (otherwise (error "Option \"%s\" not supported" otherwise)))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ; Text to phonetics ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defclass conlanging--proto-nyqy-phoneme nil + ((grapheme :initarg :grapheme + :type string + :documentation "The way the phoneme is written.") + (is-consonant :initarg :is-consonant + :initform nil + :type boolean) + (is-dorsal :initarg :is-dorsal + :initform nil + :type boolean) + (phoneme :initarg :phoneme + :type string + :documentation "Default pronunciation.") + (alt-phoneme :initarg :alt-phoneme + :initform "" + :type string + :documentation "Alternative pronunciation. For consonants only.")) + "Representation of a Proto-Ñyqy phoneme.") + +(defvar conlanging--proto-nyqy-phonetics + `(,(conlanging--proto-nyqy-phoneme :grapheme "q" :is-consonant t :is-dorsal t :phoneme "q" :alt-phoneme "ħ") + ,(conlanging--proto-nyqy-phoneme :grapheme "g" :is-consonant t :is-dorsal t :phoneme "ɢ" :alt-phoneme "ʢ") + ,(conlanging--proto-nyqy-phoneme :grapheme "ñ" :is-consonant t :is-dorsal t :phoneme "ɴ" :alt-phoneme "m") + ,(conlanging--proto-nyqy-phoneme :grapheme "c" :is-consonant t :is-dorsal t :phoneme "c" :alt-phoneme "ɬ") + ,(conlanging--proto-nyqy-phoneme :grapheme "j" :is-consonant t :is-dorsal t :phoneme "ɟ" :alt-phoneme "ɮ") + ,(conlanging--proto-nyqy-phoneme :grapheme "w" :is-consonant t :is-dorsal t :phoneme "w" :alt-phoneme "l") + ,(conlanging--proto-nyqy-phoneme :grapheme "p" :is-consonant t :phoneme "χ" :alt-phoneme "p") + ,(conlanging--proto-nyqy-phoneme :grapheme "b" :is-consonant t :phoneme "ʁ" :alt-phoneme "b") + ,(conlanging--proto-nyqy-phoneme :grapheme "m" :is-consonant t :phoneme "ʀ" :alt-phoneme "m") + ,(conlanging--proto-nyqy-phoneme :grapheme "n" :is-consonant t :phoneme "j" :alt-phoneme "n") + ,(conlanging--proto-nyqy-phoneme :grapheme "s" :is-consonant t :phoneme "x" :alt-phoneme "s") + ,(conlanging--proto-nyqy-phoneme :grapheme "z" :is-consonant t :phoneme "ɣ" :alt-phoneme "z") + ,(conlanging--proto-nyqy-phoneme :grapheme "y" :phoneme "y") + ,(conlanging--proto-nyqy-phoneme :grapheme "ú" :phoneme "u") + ,(conlanging--proto-nyqy-phoneme :grapheme "i" :phoneme "ɪ") + ,(conlanging--proto-nyqy-phoneme :grapheme "u" :phoneme "ʊ") + ,(conlanging--proto-nyqy-phoneme :grapheme "ø" :phoneme "ø") + ,(conlanging--proto-nyqy-phoneme :grapheme "œ" :phoneme "ɤ") + ,(conlanging--proto-nyqy-phoneme :grapheme "e" :phoneme "ɛ") + ,(conlanging--proto-nyqy-phoneme :grapheme "o" :phoneme "ɔ") + ,(conlanging--proto-nyqy-phoneme :grapheme " " :phoneme " ") + ,(conlanging--proto-nyqy-phoneme :grapheme "," :phoneme " ") + ,(conlanging--proto-nyqy-phoneme :grapheme ";" :phoneme " ") + ,(conlanging--proto-nyqy-phoneme :grapheme "." :phoneme " ")) + "List of Ñyqy characters and their phonetics equivalent. +See `conlanging--proto-nyqy-phoneme'.") + +(defun conlanging-proto-nyqy-to-phonetics (text) + "Return the phonetic equivalent of Proto-Ñyqy TEXT." + (let ((text (split-string (downcase text) "" t)) + (phonetics "") + (dorsal 'undefined)) + (dolist (grapheme text) + (let* ((cur-phoneme (seq-find (lambda (elem) + (equal (oref elem :grapheme) + grapheme)) + conlanging--proto-nyqy-phonetics))) + (if (oref cur-phoneme :is-consonant) + (progn + (when (eq dorsal 'undefined) + (setq dorsal (oref cur-phoneme :is-dorsal))) + (setq phonetics (concat phonetics + (if dorsal + (oref cur-phoneme :phoneme) + (oref cur-phoneme :alt-phoneme)))) + (setq dorsal (not dorsal))) + (setq phonetics (concat phonetics (oref cur-phoneme :phoneme)))))) + phonetics)) + +(defun conlanging-nyqy-to-org (text) + "Return phonetic equivalent of TEXT for `org-mode' LaTeX and HTML exports. +Text is formatted as either LaTeX code or HTML code for their respective exports." + (let ((phonetics (conlanging-proto-nyqy-to-phonetics text))) + (format (concat "@@html:%s/%s/@@" + "@@latex:\\textit{%s} (/%s/)@@") + text + phonetics + text + phonetics))) + + + + +(provide 'conlanging) + +;;; conlanging.el ends here