forked from yihui/knitr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhighlight.R
150 lines (132 loc) · 4.61 KB
/
highlight.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
hilight_source = function(x, format, options) {
if ((format %in% c('latex', 'html')) && options$highlight) {
res = if (options$engine == 'R') {
opts = opts_knit$get('highr.opts')
highr::hilight(x, format, prompt = options$prompt, markup = opts$markup)
} else {
res = try(highr::hi_andre(x, options$engine, format))
if (inherits(res, 'try-error')) {
if (format == 'html') highr:::escape_html(x) else highr:::escape_latex(x)
} else {
highlight_header()
n = length(res)
# do not touch font size
if (res[n] == '\\normalsize') res = res[-n]
res
}
}
if (format == 'latex' && is.character(tld <- opts_knit$get('latex.tilde'))) {
res = gsub('\\hlopt{~}', tld, res, fixed = TRUE)
}
res
} else if (options$prompt) {
# if you did not reformat or evaluate the code, I have to figure out which
# lines belong to one complete expression first (#779)
if (options$engine == 'R' && isFALSE(options$tidy) && isFALSE(options$eval))
x = vapply(xfun::split_source(x), one_string, character(1))
line_prompt(x)
} else x
}
highlight_header = function() {
set_header(highlight.extra = paste(c(
sprintf('\\let\\hl%s\\hldef', c('esc', 'pps', 'lin')),
sprintf('\\let\\hl%s\\hlcom', c('slc', 'ppc'))
), collapse = ' '))
}
# stolen from Romain's highlight package (v0.3.2)
# http://www.w3schools.com/css/css_colornames.asp
w3c.colors = c(
aqua = '#00FFFF', black = '#000000', blue = '#0000FF', fuchsia = '#FF00FF',
gray = '#808080', green = '#008000', lime = '#00FF00', maroon = '#800000',
navy = '#000080', olive = '#808000', purple = '#800080', red = '#FF0000',
silver = '#C0C0C0', teal = '#008080', white = '#FFFFFF', yellow = '#FFFF00'
)
css.parse.color = function(txt, default = '#000000') {
txt = gsub('\\s+', '', tolower(txt))
if (is.hex(txt)) return(txt)
# css specs are from 0 to 255
rgb = function(...) grDevices::rgb(..., maxColorValue = 255)
# first we try to match against w3c standard colors
if (!grepl('[^a-z]', txt) && txt %in% names(w3c.colors))
return(w3c.colors[txt])
# now we try R colors
if (!grepl('[^a-z0-9]', txt)) {
R.colors = colors()
res = R.colors %in% txt
if (any(res)) {
return(rgb(t(col2rgb(R.colors[res]))))
}
}
# next we try an rgb() specification
if (grepl('rgb', txt)) {
p = try_silent(parse(text = txt))
if (!inherits(p, 'try-error')) {
res = try_silent(eval(p))
if (!inherits(res, 'try-error')) return(res)
}
}
# fall back on the default color
default
}
is.hex = function(x) grepl('^#[0-9a-f]{6}$', x)
# minimal css parser
css.parser = function(file, lines = read_utf8(file)) {
rx = '^\\.(.*?) *\\{.*$'
dec.lines = grep(rx, lines)
dec.names = sub(rx, '\\1', lines[dec.lines])
if (any(grepl('[0-9]', dec.names))) warning('use of numbers in style names')
end.lines = grep('^\\s*\\}', lines)
# find the closing brace of each declaration
dec.close = end.lines[vapply(dec.lines, function(x) which.min(end.lines < x), integer(1))]
pos = matrix(c(dec.lines, dec.close), ncol = 2)
styles = apply(pos, 1, function(x) {
data = lines[(x[1] + 1):(x[2] - 1)]
settings.rx = '^\\s*(.*?)\\s*:\\s*(.*?)\\s*;\\s*$'
settings = sub(settings.rx, '\\1', data, perl = TRUE)
contents = sub(settings.rx, '\\2', data, perl = TRUE)
out = list()
for (i in seq_along(settings)) {
setting = settings[i]
content = contents[i]
out[[setting]] = switch(
setting,
color = css.parse.color(content, '#000000'),
background = css.parse.color(content, '#FFFFFF'),
content
)
}
out
})
names(styles) = dec.names
styles
}
# styler assistant for latex
styler_assistant_latex = function(x) {
styles = sapply(x, function(item) {
settings = names(item)
has = function(s, value) {
s %in% settings && grepl(value, item[[s]])
}
start = end = ''
if ('color' %in% settings) {
start = paste0(start, '\\textcolor[rgb]{', col2latexrgb(item[['color']]), '}{')
end = paste0(end, '}')
}
if (has('font-weight', 'bold')) {
start = paste0(start, '\\textbf{')
end = paste0('}', end)
}
if (has('font-style', 'italic')) {
start = paste0(start, '\\textit{')
end = paste0('}', end)
}
sprintf('%s#1%s', start, end)
})
res = sprintf('\\newcommand{\\hl%s}[1]{%s}%%', names(x), styles)
c(res, '\\let\\hlipl\\hlkwb')
}
col2latexrgb = function(hex) {
# as.character(0.123) -> 0,123 when "OutDec = ,", so make sure . is used
col = col2rgb(hex)[, 1] / 255
xfun::decimal_dot(paste(round(col, 3), collapse = ','))
}