[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
| 
Re: [xtext-dev] context dependend formatting
 | 
Hi,
I agree that it would be valuable for the formatter to have the current 
node from the node model available. The current semantic EObject would 
also be useful. Please note, that the formatter is not only called by 
the DefaultNodeModelFormatter but also by the ParseTreeConstructor. If a 
semantic model has been constructed manually or loaded from XMI (i.e. it 
has not been created by Xtext's parser), there is no node model at all. 
This is the main reason why the current formatter can not rely on the 
node model.
You didn't say what your implementation is supposed to do...I can't tell 
by the code you've sent since I don't know you grammar. However, the < 
/> remind me of XML...
I've spent a lot of work on the formatter during the last two weeks, so 
make sure you have a look at Xtext RC1. It will be released today.
Some of the new capabilities are:
- The engine which matches formatting instructions (the thing that is 
called by collectLocators(...)) to the grammar elements has gotten much 
more powerful. It is now possible to assign formatting instructions to 
Groups, Alternatives, UnorderedGroups, ParserRules, DatatypeRules and 
TerminalRules. For me this sounds like what you called "context 
sensitive formatting". The context is the position within the grammar, 
including which parser rules have been entered. In case the formatting 
needs more context than give by the grammar (e.g. EAttribute-Values, 
EObjects, Lists-sizes from your semantic model) - that's what we call 
semantic formatting.
- The formatter can now preserve linebreaks, if needed. See 
FormattingConfig.setLinewrap(int minWraps, int defaultWraps, int maxWraps)
- The formatter can now insert arbitrary spaces at defined positions 
FormattingConfig.setSpace(String).
cheers,
 Moritz
d green wrote:
It would be nice to have the current /AbstractNode/ in method 
/FormattingConfigBasedStream::addLineEntry/ available. The 
/grammarElement/ and the string /value/ isn't enough for context 
sensitiv formatting. The current workaround looks like a function eg 
interface in a subclass of /FormattingConfigBasedStream/
    protected AbstractNode node = null;
    public void setNodeHint(AbstractNode node) {
        this.node = node;
    }
This is called in a function override in a subclass of 
DefaultNodeModelFormatter, eg
    @Override
    public IFormattedRegion format(CompositeNode root, int offset, int 
length) {
        List<AbstractNode> nodes = getLeafs(root, offset, offset + 
length);
        if (nodes.size() == 0)
            return null;
        String indent = getIndentation(root, offset);
        TokenStringBuffer buf = new TokenStringBuffer();
        ITokenStream fmt = formatter.createFormatterStream(indent, 
buf, false);
       
        // this is xcl
*        XclFormattingConfigBasedStream xcl = null;
        if ( fmt instanceof XclFormattingConfigBasedStream )
            xcl = (XclFormattingConfigBasedStream) fmt;
*
        try {
            for (AbstractNode n : nodes) {
                // this is xcl
*                if ( null != xcl)
                    xcl.setNodeHint(n);
*                ...
No you can do context sensitive formatting eg leave the linebreaks out 
for an xml-like grammar just for <i>-tags in the subclass of 
/FormattingConfigBasedStream/
    *protected boolean cleanNext = false;*
    @Override
    protected void addLineEntry(EObject grammarElement, String value,
            boolean isHidden) throws IOException {
        Set<ElementLocator> locators = collectLocators(last, 
grammarElement);
        // System.out.println(loc + " --> " + value.replaceAll("\n", 
"\\n"));
*        if (cleanNext) {
            locators = normalizeLinebreaks(locators);
            cleanNext = false;
        }
        if (value.equals("<") || value.equals("</")) {
            // we ar on Start or Stop
            if (node.eContainer() instanceof CompositeNode) {
                EObject obj = ((CompositeNode) 
node.eContainer()).getElement();
                if (obj instanceof Start) {
                    Start start = (Start) obj;
                    if ("em".equals(start.getStart())) {
                         locators = normalizeLinebreaks(locators);
                    }
                } else if (obj instanceof Stop) {
                    Stop stop = (Stop) obj;
                    if ("em".equals(stop.getStop())) {
                        locators = normalizeLinebreaks(locators);
                    }
                }
            }
        } else if (value.equals(">") || value.equals("/>")) {
            // we are on the element
            if (node.eContainer() instanceof CompositeNode) {
                EObject obj = ((CompositeNode) 
node.eContainer()).getElement();
                if (obj instanceof Start) {
                    Start start = (Start) obj;
                    if ("em".equals(start.getStart())) {
                        cleanNext = true;
                    }
                } else if (obj instanceof Stop) {
                    Stop elem = ((Stop) obj);
                    if ("em".equals(elem.getStop())) {
                        cleanNext = true;
                    }
                }
            }
        }
*
        last = grammarElement;
        LineEntry e = new LineEntry(grammarElement, value, true, locators,
                preservedWS, indentationLevel);
        preservedWS = null;
        if (currentLine == null)
            currentLine = new Line();
        Line newLine = currentLine.add(e);
        if (newLine != null)
            currentLine = newLine;
    }
*    protected Set<ElementLocator> normalizeLinebreaks(
            Set<ElementLocator> locators) {
        Set<ElementLocator> locs = Sets.newHashSet();
        for (ElementLocator elm : locators) {
            if (!(elm instanceof LinewrapLocator
                    || elm instanceof IndentationLocatorStart || elm 
instanceof IndentationLocatorEnd))
                locs.add(elm);
        }
        return locs;
    }
*
Having /AbstractNode /availiable in /FormattingConfigBasedStream/ 
would do this in a standard way, at the best in a new overrideable 
function like /normalizeCurrent/ with the content of the bold part.
------------------------------------------------------------------------
_______________________________________________
xtext-dev mailing list
xtext-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/xtext-dev
  
--
Moritz Eysholdt
Software Architect
Telefon: +49 (0) 431 / 5606-335
Mobile: +49 (0) 179 / 6788196
Telefax: +49 (0) 431 / 5606-339
http://www.itemis.de
moritz.eysholdt@xxxxxxxxx
https://www.xing.com/profile/Moritz_Eysholdt
itemis AG
Schauenburgerstraße 116
24118 Kiel
Germany 
Rechtlicher Hinweis:
Amtsgericht Dortmund, HRB 20621
Vorstand: Jens Wagener (Vors.), Wolfgang Neuhaus, Dr. Georg Pietrek, Jens Trompeter, Sebastian Neus
Aufsichtsrat: Dr. Burkhard Igel (Vors.), Stephan Grollmann, Michael Neuhaus