diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..3849d2e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +/node_modules +/*.log diff --git a/.github/workflows/build-latex.yml b/.github/workflows/build-latex.yml new file mode 100644 index 0000000..83a4cf4 --- /dev/null +++ b/.github/workflows/build-latex.yml @@ -0,0 +1,99 @@ +name: CI/CD +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Compile LaTeX document + uses: xu-cheng/latex-action@v2 + with: + root_file: | + a4.tex + a5.tex + a6.tex + working_directory: latex + latexmk_use_lualatex: true + + - uses: actions/upload-artifact@v2 + with: + name: pdfs + path: latex/*.pdf + update-readme: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - uses: actions/setup-node@v2 + with: + node-version: '12' + + - name: Build READM.md + run: node readme/index.js > README.md + + - uses: EndBug/add-and-commit@v7 + with: + add: README.md + author_name: Git Actions + author_email: gitactions@example.com + message: Updated README.md + release: + needs: [build] + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + steps: + - uses: actions/download-artifact@v2 + with: + name: pdfs + + - name: Display structure of downloaded files + run: ls -R + + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: v1.${{ github.run_id }} + release_name: Release v1.${{ github.run_id }} + draft: false + prerelease: false + + - name: Upload A4 Asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./a4.pdf + asset_name: a4.pdf + asset_content_type: application/pdf + + - name: Upload A5 Asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./a5.pdf + asset_name: a5.pdf + asset_content_type: application/pdf + + - name: Upload A6 Asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./a6.pdf + asset_name: a6.pdf + asset_content_type: application/pdf diff --git a/components/Background/index.tsx b/components/Background/index.tsx index daa8442..01aa74d 100644 --- a/components/Background/index.tsx +++ b/components/Background/index.tsx @@ -1,96 +1,131 @@ // https://redstapler.co/cool-nebula-background-effect-three-js/ import * as THREE from 'three'; -import React, { useEffect } from 'react'; +import { Canvas, useFrame, useThree } from '@react-three/fiber'; +import React, { useEffect, useMemo, useState } from 'react'; -const setup = () => { - let scene, camera, renderer; - let cloudParticles = []; - - function init() { - scene = new THREE.Scene(); - camera = new THREE.PerspectiveCamera(60,window.innerWidth / window.innerHeight,1,1000); - camera.position.z = 1; - camera.rotation.x = 1.16; - camera.rotation.y = -0.12; - camera.rotation.z = 0.27; - let ambient = new THREE.AmbientLight(0x555555); - scene.add(ambient); - renderer = new THREE.WebGLRenderer(); - renderer.setSize(window.innerWidth,window.innerHeight); - scene.fog = new THREE.FogExp2(0x03544e, 0.001); - renderer.setClearColor(scene.fog.color); - renderer.domElement.style.position = 'fixed'; - renderer.domElement.style.top = '0'; - renderer.domElement.style.left = '0'; - renderer.domElement.style.width = '100%'; - renderer.domElement.style.height = '100%'; - renderer.domElement.style.zIndex = -1; - renderer.domElement.style.opacity = 1; - - document.body.appendChild(renderer.domElement); - addParticles(); - addLights(); - render(); - } - - const addParticles = () => { - let loader = new THREE.TextureLoader(); - loader.load("/images/smoke.png", (texture) => { - const cloudGeo = new THREE.PlaneBufferGeometry(500,500); - const cloudMaterial = new THREE.MeshLambertMaterial({ - map:texture, - transparent: true - }); - for(let p=0; p<50; p++) { - let cloud = new THREE.Mesh(cloudGeo, cloudMaterial); - cloud.position.set( - Math.random()*800 -400, - 500, - Math.random()*500-500 - ); - cloud.rotation.x = 1.16; - cloud.rotation.y = -0.12; - cloud.rotation.z = Math.random()*2*Math.PI; - cloud.material.opacity = 0.55; - cloudParticles.push(cloud); - scene.add(cloud); - } - }); - } - - const addLights = () => { - let directionalLight = new THREE.DirectionalLight(0xff8c19); - directionalLight.position.set(0,0,1); - scene.add(directionalLight); - - let orangeLight = new THREE.PointLight(0xcc6600,50,450,1.7); - orangeLight.position.set(200,300,100); - scene.add(orangeLight); - let redLight = new THREE.PointLight(0xd8547e,50,450,1.7); - redLight.position.set(100,300,100); - scene.add(redLight); - let blueLight = new THREE.PointLight(0x3677ac,50,450,1.7); - blueLight.position.set(300,300,200); - scene.add(blueLight); +interface CloudProps { + texture: THREE.Texture; + position: [number, number, number]; + rotation: { + x: number; + y: number; + z: number; }; +} - function render() { - cloudParticles.forEach(p => { - p.rotation.z -=0.001; - }); - renderer.render(scene,camera); - requestAnimationFrame(render); - } +const initialClouds = new Array(30).fill(undefined).map((_, i) => ({ + name: `id_${i}`, + position: [ + Math.random() * 800 - 400, + 500, + Math.random() * 500 - 500, + ] as [number, number, number], + rotation: { + x: 1.16, + y: -0.12, + z: Math.random() * 2 * Math.PI, + }, +})); - init(); +const Cloud: React.FC = ({ texture, position, rotation }) => { + return ( + + + + + ); }; -const Background: React.FC<{}> = () => { +const Clouds: React.FC<{}> = () => { + const { camera } = useThree(); + const loader = useMemo(() => new THREE.TextureLoader(), []); + const [texture, setTexture] = useState(); + const [clouds, setClouds] = useState(initialClouds); + useEffect(() => { - setup(); + console.log(camera); + camera.rotateX(1.16); + camera.rotateY(-0.12); + camera.rotateZ(0.27); }, []); - return <> + + useEffect(() => { + loader.load('images/smoke.png', (loadedTexture) => { + setTexture(loadedTexture); + }); + }, []); + + useFrame(() => { + setClouds(current => current.map(c => ({ + ...c, + rotation: { + ...c.rotation, + z: c.rotation.z -= 0.001, + } + }))); + }); + + if (!texture) { + return <>; + } + + return ( + <> + {clouds.map((cloud) => ( + + ))} + + ) +} + +const style = { + width: '100%', + height: '100%', + top: 0, + left: 0, + position: 'fixed' as any, + zIndex: -1, +} + +const Background: React.FC<{}> = () => { + const fog = useMemo(() => new THREE.FogExp2(0x03544e, 0.001), []); + const [aspect, setAspect] = useState(global.window ? window.innerWidth / window.innerHeight : 1); + if (!global.window) { + return <> + } + useEffect(() => { + const update = () => { + setAspect(window.innerWidth / window.innerHeight); + }; + window.addEventListener('resize', update); + return () => { + window.removeEventListener('resize', update); + } + }, []); + return ( + + + + + + + + + + + + + ); }; export default Background; diff --git a/components/Me.tsx b/components/Me.tsx index a194cec..4b44b41 100644 --- a/components/Me.tsx +++ b/components/Me.tsx @@ -1,28 +1,24 @@ import React from 'react'; import styled from 'styled-components'; +import Image from 'next/image' +import image from '../public/images/me.jpg'; const Wrapper = styled.div` display: flex; flex-direction: column; align-items: center; justify-content: center; - padding: 40px; + padding: 80px; `; const ImageWrapper = styled.div` border-radius: 50%; - border: solid 15px rgba(255, 255, 255, .5); - box-shadow: 0 0 15px rgba(0, 0, 0, .5); + border: solid 30px rgba(255, 255, 255, .5); + box-shadow: 0 0 35px rgba(255, 255, 255, .5); overflow: hidden; - margin: 0 40px; width: 100%; max-width: 360px; -`; - -const Image = styled.div<{ src: string }>` - width: 100%; - background: url('${({ src }) => src}'); - background-size: cover; + position: relative; `; const Spacer = styled.div` @@ -31,6 +27,7 @@ const Spacer = styled.div` const Title = styled.h1` text-transform: uppercase; + text-align: center; color: #fff; font-size: 28px; font-family: 'Source Code Pro', monospace; @@ -42,6 +39,7 @@ const Title = styled.h1` const SubTitle = styled.h2` text-transform: uppercase; + text-align: center; color: #fff; font-size: 14px; font-family: 'Source Code Pro', monospace; @@ -62,12 +60,11 @@ const Divider = styled.div` const Me: React.FC<{}> = () => ( - - - + + Morten Olsen - “...One part genius, on part crazy” + “...One part genius, one part crazy” ); diff --git a/components/Social.tsx b/components/Social.tsx index 78785d1..7755171 100644 --- a/components/Social.tsx +++ b/components/Social.tsx @@ -5,7 +5,7 @@ interface Props { sites: { title: string, link: string, - logo: string, + logo: any, }[]; } @@ -75,7 +75,7 @@ const Social: React.FC = ({ sites }) => ( {sites.map(({ title, link, logo }) => ( - + {title} diff --git a/data.json b/data.json new file mode 100644 index 0000000..87157f8 --- /dev/null +++ b/data.json @@ -0,0 +1,192 @@ +[{ + "type": "info", + "data": { + "name": "Morten Olsen", + "image": "assets/me.jpg", + "info": [{ + "name": "E-mail", + "value": "hello@buy-me.coffee" + },{ + "name": "Location", + "value": "Copenhagen, DK" + },{ + "name": "Github", + "value": "https://github.com/morten-olsen" + }] +} +}, { + "type": "text", + "data": { + "title": "Who am I?", + "content": "Hell bend on a conquest to take over the digital world (and the physical, should the chance arise). Am I over ambitious? Perhaps, but with a proven track record in most aspects of things which can process 1s and 0s and a mind which runs at a speed which can battle a well-trained racehorse, I believe I am equipt to undertake this voyage!" + } +}, { + "type": "skills", + "data": { + "title": "Platforms and Languages", + "description": "Platforms and languages which I have worked with. The list is a shortened down version.", + "skills": [{ + "title": "C\\#", + "level": 5 + },{ + "title": "JavaScript", + "level": 5 + },{ + "title": "NodeJS", + "level": 5 + },{ + "title": "React Native", + "level": 5 + },{ + "title": "HTML", + "level": 5 + },{ + "title": "CSS", + "level": 5 + },{ + "title": "TypeScript", + "level": 5 + },{ + "title": "Docker", + "level": 4 + },{ + "title": "Linux", + "level": 4 + }] + } +}, { + "type": "experiences", + "data": { + "title": "Experiences", + "positions": [{ + "company": { + "name": "Sampension", + "webpage": "https://www.sampension.dk" + }, + "title": "Senior Frontend Developer", + "startDate": "2018", + "endDate": "Present", + "description": "Sampension is a danish pension fund and my work has been to design and help to build a frontend architecture that would run natively on iOS and Android as well as on the web on both desktop and mobile devices.\n\nIt was important to ensure that the project felt at home on all platforms and that it was maintainable by a small team of developers.\n\nTo achieve this we used React Native and React Native for Web to create a unified codebase for all platforms, as well as create a component library which would deal with ensuring the best UX on all platforms." + }, { + "company": { + "name": "Trendsales", + "webpage": "https://www.trendsales.dk" + }, + "title": "Frontend Technical Lead", + "startDate": "2016", + "endDate": "2018", + "description": "In 2015 Trendsales decided to build an entirely new platform. It became my responsibility to create a modernized frontend architecture. The work began in 2016 with just me on the project and consisted of a proof of concept version containing everything from framework selection, structure, style guides build chain, continuous deployment, and an actual initial working version. The result where the platform which I was given technical ownership over and which I, along with two others, worked on expanding over the next year. The platform is currently powering _m.trendsales.dk_. The project is build using React and state management are done using Redux. In addition to the of the shelve frameworks, we also needed to develop quite a few bespoke frameworks, in order to meet demands. Among others, these were created to solve the following issues:\n\n* Introducing a new navigational paradigm\n* Create a more flexible routing mechanism\n* Be able to serve skeleton page, for page transitions while still being able to create complete server-side pages\n* Ensure project flows between multiple systems such as Github, Jira, Octopus Deploy, AppVeyor and Docker" + },{ + "company": { + "name": "Trendsales", + "webpage": "https://www.trendsales.dk" + }, + "title": "iOS and Android Developer", + "startDate": "2012", + "endDate": "2015", + "description": "I became responsible for the iOS platform, which was a task that required a new app to be built from the ground up using _Xamarin_[^1]. In addition to that, a new API to support the app along with support for our larger vendors was needed which had to be build using something closely similar to _Microsoft MVC_ so that other people could join the project at a later stage.\n\n he project started in October with the initial version available to our users in late December.\n\nThis project represented my first adventure into mobile development and became an app with more than 15 million screen views and 1.5 million sessions per month.\n\n After that, I joined two other colleagues, who were working on an Android version of the app, to form a join mobile development team.\n\n Throughout the period I also worked on the backend for the web page from time to time.\n\n [^1]: Called MonoTouch at the time" + },{ + "company": { + "name": "Trendsales", + "webpage": "https://www.trendsales.dk" + }, + "title": "Web Developer", + "startDate": "2012", + "endDate": "2012", + "description": "I got a part-time job at Trendsales, where my primary responsibility was maintaining the API which powered the iOS app. Quickly my tasks became more diverse, and I ended using about 25-50% of my time on the API, while the remaining was spend doing work on the platform in general." + },{ + "company": { + "name": "BilZonen", + "webpage": "http://www.bilzonen.dk" + }, + "title": "Web Developer", + "startDate": "2010", + "endDate": "2012", + "description": "I work as a part-time web developer on bilzonen.dk. I have worked with both day-to-day maintenance and large scale projects (new search module, integration of new data catalog, mobile site, new-car-catalog and the entire dealer solution). The page is an Umbraco solution, with all .NET (C#) code. I have introduced a new custom build provider-model system, which allows data-providers to move data between data stores, external services, and the site. (search, caching and external car date is running through the provider system). Also, i have set up the development environment, from setting up virtual server hosts to building custom tool for building and unit testing." + },{ + "company": { + "name": "Haastrup IT" + }, + "title": "Web Developer", + "startDate": "2009", + "endDate": "2010", + "description": " I have worked as a part time project koordinator and systems developer, sitting with responsibility for a wide variety of projects including projects for \"Københavns Kommune\" (Navision reporting software) and \"Syddanmarks kommune\" (Electronic application processing system). Most projects were made in C#, but also PHP, VB, ActionScript. In addtion to that i maintained the in-house hosting setup. " + },{ + "company": { + "name": "Sydbank" + }, + "title": "IT Hotline", + "startDate": "2007", + "endDate": "2009", + "description": " I work as a part-time supporter of customers (private and business) and staff, on Sydbanks different electronic banking systems. Mostly telephonic bug finding and PC setup." + }] + } +}, { + "type": "skills", + "data": { + "title": "Frameworks", + "description": "This list of frameworks is a curated list of frameworks I have been using recently and therefore are all amongst frameworks which I prefer to work with.", + "skills": [{ + "title": "React", + "level": "5" + },{ + "title": "Redux", + "level": "5" + },{ + "title": "Webpack", + "level": "5" + },{ + "title": "RxJS", + "level": "3" + },{ + "title": "RxDB", + "level": "5" + },{ + "title": "Styled-Components", + "level": "5" + },{ + "title": "GraphQL", + "level": "3" + },{ + "title": "Babel", + "level": "5" + }] + } +}, { + "type": "projects", + "data": { + "title": "Projects of interest", + "description": "A list of projects I have worked with or am working on, for which the source is publicly available. Keep in mind that some of these projects are in early stages, and some are merely created for the training, and may not represent the actual way I think production code should be structured", + "projects": [{ + "name": "Clash of Robots", + "tagline": "AI vs AI game enginge and IDE", + "url": "github.com/clash-of-robots/core", + "description": "A game engine for creating AI vs. AI turn-based games, including an IDE (still work in progress). The project is built to be the base for a space drone vs. space drone AI game. Players are given control over a set of drones and have to traverse the solar system, fighting to prosper as selles bots, pirate bots, communication relays or whatever the player decides to do within the confines of the sandbox." + }, { + "name": "Curriculum Vitae", + "tagline": "Automated CV building", + "url": "github.com/morten-olsen/curriculum-vitae", + "description": " Another small fun project is this resume, as it is created in \\LaTeX, versioned using _Git_ on _Github_ and set to automatically build and create multiple release versions using _Travis CI_ and _Docker " + }, { + "name": "LifeFlow Mind", + "tagline": "Evernote meets \\LaTeX meets Jupyter", + "url": "github.com/lifeflow-mind", + "description": "I love Evernote simple digital note storages, but as a developer and general nerd, its features often come up short. Which is why I am working on a project named Mind, which attempts to bridge the best aspect of Evernote, with a dynamic view system, so new views (for instance a calendar or a contact view) can be introduced. Also, it can render mathematical formulas using \\LaTeX and execute code snippets, to test and present code directly inside documents. A somewhat working demo can be found at https://morten-olsen.github.io/mind" + }, { + "name": "Redux App State", + "tagline": "Advanced app like navigation on the web", + "url": "github.com/trendsales/redux-app-state", + "description": " One of the most significant issues I had to overcome when I began building the revamped Trendsales front end was that the design called for an advanced navigation strategy, which did not fit into the webs linear document structure, but rather a branched multi-layer navigation. Therefore I created this project to create a high-level abstraction using a navigation trap to allow for much more advanced navigation patterns" + }, { + "name": "Clubhouse Protocol", + "tagline": "An OpenPGP based crypto group communication with decentralised rule management for both humans and machines", + "url": "github.com/clubhouse-protocol", + "description": " A cryptographic communication platform where all messages are end-to-end encrypted. It uses a decentralized rule set, so every message is verified and applied by the clients individually " + }, { + "name": "wolfsquad.co", + "tagline": "A fun experiment with encryption", + "url": "github.com/morten-olsen/wolfsquad", + "description": " This is an old project I did to play around with encryption in JavaScript. The initial boot loader is served as regular JavaScript, but after login, all communication has a level of encryption applied based upon the password, which is never sent to the server, as its encryption abilities offer this feature, without having to transfer sensitive information. It is currently available at https://wolfsquad.co/ with the username _admin_ and the password _password_" + }] + } +}] diff --git a/latex/a4.tex b/latex/a4.tex new file mode 100644 index 0000000..0f535a3 --- /dev/null +++ b/latex/a4.tex @@ -0,0 +1,5 @@ +\documentclass[10pt, a4paper]{article} +\usepackage[top=2cm, bottom=2cm, left=2cm, right=2cm]{geometry} +\def \columncount {3} +\def \skillcolumncount {2} +\include{header} diff --git a/latex/a5.tex b/latex/a5.tex new file mode 100644 index 0000000..e63a4a5 --- /dev/null +++ b/latex/a5.tex @@ -0,0 +1,5 @@ +\documentclass[10pt, a5paper]{article} +\usepackage[top=1.5cm, bottom=1cm, left=1cm, right=1cm]{geometry} +\def \columncount {2} +\def \skillcolumncount {2} +\include{header} diff --git a/latex/a6.tex b/latex/a6.tex new file mode 100644 index 0000000..dfd9847 --- /dev/null +++ b/latex/a6.tex @@ -0,0 +1,5 @@ +\documentclass[10pt, a6paper]{article} +\usepackage[top=1.5cm, bottom=2cm, left=1cm, right=1cm]{geometry} +\def \columncount {1} +\def \skillcolumncount {1} +\include{header} diff --git a/latex/document.lua b/latex/document.lua new file mode 100644 index 0000000..2792b93 --- /dev/null +++ b/latex/document.lua @@ -0,0 +1,73 @@ +require("lualibs.lua") +local file = io.open('../data.json') +local jsonstring = file:read('*a') +file:close() +jsondata = utilities.json.tolua(jsonstring) + +local function switch(a, case) + local value = a + local switchcase = {} + + switchcase["info"] = function() + tex.print("\\begin{cvtitle}{" .. value["name"] .. "}{../" .. value["image"] .. "}") + for key, value in pairs(value["info"]) do + tex.print("\\cvinfo{" .. value["name"] .. "}{" .. value["value"] .. "}") + end + + tex.print("\\end{cvtitle}") + end + + switchcase["text"] = function() + tex.print("\\begin{columns}") + tex.print("\\section*{" .. value["title"] .. "}") + tex.print("\\begin{markdown}") + tex.print(value["content"]) + tex.print("\\end{markdown}") + tex.print("\\end{columns}") + end + + switchcase["skills"] = function() + tex.print("\\section*{" .. value["title"] .. "}") + tex.print(value["description"] .. "\\\\\\\\") + tex.print("\\begin{cvskills}") + for key, value in pairs(value["skills"]) do + tex.print('\\cvskill{' .. value["title"] .. '}{' .. value["level"] .. '}') + end + tex.print("\\end{cvskills}") + end + + switchcase["experiences"] = function() + tex.print("\\section*{" .. value["title"] .. "}") + for key, value in pairs(value["positions"]) do + tex.print("\\begin{cvexp}{" .. value["company"]["name"] .. "}{" .. value["startDate"] .. "}{" .. value["endDate"] .. "}{" .. value["title"] .. "}") + tex.print("\\begin{markdown}") + tex.print(value["description"]) + tex.print("\\end{markdown}") + tex.print("\\end{cvexp}") + end + end + + switchcase["projects"] = function() + tex.print("\\section*{" .. value["title"] .. "}") + tex.print(value["description"] .. "\\\\\\hrule") + for key, value in pairs(value["projects"]) do + tex.print("\\begin{cvproj}{" .. value["name"] .. "}{" .. value["url"] .. "}{" .. value["tagline"] .. "}") + tex.print("\\begin{markdown}") + tex.print(value["description"]) + tex.print("\\end{markdown}") + tex.print("\\end{cvproj}") + end + end + + if switchcase[case] == nil then + tex.print("type " .. case .. "dont exist \\\\\\\\") + else + switchcase[case]() + end +end + +function render() + for key, value in pairs(jsondata) do + switch(value["data"], value["type"]) + end +end diff --git a/latex/header.lua b/latex/header.lua new file mode 100644 index 0000000..2b1ddcc --- /dev/null +++ b/latex/header.lua @@ -0,0 +1,16 @@ +require("lualibs.lua") +local file = io.open('../package.json') +local jsonstring = file:read('*a') +file:close() +jsondata = utilities.json.tolua(jsonstring) + +function addHeader() + if jsondata["watermark"] ~= nil and jsondata["watermark"] ~= false then + tex.print("\\usepackage{draftwatermark}") + tex.print("\\SetWatermarkLightness{0.9}") + tex.print("\\SetWatermarkScale{6}") + if jsondata["watermark"] ~= true then + tex.print("\\SetWatermarkText{" .. jsondata["watermark"] .. "}") + end + end +end diff --git a/latex/header.tex b/latex/header.tex new file mode 100644 index 0000000..f963e0e --- /dev/null +++ b/latex/header.tex @@ -0,0 +1,162 @@ +%\usepackage{showframe} +\usepackage{tex4ebook} +\usepackage{pagecolor} +\usepackage{paracol} +\usepackage{kantlipsum} +\usepackage{multicol} +\usepackage{xifthen} +\usepackage{tcolorbox} +\usepackage{wrapfig} +\usepackage{graphicx} +\usepackage{fancyhdr} +\usepackage{luacode} +%\pagecolor{yellow!5!orange!2!white} +\setlength{\columnseprule}{0.1pt} +\newcommand{\ifequals}[3]{\ifthenelse{\equal{#1}{#2}}{#3}{}} +\newcommand{\case}[2]{#1 #2} +\newenvironment{switch}[1]{\renewcommand{\case}{\ifequals{#1}}}{} +\usepackage{markdown} +\markdownSetup{ + footnotes = true, + renderers = { + link = {#1}, % Render a link as the link label. + emphasis = {\emph{#1}}, % Render emphasis using `\emph`. + } +} + +\newenvironment{columns}{ + \ifnum\columncount>1 + \begin{multicols}{\columncount} + \fi +}{ + \ifnum\columncount>1 + \end{multicols} + \fi + \vspace{0.5cm} + \hrule +} + +\newenvironment{cvskills}{ + \noindent\begin{minipage}{\textwidth} + \ifnum\skillcolumncount>1 + \begin{multicols}{\skillcolumncount} + \fi +}{ + \ifnum\skillcolumncount>1 + \end{multicols} + \fi + \vspace{0.5cm} + \hrule + \end{minipage} +} + +\newenvironment{cvtitle}[2]{ + \noindent\begin{minipage}{\textwidth} + %{\Huge Curriculum Vitae\newline\large #1} \hfill{\large \mbox{#1} \includegraphics[height=3cm]{#2}}\\\\ + + \noindent\begin{minipage}{\textwidth - 3.2cm} + \Huge Curriculum Vitae\newline\large #1 + \end{minipage} + \noindent\begin{minipage}{3cm} + \begin{flushright} + \includegraphics[height=3cm]{#2} + \end{flushright} + \end{minipage} + \vspace{0.5cm} + \hrule + \vspace{0.5cm} + \ifnum\skillcolumncount>1 + \begin{multicols}{\skillcolumncount} + \fi +}{ + \ifnum\skillcolumncount>1 + \end{multicols} + \fi + \end{minipage} + \hfill + \begin{minipage}{\textwidth/3-2cm} + \end{minipage} + \vspace{1cm} + \hrule +} + +\newenvironment{cvbox}[3] +{ + \noindent + %\begin{minipage}{\textwidth} + + %\hrule + \begin{columns} + \noindent{\Large \textbf{#1}} \hfill {\small #2} \\ + \textit{#3} + \ifnum\columncount>2 + \vfill\null\columnbreak + \else + \\\\ + \fi +} +{ + \end{columns} + %\end{minipage} + \vspace{0.5cm} +} + +\newcommand{\cvinfo}[2]{ + \noindent \textbf{#1}\dotfill#2\\ +} + +\newcommand{\cvskill}[2]{ + \textbf{#1}\dotfill + \textit{\begin{switch}{#2} + \case{1}{Needs refresh} + \case{2}{Needs refresh} + \case{3}{Comfortable} + \case{4}{Prefered} + \case{5}{Prefered} + \end{switch}}\\ +} + +\newenvironment{cvexp}[4] +{ \begin{cvbox}{#1}{#2 - #3}{#4} } +{\end{cvbox}} + +%\newenvironment{cvproj}[3] +%{\begin{cvbox}{#1}{#2}{#3}} +%{\end{cvbox}} + +\newenvironment{cvproj}[3] +{ + \noindent + %\begin{minipage}{\textwidth} + + %\hrule + \begin{columns} + \noindent{\Large \textbf{#1}} \\ {\small #3} \\ + {\tiny\textit{https://#2}} + \ifnum\columncount>2 + \vfill\null\columnbreak + \else + \\\\ + \fi + } + { + \end{columns} + %\end{minipage} + \vspace{0.5cm} +} + +\pagestyle{fancy} +\fancyhf{} +\rhead{Morten Olsen \today} +\lhead{Curriculum Vitae} +\rfoot{Page \thepage} + +\directlua{dofile("header.lua")} +\newcommand*{\addHeader}{\directlua{addHeader()}} +\addHeader + +\begin{document} +\directlua{dofile("document.lua")} +\newcommand*{\render}{\directlua{render()}} +\render +\end{document} diff --git a/latex/markdown.lua b/latex/markdown.lua new file mode 100644 index 0000000..fd190e6 --- /dev/null +++ b/latex/markdown.lua @@ -0,0 +1,1942 @@ +-- +-- Copyright (C) 2009-2017 John MacFarlane, Hans Hagen +-- +-- Permission is hereby granted, free of charge, to any person obtaining +-- a copy of this software and associated documentation files (the +-- "Software"), to deal in the Software without restriction, including +-- without limitation the rights to use, copy, modify, merge, publish, +-- distribute, sublicense, and/or sell copies of the Software, and to +-- permit persons to whom the Software is furnished to do so, subject to +-- the following conditions: +-- +-- The above copyright notice and this permission notice shall be included +-- in all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +-- +-- Copyright (C) 2017 Vít Novotný +-- +-- This work may be distributed and/or modified under the +-- conditions of the LaTeX Project Public License, either version 1.3 +-- of this license or (at your option) any later version. +-- The latest version of this license is in +-- +-- http://www.latex-project.org/lppl.txt +-- +-- and version 1.3 or later is part of all distributions of LaTeX +-- version 2005/12/01 or later. +-- +-- This work has the LPPL maintenance status `maintained'. +-- The Current Maintainer of this work is Vít Novotný. +-- +-- Send bug reports, requests for additions and questions +-- either to the GitHub issue tracker at +-- +-- https://github.com/witiko/markdown/issues +-- +-- or to the e-mail address . +-- +-- MODIFICATION ADVICE: +-- +-- If you want to customize this file, it is best to make a copy of +-- the source file(s) from which it was produced. Use a different +-- name for your copy(ies) and modify the copy(ies); this will ensure +-- that your modifications do not get overwritten when you install a +-- new release of the standard system. You should also ensure that +-- your modified source file does not generate any modified file with +-- the same name as a standard file. +-- +-- You will also need to produce your own, suitably named, .ins file to +-- control the generation of files from your source file; this file +-- should contain your own preambles for the files it generates, not +-- those in the standard .ins files. +-- +local metadata = { + version = "2.5.4", + comment = "A module for the conversion from markdown to plain TeX", + author = "John MacFarlane, Hans Hagen, Vít Novotný", + copyright = "2009-2017 John MacFarlane, Hans Hagen; " .. + "2016-2017 Vít Novotný", + license = "LPPL 1.3" +} +if not modules then modules = { } end +modules['markdown'] = metadata +local lpeg = require("lpeg") +local unicode = require("unicode") +local md5 = require("md5") +local M = {} +local defaultOptions = {} +defaultOptions.cacheDir = "." +defaultOptions.outputDir = "." +defaultOptions.blankBeforeBlockquote = false +defaultOptions.blankBeforeCodeFence = false +defaultOptions.blankBeforeHeading = false +defaultOptions.breakableBlockquotes = false +defaultOptions.citationNbsps = true +defaultOptions.citations = false +defaultOptions.codeSpans = true +defaultOptions.contentBlocks = false +defaultOptions.contentBlocksLanguageMap = "markdown-languages.json" +defaultOptions.definitionLists = false +defaultOptions.fencedCode = false +defaultOptions.footnotes = false +defaultOptions.hashEnumerators = false +defaultOptions.html = false +defaultOptions.hybrid = false +defaultOptions.inlineFootnotes = false +defaultOptions.preserveTabs = false +defaultOptions.smartEllipses = false +defaultOptions.startNumber = true +defaultOptions.tightLists = true +defaultOptions.underscores = true +local upper, gsub, format, length = + string.upper, string.gsub, string.format, string.len +local concat = table.concat +local P, R, S, V, C, Cg, Cb, Cmt, Cc, Ct, B, Cs, any = + lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.C, lpeg.Cg, lpeg.Cb, + lpeg.Cmt, lpeg.Cc, lpeg.Ct, lpeg.B, lpeg.Cs, lpeg.P(1) +local util = {} +function util.err(msg, exit_code) + io.stderr:write("markdown.lua: " .. msg .. "\n") + os.exit(exit_code or 1) +end +function util.cache(dir, string, salt, transform, suffix) + local digest = md5.sumhexa(string .. (salt or "")) + local name = util.pathname(dir, digest .. suffix) + local file = io.open(name, "r") + if file == nil then -- If no cache entry exists, then create a new one. + local file = assert(io.open(name, "w")) + local result = string + if transform ~= nil then + result = transform(result) + end + assert(file:write(result)) + assert(file:close()) + end + return name +end +function util.table_copy(t) + local u = { } + for k, v in pairs(t) do u[k] = v end + return setmetatable(u, getmetatable(t)) +end +function util.expand_tabs_in_line(s, tabstop) + local tab = tabstop or 4 + local corr = 0 + return (s:gsub("()\t", function(p) + local sp = tab - (p - 1 + corr) % tab + corr = corr - 1 + sp + return string.rep(" ", sp) + end)) +end +function util.walk(t, f) + local typ = type(t) + if typ == "string" then + f(t) + elseif typ == "table" then + local i = 1 + local n + n = t[i] + while n do + util.walk(n, f) + i = i + 1 + n = t[i] + end + elseif typ == "function" then + local ok, val = pcall(t) + if ok then + util.walk(val,f) + end + else + f(tostring(t)) + end +end +function util.flatten(ary) + local new = {} + for _,v in ipairs(ary) do + if type(v) == "table" then + for _,w in ipairs(util.flatten(v)) do + new[#new + 1] = w + end + else + new[#new + 1] = v + end + end + return new +end +function util.rope_to_string(rope) + local buffer = {} + util.walk(rope, function(x) buffer[#buffer + 1] = x end) + return table.concat(buffer) +end +function util.rope_last(rope) + if #rope == 0 then + return nil + else + local l = rope[#rope] + if type(l) == "table" then + return util.rope_last(l) + else + return l + end + end +end +function util.intersperse(ary, x) + local new = {} + local l = #ary + for i,v in ipairs(ary) do + local n = #new + new[n + 1] = v + if i ~= l then + new[n + 2] = x + end + end + return new +end +function util.map(ary, f) + local new = {} + for i,v in ipairs(ary) do + new[i] = f(v) + end + return new +end +function util.escaper(char_escapes, string_escapes) + local char_escapes_list = "" + for i,_ in pairs(char_escapes) do + char_escapes_list = char_escapes_list .. i + end + local escapable = S(char_escapes_list) / char_escapes + if string_escapes then + for k,v in pairs(string_escapes) do + escapable = P(k) / v + escapable + end + end + local escape_string = Cs((escapable + any)^0) + return function(s) + return lpeg.match(escape_string, s) + end +end +function util.pathname(dir, file) + if #dir == 0 then + return file + else + return dir .. "/" .. file + end +end +local entities = {} + +local character_entities = { + ["quot"] = 0x0022, + ["amp"] = 0x0026, + ["apos"] = 0x0027, + ["lt"] = 0x003C, + ["gt"] = 0x003E, + ["nbsp"] = 160, + ["iexcl"] = 0x00A1, + ["cent"] = 0x00A2, + ["pound"] = 0x00A3, + ["curren"] = 0x00A4, + ["yen"] = 0x00A5, + ["brvbar"] = 0x00A6, + ["sect"] = 0x00A7, + ["uml"] = 0x00A8, + ["copy"] = 0x00A9, + ["ordf"] = 0x00AA, + ["laquo"] = 0x00AB, + ["not"] = 0x00AC, + ["shy"] = 173, + ["reg"] = 0x00AE, + ["macr"] = 0x00AF, + ["deg"] = 0x00B0, + ["plusmn"] = 0x00B1, + ["sup2"] = 0x00B2, + ["sup3"] = 0x00B3, + ["acute"] = 0x00B4, + ["micro"] = 0x00B5, + ["para"] = 0x00B6, + ["middot"] = 0x00B7, + ["cedil"] = 0x00B8, + ["sup1"] = 0x00B9, + ["ordm"] = 0x00BA, + ["raquo"] = 0x00BB, + ["frac14"] = 0x00BC, + ["frac12"] = 0x00BD, + ["frac34"] = 0x00BE, + ["iquest"] = 0x00BF, + ["Agrave"] = 0x00C0, + ["Aacute"] = 0x00C1, + ["Acirc"] = 0x00C2, + ["Atilde"] = 0x00C3, + ["Auml"] = 0x00C4, + ["Aring"] = 0x00C5, + ["AElig"] = 0x00C6, + ["Ccedil"] = 0x00C7, + ["Egrave"] = 0x00C8, + ["Eacute"] = 0x00C9, + ["Ecirc"] = 0x00CA, + ["Euml"] = 0x00CB, + ["Igrave"] = 0x00CC, + ["Iacute"] = 0x00CD, + ["Icirc"] = 0x00CE, + ["Iuml"] = 0x00CF, + ["ETH"] = 0x00D0, + ["Ntilde"] = 0x00D1, + ["Ograve"] = 0x00D2, + ["Oacute"] = 0x00D3, + ["Ocirc"] = 0x00D4, + ["Otilde"] = 0x00D5, + ["Ouml"] = 0x00D6, + ["times"] = 0x00D7, + ["Oslash"] = 0x00D8, + ["Ugrave"] = 0x00D9, + ["Uacute"] = 0x00DA, + ["Ucirc"] = 0x00DB, + ["Uuml"] = 0x00DC, + ["Yacute"] = 0x00DD, + ["THORN"] = 0x00DE, + ["szlig"] = 0x00DF, + ["agrave"] = 0x00E0, + ["aacute"] = 0x00E1, + ["acirc"] = 0x00E2, + ["atilde"] = 0x00E3, + ["auml"] = 0x00E4, + ["aring"] = 0x00E5, + ["aelig"] = 0x00E6, + ["ccedil"] = 0x00E7, + ["egrave"] = 0x00E8, + ["eacute"] = 0x00E9, + ["ecirc"] = 0x00EA, + ["euml"] = 0x00EB, + ["igrave"] = 0x00EC, + ["iacute"] = 0x00ED, + ["icirc"] = 0x00EE, + ["iuml"] = 0x00EF, + ["eth"] = 0x00F0, + ["ntilde"] = 0x00F1, + ["ograve"] = 0x00F2, + ["oacute"] = 0x00F3, + ["ocirc"] = 0x00F4, + ["otilde"] = 0x00F5, + ["ouml"] = 0x00F6, + ["divide"] = 0x00F7, + ["oslash"] = 0x00F8, + ["ugrave"] = 0x00F9, + ["uacute"] = 0x00FA, + ["ucirc"] = 0x00FB, + ["uuml"] = 0x00FC, + ["yacute"] = 0x00FD, + ["thorn"] = 0x00FE, + ["yuml"] = 0x00FF, + ["OElig"] = 0x0152, + ["oelig"] = 0x0153, + ["Scaron"] = 0x0160, + ["scaron"] = 0x0161, + ["Yuml"] = 0x0178, + ["fnof"] = 0x0192, + ["circ"] = 0x02C6, + ["tilde"] = 0x02DC, + ["Alpha"] = 0x0391, + ["Beta"] = 0x0392, + ["Gamma"] = 0x0393, + ["Delta"] = 0x0394, + ["Epsilon"] = 0x0395, + ["Zeta"] = 0x0396, + ["Eta"] = 0x0397, + ["Theta"] = 0x0398, + ["Iota"] = 0x0399, + ["Kappa"] = 0x039A, + ["Lambda"] = 0x039B, + ["Mu"] = 0x039C, + ["Nu"] = 0x039D, + ["Xi"] = 0x039E, + ["Omicron"] = 0x039F, + ["Pi"] = 0x03A0, + ["Rho"] = 0x03A1, + ["Sigma"] = 0x03A3, + ["Tau"] = 0x03A4, + ["Upsilon"] = 0x03A5, + ["Phi"] = 0x03A6, + ["Chi"] = 0x03A7, + ["Psi"] = 0x03A8, + ["Omega"] = 0x03A9, + ["alpha"] = 0x03B1, + ["beta"] = 0x03B2, + ["gamma"] = 0x03B3, + ["delta"] = 0x03B4, + ["epsilon"] = 0x03B5, + ["zeta"] = 0x03B6, + ["eta"] = 0x03B7, + ["theta"] = 0x03B8, + ["iota"] = 0x03B9, + ["kappa"] = 0x03BA, + ["lambda"] = 0x03BB, + ["mu"] = 0x03BC, + ["nu"] = 0x03BD, + ["xi"] = 0x03BE, + ["omicron"] = 0x03BF, + ["pi"] = 0x03C0, + ["rho"] = 0x03C1, + ["sigmaf"] = 0x03C2, + ["sigma"] = 0x03C3, + ["tau"] = 0x03C4, + ["upsilon"] = 0x03C5, + ["phi"] = 0x03C6, + ["chi"] = 0x03C7, + ["psi"] = 0x03C8, + ["omega"] = 0x03C9, + ["thetasym"] = 0x03D1, + ["upsih"] = 0x03D2, + ["piv"] = 0x03D6, + ["ensp"] = 0x2002, + ["emsp"] = 0x2003, + ["thinsp"] = 0x2009, + ["ndash"] = 0x2013, + ["mdash"] = 0x2014, + ["lsquo"] = 0x2018, + ["rsquo"] = 0x2019, + ["sbquo"] = 0x201A, + ["ldquo"] = 0x201C, + ["rdquo"] = 0x201D, + ["bdquo"] = 0x201E, + ["dagger"] = 0x2020, + ["Dagger"] = 0x2021, + ["bull"] = 0x2022, + ["hellip"] = 0x2026, + ["permil"] = 0x2030, + ["prime"] = 0x2032, + ["Prime"] = 0x2033, + ["lsaquo"] = 0x2039, + ["rsaquo"] = 0x203A, + ["oline"] = 0x203E, + ["frasl"] = 0x2044, + ["euro"] = 0x20AC, + ["image"] = 0x2111, + ["weierp"] = 0x2118, + ["real"] = 0x211C, + ["trade"] = 0x2122, + ["alefsym"] = 0x2135, + ["larr"] = 0x2190, + ["uarr"] = 0x2191, + ["rarr"] = 0x2192, + ["darr"] = 0x2193, + ["harr"] = 0x2194, + ["crarr"] = 0x21B5, + ["lArr"] = 0x21D0, + ["uArr"] = 0x21D1, + ["rArr"] = 0x21D2, + ["dArr"] = 0x21D3, + ["hArr"] = 0x21D4, + ["forall"] = 0x2200, + ["part"] = 0x2202, + ["exist"] = 0x2203, + ["empty"] = 0x2205, + ["nabla"] = 0x2207, + ["isin"] = 0x2208, + ["notin"] = 0x2209, + ["ni"] = 0x220B, + ["prod"] = 0x220F, + ["sum"] = 0x2211, + ["minus"] = 0x2212, + ["lowast"] = 0x2217, + ["radic"] = 0x221A, + ["prop"] = 0x221D, + ["infin"] = 0x221E, + ["ang"] = 0x2220, + ["and"] = 0x2227, + ["or"] = 0x2228, + ["cap"] = 0x2229, + ["cup"] = 0x222A, + ["int"] = 0x222B, + ["there4"] = 0x2234, + ["sim"] = 0x223C, + ["cong"] = 0x2245, + ["asymp"] = 0x2248, + ["ne"] = 0x2260, + ["equiv"] = 0x2261, + ["le"] = 0x2264, + ["ge"] = 0x2265, + ["sub"] = 0x2282, + ["sup"] = 0x2283, + ["nsub"] = 0x2284, + ["sube"] = 0x2286, + ["supe"] = 0x2287, + ["oplus"] = 0x2295, + ["otimes"] = 0x2297, + ["perp"] = 0x22A5, + ["sdot"] = 0x22C5, + ["lceil"] = 0x2308, + ["rceil"] = 0x2309, + ["lfloor"] = 0x230A, + ["rfloor"] = 0x230B, + ["lang"] = 0x27E8, + ["rang"] = 0x27E9, + ["loz"] = 0x25CA, + ["spades"] = 0x2660, + ["clubs"] = 0x2663, + ["hearts"] = 0x2665, + ["diams"] = 0x2666, +} +function entities.dec_entity(s) + return unicode.utf8.char(tonumber(s)) +end +function entities.hex_entity(s) + return unicode.utf8.char(tonumber("0x"..s)) +end +function entities.char_entity(s) + local n = character_entities[s] + return unicode.utf8.char(n) +end +M.writer = {} +function M.writer.new(options) + local self = {} + options = options or {} + setmetatable(options, { __index = function (_, key) + return defaultOptions[key] end }) + self.suffix = ".tex" + self.space = " " + self.nbsp = "\\markdownRendererNbsp{}" + function self.plain(s) + return s + end + function self.paragraph(s) + return s + end + function self.pack(name) + return [[\input"]] .. name .. [["\relax]] + end + self.interblocksep = "\\markdownRendererInterblockSeparator\n{}" + self.eof = [[\relax]] + self.linebreak = "\\markdownRendererLineBreak\n{}" + self.ellipsis = "\\markdownRendererEllipsis{}" + self.hrule = "\\markdownRendererHorizontalRule{}" + local escaped_chars = { + ["{"] = "\\markdownRendererLeftBrace{}", + ["}"] = "\\markdownRendererRightBrace{}", + ["$"] = "\\markdownRendererDollarSign{}", + ["%"] = "\\markdownRendererPercentSign{}", + ["&"] = "\\markdownRendererAmpersand{}", + ["_"] = "\\markdownRendererUnderscore{}", + ["#"] = "\\markdownRendererHash{}", + ["^"] = "\\markdownRendererCircumflex{}", + ["\\"] = "\\markdownRendererBackslash{}", + ["~"] = "\\markdownRendererTilde{}", + ["|"] = "\\markdownRendererPipe{}", + } + local escaped_uri_chars = { + ["{"] = "\\markdownRendererLeftBrace{}", + ["}"] = "\\markdownRendererRightBrace{}", + ["%"] = "\\markdownRendererPercentSign{}", + ["\\"] = "\\markdownRendererBackslash{}", + } + local escaped_citation_chars = { + ["{"] = "\\markdownRendererLeftBrace{}", + ["}"] = "\\markdownRendererRightBrace{}", + ["%"] = "\\markdownRendererPercentSign{}", + ["#"] = "\\markdownRendererHash{}", + ["\\"] = "\\markdownRendererBackslash{}", + } + local escaped_minimal_strings = { + ["^^"] = "\\markdownRendererCircumflex\\markdownRendererCircumflex ", + } + local escape = util.escaper(escaped_chars) + local escape_citation = util.escaper(escaped_citation_chars, + escaped_minimal_strings) + local escape_uri = util.escaper(escaped_uri_chars, escaped_minimal_strings) + if options.hybrid then + self.string = function(s) return s end + self.citation = function(c) return c end + self.uri = function(u) return u end + else + self.string = escape + self.citation = escape_citation + self.uri = escape_uri + end + function self.code(s) + return {"\\markdownRendererCodeSpan{",escape(s),"}"} + end + function self.link(lab,src,tit) + return {"\\markdownRendererLink{",lab,"}", + "{",self.string(src),"}", + "{",self.uri(src),"}", + "{",self.string(tit or ""),"}"} + end + function self.image(lab,src,tit) + return {"\\markdownRendererImage{",lab,"}", + "{",self.string(src),"}", + "{",self.uri(src),"}", + "{",self.string(tit or ""),"}"} + end +local languages_json = (function() + local kpse = require('kpse') + kpse.set_program_name('luatex') + local base, prev, curr + for _, file in ipairs{kpse.lookup(options.contentBlocksLanguageMap, + { all=true })} do + json = assert(io.open(file, "r")):read("*all") + :gsub('("[^\n]-"):','[%1]=') + curr = (function() + local _ENV={ json=json, load=load } -- run in sandbox + return load("return "..json)() + end)() + if type(curr) == "table" then + if base == nil then + base = curr + else + setmetatable(prev, { __index = curr }) + end + prev = curr + end + end + return base or {} +end)() + function self.contentblock(src,suf,type,tit) + src = src.."."..suf + suf = suf:lower() + if type == "onlineimage" then + return {"\\markdownRendererContentBlockOnlineImage{",suf,"}", + "{",self.string(src),"}", + "{",self.uri(src),"}", + "{",self.string(tit or ""),"}"} + elseif languages_json[suf] then + return {"\\markdownRendererContentBlockCode{",suf,"}", + "{",self.string(languages_json[suf]),"}", + "{",self.string(src),"}", + "{",self.uri(src),"}", + "{",self.string(tit or ""),"}"} + else + return {"\\markdownRendererContentBlock{",suf,"}", + "{",self.string(src),"}", + "{",self.uri(src),"}", + "{",self.string(tit or ""),"}"} + end + end + local function ulitem(s) + return {"\\markdownRendererUlItem ",s, + "\\markdownRendererUlItemEnd "} + end + + function self.bulletlist(items,tight) + local buffer = {} + for _,item in ipairs(items) do + buffer[#buffer + 1] = ulitem(item) + end + local contents = util.intersperse(buffer,"\n") + if tight and options.tightLists then + return {"\\markdownRendererUlBeginTight\n",contents, + "\n\\markdownRendererUlEndTight "} + else + return {"\\markdownRendererUlBegin\n",contents, + "\n\\markdownRendererUlEnd "} + end + end + local function olitem(s,num) + if num ~= nil then + return {"\\markdownRendererOlItemWithNumber{",num,"}",s, + "\\markdownRendererOlItemEnd "} + else + return {"\\markdownRendererOlItem ",s, + "\\markdownRendererOlItemEnd "} + end + end + + function self.orderedlist(items,tight,startnum) + local buffer = {} + local num = startnum + for _,item in ipairs(items) do + buffer[#buffer + 1] = olitem(item,num) + if num ~= nil then + num = num + 1 + end + end + local contents = util.intersperse(buffer,"\n") + if tight and options.tightLists then + return {"\\markdownRendererOlBeginTight\n",contents, + "\n\\markdownRendererOlEndTight "} + else + return {"\\markdownRendererOlBegin\n",contents, + "\n\\markdownRendererOlEnd "} + end + end + function self.inline_html(html) return "" end + function self.display_html(html) return "" end + local function dlitem(term, defs) + local retVal = {"\\markdownRendererDlItem{",term,"}"} + for _, def in ipairs(defs) do + retVal[#retVal+1] = {"\\markdownRendererDlDefinitionBegin ",def, + "\\markdownRendererDlDefinitionEnd "} + end + retVal[#retVal+1] = "\\markdownRendererDlItemEnd " + return retVal + end + + function self.definitionlist(items,tight) + local buffer = {} + for _,item in ipairs(items) do + buffer[#buffer + 1] = dlitem(item.term, item.definitions) + end + if tight and options.tightLists then + return {"\\markdownRendererDlBeginTight\n", buffer, + "\n\\markdownRendererDlEndTight"} + else + return {"\\markdownRendererDlBegin\n", buffer, + "\n\\markdownRendererDlEnd"} + end + end + function self.emphasis(s) + return {"\\markdownRendererEmphasis{",s,"}"} + end + function self.strong(s) + return {"\\markdownRendererStrongEmphasis{",s,"}"} + end + function self.blockquote(s) + return {"\\markdownRendererBlockQuoteBegin\n",s, + "\n\\markdownRendererBlockQuoteEnd "} + end + function self.verbatim(s) + local name = util.cache(options.cacheDir, s, nil, nil, ".verbatim") + return {"\\markdownRendererInputVerbatim{",name,"}"} + end + function self.fencedCode(i, s) + local name = util.cache(options.cacheDir, s, nil, nil, ".verbatim") + return {"\\markdownRendererInputFencedCode{",name,"}{",i,"}"} + end + function self.heading(s,level) + local cmd + if level == 1 then + cmd = "\\markdownRendererHeadingOne" + elseif level == 2 then + cmd = "\\markdownRendererHeadingTwo" + elseif level == 3 then + cmd = "\\markdownRendererHeadingThree" + elseif level == 4 then + cmd = "\\markdownRendererHeadingFour" + elseif level == 5 then + cmd = "\\markdownRendererHeadingFive" + elseif level == 6 then + cmd = "\\markdownRendererHeadingSix" + else + cmd = "" + end + return {cmd,"{",s,"}"} + end + function self.note(s) + return {"\\markdownRendererFootnote{",s,"}"} + end + function self.citations(text_cites, cites) + local buffer = {"\\markdownRenderer", text_cites and "TextCite" or "Cite", + "{", #cites, "}"} + for _,cite in ipairs(cites) do + buffer[#buffer+1] = {cite.suppress_author and "-" or "+", "{", + cite.prenote or "", "}{", cite.postnote or "", "}{", cite.name, "}"} + end + return buffer + end + + return self +end +local parsers = {} +parsers.percent = P("%") +parsers.at = P("@") +parsers.comma = P(",") +parsers.asterisk = P("*") +parsers.dash = P("-") +parsers.plus = P("+") +parsers.underscore = P("_") +parsers.period = P(".") +parsers.hash = P("#") +parsers.ampersand = P("&") +parsers.backtick = P("`") +parsers.less = P("<") +parsers.more = P(">") +parsers.space = P(" ") +parsers.squote = P("'") +parsers.dquote = P('"') +parsers.lparent = P("(") +parsers.rparent = P(")") +parsers.lbracket = P("[") +parsers.rbracket = P("]") +parsers.circumflex = P("^") +parsers.slash = P("/") +parsers.equal = P("=") +parsers.colon = P(":") +parsers.semicolon = P(";") +parsers.exclamation = P("!") +parsers.tilde = P("~") +parsers.tab = P("\t") +parsers.newline = P("\n") +parsers.tightblocksep = P("\001") + +parsers.digit = R("09") +parsers.hexdigit = R("09","af","AF") +parsers.letter = R("AZ","az") +parsers.alphanumeric = R("AZ","az","09") +parsers.keyword = parsers.letter + * parsers.alphanumeric^0 +parsers.citation_chars = parsers.alphanumeric + + S("#$%&-+<>~/_") +parsers.internal_punctuation = S(":;,.?") + +parsers.doubleasterisks = P("**") +parsers.doubleunderscores = P("__") +parsers.fourspaces = P(" ") + +parsers.any = P(1) +parsers.fail = parsers.any - 1 + +parsers.escapable = S("\\`*_{}[]()+_.!<>#-~:^@;") +parsers.anyescaped = P("\\") / "" * parsers.escapable + + parsers.any + +parsers.spacechar = S("\t ") +parsers.spacing = S(" \n\r\t") +parsers.nonspacechar = parsers.any - parsers.spacing +parsers.optionalspace = parsers.spacechar^0 + +parsers.specialchar = S("*_`&[]= #b and i +end + +parsers.infostring = (parsers.linechar - (parsers.backtick + + parsers.space^1 * (parsers.newline + parsers.eof)))^0 + +local fenceindent +parsers.fencehead = function(char) + return C(parsers.nonindentspace) / function(s) fenceindent = #s end + * Cg(char^3, "fencelength") + * parsers.optionalspace * C(parsers.infostring) + * parsers.optionalspace * (parsers.newline + parsers.eof) +end + +parsers.fencetail = function(char) + return parsers.nonindentspace + * Cmt(C(char^3) * Cb("fencelength"), captures_geq_length) + * parsers.optionalspace * (parsers.newline + parsers.eof) + + parsers.eof +end + +parsers.fencedline = function(char) + return C(parsers.line - parsers.fencetail(char)) + / function(s) + i = 1 + remaining = fenceindent + while true do + c = s:sub(i, i) + if c == " " and remaining > 0 then + remaining = remaining - 1 + i = i + 1 + elseif c == "\t" and remaining > 3 then + remaining = remaining - 4 + i = i + 1 + else + break + end + end + return s:sub(i) + end +end +parsers.leader = parsers.space^-3 + +-- content in balanced brackets, parentheses, or quotes: +parsers.bracketed = P{ parsers.lbracket + * ((parsers.anyescaped - (parsers.lbracket + + parsers.rbracket + + parsers.blankline^2) + ) + V(1))^0 + * parsers.rbracket } + +parsers.inparens = P{ parsers.lparent + * ((parsers.anyescaped - (parsers.lparent + + parsers.rparent + + parsers.blankline^2) + ) + V(1))^0 + * parsers.rparent } + +parsers.squoted = P{ parsers.squote * parsers.alphanumeric + * ((parsers.anyescaped - (parsers.squote + + parsers.blankline^2) + ) + V(1))^0 + * parsers.squote } + +parsers.dquoted = P{ parsers.dquote * parsers.alphanumeric + * ((parsers.anyescaped - (parsers.dquote + + parsers.blankline^2) + ) + V(1))^0 + * parsers.dquote } + +-- bracketed tag for markdown links, allowing nested brackets: +parsers.tag = parsers.lbracket + * Cs((parsers.alphanumeric^1 + + parsers.bracketed + + parsers.inticks + + (parsers.anyescaped + - (parsers.rbracket + parsers.blankline^2)))^0) + * parsers.rbracket + +-- url for markdown links, allowing nested brackets: +parsers.url = parsers.less * Cs((parsers.anyescaped + - parsers.more)^0) + * parsers.more + + Cs((parsers.inparens + (parsers.anyescaped + - parsers.spacing + - parsers.rparent))^1) + +-- quoted text, possibly with nested quotes: +parsers.title_s = parsers.squote * Cs(((parsers.anyescaped-parsers.squote) + + parsers.squoted)^0) + * parsers.squote + +parsers.title_d = parsers.dquote * Cs(((parsers.anyescaped-parsers.dquote) + + parsers.dquoted)^0) + * parsers.dquote + +parsers.title_p = parsers.lparent + * Cs((parsers.inparens + (parsers.anyescaped-parsers.rparent))^0) + * parsers.rparent + +parsers.title = parsers.title_d + parsers.title_s + parsers.title_p + +parsers.optionaltitle + = parsers.spnl * parsers.title * parsers.spacechar^0 + + Cc("") +parsers.contentblock_tail + = parsers.optionaltitle + * (parsers.newline + parsers.eof) + +-- case insensitive online image suffix: +parsers.onlineimagesuffix + = (function(...) + local parser = nil + for _,suffix in ipairs({...}) do + local pattern=nil + for i=1,#suffix do + local char=suffix:sub(i,i) + char = S(char:lower()..char:upper()) + if pattern == nil then + pattern = char + else + pattern = pattern * char + end + end + if parser == nil then + parser = pattern + else + parser = parser + pattern + end + end + return parser + end)("png", "jpg", "jpeg", "gif", "tif", "tiff") + +-- online image url for iA Writer content blocks with mandatory suffix, +-- allowing nested brackets: +parsers.onlineimageurl + = (parsers.less + * Cs((parsers.anyescaped + - parsers.more + - #(parsers.period + * parsers.onlineimagesuffix + * parsers.more + * parsers.contentblock_tail))^0) + * parsers.period + * Cs(parsers.onlineimagesuffix) + * parsers.more + + (Cs((parsers.inparens + + (parsers.anyescaped + - parsers.spacing + - parsers.rparent + - #(parsers.period + * parsers.onlineimagesuffix + * parsers.contentblock_tail)))^0) + * parsers.period + * Cs(parsers.onlineimagesuffix)) + ) * Cc("onlineimage") + +-- filename for iA Writer content blocks with mandatory suffix: +parsers.localfilepath + = parsers.slash + * Cs((parsers.anyescaped + - parsers.tab + - parsers.newline + - #(parsers.period + * parsers.alphanumeric^1 + * parsers.contentblock_tail))^1) + * parsers.period + * Cs(parsers.alphanumeric^1) + * Cc("localfile") +parsers.citation_name = Cs(parsers.dash^-1) * parsers.at + * Cs(parsers.citation_chars + * (((parsers.citation_chars + parsers.internal_punctuation + - parsers.comma - parsers.semicolon) + * -#((parsers.internal_punctuation - parsers.comma + - parsers.semicolon)^0 + * -(parsers.citation_chars + parsers.internal_punctuation + - parsers.comma - parsers.semicolon)))^0 + * parsers.citation_chars)^-1) + +parsers.citation_body_prenote + = Cs((parsers.alphanumeric^1 + + parsers.bracketed + + parsers.inticks + + (parsers.anyescaped + - (parsers.rbracket + parsers.blankline^2)) + - (parsers.spnl * parsers.dash^-1 * parsers.at))^0) + +parsers.citation_body_postnote + = Cs((parsers.alphanumeric^1 + + parsers.bracketed + + parsers.inticks + + (parsers.anyescaped + - (parsers.rbracket + parsers.semicolon + + parsers.blankline^2)) + - (parsers.spnl * parsers.rbracket))^0) + +parsers.citation_body_chunk + = parsers.citation_body_prenote + * parsers.spnl * parsers.citation_name + * ((parsers.internal_punctuation - parsers.semicolon) + * parsers.spnl)^-1 + * parsers.citation_body_postnote + +parsers.citation_body + = parsers.citation_body_chunk + * (parsers.semicolon * parsers.spnl + * parsers.citation_body_chunk)^0 + +parsers.citation_headless_body_postnote + = Cs((parsers.alphanumeric^1 + + parsers.bracketed + + parsers.inticks + + (parsers.anyescaped + - (parsers.rbracket + parsers.at + + parsers.semicolon + parsers.blankline^2)) + - (parsers.spnl * parsers.rbracket))^0) + +parsers.citation_headless_body + = parsers.citation_headless_body_postnote + * (parsers.sp * parsers.semicolon * parsers.spnl + * parsers.citation_body_chunk)^0 +local function strip_first_char(s) + return s:sub(2) +end + +parsers.RawNoteRef = #(parsers.lbracket * parsers.circumflex) + * parsers.tag / strip_first_char +-- case-insensitive match (we assume s is lowercase). must be single byte encoding +parsers.keyword_exact = function(s) + local parser = P(0) + for i=1,#s do + local c = s:sub(i,i) + local m = c .. upper(c) + parser = parser * S(m) + end + return parser +end + +parsers.block_keyword = + parsers.keyword_exact("address") + parsers.keyword_exact("blockquote") + + parsers.keyword_exact("center") + parsers.keyword_exact("del") + + parsers.keyword_exact("dir") + parsers.keyword_exact("div") + + parsers.keyword_exact("p") + parsers.keyword_exact("pre") + + parsers.keyword_exact("li") + parsers.keyword_exact("ol") + + parsers.keyword_exact("ul") + parsers.keyword_exact("dl") + + parsers.keyword_exact("dd") + parsers.keyword_exact("form") + + parsers.keyword_exact("fieldset") + parsers.keyword_exact("isindex") + + parsers.keyword_exact("ins") + parsers.keyword_exact("menu") + + parsers.keyword_exact("noframes") + parsers.keyword_exact("frameset") + + parsers.keyword_exact("h1") + parsers.keyword_exact("h2") + + parsers.keyword_exact("h3") + parsers.keyword_exact("h4") + + parsers.keyword_exact("h5") + parsers.keyword_exact("h6") + + parsers.keyword_exact("hr") + parsers.keyword_exact("script") + + parsers.keyword_exact("noscript") + parsers.keyword_exact("table") + + parsers.keyword_exact("tbody") + parsers.keyword_exact("tfoot") + + parsers.keyword_exact("thead") + parsers.keyword_exact("th") + + parsers.keyword_exact("td") + parsers.keyword_exact("tr") + +-- There is no reason to support bad html, so we expect quoted attributes +parsers.htmlattributevalue + = parsers.squote * (parsers.any - (parsers.blankline + + parsers.squote))^0 + * parsers.squote + + parsers.dquote * (parsers.any - (parsers.blankline + + parsers.dquote))^0 + * parsers.dquote + +parsers.htmlattribute = parsers.spacing^1 + * (parsers.alphanumeric + S("_-"))^1 + * parsers.sp * parsers.equal * parsers.sp + * parsers.htmlattributevalue + +parsers.htmlcomment = P(""))^0 * P("-->") + +parsers.htmlinstruction = P("" ))^0 * P("?>" ) + +parsers.openelt_any = parsers.less * parsers.keyword * parsers.htmlattribute^0 + * parsers.sp * parsers.more + +parsers.openelt_exact = function(s) + return parsers.less * parsers.sp * parsers.keyword_exact(s) + * parsers.htmlattribute^0 * parsers.sp * parsers.more +end + +parsers.openelt_block = parsers.sp * parsers.block_keyword + * parsers.htmlattribute^0 * parsers.sp * parsers.more + +parsers.closeelt_any = parsers.less * parsers.sp * parsers.slash + * parsers.keyword * parsers.sp * parsers.more + +parsers.closeelt_exact = function(s) + return parsers.less * parsers.sp * parsers.slash * parsers.keyword_exact(s) + * parsers.sp * parsers.more +end + +parsers.emptyelt_any = parsers.less * parsers.sp * parsers.keyword + * parsers.htmlattribute^0 * parsers.sp * parsers.slash + * parsers.more + +parsers.emptyelt_block = parsers.less * parsers.sp * parsers.block_keyword + * parsers.htmlattribute^0 * parsers.sp * parsers.slash + * parsers.more + +parsers.displaytext = (parsers.any - parsers.less)^1 + +-- return content between two matched HTML tags +parsers.in_matched = function(s) + return { parsers.openelt_exact(s) + * (V(1) + parsers.displaytext + + (parsers.less - parsers.closeelt_exact(s)))^0 + * parsers.closeelt_exact(s) } +end + +local function parse_matched_tags(s,pos) + local t = string.lower(lpeg.match(C(parsers.keyword),s,pos)) + return lpeg.match(parsers.in_matched(t),s,pos-1) +end + +parsers.in_matched_block_tags = parsers.less + * Cmt(#parsers.openelt_block, parse_matched_tags) + +parsers.displayhtml = parsers.htmlcomment + + parsers.emptyelt_block + + parsers.openelt_exact("hr") + + parsers.in_matched_block_tags + + parsers.htmlinstruction + +parsers.inlinehtml = parsers.emptyelt_any + + parsers.htmlcomment + + parsers.htmlinstruction + + parsers.openelt_any + + parsers.closeelt_any +parsers.hexentity = parsers.ampersand * parsers.hash * S("Xx") + * C(parsers.hexdigit^1) * parsers.semicolon +parsers.decentity = parsers.ampersand * parsers.hash + * C(parsers.digit^1) * parsers.semicolon +parsers.tagentity = parsers.ampersand * C(parsers.alphanumeric^1) + * parsers.semicolon +-- parse a reference definition: [foo]: /bar "title" +parsers.define_reference_parser = parsers.leader * parsers.tag * parsers.colon + * parsers.spacechar^0 * parsers.url + * parsers.optionaltitle * parsers.blankline^1 +parsers.Inline = V("Inline") + +-- parse many p between starter and ender +parsers.between = function(p, starter, ender) + local ender2 = B(parsers.nonspacechar) * ender + return (starter * #parsers.nonspacechar * Ct(p * (p - ender2)^0) * ender2) +end + +parsers.urlchar = parsers.anyescaped - parsers.newline - parsers.more +parsers.Block = V("Block") + +parsers.OnlineImageURL + = parsers.leader + * parsers.onlineimageurl + * parsers.optionaltitle + +parsers.LocalFilePath + = parsers.leader + * parsers.localfilepath + * parsers.optionaltitle + +parsers.TildeFencedCode + = parsers.fencehead(parsers.tilde) + * Cs(parsers.fencedline(parsers.tilde)^0) + * parsers.fencetail(parsers.tilde) + +parsers.BacktickFencedCode + = parsers.fencehead(parsers.backtick) + * Cs(parsers.fencedline(parsers.backtick)^0) + * parsers.fencetail(parsers.backtick) + +parsers.lineof = function(c) + return (parsers.leader * (P(c) * parsers.optionalspace)^3 + * (parsers.newline * parsers.blankline^1 + + parsers.newline^-1 * parsers.eof)) +end +parsers.defstartchar = S("~:") +parsers.defstart = ( parsers.defstartchar * #parsers.spacing + * (parsers.tab + parsers.space^-3) + + parsers.space * parsers.defstartchar * #parsers.spacing + * (parsers.tab + parsers.space^-2) + + parsers.space * parsers.space * parsers.defstartchar + * #parsers.spacing + * (parsers.tab + parsers.space^-1) + + parsers.space * parsers.space * parsers.space + * parsers.defstartchar * #parsers.spacing + ) + +parsers.dlchunk = Cs(parsers.line * (parsers.indentedline - parsers.blankline)^0) +-- parse Atx heading start and return level +parsers.HeadingStart = #parsers.hash * C(parsers.hash^-6) + * -parsers.hash / length + +-- parse setext header ending and return level +parsers.HeadingLevel = parsers.equal^1 * Cc(1) + parsers.dash^1 * Cc(2) + +local function strip_atx_end(s) + return s:gsub("[#%s]*\n$","") +end +M.reader = {} +function M.reader.new(writer, options) + local self = {} + options = options or {} + setmetatable(options, { __index = function (_, key) + return defaultOptions[key] end }) + local function normalize_tag(tag) + return unicode.utf8.lower( + gsub(util.rope_to_string(tag), "[ \n\r\t]+", " ")) + end + local expandtabs + if options.preserveTabs then + expandtabs = function(s) return s end + else + expandtabs = function(s) + if s:find("\t") then + return s:gsub("[^\n]*", util.expand_tabs_in_line) + else + return s + end + end + end + local larsers = {} + local function create_parser(name, grammar) + return function(str) + local res = lpeg.match(grammar(), str) + if res == nil then + error(format("%s failed on:\n%s", name, str:sub(1,20))) + else + return res + end + end + end + + local parse_blocks + = create_parser("parse_blocks", + function() + return larsers.blocks + end) + + local parse_blocks_toplevel + = create_parser("parse_blocks_toplevel", + function() + return larsers.blocks_toplevel + end) + + local parse_inlines + = create_parser("parse_inlines", + function() + return larsers.inlines + end) + + local parse_inlines_no_link + = create_parser("parse_inlines_no_link", + function() + return larsers.inlines_no_link + end) + + local parse_inlines_no_inline_note + = create_parser("parse_inlines_no_inline_note", + function() + return larsers.inlines_no_inline_note + end) + + local parse_inlines_nbsp + = create_parser("parse_inlines_nbsp", + function() + return larsers.inlines_nbsp + end) + if options.hashEnumerators then + larsers.dig = parsers.digit + parsers.hash + else + larsers.dig = parsers.digit + end + + larsers.enumerator = C(larsers.dig^3 * parsers.period) * #parsers.spacing + + C(larsers.dig^2 * parsers.period) * #parsers.spacing + * (parsers.tab + parsers.space^1) + + C(larsers.dig * parsers.period) * #parsers.spacing + * (parsers.tab + parsers.space^-2) + + parsers.space * C(larsers.dig^2 * parsers.period) + * #parsers.spacing + + parsers.space * C(larsers.dig * parsers.period) + * #parsers.spacing + * (parsers.tab + parsers.space^-1) + + parsers.space * parsers.space * C(larsers.dig^1 + * parsers.period) * #parsers.spacing + -- strip off leading > and indents, and run through blocks + larsers.blockquote_body = ((parsers.leader * parsers.more * parsers.space^-1)/"" + * parsers.linechar^0 * parsers.newline)^1 + * (-(parsers.leader * parsers.more + + parsers.blankline) * parsers.linechar^1 + * parsers.newline)^0 + + if not options.breakableBlockquotes then + larsers.blockquote_body = larsers.blockquote_body + * (parsers.blankline^0 / "") + end + larsers.citations = function(text_cites, raw_cites) + local function normalize(str) + if str == "" then + str = nil + else + str = (options.citationNbsps and parse_inlines_nbsp or + parse_inlines)(str) + end + return str + end + + local cites = {} + for i = 1,#raw_cites,4 do + cites[#cites+1] = { + prenote = normalize(raw_cites[i]), + suppress_author = raw_cites[i+1] == "-", + name = writer.citation(raw_cites[i+2]), + postnote = normalize(raw_cites[i+3]), + } + end + return writer.citations(text_cites, cites) + end + local rawnotes = {} + + -- like indirect_link + local function lookup_note(ref) + return function() + local found = rawnotes[normalize_tag(ref)] + if found then + return writer.note(parse_blocks_toplevel(found)) + else + return {"[", parse_inlines("^" .. ref), "]"} + end + end + end + + local function register_note(ref,rawnote) + rawnotes[normalize_tag(ref)] = rawnote + return "" + end + + larsers.NoteRef = parsers.RawNoteRef / lookup_note + + larsers.NoteBlock = parsers.leader * parsers.RawNoteRef * parsers.colon + * parsers.spnl * parsers.indented_blocks(parsers.chunk) + / register_note + + larsers.InlineNote = parsers.circumflex + * (parsers.tag / parse_inlines_no_inline_note) -- no notes inside notes + / writer.note + -- List of references defined in the document + local references + + -- add a reference to the list + local function register_link(tag,url,title) + references[normalize_tag(tag)] = { url = url, title = title } + return "" + end + + -- lookup link reference and return either + -- the link or nil and fallback text. + local function lookup_reference(label,sps,tag) + local tagpart + if not tag then + tag = label + tagpart = "" + elseif tag == "" then + tag = label + tagpart = "[]" + else + tagpart = {"[", parse_inlines(tag), "]"} + end + if sps then + tagpart = {sps, tagpart} + end + local r = references[normalize_tag(tag)] + if r then + return r + else + return nil, {"[", parse_inlines(label), "]", tagpart} + end + end + + -- lookup link reference and return a link, if the reference is found, + -- or a bracketed label otherwise. + local function indirect_link(label,sps,tag) + return function() + local r,fallback = lookup_reference(label,sps,tag) + if r then + return writer.link(parse_inlines_no_link(label), r.url, r.title) + else + return fallback + end + end + end + + -- lookup image reference and return an image, if the reference is found, + -- or a bracketed label otherwise. + local function indirect_image(label,sps,tag) + return function() + local r,fallback = lookup_reference(label,sps,tag) + if r then + return writer.image(writer.string(label), r.url, r.title) + else + return {"!", fallback} + end + end + end + larsers.Str = parsers.normalchar^1 / writer.string + + larsers.Symbol = (parsers.specialchar - parsers.tightblocksep) + / writer.string + + larsers.Ellipsis = P("...") / writer.ellipsis + + larsers.Smart = larsers.Ellipsis + + larsers.Code = parsers.inticks / writer.code + + if options.blankBeforeBlockquote then + larsers.bqstart = parsers.fail + else + larsers.bqstart = parsers.more + end + + if options.blankBeforeHeading then + larsers.headerstart = parsers.fail + else + larsers.headerstart = parsers.hash + + (parsers.line * (parsers.equal^1 + parsers.dash^1) + * parsers.optionalspace * parsers.newline) + end + + if not options.fencedCode or options.blankBeforeCodeFence then + larsers.fencestart = parsers.fail + else + larsers.fencestart = parsers.fencehead(parsers.backtick) + + parsers.fencehead(parsers.tilde) + end + + larsers.Endline = parsers.newline * -( -- newline, but not before... + parsers.blankline -- paragraph break + + parsers.tightblocksep -- nested list + + parsers.eof -- end of document + + larsers.bqstart + + larsers.headerstart + + larsers.fencestart + ) * parsers.spacechar^0 / writer.space + + larsers.Space = parsers.spacechar^2 * larsers.Endline / writer.linebreak + + parsers.spacechar^1 * larsers.Endline^-1 * parsers.eof / "" + + parsers.spacechar^1 * larsers.Endline^-1 + * parsers.optionalspace / writer.space + + larsers.NonbreakingEndline + = parsers.newline * -( -- newline, but not before... + parsers.blankline -- paragraph break + + parsers.tightblocksep -- nested list + + parsers.eof -- end of document + + larsers.bqstart + + larsers.headerstart + + larsers.fencestart + ) * parsers.spacechar^0 / writer.nbsp + + larsers.NonbreakingSpace + = parsers.spacechar^2 * larsers.Endline / writer.linebreak + + parsers.spacechar^1 * larsers.Endline^-1 * parsers.eof / "" + + parsers.spacechar^1 * larsers.Endline^-1 + * parsers.optionalspace / writer.nbsp + + if options.underscores then + larsers.Strong = ( parsers.between(parsers.Inline, parsers.doubleasterisks, + parsers.doubleasterisks) + + parsers.between(parsers.Inline, parsers.doubleunderscores, + parsers.doubleunderscores) + ) / writer.strong + + larsers.Emph = ( parsers.between(parsers.Inline, parsers.asterisk, + parsers.asterisk) + + parsers.between(parsers.Inline, parsers.underscore, + parsers.underscore) + ) / writer.emphasis + else + larsers.Strong = ( parsers.between(parsers.Inline, parsers.doubleasterisks, + parsers.doubleasterisks) + ) / writer.strong + + larsers.Emph = ( parsers.between(parsers.Inline, parsers.asterisk, + parsers.asterisk) + ) / writer.emphasis + end + + larsers.AutoLinkUrl = parsers.less + * C(parsers.alphanumeric^1 * P("://") * parsers.urlchar^1) + * parsers.more + / function(url) + return writer.link(writer.string(url), url) + end + + larsers.AutoLinkEmail = parsers.less + * C((parsers.alphanumeric + S("-._+"))^1 + * P("@") * parsers.urlchar^1) + * parsers.more + / function(email) + return writer.link(writer.string(email), + "mailto:"..email) + end + + larsers.DirectLink = (parsers.tag / parse_inlines_no_link) -- no links inside links + * parsers.spnl + * parsers.lparent + * (parsers.url + Cc("")) -- link can be empty [foo]() + * parsers.optionaltitle + * parsers.rparent + / writer.link + + larsers.IndirectLink = parsers.tag * (C(parsers.spnl) * parsers.tag)^-1 + / indirect_link + + -- parse a link or image (direct or indirect) + larsers.Link = larsers.DirectLink + larsers.IndirectLink + + larsers.DirectImage = parsers.exclamation + * (parsers.tag / parse_inlines) + * parsers.spnl + * parsers.lparent + * (parsers.url + Cc("")) -- link can be empty [foo]() + * parsers.optionaltitle + * parsers.rparent + / writer.image + + larsers.IndirectImage = parsers.exclamation * parsers.tag + * (C(parsers.spnl) * parsers.tag)^-1 / indirect_image + + larsers.Image = larsers.DirectImage + larsers.IndirectImage + + larsers.TextCitations = Ct(Cc("") + * parsers.citation_name + * ((parsers.spnl + * parsers.lbracket + * parsers.citation_headless_body + * parsers.rbracket) + Cc(""))) + / function(raw_cites) + return larsers.citations(true, raw_cites) + end + + larsers.ParenthesizedCitations + = Ct(parsers.lbracket + * parsers.citation_body + * parsers.rbracket) + / function(raw_cites) + return larsers.citations(false, raw_cites) + end + + larsers.Citations = larsers.TextCitations + larsers.ParenthesizedCitations + + -- avoid parsing long strings of * or _ as emph/strong + larsers.UlOrStarLine = parsers.asterisk^4 + parsers.underscore^4 + / writer.string + + larsers.EscapedChar = S("\\") * C(parsers.escapable) / writer.string + + larsers.InlineHtml = C(parsers.inlinehtml) / writer.inline_html + + larsers.HtmlEntity = parsers.hexentity / entities.hex_entity / writer.string + + parsers.decentity / entities.dec_entity / writer.string + + parsers.tagentity / entities.char_entity / writer.string + larsers.ContentBlock = parsers.leader + * (parsers.localfilepath + parsers.onlineimageurl) + * parsers.contentblock_tail + / writer.contentblock + + larsers.DisplayHtml = C(parsers.displayhtml) + / expandtabs / writer.display_html + + larsers.Verbatim = Cs( (parsers.blanklines + * ((parsers.indentedline - parsers.blankline))^1)^1 + ) / expandtabs / writer.verbatim + + larsers.FencedCode = (parsers.TildeFencedCode + + parsers.BacktickFencedCode) + / function(infostring, code) + return writer.fencedCode(writer.string(infostring), + expandtabs(code)) + end + + larsers.Blockquote = Cs(larsers.blockquote_body^1) + / parse_blocks_toplevel / writer.blockquote + + larsers.HorizontalRule = ( parsers.lineof(parsers.asterisk) + + parsers.lineof(parsers.dash) + + parsers.lineof(parsers.underscore) + ) / writer.hrule + + larsers.Reference = parsers.define_reference_parser / register_link + + larsers.Paragraph = parsers.nonindentspace * Ct(parsers.Inline^1) + * parsers.newline + * ( parsers.blankline^1 + + #parsers.hash + + #(parsers.leader * parsers.more * parsers.space^-1) + ) + / writer.paragraph + + larsers.ToplevelParagraph + = parsers.nonindentspace * Ct(parsers.Inline^1) + * ( parsers.newline + * ( parsers.blankline^1 + + #parsers.hash + + #(parsers.leader * parsers.more * parsers.space^-1) + + parsers.eof + ) + + parsers.eof ) + / writer.paragraph + + larsers.Plain = parsers.nonindentspace * Ct(parsers.Inline^1) + / writer.plain + larsers.starter = parsers.bullet + larsers.enumerator + + -- we use \001 as a separator between a tight list item and a + -- nested list under it. + larsers.NestedList = Cs((parsers.optionallyindentedline + - larsers.starter)^1) + / function(a) return "\001"..a end + + larsers.ListBlockLine = parsers.optionallyindentedline + - parsers.blankline - (parsers.indent^-1 + * larsers.starter) + + larsers.ListBlock = parsers.line * larsers.ListBlockLine^0 + + larsers.ListContinuationBlock = parsers.blanklines * (parsers.indent / "") + * larsers.ListBlock + + larsers.TightListItem = function(starter) + return -larsers.HorizontalRule + * (Cs(starter / "" * larsers.ListBlock * larsers.NestedList^-1) + / parse_blocks) + * -(parsers.blanklines * parsers.indent) + end + + larsers.LooseListItem = function(starter) + return -larsers.HorizontalRule + * Cs( starter / "" * larsers.ListBlock * Cc("\n") + * (larsers.NestedList + larsers.ListContinuationBlock^0) + * (parsers.blanklines / "\n\n") + ) / parse_blocks + end + + larsers.BulletList = ( Ct(larsers.TightListItem(parsers.bullet)^1) * Cc(true) + * parsers.skipblanklines * -parsers.bullet + + Ct(larsers.LooseListItem(parsers.bullet)^1) * Cc(false) + * parsers.skipblanklines ) + / writer.bulletlist + + local function ordered_list(items,tight,startNumber) + if options.startNumber then + startNumber = tonumber(startNumber) or 1 -- fallback for '#' + else + startNumber = nil + end + return writer.orderedlist(items,tight,startNumber) + end + + larsers.OrderedList = Cg(larsers.enumerator, "listtype") * + ( Ct(larsers.TightListItem(Cb("listtype")) + * larsers.TightListItem(larsers.enumerator)^0) + * Cc(true) * parsers.skipblanklines * -larsers.enumerator + + Ct(larsers.LooseListItem(Cb("listtype")) + * larsers.LooseListItem(larsers.enumerator)^0) + * Cc(false) * parsers.skipblanklines + ) * Cb("listtype") / ordered_list + + local function definition_list_item(term, defs, tight) + return { term = parse_inlines(term), definitions = defs } + end + + larsers.DefinitionListItemLoose = C(parsers.line) * parsers.skipblanklines + * Ct((parsers.defstart + * parsers.indented_blocks(parsers.dlchunk) + / parse_blocks_toplevel)^1) + * Cc(false) / definition_list_item + + larsers.DefinitionListItemTight = C(parsers.line) + * Ct((parsers.defstart * parsers.dlchunk + / parse_blocks)^1) + * Cc(true) / definition_list_item + + larsers.DefinitionList = ( Ct(larsers.DefinitionListItemLoose^1) * Cc(false) + + Ct(larsers.DefinitionListItemTight^1) + * (parsers.skipblanklines + * -larsers.DefinitionListItemLoose * Cc(true)) + ) / writer.definitionlist + larsers.Blank = parsers.blankline / "" + + larsers.NoteBlock + + larsers.Reference + + (parsers.tightblocksep / "\n") + -- parse atx header + larsers.AtxHeading = Cg(parsers.HeadingStart,"level") + * parsers.optionalspace + * (C(parsers.line) / strip_atx_end / parse_inlines) + * Cb("level") + / writer.heading + + -- parse setext header + larsers.SetextHeading = #(parsers.line * S("=-")) + * Ct(parsers.line / parse_inlines) + * parsers.HeadingLevel + * parsers.optionalspace * parsers.newline + / writer.heading + + larsers.Heading = larsers.AtxHeading + larsers.SetextHeading + local syntax = + { "Blocks", + + Blocks = larsers.Blank^0 * parsers.Block^-1 + * (larsers.Blank^0 / function() + return writer.interblocksep + end + * parsers.Block)^0 + * larsers.Blank^0 * parsers.eof, + + Blank = larsers.Blank, + + Block = V("ContentBlock") + + V("Blockquote") + + V("Verbatim") + + V("FencedCode") + + V("HorizontalRule") + + V("BulletList") + + V("OrderedList") + + V("Heading") + + V("DefinitionList") + + V("DisplayHtml") + + V("Paragraph") + + V("Plain"), + + ContentBlock = larsers.ContentBlock, + Blockquote = larsers.Blockquote, + Verbatim = larsers.Verbatim, + FencedCode = larsers.FencedCode, + HorizontalRule = larsers.HorizontalRule, + BulletList = larsers.BulletList, + OrderedList = larsers.OrderedList, + Heading = larsers.Heading, + DefinitionList = larsers.DefinitionList, + DisplayHtml = larsers.DisplayHtml, + Paragraph = larsers.Paragraph, + Plain = larsers.Plain, + + Inline = V("Str") + + V("Space") + + V("Endline") + + V("UlOrStarLine") + + V("Strong") + + V("Emph") + + V("InlineNote") + + V("NoteRef") + + V("Citations") + + V("Link") + + V("Image") + + V("Code") + + V("AutoLinkUrl") + + V("AutoLinkEmail") + + V("InlineHtml") + + V("HtmlEntity") + + V("EscapedChar") + + V("Smart") + + V("Symbol"), + + Str = larsers.Str, + Space = larsers.Space, + Endline = larsers.Endline, + UlOrStarLine = larsers.UlOrStarLine, + Strong = larsers.Strong, + Emph = larsers.Emph, + InlineNote = larsers.InlineNote, + NoteRef = larsers.NoteRef, + Citations = larsers.Citations, + Link = larsers.Link, + Image = larsers.Image, + Code = larsers.Code, + AutoLinkUrl = larsers.AutoLinkUrl, + AutoLinkEmail = larsers.AutoLinkEmail, + InlineHtml = larsers.InlineHtml, + HtmlEntity = larsers.HtmlEntity, + EscapedChar = larsers.EscapedChar, + Smart = larsers.Smart, + Symbol = larsers.Symbol, + } + + if not options.citations then + syntax.Citations = parsers.fail + end + + if not options.contentBlocks then + syntax.ContentBlock = parsers.fail + end + + if not options.codeSpans then + syntax.Code = parsers.fail + end + + if not options.definitionLists then + syntax.DefinitionList = parsers.fail + end + + if not options.fencedCode then + syntax.FencedCode = parsers.fail + end + + if not options.footnotes then + syntax.NoteRef = parsers.fail + end + + if not options.html then + syntax.DisplayHtml = parsers.fail + syntax.InlineHtml = parsers.fail + syntax.HtmlEntity = parsers.fail + end + + if not options.inlineFootnotes then + syntax.InlineNote = parsers.fail + end + + if not options.smartEllipses then + syntax.Smart = parsers.fail + end + + local blocks_toplevel_t = util.table_copy(syntax) + blocks_toplevel_t.Paragraph = larsers.ToplevelParagraph + larsers.blocks_toplevel = Ct(blocks_toplevel_t) + + larsers.blocks = Ct(syntax) + + local inlines_t = util.table_copy(syntax) + inlines_t[1] = "Inlines" + inlines_t.Inlines = parsers.Inline^0 * (parsers.spacing^0 * parsers.eof / "") + larsers.inlines = Ct(inlines_t) + + local inlines_no_link_t = util.table_copy(inlines_t) + inlines_no_link_t.Link = parsers.fail + larsers.inlines_no_link = Ct(inlines_no_link_t) + + local inlines_no_inline_note_t = util.table_copy(inlines_t) + inlines_no_inline_note_t.InlineNote = parsers.fail + larsers.inlines_no_inline_note = Ct(inlines_no_inline_note_t) + + local inlines_nbsp_t = util.table_copy(inlines_t) + inlines_nbsp_t.Endline = larsers.NonbreakingEndline + inlines_nbsp_t.Space = larsers.NonbreakingSpace + larsers.inlines_nbsp = Ct(inlines_nbsp_t) + function self.convert(input) + references = {} + local opt_string = {} + for k,_ in pairs(defaultOptions) do + local v = options[k] + if k ~= "cacheDir" then + opt_string[#opt_string+1] = k .. "=" .. tostring(v) + end + end + table.sort(opt_string) + local salt = table.concat(opt_string, ",") .. "," .. metadata.version + local name = util.cache(options.cacheDir, input, salt, function(input) + return util.rope_to_string(parse_blocks_toplevel(input)) .. writer.eof + end, ".md" .. writer.suffix) + return writer.pack(name) + end + return self +end +function M.new(options) + local writer = M.writer.new(options) + local reader = M.reader.new(writer, options) + return reader.convert +end + +return M diff --git a/latex/markdown.sty b/latex/markdown.sty new file mode 100644 index 0000000..f60dc23 --- /dev/null +++ b/latex/markdown.sty @@ -0,0 +1,550 @@ +%% +%% This is file `markdown.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% markdown.dtx (with options: `latex') +%% +%% Copyright (C) 2017 Vít Novotný +%% +%% This work may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either version 1.3 +%% of this license or (at your option) any later version. +%% The latest version of this license is in +%% +%% http://www.latex-project.org/lppl.txt +%% +%% and version 1.3 or later is part of all distributions of LaTeX +%% version 2005/12/01 or later. +%% +%% This work has the LPPL maintenance status `maintained'. +%% The Current Maintainer of this work is Vít Novotný. +%% +%% Send bug reports, requests for additions and questions +%% either to the GitHub issue tracker at +%% +%% https://github.com/Witiko/markdown/issues +%% +%% or to the e-mail address . +%% +%% MODIFICATION ADVICE: +%% +%% If you want to customize this file, it is best to make a copy of +%% the source file(s) from which it was produced. Use a different +%% name for your copy(ies) and modify the copy(ies); this will ensure +%% that your modifications do not get overwritten when you install a +%% new release of the standard system. You should also ensure that +%% your modified source file does not generate any modified file with +%% the same name as a standard file. +%% +%% You will also need to produce your own, suitably named, .ins file to +%% control the generation of files from your source file; this file +%% should contain your own preambles for the files it generates, not +%% those in the standard .ins files. +%% +%% The names of the source files used are shown above. +%% +\NeedsTeXFormat{LaTeX2e}% +\RequirePackage{keyval} +\RequirePackage{url} +\RequirePackage{graphicx} +\RequirePackage{ifthen} +\RequirePackage{fancyvrb} +\RequirePackage{csvsimple} +\newenvironment{markdown}\relax\relax +\newenvironment{markdown*}[1]\relax\relax +\newcommand\markdownSetup[1]{% + \setkeys{markdownOptions}{#1}}% +\define@key{markdownOptions}{helperScriptFileName}{% + \def\markdownOptionHelperScriptFileName{#1}}% +\define@key{markdownOptions}{inputTempFileName}{% + \def\markdownOptionInputTempFileName{#1}}% +\define@key{markdownOptions}{outputTempFileName}{% + \def\markdownOptionOutputTempFileName{#1}}% +\define@key{markdownOptions}{errorTempFileName}{% + \def\markdownOptionErrorTempFileName{#1}}% +\define@key{markdownOptions}{cacheDir}{% + \def\markdownOptionCacheDir{#1}}% +\define@key{markdownOptions}{outputDir}{% + \def\markdownOptionOutputDir{#1}}% +\define@key{markdownOptions}{blankBeforeBlockquote}[true]{% + \def\markdownOptionBlankBeforeBlockquote{#1}}% +\define@key{markdownOptions}{blankBeforeCodeFence}[true]{% + \def\markdownOptionBlankBeforeCodeFence{#1}}% +\define@key{markdownOptions}{blankBeforeHeading}[true]{% + \def\markdownOptionBlankBeforeHeading{#1}}% +\define@key{markdownOptions}{breakableBlockquotes}[true]{% + \def\markdownOptionBreakableBlockquotes{#1}}% +\define@key{markdownOptions}{citations}[true]{% + \def\markdownOptionCitations{#1}}% +\define@key{markdownOptions}{citationNbsps}[true]{% + \def\markdownOptionCitationNbsps{#1}}% +\define@key{markdownOptions}{contentBlocks}[true]{% + \def\markdownOptionContentBlocks{#1}}% +\define@key{markdownOptions}{codeSpans}[true]{% + \def\markdownOptionCodeSpans{#1}}% +\define@key{markdownOptions}{contentBlocksLanguageMap}{% + \def\markdownOptionContentBlocksLanguageMap{#1}}% +\define@key{markdownOptions}{definitionLists}[true]{% + \def\markdownOptionDefinitionLists{#1}}% +\define@key{markdownOptions}{footnotes}[true]{% + \def\markdownOptionFootnotes{#1}}% +\define@key{markdownOptions}{fencedCode}[true]{% + \def\markdownOptionFencedCode{#1}}% +\define@key{markdownOptions}{hashEnumerators}[true]{% + \def\markdownOptionHashEnumerators{#1}}% +\define@key{markdownOptions}{html}[true]{% + \def\markdownOptionHtml{#1}}% +\define@key{markdownOptions}{hybrid}[true]{% + \def\markdownOptionHybrid{#1}}% +\define@key{markdownOptions}{inlineFootnotes}[true]{% + \def\markdownOptionInlineFootnotes{#1}}% +\define@key{markdownOptions}{preserveTabs}[true]{% + \def\markdownOptionPreserveTabs{#1}}% +\define@key{markdownOptions}{smartEllipses}[true]{% + \def\markdownOptionSmartEllipses{#1}}% +\define@key{markdownOptions}{startNumber}[true]{% + \def\markdownOptionStartNumber{#1}}% +\define@key{markdownOptions}{tightLists}[true]{% + \def\markdownOptionTightLists{#1}}% +\define@key{markdownOptions}{underscores}[true]{% + \def\markdownOptionUnderscores{#1}}% +\define@key{markdownRenderers}{interblockSeparator}{% + \renewcommand\markdownRendererInterblockSeparator{#1}}% +\define@key{markdownRenderers}{lineBreak}{% + \renewcommand\markdownRendererLineBreak{#1}}% +\define@key{markdownRenderers}{ellipsis}{% + \renewcommand\markdownRendererEllipsis{#1}}% +\define@key{markdownRenderers}{nbsp}{% + \renewcommand\markdownRendererNbsp{#1}}% +\define@key{markdownRenderers}{leftBrace}{% + \renewcommand\markdownRendererLeftBrace{#1}}% +\define@key{markdownRenderers}{rightBrace}{% + \renewcommand\markdownRendererRightBrace{#1}}% +\define@key{markdownRenderers}{dollarSign}{% + \renewcommand\markdownRendererDollarSign{#1}}% +\define@key{markdownRenderers}{percentSign}{% + \renewcommand\markdownRendererPercentSign{#1}}% +\define@key{markdownRenderers}{ampersand}{% + \renewcommand\markdownRendererAmpersand{#1}}% +\define@key{markdownRenderers}{underscore}{% + \renewcommand\markdownRendererUnderscore{#1}}% +\define@key{markdownRenderers}{hash}{% + \renewcommand\markdownRendererHash{#1}}% +\define@key{markdownRenderers}{circumflex}{% + \renewcommand\markdownRendererCircumflex{#1}}% +\define@key{markdownRenderers}{backslash}{% + \renewcommand\markdownRendererBackslash{#1}}% +\define@key{markdownRenderers}{tilde}{% + \renewcommand\markdownRendererTilde{#1}}% +\define@key{markdownRenderers}{pipe}{% + \renewcommand\markdownRendererPipe{#1}}% +\define@key{markdownRenderers}{codeSpan}{% + \renewcommand\markdownRendererCodeSpan[1]{#1}}% +\define@key{markdownRenderers}{link}{% + \renewcommand\markdownRendererLink[4]{#1}}% +\define@key{markdownRenderers}{contentBlock}{% + \renewcommand\markdownRendererContentBlock[4]{#1}}% +\define@key{markdownRenderers}{contentBlockOnlineImage}{% + \renewcommand\markdownRendererContentBlockOnlineImage[4]{#1}}% +\define@key{markdownRenderers}{contentBlockCode}{% + \renewcommand\markdownRendererContentBlockCode[5]{#1}}% +\define@key{markdownRenderers}{image}{% + \renewcommand\markdownRendererImage[4]{#1}}% +\define@key{markdownRenderers}{ulBegin}{% + \renewcommand\markdownRendererUlBegin{#1}}% +\define@key{markdownRenderers}{ulBeginTight}{% + \renewcommand\markdownRendererUlBeginTight{#1}}% +\define@key{markdownRenderers}{ulItem}{% + \renewcommand\markdownRendererUlItem{#1}}% +\define@key{markdownRenderers}{ulItemEnd}{% + \renewcommand\markdownRendererUlItemEnd{#1}}% +\define@key{markdownRenderers}{ulEnd}{% + \renewcommand\markdownRendererUlEnd{#1}}% +\define@key{markdownRenderers}{ulEndTight}{% + \renewcommand\markdownRendererUlEndTight{#1}}% +\define@key{markdownRenderers}{olBegin}{% + \renewcommand\markdownRendererOlBegin{#1}}% +\define@key{markdownRenderers}{olBeginTight}{% + \renewcommand\markdownRendererOlBeginTight{#1}}% +\define@key{markdownRenderers}{olItem}{% + \renewcommand\markdownRendererOlItem{#1}}% +\define@key{markdownRenderers}{olItemWithNumber}{% + \renewcommand\markdownRendererOlItemWithNumber[1]{#1}}% +\define@key{markdownRenderers}{olItemEnd}{% + \renewcommand\markdownRendererOlItemEnd{#1}}% +\define@key{markdownRenderers}{olEnd}{% + \renewcommand\markdownRendererOlEnd{#1}}% +\define@key{markdownRenderers}{olEndTight}{% + \renewcommand\markdownRendererOlEndTight{#1}}% +\define@key{markdownRenderers}{dlBegin}{% + \renewcommand\markdownRendererDlBegin{#1}}% +\define@key{markdownRenderers}{dlBeginTight}{% + \renewcommand\markdownRendererDlBeginTight{#1}}% +\define@key{markdownRenderers}{dlItem}{% + \renewcommand\markdownRendererDlItem[1]{#1}}% +\define@key{markdownRenderers}{dlItemEnd}{% + \renewcommand\markdownRendererDlItemEnd{#1}}% +\define@key{markdownRenderers}{dlDefinitionBegin}{% + \renewcommand\markdownRendererDlDefinitionBegin{#1}}% +\define@key{markdownRenderers}{dlDefinitionEnd}{% + \renewcommand\markdownRendererDlDefinitionEnd{#1}}% +\define@key{markdownRenderers}{dlEnd}{% + \renewcommand\markdownRendererDlEnd{#1}}% +\define@key{markdownRenderers}{dlEndTight}{% + \renewcommand\markdownRendererDlEndTight{#1}}% +\define@key{markdownRenderers}{emphasis}{% + \renewcommand\markdownRendererEmphasis[1]{#1}}% +\define@key{markdownRenderers}{strongEmphasis}{% + \renewcommand\markdownRendererStrongEmphasis[1]{#1}}% +\define@key{markdownRenderers}{blockQuoteBegin}{% + \renewcommand\markdownRendererBlockQuoteBegin{#1}}% +\define@key{markdownRenderers}{blockQuoteEnd}{% + \renewcommand\markdownRendererBlockQuoteEnd{#1}}% +\define@key{markdownRenderers}{inputVerbatim}{% + \renewcommand\markdownRendererInputVerbatim[1]{#1}}% +\define@key{markdownRenderers}{inputFencedCode}{% + \renewcommand\markdownRendererInputFencedCode[2]{#1}}% +\define@key{markdownRenderers}{headingOne}{% + \renewcommand\markdownRendererHeadingOne[1]{#1}}% +\define@key{markdownRenderers}{headingTwo}{% + \renewcommand\markdownRendererHeadingTwo[1]{#1}}% +\define@key{markdownRenderers}{headingThree}{% + \renewcommand\markdownRendererHeadingThree[1]{#1}}% +\define@key{markdownRenderers}{headingFour}{% + \renewcommand\markdownRendererHeadingFour[1]{#1}}% +\define@key{markdownRenderers}{headingFive}{% + \renewcommand\markdownRendererHeadingFive[1]{#1}}% +\define@key{markdownRenderers}{headingSix}{% + \renewcommand\markdownRendererHeadingSix[1]{#1}}% +\define@key{markdownRenderers}{horizontalRule}{% + \renewcommand\markdownRendererHorizontalRule{#1}}% +\define@key{markdownRenderers}{footnote}{% + \renewcommand\markdownRendererFootnote[1]{#1}}% +\define@key{markdownRenderers}{cite}{% + \renewcommand\markdownRendererCite[1]{#1}}% +\define@key{markdownRenderers}{textCite}{% + \renewcommand\markdownRendererTextCite[1]{#1}}% +\define@key{markdownRendererPrototypes}{interblockSeparator}{% + \renewcommand\markdownRendererInterblockSeparatorPrototype{#1}}% +\define@key{markdownRendererPrototypes}{lineBreak}{% + \renewcommand\markdownRendererLineBreakPrototype{#1}}% +\define@key{markdownRendererPrototypes}{ellipsis}{% + \renewcommand\markdownRendererEllipsisPrototype{#1}}% +\define@key{markdownRendererPrototypes}{nbsp}{% + \renewcommand\markdownRendererNbspPrototype{#1}}% +\define@key{markdownRendererPrototypes}{leftBrace}{% + \renewcommand\markdownRendererLeftBracePrototype{#1}}% +\define@key{markdownRendererPrototypes}{rightBrace}{% + \renewcommand\markdownRendererRightBracePrototype{#1}}% +\define@key{markdownRendererPrototypes}{dollarSign}{% + \renewcommand\markdownRendererDollarSignPrototype{#1}}% +\define@key{markdownRendererPrototypes}{percentSign}{% + \renewcommand\markdownRendererPercentSignPrototype{#1}}% +\define@key{markdownRendererPrototypes}{ampersand}{% + \renewcommand\markdownRendererAmpersandPrototype{#1}}% +\define@key{markdownRendererPrototypes}{underscore}{% + \renewcommand\markdownRendererUnderscorePrototype{#1}}% +\define@key{markdownRendererPrototypes}{hash}{% + \renewcommand\markdownRendererHashPrototype{#1}}% +\define@key{markdownRendererPrototypes}{circumflex}{% + \renewcommand\markdownRendererCircumflexPrototype{#1}}% +\define@key{markdownRendererPrototypes}{backslash}{% + \renewcommand\markdownRendererBackslashPrototype{#1}}% +\define@key{markdownRendererPrototypes}{tilde}{% + \renewcommand\markdownRendererTildePrototype{#1}}% +\define@key{markdownRendererPrototypes}{pipe}{% + \renewcommand\markdownRendererPipePrototype{#1}}% +\define@key{markdownRendererPrototypes}{codeSpan}{% + \renewcommand\markdownRendererCodeSpanPrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{link}{% + \renewcommand\markdownRendererLinkPrototype[4]{#1}}% +\define@key{markdownRendererPrototypes}{contentBlock}{% + \renewcommand\markdownRendererContentBlockPrototype[4]{#1}}% +\define@key{markdownRendererPrototypes}{contentBlockOnlineImage}{% + \renewcommand\markdownRendererContentBlockOnlineImagePrototype[4]{#1}}% +\define@key{markdownRendererPrototypes}{contentBlockCode}{% + \renewcommand\markdownRendererContentBlockCodePrototype[5]{#1}}% +\define@key{markdownRendererPrototypes}{image}{% + \renewcommand\markdownRendererImagePrototype[4]{#1}}% +\define@key{markdownRendererPrototypes}{ulBegin}{% + \renewcommand\markdownRendererUlBeginPrototype{#1}}% +\define@key{markdownRendererPrototypes}{ulBeginTight}{% + \renewcommand\markdownRendererUlBeginTightPrototype{#1}}% +\define@key{markdownRendererPrototypes}{ulItem}{% + \renewcommand\markdownRendererUlItemPrototype{#1}}% +\define@key{markdownRendererPrototypes}{ulItemEnd}{% + \renewcommand\markdownRendererUlItemEndPrototype{#1}}% +\define@key{markdownRendererPrototypes}{ulEnd}{% + \renewcommand\markdownRendererUlEndPrototype{#1}}% +\define@key{markdownRendererPrototypes}{ulEndTight}{% + \renewcommand\markdownRendererUlEndTightPrototype{#1}}% +\define@key{markdownRendererPrototypes}{olBegin}{% + \renewcommand\markdownRendererOlBeginPrototype{#1}}% +\define@key{markdownRendererPrototypes}{olBeginTight}{% + \renewcommand\markdownRendererOlBeginTightPrototype{#1}}% +\define@key{markdownRendererPrototypes}{olItem}{% + \renewcommand\markdownRendererOlItemPrototype{#1}}% +\define@key{markdownRendererPrototypes}{olItemWithNumber}{% + \renewcommand\markdownRendererOlItemWithNumberPrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{olItemEnd}{% + \renewcommand\markdownRendererOlItemEndPrototype{#1}}% +\define@key{markdownRendererPrototypes}{olEnd}{% + \renewcommand\markdownRendererOlEndPrototype{#1}}% +\define@key{markdownRendererPrototypes}{olEndTight}{% + \renewcommand\markdownRendererOlEndTightPrototype{#1}}% +\define@key{markdownRendererPrototypes}{dlBegin}{% + \renewcommand\markdownRendererDlBeginPrototype{#1}}% +\define@key{markdownRendererPrototypes}{dlBeginTight}{% + \renewcommand\markdownRendererDlBeginTightPrototype{#1}}% +\define@key{markdownRendererPrototypes}{dlItem}{% + \renewcommand\markdownRendererDlItemPrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{dlItemEnd}{% + \renewcommand\markdownRendererDlItemEndPrototype{#1}}% +\define@key{markdownRendererPrototypes}{dlDefinitionBegin}{% + \renewcommand\markdownRendererDlDefinitionBeginPrototype{#1}}% +\define@key{markdownRendererPrototypes}{dlDefinitionEnd}{% + \renewcommand\markdownRendererDlDefinitionEndPrototype{#1}}% +\define@key{markdownRendererPrototypes}{dlEnd}{% + \renewcommand\markdownRendererDlEndPrototype{#1}}% +\define@key{markdownRendererPrototypes}{dlEndTight}{% + \renewcommand\markdownRendererDlEndTightPrototype{#1}}% +\define@key{markdownRendererPrototypes}{emphasis}{% + \renewcommand\markdownRendererEmphasisPrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{strongEmphasis}{% + \renewcommand\markdownRendererStrongEmphasisPrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{blockQuoteBegin}{% + \renewcommand\markdownRendererBlockQuoteBeginPrototype{#1}}% +\define@key{markdownRendererPrototypes}{blockQuoteEnd}{% + \renewcommand\markdownRendererBlockQuoteEndPrototype{#1}}% +\define@key{markdownRendererPrototypes}{inputVerbatim}{% + \renewcommand\markdownRendererInputVerbatimPrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{inputFencedCode}{% + \renewcommand\markdownRendererInputFencedCodePrototype[2]{#1}}% +\define@key{markdownRendererPrototypes}{headingOne}{% + \renewcommand\markdownRendererHeadingOnePrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{headingTwo}{% + \renewcommand\markdownRendererHeadingTwoPrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{headingThree}{% + \renewcommand\markdownRendererHeadingThreePrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{headingFour}{% + \renewcommand\markdownRendererHeadingFourPrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{headingFive}{% + \renewcommand\markdownRendererHeadingFivePrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{headingSix}{% + \renewcommand\markdownRendererHeadingSixPrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{horizontalRule}{% + \renewcommand\markdownRendererHorizontalRulePrototype{#1}}% +\define@key{markdownRendererPrototypes}{footnote}{% + \renewcommand\markdownRendererFootnotePrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{cite}{% + \renewcommand\markdownRendererCitePrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{textCite}{% + \renewcommand\markdownRendererTextCitePrototype[1]{#1}}% +\input markdown +\def\markdownVersionSpace{ }% +\ProvidesPackage{markdown}[\markdownLastModified\markdownVersionSpace v% + \markdownVersion\markdownVersionSpace markdown renderer]% +\renewcommand\markdownInfo[1]{\PackageInfo{markdown}{#1}}% +\renewcommand\markdownWarning[1]{\PackageWarning{markdown}{#1}}% +\renewcommand\markdownError[2]{\PackageError{markdown}{#1}{#2.}}% +\let\markdownInputPlainTeX\markdownInput +\renewcommand\markdownInput[2][]{% + \begingroup + \markdownSetup{#1}% + \markdownInputPlainTeX{#2}% + \endgroup}% +\renewenvironment{markdown}{% + \markdownReadAndConvert@markdown{}}\relax +\renewenvironment{markdown*}[1]{% + \markdownSetup{#1}% + \markdownReadAndConvert@markdown*}\relax +\begingroup + \catcode`\|=0\catcode`\<=1\catcode`\>=2% + \catcode`\\=12|catcode`|{=12|catcode`|}=12% + |gdef|markdownReadAndConvert@markdown#1<% + |markdownReadAndConvert<\end{markdown#1}>% + <|end>>% +|endgroup +\DeclareOption*{% + \expandafter\markdownSetup\expandafter{\CurrentOption}}% +\ProcessOptions\relax +\define@key{markdownOptions}{renderers}{% + \setkeys{markdownRenderers}{#1}% + \def\KV@prefix{KV@markdownOptions@}}% +\define@key{markdownOptions}{rendererPrototypes}{% + \setkeys{markdownRendererPrototypes}{#1}% + \def\KV@prefix{KV@markdownOptions@}}% +\ifx\markdownOptionTightLists\undefined + \@ifclassloaded{beamer}{}{ + \RequirePackage{paralist}} +\else + \ifthenelse{\equal{\markdownOptionTightLists}{false}}{}{ + \RequirePackage{paralist}} +\fi +\@ifpackageloaded{paralist}{ + \markdownSetup{rendererPrototypes={ + ulBeginTight = {\begin{compactitem}}, + ulEndTight = {\end{compactitem}}, + olBeginTight = {\begin{compactenum}}, + olEndTight = {\end{compactenum}}, + dlBeginTight = {\begin{compactdesc}}, + dlEndTight = {\end{compactdesc}}}} +}{ + \markdownSetup{rendererPrototypes={ + ulBeginTight = {\markdownRendererUlBegin}, + ulEndTight = {\markdownRendererUlEnd}, + olBeginTight = {\markdownRendererOlBegin}, + olEndTight = {\markdownRendererOlEnd}, + dlBeginTight = {\markdownRendererDlBegin}, + dlEndTight = {\markdownRendererDlEnd}}}} +\markdownSetup{rendererPrototypes={ + lineBreak = {\\}, + leftBrace = {\textbraceleft}, + rightBrace = {\textbraceright}, + dollarSign = {\textdollar}, + underscore = {\textunderscore}, + circumflex = {\textasciicircum}, + backslash = {\textbackslash}, + tilde = {\textasciitilde}, + pipe = {\textbar}, + codeSpan = {\texttt{#1}}, + link = {#1\footnote{\ifx\empty#4\empty\else#4: + \fi\texttt<\url{#3}\texttt>}}, + contentBlock = {% + \ifthenelse{\equal{#1}{csv}}{% + \begin{table}% + \begin{center}% + \csvautotabular{#3}% + \end{center} + \ifx\empty#4\empty\else + \caption{#4}% + \fi + \label{tab:#1}% + \end{table}}{% + \markdownInput{#3}}}, + image = {% + \begin{figure}% + \begin{center}% + \includegraphics{#3}% + \end{center}% + \ifx\empty#4\empty\else + \caption{#4}% + \fi + \label{fig:#1}% + \end{figure}}, + ulBegin = {\begin{itemize}}, + ulItem = {\item}, + ulEnd = {\end{itemize}}, + olBegin = {\begin{enumerate}}, + olItem = {\item}, + olItemWithNumber = {\item[#1.]}, + olEnd = {\end{enumerate}}, + dlBegin = {\begin{description}}, + dlItem = {\item[#1]}, + dlEnd = {\end{description}}, + emphasis = {\emph{#1}}, + blockQuoteBegin = {\begin{quotation}}, + blockQuoteEnd = {\end{quotation}}, + inputVerbatim = {\VerbatimInput{#1}}, + inputFencedCode = {% + \ifx\relax#2\relax + \VerbatimInput{#1}% + \else + \ifx\minted@jobname\undefined + \ifx\lst@version\undefined + \markdownRendererInputFencedCode{#1}{}% + \else + \lstinputlisting[language=#2]{#1}% + \fi + \else + \inputminted{#2}{#1}% + \fi + \fi}, + horizontalRule = {\noindent\rule[0.5ex]{\linewidth}{1pt}}, + footnote = {\footnote{#1}}}} +\newif\ifmarkdownLATEXStrongEmphasisNested +\markdownLATEXStrongEmphasisNestedfalse +\markdownSetup{rendererPrototypes={ + strongEmphasis = {% + \ifmarkdownLATEXStrongEmphasisNested + \markdownLATEXStrongEmphasisNestedfalse + \textmd{#1}% + \markdownLATEXStrongEmphasisNestedtrue + \else + \markdownLATEXStrongEmphasisNestedtrue + \textbf{#1}% + \markdownLATEXStrongEmphasisNestedfalse + \fi}}} +\ifx\chapter\undefined + \markdownSetup{rendererPrototypes = { + headingOne = {\section{#1}}, + headingTwo = {\subsection{#1}}, + headingThree = {\subsubsection{#1}}, + headingFour = {\paragraph{#1}}, + headingFive = {\subparagraph{#1}}}} +\else + \markdownSetup{rendererPrototypes = { + headingOne = {\chapter{#1}}, + headingTwo = {\section{#1}}, + headingThree = {\subsection{#1}}, + headingFour = {\subsubsection{#1}}, + headingFive = {\paragraph{#1}}, + headingSix = {\subparagraph{#1}}}} +\fi +\newcount\markdownLaTeXCitationsCounter + +\def\markdownLaTeXBasicCitations#1#2#3#4{% + \advance\markdownLaTeXCitationsCounter by 1\relax + \ifx\relax#2\relax\else#2~\fi\cite[#3]{#4}% + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \expandafter\@gobble + \fi\markdownLaTeXBasicCitations} +\let\markdownLaTeXBasicTextCitations\markdownLaTeXBasicCitations + +\def\markdownLaTeXBibLaTeXCitations#1#2#3#4#5{% + \advance\markdownLaTeXCitationsCounter by 1\relax + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \autocites#1[#3][#4]{#5}% + \expandafter\@gobbletwo + \fi\markdownLaTeXBibLaTeXCitations{#1[#3][#4]{#5}}} +\def\markdownLaTeXBibLaTeXTextCitations#1#2#3#4#5{% + \advance\markdownLaTeXCitationsCounter by 1\relax + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \textcites#1[#3][#4]{#5}% + \expandafter\@gobbletwo + \fi\markdownLaTeXBibLaTeXTextCitations{#1[#3][#4]{#5}}} + +\markdownSetup{rendererPrototypes = { + cite = {% + \markdownLaTeXCitationsCounter=1% + \def\markdownLaTeXCitationsTotal{#1}% + \ifx\autocites\undefined + \expandafter + \markdownLaTeXBasicCitations + \else + \expandafter\expandafter\expandafter + \markdownLaTeXBibLaTeXCitations + \expandafter{\expandafter}% + \fi}, + textCite = {% + \markdownLaTeXCitationsCounter=1% + \def\markdownLaTeXCitationsTotal{#1}% + \ifx\textcites\undefined + \expandafter + \markdownLaTeXBasicTextCitations + \else + \expandafter\expandafter\expandafter + \markdownLaTeXBibLaTeXTextCitations + \expandafter{\expandafter}% + \fi}}} +\newcommand\markdownMakeOther{% + \count0=128\relax + \loop + \catcode\count0=11\relax + \advance\count0 by 1\relax + \ifnum\count0<256\repeat}% +\endinput +%% +%% End of file `markdown.sty'. diff --git a/latex/markdown.tex b/latex/markdown.tex new file mode 100644 index 0000000..1e5d461 --- /dev/null +++ b/latex/markdown.tex @@ -0,0 +1,550 @@ +%% +%% This is file `markdown.tex', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% markdown.dtx (with options: `tex') +%% +%% Copyright (C) 2017 Vít Novotný +%% +%% This work may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either version 1.3 +%% of this license or (at your option) any later version. +%% The latest version of this license is in +%% +%% http://www.latex-project.org/lppl.txt +%% +%% and version 1.3 or later is part of all distributions of LaTeX +%% version 2005/12/01 or later. +%% +%% This work has the LPPL maintenance status `maintained'. +%% The Current Maintainer of this work is Vít Novotný. +%% +%% Send bug reports, requests for additions and questions +%% either to the GitHub issue tracker at +%% +%% https://github.com/Witiko/markdown/issues +%% +%% or to the e-mail address . +%% +%% MODIFICATION ADVICE: +%% +%% If you want to customize this file, it is best to make a copy of +%% the source file(s) from which it was produced. Use a different +%% name for your copy(ies) and modify the copy(ies); this will ensure +%% that your modifications do not get overwritten when you install a +%% new release of the standard system. You should also ensure that +%% your modified source file does not generate any modified file with +%% the same name as a standard file. +%% +%% You will also need to produce your own, suitably named, .ins file to +%% control the generation of files from your source file; this file +%% should contain your own preambles for the files it generates, not +%% those in the standard .ins files. +%% +%% The names of the source files used are shown above. +%% +\def\markdownLastModified{2017/09/12}% +\def\markdownVersion{2.5.4}% +\let\markdownBegin\relax +\let\markdownEnd\relax +\let\markdownInput\relax +\def\markdownOptionHelperScriptFileName{\jobname.markdown.lua}% +\def\markdownOptionInputTempFileName{\jobname.markdown.in}% +\def\markdownOptionOutputTempFileName{\jobname.markdown.out}% +\def\markdownOptionErrorTempFileName{\jobname.markdown.err}% +\def\markdownOptionCacheDir{\markdownOptionOutputDir/_markdown_\jobname}% +\def\markdownOptionOutputDir{.}% +\let\markdownOptionBlankBeforeBlockquote\undefined +\let\markdownOptionBlankBeforeCodeFence\undefined +\let\markdownOptionBlankBeforeHeading\undefined +\let\markdownOptionBreakableBlockquotes\undefined +\let\markdownOptionCitations\undefined +\let\markdownOptionCitationNbsps\undefined +\let\markdownOptionContentBlocks\undefined +\let\markdownOptionContentBlocksLanguageMap\undefined +\let\markdownOptionDefinitionLists\undefined +\let\markdownOptionFootnotes\undefined +\let\markdownOptionFencedCode\undefined +\let\markdownOptionHashEnumerators\undefined +\let\markdownOptionHtml\undefined +\let\markdownOptionHybrid\undefined +\let\markdownOptionInlineFootnotes\undefined +\let\markdownOptionPreserveTabs\undefined +\let\markdownOptionSmartEllipses\undefined +\let\markdownOptionStartNumber\undefined +\let\markdownOptionTightLists\undefined +\def\markdownRendererInterblockSeparator{% + \markdownRendererInterblockSeparatorPrototype}% +\def\markdownRendererLineBreak{% + \markdownRendererLineBreakPrototype}% +\def\markdownRendererEllipsis{% + \markdownRendererEllipsisPrototype}% +\def\markdownRendererNbsp{% + \markdownRendererNbspPrototype}% +\def\markdownRendererLeftBrace{% + \markdownRendererLeftBracePrototype}% +\def\markdownRendererRightBrace{% + \markdownRendererRightBracePrototype}% +\def\markdownRendererDollarSign{% + \markdownRendererDollarSignPrototype}% +\def\markdownRendererPercentSign{% + \markdownRendererPercentSignPrototype}% +\def\markdownRendererAmpersand{% + \markdownRendererAmpersandPrototype}% +\def\markdownRendererUnderscore{% + \markdownRendererUnderscorePrototype}% +\def\markdownRendererHash{% + \markdownRendererHashPrototype}% +\def\markdownRendererCircumflex{% + \markdownRendererCircumflexPrototype}% +\def\markdownRendererBackslash{% + \markdownRendererBackslashPrototype}% +\def\markdownRendererTilde{% + \markdownRendererTildePrototype}% +\def\markdownRendererPipe{% + \markdownRendererPipePrototype}% +\def\markdownRendererCodeSpan{% + \markdownRendererCodeSpanPrototype}% +\def\markdownRendererLink{% + \markdownRendererLinkPrototype}% +\def\markdownRendererImage{% + \markdownRendererImagePrototype}% +\def\markdownRendererContentBlock{% + \markdownRendererContentBlockPrototype}% +\def\markdownRendererContentBlockOnlineImage{% + \markdownRendererContentBlockOnlineImagePrototype}% +\def\markdownRendererContentBlockCode{% + \markdownRendererContentBlockCodePrototype}% +\def\markdownRendererUlBegin{% + \markdownRendererUlBeginPrototype}% +\def\markdownRendererUlBeginTight{% + \markdownRendererUlBeginTightPrototype}% +\def\markdownRendererUlItem{% + \markdownRendererUlItemPrototype}% +\def\markdownRendererUlItemEnd{% + \markdownRendererUlItemEndPrototype}% +\def\markdownRendererUlEnd{% + \markdownRendererUlEndPrototype}% +\def\markdownRendererUlEndTight{% + \markdownRendererUlEndTightPrototype}% +\def\markdownRendererOlBegin{% + \markdownRendererOlBeginPrototype}% +\def\markdownRendererOlBeginTight{% + \markdownRendererOlBeginTightPrototype}% +\def\markdownRendererOlItem{% + \markdownRendererOlItemPrototype}% +\def\markdownRendererOlItemEnd{% + \markdownRendererOlItemEndPrototype}% +\def\markdownRendererOlItemWithNumber{% + \markdownRendererOlItemWithNumberPrototype}% +\def\markdownRendererOlEnd{% + \markdownRendererOlEndPrototype}% +\def\markdownRendererOlEndTight{% + \markdownRendererOlEndTightPrototype}% +\def\markdownRendererDlBegin{% + \markdownRendererDlBeginPrototype}% +\def\markdownRendererDlBeginTight{% + \markdownRendererDlBeginTightPrototype}% +\def\markdownRendererDlItem{% + \markdownRendererDlItemPrototype}% +\def\markdownRendererDlItemEnd{% + \markdownRendererDlItemEndPrototype}% +\def\markdownRendererDlDefinitionBegin{% + \markdownRendererDlDefinitionBeginPrototype}% +\def\markdownRendererDlDefinitionEnd{% + \markdownRendererDlDefinitionEndPrototype}% +\def\markdownRendererDlEnd{% + \markdownRendererDlEndPrototype}% +\def\markdownRendererDlEndTight{% + \markdownRendererDlEndTightPrototype}% +\def\markdownRendererEmphasis{% + \markdownRendererEmphasisPrototype}% +\def\markdownRendererStrongEmphasis{% + \markdownRendererStrongEmphasisPrototype}% +\def\markdownRendererBlockQuoteBegin{% + \markdownRendererBlockQuoteBeginPrototype}% +\def\markdownRendererBlockQuoteEnd{% + \markdownRendererBlockQuoteEndPrototype}% +\def\markdownRendererInputVerbatim{% + \markdownRendererInputVerbatimPrototype}% +\def\markdownRendererInputFencedCode{% + \markdownRendererInputFencedCodePrototype}% +\def\markdownRendererHeadingOne{% + \markdownRendererHeadingOnePrototype}% +\def\markdownRendererHeadingTwo{% + \markdownRendererHeadingTwoPrototype}% +\def\markdownRendererHeadingThree{% + \markdownRendererHeadingThreePrototype}% +\def\markdownRendererHeadingFour{% + \markdownRendererHeadingFourPrototype}% +\def\markdownRendererHeadingFive{% + \markdownRendererHeadingFivePrototype}% +\def\markdownRendererHeadingSix{% + \markdownRendererHeadingSixPrototype}% +\def\markdownRendererHorizontalRule{% + \markdownRendererHorizontalRulePrototype}% +\def\markdownRendererFootnote{% + \markdownRendererFootnotePrototype}% +\def\markdownRendererCite{% + \markdownRendererCitePrototype}% +\def\markdownRendererTextCite{% + \markdownRendererTextCitePrototype}% +\def\markdownRendererInterblockSeparatorPrototype{}% +\def\markdownRendererLineBreakPrototype{}% +\def\markdownRendererEllipsisPrototype{}% +\def\markdownRendererNbspPrototype{}% +\def\markdownRendererLeftBracePrototype{}% +\def\markdownRendererRightBracePrototype{}% +\def\markdownRendererDollarSignPrototype{}% +\def\markdownRendererPercentSignPrototype{}% +\def\markdownRendererAmpersandPrototype{}% +\def\markdownRendererUnderscorePrototype{}% +\def\markdownRendererHashPrototype{}% +\def\markdownRendererCircumflexPrototype{}% +\def\markdownRendererBackslashPrototype{}% +\def\markdownRendererTildePrototype{}% +\def\markdownRendererPipePrototype{}% +\def\markdownRendererCodeSpanPrototype#1{}% +\def\markdownRendererLinkPrototype#1#2#3#4{}% +\def\markdownRendererImagePrototype#1#2#3#4{}% +\def\markdownRendererContentBlockPrototype#1#2#3#4{}% +\def\markdownRendererContentBlockOnlineImagePrototype#1#2#3#4{}% +\def\markdownRendererContentBlockCodePrototype#1#2#3#4{}% +\def\markdownRendererUlBeginPrototype{}% +\def\markdownRendererUlBeginTightPrototype{}% +\def\markdownRendererUlItemPrototype{}% +\def\markdownRendererUlItemEndPrototype{}% +\def\markdownRendererUlEndPrototype{}% +\def\markdownRendererUlEndTightPrototype{}% +\def\markdownRendererOlBeginPrototype{}% +\def\markdownRendererOlBeginTightPrototype{}% +\def\markdownRendererOlItemPrototype{}% +\def\markdownRendererOlItemWithNumberPrototype#1{}% +\def\markdownRendererOlItemEndPrototype{}% +\def\markdownRendererOlEndPrototype{}% +\def\markdownRendererOlEndTightPrototype{}% +\def\markdownRendererDlBeginPrototype{}% +\def\markdownRendererDlBeginTightPrototype{}% +\def\markdownRendererDlItemPrototype#1{}% +\def\markdownRendererDlItemEndPrototype{}% +\def\markdownRendererDlDefinitionBeginPrototype{}% +\def\markdownRendererDlDefinitionEndPrototype{}% +\def\markdownRendererDlEndPrototype{}% +\def\markdownRendererDlEndTightPrototype{}% +\def\markdownRendererEmphasisPrototype#1{}% +\def\markdownRendererStrongEmphasisPrototype#1{}% +\def\markdownRendererBlockQuoteBeginPrototype{}% +\def\markdownRendererBlockQuoteEndPrototype{}% +\def\markdownRendererInputVerbatimPrototype#1{}% +\def\markdownRendererInputFencedCodePrototype#1#2{}% +\def\markdownRendererHeadingOnePrototype#1{}% +\def\markdownRendererHeadingTwoPrototype#1{}% +\def\markdownRendererHeadingThreePrototype#1{}% +\def\markdownRendererHeadingFourPrototype#1{}% +\def\markdownRendererHeadingFivePrototype#1{}% +\def\markdownRendererHeadingSixPrototype#1{}% +\def\markdownRendererHorizontalRulePrototype{}% +\def\markdownRendererFootnotePrototype#1{}% +\def\markdownRendererCitePrototype#1{}% +\def\markdownRendererTextCitePrototype#1{}% +\def\markdownInfo#1{}% +\def\markdownWarning#1{}% +\def\markdownError#1#2{}% +\let\markdownMakeOther\relax +\let\markdownReadAndConvert\relax +\begingroup + \catcode`\|=0\catcode`\\=12% + |gdef|markdownBegin{% + |markdownReadAndConvert{\markdownEnd}% + {|markdownEnd}}% +|endgroup +\ifx\markdownMode\undefined + \ifx\directlua\undefined + \def\markdownMode{0}% + \else + \def\markdownMode{2}% + \fi +\fi +\def\markdownLuaRegisterIBCallback#1{\relax}% +\def\markdownLuaUnregisterIBCallback#1{\relax}% +\def\markdownInfo#1{% + \immediate\write-1{(l.\the\inputlineno) markdown.tex info: #1.}}% +\def\markdownWarning#1{% + \immediate\write16{(l.\the\inputlineno) markdown.tex warning: #1}}% +\def\markdownError#1#2{% + \errhelp{#2.}% + \errmessage{(l.\the\inputlineno) markdown.tex error: #1}}% +\def\markdownRendererInterblockSeparatorPrototype{\par}% +\def\markdownRendererLineBreakPrototype{\hfil\break}% +\let\markdownRendererEllipsisPrototype\dots +\def\markdownRendererNbspPrototype{~}% +\def\markdownRendererLeftBracePrototype{\char`{}% +\def\markdownRendererRightBracePrototype{\char`}}% +\def\markdownRendererDollarSignPrototype{\char`$}% +\def\markdownRendererPercentSignPrototype{\char`\%}% +\def\markdownRendererAmpersandPrototype{\char`&}% +\def\markdownRendererUnderscorePrototype{\char`_}% +\def\markdownRendererHashPrototype{\char`\#}% +\def\markdownRendererCircumflexPrototype{\char`^}% +\def\markdownRendererBackslashPrototype{\char`\\}% +\def\markdownRendererTildePrototype{\char`~}% +\def\markdownRendererPipePrototype{|}% +\def\markdownRendererCodeSpanPrototype#1{{\tt#1}}% +\def\markdownRendererLinkPrototype#1#2#3#4{#2}% +\def\markdownRendererContentBlockPrototype#1#2#3#4{% + \markdownInput{#3}}% +\def\markdownRendererContentBlockOnlineImagePrototype{% + \markdownRendererImage}% +\def\markdownRendererContentBlockCodePrototype#1#2#3#4#5{% + \markdownRendererInputFencedCode{#3}{#2}}% +\def\markdownRendererImagePrototype#1#2#3#4{#2}% +\def\markdownRendererUlBeginPrototype{}% +\def\markdownRendererUlBeginTightPrototype{}% +\def\markdownRendererUlItemPrototype{}% +\def\markdownRendererUlItemEndPrototype{}% +\def\markdownRendererUlEndPrototype{}% +\def\markdownRendererUlEndTightPrototype{}% +\def\markdownRendererOlBeginPrototype{}% +\def\markdownRendererOlBeginTightPrototype{}% +\def\markdownRendererOlItemPrototype{}% +\def\markdownRendererOlItemWithNumberPrototype#1{}% +\def\markdownRendererOlItemEndPrototype{}% +\def\markdownRendererOlEndPrototype{}% +\def\markdownRendererOlEndTightPrototype{}% +\def\markdownRendererDlBeginPrototype{}% +\def\markdownRendererDlBeginTightPrototype{}% +\def\markdownRendererDlItemPrototype#1{#1}% +\def\markdownRendererDlItemEndPrototype{}% +\def\markdownRendererDlDefinitionBeginPrototype{}% +\def\markdownRendererDlDefinitionEndPrototype{\par}% +\def\markdownRendererDlEndPrototype{}% +\def\markdownRendererDlEndTightPrototype{}% +\def\markdownRendererEmphasisPrototype#1{{\it#1}}% +\def\markdownRendererStrongEmphasisPrototype#1{{\bf#1}}% +\def\markdownRendererBlockQuoteBeginPrototype{\par\begingroup\it}% +\def\markdownRendererBlockQuoteEndPrototype{\endgroup\par}% +\def\markdownRendererInputVerbatimPrototype#1{% + \par{\tt\input"#1"\relax}\par}% +\def\markdownRendererInputFencedCodePrototype#1#2{% + \markdownRendererInputVerbatimPrototype{#1}}% +\def\markdownRendererHeadingOnePrototype#1{#1}% +\def\markdownRendererHeadingTwoPrototype#1{#1}% +\def\markdownRendererHeadingThreePrototype#1{#1}% +\def\markdownRendererHeadingFourPrototype#1{#1}% +\def\markdownRendererHeadingFivePrototype#1{#1}% +\def\markdownRendererHeadingSixPrototype#1{#1}% +\def\markdownRendererHorizontalRulePrototype{}% +\def\markdownRendererFootnotePrototype#1{#1}% +\def\markdownRendererCitePrototype#1{}% +\def\markdownRendererTextCitePrototype#1{}% +\def\markdownLuaOptions{{% +\ifx\markdownOptionBlankBeforeBlockquote\undefined\else + blankBeforeBlockquote = \markdownOptionBlankBeforeBlockquote, +\fi +\ifx\markdownOptionBlankBeforeCodeFence\undefined\else + blankBeforeCodeFence = \markdownOptionBlankBeforeCodeFence, +\fi +\ifx\markdownOptionBlankBeforeHeading\undefined\else + blankBeforeHeading = \markdownOptionBlankBeforeHeading, +\fi +\ifx\markdownOptionBreakableBlockquotes\undefined\else + breakableBlockquotes = \markdownOptionBreakableBlockquotes, +\fi + cacheDir = "\markdownOptionCacheDir", +\ifx\markdownOptionCitations\undefined\else + citations = \markdownOptionCitations, +\fi +\ifx\markdownOptionCitationNbsps\undefined\else + citationNbsps = \markdownOptionCitationNbsps, +\fi +\ifx\markdownOptionCodeSpans\undefined\else + codeSpans = \markdownOptionCodeSpans, +\fi +\ifx\markdownOptionContentBlocks\undefined\else + contentBlocks = \markdownOptionContentBlocks, +\fi +\ifx\markdownOptionContentBlocksLanguageMap\undefined\else + contentBlocksLanguageMap = + "\markdownOptionContentBlocksLanguageMap", +\fi +\ifx\markdownOptionDefinitionLists\undefined\else + definitionLists = \markdownOptionDefinitionLists, +\fi +\ifx\markdownOptionFootnotes\undefined\else + footnotes = \markdownOptionFootnotes, +\fi +\ifx\markdownOptionFencedCode\undefined\else + fencedCode = \markdownOptionFencedCode, +\fi +\ifx\markdownOptionHashEnumerators\undefined\else + hashEnumerators = \markdownOptionHashEnumerators, +\fi +\ifx\markdownOptionHtml\undefined\else + html = \markdownOptionHtml, +\fi +\ifx\markdownOptionHybrid\undefined\else + hybrid = \markdownOptionHybrid, +\fi +\ifx\markdownOptionInlineFootnotes\undefined\else + inlineFootnotes = \markdownOptionInlineFootnotes, +\fi + outputDir = "\markdownOptionOutputDir", +\ifx\markdownOptionPreserveTabs\undefined\else + preserveTabs = \markdownOptionPreserveTabs, +\fi +\ifx\markdownOptionSmartEllipses\undefined\else + smartEllipses = \markdownOptionSmartEllipses, +\fi +\ifx\markdownOptionStartNumber\undefined\else + startNumber = \markdownOptionStartNumber, +\fi +\ifx\markdownOptionTightLists\undefined\else + tightLists = \markdownOptionTightLists, +\fi +\ifx\markdownOptionUnderscores\undefined\else + underscores = \markdownOptionUnderscores, +\fi} +}% +\def\markdownPrepare{% +local lfs = require("lfs") +local cacheDir = "\markdownOptionCacheDir" +if lfs.isdir(cacheDir) == true then else + assert(lfs.mkdir(cacheDir)) +end +local md = require("markdown") +local convert = md.new(\markdownLuaOptions) +}% +\csname newread\endcsname\markdownInputFileStream +\csname newwrite\endcsname\markdownOutputFileStream +\begingroup + \catcode`\^^I=12% + \gdef\markdownReadAndConvertTab{^^I}% +\endgroup +\begingroup + \catcode`\^^M=13% + \catcode`\^^I=13% + \catcode`|=0% + \catcode`\\=12% + |gdef|markdownReadAndConvert#1#2{% + |begingroup% + |immediate|openout|markdownOutputFileStream% + |markdownOptionInputTempFileName% + |markdownInfo{Buffering markdown input into the temporary % + input file "|markdownOptionInputTempFileName" and scanning % + for the closing token sequence "#1"}% + |def|do##1{|catcode`##1=12}|dospecials% + |catcode`| =12% + |markdownMakeOther% + |def|markdownReadAndConvertProcessLine##1#1##2#1##3|relax{% + |ifx|relax##3|relax% + |immediate|write|markdownOutputFileStream{##1}% + |else% + |def^^M{% + |markdownInfo{The ending token sequence was found}% + |immediate|closeout|markdownOutputFileStream% + |endgroup% + |markdownInput|markdownOptionInputTempFileName% + #2}% + |fi% + ^^M}% + |catcode`|^^I=13% + |def^^I{|markdownReadAndConvertTab}% + |catcode`|^^M=13% + |def^^M##1^^M{% + |def^^M####1^^M{% + |markdownReadAndConvertProcessLine####1#1#1|relax}% + ^^M}% + ^^M}% +|endgroup +\ifnum\markdownMode<2\relax +\ifnum\markdownMode=0\relax + \markdownInfo{Using mode 0: Shell escape via write18}% +\else + \markdownInfo{Using mode 1: Shell escape via os.execute}% +\fi +\ifx\pdfshellescape\undefined + \ifx\shellescape\undefined + \ifnum\markdownMode=0\relax + \def\markdownExecuteShellEscape{1}% + \else + \def\markdownExecuteShellEscape{% + \directlua{tex.sprint(status.shell_escape or "1")}}% + \fi + \else + \let\markdownExecuteShellEscape\shellescape + \fi +\else + \let\markdownExecuteShellEscape\pdfshellescape +\fi +\ifnum\markdownMode=0\relax + \def\markdownExecuteDirect#1{\immediate\write18{#1}}% +\else + \def\markdownExecuteDirect#1{% + \directlua{os.execute("\luaescapestring{#1}")}}% +\fi +\def\markdownExecute#1{% + \ifnum\markdownExecuteShellEscape=1\relax + \markdownExecuteDirect{#1}% + \else + \markdownError{I can not access the shell}{Either run the TeX + compiler with the --shell-escape or the --enable-write18 flag, + or set shell_escape=t in the texmf.cnf file}% + \fi}% +\begingroup + \catcode`|=0% + \catcode`\\=12% + |gdef|markdownLuaExecute#1{% + |immediate|openout|markdownOutputFileStream=% + |markdownOptionHelperScriptFileName + |markdownInfo{Writing a helper Lua script to the file + "|markdownOptionHelperScriptFileName"}% + |immediate|write|markdownOutputFileStream{% + local ran_ok, error = pcall(function() + local kpse = require('kpse') + kpse.set_program_name('luatex') + #1 + end) + if not ran_ok then + local file = io.open("% + |markdownOptionOutputDir + /|markdownOptionErrorTempFileName", "w") + if file then + file:write(error .. "\n") + file:close() + end + print('\\markdownError{An error was encountered while executing + Lua code}{For further clues, examine the file + "|markdownOptionOutputDir + /|markdownOptionErrorTempFileName"}') + end}% + |immediate|closeout|markdownOutputFileStream + |markdownInfo{Executing a helper Lua script from the file + "|markdownOptionHelperScriptFileName" and storing the result in the + file "|markdownOptionOutputTempFileName"}% + |markdownExecute{texlua "|markdownOptionOutputDir + /|markdownOptionHelperScriptFileName" > % + "|markdownOptionOutputDir + /|markdownOptionOutputTempFileName"}% + |input|markdownOptionOutputTempFileName|relax}% +|endgroup +\else +\markdownInfo{Using mode 2: Direct Lua access}% +\def\markdownLuaExecute#1{\directlua{local print = tex.print #1}}% +\fi +\begingroup + \catcode`|=0% + \catcode`\\=12% + |gdef|markdownInput#1{% + |markdownInfo{Including markdown document "#1"}% + |openin|markdownInputFileStream#1 + |closein|markdownInputFileStream + |markdownLuaExecute{% + |markdownPrepare + local input = assert(io.open("#1","r")):read("*a") + print(convert(input:gsub("\r\n?", "\n")))}}% +|endgroup +\endinput +%% +%% End of file `markdown.tex'. diff --git a/latex/t-markdown.tex b/latex/t-markdown.tex new file mode 100644 index 0000000..a65798a --- /dev/null +++ b/latex/t-markdown.tex @@ -0,0 +1,161 @@ +%% +%% This is file `t-markdown.tex', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% markdown.dtx (with options: `context') +%% +%% Copyright (C) 2017 Vít Novotný +%% +%% This work may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either version 1.3 +%% of this license or (at your option) any later version. +%% The latest version of this license is in +%% +%% http://www.latex-project.org/lppl.txt +%% +%% and version 1.3 or later is part of all distributions of LaTeX +%% version 2005/12/01 or later. +%% +%% This work has the LPPL maintenance status `maintained'. +%% The Current Maintainer of this work is Vít Novotný. +%% +%% Send bug reports, requests for additions and questions +%% either to the GitHub issue tracker at +%% +%% https://github.com/Witiko/markdown/issues +%% +%% or to the e-mail address . +%% +%% MODIFICATION ADVICE: +%% +%% If you want to customize this file, it is best to make a copy of +%% the source file(s) from which it was produced. Use a different +%% name for your copy(ies) and modify the copy(ies); this will ensure +%% that your modifications do not get overwritten when you install a +%% new release of the standard system. You should also ensure that +%% your modified source file does not generate any modified file with +%% the same name as a standard file. +%% +%% You will also need to produce your own, suitably named, .ins file to +%% control the generation of files from your source file; this file +%% should contain your own preambles for the files it generates, not +%% those in the standard .ins files. +%% +%% The names of the source files used are shown above. +%% +\writestatus{loading}{ConTeXt User Module / markdown}% +\unprotect +\let\startmarkdown\relax +\let\stopmarkdown\relax +\def\dospecials{\do\ \do\\\do\{\do\}\do\$\do\&% + \do\#\do\^\do\_\do\%\do\~}% +\input markdown +\def\markdownMakeOther{% + \count0=128\relax + \loop + \catcode\count0=11\relax + \advance\count0 by 1\relax + \ifnum\count0<256\repeat + \catcode`|=12}% +\def\markdownInfo#1{\writestatus{markdown}{#1.}}% +\def\markdownWarning#1{\writestatus{markdown\space warn}{#1.}}% +\begingroup + \catcode`\|=0% + \catcode`\\=12% + |gdef|startmarkdown{% + |markdownReadAndConvert{\stopmarkdown}% + {|stopmarkdown}}% +|endgroup +\def\markdownRendererLineBreakPrototype{\blank}% +\def\markdownRendererLeftBracePrototype{\textbraceleft}% +\def\markdownRendererRightBracePrototype{\textbraceright}% +\def\markdownRendererDollarSignPrototype{\textdollar}% +\def\markdownRendererPercentSignPrototype{\percent}% +\def\markdownRendererUnderscorePrototype{\textunderscore}% +\def\markdownRendererCircumflexPrototype{\textcircumflex}% +\def\markdownRendererBackslashPrototype{\textbackslash}% +\def\markdownRendererTildePrototype{\textasciitilde}% +\def\markdownRendererPipePrototype{\char`|}% +\def\markdownRendererLinkPrototype#1#2#3#4{% + \useURL[#1][#3][][#4]#1\footnote[#1]{\ifx\empty#4\empty\else#4: + \fi\tt<\hyphenatedurl{#3}>}}% +\usemodule[database] +\defineseparatedlist + [MarkdownConTeXtCSV] + [separator={,}, + before=\bTABLE,after=\eTABLE, + first=\bTR,last=\eTR, + left=\bTD,right=\eTD] +\def\markdownConTeXtCSV{csv} +\def\markdownRendererContentBlockPrototype#1#2#3#4{% + \def\markdownConTeXtCSV@arg{#1}% +\ifx\markdownConTeXtCSV@arg\markdownConTeXtCSV + \placetable[][tab:#1]{#4}{% + \processseparatedfile[MarkdownConTeXtCSV][#3]}% +\else +\markdownInput{#3}% +\fi}% +\def\markdownRendererImagePrototype#1#2#3#4{% + \placefigure[][fig:#1]{#4}{\externalfigure[#3]}}% +\def\markdownRendererUlBeginPrototype{\startitemize}% +\def\markdownRendererUlBeginTightPrototype{\startitemize[packed]}% +\def\markdownRendererUlItemPrototype{\item}% +\def\markdownRendererUlEndPrototype{\stopitemize}% +\def\markdownRendererUlEndTightPrototype{\stopitemize}% +\def\markdownRendererOlBeginPrototype{\startitemize[n]}% +\def\markdownRendererOlBeginTightPrototype{\startitemize[packed,n]}% +\def\markdownRendererOlItemPrototype{\item}% +\def\markdownRendererOlItemWithNumberPrototype#1{\sym{#1.}}% +\def\markdownRendererOlEndPrototype{\stopitemize}% +\def\markdownRendererOlEndTightPrototype{\stopitemize}% +\definedescription + [MarkdownConTeXtDlItemPrototype] + [location=hanging, + margin=standard, + headstyle=bold]% +\definestartstop + [MarkdownConTeXtDlPrototype] + [before=\blank, + after=\blank]% +\definestartstop + [MarkdownConTeXtDlTightPrototype] + [before=\blank\startpacked, + after=\stoppacked\blank]% +\def\markdownRendererDlBeginPrototype{% + \startMarkdownConTeXtDlPrototype}% +\def\markdownRendererDlBeginTightPrototype{% + \startMarkdownConTeXtDlTightPrototype}% +\def\markdownRendererDlItemPrototype#1{% + \startMarkdownConTeXtDlItemPrototype{#1}}% +\def\markdownRendererDlItemEndPrototype{% + \stopMarkdownConTeXtDlItemPrototype}% +\def\markdownRendererDlEndPrototype{% + \stopMarkdownConTeXtDlPrototype}% +\def\markdownRendererDlEndTightPrototype{% + \stopMarkdownConTeXtDlTightPrototype}% +\def\markdownRendererEmphasisPrototype#1{{\em#1}}% +\def\markdownRendererStrongEmphasisPrototype#1{{\bf#1}}% +\def\markdownRendererBlockQuoteBeginPrototype{\startquotation}% +\def\markdownRendererBlockQuoteEndPrototype{\stopquotation}% +\def\markdownRendererInputVerbatimPrototype#1{\typefile{#1}}% +\def\markdownRendererInputFencedCodePrototype#1#2{% + \ifx\relax#2\relax + \typefile{#1}% + \else + \typefile[#2][]{#1}% + \fi}% +\def\markdownRendererHeadingOnePrototype#1{\chapter{#1}}% +\def\markdownRendererHeadingTwoPrototype#1{\section{#1}}% +\def\markdownRendererHeadingThreePrototype#1{\subsection{#1}}% +\def\markdownRendererHeadingFourPrototype#1{\subsubsection{#1}}% +\def\markdownRendererHeadingFivePrototype#1{\subsubsubsection{#1}}% +\def\markdownRendererHeadingSixPrototype#1{\subsubsubsubsection{#1}}% +\def\markdownRendererHorizontalRulePrototype{% + \blackrule[height=1pt, width=\hsize]}% +\def\markdownRendererFootnotePrototype#1{\footnote{#1}}% +\stopmodule\protect +\endinput +%% +%% End of file `t-markdown.tex'. diff --git a/package.json b/package.json index 823f0d2..5727b46 100644 --- a/package.json +++ b/package.json @@ -3,11 +3,14 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "build:a4": "./scripts/build-latex.sh a4", + "build:a5": "./scripts/build-latex.sh a5", + "build:a6": "./scripts/build-latex.sh a6" }, "dependencies": { + "@react-three/fiber": "^7.0.6", "next": "^11.1.0", - "particlesjs": "^2.2.3", "react": "^17.0.2", "react-dom": "^17.0.2", "styled-components": "^5.3.1", diff --git a/pages/index.tsx b/pages/index.tsx index 9f9e038..d872ff0 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -3,6 +3,10 @@ import Head from 'next/head'; import Background from '../components/Background'; import Me from '../components/Me'; import Social from '../components/Social'; +import htbLogo from '../public/images/logos/htb.svg'; +import githubLogo from '../public/images/logos/github.svg'; +import linkedinLogo from '../public/images/logos/linkedin.svg'; +import stackOverflowLogo from '../public/images/logos/stackoverflow.svg'; const Frontpage: React.FC<{}> = () => { return ( @@ -19,19 +23,19 @@ const Frontpage: React.FC<{}> = () => { sites={[{ title: 'Github', link: 'https://github.com/morten-olsen', - logo: 'github.svg', + logo: githubLogo, }, { title: 'HackTheBox', link: 'https://app.hackthebox.eu/profile/174098', - logo: 'htb.svg', + logo: htbLogo, }, { title: 'Stack Overflow', link: 'https://stackoverflow.com/users/1689055/morten-olsen', - logo: 'stackoverflow.svg', + logo: stackOverflowLogo, }, { title: 'Linkedin', link: 'https://www.linkedin.com/in/mortenolsendk', - logo: 'linkedin.svg', + logo: linkedinLogo, }]} /> diff --git a/scripts/build-latex.sh b/scripts/build-latex.sh new file mode 100755 index 0000000..308139c --- /dev/null +++ b/scripts/build-latex.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +FORMAT=$1; shift + +docker run \ + --user "$UID:$GID" \ + --net=none \ + -v $(pwd):/var/texlive \ + blang/latex:ubuntu + lualatex "latex/$FORMAT.tex" diff --git a/scripts/update-readme.js b/scripts/update-readme.js new file mode 100644 index 0000000..b7e5607 --- /dev/null +++ b/scripts/update-readme.js @@ -0,0 +1,55 @@ +const data = require('../data.json'); + +const sections = { + info: data => ` +## Basic Info +${data.info.map(d => `* **${d.name}**: ${d.value}`).join('\n')} + `, + text: data => ` +## ${data.title} + +${data.content} + `, + skills: data => ` +## ${data.title} + +${data.description} + +${data.skills.map(d => `* **${d.title}**: ${d.level} `).join('\n')} + `, + experiences: data => ` +## ${data.title} + +${data.positions.map(d => ` +### [${d.company.name}](${d.company.webpage}) +**${d.title}** _(${d.startDate} - ${d.endDate})_ + +${d.description} + +`).join('')} + `, + projects: data => ` +## ${data.title} + +${data.description} + +${data.projects.map(d => ` +**[${d.name}](https://${d.url})** +_${d.tagline}_ + +${d.description} + +`).join('\n')} + `, +}; + +let document = ` + +# Curriculum Vitae + +**[Download the latest version](https://github.com/morten-olsen/curriculum-vitae/releases/latest)** + +${data.map(d => sections[d.type](d.data)).join('\n------\n')} +`; + +console.log(document); diff --git a/yarn.lock b/yarn.lock index 94610fb..45895ca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -107,6 +107,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.13.10": + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.3.tgz#2e1c2880ca118e5b2f9988322bd8a7656a32502b" + integrity sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4" @@ -225,6 +232,22 @@ dependencies: "@napi-rs/triples" "^1.0.3" +"@react-three/fiber@^7.0.6": + version "7.0.6" + resolved "https://registry.yarnpkg.com/@react-three/fiber/-/fiber-7.0.6.tgz#faa5aa5d496ae778a89fe2d3f503428a0e3c841b" + integrity sha512-GSMmnk66B/xGGfbSj5lGiZCxGQD0i8rm0Bt/Xp6TD2b9cYe2Lxb2wegU04zIeN89aoUYMHXhL1GNXsZvvOjfUA== + dependencies: + "@babel/runtime" "^7.13.10" + react-merge-refs "^1.1.0" + react-reconciler "^0.26.2" + react-three-fiber "0.0.0-deprecated" + react-use-measure "^2.0.4" + resize-observer-polyfill "^1.5.1" + scheduler "^0.20.2" + use-asset "^1.0.4" + utility-types "^3.10.0" + zustand "^3.5.1" + "@types/hoist-non-react-statics@*": version "3.3.1" resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" @@ -707,6 +730,11 @@ data-uri-to-buffer@3.0.1: resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636" integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og== +debounce@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" + integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== + debug@2: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -855,6 +883,11 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" +fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + fill-range@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" @@ -1506,11 +1539,6 @@ parse-asn1@^5.0.0, parse-asn1@^5.1.5: pbkdf2 "^3.0.3" safe-buffer "^5.1.1" -particlesjs@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/particlesjs/-/particlesjs-2.2.3.tgz#4d213ca740679fc1ccc772e8d864b884a091f37e" - integrity sha512-f0rL80Agqdsrnv/uhlLewv+LMdiXHu9MYPzMv0ZLPM06nLx3zmAXMH882fxqO6Uzb91csli8WlWaYd2XPN0d/Q== - path-browserify@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" @@ -1678,11 +1706,37 @@ react-is@^16.7.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-merge-refs@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/react-merge-refs/-/react-merge-refs-1.1.0.tgz#73d88b892c6c68cbb7a66e0800faa374f4c38b06" + integrity sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ== + +react-reconciler@^0.26.2: + version "0.26.2" + resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.26.2.tgz#bbad0e2d1309423f76cf3c3309ac6c96e05e9d91" + integrity sha512-nK6kgY28HwrMNwDnMui3dvm3rCFjZrcGiuwLc5COUipBK5hWHLOxMJhSnSomirqWwjPBJKV1QcbkI0VJr7Gl1Q== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler "^0.20.2" + react-refresh@0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f" integrity sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg== +react-three-fiber@0.0.0-deprecated: + version "0.0.0-deprecated" + resolved "https://registry.yarnpkg.com/react-three-fiber/-/react-three-fiber-0.0.0-deprecated.tgz#c737242487d824cf9520307308b7e4c4071a278f" + integrity sha512-EblIqTAsIpkYeM8bZtC4lcpTE0A2zCEGipFB52RgcQq/q+0oryrk7Sxt+sqhIjUu6xMNEVywV8dr74lz5yWO6A== + +react-use-measure@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/react-use-measure/-/react-use-measure-2.0.4.tgz#cb675b36eaeaf3681b94d5f5e08b2a1e081fedc9" + integrity sha512-7K2HIGaPMl3Q9ZQiEVjen3tRXl4UDda8LiTPy/QxP8dP2rl5gPBhf7mMH6MVjjRNv3loU7sNzey/ycPNnHVTxQ== + dependencies: + debounce "^1.2.0" + react@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" @@ -1725,6 +1779,11 @@ regenerator-runtime@^0.13.4: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== +resize-observer-polyfill@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" + integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== + ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" @@ -2068,6 +2127,13 @@ url@^0.11.0: punycode "1.3.2" querystring "0.2.0" +use-asset@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/use-asset/-/use-asset-1.0.4.tgz#506caafc29f602890593799e58b577b70293a6e2" + integrity sha512-7/hqDrWa0iMnCoET9W1T07EmD4Eg/Wmoj/X8TGBc++ECRK4m5yTsjP4O6s0yagbxfqIOuUkIxe2/sA+VR2GxZA== + dependencies: + fast-deep-equal "^3.1.3" + use-subscription@1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1" @@ -2118,6 +2184,11 @@ util@^0.12.0: safe-buffer "^5.1.2" which-typed-array "^1.1.2" +utility-types@^3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b" + integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg== + vm-browserify@1.1.2, vm-browserify@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" @@ -2177,3 +2248,8 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zustand@^3.5.1: + version "3.5.9" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-3.5.9.tgz#93fcf9eb29d10bc7fc37bdb5806464af516e7da9" + integrity sha512-ELj8XLrf5TZoiffbsZKaJ0uGnT1t4PGU9IgFLfiLsjMhOXFfKEl3fEUa5mNAWTzrietJuA1R2YY6GBE1siyE5Q==