#+TITLE: Tangler Example
#+AUTHOR: Enrico Palmese, 400037608
This is an org mode tangle parser for generating source code files without emacs. Written in Haskell.
*WARNING:* This program can overwrite this file or it’s own source code, if they are given as file targets.
* Preamble:
The source code featured in this .org document, when compiled with ~ghc -o tangler tangler.hs~, will produce a program that can generate it’s own source code from this .org document with ~./tangler tangler.org~.
* Libraries:
The libraries being used:
#+NAME: Libraries
#+BEGIN_SRC haskell :tangle tangler.hs
import System.Environment
import System.Directory
import Data.List
#+END_SRC
* Functions:
** Main
Get a filename as 1 command line argument:
#+NAME: Main
#+BEGIN_SRC haskell :tangle tangler.hs
main :: IO()
main = do
arg <- getArgs --command line to list
case arg of
[target] -> reader target –list of arguments must have length of 1
_ -> putStrLn (“Error: Enter 1 filename argument (./tangler sample.org)”)
#+END_SRC
** File Reader
Read a given file to separate lines, generate empty files to append to, and append appropriate code blocks (multiple passes):
#+NAME: Reader
#+BEGIN_SRC haskell :tangle tangler.hs
reader :: FilePath -> IO()
reader thefile = do
content <- readFile thefile --store the file content
let c = (lines content) --sends input file lines to a list of strings
filer (c) --makes empty source files to be appended to
parse (c) [] --appends code blocks to generated source files
#+END_SRC
** Produce File
Produce the target source code files to be written to:
#+NAME: Filer
#+BEGIN_SRC haskell :tangle tangler.hs
filer :: [String] -> IO()
filer [] = putStrLn (“Files created…”)
filer (x:xs) = if isPrefixOf “#+BEGIN_SRC” x
then do
if (isInfixOf “:tangle ” x) && (isSuffixOf “:tangle ” x) == False –needs space to have filename parameter
then do
paramer (words x)
filer xs
else do
filer xs
else do
filer xs –continue
#+END_SRC
** Get Paramater
Extract the filename parameter from the source code block and write it:
#+NAME: Paramer
#+BEGIN_SRC haskell :tangle tangler.hs
paramer :: [String] -> IO()
paramer (w:ws) | w == “:tangle” = if isInfixOf “:” (head ws) –guarenteed to find, return next word (parameter)
then do
putStrLn (“Paramater contains illegal character.”)
else do
writeFile (head ws) “” –empty file with name w
| otherwise = paramer ws
#+END_SRC
** Parse
Append source block content to generated files (takes Line & Filename):
#+NAME: Parse
#+BEGIN_SRC haskell :tangle tangler.hs
parse :: [String] -> [Char] -> IO()
parse [] _ = putStrLn (“Files written!”)
parse (x:xs) [] = if isPrefixOf “#+BEGIN_SRC” x && (isSuffixOf “:tangle ” x) == False
then do
if isInfixOf “:tangle ” x
then do
parse xs (appender (words x)) –tangle found
else do
parse xs [] –no tangle
else do
parse xs [] –continue
parse (x:xs) m = if isPrefixOf “#+END_SRC” x
then do
parse xs [] –stop appending
else do
appendFile m (x ++ “\n”) –append line
parse xs m –continue
#+END_SRC
** Target
Gets the filename to be appended to:
#+NAME: Append
#+BEGIN_SRC haskell :tangle tangler.hs
appender :: [String] -> [Char]
appender (w:ws) | w == “:tangle” = case isInfixOf “:” (head ws) of
True -> []
False -> (head ws)
| otherwise = appender ws
#+END_SRC