" NAME TeX-Reporter AUTHOR bert@isg.cs.uni-magdeburg.de URL http://www.cs.uni-magdeburg.de/~bert FUNCTION generate _highlighted_ LaTeX-Code ST-VERSIONS VisualWorks 2.5 (maybe other too) PREREQUISITES Syntax-Highlighting.st CONFLICTS (none known) DISTRIBUTION world VERSION 1.0 DATE 15-Nov-96 SUMMARY Similar to the ManualWriter, writes out a class report, but in LaTeX-format. Uses Syntax-Highlighting for the method sources. Bert Schoenwaelder "! "Test if SyntaxHighlighting was filed in" (Text respondsTo: #coloringAttributes) ifFalse: [ self halt: 'Warning!! This package needs "Syntax-Highlighting.st" to work']! Object subclass: #TeXReporter instanceVariableNames: 'output indent prevChar ' classVariableNames: 'Translator ' poolDictionaries: '' category: 'Syntax-Highlighting'! TeXReporter comment: 'TeXReporter creates a LaTeX-documentation from a Class. User defined commands are inserted to allow easy formatting. Examplary command definitions can be found in the class protocol "tex commands". Use methods in "public" protocol for creating your own reports. For a complete report of a selected class execute: "TeXReporter exampleDialog". Bert Schönwälder, 1995-96 mailto:bert@cs.uni-magdeburg.de http://www.cs.uni-magdeburg.de/~bert Instance Variables: output the stream to report on indent current indent depth prevChar the char written before the actual one Class Variables: Translator stores information on how to translate Smalltalk characters into valid LaTeX-Input'! !TeXReporter methodsFor: 'initialize-release'! output: aStream "Setup output on aStream" output := aStream. indent := 0.! ! !TeXReporter methodsFor: 'public'! toClipboard "Put contents of output to smalltalk and host clipboard" ParagraphEditor currentSelection: output contents! writeClass: class "Write all protocols in class" self writeTeXComment: 'Class: ', class name; writeBegin: 'Class' parameter: class name; writeBegin: 'ClassParameters' parameter: class name; writeCommand: 'ClassParameterSuper' parameter:class superclass printString; writeCommand: 'ClassParameterCategory' parameter: class category; writeList: class instVarNames name: 'ClassParameterInstVar'; writeList: class classVarNames name: 'ClassParameterClassVar'; writeList: (class sharedPools collect: [:pd | Smalltalk keyAtValue: pd]) name: 'ClassParameterPoolDict'. class comment isEmpty ifFalse: [ self writeCommand: 'ClassParameterComment' parameter: class comment]. self writeEnd: 'ClassParameters' parameter: class name; writeBegin: 'ClassProtocols' parameter: class name. class organization categories do: [:prot | self writeProtocol: prot inClass: class]. self writeEnd: 'ClassProtocols' parameter: class name. (class class selectors isEmpty and: [class class instVarNames isEmpty]) ifFalse: [self writeBegin: 'MetaClass' parameter: class class name; writeList: class class instVarNames name: 'MetaClassInstVar'; writeBegin: 'ClassProtocols' parameter: class class name. class class organization categories do: [:prot | self writeProtocol: prot inClass: class class]. self writeEnd: 'ClassProtocols' parameter: class class name; writeEnd: 'MetaClass' parameter: class class name]. self writeEnd: 'Class' parameter: class name! writeCommandDefinitions "Write TeX command definitions" output nextPutAll: self class generalDefinitions; nextPutAll: self class formatDefinitions; nextPutAll: self class highlightDefinitions! writeMethod: selector inClass: class "Write the highlighted method" | text pos next symbol | self writeTeXComment: 'Method: ', class name, ' ', selector; writeBegin: 'Method' parameter: selector; writeIndent. text := self symbolicTextFor: selector inClass: class. pos := 1. [pos <= text size] whileTrue: [ next := pos + (text runLengthFor: pos). symbol := text emphasisAt: pos. self write:text string from: pos to: next - 1 as: symbol. pos := next]. self cr; writeEnd: 'Method' parameter: selector.! writeProtocol: protocol inClass: class "Write all methods in protocol" self writeTeXComment: 'Protokol: ', class name, '>', protocol; writeBegin: 'Protocol' parameter: protocol. "Write methods" (class organization listAtCategoryNamed: protocol) do: [:sel | self writeMethod: sel inClass: class]. self writeEnd: 'Protocol' parameter: protocol! ! !TeXReporter methodsFor: 'writing things'! writeBegin: what parameter: parameter "Write a command \stBeginWhat{parameter}" self writeCommand: 'Begin', what parameter: parameter. indent := indent + 1.! writeCommand: command parameter: parameter "Write a indented command \command{parameter} followed by cr" self writeIndent; writeCommandOnly: command parameter: parameter; cr.! writeCommandOnly: command parameter: parameter "Write a command \command{parameter}" output nextPutAll: '\st'; nextPutAll: command. parameter notNil ifTrue: [ output nextPut: ${. self write: parameter. output nextPut: $}].! writeEnd: what parameter: parameter "Write a command \stEndWhat{parameter}" indent := indent - 1. self writeCommand: 'End', what parameter: parameter.! writeIndent "Write spaces according to indent" output next: indent * 2 put: $ .! writeList: list name: name "Write all strings in list with separators: \stBeginNames \stName{first}\stNameSep \stName{second}\stNameSep . . . \stName{last} \stEndNames" list isEmpty ifFalse: [ self writeBegin: (name, 's') parameter: nil. list do: [:item | self writeIndent; writeCommandOnly: name parameter: item] separatedBy: [self writeCommandOnly: (name, 'Sep') parameter: nil; cr]. self cr; writeEnd: (name, 's') parameter: nil].! writeTeXComment: comment "Write a TeX-comment" | count | count := 40 - indent. self cr; writeIndent. output next: count put: $%; cr. self writeIndent. output nextPut: $%; space; nextPutAll: comment; cr. self writeIndent. output next: count put: $%; cr; cr! ! !TeXReporter methodsFor: 'writing syntax'! write: aString "Write translated characters in aString" self write: aString from: 1 to: aString size! write: aString from: first to: last "Write translated characters in aString from first to last" first to: last do: [:i | self writeTranslationOf: (aString at: i)]! write: aString from: first to: last as: aSymbol "Write characters in aString from first to last with emphasis aSymbol" | space | "Determine last non space" space := last + 1. [(aString at: space - 1) isSeparator and: [space > first]] whileTrue: [space := space - 1]. "No emphasis or only spaces" (aSymbol isNil or: [first = space]) ifTrue: [^self write: aString from: first to: last]. "Make commands like \SYM from #symbol" output nextPut: $\. 1 to: 3 do: [:i | output nextPut: (aSymbol at: i) asUppercase]. output nextPut: ${. "Write argument" self write: aString from: first to: space - 1. output nextPut: $}. "Put spaces" self write: aString from: space to: last.! writeTranslationOf: aCharacter "Translate and write aCharacter by dispatching to messages in 'character translation'-protocol" | translation | translation := Translator at: aCharacter asInteger. translation isSymbol ifTrue: [self perform: translation with: aCharacter] ifFalse: [self perform: translation key with: translation value]. prevChar := aCharacter! ! !TeXReporter methodsFor: 'character translation'! cr: character "Put a \CR and carriage return. If previous char was a cr also, put a \CRCR instead" output nextPutAll: '\CR'. prevChar = character ifTrue: [output nextPutAll: 'CR']. self cr; writeIndent! encloseMath: character "Enclose character in two $" output nextPut: $$; nextPut: character; nextPut: $$! noTranslate: character "Just put character itself" output nextPut: character! precedeWithSlash: character "Precede character with a backslash" output nextPut: $\; nextPut: character! translation: string "Put string - the translation of character" output nextPutAll: string! unknown: character "Put character as \stUnknown{}" output nextPutAll: '\stUnknown{'. character asInteger printOn: output. output nextPut: $}! ! !TeXReporter methodsFor: 'private'! cr "Put a carriage return" output cr! symbolicTextFor: selector inClass: class "Answer symbolic highlighted Text" ^(class sourceCodeAt: selector) asText symbolicColorsFor: class.! ! !TeXReporter class methodsFor: 'class initialization'! initialize "TeXReporter initialize" "For each character we need to know how to translate it into valid TeX. Put corresponding selector into Translator-Array" Translator := Array new: 255. ' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.:;,?!!()[]/@+-=''' do: [:c | Translator at: c asInteger put: #noTranslate:]. '$&%#_{}' do: [:c | Translator at: c asInteger put: #precedeWithSlash:]. '|<>' do: [:c | Translator at: c asInteger put: #encloseMath:]. Translator at: 13 put: #cr:; at: 9 put: #translation: -> '\TAB '. 'äöüÄÖÜß*' with: #('\"a' '\"o' '\"u' '\"A' '\"O' '\"U' '\ss' '$\ast$') do: [:c :t | Translator at: c asInteger put: #translation: -> t]. 1 to: 255 do: [:c | (Translator at: c) == nil ifTrue: [ Translator at: c put: #unknown:]].! ! !TeXReporter class methodsFor: 'instance creation'! output: aStream "Answer new TeXReporter" ^self new output: aStream! ! !TeXReporter class methodsFor: 'tex commands'! formatDefinitions "Answer a String containing tex command definitions used for Smalltalk source formatting" ^' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Definitions for Smalltalk source formatting %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \newcommand{\TAB}{\hspace*{0.5cm}} \newcommand{\CR}{\par} \newcommand{\CRCR}{\vspace*{0.4cm}} '! generalDefinitions "Answer a String containing tex command definitions used when reporting" ^' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Definitions for Class reports %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Class \newcommand{\stBeginClass}[1]{\section{Class: \emph{#1}}} \newcommand{\stEndClass}[1]{} % MetaClass \newcommand{\stBeginMetaClass}[1]{\section{Metaclass: \emph{#1}}} \newcommand{\stEndMetaClass}[1]{} % Class Parameters \newcommand{\stBeginClassParameters}[1]{\begin{flushleft}\begin{description}} \newcommand{\stEndClassParameters}[1]{\end{description}\end{flushleft}} %Class Parameter: Super class, Category, Comment \newcommand{\stClassParameterSuper}[1]{\item[Super class:] #1} \newcommand{\stClassParameterCategory}[1]{\item[Category:] #1} \newcommand{\stClassParameterComment}[1]{\item[Comment:] #1} %Class Parameter: Instance variables \newcommand{\stBeginClassParameterInstVars}{\item[Instance variables:]} \newcommand{\stClassParameterInstVar}[1]{#1} \newcommand{\stClassParameterInstVarSep}{, } \newcommand{\stEndClassParameterInstVars}{} %Class Parameter: Class variables \newcommand{\stBeginClassParameterClassVars}{\item[Class variables:]} \newcommand{\stClassParameterClassVar}[1]{#1} \newcommand{\stClassParameterClassVarSep}{, } \newcommand{\stEndClassParameterClassVars}{} %Class Parameter: Pool dictionaries \newcommand{\stBeginClassParameterPoolDicts}{\item[Pool dictionaries:]} \newcommand{\stClassParameterPoolDict}[1]{#1} \newcommand{\stClassParameterPoolDictSep}{, } \newcommand{\stEndClassParameterPoolDicts}{} %MetaClass: Instance variables \newcommand{\stBeginMetaClassInstVars}{\begin{description}\item[Instance variables:]} \newcommand{\stMetaClassInstVar}[1]{#1} \newcommand{\stMetaClassInstVarSep}{, } \newcommand{\stEndMetaClassInstVars}{\end{description}} % Class Protocols \newcommand{\stBeginClassProtocols}[1]{} \newcommand{\stEndClassProtocols}[1]{} % Protocol \newcommand{\stBeginProtocol}[1]{\subsection{Protocol: \emph{#1}}} \newcommand{\stEndProtocol}[1]{} % Method \newcommand{\stBeginMethod}[1]{\subsubsection{Method \emph{#1}}\begin{flushleft}} \newcommand{\stEndMethod}[1]{\end{flushleft}} % Unknown Characters \newcommand{\stUnknown}[1]{\texttt{\symbol{#1}}} '! highlightDefinitions "Answer a String containing tex command definitions used for Smalltalk source highlighting" ^' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Definitions for Smalltalk source highlighting %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Variables: ARGuments, TEMporary, INStance, CLAss, and GLObal ones \newcommand{\ARG}[1]{\textbf{#1}} \newcommand{\TEM}[1]{\textbf{#1}} \newcommand{\INS}[1]{\textbf{#1}} \newcommand{\CLA}[1]{\textbf{#1}} \newcommand{\GLO}[1]{\textbf{#1}} % Literals: NUMbers, literal ARRays, STRings, SYMbols, CHAracters, and CONstants \newcommand{\NUM}[1]{\texttt{#1}} \newcommand{\ARR}[1]{\texttt{#1}} \newcommand{\STR}[1]{\texttt{#1}} \newcommand{\SYM}[1]{\texttt{#1}} \newcommand{\CHA}[1]{\texttt{#1}} \newcommand{\CON}[1]{\texttt{#1}} %Misc: COMments, METhod comments, method SELectors, and PRImitives \newcommand{\COM}[1]{\textit{#1}} \newcommand{\MET}[1]{\textit{\textbf{#1}}} \newcommand{\SEL}[1]{\textsf{\textbf{#1}}} \newcommand{\PRI}[1]{\textsf{#1}} '! ! !TeXReporter class methodsFor: 'examples'! open self exampleDialog! example "TeXReporter example" | reporter s | s := WriteStream on: (String new: 100). reporter := TeXReporter output: s. reporter writeCommandDefinitions. "reporter writeClass: Link." "Link is a _cute_ class, isn't it?" reporter writeMethod: #basicSize inClass: Object. Transcript clear; show: s contents! exampleDialog "TeXReporter exampleDialog" | className theClass fileName | className := 'Class'. theClass := nil. [ className := Dialog request: 'Report which class?' initialAnswer: className onCancel: [^self]. theClass := Smalltalk at: className ifAbsent: nil. theClass isNil] whileTrue: [Dialog warn: 'Class not found!!']. fileName := Dialog requestFileName: 'Report "', className, '" to which file?' default: className, '.tex' version: #new ifFail: [^self]. self exampleReport: theClass toFileNamed: fileName! exampleDocument: aName title: aTitle do: aBlock "Create a TeX-document named aName, write header, title and definitions to it, execute aBlock whith a TeXReporter setup on this file" | fn stream reporter | fn := aName asFilename. fn canBeWritten ifFalse: [^Dialog warn: 'Cannot write file: ', name]. [ stream := fn writeStream. reporter := self output: stream. stream nextPutAll: self exampleDocumentHeader; nextPutAll: '\title{'. reporter write: aTitle. stream nextPut: $}; cr; nextPutAll: '\date{', Date today printString, '}'; cr. reporter writeCommandDefinitions; writeTeXComment: 'Document start'. stream nextPutAll: '\begin{document}'; cr; nextPutAll: '\maketitle'; cr. aBlock value: reporter. stream nextPutAll: '\end{document}'; cr. ] valueNowOrOnUnwindDo: [stream close].! exampleDocumentHeader "Answer an example document header" ^'\documentclass{article} \author{ Documentation automatically generated by\\ \\ \textbf{\TeX -Reporter}\\ written by Bert Sch\"onw\"alder, 1996} '! exampleReport: aClass toFileNamed: aName "Write a report for aClass to the file named aName" self exampleDocument: aName title: aClass name do: [:reporter | reporter writeClass: aClass]! ! TeXReporter initialize! Transcript cr; show: 'For an example do: "TeXReporter exampleDialog"'!