Skip to content

Instantly share code, notes, and snippets.

@Utsira
Last active January 9, 2016 13:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Utsira/9ba147647374a6bd2661 to your computer and use it in GitHub Desktop.
Save Utsira/9ba147647374a6bd2661 to your computer and use it in GitHub Desktop.
Markdown-like text formatting in Codea
--# Main
-- Markdown Codea
-- by Yojimbo2000
displayMode(FULLSCREEN)
function setup()
setText()
y,vel = 0,0
scrollY={} --store deltas for smooth scrolling upon finger release
end
function setText()
fontSize(25) --use the regular fontsize command to set the size of the body level text
textImage = Markdown{
-- debug = true, --debug print
width = WIDTH *0.9, --wrap width
text = testString
}
end
function draw()
background(214, 212, 203, 255)
if y<0 then vel = math.abs(vel) * 0.5 --scroll bounce
elseif y>HEIGHT then vel = -math.abs(vel) * 0.5
end
if not touching then vel = vel * 0.95 end --friction upon touch end
y = y + vel
sprite(textImage, WIDTH*0.5, y)
end
function touched(t)
if t.state==ENDED then
local av = 0 --calculate average deltas over last 10
for i=1, #scrollY do
av = av + scrollY[i]
end
vel = av / #scrollY
scrollY = {} --reset delta table
touching = false
else
if #scrollY>10 then --store last 10 deltas
table.remove(scrollY, 1)
else
scrollY[#scrollY+1]=t.deltaY
end
vel = t.deltaY
touching = true
end
end
function orientationChanged()
setText()
end
--# Markdown
--markdown-esque string formatting
local style = { --simple cascading styles
body = { --body format
font = "IowanOldStyle", --"Baskerville", --"Optima",
col = color(91, 73, 51, 255)
},
heading = { --the array part of style.heading contains styles for heading1, heading2, etc (overrides global)
{--font = "HelveticaNeueUltraLight",
size=2.5}, --Heading1. Size is proportion of body size
{size=1.5}, --Heading2
{size=1.2}, --Heading 3
all = { --global headings settings
font = "Avenir", --"HelveticaNeueLight",
col = color(95, 89, 135, 255)
}
},
block = { --block quotes
size = 0.9,
font = "Optima", --"Verdana", -- "HelveticaNeue",
col = color(89, 78, 66, 255)},
bullet = { --bullet points
size = 0.9,
col = color(133, 97, 72, 255),
font = "Optima"
},
--non-standard names for font families. add entries here if they dont conform to suffix pattern of "", "-Italic", "-Bold", "-BoldItalic", (eg -Black for bold, -Oblique for italic etc)
Palatino = {
regular = "Palatino-Roman"
},
HoeflerText = {
regular = "HoeflerText-Regular",
bold = "HoeflerText-Black",
boldItalic = "HoeflerText-BlackItalic"
},
Optima = {
regular = "Optima-Regular"
},
HelveticaNeueUltraLight = {
regular = "HelveticaNeue-UltraLight",
italic = "HelveticaNeue-UltraLightItalic",
bold = "HelveticaNeue-Light",
boldItalic = "HelveticaNeue-LightItalic"
},
HelveticaNeueLight = {
regular = "HelveticaNeue-Light",
italic = "HelveticaNeue-LightItalic",
bold = "HelveticaNeue",
boldItalic = "HelveticaNeue-Italic"
},
IowanOldStyle = {
regular = "IowanOldStyle-Roman"
},
Avenir = {
regular = "Avenir-Roman",
italic = "Avenir-Oblique",
bold = "Avenir-Heavy",
boldItalic = "Avenir-HeavyOblique"
}
}
font("Didot-Bold")
local face --name of base font currently being used
local size --size of base font
function Markdown(t)
textMode(CORNER)
local _, baseHeight = textSize("dummy") --defines paragraph separation
size = fontSize() --base size of body text
local img = image(t.width, HEIGHT * 2) --height
setContext(img)
textWrapWidth(0) --we need to turn off text wrapping and implement our own because the built-in wrapping does not give us control over the point at which the text starts (first line indentation), nor tell us where the last line ends.
local cursor = vec2(0,HEIGHT * 2)
local italic = false
local bold = false
-- local tightList = false --remove paragraph separation for bullets
local indent = 0 --for block quotations
local parSep = baseHeight
for paragraph,sep in string.gmatch(testString, "(.-)(\n%s*)") do
print (paragraph)
--PRE-PROCESS TYPOGRAPHY
paragraph = string.gsub(paragraph, "(%S+)'", "%1\u{2019}") --right single quote. Do this first in order to catch apostrophes
paragraph = string.gsub(paragraph, "'(%S+)", "\u{2018}%1") --left single quote
paragraph = string.gsub(paragraph, "%-%-%-", "\u{2014}") --em-dash
paragraph = string.gsub(paragraph, "%-%-", "\u{2013}") --en-dash
paragraph = string.gsub(paragraph, "\"(%S+)", "\u{201C}%1") --left double quote
paragraph = string.gsub(paragraph, "(%S+)\"", "%1\u{201D}") --right double quote
--RESET TO DEFAULT BODY FONT FOR NEW PARAGRAPH
style.set(style.body)
cursor.x = 0
indent = 0
fontSize(size)
paragraph = paragraph.."\n" --add return (this also allows final part of line to be captured, as return is a whitespace character)
local cursorSet = false --set to true once initial cursor position for paragraph is set according to font size, paragraph separation
--CHECK ELEMENTS THAT ONLY COME AT START OF PARAGRAPH
--BLOCK
local bl
paragraph, bl = string.gsub(paragraph, "^> ", "", 1)
if bl>0 then
indent = size * 3 --indent paragraph
cursor.x = indent
style.set(style.block)
end
--BULLETS
local bu
paragraph, bu = string.gsub(paragraph, "^%- ", "", 1)
if bu>0 then
cursor.y = cursor.y - (parSep + baseHeight)
--[[
if not tightList then
cursor.y = cursor.y - parSep
end
]]
-- tightList = true
style.set(style.bullet)
text("\u{2022}", size * 1.75, cursor.y)
cursorSet = true
indent = size * 3
cursor.x = indent
-- paragraph = "\u{2022} "..paragraph
--[[
else
tightList = false
]]
end
--HEADINGS
local hBegin, hEnd = string.find(paragraph, "^%#+") --look for number of hashes at start of para
if hBegin then
local headLevel = hEnd + 1 - hBegin
paragraph = string.gsub(paragraph, "^%#+%s?", "")
style.set(style.heading.all) --global heading settings
style.set(style.heading[headLevel]) --level specific settings
end
--PARSE WORDS
for element, control in string.gmatch(paragraph, "(.-)([%s*]+)") do --separate at white space, *
if string.find(control, "%s") then --if whitespace
element = element.." " --put spaces back in
end
local w,h = textSize(element) --find size of word
if t.debug then print(element,control) end --debug print
if not cursorSet then --place first line of paragraph (paragraph separation etc)
cursor.y = cursor.y - (h+parSep)
cursorSet = true
end
--WRAPPING
if cursor.x + w > t.width then --if word will take us over edge
cursor.x = indent --carriage return
cursor.y = cursor.y - h
end
text(element, cursor.x, cursor.y) --print word
cursor.x = cursor.x + w
--BOLD AND ITALICS
local eBegin, eEnd = string.find(control, "%*+") --count number of asterisks
if eBegin then
local emph = eEnd + 1 - eBegin
if emph==3 then
bold = not bold
italic = not italic
elseif emph==2 then
bold = not bold
else
italic = not italic
end
if bold and italic then
font(style.boldItalic(face))
elseif bold then
font(style.bold(face))
elseif italic then
font(style.italic(face))
else
style.font(face)
end
end
end --of word
--CHECK PARAGRAPH SEPARATION (NUMBER OF RETURNS) FOR TIGHT/LOOSE LISTS
local _,returns = string.gsub(sep, "\n", "")
if returns==1 then
parSep = 0 --tight list
else
parSep = baseHeight --loose list
end
end --of paragraph
setContext()
return img
end
function style.set(sty)
for func, val in pairs(sty) do --set font features for whatever keys are in the style table
style[func](val)
end
end
--3 functions to handle non-standard named fonts (eg -Black for bold, -Oblique for italc etc)
function style.bold(f)
if style[f] and style[f].bold then --check if a nonstandard bold face is specified
return style[f].bold
end
return f.."-Bold" --else just append bold to family name
end
function style.italic(f)
if style[f] and style[f].italic then
return style[f].italic
end
return f.."-Italic"
end
function style.boldItalic(f)
if style[f] and style[f].boldItalic then
return style[f].boldItalic
end
return f.."-BoldItalic"
end
--the function names below correspond to the bottom level keys in the style table, eg font, col, size
function style.font(f)
face = f
if style[face] and style[face].regular then
font(style[face].regular)
else
font(face)
end
end
function style.col(col)
fill(col)
end
function style.size(s)
fontSize(size * s)
end
--# Sampletext
testString = [[
# *Markdown*-like text formatting --- in **Codea!**
Have you ever wanted an easy way to format text --- adding *italic*, **bold**, ***bold-italic,*** different type faces, font sizes and colours, indented block quotes, plus typography features such as "smart quotes" and em-dashes, all of them nestable within one-another --- on the fly?
## Well now you can, with **Markdown Codea.**
> *Try switching the orientation of your device to test the hand-made text wrapping feature! Touch the screen to scroll the text*
### "But --- *what **is** this **Markdown**?!?*" I hear you yell
Markdown is a way of adding rich formatting, such as:
- *Emphasis*
- **Strong emphasis**
- *Really, **really** strong emphasis*
- Or **really, *really* strong emphasis** if you prefer
- Block quotes, different headings...
- Oh, and ***bullet points!*** Bullet points can be displayed in a tight list like this, by only separating each item with one return
Or, if you prefer, you can have:
- A loose list
- Of bullet points
- Just separate each bullet with two returns
And it's all done using plain text. So it's great for using in plain-text environments such as code editors. As *Markdown's* creator John Gruber said:
> The overriding design goal for *Markdown's* formatting syntax is to make it as **readable** as possible. The idea is that a *Markdown*-formatted document should be publishable **as-is, as plain text, *without* looking like it's been marked up with tags** or formatting instructions
**But the best thing about Markdown is --- *you already know how to use it***. It's used on lots of forums, including *Codea Talk.* I've thrown in some nice, *Pandoc*-inspired extras such as typographer's quotes for the apostrophe and for 'single quotation marks' and "double" quote marks, plus en--dash and em---dash
]]
@TokOut
Copy link

TokOut commented Jan 9, 2016

Nice

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment