krz/orgstar

A native macOS editor for org-mode files. editor org-mode swift

Commit dac348a0b8

dac348a0b86a70a22c1b29dbec4bc191f52afb09

parent: bd3ef3d82a

Verified · cmc

cmc <hello@cleberg.net> · 2026-10-08 03:35 UTC

Tangle extensions from Org's ob-LANG files

:tangle yes names the file with the extension each Org 9.8.7 ob-LANG file
adds to org-babel-tangle-lang-exts (py, rb, pl, cpp, hs, tex and so on)
instead of only el and bib.

Layout: unified · split

Sources/OrgCore/Compute/Tangle.swift +7 −2
@@ -31,8 +31,13 @@ public enum Tangle {
3131 public var blocks: Int
3232 }
3333
34 /// `org-babel-tangle-lang-exts`.
35 static let extensions = ["emacs-lisp": "el", "elisp": "el", "bibtex": "bib"]
34 /// `org-babel-tangle-lang-exts`, with what Org 9.8.7's ob-LANG files add to it.
35 static let extensions = [
36 "emacs-lisp": "el", "elisp": "el", "bibtex": "bib",
37 "C++": "cpp", "D": "d", "awk": "awk", "clojure": "clj", "clojurescript": "cljs", "csharp": "cs", "fortran": "F90",
38 "groovy": "groovy", "haskell": "hs", "java": "java", "julia": "jl", "latex": "tex", "LilyPond": "ly", "lisp": "lisp",
39 "lua": "lua", "maxima": "max", "ocaml": "ml", "perl": "pl", "processing": "pde", "python": "py", "ruby": "rb", "sed": "sed",
40 ]
3641 /// `org-babel-shell-names`, and `shell` itself.
3742 static let shells: Set<String> = ["sh", "bash", "zsh", "fish", "csh", "ash", "dash", "ksh", "mksh", "posh", "shell"]
3843
Tests/OrgCoreTests/TangleTests.swift +24
@@ -291,6 +291,30 @@ struct TangleTests {
291291 #expect(Self.describe(ours, root: "/oracle") == theirs.text, "ours:\n\(Self.describe(ours, root: "/oracle"))\nemacs:\n\(theirs.text)\n\(theirs.error)")
292292 }
293293
294 /// The file names only: Emacs also wraps C, D, Java, Fortran and Clojure bodies with org-babel-expand-body:LANG.
295 @Test func extensionsLikeOrg() throws {
296 let languages = ["python", "ruby", "perl", "C", "C++", "D", "awk", "sed", "lua", "haskell", "java", "latex", "LilyPond",
297 "fortran", "clojure", "ocaml", "julia", "sh", "text"]
298 let text = languages.map { "#+begin_src \($0) :tangle yes\n\($0)\n#+end_src\n" }.joined()
299 let features = ["ob-python", "ob-ruby", "ob-perl", "ob-C", "ob-awk", "ob-sed", "ob-lua", "ob-haskell", "ob-java", "ob-latex",
300 "ob-lilypond", "ob-fortran", "ob-clojure", "ob-ocaml", "ob-julia", "ob-shell"]
301 let form = """
302 (let* ((dir (file-truename (make-temp-file "orgstar-tangle" t)))
303 (src (expand-file-name "notes.org" dir))
304 (text (buffer-string)) out)
305 \(features.map { "(require '\($0))" }.joined(separator: " ")) (setq org-babel-clojure-backend 'babashka)
306 (with-temp-file src (insert text))
307 (with-current-buffer (find-file-noselect src)
308 (let ((files (org-babel-tangle)))
309 (setq out (mapconcat (lambda (f) (concat (file-relative-name f dir) "\\n")) (sort (copy-sequence files) #'string<) ""))))
310 (erase-buffer) (insert out))
311 """
312 let theirs = try EmacsOracle.run([EmacsOracle.Case(text: text, point: 1, form: form)])[0]
313 let ours = try Tangle.run(text: text, path: "/oracle/notes.org").get()
314 let names = ours.files.map { ($0.path as NSString).lastPathComponent + "\n" }.sorted().joined()
315 #expect(names == theirs.text, "ours:\n\(names)\nemacs:\n\(theirs.text)\n\(theirs.error)")
316 }
317
294318 @Test func refusesWhatItCantDo() {
295319 for (language, header) in [("haskell", ":comments link"), ("sh", ":tangle (concat user-emacs-directory \"a.sh\")"), ("sh", ":tangle-mode go+q")] {
296320 let text = "#+begin_src \(language) :tangle yes \(header)\necho\n#+end_src\n"