Early versions of Pier included the syntax to embed Smalltalk code into a page. This was a nice feature for power users, but caused certain confusion among others. Moreover it also caused potential security issues, when the permissions weren’t setup properly. Never the less, as there were some people complaining about the missing feature, I am going to show how to extend Pier and its pluggable parser to support this functionality.
1. Creating a new Node Type
First let’s create a new node type, a subclass of PRText
:
PRText subclass: #PRCode
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Pier-Executable'
2. Register with the Parser
Let’s specify an initializer method on the class side to register it with the parser. We choose a single pipe character as the new markup:
PRCode class>>markup
^ '|'
PRCode class>>initialize
PRDocumentParser textMatcher at: self markup put: self
Next we need to implement the hook method #parse: aString markup: aMarkupString with: aParser
to parse the string. In our case this is simple as we just want to return a new instance of PRCode
with the contents:
PRDocumentParser class>>parse: aString markup: aMarkupString with: aParser
^ self new text: aString
3. Plugging into the Visitors
Next we have to make sure that the new node type plays well with the visitor framework:
PRCode>>accept: aVisitor
aVisitor visitCode: self
PRVisitor>>visitCode: anObject
self visitText: anObject
Now we add the different #visitCode:
implementations in specific visitors. First this is the visitor to serialize a parsed node back to Wiki syntax:
PRWikiWriter>>visitCode: anObject
self nextPutAll: anObject class markup.
self nextPutAll: anObject text.
self nextPutAll: anObject class markup
And second, this is the XHTML visitor that should evaluate the code and display it on the resulting output stream:
PRViewRenderer>>visitCode: anObject
html render: (Compiler
evaluate: anObject text
for: self component
logged: false)
That’s all for a very basic implementation. Now we can write in any document |TimeStamp current|
to embed the current time. Since self
refers to the current component, we can embed the current page title into the document by writing: |self context structure title|
. Or, you can write Seaside rendering code to create a link that calls the counter example: | [ :html | html anchor callback: [ self call: WACounter new ]; with: 'Start Counter' ] |
. The possibilites are endless.
To use the presented code in a productive environment, some error handling has to be added. Propre sandboxing would also be a requirement.
Comments
Very cool work Lukas. And it so simple to extend it :-)
However, it doesn’t seem possible to use a non-markup syntax. How about:
Is it possible to have this kind of syntax?
Indeed, the syntax you suggest is not easy to implement with the current framework, however it is possible to write an entirely new parser that can coexist with the existing one.
The syntax Pier is using origins in SWiki and SmallWiki. It follows two simple patterns:
!
, ordered list#
, unordered list-
, table|
, etc.*
and+
) and formattings (''
,""
,^^
, etc).Need to write cool plugin ...
See ShoutPier at: http://mc.lukas-renggli.ch/pieraddons/
I feel so free to post a screenshot of this excellent plugin. I already see many possible uses, among them all the code examples on the upcoming web site of Seaside.
It would certainly be suited for code posts in a certain blog as well ;)
One issue that remains is finding out if the code to parse is a DoIt or a method