Skip to main content

[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



Back to the top