importing the programlisting xsl stuff that does the syntax highlighting
This commit is contained in:
parent
5bc9d104a6
commit
dfaba8db30
19
manual/docbook/programlisting/README
Normal file
19
manual/docbook/programlisting/README
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Making syntax highlighting work
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
~/p/xsieve/opt/bin/xsieve -xinclude -o testdoc.html testdoc.xsl testdoc.xml
|
||||||
|
|
||||||
|
Development in this directory will be cancelled.
|
||||||
|
Something like $XSIEVE/examples/syntax_highlighting will be used.
|
||||||
|
|
||||||
|
|
||||||
|
colorer.scm: the main part, uniting trees
|
||||||
|
run-colorer.scm: low-level driver to execute a colorizing program
|
||||||
|
colorer.xsl: processing of "programlisting"
|
||||||
|
|
||||||
|
testdoc.* + test.xml: testing
|
||||||
|
run.sh: run "testdoc" conversion
|
||||||
|
|
||||||
|
testdata.xml, test.scm: testing
|
||||||
|
test-one.scm: testing
|
||||||
|
|
64
manual/docbook/programlisting/colorer-html.xsl
Normal file
64
manual/docbook/programlisting/colorer-html.xsl
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:syn="http://ns.laxan.com/text-vimcolor/1" version="1.0">
|
||||||
|
<!-- $Id: colorer-html.xsl,v 1.2 2006/04/29 05:48:16 olpa Exp $ -->
|
||||||
|
|
||||||
|
<xsl:template match="syn:Comment">
|
||||||
|
<span style="color:#0000FF;">
|
||||||
|
<xsl:apply-templates />
|
||||||
|
</span>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:Constant">
|
||||||
|
<span style="color:#FF00FF;">
|
||||||
|
<xsl:apply-templates />
|
||||||
|
</span>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:Identifier">
|
||||||
|
<span style="color:#008B8B;">
|
||||||
|
<xsl:apply-templates />
|
||||||
|
</span>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:Statement">
|
||||||
|
<span style="color:#A52A2A; font-weight:bold;">
|
||||||
|
<xsl:apply-templates />
|
||||||
|
</span>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:PreProc">
|
||||||
|
<span style="color:#A020F0;">
|
||||||
|
<xsl:apply-templates />
|
||||||
|
</span>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:Type">
|
||||||
|
<span style="color:#2E8B57; font-weight:bold;">
|
||||||
|
<xsl:apply-templates />
|
||||||
|
</span>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:Special">
|
||||||
|
<span style="color:#6A5ACD;">
|
||||||
|
<xsl:apply-templates />
|
||||||
|
</span>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:Underlined">
|
||||||
|
<span style="color:#000000; text-decoration:underline;">
|
||||||
|
<xsl:apply-templates />
|
||||||
|
</span>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:Error">
|
||||||
|
<span style="color:#FFFFFF; background:#FF0000 none;">
|
||||||
|
<xsl:apply-templates />
|
||||||
|
</span>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:Todo">
|
||||||
|
<span style="color:#0000FF; background: #FFFF00 none;">
|
||||||
|
<xsl:apply-templates />
|
||||||
|
</span>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
22
manual/docbook/programlisting/colorer-one.xsl
Normal file
22
manual/docbook/programlisting/colorer-one.xsl
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<xsl:stylesheet
|
||||||
|
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
|
||||||
|
version = "1.0"
|
||||||
|
xmlns:s = "http://xsieve.sourceforge.net"
|
||||||
|
xmlns:syn = "http://ns.laxan.com/text-vimcolor/1"
|
||||||
|
extension-element-prefixes="s">
|
||||||
|
<!-- $Id: colorer-one.xsl,v 1.1 2006/05/22 04:23:51 olpa Exp $ -->
|
||||||
|
|
||||||
|
<xsl:import href="colorer.xsl" />
|
||||||
|
|
||||||
|
<xsl:template match="node()|@*">
|
||||||
|
<xsl:copy>
|
||||||
|
<xsl:apply-templates select="node()|@*" />
|
||||||
|
</xsl:copy>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="programlisting | screen[starts-with(@role,'colorer:')]">
|
||||||
|
<xsl:apply-imports />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
|
|
131
manual/docbook/programlisting/colorer.scm
Normal file
131
manual/docbook/programlisting/colorer.scm
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
; $Id: colorer.scm,v 1.8 2006/04/29 04:49:48 olpa Exp $
|
||||||
|
|
||||||
|
; construct a tree from the text and path
|
||||||
|
; "ignore" is a list of path element which shouldn't be added to the tree
|
||||||
|
; each path item is either symbol, which is the node name,
|
||||||
|
; either (symbol (@ ...)), which is the node name and the attribute node.
|
||||||
|
; It is supposed that elements with attributes aren't in the ignore list.
|
||||||
|
(define (colorer:path-to-tree text path ignore)
|
||||||
|
(let loop ((tree text) (path path))
|
||||||
|
(if (null? path)
|
||||||
|
tree
|
||||||
|
(let (
|
||||||
|
(cur (car path))
|
||||||
|
(nodeset (cons tree '())))
|
||||||
|
(loop
|
||||||
|
(if (pair? cur)
|
||||||
|
(append cur nodeset)
|
||||||
|
(if (memq cur ignore) tree (cons cur nodeset)))
|
||||||
|
(cdr path))))))
|
||||||
|
|
||||||
|
; A fragment of the text node handler
|
||||||
|
(define-macro (%colorer:on-text)
|
||||||
|
(quote (let loop ((cur cur))
|
||||||
|
(let* (
|
||||||
|
(len-buf (string-length buf))
|
||||||
|
(len-cur (string-length cur))
|
||||||
|
(len-min (min len-buf len-cur)))
|
||||||
|
(if (> len-cur 0) ; the text node in the h-tree isn't finished yet?
|
||||||
|
(let (
|
||||||
|
(result ; result is either a tree, eiter #f
|
||||||
|
(if (zero? len-buf) ; the text node in the main tree finished?
|
||||||
|
#f
|
||||||
|
(colorer:path-to-tree
|
||||||
|
(substring buf 0 len-min)
|
||||||
|
path
|
||||||
|
ignore))))
|
||||||
|
; Update buffer, switch to the main tree traversing,
|
||||||
|
; continue h-tree traversing on switching back
|
||||||
|
(set! buf (substring buf len-min len-buf))
|
||||||
|
(call-with-current-continuation (lambda (here)
|
||||||
|
(set! walker here)
|
||||||
|
(yield result)))
|
||||||
|
(loop (substring cur len-min len-cur))))))))
|
||||||
|
|
||||||
|
; A fragment of the node and attribute handler
|
||||||
|
(define-macro (%colorer:on-pair)
|
||||||
|
(quote (let ((elem (car cur)))
|
||||||
|
(if (eq? elem '@)
|
||||||
|
; attribute: attach to the path
|
||||||
|
(set-car! path (list (car path) cur))
|
||||||
|
; element: update path, continue traversing
|
||||||
|
(let ((path (cons (car cur) path)))
|
||||||
|
(for-each
|
||||||
|
(lambda (kid) (loop kid path))
|
||||||
|
(cdr cur)))))))
|
||||||
|
|
||||||
|
; generator of highlighted chunks.
|
||||||
|
; Creation:
|
||||||
|
; (define highlighter (colorer:join-markup-stepper highlight-tree ignore))
|
||||||
|
; Usage step:
|
||||||
|
; (highlighter more-buf)
|
||||||
|
; where more-buf either text, either #f. Each step returns either a
|
||||||
|
; subtree, either #f if buffer is over.
|
||||||
|
(define (colorer:join-markup-stepper highlight-tree ignore)
|
||||||
|
(letrec (
|
||||||
|
(buf #f)
|
||||||
|
(yield #f)
|
||||||
|
; The main loop
|
||||||
|
(walker-loop (lambda (cur path)
|
||||||
|
(let loop ((cur cur) (path path))
|
||||||
|
(if (pair? cur)
|
||||||
|
(%colorer:on-pair)
|
||||||
|
(%colorer:on-text)))
|
||||||
|
; The highlighting tree is over. Stop looping.
|
||||||
|
; If the main tree isn't over (impossible),
|
||||||
|
; just return the data from main tree.
|
||||||
|
(set! walker (lambda (dummy)
|
||||||
|
(if (and buf (> (string-length buf) 0))
|
||||||
|
(let ((old-buf buf))
|
||||||
|
(set! buf #f)
|
||||||
|
(yield old-buf))
|
||||||
|
(yield #f))))
|
||||||
|
(walker 'dummy)))
|
||||||
|
; Set buffer, continue looping
|
||||||
|
(walker-entry
|
||||||
|
(lambda (new-buf)
|
||||||
|
(if new-buf
|
||||||
|
(set! buf new-buf))
|
||||||
|
(call-with-current-continuation (lambda (here)
|
||||||
|
(set! yield here)
|
||||||
|
(walker 'resume)))))
|
||||||
|
; Use once, than re-set
|
||||||
|
(walker
|
||||||
|
(lambda (dummy)
|
||||||
|
(set! walker walker-loop)
|
||||||
|
(walker-loop highlight-tree '()))))
|
||||||
|
; create generator
|
||||||
|
walker-entry))
|
||||||
|
|
||||||
|
; add the colorer namespace to the tree
|
||||||
|
(define (colorer:wrap-by-ns tree)
|
||||||
|
`(syn:syntax (@ (@
|
||||||
|
(*NAMESPACES* (syn "http://ns.laxan.com/text-vimcolor/1"))))
|
||||||
|
,tree))
|
||||||
|
|
||||||
|
; join main markup with highlighting markup
|
||||||
|
(define colorer:id (lambda x x))
|
||||||
|
(define (colorer:join-markup main-tree highlight-tree ignore)
|
||||||
|
(let ((stepper (colorer:join-markup-stepper highlight-tree ignore)))
|
||||||
|
(colorer:wrap-by-ns
|
||||||
|
; Walk over the main tree
|
||||||
|
(pre-post-order main-tree `(
|
||||||
|
; Comments, entities etc are not possible, so only few special cases
|
||||||
|
(*PI* *preorder* . ,colorer:id)
|
||||||
|
(@ *preorder* . ,colorer:id)
|
||||||
|
(*default* . ,colorer:id)
|
||||||
|
; Text node: split on highlighted subtrees
|
||||||
|
(*text* . ,(lambda (trigger str)
|
||||||
|
(let loop (
|
||||||
|
(chunks '())
|
||||||
|
(tree (stepper str)))
|
||||||
|
(if tree
|
||||||
|
; Loop while trees are being generated
|
||||||
|
(loop (cons tree chunks) (stepper #f))
|
||||||
|
; The node is processed. If there is only one chunk, return
|
||||||
|
; it, otherwise wrap the nodeset of chunks by a dummy
|
||||||
|
; element. Handle also impossible case of absense of chunks.
|
||||||
|
(cond
|
||||||
|
((null? chunks) "")
|
||||||
|
((null? (cdr chunks)) (car chunks))
|
||||||
|
(else (cons 'syn:syntax (reverse chunks)))))))))))))
|
54
manual/docbook/programlisting/colorer.xsl
Normal file
54
manual/docbook/programlisting/colorer.xsl
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<xsl:stylesheet
|
||||||
|
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
|
||||||
|
version = "1.0"
|
||||||
|
xmlns:s = "http://xsieve.sourceforge.net"
|
||||||
|
xmlns:syn = "http://ns.laxan.com/text-vimcolor/1"
|
||||||
|
extension-element-prefixes="s">
|
||||||
|
<!-- $Id: colorer.xsl,v 1.6 2006/04/29 04:30:03 olpa Exp $ -->
|
||||||
|
|
||||||
|
<xsl:param name="colorer.bin">/home/clients/jhassine/doctrine/trunk/manual/docbook/programlisting/vimcolor/vimcolor-wrapper</xsl:param>
|
||||||
|
<xsl:param name="colorer.params">--format xml</xsl:param>
|
||||||
|
<xsl:param name="colorer.param.type">--filetype </xsl:param>
|
||||||
|
<xsl:param name="colorer.param.outfile">--output </xsl:param>
|
||||||
|
|
||||||
|
<s:init>
|
||||||
|
(load-from-path "sxml-utils.scm")
|
||||||
|
(load-from-path "colorer.scm")
|
||||||
|
(load-from-path "run-colorer.scm")
|
||||||
|
</s:init>
|
||||||
|
|
||||||
|
<!-- ProgramListing is colorized -->
|
||||||
|
<xsl:template match="programlisting[parent::syn:syntax] | screen[parent::syn:syntax]" priority="2">
|
||||||
|
<xsl:apply-imports/>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!-- Colorize ProgramListing -->
|
||||||
|
<xsl:template match="programlisting | screen[starts-with(@role,'colorer:')]">
|
||||||
|
<xsl:variable name="type">
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="self::screen"><xsl:value-of select="substring-after(@role,':')"/></xsl:when>
|
||||||
|
<xsl:otherwise><xsl:value-of select="@role"/></xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:variable>
|
||||||
|
<s:scheme>
|
||||||
|
(let* (
|
||||||
|
(highlighted-tree (run-colorer (x:eval "string(.)") (x:eval "string($type)")))
|
||||||
|
(current (x:current))
|
||||||
|
(united-tree
|
||||||
|
(if (not highlighted-tree)
|
||||||
|
#f
|
||||||
|
(colorer:join-markup current highlighted-tree '()))))
|
||||||
|
(x:apply-templates
|
||||||
|
'with-param 'colorized #t
|
||||||
|
(if united-tree
|
||||||
|
united-tree
|
||||||
|
(colorer:wrap-by-ns current))))
|
||||||
|
</s:scheme>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:syntax">
|
||||||
|
<xsl:apply-templates select="node()"/>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
|
|
3
manual/docbook/programlisting/colors/CVS/Entries
Normal file
3
manual/docbook/programlisting/colors/CVS/Entries
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/Makefile/1.1/Mon May 22 04:24:28 2006//
|
||||||
|
/vim2xslt.pl/1.1/Mon May 22 04:24:28 2006//
|
||||||
|
D
|
1
manual/docbook/programlisting/colors/CVS/Repository
Normal file
1
manual/docbook/programlisting/colors/CVS/Repository
Normal file
@ -0,0 +1 @@
|
|||||||
|
xsieve/experiments/programlisting/colors
|
1
manual/docbook/programlisting/colors/CVS/Root
Normal file
1
manual/docbook/programlisting/colors/CVS/Root
Normal file
@ -0,0 +1 @@
|
|||||||
|
:pserver:anonymous@xsieve.cvs.sourceforge.net:/cvsroot/xsieve
|
9
manual/docbook/programlisting/colors/Makefile
Normal file
9
manual/docbook/programlisting/colors/Makefile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
vim_colors_dir = /usr/share/vim/colors
|
||||||
|
|
||||||
|
vim_files := $(wildcard $(vim_colors_dir)/*.vim)
|
||||||
|
xslt_files = $(patsubst %.vim,%.xsl,$(notdir $(vim_files)))
|
||||||
|
|
||||||
|
all: $(xslt_files)
|
||||||
|
|
||||||
|
%.xsl: $(vim_colors_dir)/%.vim
|
||||||
|
perl vim2xslt.pl $< >$@
|
16
manual/docbook/programlisting/colors/vim2xslt.pl
Normal file
16
manual/docbook/programlisting/colors/vim2xslt.pl
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
# Take vim colors file and convert it to an XSLT stylesheet
|
||||||
|
|
||||||
|
# The only types vim-textcolor produces
|
||||||
|
my %syntax_data = (
|
||||||
|
'Comment' => undef,
|
||||||
|
'Constant' => undef,
|
||||||
|
'Identifier' => undef,
|
||||||
|
'Statement' => undef,
|
||||||
|
'PreProc' => undef,
|
||||||
|
'Type' => undef,
|
||||||
|
'Special' => undef,
|
||||||
|
'Underlined' => undef,
|
||||||
|
'Error' => undef,
|
||||||
|
'Todo' => undef
|
||||||
|
);
|
12
manual/docbook/programlisting/id.xsl
Normal file
12
manual/docbook/programlisting/id.xsl
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<xsl:stylesheet
|
||||||
|
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
|
||||||
|
version = "1.0">
|
||||||
|
|
||||||
|
<xsl:template match="node()">
|
||||||
|
<xsl:copy>
|
||||||
|
<xsl:apply-templates/>
|
||||||
|
</xsl:copy>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
|
|
58
manual/docbook/programlisting/index.html
Normal file
58
manual/docbook/programlisting/index.html
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Syntax highlighting for DocBook program listings</title>
|
||||||
|
</head>
|
||||||
|
<body style="background:#ffffff;">
|
||||||
|
<h1>Syntax highlighting for DocBook program listings</h1>
|
||||||
|
<p>Highlight content of <tt>ProgramListing</tt> using <a href="http://xsieve.sourceforge.net/">XSieve</a> and Vim. Example:</p>
|
||||||
|
<table border="0" cellspacing="5" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<th valign="top">DocBook</th>
|
||||||
|
<td>
|
||||||
|
<pre style="background:#f0f0f0;"><programlisting role="xml">
|
||||||
|
&lt;para>Hello, <emphasis>&amp;who;</emphasis
|
||||||
|
>!&lt;/para> <co id="who-entity"/>
|
||||||
|
</programlisting></pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>HTML result </th>
|
||||||
|
<td>
|
||||||
|
<pre style="background:#f0f0f0;">
|
||||||
|
<span style="color:#008B8B;"><para></span>Hello, <span class="emphasis"><em><span style="color:#2E8B57; font-weight:bold;">&</span><span style="color:#A52A2A; font-weight:bold;">who</span><span style="color:#2E8B57; font-weight:bold;">;</span></em></span>!<span style="color:#008B8B;"></para></span> (1)</pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<a href="xsieve-programlisting.zip">Download</a> xsieve-programlisting.zip.
|
||||||
|
|
||||||
|
<h2>Usage</h2>
|
||||||
|
|
||||||
|
<p>Set the correct path to the script <tt>vimcolor-wrapper</tt> in <tt>colorer.xsl</tt>.</p>
|
||||||
|
|
||||||
|
<p>Create an XSLT wrapper which imports DocBook and colorer stylesheets:</p>
|
||||||
|
|
||||||
|
<pre style="background:#f0f0f0;">
|
||||||
|
<font color="#008b8b"><</font><font color="#6a5acd">xsl</font><font color="#0000ff">:</font><font color="#a52a2a"><b>stylesheet</b></font><font color="#008b8b"> ...></font>
|
||||||
|
...
|
||||||
|
<font color="#008b8b"><</font><font color="#6a5acd">xsl</font><font color="#0000ff">:</font><font color="#a52a2a"><b>import</b></font><font color="#008b8b"> </font><font color="#2e8b57"><b>href</b></font>=<font color="#ff00ff">"..../docbook.xsl"</font><font color="#008b8b">></font> (1)
|
||||||
|
<font color="#008b8b"><</font><font color="#6a5acd">xsl</font><font color="#0000ff">:</font><font color="#a52a2a"><b>import</b></font><font color="#008b8b"> </font><font color="#2e8b57"><b>href</b></font>=<font color="#ff00ff">"..../colorer.xsl"</font><font color="#008b8b">></font> (2)
|
||||||
|
<font color="#008b8b"><</font><font color="#6a5acd">xsl</font><font color="#0000ff">:</font><font color="#a52a2a"><b>import</b></font><font color="#008b8b"> </font><font color="#2e8b57"><b>href</b></font>=<font color="#ff00ff">"..../colorer-html.xsl"</font><font color="#008b8b">></font> (3)
|
||||||
|
|
||||||
|
... Your DocBook customization layer ...
|
||||||
|
|
||||||
|
<font color="#008b8b"></</font><font color="#6a5acd">xsl</font><font color="#0000ff">:</font><font color="#a52a2a"><b>stylesheet</b></font><font color="#008b8b">></font>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p><b>(1)</b> The path to the DocBook XSLT stylesheet. For example, <tt>/usr/share/xml/docbook/xsl-stylesheets/html/docbook.xsl</tt><br />
|
||||||
|
<b>(2)</b> The path to the colorer XSLT stylesheet.<br />
|
||||||
|
<b>(3)</b> Or <tt>colorer-fo.xsl</tt> for FO output.</p>
|
||||||
|
|
||||||
|
<h2>Test data</h2>
|
||||||
|
|
||||||
|
<p>The package contains test files <tt>test.xml</tt>, <tt>testdoc.xsl</tt> and <tt>testdoc.html</tt>. Use them as the starting point:</p>
|
||||||
|
|
||||||
|
<pre>xsieve -o testdoc.html --param callout.graphics 0 testdoc.xsl test.xml</pre>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
6
manual/docbook/programlisting/mkdist.sh
Normal file
6
manual/docbook/programlisting/mkdist.sh
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
rm -rf xsieve-programlisting.zip xsieve-programlisting
|
||||||
|
mkdir xsieve-programlisting
|
||||||
|
rsync -av --exclude CVS vimcolor xsieve-programlisting/
|
||||||
|
cp colorer.xsl colorer-html.xsl testdoc.xsl index.html sxml-utils.scm colorer.scm run-colorer.scm test.xml testdoc.html xsieve-programlisting/
|
||||||
|
zip xsieve-programlisting.zip -r xsieve-programlisting
|
||||||
|
|
51
manual/docbook/programlisting/run-colorer.scm
Normal file
51
manual/docbook/programlisting/run-colorer.scm
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
; Run colorer and return the result as SXML
|
||||||
|
; $Id: run-colorer.scm,v 1.6 2006/04/29 05:47:24 olpa Exp $
|
||||||
|
|
||||||
|
(define colorer-bin #f)
|
||||||
|
(define colorer-params #f)
|
||||||
|
(define colorer-param-type #f)
|
||||||
|
(define colorer-param-outfile #f)
|
||||||
|
|
||||||
|
; Initialize colorer variables (only once)
|
||||||
|
(define (init-colorer-variables)
|
||||||
|
(if (not colorer-bin) (begin
|
||||||
|
(set! colorer-bin (x:eval "string($colorer.bin)"))
|
||||||
|
(set! colorer-params (x:eval "string($colorer.params)"))
|
||||||
|
(set! colorer-param-type (x:eval "string($colorer.param.type)"))
|
||||||
|
(set! colorer-param-outfile (x:eval "string($colorer.param.outfile)")))))
|
||||||
|
|
||||||
|
(define-macro (no-errors . body)
|
||||||
|
`(catch #t (lambda () ,@body) (lambda (dummy . args) #f)))
|
||||||
|
|
||||||
|
(define (run-colorer program-text program-type)
|
||||||
|
; Some sanity check
|
||||||
|
(init-colorer-variables)
|
||||||
|
(if (not (and program-text (> (string-length program-text) 0)))
|
||||||
|
#f
|
||||||
|
(let* (
|
||||||
|
; Construct command line to run the colorer
|
||||||
|
(infile (tmpnam)) ; for the program text
|
||||||
|
(outfile (tmpnam)) ; for the colored tokens
|
||||||
|
(cmdline (string-append
|
||||||
|
colorer-bin " " colorer-params " "
|
||||||
|
(if (and program-type (> (string-length program-type) 0))
|
||||||
|
(string-append colorer-param-type program-type " ")
|
||||||
|
"")
|
||||||
|
colorer-param-outfile outfile " " infile)))
|
||||||
|
;(display "Command line: ")(display cmdline)(newline)
|
||||||
|
; Ignore errors
|
||||||
|
(no-errors
|
||||||
|
; Write the program text to the file and execute the colorer
|
||||||
|
(with-output-to-file infile
|
||||||
|
(lambda () (display program-text)))
|
||||||
|
;(system (string-append "cp " infile " lastin")) ; DEBUG
|
||||||
|
(system cmdline)
|
||||||
|
;(system (string-append "cp " outfile " last")) ; DEBUG
|
||||||
|
; Load the XML result, cleanup and return the result
|
||||||
|
(let* (
|
||||||
|
(eval-str (string-append "document('file://" outfile "')"))
|
||||||
|
(tree (x:eval eval-str)))
|
||||||
|
(no-errors (delete-file outfile))
|
||||||
|
(no-errors (delete-file infile))
|
||||||
|
; drop "*TOP*" and drop namespace declaration from "syn:syntax"
|
||||||
|
(cons 'syn:syntax (cdr (cdadar tree))))))))
|
1
manual/docbook/programlisting/run.sh
Normal file
1
manual/docbook/programlisting/run.sh
Normal file
@ -0,0 +1 @@
|
|||||||
|
~/p/xsieve/opt/bin/xsieve --xinclude -o testdoc.html testdoc.xsl testdoc.xml
|
2
manual/docbook/programlisting/run2.sh
Normal file
2
manual/docbook/programlisting/run2.sh
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#~/p/xsieve/opt/bin/xsieve --xinclude -o testdoc.html testdoc.xsl /home/olpa/p/xsieve/doc/book/xsieve.xml
|
||||||
|
~/p/xsieve/opt/bin/xsieve -o testdoc.html testdoc.xsl xsieve.xml
|
1
manual/docbook/programlisting/run3.sh
Normal file
1
manual/docbook/programlisting/run3.sh
Normal file
@ -0,0 +1 @@
|
|||||||
|
~/p/xsieve/opt/bin/xsieve --xinclude -o testdoc.html colorer-one.xsl /home/olpa/p/xsieve/example/hello/doc/listing2.xml
|
2
manual/docbook/programlisting/run4.sh
Normal file
2
manual/docbook/programlisting/run4.sh
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#~/p/xsieve/opt/bin/xsieve --xinclude -o testdoc.html testdoc.xsl /home/olpa/p/xsieve/doc/book/xsieve.xml
|
||||||
|
~/p/xsieve/opt/bin/xsieve -o testdoc.html --param callout.graphics 0 testdoc.xsl /home/olpa/p/xsieve/doc/project/xtech2006/programlisting/test.xml
|
35
manual/docbook/programlisting/sxml-utils.scm
Normal file
35
manual/docbook/programlisting/sxml-utils.scm
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
; $Id: sxml-utils.scm,v 1.1 2006/03/02 04:32:58 olpa Exp $
|
||||||
|
; A copy-paste of a part of the SXML library
|
||||||
|
|
||||||
|
; from CVS: SSAX/lib/SXML-tree-trans.scm
|
||||||
|
(define (pre-post-order tree bindings)
|
||||||
|
(let* ((default-binding (assq '*default* bindings))
|
||||||
|
(text-binding (or (assq '*text* bindings) default-binding))
|
||||||
|
(text-handler ; Cache default and text bindings
|
||||||
|
(and text-binding
|
||||||
|
(if (procedure? (cdr text-binding))
|
||||||
|
(cdr text-binding) (cddr text-binding)))))
|
||||||
|
(let loop ((tree tree))
|
||||||
|
(cond
|
||||||
|
((null? tree) '())
|
||||||
|
((not (pair? tree))
|
||||||
|
(let ((trigger '*text*))
|
||||||
|
(if text-handler (text-handler trigger tree)
|
||||||
|
(error "Unknown binding for " trigger " and no default"))))
|
||||||
|
((not (symbol? (car tree))) (map loop tree)) ; tree is a nodelist
|
||||||
|
(else ; tree is an SXML node
|
||||||
|
(let* ((trigger (car tree))
|
||||||
|
(binding (or (assq trigger bindings) default-binding)))
|
||||||
|
(cond
|
||||||
|
((not binding)
|
||||||
|
(error "Unknown binding for " trigger " and no default"))
|
||||||
|
((not (pair? (cdr binding))) ; must be a procedure: handler
|
||||||
|
(apply (cdr binding) trigger (map loop (cdr tree))))
|
||||||
|
((eq? '*preorder* (cadr binding))
|
||||||
|
(apply (cddr binding) tree))
|
||||||
|
((eq? '*macro* (cadr binding))
|
||||||
|
(loop (apply (cddr binding) tree)))
|
||||||
|
(else ; (cadr binding) is a local binding
|
||||||
|
(apply (cddr binding) trigger
|
||||||
|
(pre-post-order (cdr tree) (append (cadr binding) bindings)))
|
||||||
|
))))))))
|
13
manual/docbook/programlisting/test-one.scm
Normal file
13
manual/docbook/programlisting/test-one.scm
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
(load "sxml-utils.scm")
|
||||||
|
(load "colorer.scm")
|
||||||
|
|
||||||
|
(define main-tree '(programlisting (*PI* a "b") (@ (format "linespecific")) "<article id=\"hw\">
|
||||||
|
<title>Hello</title>
|
||||||
|
<para>Hello <object>World</object>!</para>
|
||||||
|
</article>"))
|
||||||
|
|
||||||
|
(define h-tree "")
|
||||||
|
|
||||||
|
(define result (colorer:join-markup main-tree h-tree '(h)))
|
||||||
|
|
||||||
|
(write result)
|
16
manual/docbook/programlisting/test.scm
Normal file
16
manual/docbook/programlisting/test.scm
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
; $Id: test.scm,v 1.2 2006/03/02 06:01:06 olpa Exp $
|
||||||
|
|
||||||
|
(define (test-case main-tree h-tree expected-result)
|
||||||
|
(display "------- Running a test case...")
|
||||||
|
(let ((result (caddr (colorer:join-markup main-tree h-tree '(h)))))
|
||||||
|
(if (equal? result expected-result)
|
||||||
|
(begin
|
||||||
|
(display "Ok")(newline))
|
||||||
|
(begin
|
||||||
|
(display "Error")(newline)
|
||||||
|
(display "Expected: ")(write expected-result)(newline)
|
||||||
|
(display "Result: ")(write result)(newline)))))
|
||||||
|
|
||||||
|
(load "sxml-utils.scm")
|
||||||
|
(load "colorer.scm")
|
||||||
|
(load "testdata.scm")
|
9
manual/docbook/programlisting/test.xml
Normal file
9
manual/docbook/programlisting/test.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<article>
|
||||||
|
<title>Testing Syntax Highlighting</title>
|
||||||
|
<para>Testing syntax highlighting</para>
|
||||||
|
<programlisting role="xml">
|
||||||
|
<para>Hello, <emphasis>&who;</emphasis
|
||||||
|
>!</para> <co id="who-entity"/>
|
||||||
|
</programlisting>
|
||||||
|
</article>
|
65
manual/docbook/programlisting/testdata.scm
Normal file
65
manual/docbook/programlisting/testdata.scm
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
; test cases for joining parallel markup
|
||||||
|
; $Id: testdata.scm,v 1.2 2006/03/02 05:58:55 olpa Exp $
|
||||||
|
; (test-case in-xml also-xml joined-xml)
|
||||||
|
|
||||||
|
; the simplest test, no highlighting at all
|
||||||
|
(test-case
|
||||||
|
'(i "012")
|
||||||
|
'(h "012")
|
||||||
|
'(i "012"))
|
||||||
|
|
||||||
|
; the simplest test, some highlighting
|
||||||
|
(test-case
|
||||||
|
'(i "012")
|
||||||
|
'(h "0" (a "1") "2")
|
||||||
|
'(i (colorer:dummy "0" (a "1") "2")))
|
||||||
|
|
||||||
|
; the size of text is different
|
||||||
|
(test-case
|
||||||
|
'(i "0123456789")
|
||||||
|
'(h (a "01") "234" (b "56") "7")
|
||||||
|
'(i (colorer:dummy (a "01") "234" (b "56") "7" "89")))
|
||||||
|
|
||||||
|
(test-case
|
||||||
|
'(i "01234567")
|
||||||
|
'(h "0" (a "12") "345" (b "5789"))
|
||||||
|
'(i (colorer:dummy "0" (a "12") "345" (b "67"))))
|
||||||
|
|
||||||
|
; the text of the main tree is not corrupted
|
||||||
|
(test-case
|
||||||
|
'(i "012345")
|
||||||
|
'(h "ab" (c "cd") "ef")
|
||||||
|
'(i (colorer:dummy "01" (c "23") "45")))
|
||||||
|
|
||||||
|
; attributes are saved
|
||||||
|
(test-case
|
||||||
|
'(i "012345")
|
||||||
|
'(h "01"
|
||||||
|
(a (@ (a1 "a1") (a2 "a2"))
|
||||||
|
(b (@ (b1 "b1") (b2 "b2"))
|
||||||
|
"23"))
|
||||||
|
"45")
|
||||||
|
'(i (colorer:dummy "01"
|
||||||
|
(a (@ (a1 "a1") (a2 "a2"))
|
||||||
|
(b (@ (b1 "b1") (b2 "b2"))
|
||||||
|
"23"))
|
||||||
|
"45")))
|
||||||
|
|
||||||
|
; ordering and nesting of empty tags
|
||||||
|
(test-case
|
||||||
|
'(i "012" (x (y)) (z) "34")
|
||||||
|
'(h "01" (a "23") "4")
|
||||||
|
'(i (colorer:dummy "01" (a "2")) (x (y)) (z) (colorer:dummy (a "3") "4")))
|
||||||
|
|
||||||
|
; intersecting at left
|
||||||
|
(test-case
|
||||||
|
'(i "01" (a "2345" (b "67")))
|
||||||
|
'(h "012" (x (y "3456")) "7")
|
||||||
|
'(i "01" (a (colorer:dummy "2" (x (y "345"))) (b (colorer:dummy (x (y "6")) "7")))))
|
||||||
|
|
||||||
|
; intersecting at right
|
||||||
|
(test-case
|
||||||
|
'(i "01" (a "23" (b "45") "6") "78")
|
||||||
|
'(h "01234" (x (y "56")) "78")
|
||||||
|
'(i "01" (a "23" (b (colorer:dummy "4" (x (y "5")))) (x (y "6"))) "78"))
|
||||||
|
|
5
manual/docbook/programlisting/testdoc.html
Normal file
5
manual/docbook/programlisting/testdoc.html
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Article with code</title><meta name="generator" content="DocBook XSL Stylesheets V1.70.1" /></head><body><div class="article" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="id2434734"></a>Article with code</h2></div></div><hr /></div><p>A sample code:</p><div class="example"><a id="id2433082"></a><p class="title"><b>Example 1. </b></p><div class="example-contents"><div class="article" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="id2434675"></a>Testing Syntax Highlighting</h2></div></div><hr /></div><p>Testing syntax highlighting</p><pre class="programlisting">
|
||||||
|
<span xmlns="" xmlns:syn="http://ns.laxan.com/text-vimcolor/1" style="color:#008B8B;"><para></span>Hello, <span class="emphasis"><em><span xmlns="" xmlns:syn="http://ns.laxan.com/text-vimcolor/1" style="color:#2E8B57; font-weight:bold;">&</span><span xmlns="" xmlns:syn="http://ns.laxan.com/text-vimcolor/1" style="color:#A52A2A; font-weight:bold;">who</span><span xmlns="" xmlns:syn="http://ns.laxan.com/text-vimcolor/1" style="color:#2E8B57; font-weight:bold;">;</span></em></span>!<span xmlns="" xmlns:syn="http://ns.laxan.com/text-vimcolor/1" style="color:#008B8B;"></para></span> <a id="who-entity"></a><img src="images/callouts/1.png" alt="1" border="0" />
|
||||||
|
</pre></div></div></div><br class="example-break" /></div></body></html>
|
7
manual/docbook/programlisting/testdoc.xml
Normal file
7
manual/docbook/programlisting/testdoc.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<article>
|
||||||
|
<title>Article with code</title>
|
||||||
|
<para>A sample code:</para>
|
||||||
|
<example>
|
||||||
|
<xi:include href="test.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||||
|
</example>
|
||||||
|
</article>
|
10
manual/docbook/programlisting/testdoc.xsl
Normal file
10
manual/docbook/programlisting/testdoc.xsl
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<xsl:stylesheet
|
||||||
|
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
|
||||||
|
version = "1.0">
|
||||||
|
|
||||||
|
<xsl:import href="/usr/share/sgml/docbook/xsl-stylesheets-1.70.1/xhtml/docbook.xsl"/>
|
||||||
|
<xsl:import href="colorer.xsl"/>
|
||||||
|
<xsl:import href="colorer-html.xsl"/>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
|
|
6
manual/docbook/programlisting/vimcolor/CVS/Entries
Normal file
6
manual/docbook/programlisting/vimcolor/CVS/Entries
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/README/1.1/Fri Apr 28 07:09:09 2006//
|
||||||
|
/README-Path-Class/1.1/Fri Apr 28 07:09:09 2006//
|
||||||
|
/README-Text-VimColor/1.1/Fri Apr 28 07:09:09 2006//
|
||||||
|
/text-vimcolor/1.1/Fri Apr 28 07:09:09 2006//
|
||||||
|
/vimcolor-wrapper/1.1/Fri Apr 28 07:09:09 2006//
|
||||||
|
D/lib////
|
1
manual/docbook/programlisting/vimcolor/CVS/Repository
Normal file
1
manual/docbook/programlisting/vimcolor/CVS/Repository
Normal file
@ -0,0 +1 @@
|
|||||||
|
xsieve/experiments/programlisting/vimcolor
|
1
manual/docbook/programlisting/vimcolor/CVS/Root
Normal file
1
manual/docbook/programlisting/vimcolor/CVS/Root
Normal file
@ -0,0 +1 @@
|
|||||||
|
:pserver:anonymous@xsieve.cvs.sourceforge.net:/cvsroot/xsieve
|
8
manual/docbook/programlisting/vimcolor/README
Normal file
8
manual/docbook/programlisting/vimcolor/README
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
Command-line syntax highlighting based on vim
|
||||||
|
|
||||||
|
It uses Perl modules Text::VimColor and Path::Class.
|
||||||
|
Perl libraries of these modules are copied to "lib".
|
||||||
|
|
||||||
|
The program "vimcolor-wrapper" sets the path to the
|
||||||
|
local copy of the libraries and runs the original
|
||||||
|
script "text-vimcolor".
|
127
manual/docbook/programlisting/vimcolor/README-Path-Class
Normal file
127
manual/docbook/programlisting/vimcolor/README-Path-Class
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
NAME
|
||||||
|
Path::Class - Cross-platform path specification manipulation
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
use Path::Class;
|
||||||
|
|
||||||
|
my $dir = dir('foo', 'bar'); # Path::Class::Dir object
|
||||||
|
my $file = file('bob', 'file.txt'); # Path::Class::File object
|
||||||
|
|
||||||
|
# Stringifies to 'foo/bar' on Unix, 'foo\bar' on Windows, etc.
|
||||||
|
print "dir: $dir\n";
|
||||||
|
|
||||||
|
# Stringifies to 'bob/file.txt' on Unix, 'bob\file.txt' on Windows
|
||||||
|
print "file: $file\n";
|
||||||
|
|
||||||
|
my $subdir = $dir->subdir('baz'); # foo/bar/baz
|
||||||
|
my $parent = $subdir->parent; # foo/bar
|
||||||
|
my $parent2 = $parent->parent; # foo
|
||||||
|
|
||||||
|
my $dir2 = $file->dir; # bob
|
||||||
|
|
||||||
|
# Work with foreign paths
|
||||||
|
use Path::Class qw(foreign_file foreign_dir);
|
||||||
|
my $file = foreign_file('Mac', ':foo:file.txt');
|
||||||
|
print $file->dir; # :foo:
|
||||||
|
print $file->as_foreign('Win32'); # foo\file.txt
|
||||||
|
|
||||||
|
# Interact with the underlying filesystem:
|
||||||
|
|
||||||
|
# $dir_handle is an IO::Dir object
|
||||||
|
my $dir_handle = $dir->open or die "Can't read $dir: $!";
|
||||||
|
|
||||||
|
# $file_handle is an IO::File object
|
||||||
|
my $file_handle = $file->open($mode) or die "Can't read $file: $!";
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
`Path::Class' is a module for manipulation of file and directory
|
||||||
|
specifications (strings describing their locations, like
|
||||||
|
`'/home/ken/foo.txt'' or `'C:\Windows\Foo.txt'') in a cross-platform
|
||||||
|
manner. It supports pretty much every platform Perl runs on, including
|
||||||
|
Unix, Windows, Mac, VMS, Epoc, Cygwin, OS/2, and NetWare.
|
||||||
|
|
||||||
|
The well-known module `File::Spec' also provides this service, but it's
|
||||||
|
sort of awkward to use well, so people sometimes avoid it, or use it in
|
||||||
|
a way that won't actually work properly on platforms significantly
|
||||||
|
different than the ones they've tested their code on.
|
||||||
|
|
||||||
|
In fact, `Path::Class' uses `File::Spec' internally, wrapping all the
|
||||||
|
unsightly details so you can concentrate on your application code.
|
||||||
|
Whereas `File::Spec' provides functions for some common path
|
||||||
|
manipulations, `Path::Class' provides an object-oriented model of the
|
||||||
|
world of path specifications and their underlying semantics.
|
||||||
|
`File::Spec' doesn't create any objects, and its classes represent the
|
||||||
|
different ways in which paths must be manipulated on various platforms
|
||||||
|
(not a very intuitive concept). `Path::Class' creates objects
|
||||||
|
representing files and directories, and provides methods that relate
|
||||||
|
them to each other. For instance, the following `File::Spec' code:
|
||||||
|
|
||||||
|
my $absolute = File::Spec->file_name_is_absolute(
|
||||||
|
File::Spec->catfile( @dirs, $file )
|
||||||
|
);
|
||||||
|
|
||||||
|
can be written using `Path::Class' as
|
||||||
|
|
||||||
|
my $absolute = Path::Class::File->new( @dirs, $file )->is_absolute;
|
||||||
|
|
||||||
|
or even as
|
||||||
|
|
||||||
|
my $absolute = file( @dirs, $file )->is_absolute;
|
||||||
|
|
||||||
|
Similar readability improvements should happen all over the place when
|
||||||
|
using `Path::Class'.
|
||||||
|
|
||||||
|
Using `Path::Class' can help solve real problems in your code too - for
|
||||||
|
instance, how many people actually take the "volume" (like `C:' on
|
||||||
|
Windows) into account when writing `File::Spec'-using code? I thought
|
||||||
|
not. But if you use `Path::Class', your file and directory objects will
|
||||||
|
know what volumes they refer to and do the right thing.
|
||||||
|
|
||||||
|
The guts of the `Path::Class' code live in the `Path::Class::File' and
|
||||||
|
`Path::Class::Dir' modules, so please see those modules' documentation
|
||||||
|
for more details about how to use them.
|
||||||
|
|
||||||
|
EXPORT
|
||||||
|
|
||||||
|
The following functions are exported by default.
|
||||||
|
|
||||||
|
file
|
||||||
|
A synonym for `Path::Class::File->new'.
|
||||||
|
|
||||||
|
dir A synonym for `Path::Class::Dir->new'.
|
||||||
|
|
||||||
|
If you would like to prevent their export, you may explicitly pass an
|
||||||
|
empty list to perl's `use', i.e. `use Path::Class ()'.
|
||||||
|
|
||||||
|
The following are exported only on demand.
|
||||||
|
|
||||||
|
foreign_file
|
||||||
|
A synonym for `Path::Class::File->new_foreign'.
|
||||||
|
|
||||||
|
foreign_dir
|
||||||
|
A synonym for `Path::Class::Dir->new_foreign'.
|
||||||
|
|
||||||
|
Notes on Cross-Platform Compatibility
|
||||||
|
Although it is much easier to write cross-platform-friendly code with
|
||||||
|
this module than with `File::Spec', there are still some issues to be
|
||||||
|
aware of.
|
||||||
|
|
||||||
|
* Some platforms, notably VMS and some older versions of DOS (I
|
||||||
|
think), all filenames must have an extension. Thus if you create a
|
||||||
|
file called foo/bar and then ask for a list of files in the
|
||||||
|
directory foo, you may find a file called bar. instead of the bar
|
||||||
|
you were expecting. Thus it might be a good idea to use an extension
|
||||||
|
in the first place.
|
||||||
|
|
||||||
|
AUTHOR
|
||||||
|
Ken Williams, KWILLIAMS@cpan.org
|
||||||
|
|
||||||
|
COPYRIGHT
|
||||||
|
Copyright (c) Ken Williams. All rights reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or modify it
|
||||||
|
under the same terms as Perl itself.
|
||||||
|
|
||||||
|
SEE ALSO
|
||||||
|
Path::Class::Dir, Path::Class::File, File::Spec
|
||||||
|
|
25
manual/docbook/programlisting/vimcolor/README-Text-VimColor
Normal file
25
manual/docbook/programlisting/vimcolor/README-Text-VimColor
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
Text::VimColor
|
||||||
|
--------------
|
||||||
|
|
||||||
|
This module tries to markup text files according to their syntax. It can
|
||||||
|
be used to produce web pages with pretty-printed colourful source code
|
||||||
|
samples. It can produce output in the following formats:
|
||||||
|
|
||||||
|
The module comes with a command line program, text-vimcolor, which makes
|
||||||
|
it easy to do 'ad-hoc' syntax coloring jobs.
|
||||||
|
|
||||||
|
|
||||||
|
Geoff Richards <qef@laxan.com>
|
||||||
|
|
||||||
|
|
||||||
|
Release procedure
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
* Update the version number in lib/Text/VimColor.pm and META.yml
|
||||||
|
* Update the changelog with a new section for a matching version number
|
||||||
|
and the correct date and time
|
||||||
|
* Copy the ChangeLog into place (from 'debian' directory in my CVS)
|
||||||
|
* Realclean, make and test
|
||||||
|
* Make the dist, take it to another machine and build and test there
|
||||||
|
* Commit everything, and set tag like 'Release_0_07-1'
|
||||||
|
* Upload to CPAN
|
2
manual/docbook/programlisting/vimcolor/lib/CVS/Entries
Normal file
2
manual/docbook/programlisting/vimcolor/lib/CVS/Entries
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
D/Path////
|
||||||
|
D/Text////
|
@ -0,0 +1 @@
|
|||||||
|
xsieve/experiments/programlisting/vimcolor/lib
|
1
manual/docbook/programlisting/vimcolor/lib/CVS/Root
Normal file
1
manual/docbook/programlisting/vimcolor/lib/CVS/Root
Normal file
@ -0,0 +1 @@
|
|||||||
|
:pserver:anonymous@xsieve.cvs.sourceforge.net:/cvsroot/xsieve
|
@ -0,0 +1,2 @@
|
|||||||
|
/Class.pm/1.1/Fri Apr 28 07:17:33 2006//
|
||||||
|
D/Class////
|
@ -0,0 +1 @@
|
|||||||
|
xsieve/experiments/programlisting/vimcolor/lib/Path
|
1
manual/docbook/programlisting/vimcolor/lib/Path/CVS/Root
Normal file
1
manual/docbook/programlisting/vimcolor/lib/Path/CVS/Root
Normal file
@ -0,0 +1 @@
|
|||||||
|
:pserver:anonymous@xsieve.cvs.sourceforge.net:/cvsroot/xsieve
|
177
manual/docbook/programlisting/vimcolor/lib/Path/Class.pm
Normal file
177
manual/docbook/programlisting/vimcolor/lib/Path/Class.pm
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
package Path::Class;
|
||||||
|
|
||||||
|
$VERSION = '0.15';
|
||||||
|
@ISA = qw(Exporter);
|
||||||
|
@EXPORT = qw(file dir);
|
||||||
|
@EXPORT_OK = qw(file dir foreign_file foreign_dir);
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use Exporter;
|
||||||
|
use Path::Class::File;
|
||||||
|
use Path::Class::Dir;
|
||||||
|
|
||||||
|
sub file { Path::Class::File->new(@_) }
|
||||||
|
sub dir { Path::Class::Dir ->new(@_) }
|
||||||
|
sub foreign_file { Path::Class::File->new_foreign(@_) }
|
||||||
|
sub foreign_dir { Path::Class::Dir ->new_foreign(@_) }
|
||||||
|
|
||||||
|
|
||||||
|
1;
|
||||||
|
__END__
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
Path::Class - Cross-platform path specification manipulation
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
use Path::Class;
|
||||||
|
|
||||||
|
my $dir = dir('foo', 'bar'); # Path::Class::Dir object
|
||||||
|
my $file = file('bob', 'file.txt'); # Path::Class::File object
|
||||||
|
|
||||||
|
# Stringifies to 'foo/bar' on Unix, 'foo\bar' on Windows, etc.
|
||||||
|
print "dir: $dir\n";
|
||||||
|
|
||||||
|
# Stringifies to 'bob/file.txt' on Unix, 'bob\file.txt' on Windows
|
||||||
|
print "file: $file\n";
|
||||||
|
|
||||||
|
my $subdir = $dir->subdir('baz'); # foo/bar/baz
|
||||||
|
my $parent = $subdir->parent; # foo/bar
|
||||||
|
my $parent2 = $parent->parent; # foo
|
||||||
|
|
||||||
|
my $dir2 = $file->dir; # bob
|
||||||
|
|
||||||
|
# Work with foreign paths
|
||||||
|
use Path::Class qw(foreign_file foreign_dir);
|
||||||
|
my $file = foreign_file('Mac', ':foo:file.txt');
|
||||||
|
print $file->dir; # :foo:
|
||||||
|
print $file->as_foreign('Win32'); # foo\file.txt
|
||||||
|
|
||||||
|
# Interact with the underlying filesystem:
|
||||||
|
|
||||||
|
# $dir_handle is an IO::Dir object
|
||||||
|
my $dir_handle = $dir->open or die "Can't read $dir: $!";
|
||||||
|
|
||||||
|
# $file_handle is an IO::File object
|
||||||
|
my $file_handle = $file->open($mode) or die "Can't read $file: $!";
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
C<Path::Class> is a module for manipulation of file and directory
|
||||||
|
specifications (strings describing their locations, like
|
||||||
|
C<'/home/ken/foo.txt'> or C<'C:\Windows\Foo.txt'>) in a cross-platform
|
||||||
|
manner. It supports pretty much every platform Perl runs on,
|
||||||
|
including Unix, Windows, Mac, VMS, Epoc, Cygwin, OS/2, and NetWare.
|
||||||
|
|
||||||
|
The well-known module C<File::Spec> also provides this service, but
|
||||||
|
it's sort of awkward to use well, so people sometimes avoid it, or use
|
||||||
|
it in a way that won't actually work properly on platforms
|
||||||
|
significantly different than the ones they've tested their code on.
|
||||||
|
|
||||||
|
In fact, C<Path::Class> uses C<File::Spec> internally, wrapping all
|
||||||
|
the unsightly details so you can concentrate on your application code.
|
||||||
|
Whereas C<File::Spec> provides functions for some common path
|
||||||
|
manipulations, C<Path::Class> provides an object-oriented model of the
|
||||||
|
world of path specifications and their underlying semantics.
|
||||||
|
C<File::Spec> doesn't create any objects, and its classes represent
|
||||||
|
the different ways in which paths must be manipulated on various
|
||||||
|
platforms (not a very intuitive concept). C<Path::Class> creates
|
||||||
|
objects representing files and directories, and provides methods that
|
||||||
|
relate them to each other. For instance, the following C<File::Spec>
|
||||||
|
code:
|
||||||
|
|
||||||
|
my $absolute = File::Spec->file_name_is_absolute(
|
||||||
|
File::Spec->catfile( @dirs, $file )
|
||||||
|
);
|
||||||
|
|
||||||
|
can be written using C<Path::Class> as
|
||||||
|
|
||||||
|
my $absolute = Path::Class::File->new( @dirs, $file )->is_absolute;
|
||||||
|
|
||||||
|
or even as
|
||||||
|
|
||||||
|
my $absolute = file( @dirs, $file )->is_absolute;
|
||||||
|
|
||||||
|
Similar readability improvements should happen all over the place when
|
||||||
|
using C<Path::Class>.
|
||||||
|
|
||||||
|
Using C<Path::Class> can help solve real problems in your code too -
|
||||||
|
for instance, how many people actually take the "volume" (like C<C:>
|
||||||
|
on Windows) into account when writing C<File::Spec>-using code? I
|
||||||
|
thought not. But if you use C<Path::Class>, your file and directory objects
|
||||||
|
will know what volumes they refer to and do the right thing.
|
||||||
|
|
||||||
|
The guts of the C<Path::Class> code live in the C<Path::Class::File>
|
||||||
|
and C<Path::Class::Dir> modules, so please see those
|
||||||
|
modules' documentation for more details about how to use them.
|
||||||
|
|
||||||
|
=head2 EXPORT
|
||||||
|
|
||||||
|
The following functions are exported by default.
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item file
|
||||||
|
|
||||||
|
A synonym for C<< Path::Class::File->new >>.
|
||||||
|
|
||||||
|
=item dir
|
||||||
|
|
||||||
|
A synonym for C<< Path::Class::Dir->new >>.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
If you would like to prevent their export, you may explicitly pass an
|
||||||
|
empty list to perl's C<use>, i.e. C<use Path::Class ()>.
|
||||||
|
|
||||||
|
The following are exported only on demand.
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item foreign_file
|
||||||
|
|
||||||
|
A synonym for C<< Path::Class::File->new_foreign >>.
|
||||||
|
|
||||||
|
=item foreign_dir
|
||||||
|
|
||||||
|
A synonym for C<< Path::Class::Dir->new_foreign >>.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 Notes on Cross-Platform Compatibility
|
||||||
|
|
||||||
|
Although it is much easier to write cross-platform-friendly code with
|
||||||
|
this module than with C<File::Spec>, there are still some issues to be
|
||||||
|
aware of.
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Some platforms, notably VMS and some older versions of DOS (I think),
|
||||||
|
all filenames must have an extension. Thus if you create a file
|
||||||
|
called F<foo/bar> and then ask for a list of files in the directory
|
||||||
|
F<foo>, you may find a file called F<bar.> instead of the F<bar> you
|
||||||
|
were expecting. Thus it might be a good idea to use an extension in
|
||||||
|
the first place.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Ken Williams, KWILLIAMS@cpan.org
|
||||||
|
|
||||||
|
=head1 COPYRIGHT
|
||||||
|
|
||||||
|
Copyright (c) Ken Williams. All rights reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the same terms as Perl itself.
|
||||||
|
|
||||||
|
|
||||||
|
=head1 SEE ALSO
|
||||||
|
|
||||||
|
Path::Class::Dir, Path::Class::File, File::Spec
|
||||||
|
|
||||||
|
=cut
|
@ -0,0 +1,4 @@
|
|||||||
|
/Dir.pm/1.1/Fri Apr 28 07:17:33 2006//
|
||||||
|
/Entity.pm/1.1/Fri Apr 28 07:17:33 2006//
|
||||||
|
/File.pm/1.1/Fri Apr 28 07:17:33 2006//
|
||||||
|
D
|
@ -0,0 +1 @@
|
|||||||
|
xsieve/experiments/programlisting/vimcolor/lib/Path/Class
|
@ -0,0 +1 @@
|
|||||||
|
:pserver:anonymous@xsieve.cvs.sourceforge.net:/cvsroot/xsieve
|
584
manual/docbook/programlisting/vimcolor/lib/Path/Class/Dir.pm
Normal file
584
manual/docbook/programlisting/vimcolor/lib/Path/Class/Dir.pm
Normal file
@ -0,0 +1,584 @@
|
|||||||
|
package Path::Class::Dir;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use Path::Class::File;
|
||||||
|
use Path::Class::Entity;
|
||||||
|
use Carp();
|
||||||
|
use base qw(Path::Class::Entity);
|
||||||
|
|
||||||
|
use IO::Dir ();
|
||||||
|
use File::Path ();
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my $self = shift->SUPER::new();
|
||||||
|
my $s = $self->_spec;
|
||||||
|
|
||||||
|
my $first = (@_ == 0 ? $s->curdir :
|
||||||
|
$_[0] eq '' ? (shift, $s->rootdir) :
|
||||||
|
shift()
|
||||||
|
);
|
||||||
|
|
||||||
|
($self->{volume}, my $dirs) = $s->splitpath( $s->canonpath($first) , 1);
|
||||||
|
$self->{dirs} = [$s->splitdir($s->catdir($dirs, @_))];
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub is_dir { 1 }
|
||||||
|
|
||||||
|
sub as_foreign {
|
||||||
|
my ($self, $type) = @_;
|
||||||
|
|
||||||
|
my $foreign = do {
|
||||||
|
local $self->{file_spec_class} = $self->_spec_class($type);
|
||||||
|
$self->SUPER::new;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Clone internal structure
|
||||||
|
$foreign->{volume} = $self->{volume};
|
||||||
|
my ($s, $fs) = ($self->_spec, $foreign->_spec);
|
||||||
|
$foreign->{dirs} = [ map {$_ eq $s->updir ? $fs->updir : $_} @{$self->{dirs}}];
|
||||||
|
return $foreign;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub stringify {
|
||||||
|
my $self = shift;
|
||||||
|
my $s = $self->_spec;
|
||||||
|
return $s->catpath($self->{volume},
|
||||||
|
$s->catdir(@{$self->{dirs}}),
|
||||||
|
'');
|
||||||
|
}
|
||||||
|
|
||||||
|
sub volume { shift()->{volume} }
|
||||||
|
|
||||||
|
sub file {
|
||||||
|
local $Path::Class::Foreign = $_[0]->{file_spec_class} if $_[0]->{file_spec_class};
|
||||||
|
return Path::Class::File->new(@_);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub dir_list {
|
||||||
|
my $self = shift;
|
||||||
|
my $d = $self->{dirs};
|
||||||
|
return @$d unless @_;
|
||||||
|
|
||||||
|
my $offset = shift;
|
||||||
|
if ($offset < 0) { $offset = $#$d + $offset + 1 }
|
||||||
|
|
||||||
|
return wantarray ? @$d[$offset .. $#$d] : $d->[$offset] unless @_;
|
||||||
|
|
||||||
|
my $length = shift;
|
||||||
|
if ($length < 0) { $length = $#$d + $length + 1 - $offset }
|
||||||
|
return @$d[$offset .. $length + $offset - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
sub subdir {
|
||||||
|
my $self = shift;
|
||||||
|
return $self->new($self, @_);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub parent {
|
||||||
|
my $self = shift;
|
||||||
|
my $dirs = $self->{dirs};
|
||||||
|
my ($curdir, $updir) = ($self->_spec->curdir, $self->_spec->updir);
|
||||||
|
|
||||||
|
if ($self->is_absolute) {
|
||||||
|
my $parent = $self->new($self);
|
||||||
|
pop @{$parent->{dirs}};
|
||||||
|
return $parent;
|
||||||
|
|
||||||
|
} elsif ($self eq $curdir) {
|
||||||
|
return $self->new($updir);
|
||||||
|
|
||||||
|
} elsif (!grep {$_ ne $updir} @$dirs) { # All updirs
|
||||||
|
return $self->new($self, $updir); # Add one more
|
||||||
|
|
||||||
|
} elsif (@$dirs == 1) {
|
||||||
|
return $self->new($curdir);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
my $parent = $self->new($self);
|
||||||
|
pop @{$parent->{dirs}};
|
||||||
|
return $parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub relative {
|
||||||
|
# File::Spec->abs2rel before version 3.13 returned the empty string
|
||||||
|
# when the two paths were equal - work around it here.
|
||||||
|
my $self = shift;
|
||||||
|
my $rel = $self->_spec->abs2rel($self->stringify, @_);
|
||||||
|
return $self->new( length $rel ? $rel : $self->_spec->curdir );
|
||||||
|
}
|
||||||
|
|
||||||
|
sub open { IO::Dir->new(@_) }
|
||||||
|
sub mkpath { File::Path::mkpath(shift()->stringify, @_) }
|
||||||
|
sub rmtree { File::Path::rmtree(shift()->stringify, @_) }
|
||||||
|
|
||||||
|
sub remove {
|
||||||
|
rmdir( shift() );
|
||||||
|
}
|
||||||
|
|
||||||
|
sub recurse {
|
||||||
|
my $self = shift;
|
||||||
|
my %opts = (preorder => 1, depthfirst => 0, @_);
|
||||||
|
|
||||||
|
my $callback = $opts{callback}
|
||||||
|
or Carp::croak( "Must provide a 'callback' parameter to recurse()" );
|
||||||
|
|
||||||
|
my @queue = ($self);
|
||||||
|
|
||||||
|
my $visit_entry;
|
||||||
|
my $visit_dir =
|
||||||
|
$opts{depthfirst} && $opts{preorder}
|
||||||
|
? sub {
|
||||||
|
my $dir = shift;
|
||||||
|
$callback->($dir);
|
||||||
|
unshift @queue, $dir->children;
|
||||||
|
}
|
||||||
|
: $opts{preorder}
|
||||||
|
? sub {
|
||||||
|
my $dir = shift;
|
||||||
|
$callback->($dir);
|
||||||
|
push @queue, $dir->children;
|
||||||
|
}
|
||||||
|
: sub {
|
||||||
|
my $dir = shift;
|
||||||
|
$visit_entry->($_) foreach $dir->children;
|
||||||
|
$callback->($dir);
|
||||||
|
};
|
||||||
|
|
||||||
|
$visit_entry = sub {
|
||||||
|
my $entry = shift;
|
||||||
|
if ($entry->is_dir) { $visit_dir->($entry) } # Will call $callback
|
||||||
|
else { $callback->($entry) }
|
||||||
|
};
|
||||||
|
|
||||||
|
while (@queue) {
|
||||||
|
$visit_entry->( shift @queue );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub children {
|
||||||
|
my ($self, %opts) = @_;
|
||||||
|
|
||||||
|
my $dh = $self->open or Carp::croak( "Can't open directory $self: $!" );
|
||||||
|
|
||||||
|
my @out;
|
||||||
|
while (my $entry = $dh->read) {
|
||||||
|
# XXX What's the right cross-platform way to do this?
|
||||||
|
next if (!$opts{all} && ($entry eq '.' || $entry eq '..'));
|
||||||
|
push @out, $self->file($entry);
|
||||||
|
$out[-1] = $self->subdir($entry) if -d $out[-1];
|
||||||
|
}
|
||||||
|
return @out;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub next {
|
||||||
|
my $self = shift;
|
||||||
|
unless ($self->{dh}) {
|
||||||
|
$self->{dh} = $self->open or Carp::croak( "Can't open directory $self: $!" );
|
||||||
|
}
|
||||||
|
|
||||||
|
my $next = $self->{dh}->read;
|
||||||
|
unless (defined $next) {
|
||||||
|
delete $self->{dh};
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Figure out whether it's a file or directory
|
||||||
|
my $file = $self->file($next);
|
||||||
|
$file = $self->subdir($next) if -d $file;
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub subsumes {
|
||||||
|
my ($self, $other) = @_;
|
||||||
|
die "No second entity given to subsumes()" unless $other;
|
||||||
|
|
||||||
|
$other = ref($self)->new($other) unless UNIVERSAL::isa($other, __PACKAGE__);
|
||||||
|
$other = $other->dir unless $other->is_dir;
|
||||||
|
|
||||||
|
if ($self->is_absolute) {
|
||||||
|
$other = $other->absolute;
|
||||||
|
} elsif ($other->is_absolute) {
|
||||||
|
$self = $self->absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
$self = $self->cleanup;
|
||||||
|
$other = $other->cleanup;
|
||||||
|
|
||||||
|
if ($self->volume) {
|
||||||
|
return 0 unless $other->volume eq $self->volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
# The root dir subsumes everything
|
||||||
|
return 1 if $self eq ref($self)->new('');
|
||||||
|
|
||||||
|
my $i = 0;
|
||||||
|
while ($i <= $#{ $self->{dirs} }) {
|
||||||
|
return 0 unless exists $other->{dirs}[$i];
|
||||||
|
return 0 if $self->{dirs}[$i] ne $other->{dirs}[$i];
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
__END__
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
Path::Class::Dir - Objects representing directories
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
use Path::Class qw(dir); # Export a short constructor
|
||||||
|
|
||||||
|
my $dir = dir('foo', 'bar'); # Path::Class::Dir object
|
||||||
|
my $dir = Path::Class::Dir->new('foo', 'bar'); # Same thing
|
||||||
|
|
||||||
|
# Stringifies to 'foo/bar' on Unix, 'foo\bar' on Windows, etc.
|
||||||
|
print "dir: $dir\n";
|
||||||
|
|
||||||
|
if ($dir->is_absolute) { ... }
|
||||||
|
|
||||||
|
my $v = $dir->volume; # Could be 'C:' on Windows, empty string
|
||||||
|
# on Unix, 'Macintosh HD:' on Mac OS
|
||||||
|
|
||||||
|
$dir->cleanup; # Perform logical cleanup of pathname
|
||||||
|
|
||||||
|
my $file = $dir->file('file.txt'); # A file in this directory
|
||||||
|
my $subdir = $dir->subdir('george'); # A subdirectory
|
||||||
|
my $parent = $dir->parent; # The parent directory, 'foo'
|
||||||
|
|
||||||
|
my $abs = $dir->absolute; # Transform to absolute path
|
||||||
|
my $rel = $abs->relative; # Transform to relative path
|
||||||
|
my $rel = $abs->relative('/foo'); # Relative to /foo
|
||||||
|
|
||||||
|
print $dir->as_foreign('MacOS'); # :foo:bar:
|
||||||
|
print $dir->as_foreign('Win32'); # foo\bar
|
||||||
|
|
||||||
|
# Iterate with IO::Dir methods:
|
||||||
|
my $handle = $dir->open;
|
||||||
|
while (my $file = $handle->read) {
|
||||||
|
$file = $dir->file($file); # Turn into Path::Class::File object
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
# Iterate with Path::Class methods:
|
||||||
|
while (my $file = $dir->next) {
|
||||||
|
# $file is a Path::Class::File or Path::Class::Dir object
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
The C<Path::Class::Dir> class contains functionality for manipulating
|
||||||
|
directory names in a cross-platform way.
|
||||||
|
|
||||||
|
=head1 METHODS
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item $dir = Path::Class::Dir->new( <dir1>, <dir2>, ... )
|
||||||
|
|
||||||
|
=item $dir = dir( <dir1>, <dir2>, ... )
|
||||||
|
|
||||||
|
Creates a new C<Path::Class::Dir> object and returns it. The
|
||||||
|
arguments specify names of directories which will be joined to create
|
||||||
|
a single directory object. A volume may also be specified as the
|
||||||
|
first argument, or as part of the first argument. You can use
|
||||||
|
platform-neutral syntax:
|
||||||
|
|
||||||
|
my $dir = dir( 'foo', 'bar', 'baz' );
|
||||||
|
|
||||||
|
or platform-native syntax:
|
||||||
|
|
||||||
|
my $dir = dir( 'foo/bar/baz' );
|
||||||
|
|
||||||
|
or a mixture of the two:
|
||||||
|
|
||||||
|
my $dir = dir( 'foo/bar', 'baz' );
|
||||||
|
|
||||||
|
All three of the above examples create relative paths. To create an
|
||||||
|
absolute path, either use the platform native syntax for doing so:
|
||||||
|
|
||||||
|
my $dir = dir( '/var/tmp' );
|
||||||
|
|
||||||
|
or use an empty string as the first argument:
|
||||||
|
|
||||||
|
my $dir = dir( '', 'var', 'tmp' );
|
||||||
|
|
||||||
|
If the second form seems awkward, that's somewhat intentional - paths
|
||||||
|
like C</var/tmp> or C<\Windows> aren't cross-platform concepts in the
|
||||||
|
first place (many non-Unix platforms don't have a notion of a "root
|
||||||
|
directory"), so they probably shouldn't appear in your code if you're
|
||||||
|
trying to be cross-platform. The first form is perfectly natural,
|
||||||
|
because paths like this may come from config files, user input, or
|
||||||
|
whatever.
|
||||||
|
|
||||||
|
As a special case, since it doesn't otherwise mean anything useful and
|
||||||
|
it's convenient to define this way, C<< Path::Class::Dir->new() >> (or
|
||||||
|
C<dir()>) refers to the current directory (C<< File::Spec->curdir >>).
|
||||||
|
To get the current directory as an absolute path, do C<<
|
||||||
|
dir()->absolute >>.
|
||||||
|
|
||||||
|
=item $dir->stringify
|
||||||
|
|
||||||
|
This method is called internally when a C<Path::Class::Dir> object is
|
||||||
|
used in a string context, so the following are equivalent:
|
||||||
|
|
||||||
|
$string = $dir->stringify;
|
||||||
|
$string = "$dir";
|
||||||
|
|
||||||
|
=item $dir->volume
|
||||||
|
|
||||||
|
Returns the volume (e.g. C<C:> on Windows, C<Macintosh HD:> on Mac OS,
|
||||||
|
etc.) of the directory object, if any. Otherwise, returns the empty
|
||||||
|
string.
|
||||||
|
|
||||||
|
=item $dir->is_dir
|
||||||
|
|
||||||
|
Returns a boolean value indicating whether this object represents a
|
||||||
|
directory. Not surprisingly, C<Path::Class::File> objects always
|
||||||
|
return false, and C<Path::Class::Dir> objects always return true.
|
||||||
|
|
||||||
|
=item $dir->is_absolute
|
||||||
|
|
||||||
|
Returns true or false depending on whether the directory refers to an
|
||||||
|
absolute path specifier (like C</usr/local> or C<\Windows>).
|
||||||
|
|
||||||
|
=item $dir->cleanup
|
||||||
|
|
||||||
|
Performs a logical cleanup of the file path. For instance:
|
||||||
|
|
||||||
|
my $dir = dir('/foo//baz/./foo')->cleanup;
|
||||||
|
# $dir now represents '/foo/baz/foo';
|
||||||
|
|
||||||
|
=item $file = $dir->file( <dir1>, <dir2>, ..., <file> )
|
||||||
|
|
||||||
|
Returns a C<Path::Class::File> object representing an entry in C<$dir>
|
||||||
|
or one of its subdirectories. Internally, this just calls C<<
|
||||||
|
Path::Class::File->new( @_ ) >>.
|
||||||
|
|
||||||
|
=item $subdir = $dir->subdir( <dir1>, <dir2>, ... )
|
||||||
|
|
||||||
|
Returns a new C<Path::Class::Dir> object representing a subdirectory
|
||||||
|
of C<$dir>.
|
||||||
|
|
||||||
|
=item $parent = $dir->parent
|
||||||
|
|
||||||
|
Returns the parent directory of C<$dir>. Note that this is the
|
||||||
|
I<logical> parent, not necessarily the physical parent. It really
|
||||||
|
means we just chop off entries from the end of the directory list
|
||||||
|
until we cain't chop no more. If the directory is relative, we start
|
||||||
|
using the relative forms of parent directories.
|
||||||
|
|
||||||
|
The following code demonstrates the behavior on absolute and relative
|
||||||
|
directories:
|
||||||
|
|
||||||
|
$dir = dir('/foo/bar');
|
||||||
|
for (1..6) {
|
||||||
|
print "Absolute: $dir\n";
|
||||||
|
$dir = $dir->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dir = dir('foo/bar');
|
||||||
|
for (1..6) {
|
||||||
|
print "Relative: $dir\n";
|
||||||
|
$dir = $dir->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
########### Output on Unix ################
|
||||||
|
Absolute: /foo/bar
|
||||||
|
Absolute: /foo
|
||||||
|
Absolute: /
|
||||||
|
Absolute: /
|
||||||
|
Absolute: /
|
||||||
|
Absolute: /
|
||||||
|
Relative: foo/bar
|
||||||
|
Relative: foo
|
||||||
|
Relative: .
|
||||||
|
Relative: ..
|
||||||
|
Relative: ../..
|
||||||
|
Relative: ../../..
|
||||||
|
|
||||||
|
=item @list = $dir->children
|
||||||
|
|
||||||
|
Returns a list of C<Path::Class::File> and/or C<Path::Class::Dir>
|
||||||
|
objects listed in this directory, or in scalar context the number of
|
||||||
|
such objects. Obviously, it is necessary for C<$dir> to
|
||||||
|
exist and be readable in order to find its children.
|
||||||
|
|
||||||
|
Note that the children are returned as subdirectories of C<$dir>,
|
||||||
|
i.e. the children of F<foo> will be F<foo/bar> and F<foo/baz>, not
|
||||||
|
F<bar> and F<baz>.
|
||||||
|
|
||||||
|
Ordinarily C<children()> will not include the I<self> and I<parent>
|
||||||
|
entries C<.> and C<..> (or their equivalents on non-Unix systems),
|
||||||
|
because that's like I'm-my-own-grandpa business. If you do want all
|
||||||
|
directory entries including these special ones, pass a true value for
|
||||||
|
the C<all> parameter:
|
||||||
|
|
||||||
|
@c = $dir->children(); # Just the children
|
||||||
|
@c = $dir->children(all => 1); # All entries
|
||||||
|
|
||||||
|
=item $abs = $dir->absolute
|
||||||
|
|
||||||
|
Returns a C<Path::Class::Dir> object representing C<$dir> as an
|
||||||
|
absolute path. An optional argument, given as either a string or a
|
||||||
|
C<Path::Class::Dir> object, specifies the directory to use as the base
|
||||||
|
of relativity - otherwise the current working directory will be used.
|
||||||
|
|
||||||
|
=item $rel = $dir->relative
|
||||||
|
|
||||||
|
Returns a C<Path::Class::Dir> object representing C<$dir> as a
|
||||||
|
relative path. An optional argument, given as either a string or a
|
||||||
|
C<Path::Class::Dir> object, specifies the directory to use as the base
|
||||||
|
of relativity - otherwise the current working directory will be used.
|
||||||
|
|
||||||
|
=item $boolean = $dir->subsumes($other)
|
||||||
|
|
||||||
|
Returns true if this directory spec subsumes the other spec, and false
|
||||||
|
otherwise. Think of "subsumes" as "contains", but we only look at the
|
||||||
|
I<specs>, not whether C<$dir> actually contains C<$other> on the
|
||||||
|
filesystem.
|
||||||
|
|
||||||
|
The C<$other> argument may be a C<Path::Class::Dir> object, a
|
||||||
|
C<Path::Class::File> object, or a string. In the latter case, we
|
||||||
|
assume it's a directory.
|
||||||
|
|
||||||
|
# Examples:
|
||||||
|
dir('foo/bar' )->subsumes(dir('foo/bar/baz')) # True
|
||||||
|
dir('/foo/bar')->subsumes(dir('/foo/bar/baz')) # True
|
||||||
|
dir('foo/bar' )->subsumes(dir('bar/baz')) # False
|
||||||
|
dir('/foo/bar')->subsumes(dir('foo/bar')) # False
|
||||||
|
|
||||||
|
|
||||||
|
=item $foreign = $dir->as_foreign($type)
|
||||||
|
|
||||||
|
Returns a C<Path::Class::Dir> object representing C<$dir> as it would
|
||||||
|
be specified on a system of type C<$type>. Known types include
|
||||||
|
C<Unix>, C<Win32>, C<Mac>, C<VMS>, and C<OS2>, i.e. anything for which
|
||||||
|
there is a subclass of C<File::Spec>.
|
||||||
|
|
||||||
|
Any generated objects (subdirectories, files, parents, etc.) will also
|
||||||
|
retain this type.
|
||||||
|
|
||||||
|
=item $foreign = Path::Class::Dir->new_foreign($type, @args)
|
||||||
|
|
||||||
|
Returns a C<Path::Class::Dir> object representing C<$dir> as it would
|
||||||
|
be specified on a system of type C<$type>. Known types include
|
||||||
|
C<Unix>, C<Win32>, C<Mac>, C<VMS>, and C<OS2>, i.e. anything for which
|
||||||
|
there is a subclass of C<File::Spec>.
|
||||||
|
|
||||||
|
The arguments in C<@args> are the same as they would be specified in
|
||||||
|
C<new()>.
|
||||||
|
|
||||||
|
=item @list = $dir->dir_list([OFFSET, [LENGTH]])
|
||||||
|
|
||||||
|
Returns the list of strings internally representing this directory
|
||||||
|
structure. Each successive member of the list is understood to be an
|
||||||
|
entry in its predecessor's directory list. By contract, C<<
|
||||||
|
Path::Class->new( $dir->dir_list ) >> should be equivalent to C<$dir>.
|
||||||
|
|
||||||
|
The semantics of this method are similar to Perl's C<splice> or
|
||||||
|
C<substr> functions; they return C<LENGTH> elements starting at
|
||||||
|
C<OFFSET>. If C<LENGTH> is omitted, returns all the elements starting
|
||||||
|
at C<OFFSET> up to the end of the list. If C<LENGTH> is negative,
|
||||||
|
returns the elements from C<OFFSET> onward except for C<-LENGTH>
|
||||||
|
elements at the end. If C<OFFSET> is negative, it counts backward
|
||||||
|
C<OFFSET> elements from the end of the list. If C<OFFSET> and
|
||||||
|
C<LENGTH> are both omitted, the entire list is returned.
|
||||||
|
|
||||||
|
In a scalar context, C<dir_list()> with no arguments returns the
|
||||||
|
number of entries in the directory list; C<dir_list(OFFSET)> returns
|
||||||
|
the single element at that offset; C<dir_list(OFFSET, LENGTH)> returns
|
||||||
|
the final element that would have been returned in a list context.
|
||||||
|
|
||||||
|
=item $fh = $dir->open()
|
||||||
|
|
||||||
|
Passes C<$dir> to C<< IO::Dir->open >> and returns the result as an
|
||||||
|
C<IO::Dir> object. If the opening fails, C<undef> is returned and
|
||||||
|
C<$!> is set.
|
||||||
|
|
||||||
|
=item $dir->mkpath($verbose, $mode)
|
||||||
|
|
||||||
|
Passes all arguments, including C<$dir>, to C<< File::Path::mkpath()
|
||||||
|
>> and returns the result (a list of all directories created).
|
||||||
|
|
||||||
|
=item $dir->rmtree($verbose, $cautious)
|
||||||
|
|
||||||
|
Passes all arguments, including C<$dir>, to C<< File::Path::rmtree()
|
||||||
|
>> and returns the result (the number of files successfully deleted).
|
||||||
|
|
||||||
|
=item $dir->remove()
|
||||||
|
|
||||||
|
Removes the directory, which must be empty. Returns a boolean value
|
||||||
|
indicating whether or not the directory was successfully removed.
|
||||||
|
This method is mainly provided for consistency with
|
||||||
|
C<Path::Class::File>'s C<remove()> method.
|
||||||
|
|
||||||
|
=item $dir_or_file = $dir->next()
|
||||||
|
|
||||||
|
A convenient way to iterate through directory contents. The first
|
||||||
|
time C<next()> is called, it will C<open()> the directory and read the
|
||||||
|
first item from it, returning the result as a C<Path::Class::Dir> or
|
||||||
|
C<Path::Class::File> object (depending, of course, on its actual
|
||||||
|
type). Each subsequent call to C<next()> will simply iterate over the
|
||||||
|
directory's contents, until there are no more items in the directory,
|
||||||
|
and then the undefined value is returned. For example, to iterate
|
||||||
|
over all the regular files in a directory:
|
||||||
|
|
||||||
|
while (my $file = $dir->next) {
|
||||||
|
next unless -f $file;
|
||||||
|
my $fh = $file->open('r') or die "Can't read $file: $!";
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
If an error occurs when opening the directory (for instance, it
|
||||||
|
doesn't exist or isn't readable), C<next()> will throw an exception
|
||||||
|
with the value of C<$!>.
|
||||||
|
|
||||||
|
=item $dir->recurse( callback => sub {...} )
|
||||||
|
|
||||||
|
Iterates through this directory and all of its children, and all of
|
||||||
|
its children's children, etc., calling the C<callback> subroutine for
|
||||||
|
each entry. This is a lot like what the C<File::Find> module does,
|
||||||
|
and of course C<File::Find> will work fine on C<Path::Class> objects,
|
||||||
|
but the advantage of the C<recurse()> method is that it will also feed
|
||||||
|
your callback routine C<Path::Class> objects rather than just pathname
|
||||||
|
strings.
|
||||||
|
|
||||||
|
The C<recurse()> method requires a C<callback> parameter specifying
|
||||||
|
the subroutine to invoke for each entry. It will be passed the
|
||||||
|
C<Path::Class> object as its first argument.
|
||||||
|
|
||||||
|
C<recurse()> also accepts two boolean parameters, C<depthfirst> and
|
||||||
|
C<preorder> that control the order of recursion. The default is a
|
||||||
|
preorder, breadth-first search, i.e. C<< depthfirst => 0, preorder => 1 >>.
|
||||||
|
At the time of this writing, all combinations of these two parameters
|
||||||
|
are supported I<except> C<< depthfirst => 0, preorder => 0 >>.
|
||||||
|
|
||||||
|
=item $st = $file->stat()
|
||||||
|
|
||||||
|
Invokes C<< File::stat::stat() >> on this directory and returns a
|
||||||
|
C<File::stat> object representing the result.
|
||||||
|
|
||||||
|
=item $st = $file->lstat()
|
||||||
|
|
||||||
|
Same as C<stat()>, but if C<$file> is a symbolic link, C<lstat()>
|
||||||
|
stats the link instead of the directory the link points to.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Ken Williams, ken@mathforum.org
|
||||||
|
|
||||||
|
=head1 SEE ALSO
|
||||||
|
|
||||||
|
Path::Class, Path::Class::File, File::Spec
|
||||||
|
|
||||||
|
=cut
|
@ -0,0 +1,67 @@
|
|||||||
|
package Path::Class::Entity;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use File::Spec;
|
||||||
|
use File::stat ();
|
||||||
|
|
||||||
|
use overload
|
||||||
|
(
|
||||||
|
q[""] => 'stringify',
|
||||||
|
fallback => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my $from = shift;
|
||||||
|
my ($class, $fs_class) = (ref($from)
|
||||||
|
? (ref $from, $from->{file_spec_class})
|
||||||
|
: ($from, $Path::Class::Foreign));
|
||||||
|
return bless {file_spec_class => $fs_class}, $class;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub is_dir { 0 }
|
||||||
|
|
||||||
|
sub _spec_class {
|
||||||
|
my ($class, $type) = @_;
|
||||||
|
|
||||||
|
die "Invalid system type '$type'" unless ($type) = $type =~ /^(\w+)$/; # Untaint
|
||||||
|
my $spec = "File::Spec::$type";
|
||||||
|
eval "require $spec; 1" or die $@;
|
||||||
|
return $spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub new_foreign {
|
||||||
|
my ($class, $type) = (shift, shift);
|
||||||
|
local $Path::Class::Foreign = $class->_spec_class($type);
|
||||||
|
return $class->new(@_);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _spec { $_[0]->{file_spec_class} || 'File::Spec' }
|
||||||
|
|
||||||
|
sub is_absolute {
|
||||||
|
# 5.6.0 has a bug with regexes and stringification that's ticked by
|
||||||
|
# file_name_is_absolute(). Help it along.
|
||||||
|
$_[0]->_spec->file_name_is_absolute($_[0]->stringify)
|
||||||
|
}
|
||||||
|
|
||||||
|
sub cleanup {
|
||||||
|
my $self = shift;
|
||||||
|
my $cleaned = $self->new( $self->_spec->canonpath($self) );
|
||||||
|
%$self = %$cleaned;
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub absolute {
|
||||||
|
my $self = shift;
|
||||||
|
return $self if $self->is_absolute;
|
||||||
|
return $self->new($self->_spec->rel2abs($self->stringify, @_));
|
||||||
|
}
|
||||||
|
|
||||||
|
sub relative {
|
||||||
|
my $self = shift;
|
||||||
|
return $self->new($self->_spec->abs2rel($self->stringify, @_));
|
||||||
|
}
|
||||||
|
|
||||||
|
sub stat { File::stat::stat("$_[0]") }
|
||||||
|
sub lstat { File::stat::lstat("$_[0]") }
|
||||||
|
|
||||||
|
1;
|
311
manual/docbook/programlisting/vimcolor/lib/Path/Class/File.pm
Normal file
311
manual/docbook/programlisting/vimcolor/lib/Path/Class/File.pm
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
package Path::Class::File;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use Path::Class::Dir;
|
||||||
|
use Path::Class::Entity;
|
||||||
|
use base qw(Path::Class::Entity);
|
||||||
|
|
||||||
|
use IO::File ();
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my $self = shift->SUPER::new;
|
||||||
|
my $file = pop();
|
||||||
|
my @dirs = @_;
|
||||||
|
|
||||||
|
my ($volume, $dirs, $base) = $self->_spec->splitpath($file);
|
||||||
|
|
||||||
|
if (length $dirs) {
|
||||||
|
push @dirs, $self->_spec->catpath($volume, $dirs, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->{dir} = @dirs ? Path::Class::Dir->new(@dirs) : undef;
|
||||||
|
$self->{file} = $base;
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub as_foreign {
|
||||||
|
my ($self, $type) = @_;
|
||||||
|
local $Path::Class::Foreign = $self->_spec_class($type);
|
||||||
|
my $foreign = ref($self)->SUPER::new;
|
||||||
|
$foreign->{dir} = $self->{dir}->as_foreign($type) if defined $self->{dir};
|
||||||
|
$foreign->{file} = $self->{file};
|
||||||
|
return $foreign;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub stringify {
|
||||||
|
my $self = shift;
|
||||||
|
return $self->{file} unless defined $self->{dir};
|
||||||
|
return $self->_spec->catfile($self->{dir}->stringify, $self->{file});
|
||||||
|
}
|
||||||
|
|
||||||
|
sub dir {
|
||||||
|
my $self = shift;
|
||||||
|
return $self->{dir} if defined $self->{dir};
|
||||||
|
return Path::Class::Dir->new($self->_spec->curdir);
|
||||||
|
}
|
||||||
|
BEGIN { *parent = \&dir; }
|
||||||
|
|
||||||
|
sub volume {
|
||||||
|
my $self = shift;
|
||||||
|
return '' unless defined $self->{dir};
|
||||||
|
return $self->{dir}->volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub basename { shift->{file} }
|
||||||
|
sub open { IO::File->new(@_) }
|
||||||
|
|
||||||
|
sub openr { $_[0]->open('r') or die "Can't read $_[0]: $!" }
|
||||||
|
sub openw { $_[0]->open('w') or die "Can't write $_[0]: $!" }
|
||||||
|
|
||||||
|
sub touch {
|
||||||
|
my $self = shift;
|
||||||
|
if (-e $self) {
|
||||||
|
my $now = time();
|
||||||
|
utime $now, $now, $self;
|
||||||
|
} else {
|
||||||
|
$self->openw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub slurp {
|
||||||
|
my ($self, %args) = @_;
|
||||||
|
my $fh = $self->openr;
|
||||||
|
|
||||||
|
if ($args{chomped} or $args{chomp}) {
|
||||||
|
chomp( my @data = <$fh> );
|
||||||
|
return wantarray ? @data : join '', @data;
|
||||||
|
}
|
||||||
|
|
||||||
|
local $/ unless wantarray;
|
||||||
|
return <$fh>;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub remove {
|
||||||
|
my $file = shift->stringify;
|
||||||
|
return unlink $file unless -e $file; # Sets $! correctly
|
||||||
|
1 while unlink $file;
|
||||||
|
return not -e $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
__END__
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
Path::Class::File - Objects representing files
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
use Path::Class qw(file); # Export a short constructor
|
||||||
|
|
||||||
|
my $file = file('foo', 'bar.txt'); # Path::Class::File object
|
||||||
|
my $file = Path::Class::File->new('foo', 'bar.txt'); # Same thing
|
||||||
|
|
||||||
|
# Stringifies to 'foo/bar.txt' on Unix, 'foo\bar.txt' on Windows, etc.
|
||||||
|
print "file: $file\n";
|
||||||
|
|
||||||
|
if ($file->is_absolute) { ... }
|
||||||
|
|
||||||
|
my $v = $file->volume; # Could be 'C:' on Windows, empty string
|
||||||
|
# on Unix, 'Macintosh HD:' on Mac OS
|
||||||
|
|
||||||
|
$file->cleanup; # Perform logical cleanup of pathname
|
||||||
|
|
||||||
|
my $dir = $file->dir; # A Path::Class::Dir object
|
||||||
|
|
||||||
|
my $abs = $file->absolute; # Transform to absolute path
|
||||||
|
my $rel = $file->relative; # Transform to relative path
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
The C<Path::Class::File> class contains functionality for manipulating
|
||||||
|
file names in a cross-platform way.
|
||||||
|
|
||||||
|
=head1 METHODS
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item $file = Path::Class::File->new( <dir1>, <dir2>, ..., <file> )
|
||||||
|
|
||||||
|
=item $file = file( <dir1>, <dir2>, ..., <file> )
|
||||||
|
|
||||||
|
Creates a new C<Path::Class::File> object and returns it. The
|
||||||
|
arguments specify the path to the file. Any volume may also be
|
||||||
|
specified as the first argument, or as part of the first argument.
|
||||||
|
You can use platform-neutral syntax:
|
||||||
|
|
||||||
|
my $dir = file( 'foo', 'bar', 'baz.txt' );
|
||||||
|
|
||||||
|
or platform-native syntax:
|
||||||
|
|
||||||
|
my $dir = dir( 'foo/bar/baz.txt' );
|
||||||
|
|
||||||
|
or a mixture of the two:
|
||||||
|
|
||||||
|
my $dir = dir( 'foo/bar', 'baz.txt' );
|
||||||
|
|
||||||
|
All three of the above examples create relative paths. To create an
|
||||||
|
absolute path, either use the platform native syntax for doing so:
|
||||||
|
|
||||||
|
my $dir = dir( '/var/tmp/foo.txt' );
|
||||||
|
|
||||||
|
or use an empty string as the first argument:
|
||||||
|
|
||||||
|
my $dir = dir( '', 'var', 'tmp', 'foo.txt' );
|
||||||
|
|
||||||
|
If the second form seems awkward, that's somewhat intentional - paths
|
||||||
|
like C</var/tmp> or C<\Windows> aren't cross-platform concepts in the
|
||||||
|
first place, so they probably shouldn't appear in your code if you're
|
||||||
|
trying to be cross-platform. The first form is perfectly fine,
|
||||||
|
because paths like this may come from config files, user input, or
|
||||||
|
whatever.
|
||||||
|
|
||||||
|
=item $file->stringify
|
||||||
|
|
||||||
|
This method is called internally when a C<Path::Class::File> object is
|
||||||
|
used in a string context, so the following are equivalent:
|
||||||
|
|
||||||
|
$string = $file->stringify;
|
||||||
|
$string = "$file";
|
||||||
|
|
||||||
|
=item $file->volume
|
||||||
|
|
||||||
|
Returns the volume (e.g. C<C:> on Windows, C<Macintosh HD:> on Mac OS,
|
||||||
|
etc.) of the object, if any. Otherwise, returns the empty string.
|
||||||
|
|
||||||
|
=item $file->basename
|
||||||
|
|
||||||
|
Returns the name of the file as a string, without the directory
|
||||||
|
portion (if any).
|
||||||
|
|
||||||
|
=item $file->is_dir
|
||||||
|
|
||||||
|
Returns a boolean value indicating whether this object represents a
|
||||||
|
directory. Not surprisingly, C<Path::Class::File> objects always
|
||||||
|
return false, and C<Path::Class::Dir> objects always return true.
|
||||||
|
|
||||||
|
=item $file->is_absolute
|
||||||
|
|
||||||
|
Returns true or false depending on whether the file refers to an
|
||||||
|
absolute path specifier (like C</usr/local/foo.txt> or C<\Windows\Foo.txt>).
|
||||||
|
|
||||||
|
=item $file->cleanup
|
||||||
|
|
||||||
|
Performs a logical cleanup of the file path. For instance:
|
||||||
|
|
||||||
|
my $file = file('/foo//baz/./foo.txt')->cleanup;
|
||||||
|
# $file now represents '/foo/baz/foo.txt';
|
||||||
|
|
||||||
|
=item $dir = $file->dir
|
||||||
|
|
||||||
|
Returns a C<Path::Class::Dir> object representing the directory
|
||||||
|
containing this file.
|
||||||
|
|
||||||
|
=item $dir = $file->parent
|
||||||
|
|
||||||
|
A synonym for the C<dir()> method.
|
||||||
|
|
||||||
|
=item $abs = $file->absolute
|
||||||
|
|
||||||
|
Returns a C<Path::Class::File> object representing C<$file> as an
|
||||||
|
absolute path. An optional argument, given as either a string or a
|
||||||
|
C<Path::Class::Dir> object, specifies the directory to use as the base
|
||||||
|
of relativity - otherwise the current working directory will be used.
|
||||||
|
|
||||||
|
=item $rel = $file->relative
|
||||||
|
|
||||||
|
Returns a C<Path::Class::File> object representing C<$file> as a
|
||||||
|
relative path. An optional argument, given as either a string or a
|
||||||
|
C<Path::Class::Dir> object, specifies the directory to use as the base
|
||||||
|
of relativity - otherwise the current working directory will be used.
|
||||||
|
|
||||||
|
=item $foreign = $file->as_foreign($type)
|
||||||
|
|
||||||
|
Returns a C<Path::Class::File> object representing C<$file> as it would
|
||||||
|
be specified on a system of type C<$type>. Known types include
|
||||||
|
C<Unix>, C<Win32>, C<Mac>, C<VMS>, and C<OS2>, i.e. anything for which
|
||||||
|
there is a subclass of C<File::Spec>.
|
||||||
|
|
||||||
|
Any generated objects (subdirectories, files, parents, etc.) will also
|
||||||
|
retain this type.
|
||||||
|
|
||||||
|
=item $foreign = Path::Class::File->new_foreign($type, @args)
|
||||||
|
|
||||||
|
Returns a C<Path::Class::File> object representing a file as it would
|
||||||
|
be specified on a system of type C<$type>. Known types include
|
||||||
|
C<Unix>, C<Win32>, C<Mac>, C<VMS>, and C<OS2>, i.e. anything for which
|
||||||
|
there is a subclass of C<File::Spec>.
|
||||||
|
|
||||||
|
The arguments in C<@args> are the same as they would be specified in
|
||||||
|
C<new()>.
|
||||||
|
|
||||||
|
=item $fh = $file->open($mode, $permissions)
|
||||||
|
|
||||||
|
Passes the given arguments, including C<$file>, to C<< IO::File->new >>
|
||||||
|
(which in turn calls C<< IO::File->open >> and returns the result
|
||||||
|
as an C<IO::File> object. If the opening
|
||||||
|
fails, C<undef> is returned and C<$!> is set.
|
||||||
|
|
||||||
|
=item $fh = $file->openr()
|
||||||
|
|
||||||
|
A shortcut for
|
||||||
|
|
||||||
|
$fh = $file->open('r') or die "Can't read $file: $!";
|
||||||
|
|
||||||
|
=item $fh = $file->openw()
|
||||||
|
|
||||||
|
A shortcut for
|
||||||
|
|
||||||
|
$fh = $file->open('w') or die "Can't write $file: $!";
|
||||||
|
|
||||||
|
=item $file->touch
|
||||||
|
|
||||||
|
Sets the modification and access time of the given file to right now,
|
||||||
|
if the file exists. If it doesn't exist, C<touch()> will I<make> it
|
||||||
|
exist, and - YES! - set its modification and access time to now.
|
||||||
|
|
||||||
|
=item $file->slurp()
|
||||||
|
|
||||||
|
In a scalar context, returns the contents of C<$file> in a string. In
|
||||||
|
a list context, returns the lines of C<$file> (according to how C<$/>
|
||||||
|
is set) as a list. If the file can't be read, this method will throw
|
||||||
|
an exception.
|
||||||
|
|
||||||
|
If you want C<chomp()> run on each line of the file, pass a true value
|
||||||
|
for the C<chomp> or C<chomped> parameters:
|
||||||
|
|
||||||
|
my @lines = $file->slurp(chomp => 1);
|
||||||
|
|
||||||
|
=item $file->remove()
|
||||||
|
|
||||||
|
This method will remove the file in a way that works well on all
|
||||||
|
platforms, and returns a boolean value indicating whether or not the
|
||||||
|
file was successfully removed.
|
||||||
|
|
||||||
|
C<remove()> is better than simply calling Perl's C<unlink()> function,
|
||||||
|
because on some platforms (notably VMS) you actually may need to call
|
||||||
|
C<unlink()> several times before all versions of the file are gone -
|
||||||
|
the C<remove()> method handles this process for you.
|
||||||
|
|
||||||
|
=item $st = $file->stat()
|
||||||
|
|
||||||
|
Invokes C<< File::stat::stat() >> on this file and returns a
|
||||||
|
C<File::stat> object representing the result.
|
||||||
|
|
||||||
|
=item $st = $file->lstat()
|
||||||
|
|
||||||
|
Same as C<stat()>, but if C<$file> is a symbolic link, C<lstat()>
|
||||||
|
stats the link instead of the file the link points to.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Ken Williams, ken@mathforum.org
|
||||||
|
|
||||||
|
=head1 SEE ALSO
|
||||||
|
|
||||||
|
Path::Class, Path::Class::Dir, File::Spec
|
||||||
|
|
||||||
|
=cut
|
@ -0,0 +1,2 @@
|
|||||||
|
/VimColor.pm/1.1/Fri Apr 28 07:16:26 2006//
|
||||||
|
D/VimColor////
|
@ -0,0 +1 @@
|
|||||||
|
xsieve/experiments/programlisting/vimcolor/lib/Text
|
1
manual/docbook/programlisting/vimcolor/lib/Text/CVS/Root
Normal file
1
manual/docbook/programlisting/vimcolor/lib/Text/CVS/Root
Normal file
@ -0,0 +1 @@
|
|||||||
|
:pserver:anonymous@xsieve.cvs.sourceforge.net:/cvsroot/xsieve
|
845
manual/docbook/programlisting/vimcolor/lib/Text/VimColor.pm
Normal file
845
manual/docbook/programlisting/vimcolor/lib/Text/VimColor.pm
Normal file
@ -0,0 +1,845 @@
|
|||||||
|
package Text::VimColor;
|
||||||
|
use warnings;
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
use IO::File;
|
||||||
|
use File::Copy qw( copy );
|
||||||
|
use File::Temp qw( tempfile );
|
||||||
|
use Path::Class qw( file );
|
||||||
|
use Carp;
|
||||||
|
|
||||||
|
die "Text::VimColor can't see where it's installed"
|
||||||
|
unless -f __FILE__;
|
||||||
|
our $SHARED = file(__FILE__)->dir->subdir('VimColor')->stringify;
|
||||||
|
|
||||||
|
our $VERSION = '0.11';
|
||||||
|
our $VIM_COMMAND = 'vim';
|
||||||
|
our @VIM_OPTIONS = (qw( -RXZ -i NONE -u NONE -N ), "+set nomodeline");
|
||||||
|
our $NAMESPACE_ID = 'http://ns.laxan.com/text-vimcolor/1';
|
||||||
|
|
||||||
|
our %VIM_LET = (
|
||||||
|
perl_include_pod => 1,
|
||||||
|
'b:is_bash' => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
our %SYNTAX_TYPE = (
|
||||||
|
Comment => 1,
|
||||||
|
Constant => 1,
|
||||||
|
Identifier => 1,
|
||||||
|
Statement => 1,
|
||||||
|
PreProc => 1,
|
||||||
|
Type => 1,
|
||||||
|
Special => 1,
|
||||||
|
Underlined => 1,
|
||||||
|
Error => 1,
|
||||||
|
Todo => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
# Set to true to print the command line used to run Vim.
|
||||||
|
our $DEBUG = 0;
|
||||||
|
|
||||||
|
sub new
|
||||||
|
{
|
||||||
|
my ($class, %options) = @_;
|
||||||
|
|
||||||
|
$options{vim_command} = $VIM_COMMAND
|
||||||
|
unless defined $options{vim_command};
|
||||||
|
$options{vim_options} = \@VIM_OPTIONS
|
||||||
|
unless defined $options{vim_options};
|
||||||
|
|
||||||
|
$options{html_inline_stylesheet} = 1
|
||||||
|
unless exists $options{html_inline_stylesheet};
|
||||||
|
$options{xml_root_element} = 1
|
||||||
|
unless exists $options{xml_root_element};
|
||||||
|
|
||||||
|
$options{vim_let} = {
|
||||||
|
%VIM_LET,
|
||||||
|
(exists $options{vim_let} ? %{$options{vim_let}} : ()),
|
||||||
|
};
|
||||||
|
|
||||||
|
croak "only one of the 'file' or 'string' options should be used"
|
||||||
|
if defined $options{file} && defined $options{string};
|
||||||
|
|
||||||
|
my $self = bless \%options, $class;
|
||||||
|
$self->_do_markup
|
||||||
|
if defined $options{file} || defined $options{string};
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub vim_let
|
||||||
|
{
|
||||||
|
my ($self, %option) = @_;
|
||||||
|
|
||||||
|
while (my ($name, $value) = each %option) {
|
||||||
|
$self->{vim_let}->{$name} = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub syntax_mark_file
|
||||||
|
{
|
||||||
|
my ($self, $file, %options) = @_;
|
||||||
|
|
||||||
|
local $self->{filetype} = exists $options{filetype} ? $options{filetype}
|
||||||
|
: $self->{filetype};
|
||||||
|
|
||||||
|
local $self->{file} = $file;
|
||||||
|
$self->_do_markup;
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub syntax_mark_string
|
||||||
|
{
|
||||||
|
my ($self, $string, %options) = @_;
|
||||||
|
|
||||||
|
local $self->{filetype} = exists $options{filetype} ? $options{filetype}
|
||||||
|
: $self->{filetype};
|
||||||
|
|
||||||
|
local $self->{string} = $string;
|
||||||
|
$self->_do_markup;
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub html
|
||||||
|
{
|
||||||
|
my ($self) = @_;
|
||||||
|
my $syntax = $self->marked;
|
||||||
|
|
||||||
|
my $html = '';
|
||||||
|
$html .= $self->_html_header
|
||||||
|
if $self->{html_full_page};
|
||||||
|
|
||||||
|
foreach (@$syntax) {
|
||||||
|
$html .= _xml_escape($_->[1]), next
|
||||||
|
if $_->[0] eq '';
|
||||||
|
|
||||||
|
$html .= "<span class=\"syn$_->[0]\">" .
|
||||||
|
_xml_escape($_->[1]) .
|
||||||
|
'</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$html .= "</pre>\n\n </body>\n</html>\n"
|
||||||
|
if $self->{html_full_page};
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub xml
|
||||||
|
{
|
||||||
|
my ($self) = @_;
|
||||||
|
my $syntax = $self->marked;
|
||||||
|
|
||||||
|
my $xml = '';
|
||||||
|
if ($self->{xml_root_element}) {
|
||||||
|
my $filename = $self->input_filename;
|
||||||
|
$xml .= "<syn:syntax xmlns:syn=\"$NAMESPACE_ID\"";
|
||||||
|
$xml .= ' filename="' . _xml_escape($filename) . '"'
|
||||||
|
if defined $filename;;
|
||||||
|
$xml .= '>';
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (@$syntax) {
|
||||||
|
$xml .= _xml_escape($_->[1]), next
|
||||||
|
if $_->[0] eq '';
|
||||||
|
|
||||||
|
$xml .= "<syn:$_->[0]>" .
|
||||||
|
_xml_escape($_->[1]) .
|
||||||
|
"</syn:$_->[0]>";
|
||||||
|
}
|
||||||
|
|
||||||
|
$xml .= "</syn:syntax>\n"
|
||||||
|
if $self->{xml_root_element};
|
||||||
|
|
||||||
|
return $xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub marked
|
||||||
|
{
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
exists $self->{syntax}
|
||||||
|
or croak "an input file or string must be specified, either to 'new' or".
|
||||||
|
" 'syntax_mark_file/string'";
|
||||||
|
|
||||||
|
return $self->{syntax};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub input_filename
|
||||||
|
{
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
my $file = $self->{file};
|
||||||
|
return $file if defined $file && !ref $file;
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Return a string consisting of the start of an XHTML file, with a stylesheet
|
||||||
|
# either included inline or referenced with a <link>.
|
||||||
|
sub _html_header
|
||||||
|
{
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
my $input_filename = $self->input_filename;
|
||||||
|
my $title = defined $self->{html_title} ? _xml_escape($self->{html_title})
|
||||||
|
: defined $input_filename ? _xml_escape($input_filename)
|
||||||
|
: '[untitled]';
|
||||||
|
|
||||||
|
my $stylesheet;
|
||||||
|
if ($self->{html_inline_stylesheet}) {
|
||||||
|
$stylesheet = "<style>\n";
|
||||||
|
if ($self->{html_stylesheet}) {
|
||||||
|
$stylesheet .= _xml_escape($self->{html_stylesheet});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
my $file = $self->{html_stylesheet_file};
|
||||||
|
$file = file($SHARED, 'light.css')->stringify
|
||||||
|
unless defined $file;
|
||||||
|
unless (ref $file) {
|
||||||
|
$file = IO::File->new($file, 'r')
|
||||||
|
or croak "error reading stylesheet '$file': $!";
|
||||||
|
}
|
||||||
|
local $/;
|
||||||
|
$stylesheet .= _xml_escape(<$file>);
|
||||||
|
}
|
||||||
|
$stylesheet .= "</style>\n";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$stylesheet =
|
||||||
|
"<link rel=\"stylesheet\" type=\"text/css\" href=\"" .
|
||||||
|
_xml_escape($self->{html_stylesheet_url} ||
|
||||||
|
"file://$SHARED/light.css") .
|
||||||
|
"\" />\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"" .
|
||||||
|
" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" .
|
||||||
|
"<html>\n" .
|
||||||
|
" <head>\n" .
|
||||||
|
" <title>$title</title>\n" .
|
||||||
|
" $stylesheet" .
|
||||||
|
" </head>\n" .
|
||||||
|
" <body>\n\n" .
|
||||||
|
"<pre>";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Return a string safe to put in XML text or attribute values. It doesn't
|
||||||
|
# escape single quotes (') because we don't use those to quote
|
||||||
|
# attribute values.
|
||||||
|
sub _xml_escape
|
||||||
|
{
|
||||||
|
my ($s) = @_;
|
||||||
|
$s =~ s/&/&/g;
|
||||||
|
$s =~ s/</</g;
|
||||||
|
$s =~ s/>/>/g;
|
||||||
|
$s =~ s/"/"/g;
|
||||||
|
return $s;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Actually run Vim and turn the script's output into a datastructure.
|
||||||
|
sub _do_markup
|
||||||
|
{
|
||||||
|
my ($self) = @_;
|
||||||
|
my $vim_syntax_script = file($SHARED, 'mark.vim')->stringify;
|
||||||
|
|
||||||
|
croak "Text::VimColor syntax script '$vim_syntax_script' not installed"
|
||||||
|
unless -f $vim_syntax_script && -r $vim_syntax_script;
|
||||||
|
|
||||||
|
my $filename = $self->{file};
|
||||||
|
my $input_is_temporary = 0;
|
||||||
|
if (ref $self->{file}) {
|
||||||
|
my $fh;
|
||||||
|
($fh, $filename) = tempfile();
|
||||||
|
$input_is_temporary = 1;
|
||||||
|
|
||||||
|
binmode $self->{file};
|
||||||
|
binmode $fh;
|
||||||
|
copy($self->{file}, $fh);
|
||||||
|
}
|
||||||
|
elsif (exists $self->{string}) {
|
||||||
|
my $fh;
|
||||||
|
($fh, $filename) = tempfile();
|
||||||
|
$input_is_temporary = 1;
|
||||||
|
|
||||||
|
binmode $fh;
|
||||||
|
print $fh (ref $self->{string} ? ${$self->{string}} : $self->{string});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
croak "input file '$filename' not found"
|
||||||
|
unless -f $filename;
|
||||||
|
croak "input file '$filename' not accessible"
|
||||||
|
unless -r $filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create a temp file to put the output in.
|
||||||
|
my ($out_fh, $out_filename) = tempfile();
|
||||||
|
|
||||||
|
# Create a temp file for the 'script', which is given to vim
|
||||||
|
# with the -s option. This is necessary because it tells Vim not
|
||||||
|
# to delay for 2 seconds after displaying a message.
|
||||||
|
my ($script_fh, $script_filename) = tempfile();
|
||||||
|
my $filetype = $self->{filetype};
|
||||||
|
my $filetype_set = defined $filetype ? ":set filetype=$filetype" : '';
|
||||||
|
my $vim_let = $self->{vim_let};
|
||||||
|
print $script_fh (map { ":let $_=$vim_let->{$_}\n" }
|
||||||
|
grep { defined $vim_let->{$_} }
|
||||||
|
keys %$vim_let),
|
||||||
|
":filetype on\n",
|
||||||
|
"$filetype_set\n",
|
||||||
|
":source $vim_syntax_script\n",
|
||||||
|
":write! $out_filename\n",
|
||||||
|
":qall!\n";
|
||||||
|
close $script_fh;
|
||||||
|
|
||||||
|
$self->_run(
|
||||||
|
$self->{vim_command},
|
||||||
|
@{$self->{vim_options}},
|
||||||
|
$filename,
|
||||||
|
'-s', $script_filename,
|
||||||
|
);
|
||||||
|
|
||||||
|
unlink $filename
|
||||||
|
if $input_is_temporary;
|
||||||
|
unlink $out_filename;
|
||||||
|
unlink $script_filename;
|
||||||
|
|
||||||
|
my $data = do { local $/; <$out_fh> };
|
||||||
|
|
||||||
|
# Convert line endings to ones appropriate for the current platform.
|
||||||
|
$data =~ s/\x0D\x0A?/\n/g;
|
||||||
|
|
||||||
|
my $syntax = [];
|
||||||
|
LOOP: {
|
||||||
|
_add_markup($syntax, $1, $2), redo LOOP
|
||||||
|
if $data =~ /\G>(.*?)>(.*?)<\1</cgs;
|
||||||
|
_add_markup($syntax, '', $1), redo LOOP
|
||||||
|
if $data =~ /\G([^<>]+)/cgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->{syntax} = $syntax;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Given an array ref ($syntax), we add a new syntax chunk to it, unescaping
|
||||||
|
# the text and making sure that consecutive chunks of the same type are
|
||||||
|
# merged.
|
||||||
|
sub _add_markup
|
||||||
|
{
|
||||||
|
my ($syntax, $type, $text) = @_;
|
||||||
|
|
||||||
|
# Ignore types we don't know about. At least one syntax file (xml.vim)
|
||||||
|
# can produce these. It happens when a syntax type isn't 'linked' to
|
||||||
|
# one of the predefined types.
|
||||||
|
$type = ''
|
||||||
|
unless exists $SYNTAX_TYPE{$type};
|
||||||
|
|
||||||
|
# Unescape ampersands and pointies.
|
||||||
|
$text =~ s/&l/</g;
|
||||||
|
$text =~ s/&g/>/g;
|
||||||
|
$text =~ s/&a/&/g;
|
||||||
|
|
||||||
|
if (@$syntax && $syntax->[-1][0] eq $type) {
|
||||||
|
# Concatenate consecutive bits of the same type.
|
||||||
|
$syntax->[-1][1] .= $text;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# A new chunk of marked-up text.
|
||||||
|
push @$syntax, [ $type, $text ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# This is a private internal method which runs a program.
|
||||||
|
# It takes a list of the program name and arguments.
|
||||||
|
sub _run
|
||||||
|
{
|
||||||
|
my ($self, $prog, @args) = @_;
|
||||||
|
|
||||||
|
if ($DEBUG) {
|
||||||
|
print STDERR __PACKAGE__."::_run: $prog " .
|
||||||
|
join(' ', map { s/'/'\\''/g; "'$_'" } @args) . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
my ($err_fh, $err_filename) = tempfile();
|
||||||
|
my $old_fh = select($err_fh);
|
||||||
|
$| = 1;
|
||||||
|
select($old_fh);
|
||||||
|
|
||||||
|
my $pid = fork;
|
||||||
|
if ($pid) {
|
||||||
|
my $gotpid = waitpid($pid, 0);
|
||||||
|
croak "couldn't run the program '$prog'" if $gotpid == -1;
|
||||||
|
my $error = $? >> 8;
|
||||||
|
if ($error) {
|
||||||
|
seek $err_fh, 0, 0;
|
||||||
|
my $errout = do { local $/; <$err_fh> };
|
||||||
|
$errout =~ s/\n+\z//;
|
||||||
|
close $err_fh;
|
||||||
|
unlink $err_filename;
|
||||||
|
my $details = $errout eq '' ? '' :
|
||||||
|
"\nVim wrote this error output:\n$errout\n";
|
||||||
|
croak "$prog returned an error code of '$error'$details";
|
||||||
|
}
|
||||||
|
close $err_fh;
|
||||||
|
unlink $err_filename;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
defined $pid
|
||||||
|
or croak "error forking to run $prog: $!";
|
||||||
|
open STDIN, '/dev/null';
|
||||||
|
open STDOUT, '>/dev/null';
|
||||||
|
open STDERR, '>&=' . fileno($err_fh)
|
||||||
|
or croak "can't connect STDERR to temporary file '$err_filename': $!";
|
||||||
|
exec $prog $prog, @args;
|
||||||
|
die "\n"; # exec() will already have sent a suitable error message.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
Text::VimColor - syntax color text in HTML or XML using Vim
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
use Text::VimColor;
|
||||||
|
my $syntax = Text::VimColor->new(
|
||||||
|
file => $0,
|
||||||
|
filetype => 'perl',
|
||||||
|
);
|
||||||
|
|
||||||
|
print $syntax->html;
|
||||||
|
print $syntax->xml;
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
This module tries to markup text files according to their syntax. It can
|
||||||
|
be used to produce web pages with pretty-printed colourful source code
|
||||||
|
samples. It can produce output in the following formats:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item HTML
|
||||||
|
|
||||||
|
Valid XHTML 1.0, with the exact colouring and style left to a CSS stylesheet
|
||||||
|
|
||||||
|
=item XML
|
||||||
|
|
||||||
|
Pieces of text are marked with XML elements in a simple vocabulary,
|
||||||
|
which can be converted to other formats, for example, using XSLT
|
||||||
|
|
||||||
|
=item Perl array
|
||||||
|
|
||||||
|
A simple Perl data structure, so that Perl code can be used to turn it
|
||||||
|
into whatever is needed
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
This module works by running the Vim text editor and getting it to apply its
|
||||||
|
excellent syntax highlighting (aka 'font-locking') to an input file, and mark
|
||||||
|
pieces of text according to whether it thinks they are comments, keywords,
|
||||||
|
strings, etc. The Perl code then reads back this markup and converts it
|
||||||
|
to the desired output format.
|
||||||
|
|
||||||
|
This is an object-oriented module. To use it, create an object with
|
||||||
|
the C<new> function (as shown above in the SYNOPSIS) and then call methods
|
||||||
|
to get the markup out.
|
||||||
|
|
||||||
|
=head1 METHODS
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item new(I<options>)
|
||||||
|
|
||||||
|
Returns a syntax highlighting object. Pass it a hash of options.
|
||||||
|
|
||||||
|
The following options are recognised:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item file
|
||||||
|
|
||||||
|
The file to syntax highlight. Can be either a filename or an open file handle.
|
||||||
|
|
||||||
|
Note that using a filename might allow Vim to guess the file type from its
|
||||||
|
name if none is specified explicitly.
|
||||||
|
|
||||||
|
If the file isn't specified while creating the object, it can be given later
|
||||||
|
in a call to the C<syntax_mark_file> method (see below), allowing a single
|
||||||
|
Text::VimColor object to be used with multiple input files.
|
||||||
|
|
||||||
|
=item string
|
||||||
|
|
||||||
|
Use this to pass a string to be used as the input. This is an alternative
|
||||||
|
to the C<file> option. A reference to a string will also work.
|
||||||
|
|
||||||
|
The C<syntax_mark_string> method (see below) is another way to use a string
|
||||||
|
as input.
|
||||||
|
|
||||||
|
=item filetype
|
||||||
|
|
||||||
|
Specify the type of file Vim should expect, in case Vim's automatic
|
||||||
|
detection by filename or contents doesn't get it right. This is
|
||||||
|
particularly important when providing the file as a string of file
|
||||||
|
handle, since Vim won't be able to use the file extension to guess
|
||||||
|
the file type.
|
||||||
|
|
||||||
|
The filetypes recognised by Vim are short strings like 'perl' or 'lisp'.
|
||||||
|
They are the names of files in the 'syntax' directory in the Vim
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
This option, whether or not it is passed to C<new()>, can be overridden
|
||||||
|
when calling C<syntax_mark_file> and C<syntax_mark_string>, so you can
|
||||||
|
use the same object to process multiple files of different types.
|
||||||
|
|
||||||
|
=item html_full_page
|
||||||
|
|
||||||
|
By default the C<html()> output method returns a fragment of HTML, not a
|
||||||
|
full file. To make useful output this must be wrapped in a C<E<lt>preE<gt>>
|
||||||
|
element and a stylesheet must be included from somewhere. Setting the
|
||||||
|
C<html_full_page> option will instead make the C<html()> method return a
|
||||||
|
complete stand-alone XHTML file.
|
||||||
|
|
||||||
|
Note that while this is useful for testing, most of the time you'll want to
|
||||||
|
put the syntax highlighted source code in a page with some other content,
|
||||||
|
in which case the default output of the C<html()> method is more appropriate.
|
||||||
|
|
||||||
|
=item html_inline_stylesheet
|
||||||
|
|
||||||
|
Turned on by default, but has no effect unless C<html_full_page> is also
|
||||||
|
enabled.
|
||||||
|
|
||||||
|
This causes the CSS stylesheet defining the colours to be used
|
||||||
|
to render the markup to be be included in the HTML output, in a
|
||||||
|
C<E<lt>styleE<gt>> element. Turn it off to instead use a C<E<lt>linkE<gt>>
|
||||||
|
to reference an external stylesheet (recommended if putting more than one
|
||||||
|
page on the web).
|
||||||
|
|
||||||
|
=item html_stylesheet
|
||||||
|
|
||||||
|
Ignored unless C<html_full_page> and C<html_inline_stylesheet> are both
|
||||||
|
enabled.
|
||||||
|
|
||||||
|
This can be set to a stylesheet to include inline in the HTML output (the
|
||||||
|
actual CSS, not the filename of it).
|
||||||
|
|
||||||
|
=item html_stylesheet_file
|
||||||
|
|
||||||
|
Ignored unless C<html_full_page> and C<html_inline_stylesheet> are both
|
||||||
|
enabled.
|
||||||
|
|
||||||
|
This can be the filename of a stylesheet to copy into the HTML output,
|
||||||
|
or a file handle to read one from. If neither this nor C<html_stylesheet>
|
||||||
|
are given, the supplied stylesheet F<light.css> will be used instead.
|
||||||
|
|
||||||
|
=item html_stylesheet_url
|
||||||
|
|
||||||
|
Ignored unless C<html_full_page> is enabled and C<html_inline_stylesheet>
|
||||||
|
is disabled.
|
||||||
|
|
||||||
|
This can be used to supply the URL (relative or absolute) or the stylesheet
|
||||||
|
to be referenced from the HTML C<E<lt>linkE<gt>> element in the header.
|
||||||
|
If this isn't given it will default to using a C<file:> URL to reference
|
||||||
|
the supplied F<light.css> stylesheet, which is only really useful for testing.
|
||||||
|
|
||||||
|
=item xml_root_element
|
||||||
|
|
||||||
|
By default this is true. If set to a false value, XML output will not be
|
||||||
|
wrapped in a root element called <syn:syntax>, but will be otherwise the
|
||||||
|
same. This could allow XML output for several files to be concatenated,
|
||||||
|
but to make it valid XML a root element must be added. Disabling this
|
||||||
|
option will also remove the binding of the namespace prefix C<syn:>, so
|
||||||
|
an C<xmlns:syn> attribute would have to be added elsewhere.
|
||||||
|
|
||||||
|
=item vim_command
|
||||||
|
|
||||||
|
The name of the executable which will be run to invoke Vim.
|
||||||
|
The default is C<vim>.
|
||||||
|
|
||||||
|
=item vim_options
|
||||||
|
|
||||||
|
A reference to an array of options to pass to Vim. The default options are:
|
||||||
|
|
||||||
|
qw( -RXZ -i NONE -u NONE -N )
|
||||||
|
|
||||||
|
=item vim_let
|
||||||
|
|
||||||
|
A reference to a hash of options to set in Vim before the syntax file
|
||||||
|
is loaded. Each of these is set using the C<:let> command to the value
|
||||||
|
specified. No escaping is done on the values, they are executed exactly
|
||||||
|
as specified.
|
||||||
|
|
||||||
|
Values in this hash override some default options. Use a value of
|
||||||
|
C<undef> to prevent a default option from being set at all. The
|
||||||
|
defaults are as follows:
|
||||||
|
|
||||||
|
(
|
||||||
|
perl_include_pod => 1, # Recognize POD inside Perl code
|
||||||
|
'b:is_bash' => 1, # Allow Bash syntax in shell scripts
|
||||||
|
)
|
||||||
|
|
||||||
|
These settings can be modified later with the C<vim_let()> method.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=item vim_let(I<name> =E<gt> I<value>, ...)
|
||||||
|
|
||||||
|
Change the options that are set with the Vim C<let> command when Vim
|
||||||
|
is run. See C<new()> for details.
|
||||||
|
|
||||||
|
=item syntax_mark_file(I<file>, I<options...>)
|
||||||
|
|
||||||
|
Mark up the specified file. Subsequent calls to the output methods will then
|
||||||
|
return the markup. It is not necessary to call this if a C<file> or C<string>
|
||||||
|
option was passed to C<new()>.
|
||||||
|
|
||||||
|
Returns the object it was called on, so an output method can be called
|
||||||
|
on it directly:
|
||||||
|
|
||||||
|
my $syntax = Text::VimColor->new(
|
||||||
|
vim_command => '/usr/local/bin/special-vim',
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach (@files) {
|
||||||
|
print $syntax->syntax_mark_file($_)->html;
|
||||||
|
}
|
||||||
|
|
||||||
|
You can override the filetype set in new() by passing in a C<filetype>
|
||||||
|
option, like so:
|
||||||
|
|
||||||
|
$syntax->syntax_mark_file($filename, filetype => 'perl');
|
||||||
|
|
||||||
|
This option will only affect the syntax colouring for that one call,
|
||||||
|
not for any subsequent ones on the same object.
|
||||||
|
|
||||||
|
=item syntax_mark_string(I<string>, I<options...>)
|
||||||
|
|
||||||
|
Does the same as C<syntax_mark_file> (see above) but uses a string as input.
|
||||||
|
I<string> can also be a reference to a string.
|
||||||
|
Returns the object it was called on. Supports the C<filetype> option
|
||||||
|
just as C<syntax_mark_file> does.
|
||||||
|
|
||||||
|
=item html()
|
||||||
|
|
||||||
|
Return XHTML markup based on the Vim syntax colouring of the input file.
|
||||||
|
|
||||||
|
Unless the C<html_full_page> option is set, this will only return a fragment
|
||||||
|
of HTML, which can then be incorporated into a full page. The fragment
|
||||||
|
will be valid as either HTML and XHTML.
|
||||||
|
|
||||||
|
The only markup used for the actual text will be C<E<lt>spanE<gt>> elements
|
||||||
|
wrapped round appropriate pieces of text. Each one will have a C<class>
|
||||||
|
attribute set to a name which can be tied to a foreground and background
|
||||||
|
color in a stylesheet. The class names used will have the prefix C<syn>,
|
||||||
|
for example C<synComment>. For the full list see the section
|
||||||
|
HIGHLIGHTING TYPES below.
|
||||||
|
|
||||||
|
=item xml()
|
||||||
|
|
||||||
|
Returns markup in a simple XML vocabulary. Unless the C<xml_root_element>
|
||||||
|
option is turned off (it's on by default) this will produce a complete XML
|
||||||
|
document, with all the markup inside a C<E<lt>syntaxE<gt>> element.
|
||||||
|
|
||||||
|
This XML output can be transformed into other formats, either using programs
|
||||||
|
which read it with an XML parser, or using XSLT. See the
|
||||||
|
text-vimcolor(1) program for an example of how XSLT can be used with
|
||||||
|
XSL-FO to turn this into PDF.
|
||||||
|
|
||||||
|
The markup will consist of mixed content with elements wrapping pieces
|
||||||
|
of text which Vim recognized as being of a particular type. The names of
|
||||||
|
the elements used are the ones listed in the HIGHLIGHTING TYPES section
|
||||||
|
below.
|
||||||
|
|
||||||
|
The C<E<lt>syntaxE<gt>> element will declare the namespace for all the
|
||||||
|
elements prodeced, which will be C<http://ns.laxan.com/text-vimcolor/1>.
|
||||||
|
It will also have an attribute called C<filename>, which will be set to the
|
||||||
|
value returned by the C<input_filename> method, if that returns something
|
||||||
|
other than undef.
|
||||||
|
|
||||||
|
The XML namespace is also available as C<$Text::VimColor::NAMESPACE_ID>.
|
||||||
|
|
||||||
|
=item marked()
|
||||||
|
|
||||||
|
This output function returns the marked-up text in the format which the module
|
||||||
|
stores it in internally. The data looks like this:
|
||||||
|
|
||||||
|
use Data::Dumper;
|
||||||
|
print Dumper($syntax->marked);
|
||||||
|
|
||||||
|
$VAR1 = [
|
||||||
|
[ 'Statement', 'my' ],
|
||||||
|
[ '', ' ' ],
|
||||||
|
[ 'Identifier', '$syntax' ],
|
||||||
|
[ '', ' = ' ],
|
||||||
|
...
|
||||||
|
];
|
||||||
|
|
||||||
|
The C<marked()> method returns a reference to an array. Each item in the
|
||||||
|
array is itself a reference to an array of two items: the first is one of
|
||||||
|
the names listed in the HIGHLIGHTING TYPES section below (or the empty
|
||||||
|
string if none apply), and the second is the actual piece of text.
|
||||||
|
|
||||||
|
=item input_filename()
|
||||||
|
|
||||||
|
Returns the filename of the input file, or undef if a filename wasn't
|
||||||
|
specified.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 HIGHLIGHTING TYPES
|
||||||
|
|
||||||
|
The following list gives the names of highlighting types which will be
|
||||||
|
set for pieces of text. For HTML output, these will appear as CSS class
|
||||||
|
names, except that they will all have the prefix C<syn> added. For XML
|
||||||
|
output, these will be the names of elements which will all be in the
|
||||||
|
namespace C<http://ns.laxan.com/text-vimcolor/1>.
|
||||||
|
|
||||||
|
Here is the complete list:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Comment
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Constant
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Identifier
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Statement
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
PreProc
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Type
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Special
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Underlined
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Error
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Todo
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 RELATED MODULES
|
||||||
|
|
||||||
|
These modules allow Text::VimColor to be used more easily in particular
|
||||||
|
environments:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item L<Apache::VimColor>
|
||||||
|
|
||||||
|
=item L<Kwiki::VimMode>
|
||||||
|
|
||||||
|
=item L<Template-Plugin-VimColor>
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 SEE ALSO
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item text-vimcolor(1)
|
||||||
|
|
||||||
|
A simple command line interface to this module's features. It can be used
|
||||||
|
to produce HTML and XML output, and can also generate PDF output using
|
||||||
|
an XSLT/XSL-FO stylesheet and the FOP processor.
|
||||||
|
|
||||||
|
=item http://www.vim.org/
|
||||||
|
|
||||||
|
Everything to do with the Vim text editor.
|
||||||
|
|
||||||
|
=item http://ungwe.org/blog/
|
||||||
|
|
||||||
|
The author's weblog, which uses this module. It is used to make the code
|
||||||
|
samples look pretty.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 BUGS
|
||||||
|
|
||||||
|
Quite a few, actually:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Apparently this module doesn't always work if run from within a 'gvim'
|
||||||
|
window, although I've been unable to reproduce this so far.
|
||||||
|
CPAN bug #11555.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
Things can break if there is already a Vim swapfile, but sometimes it
|
||||||
|
seems to work.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
There should be a way of getting a DOM object back instead of an XML string.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
It should be possible to choose between HTML and XHTML, and perhaps there
|
||||||
|
should be some control over the DOCTYPE declaration when a complete file is
|
||||||
|
produced.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
With Vim versions earlier than 6.2 there is a 2 second delay each time
|
||||||
|
Vim is run.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
It doesn't work on Windows. I am unlikely to fix this, but if anyone
|
||||||
|
who knows Windows can sort it out let me know.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Geoff Richards E<lt>qef@laxan.comE<gt>
|
||||||
|
|
||||||
|
The Vim script F<mark.vim> is a crufted version of F<2html.vim> by
|
||||||
|
Bram Moolenaar E<lt>Bram@vim.orgE<gt> and
|
||||||
|
David Ne\v{c}as (Yeti) E<lt>yeti@physics.muni.czE<gt>.
|
||||||
|
|
||||||
|
=head1 COPYRIGHT
|
||||||
|
|
||||||
|
Copyright 2002-2006, Geoff Richards.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the same terms as Perl itself.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
# Local Variables:
|
||||||
|
# mode: perl
|
||||||
|
# perl-indent-level: 3
|
||||||
|
# perl-continued-statement-offset: 3
|
||||||
|
# End:
|
||||||
|
# vi:ts=3 sw=3 expandtab:
|
@ -0,0 +1,4 @@
|
|||||||
|
/light.css/1.1/Fri Apr 28 07:16:26 2006//
|
||||||
|
/light.xsl/1.1/Fri Apr 28 07:16:26 2006//
|
||||||
|
/mark.vim/1.1/Fri Apr 28 07:16:26 2006//
|
||||||
|
D
|
@ -0,0 +1 @@
|
|||||||
|
xsieve/experiments/programlisting/vimcolor/lib/Text/VimColor
|
@ -0,0 +1 @@
|
|||||||
|
:pserver:anonymous@xsieve.cvs.sourceforge.net:/cvsroot/xsieve
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* A stylesheet designed to be used with the HTML output of the
|
||||||
|
* Perl module Text::Highlight::Vim.
|
||||||
|
*
|
||||||
|
* This is designed to make the highlighting look like the default gvim
|
||||||
|
* colour scheme, with 'background=light'.
|
||||||
|
*
|
||||||
|
* Geoff Richards (qef@laxan.com)
|
||||||
|
*
|
||||||
|
* This CSS file (light.css) is public domain. Do what you want with it.
|
||||||
|
* That doesn't mean that HTML with this CSS in is public domain.
|
||||||
|
*/
|
||||||
|
|
||||||
|
body { color: black; background: white none }
|
||||||
|
|
||||||
|
A:link { color: #00F; background: white none }
|
||||||
|
A:visited { color: #909; background: white none }
|
||||||
|
A:hover { color: #F00; background: white none }
|
||||||
|
A:active { color: #F00; background: white none }
|
||||||
|
|
||||||
|
.synComment { color: #0000FF }
|
||||||
|
.synConstant { color: #FF00FF }
|
||||||
|
.synIdentifier { color: #008B8B }
|
||||||
|
.synStatement { color: #A52A2A ; font-weight: bold }
|
||||||
|
.synPreProc { color: #A020F0 }
|
||||||
|
.synType { color: #2E8B57 ; font-weight: bold }
|
||||||
|
.synSpecial { color: #6A5ACD }
|
||||||
|
.synUnderlined { color: #000000 ; text-decoration: underline }
|
||||||
|
.synError { color: #FFFFFF ; background: #FF0000 none }
|
||||||
|
.synTodo { color: #0000FF ; background: #FFFF00 none }
|
@ -0,0 +1,128 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
This is an XSLT/XSL-FO stylesheet designed to be used with the XML
|
||||||
|
output of the Perl module Text::VimColor.
|
||||||
|
|
||||||
|
This is designed to make the highlighting look like the default gvim
|
||||||
|
colour scheme, with 'background=light'.
|
||||||
|
|
||||||
|
Geoff Richards <qef@laxan.com>
|
||||||
|
|
||||||
|
This XSL file (light.xsl) is public domain. Do what you want with it.
|
||||||
|
|
||||||
|
Bugs: background colouring doesn't work in FOP.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<xsl:stylesheet version="1.0"
|
||||||
|
xmlns:fo="http://www.w3.org/1999/XSL/Format"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:syn="http://ns.laxan.com/text-vimcolor/1">
|
||||||
|
|
||||||
|
<xsl:template match="syn:syntax">
|
||||||
|
<fo:root>
|
||||||
|
|
||||||
|
<fo:layout-master-set>
|
||||||
|
|
||||||
|
<!-- Master for odd (right hand) pages -->
|
||||||
|
<fo:simple-page-master master-name="recto"
|
||||||
|
page-height="297mm" page-width="210mm"
|
||||||
|
margin-top="10mm" margin-left="25mm"
|
||||||
|
margin-bottom="10mm" margin-right="15mm">
|
||||||
|
<fo:region-body margin-top="10mm" margin-bottom="10mm"/>
|
||||||
|
<fo:region-before extent="10mm"/>
|
||||||
|
<fo:region-after extent="10mm"/>
|
||||||
|
</fo:simple-page-master>
|
||||||
|
|
||||||
|
<!-- Master for even (left hand) pages -->
|
||||||
|
<fo:simple-page-master master-name="verso"
|
||||||
|
page-height="297mm" page-width="210mm"
|
||||||
|
margin-top="10mm" margin-left="15mm"
|
||||||
|
margin-bottom="10mm" margin-right="25mm">
|
||||||
|
<fo:region-body margin-top="10mm" margin-bottom="10mm"/>
|
||||||
|
<fo:region-before extent="10mm"/>
|
||||||
|
<fo:region-after extent="10mm"/>
|
||||||
|
</fo:simple-page-master>
|
||||||
|
|
||||||
|
<fo:page-sequence-master master-name="recto-verso">
|
||||||
|
<fo:repeatable-page-master-alternatives>
|
||||||
|
<fo:conditional-page-master-reference
|
||||||
|
master-name="recto" odd-or-even="odd"/>
|
||||||
|
<fo:conditional-page-master-reference
|
||||||
|
master-name="verso" odd-or-even="even"/>
|
||||||
|
</fo:repeatable-page-master-alternatives>
|
||||||
|
</fo:page-sequence-master>
|
||||||
|
|
||||||
|
</fo:layout-master-set>
|
||||||
|
|
||||||
|
<fo:page-sequence master-reference="recto">
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<fo:static-content flow-name="xsl-region-before">
|
||||||
|
<fo:block text-align="end" font-size="10pt"
|
||||||
|
font-family="sans-serif" font-style="italic">
|
||||||
|
<xsl:value-of select="@filename"/>
|
||||||
|
</fo:block>
|
||||||
|
</fo:static-content>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<fo:static-content flow-name="xsl-region-after">
|
||||||
|
<fo:block text-align="end" font-size="10pt" font-family="sans-serif">
|
||||||
|
<fo:page-number/>
|
||||||
|
</fo:block>
|
||||||
|
</fo:static-content>
|
||||||
|
|
||||||
|
<!-- Body text -->
|
||||||
|
<fo:flow flow-name="xsl-region-body">
|
||||||
|
<fo:block font-family="monospace" font-size="10pt" line-height="12pt"
|
||||||
|
white-space-collapse="false">
|
||||||
|
<xsl:apply-templates/>
|
||||||
|
</fo:block>
|
||||||
|
</fo:flow>
|
||||||
|
|
||||||
|
</fo:page-sequence>
|
||||||
|
|
||||||
|
</fo:root>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:Comment">
|
||||||
|
<fo:inline color="#0000FF"><xsl:apply-templates/></fo:inline>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:Constant">
|
||||||
|
<fo:inline color="#FF00FF"><xsl:apply-templates/></fo:inline>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:Identifier">
|
||||||
|
<fo:inline color="#008B8B"><xsl:apply-templates/></fo:inline>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:Statement">
|
||||||
|
<fo:inline color="#A52A2A" font-weight="bold"><xsl:apply-templates/></fo:inline>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:PreProc">
|
||||||
|
<fo:inline color="#A020F0"><xsl:apply-templates/></fo:inline>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:Type">
|
||||||
|
<fo:inline color="#2E8B57" font-weight="bold"><xsl:apply-templates/></fo:inline>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:Special">
|
||||||
|
<fo:inline color="#6A5ACD"><xsl:apply-templates/></fo:inline>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:Underlined">
|
||||||
|
<fo:inline text-decoration="underline"><xsl:apply-templates/></fo:inline>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:Error">
|
||||||
|
<fo:inline color="#FFFFFF" background-color="#FF0000"><xsl:apply-templates/></fo:inline>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="syn:Todo">
|
||||||
|
<fo:inline color="#0000FF" background-color="#FFFF00"><xsl:apply-templates/></fo:inline>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
@ -0,0 +1,67 @@
|
|||||||
|
" mark.vim - turn Vim syntax highlighting into an ad-hoc markup language that
|
||||||
|
" can be parsed by the Text::VimColor Perl module.
|
||||||
|
"
|
||||||
|
" Maintainer: Geoff Richards <qef@laxan.com>
|
||||||
|
" Based loosely on 2html.vim, by Bram Moolenaar <Bram@vim.org>,
|
||||||
|
" modified by David Ne\v{c}as (Yeti) <yeti@physics.muni.cz>.
|
||||||
|
|
||||||
|
set report=1000000
|
||||||
|
|
||||||
|
" For some reason (I'm sure it used to work) we now need to get Vim
|
||||||
|
" to make another attempt to detect the filetype if it wasn't set
|
||||||
|
" explicitly.
|
||||||
|
if !strlen(&filetype)
|
||||||
|
filetype detect
|
||||||
|
endif
|
||||||
|
syn on
|
||||||
|
|
||||||
|
" Set up the output buffer.
|
||||||
|
new
|
||||||
|
set modifiable
|
||||||
|
set paste
|
||||||
|
|
||||||
|
" Expand tabs. Without this they come out as '^I'.
|
||||||
|
set isprint+=9
|
||||||
|
|
||||||
|
wincmd p
|
||||||
|
|
||||||
|
" Loop over all lines in the original text
|
||||||
|
let s:end = line("$")
|
||||||
|
let s:lnum = 1
|
||||||
|
while s:lnum <= s:end
|
||||||
|
|
||||||
|
" Get the current line
|
||||||
|
let s:line = getline(s:lnum)
|
||||||
|
let s:len = strlen(s:line)
|
||||||
|
let s:new = ""
|
||||||
|
|
||||||
|
" Loop over each character in the line
|
||||||
|
let s:col = 1
|
||||||
|
while s:col <= s:len
|
||||||
|
let s:startcol = s:col " The start column for processing text
|
||||||
|
let s:id = synID(s:lnum, s:col, 1)
|
||||||
|
let s:col = s:col + 1
|
||||||
|
" Speed loop (it's small - that's the trick)
|
||||||
|
" Go along till we find a change in synID
|
||||||
|
while s:col <= s:len && s:id == synID(s:lnum, s:col, 1) | let s:col = s:col + 1 | endwhile
|
||||||
|
|
||||||
|
" Output the text with the same synID, with class set to c{s:id}
|
||||||
|
let s:id = synIDtrans(s:id)
|
||||||
|
let s:name = synIDattr(s:id, 'name')
|
||||||
|
let s:new = s:new . '>' . s:name . '>' . substitute(substitute(substitute(strpart(s:line, s:startcol - 1, s:col - s:startcol), '&', '\&a', 'g'), '<', '\&l', 'g'), '>', '\&g', 'g') . '<' . s:name . '<'
|
||||||
|
|
||||||
|
if s:col > s:len
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
exe "normal \<C-W>pa" . strtrans(s:new) . "\n\e\<C-W>p"
|
||||||
|
let s:lnum = s:lnum + 1
|
||||||
|
+
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
" Strip whitespace from the ends of lines
|
||||||
|
%s:\s\+$::e
|
||||||
|
|
||||||
|
wincmd p
|
||||||
|
normal dd
|
278
manual/docbook/programlisting/vimcolor/text-vimcolor
Executable file
278
manual/docbook/programlisting/vimcolor/text-vimcolor
Executable file
@ -0,0 +1,278 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
use Text::VimColor;
|
||||||
|
use Getopt::Long;
|
||||||
|
use File::Temp qw( tempfile );
|
||||||
|
use IO::File;
|
||||||
|
use Path::Class qw( file );
|
||||||
|
|
||||||
|
my $XSL_STYLESHEET = file($Text::VimColor::SHARED, 'light.xsl');
|
||||||
|
|
||||||
|
# Default values for options.
|
||||||
|
my $filetype;
|
||||||
|
my $format;
|
||||||
|
my $usage;
|
||||||
|
my $output_filename;
|
||||||
|
my $html_full_page;
|
||||||
|
my $html_no_inline_stylesheet;
|
||||||
|
my @let;
|
||||||
|
my @unlet;
|
||||||
|
|
||||||
|
my $option = GetOptions(
|
||||||
|
'debug' => \$Text::VimColor::DEBUG,
|
||||||
|
'filetype=s' => \$filetype,
|
||||||
|
'format=s' => \$format,
|
||||||
|
'help' => \$usage,
|
||||||
|
'output=s' => \$output_filename,
|
||||||
|
'full-page' => \$html_full_page,
|
||||||
|
'no-inline-stylesheet' => \$html_no_inline_stylesheet,
|
||||||
|
'let=s' => \@let,
|
||||||
|
'unlet=s' => \@unlet,
|
||||||
|
'usage' => \$usage,
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($usage) {
|
||||||
|
print STDERR
|
||||||
|
"Usage: $0 --format html|xml [options] filename\n",
|
||||||
|
" $0 --format pdf --output foo.pdf [options] filename\n",
|
||||||
|
"(the output is written to standard output, except in PDF\n",
|
||||||
|
"mode, where you have to supply a filename for the output.)\n",
|
||||||
|
"\n",
|
||||||
|
"Options:\n",
|
||||||
|
" --debug turn on Text::VimColor debugging mode\n",
|
||||||
|
" --filetype set Vim filetype name, if it can't be guessed from\n",
|
||||||
|
" the file's name or contents\n",
|
||||||
|
" --format set format to use for output, can be xml,\n",
|
||||||
|
" html, or pdf\n",
|
||||||
|
" --help show this helpful message\n",
|
||||||
|
" --output set filename to write output to (required with\n",
|
||||||
|
" PDF format, otherwise defaults to standard output)\n",
|
||||||
|
" --full-page output a complete HTML page, not just a fragment\n",
|
||||||
|
" --no-inline-stylesheet\n",
|
||||||
|
" don't include the stylesheet in a complete HTML page\n",
|
||||||
|
" --let set a Vim variable with the Vim :let command\n",
|
||||||
|
" --unlet turn off default setting of a Vim variable\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
defined $format
|
||||||
|
or die "$0: an output format must be specified (html, pdf or xml).\n";
|
||||||
|
|
||||||
|
$format = lc $format;
|
||||||
|
$format eq 'html' || $format eq 'pdf' || $format eq 'xml'
|
||||||
|
or die "$0: invalid output format '$format' (must be html, pdf or xml).\n";
|
||||||
|
|
||||||
|
my $output;
|
||||||
|
if (defined $output_filename) {
|
||||||
|
$output = IO::File->new($output_filename, 'w')
|
||||||
|
or die "$0: error opening output file '$output_filename': $!\n";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$format ne 'pdf'
|
||||||
|
or die "$0: an output file must be specified with '--format pdf'.\n";
|
||||||
|
|
||||||
|
$output = \*STDOUT;
|
||||||
|
$output_filename = '<stdout>';
|
||||||
|
}
|
||||||
|
|
||||||
|
@ARGV <= 1
|
||||||
|
or die "$0: only one input filename should be specified.\n";
|
||||||
|
|
||||||
|
my $file = @ARGV ? shift : \*STDIN;
|
||||||
|
|
||||||
|
my $syntax = Text::VimColor->new(
|
||||||
|
filetype => $filetype,
|
||||||
|
html_full_page => $html_full_page,
|
||||||
|
html_inline_stylesheet => !$html_no_inline_stylesheet,
|
||||||
|
);
|
||||||
|
|
||||||
|
# Handle the --let and --unlet options.
|
||||||
|
foreach (@unlet) {
|
||||||
|
$syntax->vim_let($_ => undef);
|
||||||
|
}
|
||||||
|
foreach (@let) {
|
||||||
|
my ($name, $value) = /^(.*?)=(.*)\z/
|
||||||
|
or die "$0: bad --let option '$_'\n";
|
||||||
|
print STDERR "[$name] [$value]\n";
|
||||||
|
$syntax->vim_let($name => $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$syntax->syntax_mark_file($file);
|
||||||
|
|
||||||
|
if ($format eq 'xml') {
|
||||||
|
print $output $syntax->xml
|
||||||
|
or die "$0: error writing to output file '$output_filename': $!\n";
|
||||||
|
}
|
||||||
|
elsif ($format eq 'html') {
|
||||||
|
print $output $syntax->html
|
||||||
|
or die "$0: error writing to output file '$output_filename': $!\n";
|
||||||
|
}
|
||||||
|
else { # ($format eq 'pdf')
|
||||||
|
my ($fh, $tmp_filename) = tempfile();
|
||||||
|
print $fh $syntax->xml
|
||||||
|
or die "$0: error writing to temporary file '$tmp_filename': $!\n";
|
||||||
|
|
||||||
|
system('fop', '-xsl', $XSL_STYLESHEET,
|
||||||
|
'-xml', $tmp_filename,
|
||||||
|
'-pdf', $output_filename) == 0
|
||||||
|
or die "$0: error running 'fop' (exit code was $?).\n";
|
||||||
|
|
||||||
|
unlink $tmp_filename
|
||||||
|
or die "$0: error deleting temporary file '$tmp_filename': $!\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
text-vimcolor - command-line program to syntax color a file in HTML, XML or PDF
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
$ text-vimcolor --format html --full-page FILENAME > OUTPUT.html
|
||||||
|
$ text-vimcolor --format xml FILENAME > OUTPUT.xml
|
||||||
|
$ text-vimcolor --format pdf FILENAME --output OUTPUT.pdf
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
This program uses the Vim text editor to highlight text according to its
|
||||||
|
syntax, and turn the highlighting into HTML, XML or PDF output. It works
|
||||||
|
with any file type which Vim itself can highlight. Usually Vim will be
|
||||||
|
able to autodetect the file format based on the filename (and sometimes the
|
||||||
|
contents of the file).
|
||||||
|
|
||||||
|
Exactly one filename should be given on the command line to name the input
|
||||||
|
file. If none is given input will instead be read from stdin (the standard
|
||||||
|
input).
|
||||||
|
|
||||||
|
If Vim can't guess the file type automatically, it can be specified explicitly
|
||||||
|
using the C<--filetype> option. For example:
|
||||||
|
|
||||||
|
$ text-vimcolor --format html --filetype prolog foo.pl > foo.html
|
||||||
|
|
||||||
|
This program is a command line interface to the Perl module Text::VimColor.
|
||||||
|
|
||||||
|
=head1 OPTIONS
|
||||||
|
|
||||||
|
The following options are understood:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item --help
|
||||||
|
|
||||||
|
Show a summary of the usage, including a list of options.
|
||||||
|
|
||||||
|
=item --debug
|
||||||
|
|
||||||
|
Turns on debugging in the underlying Perl module. This makes it print
|
||||||
|
the command used to run Vim.
|
||||||
|
|
||||||
|
=item --filetype I<file-type>
|
||||||
|
|
||||||
|
Set the type of the file explicitly. The I<file-type> argument should be
|
||||||
|
something which Vim will recognise when set with its C<filetype> option.
|
||||||
|
Examples are C<perl>, C<cpp> (for C++) and C<sh> (for Unix shell scripts).
|
||||||
|
These names are case sensitive, and should usually be all-lowercase.
|
||||||
|
|
||||||
|
=item --format I<output-format>
|
||||||
|
|
||||||
|
The output format to generate. Must be one of the following:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item html
|
||||||
|
|
||||||
|
Generate XHTML output, with text marked with C<E<lt>spanE<gt>> elements
|
||||||
|
with C<class> attributes. A CSS stylesheet should be used to define the
|
||||||
|
coloring, etc., for the output. See the C<--full-page> option below.
|
||||||
|
|
||||||
|
=item xml
|
||||||
|
|
||||||
|
Output is in a simple XML vocabulary. This can then be used by other
|
||||||
|
software to do further transformations (e.g., using XSLT).
|
||||||
|
|
||||||
|
=item pdf
|
||||||
|
|
||||||
|
XML output is generated and fed to the FOP XSL-FO processor, with an
|
||||||
|
appropriate XSL style sheet. The stylesheet uses XSLT to transform the
|
||||||
|
normal XML output into XSL-FO, which is then rendered to PDF. For this
|
||||||
|
to work, the command C<fop> must be available. An output file must be
|
||||||
|
specified with C<--output> with this format.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
Full details of the HTML and XML output formats can be found in the
|
||||||
|
documentation for Text::VimColor.
|
||||||
|
|
||||||
|
=item --output I<output-filename>
|
||||||
|
|
||||||
|
Specifies the name of the output file (which will end up containing either
|
||||||
|
HTML, XML or PDF). If this option is omitted, the output will be sent
|
||||||
|
to stdout (the standard output). This option is required when the output
|
||||||
|
format is PDF (because of limitations in FOP).
|
||||||
|
|
||||||
|
=item --full-page
|
||||||
|
|
||||||
|
When the output format is HTML, this option will make the output a complete
|
||||||
|
HTML page, rather than just a fragment of HTML. A CSS stylesheet will be
|
||||||
|
inserted inline into the output, so the output will be useable as it is.
|
||||||
|
|
||||||
|
=item --no-inline-stylesheet
|
||||||
|
|
||||||
|
When the output format is HTML and C<--fullpage> is given, a stylesheet
|
||||||
|
is normally inserted in-line in the output file. If this option is given it
|
||||||
|
will instead be referenced with a C<E<lt>linkE<gt>> element.
|
||||||
|
|
||||||
|
=item --let I<name>=I<value>
|
||||||
|
|
||||||
|
When Vim is run the value of I<name> will be set to I<value> using
|
||||||
|
Vim's C<let> command. More than one of these options can be set.
|
||||||
|
The value is not quoted or escaped in any way, so it can be an expression.
|
||||||
|
These settings take precedence over C<--unlet> options.
|
||||||
|
|
||||||
|
This option corresponds to the C<vim_let> setting and method in
|
||||||
|
the Perl module.
|
||||||
|
|
||||||
|
=item --unlet I<name>
|
||||||
|
|
||||||
|
Prevent the value of I<name> being set with Vim's C<let> command.
|
||||||
|
This can be used to turn off default settings.
|
||||||
|
|
||||||
|
This option corresponds to the C<vim_let> setting and method in
|
||||||
|
the Perl module, when used with a value of C<undef>.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 BUGS
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
The PDF output option often doesn't work, because it is dependent on FOP,
|
||||||
|
which often doesn't work. This is also why it is mind numbingly slow.
|
||||||
|
|
||||||
|
=item *
|
||||||
|
|
||||||
|
FOP (0.20.3) seems to ignore the C<background-color> property on
|
||||||
|
C<E<lt>fo:inlineE<gt>>. If that's what it's meant to do, how do you set the
|
||||||
|
background color on part of a line?
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Geoff Richards E<lt>qef@laxan.comE<gt>
|
||||||
|
|
||||||
|
=head1 COPYRIGHT
|
||||||
|
|
||||||
|
Copyright 2002-2006, Geoff Richards.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the same terms as Perl.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
# vi:ts=3 sw=3 expandtab
|
9
manual/docbook/programlisting/vimcolor/vimcolor-wrapper
Executable file
9
manual/docbook/programlisting/vimcolor/vimcolor-wrapper
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
DIR=`dirname $0`
|
||||||
|
|
||||||
|
PERL5LIB=$DIR/lib:$PERL5LIB
|
||||||
|
export PERL5LIB
|
||||||
|
|
||||||
|
$DIR/text-vimcolor "$@"
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user