----------------------------------------------------------------------- -- RTF exporter in Lua for SciTE -- Version 0.9.3, 20070805 -- -- Adapted from SciTE sources (scite/src/Exporters.cxx CVS 20040723) -- by Kein-Hong Man (This is a straightforward -- conversion and so I decline to claim it as my own.) -- -- Copyright 1998-2007 by Neil Hodgson -- All Rights Reserved -- -- Permission to use, copy, modify, and distribute this software and -- its documentation for any purpose and without fee is hereby granted, -- provided that the above copyright notice appear in all copies and -- that both that copyright notice and this permission notice appear in -- supporting documentation. -- -- NEIL HODGSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -- INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN -- NO EVENT SHALL NEIL HODGSON BE LIABLE FOR ANY SPECIAL, INDIRECT OR -- CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -- OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION -- WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -- ----------------------------------------------------------------------- -- USAGE -- -- * Please see SciTELuaExporters.html for notes on how to get this -- exporter up and running. -- * Requires SciTE_ExportBase.lua to be loaded first. -- * The start and end arguments to the RTF function have been removed -- but they can be implemented without too much trouble. -- * Has been tested casually with these lexers: lua, props, cpp and -- basic text, giving byte-for-byte identical output. ----------------------------------------------------------------------- ----------------------------------------------------------------------- -- a simple check to alert of namespace collision, but allows different -- files to define their own functions in the exporters table ----------------------------------------------------------------------- if exporters then if exporters.SaveToRTF then error("SciTE_ExporterRTF: exporters.SaveToRTF already defined") end else exporters = {} end ----------------------------------------------------------------------- -- exporters:SaveToRTF -- -- Exports the document in the current window to a RTF format file. -- ----------------------------------------------------------------------- function exporters:SaveToRTF() local selBeg, selEnd = exportutil.GetSelPos() local RTFDefaultTabSize = 4 local RTF_HEADEROPEN = "{\\rtf1\\ansi\\deff0\\deftab720" local RTF_FONTDEFOPEN = "{\\fonttbl" local RTF_FONTDEF = "{\\f%d\\fnil\\fcharset%u %s;}" local RTF_FONTDEFCLOSE = "}" local RTF_COLORDEFOPEN = "{\\colortbl" local RTF_COLORDEF = "\\red%d\\green%d\\blue%d;" local RTF_COLORDEFCLOSE = "}" local RTF_HEADERCLOSE = "\n" local RTF_BODYOPEN = "" local RTF_BODYCLOSE = "}" local RTF_SETFONTFACE = "\\f" local RTF_SETFONTSIZE = "\\fs" local RTF_SETCOLOR = "\\cf" local RTF_SETBACKGROUND = "\\highlight" local RTF_BOLD_ON = "\\b" local RTF_BOLD_OFF = "\\b0" local RTF_ITALIC_ON = "\\i" local RTF_ITALIC_OFF = "\\i0" local RTF_UNDERLINE_ON = "\\ul" local RTF_UNDERLINE_OFF = "\\ulnone" local RTF_STRIKE_ON = "\\i" local RTF_STRIKE_OFF = "\\strike0" local RTF_EOLN = "\\par\n" local RTF_TAB = "\\tab " local MAX_STYLEDEF = 128 local MAX_FONTDEF = 64 local MAX_COLORDEF = 8 local RTF_FONTFACE = "Courier New" local RTF_COLOR = "#000000" -- the original C code was rather bizzare... local function GetRTFStyleChange(last, current) -- \f0\fs20\cf0\highlight0\b0\i0 local function GetNextElem(style) local x, y = string.find(style, "\\", 2, 1) if not x then return style, "" end return string.sub(style, 1, x - 1), string.sub(style, x, -1) end local lastElem, currentElem local delta = "" -- font face, size, color, background, bold, italic for i = 1,6 do lastElem, last = GetNextElem(last) currentElem, current = GetNextElem(current) if lastElem ~= currentElem then -- change delta = delta..currentElem end end if delta ~= "" then delta = delta.." " end return delta end -- local lengthDoc = editor.Length editor:Colourise(0, -1) -- Read the default settings stylemgr:setlexer(editor.Lexer) local defaultStyle = stylemgr.styles[32] local tabSize = tonumber(props["export.rtf.tabsize"]) if not tabSize or tabSize == 0 then tabSize = tonumber(props["tabsize"]) if not tabSize or tabSize == 0 then tabSize = RTFDefaultTabSize end end local wysiwyg = tonumber(props["export.rtf.wysiwyg"]) or 1 local fontFace = props["export.rtf.font.face"] if fontFace and fontFace ~= "" then defaultStyle.font = fontFace elseif defaultStyle.font == "" then defaultStyle.font = RTF_FONTFACE end local fontSize = tonumber(props["export.rtf.font.size"]) or 0 if fontSize > 0 then defaultStyle.size = fontSize * 2 elseif defaultStyle.size == 0 then defaultStyle.size = 10 * 2 else defaultStyle.size = defaultStyle.size * 2 end local characterset = tonumber(props["character.set"]) or SC_CHARSET_DEFAULT local tabs = tonumber(props["export.rtf.tabs"]) or false local saveName = exportutil.exportfile(props["FileDir"], props["FileName"], "rtf") local fp = io.open(saveName, "wt") if not fp then error("exporters:SaveToRTF: could not save file \""..saveName.."\"") end if exportutil.VERBOSE ~= 0 then _ALERT("\nExporting to RTF, filepath: "..saveName) end local styles = {} local fonts = {} local colors = {} local lastStyle, deltaStyle local fontCount = 1 local colorCount = 2 local ifound fp:write(RTF_HEADEROPEN..RTF_FONTDEFOPEN); fonts[1] = defaultStyle.font fp:write(string.format(RTF_FONTDEF, 0, characterset, defaultStyle.font)) colors[1] = defaultStyle.fore colors[2] = defaultStyle.back for istyle = 0, exportutil.STYLE_DEFAULT - 1 do local sd = stylemgr:locate(istyle) if sd.specified ~= "" then if wysiwyg and string.match(sd.specified, "font") then ifound = nil for i = 1, fontCount do if string.lower(sd.font) == string.lower(fonts[i]) then ifound = i; break end end if not ifound then fontCount = fontCount + 1 fonts[fontCount] = sd.font ifound = fontCount fp:write(string.format(RTF_FONTDEF, ifound - 1, characterset, sd.font)) end lastStyle = RTF_SETFONTFACE..(ifound - 1) else lastStyle = RTF_SETFONTFACE.."0" end lastStyle = lastStyle..RTF_SETFONTSIZE if wysiwyg and string.match(sd.specified, "size") then lastStyle = lastStyle..(sd.size * 2) else lastStyle = lastStyle..defaultStyle.size end if string.match(sd.specified, "fore") then ifound = nil for i = 1, colorCount do if stylemgr:hexstr(sd.fore) == stylemgr:hexstr(colors[i]) then ifound = i; break end end if not ifound then colorCount = colorCount + 1 colors[colorCount] = sd.fore ifound = colorCount end lastStyle = lastStyle..RTF_SETCOLOR..(ifound - 1) else lastStyle = lastStyle..RTF_SETCOLOR.."0" -- Default fore end if string.match(sd.specified, "back") then ifound = nil for i = 1, colorCount do if stylemgr:hexstr(sd.back) == stylemgr:hexstr(colors[i]) then ifound = i; break end end if not ifound then colorCount = colorCount + 1 colors[colorCount] = sd.back ifound = colorCount end lastStyle = lastStyle..RTF_SETBACKGROUND..(ifound - 1) else lastStyle = lastStyle..RTF_SETBACKGROUND.."1" -- Default back end if string.match(sd.specified, "bold") then lastStyle = lastStyle..(sd.bold and RTF_BOLD_ON or RTF_BOLD_OFF) else lastStyle = lastStyle..(defaultStyle.bold and RTF_BOLD_ON or RTF_BOLD_OFF) end if string.match(sd.specified, "italics") then lastStyle = lastStyle..(sd.italics and RTF_ITALIC_ON or RTF_ITALIC_OFF) else lastStyle = lastStyle..(defaultStyle.italics and RTF_ITALIC_ON or RTF_ITALIC_OFF) end styles[istyle] = lastStyle else styles[istyle] = RTF_SETFONTFACE.."0"..RTF_SETFONTSIZE..defaultStyle.size.. RTF_SETCOLOR.."0"..RTF_SETBACKGROUND.."1".. RTF_BOLD_OFF..RTF_ITALIC_OFF end--if sd.specified end--for fp:write(RTF_FONTDEFCLOSE..RTF_COLORDEFOPEN) for i = 1, colorCount do fp:write(string.format(RTF_COLORDEF, colors[i].r, colors[i].g, colors[i].b)) end fp:write(RTF_COLORDEFCLOSE..RTF_HEADERCLOSE..RTF_BODYOPEN..RTF_SETFONTFACE.."0".. RTF_SETFONTSIZE..defaultStyle.size..RTF_SETCOLOR.."0 ") lastStyle = RTF_SETFONTFACE.."0"..RTF_SETFONTSIZE..defaultStyle.size.. RTF_SETCOLOR.."0"..RTF_SETBACKGROUND.."1".. RTF_BOLD_OFF..RTF_ITALIC_OFF local prevCR = false local styleCurrent = -1 local column = 0 for i = selBeg, selEnd - 1 do local ch = exportutil.CharAt(i) local style = exportutil.StyleAt(i) if style > STYLE_DEFAULT then style = 0 end if style ~= styleCurrent then deltaStyle = GetRTFStyleChange(lastStyle, styles[style]) if deltaStyle ~= "" then fp:write(deltaStyle) end lastStyle = styles[style] styleCurrent = style end if ch == "{" then fp:write("\\{") elseif ch == "}" then fp:write("\\}") elseif ch == "\\" then fp:write("\\\\") elseif ch == "\t" then if tabs then fp:write(RTF_TAB) else local ts = tabSize - column % tabSize fp:write(string.rep(' ', ts)) column = column + ts - 1 end elseif ch == "\n" then if not prevCR then fp:write(RTF_EOLN) column = -1 end elseif ch == "\r" then fp:write(RTF_EOLN) column = -1 else fp:write(ch) end--ch column = column + 1 prevCR = ch == "\r" end--for fp:write(RTF_BODYCLOSE) fp:close() if exportutil.VERBOSE ~= 0 then exportutil.progress("... done.") end end -- end of script