wee-pm 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +60 -0
- data/TODO +9 -0
- data/bin/wee-pm +114 -0
- data/bin/wee-pm-pdf +49 -0
- data/lib/wee-pm/colorize.rb +475 -0
- data/lib/wee-pm/colorize_filter.rb +22 -0
- data/lib/wee-pm/converter.rb +104 -0
- data/lib/wee-pm/presentation.rb +152 -0
- data/lib/wee-pm/presentation_maker.rb +395 -0
- data/lib/wee-pm/slideshtml.rb +204 -0
- data/lib/wee-pm/utils.rb +40 -0
- data/wee-pm.gemspec +25 -0
- metadata +71 -0
data/README
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
= Presentation Maker
|
2
|
+
|
3
|
+
Copyright (c) 2005, 2007 by Michael Neumann (mneumann@ntecs.de).
|
4
|
+
All rights reserved.
|
5
|
+
|
6
|
+
== Dependencies
|
7
|
+
|
8
|
+
* ruby 1.8.x
|
9
|
+
* Wee 0.10.0 (gem install wee)
|
10
|
+
* vim (for colorizing sources)
|
11
|
+
* html2ps (for creating the Postscript output)
|
12
|
+
* ps2pdf (for creating the PDF output)
|
13
|
+
|
14
|
+
== Start
|
15
|
+
|
16
|
+
cd directory-where-all-your-presentation-related-files-reside
|
17
|
+
wee-pm presentation-file
|
18
|
+
|
19
|
+
Then point your browser to: http://localhost:2000/
|
20
|
+
|
21
|
+
== Navigation
|
22
|
+
|
23
|
+
* Page-Up/-Down: Previous/Next slide/overlay.
|
24
|
+
|
25
|
+
* Key 's': toggle slide/overlay mode.
|
26
|
+
|
27
|
+
* Key 'e': enter edit mode.
|
28
|
+
|
29
|
+
* Next overlay/slide: Click with the mouse on the slide-title.
|
30
|
+
|
31
|
+
* Switch to edit-mode: Position the mouse into the top-left corner of the
|
32
|
+
frame, you'll notice a hover-effect. Then click.
|
33
|
+
|
34
|
+
== Presentation file format
|
35
|
+
|
36
|
+
Pure rdoc! Each level-one heading ("=") generates a slide.
|
37
|
+
|
38
|
+
== RDoc extensions
|
39
|
+
|
40
|
+
To colorize sourcecode, use a verbatim block like this:
|
41
|
+
|
42
|
+
!!colorize:ruby
|
43
|
+
def method_a
|
44
|
+
end
|
45
|
+
|
46
|
+
Note that you'll need +vim+ to be installed on your system.
|
47
|
+
|
48
|
+
== Generating PDF
|
49
|
+
|
50
|
+
wee-pm-pdf presentation-file > pdf-file
|
51
|
+
|
52
|
+
You can tweak the generated PDF file, by editing bin/wee-pm-pdf. For
|
53
|
+
example, if you want to have a PDF that is not intended for printing and
|
54
|
+
as such could ommit the URLs to be shown as text, set SHOW_URL to false
|
55
|
+
in bin/wee-pm-pdf.
|
56
|
+
|
57
|
+
If you need Postscript, then have a look at bin/wee-pm-pdf, and remove
|
58
|
+
the "| ps2pdf - -" part in the IO.popen line. But you generally don't
|
59
|
+
want this, as the PDF output allows easier navigating, and the links are
|
60
|
+
clickable (if you use AcroRead).
|
data/TODO
ADDED
data/bin/wee-pm
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'rubygems'
|
5
|
+
rescue LoadError
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'wee'
|
9
|
+
require 'wee/pageless'
|
10
|
+
require 'wee/utils/helper'
|
11
|
+
require 'wee/utils/cache'
|
12
|
+
require 'wee/utils/autoreload'
|
13
|
+
require 'wee/adaptors/webrick'
|
14
|
+
begin
|
15
|
+
require 'wee-pm/presentation_maker'
|
16
|
+
rescue LoadError
|
17
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), '../lib')
|
18
|
+
end
|
19
|
+
require 'wee-pm/presentation_maker'
|
20
|
+
|
21
|
+
# Overrides for Wee 0.10.0 to get be able to mount
|
22
|
+
# an application as "/".
|
23
|
+
class Wee::Request
|
24
|
+
def initialize(app_path, path, headers, fields, cookies)
|
25
|
+
unless app_path == '/'
|
26
|
+
raise ArgumentError, app_path if app_path[-1] == ?/
|
27
|
+
end
|
28
|
+
@app_path, @path, @headers, @cookies = app_path, path, headers, cookies
|
29
|
+
parse_fields(fields)
|
30
|
+
parse_path
|
31
|
+
end
|
32
|
+
|
33
|
+
def build_url(hash={})
|
34
|
+
default = {
|
35
|
+
:request_handler_id => self.request_handler_id,
|
36
|
+
:page_id => self.page_id,
|
37
|
+
:info => self.info
|
38
|
+
}
|
39
|
+
hash = default.update(hash)
|
40
|
+
|
41
|
+
request_handler_id = hash[:request_handler_id]
|
42
|
+
page_id = hash[:page_id]
|
43
|
+
callback_id = hash[:callback_id]
|
44
|
+
info = hash[:info]
|
45
|
+
|
46
|
+
raise ArgumentError if request_handler_id.nil? and not page_id.nil?
|
47
|
+
if not pageless?
|
48
|
+
raise ArgumentError if page_id.nil? and not callback_id.nil?
|
49
|
+
end
|
50
|
+
|
51
|
+
# build request path, e.g. /___/req-id/page-id
|
52
|
+
req_path = make_request_path(request_handler_id, page_id)
|
53
|
+
|
54
|
+
# build the whole url
|
55
|
+
if @app_path == '/'
|
56
|
+
url = ""
|
57
|
+
if info
|
58
|
+
url << '/'
|
59
|
+
url << info
|
60
|
+
end
|
61
|
+
url << req_path
|
62
|
+
|
63
|
+
url << '/' if info.nil? and req_path.empty?
|
64
|
+
|
65
|
+
url << ('?' + callback_id) if callback_id
|
66
|
+
else
|
67
|
+
url = ""
|
68
|
+
url << @app_path
|
69
|
+
|
70
|
+
raise if url[-1] == ?/ # sanity check
|
71
|
+
|
72
|
+
if info
|
73
|
+
url << '/'
|
74
|
+
url << info
|
75
|
+
end
|
76
|
+
url << req_path
|
77
|
+
|
78
|
+
url << '/' if info.nil? and req_path.empty?
|
79
|
+
|
80
|
+
url << ('?' + callback_id) if callback_id
|
81
|
+
end
|
82
|
+
|
83
|
+
return url
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class DispatchHandler < WEBrick::HTTPServlet::AbstractServlet
|
88
|
+
def initialize(server, application, file_dir)
|
89
|
+
super(server)
|
90
|
+
@app_handler = Wee::WEBrickAdaptor.new(server, '/', application, Wee::PagelessRequest)
|
91
|
+
@file_handler = WEBrick::HTTPServlet::FileHandler.new(server, file_dir)
|
92
|
+
end
|
93
|
+
|
94
|
+
def do_GET(req, res)
|
95
|
+
(req.path == '/' ? @app_handler : @file_handler).do_GET(req, res)
|
96
|
+
end
|
97
|
+
|
98
|
+
def do_POST(req, res)
|
99
|
+
(req.path == '/' ? @app_handler : @file_handler).do_POST(req, res)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def run(presentation_file)
|
104
|
+
comp = proc { PresentationMaker.new(presentation_file) };
|
105
|
+
def comp.new; call end
|
106
|
+
app = Wee::Utils.app_for(comp,
|
107
|
+
:session => Wee::PagelessSession,
|
108
|
+
:application => Wee::PagelessApplication)
|
109
|
+
Wee::WEBrickAdaptor.
|
110
|
+
mount('/', DispatchHandler, app, '.').
|
111
|
+
start
|
112
|
+
end
|
113
|
+
|
114
|
+
run(ARGV[0])
|
data/bin/wee-pm-pdf
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'rubygems'
|
5
|
+
rescue LoadError
|
6
|
+
end
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'wee-pm/presentation'
|
10
|
+
rescue LoadError
|
11
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), '../lib')
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'wee-pm/presentation'
|
15
|
+
require 'wee-pm/converter'
|
16
|
+
require 'tempfile'
|
17
|
+
|
18
|
+
SHOW_URL = true
|
19
|
+
|
20
|
+
pres = Presentation.from_string(File.read(ARGV[0]))
|
21
|
+
|
22
|
+
rc = Tempfile.new('html2psrc')
|
23
|
+
rc << <<EOS
|
24
|
+
@html2ps { showurl: #{ SHOW_URL ? 1 : 0 }; seq-number: 1; }
|
25
|
+
titlepage { content: "<div align=center><h1><big>$[title]</big></h1><h3>$[author]</h3><h4>$[email]</h4></div>" }
|
26
|
+
EOS
|
27
|
+
rc.close(false)
|
28
|
+
|
29
|
+
io = IO.popen("/usr/bin/perl /usr/local/bin/html2ps --toc hb -f #{ rc.path } --titlepage --hyphenate --underline --web b --colour --frame --landscape | ps2pdf - -", 'w+')
|
30
|
+
io << "<html><head><title>#{ pres.title }</title>\n"
|
31
|
+
io << %[<meta name="Title" content="#{pres.title}"/>]
|
32
|
+
io << %[<meta name="Author" content="#{pres.author}"/>]
|
33
|
+
io << %[<meta name="Email" content="#{pres.email}"/>]
|
34
|
+
io << "</head><body>"
|
35
|
+
io << pres.style || ""
|
36
|
+
pres.slides.each do |slide|
|
37
|
+
slide.converter = PsHtmlConverter
|
38
|
+
io << slide.style || ""
|
39
|
+
io << "<h1>#{ slide.title }</h1>\n"
|
40
|
+
slide.render_on(io, slide.number_of_overlays)
|
41
|
+
unless slide.annotations.strip.empty?
|
42
|
+
io << "<hr>"
|
43
|
+
slide.render_annotations_on(io)
|
44
|
+
end
|
45
|
+
io << "<!--NewPage-->\n"
|
46
|
+
end
|
47
|
+
io << "</body></html>\n"
|
48
|
+
io.close_write
|
49
|
+
puts io.read
|
@@ -0,0 +1,475 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
# Colorize Source Code using Vim
|
4
|
+
#
|
5
|
+
# by Michael Neumann (mneumann@ntecs.de)
|
6
|
+
#
|
7
|
+
# Freeware.
|
8
|
+
|
9
|
+
# Use --terminal=xterm-color for coloring output when called by a CGI script (Apache).
|
10
|
+
#
|
11
|
+
# TODO:
|
12
|
+
# - Make sure caching works with --headers and --mode option.
|
13
|
+
# Currently it's assumed that caching is used with the same options
|
14
|
+
# all the time except --lang or --strip-ws
|
15
|
+
# - remove too old entries in the cache?
|
16
|
+
|
17
|
+
require "getopts"
|
18
|
+
require "tempfile"
|
19
|
+
require "md5"
|
20
|
+
|
21
|
+
def usage
|
22
|
+
STDERR.puts "USAGE: #{ $0 }
|
23
|
+
[--mode=gui|text] (default: text)
|
24
|
+
[--lang=vim_lang] (default: __auto__)
|
25
|
+
[--strip-ws]
|
26
|
+
[--cache [--cache-prefix=prefix]] (default: cache-prefix=/tmp/_colorize)
|
27
|
+
[--headers]
|
28
|
+
[--terminal=...] (default: __none__; which terminal to use for vim)
|
29
|
+
[input-file [output-file]] (default: stdin stdout)
|
30
|
+
[--help]"
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
|
34
|
+
# remove leading and trailing empty lines
|
35
|
+
def strip_ws(str)
|
36
|
+
# find first non-empty line
|
37
|
+
first_non_empty = 0
|
38
|
+
str.each_with_index do |line, i|
|
39
|
+
if line.strip != ""
|
40
|
+
first_non_empty = i
|
41
|
+
break
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# find last non-empty line
|
46
|
+
last_non_empty = 0
|
47
|
+
str.each_with_index do |line, i|
|
48
|
+
if line.strip != ""
|
49
|
+
last_non_empty = i
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
return str.to_a[first_non_empty..last_non_empty].join("")
|
54
|
+
end
|
55
|
+
|
56
|
+
def gen_cache_name(content, lang)
|
57
|
+
md5 = MD5.new(content)
|
58
|
+
$OPT["cache-prefix"] + ".#{ md5 }.#{ lang }"
|
59
|
+
end
|
60
|
+
|
61
|
+
getopts(nil, "mode:text", "lang:__auto__", "headers", "terminal:xterm",
|
62
|
+
"strip-ws", "cache", "cache-prefix:/tmp/_colorize", "help")
|
63
|
+
|
64
|
+
if ARGV.size > 2 or $OPT["help"]
|
65
|
+
usage
|
66
|
+
else
|
67
|
+
|
68
|
+
# generate temporary 2html_michael.vim file
|
69
|
+
f = Tempfile.new("2html_michael.vim")
|
70
|
+
f << DATA.read
|
71
|
+
f.close(false)
|
72
|
+
|
73
|
+
input_file, output_file = ARGV
|
74
|
+
|
75
|
+
if input_file.nil?
|
76
|
+
# read input from STDIN
|
77
|
+
inp = Tempfile.new("input")
|
78
|
+
inp << STDIN.read
|
79
|
+
inp.close(false)
|
80
|
+
input_file = inp.path
|
81
|
+
end
|
82
|
+
|
83
|
+
if output_file.nil?
|
84
|
+
of = Tempfile.new("colorize")
|
85
|
+
of.close(false)
|
86
|
+
output_file = of.path
|
87
|
+
else
|
88
|
+
of = nil
|
89
|
+
end
|
90
|
+
|
91
|
+
vim =
|
92
|
+
case $OPT["mode"]
|
93
|
+
when "gui"
|
94
|
+
'/usr/local/bin/gvim -f'
|
95
|
+
when "text"
|
96
|
+
if $OPT["terminal"] == "__none__" or $OPT["terminal"].empty?
|
97
|
+
'/usr/local/bin/vim'
|
98
|
+
else
|
99
|
+
"/usr/local/bin/vim -T #{ $OPT['terminal'] }"
|
100
|
+
end
|
101
|
+
else
|
102
|
+
raise
|
103
|
+
end
|
104
|
+
|
105
|
+
lang =
|
106
|
+
case $OPT["lang"]
|
107
|
+
when "__auto__"
|
108
|
+
""
|
109
|
+
else
|
110
|
+
%{ +"setf #{ $OPT['lang'] }" }
|
111
|
+
end
|
112
|
+
|
113
|
+
headers =
|
114
|
+
if $OPT["headers"] then
|
115
|
+
""
|
116
|
+
else
|
117
|
+
%{ +"let html_no_header=''" }
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
vim_command = %{#{ vim } +"syn on" +"set nonumber" #{ headers } #{ lang } +"set runtimepath=#{ File.dirname f.path } " +"run #{ File.basename f.path }" +"w! #{ output_file }" +"q!" +"q!" #{ input_file } > /dev/null 2> /dev/null}
|
124
|
+
|
125
|
+
if $OPT["cache"] then
|
126
|
+
# TODO: doesn't work together with --headers
|
127
|
+
cn = gen_cache_name(File.readlines(input_file).to_s, $OPT["lang"])
|
128
|
+
if File.exists? cn
|
129
|
+
# result is in cache
|
130
|
+
`cp #{ cn } #{ output_file }`
|
131
|
+
else
|
132
|
+
# generate we have to generate the cache file
|
133
|
+
`#{ vim_command }`
|
134
|
+
`cp #{ output_file } #{ cn }`
|
135
|
+
end
|
136
|
+
else
|
137
|
+
# no caching
|
138
|
+
`#{ vim_command }`
|
139
|
+
end
|
140
|
+
|
141
|
+
if of != nil
|
142
|
+
str = File.readlines(output_file).to_s
|
143
|
+
STDOUT <<
|
144
|
+
if $OPT["strip-ws"]
|
145
|
+
strip_ws(str)
|
146
|
+
else
|
147
|
+
str
|
148
|
+
end
|
149
|
+
else
|
150
|
+
if $OPT["strip-ws"]
|
151
|
+
str = File.readlines(output_file).to_s
|
152
|
+
File.open(output_file, "w+") {|f| f << strip_ws(str) }
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
__END__
|
159
|
+
" Vim syntax support file
|
160
|
+
" Maintainer: Bram Moolenaar <Bram@vim.org>
|
161
|
+
" Last Change: 2002 Jul 10
|
162
|
+
" (modified by David Ne\v{c}as (Yeti) <yeti@physics.muni.cz>)
|
163
|
+
" (modified by Michael Neumann <mneumann@ntecs.de>)
|
164
|
+
|
165
|
+
" Transform a file into HTML, using the current syntax highlighting.
|
166
|
+
|
167
|
+
" Number lines when explicitely requested or when `number' is set
|
168
|
+
if exists("html_number_lines")
|
169
|
+
let s:numblines = html_number_lines
|
170
|
+
else
|
171
|
+
let s:numblines = &number
|
172
|
+
endif
|
173
|
+
|
174
|
+
" When not in gui we can only guess the colors.
|
175
|
+
if has("gui_running")
|
176
|
+
let s:whatterm = "gui"
|
177
|
+
else
|
178
|
+
let s:whatterm = "cterm"
|
179
|
+
if &t_Co == 99999 " to active this section, use == 8
|
180
|
+
let s:cterm_color0 = "#808080"
|
181
|
+
let s:cterm_color1 = "#ff6060"
|
182
|
+
let s:cterm_color2 = "#00ff00"
|
183
|
+
let s:cterm_color3 = "#ffff00"
|
184
|
+
let s:cterm_color4 = "#8080ff"
|
185
|
+
let s:cterm_color5 = "#ff40ff"
|
186
|
+
let s:cterm_color6 = "#00ffff"
|
187
|
+
let s:cterm_color7 = "#ffffff"
|
188
|
+
else
|
189
|
+
let s:cterm_color0 = "#000000"
|
190
|
+
let s:cterm_color1 = "#c00000"
|
191
|
+
let s:cterm_color2 = "#008000"
|
192
|
+
let s:cterm_color3 = "#804000"
|
193
|
+
let s:cterm_color4 = "#0000c0"
|
194
|
+
let s:cterm_color5 = "#c000c0"
|
195
|
+
let s:cterm_color6 = "#008080"
|
196
|
+
let s:cterm_color7 = "#c0c0c0"
|
197
|
+
let s:cterm_color8 = "#808080"
|
198
|
+
let s:cterm_color9 = "#ff6060"
|
199
|
+
let s:cterm_color10 = "#00ff00"
|
200
|
+
let s:cterm_color11 = "#ffff00"
|
201
|
+
let s:cterm_color12 = "#8080ff"
|
202
|
+
let s:cterm_color13 = "#ff40ff"
|
203
|
+
let s:cterm_color14 = "#00ffff"
|
204
|
+
let s:cterm_color15 = "#ffffff"
|
205
|
+
endif
|
206
|
+
endif
|
207
|
+
|
208
|
+
" Return good color specification: in GUI no transformation is done, in
|
209
|
+
" terminal return RGB values of known colors and empty string on unknown
|
210
|
+
if s:whatterm == "gui"
|
211
|
+
function! s:HtmlColor(color)
|
212
|
+
return a:color
|
213
|
+
endfun
|
214
|
+
else
|
215
|
+
function! s:HtmlColor(color)
|
216
|
+
if exists("s:cterm_color" . a:color)
|
217
|
+
execute "return s:cterm_color" . a:color
|
218
|
+
else
|
219
|
+
return ""
|
220
|
+
endif
|
221
|
+
endfun
|
222
|
+
endif
|
223
|
+
|
224
|
+
if !exists("html_use_css")
|
225
|
+
" Return opening HTML tag for given highlight id
|
226
|
+
function! s:HtmlOpening(id)
|
227
|
+
let a = ""
|
228
|
+
if synIDattr(a:id, "inverse")
|
229
|
+
" For inverse, we always must set both colors (and exchange them)
|
230
|
+
let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
|
231
|
+
let a = a . '<span style="background-color: ' . ( x != "" ? x : s:fgc ) . '">'
|
232
|
+
let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
|
233
|
+
let a = a . '<font color="' . ( x != "" ? x : s:bgc ) . '">'
|
234
|
+
else
|
235
|
+
let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
|
236
|
+
if x != "" | let a = a . '<span style="background-color: ' . x . '">' | endif
|
237
|
+
let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
|
238
|
+
if x != "" | let a = a . '<font color="' . x . '">' | endif
|
239
|
+
endif
|
240
|
+
if synIDattr(a:id, "bold") | let a = a . "<b>" | endif
|
241
|
+
if synIDattr(a:id, "italic") | let a = a . "<i>" | endif
|
242
|
+
if synIDattr(a:id, "underline") | let a = a . "<u>" | endif
|
243
|
+
return a
|
244
|
+
endfun
|
245
|
+
|
246
|
+
" Return closing HTML tag for given highlight id
|
247
|
+
function s:HtmlClosing(id)
|
248
|
+
let a = ""
|
249
|
+
if synIDattr(a:id, "underline") | let a = a . "</u>" | endif
|
250
|
+
if synIDattr(a:id, "italic") | let a = a . "</i>" | endif
|
251
|
+
if synIDattr(a:id, "bold") | let a = a . "</b>" | endif
|
252
|
+
if synIDattr(a:id, "inverse")
|
253
|
+
let a = a . '</font></span>'
|
254
|
+
else
|
255
|
+
let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
|
256
|
+
if x != "" | let a = a . '</font>' | endif
|
257
|
+
let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
|
258
|
+
if x != "" | let a = a . '</span>' | endif
|
259
|
+
endif
|
260
|
+
return a
|
261
|
+
endfun
|
262
|
+
endif
|
263
|
+
|
264
|
+
" Return CSS style describing given highlight id (can be empty)
|
265
|
+
function! s:CSS1(id)
|
266
|
+
let a = ""
|
267
|
+
if synIDattr(a:id, "inverse")
|
268
|
+
" For inverse, we always must set both colors (and exchange them)
|
269
|
+
let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
|
270
|
+
let a = a . "color: " . ( x != "" ? x : s:bgc ) . "; "
|
271
|
+
let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
|
272
|
+
let a = a . "background-color: " . ( x != "" ? x : s:fgc ) . "; "
|
273
|
+
else
|
274
|
+
let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
|
275
|
+
if x != "" | let a = a . "color: " . x . "; " | endif
|
276
|
+
let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
|
277
|
+
if x != "" | let a = a . "background-color: " . x . "; " | endif
|
278
|
+
endif
|
279
|
+
if synIDattr(a:id, "bold") | let a = a . "font-weight: bold; " | endif
|
280
|
+
if synIDattr(a:id, "italic") | let a = a . "font-style: italic; " | endif
|
281
|
+
if synIDattr(a:id, "underline") | let a = a . "text-decoration: underline; " | endif
|
282
|
+
return a
|
283
|
+
endfun
|
284
|
+
|
285
|
+
" Set some options to make it work faster.
|
286
|
+
" Expand tabs in original buffer to get 'tabstop' correctly used.
|
287
|
+
" Don't report changes for :substitute, there will be many of them.
|
288
|
+
let s:old_title = &title
|
289
|
+
let s:old_icon = &icon
|
290
|
+
let s:old_et = &l:et
|
291
|
+
let s:old_report = &report
|
292
|
+
let s:old_search = @/
|
293
|
+
set notitle noicon
|
294
|
+
setlocal et
|
295
|
+
set report=1000000
|
296
|
+
|
297
|
+
" Split window to create a buffer with the HTML file.
|
298
|
+
if expand("%") == ""
|
299
|
+
new Untitled.html
|
300
|
+
else
|
301
|
+
new %.html
|
302
|
+
endif
|
303
|
+
set modifiable
|
304
|
+
%d
|
305
|
+
let s:old_paste = &paste
|
306
|
+
set paste
|
307
|
+
|
308
|
+
" The DTD
|
309
|
+
if exists("html_use_css")
|
310
|
+
exe "normal a<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n \"http://www.w3.org/TR/html4/strict.dtd\">\n\e"
|
311
|
+
endif
|
312
|
+
|
313
|
+
" HTML header, with the title and generator ;-). Left free space for the CSS,
|
314
|
+
" to be filled at the end.
|
315
|
+
if !exists("html_no_header")
|
316
|
+
exe "normal a<html>\n<head>\n<title>\e"
|
317
|
+
exe "normal a" . expand("%:p:~") . "</title>\n\e"
|
318
|
+
exe "normal a<meta name=\"Generator\" content=\"Vim/" . version/100 . "." . version %100 . "\">\n\e"
|
319
|
+
if exists("html_use_css")
|
320
|
+
exe "normal a<style type=\"text/css\">\n<!--\n-->\n</style>\n\e"
|
321
|
+
endif
|
322
|
+
exe "normal a</head>\n<body>\n<pre>\n\e"
|
323
|
+
endif
|
324
|
+
|
325
|
+
wincmd p
|
326
|
+
|
327
|
+
" List of all id's
|
328
|
+
let s:idlist = ","
|
329
|
+
|
330
|
+
let s:expandedtab = ' '
|
331
|
+
while strlen(s:expandedtab) < &ts
|
332
|
+
let s:expandedtab = s:expandedtab . ' '
|
333
|
+
endwhile
|
334
|
+
|
335
|
+
" Loop over all lines in the original text
|
336
|
+
let s:end = line("$")
|
337
|
+
let s:lnum = 1
|
338
|
+
while s:lnum <= s:end
|
339
|
+
|
340
|
+
" Get the current line
|
341
|
+
let s:line = getline(s:lnum)
|
342
|
+
let s:len = strlen(s:line)
|
343
|
+
let s:new = ""
|
344
|
+
|
345
|
+
if s:numblines
|
346
|
+
let s:new = '<span class="lnr">' . strpart(' ', 0, strlen(line("$")) - strlen(s:lnum)) . s:lnum . '</span> '
|
347
|
+
endif
|
348
|
+
|
349
|
+
" Loop over each character in the line
|
350
|
+
let s:col = 1
|
351
|
+
while s:col <= s:len
|
352
|
+
let s:startcol = s:col " The start column for processing text
|
353
|
+
let s:id = synID(s:lnum, s:col, 1)
|
354
|
+
let s:col = s:col + 1
|
355
|
+
" Speed loop (it's small - that's the trick)
|
356
|
+
" Go along till we find a change in synID
|
357
|
+
while s:col <= s:len && s:id == synID(s:lnum, s:col, 1) | let s:col = s:col + 1 | endwhile
|
358
|
+
|
359
|
+
" Output the text with the same synID, with class set to c{s:id}
|
360
|
+
let s:id = synIDtrans(s:id)
|
361
|
+
let s:new = s:new . '<span class="c' . s:id . '">' . substitute(substitute(substitute(substitute(substitute(strpart(s:line, s:startcol - 1, s:col - s:startcol), '&', '\&', 'g'), '<', '\<', 'g'), '>', '\>', 'g'), '"', '\"', 'g'), "\x0c", '<hr class="PAGE-BREAK">', 'g') . '</span>'
|
362
|
+
" Add the class to class list if it's not there yet
|
363
|
+
if stridx(s:idlist, "," . s:id . ",") == -1
|
364
|
+
let s:idlist = s:idlist . s:id . ","
|
365
|
+
endif
|
366
|
+
|
367
|
+
if s:col > s:len
|
368
|
+
break
|
369
|
+
endif
|
370
|
+
endwhile
|
371
|
+
|
372
|
+
" Expand tabs
|
373
|
+
let s:pad=0
|
374
|
+
let s:start = 0
|
375
|
+
let s:idx = stridx(s:line, "\t")
|
376
|
+
while s:idx >= 0
|
377
|
+
let s:i = &ts - ((s:start + s:pad + s:idx) % &ts)
|
378
|
+
let s:new = substitute(s:new, '\t', strpart(s:expandedtab, 0, s:i), '')
|
379
|
+
let s:pad = s:pad + s:i - 1
|
380
|
+
let s:start = s:start + s:idx + 1
|
381
|
+
let s:idx = stridx(strpart(s:line, s:start), "\t")
|
382
|
+
endwhile
|
383
|
+
|
384
|
+
exe "normal \<C-W>pa" . strtrans(s:new) . "\n\e\<C-W>p"
|
385
|
+
let s:lnum = s:lnum + 1
|
386
|
+
+
|
387
|
+
endwhile
|
388
|
+
" Finish with the last line
|
389
|
+
if !exists("html_no_header")
|
390
|
+
exe "normal \<C-W>pa</pre>\n</body>\n</html>\e"
|
391
|
+
else
|
392
|
+
exe "normal \<C-W>p"
|
393
|
+
end
|
394
|
+
|
395
|
+
" Now, when we finally know which, we define the colors and styles
|
396
|
+
if exists("html_use_css")
|
397
|
+
8
|
398
|
+
endif
|
399
|
+
|
400
|
+
" Find out the background and foreground color.
|
401
|
+
let s:fgc = s:HtmlColor(synIDattr(highlightID("Normal"), "fg#", s:whatterm))
|
402
|
+
let s:bgc = s:HtmlColor(synIDattr(highlightID("Normal"), "bg#", s:whatterm))
|
403
|
+
if s:fgc == ""
|
404
|
+
let s:fgc = ( &background == "dark" ? "#ffffff" : "#000000" )
|
405
|
+
endif
|
406
|
+
if s:bgc == ""
|
407
|
+
let s:bgc = ( &background == "dark" ? "#000000" : "#ffffff" )
|
408
|
+
endif
|
409
|
+
|
410
|
+
" Normal/global attributes
|
411
|
+
" For Netscape 4, set <body> attributes too, though, strictly speaking, it's
|
412
|
+
" incorrect.
|
413
|
+
if exists("html_use_css")
|
414
|
+
execute "normal A\npre { color: " . s:fgc . "; background-color: " . s:bgc . "; }\e"
|
415
|
+
yank
|
416
|
+
put
|
417
|
+
execute "normal ^cwbody\e"
|
418
|
+
else
|
419
|
+
execute '%s:<body>:<body ' . 'bgcolor="' . s:bgc . '" text="' . s:fgc . '">'
|
420
|
+
endif
|
421
|
+
|
422
|
+
" Line numbering attributes
|
423
|
+
if s:numblines
|
424
|
+
if exists("html_use_css")
|
425
|
+
execute "normal A\n.lnr { " . s:CSS1(highlightID("LineNr")) . "}\e"
|
426
|
+
else
|
427
|
+
execute '%s+<span class="lnr">\([^<]*\)</span>+' . s:HtmlOpening(highlightID("LineNr")) . '\1' . s:HtmlClosing(highlightID("LineNr")) . '+g'
|
428
|
+
endif
|
429
|
+
endif
|
430
|
+
|
431
|
+
" Gather attributes for all other classes
|
432
|
+
let s:idlist = strpart(s:idlist, 1)
|
433
|
+
while s:idlist != ""
|
434
|
+
let s:attr = ""
|
435
|
+
let s:col = stridx(s:idlist, ",")
|
436
|
+
let s:id = strpart(s:idlist, 0, s:col)
|
437
|
+
let s:idlist = strpart(s:idlist, s:col + 1)
|
438
|
+
let s:attr = s:CSS1(s:id)
|
439
|
+
" If the class has some attributes, export the style, otherwise DELETE all
|
440
|
+
" its occurences to make the HTML shorter
|
441
|
+
if s:attr != ""
|
442
|
+
if exists("html_use_css")
|
443
|
+
execute "normal A\n.c" . s:id . " { " . s:attr . "}"
|
444
|
+
else
|
445
|
+
execute '%s+<span class="c' . s:id . '">\([^<]*\)</span>+' . s:HtmlOpening(s:id) . '\1' . s:HtmlClosing(s:id) . '+g'
|
446
|
+
endif
|
447
|
+
else
|
448
|
+
execute '%s+<span class="c' . s:id . '">\([^<]*\)</span>+\1+g'
|
449
|
+
8
|
450
|
+
endif
|
451
|
+
endwhile
|
452
|
+
|
453
|
+
" Cleanup
|
454
|
+
%s:\s\+$::e
|
455
|
+
|
456
|
+
" Restore old settings
|
457
|
+
let &report = s:old_report
|
458
|
+
let &title = s:old_title
|
459
|
+
let &icon = s:old_icon
|
460
|
+
let &paste = s:old_paste
|
461
|
+
let @/ = s:old_search
|
462
|
+
wincmd p
|
463
|
+
let &l:et = s:old_et
|
464
|
+
wincmd p
|
465
|
+
|
466
|
+
" Save a little bit of memory (worths doing?)
|
467
|
+
unlet s:old_et s:old_paste s:old_icon s:old_report s:old_title s:old_search
|
468
|
+
unlet s:whatterm s:idlist s:lnum s:end s:fgc s:bgc
|
469
|
+
unlet! s:col s:id s:attr s:len s:line s:new s:did_retab s:numblines
|
470
|
+
delfunc s:HtmlColor
|
471
|
+
delfunc s:CSS1
|
472
|
+
if !exists("html_use_css")
|
473
|
+
delfunc s:HtmlOpening
|
474
|
+
delfunc s:HtmlClosing
|
475
|
+
endif
|